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..674e1494ecd 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 @@ -38,7 +39,60 @@ PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 -SortIncludes: false +SortIncludes: CaseSensitive +IncludeBlocks: Regroup +IncludeCategories: + # O2Physics, PWG + - Regex: ^(<|")PWG[A-Z]{2}/.*\.h + Priority: 2 + CaseSensitive: true + # O2Physics, non-PWG + - Regex: ^(<|")(Common|ALICE3|DPG|EventFiltering|Tools|Tutorials)/.*\.h + Priority: 3 + CaseSensitive: true + # O2 + - Regex: ^(<|")(Algorithm|CCDB|Common[A-Z]|DataFormats|DCAFitter|Detectors|EMCAL|Field|Framework|FT0|FV0|GlobalTracking|GPU|ITS|MathUtils|MFT|MCH|MID|PHOS|PID|ReconstructionDataFormats|SimulationDataFormat|TOF|TPC|ZDC).*/.*\.h + Priority: 4 + CaseSensitive: true + # ROOT + - Regex: ^(<|")(T[A-Z]|Math/|Roo[A-Z])[[:alnum:]/]+\.h + Priority: 5 + CaseSensitive: true + # known third-party: KFParticle + - Regex: ^(<|")KF[A-Z][[:alnum:]]+\.h + Priority: 6 + CaseSensitive: true + # known third-party: FastJet + - Regex: ^(<|")fastjet/ + Priority: 6 + CaseSensitive: true + # known third-party: ONNX runtime + - Regex: ^(<|")onnxruntime + Priority: 6 + CaseSensitive: true + # incomplete path to DataModel + - Regex: ^(<|").*DataModel/ + Priority: 1 + CaseSensitive: true + # other third-party + - Regex: ^(<|")([[:alnum:]_]+/)+[[:alnum:]_]+\.h + Priority: 6 + CaseSensitive: true + # other local-looking file + - Regex: ^".*\. + Priority: 1 + CaseSensitive: true + # C system + - Regex: ^(<|")[[:lower:]_]+\.h(>|") + Priority: 102 + CaseSensitive: true + # C++ system + - Regex: ^(<|")[[:lower:]_/]+(>|") + Priority: 101 + CaseSensitive: true + # rest + - Regex: .* + Priority: 100 SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false diff --git a/.clang-tidy b/.clang-tidy index da768906bcc..1d933b5937e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,3 +1,21 @@ CheckOptions: - - key: CheckPathRegex - value: '.*/O2/.*' + # Naming conventions + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.ClassMemberPrefix, value: m } + - { key: readability-identifier-naming.ConceptCase, value: CamelCase } + - { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase } + - { key: readability-identifier-naming.EnumCase, value: CamelCase } + - { key: readability-identifier-naming.EnumConstantCase, value: CamelCase } + - { key: readability-identifier-naming.EnumConstantIgnoredRegexp, value: "^k?[A-Z][a-zA-Z0-9_]*$" } # Allow "k" prefix and non-trailing underscores in PDG names. + - { key: readability-identifier-naming.FunctionCase, value: camelBack } + - { key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE } + - { key: readability-identifier-naming.MacroDefinitionIgnoredRegexp, value: "^[A-Z][A-Z0-9_]*_$" } # Allow the trailing underscore in header guards. + - { key: readability-identifier-naming.MemberCase, value: camelBack } + - { key: readability-identifier-naming.NamespaceCase, value: lower_case } + - { key: readability-identifier-naming.ParameterCase, value: camelBack } + - { key: readability-identifier-naming.StructCase, value: CamelCase } + - { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase } + - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } + - { key: readability-identifier-naming.TypedefCase, value: CamelCase } + - { key: readability-identifier-naming.TypeTemplateParameterCase, value: CamelCase } + - { key: readability-identifier-naming.VariableCase, value: camelBack } diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000000..e69de29bb2d 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..6ea6ff04aed --- /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@v6 + 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 893581a817e..5e68ae7d853 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -23,7 +23,7 @@ jobs: steps: # Git Checkout - name: Checkout Code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: # Checkout the HEAD of the PR instead of the merge commit. ref: ${{ github.event.pull_request.head.sha }} @@ -38,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@v9.1.0 env: # All available variables are described in documentation: # https://megalinter.io/configuration/ @@ -49,7 +49,7 @@ jobs: # Upload MegaLinter artifacts - name: Archive production artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: success() || failure() with: name: MegaLinter reports diff --git a/.github/workflows/o2-linter.yml b/.github/workflows/o2-linter.yml new file mode 100644 index 00000000000..00c710dbd5a --- /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@v6 + 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..62006bf7d90 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -5,6 +5,7 @@ on: - cron: "0 0 * * *" permissions: + actions: write issues: write pull-requests: write @@ -12,10 +13,12 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v1 + - uses: actions/stale@v10 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.' + stale-issue-message: 'This issue 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.' stale-pr-label: stale days-before-stale: 30 days-before-close: 5 + exempt-issue-labels: bug,enhancement diff --git a/.mega-linter.yml b/.mega-linter.yml index 838c5454d14..b9a956bd20a 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,6 @@ 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"] +CPP_CPPCHECK_FILE_EXTENSIONS: [".C", ".c", ".c++", ".cc", ".cl", ".cpp", ".cu", ".cuh", ".cxx", ".cxx.in", ".h", ".h++", ".hh", ".h.in", ".hpp", ".hxx", ".inc", ".inl", ".macro"] +CPP_CPPCHECK_ARGUMENTS: --language=c++ --std=c++20 --check-level=exhaustive --suppressions-list=cppcheck_config +REPOSITORY_GITLEAKS_PR_COMMITS_SCAN: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000000..ebff84266f2 --- /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: v20.1.5 # clang-format version + hooks: + - id: clang-format + - repo: https://github.com/cpplint/cpplint + rev: 2.0.2 + hooks: + - id: cpplint diff --git a/ALICE3/CMakeLists.txt b/ALICE3/CMakeLists.txt index ab460641cad..10172ee7d01 100644 --- a/ALICE3/CMakeLists.txt +++ b/ALICE3/CMakeLists.txt @@ -14,4 +14,4 @@ add_subdirectory(Core) # add_subdirectory(DataModel) add_subdirectory(Tasks) add_subdirectory(TableProducer) -add_subdirectory(Tools) +# add_subdirectory(Tools) diff --git a/ALICE3/Core/CMakeLists.txt b/ALICE3/Core/CMakeLists.txt index 6db27c117d8..6d44d580c45 100644 --- a/ALICE3/Core/CMakeLists.txt +++ b/ALICE3/Core/CMakeLists.txt @@ -11,10 +11,27 @@ o2physics_add_library(ALICE3Core SOURCES TOFResoALICE3.cxx + TrackUtilities.cxx DelphesO2TrackSmearer.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) + PUBLIC_LINK_LIBRARIES O2::Framework + O2Physics::AnalysisCore) o2physics_target_root_dictionary(ALICE3Core - HEADERS TOFResoALICE3.h - DelphesO2TrackSmearer.h - LINKDEF ALICE3CoreLinkDef.h) + HEADERS TOFResoALICE3.h + TrackUtilities.h + DelphesO2TrackSmearer.h + LINKDEF ALICE3CoreLinkDef.h) + +o2physics_add_library(FastTracker + SOURCES FastTracker.cxx + DetLayer.cxx + DelphesO2LutWriter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2Physics::AnalysisCore + O2Physics::ALICE3Core) + +o2physics_target_root_dictionary(FastTracker + HEADERS FastTracker.h + DetLayer.h + DelphesO2LutWriter.h + LINKDEF FastTrackerLinkDef.h) diff --git a/ALICE3/Core/DelphesO2LutWriter.cxx b/ALICE3/Core/DelphesO2LutWriter.cxx new file mode 100644 index 00000000000..987383092ec --- /dev/null +++ b/ALICE3/Core/DelphesO2LutWriter.cxx @@ -0,0 +1,538 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// @file DelphesO2LutWriter.cxx +/// @brief Porting to O2Physics of DelphesO2 code. +/// Minimal changes have been made to the original code for adaptation purposes, formatting and commented parts have been considered. +/// Relevant sources: +/// DelphesO2/src/lutWrite.cc https://github.com/AliceO2Group/DelphesO2/blob/master/src/lutWrite.cc +/// @author: Roberto Preghenella +/// @email: preghenella@bo.infn.it +/// + +#include "ALICE3/Core/DelphesO2LutWriter.h" + +#include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include "ALICE3/Core/FastTracker.h" +#include "ALICE3/Core/TrackUtilities.h" + +#include "TAxis.h" +#include "TDatabasePDG.h" +#include "TLorentzVector.h" +#include "TMatrixD.h" +#include "TMatrixDSymEigen.h" +#include "TVectorD.h" + +#include +#include + +// #define USE_FWD_PARAM +#ifdef USE_FWD_PARAM +#include "fwdRes.C" +#endif + +namespace o2::fastsim +{ + +void DelphesO2LutWriter::print() const +{ + LOG(info) << " --- Printing configuration of LUT writer --- "; + LOG(info) << " -> etaMaxBarrel = " << etaMaxBarrel; + LOG(info) << " -> usePara = " << usePara; + LOG(info) << " -> useDipole = " << useDipole; + LOG(info) << " -> useFlatDipole = " << useFlatDipole; + LOG(info) << " -> mAtLeastHits = " << mAtLeastHits; + LOG(info) << " -> mAtLeastCorr = " << mAtLeastCorr; + LOG(info) << " -> mAtLeastFake = " << mAtLeastFake; + LOG(info) << " -> Nch Binning: = " << mNchBinning.toString(); + LOG(info) << " -> Radius Binning: = " << mRadiusBinning.toString(); + LOG(info) << " -> Eta Binning: = " << mEtaBinning.toString(); + LOG(info) << " -> Pt Binning: = " << mPtBinning.toString(); + LOG(info) << " --- End of configuration --- "; +} + +std::string DelphesO2LutWriter::LutBinning::toString() const +{ + std::string str = ""; + str.append(log ? "log" : "lin"); + str.append(" nbins: "); + str.append(std::to_string(nbins)); + str.append(" min: "); + str.append(std::to_string(min)); + str.append(" max: "); + str.append(std::to_string(max)); + return str; +} + +bool DelphesO2LutWriter::fatSolve(lutEntry_t& lutEntry, + float pt, + float eta, + const float mass, + size_t itof, + size_t otof, + int q, + const float nch) +{ + lutEntry.valid = false; + + static TLorentzVector tlv; + tlv.SetPtEtaPhiM(pt, eta, 0., mass); + o2::track::TrackParCov trkIn; + o2::upgrade::convertTLorentzVectorToO2Track(q, tlv, {0., 0., 0.}, trkIn); + // tlv.Print(); + // return fmt::format("X:{:+.4e} Alp:{:+.3e} Par: {:+.4e} {:+.4e} {:+.4e} {:+.4e} {:+.4e} |Q|:{:d} {:s}\n", + // getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt(), getAbsCharge(), getPID().getName()); + // trkIn.print(); + o2::track::TrackParCov trkOut; + const int status = fat.FastTrack(trkIn, trkOut, nch); + if (status <= mAtLeastHits) { + LOGF(info, " --- fatSolve: FastTrack failed ---"); + // tlv.Print(); + return false; + } + LOGF(info, " --- fatSolve: FastTrack succeeded %d ---", status); + // trkOut.print(); + lutEntry.valid = true; + lutEntry.itof = fat.GetGoodHitProb(itof); + lutEntry.otof = fat.GetGoodHitProb(otof); + static constexpr int nCov = 15; + for (int i = 0; i < nCov; ++i) + lutEntry.covm[i] = trkOut.getCov()[i]; + + // define the efficiency + auto totfake = 0.; + lutEntry.eff = 1.; + for (size_t i = 1; i < fat.GetNLayers(); ++i) { + if (fat.IsLayerInert(i)) + continue; // skip inert layers + auto igoodhit = fat.GetGoodHitProb(i); + if (igoodhit <= 0. || i == itof || i == otof) + continue; + lutEntry.eff *= igoodhit; + auto pairfake = 0.; + for (size_t j = i + 1; j < fat.GetNLayers(); ++j) { + auto jgoodhit = fat.GetGoodHitProb(j); + if (jgoodhit <= 0. || j == itof || j == otof) + continue; + pairfake = (1. - igoodhit) * (1. - jgoodhit); + break; + } + totfake += pairfake; + } + lutEntry.eff2 = (1. - totfake); + + return true; +} + +#ifdef USE_FWD_PARAM +bool DelphesO2LutWriter::fwdSolve(float* covm, float pt, float eta, float mass) +{ + if (fwdRes(covm, pt, eta, mass) < 0) + return false; + return true; +} +#else +bool DelphesO2LutWriter::fwdSolve(float*, float, float, float) +{ + return false; +} +#endif + +bool DelphesO2LutWriter::fwdPara(lutEntry_t& lutEntry, float pt, float eta, float mass, float Bfield) +{ + lutEntry.valid = false; + + // parametrised forward response; interpolates between FAT at eta = 1.75 and a fixed parametrisation at eta = 4; only diagonal elements + static constexpr float etaLimit = 4.0f; + if (std::fabs(eta) < etaMaxBarrel || std::fabs(eta) > etaLimit) + return false; + + if (!fatSolve(lutEntry, pt, etaMaxBarrel, mass)) + return false; + static constexpr int nCov = 15; + float covmbarrel[nCov] = {0}; + for (int i = 0; i < nCov; ++i) { + covmbarrel[i] = lutEntry.covm[i]; + } + + // parametrisation at eta = 4 + const double beta = 1. / std::sqrt(1 + mass * mass / pt / pt / std::cosh(eta) / std::cosh(eta)); + const float dcaPos = 2.5e-4 / std::sqrt(3); // 2.5 micron/sqrt(3) + const float r0 = 0.5; // layer 0 radius [cm] + const float r1 = 1.3; + const float r2 = 2.5; + const float x0layer = 0.001; // material budget (rad length) per layer + const double sigmaAlpha = 0.0136 / beta / pt * std::sqrt(x0layer * std::cosh(eta)) * (1 + 0.038 * std::log(x0layer * std::cosh(eta))); + const double dcaxyMs = sigmaAlpha * r0 * std::sqrt(1 + r1 * r1 / (r2 - r0) / (r2 - r0)); + const double dcaxy2 = dcaPos * dcaPos + dcaxyMs * dcaxyMs; + + const double dcazMs = sigmaAlpha * r0 * std::cosh(eta); + const double dcaz2 = dcaPos * dcaPos + dcazMs * dcazMs; + + const float Leta = 2.8 / std::sinh(eta) - 0.01 * r0; // m + const double relmomresPos = 10e-6 * pt / 0.3 / Bfield / Leta / Leta * std::sqrt(720. / 15.); + + const float relmomresBarrel = std::sqrt(covmbarrel[14]) * pt; + const float rOuter = 1; // m + const float relmomresPosBarrel = 10e-6 * pt / 0.3 / Bfield / rOuter / rOuter / std::sqrt(720. / 15.); + const float relmomresMSBarrel = std::sqrt(relmomresBarrel * relmomresBarrel - relmomresPosBarrel * relmomresPosBarrel); + + // interpolate MS contrib (rel resolution 0.4 at eta = 4) + const float relmomresMSEta4 = 0.4 / beta * 0.5 / Bfield; + const float relmomresMS = relmomresMSEta4 * std::pow(relmomresMSEta4 / relmomresMSBarrel, (std::fabs(eta) - 4.) / (4. - etaMaxBarrel)); + const float momresTot = pt * std::sqrt(relmomresPos * relmomresPos + relmomresMS * relmomresMS); // total absolute mom reso + + // Fill cov matrix diag + for (int i = 0; i < 15; ++i) + lutEntry.covm[i] = 0; + + lutEntry.covm[0] = covmbarrel[0]; + if (dcaxy2 > lutEntry.covm[0]) + lutEntry.covm[0] = dcaxy2; + lutEntry.covm[2] = covmbarrel[2]; + if (dcaz2 > lutEntry.covm[2]) + lutEntry.covm[2] = dcaz2; + lutEntry.covm[5] = covmbarrel[5]; // sigma^2 sin(phi) + lutEntry.covm[9] = covmbarrel[9]; // sigma^2 tanl + lutEntry.covm[14] = momresTot * momresTot / pt / pt / pt / pt; // sigma^2 1/pt + // Check that all numbers are numbers + for (int i = 0; i < 15; ++i) { + if (std::isnan(lutEntry.covm[i])) { + LOGF(info, " --- lutEntry.covm[%d] is NaN", i); + return false; + } + } + return true; +} + +void DelphesO2LutWriter::lutWrite(const char* filename, int pdg, float field, size_t itof, size_t otof) +{ + + if (useFlatDipole && useDipole) { + LOGF(info, "Both dipole and dipole flat flags are on, please use only one of them"); + return; + } + + // output file + std::ofstream lutFile(filename, std::ofstream::binary); + if (!lutFile.is_open()) { + LOGF(info, "Did not manage to open output file!!"); + return; + } + + // write header + lutHeader_t lutHeader; + // pid + lutHeader.pdg = pdg; + const TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(pdg); + if (!particle) { + LOG(fatal) << "Cannot find particle with PDG code " << pdg; + return; + } + lutHeader.mass = particle->Mass(); + const int q = std::abs(particle->Charge()) / 3; + if (q <= 0) { + LOGF(info, "Negative or null charge (%f) for pdg code %i. Fix the charge!", particle->Charge(), pdg); + return; + } + lutHeader.field = field; + auto setMap = [](map_t& map, LutBinning b) { + map.log = b.log; + map.nbins = b.nbins; + map.min = b.min; + map.max = b.max; + }; + // nch + setMap(lutHeader.nchmap, mNchBinning); + // radius + setMap(lutHeader.radmap, mRadiusBinning); + // eta + setMap(lutHeader.etamap, mEtaBinning); + // pt + setMap(lutHeader.ptmap, mPtBinning); + + lutFile.write(reinterpret_cast(&lutHeader), sizeof(lutHeader)); + + // entries + const int nnch = lutHeader.nchmap.nbins; + const int nrad = lutHeader.radmap.nbins; + const int neta = lutHeader.etamap.nbins; + const int npt = lutHeader.ptmap.nbins; + lutEntry_t lutEntry; + + // write entries + int nCalls = 0; + int successfullCalls = 0; + int failedCalls = 0; + for (int inch = 0; inch < nnch; ++inch) { + LOGF(info, " --- writing nch = %d/%d", inch, nnch); + auto nch = lutHeader.nchmap.eval(inch); + lutEntry.nch = nch; + fat.SetdNdEtaCent(nch); + for (int irad = 0; irad < nrad; ++irad) { + LOGF(info, " --- writing irad = %d/%d", irad, nrad); + for (int ieta = 0; ieta < neta; ++ieta) { + LOGF(info, " --- writing ieta = %d/%d", ieta, neta); + auto eta = lutHeader.etamap.eval(ieta); + lutEntry.eta = lutHeader.etamap.eval(ieta); + for (int ipt = 0; ipt < npt; ++ipt) { + nCalls++; + LOGF(info, " --- writing ipt = %d/%d", ipt, npt); + lutEntry.pt = lutHeader.ptmap.eval(ipt); + lutEntry.valid = true; + if (std::fabs(eta) <= etaMaxBarrel) { // full lever arm ends at etaMaxBarrel + LOGF(info, "Solving in the barrel"); + // LOGF(info, " --- fatSolve: pt = %f, eta = %f, mass = %f, field=%f", lutEntry.pt, lutEntry.eta, lutHeader.mass, lutHeader.field); + successfullCalls++; + if (!fatSolve(lutEntry, lutEntry.pt, lutEntry.eta, lutHeader.mass, itof, otof, q)) { + // LOGF(info, " --- fatSolve: error"); + lutEntry.valid = false; + lutEntry.eff = 0.; + lutEntry.eff2 = 0.; + for (int i = 0; i < 15; ++i) { + lutEntry.covm[i] = 0.; + } + successfullCalls--; + failedCalls++; + } + } else { + LOGF(info, "Solving outside the barrel"); + // LOGF(info, " --- fwdSolve: pt = %f, eta = %f, mass = %f, field=%f", lutEntry.pt, lutEntry.eta, lutHeader.mass, lutHeader.field); + lutEntry.eff = 1.; + lutEntry.eff2 = 1.; + bool retval = true; + successfullCalls++; + if (useFlatDipole) { // Using the parametrization at the border of the barrel + retval = fatSolve(lutEntry, lutEntry.pt, etaMaxBarrel, lutHeader.mass, itof, otof, q); + } else if (usePara) { + retval = fwdPara(lutEntry, lutEntry.pt, lutEntry.eta, lutHeader.mass, field); + } else { + retval = fwdSolve(lutEntry.covm, lutEntry.pt, lutEntry.eta, lutHeader.mass); + } + if (useDipole) { // Using the parametrization at the border of the barrel only for efficiency and momentum resolution + lutEntry_t lutEntryBarrel; + retval = fatSolve(lutEntryBarrel, lutEntry.pt, etaMaxBarrel, lutHeader.mass, itof, otof, q); + lutEntry.valid = lutEntryBarrel.valid; + lutEntry.covm[14] = lutEntryBarrel.covm[14]; + lutEntry.eff = lutEntryBarrel.eff; + lutEntry.eff2 = lutEntryBarrel.eff2; + } + if (!retval) { + LOGF(info, " --- fwdSolve: error"); + lutEntry.valid = false; + for (int i = 0; i < 15; ++i) { + lutEntry.covm[i] = 0.; + } + successfullCalls--; + failedCalls++; + } + } + LOGF(info, "Diagonalizing"); + diagonalise(lutEntry); + LOGF(info, "Writing"); + lutFile.write(reinterpret_cast(&lutEntry), sizeof(lutEntry_t)); + } + } + } + } + LOGF(info, " --- finished writing LUT file %s", filename); + LOGF(info, " --- successfull calls: %d/%d, failed calls: %d/%d", successfullCalls, nCalls, failedCalls, nCalls); + lutFile.close(); +} + +void DelphesO2LutWriter::diagonalise(lutEntry_t& lutEntry) +{ + static constexpr int kEig = 5; + TMatrixDSym m(kEig); + for (int i = 0, k = 0; i < kEig; ++i) { + for (int j = 0; j < i + 1; ++j, ++k) { + m(i, j) = lutEntry.covm[k]; + m(j, i) = lutEntry.covm[k]; + } + } + + // m.Print(); + TMatrixDSymEigen eigen(m); + // eigenvalues vector + TVectorD eigenVal = eigen.GetEigenValues(); + for (int i = 0; i < kEig; ++i) + lutEntry.eigval[i] = eigenVal[i]; + // eigenvectors matrix + TMatrixD eigenVec = eigen.GetEigenVectors(); + for (int i = 0; i < kEig; ++i) + for (int j = 0; j < kEig; ++j) + lutEntry.eigvec[i][j] = eigenVec[i][j]; + // inverse eigenvectors matrix + eigenVec.Invert(); + for (int i = 0; i < kEig; ++i) + for (int j = 0; j < kEig; ++j) + lutEntry.eiginv[i][j] = eigenVec[i][j]; +} + +TGraph* DelphesO2LutWriter::lutRead(const char* filename, int pdg, int what, int vs, float nch, float radius, float eta, float pt) +{ + LOGF(info, " --- reading LUT file %s", filename); + // vs + static const int kNch = 0; + static const int kEta = 1; + static const int kPt = 2; + + // what + static const int kEfficiency = 0; + static const int kEfficiency2 = 1; + static const int kEfficiencyInnerTOF = 2; + static const int kEfficiencyOuterTOF = 3; + static const int kPtResolution = 4; + static const int kRPhiResolution = 5; + static const int kZResolution = 6; + + o2::delphes::DelphesO2TrackSmearer smearer; + smearer.loadTable(pdg, filename); + auto lutHeader = smearer.getLUTHeader(pdg); + lutHeader->print(); + map_t lutMap; + switch (vs) { + case kNch: + lutMap = lutHeader->nchmap; + break; + case kEta: + lutMap = lutHeader->etamap; + break; + case kPt: + lutMap = lutHeader->ptmap; + break; + } + auto nbins = lutMap.nbins; + auto g = new TGraph(); + g->SetName(Form("lut_%s_%d_vs_%d_what_%d", filename, pdg, vs, what)); + g->SetTitle(Form("LUT for %s, pdg %d, vs %d, what %d", filename, pdg, vs, what)); + switch (vs) { + case kNch: + LOGF(info, " --- vs = kNch"); + g->GetXaxis()->SetTitle("Nch"); + break; + case kEta: + LOGF(info, " --- vs = kEta"); + g->GetXaxis()->SetTitle("#eta"); + break; + case kPt: + LOGF(info, " --- vs = kPt"); + g->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + break; + default: + LOGF(info, " --- error: unknown vs %d", vs); + return nullptr; + } + switch (what) { + case kEfficiency: + LOGF(info, " --- what = kEfficiency"); + g->GetYaxis()->SetTitle("Efficiency (%)"); + break; + case kEfficiency2: + LOGF(info, " --- what = kEfficiency2"); + g->GetYaxis()->SetTitle("Efficiency2 (%)"); + break; + case kEfficiencyInnerTOF: + LOGF(info, " --- what = kEfficiencyInnerTOF"); + g->GetYaxis()->SetTitle("Inner TOF Efficiency (%)"); + break; + case kEfficiencyOuterTOF: + LOGF(info, " --- what = kEfficiencyOuterTOF"); + g->GetYaxis()->SetTitle("Outer TOF Efficiency (%)"); + break; + case kPtResolution: + LOGF(info, " --- what = kPtResolution"); + g->GetYaxis()->SetTitle("p_{T} Resolution (%)"); + break; + case kRPhiResolution: + LOGF(info, " --- what = kRPhiResolution"); + g->GetYaxis()->SetTitle("R#phi Resolution (#mum)"); + break; + case kZResolution: + LOGF(info, " --- what = kZResolution"); + g->GetYaxis()->SetTitle("Z Resolution (#mum)"); + break; + default: + LOGF(info, " --- error: unknown what %d", what); + return nullptr; + } + + bool canBeInvalid = true; + for (int i = 0; i < nbins; ++i) { + switch (vs) { + case kNch: + nch = lutMap.eval(i); + break; + case kEta: + eta = lutMap.eval(i); + break; + case kPt: + pt = lutMap.eval(i); + break; + } + float eff = 0.; + auto lutEntry = smearer.getLUTEntry(pdg, nch, radius, eta, pt, eff); + if (!lutEntry->valid || lutEntry->eff == 0.) { + if (!canBeInvalid) { + LOGF(info, " --- warning: it cannot be invalid"); + } + continue; + } + canBeInvalid = false; + + double cen = 0.; + switch (vs) { + case kNch: + cen = lutEntry->nch; + break; + case kEta: + cen = lutEntry->eta; + break; + case kPt: + cen = lutEntry->pt; + break; + } + double val = 0.; + switch (what) { + case kEfficiency: + val = lutEntry->eff * 100.; // efficiency (%) + break; + case kEfficiency2: + val = lutEntry->eff2 * 100.; // efficiency (%) + break; + case kEfficiencyInnerTOF: + val = lutEntry->itof * 100.; // efficiency (%) + break; + case kEfficiencyOuterTOF: + val = lutEntry->otof * 100.; // efficiency (%) + break; + case kPtResolution: + val = std::sqrt(lutEntry->covm[14]) * lutEntry->pt * 100.; // pt resolution (%) + break; + case kRPhiResolution: + val = std::sqrt(lutEntry->covm[0]) * 1.e4; // rphi resolution (um) + break; + case kZResolution: + val = std::sqrt(lutEntry->covm[1]) * 1.e4; // z resolution (um) + break; + default: + LOGF(info, " --- error: unknown what %d", what); + break; + } + g->AddPoint(cen, val); + } + + return g; +} +} // namespace o2::fastsim + +ClassImp(o2::fastsim::DelphesO2LutWriter); diff --git a/ALICE3/Core/DelphesO2LutWriter.h b/ALICE3/Core/DelphesO2LutWriter.h new file mode 100644 index 00000000000..1528ab80bac --- /dev/null +++ b/ALICE3/Core/DelphesO2LutWriter.h @@ -0,0 +1,94 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file DelphesO2LutWriter.h +/// \brief Porting to O2Physics of DelphesO2 code. +/// Minimal changes have been made to the original code for adaptation purposes, formatting and commented parts have been considered. +/// Relevant sources: +/// DelphesO2/src/lutWrite.cc https://github.com/AliceO2Group/DelphesO2/blob/master/src/lutWrite.cc +/// \author: Roberto Preghenella +/// \email: preghenella@bo.infn.it +/// + +#ifndef ALICE3_CORE_DELPHESO2LUTWRITER_H_ +#define ALICE3_CORE_DELPHESO2LUTWRITER_H_ + +#include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include "ALICE3/Core/FastTracker.h" + +#include "ReconstructionDataFormats/PID.h" + +#include "TGraph.h" + +#include + +namespace o2::fastsim +{ +class DelphesO2LutWriter +{ + public: + DelphesO2LutWriter() = default; + virtual ~DelphesO2LutWriter() = default; + + // Setters + void setBinningNch(bool log, int nbins, float min, float max) { mNchBinning = {log, nbins, min, max}; } + void setBinningRadius(bool log, int nbins, float min, float max) { mRadiusBinning = {log, nbins, min, max}; } + void setBinningEta(bool log, int nbins, float min, float max) { mEtaBinning = {log, nbins, min, max}; } + void setBinningPt(bool log, int nbins, float min, float max) { mPtBinning = {log, nbins, min, max}; } + void setEtaMaxBarrel(float eta) { etaMaxBarrel = eta; } + void setAtLeastHits(int n) { mAtLeastHits = n; } + void setAtLeastCorr(int n) { mAtLeastCorr = n; } + void setAtLeastFake(int n) { mAtLeastFake = n; } + bool fatSolve(lutEntry_t& lutEntry, + float pt = 0.1, + float eta = 0.0, + const float mass = o2::track::pid_constants::sMasses[o2::track::PID::Pion], + size_t itof = 0, + size_t otof = 0, + int q = 1, + const float nch = 1); + + void print() const; + bool fwdSolve(float* covm, float pt = 0.1, float eta = 0.0, float mass = o2::track::pid_constants::sMasses[o2::track::PID::Pion]); + bool fwdPara(lutEntry_t& lutEntry, float pt = 0.1, float eta = 0.0, float mass = o2::track::pid_constants::sMasses[o2::track::PID::Pion], float Bfield = 0.5); + void lutWrite(const char* filename = "lutCovm.dat", int pdg = 211, float field = 0.2, size_t itof = 0, size_t otof = 0); + TGraph* lutRead(const char* filename, int pdg, int what, int vs, float nch = 0., float radius = 0., float eta = 0., float pt = 0.); + + o2::fastsim::FastTracker fat; + + private: + void diagonalise(lutEntry_t& lutEntry); + float etaMaxBarrel = 1.75f; + bool usePara = true; // use fwd parameterisation + bool useDipole = false; // use dipole i.e. flat parametrization for efficiency and momentum resolution + bool useFlatDipole = false; // use dipole i.e. flat parametrization outside of the barrel + + int mAtLeastHits = 4; + int mAtLeastCorr = 4; + int mAtLeastFake = 0; + + // Binning of the LUT to make + struct LutBinning { + bool log; + int nbins; + float min; + float max; + std::string toString() const; + }; + LutBinning mNchBinning = {true, 20, 0.5f, 3.5f}; + LutBinning mRadiusBinning = {false, 1, 0.0f, 100.0f}; + LutBinning mEtaBinning = {false, 80, -4.0f, 4.0f}; + LutBinning mPtBinning = {true, 200, -2.0f, 2.0f}; + + ClassDef(DelphesO2LutWriter, 1); +}; +} // namespace o2::fastsim + +#endif // ALICE3_CORE_DELPHESO2LUTWRITER_H_ diff --git a/ALICE3/Core/DelphesO2TrackSmearer.cxx b/ALICE3/Core/DelphesO2TrackSmearer.cxx index f4ea4ebdf3c..599d9cd9413 100644 --- a/ALICE3/Core/DelphesO2TrackSmearer.cxx +++ b/ALICE3/Core/DelphesO2TrackSmearer.cxx @@ -10,14 +10,14 @@ // or submit itself to any jurisdiction. /// -/// @file DelphesO2TrackSmearer.cxx -/// @brief Porting to O2Physics of DelphesO2 code. +/// \file DelphesO2TrackSmearer.cxx +/// \author Roberto Preghenella +/// \brief Porting to O2Physics of DelphesO2 code. /// Minimal changes have been made to the original code for adaptation purposes, formatting and commented parts have been considered. /// Relevant sources: /// DelphesO2/src/lutCovm.hh https://github.com/AliceO2Group/DelphesO2/blob/master/src/lutCovm.hh /// DelphesO2/src/TrackSmearer.cc https://github.com/AliceO2Group/DelphesO2/blob/master/src/TrackSmearer.cc /// DelphesO2/src/TrackSmearer.hh https://github.com/AliceO2Group/DelphesO2/blob/master/src/TrackSmearer.hh -/// @author: Roberto Preghenella /// @email: preghenella@bo.infn.it /// @@ -36,6 +36,12 @@ #include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include +#include + +#include +#include + namespace o2 { namespace delphes @@ -45,35 +51,73 @@ namespace delphes bool TrackSmearer::loadTable(int pdg, const char* filename, bool forceReload) { - auto ipdg = getIndexPDG(pdg); + if (!filename || filename[0] == '\0') { + LOG(info) << " --- No LUT file provided for PDG " << pdg << ". Skipping load."; + return false; + } + const auto ipdg = getIndexPDG(pdg); + LOGF(info, "Will load %s lut file ..: '%s'", getParticleName(pdg), filename); if (mLUTHeader[ipdg] && !forceReload) { - std::cout << " --- LUT table for PDG " << pdg << " has been already loaded with index " << ipdg << std::endl; + LOG(info) << " --- LUT table for PDG " << pdg << " has been already loaded with index " << ipdg << std::endl; return false; } + if (strncmp(filename, "ccdb:", 5) == 0) { // Check if filename starts with "ccdb:" + LOG(info) << " --- LUT file source identified as CCDB."; + std::string path = std::string(filename).substr(5); // Remove "ccdb:" prefix + const std::string outPath = "/tmp/LUTs/"; + filename = Form("%s/%s/snapshot.root", outPath.c_str(), path.c_str()); + std::ifstream checkFile(filename); // Check if file already exists + if (!checkFile.is_open()) { // File does not exist, retrieve from CCDB + LOG(info) << " --- CCDB source detected for PDG " << pdg << ": " << path; + if (!mCcdbManager) { + LOG(fatal) << " --- CCDB manager not set. Please set it before loading LUT from CCDB."; + } + std::map metadata; + mCcdbManager->getCCDBAccessor().retrieveBlob(path, outPath, metadata, 1); + // Add CCDB handling logic here if needed + LOG(info) << " --- Now retrieving LUT file from CCDB to: " << filename; + } else { // File exists, proceed to load + LOG(info) << " --- LUT file already exists: " << filename << ". Skipping download."; + checkFile.close(); + } + return loadTable(pdg, filename, forceReload); + } + mLUTHeader[ipdg] = new lutHeader_t; std::ifstream lutFile(filename, std::ifstream::binary); if (!lutFile.is_open()) { - std::cout << " --- cannot open covariance matrix file for PDG " << pdg << ": " << filename << std::endl; + LOG(info) << " --- cannot open covariance matrix file for PDG " << pdg << ": " << filename << std::endl; delete mLUTHeader[ipdg]; mLUTHeader[ipdg] = nullptr; return false; } lutFile.read(reinterpret_cast(mLUTHeader[ipdg]), sizeof(lutHeader_t)); if (lutFile.gcount() != sizeof(lutHeader_t)) { - std::cout << " --- troubles reading covariance matrix header for PDG " << pdg << ": " << filename << std::endl; + LOG(info) << " --- troubles reading covariance matrix header for PDG " << pdg << ": " << filename << std::endl; delete mLUTHeader[ipdg]; mLUTHeader[ipdg] = nullptr; return false; } if (mLUTHeader[ipdg]->version != LUTCOVM_VERSION) { - std::cout << " --- LUT header version mismatch: expected/detected = " << LUTCOVM_VERSION << "/" << mLUTHeader[ipdg]->version << std::endl; + LOG(info) << " --- LUT header version mismatch: expected/detected = " << LUTCOVM_VERSION << "/" << mLUTHeader[ipdg]->version << std::endl; delete mLUTHeader[ipdg]; mLUTHeader[ipdg] = nullptr; return false; } - if (mLUTHeader[ipdg]->pdg != pdg) { - std::cout << " --- LUT header PDG mismatch: expected/detected = " << pdg << "/" << mLUTHeader[ipdg]->pdg << std::endl; + bool specialPdgCase = false; + switch (pdg) { // Handle special cases + case o2::constants::physics::kAlpha: // Special case: Allow Alpha particles to use He3 LUT + specialPdgCase = (mLUTHeader[ipdg]->pdg == o2::constants::physics::kHelium3); + if (specialPdgCase) + LOG(info) + << " --- Alpha particles (PDG " << pdg << ") will use He3 LUT data (PDG " << mLUTHeader[ipdg]->pdg << ")" << std::endl; + break; + default: + break; + } + if (mLUTHeader[ipdg]->pdg != pdg && !specialPdgCase) { + LOG(info) << " --- LUT header PDG mismatch: expected/detected = " << pdg << "/" << mLUTHeader[ipdg]->pdg << std::endl; delete mLUTHeader[ipdg]; mLUTHeader[ipdg] = nullptr; return false; @@ -93,14 +137,14 @@ bool TrackSmearer::loadTable(int pdg, const char* filename, bool forceReload) mLUTEntry[ipdg][inch][irad][ieta][ipt] = new lutEntry_t; lutFile.read(reinterpret_cast(mLUTEntry[ipdg][inch][irad][ieta][ipt]), sizeof(lutEntry_t)); if (lutFile.gcount() != sizeof(lutEntry_t)) { - std::cout << " --- troubles reading covariance matrix entry for PDG " << pdg << ": " << filename << std::endl; + LOG(info) << " --- troubles reading covariance matrix entry for PDG " << pdg << ": " << filename << std::endl; return false; } } } } } - std::cout << " --- read covariance matrix table for PDG " << pdg << ": " << filename << std::endl; + LOG(info) << " --- read covariance matrix table for PDG " << pdg << ": " << filename << std::endl; mLUTHeader[ipdg]->print(); lutFile.close(); @@ -109,12 +153,13 @@ bool TrackSmearer::loadTable(int pdg, const char* filename, bool forceReload) /*****************************************************************/ -lutEntry_t* - TrackSmearer::getLUTEntry(int pdg, float nch, float radius, float eta, float pt, float& interpolatedEff) +lutEntry_t* TrackSmearer::getLUTEntry(const int pdg, const float nch, const float radius, const float eta, const float pt, float& interpolatedEff) { - auto ipdg = getIndexPDG(pdg); - if (!mLUTHeader[ipdg]) + const int ipdg = getIndexPDG(pdg); + if (!mLUTHeader[ipdg]) { + LOG(error) << " --- getLUTEntry: LUT header not loaded for pdg=" << pdg << ". Returning nullptr."; return nullptr; + } auto inch = mLUTHeader[ipdg]->nchmap.find(nch); auto irad = mLUTHeader[ipdg]->radmap.find(radius); auto ieta = mLUTHeader[ipdg]->etamap.find(eta); @@ -123,43 +168,58 @@ lutEntry_t* // Interpolate if requested auto fraction = mLUTHeader[ipdg]->nchmap.fracPositionWithinBin(nch); if (mInterpolateEfficiency) { - if (fraction > 0.5) { - if (mWhatEfficiency == 1) { - if (inch < mLUTHeader[ipdg]->nchmap.nbins - 1) { - interpolatedEff = (1.5f - fraction) * mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff + (-0.5f + fraction) * mLUTEntry[ipdg][inch + 1][irad][ieta][ipt]->eff; - } else { - interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff; - } - } - if (mWhatEfficiency == 2) { - if (inch < mLUTHeader[ipdg]->nchmap.nbins - 1) { - interpolatedEff = (1.5f - fraction) * mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2 + (-0.5f + fraction) * mLUTEntry[ipdg][inch + 1][irad][ieta][ipt]->eff2; - } else { - interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2; - } + static constexpr float kFractionThreshold = 0.5f; + if (fraction > kFractionThreshold) { + switch (mWhatEfficiency) { + case 1: + if (inch < mLUTHeader[ipdg]->nchmap.nbins - 1) { + interpolatedEff = (1.5f - fraction) * mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff + (-0.5f + fraction) * mLUTEntry[ipdg][inch + 1][irad][ieta][ipt]->eff; + } else { + interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff; + } + break; + case 2: + if (inch < mLUTHeader[ipdg]->nchmap.nbins - 1) { + interpolatedEff = (1.5f - fraction) * mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2 + (-0.5f + fraction) * mLUTEntry[ipdg][inch + 1][irad][ieta][ipt]->eff2; + } else { + interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2; + } + break; + default: + LOG(fatal) << " --- getLUTEntry: unknown efficiency type " << mWhatEfficiency; } } else { - float comparisonValue = mLUTHeader[ipdg]->nchmap.log ? log10(nch) : nch; - if (mWhatEfficiency == 1) { - if (inch > 0 && comparisonValue < mLUTHeader[ipdg]->nchmap.max) { - interpolatedEff = (0.5f + fraction) * mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff + (0.5f - fraction) * mLUTEntry[ipdg][inch - 1][irad][ieta][ipt]->eff; - } else { - interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff; - } - } - if (mWhatEfficiency == 2) { - if (inch > 0 && comparisonValue < mLUTHeader[ipdg]->nchmap.max) { - interpolatedEff = (0.5f + fraction) * mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2 + (0.5f - fraction) * mLUTEntry[ipdg][inch - 1][irad][ieta][ipt]->eff2; - } else { - interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2; - } + float comparisonValue = mLUTHeader[ipdg]->nchmap.log ? std::log10(nch) : nch; + switch (mWhatEfficiency) { + case 1: + if (inch > 0 && comparisonValue < mLUTHeader[ipdg]->nchmap.max) { + interpolatedEff = (0.5f + fraction) * mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff + (0.5f - fraction) * mLUTEntry[ipdg][inch - 1][irad][ieta][ipt]->eff; + } else { + interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff; + } + break; + case 2: + if (inch > 0 && comparisonValue < mLUTHeader[ipdg]->nchmap.max) { + interpolatedEff = (0.5f + fraction) * mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2 + (0.5f - fraction) * mLUTEntry[ipdg][inch - 1][irad][ieta][ipt]->eff2; + } else { + interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2; + } + break; + default: + LOG(fatal) << " --- getLUTEntry: unknown efficiency type " << mWhatEfficiency; } } } else { - if (mWhatEfficiency == 1) - interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff; - if (mWhatEfficiency == 2) - interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2; + switch (mWhatEfficiency) { + case 1: + interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff; + break; + case 2: + interpolatedEff = mLUTEntry[ipdg][inch][irad][ieta][ipt]->eff2; + break; + default: + LOG(fatal) << " --- getLUTEntry: unknown efficiency type " << mWhatEfficiency; + } } return mLUTEntry[ipdg][inch][irad][ieta][ipt]; } //; @@ -172,10 +232,14 @@ bool TrackSmearer::smearTrack(O2Track& o2track, lutEntry_t* lutEntry, float inte // generate efficiency if (mUseEfficiency) { auto eff = 0.; - if (mWhatEfficiency == 1) - eff = lutEntry->eff; - if (mWhatEfficiency == 2) - eff = lutEntry->eff2; + switch (mWhatEfficiency) { + case 1: + eff = lutEntry->eff; + break; + case 2: + eff = lutEntry->eff2; + break; + } if (mInterpolateEfficiency) eff = interpolatedEff; if (gRandom->Uniform() > eff) @@ -187,26 +251,28 @@ bool TrackSmearer::smearTrack(O2Track& o2track, lutEntry_t* lutEntry, float inte return false; // transform params vector and smear - double params_[5]; - for (int i = 0; i < 5; ++i) { + static constexpr int kParSize = 5; + double params[kParSize]; + for (int i = 0; i < kParSize; ++i) { double val = 0.; - for (int j = 0; j < 5; ++j) + for (int j = 0; j < kParSize; ++j) val += lutEntry->eigvec[j][i] * o2track.getParam(j); - params_[i] = gRandom->Gaus(val, sqrt(lutEntry->eigval[i])); + params[i] = gRandom->Gaus(val, std::sqrt(lutEntry->eigval[i])); } // transform back params vector - for (int i = 0; i < 5; ++i) { + for (int i = 0; i < kParSize; ++i) { double val = 0.; - for (int j = 0; j < 5; ++j) - val += lutEntry->eiginv[j][i] * params_[j]; + for (int j = 0; j < kParSize; ++j) + val += lutEntry->eiginv[j][i] * params[j]; o2track.setParam(val, i); } // should make a sanity check that par[2] sin(phi) is in [-1, 1] - if (fabs(o2track.getParam(2)) > 1.) { - std::cout << " --- smearTrack failed sin(phi) sanity check: " << o2track.getParam(2) << std::endl; + if (std::fabs(o2track.getParam(2)) > 1.) { + LOG(info) << " --- smearTrack failed sin(phi) sanity check: " << o2track.getParam(2) << std::endl; } // set covariance matrix - for (int i = 0; i < 15; ++i) + static constexpr int kCovMatSize = 15; + for (int i = 0; i < kCovMatSize; ++i) o2track.setCov(lutEntry->covm[i], i); return isReconstructed; } @@ -217,12 +283,15 @@ bool TrackSmearer::smearTrack(O2Track& o2track, int pdg, float nch) { auto pt = o2track.getPt(); - if (abs(pdg) == 1000020030) { - pt *= 2.f; + switch (pdg) { + case o2::constants::physics::kHelium3: + case -o2::constants::physics::kHelium3: + pt *= 2.f; + break; } auto eta = o2track.getEta(); float interpolatedEff = 0.0f; - auto lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, interpolatedEff); + lutEntry_t* lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, interpolatedEff); if (!lutEntry || !lutEntry->valid) return false; return smearTrack(o2track, lutEntry, interpolatedEff); @@ -230,48 +299,48 @@ bool TrackSmearer::smearTrack(O2Track& o2track, int pdg, float nch) /*****************************************************************/ // relative uncertainty on pt -double TrackSmearer::getPtRes(int pdg, float nch, float eta, float pt) +double TrackSmearer::getPtRes(const int pdg, const float nch, const float eta, const float pt) { float dummy = 0.0f; - auto lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, dummy); - auto val = sqrt(lutEntry->covm[14]) * lutEntry->pt; + lutEntry_t* lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, dummy); + auto val = std::sqrt(lutEntry->covm[14]) * lutEntry->pt; return val; } /*****************************************************************/ // relative uncertainty on eta -double TrackSmearer::getEtaRes(int pdg, float nch, float eta, float pt) +double TrackSmearer::getEtaRes(const int pdg, const float nch, const float eta, const float pt) { float dummy = 0.0f; - auto lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, dummy); - auto sigmatgl = sqrt(lutEntry->covm[9]); // sigmatgl2 - auto etaRes = fabs(sin(2.0 * atan(exp(-eta)))) * sigmatgl; // propagate tgl to eta uncertainty - etaRes /= lutEntry->eta; // relative uncertainty + lutEntry_t* lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, dummy); + auto sigmatgl = std::sqrt(lutEntry->covm[9]); // sigmatgl2 + auto etaRes = std::fabs(std::sin(2.0 * std::atan(std::exp(-eta)))) * sigmatgl; // propagate tgl to eta uncertainty + etaRes /= lutEntry->eta; // relative uncertainty return etaRes; } /*****************************************************************/ // absolute uncertainty on pt -double TrackSmearer::getAbsPtRes(int pdg, float nch, float eta, float pt) +double TrackSmearer::getAbsPtRes(const int pdg, const float nch, const float eta, const float pt) { float dummy = 0.0f; - auto lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, dummy); - auto val = sqrt(lutEntry->covm[14]) * pow(lutEntry->pt, 2); + lutEntry_t* lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, dummy); + auto val = std::sqrt(lutEntry->covm[14]) * lutEntry->pt * lutEntry->pt; return val; } /*****************************************************************/ // absolute uncertainty on eta -double TrackSmearer::getAbsEtaRes(int pdg, float nch, float eta, float pt) +double TrackSmearer::getAbsEtaRes(const int pdg, const float nch, const float eta, const float pt) { float dummy = 0.0f; - auto lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, dummy); - auto sigmatgl = sqrt(lutEntry->covm[9]); // sigmatgl2 - auto etaRes = fabs(sin(2.0 * atan(exp(-eta)))) * sigmatgl; // propagate tgl to eta uncertainty + lutEntry_t* lutEntry = getLUTEntry(pdg, nch, 0., eta, pt, dummy); + auto sigmatgl = std::sqrt(lutEntry->covm[9]); // sigmatgl2 + auto etaRes = std::fabs(std::sin(2.0 * std::atan(std::exp(-eta)))) * sigmatgl; // propagate tgl to eta uncertainty return etaRes; } /*****************************************************************/ // efficiency -double TrackSmearer::getEfficiency(int pdg, float nch, float eta, float pt) +double TrackSmearer::getEfficiency(const int pdg, const float nch, const float eta, const float pt) { float efficiency = 0.0f; getLUTEntry(pdg, nch, 0., eta, pt, efficiency); @@ -292,7 +361,7 @@ double TrackSmearer::getEfficiency(int pdg, float nch, float eta, float pt) // return true; // #if 0 -// auto lutEntry = getLUTEntry(track.PID, 0., 0., track.Eta, track.PT); +// lutEntry_t* lutEntry = getLUTEntry(track.PID, 0., 0., track.Eta, track.PT); // if (!lutEntry) // return; diff --git a/ALICE3/Core/DelphesO2TrackSmearer.h b/ALICE3/Core/DelphesO2TrackSmearer.h index 1e0fd873e2c..027809fa004 100644 --- a/ALICE3/Core/DelphesO2TrackSmearer.h +++ b/ALICE3/Core/DelphesO2TrackSmearer.h @@ -24,12 +24,15 @@ #ifndef ALICE3_CORE_DELPHESO2TRACKSMEARER_H_ #define ALICE3_CORE_DELPHESO2TRACKSMEARER_H_ -#include -#include -#include +#include +#include -#include "TRandom.h" -#include "ReconstructionDataFormats/Track.h" +#include + +#include +#include +#include +#include /////////////////////////////// /// DelphesO2/src/lutCovm.hh // @@ -85,7 +88,7 @@ struct map_t { if (bin > nbins - 1) return nbins - 1; return bin; - } //; + } //; void print() { printf("nbins = %d, min = %f, max = %f, log = %s \n", nbins, min, max, log ? "on" : "off"); } //; }; @@ -177,23 +180,24 @@ class TrackSmearer /** LUT methods **/ bool loadTable(int pdg, const char* filename, bool forceReload = false); - void useEfficiency(bool val) { mUseEfficiency = val; } //; - void interpolateEfficiency(bool val) { mInterpolateEfficiency = val; } //; - void skipUnreconstructed(bool val) { mSkipUnreconstructed = val; } //; - void setWhatEfficiency(int val) { mWhatEfficiency = val; } //; - lutHeader_t* getLUTHeader(int pdg) { return mLUTHeader[getIndexPDG(pdg)]; } //; - lutEntry_t* getLUTEntry(int pdg, float nch, float radius, float eta, float pt, float& interpolatedEff); + bool hasTable(int pdg) { return (mLUTHeader[getIndexPDG(pdg)] != nullptr); } //; + void useEfficiency(bool val) { mUseEfficiency = val; } //; + void interpolateEfficiency(bool val) { mInterpolateEfficiency = val; } //; + void skipUnreconstructed(bool val) { mSkipUnreconstructed = val; } //; + void setWhatEfficiency(int val) { mWhatEfficiency = val; } //; + lutHeader_t* getLUTHeader(int pdg) { return mLUTHeader[getIndexPDG(pdg)]; } //; + lutEntry_t* getLUTEntry(const int pdg, const float nch, const float radius, const float eta, const float pt, float& interpolatedEff); bool smearTrack(O2Track& o2track, lutEntry_t* lutEntry, float interpolatedEff); bool smearTrack(O2Track& o2track, int pdg, float nch); // bool smearTrack(Track& track, bool atDCA = true); // Only in DelphesO2 - double getPtRes(int pdg, float nch, float eta, float pt); - double getEtaRes(int pdg, float nch, float eta, float pt); - double getAbsPtRes(int pdg, float nch, float eta, float pt); - double getAbsEtaRes(int pdg, float nch, float eta, float pt); - double getEfficiency(int pdg, float nch, float eta, float pt); + double getPtRes(const int pdg, const float nch, const float eta, const float pt); + double getEtaRes(const int pdg, const float nch, const float eta, const float pt); + double getAbsPtRes(const int pdg, const float nch, const float eta, const float pt); + double getAbsEtaRes(const int pdg, const float nch, const float eta, const float pt); + double getEfficiency(const int pdg, const float nch, const float eta, const float pt); - int getIndexPDG(int pdg) + int getIndexPDG(const int pdg) { switch (abs(pdg)) { case 11: @@ -212,15 +216,43 @@ class TrackSmearer return 6; // Triton case 1000020030: return 7; // Helium3 + case 1000020040: + return 8; // Alphas default: return 2; // Default: pion - } //; - } //; + } + } - void setdNdEta(float val) { mdNdEta = val; } //; + const char* getParticleName(int pdg) + { + switch (abs(pdg)) { + case 11: + return "electron"; + case 13: + return "muon"; + case 211: + return "pion"; + case 321: + return "kaon"; + case 2212: + return "proton"; + case 1000010020: + return "deuteron"; + case 1000010030: + return "triton"; + case 1000020030: + return "helium3"; + case 1000020040: + return "alpha"; + default: + return "pion"; // Default: pion + } + } + void setdNdEta(float val) { mdNdEta = val; } //; + void setCcdbManager(o2::ccdb::BasicCCDBManager* mgr) { mCcdbManager = mgr; } //; protected: - static constexpr unsigned int nLUTs = 8; // Number of LUT available + static constexpr unsigned int nLUTs = 9; // Number of LUT available lutHeader_t* mLUTHeader[nLUTs] = {nullptr}; lutEntry_t***** mLUTEntry[nLUTs] = {nullptr}; bool mUseEfficiency = true; @@ -228,6 +260,9 @@ class TrackSmearer bool mSkipUnreconstructed = true; // don't smear tracks that are not reco'ed int mWhatEfficiency = 1; float mdNdEta = 1600.; + + private: + o2::ccdb::BasicCCDBManager* mCcdbManager = nullptr; }; } // namespace delphes diff --git a/ALICE3/Core/DetLayer.cxx b/ALICE3/Core/DetLayer.cxx new file mode 100644 index 00000000000..b9757de2d2f --- /dev/null +++ b/ALICE3/Core/DetLayer.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. + +/// +/// \file DetLayer.cxx +/// \author David Dobrigkeit Chinellato +/// \since 11/03/2021 +/// \brief Basic struct to hold information regarding a detector layer to be used in fast simulation +/// + +#include "DetLayer.h" + +#include +#include + +#include +#include + +namespace o2::fastsim +{ + +// Parametric constructor +DetLayer::DetLayer(const TString& name_, + float r_, + float z_, + float x0_, + float xrho_, + float resRPhi_, + float resZ_, + float eff_, + int type_) + : name(name_), + r(r_), + z(z_), + x0(x0_), + xrho(xrho_), + resRPhi(resRPhi_), + resZ(resZ_), + eff(eff_), + type(type_) +{ +} + +DetLayer::DetLayer(const DetLayer& other) + : name(other.name), r(other.r), z(other.z), x0(other.x0), xrho(other.xrho), resRPhi(other.resRPhi), resZ(other.resZ), eff(other.eff), type(other.type) +{ +} + +void DetLayer::addDeadPhiRegion(float phiStart, float phiEnd) +{ + static constexpr float kDefaultValue = 2.f; + static constexpr float kPhiTolerance = 1e-4f; + if (mDeadPhiRegions == nullptr) { + mDeadPhiRegions = new TGraph(); + mDeadPhiRegions->SetNameTitle(Form("deadPhiRegions_%s", name.Data()), Form("Dead phi regions for layer %s", name.Data())); + mDeadPhiRegions->AddPoint(0, kDefaultValue); + mDeadPhiRegions->AddPoint(o2::constants::math::TwoPI, kDefaultValue); + } + if (phiStart < 0 || phiStart >= o2::constants::math::TwoPI || phiEnd < 0 || phiEnd >= o2::constants::math::TwoPI) { + LOG(fatal) << "Cannot add dead phi region with invalid range [" << phiStart << ", " << phiEnd << "] to layer " << name; + return; + } + mDeadPhiRegions->AddPoint(phiStart, kDefaultValue); + mDeadPhiRegions->AddPoint(phiEnd, kDefaultValue); + mDeadPhiRegions->AddPoint(phiStart + kPhiTolerance, 0.f); + mDeadPhiRegions->AddPoint(phiEnd - kPhiTolerance, 0.f); + mDeadPhiRegions->Sort(); +} + +void DetLayer::setDeadPhiRegions(TGraph* graph) +{ + LOG(debug) << "Setting dead phi regions for layer " << name << " with graph " << (graph ? graph->GetName() : "nullptr"); + if (mDeadPhiRegions != nullptr) { + LOG(warning) << "Overriding existing dead phi regions for layer " << name; + delete mDeadPhiRegions; + } + mDeadPhiRegions = graph; + if (mDeadPhiRegions->GetN() == 0) { + LOG(warning) << "Dead phi regions graph for layer " << name << " is empty, clearing dead regions"; + mDeadPhiRegions = nullptr; + return; // cleared the dead regions + } + // Check sanity of the graph + if (mDeadPhiRegions != nullptr) { + for (int i = 0; i < mDeadPhiRegions->GetN(); i++) { + const float x = mDeadPhiRegions->GetX()[i]; + const float y = mDeadPhiRegions->GetY()[i]; + // First point has to be at 0, last point has to be at 2PI + if ((i == 0 && x != 0.f) || (i == mDeadPhiRegions->GetN() - 1 && x != o2::constants::math::TwoPI)) { + LOG(fatal) << "Dead phi regions graph for layer " << name << " has invalid x value " << x << " at point " << i << ", first point should be 0 and last point should be 2PI"; + } + LOG(debug) << "Point " << i << ": (" << x << ", " << y << ")"; + if (x < 0 || x > o2::constants::math::TwoPI) { + LOG(fatal) << "Dead phi regions graph for layer " << name << " has invalid x value " << x << " at point " << i; + } + if (y != 0.f && y != 2.f) { + LOG(fatal) << "Dead phi regions graph for layer " << name << " has invalid y value " << y << " at point " << i << ", should be 0 or 2"; + } + } + } else { + LOG(info) << "Cleared dead phi regions for layer " << name; + } +} + +std::string DetLayer::toString() const +{ + std::string out = ""; + out.append("DetLayer: "); + out.append(name.Data()); + out.append(" | r: "); + out.append(std::to_string(r)); + out.append(" cm | z: "); + out.append(std::to_string(z)); + out.append(" cm | x0: "); + out.append(std::to_string(x0)); + out.append(" cm | xrho: "); + out.append(std::to_string(xrho)); + out.append(" g/cm^3 | resRPhi: "); + out.append(std::to_string(resRPhi)); + out.append(" cm | resZ: "); + out.append(std::to_string(resZ)); + out.append(" cm | eff: "); + out.append(std::to_string(eff)); + out.append(" | type: "); + switch (type) { + case layerInert: + out.append("Inert"); + break; + case layerSilicon: + out.append("Silicon"); + break; + case layerGas: + out.append("Gas/TPC"); + break; + default: + out.append("Unknown"); + break; + } + return out; +} + +} // namespace o2::fastsim diff --git a/ALICE3/Core/DetLayer.h b/ALICE3/Core/DetLayer.h new file mode 100644 index 00000000000..1efc730c0d5 --- /dev/null +++ b/ALICE3/Core/DetLayer.h @@ -0,0 +1,127 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 +#include + +#include + +namespace o2::fastsim +{ + +struct DetLayer { + public: + // Default constructor + DetLayer() = default; + // Parametric constructor + DetLayer(const TString& name_, float r_, float z_, float x0_, float xrho_, + float resRPhi_ = 0.0f, float resZ_ = 0.0f, float eff_ = 0.0f, int type_ = layerInert); + // Copy constructor + DetLayer(const DetLayer& other); + + // Setters + void setName(const TString& name_) { name = name_; } + void setRadius(float r_) { r = r_; } + void setZ(float z_) { z = z_; } + void setRadiationLength(float x0_) { x0 = x0_; } + void setDensity(float xrho_) { xrho = xrho_; } + void setResolutionRPhi(float resRPhi_) { resRPhi = resRPhi_; } + void setResolutionZ(float resZ_) { resZ = resZ_; } + void setEfficiency(float eff_) { eff = eff_; } + void setType(int type_) { type = type_; } + + // Dead areas + + /// @brief Add a dead region in phi for this layer + /// @param phiStart starting angle in radians of the dead region + /// @param phiEnd ending angle in radians of the dead region + void addDeadPhiRegion(float phiStart, float phiEnd); + + /// @brief Set the dead regions in phi for this layer with a TGraph containing all regions. The graph should have y=2 for dead regions and y=0 for alive regions. + /// @param graph graph of the dead regions. Can be nullptr to clear the dead regions. + void setDeadPhiRegions(TGraph* graph); + + // Getters + float getRadius() const { return r; } + float getZ() const { return z; } + float getRadiationLength() const { return x0; } + float getDensity() const { return xrho; } + float getResolutionRPhi() const { return resRPhi; } + float getResolutionZ() const { return resZ; } + float getEfficiency() const { return eff; } + int getType() const { return type; } + const TString& getName() const { return name; } + const TGraph* getDeadPhiRegions() const { return mDeadPhiRegions; } + + // Check layer type + bool isInert() const { return type == layerInert; } + bool isSilicon() const { return type == layerSilicon; } + bool isGas() const { return type == layerGas; } + + // Utilities + std::string toString() const; + friend std::ostream& operator<<(std::ostream& os, const DetLayer& layer) + { + os << layer.toString(); + return os; + } + /// @brief Check if a given phi angle is in a dead region + /// @param phi The phi angle to check + /// @return True if the phi angle is in a dead region, false otherwise + bool isInDeadPhiRegion(float phi) const + { + if (mDeadPhiRegions == nullptr) + return false; + return mDeadPhiRegions->Eval(phi) > 1.f; + }; + + private: + // 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 + + // dead regions in phi (in radians) + TGraph* mDeadPhiRegions = nullptr; + + // layer type + int type; // 0: undefined/inert, 1: silicon, 2: gas/tpc + static constexpr int layerInert = 0; // inert/undefined layer + static constexpr int layerSilicon = 1; // silicon layer + static constexpr int layerGas = 2; // gas/tpc layer +}; + +} // 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..ef45e99ca01 --- /dev/null +++ b/ALICE3/Core/FastTracker.cxx @@ -0,0 +1,755 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "FastTracker.h" + +#include "ReconstructionDataFormats/TrackParametrization.h" + +#include "TMath.h" +#include "TMatrixD.h" +#include "TMatrixDSymEigen.h" +#include "TRandom.h" +#include +#include +#include + +#include +#include +#include +#include + +namespace o2 +{ +namespace fastsim +{ + +// +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + +DetLayer* FastTracker::AddLayer(TString name, float r, float z, float x0, float xrho, float resRPhi, float resZ, float eff, int type) +{ + LOG(debug) << "Adding layer " << name << " r=" << r << " z=" << z << " x0=" << x0 << " xrho=" << xrho << " resRPhi=" << resRPhi << " resZ=" << resZ << " eff=" << eff << " type=" << type; + DetLayer newLayer(name, r, z, x0, xrho, resRPhi, resZ, eff, type); + // Check that efficient layers are not inert layers + if (newLayer.getEfficiency() > 0.0f && newLayer.isInert()) { + LOG(error) << "Layer " << name << " with efficiency > 0.0 should not be inert"; + } + // Layers should be ordered by increasing radius, check this + if (!layers.empty() && newLayer.getRadius() < layers.back().getRadius()) { + LOG(fatal) << "Layer " << newLayer << " is not ordered correctly, it should be after layer " << layers.back(); + } + // Layers should all have different names + for (const auto& layer : layers) { + if (layer.getName() == newLayer.getName()) { + LOG(fatal) << "Layer with name " << newLayer.getName() << " already exists in FastTracker layers"; + } + } + // Add the new layer to the layers vector + layers.push_back(newLayer); + // Return the last added layer + return &layers.back(); +} + +void FastTracker::addDeadPhiRegionInLayer(const std::string& layerName, float phiStart, float phiEnd) +{ + const int layerIdx = GetLayerIndex(layerName); + if (layerIdx < 0) { + LOG(fatal) << "Cannot add dead phi region to non-existing layer " << layerName; + return; + } + layers[layerIdx].addDeadPhiRegion(phiStart, phiEnd); +} + +int FastTracker::GetLayerIndex(const std::string& name) const +{ + int i = 0; + for (const auto& layer : layers) { + if (layer.getName() == name) { + return i; + } + i++; + } + LOG(error) << "Layer with name " << name << " not found in FastTracker layers"; + return -1; +} + +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]; + } + 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]; + + AddLayer("bpipe0", 0.48, 250, 0.00042, 2.772e-02, 0.0f, 0.0f, 0.0f, 0); // 150 mum Be + AddLayer("ddd0", 0.5, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1); + AddLayer("ddd1", 1.2, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1); + AddLayer("ddd2", 2.5, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1); + AddLayer("bpipe1", 5.7, 250, 0.0014, 9.24e-02, 0.0f, 0.0f, 0.0f, 0); // 500 mum Be + AddLayer("ddd3", 7., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("ddd4", 10., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("ddd5", 13., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("ddd6", 16., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("ddd7", 25., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("ddd8", 40., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("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]; + + AddLayer("bpipe0", 0.48, 250, 0.00042, 2.772e-02, 0.0f, 0.0f, 0.0f, 0); // 150 mum Be + AddLayer("B00", 0.5, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1); + AddLayer("B01", 1.2, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1); + AddLayer("B02", 2.5, 250, x0IT, xrhoIB, resRPhiIT, resZIT, eff, 1); + AddLayer("bpipe1", 3.7, 250, 0.0014, 9.24e-02, 0.0f, 0.0f, 0.0f, 0); // 500 mum Be + AddLayer("B03", 3.75, 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B04", 7., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B05", 12., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B06", 20., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B07", 30., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B08", 45., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B09", 60., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B10", 80., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); +} + +void FastTracker::AddSiliconALICE3(float scaleX0VD, std::vector pixelResolution) +{ + float x0Pipe0 = 0.001592; // 200 um AlBe + float x0VDL0 = 0.00076; // 30 um Si + 50 um glue + carbon foam 0.03% + float x0VDL1 = 0.00096; // 30 um Si + 50 um glue + carbon foam 0.05% + float x0VDL2 = 0.00167; // 30 um Si + 50 um glue + carbon foam 0.05% + 0.07% Be case + float x0Coldplate = 0.02f; // (1.5 mm Al2O3 2%) + float x0Pipe1 = 0.0023f; // 800 um Be + float x0OT = 0.01; // 1.0% + float x0iTOF = x0OT * 3.; + + float resRPhiVD = pixelResolution[0]; + float resZVD = pixelResolution[1]; + float resRPhiOT = pixelResolution[2]; + float resZOT = pixelResolution[3]; + + float xrhoPipe0 = 0; + float xrhoVDL0 = 0; + float xrhoVDL1 = 0; + float xrhoVDL2 = 0; + float xrhoColdplate = 0; + float xrhoPipe1 = 0; + float xrhoOT = 2.3292e-01; + float xrhoiTOF = 0.03; + float eff = 1.00; + + AddLayer("bpipe0", 0.48, 250, x0Pipe0, xrhoPipe0, 0.0f, 0.0f, 0.0f, 0); + AddLayer("B00", 0.5, 250, x0VDL0 * scaleX0VD, xrhoVDL0, resRPhiVD, resZVD, eff, 1); + AddLayer("B01", 1.2, 250, x0VDL1 * scaleX0VD, xrhoVDL1, resRPhiVD, resZVD, eff, 1); + AddLayer("B02", 2.5, 250, x0VDL2 * scaleX0VD, xrhoVDL2, resRPhiVD, resZVD, eff, 1); + AddLayer("coldplate", 2.6, 250, x0Coldplate, xrhoColdplate, 0.0f, 0.0f, 0.0f, 0); + AddLayer("bpipe1", 5.7, 250, x0Pipe1, xrhoPipe1, 0.0f, 0.0f, 0.0f, 0); + AddLayer("B03", 7., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B04", 9., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B05", 12., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("iTOF", 19, 250, x0iTOF, xrhoiTOF, resRPhiOT, resZOT, eff, 0); + AddLayer("B06", 20., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B07", 30., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B08", 45., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("B09", 60., 250, x0OT, xrhoOT, resRPhiOT, resZOT, eff, 1); + AddLayer("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); + } +} + +void FastTracker::AddGenericDetector(std::string filename, o2::ccdb::BasicCCDBManager* ccdbManager) +{ + LOG(info) << " Adding generic detector from file " << filename; + // If the filename starts with ccdb: then take the file from the ccdb + if (filename.rfind("ccdb:", 0) == 0) { + std::string ccdbPath = filename.substr(5); // remove "ccdb:" prefix + if (ccdbManager == nullptr) { + LOG(fatal) << "CCDB manager is null, cannot retrieve file " << ccdbPath; + return; + } + const std::string outPath = "/tmp/DetGeo/"; + filename = Form("%s/%s/snapshot.root", outPath.c_str(), ccdbPath.c_str()); + std::ifstream checkFile(filename); // Check if file already exists + if (!checkFile.is_open()) { // File does not exist, retrieve from CCDB + LOG(info) << " --- CCDB source detected for detector geometry " << filename; + std::map metadata; + ccdbManager->getCCDBAccessor().retrieveBlob(ccdbPath, outPath, metadata, 1); + // Add CCDB handling logic here if needed + LOG(info) << " --- Now retrieving geometry configuration from CCDB to: " << filename; + } else { // File exists, proceed to load + LOG(info) << " --- Geometry configuration file already exists: " << filename << ". Skipping download."; + checkFile.close(); + } + AddGenericDetector(filename, nullptr); + return; + } + + TEnv env(filename.c_str()); + THashList* table = env.GetTable(); + std::vector layers; + for (int i = 0; i < table->GetEntries(); ++i) { + const std::string key = table->At(i)->GetName(); + // key should contain exactly one dot + if (key.find('.') == std::string::npos || key.find('.') != key.rfind('.')) { + LOG(fatal) << "Key " << key << " does not contain exactly one dot"; + continue; + } + const std::string firstPart = key.substr(0, key.find('.')); + if (std::find(layers.begin(), layers.end(), firstPart) == layers.end()) { + layers.push_back(firstPart); + } + } + // env.Print(); + // Layers + for (const auto& layer : layers) { + LOG(info) << " Reading layer " << layer; + + auto getKey = [&layer, &env](const std::string& name, const bool required = true) { + std::string key = layer + "." + name; + if (!env.Defined(key.c_str())) { + if (required) { + LOG(fatal) << "Key " << key << " not defined in configuration file"; + } + LOG(debug) << "Key " << key << " not defined in configuration file, getting the default value"; + } + LOG(debug) << " Getting key " << key << " from configuration file"; + return key; + }; + const float r = env.GetValue(getKey("r").c_str(), -1.0f); + LOG(info) << " Layer " << layer << " has radius " << r; + const float z = env.GetValue(getKey("z").c_str(), -1.0f); + const float x0 = env.GetValue(getKey("x0").c_str(), 0.0f); + const float xrho = env.GetValue(getKey("xrho").c_str(), 0.0f); + const float resRPhi = env.GetValue(getKey("resRPhi").c_str(), 0.0f); + const float resZ = env.GetValue(getKey("resZ").c_str(), 0.0f); + const float eff = env.GetValue(getKey("eff").c_str(), 0.0f); + const int type = env.GetValue(getKey("type").c_str(), 0); + const char* deadPhiRegions = env.GetValue(getKey("deadPhiRegions", false).c_str(), ""); + + // 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); + LOG(info) << " Adding layer " << layer << " r=" << r << " z=" << z << " x0=" << x0 << " xrho=" << xrho << " resRPhi=" << resRPhi << " resZ=" << resZ << " eff=" << eff << " type=" << type << " deadPhiRegions=" << deadPhiRegions; + + DetLayer* addedLayer = AddLayer(layer.c_str(), r, z, x0, xrho, resRPhi, resZ, eff, type); + if (strlen(deadPhiRegions) > 0) { // Taking it as ccdb path or local file + // Check if it begins with ccdb: + if (std::string(deadPhiRegions).rfind("ccdb:", 0) == 0) { + std::string ccdbPath = std::string(deadPhiRegions).substr(5); // remove "ccdb:" prefix + if (ccdbManager == nullptr) { + LOG(fatal) << "CCDB manager is null, cannot retrieve file " << ccdbPath; + return; + } + TGraph* g = ccdbManager->getForTimeStamp(ccdbPath, -1); + addedLayer->setDeadPhiRegions(g); + } else { + // Taking it as local file + TFile infile(deadPhiRegions, "READ"); + if (!infile.IsOpen()) { + LOG(fatal) << "Cannot open dead phi regions file " << deadPhiRegions; + return; + } + TGraph* g = reinterpret_cast(infile.Get(infile.GetListOfKeys()->At(0)->GetName())); + infile.Close(); + addedLayer->setDeadPhiRegions(g); + } + } else { + LOG(debug) << " No dead phi regions for layer " << layer; + } + } +} + +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; + float dist = 0.0; + float dz0 = (4 * sigmaD - (-4) * sigmaD / (nSteps = 1)); + float 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) * std::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 * mCrossSectionMinB; + 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, const float nch) +{ + dNdEtaCent = nch; // set the number of charged particles per unit rapidity + 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; + + int firstActiveLayer = -1; // first layer that is not inert + for (size_t i = 0; i < layers.size(); ++i) { + if (!layers[i].isInert()) { + firstActiveLayer = i; + break; + } + } + if (firstActiveLayer < 0) { + LOG(fatal) << "No active layers found in FastTracker, check layer setup"; + return -2; // no active layers + } + const int xrhosteps = 100; + const bool applyAngularCorrection = true; + + // Delphes sets this to 20 instead of the number of layers, + // but does not count all points in the tpc as layers which we do here + // Loop over all the added layers to prevent crash when adding the tpc + // Should not affect efficiency calculation + goodHitProbability.clear(); + for (size_t i = 0; i < layers.size(); ++i) { + goodHitProbability.push_back(-1.); + } + goodHitProbability[0] = 1.; // we use layer zero to accumulate + + // +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ + // Outward pass to find intercepts + int firstLayerReached = -1; + int lastLayerReached = -1; + new (&outputTrack)(o2::track::TrackParCov)(inputTrack); + for (size_t il = 0; il < layers.size(); il++) { + // check if layer is doable + if (layers[il].getRadius() < initialRadius) { + continue; // this layer should not be attempted, but go ahead + } + + // check if layer is reached + float targetX = 1e+3; + inputTrack.getXatLabR(layers[il].getRadius(), targetX, magneticField); + if (targetX > 999.f) { + LOGF(debug, "Failed to find intercept for layer %d at radius %.2f cm", il, layers[il].getRadius()); + break; // failed to find intercept + } + + bool ok = inputTrack.propagateTo(targetX, magneticField); + if (ok && mApplyMSCorrection && layers[il].getRadiationLength() > 0) { + ok = inputTrack.correctForMaterial(layers[il].getRadiationLength(), 0, applyAngularCorrection); + } + if (ok && mApplyElossCorrection && layers[il].getDensity() > 0) { // correct in small steps + for (int ise = xrhosteps; ise--;) { + ok = inputTrack.correctForMaterial(0, -layers[il].getDensity() / xrhosteps, applyAngularCorrection); + if (!ok) + break; + } + } + LOGF(debug, "Propagation was %s up to layer %d", ok ? "successful" : "unsuccessful", il); + + // 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 maxR = layers[il - 1].getRadius() + 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].getZ() && mApplyZacceptance) { + break; // out of acceptance bounds + } + + if (layers[il].isInert()) { + if (mVerboseLevel > 0) { + LOG(info) << "Skipping inert layer: " << layers[il].getName() << " at radius " << layers[il].getRadius() << " cm"; + } + continue; // inert layer, skip + } + + if (layers[il].isInDeadPhiRegion(inputTrack.getPhi())) { + LOGF(debug, "Track is in dead region of layer %d", il); + continue; // dead region, skip + } + + // layer is reached + if (firstLayerReached < 0) { + LOGF(debug, "First layer reached: %d", il); + 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 < o2::track::kNParams; ip++) { + trPars[ip] = outputTrack.getParam(ip); + } + static constexpr float kLargeErr2Coord = 5 * 5; + static constexpr float kLargeErr2Dir = 0.7 * 0.7; + static constexpr float kLargeErr2PtI = 30.5 * 30.5; + std::array largeCov = {0.}; + for (int ic = o2::track::kCovMatSize; ic--;) + largeCov[ic] = 0.; + largeCov[o2::track::CovLabels::kSigY2] = largeCov[o2::track::CovLabels::kSigZ2] = kLargeErr2Coord; + largeCov[o2::track::CovLabels::kSigSnp2] = largeCov[o2::track::CovLabels::kSigTgl2] = kLargeErr2Dir; + largeCov[o2::track::CovLabels::kSigQ2Pt2] = kLargeErr2PtI * trPars[o2::track::ParLabels::kQ2Pt] * trPars[o2::track::ParLabels::kQ2Pt]; + + 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].getRadius(), 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].getZ() && mApplyZacceptance) { + 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 + float alpha = inwardTrack.getAlpha(); + float xyz1[3]{ + std::cos(alpha) * spacePoint[0] + std::sin(alpha) * spacePoint[1], + -std::sin(alpha) * spacePoint[0] + std::cos(alpha) * spacePoint[1], + spacePoint[2]}; + if (!inwardTrack.propagateTo(xyz1[0], magneticField)) + continue; + + if (!layers[il].isInert()) { // 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].getResolutionRPhi() * layers[il].getResolutionRPhi(), 0.f, layers[il].getResolutionZ() * layers[il].getResolutionZ()}; + + inwardTrack.update(hitpoint, hitpointcov); + inwardTrack.checkCovariance(); + } + + if (mApplyMSCorrection && layers[il].getRadiationLength() > 0) { + if (!inputTrack.correctForMaterial(layers[il].getRadiationLength(), 0, applyAngularCorrection)) { + return -6; + } + if (!inwardTrack.correctForMaterial(layers[il].getRadiationLength(), 0, applyAngularCorrection)) { + return -6; + } + } + if (mApplyElossCorrection && layers[il].getDensity() > 0) { + for (int ise = xrhosteps; ise--;) { // correct in small steps + if (!inputTrack.correctForMaterial(0, layers[il].getDensity() / xrhosteps, applyAngularCorrection)) { + return -7; + } + if (!inwardTrack.correctForMaterial(0, layers[il].getDensity() / xrhosteps, applyAngularCorrection)) { + return -7; + } + } + } + + if (layers[il].isSilicon()) + nSiliconPoints++; // count silicon hits + if (layers[il].isGas()) + nGasPoints++; // count TPC/gas hits + + hits.push_back(thisHit); + + if (!layers[il].isInert()) { // good hit probability calculation + float sigYCmb = o2::math_utils::sqrt(inwardTrack.getSigmaY2() + layers[il].getResolutionRPhi() * layers[il].getResolutionRPhi()); + float sigZCmb = o2::math_utils::sqrt(inwardTrack.getSigmaZ2() + layers[il].getResolutionZ() * layers[il].getResolutionZ()); + goodHitProbability[il] = ProbGoodChiSqHit(layers[il].getRadius() * 100, sigYCmb * 100, sigZCmb * 100); + goodHitProbability[0] *= goodHitProbability[il]; + } + } + + // backpropagate to original radius + float finalX = 1e+3; + bool inPropStatus = inwardTrack.getXatLabR(initialRadius, finalX, magneticField); + if (finalX > 999) { + LOG(debug) << "Failed to find intercept for initial radius " << initialRadius << " cm, x = " << finalX << " and status " << inPropStatus << " and sn = " << inwardTrack.getSnp() << " r = " << inwardTrack.getY() * inwardTrack.getY(); + 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 + float eff = 1.; + for (size_t i = 0; i < layers.size(); i++) { + float iGoodHit = goodHitProbability[i]; + if (iGoodHit <= 0) + continue; + + eff *= iGoodHit; + } + if (mApplyEffCorrection) { + 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 < o2::track::kCovMatSize; ii++) + covMat[ii] = outputTrack.getCov()[ii]; + TMatrixDSym m(5); + double fcovm[5][5]; // double precision is needed for regularisation + + 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 + const 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 (mVerboseLevel > 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 + float params_[5]; + for (int ii = 0; ii < 5; ++ii) { + float 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) { + float 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..d4d88cb13d9 --- /dev/null +++ b/ALICE3/Core/FastTracker.h @@ -0,0 +1,179 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "DetLayer.h" + +#include +#include + +#include + +#include +#include + +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() = default; + // Destructor + virtual ~FastTracker() {} + + // Layer and layer configuration + DetLayer* 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); + + /// Add a dead region in phi for a specific layer + /// \param layerName Name of the layer to modify + /// \param phiStart Start angle of the dead region (in radians) + /// \param phiEnd End angle of the dead region (in radians) + void addDeadPhiRegionInLayer(const std::string& layerName, float phiStart, float phiEnd); + DetLayer GetLayer(const int layer) const { return layers[layer]; } + std::vector GetLayers() const { return layers; } + int GetLayerIndex(const std::string& name) const; + size_t GetNLayers() const { return layers.size(); } + bool IsLayerInert(const int layer) const { return layers[layer].isInert(); } + void ClearLayers() { layers.clear(); } + void SetRadiationLength(const std::string layerName, float x0) { layers[GetLayerIndex(layerName)].setRadiationLength(x0); } + void SetRadius(const std::string layerName, float r) { layers[GetLayerIndex(layerName)].setRadius(r); } + void SetResolutionRPhi(const std::string layerName, float resRPhi) { layers[GetLayerIndex(layerName)].setResolutionRPhi(resRPhi); } + void SetResolutionZ(const std::string layerName, float resZ) { layers[GetLayerIndex(layerName)].setResolutionZ(resZ); } + void SetResolution(const std::string layerName, float resRPhi, float resZ) + { + SetResolutionRPhi(layerName, resRPhi); + SetResolutionZ(layerName, resZ); + } + + void AddSiliconALICE3v4(std::vector pixelResolution); + void AddSiliconALICE3v2(std::vector pixelResolution); + void AddSiliconALICE3(float scaleX0VD, std::vector pixelResolution); + void AddTPC(float phiResMean, float zResMean); + /** + * @brief Adds a generic detector configuration from the specified file. + * + * This function loads and integrates a detector configuration into the tracker + * using the provided filename. The file should contain the necessary parameters + * and settings for the detector to be added. + * + * @param filename Path to the configuration file describing the detector. + * @param ccdbManager Pointer to a BasicCCDBManager instance for database access (if needed). + */ + void AddGenericDetector(std::string filename, o2::ccdb::BasicCCDBManager* ccdbManager = nullptr); + + void Print(); + + /** + * @brief Performs fast tracking on the input track parameters. + * + * Propagates the given input track through the detector layers, applying + * relevant corrections and updates, and stores the result in outputTrack. + * + * @param inputTrack The input track parameters and covariance (const, by value). + * @param outputTrack Reference to the output track parameters and covariance, to be filled. + * @param nch Charged particle multiplicity (used for hit density calculations). + * @return int i.e. number of intercepts (implementation-defined). + */ + int FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const 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); + + // Setters and getters for configuration + void SetIntegrationTime(float t) { integrationTime = t; } + void SetMaxRadiusOfSlowDetectors(float r) { maxRadiusSlowDet = r; } + void SetAvgRapidity(float y) { avgRapidity = y; } + void SetdNdEtaCent(int d) { dNdEtaCent = d; } + void SetLhcUPCscale(float s) { lhcUPCScale = s; } + void SetBField(float b) { magneticField = b; } + void SetMinRadTrack(float r) { fMinRadTrack = r; } + void SetMagneticField(float b) { magneticField = b; } + void SetApplyZacceptance(bool b) { mApplyZacceptance = b; } + void SetApplyMSCorrection(bool b) { mApplyMSCorrection = b; } + void SetApplyElossCorrection(bool b) { mApplyElossCorrection = b; } + void SetApplyEffCorrection(bool b) { mApplyEffCorrection = b; } + + // Getters for the last track + int GetNIntercepts() const { return nIntercepts; } + int GetNSiliconPoints() const { return nSiliconPoints; } + int GetNGasPoints() const { return nGasPoints; } + float GetGoodHitProb(int layer) const + { + return (layer >= 0 && static_cast(layer) < goodHitProbability.size()) ? goodHitProbability[layer] : 0.0f; + } + std::size_t GetNHits() const { return hits.size(); } + float GetHitX(const int i) const { return hits[i][0]; } + float GetHitY(const int i) const { return hits[i][1]; } + float GetHitZ(const int i) const { return hits[i][2]; } + uint64_t GetCovMatOK() const { return covMatOK; } + uint64_t GetCovMatNotOK() const { return covMatNotOK; } + + private: + // Definition of detector layers + std::vector layers; + std::vector> hits; // bookkeep last added hits + + /// configuration parameters + bool mApplyZacceptance = false; /// check z acceptance or not + bool mApplyMSCorrection = true; /// Apply correction for multiple scattering + bool mApplyElossCorrection = true; /// Apply correction for eloss (requires MS correction) + bool mApplyEffCorrection = true; /// Apply correction for hit efficiency + int mVerboseLevel = 0; /// 0: not verbose, >0 more verbose + const float mCrossSectionMinB = 8; /// Minimum bias Cross section for event under study (PbPb MinBias ~ 8 Barns) + int dNdEtaCent = 2200; /// dN/deta e.g. at centrality 0-5% (for 5 TeV PbPb) + int dNdEtaMinB = 1; /// dN/deta for minimum bias events + float integrationTime = 0.02f; /// Integration time in ms + float magneticField = 20.f; /// Magnetic field in kiloGauss (5 = 0.5T, 20 = 2T, etc) + float covMatFactor = 0.99f; /// covmat off-diagonal factor to use for covmat fix (negative: no factor) + float sigmaD = 6.0f; /// sigma for the detector resolution in cm + float luminosity = 1.e27f; /// luminosity in cm^-2 s^-1 (e.g. 1.e27 for PbPb at 5 TeV) + float otherBackground = 0.0f; /// background from other sources, e.g. pileup, in [0, 1] + float maxRadiusSlowDet = 10.f; /// maximum radius of slow detectors in cm + float avgRapidity = 0.45f; /// average rapidity for hit density calculation + float lhcUPCScale = 1.0f; /// scale factor for LHC UPC events + float upcBackgroundMultiplier = 1.0f; /// multiplier for UPC background + float fMinRadTrack = 132.f; /// minimum radius for track propagation in cm + + /// counters for covariance matrix statuses + uint64_t covMatOK = 0; /// cov mat has positive eigenvals + uint64_t covMatNotOK = 0; /// cov mat has negative eigenvals + + /// last track information + int nIntercepts = 0; /// found in first outward propagation + int nSiliconPoints = 0; /// silicon-based space points added to track + int nGasPoints = 0; /// 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..a5441d81cde --- /dev/null +++ b/ALICE3/Core/FastTrackerLinkDef.h @@ -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. + +#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 + ; +#pragma link C++ class o2::fastsim::DelphesO2LutWriter + ; + +#endif // ALICE3_CORE_FASTTRACKERLINKDEF_H_ diff --git a/ALICE3/Core/TrackUtilities.cxx b/ALICE3/Core/TrackUtilities.cxx new file mode 100644 index 00000000000..c07fe145ccf --- /dev/null +++ b/ALICE3/Core/TrackUtilities.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. +/// +/// \file TrackUtilities.cxx +/// \author Nicolò Jacazio, Universita del Piemonte Orientale (IT) +/// \brief Set of utilities for the ALICE3 track handling +/// \since May 21, 2025 +/// + +#include "TrackUtilities.h" + +#include + +void o2::upgrade::convertTLorentzVectorToO2Track(const int charge, + const TLorentzVector particle, + const std::vector productionVertex, + o2::track::TrackParCov& o2track) +{ + 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.; // since alpha = phi + const 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); +} diff --git a/ALICE3/Core/TrackUtilities.h b/ALICE3/Core/TrackUtilities.h new file mode 100644 index 00000000000..9bbc00c8f09 --- /dev/null +++ b/ALICE3/Core/TrackUtilities.h @@ -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 TrackUtilities.h +/// \author Nicolò Jacazio, Universita del Piemonte Orientale (IT) +/// \brief Set of utilities for the ALICE3 track handling +/// \since May 21, 2025 +/// + +#ifndef ALICE3_CORE_TRACKUTILITIES_H_ +#define ALICE3_CORE_TRACKUTILITIES_H_ + +#include "ReconstructionDataFormats/Track.h" + +#include "TLorentzVector.h" + +#include + +namespace o2::upgrade +{ + +/// Function to convert a TLorentzVector into a perfect Track +/// \param charge particle charge (integer) +/// \param particle the particle to convert (TLorentzVector) +/// \param productionVertex where the particle was produced +/// \param o2track the address of the resulting TrackParCov +void convertTLorentzVectorToO2Track(const int charge, + const TLorentzVector particle, + const std::vector productionVertex, + o2::track::TrackParCov& o2track); + +/// 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 +/// \param pdg the pdg service +template +void convertTLorentzVectorToO2Track(int pdgCode, + TLorentzVector particle, + std::vector productionVertex, + o2::track::TrackParCov& o2track, + const PdgService& pdg) +{ + const auto pdgInfo = pdg->GetParticle(pdgCode); + int charge = 0; + if (pdgInfo != nullptr) { + charge = pdgInfo->Charge() / 3; + } + convertTLorentzVectorToO2Track(charge, particle, productionVertex, o2track); +} + +/// Function to convert a McParticle into a perfect Track +/// \param particle the particle to convert (mcParticle) +/// \param o2track the address of the resulting TrackParCov +/// \param pdg the pdg service +template +void convertMCParticleToO2Track(McParticleType& particle, + o2::track::TrackParCov& o2track, + const PdgService& pdg) +{ + static TLorentzVector tlv; + tlv.SetPxPyPzE(particle.px(), particle.py(), particle.pz(), particle.e()); + convertTLorentzVectorToO2Track(particle.pdgCode(), tlv, {particle.vx(), particle.vy(), particle.vz()}, o2track, pdg); +} + +/// Function to convert a McParticle into a perfect Track +/// \param particle the particle to convert (mcParticle) +/// \param o2track the address of the resulting TrackParCov +/// \param pdg the pdg service +template +o2::track::TrackParCov convertMCParticleToO2Track(McParticleType& particle, + const PdgService& pdg) +{ + o2::track::TrackParCov o2track; + convertMCParticleToO2Track(particle, o2track, pdg); + return o2track; +} + +} // namespace o2::upgrade + +#endif // ALICE3_CORE_TRACKUTILITIES_H_ diff --git a/ALICE3/DataModel/A3DecayFinderTables.h b/ALICE3/DataModel/A3DecayFinderTables.h index cc7e8f3d3c7..d1c87c989bd 100644 --- a/ALICE3/DataModel/A3DecayFinderTables.h +++ b/ALICE3/DataModel/A3DecayFinderTables.h @@ -19,6 +19,9 @@ #define ALICE3_DATAMODEL_A3DECAYFINDERTABLES_H_ // O2 includes +#include "Common/Core/RecoDecay.h" + +#include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisDataModel.h" enum a3selectionBit : uint32_t { kDCAxy = 0, @@ -43,19 +46,382 @@ enum a3selectionBit : uint32_t { kDCAxy = 0, kTruePrPlusFromLc, kTruePiMinusFromLc, kTrueKaMinusFromLc, - kTruePrMinusFromLc }; + kTruePrMinusFromLc, + kTrueXiFromXiC, + kTruePiFromXiC, + kTruePiFromXiCC }; namespace o2::aod { + +// general decay properties +namespace a3_hf_cand +{ +// collision properties +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +// secondary vertex +DECLARE_SOA_COLUMN(XSecondaryVertex, xSecondaryVertex, double); //! +DECLARE_SOA_COLUMN(YSecondaryVertex, ySecondaryVertex, double); //! +DECLARE_SOA_COLUMN(ZSecondaryVertex, zSecondaryVertex, double); //! +DECLARE_SOA_DYNAMIC_COLUMN(RSecondaryVertex, rSecondaryVertex, //! + [](float xVtxS, float yVtxS) -> float { return RecoDecay::sqrtSumOfSquares(xVtxS, yVtxS); }); +DECLARE_SOA_COLUMN(Chi2PCA, chi2PCA, float); //! sum of (non-weighted) distances of the secondary vertex to its prongs +// prong properties +DECLARE_SOA_COLUMN(PxProng0, pxProng0, float); //! +DECLARE_SOA_COLUMN(PyProng0, pyProng0, float); //! +DECLARE_SOA_COLUMN(PzProng0, pzProng0, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(PtProng0, ptProng0, //! + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt2Prong0, pt2Prong0, //! + [](float px, float py) -> float { return RecoDecay::pt2(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PVectorProng0, pVectorProng0, //! + [](float px, float py, float pz) -> std::array { return std::array{px, py, pz}; }); +DECLARE_SOA_COLUMN(ImpactParameterY0, impactParameterY0, float); //! +DECLARE_SOA_COLUMN(ErrorImpactParameterY0, errorImpactParameterY0, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterNormalised0, impactParameterNormalised0, //! + [](float dca, float err) -> float { return dca / err; }); +DECLARE_SOA_COLUMN(ImpactParameterZ0, impactParameterZ0, float); //! +DECLARE_SOA_COLUMN(ErrorImpactParameterZ0, errorImpactParameterZ0, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterZNormalised0, impactParameterZNormalised0, //! + [](float dca, float err) -> float { return dca / err; }); +DECLARE_SOA_COLUMN(PxProng1, pxProng1, float); //! +DECLARE_SOA_COLUMN(PyProng1, pyProng1, float); //! +DECLARE_SOA_COLUMN(PzProng1, pzProng1, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(PtProng1, ptProng1, //! + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt2Prong1, pt2Prong1, //! + [](float px, float py) -> float { return RecoDecay::pt2(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PVectorProng1, pVectorProng1, //! + [](float px, float py, float pz) -> std::array { return std::array{px, py, pz}; }); +DECLARE_SOA_COLUMN(ImpactParameterY1, impactParameterY1, float); //! +DECLARE_SOA_COLUMN(ErrorImpactParameterY1, errorImpactParameterY1, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterNormalised1, impactParameterNormalised1, //! + [](float dca, float err) -> float { return dca / err; }); +DECLARE_SOA_COLUMN(ImpactParameterZ1, impactParameterZ1, float); //! +DECLARE_SOA_COLUMN(ErrorImpactParameterZ1, errorImpactParameterZ1, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterZNormalised1, impactParameterZNormalised1, //! + [](float dca, float err) -> float { return dca / err; }); +DECLARE_SOA_COLUMN(PxProng2, pxProng2, float); //! +DECLARE_SOA_COLUMN(PyProng2, pyProng2, float); //! +DECLARE_SOA_COLUMN(PzProng2, pzProng2, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(PtProng2, ptProng2, //! + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt2Prong2, pt2Prong2, //! + [](float px, float py) -> float { return RecoDecay::pt2(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PVectorProng2, pVectorProng2, //! + [](float px, float py, float pz) -> std::array { return std::array{px, py, pz}; }); +DECLARE_SOA_COLUMN(ImpactParameterY2, impactParameterY2, float); //! +DECLARE_SOA_COLUMN(ErrorImpactParameterY2, errorImpactParameterY2, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterNormalised2, impactParameterNormalised2, //! + [](float dca, float err) -> float { return dca / err; }); +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; }); + +/// prong PID nsigma +DECLARE_SOA_COLUMN(NSigTrkPi0, nSigTrkPi0, float); //! +DECLARE_SOA_COLUMN(NSigTrkKa0, nSigTrkKa0, float); //! +DECLARE_SOA_COLUMN(NSigTrkPr0, nSigTrkPr0, float); //! +DECLARE_SOA_COLUMN(NSigTrkPi1, nSigTrkPi1, float); //! +DECLARE_SOA_COLUMN(NSigTrkKa1, nSigTrkKa1, float); //! +DECLARE_SOA_COLUMN(NSigTrkPr1, nSigTrkPr1, float); //! +DECLARE_SOA_COLUMN(NSigTrkPi2, nSigTrkPi2, float); //! +DECLARE_SOA_COLUMN(NSigTrkKa2, nSigTrkKa2, float); //! +DECLARE_SOA_COLUMN(NSigTrkPr2, nSigTrkPr2, float); //! +DECLARE_SOA_COLUMN(NSigRichPi0, nSigRichPi0, float); //! +DECLARE_SOA_COLUMN(NSigRichKa0, nSigRichKa0, float); //! +DECLARE_SOA_COLUMN(NSigRichPr0, nSigRichPr0, float); //! +DECLARE_SOA_COLUMN(NSigRichPi1, nSigRichPi1, float); //! +DECLARE_SOA_COLUMN(NSigRichKa1, nSigRichKa1, float); //! +DECLARE_SOA_COLUMN(NSigRichPr1, nSigRichPr1, float); //! +DECLARE_SOA_COLUMN(NSigRichPi2, nSigRichPi2, float); //! +DECLARE_SOA_COLUMN(NSigRichKa2, nSigRichKa2, float); //! +DECLARE_SOA_COLUMN(NSigRichPr2, nSigRichPr2, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPi0, nSigInnTofPi0, float); //! +DECLARE_SOA_COLUMN(NSigInnTofKa0, nSigInnTofKa0, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPr0, nSigInnTofPr0, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPi1, nSigInnTofPi1, float); //! +DECLARE_SOA_COLUMN(NSigInnTofKa1, nSigInnTofKa1, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPr1, nSigInnTofPr1, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPi2, nSigInnTofPi2, float); //! +DECLARE_SOA_COLUMN(NSigInnTofKa2, nSigInnTofKa2, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPr2, nSigInnTofPr2, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPi0, nSigOutTofPi0, float); //! +DECLARE_SOA_COLUMN(NSigOutTofKa0, nSigOutTofKa0, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPr0, nSigOutTofPr0, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPi1, nSigOutTofPi1, float); //! +DECLARE_SOA_COLUMN(NSigOutTofKa1, nSigOutTofKa1, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPr1, nSigOutTofPr1, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPi2, nSigOutTofPi2, float); //! +DECLARE_SOA_COLUMN(NSigOutTofKa2, nSigOutTofKa2, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPr2, nSigOutTofPr2, float); //! + +// candidate properties +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt2, pt2, //! + [](float px, float py) -> float { return RecoDecay::pt2(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(P2, p2, //! + [](float px, float py, float pz) -> float { return RecoDecay::p2(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(E, e, //! + [](float px, float py, float pz, double m) -> float { return RecoDecay::e(px, py, pz, m); }); +DECLARE_SOA_DYNAMIC_COLUMN(E2, e2, //! + [](float px, float py, float pz, double m) -> float { return RecoDecay::e2(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_COLUMN(ErrorDecayLength, errorDecayLength, float); //! +DECLARE_SOA_COLUMN(ErrorDecayLengthXY, errorDecayLengthXY, float); //! +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, //! + [](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}); }); + +// ML scores columns +DECLARE_SOA_COLUMN(MlScore0, mlScore0, float); //! +DECLARE_SOA_COLUMN(MlScore1, mlScore1, float); //! +DECLARE_SOA_COLUMN(MlScore2, mlScore2, float); //! +} // namespace a3_hf_cand + +#define HFCAND_COLUMNS \ + a3_hf_cand::CollisionId, \ + collision::PosX, collision::PosY, collision::PosZ, \ + a3_hf_cand::XSecondaryVertex, a3_hf_cand::YSecondaryVertex, a3_hf_cand::ZSecondaryVertex, \ + a3_hf_cand::ErrorDecayLength, a3_hf_cand::ErrorDecayLengthXY, \ + a3_hf_cand::Chi2PCA, \ + /* dynamic columns */ a3_hf_cand::RSecondaryVertex, \ + a3_hf_cand::DecayLength, \ + a3_hf_cand::DecayLengthXY, \ + a3_hf_cand::DecayLengthNormalised, \ + a3_hf_cand::DecayLengthXYNormalised + +// general columns +#define HFPRONG0_COLUMNS \ + a3_hf_cand::ImpactParameterNormalised0, \ + a3_hf_cand::PtProng0, \ + a3_hf_cand::Pt2Prong0, \ + a3_hf_cand::PVectorProng0 + +#define HFPRONG1_COLUMNS \ + a3_hf_cand::ImpactParameterNormalised1, \ + a3_hf_cand::PtProng1, \ + a3_hf_cand::Pt2Prong1, \ + a3_hf_cand::PVectorProng1 + +#define HFPRONG2_COLUMNS \ + a3_hf_cand::ImpactParameterNormalised2, \ + a3_hf_cand::PtProng2, \ + a3_hf_cand::Pt2Prong2, \ + a3_hf_cand::PVectorProng2 + 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; +namespace a3D0meson +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_COLUMN(PxProng0, pxProng0, float); //! positive track +DECLARE_SOA_COLUMN(PyProng0, pyProng0, float); //! +DECLARE_SOA_COLUMN(PzProng0, pzProng0, float); //! +DECLARE_SOA_COLUMN(PxProng1, pxProng1, float); //! negative track +DECLARE_SOA_COLUMN(PyProng1, pyProng1, float); //! +DECLARE_SOA_COLUMN(PzProng1, pzProng1, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(PtProng0, ptProng0, //! + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtProng1, ptProng1, //! + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_EXPRESSION_COLUMN(Px, px, //! + float, 1.f * aod::a3D0meson::pxProng0 + 1.f * aod::a3D0meson::pxProng1); +DECLARE_SOA_EXPRESSION_COLUMN(Py, py, //! + float, 1.f * aod::a3D0meson::pyProng0 + 1.f * aod::a3D0meson::pyProng1); +DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, //! + float, 1.f * aod::a3D0meson::pzProng0 + 1.f * aod::a3D0meson::pzProng1); +DECLARE_SOA_COLUMN(Pt, pt, float); //! +DECLARE_SOA_COLUMN(M, m, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(E, e, //! + [](float px, float py, float pz, double m) -> float { return RecoDecay::e(px, py, pz, m); }); +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_COLUMN(Y, y, float); +} // namespace a3D0meson +DECLARE_SOA_TABLE(Alice3D0Meson, "AOD", "ALICE3D0MESON", //! + o2::soa::Index<>, + a3D0meson::CollisionId, + a3D0meson::PxProng0, a3D0meson::PyProng0, a3D0meson::PzProng0, // positive track + a3D0meson::PxProng1, a3D0meson::PyProng1, a3D0meson::PzProng1, // negative track + a3D0meson::PtProng0, + a3D0meson::PtProng1, + a3D0meson::Px, a3D0meson::Py, a3D0meson::Pz, + a3D0meson::Pt, + a3D0meson::M, + a3D0meson::E, + a3D0meson::Eta, + a3D0meson::Phi, + a3D0meson::Y); + +namespace a3D0Selection +{ +DECLARE_SOA_COLUMN(IsSelD0, isSelD0, int); //! +DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int); //! +} // namespace a3D0Selection +DECLARE_SOA_TABLE(Alice3D0Sel, "AOD", "ALICE3D0SEL", //! + a3D0Selection::IsSelD0, + a3D0Selection::IsSelD0bar); + +namespace a3D0MCTruth +{ +DECLARE_SOA_COLUMN(McTruthInfo, mcTruthInfo, int); //! 0 for bkg, 1 for true D0, 2 for true D0bar +} // namespace a3D0MCTruth +DECLARE_SOA_TABLE(Alice3D0MCTruth, "AOD", "ALICE3D0MCTRUTH", //! + a3D0MCTruth::McTruthInfo); //! + +// Now let's define the Lc to pKpi table +namespace a3_hf_cand_3prong +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +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_DYNAMIC_COLUMN(M, m, + [](float px0, float py0, float pz0, + float px1, float py1, float pz1, + float px2, float py2, float pz2, + const std::array& m) -> float { return RecoDecay::m(std::array{std::array{px0, py0, pz0}, + std::array{px1, py1, pz1}, + std::array{px2, py2, pz2}}, + m); }); +DECLARE_SOA_DYNAMIC_COLUMN(E, e, //! + [](float px, float py, float pz, const float m) -> float { return RecoDecay::e(px, py, pz, m); }); +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, + [](float px, float py, float pz, const float m) -> float { return RecoDecay::y(std::array{px, py, pz}, m); }); +} // namespace a3_hf_cand_3prong +DECLARE_SOA_TABLE(Alice3Cand3Ps, "AOD", "ALICE3CAND3P", //! + o2::soa::Index<>, + // general candidate properties + HFCAND_COLUMNS, + HFPRONG0_COLUMNS, + HFPRONG1_COLUMNS, + HFPRONG2_COLUMNS, + // candidate kinematics + a3_hf_cand_3prong::Eta, + a3_hf_cand_3prong::Phi, + a3_hf_cand_3prong::Pt, + // prong properties + a3_hf_cand::PxProng0, a3_hf_cand::PyProng0, a3_hf_cand::PzProng0, // proton track + a3_hf_cand::PxProng1, a3_hf_cand::PyProng1, a3_hf_cand::PzProng1, // kaon track + a3_hf_cand::PxProng2, a3_hf_cand::PyProng2, a3_hf_cand::PzProng2, // pion track + a3_hf_cand::ImpactParameterY0, a3_hf_cand::ImpactParameterY1, a3_hf_cand::ImpactParameterY2, + a3_hf_cand::ErrorImpactParameterY0, a3_hf_cand::ErrorImpactParameterY1, a3_hf_cand::ErrorImpactParameterY2, + a3_hf_cand::ImpactParameterZ0, a3_hf_cand::ImpactParameterZ1, a3_hf_cand::ImpactParameterZ2, + a3_hf_cand::ErrorImpactParameterZ0, a3_hf_cand::ErrorImpactParameterZ1, a3_hf_cand::ErrorImpactParameterZ2, + // Candidate momenta + a3_hf_cand_3prong::Px, a3_hf_cand_3prong::Py, a3_hf_cand_3prong::Pz, + // dynamic candidate properties + a3_hf_cand::Cpa, + a3_hf_cand::CpaXY, + a3_hf_cand::ImpactParameterXY, + a3_hf_cand_3prong::Y, + a3_hf_cand_3prong::M, + a3_hf_cand_3prong::E); + +namespace a3_hf_sel_3prong +{ +DECLARE_SOA_COLUMN(IsSelMassHypo0, isSelMassHypo0, bool); //! +DECLARE_SOA_COLUMN(IsSelMassHypo1, isSelMassHypo1, bool); //! + +// PID selection +enum PidSels { + None = 0, + TrkProng0, + RichProng0, + InnTofProng0, + OutTofProng0, + TrkProng1, + RichProng1, + InnTofProng1, + OutTofProng1, + TrkProng2, + RichProng2, + InnTofProng2, + OutTofProng2, + NPidSelections +}; +DECLARE_SOA_COLUMN(PidBitMask, pidBitMask, uint32_t); //! +} // namespace a3_hf_sel_3prong +DECLARE_SOA_TABLE(Alice3Sel3Ps, "AOD", "ALICE3SEL3P", //! + a3_hf_sel_3prong::IsSelMassHypo0, + a3_hf_sel_3prong::IsSelMassHypo1, + a3_hf_sel_3prong::PidBitMask); + +namespace a3_mc_truth +{ +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int); //! +DECLARE_SOA_COLUMN(BHadMotherPtRec, bHadMotherPtRec, float); //! +DECLARE_SOA_COLUMN(FlagMcRec, flagMcRec, int); //! +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int); //! +DECLARE_SOA_COLUMN(BHadMotherPtGen, bHadMotherPtGen, float); //! +DECLARE_SOA_COLUMN(FlagMcGen, flagMcGen, int); //! +} // namespace a3_mc_truth +DECLARE_SOA_TABLE(Alice3McRecFlags, "AOD", "ALICE3MCRECFLAG", //! + a3_mc_truth::OriginMcRec, + a3_mc_truth::BHadMotherPtRec, + a3_mc_truth::FlagMcRec); + +DECLARE_SOA_TABLE(Alice3McGenFlags, "AOD", "ALICE3MCGENFLAG", //! + a3_mc_truth::OriginMcGen, + a3_mc_truth::BHadMotherPtGen, + a3_mc_truth::FlagMcGen); + +DECLARE_SOA_TABLE(Alice3PidLcs, "AOD", "ALICE3PIDLC", //! + a3_hf_cand::NSigTrkPr0, + a3_hf_cand::NSigRichPr0, + a3_hf_cand::NSigInnTofPr0, + a3_hf_cand::NSigOutTofPr0, + a3_hf_cand::NSigTrkKa1, + a3_hf_cand::NSigRichKa1, + a3_hf_cand::NSigInnTofKa1, + a3_hf_cand::NSigOutTofKa1, + a3_hf_cand::NSigTrkPi2, + a3_hf_cand::NSigRichPi2, + a3_hf_cand::NSigInnTofPi2, + a3_hf_cand::NSigOutTofPi2); + +DECLARE_SOA_TABLE(Alice3Ml3Ps, "AOD", "ALICE3ML3P", //! + a3_hf_cand::MlScore0, + a3_hf_cand::MlScore1, + a3_hf_cand::MlScore2); + } // namespace o2::aod #endif // ALICE3_DATAMODEL_A3DECAYFINDERTABLES_H_ diff --git a/ALICE3/DataModel/OTFMcTrackExtra.h b/ALICE3/DataModel/OTFMcTrackExtra.h deleted file mode 100644 index bb75c86746c..00000000000 --- a/ALICE3/DataModel/OTFMcTrackExtra.h +++ /dev/null @@ -1,42 +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 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..944aa578ab2 --- /dev/null +++ b/ALICE3/DataModel/OTFMulticharm.h @@ -0,0 +1,209 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file OTFMulticharm.h +/// \author David Dobrigkeit Chinellato +/// \author Jesper Karlsson Gumprecht +/// \since 05/08/2024 +/// \brief Set of tables for the ALICE3 multi-charm information +/// + +#ifndef ALICE3_DATAMODEL_OTFMULTICHARM_H_ +#define ALICE3_DATAMODEL_OTFMULTICHARM_H_ + +// O2 includes +#include "ALICE3/DataModel/OTFStrangeness.h" + +#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"); + +DECLARE_SOA_COLUMN(XicMass, xicMass, float); +DECLARE_SOA_COLUMN(XiccMass, xiccMass, float); +DECLARE_SOA_COLUMN(LUTConfigId, lutConfigId, int); //! Index for LUT configuration + +// kine vars +DECLARE_SOA_COLUMN(XiccPt, xiccPt, float); +DECLARE_SOA_COLUMN(XiccEta, xiccEta, float); +DECLARE_SOA_COLUMN(XicPt, xicPt, float); +DECLARE_SOA_COLUMN(XicEta, xicEta, float); + +// topo vars +DECLARE_SOA_COLUMN(XiDCAz, xiDCAz, float); +DECLARE_SOA_COLUMN(XiDCAxy, xiDCAxy, float); +DECLARE_SOA_COLUMN(XicDauDCA, xicDauDCA, float); +DECLARE_SOA_COLUMN(XicDCAxy, xicDCAxy, float); +DECLARE_SOA_COLUMN(XicDCAz, xicDCAz, float); +DECLARE_SOA_COLUMN(XiccDauDCA, xiccDauDCA, float); +DECLARE_SOA_COLUMN(XiccDCAxy, xiccDCAxy, float); +DECLARE_SOA_COLUMN(XiccDCAz, xiccDCAz, float); + +DECLARE_SOA_COLUMN(BachDCAxy, bachDCAxy, float); +DECLARE_SOA_COLUMN(BachDCAz, bachDCAz, float); +DECLARE_SOA_COLUMN(PosDCAxy, posDCAxy, float); +DECLARE_SOA_COLUMN(PosDCAz, posDCAz, float); +DECLARE_SOA_COLUMN(NegDCAxy, negDCAxy, float); +DECLARE_SOA_COLUMN(NegDCAz, negDCAz, float); + +DECLARE_SOA_COLUMN(Pi1cDCAxy, pi1cDCAxy, float); +DECLARE_SOA_COLUMN(Pi1cDCAz, pi1cDCAz, float); +DECLARE_SOA_COLUMN(Pi2cDCAxy, pi2cDCAxy, float); +DECLARE_SOA_COLUMN(Pi2cDCAz, pi2cDCAz, float); +DECLARE_SOA_COLUMN(PiccDCAxy, piccDCAxy, float); +DECLARE_SOA_COLUMN(PiccDCAz, piccDCAz, float); + +// Lengths +DECLARE_SOA_COLUMN(XicDecayRadius2D, xicDecayRadius2D, float); +DECLARE_SOA_COLUMN(XiccDecayRadius2D, xiccDecayRadius2D, float); +DECLARE_SOA_COLUMN(XicProperLength, xicProperLength, float); +DECLARE_SOA_COLUMN(XicDistanceFromPV, xicDistanceFromPV, float); +DECLARE_SOA_COLUMN(XiccProperLength, xiccProperLength, float); + +// PID +DECLARE_SOA_COLUMN(Pi1cTofDeltaInner, pi1cTofDeltaInner, float); +DECLARE_SOA_COLUMN(Pi1cTofNSigmaInner, pi1cTofNSigmaInner, float); +DECLARE_SOA_COLUMN(Pi1cTofDeltaOuter, pi1cTofDeltaOuter, float); +DECLARE_SOA_COLUMN(Pi1cTofNSigmaOuter, pi1cTofNSigmaOuter, float); +DECLARE_SOA_COLUMN(Pi1cHasRichSignal, pi1cHasRichSignal, bool); +DECLARE_SOA_COLUMN(Pi1cRichNSigma, pi1cRichNSigma, float); +DECLARE_SOA_COLUMN(Pi1cPdgCode, pi1cPdgCode, int); + +DECLARE_SOA_COLUMN(Pi2cTofDeltaInner, pi2cTofDeltaInner, float); +DECLARE_SOA_COLUMN(Pi2cTofNSigmaInner, pi2cTofNSigmaInner, float); +DECLARE_SOA_COLUMN(Pi2cTofDeltaOuter, pi2cTofDeltaOuter, float); +DECLARE_SOA_COLUMN(Pi2cTofNSigmaOuter, pi2cTofNSigmaOuter, float); +DECLARE_SOA_COLUMN(Pi2cHasRichSignal, pi2cHasRichSignal, bool); +DECLARE_SOA_COLUMN(Pi2cRichNSigma, pi2cRichNSigma, float); +DECLARE_SOA_COLUMN(Pi2cPdgCode, pi2cPdgCode, int); + +DECLARE_SOA_COLUMN(PiccTofDeltaInner, piccTofDeltaInner, float); +DECLARE_SOA_COLUMN(PiccTofNSigmaInner, piccTofNSigmaInner, float); +DECLARE_SOA_COLUMN(PiccTofDeltaOuter, piccTofDeltaOuter, float); +DECLARE_SOA_COLUMN(PiccTofNSigmaOuter, piccTofNSigmaOuter, float); +DECLARE_SOA_COLUMN(PiccHasRichSignal, piccHasRichSignal, bool); +DECLARE_SOA_COLUMN(PiccRichNSigma, piccRichNSigma, float); +DECLARE_SOA_COLUMN(PiccPdgCode, piccPdgCode, int); + +// Daughter info +DECLARE_SOA_COLUMN(PosPt, posPt, float); +DECLARE_SOA_COLUMN(PosEta, posEta, float); +DECLARE_SOA_COLUMN(NegPt, negPt, float); +DECLARE_SOA_COLUMN(NegEta, negEta, float); +DECLARE_SOA_COLUMN(BachPt, bachPt, float); +DECLARE_SOA_COLUMN(BachEta, bachEta, float); +DECLARE_SOA_COLUMN(BachPhi, bachPhi, float); +DECLARE_SOA_COLUMN(Pi1cPt, pi1cPt, float); +DECLARE_SOA_COLUMN(Pi1cEta, pi1cEta, float); +DECLARE_SOA_COLUMN(Pi2cPt, pi2cPt, float); +DECLARE_SOA_COLUMN(Pi2cEta, pi2cEta, float); +DECLARE_SOA_COLUMN(PiccPt, piccPt, float); +DECLARE_SOA_COLUMN(PiccEta, piccEta, 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::XiccMass, + otfmulticharm::XiccPt, + otfmulticharm::XiccEta, + otfmulticharm::XiccDauDCA, + + otfmulticharm::XicMass, + otfmulticharm::XicPt, + otfmulticharm::XicEta, + otfmulticharm::XicDauDCA, + + otfmulticharm::XiDCAxy, + otfmulticharm::XiDCAz, + otfmulticharm::XicDCAxy, + otfmulticharm::XicDCAz, + otfmulticharm::XiccDCAxy, + otfmulticharm::XiccDCAz, + + otfmulticharm::Pi1cDCAxy, + otfmulticharm::Pi1cDCAz, + otfmulticharm::Pi2cDCAxy, + otfmulticharm::Pi2cDCAz, + otfmulticharm::PiccDCAxy, + otfmulticharm::PiccDCAz, + + otfmulticharm::XicDecayRadius2D, + otfmulticharm::XiccDecayRadius2D, + otfmulticharm::XicProperLength, + otfmulticharm::XicDistanceFromPV, + otfmulticharm::XiccProperLength, + otfmulticharm::Pi1cPt, + otfmulticharm::Pi2cPt, + otfmulticharm::PiccPt, + otfmulticharm::LUTConfigId); + +DECLARE_SOA_TABLE(MCharmPID, "AOD", "MCharmPID", + otfmulticharm::Pi1cTofDeltaInner, + otfmulticharm::Pi1cTofNSigmaInner, + otfmulticharm::Pi1cTofDeltaOuter, + otfmulticharm::Pi1cTofNSigmaOuter, + otfmulticharm::Pi1cHasRichSignal, + otfmulticharm::Pi1cRichNSigma, + otfmulticharm::Pi1cPdgCode, + + otfmulticharm::Pi2cTofDeltaInner, + otfmulticharm::Pi2cTofNSigmaInner, + otfmulticharm::Pi2cTofDeltaOuter, + otfmulticharm::Pi2cTofNSigmaOuter, + otfmulticharm::Pi2cHasRichSignal, + otfmulticharm::Pi2cRichNSigma, + otfmulticharm::Pi2cPdgCode, + + otfmulticharm::PiccTofDeltaInner, + otfmulticharm::PiccTofNSigmaInner, + otfmulticharm::PiccTofDeltaOuter, + otfmulticharm::PiccTofNSigmaOuter, + otfmulticharm::PiccHasRichSignal, + otfmulticharm::PiccRichNSigma, + otfmulticharm::PiccPdgCode); + +DECLARE_SOA_TABLE(MCharmExtra, "AOD", "MCharmExtra", + otfmulticharm::BachPt, + otfmulticharm::BachEta, + otfmulticharm::BachDCAxy, + otfmulticharm::BachDCAz, + + otfmulticharm::PosPt, + otfmulticharm::PosEta, + otfmulticharm::PosDCAxy, + otfmulticharm::PosDCAz, + + otfmulticharm::NegPt, + otfmulticharm::NegEta, + otfmulticharm::NegDCAxy, + otfmulticharm::NegDCAz, + + otfmulticharm::Pi1cEta, + otfmulticharm::Pi2cEta, + otfmulticharm::PiccEta); + +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_OTFMULTICHARM_H_ diff --git a/ALICE3/DataModel/OTFPIDTrk.h b/ALICE3/DataModel/OTFPIDTrk.h new file mode 100644 index 00000000000..ce8a5d07a4f --- /dev/null +++ b/ALICE3/DataModel/OTFPIDTrk.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. + +/// +/// \file OTFPIDTrk.h +/// \author Henrik Fribert TUM +/// \author Nicolò Jacazio Università del Piemonte Orientale +/// \since May 22, 2025 +/// \brief Set of tables for the ALICE3 Trk PID information +/// + +#ifndef ALICE3_DATAMODEL_OTFPIDTRK_H_ +#define ALICE3_DATAMODEL_OTFPIDTRK_H_ + +// O2 includes +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace upgrade::trk +{ + +DECLARE_SOA_COLUMN(TimeOverThresholdBarrel, timeOverThresholdBarrel, float); //! Time over threshold for the Barrel layers +DECLARE_SOA_COLUMN(TimeOverThresholdForward, timeOverThresholdForward, float); //! Time over threshold for the Forward layers + +DECLARE_SOA_COLUMN(NSigmaTrkEl, nSigmaTrkEl, float); //! NSigma electron from the tracker layers +DECLARE_SOA_COLUMN(NSigmaTrkMu, nSigmaTrkMu, float); //! NSigma muon from the tracker layers +DECLARE_SOA_COLUMN(NSigmaTrkPi, nSigmaTrkPi, float); //! NSigma pion from the tracker layers +DECLARE_SOA_COLUMN(NSigmaTrkKa, nSigmaTrkKa, float); //! NSigma kaon from the tracker layers +DECLARE_SOA_COLUMN(NSigmaTrkPr, nSigmaTrkPr, float); //! NSigma proton from the tracker layers +DECLARE_SOA_COLUMN(NSigmaTrkDe, nSigmaTrkDe, float); //! NSigma deuteron from the tracker layers +DECLARE_SOA_COLUMN(NSigmaTrkTr, nSigmaTrkTr, float); //! NSigma triton from the tracker layers +DECLARE_SOA_COLUMN(NSigmaTrkHe, nSigmaTrkHe, float); //! NSigma helium-3 from the tracker layers +DECLARE_SOA_COLUMN(NSigmaTrkAl, nSigmaTrkAl, float); //! NSigma alpha from the tracker layers + +DECLARE_SOA_DYNAMIC_COLUMN(NSigmaTrk, nSigmaTrk, //! General function to get the nSigma for the tracker layers + [](const float el, + const float mu, + const float pi, + const float ka, + const float pr, + const float de, + const float tr, + const float he, + const float al, + const int id) -> float { + switch (std::abs(id)) { + case 0: + return el; + case 1: + return mu; + case 2: + return pi; + case 3: + return ka; + case 4: + return pr; + case 5: + return de; + case 6: + return tr; + case 7: + return he; + case 8: + return al; + default: + LOG(fatal) << "Unrecognized PDG code"; + return 999.f; + } + }); + +} // namespace upgrade::trk + +DECLARE_SOA_TABLE(UpgradeTrkPidSignals, "AOD", "UPGRADETRKSIG", + o2::soa::Index<>, + upgrade::trk::TimeOverThresholdBarrel); + +DECLARE_SOA_TABLE(UpgradeTrkPids, "AOD", "UPGRADETRKPID", + o2::soa::Index<>, + upgrade::trk::NSigmaTrkEl, + upgrade::trk::NSigmaTrkMu, + upgrade::trk::NSigmaTrkPi, + upgrade::trk::NSigmaTrkKa, + upgrade::trk::NSigmaTrkPr, + upgrade::trk::NSigmaTrkDe, + upgrade::trk::NSigmaTrkTr, + upgrade::trk::NSigmaTrkHe, + upgrade::trk::NSigmaTrkAl, + upgrade::trk::NSigmaTrk); + +using UpgradeTrkPidSignal = UpgradeTrkPidSignals::iterator; +using UpgradeTrkPid = UpgradeTrkPids::iterator; + +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_OTFPIDTRK_H_ diff --git a/ALICE3/DataModel/OTFRICH.h b/ALICE3/DataModel/OTFRICH.h index e853a2ff30f..05771dda57b 100644 --- a/ALICE3/DataModel/OTFRICH.h +++ b/ALICE3/DataModel/OTFRICH.h @@ -31,16 +31,96 @@ DECLARE_SOA_COLUMN(NSigmaMuonRich, nSigmaMuonRich, float); //! NSigma mu DECLARE_SOA_COLUMN(NSigmaPionRich, nSigmaPionRich, float); //! NSigma pion BarrelRich DECLARE_SOA_COLUMN(NSigmaKaonRich, nSigmaKaonRich, float); //! NSigma kaon BarrelRich DECLARE_SOA_COLUMN(NSigmaProtonRich, nSigmaProtonRich, float); //! NSigma proton BarrelRich +DECLARE_SOA_COLUMN(NSigmaDeuteronRich, nSigmaDeuteronRich, float); //! NSigma deuteron BarrelRich +DECLARE_SOA_COLUMN(NSigmaTritonRich, nSigmaTritonRich, float); //! NSigma triton BarrelRich +DECLARE_SOA_COLUMN(NSigmaHelium3Rich, nSigmaHelium3Rich, float); //! NSigma helium3 BarrelRich +DECLARE_SOA_COLUMN(NSigmaAlphaRich, nSigmaAlphaRich, float); //! NSigma alpha BarrelRich +DECLARE_SOA_DYNAMIC_COLUMN(NSigmaRich, nSigmaRich, //! General function to get the nSigma for the RICH + [](const float el, + const float mu, + const float pi, + const float ka, + const float pr, + const float de, + const float tr, + const float he3, + const float al, + const int id) -> float { + switch (std::abs(id)) { + case 0: + return el; + case 1: + return mu; + case 2: + return pi; + case 3: + return ka; + case 4: + return pr; + case 5: + return de; + case 6: + return tr; + case 7: + return he3; + case 8: + return al; + default: + LOG(fatal) << "Unrecognized PDG code for RICH"; + return 999.f; + } + }); + +DECLARE_SOA_COLUMN(HasSig, hasSig, bool); //! Has signal in the barrel rich (is particle over threshold) +DECLARE_SOA_COLUMN(HasSigInGas, hasSigInGas, bool); //! Has signal in the gas radiator in the barrel rich (is particle over threshold) +DECLARE_SOA_COLUMN(HasSigEl, hasSigEl, bool); //! Has nSigma electron BarrelRich (is electron over threshold) +DECLARE_SOA_COLUMN(HasSigMu, hasSigMu, bool); //! Has nSigma muon BarrelRich (is muon over threshold) +DECLARE_SOA_COLUMN(HasSigPi, hasSigPi, bool); //! Has nSigma pion BarrelRich (is pion over threshold) +DECLARE_SOA_COLUMN(HasSigKa, hasSigKa, bool); //! Has nSigma kaon BarrelRich (is kaon over threshold) +DECLARE_SOA_COLUMN(HasSigPr, hasSigPr, bool); //! Has nSigma proton BarrelRich (is proton over threshold) +DECLARE_SOA_COLUMN(HasSigDe, hasSigDe, bool); //! Has nSigma deuteron BarrelRich (is deuteron over threshold) +DECLARE_SOA_COLUMN(HasSigTr, hasSigTr, bool); //! Has nSigma triton BarrelRich (is triton over threshold) +DECLARE_SOA_COLUMN(HasSigHe3, hasSigHe3, bool); //! Has nSigma helium3 BarrelRich (is helium3 over threshold) +DECLARE_SOA_COLUMN(HasSigAl, hasSigAl, bool); //! Has nSigma alpha BarrelRich (is alpha over threshold) + } // namespace upgrade_rich DECLARE_SOA_TABLE(UpgradeRichs, "AOD", "UPGRADERICH", upgrade_rich::NSigmaElectronRich, upgrade_rich::NSigmaMuonRich, upgrade_rich::NSigmaPionRich, upgrade_rich::NSigmaKaonRich, - upgrade_rich::NSigmaProtonRich); + upgrade_rich::NSigmaProtonRich, + upgrade_rich::NSigmaDeuteronRich, + upgrade_rich::NSigmaTritonRich, + upgrade_rich::NSigmaHelium3Rich, + upgrade_rich::NSigmaAlphaRich, + upgrade_rich::NSigmaRich); using UpgradeRich = UpgradeRichs::iterator; +DECLARE_SOA_TABLE(UpgradeRichSignals, "AOD", "UPGRADERICHSIG", + upgrade_rich::HasSig, + upgrade_rich::HasSigEl, + upgrade_rich::HasSigMu, + upgrade_rich::HasSigPi, + upgrade_rich::HasSigKa, + upgrade_rich::HasSigPr, + upgrade_rich::HasSigDe, + upgrade_rich::HasSigTr, + upgrade_rich::HasSigHe3, + upgrade_rich::HasSigAl, + upgrade_rich::HasSigInGas); + +using UpgradeRichSignal = UpgradeRichSignals::iterator; + } // namespace o2::aod #endif // ALICE3_DATAMODEL_OTFRICH_H_ diff --git a/ALICE3/DataModel/OTFStrangeness.h b/ALICE3/DataModel/OTFStrangeness.h new file mode 100644 index 00000000000..3bc6872eb4c --- /dev/null +++ b/ALICE3/DataModel/OTFStrangeness.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 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 otfv0 +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, Tracks, "_Pos"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(NegTrack, negTrack, int, Tracks, "_Neg"); //! +DECLARE_SOA_INDEX_COLUMN(V0, v0); //! + +// topo vars +DECLARE_SOA_COLUMN(DCAV0Daughters, dcaV0Daughters, float); +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(MLambda, mLambda, float); +DECLARE_SOA_COLUMN(MAntiLambda, mAntiLambda, float); +DECLARE_SOA_COLUMN(MK0, mK0, float); + +// kinematics +DECLARE_SOA_COLUMN(Pt, pt, float); + +} // namespace otfv0 +DECLARE_SOA_TABLE(UpgradeV0s, "AOD", "UPGRADEV0S", + o2::soa::Index<>, + otfv0::CollisionId, + otfv0::PosTrackId, + otfv0::NegTrackId, + otfv0::DCAV0Daughters, + otfv0::V0Radius, + otfv0::MLambda, + otfv0::MAntiLambda, + otfv0::MK0, + otfv0::Pt); + +using UpgradeV0 = UpgradeV0s::iterator; +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_OTFSTRANGENESS_H_ diff --git a/ALICE3/DataModel/OTFTOF.h b/ALICE3/DataModel/OTFTOF.h index 57fd5bb8e8c..150efc91f5e 100644 --- a/ALICE3/DataModel/OTFTOF.h +++ b/ALICE3/DataModel/OTFTOF.h @@ -27,42 +27,202 @@ namespace o2::aod { namespace upgrade_tof { -DECLARE_SOA_COLUMN(NSigmaElectronInnerTOF, nSigmaElectronInnerTOF, float); //! NSigma electron InnerTOF -DECLARE_SOA_COLUMN(NSigmaMuonInnerTOF, nSigmaMuonInnerTOF, float); //! NSigma muon InnerTOF -DECLARE_SOA_COLUMN(NSigmaPionInnerTOF, nSigmaPionInnerTOF, float); //! NSigma pion InnerTOF -DECLARE_SOA_COLUMN(NSigmaKaonInnerTOF, nSigmaKaonInnerTOF, float); //! NSigma kaon InnerTOF -DECLARE_SOA_COLUMN(NSigmaProtonInnerTOF, nSigmaProtonInnerTOF, float); //! NSigma proton InnerTOF -DECLARE_SOA_COLUMN(InnerTOFTrackLength, innerTOFTrackLength, float); //! track length for calculation of InnerTOF -DECLARE_SOA_COLUMN(InnerTOFTrackLengthReco, innerTOFTrackLengthReco, float); //! track length for calculation of InnerTOF -DECLARE_SOA_COLUMN(DeltaTrackLengthInnerTOF, deltaTrackLengthInnerTOF, float); //! track length for calculation of InnerTOF -DECLARE_SOA_COLUMN(NSigmaElectronOuterTOF, nSigmaElectronOuterTOF, float); //! NSigma electron OuterTOF -DECLARE_SOA_COLUMN(NSigmaMuonOuterTOF, nSigmaMuonOuterTOF, float); //! NSigma muon OuterTOF -DECLARE_SOA_COLUMN(NSigmaPionOuterTOF, nSigmaPionOuterTOF, float); //! NSigma pion OuterTOF -DECLARE_SOA_COLUMN(NSigmaKaonOuterTOF, nSigmaKaonOuterTOF, float); //! NSigma kaon OuterTOF -DECLARE_SOA_COLUMN(NSigmaProtonOuterTOF, nSigmaProtonOuterTOF, float); //! NSigma proton OuterTOF -DECLARE_SOA_COLUMN(OuterTOFTrackLength, outerTOFTrackLength, float); //! track length for calculation of OuterTOF -DECLARE_SOA_COLUMN(OuterTOFTrackLengthReco, outerTOFTrackLengthReco, float); //! track length for calculation of OuterTOF -DECLARE_SOA_COLUMN(DeltaTrackLengthOuterTOF, deltaTrackLengthOuterTOF, float); //! track length for calculation of InnerTOF +DECLARE_SOA_COLUMN(InnerTOFTrackTime, innerTOFTrackTime, float); //! Track time generated at the InnerTOF +DECLARE_SOA_COLUMN(InnerTOFTrackLength, innerTOFTrackLength, float); //! track length for calculation of InnerTOF (generated) +DECLARE_SOA_COLUMN(OuterTOFTrackTime, outerTOFTrackTime, float); //! Track time generated at the OuterTOF +DECLARE_SOA_COLUMN(OuterTOFTrackLength, outerTOFTrackLength, float); //! track length for calculation of OuterTOF (generated) + +DECLARE_SOA_COLUMN(TOFEventTime, tofEventTime, float); //! Event time reconstructed with the TOF +DECLARE_SOA_COLUMN(TOFEventTimeErr, tofEventTimeErr, float); //! Uncertainty on the event time reconstructed with the TOF +DECLARE_SOA_COLUMN(NSigmaElectronInnerTOF, nSigmaElectronInnerTOF, float); //! NSigma electron InnerTOF +DECLARE_SOA_COLUMN(NSigmaMuonInnerTOF, nSigmaMuonInnerTOF, float); //! NSigma muon InnerTOF +DECLARE_SOA_COLUMN(NSigmaPionInnerTOF, nSigmaPionInnerTOF, float); //! NSigma pion InnerTOF +DECLARE_SOA_COLUMN(NSigmaKaonInnerTOF, nSigmaKaonInnerTOF, float); //! NSigma kaon InnerTOF +DECLARE_SOA_COLUMN(NSigmaProtonInnerTOF, nSigmaProtonInnerTOF, float); //! NSigma proton InnerTOF +DECLARE_SOA_COLUMN(NSigmaDeuteronInnerTOF, nSigmaDeuteronInnerTOF, float); //! NSigma deuteron InnerTOF +DECLARE_SOA_COLUMN(NSigmaTritonInnerTOF, nSigmaTritonInnerTOF, float); //! NSigma triton InnerTOF +DECLARE_SOA_COLUMN(NSigmaHelium3InnerTOF, nSigmaHelium3InnerTOF, float); //! NSigma helium3 InnerTOF +DECLARE_SOA_COLUMN(NSigmaAlphaInnerTOF, nSigmaAlphaInnerTOF, float); //! NSigma alpha InnerTOF +DECLARE_SOA_COLUMN(InnerTOFTrackTimeReco, innerTOFTrackTimeReco, float); //! Track time measured at the InnerTOF +DECLARE_SOA_COLUMN(InnerTOFTrackLengthReco, innerTOFTrackLengthReco, float); //! track length for calculation of InnerTOF (reconstructed) + +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeEl, innerTOFExpectedTimeEl, float); //! Reconstructed expected time at the InnerTOF for the Electron mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeMu, innerTOFExpectedTimeMu, float); //! Reconstructed expected time at the InnerTOF for the Muon mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimePi, innerTOFExpectedTimePi, float); //! Reconstructed expected time at the InnerTOF for the Pion mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeKa, innerTOFExpectedTimeKa, float); //! Reconstructed expected time at the InnerTOF for the Kaon mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimePr, innerTOFExpectedTimePr, float); //! Reconstructed expected time at the InnerTOF for the Proton mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeDe, innerTOFExpectedTimeDe, float); //! Reconstructed expected time at the InnerTOF for the Deuteron mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeTr, innerTOFExpectedTimeTr, float); //! Reconstructed expected time at the InnerTOF for the Triton mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeHe3, innerTOFExpectedTimeHe3, float); //! Reconstructed expected time at the InnerTOF for the Helium3 mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeAl, innerTOFExpectedTimeAl, float); //! Reconstructed expected time at the InnerTOF for the Alpha mass hypotheses + +DECLARE_SOA_COLUMN(NSigmaElectronOuterTOF, nSigmaElectronOuterTOF, float); //! NSigma electron OuterTOF +DECLARE_SOA_COLUMN(NSigmaMuonOuterTOF, nSigmaMuonOuterTOF, float); //! NSigma muon OuterTOF +DECLARE_SOA_COLUMN(NSigmaPionOuterTOF, nSigmaPionOuterTOF, float); //! NSigma pion OuterTOF +DECLARE_SOA_COLUMN(NSigmaKaonOuterTOF, nSigmaKaonOuterTOF, float); //! NSigma kaon OuterTOF +DECLARE_SOA_COLUMN(NSigmaProtonOuterTOF, nSigmaProtonOuterTOF, float); //! NSigma proton OuterTOF +DECLARE_SOA_COLUMN(NSigmaDeuteronOuterTOF, nSigmaDeuteronOuterTOF, float); //! NSigma deuteron OuterTOF +DECLARE_SOA_COLUMN(NSigmaTritonOuterTOF, nSigmaTritonOuterTOF, float); //! NSigma triton OuterTOF +DECLARE_SOA_COLUMN(NSigmaHelium3OuterTOF, nSigmaHelium3OuterTOF, float); //! NSigma helium3 OuterTOF +DECLARE_SOA_COLUMN(NSigmaAlphaOuterTOF, nSigmaAlphaOuterTOF, float); //! NSigma alpha OuterTOF +DECLARE_SOA_COLUMN(OuterTOFTrackTimeReco, outerTOFTrackTimeReco, float); //! Track time measured at the OuterTOF +DECLARE_SOA_COLUMN(OuterTOFTrackLengthReco, outerTOFTrackLengthReco, float); //! track length for calculation of OuterTOF (reconstructed) + +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeEl, outerTOFExpectedTimeEl, float); //! Reconstructed expected time at the OuterTOF for the Electron mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeMu, outerTOFExpectedTimeMu, float); //! Reconstructed expected time at the OuterTOF for the Muon mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimePi, outerTOFExpectedTimePi, float); //! Reconstructed expected time at the OuterTOF for the Pion mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeKa, outerTOFExpectedTimeKa, float); //! Reconstructed expected time at the OuterTOF for the Kaon mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimePr, outerTOFExpectedTimePr, float); //! Reconstructed expected time at the OuterTOF for the Proton mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeDe, outerTOFExpectedTimeDe, float); //! Reconstructed expected time at the OuterTOF for the Deuteron mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeTr, outerTOFExpectedTimeTr, float); //! Reconstructed expected time at the OuterTOF for the Triton mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeHe3, outerTOFExpectedTimeHe3, float); //! Reconstructed expected time at the OuterTOF for the Helium3 mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeAl, outerTOFExpectedTimeAl, float); //! Reconstructed expected time at the OuterTOF for the Alpha mass hypotheses +DECLARE_SOA_DYNAMIC_COLUMN(NSigmaInnerTOF, nSigmaInnerTOF, //! General function to get the nSigma for the InnerTOF + [](const float el, + const float mu, + const float pi, + const float ka, + const float pr, + const float de, + const float tr, + const float he3, + const float al, + const int id) -> float { + switch (std::abs(id)) { + case 0: + return el; + case 1: + return mu; + case 2: + return pi; + case 3: + return ka; + case 4: + return pr; + case 5: + return de; + case 6: + return tr; + case 7: + return he3; + case 8: + return al; + default: + LOG(fatal) << "Unrecognized PDG code for InnerTOF"; + return 999.f; + } + }); +DECLARE_SOA_DYNAMIC_COLUMN(NSigmaOuterTOF, nSigmaOuterTOF, //! General function to get the nSigma for the OuterTOF + [](const float el, + const float mu, + const float pi, + const float ka, + const float pr, + const float de, + const float tr, + const float he3, + const float al, + const int id) -> float { + switch (std::abs(id)) { + case 0: + return el; + case 1: + return mu; + case 2: + return pi; + case 3: + return ka; + case 4: + return pr; + case 5: + return de; + case 6: + return tr; + case 7: + return he3; + case 8: + return al; + default: + LOG(fatal) << "Unrecognized PDG code for InnerTOF"; + return 999.f; + } + }); + } // namespace upgrade_tof + +DECLARE_SOA_TABLE(UpgradeTofMCs, "AOD", "UPGRADETOFMC", + upgrade_tof::InnerTOFTrackTime, + upgrade_tof::InnerTOFTrackLength, + upgrade_tof::OuterTOFTrackTime, + upgrade_tof::OuterTOFTrackLength); + DECLARE_SOA_TABLE(UpgradeTofs, "AOD", "UPGRADETOF", + upgrade_tof::TOFEventTime, + upgrade_tof::TOFEventTimeErr, upgrade_tof::NSigmaElectronInnerTOF, upgrade_tof::NSigmaMuonInnerTOF, upgrade_tof::NSigmaPionInnerTOF, upgrade_tof::NSigmaKaonInnerTOF, upgrade_tof::NSigmaProtonInnerTOF, - upgrade_tof::InnerTOFTrackLength, + upgrade_tof::NSigmaDeuteronInnerTOF, + upgrade_tof::NSigmaTritonInnerTOF, + upgrade_tof::NSigmaHelium3InnerTOF, + upgrade_tof::NSigmaAlphaInnerTOF, + upgrade_tof::InnerTOFTrackTimeReco, upgrade_tof::InnerTOFTrackLengthReco, - upgrade_tof::DeltaTrackLengthInnerTOF, upgrade_tof::NSigmaElectronOuterTOF, upgrade_tof::NSigmaMuonOuterTOF, upgrade_tof::NSigmaPionOuterTOF, upgrade_tof::NSigmaKaonOuterTOF, upgrade_tof::NSigmaProtonOuterTOF, - upgrade_tof::OuterTOFTrackLength, + upgrade_tof::NSigmaDeuteronOuterTOF, + upgrade_tof::NSigmaTritonOuterTOF, + upgrade_tof::NSigmaHelium3OuterTOF, + upgrade_tof::NSigmaAlphaOuterTOF, + upgrade_tof::OuterTOFTrackTimeReco, upgrade_tof::OuterTOFTrackLengthReco, - upgrade_tof::DeltaTrackLengthOuterTOF); + upgrade_tof::NSigmaInnerTOF, + upgrade_tof::NSigmaOuterTOF); + +DECLARE_SOA_TABLE(UpgradeTofExpectedTimes, "AOD", "UPGRADETOFEXPT", + upgrade_tof::InnerTOFExpectedTimeEl, + upgrade_tof::InnerTOFExpectedTimeMu, + upgrade_tof::InnerTOFExpectedTimePi, + upgrade_tof::InnerTOFExpectedTimeKa, + upgrade_tof::InnerTOFExpectedTimePr, + upgrade_tof::InnerTOFExpectedTimeDe, + upgrade_tof::InnerTOFExpectedTimeTr, + upgrade_tof::InnerTOFExpectedTimeHe3, + upgrade_tof::InnerTOFExpectedTimeAl, + upgrade_tof::OuterTOFExpectedTimeEl, + upgrade_tof::OuterTOFExpectedTimeMu, + upgrade_tof::OuterTOFExpectedTimePi, + upgrade_tof::OuterTOFExpectedTimeKa, + upgrade_tof::OuterTOFExpectedTimePr, + upgrade_tof::OuterTOFExpectedTimeDe, + upgrade_tof::OuterTOFExpectedTimeTr, + upgrade_tof::OuterTOFExpectedTimeHe3, + upgrade_tof::OuterTOFExpectedTimeAl); +using UpgradeTofMC = UpgradeTofMCs::iterator; using UpgradeTof = UpgradeTofs::iterator; +using UpgradeTofExpectedTime = UpgradeTofExpectedTimes::iterator; } // namespace o2::aod diff --git a/ALICE3/DataModel/OTFTracks.h b/ALICE3/DataModel/OTFTracks.h new file mode 100644 index 00000000000..390e3680716 --- /dev/null +++ b/ALICE3/DataModel/OTFTracks.h @@ -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. + +/// +/// \file OTFTracks.h +/// \author Jesper Karlsson Gumprecht +/// \since 11/11/2025 +/// \brief Table to map track to LUT configuration +/// + +#ifndef ALICE3_DATAMODEL_OTFTRACKS_H_ +#define ALICE3_DATAMODEL_OTFTRACKS_H_ + +// O2 includes +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace otftracks +{ +DECLARE_SOA_COLUMN(LUTConfigId, lutConfigId, int); //! Index for LUT configuration +} // namespace otftracks + +DECLARE_SOA_TABLE(OTFLUTConfigId, "AOD", "OTFLUTConfigId", otftracks::LUTConfigId); +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_OTFTRACKS_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/ML/HfMlResponse3Prong.h b/ALICE3/ML/HfMlResponse3Prong.h new file mode 100644 index 00000000000..24c7b479213 --- /dev/null +++ b/ALICE3/ML/HfMlResponse3Prong.h @@ -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 Alice3MlRResponse3Prong.h +/// \brief Class to compute the ML response for HF 3-prong candidates +/// \author Marcello Di Costanzo , Polytechnic University of Turin and INFN Turin + +#ifndef ALICE3_ML_HFMLRESPONSE3PRONG_H_ +#define ALICE3_ML_HFMLRESPONSE3PRONG_H_ + +#include "Tools/ML/MlResponse.h" + +#include +#include +#include +#include + +// 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_3PRONG(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeatures3Prong::FEATURE) \ + } + +// Specific case of CHECK_AND_FILL_ML_ALICE3_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_ML_ALICE3(GETTER) \ + case static_cast(InputFeatures3Prong::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +namespace o2::analysis +{ +enum class InputFeatures3Prong : uint8_t { + ptProng0 = 0, + ptProng1, + ptProng2, + impactParameterY0, + impactParameterY1, + impactParameterY2, + impactParameterZ0, + impactParameterZ1, + impactParameterZ2, + decayLength, + decayLengthXY, + decayLengthXYNormalised, + cpa, + cpaXY, + chi2PCA, + nSigRichPr0, // 0 + nSigRichKa0, // 0 + nSigRichPi0, // 0 + nSigRichPr1, // 1 + nSigRichKa1, // 1 + nSigRichPi1, // 1 + nSigRichPr2, // 2 + nSigRichKa2, // 2 + nSigRichPi2, // 2 + nSigInnTofPr0, // 0 + nSigInnTofKa0, // 0 + nSigInnTofPi0, // 0 + nSigInnTofPr1, // 1 + nSigInnTofKa1, // 1 + nSigInnTofPi1, // 1 + nSigInnTofPr2, // 2 + nSigInnTofKa2, // 2 + nSigInnTofPi2, // 2 + nSigOutTofPr0, // 0 + nSigOutTofKa0, // 0 + nSigOutTofPi0, // 0 + nSigOutTofPr1, // 1 + nSigOutTofKa1, // 1 + nSigOutTofPi1, // 1 + nSigOutTofPr2, // 2 + nSigOutTofKa2, // 2 + nSigOutTofPi2, // 2 + nSigTrkPr0, // 0 + nSigTrkKa0, // 0 + nSigTrkPi0, // 0 + nSigTrkPr1, // 1 + nSigTrkKa1, // 1 + nSigTrkPi1, // 1 + nSigTrkPr2, // 2 + nSigTrkKa2, // 2 + nSigTrkPi2 // 2 +}; + +template +class HfMlResponse3Prong : public MlResponse +{ + public: + /// Default constructor + HfMlResponse3Prong() = default; + /// Default destructor + virtual ~HfMlResponse3Prong() = default; + + /// Method to get the input features vector needed for ML inference + /// \tparam T1 type of the 3-prong candidate + /// \param candidate is the 3-prong 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_ML_ALICE3(ptProng0); + CHECK_AND_FILL_ML_ALICE3(ptProng1); + CHECK_AND_FILL_ML_ALICE3(ptProng2); + CHECK_AND_FILL_ML_ALICE3(impactParameterY0); + CHECK_AND_FILL_ML_ALICE3(impactParameterY1); + CHECK_AND_FILL_ML_ALICE3(impactParameterY2); + CHECK_AND_FILL_ML_ALICE3(impactParameterZ0); + CHECK_AND_FILL_ML_ALICE3(impactParameterZ1); + CHECK_AND_FILL_ML_ALICE3(impactParameterZ2); + CHECK_AND_FILL_ML_ALICE3(decayLength); + CHECK_AND_FILL_ML_ALICE3(decayLengthXY); + CHECK_AND_FILL_ML_ALICE3(decayLengthXYNormalised); + CHECK_AND_FILL_ML_ALICE3(cpa); + CHECK_AND_FILL_ML_ALICE3(cpaXY); + CHECK_AND_FILL_ML_ALICE3(chi2PCA); + // TRACKER PID variables + CHECK_AND_FILL_ML_ALICE3(nSigTrkPr0); + CHECK_AND_FILL_ML_ALICE3(nSigTrkKa1); + CHECK_AND_FILL_ML_ALICE3(nSigTrkPi2); + // RICH PID variables + CHECK_AND_FILL_ML_ALICE3(nSigRichPr0); + CHECK_AND_FILL_ML_ALICE3(nSigRichKa1); + CHECK_AND_FILL_ML_ALICE3(nSigRichPi2); + // INNER TOF PID variables + CHECK_AND_FILL_ML_ALICE3(nSigInnTofPr0); + CHECK_AND_FILL_ML_ALICE3(nSigInnTofKa1); + CHECK_AND_FILL_ML_ALICE3(nSigInnTofPi2); + // OUTER TOF PID variables + CHECK_AND_FILL_ML_ALICE3(nSigOutTofPr0); + CHECK_AND_FILL_ML_ALICE3(nSigOutTofKa1); + CHECK_AND_FILL_ML_ALICE3(nSigOutTofPi2); + } + } + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_3PRONG(ptProng0), + FILL_MAP_3PRONG(ptProng1), + FILL_MAP_3PRONG(ptProng2), + FILL_MAP_3PRONG(impactParameterY0), + FILL_MAP_3PRONG(impactParameterY1), + FILL_MAP_3PRONG(impactParameterY2), + FILL_MAP_3PRONG(impactParameterZ0), + FILL_MAP_3PRONG(impactParameterZ1), + FILL_MAP_3PRONG(impactParameterZ2), + FILL_MAP_3PRONG(decayLength), + FILL_MAP_3PRONG(decayLengthXY), + FILL_MAP_3PRONG(decayLengthXYNormalised), + FILL_MAP_3PRONG(cpa), + FILL_MAP_3PRONG(cpaXY), + FILL_MAP_3PRONG(chi2PCA), + // RICH PID variables + FILL_MAP_3PRONG(nSigRichPr0), + FILL_MAP_3PRONG(nSigRichKa0), + FILL_MAP_3PRONG(nSigRichPi0), + FILL_MAP_3PRONG(nSigRichPr1), + FILL_MAP_3PRONG(nSigRichKa1), + FILL_MAP_3PRONG(nSigRichPi1), + FILL_MAP_3PRONG(nSigRichPr2), + FILL_MAP_3PRONG(nSigRichKa2), + FILL_MAP_3PRONG(nSigRichPi2), + // INNER TOF PID variables + FILL_MAP_3PRONG(nSigInnTofPr0), + FILL_MAP_3PRONG(nSigInnTofKa0), + FILL_MAP_3PRONG(nSigInnTofPi0), + FILL_MAP_3PRONG(nSigInnTofPr1), + FILL_MAP_3PRONG(nSigInnTofKa1), + FILL_MAP_3PRONG(nSigInnTofPi1), + FILL_MAP_3PRONG(nSigInnTofPr2), + FILL_MAP_3PRONG(nSigInnTofKa2), + FILL_MAP_3PRONG(nSigInnTofPi2), + // OUTER TOF PID variables + FILL_MAP_3PRONG(nSigOutTofPr0), + FILL_MAP_3PRONG(nSigOutTofKa0), + FILL_MAP_3PRONG(nSigOutTofPi0), + FILL_MAP_3PRONG(nSigOutTofPr1), + FILL_MAP_3PRONG(nSigOutTofKa1), + FILL_MAP_3PRONG(nSigOutTofPi1), + FILL_MAP_3PRONG(nSigOutTofPr2), + FILL_MAP_3PRONG(nSigOutTofKa2), + FILL_MAP_3PRONG(nSigOutTofPi2), + // TRACKER PID variables + FILL_MAP_3PRONG(nSigTrkPr0), + FILL_MAP_3PRONG(nSigTrkKa0), + FILL_MAP_3PRONG(nSigTrkPi0), + FILL_MAP_3PRONG(nSigTrkPr1), + FILL_MAP_3PRONG(nSigTrkKa1), + FILL_MAP_3PRONG(nSigTrkPi1), + FILL_MAP_3PRONG(nSigTrkPr2), + FILL_MAP_3PRONG(nSigTrkKa2), + FILL_MAP_3PRONG(nSigTrkPi2)}; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_3PRONG +#undef CHECK_AND_FILL_ML_ALICE3 + +#endif // ALICE3_ML_HFMLRESPONSE3PRONG_H_ diff --git a/ALICE3/TableProducer/CMakeLists.txt b/ALICE3/TableProducer/CMakeLists.txt index 52300bfc644..61f46fba7cd 100644 --- a/ALICE3/TableProducer/CMakeLists.txt +++ b/ALICE3/TableProducer/CMakeLists.txt @@ -21,18 +21,42 @@ o2physics_add_dpl_workflow(alice3-trackextension PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(alice3-pid-tof - SOURCES alice3-pidTOF.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::ALICE3Core - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(alice3-centrality SOURCES alice3-centrality.cxx 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-table + SOURCES alice3-multicharmTable.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-correlatorddbar + SOURCES alice3-correlatorDDbar.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-hf-selector-3prong + SOURCES alice3HfSelector3Prong.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-hf-tree-creator-3prong + SOURCES alice3HfTreeCreator3Prong.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-tracking-translator + SOURCES alice3TrackingTranslator.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/ALICE3/TableProducer/OTF/CMakeLists.txt b/ALICE3/TableProducer/OTF/CMakeLists.txt index 305fcce4b66..69a4d2ec722 100644 --- a/ALICE3/TableProducer/OTF/CMakeLists.txt +++ b/ALICE3/TableProducer/OTF/CMakeLists.txt @@ -11,15 +11,20 @@ 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 - SOURCES onTheFlyTOFPID.cxx + SOURCES onTheFlyTofPid.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(onthefly-richpid - SOURCES onTheFlyRICHPID.cxx + SOURCES onTheFlyRichPid.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(on-the-fly-tracker-pid + SOURCES onTheFlyTrackerPid.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats O2Physics::ALICE3Core COMPONENT_NAME Analysis) diff --git a/ALICE3/TableProducer/OTF/onTheFlyRICHPID.cxx b/ALICE3/TableProducer/OTF/onTheFlyRICHPID.cxx deleted file mode 100644 index af6024f3afd..00000000000 --- a/ALICE3/TableProducer/OTF/onTheFlyRICHPID.cxx +++ /dev/null @@ -1,627 +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 add a table of track parameters propagated to the primary vertex -// - -#include -#include - -#include - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/trackUtilities.h" -#include "ReconstructionDataFormats/DCA.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "CommonUtils/NameConf.h" -#include "CCDB/CcdbApi.h" -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsCalibration/MeanVertexObject.h" -#include "CommonConstants/GeomConstants.h" -#include "CommonConstants/PhysicsConstants.h" -#include "TRandom3.h" -#include "TVector3.h" -#include "TString.h" -#include "ALICE3/DataModel/OTFRICH.h" -#include "DetectorsVertexing/HelixHelper.h" - -#include "TableHelper.h" -#include "ALICE3/Core/DelphesO2TrackSmearer.h" - -/// \file onTheFlyRichPid.cxx -/// -/// \brief This task goes straight from a combination of track table and mcParticles -/// and a projective bRICH configuration to a table of TOF NSigmas for the particles -/// being analysed. It currently contemplates 5 particle types: -/// electrons, pions, kaons, protons and muons. -/// -/// More particles could be added but would have to be added to the LUT -/// being used in the onTheFly tracker task. -/// -/// \warning Geometry parameters are configurable, but resolution values should be adapted. -/// Since angular resolution depends on the specific geometric details, it is better to -/// calculate it from full simulation and add new input. Alternatively, an analytical -/// expression can be provided as a function of the main parameters. -/// -/// \author David Dobrigkeit Chinellato, UNICAMP, Nicola Nicassio, University and INFN Bari - -using namespace o2; -using namespace o2::framework; - -struct OnTheFlyRichPid { - Produces upgradeRich; - - // necessary for particle charges - Service pdg; - - // master setting: magnetic field - Configurable dBz{"dBz", 20, "magnetic field (kilogauss)"}; - - // add rich-specific configurables here - Configurable bRichNumberOfSectors{"bRichNumberOfSectors", 21, "barrel RICH number of sectors"}; - Configurable bRichPhotodetectorCentralModuleHalfLength{"bRichPhotodetectorCentralModuleHalfLength", 18.4 / 2.0, "barrel RICH photodetector central module half length (cm)"}; - Configurable bRichPhotodetectorOtherModuleLength{"bRichPhotodetectorOtherModuleLength", 18.4, "barrel RICH photodetector other module length (cm)"}; - Configurable bRichRadiatorInnerRadius{"bRichRadiatorInnerRadius", 85., "barrel RICH radiator inner radius (cm)"}; - Configurable bRichPhotodetectorOuterRadius{"bRichPhotodetectorOuterRadius", 112., "barrel RICH photodetector outer radius (cm)"}; - Configurable bRichRadiatorThickness{"bRichRadiatorThickness", 2., "barrel RICH radiator thickness (cm)"}; - Configurable bRichRefractiveIndex{"bRichRefractiveIndex", 1.03, "barrel RICH refractive index"}; - Configurable bRichFlagAbsorbingWalls{"bRichFlagAbsorbingWalls", false, "barrel RICH flag absorbing walls between sectors"}; - Configurable nStepsLIntegrator{"nStepsLIntegrator", 200, "number of steps in length integrator"}; - Configurable doQAplots{"doQAplots", true, "do basic velocity plot qa"}; - Configurable nBinsThetaRing{"nBinsThetaRing", 3000, "number of bins in theta ring"}; - Configurable nBinsP{"nBinsP", 400, "number of bins in momentum"}; - 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 nBinsAngularRes{"nBinsAngularRes", 400, "number of bins plots angular 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"}; - Configurable flagIncludeTrackAngularRes{"flagIncludeTrackAngularRes", true, "flag to include or exclude track time resolution"}; - Configurable multiplicityEtaRange{"multiplicityEtaRange", 0.800000012, "eta range to compute the multiplicity"}; - Configurable flagRICHLoadDelphesLUTs{"flagRICHLoadDelphesLUTs", false, "flag to load Delphes LUTs for tracking correction (use recoTrack parameters if false)"}; - - Configurable lutEl{"lutEl", "lutCovm.el.dat", "LUT for electrons"}; - Configurable lutMu{"lutMu", "lutCovm.mu.dat", "LUT for muons"}; - Configurable lutPi{"lutPi", "lutCovm.pi.dat", "LUT for pions"}; - Configurable lutKa{"lutKa", "lutCovm.ka.dat", "LUT for kaons"}; - Configurable lutPr{"lutPr", "lutCovm.pr.dat", "LUT for protons"}; - - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - - // Track smearer (here used to get relative pt and eta uncertainties) - o2::delphes::DelphesO2TrackSmearer mSmearer; - - // needed: random number generator for smearing - TRandom3 pRandomNumberGenerator; - - // for handling basic QA histograms if requested - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - /// Flag unphysical and unavailable values - float error_value = -1000; - - // Variables projective/hybrid layout - int mNumberSectors = bRichNumberOfSectors; // 21; - float mTileLength = bRichPhotodetectorOtherModuleLength; // 18.4; // [cm] - float mTileLengthCentral = bRichPhotodetectorCentralModuleHalfLength; // 18.4 / 2.0; // [cm] - float mProjectiveLengthInner = mTileLengthCentral; - float mRadiusProjIn = bRichRadiatorInnerRadius; // 85.; // [cm] - float mRadiusProjOut = bRichPhotodetectorOuterRadius; // 112.; // [cm] - std::vector det_centers; - std::vector rad_centers; - std::vector angle_centers; - std::vector theta_min; - std::vector theta_max; - - // Update projective geometry - void updateProjectiveParameters() - { - const int number_of_sectors_in_z = mNumberSectors; - det_centers.resize(number_of_sectors_in_z); - rad_centers.resize(number_of_sectors_in_z); - angle_centers.resize(number_of_sectors_in_z); - theta_min.resize(number_of_sectors_in_z); - theta_max.resize(number_of_sectors_in_z); - float square_size_barrel_cylinder = 2.0 * mTileLengthCentral; - float square_size_z = mTileLength; - float R_min = mRadiusProjIn; - float R_max = mRadiusProjOut; - std::vector theta_bi; - std::vector R0_tilt; - std::vector z0_tilt; - std::vector T_r_plus_g; - std::vector l_aerogel_z; - std::vector l_detector_z; - theta_bi.resize(number_of_sectors_in_z); - R0_tilt.resize(number_of_sectors_in_z); - z0_tilt.resize(number_of_sectors_in_z); - T_r_plus_g.resize(number_of_sectors_in_z); - l_aerogel_z.resize(number_of_sectors_in_z); - l_detector_z.resize(number_of_sectors_in_z); - - // Central sector - int i_central_mirror = static_cast((number_of_sectors_in_z) / 2.0); - float m_val = std::tan(0.0); - theta_bi[i_central_mirror] = std::atan(m_val); - R0_tilt[i_central_mirror] = R_max; - z0_tilt[i_central_mirror] = R0_tilt[i_central_mirror] * std::tan(theta_bi[i_central_mirror]); - l_detector_z[i_central_mirror] = square_size_barrel_cylinder; - l_aerogel_z[i_central_mirror] = std::sqrt(1.0 + m_val * m_val) * R_min * square_size_barrel_cylinder / (std::sqrt(1.0 + m_val * m_val) * R_max - m_val * square_size_barrel_cylinder); - T_r_plus_g[i_central_mirror] = R_max - R_min; - float t = std::tan(atan(m_val) + std::atan(square_size_barrel_cylinder / (2.0 * R_max * std::sqrt(1.0 + m_val * m_val) - square_size_barrel_cylinder * m_val))); - theta_max[i_central_mirror] = M_PI / 2.0 - std::atan(t); - theta_min[i_central_mirror] = M_PI / 2.0 + std::atan(t); - mProjectiveLengthInner = R_min * t; - for (int i = static_cast((number_of_sectors_in_z) / 2.0) + 1; i < number_of_sectors_in_z; i++) { - float par_a = t; - float par_b = 2.0 * R_max / square_size_z; - m_val = (std::sqrt(par_a * par_a * par_b * par_b + par_b * par_b - 1.0) + par_a * par_b * par_b) / (par_b * par_b - 1.0); - theta_min[i] = M_PI / 2.0 - std::atan(t); - theta_max[2 * i_central_mirror - i] = M_PI / 2.0 + std::atan(t); - t = std::tan(std::atan(m_val) + std::atan(square_size_z / (2.0 * R_max * std::sqrt(1.0 + m_val * m_val) - square_size_z * m_val))); - theta_max[i] = M_PI / 2.0 - std::atan(t); - theta_min[2 * i_central_mirror - i] = M_PI / 2.0 + std::atan(t); - // Forward sectors - theta_bi[i] = std::atan(m_val); - R0_tilt[i] = R_max - square_size_z / 2.0 * std::sin(std::atan(m_val)); - z0_tilt[i] = R0_tilt[i] * std::tan(theta_bi[i]); - l_detector_z[i] = square_size_z; - l_aerogel_z[i] = std::sqrt(1.0 + m_val * m_val) * R_min * square_size_z / (std::sqrt(1.0 + m_val * m_val) * R_max - m_val * square_size_z); - T_r_plus_g[i] = std::sqrt(1.0 + m_val * m_val) * (R_max - R_min) - m_val / 2.0 * (square_size_z + l_aerogel_z[i]); - // Backword sectors - theta_bi[2 * i_central_mirror - i] = -std::atan(m_val); - R0_tilt[2 * i_central_mirror - i] = R_max - square_size_z / 2.0 * std::sin(std::atan(m_val)); - z0_tilt[2 * i_central_mirror - i] = -R0_tilt[i] * std::tan(theta_bi[i]); - l_detector_z[2 * i_central_mirror - i] = square_size_z; - l_aerogel_z[2 * i_central_mirror - i] = std::sqrt(1.0 + m_val * m_val) * R_min * square_size_z / (std::sqrt(1.0 + m_val * m_val) * R_max - m_val * square_size_z); - T_r_plus_g[2 * i_central_mirror - i] = std::sqrt(1.0 + m_val * m_val) * (R_max - R_min) - m_val / 2.0 * (square_size_z + l_aerogel_z[i]); - mProjectiveLengthInner = R_min * t; // <-- At the end of the loop this will be the maximum Z - } - // Coordinate radiali layer considerati - std::vector R0_detector; - std::vector R0_aerogel; - R0_detector.resize(number_of_sectors_in_z); - R0_aerogel.resize(number_of_sectors_in_z); - for (int i = 0; i < number_of_sectors_in_z; i++) { - R0_detector[i] = R0_tilt[i]; - det_centers[i].SetXYZ(R0_detector[i], 0, R0_detector[i] * std::tan(theta_bi[i])); - R0_aerogel[i] = R0_tilt[i] - (T_r_plus_g[i]) * std::cos(theta_bi[i]); - rad_centers[i].SetXYZ(R0_aerogel[i], 0, R0_aerogel[i] * std::tan(theta_bi[i])); - angle_centers[i] = theta_bi[i]; - } - } - - void init(o2::framework::InitContext&) - { - pRandomNumberGenerator.SetSeed(0); // fully randomize - - // Load LUT for pt and eta smearing - if (flagIncludeTrackAngularRes && flagRICHLoadDelphesLUTs) { - std::map mapPdgLut; - const char* lutElChar = lutEl->c_str(); - const char* lutMuChar = lutMu->c_str(); - const char* lutPiChar = lutPi->c_str(); - const char* lutKaChar = lutKa->c_str(); - const char* lutPrChar = lutPr->c_str(); - - LOGF(info, "Will load electron lut file ..: %s for RICH PID", lutElChar); - LOGF(info, "Will load muon lut file ......: %s for RICH PID", lutMuChar); - LOGF(info, "Will load pion lut file ......: %s for RICH PID", lutPiChar); - LOGF(info, "Will load kaon lut file ......: %s for RICH PID", lutKaChar); - LOGF(info, "Will load proton lut file ....: %s for RICH PID", lutPrChar); - - mapPdgLut.insert(std::make_pair(11, lutElChar)); - mapPdgLut.insert(std::make_pair(13, lutMuChar)); - mapPdgLut.insert(std::make_pair(211, lutPiChar)); - mapPdgLut.insert(std::make_pair(321, lutKaChar)); - mapPdgLut.insert(std::make_pair(2212, lutPrChar)); - - for (auto e : mapPdgLut) { - if (!mSmearer.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; - } - } - } - - if (doQAplots) { - const AxisSpec axisMomentum{static_cast(nBinsP), 0.0f, +20.0f, "#it{p} (GeV/#it{c})"}; - const AxisSpec axisAngle{static_cast(nBinsThetaRing), 0.0f, +0.30f, "Measured Cherenkov angle (rad)"}; - histos.add("h2dAngleVsMomentumBarrelRICH", "h2dAngleVsMomentumBarrelRICH", kTH2F, {axisMomentum, axisAngle}); - - std::string particle_names1[5] = {"#it{e}", "#it{#mu}", "#it{#pi}", "#it{K}", "#it{p}"}; - std::string particle_names2[5] = {"Elec", "Muon", "Pion", "Kaon", "Prot"}; - for (int i_true = 0; i_true < 5; i_true++) { - std::string name_title_barrel_track_res = "h2dBarrelAngularResTrack" + particle_names2[i_true] + "VsP"; - std::string name_title_barrel_total_res = "h2dBarrelAngularResTotal" + particle_names2[i_true] + "VsP"; - const AxisSpec axisTrackAngularRes{static_cast(nBinsAngularRes), 0.0f, +5.0f, "Track angular resolution - " + particle_names1[i_true] + " (mrad)"}; - const AxisSpec axisTotalAngularRes{static_cast(nBinsAngularRes), 0.0f, +5.0f, "Total angular resolution - " + particle_names1[i_true] + " (mrad)"}; - histos.add(name_title_barrel_track_res.c_str(), name_title_barrel_track_res.c_str(), kTH2F, {axisMomentum, axisTrackAngularRes}); - histos.add(name_title_barrel_total_res.c_str(), name_title_barrel_total_res.c_str(), kTH2F, {axisMomentum, axisTotalAngularRes}); - } - for (int i_true = 0; i_true < 5; i_true++) { - for (int i_hyp = 0; i_hyp < 5; i_hyp++) { - std::string name_title = "h2dBarrelNsigmaTrue" + 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"}; - histos.add(name_title.c_str(), name_title.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"}; - histos.add(name_title.c_str(), name_title.c_str(), kTH2F, {axisMomentum, axisNsigmaWrong}); - } - } - } - } - - // Update projective parameters - updateProjectiveParameters(); - } - - /// Function to convert a McParticle into a perfect Track - /// \param particle the particle to convert (mcParticle) - /// \param o2track the address of the resulting TrackParCov - template - o2::track::TrackParCov convertMCParticleToO2Track(McParticleType& particle) - { - // FIXME: this is a fundamentally important piece of code. - // It could be placed in a utility file instead of here. - auto pdgInfo = pdg->GetParticle(particle.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(particle.phi(), s, c); - o2::math_utils::rotateZInv(particle.vx(), particle.vy(), x, params[0], s, c); - params[1] = particle.vz(); - params[2] = 0.; // since alpha = phi - auto theta = 2. * std::atan(std::exp(-particle.eta())); - params[3] = 1. / std::tan(theta); - params[4] = charge / particle.pt(); - - // Return TrackParCov - return o2::track::TrackParCov(x, particle.phi(), params, covm); - } - - /// check if particle reaches radiator - /// \param track the input track - /// \param radius the radius of the layer you're calculating the length to - /// \param magneticField the magnetic field to use when propagating - bool checkMagfieldLimit(o2::track::TrackParCov track, float radius, float magneticField) - { - o2::math_utils::CircleXYf_t trcCircle; - float sna, csa; - track.getCircleParams(magneticField, trcCircle, sna, csa); - - // distance between circle centers (one circle is at origin -> easy) - float centerDistance = std::hypot(trcCircle.xC, trcCircle.yC); - - // condition of circles touching - if not satisfied returned value if false - if (centerDistance < trcCircle.rC + radius && centerDistance > std::fabs(trcCircle.rC - radius)) { - return true; - } else { - return false; - } - } - - /// returns radiator radius in cm at considered eta (accounting for sector inclination) - /// \param eta the pseudorapidity of the tarck (assuming primary vertex at origin) - float radiusRipple(float eta) - { - float polar = 2.0 * std::atan(std::exp(-eta)); - float i_sector = 0; - bool flag_sector = false; - for (int j_sec = 0; j_sec < mNumberSectors; j_sec++) { - if (polar > theta_max[j_sec] && polar < theta_min[j_sec]) { - flag_sector = true; - i_sector = j_sec; - } - } - if (flag_sector) { - float R_sec_rich = rad_centers[i_sector].X(); - float z_sec_rich = rad_centers[i_sector].Z(); - return (std::pow(R_sec_rich, 2) + std::pow(z_sec_rich, 2)) / (R_sec_rich + z_sec_rich / std::tan(polar)); - } else { - return error_value; - } - } - - /// returns Cherenkov angle in rad (above threshold) or bad flag (below threshold) - /// \param momentum the momentum of the tarck - /// \param mass the mass of the particle - float CherenkovAngle(float momentum, float mass) - { - // Check if particle is above the threshold - if (momentum > mass / std::sqrt(bRichRefractiveIndex * bRichRefractiveIndex - 1.0)) { - // Calculate angle - float angle = std::acos(std::sqrt(momentum * momentum + mass * mass) / (momentum * bRichRefractiveIndex)); - - // Mean number of detected photons (SiPM PDE is accountd in multiplicative factor!!!) - float meanNumberofDetectedPhotons = 230. * std::sin(angle) * std::sin(angle) * bRichRadiatorThickness; - - // Require at least 3 photons on average for real angle reconstruction - if (meanNumberofDetectedPhotons > 3.) { - return angle; - } else { - return error_value; - } - } else { - return error_value; - } - } - - /// returns linear interpolation - /// \param x the eta we want the resolution for - /// \param x0 the closest smaller available eta - /// \param x1 the closest larger available eta - /// \param y0 the resolution corresponding to x0 - /// \param y1 the resolution corresponding to x1 - float interpolate(double x, double x0, double x1, double y0, double y1) - { - float y = y0 + ((y1 - y0) / (x1 - x0)) * (x - x0); - return y; - } - - /// returns angular resolution for considered track eta - /// \param eta the pseudorapidity of the tarck (assuming primary vertex at origin) - float AngularResolution(float eta) - { - // Vectors for sampling (USE ANALYTICAL EXTRAPOLATION FOR BETTER RESULTS) - float eta_sampling[] = {-2.000000, -1.909740, -1.731184, -1.552999, -1.375325, -1.198342, -1.022276, -0.847390, -0.673976, -0.502324, -0.332683, -0.165221, 0.000000, 0.165221, 0.332683, 0.502324, 0.673976, 0.847390, 1.022276, 1.198342, 1.375325, 1.552999, 1.731184, 1.909740, 2.000000}; - float res_ring_sampling_with_abs_walls[] = {0.0009165, 0.000977, 0.001098, 0.001198, 0.001301, 0.001370, 0.001465, 0.001492, 0.001498, 0.001480, 0.001406, 0.001315, 0.001241, 0.001325, 0.001424, 0.001474, 0.001480, 0.001487, 0.001484, 0.001404, 0.001273, 0.001197, 0.001062, 0.000965, 0.0009165}; - float res_ring_sampling_without_abs_walls[] = {0.0009165, 0.000977, 0.001095, 0.001198, 0.001300, 0.001369, 0.001468, 0.001523, 0.001501, 0.001426, 0.001299, 0.001167, 0.001092, 0.001179, 0.001308, 0.001407, 0.001491, 0.001508, 0.001488, 0.001404, 0.001273, 0.001196, 0.001061, 0.000965, 0.0009165}; - int size_res_vector = sizeof(eta_sampling) / sizeof(eta_sampling[0]); - // Use binary search to find the lower and upper indices - int lowerIndex = std::lower_bound(eta_sampling, eta_sampling + size_res_vector, eta) - eta_sampling - 1; - int upperIndex = lowerIndex + 1; - if (lowerIndex >= 0 && upperIndex < size_res_vector) { - // Resolution interpolation - if (bRichFlagAbsorbingWalls) { - float interpolatedResRing = interpolate(eta, eta_sampling[lowerIndex], eta_sampling[upperIndex], res_ring_sampling_with_abs_walls[lowerIndex], res_ring_sampling_with_abs_walls[upperIndex]); - // std::cout << "Interpolated y value: " << interpolatedY << std::endl; - return interpolatedResRing; - } else { - float interpolatedResRing = interpolate(eta, eta_sampling[lowerIndex], eta_sampling[upperIndex], res_ring_sampling_without_abs_walls[lowerIndex], res_ring_sampling_without_abs_walls[upperIndex]); - // std::cout << "Interpolated y value: " << interpolatedY << std::endl; - return interpolatedResRing; - } - } else { - // std::cout << "Unable to interpolate. Target x value is outside the range of available data." << std::endl; - return error_value; - } - } - - /// returns track angular resolution - /// \param pt the transverse momentum of the tarck - /// \param eta the pseudorapidity of the tarck - /// \param track_pt_resolution the absolute resolution on pt - /// \param track_pt_resolution the absolute resolution on eta - /// \param mass the mass of the particle - /// \param refractive_index the refractive index of the radiator - double calculate_track_time_resolution_advanced(float pt, float eta, float track_pt_resolution, float track_eta_resolution, float mass, float refractive_index) - { - // Compute tracking contribution to timing using the error propagation formula - // Uses light speed in m/ps, magnetic field in T (*0.1 for conversion kGauss -> T) - double a0 = mass * mass; - double a1 = refractive_index; - double dtheta_on_dpt = a0 / (pt * std::sqrt(a0 + std::pow(pt * std::cosh(eta), 2)) * std::sqrt(std::pow(pt * std::cosh(eta), 2) * (std::pow(a1, 2) - 1.0) - a0)); - double dtheta_on_deta = (a0 * std::tanh(eta)) / (std::sqrt(a0 + std::pow(pt * std::cosh(eta), 2)) * std::sqrt(std::pow(pt * std::cosh(eta), 2) * (std::pow(a1, 2) - 1.0) - a0)); - double track_angular_resolution = std::hypot(std::fabs(dtheta_on_dpt) * track_pt_resolution, std::fabs(dtheta_on_deta) * track_eta_resolution); - return track_angular_resolution; - } - - void process(soa::Join::iterator const& collision, soa::Join const& tracks, aod::McParticles const&, aod::McCollisions const&) - { - - o2::dataformats::VertexBase pvVtx({collision.posX(), collision.posY(), collision.posZ()}, - {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}); - - std::array mcPvCov = {0.}; - o2::dataformats::VertexBase mcPvVtx({0.0f, 0.0f, 0.0f}, mcPvCov); - if (collision.has_mcCollision()) { - auto mcCollision = collision.mcCollision(); - mcPvVtx.setX(mcCollision.posX()); - mcPvVtx.setY(mcCollision.posY()); - mcPvVtx.setZ(mcCollision.posZ()); - } // else remains untreated for now - - // First we compute the number of charged particles in the event - float dNdEta = 0.f; - if (flagRICHLoadDelphesLUTs) { - for (const auto& track : tracks) { - if (!track.has_mcParticle()) - continue; - auto mcParticle = track.mcParticle(); - if (std::abs(mcParticle.eta()) > multiplicityEtaRange) { - continue; - } - if (mcParticle.has_daughters()) { - continue; - } - const auto& pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); - if (!pdgInfo) { - // LOG(warning) << "PDG code " << mcParticle.pdgCode() << " not found in the database"; - continue; - } - if (pdgInfo->Charge() == 0) { - continue; - } - dNdEta += 1.f; - } - } - - for (const auto& track : tracks) { - // first step: find precise arrival time (if any) - // --- convert track into perfect track - if (!track.has_mcParticle()) // should always be OK but check please - continue; - - auto mcParticle = track.mcParticle(); - o2::track::TrackParCov o2track = convertMCParticleToO2Track(mcParticle); - - // float xPv = error_value; - if (o2track.propagateToDCA(mcPvVtx, dBz)) { - // xPv = o2track.getX(); - } - - // get particle to calculate Cherenkov angle and resolution - auto pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); - if (pdgInfo == nullptr) { - continue; - } - float expectedAngleBarrelRich = CherenkovAngle(o2track.getP(), pdgInfo->Mass()); - float barrelRICHAngularResolution = AngularResolution(o2track.getEta()); - float projectiveRadiatorRadius = radiusRipple(o2track.getEta()); - bool flagReachesRadiator = false; - if (projectiveRadiatorRadius > error_value + 1.) { - flagReachesRadiator = checkMagfieldLimit(o2track, projectiveRadiatorRadius, dBz); - } - /// DISCLAIMER: Exact extrapolation of angular resolution would require track propagation - /// to the RICH radiator (accounting sector inclination) in terms of (R,z). - /// The extrapolation with Eta is correct only if the primary vertex is at origin. - /// Discrepancies may be negligible, but would be more rigorous if propagation tool is available - - // Smear with expected resolutions - float measuredAngleBarrelRich = pRandomNumberGenerator.Gaus(expectedAngleBarrelRich, barrelRICHAngularResolution); - - // Now we calculate the expected arrival time following certain mass hypotheses - // and the (imperfect!) reconstructed track parametrizations - auto recoTrack = getTrackParCov(track); - if (recoTrack.propagateToDCA(pvVtx, dBz)) { - // xPv = recoTrack.getX(); - } - - // Straight to Nsigma - float deltaThetaBarrelRich[5], nSigmaBarrelRich[5]; - int lpdg_array[5] = {kElectron, kMuonMinus, kPiPlus, kKPlus, kProton}; - float masses[5]; - - for (int ii = 0; ii < 5; ii++) { - nSigmaBarrelRich[ii] = error_value; - - auto pdgInfoThis = pdg->GetParticle(lpdg_array[ii]); - masses[ii] = pdgInfoThis->Mass(); - float hypothesisAngleBarrelRich = CherenkovAngle(recoTrack.getP(), masses[ii]); - - // Evaluate total sigma (layer + tracking resolution) - float barrelTotalAngularReso = barrelRICHAngularResolution; - if (flagIncludeTrackAngularRes) { - double pt_resolution = std::pow(recoTrack.getP() / std::cosh(recoTrack.getEta()), 2) * std::sqrt(recoTrack.getSigma1Pt2()); - double eta_resolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-recoTrack.getEta())))) * std::sqrt(recoTrack.getSigmaTgl2()); - if (flagRICHLoadDelphesLUTs) { - pt_resolution = mSmearer.getAbsPtRes(pdgInfoThis->PdgCode(), dNdEta, recoTrack.getEta(), recoTrack.getP() / std::cosh(recoTrack.getEta())); - eta_resolution = mSmearer.getAbsEtaRes(pdgInfoThis->PdgCode(), dNdEta, recoTrack.getEta(), recoTrack.getP() / std::cosh(recoTrack.getEta())); - } - // cout << endl << "Pt resolution: " << pt_resolution << ", Eta resolution: " << eta_resolution << endl << endl; - float barrelTrackAngularReso = calculate_track_time_resolution_advanced(recoTrack.getP() / std::cosh(recoTrack.getEta()), recoTrack.getEta(), pt_resolution, eta_resolution, masses[ii], bRichRefractiveIndex); - barrelTotalAngularReso = std::hypot(barrelRICHAngularResolution, barrelTrackAngularReso); - if (doQAplots && hypothesisAngleBarrelRich > error_value + 1. && measuredAngleBarrelRich > error_value + 1. && barrelRICHAngularResolution > error_value + 1. && flagReachesRadiator) { - float momentum = recoTrack.getP(); - // float pseudorapidity = recoTrack.getEta(); - // float transverse_momentum = momentum / std::cosh(pseudorapidity); - if (ii == 0 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[0])->PdgCode()) { - histos.fill(HIST("h2dBarrelAngularResTrackElecVsP"), momentum, 1000.0 * barrelTrackAngularReso); - histos.fill(HIST("h2dBarrelAngularResTotalElecVsP"), momentum, 1000.0 * barrelTotalAngularReso); - } - if (ii == 1 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[1])->PdgCode()) { - histos.fill(HIST("h2dBarrelAngularResTrackMuonVsP"), momentum, 1000.0 * barrelTrackAngularReso); - histos.fill(HIST("h2dBarrelAngularResTotalMuonVsP"), momentum, 1000.0 * barrelTotalAngularReso); - } - if (ii == 2 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[2])->PdgCode()) { - histos.fill(HIST("h2dBarrelAngularResTrackPionVsP"), momentum, 1000.0 * barrelTrackAngularReso); - histos.fill(HIST("h2dBarrelAngularResTotalPionVsP"), momentum, 1000.0 * barrelTotalAngularReso); - } - if (ii == 3 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[3])->PdgCode()) { - histos.fill(HIST("h2dBarrelAngularResTrackKaonVsP"), momentum, 1000.0 * barrelTrackAngularReso); - histos.fill(HIST("h2dBarrelAngularResTotalKaonVsP"), momentum, 1000.0 * barrelTotalAngularReso); - } - if (ii == 4 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[4])->PdgCode()) { - histos.fill(HIST("h2dBarrelAngularResTrackProtVsP"), momentum, 1000.0 * barrelTrackAngularReso); - histos.fill(HIST("h2dBarrelAngularResTotalProtVsP"), momentum, 1000.0 * barrelTotalAngularReso); - } - } - } - - /// DISCLAIMER: here tracking is accounted only for momentum value, but not for track parameters at impact point on the - /// RICH radiator, since exact resolution would require photon generation and transport to photodetector. - /// Effects are expected to be negligible (a few tenths of a milliradian) but further studies are required ! - if (hypothesisAngleBarrelRich > error_value + 1. && measuredAngleBarrelRich > error_value + 1. && barrelRICHAngularResolution > error_value + 1. && flagReachesRadiator) { - deltaThetaBarrelRich[ii] = hypothesisAngleBarrelRich - measuredAngleBarrelRich; - nSigmaBarrelRich[ii] = deltaThetaBarrelRich[ii] / barrelTotalAngularReso; - } - } - - // Fill histograms - if (doQAplots) { - float momentum = recoTrack.getP(); - float barrelRichTheta = measuredAngleBarrelRich; - - if (barrelRichTheta > error_value + 1. && barrelRICHAngularResolution > error_value + 1. && flagReachesRadiator) { - histos.fill(HIST("h2dAngleVsMomentumBarrelRICH"), momentum, barrelRichTheta); - - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[0])->PdgCode()) { - histos.fill(HIST("h2dBarrelNsigmaTrueElecVsElecHypothesis"), momentum, nSigmaBarrelRich[0]); - histos.fill(HIST("h2dBarrelNsigmaTrueElecVsMuonHypothesis"), momentum, nSigmaBarrelRich[1]); - histos.fill(HIST("h2dBarrelNsigmaTrueElecVsPionHypothesis"), momentum, nSigmaBarrelRich[2]); - histos.fill(HIST("h2dBarrelNsigmaTrueElecVsKaonHypothesis"), momentum, nSigmaBarrelRich[3]); - histos.fill(HIST("h2dBarrelNsigmaTrueElecVsProtHypothesis"), momentum, nSigmaBarrelRich[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[1])->PdgCode()) { - histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsElecHypothesis"), momentum, nSigmaBarrelRich[0]); - histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsMuonHypothesis"), momentum, nSigmaBarrelRich[1]); - histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsPionHypothesis"), momentum, nSigmaBarrelRich[2]); - histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsKaonHypothesis"), momentum, nSigmaBarrelRich[3]); - histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsProtHypothesis"), momentum, nSigmaBarrelRich[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[2])->PdgCode()) { - histos.fill(HIST("h2dBarrelNsigmaTruePionVsElecHypothesis"), momentum, nSigmaBarrelRich[0]); - histos.fill(HIST("h2dBarrelNsigmaTruePionVsMuonHypothesis"), momentum, nSigmaBarrelRich[1]); - histos.fill(HIST("h2dBarrelNsigmaTruePionVsPionHypothesis"), momentum, nSigmaBarrelRich[2]); - histos.fill(HIST("h2dBarrelNsigmaTruePionVsKaonHypothesis"), momentum, nSigmaBarrelRich[3]); - histos.fill(HIST("h2dBarrelNsigmaTruePionVsProtHypothesis"), momentum, nSigmaBarrelRich[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[3])->PdgCode()) { - histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsElecHypothesis"), momentum, nSigmaBarrelRich[0]); - histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsMuonHypothesis"), momentum, nSigmaBarrelRich[1]); - histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsPionHypothesis"), momentum, nSigmaBarrelRich[2]); - histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsKaonHypothesis"), momentum, nSigmaBarrelRich[3]); - histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsProtHypothesis"), momentum, nSigmaBarrelRich[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[4])->PdgCode()) { - histos.fill(HIST("h2dBarrelNsigmaTrueProtVsElecHypothesis"), momentum, nSigmaBarrelRich[0]); - histos.fill(HIST("h2dBarrelNsigmaTrueProtVsMuonHypothesis"), momentum, nSigmaBarrelRich[1]); - histos.fill(HIST("h2dBarrelNsigmaTrueProtVsPionHypothesis"), momentum, nSigmaBarrelRich[2]); - histos.fill(HIST("h2dBarrelNsigmaTrueProtVsKaonHypothesis"), momentum, nSigmaBarrelRich[3]); - histos.fill(HIST("h2dBarrelNsigmaTrueProtVsProtHypothesis"), momentum, nSigmaBarrelRich[4]); - } - } - } - - // Sigmas have been fully calculated. Please populate the NSigma helper table (once per track) - upgradeRich(nSigmaBarrelRich[0], nSigmaBarrelRich[1], nSigmaBarrelRich[2], nSigmaBarrelRich[3], nSigmaBarrelRich[4]); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx new file mode 100644 index 00000000000..357e208f95f --- /dev/null +++ b/ALICE3/TableProducer/OTF/onTheFlyRichPid.cxx @@ -0,0 +1,1041 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file onTheFlyRichPid.cxx +/// +/// \brief This task goes straight from a combination of track table and mcParticles +/// and a projective bRICH configuration to a table of TOF NSigmas for the particles +/// being analysed. It currently contemplates 5 particle types: +/// electrons, pions, kaons, protons and muons +/// +/// More particles could be added but would have to be added to the LUT +/// being used in the onTheFly tracker task. +/// +/// \warning Geometry parameters are configurable, but resolution values should be adapted. +/// Since angular resolution depends on the specific geometric details, it is better to +/// calculate it from full simulation and add new input. Alternatively, an analytical +/// expression can be provided as a function of the main parameters. +/// Latest version: analytical parametrization of angular resolution !!! +/// +/// \author David Dobrigkeit Chinellato, UNICAMP +/// \author Nicola Nicassio, University and INFN Bari +/// \since May 22, 2024 +/// + +#include "TableHelper.h" + +#include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include "ALICE3/Core/TrackUtilities.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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::constants::math; + +struct OnTheFlyRichPid { + Produces upgradeRich; + Produces upgradeRichSignal; + + // necessary for particle charges + Service pdg; + // Necessary for LUTs + Service ccdb; + + // master setting: magnetic field + Configurable magneticField{"magneticField", 0, "magnetic field (kilogauss) if 0, taken from the tracker task"}; + + // add rich-specific configurables here + Configurable bRichNumberOfSectors{"bRichNumberOfSectors", 21, "barrel RICH number of sectors"}; + Configurable bRichPhotodetectorCentralModuleHalfLength{"bRichPhotodetectorCentralModuleHalfLength", 18.4 / 2.0, "barrel RICH photodetector central module half length (cm)"}; + Configurable bRichPhotodetectorOtherModuleLength{"bRichPhotodetectorOtherModuleLength", 18.4, "barrel RICH photodetector other module length (cm)"}; + Configurable bRichRadiatorInnerRadius{"bRichRadiatorInnerRadius", 85., "barrel RICH radiator inner radius (cm)"}; + Configurable bRichPhotodetectorOuterRadius{"bRichPhotodetectorOuterRadius", 112., "barrel RICH photodetector outer radius (cm)"}; + Configurable bRichRadiatorThickness{"bRichRadiatorThickness", 2., "barrel RICH radiator thickness (cm)"}; + Configurable bRichRefractiveIndex{"bRichRefractiveIndex", 1.03, "barrel RICH refractive index"}; + Configurable bRichFlagAbsorbingWalls{"bRichFlagAbsorbingWalls", false, "barrel RICH flag absorbing walls between sectors"}; + Configurable nStepsLIntegrator{"nStepsLIntegrator", 200, "number of steps in length integrator"}; + Configurable doQAplots{"doQAplots", true, "do basic velocity plot qa"}; + Configurable nBinsThetaRing{"nBinsThetaRing", 3000, "number of bins in theta ring"}; + Configurable nBinsP{"nBinsP", 400, "number of bins in momentum"}; + 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 nBinsAngularRes{"nBinsAngularRes", 400, "number of bins plots angular 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"}; + Configurable flagIncludeTrackAngularRes{"flagIncludeTrackAngularRes", true, "flag to include or exclude track time resolution"}; + Configurable multiplicityEtaRange{"multiplicityEtaRange", 0.800000012, "eta range to compute the multiplicity"}; + Configurable flagRICHLoadDelphesLUTs{"flagRICHLoadDelphesLUTs", false, "flag to load Delphes LUTs for tracking correction (use recoTrack parameters if false)"}; + Configurable gasRadiatorRindex{"gasRadiatorRindex", 1.0006f, "gas radiator refractive index"}; + Configurable gasRichRadiatorThickness{"gasRichRadiatorThickness", 25.f, "gas radiator thickness (cm)"}; + Configurable bRichRefractiveIndexSector0{"bRichRefractiveIndexSector0", 1.03, "barrel RICH refractive index central(s)"}; // central(s) + Configurable bRichRefractiveIndexSector1{"bRichRefractiveIndexSector1", 1.03, "barrel RICH refractive index central(s)-1 and central(s)+1"}; // central(s)-1 and central(s)+1 + Configurable bRichRefractiveIndexSector2{"bRichRefractiveIndexSector2", 1.03, "barrel RICH refractive index central(s)-2 and central(s)+2"}; // central(s)-2 and central(s)+2 + Configurable bRichRefractiveIndexSector3{"bRichRefractiveIndexSector3", 1.03, "barrel RICH refractive index central(s)-3 and central(s)+3"}; // central(s)-3 and central(s)+3 + Configurable bRichRefractiveIndexSector4{"bRichRefractiveIndexSector4", 1.03, "barrel RICH refractive index central(s)-4 and central(s)+4"}; // central(s)-4 and central(s)+4 + Configurable bRichRefractiveIndexSector5{"bRichRefractiveIndexSector5", 1.03, "barrel RICH refractive index central(s)-5 and central(s)+5"}; // central(s)-5 and central(s)+5 + Configurable bRichRefractiveIndexSector6{"bRichRefractiveIndexSector6", 1.03, "barrel RICH refractive index central(s)-6 and central(s)+6"}; // central(s)-6 and central(s)+6 + Configurable bRichRefractiveIndexSector7{"bRichRefractiveIndexSector7", 1.03, "barrel RICH refractive index central(s)-7 and central(s)+7"}; // central(s)-7 and central(s)+7 + Configurable bRichRefractiveIndexSector8{"bRichRefractiveIndexSector8", 1.03, "barrel RICH refractive index central(s)-8 and central(s)+8"}; // central(s)-8 and central(s)+8 + Configurable bRichRefractiveIndexSector9{"bRichRefractiveIndexSector9", 1.03, "barrel RICH refractive index central(s)-9 and central(s)+9"}; // central(s)-9 and central(s)+9 + Configurable bRichRefractiveIndexSector10{"bRichRefractiveIndexSector10", 1.03, "barrel RICH refractive index central(s)-10 and central(s)+10"}; // central(s)-10 and central(s)+10 + Configurable bRichRefractiveIndexSector11{"bRichRefractiveIndexSector11", 1.03, "barrel RICH refractive index central(s)-11 and central(s)+11"}; // central(s)-11 and central(s)+11 + Configurable bRichRefractiveIndexSector12{"bRichRefractiveIndexSector12", 1.03, "barrel RICH refractive index central(s)-12 and central(s)+12"}; // central(s)-12 and central(s)+12 + Configurable bRichRefractiveIndexSector13{"bRichRefractiveIndexSector13", 1.03, "barrel RICH refractive index central(s)-13 and central(s)+13"}; // central(s)-13 and central(s)+13 + Configurable bRichRefractiveIndexSector14{"bRichRefractiveIndexSector14", 1.03, "barrel RICH refractive index central(s)-14 and central(s)+14"}; // central(s)-14 and central(s)+14 + Configurable bRichRefractiveIndexSector15{"bRichRefractiveIndexSector15", 1.03, "barrel RICH refractive index central(s)-15 and central(s)+15"}; // central(s)-15 and central(s)+15 + Configurable bRichRefractiveIndexSector16{"bRichRefractiveIndexSector16", 1.03, "barrel RICH refractive index central(s)-16 and central(s)+16"}; // central(s)-16 and central(s)+16 + Configurable bRichRefractiveIndexSector17{"bRichRefractiveIndexSector17", 1.03, "barrel RICH refractive index central(s)-17 and central(s)+17"}; // central(s)-17 and central(s)+17 + Configurable bRichRefractiveIndexSector18{"bRichRefractiveIndexSector18", 1.03, "barrel RICH refractive index central(s)-18 and central(s)+18"}; // central(s)-18 and central(s)+18 + Configurable bRichRefractiveIndexSector19{"bRichRefractiveIndexSector19", 1.03, "barrel RICH refractive index central(s)-19 and central(s)+19"}; // central(s)-19 and central(s)+19 + Configurable bRichRefractiveIndexSector20{"bRichRefractiveIndexSector20", 1.03, "barrel RICH refractive index central(s)-20 and central(s)+20"}; // central(s)-20 and central(s)+20 + Configurable bRICHPixelSize{"bRICHPixelSize", 0.1, "barrel RICH pixel size (cm)"}; + Configurable bRichGapRefractiveIndex{"bRichGapRefractiveIndex", 1.000283, "barrel RICH gap refractive index"}; + + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + // Track smearer (here used to get relative pt and eta uncertainties) + o2::delphes::DelphesO2TrackSmearer mSmearer; + + // needed: random number generator for smearing + TRandom3 pRandomNumberGenerator; + + // for handling basic QA histograms if requested + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + /// Flag unphysical and unavailable values (must be negative) + static constexpr float kErrorValue = -1000; + + // Variables projective/hybrid layout + std::vector detCenters; + std::vector radCenters; + std::vector angleCenters; + std::vector thetaMin; + std::vector thetaMax; + std::vector bRichRefractiveIndexSector; + std::vector aerogelRindex; + std::vector photodetrctorLength; + std::vector gapThickness; + + // Update projective geometry + void updateProjectiveParameters() + { + const int numberOfSectorsInZ = bRichNumberOfSectors; + detCenters.resize(numberOfSectorsInZ); + radCenters.resize(numberOfSectorsInZ); + angleCenters.resize(numberOfSectorsInZ); + thetaMin.resize(numberOfSectorsInZ); + thetaMax.resize(numberOfSectorsInZ); + aerogelRindex.resize(numberOfSectorsInZ); + photodetrctorLength.resize(numberOfSectorsInZ); + gapThickness.resize(numberOfSectorsInZ); + float squareSizeBarrelCylinder = 2.0 * bRichPhotodetectorCentralModuleHalfLength; + float squareSizeZ = bRichPhotodetectorOtherModuleLength; + float rMin = bRichRadiatorInnerRadius; + float rMax = bRichPhotodetectorOuterRadius; + std::vector thetaBi; + std::vector r0Tilt; + std::vector z0Tilt; + std::vector tRPlusG; + std::vector lAerogelZ; + std::vector lDetectorZ; + thetaBi.resize(numberOfSectorsInZ); + r0Tilt.resize(numberOfSectorsInZ); + z0Tilt.resize(numberOfSectorsInZ); + tRPlusG.resize(numberOfSectorsInZ); + lAerogelZ.resize(numberOfSectorsInZ); + lDetectorZ.resize(numberOfSectorsInZ); + + // Odd number of sectors + static constexpr int kTwo = 2; + if (numberOfSectorsInZ % kTwo != 0) { + int iCentralMirror = static_cast((numberOfSectorsInZ) / 2.0); + float mVal = std::tan(0.0); + thetaBi[iCentralMirror] = std::atan(mVal); + r0Tilt[iCentralMirror] = rMax; + z0Tilt[iCentralMirror] = r0Tilt[iCentralMirror] * std::tan(thetaBi[iCentralMirror]); + lDetectorZ[iCentralMirror] = squareSizeBarrelCylinder; + lAerogelZ[iCentralMirror] = std::sqrt(1.0 + mVal * mVal) * rMin * squareSizeBarrelCylinder / (std::sqrt(1.0 + mVal * mVal) * rMax - mVal * squareSizeBarrelCylinder); + tRPlusG[iCentralMirror] = rMax - rMin; + float t = std::tan(std::atan(mVal) + std::atan(squareSizeBarrelCylinder / (2.0 * rMax * std::sqrt(1.0 + mVal * mVal) - squareSizeBarrelCylinder * mVal))); + thetaMax[iCentralMirror] = o2::constants::math::PIHalf - std::atan(t); + thetaMin[iCentralMirror] = o2::constants::math::PIHalf + std::atan(t); + bRichPhotodetectorCentralModuleHalfLength.value = rMin * t; + aerogelRindex[iCentralMirror] = bRichRefractiveIndexSector[0]; + for (int i = iCentralMirror + 1; i < numberOfSectorsInZ; i++) { + float parA = t; + float parB = 2.0 * rMax / squareSizeZ; + mVal = (std::sqrt(parA * parA * parB * parB + parB * parB - 1.0) + parA * parB * parB) / (parB * parB - 1.0); + thetaMin[i] = o2::constants::math::PIHalf - std::atan(t); + thetaMax[2 * iCentralMirror - i] = o2::constants::math::PIHalf + std::atan(t); + t = std::tan(std::atan(mVal) + std::atan(squareSizeZ / (2.0 * rMax * std::sqrt(1.0 + mVal * mVal) - squareSizeZ * mVal))); + thetaMax[i] = o2::constants::math::PIHalf - std::atan(t); + thetaMin[2 * iCentralMirror - i] = o2::constants::math::PIHalf + std::atan(t); + // Forward sectors + thetaBi[i] = std::atan(mVal); + r0Tilt[i] = rMax - squareSizeZ / 2.0 * std::sin(std::atan(mVal)); + z0Tilt[i] = r0Tilt[i] * std::tan(thetaBi[i]); + lDetectorZ[i] = squareSizeZ; + lAerogelZ[i] = std::sqrt(1.0 + mVal * mVal) * rMin * squareSizeZ / (std::sqrt(1.0 + mVal * mVal) * rMax - mVal * squareSizeZ); + tRPlusG[i] = std::sqrt(1.0 + mVal * mVal) * (rMax - rMin) - mVal / 2.0 * (squareSizeZ + lAerogelZ[i]); + aerogelRindex[i] = bRichRefractiveIndexSector[i - iCentralMirror]; + // Backword sectors + thetaBi[2 * iCentralMirror - i] = -std::atan(mVal); + r0Tilt[2 * iCentralMirror - i] = rMax - squareSizeZ / 2.0 * std::sin(std::atan(mVal)); + z0Tilt[2 * iCentralMirror - i] = -r0Tilt[i] * std::tan(thetaBi[i]); + lDetectorZ[2 * iCentralMirror - i] = squareSizeZ; + lAerogelZ[2 * iCentralMirror - i] = std::sqrt(1.0 + mVal * mVal) * rMin * squareSizeZ / (std::sqrt(1.0 + mVal * mVal) * rMax - mVal * squareSizeZ); + tRPlusG[2 * iCentralMirror - i] = std::sqrt(1.0 + mVal * mVal) * (rMax - rMin) - mVal / 2.0 * (squareSizeZ + lAerogelZ[i]); + aerogelRindex[2 * iCentralMirror - i] = bRichRefractiveIndexSector[i - iCentralMirror]; + bRichPhotodetectorCentralModuleHalfLength.value = rMin * t; // <-- At the end of the loop this will be the maximum z + } + } else { // Even number of sectors + float twoHalfGap = 1.0; + int iCentralMirror = static_cast((numberOfSectorsInZ) / 2.0); + float mVal = std::tan(0.0); + float t = std::tan(std::atan(mVal) + std::atan(twoHalfGap / (2.0 * rMax * std::sqrt(1.0 + mVal * mVal) - twoHalfGap * mVal))); + bRichPhotodetectorCentralModuleHalfLength.value = rMin * t; + for (int i = iCentralMirror; i < numberOfSectorsInZ; i++) { + float parA = t; + float parB = 2.0 * rMax / squareSizeZ; + mVal = (std::sqrt(parA * parA * parB * parB + parB * parB - 1.0) + parA * parB * parB) / (parB * parB - 1.0); + thetaMin[i] = o2::constants::math::PIHalf - std::atan(t); + thetaMax[2 * iCentralMirror - i - 1] = o2::constants::math::PIHalf + std::atan(t); + t = std::tan(std::atan(mVal) + std::atan(squareSizeZ / (2.0 * rMax * std::sqrt(1.0 + mVal * mVal) - squareSizeZ * mVal))); + thetaMax[i] = o2::constants::math::PIHalf - std::atan(t); + thetaMin[2 * iCentralMirror - i - 1] = o2::constants::math::PIHalf + std::atan(t); + // Forward sectors + thetaBi[i] = std::atan(mVal); + r0Tilt[i] = rMax - squareSizeZ / 2.0 * std::sin(std::atan(mVal)); + z0Tilt[i] = r0Tilt[i] * std::tan(thetaBi[i]); + lDetectorZ[i] = squareSizeZ; + lAerogelZ[i] = std::sqrt(1.0 + mVal * mVal) * rMin * squareSizeZ / (std::sqrt(1.0 + mVal * mVal) * rMax - mVal * squareSizeZ); + tRPlusG[i] = std::sqrt(1.0 + mVal * mVal) * (rMax - rMin) - mVal / 2.0 * (squareSizeZ + lAerogelZ[i]); + aerogelRindex[i] = bRichRefractiveIndexSector[i - iCentralMirror]; + // Backword sectors + thetaBi[2 * iCentralMirror - i - 1] = -std::atan(mVal); + r0Tilt[2 * iCentralMirror - i - 1] = rMax - squareSizeZ / 2.0 * std::sin(std::atan(mVal)); + z0Tilt[2 * iCentralMirror - i - 1] = -r0Tilt[i] * std::tan(thetaBi[i]); + lDetectorZ[2 * iCentralMirror - i - 1] = squareSizeZ; + lAerogelZ[2 * iCentralMirror - i - 1] = std::sqrt(1.0 + mVal * mVal) * rMin * squareSizeZ / (std::sqrt(1.0 + mVal * mVal) * rMax - mVal * squareSizeZ); + tRPlusG[2 * iCentralMirror - i - 1] = std::sqrt(1.0 + mVal * mVal) * (rMax - rMin) - mVal / 2.0 * (squareSizeZ + lAerogelZ[i]); + aerogelRindex[2 * iCentralMirror - i - 1] = bRichRefractiveIndexSector[i - iCentralMirror]; + bRichPhotodetectorCentralModuleHalfLength.value = rMin * t; // <-- At the end of the loop this will be the maximum z + } + } + // Coordinate radiali layer considerati + std::vector r0Detector; + std::vector r0Aerogel; + r0Detector.resize(numberOfSectorsInZ); + r0Aerogel.resize(numberOfSectorsInZ); + for (int i = 0; i < numberOfSectorsInZ; i++) { + r0Detector[i] = r0Tilt[i]; // + (detector_thickness / 2.0) * std::cos(thetaBi[i]) NEGLIGIBLE + detCenters[i].SetXYZ(r0Detector[i], 0, r0Detector[i] * std::tan(thetaBi[i])); + r0Aerogel[i] = r0Tilt[i] - (tRPlusG[i] - bRichRadiatorThickness / 2.0) * std::cos(thetaBi[i]); + radCenters[i].SetXYZ(r0Aerogel[i], 0, r0Aerogel[i] * std::tan(thetaBi[i])); + angleCenters[i] = thetaBi[i]; + photodetrctorLength[i] = lDetectorZ[i]; + gapThickness[i] = (detCenters[i] - radCenters[i]).Mag() - bRichRadiatorThickness / 2.0; + } + // DEBUG + // std::cout << std::endl << std::endl; + // for (int i = 0; i < numberOfSectorsInZ; i++) { + // std::cout << "Sector " << i << ": Gap = " << gapThickness[i] << " cm, Index aerogel = " << aerogelRindex[i] << ", Gap thickness = " << gapThickness[i] << " cm" << std::endl; + // } + // std::cout << std::endl << std::endl; + } + + void init(o2::framework::InitContext& initContext) + { + pRandomNumberGenerator.SetSeed(0); // fully randomize + + if (magneticField.value < o2::constants::math::Epsilon) { + LOG(info) << "Getting the magnetic field from the on-the-fly tracker task"; + if (!getTaskOptionValue(initContext, "on-the-fly-tracker", magneticField, false)) { + LOG(fatal) << "Could not get Bz from on-the-fly-tracker task"; + } + LOG(info) << "Bz = " << magneticField.value << " T"; + } + + // Load LUT for pt and eta smearing + if (flagIncludeTrackAngularRes && flagRICHLoadDelphesLUTs) { + mSmearer.setCcdbManager(ccdb.operator->()); + auto loadLUT = [&](int pdg, const std::string& cfgNameToInherit) { + std::string lut = "none"; + if (!getTaskOptionValue(initContext, "on-the-fly-tracker", cfgNameToInherit, lut, false)) { + LOG(fatal) << "Could not get " << cfgNameToInherit << " from on-the-fly-tracker task"; + } + bool success = mSmearer.loadTable(pdg, lut.c_str()); + if (!success && !lut.empty()) { + LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << lut; + } + }; + loadLUT(11, "lutEl"); + loadLUT(13, "lutMu"); + loadLUT(211, "lutPi"); + loadLUT(321, "lutKa"); + loadLUT(2212, "lutPr"); + loadLUT(1000010020, "lutDe"); + loadLUT(1000010030, "lutTr"); + loadLUT(1000020030, "lutHe3"); + loadLUT(1000020040, "lutAl"); + } + + if (doQAplots) { + const AxisSpec axisMomentum{static_cast(nBinsP), 0.0f, +20.0f, "#it{p} (GeV/#it{c})"}; + const AxisSpec axisAngle{static_cast(nBinsThetaRing), 0.0f, +0.30f, "Measured Cherenkov angle (rad)"}; + const AxisSpec axisEta{static_cast(nBinsEta), -2.0f, +2.0f, "#eta"}; + const AxisSpec axisSector{static_cast(bRichNumberOfSectors), -0.5f, static_cast(bRichNumberOfSectors) - 0.5f, "Sector ID number"}; + const AxisSpec axisRingAngularResolution{static_cast(nBinsAngularRes), 0.0f, +5.0f, "Ring angular resolution - rec. only (mrad)"}; + histos.add("h2dAngleVsMomentumBarrelRICH", "h2dAngleVsMomentumBarrelRICH", kTH2F, {axisMomentum, axisAngle}); + histos.add("h2dAngleVsEtaBarrelRICH", "h2dAngleVsEtaBarrelRICH", kTH2F, {axisEta, axisAngle}); + histos.add("h2dAngularResolutionVsMomentumBarrelRICH", "h2dAngularResolutionVsMomentumBarrelRICH", kTH2F, {axisMomentum, axisRingAngularResolution}); + histos.add("h2dAngularResolutionVsEtaBarrelRICH", "h2dAngularResolutionVsEtaBarrelRICH", kTH2F, {axisEta, axisRingAngularResolution}); + histos.add("hSectorID", "hSectorID", kTH1F, {axisSector}); + + const int kNspec = 9; // electron, muon, pion, kaon, proton, deuteron, triton, helium3, alpha + std::string particleNames1[kNspec] = {"#it{e}", "#it{#mu}", "#it{#pi}", "#it{K}", "#it{p}", "#it{d}", "#it{t}", "^{3}He", "#it{#alpha}"}; + std::string particleNames2[kNspec] = {"Elec", "Muon", "Pion", "Kaon", "Prot", "Deut", "Trit", "He3", "Al"}; + for (int iTrue = 0; iTrue < kNspec; iTrue++) { + std::string nameTitleBarrelTrackRes = "h2dBarrelAngularResTrack" + particleNames2[iTrue] + "VsP"; + std::string nameTitleBarrelTotalRes = "h2dBarrelAngularResTotal" + particleNames2[iTrue] + "VsP"; + const AxisSpec axisTrackAngularRes{static_cast(nBinsAngularRes), 0.0f, +5.0f, "Track angular resolution - " + particleNames1[iTrue] + " (mrad)"}; + const AxisSpec axisTotalAngularRes{static_cast(nBinsAngularRes), 0.0f, +5.0f, "Total angular resolution - " + particleNames1[iTrue] + " (mrad)"}; + histos.add(nameTitleBarrelTrackRes.c_str(), nameTitleBarrelTrackRes.c_str(), kTH2F, {axisMomentum, axisTrackAngularRes}); + histos.add(nameTitleBarrelTotalRes.c_str(), nameTitleBarrelTotalRes.c_str(), kTH2F, {axisMomentum, axisTotalAngularRes}); + } + for (int iTrue = 0; iTrue < kNspec; iTrue++) { + for (int iHyp = 0; iHyp < kNspec; iHyp++) { + std::string nameTitle = "h2dBarrelNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; + if (iTrue == iHyp) { + const AxisSpec axisNsigmaCorrect{static_cast(nBinsNsigmaCorrectSpecies), -10.0f, +10.0f, "N#sigma - True " + particleNames1[iTrue] + " vs " + particleNames1[iHyp] + " hypothesis"}; + histos.add(nameTitle.c_str(), nameTitle.c_str(), kTH2F, {axisMomentum, axisNsigmaCorrect}); + } else { + const AxisSpec axisNsigmaWrong{static_cast(nBinsNsigmaWrongSpecies), -10.0f, +10.0f, "N#sigma - True " + particleNames1[iTrue] + " vs " + particleNames1[iHyp] + " hypothesis"}; + histos.add(nameTitle.c_str(), nameTitle.c_str(), kTH2F, {axisMomentum, axisNsigmaWrong}); + } + } + } + } + // Load all sector refractive indices + /*bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector0AndNMinus1); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector1AndNMinus2); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector2AndNMinus3); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector3AndNMinus4); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector4AndNMinus5); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector5AndNMinus6); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector6AndNMinus7); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector7AndNMinus8); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector8AndNMinus9); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector9AndNMinus10); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector10AndNMinus11); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector11AndNMinus12); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector12AndNMinus13); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector13AndNMinus14); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector14AndNMinus15); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector15AndNMinus16); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector16AndNMinus17); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector17AndNMinus18); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector18AndNMinus19); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector19AndNMinus20); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector20AndNMinus21);*/ + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector0); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector1); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector2); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector3); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector4); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector5); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector6); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector7); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector8); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector9); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector10); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector11); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector12); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector13); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector14); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector15); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector16); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector17); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector18); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector19); + bRichRefractiveIndexSector.push_back(bRichRefractiveIndexSector20); + + // Update projective parameters + updateProjectiveParameters(); + } + + /// check if particle reaches radiator + /// \param track the input track + /// \param radius the radius of the layer you're calculating the length to + /// \param magneticField the magnetic field to use when propagating + bool checkMagfieldLimit(o2::track::TrackParCov track, const float radius, const float magneticField) + { + o2::math_utils::CircleXYf_t trcCircle; + float sna, csa; + track.getCircleParams(magneticField, trcCircle, sna, csa); + + // distance between circle centers (one circle is at origin -> easy) + float centerDistance = std::hypot(trcCircle.xC, trcCircle.yC); + + // condition of circles touching - if not satisfied returned value if false + if (centerDistance < trcCircle.rC + radius && centerDistance > std::fabs(trcCircle.rC - radius)) { + return true; + } else { + return false; + } + } + + /// returns sector hit by the track (if any), -1 otherwise + /// \param eta the pseudorapidity of the tarck (assuming primary vertex at origin) + int findSector(const float eta) + { + float polar = 2.0 * std::atan(std::exp(-eta)); + for (int jSector = 0; jSector < bRichNumberOfSectors; jSector++) { + if (polar > thetaMax[jSector] && polar < thetaMin[jSector]) { + return jSector; + } + } + return -1; + } + + /// returns radiator radius in cm at considered eta (accounting for sector inclination) + /// \param eta the pseudorapidity of the tarck (assuming primary vertex at origin) + /// \param iSecor the index of the track RICH sector + float radiusRipple(const float eta, const int iSecor) + { + if (iSecor > 0) { + const float polar = 2.0 * std::atan(std::exp(-eta)); + const float rSecRich = radCenters[iSecor].X(); + const float zSecRich = radCenters[iSecor].Z(); + const float rSecRichSquared = rSecRich * rSecRich; + const float zSecRichSquared = zSecRich * zSecRich; + return (rSecRichSquared + zSecRichSquared) / (rSecRich + zSecRich / std::tan(polar)); + } else { + return kErrorValue; + } + } + + /// returns Cherenkov angle in rad (above threshold) or bad flag (below threshold) + /// \param momentum the momentum of the tarck + /// \param mass the mass of the particle + /// \param n the refractive index of the considered sector + /// \param angle the output angle (passed by reference) + /// \return true if particle is above the threshold and enough photons, false otherwise + bool cherenkovAngle(const float momentum, const float mass, const float n, float& angle) + { + if (momentum > mass / std::sqrt(n * n - 1.0)) { // Check if particle is above the threshold + // Calculate angle + angle = std::acos(std::sqrt(momentum * momentum + mass * mass) / (momentum * n)); + + // Mean number of detected photons (SiPM PDE is accountd in multiplicative factor!!!) + const float meanNumberofDetectedPhotons = 230. * std::sin(angle) * std::sin(angle) * bRichRadiatorThickness; + + // Require at least 3 photons on average for real angle reconstruction + static constexpr float kMinPhotons = 3.f; + if (meanNumberofDetectedPhotons > kMinPhotons) { + return true; // Particle is above the threshold and enough photons + } + return false; // Particle is above the threshold, but not enough photons + } + return false; // Particle is below the threshold + } + + bool isOverTrhesholdInGasRadiator(const float momentum, const float mass) + { + if (momentum < mass / std::sqrt(gasRadiatorRindex * gasRadiatorRindex - 1.0)) { // Check if particle is above the threshold + return false; + } + const float angle = std::acos(std::sqrt(momentum * momentum + mass * mass) / (momentum * gasRadiatorRindex)); + const float meanNumberofDetectedPhotons = 230. * std::sin(angle) * std::sin(angle) * gasRichRadiatorThickness; + + // Require at least 3 photons on average for real angle reconstruction + static constexpr float kMinPhotons = 3.f; + if (meanNumberofDetectedPhotons <= kMinPhotons) { + return false; + } + return true; + } + + /// returns linear interpolation + /// \param x the eta we want the resolution for + /// \param x0 the closest smaller available eta + /// \param x1 the closest larger available eta + /// \param y0 the resolution corresponding to x0 + /// \param y1 the resolution corresponding to x1 + float interpolate(double x, double x0, double x1, double y0, double y1) + { + float y = y0 + ((y1 - y0) / (x1 - x0)) * (x - x0); + return y; + } + + /// returns angular resolution for considered track eta + /// \param eta the pseudorapidity of the tarck (assuming primary vertex at origin) + float angularResolution(float eta) + { + // Vectors for sampling (USE ANALYTICAL EXTRAPOLATION FOR BETTER RESULTS) + static constexpr float kEtaSampling[] = {-2.000000, -1.909740, -1.731184, -1.552999, -1.375325, -1.198342, -1.022276, -0.847390, -0.673976, -0.502324, -0.332683, -0.165221, 0.000000, 0.165221, 0.332683, 0.502324, 0.673976, 0.847390, 1.022276, 1.198342, 1.375325, 1.552999, 1.731184, 1.909740, 2.000000}; + static constexpr float kResRingSamplingWithAbsWalls[] = {0.0009165, 0.000977, 0.001098, 0.001198, 0.001301, 0.001370, 0.001465, 0.001492, 0.001498, 0.001480, 0.001406, 0.001315, 0.001241, 0.001325, 0.001424, 0.001474, 0.001480, 0.001487, 0.001484, 0.001404, 0.001273, 0.001197, 0.001062, 0.000965, 0.0009165}; + static constexpr float kResRingSamplingWithoutAbsWalls[] = {0.0009165, 0.000977, 0.001095, 0.001198, 0.001300, 0.001369, 0.001468, 0.001523, 0.001501, 0.001426, 0.001299, 0.001167, 0.001092, 0.001179, 0.001308, 0.001407, 0.001491, 0.001508, 0.001488, 0.001404, 0.001273, 0.001196, 0.001061, 0.000965, 0.0009165}; + static constexpr int kSizeResVector = sizeof(kEtaSampling) / sizeof(kEtaSampling[0]); + // Use binary search to find the lower and upper indices + const int lowerIndex = std::lower_bound(kEtaSampling, kEtaSampling + kSizeResVector, eta) - kEtaSampling - 1; + const int upperIndex = lowerIndex + 1; + if (lowerIndex >= 0 && upperIndex < kSizeResVector) { + // Resolution interpolation + if (bRichFlagAbsorbingWalls) { + float interpolatedResRing = interpolate(eta, kEtaSampling[lowerIndex], kEtaSampling[upperIndex], kResRingSamplingWithAbsWalls[lowerIndex], kResRingSamplingWithAbsWalls[upperIndex]); + // std::cout << "Interpolated y value: " << interpolatedY << std::endl; + return interpolatedResRing; + } else { + float interpolatedResRing = interpolate(eta, kEtaSampling[lowerIndex], kEtaSampling[upperIndex], kResRingSamplingWithoutAbsWalls[lowerIndex], kResRingSamplingWithoutAbsWalls[upperIndex]); + // std::cout << "Interpolated y value: " << interpolatedY << std::endl; + return interpolatedResRing; + } + } else { + // std::cout << "Unable to interpolate. Target x value is outside the range of available data." << std::endl; + return kErrorValue; + } + } + + /// To account border effects in bRICH + /// Approximation for analytic calculation: track along projective sector normal (reasonable) + /// \param eta the pseudorapidity of the tarck (assuming primary vertex at origin) + /// \param tileZlength the Z-length of the photodetector plane of the considered sector + /// \param radius the nominal radius of the Cherenkov ring + float fractionPhotonsProjectiveRICH(float eta, float tileZlength, float radius) + { + const float polar = 2.0 * std::atan(std::exp(-eta)); + int iSecor = 0; + bool flagSector = false; + for (int jSector = 0; jSector < bRichNumberOfSectors; jSector++) { + if (polar > thetaMax[jSector] && polar < thetaMin[jSector]) { + flagSector = true; + iSecor = jSector; + } + } + if (flagSector == false) { + return kErrorValue; // <-- Returning negative value + } + float rSecRich = radCenters[iSecor].X(); + float zSecRich = radCenters[iSecor].Z(); + // float rSecTof = detCenters[iSecor].X(); + // float zSecTof = detCenters[iSecor].Z(); + const float rSecRichSquared = rSecRich * rSecRich; + const float zSecRichSquared = zSecRich * zSecRich; + const float radiusRipple = (rSecRichSquared + zSecRichSquared) / (rSecRich + zSecRich / std::tan(polar)); + const float zRipple = radiusRipple / std::tan(polar); + const float absZ = std::hypot(radiusRipple - rSecRich, zRipple - zSecRich); + float fraction = 1.; + if (tileZlength / 2. - absZ < radius) { + fraction = fraction - (1. / o2::constants::math::PI) * std::acos((tileZlength / 2. - absZ) / radius); + if (tileZlength / 2. + absZ < radius) { + fraction = fraction - (1. / o2::constants::math::PI) * std::acos((tileZlength / 2. + absZ) / radius); + } + } + return fraction; + } + + /// returns refined ring angular resolution + /// \param eta the pseudorapidity of the tarck (assuming primary vertex at origin) + /// \param n the refractive index of the considered sector + /// \param nGas the refractive index of the gas filling the RICH proximity gap + /// \param thicknessRad the radiator thickness in cm + /// \param thicknessGas the proximity gap thickness of the considered sector in cm + /// \param pixelSize the SiPM pixel size in cm + /// \param thetaCherenkov the Cherenkov angle for the considered track + /// \param tileZlength the Z-length of the photodetector plane of the considered sector + float extractRingAngularResolution(const float eta, const float n, const float nGas, const float thicknessRad, const float thicknessGas, const float pixelSize, const float thetaCherenkov, const float tileZlength) + { + // Check if input angle is error value + if (thetaCherenkov <= kErrorValue + 1) + return kErrorValue; + // Parametrization variables (notation from https://doi.org/10.1016/0168-9002(94)90532-0) + const float phiC = 0.; + const float thetaP = 0.; + const float sinThetaCherenkov = std::sin(thetaCherenkov); + const float cosThetaCherenkov = std::cos(thetaCherenkov); + const float xP = std::sin(thetaP); + const float zP = std::cos(thetaP); + const float sinPhi = std::sin(phiC); + const float cosPhi = std::cos(phiC); + // const float ze = thicknessRad / (2. * zP); + const float aZ = zP * cosThetaCherenkov - xP * sinThetaCherenkov * cosPhi; + const float e3z = std::sqrt(aZ * aZ + (nGas / n) * (nGas / n) - 1.); + const float z = thicknessGas; + const float alpha = e3z / aZ; + const float etac = e3z * n * n; + const float k = thicknessRad / (2. * z); + const float m = 1. / (n * n); + const float lambda = (1. + k * alpha * alpha * alpha) / (1. + k * alpha); + // Derivative d(thetaCherenkov)/dx + const float temp1 = etac / z; + const float temp2 = alpha * e3z * cosPhi; + const float temp3 = xP * sinThetaCherenkov * sinPhi * sinPhi; + const float dThetaX = temp1 * (temp2 - temp3); + // Derivative d(thetaCherenkov)/dy + const float temp4 = etac * sinPhi / z; + const float temp5 = cosThetaCherenkov - zP * (1 - m) / aZ; + const float dThetaY = temp4 * temp5; + // Derivative d(thetaCherenkov)/dze + const float temp8 = etac * sinThetaCherenkov; + const float temp9 = z * (1.0 + k * alpha * alpha * alpha * n * n); + const float temp10 = alpha * alpha * (1.0 - xP * xP * sinPhi * sinPhi) + lambda * xP * xP * sinPhi * sinPhi; + const float dThetaZe = temp8 * temp10 / temp9; + // Derivative d(thetaCherenkov)/dn + const float dThetaN = zP / (n * aZ * sinThetaCherenkov); + // RMS wavelength (using Sellmeier formula with measured aerogel parameters) + const float a0 = 0.0616; + const float w0 = 56.5; + const float n0 = 1.0307; + const float wMean = 436.0; // 450.0;//484.9;//426.0; //450;//485;//450; // nm //450 426 493.5 // 426.0 + const float scaling = n / n0; + const float temp11 = a0 * w0 * w0 * wMean; + const float temp12 = std::pow(wMean * wMean - w0 * w0, 1.5); + const float temp13 = std::sqrt(wMean * wMean * (1.0 + a0) - w0 * w0); + const float dNw = temp11 / (temp12 * temp13) * scaling; + const float sigmaW = 115.0; + // RMS x y + const float sigmaThetaX = pixelSize / std::sqrt(12.0); + const float sigmaThetaY = pixelSize / std::sqrt(12.0); + // RMS emission point + const float sigmaThetaZe = thicknessRad / (zP * std::sqrt(12.0)); + // Single photon angular resolution + const float resX = dThetaX * sigmaThetaX; + const float resY = dThetaY * sigmaThetaY; + const float resZe = dThetaZe * sigmaThetaZe; + const float resN = dThetaN * dNw * sigmaW; + const float resXsquared = resX * resX; + const float resYsquared = resY * resY; + const float resZesquared = resZe * resZe; + const float resNsquared = resN * resN; + const float singlePhotonAngularResolution = std::sqrt(resXsquared + resYsquared + resZesquared + resNsquared); + // Fraction of photons in rings (to account loss close to sector boundary in projective geometry) + const float sinThetaCherenkovSquared = sinThetaCherenkov * sinThetaCherenkov; + const float radius = (thicknessRad / 2.0) * std::tan(thetaCherenkov) + thicknessGas * std::tan(std::asin((n / nGas) * sinThetaCherenkov)); + const float n0Photons = 24. * thicknessRad / 2.; // photons for N = 1.03 at saturation ( 24/2 factor per radiator cm ) + const float sinAngle = std::sin(std::acos(1. / 1.03)); + const float sinAngleSquared = sinAngle * sinAngle; + const float multiplicitySpectrumFactor = sinThetaCherenkovSquared / sinAngleSquared; // scale multiplicity w.r.t. N = 1.03 at saturation + // Considering average resolution (integrated over the sector) + // float nPhotons = (tileZlength / 2.0 > radius) ? n0Photons * multiplicitySpectrumFactor * (1.-(2.0*radius)/(o2::constants::math::PI*tileZlength)) : n0Photons * multiplicitySpectrumFactor * (1.-(2.0*radius)/(o2::constants::math::PI*tileZlength) - (2.0/(tileZlength*o2::constants::math::PI))*(-(tileZlength/(2.0))*std::acos(tileZlength/(2.0*radius)) + radius*std::sqrt(1.-std::pow(tileZlength/(2.0*radius),2.0)))); + // Considering "exact" resolution (eta by eta) + const float nPhotons = n0Photons * multiplicitySpectrumFactor * fractionPhotonsProjectiveRICH(eta, tileZlength, radius); + if (nPhotons <= kErrorValue + 1) + return kErrorValue; + // Ring angular resolution + const float ringAngularResolution = singlePhotonAngularResolution / std::sqrt(nPhotons); + return ringAngularResolution; + } + + /// returns track angular resolution + /// \param pt the transverse momentum of the tarck + /// \param eta the pseudorapidity of the tarck + /// \param trackPtResolution the absolute resolution on pt + /// \param trackPtResolution the absolute resolution on eta + /// \param mass the mass of the particle + /// \param refractiveIndex the refractive index of the radiator + double calculateTrackAngularResolutionAdvanced(const float pt, const float eta, const float trackPtResolution, const float trackEtaResolution, const float mass, const float refractiveIndex) + { + // Compute tracking contribution to timing using the error propagation formula + // Uses light speed in m/ps, magnetic field in T (*0.1 for conversion kGauss -> T) + const double a0 = mass * mass; + const double a1 = refractiveIndex; + const double a1Squared = a1 * a1; + const float ptCoshEta = pt * std::cosh(eta); + const float ptCoshEtaSquared = ptCoshEta * ptCoshEta; + const double dThetaOndPt = a0 / (pt * std::sqrt(a0 + ptCoshEtaSquared) * std::sqrt(ptCoshEtaSquared * (a1Squared - 1.0) - a0)); + const double dThetaOndEta = (a0 * std::tanh(eta)) / (std::sqrt(a0 + ptCoshEtaSquared) * std::sqrt(ptCoshEtaSquared * (a1Squared - 1.0) - a0)); + const double trackAngularResolution = std::hypot(std::fabs(dThetaOndPt) * trackPtResolution, std::fabs(dThetaOndEta) * trackEtaResolution); + return trackAngularResolution; + } + + void process(soa::Join::iterator const& collision, + soa::Join const& tracks, + aod::McParticles const&, + aod::McCollisions const&) + { + const o2::dataformats::VertexBase pvVtx({collision.posX(), collision.posY(), collision.posZ()}, + {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}); + + std::array mcPvCov = {0.}; + o2::dataformats::VertexBase mcPvVtx({0.0f, 0.0f, 0.0f}, mcPvCov); + if (collision.has_mcCollision()) { + auto mcCollision = collision.mcCollision(); + mcPvVtx.setX(mcCollision.posX()); + mcPvVtx.setY(mcCollision.posY()); + mcPvVtx.setZ(mcCollision.posZ()); + } // else remains untreated for now + + // First we compute the number of charged particles in the event + float dNdEta = 0.f; + if (flagRICHLoadDelphesLUTs) { + for (const auto& track : tracks) { + if (!track.has_mcParticle()) + continue; + auto mcParticle = track.mcParticle(); + if (std::abs(mcParticle.eta()) > multiplicityEtaRange) { + continue; + } + if (mcParticle.has_daughters()) { + continue; + } + const auto& pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); + if (!pdgInfo) { + // LOG(warning) << "PDG code " << mcParticle.pdgCode() << " not found in the database"; + continue; + } + if (pdgInfo->Charge() == 0) { + continue; + } + dNdEta += 1.f; + } + } + + for (const auto& track : tracks) { + + auto fillDummyValues = [&](bool gasRich = false) { + upgradeRich(kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue); + upgradeRichSignal(false, false, false, false, false, false, false, false, false, false, gasRich); + }; + + // first step: find precise arrival time (if any) + // --- convert track into perfect track + if (!track.has_mcParticle()) { // should always be OK but check please + fillDummyValues(); + continue; + } + + const auto& mcParticle = track.mcParticle(); + o2::track::TrackParCov o2track = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdg); + + // float xPv = kErrorValue; + if (o2track.propagateToDCA(mcPvVtx, magneticField)) { + // xPv = o2track.getX(); + } + + // get particle to calculate Cherenkov angle and resolution + auto pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); + if (pdgInfo == nullptr) { + fillDummyValues(); + continue; + } + + // find track bRICH sector + const int iSecor = findSector(o2track.getEta()); + if (iSecor < 0) { + fillDummyValues(); + continue; + } + + const bool expectedAngleBarrelGasRichOk = isOverTrhesholdInGasRadiator(o2track.getP(), pdgInfo->Mass()); + float expectedAngleBarrelRich = kErrorValue; + const bool expectedAngleBarrelRichOk = cherenkovAngle(o2track.getP(), pdgInfo->Mass(), aerogelRindex[iSecor], expectedAngleBarrelRich); + if (!expectedAngleBarrelRichOk) { + fillDummyValues(expectedAngleBarrelGasRichOk); + continue; // Particle is below the threshold or not enough photons + } + // float barrelRICHAngularResolution = angularResolution(o2track.getEta()); + const float barrelRICHAngularResolution = extractRingAngularResolution(o2track.getEta(), aerogelRindex[iSecor], bRichGapRefractiveIndex, bRichRadiatorThickness, gapThickness[iSecor], bRICHPixelSize, expectedAngleBarrelRich, photodetrctorLength[iSecor]); + const float projectiveRadiatorRadius = radiusRipple(o2track.getEta(), iSecor); + bool flagReachesRadiator = false; + if (projectiveRadiatorRadius > kErrorValue + 1.) { + flagReachesRadiator = checkMagfieldLimit(o2track, projectiveRadiatorRadius, magneticField); + } + /// DISCLAIMER: Exact extrapolation of angular resolution would require track propagation + /// to the RICH radiator (accounting sector inclination) in terms of (R,z). + /// The extrapolation with Eta is correct only if the primary vertex is at origin. + /// Discrepancies may be negligible, but would be more rigorous if propagation tool is available + + // Smear with expected resolutions + const float measuredAngleBarrelRich = pRandomNumberGenerator.Gaus(expectedAngleBarrelRich, barrelRICHAngularResolution); + + // Now we calculate the expected Cherenkov angle following certain mass hypotheses + // and the (imperfect!) reconstructed track parametrizations + auto recoTrack = getTrackParCov(track); + if (recoTrack.propagateToDCA(pvVtx, magneticField)) { + // xPv = recoTrack.getX(); + } + + // Straight to Nsigma + static constexpr int kNspecies = 9; + static constexpr int kEl = 0; + static constexpr int kMu = 1; + static constexpr int kPi = 2; + static constexpr int kKa = 3; + static constexpr int kPr = 4; + static constexpr int kDe = 5; + static constexpr int kTr = 6; + static constexpr int kHe3 = 7; + static constexpr int kAl = 8; + float nSigmaBarrelRich[kNspecies] = {kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue, kErrorValue}; + bool signalBarrelRich[kNspecies] = {false, false, false, false, false, false, false, false, false}; + float deltaThetaBarrelRich[kNspecies]; //, nSigmaBarrelRich[kNspecies]; + static constexpr int kParticlePdgs[kNspecies] = {kElectron, + kMuonMinus, + kPiPlus, + kKPlus, + kProton, + o2::constants::physics::kDeuteron, + o2::constants::physics::kTriton, + o2::constants::physics::kHelium3, + o2::constants::physics::kAlpha}; + static constexpr float kParticleMasses[kNspecies] = {o2::track::pid_constants::sMasses[o2::track::PID::Electron], + o2::track::pid_constants::sMasses[o2::track::PID::Muon], + o2::track::pid_constants::sMasses[o2::track::PID::Pion], + o2::track::pid_constants::sMasses[o2::track::PID::Kaon], + o2::track::pid_constants::sMasses[o2::track::PID::Proton], + o2::track::pid_constants::sMasses[o2::track::PID::Deuteron], + o2::track::pid_constants::sMasses[o2::track::PID::Triton], + o2::track::pid_constants::sMasses[o2::track::PID::Helium3], + o2::track::pid_constants::sMasses[o2::track::PID::Alpha]}; + + for (int ii = 0; ii < kNspecies; ii++) { // Loop on the particle hypotheses + + float hypothesisAngleBarrelRich = kErrorValue; + const bool hypothesisAngleBarrelRichOk = cherenkovAngle(recoTrack.getP(), kParticleMasses[ii], aerogelRindex[iSecor], hypothesisAngleBarrelRich); + signalBarrelRich[ii] = hypothesisAngleBarrelRichOk; // Particle is above the threshold and enough photons + + // Evaluate total sigma (layer + tracking resolution) + float barrelTotalAngularReso = barrelRICHAngularResolution; + if (flagIncludeTrackAngularRes) { + const float transverseMomentum = recoTrack.getP() / std::cosh(recoTrack.getEta()); + double ptResolution = transverseMomentum * transverseMomentum * std::sqrt(recoTrack.getSigma1Pt2()); + double etaResolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-recoTrack.getEta())))) * std::sqrt(recoTrack.getSigmaTgl2()); + if (flagRICHLoadDelphesLUTs) { + if (mSmearer.hasTable(kParticlePdgs[ii])) { + ptResolution = mSmearer.getAbsPtRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum); + etaResolution = mSmearer.getAbsEtaRes(kParticlePdgs[ii], dNdEta, recoTrack.getEta(), transverseMomentum); + } + } + // cout << endl << "Pt resolution: " << ptResolution << ", Eta resolution: " << etaResolution << endl << endl; + const float barrelTrackAngularReso = calculateTrackAngularResolutionAdvanced(recoTrack.getP() / std::cosh(recoTrack.getEta()), recoTrack.getEta(), ptResolution, etaResolution, kParticleMasses[ii], aerogelRindex[iSecor]); + barrelTotalAngularReso = std::hypot(barrelRICHAngularResolution, barrelTrackAngularReso); + if (doQAplots && + hypothesisAngleBarrelRich > kErrorValue + 1. && + measuredAngleBarrelRich > kErrorValue + 1. && + barrelRICHAngularResolution > kErrorValue + 1. && + flagReachesRadiator) { + switch (mcParticle.pdgCode()) { + case kParticlePdgs[kEl]: // Electron + case -kParticlePdgs[kEl]: // Positron + if (ii == kEl) { + histos.fill(HIST("h2dBarrelAngularResTrackElecVsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalElecVsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + case kParticlePdgs[kMu]: // Muon + case -kParticlePdgs[kMu]: // AntiMuon + if (ii == kMu) { + histos.fill(HIST("h2dBarrelAngularResTrackMuonVsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalMuonVsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + case kParticlePdgs[kPi]: // Pion + case -kParticlePdgs[kPi]: // AntiPion + if (ii == kPi) { + histos.fill(HIST("h2dBarrelAngularResTrackPionVsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalPionVsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + case kParticlePdgs[kKa]: // Kaon + case -kParticlePdgs[kKa]: // AntiKaon + if (ii == kKa) { + histos.fill(HIST("h2dBarrelAngularResTrackKaonVsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalKaonVsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + case kParticlePdgs[kPr]: // Proton + case -kParticlePdgs[kPr]: // AntiProton + if (ii == kPr) { + histos.fill(HIST("h2dBarrelAngularResTrackProtVsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalProtVsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + case kParticlePdgs[kDe]: // Deuteron + case -kParticlePdgs[kDe]: // AntiDeuteron + if (ii == kDe) { + histos.fill(HIST("h2dBarrelAngularResTrackDeutVsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalDeutVsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + case kParticlePdgs[kTr]: // Triton + case -kParticlePdgs[kTr]: // AntiTriton + if (ii == kTr) { + histos.fill(HIST("h2dBarrelAngularResTrackTritVsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalTritVsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + case kParticlePdgs[kHe3]: // Helium3 + case -kParticlePdgs[kHe3]: // AntiHelium3 + if (ii == kHe3) { + histos.fill(HIST("h2dBarrelAngularResTrackHe3VsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalHe3VsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + case kParticlePdgs[kAl]: // Alpha + case -kParticlePdgs[kAl]: // AntiAlpha + if (ii == kAl) { + histos.fill(HIST("h2dBarrelAngularResTrackAlVsP"), recoTrack.getP(), 1000.0 * barrelTrackAngularReso); + histos.fill(HIST("h2dBarrelAngularResTotalAlVsP"), recoTrack.getP(), 1000.0 * barrelTotalAngularReso); + } + break; + default: + break; + } + } + } + + /// DISCLAIMER: here tracking is accounted only for momentum value, but not for track parameters at impact point on the + /// RICH radiator, since exact resolution would require photon generation and transport to photodetector. + /// Effects are expected to be negligible (a few tenths of a milliradian) but further studies are required ! + if (hypothesisAngleBarrelRich > kErrorValue + 1. && + measuredAngleBarrelRich > kErrorValue + 1. && + barrelRICHAngularResolution > kErrorValue + 1. && + flagReachesRadiator) { + deltaThetaBarrelRich[ii] = hypothesisAngleBarrelRich - measuredAngleBarrelRich; + nSigmaBarrelRich[ii] = deltaThetaBarrelRich[ii] / barrelTotalAngularReso; + } + } + + // Fill histograms + if (doQAplots) { + if (measuredAngleBarrelRich > kErrorValue + 1. && + barrelRICHAngularResolution > kErrorValue + 1. && + flagReachesRadiator) { + histos.fill(HIST("h2dAngleVsMomentumBarrelRICH"), recoTrack.getP(), measuredAngleBarrelRich); + histos.fill(HIST("h2dAngleVsEtaBarrelRICH"), recoTrack.getEta(), measuredAngleBarrelRich); + histos.fill(HIST("h2dAngularResolutionVsMomentumBarrelRICH"), recoTrack.getP(), 1000 * barrelRICHAngularResolution); + histos.fill(HIST("h2dAngularResolutionVsEtaBarrelRICH"), recoTrack.getEta(), 1000 * barrelRICHAngularResolution); + histos.fill(HIST("hSectorID"), iSecor); + + switch (mcParticle.pdgCode()) { + case kParticlePdgs[kEl]: // Electron + case -kParticlePdgs[kEl]: // Positron + histos.fill(HIST("h2dBarrelNsigmaTrueElecVsElecHypothesis"), recoTrack.getP(), nSigmaBarrelRich[0]); + histos.fill(HIST("h2dBarrelNsigmaTrueElecVsMuonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[1]); + histos.fill(HIST("h2dBarrelNsigmaTrueElecVsPionHypothesis"), recoTrack.getP(), nSigmaBarrelRich[2]); + histos.fill(HIST("h2dBarrelNsigmaTrueElecVsKaonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[3]); + histos.fill(HIST("h2dBarrelNsigmaTrueElecVsProtHypothesis"), recoTrack.getP(), nSigmaBarrelRich[4]); + break; + case kParticlePdgs[kMu]: // Muon + case -kParticlePdgs[kMu]: // AntiMuon + histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsElecHypothesis"), recoTrack.getP(), nSigmaBarrelRich[0]); + histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsMuonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[1]); + histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsPionHypothesis"), recoTrack.getP(), nSigmaBarrelRich[2]); + histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsKaonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[3]); + histos.fill(HIST("h2dBarrelNsigmaTrueMuonVsProtHypothesis"), recoTrack.getP(), nSigmaBarrelRich[4]); + break; + case kParticlePdgs[kPi]: // Pion + case -kParticlePdgs[kPi]: // AntiPion + histos.fill(HIST("h2dBarrelNsigmaTruePionVsElecHypothesis"), recoTrack.getP(), nSigmaBarrelRich[0]); + histos.fill(HIST("h2dBarrelNsigmaTruePionVsMuonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[1]); + histos.fill(HIST("h2dBarrelNsigmaTruePionVsPionHypothesis"), recoTrack.getP(), nSigmaBarrelRich[2]); + histos.fill(HIST("h2dBarrelNsigmaTruePionVsKaonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[3]); + histos.fill(HIST("h2dBarrelNsigmaTruePionVsProtHypothesis"), recoTrack.getP(), nSigmaBarrelRich[4]); + break; + case kParticlePdgs[kKa]: // Kaon + case -kParticlePdgs[kKa]: // AntiKaon + histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsElecHypothesis"), recoTrack.getP(), nSigmaBarrelRich[0]); + histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsMuonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[1]); + histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsPionHypothesis"), recoTrack.getP(), nSigmaBarrelRich[2]); + histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsKaonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[3]); + histos.fill(HIST("h2dBarrelNsigmaTrueKaonVsProtHypothesis"), recoTrack.getP(), nSigmaBarrelRich[4]); + break; + case kParticlePdgs[kPr]: // Proton + case -kParticlePdgs[kPr]: // AntiProton + histos.fill(HIST("h2dBarrelNsigmaTrueProtVsElecHypothesis"), recoTrack.getP(), nSigmaBarrelRich[0]); + histos.fill(HIST("h2dBarrelNsigmaTrueProtVsMuonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[1]); + histos.fill(HIST("h2dBarrelNsigmaTrueProtVsPionHypothesis"), recoTrack.getP(), nSigmaBarrelRich[2]); + histos.fill(HIST("h2dBarrelNsigmaTrueProtVsKaonHypothesis"), recoTrack.getP(), nSigmaBarrelRich[3]); + histos.fill(HIST("h2dBarrelNsigmaTrueProtVsProtHypothesis"), recoTrack.getP(), nSigmaBarrelRich[4]); + histos.fill(HIST("h2dBarrelNsigmaTrueProtVsDeutHypothesis"), recoTrack.getP(), nSigmaBarrelRich[5]); + break; + case kParticlePdgs[kDe]: // Deuteron + case -kParticlePdgs[kDe]: // AntiDeuteron + histos.fill(HIST("h2dBarrelNsigmaTrueDeutVsProtHypothesis"), recoTrack.getP(), nSigmaBarrelRich[4]); + histos.fill(HIST("h2dBarrelNsigmaTrueDeutVsDeutHypothesis"), recoTrack.getP(), nSigmaBarrelRich[5]); + histos.fill(HIST("h2dBarrelNsigmaTrueDeutVsTritHypothesis"), recoTrack.getP(), nSigmaBarrelRich[6]); + histos.fill(HIST("h2dBarrelNsigmaTrueDeutVsHe3Hypothesis"), recoTrack.getP(), nSigmaBarrelRich[7]); + histos.fill(HIST("h2dBarrelNsigmaTrueDeutVsAlHypothesis"), recoTrack.getP(), nSigmaBarrelRich[8]); + break; + case kParticlePdgs[kTr]: // Triton + case -kParticlePdgs[kTr]: // AntiTriton + histos.fill(HIST("h2dBarrelNsigmaTrueTritVsProtHypothesis"), recoTrack.getP(), nSigmaBarrelRich[4]); + histos.fill(HIST("h2dBarrelNsigmaTrueTritVsDeutHypothesis"), recoTrack.getP(), nSigmaBarrelRich[5]); + histos.fill(HIST("h2dBarrelNsigmaTrueTritVsTritHypothesis"), recoTrack.getP(), nSigmaBarrelRich[6]); + histos.fill(HIST("h2dBarrelNsigmaTrueTritVsHe3Hypothesis"), recoTrack.getP(), nSigmaBarrelRich[7]); + histos.fill(HIST("h2dBarrelNsigmaTrueTritVsAlHypothesis"), recoTrack.getP(), nSigmaBarrelRich[8]); + break; + case kParticlePdgs[kHe3]: // Helium3 + case -kParticlePdgs[kHe3]: // AntiHelium3 + histos.fill(HIST("h2dBarrelNsigmaTrueHe3VsDeutHypothesis"), recoTrack.getP(), nSigmaBarrelRich[5]); + histos.fill(HIST("h2dBarrelNsigmaTrueHe3VsTritHypothesis"), recoTrack.getP(), nSigmaBarrelRich[6]); + histos.fill(HIST("h2dBarrelNsigmaTrueHe3VsHe3Hypothesis"), recoTrack.getP(), nSigmaBarrelRich[7]); + histos.fill(HIST("h2dBarrelNsigmaTrueHe3VsAlHypothesis"), recoTrack.getP(), nSigmaBarrelRich[8]); + break; + case kParticlePdgs[kAl]: // Alpha + case -kParticlePdgs[kAl]: // AntiAlpha + histos.fill(HIST("h2dBarrelNsigmaTrueAlVsDeutHypothesis"), recoTrack.getP(), nSigmaBarrelRich[5]); + histos.fill(HIST("h2dBarrelNsigmaTrueAlVsTritHypothesis"), recoTrack.getP(), nSigmaBarrelRich[6]); + histos.fill(HIST("h2dBarrelNsigmaTrueAlVsHe3Hypothesis"), recoTrack.getP(), nSigmaBarrelRich[7]); + histos.fill(HIST("h2dBarrelNsigmaTrueAlVsAlHypothesis"), recoTrack.getP(), nSigmaBarrelRich[8]); + break; + default: + break; + } + } + } + + // Sigmas have been fully calculated. Please populate the NSigma helper table (once per track) + upgradeRich(nSigmaBarrelRich[0], nSigmaBarrelRich[1], nSigmaBarrelRich[2], nSigmaBarrelRich[3], nSigmaBarrelRich[4], nSigmaBarrelRich[5], nSigmaBarrelRich[6], nSigmaBarrelRich[7], nSigmaBarrelRich[8]); + upgradeRichSignal(expectedAngleBarrelRichOk, signalBarrelRich[0], signalBarrelRich[1], signalBarrelRich[2], signalBarrelRich[3], signalBarrelRich[4], signalBarrelRich[5], signalBarrelRich[6], signalBarrelRich[7], signalBarrelRich[8], expectedAngleBarrelGasRichOk); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/TableProducer/OTF/onTheFlyTOFPID.cxx b/ALICE3/TableProducer/OTF/onTheFlyTOFPID.cxx deleted file mode 100644 index 39ace42c926..00000000000 --- a/ALICE3/TableProducer/OTF/onTheFlyTOFPID.cxx +++ /dev/null @@ -1,607 +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 add a table of track parameters propagated to the primary vertex -// - -#include - -#include - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/trackUtilities.h" -#include "ReconstructionDataFormats/DCA.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "CommonUtils/NameConf.h" -#include "CCDB/CcdbApi.h" -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsCalibration/MeanVertexObject.h" -#include "CommonConstants/GeomConstants.h" -#include "CommonConstants/PhysicsConstants.h" -#include "TRandom3.h" -#include "ALICE3/DataModel/OTFTOF.h" -#include "DetectorsVertexing/HelixHelper.h" -#include "TableHelper.h" -#include "ALICE3/Core/DelphesO2TrackSmearer.h" - -/// \file onTheFlyTOFPID.cxx -/// -/// \brief This task goes straight from a combination of track table and mcParticles -/// and a custom TOF configuration to a table of TOF NSigmas for the particles -/// being analysed. It currently contemplates 5 particle types: -/// electrons, pions, kaons, protons and muons -/// -/// More particles could be added but would have to be added to the LUT -/// being used in the onTheFly tracker task. -/// -/// \author David Dobrigkeit Chinellato, UNICAMP, Nicola Nicassio, University and INFN Bari - -using namespace o2; -using namespace o2::framework; - -struct OnTheFlyTOFPID { - Produces upgradeTof; - - // necessary for particle charges - Service pdg; - - // these are the settings governing the TOF layers to be used - // note that there are two layers foreseen for now: inner and outer TOF - // more could be added (especially a disk TOF at a certain z?) - // in the evolution of this effort - Configurable dBz{"dBz", 20, "magnetic field (kilogauss)"}; - Configurable innerTOFRadius{"innerTOFRadius", 20, "barrel inner TOF radius (cm)"}; - Configurable outerTOFRadius{"outerTOFRadius", 80, "barrel outer TOF radius (cm)"}; - Configurable innerTOFTimeReso{"innerTOFTimeReso", 20, "barrel inner TOF time error (ps)"}; - Configurable outerTOFTimeReso{"outerTOFTimeReso", 20, "barrel outer TOF time error (ps)"}; - Configurable nStepsLIntegrator{"nStepsLIntegrator", 200, "number of steps in length integrator"}; - Configurable doQAplots{"doQAplots", true, "do basic velocity plot qa"}; - Configurable nBinsBeta{"nBinsBeta", 2200, "number of bins in beta"}; - Configurable nBinsP{"nBinsP", 80, "number of bins in momentum"}; - Configurable nBinsTrackLengthInner{"nBinsTrackLengthInner", 300, "number of bins in track length"}; - Configurable nBinsTrackLengthOuter{"nBinsTrackLengthOuter", 300, "number of bins in track length"}; - 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 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"}; - Configurable flagIncludeTrackTimeRes{"flagIncludeTrackTimeRes", true, "flag to include or exclude track time resolution"}; - Configurable multiplicityEtaRange{"multiplicityEtaRange", 0.800000012, "eta range to compute the multiplicity"}; - Configurable flagTOFLoadDelphesLUTs{"flagTOFLoadDelphesLUTs", false, "flag to load Delphes LUTs for tracking correction (use recoTrack parameters if false)"}; - - Configurable lutEl{"lutEl", "lutCovm.el.dat", "LUT for electrons"}; - Configurable lutMu{"lutMu", "lutCovm.mu.dat", "LUT for muons"}; - Configurable lutPi{"lutPi", "lutCovm.pi.dat", "LUT for pions"}; - Configurable lutKa{"lutKa", "lutCovm.ka.dat", "LUT for kaons"}; - Configurable lutPr{"lutPr", "lutCovm.pr.dat", "LUT for protons"}; - - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - - // Track smearer (here used to get absolute pt and eta uncertainties if flagTOFLoadDelphesLUTs is true) - o2::delphes::DelphesO2TrackSmearer mSmearer; - - // needed: random number generator for smearing - TRandom3 pRandomNumberGenerator; - - // for handling basic QA histograms if requested - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(o2::framework::InitContext&) - { - pRandomNumberGenerator.SetSeed(0); // fully randomize - - // Load LUT for pt and eta smearing - if (flagIncludeTrackTimeRes && flagTOFLoadDelphesLUTs) { - std::map mapPdgLut; - const char* lutElChar = lutEl->c_str(); - const char* lutMuChar = lutMu->c_str(); - const char* lutPiChar = lutPi->c_str(); - const char* lutKaChar = lutKa->c_str(); - const char* lutPrChar = lutPr->c_str(); - - LOGF(info, "Will load electron lut file ..: %s for TOF PID", lutElChar); - LOGF(info, "Will load muon lut file ......: %s for TOF PID", lutMuChar); - LOGF(info, "Will load pion lut file ......: %s for TOF PID", lutPiChar); - LOGF(info, "Will load kaon lut file ......: %s for TOF PID", lutKaChar); - LOGF(info, "Will load proton lut file ....: %s for TOF PID", lutPrChar); - - mapPdgLut.insert(std::make_pair(11, lutElChar)); - mapPdgLut.insert(std::make_pair(13, lutMuChar)); - mapPdgLut.insert(std::make_pair(211, lutPiChar)); - mapPdgLut.insert(std::make_pair(321, lutKaChar)); - mapPdgLut.insert(std::make_pair(2212, lutPrChar)); - - for (auto e : mapPdgLut) { - if (!mSmearer.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; - } - } - } - - if (doQAplots) { - const AxisSpec axisMomentum{static_cast(nBinsP), 0.0f, +4.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)"}; - const AxisSpec axisTrackLengthOuter{static_cast(nBinsTrackLengthOuter), 0.0f, 300.0f, "Track length (cm)"}; - const AxisSpec axisTrackDeltaLength{static_cast(nBinsTrackDeltaLength), 0.0f, 30.0f, "Delta Track length (cm)"}; - histos.add("h2dVelocityVsMomentumInner", "h2dVelocityVsMomentumInner", kTH2F, {axisMomentum, axisVelocity}); - histos.add("h2dVelocityVsMomentumOuter", "h2dVelocityVsMomentumOuter", kTH2F, {axisMomentum, axisVelocity}); - histos.add("h2dTrackLengthInnerVsPt", "h2dTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner}); - histos.add("h2dTrackLengthOuterVsPt", "h2dTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter}); - - histos.add("h2dTrackLengthInnerRecoVsPt", "h2dTrackLengthInnerRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner}); - histos.add("h2dTrackLengthOuterRecoVsPt", "h2dTrackLengthOuterRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter}); - - histos.add("h2dDeltaTrackLengthInnerVsPt", "h2dDeltaTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength}); - histos.add("h2dDeltaTrackLengthOuterVsPt", "h2dDeltaTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength}); - - const AxisSpec axisPt{static_cast(nBinsP), 0.0f, +4.0f, "#it{p_{T}} (GeV/#it{c})"}; - const AxisSpec axisEta{static_cast(nBinsEta), -2.0f, +2.0f, "#eta"}; - const AxisSpec axisRelativePt{static_cast(nBinsRelativeEtaPt), 0.0f, +10.0f, "#it{#sigma_{p_{T}}} / #it{p_{T}} (%)"}; - const AxisSpec axisRelativeEta{static_cast(nBinsRelativeEtaPt), 0.0f, +10.0f, "#it{#sigma_{#eta}} / #it{#eta} (%)"}; - histos.add("h2dRelativePtResolution", "h2dRelativePtResolution", kTH2F, {axisPt, axisRelativePt}); - histos.add("h2dRelativeEtaResolution", "h2dRelativeEtaResolution", kTH2F, {axisEta, axisRelativeEta}); - - std::string particle_names1[5] = {"#it{e}", "#it{#mu}", "#it{#pi}", "#it{K}", "#it{p}"}; - std::string particle_names2[5] = {"Elec", "Muon", "Pion", "Kaon", "Prot"}; - for (int i_true = 0; i_true < 5; i_true++) { - std::string name_title_inner_track_res = "h2dInnerTimeResTrack" + particle_names2[i_true] + "VsP"; - std::string name_title_inner_total_res = "h2dInnerTimeResTotal" + particle_names2[i_true] + "VsP"; - std::string name_title_outer_track_res = "h2dOuterTimeResTrack" + particle_names2[i_true] + "VsP"; - std::string name_title_outer_total_res = "h2dOuterTimeResTotal" + particle_names2[i_true] + "VsP"; - const AxisSpec axisTrackTimeRes{static_cast(nBinsTimeRes), 0.0f, +200.0f, "Track time resolution - " + particle_names1[i_true] + " (ps)"}; - const AxisSpec axisTotalTimeRes{static_cast(nBinsTimeRes), 0.0f, +200.0f, "Total time resolution - " + particle_names1[i_true] + " (ps)"}; - histos.add(name_title_inner_track_res.c_str(), name_title_inner_track_res.c_str(), kTH2F, {axisMomentum, axisTrackTimeRes}); - histos.add(name_title_inner_total_res.c_str(), name_title_inner_total_res.c_str(), kTH2F, {axisMomentum, axisTotalTimeRes}); - histos.add(name_title_outer_track_res.c_str(), name_title_outer_track_res.c_str(), kTH2F, {axisMomentum, axisTrackTimeRes}); - histos.add(name_title_outer_total_res.c_str(), name_title_outer_total_res.c_str(), kTH2F, {axisMomentum, axisTotalTimeRes}); - } - - for (int i_true = 0; i_true < 5; i_true++) { - for (int i_hyp = 0; i_hyp < 5; i_hyp++) { - 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"}; - 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"}; - 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}); - } - } - } - } - } - - /// Function to convert a McParticle into a perfect Track - /// \param particle the particle to convert (mcParticle) - /// \param o2track the address of the resulting TrackParCov - template - o2::track::TrackParCov convertMCParticleToO2Track(McParticleType& particle) - { - // FIXME: this is a fundamentally important piece of code. - // It could be placed in a utility file instead of here. - auto pdgInfo = pdg->GetParticle(particle.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(particle.phi(), s, c); - o2::math_utils::rotateZInv(particle.vx(), particle.vy(), x, params[0], s, c); - params[1] = particle.vz(); - params[2] = 0.; // since alpha = phi - auto theta = 2. * std::atan(std::exp(-particle.eta())); - params[3] = 1. / std::tan(theta); - params[4] = charge / particle.pt(); - - // Return TrackParCov - return o2::track::TrackParCov(x, particle.phi(), params, covm); - } - - /// function to calculate track length of this track up to a certain radius - /// \param track the input track - /// \param radius the radius of the layer you're calculating the length to - /// \param magneticField the magnetic field to use when propagating - float trackLength(o2::track::TrackParCov track, float radius, float magneticField) - { - // don't make use of the track parametrization - float length = -100; - - o2::math_utils::CircleXYf_t trcCircle; - float sna, csa; - track.getCircleParams(magneticField, trcCircle, sna, csa); - - // distance between circle centers (one circle is at origin -> easy) - float centerDistance = std::hypot(trcCircle.xC, trcCircle.yC); - - // condition of circles touching - if not satisfied returned length will be -100 - if (centerDistance < trcCircle.rC + radius && centerDistance > fabs(trcCircle.rC - radius)) { - length = 0.0f; - - // base radical direction - float ux = trcCircle.xC / centerDistance; - float uy = trcCircle.yC / centerDistance; - // calculate perpendicular vector (normalized) for +/- displacement - float vx = -uy; - float vy = +ux; - // calculate coordinate for radical line - float radical = (centerDistance * centerDistance - trcCircle.rC * trcCircle.rC + radius * radius) / (2.0f * centerDistance); - // calculate absolute displacement from center-to-center axis - float displace = (0.5f / centerDistance) * TMath::Sqrt( - (-centerDistance + trcCircle.rC - radius) * - (-centerDistance - trcCircle.rC + radius) * - (-centerDistance + trcCircle.rC + radius) * - (centerDistance + trcCircle.rC + radius)); - - // possible intercept points of track and TOF layer in 2D plane - float point1[2] = {radical * ux + displace * vx, radical * uy + displace * vy}; - float point2[2] = {radical * ux - displace * vx, radical * uy - displace * vy}; - - // decide on correct intercept point - std::array mom; - track.getPxPyPzGlo(mom); - float scalarProduct1 = point1[0] * mom[0] + point1[1] * mom[1]; - float scalarProduct2 = point2[0] * mom[0] + point2[1] * mom[1]; - - // get start point - std::array startPoint; - track.getXYZGlo(startPoint); - - float cosAngle = -1000, modulus = -1000; - - if (scalarProduct1 > scalarProduct2) { - modulus = std::hypot(point1[0] - trcCircle.xC, point1[1] - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); - cosAngle = (point1[0] - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (point1[1] - trcCircle.yC) * (startPoint[1] - trcCircle.yC); - } else { - modulus = std::hypot(point2[0] - trcCircle.xC, point2[1] - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); - cosAngle = (point2[0] - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (point2[1] - trcCircle.yC) * (startPoint[1] - trcCircle.yC); - } - cosAngle /= modulus; - length = trcCircle.rC * TMath::ACos(cosAngle); - length *= sqrt(1.0f + track.getTgl() * track.getTgl()); - } - return length; - } - - /// returns velocity in centimeters per picoseconds - /// \param momentum the momentum of the tarck - /// \param mass the mass of the particle - float velocity(float momentum, float mass) - { - float a = std::pow(momentum / mass, 2); - // uses light speed in cm/ps so output is in those units - return (o2::constants::physics::LightSpeedCm2NS / 1e+3) * std::sqrt(a / (1 + a)); - } - - /// returns track time resolution - /// \param pt the transverse momentum of the tarck - /// \param eta the pseudorapidity of the tarck - /// \param track_pt_resolution the absolute resolution on pt - /// \param track_pt_resolution the absolute resolution on eta - /// \param mass the mass of the particle - /// \param det_radius the radius of the cylindrical layer - /// \param magneticField the magnetic field (along Z) - double calculate_track_time_resolution_advanced(float pt, float eta, float track_pt_resolution, float track_eta_resolution, float mass, float det_radius, float magneticField) - { - // Compute tracking contribution to timing using the error propagation formula - // Uses light speed in m/ps, magnetic field in T (*0.1 for conversion kGauss -> T) - double a0 = mass * mass; - double a1 = 0.299792458 * (0.1 * magneticField) * (0.01 * o2::constants::physics::LightSpeedCm2NS / 1e+3); - double a2 = (det_radius * 0.01) * (det_radius * 0.01) * (0.299792458) * (0.299792458) * (0.1 * magneticField) * (0.1 * magneticField) / 2.0; - double dtof_on_dpt = (std::pow(pt, 4) * std::pow(std::cosh(eta), 2) * std::acos(1.0 - a2 / std::pow(pt, 2)) - 2.0 * a2 * std::pow(pt, 2) * (a0 + std::pow(pt * std::cosh(eta), 2)) / std::sqrt(a2 * (2.0 * std::pow(pt, 2) - a2))) / (a1 * std::pow(pt, 3) * std::sqrt(a0 + std::pow(pt * std::cosh(eta), 2))); - double dtof_on_deta = std::pow(pt, 2) * std::sinh(eta) * std::cosh(eta) * std::acos(1.0 - a2 / std::pow(pt, 2)) / (a1 * std::sqrt(a0 + std::pow(pt * std::cosh(eta), 2))); - double track_time_resolution = std::hypot(std::fabs(dtof_on_dpt) * track_pt_resolution, std::fabs(dtof_on_deta) * track_eta_resolution); - return track_time_resolution; - } - - void process(soa::Join::iterator const& collision, soa::Join const& tracks, aod::McParticles const&, aod::McCollisions const&) - { - o2::dataformats::VertexBase pvVtx({collision.posX(), collision.posY(), collision.posZ()}, - {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}); - - std::array mcPvCov = {0.}; - o2::dataformats::VertexBase mcPvVtx({0.0f, 0.0f, 0.0f}, mcPvCov); - if (collision.has_mcCollision()) { - auto mcCollision = collision.mcCollision(); - mcPvVtx.setX(mcCollision.posX()); - mcPvVtx.setY(mcCollision.posY()); - mcPvVtx.setZ(mcCollision.posZ()); - } // else remains untreated for now - - // First we compute the number of charged particles in the event if LUTs are loaded - float dNdEta = 0.f; - if (flagTOFLoadDelphesLUTs) { - for (const auto& track : tracks) { - if (!track.has_mcParticle()) - continue; - auto mcParticle = track.mcParticle(); - if (std::abs(mcParticle.eta()) > multiplicityEtaRange) { - continue; - } - if (mcParticle.has_daughters()) { - continue; - } - const auto& pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); - if (!pdgInfo) { - // LOG(warning) << "PDG code " << mcParticle.pdgCode() << " not found in the database"; - continue; - } - if (pdgInfo->Charge() == 0) { - continue; - } - dNdEta += 1.f; - } - } - - for (const auto& track : tracks) { - // first step: find precise arrival time (if any) - // --- convert track into perfect track - if (!track.has_mcParticle()) // should always be OK but check please - continue; - - auto mcParticle = track.mcParticle(); - o2::track::TrackParCov o2track = convertMCParticleToO2Track(mcParticle); - - float xPv = -100, trackLengthInnerTOF = -1, trackLengthOuterTOF = -1; - if (o2track.propagateToDCA(mcPvVtx, dBz)) - xPv = o2track.getX(); - if (xPv > -99.) { - trackLengthInnerTOF = trackLength(o2track, innerTOFRadius, dBz); - trackLengthOuterTOF = trackLength(o2track, outerTOFRadius, dBz); - } - - // get mass to calculate velocity - auto pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); - if (pdgInfo == nullptr) { - continue; - } - float expectedTimeInnerTOF = trackLengthInnerTOF / velocity(o2track.getP(), pdgInfo->Mass()); - float expectedTimeOuterTOF = trackLengthOuterTOF / velocity(o2track.getP(), pdgInfo->Mass()); - - // Smear with expected resolutions - float measuredTimeInnerTOF = pRandomNumberGenerator.Gaus(expectedTimeInnerTOF, innerTOFTimeReso); - float measuredTimeOuterTOF = pRandomNumberGenerator.Gaus(expectedTimeOuterTOF, outerTOFTimeReso); - - // Now we calculate the expected arrival time following certain mass hypotheses - // and the (imperfect!) reconstructed track parametrizations - float trackLengthRecoInnerTOF = -1, trackLengthRecoOuterTOF = -1; - auto recoTrack = getTrackParCov(track); - if (recoTrack.propagateToDCA(pvVtx, dBz)) - xPv = recoTrack.getX(); - if (xPv > -99.) { - trackLengthRecoInnerTOF = trackLength(recoTrack, innerTOFRadius, dBz); - trackLengthRecoOuterTOF = trackLength(recoTrack, outerTOFRadius, dBz); - } - - // Straight to Nsigma - float deltaTimeInnerTOF[5], nSigmaInnerTOF[5]; - float deltaTimeOuterTOF[5], nSigmaOuterTOF[5]; - int lpdg_array[5] = {kElectron, kMuonMinus, kPiPlus, kKPlus, kProton}; - float masses[5]; - - if (doQAplots) { - float momentum = recoTrack.getP(); - // unit conversion: length in cm, time in ps - float innerBeta = 1e+3 * (trackLengthInnerTOF / measuredTimeInnerTOF) / o2::constants::physics::LightSpeedCm2NS; - float outerBeta = 1e+3 * (trackLengthOuterTOF / measuredTimeOuterTOF) / o2::constants::physics::LightSpeedCm2NS; - if (trackLengthRecoInnerTOF > 0) { - histos.fill(HIST("h2dVelocityVsMomentumInner"), momentum, innerBeta); - histos.fill(HIST("h2dTrackLengthInnerVsPt"), o2track.getPt(), trackLengthInnerTOF); - histos.fill(HIST("h2dTrackLengthInnerRecoVsPt"), o2track.getPt(), trackLengthRecoInnerTOF); - } - if (trackLengthRecoOuterTOF > 0) { - histos.fill(HIST("h2dVelocityVsMomentumOuter"), momentum, outerBeta); - histos.fill(HIST("h2dTrackLengthOuterVsPt"), o2track.getPt(), trackLengthOuterTOF); - histos.fill(HIST("h2dTrackLengthOuterRecoVsPt"), o2track.getPt(), trackLengthRecoOuterTOF); - } - } - - for (int ii = 0; ii < 5; ii++) { - nSigmaInnerTOF[ii] = -100; - nSigmaOuterTOF[ii] = -100; - - auto pdgInfoThis = pdg->GetParticle(lpdg_array[ii]); - masses[ii] = pdgInfoThis->Mass(); - deltaTimeInnerTOF[ii] = trackLengthRecoInnerTOF / velocity(recoTrack.getP(), masses[ii]) - measuredTimeInnerTOF; - deltaTimeOuterTOF[ii] = trackLengthRecoOuterTOF / velocity(recoTrack.getP(), masses[ii]) - measuredTimeOuterTOF; - - // Evaluate total sigma (layer + tracking resolution) - float innerTotalTimeReso = innerTOFTimeReso; - float outerTotalTimeReso = outerTOFTimeReso; - if (flagIncludeTrackTimeRes) { - double pt_resolution = std::pow(recoTrack.getP() / std::cosh(recoTrack.getEta()), 2) * std::sqrt(recoTrack.getSigma1Pt2()); - double eta_resolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-recoTrack.getEta())))) * std::sqrt(recoTrack.getSigmaTgl2()); - if (flagTOFLoadDelphesLUTs) { - pt_resolution = mSmearer.getAbsPtRes(pdgInfoThis->PdgCode(), dNdEta, recoTrack.getEta(), recoTrack.getP() / std::cosh(recoTrack.getEta())); - eta_resolution = mSmearer.getAbsEtaRes(pdgInfoThis->PdgCode(), dNdEta, recoTrack.getEta(), recoTrack.getP() / std::cosh(recoTrack.getEta())); - } - float innerTrackTimeReso = calculate_track_time_resolution_advanced(recoTrack.getP() / std::cosh(recoTrack.getEta()), recoTrack.getEta(), pt_resolution, eta_resolution, masses[ii], innerTOFRadius, dBz); - float outerTrackTimeReso = calculate_track_time_resolution_advanced(recoTrack.getP() / std::cosh(recoTrack.getEta()), recoTrack.getEta(), pt_resolution, eta_resolution, masses[ii], outerTOFRadius, dBz); - innerTotalTimeReso = std::hypot(innerTOFTimeReso, innerTrackTimeReso); - outerTotalTimeReso = std::hypot(outerTOFTimeReso, outerTrackTimeReso); - - if (doQAplots && trackLengthRecoInnerTOF > 0) { - float momentum = recoTrack.getP(); - if (ii == 0 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[0])->PdgCode()) { - histos.fill(HIST("h2dInnerTimeResTrackElecVsP"), momentum, innerTrackTimeReso); - histos.fill(HIST("h2dInnerTimeResTotalElecVsP"), momentum, innerTotalTimeReso); - } - if (ii == 1 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[1])->PdgCode()) { - histos.fill(HIST("h2dInnerTimeResTrackMuonVsP"), momentum, innerTrackTimeReso); - histos.fill(HIST("h2dInnerTimeResTotalMuonVsP"), momentum, innerTotalTimeReso); - } - if (ii == 2 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[2])->PdgCode()) { - histos.fill(HIST("h2dInnerTimeResTrackPionVsP"), momentum, innerTrackTimeReso); - histos.fill(HIST("h2dInnerTimeResTotalPionVsP"), momentum, innerTotalTimeReso); - } - if (ii == 3 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[3])->PdgCode()) { - histos.fill(HIST("h2dInnerTimeResTrackKaonVsP"), momentum, innerTrackTimeReso); - histos.fill(HIST("h2dInnerTimeResTotalKaonVsP"), momentum, innerTotalTimeReso); - } - if (ii == 4 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[4])->PdgCode()) { - histos.fill(HIST("h2dInnerTimeResTrackProtVsP"), momentum, innerTrackTimeReso); - histos.fill(HIST("h2dInnerTimeResTotalProtVsP"), momentum, innerTotalTimeReso); - } - } - if (doQAplots && trackLengthRecoOuterTOF > 0) { - float momentum = recoTrack.getP(); - float pseudorapidity = recoTrack.getEta(); - float transverse_momentum = momentum / std::cosh(pseudorapidity); - if (ii == 0 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[0])->PdgCode()) { - histos.fill(HIST("h2dOuterTimeResTrackElecVsP"), momentum, outerTrackTimeReso); - histos.fill(HIST("h2dOuterTimeResTotalElecVsP"), momentum, outerTotalTimeReso); - } - if (ii == 1 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[1])->PdgCode()) { - histos.fill(HIST("h2dOuterTimeResTrackMuonVsP"), momentum, outerTrackTimeReso); - histos.fill(HIST("h2dOuterTimeResTotalMuonVsP"), momentum, outerTotalTimeReso); - } - if (ii == 2 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[2])->PdgCode()) { - histos.fill(HIST("h2dOuterTimeResTrackPionVsP"), momentum, outerTrackTimeReso); - histos.fill(HIST("h2dOuterTimeResTotalPionVsP"), momentum, outerTotalTimeReso); - - histos.fill(HIST("h2dRelativePtResolution"), transverse_momentum, 100.0 * pt_resolution / transverse_momentum); - histos.fill(HIST("h2dRelativeEtaResolution"), pseudorapidity, 100.0 * eta_resolution / (std::fabs(pseudorapidity) + 1e-6)); - } - if (ii == 3 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[3])->PdgCode()) { - histos.fill(HIST("h2dOuterTimeResTrackKaonVsP"), momentum, outerTrackTimeReso); - histos.fill(HIST("h2dOuterTimeResTotalKaonVsP"), momentum, outerTotalTimeReso); - } - if (ii == 4 && std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[4])->PdgCode()) { - histos.fill(HIST("h2dOuterTimeResTrackProtVsP"), momentum, outerTrackTimeReso); - histos.fill(HIST("h2dOuterTimeResTotalProtVsP"), momentum, outerTotalTimeReso); - } - } - } - - // Fixme: assumes dominant resolution effect is the TOF resolution - // and not the tracking itself. It's *probably* a fair assumption - // but it should be tested further! --> FIXED IN THIS VERSION - if (trackLengthInnerTOF > 0 && trackLengthRecoInnerTOF > 0) - nSigmaInnerTOF[ii] = deltaTimeInnerTOF[ii] / innerTotalTimeReso; - if (trackLengthOuterTOF > 0 && trackLengthRecoOuterTOF > 0) - nSigmaOuterTOF[ii] = deltaTimeOuterTOF[ii] / outerTotalTimeReso; - } - - if (doQAplots) { - float momentum = recoTrack.getP(); - if (trackLengthRecoInnerTOF > 0) { - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[0])->PdgCode()) { - histos.fill(HIST("h2dInnerNsigmaTrueElecVsElecHypothesis"), momentum, nSigmaInnerTOF[0]); - histos.fill(HIST("h2dInnerNsigmaTrueElecVsMuonHypothesis"), momentum, nSigmaInnerTOF[1]); - histos.fill(HIST("h2dInnerNsigmaTrueElecVsPionHypothesis"), momentum, nSigmaInnerTOF[2]); - histos.fill(HIST("h2dInnerNsigmaTrueElecVsKaonHypothesis"), momentum, nSigmaInnerTOF[3]); - histos.fill(HIST("h2dInnerNsigmaTrueElecVsProtHypothesis"), momentum, nSigmaInnerTOF[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[1])->PdgCode()) { - histos.fill(HIST("h2dInnerNsigmaTrueMuonVsElecHypothesis"), momentum, nSigmaInnerTOF[0]); - histos.fill(HIST("h2dInnerNsigmaTrueMuonVsMuonHypothesis"), momentum, nSigmaInnerTOF[1]); - histos.fill(HIST("h2dInnerNsigmaTrueMuonVsPionHypothesis"), momentum, nSigmaInnerTOF[2]); - histos.fill(HIST("h2dInnerNsigmaTrueMuonVsKaonHypothesis"), momentum, nSigmaInnerTOF[3]); - histos.fill(HIST("h2dInnerNsigmaTrueMuonVsProtHypothesis"), momentum, nSigmaInnerTOF[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[2])->PdgCode()) { - histos.fill(HIST("h2dInnerNsigmaTruePionVsElecHypothesis"), momentum, nSigmaInnerTOF[0]); - histos.fill(HIST("h2dInnerNsigmaTruePionVsMuonHypothesis"), momentum, nSigmaInnerTOF[1]); - histos.fill(HIST("h2dInnerNsigmaTruePionVsPionHypothesis"), momentum, nSigmaInnerTOF[2]); - histos.fill(HIST("h2dInnerNsigmaTruePionVsKaonHypothesis"), momentum, nSigmaInnerTOF[3]); - histos.fill(HIST("h2dInnerNsigmaTruePionVsProtHypothesis"), momentum, nSigmaInnerTOF[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[3])->PdgCode()) { - histos.fill(HIST("h2dInnerNsigmaTrueKaonVsElecHypothesis"), momentum, nSigmaInnerTOF[0]); - histos.fill(HIST("h2dInnerNsigmaTrueKaonVsMuonHypothesis"), momentum, nSigmaInnerTOF[1]); - histos.fill(HIST("h2dInnerNsigmaTrueKaonVsPionHypothesis"), momentum, nSigmaInnerTOF[2]); - histos.fill(HIST("h2dInnerNsigmaTrueKaonVsKaonHypothesis"), momentum, nSigmaInnerTOF[3]); - histos.fill(HIST("h2dInnerNsigmaTrueKaonVsProtHypothesis"), momentum, nSigmaInnerTOF[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[4])->PdgCode()) { - histos.fill(HIST("h2dInnerNsigmaTrueProtVsElecHypothesis"), momentum, nSigmaInnerTOF[0]); - histos.fill(HIST("h2dInnerNsigmaTrueProtVsMuonHypothesis"), momentum, nSigmaInnerTOF[1]); - histos.fill(HIST("h2dInnerNsigmaTrueProtVsPionHypothesis"), momentum, nSigmaInnerTOF[2]); - histos.fill(HIST("h2dInnerNsigmaTrueProtVsKaonHypothesis"), momentum, nSigmaInnerTOF[3]); - histos.fill(HIST("h2dInnerNsigmaTrueProtVsProtHypothesis"), momentum, nSigmaInnerTOF[4]); - } - } - if (trackLengthRecoOuterTOF > 0) { - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[0])->PdgCode()) { - histos.fill(HIST("h2dOuterNsigmaTrueElecVsElecHypothesis"), momentum, nSigmaOuterTOF[0]); - histos.fill(HIST("h2dOuterNsigmaTrueElecVsMuonHypothesis"), momentum, nSigmaOuterTOF[1]); - histos.fill(HIST("h2dOuterNsigmaTrueElecVsPionHypothesis"), momentum, nSigmaOuterTOF[2]); - histos.fill(HIST("h2dOuterNsigmaTrueElecVsKaonHypothesis"), momentum, nSigmaOuterTOF[3]); - histos.fill(HIST("h2dOuterNsigmaTrueElecVsProtHypothesis"), momentum, nSigmaOuterTOF[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[1])->PdgCode()) { - histos.fill(HIST("h2dOuterNsigmaTrueMuonVsElecHypothesis"), momentum, nSigmaOuterTOF[0]); - histos.fill(HIST("h2dOuterNsigmaTrueMuonVsMuonHypothesis"), momentum, nSigmaOuterTOF[1]); - histos.fill(HIST("h2dOuterNsigmaTrueMuonVsPionHypothesis"), momentum, nSigmaOuterTOF[2]); - histos.fill(HIST("h2dOuterNsigmaTrueMuonVsKaonHypothesis"), momentum, nSigmaOuterTOF[3]); - histos.fill(HIST("h2dOuterNsigmaTrueMuonVsProtHypothesis"), momentum, nSigmaOuterTOF[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[2])->PdgCode()) { - histos.fill(HIST("h2dOuterNsigmaTruePionVsElecHypothesis"), momentum, nSigmaOuterTOF[0]); - histos.fill(HIST("h2dOuterNsigmaTruePionVsMuonHypothesis"), momentum, nSigmaOuterTOF[1]); - histos.fill(HIST("h2dOuterNsigmaTruePionVsPionHypothesis"), momentum, nSigmaOuterTOF[2]); - histos.fill(HIST("h2dOuterNsigmaTruePionVsKaonHypothesis"), momentum, nSigmaOuterTOF[3]); - histos.fill(HIST("h2dOuterNsigmaTruePionVsProtHypothesis"), momentum, nSigmaOuterTOF[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[3])->PdgCode()) { - histos.fill(HIST("h2dOuterNsigmaTrueKaonVsElecHypothesis"), momentum, nSigmaOuterTOF[0]); - histos.fill(HIST("h2dOuterNsigmaTrueKaonVsMuonHypothesis"), momentum, nSigmaOuterTOF[1]); - histos.fill(HIST("h2dOuterNsigmaTrueKaonVsPionHypothesis"), momentum, nSigmaOuterTOF[2]); - histos.fill(HIST("h2dOuterNsigmaTrueKaonVsKaonHypothesis"), momentum, nSigmaOuterTOF[3]); - histos.fill(HIST("h2dOuterNsigmaTrueKaonVsProtHypothesis"), momentum, nSigmaOuterTOF[4]); - } - if (std::fabs(mcParticle.pdgCode()) == pdg->GetParticle(lpdg_array[4])->PdgCode()) { - histos.fill(HIST("h2dOuterNsigmaTrueProtVsElecHypothesis"), momentum, nSigmaOuterTOF[0]); - histos.fill(HIST("h2dOuterNsigmaTrueProtVsMuonHypothesis"), momentum, nSigmaOuterTOF[1]); - histos.fill(HIST("h2dOuterNsigmaTrueProtVsPionHypothesis"), momentum, nSigmaOuterTOF[2]); - histos.fill(HIST("h2dOuterNsigmaTrueProtVsKaonHypothesis"), momentum, nSigmaOuterTOF[3]); - histos.fill(HIST("h2dOuterNsigmaTrueProtVsProtHypothesis"), momentum, nSigmaOuterTOF[4]); - } - } - } - - float deltaTrackLengthInnerTOF = abs(trackLengthInnerTOF - trackLengthRecoInnerTOF); - if (trackLengthInnerTOF > 0 && trackLengthRecoInnerTOF > 0) { - histos.fill(HIST("h2dDeltaTrackLengthInnerVsPt"), o2track.getPt(), deltaTrackLengthInnerTOF); - } - float deltaTrackLengthOuterTOF = abs(trackLengthOuterTOF - trackLengthRecoOuterTOF); - if (trackLengthOuterTOF > 0 && trackLengthRecoOuterTOF > 0) { - histos.fill(HIST("h2dDeltaTrackLengthOuterVsPt"), o2track.getPt(), deltaTrackLengthInnerTOF); - } - - // Sigmas have been fully calculated. Please populate the NSigma helper table (once per track) - upgradeTof(nSigmaInnerTOF[0], nSigmaInnerTOF[1], nSigmaInnerTOF[2], nSigmaInnerTOF[3], nSigmaInnerTOF[4], trackLengthInnerTOF, trackLengthRecoInnerTOF, deltaTrackLengthInnerTOF, - nSigmaOuterTOF[0], nSigmaOuterTOF[1], nSigmaOuterTOF[2], nSigmaOuterTOF[3], nSigmaOuterTOF[4], trackLengthOuterTOF, trackLengthRecoOuterTOF, deltaTrackLengthOuterTOF); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx new file mode 100644 index 00000000000..f7091d7f26b --- /dev/null +++ b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx @@ -0,0 +1,933 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file onTheFlyTofPid.cxx +/// +/// \brief This task goes straight from a combination of track table and mcParticles +/// and a custom TOF configuration to a table of TOF NSigmas for the particles +/// being analysed. It currently contemplates 5 particle types: +/// electrons, pions, kaons, protons and muons +/// +/// More particles could be added but would have to be added to the LUT +/// being used in the onTheFly tracker task. +/// +/// \author David Dobrigkeit Chinellato, UNICAMP +/// \author Nicola Nicassio, University and INFN Bari +/// \since May 22, 2024 +/// + +#include "TableHelper.h" + +#include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include "ALICE3/Core/TrackUtilities.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +std::array, 9> h2dInnerTimeResTrack; +std::array, 9> h2dInnerTimeResTotal; +std::array, 9> h2dOuterTimeResTrack; +std::array, 9> h2dOuterTimeResTotal; +std::array, 9>, 9> h2dInnerNsigmaTrue; +std::array, 9>, 9> h2dOuterNsigmaTrue; +std::array, 9>, 9> h2dInnerDeltaTrue; +std::array, 9>, 9> h2dOuterDeltaTrue; + +struct OnTheFlyTofPid { + Produces upgradeTofMC; + Produces upgradeTof; + Produces upgradeTofExpectedTime; + + // necessary for particle charges + Service pdg; + // Necessary for LUTs + Service ccdb; + + // these are the settings governing the TOF layers to be used + // note that there are two layers foreseen for now: inner and outer TOF + // more could be added (especially a disk TOF at a certain z?) + // in the evolution of this effort + struct : ConfigurableGroup { + Configurable magneticField{"magneticField", 0, "magnetic field (kilogauss) if 0, taken from the tracker task"}; + Configurable considerEventTime{"considerEventTime", true, "flag to consider event time"}; + Configurable innerTOFRadius{"innerTOFRadius", 20, "barrel inner TOF radius (cm)"}; + Configurable outerTOFRadius{"outerTOFRadius", 80, "barrel outer TOF radius (cm)"}; + Configurable innerTOFLength{"innerTOFLength", 124, "barrel inner TOF length (cm)"}; + Configurable outerTOFLength{"outerTOFLength", 250, "barrel outer TOF length (cm)"}; + Configurable> innerTOFPixelDimension{"innerTOFPixelDimension", {0.1, 0.1}, "barrel inner TOF pixel dimension in Z and RPhi (cm)"}; + Configurable innerTOFFractionOfInactiveArea{"innerTOFFractionOfInactiveArea", 0.f, "barrel inner TOF fraction of inactive area"}; + Configurable> outerTOFPixelDimension{"outerTOFPixelDimension", {0.1, 0.1}, "barrel outer TOF pixel dimension in Z and RPhi (cm)"}; + Configurable outerTOFFractionOfInactiveArea{"outerTOFFractionOfInactiveArea", 0.f, "barrel outer TOF fraction of inactive area"}; + Configurable innerTOFTimeReso{"innerTOFTimeReso", 20, "barrel inner TOF time error (ps)"}; + Configurable outerTOFTimeReso{"outerTOFTimeReso", 20, "barrel outer TOF time error (ps)"}; + Configurable nStepsLIntegrator{"nStepsLIntegrator", 200, "number of steps in length integrator"}; + Configurable multiplicityEtaRange{"multiplicityEtaRange", 0.800000012, "eta range to compute the multiplicity"}; + Configurable flagIncludeTrackTimeRes{"flagIncludeTrackTimeRes", true, "flag to include or exclude track time resolution"}; + Configurable flagTOFLoadDelphesLUTs{"flagTOFLoadDelphesLUTs", false, "flag to load Delphes LUTs for tracking correction (use recoTrack parameters if false)"}; + } simConfig; + + struct : ConfigurableGroup { + Configurable doQAplots{"doQAplots", true, "do basic velocity plot qa"}; + Configurable doSeparationVsPt{"doSeparationVsPt", true, "Produce plots vs pt or p"}; + Configurable nBinsBeta{"nBinsBeta", 2200, "number of bins in beta"}; + Configurable nBinsP{"nBinsP", 80, "number of bins in momentum/pT depending on doSeparationVsPt"}; + Configurable nBinsTrackLengthInner{"nBinsTrackLengthInner", 300, "number of bins in track length"}; + Configurable nBinsTrackLengthOuter{"nBinsTrackLengthOuter", 300, "number of bins in track length"}; + 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 nBinsDeltaCorrectSpecies{"nBinsDeltaCorrectSpecies", 200, "number of bins in Delta plot (correct speies)"}; + Configurable nBinsDeltaWrongSpecies{"nBinsDeltaWrongSpecies", 200, "number of bins in Delta plot (wrong species)"}; + Configurable minDeltaRange{"minDeltaRange", -100, "lower limit for the nsigma axis"}; + Configurable maxDeltaRange{"maxDeltaRange", +100, "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"}; + Configurable nBinsMult{"nBinsMult", 200, "number of bins in multiplicity"}; + Configurable maxMultRange{"maxMultRange", 1000.f, "upper limit in multiplicity plots"}; + } plotsConfig; + + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + // Track smearer (here used to get absolute pt and eta uncertainties if simConfig.flagTOFLoadDelphesLUTs is true) + o2::delphes::DelphesO2TrackSmearer mSmearer; + + // needed: random number generator for smearing + TRandom3 pRandomNumberGenerator; + + // for handling basic QA histograms if requested + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + OutputObj listEfficiency{"efficiency"}; + static constexpr int kParticles = 9; + + void init(o2::framework::InitContext& initContext) + { + pRandomNumberGenerator.SetSeed(0); // fully randomize + if (simConfig.magneticField.value < o2::constants::math::Epsilon) { + LOG(info) << "Getting the magnetic field from the on-the-fly tracker task"; + if (!getTaskOptionValue(initContext, "on-the-fly-tracker", simConfig.magneticField, false)) { + LOG(fatal) << "Could not get Bz from on-the-fly-tracker task"; + } + LOG(info) << "Bz = " << simConfig.magneticField.value << " T"; + } + + // Load LUT for pt and eta smearing + if (simConfig.flagIncludeTrackTimeRes && simConfig.flagTOFLoadDelphesLUTs) { + mSmearer.setCcdbManager(ccdb.operator->()); + auto loadLUT = [&](int pdg, const std::string& cfgNameToInherit) { + std::string lut = "none"; + if (!getTaskOptionValue(initContext, "on-the-fly-tracker", cfgNameToInherit, lut, false)) { + LOG(fatal) << "Could not get " << cfgNameToInherit << " from on-the-fly-tracker task"; + } + bool success = mSmearer.loadTable(pdg, lut.c_str()); + if (!success && !lut.empty()) { + LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << lut; + } + }; + loadLUT(11, "lutEl"); + loadLUT(13, "lutMu"); + loadLUT(211, "lutPi"); + loadLUT(321, "lutKa"); + loadLUT(2212, "lutPr"); + loadLUT(1000010020, "lutDe"); + loadLUT(1000010030, "lutTr"); + loadLUT(1000020030, "lutHe3"); + loadLUT(1000020040, "lutAl"); + } + + if (plotsConfig.doQAplots) { + const AxisSpec axisdNdeta{plotsConfig.nBinsMult, 0.0f, plotsConfig.maxMultRange, Form("dN/d#eta in |#eta| < %f", simConfig.multiplicityEtaRange.value)}; + + histos.add("h1dNdeta", "h2dNdeta", kTH1F, {axisdNdeta}); + histos.add("h2dEventTime", "h2dEventTime", kTH2F, {{200, -1000, 1000, "computed"}, {200, -1000, 1000, "generated"}}); + histos.add("h1dEventTimegen", "h1dEventTimegen", kTH1F, {{200, -1000, 1000, "generated"}}); + histos.add("h1dEventTimerec", "h1dEventTimerec", kTH1F, {{200, -1000, 1000, "computed"}}); + histos.add("h1dEventTimedelta", "h1dEventTimedelta", kTH1F, {{200, -1000, 1000, "generated - computed"}}); + histos.add("h2dEventTimeres", "h2dEventTimeres", kTH2F, {axisdNdeta, {300, 0, 300, "resolution"}}); + listEfficiency.setObject(new THashList); + listEfficiency->Add(new TEfficiency("effEventTime", "effEventTime", plotsConfig.nBinsMult, 0.0f, plotsConfig.maxMultRange)); + + const AxisSpec axisMomentum{static_cast(plotsConfig.nBinsP), 0.0f, +10.0f, "#it{p} (GeV/#it{c})"}; + const AxisSpec axisRigidity{static_cast(plotsConfig.nBinsP), 0.0f, +10.0f, "#it{p} / |#it{z}| (GeV/#it{c})"}; + const AxisSpec axisMomentumSmall{static_cast(plotsConfig.nBinsP), 0.0f, +1.0f, "#it{p} (GeV/#it{c})"}; + const AxisSpec axisVelocity{static_cast(plotsConfig.nBinsBeta), 0.0f, +1.1f, "Measured #beta"}; + const AxisSpec axisTrackLengthInner{static_cast(plotsConfig.nBinsTrackLengthInner), 0.0f, 60.0f, "Track length (cm)"}; + const AxisSpec axisTrackLengthOuter{static_cast(plotsConfig.nBinsTrackLengthOuter), 0.0f, 300.0f, "Track length (cm)"}; + const AxisSpec axisTrackDeltaLength{static_cast(plotsConfig.nBinsTrackDeltaLength), 0.0f, 30.0f, "Delta Track length (cm)"}; + histos.add("iTOF/h2dVelocityVsMomentumInner", "h2dVelocityVsMomentumInner", kTH2F, {axisMomentum, axisVelocity}); + histos.add("iTOF/h2dVelocityVsRigidityInner", "h2dVelocityVsRigidityInner", kTH2F, {axisRigidity, axisVelocity}); + histos.add("iTOF/h2dTrackLengthInnerVsPt", "h2dTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner}); + histos.add("iTOF/h2dTrackLengthInnerRecoVsPt", "h2dTrackLengthInnerRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner}); + histos.add("iTOF/h2dDeltaTrackLengthInnerVsPt", "h2dDeltaTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength}); + histos.add("iTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.innerTOFLength / 2, simConfig.innerTOFLength / 2}, {1000, 0, simConfig.innerTOFRadius * 2 * M_PI}}); + + histos.add("oTOF/h2dVelocityVsMomentumOuter", "h2dVelocityVsMomentumOuter", kTH2F, {axisMomentum, axisVelocity}); + histos.add("oTOF/h2dVelocityVsRigidityOuter", "h2dVelocityVsRigidityOuter", kTH2F, {axisRigidity, axisVelocity}); + histos.add("oTOF/h2dTrackLengthOuterVsPt", "h2dTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter}); + histos.add("oTOF/h2dTrackLengthOuterRecoVsPt", "h2dTrackLengthOuterRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter}); + histos.add("oTOF/h2dDeltaTrackLengthOuterVsPt", "h2dDeltaTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength}); + histos.add("oTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.outerTOFLength / 2, simConfig.outerTOFLength / 2}, {1000, 0, simConfig.outerTOFRadius * 2 * M_PI}}); + + const AxisSpec axisPt{static_cast(plotsConfig.nBinsP), 0.0f, +4.0f, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisEta{static_cast(plotsConfig.nBinsEta), -2.0f, +2.0f, "#eta"}; + const AxisSpec axisRelativePt{static_cast(plotsConfig.nBinsRelativeEtaPt), 0.0f, +10.0f, "#it{#sigma_{p_{T}}} / #it{p_{T}} (%)"}; + const AxisSpec axisRelativeEta{static_cast(plotsConfig.nBinsRelativeEtaPt), 0.0f, +10.0f, "#it{#sigma_{#eta}} / #it{#eta} (%)"}; + histos.add("h2dRelativePtResolution", "h2dRelativePtResolution", kTH2F, {axisPt, axisRelativePt}); + histos.add("h2dRelativeEtaResolution", "h2dRelativeEtaResolution", kTH2F, {axisEta, axisRelativeEta}); + + std::string particleNames[kParticles] = {"#it{e}", "#it{#mu}", "#it{#pi}", "#it{K}", "#it{p}", "#it{d}", "#it{t}", "^{3}He", "#it{#alpha}"}; + std::string particleNames2[kParticles] = {"Elec", "Muon", "Pion", "Kaon", "Prot", "Deut", "Trit", "He3", "Al"}; + for (int iTrue = 0; iTrue < kParticles; iTrue++) { + auto addHistogram = [&](const std::string& name, const AxisSpec& axis) { + return histos.add(name, "", kTH2F, {axisMomentum, axis}); + }; + + const AxisSpec axisTrackTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, "Track time resolution - " + particleNames[iTrue] + " (ps)"}; + h2dInnerTimeResTrack[iTrue] = addHistogram("iTOF/res/h2dInnerTimeResTrack" + particleNames2[iTrue] + "VsP", axisTrackTimeRes); + h2dOuterTimeResTrack[iTrue] = addHistogram("oTOF/res/h2dOuterTimeResTrack" + particleNames2[iTrue] + "VsP", axisTrackTimeRes); + const AxisSpec axisTotalTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, "Total time resolution - " + particleNames[iTrue] + " (ps)"}; + h2dInnerTimeResTotal[iTrue] = addHistogram("iTOF/res/h2dInnerTimeResTotal" + particleNames2[iTrue] + "VsP", axisTotalTimeRes); + h2dOuterTimeResTotal[iTrue] = addHistogram("oTOF/res/h2dOuterTimeResTotal" + particleNames2[iTrue] + "VsP", axisTotalTimeRes); + for (int iHyp = 0; iHyp < kParticles; iHyp++) { + std::string nameTitleInner = "h2dInnerNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; + std::string nameTitleOuter = "h2dOuterNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; + std::string nameTitleInnerDelta = "h2dInnerDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; + std::string nameTitleOuterDelta = "h2dOuterDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; + const AxisSpec axisX{plotsConfig.doSeparationVsPt.value ? axisPt : axisMomentum}; + const AxisSpec axisNsigmaCorrect{plotsConfig.nBinsNsigmaCorrectSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, "N#sigma - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; + const AxisSpec axisDeltaCorrect{plotsConfig.nBinsDeltaCorrectSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, "#Delta - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; + const AxisSpec axisNsigmaWrong{plotsConfig.nBinsNsigmaWrongSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, "N#sigma - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; + const AxisSpec axisDeltaWrong{plotsConfig.nBinsDeltaWrongSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, "#Delta - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; + const AxisSpec axisNSigma{iTrue == iHyp ? axisNsigmaCorrect : axisNsigmaWrong}; + const AxisSpec axisDelta{iTrue == iHyp ? axisDeltaCorrect : axisDeltaWrong}; + h2dInnerNsigmaTrue[iTrue][iHyp] = histos.add("iTOF/nsigma/h2dInnerNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisNSigma}); + h2dOuterNsigmaTrue[iTrue][iHyp] = histos.add("oTOF/nsigma/h2dOuterNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisNSigma}); + h2dInnerDeltaTrue[iTrue][iHyp] = histos.add("iTOF/delta/h2dInnerDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisDelta}); + h2dOuterDeltaTrue[iTrue][iHyp] = histos.add("oTOF/delta/h2dOuterDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisDelta}); + } + } + } + } + + struct TOFLayerEfficiency { + private: + const float layerRadius; + const float layerLength; + const float pixelDimensionZ; + const float pixelDimensionRPhi; + const float fractionInactive; + const float magField; + + TAxis* axisZ = nullptr; + TAxis* axisRPhi = nullptr; + TAxis* axisInPixelZ = nullptr; + TAxis* axisInPixelRPhi = nullptr; + + TH2F* hHitMapInPixel = nullptr; + TH2F* hHitMapInPixelBefore = nullptr; + TH2F* hHitMap = nullptr; + + public: + ~TOFLayerEfficiency() + { + hHitMap->SaveAs(Form("/tmp/%s.png", hHitMap->GetName())); + hHitMapInPixel->SaveAs(Form("/tmp/%s.png", hHitMapInPixel->GetName())); + hHitMapInPixelBefore->SaveAs(Form("/tmp/%s.png", hHitMapInPixelBefore->GetName())); + + delete axisZ; + delete axisRPhi; + delete axisInPixelZ; + delete axisInPixelRPhi; + delete hHitMap; + delete hHitMapInPixel; + delete hHitMapInPixelBefore; + } + + TOFLayerEfficiency(float r, float l, std::array pDimensions, float fIA, float m) + : layerRadius(r), layerLength(l), pixelDimensionZ(pDimensions[0]), pixelDimensionRPhi(pDimensions[1]), fractionInactive(fIA), magField(m) + { + // Assuming square pixels for simplicity + const float circumference = 2.0f * M_PI * layerRadius; + axisZ = new TAxis(static_cast(layerLength / pixelDimensionZ), -layerLength / 2, layerLength); + axisRPhi = new TAxis(static_cast(circumference / pixelDimensionRPhi), 0.f, circumference); + + const float inactiveBorderRPhi = pixelDimensionRPhi * std::sqrt(fractionInactive) / 2; + const float inactiveBorderZ = pixelDimensionZ * std::sqrt(fractionInactive) / 2; + const double arrayRPhi[4] = {-pixelDimensionRPhi / 2, -pixelDimensionRPhi / 2 + inactiveBorderRPhi, pixelDimensionRPhi / 2 - inactiveBorderRPhi, pixelDimensionRPhi / 2}; + for (int i = 0; i < 4; i++) { + LOG(info) << "arrayRPhi[" << i << "] = " << arrayRPhi[i]; + } + axisInPixelRPhi = new TAxis(3, arrayRPhi); + const double arrayZ[4] = {-pixelDimensionZ / 2, -pixelDimensionZ / 2 + inactiveBorderZ, pixelDimensionZ / 2 - inactiveBorderZ, pixelDimensionZ / 2}; + for (int i = 0; i < 4; i++) { + LOG(info) << "arrayZ[" << i << "] = " << arrayZ[i]; + } + axisInPixelZ = new TAxis(3, arrayZ); + + hHitMap = new TH2F(Form("hHitMap_R%.0f", layerRadius), "HitMap;z (cm); r#phi (cm)", 1000, -1000, 1000, 1000, -1000, 1000); + hHitMapInPixel = new TH2F(Form("hHitMapInPixel_R%.0f", layerRadius), "HitMapInPixel;z (cm); r#phi (cm)", 1000, -10, 10, 1000, -10, 10); + hHitMapInPixelBefore = new TH2F(Form("hHitMapInPixelBefore_R%.0f", layerRadius), "HitMapInPixel;z (cm); r#phi (cm)", 1000, -10, 10, 1000, -10, 10); + } + + bool isInTOFActiveArea(std::array hitPosition) + { + if (fractionInactive <= 0.0f) { + return true; + } + if (fractionInactive >= 1.0f) { + return false; + } + + // Convert 3D position to cylindrical coordinates for area calculation + const float phi = std::atan2(hitPosition[1], hitPosition[0]); + const float rphi = phi * layerRadius; + const float z = hitPosition[2]; + const float r = std::sqrt(hitPosition[0] * hitPosition[0] + hitPosition[1] * hitPosition[1]); + + // Check if hit is within layer geometric acceptance + if (std::abs(layerRadius - r) > 10.f) { + LOG(debug) << "Hit out of TOF layer acceptance: r=" << r << " cm with respect to the layer radius " << layerRadius; + return false; + } + if (std::abs(z) > layerLength / 2.0f) { + LOG(debug) << "Hit out of TOF layer acceptance: z=" << z << " cm with respect to the layer length " << layerLength; + return false; + } + + const int pixelIndexPhi = axisRPhi->FindBin(rphi); + const int pixelIndexZ = axisZ->FindBin(z); + + // LOG(info) << "Hit pixel " << pixelIndexPhi << "/" << nPixelsRPhi << " and " << pixelIndexZ << "/" << nPixelsZ; + + if (pixelIndexPhi <= 0 || pixelIndexPhi > axisRPhi->GetNbins() || pixelIndexZ <= 0 || pixelIndexZ > axisZ->GetNbins()) { + // LOG(info) << "Hit out of TOF layer pixel range: pixelIndexPhi=" << pixelIndexPhi << ", pixelIndexZ=" << pixelIndexZ; + return false; + } + // Calculate local position within the pixel + const float localRPhi = (rphi - axisRPhi->GetBinCenter(pixelIndexPhi)); + const float localZ = (z - axisZ->GetBinCenter(pixelIndexZ)); + + // The difference between the hit and the pixel position cannot be greater than the size of the pixel + if (std::abs(localRPhi - axisRPhi->GetBinCenter(pixelIndexPhi)) > axisRPhi->GetBinWidth(pixelIndexPhi)) { + // LOG(warning) << "Local hit difference in phi is bigger than the pixel size"; + } + if (std::abs(localZ - axisZ->GetBinCenter(pixelIndexZ)) > axisZ->GetBinWidth(pixelIndexZ)) { + // LOG(warning) << "Local hit difference in z is bigger than the pixel size"; + } + hHitMapInPixelBefore->Fill(localZ, localRPhi); + switch (axisInPixelRPhi->FindBin(localRPhi)) { + case 0: + case 1: + case 3: + case 4: + return false; + } + switch (axisInPixelZ->FindBin(localZ)) { + case 0: + case 1: + case 3: + case 4: + return false; + } + hHitMapInPixel->Fill(localZ, localRPhi); + hHitMap->Fill(z, rphi); + return true; + } + + /// Check if a track hits the active area (convenience function) + /// \param track the track parameters for automatic hit position calculation + /// \return true if the hit is in the active area + bool isTrackInActiveArea(const o2::track::TrackParCov& track) + { + if (fractionInactive <= 0.f) { + return true; + } + float x, y, z; + if (!track.getXatLabR(layerRadius, x, magField)) { + LOG(debug) << "Could not propagate track to TOF layer at radius " << layerRadius << " cm"; + return false; + } + bool b; + ROOT::Math::PositionVector3D hit = track.getXYZGloAt(x, magField, b); + if (!b) { + LOG(debug) << "Could not get hit position at radius " << layerRadius << " cm"; + return false; + } + hit.GetCoordinates(x, y, z); + return isInTOFActiveArea(std::array{x, y, z}); + } + }; + + bool isInInnerTOFActiveArea(const o2::track::TrackParCov& track) + { + static TOFLayerEfficiency innerTOFLayer(simConfig.innerTOFRadius, simConfig.innerTOFLength, simConfig.innerTOFPixelDimension, simConfig.innerTOFFractionOfInactiveArea, simConfig.magneticField); + return innerTOFLayer.isTrackInActiveArea(track); + } + + bool isInOuterTOFActiveArea(const o2::track::TrackParCov& track) + { + static TOFLayerEfficiency outerTOFLayer(simConfig.outerTOFRadius, simConfig.outerTOFLength, simConfig.outerTOFPixelDimension, simConfig.outerTOFFractionOfInactiveArea, simConfig.magneticField); + return outerTOFLayer.isTrackInActiveArea(track); + } + + /// function to calculate track length of this track up to a certain radius + /// \param track the input track + /// \param radius the radius of the layer you're calculating the length to + /// \param magneticField the magnetic field to use when propagating + static float computeTrackLength(o2::track::TrackParCov track, float radius, float magneticField) + { + // don't make use of the track parametrization + float length = -100; + + o2::math_utils::CircleXYf_t trcCircle; + float sna, csa; + track.getCircleParams(magneticField, trcCircle, sna, csa); + + // distance between circle centers (one circle is at origin -> easy) + const float centerDistance = std::hypot(trcCircle.xC, trcCircle.yC); + + // condition of circles touching - if not satisfied returned length will be -100 + if (centerDistance < trcCircle.rC + radius && centerDistance > std::fabs(trcCircle.rC - radius)) { + length = 0.0f; + + // base radical direction + const float ux = trcCircle.xC / centerDistance; + const float uy = trcCircle.yC / centerDistance; + // calculate perpendicular vector (normalized) for +/- displacement + const float vx = -uy; + const float vy = +ux; + // calculate coordinate for radical line + const float radical = (centerDistance * centerDistance - trcCircle.rC * trcCircle.rC + radius * radius) / (2.0f * centerDistance); + // calculate absolute displacement from center-to-center axis + const float displace = (0.5f / centerDistance) * std::sqrt( + (-centerDistance + trcCircle.rC - radius) * + (-centerDistance - trcCircle.rC + radius) * + (-centerDistance + trcCircle.rC + radius) * + (centerDistance + trcCircle.rC + radius)); + + // possible intercept points of track and TOF layer in 2D plane + const float point1[2] = {radical * ux + displace * vx, radical * uy + displace * vy}; + const float point2[2] = {radical * ux - displace * vx, radical * uy - displace * vy}; + + // decide on correct intercept point + std::array mom; + track.getPxPyPzGlo(mom); + const float scalarProduct1 = point1[0] * mom[0] + point1[1] * mom[1]; + const float scalarProduct2 = point2[0] * mom[0] + point2[1] * mom[1]; + + // get start point + std::array startPoint; + track.getXYZGlo(startPoint); + + float cosAngle = -1000, modulus = -1000; + + if (scalarProduct1 > scalarProduct2) { + modulus = std::hypot(point1[0] - trcCircle.xC, point1[1] - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); + cosAngle = (point1[0] - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (point1[1] - trcCircle.yC) * (startPoint[1] - trcCircle.yC); + } else { + modulus = std::hypot(point2[0] - trcCircle.xC, point2[1] - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); + cosAngle = (point2[0] - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (point2[1] - trcCircle.yC) * (startPoint[1] - trcCircle.yC); + } + cosAngle /= modulus; + length = trcCircle.rC * std::acos(cosAngle); + length *= std::sqrt(1.0f + track.getTgl() * track.getTgl()); + } + return length; + } + + /// returns velocity in centimeters per picoseconds + /// \param momentum the momentum of the tarck + /// \param mass the mass of the particle + float computeParticleVelocity(float momentum, float mass) + { + const float a = momentum / mass; + // uses light speed in cm/ps so output is in those units + return o2::constants::physics::LightSpeedCm2PS * a / std::sqrt((1.f + a * a)); + } + + struct TracksWithTime { + TracksWithTime(int pdgCode, + std::pair innerTOFTime, + std::pair outerTOFTime, + std::pair trackLengthInnerTOF, + std::pair trackLengthOuterTOF, + std::pair momentum, + std::pair pseudorapidity, + float noSmearingPt) + : mPdgCode(pdgCode), + mInnerTOFTime(innerTOFTime), + mOuterTOFTime(outerTOFTime), + mTrackLengthInnerTOF(trackLengthInnerTOF), + mTrackLengthOuterTOF(trackLengthOuterTOF), + mMomentum(momentum), + mPseudorapidity{pseudorapidity}, + mNoSmearingPt{noSmearingPt} {} + + int mPdgCode; + std::pair mInnerTOFTime; // Measured time and expected resolution at the inner TOF [ps] + std::pair mOuterTOFTime; // Measured time and expected resolution at the outer TOF [ps] + std::pair mTrackLengthInnerTOF; // Measured and generated length at the innerTOF [cm] + std::pair mTrackLengthOuterTOF; // Measured and generated length at the outerTOF [cm] + std::pair mMomentum; // Measured momentum and uncertainty on the momentum [GeV/c] + std::pair mPseudorapidity; // Measured pseudorapidity and uncertainty on the pseudorapidity + float mNoSmearingPt; // No smearing pt + }; + + std::vector tracksWithTime; + bool eventTime(std::vector& tracks, + std::array& tzero) + { + + float sum = 0.; + float sumw = 0.; + + // Todo: check the different mass hypothesis iteratively + for (const auto& track : tracks) { + auto pdgInfo = pdg->GetParticle(track.mPdgCode); + if (pdgInfo == nullptr) { + continue; + } + const float mass = pdgInfo->Mass(); + const float mass2 = mass * mass; + const float tof = track.mInnerTOFTime.first; // [ps] + if (tof <= 0) { + continue; + } + const float etof = track.mInnerTOFTime.second; // [ps] + const float length = track.mTrackLengthInnerTOF.first; // [cm] + float p = track.mMomentum.first; // [GeV/c] + p *= std::abs(pdgInfo->Charge()) / 3.; // Total momentum + const float ep = track.mMomentum.second; // [GeV/c] + const float p2 = p * p; + const float lengthOverC = length * o2::constants::physics::invLightSpeedCm2PS; + const float texp = lengthOverC / p * std::sqrt(mass2 + p2); + // LOG(info) << "TOF: " << tof << " " << etof << " vs " << texp; + const float etexp = lengthOverC * mass2 / p2 / std::sqrt(mass2 + p2) * ep; + const float sigma = std::sqrt(etexp * etexp + etof * etof); + const float deltat = tof - texp; + + const float w = 1. / (sigma * sigma); + + sum += w * deltat; + sumw += w; + } + + static constexpr float kMaxEventTimeResolution = 200.f; + if (sumw <= 0. || tracks.size() <= 1 || std::sqrt(1. / sumw) > kMaxEventTimeResolution) { + tzero[0] = 0.; // [ps] + tzero[1] = kMaxEventTimeResolution; // [ps] + return false; + } + + tzero[0] = sum / sumw; + tzero[1] = std::sqrt(1. / sumw); + return true; + } + + /// returns track time resolution + /// \param pt the transverse momentum of the tarck + /// \param eta the pseudorapidity of the tarck + /// \param trackPtResolution the absolute resolution on pt + /// \param trackEtaResolution the absolute resolution on eta + /// \param mass the mass of the particle + /// \param detRadius the radius of the cylindrical layer + /// \param magneticField the magnetic field (along Z) + double calculateTrackTimeResolutionAdvanced(const float pt, + const float eta, + const float trackPtResolution, + const float trackEtaResolution, + const float mass, + const float detRadius, + const float magneticField) + { + // Compute tracking contribution to timing using the error propagation formula + // Uses light speed in m/ps, magnetic field in T (*0.1 for conversion kGauss -> T) + double a0 = mass * mass; + double a1 = 0.299792458 * (0.1 * magneticField) * (0.01 * o2::constants::physics::LightSpeedCm2NS / 1e+3); + double a2 = (detRadius * 0.01) * (detRadius * 0.01) * (0.299792458) * (0.299792458) * (0.1 * magneticField) * (0.1 * magneticField) / 2.0; + double dtofOndPt = (std::pow(pt, 4) * std::pow(std::cosh(eta), 2) * std::acos(1.0 - a2 / std::pow(pt, 2)) - 2.0 * a2 * std::pow(pt, 2) * (a0 + std::pow(pt * std::cosh(eta), 2)) / std::sqrt(a2 * (2.0 * std::pow(pt, 2) - a2))) / (a1 * std::pow(pt, 3) * std::sqrt(a0 + std::pow(pt * std::cosh(eta), 2))); + double dtofOndEta = std::pow(pt, 2) * std::sinh(eta) * std::cosh(eta) * std::acos(1.0 - a2 / std::pow(pt, 2)) / (a1 * std::sqrt(a0 + std::pow(pt * std::cosh(eta), 2))); + double trackTimeResolution = std::hypot(std::fabs(dtofOndPt) * trackPtResolution, std::fabs(dtofOndEta) * trackEtaResolution); + return trackTimeResolution; + } + + void process(soa::Join::iterator const& collision, + soa::Join const& tracks, + aod::McParticles const&, + aod::McCollisions const&) + { + o2::dataformats::VertexBase pvVtx({collision.posX(), collision.posY(), collision.posZ()}, + {collision.covXX(), collision.covXY(), collision.covYY(), + collision.covXZ(), collision.covYZ(), collision.covZZ()}); + + std::array mcPvCov = {0.}; + o2::dataformats::VertexBase mcPvVtx({0.0f, 0.0f, 0.0f}, mcPvCov); + const float eventCollisionTimePS = (simConfig.considerEventTime.value ? collision.collisionTime() * 1e3 : 0.f); // convert ns to ps + if (collision.has_mcCollision()) { + auto mcCollision = collision.mcCollision(); + mcPvVtx.setX(mcCollision.posX()); + mcPvVtx.setY(mcCollision.posY()); + mcPvVtx.setZ(mcCollision.posZ()); + } // else remains untreated for now + + // First we compute the number of charged particles in the event if LUTs are loaded + float dNdEta = 0.f; + for (const auto& track : tracks) { + if (!track.has_mcParticle()) + continue; + auto mcParticle = track.mcParticle(); + if (std::abs(mcParticle.eta()) > simConfig.multiplicityEtaRange) { + continue; + } + if (mcParticle.has_daughters()) { + continue; + } + const auto& pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); + if (!pdgInfo) { + // LOG(warning) << "PDG code " << mcParticle.pdgCode() << " not found in the database"; + continue; + } + if (pdgInfo->Charge() == 0) { + continue; + } + dNdEta += 1.f; + } + if (plotsConfig.doQAplots) { + histos.fill(HIST("h1dNdeta"), dNdEta); + } + + tracksWithTime.clear(); // clear the vector of tracks with time to prepare the cache for the next event + tracksWithTime.reserve(tracks.size()); + // First loop to generate the arrival time of the particles to the TOF layers + for (const auto& track : tracks) { + // first step: find precise arrival time (if any) + // --- convert track into perfect track + if (!track.has_mcParticle()) { // should always be OK but check please + upgradeTofMC(-999.f, -999.f, -999.f, -999.f); + continue; + } else { + LOG(debug) << "Track without mcParticle found!"; + } + const auto& mcParticle = track.mcParticle(); + o2::track::TrackParCov o2track = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdg); + + float xPv = -100.f; + static constexpr float kTrkXThreshold = -99.f; // Threshold to consider a good propagation of the track + if (o2track.propagateToDCA(mcPvVtx, simConfig.magneticField)) { + xPv = o2track.getX(); + } + float trackLengthInnerTOF = -1, trackLengthOuterTOF = -1; + if (xPv > kTrkXThreshold) { + trackLengthInnerTOF = computeTrackLength(o2track, simConfig.innerTOFRadius, simConfig.magneticField); + trackLengthOuterTOF = computeTrackLength(o2track, simConfig.outerTOFRadius, simConfig.magneticField); + } + + // Check if the track hit a sensitive area of the TOF + const bool activeInnerTOF = isInInnerTOFActiveArea(o2track); + if (!activeInnerTOF) { + trackLengthInnerTOF = -999.f; + } else { + float x = 0.f; + o2track.getXatLabR(simConfig.innerTOFRadius, x, simConfig.magneticField); + histos.fill(HIST("iTOF/h2HitMap"), o2track.getZAt(x, simConfig.magneticField), simConfig.innerTOFRadius * o2track.getPhiAt(x, simConfig.magneticField)); + } + + const bool activeOuterTOF = isInOuterTOFActiveArea(o2track); + if (!activeOuterTOF) { + trackLengthOuterTOF = -999.f; + } else { + float x = 0.f; + o2track.getXatLabR(simConfig.outerTOFRadius, x, simConfig.magneticField); + histos.fill(HIST("oTOF/h2HitMap"), o2track.getZAt(x, simConfig.magneticField), simConfig.outerTOFRadius * o2track.getPhiAt(x, simConfig.magneticField)); + } + + // get mass to calculate velocity + auto pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); + if (pdgInfo == nullptr) { + LOG(error) << "PDG code " << mcParticle.pdgCode() << " not found in the database"; + upgradeTofMC(-999.f, -999.f, -999.f, -999.f); + continue; + } + const float v = computeParticleVelocity(o2track.getP(), pdgInfo->Mass()); + const float expectedTimeInnerTOF = trackLengthInnerTOF > 0 ? trackLengthInnerTOF / v + eventCollisionTimePS : -999.f; // arrival time to the Inner TOF in ps + const float expectedTimeOuterTOF = trackLengthOuterTOF > 0 ? trackLengthOuterTOF / v + eventCollisionTimePS : -999.f; // arrival time to the Outer TOF in ps + upgradeTofMC(expectedTimeInnerTOF, trackLengthInnerTOF, expectedTimeOuterTOF, trackLengthOuterTOF); + + // Smear with expected resolutions + const float measuredTimeInnerTOF = pRandomNumberGenerator.Gaus(expectedTimeInnerTOF, simConfig.innerTOFTimeReso); + const float measuredTimeOuterTOF = pRandomNumberGenerator.Gaus(expectedTimeOuterTOF, simConfig.outerTOFTimeReso); + + // Now we calculate the expected arrival time following certain mass hypotheses + // and the (imperfect!) reconstructed track parametrizations + float trackLengthRecoInnerTOF = -1, trackLengthRecoOuterTOF = -1; + auto recoTrack = getTrackParCov(track); + xPv = -100.f; + if (recoTrack.propagateToDCA(pvVtx, simConfig.magneticField)) { + xPv = recoTrack.getX(); + } + if (xPv > kTrkXThreshold) { + trackLengthRecoInnerTOF = computeTrackLength(recoTrack, simConfig.innerTOFRadius, simConfig.magneticField); + trackLengthRecoOuterTOF = computeTrackLength(recoTrack, simConfig.outerTOFRadius, simConfig.magneticField); + } + + // cache the track info needed for the event time calculation + // Reuse or emplace a new object in the vector + tracksWithTime.emplace_back(TracksWithTime{mcParticle.pdgCode(), + {measuredTimeInnerTOF, simConfig.innerTOFTimeReso}, + {measuredTimeOuterTOF, simConfig.outerTOFTimeReso}, + {trackLengthRecoInnerTOF, trackLengthInnerTOF}, + {trackLengthRecoOuterTOF, trackLengthOuterTOF}, + {recoTrack.getP(), recoTrack.getSigma1Pt2()}, + {recoTrack.getEta(), recoTrack.getSigmaTgl2()}, + o2track.getPt()}); + } + + // Now we compute the event time for the tracks + + std::array tzero = {0.f, 0.f}; + bool etStatus = false; + if (simConfig.considerEventTime.value) { + etStatus = eventTime(tracksWithTime, tzero); + if (!etStatus) { + LOG(debug) << "Event time calculation failed with " << tracksWithTime.size() << " tracks with time and " << dNdEta << " charged particles"; + } + } + + if (plotsConfig.doQAplots) { + histos.fill(HIST("h2dEventTime"), tzero[0], eventCollisionTimePS); + histos.fill(HIST("h1dEventTimegen"), eventCollisionTimePS); + histos.fill(HIST("h1dEventTimerec"), tzero[0]); + histos.fill(HIST("h2dEventTimeres"), dNdEta, tzero[1]); + if (etStatus) { + histos.fill(HIST("h1dEventTimedelta"), eventCollisionTimePS - tzero[0]); + } + static_cast(listEfficiency->At(0))->Fill(etStatus, dNdEta); + } + + // Then we do a second loop to compute the measured quantities with the measured event time + int trackWithTimeIndex = 0; + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { // should always be OK but check please + continue; + } + const auto& mcParticle = track.mcParticle(); + + const auto& trkWithTime = tracksWithTime[trackWithTimeIndex++]; + const float trackLengthRecoInnerTOF = trkWithTime.mTrackLengthInnerTOF.first; + const float trackLengthRecoOuterTOF = trkWithTime.mTrackLengthOuterTOF.first; + const float trackLengthInnerTOF = trkWithTime.mTrackLengthInnerTOF.second; + const float trackLengthOuterTOF = trkWithTime.mTrackLengthOuterTOF.second; + // Todo: remove the bias of the track used in the event time calculation for low multiplicity events + const float measuredTimeInnerTOF = trkWithTime.mInnerTOFTime.first - tzero[0]; + const float measuredTimeOuterTOF = trkWithTime.mOuterTOFTime.first - tzero[0]; + const float momentum = trkWithTime.mMomentum.first; + const float pseudorapidity = trkWithTime.mPseudorapidity.first; + const float noSmearingPt = trkWithTime.mNoSmearingPt; + + // Straight to Nsigma + static std::array expectedTimeInnerTOF, expectedTimeOuterTOF; + static std::array deltaTimeInnerTOF, deltaTimeOuterTOF; + static std::array nSigmaInnerTOF, nSigmaOuterTOF; + static constexpr int kParticlePdgs[kParticles] = {kElectron, + kMuonMinus, + kPiPlus, + kKPlus, + kProton, + o2::constants::physics::kDeuteron, + o2::constants::physics::kTriton, + o2::constants::physics::kHelium3, + o2::constants::physics::kAlpha}; + static constexpr float kParticleMasses[kParticles] = {o2::constants::physics::MassElectron, + o2::constants::physics::MassMuon, + o2::constants::physics::MassPionCharged, + o2::constants::physics::MassKaonCharged, + o2::constants::physics::MassProton, + o2::constants::physics::MassDeuteron, + o2::constants::physics::MassTriton, + o2::constants::physics::MassHelium3, + o2::constants::physics::MassAlpha}; + static constexpr float kParticleCharges[kParticles] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 2.f, 2.f}; + float momentumHypotheses[kParticles]; // Store momentum hypothesis for each particle + + auto truePdgInfo = pdg->GetParticle(mcParticle.pdgCode()); + float rigidity = momentum; // fallback to momentum if charge unknown + + // Use MC truth charge for rigidity calculation + if (truePdgInfo) { + const float trueCharge = std::abs(truePdgInfo->Charge()) / 3.0f; + if (trueCharge > 0) { + rigidity = momentum / trueCharge; + } + } + + if (plotsConfig.doQAplots) { + // unit conversion: length in cm, time in ps + const float innerBeta = (trackLengthInnerTOF / measuredTimeInnerTOF) / o2::constants::physics::LightSpeedCm2PS; + const float outerBeta = (trackLengthOuterTOF / measuredTimeOuterTOF) / o2::constants::physics::LightSpeedCm2PS; + if (trackLengthRecoInnerTOF > 0) { + histos.fill(HIST("iTOF/h2dVelocityVsMomentumInner"), momentum, innerBeta); + histos.fill(HIST("iTOF/h2dVelocityVsRigidityInner"), rigidity, innerBeta); + histos.fill(HIST("iTOF/h2dTrackLengthInnerVsPt"), noSmearingPt, trackLengthInnerTOF); + histos.fill(HIST("iTOF/h2dTrackLengthInnerRecoVsPt"), noSmearingPt, trackLengthRecoInnerTOF); + } + if (trackLengthRecoOuterTOF > 0) { + histos.fill(HIST("oTOF/h2dVelocityVsMomentumOuter"), momentum, outerBeta); + histos.fill(HIST("oTOF/h2dVelocityVsRigidityOuter"), rigidity, outerBeta); + histos.fill(HIST("oTOF/h2dTrackLengthOuterVsPt"), noSmearingPt, trackLengthOuterTOF); + histos.fill(HIST("oTOF/h2dTrackLengthOuterRecoVsPt"), noSmearingPt, trackLengthRecoOuterTOF); + } + } + + // For every mass hypothesis compute the expected time, the delta with respect to it and the nsigma + for (int ii = 0; ii < kParticles; ii++) { + expectedTimeInnerTOF[ii] = -100; + expectedTimeOuterTOF[ii] = -100; + deltaTimeInnerTOF[ii] = -100; + deltaTimeOuterTOF[ii] = -100; + nSigmaInnerTOF[ii] = -100; + nSigmaOuterTOF[ii] = -100; + + momentumHypotheses[ii] = rigidity * kParticleCharges[ii]; // Total momentum for this hypothesis + const float v = computeParticleVelocity(momentumHypotheses[ii], kParticleMasses[ii]); + + expectedTimeInnerTOF[ii] = trackLengthInnerTOF / v; + expectedTimeOuterTOF[ii] = trackLengthOuterTOF / v; + + deltaTimeInnerTOF[ii] = measuredTimeInnerTOF - expectedTimeInnerTOF[ii]; + deltaTimeOuterTOF[ii] = measuredTimeOuterTOF - expectedTimeOuterTOF[ii]; + + // Evaluate total sigma (layer + tracking resolution) + float innerTotalTimeReso = simConfig.innerTOFTimeReso; + float outerTotalTimeReso = simConfig.outerTOFTimeReso; + if (simConfig.flagIncludeTrackTimeRes) { + const float transverseMomentum = momentumHypotheses[ii] / std::cosh(pseudorapidity); + double ptResolution = transverseMomentum * transverseMomentum * std::sqrt(trkWithTime.mMomentum.second); + double etaResolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-pseudorapidity)))) * std::sqrt(trkWithTime.mPseudorapidity.second); + if (simConfig.flagTOFLoadDelphesLUTs) { + if (mSmearer.hasTable(kParticlePdgs[ii])) { // Only if the LUT for this particle was loaded + ptResolution = mSmearer.getAbsPtRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); + etaResolution = mSmearer.getAbsEtaRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); + } + } + const float innerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, kParticleMasses[ii], simConfig.innerTOFRadius, simConfig.magneticField); + const float outerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, kParticleMasses[ii], simConfig.outerTOFRadius, simConfig.magneticField); + innerTotalTimeReso = std::hypot(simConfig.innerTOFTimeReso, innerTrackTimeReso); + outerTotalTimeReso = std::hypot(simConfig.outerTOFTimeReso, outerTrackTimeReso); + + if (plotsConfig.doQAplots) { + if (std::fabs(mcParticle.pdgCode()) == kParticlePdgs[ii]) { + if (trackLengthRecoInnerTOF > 0) { + h2dInnerTimeResTrack[ii]->Fill(momentumHypotheses[ii], innerTrackTimeReso); + h2dInnerTimeResTotal[ii]->Fill(momentumHypotheses[ii], innerTotalTimeReso); + } + if (trackLengthRecoOuterTOF > 0) { + h2dOuterTimeResTrack[ii]->Fill(momentumHypotheses[ii], outerTrackTimeReso); + h2dOuterTimeResTotal[ii]->Fill(momentumHypotheses[ii], outerTotalTimeReso); + static constexpr int kIdPion = 2; + if (ii == kIdPion) { + histos.fill(HIST("h2dRelativePtResolution"), transverseMomentum, 100.0 * ptResolution / transverseMomentum); + histos.fill(HIST("h2dRelativeEtaResolution"), pseudorapidity, 100.0 * etaResolution / (std::fabs(pseudorapidity) + 1e-6)); + } + } + } + } + } + + // Fixme: assumes dominant resolution effect is the TOF resolution + // and not the tracking itself. It's *probably* a fair assumption + // but it should be tested further! --> FIXED IN THIS VERSION + if (trackLengthInnerTOF > 0 && trackLengthRecoInnerTOF > 0) + nSigmaInnerTOF[ii] = deltaTimeInnerTOF[ii] / std::sqrt(innerTotalTimeReso * innerTotalTimeReso + tzero[1] * tzero[1]); + if (trackLengthOuterTOF > 0 && trackLengthRecoOuterTOF > 0) + nSigmaOuterTOF[ii] = deltaTimeOuterTOF[ii] / std::sqrt(outerTotalTimeReso * outerTotalTimeReso + tzero[1] * tzero[1]); + } + + if (plotsConfig.doQAplots) { + for (int ii = 0; ii < kParticles; ii++) { + if (std::fabs(mcParticle.pdgCode()) != pdg->GetParticle(kParticlePdgs[ii])->PdgCode()) { + continue; + } + if (trackLengthRecoInnerTOF > 0) { + for (int iii = 0; iii < kParticles; iii++) { + h2dInnerNsigmaTrue[ii][iii]->Fill(momentumHypotheses[ii], nSigmaInnerTOF[iii]); + h2dInnerDeltaTrue[ii][iii]->Fill(momentumHypotheses[ii], deltaTimeInnerTOF[iii]); + } + } + if (trackLengthRecoOuterTOF > 0) { + for (int iii = 0; iii < kParticles; iii++) { + h2dOuterNsigmaTrue[ii][iii]->Fill(momentumHypotheses[ii], nSigmaOuterTOF[iii]); + h2dOuterDeltaTrue[ii][iii]->Fill(momentumHypotheses[ii], deltaTimeOuterTOF[iii]); + } + } + } + } + + const float deltaTrackLengthInnerTOF = std::abs(trackLengthInnerTOF - trackLengthRecoInnerTOF); + if (trackLengthInnerTOF > 0 && trackLengthRecoInnerTOF > 0) { + histos.fill(HIST("iTOF/h2dDeltaTrackLengthInnerVsPt"), noSmearingPt, deltaTrackLengthInnerTOF); + } + const float deltaTrackLengthOuterTOF = std::abs(trackLengthOuterTOF - trackLengthRecoOuterTOF); + if (trackLengthOuterTOF > 0 && trackLengthRecoOuterTOF > 0) { + histos.fill(HIST("oTOF/h2dDeltaTrackLengthOuterVsPt"), noSmearingPt, deltaTrackLengthOuterTOF); + } + + // Sigmas have been fully calculated. Please populate the NSigma helper table (once per track) + upgradeTof(tzero[0], tzero[1], + nSigmaInnerTOF[0], nSigmaInnerTOF[1], nSigmaInnerTOF[2], nSigmaInnerTOF[3], nSigmaInnerTOF[4], nSigmaInnerTOF[5], nSigmaInnerTOF[6], nSigmaInnerTOF[7], nSigmaInnerTOF[8], + measuredTimeInnerTOF, trackLengthRecoInnerTOF, + nSigmaOuterTOF[0], nSigmaOuterTOF[1], nSigmaOuterTOF[2], nSigmaOuterTOF[3], nSigmaOuterTOF[4], nSigmaOuterTOF[5], nSigmaOuterTOF[6], nSigmaOuterTOF[7], nSigmaOuterTOF[8], + measuredTimeOuterTOF, trackLengthRecoOuterTOF); + upgradeTofExpectedTime(expectedTimeInnerTOF[0], expectedTimeInnerTOF[1], expectedTimeInnerTOF[2], expectedTimeInnerTOF[3], expectedTimeInnerTOF[4], expectedTimeInnerTOF[5], expectedTimeInnerTOF[6], expectedTimeInnerTOF[7], expectedTimeInnerTOF[8], + expectedTimeOuterTOF[0], expectedTimeOuterTOF[1], expectedTimeOuterTOF[2], expectedTimeOuterTOF[3], expectedTimeOuterTOF[4], expectedTimeOuterTOF[5], expectedTimeOuterTOF[6], expectedTimeOuterTOF[7], expectedTimeOuterTOF[8]); + } + + if (trackWithTimeIndex != tracks.size()) { + LOG(fatal) << "Track with time index " << trackWithTimeIndex << " does not match the number of tracks " << tracks.size(); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index a73fabdbc80..c3c64b39665 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -23,107 +23,180 @@ /// \author Roberto Preghenella preghenella@bo.infn.it /// -#include +#include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include "ALICE3/Core/DetLayer.h" +#include "ALICE3/Core/FastTracker.h" +#include "ALICE3/Core/TrackUtilities.h" +#include "ALICE3/DataModel/OTFStrangeness.h" +#include "ALICE3/DataModel/OTFTracks.h" +#include "ALICE3/DataModel/collisionAlice3.h" +#include "ALICE3/DataModel/tracksAlice3.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 "Framework/O2DatabasePDGPlugin.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "ReconstructionDataFormats/DCA.h" -#include "DetectorsBase/Propagator.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DetectorsVertexing/PVertexer.h" -#include "DetectorsVertexing/PVertexerHelpers.h" -#include "SimulationDataFormat/InteractionSampler.h" -#include "Field/MagneticField.h" +#include -#include "ALICE3/Core/DelphesO2TrackSmearer.h" -#include "ALICE3/DataModel/collisionAlice3.h" -#include "ALICE3/DataModel/tracksAlice3.h" -#include "ALICE3/DataModel/OTFMcTrackExtra.h" +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; +using std::array; +#define getHist(type, name) std::get>(histPointers[name]) struct OnTheFlyTracker { - Produces collisions; - Produces collLabels; - Produces tracksPar; - Produces tracksParExtension; - Produces tracksParCov; - Produces tracksParCovExtension; - Produces tracksLabels; - Produces tracksDCA; - Produces tracksDCACov; - Produces collisionsAlice3; - Produces TracksAlice3; - Produces OTFMcExtra; + Produces tableCollisions; + Produces tableMcCollisionLabels; + Produces tableStoredTracks; + Produces tableTracksExtension; + Produces tableStoredTracksCov; + Produces tableTracksCovExtension; + Produces tableMcTrackLabels; + Produces tableTracksDCA; + Produces tableTracksDCACov; + Produces tableCollisionsAlice3; + Produces tableTracksAlice3; + Produces tableTracksExtraA3; + Produces tableUpgradeCascades; + Produces tableOTFLUTConfigId; + Produces tableUpgradeV0s; // optionally produced, empty (to be tuned later) - Produces tracksExtra; // base table, extend later - Produces trackSelection; - Produces trackSelectionExtension; + Produces tableStoredTracksExtra; // base table, extend later + Produces tableTrackSelection; + Produces tableTrackSelectionExtension; 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 treatXi{"treatXi", false, "Manually decay Xi^{-} and fill tables with daughters"}; Configurable populateTracksDCA{"populateTracksDCA", true, "populate TracksDCA table"}; Configurable populateTracksDCACov{"populateTracksDCACov", false, "populate TracksDCACov table"}; - Configurable populateTracksExtra{"populateTracksExtra", false, "populate TracksExtra table (legacy)"}; + 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"}; Configurable doExtraQA{"doExtraQA", false, "do extra 2D QA plots"}; Configurable extraQAwithoutDecayDaughters{"extraQAwithoutDecayDaughters", false, "remove decay daughters from qa plots (yes/no)"}; - Configurable lutEl{"lutEl", "lutCovm.el.dat", "LUT for electrons"}; - Configurable lutMu{"lutMu", "lutCovm.mu.dat", "LUT for muons"}; - Configurable lutPi{"lutPi", "lutCovm.pi.dat", "LUT for pions"}; - Configurable lutKa{"lutKa", "lutCovm.ka.dat", "LUT for kaons"}; - Configurable lutPr{"lutPr", "lutCovm.pr.dat", "LUT for protons"}; - Configurable lutDe{"lutDe", "lutCovm.de.dat", "LUT for deuterons"}; - Configurable lutTr{"lutTr", "lutCovm.tr.dat", "LUT for tritons"}; - Configurable lutHe3{"lutHe3", "lutCovm.he3.dat", "LUT for Helium-3"}; - - Configurable lutPi0{"lutPi0", "lutCovm.pi.20kG.rmin20.geometry_v0.dat", "LUT for pions without layer 0"}; - Configurable lutPi1{"lutPi1", "lutCovm.pi.20kG.rmin20.geometry_v1.dat", "LUT for pions without layer 1"}; - Configurable lutPi2{"lutPi2", "lutCovm.pi.20kG.rmin20.geometry_v2.dat", "LUT for pions without layer 2"}; - Configurable lutPi3{"lutPi3", "lutCovm.pi.20kG.rmin20.geometry_v3.dat", "LUT for pions without layer 3"}; - Configurable lutPi4{"lutPi4", "lutCovm.pi.20kG.rmin20.geometry_v4.dat", "LUT for pions without layer 4"}; - Configurable lutPi5{"lutPi5", "lutCovm.pi.20kG.rmin20.geometry_v5.dat", "LUT for pions without layer 5"}; - Configurable lutPr0{"lutPr0", "lutCovm.pr.20kG.rmin20.geometry_v0.dat", "LUT for protons without layer 0"}; - Configurable lutPr1{"lutPr1", "lutCovm.pr.20kG.rmin20.geometry_v1.dat", "LUT for protons without layer 1"}; - Configurable lutPr2{"lutPr2", "lutCovm.pr.20kG.rmin20.geometry_v2.dat", "LUT for protons without layer 2"}; - Configurable lutPr3{"lutPr3", "lutCovm.pr.20kG.rmin20.geometry_v3.dat", "LUT for protons without layer 3"}; - Configurable lutPr4{"lutPr4", "lutCovm.pr.20kG.rmin20.geometry_v4.dat", "LUT for protons without layer 4"}; - Configurable lutPr5{"lutPr5", "lutCovm.pr.20kG.rmin20.geometry_v5.dat", "LUT for protons without layer 5"}; - - 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 axisRadius{"axisRadius", {55, 0.01, 100}, "decay radius"}; + struct : ConfigurableGroup { + std::string prefix = "lookUpTables"; // JSON group name + Configurable> lutEl{"lutEl", std::vector{"lutCovm.el.dat "}, "LUT for electrons (if emtpy no LUT is taken)"}; + Configurable> lutMu{"lutMu", std::vector{"lutCovm.mu.dat "}, "LUT for muons (if emtpy no LUT is taken)"}; + Configurable> lutPi{"lutPi", std::vector{"lutCovm.pi.dat "}, "LUT for pions (if emtpy no LUT is taken)"}; + Configurable> lutKa{"lutKa", std::vector{"lutCovm.ka.dat "}, "LUT for kaons (if emtpy no LUT is taken)"}; + Configurable> lutPr{"lutPr", std::vector{"lutCovm.pr.dat "}, "LUT for protons (if emtpy no LUT is taken)"}; + Configurable> lutDe{"lutDe", std::vector{" "}, "LUT for deuterons (if emtpy no LUT is taken)"}; + Configurable> lutTr{"lutTr", std::vector{" "}, "LUT for tritons (if emtpy no LUT is taken)"}; + Configurable> lutHe3{"lutHe3", std::vector{" "}, "LUT for Helium-3 (if emtpy no LUT is taken)"}; + Configurable> lutAl{"lutAl", std::vector{" "}, "LUT for Alphas (if emtpy no LUT is taken)"}; + } lookUpTables; + + 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 axisK0Mass{"axisK0Mass", {200, 0.4f, 0.6f}, ""}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, ""}; + ConfigurableAxis axisXiMass{"axisXiMass", {200, 1.22f, 1.42f}, ""}; + + ConfigurableAxis axisPtRes{"axisPtRes", {200, -0.4f, 0.4f}, "#Delta p_{T} / Reco p_{T}"}; + 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> alice3geo{"alice3geo", std::vector{"2"}, "0: ALICE 3 v1, 1: ALICE 3 v4, 2: ALICE 3 Sep 2025, or path to ccdb with a3 geo (ccdb:Users/u/user/)"}; + 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 scaleVD{"scaleVD", 1, "scale x0 and xrho in VD layers"}; + 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 = "fastPrimaryTrackerSettings"; + Configurable fastTrackPrimaries{"fastTrackPrimaries", false, "Use fasttracker for primary tracks. Enable with care"}; + Configurable minSiliconHits{"minSiliconHits", 4, "minimum number of silicon hits to accept track"}; + Configurable alice3geo{"alice3geo", "2", "0: ALICE 3 v1, 1: ALICE 3 v4, 2: ALICE 3 Sep 2025, or path to ccdb with a3 geo"}; + 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"}; + } fastPrimaryTrackerSettings; + + 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; + + struct : ConfigurableGroup { + std::string prefix = "v0DecaySettings"; // Cascade decay settings + Configurable decayV0{"decayV0", false, "Manually decay V0 and fill tables with daughters"}; + Configurable findV0{"findV0", false, "if decayV0 on, find V0 and fill Tracks table also with Xi"}; + Configurable doV0QA{"doV0QA", false, "QA plots for when treating V0"}; + } v0DecaySettings; using PVertex = o2::dataformats::PrimaryVertex; + // for secondary vertex finding + o2::vertexing::DCAFitterN<2> fitter; + + // FastTracker machinery + // o2::fastsim::FastTracker fastTracker; + std::vector> fastTracker; + o2::fastsim::FastTracker fastPrimaryTracker; + + // V0 names for filling histograms + static constexpr std::string_view kV0names[] = {"K0", "Lambda", "AntiLambda"}; + // Class to hold the track information for the O2 vertexing class TrackAlice3 : public o2::track::TrackParCov { @@ -133,229 +206,311 @@ 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; + + // Helper struct to pass V0 information + struct v0candidate { + int positiveId; // track index in the Tracks table + int negativeId; // track index in the Tracks table + + float pt; + + float dcaV0dau; + float v0radius; + + float mLambda; + float mAntiLambda; + float mK0; + }; + v0candidate thisV0; + // Constants + static constexpr int kv0Prongs = 2; + static constexpr std::array v0PDGs = {kK0Short, + kLambda0, + kLambda0Bar}; + // necessary for particle charges Service pdgDB; // for handling basic QA histograms if requested HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::map histPointers; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // Track smearer - o2::delphes::DelphesO2TrackSmearer mSmearer; - - // Xi daughters uses different smearers - o2::delphes::DelphesO2TrackSmearer mSmearer0; - o2::delphes::DelphesO2TrackSmearer mSmearer1; - o2::delphes::DelphesO2TrackSmearer mSmearer2; - o2::delphes::DelphesO2TrackSmearer mSmearer3; - o2::delphes::DelphesO2TrackSmearer mSmearer4; - o2::delphes::DelphesO2TrackSmearer mSmearer5; + std::vector> mSmearer; // For processing and vertexing std::vector tracksAlice3; std::vector ghostTracksAlice3; - std::vector trackPdg; - std::vector trackIsFromXi; - std::vector trackIsFromL0; - std::vector ghostTrackPdg; - std::vector ghostTrackIsFromXi; - std::vector ghostTrackIsFromL0; std::vector bcData; o2::steer::InteractionSampler irSampler; o2::vertexing::PVertexer vertexer; + std::vector cascadesAlice3; + std::vector v0sAlice3; + + // For TGenPhaseSpace seed + TRandom3 rand; + Service ccdb; + static constexpr int kMaxLUTConfigs = 20; void init(o2::framework::InitContext&) { - if (enableLUT) { - std::map mapPdgLut; - const char* lutElChar = lutEl->c_str(); - const char* lutMuChar = lutMu->c_str(); - const char* lutPiChar = lutPi->c_str(); - const char* lutKaChar = lutKa->c_str(); - const char* lutPrChar = lutPr->c_str(); - - LOGF(info, "Will load electron lut file ..: %s", lutElChar); - LOGF(info, "Will load muon lut file ......: %s", lutMuChar); - LOGF(info, "Will load pion lut file ......: %s", lutPiChar); - LOGF(info, "Will load kaon lut file ......: %s", lutKaChar); - LOGF(info, "Will load proton lut file ....: %s", lutPrChar); - - mapPdgLut.insert(std::make_pair(11, lutElChar)); - mapPdgLut.insert(std::make_pair(13, lutMuChar)); - mapPdgLut.insert(std::make_pair(211, lutPiChar)); - mapPdgLut.insert(std::make_pair(321, lutKaChar)); - mapPdgLut.insert(std::make_pair(2212, lutPrChar)); - - if (enableNucleiSmearing) { - const char* lutDeChar = lutDe->c_str(); - const char* lutTrChar = lutTr->c_str(); - const char* lutHe3Char = lutHe3->c_str(); - mapPdgLut.insert(std::make_pair(1000010020, lutDeChar)); - mapPdgLut.insert(std::make_pair(1000010030, lutTrChar)); - mapPdgLut.insert(std::make_pair(1000020030, lutHe3Char)); - } - for (auto e : mapPdgLut) { - if (!mSmearer.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setTimestamp(-1); + + if (enablePrimarySmearing) { + auto loadLUT = [&](int icfg, int pdg, const std::vector& tables) { + LOG(info) << "Loading LUT for pdg " << pdg << " for config " << icfg << " from provided tables with size " << tables.size(); + if (tables.empty()) { + LOG(debug) << "No LUT file passed for pdg " << pdg << ", skipping."; + return false; } - } - // interpolate efficiencies if requested to do so - mSmearer.interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); - - // smear un-reco'ed tracks if asked to do so - mSmearer.skipUnreconstructed(static_cast(!processUnreconstructedTracks)); - - if (treatXi) { - std::map mapPdgLut0; - const char* lutPiChar0 = lutPi0->c_str(); - const char* lutPrChar0 = lutPr0->c_str(); - LOGF(info, "Load more pion lut files .....: %s", lutPiChar0); - LOGF(info, "Load more proton lut files ...: %s", lutPrChar0); - mapPdgLut0.insert(std::make_pair(211, lutPiChar0)); - mapPdgLut0.insert(std::make_pair(2212, lutPrChar0)); - - std::map mapPdgLut1; - const char* lutPiChar1 = lutPi1->c_str(); - const char* lutPrChar1 = lutPr1->c_str(); - LOGF(info, "Load more pion lut files .....: %s", lutPiChar1); - LOGF(info, "Load more proton lut files ...: %s", lutPrChar1); - mapPdgLut1.insert(std::make_pair(211, lutPiChar1)); - mapPdgLut1.insert(std::make_pair(2212, lutPrChar1)); - - std::map mapPdgLut2; - const char* lutPiChar2 = lutPi2->c_str(); - const char* lutPrChar2 = lutPr2->c_str(); - LOGF(info, "Load more pion lut files .....: %s", lutPiChar2); - LOGF(info, "Load more proton lut files ...: %s", lutPrChar2); - mapPdgLut2.insert(std::make_pair(211, lutPiChar2)); - mapPdgLut2.insert(std::make_pair(2212, lutPrChar2)); - - std::map mapPdgLut3; - const char* lutPiChar3 = lutPi3->c_str(); - const char* lutPrChar3 = lutPr3->c_str(); - LOGF(info, "Load more pion lut files .....: %s", lutPiChar3); - LOGF(info, "Load more proton lut files ...: %s", lutPrChar3); - mapPdgLut3.insert(std::make_pair(211, lutPiChar3)); - mapPdgLut3.insert(std::make_pair(2212, lutPrChar3)); - - std::map mapPdgLut4; - const char* lutPiChar4 = lutPi4->c_str(); - const char* lutPrChar4 = lutPr4->c_str(); - LOGF(info, "Load more pion lut files .....: %s", lutPiChar4); - LOGF(info, "Load more proton lut files ...: %s", lutPrChar4); - mapPdgLut4.insert(std::make_pair(211, lutPiChar4)); - mapPdgLut4.insert(std::make_pair(2212, lutPrChar4)); - - std::map mapPdgLut5; - const char* lutPiChar5 = lutPi5->c_str(); - const char* lutPrChar5 = lutPr5->c_str(); - LOGF(info, "Load more pion lut files .....: %s", lutPiChar5); - LOGF(info, "Load more proton lut files ...: %s", lutPrChar5); - mapPdgLut5.insert(std::make_pair(211, lutPiChar5)); - mapPdgLut5.insert(std::make_pair(2212, lutPrChar5)); - - for (auto e : mapPdgLut0) { - if (!mSmearer0.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; - } + const bool foundNewCfg = static_cast(icfg) < tables.size(); + std::string lutFile = foundNewCfg ? tables[icfg] : tables.front(); + LOG(info) << "Loading LUT for pdg " << pdg << " from file " << lutFile << " for config " << icfg; + // strip from leading/trailing spaces + lutFile.erase(0, lutFile.find_first_not_of(" ")); + lutFile.erase(lutFile.find_last_not_of(" ") + 1); + if (lutFile.empty()) { + LOG(debug) << "Empty LUT file name for pdg " << pdg << ", skipping."; + return false; } - for (auto e : mapPdgLut1) { - if (!mSmearer1.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; - } - } - for (auto e : mapPdgLut2) { - if (!mSmearer2.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; - } - } - for (auto e : mapPdgLut3) { - if (!mSmearer3.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; - } - } - for (auto e : mapPdgLut4) { - if (!mSmearer4.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; - } + bool success = mSmearer[icfg]->loadTable(pdg, lutFile.c_str()); + if (!success) { + LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << lutFile; } - for (auto e : mapPdgLut5) { - if (!mSmearer5.loadTable(e.first, e.second)) { - LOG(fatal) << "Having issue with loading the LUT " << e.first << " " << e.second; - } + + return foundNewCfg; + }; + + for (int icfg = 0; icfg < kMaxLUTConfigs; ++icfg) { + mSmearer.emplace_back(std::make_unique()); + mSmearer[icfg]->setCcdbManager(ccdb.operator->()); + + // check if more configs were provided, fall back to first entry + bool newLUTLoaded = false; + newLUTLoaded |= loadLUT(icfg, kElectron, lookUpTables.lutEl.value); + newLUTLoaded |= loadLUT(icfg, kMuonMinus, lookUpTables.lutMu.value); + newLUTLoaded |= loadLUT(icfg, kPiPlus, lookUpTables.lutPi.value); + newLUTLoaded |= loadLUT(icfg, kKPlus, lookUpTables.lutKa.value); + newLUTLoaded |= loadLUT(icfg, kProton, lookUpTables.lutPr.value); + newLUTLoaded |= loadLUT(icfg, o2::constants::physics::kDeuteron, lookUpTables.lutDe.value); + newLUTLoaded |= loadLUT(icfg, o2::constants::physics::kTriton, lookUpTables.lutTr.value); + newLUTLoaded |= loadLUT(icfg, o2::constants::physics::kHelium3, lookUpTables.lutHe3.value); + newLUTLoaded |= loadLUT(icfg, o2::constants::physics::kAlpha, lookUpTables.lutAl.value); + + if (!newLUTLoaded) { + mSmearer.pop_back(); + break; } // interpolate efficiencies if requested to do so - mSmearer0.interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); - mSmearer1.interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); - mSmearer2.interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); - mSmearer3.interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); - mSmearer4.interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); - mSmearer5.interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); + mSmearer[icfg]->interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); // smear un-reco'ed tracks if asked to do so - mSmearer0.skipUnreconstructed(static_cast(!processUnreconstructedTracks)); - mSmearer1.skipUnreconstructed(static_cast(!processUnreconstructedTracks)); - mSmearer2.skipUnreconstructed(static_cast(!processUnreconstructedTracks)); - mSmearer3.skipUnreconstructed(static_cast(!processUnreconstructedTracks)); - mSmearer4.skipUnreconstructed(static_cast(!processUnreconstructedTracks)); - mSmearer5.skipUnreconstructed(static_cast(!processUnreconstructedTracks)); - } + mSmearer[icfg]->skipUnreconstructed(static_cast(!processUnreconstructedTracks)); + + std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; + histPointers.insert({histPath + "hPtGenerated", histos.add((histPath + "hPtGenerated").c_str(), "hPtGenerated", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPhiGenerated", histos.add((histPath + "hPhiGenerated").c_str(), "hPhiGenerated", {kTH1D, {{100, 0.0f, 2 * M_PI, "#phi (rad)"}}})}); + + histPointers.insert({histPath + "hPtGeneratedEl", histos.add((histPath + "hPtGeneratedEl").c_str(), "hPtGeneratedEl", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtGeneratedPi", histos.add((histPath + "hPtGeneratedPi").c_str(), "hPtGeneratedPi", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtGeneratedKa", histos.add((histPath + "hPtGeneratedKa").c_str(), "hPtGeneratedKa", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtGeneratedPr", histos.add((histPath + "hPtGeneratedPr").c_str(), "hPtGeneratedPr", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructed", histos.add((histPath + "hPtReconstructed").c_str(), "hPtReconstructed", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructedEl", histos.add((histPath + "hPtReconstructedEl").c_str(), "hPtReconstructedEl", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructedPi", histos.add((histPath + "hPtReconstructedPi").c_str(), "hPtReconstructedPi", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructedKa", histos.add((histPath + "hPtReconstructedKa").c_str(), "hPtReconstructedKa", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructedPr", histos.add((histPath + "hPtReconstructedPr").c_str(), "hPtReconstructedPr", {kTH1D, {{axes.axisMomentum}}})}); + + // Collision QA + histPointers.insert({histPath + "hPVz", histos.add((histPath + "hPVz").c_str(), "hPVz", {kTH1D, {{axes.axisVertexZ}}})}); + histPointers.insert({histPath + "hLUTMultiplicity", histos.add((histPath + "hLUTMultiplicity").c_str(), "hLUTMultiplicity", {kTH1D, {{axes.axisMultiplicity}}})}); + histPointers.insert({histPath + "hSimMultiplicity", histos.add((histPath + "hSimMultiplicity").c_str(), "hSimMultiplicity", {kTH1D, {{axes.axisMultiplicity}}})}); + histPointers.insert({histPath + "hRecoMultiplicity", histos.add((histPath + "hRecoMultiplicity").c_str(), "hRecoMultiplicity", {kTH1D, {{axes.axisMultiplicity}}})}); + + if (enableSecondarySmearing) { + fastTracker.emplace_back(std::make_unique()); + fastTracker[icfg]->SetMagneticField(magneticField); + fastTracker[icfg]->SetApplyZacceptance(fastTrackerSettings.applyZacceptance); + fastTracker[icfg]->SetApplyMSCorrection(fastTrackerSettings.applyMSCorrection); + fastTracker[icfg]->SetApplyElossCorrection(fastTrackerSettings.applyElossCorrection); + + if (fastTrackerSettings.alice3geo.value[icfg] == "0") { + fastTracker[icfg]->AddSiliconALICE3v2(fastTrackerSettings.pixelRes); + } else if (fastTrackerSettings.alice3geo.value[icfg] == "1") { + fastTracker[icfg]->AddSiliconALICE3v4(fastTrackerSettings.pixelRes); + fastTracker[icfg]->AddTPC(0.1, 0.1); + } else if (fastTrackerSettings.alice3geo.value[icfg] == "2") { + fastTracker[icfg]->AddSiliconALICE3(fastTrackerSettings.scaleVD, fastTrackerSettings.pixelRes); + } else { + fastTracker[icfg]->AddGenericDetector(fastTrackerSettings.alice3geo.value[icfg], ccdb.operator->()); + } + + // print fastTracker settings + fastTracker[icfg]->Print(); + histPointers.insert({histPath + "hMassXi", histos.add((histPath + "hMassXi").c_str(), "hMassXi", {kTH1D, {{axes.axisXiMass}}})}); + } + + if (doExtraQA) { + histPointers.insert({histPath + "h2dPtRes", histos.add((histPath + "h2dPtRes").c_str(), "h2dPtRes", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}})}); + histPointers.insert({histPath + "h2dDCAxy", histos.add((histPath + "h2dDCAxy").c_str(), "h2dDCAxy", {kTH2D, {{axes.axisMomentum, axes.axisDCA}}})}); + histPointers.insert({histPath + "h2dDCAz", histos.add((histPath + "h2dDCAz").c_str(), "h2dDCAz", {kTH2D, {{axes.axisMomentum, axes.axisDCA}}})}); + } + + } // end config loop } // 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}); - - // 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}); + 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"); 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("hSimTrackX", "hSimTrackX", kTH1F, {axisX}); - histos.add("hRecoTrackX", "hRecoTrackX", kTH1F, {axisX}); - histos.add("hTrackXatDCA", "hTrackXatDCA", kTH1F, {axisX}); + histos.add("hSimTrackX", "hSimTrackX", kTH1F, {axes.axisX}); + histos.add("hRecoTrackX", "hRecoTrackX", kTH1F, {axes.axisX}); + histos.add("hTrackXatDCA", "hTrackXatDCA", kTH1F, {axes.axisX}); } - if (treatXi) { - histos.add("hGenXi", "hGenXi", kTH2F, {axisRadius, axisMomentum}); - histos.add("hRecoXi", "hRecoXi", kTH2F, {axisRadius, axisMomentum}); - - histos.add("hGenPiFromXi", "hGenPiFromXi", kTH2F, {axisRadius, axisMomentum}); - histos.add("hGenPiFromL0", "hGenPiFromL0", kTH2F, {axisRadius, axisMomentum}); - histos.add("hGenPrFromL0", "hGenPrFromL0", kTH2F, {axisRadius, axisMomentum}); - histos.add("hRecoPiFromXi", "hRecoPiFromXi", kTH2F, {axisRadius, axisMomentum}); - histos.add("hRecoPiFromL0", "hRecoPiFromL0", kTH2F, {axisRadius, axisMomentum}); - histos.add("hRecoPrFromL0", "hRecoPrFromL0", kTH2F, {axisRadius, axisMomentum}); - - histos.add("hPiFromXiDCAxy", "hPiFromXiDCAxy", kTH1F, {axisDCA}); - histos.add("hPiFromL0DCAxy", "hPiFromL0DCAxy", kTH1F, {axisDCA}); - histos.add("hPrFromL0DCAxy", "hPrFromL0DCAxy", kTH1F, {axisDCA}); - histos.add("hPiFromXiDCAxyVsPt", "hPiFromXiDCAxyVsPt", kTH2F, {axisMomentum, axisDCA}); - histos.add("hPiFromL0DCAxyVsPt", "hPiFromL0DCAxyVsPt", kTH2F, {axisMomentum, axisDCA}); - histos.add("hPrFromL0DCAxyVsPt", "hPrFromL0DCAxyVsPt", kTH2F, {axisMomentum, axisDCA}); + 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"); + } + if (v0DecaySettings.doV0QA) { + histos.add("V0Building/hV0Building", "hV0Building", kTH1F, {{10, -0.5f, 9.5f}}); + + histos.add("V0Building/K0/hGen", "hGen", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("V0Building/K0/hReco", "hReco", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("V0Building/K0/hGenNegDaughterFromV0", "hGenNegDaughterFromV0", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("V0Building/K0/hGenPosDaughterFromV0", "hGenPosDaughterFromV0", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("V0Building/K0/hRecoNegDaughterFromV0", "hRecoNegDaughterFromV0", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + histos.add("V0Building/K0/hRecoPosDaughterFromV0", "hRecoPosDaughterFromV0", kTH2F, {axes.axisDecayRadius, axes.axisMomentum}); + + // histos.add("V0Building/K0/h2dDCAxyV0Negative", "h2dDCAxyV0Negative", kTH2F, {axes.axisMomentum, axes.axisDCA}); + // histos.add("V0Building/K0/h2dDCAxyV0Positive", "h2dDCAxyV0Positive", kTH2F, {axes.axisMomentum, axes.axisDCA}); + + // histos.add("V0Building/K0/h2dDCAzV0Negative", "h2dDCAzV0Negative", kTH2F, {axes.axisMomentum, axes.axisDCA}); + // histos.add("V0Building/K0/h2dDCAzV0Positive", "h2dDCAzV0Positive", kTH2F, {axes.axisMomentum, axes.axisDCA}); + + histos.addClone("V0Building/K0/", "V0Building/Lambda/"); + histos.addClone("V0Building/K0/", "V0Building/AntiLambda/"); + + histos.add("V0Building/K0/hMass", "hMass", kTH2F, {axes.axisK0Mass, axes.axisMomentum}); + histos.add("V0Building/K0/hFinalMass", "hMass", kTH1F, {axes.axisK0Mass}); + histos.add("V0Building/Lambda/hMass", "hMass", kTH2F, {axes.axisLambdaMass, axes.axisMomentum}); + histos.add("V0Building/AntiLambda/hMass", "hMass", kTH2F, {axes.axisLambdaMass, axes.axisMomentum}); + + histos.add("V0Building/hFastTrackerHits", "hFastTrackerHits", kTH2F, {axes.axisZ, axes.axisRadius}); + auto hFastTrackerQA = histos.add("V0Building/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)); @@ -372,7 +527,6 @@ struct OnTheFlyTracker { // Cross-check LOGF(info, "Check field at (0, 0, 0): %.1f kG, nominal: %.1f", static_cast(fieldInstance->GetBz(0, 0, 0)), static_cast(field)); - LOGF(info, "Initializing empty material cylinder LUT - could be better in the future"); o2::base::MatLayerCylSet* lut = new o2::base::MatLayerCylSet(); lut->addLayer(200, 200.1, 2, 1.0f, 100.0f); @@ -388,140 +542,173 @@ 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 for primaries + if (fastPrimaryTrackerSettings.fastTrackPrimaries) { + fastPrimaryTracker.SetMagneticField(magneticField); + fastPrimaryTracker.SetApplyZacceptance(fastPrimaryTrackerSettings.applyZacceptance); + fastPrimaryTracker.SetApplyMSCorrection(fastPrimaryTrackerSettings.applyMSCorrection); + fastPrimaryTracker.SetApplyElossCorrection(fastPrimaryTrackerSettings.applyElossCorrection); + + if (fastPrimaryTrackerSettings.alice3geo.value == "0") { + fastPrimaryTracker.AddSiliconALICE3v2({0.00025, 0.00025, 0.001, 0.001}); + } else if (fastPrimaryTrackerSettings.alice3geo.value == "1") { + fastPrimaryTracker.AddSiliconALICE3v4({0.00025, 0.00025, 0.001, 0.001}); + fastPrimaryTracker.AddTPC(0.1, 0.1); + } else if (fastPrimaryTrackerSettings.alice3geo.value == "2") { + fastPrimaryTracker.AddSiliconALICE3(1., {0.00025, 0.00025, 0.001, 0.001}); + } else { + fastPrimaryTracker.AddGenericDetector(fastPrimaryTrackerSettings.alice3geo, ccdb.operator->()); + } + + // print fastTracker settings + fastPrimaryTracker.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 l0DecayVertex the address of the l0 decay vertex + /// \param laDecayVertex the address of the la decay vertex template - void decayParticle(McParticleType particle, std::vector& decayDaughters, std::vector& xiDecayVertex, std::vector& l0DecayVertex) + void decayCascade(McParticleType particle, o2::track::TrackParCov track, std::vector& decayDaughters, std::vector& xiDecayVertex, std::vector& laDecayVertex) { - std::vector xiVelocity(3); - std::vector l0Velocity(3); - std::vector xiMomentum = {particle.px(), particle.py(), particle.pz()}; - std::vector xiProductionVertex = {particle.vx(), particle.vy(), particle.vz()}; - double bz = magneticField * 0.1; // To tesla - TRandom3 rand; - rand.SetSeed(seed); - double u = rand.Uniform(0, 1); - for (int i = 0; i < 3; i++) { - xiVelocity[i] = xiMomentum[i] / particle.e(); - } - double xi_v_tot = particle.p() / particle.e(); - double xi_ctau = 4.91; // xi - double xi_charge = -1.6022e-19; - double speedOfLight = 3e+8; - double xi_v_xy = speedOfLight * sqrt(xiVelocity[0] * xiVelocity[0] + xiVelocity[1] * xiVelocity[1]); - double xi_lifetime = (-xi_ctau * log(1 - u)) / xi_v_tot; - double xi_kgMass = 1.32171 * 1.78e-27; - double xi_r = (xi_kgMass * xi_v_xy) / (xi_charge * bz); - double xi_theta = ((xi_lifetime / speedOfLight) * xi_charge * bz) / xi_kgMass; - double xi_phi = TMath::ATan2(xiVelocity[1], xiVelocity[0]); - xiDecayVertex.push_back(xiProductionVertex[0] + xi_r * (std::sin(xi_theta) * std::cos(xi_phi) - (1 - std::cos(xi_theta)) * std::sin(xi_phi))); - xiDecayVertex.push_back(xiProductionVertex[1] + xi_r * ((1 - std::cos(xi_theta)) * std::cos(xi_phi) + std::sin(xi_theta) * std::sin(xi_phi))); - xiDecayVertex.push_back(xiProductionVertex[2] + xi_lifetime * xiVelocity[2]); - std::vector xiDaughters = {1.115, 0.139}; - double px = (xi_v_xy * std::cos(xi_theta + xi_phi) * particle.e()) / speedOfLight; - double py = (xi_v_xy * std::sin(xi_theta + xi_phi) * particle.e()) / speedOfLight; - - TLorentzVector xi(px, py, particle.pz(), particle.e()); + const double uXi = rand.Uniform(0, 1); + const double ctauXi = 4.91; // cm + const double betaGammaXi = particle.p() / o2::constants::physics::MassXiMinus; + const double rxyzXi = (-betaGammaXi * ctauXi * std::log(1 - uXi)); + + float sna, csa; + o2::math_utils::CircleXYf_t circleXi; + track.getCircleParams(magneticField, circleXi, sna, csa); + const double rxyXi = rxyzXi / std::sqrt(1. + track.getTgl() * track.getTgl()); + const double theta = rxyXi / circleXi.rC; + const double newX = ((particle.vx() - circleXi.xC) * std::cos(theta) - (particle.vy() - circleXi.yC) * std::sin(theta)) + circleXi.xC; + const double newY = ((particle.vy() - circleXi.yC) * std::cos(theta) + (particle.vx() - circleXi.xC) * std::sin(theta)) + circleXi.yC; + const double newPx = particle.px() * std::cos(theta) - particle.py() * std::sin(theta); + const double newPy = particle.py() * std::cos(theta) + particle.px() * std::sin(theta); + const double newE = std::sqrt(o2::constants::physics::MassXiMinus * o2::constants::physics::MassXiMinus + newPx * newPx + newPy * newPy + particle.pz() * particle.pz()); + + xiDecayVertex.push_back(newX); + xiDecayVertex.push_back(newY); + xiDecayVertex.push_back(particle.vz() + rxyzXi * (particle.pz() / particle.p())); + + std::vector xiDaughters = {o2::constants::physics::MassLambda, o2::constants::physics::MassPionCharged}; + TLorentzVector xi(newPx, newPy, particle.pz(), newE); TGenPhaseSpace xiDecay; xiDecay.SetDecay(xi, 2, xiDaughters.data()); xiDecay.Generate(); decayDaughters.push_back(*xiDecay.GetDecay(1)); - - double l0_ctau = 7.89; // lambda - double l0_v_tot = xiDecay.GetDecay(0)->P() / xiDecay.GetDecay(0)->E(); - std::vector l0Daughters = {0.139, 0.938}; - l0Velocity[0] = xiDecay.GetDecay(0)->Px() / xiDecay.GetDecay(0)->E(); - l0Velocity[1] = xiDecay.GetDecay(0)->Py() / xiDecay.GetDecay(0)->E(); - l0Velocity[2] = xiDecay.GetDecay(0)->Pz() / xiDecay.GetDecay(0)->E(); - double l0_lifetime = (-l0_ctau * log(1 - u)) / l0_v_tot; - for (int i = 0; i < 3; i++) { - l0DecayVertex.push_back(xiDecayVertex[i] + l0_lifetime * l0Velocity[i]); - } - - TLorentzVector l0 = *xiDecay.GetDecay(0); - TGenPhaseSpace l0Decay; - l0Decay.SetDecay(l0, 2, l0Daughters.data()); - l0Decay.Generate(); - decayDaughters.push_back(*l0Decay.GetDecay(0)); - decayDaughters.push_back(*l0Decay.GetDecay(1)); + TLorentzVector la = *xiDecay.GetDecay(0); + + const double uLa = rand.Uniform(0, 1); + const double ctauLa = 7.845; // cm + const double betaGammaLa = la.P() / o2::constants::physics::MassLambda; + const double rxyzLa = (-betaGammaLa * ctauLa * std::log(1 - uLa)); + laDecayVertex.push_back(xiDecayVertex[0] + rxyzLa * (xiDecay.GetDecay(0)->Px() / xiDecay.GetDecay(0)->P())); + laDecayVertex.push_back(xiDecayVertex[1] + rxyzLa * (xiDecay.GetDecay(0)->Py() / xiDecay.GetDecay(0)->P())); + laDecayVertex.push_back(xiDecayVertex[2] + rxyzLa * (xiDecay.GetDecay(0)->Pz() / xiDecay.GetDecay(0)->P())); + + std::vector laDaughters = {o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}; + 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 - /// \param particle the particle to convert (mcParticle) - /// \param o2track the address of the resulting TrackParCov + /// Function to decay the V0 + /// \param particle the particle to decay + /// \param decayDaughters the address of resulting daughters + /// \param v0DecayVertex the address of the la decay vertex template - void convertMCParticleToO2Track(McParticleType& particle, o2::track::TrackParCov& o2track) + void decayV0Particle(McParticleType particle, std::vector& decayDaughters, std::vector& v0DecayVertex, int pdgCode) { - auto pdgInfo = pdgDB->GetParticle(particle.pdgCode()); - int charge = 0; - if (pdgInfo != nullptr) { - charge = pdgInfo->Charge() / 3; + double u = rand.Uniform(0, 1); + double v0Mass = -1.; + double negDauMass = -1.; + double posDauMass = -1.; + double ctau = -1.; + + if (std::abs(pdgCode) == kK0Short) { + v0Mass = o2::constants::physics::MassK0Short; + negDauMass = o2::constants::physics::MassPionCharged; + posDauMass = o2::constants::physics::MassPionCharged; + ctau = 2.68; + } else if (std::abs(pdgCode) == kLambda0) { + v0Mass = o2::constants::physics::MassLambda; + negDauMass = o2::constants::physics::MassPionCharged; + posDauMass = o2::constants::physics::MassProton; + ctau = 7.845; + } else if (std::abs(pdgCode) == kLambda0Bar) { + v0Mass = o2::constants::physics::MassLambda; + negDauMass = o2::constants::physics::MassProton; + posDauMass = o2::constants::physics::MassPionCharged; + ctau = 7.845; } - std::array params; - std::array covm = {0.}; - float s, c, x; - o2::math_utils::sincos(particle.phi(), s, c); - o2::math_utils::rotateZInv(particle.vx(), particle.vy(), x, params[0], s, c); - params[1] = particle.vz(); - params[2] = 0.; // since alpha = phi - auto theta = 2. * std::atan(std::exp(-particle.eta())); - 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); + + const double v0BetaGamma = particle.p() / v0Mass; + const double v0rxyz = (-v0BetaGamma * ctau * std::log(1 - u)); + TLorentzVector v0(particle.px(), particle.py(), particle.pz(), particle.e()); + + v0DecayVertex.push_back(particle.vx() + v0rxyz * (particle.px() / particle.p())); + v0DecayVertex.push_back(particle.vy() + v0rxyz * (particle.py() / particle.p())); + v0DecayVertex.push_back(particle.vz() + v0rxyz * (particle.pz() / particle.p())); + std::vector v0Daughters = {negDauMass, posDauMass}; + + TGenPhaseSpace v0Decay; + v0Decay.SetDecay(v0, 2, v0Daughters.data()); + v0Decay.Generate(); + decayDaughters.push_back(*v0Decay.GetDecay(0)); + decayDaughters.push_back(*v0Decay.GetDecay(1)); } float dNdEta = 0.f; // Charged particle multiplicity to use in the efficiency evaluation - void process(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + void processWithLUTs(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, int const& icfg) { + int lastTrackIndex = tableStoredTracksCov.lastIndex() + 1; // bookkeep the last added track + const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; + tracksAlice3.clear(); ghostTracksAlice3.clear(); - trackPdg.clear(); - trackIsFromXi.clear(); - trackIsFromL0.clear(); - ghostTrackPdg.clear(); - ghostTrackIsFromXi.clear(); - ghostTrackIsFromL0.clear(); bcData.clear(); + cascadesAlice3.clear(); + v0sAlice3.clear(); o2::dataformats::DCA dcaInfo; o2::dataformats::VertexBase vtx; // generate collision time auto ir = irSampler.generateCollisionTime(); + const float eventCollisionTime = ir.timeInBCNS; + + constexpr std::array longLivedHandledPDGs = {kElectron, + kMuonMinus, + kPiPlus, + kKPlus, + kProton}; + + constexpr std::array nucleiPDGs = {o2::constants::physics::kDeuteron, + o2::constants::physics::kTriton, + o2::constants::physics::kHelium3, + o2::constants::physics::kAlpha}; // First we compute the number of charged particles in the event dNdEta = 0.f; @@ -529,17 +716,19 @@ struct OnTheFlyTracker { if (std::abs(mcParticle.eta()) > multEtaRange) { continue; } + if (!mcParticle.isPhysicalPrimary()) { continue; } + const auto pdg = std::abs(mcParticle.pdgCode()); - if (pdg != kElectron && pdg != kMuonMinus && pdg != kPiPlus && pdg != kKPlus && pdg != kProton) { - if (!treatXi) { - continue; - } else if (pdg != 3312) { - continue; - } + const bool longLivedToBeHandled = std::find(longLivedHandledPDGs.begin(), longLivedHandledPDGs.end(), pdg) != longLivedHandledPDGs.end(); + const bool nucleiToBeHandled = std::find(nucleiPDGs.begin(), nucleiPDGs.end(), pdg) != nucleiPDGs.end(); + const bool pdgsToBeHandled = longLivedToBeHandled || (enableNucleiSmearing && nucleiToBeHandled) || (cascadeDecaySettings.decayXi && mcParticle.pdgCode() == kXiMinus); + if (!pdgsToBeHandled) { + continue; } + const auto& pdgInfo = pdgDB->GetParticle(mcParticle.pdgCode()); if (!pdgInfo) { LOG(warning) << "PDG code " << mcParticle.pdgCode() << " not found in the database"; @@ -553,190 +742,575 @@ struct OnTheFlyTracker { dNdEta /= (multEtaRange * 2.0f); uint32_t multiplicityCounter = 0; - histos.fill(HIST("hLUTMultiplicity"), dNdEta); + getHist(TH1, histPath + "hLUTMultiplicity")->Fill(dNdEta); + gRandom->SetSeed(seed); for (const auto& mcParticle : mcParticles) { double xiDecayRadius2D = 0; - double l0DecayRadius2D = 0; + double laDecayRadius2D = 0; + double v0DecayRadius2D = 0; std::vector decayProducts; - std::vector xiDecayVertex, l0DecayVertex; - std::vector layers = {0.50, 1.20, 2.50, 3.75, 7.00, 12.0, 20.0}; - if (treatXi) { - if (mcParticle.pdgCode() == 3312) { - decayParticle(mcParticle, decayProducts, xiDecayVertex, l0DecayVertex); - xiDecayRadius2D = sqrt(xiDecayVertex[0] * xiDecayVertex[0] + xiDecayVertex[1] * xiDecayVertex[1]); - l0DecayRadius2D = sqrt(l0DecayVertex[0] * l0DecayVertex[0] + l0DecayVertex[1] * l0DecayVertex[1]); + std::vector v0DecayProducts; + std::vector xiDecayVertex, laDecayVertex, v0DecayVertex; + if (cascadeDecaySettings.decayXi) { + if (mcParticle.pdgCode() == kXiMinus) { + o2::track::TrackParCov xiTrackParCov; + o2::upgrade::convertMCParticleToO2Track(mcParticle, xiTrackParCov, pdgDB); + decayCascade(mcParticle, xiTrackParCov, decayProducts, xiDecayVertex, laDecayVertex); + xiDecayRadius2D = std::hypot(xiDecayVertex[0], xiDecayVertex[1]); + laDecayRadius2D = std::hypot(laDecayVertex[0], laDecayVertex[1]); } } - const auto pdg = std::abs(mcParticle.pdgCode()); + bool isV0 = std::find(v0PDGs.begin(), v0PDGs.end(), pdg) != v0PDGs.end(); + bool isK0 = (std::abs(pdg) == kK0Short); + bool isLambda = (std::abs(pdg) == kLambda0); + bool isAntiLambda = (std::abs(pdg) == kLambda0Bar); + + if (v0DecaySettings.decayV0 && isV0) { + decayV0Particle(mcParticle, v0DecayProducts, v0DecayVertex, pdg); + v0DecayRadius2D = std::hypot(v0DecayVertex[0], v0DecayVertex[1]); + } + if (!mcParticle.isPhysicalPrimary()) { - if (!treatXi) { - continue; - } else if (pdg != 3312) { - continue; - } + continue; } - if (pdg != kElectron && pdg != kMuonMinus && pdg != kPiPlus && pdg != kKPlus && pdg != kProton) { - if (!treatXi) { - continue; - } else if (pdg != 3312) { - continue; - } + + const bool longLivedToBeHandled = std::find(longLivedHandledPDGs.begin(), longLivedHandledPDGs.end(), pdg) != longLivedHandledPDGs.end(); + const bool nucleiToBeHandled = std::find(nucleiPDGs.begin(), nucleiPDGs.end(), pdg) != nucleiPDGs.end(); + const bool pdgsToBeHandled = longLivedToBeHandled || (enableNucleiSmearing && nucleiToBeHandled) || (cascadeDecaySettings.decayXi && mcParticle.pdgCode() == kXiMinus) || (v0DecaySettings.decayV0 && isV0); + if (!pdgsToBeHandled) { + continue; } + if (std::fabs(mcParticle.eta()) > maxEta) { continue; } - histos.fill(HIST("hPtGenerated"), mcParticle.pt()); - if (TMath::Abs(mcParticle.pdgCode()) == 11) - histos.fill(HIST("hPtGeneratedEl"), mcParticle.pt()); - if (TMath::Abs(mcParticle.pdgCode()) == 211) - histos.fill(HIST("hPtGeneratedPi"), mcParticle.pt()); - if (TMath::Abs(mcParticle.pdgCode()) == 321) - histos.fill(HIST("hPtGeneratedKa"), mcParticle.pt()); - if (TMath::Abs(mcParticle.pdgCode()) == 2212) - histos.fill(HIST("hPtGeneratedPr"), mcParticle.pt()); - - if (treatXi && mcParticle.pdgCode() == 3312) { + getHist(TH1, histPath + "hPtGenerated")->Fill(mcParticle.pt()); + getHist(TH1, histPath + "hPhiGenerated")->Fill(mcParticle.phi()); + if (std::abs(mcParticle.pdgCode()) == kElectron) + getHist(TH1, histPath + "hPtGeneratedEl")->Fill(mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == kPiPlus) + getHist(TH1, histPath + "hPtGeneratedPi")->Fill(mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == kKPlus) + getHist(TH1, histPath + "hPtGeneratedKa")->Fill(mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == kProton) + getHist(TH1, histPath + "hPtGeneratedPr")->Fill(mcParticle.pt()); + + if (cascadeDecaySettings.doXiQA && mcParticle.pdgCode() == kXiMinus) { histos.fill(HIST("hGenXi"), xiDecayRadius2D, mcParticle.pt()); histos.fill(HIST("hGenPiFromXi"), xiDecayRadius2D, decayProducts[0].Pt()); - histos.fill(HIST("hGenPiFromL0"), l0DecayRadius2D, decayProducts[1].Pt()); - histos.fill(HIST("hGenPrFromL0"), l0DecayRadius2D, decayProducts[2].Pt()); + histos.fill(HIST("hGenPiFromLa"), laDecayRadius2D, decayProducts[1].Pt()); + histos.fill(HIST("hGenPrFromLa"), laDecayRadius2D, decayProducts[2].Pt()); + } + if (v0DecaySettings.doV0QA && isV0) { + static_for<0, 2>([&](auto i) { + constexpr int Index = i.value; + histos.fill(HIST("V0Building/") + HIST(kV0names[Index]) + HIST("/hGen"), v0DecayRadius2D, mcParticle.pt()); + histos.fill(HIST("V0Building/") + HIST(kV0names[Index]) + HIST("/hGenNegDaughterFromV0"), v0DecayRadius2D, v0DecayProducts[0].Pt()); + histos.fill(HIST("V0Building/") + HIST(kV0names[Index]) + HIST("/hGenPosDaughterFromV0"), v0DecayRadius2D, v0DecayProducts[1].Pt()); + }); } - if (mcParticle.pt() < minPt) { continue; } + o2::track::TrackParCov trackParCov; + o2::upgrade::convertMCParticleToO2Track(mcParticle, trackParCov, pdgDB); + bool isDecayDaughter = false; - if (mcParticle.getProcess() == 4) + if (mcParticle.getProcess() == TMCProcess::kPDecay) isDecayDaughter = true; multiplicityCounter++; - const float t = (ir.timeInBCNS + gRandom->Gaus(0., 100.)) * 1e-3; - std::vector xiDaughterTrackParCovs(3); - std::vector isReco(3); - std::vector dauPdg = {-211, -211, 2212}; - std::vector fromXi = {true, false, false}; - std::vector fromL0 = {false, true, true}; - std::vector smearer = {mSmearer0, mSmearer1, mSmearer2, mSmearer3, mSmearer4, mSmearer5}; - if (treatXi && mcParticle.pdgCode() == 3312) { - if (xiDecayRadius2D > 20) { - continue; + const float t = (eventCollisionTime + gRandom->Gaus(0., 100.)) * 1e-3; + static constexpr int kCascProngs = 3; + std::vector xiDaughterTrackParCovsPerfect(3); + std::vector xiDaughterTrackParCovsTracked(3); + std::vector isReco(kCascProngs); + std::vector nHits(kCascProngs); // total + std::vector nSiliconHits(kCascProngs); // silicon type + std::vector nTPCHits(kCascProngs); // TPC type + if (cascadeDecaySettings.decayXi && mcParticle.pdgCode() == kXiMinus) { + if (cascadeDecaySettings.doXiQA) { + histos.fill(HIST("hXiBuilding"), 0.0f); } - convertTLorentzVectorToO2Track(-211, decayProducts[0], xiDecayVertex, xiDaughterTrackParCovs[0]); - convertTLorentzVectorToO2Track(-211, decayProducts[1], l0DecayVertex, xiDaughterTrackParCovs[1]); - convertTLorentzVectorToO2Track(2212, decayProducts[2], l0DecayVertex, xiDaughterTrackParCovs[2]); - - // Map daughter to smearer - int firstSmearerIndex = -1; - int secondSmearerIndex = -1; - for (unsigned i = 0; i < layers.size(); i++) { - if (xiDecayRadius2D > layers[i]) { - firstSmearerIndex = i; - } - if (l0DecayRadius2D > layers[i]) { - secondSmearerIndex = i; - } - } - if (firstSmearerIndex > 5) { - isReco[0] = false; - } else if (firstSmearerIndex == -1) { - isReco[0] = mSmearer.smearTrack(xiDaughterTrackParCovs[0], 211, dNdEta); - } else { - isReco[0] = smearer[firstSmearerIndex].smearTrack(xiDaughterTrackParCovs[0], 211, dNdEta); - } - if (secondSmearerIndex > 5) { - isReco[1] = false; - isReco[2] = false; - } else if (secondSmearerIndex == -1) { - isReco[1] = mSmearer.smearTrack(xiDaughterTrackParCovs[1], 211, dNdEta); - isReco[2] = mSmearer.smearTrack(xiDaughterTrackParCovs[2], 2212, dNdEta); - } else { - isReco[1] = smearer[secondSmearerIndex].smearTrack(xiDaughterTrackParCovs[1], 211, dNdEta); - isReco[2] = smearer[secondSmearerIndex].smearTrack(xiDaughterTrackParCovs[2], 2212, dNdEta); - } - for (int i = 0; i < 3; i++) { - if (decayProducts[i].Pt() < minPt) { - isReco[i] = false; - } - if (!isReco[i] && !processUnreconstructedTracks) { - continue; + o2::upgrade::convertTLorentzVectorToO2Track(kPiMinus, decayProducts[0], xiDecayVertex, xiDaughterTrackParCovsPerfect[0], pdgDB); + o2::upgrade::convertTLorentzVectorToO2Track(kPiMinus, decayProducts[1], laDecayVertex, xiDaughterTrackParCovsPerfect[1], pdgDB); + o2::upgrade::convertTLorentzVectorToO2Track(kProton, decayProducts[2], laDecayVertex, xiDaughterTrackParCovsPerfect[2], pdgDB); + + for (int i = 0; i < kCascProngs; i++) { + isReco[i] = false; + nHits[i] = 0; + nSiliconHits[i] = 0; + nTPCHits[i] = 0; + if (enableSecondarySmearing) { + nHits[i] = fastTracker[icfg]->FastTrack(xiDaughterTrackParCovsPerfect[i], xiDaughterTrackParCovsTracked[i], dNdEta); + nSiliconHits[i] = fastTracker[icfg]->GetNSiliconPoints(); + nTPCHits[i] = fastTracker[icfg]->GetNGasPoints(); + + 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[icfg]->GetNHits(); ih++) { + histos.fill(HIST("hFastTrackerHits"), fastTracker[icfg]->GetHitZ(ih), std::hypot(fastTracker[icfg]->GetHitX(ih), fastTracker[icfg]->GetHitY(ih))); + } + } else { + isReco[i] = true; + xiDaughterTrackParCovsTracked[i] = xiDaughterTrackParCovsPerfect[i]; } - if (TMath::IsNaN(xiDaughterTrackParCovs[i].getZ())) { + + if (TMath::IsNaN(xiDaughterTrackParCovsTracked[i].getZ())) { continue; + } else { + histos.fill(HIST("hNaNBookkeeping"), i + 1, 1.0f); } if (isReco[i]) { - tracksAlice3.push_back(TrackAlice3{xiDaughterTrackParCovs[i], mcParticle.globalIndex(), t, 100.f * 1e-3, true}); - trackPdg.push_back(dauPdg[i]); - trackIsFromXi.push_back(fromXi[i]); - trackIsFromL0.push_back(fromL0[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{xiDaughterTrackParCovs[i], mcParticle.globalIndex(), t, 100.f * 1e-3, true}); - ghostTrackPdg.push_back(dauPdg[i]); - ghostTrackIsFromXi.push_back(fromXi[i]); - ghostTrackIsFromL0.push_back(fromL0[i]); + ghostTracksAlice3.push_back(TrackAlice3{xiDaughterTrackParCovsTracked[i], mcParticle.globalIndex(), t, 100.f * 1e-3, true, true, i + 2}); } } - if (treatXi && mcParticle.pdgCode() == 3312) { - if (isReco[0] && isReco[1] && isReco[2]) + if (cascadeDecaySettings.doXiQA && mcParticle.pdgCode() == kXiMinus) { + 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("hRecoPiFromL0"), l0DecayRadius2D, decayProducts[1].Pt()); + histos.fill(HIST("hRecoPiFromLa"), laDecayRadius2D, decayProducts[1].Pt()); if (isReco[2]) - histos.fill(HIST("hRecoPrFromL0"), l0DecayRadius2D, decayProducts[2].Pt()); + histos.fill(HIST("hRecoPrFromLa"), laDecayRadius2D, decayProducts[2].Pt()); } - continue; // Not filling the tables with the xi itself + + // +-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+ + // combine particles into actual Xi candidate + // cascade building starts here + if (cascadeDecaySettings.findXi && mcParticle.pdgCode() == kXiMinus && 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(std::array{std::array{posP[0], posP[1], posP[2]}, + std::array{negP[0], negP[1], negP[2]}}, + std::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(std::array{std::array{bachP[0], bachP[1], bachP[2]}, + std::array{posP[0] + negP[0], posP[1] + negP[1], posP[2] + negP[2]}}, + std::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 = fastTracker[icfg]->GetLayers().size() - 1; i >= 0; --i) { + o2::fastsim::DetLayer layer = fastTracker[icfg]->GetLayer(i); + if (layer.isInert()) { + continue; // Not an active tracking layer + } + + if (thisCascade.cascradiusMC < layer.getRadius()) { + continue; // Cascade did not reach this layer + } + + // cascade decayed after the corresponding radius + thisCascade.findableClusters++; // add to findable + + // find perfect intercept XYZ + float targetX = 1e+3; + trackParCov.getXatLabR(layer.getRadius(), 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::constants::math::PI}; + + if (layer.getResolutionRPhi() > 1e-8 && layer.getResolutionZ() > 1e-8) { // catch zero (though should not really happen...) + phi = gRandom->Gaus(phi, std::asin(layer.getResolutionRPhi() / r)); + posClusterCandidate[0] = r * std::cos(phi); + posClusterCandidate[1] = r * std::sin(phi); + posClusterCandidate[2] = gRandom->Gaus(posClusterCandidate[2], layer.getResolutionZ()); + } + + if (std::isnan(phi)) + continue; // Catch when getXatLabR misses layer[i] + + // 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 = {layer.getResolutionRPhi() * layer.getResolutionRPhi(), 0.f, layer.getResolutionZ() * layer.getResolutionZ()}; + if (layer.isInDeadPhiRegion(phi)) { + continue; // No hit for strangeness tracking update + } + + 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); + getHist(TH1, histPath + "hMassXi")->Fill(thisCascade.mXi); + } + + // add this cascade to vector (will fill cursor later with collision ID) + cascadesAlice3.push_back(thisCascade); + } + } + } // end cascade building + // +-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+ + continue; // Cascade handling done, should not be considered anymore } + // V0 handling + std::vector v0DaughterTrackParCovsPerfect(2); + std::vector v0DaughterTrackParCovsTracked(2); + std::vector isV0Reco(kv0Prongs); + std::vector nV0Hits(kv0Prongs); // total + std::vector nV0SiliconHits(kv0Prongs); // silicon type + std::vector nV0TPCHits(kv0Prongs); // TPC type + if (v0DecaySettings.decayV0 && isV0) { + if (v0DecaySettings.doV0QA) { + histos.fill(HIST("V0Building/hV0Building"), 0.0f); + } + if (isK0) { + o2::upgrade::convertTLorentzVectorToO2Track(kPiMinus, v0DecayProducts[0], v0DecayVertex, v0DaughterTrackParCovsPerfect[0], pdgDB); + o2::upgrade::convertTLorentzVectorToO2Track(kPiPlus, v0DecayProducts[1], v0DecayVertex, v0DaughterTrackParCovsPerfect[1], pdgDB); + } else if (isLambda) { + o2::upgrade::convertTLorentzVectorToO2Track(kPiMinus, v0DecayProducts[0], v0DecayVertex, v0DaughterTrackParCovsPerfect[0], pdgDB); + o2::upgrade::convertTLorentzVectorToO2Track(kProton, v0DecayProducts[1], v0DecayVertex, v0DaughterTrackParCovsPerfect[1], pdgDB); + } else if (isAntiLambda) { + o2::upgrade::convertTLorentzVectorToO2Track(kProtonBar, v0DecayProducts[0], v0DecayVertex, v0DaughterTrackParCovsPerfect[0], pdgDB); + o2::upgrade::convertTLorentzVectorToO2Track(kPiPlus, v0DecayProducts[1], v0DecayVertex, v0DaughterTrackParCovsPerfect[1], pdgDB); + } + for (int i = 0; i < kv0Prongs; i++) { + isV0Reco[i] = false; + nV0Hits[i] = 0; + nV0SiliconHits[i] = 0; + nV0TPCHits[i] = 0; + if (enableSecondarySmearing) { + nV0Hits[i] = fastTracker[icfg]->FastTrack(v0DaughterTrackParCovsPerfect[i], v0DaughterTrackParCovsTracked[i], dNdEta); + nV0SiliconHits[i] = fastTracker[icfg]->GetNSiliconPoints(); + nV0TPCHits[i] = fastTracker[icfg]->GetNGasPoints(); + + if (nV0Hits[i] < 0) { // QA + histos.fill(HIST("V0Building/hFastTrackerQA"), o2::math_utils::abs(nV0Hits[i])); + } + + if (nV0SiliconHits[i] >= fastTrackerSettings.minSiliconHits || (nV0SiliconHits[i] >= fastTrackerSettings.minSiliconHitsIfTPCUsed && nV0TPCHits[i] >= fastTrackerSettings.minTPCClusters)) { + isReco[i] = true; + } else { + continue; // extra sure + } + for (uint32_t ih = 0; ih < fastTracker[icfg]->GetNHits(); ih++) { + histos.fill(HIST("V0Building/hFastTrackerHits"), fastTracker[icfg]->GetHitZ(ih), std::hypot(fastTracker[icfg]->GetHitX(ih), fastTracker[icfg]->GetHitY(ih))); + } + } else { + isReco[i] = true; + v0DaughterTrackParCovsTracked[i] = v0DaughterTrackParCovsPerfect[i]; + } - o2::track::TrackParCov trackParCov; - convertMCParticleToO2Track(mcParticle, trackParCov); + // if (TMath::IsNaN(v0DaughterTrackParCovsTracked[i].getZ())) { + // continue; + // } else { + // histos.fill(HIST("hNaNBookkeeping"), i + 1, 1.0f); + // } + if (isReco[i]) { + tracksAlice3.push_back(TrackAlice3{v0DaughterTrackParCovsTracked[i], mcParticle.globalIndex(), t, 100.f * 1e-3, true, true, i + 2, nSiliconHits[i], nTPCHits[i]}); + } else { + ghostTracksAlice3.push_back(TrackAlice3{v0DaughterTrackParCovsTracked[i], mcParticle.globalIndex(), t, 100.f * 1e-3, true, true, i + 2}); + } + } + if (v0DecaySettings.doV0QA) { + static_for<0, 2>([&](auto i) { + constexpr int Index = i.value; + if (pdg == v0PDGs[Index]) { + if (isReco[0] && isReco[1]) { + histos.fill(HIST("V0Building/") + HIST(kV0names[Index]) + HIST("/hReco"), v0DecayRadius2D, mcParticle.pt()); + } + if (isReco[0]) + histos.fill(HIST("V0Building/") + HIST(kV0names[Index]) + HIST("/hRecoNegDaughterFromV0"), v0DecayRadius2D, v0DecayProducts[0].Pt()); + if (isReco[1]) + histos.fill(HIST("V0Building/") + HIST(kV0names[Index]) + HIST("/hRecoPosDaughterFromV0"), v0DecayRadius2D, v0DecayProducts[1].Pt()); + } + }); + if (isReco[0] && isReco[1]) { + histos.fill(HIST("V0Building/hV0Building"), 1.0f); + } + } + // +-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+-~-+ + // combine particles into actual V0 candidate + // V0 building starts here + if (v0DecaySettings.findV0 && isReco[0] && isReco[1]) { + if (v0DecaySettings.doV0QA) + histos.fill(HIST("V0Building/hV0Building"), 2.0f); + // assign indices of the particles we've used + // they should be the last ones to be filled, in order: + // n-1: positive Track from V0 + // n-2: negative Track from V0 + thisV0.positiveId = lastTrackIndex + tracksAlice3.size() - 1; + thisV0.negativeId = lastTrackIndex + tracksAlice3.size() - 2; + // use DCA fitters + int nCand = 0; + bool dcaFitterOK_V0 = true; + try { + nCand = fitter.process(v0DaughterTrackParCovsTracked[0], v0DaughterTrackParCovsTracked[1]); + } 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 (v0DecaySettings.doV0QA) + histos.fill(HIST("V0Building/hV0Building"), 3.0f); + std::array pos; + std::array posP; + std::array negP; + + o2::track::TrackParCov pTrackAtPCA = fitter.getTrack(1); // (positive) + o2::track::TrackParCov nTrackAtPCA = fitter.getTrack(0); // (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 + thisV0.dcaV0dau = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + thisV0.v0radius = std::hypot(pos[0], pos[1]); + thisV0.pt = std::hypot(std::cos(v0DaughterTrackParCovsTracked[0].getPhi()) * v0DaughterTrackParCovsTracked[0].getPt() + std::cos(v0DaughterTrackParCovsTracked[1].getPhi()) * v0DaughterTrackParCovsTracked[1].getPt(), + std::sin(v0DaughterTrackParCovsTracked[0].getPhi()) * v0DaughterTrackParCovsTracked[0].getPt() + std::sin(v0DaughterTrackParCovsTracked[1].getPhi()) * v0DaughterTrackParCovsTracked[1].getPt()); + // thisV0.mLambda = RecoDecay::m(std::array{std::array{posP[0], posP[1], posP[2]}, + // std::array{negP[0], negP[1], negP[2]}}, + // std::array{o2::constants::physics::MassProton, + // o2::constants::physics::MassPionCharged}); + if (isK0) { + thisV0.mK0 = RecoDecay::m(std::array{std::array{posP[0], posP[1], posP[2]}, + std::array{negP[0], negP[1], negP[2]}}, + std::array{o2::constants::physics::MassPionCharged, + o2::constants::physics::MassPionCharged}); + } else { + thisV0.mK0 = -1; + } + + if (isLambda) { + thisV0.mLambda = RecoDecay::m(std::array{std::array{posP[0], posP[1], posP[2]}, + std::array{negP[0], negP[1], negP[2]}}, + std::array{o2::constants::physics::MassPionCharged, + o2::constants::physics::MassProton}); + } else { + thisV0.mLambda = -1; + } + + if (isAntiLambda) { + thisV0.mAntiLambda = RecoDecay::m(std::array{std::array{posP[0], posP[1], posP[2]}, + std::array{negP[0], negP[1], negP[2]}}, + std::array{o2::constants::physics::MassProton, + o2::constants::physics::MassPionCharged}); + } else { + thisV0.mAntiLambda = -1; + } + + if (v0DecaySettings.doV0QA) { + histos.fill(HIST("V0Building/hV0Building"), 4.0f); + + histos.fill(HIST("V0Building/K0/hMass"), thisV0.mK0, thisV0.pt); + histos.fill(HIST("V0Building/Lambda/hMass"), thisV0.mLambda, thisV0.pt); + histos.fill(HIST("V0Building/AntiLambda/hMass"), thisV0.mAntiLambda, thisV0.pt); + } + + // add this V0 to vector (will fill cursor later with collision ID) + v0sAlice3.push_back(thisV0); + } + } + } if (doExtraQA) { histos.fill(HIST("hSimTrackX"), trackParCov.getX()); } - bool reconstructed = mSmearer.smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + bool reconstructed = true; + if (enablePrimarySmearing && !fastPrimaryTrackerSettings.fastTrackPrimaries) { + reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + } else if (fastPrimaryTrackerSettings.fastTrackPrimaries) { + o2::track::TrackParCov o2Track; + o2::upgrade::convertMCParticleToO2Track(mcParticle, o2Track, pdgDB); + int nHits = fastPrimaryTracker.FastTrack(o2Track, trackParCov, dNdEta); + if (nHits < fastPrimaryTrackerSettings.minSiliconHits) { + reconstructed = false; + } + } + 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) - histos.fill(HIST("hPtReconstructed"), trackParCov.getPt()); - if (TMath::Abs(mcParticle.pdgCode()) == 11) - histos.fill(HIST("hPtReconstructedEl"), mcParticle.pt()); - if (TMath::Abs(mcParticle.pdgCode()) == 211) - histos.fill(HIST("hPtReconstructedPi"), mcParticle.pt()); - if (TMath::Abs(mcParticle.pdgCode()) == 321) - histos.fill(HIST("hPtReconstructedKa"), mcParticle.pt()); - if (TMath::Abs(mcParticle.pdgCode()) == 2212) - histos.fill(HIST("hPtReconstructedPr"), mcParticle.pt()); + getHist(TH1, histPath + "hPtReconstructed")->Fill(trackParCov.getPt()); + if (std::abs(mcParticle.pdgCode()) == kElectron) + getHist(TH1, histPath + "hPtReconstructedEl")->Fill(trackParCov.getPt()); + if (std::abs(mcParticle.pdgCode()) == kPiPlus) + getHist(TH1, histPath + "hPtReconstructedPi")->Fill(trackParCov.getPt()); + if (std::abs(mcParticle.pdgCode()) == kKPlus) + getHist(TH1, histPath + "hPtReconstructedKa")->Fill(trackParCov.getPt()); + if (std::abs(mcParticle.pdgCode()) == kProton) + getHist(TH1, histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); if (doExtraQA) { + getHist(TH2, histPath + "h2dPtRes")->Fill(trackParCov.getPt(), (trackParCov.getPt() - mcParticle.pt()) / trackParCov.getPt()); histos.fill(HIST("hRecoTrackX"), trackParCov.getX()); } // populate vector with track if we reco-ed it if (reconstructed) { tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), t, 100.f * 1e-3, isDecayDaughter}); - trackPdg.push_back(mcParticle.pdgCode()); - trackIsFromXi.push_back(false); - trackIsFromL0.push_back(false); } else { ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), t, 100.f * 1e-3, isDecayDaughter}); - ghostTrackPdg.push_back(mcParticle.pdgCode()); - ghostTrackIsFromXi.push_back(false); - ghostTrackIsFromL0.push_back(false); } } @@ -744,7 +1318,6 @@ struct OnTheFlyTracker { // Calculate primary vertex with tracks from this collision // data preparation o2::vertexing::PVertex primaryVertex; - if (enablePrimaryVertexing) { std::vector lblTracks; std::vector vertices; @@ -791,9 +1364,9 @@ struct OnTheFlyTracker { // *+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+* // debug / informational - histos.fill(HIST("hSimMultiplicity"), multiplicityCounter); - histos.fill(HIST("hRecoMultiplicity"), tracksAlice3.size()); - histos.fill(HIST("hPVz"), primaryVertex.getZ()); + getHist(TH1, histPath + "hSimMultiplicity")->Fill(multiplicityCounter); + getHist(TH1, histPath + "hRecoMultiplicity")->Fill(tracksAlice3.size()); + getHist(TH1, histPath + "hPVz")->Fill(primaryVertex.getZ()); if (doExtraQA) { histos.fill(HIST("hRecoVsSimMultiplicity"), multiplicityCounter, tracksAlice3.size()); @@ -801,19 +1374,18 @@ struct OnTheFlyTracker { // *+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+* // populate collisions - collisions(-1, // BC is irrelevant in synthetic MC tests for now, could be adjusted in future - primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), - primaryVertex.getSigmaX2(), primaryVertex.getSigmaXY(), primaryVertex.getSigmaY2(), - primaryVertex.getSigmaXZ(), primaryVertex.getSigmaYZ(), primaryVertex.getSigmaZ2(), - 0, primaryVertex.getChi2(), primaryVertex.getNContributors(), - 0, 0); - collLabels(mcCollision.globalIndex(), 0); - collisionsAlice3(dNdEta); + tableCollisions(-1, // BC is irrelevant in synthetic MC tests for now, could be adjusted in future + primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), + primaryVertex.getSigmaX2(), primaryVertex.getSigmaXY(), primaryVertex.getSigmaY2(), + primaryVertex.getSigmaXZ(), primaryVertex.getSigmaYZ(), primaryVertex.getSigmaZ2(), + 0, primaryVertex.getChi2(), primaryVertex.getNContributors(), + eventCollisionTime, 0.f); // For the moment the event collision time is taken as the "GEANT" time, the computation of the event time is done a posteriori from the tracks in the OTF TOF PID task + tableMcCollisionLabels(mcCollision.globalIndex(), 0); + tableCollisionsAlice3(dNdEta); // *+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+* // *+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+* // populate tracks - unsigned trackCounter = 0; for (const auto& trackParCov : tracksAlice3) { // Fixme: collision index could be changeable aod::track::TrackTypeEnum trackType = aod::track::Track; @@ -826,60 +1398,61 @@ struct OnTheFlyTracker { dcaZ = dcaInfo.getZ(); } if (doExtraQA && (!extraQAwithoutDecayDaughters || (extraQAwithoutDecayDaughters && !trackParCov.isDecayDau))) { - histos.fill(HIST("h2dDCAxy"), trackParametrization.getPt(), dcaXY * 1e+4); // in microns, please + getHist(TH2, histPath + "h2dDCAxy")->Fill(trackParametrization.getPt(), dcaXY * 1e+4); + getHist(TH2, histPath + "h2dDCAz")->Fill(trackParametrization.getPt(), dcaZ * 1e+4); histos.fill(HIST("hTrackXatDCA"), trackParametrization.getX()); } - if (treatXi) { - if (trackPdg[trackCounter] == -211 && trackIsFromXi[trackCounter]) { - histos.fill(HIST("hPiFromXiDCAxy"), dcaXY); - histos.fill(HIST("hPiFromXiDCAxyVsPt"), trackParametrization.getPt(), dcaXY); + 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 (trackPdg[trackCounter] == -211 && trackIsFromL0[trackCounter]) { - histos.fill(HIST("hPiFromL0DCAxy"), dcaXY); - histos.fill(HIST("hPiFromL0DCAxyVsPt"), trackParametrization.getPt(), dcaXY); + 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 (trackPdg[trackCounter] == 2212 && trackIsFromL0[trackCounter]) { - histos.fill(HIST("hPrFromL0DCAxy"), dcaXY); - histos.fill(HIST("hPrFromL0DCAxyVsPt"), trackParametrization.getPt(), dcaXY); + 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); + tableTracksDCA(dcaXY, dcaZ); if (populateTracksDCACov) { - tracksDCACov(dcaInfo.getSigmaY2(), dcaInfo.getSigmaZ2()); + tableTracksDCACov(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()); + tableOTFLUTConfigId(icfg); + tableStoredTracks(tableCollisions.lastIndex(), trackType, trackParCov.getX(), trackParCov.getAlpha(), trackParCov.getY(), trackParCov.getZ(), trackParCov.getSnp(), trackParCov.getTgl(), trackParCov.getQ2Pt()); + tableTracksExtension(trackParCov.getPt(), trackParCov.getP(), trackParCov.getEta(), trackParCov.getPhi()); // TODO do we keep the rho as 0? Also the sigma's are duplicated information - tracksParCov(std::sqrt(trackParCov.getSigmaY2()), std::sqrt(trackParCov.getSigmaZ2()), std::sqrt(trackParCov.getSigmaSnp2()), - std::sqrt(trackParCov.getSigmaTgl2()), std::sqrt(trackParCov.getSigma1Pt2()), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - tracksParCovExtension(trackParCov.getSigmaY2(), trackParCov.getSigmaZY(), trackParCov.getSigmaZ2(), trackParCov.getSigmaSnpY(), - trackParCov.getSigmaSnpZ(), trackParCov.getSigmaSnp2(), trackParCov.getSigmaTglY(), trackParCov.getSigmaTglZ(), trackParCov.getSigmaTglSnp(), - trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), - trackParCov.getSigma1Pt2()); - tracksLabels(trackParCov.mcLabel, 0); + tableStoredTracksCov(std::sqrt(trackParCov.getSigmaY2()), std::sqrt(trackParCov.getSigmaZ2()), std::sqrt(trackParCov.getSigmaSnp2()), + std::sqrt(trackParCov.getSigmaTgl2()), std::sqrt(trackParCov.getSigma1Pt2()), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + tableTracksCovExtension(trackParCov.getSigmaY2(), trackParCov.getSigmaZY(), trackParCov.getSigmaZ2(), trackParCov.getSigmaSnpY(), + trackParCov.getSigmaSnpZ(), trackParCov.getSigmaSnp2(), trackParCov.getSigmaTglY(), trackParCov.getSigmaTglZ(), trackParCov.getSigmaTglSnp(), + trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), + trackParCov.getSigma1Pt2()); + tableMcTrackLabels(trackParCov.mcLabel, 0); + tableTracksExtraA3(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, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + tableStoredTracksExtra(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); - trackSelectionExtension(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); + tableTrackSelection(static_cast(0), false, false, false, false, false, false); + tableTrackSelectionExtension(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); } - TracksAlice3(true); - - // populate with xi daughter info - OTFMcExtra(trackPdg[trackCounter], trackIsFromXi[trackCounter], trackIsFromL0[trackCounter]); - trackCounter++; + tableTracksAlice3(true); } - // populate ghost tracks - unsigned ghostTrackCounter = 0; for (const auto& trackParCov : ghostTracksAlice3) { // Fixme: collision index could be changeable aod::track::TrackTypeEnum trackType = aod::track::Track; @@ -893,49 +1466,90 @@ 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); + tableTracksDCA(dcaXY, dcaZ); if (populateTracksDCACov) { - tracksDCACov(dcaInfo.getSigmaY2(), dcaInfo.getSigmaZ2()); + tableTracksDCACov(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()); + tableStoredTracks(tableCollisions.lastIndex(), trackType, trackParCov.getX(), trackParCov.getAlpha(), trackParCov.getY(), trackParCov.getZ(), trackParCov.getSnp(), trackParCov.getTgl(), trackParCov.getQ2Pt()); + tableTracksExtension(trackParCov.getPt(), trackParCov.getP(), trackParCov.getEta(), trackParCov.getPhi()); // TODO do we keep the rho as 0? Also the sigma's are duplicated information - tracksParCov(std::sqrt(trackParCov.getSigmaY2()), std::sqrt(trackParCov.getSigmaZ2()), std::sqrt(trackParCov.getSigmaSnp2()), - std::sqrt(trackParCov.getSigmaTgl2()), std::sqrt(trackParCov.getSigma1Pt2()), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - tracksParCovExtension(trackParCov.getSigmaY2(), trackParCov.getSigmaZY(), trackParCov.getSigmaZ2(), trackParCov.getSigmaSnpY(), - trackParCov.getSigmaSnpZ(), trackParCov.getSigmaSnp2(), trackParCov.getSigmaTglY(), trackParCov.getSigmaTglZ(), trackParCov.getSigmaTglSnp(), - trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), - trackParCov.getSigma1Pt2()); - tracksLabels(trackParCov.mcLabel, 0); + tableStoredTracksCov(std::sqrt(trackParCov.getSigmaY2()), std::sqrt(trackParCov.getSigmaZ2()), std::sqrt(trackParCov.getSigmaSnp2()), + std::sqrt(trackParCov.getSigmaTgl2()), std::sqrt(trackParCov.getSigma1Pt2()), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + tableTracksCovExtension(trackParCov.getSigmaY2(), trackParCov.getSigmaZY(), trackParCov.getSigmaZ2(), trackParCov.getSigmaSnpY(), + trackParCov.getSigmaSnpZ(), trackParCov.getSigmaSnp2(), trackParCov.getSigmaTglY(), trackParCov.getSigmaTglZ(), trackParCov.getSigmaTglSnp(), + trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), + trackParCov.getSigma1Pt2()); + tableMcTrackLabels(trackParCov.mcLabel, 0); + tableTracksExtraA3(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, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + tableStoredTracksExtra(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); - trackSelectionExtension(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); + tableTrackSelection(static_cast(0), false, false, false, false, false, false); + tableTrackSelectionExtension(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); } - TracksAlice3(false); + tableTracksAlice3(false); + } + + for (const auto& cascade : cascadesAlice3) { + tableUpgradeCascades(tableCollisions.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); + } + for (const auto& v0 : v0sAlice3) { + if (v0.mK0 > 0) + histos.fill(HIST("V0Building/K0/hFinalMass"), v0.mK0); + tableUpgradeV0s(tableCollisions.lastIndex(), // now we know the collision index -> populate table + v0.positiveId, + v0.negativeId, + v0.dcaV0dau, + v0.v0radius, + v0.mLambda, + v0.mAntiLambda, + v0.mK0, + v0.pt); + } - // populate table with xi daughter info - OTFMcExtra(ghostTrackPdg[ghostTrackCounter], ghostTrackIsFromXi[trackCounter], ghostTrackIsFromL0[trackCounter]); - ghostTrackCounter++; + // do bookkeeping of fastTracker tracking + if (enableSecondarySmearing) { + histos.fill(HIST("hCovMatOK"), 0.0f, fastTracker[icfg]->GetCovMatNotOK()); + histos.fill(HIST("hCovMatOK"), 1.0f, fastTracker[icfg]->GetCovMatOK()); + } + } // end process + + void process(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + for (size_t icfg = 0; icfg < mSmearer.size(); ++icfg) { + processWithLUTs(mcCollision, mcParticles, static_cast(icfg)); } } }; /// Extends TracksExtra if necessary struct onTheFlyTrackerInitializer { - Spawns tracksExtra; + Spawns tableStoredTracksExtra; void init(InitContext const&) {} }; diff --git a/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx new file mode 100644 index 00000000000..0fa228f57f6 --- /dev/null +++ b/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.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 onTheFlyTrackerPid.cxx +/// +/// \brief This task produces the PID information that can be obtained from the tracker layers (i.e. ToT and possibly cluster size). +/// So far only ToT implemented. It currently contemplates 5 (9) particle types: electrons, muons, pions, kaons and +/// protons (as well as deuterons, tritons, helium-3 and alphas/helium-4 if added via the event generator). +/// +/// \author Henrik Fribert TUM +/// \author Nicolò Jacazio Università del Piemonte Orientale +/// \since May 22, 2025 +/// + +#include "TableHelper.h" + +#include "ALICE3/Core/DelphesO2TrackSmearer.h" +#include "ALICE3/Core/TrackUtilities.h" +#include "ALICE3/DataModel/OTFPIDTrk.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +static constexpr std::array kTrackerRadii = {0.5f, 1.2f, 2.5f, 3.75f, 7.0f, 12.0f, 20.0f, 30.0f, 45.0f, 60.0f, 80.0f}; + +// Constants for magic numbers +static constexpr int kMinEntriesForProjection = 10; +static constexpr double kMinMomentumForLogBins = 0.05; +static constexpr double kMaxMomentumForLogBins = 10.0; +static constexpr int kMinLayerForTruncation = 3; + +// Constants for validation conditions +static constexpr size_t kMinValidHits = 1; +static constexpr size_t kLowValidHits = 2; +static constexpr size_t kMidLowValidHits = 3; +static constexpr size_t kMidHighValidHits = 4; +static constexpr size_t kHighValidHits1 = 5; +static constexpr size_t kHighValidHits2 = 6; +static constexpr size_t kMaxValidHits = 7; + +// Constants for truncated mean calculation +static constexpr size_t kMaxValidHitsForTruncation7Plus = 4; +static constexpr size_t kMaxValidHitsForTruncation56 = 3; +static constexpr size_t kMaxValidHitsForTruncation34 = 2; +static constexpr size_t kMaxValidHitsForTruncation12 = 1; + +// Constants for LUT binning +// To do: Include in LUT header or similar +static constexpr int kLUTEtaBins = 50; +static constexpr float kLUTEtaMin = -2.5f; +static constexpr float kLUTEtaMax = 2.5f; +static constexpr int kLUTPtBins = 500; +static constexpr float kLUTPtMin = 0.0f; +static constexpr float kLUTPtMax = 10.0f; + +class ToTLUT +{ + public: + explicit ToTLUT(int maxLayers, float analysisEtaMinVal = 0.0f, float analysisEtaMaxVal = 1.0f, float analysisPtMinVal = 0.0f, float analysisPtMaxVal = 10.0f) + : mMaxLayers(maxLayers), + mAnalysisEtaMin(analysisEtaMinVal), + mAnalysisEtaMax(analysisEtaMaxVal), + mAnalysisPtMin(analysisPtMinVal), + mAnalysisPtMax(analysisPtMaxVal), + mEtaBins(kLUTEtaBins), + mEtaMin(kLUTEtaMin), + mEtaMax(kLUTEtaMax), + mPtBins(kLUTPtBins), + mPtMin(kLUTPtMin), + mPtMax(kLUTPtMax), + mEtaBinWidth((kLUTEtaMax - kLUTEtaMin) / kLUTEtaBins), + mPtBinWidth((kLUTPtMax - kLUTPtMin) / kLUTPtBins) + { + mPdgToIndexMap.reserve(10); + mIndexToPdgMap.reserve(10); + } + ToTLUT() = delete; + + ~ToTLUT() + { + for (const auto& hist_ptr : mLUTHistogramFlat) { + if (hist_ptr) { + delete hist_ptr; + } + } + } + + void setCcdbManager(o2::ccdb::BasicCCDBManager* mgr) { mCcdbManager = mgr; } + + bool load(int pdg, const std::string& filename) + { + if (!filename.empty() && strncmp(filename.c_str(), "ccdb:", 5) == 0) { + std::string basePath = std::string(filename).substr(5); + std::string path = basePath + "/PDG_" + std::to_string(pdg); + const std::string outPath = "/tmp/ToTLUTs/"; + + std::string localFilename = Form("%s/lut_tot_%d.root", outPath.c_str(), pdg); + std::ifstream checkFile(localFilename); + if (!checkFile.is_open()) { + if (!mCcdbManager) { + LOG(fatal) << "CCDB manager not set. Please set it before loading LUT from CCDB."; + } + std::map metadata; + mCcdbManager->getCCDBAccessor().retrieveBlob(path, outPath, metadata, 1); + + std::string foundFile = Form("%s/%s/snapshot.root", outPath.c_str(), path.c_str()); + std::ifstream testFile(foundFile); + if (!testFile.is_open()) { + LOG(error) << "Could not find downloaded CCDB file for PDG " << pdg; + return false; + } + testFile.close(); + + return load(pdg, foundFile); + } else { + checkFile.close(); + return load(pdg, localFilename); + } + } + + TFile* f = TFile::Open(filename.c_str()); + if (!f || f->IsZombie()) { + LOG(error) << "Failed to open LUT file: " << filename; + return false; + } + + int currentPdgIdx; + auto it = mPdgToIndexMap.find(pdg); + if (it == mPdgToIndexMap.end()) { + currentPdgIdx = mIndexToPdgMap.size(); + mPdgToIndexMap[pdg] = currentPdgIdx; + mIndexToPdgMap.push_back(pdg); + + size_t totalSize = (currentPdgIdx + 1) * mMaxLayers * mEtaBins * mPtBins; + if (mLUTHistogramFlat.size() < totalSize) { + mLUTHistogramFlat.resize(totalSize, nullptr); + } + } else { + currentPdgIdx = it->second; + } + + bool success = true; + for (int layer = 0; layer < mMaxLayers; ++layer) { + for (int etaBin = 0; etaBin < mEtaBins; ++etaBin) { + float etaMinBin = mEtaMin + etaBin * mEtaBinWidth; + float etaMaxBin = etaMinBin + mEtaBinWidth; + + float etaCenter = (etaMinBin + etaMaxBin) / 2.0f; + if (std::abs(etaCenter) < mAnalysisEtaMin || std::abs(etaCenter) > mAnalysisEtaMax) { + continue; + } + + for (int ptBin = 0; ptBin < mPtBins; ++ptBin) { + float ptMinBin = mPtMin + ptBin * mPtBinWidth; + float ptMaxBin = ptMinBin + mPtBinWidth; + float ptCenter = (ptMinBin + ptMaxBin) / 2.0f; + + if (ptCenter < mAnalysisPtMin || ptCenter >= mAnalysisPtMax) { + continue; + } + + TString histName = Form("tot_%d_barrel%d_eta%.2f-%.2f_pt%.2f-%.2f", pdg, layer, etaMinBin, etaMaxBin, ptMinBin, ptMaxBin); + + TH1F* histFromFile = dynamic_cast(f->Get(histName)); + if (histFromFile) { + TH1F* clonedHist = static_cast(histFromFile->Clone()); + clonedHist->SetDirectory(nullptr); + + size_t flatIdx = getFlatIndex(currentPdgIdx, layer, etaBin, ptBin); + mLUTHistogramFlat[flatIdx] = clonedHist; + } else { + size_t flatIdx = getFlatIndex(currentPdgIdx, layer, etaBin, ptBin); + mLUTHistogramFlat[flatIdx] = nullptr; + success = false; + } + } + } + } + + f->Close(); + delete f; + return success; + } + + TH1F* getHistogramForSampling(int pdgIdx, int layer, int etaBin, int ptBin) const + { + if (pdgIdx < 0 || static_cast(pdgIdx) >= getNumPdgTypes() || + layer < 0 || layer >= mMaxLayers || + etaBin < 0 || etaBin >= mEtaBins || ptBin < 0 || ptBin >= mPtBins) { + return nullptr; + } + size_t flatIdx = getFlatIndex(pdgIdx, layer, etaBin, ptBin); + return (flatIdx < mLUTHistogramFlat.size()) ? mLUTHistogramFlat[flatIdx] : nullptr; + } + + int getPdgIndex(int pdgCode) const + { + auto it = mPdgToIndexMap.find(pdgCode); + if (it != mPdgToIndexMap.end()) { + return it->second; + } + return -1; + } + + inline int getEtaBin(float eta) const + { + const float clampedEta = std::max(mEtaMin, std::min(eta, mEtaMax - 1e-6f)); + return std::min(static_cast((clampedEta - mEtaMin) / mEtaBinWidth), mEtaBins - 1); + } + + inline int getPtBin(float pt) const + { + const float clampedPt = std::max(mPtMin, std::min(pt, mPtMax - 1e-6f)); + return std::min(static_cast((clampedPt - mPtMin) / mPtBinWidth), mPtBins - 1); + } + + inline size_t getFlatIndex(int pdgIdx, int layer, int etaBin, int ptBin) const + { + return ((pdgIdx * mMaxLayers + layer) * mEtaBins + etaBin) * mPtBins + ptBin; + } + + size_t getNumPdgTypes() const + { + return mIndexToPdgMap.size(); + } + + std::vector mLUTHistogramFlat; + + std::unordered_map mPdgToIndexMap; + std::vector mIndexToPdgMap; + + int mMaxLayers; + float mAnalysisEtaMin; + float mAnalysisEtaMax; + float mAnalysisPtMin; + float mAnalysisPtMax; + int mEtaBins; + float mEtaMin; + float mEtaMax; + int mPtBins; + float mPtMin; + float mPtMax; + + float mEtaBinWidth; + float mPtBinWidth; + + private: + o2::ccdb::BasicCCDBManager* mCcdbManager = nullptr; +}; + +static constexpr int kNumHypothesisParticles = 9; +std::array, kNumHypothesisParticles>, kNumHypothesisParticles> h2dBarrelNsigmaTrue; +std::array, kNumHypothesisParticles> h2dHitsPerTrackVsP; +std::array, kNumHypothesisParticles> h2dToTvsPperParticle; + +struct OnTheFlyTrackerPid { + + float calculateNsigma(float measuredToT, float expectedToT, float resolution) + { + if (resolution <= 0) + return 999.f; + return (measuredToT - expectedToT) / resolution; + } + + float getToTMeanFromMomentumSlice(std::shared_ptr hist, float momentum) + { + if (!hist) + return -1.f; + int binX = hist->GetXaxis()->FindBin(momentum); + TH1D* proj = hist->ProjectionY("temp", binX, binX); + if (proj->GetEntries() < kMinEntriesForProjection) { + delete proj; + return -1.f; + } + float mean = proj->GetMean(); + delete proj; + return mean; + } + + float getToTResolutionFromMomentumSlice(std::shared_ptr hist, float momentum) + { + if (!hist) + return -1.f; + int binX = hist->GetXaxis()->FindBin(momentum); + TH1D* proj = hist->ProjectionY("temp", binX, binX); + if (proj->GetEntries() < kMinEntriesForProjection) { + delete proj; + return -1.f; + } + float stddev = proj->GetStdDev(); + delete proj; + return stddev; + } + + float computeTrackLength(o2::track::TrackParCov track, float radius, float magneticField) + { + float length = -100; + o2::math_utils::CircleXYf_t trcCircle; + float sna, csa; + track.getCircleParams(magneticField, trcCircle, sna, csa); + + const float centerDistance = std::hypot(trcCircle.xC, trcCircle.yC); + + if (centerDistance < trcCircle.rC + radius && centerDistance > std::fabs(trcCircle.rC - radius)) { + length = 0.0f; + const float ux = trcCircle.xC / centerDistance; + const float uy = trcCircle.yC / centerDistance; + const float vx = -uy; + const float vy = +ux; + const float radical = (centerDistance * centerDistance - trcCircle.rC * trcCircle.rC + radius * radius) / (2.0f * centerDistance); + const float displace = (0.5f / centerDistance) * std::sqrt( + (-centerDistance + trcCircle.rC - radius) * + (-centerDistance - trcCircle.rC + radius) * + (-centerDistance + trcCircle.rC + radius) * + (centerDistance + trcCircle.rC + radius)); + + const float point1[2] = {radical * ux + displace * vx, radical * uy + displace * vy}; + const float point2[2] = {radical * ux - displace * vx, radical * uy - displace * vy}; + + std::array mom; + track.getPxPyPzGlo(mom); + const float scalarProduct1 = point1[0] * mom[0] + point1[1] * mom[1]; + const float scalarProduct2 = point2[0] * mom[0] + point2[1] * mom[1]; + + std::array startPoint; + track.getXYZGlo(startPoint); + + float cosAngle = -1000, modulus = -1000; + + if (scalarProduct1 > scalarProduct2) { + modulus = std::hypot(point1[0] - trcCircle.xC, point1[1] - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); + cosAngle = (point1[0] - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (point1[1] - trcCircle.yC) * (startPoint[1] - trcCircle.yC); + } else { + modulus = std::hypot(point2[0] - trcCircle.xC, point2[1] - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); + cosAngle = (point2[0] - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (point2[1] - trcCircle.yC) * (startPoint[1] - trcCircle.yC); + } + cosAngle /= modulus; + length = trcCircle.rC * std::acos(cosAngle); + length *= std::sqrt(1.0f + track.getTgl() * track.getTgl()); + } + return length; + } + + Produces tableUpgradeTrkPidSignals; + Produces tableUpgradeTrkPids; + + Service pdg; + Service ccdb; + std::unique_ptr mToTLUT; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable lutTotEl{"lutTotEl", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for electrons"}; + Configurable lutTotMu{"lutTotMu", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for muons"}; + Configurable lutTotPi{"lutTotPi", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for pions"}; + Configurable lutTotKa{"lutTotKa", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for kaons"}; + Configurable lutTotPr{"lutTotPr", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for protons"}; + Configurable lutTotDe{"lutTotDe", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for deuteron"}; + Configurable lutTotTr{"lutTotTr", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for triton"}; + Configurable lutTotHe{"lutTotHe", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for helium-3"}; + Configurable lutTotAl{"lutTotAl", "ccdb:Users/h/hfribert/ToT_LUTs", "ToT LUT for alphas"}; + + Configurable dBz{"dBz", 20, "magnetic field (kilogauss) for track propagation"}; + Configurable maxBarrelLayers{"maxBarrelLayers", 11, "Maximum number of barrel layers"}; + Configurable numLogBins{"numLogBins", 200, "Number of logarithmic momentum bins"}; + Configurable analysisEtaMin{"analysisEtaMin", 0.0f, "Minimum |eta| for LUT loading optimization"}; + Configurable analysisEtaMax{"analysisEtaMax", 1.0f, "Maximum |eta| for LUT loading optimization"}; + Configurable analysisPtMin{"analysisPtMin", 0.0f, "Minimum pT (GeV/c) for LUT loading optimization"}; + Configurable analysisPtMax{"analysisPtMax", 10.0f, "Maximum pT (GeV/c) for LUT loading optimization"}; + + std::vector mLogBins; + + std::array mHypothesisPdgCodes = { + 11, // Electron + 13, // Muon + 211, // Pion + 321, // Kaon + 2212, // Proton + 1000010020, // Deuteron + 1000010030, // Triton + 1000020030, // Helium-3 + 1000020040 // Alpha + }; + + void init(o2::framework::InitContext&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setTimestamp(-1); + + if (static_cast(maxBarrelLayers.value) > kTrackerRadii.size()) { + LOG(fatal) << "Configured maxBarrelLayers (" << maxBarrelLayers.value + << ") exceeds the size of kTrackerRadii (" << kTrackerRadii.size() + << "). Please adjust maxBarrelLayers."; + } + + mToTLUT = std::make_unique(maxBarrelLayers.value, analysisEtaMin.value, analysisEtaMax.value, analysisPtMin.value, analysisPtMax.value); + + mToTLUT->setCcdbManager(ccdb.operator->()); + + bool loaded = true; + loaded &= mToTLUT->load(11, lutTotEl.value); + loaded &= mToTLUT->load(13, lutTotMu.value); + loaded &= mToTLUT->load(211, lutTotPi.value); + loaded &= mToTLUT->load(321, lutTotKa.value); + loaded &= mToTLUT->load(2212, lutTotPr.value); + loaded &= mToTLUT->load(1000010020, lutTotDe.value); + loaded &= mToTLUT->load(1000010030, lutTotTr.value); + loaded &= mToTLUT->load(1000020030, lutTotHe.value); + loaded &= mToTLUT->load(1000020040, lutTotAl.value); + + if (!loaded) { + LOG(warning) << "Failed to load one or more ToT LUTs. PID results might be incomplete."; + } + + // Logarithmic momentum bins + mLogBins.clear(); + double pMin = kMinMomentumForLogBins; + double pMax = kMaxMomentumForLogBins; + double logMin = std::log10(pMin); + double logMax = std::log10(pMax); + double dLog = (logMax - logMin) / numLogBins.value; + for (int i = 0; i <= numLogBins.value; ++i) { + mLogBins.push_back(std::pow(10, logMin + i * dLog)); + } + + const AxisSpec axisMomentum{mLogBins, "#it{p/z} (GeV/#it{c})"}; + const AxisSpec axisToT{600, 0., 300., "ToT (#mus/10#mum)"}; + const AxisSpec axisNsigma{200, -10., 10., "N#sigma"}; + const AxisSpec axisLayer{maxBarrelLayers.value, -0.5, static_cast(maxBarrelLayers.value) - 0.5, "Layer"}; + const AxisSpec axisHitsPerTrack{maxBarrelLayers.value + 1, -0.5, static_cast(maxBarrelLayers.value) + 0.5, "# Hits per track"}; + + histos.add("hToTvsP", "ToT vs #it{p/z}; #it{p/z} (GeV/#it{c}); ToT (#mus/10#mum)", kTH2F, {axisMomentum, axisToT}); + histos.add("hToTvsPt", "ToT vs #it{p}; #it{p} (GeV/#it{c}); ToT (#mus/10#mum)", kTH2F, {mLogBins, axisToT}); + histos.add("hHitLayers", "Number of hits on each detector layer;Layer;Counts", kTH1F, {axisLayer}); + histos.add("hHitMultiplicity", "Hit multiplicity along the track; # Hits per track;Counts", kTH1F, {axisHitsPerTrack}); + + std::vector> particleInfo = { + {11, "Elec"}, {13, "Muon"}, {211, "Pion"}, {321, "Kaon"}, {2212, "Prot"}, {1000010020, "Deut"}, {1000010030, "Trit"}, {1000020030, "He3"}, {1000020040, "Al"}}; + + for (size_t iTrue = 0; iTrue < particleInfo.size(); ++iTrue) { + std::string trueName = particleInfo[iTrue].second; + std::string trueNamePretty = trueName; // Fallback + if (trueName == "Elec") + trueNamePretty = "#it{e}"; + else if (trueName == "Muon") + trueNamePretty = "#it{#mu}"; + else if (trueName == "Pion") + trueNamePretty = "#it{#pi}"; + else if (trueName == "Kaon") + trueNamePretty = "#it{K}"; + else if (trueName == "Prot") + trueNamePretty = "#it{p}"; + else if (trueName == "Deut") + trueNamePretty = "#it{d}"; + else if (trueName == "Trit") + trueNamePretty = "#it{t}"; + else if (trueName == "He3") + trueNamePretty = "#it{^{3}He}"; + else if (trueName == "Al") + trueNamePretty = "#it{^{4}He}"; + + std::string hitsVsPName = "HitsPerTrack/hHitsPerTrackVsP_" + trueName; + std::string hitsVsPTitle = "N_hits vs #it{p/z} for " + trueNamePretty + "; #it{p/z} (GeV/#it{c}); N_hits"; + h2dHitsPerTrackVsP[iTrue] = histos.add(hitsVsPName.c_str(), hitsVsPTitle.c_str(), kTH2F, {axisMomentum, axisHitsPerTrack}); + + std::string totVsPName = "ToTvsP/hToTvsP_" + trueName; + std::string totVsPTitle = "ToT vs #it{p/z} for " + trueNamePretty + "; #it{p/z} (GeV/#it{c}); ToT (#mus/10#mum)"; + h2dToTvsPperParticle[iTrue] = histos.add(totVsPName.c_str(), totVsPTitle.c_str(), kTH2F, {axisMomentum, axisToT}); + + for (size_t iHyp = 0; iHyp < particleInfo.size(); ++iHyp) { + std::string hypName = particleInfo[iHyp].second; + std::string hypNamePretty = hypName; // Fallback + if (hypName == "Elec") + hypNamePretty = "#it{e}"; + else if (hypName == "Muon") + hypNamePretty = "#it{#mu}"; + else if (hypName == "Pion") + hypNamePretty = "#it{#pi}"; + else if (hypName == "Kaon") + hypNamePretty = "#it{K}"; + else if (hypName == "Prot") + hypNamePretty = "#it{p}"; + else if (hypName == "Deut") + hypNamePretty = "#it{d}"; + else if (hypName == "Trit") + hypNamePretty = "#it{t}"; + else if (hypName == "He3") + hypNamePretty = "#it{^{3}He}"; + else if (hypName == "Al") + hypNamePretty = "#it{^{4}He}"; + + std::string histName = "NSigma/BarrelNsigmaTrue" + trueName + "Vs" + hypName + "Hypothesis"; + std::string histTitle = "Nsigma (True " + trueNamePretty + " vs Hyp " + hypNamePretty + "); #it{p/z} (GeV/#it{c}); N#sigma"; + h2dBarrelNsigmaTrue[iTrue][iHyp] = histos.add(histName.c_str(), histTitle.c_str(), kTH2F, {axisMomentum, axisNsigma}); + } + } + } + + void process(soa::Join::iterator const& collision, + soa::Join const& tracks, + aod::McParticles const& /*mcParticles*/, + aod::McCollisions const& /*mcCollisions*/) + { + o2::dataformats::VertexBase mcPvVtx({0.0f, 0.0f, 0.0f}, {0.}); + + if (collision.has_mcCollision()) { + const auto& mcCollisionObject = collision.mcCollision(); + mcPvVtx.setX(mcCollisionObject.posX()); + mcPvVtx.setY(mcCollisionObject.posY()); + mcPvVtx.setZ(mcCollisionObject.posZ()); + } + + for (const auto& track : tracks) { + float truncatedMeanToT = -1.0f; + std::array nSigmaValues; + nSigmaValues.fill(999.f); + + if (!track.has_mcParticle()) { + tableUpgradeTrkPidSignals(truncatedMeanToT); + tableUpgradeTrkPids(nSigmaValues[0], nSigmaValues[1], nSigmaValues[2], nSigmaValues[3], + nSigmaValues[4], nSigmaValues[5], nSigmaValues[6], nSigmaValues[7], nSigmaValues[8]); + continue; + } + + const auto& mcParticle = track.mcParticle(); + + const auto& pdgInfo = pdg->GetParticle(mcParticle.pdgCode()); + if (!pdgInfo) { + tableUpgradeTrkPidSignals(truncatedMeanToT); + tableUpgradeTrkPids(nSigmaValues[0], nSigmaValues[1], nSigmaValues[2], nSigmaValues[3], + nSigmaValues[4], nSigmaValues[5], nSigmaValues[6], nSigmaValues[7], nSigmaValues[8]); + continue; + } + + const float pt = mcParticle.pt(); + const float p = mcParticle.p(); + const float eta = mcParticle.eta(); + const int truePdgCode = std::abs(mcParticle.pdgCode()); + + float rigidity = p; + if (pdgInfo) { + const float trueCharge = std::abs(pdgInfo->Charge()) / 3.0f; + if (trueCharge > 0) { + rigidity = p / trueCharge; + } + } + + int truePdgIdx = mToTLUT->getPdgIndex(truePdgCode); + if (truePdgIdx == -1) { + tableUpgradeTrkPidSignals(truncatedMeanToT); + tableUpgradeTrkPids(nSigmaValues[0], nSigmaValues[1], nSigmaValues[2], nSigmaValues[3], + nSigmaValues[4], nSigmaValues[5], nSigmaValues[6], nSigmaValues[7], nSigmaValues[8]); + continue; + } + + const int binnedPt = mToTLUT->getPtBin(pt); + const int binnedEta = mToTLUT->getEtaBin(std::abs(eta)); + + uint16_t hitMap = 0; + int nHitLayers = 0; + o2::track::TrackParCov o2track = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdg); + + float xPv = -100.f; + static constexpr float kTrkXThreshold = -99.f; + if (o2track.propagateToDCA(mcPvVtx, dBz)) { + xPv = o2track.getX(); + } + + if (xPv > kTrkXThreshold) { + for (int layer = 0; layer < maxBarrelLayers.value; ++layer) { + float layerRadius = kTrackerRadii[layer]; + float trackLength = computeTrackLength(o2track, layerRadius, dBz); + + if (trackLength > 0) { + hitMap |= (1 << layer); + histos.fill(HIST("hHitLayers"), layer); + nHitLayers++; + } + } + } + + histos.fill(HIST("hHitMultiplicity"), nHitLayers); + h2dHitsPerTrackVsP[truePdgIdx]->Fill(rigidity, nHitLayers); + + std::vector validToTs; + + for (int layer = kMinLayerForTruncation; layer < maxBarrelLayers.value; ++layer) { + if ((hitMap >> layer) & 0x1) { + TH1F* totHist = mToTLUT->getHistogramForSampling(truePdgIdx, layer, binnedEta, binnedPt); + + if (totHist && totHist->GetEntries() > 1) { + float sampledToT = totHist->GetRandom(); + validToTs.push_back(sampledToT); + } + } + } + + truncatedMeanToT = -1.0f; + const size_t nValid = validToTs.size(); + size_t nUse = 0; + + if (nValid == kMidLowValidHits || nValid == kMidHighValidHits) + nUse = kMaxValidHitsForTruncation34; + else if (nValid == kMinValidHits || nValid == kLowValidHits) + nUse = kMaxValidHitsForTruncation12; + else if (nValid == kHighValidHits1 || nValid == kHighValidHits2) + nUse = kMaxValidHitsForTruncation56; + else if (nValid >= kMaxValidHits) + nUse = kMaxValidHitsForTruncation7Plus; + + if (nUse > 0 && nValid >= nUse) { + std::sort(validToTs.begin(), validToTs.end()); + float sum = 0.0f; + for (size_t i = 0; i < nUse; ++i) { + sum += validToTs[i]; + } + truncatedMeanToT = sum / static_cast(nUse); + + histos.fill(HIST("hToTvsPt"), p, truncatedMeanToT); + histos.fill(HIST("hToTvsP"), rigidity, truncatedMeanToT); + h2dToTvsPperParticle[truePdgIdx]->Fill(rigidity, truncatedMeanToT); + } + + nSigmaValues.fill(999.f); + + if (truncatedMeanToT > 0) { + for (size_t iHyp = 0; iHyp < mHypothesisPdgCodes.size(); ++iHyp) { + int hypPdgCode = mHypothesisPdgCodes[iHyp]; + int hypPdgIdx = mToTLUT->getPdgIndex(hypPdgCode); + + if (hypPdgIdx == -1) { + nSigmaValues[iHyp] = 999.f; + continue; + } + + float expectedToT = getToTMeanFromMomentumSlice(h2dToTvsPperParticle[hypPdgIdx], rigidity); + float resolution = getToTResolutionFromMomentumSlice(h2dToTvsPperParticle[hypPdgIdx], rigidity); + + if (expectedToT > 0 && resolution > 0) { + nSigmaValues[iHyp] = calculateNsigma(truncatedMeanToT, expectedToT, resolution); + h2dBarrelNsigmaTrue[truePdgIdx][iHyp]->Fill(rigidity, nSigmaValues[iHyp]); + } else { + nSigmaValues[iHyp] = 999.f; + } + } + } + + tableUpgradeTrkPidSignals(truncatedMeanToT); + tableUpgradeTrkPids(nSigmaValues[0], nSigmaValues[1], nSigmaValues[2], nSigmaValues[3], + nSigmaValues[4], nSigmaValues[5], nSigmaValues[6], nSigmaValues[7], nSigmaValues[8]); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/TableProducer/alice3-correlatorDDbar.cxx b/ALICE3/TableProducer/alice3-correlatorDDbar.cxx new file mode 100644 index 00000000000..b17216e9b76 --- /dev/null +++ b/ALICE3/TableProducer/alice3-correlatorDDbar.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. + +/// \file alice3-correlatorDDbar.cxx +/// \brief D0-D0bar correlator task - data-like and MC-reco analysis performance on ALICE 3 detector. +/// +/// \author Fabio Colamaria , INFN Bari + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" + +#include "ALICE3/DataModel/A3DecayFinderTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include + +using namespace o2; +using namespace o2::analysis; +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 phiD, double phiDbar) +{ + return RecoDecay::constrainAngle(phiDbar - phiD, -o2::constants::math::PIHalf); +} + +/// definition of variables for D0D0bar pairs vs eta acceptance studies (hDDbarVsEtaCut, in data-like, MC-reco and MC-kine tasks) +const double maxEtaCut = 5.; +const double ptThresholdForMaxEtaCut = 10.; +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 double efficiencyDmesonDefault[npTBinsMassAndEfficiency] = {}; +auto efficiencyDmeson_v = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsMassAndEfficiency}; + +// histogram binning definition +const int massAxisBins = 120; +const double massAxisMin = 1.5848; +const double massAxisMax = 2.1848; +const int phiAxisBins = 32; +const double phiAxisMin = 0.; +const double phiAxisMax = o2::constants::math::TwoPI; +const int yAxisBins = 100; +const double yAxisMin = -5.; +const double yAxisMax = 5.; +const int ptDAxisBins = 180; +const double ptDAxisMin = 0.; +const double ptDAxisMax = 36.; + +struct alice3correlatorddbar { + SliceCache cache; + Preslice perCol = aod::a3D0meson::collisionId; + Produces entryD0D0barPair; + Produces entryD0D0barRecoInfo; + + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; + Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; + Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying D-meson efficiency weights"}; + Configurable yCandMax{"yCandMax", 999., "max. cand. rapidity"}; + Configurable ptCandMin{"ptCandMin", -1., "min. cand. pT"}; + Configurable> binsPt{"binsPt", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots and efficiency"}; + Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmeson_v}, "Efficiency values for D0 meson"}; + + // HfHelper hfHelper; //not needed for now + + Partition> selectedCandidates = aod::a3D0meson::y > -yCandMax&& aod::a3D0meson::y ptCandMin && (aod::a3D0Selection::isSelD0 >= selectionFlagD0 || aod::a3D0Selection::isSelD0bar >= selectionFlagD0bar); + Partition> selectedCandidatesMC = aod::a3D0meson::y > -yCandMax&& aod::a3D0meson::y ptCandMin && (aod::a3D0Selection::isSelD0 >= selectionFlagD0 || aod::a3D0Selection::isSelD0bar >= selectionFlagD0bar); + + 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, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, + {"hPtProng0", "D0,D0bar candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, + {"hPtProng1", "D0,D0bar candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, 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, {{yAxisBins, yAxisMin, yAxisMax}}}}, + {"hPhi", "D0,D0bar candidates;candidate #it{#varphi};entries", {HistType::kTH1F, {{phiAxisBins, phiAxisMin, phiAxisMax}}}}, + {"hY", "D0,D0bar candidates;candidate #it{y};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, + {"hDDbarVsEtaCut", "D0,D0bar pairs vs #eta cut;#eta_{max};candidates #it{p}_{T} threshold (GeV/#it{c});entries", {HistType::kTH2F, {{static_cast(maxEtaCut / incrementEtaCut), 0., maxEtaCut}, {static_cast(ptThresholdForMaxEtaCut / incrementPtThreshold), 0., ptThresholdForMaxEtaCut}}}}, + {"hPtCandMCRec", "D0,D0bar candidates - MC reco;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, + {"hPtProng0MCRec", "D0,D0bar candidates - MC reco;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, + {"hPtProng1MCRec", "D0,D0bar candidates - MC reco;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{ptDAxisBins, ptDAxisMin, ptDAxisMax}}}}, + {"hSelectionStatusMCRec", "D0,D0bar candidates - MC reco;selection status;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}}, + {"hEtaMCRec", "D0,D0bar candidates - MC reco;candidate #it{#eta};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}, + {"hPhiMCRec", "D0,D0bar candidates - MC reco;candidate #it{#varphi};entries", {HistType::kTH1F, {{phiAxisBins, phiAxisMin, phiAxisMax}}}}, + {"hYMCRec", "D0,D0bar candidates - MC reco;candidate #it{y};entries", {HistType::kTH1F, {{yAxisBins, yAxisMin, yAxisMax}}}}}}; + + void init(InitContext&) + { + auto vbins = (std::vector)binsPt; + registry.add("hMass", "D0,D0bar candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0", "D0,D0bar candidates;inv. mass D0 only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0bar", "D0,D0bar candidates;inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0MCRecSig", "D0 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("hMassD0MCRecRefl", "D0 reflection 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("hMassD0MCRecBkg", "D0 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("hMassD0barMCRecSig", "D0bar signal candidates - MC reco;inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0barMCRecRefl", "D0bar reflection candidates - MC reco;inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0barMCRecBkg", "D0bar background candidates - MC reco;inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMass_NoEff", "D0,D0bar candidates (wo efficiency);inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0_NoEff", "D0,D0bar candidates (wo efficiency);inv. mass D0 only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0bar_NoEff", "D0,D0bar candidates (wo efficiency);inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0MCRecSig_NoEff", "D0 signal candidates - MC reco (wo efficiency);inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0MCRecRefl_NoEff", "D0 reflection candidates - MC reco (wo efficiency);inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0MCRecBkg_NoEff", "D0 background candidates - MC reco (wo efficiency);inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0barMCRecSig_NoEff", "D0bar signal candidates - MC reco (wo efficiency);inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0barMCRecRefl_NoEff", "D0bar reflection candidates - MC reco (wo efficiency);inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassD0barMCRecBkg_NoEff", "D0bar background candidates - MC reco (wo efficiency);inv. mass D0bar only (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{massAxisBins, massAxisMin, massAxisMax}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + } + + /// D0-D0bar 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&) + { + auto selectedCandidatesGrouped = selectedCandidates->sliceByCached(aod::a3D0meson::collisionId, collision.globalIndex(), cache); + + for (const auto& candidate1 : selectedCandidatesGrouped) { // loop over reconstructed and selected D0 and D0bar (together, to fill mass plots first) + double efficiencyWeight = 1.; + if (applyEfficiency) { + efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); + } + + // fill invariant mass plots and generic info from all D0/D0bar candidates + if (candidate1.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMass"), candidate1.m(), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0"), candidate1.m(), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMass_NoEff"), candidate1.m(), candidate1.pt()); + registry.fill(HIST("hMassD0_NoEff"), candidate1.m(), candidate1.pt()); + } + if (candidate1.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMass"), candidate1.m(), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0bar"), candidate1.m(), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMass_NoEff"), candidate1.m(), candidate1.pt()); + registry.fill(HIST("hMassD0bar_NoEff"), candidate1.m(), candidate1.pt()); + } + 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"), candidate1.y()); + registry.fill(HIST("hSelectionStatus"), candidate1.isSelD0() + (candidate1.isSelD0bar() * 2)); + + // D-Dbar correlation dedicated section + + // if the candidate is a D0, search for D0bar and evaluate correlations + if (candidate1.isSelD0() < selectionFlagD0) { + continue; + } + for (const auto& candidate2 : selectedCandidatesGrouped) { + if (candidate2.isSelD0bar() < selectionFlagD0bar) { // keep only D0bar candidates passing the selection + continue; + } + // excluding trigger self-correlations (possible in case of both mass hypotheses accepted) + if (candidate1.mRowIndex == candidate2.mRowIndex) { // this by definition should never happen, since each candidate is either D0 or D0bar + continue; + } + if ((candidate1.pt() - candidate2.pt()) < 1e-5 && (candidate1.eta() - candidate2.eta()) < 1e-5 && (candidate1.phi() - candidate2.phi()) < 1e-5) { // revised, temporary condition to avoid self-correlations (the best would be check the daughterIDs, but we don't store them at the moment) + continue; + } + entryD0D0barPair(getDeltaPhi(candidate2.phi(), candidate1.phi()), + candidate2.eta() - candidate1.eta(), + candidate1.pt(), + candidate2.pt()); + entryD0D0barRecoInfo(candidate1.m(), // mD0 + candidate2.m(), // mD0bar + 0); + double etaCut = 0.; + double ptCut = 0.; + do { // fill pairs vs etaCut plot + ptCut = 0.; + etaCut += incrementEtaCut; + do { // fill pairs vs etaCut plot + if (std::abs(candidate1.eta()) < etaCut && std::abs(candidate2.eta()) < etaCut && candidate1.pt() > ptCut && candidate2.pt() > ptCut) { + registry.fill(HIST("hDDbarVsEtaCut"), etaCut - epsilon, ptCut + epsilon); + } + ptCut += incrementPtThreshold; + } while (ptCut < ptThresholdForMaxEtaCut - epsilon); + } while (etaCut < maxEtaCut - epsilon); + // note: candidates selected as both D0 and D0bar are used, and considered in both situation (but not auto-correlated): reflections could play a relevant role. + // another, more restrictive, option, could be to consider only candidates selected with a single option (D0 xor D0bar) + + } // end inner loop (Dbars) + + } // end outer loop + } + + PROCESS_SWITCH(alice3correlatorddbar, processData, "Process data", true); + + /// D0-D0bar correlation pair builder - for MC reco-level analysis (candidates matched to true signal only, but also the various bkg sources are studied) + void processMcRec(aod::Collision const& collision, + soa::Join const&) + { + auto selectedCandidatesGroupedMC = selectedCandidatesMC->sliceByCached(aod::a3D0meson::collisionId, collision.globalIndex(), cache); + + // MC reco level + bool flagD0Signal = false; + bool flagD0Reflection = false; + bool flagD0barSignal = false; + bool flagD0barReflection = false; + for (const auto& candidate1 : selectedCandidatesGroupedMC) { + double efficiencyWeight = 1.; + if (applyEfficiency) { + efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); + } + + if (candidate1.mcTruthInfo()) { // 1 or 2, i.e. true D0 or D0bar + // fill per-candidate distributions from D0/D0bar true candidates + registry.fill(HIST("hPtCandMCRec"), candidate1.pt()); + registry.fill(HIST("hPtProng0MCRec"), candidate1.ptProng0()); + registry.fill(HIST("hPtProng1MCRec"), candidate1.ptProng1()); + registry.fill(HIST("hEtaMCRec"), candidate1.eta()); + registry.fill(HIST("hPhiMCRec"), candidate1.phi()); + registry.fill(HIST("hYMCRec"), candidate1.y()); + registry.fill(HIST("hSelectionStatusMCRec"), candidate1.isSelD0() + (candidate1.isSelD0bar() * 2)); + } + // fill invariant mass plots from D0/D0bar signal and background candidates + if (candidate1.isSelD0() >= selectionFlagD0) { // only reco as D0 + if (candidate1.mcTruthInfo() == 1) { // also matched as D0 + registry.fill(HIST("hMassD0MCRecSig"), candidate1.m(), candidate1.pt(), efficiencyWeight); // here m is univoque, since a given candidate passes the selection with only a single mass option + registry.fill(HIST("hMassD0MCRecSig_NoEff"), candidate1.m(), candidate1.pt()); + } else if (candidate1.mcTruthInfo() == 2) { + registry.fill(HIST("hMassD0MCRecRefl"), candidate1.m(), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0MCRecRefl_NoEff"), candidate1.m(), candidate1.pt()); + } else { + registry.fill(HIST("hMassD0MCRecBkg"), candidate1.m(), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0MCRecBkg_NoEff"), candidate1.m(), candidate1.pt()); + } + } + if (candidate1.isSelD0bar() >= selectionFlagD0bar) { // only reco as D0bar + if (candidate1.mcTruthInfo() == 2) { // also matched as D0bar + registry.fill(HIST("hMassD0barMCRecSig"), candidate1.m(), candidate1.pt(), efficiencyWeight); // here m is univoque, since a given candidate passes the selection with only a single mass option + registry.fill(HIST("hMassD0barMCRecSig_NoEff"), candidate1.m(), candidate1.pt()); + } else if (candidate1.mcTruthInfo() == 1) { + registry.fill(HIST("hMassD0barMCRecRefl"), candidate1.m(), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0barMCRecRefl_NoEff"), candidate1.m(), candidate1.pt()); + } else { + registry.fill(HIST("hMassD0barMCRecBkg"), candidate1.m(), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0barMCRecBkg_NoEff"), candidate1.m(), candidate1.pt()); + } + } + + // D-Dbar correlation dedicated section + // if the candidate is selected ad D0, search for D0bar and evaluate correlations + if (candidate1.isSelD0() < selectionFlagD0) { // discard candidates not selected as D0 in outer loop + continue; + } + + flagD0Signal = candidate1.mcTruthInfo() == 1; // flagD0Signal 'true' if candidate1 matched to D0 (particle) + flagD0Reflection = candidate1.mcTruthInfo() == 2; // flagD0Reflection 'true' if candidate1, selected as D0 (particle), is matched to D0bar (antiparticle) + + for (const auto& candidate2 : selectedCandidatesGroupedMC) { + if (candidate2.isSelD0bar() < selectionFlagD0bar) { // discard candidates not selected as D0bar in inner loop + continue; + } + flagD0barSignal = candidate2.mcTruthInfo() == 2; // flagD0barSignal 'true' if candidate2 matched to D0bar (antiparticle) + flagD0barReflection = candidate2.mcTruthInfo() == 1; // flagD0barReflection 'true' if candidate2, selected as D0bar (antiparticle), is matched to D0 (particle) + + // Excluding trigger self-correlations (possible in case of both mass hypotheses of the same real particle, reconstructed as candidate1 for D0 and candidate2 for D0bar) + if (candidate1.mRowIndex == candidate2.mRowIndex) { // this by definition should never happen, since each candidate is either D0 or D0bar + continue; + } + if ((candidate1.pt() - candidate2.pt()) < 1e-5 && (candidate1.eta() - candidate2.eta()) < 1e-5 && (candidate1.phi() - candidate2.phi()) < 1e-5) { // revised, temporary condition to avoid self-correlations (the best would be check the daughterIDs, but we don't store them at the moment) + continue; + } + // choice of options (D0/D0bar signal/bkg) + int pairSignalStatus = 0; // 0 = bkg/bkg, 1 = bkg/ref, 2 = bkg/sig, 3 = ref/bkg, 4 = ref/ref, 5 = ref/sig, 6 = sig/bkg, 7 = sig/ref, 8 = sig/sig + if (flagD0Signal) { + pairSignalStatus += 6; + } + if (flagD0Reflection) { + pairSignalStatus += 3; + } + if (flagD0barSignal) { + pairSignalStatus += 2; + } + if (flagD0barReflection) { + pairSignalStatus += 1; + } + entryD0D0barPair(getDeltaPhi(candidate2.phi(), candidate1.phi()), + candidate2.eta() - candidate1.eta(), + candidate1.pt(), + candidate2.pt()); + entryD0D0barRecoInfo(candidate1.m(), // mD0 + candidate2.m(), // mD0bar + pairSignalStatus); + double etaCut = 0.; + double ptCut = 0.; + do { // fill pairs vs etaCut plot + ptCut = 0.; + etaCut += incrementEtaCut; + do { // fill pairs vs etaCut plot + if (std::abs(candidate1.eta()) < etaCut && std::abs(candidate2.eta()) < etaCut && candidate1.pt() > ptCut && candidate2.pt() > ptCut) { + registry.fill(HIST("hDDbarVsEtaCut"), etaCut - epsilon, ptCut + epsilon); + } + ptCut += incrementPtThreshold; + } while (ptCut < ptThresholdForMaxEtaCut - epsilon); + } while (etaCut < maxEtaCut - epsilon); + } // end inner loop (Dbars) + + } // end outer loop + } + + PROCESS_SWITCH(alice3correlatorddbar, processMcRec, "Process MC Reco mode", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/TableProducer/alice3-decayfinder.cxx b/ALICE3/TableProducer/alice3-decayfinder.cxx index 80b9de80238..a0a6e319055 100644 --- a/ALICE3/TableProducer/alice3-decayfinder.cxx +++ b/ALICE3/TableProducer/alice3-decayfinder.cxx @@ -17,38 +17,44 @@ // 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 "ALICE3/DataModel/A3DecayFinderTables.h" +#include "ALICE3/DataModel/OTFPIDTrk.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/RICH.h" +#include "ALICE3/Utils/utilsHfAlice3.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/Core/trackUtilities.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 "DCAFitter/DCAFitterN.h" #include "DataFormatsCalibration/MeanVertexObject.h" -#include "ALICE3/DataModel/OTFTOF.h" -#include "ALICE3/DataModel/RICH.h" -#include "ALICE3/DataModel/A3DecayFinderTables.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; +using namespace o2::analysis; using namespace o2::framework; +using namespace o2::constants::physics; using namespace o2::framework::expressions; using std::array; @@ -57,164 +63,34 @@ using std::array; #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 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); - //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* -}; +using Alice3TracksWPid = soa::Join; struct alice3decayFinder { SliceCache cache; + Produces candidateD0meson; // contains D0 and D0bar selected candidates (separated, i.e. each row with a single mass hypothesis) + Produces selectionOutcome; // flags for isSelD0 and isSelD0bar + Produces mcTruthOutcome; // contains MC truth info (is true D0, true D0bar, or bkg) + Produces candidate3Prong; // contains Lc selected candidates + Produces mcRecFlags; // contains MC truth info (is true Lc, or bkg) + Produces pidInfoLcDaugs; // contains PID info for Lc candidates + Produces mcGenFlags; // contains MC gen info for 3-prong candidates + + // Vertexing + 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", 1e9, "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable maxVtxChi2{"maxVtxChi2", 1e9, "reject (if>0) vtx. chi2 above this value"}; + 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"}; // Operation and minimisation criteria Configurable magneticField{"magneticField", 20.0f, "Magnetic field (in kilogauss)"}; Configurable doDCAplotsD{"doDCAplotsD", true, "do daughter prong DCA plots for D mesons"}; - Configurable doDCAplotsLc{"doDCAplotsLc", true, "do daughter prong DCA plots for Lc baryons"}; + Configurable doDCAplots3Prong{"doDCAplots3Prong", true, "do daughter prong DCA plots for Lc baryons"}; + Configurable doTopoPlotsForSAndB{"doTopoPlotsForSAndB", true, "do topological variable distributions for S and B separately"}; Configurable mcSameMotherCheck{"mcSameMotherCheck", true, "check if tracks come from the same MC mother"}; Configurable dcaDaughtersSelection{"dcaDaughtersSelection", 1000.0f, "DCA between daughters (cm)"}; @@ -223,6 +99,26 @@ 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: low pt"}; + Configurable DCosPAHighPt{"DCosPAHighPt", 0.995, " Cos of pointing angle: high pt"}; + Configurable DCosPAxy{"DCosPAxy", 0.99, " Cos of pointing angle xy: low pt"}; + Configurable DCosPAxyHighPt{"DCosPAxyHighPt", 0.995, " Cos of pointing angle xy: DCosPAxyHighPt pt"}; + Configurable DCosThetaStarLowPt{"DCosThetaStarLowPt", 0.8, "Cos theta; low pt"}; + Configurable DCosThetaStarHighPt{"DCosThetaStarHighPt", 0.9, "Cos theta; high pt"}; + Configurable DCosThetaStarVHighPt{"DCosThetaStarVHighPt", 1.0, "Cos theta; very high pt"}; + Configurable DDecayLengthSquaredCut{"DDecayLengthSquaredCut", 0., "Flat component of squared decay length cut (only for LoI legacy)"}; + Configurable DMinDecayLength{"DMinDecayLength", 0., "Minimum D decay length (3D)"}; + Configurable DMaxDecayLength{"DMaxDecayLength", 10., "Maximum D decay length (3D)"}; + Configurable DMinDecayLengthXY{"DMinDecayLengthXY", 0., "Minimum D decay length (xy)"}; + Configurable DMaxDecayLengthXY{"DMaxDecayLengthXY", 10., "Maximum D decay length (xy)"}; + Configurable DMinNormDecayLength{"DMinNormDecayLength", 3, "Minimum normalized decay length"}; + Configurable DMaxNormDecayLength{"DMaxNormDecayLength", 3, "Maximum normalized decay length"}; + Configurable minPtPi{"minPtPi", 0., "Minimum pT of daughter pion track"}; + Configurable minPtK{"minPtK", 0., "Minimum pT of daughter kaon track"}; + Configurable maxImpParPi{"maxImpParPi", 1., "Maximum impact paramter of daughter pion track"}; + Configurable maxImpParK{"maxImpParK", 1., "Maximum impact paramter of daughter kaon track"}; + Configurable maxImpParProduct{"maxImpParProduct", 0., "Maximum daughter impact paramter product"}; + 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"}; @@ -230,15 +126,27 @@ struct alice3decayFinder { Configurable prFromLc_dcaXYconstant{"prFromLc_dcaXYconstant", -1.0f, "[0] in |DCAxy| > [0]+[1]/pT"}; Configurable prFromLc_dcaXYpTdep{"prFromLc_dcaXYpTdep", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable lowPtDLimit{"lowPtDLimit", 3.5, "Upper boundary of low pT D range, for topological selection (GeV/c)"}; + Configurable highPtDLimit{"highPtDLimit", 16, "Upper boundary of high pT D range, for topological selection (GeV/c)"}; + ConfigurableAxis axisEta{"axisEta", {8, -4.0f, +4.0f}, "#eta"}; + ConfigurableAxis axisY{"axisY", {12, -6.0f, +6.0f}, "y"}; 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})"}; o2::vertexing::DCAFitterN<2> fitter; o2::vertexing::DCAFitterN<3> fitter3; + double bz{0.}; + const float toMicrometers{10000.}; // from cm to µm + std::array daugsPdgCodes3Prong{{-1, -1, -1}}; + std::array daughtersMasses3Prong{{-1.f, -1.f, -1.f}}; + int motherPdgCode{-1}; + int charmHadFlag{0}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; Partition trueD = aod::mcparticle::pdgCode == 421; @@ -261,45 +169,86 @@ struct alice3decayFinder { static constexpr uint32_t trackSelectionPrMinusFromLc = 1 << kInnerTOFProton | 1 << kOuterTOFProton | 1 << kRICHProton | 1 << kTruePrMinusFromLc; // 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); - Partition tracksPiMinusFromD = + Partition tracksPiPlusFromD = + ((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 = + Partition tracksKaPlusFromD = ((aod::a3DecayMap::decayMap & trackSelectionKaPlusFromD) == trackSelectionKaPlusFromD) && aod::track::signed1Pt > 0.0f && nabs(aod::track::dcaXY) > kaFromD_dcaXYconstant + kaFromD_dcaXYpTdep* nabs(aod::track::signed1Pt); - Partition tracksKaMinusFromD = + Partition tracksKaMinusFromD = ((aod::a3DecayMap::decayMap & trackSelectionKaMinusFromD) == trackSelectionKaMinusFromD) && aod::track::signed1Pt < 0.0f && nabs(aod::track::dcaXY) > kaFromD_dcaXYconstant + kaFromD_dcaXYpTdep* nabs(aod::track::signed1Pt); // partitions for Lc baryons - Partition tracksPiPlusFromLc = + Partition tracksPiPlusFromLc = ((aod::a3DecayMap::decayMap & trackSelectionPiPlusFromLc) == trackSelectionPiPlusFromLc) && aod::track::signed1Pt > 0.0f && nabs(aod::track::dcaXY) > piFromLc_dcaXYconstant + piFromLc_dcaXYpTdep* nabs(aod::track::signed1Pt); - Partition tracksKaPlusFromLc = + Partition tracksKaPlusFromLc = ((aod::a3DecayMap::decayMap & trackSelectionKaPlusFromLc) == trackSelectionKaPlusFromLc) && aod::track::signed1Pt > 0.0f && nabs(aod::track::dcaXY) > kaFromLc_dcaXYconstant + kaFromLc_dcaXYpTdep* nabs(aod::track::signed1Pt); - Partition tracksPrPlusFromLc = + Partition tracksPrPlusFromLc = ((aod::a3DecayMap::decayMap & trackSelectionPrPlusFromLc) == trackSelectionPrPlusFromLc) && aod::track::signed1Pt > 0.0f && nabs(aod::track::dcaXY) > prFromLc_dcaXYconstant + prFromLc_dcaXYpTdep* nabs(aod::track::signed1Pt); // partitions for Lc baryons - Partition tracksPiMinusFromLc = + Partition tracksPiMinusFromLc = ((aod::a3DecayMap::decayMap & trackSelectionPiMinusFromLc) == trackSelectionPiMinusFromLc) && aod::track::signed1Pt < 0.0f && nabs(aod::track::dcaXY) > piFromLc_dcaXYconstant + piFromLc_dcaXYpTdep* nabs(aod::track::signed1Pt); - Partition tracksKaMinusFromLc = + Partition tracksKaMinusFromLc = ((aod::a3DecayMap::decayMap & trackSelectionKaMinusFromLc) == trackSelectionKaMinusFromLc) && aod::track::signed1Pt < 0.0f && nabs(aod::track::dcaXY) > kaFromLc_dcaXYconstant + kaFromLc_dcaXYpTdep* nabs(aod::track::signed1Pt); - Partition tracksPrMinusFromLc = + Partition tracksPrMinusFromLc = ((aod::a3DecayMap::decayMap & trackSelectionPrMinusFromLc) == trackSelectionPrMinusFromLc) && aod::track::signed1Pt < 0.0f && nabs(aod::track::dcaXY) > prFromLc_dcaXYconstant + prFromLc_dcaXYpTdep* nabs(aod::track::signed1Pt); // Helper struct to pass candidate information struct { + float dcaDau; float mass; + std::array posSV; + std::array P; + std::array Pdaug; // positive track + std::array Ndaug; // negative track float pt; + float ptdaugPos; + float ptdaugNeg; + float phi; float eta; + float y; + float cosPA; + float cosPAxy; + float cosThetaStar; + float normalizedDecayLength; + int mcTruth; // 0 = bkg, 1 = D0, 2 = D0bar } dmeson; struct { + float dcaDau; float mass; float pt; + float phi; float eta; - } lcbaryon; + std::array Pdaug0; // proton track + std::array Pdaug1; // kaon track + std::array Pdaug2; // pion track + std::array primaryVertex; // primary vertex coordinates + std::array secondaryVertex; // secondary vertex coordinates + float impactParameterY0; // impact parameters + float errorImpactParameterY0; // impact parameters error + float impactParameterY1; // impact parameters + float errorImpactParameterY1; // impact parameters error + float impactParameterY2; // impact parameters + float errorImpactParameterY2; // impact parameters error + float impactParameterZ0; // impact parameters + float errorImpactParameterZ0; // impact parameters error + float impactParameterZ1; // impact parameters + float errorImpactParameterZ1; // impact parameters error + float impactParameterZ2; // impact parameters + float errorImpactParameterZ2; // impact parameters error + float errorDecayLength; // normalized 3D decay length + float errorDecayLengthXY; // normalized 3D decay length + float chi2PCA; // normalized 3D decay length + int flagMc; // 0 = bkg, CharmHadAlice3 otherwise + int origin; // 1 = prompt, 2 = non-prompt + float ptBMotherRec; // pT of the B hadron mother (reconstructed) + } cand3prong; template - bool buildDecayCandidateTwoBody(TTrackType const& posTrackRow, TTrackType const& negTrackRow, float posMass, float negMass) + bool buildDecayCandidateTwoBody(TTrackType const& posTrackRow, TTrackType const& negTrackRow, float posMass, float negMass, aod::McParticles const& mcParticles) { o2::track::TrackParCov posTrack = getTrackParCov(posTrackRow); o2::track::TrackParCov negTrack = getTrackParCov(negTrackRow); @@ -323,31 +272,66 @@ struct alice3decayFinder { std::array negP; posTrack.getPxPyPzGlo(posP); negTrack.getPxPyPzGlo(negP); + dmeson.dcaDau = TMath::Sqrt(fitter.getChi2AtPCACandidate()); + dmeson.Pdaug[0] = posP[0]; + dmeson.Pdaug[1] = posP[1]; + dmeson.Pdaug[2] = posP[2]; + dmeson.Ndaug[0] = negP[0]; + dmeson.Ndaug[1] = negP[1]; + dmeson.Ndaug[2] = negP[2]; - float dcaDau = TMath::Sqrt(fitter.getChi2AtPCACandidate()); - if (dcaDau > dcaDaughtersSelection) - return false; - - // return mass + // return mass and kinematic variables 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.ptdaugPos = std::hypot(posP[0], posP[1]); + dmeson.ptdaugNeg = std::hypot(negP[0], negP[1]); + dmeson.phi = RecoDecay::phi(array{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]}); + dmeson.y = RecoDecay::y(std::array{posP[0] + negP[0], posP[1] + negP[1], posP[2] + negP[2]}, dmeson.mass); + 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); + + // MC truth check + int indexRec = -1; + int8_t sign = 0; + auto arrayDaughters = std::array{posTrackRow, negTrackRow}; + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign); + if (indexRec < 0) { + dmeson.mcTruth = 0; // bkg + } else { + if (sign > 0) { + dmeson.mcTruth = 1; // D0 + } else { + dmeson.mcTruth = 2; // D0bar + } + } + return true; } template - bool buildDecayCandidateThreeBody(TTrackType const& prong0, TTrackType const& prong1, TTrackType const& prong2, float p0mass, float p1mass, float p2mass) + bool buildDecayCandidateThreeBody(aod::Collision const& collision, TTrackType const& prong0, TTrackType const& prong1, TTrackType const& prong2, aod::McParticles const& mcParticles) { - o2::track::TrackParCov t0 = getTrackParCov(prong0); - o2::track::TrackParCov t1 = getTrackParCov(prong1); - o2::track::TrackParCov t2 = getTrackParCov(prong2); + // get the collision primary vertex + auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + + o2::track::TrackParCov trackParVar0 = getTrackParCov(prong0); + o2::track::TrackParCov trackParVar1 = getTrackParCov(prong1); + o2::track::TrackParCov trackParVar2 = getTrackParCov(prong2); //}-{}-{}-{}-{}-{}-{}-{}-{}-{} // Move close to minima int nCand = 0; try { - nCand = fitter3.process(t0, t1, t2); + nCand = fitter3.process(trackParVar0, trackParVar1, trackParVar2); } catch (...) { + LOG(info) << "Second vertex fit failed"; return false; } if (nCand == 0) { @@ -355,24 +339,102 @@ struct alice3decayFinder { } //}-{}-{}-{}-{}-{}-{}-{}-{}-{} - t0 = fitter.getTrack(0); - t1 = fitter.getTrack(1); - t2 = fitter.getTrack(2); - std::array P0; - std::array P1; - std::array P2; - t0.getPxPyPzGlo(P0); - t1.getPxPyPzGlo(P1); - t2.getPxPyPzGlo(P2); - - float dcaDau = TMath::Sqrt(fitter3.getChi2AtPCACandidate()); - if (dcaDau > dcaDaughtersSelection) + auto covMatrixPCA = fitter3.calcPCACovMatrixFlat(); + cand3prong.chi2PCA = fitter3.getChi2AtPCACandidate(); + cand3prong.dcaDau = TMath::Sqrt(fitter3.getChi2AtPCACandidate()); + if (cand3prong.dcaDau > dcaDaughtersSelection) { return false; + } + + cand3prong.primaryVertex = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; + auto secondaryVertex = fitter3.getPCACandidate(); + cand3prong.secondaryVertex = {secondaryVertex[0], secondaryVertex[1], secondaryVertex[2]}; + + trackParVar0 = fitter3.getTrack(0); + trackParVar1 = fitter3.getTrack(1); + trackParVar2 = fitter3.getTrack(2); + + std::array P0{}; + std::array P1{}; + std::array P2{}; + trackParVar0.getPxPyPzGlo(P0); + trackParVar1.getPxPyPzGlo(P1); + trackParVar2.getPxPyPzGlo(P2); + + o2::dataformats::DCA impactParameter0; + o2::dataformats::DCA impactParameter1; + o2::dataformats::DCA impactParameter2; + trackParVar0.propagateToDCA(primaryVertex, bz, &impactParameter0); + trackParVar1.propagateToDCA(primaryVertex, bz, &impactParameter1); + trackParVar2.propagateToDCA(primaryVertex, bz, &impactParameter2); + histos.fill(HIST("hDcaXYProngs"), prong0.pt(), impactParameter0.getY() * toMicrometers); + histos.fill(HIST("hDcaXYProngs"), prong1.pt(), impactParameter1.getY() * toMicrometers); + histos.fill(HIST("hDcaXYProngs"), prong2.pt(), impactParameter2.getY() * toMicrometers); + histos.fill(HIST("hDcaZProngs"), prong0.pt(), impactParameter0.getZ() * toMicrometers); + histos.fill(HIST("hDcaZProngs"), prong1.pt(), impactParameter1.getZ() * toMicrometers); + histos.fill(HIST("hDcaZProngs"), prong2.pt(), impactParameter2.getZ() * toMicrometers); + + // get uncertainty of the decay length + double phi, theta; + getPointDirection(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, secondaryVertex, phi, theta); + cand3prong.errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + cand3prong.errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + + cand3prong.impactParameterY0 = impactParameter0.getY(); + cand3prong.errorImpactParameterY0 = impactParameter0.getSigmaY2(); + cand3prong.impactParameterY1 = impactParameter1.getY(); + cand3prong.errorImpactParameterY1 = impactParameter1.getSigmaY2(); + cand3prong.impactParameterY2 = impactParameter2.getY(); + cand3prong.errorImpactParameterY2 = impactParameter2.getSigmaY2(); + + cand3prong.impactParameterZ0 = impactParameter0.getZ(); + cand3prong.errorImpactParameterZ0 = impactParameter0.getSigmaZ2(); + cand3prong.impactParameterZ1 = impactParameter1.getZ(); + cand3prong.errorImpactParameterZ1 = impactParameter1.getSigmaZ2(); + cand3prong.impactParameterZ2 = impactParameter2.getZ(); + cand3prong.errorImpactParameterZ2 = impactParameter2.getSigmaZ2(); // return mass - lcbaryon.mass = RecoDecay::m(array{array{P0[0], P0[1], P0[2]}, array{P1[0], P1[1], P1[2]}, array{P2[0], P2[1], P2[2]}}, array{p0mass, p1mass, p2mass}); - lcbaryon.pt = std::hypot(P0[0] + P1[0] + P2[0], P0[1] + P1[1] + P2[1]); - lcbaryon.eta = RecoDecay::eta(array{P0[0] + P1[0] + P2[0], P0[1] + P1[1] + P2[1], P0[2] + P1[2] + P2[2]}); + cand3prong.mass = RecoDecay::m(array{array{P0[0], P0[1], P0[2]}, + array{P1[0], P1[1], P1[2]}, + array{P2[0], P2[1], P2[2]}}, + daughtersMasses3Prong); + + cand3prong.pt = std::hypot(P0[0] + P1[0] + P2[0], P0[1] + P1[1] + P2[1]); + cand3prong.phi = RecoDecay::phi(array{P0[0] + P1[0] + P2[0], P0[1] + P1[1] + P2[1]}); + cand3prong.eta = RecoDecay::eta(array{P0[0] + P1[0] + P2[0], P0[1] + P1[1] + P2[1], P0[2] + P1[2] + P2[2]}); + cand3prong.Pdaug0[0] = P0[0]; + cand3prong.Pdaug0[1] = P0[1]; + cand3prong.Pdaug0[2] = P0[2]; + cand3prong.Pdaug1[0] = P1[0]; + cand3prong.Pdaug1[1] = P1[1]; + cand3prong.Pdaug1[2] = P1[2]; + cand3prong.Pdaug2[0] = P2[0]; + cand3prong.Pdaug2[1] = P2[1]; + cand3prong.Pdaug2[2] = P2[2]; + + // MC truth check + cand3prong.flagMc = 0; // bkg + int8_t sign = 0; + auto arrayDaughters = std::array{prong0, prong1, prong2}; + int indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, motherPdgCode, daugsPdgCodes3Prong, true, &sign, 2); + auto motherPart = mcParticles.rawIteratorAt(indexRec); + if (indexRec > -1) { + cand3prong.flagMc = motherPart.pdgCode() > 0 ? charmHadFlag : -charmHadFlag; // Particle + } + + cand3prong.origin = 0; + if (indexRec > -1) { + auto motherParticle = mcParticles.rawIteratorAt(indexRec); + std::vector idxBhadMothers{}; + int origin = RecoDecay::getCharmHadronOrigin(mcParticles, motherParticle, false, &idxBhadMothers); + cand3prong.origin = origin; + cand3prong.ptBMotherRec = -1.f; + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + cand3prong.ptBMotherRec = bHadMother.pt(); + } + } return true; } @@ -402,84 +464,206 @@ struct alice3decayFinder { 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.setPropagateToPCA(propagateToPCA); + fitter.setMaxR(maxR); + fitter.setMinParamChange(minParamChange); + fitter.setMinRelChi2Change(minRelChi2Change); + fitter.setMaxDZIni(maxDZIni); + fitter.setMaxChi2(maxVtxChi2); + fitter.setUseAbsDCA(useAbsDCA); + fitter.setWeightedFinalPCA(useWeightedFinalPCA); 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.setPropagateToPCA(propagateToPCA); + fitter3.setMaxR(maxR); + fitter3.setMinParamChange(minParamChange); + fitter3.setMinRelChi2Change(minRelChi2Change); + fitter3.setMaxDZIni(maxDZIni); + fitter3.setMaxChi2(maxVtxChi2); + fitter3.setUseAbsDCA(useAbsDCA); + fitter3.setWeightedFinalPCA(useWeightedFinalPCA); fitter3.setBz(magneticField); fitter3.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); if (doprocessFindDmesons) { histos.add("h2dGenD", "h2dGenD", kTH2F, {axisPt, axisEta}); + histos.add("h2dGenD_KpiOnly", "h2dGenD_KpiOnly", kTH2F, {axisPt, axisEta}); histos.add("h2dGenDbar", "h2dGenDbar", kTH2F, {axisPt, axisEta}); - histos.add("h3dRecD", "h2dRecD", kTH3F, {axisPt, axisEta, axisDMass}); - histos.add("h3dRecDbar", "h2dRecDbar", kTH3F, {axisPt, axisEta, axisDMass}); + histos.add("h2dGenDbar_KpiOnly", "h2dGenDbar_KpiOnly", kTH2F, {axisPt, axisEta}); + histos.add("h3dRecD", "h3dRecD", kTH3F, {axisPt, axisEta, axisDMass}); + histos.add("h3dRecDSig", "h3dRecDSig", kTH3F, {axisPt, axisEta, axisDMass}); + histos.add("h3dRecDRefl", "h3dRecDRefl", kTH3F, {axisPt, axisEta, axisDMass}); + histos.add("h3dRecDBkg", "h3dRecDBkg", kTH3F, {axisPt, axisEta, axisDMass}); + histos.add("h3dRecDbar", "h3dRecDbar", kTH3F, {axisPt, axisEta, axisDMass}); + histos.add("h3dRecDbarSig", "h3dRecDbarSig", kTH3F, {axisPt, axisEta, axisDMass}); + histos.add("h3dRecDbarRefl", "h3dRecDbarRefl", kTH3F, {axisPt, axisEta, axisDMass}); + histos.add("h3dRecDbarBkg", "h3dRecDbarBkg", kTH3F, {axisPt, axisEta, axisDMass}); + + histos.add("hDGenForEfficiency", "hDGenForEfficiency", kTH2F, {axisPt, axisY}); // 2D vs pT, Y, filling generated D0 and D0bar + histos.add("hDRecForEfficiency", "hDRecForEfficiency", kTH2F, {axisPt, axisY}); // 2D vs pT, Y, filling reconstructed D0 and D0bar with correct MC matching histos.add("hMassD", "hMassD", kTH1F, {axisDMass}); + histos.add("hMassDSig", "hMassDSig", kTH1F, {axisDMass}); + histos.add("hMassDRefl", "hMassDRefl", kTH1F, {axisDMass}); + histos.add("hMassDBkg", "hMassDBkg", kTH1F, {axisDMass}); histos.add("hMassDbar", "hMassDbar", kTH1F, {axisDMass}); + histos.add("hMassDbarSig", "hMassDbarSig", kTH1F, {axisDMass}); + histos.add("hMassDbarRefl", "hMassDbarRefl", kTH1F, {axisDMass}); + histos.add("hMassDbarBkg", "hMassDbarBkg", kTH1F, {axisDMass}); + + histos.add("hDCosPA", "hDCosPA", kTH1F, {{800, -1, 1}}); + histos.add("hDCosPAxy", "hDCosPAxy", kTH1F, {{800, -1, 1}}); + histos.add("hDCosThetaStar", "hDCosThetaStar", kTH1F, {{200, -1, 1}}); + histos.add("hDDecayLength", "hDDecayLength", kTH1F, {{100, 0, 0.5}}); + histos.add("hDDecayLengthXY", "hDDecayLengthXY", kTH1F, {{100, 0, 0.5}}); + histos.add("hDNormDecayLength", "hDNormDecayLength", kTH1F, {{100, 0, 10}}); + histos.add("hImpParPi", "hImpParPi", kTH1F, {{200, -0.4, 0.4}}); + histos.add("hImpParK", "hImpParK", kTH1F, {{200, -0.4, 0.4}}); + histos.add("hImpParProduct", "hImpParProduct", kTH1F, {{400, -0.04, 0.04}}); + + histos.add("hDCosPA_Selected", "hDCosPA_Selected", kTH1F, {{800, -1, 1}}); + histos.add("hDCosPAxy_Selected", "hDCosPAxy_Selected", kTH1F, {{800, -1, 1}}); + histos.add("hDCosThetaStar_Selected", "hDCosThetaStar_Selected", kTH1F, {{200, -1, 1}}); + histos.add("hDDecayLength_Selected", "hDDecayLength_Selected", kTH1F, {{100, 0, 0.5}}); + histos.add("hDDecayLengthXY_Selected", "hDDecayLengthXY_Selected", kTH1F, {{100, 0, 0.5}}); + histos.add("hDNormDecayLength_Selected", "hDNormDecayLength_Selected", kTH1F, {{100, 0, 10}}); + histos.add("hImpParPi_Selected", "hImpParPi_Selected", kTH1F, {{200, -0.4, 0.4}}); + histos.add("hImpParK_Selected", "hImpParK_Selected", kTH1F, {{200, -0.4, 0.4}}); + histos.add("hImpParProduct_Selected", "hImpParProduct_Selected", kTH1F, {{400, -0.04, 0.04}}); + + if (doTopoPlotsForSAndB) { + histos.add("hDCosPA_Signal", "hDCosPA_Signal", kTH1F, {{800, -1, 1}}); + histos.add("hDCosPAxy_Signal", "hDCosPAxy_Signal", kTH1F, {{800, -1, 1}}); + histos.add("hDCosThetaStar_Signal", "hDCosThetaStar_Signal", kTH1F, {{200, -1, 1}}); + histos.add("hDDecayLength_Signal", "hDDecayLength_Signal", kTH1F, {{100, 0, 0.5}}); + histos.add("hDDecayLengthXY_Signal", "hDDecayLengthXY_Signal", kTH1F, {{100, 0, 0.5}}); + histos.add("hDNormDecayLength_Signal", "hDNormDecayLength_Signal", kTH1F, {{100, 0, 10}}); + histos.add("hImpParPi_Signal", "hImpParPi_Signal", kTH1F, {{200, -0.4, 0.4}}); + histos.add("hImpParK_Signal", "hImpParK_Signal", kTH1F, {{200, -0.4, 0.4}}); + histos.add("hImpParProduct_Signal", "hImpParProduct_Signal", kTH1F, {{400, -0.04, 0.04}}); + histos.add("hDCosPA_Bkg", "hDCosPA_Bkg", kTH1F, {{800, -1, 1}}); + histos.add("hDCosPAxy_Bkg", "hDCosPAxy_Bkg", kTH1F, {{800, -1, 1}}); + histos.add("hDCosThetaStar_Bkg", "hDCosThetaStar_Bkg", kTH1F, {{200, -1, 1}}); + histos.add("hDDecayLength_Bkg", "hDDecayLength_Bkg", kTH1F, {{100, 0, 0.5}}); + histos.add("hDDecayLengthXY_Bkg", "hDDecayLengthXY_Bkg", kTH1F, {{100, 0, 0.5}}); + histos.add("hDNormDecayLength_Bkg", "hDNormDecayLength_Bkg", kTH1F, {{100, 0, 10}}); + histos.add("hImpParPi_Bkg", "hImpParPi_Bkg", kTH1F, {{200, -0.4, 0.4}}); + histos.add("hImpParK_Bkg", "hImpParK_Bkg", kTH1F, {{200, -0.4, 0.4}}); + histos.add("hImpParProduct_Bkg", "hImpParProduct_Bkg", kTH1F, {{400, -0.04, 0.04}}); + } if (doDCAplotsD) { + histos.add("hDCADDaughters", "hDCADDaughters", kTH1D, {axisDCADaughters}); + histos.add("hDCADbarDaughters", "hDCADbarDaughters", kTH1D, {axisDCADaughters}); + histos.add("hDCADDaughters_Selected", "hDCADDaughters_Selected", kTH1D, {axisDCADaughters}); + histos.add("hDCADbarDaughters_Selected", "hDCADbarDaughters_Selected", kTH1D, {axisDCADaughters}); histos.add("h2dDCAxyVsPtPiPlusFromD", "h2dDCAxyVsPtPiPlusFromD", kTH2F, {axisPt, axisDCA}); histos.add("h2dDCAxyVsPtPiMinusFromD", "h2dDCAxyVsPtPiMinusFromD", kTH2F, {axisPt, axisDCA}); histos.add("h2dDCAxyVsPtKaPlusFromD", "h2dDCAxyVsPtKaPlusFromD", kTH2F, {axisPt, axisDCA}); histos.add("h2dDCAxyVsPtKaMinusFromD", "h2dDCAxyVsPtKaMinusFromD", kTH2F, {axisPt, axisDCA}); + if (doTopoPlotsForSAndB) { + histos.add("hDCADDaughters_Signal", "hDCADDaughters_Signal", kTH1D, {axisDCADaughters}); + histos.add("hDCADDaughters_Bkg", "hDCADDaughters_Bkg", kTH1D, {axisDCADaughters}); + histos.add("hDCADbarDaughters_Signal", "hDCADbarDaughters_Signal", kTH1D, {axisDCADaughters}); + histos.add("hDCADbarDaughters_Bkg", "hDCADbarDaughters_Bkg", kTH1D, {axisDCADaughters}); + } } } - if (doprocessFindLcBaryons) { - histos.add("h2dGenLc", "h2dGenLc", kTH2F, {axisPt, axisEta}); - histos.add("h2dGenLcbar", "h2dGenLcbar", kTH2F, {axisPt, axisEta}); - histos.add("h3dRecLc", "h2dRecLc", kTH3F, {axisPt, axisEta, axisLcMass}); - histos.add("h3dRecLcbar", "h2dRecLcbar", kTH3F, {axisPt, axisEta, axisLcMass}); + if (doprocessFindLc) { + histos.add("h2dGen3Prong", "h2dGen3Prong", kTH2F, {axisPt, axisEta}); + histos.add("h2dGen3ProngBar", "h2dGen3ProngBar", kTH2F, {axisPt, axisEta}); + histos.add("h3dRec3Prong", "h3dRec3Prong", kTH3F, {axisPt, axisEta, axisLcMass}); + histos.add("hMass3Prong", "hMass3Prong", kTH1F, {axisLcMass}); - histos.add("hMassLc", "hMassLc", kTH1F, {axisLcMass}); - histos.add("hMassLcbar", "hMassLcbar", kTH1F, {axisLcMass}); - - if (doDCAplotsD) { - histos.add("h2dDCAxyVsPtPiPlusFromLc", "h2dDCAxyVsPtPiPlusFromLc", kTH2F, {axisPt, axisDCA}); - histos.add("h2dDCAxyVsPtPiMinusFromLc", "h2dDCAxyVsPtPiMinusFromLc", kTH2F, {axisPt, axisDCA}); - histos.add("h2dDCAxyVsPtKaPlusFromLc", "h2dDCAxyVsPtKaPlusFromLc", kTH2F, {axisPt, axisDCA}); - histos.add("h2dDCAxyVsPtKaMinusFromLc", "h2dDCAxyVsPtKaMinusFromLc", kTH2F, {axisPt, axisDCA}); - histos.add("h2dDCAxyVsPtPrPlusFromLc", "h2dDCAxyVsPtPrPlusFromLc", kTH2F, {axisPt, axisDCA}); - histos.add("h2dDCAxyVsPtPrMinusFromLc", "h2dDCAxyVsPtPrMinusFromLc", kTH2F, {axisPt, axisDCA}); + if (doDCAplots3Prong) { + histos.add("hDCA3ProngDaughters", "hDCA3ProngDaughters", kTH1D, {axisDCADaughters}); + histos.add("h2dDCAxyVsPtPiPlusFrom3P", "h2dDCAxyVsPtPiPlusFrom3P", kTH2F, {axisPt, axisDCA}); + histos.add("h2dDCAxyVsPtPiMinusFrom3P", "h2dDCAxyVsPtPiMinusFrom3P", kTH2F, {axisPt, axisDCA}); + histos.add("h2dDCAxyVsPtKaPlusFrom3P", "h2dDCAxyVsPtKaPlusFrom3P", kTH2F, {axisPt, axisDCA}); + histos.add("h2dDCAxyVsPtKaMinusFrom3P", "h2dDCAxyVsPtKaMinusFrom3P", kTH2F, {axisPt, axisDCA}); + histos.add("h2dDCAxyVsPtPrPlusFrom3P", "h2dDCAxyVsPtPrPlusFrom3P", kTH2F, {axisPt, axisDCA}); + histos.add("h2dDCAxyVsPtPrMinusFrom3P", "h2dDCAxyVsPtPrMinusFrom3P", kTH2F, {axisPt, axisDCA}); + histos.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.}}}); + histos.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.}}}); } } + + if (doprocessFindLc) { + daugsPdgCodes3Prong = {+kProton, -kKPlus, +kPiPlus}; + motherPdgCode = o2::constants::physics::Pdg::kLambdaCPlus; + daughtersMasses3Prong = {o2::constants::physics::MassProton, + o2::constants::physics::MassKaonCharged, + o2::constants::physics::MassPionCharged}; + charmHadFlag = CharmHadAlice3::Lc; + } } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processGenerated(aod::McParticles const&) + void processGenerated(aod::McParticles const& mcParticles) { // no grouping for MC particles -> as intended if (doprocessFindDmesons) { - for (auto const& mcParticle : trueD) + for (auto const& mcParticle : trueD) { histos.fill(HIST("h2dGenD"), mcParticle.pt(), mcParticle.eta()); - for (auto const& mcParticle : trueDbar) + auto daughters = mcParticle.template daughters_as(); + if (daughters.size() != 2) + continue; + // int daugID[2]; + int daugPDG[2], i = 0; + for (const auto& dau : daughters) { + // daugID[i] = dau.globalIndex(); + daugPDG[i] = dau.pdgCode(); + i++; + } + if ((std::fabs(daugPDG[0]) == 321 && std::fabs(daugPDG[1]) == 211) || (std::fabs(daugPDG[0]) == 211 && std::fabs(daugPDG[1]) == 321)) { + histos.fill(HIST("h2dGenD_KpiOnly"), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hDGenForEfficiency"), mcParticle.pt(), mcParticle.y()); // in common for D and Dbar + } + } + for (auto const& mcParticle : trueDbar) { histos.fill(HIST("h2dGenDbar"), mcParticle.pt(), mcParticle.eta()); + auto daughters = mcParticle.template daughters_as(); + if (daughters.size() != 2) + continue; + // int daugID[2]; + int daugPDG[2], i = 0; + for (const auto& dau : daughters) { + // daugID[i] = dau.globalIndex(); + daugPDG[i] = dau.pdgCode(); + i++; + } + if ((std::fabs(daugPDG[0]) == 321 && std::fabs(daugPDG[1]) == 211) || (std::fabs(daugPDG[0]) == 211 && std::fabs(daugPDG[1]) == 321)) { + histos.fill(HIST("h2dGenDbar_KpiOnly"), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hDGenForEfficiency"), mcParticle.pt(), mcParticle.y()); // in common for D and Dbar + } + } } - if (doprocessFindLcBaryons) { - for (auto const& mcParticle : trueLc) - histos.fill(HIST("h2dGenLc"), mcParticle.pt(), mcParticle.eta()); - for (auto const& mcParticle : trueLcbar) - histos.fill(HIST("h2dGenLcbar"), mcParticle.pt(), mcParticle.eta()); + if (doprocessFindLc) { + for (auto const& mcParticle : mcParticles) { + if (std::abs(mcParticle.pdgCode()) != motherPdgCode) { + mcGenFlags(-1, -1, -1); + continue; + } + std::vector idxBhadMothers{}; + int origin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, false, &idxBhadMothers); + float ptBMotherGen{-1.f}; + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + ptBMotherGen = bHadMother.pt(); + } + mcGenFlags(origin, ptBMotherGen, mcParticle.pdgCode() ? charmHadFlag : -charmHadFlag); + if (mcParticle.pdgCode() > 0) { + histos.fill(HIST("h2dGen3Prong"), mcParticle.pt(), mcParticle.eta()); + } else { + histos.fill(HIST("h2dGen3ProngBar"), mcParticle.pt(), mcParticle.eta()); + } + } } } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processFindDmesons(aod::Collision const& collision, alice3tracks const&, aod::McParticles const&) + void processFindDmesons(aod::Collision const& collision, Alice3TracksWPid const&, aod::McParticles const& mcParticles) { // group with this collision auto tracksPiPlusFromDgrouped = tracksPiPlusFromD->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); @@ -498,85 +682,359 @@ struct alice3decayFinder { histos.fill(HIST("h2dDCAxyVsPtKaMinusFromD"), track.pt(), track.dcaXY() * 1e+4); } - // D mesons + // D0 mesons for (auto const& posTrackRow : tracksPiPlusFromDgrouped) { for (auto const& negTrackRow : tracksKaMinusFromDgrouped) { + if (mcSameMotherCheck && !checkSameMother(posTrackRow, negTrackRow)) continue; - if (!buildDecayCandidateTwoBody(posTrackRow, negTrackRow, o2::constants::physics::MassPionCharged, o2::constants::physics::MassKaonCharged)) + if (!buildDecayCandidateTwoBody(posTrackRow, negTrackRow, o2::constants::physics::MassPionCharged, o2::constants::physics::MassKaonCharged, mcParticles)) 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; + + auto impParXY_daugPos = RecoDecay::impParXY(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]}, std::array{dmeson.Pdaug[0], dmeson.Pdaug[1], dmeson.Pdaug[2]}); + auto impParXY_daugNeg = RecoDecay::impParXY(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]}, std::array{dmeson.Ndaug[0], dmeson.Ndaug[1], dmeson.Ndaug[2]}); + auto decayLength = std::hypot(collision.posX() - dmeson.posSV[0], collision.posY() - dmeson.posSV[1], collision.posZ() - dmeson.posSV[2]); + auto decayLengthXY = std::hypot(collision.posX() - dmeson.posSV[0], collision.posY() - dmeson.posSV[1]); + + // fill plots of topological variables before topological selection + histos.fill(HIST("hDCosPA"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar"), dmeson.cosThetaStar); + histos.fill(HIST("hDDecayLength"), decayLength); + histos.fill(HIST("hDDecayLengthXY"), decayLengthXY); + histos.fill(HIST("hDNormDecayLength"), dmeson.normalizedDecayLength); + histos.fill(HIST("hImpParPi"), impParXY_daugPos); + histos.fill(HIST("hImpParK"), impParXY_daugNeg); + histos.fill(HIST("hImpParProduct"), impParXY_daugPos * impParXY_daugNeg); + if (doDCAplotsD) + histos.fill(HIST("hDCADDaughters"), dmeson.dcaDau * 1e+4); + + if (doTopoPlotsForSAndB) { // fill plots of topological variables for S and B separately (reflections not considered here) + if (dmeson.mcTruth == 1) { // true D0 + histos.fill(HIST("hDCosPA_Signal"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy_Signal"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar_Signal"), dmeson.cosThetaStar); + histos.fill(HIST("hDDecayLength_Signal"), decayLength); + histos.fill(HIST("hDDecayLengthXY_Signal"), decayLengthXY); + histos.fill(HIST("hDNormDecayLength_Signal"), dmeson.normalizedDecayLength); + histos.fill(HIST("hImpParPi_Signal"), impParXY_daugPos); + histos.fill(HIST("hImpParK_Signal"), impParXY_daugNeg); + histos.fill(HIST("hImpParProduct_Signal"), impParXY_daugPos * impParXY_daugNeg); + if (doDCAplotsD) + histos.fill(HIST("hDCADDaughters_Signal"), dmeson.dcaDau * 1e+4); + } else if (!dmeson.mcTruth) { // bkg D0 + histos.fill(HIST("hDCosPA_Bkg"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy_Bkg"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar_Bkg"), dmeson.cosThetaStar); + histos.fill(HIST("hDDecayLength_Bkg"), decayLength); + histos.fill(HIST("hDDecayLengthXY_Bkg"), decayLengthXY); + histos.fill(HIST("hDNormDecayLength_Bkg"), dmeson.normalizedDecayLength); + histos.fill(HIST("hImpParPi_Bkg"), impParXY_daugPos); + histos.fill(HIST("hImpParK_Bkg"), impParXY_daugNeg); + histos.fill(HIST("hImpParProduct_Bkg"), impParXY_daugPos * impParXY_daugNeg); + if (doDCAplotsD) + histos.fill(HIST("hDCADDaughters_Bkg"), dmeson.dcaDau * 1e+4); + } + } + + if (dmeson.dcaDau > dcaDaughtersSelection) + continue; + + if (dmeson.pt <= lowPtDLimit && dmeson.cosPA < DCosPA) + continue; + else if (dmeson.pt > lowPtDLimit && dmeson.cosPA < DCosPAHighPt) + continue; + + if (dmeson.pt <= lowPtDLimit && dmeson.cosPAxy < DCosPAxy) + continue; + else if (dmeson.pt > lowPtDLimit && dmeson.cosPAxy < DCosPAxyHighPt) + continue; + + if (dmeson.pt <= lowPtDLimit && std::fabs(dmeson.cosThetaStar) > DCosThetaStarLowPt) + continue; + else if (dmeson.pt <= highPtDLimit && std::fabs(dmeson.cosThetaStar) > DCosThetaStarHighPt) + continue; + else if (dmeson.pt > highPtDLimit && std::fabs(dmeson.cosThetaStar) > DCosThetaStarVHighPt) + continue; + + if (dmeson.normalizedDecayLength < DMinNormDecayLength || dmeson.normalizedDecayLength > DMaxNormDecayLength) + continue; + + if (dmeson.ptdaugPos < minPtPi) // track1 (positive) is the pion + continue; + if (dmeson.ptdaugNeg < minPtK) // track2 (negative) is the kaon + continue; + + if (impParXY_daugPos > maxImpParPi) + continue; + if (impParXY_daugNeg > maxImpParK) + continue; + if (impParXY_daugPos * impParXY_daugNeg > maxImpParProduct) + continue; + + if (decayLength < DMinDecayLength || decayLength > DMaxDecayLength) + continue; + if (decayLengthXY < DMinDecayLengthXY || decayLengthXY > DMaxDecayLengthXY) + continue; + auto decayLengthSquaredCut = std::min((std::hypot(dmeson.P[0], dmeson.P[1], dmeson.P[2]) * 0.0066) + 0.01, static_cast(DDecayLengthSquaredCut)); + if (decayLength * decayLength < decayLengthSquaredCut * decayLengthSquaredCut) + continue; + + // fill plots of topological variables after topological selection + histos.fill(HIST("hDCosPA_Selected"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy_Selected"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar_Selected"), dmeson.cosThetaStar); + histos.fill(HIST("hDDecayLength_Selected"), decayLength); + histos.fill(HIST("hDDecayLengthXY_Selected"), decayLengthXY); + histos.fill(HIST("hDNormDecayLength_Selected"), dmeson.normalizedDecayLength); + histos.fill(HIST("hImpParPi_Selected"), impParXY_daugPos); + histos.fill(HIST("hImpParK_Selected"), impParXY_daugNeg); + histos.fill(HIST("hImpParProduct_Selected"), impParXY_daugPos * impParXY_daugNeg); + if (doDCAplotsD) + histos.fill(HIST("hDCADDaughters_Selected"), dmeson.dcaDau * 1e+4); + + // filling of mass plots for selected candidates histos.fill(HIST("hMassD"), dmeson.mass); histos.fill(HIST("h3dRecD"), dmeson.pt, dmeson.eta, dmeson.mass); + if (dmeson.mcTruth == 1) { // true D0 meson, reco as D0 (= correct matching) + histos.fill(HIST("h3dRecDSig"), dmeson.pt, dmeson.eta, dmeson.mass); + histos.fill(HIST("hMassDSig"), dmeson.mass); + histos.fill(HIST("hDRecForEfficiency"), dmeson.pt, dmeson.y); // for efficiency + } else if (dmeson.mcTruth == 2) { // true D0bar meson, reco as D0 (= reflection) + histos.fill(HIST("hMassDRefl"), dmeson.mass); + histos.fill(HIST("h3dRecDRefl"), dmeson.pt, dmeson.eta, dmeson.mass); + } else { // background, reco as D0 + histos.fill(HIST("hMassDBkg"), dmeson.mass); + histos.fill(HIST("h3dRecDBkg"), dmeson.pt, dmeson.eta, dmeson.mass); + } + + // store D0 in output table + candidateD0meson(collision.globalIndex(), + dmeson.Pdaug[0], dmeson.Pdaug[1], dmeson.Pdaug[2], + dmeson.Ndaug[0], dmeson.Ndaug[1], dmeson.Ndaug[2], + dmeson.P[0], dmeson.P[1], dmeson.P[2], + dmeson.pt, + dmeson.mass, + dmeson.eta, + dmeson.phi, + dmeson.y); + selectionOutcome(1, 0); // isSelD0 true, isSelD0bar false + mcTruthOutcome(dmeson.mcTruth); } } - // D mesons + + // D0bar mesons for (auto const& posTrackRow : tracksKaPlusFromDgrouped) { for (auto const& negTrackRow : tracksPiMinusFromDgrouped) { + if (mcSameMotherCheck && !checkSameMother(posTrackRow, negTrackRow)) continue; - if (!buildDecayCandidateTwoBody(posTrackRow, negTrackRow, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassPionCharged)) + if (!buildDecayCandidateTwoBody(posTrackRow, negTrackRow, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassPionCharged, mcParticles)) + 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; + + auto impParXY_daugPos = RecoDecay::impParXY(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]}, std::array{dmeson.Pdaug[0], dmeson.Pdaug[1], dmeson.Pdaug[2]}); + auto impParXY_daugNeg = RecoDecay::impParXY(std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{dmeson.posSV[0], dmeson.posSV[1], dmeson.posSV[2]}, std::array{dmeson.Ndaug[0], dmeson.Ndaug[1], dmeson.Ndaug[2]}); + auto decayLength = std::hypot(collision.posX() - dmeson.posSV[0], collision.posY() - dmeson.posSV[1], collision.posZ() - dmeson.posSV[2]); + auto decayLengthXY = std::hypot(collision.posX() - dmeson.posSV[0], collision.posY() - dmeson.posSV[1]); + + // fill plots of topological variables before topological selection + histos.fill(HIST("hDCosPA"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar"), dmeson.cosThetaStar); + histos.fill(HIST("hDDecayLength"), decayLength); + histos.fill(HIST("hDDecayLengthXY"), decayLengthXY); + histos.fill(HIST("hDNormDecayLength"), dmeson.normalizedDecayLength); + histos.fill(HIST("hImpParPi"), impParXY_daugNeg); + histos.fill(HIST("hImpParK"), impParXY_daugPos); + histos.fill(HIST("hImpParProduct"), impParXY_daugPos * impParXY_daugNeg); + if (doDCAplotsD) + histos.fill(HIST("hDCADbarDaughters"), dmeson.dcaDau * 1e+4); + + if (doTopoPlotsForSAndB) { // fill plots of topological variables for S and B separately (reflections not considered here) + if (dmeson.mcTruth == 2) { // true D0bar + histos.fill(HIST("hDCosPA_Signal"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy_Signal"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar_Signal"), dmeson.cosThetaStar); + histos.fill(HIST("hDDecayLength_Signal"), decayLength); + histos.fill(HIST("hDDecayLengthXY_Signal"), decayLengthXY); + histos.fill(HIST("hDNormDecayLength_Signal"), dmeson.normalizedDecayLength); + histos.fill(HIST("hImpParPi_Signal"), impParXY_daugNeg); + histos.fill(HIST("hImpParK_Signal"), impParXY_daugPos); + histos.fill(HIST("hImpParProduct_Signal"), impParXY_daugPos * impParXY_daugNeg); + if (doDCAplotsD) + histos.fill(HIST("hDCADbarDaughters_Signal"), dmeson.dcaDau * 1e+4); + } else if (!dmeson.mcTruth) { // bkg D0bar + histos.fill(HIST("hDCosPA_Bkg"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy_Bkg"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar_Bkg"), dmeson.cosThetaStar); + histos.fill(HIST("hDDecayLength_Bkg"), decayLength); + histos.fill(HIST("hDDecayLengthXY_Bkg"), decayLengthXY); + histos.fill(HIST("hDNormDecayLength_Bkg"), dmeson.normalizedDecayLength); + histos.fill(HIST("hImpParPi_Bkg"), impParXY_daugNeg); + histos.fill(HIST("hImpParK_Bkg"), impParXY_daugPos); + histos.fill(HIST("hImpParProduct_Bkg"), impParXY_daugPos * impParXY_daugNeg); + } + if (doDCAplotsD) + histos.fill(HIST("hDCADbarDaughters_Bkg"), dmeson.dcaDau * 1e+4); + } + + if (dmeson.dcaDau > dcaDaughtersSelection) + continue; + + if (dmeson.pt <= lowPtDLimit && dmeson.cosPA < DCosPA) + continue; + else if (dmeson.pt > lowPtDLimit && dmeson.cosPA < DCosPAHighPt) + continue; + + if (dmeson.pt <= lowPtDLimit && dmeson.cosPAxy < DCosPAxy) + continue; + else if (dmeson.pt > lowPtDLimit && dmeson.cosPAxy < DCosPAxyHighPt) + continue; + + if (dmeson.pt <= highPtDLimit && std::fabs(dmeson.cosThetaStar) > DCosThetaStarLowPt) + continue; + else if (dmeson.pt <= highPtDLimit && std::fabs(dmeson.cosThetaStar) > DCosThetaStarHighPt) + continue; + else if (dmeson.pt > highPtDLimit && std::fabs(dmeson.cosThetaStar) > DCosThetaStarVHighPt) + continue; + + if (dmeson.normalizedDecayLength < DMinNormDecayLength || dmeson.normalizedDecayLength > DMaxNormDecayLength) + continue; + + if (dmeson.ptdaugPos < minPtK) // track1 is the kaon + continue; + if (dmeson.ptdaugNeg < minPtPi) // track2 is the pion + continue; + + if (impParXY_daugPos > maxImpParK) + continue; + if (impParXY_daugNeg > maxImpParPi) + continue; + if (impParXY_daugPos * impParXY_daugNeg > maxImpParProduct) continue; + + if (decayLength < DMinDecayLength || decayLength > DMaxDecayLength) + continue; + if (decayLengthXY < DMinDecayLengthXY || decayLengthXY > DMaxDecayLengthXY) + continue; + auto decayLengthSquaredCut = std::min((std::hypot(dmeson.P[0], dmeson.P[1], dmeson.P[2]) * 0.0066) + 0.01, static_cast(DDecayLengthSquaredCut)); + if (decayLength * decayLength < decayLengthSquaredCut * decayLengthSquaredCut) + continue; + + // fill plots of topological variables after topological selection + histos.fill(HIST("hDCosPA_Selected"), dmeson.cosPA); + histos.fill(HIST("hDCosPAxy_Selected"), dmeson.cosPAxy); + histos.fill(HIST("hDCosThetaStar_Selected"), dmeson.cosThetaStar); + histos.fill(HIST("hDDecayLength_Selected"), decayLength); + histos.fill(HIST("hDDecayLengthXY_Selected"), decayLengthXY); + histos.fill(HIST("hDNormDecayLength_Selected"), dmeson.normalizedDecayLength); + histos.fill(HIST("hImpParK_Selected"), impParXY_daugPos); + histos.fill(HIST("hImpParPi_Selected"), impParXY_daugNeg); + histos.fill(HIST("hImpParProduct_Selected"), impParXY_daugPos * impParXY_daugNeg); + if (doDCAplotsD) + histos.fill(HIST("hDCADbarDaughters_Selected"), dmeson.dcaDau * 1e+4); + + // filling of mass plots for selected candidates histos.fill(HIST("hMassDbar"), dmeson.mass); histos.fill(HIST("h3dRecDbar"), dmeson.pt, dmeson.eta, dmeson.mass); + if (dmeson.mcTruth == 2) { // true D0bar meson, reco as D0bar (= correct matching) + histos.fill(HIST("h3dRecDbarSig"), dmeson.pt, dmeson.eta, dmeson.mass); + histos.fill(HIST("hMassDbarSig"), dmeson.mass); + histos.fill(HIST("hDRecForEfficiency"), dmeson.pt, dmeson.y); // for efficiency + } else if (dmeson.mcTruth == 1) { // true D0 meson, reco as D0bar (= reflection) + histos.fill(HIST("hMassDbarRefl"), dmeson.mass); + histos.fill(HIST("h3dRecDbarRefl"), dmeson.pt, dmeson.eta, dmeson.mass); + } else { // background, reco as D0 + histos.fill(HIST("hMassDbarBkg"), dmeson.mass); + histos.fill(HIST("h3dRecDbarBkg"), dmeson.pt, dmeson.eta, dmeson.mass); + } + + // store D0bar in output table + candidateD0meson(collision.globalIndex(), + dmeson.Pdaug[0], dmeson.Pdaug[1], dmeson.Pdaug[2], + dmeson.Ndaug[0], dmeson.Ndaug[1], dmeson.Ndaug[2], + dmeson.P[0], dmeson.P[1], dmeson.P[2], + dmeson.pt, + dmeson.mass, + dmeson.eta, + dmeson.phi, + dmeson.y); + selectionOutcome(0, 1); // isSelD0 true, isSelD0bar false + mcTruthOutcome(dmeson.mcTruth); } } } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void processFindLcBaryons(aod::Collision const& collision, alice3tracks const&, aod::McParticles const&) + template + void fillPidTable(TProng const& prong0, TProng const& prong1, TProng const& prong2) { - // group with this collision - auto tracksPiPlusFromLcgrouped = tracksPiPlusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto tracksKaPlusFromLcgrouped = tracksKaPlusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto tracksPrPlusFromLcgrouped = tracksPrPlusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - - auto tracksPiMinusFromLcgrouped = tracksPiMinusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto tracksKaMinusFromLcgrouped = tracksKaMinusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto tracksPrMinusFromLcgrouped = tracksPrMinusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - - if (doDCAplotsLc) { - for (auto const& track : tracksPiPlusFromLcgrouped) - histos.fill(HIST("h2dDCAxyVsPtPiPlusFromLc"), track.pt(), track.dcaXY() * 1e+4); - for (auto const& track : tracksPiMinusFromLcgrouped) - histos.fill(HIST("h2dDCAxyVsPtPiMinusFromLc"), track.pt(), track.dcaXY() * 1e+4); - for (auto const& track : tracksKaPlusFromLcgrouped) - histos.fill(HIST("h2dDCAxyVsPtKaPlusFromLc"), track.pt(), track.dcaXY() * 1e+4); - for (auto const& track : tracksKaMinusFromLcgrouped) - histos.fill(HIST("h2dDCAxyVsPtKaMinusFromLc"), track.pt(), track.dcaXY() * 1e+4); - for (auto const& track : tracksPrPlusFromLcgrouped) - histos.fill(HIST("h2dDCAxyVsPtPrPlusFromLc"), track.pt(), track.dcaXY() * 1e+4); - for (auto const& track : tracksPrMinusFromLcgrouped) - histos.fill(HIST("h2dDCAxyVsPtPrMinusFromLc"), track.pt(), track.dcaXY() * 1e+4); + if (motherPdgCode == o2::constants::physics::Pdg::kLambdaCPlus) { + pidInfoLcDaugs(prong0.nSigmaTrkPr(), prong0.nSigmaProtonRich(), prong0.nSigmaProtonInnerTOF(), prong0.nSigmaProtonOuterTOF(), + prong1.nSigmaTrkKa(), prong1.nSigmaKaonRich(), prong1.nSigmaKaonInnerTOF(), prong1.nSigmaKaonOuterTOF(), + prong2.nSigmaTrkPi(), prong2.nSigmaPionRich(), prong2.nSigmaPionInnerTOF(), prong2.nSigmaPionOuterTOF()); + } else { + LOG(fatal) << "3-prong candidate not implemented yet"; } + } - // Lc+ baryons +4122 -> +2212 -321 +211 - for (auto const& proton : tracksPrPlusFromLcgrouped) { - for (auto const& pion : tracksPiPlusFromLcgrouped) { - if (pion.globalIndex() == proton.globalIndex()) - continue; // avoid self - for (auto const& kaon : tracksKaMinusFromLcgrouped) { - if (mcSameMotherCheck && (!checkSameMother(proton, kaon) || !checkSameMother(proton, pion))) - continue; - if (!buildDecayCandidateThreeBody(proton, kaon, pion, o2::constants::physics::MassProton, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassPionCharged)) - continue; - histos.fill(HIST("hMassLc"), lcbaryon.mass); - histos.fill(HIST("h3dRecLc"), lcbaryon.pt, lcbaryon.eta, lcbaryon.mass); - } - } - } - // Lc- baryons -4122 -> -2212 +321 -211 - for (auto const& proton : tracksPrMinusFromLcgrouped) { - for (auto const& pion : tracksPiMinusFromLcgrouped) { - if (pion.globalIndex() == proton.globalIndex()) + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + template + void fill3ProngTable(aod::Collision const& collision, TProng const& prongs0, TProng const& prongs1, TProng const& prongs2, aod::McParticles const& mcParticles) + { + for (auto const& prong0 : prongs0) { + for (auto const& prong2 : prongs2) { + if (prong2.globalIndex() == prong0.globalIndex()) continue; // avoid self - for (auto const& kaon : tracksKaPlusFromLcgrouped) { - if (mcSameMotherCheck && (!checkSameMother(proton, kaon) || !checkSameMother(proton, pion))) + for (auto const& prong1 : prongs1) { + if (mcSameMotherCheck && (!checkSameMother(prong0, prong1) || !checkSameMother(prong0, prong1))) { continue; - if (!buildDecayCandidateThreeBody(proton, kaon, pion, o2::constants::physics::MassProton, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassPionCharged)) + } + if (!buildDecayCandidateThreeBody(collision, prong0, prong1, prong2, mcParticles)) { continue; - histos.fill(HIST("hMassLcbar"), lcbaryon.mass); - histos.fill(HIST("h3dRecLcbar"), lcbaryon.pt, lcbaryon.eta, lcbaryon.mass); + } + histos.fill(HIST("hDCA3ProngDaughters"), cand3prong.dcaDau * 1e+4); + histos.fill(HIST("hMass3Prong"), cand3prong.mass); + histos.fill(HIST("h3dRec3Prong"), cand3prong.pt, cand3prong.eta, cand3prong.mass); + + auto candPx = cand3prong.Pdaug0[0] + cand3prong.Pdaug1[0] + cand3prong.Pdaug2[0]; + auto candPy = cand3prong.Pdaug0[1] + cand3prong.Pdaug1[1] + cand3prong.Pdaug2[1]; + auto candPz = cand3prong.Pdaug0[2] + cand3prong.Pdaug1[2] + cand3prong.Pdaug2[2]; + + candidate3Prong(collision.globalIndex(), + cand3prong.primaryVertex[0], cand3prong.primaryVertex[1], cand3prong.primaryVertex[2], + cand3prong.secondaryVertex[0], cand3prong.secondaryVertex[1], cand3prong.secondaryVertex[2], + cand3prong.errorDecayLength, cand3prong.errorDecayLengthXY, + cand3prong.chi2PCA, + cand3prong.eta, + cand3prong.phi, + cand3prong.pt, + cand3prong.Pdaug2[0], cand3prong.Pdaug2[1], cand3prong.Pdaug2[2], + cand3prong.Pdaug1[0], cand3prong.Pdaug1[1], cand3prong.Pdaug1[2], + cand3prong.Pdaug0[0], cand3prong.Pdaug0[1], cand3prong.Pdaug0[2], + cand3prong.impactParameterY0, cand3prong.impactParameterY1, cand3prong.impactParameterY2, + std::sqrt(cand3prong.errorImpactParameterY0), + std::sqrt(cand3prong.errorImpactParameterY1), + std::sqrt(cand3prong.errorImpactParameterY2), + cand3prong.impactParameterZ0, cand3prong.impactParameterZ1, cand3prong.impactParameterZ2, + std::sqrt(cand3prong.errorImpactParameterZ0), + std::sqrt(cand3prong.errorImpactParameterZ1), + std::sqrt(cand3prong.errorImpactParameterZ2), + candPx, candPy, candPz); + mcRecFlags(cand3prong.origin, cand3prong.ptBMotherRec, cand3prong.flagMc); // placeholder for prompt/non-prompt + fillPidTable(prong0, prong1, prong2); } } } @@ -586,13 +1044,44 @@ struct alice3decayFinder { //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* PROCESS_SWITCH(alice3decayFinder, processGenerated, "fill MC-only histograms", true); PROCESS_SWITCH(alice3decayFinder, processFindDmesons, "find D mesons", true); - PROCESS_SWITCH(alice3decayFinder, processFindLcBaryons, "find Lc Baryons", true); + + void processFindLc(aod::Collision const& collision, + aod::McParticles const& mcParticles, + Alice3TracksWPid const&) + { + + auto tracksPiPlus = tracksPiPlusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto tracksKaPlus = tracksKaPlusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto tracksPrPlus = tracksPrPlusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto tracksPiMinus = tracksPiMinusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto tracksKaMinus = tracksKaMinusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto tracksPrMinus = tracksPrMinusFromLc->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + if (doDCAplots3Prong) { + for (auto const& track : tracksPiPlus) + histos.fill(HIST("h2dDCAxyVsPtPiPlusFrom3P"), track.pt(), track.dcaXY() * 1e+4); + for (auto const& track : tracksPiMinus) + histos.fill(HIST("h2dDCAxyVsPtPiMinusFrom3P"), track.pt(), track.dcaXY() * 1e+4); + for (auto const& track : tracksKaPlus) + histos.fill(HIST("h2dDCAxyVsPtKaPlusFrom3P"), track.pt(), track.dcaXY() * 1e+4); + for (auto const& track : tracksKaMinus) + histos.fill(HIST("h2dDCAxyVsPtKaMinusFrom3P"), track.pt(), track.dcaXY() * 1e+4); + for (auto const& track : tracksPrPlus) + histos.fill(HIST("h2dDCAxyVsPtPrPlusFrom3P"), track.pt(), track.dcaXY() * 1e+4); + for (auto const& track : tracksPrMinus) + histos.fill(HIST("h2dDCAxyVsPtPrMinusFrom3P"), track.pt(), track.dcaXY() * 1e+4); + } + + // Particles + fill3ProngTable(collision, tracksPrPlus, tracksKaMinus, tracksPiPlus, mcParticles); + fill3ProngTable(collision, tracksPrMinus, tracksKaPlus, tracksPiMinus, mcParticles); + } + PROCESS_SWITCH(alice3decayFinder, processFindLc, "find Lc Baryons", true); //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; // o2-linter: disable=name/o2-task (wrong hyphenation) } diff --git a/ALICE3/TableProducer/alice3-decaypreselector.cxx b/ALICE3/TableProducer/alice3-decaypreselector.cxx new file mode 100644 index 00000000000..527d1c1d197 --- /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 = aod::upgrade_rich::hasSig && aod::upgrade_rich::hasSigPi && nabs(aod::upgrade_rich::nSigmaPionRich) > nSigmaRICH; + Partition pRICHKa = aod::upgrade_rich::hasSig && aod::upgrade_rich::hasSigKa && nabs(aod::upgrade_rich::nSigmaKaonRich) > nSigmaRICH; + Partition pRICHPr = aod::upgrade_rich::hasSig && aod::upgrade_rich::hasSigPr && 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-multicharmTable.cxx b/ALICE3/TableProducer/alice3-multicharmTable.cxx new file mode 100644 index 00000000000..74728aca472 --- /dev/null +++ b/ALICE3/TableProducer/alice3-multicharmTable.cxx @@ -0,0 +1,848 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "ALICE3/DataModel/A3DecayFinderTables.h" +#include "ALICE3/DataModel/OTFMulticharm.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFStrangeness.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/OTFTracks.h" +#include "ALICE3/DataModel/tracksAlice3.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsVertexing/PVertexer.h" +#include "DetectorsVertexing/PVertexerHelpers.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +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))) +#define getHist(type, name) std::get>(histPointers[name]) + +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 alice3multicharmTable { + SliceCache cache; + + Produces multiCharmIdx; + Produces multiCharmCore; + Produces multiCharmPID; + Produces multiCharmExtra; + + // 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 piFromXiC_tofDiffInner{"piFromXiC_tofDiffInner", 50, "|signal - expected| (ps)"}; + Configurable piFromXiCC_tofDiffInner{"piFromXiCC_tofDiffInner", 50, "|signal - expected| (ps)"}; + 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 minXiRadius{"minXiRadius", 0.5, "Minimum R2D for XiC decay (cm)"}; + Configurable minXiCRadius{"minXiCRadius", 0.001, "Minimum R2D for XiC decay (cm)"}; + Configurable minXiCCRadius{"minXiCCRadius", 0.005, "Minimum R2D for XiCC decay (cm)"}; + Configurable xicMinDecayDistanceFromPV{"xicMinDecayDistanceFromPV", 0.002, "Minimum distance for XiC decay from PV (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 xiccMaxEta{"xiccMaxEta", 1.5, "Max eta"}; + Configurable massWindowXi{"massWindowXi", 0.015, "Mass window around Xi peak (GeV/c)"}; + Configurable massWindowXiC{"massWindowXiC", 0.015, "Mass window around XiC peak (GeV/c)"}; + Configurable massWindowXiCC{"massWindowXiCC", 0.4, "Mass window around XiCC peak (GeV/c). Make sure that bkg region is included in this window"}; + + 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", {400, 0, 400}, "DCA (#mum)"}; + ConfigurableAxis axisRadius{"axisRadius", {10000, 0, 10000}, "Decay radius (#mum)"}; + ConfigurableAxis axisRadius2D{"axisRadius2D", {1000, 0, 100000}, "Decay radius (#mum)"}; + ConfigurableAxis axisRadius2DXi{"axisRadius2DXi", {1000, 0, 20}, "Decay radius (cm)"}; + ConfigurableAxis axisDecayLength{"axisDecayLength", {2000, 0, 2000}, "Decay lenght (#mum)"}; + ConfigurableAxis axisTOFTrack{"axisTOFTrack", {1000, 0, 5000}, "TOF track time"}; + + 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}; + std::map histPointers; + std::vector savedConfigs; + + 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) && nabs(aod::track::dcaZ) > piFromXiCC_dcaZconstant + piFromXiCC_dcaZpTdep* 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}); + + if (std::fabs(thisXiCCcandidate.mass - o2::constants::physics::MassXiCCPlusPlus) > massWindowXiCC) { + return false; + } + + 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; + } + + template + int getPdgCodeForTrack(TTrackType track) + { + auto mcParticle = track.template mcParticle_as(); + return mcParticle.pdgCode(); + } + + /// 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; + } + + template + bool checkSameLUTConf(TTrackType const& track1, const int track2) + { + return track1.lutConfigId() == track2; + } + + 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("hPi1cDCAxy", "hPi1cDCAxy", kTH1D, {axisDCA}); + histos.add("hPi1cDCAz", "hPi1cDCAz", kTH1D, {axisDCA}); + histos.add("hPi2cDCAxy", "hPi2cDCAxy", kTH1D, {axisDCA}); + histos.add("hPi2cDCAz", "hPi2cDCAz", kTH1D, {axisDCA}); + histos.add("hPiccDCAxy", "hPiccDCAxy", kTH1D, {axisDCA}); + histos.add("hPiccDCAz", "hPiccDCAz", kTH1D, {axisDCA}); + + histos.add("hMinXiDecayRadius", "hMinXiDecayRadius", kTH1D, {axisRadius2DXi}); + histos.add("hMinXiCDecayRadius", "hMinXiCDecayRadius", kTH1D, {axisRadius}); + histos.add("hMinXiCCDecayRadius", "hMinXiCCDecayRadius", kTH1D, {axisRadius}); + + histos.add("hMinxicDecayDistanceFromPV", "hMinxicDecayDistanceFromPV", kTH1D, {axisDecayLength}); + histos.add("hProperLengthXiC", "hProperLengthXiC", kTH1D, {axisDecayLength}); + histos.add("hProperLengthXiCC", "hProperLengthXiCC", kTH1D, {axisDecayLength}); + + histos.add("hInnerTOFTrackTimeRecoPi1c", "hInnerTOFTrackTimeRecoPi1c", kTH1D, {axisTOFTrack}); + histos.add("hInnerTOFTrackTimeRecoPi2c", "hInnerTOFTrackTimeRecoPi2c", kTH1D, {axisTOFTrack}); + histos.add("hInnerTOFTrackTimeRecoPicc", "hInnerTOFTrackTimeRecoPicc", kTH1D, {axisTOFTrack}); + + histos.add("hXiRadiusVsXicRadius", "hXiRadiusVsXicRadius", kTH2D, {axisRadius2D, axisRadius2D}); + histos.add("hXicRadiusVsXiccRadius", "hXicRadiusVsXiccRadius", kTH2D, {axisRadius2D, axisRadius2D}); + + // 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 initConf(const int icfg) + { + const bool confExists = std::find(savedConfigs.begin(), savedConfigs.end(), icfg) != savedConfigs.end(); + if (confExists) { + return; + } + savedConfigs.push_back(icfg); + + // do more plots + std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; + histPointers.insert({histPath + "hMassXiCC", histos.add((histPath + "hMassXiCC").c_str(), "hMassXiCC", {kTH1D, {{axisXiCCMass}}})}); + histPointers.insert({histPath + "hNCollisions", histos.add((histPath + "hNCollisions").c_str(), "hNCollisions", {kTH1D, {{2, 0.5, 2.5}}})}); + histPointers.insert({histPath + "hNTracks", histos.add((histPath + "hNTracks").c_str(), "hNTracks", {kTH1D, {{20000, 0, 20000}}})}); + } + + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + 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) + { + // 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); + + static constexpr int kMaxLUTConfigs = 20; + std::vector nTracks(kMaxLUTConfigs); + for (auto const& track : tracks) { + int lutConfigId = track.lutConfigId(); + nTracks[lutConfigId]++; + + 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) { + auto xi = xiCand.cascadeTrack_as(); // de-reference cascade track + int lutConfigId = xi.lutConfigId(); + initConf(lutConfigId); + if (minNTracks.value.size() < static_cast(lutConfigId)) { + if (nTracks[lutConfigId] < minNTracks.value.front()) { + continue; // fallback to first + } + } else { + if (nTracks[lutConfigId] < minNTracks.value[lutConfigId]) { + continue; + } + } + + std::string histPath = "Configuration_" + std::to_string(lutConfigId) + "/"; + histos.fill(HIST("hMassXi"), xiCand.mXi()); + histos.fill(HIST("h2dDCAxyVsPtXiFromXiC"), xi.pt(), xi.dcaXY() * 1e+4); + if (std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > massWindowXi) + continue; // out of mass region + + uint32_t nCombinationsC = 0; + 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; // likely a primary xi + + histos.fill(HIST("hDCAxyXi"), std::fabs(xi.dcaXY() * 1e+4)); + histos.fill(HIST("hDCAzXi"), std::fabs(xi.dcaZ() * 1e+4)); + + if (xiCand.cascRadius() < minXiRadius) + continue; + + histos.fill(HIST("hMinXiDecayRadius"), xiCand.cascRadius()); + for (auto const& pi1c : tracksPiFromXiCgrouped) { + if (!checkSameLUTConf(pi1c, lutConfigId)) + continue; + 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; // too low momentum + + histos.fill(HIST("hPi1cPt"), pi1c.pt()); + float pi1cTOFDiffInner = std::fabs(pi1c.innerTOFTrackTimeReco() - pi1c.innerTOFExpectedTimePi()); + float pi1cTOFDiffOuter = std::fabs(pi1c.outerTOFTrackTimeReco() - pi1c.outerTOFExpectedTimePi()); + if (pi1cTOFDiffInner > piFromXiC_tofDiffInner) + continue; // did not arrive at expected time + + histos.fill(HIST("hInnerTOFTrackTimeRecoPi1c"), pi1cTOFDiffInner); + // second pion from XiC decay for starts here + for (auto const& pi2c : tracksPiFromXiCgrouped) { + if (!checkSameLUTConf(pi2c, lutConfigId)) + continue; + 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; // too low momentum + + histos.fill(HIST("hPi2cPt"), pi2c.pt()); + float pi2cTOFDiffInner = std::fabs(pi2c.innerTOFTrackTimeReco() - pi2c.innerTOFExpectedTimePi()); + float pi2cTOFDiffOuter = std::fabs(pi2c.outerTOFTrackTimeReco() - pi2c.outerTOFExpectedTimePi()); + if (pi2cTOFDiffInner > piFromXiC_tofDiffInner) + continue; // did not arrive at expected time + + histos.fill(HIST("hInnerTOFTrackTimeRecoPi2c"), pi2cTOFDiffInner); + // 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 + + histos.fill(HIST("hDCAXiCDaughters"), thisXiCcandidate.dca * 1e+4); + + 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); + float xicDecayRadius2D = std::hypot(thisXiCcandidate.xyz[0], thisXiCcandidate.xyz[1]); + if (xicDecayRadius2D < minXiCRadius) + continue; // do not take if radius too small, likely a primary combination + + histos.fill(HIST("hMinXiCDecayRadius"), xicDecayRadius2D * 1e+4); + + if (xicDecayRadius2D > xiCand.cascRadius()) + continue; + + histos.fill(HIST("hXiRadiusVsXicRadius"), xiCand.cascRadius() * 1e+4, xicDecayRadius2D * 1e+4); + + 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; // likely a primary xic + + histos.fill(HIST("hDCAxyXiC"), std::fabs(xicdcaXY * 1e+4)); + histos.fill(HIST("hDCAzXiC"), std::fabs(xicdcaZ * 1e+4)); + histos.fill(HIST("hMassXiC"), thisXiCcandidate.mass); + + // attempt XiCC finding + uint32_t nCombinationsCC = 0; + for (auto const& picc : tracksPiFromXiCCgrouped) { + if (!checkSameLUTConf(picc, lutConfigId)) + continue; + + 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; // too low momentum + + histos.fill(HIST("hPiccPt"), picc.pt()); + + float piccTOFDiffInner = std::fabs(picc.innerTOFTrackTimeReco() - picc.innerTOFExpectedTimePi()); + float piccTOFDiffOuter = std::fabs(picc.outerTOFTrackTimeReco() - picc.outerTOFExpectedTimePi()); + if (piccTOFDiffInner > piFromXiCC_tofDiffInner) + continue; // did not arrive at expected time + + histos.fill(HIST("hInnerTOFTrackTimeRecoPicc"), piccTOFDiffInner); + + 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 + + histos.fill(HIST("hDCAXiCCDaughters"), thisXiCCcandidate.dca * 1e+4); + + 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); + float xiccDecayRadius2D = std::hypot(thisXiCCcandidate.xyz[0], thisXiCCcandidate.xyz[1]); + if (xiccDecayRadius2D < minXiCCRadius) + continue; // do not take if radius too small, likely a primary combination + + histos.fill(HIST("hMinXiCCDecayRadius"), xiccDecayRadius2D * 1e+4); + + float totalMomentumC = std::hypot(momentumC[0], momentumC[1], momentumC[2]); + float decayLengthXiC = std::hypot( + thisXiCcandidate.xyz[0] - thisXiCCcandidate.xyz[0], + thisXiCcandidate.xyz[1] - thisXiCCcandidate.xyz[1], + thisXiCcandidate.xyz[2] - thisXiCCcandidate.xyz[2]); + float xicProperLength = decayLengthXiC * thisXiCcandidate.mass / totalMomentumC; + + if (xicProperLength < xicMinProperLength || xicProperLength > xicMaxProperLength) + continue; // likely background + + histos.fill(HIST("hProperLengthXiC"), xicProperLength * 1e+4); + + float xicDistanceFromPV = std::hypot( + thisXiCcandidate.xyz[0] - collision.posX(), + thisXiCcandidate.xyz[1] - collision.posY(), + thisXiCcandidate.xyz[2] - collision.posZ()); + float xicDecayDistanceFromPV = xicDistanceFromPV * thisXiCcandidate.mass / totalMomentumC; + if (xicDecayDistanceFromPV < xicMinDecayDistanceFromPV) + continue; // too close to PV + + histos.fill(HIST("hMinxicDecayDistanceFromPV"), xicDecayDistanceFromPV * 1e+4); + + float totalMomentumCC = std::hypot(momentumCC[0], momentumCC[1], momentumCC[2]); + float decayLengthXiCC = std::hypot( + thisXiCCcandidate.xyz[0] - collision.posX(), + thisXiCCcandidate.xyz[1] - collision.posY(), + thisXiCCcandidate.xyz[2] - collision.posZ()); + float xiccProperLength = decayLengthXiCC * thisXiCCcandidate.mass / totalMomentumCC; + if (xiccProperLength < xiccMinProperLength || xiccProperLength > xicMaxProperLength) + continue; // likely background + + histos.fill(HIST("hProperLengthXiCC"), xiccProperLength * 1e+4); + if (xiccDecayRadius2D > xicDecayRadius2D) + continue; // XiCC should decay before XiC + + histos.fill(HIST("hXicRadiusVsXiccRadius"), xicDecayRadius2D * 1e+4, xiccDecayRadius2D * 1e+4); + + 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; // not pointing to PV + + histos.fill(HIST("hDCAxyXiCC"), std::fabs(xiccdcaXY * 1e+4)); + histos.fill(HIST("hDCAzXiCC"), std::fabs(xiccdcaZ * 1e+4)); + + if (std::fabs(thisXiCCcandidate.eta) > xiccMaxEta) + continue; // not in central barrel + + histos.fill(HIST("hCharmBuilding"), 3.0f); + histos.fill(HIST("hMassXiCC"), thisXiCCcandidate.mass); + getHist(TH1, histPath + "hMassXiCC")->Fill(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) { + multiCharmIdx( + xiCand.globalIndex(), + pi1c.globalIndex(), pi2c.globalIndex(), + picc.globalIndex()); + + multiCharmCore( + thisXiCCcandidate.mass, thisXiCCcandidate.pt, + thisXiCCcandidate.eta, thisXiCCcandidate.dca, + thisXiCcandidate.mass, thisXiCcandidate.pt, + thisXiCcandidate.eta, thisXiCcandidate.dca, + xi.dcaXY(), xi.dcaZ(), + xicdcaXY, xicdcaZ, + xiccdcaXY, xiccdcaZ, + pi1c.dcaXY(), pi1c.dcaZ(), + pi2c.dcaXY(), pi2c.dcaZ(), + picc.dcaXY(), picc.dcaZ(), + xicDecayRadius2D, xiccDecayRadius2D, + xicProperLength, + xicDecayDistanceFromPV, + xiccProperLength, + pi1c.pt(), pi2c.pt(), picc.pt(), + lutConfigId); + + multiCharmPID( + pi1cTOFDiffInner, pi1c.nSigmaPionInnerTOF(), + pi1cTOFDiffOuter, pi1c.nSigmaPionOuterTOF(), + pi1c.hasSigPi(), pi1c.nSigmaPionRich(), + getPdgCodeForTrack(pi1c), + pi2cTOFDiffInner, pi2c.nSigmaPionInnerTOF(), + pi2cTOFDiffOuter, pi2c.nSigmaPionOuterTOF(), + pi2c.hasSigPi(), pi2c.nSigmaPionRich(), + getPdgCodeForTrack(pi2c), + piccTOFDiffInner, picc.nSigmaPionInnerTOF(), + piccTOFDiffOuter, picc.nSigmaPionOuterTOF(), + picc.hasSigPi(), picc.nSigmaPionRich(), + getPdgCodeForTrack(picc)); + + multiCharmExtra( + piFromXi.pt(), piFromXi.eta(), + piFromXi.dcaXY(), piFromXi.dcaZ(), + prFromLa.pt(), prFromLa.eta(), + prFromLa.dcaXY(), prFromLa.dcaZ(), + piFromLa.pt(), piFromLa.eta(), + piFromLa.dcaXY(), piFromLa.dcaZ(), + pi1c.eta(), pi2c.eta(), picc.eta()); + + histos.fill(HIST("hPi1cDCAxy"), std::abs(pi1c.dcaXY() * 1e+4)); + histos.fill(HIST("hPi1cDCAz"), std::abs(pi1c.dcaZ() * 1e+4)); + histos.fill(HIST("hPi2cDCAxy"), std::abs(pi2c.dcaXY() * 1e+4)); + histos.fill(HIST("hPi2cDCAz"), std::abs(pi2c.dcaZ() * 1e+4)); + histos.fill(HIST("hPiccDCAxy"), std::abs(picc.dcaXY() * 1e+4)); + histos.fill(HIST("hPiccDCAz"), std::abs(picc.dcaZ() * 1e+4)); + } + } + histos.fill(HIST("hCombinationsXiCC"), nCombinationsCC); + } + } + histos.fill(HIST("hCombinationsXiC"), nCombinationsC); + } + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + + //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* + PROCESS_SWITCH(alice3multicharmTable, processGenerated, "fill MC-only histograms", true); + PROCESS_SWITCH(alice3multicharmTable, 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 deleted file mode 100644 index 4ced165e00a..00000000000 --- a/ALICE3/TableProducer/alice3-pidTOF.cxx +++ /dev/null @@ -1,324 +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 alice3-pidTOF.cxx -/// \author Nicolò Jacazio nicolo.jacazio@cern.ch -/// \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. -/// - -// O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "ReconstructionDataFormats/Track.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/DataModel/PIDResponse.h" -#include "ALICE3/Core/TOFResoALICE3.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/StaticFor.h" - -using namespace o2; -using namespace o2::framework; -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, {"Produce TOF PID QA histograms"}}}; - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - -struct ALICE3tofSignal { /// Task that produces the TOF signal from the trackTime - Produces table; - bool enableTable = false; - - void init(o2::framework::InitContext& initContext) - { - // Checking the tables are requested in the workflow and enabling them - auto& workflows = initContext.services().get(); - for (DeviceSpec const& device : workflows.devices) { - for (auto const& input : device.inputs) { - const std::string table = "TOFSignal"; - if (input.matcher.binding == table) { - enableTable = true; - } - } - } - } - using Trks = soa::Join; - void process(Trks const& tracks) - { - if (!enableTable) { - return; - } - table.reserve(tracks.size()); - for (auto& t : tracks) { - table(t.trackTime() * 1000.f); - } - } -}; - -struct ALICE3pidTOFTask { - using Trks = soa::Join; - using Coll = aod::Collisions; - // Tables to produce - Produces tablePIDEl; - Produces tablePIDMu; - Produces tablePIDPi; - Produces tablePIDKa; - Produces tablePIDPr; - Produces tablePIDDe; - Produces tablePIDTr; - Produces tablePIDHe; - Produces tablePIDAl; - Parameters resoParameters{1}; - Service ccdb; - Configurable paramfile{"param-file", "", "Path to the parametrization object, if empty the parametrization is not taken from file"}; - Configurable sigmaname{"param-sigma", "TOFResoALICE3", "Name of the parametrization for the expected sigma, used in both file and CCDB mode"}; - Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; - - void init(o2::framework::InitContext&) - { - 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()); - // - const std::vector p = {24.5}; - resoParameters.SetParameters(p); - const std::string fname = paramfile.value; - if (!fname.empty()) { // Loading the parametrization from file - LOG(info) << "Loading parametrization from file" << fname << ", using param: " << sigmaname; - resoParameters.LoadParamFromFile(fname.data(), sigmaname.value.data()); - } else { // Loading it from CCDB - const std::string path = "Analysis/ALICE3/PID/TOF/Parameters"; - resoParameters.SetParameters(ccdb->getForTimeStamp(path + "/" + sigmaname.value, timestamp.value)); - } - } - - template - float sigma(Trks::iterator track) - { - return o2::pid::tof::TOFResoALICE3ParamTrack(track, resoParameters); - } - template - float nsigma(Trks::iterator track) - { - 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, - track.length())) / - sigma(track); - } - void process(Trks const& tracks, Coll const&) - { - tablePIDEl.reserve(tracks.size()); - tablePIDMu.reserve(tracks.size()); - tablePIDPi.reserve(tracks.size()); - tablePIDKa.reserve(tracks.size()); - tablePIDPr.reserve(tracks.size()); - tablePIDDe.reserve(tracks.size()); - tablePIDTr.reserve(tracks.size()); - tablePIDHe.reserve(tracks.size()); - tablePIDAl.reserve(tracks.size()); - for (auto const& trk : tracks) { - tablePIDEl(sigma(trk), nsigma(trk)); - tablePIDMu(sigma(trk), nsigma(trk)); - tablePIDPi(sigma(trk), nsigma(trk)); - tablePIDKa(sigma(trk), nsigma(trk)); - tablePIDPr(sigma(trk), nsigma(trk)); - tablePIDDe(sigma(trk), nsigma(trk)); - tablePIDTr(sigma(trk), nsigma(trk)); - tablePIDHe(sigma(trk), nsigma(trk)); - tablePIDAl(sigma(trk), nsigma(trk)); - } - } -}; - -struct ALICE3pidTOFTaskQA { - - static constexpr int Np = 9; - static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"}; - static constexpr std::string_view hexpected[Np] = {"expected/El", "expected/Mu", "expected/Pi", - "expected/Ka", "expected/Pr", "expected/De", - "expected/Tr", "expected/He", "expected/Al"}; - static constexpr std::string_view hexpected_diff[Np] = {"expected_diff/El", "expected_diff/Mu", "expected_diff/Pi", - "expected_diff/Ka", "expected_diff/Pr", "expected_diff/De", - "expected_diff/Tr", "expected_diff/He", "expected_diff/Al"}; - static constexpr std::string_view hexpsigma[Np] = {"expsigma/El", "expsigma/Mu", "expsigma/Pi", - "expsigma/Ka", "expsigma/Pr", "expsigma/De", - "expsigma/Tr", "expsigma/He", "expsigma/Al"}; - 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"}; - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::QAObject}; - - Configurable logAxis{"logAxis", 1, "Flag to use a log momentum axis"}; - Configurable nBinsP{"nBinsP", 400, "Number of bins for the momentum"}; - Configurable minP{"minP", 0.01f, "Minimum momentum in range"}; - Configurable maxP{"maxP", 20.f, "Maximum momentum in range"}; - Configurable nBinsDelta{"nBinsDelta", 200, "Number of bins for the Delta"}; - Configurable minDelta{"minDelta", -1000.f, "Minimum Delta in range"}; - Configurable maxDelta{"maxDelta", 1000.f, "Maximum Delta in range"}; - Configurable nBinsExpSigma{"nBinsExpSigma", 200, "Number of bins for the ExpSigma"}; - Configurable minExpSigma{"minExpSigma", 0.f, "Minimum ExpSigma in range"}; - Configurable maxExpSigma{"maxExpSigma", 200.f, "Maximum ExpSigma in range"}; - Configurable nBinsNSigma{"nBinsNSigma", 200, "Number of bins for the NSigma"}; - Configurable minNSigma{"minNSigma", -10.f, "Minimum NSigma in range"}; - Configurable maxNSigma{"maxNSigma", 10.f, "Maximum NSigma in range"}; - Configurable minMult{"minMult", 1, "Minimum track multiplicity with TOF"}; - - template - void addParticleHistos(const AxisSpec& pAxis, const AxisSpec& /*ptAxis*/) - { - // Exp signal - const AxisSpec expAxis{1000, 0, 2e6, Form("t_{exp}(%s)", pT[i])}; - histos.add(hexpected[i].data(), "", kTH2F, {pAxis, expAxis}); - - // Signal - Expected signal - const AxisSpec deltaAxis{nBinsDelta, minDelta, maxDelta, Form("(t-t_{evt}-t_{exp}(%s))", pT[i])}; - histos.add(hexpected_diff[i].data(), "", kTH2F, {pAxis, deltaAxis}); - - // Exp Sigma - const AxisSpec expSigmaAxis{nBinsExpSigma, minExpSigma, maxExpSigma, Form("Exp_{#sigma}^{TOF}(%s)", pT[i])}; - histos.add(hexpsigma[i].data(), "", kTH2F, {pAxis, expSigmaAxis}); - - // NSigma - const AxisSpec nSigmaAxis{nBinsNSigma, minNSigma, maxNSigma, Form("N_{#sigma}^{TOF}(%s)", pT[i])}; - histos.add(hnsigma[i].data(), "", kTH2F, {pAxis, nSigmaAxis}); - } - - void init(o2::framework::InitContext&) - { - - const AxisSpec multAxis{100, 0, 100, "TOF multiplicity"}; - const AxisSpec vtxZAxis{100, -20, 20, "Vtx_{z} (cm)"}; - const AxisSpec tofAxis{10000, 0, 2e6, "TOF Signal"}; - const AxisSpec etaAxis{100, -2, 2, "#it{#eta}"}; - const AxisSpec colTimeAxis{100, -2000, 2000, "Collision time (ps)"}; - const AxisSpec colTimeResoAxis{100, 0, 1000, "#sigma_{Collision time} (ps)"}; - const AxisSpec lAxis{100, 0, 500, "Track length (cm)"}; - const AxisSpec ptResoAxis{100, 0, 0.1, "#sigma_{#it{p}_{T}}"}; - AxisSpec ptAxis{nBinsP, minP, maxP, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec pAxis{nBinsP, minP, maxP, "#it{p} (GeV/#it{c})"}; - AxisSpec pExpAxis{nBinsP, minP, maxP, "#it{p}_{Exp. TOF} (GeV/#it{c})"}; - if (logAxis) { - ptAxis.makeLogarithmic(); - pAxis.makeLogarithmic(); - pExpAxis.makeLogarithmic(); - } - - // Event properties - histos.add("event/vertexz", "", kTH1F, {vtxZAxis}); - histos.add("event/tofmultiplicity", "", kTH1F, {multAxis}); - histos.add("event/colltime", "", kTH1F, {colTimeAxis}); - histos.add("event/colltimereso", "", kTH2F, {multAxis, colTimeResoAxis}); - histos.add("event/tofsignal", "", kTH2F, {pAxis, tofAxis}); - histos.add("event/pexp", "", kTH2F, {pAxis, pExpAxis}); - histos.add("event/eta", "", kTH1F, {etaAxis}); - histos.add("event/length", "", kTH1F, {lAxis}); - histos.add("event/pt", "", kTH1F, {ptAxis}); - histos.add("event/p", "", kTH1F, {pAxis}); - histos.add("event/ptreso", "", kTH2F, {pAxis, ptResoAxis}); - - static_for<0, 8>([&](auto i) { - addParticleHistos(pAxis, ptAxis); - }); - } - - template - void fillParticleHistos(const T& t, const float& tof, const float& exp_diff, const float& expsigma) - { - histos.fill(HIST(hexpected[i]), t.p(), tof - exp_diff); - histos.fill(HIST(hexpected_diff[i]), t.p(), exp_diff); - histos.fill(HIST(hexpsigma[i]), t.p(), expsigma); - histos.fill(HIST(hnsigma[i]), t.p(), o2::aod::pidutils::tofNSigma(i, t)); - } - - void process(aod::Collision const& collision, - soa::Join const& tracks) - { - // Computing Multiplicity first - int mult = 0; - for (auto t : tracks) { - // - if (!t.hasTOF()) { // Skipping tracks without TOF - continue; - } - mult++; - } - if (mult < minMult) { // Cutting on low multiplicity events - return; - } - - const float collisionTime_ps = collision.collisionTime() * 1000.f; - histos.fill(HIST("event/vertexz"), collision.posZ()); - histos.fill(HIST("event/colltime"), collisionTime_ps); - histos.fill(HIST("event/tofmultiplicity"), mult); - histos.fill(HIST("event/colltimereso"), mult, collision.collisionTimeRes() * 1000.f); - - for (auto t : tracks) { - // - if (!t.hasTOF()) { // Skipping tracks without TOF - continue; - } - if (!t.isGlobalTrack()) { - continue; - } - - const float tofSignal = t.trackTime() * 1e3f; - // const float tof = t.tofSignal() - collisionTime_ps; - const float tof = tofSignal - collisionTime_ps; - - // - // 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/eta"), t.eta()); - histos.fill(HIST("event/length"), t.length()); - histos.fill(HIST("event/pt"), t.pt()); - histos.fill(HIST("event/ptreso"), t.p(), t.sigma1Pt() * t.pt() * t.pt()); - // - fillParticleHistos(t, tof, t.tofExpSignalDiffEl(), t.tofExpSigmaEl()); - fillParticleHistos(t, tof, t.tofExpSignalDiffMu(), t.tofExpSigmaMu()); - fillParticleHistos(t, tof, t.tofExpSignalDiffPi(), t.tofExpSigmaPi()); - fillParticleHistos(t, tof, t.tofExpSignalDiffKa(), t.tofExpSigmaKa()); - fillParticleHistos(t, tof, t.tofExpSignalDiffPr(), t.tofExpSigmaPr()); - fillParticleHistos(t, tof, t.tofExpSignalDiffDe(), t.tofExpSigmaDe()); - fillParticleHistos(t, tof, t.tofExpSignalDiffTr(), t.tofExpSigmaTr()); - fillParticleHistos(t, tof, t.tofExpSignalDiffHe(), t.tofExpSigmaHe()); - fillParticleHistos(t, tof, t.tofExpSignalDiffAl(), t.tofExpSigmaAl()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"alice3-pidTOF-task"}), - adaptAnalysisTask(cfgc, TaskName{"alice3-tof-signal-task"})}; - if (cfgc.options().get("add-qa")) { - workflow.push_back(adaptAnalysisTask(cfgc, TaskName{"alice3-pidTOFQA-task"})); - } - return workflow; -} diff --git a/ALICE3/TableProducer/alice3HfSelector3Prong.cxx b/ALICE3/TableProducer/alice3HfSelector3Prong.cxx new file mode 100644 index 00000000000..4fe0f4d1e19 --- /dev/null +++ b/ALICE3/TableProducer/alice3HfSelector3Prong.cxx @@ -0,0 +1,380 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file alice3HfSelector3prong.cxx +/// \brief 3-prong candidates selection task +/// +/// \author Marcello Di Costanzo , Polytechnic University of Turin and INFN Turin + +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "ALICE3/DataModel/A3DecayFinderTables.h" +#include "ALICE3/DataModel/OTFPIDTrk.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/RICH.h" +#include "ALICE3/ML/HfMlResponse3Prong.h" +#include "ALICE3/Utils/utilsHfAlice3.h" +#include "ALICE3/Utils/utilsSelectionsAlice3.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::aod::a3_hf_sel_3prong; + +/// Struct for applying Lc selection cuts +struct Alice3HfSelector3Prong { + Produces candSelFlags; // flags for isSelLc + Produces candMlScores; + + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of cand pT"}; + Configurable ptCandMax{"ptCandMax", 36., "Upper bound of cand pT"}; + // TRK PID + Configurable ptPidTrkMin{"ptPidTrkMin", 0.1, "Lower bound of track pT for Trk PID"}; + Configurable ptPidTrkMax{"ptPidTrkMax", 1., "Upper bound of track pT for Trk PID"}; + Configurable nSigmaTrkMax{"nSigmaTrkMax", 3., "Nsigma cut on Trk only"}; + // RICH PID + Configurable ptPidRichMin{"ptPidRichMin", 0.1, "Lower bound of track pT for Rich PID"}; + Configurable ptPidRichMax{"ptPidRichMax", 1., "Upper bound of track pT for Rich PID"}; + Configurable nSigmaRichMax{"nSigmaRichMax", 3., "Nsigma cut on Rich only"}; + // INNER TOF PID + Configurable ptPidInnTofMin{"ptPidInnTofMin", 0.5, "Lower bound of track pT for InTOF PID"}; + Configurable ptPidInnTofMax{"ptPidInnTofMax", 2.5, "Upper bound of track pT for InTOF PID"}; + Configurable nSigmaInnTofMax{"nSigmaInnTofMax", 3., "Nsigma cut on InTOF only"}; + // OUTER TOF PID + Configurable ptPidOutTofMin{"ptPidOutTofMin", 0.5, "Lower bound of track pT for OutTOF PID"}; + Configurable ptPidOutTofMax{"ptPidOutTofMax", 2.5, "Upper bound of track pT for OutTOF PID"}; + Configurable nSigmaOutTofMax{"nSigmaOutTofMax", 3., "Nsigma cut on OutTOF only"}; + // 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_3prongs_alice3::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_3prongs_alice3::Cuts[0], hf_cuts_3prongs_alice3::NBinsPt, hf_cuts_3prongs_alice3::NCutVars, hf_cuts_3prongs_alice3::labelsPt, hf_cuts_3prongs_alice3::labelsCutVar}, "Lc cand 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", 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/BDTLc"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_MassHypo0.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"}; + + HfHelperAlice3 hfHelper; + o2::analysis::HfMlResponse3Prong mlResponse; + o2::ccdb::CcdbApi ccdbApi; + + using CandsLc = soa::Join; + using CandsLcWMcTruth = soa::Join; + + float MassReference{-1.f}; + + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + 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) { + 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(); + } + + if (doprocessLc) { + MassReference = o2::constants::physics::MassLambdaCPlus; + } + } + + /// Conjugate-independent topological cuts + /// \tparam T is candidate type + /// \param cand is cand + /// \param candPt is candidate pT + /// \return true if cand passes all cuts + template + bool selectionTopol(const T& cand, float candPt) + { + int const ptBin = findBin(binsPt, candPt); + + // check that the cand pT is within the analysis range + if (candPt < ptCandMin || candPt >= ptCandMax) { + return false; + } + + // cut on daughter pT + if (cand.ptProng0() < cuts->get(ptBin, "pT prong 0") || + cand.ptProng1() < cuts->get(ptBin, "pT prong 1") || + cand.ptProng2() < cuts->get(ptBin, "pT prong 2")) { + return false; + } + + // cosine of pointing angle + if (cand.cpa() <= cuts->get(ptBin, "cos pointing angle")) { + return false; + } + + // cand chi2PCA + if (cand.chi2PCA() > cuts->get(ptBin, "Chi2PCA")) { + return false; + } + + if (cand.decayLength() <= cuts->get(ptBin, "decay length")) { + return false; + } + + // cand decay length XY + if (cand.decayLengthXY() <= cuts->get(ptBin, "decLengthXY")) { + return false; + } + + // cand normalized decay length XY + if (cand.decayLengthXYNormalised() < cuts->get(ptBin, "normDecLXY")) { + return false; + } + + // cand impact parameter XY + if (std::abs(cand.impactParameterXY()) > cuts->get(ptBin, "impParXY")) { + return false; + } + + // cand daughter prong DCA + if (!isSelectedCandidateProngDca(cand)) { + return false; + } + + return true; + } + + /// Candidate mass selection + /// \tparam CharmHad is the charm hadron type + /// \tparam SwapHypo indicates whether to swap mass hypothesis or not + /// \tparam TCandidate is candidate type + /// \param ptBin is candidate pT bin + /// \param cand is candidate + /// \return true if candidate passes mass selection + template + bool selectionCandidateMass(int const ptBin, const TCandidate& cand) + { + float massCand = hfHelper.getCandMass(cand); + // cut on mass window + if (std::abs(massCand - MassReference) > cuts->get(ptBin, "m")) { + return false; + } + + return true; + } + + /// Single-track dca_xy and dca_z cuts + /// \tparam T1 is candidate type + /// \param cand is the Lc cand + /// \return true if all the prongs pass the selections + template + bool isSelectedCandidateProngDca(const T1& cand) + { + return (isSelectedTrackDca(binsPtTrack, cutsSingleTrack, cand.ptProng0(), cand.impactParameterY0(), cand.impactParameterZ0()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, cand.ptProng1(), cand.impactParameterY1(), cand.impactParameterZ1()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, cand.ptProng2(), cand.impactParameterY2(), cand.impactParameterZ2())); + } + + /// Apply PID selection + /// \tparam CharmHad is charm hadron type + /// \tparam TCand is candidate type + /// \param cand is candidate + /// \param pidMask is bitmask to be configured + template + void configurePidMask(const TCand& cand, uint32_t& pidMask) + { + + auto isSelPid = [&](int selCut, float nsigma, float pt, float nSigmaMax, float ptMin, float ptMax) { + bool isSelected = !(pt >= ptMin && pt < ptMax && std::abs(nsigma) > nSigmaMax); + if (isSelected) + SETBIT(pidMask, selCut); + return isSelected; + }; + + // prong 0 + float ptProng0{cand.ptProng0()}; + if constexpr (CharmHad == CharmHadAlice3::Lc) { + isSelPid(cand.nSigTrkPr0(), PidSels::TrkProng0, ptProng0, nSigmaTrkMax, ptPidTrkMin, ptPidTrkMax); + isSelPid(cand.nSigRichPr0(), PidSels::RichProng0, ptProng0, nSigmaRichMax, ptPidRichMin, ptPidRichMax); + isSelPid(cand.nSigInnTofPr0(), PidSels::InnTofProng0, ptProng0, nSigmaInnTofMax, ptPidInnTofMin, ptPidInnTofMax); + isSelPid(cand.nSigOutTofPr0(), PidSels::OutTofProng0, ptProng0, nSigmaOutTofMax, ptPidOutTofMin, ptPidOutTofMax); + } + + // prong 1 + float ptProng1{cand.ptProng1()}; + if constexpr (CharmHad == CharmHadAlice3::Lc) { + isSelPid(cand.nSigTrkKa1(), PidSels::TrkProng1, ptProng1, nSigmaTrkMax, ptPidTrkMin, ptPidTrkMax); + isSelPid(cand.nSigRichKa1(), PidSels::RichProng1, ptProng1, nSigmaRichMax, ptPidRichMin, ptPidRichMax); + isSelPid(cand.nSigInnTofKa1(), PidSels::InnTofProng1, ptProng1, nSigmaInnTofMax, ptPidInnTofMin, ptPidInnTofMax); + isSelPid(cand.nSigOutTofKa1(), PidSels::OutTofProng1, ptProng1, nSigmaOutTofMax, ptPidOutTofMin, ptPidOutTofMax); + } + + // prong 2 + float ptProng2{cand.ptProng2()}; + if constexpr (CharmHad == CharmHadAlice3::Lc) { + isSelPid(cand.nSigTrkPi2(), PidSels::TrkProng2, ptProng2, nSigmaTrkMax, ptPidTrkMin, ptPidTrkMax); + isSelPid(cand.nSigRichPi2(), PidSels::RichProng2, ptProng2, nSigmaRichMax, ptPidRichMin, ptPidRichMax); + isSelPid(cand.nSigInnTofPi2(), PidSels::InnTofProng2, ptProng2, nSigmaInnTofMax, ptPidInnTofMin, ptPidInnTofMax); + isSelPid(cand.nSigOutTofPi2(), PidSels::OutTofProng2, ptProng2, nSigmaOutTofMax, ptPidOutTofMin, ptPidOutTofMax); + } + + return; + } + + /// \brief function to apply Lc selections + /// \tparam CharmHad is charm hadron type + /// \tparam CandType is candidate type + /// \param cands are 3-prong candidates + template + void runSelect3Prong(CandType const& cands) + { + bool isSelMassHypo0{false}; + bool isSelMassHypo1{false}; + std::vector outputMl{-1.f, -1.f, -1.f}; + uint32_t pidMask = 0; + + // looping over 3-prong cands + for (const auto& cand : cands) { + outputMl = {-1.f, -1.f, -1.f}; + pidMask = 0; + + auto ptCand = cand.pt(); + int const ptBin = findBin(binsPt, ptCand); + if (ptBin == -1) { + candSelFlags(isSelMassHypo0, isSelMassHypo1, pidMask); + if (applyMl) { + candMlScores(outputMl[0], outputMl[1], outputMl[2]); + } + continue; + } + + // Here all cands pass the cut on the mass selection + bool const selMassHypo0 = selectionCandidateMass(ptBin, cand); + bool const selMassHypo1 = selectionCandidateMass(ptBin, cand); + if (!selMassHypo0 && !selMassHypo1) { + candSelFlags(isSelMassHypo0, isSelMassHypo1, pidMask); + if (applyMl) { + candMlScores(outputMl[0], outputMl[1], outputMl[2]); + } + continue; + } + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoSkims, ptCand); + } + + // Topological selection (TODO: track quality selection) + if (!selectionTopol(cand, ptCand)) { + candSelFlags(isSelMassHypo0, isSelMassHypo1, pidMask); + if (applyMl) { + candMlScores(outputMl[0], outputMl[1], outputMl[2]); + } + continue; + } + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoTopol, ptCand); + } + + // PID selection + configurePidMask(cand, pidMask); + if (pidMask == 0) { + candSelFlags(isSelMassHypo0, isSelMassHypo1, pidMask); + if (applyMl) { + candMlScores(outputMl[0], outputMl[1], outputMl[2]); + } + continue; + } + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoPID, ptCand); + } + + bool isSelectedMl = true; + // ML selections + if (applyMl) { + + std::vector inputFeaturesMassHypo0 = mlResponse.getInputFeatures(cand); + isSelectedMl = mlResponse.isSelectedMl(inputFeaturesMassHypo0, ptCand, outputMl); + candMlScores(outputMl[0], outputMl[1], outputMl[2]); + if (!isSelectedMl) { + candSelFlags(isSelMassHypo0, isSelMassHypo1, pidMask); + continue; + } + + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoMl, ptCand); + } + } + + candSelFlags(selMassHypo0, selMassHypo1, pidMask); + } + } + + /// \brief process function for cand selection + /// \param cands Lc cand table + void processLc(CandsLcWMcTruth const& cands) + { + runSelect3Prong(cands); + } + PROCESS_SWITCH(Alice3HfSelector3Prong, processLc, "Process 3 prong selection for Lc", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/TableProducer/alice3HfTreeCreator3Prong.cxx b/ALICE3/TableProducer/alice3HfTreeCreator3Prong.cxx new file mode 100644 index 00000000000..15bfcd8da17 --- /dev/null +++ b/ALICE3/TableProducer/alice3HfTreeCreator3Prong.cxx @@ -0,0 +1,517 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file alice3HfTreeCreator3Prong.cxx +/// \brief Writer of 3-prong candidates in the form of flat tables to be stored in TTrees. +/// Intended for debug, local optimization of analysis on small samples or ML training. +/// +/// \author Marcello Di Costanzo , Turin Polytechnic University and INFN Turin + +#include "ALICE3/DataModel/A3DecayFinderTables.h" +#include "ALICE3/DataModel/OTFPIDTrk.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/RICH.h" +#include "ALICE3/Utils/utilsHfAlice3.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace full +{ +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(PtProng2, ptProng2, float); //! Transverse momentum of prong2 (GeV/c) +DECLARE_SOA_COLUMN(PProng2, pProng2, float); //! Momentum of prong2 (GeV/c) +DECLARE_SOA_COLUMN(ImpactParameterNormalised2, impactParameterNormalised2, float); //! Normalised impact parameter of prong2 +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of cand (GeV/c2) +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of cand (GeV/c) +DECLARE_SOA_COLUMN(P, p, float); //! Momentum of cand (GeV/c) +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of cand +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of cand +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of cand +DECLARE_SOA_COLUMN(E, e, float); //! Energy of cand (GeV) +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of cand (cm) +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of cand (cm) +DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of cand +DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! Normalised transverse decay length of cand +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of cand +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine pointing angle of cand in transverse plane +// PID columns +// Prong 0 +DECLARE_SOA_COLUMN(NSigTrkPi0, nSigTrkPi0, float); //! +DECLARE_SOA_COLUMN(NSigRichPi0, nSigRichPi0, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPi0, nSigInnTofPi0, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPi0, nSigOutTofPi0, float); //! +DECLARE_SOA_COLUMN(NSigTrkKa0, nSigTrkKa0, float); //! +DECLARE_SOA_COLUMN(NSigRichKa0, nSigRichKa0, float); //! +DECLARE_SOA_COLUMN(NSigInnTofKa0, nSigInnTofKa0, float); //! +DECLARE_SOA_COLUMN(NSigOutTofKa0, nSigOutTofKa0, float); //! +DECLARE_SOA_COLUMN(NSigTrkPr0, nSigTrkPr0, float); //! +DECLARE_SOA_COLUMN(NSigRichPr0, nSigRichPr0, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPr0, nSigInnTofPr0, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPr0, nSigOutTofPr0, float); //! +// Prong 1 +DECLARE_SOA_COLUMN(NSigTrkPi1, nSigTrkPi1, float); //! +DECLARE_SOA_COLUMN(NSigRichPi1, nSigRichPi1, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPi1, nSigInnTofPi1, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPi1, nSigOutTofPi1, float); //! +DECLARE_SOA_COLUMN(NSigTrkKa1, nSigTrkKa1, float); //! +DECLARE_SOA_COLUMN(NSigRichKa1, nSigRichKa1, float); //! +DECLARE_SOA_COLUMN(NSigInnTofKa1, nSigInnTofKa1, float); //! +DECLARE_SOA_COLUMN(NSigOutTofKa1, nSigOutTofKa1, float); //! +DECLARE_SOA_COLUMN(NSigTrkPr1, nSigTrkPr1, float); //! +DECLARE_SOA_COLUMN(NSigRichPr1, nSigRichPr1, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPr1, nSigInnTofPr1, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPr1, nSigOutTofPr1, float); //! +// Prong 2 +DECLARE_SOA_COLUMN(NSigTrkPi2, nSigTrkPi2, float); //! +DECLARE_SOA_COLUMN(NSigRichPi2, nSigRichPi2, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPi2, nSigInnTofPi2, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPi2, nSigOutTofPi2, float); //! +DECLARE_SOA_COLUMN(NSigTrkKa2, nSigTrkKa2, float); //! +DECLARE_SOA_COLUMN(NSigRichKa2, nSigRichKa2, float); //! +DECLARE_SOA_COLUMN(NSigInnTofKa2, nSigInnTofKa2, float); //! +DECLARE_SOA_COLUMN(NSigOutTofKa2, nSigOutTofKa2, float); //! +DECLARE_SOA_COLUMN(NSigTrkPr2, nSigTrkPr2, float); //! +DECLARE_SOA_COLUMN(NSigRichPr2, nSigRichPr2, float); //! +DECLARE_SOA_COLUMN(NSigInnTofPr2, nSigInnTofPr2, float); //! +DECLARE_SOA_COLUMN(NSigOutTofPr2, nSigOutTofPr2, float); //! +// 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 +DECLARE_SOA_COLUMN(MlScore2, mlScore2, float); //! ML score of the third configured index +} // namespace full + +// Topology tables +DECLARE_SOA_TABLE(Alice3CandVtxs, "AOD", "ALICE3CANDVTX", //! + collision::PosX, + collision::PosY, + collision::PosZ, + a3_hf_cand::XSecondaryVertex, + a3_hf_cand::YSecondaryVertex, + a3_hf_cand::ZSecondaryVertex, + full::RSecondaryVertex); + +DECLARE_SOA_TABLE(Alice3CandTopos, "AOD", "ALICE3CANDTOPO", //! + a3_hf_cand::Chi2PCA, + full::DecayLength, + a3_hf_cand::ErrorDecayLength, + full::DecayLengthXY, + a3_hf_cand::ErrorDecayLengthXY, + full::DecayLengthNormalised, + full::DecayLengthXYNormalised, + full::Cpa, + full::CpaXY); + +DECLARE_SOA_TABLE(Alice3DaugTopos, "AOD", "ALICE3DAUGTOPO", //! + full::ImpactParameterNormalised0, + full::ImpactParameterNormalised1, + full::ImpactParameterNormalised2, + a3_hf_cand::ImpactParameterY0, + a3_hf_cand::ImpactParameterY1, + a3_hf_cand::ImpactParameterY2, + a3_hf_cand::ErrorImpactParameterY0, + a3_hf_cand::ErrorImpactParameterY1, + a3_hf_cand::ErrorImpactParameterY2, + a3_hf_cand::ImpactParameterZ0, + a3_hf_cand::ImpactParameterZ1, + a3_hf_cand::ImpactParameterZ2, + a3_hf_cand::ErrorImpactParameterZ0, + a3_hf_cand::ErrorImpactParameterZ1, + a3_hf_cand::ErrorImpactParameterZ2); + +// ML tables +DECLARE_SOA_TABLE(Alice3PMls, "AOD", "ALICE3PML", + full::MlScore0, + full::MlScore1, + full::MlScore2) +// Kinematics information table +DECLARE_SOA_TABLE(Alice3Kine3Ps, "AOD", "ALICE3KINE3P", + full::PtProng0, + full::PtProng1, + full::PtProng2, + full::Pt, + full::P, + full::Eta, + full::Phi, + full::M, + full::Y, + full::E); + +DECLARE_SOA_TABLE(Alice3Cand3PGens, "AOD", "ALICE3CAND3PGEN", + full::Pt, + full::Eta, + full::Phi, + full::Y); +DECLARE_SOA_TABLE(Alice3DaugMoms, "AOD", "ALICE3DAUGMOM", //! + a3_hf_cand::PxProng0, a3_hf_cand::PyProng0, a3_hf_cand::PzProng0, full::PProng0, + a3_hf_cand::PxProng1, a3_hf_cand::PyProng1, a3_hf_cand::PzProng1, full::PProng1, + a3_hf_cand::PxProng2, a3_hf_cand::PyProng2, a3_hf_cand::PzProng2, full::PProng2); +// MC matching tables +DECLARE_SOA_TABLE(Alice3McRecs, "AOD", "ALICE3MCREC", + a3_mc_truth::FlagMcRec, + a3_mc_truth::OriginMcRec); + +DECLARE_SOA_TABLE(Alice3McGens, "AOD", "ALICE3MCGEN", + a3_mc_truth::FlagMcGen, + a3_mc_truth::OriginMcGen); +// PID tables +DECLARE_SOA_TABLE(Alice3PidPi0s, "AOD", "ALICE3PIDPI0", + full::NSigTrkPi0, + full::NSigRichPi0, + full::NSigInnTofPi0, + full::NSigOutTofPi0) +DECLARE_SOA_TABLE(Alice3PidPi1s, "AOD", "ALICE3PIDPI1", + full::NSigTrkPi1, + full::NSigRichPi1, + full::NSigInnTofPi1, + full::NSigOutTofPi1) +DECLARE_SOA_TABLE(Alice3PidPi2s, "AOD", "ALICE3PIDPI2", + full::NSigTrkPi2, + full::NSigRichPi2, + full::NSigInnTofPi2, + full::NSigOutTofPi2) +DECLARE_SOA_TABLE(Alice3PidKa0s, "AOD", "ALICE3PIDKA0", + full::NSigTrkKa0, + full::NSigRichKa0, + full::NSigInnTofKa0, + full::NSigOutTofKa0) +DECLARE_SOA_TABLE(Alice3PidKa1s, "AOD", "ALICE3PIDKA1", + full::NSigTrkKa1, + full::NSigRichKa1, + full::NSigInnTofKa1, + full::NSigOutTofKa1) +DECLARE_SOA_TABLE(Alice3PidKa2s, "AOD", "ALICE3PIDKA2", + full::NSigTrkKa2, + full::NSigRichKa2, + full::NSigInnTofKa2, + full::NSigOutTofKa2) +DECLARE_SOA_TABLE(Alice3PidPr0s, "AOD", "ALICE3PIDPR0", + full::NSigTrkPr0, + full::NSigRichPr0, + full::NSigInnTofPr0, + full::NSigOutTofPr0) +DECLARE_SOA_TABLE(Alice3PidPr1s, "AOD", "ALICE3PIDPR1", + full::NSigTrkPr1, + full::NSigRichPr1, + full::NSigInnTofPr1, + full::NSigOutTofPr1) +DECLARE_SOA_TABLE(Alice3PidPr2s, "AOD", "ALICE3PIDPR2", + full::NSigTrkPr2, + full::NSigRichPr2, + full::NSigInnTofPr2, + full::NSigOutTofPr2) + +} // namespace o2::aod + +/// Writes the full information in an output TTree +struct Alice3HfTreeCreator3Prong { + Produces rowCandVtxs; + Produces rowCandTopos; + Produces rowDaugTopos; + Produces rowCandMls; + Produces rowCandKine3Ps; + Produces rowCand3PGen; + Produces rowDaugMoms; + Produces rowCand3PMcMatchRec; + Produces rowCand3PMcMatchGen; + Produces rowPidPi0; + Produces rowPidPi1; + Produces rowPidPi2; + Produces rowPidKa0; + Produces rowPidKa1; + Produces rowPidKa2; + Produces rowPidPr0; + Produces rowPidPr1; + Produces rowPidPr2; + + // Configurables to fill tables + struct : o2::framework::ConfigurableGroup { + Configurable fillCandVtxInfo{"fillCandVtxInfo", false, "fill candidate vtx info"}; + Configurable fillCandTopoInfo{"fillCandTopoInfo", false, "fill candidate topology info"}; + Configurable fillDaugTopoInfo{"fillDaugTopoInfo", false, "fill daughter topology info"}; + Configurable fillMlScoreInfo{"fillMlScoreInfo", false, "fill ML scores info"}; + Configurable fillCandKineInfo{"fillCandKineInfo", false, "fill candidate kinematic info"}; + Configurable fillCandGenKineInfo{"fillCandGenKineInfo", false, "fill generated candidate kinematic info"}; + Configurable fillDaugKineInfo{"fillDaugKineInfo", false, "fill daughter kinematic info"}; + Configurable fillMcMatchRecoInfo{"fillMcMatchRecoInfo", false, "fill MC match reconstruction info"}; + Configurable fillMcMatchGenInfo{"fillMcMatchGenInfo", false, "fill MC match generation info"}; + Configurable fillPid{"fillPid", false, "fill PID info"}; + } fillTables; + // parameters for production of training samples + Configurable fillOnlySignal{"fillOnlySignal", true, "Flag to fill derived tables with signal"}; + Configurable fillOnlyBackground{"fillOnlyBackground", false, "Flag to fill derived tables with background"}; + Configurable downSampleFactor{"downSampleFactor", 1., "Fraction of cands to keep"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + + HfHelperAlice3 hfHelper; + + using CandsLcRec = soa::Filtered>; + using CandsLcRecWMl = soa::Filtered>; + using CandsMcGen = soa::Join; + + Filter filterSelectCandidates = (aod::a3_hf_sel_3prong::isSelMassHypo0 == true || aod::a3_hf_sel_3prong::isSelMassHypo1 == true); + Filter filterSelectGenCands = nabs(aod::a3_mc_truth::flagMcGen) == static_cast(CharmHadAlice3::Lc); + + Partition recoLcCandSig = nabs(o2::aod::a3_mc_truth::flagMcRec) == static_cast(CharmHadAlice3::Lc); + Partition recoLcCandBkg = nabs(o2::aod::a3_mc_truth::flagMcRec) == 0; + Partition recoLcCandSigWMl = nabs(o2::aod::a3_mc_truth::flagMcRec) == static_cast(CharmHadAlice3::Lc); + Partition recoLcCandBkgWMl = nabs(o2::aod::a3_mc_truth::flagMcRec) == 0; + + void init(InitContext const&) + { + const std::array doprocess{doprocessLc, doprocessLcWMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "no or more than one process function enabled! Please check your configuration!"); + } + } + + /// Reserve space in the output tables + /// \tparam TCand Type of candidate + /// \param nCands Number of candidates to reserve space for + /// \param cand Candidate to be used to check which PID tables to reserve + template + void reserveTables(size_t nCands, const TCand& cand) + { + if (fillTables.fillCandVtxInfo) + rowCandVtxs.reserve(nCands); + if (fillTables.fillCandTopoInfo) + rowCandTopos.reserve(nCands); + if (fillTables.fillDaugTopoInfo) + rowDaugTopos.reserve(nCands); + if (fillTables.fillMlScoreInfo) + rowCandMls.reserve(nCands); + if (fillTables.fillCandKineInfo) + rowCandKine3Ps.reserve(nCands); + if (fillTables.fillCandGenKineInfo) + rowCand3PGen.reserve(nCands); + if (fillTables.fillDaugKineInfo) + rowDaugMoms.reserve(nCands); + if (fillTables.fillMcMatchRecoInfo) + rowCand3PMcMatchRec.reserve(nCands); + if (fillTables.fillMcMatchGenInfo) + rowCand3PMcMatchGen.reserve(nCands); + // PID tables + if (fillTables.fillPid) { + if constexpr (requires { cand.nSigTrkPi0(); }) + rowPidPi0.reserve(nCands); + if constexpr (requires { cand.nSigTrkPi1(); }) + rowPidPi1.reserve(nCands); + if constexpr (requires { cand.nSigTrkPi2(); }) + rowPidPi2.reserve(nCands); + if constexpr (requires { cand.nSigTrkKa0(); }) + rowPidKa0.reserve(nCands); + if constexpr (requires { cand.nSigTrkKa1(); }) + rowPidKa1.reserve(nCands); + if constexpr (requires { cand.nSigTrkKa2(); }) + rowPidKa2.reserve(nCands); + if constexpr (requires { cand.nSigTrkPr0(); }) + rowPidPr0.reserve(nCands); + if constexpr (requires { cand.nSigTrkPr1(); }) + rowPidPr1.reserve(nCands); + if constexpr (requires { cand.nSigTrkPr2(); }) + rowPidPr2.reserve(nCands); + } + } + + /// Fill reconstructed candidate tables + /// \tparam CharmHadAlice3: charm hadron type + /// \tparam IsSwapMassHypo: whether to swap mass hypothesis or not + /// \tparam T: candidate type + /// \param cand: candidate to be used to fill the tables + template + void fillRecoTables(const T& cand) + { + if (fillTables.fillCandVtxInfo) { + rowCandVtxs( + cand.posX(), + cand.posY(), + cand.posZ(), + cand.xSecondaryVertex(), + cand.ySecondaryVertex(), + cand.zSecondaryVertex(), + cand.rSecondaryVertex()); + } + if (fillTables.fillCandTopoInfo) { + rowCandTopos( + cand.chi2PCA(), + cand.decayLength(), + cand.errorDecayLength(), + cand.decayLengthXY(), + cand.errorDecayLengthXY(), + cand.decayLengthNormalised(), + cand.decayLengthXYNormalised(), + cand.cpa(), + cand.cpaXY()); + } + if (fillTables.fillDaugTopoInfo) { + rowDaugTopos( + cand.impactParameterNormalised0(), + cand.impactParameterNormalised1(), + cand.impactParameterNormalised2(), + cand.impactParameterY0(), + cand.impactParameterY1(), + cand.impactParameterY2(), + cand.errorImpactParameterY0(), + cand.errorImpactParameterY1(), + cand.errorImpactParameterY2(), + cand.impactParameterZ0(), + cand.impactParameterZ1(), + cand.impactParameterZ2(), + cand.errorImpactParameterZ0(), + cand.errorImpactParameterZ1(), + cand.errorImpactParameterZ2()); + } + if constexpr (requires { cand.mlScore0(); }) { + if (fillTables.fillMlScoreInfo) { + rowCandMls(cand.mlScore0(), cand.mlScore1(), cand.mlScore2()); + } + } + if (fillTables.fillCandKineInfo) { + rowCandKine3Ps( + cand.ptProng0(), cand.ptProng1(), cand.ptProng2(), + cand.pt(), RecoDecay::p(cand.px(), cand.py(), cand.pz()), cand.eta(), cand.phi(), + hfHelper.getCandMass(cand), hfHelper.getCandY(cand), hfHelper.getCandEnergy(cand)); + } + if (fillTables.fillDaugKineInfo) { + rowDaugMoms( + cand.pxProng0(), cand.pyProng0(), cand.pzProng0(), RecoDecay::p(cand.pxProng0(), cand.pyProng0(), cand.pzProng0()), + cand.pxProng1(), cand.pyProng1(), cand.pzProng1(), RecoDecay::p(cand.pxProng1(), cand.pyProng1(), cand.pzProng1()), + cand.pxProng2(), cand.pyProng2(), cand.pzProng2(), RecoDecay::p(cand.pxProng2(), cand.pyProng2(), cand.pzProng2())); + } + if (fillTables.fillMcMatchRecoInfo) + rowCand3PMcMatchRec(cand.flagMcRec(), cand.originMcRec()); + + // Fill PID tables + if (fillTables.fillPid) { + if constexpr (requires { cand.nSigTrkPi0(); }) + rowPidPi0(cand.nSigTrkPi0(), cand.nSigRichPi0(), cand.nSigInnTofPi0(), cand.nSigOutTofPi0()); + if constexpr (requires { cand.nSigTrkPi1(); }) + rowPidPi1(cand.nSigTrkPi1(), cand.nSigRichPi1(), cand.nSigInnTofPi1(), cand.nSigOutTofPi1()); + if constexpr (requires { cand.nSigTrkPi2(); }) + rowPidPi2(cand.nSigTrkPi2(), cand.nSigRichPi2(), cand.nSigInnTofPi2(), cand.nSigOutTofPi2()); + if constexpr (requires { cand.nSigTrkKa0(); }) + rowPidKa0(cand.nSigTrkKa0(), cand.nSigRichKa0(), cand.nSigInnTofKa0(), cand.nSigOutTofKa0()); + if constexpr (requires { cand.nSigTrkKa1(); }) + rowPidKa1(cand.nSigTrkKa1(), cand.nSigRichKa1(), cand.nSigInnTofKa1(), cand.nSigOutTofKa1()); + if constexpr (requires { cand.nSigTrkKa2(); }) + rowPidKa2(cand.nSigTrkKa2(), cand.nSigRichKa2(), cand.nSigInnTofKa2(), cand.nSigOutTofKa2()); + if constexpr (requires { cand.nSigTrkPr0(); }) + rowPidPr0(cand.nSigTrkPr0(), cand.nSigRichPr0(), cand.nSigInnTofPr0(), cand.nSigOutTofPr0()); + if constexpr (requires { cand.nSigTrkPr1(); }) + rowPidPr1(cand.nSigTrkPr1(), cand.nSigRichPr1(), cand.nSigInnTofPr1(), cand.nSigOutTofPr1()); + if constexpr (requires { cand.nSigTrkPr2(); }) + rowPidPr2(cand.nSigTrkPr2(), cand.nSigRichPr2(), cand.nSigInnTofPr2(), cand.nSigOutTofPr2()); + } + } + + /// Function to fill generated tables + /// \tparam CharmHad Type of 3prong particle + /// \tparam T Type of generated candidates collection + /// \param parts Generated candidates collection + template + void fillGenTables(const T& parts) + { + for (const auto& part : parts) { + if (fillTables.fillCandGenKineInfo) { + rowCand3PGen(part.pt(), part.eta(), part.phi(), hfHelper.getCandY(part)); + } + if (fillTables.fillMcMatchGenInfo) { + rowCand3PMcMatchGen(part.flagMcGen(), part.originMcGen()); + } + } + } + + /// Function to fill both reco and gen tables + /// from any candidate collection + /// \tparam CharmHad Type of 3prong particle + /// \tparam TCandsRec Type of reconstructed candidates collection + /// \tparam TCandsGen Type of generated candidates collection + /// \param candsRec Reconstructed candidates collection + /// \param candsGen Generated candidates collection + template + void fillRecoGenTables(const TCandsRec& candsRec, + const TCandsGen& candsGen) + { + reserveTables(candsRec.size(), *candsRec.begin()); + for (const auto& cand : candsRec) { + if (downSampleFactor < 1.) { + float const pseudoRndm = cand.ptProng0() * 1000. - static_cast(cand.ptProng0() * 1000); + if (cand.pt() < ptMaxForDownSample && pseudoRndm >= downSampleFactor) { + continue; + } + } + if (cand.isSelMassHypo0()) { + fillRecoTables(cand); + } + if (cand.isSelMassHypo1()) { + fillRecoTables(cand); + } + } + fillGenTables(candsGen); + } + + void processLc(CandsLcRec const& selCandsLcRec, + CandsMcGen const& parts, + aod::McCollisions const&) + { + if (fillOnlySignal) { + fillRecoGenTables(recoLcCandSig, parts); + } else if (fillOnlyBackground) { + fillRecoGenTables(recoLcCandBkg, parts); + } else { + fillRecoGenTables(selCandsLcRec, parts); + } + } + PROCESS_SWITCH(Alice3HfTreeCreator3Prong, processLc, "Process Lc", true); + + void processLcWMl(CandsLcRecWMl const& selCandsLcRec, + CandsMcGen const& parts, + aod::McCollisions const&) + { + if (fillOnlySignal) { + fillRecoGenTables(recoLcCandSig, parts); + } else if (fillOnlyBackground) { + fillRecoGenTables(recoLcCandBkg, parts); + } else { + fillRecoGenTables(selCandsLcRec, parts); + } + } + PROCESS_SWITCH(Alice3HfTreeCreator3Prong, processLcWMl, "Process Lc with ML", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/TableProducer/alice3TrackingTranslator.cxx b/ALICE3/TableProducer/alice3TrackingTranslator.cxx new file mode 100644 index 00000000000..15abeda2b17 --- /dev/null +++ b/ALICE3/TableProducer/alice3TrackingTranslator.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. + +/// \file alice3TrackingTranslator.cxx +/// +/// \brief Translator task to convert tracking software to the AO2D format digestible with the O2Physics analysis framework +/// +/// \author Nicolò Jacazio, Universita del Piemonte Orientale (IT) +/// + +#include "ALICE3/DataModel/collisionAlice3.h" +#include "ALICE3/DataModel/tracksAlice3.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __CLING__ +#pragma link C++ class std::vector < std::vector < unsigned int>> + ; +#pragma link C++ class std::vector < std::vector < std::uint32_t>> + ; +#endif + +TString inputPath; + +struct Alice3TrackingTranslator { + o2::framework::Produces tableCollisions; + o2::framework::Produces tableMcCollisionLabels; + o2::framework::Produces tableStoredTracks; + o2::framework::Produces tableTracksExtension; + o2::framework::Produces tableStoredTracksCov; + o2::framework::Produces tableTracksCovExtension; + o2::framework::Produces tableMcTrackLabels; + o2::framework::Produces tableTracksDCA; + o2::framework::Produces tableTracksDCACov; + o2::framework::Produces tableCollisionsAlice3; + o2::framework::Produces tableTracksAlice3; + o2::framework::Produces tableTracksExtraA3; + + o2::framework::Produces tableStoredTracksExtra; + o2::framework::Produces tableTrackSelection; + o2::framework::Produces tableTrackSelectionExtension; + o2::framework::Produces tableStoredMcParticles; + o2::framework::Produces tableMcCollisions; + + void init(o2::framework::InitContext&) + { + // Initialization if needed + LOG(info) << "Alice3TrackingTranslator init called"; + // Load dictionary for nested vector + gInterpreter->GenerateDictionary("vector>", "vector"); + } + +#define SETADDRESS(branchname, branchvar) \ + if (mTree->SetBranchAddress(branchname, &branchvar)) { \ + LOG(fatal) << "Could not set branch address for " << branchname; \ + } + struct FileStruct { + FileStruct(std::string filename, std::string treename) : mFile(filename.c_str(), "READ") + { + if (mFile.IsZombie()) { + LOG(fatal) << "Could not open file " << filename; + } + mFile.GetObject(treename.c_str(), mTree); + if (mTree) { + LOG(info) << "Found " << treename << " tree with " << mTree->GetEntries() << " entries."; + } else { + LOG(fatal) << treename << " tree not found in " << filename; + } + } + void setEventEntry(Long64_t entry) + { + if (mTree->GetEntry(entry) < 0) { + LOG(fatal) << "Could not read entry " << entry << " from tree."; + } + } + Long64_t getEntries() const { return mTree->GetEntries(); } + TFile mFile; + TTree* mTree; + }; + + struct ParticleStruct : public FileStruct { + ParticleStruct(std::string filename, std::string treename) : FileStruct(filename, treename) + { + // mTree->Print(); + SETADDRESS("particle_type", m_particle_type); + SETADDRESS("vx", m_vx); + SETADDRESS("vy", m_vy); + SETADDRESS("vz", m_vz); + SETADDRESS("vt", m_vt); + SETADDRESS("px", m_px); + SETADDRESS("py", m_py); + SETADDRESS("pz", m_pz); + SETADDRESS("m", m_m); + SETADDRESS("p", m_p); + } + std::vector* m_particle_type = nullptr; + std::vector* m_vx = nullptr; + std::vector* m_vy = nullptr; + std::vector* m_vz = nullptr; + std::vector* m_vt = nullptr; + std::vector* m_px = nullptr; + std::vector* m_py = nullptr; + std::vector* m_pz = nullptr; + std::vector* m_m = nullptr; + std::vector* m_p = nullptr; + }; + + struct TrackStruct : public FileStruct { + TrackStruct(std::string filename, std::string treename) : FileStruct(filename, treename) + { + mTree->Print(); + // Set branch addresses for ACTS track parameters + + SETADDRESS("event_nr", m_event_nr); + SETADDRESS("nMeasurements", m_nMeasurements); + SETADDRESS("nStates", m_nStates); + SETADDRESS("nHoles", m_nHoles); + SETADDRESS("chi2Sum", m_chi2Sum); + SETADDRESS("NDF", m_NDF); + SETADDRESS("eLOC0_fit", m_eLOC0_fit); + SETADDRESS("eLOC1_fit", m_eLOC1_fit); + SETADDRESS("ePHI_fit", m_ePHI_fit); + SETADDRESS("eTHETA_fit", m_eTHETA_fit); + SETADDRESS("eQOP_fit", m_eQOP_fit); + SETADDRESS("eT_fit", m_eT_fit); + SETADDRESS("nMajorityHits", m_nMajorityHits); + // SETADDRESS("majorityParticleId", m_majorityParticleId); + mTree->SetBranchAddress("majorityParticleId", &m_majorityParticleId); + SETADDRESS("t_charge", m_t_charge); + SETADDRESS("t_vx", m_t_vx); + SETADDRESS("t_vy", m_t_vy); + SETADDRESS("t_vz", m_t_vz); + SETADDRESS("t_time", m_t_time); + SETADDRESS("t_px", m_t_px); + SETADDRESS("t_py", m_t_py); + SETADDRESS("t_pz", m_t_pz); + SETADDRESS("t_theta", m_t_theta); + SETADDRESS("t_phi", m_t_phi); + SETADDRESS("t_pT", m_t_pT); + SETADDRESS("t_eta", m_t_eta); + } + // Define track-related members here + UInt_t* m_event_nr = nullptr; + std::vector* m_nMeasurements = nullptr; + std::vector* m_nStates = nullptr; + std::vector* m_nHoles = nullptr; + std::vector* m_chi2Sum = nullptr; + std::vector* m_NDF = nullptr; + // Fitted track parameters + std::vector* m_eLOC0_fit = nullptr; // local position 0 (typically y in local frame) + std::vector* m_eLOC1_fit = nullptr; // local position 1 (typically z in local frame) + std::vector* m_ePHI_fit = nullptr; // azimuthal angle + std::vector* m_eTHETA_fit = nullptr; // polar angle + std::vector* m_eQOP_fit = nullptr; // q/m_p (charge over momentum) + std::vector* m_eT_fit = nullptr; // time + + // The majority truth particle info + std::vector* m_nMajorityHits = nullptr; /// The number of hits from majority particle + std::vector>* m_majorityParticleId = nullptr; /// The particle Id of the majority particle + std::vector* m_t_charge = nullptr; /// Charge of majority particle + std::vector* m_t_time = nullptr; /// Time of majority particle + std::vector* m_t_vx = nullptr; /// Vertex x positions of majority particle + std::vector* m_t_vy = nullptr; /// Vertex y positions of majority particle + std::vector* m_t_vz = nullptr; /// Vertex z positions of majority particle + std::vector* m_t_px = nullptr; /// Initial momenta m_px of majority particle + std::vector* m_t_py = nullptr; /// Initial momenta m_py of majority particle + std::vector* m_t_pz = nullptr; /// Initial momenta m_pz of majority particle + std::vector* m_t_theta = nullptr; /// Initial momenta theta of majority particle + std::vector* m_t_phi = nullptr; /// Initial momenta phi of majority particle + std::vector* m_t_pT = nullptr; /// Initial momenta pT of majority particle + std::vector* m_t_eta = nullptr; /// Initial momenta eta of majority particle + }; + + struct HitsStruct : public FileStruct { + HitsStruct(std::string filename, std::string treename) : FileStruct(filename, treename) + { + mTree->Print(); + SETADDRESS("barcode", barcode); + } + std::vector* barcode = nullptr; + }; + + void process(o2::aod::BCs const&) + { + LOG(info) << "Alice3TrackingTranslator process called"; + // Find all ROOT files in the folder + std::vector rootFiles; + TSystemDirectory dir(inputPath.Data(), inputPath.Data()); + TList* filesList = dir.GetListOfFiles(); + if (filesList) { + TIter next(filesList); + TSystemFile* file; + while ((file = static_cast(next()))) { + TString fname = file->GetName(); + if (!file->IsDirectory() && fname.EndsWith(".root")) { + TString fullPath = TString::Format("%s/%s", inputPath.Data(), fname.Data()); + rootFiles.push_back(fullPath.Data()); + } + } + delete filesList; + } + // Open all found ROOT files + std::map files; + for (const auto& filename : rootFiles) { + LOG(info) << "Opened ROOT file: " << filename; + // Extract just the filename without path + TString tfilename(filename.c_str()); + TString justFilename = gSystem->BaseName(tfilename); + LOG(info) << "Processing file: " << justFilename.Data(); + files[justFilename.Data()] = filename; + } + + // Now open the files to translate and read the trees + ParticleStruct fileParticles(files["particles_simulation.root"], "particles"); + // FileStruct fileVertices(files["performance_vertexing.root"], "vertexing"); + TrackStruct fileTracksummary(files["tracksummary_ckf.root"], "tracksummary"); + // HitsStruct fileHits(files["hits.root"], "hits"); + + const Long64_t kEvents = fileParticles.getEntries(); + for (Long64_t iEvent = 0; iEvent < kEvents; ++iEvent) { + fileParticles.setEventEntry(iEvent); + // fileVertices.setEventEntry(iEvent); + fileTracksummary.setEventEntry(iEvent); + // fileHits.setEventEntry(iEvent); + + LOG(info) << "Processing event " << iEvent << "/" << kEvents; + + // Create collision entry for this event + // TODO: Extract proper collision position from vertex file if available + float collisionX = 0.0f; + float collisionY = 0.0f; + float collisionZ = 0.0f; + + tableCollisions(0, // bcId + collisionX, // posX + collisionY, // posY + collisionZ, // posZ + 0.0f, // covXX + 0.0f, // covXY + 0.0f, // covXZ + 0.0f, // covYY + 0.0f, // covYZ + 0.0f, // covZZ + 0, // flags + 0.0f, // m_chi2Sum + 0, // numContrib + 0.0f, // collisionTime + 0.0f); // collisionTimeRes + + tableMcCollisionLabels(iEvent, // mcCollisionId + 0); // mcMask + + tableCollisionsAlice3(0.f); // multDensity + + // Fill MC particles + int mothers[2] = {-1, -1}; + int daughters[2] = {-1, -1}; + const size_t nParticlesGen = fileParticles.m_vx->size(); + for (size_t iParticle = 0; iParticle < nParticlesGen; ++iParticle) { + continue; + if (iParticle == 0) { + tableMcCollisions(0, // mccollision::BCId, + 0, // mccollision::GeneratorsID, + fileParticles.m_vx->at(iParticle), // mccollision::PosX, + fileParticles.m_vy->at(iParticle), // mccollision::PosY, + fileParticles.m_vz->at(iParticle), // mccollision::PosZ + fileParticles.m_vt->at(iParticle), // mccollision::T + 1.0f, // mccollision::Weight + 0.0f, // mccollision::ImpactParameter, + 0.f); // mccollision::EventPlaneAngle, + } + + uint8_t flags = 0; + flags |= o2::aod::mcparticle::enums::PhysicalPrimary; + tableStoredMcParticles(tableMcCollisions.lastIndex(), // mcCollisionId + fileParticles.m_particle_type->at(iParticle), // pdgCode + 0, // statusCode + flags, // flags + mothers, // mothersIds + daughters, // daughtersIdSlice + 1.0f, // weight + fileParticles.m_px->at(iParticle), // m_px + fileParticles.m_py->at(iParticle), // m_py + fileParticles.m_pz->at(iParticle), // m_pz + std::hypot(fileParticles.m_p->at(iParticle), fileParticles.m_m->at(iParticle)), // e + fileParticles.m_vx->at(iParticle), // m_vx + fileParticles.m_vy->at(iParticle), // m_vy + fileParticles.m_vz->at(iParticle), // m_vz + fileParticles.m_vt->at(iParticle)); // m_vt + } + + // Convert tracks from ACTS to ALICE format + const size_t nParticles = fileTracksummary.m_t_vx->size(); + const size_t nTracks = fileTracksummary.m_eLOC0_fit->size(); + for (size_t iTrack = 0; iTrack < nTracks; ++iTrack) { + LOG(info) << "Processing track " << iTrack << "/" << nTracks << " (nParticles=" << nParticles << ") nParticlesGen=" << nParticlesGen; + const size_t iParticle = iTrack; + if (iParticle == 0) { + tableMcCollisions(0, // mccollision::BCId, + 0, // mccollision::GeneratorsID, + fileTracksummary.m_t_vx->at(iParticle), // mccollision::PosX, + fileTracksummary.m_t_vy->at(iParticle), // mccollision::PosY, + fileTracksummary.m_t_vz->at(iParticle), // mccollision::PosZ + fileTracksummary.m_t_time->at(iParticle), // mccollision::T + 1.0f, // mccollision::Weight + 0.0f, // mccollision::ImpactParameter, + 0.f); // mccollision::EventPlaneAngle, + } + uint8_t flags = 0; + flags |= o2::aod::mcparticle::enums::PhysicalPrimary; + + // fileTracksummary.m_majorityParticleId->at(iParticle).at(2), // pdgCode + const size_t iParticleGen = fileTracksummary.m_majorityParticleId->at(iParticle).empty() ? 0 : fileTracksummary.m_majorityParticleId->at(iParticle).at(0); + tableStoredMcParticles(tableMcCollisions.lastIndex(), // mcCollisionId + fileParticles.m_particle_type->at(iParticleGen), // pdgCode + 0, // statusCode + flags, // flags + mothers, // mothersIds + daughters, // daughtersIdSlice + 1.0f, // weight + fileTracksummary.m_t_px->at(iParticle), // m_px + fileTracksummary.m_t_py->at(iParticle), // m_py + fileTracksummary.m_t_pz->at(iParticle), // m_pz + 0, // e + fileTracksummary.m_t_vx->at(iParticle), // m_vx + fileTracksummary.m_t_vy->at(iParticle), // m_vy + fileTracksummary.m_t_vz->at(iParticle), // m_vz + fileTracksummary.m_t_time->at(iParticle)); // m_vt + + // Extract ACTS track parameters + const float phi = fileTracksummary.m_ePHI_fit->at(iTrack); + const float theta = fileTracksummary.m_eTHETA_fit->at(iTrack); + const float qOverP = fileTracksummary.m_eQOP_fit->at(iTrack); + const float loc0 = fileTracksummary.m_eLOC0_fit->at(iTrack); + const float loc1 = fileTracksummary.m_eLOC1_fit->at(iTrack); + + // Convert to ALICE track parameters + // ALICE uses: alpha, x, y, z, snp, tgl, signed1Pt + float alpha = phi; // Track angle in global frame + float x = loc0; // Local x position + float y = loc1; // Local y position + float z = 0.0f; // Will be set from DCA or collision vertex + + // Calculate snp (sin of track momentum azimuthal angle) + float snp = std::sin(phi); + + // Calculate tgl (tangent of track momentum dip angle) + float tgl = 1.0f / std::tan(theta); + + // Calculate signed1Pt (charge/pt) + const float m_p = (qOverP != 0) ? std::abs(1.0f / qOverP) : 0.0f; + const float pt = m_p * std::sin(theta); + int8_t charge = (qOverP > 0) ? 1 : -1; + const float signed1Pt = (pt != 0) ? charge / pt : 0.0f; + + // Track quality + float m_chi2Sum = fileTracksummary.m_chi2Sum->at(iTrack); + uint32_t m_nMeasurements = fileTracksummary.m_nMeasurements->at(iTrack); + uint32_t m_NDF = fileTracksummary.m_NDF->at(iTrack); + + // Fill covariance matrices (simplified - should be extracted from ACTS if available) + float cYY = 0.1f; + float cZY = 0.0f; + float cZZ = 0.1f; + float cSnpY = 0.0f; + float cSnpZ = 0.0f; + float cSnpSnp = 0.001f; + float cTglY = 0.0f; + float cTglZ = 0.0f; + float cTglSnp = 0.0f; + float cTglTgl = 0.001f; + float c1PtY = 0.0f; + float c1PtZ = 0.0f; + float c1PtSnp = 0.0f; + float c1PtTgl = 0.0f; + float c1Pt21Pt2 = 0.001f * signed1Pt * signed1Pt; + + // Create TrackParCov object with dummy covariance matrix + std::array trackParams = {y, z, snp, tgl, signed1Pt}; + std::array trackCov = {cYY, cZY, cZZ, cSnpY, cSnpZ, cSnpSnp, + cTglY, cTglZ, cTglSnp, cTglTgl, + c1PtY, c1PtZ, c1PtSnp, c1PtTgl, c1Pt21Pt2}; + o2::track::TrackParCov trackParCov(x, alpha, trackParams, trackCov, charge); + + // Fill StoredTracks table (basic track parameters) + tableStoredTracks(tableCollisions.lastIndex(), // collisionId + o2::aod::track::TrackTypeEnum::Track, // trackType + trackParCov.getX(), // x + trackParCov.getAlpha(), // alpha + trackParCov.getY(), // y + trackParCov.getZ(), // z + trackParCov.getSnp(), // snp + trackParCov.getTgl(), // tgl + trackParCov.getQ2Pt()); // signed1Pt + + // Fill TracksExtension table + tableTracksExtension(trackParCov.getPt(), + trackParCov.getP(), + trackParCov.getEta(), + trackParCov.getPhi()); + + tableStoredTracksCov(std::sqrt(trackParCov.getSigmaY2()), // SigmaY + std::sqrt(trackParCov.getSigmaZ2()), // SigmaZ + std::sqrt(trackParCov.getSigmaSnp2()), // SigmaSnp + std::sqrt(trackParCov.getSigmaTgl2()), // SigmaTgl + std::sqrt(trackParCov.getSigma1Pt2()), // Sigma1Pt + 0, // RhoZY + 0, // RhoSnpY + 0, // RhoSnpZ + 0, // RhoTglY + 0, // RhoTglZ + 0, // RhoTglSnp + 0, // Rho1PtY + 0, // Rho1PtZ + 0, // Rho1PtSnp + 0); // Rho1PtTgl + + // covariance matrix at collision vertex + tableTracksCovExtension(trackParCov.getSigmaY2(), // sigmaY2 + trackParCov.getSigmaZY(), // sigmaZY + trackParCov.getSigmaZ2(), // sigmaZ2 + trackParCov.getSigmaSnpY(), // sigmaSnpY + trackParCov.getSigmaSnpZ(), // sigmaSnpZ + trackParCov.getSigmaSnp2(), // sigmaSnp2 + trackParCov.getSigmaTglY(), // sigmaTglY + trackParCov.getSigmaTglZ(), // sigmaTglZ + trackParCov.getSigmaTglSnp(), // sigmaTglSnp + trackParCov.getSigmaTgl2(), // sigmaTgl2 + trackParCov.getSigma1PtY(), // sigma1PtY + trackParCov.getSigma1PtZ(), // sigma1PtZ + trackParCov.getSigma1PtSnp(), // sigma1PtSnp + trackParCov.getSigma1PtTgl(), // sigma1PtTgl + trackParCov.getSigma1Pt2()); // sigma1Pt2 + + // Fill MC track labels + // Get particle linkage from hits using the majority hit index + int32_t mcParticleId = -1; // Default to invalid particle ID + mcParticleId = tableStoredMcParticles.lastIndex(); // Temporary: link all tracks to the last added MC particle + // if (fileTracksummary.nMajorityHits && iTrack < fileTracksummary.nMajorityHits->size()) { + // unsigned int hitIndex = fileTracksummary.nMajorityHits->at(iTrack); + // if (fileHits.barcode && hitIndex < fileHits.barcode->size()) { + // mcParticleId = static_cast(fileHits.barcode->at(hitIndex)); + // LOG(debug) << "Track " << iTrack << " linked to MC particle " << mcParticleId + // << " via hit index " << hitIndex; + // } else { + // LOG(warning) << "Hit index " << hitIndex << " out of range for track " << iTrack + // << " (barcode vector size: " << (fileHits.barcode ? fileHits.barcode->size() : 0) << ")"; + // } + // } else { + // LOG(warning) << "No majority hit information available for track " << iTrack; + // } + // for ( const auto &vv : fileTracksummary.majorityParticleId->at(iTrack) ){ + // LOG(info) << vv; + // } + tableMcTrackLabels(mcParticleId, // McParticleId + 0); // mcMask + + // Fill DCA info (simplified - should be calculated properly) + tableTracksDCA(0.0f, // dcaXY + 0.0f); // dcaZ + + tableTracksDCACov(0.0f, // sigmaDcaXY2 + 0.0f); // sigmaDcaZ2 + + // Fill ALICE3 specific tables + tableTracksAlice3(true); // isReconstructed + + tableTracksExtraA3(m_nMeasurements, // nSiliconHits (using m_nMeasurements as proxy) + 0); // nTPCHits + + // Fill extra track info + tableStoredTracksExtra(0.f, // TPCInnerParam + static_cast(0), // Flags + static_cast(0), // ITSClusterSizes + static_cast(0), // TPCNClsFindable + static_cast(0), // TPCNClsFindableMinusFound + static_cast(0), // TPCNClsFindableMinusPID + static_cast(0), // TPCNClsFindableMinusCrossedRows + static_cast(0), // TPCNClsShared + static_cast(0), // TRDPattern + m_chi2Sum / (m_NDF > 0 ? m_NDF : 1), // ITSChi2NCl + 0.f, // TPCChi2NCl + 0.f, // TRDChi2 + 0.f, // TOFChi2 + 0.f, // TPCSignal + 0.f, // TRDSignal + 0.f, // Length + 0.f, // TOFExpMom + 0.f, // TrackEtaEMCAL + 0.f, // TrackPhiEMCAL + 0.f, // TrackTime + 0.f); // TrackTimeRes + + // Fill track selection + tableTrackSelection(false, // IsGlobalTrackSDD, + false, // TrackCutFlag, + false, // TrackCutFlagFb1, + false, // TrackCutFlagFb2, + false, // TrackCutFlagFb3, + false, // TrackCutFlagFb4, + false); // TrackCutFlagFb5, + + tableTrackSelectionExtension(false, // PassedTrackType, + false, // PassedPtRange, + false, // PassedEtaRange, + false, // PassedTPCNCls, + false, // PassedTPCCrossedRows, + false, // PassedTPCCrossedRowsOverNCls, + false, // PassedTPCChi2NDF, + false, // PassedTPCRefit, + false, // PassedITSNCls, + false, // PassedITSChi2NDF, + false, // PassedITSRefit, + false, // PassedITSHits, + false, // PassedGoldenChi2, + false, // PassedDCAxy, + false, // PassedDCAz, + false, // PassedITSHitsFB1, + false); // PassedITSHitsFB2 + } + + LOG(info) << "Event " << iEvent << ": has " << nTracks << " tracks and " << nParticles << " particles."; + } + } +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + o2::framework::WorkflowSpec w; + if (cfgc.options().hasOption("aod-file")) { + std::string inputFile = cfgc.options().get("aod-file"); + if (!inputFile.empty()) { + LOG(info) << " " << inputFile; + TString tinputFile(inputFile.c_str()); + inputPath = gSystem->DirName(tinputFile); + } + } + w.push_back(adaptAnalysisTask(cfgc)); + return w; +} diff --git a/ALICE3/Tasks/CMakeLists.txt b/ALICE3/Tasks/CMakeLists.txt index 36a9d8d58e8..719855e43cd 100644 --- a/ALICE3/Tasks/CMakeLists.txt +++ b/ALICE3/Tasks/CMakeLists.txt @@ -39,6 +39,11 @@ o2physics_add_dpl_workflow(alice3-pid-ftof-qa PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(alice3-pid-separation-power + SOURCES alice3SeparationPower.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(alice3-cdeuteron SOURCES alice3-cdeuteron.cxx PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore @@ -48,3 +53,38 @@ o2physics_add_dpl_workflow(alice3-dilepton SOURCES alice3-dilepton.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-taskcorrelationddbar + SOURCES alice3-taskcorrelationDDbar.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-multicharm + SOURCES alice3-multicharm.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-hf-task-3prong + SOURCES alice3HfTask3Prong.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-efficiency + SOURCES alice3Efficiency.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-tracking-performance + SOURCES alice3TrackingPerformance.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-pid-evaluation + SOURCES alice3PidEvaluation.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(alice3-strangeness + SOURCES alice3-strangeness.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/ALICE3/Tasks/ECALqa.cxx b/ALICE3/Tasks/ECALqa.cxx index b3d1b200f71..5e337cefdbd 100644 --- a/ALICE3/Tasks/ECALqa.cxx +++ b/ALICE3/Tasks/ECALqa.cxx @@ -17,12 +17,12 @@ /// // O2 includes -#include "Framework/AnalysisTask.h" #include "ALICE3/DataModel/ECAL.h" -#include "Common/DataModel/PIDResponse.h" -#include "ReconstructionDataFormats/PID.h" + +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" using namespace o2; using namespace o2::track; diff --git a/ALICE3/Tasks/alice3-cdeuteron.cxx b/ALICE3/Tasks/alice3-cdeuteron.cxx index de6b6738d02..c3c67e2efdb 100644 --- a/ALICE3/Tasks/alice3-cdeuteron.cxx +++ b/ALICE3/Tasks/alice3-cdeuteron.cxx @@ -13,15 +13,17 @@ /// \author Alexander Kalweit , CERN // O2 includes +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/PIDResponseTOF.h" + +#include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "TLorentzVector.h" #include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/PID.h" -#include "Common/Core/RecoDecay.h" -#include "DCAFitter/DCAFitterN.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/trackUtilities.h" + +#include "TLorentzVector.h" using namespace o2; using namespace o2::framework; @@ -468,7 +470,7 @@ struct Alice3CDeuteron { // fitterCasc.getTrack(1).getPxPyPzGlo(pvecbach); } // End loop on pions - } // End loop on kaons + } // End loop on kaons histos.fill(HIST("event/candperdeuteron"), ncand); } // End loop on deuterons } diff --git a/ALICE3/Tasks/alice3-dilepton.cxx b/ALICE3/Tasks/alice3-dilepton.cxx index ef8d1ff4b53..455de21fc34 100644 --- a/ALICE3/Tasks/alice3-dilepton.cxx +++ b/ALICE3/Tasks/alice3-dilepton.cxx @@ -14,18 +14,21 @@ /// \author s.scheid@cern.ch, daiki.sekihata@cern.ch /// -#include "Math/Vector4D.h" -// O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/runDataProcessing.h" -#include "Framework/HistogramRegistry.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/AnalysisDataModel.h" -#include "ALICE3/DataModel/OTFTOF.h" #include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFTOF.h" #include "ALICE3/DataModel/tracksAlice3.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include using namespace o2; using namespace o2::aod; @@ -128,6 +131,15 @@ struct Alice3Dilepton { registry.addClone("Reconstructed/Pair/ULS/", "Reconstructed/Pair/LSpp/"); registry.addClone("Reconstructed/Pair/ULS/", "Reconstructed/Pair/LSnn/"); + registry.add("ReconstructedFiltered/Pair/ULS/Mass", "Pair Mass", kTH1F, {axisM}); + registry.add("ReconstructedFiltered/Pair/ULS/Pt", "Pair Pt", kTH1F, {axisPt}); + registry.add("ReconstructedFiltered/Pair/ULS/Eta", "Pair Eta", kTH1F, {axisEta}); + registry.add("ReconstructedFiltered/Pair/ULS/Phi", "Pair Phi", kTH1F, {axisPhi}); + registry.add("ReconstructedFiltered/Pair/ULS/Mass_Pt", "Pair Mass vs. Pt", kTH2F, {axisM, axisPt}, true); + + registry.addClone("ReconstructedFiltered/Pair/ULS/", "ReconstructedFiltered/Pair/LSpp/"); + registry.addClone("ReconstructedFiltered/Pair/ULS/", "ReconstructedFiltered/Pair/LSnn/"); + HistogramConfigSpec hs_rec{HistType::kTHnSparseF, {axisM, axisPt, axisDCAxy}, 3}; registry.add("Reconstructed/Pair/ULS/hs_rec", "", hs_rec); registry.add("Reconstructed/Pair/LSpp/hs_rec", "", hs_rec); @@ -287,6 +299,69 @@ struct Alice3Dilepton { return HFllType::kUndef; } + template + ROOT::Math::PtEtaPhiMVector buildPairDCA(T1 const& t1, T2 const& t2, float& pair_dca_xy) + { + + const float dcaXY_t1 = t1.dcaXY(); + const float dcaXY_t2 = t2.dcaXY(); + const float dcaXY_res_t1 = sqrt(t1.cYY()); + const float dcaXY_res_t2 = sqrt(t2.cYY()); + + pair_dca_xy = sqrt((dcaXY_t2 * dcaXY_t2 / dcaXY_res_t2 + dcaXY_t1 * dcaXY_t1 / dcaXY_res_t1) / 2.); + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), std::abs(pdg) == 11 ? o2::constants::physics::MassElectron : o2::constants::physics::MassMuon); // reconstructed pt/eta/phi + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), std::abs(pdg) == 11 ? o2::constants::physics::MassElectron : o2::constants::physics::MassMuon); // reconstructed pt/eta/phi + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + return v12; + } + + template + void FillPairRecWithPrefilter(TTracks const& tracks1, TTracks const& tracks2, TMCTracks const& /*mcParticles*/) + { + std::vector prefilteredTracks; + if constexpr (pairtype == PairType::kULS) { + for (auto& [t1, t2] : combinations(soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!t1.has_mcParticle() || !t2.has_mcParticle()) { + continue; + } + + float pair_dca_xy = 999.f; + ROOT::Math::PtEtaPhiMVector v12 = buildPairDCA(t1, t2, pair_dca_xy); + // prefilter for low-mass pairs + if (v12.M() > 0.10) { + continue; + } + // prefilter small opening angle pairs + if (std::cos(t1.phi() - t2.phi()) < 0.99) { + continue; + } + prefilteredTracks.push_back(t1.globalIndex()); + prefilteredTracks.push_back(t2.globalIndex()); + + } // end of unlike-sign pair loop + + for (auto& [t1, t2] : combinations(soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + // Skipping tracks that are in the prefiltered list + if (std::find(prefilteredTracks.begin(), prefilteredTracks.end(), t1.globalIndex()) != prefilteredTracks.end()) { + continue; + } + if (std::find(prefilteredTracks.begin(), prefilteredTracks.end(), t2.globalIndex()) != prefilteredTracks.end()) { + continue; + } + + float pair_dca_xy = 999.f; + ROOT::Math::PtEtaPhiMVector v12 = buildPairDCA(t1, t2, pair_dca_xy); + + registry.fill(HIST("ReconstructedFiltered/Pair/ULS/Mass"), v12.M()); + registry.fill(HIST("ReconstructedFiltered/Pair/ULS/Pt"), v12.Pt()); + registry.fill(HIST("ReconstructedFiltered/Pair/ULS/Eta"), v12.Eta()); + registry.fill(HIST("ReconstructedFiltered/Pair/ULS/Phi"), v12.Phi() < 0.f ? v12.Phi() + TMath::TwoPi() : v12.Phi()); + registry.fill(HIST("ReconstructedFiltered/Pair/ULS/Mass_Pt"), v12.M(), v12.Pt()); + registry.fill(HIST("ReconstructedFiltered/Pair/ULS/hs_rec"), v12.M(), v12.Pt(), pair_dca_xy); + } + } + } + template void FillPairRec(TTracks const& tracks1, TTracks const& tracks2, TMCTracks const& mcParticles) { @@ -314,15 +389,8 @@ struct Alice3Dilepton { } // auto mother = mcparticles.iteratorAt(motherid); - // float dcaXY_t1 = t1.dcaXY(); - // float dcaXY_t2 = t2.dcaXY(); - // float dcaXY_res_t1 = sqrt(t1.cYY()); - // float dcaXY_res_t2 = sqrt(t2.cYY()); - - float pair_dca_xy = sqrt((pow(t2.dcaXY() / sqrt(t2.cYY()), 2) + pow(t1.dcaXY() / sqrt(t1.cYY()), 2)) / 2.); - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), std::abs(pdg) == 11 ? o2::constants::physics::MassElectron : o2::constants::physics::MassMuon); // reconstructed pt/eta/phi - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), std::abs(pdg) == 11 ? o2::constants::physics::MassElectron : o2::constants::physics::MassMuon); // reconstructed pt/eta/phi - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float pair_dca_xy = 999.f; + ROOT::Math::PtEtaPhiMVector v12 = buildPairDCA(t1, t2, pair_dca_xy); registry.fill(HIST("Reconstructed/Pair/ULS/Mass"), v12.M()); registry.fill(HIST("Reconstructed/Pair/ULS/Pt"), v12.Pt()); @@ -356,15 +424,8 @@ struct Alice3Dilepton { } // auto mother = mcparticles.iteratorAt(motherid); - // float dcaXY_t1 = t1.dcaXY(); - // float dcaXY_t2 = t2.dcaXY(); - // float dcaXY_res_t1 = sqrt(t1.cYY()); - // float dcaXY_res_t2 = sqrt(t2.cYY()); - - float pair_dca_xy = sqrt((pow(t2.dcaXY() / sqrt(t2.cYY()), 2) + pow(t1.dcaXY() / sqrt(t1.cYY()), 2)) / 2.); - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), std::abs(pdg) == 11 ? o2::constants::physics::MassElectron : o2::constants::physics::MassMuon); // reconstructed pt/eta/phi - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), std::abs(pdg) == 11 ? o2::constants::physics::MassElectron : o2::constants::physics::MassMuon); // reconstructed pt/eta/phi - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float pair_dca_xy = 999.f; + ROOT::Math::PtEtaPhiMVector v12 = buildPairDCA(t1, t2, pair_dca_xy); if constexpr (pairtype == PairType::kLSpp) { registry.fill(HIST("Reconstructed/Pair/LSpp/Mass"), v12.M()); @@ -464,6 +525,7 @@ struct Alice3Dilepton { } // end of like-sign pair loop } } + // Functions for pid template bool electronIDTOF(TTrack const& track) @@ -531,9 +593,9 @@ struct Alice3Dilepton { FillPairGen(neg_mcParticles_coll, neg_mcParticles_coll, mcParticles); } // end of mc collision loop - } // end of processGen + } // end of processGen - using MyTracksMC = soa::Join; + using MyTracksMC = soa::Join; // Filter trackFilter = etaMin < o2::aod::track::eta && // o2::aod::track::eta < etaMax && // ptMin < o2::aod::track::pt && @@ -545,11 +607,10 @@ struct Alice3Dilepton { Partition posTracks = o2::aod::track::signed1Pt > 0.f; Partition negTracks = o2::aod::track::signed1Pt < 0.f; - void processRec( - const o2::aod::Collisions& collisions, - MyFilteredTracksMC const& tracks, - const o2::aod::McCollisions&, - const aod::McParticles& mcParticles) + void processRec(const o2::aod::Collisions& collisions, + MyFilteredTracksMC const& tracks, + const o2::aod::McCollisions&, + const aod::McParticles& mcParticles) { for (const auto& collision : collisions) { registry.fill(HIST("Reconstructed/Event/VtxX"), collision.posX()); @@ -616,7 +677,7 @@ struct Alice3Dilepton { FillPairRec(negTracks_coll, negTracks_coll, mcParticles); } // end of collision loop - } // end of processRec + } // end of processRec PROCESS_SWITCH(Alice3Dilepton, processGen, "Run for generated particle", true); PROCESS_SWITCH(Alice3Dilepton, processRec, "Run for reconstructed track", false); diff --git a/ALICE3/Tasks/alice3-lutmaker.cxx b/ALICE3/Tasks/alice3-lutmaker.cxx index 50c03099468..4b57e462a8e 100644 --- a/ALICE3/Tasks/alice3-lutmaker.cxx +++ b/ALICE3/Tasks/alice3-lutmaker.cxx @@ -25,11 +25,11 @@ using namespace framework::expressions; void customize(std::vector& workflowOptions) { std::vector options{ - {"lut-el", VariantType::Int, 1, {"LUT input for the Electron PDG code"}}, - {"lut-mu", VariantType::Int, 1, {"LUT input for the Muon PDG code"}}, + {"lut-el", VariantType::Int, 0, {"LUT input for the Electron PDG code"}}, + {"lut-mu", VariantType::Int, 0, {"LUT input for the Muon PDG code"}}, {"lut-pi", VariantType::Int, 1, {"LUT input for the Pion PDG code"}}, - {"lut-ka", VariantType::Int, 1, {"LUT input for the Kaon PDG code"}}, - {"lut-pr", VariantType::Int, 1, {"LUT input for the Proton PDG code"}}, + {"lut-ka", VariantType::Int, 0, {"LUT input for the Kaon PDG code"}}, + {"lut-pr", VariantType::Int, 0, {"LUT input for the Proton PDG code"}}, {"lut-tr", VariantType::Int, 0, {"LUT input for the Triton PDG code"}}, {"lut-de", VariantType::Int, 0, {"LUT input for the Deuteron PDG code"}}, {"lut-he", VariantType::Int, 0, {"LUT input for the Helium3 PDG code"}}}; @@ -153,6 +153,7 @@ struct Alice3LutMaker { histos.add("QA/CovMat_sigmaSnp", "sigmaSnp" + commonTitle, kTH3F, {axisPt, axisEta, axissigmaSnp}); histos.add("QA/CovMat_sigmaTgl", "sigmaTgl" + commonTitle, kTH3F, {axisPt, axisEta, axissigmaTgl}); histos.add("QA/CovMat_sigma1Pt", "sigma1Pt" + commonTitle, kTH3F, {axisPt, axisEta, axissigma1Pt}); + histos.add("QA/sigma1Pt", "sigma1Pt" + commonTitle, kTH3F, {axisPt, axisEta, axissigma1Pt}); histos.add("QA/CovMat_rhoZY", "rhoZY" + commonTitle, kTH3F, {axisPt, axisEta, axisrhoZY}); histos.add("QA/CovMat_rhoSnpY", "rhoSnpY" + commonTitle, kTH3F, {axisPt, axisEta, axisrhoSnpY}); histos.add("QA/CovMat_rhoSnpZ", "rhoSnpZ" + commonTitle, kTH3F, {axisPt, axisEta, axisrhoSnpZ}); @@ -262,6 +263,7 @@ struct Alice3LutMaker { histos.fill(HIST("QA/CovMat_sigmaSnp"), mcParticle.pt(), mcParticle.eta(), track.sigmaSnp()); histos.fill(HIST("QA/CovMat_sigmaTgl"), mcParticle.pt(), mcParticle.eta(), track.sigmaTgl()); histos.fill(HIST("QA/CovMat_sigma1Pt"), mcParticle.pt(), mcParticle.eta(), track.sigma1Pt()); + histos.fill(HIST("QA/sigma1Pt"), mcParticle.pt(), mcParticle.eta(), std::abs(track.signed1Pt()) - 1. / mcParticle.pt()); histos.fill(HIST("QA/CovMat_rhoZY"), mcParticle.pt(), mcParticle.eta(), track.rhoZY()); histos.fill(HIST("QA/CovMat_rhoSnpY"), mcParticle.pt(), mcParticle.eta(), track.rhoSnpY()); histos.fill(HIST("QA/CovMat_rhoSnpZ"), mcParticle.pt(), mcParticle.eta(), track.rhoSnpZ()); diff --git a/ALICE3/Tasks/alice3-multicharm.cxx b/ALICE3/Tasks/alice3-multicharm.cxx new file mode 100644 index 00000000000..8797759b57b --- /dev/null +++ b/ALICE3/Tasks/alice3-multicharm.cxx @@ -0,0 +1,577 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "ALICE3/DataModel/A3DecayFinderTables.h" +#include "ALICE3/DataModel/OTFMulticharm.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFStrangeness.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/tracksAlice3.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsVertexing/PVertexer.h" +#include "DetectorsVertexing/PVertexerHelpers.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::ml; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using multiCharmTracksPID = soa::Join; +using multiCharmTracksFull = soa::Join; + +struct alice3multicharm { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::map histPointers; + std::vector savedConfigs; + std::string histPath; + + std::map pdgToBin; + o2::ml::OnnxModel bdtMCharm; + + std::map metadata; + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + + struct : ConfigurableGroup { + std::string prefix = "bdt"; // JSON group name + Configurable ccdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable localPath{"localPath", "MCharm_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable pathCCDB{"btdPathCCDB", "Users/j/jekarlss/MLModels", "Path on CCDB"}; + Configurable timestampCCDB{"timestampCCDB", 1695750420200, "timestamp of the ONNX file for ML model used to query in CCDB. Please use 1695750420200"}; + 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)"}; + Configurable enableML{"enableML", false, "Enables bdt model"}; + } bdt; + + ConfigurableAxis axisEta{"axisEta", {80, -4.0f, +4.0f}, "#eta"}; + 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 axisDCA{"axisDCA", {400, 0, 400}, "DCA (#mum)"}; + ConfigurableAxis axisRadiusLarge{"axisRadiusLarge", {1000, 0, 20}, "Decay radius (cm)"}; + ConfigurableAxis axisRadius{"axisRadius", {10000, 0, 10000}, "Decay radius (#mum)"}; + ConfigurableAxis axisTofTrackDelta{"axisTofTrackDelta", {200, 0, 1000}, "TOF track time"}; + ConfigurableAxis axisNSigma{"axisNSigma", {21, -10, 10}, "nsigma"}; + ConfigurableAxis axisDecayLength{"axisDecayLength", {2000, 0, 2000}, "Decay lenght (#mum)"}; + ConfigurableAxis axisDcaDaughters{"axisDcaDaughters", {200, 0, 100}, "DCA (mum)"}; + ConfigurableAxis axisBDTScore{"axisBDTScore", {100, 0, 1}, "BDT Score"}; + 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"}; + + Configurable xiMinDCAxy{"xiMinDCAxy", -1, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiMinDCAz{"xiMinDCAz", -1, "[0] in |DCAz| > [0]+[1]/pT"}; + Configurable xiMinRadius{"xiMinRadius", -1, "Minimum R2D for Xic decay (cm)"}; + + Configurable picMinDCAxy{"picMinDCAxy", -1, "[0] in |DCAz| > [0]+[1]/pT"}; + Configurable picMinDCAz{"picMinDCAz", -1, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable picMinPt{"picMinPt", -1, "Minimum pT for Xic pions"}; + + Configurable piccMinDCAxy{"piccMinDCAxy", -1, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable piccMinDCAz{"piccMinDCAz", -1, "[0] in |DCAz| > [0]+[1]/pT"}; + Configurable piccMinPt{"piccMinPt", -1, "Minimum pT for Xicc pions"}; + + Configurable xicMaxDauDCA{"xicMaxDauDCA", 1e+4, "DCA between Xic daughters (cm)"}; + Configurable xicMinDCAxy{"xicMinDCAxy", -1, "[0] in |DCAz| > [0]+[1]/pT"}; + Configurable xicMinDCAz{"xicMinDCAz", -1, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiccMaxDCAxy{"xiccMaxDCAxy", 1e+4, "Maximum DCAxy"}; + Configurable xiccMaxDCAz{"xiccMaxDCAz", 1e+4, "Maximum DCAz"}; + Configurable xicMinRadius{"xicMinRadius", -1, "Minimum R2D for Xic decay (cm)"}; + Configurable xicMinDecayDistanceFromPV{"xicMinDecayDistanceFromPV", -1, "Minimum distance for Xic decay from PV (cm)"}; + Configurable xicMinProperLength{"xicMinProperLength", -1, "Minimum proper length for Xic decay (cm)"}; + Configurable xicMaxProperLength{"xicMaxProperLength", 1e+4, "Minimum proper length for Xic decay (cm)"}; + + Configurable xiccMaxDauDCA{"xiccMaxDauDCA", 1e+4, "DCA between Xicc daughters (cm)"}; + Configurable xiccMinRadius{"xiccMinRadius", -1, "Minimum R2D for Xicc decay (cm)"}; + Configurable xiccMinProperLength{"xiccMinProperLength", -1, "Minimum proper length for Xicc decay (cm)"}; + Configurable xiccMaxProperLength{"xiccMaxProperLength", 1e+4, "Minimum proper length for Xicc decay (cm)"}; + Configurable otfConfig{"otfConfig", 0, "OTF configuration flag"}; + Filter configFilter = (aod::otfmulticharm::lutConfigId == otfConfig); + + void init(InitContext&) + { + histos.add("SelectionQA/hDCAXicDaughters", "hDCAXicDaughters; DCA between Xic daughters (#mum)", kTH1D, {axisDcaDaughters}); + histos.add("SelectionQA/hDCAXiccDaughters", "hDCAXiccDaughters; DCA between Xicc daughters (#mum)", kTH1D, {axisDcaDaughters}); + histos.add("SelectionQA/hDCAxyXi", "hDCAxyXi; Xi DCAxy to PV (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hDCAzXi", "hDCAzXi; Xi DCAz to PV (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hDCAxyXic", "hDCAxyXic; Xic DCAxy to PV (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hDCAzXic", "hDCAzXic; Xic DCAz to PV (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hDCAxyXicc", "hDCAxyXicc; Xicc DCAxy to PV (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hDCAzXicc", "hDCAzXicc; Xicc DCAz to PV (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hDecayRadiusXic", "hDecayRadiusXic; Distance (#mum)", kTH1D, {axisRadius}); + histos.add("SelectionQA/hDecayRadiusXicc", "hDecayRadiusXicc; Distance (#mum)", kTH1D, {axisRadius}); + histos.add("SelectionQA/hDecayDistanceFromPVXic", "hDecayDistanceFromPVXic; Distance (#mum)", kTH1D, {axisDecayLength}); + histos.add("SelectionQA/hProperLengthXic", "hProperLengthXic; Distance (#mum)", kTH1D, {axisDecayLength}); + histos.add("SelectionQA/hProperLengthXicc", "hProperLengthXicc; Distance (#mum)", kTH1D, {axisDecayLength}); + histos.add("SelectionQA/hPi1cDCAxy", "hPi1cDCAxy; Pi1c DCAxy (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hPi1cDCAz", "hPi1cDCAz; Pi1c DCAz (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hPi2cDCAxy", "hPi2cDCAxy; Pi2c DCAxy (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hPi2cDCAz", "hPi2cDCAz; Pi2c DCAz (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hPiccDCAxy", "hPiccDCAxy; Picc DCAxy (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hPiccDCAz", "hPiccDCAz; Picc DCAz (#mum)", kTH1D, {axisDCA}); + histos.add("SelectionQA/hPi1cPt", "hPi1cPt; Pi1c pT (Gev/#it(c))", kTH1D, {axisPt}); + histos.add("SelectionQA/hPi2cPt", "hPi2cPt; Pi2c pT (Gev/#it(c))", kTH1D, {axisPt}); + histos.add("SelectionQA/hPiccPt", "hPiccPt; Picc pT (Gev/#it(c))", kTH1D, {axisPt}); + + auto hMCharmBuilding = histos.add("hMCharmBuilding", "hMCharmBuilding", kTH1D, {{22, -0.5, 21.5}}); + hMCharmBuilding->GetXaxis()->SetBinLabel(1, "nTotalCandidates"); + hMCharmBuilding->GetXaxis()->SetBinLabel(2, "xicMaxDauDCA"); + hMCharmBuilding->GetXaxis()->SetBinLabel(3, "xiccMaxDauDCA"); + hMCharmBuilding->GetXaxis()->SetBinLabel(4, "xiMinDCAxy"); + hMCharmBuilding->GetXaxis()->SetBinLabel(5, "xiMinDCAz"); + hMCharmBuilding->GetXaxis()->SetBinLabel(6, "pi1cMinDCAxy"); + hMCharmBuilding->GetXaxis()->SetBinLabel(7, "pi1cMinDCAz"); + hMCharmBuilding->GetXaxis()->SetBinLabel(8, "pi2cMinDCAxy"); + hMCharmBuilding->GetXaxis()->SetBinLabel(9, "pi2cMinDCAz"); + hMCharmBuilding->GetXaxis()->SetBinLabel(10, "piccMinDCAxy"); + hMCharmBuilding->GetXaxis()->SetBinLabel(11, "piccMinDCAz"); + hMCharmBuilding->GetXaxis()->SetBinLabel(12, "xicMinDCAxy"); + hMCharmBuilding->GetXaxis()->SetBinLabel(13, "xicMinDCAz"); + hMCharmBuilding->GetXaxis()->SetBinLabel(14, "xiccMaxDCAxy"); + hMCharmBuilding->GetXaxis()->SetBinLabel(15, "xiccMaxDCAz"); + hMCharmBuilding->GetXaxis()->SetBinLabel(16, "xicMinRadius"); + hMCharmBuilding->GetXaxis()->SetBinLabel(17, "xiccMinRadius"); + hMCharmBuilding->GetXaxis()->SetBinLabel(18, "xicMinProperLength"); + hMCharmBuilding->GetXaxis()->SetBinLabel(19, "xicMaxProperLength"); + hMCharmBuilding->GetXaxis()->SetBinLabel(20, "xiccMinProperLength"); + hMCharmBuilding->GetXaxis()->SetBinLabel(21, "xiccMaxProperLength"); + hMCharmBuilding->GetXaxis()->SetBinLabel(22, "xicMinDecayDistanceFromPV"); + + if (doprocessXiccPID || doprocessXiccExtra) { + auto hPdgCodes = histos.add("PIDQA/hPdgCodes", "hPdgCodes", kTH2D, {{3, 0.5, 3.5}, {7, 0.5, 7.5}}); + hPdgCodes->GetXaxis()->SetBinLabel(1, "pi1c"); + hPdgCodes->GetXaxis()->SetBinLabel(2, "pi2c"); + hPdgCodes->GetXaxis()->SetBinLabel(3, "picc"); + hPdgCodes->GetYaxis()->SetBinLabel(1, "el"); + hPdgCodes->GetYaxis()->SetBinLabel(2, "mu"); + hPdgCodes->GetYaxis()->SetBinLabel(3, "pi"); + hPdgCodes->GetYaxis()->SetBinLabel(4, "ka"); + hPdgCodes->GetYaxis()->SetBinLabel(5, "pr"); + hPdgCodes->GetYaxis()->SetBinLabel(6, "xi"); + hPdgCodes->GetYaxis()->SetBinLabel(7, "other"); + pdgToBin.insert({kElectron, 1}); + pdgToBin.insert({kMuonMinus, 2}); + pdgToBin.insert({kPiPlus, 3}); + pdgToBin.insert({kKPlus, 4}); + pdgToBin.insert({kProton, 5}); + pdgToBin.insert({kXiMinus, 6}); + + histos.add("PIDQA/hInnerTofTimeDeltaPi1c", "hInnerTofTimeDeltaPi1c; Reco - expected pion (ps)", kTH1D, {axisTofTrackDelta}); + histos.add("PIDQA/hInnerTofTimeDeltaPi2c", "hInnerTofTimeDeltaPi2c; Reco - expected pion (ps)", kTH1D, {axisTofTrackDelta}); + histos.add("PIDQA/hInnerTofTimeDeltaPicc", "hInnerTofTimeDeltaPicc; Reco - expected pion (ps)", kTH1D, {axisTofTrackDelta}); + histos.add("PIDQA/hOuterTofTimeDeltaPi1c", "hOuterTofTimeDeltaPi1c; Reco - expected pion (ps)", kTH1D, {axisTofTrackDelta}); + histos.add("PIDQA/hOuterTofTimeDeltaPi2c", "hOuterTofTimeDeltaPi2c; Reco - expected pion (ps)", kTH1D, {axisTofTrackDelta}); + histos.add("PIDQA/hOuterTofTimeDeltaPicc", "hOuterTofTimeDeltaPicc; Reco - expected pion (ps)", kTH1D, {axisTofTrackDelta}); + + histos.add("PIDQA/hInnerTofNSigmaPi1c", "hInnerTofNSigmaPi1c; TOF NSigma pion", kTH2D, {axisPt, axisNSigma}); + histos.add("PIDQA/hOuterTofNSigmaPi1c", "hOuterTofNSigmaPi1c; TOF NSigma pion", kTH2D, {axisPt, axisNSigma}); + histos.add("PIDQA/hInnerTofNSigmaPi2c", "hInnerTofNSigmaPi2c; TOF NSigma pion", kTH2D, {axisPt, axisNSigma}); + histos.add("PIDQA/hOuterTofNSigmaPi2c", "hOuterTofNSigmaPi2c; TOF NSigma pion", kTH2D, {axisPt, axisNSigma}); + histos.add("PIDQA/hInnerTofNSigmaPicc", "hInnerTofNSigmaPicc; TOF NSigma pion", kTH2D, {axisPt, axisNSigma}); + histos.add("PIDQA/hOuterTofNSigmaPicc", "hOuterTofNSigmaPicc; TOF NSigma pion", kTH2D, {axisPt, axisNSigma}); + + histos.add("PIDQA/hRichNSigmaPi1c", "hRichNSigmaPi1c; RICH NSigma pion", kTH2D, {axisPt, axisNSigma}); + histos.add("PIDQA/hRichNSigmaPi2c", "hRichNSigmaPi2c; RICH NSigma pion", kTH2D, {axisPt, axisNSigma}); + histos.add("PIDQA/hRichNSigmaPicc", "hRichNSigmaPicc; RICH NSigma pion", kTH2D, {axisPt, axisNSigma}); + } + + if (doprocessXiccExtra) { + histos.add("XiccProngs/h3dPos", "h3dPos; Xicc pT (GeV/#it(c)); Pos pT (GeV/#it(c)); Pos #eta", kTH3D, {axisPt, axisPt, axisEta}); + histos.add("XiccProngs/h3dNeg", "h3dNeg; Xicc pT (GeV/#it(c)); Neg pT (GeV/#it(c)); Neg #eta", kTH3D, {axisPt, axisPt, axisEta}); + histos.add("XiccProngs/h3dBach", "h3dBach; Xicc pT (GeV/#it(c)); Bach pT (GeV/#it(c)); Bach #eta", kTH3D, {axisPt, axisPt, axisEta}); + histos.add("XiccProngs/h3dPi1c", "h3dPi1c; Xicc pT (GeV/#it(c)); Pi1c pT (GeV/#it(c)); Pi1c #eta", kTH3D, {axisPt, axisPt, axisEta}); + histos.add("XiccProngs/h3dPi2c", "h3dPi2c; Xicc pT (GeV/#it(c)); Pi2c pT (GeV/#it(c)); Pi2c #eta", kTH3D, {axisPt, axisPt, axisEta}); + histos.add("XiccProngs/h3dPicc", "h3dPicc; Xicc pT (GeV/#it(c)); Picc pT (GeV/#it(c)); Picc #eta", kTH3D, {axisPt, axisPt, axisEta}); + } + + histos.add("hXiccMass", "hXiccMass", kTH1D, {axisXiccMass}); + histos.add("hXicMass", "hXicMass", kTH1D, {axisXicMass}); + histos.add("hXiccPt", "hXiccPt", kTH1D, {axisPt}); + histos.add("hXicPt", "hXicPt", kTH1D, {axisPt}); + histos.add("h3dXicc", "h3dXicc; Xicc pT (GeV/#it(c)); Xicc #eta; Xicc mass (GeV/#it(c)^{2})", kTH3D, {axisPt, axisEta, axisXiccMass}); + histos.add("hConfigId", "hConfigId", kTH1D, {{11, -0.5, 10.5}}); + + if (bdt.enableML) { + ccdb->setURL(bdt.ccdbUrl.value); + if (bdt.loadModelsFromCCDB) { + ccdbApi.init(bdt.ccdbUrl); + LOG(info) << "Fetching model for timestamp: " << bdt.timestampCCDB.value; + bool retrieveSuccessMCharm = ccdbApi.retrieveBlob(bdt.pathCCDB.value, ".", metadata, bdt.timestampCCDB.value, false, bdt.localPath.value); + + if (retrieveSuccessMCharm) { + bdtMCharm.initModel(bdt.localPath.value, bdt.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the MCharm model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } else { + bdtMCharm.initModel(bdt.localPath.value, bdt.enableOptimizations.value); + } + + histos.add("hBDTScore", "hBDTScore", kTH1D, {axisBDTScore}); + histos.add("hBDTScoreVsXiccMass", "hBDTScoreVsXiccMass", kTH2D, {axisXiccMass, axisBDTScore}); + histos.add("hBDTScoreVsXiccPt", "hBDTScoreVsXiccPt", kTH2D, {axisPt, axisBDTScore}); + histos.add("h3dBDTScore", "h3dBDTScore", kTH3D, {axisPt, axisXiccMass, axisBDTScore}); + histos.add("hDCAXicDaughters", "hDCAXicDaughters", kTH2D, {{axisBDTScore, axisDcaDaughters}}); + histos.add("hDCAXiccDaughters", "hDCAXiccDaughters", kTH2D, {{axisBDTScore, axisDcaDaughters}}); + histos.add("hDCAxyXi", "hDCAxyXi", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hDCAzXi", "hDCAzXi", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hDCAxyXic", "hDCAxyXic", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hDCAzXic", "hDCAzXic", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hDCAxyXicc", "hDCAxyXicc", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hDCAzXicc", "hDCAzXicc", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hDecayRadiusXic", "hDecayRadiusXic", kTH2D, {{axisBDTScore, axisRadius}}); + histos.add("hDecayRadiusXicc", "hDecayRadiusXicc", kTH2D, {{axisBDTScore, axisRadius}}); + histos.add("hDecayDistanceFromPVXic", "hDecayDistanceFromPVXic", kTH2D, {{axisBDTScore, axisDecayLength}}); + histos.add("hProperLengthXic", "hProperLengthXic", kTH2D, {{axisBDTScore, axisDecayLength}}); + histos.add("hProperLengthXicc", "hProperLengthXicc", kTH2D, {{axisBDTScore, axisDecayLength}}); + histos.add("hPi1cDCAxy", "hPi1cDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hPi1cDCAz", "hPi1cDCAz", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hPi2cDCAxy", "hPi2cDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hPi2cDCAz", "hPi2cDCAz", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hPiccDCAxy", "hPiccDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hPiccDCAz", "hPiccDCAz", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("hPi1cPt", "hPi1cPt", kTH2D, {{axisBDTScore, axisPt}}); + histos.add("hPi2cPt", "hPi2cPt", kTH2D, {{axisBDTScore, axisPt}}); + histos.add("hPiccPt", "hPiccPt", kTH2D, {{axisBDTScore, axisPt}}); + histos.add("hXiccMass", "hXiccMass", kTH2D, {{axisBDTScore, axisXiccMass}}); + histos.add("hXicMass", "hXicMass", kTH2D, {{axisBDTScore, axisXicMass}}); + histos.add("hXiccPt", "hXiccPt", kTH2D, {{axisBDTScore, axisPt}}); + histos.add("hXicPt", "hXicPt", kTH2D, {{axisBDTScore, axisPt}}); + } + } + + int getBin(const std::map& pdgToBin, int pdg) + { + auto it = pdgToBin.find(pdg); + return (it != pdgToBin.end()) ? it->second : 7; + } + + template + void genericProcessXicc(TMCharmCands const& xiccCands) + { + for (const auto& xiccCand : xiccCands) { + int icfg = xiccCand.lutConfigId(); + histos.fill(HIST("hConfigId"), icfg); + if (bdt.enableML) { + std::vector inputFeatures{ + xiccCand.xicDauDCA(), + xiccCand.xiccDauDCA(), + xiccCand.xiDCAxy(), + xiccCand.xicDCAxy(), + xiccCand.xiccDCAxy(), + xiccCand.xiDCAz(), + xiccCand.xicDCAz(), + xiccCand.xiccDCAz(), + xiccCand.pi1cDCAxy(), + xiccCand.pi2cDCAxy(), + xiccCand.piccDCAxy(), + xiccCand.pi1cDCAz(), + xiccCand.pi2cDCAz(), + xiccCand.piccDCAz(), + xiccCand.xicDecayRadius2D(), + xiccCand.xiccDecayRadius2D(), + xiccCand.xicProperLength(), + xiccCand.xicDistanceFromPV(), + xiccCand.xiccProperLength()}; + + float* probabilityMCharm = bdtMCharm.evalModel(inputFeatures); + float bdtScore = probabilityMCharm[1]; + + histos.fill(HIST("hBDTScore"), bdtScore); + histos.fill(HIST("hBDTScoreVsXiccMass"), xiccCand.xiccMass(), bdtScore); + histos.fill(HIST("hBDTScoreVsXiccPt"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("h3dBDTScore"), xiccCand.xiccPt(), xiccCand.xiccMass(), bdtScore); + histos.fill(HIST("hDCAXicDaughters"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDCAXiccDaughters"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDCAxyXi"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDCAzXi"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDCAxyXic"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDCAzXic"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDCAxyXicc"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDCAzXicc"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDecayRadiusXic"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDecayRadiusXicc"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hDecayDistanceFromPVXic"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hProperLengthXic"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hProperLengthXicc"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPi1cDCAxy"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPi1cDCAz"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPi2cDCAxy"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPi2cDCAz"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPiccDCAxy"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPiccDCAz"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPi1cPt"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPi2cPt"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hPiccPt"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hXiccMass"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hXicMass"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hXicPt"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("hXiccPt"), xiccCand.xiccPt(), bdtScore); + histos.fill(HIST("h3dXicc"), xiccCand.xiccPt(), bdtScore); + } + + histos.fill(HIST("hMCharmBuilding"), 0); + if (xiccCand.xicDauDCA() > xicMaxDauDCA) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 1); + } + + if (xiccCand.xiccDauDCA() > xiccMaxDauDCA) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 2); + } + + if (std::fabs(xiccCand.xiDCAxy()) < xiMinDCAxy) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 3); + } + + if (std::fabs(xiccCand.xiDCAz()) < xiMinDCAz) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 4); + } + + if (std::fabs(xiccCand.pi1cDCAxy()) < picMinDCAxy) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 5); + } + + if (std::fabs(xiccCand.pi1cDCAz()) < picMinDCAz) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 6); + } + + if (std::fabs(xiccCand.pi2cDCAxy()) < picMinDCAxy) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 7); + } + + if (std::fabs(xiccCand.pi2cDCAz()) < picMinDCAz) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 8); + } + + if (std::fabs(xiccCand.piccDCAxy()) < piccMinDCAxy) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 9); + } + + if (std::fabs(xiccCand.piccDCAz()) < piccMinDCAz) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 10); + } + + if (std::fabs(xiccCand.xicDCAxy()) < xicMinDCAxy) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 11); + } + + if (std::fabs(xiccCand.xicDCAz()) < xicMinDCAz) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 12); + } + + if (std::fabs(xiccCand.xiccDCAxy()) > xiccMaxDCAxy) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 13); + } + + if (std::fabs(xiccCand.xiccDCAz()) > xiccMaxDCAz) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 14); + } + + if (xiccCand.xicDecayRadius2D() < xicMinRadius) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 15); + } + + if (xiccCand.xiccDecayRadius2D() < xiccMinRadius) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 16); + } + + if (xiccCand.xicProperLength() < xicMinProperLength) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 17); + } + + if (xiccCand.xicProperLength() > xicMaxProperLength) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 18); + } + + if (xiccCand.xiccProperLength() < xiccMinProperLength) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 19); + } + + if (xiccCand.xiccProperLength() > xiccMaxProperLength) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 20); + } + + if (xiccCand.xicDistanceFromPV() < xicMinDecayDistanceFromPV) { + continue; + } else { + histos.fill(HIST("hMCharmBuilding"), 21); + } + + histos.fill(HIST("SelectionQA/hDCAXicDaughters"), xiccCand.xicDauDCA() * 1e+4); + histos.fill(HIST("SelectionQA/hDCAXiccDaughters"), xiccCand.xiccDauDCA() * 1e+4); + histos.fill(HIST("SelectionQA/hDCAxyXi"), std::fabs(xiccCand.xiDCAxy() * 1e+4)); + histos.fill(HIST("SelectionQA/hDCAzXi"), std::fabs(xiccCand.xiDCAz() * 1e+4)); + histos.fill(HIST("SelectionQA/hDCAxyXic"), std::fabs(xiccCand.xicDCAxy() * 1e+4)); + histos.fill(HIST("SelectionQA/hDCAzXic"), std::fabs(xiccCand.xicDCAz() * 1e+4)); + histos.fill(HIST("SelectionQA/hDCAxyXicc"), std::fabs(xiccCand.xiccDCAxy() * 1e+4)); + histos.fill(HIST("SelectionQA/hDCAzXicc"), std::fabs(xiccCand.xiccDCAz() * 1e+4)); + histos.fill(HIST("SelectionQA/hDecayRadiusXic"), xiccCand.xicDecayRadius2D() * 1e+4); + histos.fill(HIST("SelectionQA/hDecayRadiusXicc"), xiccCand.xiccDecayRadius2D() * 1e+4); + histos.fill(HIST("SelectionQA/hDecayDistanceFromPVXic"), xiccCand.xicDistanceFromPV() * 1e+4); + histos.fill(HIST("SelectionQA/hProperLengthXic"), xiccCand.xicProperLength() * 1e+4); + histos.fill(HIST("SelectionQA/hProperLengthXicc"), xiccCand.xiccProperLength() * 1e+4); + histos.fill(HIST("SelectionQA/hPi1cDCAxy"), xiccCand.pi1cDCAxy() * 1e+4); + histos.fill(HIST("SelectionQA/hPi1cDCAz"), xiccCand.pi1cDCAz() * 1e+4); + histos.fill(HIST("SelectionQA/hPi2cDCAxy"), xiccCand.pi2cDCAxy() * 1e+4); + histos.fill(HIST("SelectionQA/hPi2cDCAz"), xiccCand.pi2cDCAz() * 1e+4); + histos.fill(HIST("SelectionQA/hPiccDCAxy"), xiccCand.piccDCAxy() * 1e+4); + histos.fill(HIST("SelectionQA/hPiccDCAz"), xiccCand.piccDCAz() * 1e+4); + histos.fill(HIST("SelectionQA/hPi1cPt"), xiccCand.pi1cPt()); + histos.fill(HIST("SelectionQA/hPi2cPt"), xiccCand.pi2cPt()); + histos.fill(HIST("SelectionQA/hPiccPt"), xiccCand.piccPt()); + + if constexpr (requires { xiccCand.pi1cTofDeltaInner(); }) { // if pid table + histos.fill(HIST("PIDQA/hInnerTofTimeDeltaPi1c"), xiccCand.pi1cTofDeltaInner()); + histos.fill(HIST("PIDQA/hInnerTofTimeDeltaPi2c"), xiccCand.pi2cTofDeltaInner()); + histos.fill(HIST("PIDQA/hInnerTofTimeDeltaPicc"), xiccCand.piccTofDeltaInner()); + histos.fill(HIST("PIDQA/hOuterTofTimeDeltaPi1c"), xiccCand.pi1cTofDeltaOuter()); + histos.fill(HIST("PIDQA/hOuterTofTimeDeltaPi2c"), xiccCand.pi2cTofDeltaOuter()); + histos.fill(HIST("PIDQA/hOuterTofTimeDeltaPicc"), xiccCand.piccTofDeltaOuter()); + histos.fill(HIST("PIDQA/hInnerTofNSigmaPi1c"), xiccCand.pi1cPt(), xiccCand.pi1cTofNSigmaInner()); + histos.fill(HIST("PIDQA/hOuterTofNSigmaPi1c"), xiccCand.pi1cPt(), xiccCand.pi1cTofNSigmaOuter()); + histos.fill(HIST("PIDQA/hInnerTofNSigmaPi2c"), xiccCand.pi2cPt(), xiccCand.pi2cTofNSigmaInner()); + histos.fill(HIST("PIDQA/hOuterTofNSigmaPi2c"), xiccCand.pi2cPt(), xiccCand.pi2cTofNSigmaOuter()); + histos.fill(HIST("PIDQA/hInnerTofNSigmaPicc"), xiccCand.piccPt(), xiccCand.piccTofNSigmaInner()); + histos.fill(HIST("PIDQA/hOuterTofNSigmaPicc"), xiccCand.piccPt(), xiccCand.piccTofNSigmaOuter()); + if (xiccCand.pi1cHasRichSignal()) { + histos.fill(HIST("PIDQA/hRichNSigmaPi1c"), xiccCand.pi1cPt(), xiccCand.pi1cRichNSigma()); + } + if (xiccCand.pi2cHasRichSignal()) { + histos.fill(HIST("PIDQA/hRichNSigmaPi2c"), xiccCand.pi2cPt(), xiccCand.pi2cRichNSigma()); + } + if (xiccCand.piccHasRichSignal()) { + histos.fill(HIST("PIDQA/hRichNSigmaPicc"), xiccCand.piccPt(), xiccCand.piccRichNSigma()); + } + + histos.fill(HIST("PIDQA/hPdgCodes"), 1, getBin(pdgToBin, std::abs(xiccCand.pi1cPdgCode()))); + histos.fill(HIST("PIDQA/hPdgCodes"), 2, getBin(pdgToBin, std::abs(xiccCand.pi2cPdgCode()))); + histos.fill(HIST("PIDQA/hPdgCodes"), 3, getBin(pdgToBin, std::abs(xiccCand.piccPdgCode()))); + } + + if constexpr (requires { xiccCand.negPt(); }) { // if extra table + histos.fill(HIST("XiccProngs/h3dNeg"), xiccCand.xiccPt(), xiccCand.negPt(), xiccCand.negEta()); + histos.fill(HIST("XiccProngs/h3dPos"), xiccCand.xiccPt(), xiccCand.posPt(), xiccCand.posEta()); + histos.fill(HIST("XiccProngs/h3dBach"), xiccCand.xiccPt(), xiccCand.bachPt(), xiccCand.bachEta()); + histos.fill(HIST("XiccProngs/h3dPi1c"), xiccCand.xiccPt(), xiccCand.pi1cPt(), xiccCand.pi1cEta()); + histos.fill(HIST("XiccProngs/h3dPi2c"), xiccCand.xiccPt(), xiccCand.pi2cPt(), xiccCand.pi2cEta()); + histos.fill(HIST("XiccProngs/h3dPicc"), xiccCand.xiccPt(), xiccCand.piccPt(), xiccCand.piccEta()); + } + + histos.fill(HIST("hXiccMass"), xiccCand.xiccMass()); + histos.fill(HIST("hXicMass"), xiccCand.xicMass()); + histos.fill(HIST("hXiccPt"), xiccCand.xiccPt()); + histos.fill(HIST("hXicPt"), xiccCand.xicPt()); + histos.fill(HIST("h3dXicc"), xiccCand.xiccPt(), xiccCand.xiccEta(), xiccCand.xiccMass()); + } + } + + void processXicc(soa::Filtered const& multiCharmTracks) + { + genericProcessXicc(multiCharmTracks); + } + + void processXiccPID(soa::Filtered const& multiCharmTracks) + { + genericProcessXicc(multiCharmTracks); + } + + void processXiccExtra(soa::Filtered const& multiCharmTracks) + { + genericProcessXicc(multiCharmTracks); + } + + PROCESS_SWITCH(alice3multicharm, processXicc, "find Xicc baryons", true); + PROCESS_SWITCH(alice3multicharm, processXiccPID, "find Xicc baryons with more QA from PID information", false); + PROCESS_SWITCH(alice3multicharm, processXiccExtra, "find Xicc baryons with all QA", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/Tasks/alice3-strangeness.cxx b/ALICE3/Tasks/alice3-strangeness.cxx new file mode 100644 index 00000000000..c29e764e9c0 --- /dev/null +++ b/ALICE3/Tasks/alice3-strangeness.cxx @@ -0,0 +1,118 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file alice3-strangeness.cxx +/// +/// \brief This task produces invariant mass distributions for strange hadrons +/// +/// \author Lucia Anna Tarasovičová, Pavol Jozef Šafárik University (SK) +/// \since November 20, 2025 +/// + +#include "ALICE3/DataModel/OTFStrangeness.h" +#include "ALICE3/DataModel/tracksAlice3.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; + +using alice3tracks = soa::Join; + +struct alice3strangeness { + 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 axisK0Mass{"axisK0Mass", {200, 0.4f, 0.6f}, ""}; + ConfigurableAxis axisVertexZ{"axisVertexZ", {40, -20, 20}, "vertex Z (cm)"}; + + void init(InitContext&) + { + histos.add("K0/hMassAllCandidates", "", kTH2D, {axisK0Mass, axisPt}); + histos.add("K0/hMassSelected", "", kTH2D, {axisK0Mass, axisPt}); + histos.add("K0/hSelections", "", kTH1D, {{10, 0, 10}}); + histos.add("K0/hDCANegDaughter", "", kTH1D, {{200, -5, 5}}); + histos.add("K0/hDCAPosDaughter", "", kTH1D, {{200, -5, 5}}); + histos.add("hPVz", "hPVz", kTH1F, {axisVertexZ}); + } + long int nEvents = 0; + void process(aod::Collisions const& collisions, aod::McCollisions const& mcCollisions, aod::UpgradeV0s const& v0Recos, alice3tracks const&) + { + LOG(info) << "Event processed " << nEvents++ << " :" << collisions.size() << " " << mcCollisions.size(); + for (const auto& collision : collisions) { + float collisionZ = collision.posZ(); + // std::cout << "______ process V0_______" << collision.size() << std::endl; + histos.fill(HIST("hPVz"), collisionZ); + for (const auto& v0Cand : v0Recos) { + + auto negV0Daughter = v0Cand.negTrack_as(); // de-reference neg track + auto posV0Daughter = v0Cand.posTrack_as(); // de-reference pos track + + bool isK0 = v0Cand.mK0() > 0; + if (isK0) { + histos.fill(HIST("K0/hMassAllCandidates"), v0Cand.mK0(), v0Cand.pt()); + histos.fill(HIST("K0/hSelections"), 0); // all candidates + histos.fill(HIST("K0/hDCANegDaughter"), negV0Daughter.dcaXY()); + histos.fill(HIST("K0/hDCAPosDaughter"), posV0Daughter.dcaXY()); + if (std::abs(negV0Daughter.dcaXY()) < 0.05) + continue; + histos.fill(HIST("K0/hSelections"), 1); // dcaXY cut + if (std::abs(posV0Daughter.dcaXY()) < 0.05) + continue; + histos.fill(HIST("K0/hSelections"), 2); // dcaXY cut + if (v0Cand.dcaV0Daughters() > 1.0) + continue; + histos.fill(HIST("K0/hSelections"), 3); // dca between daughters + if (v0Cand.v0Radius() < 0.5) + continue; + histos.fill(HIST("K0/hSelections"), 4); // radius cut + if (std::abs(negV0Daughter.eta()) > 0.8 || std::abs(posV0Daughter.eta()) > 0.8) + continue; + histos.fill(HIST("K0/hSelections"), 5); // eta cut + histos.fill(HIST("K0/hMassSelected"), v0Cand.mK0(), v0Cand.pt()); + } + } + } + } + PROCESS_SWITCH(alice3strangeness, process, "", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/Tasks/alice3-taskcorrelationDDbar.cxx b/ALICE3/Tasks/alice3-taskcorrelationDDbar.cxx new file mode 100644 index 00000000000..b6c8058f747 --- /dev/null +++ b/ALICE3/Tasks/alice3-taskcorrelationDDbar.cxx @@ -0,0 +1,434 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file taskCorrelationDDbar.cxx +/// \brief D0-D0bar correlation analysis task - data-like and MC-reco analysis performance on ALICE 3 detector. +/// +/// \author Fabio Colamaria , INFN Bari + +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.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 +{ +using DDbarPairFull = 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 phiDbar) +{ + return RecoDecay::constrainAngle(phiDbar - 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 stringPtDbar = "#it{p}_{T}^{Dbar} (GeV/#it{c});"; +const TString stringDeltaPt = "#it{p}_{T}^{Dbar}-#it{p}_{T}^{D} (GeV/#it{c});"; +const TString stringDeltaPtMaxMin = "#it{p}_{T}^{max}-#it{p}_{T}^{min} (GeV/#it{c});"; +const TString stringDeltaEta = "#it{#eta}^{Dbar}-#it{#eta}^{D};"; +const TString stringDeltaPhi = "#it{#varphi}^{Dbar}-#it{#varphi}^{D} (rad);"; +const TString stringDDbar = "D,Dbar candidates "; +const TString stringSignal = "signal region;"; +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 +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}; +const double signalRegionInnerDefault[npTBinsCorrelations] = {1.810, 1.810, 1.810, 1.810, 1.810, 1.810, 1.810, 1.810}; +const double signalRegionOuterDefault[npTBinsCorrelations] = {1.922, 1.922, 1.922, 1.922, 1.922, 1.922, 1.922, 1.922}; +const double sidebandLeftInnerDefault[npTBinsCorrelations] = {1.642, 1.642, 1.642, 1.642, 1.642, 1.642, 1.642, 1.642}; +const double sidebandLeftOuterDefault[npTBinsCorrelations] = {1.754, 1.754, 1.754, 1.754, 1.754, 1.754, 1.754, 1.754}; +const double sidebandRightInnerDefault[npTBinsCorrelations] = {1.978, 1.978, 1.978, 1.978, 1.978, 1.978, 1.978, 1.978}; +const double sidebandRightOuterDefault[npTBinsCorrelations] = {2.090, 2.090, 2.090, 2.090, 2.090, 2.090, 2.090, 2.090}; +auto signalRegionInner_v = std::vector{signalRegionInnerDefault, signalRegionInnerDefault + npTBinsCorrelations}; +auto signalRegionOuter_v = std::vector{signalRegionOuterDefault, signalRegionOuterDefault + npTBinsCorrelations}; +auto sidebandLeftInner_v = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + npTBinsCorrelations}; +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 double efficiencyDmesonDefault[npTBinsEfficiency] = {}; +auto efficiencyDmeson_v = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsEfficiency}; + +struct alice3taskcorrelationddbar { + Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying efficiency weights"}; + // 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> binsPtCorrelations{"binsPtCorrelations", std::vector{pTBinsCorrelations_v}, "pT bin limits for correlation plots"}; + // pT bins for effiencies: same as above + Configurable> binsPtEfficiency{"binsPtEfficiency", 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) + 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"}; + Configurable> sidebandLeftInner{"sidebandLeftInner", std::vector{sidebandLeftInner_v}, "Inner values of left sideband vs pT"}; + 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_v}, "Efficiency values for D meson specie under study"}; + + HistogramRegistry registry{ + "registry", + // NOTE: use hMassD0 (from correlator task) for normalisation, and hMass2DCorrelationPairs for 2D-sideband-subtraction purposes + {{"hMass2DCorrelationPairs", stringDDbar + "2D;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hDeltaEtaPtIntSignalRegion", stringDDbar + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, + {"hDeltaPhiPtIntSignalRegion", stringDDbar + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, + {"hCorrel2DPtIntSignalRegion", stringDDbar + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, + {"hCorrel2DVsPtSignalRegion", stringDDbar + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hDeltaPtDDbarSignalRegion", stringDDbar + stringSignal + stringDeltaPt + "entries", {HistType::kTH1F, {{144, -36., 36.}}}}, + {"hDeltaPtMaxMinSignalRegion", stringDDbar + stringSignal + stringDeltaPtMaxMin + "entries", {HistType::kTH1F, {{72, 0., 36.}}}}, + {"hDeltaEtaPtIntSidebands", stringDDbar + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, + {"hDeltaPhiPtIntSidebands", stringDDbar + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, + {"hCorrel2DPtIntSidebands", stringDDbar + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, + {"hCorrel2DVsPtSidebands", stringDDbar + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hDeltaPtDDbarSidebands", stringDDbar + stringSideband + stringDeltaPt + "entries", {HistType::kTH1F, {{144, -36., 36.}}}}, + {"hDeltaPtMaxMinSidebands", stringDDbar + stringSideband + stringDeltaPtMaxMin + "entries", {HistType::kTH1F, {{72, 0., 36.}}}}, + {"hMass2DCorrelationPairsMCRecBkgBkg", stringDDbar + "2D BkgBkg - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hMass2DCorrelationPairsMCRecBkgRef", stringDDbar + "2D BkgRef - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hMass2DCorrelationPairsMCRecBkgSig", stringDDbar + "2D BkgSig - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hMass2DCorrelationPairsMCRecRefBkg", stringDDbar + "2D RefBkg - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hMass2DCorrelationPairsMCRecRefRef", stringDDbar + "2D RefRef - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hMass2DCorrelationPairsMCRecRefSig", stringDDbar + "2D RefSig - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hMass2DCorrelationPairsMCRecSigBkg", stringDDbar + "2D SigBkg - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hMass2DCorrelationPairsMCRecSigRef", stringDDbar + "2D SigRef - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hMass2DCorrelationPairsMCRecSigSig", stringDDbar + "2D SigSig - MC reco;inv. mass D (GeV/#it{c}^{2});inv. mass Dbar (GeV/#it{c}^{2});" + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{200, 1.6, 2.1}, {200, 1.6, 2.1}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hDeltaEtaPtIntSignalRegionMCRec", stringMCReco + stringSignal + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, + {"hDeltaPhiPtIntSignalRegionMCRec", stringMCReco + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, + {"hCorrel2DPtIntSignalRegionMCRec", stringMCReco + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, + {"hDeltaPtDDbarSignalRegionMCRec", stringMCReco + stringSignal + stringDeltaPt + "entries", {HistType::kTH1F, {{144, -36., 36.}}}}, + {"hDeltaPtMaxMinSignalRegionMCRec", stringMCReco + stringSignal + stringDeltaPtMaxMin + "entries", {HistType::kTH1F, {{72, 0., 36.}}}}, + {"hCorrel2DVsPtSignalRegionMCRecBkgBkg", stringMCReco + "BkgBkg" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSignalRegionMCRecBkgRef", stringMCReco + "BkgRef" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSignalRegionMCRecBkgSig", stringMCReco + "BkgSig" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSignalRegionMCRecRefBkg", stringMCReco + "RefBkg" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSignalRegionMCRecRefRef", stringMCReco + "RefRef" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSignalRegionMCRecRefSig", stringMCReco + "RefSig" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSignalRegionMCRecSigBkg", stringMCReco + "SigBkg" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSignalRegionMCRecSigRef", stringMCReco + "SigRef" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSignalRegionMCRecSigSig", stringMCReco + "SigSig" + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hDeltaEtaPtIntSidebandsMCRec", stringMCReco + stringSideband + stringDeltaEta + "entries", {HistType::kTH1F, {{200, -10., 10.}}}}, + {"hDeltaPhiPtIntSidebandsMCRec", stringMCReco + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}}}}, + {"hCorrel2DPtIntSidebandsMCRec", stringMCReco + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {200, -10., 10.}}}}, + {"hDeltaPtDDbarSidebandsMCRec", stringMCReco + stringSideband + stringDeltaPt + "entries", {HistType::kTH1F, {{144, -36., 36.}}}}, + {"hDeltaPtMaxMinSidebandsMCRec", stringMCReco + stringSideband + stringDeltaPtMaxMin + "entries", {HistType::kTH1F, {{72, 0., 36.}}}}, + {"hCorrel2DVsPtSidebandsMCRecBkgBkg", stringMCReco + "BkgBkg" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSidebandsMCRecBkgRef", stringMCReco + "BkgRef" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSidebandsMCRecBkgSig", stringMCReco + "BkgSig" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSidebandsMCRecRefBkg", stringMCReco + "RefBkg" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSidebandsMCRecRefRef", stringMCReco + "RefRef" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSidebandsMCRecRefSig", stringMCReco + "RefSig" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSidebandsMCRecSigBkg", stringMCReco + "SigBkg" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSidebandsMCRecSigRef", stringMCReco + "SigRef" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}, // note: axes 3 and 4 (the pT) are updated in the init() + {"hCorrel2DVsPtSidebandsMCRecSigSig", stringMCReco + "SigSig" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtDbar + "entries", {HistType::kTHnSparseD, {{64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, {120, -6., 6.}, {10, 0., 10.}, {10, 0., 10.}}}}}}; // note: axes 3 and 4 (the pT) are updated in the init() + + void init(InitContext&) + { + // redefinition of pT axes for THnSparse holding correlation entries + int nBinspTaxis = binsPtCorrelations->size() - 1; + const double* valuespTaxis = binsPtCorrelations->data(); + + for (int i = 2; i <= 3; i++) { + registry.get(HIST("hMass2DCorrelationPairs"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegion"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebands"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairs"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebands"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecBkgBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecBkgRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecBkgSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecRefBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecRefRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecRefSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecSigBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecSigRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecSigSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecBkgBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecBkgRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecBkgSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecRefBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecRefRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecRefSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecSigBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecSigRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecSigSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecBkgBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecBkgRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecBkgSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecRefBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecRefRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecRefSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecSigBkg"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecSigRef"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecSigSig"))->GetAxis(i)->Set(nBinspTaxis, valuespTaxis); + registry.get(HIST("hMass2DCorrelationPairsMCRecBkgBkg"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecBkgRef"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecBkgSig"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecRefBkg"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecRefRef"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecRefSig"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecSigBkg"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecSigRef"))->Sumw2(); + registry.get(HIST("hMass2DCorrelationPairsMCRecSigSig"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecBkgBkg"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecBkgRef"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecBkgSig"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecRefBkg"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecRefRef"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecRefSig"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecSigBkg"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecSigRef"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionMCRecSigSig"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecBkgBkg"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecBkgRef"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecBkgSig"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecRefBkg"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecRefRef"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecRefSig"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecSigBkg"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecSigRef"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandsMCRecSigSig"))->Sumw2(); + } + } + + /// D-Dbar 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::DDbarPairFull 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 ptDbar = pairEntry.ptDbar(); + double massD = pairEntry.mD(); + double massDbar = pairEntry.mDbar(); + + int pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); + int pTBinDbar = o2::analysis::findBin(binsPtCorrelations, ptDbar); + + double efficiencyWeight = 1.; + if (applyEfficiency) { + efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiency, ptD)) * efficiencyD->at(o2::analysis::findBin(binsPtEfficiency, ptDbar))); + } + + // 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 + continue; + } + + // 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 + registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + registry.fill(HIST("hCorrel2DPtIntSignalRegion"), deltaPhi, deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSignalRegion"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hDeltaPtDDbarSignalRegion"), ptDbar - ptD, efficiencyWeight); + registry.fill(HIST("hDeltaPtMaxMinSignalRegion"), std::abs(ptDbar - ptD), efficiencyWeight); + } + + if ((massD > sidebandLeftInner->at(pTBinD) && massD < sidebandLeftOuter->at(pTBinD) && massDbar > sidebandLeftInner->at(pTBinDbar) && massDbar < sidebandRightOuter->at(pTBinDbar)) || + (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 + registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebands"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hDeltaPtDDbarSidebands"), ptDbar - ptD, efficiencyWeight); + registry.fill(HIST("hDeltaPtMaxMinSidebands"), std::abs(ptDbar - ptD), efficiencyWeight); + } + } // end loop + } + + PROCESS_SWITCH(alice3taskcorrelationddbar, processData, "Process data", true); + + /// D-Dbar correlation pair filling task, from pair tables - for MC reco-level analysis (candidates matched to true signal only, but also bkg sources are studied) + /// Works on both USL and LS analyses pair tables + void processMcRec(aod::DDbarPairFull 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 ptDbar = pairEntry.ptDbar(); + double massD = pairEntry.mD(); + double massDbar = pairEntry.mDbar(); + + int pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); + int pTBinDbar = o2::analysis::findBin(binsPtCorrelations, ptDbar); + + double efficiencyWeight = 1.; + if (applyEfficiency) { + efficiencyWeight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiency, ptD)) * efficiencyD->at(o2::analysis::findBin(binsPtEfficiency, ptDbar))); + } + + // fill 2D invariant mass plots + switch (pairEntry.signalStatus()) { + case 0: // D Bkg, Dbar Bkg + registry.fill(HIST("hMass2DCorrelationPairsMCRecBkgBkg"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + case 1: // D Bkg, Dbar Ref + registry.fill(HIST("hMass2DCorrelationPairsMCRecBkgRef"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + case 2: // D Bkg, Dbar Sig + registry.fill(HIST("hMass2DCorrelationPairsMCRecBkgSig"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + case 3: // D Ref, Dbar Bkg + registry.fill(HIST("hMass2DCorrelationPairsMCRecRefBkg"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + case 4: // D Ref, Dbar Ref + registry.fill(HIST("hMass2DCorrelationPairsMCRecRefRef"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + case 5: // D Ref, Dbar Sig + registry.fill(HIST("hMass2DCorrelationPairsMCRecRefSig"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + case 6: // D Sig, Dbar Bkg + registry.fill(HIST("hMass2DCorrelationPairsMCRecSigBkg"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + case 7: // D Sig, Dbar Ref + registry.fill(HIST("hMass2DCorrelationPairsMCRecSigRef"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + case 8: // D Sig, Dbar Sig + registry.fill(HIST("hMass2DCorrelationPairsMCRecSigSig"), massD, massDbar, ptD, ptDbar, efficiencyWeight); + break; + 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 + continue; + } + + // 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 + 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 + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecBkgBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 1: // D Bkg, Dbar Ref + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecBkgRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 2: // D Bkg, Dbar Sig + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecBkgSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 3: // D Ref, Dbar Bkg + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecRefBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 4: // D Ref, Dbar Ref + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecRefRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 5: // D Ref, Dbar Sig + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecRefSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 6: // D Sig, Dbar Bkg + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecSigBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 7: // D Sig, Dbar Ref + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecSigRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 8: // D Sig, Dbar Sig + registry.fill(HIST("hCorrel2DVsPtSignalRegionMCRecSigSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + default: // should not happen for MC reco + break; + } + } + + if ((massD > sidebandLeftInner->at(pTBinD) && massD < sidebandLeftOuter->at(pTBinD) && massDbar > sidebandLeftInner->at(pTBinDbar) && massDbar < sidebandRightOuter->at(pTBinDbar)) || + (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 + 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 + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecBkgBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 1: // D Bkg, Dbar Ref + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecBkgRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 2: // D Bkg, Dbar Sig + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecBkgSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 3: // D Ref, Dbar Bkg + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecRefBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 4: // D Ref, Dbar Ref + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecRefRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 5: // D Ref, Dbar Sig + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecRefSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 6: // D Sig, Dbar Bkg + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecSigBkg"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 7: // D Sig, Dbar Ref + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecSigRef"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + case 8: // D Sig, Dbar Sig + registry.fill(HIST("hCorrel2DVsPtSidebandsMCRecSigSig"), deltaPhi, deltaEta, ptD, ptDbar, efficiencyWeight); + break; + default: // should not happen for MC reco + break; + } + } + } // end loop + } + + PROCESS_SWITCH(alice3taskcorrelationddbar, processMcRec, "Process MC Reco mode", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/Tasks/alice3Efficiency.cxx b/ALICE3/Tasks/alice3Efficiency.cxx new file mode 100644 index 00000000000..7741ea24696 --- /dev/null +++ b/ALICE3/Tasks/alice3Efficiency.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 alice3Efficiency.cxx +/// +/// \brief This task produces the efficiency +/// +/// \author Nicolò Jacazio, Universita del Piemonte Orientale (IT) +/// \since May 27, 2025 +/// + +#include +#include + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/ConfigParamRegistry.h" +#include "TEfficiency.h" +#include "THashList.h" + +using namespace o2; +using namespace o2::framework; +std::map effVsPt; +std::map effVsEta; + +struct alice3Efficiency { + Configurable> pdgCodes{"pdgCodes", {211}, "List of PDG codes to consider for efficiency calculation"}; + OutputObj outList{"output"}; + Configurable> etaRange{"etaRange", {-5.f, 5.f}, "Eta range for efficiency calculation"}; + void init(o2::framework::InitContext&) + { + outList.setObject(new THashList); + auto createEff = [&](const char* baseName, const char* axisTitle, int pdg, int nBins, double min, double max) { + auto eff = new TEfficiency(Form("%s_pdg%d", baseName, pdg), + Form("Efficiency for PDG %d; %s; Efficiency", pdg, axisTitle), + nBins, min, max); + outList->Add(eff); + return eff; + }; + for (auto pdg : pdgCodes.value) { + effVsPt[pdg] = createEff("efficiency", "p_{T} (GeV/c)", pdg, 100, 0, 10); + effVsEta[pdg] = createEff("efficiency_eta", "#eta", pdg, 100, -5, 5); + } + } + + void process(soa::Join const& tracks, + aod::McParticles const& mcParticles) + { + std::map> pdgIndices; + + // Lambda function to select particles after all cuts + auto isParticleSelected = [&](const o2::aod::McParticle& p) { + if (!p.isPhysicalPrimary()) { + return false; + } + if (p.eta() < etaRange.value.first) { + return false; + } + if (p.eta() > etaRange.value.second) { + return false; + } + return true; + }; + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + const auto& mcParticle = track.mcParticle(); + if (!isParticleSelected(mcParticle)) { + continue; + } + pdgIndices[mcParticle.pdgCode()].push_back(mcParticle.globalIndex()); + } + + for (auto& mc : mcParticles) { + if (effVsPt.find(mc.pdgCode()) == effVsPt.end()) { + continue; + } + if (!isParticleSelected(mc)) { + continue; + } + std::vector& indices = pdgIndices[mc.pdgCode()]; + // Fill efficiency histogram + const bool found = std::find(indices.begin(), indices.end(), mc.globalIndex()) != indices.end(); + effVsPt[mc.pdgCode()]->Fill(found, mc.pt()); + effVsEta[mc.pdgCode()]->Fill(found, mc.eta()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& ctx) +{ + return WorkflowSpec{adaptAnalysisTask(ctx)}; +} diff --git a/ALICE3/Tasks/alice3HfTask3Prong.cxx b/ALICE3/Tasks/alice3HfTask3Prong.cxx new file mode 100644 index 00000000000..fa0e2867503 --- /dev/null +++ b/ALICE3/Tasks/alice3HfTask3Prong.cxx @@ -0,0 +1,367 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file hfTask3Prong.cxx +/// \brief 3-prong candidates analysis task for ALICE 3 simulation studies +/// \author Marcello Di Costanzo , Polytechnic University of Turin and INFN Turin + +#include "ALICE3/DataModel/A3DecayFinderTables.h" +#include "ALICE3/DataModel/OTFPIDTrk.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/RICH.h" +#include "ALICE3/Utils/utilsHfAlice3.h" +#include "ALICE3/Utils/utilsSelectionsAlice3.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Λc± → p± K∓ π± analysis task +struct Alice3HfTask3Prong { + Configurable yCandGenMax{"yCandGenMax", 0.8, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + Configurable> binsPt{"binsPt", std::vector{hf_cuts_3prongs_alice3::vecBinsPt}, "pT bin limits"}; + Configurable fillThn{"fillThn", false, "fill Thn"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + 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)"}; + + HfHelperAlice3 hfHelper; + SliceCache cache; + Service ccdb; + + int selectedPdg{-1}; + + using Cands3PReco = soa::Filtered>; + using Cands3PRecoWMl = soa::Filtered>; + using Cands3PGen = soa::Join; + + Filter filterSelectCandidates = (aod::a3_hf_sel_3prong::isSelMassHypo0 == true || aod::a3_hf_sel_3prong::isSelMassHypo1 == true); + + Partition candsGenLcs = nabs(aod::a3_mc_truth::flagMcGen) == static_cast(CharmHadAlice3::Lc); + + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {72, 0, 36}, ""}; + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {300, 1.98, 2.58}, ""}; + ConfigurableAxis thnConfigAxisBdtScoreBkg{"thnConfigAxisBdtScoreBkg", {1000, 0., 1.}, ""}; + ConfigurableAxis thnConfigAxisBdtScoreSignal{"thnConfigAxisBdtScoreSignal", {100, 0., 1.}, ""}; + ConfigurableAxis thnConfigAxisCanType{"thnConfigAxisCanType", {5, 0., 5.}, ""}; + ConfigurableAxis thnAxisRapidity{"thnAxisRapidity", {20, -1, 1}, "Cand. rapidity bins"}; + ConfigurableAxis thnConfigAxisGenPtB{"thnConfigAxisGenPtB", {1000, 0, 100}, "Gen Pt B"}; + + HistogramRegistry registry{"registry", {}}; + + // Names of folders and suffixes for MC signal histograms + constexpr static std::string_view SignalFolders[] = {"signal", "prompt", "nonprompt"}; + constexpr static std::string_view SignalSuffixes[] = {"", "Prompt", "NonPrompt"}; + + enum SignalClasses : int { + Signal = 0, + Prompt, + NonPrompt + }; + + void init(InitContext&) + { + const std::array doprocess{doprocessLc, doprocessLcWMl}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "no or more than one process function enabled! Please check your configuration!"); + } + + if (doprocessLc || doprocessLcWMl) { + selectedPdg = CharmHadAlice3::Lc; + } + + auto addHistogramsRec = [&](const std::string& histoName, const std::string& xAxisTitle, const std::string& yAxisTitle, const HistogramConfigSpec& configSpec) { + registry.add(("MC/rec/signal/" + histoName + "RecSig").c_str(), ("3-prong cands (matched);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + registry.add(("MC/rec/prompt/" + histoName + "RecSigPrompt").c_str(), ("3-prong cands (matched, prompt);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + registry.add(("MC/rec/nonprompt/" + histoName + "RecSigNonPrompt").c_str(), ("3-prong cands (matched, non-prompt);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + }; + + auto addHistogramsGen = [&](const std::string& histoName, const std::string& xAxisTitle, const std::string& yAxisTitle, const HistogramConfigSpec& configSpec) { + registry.add(("MC/gen/signal/" + histoName + "Gen").c_str(), ("MC particles (matched);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + registry.add(("MC/gen/prompt/" + histoName + "GenPrompt").c_str(), ("MC particles (matched, prompt);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + registry.add(("MC/gen/nonprompt/" + histoName + "GenNonPrompt").c_str(), ("MC particles (matched, non-prompt);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + }; + + auto vbins = (std::vector)binsPt; + + /// Reconstructed Histograms + addHistogramsRec("hMass", "inv. mass (p K #pi) (GeV/#it{c}^{2})", "", {HistType::kTH1F, {{600, 1.98, 2.58}}}); + addHistogramsRec("hPt", "#it{p}_{T}^{rec.} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + addHistogramsRec("hPhi", "#it{#Phi}", "entries", {HistType::kTH1F, {{100, 0., 6.3}}}); + addHistogramsRec("hPtProng0", "prong 0 #it{p}_{T} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + addHistogramsRec("hPtProng1", "prong 1 #it{p}_{T} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + addHistogramsRec("hPtProng2", "prong 2 #it{p}_{T} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + addHistogramsRec("hd0Prong0", "prong 0 DCAxy to prim. vertex (cm)", "entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}); + addHistogramsRec("hd0Prong1", "prong 1 DCAxy to prim. vertex (cm)", "entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}); + addHistogramsRec("hd0Prong2", "prong 2 DCAxy to prim. vertex (cm)", "entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}); + addHistogramsRec("hDecLength", "decay length (cm)", "entries", {HistType::kTH1F, {{400, 0., 1.}}}); + addHistogramsRec("hDecLengthxy", "decay length xy (cm)", "entries", {HistType::kTH1F, {{400, 0., 1.}}}); + addHistogramsRec("hCPA", "cosine of pointing angle", "entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}); + addHistogramsRec("hCPAxy", "cosine of pointing angle xy", "entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}); + addHistogramsRec("hDca2", "prong Chi2PCA to sec. vertex (cm)", "entries", {HistType::kTH1F, {{400, 0., 20.}}}); + addHistogramsRec("hEta", "#it{#eta}", "entries", {HistType::kTH1F, {{100, -2., 2.}}}); + addHistogramsRec("hMassVsPt", "inv. mass (p K #pi) (GeV/#it{c}^{2})", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{600, 1.98, 2.58}, {vbins}}}); + addHistogramsRec("hd0VsPtProng0", "prong 0 DCAxy to prim. vertex (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins}}}); + addHistogramsRec("hd0VsPtProng1", "prong 1 DCAxy to prim. vertex (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins}}}); + addHistogramsRec("hd0VsPtProng2", "prong 2 DCAxy to prim. vertex (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins}}}); + addHistogramsRec("hDecLengthVsPt", "decay length (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 1.}, {vbins}}}); + addHistogramsRec("hDecLengthxyVsPt", "decay length xy (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 1.}, {vbins}}}); + addHistogramsRec("hCPAVsPt", "cosine of pointing angle", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins}}}); + addHistogramsRec("hCPAxyVsPt", "cosine of pointing angle xy", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins}}}); + addHistogramsRec("hDca2VsPt", "prong Chi2PCA to sec. vertex (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 20.}, {vbins}}}); + addHistogramsRec("hEtaVsPt", "candidate #it{#eta}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -2., 2.}, {vbins}}}); + addHistogramsRec("hPhiVsPt", "candidate #it{#Phi}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 6.3}, {vbins}}}); + addHistogramsRec("hImpParErrProng0VsPt", "prong 0 impact parameter error (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1., 1.}, {vbins}}}); + addHistogramsRec("hImpParErrProng1VsPt", "prong 1 impact parameter error (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1., 1.}, {vbins}}}); + addHistogramsRec("hImpParErrProng2VsPt", "prong 2 impact parameter error (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1., 1.}, {vbins}}}); + addHistogramsRec("hDecLenErrVsPt", "decay length error (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 1.}, {vbins}}}); + + /// Generated Histograms + addHistogramsGen("hPt", "#it{p}_{T}^{gen.} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + addHistogramsGen("hEta", "#it{#eta}", "entries", {HistType::kTH1F, {{100, -2., 2.}}}); + addHistogramsGen("hPhi", "#it{#Phi}", "entries", {HistType::kTH1F, {{100, 0., 6.3}}}); + addHistogramsGen("hY", "#it{y}", "entries", {HistType::kTH1F, {{100, -2., 2.}}}); + addHistogramsGen("hEtaVsPt", "#it{#eta}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -2., 2.}, {vbins}}}); + addHistogramsGen("hYVsPt", "#it{y}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -2., 2.}, {vbins}}}); + addHistogramsGen("hPhiVsPt", "#it{#Phi}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 6.3}, {vbins}}}); + + /// selection status + registry.add("hSelectionStatus", "3-prong cands;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + + 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 thnAxisScoreBkg{thnConfigAxisBdtScoreBkg, "BDT bkg score"}; + const AxisSpec thnAxisScorePrompt{thnConfigAxisBdtScoreSignal, "BDT prompt score"}; + const AxisSpec thnAxisScoreNonPrompt{thnConfigAxisBdtScoreSignal, "BDT non-prompt score"}; + const AxisSpec thnAxisCanType{thnConfigAxisCanType, "candidates type"}; + const AxisSpec thnAxisY{thnAxisRapidity, "rapidity"}; + const AxisSpec thnAxisPtB{thnConfigAxisGenPtB, "#it{p}_{T}^{B} (GeV/#it{c})"}; + + std::vector axesWithBdt = {thnAxisMass, thnAxisPt, thnAxisScoreBkg, thnAxisScorePrompt, thnAxisScoreNonPrompt, thnAxisPtB, thnAxisCanType}; + registry.add("hSparseRec", "Thn for reco cands", HistType::kTHnSparseF, axesWithBdt); + std::vector axesGen = {thnAxisPt, thnAxisY, thnAxisPtB, thnAxisCanType}; + registry.add("hSparseGen", "Thn for gen cands", HistType::kTHnSparseF, axesGen); + } + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + } + + /// Helper function for filling MC reconstructed histograms for prompt, nonpromt and common (signal) + /// \param candidate is a reconstructed candidate + /// \tparam SignalType is an enum defining which histogram in which folder (signal, prompt or nonpromt) to fill + template + void fillHistogramsRecSig(CandidateType const& candidate, float mass) + { + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hMassRecSig") + HIST(SignalSuffixes[SignalType]), mass); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hMassVsPtRecSig") + HIST(SignalSuffixes[SignalType]), mass, candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hPtProng0RecSig") + HIST(SignalSuffixes[SignalType]), candidate.ptProng0()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hPtProng1RecSig") + HIST(SignalSuffixes[SignalType]), candidate.ptProng1()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hPtProng2RecSig") + HIST(SignalSuffixes[SignalType]), candidate.ptProng2()); + + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hd0Prong0RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameterY0()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hd0Prong1RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameterY1()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hd0Prong2RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameterY2()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hd0VsPtProng0RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameterY0(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hd0VsPtProng1RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameterY1(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hd0VsPtProng2RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameterY2(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLengthRecSig") + HIST(SignalSuffixes[SignalType]), candidate.decayLength()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLengthVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.decayLength(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLengthxyRecSig") + HIST(SignalSuffixes[SignalType]), candidate.decayLengthXY()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLengthxyVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.decayLengthXY(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hCPARecSig") + HIST(SignalSuffixes[SignalType]), candidate.cpa()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hCPAVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.cpa(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hCPAxyRecSig") + HIST(SignalSuffixes[SignalType]), candidate.cpaXY()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hCPAxyVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.cpaXY(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hDca2RecSig") + HIST(SignalSuffixes[SignalType]), candidate.chi2PCA()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hDca2VsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.chi2PCA(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaRecSig") + HIST(SignalSuffixes[SignalType]), candidate.eta()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.eta(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hPhiRecSig") + HIST(SignalSuffixes[SignalType]), candidate.phi()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hPhiVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.phi(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hImpParErrProng0VsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.errorImpactParameterY0(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hImpParErrProng1VsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.errorImpactParameterY1(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hImpParErrProng2VsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.errorImpactParameterY2(), candidate.pt()); + registry.fill(HIST("MC/rec/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLenErrVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.errorDecayLength(), candidate.pt()); + } + + /// Fill MC histograms at reconstruction level + /// \tparam CharmHad is the charm hadron species + /// \tparam SaveMl indicates whether ML scores are saved in the THnSparse + /// \tparam CandsRec is the type of the reconstructed candidates collection + /// \param candidates is the collection of reconstructed candidates + template + void fillHistosMcRec(CandsRec const& candidates) + { + for (const auto& candidate : candidates) { + /// rapidity selection + if (yCandRecoMax >= 0. && std::abs(hfHelper.getCandY(candidate)) > yCandRecoMax) { + continue; + } + + if (candidate.flagMcRec() != 0) { + // Get the corresponding MC particle. + + const auto pt = candidate.pt(); + const auto originType = candidate.originMcRec(); + + if (fillThn) { + if (candidate.isSelMassHypo0()) { + registry.fill(HIST("hSelectionStatus"), 0., pt); + double mass = hfHelper.getCandMass(candidate); + /// Fill histograms + fillHistogramsRecSig(candidate, mass); + if (originType == RecoDecay::OriginType::Prompt) { + fillHistogramsRecSig(candidate, mass); + } else if (originType == RecoDecay::OriginType::NonPrompt) { + fillHistogramsRecSig(candidate, mass); + } + std::vector valuesToFill{mass, pt}; + if constexpr (SaveMl) { + LOGP(fatal, "Trying to access ML scores, but SaveMl is false!"); + valuesToFill.push_back(candidate.mlScore0()); + valuesToFill.push_back(candidate.mlScore1()); + valuesToFill.push_back(candidate.mlScore2()); + } + valuesToFill.push_back(static_cast(originType)); + registry.get(HIST("hSparseRec"))->Fill(valuesToFill.data()); + } + if (candidate.isSelMassHypo1()) { + registry.fill(HIST("hSelectionStatus"), 1., pt); + double mass = hfHelper.getCandMass(candidate); + /// Fill histograms + fillHistogramsRecSig(candidate, mass); + if (originType == RecoDecay::OriginType::Prompt) { + fillHistogramsRecSig(candidate, mass); + } else if (originType == RecoDecay::OriginType::NonPrompt) { + fillHistogramsRecSig(candidate, mass); + } + std::vector valuesToFill{mass, pt}; + if constexpr (SaveMl) { + LOGP(fatal, "Trying to access ML scores, but SaveMl is false!"); + valuesToFill.push_back(candidate.mlScore0()); + valuesToFill.push_back(candidate.mlScore1()); + valuesToFill.push_back(candidate.mlScore2()); + } + valuesToFill.push_back(static_cast(originType)); + registry.get(HIST("hSparseRec"))->Fill(valuesToFill.data()); + } + } + } + } + } + + /// Helper function for filling MC generated histograms for prompt, nonpromt and common (signal) + /// \tparam CharmHad is the charm hadron species + /// \tparam SignalType is an enum defining which histogram in which folder (signal, prompt or nonpromt) to fill + /// \tparam ParticleType is the type of the generated particle + /// \param particle is a generated particle + template + void fillHistogramsGen(ParticleType const& particle) + { + LOG(debug) << "Filling generated histograms for signal type " << SignalType; + registry.fill(HIST("MC/gen/") + HIST(SignalFolders[SignalType]) + HIST("/hPtGen") + HIST(SignalSuffixes[SignalType]), particle.pt()); + registry.fill(HIST("MC/gen/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaGen") + HIST(SignalSuffixes[SignalType]), particle.eta()); + registry.fill(HIST("MC/gen/") + HIST(SignalFolders[SignalType]) + HIST("/hYGen") + HIST(SignalSuffixes[SignalType]), hfHelper.getCandY(particle)); + registry.fill(HIST("MC/gen/") + HIST(SignalFolders[SignalType]) + HIST("/hPhiGen") + HIST(SignalSuffixes[SignalType]), particle.phi()); + registry.fill(HIST("MC/gen/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaVsPtGen") + HIST(SignalSuffixes[SignalType]), particle.eta(), particle.pt()); + registry.fill(HIST("MC/gen/") + HIST(SignalFolders[SignalType]) + HIST("/hYVsPtGen") + HIST(SignalSuffixes[SignalType]), hfHelper.getCandY(particle), particle.pt()); + registry.fill(HIST("MC/gen/") + HIST(SignalFolders[SignalType]) + HIST("/hPhiVsPtGen") + HIST(SignalSuffixes[SignalType]), particle.phi(), particle.pt()); + } + + /// Fill MC histograms at generated level + /// \tparam CharmHad is the charm hadron species + /// \tparam CandsGen is the type of the generated candidates collection + /// \param mcParticles is the collection of generated particles + template + void fillHistosMcGen(CandsGen const& mcParticles) + { + // MC gen. + for (const auto& particle : mcParticles) { + if (std::abs(particle.flagMcGen()) == selectedPdg) { + double yGen = hfHelper.getCandY(particle); + if (yCandGenMax >= 0. && std::abs(yGen) > yCandGenMax) { + continue; + } + const auto ptGen = particle.pt(); + const auto originType = particle.originMcGen(); + + fillHistogramsGen(particle); + + float ptGenB = -1.f; + if (originType == RecoDecay::OriginType::Prompt) { + fillHistogramsGen(particle); + } else if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + ptGenB = particle.bHadMotherPtGen(); + fillHistogramsGen(particle); + } + + if (fillThn) { + std::vector valuesToFill{ptGen, yGen, ptGenB, static_cast(originType)}; + registry.get(HIST("hSparseGen"))->Fill(valuesToFill.data()); + } + } + } + } + + void processLc(Cands3PReco const& candsLc, + Cands3PGen const&) + { + fillHistosMcRec(candsLc); + fillHistosMcGen(candsGenLcs); + } + PROCESS_SWITCH(Alice3HfTask3Prong, processLc, "Process Lc w/o ML sels", true); + + void processLcWMl(Cands3PRecoWMl const& candsLcWMl, + Cands3PGen const&) + { + fillHistosMcRec(candsLcWMl); + fillHistosMcGen(candsGenLcs); + } + PROCESS_SWITCH(Alice3HfTask3Prong, processLcWMl, "Process Lc with ML sels", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/Tasks/alice3PidEvaluation.cxx b/ALICE3/Tasks/alice3PidEvaluation.cxx new file mode 100644 index 00000000000..2ee64ea7623 --- /dev/null +++ b/ALICE3/Tasks/alice3PidEvaluation.cxx @@ -0,0 +1,371 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file alice3PidEvaluation.cxx +/// +/// \brief This task computes purity and efficiency from the OTF PID tables for multiple detectors. +/// Analyzes individual detectors (Tracker, TOF Inner, TOF Outer, RICH), +/// as well as combined detector performance using quadrature combination +/// of nSigma values. +/// +/// \author Henrik Fribert TUM +/// \since August 14, 2025 +/// + +#include "ALICE3/DataModel/OTFPIDTrk.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonUtils/NameConf.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" + +#include "TH1F.h" +#include "TH2F.h" +#include "TProfile.h" +#include "TVector3.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +struct Alice3PidEvaluation { + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + static constexpr float kInvalidNSigmaValue = 999.0f; + + Configurable maxNSigmaForIdentification{"maxNSigmaForIdentification", 3.0f, "Maximum |nSigma| allowed for particle identification (closest-hypothesis rule)"}; + Configurable numLogBins{"numLogBins", 200, "Number of logarithmic momentum bins"}; + Configurable useClosestHypothesisRule{"useClosestHypothesisRule", true, "Use closest-hypothesis rule: assign track to hypothesis with smallest |nSigma|"}; + Configurable useMinimalIdentification{"useMinimalIdentification", false, "Require that only one hypothesis is within the cutoff"}; + Configurable includeTrackerInCombined{"includeTrackerInCombined", true, "Include Tracker in combined analysis"}; + Configurable includeTofInnerInCombined{"includeTofInnerInCombined", true, "Include TOF Inner in combined analysis"}; + Configurable includeTofOuterInCombined{"includeTofOuterInCombined", true, "Include TOF Outer in combined analysis"}; + Configurable includeRichInCombined{"includeRichInCombined", false, "Include RICH in combined analysis"}; + + std::vector mLogBins; + + enum PidHypothesis { kElectron, + kMuon, + kPion, + kKaon, + kProton, + kDeuteron, + kTriton, + kHelium3, + kAlpha, + kCount }; + static constexpr std::array kHypothesisPdg = {11, 13, 211, 321, 2212, 1000010020, 1000010030, 1000020030, 1000020040}; + static constexpr std::array kHypothesisNames = {"Electron", "Muon", "Pion", "Kaon", "Proton", "Deuteron", "Triton", "Helium3", "Alpha"}; + + struct DetectorHistograms { + std::array, PidHypothesis::kCount> hTotalTrue; + std::array, PidHypothesis::kCount> hEfficiency; + std::array, PidHypothesis::kCount> hPurityAsHypothesis; + }; + + std::shared_ptr hDetectorParticipation2D; + + DetectorHistograms trackerHists; + DetectorHistograms tofInnerHists; + DetectorHistograms tofOuterHists; + DetectorHistograms richHists; + DetectorHistograms combinedHists; + DetectorHistograms combinedNoTrackerHists; + void init(o2::framework::InitContext&) + { + LOG(info) << "Initializing multi-detector PID evaluation using closest-hypothesis rule"; + LOG(info) << "Maximum |nSigma| for identification: " << maxNSigmaForIdentification.value; + LOG(info) << "Closest-hypothesis rule: " << (useClosestHypothesisRule.value ? "ENABLED" : "DISABLED"); + LOG(info) << "Require unique identification: " << (useMinimalIdentification.value ? "YES" : "NO"); + LOG(info) << "Combined analysis includes: " + << (includeTrackerInCombined.value ? "Tracker " : "") + << (includeTofInnerInCombined.value ? "TOF_Inner " : "") + << (includeTofOuterInCombined.value ? "TOF_Outer " : "") + << (includeRichInCombined.value ? "RICH " : ""); + + mLogBins.clear(); + double pMin = 0.05; + double pMax = 10; + double logMin = std::log10(pMin); + double logMax = std::log10(pMax); + double dLog = (logMax - logMin) / numLogBins.value; + for (int i = 0; i <= numLogBins.value; ++i) { + mLogBins.push_back(std::pow(10, logMin + i * dLog)); + } + const AxisSpec axisMomentum{mLogBins, "#it{p} (GeV/#it{c})"}; + + auto createDetectorHistograms = [&](DetectorHistograms& detHists, const std::string& detectorName) { + for (int trueIdx = 0; trueIdx < PidHypothesis::kCount; ++trueIdx) { + const auto& trueName = kHypothesisNames[trueIdx]; + detHists.hTotalTrue[trueIdx] = histos.add(Form("%s/hTotalTrue%s", detectorName.c_str(), trueName), + Form("%s: Total True %s; #it{p} (GeV/#it{c})", detectorName.c_str(), trueName), + kTH1F, {axisMomentum}); + detHists.hEfficiency[trueIdx] = histos.add(Form("%s/hEfficiency%s", detectorName.c_str(), trueName), + Form("%s: PID Efficiency for %s; #it{p} (GeV/#it{c}); Efficiency", detectorName.c_str(), trueName), + kTProfile, {axisMomentum}); + } + + for (int hypIdx = 0; hypIdx < PidHypothesis::kCount; ++hypIdx) { + const auto& hypName = kHypothesisNames[hypIdx]; + detHists.hPurityAsHypothesis[hypIdx] = histos.add(Form("%s/hPurityAs%s", detectorName.c_str(), hypName), + Form("%s: Purity when selecting as %s; #it{p} (GeV/#it{c}); Purity", detectorName.c_str(), hypName), + kTProfile, {axisMomentum}); + } + }; + + createDetectorHistograms(trackerHists, "Tracker"); + createDetectorHistograms(tofInnerHists, "TOF_Inner"); + createDetectorHistograms(tofOuterHists, "TOF_Outer"); + createDetectorHistograms(richHists, "RICH"); + createDetectorHistograms(combinedHists, "Combined"); + createDetectorHistograms(combinedNoTrackerHists, "Combined_NoTracker"); + + const AxisSpec axisDetectorCount{5, -0.5, 4.5, "Number of detectors"}; + hDetectorParticipation2D = histos.add("Combined/hDetectorParticipation2D", + "Detector participation vs momentum; #it{p} (GeV/#it{c}); Number of detectors", + kTH2F, {axisMomentum, axisDetectorCount}); + } + + void process(soa::Join const& tracks, + aod::McParticles const& /*mcParticles*/) + { + + auto isValidNSigma = [](float nSigma) -> bool { + return (nSigma < kInvalidNSigmaValue && nSigma > -kInvalidNSigmaValue); + }; + + auto computeCombinedNSigma = [&](const std::vector>& detectorNSigmas, float p) -> std::array { + std::array combinedNSigma; + int totalValidDetectors = 0; + for (const auto& detNSigma : detectorNSigmas) { + bool detectorHasValidMeasurement = false; + for (int hypIdx = 0; hypIdx < PidHypothesis::kCount; ++hypIdx) { + if (isValidNSigma(detNSigma[hypIdx])) { + detectorHasValidMeasurement = true; + break; + } + } + if (detectorHasValidMeasurement) { + totalValidDetectors++; + } + } + + for (int hypIdx = 0; hypIdx < PidHypothesis::kCount; ++hypIdx) { + float sumSquares = 0.0f; + int validDetectors = 0; + + for (const auto& detNSigma : detectorNSigmas) { + if (isValidNSigma(detNSigma[hypIdx])) { + sumSquares += detNSigma[hypIdx] * detNSigma[hypIdx]; + validDetectors++; + } + } + + if (validDetectors > 0) { + combinedNSigma[hypIdx] = std::sqrt(sumSquares); + } else { + combinedNSigma[hypIdx] = kInvalidNSigmaValue; + } + } + if (totalValidDetectors > 0) { + hDetectorParticipation2D->Fill(p, totalValidDetectors); + } + + return combinedNSigma; + }; + + auto analyzeDetector = [&](DetectorHistograms& detHists, const std::array& nSigmaValues, + int trueParticleIndex, float p) { + detHists.hTotalTrue[trueParticleIndex]->Fill(p); + bool hasValidNSigma = false; + for (int i = 0; i < PidHypothesis::kCount; ++i) { + if (isValidNSigma(nSigmaValues[i])) { + hasValidNSigma = true; + break; + } + } + if (!hasValidNSigma) { + return; + } + + bool correctlyIdentified = false; + int selectedHypothesis = -1; + + if (useClosestHypothesisRule.value) { + float minAbsNSigma = kInvalidNSigmaValue; + int bestHypothesis = -1; + int validHypothesesCount = 0; + + for (int hypIdx = 0; hypIdx < PidHypothesis::kCount; ++hypIdx) { + if (isValidNSigma(nSigmaValues[hypIdx])) { + float absNSigma = std::fabs(nSigmaValues[hypIdx]); + if (absNSigma < minAbsNSigma) { + minAbsNSigma = absNSigma; + bestHypothesis = hypIdx; + } + if (absNSigma < maxNSigmaForIdentification.value) { + validHypothesesCount++; + } + } + } + + if (bestHypothesis >= 0 && minAbsNSigma < maxNSigmaForIdentification.value) { + if (useMinimalIdentification.value && validHypothesesCount > 1) { + selectedHypothesis = -1; + } else { + selectedHypothesis = bestHypothesis; + } + } + correctlyIdentified = (selectedHypothesis == trueParticleIndex); + } else { + correctlyIdentified = (std::fabs(nSigmaValues[trueParticleIndex]) < maxNSigmaForIdentification.value); + for (int hypIdx = 0; hypIdx < PidHypothesis::kCount; ++hypIdx) { + if (std::fabs(nSigmaValues[hypIdx]) < maxNSigmaForIdentification.value) { + bool isCorrect = (hypIdx == trueParticleIndex); + detHists.hPurityAsHypothesis[hypIdx]->Fill(p, isCorrect ? 1.0 : 0.0); + } + } + } + + detHists.hEfficiency[trueParticleIndex]->Fill(p, correctlyIdentified ? 1.0 : 0.0); + + if (useClosestHypothesisRule.value && selectedHypothesis >= 0) { + bool isCorrect = (selectedHypothesis == trueParticleIndex); + detHists.hPurityAsHypothesis[selectedHypothesis]->Fill(p, isCorrect ? 1.0 : 0.0); + } + }; + + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + + const auto& mcParticle = track.mcParticle(); + const float p = mcParticle.p(); + const int truePdg = std::abs(mcParticle.pdgCode()); + + int trueParticleIndex = -1; + for (int i = 0; i < PidHypothesis::kCount; ++i) { + if (kHypothesisPdg[i] == truePdg) { + trueParticleIndex = i; + break; + } + } + if (trueParticleIndex == -1) { + continue; + } + + std::array trackerNSigma; + trackerNSigma[kElectron] = track.nSigmaTrkEl(); + trackerNSigma[kMuon] = track.nSigmaTrkMu(); + trackerNSigma[kPion] = track.nSigmaTrkPi(); + trackerNSigma[kKaon] = track.nSigmaTrkKa(); + trackerNSigma[kProton] = track.nSigmaTrkPr(); + trackerNSigma[kDeuteron] = track.nSigmaTrkDe(); + trackerNSigma[kTriton] = track.nSigmaTrkTr(); + trackerNSigma[kHelium3] = track.nSigmaTrkHe(); + trackerNSigma[kAlpha] = track.nSigmaTrkAl(); + + analyzeDetector(trackerHists, trackerNSigma, trueParticleIndex, p); + + std::array tofInnerNSigma; + tofInnerNSigma[kElectron] = track.nSigmaElectronInnerTOF(); + tofInnerNSigma[kMuon] = track.nSigmaMuonInnerTOF(); + tofInnerNSigma[kPion] = track.nSigmaPionInnerTOF(); + tofInnerNSigma[kKaon] = track.nSigmaKaonInnerTOF(); + tofInnerNSigma[kProton] = track.nSigmaProtonInnerTOF(); + tofInnerNSigma[kDeuteron] = track.nSigmaDeuteronInnerTOF(); + tofInnerNSigma[kTriton] = track.nSigmaTritonInnerTOF(); + tofInnerNSigma[kHelium3] = track.nSigmaHelium3InnerTOF(); + tofInnerNSigma[kAlpha] = track.nSigmaAlphaInnerTOF(); + + analyzeDetector(tofInnerHists, tofInnerNSigma, trueParticleIndex, p); + + std::array tofOuterNSigma; + tofOuterNSigma[kElectron] = track.nSigmaElectronOuterTOF(); + tofOuterNSigma[kMuon] = track.nSigmaMuonOuterTOF(); + tofOuterNSigma[kPion] = track.nSigmaPionOuterTOF(); + tofOuterNSigma[kKaon] = track.nSigmaKaonOuterTOF(); + tofOuterNSigma[kProton] = track.nSigmaProtonOuterTOF(); + tofOuterNSigma[kDeuteron] = track.nSigmaDeuteronOuterTOF(); + tofOuterNSigma[kTriton] = track.nSigmaTritonOuterTOF(); + tofOuterNSigma[kHelium3] = track.nSigmaHelium3OuterTOF(); + tofOuterNSigma[kAlpha] = track.nSigmaAlphaOuterTOF(); + + analyzeDetector(tofOuterHists, tofOuterNSigma, trueParticleIndex, p); + + std::array richNSigma; + richNSigma[kElectron] = track.nSigmaElectronRich(); + richNSigma[kMuon] = track.nSigmaMuonRich(); + richNSigma[kPion] = track.nSigmaPionRich(); + richNSigma[kKaon] = track.nSigmaKaonRich(); + richNSigma[kProton] = track.nSigmaProtonRich(); + richNSigma[kDeuteron] = track.nSigmaDeuteronRich(); + richNSigma[kTriton] = track.nSigmaTritonRich(); + richNSigma[kHelium3] = track.nSigmaHelium3Rich(); + richNSigma[kAlpha] = track.nSigmaAlphaRich(); + + analyzeDetector(richHists, richNSigma, trueParticleIndex, p); + + std::vector> allDetectorNSigmas; + + if (includeTrackerInCombined.value) { + allDetectorNSigmas.push_back(trackerNSigma); + } + if (includeTofInnerInCombined.value) { + allDetectorNSigmas.push_back(tofInnerNSigma); + } + if (includeTofOuterInCombined.value) { + allDetectorNSigmas.push_back(tofOuterNSigma); + } + if (includeRichInCombined.value) { + allDetectorNSigmas.push_back(richNSigma); + } + if (!allDetectorNSigmas.empty()) { + std::array combinedNSigma = computeCombinedNSigma(allDetectorNSigmas, p); + analyzeDetector(combinedHists, combinedNSigma, trueParticleIndex, p); + } + + std::vector> noTrackerDetectorNSigmas; + + if (includeTofInnerInCombined.value) { + noTrackerDetectorNSigmas.push_back(tofInnerNSigma); + } + if (includeTofOuterInCombined.value) { + noTrackerDetectorNSigmas.push_back(tofOuterNSigma); + } + if (includeRichInCombined.value) { + noTrackerDetectorNSigmas.push_back(richNSigma); + } + if (!noTrackerDetectorNSigmas.empty()) { + std::array combinedNoTrackerNSigma = computeCombinedNSigma(noTrackerDetectorNSigmas, p); + analyzeDetector(combinedNoTrackerHists, combinedNoTrackerNSigma, trueParticleIndex, p); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/Tasks/alice3SeparationPower.cxx b/ALICE3/Tasks/alice3SeparationPower.cxx new file mode 100644 index 00000000000..ae5b52d0692 --- /dev/null +++ b/ALICE3/Tasks/alice3SeparationPower.cxx @@ -0,0 +1,106 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file alice3SeparationPower.cxx +/// +/// \brief This task produces the separation power of the ALICE3 detector +/// +/// \author Nicolò Jacazio, Universita del Piemonte Orientale (IT) +/// \since May 13, 2025 +/// + +#include +#include +#include +#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/HistogramRegistry.h" +#include "TProfile2D.h" +#include "THashList.h" +#include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/OTFRICH.h" + +using namespace o2; +using namespace o2::framework; + +std::array separationInnerTOF; +std::array separationOuterTOF; +std::array separationRICH; +struct alice3SeparationPower { + + ConfigurableAxis etaAxis{"etaAxis", {100, -1.f, 1.f}, "Binning in eta"}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + OutputObj listSeparation{"separationPower"}; + void init(o2::framework::InitContext&) + { + listSeparation.setObject(new THashList); + for (int i = 0; i < 5; i++) { + auto createEfficiency = [&](const char* name, const char* title) { + TProfile2D* eff = new TProfile2D(Form("%s_%d", name, i), + Form("%s_%d;%s", title, i, "#it{p}_{T} (GeV/#it{c});#it{#eta}"), + 100, 0.f, 10.f, + 100, 0.f, 10.f); + listSeparation->Add(eff); + return eff; + }; + separationInnerTOF[i] = createEfficiency("separationInnerTOF", "separationInnerTOF"); + separationOuterTOF[i] = createEfficiency("separationOuterTOF", "separationOuterTOF"); + separationRICH[i] = createEfficiency("separationRICH", "separationRICH"); + } + } + + void process(soa::Join::iterator const& /*collision*/, + soa::Join const& tracks, + aod::McParticles const&, + aod::McCollisions const&) + { + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + // Check that all the nsigmas are numbers (sanity check) + for (int i = 0; i < 5; i++) { + if (std::isnan(track.nSigmaInnerTOF(i)) || std::isnan(track.nSigmaOuterTOF(i))) { + LOG(fatal) << "Unrecognized nsigma for " << i << " " << track.nSigmaInnerTOF(i) << " " << track.nSigmaOuterTOF(i); + } + } + + const auto& mcParticle = track.mcParticle(); + // Separation electron pion + switch (std::abs(mcParticle.pdgCode())) { + { + case 211: // electron-pion separation + separationInnerTOF[0]->Fill(track.pt(), track.eta(), track.nSigmaInnerTOF(0)); + separationOuterTOF[0]->Fill(track.pt(), track.eta(), track.nSigmaOuterTOF(0)); + // separationRICH[0]->Fill(track.pt(), track.eta(), track.nSigmaElectronRich() ); + break; + case 321: // pion-kaon separation + separationInnerTOF[1]->Fill(track.pt(), track.eta(), track.nSigmaInnerTOF(1)); + separationOuterTOF[1]->Fill(track.pt(), track.eta(), track.nSigmaInnerTOF(1)); + // separationRICH[1]->Fill(track.pt(), track.eta(), track.nSigmaPionRich() ); + break; + case 2212: // kaon-proton separation + separationInnerTOF[2]->Fill(track.pt(), track.eta(), track.nSigmaInnerTOF(2)); + separationOuterTOF[2]->Fill(track.pt(), track.eta(), track.nSigmaInnerTOF(2)); + // separationRICH[2]->Fill((track.nSigmaKaonRich() > 3.f), track.pt(), track.eta()); + default: + break; + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/ALICE3/Tasks/alice3TrackingPerformance.cxx b/ALICE3/Tasks/alice3TrackingPerformance.cxx new file mode 100644 index 00000000000..a5958bab772 --- /dev/null +++ b/ALICE3/Tasks/alice3TrackingPerformance.cxx @@ -0,0 +1,130 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file alice3TrackingPerformance.cxx +/// +/// \brief This task produces the tracking performance +/// +/// \author Nicolò Jacazio, Universita del Piemonte Orientale (IT) +/// \since May 27, 2025 +/// + +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +std::shared_ptr particlePdgCodes; +std::map> particlePtDistribution; +std::map> particleEtaDistribution; +std::map> ptDistribution; +std::map> ptResolutionVsPt; +std::map> invPtResolutionVsPt; +std::map> dcaXyResolutionVsPt; +std::map> dcaZResolutionVsPt; + +struct Alice3TrackingPerformance { + Configurable> pdgCodes{"pdgCodes", {0, 211}, "List of PDG codes to consider for efficiency calculation. (0 means all)"}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable> etaRange{"etaRange", {-5.f, 5.f}, "Eta range for efficiency calculation"}; + + void init(o2::framework::InitContext&) + { + const AxisSpec axisPt{100, 0, 10, "p_{T} (GeV/c)"}; + const AxisSpec axisEta{100, etaRange.value.first, etaRange.value.second, "#eta"}; + const AxisSpec axisPtDelta{100, -1, 1, "p_{T}^{gen} - p_{T}^{reco} (GeV/c)"}; + const AxisSpec axisInvPtDelta{100, -1, 1, "1./p_{T}^{gen} - 1./p_{T}^{reco} (GeV/c)^{-1}"}; + const AxisSpec axisDcaXy{100, -1, 1, "DCA_{xy} (cm)"}; + const AxisSpec axisDcaZ{100, -1, 1, "DCA_{z} (cm)"}; + particlePdgCodes = histos.add("particlePdgCodes", "", kTH1D, {AxisSpec{100, -0.5, 99.5, "PDG Code"}}); + for (const int& pdg : pdgCodes.value) { + std::string tag = Form("_%d", pdg); + if (pdg < 0) { + tag = Form("_m%d", -pdg); + } + particlePtDistribution[pdg] = histos.add("particlePtDistribution" + tag, "", kTH1D, {axisPt}); + particleEtaDistribution[pdg] = histos.add("particleEtaDistribution" + tag, "", kTH1D, {axisEta}); + + ptDistribution[pdg] = histos.add("ptDistribution" + tag, "", kTH1D, {axisPt}); + ptResolutionVsPt[pdg] = histos.add("ptResolutionVsPt" + tag, "", kTH2D, {axisPt, axisPtDelta}); + invPtResolutionVsPt[pdg] = histos.add("invPtResolutionVsPt" + tag, "", kTH2D, {axisPt, axisInvPtDelta}); + dcaXyResolutionVsPt[pdg] = histos.add("dcaXyResolutionVsPt" + tag, "", kTH2D, {axisPt, axisDcaXy}); + dcaZResolutionVsPt[pdg] = histos.add("dcaZResolutionVsPt" + tag, "", kTH2D, {axisPt, axisDcaZ}); + } + } + + void process(soa::Join const& tracks, + aod::McParticles const& mcParticles) + { + auto isParticleSelected = [&](const o2::aod::McParticle& p) { + if (!p.isPhysicalPrimary()) { + return false; + } + if (p.eta() < etaRange.value.first) { + return false; + } + if (p.eta() > etaRange.value.second) { + return false; + } + return true; + }; + + for (const auto& mcParticle : mcParticles) { + particlePdgCodes->Fill(Form("%d", mcParticle.pdgCode()), 1); + if (!isParticleSelected(mcParticle)) { + continue; + } + particlePtDistribution[0]->Fill(mcParticle.pt()); + particleEtaDistribution[0]->Fill(mcParticle.eta()); + if (particlePtDistribution.find(mcParticle.pdgCode()) == particlePtDistribution.end()) { + continue; + } + particlePtDistribution[mcParticle.pdgCode()]->Fill(mcParticle.pt()); + particleEtaDistribution[mcParticle.pdgCode()]->Fill(mcParticle.eta()); + } + for (const auto& track : tracks) { + ptDistribution[0]->Fill(track.pt()); + if (!track.has_mcParticle()) { + continue; + } + const auto& mcParticle = track.mcParticle(); + ptResolutionVsPt[0]->Fill(mcParticle.pt(), mcParticle.pt() - track.pt()); + invPtResolutionVsPt[0]->Fill(mcParticle.pt(), 1.f / mcParticle.pt() - 1.f / track.pt()); + dcaXyResolutionVsPt[0]->Fill(mcParticle.pt(), track.dcaXY()); + dcaZResolutionVsPt[0]->Fill(mcParticle.pt(), track.dcaZ()); + if (!isParticleSelected(mcParticle)) { + continue; + } + if (ptResolutionVsPt.find(mcParticle.pdgCode()) == ptResolutionVsPt.end()) { + continue; + } + ptDistribution[mcParticle.pdgCode()]->Fill(mcParticle.pt()); + ptResolutionVsPt[mcParticle.pdgCode()]->Fill(mcParticle.pt(), mcParticle.pt() - track.pt()); + invPtResolutionVsPt[mcParticle.pdgCode()]->Fill(mcParticle.pt(), 1.f / mcParticle.pt() - 1.f / track.pt()); + dcaXyResolutionVsPt[mcParticle.pdgCode()]->Fill(mcParticle.pt(), track.dcaXY()); + dcaZResolutionVsPt[mcParticle.pdgCode()]->Fill(mcParticle.pt(), track.dcaZ()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& ctx) +{ + return WorkflowSpec{adaptAnalysisTask(ctx)}; +} diff --git a/ALICE3/Tasks/pidRICHqa.cxx b/ALICE3/Tasks/pidRICHqa.cxx index ab2a71e3ad9..3a8a960b4ed 100644 --- a/ALICE3/Tasks/pidRICHqa.cxx +++ b/ALICE3/Tasks/pidRICHqa.cxx @@ -16,9 +16,10 @@ /// // O2 includes -#include "Framework/AnalysisTask.h" #include "ALICE3/DataModel/RICH.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" + +#include "Framework/AnalysisTask.h" #include "ReconstructionDataFormats/PID.h" using namespace o2; diff --git a/ALICE3/Tools/handleParamTOFResoALICE3.cxx b/ALICE3/Tools/handleParamTOFResoALICE3.cxx deleted file mode 100644 index 79184cfd8d2..00000000000 --- a/ALICE3/Tools/handleParamTOFResoALICE3.cxx +++ /dev/null @@ -1,132 +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 handleParamTOFResoALICE3.cxx -/// \author Nicolo' Jacazio -/// \since 2020-06-22 -/// \brief A simple tool to produce Bethe Bloch parametrization objects for the TOF PID Response -/// - -#include "CCDB/CcdbApi.h" -#include -#include "Framework/Logger.h" -#include "TFile.h" -#include "ALICE3/Core/TOFResoALICE3.h" - -using namespace o2::pid::tof; -namespace bpo = boost::program_options; - -bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv[], bpo::variables_map& vm) -{ - options.add_options()( - "url,u", bpo::value()->default_value("http://alice-ccdb.cern.ch"), "URL of the CCDB database")( - "ccdb-path,c", bpo::value()->default_value("Analysis/ALICE3/PID/TOF"), "CCDB path for storage/retrieval")( - "start,s", bpo::value()->default_value(0), "Start timestamp of object validity")( - "stop,S", bpo::value()->default_value(4108971600000), "Stop timestamp of object validity")( - "delete-previous,delete_previous,d", bpo::value()->default_value(0), "Flag to delete previous versions of converter objects in the CCDB before uploading the new one so as to avoid proliferation on CCDB")( - "save-to-file,file,f,o", bpo::value()->default_value(""), "Option to save parametrization to file instead of uploading to ccdb")( - "read-from-file,i", bpo::value()->default_value(""), "Option to get parametrization from a file")( - "reso-name,n", bpo::value()->default_value("TOFResoALICE3"), "Name of the parametrization object")( - "mode,m", bpo::value()->default_value(1), "Working mode: 0 push 1 pull and test")( - "p0", bpo::value()->default_value(20.0f), "Parameter 0 of the TOF resolution: average TOF resolution")( - "verbose,v", bpo::value()->default_value(0), "Verbose level 0, 1")( - "help,h", "Produce help message."); - try { - bpo::store(parse_command_line(argc, argv, options), vm); - - // help - if (vm.count("help")) { - LOG(info) << options; - return false; - } - - bpo::notify(vm); - } catch (const bpo::error& e) { - LOG(error) << e.what() << "\n"; - LOG(error) << "Error parsing command line arguments; Available options:"; - LOG(error) << options; - return false; - } - return true; -} - -int main(int argc, char* argv[]) -{ - bpo::options_description options("Allowed options"); - bpo::variables_map vm; - if (!initOptionsAndParse(options, argc, argv, vm)) { - return 1; - } - - const unsigned int mode = vm["mode"].as(); - const std::string path = vm["ccdb-path"].as(); - std::map metadata; - std::map* headers = nullptr; - o2::ccdb::CcdbApi api; - const std::string url = vm["url"].as(); - api.init(url); - if (!api.isHostReachable()) { - LOG(warning) << "CCDB host " << url << " is not reacheable, cannot go forward"; - return 1; - } - TOFResoALICE3* reso = nullptr; - const std::string reso_name = vm["reso-name"].as(); - if (mode == 0) { // Push mode - LOG(info) << "Handling TOF parametrization in create mode"; - const std::string input_file_name = vm["read-from-file"].as(); - if (!input_file_name.empty()) { - TFile f(input_file_name.data(), "READ"); - if (!f.IsOpen()) { - LOG(warning) << "Input file " << input_file_name << " is not reacheable, cannot get param from file"; - } - f.GetObject(reso_name.c_str(), reso); - f.Close(); - } - if (!reso) { - reso = new TOFResoALICE3(); - const std::vector resoparams = {vm["p0"].as()}; - reso->SetParameters(resoparams); - } - reso->Print(); - const std::string fname = vm["save-to-file"].as(); - if (!fname.empty()) { // Saving it to file - LOG(info) << "Saving parametrization to file " << fname; - TFile f(fname.data(), "RECREATE"); - reso->Write(); - reso->GetParameters().Write(); - f.ls(); - f.Close(); - } else { // Saving it to CCDB - LOG(info) << "Saving parametrization to CCDB " << path; - - long start = vm["start"].as(); - long stop = vm["stop"].as(); - - if (vm["delete-previous"].as()) { - api.truncate(path); - } - api.storeAsTFileAny(reso, path + "/" + reso_name, metadata, start, stop); - o2::pid::Parameters* params; - reso->GetParameters(params); - api.storeAsTFileAny(params, path + "/Parameters/" + reso_name, metadata, start, stop); - } - } else { // Pull and test mode - LOG(info) << "Handling TOF parametrization in test mode"; - const float x[7] = {1, 1, 1, 1, 1, 1, 1}; // mom, time, ev. reso, mass, length, sigma1pt, pt - reso = api.retrieveFromTFileAny(path + "/" + reso_name, metadata, -1, headers); - reso->Print(); - LOG(info) << "TOF expected resolution at p=" << x[0] << " GeV/c " - << " and mass " << x[3] << ":" << reso->operator()(x); - } - - return 0; -} diff --git a/ALICE3/Utils/utilsHfAlice3.h b/ALICE3/Utils/utilsHfAlice3.h new file mode 100644 index 00000000000..4f58316369b --- /dev/null +++ b/ALICE3/Utils/utilsHfAlice3.h @@ -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. + +/// \file HfHelperAlice3.h +/// \brief Class with helper functions for HF analyses +/// +/// \author Marcello Di Costanzo , Polytechnic University of Turin and INFN Turin + +#ifndef ALICE3_UTILS_UTILSHFALICE3_H_ +#define ALICE3_UTILS_UTILSHFALICE3_H_ + +#include "PWGHF/Core/HfHelper.h" + +namespace o2::analysis +{ + +enum CharmHadAlice3 { Lc = 1 }; + +} // namespace o2::analysis + +class HfHelperAlice3 +{ + public: + /// Default constructor + HfHelperAlice3() = default; + + /// Default destructor + ~HfHelperAlice3() = default; + + /// Get candidate mass (ALICE3 HF data model) + /// \tparam TCand candidate type + /// \param cand candidate + /// \return candidate mass + template + static double getCandMass(const TCand& cand) + { + switch (CharmHad) { + case o2::analysis::CharmHadAlice3::Lc: + return SwapHypo ? HfHelper::invMassLcToPiKP(cand) : HfHelper::invMassLcToPKPi(cand); + default: + LOG(fatal) << "Unsupported charm hadron type"; + return -1.; + } + } + + /// Get candidate energy (ALICE3 HF data model) + /// \tparam TCand candidate type + /// \param cand candidate + /// \return candidate energy + template + static double getCandEnergy(const TCand& cand) + { + switch (CharmHad) { + case o2::analysis::CharmHadAlice3::Lc: + return HfHelper::eLc(cand); + default: + LOG(fatal) << "Unsupported charm hadron type"; + return -1.; + } + } + + /// Get candidate rapidity (ALICE3 HF data model) + /// \tparam TCand candidate type + /// \param cand candidate + /// \return candidate rapidity + template + static double getCandY(const TCand& cand) + { + if constexpr (requires { cand.flagMcRec(); }) { + switch (CharmHad) { + case o2::analysis::CharmHadAlice3::Lc: + return HfHelper::yLc(cand); + default: + LOG(fatal) << "Unsupported charm hadron type"; + return -1.; + } + } else { + switch (CharmHad) { + case o2::analysis::CharmHadAlice3::Lc: + return RecoDecay::y(cand.pVector(), o2::constants::physics::MassLambdaCPlus); + default: + LOG(fatal) << "Unsupported charm hadron type"; + return -1.; + } + } + } +}; + +#endif // ALICE3_UTILS_UTILSHFALICE3_H_ diff --git a/ALICE3/Utils/utilsSelectionsAlice3.h b/ALICE3/Utils/utilsSelectionsAlice3.h new file mode 100644 index 00000000000..585b22e5295 --- /dev/null +++ b/ALICE3/Utils/utilsSelectionsAlice3.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. + +/// \file utilsSelectionsAlice3s.h +/// \brief Default pT bins and cut arrays for selections in ALICE3 performance analysis tasks +/// +/// \author Marcello Di Costanzo , Polytechnic University of Turin and INFN Turin + +#ifndef ALICE3_UTILS_UTILSSELECTIONSALICE3_H_ +#define ALICE3_UTILS_UTILSSELECTIONSALICE3_H_ + +#include // std::string +#include // std::vector + +namespace o2::analysis +{ +namespace hf_cuts_3prongs_alice3 +{ +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] = { + 0., + 1., + 2., + 3., + 4., + 5., + 6., + 8., + 12., + 24., + 36.}; +const auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts m, ptP, ptK, ptPi, chi2PCA, cosp, dL, dLXY, NdLXY, ImpParXY +constexpr double Cuts[NBinsPt][NCutVars] = {{0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 0 < pT < 1 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 1 < pT < 2 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 2 < pT < 3 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 3 < pT < 4 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 4 < pT < 5 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 5 < pT < 6 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 6 < pT < 8 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 8 < pT < 12 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 12 < pT < 24 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}}; /* 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 prong 0", "pT prong 1", "pT prong 2", "Chi2PCA", "cos pointing angle", "decay length", "decLengthXY", "normDecLXY", "impParXY"}; +} // namespace hf_cuts_3prongs_alice3 + +} // namespace o2::analysis + +#endif // ALICE3_UTILS_UTILSSELECTIONSALICE3_H_ diff --git a/ALICE3/macros/a3geo.ini b/ALICE3/macros/a3geo.ini new file mode 100644 index 00000000000..b9bae64b575 --- /dev/null +++ b/ALICE3/macros/a3geo.ini @@ -0,0 +1,148 @@ +# Example of the ALICE3 geometry file in TEnv format +bpipe0.r: 0.48 +bpipe0.z: 250 +bpipe0.x0: 0.001592 +bpipe0.xrho: 0 +bpipe0.resRPhi: 0.0 +bpipe0.resZ: 0.0 +bpipe0.eff: 0.0 +bpipe0.type: 0 +bpipe0.deadPhiRegions: /tmp/asd.root + +B00.r: 0.5 +B00.z: 250 +B00.x0: 0.00076 +B00.xrho: 0 +B00.resRPhi: 0.00025 +B00.resZ: 0.00025 +B00.eff: 1. +B00.type: 1 + +B01.r: 1.2 +B01.z: 250 +B01.x0: 0.00096 +B01.xrho: 0 +B01.resRPhi: 0.00025 +B01.resZ: 0.00025 +B01.eff: 1. +B01.type: 1 + +B02.r: 2.5 +B02.z: 250 +B02.x0: 0.00096 +B02.xrho: 0 +B02.resRPhi: 0.00025 +B02.resZ: 0.00025 +B02.eff: 1. +B02.type: 1 + +coldplate.r: 2.6 +coldplate.z: 250 +coldplate.x0: 0.02 +coldplate.xrho: 0 +coldplate.resRPhi: 0 +coldplate.resZ: 0 +coldplate.eff: 0 +coldplate.type: 0 + +petal.r: 3.7 +petal.z: 250 +petal.x0: 0.001592 +petal.xrho: 0 +petal.resRPhi: 0 +petal.resZ: 0 +petal.eff: 0 +petal.type: 0 + +bpipe1.r: 5.7 +bpipe1.z: 250 +bpipe1.x0: 0.0023 +bpipe1.xrho: 0 +bpipe1.resRPhi: 0.0 +bpipe1.resZ: 0.0 +bpipe1.eff: 0.0 +bpipe1.type: 0 + +B03.r: 7. +B03.z: 250 +B03.x0: 0.01 +B03.xrho: 0 +B03.resRPhi: 0.001 +B03.resZ: 0.001 +B03.eff: 1. +B03.type: 1 + +B04.r: 9. +B04.z: 250 +B04.x0: 0.01 +B04.xrho: 0 +B04.resRPhi: 0.001 +B04.resZ: 0.001 +B04.eff: 1. +B04.type: 1 + +B05.r: 12. +B05.z: 250 +B05.x0: 0.01 +B05.xrho: 0 +B05.resRPhi: 0.001 +B05.resZ: 0.001 +B05.eff: 1. +B05.type: 1 + +iTOF.r: 19. +iTOF.z: 250 +iTOF.x0: 0.03 +iTOF.xrho: 0 +iTOF.resRPhi: 0.001 +iTOF.resZ: 0.001 +iTOF.eff: 1. +iTOF.type: 0 + +B06.r: 20. +B06.z: 250 +B06.x0: 0.01 +B06.xrho: 0 +B06.resRPhi: 0.001 +B06.resZ: 0.001 +B06.eff: 1. +B06.type: 1 + +B07.r: 30. +B07.z: 250 +B07.x0: 0.01 +B07.xrho: 0 +B07.resRPhi: 0.001 +B07.resZ: 0.001 +B07.eff: 1. +B07.type: 1 + +B08.r: 45. +B08.z: 250 +B08.x0: 0.01 +B08.xrho: 0 +B08.resRPhi: 0.001 +B08.resZ: 0.001 +B08.eff: 1. +B08.type: 1 + +B09.r: 60. +B09.z: 250 +B09.x0: 0.01 +B09.xrho: 0 +B09.resRPhi: 0.001 +B09.resZ: 0.001 +B09.eff: 1. +B09.type: 1 + +B10.r: 80. +B10.z: 250 +B10.x0: 0.01 +B10.xrho: 0 +B10.resRPhi: 0.001 +B10.resZ: 0.001 +B10.eff: 1. +B10.type: 1 + + + diff --git a/ALICE3/macros/testFastTracker.C b/ALICE3/macros/testFastTracker.C new file mode 100644 index 00000000000..f9ec72e0765 --- /dev/null +++ b/ALICE3/macros/testFastTracker.C @@ -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 testFastTracker.C +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Test the FastTracker functionality + +#include "ALICE3/Core/FastTracker.h" + +#include +#include + +#include + +void testFastTracker(std::string geometryFile = "a3geo.ini") +{ + + fair::Logger::SetConsoleSeverity(fair::Severity::debug); + + // auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); + // ccdb.setURL("http://alice-ccdb.cern.ch"); + o2::fastsim::FastTracker fastTracker; + fastTracker.AddGenericDetector(geometryFile); + // fastTracker.AddGenericDetector(geometryFile, &ccdb); + fastTracker.Print(); +} diff --git a/CODEOWNERS b/CODEOWNERS index 05334d1b9bd..b4c64b16b99 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -15,42 +15,61 @@ /Common/CCDB @alibuild @jgrosseo @iarsene @ekryshen @ddobrigk /Common/Tools/Multiplicity @alibuild @ddobrigk @victor-gonzalez /ALICE3 @alibuild @njacazio @hscheid -/DPG @alibuild @chiarazampolli @noferini +/DPG @alibuild @chiarazampolli @alcaliva @catalinristea /DPG/Tasks/AOTEvent @alibuild @ekryshen @strogolo @altsybee -/DPG/Tasks/AOTTrack @alibuild @mfaggin @iouribelikov @njacazio +/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 -/PWGDQ @alibuild @iarsene @dsekihat @feisenhu @lucamicheletti93 -/PWGEM @alibuild @mikesas @rbailhac @feisenhu -/PWGEM/Dilepton @alibuild @mikesas @rbailhac @dsekihat @ivorobye @feisenhu +/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 @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF/Core @alibuild @jgrosseo @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF/DataModel @alibuild @jgrosseo @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF/TableProducer @alibuild @jgrosseo @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGCF/Tasks @alibuild @jgrosseo @victor-gonzalez @zchochul @lgraczykCern @prchakra @lauraser @ariedel-cern @EmilGorm @otonvd @shouqiye @glromane +/PWGDQ @alibuild @iarsene @mcoquet642 @lucamicheletti93 @XiaozhiBai +/PWGEM @alibuild @feisenhu @dsekihat @ivorobye +/PWGEM/Dilepton @alibuild @mikesas @rbailhac @dsekihat @ivorobye @feisenhu @hscheid /PWGEM/PhotonMeson @alibuild @mikesas @rbailhac @m-c-danisch @novitzky @mhemmer-cern @dsekihat -/PWGHF @alibuild @vkucera @fcolamar @fgrosa @fcatalan92 @mfaggin @mmazzilli @deepathoms @NicoleBastid @hahassan7 @jpxrk @apalasciano -/PWGLF @alibuild @ercolessi @fmazzasc @chiarapinto @BongHwi @smaff92 @mbombara @ChiaraDeMartin95 @njacazio @skundu692 -/PWGMM @alibuild @aalkin -/PWGMM/Lumi @alibuild @aalkin -/PWGMM/Mult @alibuild @aalkin @aortizve @ddobrigk -/PWGMM/UE @alibuild @aalkin @aortizve -/PWGUD @alibuild @pbuehler @abylinkin @rolavick -/PWGJE @alibuild @lhavener @maoyx @nzardosh @ddobrigk @mfasDa +/PWGHF @alibuild @vkucera @fcolamar @fgrosa @fcatalan92 @mfaggin @mmazzilli @deepathoms @NicoleBastid @hahassan7 @jpxrk @apalasciano @zhangbiao-phy @gluparel @stefanopolitano @xinyepeng +# PWG-LF +/PWGLF @alibuild @sustripathy @skundu692 @mpuccio +/PWGLF/DataModel @alibuild @sustripathy @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @dmallick2 @smaff92 @ercolessi @romainschotter +/PWGLF/Tasks/GlobalEventProperties @alibuild @sustripathy @skundu692 @mpuccio @gbencedi @abmodak @omvazque +/PWGLF/TableProducer/GlobalEventProperties @alibuild @sustripathy @skundu692 @mpuccio @gbencedi @abmodak @omvazque +/PWGLF/Tasks/Nuspex @alibuild @sustripathy @skundu692 @mpuccio @fmazzasc @maciacco +/PWGLF/TableProducer/Nuspex @alibuild @sustripathy @skundu692 @mpuccio @fmazzasc @maciacco +/PWGLF/Tasks/Resonances @alibuild @sustripathy @skundu692 @mpuccio @dmallick2 @smaff92 +/PWGLF/TableProducer/Resonances @alibuild @sustripathy @skundu692 @mpuccio @dmallick2 @smaff92 +/PWGLF/Tasks/Strangeness @alibuild @sustripathy @skundu692 @mpuccio @ercolessi @romainschotter +/PWGLF/TableProducer/Strangeness @alibuild @sustripathy @mpuccio @skundu692 @ercolessi @romainschotter +/PWGLF/TableProducer/QC @alibuild @sustripathy @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @dmallick2 @smaff92 @ercolessi @romainschotter +/PWGLF/Tasks/QC @alibuild @sustripathy @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @dmallick2 @smaff92 @ercolessi @romainschotter +/PWGLF/Utils @alibuild @sustripathy @skundu692 @mpuccio @gbencedi @abmodak @fmazzasc @maciacco @dmallick2 @smaff92 @ercolessi @romainschotter + +# PWG-MM (fused with LF, LF conveners included. Directories to be merged in the future) +/PWGMM @alibuild @mpuccio @skundu692 @aalkin @jgcn +/PWGMM/Mult @alibuild @mpuccio @skundu692 @aalkin @aortizve @ddobrigk @gbencedi @jgcn +/PWGMM/Lumi @alibuild @mpuccio @skundu692 @aalkin @jgcn @gbencedi @abmodak +/PWGMM/UE @alibuild @mpuccio @skundu692 @aalkin @aortizve @jgcn + +/PWGUD @alibuild @amatyja @rolavick +/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/PWGCF @alibuild @jgrosseo @victor-gonzalez @zchochul +/Tutorials/PWGDQ @alibuild @iarsene @mcoquet @lucamicheletti93 /Tutorials/PWGEM @alibuild @mikesas @rbailhac @dsekihat @ivorobye @feisenhu -/Tutorials/PWGHF @alibuild @vkucera @fcolamar @fgrosa -/Tutorials/PWGJE @alibuild @lhavener @maoyx @nzardosh @ddobrigk @mfasDa -/Tutorials/PWGLF @alibuild @alcaliva @lbariogl @chiarapinto @BongHwi @lbarnby @mbombara @iravasen @njacazio @ChiaraDeMartin95 @skundu692 +/Tutorials/PWGHF @alibuild @vkucera @fcolamar @fgrosa @gluparel @xinyepeng +/Tutorials/PWGJE @alibuild @lhavener @maoyx @nzardosh @mfasDa @fjonasALICE +/Tutorials/PWGLF @alibuild @alcaliva @lbariogl @chiarapinto @BongHwi @lbarnby @ercolessi @iravasen @njacazio @romainschotter @skundu692 /Tutorials/PWGMM @alibuild @aalkin @ddobrigk -/Tutorials/PWGUD @alibuild @pbuehler +/Tutorials/PWGUD @alibuild @pbuehler @amatyja diff --git a/CPPLINT.cfg b/CPPLINT.cfg index e050d1df67c..96a8077f685 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/include_order,-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/CMakeLists.txt b/Common/CCDB/CMakeLists.txt index 63584528a38..21a2c31877e 100644 --- a/Common/CCDB/CMakeLists.txt +++ b/Common/CCDB/CMakeLists.txt @@ -19,4 +19,8 @@ o2physics_target_root_dictionary(AnalysisCCDB HEADERS EventSelectionParams.h HEADERS TriggerAliases.h HEADERS ctpRateFetcher.h + HEADERS RCTSelectionFlags.h LINKDEF AnalysisCCDBLinkDef.h) + +o2physics_add_header_only_library(RCTSelectionFlags + HEADERS RCTSelectionFlags.h) diff --git a/Common/CCDB/EventSelectionParams.cxx b/Common/CCDB/EventSelectionParams.cxx index 55ff1d04af1..013711d0464 100644 --- a/Common/CCDB/EventSelectionParams.cxx +++ b/Common/CCDB/EventSelectionParams.cxx @@ -9,8 +9,18 @@ // 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" +#include +#include + namespace o2::aod::evsel { const char* selectionLabels[kNsel] = { @@ -55,13 +65,15 @@ const char* selectionLabels[kNsel] = { "kIsVertexITSTPC", "kIsVertexTOFmatched", "kIsVertexTRDmatched", - "kNoHighOccupancyAgressive", - "kNoHighOccupancyStrict", - "kNoHighOccupancyMedium", - "kNoHighOccupancyRelaxed", - "kNoHighOccupancyGentle", + "kNoCollInTimeRangeNarrow", + "kNoCollInTimeRangeStrict", "kNoCollInTimeRangeStandard", - "kNoCollInTimeRangeNarrow"}; + "kNoCollInRofStrict", + "kNoCollInRofStandard", + "kNoHighMultCollInPrevRof", + "kIsGoodITSLayer3", + "kIsGoodITSLayer0123", + "kIsGoodITSLayersAll"}; } // namespace o2::aod::evsel using namespace o2::aod::evsel; @@ -166,7 +178,7 @@ EventSelectionParams::EventSelectionParams(int system, int run) } } -void EventSelectionParams::DisableOutOfBunchPileupCuts() +void EventSelectionParams::disableOutOfBunchPileupCuts() { selectionBarrel[kNoV0MOnVsOfPileup] = 0; selectionBarrel[kNoSPDOnVsOfPileup] = 0; @@ -184,7 +196,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; @@ -192,7 +204,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 dfedfd1e12f..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_ @@ -60,13 +65,15 @@ enum EventSelectionFlags { 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 - kNoHighOccupancyAgressive, // no occupancy according to the agressive cuts - kNoHighOccupancyStrict, // no occupancy according to the strict cuts - kNoHighOccupancyMedium, // no occupancy according to the medium cuts - kNoHighOccupancyRelaxed, // no occupancy according to the relaxed cuts - kNoHighOccupancyGentle, // no occupancy according to the gentle cuts - kNoCollInTimeRangeStandard, // no collisions in specified time range - kNoCollInTimeRangeNarrow, // no collisions in specified time range (narrower than Standard) + 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 }; @@ -77,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]; @@ -154,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, 6) + 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..265b201ffde --- /dev/null +++ b/Common/CCDB/RCTSelectionFlags.h @@ -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. + +/// \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, + kDummy24, + kDummy25, + kDummy26, + kDummy27, + kDummy28, + kDummy29, + kDummy30, + kCcdbObjectLoaded +}; + +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" + // - "CBT_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 + // The checkTableValidity boolean flag controls whether events without a corresponding valid RCT CCDB object should be + // treated as Bad and excluded + explicit RCTFlagsChecker(const std::string& label, + bool checkZDC = false, + bool treatLimitedAcceptanceAsBad = false, + bool checkTableValidity = false) + { + init(label, checkZDC, treatLimitedAcceptanceAsBad, checkTableValidity); + } + + // 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 + // The checkTableValidity boolean flag controls whether events without a corresponding valid RCT CCDB object should be + // treated as Bad and excluded + void init(const std::string& label, + bool checkZDC = false, + bool treatLimitedAcceptanceAsBad = false, + bool checkTableValidity = 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); + } + + if (checkTableValidity) { + set(kCcdbObjectLoaded); + } + } + + // 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) + { + // throw an exception if none of the bits in the checker mask is set + if (!any()) { + throw std::out_of_range("RCTFlagsChecker has 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); + } + + // Check the validity of the RCT column of a given event selection table. + // The function returns true if the RCT CCDB object was correctly fetched (bit31 == 0). + bool isTableValid(const HasRCTFlags auto& table) + { + return (table.rct_bit(kCcdbObjectLoaded) == 0); + } + + bool operator()(const HasRCTFlags auto& table) + { + return checkTable(table); + } +}; + +} // namespace o2::aod::rctsel +#endif // COMMON_CCDB_RCTSELECTIONFLAGS_H_ diff --git a/Common/CCDB/TriggerAliases.cxx b/Common/CCDB/TriggerAliases.cxx index 789d293c1d0..c3d28889bca 100644 --- a/Common/CCDB/TriggerAliases.cxx +++ b/Common/CCDB/TriggerAliases.cxx @@ -10,7 +10,11 @@ // or submit itself to any jurisdiction. #include "Common/CCDB/TriggerAliases.h" -#include "Framework/Logger.h" + +#include + +#include +#include std::string aliasLabels[kNaliases] = { "kINT7", diff --git a/Common/CCDB/TriggerAliases.h b/Common/CCDB/TriggerAliases.h index f1baf04fdcc..60dbd965741 100644 --- a/Common/CCDB/TriggerAliases.h +++ b/Common/CCDB/TriggerAliases.h @@ -12,10 +12,12 @@ #ifndef COMMON_CCDB_TRIGGERALIASES_H_ #define COMMON_CCDB_TRIGGERALIASES_H_ +#include +#include + #include #include #include -#include enum triggerAliases { kINT7 = 0, @@ -57,7 +59,7 @@ class TriggerAliases TriggerAliases() = default; ~TriggerAliases() = default; - void AddAlias(uint32_t aliasId, std::string classNames) { mAliasToClassNames[aliasId] = classNames; } + void AddAlias(uint32_t aliasId, std::string const& classNames) { mAliasToClassNames[aliasId] = classNames; } void AddClassIdToAlias(uint32_t aliasId, int classId); const std::map& GetAliasToClassNamesMap() const { return mAliasToClassNames; } const std::map& GetAliasToTriggerMaskMap() const { return mAliasToTriggerMask; } diff --git a/Common/CCDB/ctpRateFetcher.cxx b/Common/CCDB/ctpRateFetcher.cxx index 49d3c7ecd97..6cf7213f2e7 100644 --- a/Common/CCDB/ctpRateFetcher.cxx +++ b/Common/CCDB/ctpRateFetcher.cxx @@ -11,18 +11,24 @@ #include "ctpRateFetcher.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include +#include +#include #include -#include "CommonConstants/LHCConstants.h" -#include "DataFormatsCTP/Configuration.h" -#include "DataFormatsCTP/Scalers.h" -#include "DataFormatsParameters/GRPLHCIFData.h" -#include "CCDB/BasicCCDBManager.h" - 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, const std::string& sourceName, bool fCrashOnNull) { setupRun(runNumber, ccdb, timeStamp); if (sourceName.find("ZNC") != std::string::npos) { @@ -43,7 +49,7 @@ double ctpRateFetcher::fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStam if (ret < 0.) { LOG(info) << "Trying different class"; ret = fetchCTPratesClasses(ccdb, timeStamp, runNumber, "CMTVX-NONE"); - if (ret < 0) { + if ((ret < 0) && fCrashOnNull) { LOG(fatal) << "None of the classes used for lumi found"; } } @@ -69,7 +75,7 @@ double ctpRateFetcher::fetchCTPratesClasses(o2::ccdb::BasicCCDBManager* /*ccdb*/ LOG(warn) << "Trigger class " << className << " not found in CTPConfiguration"; return -1.; } - auto rate{mScalers->getRateGivenT(timeStamp * 1.e-3, classIndex, inputType)}; + auto rate{mScalers->getRateGivenT(timeStamp * 1.e-3, classIndex, inputType, 1)}; return pileUpCorrection(rate.second); } @@ -77,7 +83,7 @@ double ctpRateFetcher::fetchCTPratesInputs(o2::ccdb::BasicCCDBManager* /*ccdb*/, { std::vector recs = mScalers->getScalerRecordO2(); if (recs[0].scalersInps.size() == 48) { - return pileUpCorrection(mScalers->getRateGivenT(timeStamp * 1.e-3, input, 7).second); + return pileUpCorrection(mScalers->getRateGivenT(timeStamp * 1.e-3, input, 7, 1).second); } else { LOG(error) << "Inputs not available"; return -1.; @@ -109,7 +115,7 @@ void ctpRateFetcher::setupRun(int runNumber, o2::ccdb::BasicCCDBManager* ccdb, u delete mScalers; delete mLHCIFdata; } - std::map metadata; + std::map metadata; mLHCIFdata = ccdb->getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); if (mLHCIFdata == nullptr) { LOG(fatal) << "GRPLHCIFData not in database, timestamp:" << timeStamp; diff --git a/Common/CCDB/ctpRateFetcher.h b/Common/CCDB/ctpRateFetcher.h index 412c1e7a424..58c9d2ed553 100644 --- a/Common/CCDB/ctpRateFetcher.h +++ b/Common/CCDB/ctpRateFetcher.h @@ -12,9 +12,10 @@ #ifndef COMMON_CCDB_CTPRATEFETCHER_H_ #define COMMON_CCDB_CTPRATEFETCHER_H_ -#include +#include -#include "CCDB/BasicCCDBManager.h" +#include +#include namespace o2 { @@ -34,7 +35,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, const std::string& sourceName, bool fCrashOnNull = true); void setManualCleanup(bool manualCleanup = true) { mManualCleanup = manualCleanup; } diff --git a/Common/CCDB/macros/upload_event_selection_params.C b/Common/CCDB/macros/upload_event_selection_params.C index 5d63cf49be8..cafc863ab03 100644 --- a/Common/CCDB/macros/upload_event_selection_params.C +++ b/Common/CCDB/macros/upload_event_selection_params.C @@ -12,8 +12,8 @@ #include "CCDB/CcdbApi.h" #include "CCDB/BasicCCDBManager.h" #include "TString.h" -#include "map" -#include "string" +#include +#include #include "EventSelectionParams.h" using std::map; using std::string; diff --git a/Common/CCDB/macros/upload_event_selection_params_run3.C b/Common/CCDB/macros/upload_event_selection_params_run3.C index b439959fe1c..f81491949c6 100644 --- a/Common/CCDB/macros/upload_event_selection_params_run3.C +++ b/Common/CCDB/macros/upload_event_selection_params_run3.C @@ -11,8 +11,8 @@ #include "CCDB/CcdbApi.h" #include "TString.h" -#include "map" -#include "string" +#include +#include #include "EventSelectionParams.h" using std::map; using std::string; 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 61ca933740c..f6974f06f14 100644 --- a/Common/Core/CMakeLists.txt +++ b/Common/Core/CMakeLists.txt @@ -13,12 +13,16 @@ o2physics_add_library(AnalysisCore SOURCES TrackSelection.cxx OrbitRange.cxx PID/ParamBase.cxx + PID/PIDTOF.cxx + PID/PIDTOFParamService.cxx CollisionAssociation.cxx TrackSelectionDefaults.cxx EventPlaneHelper.cxx TableHelper.cxx MetadataHelper.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsParameters ROOT::EG O2::CCDB ROOT::Physics O2::FT0Base O2::FV0Base) + CollisionTypeHelper.cxx + FFitWeights.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsParameters ROOT::EG O2::CCDB ROOT::Physics O2::FT0Base O2::FV0Base O2::DataFormatsParamTOF) o2physics_target_root_dictionary(AnalysisCore HEADERS TrackSelection.h @@ -31,4 +35,20 @@ o2physics_target_root_dictionary(AnalysisCore PID/DetectorResponse.h PID/PIDTOF.h PID/TPCPIDResponse.h + PID/PIDTOFParamService.h + CollisionTypeHelper.h + FFitWeights.h LINKDEF AnalysisCoreLinkDef.h) + +o2physics_add_library(EventFilteringUtils + SOURCES Zorro.cxx ZorroSummary.cxx + INSTALL_HEADERS ZorroHelper.h ZorroSummary.h + PUBLIC_LINK_LIBRARIES O2::Framework O2::CCDB ROOT::EG O2::CCDB ROOT::Physics Arrow::arrow_shared) + +o2physics_target_root_dictionary(EventFilteringUtils + HEADERS ZorroHelper.h ZorroSummary.h + LINKDEF EventFilteringUtilsLinkDef.h) + +o2physics_add_header_only_library(TPCDriftManager + HEADERS TPCVDriftManager.h + INTERFACE_LINK_LIBRARIES O2::DataFormatsTPC) diff --git a/Common/Core/CollisionAssociation.cxx b/Common/Core/CollisionAssociation.cxx index dff8fee51cd..99b3b00e45f 100644 --- a/Common/Core/CollisionAssociation.cxx +++ b/Common/Core/CollisionAssociation.cxx @@ -17,4 +17,4 @@ /// \author Sarah Herrmann , IP2I Lyon /// \author Maurice Coquet , CEA-Saclay/Irfu -#include "Common/Core/CollisionAssociation.h" +#include "Common/Core/CollisionAssociation.h" // IWYU pragma: keep diff --git a/Common/Core/CollisionAssociation.h b/Common/Core/CollisionAssociation.h index 69ec38a24db..338a37022c9 100644 --- a/Common/Core/CollisionAssociation.h +++ b/Common/Core/CollisionAssociation.h @@ -20,13 +20,19 @@ #ifndef COMMON_CORE_COLLISIONASSOCIATION_H_ #define COMMON_CORE_COLLISIONASSOCIATION_H_ -#include +#include +#include +#include +#include + +#include + +#include +#include +#include #include #include - -#include "CommonConstants/LHCConstants.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" +#include namespace o2::aod { @@ -74,7 +80,8 @@ class CollisionAssociation switch (mTrackSelection) { case o2::aod::track_association::TrackSelection::CentralBarrelRun2: { unsigned char itsClusterMap = track.itsClusterMap(); - if (!(track.tpcNClsFound() >= 50 && track.flags() & o2::aod::track::ITSrefit && track.flags() & o2::aod::track::TPCrefit && (TESTBIT(itsClusterMap, 0) || TESTBIT(itsClusterMap, 1)))) { + int minTpcNClsFound{50}; + if (!(track.tpcNClsFound() >= minTpcNClsFound && track.flags() & o2::aod::track::ITSrefit && track.flags() & o2::aod::track::TPCrefit && (TESTBIT(itsClusterMap, 0) || TESTBIT(itsClusterMap, 1)))) { hasGoodQuality = false; } break; @@ -121,7 +128,7 @@ class CollisionAssociation TTracksUnfiltered const& tracksUnfiltered, TTracks const& tracks, TAmbiTracks const& ambiguousTracks, - o2::aod::BCs const&, + o2::aod::BCs const& bcs, Assoc& association, RevIndices& reverseIndices) { @@ -145,6 +152,11 @@ class CollisionAssociation for (const auto& ambTrack : ambiguousTracks) { if constexpr (isCentralBarrel) { // FIXME: to be removed as soon as it is possible to use getId() for joined tables if (ambTrack.trackId() == track.globalIndex()) { + // special check to avoid crashes (in particular on some MC datasets) + // related to shifts in ambiguous tracks association to bc slices (off by 1) - see https://mattermost.web.cern.ch/alice/pl/g9yaaf3tn3g4pgn7c1yex9copy + if (ambTrack.bcIds()[0] >= bcs.size() || ambTrack.bcIds()[1] >= bcs.size()) { + break; + } if (!ambTrack.has_bc() || ambTrack.bc().size() == 0) { break; } @@ -188,33 +200,33 @@ class CollisionAssociation uint64_t collBC = collision.bc().globalBC(); // This is done per block to allow optimization below. Within each block the globalBC increase continously - for (auto& iterationWindow : trackIterationWindows) { + for (auto& iterationWindow : trackIterationWindows) { // o2-linter: disable=const-ref-in-for-loop (iterationWindow is modified) bool iteratorMoved = false; const bool isAssignedTrackWindow = (iterationWindow.first != iterationWindow.second) ? iterationWindow.first.has_collision() : false; - for (auto track = iterationWindow.first; track != iterationWindow.second; ++track) { - int64_t trackBC = globalBC[track.filteredIndex()]; + for (auto trackInWindow = iterationWindow.first; trackInWindow != iterationWindow.second; ++trackInWindow) { + int64_t trackBC = globalBC[trackInWindow.filteredIndex()]; if (trackBC < 0) { continue; } // Optimization to avoid looping over the full track list each time. This builds on that tracks are sorted by BCs (which they should be because collisions are sorted by BCs) - const int64_t bcOffset = trackBC - (int64_t)collBC; + const int64_t bcOffset = trackBC - static_cast(collBC); if constexpr (isCentralBarrel) { // only for blocks with collision association if (isAssignedTrackWindow) { constexpr int margin = 200; if (!iteratorMoved && bcOffset > -bcOffsetMax - margin) { - iterationWindow.first.setCursor(track.filteredIndex()); + iterationWindow.first.setCursor(trackInWindow.filteredIndex()); iteratorMoved = true; - LOGP(debug, "Moving iterator begin {}", track.filteredIndex()); + LOGP(debug, "Moving iterator begin {}", trackInWindow.filteredIndex()); } else if (bcOffset > bcOffsetMax + margin) { - LOGP(debug, "Stopping iterator {}", track.filteredIndex()); + LOGP(debug, "Stopping iterator {}", trackInWindow.filteredIndex()); break; } } } - int64_t bcOffsetWindow = trackBCCache[track.filteredIndex()] - (int64_t)collBC; + int64_t bcOffsetWindow = trackBCCache[trackInWindow.filteredIndex()] - static_cast(collBC); if (std::abs(bcOffsetWindow) > bcOffsetMax) { continue; } @@ -222,27 +234,27 @@ class CollisionAssociation float trackTime = 0; float trackTimeRes = 0; if constexpr (isCentralBarrel) { - if (mUsePvAssociation && track.isPVContributor()) { - trackTime = track.collision().collisionTime(); // if PV contributor, we assume the time to be the one of the collision - trackTimeRes = o2::constants::lhc::LHCBunchSpacingNS; // 1 BC + if (mUsePvAssociation && trackInWindow.isPVContributor()) { + trackTime = trackInWindow.collision().collisionTime(); // if PV contributor, we assume the time to be the one of the collision + trackTimeRes = o2::constants::lhc::LHCBunchSpacingNS; // 1 BC } else { - trackTime = track.trackTime(); - trackTimeRes = track.trackTimeRes(); + trackTime = trackInWindow.trackTime(); + trackTimeRes = trackInWindow.trackTimeRes(); } } else { - trackTime = track.trackTime(); - trackTimeRes = track.trackTimeRes(); + trackTime = trackInWindow.trackTime(); + trackTimeRes = trackInWindow.trackTimeRes(); } const float deltaTime = trackTime - collTime + bcOffset * o2::constants::lhc::LHCBunchSpacingNS; float sigmaTimeRes2 = collTimeRes2 + trackTimeRes * trackTimeRes; - LOGP(debug, "collision time={}, collision time res={}, track time={}, track time res={}, bc collision={}, bc track={}, delta time={}", collTime, collision.collisionTimeRes(), track.trackTime(), track.trackTimeRes(), collBC, trackBC, deltaTime); + LOGP(debug, "collision time={}, collision time res={}, track time={}, track time res={}, bc collision={}, bc track={}, delta time={}", collTime, collision.collisionTimeRes(), trackInWindow.trackTime(), trackInWindow.trackTimeRes(), collBC, trackBC, deltaTime); float thresholdTime = 0.; if constexpr (isCentralBarrel) { - if (mUsePvAssociation && track.isPVContributor()) { + if (mUsePvAssociation && trackInWindow.isPVContributor()) { thresholdTime = trackTimeRes; - } else if (TESTBIT(track.flags(), o2::aod::track::TrackTimeResIsRange)) { + } else if (TESTBIT(trackInWindow.flags(), o2::aod::track::TrackTimeResIsRange)) { // the track time resolution is a range, not a gaussian resolution thresholdTime = trackTimeRes + mNumSigmaForTimeCompat * std::sqrt(collTimeRes2) + mTimeMargin; } else { @@ -262,7 +274,7 @@ class CollisionAssociation if (std::abs(deltaTime) < thresholdTime) { const auto collIdx = collision.globalIndex(); - const auto trackIdx = track.globalIndex(); + const auto trackIdx = trackInWindow.globalIndex(); LOGP(debug, "Filling track id {} for coll id {}", trackIdx, collIdx); association(collIdx, trackIdx); if (mFillTableOfCollIdsPerTrack) { @@ -278,9 +290,9 @@ class CollisionAssociation // create reverse index track to collisions if enabled if (mFillTableOfCollIdsPerTrack) { std::vector empty{}; - for (const auto& track : tracksUnfiltered) { + for (const auto& trackUnfiltered : tracksUnfiltered) { - const auto trackId = track.globalIndex(); + const auto trackId = trackUnfiltered.globalIndex(); if (collsPerTrack[trackId] == nullptr) { reverseIndices(empty); } else { diff --git a/Common/Core/CollisionTypeHelper.cxx b/Common/Core/CollisionTypeHelper.cxx new file mode 100644 index 00000000000..f66fd85a198 --- /dev/null +++ b/Common/Core/CollisionTypeHelper.cxx @@ -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. + +/// +/// \file CollisionTypeHelper.cxx +/// \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 + +#include + +std::string o2::common::core::CollisionSystemType::getCollisionSystemName(collType collSys) +{ + switch (collSys) { + case kCollSyspp: + return "pp"; + case kCollSysPbPb: + return "PbPb"; + case kCollSysXeXe: + return "XeXe"; + case kCollSyspPb: + return "pPb"; + case kCollSysOO: + return "OO"; + case kCollSyspO: + return "pO"; + case kCollSysNeNe: + return "NeNe"; + case kCollSysUndef: + return "Undefined"; + default: + LOG(warning) << "Undefined collision system type: " << collSys; + return "Undefined"; + } +} + +int o2::common::core::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 Z: " << zBeamA << " * " << zBeamC << " detected = " << zBeamA * zBeamC; + 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; + case 64: // O-O 8*8 + return kCollSysOO; + case 8: // p-O 8*1 + return kCollSyspO; + case 100: // Ne-Ne 10*10 + return kCollSysNeNe; + default: + LOG(fatal) << "Undefined collision system in getCollisionTypeFromGrp with Z of BeamA = " << zBeamA << " and Z of BeamC = " << zBeamC; + return kCollSysUndef; + } + return kCollSysUndef; +} diff --git a/Common/Core/CollisionTypeHelper.h b/Common/Core/CollisionTypeHelper.h new file mode 100644 index 00000000000..f0edc19fd90 --- /dev/null +++ b/Common/Core/CollisionTypeHelper.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 + +namespace o2::common::core +{ +// 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 kCollSysOO = 4; // OO (Oxygen-Oxygen) + static constexpr collType kCollSyspO = 5; // pO (proton-Oxygen) + static constexpr collType kCollSysNeNe = 6; // NeNe (Neon-Neon) + static constexpr collType kNCollSys = 7; // Number of collision systems + + static std::string getCollisionSystemName(collType collSys); + + static int getCollisionTypeFromGrp(o2::parameters::GRPLHCIFData* grplhcif); +}; + +} // namespace o2::common::core + +using CollisionSystemType = o2::common::core::CollisionSystemType; + +#endif // COMMON_CORE_COLLISIONTYPEHELPER_H_ diff --git a/EventFiltering/EventFilteringUtilsLinkDef.h b/Common/Core/EventFilteringUtilsLinkDef.h similarity index 94% rename from EventFiltering/EventFilteringUtilsLinkDef.h rename to Common/Core/EventFilteringUtilsLinkDef.h index 61def8978aa..3f029b8aa9a 100644 --- a/EventFiltering/EventFilteringUtilsLinkDef.h +++ b/Common/Core/EventFilteringUtilsLinkDef.h @@ -14,4 +14,5 @@ #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/Common/Core/EventPlaneHelper.cxx b/Common/Core/EventPlaneHelper.cxx index 75424d900d9..9ffd39538a4 100644 --- a/Common/Core/EventPlaneHelper.cxx +++ b/Common/Core/EventPlaneHelper.cxx @@ -20,13 +20,20 @@ #include "Common/Core/EventPlaneHelper.h" +#include +#include + +#include +#include +#include +#include + #include +#include +#include #include -#include #include - -#include "TMath.h" -#include "TVector3.h" +#include double EventPlaneHelper::GetPhiFV0(int chno, o2::fv0::Geometry* fv0geom) { @@ -37,8 +44,8 @@ double EventPlaneHelper::GetPhiFV0(int chno, o2::fv0::Geometry* fv0geom) float offsetX = 0.; float offsetY = 0.; - int cellsInLeft[] = {0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, - 32, 40, 33, 41, 34, 42, 35, 43}; + const int cellsInLeft[] = {0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, + 32, 40, 33, 41, 34, 42, 35, 43}; bool isChnoInLeft = std::find(std::begin(cellsInLeft), std::end(cellsInLeft), chno) != std::end(cellsInLeft); if (isChnoInLeft) { @@ -131,10 +138,10 @@ void EventPlaneHelper::DoCorrections(float& qx, float& qy, qy = (qy - corrections[2] * qx) / (1.0 - corrections[3] * corrections[2]); // Rescaling of the Qx-Qy into a circle. - if (fabs(corrections[4]) > 1e-8) { + if (std::fabs(corrections[4]) > 1e-8) { qx /= corrections[4]; } - if (fabs(corrections[5]) > 1e-8) { + if (std::fabs(corrections[5]) > 1e-8) { qy /= corrections[5]; } } @@ -153,9 +160,9 @@ void EventPlaneHelper::DoTwist(float& qx, float& qy, float lp, float lm) void EventPlaneHelper::DoRescale(float& qx, float& qy, float ap, float am) { - if (fabs(ap) > 1e-8) + if (std::fabs(ap) > 1e-8) qx /= ap; - if (fabs(am) > 1e-8) + if (std::fabs(am) > 1e-8) qy /= am; } diff --git a/Common/Core/EventPlaneHelper.h b/Common/Core/EventPlaneHelper.h index d6a2f3cba11..820af4336c2 100644 --- a/Common/Core/EventPlaneHelper.h +++ b/Common/Core/EventPlaneHelper.h @@ -21,17 +21,16 @@ #ifndef COMMON_CORE_EVENTPLANEHELPER_H_ #define COMMON_CORE_EVENTPLANEHELPER_H_ -#include -#include - -#include "TNamed.h" +#include +#include #include -#include -#include +#include -#include "FV0Base/Geometry.h" -#include "FT0Base/Geometry.h" +#include + +#include +#include class EventPlaneHelper { diff --git a/Common/Core/FFitWeights.cxx b/Common/Core/FFitWeights.cxx new file mode 100644 index 00000000000..41e39b66854 --- /dev/null +++ b/Common/Core/FFitWeights.cxx @@ -0,0 +1,249 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Framework/Logger.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +ClassImp(FFitWeights) + + FFitWeights::FFitWeights() : TNamed("", ""), + fW_data{nullptr}, + ptProfCent{nullptr}, + h2ptCent{nullptr}, + centBin{100}, + qAxis{nullptr}, + nResolution{3000}, + ptBin{100}, + ptAxis{nullptr}, + qnTYPE{0} +{ +} + +FFitWeights::FFitWeights(const char* name) : TNamed(name, name), + fW_data{nullptr}, + ptProfCent{nullptr}, + h2ptCent{nullptr}, + centBin{100}, + qAxis{nullptr}, + nResolution{3000}, + ptBin{100}, + ptAxis{nullptr}, + qnTYPE{0} {} + +FFitWeights::~FFitWeights() +{ + delete fW_data; + if (qAxis) + delete qAxis; + if (ptAxis) + delete ptAxis; +}; + +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())); + } + + if (!ptAxis) + this->setPtAxis(3000, -3, 3); + fW_data->Add(new TProfile("pMeanPt", "", centBin, 0, centBin)); + fW_data->Add(new TH2D("hPtWeight", "", centBin, 0, centBin, ptBin, ptAxis->GetXmin(), ptAxis->GetXmax())); + + ptProfCent = reinterpret_cast(fW_data->FindObject("pMeanPt")); + h2ptCent = reinterpret_cast(fW_data->FindObject("hPtWeight")); +}; + +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); +}; + +void FFitWeights::fillPt(float centrality, float pt, float weight, bool first) +{ + if (first) { + ptProfCent->Fill(centrality, pt, weight); + } else { + h2ptCent->Fill(centrality, pt, weight); + } +}; +float FFitWeights::getPtMult(float centrality) +{ + if (!ptProfCent) { + ptProfCent = reinterpret_cast(fW_data->FindObject("pMeanPt")); + } + return ptProfCent->GetBinContent(ptProfCent->FindBin(centrality)); +}; + +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* lW = 0; + TIter allW(collist); + while ((lW = (reinterpret_cast(allW())))) { + addArray(fW_data, lW->getDataArray()); + nmerged++; + } + return nmerged; +}; +void FFitWeights::addArray(TObjArray* targ, TObjArray* sour) +{ + if (!sour) + return; + + for (int i = 0; i < sour->GetEntries(); i++) { + auto* obj = sour->At(i); + if (!obj) + continue; + + auto* tObj = targ->FindObject(obj->GetName()); + if (!tObj) { + auto* clone = static_cast(obj->Clone(obj->GetName())); + if (auto* h = dynamic_cast(clone)) + h->SetDirectory(0); + targ->Add(clone); + } else if (auto* h1 = dynamic_cast(tObj)) { + if (auto* h2 = dynamic_cast(obj)) + h1->Add(h2); + } + } +} + +void FFitWeights::mptSel() +{ + TObjArray* tar{nullptr}; + tar = fW_data; + if (!tar) + return; + + TH2D* th2 = reinterpret_cast(tar->FindObject("hPtWeight")); + if (!th2) { + return; + } + + TH1D* tmp{nullptr}; + TGraph* tmpgr{nullptr}; + for (int iSP{0}; iSP < NumberSp; iSP++) { + tmp = th2->ProjectionY(Form("mpt_%i_%i", 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_mpt_%i", iSP)); + fW_data->Add(tmpgr); + } +} + +void FFitWeights::qSelection(const std::vector& nhv, const 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) { + LOGF(info, "FFitWeights qh not found!"); + return; + } + + TH1D* tmp{nullptr}; + TGraph* tmpgr{nullptr}; + // TSpline3* spline = nullptr; + for (int iSP{0}; iSP < NumberSp; 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)); + fW_data->Add(tmpgr); + } + } + } +}; +float FFitWeights::internalEval(float centr, const float& val, const char* name) +{ + if (!fW_data) { + return -1; + } + int isp = static_cast(centr); + if (isp < 0 || isp > NumberSp) { + return -1; + } + + auto* spline = dynamic_cast(fW_data->FindObject(Form(name, isp))); + if (!spline) { + return -1; + } + + float perc = 100.f * spline->Eval(val); + return (perc < 0 || perc > MaxTol) ? -1 : perc; +}; + +float FFitWeights::eval(float centr, const float& dqn, int nh, const char* pf) +{ + return internalEval(centr, dqn, Form("sp_q%i%s_%%i", nh, pf)); +}; + +float FFitWeights::evalPt(float centr, const float& mpt) +{ + return internalEval(centr, mpt, "sp_mpt_%i"); +}; diff --git a/Common/Core/FFitWeights.h b/Common/Core/FFitWeights.h new file mode 100644 index 00000000000..e369da29f95 --- /dev/null +++ b/Common/Core/FFitWeights.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. + +/// \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 + +#include +#include + +#include +#include +#include + +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 = ""); + void fillPt(float centrality, float pt, float weight, bool first); + float getPtMult(float centrality); + 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; } + + void setPtBin(int bin) { ptBin = bin; } + void setPtAxis(int bin, float min, float max) + { + ptAxis = new TAxis(bin, min, max); + } + TAxis* getPtAx() { return ptAxis; } + + Long64_t Merge(TCollection* collist); + void qSelection(const std::vector& nhv, const std::vector& stv); + float eval(float centr, const float& dqn, const int nh, const char* pf = ""); + float evalPt(float centr, const float& mpt); + void setResolution(int res) { nResolution = res; } + int getResolution() const { return nResolution; } + void setQnType(const std::vector>& qninp) { qnTYPE = qninp; } + + void mptSel(); + + private: + TObjArray* fW_data; + TProfile* ptProfCent; //! + TH2D* h2ptCent; //! + + int centBin; + TAxis* qAxis; //! + int nResolution; + int ptBin; + TAxis* ptAxis; //! + + 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); + + static constexpr int NumberSp = 90; + static constexpr float MaxTol = 100.05; + + float internalEval(float centr, const float& val, const char* name); + + ClassDef(FFitWeights, 1); // calibration class +}; +#endif // COMMON_CORE_FFITWEIGHTS_H_ diff --git a/Common/Core/MetadataHelper.cxx b/Common/Core/MetadataHelper.cxx index bdcb7e2e8a4..70af2dbec2b 100644 --- a/Common/Core/MetadataHelper.cxx +++ b/Common/Core/MetadataHelper.cxx @@ -17,16 +17,27 @@ #include "Common/Core/MetadataHelper.h" -#include "Framework/InitContext.h" -#include "Framework/RunningWorkflowInfo.h" +#include +#include +#include + +#include + +#include +#include + +using namespace o2::common::core; MetadataHelper::MetadataHelper() { - const std::array keyList = {"DataType", + const std::array keyList = {"DataType", "RecoPassName", "Run", "AnchorPassName", - "AnchorProduction"}; + "AnchorProduction", + "ROOTVersion", + "LPMProductionTag", + "O2Version"}; for (const auto& key : keyList) { mMetadata[key] = "undefined"; } @@ -115,3 +126,47 @@ bool MetadataHelper::isInitialized() const } return mIsInitialized; } + +std::string MetadataHelper::makeMetadataLabel() const +{ + if (!mIsInitialized) { + LOG(fatal) << "Metadata not initialized"; + } + std::string label = get("DataType"); + label += "_" + get("LPMProductionTag"); + if (isMC()) { + label += "_" + get("AnchorPassName"); + label += "_" + get("AnchorProduction"); + } else { + label += "_" + get("RecoPassName"); + } + return label; +} + +std::string MetadataHelper::getO2Version() const +{ + if (!mIsInitialized) { + LOG(warning) << "Metadata not initialized"; + return "undefined"; + } + return get("O2Version"); +} + +bool MetadataHelper::isCommitInSoftwareTag(const std::string& commitHash, const std::string& ccdbUrl) const +{ + const std::string softwareTag = getO2Version(); + std::string command = "curl -i -L "; + command += ccdbUrl; + command += "O2Version/CommitHash/"; + command += commitHash; + command += "/-1/"; + command += "O2Version=" + softwareTag; + command += " 2>&1 | grep --text O2Version:"; + // LOG(info) << "Command to check if commit " << commitHash << " is in software tag " << softwareTag << ": " << command; + TString res = gSystem->GetFromPipe(command.c_str()); + if (res.Contains(Form("O2Version: %s", softwareTag.c_str()))) { + LOG(debug) << "Commit " << commitHash << " is contained in software tag " << softwareTag; + return true; + } + return false; +} diff --git a/Common/Core/MetadataHelper.h b/Common/Core/MetadataHelper.h index 8519c25bc88..7b871084f9a 100644 --- a/Common/Core/MetadataHelper.h +++ b/Common/Core/MetadataHelper.h @@ -9,18 +9,20 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// -/// \file TableHelper.h +/// \file MetadataHelper.h +/// \brief Utility to handle the metadata from the AOD /// \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 -#include "Framework/ConfigContext.h" +#include + +namespace o2::common::core +{ struct MetadataHelper { /// @brief Constructor for the MetadataHelper. Defines the all the metadata keys that will be looked for and accessible @@ -49,19 +51,39 @@ struct MetadataHelper { /// @return true if the data has been initialized, false otherwise bool isInitialized() const; + /// @brief Function to get the O2 version from the metadata in the monalisa format + /// @return the O2 version from the metadata + std::string getO2Version() 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 set a metadata key to a given value + /// @param key the key of the metadata + /// @param value the value to set + /// Note: this function does not check if the key is valid + void set(const std::string& key, const std::string& value) { mMetadata[key] = value; } + /// @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; + /// @brief Function to create a label with the metadata information, useful e.g. for histogram naming + std::string makeMetadataLabel() const; + + /// Function to check if a commit is included in the software tag + /// @param commitHash the commit hash to check + /// @return true if the commit is included in the software tag, false otherwise + bool isCommitInSoftwareTag(const std::string& commitHash, const std::string& ccdbUrl = "http://ccdb-test.cern.ch:8080/") const; + private: std::map mMetadata; /// < The metadata map bool mIsInitialized = false; /// < Flag to check if the metadata has been initialized }; +} // namespace o2::common::core + #endif // COMMON_CORE_METADATAHELPER_H_ diff --git a/Common/Core/OrbitRange.cxx b/Common/Core/OrbitRange.cxx index 51a3ec5fe78..f9fbbb9eec0 100644 --- a/Common/Core/OrbitRange.cxx +++ b/Common/Core/OrbitRange.cxx @@ -14,8 +14,16 @@ // #include "Common/Core/OrbitRange.h" -#include "TCollection.h" -#include "TMath.h" + +#include +#include +#include +#include + +#include +#include + +#include ClassImp(OrbitRange) diff --git a/Common/Core/OrbitRange.h b/Common/Core/OrbitRange.h index 65e3abe2c69..ed1e298fe37 100644 --- a/Common/Core/OrbitRange.h +++ b/Common/Core/OrbitRange.h @@ -13,16 +13,22 @@ // Container to store minimum and maximum orbit counter // -#ifndef OrbitRange_H -#define OrbitRange_H +#ifndef COMMON_CORE_ORBITRANGE_H_ +#define COMMON_CORE_ORBITRANGE_H_ + +#include + +#include +#include + +#include -#include "TNamed.h" class TCollection; class OrbitRange : public TNamed { public: - OrbitRange(const char* name = "orbitRange") : TNamed(name, name), fRunNumber(0), fMinOrbit(0xFFFFFFFF), fMaxOrbit(0) {} + explicit OrbitRange(const char* name = "orbitRange") : TNamed(name, name), fRunNumber(0), fMinOrbit(0xFFFFFFFF), fMaxOrbit(0) {} ~OrbitRange() {} void SetRunNumber(uint32_t runNumber) { fRunNumber = runNumber; } void SetMinOrbit(uint32_t orbit) { fMinOrbit = orbit; } @@ -39,4 +45,4 @@ class OrbitRange : public TNamed ClassDef(OrbitRange, 1) }; -#endif +#endif // COMMON_CORE_ORBITRANGE_H_ diff --git a/Common/Core/PID/DetectorResponse.h b/Common/Core/PID/DetectorResponse.h index 1f687a4605c..f161a1a0e4b 100644 --- a/Common/Core/PID/DetectorResponse.h +++ b/Common/Core/PID/DetectorResponse.h @@ -17,20 +17,20 @@ /// This provides the basic quantities computed by any response i.e. expected values, resolutions and Nsigmas /// -#ifndef O2_ANALYSIS_PID_DETECTORRESPONSE_H_ -#define O2_ANALYSIS_PID_DETECTORRESPONSE_H_ +#ifndef COMMON_CORE_PID_DETECTORRESPONSE_H_ +#define COMMON_CORE_PID_DETECTORRESPONSE_H_ + +#include "Common/Core/PID/ParamBase.h" + +#include + +#include + +#include #include +#include #include -#include "Framework/Logger.h" -// ROOT includes -#include "Rtypes.h" -#include "TMath.h" -#include "TFile.h" - -// O2 includes -#include "ReconstructionDataFormats/PID.h" -#include "Common/Core/PID/ParamBase.h" namespace o2::pid { @@ -52,7 +52,7 @@ class DetectorResponse /// \param fname File name used for input /// \param pname Name of the parametrization in the file /// \param ptype Type of the parametrization - void LoadParamFromFile(const TString fname, const TString pname, const Param_t ptype); + void LoadParamFromFile(const TString& fname, const TString& pname, const Param_t ptype); /// Setter for the parametrization /// \param ptype Type of the parametrization @@ -65,7 +65,7 @@ class DetectorResponse /// Setter for the parametrizations parameters, if the parametrization is not yet initialized a new parametrization is created without any implementation and just parameters /// \param ptype parametrization type /// \param p vector with parameters - void SetParameters(const Param_t ptype, std::vector p); + void SetParameters(const Param_t ptype, const std::vector& p); /// Getter for the value of the parametrization /// \param ptype parametrization type @@ -85,7 +85,7 @@ inline void DetectorResponse::LoadParam(const Param_t ptype, Parametrization* pa mParam[ptype] = param; } -inline void DetectorResponse::LoadParamFromFile(const TString fname, const TString pname, const Param_t ptype) +inline void DetectorResponse::LoadParamFromFile(const TString& fname, const TString& pname, const Param_t ptype) { TFile f(fname, "READ"); if (!f.Get(pname)) { @@ -97,7 +97,7 @@ inline void DetectorResponse::LoadParamFromFile(const TString fname, const TStri mParam[ptype]->Print(); } -inline void DetectorResponse::SetParameters(const DetectorResponse::Param_t ptype, std::vector p) +inline void DetectorResponse::SetParameters(const DetectorResponse::Param_t ptype, const std::vector& p) { if (!mParam[ptype]) { const std::string pname = std::string(ParamName[ptype]) + "_default_param"; @@ -110,4 +110,4 @@ inline void DetectorResponse::SetParameters(const DetectorResponse::Param_t ptyp } // namespace o2::pid -#endif // O2_ANALYSIS_PID_DETECTORRESPONSE_H_ +#endif // COMMON_CORE_PID_DETECTORRESPONSE_H_ diff --git a/Common/Core/PID/PIDTOF.cxx b/Common/Core/PID/PIDTOF.cxx new file mode 100644 index 00000000000..eaef6e9113f --- /dev/null +++ b/Common/Core/PID/PIDTOF.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 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 + +#include +#include +#include +#include + +#include +#include +#include +#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 5ecd32cbbd0..b4c00631048 100644 --- a/Common/Core/PID/PIDTOF.h +++ b/Common/Core/PID/PIDTOF.h @@ -19,109 +19,30 @@ #ifndef COMMON_CORE_PID_PIDTOF_H_ #define COMMON_CORE_PID_PIDTOF_H_ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include #include #include #include -// ROOT includes -#include "Rtypes.h" -#include "TMath.h" -#include "TGraph.h" -#include "TFile.h" - -// O2 includes -#include "DataFormatsTOF/ParameterContainers.h" -#include "Framework/Logger.h" -#include "ReconstructionDataFormats/PID.h" -#include "Framework/DataTypes.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,6 +60,11 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13> ~TOFResoParamsV2() = default; + template + float getResolution(const float, const float) const + { + return -1.f; + } // Momentum shift for charge calibration void setMomentumChargeShiftParameters(std::unordered_map const& pars) { @@ -212,7 +138,7 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13> } f.Close(); } - LOG(info) << "Set the Time Shift parameters from file " << filename << " and object " << objname << " for " << (positive ? "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 positive) { @@ -254,14 +180,12 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13> class TOFResoParamsV3 : public o2::tof::Parameters<13> { public: - TOFResoParamsV3() : Parameters(std::array{"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"}, + 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{0.008, 0.008, 0.002, 40.0, 60.0, - 0.008, 0.008, 0.002, 40.0, - 0.008, 0.008, 0.002, 40.0}); + 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; @@ -313,58 +237,79 @@ class TOFResoParamsV3 : public o2::tof::Parameters<13> } } - // Time shift for post calibration - void setTimeShiftParameters(std::unordered_map const& pars, bool positive) - { - std::string baseOpt = positive ? "TimeShift.Pos." : "TimeShift.Neg."; + // 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; - 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"; + 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); } - 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))); + 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); } - setTimeShiftParameters(&graph, positive); } - void setTimeShiftParameters(std::string const& filename, std::string const& objname, bool positive) + + void setResolutionParametrization(std::unordered_map const& pars) { - TFile f(filename.c_str(), "READ"); - if (f.IsOpen()) { - if (positive) { - f.GetObject(objname.c_str(), gPosEtaTimeCorr); - } else { - f.GetObject(objname.c_str(), gNegEtaTimeCorr); + 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; + } } - f.Close(); } - LOG(info) << "Set the Time Shift parameters from file " << filename << " and object " << objname << " for " << (positive ? "positive" : "negative"); + // 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 setTimeShiftParameters(TGraph* g, bool positive) + + void setResolutionParametrizationRun2(std::unordered_map const& pars); + + template + float getResolution(const float p, const float eta) const { - if (positive) { - gPosEtaTimeCorr = g; - } else { - gNegEtaTimeCorr = g; - } - LOG(info) << "Set the Time Shift parameters from object " << g->GetName() << " " << g->GetTitle() << " for " << (positive ? "positive" : "negative"); + return mResolution[pid]->Eval(p, eta); } - float getTimeShift(float eta, int16_t sign) const + + void printResolution() const { - if (sign > 0) { - if (!gPosEtaTimeCorr) { - return 0.f; + // 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; } - return gPosEtaTimeCorr->Eval(eta); - } - if (!gNegEtaTimeCorr) { - return 0.f; + LOG(info) << "Resolution function for " << particleNames[i] << " is " << mResolution[i]->GetName() << " with formula " << mResolution[i]->GetFormula()->GetExpFormula(); } - return gNegEtaTimeCorr->Eval(eta); + } + void printFullConfig() const + { + print(); + printMomentumChargeShiftParameters(); + printTimeShiftParameters(); + printResolution(); } private: @@ -374,12 +319,121 @@ class TOFResoParamsV3 : public o2::tof::Parameters<13> 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 template class ExpTimes @@ -391,7 +445,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 * std::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 @@ -401,7 +455,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()); } @@ -416,7 +470,7 @@ class ExpTimes return defaultReturnValue; } if (track.trackType() == o2::aod::track::Run2Track) { - return ComputeExpectedTime(track.tofExpMom() * kCSPEDDInv / (1.f + track.sign() * parameters.getMomentumChargeShift(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.getMomentumChargeShift(track.eta())); return ComputeExpectedTime(track.tofExpMom() / (1.f + track.sign() * parameters.getMomentumChargeShift(track.eta())), track.length()) + parameters.getTimeShift(track.eta(), track.sign()); @@ -432,9 +486,14 @@ class ExpTimes static float GetExpectedSigma(const ParamType& parameters, const TrackType& track, const float tofSignal, const float collisionTimeRes) { const float& mom = track.p(); + const float& etaTrack = track.eta(); if (mom <= 0) { return -999.f; } + const float reso = parameters.template getResolution(mom, etaTrack); + 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; diff --git a/Common/Core/PID/PIDTOFParamService.cxx b/Common/Core/PID/PIDTOFParamService.cxx new file mode 100644 index 00000000000..29fe01360fe --- /dev/null +++ b/Common/Core/PID/PIDTOFParamService.cxx @@ -0,0 +1,293 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file PIDTOFParamService.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \since 30/06/2025 +/// \brief Implementation of the TOF PID service for the detector response +/// + +#include "PIDTOFParamService.h" + +#include +#include +#include +#include + +#include +#include + +using namespace o2::framework; + +o2::pid::tof::TOFResoParamsV3 o2::pid::tof::TOFResponseImpl::parameters; +o2::common::core::MetadataHelper o2::pid::tof::TOFResponseImpl::metadataInfo; +bool o2::pid::tof::TOFResponseImpl::mIsInit = false; +int o2::pid::tof::TOFResponseImpl::mLastRunNumber = -1; + +void o2::pid::tof::TOFResponseImpl::inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string task) +{ + if (mIsInit) { + LOG(fatal) << "TOFResponseImpl already initialized, cannot re-initialize"; + } + 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); +} + +void o2::pid::tof::TOFResponseImpl::initSetup(o2::ccdb::BasicCCDBManager* ccdb, + o2::framework::InitContext& initContext) +{ + if (mIsInit) { + LOG(fatal) << "TOFResponseImpl already initialized, cannot re-initialize"; + } + + if (!ccdb) { + LOG(fatal) << "CCDB manager is not set, cannot initialize TOFResponseImpl"; + } + inheritFromBaseTask(initContext); // Gets the configuration parameters from the base task (tof-signal) + mCcdb = ccdb; // Set the CCDB manager + mCcdb->setURL(mUrl); + mCcdb->setTimestamp(mTimestamp); + mCcdb->setCaching(true); + mCcdb->setLocalObjectValidityChecking(); + // Not later than now objects + mCcdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + + mIsInit = true; // Set the initialization flag + + // 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(parameters, 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(parameters, mReconstructionPassDefault)) { + paramCollection.print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { + if (metadataInfo.isRun3()) { + parameters.setResolutionParametrization(paramCollection.getPars(mReconstructionPassDefault)); + } else { + parameters.setResolutionParametrizationRun2(paramCollection.getPars(mReconstructionPassDefault)); + } + parameters.setMomentumChargeShiftParameters(paramCollection.getPars(mReconstructionPassDefault)); + } + } + } else { // Pass is available, load non standard parameters + if (metadataInfo.isRun3()) { + parameters.setResolutionParametrization(paramCollection.getPars(mReconstructionPass)); + } else { + parameters.setResolutionParametrizationRun2(paramCollection.getPars(mReconstructionPass)); + } + parameters.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 = mCcdb->getSpecific(mParametrizationPath, mTimestamp); + if (!paramCollection->retrieveParameters(parameters, 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(parameters, mReconstructionPassDefault)) { + paramCollection->print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { + if (metadataInfo.isRun3()) { + parameters.setResolutionParametrization(paramCollection->getPars(mReconstructionPassDefault)); + } else { + parameters.setResolutionParametrizationRun2(paramCollection->getPars(mReconstructionPassDefault)); + } + parameters.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPassDefault)); + } + } + } else { // Pass is available, load non standard parameters + if (metadataInfo.isRun3()) { + parameters.setResolutionParametrization(paramCollection->getPars(mReconstructionPass)); + } else { + parameters.setResolutionParametrizationRun2(paramCollection->getPars(mReconstructionPass)); + } + parameters.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 << "'"; + parameters.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 << "'"; + mCcdb->setFatalWhenNull(false); + parameters.setTimeShiftParameters(mCcdb->getSpecific(nameShift, mTimestamp, metadata), isPositive); + mCcdb->setFatalWhenNull(true); + } + LOG(info) << " test getTimeShift at 0 " << (isPositive ? "pos" : "neg") << ": " + << parameters.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:"; + parameters.printFullConfig(); +} + +void o2::pid::tof::TOFResponseImpl::processSetup(const int runNumber, const int64_t timeStamp) +{ + LOG(debug) << "Processing setup for run number " << runNumber << " from run " << mLastRunNumber; + // First we check if this run number was already processed + if (mLastRunNumber == runNumber) { + return; + } + LOG(info) << "Updating the parametrization from last run " << mLastRunNumber << " to " << runNumber << " and timestamp from " << mTimestamp << " " << timeStamp; + mLastRunNumber = runNumber; + mTimestamp = timeStamp; + + // Check the beam type + if (mCollisionSystem == o2::common::core::CollisionSystemType::kCollSysUndef) { + o2::parameters::GRPLHCIFData* grpo = mCcdb->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 " << runNumber; + if (mParamFileName.empty()) { // Not loading if parametrization was taken from file + LOG(info) << "Updating parametrization from ccdb"; + const o2::tof::ParameterCollection* paramCollection = mCcdb->getSpecific(mParametrizationPath, mTimestamp); + if (!paramCollection->retrieveParameters(parameters, 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(parameters, mReconstructionPassDefault)) { + paramCollection->print(); + LOG(fatal) << "Cannot get default pass for calibration " << mReconstructionPassDefault; + } else { // Found the default case + if (metadataInfo.isRun3()) { + parameters.setResolutionParametrization(paramCollection->getPars(mReconstructionPassDefault)); + } else { + parameters.setResolutionParametrizationRun2(paramCollection->getPars(mReconstructionPassDefault)); + } + parameters.setMomentumChargeShiftParameters(paramCollection->getPars(mReconstructionPassDefault)); + } + } + } else { // Found the non default case + if (metadataInfo.isRun3()) { + parameters.setResolutionParametrization(paramCollection->getPars(mReconstructionPass)); + } else { + parameters.setResolutionParametrizationRun2(paramCollection->getPars(mReconstructionPass)); + } + parameters.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 << "'"; + mCcdb->setFatalWhenNull(false); + parameters.setTimeShiftParameters(mCcdb->getSpecific(nameShift, mTimestamp, metadata), isPositive); + mCcdb->setFatalWhenNull(true); + LOG(info) << " test getTimeShift at 0 " << (isPositive ? "pos" : "neg") << ": " + << parameters.getTimeShift(0, isPositive); + }; + + updateTimeShift(metadataInfo.isMC() ? mTimeShiftCCDBPathPosMC : mTimeShiftCCDBPathPos, true); + updateTimeShift(metadataInfo.isMC() ? mTimeShiftCCDBPathNegMC : mTimeShiftCCDBPathNeg, false); + + LOG(info) << "Parametrization at setup time:"; + parameters.printFullConfig(); +} + +struct TOFSupport : o2::framework::ServicePlugin { + o2::framework::ServiceSpec* create() final + { + return new ServiceSpec{ + .name = "tof-response", + .init = [](ServiceRegistryRef, DeviceState&, fair::mq::ProgOptions&) -> ServiceHandle { + auto* wrapper = new o2::pid::tof::TOFResponse(); + auto* ptr = new o2::pid::tof::TOFResponseImpl(); + wrapper->setInstance(ptr); + return ServiceHandle{TypeIdHelpers::uniqueId(), wrapper, ServiceKind::Serial, "database-pdg"}; + }, + .configure = CommonServices::noConfiguration(), + .exit = [](ServiceRegistryRef, void* service) { + auto* resp = reinterpret_cast(service); + delete resp; }, + .kind = ServiceKind::Serial}; + } +}; + +DEFINE_DPL_PLUGINS_BEGIN +DEFINE_DPL_PLUGIN_INSTANCE(TOFSupport, CustomService); +DEFINE_DPL_PLUGINS_END diff --git a/Common/Core/PID/PIDTOFParamService.h b/Common/Core/PID/PIDTOFParamService.h new file mode 100644 index 00000000000..73b6a4e0c93 --- /dev/null +++ b/Common/Core/PID/PIDTOFParamService.h @@ -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 PIDTOFParamService.h +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \since 30/06/2025 +/// \brief Implementation of the TOF PID service for the detector response +/// + +#ifndef COMMON_CORE_PID_PIDTOFPARAMSERVICE_H_ +#define COMMON_CORE_PID_PIDTOFPARAMSERVICE_H_ + +#include "Common/Core/CollisionTypeHelper.h" +#include "Common/Core/MetadataHelper.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/TableHelper.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsTOF/ParameterContainers.h" +#include "Framework/DataTypes.h" +#include "Framework/PID.h" +#include "Framework/Plugins.h" +#include "ReconstructionDataFormats/PID.h" + +#include + +namespace o2::pid::tof +{ + +struct TOFResponseImpl { + static o2::pid::tof::TOFResoParamsV3 parameters; // TOF response parameters for the expected resolution + static o2::common::core::MetadataHelper metadataInfo; // Metadata information used for the TOF response + + /// Initialize the TOF response parameters in the init function of each task + /// \param ccdb Pointer to the CCDB manager + /// \param initContext Initialization context + /// \note This function should be called in the init function of each task that uses the TOF response + /// \note The parameters are loaded from the CCDB and stored in the static variable `parameters` + /// \note The metadata information is also initialized in this function + void initSetup(o2::ccdb::BasicCCDBManager* ccdb, o2::framework::InitContext& initContext); + + /// Initialize the TOF response parameters in the init function of each task + /// \param ccdb Service pointer to the CCDB manager + template + void initSetup(T ccdb, o2::framework::InitContext& initContext) + { + initSetup(ccdb.operator->(), initContext); + } + + /// Initialize the TOF response parameters in the process function of each task, should be called only at least once per run + /// \param runNumber Run number for which the calibration is loaded + /// \param timeStamp Timestamp for which the calibration is loaded + /// \note This function should be called in the process function of each task that uses the TOF response + /// \note The parameters are loaded from the CCDB and stored in the static variable `parameters` + /// \note The metadata information is also initialized in this function + void processSetup(const int runNumber, const int64_t timeStamp); + + /// Initialize the TOF response parameters in the process function of each task, should be called only at least once per run + /// \param bc Bunch crossing containing the run number and timestamp for which the calibration is loaded + template + void processSetup(const T& bc) + { + processSetup(bc.runNumber(), bc.timestamp()); + } + + template + static float expectedSigma(const float tofSignal, + const float tofExpMom, + const float momentum, + const float eta, + const float tofEvTimeErr, + const o2::pid::tof::TOFResoParamsV3& params = parameters) + { + if (!mIsInit) { + LOG(fatal) << "TOF response parameters not initialized, call initSetup() first"; + } + if (mLastRunNumber < 0) { + LOG(fatal) << "TOF response parameters not initialized, call processSetup() first"; + } + if (tofSignal <= 0.f) { + // return o2::pid::tof::defaultReturnValue; + } + if (tofExpMom <= 0.f) { + return o2::pid::tof::defaultReturnValue; + } + if (momentum <= 0) { + return o2::pid::tof::defaultReturnValue; + } + const float trackingReso = params.getResolution(momentum, eta); + const float tofReso = params.getParameter(4); + if (trackingReso > 0) { + return std::sqrt(trackingReso * trackingReso + + tofReso * tofReso + + tofEvTimeErr * tofEvTimeErr); + } + constexpr float MassSquared = o2::track::pid_constants::sMasses2[id]; + const float dpp = params.getParameter(0) + + params.getParameter(1) * momentum + + params.getParameter(2) * o2::constants::physics::MassElectron / momentum; + const float sigma = dpp * tofSignal / (1. + momentum * momentum / (MassSquared)); + return std::sqrt(sigma * sigma + + params.getParameter(3) * params.getParameter(3) / momentum / momentum + + tofReso * tofReso + + tofEvTimeErr * tofEvTimeErr); + } + + template + static float expectedSigma(const TrackType& track, const o2::pid::tof::TOFResoParamsV3& params = parameters) + { + return expectedSigma(track.tofSignal(), track.tofExpMom(), track.p(), track.eta(), track.tofEvTimeErr(), params); + } + + template + static float nSigma(const float tofSignal, + const float tofExpMom, + const float length, + const float momentum, + const float eta, + const float tofEvTime, + const float tofEvTimeErr, + const o2::pid::tof::TOFResoParamsV3& params = parameters) + { + if (tofSignal <= 0.f) { + return o2::pid::tof::defaultReturnValue; + } + if (tofExpMom <= 0.f) { + return o2::pid::tof::defaultReturnValue; + } + if (momentum <= 0) { + return o2::pid::tof::defaultReturnValue; + } + + const float resolution = expectedSigma(tofSignal, tofExpMom, momentum, eta, tofEvTimeErr, params); + const float expTime = o2::framework::pid::tof::MassToExpTime(tofExpMom, + length, + o2::track::pid_constants::sMasses2[id]); + const float delta = tofSignal - tofEvTime - expTime; + return delta / resolution; + } + + template + static float nSigma(const TrackType& track, const o2::pid::tof::TOFResoParamsV3& params = parameters) + { + return nSigma(track.tofSignal(), track.tofExpMom(), track.length(), track.p(), track.eta(), track.tofEvTime(), track.tofEvTimeErr(), params); + } + + static bool isInit() { return mIsInit; } //! Get the initialization flag + + // Getters for the configurable options + bool cfgAutoSetProcessFunctions() const { return mAutoSetProcessFunctions; } + o2::common::core::CollisionSystemType::collType cfgCollisionType() const { return mCollisionSystem; } + + private: + void inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string task = "tof-signal"); + + static bool mIsInit; //! Flag to check if the parameters are initialized + static int mLastRunNumber; //! Last run number for which the calibration was loaded + + o2::ccdb::BasicCCDBManager* mCcdb = nullptr; // Pointer to the CCDB manager + + // Configurable options + std::string mUrl = "undefined"; + std::string mPathGrpLhcIf = "undefined"; + int64_t mTimestamp = -1; + std::string mTimeShiftCCDBPathPos = "undefined"; + std::string mTimeShiftCCDBPathNeg = "undefined"; + std::string mTimeShiftCCDBPathPosMC = "undefined"; + std::string mTimeShiftCCDBPathNegMC = "undefined"; + std::string mParamFileName = "undefined"; + std::string mParametrizationPath = "undefined"; + std::string mReconstructionPass = "undefined"; + std::string mReconstructionPassDefault = "undefined"; + bool mFatalOnPassNotAvailable = false; + bool mEnableTimeDependentResponse = false; + o2::common::core::CollisionSystemType::collType mCollisionSystem = o2::common::core::CollisionSystemType::kCollSysUndef; + bool mAutoSetProcessFunctions = false; + + 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"; + } + } +}; + +struct TOFResponse : o2::framework::LoadableServicePlugin { + TOFResponse() : LoadableServicePlugin{"O2PhysicsAnalysisCore:TOFSupport"} + { + } +}; + +} // namespace o2::pid::tof + +#endif // COMMON_CORE_PID_PIDTOFPARAMSERVICE_H_ diff --git a/Common/Core/PID/ParamBase.cxx b/Common/Core/PID/ParamBase.cxx index 74824781d07..e1375b3916c 100644 --- a/Common/Core/PID/ParamBase.cxx +++ b/Common/Core/PID/ParamBase.cxx @@ -17,14 +17,20 @@ /// These are the basic storage elements to be kept in the CCDB /// -#include "PID/ParamBase.h" -#include "Framework/Logger.h" -#include "TFile.h" +#include +#include + +#include +#include + +#include + +#include namespace o2::pid { -void Parameters::SetParameters(const std::vector params) +void Parameters::SetParameters(const std::vector& params) { if (mPar.size() != params.size()) { LOG(fatal) << "Updating parametrization size! Trying to fit a parametrization of size " << params.size() << " into one of size " << mPar.size(); @@ -40,7 +46,7 @@ void Parameters::Print(Option_t* /*options*/) const } }; -void Parameters::LoadParamFromFile(const TString FileName, const TString ParamName) +void Parameters::LoadParamFromFile(const TString& FileName, const TString& ParamName) { TFile f(FileName, "READ"); if (!f.Get(ParamName)) { @@ -66,7 +72,7 @@ void Parametrization::Print(Option_t* options) const mParameters.Print(options); }; -void Parametrization::LoadParamFromFile(const TString FileName, const TString ParamName) +void Parametrization::LoadParamFromFile(const TString& FileName, const TString& ParamName) { TFile f(FileName, "READ"); if (!f.Get(ParamName)) { diff --git a/Common/Core/PID/ParamBase.h b/Common/Core/PID/ParamBase.h index ec4b17083f4..fa9f0749d2a 100644 --- a/Common/Core/PID/ParamBase.h +++ b/Common/Core/PID/ParamBase.h @@ -20,17 +20,20 @@ #ifndef COMMON_CORE_PID_PARAMBASE_H_ #define COMMON_CORE_PID_PARAMBASE_H_ +#include + +#include +#include +#include + +#include +#include + #include // std::copy #include // std::map #include // std::string #include // std::vector -// ROOT includes -#include "TNamed.h" -#include "TFile.h" - -#include "Framework/Logger.h" - namespace o2::pid { /// Variable to use for the pid input/output i.e. float, double et cetera @@ -49,11 +52,11 @@ class Parameters : public TNamed /// 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; @@ -69,11 +72,11 @@ class Parameters : public TNamed /// Setter for the parameter, using a vector /// \param params vector with parameters - void SetParameters(const std::vector params); + void SetParameters(const std::vector& params); /// 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 @@ -85,7 +88,7 @@ class Parameters : public TNamed /// Loader from file /// \param FileName name of the input file /// \param ParamName name of the input object - void LoadParamFromFile(const TString FileName, const TString ParamName); + void LoadParamFromFile(const TString& FileName, const TString& ParamName); /// Getter for the parameters /// \return returns an array of parameters @@ -138,7 +141,7 @@ 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 @@ -164,7 +167,7 @@ class PidParameters : public TNamed /// Loader from file /// \param FileName name of the input file /// \param ParamName name of the input object - void LoadParamFromFile(const TString FileName, const TString ParamName) + void LoadParamFromFile(const TString& FileName, const TString& ParamName) { TFile f(FileName, "READ"); if (!f.Get(ParamName)) { @@ -215,12 +218,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(const 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(const TString& name, const std::vector& params) : TNamed(name, name), mParameters{name + "Parameters", params} {} /// Default destructor ~Parametrization() override = default; @@ -235,7 +238,7 @@ class Parametrization : public TNamed /// Loader from file /// \param FileName name of the input file /// \param ParamName name of the input object - void LoadParamFromFile(const TString FileName, const TString ParamName); + void LoadParamFromFile(const TString& FileName, const TString& ParamName); /// Setter for the parameter at position iparam /// \param iparam index in the array of the parameters diff --git a/Common/Core/PID/TPCPIDResponse.h b/Common/Core/PID/TPCPIDResponse.h index f25e1acd69e..3f2fe069490 100644 --- a/Common/Core/PID/TPCPIDResponse.h +++ b/Common/Core/PID/TPCPIDResponse.h @@ -17,14 +17,15 @@ #ifndef COMMON_CORE_PID_TPCPIDRESPONSE_H_ #define COMMON_CORE_PID_TPCPIDRESPONSE_H_ +#include +#include +#include + +#include + #include -#include #include -#include "Framework/Logger.h" -// O2 includes -#include "ReconstructionDataFormats/PID.h" -#include "Framework/DataTypes.h" -#include "DataFormatsTPC/BetheBlochAleph.h" +#include namespace o2::pid::tpc { @@ -74,12 +75,18 @@ class Response /// Gets the expected resolution of the track template float GetExpectedSigma(const CollisionType& collision, const TrackType& trk, const o2::track::PID::ID id) const; + /// Gets the expected resolution of the track with multTPC explicitly provided + template + float GetExpectedSigmaAtMultiplicity(const long multTPC, const TrackType& trk, const o2::track::PID::ID id) const; /// 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; + // Number of sigmas with respect to expected for MC, defining a tune-on-data signal value, explicit multTPC + template + float GetNumberOfSigmaMCTunedAtMultiplicity(const long multTPC, 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; @@ -116,6 +123,14 @@ inline float Response::GetExpectedSignal(const TrackType& track, const o2::track /// Gets the expected resolution of the measurement template inline float Response::GetExpectedSigma(const CollisionType& collision, const TrackType& track, const o2::track::PID::ID id) const +{ + // use multTPC (legacy behaviour) if multTPC not provided + return Response::GetExpectedSigmaAtMultiplicity(collision.multTPC(), track, id); +} + +/// Gets the expected resolution of the measurement +template +inline float Response::GetExpectedSigmaAtMultiplicity(const long multTPC, const TrackType& track, const o2::track::PID::ID id) const { if (!track.hasTPC()) { return -999.f; @@ -133,7 +148,7 @@ inline float Response::GetExpectedSigma(const CollisionType& collision, const Tr const double dEdx = o2::tpc::BetheBlochAleph(static_cast(bg), mBetheBlochParams[0], mBetheBlochParams[1], mBetheBlochParams[2], mBetheBlochParams[3], mBetheBlochParams[4]) * std::pow(static_cast(o2::track::pid_constants::sCharges[id]), mChargeFactor); const double relReso = GetRelativeResolutiondEdx(p, mass, o2::track::pid_constants::sCharges[id], mResolutionParams[3]); - const std::vector values{1.f / dEdx, track.tgl(), std::sqrt(ncl), relReso, track.signed1Pt(), collision.multTPC() / mMultNormalization}; + const std::vector values{1.f / dEdx, track.tgl(), std::sqrt(ncl), relReso, track.signed1Pt(), multTPC / mMultNormalization}; const float reso = sqrt(pow(mResolutionParams[0], 2) * values[0] + pow(mResolutionParams[1], 2) * (values[2] * mResolutionParams[5]) * pow(values[0] / sqrt(1 + pow(values[1], 2)), mResolutionParams[2]) + values[2] * pow(values[3], 2) + pow(mResolutionParams[4] * values[4], 2) + pow(values[5] * mResolutionParams[6], 2) + pow(values[5] * (values[0] / sqrt(1 + pow(values[1], 2))) * mResolutionParams[7], 2)) * dEdx * mMIP; reso >= 0.f ? resolution = reso : resolution = -999.f; @@ -160,7 +175,13 @@ inline float Response::GetNumberOfSigma(const CollisionType& collision, const Tr 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 Response::GetNumberOfSigmaMCTunedAtMultiplicity(collision.multTPC(), trk, id, mcTunedTPCSignal); +} + +template +inline float Response::GetNumberOfSigmaMCTunedAtMultiplicity(const long multTPC, const TrackType& trk, const o2::track::PID::ID id, float mcTunedTPCSignal) const +{ + if (GetExpectedSigmaAtMultiplicity(multTPC, trk, id) < 0.) { return -999.f; } if (GetExpectedSignal(trk, id) < 0.) { @@ -169,7 +190,7 @@ inline float Response::GetNumberOfSigmaMCTuned(const CollisionType& collision, c if (!trk.hasTPC()) { return -999.f; } - return ((mcTunedTPCSignal - GetExpectedSignal(trk, id)) / GetExpectedSigma(collision, trk, id)); + return ((mcTunedTPCSignal - GetExpectedSignal(trk, id)) / GetExpectedSigmaAtMultiplicity(multTPC, trk, id)); } /// Gets the deviation between the actual signal and the expected signal diff --git a/Common/Core/RecoDecay.h b/Common/Core/RecoDecay.h index f772ba40e09..fcc50d23bf8 100644 --- a/Common/Core/RecoDecay.h +++ b/Common/Core/RecoDecay.h @@ -17,14 +17,20 @@ #ifndef COMMON_CORE_RECODECAY_H_ #define COMMON_CORE_RECODECAY_H_ -#include // std::find -#include // std::array -#include // std::abs, std::sqrt -#include // std::move -#include // std::vector +#include -#include "TMCProcess.h" // for VMC Particle Production Process -#include "CommonConstants/MathConstants.h" +#include // for VMC Particle Production Process +#include // for PDG codes + +#include // std::find +#include // std::array +#include // std::abs, std::sqrt +#include // std::size_t +#include // intX_t +#include // std::apply +#include // std::decay_t +#include // std::move +#include // std::vector /// Base class for calculating properties of reconstructed decays /// @@ -36,11 +42,18 @@ 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 + enum OriginType { + None = 0, + Prompt, + NonPrompt + }; + + static constexpr int8_t StatusCodeAfterFlavourOscillation{92}; // decay products after B0(s) flavour oscillation + static constexpr int PdgQuarkMax{8}; // largest quark PDG code; o2-linter: disable=pdg/explicit-code (t' does not have a named constant.) + static constexpr int PdgBosonMin{PDG_t::kGluon}; // smallest boson (gauge or H) PDG code + static constexpr int PdgBosonMax{37}; // largest boson (gauge or H) PDG code; o2-linter: disable=pdg/explicit-code (H+ does not have a named constant.) + static constexpr int PdgDivisorMeson{100}; // order of magnitude of the meson PDG codes + static constexpr int PdgDivisorBaryon{1000}; // order of magnitude of the baryon PDG codes // Auxiliary functions @@ -103,7 +116,7 @@ struct RecoDecay { /// Calculates scalar product of vectors. /// \note Promotes numbers to double to avoid precision loss in float multiplication. - /// \param N dimension + /// \tparam N dimension /// \param vec1,vec2 vectors /// \return scalar product template @@ -130,7 +143,7 @@ struct RecoDecay { } /// Calculates magnitude squared of a vector. - /// \param N dimension + /// \tparam N dimension /// \param vec vector /// \return magnitude squared template @@ -206,18 +219,23 @@ struct 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 < minimum) { + angle += period; } - while (angle >= min + o2::constants::math::TwoPI) { - angle -= o2::constants::math::TwoPI; + while (angle >= minimum + period) { + angle -= period; } - return (T)angle; + return angle; } /// Calculates cosine of pointing angle. @@ -274,6 +292,19 @@ struct RecoDecay { return static_cast(length) * static_cast(mass) / p(mom); } + /// Calculates proper lifetime times c (pseudoproper decay length) in XY from information on daughter tracks. + /// \param posPV {x, y, z} or {x, y} position of the primary vertex + /// \param posSV {x, y, z} or {x, y} position of the secondary vertex + /// \param mom array of {x, y, z} or {x, y} momentum arrays of the decay products + /// \param mass mass of the decay products + /// \return pseudoproper decay length + template + static double ctXY(const T& posPV, const U& posSV, const std::array, N>& mom, const std::array mass) + { + // c t_xy = l_xy * m c^2 / (pT c) + return distanceXY(posPV, posSV) * m(mom, mass) / std::apply([](const auto&... args) { return pt(args...); }, mom); + } + /// Calculates cosine of θ* (theta star). /// \note Implemented for 2 prongs only. /// \param arrMom array of two 3-momentum arrays @@ -410,7 +441,7 @@ struct RecoDecay { } /// Calculates invariant mass squared from momenta and masses of several particles (prongs). - /// \param N number of prongs + /// \tparam N number of prongs /// \param arrMom array of N 3-momentum arrays /// \param arrMass array of N masses (in the same order as arrMom) /// \return invariant mass squared @@ -418,9 +449,9 @@ struct 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) { + for (std::size_t iMom = 0; iMom < 3; ++iMom) { // o2-linter: disable=magic-number ({x, y, z} coordinates) momTotal[iMom] += arrMom[iProng][iMom]; } // loop over momentum components energyTot += e(arrMom[iProng], arrMass[iProng]); @@ -510,22 +541,23 @@ struct RecoDecay { } /// Finds the mother of an MC particle by looking for the expected PDG code in the mother chain. + /// \tparam acceptFlavourOscillation switch to accept decays where the mother oscillated (e.g. B0 -> B0bar) /// \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 @@ -541,7 +573,7 @@ struct 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 @@ -550,17 +582,17 @@ struct 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; @@ -577,8 +609,8 @@ struct 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; @@ -588,18 +620,18 @@ struct RecoDecay { } /// Gets the complete list of indices of final-state daughters of an MC particle. - /// \param checkProcess switch to accept only decay daughters by checking the production process of MC particles + /// \tparam 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) { @@ -628,12 +660,12 @@ struct 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; } @@ -644,7 +676,7 @@ struct 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; } @@ -652,39 +684,52 @@ struct 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 decays where the mother oscillated (e.g. B0 -> B0bar) + /// \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; } @@ -694,9 +739,9 @@ struct 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].template mcParticle_as(); // 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; } } @@ -706,13 +751,50 @@ struct RecoDecay { if (!arrDaughters[iProng].has_mcParticle()) { return -1; } - auto particleI = arrDaughters[iProng].mcParticle(); // ith daughter particle + auto particleI = arrDaughters[iProng].template mcParticle_as(); // 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 == PDG_t::kMuonMinus && pdgMotherI == PDG_t::kPiPlus) { + // π → μ + nPiToMuLocal++; + particleI = motherI; + } else if (pdgI == PDG_t::kPiPlus && pdgMotherI == PDG_t::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"); @@ -726,21 +808,21 @@ struct 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; } @@ -760,18 +842,18 @@ struct 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; } } @@ -779,64 +861,79 @@ struct 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; } /// Checks whether the MC particle is the expected one. - /// \param checkProcess switch to accept only decay daughters by checking the production process of MC particles + /// \tparam acceptFlavourOscillation switch to accept decays where the mother oscillated (e.g. B0 -> B0bar) + /// \tparam 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 + /// \tparam acceptFlavourOscillation switch to accept decays where the mother oscillated (e.g. B0 -> B0bar) + /// \tparam 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. @@ -856,7 +953,7 @@ struct 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); @@ -869,29 +966,29 @@ struct 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; } } @@ -924,23 +1021,23 @@ struct 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 / PdgDivisorMeson == PDG_t::kCharm || pdgParticle / PdgDivisorBaryon == PDG_t::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) + // we exit immediately if searchUpToQuark is false and the first mother is a quark or a boson (a 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 pdgParticleIMother = std::abs(mother.pdgCode()); // PDG code of the mother + if (pdgParticleIMother <= PdgQuarkMax || (pdgParticleIMother >= PdgBosonMin && pdgParticleIMother <= PdgBosonMax)) { return OriginType::Prompt; } } @@ -951,30 +1048,30 @@ struct RecoDecay { } 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 (idxBhadMothers) { - if (PDGParticleIMother / 100 == 5 || // b mesons - PDGParticleIMother / 1000 == 5) // b baryons + if (pdgParticleIMother / PdgDivisorMeson == PDG_t::kBottom || // b mesons + pdgParticleIMother / PdgDivisorBaryon == PDG_t::kBottom) // b baryons { idxBhadMothers->push_back(iMother); } } - if (PDGParticleIMother == 5) { // b quark + if (pdgParticleIMother == PDG_t::kBottom) { // b quark return OriginType::NonPrompt; } - if (PDGParticleIMother == 4) { // c quark + if (pdgParticleIMother == PDG_t::kCharm) { // c quark return OriginType::Prompt; } } else { if ( - (PDGParticleIMother / 100 == 5 || // b mesons - PDGParticleIMother / 1000 == 5) // b baryons + (pdgParticleIMother / PdgDivisorMeson == PDG_t::kBottom || // b mesons + pdgParticleIMother / PdgDivisorBaryon == PDG_t::kBottom) // b baryons ) { if (idxBhadMothers) { idxBhadMothers->push_back(iMother); @@ -982,8 +1079,8 @@ struct RecoDecay { return OriginType::NonPrompt; } if ( - (PDGParticleIMother / 100 == 4 || // c mesons - PDGParticleIMother / 1000 == 4) // c baryons + (pdgParticleIMother / PdgDivisorMeson == PDG_t::kCharm || // c mesons + pdgParticleIMother / PdgDivisorBaryon == PDG_t::kCharm) // c baryons ) { couldBePrompt = true; } @@ -1002,6 +1099,119 @@ struct 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 / PdgDivisorMeson == PDG_t::kCharm || pdgParticle / PdgDivisorBaryon == PDG_t::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 quark or a boson (a 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 <= PdgQuarkMax || (pdgParticleIMother >= PdgBosonMin && pdgParticleIMother <= PdgBosonMax)) { + // auto PDGPaticle = std::abs(particleMother.pdgCode()); + if ( + (pdgParticle / PdgDivisorMeson == PDG_t::kBottom || // b mesons + pdgParticle / PdgDivisorBaryon == PDG_t::kBottom) // b baryons + ) { + return OriginType::NonPrompt; // beauty + } + if ( + (pdgParticle / PdgDivisorMeson == PDG_t::kCharm || // c mesons + pdgParticle / PdgDivisorBaryon == PDG_t::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 / PdgDivisorMeson == PDG_t::kBottom || // b mesons + pdgParticleIMother / PdgDivisorBaryon == PDG_t::kBottom) // b baryons + { + idxBhadMothers->push_back(iMother); + } + } + if (pdgParticleIMother == PDG_t::kBottom) { // b quark + return OriginType::NonPrompt; // beauty + } + if (pdgParticleIMother == PDG_t::kCharm) { // c quark + return OriginType::Prompt; // charm + } + } else { + if ( + (pdgParticleIMother / PdgDivisorMeson == PDG_t::kBottom || // b mesons + pdgParticleIMother / PdgDivisorBaryon == PDG_t::kBottom) // b baryons + ) { + if (idxBhadMothers) { + idxBhadMothers->push_back(iMother); + } + return OriginType::NonPrompt; // beauty + } + if ( + (pdgParticleIMother / PdgDivisorMeson == PDG_t::kCharm || // c mesons + pdgParticleIMother / PdgDivisorBaryon == PDG_t::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) @@ -1211,41 +1421,41 @@ struct RecoDecayPtEtaPhiBase { 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]); - } + // /// 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 diff --git a/Common/Core/TPCVDriftManager.h b/Common/Core/TPCVDriftManager.h new file mode 100644 index 00000000000..3219b6189a0 --- /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 +#include +#include +#include +#include +#include + +#include +#include + +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/TableHelper.cxx b/Common/Core/TableHelper.cxx index 4af58f00428..acd09e49c31 100644 --- a/Common/Core/TableHelper.cxx +++ b/Common/Core/TableHelper.cxx @@ -17,16 +17,17 @@ #include "Common/Core/TableHelper.h" -#include +#include +#include +#include -#include "Framework/InitContext.h" -#include "Framework/RunningWorkflowInfo.h" +#include /// Function to print the table required in the full workflow /// @param initContext initContext of the init function -void printTablesInWorkflow(o2::framework::InitContext& initContext) +void o2::common::core::printTablesInWorkflow(o2::framework::InitContext& initContext) { - auto& workflows = initContext.services().get(); + const auto& workflows = initContext.services().get(); for (auto const& device : workflows.devices) { for (auto const& input : device.inputs) { LOG(info) << "Table: " << input.matcher.binding << " in device: " << device.name; @@ -37,11 +38,11 @@ void printTablesInWorkflow(o2::framework::InitContext& initContext) /// Function to check if a table is required in a workflow /// @param initContext initContext of the init function /// @param table name of the table to check for -bool isTableRequiredInWorkflow(o2::framework::InitContext& initContext, const std::string& table) +bool o2::common::core::isTableRequiredInWorkflow(o2::framework::InitContext& initContext, const std::string& table) { LOG(debug) << "Checking if table " << table << " is needed"; bool tableNeeded = false; - auto& workflows = initContext.services().get(); + const auto& workflows = initContext.services().get(); for (auto const& device : workflows.devices) { for (auto const& input : device.inputs) { if (input.matcher.binding == table) { @@ -57,7 +58,7 @@ bool isTableRequiredInWorkflow(o2::framework::InitContext& initContext, const st /// @param initContext initContext of the init function /// @param table name of the table to check for /// @param flag bool value of flag to set, if the given value is true it will be kept, disregarding the table usage in the workflow. -void enableFlagIfTableRequired(o2::framework::InitContext& initContext, const std::string& table, bool& flag) +void o2::common::core::enableFlagIfTableRequired(o2::framework::InitContext& initContext, const std::string& table, bool& flag) { if (flag) { LOG(info) << "Table enabled: " + table; @@ -75,7 +76,7 @@ void enableFlagIfTableRequired(o2::framework::InitContext& initContext, const st /// @param initContext initContext of the init function /// @param table name of the table to check for /// @param flag int value of flag to set, only if initially set to -1. Initial values of 0 or 1 will be kept disregarding the table usage in the workflow. -void enableFlagIfTableRequired(o2::framework::InitContext& initContext, const std::string& table, int& flag) +void o2::common::core::enableFlagIfTableRequired(o2::framework::InitContext& initContext, const std::string& table, int& flag) { if (flag > 0) { flag = 1; diff --git a/Common/Core/TableHelper.h b/Common/Core/TableHelper.h index a5935c558f3..af5df6a7b0a 100644 --- a/Common/Core/TableHelper.h +++ b/Common/Core/TableHelper.h @@ -18,10 +18,16 @@ #ifndef COMMON_CORE_TABLEHELPER_H_ #define COMMON_CORE_TABLEHELPER_H_ +#include +#include +#include +#include +#include + #include -#include "Framework/InitContext.h" -#include "Framework/RunningWorkflowInfo.h" +namespace o2::common::core +{ /// Function to print the table required in the full workflow /// @param initContext initContext of the init function @@ -66,7 +72,7 @@ bool getTaskOptionValue(o2::framework::InitContext& initContext, const std::stri if (verbose) { LOG(info) << "Checking for option '" << optName << "' in task '" << taskName << "'"; } - auto& workflows = initContext.services().get(); + const auto& workflows = initContext.services().get(); int deviceCounter = 0; bool found = false; for (auto const& device : workflows.devices) { @@ -75,14 +81,16 @@ bool getTaskOptionValue(o2::framework::InitContext& initContext, const std::stri } if (device.name == taskName) { // Found the mother task int optionCounter = 0; - for (auto const& option : device.options) { + for (const o2::framework::ConfigParamSpec& option : device.options) { if (verbose) { - LOG(info) << " Option " << optionCounter++ << " " << option.name << " = '" << option.defaultValue.asString() << "'"; + LOG(info) << " Option " << optionCounter++ << " " << option.name << " of type " << static_cast(option.type) << " = '" << option.defaultValue.asString() << "'"; } if (option.name == optName) { value = option.defaultValue.get(); if (verbose) { - LOG(info) << " Found option '" << optName << "' with value '" << value << "'"; + if constexpr (!std::is_same_v>) { + LOG(info) << " Found option '" << optName << "' with value '" << value << "'"; + } found = true; } else { return true; @@ -95,4 +103,22 @@ bool getTaskOptionValue(o2::framework::InitContext& initContext, const std::stri return false; } +/// Function to check for a specific configurable from another task in the current workflow and fetch its value. Useful for tasks that need to know the value of a configurable in another task. +/// @param initContext initContext of the init function +/// @param taskName name of the task to check for +/// @param value Task configurable to inherit from (name and values are used) +/// @param verbose if true, print debug messages +template +bool getTaskOptionValue(o2::framework::InitContext& initContext, const std::string& taskName, ValueType& configurable, const bool verbose = true) +{ + return getTaskOptionValue(initContext, taskName, configurable.name, configurable.value, verbose); +} + +} // namespace o2::common::core + +using o2::common::core::enableFlagIfTableRequired; +using o2::common::core::getTaskOptionValue; +using o2::common::core::isTableRequiredInWorkflow; +using o2::common::core::printTablesInWorkflow; + #endif // COMMON_CORE_TABLEHELPER_H_ diff --git a/Common/Core/TrackSelection.cxx b/Common/Core/TrackSelection.cxx index 4cc355b57ce..6fe7a2e162b 100644 --- a/Common/Core/TrackSelection.cxx +++ b/Common/Core/TrackSelection.cxx @@ -13,9 +13,18 @@ // Class for track selection // -#include "Framework/Logger.h" #include "Common/Core/TrackSelection.h" +#include +#include + +#include +#include +#include +#include +#include +#include + bool TrackSelection::FulfillsITSHitRequirements(uint8_t itsClusterMap) const { constexpr uint8_t bit = 1; @@ -30,7 +39,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 +88,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; @@ -162,7 +176,7 @@ void TrackSelection::print() const LOG(info) << mCutNames[i] << " == " << mRequireITSRefit; break; case TrackCuts::kITSHits: - for (auto& itsRequirement : mRequiredITSHits) { + for (const auto& itsRequirement : mRequiredITSHits) { LOG(info) << mCutNames[i] << " == " << itsRequirement.first; } break; @@ -175,6 +189,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 618124f638f..5f8590cb85f 100644 --- a/Common/Core/TrackSelection.h +++ b/Common/Core/TrackSelection.h @@ -16,13 +16,17 @@ #ifndef COMMON_CORE_TRACKSELECTION_H_ #define COMMON_CORE_TRACKSELECTION_H_ +#include + +#include + +#include +#include +#include #include -#include -#include #include -#include "Framework/Logger.h" -#include "Framework/DataTypes.h" -#include "Rtypes.h" +#include +#include class TrackSelection { @@ -45,6 +49,7 @@ class TrackSelection kGoldenChi2, kDCAxy, kDCAz, + kTPCFracSharedCls, kNCuts }; @@ -114,6 +119,9 @@ class TrackSelection if (!IsSelected(track, TrackCuts::kDCAz)) { return false; } + if (!IsSelected(track, TrackCuts::kTPCFracSharedCls)) { + return false; + } return true; } @@ -144,6 +152,7 @@ class TrackSelection setFlag(TrackCuts::kGoldenChi2); setFlag(TrackCuts::kDCAxy); setFlag(TrackCuts::kDCAz); + setFlag(TrackCuts::kTPCFracSharedCls); return flag; } @@ -195,10 +204,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; @@ -225,6 +236,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; @@ -250,6 +262,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 1974b7df38f..e8476db5e17 100644 --- a/Common/Core/TrackSelectionDefaults.cxx +++ b/Common/Core/TrackSelectionDefaults.cxx @@ -15,10 +15,15 @@ /// \since 20-10-2020 /// -#include "Framework/DataTypes.h" -#include "Common/Core/TrackSelection.h" #include "TrackSelectionDefaults.h" +#include "Common/Core/TrackSelection.h" + +#include +#include + +#include + // Default track selection requiring one hit in the SPD TrackSelection getGlobalTrackSelection() { @@ -120,12 +125,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/TrackSelectionDefaults.h b/Common/Core/TrackSelectionDefaults.h index 72c666456ae..aaa1ef3644f 100644 --- a/Common/Core/TrackSelectionDefaults.h +++ b/Common/Core/TrackSelectionDefaults.h @@ -18,7 +18,6 @@ #ifndef COMMON_CORE_TRACKSELECTIONDEFAULTS_H_ #define COMMON_CORE_TRACKSELECTIONDEFAULTS_H_ -#include "Framework/DataTypes.h" #include "Common/Core/TrackSelection.h" // Default track selection requiring one hit in the SPD diff --git a/Common/Core/TrackSelectorPID.h b/Common/Core/TrackSelectorPID.h index e09969ba946..e8ceaa4fa07 100644 --- a/Common/Core/TrackSelectorPID.h +++ b/Common/Core/TrackSelectorPID.h @@ -17,10 +17,13 @@ #ifndef COMMON_CORE_TRACKSELECTORPID_H_ #define COMMON_CORE_TRACKSELECTORPID_H_ +#include +#include +#include + #include -#include "Framework/Logger.h" -#include "ReconstructionDataFormats/PID.h" +#include /// Class for track selection using PID detectors @@ -34,13 +37,16 @@ struct TrackSelectorPID { }; }; -template +template class TrackSelectorPidBase { public: /// Default constructor TrackSelectorPidBase() = default; + static constexpr float NSigmaMinDefault{-999.f}; + static constexpr float NSigmaMaxDefault{999.f}; + /// Conversion operator template operator TrackSelectorPidBase() const @@ -103,32 +109,40 @@ 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 = NSigmaMinDefault) { // Accept if selection is disabled via large values. - if (mNSigmaTpcMin < -999. && mNSigmaTpcMax > 999.) { + if (mNSigmaTpcMin < NSigmaMinDefault && mNSigmaTpcMax > NSigmaMaxDefault) { return true; } // Get nσ for a given particle hypothesis. double nSigma = 100.; - if constexpr (pdg == kElectron) { + if constexpr (pdg == PDG_t::kElectron) { nSigma = track.tpcNSigmaEl(); - } else if constexpr (pdg == kMuonMinus) { + } else if constexpr (pdg == PDG_t::kMuonMinus) { nSigma = track.tpcNSigmaMu(); - } else if constexpr (pdg == kPiPlus) { + } else if constexpr (pdg == PDG_t::kPiPlus) { nSigma = track.tpcNSigmaPi(); - } else if constexpr (pdg == kKPlus) { + } else if constexpr (pdg == PDG_t::kKPlus) { nSigma = track.tpcNSigmaKa(); - } else if constexpr (pdg == kProton) { + } else if constexpr (pdg == PDG_t::kProton) { nSigma = track.tpcNSigmaPr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { + nSigma = track.tpcNSigmaDe(); } else { errorPdg(); } - if (mNSigmaTpcMinCondTof < -999. && mNSigmaTpcMaxCondTof > 999.) { + /// use custom TPC nσ, if a valid value is provided + if (tpcNSigmaCustom > NSigmaMinDefault) { + nSigma = tpcNSigmaCustom; + } + + if (mNSigmaTpcMinCondTof < NSigmaMinDefault && mNSigmaTpcMaxCondTof > NSigmaMaxDefault) { conditionalTof = true; } else { conditionalTof = mNSigmaTpcMinCondTof <= nSigma && nSigma <= mNSigmaTpcMaxCondTof; @@ -140,13 +154,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 = NSigmaMinDefault) { 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,32 +205,40 @@ 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 = NSigmaMinDefault) { // Accept if selection is disabled via large values. - if (mNSigmaTofMin < -999. && mNSigmaTofMax > 999.) { + if (mNSigmaTofMin < NSigmaMinDefault && mNSigmaTofMax > NSigmaMaxDefault) { return true; } // Get nσ for a given particle hypothesis. double nSigma = 100.; - if constexpr (pdg == kElectron) { + if constexpr (pdg == PDG_t::kElectron) { nSigma = track.tofNSigmaEl(); - } else if constexpr (pdg == kMuonMinus) { + } else if constexpr (pdg == PDG_t::kMuonMinus) { nSigma = track.tofNSigmaMu(); - } else if constexpr (pdg == kPiPlus) { + } else if constexpr (pdg == PDG_t::kPiPlus) { nSigma = track.tofNSigmaPi(); - } else if constexpr (pdg == kKPlus) { + } else if constexpr (pdg == PDG_t::kKPlus) { nSigma = track.tofNSigmaKa(); - } else if constexpr (pdg == kProton) { + } else if constexpr (pdg == PDG_t::kProton) { nSigma = track.tofNSigmaPr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { + nSigma = track.tofNSigmaDe(); } else { errorPdg(); } - if (mNSigmaTofMinCondTpc < -999. && mNSigmaTofMaxCondTpc > 999.) { + /// use custom TOF nσ, if a valid value is provided + if (tofNSigmaCustom > NSigmaMinDefault) { + nSigma = tofNSigmaCustom; + } + + if (mNSigmaTofMinCondTpc < NSigmaMinDefault && mNSigmaTofMaxCondTpc > NSigmaMaxDefault) { conditionalTpc = true; } else { conditionalTpc = mNSigmaTofMinCondTpc <= nSigma && nSigma <= mNSigmaTofMaxCondTpc; @@ -228,13 +250,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 = NSigmaMinDefault) { 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 @@ -287,27 +309,27 @@ class TrackSelectorPidBase bool isSelectedByRich(const T& track, bool& conditionalTof) { // Accept if selection is disabled via large values. - if (mNSigmaRichMin < -999. && mNSigmaRichMax > 999.) { + if (mNSigmaRichMin < NSigmaMinDefault && mNSigmaRichMax > NSigmaMaxDefault) { return true; } // Get nσ for a given particle hypothesis. double nSigma = 100.; - if constexpr (pdg == kElectron) { + if constexpr (pdg == PDG_t::kElectron) { nSigma = track.rich().richNsigmaEl(); - } else if constexpr (pdg == kMuonMinus) { + } else if constexpr (pdg == PDG_t::kMuonMinus) { nSigma = track.rich().richNsigmaMu(); - } else if constexpr (pdg == kPiPlus) { + } else if constexpr (pdg == PDG_t::kPiPlus) { nSigma = track.rich().richNsigmaPi(); - } else if constexpr (pdg == kKPlus) { + } else if constexpr (pdg == PDG_t::kKPlus) { nSigma = track.rich().richNsigmaKa(); - } else if constexpr (pdg == kProton) { + } else if constexpr (pdg == PDG_t::kProton) { nSigma = track.rich().richNsigmaPr(); } else { errorPdg(); } - if (mNSigmaRichMinCondTof < -999. && mNSigmaRichMaxCondTof > 999.) { + if (mNSigmaRichMinCondTof < NSigmaMinDefault && mNSigmaRichMaxCondTof > NSigmaMaxDefault) { conditionalTof = true; } else { conditionalTof = mNSigmaRichMinCondTof <= nSigma && nSigma <= mNSigmaRichMaxCondTof; @@ -342,7 +364,7 @@ class TrackSelectorPidBase template bool isValidForMid(const T& track) { - if constexpr (pdg == kMuonMinus) { + if constexpr (pdg == PDG_t::kMuonMinus) { return track.midId() > -1; } else { errorPdg(); @@ -356,7 +378,7 @@ class TrackSelectorPidBase template bool isSelectedByMid(const T& track) { - if constexpr (pdg == kMuonMinus) { + if constexpr (pdg == PDG_t::kMuonMinus) { return track.mid().midIsMuon() == 1; // FIXME: change to return track.midIsMuon() once the column is bool. } else { errorPdg(); @@ -370,7 +392,7 @@ class TrackSelectorPidBase template TrackSelectorPID::Status statusMid(const T& track) { - if constexpr (pdg == kMuonMinus) { + if constexpr (pdg == PDG_t::kMuonMinus) { if (!isValidForMid(track)) { return TrackSelectorPID::NotApplicable; } @@ -391,10 +413,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 = NSigmaMinDefault, float tofNSigmaCustom = NSigmaMinDefault) { - 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 +434,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 = NSigmaMinDefault, float tofNSigmaCustom = NSigmaMinDefault) { 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) { @@ -450,23 +472,29 @@ class TrackSelectorPidBase template bool isElectronAndNotPion(const T& track, bool useTof = true, bool useRich = true) { + constexpr float NSigmaInvalid{-1000.f}; + constexpr float PTofRichTElectronMin{0.4f}; + constexpr float PTofRichTElectronMax{0.6f}; + constexpr float PRichPionBandMin{1.0f}; + constexpr float PRichPionBandMax{2.0f}; + bool isSelTof = false; bool isSelRich = false; bool hasRich = track.richId() > -1; bool hasTof = isValidForTof(track); auto nSigmaTofEl = track.tofNSigmaEl(); auto nSigmaTofPi = track.tofNSigmaPi(); - auto nSigmaRichEl = hasRich ? track.rich().richNsigmaEl() : -1000.; - auto nSigmaRichPi = hasRich ? track.rich().richNsigmaPi() : -1000.; + auto nSigmaRichEl = hasRich ? track.rich().richNsigmaEl() : NSigmaInvalid; + auto nSigmaRichPi = hasRich ? track.rich().richNsigmaPi() : NSigmaInvalid; auto p = track.p(); // TOF - if (useTof && hasTof && (p < 0.6)) { - if (p > 0.4 && hasRich) { + if (useTof && hasTof && (p < PTofRichTElectronMax)) { + if (p > PTofRichTElectronMin && hasRich) { if ((std::abs(nSigmaTofEl) < mNSigmaTofMax) && (std::abs(nSigmaRichEl) < mNSigmaRichMax)) { isSelTof = true; // is selected as electron by TOF and RICH } - } else if (p <= 0.4) { + } else if (p <= PTofRichTElectronMin) { if (std::abs(nSigmaTofEl) < mNSigmaTofMax) { isSelTof = true; // is selected as electron by TOF } @@ -485,7 +513,7 @@ class TrackSelectorPidBase if (std::abs(nSigmaRichEl) < mNSigmaRichMax) { isSelRich = true; // is selected as electron by RICH } - if ((std::abs(nSigmaRichPi) < mNSigmaRichMax) && (p > 1.0) && (p < 2.0)) { + if ((std::abs(nSigmaRichPi) < mNSigmaRichMax) && (p > PRichPionBandMin) && (p < PRichPionBandMax)) { isSelRich = false; // is selected as pion by RICH } } else { @@ -527,16 +555,18 @@ class TrackSelectorPidBase bool isSelectedByBayes(const T& track) { // Get index of the most probable species for a given track. - if constexpr (pdg == kElectron) { + if constexpr (pdg == PDG_t::kElectron) { return track.bayesID() == o2::track::PID::Electron; - } else if constexpr (pdg == kMuonMinus) { + } else if constexpr (pdg == PDG_t::kMuonMinus) { return track.bayesID() == o2::track::PID::Muon; - } else if constexpr (pdg == kPiPlus) { + } else if constexpr (pdg == PDG_t::kPiPlus) { return track.bayesID() == o2::track::PID::Pion; - } else if constexpr (pdg == kKPlus) { + } else if constexpr (pdg == PDG_t::kKPlus) { return track.bayesID() == o2::track::PID::Kaon; - } else if constexpr (pdg == kProton) { + } else if constexpr (pdg == PDG_t::kProton) { return track.bayesID() == o2::track::PID::Proton; + } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { + return track.bayesID() == o2::track::PID::Deuteron; } else { errorPdg(); return false; @@ -555,16 +585,18 @@ class TrackSelectorPidBase // Get probability for a given particle hypothesis. double prob = 0.; - if constexpr (pdg == kElectron) { + if constexpr (pdg == PDG_t::kElectron) { prob = track.bayesEl(); - } else if constexpr (pdg == kMuonMinus) { + } else if constexpr (pdg == PDG_t::kMuonMinus) { prob = track.bayesMu(); - } else if constexpr (pdg == kPiPlus) { + } else if constexpr (pdg == PDG_t::kPiPlus) { prob = track.bayesPi(); - } else if constexpr (pdg == kKPlus) { + } else if constexpr (pdg == PDG_t::kKPlus) { prob = track.bayesKa(); - } else if constexpr (pdg == kProton) { + } else if constexpr (pdg == PDG_t::kProton) { prob = track.bayesPr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { + prob = track.bayesDe(); } else { errorPdg(); } @@ -642,10 +674,11 @@ class TrackSelectorPidBase }; // Predefined types -using TrackSelectorEl = TrackSelectorPidBase; // El -using TrackSelectorMu = TrackSelectorPidBase; // Mu -using TrackSelectorPi = TrackSelectorPidBase; // Pi -using TrackSelectorKa = TrackSelectorPidBase; // Ka -using TrackSelectorPr = TrackSelectorPidBase; // Pr +using TrackSelectorEl = TrackSelectorPidBase; // El +using TrackSelectorMu = TrackSelectorPidBase; // Mu +using TrackSelectorPi = TrackSelectorPidBase; // Pi +using TrackSelectorKa = TrackSelectorPidBase; // Ka +using TrackSelectorPr = TrackSelectorPidBase; // Pr +using TrackSelectorDe = TrackSelectorPidBase; // De #endif // COMMON_CORE_TRACKSELECTORPID_H_ diff --git a/EventFiltering/Zorro.cxx b/Common/Core/Zorro.cxx similarity index 51% rename from EventFiltering/Zorro.cxx rename to Common/Core/Zorro.cxx index 2cb74831d72..cf830cf5c22 100644 --- a/EventFiltering/Zorro.cxx +++ b/Common/Core/Zorro.cxx @@ -12,13 +12,31 @@ #include "Zorro.h" -#include -#include +#include "Common/Core/ZorroHelper.h" + +#include +#include +#include +#include +#include +#include +#include +#include -#include +#include +#include +#include -#include "CCDB/BasicCCDBManager.h" -#include "CommonDataFormat/InteractionRecord.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include using o2::InteractionRecord; @@ -56,6 +74,7 @@ void Zorro::populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, 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)); @@ -64,6 +83,7 @@ void Zorro::populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, } 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)); @@ -72,6 +92,7 @@ void Zorro::populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, } 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)); @@ -89,6 +110,73 @@ void Zorro::populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, 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) { @@ -97,47 +185,45 @@ std::vector Zorro::initCCDB(o2::ccdb::BasicCCDBManager* ccdb, int runNumber mCCDB = ccdb; mRunNumber = runNumber; mBCtolerance = bcRange; - std::map metadata; - metadata["runNumber"] = std::to_string(runNumber); - mScalers = mCCDB->getSpecific(mBaseCCDBPath + "FilterCounters", timestamp, metadata); - mSelections = mCCDB->getSpecific(mBaseCCDBPath + "SelectionCounters", timestamp, metadata); - mInspectedTVX = mCCDB->getSpecific(mBaseCCDBPath + "InspectedTVX", timestamp, metadata); - mZorroHelpers = mCCDB->getSpecific>(mBaseCCDBPath + "ZorroHelpers", timestamp, metadata); - 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); - + auto ctp = ccdb->getForRun>("CTP/Calib/OrbitReset", runNumber, false); + mOrbitResetTimestamp = (*ctp)[0]; + mScalers = mCCDB->getForRun(mBaseCCDBPath + "FilterCounters", runNumber, true); + mSelections = mCCDB->getForRun(mBaseCCDBPath + "SelectionCounters", runNumber, true); + mInspectedTVX = mCCDB->getForRun(mBaseCCDBPath + "InspectedTVX", runNumber, true); + 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); + std::vector tokens = o2::utils::Str::tokenize(tois, ','); // tokens are trimmed + for (auto const& token : tokens) { 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); + mATcounts.resize(mSelections->GetNbinsX() - 2, 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(), mTOIs); + 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 + static_cast(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; @@ -150,8 +236,11 @@ std::bitset<128> Zorro::fetch(uint64_t bcGlobalId, uint64_t tolerance) 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); + if (!mAccountedBCranges[i]) { + mATcounts[iMask * 64 + iTOI]++; + if (mAnalysedTriggers) { + mAnalysedTriggers->Fill(iMask * 64 + iTOI); + } } } } @@ -167,20 +256,70 @@ std::bitset<128> Zorro::fetch(uint64_t bcGlobalId, uint64_t tolerance) return mLastResult; } -bool Zorro::isSelected(uint64_t bcGlobalId, uint64_t tolerance) +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); } - return true; + retVal = true; } } - return false; + 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 (const 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/Common/Core/Zorro.h similarity index 60% rename from EventFiltering/Zorro.h rename to Common/Core/Zorro.h index 65cc7c45090..f5cb580061a 100644 --- a/EventFiltering/Zorro.h +++ b/Common/Core/Zorro.h @@ -9,21 +9,31 @@ // 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 + +/// +/// \file Zorro.h +/// \brief Zero Obstacles Results Retriever for Offline trigger selections +/// \author M Puccio +/// #ifndef EVENTFILTERING_ZORRO_H_ #define EVENTFILTERING_ZORRO_H_ +#include "ZorroHelper.h" +#include "ZorroSummary.h" + +#include +#include + +#include +#include + #include -#include +#include #include +#include #include -#include "TH1D.h" -#include "CommonDataFormat/IRFrame.h" -#include "Framework/HistogramRegistry.h" -#include "ZorroHelper.h" - namespace o2 { namespace ccdb @@ -38,25 +48,39 @@ class Zorro 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); + 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 getATcounters() const { return mATcounts; } + std::vector getTriggerOfInterestResults(uint64_t bcGlobalId, uint64_t tolerance = 100); + std::vector getTriggerOfInterestResults() const; + int getNTOIs() const { return mTOIs.size(); } - void setCCDBpath(std::string path) { mBaseCCDBPath = path; } - void setBaseCCDBPath(std::string path) { mBaseCCDBPath = path; } + void setCCDBpath(const std::string& path) { mBaseCCDBPath = path; } + void setBaseCCDBPath(const std::string& path) { mBaseCCDBPath = path; } void setBCtolerance(int tolerance) { mBCtolerance = tolerance; } + ZorroSummary* getZorroSummary() { return &mZorroSummary; } + private: - std::string mBaseCCDBPath = "Users/m/mpuccio/EventFiltering/OTS/"; + void setupHelpers(int64_t timestamp); + + ZorroSummary mZorroSummary{"ZorroSummary", "ZorroSummary"}; + + std::string mBaseCCDBPath = "EventFiltering/Zorro/"; int mRunNumber = 0; - TH1* mAnalysedTriggers; /// Accounting for all triggers in the current run - TH1* mAnalysedTriggersOfInterest; /// Accounting for triggers of interest in the current run + std::pair mRunDuration; + int64_t mOrbitResetTimestamp = 0; + TH1* mAnalysedTriggers = nullptr; /// Accounting for all triggers in the current run + TH1* mAnalysedTriggersOfInterest = nullptr; /// Accounting for triggers of interest in the current run std::vector mRunNumberHistos; std::vector mAnalysedTriggersList; /// Per run histograms @@ -75,6 +99,7 @@ class Zorro std::vector mTOIs; std::vector mTOIidx; std::vector mTOIcounts; + std::vector mATcounts; o2::ccdb::BasicCCDBManager* mCCDB = nullptr; }; diff --git a/EventFiltering/ZorroHelper.h b/Common/Core/ZorroHelper.h similarity index 94% rename from EventFiltering/ZorroHelper.h rename to Common/Core/ZorroHelper.h index 8bcc6240bc0..e80a07ef994 100644 --- a/EventFiltering/ZorroHelper.h +++ b/Common/Core/ZorroHelper.h @@ -13,7 +13,8 @@ #ifndef EVENTFILTERING_ZORROHELPER_H_ #define EVENTFILTERING_ZORROHELPER_H_ -#include "Rtypes.h" +#include +#include struct ZorroHelper { ULong64_t bcAOD, bcEvSel, trigMask[2], selMask[2]; diff --git a/Common/Core/ZorroSummary.cxx b/Common/Core/ZorroSummary.cxx new file mode 100644 index 00000000000..0a1012c3edc --- /dev/null +++ b/Common/Core/ZorroSummary.cxx @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 +#include + +#include + +#include + +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 (std::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; +} diff --git a/Common/Core/ZorroSummary.h b/Common/Core/ZorroSummary.h new file mode 100644 index 00000000000..51019aeef18 --- /dev/null +++ b/Common/Core/ZorroSummary.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. +// + +#ifndef EVENTFILTERING_ZORROSUMMARY_H_ +#define EVENTFILTERING_ZORROSUMMARY_H_ + +#include + +#include +#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::vector& toinames) + { + mNtois = ntois; + if (toinames.size() == 0) { + return; + } + mTOInames = toinames[0]; + for (size_t i = 1; i < toinames.size(); i++) { + mTOInames += "," + toinames[i]; + } + } + void setupRun(int runNumber, double tvxCountes, const std::vector& toiCounters) + { + if (mRunNumber == runNumber) { + return; + } + mRunNumber = runNumber; + mTVXcounters[runNumber] = tvxCountes; + mTOIcounters[runNumber] = toiCounters; + mAnalysedTOIcounters.try_emplace(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)++; + } + + const auto& 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_ diff --git a/Common/Core/fwdtrackUtilities.h b/Common/Core/fwdtrackUtilities.h new file mode 100644 index 00000000000..14bc744e634 --- /dev/null +++ b/Common/Core/fwdtrackUtilities.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 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 "DetectorsBase/GeometryManager.h" +#include "Field/MagneticField.h" +#include "Framework/AnalysisDataModel.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MCHTracking/TrackExtrap.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "ReconstructionDataFormats/TrackFwd.h" + +#include "Math/MatrixRepresentationsStatic.h" +#include "Math/SMatrix.h" +#include "TGeoGlobalMagField.h" + +#include +#include + +namespace o2::aod +{ +namespace fwdtrackutils +{ +// Index used to set different options for muon propagation +enum class propagationPoint : int { + kToVertex = 0, + kToDCA = 1, + kToRabs = 2, + kToMatchingPlane = 3, +}; +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix55Std = ROOT::Math::SMatrix; +using SMatrix5 = ROOT::Math::SVector; + +template +o2::track::TrackParCovFwd getTrackParCovFwd(TFwdTrack const& track, TFwdTrackCov const& cov) +{ + // This function works for (glMuon, glMuon), (saMuon, saMuon) and (MFTTrack, MFTTrackCov). + + double chi2 = track.chi2(); + if constexpr (std::is_same_v, aod::MFTTracksCov::iterator>) { + chi2 = track.chi2(); + } else { + if (track.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + chi2 = track.chi2(); + } else if (track.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + chi2 = track.chi2() * (2.f * track.nClusters() - 5.f); + } + } + + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), + cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), + cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; // this is chi2! Not chi2/ndf. + v1.clear(); + v1.shrink_to_fit(); + return trackparCov; +} + +/// propagate fwdtrack to a certain point. +template +o2::dataformats::GlobalFwdTrack propagateMuon(TFwdTrack const& muon, TFwdTrackCov const& cov, TCollision const& collision, const propagationPoint endPoint, const float matchingZ, const float bzkG) +{ + o2::track::TrackParCovFwd trackParCovFwd; + if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + trackParCovFwd = getTrackParCovFwd(muon, cov); + } else if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + trackParCovFwd = getTrackParCovFwd(muon, muon); + } else { + trackParCovFwd = getTrackParCovFwd(muon, muon); + } + + o2::dataformats::GlobalFwdTrack propmuon = propagateTrackParCovFwd(trackParCovFwd, muon.trackType(), collision, endPoint, matchingZ, bzkG); + return propmuon; +} + +template +o2::dataformats::GlobalFwdTrack propagateTrackParCovFwd(TFwdTrackParCov const& fwdtrackORG, uint8_t trackType, TCollision const& collision, const propagationPoint endPoint, const float matchingZ, const float bzkG) +{ + // TFwdTrackParCov is o2::track::TrackParCovFwd + + o2::track::TrackParCovFwd fwdtrack(fwdtrackORG); + o2::dataformats::GlobalFwdTrack propmuon; + o2::globaltracking::MatchGlobalFwd mMatching; + + if (trackType > 2) { // MCH-MID or MCH standalone + o2::dataformats::GlobalFwdTrack track; + track.setParameters(fwdtrack.getParameters()); + track.setZ(fwdtrack.getZ()); + track.setCovariances(fwdtrack.getCovariances()); + 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.); + } else if (endPoint == propagationPoint::kToMatchingPlane) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, matchingZ); + } + + auto proptrack = mMatching.MCHtoFwd(mchTrack); + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + } else if (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 in kG. + + if (endPoint == propagationPoint::kToVertex) { + // auto geoMan = o2::base::GeometryManager::meanMaterialBudget(fwdtrack.getX(), fwdtrack.getY(), fwdtrack.getZ(), collision.posX(), collision.posY(), collision.posZ()); + // auto x2x0 = static_cast(geoMan.meanX2X0); + // fwdtrack.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, {collision.covXX(), collision.covYY()}, bzkG, x2x0); + std::array dcaInfOrig{999.f, 999.f, 999.f}; + fwdtrack.propagateToDCAhelix(bzkG, {collision.posX(), collision.posY(), collision.posZ()}, dcaInfOrig); + } else if (endPoint == propagationPoint::kToDCA) { + fwdtrack.propagateToZhelix(collision.posZ(), bzkG); + } else if (endPoint == propagationPoint::kToMatchingPlane) { + fwdtrack.propagateToZhelix(matchingZ, bzkG); + } + propmuon.setParameters(fwdtrack.getParameters()); + propmuon.setZ(fwdtrack.getZ()); + propmuon.setCovariances(fwdtrack.getCovariances()); + } + + return propmuon; +} + +template +o2::dataformats::GlobalFwdTrack refitGlobalMuonCov(TFwdTrack const& muon, TMFTTrack const& mft) +{ + // TFwdTrack and TMFTTrack are o2::track::TrackParCovFwd. + + auto muonCov = muon.getCovariances(); + auto mftCov = mft.getCovariances(); + + SMatrix55Std jacob = ROOT::Math::SMatrixIdentity(); + auto tl = muon.getTgl(); + auto invQPt = muon.getInvQPt(); + jacob(4, 3) = tl / (invQPt * std::sqrt(1 + tl * tl)); + jacob(4, 4) = -std::sqrt(1 + tl * tl) / (invQPt * invQPt); + + auto covQP = ROOT::Math::Similarity(jacob, muonCov); + mftCov(4, 0) = 0; + mftCov(4, 1) = 0; + mftCov(4, 2) = 0; + mftCov(4, 3) = 0; + + mftCov(0, 4) = 0; + mftCov(1, 4) = 0; + mftCov(2, 4) = 0; + mftCov(3, 4) = 0; + mftCov(4, 4) = covQP(4, 4); + + SMatrix55Std jacobInv = ROOT::Math::SMatrixIdentity(); + auto qp = std::sqrt(1 + tl * tl) / invQPt; + auto tlMFT = mft.getTgl(); + jacobInv(4, 3) = tlMFT / (qp * std::sqrt(1 + tlMFT * tlMFT)); + jacobInv(4, 4) = -std::sqrt(1 + tlMFT * tlMFT) / (qp * qp); + auto globalCov = ROOT::Math::Similarity(jacobInv, mftCov); + + auto invQPtGlob = std::sqrt(1 + tlMFT * tlMFT) / qp; + + o2::dataformats::GlobalFwdTrack globalTrack; + globalTrack.setParameters(mft.getParameters()); + globalTrack.setZ(mft.getZ()); + globalTrack.setInvQPt(invQPtGlob); + globalTrack.setCovariances(globalCov); + + return globalTrack; +} + +} // namespace fwdtrackutils +} // namespace o2::aod + +#endif // COMMON_CORE_FWDTRACKUTILITIES_H_ diff --git a/Common/Core/macros/testCollisionTypeHelper.C b/Common/Core/macros/testCollisionTypeHelper.C new file mode 100644 index 00000000000..43624ea697e --- /dev/null +++ b/Common/Core/macros/testCollisionTypeHelper.C @@ -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. + +/// \file testCollisionTypeHelper.C +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Test the CollisionTypeHelper functionality + +#include "Common/Core/CollisionTypeHelper.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPLHCIFData.h" + +void testCollisionTypeHelper(int runNumber = 544124) +{ + + auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); + ccdb.setURL("http://alice-ccdb.cern.ch"); + o2::parameters::GRPLHCIFData* grpo = ccdb.getSpecificForRun("GLO/Config/GRPLHCIF", + runNumber); + grpo->print(); + int collsys = o2::common::core::CollisionSystemType::getCollisionTypeFromGrp(grpo); +} diff --git a/Common/Core/macros/testMetadataHelper.C b/Common/Core/macros/testMetadataHelper.C new file mode 100644 index 00000000000..27371aaf0e3 --- /dev/null +++ b/Common/Core/macros/testMetadataHelper.C @@ -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 testMetadataHelper.C +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Test the MetadataHelper functionality + +#include "Common/Core/MetadataHelper.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// Taken from O2/Framework/AnalysisSupport/src/Plugin.cxx +auto readMetadata(std::unique_ptr& currentFile) -> std::vector +{ + // Get the metadata, if any + auto m = (TMap*)currentFile->Get("metaData"); + if (!m) { + return {}; + } + std::vector results; + auto it = m->MakeIterator(); + + // Serialise metadata into a ; separated string with : separating key and value + bool first = true; + while (auto obj = it->Next()) { + if (first) { + LOGP(info, "Metadata for file \"{}\":", currentFile->GetName()); + first = false; + } + auto objString = (TObjString*)m->GetValue(obj); + std::string key = "aod-metadata-" + std::string(obj->GetName()); + LOGP(info, "- {}: {} goes into key {}", obj->GetName(), objString->String().Data(), key); + char const* value = strdup(objString->String()); + results.push_back(o2::framework::ConfigParamSpec{key, o2::framework::VariantType::String, value, {"Metadata in AOD"}}); + } + return results; +} + +// Create a file with all the versions of the O2 software with alienv q +void createO2VersionFile() +{ + // Can do this only if on lxplus + std::string host = gSystem->HostName() ? gSystem->HostName() : ""; + if (host.find("lxplus") == std::string::npos) { + LOG(warn) << "Not on lxplus (" << host << "); skipping creation of /tmp/o2version.txt"; + return; + } + // If file exists, do nothing + std::ifstream infile("/tmp/o2version.txt"); + if (infile.is_open()) { + return; + } + gSystem->Exec("alienv q | grep VO_ALICE@O2:: > /tmp/o2version.txt"); +} + +std::map buildMapForCommitHash(const std::string& hash) +{ + // Change directory to /tmp + std::map results; + std::ifstream infileO2Versions("/tmp/o2version.txt"); + std::string lineOfO2Version; + const std::string fileContainingCommit = "/tmp/branches_" + hash + ".txt"; + std::ifstream infileO2VersionsWithHash(fileContainingCommit); + if (!infileO2VersionsWithHash.is_open()) { + gSystem->cd("/tmp/"); + gSystem->Exec("git clone git@github.com:AliceO2Group/AliceO2.git"); + gSystem->cd("AliceO2"); + std::string cmd = Form("git branch -r --contains %s > %s 2>&1", hash.c_str(), fileContainingCommit.c_str()); + LOG(info) << "Executing command " << cmd; + gSystem->Exec(cmd.c_str()); + } + std::string lineOfO2VersionsWithHash; + while (std::getline(infileO2Versions, lineOfO2Version)) { + // Extract the tag + int stripSize = 4; + std::string tag = lineOfO2Version.substr(lineOfO2Version.find("O2::") + stripSize); + // Strip a trailing "-1" (some alienv entries append this) + stripSize = 2; + if (tag.size() >= stripSize && tag.compare(tag.size() - stripSize, stripSize, "-1") == 0) { + tag.resize(tag.size() - stripSize); + } + LOG(debug) << "Checking tag '" << lineOfO2Version << "' tag (" << tag << ")"; + bool found = false; + infileO2VersionsWithHash.open(fileContainingCommit); + while (std::getline(infileO2VersionsWithHash, lineOfO2VersionsWithHash)) { + // LOG(info) << "Comparing " << lineOfO2Version << " with " << lineOfO2VersionsWithHash; + if (lineOfO2VersionsWithHash.find(tag) != std::string::npos) { + LOG(info) << "Tag " << tag << " contains hash " << hash; + found = true; + break; + } + } + infileO2VersionsWithHash.close(); + results[tag] = found; + } + return results; +} + +void populateCCDBWithCommitAvailability(std::map hasHashMap, + const std::string commitHash const std::string ccdbUrl = "http://ccdb-test.cern.ch:8080/") +{ + // First, init the CCDB manager to test if the ccdb is already populated + o2::ccdb::CcdbApi api; + api.init(ccdbUrl); + if (!api.isHostReachable()) { + LOG(fatal) << "CCDB host " << ccdbUrl << " is not reacheable, cannot go forward"; + } + for (const auto& entry : hasHashMap) { + if (!entry.second) { // Version of the code does not have the hash + continue; + } + LOG(info) << "Populating CCDB with information that commit hash " << commitHash << " is contained in software tag " << entry.first; + std::map metadata; + metadata["O2Version"] = entry.first; + const std::string ccdbPath = "O2Version/CommitHash/" + commitHash; + auto headers = api.retrieveHeaders(ccdbPath, metadata, -1); + if (headers.size() != 0) { + LOG(info) << "Entry in CCDB already present for commit hash " << commitHash << ", skipping creation"; + continue; + } + LOG(info) << "No entry in CCDB for commit hash " << commitHash << ", creating it"; + std::string s = "available"; + api.storeAsTFileAny(&s, ccdbPath, metadata); + } +} + +void testMetadataHelper(std::string aod = "/tmp/AO2D.root") +{ + createO2VersionFile(); + const std::string commitHash = "63bc2e3893851ef0f849bb4c98c65eae1ba21e47"; + const std::map hasHashMap = buildMapForCommitHash(commitHash); + populateCCDBWithCommitAvailability(hasHashMap, commitHash); + + TFile* file = TFile::Open(aod.c_str()); + if (!file || file->IsZombie()) { + LOG(fatal) << "Could not open file " << aod; + } + std::unique_ptr currentFile{file}; + std::vector specs = readMetadata(currentFile); + + std::vector> retrievers; + auto paramStore = std::make_unique(specs, std::move(retrievers)); + paramStore->preload(); + paramStore->activate(); + o2::framework::ConfigParamRegistry paramRegistry(std::move(paramStore)); + o2::framework::ServiceRegistry serviceRegistry; + o2::framework::ServiceRegistryRef services(serviceRegistry); + o2::framework::ConfigContext aodCfg(paramRegistry, services, 0, nullptr); + LOG(info) << "Loaded " << aodCfg.options().specs().size() << " configuration entries from file " << aod; + aodCfg.options().get("aod-metadata-DataType"); + o2::common::core::MetadataHelper metadataInfo; + metadataInfo.initMetadata(aodCfg); + metadataInfo.set("O2Version", "epn-20250715"); // Override the O2 version to a known one + metadataInfo.print(); + LOG(info) << "Metadata label: " << metadataInfo.makeMetadataLabel(); + + // Check if the hash is in the software tag + const std::string v = metadataInfo.getO2Version(); + if (hasHashMap.find(v) == hasHashMap.end()) { + LOG(fatal) << "Software tag " << v << " not found in available O2 versions"; + } + if (hasHashMap.at(v)) { + LOG(info) << "Hash " << commitHash << " is contained in software tag " << v; + } else { + LOG(warn) << "Hash " << commitHash << " is NOT contained in software tag " << v; + } + if (metadataInfo.isCommitInSoftwareTag(commitHash)) { + LOG(info) << "MetadataHelper confirms that hash " << commitHash << " is contained in software tag " << v; + } else { + LOG(warn) << "MetadataHelper confirms that hash " << commitHash << " is NOT contained in software tag " << v; + } +} diff --git a/Common/Core/trackUtilities.h b/Common/Core/trackUtilities.h index e67e0f82d6f..26f55491f05 100644 --- a/Common/Core/trackUtilities.h +++ b/Common/Core/trackUtilities.h @@ -17,12 +17,18 @@ #ifndef COMMON_CORE_TRACKUTILITIES_H_ #define COMMON_CORE_TRACKUTILITIES_H_ -#include // std::move -#include "CommonConstants/MathConstants.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/Vertex.h" #include "Common/Core/RecoDecay.h" +#include +#include +#include +#include + +#include + +#include +#include // std::move + /// Extracts track parameters from a track. template o2::track::TrackParametrization getTrackPar(const T& track) @@ -122,12 +128,12 @@ auto getRotatedCovMatrixXX(const T& matrix, U phi, V theta) template void getPxPyPz(T const& trackPars, U& pVec) { - auto pt = 1.f / std::abs(trackPars.getQ2Pt()); + auto ptTrack = 1.f / std::abs(trackPars.getQ2Pt()); float cs = cosf(trackPars.getAlpha()), sn = sinf(trackPars.getAlpha()); auto r = std::sqrt((1.f - trackPars.getSnp()) * (1.f + trackPars.getSnp())); - pVec[0] = pt * (r * cs - trackPars.getSnp() * sn); - pVec[1] = pt * (trackPars.getSnp() * cs + r * sn); - pVec[2] = pt * trackPars.getTgl(); + pVec[0] = ptTrack * (r * cs - trackPars.getSnp() * sn); + pVec[1] = ptTrack * (trackPars.getSnp() * cs + r * sn); + pVec[2] = ptTrack * trackPars.getTgl(); } /// Calculates DCA XYZ of a track w.r.t. the primary vertex and its uncertainty if required. diff --git a/Common/DataModel/CMakeLists.txt b/Common/DataModel/CMakeLists.txt index 312e9c15225..dc9001e61ff 100644 --- a/Common/DataModel/CMakeLists.txt +++ b/Common/DataModel/CMakeLists.txt @@ -16,8 +16,17 @@ o2physics_add_header_only_library(DataModel FT0Corrected.h Multiplicity.h PIDResponse.h + PIDResponseITS.h + PIDResponseTOF.h + PIDResponseTPC.h + PIDResponseCombined.h CollisionAssociationTables.h TrackSelectionTables.h McCollisionExtra.h Qvectors.h - MftmchMatchingML.h) + MatchMFTFT0.h + MftmchMatchingML.h + ZDCExtra.h + ZDCLightIons.h + EseTable.h + FwdTrackReAlignTables.h) diff --git a/Common/DataModel/CaloClusters.h b/Common/DataModel/CaloClusters.h index 23a44371d80..473cba9a5a7 100644 --- a/Common/DataModel/CaloClusters.h +++ b/Common/DataModel/CaloClusters.h @@ -12,8 +12,10 @@ #ifndef COMMON_DATAMODEL_CALOCLUSTERS_H_ #define COMMON_DATAMODEL_CALOCLUSTERS_H_ +#include + +#include #include -#include "Framework/AnalysisDataModel.h" namespace o2::aod { diff --git a/Common/DataModel/Centrality.h b/Common/DataModel/Centrality.h index f89e6b23e71..97be46c17b1 100644 --- a/Common/DataModel/Centrality.h +++ b/Common/DataModel/Centrality.h @@ -11,49 +11,99 @@ #ifndef COMMON_DATAMODEL_CENTRALITY_H_ #define COMMON_DATAMODEL_CENTRALITY_H_ -#include "Framework/AnalysisDataModel.h" +#include 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(CentFT0CVariant2, centFT0CVariant2, float); //! Run 3 cent. from FT0C multiplicity, uses classical truncated Nancestors (NOT recommended, cross-check only!) +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 +DECLARE_SOA_TABLE(CentFT0CVariant2s, "AOD", "CENTFT0Cvar2", cent::CentFT0CVariant2); //! Run 3 FT0C variant 1 - uses truncated Nancestors in glauber fit. Not recommended! for cross-checks only + +// Run 3 centrality per BC (joinable with BC) +DECLARE_SOA_TABLE(BCCentFT0Ms, "AOD", "BCCENTFT0M", cent::CentFT0M, o2::soa::Marker<1>); //! Run 3 FT0M BC centrality table +DECLARE_SOA_TABLE(BCCentFT0As, "AOD", "BCCENTFT0A", cent::CentFT0A, o2::soa::Marker<1>); //! Run 3 FT0A BC centrality table +DECLARE_SOA_TABLE(BCCentFT0Cs, "AOD", "BCCENTFT0C", cent::CentFT0C, o2::soa::Marker<1>); //! Run 3 FT0C BC centrality table + 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; + +using BCCentFT0M = BCCentFT0Ms::iterator; +using BCCentFT0A = BCCentFT0As::iterator; +using BCCentFT0C = BCCentFT0Cs::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/CollisionAssociationTables.h b/Common/DataModel/CollisionAssociationTables.h index 7bdbc0c97bd..7ddb2868683 100644 --- a/Common/DataModel/CollisionAssociationTables.h +++ b/Common/DataModel/CollisionAssociationTables.h @@ -20,7 +20,7 @@ #ifndef COMMON_DATAMODEL_COLLISIONASSOCIATIONTABLES_H_ #define COMMON_DATAMODEL_COLLISIONASSOCIATIONTABLES_H_ -#include "Framework/AnalysisDataModel.h" +#include namespace o2::aod { diff --git a/Common/DataModel/EseTable.h b/Common/DataModel/EseTable.h new file mode 100644 index 00000000000..d78c783e12a --- /dev/null +++ b/Common/DataModel/EseTable.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. + +/// \file EseTable.h +/// \brief ESE Framework (20/08/2024) +/// \author Joachim C. K. B. Hansen, Lund University, joachim.hansen@cern.ch + +// + +#ifndef COMMON_DATAMODEL_ESETABLE_H_ +#define COMMON_DATAMODEL_ESETABLE_H_ + +#include + +#include + +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 meanptshape +{ +DECLARE_SOA_COLUMN(FMEANPT, fMEANPT, std::vector); +DECLARE_SOA_COLUMN(FMEANPTSHAPE, fMEANPTSHAPE, std::vector); +} // namespace meanptshape +DECLARE_SOA_TABLE(MeanPts, "AOD", "MEANPT", meanptshape::FMEANPT); +DECLARE_SOA_TABLE(MeanPtShapes, "AOD", "MEANPTSHAPE", meanptshape::FMEANPTSHAPE); +using MeanPt = MeanPts::iterator; +using MeanPtShape = MeanPtShapes::iterator; + +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_ESETABLE_H_ diff --git a/Common/DataModel/EventSelection.h b/Common/DataModel/EventSelection.h index ea1cce4ebbb..670e1e05b61 100644 --- a/Common/DataModel/EventSelection.h +++ b/Common/DataModel/EventSelection.h @@ -8,12 +8,20 @@ // In applying this license CERN does not 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/EventSelectionParams.h" // FIXME: remove +#include "Common/CCDB/RCTSelectionFlags.h" // FIXME: remove +#include "Common/CCDB/TriggerAliases.h" // FIXME: remove + +#include namespace o2::aod { @@ -47,6 +55,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,17 +63,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 +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::NumTracksInTimeRange); + 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/FT0Corrected.h b/Common/DataModel/FT0Corrected.h index af11b3ff811..4c587dc28ad 100644 --- a/Common/DataModel/FT0Corrected.h +++ b/Common/DataModel/FT0Corrected.h @@ -11,7 +11,7 @@ #ifndef COMMON_DATAMODEL_FT0CORRECTED_H_ #define COMMON_DATAMODEL_FT0CORRECTED_H_ -#include "Framework/AnalysisDataModel.h" +#include namespace o2::aod { diff --git a/Common/DataModel/FwdTrackReAlignTables.h b/Common/DataModel/FwdTrackReAlignTables.h new file mode 100644 index 00000000000..199a9c994c0 --- /dev/null +++ b/Common/DataModel/FwdTrackReAlignTables.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. + +/// \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 + +namespace o2::aod +{ +namespace fwdtrackrealign +{ +DECLARE_SOA_COLUMN(IsRemovable, isRemovable, int); //! flag to check the refit status +} + +DECLARE_SOA_TABLE_FULL(StoredFwdTracksReAlign, "FwdTracksReAlign", "AOD", "FWDTRACKREALIGN", + 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, + fwdtrackrealign::IsRemovable, + fwdtrack::Px, + fwdtrack::Py, + fwdtrack::Pz, + fwdtrack::Sign, + fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMID, fwdtrack::Chi2MatchMCHMFT, + fwdtrack::MatchScoreMCHMFT, fwdtrack::MFTTrackId, fwdtrack::MCHTrackId, + fwdtrack::MCHBitMap, fwdtrack::MIDBitMap, fwdtrack::MIDBoards, + fwdtrack::TrackTime, fwdtrack::TrackTimeRes); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(FwdTracksReAlign, StoredFwdTracksReAlign, "FWDTRKREALIGNEXT", //! + fwdtrack::Pt, + fwdtrack::Eta, + fwdtrack::P); + +DECLARE_SOA_TABLE_FULL(StoredFwdTrksCovReAlign, "FwdCovsReAlign", "AOD", "FWDCOVREALIGN", + 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); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(FwdTrksCovReAlign, StoredFwdTrksCovReAlign, "FWDCOVREALIGNEXT", //! + 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); + +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..8ff2e04ecad --- /dev/null +++ b/Common/DataModel/MatchMFTFT0.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. + +// \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 + +#ifndef COMMON_DATAMODEL_MATCHMFTFT0_H_ +#define COMMON_DATAMODEL_MATCHMFTFT0_H_ + +#include + +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 + +#endif // COMMON_DATAMODEL_MATCHMFTFT0_H_ diff --git a/Common/DataModel/MatchMFTMuonData.h b/Common/DataModel/MatchMFTMuonData.h new file mode 100644 index 00000000000..582e8e46692 --- /dev/null +++ b/Common/DataModel/MatchMFTMuonData.h @@ -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. + +#ifndef COMMON_DATAMODEL_MATCHMFTMUONDATA_H_ +#define COMMON_DATAMODEL_MATCHMFTMUONDATA_H_ + +#include + +#include + +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 +#endif // COMMON_DATAMODEL_MATCHMFTMUONDATA_H_ diff --git a/Common/DataModel/McCollisionExtra.h b/Common/DataModel/McCollisionExtra.h index 14b11b9a4e8..475ab68d50a 100644 --- a/Common/DataModel/McCollisionExtra.h +++ b/Common/DataModel/McCollisionExtra.h @@ -14,15 +14,17 @@ #ifndef COMMON_DATAMODEL_MCCOLLISIONEXTRA_H_ #define COMMON_DATAMODEL_MCCOLLISIONEXTRA_H_ +#include + #include -#include "Framework/AnalysisDataModel.h" +#include namespace o2::aod { namespace mccollisionprop { -DECLARE_SOA_COLUMN(NumRecoCollision, numRecoCollision, int); //! stores N times this PV was recoed -DECLARE_SOA_COLUMN(BestCollisionIndex, bestCollisionIndex, int); //! stores N times this PV was recoed +DECLARE_SOA_COLUMN(NumRecoCollision, numRecoCollision, int); //! stores N times this PV was recoed +DECLARE_SOA_COLUMN(BestCollisionIndex, bestCollisionIndex, int); //! stores N times this PV was recoed DECLARE_SOA_COLUMN(BestCollisionCentFT0C, bestCollisionCentFT0C, float); //! stores best FT0C centrality // collision MC context (neighbours contain PoI?) @@ -35,4 +37,4 @@ DECLARE_SOA_TABLE(McCollContexts, "AOD", "MCCOLLCONTEXT", mccollisionprop::ForwardCollisionMap, mccollisionprop::BackwardCollisionMap); } // namespace o2::aod -#endif // COMMON_DATAMODEL_MCCOLLISIONEXTRA_H_ \ No newline at end of file +#endif // COMMON_DATAMODEL_MCCOLLISIONEXTRA_H_ diff --git a/Common/DataModel/MftmchMatchingML.h b/Common/DataModel/MftmchMatchingML.h index f243411f3b7..65e9234586f 100644 --- a/Common/DataModel/MftmchMatchingML.h +++ b/Common/DataModel/MftmchMatchingML.h @@ -12,9 +12,10 @@ #ifndef COMMON_DATAMODEL_MFTMCHMATCHINGML_H_ #define COMMON_DATAMODEL_MFTMCHMATCHINGML_H_ -#include "Framework/AnalysisDataModel.h" #include "Common/DataModel/TrackSelectionTables.h" +#include + namespace o2::aod { DECLARE_SOA_TABLE(FwdTracksML, "AOD", "FWDTRACKML", diff --git a/Common/DataModel/Multiplicity.h b/Common/DataModel/Multiplicity.h index 97d6661bb6a..5337d5ffd59 100644 --- a/Common/DataModel/Multiplicity.h +++ b/Common/DataModel/Multiplicity.h @@ -8,29 +8,38 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. + +/// \file Multiplicity.h +/// \brief multiplicity tables +/// \author ALICE + #ifndef COMMON_DATAMODEL_MULTIPLICITY_H_ #define COMMON_DATAMODEL_MULTIPLICITY_H_ -#include "Framework/AnalysisDataModel.h" #include "Common/DataModel/EventSelection.h" +#include + +#include + 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,12 +54,21 @@ 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); //! @@ -72,8 +90,9 @@ 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(BCNumber, bcNumber, int); //! +DECLARE_SOA_COLUMN(MultNGlobalTracksPV, multNGlobalTracksPV, int); +DECLARE_SOA_COLUMN(MultNGlobalTracksPVeta1, multNGlobalTracksPVeta1, int); +DECLARE_SOA_COLUMN(MultNGlobalTracksPVetaHalf, multNGlobalTracksPVetaHalf, int); // even further QA: timing information for neighboring events DECLARE_SOA_COLUMN(TimeToPrePrevious, timeToPrePrevious, float); //! @@ -85,6 +104,8 @@ DECLARE_SOA_COLUMN(TimeToNeNext, timeToNeNext, float); //! 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); @@ -103,17 +124,33 @@ 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 MultsRun3 = 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); + 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, @@ -121,29 +158,70 @@ DECLARE_SOA_TABLE(MultNeighs, "AOD", "MULTNEIGH", //! // 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 + +// 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>); -using MultExtraMC = MultsExtraMC::iterator; + +// 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); + +DECLARE_SOA_TABLE(MultHepMCHIs, "AOD", "MULTHEPMCHI", //! complementary table for heavy-ion mc info (subset of HepMCHeavyIons) + o2::soa::Index<>, mult::MultMCExtraId, hepmcheavyion::NcollHard, hepmcheavyion::NpartProj, hepmcheavyion::NpartTarg, + hepmcheavyion::Ncoll, hepmcheavyion::ImpactParameter); + +using MultHepMCHI = MultHepMCHIs::iterator; namespace multZeq { -DECLARE_SOA_COLUMN(MultZeqFV0A, multZeqFV0A, float); //! Multiplicity equalized for the vertex position with the FV0A detector -DECLARE_SOA_COLUMN(MultZeqFT0A, multZeqFT0A, float); //! Multiplicity equalized for the vertex position with the FT0A detector -DECLARE_SOA_COLUMN(MultZeqFT0C, multZeqFT0C, float); //! Multiplicity equalized for the vertex position with the FT0C detector -DECLARE_SOA_COLUMN(MultZeqFDDA, multZeqFDDA, float); //! Multiplicity equalized for the vertex position with the FDDA detector -DECLARE_SOA_COLUMN(MultZeqFDDC, multZeqFDDC, float); //! Multiplicity equalized for the vertex position with the FDDC detector -DECLARE_SOA_COLUMN(MultZeqNTracksPV, multZeqNTracksPV, float); //! Multiplicity equalized for the vertex position from the PV contributors +DECLARE_SOA_COLUMN(MultZeqFV0A, multZeqFV0A, float); //! Multiplicity equalized for the vertex position with the FV0A detector +DECLARE_SOA_COLUMN(MultZeqFT0A, multZeqFT0A, float); //! Multiplicity equalized for the vertex position with the FT0A detector +DECLARE_SOA_COLUMN(MultZeqFT0C, multZeqFT0C, float); //! Multiplicity equalized for the vertex position with the FT0C detector +DECLARE_SOA_COLUMN(MultZeqFDDA, multZeqFDDA, float); //! Multiplicity equalized for the vertex position with the FDDA detector +DECLARE_SOA_COLUMN(MultZeqFDDC, multZeqFDDC, float); //! Multiplicity equalized for the vertex position with the FDDC detector +DECLARE_SOA_COLUMN(MultZeqNTracksPV, multZeqNTracksPV, float); //! Multiplicity equalized for the vertex position from the PV contributors +DECLARE_SOA_COLUMN(MultZeqNTracksGlobal, multZeqNTracksGlobal, float); //! Multiplicity equalized for the vertex position, global tracks +DECLARE_SOA_COLUMN(MultZeqMFTNtracks, multZeqMFTNtracks, float); //! Multiplicity equalized for the vertex position, MFT tracks } // namespace multZeq DECLARE_SOA_TABLE(FV0MultZeqs, "AOD", "FV0MULTZEQ", //! Multiplicity equalized for the vertex position with the FV0 detector multZeq::MultZeqFV0A); @@ -153,52 +231,67 @@ DECLARE_SOA_TABLE(FDDMultZeqs, "AOD", "FDDMULTZEQ", //! Multiplicity equalized f multZeq::MultZeqFDDA, multZeq::MultZeqFDDC); DECLARE_SOA_TABLE(PVMultZeqs, "AOD", "PVMULTZEQ", //! Multiplicity equalized for the vertex position from the PV contributors multZeq::MultZeqNTracksPV); +DECLARE_SOA_TABLE(GlobalMultZeqs, "AOD", "GLOBALMULTZEQ", //! Multiplicity equalized for the vertex position, global tracks + multZeq::MultZeqNTracksGlobal); +DECLARE_SOA_TABLE(MFTMultZeqs, "AOD", "MFTMULTZEQS", //! Multiplicity equalized for the vertex position, MFT tracks + multZeq::MultZeqMFTNtracks); 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..21ae2c0c0f3 --- /dev/null +++ b/Common/DataModel/OccupancyTables.h @@ -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. + +/// \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 + +#include +#include + +#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); +// 1 +DECLARE_SOA_TABLE(OccsPrim, "AOD", "OCCSPRIM", o2::soa::Index<>, + o2::aod::occp::OccPrimUnfm80); +DECLARE_SOA_TABLE(OccsMeanPrim, "AOD", "OCCSMEANPRIM", o2::soa::Index<>, + o2::aod::occp::MeanOccPrimUnfm80); +// 2 +DECLARE_SOA_TABLE(OccsT0V0, "AOD", "OCCST0V0", o2::soa::Index<>, + o2::aod::occp::OccFV0AUnfm80, + o2::aod::occp::OccFV0CUnfm80, + o2::aod::occp::OccFT0AUnfm80, + o2::aod::occp::OccFT0CUnfm80); +DECLARE_SOA_TABLE(OccsMeanT0V0, "AOD", "OCCSMEANT0V0", o2::soa::Index<>, + o2::aod::occp::MeanOccFV0AUnfm80, + o2::aod::occp::MeanOccFV0CUnfm80, + o2::aod::occp::MeanOccFT0AUnfm80, + o2::aod::occp::MeanOccFT0CUnfm80); +// 3 +DECLARE_SOA_TABLE(OccsFDD, "AOD", "OCCSFDD", o2::soa::Index<>, + o2::aod::occp::OccFDDAUnfm80, + o2::aod::occp::OccFDDCUnfm80); +DECLARE_SOA_TABLE(OccsMeanFDD, "AOD", "OCCSMEANFDD", o2::soa::Index<>, + o2::aod::occp::MeanOccFDDAUnfm80, + o2::aod::occp::MeanOccFDDCUnfm80); +// 4 +DECLARE_SOA_TABLE(OccsNTrackDet, "AOD", "OCCSNTRACKDET", 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(OccsMeanNTrkDet, "AOD", "OCCSMEANNTRKDET", 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); +// 5 +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(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); + +// Robust Occupancies +// 1 +DECLARE_SOA_TABLE(ORT0V0Prim, "AOD", "ORT0V0Prim", o2::soa::Index<>, + o2::aod::occp::OccRobustT0V0PrimUnfm80); +DECLARE_SOA_TABLE(OMRT0V0Prim, "AOD", "OMRT0V0PRIM", o2::soa::Index<>, + o2::aod::occp::MeanOccRobustT0V0PrimUnfm80); +// 2 +DECLARE_SOA_TABLE(ORFDDT0V0Prim, "AOD", "ORFDDT0V0PRIM", o2::soa::Index<>, + o2::aod::occp::OccRobustFDDT0V0PrimUnfm80); +DECLARE_SOA_TABLE(OMRFDDT0V0Prim, "AOD", "OMRFDDT0V0PRIM", o2::soa::Index<>, + o2::aod::occp::MeanOccRobustFDDT0V0PrimUnfm80); +// 3 +DECLARE_SOA_TABLE(ORNtrackDet, "AOD", "ORNTRACKDET", o2::soa::Index<>, + o2::aod::occp::OccRobustNtrackDetUnfm80); +DECLARE_SOA_TABLE(OMRNtrackDet, "AOD", "OMRNTRACKDET", o2::soa::Index<>, + o2::aod::occp::MeanOccRobustNtrackDetUnfm80); +// 4 +DECLARE_SOA_TABLE(ORMultExtra, "AOD", "ORMULTEXTRA", o2::soa::Index<>, + o2::aod::occp::OccRobustMultExtraTableUnfm80); +DECLARE_SOA_TABLE(OMRMultExtra, "AOD", "OMRMULTEXTRA", o2::soa::Index<>, + o2::aod::occp::MeanOccRobustMultExtraTableUnfm80); + +using Occs = aod::OccsBCsList; +using Occ = Occs::iterator; + +namespace occidx +{ +DECLARE_SOA_INDEX_COLUMN(BC, bc); // o2-linter: disable=name/o2-column (BC is an acronym already defined in data model) // 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<>, + 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_INDEX_COLUMN(TracksQA, tracksQA);// this is not working + +DECLARE_SOA_COLUMN(TmoPrimUnfm80, tmoPrimUnfm80, float); +DECLARE_SOA_COLUMN(TmoFV0AUnfm80, tmoFV0AUnfm80, float); +DECLARE_SOA_COLUMN(TmoFV0CUnfm80, tmoFV0CUnfm80, float); +DECLARE_SOA_COLUMN(TmoFT0AUnfm80, tmoFT0AUnfm80, float); +DECLARE_SOA_COLUMN(TmoFT0CUnfm80, tmoFT0CUnfm80, float); +DECLARE_SOA_COLUMN(TmoFDDAUnfm80, tmoFDDAUnfm80, float); +DECLARE_SOA_COLUMN(TmoFDDCUnfm80, tmoFDDCUnfm80, float); + +DECLARE_SOA_COLUMN(TmoNTrackITSUnfm80, tmoNTrackITSUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackTPCUnfm80, tmoNTrackTPCUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackTRDUnfm80, tmoNTrackTRDUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackTOFUnfm80, tmoNTrackTOFUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackSizeUnfm80, tmoNTrackSizeUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackTPCAUnfm80, tmoNTrackTPCAUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackTPCCUnfm80, tmoNTrackTPCCUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackITSTPCUnfm80, tmoNTrackITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackITSTPCAUnfm80, tmoNTrackITSTPCAUnfm80, float); +DECLARE_SOA_COLUMN(TmoNTrackITSTPCCUnfm80, tmoNTrackITSTPCCUnfm80, float); + +DECLARE_SOA_COLUMN(TmoMultNTracksHasITSUnfm80, tmoMultNTracksHasITSUnfm80, float); +DECLARE_SOA_COLUMN(TmoMultNTracksHasTPCUnfm80, tmoMultNTracksHasTPCUnfm80, float); +DECLARE_SOA_COLUMN(TmoMultNTracksHasTOFUnfm80, tmoMultNTracksHasTOFUnfm80, float); +DECLARE_SOA_COLUMN(TmoMultNTracksHasTRDUnfm80, tmoMultNTracksHasTRDUnfm80, float); +DECLARE_SOA_COLUMN(TmoMultNTracksITSOnlyUnfm80, tmoMultNTracksITSOnlyUnfm80, float); +DECLARE_SOA_COLUMN(TmoMultNTracksTPCOnlyUnfm80, tmoMultNTracksTPCOnlyUnfm80, float); +DECLARE_SOA_COLUMN(TmoMultNTracksITSTPCUnfm80, tmoMultNTracksITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(TmoMultAllTracksTPCOnlyUnfm80, tmoMultAllTracksTPCOnlyUnfm80, float); + +DECLARE_SOA_COLUMN(TmoRobustT0V0PrimUnfm80, tmoRobustT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(TmoRobustFDDT0V0PrimUnfm80, tmoRobustFDDT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(TmoRobustNtrackDetUnfm80, tmoRobustNtrackDetUnfm80, float); +DECLARE_SOA_COLUMN(TmoRobustMultExtraTableUnfm80, tmoRobustMultExtraTableUnfm80, float); + +DECLARE_SOA_COLUMN(TwmoPrimUnfm80, twmoPrimUnfm80, float); +DECLARE_SOA_COLUMN(TwmoFV0AUnfm80, twmoFV0AUnfm80, float); +DECLARE_SOA_COLUMN(TwmoFV0CUnfm80, twmoFV0CUnfm80, float); +DECLARE_SOA_COLUMN(TwmoFT0AUnfm80, twmoFT0AUnfm80, float); +DECLARE_SOA_COLUMN(TwmoFT0CUnfm80, twmoFT0CUnfm80, float); +DECLARE_SOA_COLUMN(TwmoFDDAUnfm80, twmoFDDAUnfm80, float); +DECLARE_SOA_COLUMN(TwmoFDDCUnfm80, twmoFDDCUnfm80, float); + +DECLARE_SOA_COLUMN(TwmoNTrackITSUnfm80, twmoNTrackITSUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackTPCUnfm80, twmoNTrackTPCUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackTRDUnfm80, twmoNTrackTRDUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackTOFUnfm80, twmoNTrackTOFUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackSizeUnfm80, twmoNTrackSizeUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackTPCAUnfm80, twmoNTrackTPCAUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackTPCCUnfm80, twmoNTrackTPCCUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackITSTPCUnfm80, twmoNTrackITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackITSTPCAUnfm80, twmoNTrackITSTPCAUnfm80, float); +DECLARE_SOA_COLUMN(TwmoNTrackITSTPCCUnfm80, twmoNTrackITSTPCCUnfm80, float); + +DECLARE_SOA_COLUMN(TwmoMultNTracksHasITSUnfm80, twmoMultNTracksHasITSUnfm80, float); +DECLARE_SOA_COLUMN(TwmoMultNTracksHasTPCUnfm80, twmoMultNTracksHasTPCUnfm80, float); +DECLARE_SOA_COLUMN(TwmoMultNTracksHasTOFUnfm80, twmoMultNTracksHasTOFUnfm80, float); +DECLARE_SOA_COLUMN(TwmoMultNTracksHasTRDUnfm80, twmoMultNTracksHasTRDUnfm80, float); +DECLARE_SOA_COLUMN(TwmoMultNTracksITSOnlyUnfm80, twmoMultNTracksITSOnlyUnfm80, float); +DECLARE_SOA_COLUMN(TwmoMultNTracksTPCOnlyUnfm80, twmoMultNTracksTPCOnlyUnfm80, float); +DECLARE_SOA_COLUMN(TwmoMultNTracksITSTPCUnfm80, twmoMultNTracksITSTPCUnfm80, float); +DECLARE_SOA_COLUMN(TwmoMultAllTracksTPCOnlyUnfm80, twmoMultAllTracksTPCOnlyUnfm80, float); + +DECLARE_SOA_COLUMN(TwmoRobustT0V0PrimUnfm80, twmoRobustT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(TwmoRobustFDDT0V0PrimUnfm80, twmoRobustFDDT0V0PrimUnfm80, float); +DECLARE_SOA_COLUMN(TwmoRobustNtrackDetUnfm80, twmoRobustNtrackDetUnfm80, float); +DECLARE_SOA_COLUMN(TwmoRobustMultExtraTableUnfm80, twmoRobustMultExtraTableUnfm80, float); + +} // namespace trackmeanocc + +// Tracks +// using Tracks = aod::Tracks; +// DECLARE_SOA_INDEX_TABLE_USER(TrackMeanOccs0, Tracks, "TRACKMEANOCCS0", o2::aod::trackmeanocc::TrackId); + +DECLARE_SOA_TABLE(TmoTrackIds, "AOD", "TMOTRACKIDS", o2::aod::trackmeanocc::TrackId); + +DECLARE_SOA_TABLE(TmoPrim, "AOD", "TMOPRIM", o2::soa::Index<>, // TrackMeanOccDet + o2::aod::trackmeanocc::TmoPrimUnfm80); + +DECLARE_SOA_TABLE(TmoT0V0, "AOD", "TMOT0V0", o2::soa::Index<>, // TrackMeanOccDet + o2::aod::trackmeanocc::TmoFV0AUnfm80, + o2::aod::trackmeanocc::TmoFV0CUnfm80, + o2::aod::trackmeanocc::TmoFT0AUnfm80, + o2::aod::trackmeanocc::TmoFT0CUnfm80); + +DECLARE_SOA_TABLE(TmoFDD, "AOD", "TMOFDD", o2::soa::Index<>, // TrackMeanOccDet + o2::aod::trackmeanocc::TmoFDDAUnfm80, + o2::aod::trackmeanocc::TmoFDDCUnfm80); + +DECLARE_SOA_TABLE(TmoNTrackDet, "AOD", "TMONTRACKDET", o2::soa::Index<>, // TrackMeanOccNtrackDet + o2::aod::trackmeanocc::TmoNTrackITSUnfm80, + o2::aod::trackmeanocc::TmoNTrackTPCUnfm80, + o2::aod::trackmeanocc::TmoNTrackTRDUnfm80, + o2::aod::trackmeanocc::TmoNTrackTOFUnfm80, + o2::aod::trackmeanocc::TmoNTrackSizeUnfm80, + o2::aod::trackmeanocc::TmoNTrackTPCAUnfm80, + o2::aod::trackmeanocc::TmoNTrackTPCCUnfm80, + o2::aod::trackmeanocc::TmoNTrackITSTPCUnfm80, + o2::aod::trackmeanocc::TmoNTrackITSTPCAUnfm80, + o2::aod::trackmeanocc::TmoNTrackITSTPCCUnfm80); + +DECLARE_SOA_TABLE(TmoMultExtra, "AOD", "TMOMULTEXTRA", o2::soa::Index<>, // TrackMeanOccMultExtra + o2::aod::trackmeanocc::TmoMultNTracksHasITSUnfm80, + o2::aod::trackmeanocc::TmoMultNTracksHasTPCUnfm80, + o2::aod::trackmeanocc::TmoMultNTracksHasTOFUnfm80, + o2::aod::trackmeanocc::TmoMultNTracksHasTRDUnfm80, + o2::aod::trackmeanocc::TmoMultNTracksITSOnlyUnfm80, + o2::aod::trackmeanocc::TmoMultNTracksTPCOnlyUnfm80, + o2::aod::trackmeanocc::TmoMultNTracksITSTPCUnfm80, + o2::aod::trackmeanocc::TmoMultAllTracksTPCOnlyUnfm80); + +DECLARE_SOA_TABLE(TmoRT0V0Prim, "AOD", "TMORT0V0PRIM", o2::soa::Index<>, + o2::aod::trackmeanocc::TmoRobustT0V0PrimUnfm80); + +DECLARE_SOA_TABLE(TmoRFDDT0V0Prim, "AOD", "TMORFDDT0V0PRIM", o2::soa::Index<>, + o2::aod::trackmeanocc::TmoRobustFDDT0V0PrimUnfm80); + +DECLARE_SOA_TABLE(TmoRNtrackDet, "AOD", "TMORNTRACKDET", o2::soa::Index<>, + o2::aod::trackmeanocc::TmoRobustNtrackDetUnfm80); + +DECLARE_SOA_TABLE(TmoRMultExtra, "AOD", "TMORMULTEXTRA", o2::soa::Index<>, + o2::aod::trackmeanocc::TmoRobustMultExtraTableUnfm80); + +DECLARE_SOA_TABLE(TwmoPrim, "AOD", "TWMOPRIM", o2::soa::Index<>, // WeightTrackMeanOcc + o2::aod::trackmeanocc::TwmoPrimUnfm80); + +DECLARE_SOA_TABLE(TwmoT0V0, "AOD", "TWMOT0V0", o2::soa::Index<>, // WeightTrackMeanOccDet + o2::aod::trackmeanocc::TwmoFV0AUnfm80, + o2::aod::trackmeanocc::TwmoFV0CUnfm80, + o2::aod::trackmeanocc::TwmoFT0AUnfm80, + o2::aod::trackmeanocc::TwmoFT0CUnfm80); + +DECLARE_SOA_TABLE(TwmoFDD, "AOD", "TWMOFDD", o2::soa::Index<>, // WeightTrackMeanOccDet + o2::aod::trackmeanocc::TwmoFDDAUnfm80, + o2::aod::trackmeanocc::TwmoFDDCUnfm80); + +DECLARE_SOA_TABLE(TwmoNTrackDet, "AOD", "TWMONTRACKDET", o2::soa::Index<>, // WeightTrackMeanOccTrackMult + o2::aod::trackmeanocc::TwmoNTrackITSUnfm80, + o2::aod::trackmeanocc::TwmoNTrackTPCUnfm80, + o2::aod::trackmeanocc::TwmoNTrackTRDUnfm80, + o2::aod::trackmeanocc::TwmoNTrackTOFUnfm80, + o2::aod::trackmeanocc::TwmoNTrackSizeUnfm80, + o2::aod::trackmeanocc::TwmoNTrackTPCAUnfm80, + o2::aod::trackmeanocc::TwmoNTrackTPCCUnfm80, + o2::aod::trackmeanocc::TwmoNTrackITSTPCUnfm80, + o2::aod::trackmeanocc::TwmoNTrackITSTPCAUnfm80, + o2::aod::trackmeanocc::TwmoNTrackITSTPCCUnfm80); + +DECLARE_SOA_TABLE(TwmoMultExtra, "AOD", "TWMOMULTEXTRA", o2::soa::Index<>, // WeightTrackMeanOccMultExtra + o2::aod::trackmeanocc::TwmoMultNTracksHasITSUnfm80, + o2::aod::trackmeanocc::TwmoMultNTracksHasTPCUnfm80, + o2::aod::trackmeanocc::TwmoMultNTracksHasTOFUnfm80, + o2::aod::trackmeanocc::TwmoMultNTracksHasTRDUnfm80, + o2::aod::trackmeanocc::TwmoMultNTracksITSOnlyUnfm80, + o2::aod::trackmeanocc::TwmoMultNTracksTPCOnlyUnfm80, + o2::aod::trackmeanocc::TwmoMultNTracksITSTPCUnfm80, + o2::aod::trackmeanocc::TwmoMultAllTracksTPCOnlyUnfm80); + +DECLARE_SOA_TABLE(TwmoRT0V0Prim, "AOD", "TWMORT0V0PRIM", o2::soa::Index<>, + o2::aod::trackmeanocc::TwmoRobustT0V0PrimUnfm80); + +DECLARE_SOA_TABLE(TwmoRFDDT0V0Pri, "AOD", "TWMORFDDT0V0PRI", o2::soa::Index<>, + o2::aod::trackmeanocc::TwmoRobustFDDT0V0PrimUnfm80); + +DECLARE_SOA_TABLE(TwmoRNtrackDet, "AOD", "TWMORNTRACKDET", o2::soa::Index<>, + o2::aod::trackmeanocc::TwmoRobustNtrackDetUnfm80); + +DECLARE_SOA_TABLE(TwmoRMultExtra, "AOD", "TWMORMULTEXTRA", o2::soa::Index<>, + o2::aod::trackmeanocc::TwmoRobustMultExtraTableUnfm80); + +using Tmo = aod::TmoTrackIds::iterator; + +using TrackQA = TracksQAVersion::iterator; + +namespace trackmeanocc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Tmo, tmo, int64_t, TmoTrackIds, ""); +DECLARE_SOA_INDEX_COLUMN_FULL(TrackQA, trackQA, int64_t, TracksQAVersion, ""); +} // namespace trackmeanocc + +DECLARE_SOA_TABLE(TrackToTracksQA, "AOD", "TRACKTOTRACKSQA", o2::aod::trackmeanocc::TrackQAId); +DECLARE_SOA_TABLE(TrackToTmo, "AOD", "TRACKTOTMO", o2::aod::trackmeanocc::TmoId); + +DECLARE_SOA_TABLE(TrackQAToTmo, "AOD", "TRACKQATOTMO", o2::aod::trackmeanocc::TmoId); +DECLARE_SOA_TABLE(TmoToTrackQA, "AOD", "TMOTOTRACKQA", o2::aod::trackmeanocc::TrackQAId); + +} // namespace o2::aod +#endif // COMMON_DATAMODEL_OCCUPANCYTABLES_H_ diff --git a/Common/DataModel/PIDResponse.h b/Common/DataModel/PIDResponse.h index 3ef77fef8d4..a2b3c0f7390 100644 --- a/Common/DataModel/PIDResponse.h +++ b/Common/DataModel/PIDResponse.h @@ -13,792 +13,33 @@ /// \file PIDResponse.h /// \author Nicolò Jacazio nicolo.jacazio@cern.ch /// \brief Set of tables, tasks and utilities to provide the interface between -/// the analysis data model and the PID response +/// the analysis data model and the PID response. This is interim. To be removed /// #ifndef COMMON_DATAMODEL_PIDRESPONSE_H_ #define COMMON_DATAMODEL_PIDRESPONSE_H_ -#include - -// O2 includes -#include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" -#include "ReconstructionDataFormats/PID.h" -#include "Framework/Logger.h" +#include "Common/DataModel/PIDResponseTOF.h" // FIXME: remove +#include "Common/DataModel/PIDResponseTPC.h" // FIXME: remove namespace o2::aod { namespace pidutils { -// Function to pack a float into a binned value in table +// Function to pack a float into a binned value in table (interim solution) template void packInTable(const float& valueToBin, T& table) { - if (valueToBin <= binningType::binned_min) { - table(binningType::underflowBin); - } else if (valueToBin >= binningType::binned_max) { - table(binningType::overflowBin); - } else if (valueToBin >= 0) { - table(static_cast((valueToBin / binningType::bin_width) + 0.5f)); - } else { - table(static_cast((valueToBin / binningType::bin_width) - 0.5f)); - } + binningType::packInTable(valueToBin, table); } // Function to unpack a binned value into a float template float unPackInTable(const typename binningType::binned_t& valueToUnpack) { - return binningType::bin_width * static_cast(valueToUnpack); -} - -// Checkers for TOF PID hypothesis availability (runtime) -template -using hasTOFEl = decltype(std::declval().tofNSigmaEl()); -template -using hasTOFMu = decltype(std::declval().tofNSigmaMu()); -template -using hasTOFPi = decltype(std::declval().tofNSigmaPi()); -template -using hasTOFKa = decltype(std::declval().tofNSigmaKa()); -template -using hasTOFPr = decltype(std::declval().tofNSigmaPr()); -template -using hasTOFDe = decltype(std::declval().tofNSigmaDe()); -template -using hasTOFTr = decltype(std::declval().tofNSigmaTr()); -template -using hasTOFHe = decltype(std::declval().tofNSigmaHe()); -template -using hasTOFAl = decltype(std::declval().tofNSigmaAl()); - -// Checkers for TPC PID hypothesis availability (runtime) -template -using hasTPCEl = decltype(std::declval().tpcNSigmaEl()); -template -using hasTPCMu = decltype(std::declval().tpcNSigmaMu()); -template -using hasTPCPi = decltype(std::declval().tpcNSigmaPi()); -template -using hasTPCKa = decltype(std::declval().tpcNSigmaKa()); -template -using hasTPCPr = decltype(std::declval().tpcNSigmaPr()); -template -using hasTPCDe = decltype(std::declval().tpcNSigmaDe()); -template -using hasTPCTr = decltype(std::declval().tpcNSigmaTr()); -template -using hasTPCHe = decltype(std::declval().tpcNSigmaHe()); -template -using hasTPCAl = decltype(std::declval().tpcNSigmaAl()); - -// PID index as template argument -#define perSpeciesWrapper(functionName) \ - template \ - auto functionName(const TrackType& track) \ - { \ - if constexpr (index == o2::track::PID::Electron) { \ - return track.functionName##El(); \ - } else if constexpr (index == o2::track::PID::Muon) { \ - return track.functionName##Mu(); \ - } else if constexpr (index == o2::track::PID::Pion) { \ - return track.functionName##Pi(); \ - } else if constexpr (index == o2::track::PID::Kaon) { \ - return track.functionName##Ka(); \ - } else if constexpr (index == o2::track::PID::Proton) { \ - return track.functionName##Pr(); \ - } else if constexpr (index == o2::track::PID::Deuteron) { \ - return track.functionName##De(); \ - } else if constexpr (index == o2::track::PID::Triton) { \ - return track.functionName##Tr(); \ - } else if constexpr (index == o2::track::PID::Helium3) { \ - return track.functionName##He(); \ - } else if constexpr (index == o2::track::PID::Alpha) { \ - return track.functionName##Al(); \ - } \ - } - -perSpeciesWrapper(tofNSigma); -perSpeciesWrapper(tofExpSigma); -template -auto tofExpSignal(const TrackType& track) -{ - if constexpr (index == o2::track::PID::Electron) { - return track.tofExpSignalEl(track.tofSignal()); - } else if constexpr (index == o2::track::PID::Muon) { - return track.tofExpSignalMu(track.tofSignal()); - } else if constexpr (index == o2::track::PID::Pion) { - return track.tofExpSignalPi(track.tofSignal()); - } else if constexpr (index == o2::track::PID::Kaon) { - return track.tofExpSignalKa(track.tofSignal()); - } else if constexpr (index == o2::track::PID::Proton) { - return track.tofExpSignalPr(track.tofSignal()); - } else if constexpr (index == o2::track::PID::Deuteron) { - return track.tofExpSignalDe(track.tofSignal()); - } else if constexpr (index == o2::track::PID::Triton) { - return track.tofExpSignalTr(track.tofSignal()); - } else if constexpr (index == o2::track::PID::Helium3) { - return track.tofExpSignalHe(track.tofSignal()); - } else if constexpr (index == o2::track::PID::Alpha) { - return track.tofExpSignalAl(track.tofSignal()); - } -} -perSpeciesWrapper(tofExpSignalDiff); - -perSpeciesWrapper(tpcNSigma); -perSpeciesWrapper(tpcExpSigma); -template -auto tpcExpSignal(const TrackType& track) -{ - if constexpr (index == o2::track::PID::Electron) { - return track.tpcExpSignalEl(track.tpcSignal()); - } else if constexpr (index == o2::track::PID::Muon) { - return track.tpcExpSignalMu(track.tpcSignal()); - } else if constexpr (index == o2::track::PID::Pion) { - return track.tpcExpSignalPi(track.tpcSignal()); - } else if constexpr (index == o2::track::PID::Kaon) { - return track.tpcExpSignalKa(track.tpcSignal()); - } else if constexpr (index == o2::track::PID::Proton) { - return track.tpcExpSignalPr(track.tpcSignal()); - } else if constexpr (index == o2::track::PID::Deuteron) { - return track.tpcExpSignalDe(track.tpcSignal()); - } else if constexpr (index == o2::track::PID::Triton) { - return track.tpcExpSignalTr(track.tpcSignal()); - } else if constexpr (index == o2::track::PID::Helium3) { - return track.tpcExpSignalHe(track.tpcSignal()); - } else if constexpr (index == o2::track::PID::Alpha) { - return track.tpcExpSignalAl(track.tpcSignal()); - } -} -perSpeciesWrapper(tpcExpSignalDiff); - -#undef perSpeciesWrapper - -// PID index as function argument for TOF -#define perSpeciesWrapper(functionName) \ - template \ - auto functionName(const o2::track::PID::ID index, const TrackType& track) \ - { \ - switch (index) { \ - case o2::track::PID::Electron: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##El(); \ - } \ - case o2::track::PID::Muon: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Mu(); \ - } \ - case o2::track::PID::Pion: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Pi(); \ - } \ - case o2::track::PID::Kaon: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Ka(); \ - } \ - case o2::track::PID::Proton: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Pr(); \ - } \ - case o2::track::PID::Deuteron: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##De(); \ - } \ - case o2::track::PID::Triton: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Tr(); \ - } \ - case o2::track::PID::Helium3: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##He(); \ - } \ - case o2::track::PID::Alpha: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Al(); \ - } \ - default: \ - LOGF(fatal, "TOF PID table for PID index %i (%s) is not available", index, o2::track::PID::getName(index)); \ - return 0.f; \ - } \ - } - -perSpeciesWrapper(tofNSigma); -perSpeciesWrapper(tofExpSigma); -template -auto tofExpSignal(const o2::track::PID::ID index, const TrackType& track) -{ - switch (index) { - case o2::track::PID::Electron: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalEl(track.tofSignal()); - } - case o2::track::PID::Muon: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalMu(track.tofSignal()); - } - case o2::track::PID::Pion: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalPi(track.tofSignal()); - } - case o2::track::PID::Kaon: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalKa(track.tofSignal()); - } - case o2::track::PID::Proton: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalPr(track.tofSignal()); - } - case o2::track::PID::Deuteron: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalDe(track.tofSignal()); - } - case o2::track::PID::Triton: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalTr(track.tofSignal()); - } - case o2::track::PID::Helium3: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalHe(track.tofSignal()); - } - case o2::track::PID::Alpha: - if constexpr (std::experimental::is_detected::value) { - return track.tofExpSignalAl(track.tofSignal()); - } - default: - LOGF(fatal, "TOF PID table for PID index %i (%s) is not available", index, o2::track::PID::getName(index)); - return 0.f; - } -} -perSpeciesWrapper(tofExpSignalDiff); - -#undef perSpeciesWrapper - -// PID index as function argument for TPC -#define perSpeciesWrapper(functionName) \ - template \ - auto functionName(const o2::track::PID::ID index, const TrackType& track) \ - { \ - switch (index) { \ - case o2::track::PID::Electron: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##El(); \ - } \ - case o2::track::PID::Muon: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Mu(); \ - } \ - case o2::track::PID::Pion: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Pi(); \ - } \ - case o2::track::PID::Kaon: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Ka(); \ - } \ - case o2::track::PID::Proton: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Pr(); \ - } \ - case o2::track::PID::Deuteron: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##De(); \ - } \ - case o2::track::PID::Triton: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Tr(); \ - } \ - case o2::track::PID::Helium3: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##He(); \ - } \ - case o2::track::PID::Alpha: \ - if constexpr (std::experimental::is_detected::value) { \ - return track.functionName##Al(); \ - } \ - default: \ - LOGF(fatal, "TPC PID table for PID index %i (%s) is not available", index, o2::track::PID::getName(index)); \ - return 0.f; \ - } \ - } - -perSpeciesWrapper(tpcNSigma); -perSpeciesWrapper(tpcExpSigma); -template -auto tpcExpSignal(const o2::track::PID::ID index, const TrackType& track) -{ - switch (index) { - case o2::track::PID::Electron: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalEl(track.tpcSignal()); - } - case o2::track::PID::Muon: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalMu(track.tpcSignal()); - } - case o2::track::PID::Pion: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalPi(track.tpcSignal()); - } - case o2::track::PID::Kaon: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalKa(track.tpcSignal()); - } - case o2::track::PID::Proton: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalPr(track.tpcSignal()); - } - case o2::track::PID::Deuteron: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalDe(track.tpcSignal()); - } - case o2::track::PID::Triton: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalTr(track.tpcSignal()); - } - case o2::track::PID::Helium3: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalHe(track.tpcSignal()); - } - case o2::track::PID::Alpha: - if constexpr (std::experimental::is_detected::value) { - return track.tpcExpSignalAl(track.tpcSignal()); - } - default: - LOGF(fatal, "TPC PID table for PID index %i (%s) is not available", index, o2::track::PID::getName(index)); - return 0.f; - } + return binningType::unPackInTable(valueToUnpack); } -perSpeciesWrapper(tpcExpSignalDiff); - -#undef perSpeciesWrapper - } // namespace pidutils - -namespace pidflags -{ - -namespace enums -{ -enum PIDFlags : uint8_t { - EvTimeUndef = 0x0, // Event collision not set, corresponding to the LHC Fill event time - EvTimeTOF = 0x1, // Event collision time from TOF - EvTimeT0AC = 0x2, // Event collision time from the FT0AC - EvTimeTOFT0AC = 0x4 // Event collision time from the TOF and FT0AC -}; -} - -DECLARE_SOA_COLUMN(GoodTOFMatch, goodTOFMatch, bool); //! Bool for the TOF PID information on the single track information -DECLARE_SOA_COLUMN(TOFFlags, tofFlags, uint8_t); //! Flag for the complementary TOF PID information for the event time -DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeDefined, isEvTimeDefined, //! True if the Event Time was computed with any method i.e. there is a usable event time - [](uint8_t flags) -> bool { return (flags > 0); }); -DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOF, isEvTimeTOF, //! True if the Event Time was computed with the TOF - [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeTOF) == enums::PIDFlags::EvTimeTOF; }); -DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeT0AC, isEvTimeT0AC, //! True if the Event Time was computed with the T0AC - [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeT0AC) == enums::PIDFlags::EvTimeT0AC; }); -DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOFT0AC, isEvTimeTOFT0AC, //! True if the Event Time was computed with the TOF and T0AC - [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeTOFT0AC) == enums::PIDFlags::EvTimeTOFT0AC; }); - -} // namespace pidflags - -namespace pidtofsignal -{ -DECLARE_SOA_COLUMN(TOFSignal, tofSignal, float); //! TOF signal from track time -DECLARE_SOA_DYNAMIC_COLUMN(EventCollisionTime, eventCollisionTime, //! Event collision time used for the track. Needs the TOF - [](float signal, float tMinusTexp, float texp) -> float { return texp + tMinusTexp - signal; }); - -} // namespace pidtofsignal - -namespace pidtofbeta -{ -DECLARE_SOA_COLUMN(Beta, beta, float); //! TOF beta -DECLARE_SOA_COLUMN(BetaError, betaerror, float); //! Uncertainty on the TOF beta -// -DECLARE_SOA_COLUMN(ExpBetaEl, expbetael, float); //! Expected beta of electron -DECLARE_SOA_COLUMN(ExpBetaElError, expbetaelerror, float); //! Expected uncertainty on the beta of electron -// -DECLARE_SOA_COLUMN(SeparationBetaEl, separationbetael, float); //! Separation computed with the expected beta for electrons -DECLARE_SOA_DYNAMIC_COLUMN(DiffBetaEl, diffbetael, //! Difference between the measured and the expected beta for electrons - [](float beta, float expbetael) -> float { return beta - expbetael; }); -} // namespace pidtofbeta - -namespace pidtofmass -{ -DECLARE_SOA_COLUMN(TOFMass, mass, float); //! TOF mass -} // namespace pidtofmass - -namespace pidtof -{ -// Expected times -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalEl, tofExpSignalEl, //! Expected time for electron - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalMu, tofExpSignalMu, //! Expected time for muon - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalPi, tofExpSignalPi, //! Expected time for pion - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalKa, tofExpSignalKa, //! Expected time for kaon - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalPr, tofExpSignalPr, //! Expected time for proton - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDe, tofExpSignalDe, //! Expected time for deuteron - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalTr, tofExpSignalTr, //! Expected time for triton - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalHe, tofExpSignalHe, //! Expected time for helium3 - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalAl, tofExpSignalAl, //! Expected time for alpha - [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); -// Delta with respect to signal -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffEl, tofExpSignalDiffEl, //! Difference between signal and expected for electron - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffMu, tofExpSignalDiffMu, //! Difference between signal and expected for muon - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffPi, tofExpSignalDiffPi, //! Difference between signal and expected for pion - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffKa, tofExpSignalDiffKa, //! Difference between signal and expected for kaon - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffPr, tofExpSignalDiffPr, //! Difference between signal and expected for proton - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffDe, tofExpSignalDiffDe, //! Difference between signal and expected for deuteron - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffTr, tofExpSignalDiffTr, //! Difference between signal and expected for triton - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffHe, tofExpSignalDiffHe, //! Difference between signal and expected for helium3 - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffAl, tofExpSignalDiffAl, //! Difference between signal and expected for alpha - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -// Expected sigma -DECLARE_SOA_COLUMN(TOFExpSigmaEl, tofExpSigmaEl, float); //! Expected resolution with the TOF detector for electron -DECLARE_SOA_COLUMN(TOFExpSigmaMu, tofExpSigmaMu, float); //! Expected resolution with the TOF detector for muon -DECLARE_SOA_COLUMN(TOFExpSigmaPi, tofExpSigmaPi, float); //! Expected resolution with the TOF detector for pion -DECLARE_SOA_COLUMN(TOFExpSigmaKa, tofExpSigmaKa, float); //! Expected resolution with the TOF detector for kaon -DECLARE_SOA_COLUMN(TOFExpSigmaPr, tofExpSigmaPr, float); //! Expected resolution with the TOF detector for proton -DECLARE_SOA_COLUMN(TOFExpSigmaDe, tofExpSigmaDe, float); //! Expected resolution with the TOF detector for deuteron -DECLARE_SOA_COLUMN(TOFExpSigmaTr, tofExpSigmaTr, float); //! Expected resolution with the TOF detector for triton -DECLARE_SOA_COLUMN(TOFExpSigmaHe, tofExpSigmaHe, float); //! Expected resolution with the TOF detector for helium3 -DECLARE_SOA_COLUMN(TOFExpSigmaAl, tofExpSigmaAl, float); //! Expected resolution with the TOF detector for alpha -// NSigma -DECLARE_SOA_COLUMN(TOFNSigmaEl, tofNSigmaEl, float); //! Nsigma separation with the TOF detector for electron -DECLARE_SOA_COLUMN(TOFNSigmaMu, tofNSigmaMu, float); //! Nsigma separation with the TOF detector for muon -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(TOFNSigmaAl, tofNSigmaAl, float); //! Nsigma separation with the TOF detector for alpha -} // namespace pidtof - -// Macro to convert the stored Nsigmas to floats -#define DEFINE_UNWRAP_NSIGMA_COLUMN(COLUMN, COLUMN_NAME) \ - DECLARE_SOA_DYNAMIC_COLUMN(COLUMN, COLUMN_NAME, \ - [](binning::binned_t nsigma_binned) -> float { return o2::aod::pidutils::unPackInTable(nsigma_binned); }); - -namespace pidtof_tiny -{ -struct binning { - public: - typedef int8_t 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); - static constexpr float binned_max = 6.35; - static constexpr float binned_min = -6.35; - static constexpr float bin_width = (binned_max - binned_min) / nbins; -}; - -// NSigma with reduced size 8 bit -DECLARE_SOA_COLUMN(TOFNSigmaStoreEl, tofNSigmaStoreEl, binning::binned_t); //! Stored binned nsigma with the TOF detector for electron -DECLARE_SOA_COLUMN(TOFNSigmaStoreMu, tofNSigmaStoreMu, binning::binned_t); //! Stored binned nsigma with the TOF detector for muon -DECLARE_SOA_COLUMN(TOFNSigmaStorePi, tofNSigmaStorePi, binning::binned_t); //! Stored binned nsigma with the TOF detector for pion -DECLARE_SOA_COLUMN(TOFNSigmaStoreKa, tofNSigmaStoreKa, binning::binned_t); //! Stored binned nsigma with the TOF detector for kaon -DECLARE_SOA_COLUMN(TOFNSigmaStorePr, tofNSigmaStorePr, binning::binned_t); //! Stored binned nsigma with the TOF detector for proton -DECLARE_SOA_COLUMN(TOFNSigmaStoreDe, tofNSigmaStoreDe, binning::binned_t); //! Stored binned nsigma with the TOF detector for deuteron -DECLARE_SOA_COLUMN(TOFNSigmaStoreTr, tofNSigmaStoreTr, binning::binned_t); //! Stored binned nsigma with the TOF detector for triton -DECLARE_SOA_COLUMN(TOFNSigmaStoreHe, tofNSigmaStoreHe, binning::binned_t); //! Stored binned nsigma with the TOF detector for helium3 -DECLARE_SOA_COLUMN(TOFNSigmaStoreAl, tofNSigmaStoreAl, binning::binned_t); //! Stored binned nsigma with the TOF detector for alpha -// NSigma with reduced size in [binned_min, binned_max] bin size bin_width -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaEl, tofNSigmaEl); //! Unwrapped (float) nsigma with the TOF detector for electron -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaMu, tofNSigmaMu); //! Unwrapped (float) nsigma with the TOF detector for muon -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaPi, tofNSigmaPi); //! Unwrapped (float) nsigma with the TOF detector for pion -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaKa, tofNSigmaKa); //! Unwrapped (float) nsigma with the TOF detector for kaon -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaPr, tofNSigmaPr); //! Unwrapped (float) nsigma with the TOF detector for proton -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaDe, tofNSigmaDe); //! Unwrapped (float) nsigma with the TOF detector for deuteron -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaTr, tofNSigmaTr); //! Unwrapped (float) nsigma with the TOF detector for triton -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaHe, tofNSigmaHe); //! Unwrapped (float) nsigma with the TOF detector for helium3 -DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaAl, tofNSigmaAl); //! Unwrapped (float) nsigma with the TOF detector for alpha - -} // namespace pidtof_tiny - -DECLARE_SOA_TABLE(TOFSignal, "AOD", "TOFSignal", //! Table of the TOF signal - pidtofsignal::TOFSignal, - pidtofsignal::EventCollisionTime); - -DECLARE_SOA_TABLE(pidTOFFlags, "AOD", "pidTOFFlags", //! Table of the flags for TOF signal quality on the track level - pidflags::GoodTOFMatch); - -DECLARE_SOA_TABLE(pidTOFbeta, "AOD", "pidTOFbeta", //! Table of the TOF beta - pidtofbeta::Beta, pidtofbeta::BetaError); - -DECLARE_SOA_TABLE(pidTOFmass, "AOD", "pidTOFmass", //! Table of the TOF mass - pidtofmass::TOFMass); - -DECLARE_SOA_TABLE(pidEvTimeFlags, "AOD", "pidEvTimeFlags", //! Table of the PID flags for the event time tables - pidflags::TOFFlags, - pidflags::IsEvTimeDefined, - pidflags::IsEvTimeTOF, - pidflags::IsEvTimeT0AC, - pidflags::IsEvTimeTOFT0AC); - -// Per particle tables -DECLARE_SOA_TABLE(pidTOFFullEl, "AOD", "pidTOFFullEl", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for electron - pidtof::TOFExpSignalDiffEl, - pidtof::TOFExpSignalEl, - pidtof::TOFExpSigmaEl, pidtof::TOFNSigmaEl); -DECLARE_SOA_TABLE(pidTOFFullMu, "AOD", "pidTOFFullMu", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for muon - pidtof::TOFExpSignalDiffMu, - pidtof::TOFExpSignalMu, - pidtof::TOFExpSigmaMu, pidtof::TOFNSigmaMu); -DECLARE_SOA_TABLE(pidTOFFullPi, "AOD", "pidTOFFullPi", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for pion - pidtof::TOFExpSignalDiffPi, - pidtof::TOFExpSignalPi, - pidtof::TOFExpSigmaPi, pidtof::TOFNSigmaPi); -DECLARE_SOA_TABLE(pidTOFFullKa, "AOD", "pidTOFFullKa", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for kaon - pidtof::TOFExpSignalDiffKa, - pidtof::TOFExpSignalKa, - pidtof::TOFExpSigmaKa, pidtof::TOFNSigmaKa); -DECLARE_SOA_TABLE(pidTOFFullPr, "AOD", "pidTOFFullPr", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for proton - pidtof::TOFExpSignalDiffPr, - pidtof::TOFExpSignalPr, - pidtof::TOFExpSigmaPr, pidtof::TOFNSigmaPr); -DECLARE_SOA_TABLE(pidTOFFullDe, "AOD", "pidTOFFullDe", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for deuteron - pidtof::TOFExpSignalDiffDe, - pidtof::TOFExpSignalDe, - pidtof::TOFExpSigmaDe, pidtof::TOFNSigmaDe); -DECLARE_SOA_TABLE(pidTOFFullTr, "AOD", "pidTOFFullTr", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for triton - pidtof::TOFExpSignalDiffTr, - pidtof::TOFExpSignalTr, - pidtof::TOFExpSigmaTr, pidtof::TOFNSigmaTr); -DECLARE_SOA_TABLE(pidTOFFullHe, "AOD", "pidTOFFullHe", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for helium3 - pidtof::TOFExpSignalDiffHe, - pidtof::TOFExpSignalHe, - pidtof::TOFExpSigmaHe, pidtof::TOFNSigmaHe); -DECLARE_SOA_TABLE(pidTOFFullAl, "AOD", "pidTOFFullAl", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for alpha - pidtof::TOFExpSignalDiffAl, - pidtof::TOFExpSignalAl, - pidtof::TOFExpSigmaAl, pidtof::TOFNSigmaAl); - -// Tiny size tables -DECLARE_SOA_TABLE(pidTOFEl, "AOD", "pidTOFEl", //! Table of the TOF response with binned Nsigma for electron - pidtof_tiny::TOFNSigmaStoreEl, pidtof_tiny::TOFNSigmaEl); -DECLARE_SOA_TABLE(pidTOFMu, "AOD", "pidTOFMu", //! Table of the TOF response with binned Nsigma for muon - pidtof_tiny::TOFNSigmaStoreMu, pidtof_tiny::TOFNSigmaMu); -DECLARE_SOA_TABLE(pidTOFPi, "AOD", "pidTOFPi", //! Table of the TOF response with binned Nsigma for pion - pidtof_tiny::TOFNSigmaStorePi, pidtof_tiny::TOFNSigmaPi); -DECLARE_SOA_TABLE(pidTOFKa, "AOD", "pidTOFKa", //! Table of the TOF response with binned Nsigma for kaon - pidtof_tiny::TOFNSigmaStoreKa, pidtof_tiny::TOFNSigmaKa); -DECLARE_SOA_TABLE(pidTOFPr, "AOD", "pidTOFPr", //! Table of the TOF response with binned Nsigma for proton - pidtof_tiny::TOFNSigmaStorePr, pidtof_tiny::TOFNSigmaPr); -DECLARE_SOA_TABLE(pidTOFDe, "AOD", "pidTOFDe", //! Table of the TOF response with binned Nsigma for deuteron - pidtof_tiny::TOFNSigmaStoreDe, pidtof_tiny::TOFNSigmaDe); -DECLARE_SOA_TABLE(pidTOFTr, "AOD", "pidTOFTr", //! Table of the TOF response with binned Nsigma for triton - pidtof_tiny::TOFNSigmaStoreTr, pidtof_tiny::TOFNSigmaTr); -DECLARE_SOA_TABLE(pidTOFHe, "AOD", "pidTOFHe", //! Table of the TOF response with binned Nsigma for helium3 - pidtof_tiny::TOFNSigmaStoreHe, pidtof_tiny::TOFNSigmaHe); -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 -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalEl, tpcExpSignalEl, //! Expected signal with the TPC detector for electron - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalMu, tpcExpSignalMu, //! Expected signal with the TPC detector for muon - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalPi, tpcExpSignalPi, //! Expected signal with the TPC detector for pion - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalKa, tpcExpSignalKa, //! Expected signal with the TPC detector for kaon - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalPr, tpcExpSignalPr, //! Expected signal with the TPC detector for proton - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDe, tpcExpSignalDe, //! Expected signal with the TPC detector for deuteron - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalTr, tpcExpSignalTr, //! Expected signal with the TPC detector for triton - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalHe, tpcExpSignalHe, //! Expected signal with the TPC detector for helium3 - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalAl, tpcExpSignalAl, //! Expected signal with the TPC detector for alpha - [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); -// Expected signals difference -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffEl, tpcExpSignalDiffEl, //! Difference between signal and expected for electron - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffMu, tpcExpSignalDiffMu, //! Difference between signal and expected for muon - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffPi, tpcExpSignalDiffPi, //! Difference between signal and expected for pion - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffKa, tpcExpSignalDiffKa, //! Difference between signal and expected for kaon - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffPr, tpcExpSignalDiffPr, //! Difference between signal and expected for proton - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffDe, tpcExpSignalDiffDe, //! Difference between signal and expected for deuteron - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffTr, tpcExpSignalDiffTr, //! Difference between signal and expected for triton - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffHe, tpcExpSignalDiffHe, //! Difference between signal and expected for helium3 - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffAl, tpcExpSignalDiffAl, //! Difference between signal and expected for alpha - [](float nsigma, float sigma) -> float { return nsigma * sigma; }); -// Expected sigma -DECLARE_SOA_COLUMN(TPCExpSigmaEl, tpcExpSigmaEl, float); //! Expected resolution with the TPC detector for electron -DECLARE_SOA_COLUMN(TPCExpSigmaMu, tpcExpSigmaMu, float); //! Expected resolution with the TPC detector for muon -DECLARE_SOA_COLUMN(TPCExpSigmaPi, tpcExpSigmaPi, float); //! Expected resolution with the TPC detector for pion -DECLARE_SOA_COLUMN(TPCExpSigmaKa, tpcExpSigmaKa, float); //! Expected resolution with the TPC detector for kaon -DECLARE_SOA_COLUMN(TPCExpSigmaPr, tpcExpSigmaPr, float); //! Expected resolution with the TPC detector for proton -DECLARE_SOA_COLUMN(TPCExpSigmaDe, tpcExpSigmaDe, float); //! Expected resolution with the TPC detector for deuteron -DECLARE_SOA_COLUMN(TPCExpSigmaTr, tpcExpSigmaTr, float); //! Expected resolution with the TPC detector for triton -DECLARE_SOA_COLUMN(TPCExpSigmaHe, tpcExpSigmaHe, float); //! Expected resolution with the TPC detector for helium3 -DECLARE_SOA_COLUMN(TPCExpSigmaAl, tpcExpSigmaAl, float); //! Expected resolution with the TPC detector for alpha -// NSigma -DECLARE_SOA_COLUMN(TPCNSigmaEl, tpcNSigmaEl, float); //! Nsigma separation with the TPC detector for electron -DECLARE_SOA_COLUMN(TPCNSigmaMu, tpcNSigmaMu, float); //! Nsigma separation with the TPC detector for muon -DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); //! Nsigma separation with the TPC detector for pion -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(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(TPCNSigmaAl, tpcNSigmaAl, float); //! Nsigma separation with the TPC detector for alpha - -} // namespace pidtpc - -namespace pidtpc_tiny -{ - -struct binning { - public: - typedef int8_t 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); - static constexpr float binned_max = 6.35; - static constexpr float binned_min = -6.35; - static constexpr float bin_width = (binned_max - binned_min) / nbins; -}; - -// NSigma with reduced size -DECLARE_SOA_COLUMN(TPCNSigmaStoreEl, tpcNSigmaStoreEl, binning::binned_t); //! Stored binned nsigma with the TPC detector for electron -DECLARE_SOA_COLUMN(TPCNSigmaStoreMu, tpcNSigmaStoreMu, binning::binned_t); //! Stored binned nsigma with the TPC detector for muon -DECLARE_SOA_COLUMN(TPCNSigmaStorePi, tpcNSigmaStorePi, binning::binned_t); //! Stored binned nsigma with the TPC detector for pion -DECLARE_SOA_COLUMN(TPCNSigmaStoreKa, tpcNSigmaStoreKa, binning::binned_t); //! Stored binned nsigma with the TPC detector for kaon -DECLARE_SOA_COLUMN(TPCNSigmaStorePr, tpcNSigmaStorePr, binning::binned_t); //! Stored binned nsigma with the TPC detector for proton -DECLARE_SOA_COLUMN(TPCNSigmaStoreDe, tpcNSigmaStoreDe, binning::binned_t); //! Stored binned nsigma with the TPC detector for deuteron -DECLARE_SOA_COLUMN(TPCNSigmaStoreTr, tpcNSigmaStoreTr, binning::binned_t); //! Stored binned nsigma with the TPC detector for triton -DECLARE_SOA_COLUMN(TPCNSigmaStoreHe, tpcNSigmaStoreHe, binning::binned_t); //! Stored binned nsigma with the TPC detector for helium3 -DECLARE_SOA_COLUMN(TPCNSigmaStoreAl, tpcNSigmaStoreAl, binning::binned_t); //! Stored binned nsigma with the TPC detector for alpha -// NSigma with reduced size in [binned_min, binned_max] bin size bin_width -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaEl, tpcNSigmaEl); //! Unwrapped (float) nsigma with the TPC detector for electron -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaMu, tpcNSigmaMu); //! Unwrapped (float) nsigma with the TPC detector for muon -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaPi, tpcNSigmaPi); //! Unwrapped (float) nsigma with the TPC detector for pion -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaKa, tpcNSigmaKa); //! Unwrapped (float) nsigma with the TPC detector for kaon -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaPr, tpcNSigmaPr); //! Unwrapped (float) nsigma with the TPC detector for proton -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaDe, tpcNSigmaDe); //! Unwrapped (float) nsigma with the TPC detector for deuteron -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaTr, tpcNSigmaTr); //! Unwrapped (float) nsigma with the TPC detector for triton -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaHe, tpcNSigmaHe); //! Unwrapped (float) nsigma with the TPC detector for helium3 -DEFINE_UNWRAP_NSIGMA_COLUMN(TPCNSigmaAl, tpcNSigmaAl); //! Unwrapped (float) nsigma with the TPC detector for alpha - -} // namespace pidtpc_tiny - -// Per particle tables -DECLARE_SOA_TABLE(pidTPCFullEl, "AOD", "pidTPCFullEl", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for electron - pidtpc::TPCExpSignalEl, pidtpc::TPCExpSignalDiffEl, pidtpc::TPCExpSigmaEl, pidtpc::TPCNSigmaEl); -DECLARE_SOA_TABLE(pidTPCFullMu, "AOD", "pidTPCFullMu", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for muon - pidtpc::TPCExpSignalMu, pidtpc::TPCExpSignalDiffMu, pidtpc::TPCExpSigmaMu, pidtpc::TPCNSigmaMu); -DECLARE_SOA_TABLE(pidTPCFullPi, "AOD", "pidTPCFullPi", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for pion - pidtpc::TPCExpSignalPi, pidtpc::TPCExpSignalDiffPi, pidtpc::TPCExpSigmaPi, pidtpc::TPCNSigmaPi); -DECLARE_SOA_TABLE(pidTPCFullKa, "AOD", "pidTPCFullKa", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for kaon - pidtpc::TPCExpSignalKa, pidtpc::TPCExpSignalDiffKa, pidtpc::TPCExpSigmaKa, pidtpc::TPCNSigmaKa); -DECLARE_SOA_TABLE(pidTPCFullPr, "AOD", "pidTPCFullPr", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for proton - pidtpc::TPCExpSignalPr, pidtpc::TPCExpSignalDiffPr, pidtpc::TPCExpSigmaPr, pidtpc::TPCNSigmaPr); -DECLARE_SOA_TABLE(pidTPCFullDe, "AOD", "pidTPCFullDe", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for deuteron - pidtpc::TPCExpSignalDe, pidtpc::TPCExpSignalDiffDe, pidtpc::TPCExpSigmaDe, pidtpc::TPCNSigmaDe); -DECLARE_SOA_TABLE(pidTPCFullTr, "AOD", "pidTPCFullTr", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for triton - pidtpc::TPCExpSignalTr, pidtpc::TPCExpSignalDiffTr, pidtpc::TPCExpSigmaTr, pidtpc::TPCNSigmaTr); -DECLARE_SOA_TABLE(pidTPCFullHe, "AOD", "pidTPCFullHe", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for helium3 - pidtpc::TPCExpSignalHe, pidtpc::TPCExpSignalDiffHe, pidtpc::TPCExpSigmaHe, pidtpc::TPCNSigmaHe); -DECLARE_SOA_TABLE(pidTPCFullAl, "AOD", "pidTPCFullAl", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for alpha - pidtpc::TPCExpSignalAl, pidtpc::TPCExpSignalDiffAl, pidtpc::TPCExpSigmaAl, pidtpc::TPCNSigmaAl); - -// Tiny size tables -DECLARE_SOA_TABLE(pidTPCEl, "AOD", "pidTPCEl", //! Table of the TPC response with binned Nsigma for electron - pidtpc_tiny::TPCNSigmaStoreEl, pidtpc_tiny::TPCNSigmaEl); -DECLARE_SOA_TABLE(pidTPCMu, "AOD", "pidTPCMu", //! Table of the TPC response with binned Nsigma for muon - pidtpc_tiny::TPCNSigmaStoreMu, pidtpc_tiny::TPCNSigmaMu); -DECLARE_SOA_TABLE(pidTPCPi, "AOD", "pidTPCPi", //! Table of the TPC response with binned Nsigma for pion - pidtpc_tiny::TPCNSigmaStorePi, pidtpc_tiny::TPCNSigmaPi); -DECLARE_SOA_TABLE(pidTPCKa, "AOD", "pidTPCKa", //! Table of the TPC response with binned Nsigma for kaon - pidtpc_tiny::TPCNSigmaStoreKa, pidtpc_tiny::TPCNSigmaKa); -DECLARE_SOA_TABLE(pidTPCPr, "AOD", "pidTPCPr", //! Table of the TPC response with binned Nsigma for proton - pidtpc_tiny::TPCNSigmaStorePr, pidtpc_tiny::TPCNSigmaPr); -DECLARE_SOA_TABLE(pidTPCDe, "AOD", "pidTPCDe", //! Table of the TPC response with binned Nsigma for deuteron - pidtpc_tiny::TPCNSigmaStoreDe, pidtpc_tiny::TPCNSigmaDe); -DECLARE_SOA_TABLE(pidTPCTr, "AOD", "pidTPCTr", //! Table of the TPC response with binned Nsigma for triton - pidtpc_tiny::TPCNSigmaStoreTr, pidtpc_tiny::TPCNSigmaTr); -DECLARE_SOA_TABLE(pidTPCHe, "AOD", "pidTPCHe", //! Table of the TPC response with binned Nsigma for helium3 - pidtpc_tiny::TPCNSigmaStoreHe, pidtpc_tiny::TPCNSigmaHe); -DECLARE_SOA_TABLE(pidTPCAl, "AOD", "pidTPCAl", //! Table of the TPC response with binned Nsigma for alpha - pidtpc_tiny::TPCNSigmaStoreAl, pidtpc_tiny::TPCNSigmaAl); - -#undef DEFINE_UNWRAP_NSIGMA_COLUMN - -namespace pidbayes -{ -typedef int8_t binned_prob_t; -// Bayesian probabilities with reduced size -DECLARE_SOA_COLUMN(BayesEl, bayesEl, binned_prob_t); //! Bayesian probability for electron expressed in % -DECLARE_SOA_COLUMN(BayesMu, bayesMu, binned_prob_t); //! Bayesian probability for muon expressed in % -DECLARE_SOA_COLUMN(BayesPi, bayesPi, binned_prob_t); //! Bayesian probability for pion expressed in % -DECLARE_SOA_COLUMN(BayesKa, bayesKa, binned_prob_t); //! Bayesian probability for kaon expressed in % -DECLARE_SOA_COLUMN(BayesPr, bayesPr, binned_prob_t); //! Bayesian probability for proton expressed in % -DECLARE_SOA_COLUMN(BayesDe, bayesDe, binned_prob_t); //! Bayesian probability for deuteron expressed in % -DECLARE_SOA_COLUMN(BayesTr, bayesTr, binned_prob_t); //! Bayesian probability for triton expressed in % -DECLARE_SOA_COLUMN(BayesHe, bayesHe, binned_prob_t); //! Bayesian probability for helium3 expressed in % -DECLARE_SOA_COLUMN(BayesAl, bayesAl, binned_prob_t); //! Bayesian probability for alpha expressed in % -DECLARE_SOA_COLUMN(BayesProb, bayesProb, binned_prob_t); //! Bayesian probability of the most probable ID -DECLARE_SOA_COLUMN(BayesID, bayesID, o2::track::pid_constants::ID); //! Most probable ID - -} // namespace pidbayes - -// Table for each particle hypothesis -DECLARE_SOA_TABLE(pidBayesEl, "AOD", "pidBayesEl", //! Binned (in percentage) Bayesian probability of having a Electron - pidbayes::BayesEl); -DECLARE_SOA_TABLE(pidBayesMu, "AOD", "pidBayesMu", //! Binned (in percentage) Bayesian probability of having a Muon - pidbayes::BayesMu); -DECLARE_SOA_TABLE(pidBayesPi, "AOD", "pidBayesPi", //! Binned (in percentage) Bayesian probability of having a Pion - pidbayes::BayesPi); -DECLARE_SOA_TABLE(pidBayesKa, "AOD", "pidBayesKa", //! Binned (in percentage) Bayesian probability of having a Kaon - pidbayes::BayesKa); -DECLARE_SOA_TABLE(pidBayesPr, "AOD", "pidBayesPr", //! Binned (in percentage) Bayesian probability of having a Proton - pidbayes::BayesPr); -DECLARE_SOA_TABLE(pidBayesDe, "AOD", "pidBayesDe", //! Binned (in percentage) Bayesian probability of having a Deuteron - pidbayes::BayesDe); -DECLARE_SOA_TABLE(pidBayesTr, "AOD", "pidBayesTr", //! Binned (in percentage) Bayesian probability of having a Triton - pidbayes::BayesTr); -DECLARE_SOA_TABLE(pidBayesHe, "AOD", "pidBayesHe", //! Binned (in percentage) Bayesian probability of having a Helium3 - pidbayes::BayesHe); -DECLARE_SOA_TABLE(pidBayesAl, "AOD", "pidBayesAl", //! Binned (in percentage) Bayesian probability of having a Alpha - pidbayes::BayesAl); - -// Table for the most probable particle -DECLARE_SOA_TABLE(pidBayes, "AOD", "pidBayes", pidbayes::BayesProb, pidbayes::BayesID); //! Index of the most probable ID and its bayesian probability - } // namespace o2::aod #endif // COMMON_DATAMODEL_PIDRESPONSE_H_ diff --git a/Common/DataModel/PIDResponseCombined.h b/Common/DataModel/PIDResponseCombined.h new file mode 100644 index 00000000000..d18b2528c32 --- /dev/null +++ b/Common/DataModel/PIDResponseCombined.h @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file PIDResponseCombined.h +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Set of tables, tasks and utilities to provide the interface between +/// the analysis data model and the combined PID response +/// + +#ifndef COMMON_DATAMODEL_PIDRESPONSECOMBINED_H_ +#define COMMON_DATAMODEL_PIDRESPONSECOMBINED_H_ + +#include +#include +#include + +#include + +namespace o2::aod +{ + +namespace pidbayes +{ +typedef int8_t binned_prob_t; +// Bayesian probabilities with reduced size +DECLARE_SOA_COLUMN(BayesEl, bayesEl, binned_prob_t); //! Bayesian probability for electron expressed in % +DECLARE_SOA_COLUMN(BayesMu, bayesMu, binned_prob_t); //! Bayesian probability for muon expressed in % +DECLARE_SOA_COLUMN(BayesPi, bayesPi, binned_prob_t); //! Bayesian probability for pion expressed in % +DECLARE_SOA_COLUMN(BayesKa, bayesKa, binned_prob_t); //! Bayesian probability for kaon expressed in % +DECLARE_SOA_COLUMN(BayesPr, bayesPr, binned_prob_t); //! Bayesian probability for proton expressed in % +DECLARE_SOA_COLUMN(BayesDe, bayesDe, binned_prob_t); //! Bayesian probability for deuteron expressed in % +DECLARE_SOA_COLUMN(BayesTr, bayesTr, binned_prob_t); //! Bayesian probability for triton expressed in % +DECLARE_SOA_COLUMN(BayesHe, bayesHe, binned_prob_t); //! Bayesian probability for helium3 expressed in % +DECLARE_SOA_COLUMN(BayesAl, bayesAl, binned_prob_t); //! Bayesian probability for alpha expressed in % +DECLARE_SOA_COLUMN(BayesProb, bayesProb, binned_prob_t); //! Bayesian probability of the most probable ID +DECLARE_SOA_COLUMN(BayesID, bayesID, o2::track::pid_constants::ID); //! Most probable ID + +} // namespace pidbayes + +// Table for each particle hypothesis +DECLARE_SOA_TABLE(pidBayesEl, "AOD", "pidBayesEl", //! Binned (in percentage) Bayesian probability of having a Electron + pidbayes::BayesEl); +DECLARE_SOA_TABLE(pidBayesMu, "AOD", "pidBayesMu", //! Binned (in percentage) Bayesian probability of having a Muon + pidbayes::BayesMu); +DECLARE_SOA_TABLE(pidBayesPi, "AOD", "pidBayesPi", //! Binned (in percentage) Bayesian probability of having a Pion + pidbayes::BayesPi); +DECLARE_SOA_TABLE(pidBayesKa, "AOD", "pidBayesKa", //! Binned (in percentage) Bayesian probability of having a Kaon + pidbayes::BayesKa); +DECLARE_SOA_TABLE(pidBayesPr, "AOD", "pidBayesPr", //! Binned (in percentage) Bayesian probability of having a Proton + pidbayes::BayesPr); +DECLARE_SOA_TABLE(pidBayesDe, "AOD", "pidBayesDe", //! Binned (in percentage) Bayesian probability of having a Deuteron + pidbayes::BayesDe); +DECLARE_SOA_TABLE(pidBayesTr, "AOD", "pidBayesTr", //! Binned (in percentage) Bayesian probability of having a Triton + pidbayes::BayesTr); +DECLARE_SOA_TABLE(pidBayesHe, "AOD", "pidBayesHe", //! Binned (in percentage) Bayesian probability of having a Helium3 + pidbayes::BayesHe); +DECLARE_SOA_TABLE(pidBayesAl, "AOD", "pidBayesAl", //! Binned (in percentage) Bayesian probability of having a Alpha + pidbayes::BayesAl); + +// Table for the most probable particle +DECLARE_SOA_TABLE(pidBayes, "AOD", "pidBayes", pidbayes::BayesProb, pidbayes::BayesID); //! Index of the most probable ID and its bayesian probability + +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_PIDRESPONSECOMBINED_H_ diff --git a/Common/DataModel/PIDResponseITS.h b/Common/DataModel/PIDResponseITS.h new file mode 100644 index 00000000000..7a13c4cbfa1 --- /dev/null +++ b/Common/DataModel/PIDResponseITS.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 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_ + +#include "Common/Core/TableHelper.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +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[1] > -999.0 ? mResolutionParamsZ2[0] * std::erf((bg - mResolutionParamsZ2[1]) / mResolutionParamsZ2[2]) : mResolutionParamsZ2[0]; + } + return mResolutionParams[1] > -999.0 ? mResolutionParams[0] * std::erf((bg - mResolutionParams[1]) / mResolutionParams[2]) : mResolutionParams[0]; + } + + template + static float nSigmaITS(uint32_t itsClusterSizes, float momentum, float eta) + { + unsigned int charge = (id == o2::track::PID::Helium3 || id == o2::track::PID::Alpha) ? 2 : 1; + momentum *= charge; + 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; + } + + static void setMCDefaultParameters() + { + setParameters(1.63806, 1.58847, 2.52275, + 2.66505, 1.48405, 6.90453, + 1.40487e-01, -4.31078e-01, 1.50052, + 0.09, -999., -999.); + } + + /// Initialize the TOF response parameters in the init function of each task + /// \param initContext Initialization context. Gets the configuration parameters from the pidITS task + static void setParameters(o2::framework::InitContext& initContext, bool isMC = false) + { + float p0 = 0, p1 = 0, p2 = 0; + float p0_Z2 = 0, p1_Z2 = 0, p2_Z2 = 0; + float p0_res = 0, p1_res = 0, p2_res = 0; + float p0_res_Z2 = 0, p1_res_Z2 = 0, p2_res_Z2 = 0; + o2::framework::LabeledArray itsParams; + getTaskOptionValue(initContext, "its-pid", "itsParams", itsParams, true); + auto data = itsParams.getData(); + const int col = isMC ? 1 : 0; // 0 for Data, 1 for MC + if (data.rows != 2 || data.cols != 12) { + LOG(fatal) << "ITSResponse parameters not initialized, check the itsParams configuration"; + } + p0 = data(col, 0); + p1 = data(col, 1); + p2 = data(col, 2); + p0_Z2 = data(col, 3); + p1_Z2 = data(col, 4); + p2_Z2 = data(col, 5); + p0_res = data(col, 6); + p1_res = data(col, 7); + p2_res = data(col, 8); + p0_res_Z2 = data(col, 9); + p1_res_Z2 = data(col, 10); + p2_res_Z2 = data(col, 11); + + setParameters(p0, p1, p2, + p0_Z2, p1_Z2, p2_Z2, + p0_res, p1_res, p2_res, + p0_res_Z2, p1_res_Z2, 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 = {0.09, -999., -999.}; +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/PIDResponseTOF.h b/Common/DataModel/PIDResponseTOF.h new file mode 100644 index 00000000000..16ad2e8bf35 --- /dev/null +++ b/Common/DataModel/PIDResponseTOF.h @@ -0,0 +1,578 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file PIDResponseTOF.h +/// \since 2024-11-15 +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Set of tables, tasks and utilities to provide the interface between +/// the analysis data model and the PID response of the TOF +/// + +#ifndef COMMON_DATAMODEL_PIDRESPONSETOF_H_ +#define COMMON_DATAMODEL_PIDRESPONSETOF_H_ + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/PIDTOFParamService.h" + +#include +#include +#include +#include + +#include +#include + +namespace o2::aod +{ +namespace pidutils +{ + +// Checkers for TOF PID hypothesis availability (runtime) +template +using hasTOFEl = decltype(std::declval().tofNSigmaEl()); +template +using hasTOFMu = decltype(std::declval().tofNSigmaMu()); +template +using hasTOFPi = decltype(std::declval().tofNSigmaPi()); +template +using hasTOFKa = decltype(std::declval().tofNSigmaKa()); +template +using hasTOFPr = decltype(std::declval().tofNSigmaPr()); +template +using hasTOFDe = decltype(std::declval().tofNSigmaDe()); +template +using hasTOFTr = decltype(std::declval().tofNSigmaTr()); +template +using hasTOFHe = decltype(std::declval().tofNSigmaHe()); +template +using hasTOFAl = decltype(std::declval().tofNSigmaAl()); + +// PID index as template argument +#define perSpeciesWrapper(functionName) \ + template \ + auto functionName(const TrackType& track) \ + { \ + if constexpr (index == o2::track::PID::Electron) { \ + return track.functionName##El(); \ + } else if constexpr (index == o2::track::PID::Muon) { \ + return track.functionName##Mu(); \ + } else if constexpr (index == o2::track::PID::Pion) { \ + return track.functionName##Pi(); \ + } else if constexpr (index == o2::track::PID::Kaon) { \ + return track.functionName##Ka(); \ + } else if constexpr (index == o2::track::PID::Proton) { \ + return track.functionName##Pr(); \ + } else if constexpr (index == o2::track::PID::Deuteron) { \ + return track.functionName##De(); \ + } else if constexpr (index == o2::track::PID::Triton) { \ + return track.functionName##Tr(); \ + } else if constexpr (index == o2::track::PID::Helium3) { \ + return track.functionName##He(); \ + } else if constexpr (index == o2::track::PID::Alpha) { \ + return track.functionName##Al(); \ + } \ + } + +perSpeciesWrapper(tofNSigma); +perSpeciesWrapper(tofExpSigma); +template +auto tofExpSignal(const TrackType& track) +{ + if constexpr (index == o2::track::PID::Electron) { + return track.tofExpSignalEl(track.tofSignal()); + } else if constexpr (index == o2::track::PID::Muon) { + return track.tofExpSignalMu(track.tofSignal()); + } else if constexpr (index == o2::track::PID::Pion) { + return track.tofExpSignalPi(track.tofSignal()); + } else if constexpr (index == o2::track::PID::Kaon) { + return track.tofExpSignalKa(track.tofSignal()); + } else if constexpr (index == o2::track::PID::Proton) { + return track.tofExpSignalPr(track.tofSignal()); + } else if constexpr (index == o2::track::PID::Deuteron) { + return track.tofExpSignalDe(track.tofSignal()); + } else if constexpr (index == o2::track::PID::Triton) { + return track.tofExpSignalTr(track.tofSignal()); + } else if constexpr (index == o2::track::PID::Helium3) { + return track.tofExpSignalHe(track.tofSignal()); + } else if constexpr (index == o2::track::PID::Alpha) { + return track.tofExpSignalAl(track.tofSignal()); + } +} +perSpeciesWrapper(tofExpSignalDiff); + +#undef perSpeciesWrapper + +// PID index as function argument for TOF +#define perSpeciesWrapper(functionName) \ + template \ + auto functionName(const o2::track::PID::ID index, const TrackType& track) \ + { \ + switch (index) { \ + case o2::track::PID::Electron: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##El(); \ + } \ + case o2::track::PID::Muon: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Mu(); \ + } \ + case o2::track::PID::Pion: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Pi(); \ + } \ + case o2::track::PID::Kaon: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Ka(); \ + } \ + case o2::track::PID::Proton: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Pr(); \ + } \ + case o2::track::PID::Deuteron: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##De(); \ + } \ + case o2::track::PID::Triton: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Tr(); \ + } \ + case o2::track::PID::Helium3: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##He(); \ + } \ + case o2::track::PID::Alpha: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Al(); \ + } \ + default: \ + LOGF(fatal, "TOF PID table for PID index %i (%s) is not available", index, o2::track::PID::getName(index)); \ + return 0.f; \ + } \ + } + +perSpeciesWrapper(tofNSigma); +perSpeciesWrapper(tofExpSigma); +template +auto tofExpSignal(const o2::track::PID::ID index, const TrackType& track) +{ + switch (index) { + case o2::track::PID::Electron: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalEl(track.tofSignal()); + } + case o2::track::PID::Muon: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalMu(track.tofSignal()); + } + case o2::track::PID::Pion: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalPi(track.tofSignal()); + } + case o2::track::PID::Kaon: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalKa(track.tofSignal()); + } + case o2::track::PID::Proton: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalPr(track.tofSignal()); + } + case o2::track::PID::Deuteron: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalDe(track.tofSignal()); + } + case o2::track::PID::Triton: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalTr(track.tofSignal()); + } + case o2::track::PID::Helium3: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalHe(track.tofSignal()); + } + case o2::track::PID::Alpha: + if constexpr (std::experimental::is_detected::value) { + return track.tofExpSignalAl(track.tofSignal()); + } + default: + LOGF(fatal, "TOF PID table for PID index %i (%s) is not available", index, o2::track::PID::getName(index)); + return 0.f; + } +} +perSpeciesWrapper(tofExpSignalDiff); + +#undef perSpeciesWrapper + +} // namespace pidutils + +// Extra tables +namespace pidflags +{ + +namespace enums +{ +enum PIDFlags : uint8_t { + EvTimeUndef = 0x0, // Event collision not set, corresponding to the LHC Fill event time + EvTimeTOF = 0x1, // Event collision time from TOF + EvTimeT0AC = 0x2, // Event collision time from the FT0AC + EvTimeTOFT0AC = 0x4 // Event collision time from the TOF and FT0AC +}; +} + +DECLARE_SOA_COLUMN(GoodTOFMatch, goodTOFMatch, bool); //! Bool for the TOF PID information on the single track information +DECLARE_SOA_COLUMN(TOFFlags, tofFlags, uint8_t); //! Flag for the complementary TOF PID information for the event time +DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeDefined, isEvTimeDefined, //! True if the Event Time was computed with any method i.e. there is a usable event time + [](uint8_t flags) -> bool { return (flags > 0); }); +DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOF, isEvTimeTOF, //! True if the Event Time was computed with the TOF + [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeTOF) == enums::PIDFlags::EvTimeTOF; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeT0AC, isEvTimeT0AC, //! True if the Event Time was computed with the T0AC + [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeT0AC) == enums::PIDFlags::EvTimeT0AC; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOFT0AC, isEvTimeTOFT0AC, //! True if the Event Time was computed with the TOF and T0AC + [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeTOFT0AC) == enums::PIDFlags::EvTimeTOFT0AC; }); + +} // namespace pidflags + +DECLARE_SOA_TABLE(pidTOFFlags, "AOD", "pidTOFFlags", //! Table of the flags for TOF signal quality on the track level + pidflags::GoodTOFMatch); + +DECLARE_SOA_TABLE(pidEvTimeFlags, "AOD", "pidEvTimeFlags", //! Table of the PID flags for the event time tables + pidflags::TOFFlags, + pidflags::IsEvTimeDefined, + pidflags::IsEvTimeTOF, + pidflags::IsEvTimeT0AC, + pidflags::IsEvTimeTOFT0AC); + +namespace pidtofsignal +{ +DECLARE_SOA_COLUMN(TOFSignal, tofSignal, float); //! TOF signal from track time +DECLARE_SOA_DYNAMIC_COLUMN(EventCollisionTime, eventCollisionTime, //! Event collision time used for the track. Needs the TOF + [](float signal, float tMinusTexp, float texp) -> float { return texp + tMinusTexp - signal; }); + +} // namespace pidtofsignal + +DECLARE_SOA_TABLE(TOFSignal, "AOD", "TOFSignal", //! Table of the TOF signal + pidtofsignal::TOFSignal, + pidtofsignal::EventCollisionTime); + +namespace pidtofevtime +{ +DECLARE_SOA_COLUMN(TOFEvTime, tofEvTime, float); //! event time for TOF signal. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C +DECLARE_SOA_COLUMN(TOFEvTimeErr, tofEvTimeErr, float); //! event time error for TOF. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C +} // namespace pidtofevtime + +DECLARE_SOA_TABLE(TOFEvTime, "AOD", "TOFEvTime", //! Table of the TOF event time. One entry per track. + pidtofevtime::TOFEvTime, + pidtofevtime::TOFEvTimeErr); + +namespace pidtof +{ +// Expected signals +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalEl, tofExpSignalEl, //! Expected time for electron + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalMu, tofExpSignalMu, //! Expected time for muon + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalPi, tofExpSignalPi, //! Expected time for pion + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalKa, tofExpSignalKa, //! Expected time for kaon + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalPr, tofExpSignalPr, //! Expected time for proton + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDe, tofExpSignalDe, //! Expected time for deuteron + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalTr, tofExpSignalTr, //! Expected time for triton + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalHe, tofExpSignalHe, //! Expected time for helium3 + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalAl, tofExpSignalAl, //! Expected time for alpha + [](float nsigma, float sigma, float tofsignal) -> float { return tofsignal - nsigma * sigma; }); +// Delta with respect to signal +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffEl, tofExpSignalDiffEl, //! Difference between signal and expected for electron + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffMu, tofExpSignalDiffMu, //! Difference between signal and expected for muon + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffPi, tofExpSignalDiffPi, //! Difference between signal and expected for pion + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffKa, tofExpSignalDiffKa, //! Difference between signal and expected for kaon + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffPr, tofExpSignalDiffPr, //! Difference between signal and expected for proton + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffDe, tofExpSignalDiffDe, //! Difference between signal and expected for deuteron + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffTr, tofExpSignalDiffTr, //! Difference between signal and expected for triton + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffHe, tofExpSignalDiffHe, //! Difference between signal and expected for helium3 + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSignalDiffAl, tofExpSignalDiffAl, //! Difference between signal and expected for alpha + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +// Expected sigma +DECLARE_SOA_COLUMN(TOFExpSigmaEl, tofExpSigmaEl, float); //! Expected resolution with the TOF detector for electron +DECLARE_SOA_COLUMN(TOFExpSigmaMu, tofExpSigmaMu, float); //! Expected resolution with the TOF detector for muon +DECLARE_SOA_COLUMN(TOFExpSigmaPi, tofExpSigmaPi, float); //! Expected resolution with the TOF detector for pion +DECLARE_SOA_COLUMN(TOFExpSigmaKa, tofExpSigmaKa, float); //! Expected resolution with the TOF detector for kaon +DECLARE_SOA_COLUMN(TOFExpSigmaPr, tofExpSigmaPr, float); //! Expected resolution with the TOF detector for proton +DECLARE_SOA_COLUMN(TOFExpSigmaDe, tofExpSigmaDe, float); //! Expected resolution with the TOF detector for deuteron +DECLARE_SOA_COLUMN(TOFExpSigmaTr, tofExpSigmaTr, float); //! Expected resolution with the TOF detector for triton +DECLARE_SOA_COLUMN(TOFExpSigmaHe, tofExpSigmaHe, float); //! Expected resolution with the TOF detector for helium3 +DECLARE_SOA_COLUMN(TOFExpSigmaAl, tofExpSigmaAl, float); //! Expected resolution with the TOF detector for alpha +// NSigma +DECLARE_SOA_COLUMN(TOFNSigmaEl, tofNSigmaEl, float); //! Nsigma separation with the TOF detector for electron +DECLARE_SOA_COLUMN(TOFNSigmaMu, tofNSigmaMu, float); //! Nsigma separation with the TOF detector for muon +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(TOFNSigmaAl, tofNSigmaAl, float); //! Nsigma separation with the TOF detector for alpha + +//! Expected resolution with the TOF detector for electron (computed on the fly) +#define PERSPECIES_TOF_SIGMA_COLUMN(name, id) \ + DECLARE_SOA_DYNAMIC_COLUMN(TOFExpSigma##name##Imp, tofExpSigmaDyn##name, \ + [](float tofSignal, \ + float tofExpMom, \ + float momentum, \ + float eta, \ + float tofEvTimeErr) -> float { \ + return o2::pid::tof::TOFResponseImpl::expectedSigma(tofSignal, \ + tofExpMom, \ + momentum, \ + eta, \ + tofEvTimeErr); \ + }); + +PERSPECIES_TOF_SIGMA_COLUMN(El, o2::track::PID::Electron); +PERSPECIES_TOF_SIGMA_COLUMN(Mu, o2::track::PID::Muon); +PERSPECIES_TOF_SIGMA_COLUMN(Pi, o2::track::PID::Pion); +PERSPECIES_TOF_SIGMA_COLUMN(Ka, o2::track::PID::Kaon); +PERSPECIES_TOF_SIGMA_COLUMN(Pr, o2::track::PID::Proton); +PERSPECIES_TOF_SIGMA_COLUMN(De, o2::track::PID::Deuteron); +PERSPECIES_TOF_SIGMA_COLUMN(Tr, o2::track::PID::Triton); +PERSPECIES_TOF_SIGMA_COLUMN(He, o2::track::PID::Helium3); +PERSPECIES_TOF_SIGMA_COLUMN(Al, o2::track::PID::Alpha); +#undef PERSPECIES_TOF_SIGMA_COLUMN + +#define PERSPECIES_TOF_SEPARATION_COLUMN(name, id) \ + DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigma##name##Imp, tofNSigmaDyn##name, \ + [](const float tofSignal, \ + const float tofExpMom, \ + const float length, \ + const float momentum, \ + const float eta, \ + const float tofEvTime, \ + const float tofEvTimeErr) -> float { \ + return o2::pid::tof::TOFResponseImpl::nSigma(tofSignal, \ + tofExpMom, \ + length, \ + momentum, \ + eta, \ + tofEvTime, \ + tofEvTimeErr); \ + }); + +PERSPECIES_TOF_SEPARATION_COLUMN(El, o2::track::PID::Electron); +PERSPECIES_TOF_SEPARATION_COLUMN(Mu, o2::track::PID::Muon); +PERSPECIES_TOF_SEPARATION_COLUMN(Pi, o2::track::PID::Pion); +PERSPECIES_TOF_SEPARATION_COLUMN(Ka, o2::track::PID::Kaon); +PERSPECIES_TOF_SEPARATION_COLUMN(Pr, o2::track::PID::Proton); +PERSPECIES_TOF_SEPARATION_COLUMN(De, o2::track::PID::Deuteron); +PERSPECIES_TOF_SEPARATION_COLUMN(Tr, o2::track::PID::Triton); +PERSPECIES_TOF_SEPARATION_COLUMN(He, o2::track::PID::Helium3); +PERSPECIES_TOF_SEPARATION_COLUMN(Al, o2::track::PID::Alpha); +#undef PERSPECIES_TOF_SEPARATION_COLUMN + +} // namespace pidtof + +using TOFExpSigmaDynEl = pidtof::TOFExpSigmaElImp; +using TOFExpSigmaDynMu = pidtof::TOFExpSigmaMuImp; +using TOFExpSigmaDynPi = pidtof::TOFExpSigmaPiImp; +using TOFExpSigmaDynKa = pidtof::TOFExpSigmaKaImp; +using TOFExpSigmaDynPr = pidtof::TOFExpSigmaPrImp; +using TOFExpSigmaDynDe = pidtof::TOFExpSigmaDeImp; +using TOFExpSigmaDynTr = pidtof::TOFExpSigmaTrImp; +using TOFExpSigmaDynHe = pidtof::TOFExpSigmaHeImp; +using TOFExpSigmaDynAl = pidtof::TOFExpSigmaAlImp; + +using TOFNSigmaDynEl = pidtof::TOFNSigmaElImp; +using TOFNSigmaDynMu = pidtof::TOFNSigmaMuImp; +using TOFNSigmaDynPi = pidtof::TOFNSigmaPiImp; +using TOFNSigmaDynKa = pidtof::TOFNSigmaKaImp; +using TOFNSigmaDynPr = pidtof::TOFNSigmaPrImp; +using TOFNSigmaDynDe = pidtof::TOFNSigmaDeImp; +using TOFNSigmaDynTr = pidtof::TOFNSigmaTrImp; +using TOFNSigmaDynHe = pidtof::TOFNSigmaHeImp; +using TOFNSigmaDynAl = pidtof::TOFNSigmaAlImp; + +namespace pidtof_tiny +{ +struct binning { + public: + typedef int8_t 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); + static constexpr float binned_max = 6.35; + static constexpr float binned_min = -6.35; + static constexpr float bin_width = (binned_max - binned_min) / nbins; + + // Function to pack a float into a binned value in table + template + static void packInTable(const float& valueToBin, T& table) + { + if (valueToBin <= binned_min) { + table(underflowBin); + } else if (valueToBin >= binned_max) { + table(overflowBin); + } else if (valueToBin >= 0) { + table(static_cast((valueToBin / bin_width) + 0.5f)); + } else { + table(static_cast((valueToBin / bin_width) - 0.5f)); + } + } + + // Function to unpack a binned value into a float + static float unPackInTable(const binned_t& valueToUnpack) + { + return bin_width * static_cast(valueToUnpack); + } +}; + +// NSigma with reduced size 8 bit +DECLARE_SOA_COLUMN(TOFNSigmaStoreEl, tofNSigmaStoreEl, binning::binned_t); //! Stored binned nsigma with the TOF detector for electron +DECLARE_SOA_COLUMN(TOFNSigmaStoreMu, tofNSigmaStoreMu, binning::binned_t); //! Stored binned nsigma with the TOF detector for muon +DECLARE_SOA_COLUMN(TOFNSigmaStorePi, tofNSigmaStorePi, binning::binned_t); //! Stored binned nsigma with the TOF detector for pion +DECLARE_SOA_COLUMN(TOFNSigmaStoreKa, tofNSigmaStoreKa, binning::binned_t); //! Stored binned nsigma with the TOF detector for kaon +DECLARE_SOA_COLUMN(TOFNSigmaStorePr, tofNSigmaStorePr, binning::binned_t); //! Stored binned nsigma with the TOF detector for proton +DECLARE_SOA_COLUMN(TOFNSigmaStoreDe, tofNSigmaStoreDe, binning::binned_t); //! Stored binned nsigma with the TOF detector for deuteron +DECLARE_SOA_COLUMN(TOFNSigmaStoreTr, tofNSigmaStoreTr, binning::binned_t); //! Stored binned nsigma with the TOF detector for triton +DECLARE_SOA_COLUMN(TOFNSigmaStoreHe, tofNSigmaStoreHe, binning::binned_t); //! Stored binned nsigma with the TOF detector for helium3 +DECLARE_SOA_COLUMN(TOFNSigmaStoreAl, tofNSigmaStoreAl, binning::binned_t); //! Stored binned nsigma with the TOF detector for alpha + +// NSigma with reduced size in [binned_min, binned_max] bin size bin_width +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaEl, tofNSigmaEl, //! Unwrapped (float) nsigma with the TOF detector for electron + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaMu, tofNSigmaMu, //! Unwrapped (float) nsigma with the TOF detector for muon + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaPi, tofNSigmaPi, //! Unwrapped (float) nsigma with the TOF detector for pion + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaKa, tofNSigmaKa, //! Unwrapped (float) nsigma with the TOF detector for kaon + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaPr, tofNSigmaPr, //! Unwrapped (float) nsigma with the TOF detector for proton + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaDe, tofNSigmaDe, //! Unwrapped (float) nsigma with the TOF detector for deuteron + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaTr, tofNSigmaTr, //! Unwrapped (float) nsigma with the TOF detector for triton + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaHe, tofNSigmaHe, //! Unwrapped (float) nsigma with the TOF detector for helium3 + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigmaAl, tofNSigmaAl, //! Unwrapped (float) nsigma with the TOF detector for alpha + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); + +} // namespace pidtof_tiny + +// Per particle tables +DECLARE_SOA_TABLE(pidTOFFullEl, "AOD", "pidTOFFullEl", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for electron + pidtof::TOFExpSignalDiffEl, + pidtof::TOFExpSignalEl, + pidtof::TOFExpSigmaEl, pidtof::TOFNSigmaEl); +DECLARE_SOA_TABLE(pidTOFFullMu, "AOD", "pidTOFFullMu", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for muon + pidtof::TOFExpSignalDiffMu, + pidtof::TOFExpSignalMu, + pidtof::TOFExpSigmaMu, pidtof::TOFNSigmaMu); +DECLARE_SOA_TABLE(pidTOFFullPi, "AOD", "pidTOFFullPi", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for pion + pidtof::TOFExpSignalDiffPi, + pidtof::TOFExpSignalPi, + pidtof::TOFExpSigmaPi, pidtof::TOFNSigmaPi); +DECLARE_SOA_TABLE(pidTOFFullKa, "AOD", "pidTOFFullKa", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for kaon + pidtof::TOFExpSignalDiffKa, + pidtof::TOFExpSignalKa, + pidtof::TOFExpSigmaKa, pidtof::TOFNSigmaKa); +DECLARE_SOA_TABLE(pidTOFFullPr, "AOD", "pidTOFFullPr", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for proton + pidtof::TOFExpSignalDiffPr, + pidtof::TOFExpSignalPr, + pidtof::TOFExpSigmaPr, pidtof::TOFNSigmaPr); +DECLARE_SOA_TABLE(pidTOFFullDe, "AOD", "pidTOFFullDe", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for deuteron + pidtof::TOFExpSignalDiffDe, + pidtof::TOFExpSignalDe, + pidtof::TOFExpSigmaDe, pidtof::TOFNSigmaDe); +DECLARE_SOA_TABLE(pidTOFFullTr, "AOD", "pidTOFFullTr", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for triton + pidtof::TOFExpSignalDiffTr, + pidtof::TOFExpSignalTr, + pidtof::TOFExpSigmaTr, pidtof::TOFNSigmaTr); +DECLARE_SOA_TABLE(pidTOFFullHe, "AOD", "pidTOFFullHe", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for helium3 + pidtof::TOFExpSignalDiffHe, + pidtof::TOFExpSignalHe, + pidtof::TOFExpSigmaHe, pidtof::TOFNSigmaHe); +DECLARE_SOA_TABLE(pidTOFFullAl, "AOD", "pidTOFFullAl", //! Table of the TOF (full) response with expected signal, expected resolution and Nsigma for alpha + pidtof::TOFExpSignalDiffAl, + pidtof::TOFExpSignalAl, + pidtof::TOFExpSigmaAl, pidtof::TOFNSigmaAl); + +// Tiny size tables +DECLARE_SOA_TABLE(pidTOFEl, "AOD", "pidTOFEl", //! Table of the TOF response with binned Nsigma for electron + pidtof_tiny::TOFNSigmaStoreEl, pidtof_tiny::TOFNSigmaEl); +DECLARE_SOA_TABLE(pidTOFMu, "AOD", "pidTOFMu", //! Table of the TOF response with binned Nsigma for muon + pidtof_tiny::TOFNSigmaStoreMu, pidtof_tiny::TOFNSigmaMu); +DECLARE_SOA_TABLE(pidTOFPi, "AOD", "pidTOFPi", //! Table of the TOF response with binned Nsigma for pion + pidtof_tiny::TOFNSigmaStorePi, pidtof_tiny::TOFNSigmaPi); +DECLARE_SOA_TABLE(pidTOFKa, "AOD", "pidTOFKa", //! Table of the TOF response with binned Nsigma for kaon + pidtof_tiny::TOFNSigmaStoreKa, pidtof_tiny::TOFNSigmaKa); +DECLARE_SOA_TABLE(pidTOFPr, "AOD", "pidTOFPr", //! Table of the TOF response with binned Nsigma for proton + pidtof_tiny::TOFNSigmaStorePr, pidtof_tiny::TOFNSigmaPr); +DECLARE_SOA_TABLE(pidTOFDe, "AOD", "pidTOFDe", //! Table of the TOF response with binned Nsigma for deuteron + pidtof_tiny::TOFNSigmaStoreDe, pidtof_tiny::TOFNSigmaDe); +DECLARE_SOA_TABLE(pidTOFTr, "AOD", "pidTOFTr", //! Table of the TOF response with binned Nsigma for triton + pidtof_tiny::TOFNSigmaStoreTr, pidtof_tiny::TOFNSigmaTr); +DECLARE_SOA_TABLE(pidTOFHe, "AOD", "pidTOFHe", //! Table of the TOF response with binned Nsigma for helium3 + pidtof_tiny::TOFNSigmaStoreHe, pidtof_tiny::TOFNSigmaHe); +DECLARE_SOA_TABLE(pidTOFAl, "AOD", "pidTOFAl", //! Table of the TOF response with binned Nsigma for alpha + pidtof_tiny::TOFNSigmaStoreAl, pidtof_tiny::TOFNSigmaAl); + +namespace pidtofbeta +{ +DECLARE_SOA_COLUMN(Beta, beta, float); //! TOF beta +DECLARE_SOA_COLUMN(BetaError, betaerror, float); //! Uncertainty on the TOF beta +// Dynamic column, i.e. the future +DECLARE_SOA_DYNAMIC_COLUMN(TOFBetaImp, tofBeta, //! TOF Beta value + [](const float length, const float tofSignal, const float collisionTime) -> float { + return o2::pid::tof::Beta::GetBeta(length, tofSignal, collisionTime); + }); +// +DECLARE_SOA_COLUMN(ExpBetaEl, expbetael, float); //! Expected beta of electron +DECLARE_SOA_COLUMN(ExpBetaElError, expbetaelerror, float); //! Expected uncertainty on the beta of electron +// +DECLARE_SOA_COLUMN(SeparationBetaEl, separationbetael, float); //! Separation computed with the expected beta for electrons +DECLARE_SOA_DYNAMIC_COLUMN(DiffBetaEl, diffbetael, //! Difference between the measured and the expected beta for electrons + [](float beta, float expbetael) -> float { return beta - expbetael; }); +} // namespace pidtofbeta + +using TOFBeta = pidtofbeta::TOFBetaImp; + +DECLARE_SOA_TABLE(pidTOFbeta, "AOD", "pidTOFbeta", //! Table of the TOF beta + pidtofbeta::Beta, pidtofbeta::BetaError); + +namespace pidtofmass +{ +DECLARE_SOA_COLUMN(TOFMass, mass, float); //! TOF mass +// Dynamic column, i.e. the future +DECLARE_SOA_DYNAMIC_COLUMN(TOFMassImp, tofMass, //! TOF Mass value + [](const float length, const float tofSignal, const float collisionTime, const float momentum) -> float { + const float beta = o2::pid::tof::Beta::GetBeta(length, tofSignal, collisionTime); + return o2::pid::tof::TOFMass::GetTOFMass(momentum, beta); + }); +} // namespace pidtofmass + +using TOFMass = pidtofmass::TOFMassImp; + +DECLARE_SOA_TABLE(pidTOFmass, "AOD", "pidTOFmass", //! Table of the TOF mass + pidtofmass::TOFMass); + +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_PIDRESPONSETOF_H_ diff --git a/Common/DataModel/PIDResponseTPC.h b/Common/DataModel/PIDResponseTPC.h new file mode 100644 index 00000000000..66df7dc403f --- /dev/null +++ b/Common/DataModel/PIDResponseTPC.h @@ -0,0 +1,411 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file PIDResponseTPC.h +/// \since 2024-11-15 +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Set of tables, tasks and utilities to provide the interface between +/// the analysis data model and the PID response of the TPC +/// + +#ifndef COMMON_DATAMODEL_PIDRESPONSETPC_H_ +#define COMMON_DATAMODEL_PIDRESPONSETPC_H_ + +#include +#include +#include +#include + +#include +#include + +namespace o2::aod +{ +namespace pidutils +{ + +// Checkers for TPC PID hypothesis availability (runtime) +template +using hasTPCEl = decltype(std::declval().tpcNSigmaEl()); +template +using hasTPCMu = decltype(std::declval().tpcNSigmaMu()); +template +using hasTPCPi = decltype(std::declval().tpcNSigmaPi()); +template +using hasTPCKa = decltype(std::declval().tpcNSigmaKa()); +template +using hasTPCPr = decltype(std::declval().tpcNSigmaPr()); +template +using hasTPCDe = decltype(std::declval().tpcNSigmaDe()); +template +using hasTPCTr = decltype(std::declval().tpcNSigmaTr()); +template +using hasTPCHe = decltype(std::declval().tpcNSigmaHe()); +template +using hasTPCAl = decltype(std::declval().tpcNSigmaAl()); + +// PID index as template argument +#define perSpeciesWrapper(functionName) \ + template \ + auto functionName(const TrackType& track) \ + { \ + if constexpr (index == o2::track::PID::Electron) { \ + return track.functionName##El(); \ + } else if constexpr (index == o2::track::PID::Muon) { \ + return track.functionName##Mu(); \ + } else if constexpr (index == o2::track::PID::Pion) { \ + return track.functionName##Pi(); \ + } else if constexpr (index == o2::track::PID::Kaon) { \ + return track.functionName##Ka(); \ + } else if constexpr (index == o2::track::PID::Proton) { \ + return track.functionName##Pr(); \ + } else if constexpr (index == o2::track::PID::Deuteron) { \ + return track.functionName##De(); \ + } else if constexpr (index == o2::track::PID::Triton) { \ + return track.functionName##Tr(); \ + } else if constexpr (index == o2::track::PID::Helium3) { \ + return track.functionName##He(); \ + } else if constexpr (index == o2::track::PID::Alpha) { \ + return track.functionName##Al(); \ + } \ + } + +perSpeciesWrapper(tpcNSigma); +perSpeciesWrapper(tpcExpSigma); +template +auto tpcExpSignal(const TrackType& track) +{ + if constexpr (index == o2::track::PID::Electron) { + return track.tpcExpSignalEl(track.tpcSignal()); + } else if constexpr (index == o2::track::PID::Muon) { + return track.tpcExpSignalMu(track.tpcSignal()); + } else if constexpr (index == o2::track::PID::Pion) { + return track.tpcExpSignalPi(track.tpcSignal()); + } else if constexpr (index == o2::track::PID::Kaon) { + return track.tpcExpSignalKa(track.tpcSignal()); + } else if constexpr (index == o2::track::PID::Proton) { + return track.tpcExpSignalPr(track.tpcSignal()); + } else if constexpr (index == o2::track::PID::Deuteron) { + return track.tpcExpSignalDe(track.tpcSignal()); + } else if constexpr (index == o2::track::PID::Triton) { + return track.tpcExpSignalTr(track.tpcSignal()); + } else if constexpr (index == o2::track::PID::Helium3) { + return track.tpcExpSignalHe(track.tpcSignal()); + } else if constexpr (index == o2::track::PID::Alpha) { + return track.tpcExpSignalAl(track.tpcSignal()); + } +} +perSpeciesWrapper(tpcExpSignalDiff); + +#undef perSpeciesWrapper + +// PID index as function argument for TPC +#define perSpeciesWrapper(functionName) \ + template \ + auto functionName(const o2::track::PID::ID index, const TrackType& track) \ + { \ + switch (index) { \ + case o2::track::PID::Electron: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##El(); \ + } \ + case o2::track::PID::Muon: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Mu(); \ + } \ + case o2::track::PID::Pion: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Pi(); \ + } \ + case o2::track::PID::Kaon: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Ka(); \ + } \ + case o2::track::PID::Proton: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Pr(); \ + } \ + case o2::track::PID::Deuteron: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##De(); \ + } \ + case o2::track::PID::Triton: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Tr(); \ + } \ + case o2::track::PID::Helium3: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##He(); \ + } \ + case o2::track::PID::Alpha: \ + if constexpr (std::experimental::is_detected::value) { \ + return track.functionName##Al(); \ + } \ + default: \ + LOGF(fatal, "TPC PID table for PID index %i (%s) is not available", index, o2::track::PID::getName(index)); \ + return 0.f; \ + } \ + } + +perSpeciesWrapper(tpcNSigma); +perSpeciesWrapper(tpcExpSigma); +template +auto tpcExpSignal(const o2::track::PID::ID index, const TrackType& track) +{ + switch (index) { + case o2::track::PID::Electron: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalEl(track.tpcSignal()); + } + case o2::track::PID::Muon: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalMu(track.tpcSignal()); + } + case o2::track::PID::Pion: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalPi(track.tpcSignal()); + } + case o2::track::PID::Kaon: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalKa(track.tpcSignal()); + } + case o2::track::PID::Proton: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalPr(track.tpcSignal()); + } + case o2::track::PID::Deuteron: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalDe(track.tpcSignal()); + } + case o2::track::PID::Triton: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalTr(track.tpcSignal()); + } + case o2::track::PID::Helium3: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalHe(track.tpcSignal()); + } + case o2::track::PID::Alpha: + if constexpr (std::experimental::is_detected::value) { + return track.tpcExpSignalAl(track.tpcSignal()); + } + default: + LOGF(fatal, "TPC PID table for PID index %i (%s) is not available", index, o2::track::PID::getName(index)); + return 0.f; + } +} +perSpeciesWrapper(tpcExpSignalDiff); + +#undef perSpeciesWrapper + +} // namespace pidutils + +namespace pidtpc +{ +// Expected signals +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalEl, tpcExpSignalEl, //! Expected signal with the TPC detector for electron + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalMu, tpcExpSignalMu, //! Expected signal with the TPC detector for muon + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalPi, tpcExpSignalPi, //! Expected signal with the TPC detector for pion + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalKa, tpcExpSignalKa, //! Expected signal with the TPC detector for kaon + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalPr, tpcExpSignalPr, //! Expected signal with the TPC detector for proton + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDe, tpcExpSignalDe, //! Expected signal with the TPC detector for deuteron + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalTr, tpcExpSignalTr, //! Expected signal with the TPC detector for triton + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalHe, tpcExpSignalHe, //! Expected signal with the TPC detector for helium3 + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalAl, tpcExpSignalAl, //! Expected signal with the TPC detector for alpha + [](float nsigma, float sigma, float tpcsignal) -> float { return tpcsignal - nsigma * sigma; }); +// Delta with respect to signal +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffEl, tpcExpSignalDiffEl, //! Difference between signal and expected for electron + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffMu, tpcExpSignalDiffMu, //! Difference between signal and expected for muon + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffPi, tpcExpSignalDiffPi, //! Difference between signal and expected for pion + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffKa, tpcExpSignalDiffKa, //! Difference between signal and expected for kaon + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffPr, tpcExpSignalDiffPr, //! Difference between signal and expected for proton + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffDe, tpcExpSignalDiffDe, //! Difference between signal and expected for deuteron + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffTr, tpcExpSignalDiffTr, //! Difference between signal and expected for triton + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffHe, tpcExpSignalDiffHe, //! Difference between signal and expected for helium3 + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCExpSignalDiffAl, tpcExpSignalDiffAl, //! Difference between signal and expected for alpha + [](float nsigma, float sigma) -> float { return nsigma * sigma; }); +// Expected sigma +DECLARE_SOA_COLUMN(TPCExpSigmaEl, tpcExpSigmaEl, float); //! Expected resolution with the TPC detector for electron +DECLARE_SOA_COLUMN(TPCExpSigmaMu, tpcExpSigmaMu, float); //! Expected resolution with the TPC detector for muon +DECLARE_SOA_COLUMN(TPCExpSigmaPi, tpcExpSigmaPi, float); //! Expected resolution with the TPC detector for pion +DECLARE_SOA_COLUMN(TPCExpSigmaKa, tpcExpSigmaKa, float); //! Expected resolution with the TPC detector for kaon +DECLARE_SOA_COLUMN(TPCExpSigmaPr, tpcExpSigmaPr, float); //! Expected resolution with the TPC detector for proton +DECLARE_SOA_COLUMN(TPCExpSigmaDe, tpcExpSigmaDe, float); //! Expected resolution with the TPC detector for deuteron +DECLARE_SOA_COLUMN(TPCExpSigmaTr, tpcExpSigmaTr, float); //! Expected resolution with the TPC detector for triton +DECLARE_SOA_COLUMN(TPCExpSigmaHe, tpcExpSigmaHe, float); //! Expected resolution with the TPC detector for helium3 +DECLARE_SOA_COLUMN(TPCExpSigmaAl, tpcExpSigmaAl, float); //! Expected resolution with the TPC detector for alpha +// NSigma +DECLARE_SOA_COLUMN(TPCNSigmaEl, tpcNSigmaEl, float); //! Nsigma separation with the TPC detector for electron +DECLARE_SOA_COLUMN(TPCNSigmaMu, tpcNSigmaMu, float); //! Nsigma separation with the TPC detector for muon +DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); //! Nsigma separation with the TPC detector for pion +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(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(TPCNSigmaAl, tpcNSigmaAl, float); //! Nsigma separation with the TPC detector for alpha + +} // namespace pidtpc + +namespace pidtpc_tiny +{ +struct binning { + public: + typedef int8_t 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); + static constexpr float binned_max = 6.35; + static constexpr float binned_min = -6.35; + static constexpr float bin_width = (binned_max - binned_min) / nbins; + + // Function to pack a float into a binned value in table + template + static void packInTable(const float& valueToBin, T& table) + { + if (valueToBin <= binned_min) { + table(underflowBin); + } else if (valueToBin >= binned_max) { + table(overflowBin); + } else if (valueToBin >= 0) { + table(static_cast((valueToBin / bin_width) + 0.5f)); + } else { + table(static_cast((valueToBin / bin_width) - 0.5f)); + } + } + + // Function to unpack a binned value into a float + static float unPackInTable(const binned_t& valueToUnpack) + { + return bin_width * static_cast(valueToUnpack); + } +}; + +// NSigma with reduced size 8 bit +DECLARE_SOA_COLUMN(TPCNSigmaStoreEl, tpcNSigmaStoreEl, binning::binned_t); //! Stored binned nsigma with the TPC detector for electron +DECLARE_SOA_COLUMN(TPCNSigmaStoreMu, tpcNSigmaStoreMu, binning::binned_t); //! Stored binned nsigma with the TPC detector for muon +DECLARE_SOA_COLUMN(TPCNSigmaStorePi, tpcNSigmaStorePi, binning::binned_t); //! Stored binned nsigma with the TPC detector for pion +DECLARE_SOA_COLUMN(TPCNSigmaStoreKa, tpcNSigmaStoreKa, binning::binned_t); //! Stored binned nsigma with the TPC detector for kaon +DECLARE_SOA_COLUMN(TPCNSigmaStorePr, tpcNSigmaStorePr, binning::binned_t); //! Stored binned nsigma with the TPC detector for proton +DECLARE_SOA_COLUMN(TPCNSigmaStoreDe, tpcNSigmaStoreDe, binning::binned_t); //! Stored binned nsigma with the TPC detector for deuteron +DECLARE_SOA_COLUMN(TPCNSigmaStoreTr, tpcNSigmaStoreTr, binning::binned_t); //! Stored binned nsigma with the TPC detector for triton +DECLARE_SOA_COLUMN(TPCNSigmaStoreHe, tpcNSigmaStoreHe, binning::binned_t); //! Stored binned nsigma with the TPC detector for helium3 +DECLARE_SOA_COLUMN(TPCNSigmaStoreAl, tpcNSigmaStoreAl, binning::binned_t); //! Stored binned nsigma with the TPC detector for alpha + +// NSigma with reduced size in [binned_min, binned_max] bin size bin_width +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaEl, tpcNSigmaEl, //! Unwrapped (float) nsigma with the TPC detector for electron + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaMu, tpcNSigmaMu, //! Unwrapped (float) nsigma with the TPC detector for muon + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaPi, tpcNSigmaPi, //! Unwrapped (float) nsigma with the TPC detector for pion + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaKa, tpcNSigmaKa, //! Unwrapped (float) nsigma with the TPC detector for kaon + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaPr, tpcNSigmaPr, //! Unwrapped (float) nsigma with the TPC detector for proton + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaDe, tpcNSigmaDe, //! Unwrapped (float) nsigma with the TPC detector for deuteron + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaTr, tpcNSigmaTr, //! Unwrapped (float) nsigma with the TPC detector for triton + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaHe, tpcNSigmaHe, //! Unwrapped (float) nsigma with the TPC detector for helium3 + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaAl, tpcNSigmaAl, //! Unwrapped (float) nsigma with the TPC detector for alpha + [](binning::binned_t nsigma_binned) -> float { return binning::unPackInTable(nsigma_binned); }); + +} // namespace pidtpc_tiny + +// Per particle tables +DECLARE_SOA_TABLE(pidTPCFullEl, "AOD", "pidTPCFullEl", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for electron + pidtpc::TPCExpSignalEl, + pidtpc::TPCExpSignalDiffEl, + pidtpc::TPCExpSigmaEl, pidtpc::TPCNSigmaEl); +DECLARE_SOA_TABLE(pidTPCFullMu, "AOD", "pidTPCFullMu", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for muon + pidtpc::TPCExpSignalMu, + pidtpc::TPCExpSignalDiffMu, + pidtpc::TPCExpSigmaMu, pidtpc::TPCNSigmaMu); +DECLARE_SOA_TABLE(pidTPCFullPi, "AOD", "pidTPCFullPi", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for pion + pidtpc::TPCExpSignalPi, + pidtpc::TPCExpSignalDiffPi, + pidtpc::TPCExpSigmaPi, pidtpc::TPCNSigmaPi); +DECLARE_SOA_TABLE(pidTPCFullKa, "AOD", "pidTPCFullKa", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for kaon + pidtpc::TPCExpSignalKa, + pidtpc::TPCExpSignalDiffKa, + pidtpc::TPCExpSigmaKa, pidtpc::TPCNSigmaKa); +DECLARE_SOA_TABLE(pidTPCFullPr, "AOD", "pidTPCFullPr", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for proton + pidtpc::TPCExpSignalPr, + pidtpc::TPCExpSignalDiffPr, + pidtpc::TPCExpSigmaPr, pidtpc::TPCNSigmaPr); +DECLARE_SOA_TABLE(pidTPCFullDe, "AOD", "pidTPCFullDe", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for deuteron + pidtpc::TPCExpSignalDe, + pidtpc::TPCExpSignalDiffDe, + pidtpc::TPCExpSigmaDe, pidtpc::TPCNSigmaDe); +DECLARE_SOA_TABLE(pidTPCFullTr, "AOD", "pidTPCFullTr", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for triton + pidtpc::TPCExpSignalTr, + pidtpc::TPCExpSignalDiffTr, + pidtpc::TPCExpSigmaTr, pidtpc::TPCNSigmaTr); +DECLARE_SOA_TABLE(pidTPCFullHe, "AOD", "pidTPCFullHe", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for helium3 + pidtpc::TPCExpSignalHe, + pidtpc::TPCExpSignalDiffHe, + pidtpc::TPCExpSigmaHe, pidtpc::TPCNSigmaHe); +DECLARE_SOA_TABLE(pidTPCFullAl, "AOD", "pidTPCFullAl", //! Table of the TPC (full) response with expected signal, expected resolution and Nsigma for alpha + pidtpc::TPCExpSignalAl, + pidtpc::TPCExpSignalDiffAl, + pidtpc::TPCExpSigmaAl, pidtpc::TPCNSigmaAl); + +// Tiny size tables +DECLARE_SOA_TABLE(pidTPCEl, "AOD", "pidTPCEl", //! Table of the TPC response with binned Nsigma for electron + pidtpc_tiny::TPCNSigmaStoreEl, pidtpc_tiny::TPCNSigmaEl); +DECLARE_SOA_TABLE(pidTPCMu, "AOD", "pidTPCMu", //! Table of the TPC response with binned Nsigma for muon + pidtpc_tiny::TPCNSigmaStoreMu, pidtpc_tiny::TPCNSigmaMu); +DECLARE_SOA_TABLE(pidTPCPi, "AOD", "pidTPCPi", //! Table of the TPC response with binned Nsigma for pion + pidtpc_tiny::TPCNSigmaStorePi, pidtpc_tiny::TPCNSigmaPi); +DECLARE_SOA_TABLE(pidTPCKa, "AOD", "pidTPCKa", //! Table of the TPC response with binned Nsigma for kaon + pidtpc_tiny::TPCNSigmaStoreKa, pidtpc_tiny::TPCNSigmaKa); +DECLARE_SOA_TABLE(pidTPCPr, "AOD", "pidTPCPr", //! Table of the TPC response with binned Nsigma for proton + pidtpc_tiny::TPCNSigmaStorePr, pidtpc_tiny::TPCNSigmaPr); +DECLARE_SOA_TABLE(pidTPCDe, "AOD", "pidTPCDe", //! Table of the TPC response with binned Nsigma for deuteron + pidtpc_tiny::TPCNSigmaStoreDe, pidtpc_tiny::TPCNSigmaDe); +DECLARE_SOA_TABLE(pidTPCTr, "AOD", "pidTPCTr", //! Table of the TPC response with binned Nsigma for triton + pidtpc_tiny::TPCNSigmaStoreTr, pidtpc_tiny::TPCNSigmaTr); +DECLARE_SOA_TABLE(pidTPCHe, "AOD", "pidTPCHe", //! Table of the TPC response with binned Nsigma for helium3 + pidtpc_tiny::TPCNSigmaStoreHe, pidtpc_tiny::TPCNSigmaHe); +DECLARE_SOA_TABLE(pidTPCAl, "AOD", "pidTPCAl", //! Table of the TPC response with binned Nsigma for alpha + pidtpc_tiny::TPCNSigmaStoreAl, pidtpc_tiny::TPCNSigmaAl); + +// Extra tables +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 o2::aod + +#endif // COMMON_DATAMODEL_PIDRESPONSETPC_H_ diff --git a/Common/DataModel/PmdTable.h b/Common/DataModel/PmdTable.h new file mode 100644 index 00000000000..5efd66df32e --- /dev/null +++ b/Common/DataModel/PmdTable.h @@ -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. +/// +/// \file PmdTable.h +/// +/// \brief pmd index table define +/// \author Abhi Modak (abhi.modak@cern.ch) +/// \since May 17, 2025 + +#ifndef COMMON_DATAMODEL_PMDTABLE_H_ +#define COMMON_DATAMODEL_PMDTABLE_H_ + +#include + +namespace o2::aod +{ +namespace pmdtrack +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_ARRAY_INDEX_COLUMN(Collision, collisions); +DECLARE_SOA_INDEX_COLUMN(BC, bc); +DECLARE_SOA_SLICE_INDEX_COLUMN(Pmd, pmd); +} // namespace pmdtrack + +DECLARE_SOA_INDEX_TABLE_USER(PMDTracksIndex, BCs, "PMDTRKIDX", pmdtrack::CollisionId, pmdtrack::BCId, pmdtrack::PmdIdSlice); +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_PMDTABLE_H_ diff --git a/Common/DataModel/Qvectors.h b/Common/DataModel/Qvectors.h index 2185e1bb7c2..4a750306cbf 100644 --- a/Common/DataModel/Qvectors.h +++ b/Common/DataModel/Qvectors.h @@ -21,8 +21,9 @@ #ifndef COMMON_DATAMODEL_QVECTORS_H_ #define COMMON_DATAMODEL_QVECTORS_H_ +#include + #include -#include "Framework/AnalysisDataModel.h" namespace o2::aod { @@ -43,12 +44,30 @@ 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(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(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(QvecShiftedRe, qvecShiftedRe, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedIm, qvecShiftedIm, std::vector); + +DECLARE_SOA_COLUMN(QvecShiftedFT0CReVec, qvecShiftedFT0CReVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedFT0CImVec, qvecShiftedFT0CImVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedFT0AReVec, qvecShiftedFT0AReVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedFT0AImVec, qvecShiftedFT0AImVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedFT0MReVec, qvecShiftedFT0MReVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedFT0MImVec, qvecShiftedFT0MImVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedFV0AReVec, qvecShiftedFV0AReVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedFV0AImVec, qvecShiftedFV0AImVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedTPCposReVec, qvecShiftedTPCposReVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedTPCposImVec, qvecShiftedTPCposImVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedTPCnegReVec, qvecShiftedTPCnegReVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedTPCnegImVec, qvecShiftedTPCnegImVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedTPCallReVec, qvecShiftedTPCallReVec, std::vector); +DECLARE_SOA_COLUMN(QvecShiftedTPCallImVec, qvecShiftedTPCallImVec, std::vector); DECLARE_SOA_COLUMN(QvecFT0CRe, qvecFT0CRe, float); DECLARE_SOA_COLUMN(QvecFT0CIm, qvecFT0CIm, float); @@ -58,6 +77,32 @@ 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(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); @@ -65,53 +110,87 @@ DECLARE_SOA_COLUMN(QvecBNegIm, qvecBNegIm, float); DECLARE_SOA_COLUMN(QvecBTotRe, qvecBTotRe, float); DECLARE_SOA_COLUMN(QvecBTotIm, qvecBTotIm, 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(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::IsCalibrated, qvec::QvecRe, qvec::QvecIm, qvec::QvecAmp); using Qvector = Qvectors::iterator; +DECLARE_SOA_TABLE(QvectorsShifteds, "AOD", "QVECTORSCDEVS", //! Table with all shifted Qvectors. + qvec::Cent, qvec::IsCalibrated, qvec::QvecShiftedRe, qvec::QvecShiftedIm, qvec::QvecAmp); +using QvectorShifted = QvectorsShifteds::iterator; 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(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(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(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); +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); + +DECLARE_SOA_TABLE(QvectorShiftedFT0CVecs, "AOD", "QVECSHIFTEDFT0C", qvec::IsCalibrated, qvec::QvecShiftedFT0CReVec, qvec::QvecShiftedFT0CImVec, qvec::SumAmplFT0C); +DECLARE_SOA_TABLE(QvectorShiftedFT0AVecs, "AOD", "QVECSHIFTEDFT0A", qvec::IsCalibrated, qvec::QvecShiftedFT0AReVec, qvec::QvecShiftedFT0AImVec, qvec::SumAmplFT0A); +DECLARE_SOA_TABLE(QvectorShiftedFT0MVecs, "AOD", "QVECSHIFTEDFT0M", qvec::IsCalibrated, qvec::QvecShiftedFT0MReVec, qvec::QvecShiftedFT0MImVec, qvec::SumAmplFT0M); +DECLARE_SOA_TABLE(QvectorShiftedFV0AVecs, "AOD", "QVECSHIFTEDFV0A", qvec::IsCalibrated, qvec::QvecShiftedFV0AReVec, qvec::QvecShiftedFV0AImVec, qvec::SumAmplFV0A); +DECLARE_SOA_TABLE(QvectorShiftedTPCposVecs, "AOD", "QVECSHIFTEDTPCP", qvec::IsCalibrated, qvec::QvecShiftedTPCposReVec, qvec::QvecShiftedTPCposImVec, qvec::NTrkTPCpos, qvec::LabelsTPCpos); +DECLARE_SOA_TABLE(QvectorShiftedTPCnegVecs, "AOD", "QVECSHIFTEDTPCN", qvec::IsCalibrated, qvec::QvecShiftedTPCnegReVec, qvec::QvecShiftedTPCnegImVec, qvec::NTrkTPCneg, qvec::LabelsTPCneg); +DECLARE_SOA_TABLE(QvectorShiftedTPCallVecs, "AOD", "QVECSHIFTEDTPCA", qvec::IsCalibrated, qvec::QvecShiftedTPCallReVec, qvec::QvecShiftedTPCallImVec, qvec::NTrkTPCall, qvec::LabelsTPCall); using QvectorFT0C = QvectorFT0Cs::iterator; using QvectorFT0A = QvectorFT0As::iterator; using QvectorFT0M = QvectorFT0Ms::iterator; using QvectorFV0A = QvectorFV0As::iterator; -using QvectorBPos = QvectorBPoss::iterator; -using QvectorBNeg = QvectorBNegs::iterator; -using QvectorBTot = QvectorBTots::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; + +using QvectorShiftedFT0CVec = QvectorShiftedFT0CVecs::iterator; +using QvectorShiftedFT0AVec = QvectorShiftedFT0AVecs::iterator; +using QvectorShiftedFT0MVec = QvectorShiftedFT0MVecs::iterator; +using QvectorShiftedFV0AVec = QvectorShiftedFV0AVecs::iterator; +using QvectorShiftedTPCposVec = QvectorShiftedTPCposVecs::iterator; +using QvectorShiftedTPCnegVec = QvectorShiftedTPCnegVecs::iterator; +using QvectorShiftedTPCallVec = QvectorShiftedTPCallVecs::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/SelectionStudyTables.h b/Common/DataModel/SelectionStudyTables.h new file mode 100644 index 00000000000..e2c14375ab1 --- /dev/null +++ b/Common/DataModel/SelectionStudyTables.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 SelectionStudyTables +/// \brief tables meant to do event selection studies for O-O / light systems +/// +/// \author ALICE + +#include +#include + +#include + +#ifndef COMMON_DATAMODEL_SELECTIONSTUDYTABLES_H_ +#define COMMON_DATAMODEL_SELECTIONSTUDYTABLES_H_ + +namespace o2::aod +{ +namespace selectionstudy +{ +DECLARE_SOA_COLUMN(PtPions, ptPions, std::vector); +DECLARE_SOA_COLUMN(PtKaons, ptKaons, std::vector); +DECLARE_SOA_COLUMN(PtProtons, ptProtons, std::vector); +DECLARE_SOA_COLUMN(PtK0s, ptPK0s, std::vector); +DECLARE_SOA_COLUMN(PtLambdas, ptLambdas, std::vector); +DECLARE_SOA_COLUMN(PtXis, ptXis, std::vector); +DECLARE_SOA_COLUMN(PtOmegas, ptOmegas, std::vector); +DECLARE_SOA_COLUMN(PtPhis, ptPhis, std::vector); +DECLARE_SOA_COLUMN(PtKStars, ptKStars, std::vector); +DECLARE_SOA_COLUMN(PtDs, ptDs, std::vector); +DECLARE_SOA_COLUMN(PtLambdaCs, ptLambdaCs, std::vector); +DECLARE_SOA_COLUMN(PtJPsis, ptJPsis, std::vector); +} // namespace selectionstudy + +DECLARE_SOA_TABLE(PIDPts, "AOD", "PIDPTS", o2::soa::Index<>, + o2::aod::selectionstudy::PtPions, + o2::aod::selectionstudy::PtKaons, + o2::aod::selectionstudy::PtProtons, + o2::aod::selectionstudy::PtK0s, + o2::aod::selectionstudy::PtLambdas, + o2::aod::selectionstudy::PtXis, + o2::aod::selectionstudy::PtOmegas, + o2::aod::selectionstudy::PtPhis, + o2::aod::selectionstudy::PtKStars, + o2::aod::selectionstudy::PtDs, + o2::aod::selectionstudy::PtLambdaCs, + o2::aod::selectionstudy::PtJPsis); +} // namespace o2::aod +#endif // COMMON_DATAMODEL_SELECTIONSTUDYTABLES_H_ diff --git a/Common/DataModel/TrackSelectionTables.h b/Common/DataModel/TrackSelectionTables.h index cc27e06bfe7..b710ff89ac1 100644 --- a/Common/DataModel/TrackSelectionTables.h +++ b/Common/DataModel/TrackSelectionTables.h @@ -12,7 +12,9 @@ #ifndef COMMON_DATAMODEL_TRACKSELECTIONTABLES_H_ #define COMMON_DATAMODEL_TRACKSELECTIONTABLES_H_ -#include "Framework/AnalysisDataModel.h" +#include + +#include namespace o2::aod { @@ -60,6 +62,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/ZDCExtra.h b/Common/DataModel/ZDCExtra.h new file mode 100644 index 00000000000..5232b0519c3 --- /dev/null +++ b/Common/DataModel/ZDCExtra.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 ZDCExtra.h +/// \brief ZDC extra table producer +/// \author Chiara Oppedisano , INFN Torino +/// \author Uliana Dmitrieva , INFN Torino + +#ifndef COMMON_DATAMODEL_ZDCEXTRA_H_ +#define COMMON_DATAMODEL_ZDCEXTRA_H_ + +#include + +#include + +namespace o2::aod +{ +namespace zdcextra +{ +DECLARE_SOA_COLUMN(ZnaTowC, znaTowC, float); //! Common tower ZNA +DECLARE_SOA_COLUMN(ZnaTow1, znaTow1, float); //! Tower 1 ZNA +DECLARE_SOA_COLUMN(ZnaTow2, znaTow2, float); //! Tower 2 ZNA +DECLARE_SOA_COLUMN(ZnaTow3, znaTow3, float); //! Tower 3 ZNA +DECLARE_SOA_COLUMN(ZnaTow4, znaTow4, float); //! Tower 4 ZNA +DECLARE_SOA_COLUMN(ZnaTdc, znaTdc, float); //! TDC ZNA +DECLARE_SOA_COLUMN(ZnaQx, znaQx, float); //! Q-vector X ZNA +DECLARE_SOA_COLUMN(ZnaQy, znaQy, float); //! Q-vector Y ZNA +DECLARE_SOA_COLUMN(ZncTowC, zncTowC, float); //! Common tower ZNC +DECLARE_SOA_COLUMN(ZncTow1, zncTow1, float); //! Tower 1 ZNC +DECLARE_SOA_COLUMN(ZncTow2, zncTow2, float); //! Tower 2 ZNC +DECLARE_SOA_COLUMN(ZncTow3, zncTow3, float); //! Tower 3 ZNC +DECLARE_SOA_COLUMN(ZncTow4, zncTow4, float); //! Tower 4 ZNC +DECLARE_SOA_COLUMN(ZncTdc, zncTdc, float); //! TDC ZNC +DECLARE_SOA_COLUMN(ZncQx, zncQx, float); //! Q-vector X ZNC +DECLARE_SOA_COLUMN(ZncQy, zncQy, float); //! Q-vector Y ZNC +DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Centrality +DECLARE_SOA_COLUMN(Vx, vx, float); //! Vertex X +DECLARE_SOA_COLUMN(Vy, vy, float); //! Vertex Y +DECLARE_SOA_COLUMN(Vz, vz, float); //! Vertex Z +DECLARE_SOA_COLUMN(Timestamp, timestamp, uint64_t); //! Timestamp +DECLARE_SOA_COLUMN(RunNumber, runNumber, uint32_t); //! Run Number +DECLARE_SOA_COLUMN(SelectionBits, selectionBits, uint8_t); //! Selection Flags +} // namespace zdcextra + +DECLARE_SOA_TABLE(ZdcExtras, "AOD", "ZDCEXTRA", o2::soa::Index<>, + zdcextra::ZnaTowC, + zdcextra::ZnaTow1, + zdcextra::ZnaTow2, + zdcextra::ZnaTow3, + zdcextra::ZnaTow4, + zdcextra::ZnaTdc, + zdcextra::ZnaQx, + zdcextra::ZnaQy, + zdcextra::ZncTowC, + zdcextra::ZncTow1, + zdcextra::ZncTow2, + zdcextra::ZncTow3, + zdcextra::ZncTow4, + zdcextra::ZncTdc, + zdcextra::ZncQx, + zdcextra::ZncQy, + zdcextra::Centrality, + zdcextra::Vx, + zdcextra::Vy, + zdcextra::Vz, + zdcextra::Timestamp, + zdcextra::RunNumber, + zdcextra::SelectionBits); +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_ZDCEXTRA_H_ diff --git a/Common/DataModel/ZDCLightIons.h b/Common/DataModel/ZDCLightIons.h new file mode 100644 index 00000000000..c1a0dc668b5 --- /dev/null +++ b/Common/DataModel/ZDCLightIons.h @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file ZDCLightIons.h +/// \brief ZDC data model for O-O Ne-Ne and p-O collisions +/// \author Chiara Oppedisano + +#ifndef COMMON_DATAMODEL_ZDCLIGHTIONS_H_ +#define COMMON_DATAMODEL_ZDCLIGHTIONS_H_ + +#include "Common/DataModel/Centrality.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace zdclightions +{ +DECLARE_SOA_COLUMN(ZnaTdc, znaTdc, float); //! TDC ZNA +DECLARE_SOA_COLUMN(ZnaAmpl, znaAmpl, float); //! amplitude ZNA +DECLARE_SOA_COLUMN(ZnaPmc, znaPmc, float); //! ADC PmC ZNA +DECLARE_SOA_COLUMN(ZnaPm1, znaPm1, float); //! ADC PmQ1 ZNA +DECLARE_SOA_COLUMN(ZnaPm2, znaPm2, float); //! ADC PmQ2 ZNA +DECLARE_SOA_COLUMN(ZnaPm3, znaPm3, float); //! ADC PmQ3 ZNA +DECLARE_SOA_COLUMN(ZnaPm4, znaPm4, float); //! ADC PmQ4 ZNA +DECLARE_SOA_COLUMN(ZncTdc, zncTdc, float); //! TDC ZNC +DECLARE_SOA_COLUMN(ZncAmpl, zncAmpl, float); //! amplitude ZNC +DECLARE_SOA_COLUMN(ZncPmc, zncPmc, float); //! ADC PmC ZNC +DECLARE_SOA_COLUMN(ZncPm1, zncPm1, float); //! ADC PmQ1 ZNC +DECLARE_SOA_COLUMN(ZncPm2, zncPm2, float); //! ADC PmQ2 ZNC +DECLARE_SOA_COLUMN(ZncPm3, zncPm3, float); //! ADC PmQ3 ZNC +DECLARE_SOA_COLUMN(ZncPm4, zncPm4, float); //! ADC PmQ4 ZNC +DECLARE_SOA_COLUMN(ZpaTdc, zpaTdc, float); //! TDC ZPA +DECLARE_SOA_COLUMN(ZpaAmpl, zpaAmpl, float); //! amplitude ZPA +DECLARE_SOA_COLUMN(ZpaPmc, zpaPmc, float); //! ADC PmC ZPA +DECLARE_SOA_COLUMN(ZpcTdc, zpcTdc, float); //! TDC ZPC +DECLARE_SOA_COLUMN(ZpcAmpl, zpcAmpl, float); //! amplitude ZPA +DECLARE_SOA_COLUMN(ZpcPmc, zpcPmc, float); //! ADC PmC ZPA +DECLARE_SOA_COLUMN(Zem1Tdc, zem1Tdc, float); //! TDC ZEM1 +DECLARE_SOA_COLUMN(Zem1Ampl, zem1Ampl, float); //! amplitude ZEM1 +DECLARE_SOA_COLUMN(Zem2Tdc, zem2Tdc, float); //! TDC ZEM2 +DECLARE_SOA_COLUMN(Zem2Ampl, zem2Ampl, float); //! amplitude ZEM2 +DECLARE_SOA_COLUMN(MultFt0a, multFt0a, float); //! mult. FIT-A +DECLARE_SOA_COLUMN(MultFt0c, multFt0c, float); //! mult. FIT-C +DECLARE_SOA_COLUMN(MultV0a, multV0a, float); //! mult. V0-A +DECLARE_SOA_COLUMN(VertexZ, vertexZ, float); //! Z vertex +DECLARE_SOA_COLUMN(CentralityFt0c, centralityFt0c, float); //! Centrality +DECLARE_SOA_COLUMN(CentralityFt0a, centralityFt0a, float); //! Centrality +DECLARE_SOA_COLUMN(CentralityFt0m, centralityFt0m, float); //! Centrality +DECLARE_SOA_COLUMN(Timestamp, timestamp, uint64_t); //! Timestamp +DECLARE_SOA_COLUMN(SelectionBits, selectionBits, uint8_t); //! Selection Flags +} // namespace zdclightions + +DECLARE_SOA_TABLE(ZDCLightIons, "AOD", "ZDCTABLELIGHTIONS", + zdclightions::ZnaTdc, + zdclightions::ZnaAmpl, + zdclightions::ZnaPmc, + zdclightions::ZnaPm1, + zdclightions::ZnaPm2, + zdclightions::ZnaPm3, + zdclightions::ZnaPm4, + zdclightions::ZncTdc, + zdclightions::ZncAmpl, + zdclightions::ZncPmc, + zdclightions::ZncPm1, + zdclightions::ZncPm2, + zdclightions::ZncPm3, + zdclightions::ZncPm4, + zdclightions::ZpaTdc, + zdclightions::ZpaAmpl, + zdclightions::ZpaPmc, + zdclightions::ZpcTdc, + zdclightions::ZpcAmpl, + zdclightions::ZpcPmc, + zdclightions::Zem1Tdc, + zdclightions::Zem1Ampl, + zdclightions::Zem2Tdc, + zdclightions::Zem2Ampl, + zdclightions::MultFt0a, + zdclightions::MultFt0c, + zdclightions::MultV0a, + zdclightions::VertexZ, + zdclightions::CentralityFt0c, + zdclightions::CentralityFt0a, + zdclightions::CentralityFt0m, + zdclightions::Timestamp, + zdclightions::SelectionBits); +} // namespace o2::aod + +#endif // COMMON_DATAMODEL_ZDCLIGHTIONS_H_ diff --git a/Common/LegacyDataQA/CMakeLists.txt b/Common/LegacyDataQA/CMakeLists.txt new file mode 100644 index 00000000000..e23c1f7c29c --- /dev/null +++ b/Common/LegacyDataQA/CMakeLists.txt @@ -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. + +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) + +o2physics_add_dpl_workflow(pmd-qa + SOURCES pmdQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pcm-run2 + SOURCES pcmRun2.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/Common/LegacyDataQA/centqa.cxx b/Common/LegacyDataQA/centqa.cxx new file mode 100644 index 00000000000..6d9e2722bbf --- /dev/null +++ b/Common/LegacyDataQA/centqa.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 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 "Common/DataModel/Centrality.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +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..65ce7891dbb --- /dev/null +++ b/Common/LegacyDataQA/otfv0qa.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 +#include +#include +#include +#include +#include +#include +#include + +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/pcmRun2.cxx b/Common/LegacyDataQA/pcmRun2.cxx new file mode 100644 index 00000000000..a05932170de --- /dev/null +++ b/Common/LegacyDataQA/pcmRun2.cxx @@ -0,0 +1,316 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file pcmRun2.cxx +/// \brief Analysis using PCM photons from Run2 +/// \author M. Hemmer, marvin.hemmer@cern.ch + +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct PcmRun2 { + struct : ConfigurableGroup { + std::string prefix = "trackcuts"; + Configurable tpcFindOverFoundable{"tpcFindOverFoundable", 0.6, "Ratio of number of found TPC clusters to the number of foundable TPC clusters a track must have at least."}; + Configurable minPt{"minPt", 0.05, "Minimum pT cut for the tracks."}; + } trackcuts; + + struct : ConfigurableGroup { + std::string prefix = "pidcuts"; + Configurable minNSigmaEl{"minNSigmaEl", -3., "Minimum NSgimal electron allowed for V0 leg."}; + Configurable maxNSigmaEl{"maxNSigmaEl", +4., "Maximum NSgimal electron allowed for V0 leg."}; + Configurable doPionRejection{"doPionRejection", true, "Flag to enable pion rejection based on TPC PID for V0 legs."}; + Configurable minNSigmaPiLowP{"minNSigmaPiLowP", 1., "Minimum NSgimal pion to reject V0 legs for low 0.4 < pT/(GeV/c) < 3.5."}; + Configurable minNSigmaPiHighP{"minNSigmaPiHighP", +0.5, "Minimum NSgimal pion to reject V0 legs for pT > 3.5 GeV/c."}; + } pidcuts; + + struct : ConfigurableGroup { + std::string prefix = "v0cuts"; + Configurable minPt{"minPt", 0.02, "Minimum pT cut for the V0."}; + Configurable maxEta{"maxEta", 0.8, "Maximum absolut pseudorapidity cut for the V0."}; + Configurable maxZconv{"maxZconv", 0.8, "Maximum absolut z conversion position cut for the V0."}; + Configurable qTFactor{"qTFactor", 0.125, "qT < this * pT"}; + Configurable cosP{"cosP", 0.85, "cos of pointing angle > this value."}; + Configurable rejectTooCloseV0{"rejectTooCloseV0", true, "."}; + } v0cuts; + + using TracksWithPID = soa::Join; + + SliceCache cache; + Preslice perCollisionV0 = aod::run2::oftv0::collisionId; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + void init(InitContext&) + { + + const AxisSpec thnAxisInvMass{400, 0.0, 0.8, "#it{M}_{#gamma#gamma} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{100, 0., 20., "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisCent{20, 0., 100., "Centrality (%)"}; + const AxisSpec thnAxisCuts{5, -0.5, 4.5, "cuts"}; + const AxisSpec thnAxisNSgimaE{254, -6.35f, 6.35f, "n#sigma_{e}"}; + + registry.add("hSameEvent2D", "hSameEvent2D", HistType::kTH2D, {thnAxisInvMass, thnAxisPt}); + registry.add("hNSigmaEPt", "hNSigmaEPt", HistType::kTH2D, {thnAxisNSgimaE, thnAxisPt}); + + registry.add("hCuts", "hCuts", HistType::kTH1D, {thnAxisCuts}); + registry.add("hCutsPair", "hCutsPair", HistType::kTH1D, {thnAxisCuts}); + + }; // end init + + template + float getCosP(CollisionIter const& coll, V0Iter const& v0) + { + // V0 momentum + float px = v0.px(); + float py = v0.py(); + float pz = v0.pz(); + + // V0 decay position + float xV0 = v0.x(); + float yV0 = v0.y(); + float zV0 = v0.z(); + + // Primary vertex + float xPV = coll.posX(); + float yPV = coll.posY(); + float zPV = coll.posZ(); + + // Displacement vector r = V0 - PV + float rx = xV0 - xPV; + float ry = yV0 - yPV; + float rz = zV0 - zPV; + + // Dot product p·r + float dot = px * rx + py * ry + pz * rz; + + // Magnitudes |p| and |r| + float magP = std::sqrt(px * px + py * py + pz * pz); + float magR = std::sqrt(rx * rx + ry * ry + rz * rz); + + // Cosine of pointing angle + return dot / (magP * magR); + } + + template + bool checkLegs(V0Iter const& v0) + { + + auto posLeg = v0.template posTrack_as(); + auto negLeg = v0.template negTrack_as(); + + registry.fill(HIST("hNSigmaEPt"), posLeg.tpcNSigmaEl(), posLeg.pt()); + registry.fill(HIST("hNSigmaEPt"), negLeg.tpcNSigmaEl(), negLeg.pt()); + + // first let's check the positive leg + if (posLeg.pt() <= trackcuts.minPt.value) { + registry.fill(HIST("hCuts"), 1); + return false; + } + if (posLeg.tpcFoundOverFindableCls() <= trackcuts.tpcFindOverFoundable.value) { + registry.fill(HIST("hCuts"), 1); + return false; + } + if (posLeg.tpcNSigmaEl() <= pidcuts.minNSigmaEl.value || posLeg.tpcNSigmaEl() >= pidcuts.maxNSigmaEl.value) { + registry.fill(HIST("hCuts"), 2); + return false; + } + + float minP = 0.4f; // minimum momentum for legs + float midP = 3.5f; // momentum where we change NSigma window + if (pidcuts.doPionRejection.value && posLeg.p() > minP) { + if (posLeg.p() < midP && posLeg.tpcNSigmaPi() <= pidcuts.minNSigmaPiLowP.value) { + registry.fill(HIST("hCuts"), 2); + return false; + } else if (posLeg.p() >= midP && posLeg.tpcNSigmaPi() <= pidcuts.minNSigmaPiHighP.value) { + registry.fill(HIST("hCuts"), 2); + return false; + } + } + + // second let's check the negative leg + if (negLeg.pt() <= trackcuts.minPt.value) { + registry.fill(HIST("hCuts"), 1); + return false; + } + if (negLeg.tpcFoundOverFindableCls() <= trackcuts.tpcFindOverFoundable.value) { + registry.fill(HIST("hCuts"), 1); + return false; + } + if (negLeg.tpcNSigmaEl() <= pidcuts.minNSigmaEl.value || negLeg.tpcNSigmaEl() >= pidcuts.maxNSigmaEl.value) { + registry.fill(HIST("hCuts"), 2); + return false; + } + + if (pidcuts.doPionRejection.value && negLeg.p() > minP) { + if (negLeg.p() < midP && negLeg.tpcNSigmaPi() <= pidcuts.minNSigmaPiLowP.value) { + registry.fill(HIST("hCuts"), 2); + return false; + } else if (negLeg.p() >= midP && negLeg.tpcNSigmaPi() <= pidcuts.minNSigmaPiHighP.value) { + registry.fill(HIST("hCuts"), 2); + return false; + } + } + return true; + } + + // Pi0 from EMCal + void process(o2::aod::Collisions const& collisions, o2::aod::Run2OTFV0s const& v0s, TracksWithPID const& /*tracks*/) + { + // TODO: + // - Add TooCloseToV0 cut: if two V0s are within dAngle < 0.02 and dR < 6. then remove the V0 with higher Chi2 + // - Everything here! + // nothing yet + + const float zRslope = std::tan(2.f * std::atan(std::exp(-1.f * v0cuts.maxEta.value))); + const float z0 = 7.f; // 7 cm + const float maxZ = 10.f; + const float minR = 5.f; + const float maxR = 280.f; + const float minRExclude = 55.f; + const float maxRExclude = 72.f; + + for (const auto& collision : collisions) { + if (std::fabs(collision.posZ()) > maxZ) { + continue; + } + auto photonsPerCollision = v0s.sliceBy(perCollisionV0, collision.globalIndex()); + + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photonsPerCollision, photonsPerCollision))) { + registry.fill(HIST("hCutsPair"), 0); + // next V0 cuts + float cX1 = g1.x(); + float cY1 = g1.y(); + float cZ1 = g1.z(); + float cR1 = std::sqrt(std::pow(cX1, 2.) + std::pow(cY1, 2.)); + + float cX2 = g2.x(); + float cY2 = g2.y(); + float cZ2 = g2.z(); + float cR2 = std::sqrt(std::pow(cX2, 2.) + std::pow(cY2, 2.)); + + ROOT::Math::PxPyPzEVector v4Photon2(g2.px(), g2.py(), g2.pz(), g2.e()); + ROOT::Math::PxPyPzEVector v4Photon1(g1.px(), g1.py(), g1.pz(), g1.e()); + + if (!checkLegs(g1)) { + registry.fill(HIST("hCutsPair"), 1); + continue; + } + + if (!checkLegs(g2)) { + registry.fill(HIST("hCutsPair"), 1); + continue; + } + + if (cR1 < minR || (cR1 > minRExclude && cR1 < maxRExclude) || cR1 > maxR) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (v4Photon1.Pt() < v0cuts.minPt.value) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (std::fabs(v4Photon1.Eta()) >= v0cuts.maxEta.value) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (std::fabs(cZ1) > v0cuts.maxZconv.value) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (cR1 <= ((std::fabs(cZ1) * zRslope) - z0)) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (g1.psiPair() >= (0.18f * std::exp(-0.055f * g1.chi2NDF()))) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (g1.qt() >= (v0cuts.qTFactor.value * v4Photon1.Pt())) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (getCosP(collision, g1) <= v0cuts.cosP.value) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + + if (cR2 < minR || (cR2 > minRExclude && cR2 < maxRExclude) || cR2 > maxR) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (v4Photon2.Pt() < v0cuts.minPt.value) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (std::fabs(v4Photon2.Eta()) >= v0cuts.maxEta.value) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (std::fabs(cZ2) > v0cuts.maxZconv.value) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (cR2 <= ((std::fabs(cZ2) * zRslope) - z0)) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (g2.psiPair() >= (0.18f * std::exp(-0.055f * g2.chi2NDF()))) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (g2.qt() >= (v0cuts.qTFactor.value * v4Photon2.Pt())) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + if (getCosP(collision, g2) <= v0cuts.cosP.value) { + registry.fill(HIST("hCutsPair"), 2); + continue; + } + + ROOT::Math::PxPyPzEVector vMeson = v4Photon1 + v4Photon2; + registry.fill(HIST("hCutsPair"), 3); + registry.fill(HIST("hSameEvent2D"), vMeson.M(), vMeson.Pt()); + } // end of loop over photon pairs + } // end of loop over collision + } + PROCESS_SWITCH(PcmRun2, process, "Default process function", true); +}; // End struct PcmRun2 + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/LegacyDataQA/pmdQa.cxx b/Common/LegacyDataQA/pmdQa.cxx new file mode 100644 index 00000000000..e2e3da0001a --- /dev/null +++ b/Common/LegacyDataQA/pmdQa.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. +/// +/// \file pmdQa.cxx +/// +/// \brief QA task to check PMD info on Run 2 converted data +/// \author Abhi Modak (abhi.modak@cern.ch) +/// \since May 17, 2025 + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PmdTable.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::aod::run2; +using namespace o2::framework; +using namespace o2::aod::evsel; +using namespace o2::framework::expressions; + +struct BuiltPmdIndex { + // build the index table PMDTracksIndex + Builds idx; + void init(InitContext const&) {} +}; + +struct PmdQa { + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + ConfigurableAxis axisEventBin{"axisEventBin", {4, 0.5, 4.5}, ""}; + ConfigurableAxis axisVtxZBin{"axisVtxZBin", {40, -20, 20}, ""}; + ConfigurableAxis axisNPMDtracksBin{"axisNPMDtracksBin", {500, 0, 500}, "Number of pmdtracks"}; + ConfigurableAxis axisClsxyBin{"axisClsxyBin", {200, -100, 100}, ""}; + ConfigurableAxis axisAdcBin{"axisAdcBin", {200, 0, 2000}, ""}; + ConfigurableAxis axisEtaBin{"axisEtaBin", {10, 2.1, 4.1}, ""}; + ConfigurableAxis axisNcellBin{"axisNcellBin", {50, -0.5, 49.5}, ""}; + Configurable fMipCut{"fMipCut", 432, "fMipCut"}; + Configurable fNcellCut{"fNcellCut", 2, "fNcellCut"}; + Configurable fEtalow{"fEtalow", 2.3, "fEtalow"}; + Configurable fEtahigh{"fEtahigh", 3.9, "fEtahigh"}; + Configurable fVtxCut{"fVtxCut", 10.0, "fVtxCut"}; + + void init(InitContext&) + { + + AxisSpec axisEvent = {axisEventBin, "Event", "EventAxis"}; + AxisSpec axisVtxZ = {axisVtxZBin, "VtxZ", "VtxZAxis"}; + AxisSpec axisNPMDtracks = {axisNPMDtracksBin, "NPMDtracks", "NPMDtracksAxis"}; + AxisSpec axisClsxy = {axisClsxyBin, "Clsxy", "ClsxyAxis"}; + AxisSpec axisAdc = {axisAdcBin, "Adc", "AdcAxis"}; + AxisSpec axisEta = {axisEtaBin, "Eta", "EtaAxis"}; + AxisSpec axisNcell = {axisNcellBin, "Ncell", "NcellAxis"}; + + histos.add("hEventHist", "hEventHist", kTH1F, {axisEvent}); + histos.add("hVtxZHist", "hVtxZHist", kTH1F, {axisVtxZ}); + histos.add("hNPMDtracks", "Number of pmdtracks", kTH1F, {axisNPMDtracks}); + histos.add("hClusXY", "hClusXY", kTH2F, {axisClsxy, axisClsxy}); + histos.add("hClusAdc", "hClusAdc", kTH1F, {axisAdc}); + histos.add("hetacls", "hetacls", kTH1F, {axisEta}); + histos.add("hclsncell", "hclsncell", kTH1F, {axisNcell}); + } + + using ColTable = soa::Join; + using ColevSel = soa::Join; + + void process(ColevSel::iterator const& collision, aod::Pmds const&) + { + histos.fill(HIST("hEventHist"), 1); + if (collision.sel7()) { + return; + } + histos.fill(HIST("hEventHist"), 2); + if (std::abs(collision.posZ()) >= fVtxCut) { + return; + } + histos.fill(HIST("hEventHist"), 3); + histos.fill(HIST("hVtxZHist"), collision.posZ()); + + if (collision.has_pmd()) { + histos.fill(HIST("hEventHist"), 4); + auto tracks = collision.pmd(); + histos.fill(HIST("hNPMDtracks"), tracks.size()); + for (const auto& track : tracks) { + if (track.pmddet() == 1) { + return; + } + if (track.pmdclsz() == 0) { + return; + } + if (!track.pmdmodule()) { + return; + } + histos.fill(HIST("hClusXY"), track.pmdclsx(), track.pmdclsy()); + histos.fill(HIST("hClusAdc"), track.pmdclsadc()); + float rdist = std::sqrt(track.pmdclsx() * track.pmdclsx() + track.pmdclsy() * track.pmdclsy()); + float theta = std::atan2(rdist, track.pmdclsz()); + float etacls = -std::log(std::tan(0.5 * theta)); + if (track.pmdclsadc() > fMipCut && track.pmdncell() > fNcellCut) { + if (etacls > fEtalow && etacls < fEtahigh) { + histos.fill(HIST("hetacls"), etacls); + histos.fill(HIST("hclsncell"), track.pmdncell()); + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/Common/LegacyDataQA/tpcpidqa.cxx b/Common/LegacyDataQA/tpcpidqa.cxx new file mode 100644 index 00000000000..46b02aa8d93 --- /dev/null +++ b/Common/LegacyDataQA/tpcpidqa.cxx @@ -0,0 +1,130 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// 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 "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +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..2282a06b5e7 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 @@ -25,6 +25,19 @@ o2physics_add_dpl_workflow(trackselection o2physics_add_dpl_workflow(event-selection SOURCES eventSelection.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCCDB + O2::DataFormatsITSMFT + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-selection-service + SOURCES eventSelectionService.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCCDB + O2::DataFormatsITSMFT + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-selection-service-run2 + SOURCES eventSelectionServiceRun2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCCDB + O2::DataFormatsITSMFT COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(multiplicity-table @@ -32,6 +45,11 @@ o2physics_add_dpl_workflow(multiplicity-table PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(multcenttable + SOURCES multCentTable.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(multiplicity-extra-table SOURCES multiplicityExtraTable.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -59,12 +77,22 @@ 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(propagationservice + SOURCES propagationService.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::TPCDriftManager + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(propagationservice-run2 + SOURCES propagationServiceRun2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::TPCDriftManager COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(track-propagation-tester - SOURCES trackPropagationTester.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore O2Physics::trackSelectionRequest +o2physics_add_dpl_workflow(track-dca-cov-filler-run2 + SOURCES trackDcaCovFillerRun2.cxx + PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(calo-clusters @@ -92,7 +120,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 +140,50 @@ 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-extra-table-producer + SOURCES zdcExtraTableProducer.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::GlobalTracking + 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::GlobalTracking + 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(selectionstudytable + SOURCES selectionStudyTable.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(zdc-task-light-ions + SOURCES zdcTaskLightIons.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/Common/TableProducer/Converters/CMakeLists.txt b/Common/TableProducer/Converters/CMakeLists.txt index 989b58bdab8..34ddc8efb3e 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 @@ -49,6 +54,11 @@ o2physics_add_dpl_workflow(bc-converter 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 @@ -64,3 +74,42 @@ 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(trackqa-converter-003 + SOURCES trackQA003Converter.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/bcConverter.cxx b/Common/TableProducer/Converters/bcConverter.cxx index 54f9a90aa8b..a8d8ab7d6ed 100644 --- a/Common/TableProducer/Converters/bcConverter.cxx +++ b/Common/TableProducer/Converters/bcConverter.cxx @@ -8,9 +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 "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/bcFlagsCreator.cxx b/Common/TableProducer/Converters/bcFlagsCreator.cxx new file mode 100644 index 00000000000..4d10272e1d7 --- /dev/null +++ b/Common/TableProducer/Converters/bcFlagsCreator.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. +#include +#include +#include +#include + +#include + +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/caloLabelConverter.cxx b/Common/TableProducer/Converters/caloLabelConverter.cxx index 0186e34f628..7716abf964f 100644 --- a/Common/TableProducer/Converters/caloLabelConverter.cxx +++ b/Common/TableProducer/Converters/caloLabelConverter.cxx @@ -8,9 +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. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/collisionConverter.cxx b/Common/TableProducer/Converters/collisionConverter.cxx index d3186ea462f..d6d27dcdaf3 100644 --- a/Common/TableProducer/Converters/collisionConverter.cxx +++ b/Common/TableProducer/Converters/collisionConverter.cxx @@ -8,9 +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. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/fddConverter.cxx b/Common/TableProducer/Converters/fddConverter.cxx index 50d47ade048..d7f359e6f68 100644 --- a/Common/TableProducer/Converters/fddConverter.cxx +++ b/Common/TableProducer/Converters/fddConverter.cxx @@ -8,9 +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 "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/hmpConverter.cxx b/Common/TableProducer/Converters/hmpConverter.cxx index da4eeeb7bca..ae423c0c9e8 100644 --- a/Common/TableProducer/Converters/hmpConverter.cxx +++ b/Common/TableProducer/Converters/hmpConverter.cxx @@ -12,9 +12,10 @@ // HMPID converter to new format // to be used with Run 2 converted data and older AO2Ds -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/mcCollisionConverter.cxx b/Common/TableProducer/Converters/mcCollisionConverter.cxx index b965a092117..290ce3d13dd 100644 --- a/Common/TableProducer/Converters/mcCollisionConverter.cxx +++ b/Common/TableProducer/Converters/mcCollisionConverter.cxx @@ -8,9 +8,10 @@ // In applying this license CERN does 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 +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/mcConverter.cxx b/Common/TableProducer/Converters/mcConverter.cxx index a78ac3158ea..4f18556f8a9 100644 --- a/Common/TableProducer/Converters/mcConverter.cxx +++ b/Common/TableProducer/Converters/mcConverter.cxx @@ -8,9 +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 "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/mftTracksConverter.cxx b/Common/TableProducer/Converters/mftTracksConverter.cxx index 425bb0c6392..175e9610f4f 100644 --- a/Common/TableProducer/Converters/mftTracksConverter.cxx +++ b/Common/TableProducer/Converters/mftTracksConverter.cxx @@ -19,9 +19,12 @@ /// \author L.Micheletti -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/multMCExtrasConverter.cxx b/Common/TableProducer/Converters/multMCExtrasConverter.cxx new file mode 100644 index 00000000000..56d6233690d --- /dev/null +++ b/Common/TableProducer/Converters/multMCExtrasConverter.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 "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include + +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..36b7f70d33a --- /dev/null +++ b/Common/TableProducer/Converters/multsExtraConverter.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 "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include + +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..ecad9de711f --- /dev/null +++ b/Common/TableProducer/Converters/run2TinyToFullPID.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. +// +// 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 "Common/Core/TableHelper.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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..fd0f43f3fda --- /dev/null +++ b/Common/TableProducer/Converters/run2bcinfosConverter.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 +#include +#include +#include + +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..2d321ee06fb --- /dev/null +++ b/Common/TableProducer/Converters/run2tracksExtraConverter.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. + +#include +#include +#include +#include + +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..34e1bac2363 --- /dev/null +++ b/Common/TableProducer/Converters/trackQA002Converter.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. +#include +#include +#include +#include +#include + +#include +#include + +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/trackQA003Converter.cxx b/Common/TableProducer/Converters/trackQA003Converter.cxx new file mode 100644 index 00000000000..4b6e0c7b2bd --- /dev/null +++ b/Common/TableProducer/Converters/trackQA003Converter.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. +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; + +struct TrackQAConverter003 { + Produces tracksQA_003; + + void process000(aod::TracksQA_000 const& tracksQA_000) + { + for (const auto& trackQA : tracksQA_000) { + tracksQA_003( + trackQA.trackId(), + trackQA.tpcTime0(), + 0.f, // dummy, not available in _000 + 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(TrackQAConverter003, process000, "process v000-to-v003 conversion", false); + + void process001(aod::TracksQA_001 const& tracksQA_001) + { + for (const auto& trackQA : tracksQA_001) { + tracksQA_003( + trackQA.trackId(), + trackQA.tpcTime0(), + 0.f, // dummy, not available in _001 + 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(TrackQAConverter003, process001, "process v001-to-v003 conversion", false); + + void process002(aod::TracksQA_002 const& tracksQA_002) + { + for (const auto& trackQA : tracksQA_002) { + tracksQA_003( + trackQA.trackId(), + trackQA.tpcTime0(), + 0.f, // dummy, not available in _002 + 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(), + trackQA.deltaTOFdX(), + trackQA.deltaTOFdZ()); + } + } + PROCESS_SWITCH(TrackQAConverter003, process002, "process v002-to-v003 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..25200812076 --- /dev/null +++ b/Common/TableProducer/Converters/trackQAConverter.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 +#include +#include +#include + +#include +#include + +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/tracksExtraConverter.cxx b/Common/TableProducer/Converters/tracksExtraConverter.cxx index b097cb7c4a3..0366a84dd8f 100644 --- a/Common/TableProducer/Converters/tracksExtraConverter.cxx +++ b/Common/TableProducer/Converters/tracksExtraConverter.cxx @@ -19,9 +19,12 @@ /// \author F.Mazzaschi -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/tracksExtraV002Converter.cxx b/Common/TableProducer/Converters/tracksExtraV002Converter.cxx new file mode 100644 index 00000000000..d45eb6e2c09 --- /dev/null +++ b/Common/TableProducer/Converters/tracksExtraV002Converter.cxx @@ -0,0 +1,120 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 + +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/Converters/v0converter.cxx b/Common/TableProducer/Converters/v0converter.cxx index 849e35591e1..38c513681b4 100644 --- a/Common/TableProducer/Converters/v0converter.cxx +++ b/Common/TableProducer/Converters/v0converter.cxx @@ -8,9 +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 "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/Converters/zdcConverter.cxx b/Common/TableProducer/Converters/zdcConverter.cxx index 2c94d5ca46f..99a88d2b6ca 100644 --- a/Common/TableProducer/Converters/zdcConverter.cxx +++ b/Common/TableProducer/Converters/zdcConverter.cxx @@ -12,10 +12,14 @@ // ZDC converter to new format // to be used with Run 2 converted data and older AO2Ds -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "ZDCBase/Constants.h" +#include +#include +#include +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/PID/CMakeLists.txt b/Common/TableProducer/PID/CMakeLists.txt index dc8a89337d4..975898966fe 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 @@ -38,14 +43,24 @@ o2physics_add_dpl_workflow(pid-tof-full # TPC +o2physics_add_dpl_workflow(pid-tpc-service + SOURCES pidTPCService.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-tpc-service-run2 + SOURCES pidTPCServiceRun2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(pid-tpc-base SOURCES pidTPCBase.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(pid-tpc SOURCES pidTPC.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase O2Physics::AnalysisCCDB O2Physics::MLCore COMPONENT_NAME Analysis) # HMPID diff --git a/Common/TableProducer/PID/pidBayes.cxx b/Common/TableProducer/PID/pidBayes.cxx index c990875e967..dd52d06e6cb 100644 --- a/Common/TableProducer/PID/pidBayes.cxx +++ b/Common/TableProducer/PID/pidBayes.cxx @@ -16,21 +16,46 @@ /// Only the tables for the mass hypotheses requested are filled, the others are sent empty. /// -// O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/Array2D.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/Core/PID/TPCPIDResponse.h" #include "Common/Core/PID/DetectorResponse.h" -#include "Common/Core/PID/ParamBase.h" #include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/ParamBase.h" +#include "Common/Core/PID/TPCPIDResponse.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseCombined.h" +#include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "pidTOFBase.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -44,7 +69,7 @@ void customize(std::vector& workflowOptions) std::swap(workflowOptions, options); } -#include "Framework/runDataProcessing.h" +#include struct bayesPid { using Trks = soa::Join; @@ -155,7 +180,7 @@ struct bayesPid { } // Checking the tables are requested in the workflow and enabling them - auto& workflows = initContext.services().get(); + const auto& workflows = initContext.services().get(); for (DeviceSpec const& device : workflows.devices) { for (auto const& input : device.inputs) { auto enableFlag = [&input](const PID::ID& id, Configurable& flag) { @@ -276,12 +301,12 @@ struct bayesPid { // bethe = fTPCResponse.GetExpectedSignal(track, type, AliTPCPIDResponse::kdEdxDefault, fUseTPCEtaCorrection, fUseTPCMultiplicityCorrection, fUseTPCPileupCorrection); // sigma = fTPCResponse.GetExpectedSigma(track, type, AliTPCPIDResponse::kdEdxDefault, fUseTPCEtaCorrection, fUseTPCMultiplicityCorrection, fUseTPCPileupCorrection); - if (abs(dedx - bethe) > fRange * sigma) { - // Probability[kTPC][pid] = exp(-0.5 * fRange * fRange) / sigma; // BUG fix - Probability[kTPC][pid] = exp(-0.5 * fRange * fRange); + if (std::abs(dedx - bethe) > fRange * sigma) { + // Probability[kTPC][pid] = std::exp(-0.5 * fRange * fRange) / sigma; // BUG fix + Probability[kTPC][pid] = std::exp(-0.5 * fRange * fRange); } else { - // Probability[kTPC][pid] = exp(-0.5 * (dedx - bethe) * (dedx - bethe) / (sigma * sigma)) / sigma; //BUG fix - Probability[kTPC][pid] = exp(-0.5 * (dedx - bethe) * (dedx - bethe) / (sigma * sigma)); + // Probability[kTPC][pid] = std::exp(-0.5 * (dedx - bethe) * (dedx - bethe) / (sigma * sigma)) / sigma; //BUG fix + Probability[kTPC][pid] = std::exp(-0.5 * (dedx - bethe) * (dedx - bethe) / (sigma * sigma)); mismatch = false; } if (Probability[kTPC][pid] <= 0.f) { @@ -317,10 +342,10 @@ struct bayesPid { constexpr respTOF responseTOFPID; // const float pt = track.pt(); - float mismPropagationFactor[10] = {1., 1., 1., 1., 1., 1., 1., 1., 1., 1.}; + const float mismPropagationFactor[10] = {1., 1., 1., 1., 1., 1., 1., 1., 1., 1.}; // In the O2 this cannot be done because the cluster information is missing in the AOD // if (!fNoTOFmism) { // this flag allows to disable mismatch for iterative procedure to get prior probabilities - // mismPropagationFactor[3] = 1 + exp(1 - 1.12 * pt); // it has to be aligned with the one in AliPIDCombined + // mismPropagationFactor[3] = 1 + std::exp(1 - 1.12 * pt); // it has to be aligned with the one in AliPIDCombined // mismPropagationFactor[4] = 1 + 1. / (4.71114 - 5.72372 * pt + 2.94715 * pt * pt); // it has to be aligned with the one in AliPIDCombined // int nTOFcluster = 0; @@ -334,10 +359,10 @@ struct bayesPid { // nTOFcluster = 80; // break; // case kPPB: // pPb 5.05 ATeV - // nTOFcluster = int(308 - 2.12 * fCurrCentrality + exp(4.917 - 0.1604 * fCurrCentrality)); + // nTOFcluster = int(308 - 2.12 * fCurrCentrality + std::exp(4.917 - 0.1604 * fCurrCentrality)); // break; // case kPBPB: // PbPb 2.76 ATeV - // nTOFcluster = int(exp(9.4 - 0.022 * fCurrCentrality)); + // nTOFcluster = int(std::exp(9.4 - 0.022 * fCurrCentrality)); // break; // } // } @@ -368,9 +393,9 @@ struct bayesPid { const float sig = /*responseTOFPID.GetExpectedSigma(Response[kTOF], track)*/ +0.f; if (nsigmas < fTOFtail) { - Probability[kTOF][pid] = exp(-0.5 * nsigmas * nsigmas) / sig; + Probability[kTOF][pid] = std::exp(-0.5 * nsigmas * nsigmas) / sig; } else { - Probability[kTOF][pid] = exp(-(nsigmas - fTOFtail * 0.5) * fTOFtail) / sig; + Probability[kTOF][pid] = std::exp(-(nsigmas - fTOFtail * 0.5) * fTOFtail) / sig; } Probability[kTOF][pid] += fgTOFmismatchProb * mismPropagationFactor[pid]; @@ -548,7 +573,7 @@ struct bayesPidQa { double lmin = TMath::Log10(min); double ldelta = (TMath::Log10(max) - lmin) / (static_cast(kNBins)); for (int i = 0; i < kNBins; i++) { - binp[i] = exp(TMath::Log(10) * (lmin + i * ldelta)); + binp[i] = std::exp(TMath::Log(10) * (lmin + i * ldelta)); } binp[kNBins] = max + 1; h->GetXaxis()->Set(kNBins, binp); diff --git a/Common/TableProducer/PID/pidITS.cxx b/Common/TableProducer/PID/pidITS.cxx new file mode 100644 index 00000000000..ab9f30c3659 --- /dev/null +++ b/Common/TableProducer/PID/pidITS.cxx @@ -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 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 "Common/Core/MetadataHelper.h" +#include "Common/DataModel/PIDResponseITS.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::track; + +o2::common::core::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, 0.09, -999., -999.}, + {1.63806, 1.58847, 2.52275, 2.66505, 1.48405, 6.90453, 1.40487e-01, -4.31078e-01, 1.50052, 0.09, -999., -999.}}; + +/// 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). If p1/p2 is -999, the resolution is set to p0. +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/pidTOF.cxx b/Common/TableProducer/PID/pidTOF.cxx index f26df966313..b9efb4ca12f 100644 --- a/Common/TableProducer/PID/pidTOF.cxx +++ b/Common/TableProducer/PID/pidTOF.cxx @@ -16,15 +16,32 @@ /// Only the tables for the mass hypotheses requested are filled, the others are sent empty. /// -// O2 includes +#include "pidTOFBase.h" + +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/PIDResponseTOF.h" + #include -#include "TOFBase/EventTimeMaker.h" -#include "Framework/AnalysisTask.h" -#include "ReconstructionDataFormats/Track.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -// O2Physics includes -#include "TableHelper.h" -#include "pidTOFBase.h" +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -38,7 +55,7 @@ void customize(std::vector& workflowOptions) std::swap(workflowOptions, options); } -#include "Framework/runDataProcessing.h" +#include /// Task to produce the response table struct tofPid { @@ -232,40 +249,31 @@ struct tofPid { { switch (id) { case 0: - aod::pidutils::packInTable(-999.f, - tablePIDEl); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDEl); break; case 1: - aod::pidutils::packInTable(-999.f, - tablePIDMu); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDMu); break; case 2: - aod::pidutils::packInTable(-999.f, - tablePIDPi); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDPi); break; case 3: - aod::pidutils::packInTable(-999.f, - tablePIDKa); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDKa); break; case 4: - aod::pidutils::packInTable(-999.f, - tablePIDPr); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDPr); break; case 5: - aod::pidutils::packInTable(-999.f, - tablePIDDe); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDDe); break; case 6: - aod::pidutils::packInTable(-999.f, - tablePIDTr); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDTr); break; case 7: - aod::pidutils::packInTable(-999.f, - tablePIDHe); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDHe); break; case 8: - aod::pidutils::packInTable(-999.f, - tablePIDAl); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDAl); break; default: LOG(fatal) << "Wrong particle ID in makeTableEmpty()"; @@ -326,40 +334,40 @@ struct tofPid { for (auto const& pidId : mEnabledParticles) { // Loop on enabled particle hypotheses switch (pidId) { case 0: - aod::pidutils::packInTable(responseEl.GetSeparation(mRespParamsV2, trkInColl), - tablePIDEl); + aod::pidtof_tiny::binning::packInTable(responseEl.GetSeparation(mRespParamsV2, trkInColl), + tablePIDEl); break; case 1: - aod::pidutils::packInTable(responseMu.GetSeparation(mRespParamsV2, trkInColl), - tablePIDMu); + aod::pidtof_tiny::binning::packInTable(responseMu.GetSeparation(mRespParamsV2, trkInColl), + tablePIDMu); break; case 2: - aod::pidutils::packInTable(responsePi.GetSeparation(mRespParamsV2, trkInColl), - tablePIDPi); + aod::pidtof_tiny::binning::packInTable(responsePi.GetSeparation(mRespParamsV2, trkInColl), + tablePIDPi); break; case 3: - aod::pidutils::packInTable(responseKa.GetSeparation(mRespParamsV2, trkInColl), - tablePIDKa); + aod::pidtof_tiny::binning::packInTable(responseKa.GetSeparation(mRespParamsV2, trkInColl), + tablePIDKa); break; case 4: - aod::pidutils::packInTable(responsePr.GetSeparation(mRespParamsV2, trkInColl), - tablePIDPr); + aod::pidtof_tiny::binning::packInTable(responsePr.GetSeparation(mRespParamsV2, trkInColl), + tablePIDPr); break; case 5: - aod::pidutils::packInTable(responseDe.GetSeparation(mRespParamsV2, trkInColl), - tablePIDDe); + aod::pidtof_tiny::binning::packInTable(responseDe.GetSeparation(mRespParamsV2, trkInColl), + tablePIDDe); break; case 6: - aod::pidutils::packInTable(responseTr.GetSeparation(mRespParamsV2, trkInColl), - tablePIDTr); + aod::pidtof_tiny::binning::packInTable(responseTr.GetSeparation(mRespParamsV2, trkInColl), + tablePIDTr); break; case 7: - aod::pidutils::packInTable(responseHe.GetSeparation(mRespParamsV2, trkInColl), - tablePIDHe); + aod::pidtof_tiny::binning::packInTable(responseHe.GetSeparation(mRespParamsV2, trkInColl), + tablePIDHe); break; case 8: - aod::pidutils::packInTable(responseAl.GetSeparation(mRespParamsV2, trkInColl), - tablePIDAl); + aod::pidtof_tiny::binning::packInTable(responseAl.GetSeparation(mRespParamsV2, trkInColl), + tablePIDAl); break; default: LOG(fatal) << "Wrong particle ID in processWSlice()"; @@ -414,40 +422,40 @@ struct tofPid { for (auto const& pidId : mEnabledParticles) { // Loop on enabled particle hypotheses switch (pidId) { case 0: - aod::pidutils::packInTable(responseEl.GetSeparation(mRespParamsV2, track), - tablePIDEl); + aod::pidtof_tiny::binning::packInTable(responseEl.GetSeparation(mRespParamsV2, track), + tablePIDEl); break; case 1: - aod::pidutils::packInTable(responseMu.GetSeparation(mRespParamsV2, track), - tablePIDMu); + aod::pidtof_tiny::binning::packInTable(responseMu.GetSeparation(mRespParamsV2, track), + tablePIDMu); break; case 2: - aod::pidutils::packInTable(responsePi.GetSeparation(mRespParamsV2, track), - tablePIDPi); + aod::pidtof_tiny::binning::packInTable(responsePi.GetSeparation(mRespParamsV2, track), + tablePIDPi); break; case 3: - aod::pidutils::packInTable(responseKa.GetSeparation(mRespParamsV2, track), - tablePIDKa); + aod::pidtof_tiny::binning::packInTable(responseKa.GetSeparation(mRespParamsV2, track), + tablePIDKa); break; case 4: - aod::pidutils::packInTable(responsePr.GetSeparation(mRespParamsV2, track), - tablePIDPr); + aod::pidtof_tiny::binning::packInTable(responsePr.GetSeparation(mRespParamsV2, track), + tablePIDPr); break; case 5: - aod::pidutils::packInTable(responseDe.GetSeparation(mRespParamsV2, track), - tablePIDDe); + aod::pidtof_tiny::binning::packInTable(responseDe.GetSeparation(mRespParamsV2, track), + tablePIDDe); break; case 6: - aod::pidutils::packInTable(responseTr.GetSeparation(mRespParamsV2, track), - tablePIDTr); + aod::pidtof_tiny::binning::packInTable(responseTr.GetSeparation(mRespParamsV2, track), + tablePIDTr); break; case 7: - aod::pidutils::packInTable(responseHe.GetSeparation(mRespParamsV2, track), - tablePIDHe); + aod::pidtof_tiny::binning::packInTable(responseHe.GetSeparation(mRespParamsV2, track), + tablePIDHe); break; case 8: - aod::pidutils::packInTable(responseAl.GetSeparation(mRespParamsV2, track), - tablePIDAl); + aod::pidtof_tiny::binning::packInTable(responseAl.GetSeparation(mRespParamsV2, track), + tablePIDAl); break; default: LOG(fatal) << "Wrong particle ID in processWoSlice()"; diff --git a/Common/TableProducer/PID/pidTOFBase.cxx b/Common/TableProducer/PID/pidTOFBase.cxx index e82ea651304..50854085476 100644 --- a/Common/TableProducer/PID/pidTOFBase.cxx +++ b/Common/TableProducer/PID/pidTOFBase.cxx @@ -15,25 +15,36 @@ /// \brief Base to build tasks for TOF PID tasks. /// -#include -#include -#include - -// O2 includes -#include "CCDB/BasicCCDBManager.h" -#include "TOFBase/EventTimeMaker.h" -#include "Framework/AnalysisTask.h" -#include "ReconstructionDataFormats/Track.h" +#include "pidTOFBase.h" -// O2Physics includes -#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/TableHelper.h" #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" +#include "Common/DataModel/PIDResponseTOF.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -46,16 +57,13 @@ 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 @@ -114,7 +122,7 @@ struct tofSignal { if (enableTableFlags) { tableFlags.reserve(tracks.size()); } - for (auto& t : tracks) { + for (const auto& t : tracks) { const auto s = o2::pid::tof::TOFSignal::GetTOFSignal(t); if (enableQaHistograms) { histos.fill(HIST("tofSignal"), s); @@ -142,7 +150,7 @@ struct tofSignal { if (enableTableFlags) { tableFlags.reserve(tracks.size()); } - for (auto& t : tracks) { + for (const auto& t : tracks) { table(o2::pid::tof::TOFSignal::GetTOFSignal(t)); if (!enableTableFlags) { continue; @@ -391,7 +399,7 @@ struct tofEventTime { evTimeTOF.removeBias(trk, nGoodTracksForTOF, et, erret, 2); } uint8_t flags = 0; - if (erret < errDiamond && (maxEvTimeTOF <= 0.f || abs(et) < maxEvTimeTOF)) { + if (erret < errDiamond && (maxEvTimeTOF <= 0.f || std::abs(et) < maxEvTimeTOF)) { flags |= o2::aod::pidflags::enums::PIDFlags::EvTimeTOF; } else { et = 0.f; @@ -410,7 +418,7 @@ struct tofEventTime { /// /// Process function to prepare the event for each track on Run 3 data with the FT0 using EvTimeCollisionsFT0 = soa::Join; - void processFT0(TrksEvTime& tracks, + void processFT0(TrksEvTime const& tracks, aod::FT0s const&, EvTimeCollisionsFT0 const&) { @@ -466,7 +474,7 @@ struct tofEventTime { if constexpr (removeTOFEvTimeBias) { evTimeTOF.removeBias(trk, nGoodTracksForTOF, t0TOF[0], t0TOF[1], 2); } - if (t0TOF[1] < errDiamond && (maxEvTimeTOF <= 0 || abs(t0TOF[0]) < maxEvTimeTOF)) { + 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]); @@ -494,7 +502,7 @@ struct tofEventTime { } else { tableFlags(flags); } - tableEvTime(eventTime / sumOfWeights, sqrt(1. / sumOfWeights)); + tableEvTime(eventTime / sumOfWeights, std::sqrt(1. / sumOfWeights)); if (enableTableTOFOnly) { tableEvTimeTOFOnly((uint8_t)filterForTOFEventTime(trk), t0TOF[0], t0TOF[1], evTimeTOF.mEventTimeMultiplicity); } @@ -505,7 +513,7 @@ struct tofEventTime { /// /// Process function to prepare the event for each track on Run 3 data with only the FT0 - void processOnlyFT0(TrksEvTime& tracks, + void processOnlyFT0(TrksEvTime const& tracks, aod::FT0s const&, EvTimeCollisionsFT0 const&) { diff --git a/Common/TableProducer/PID/pidTOFBase.h b/Common/TableProducer/PID/pidTOFBase.h index d8556f95432..0aa87763775 100644 --- a/Common/TableProducer/PID/pidTOFBase.h +++ b/Common/TableProducer/PID/pidTOFBase.h @@ -18,14 +18,12 @@ #ifndef COMMON_TABLEPRODUCER_PID_PIDTOFBASE_H_ #define COMMON_TABLEPRODUCER_PID_PIDTOFBASE_H_ +#include + +#include #include #include -// O2Physics -#include "PID/ParamBase.h" -#include "PID/PIDTOF.h" -#include "Common/DataModel/PIDResponse.h" - static constexpr int nSpecies = 9; static constexpr int nParameters = 1; static const std::vector particleNames{"El", "Mu", "Pi", "Ka", "Pr", "De", "Tr", "He", "Al"}; @@ -37,8 +35,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 +42,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/pidTOFFull.cxx b/Common/TableProducer/PID/pidTOFFull.cxx index 6fec03a10ff..e8c94641f18 100644 --- a/Common/TableProducer/PID/pidTOFFull.cxx +++ b/Common/TableProducer/PID/pidTOFFull.cxx @@ -16,15 +16,32 @@ /// Only the tables for the mass hypotheses requested are filled, the others are sent empty. /// -// O2 includes +#include "pidTOFBase.h" + +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/PIDResponseTOF.h" + #include -#include "TOFBase/EventTimeMaker.h" -#include "Framework/AnalysisTask.h" -#include "ReconstructionDataFormats/Track.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -// O2Physics includes -#include "TableHelper.h" -#include "pidTOFBase.h" +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -38,7 +55,7 @@ void customize(std::vector& workflowOptions) std::swap(workflowOptions, options); } -#include "Framework/runDataProcessing.h" +#include /// Task to produce the response table struct tofPidFull { diff --git a/Common/TableProducer/PID/pidTOFMerge.cxx b/Common/TableProducer/PID/pidTOFMerge.cxx index 7fc99517fdb..79a2c02d655 100644 --- a/Common/TableProducer/PID/pidTOFMerge.cxx +++ b/Common/TableProducer/PID/pidTOFMerge.cxx @@ -8,34 +8,57 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. - /// -/// \file tofPidMerge.cxx +/// \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 -/// \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. /// -#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 "pidTOFBase.h" -#include "Common/DataModel/TrackSelectionTables.h" + +#include "Common/Core/CollisionTypeHelper.h" +#include "Common/Core/MetadataHelper.h" +#include "Common/Core/PID/PIDTOFParamService.h" +#include "Common/Core/TableHelper.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FT0Corrected.h" -#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -43,155 +66,62 @@ using namespace o2::pid; using namespace o2::framework::expressions; using namespace o2::track; -MetadataHelper metadataInfo; +// Input data types +using Run3Trks = o2::soa::Join; +using Run3TrksWtof = soa::Join; +using Run3TrksWtofWevTime = soa::Join; -// Configuration common to all tasks -struct TOFCalibConfig : ConfigurableGroup { - Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; - Configurable timeShiftCCDBPath{"timeShiftCCDBPath", "", "Path of the TOF time shift vs eta. If empty none is taken"}; - 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 fatalOnPassNotAvailable{"fatalOnPassNotAvailable", true, "Flag to throw a fatal if the pass is not available in the retrieved CCDB object"}; +using EvTimeCollisions = soa::Join; +using EvTimeCollisionsFT0 = soa::Join; - void inheritFromBaseTask(o2::framework::InitContext& initContext) - { - 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"; - } - if (!getTaskOptionValue(initContext, "tof-signal", "paramFileName", paramFileName.value, true)) { - LOG(fatal) << "Could not get paramFileName from tof-signal task"; - } - if (!getTaskOptionValue(initContext, "tof-signal", "parametrizationPath", parametrizationPath.value, true)) { - LOG(fatal) << "Could not get parametrizationPath from tof-signal task"; - } - if (!getTaskOptionValue(initContext, "tof-signal", "passName", passName.value, true)) { - LOG(fatal) << "Could not get passName from tof-signal task"; - } - if (!getTaskOptionValue(initContext, "tof-signal", "timeShiftCCDBPath", timeShiftCCDBPath.value, true)) { - LOG(fatal) << "Could not get timeShiftCCDBPath from tof-signal task"; - } - if (!getTaskOptionValue(initContext, "tof-signal", "loadResponseFromCCDB", loadResponseFromCCDB.value, true)) { - LOG(fatal) << "Could not get loadResponseFromCCDB from tof-signal task"; - } - if (!getTaskOptionValue(initContext, "tof-signal", "fatalOnPassNotAvailable", fatalOnPassNotAvailable.value, true)) { - LOG(fatal) << "Could not get fatalOnPassNotAvailable from tof-signal task"; - } - } - - template - void setUp(o2::pid::tof::TOFResoParamsV3& mRespParamsV3, CCDBObject ccdb) - { - // First we set the CCDB manager - 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()); - - // Then the information about the metadata - if (passName.value == "metadata") { - LOG(info) << "Getting pass from metadata"; - if (metadataInfo.isMC()) { - passName.value = metadataInfo.get("AnchorPassName"); - } else { - passName.value = metadataInfo.get("RecoPassName"); - } - LOG(info) << "Passed autodetect mode for pass. 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(mRespParamsV3, 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 { - mRespParamsV3.setMomentumChargeShiftParameters(paramCollection.getPars(passName.value)); - mRespParamsV3.printMomentumChargeShiftParameters(); - } - } else { - mRespParamsV3.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->template getForTimeStamp(parametrizationPath.value, timestamp.value); - paramCollection->print(); - if (!paramCollection->retrieveParameters(mRespParamsV3, 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 - mRespParamsV3.setMomentumChargeShiftParameters(paramCollection->getPars(passName.value)); - mRespParamsV3.printMomentumChargeShiftParameters(); - } - } - mRespParamsV3.print(); - if (timeShiftCCDBPath.value != "") { - if (timeShiftCCDBPath.value.find(".root") != std::string::npos) { - mRespParamsV3.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Pos", true); - mRespParamsV3.setTimeShiftParameters(timeShiftCCDBPath.value, "gmean_Neg", false); - } else { - mRespParamsV3.setTimeShiftParameters(ccdb->template getForTimeStamp(Form("%s/pos", timeShiftCCDBPath.value.c_str()), timestamp.value), true); - mRespParamsV3.setTimeShiftParameters(ccdb->template getForTimeStamp(Form("%s/neg", timeShiftCCDBPath.value.c_str()), timestamp.value), false); - } - } - } -}; - -// Part 1 TOF signal definition +using Run2Trks = o2::soa::Join; +using Run2TrksWtofWevTime = soa::Join; /// 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; -bool isTrackGoodMatchForTOFPID(const Run3Trks::iterator& tr, const Run3Cols& /*ev*/) +bool isTrackGoodMatchForTOFPID(const Run3Trks::iterator& tr) { 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 { + // Detector response and input parameters + Service ccdb; + Service tofResponse; // 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 - TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration - 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"}; // Output histograms Configurable enableQaHistograms{"enableQaHistograms", false, "Flag to enable the QA histograms"}; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + 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) void init(o2::framework::InitContext& initContext) { + LOG(debug) << "Initializing the tofSignal task"; + tofResponse->initSetup(ccdb, initContext); // Checking that the table is requested in the workflow and enabling it enableTableTOFSignal = isTableRequiredInWorkflow(initContext, "TOFSignal"); if (enableTableTOFSignal) { @@ -207,11 +137,14 @@ struct tofSignal { LOG(info) << "No table or process is enabled. Disabling task"; return; } - 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 (tofResponse->cfgAutoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions"; + if (tofResponse->metadataInfo.isFullyDefined() && !doprocessRun2 && !doprocessRun3) { // Check if the metadata is initialized (only if not forced from the workflow configuration) + if (tofResponse->metadataInfo.isRun3()) { + doprocessRun3.value = true; + } else { + doprocessRun2.value = false; + } } } @@ -222,11 +155,6 @@ struct tofSignal { if (!doprocessRun2 && !doprocessRun3) { LOG(fatal) << "Neither processRun2 nor processRun3 are enabled. Pick one of the two"; } - - trackDistanceForGoodMatch = distanceForGoodMatch; - trackDistanceForGoodMatchLowMult = distanceForGoodMatchLowMult; - multiplicityThreshold = multThreshold; - LOG(info) << "Configuring selections for good match: " << trackDistanceForGoodMatch << " low mult " << trackDistanceForGoodMatchLowMult << " mult. threshold " << multiplicityThreshold; if (!enableQaHistograms) { return; } @@ -239,7 +167,7 @@ struct tofSignal { /// 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, Run3Cols const& collisions) + void processRun3(Run3Trks const& tracks) { if (!enableTableTOFSignal) { return; @@ -248,26 +176,25 @@ struct tofSignal { if (enableTablepidTOFFlags) { tableFlags.reserve(tracks.size()); } - for (auto& t : tracks) { - const auto s = o2::pid::tof::TOFSignal::GetTOFSignal(t); + for (const auto& trk : tracks) { + const float& sig = o2::pid::tof::TOFSignal::GetTOFSignal(trk); if (enableQaHistograms) { - histos.fill(HIST("tofSignal"), s); + histos.fill(HIST("tofSignal"), sig); } - table(s); + table(sig); if (!enableTablepidTOFFlags) { continue; } - const auto b = isTrackGoodMatchForTOFPID(t, collisions); + const auto& b = isTrackGoodMatchForTOFPID(trk); if (enableQaHistograms) { - histos.fill(HIST("goodForPIDFlags"), s); + 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); - using TrksRun2 = o2::soa::Join; - void processRun2(TrksRun2 const& tracks) + void processRun2(Run2Trks const& tracks) { if (!enableTableTOFSignal) { return; @@ -276,8 +203,8 @@ struct tofSignal { if (enableTablepidTOFFlags) { tableFlags.reserve(tracks.size()); } - for (auto& t : tracks) { - table(o2::pid::tof::TOFSignal::GetTOFSignal(t)); + for (const auto& trk : tracks) { + table(o2::pid::tof::TOFSignal::GetTOFSignal(trk)); if (!enableTablepidTOFFlags) { continue; } @@ -293,7 +220,11 @@ 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)); + 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 @@ -313,31 +244,34 @@ o2::tof::eventTimeContainer evTimeMakerForTracks(const trackTypeContainer& track /// Task to produce the TOF event time table struct tofEventTime { + // Detector response and input parameters + Service ccdb; + Service tofResponse; // 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); + 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) { + LOG(debug) << "Initializing the tofEventTime task"; + tofResponse->initSetup(ccdb, initContext); // Checking that the table is requested in the workflow and enabling it enableTableTOFEvTime = isTableRequiredInWorkflow(initContext, "TOFEvTime"); @@ -356,8 +290,24 @@ struct tofEventTime { return; } - if (metadataInfo.isFullyDefined() && metadataInfo.isRun3() && doprocessRun2) { - LOG(fatal) << "Run2 process function is enabled but the metadata says it is Run3"; + if (tofResponse->cfgAutoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions"; + if (tofResponse->metadataInfo.isFullyDefined()) { + if (tofResponse->metadataInfo.isRun3()) { + doprocessRun3.value = true; + } else { + doprocessRun2.value = true; + } + } + } + + if (tofResponse->metadataInfo.isFullyDefined()) { + if (tofResponse->metadataInfo.isRun3() && doprocessRun2) { + LOG(fatal) << "Run2 process function is enabled but the metadata says it is Run3"; + } + if (!tofResponse->metadataInfo.isRun3() && doprocessRun3) { + LOG(fatal) << "Run3 process function is enabled but the metadata says it is Run2"; + } } trackSampleMinMomentum = minMomentum; @@ -369,16 +319,8 @@ struct tofEventTime { LOGF(info, "Enabling process function: processRun2"); nEnabled++; } - 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"); + if (doprocessRun3 == true) { + LOGF(info, "Enabling process function: processRun3"); nEnabled++; } if (nEnabled > 1) { @@ -388,8 +330,6 @@ struct tofEventTime { if (sel8TOFEvTime.value == true) { LOG(info) << "TOF event time will be computed for collisions that pass the event selection only!"; } - mTOFCalibConfig.setUp(mRespParamsV3, ccdb); // Getting the parametrization parameters - o2::tof::eventTimeContainer::setMaxNtracksInSet(maxNtracksInSet.value); o2::tof::eventTimeContainer::printConfig(); } @@ -399,11 +339,13 @@ struct tofEventTime { /// /// Process function to prepare the event for each track on Run 2 data void processRun2(aod::Tracks const& tracks, - aod::Collisions const&) + aod::Collisions const&, + aod::BCsWithTimestamps const& bcs) { if (!enableTableTOFEvTime) { return; } + tofResponse->processSetup(bcs.iteratorAt(0)); // Update the response parameters tableEvTime.reserve(tracks.size()); tableFlags.reserve(tracks.size()); @@ -418,227 +360,213 @@ struct tofEventTime { tableEvTime(t.collision().collisionTime() * 1000.f, t.collision().collisionTimeRes() * 1000.f); } } - PROCESS_SWITCH(tofEventTime, processRun2, "Process with Run2 data", false); + 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 - using TrksEvTime = soa::Join; // Define slice per collision - Preslice perCollision = aod::track::collisionId; + Preslice perCollision = aod::track::collisionId; template - using ResponseImplementationEvTime = o2::pid::tof::ExpTimes; - using EvTimeCollisions = soa::Join; - void processNoFT0(TrksEvTime const& tracks, - EvTimeCollisions const&) + 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()); } + tofResponse->processSetup(bcs.iteratorAt(0)); // Update the response parameters + + // Autoset the processing mode for the event time computation + if (mComputeEvTimeWithTOF == -1 || mComputeEvTimeWithFT0 == -1) { + switch (tofResponse->cfgCollisionType()) { + 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 " << tofResponse->cfgCollisionType() << " " << CollisionSystemType::getCollisionSystemName(tofResponse->cfgCollisionType()) << " not supported for TOF event time computation"; + break; + } + } + LOG(debug) << "Running on " << CollisionSystemType::getCollisionSystemName(tofResponse->cfgCollisionType()) << " mComputeEvTimeWithTOF " << mComputeEvTimeWithTOF.value << " mComputeEvTimeWithFT0 " << mComputeEvTimeWithFT0.value; - 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); + 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; } - 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 + 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& tracksInCollision = tracks.sliceBy(perCollision, lastCollisionId); + const auto& collision = t.collision_as(); - // First make table for event time - const auto evTimeTOF = evTimeMakerForTracks(tracksInCollision, mRespParamsV3, diamond); - int nGoodTracksForTOF = 0; - float et = evTimeTOF.mEventTime; - float erret = evTimeTOF.mEventTimeError; + // Compute the TOF event time + const auto evTimeMakerTOF = evTimeMakerForTracks(tracksInCollision, tofResponse->parameters, 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 - for (auto const& trk : tracksInCollision) { // Loop on Tracks - if constexpr (removeTOFEvTimeBias) { - evTimeTOF.removeBias(trk, nGoodTracksForTOF, et, erret, 2); - } uint8_t flags = 0; - if (erret < errDiamond && (maxEvTimeTOF <= 0.f || 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, evTimeTOF.mEventTimeMultiplicity); - } - } - } - } - PROCESS_SWITCH(tofEventTime, processNoFT0, "Process without FT0", false); + 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; - /// - /// 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&) - { - if (!enableTableTOFEvTime) { - return; - } + weight = 1.f / (t0TOF[1] * t0TOF[1]); + eventTime += t0TOF[0] * weight; + sumOfWeights += weight; + } - tableEvTime.reserve(tracks.size()); - tableFlags.reserve(tracks.size()); - if (enableTableEvTimeTOFOnly) { - tableEvTimeTOFOnly.reserve(tracks.size()); - } + 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; + } - 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); + 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); + } } - 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 evTimeTOF = evTimeMakerForTracks(tracksInCollision, mRespParamsV3, diamond); - - float t0AC[2] = {.0f, 999.f}; // Value and error of T0A or T0C or T0AC - float t0TOF[2] = {static_cast(evTimeTOF.mEventTime), static_cast(evTimeTOF.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) { - evTimeTOF.removeBias(trk, nGoodTracksForTOF, t0TOF[0], t0TOF[1], 2); + } 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 (t0TOF[1] < errDiamond && (maxEvTimeTOF <= 0 || 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 (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 - 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; - } + const auto& tracksInCollision = tracks.sliceBy(perCollision, lastCollisionId); - weight = 1.f / (t0AC[1] * t0AC[1]); - eventTime += t0AC[0] * weight; - sumOfWeights += weight; - } + // First make table for event time + const auto evTimeMakerTOF = evTimeMakerForTracks(tracksInCollision, tofResponse->parameters, kDiamond); + int nGoodTracksForTOF = 0; + float et = evTimeMakerTOF.mEventTime; + float erret = evTimeMakerTOF.mEventTimeError; - if (sumOfWeights < weightDiamond) { // avoiding sumOfWeights = 0 or worse that diamond - eventTime = 0; - sumOfWeights = weightDiamond; - tableFlags(0); - } else { + 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); + } } - tableEvTime(eventTime / sumOfWeights, sqrt(1. / sumOfWeights)); + } + } else if (mComputeEvTimeWithTOF == 0 && mComputeEvTimeWithFT0 == 1) { + for (auto const& t : tracks) { // Loop on collisions if (enableTableEvTimeTOFOnly) { - tableEvTimeTOFOnly((uint8_t)filterForTOFEventTime(trk), t0TOF[0], t0TOF[1], evTimeTOF.mEventTimeMultiplicity); + tableEvTimeTOFOnly((uint8_t)0, 0.f, 0.f, -1); } - } - } - } - PROCESS_SWITCH(tofEventTime, processFT0, "Process with FT0", false); - - /// - /// Process function to prepare the event for each track on Run 3 data with only the FT0 - void processOnlyFT0(TrksEvTime& tracks, - aod::FT0s const&, - EvTimeCollisionsFT0 const&) - { - if (!enableTableTOFEvTime) { - return; - } - - tableEvTime.reserve(tracks.size()); - tableFlags.reserve(tracks.size()); - if (!enableTableEvTimeTOFOnly) { - tableEvTimeTOFOnly.reserve(tracks.size()); - } + 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(); - 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 + 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); - 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, processOnlyFT0, "Process only with FT0", false); + PROCESS_SWITCH(tofEventTime, processRun3, "Process the Run3 data", true); }; // Part 3 Nsigma computation -static constexpr int nParameters2 = 2; -static const std::vector parameterNames2{"Enable", "EnableFull"}; -static constexpr int idxEl = 0; -static constexpr int idxMu = 1; -static constexpr int idxPi = 2; -static constexpr int idxKa = 3; -static constexpr int idxPr = 4; -static constexpr int idxDe = 5; -static constexpr int idxTr = 6; -static constexpr int idxHe = 7; -static constexpr int idxAl = 8; - -static constexpr int defaultParameters2[nSpecies][nParameters2]{{-1, -1}, +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}, @@ -650,6 +578,10 @@ static constexpr int defaultParameters2[nSpecies][nParameters2]{{-1, -1}, /// Task to produce the response table struct tofPidMerge { + // Detector response and input parameters + Service tofResponse; + Service ccdb; + // Tables to produce Produces tablePIDEl; Produces tablePIDMu; @@ -672,17 +604,18 @@ struct tofPidMerge { Produces tablePIDFullHe; Produces tablePIDFullAl; - // Detector response parameters - o2::pid::tof::TOFResoParamsV3 mRespParamsV3; - Service ccdb; - TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration - // Configurable inheritFromBaseTask{"inheritFromBaseTask", true, "Flag to iherit all common configurables from the TOF base task"}; + // Beta tables + Produces tablePIDBeta; + Produces tablePIDTOFMass; + bool enableTableBeta = false; + bool enableTableMass = false; + Configurable enableQaHistograms{"enableQaHistograms", false, "Flag to enable the QA histograms"}; - Configurable enableTimeDependentResponse{"enableTimeDependentResponse", false, "Flag to use the collision timestamp to fetch the PID Response"}; + 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", - {defaultParameters2[0], nSpecies, nParameters2, particleNames, parameterNames2}, + {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 @@ -696,6 +629,8 @@ struct tofPidMerge { std::vector mEnabledParticlesFull; // Vector of enabled PID hypotheses to loop on when making full tables void init(o2::framework::InitContext& initContext) { + LOG(debug) << "Initializing the TOF PID Merge task"; + tofResponse->initSetup(ccdb, initContext); // Checking the tables are requested in the workflow and enabling them for (int i = 0; i < nSpecies; i++) { // First checking tiny @@ -714,12 +649,28 @@ struct tofPidMerge { } if (mEnabledParticlesFull.size() == 0 && mEnabledParticles.size() == 0) { LOG(info) << "No PID tables are required, disabling the task"; - doprocessData.value = false; - return; - } else if (doprocessData.value == false) { - LOG(fatal) << "PID tables are required but process data is disabled. Please enable it"; + doprocessRun3.value = false; + doprocessRun2.value = false; + } else { + if (tofResponse->cfgAutoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions for mass and beta"; + if (tofResponse->metadataInfo.isFullyDefined()) { + if (tofResponse->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.setUp(mRespParamsV3, ccdb); // Getting the parametrization parameters // Printing enabled tables and enabling QA histograms if needed LOG(info) << "++ Enabled tables:"; @@ -739,13 +690,47 @@ struct tofPidMerge { } 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 (tofResponse->cfgAutoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions for mass and beta"; + if (tofResponse->metadataInfo.isFullyDefined()) { + if (tofResponse->metadataInfo.isRun3()) { + doprocessRun3BetaM.value = true; + doprocessRun2BetaM.value = false; + } else { + doprocessRun2BetaM.value = true; + doprocessRun3BetaM.value = false; + } + } else { + tofResponse->metadataInfo.print(); + LOG(warning) << "Metadata is not defined, cannot autodetect process functions for mass and beta"; + } + } else { + LOG(info) << "Process functions for mass and beta are set manually"; + } + 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 idxEl: { + case kIdxEl: { if (fullTable) { tablePIDFullEl.reserve(size); } else { @@ -753,7 +738,7 @@ struct tofPidMerge { } break; } - case idxMu: { + case kIdxMu: { if (fullTable) { tablePIDFullMu.reserve(size); } else { @@ -761,7 +746,7 @@ struct tofPidMerge { } break; } - case idxPi: { + case kIdxPi: { if (fullTable) { tablePIDFullPi.reserve(size); } else { @@ -769,7 +754,7 @@ struct tofPidMerge { } break; } - case idxKa: { + case kIdxKa: { if (fullTable) { tablePIDFullKa.reserve(size); } else { @@ -777,7 +762,7 @@ struct tofPidMerge { } break; } - case idxPr: { + case kIdxPr: { if (fullTable) { tablePIDFullPr.reserve(size); } else { @@ -785,7 +770,7 @@ struct tofPidMerge { } break; } - case idxDe: { + case kIdxDe: { if (fullTable) { tablePIDFullDe.reserve(size); } else { @@ -793,7 +778,7 @@ struct tofPidMerge { } break; } - case idxTr: { + case kIdxTr: { if (fullTable) { tablePIDFullTr.reserve(size); } else { @@ -801,7 +786,7 @@ struct tofPidMerge { } break; } - case idxHe: { + case kIdxHe: { if (fullTable) { tablePIDFullHe.reserve(size); } else { @@ -809,7 +794,7 @@ struct tofPidMerge { } break; } - case idxAl: { + case kIdxAl: { if (fullTable) { tablePIDFullAl.reserve(size); } else { @@ -827,76 +812,67 @@ struct tofPidMerge { void makeTableEmpty(const int id, bool fullTable = false) { switch (id) { - case idxEl: + case kIdxEl: if (fullTable) { tablePIDFullEl(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDEl); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDEl); } break; - case idxMu: + case kIdxMu: if (fullTable) { tablePIDFullMu(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDMu); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDMu); } break; - case idxPi: + case kIdxPi: if (fullTable) { tablePIDFullPi(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDPi); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDPi); } break; - case idxKa: + case kIdxKa: if (fullTable) { tablePIDFullKa(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDKa); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDKa); } break; - case idxPr: + case kIdxPr: if (fullTable) { tablePIDFullPr(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDPr); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDPr); } break; - case idxDe: + case kIdxDe: if (fullTable) { tablePIDFullDe(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDDe); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDDe); } break; - case idxTr: + case kIdxTr: if (fullTable) { tablePIDFullTr(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDTr); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDTr); } break; - case idxHe: + case kIdxHe: if (fullTable) { tablePIDFullHe(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDHe); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDHe); } break; - case idxAl: + case kIdxAl: if (fullTable) { tablePIDFullAl(-999.f, -999.f); } else { - aod::pidutils::packInTable(-999.f, - tablePIDAl); + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDAl); } break; default: @@ -907,10 +883,11 @@ struct tofPidMerge { void process(aod::BCs const&) {} - using Trks = soa::Join; template - using ResponseImplementation = o2::pid::tof::ExpTimes; - void processData(Trks const& tracks, aod::Collisions const&, aod::BCsWithTimestamps const&) + using ResponseImplementation = o2::pid::tof::ExpTimes; + void processRun3(Run3TrksWtofWevTime const& tracks, + aod::Collisions const&, + aod::BCsWithTimestamps const& bcs) { constexpr auto responseEl = ResponseImplementation(); constexpr auto responseMu = ResponseImplementation(); @@ -922,23 +899,7 @@ struct tofPidMerge { constexpr auto responseHe = ResponseImplementation(); constexpr auto responseAl = ResponseImplementation(); - for (auto const& track : tracks) { // Loop on all tracks - if (!track.has_collision()) { // Skipping tracks without collisions - continue; - } - mTOFCalibConfig.timestamp.value = track.collision().bc_as().timestamp(); - if (enableTimeDependentResponse) { - LOG(debug) << "Updating parametrization from path '" << mTOFCalibConfig.parametrizationPath.value << "' and timestamp " << mTOFCalibConfig.timestamp.value; - if (!ccdb->getForTimeStamp(mTOFCalibConfig.parametrizationPath.value, mTOFCalibConfig.timestamp.value)->retrieveParameters(mRespParamsV3, mTOFCalibConfig.passName.value)) { - if (mTOFCalibConfig.fatalOnPassNotAvailable) { - LOGF(fatal, "Pass '%s' not available in the retrieved CCDB object", mTOFCalibConfig.passName.value.data()); - } else { - LOGF(warning, "Pass '%s' not available in the retrieved CCDB object", mTOFCalibConfig.passName.value.data()); - } - } - } - break; - } + tofResponse->processSetup(bcs.iteratorAt(0)); // Update the calibration parameters for (auto const& pidId : mEnabledParticles) { reserveTable(pidId, tracks.size(), false); @@ -963,49 +924,49 @@ struct tofPidMerge { for (auto const& pidId : mEnabledParticles) { // Loop on enabled particle hypotheses switch (pidId) { - case idxEl: { - nsigma = responseEl.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDEl); + case kIdxEl: { + nsigma = responseEl.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDEl); break; } - case idxMu: { - nsigma = responseMu.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDMu); + case kIdxMu: { + nsigma = responseMu.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDMu); break; } - case idxPi: { - nsigma = responsePi.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDPi); + case kIdxPi: { + nsigma = responsePi.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDPi); break; } - case idxKa: { - nsigma = responseKa.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDKa); + case kIdxKa: { + nsigma = responseKa.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDKa); break; } - case idxPr: { - nsigma = responsePr.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDPr); + case kIdxPr: { + nsigma = responsePr.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDPr); break; } - case idxDe: { - nsigma = responseDe.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDDe); + case kIdxDe: { + nsigma = responseDe.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDDe); break; } - case idxTr: { - nsigma = responseTr.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDTr); + case kIdxTr: { + nsigma = responseTr.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDTr); break; } - case idxHe: { - nsigma = responseHe.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDHe); + case kIdxHe: { + nsigma = responseHe.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDHe); break; } - case idxAl: { - nsigma = responseAl.GetSeparation(mRespParamsV3, trk); - aod::pidutils::packInTable(nsigma, tablePIDAl); + case kIdxAl: { + nsigma = responseAl.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDAl); break; } default: @@ -1018,57 +979,57 @@ struct tofPidMerge { } for (auto const& pidId : mEnabledParticlesFull) { // Loop on enabled particle hypotheses with full tables switch (pidId) { - case idxEl: { - resolution = responseEl.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responseEl.GetSeparation(mRespParamsV3, trk, resolution); + case kIdxEl: { + resolution = responseEl.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseEl.GetSeparation(tofResponse->parameters, trk, resolution); tablePIDFullEl(resolution, nsigma); break; } - case idxMu: { - resolution = responseMu.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responseMu.GetSeparation(mRespParamsV3, trk, resolution); + case kIdxMu: { + resolution = responseMu.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseMu.GetSeparation(tofResponse->parameters, trk, resolution); tablePIDFullMu(resolution, nsigma); break; } - case idxPi: { - resolution = responsePi.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responsePi.GetSeparation(mRespParamsV3, trk); + case kIdxPi: { + resolution = responsePi.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responsePi.GetSeparation(tofResponse->parameters, trk); tablePIDFullPi(resolution, nsigma); break; } - case idxKa: { - resolution = responseKa.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responseKa.GetSeparation(mRespParamsV3, trk, resolution); + case kIdxKa: { + resolution = responseKa.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseKa.GetSeparation(tofResponse->parameters, trk, resolution); tablePIDFullKa(resolution, nsigma); break; } - case idxPr: { - resolution = responsePr.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responsePr.GetSeparation(mRespParamsV3, trk, resolution); + case kIdxPr: { + resolution = responsePr.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responsePr.GetSeparation(tofResponse->parameters, trk, resolution); tablePIDFullPr(resolution, nsigma); break; } - case idxDe: { - resolution = responseDe.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responseDe.GetSeparation(mRespParamsV3, trk, resolution); + case kIdxDe: { + resolution = responseDe.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseDe.GetSeparation(tofResponse->parameters, trk, resolution); tablePIDFullDe(resolution, nsigma); break; } - case idxTr: { - resolution = responseTr.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responseTr.GetSeparation(mRespParamsV3, trk, resolution); + case kIdxTr: { + resolution = responseTr.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseTr.GetSeparation(tofResponse->parameters, trk, resolution); tablePIDFullTr(resolution, nsigma); break; } - case idxHe: { - resolution = responseHe.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responseHe.GetSeparation(mRespParamsV3, trk, resolution); + case kIdxHe: { + resolution = responseHe.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseHe.GetSeparation(tofResponse->parameters, trk, resolution); tablePIDFullHe(resolution, nsigma); break; } - case idxAl: { - resolution = responseAl.GetExpectedSigma(mRespParamsV3, trk); - nsigma = responseAl.GetSeparation(mRespParamsV3, trk, resolution); + case kIdxAl: { + resolution = responseAl.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseAl.GetSeparation(tofResponse->parameters, trk, resolution); tablePIDFullAl(resolution, nsigma); break; } @@ -1082,51 +1043,172 @@ struct tofPidMerge { } } } - PROCESS_SWITCH(tofPidMerge, processData, "Produce tables. Set to off if the tables are not required", true); -}; + PROCESS_SWITCH(tofPidMerge, processRun3, "Produce Run 3 Nsigma table. Set to off if the tables are not required, or autoset is on", false); -// Part 4 Beta and TOF mass computation + template + using ResponseImplementationRun2 = o2::pid::tof::ExpTimes; + void processRun2(Run2TrksWtofWevTime const& tracks, + aod::Collisions 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(); + + tofResponse->processSetup(bcs.iteratorAt(0)); // Update the calibration parameters -struct tofPidBeta { - Produces tablePIDBeta; - Produces tablePIDTOFMass; - Configurable expreso{"tof-expreso", 80, "Expected resolution for the computation of the expected beta"}; - // Detector response and input parameters - o2::pid::tof::TOFResoParamsV3 mRespParamsV3; - TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration - Service ccdb; - Configurable enableTOFParams{"enableTOFParams", false, "Flag to use TOF parameters"}; + for (auto const& pidId : mEnabledParticles) { + reserveTable(pidId, tracks.size(), false); + } - bool enableTableBeta = false; - bool enableTableMass = false; - void init(o2::framework::InitContext& initContext) - { - enableTableBeta = isTableRequiredInWorkflow(initContext, "pidTOFbeta"); - enableTableMass = isTableRequiredInWorkflow(initContext, "pidTOFmass"); - if (!enableTableBeta && !enableTableMass && !doprocessRun2 && !doprocessRun3) { - LOG(info) << "No table or process is enabled. Disabling task"; - return; + for (auto const& pidId : mEnabledParticlesFull) { + reserveTable(pidId, tracks.size(), true); } - if (metadataInfo.isFullyDefined()) { - if (metadataInfo.isRun3()) { - doprocessRun3.value = true; - } else { - doprocessRun2.value = 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; } - } - responseBeta.mExpectedResolution = expreso.value; - if (!enableTOFParams) { - return; + for (auto const& pidId : mEnabledParticles) { // Loop on enabled particle hypotheses + switch (pidId) { + case kIdxEl: { + nsigma = responseEl.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDEl); + break; + } + case kIdxMu: { + nsigma = responseMu.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDMu); + break; + } + case kIdxPi: { + nsigma = responsePi.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDPi); + break; + } + case kIdxKa: { + nsigma = responseKa.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDKa); + break; + } + case kIdxPr: { + nsigma = responsePr.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDPr); + break; + } + case kIdxDe: { + nsigma = responseDe.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDDe); + break; + } + case kIdxTr: { + nsigma = responseTr.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDTr); + break; + } + case kIdxHe: { + nsigma = responseHe.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::packInTable(nsigma, tablePIDHe); + break; + } + case kIdxAl: { + nsigma = responseAl.GetSeparation(tofResponse->parameters, trk); + aod::pidtof_tiny::binning::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(tofResponse->parameters, trk); + nsigma = responseEl.GetSeparation(tofResponse->parameters, trk, resolution); + tablePIDFullEl(resolution, nsigma); + break; + } + case kIdxMu: { + resolution = responseMu.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseMu.GetSeparation(tofResponse->parameters, trk, resolution); + tablePIDFullMu(resolution, nsigma); + break; + } + case kIdxPi: { + resolution = responsePi.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responsePi.GetSeparation(tofResponse->parameters, trk); + tablePIDFullPi(resolution, nsigma); + break; + } + case kIdxKa: { + resolution = responseKa.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseKa.GetSeparation(tofResponse->parameters, trk, resolution); + tablePIDFullKa(resolution, nsigma); + break; + } + case kIdxPr: { + resolution = responsePr.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responsePr.GetSeparation(tofResponse->parameters, trk, resolution); + tablePIDFullPr(resolution, nsigma); + break; + } + case kIdxDe: { + resolution = responseDe.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseDe.GetSeparation(tofResponse->parameters, trk, resolution); + tablePIDFullDe(resolution, nsigma); + break; + } + case kIdxTr: { + resolution = responseTr.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseTr.GetSeparation(tofResponse->parameters, trk, resolution); + tablePIDFullTr(resolution, nsigma); + break; + } + case kIdxHe: { + resolution = responseHe.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseHe.GetSeparation(tofResponse->parameters, trk, resolution); + tablePIDFullHe(resolution, nsigma); + break; + } + case kIdxAl: { + resolution = responseAl.GetExpectedSigma(tofResponse->parameters, trk); + nsigma = responseAl.GetSeparation(tofResponse->parameters, trk, resolution); + tablePIDFullAl(resolution, nsigma); + break; + } + default: + LOG(fatal) << "Wrong particle ID for full tables"; + break; + } + if (enableQaHistograms) { + hnsigmaFull[pidId]->Fill(trk.p(), nsigma); + } + } } - mTOFCalibConfig.setUp(mRespParamsV3, ccdb); // Getting the parametrization parameters } + PROCESS_SWITCH(tofPidMerge, processRun2, "Produce Run 2 Nsigma table. Set to off if the tables are not required, or autoset is on", false); - void process(aod::BCs const&) {} - - using TrksRun2 = soa::Join; - o2::pid::tof::Beta responseBetaRun2; - void processRun2(TrksRun2 const& tracks) + o2::pid::tof::Beta responseBetaRun2; + void processRun2BetaM(Run2TrksWtofWevTime const& tracks) { if (!enableTableBeta && !enableTableMass) { return; @@ -1139,19 +1221,18 @@ struct tofPidBeta { tablePIDBeta(beta, responseBetaRun2.GetExpectedSigma(trk)); } if (enableTableMass) { - if (enableTOFParams) { - tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk.tofExpMom() / (1.f + trk.sign() * mRespParamsV3.getMomentumChargeShift(trk.eta())), beta)); + if (enableTOFParamsForBetaMass) { + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk.tofExpMom() / (1.f + trk.sign() * tofResponse->parameters.getMomentumChargeShift(trk.eta())), beta)); } else { - tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk, beta)); + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk, beta)); } } } } - PROCESS_SWITCH(tofPidBeta, processRun2, "Process Run3 data i.e. input is TrackIU. If false, taken from metadata automatically", false); + 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); - using Trks = soa::Join; - o2::pid::tof::Beta responseBeta; - void processRun3(Trks const& tracks) + o2::pid::tof::Beta responseBeta; + void processRun3BetaM(Run3TrksWtofWevTime const& tracks) { if (!enableTableBeta && !enableTableMass) { return; @@ -1165,24 +1246,23 @@ struct tofPidBeta { responseBeta.GetExpectedSigma(trk)); } if (enableTableMass) { - if (enableTOFParams) { - tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk.tofExpMom() / (1.f + trk.sign() * mRespParamsV3.getMomentumChargeShift(trk.eta())), beta)); + if (enableTOFParamsForBetaMass) { + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk.tofExpMom() / (1.f + trk.sign() * tofResponse->parameters.getMomentumChargeShift(trk.eta())), beta)); } else { - tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk, beta)); + tablePIDTOFMass(o2::pid::tof::TOFMass::GetTOFMass(trk, beta)); } } } } - PROCESS_SWITCH(tofPidBeta, processRun3, "Process Run3 data i.e. input is TrackIU. If false, taken from metadata automatically", false); + 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); + o2::pid::tof::TOFResponseImpl::metadataInfo.initMetadata(cfgc); auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc)}; workflow.push_back(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..8015dc3caea 100644 --- a/Common/TableProducer/PID/pidTOFbeta.cxx +++ b/Common/TableProducer/PID/pidTOFbeta.cxx @@ -15,15 +15,26 @@ /// \brief Task to produce TOF beta and TOF mass tables /// -// O2 includes -#include "CCDB/BasicCCDBManager.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "pidTOFBase.h" -#include "TableHelper.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/PIDResponseTOF.h" -// O2Physics includes -#include "PID/PIDTOF.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::pid; @@ -37,7 +48,7 @@ void customize(std::vector& workflowOptions) std::swap(workflowOptions, options); } -#include "Framework/runDataProcessing.h" +#include struct tofPidBeta { Produces tablePIDBeta; @@ -124,7 +135,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 +153,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 967225b5ca1..ebb66f8934a 100644 --- a/Common/TableProducer/PID/pidTPC.cxx +++ b/Common/TableProducer/PID/pidTPC.cxx @@ -18,24 +18,41 @@ /// \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 "pidTPCBase.h" -// ROOT includes -#include "TFile.h" -#include "TRandom.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/CCDB/ctpRateFetcher.h" +#include "Common/Core/MetadataHelper.h" #include "Common/Core/PID/TPCPIDResponse.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/Multiplicity.h" -#include "TableHelper.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Tools/ML/model.h" -#include "pidTPCBase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -45,21 +62,21 @@ using namespace o2::framework::expressions; using namespace o2::track; using namespace o2::ml; +o2::common::core::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; + using CollMC = soa::Join; // Tables to produce Produces tablePIDFullEl; @@ -90,8 +107,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; @@ -138,19 +157,24 @@ struct tpcPid { 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"}}; - + Configurable networkInputBatchedMode{"networkInputBatchedMode", -1, {"-1: Takes all tracks, >0: Takes networkInputBatchedMode number of tracks at once"}}; + Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + ctpRateFetcher mRateFetcher; // Parametrization configuration bool useCCDBParam = false; + std::vector track_properties; 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."; + if (!((doprocessStandard && !doprocessStandard2 && !doprocessMcTuneOnData) || + (!doprocessStandard && doprocessStandard2 && !doprocessMcTuneOnData) || + (!doprocessStandard && !doprocessStandard2 && doprocessMcTuneOnData))) { + LOG(fatal) << "pid-tpc must have only one of the options 'processStandard', 'processStandard2', '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) { + auto enableFlag = [&](const std::string& particle, Configurable& flag) { enableFlagIfTableRequired(initContext, "pidTPC" + particle, flag); }; enableFlag("FullEl", pidFullEl); @@ -187,11 +211,14 @@ struct tpcPid { speciesNetworkFlags[7] = useNetworkHe; speciesNetworkFlags[8] = useNetworkAl; - // Initialise metadata object for CCDB calls + // 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; } @@ -215,17 +242,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(); } } @@ -236,19 +269,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 @@ -266,15 +301,13 @@ 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); 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(); @@ -286,13 +319,18 @@ struct tpcPid { 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.", recoPass.value); + 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(); } @@ -300,12 +338,14 @@ struct tpcPid { 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) << "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"; } } } @@ -313,20 +353,24 @@ struct tpcPid { // 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; + const uint8_t numSpecies = 9; + const uint64_t total_eval_size = size * numSpecies; // 9 species - 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; + uint64_t counter_track_props = 0, exec_counter = 0, in_batch_counter = 0, total_input_count = 0; + uint64_t track_prop_size = networkInputBatchedMode.value; + if (networkInputBatchedMode.value <= 0) { + track_prop_size = size; // If the networkInputBatchedMode is not set, we use all tracks at once + } + track_properties.resize(track_prop_size * input_dimensions); // If the networkInputBatchedMode is set, we use the number of tracks specified in the config + std::vector network_prediction(prediction_size * numSpecies); // For each mass hypotheses // 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 (int species = 0; species < numSpecies; species++) { // Loop over particle number for which network correction is used for (auto const& trk : tracks) { if (!trk.hasTPC()) { continue; @@ -336,27 +380,49 @@ struct tpcPid { continue; } } - track_properties[counter_track_props] = trk.tpcInnerParam(); + + if ((in_batch_counter == track_prop_size) || (total_input_count == total_eval_size)) { // If the batch size is reached, reset the counter + int32_t fill_shift = (exec_counter * track_prop_size - ((total_input_count == total_eval_size) ? (total_input_count % track_prop_size) : 0)) * output_dimensions; + auto start_network_eval = std::chrono::high_resolution_clock::now(); + const 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 < (in_batch_counter * output_dimensions); i += output_dimensions) { + for (int j = 0; j < output_dimensions; j++) { + network_prediction[i + j + fill_shift] = output_network[i + j]; + } + } + counter_track_props = 0; + in_batch_counter = 0; + exec_counter++; + } + + // LOG(info) << "counter_tracks_props: " << counter_track_props << "; in_batch_counter: " << in_batch_counter << "; total_input_count: " << total_input_count << "; exec_counter: " << exec_counter << "; track_prop_size: " << track_prop_size << "; size: " << size << "; track_properties.size(): " << track_properties.size(); + track_properties[counter_track_props] = trk.tpcInnerParam(); // (tracks.asArrowTable()->GetColumn("tpcInnerParam")).GetData(); 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 + 3] = o2::track::pid_constants::sMasses[species]; 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()); - 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]; + if (input_dimensions == 7 && networkVersion == "2") { + track_properties[counter_track_props + 6] = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).ft0cOccupancyInTimeRange() / 60000. : 1.; + } + if (input_dimensions == 8 && networkVersion == "3") { + track_properties[counter_track_props + 6] = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).ft0cOccupancyInTimeRange() / 60000. : 1.; + if (trk.has_collision()) { + auto trk_bc = (collisions.iteratorAt(trk.collisionId())).template bc_as(); + float hadronicRate = mRateFetcher.fetch(ccdb.service, trk_bc.timestamp(), trk_bc.runNumber(), irSource) * 1.e-3; + track_properties[counter_track_props + 7] = hadronicRate / 50.; + } else { + track_properties[counter_track_props + 7] = 1; + } } - } - counter_track_props = 0; - loop_counter += 1; + counter_track_props += input_dimensions; + in_batch_counter++; + total_input_count++; + } } track_properties.clear(); @@ -390,8 +456,8 @@ struct tpcPid { } } 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 + auto expSigma = trk.has_collision() ? response->GetExpectedSigma(collisions.iteratorAt(trk.collisionId()), trk, pid) : 0.07f * 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) @@ -400,6 +466,11 @@ struct tpcPid { } float nSigma = -999.f; + int multTPC = 0; + if (trk.has_collision()) { + auto collision = collisions.rawIteratorAt(trk.collisionId()); + multTPC = collision.multTPC(); + } 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) { @@ -422,12 +493,12 @@ struct tpcPid { LOGF(fatal, "Network output-dimensions incompatible!"); } } else { - nSigma = response->GetNumberOfSigmaMCTuned(collisions.iteratorAt(trk.collisionId()), trk, pid, tpcSignal); + nSigma = response->GetNumberOfSigmaMCTunedAtMultiplicity(multTPC, trk, pid, tpcSignal); } if (flagFull) tableFull(expSigma, nSigma); if (flagTiny) - aod::pidutils::packInTable(nSigma, tableTiny); + aod::pidtpc_tiny::binning::packInTable(nSigma, tableTiny); }; void processStandard(Coll const& collisions, Trks const& tracks, aod::BCsWithTimestamps const& bcs) @@ -483,13 +554,16 @@ struct tpcPid { 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.", recoPass.value); + 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(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"]; response->PrintAll(); } @@ -515,9 +589,101 @@ struct tpcPid { PROCESS_SWITCH(tpcPid, processStandard, "Creating PID tables without MC TuneOnData", true); - Partition mcnotTPCStandaloneTracks = (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 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); + void processStandard2(Coll const& collisions, Trks const& tracks, aod::DEdxsCorrected const& dedxscorrected, aod::BCsWithTimestamps const& bcs) + { + const uint64_t outTable_size = tracks.size(); + const uint64_t dedxscorrected_size = dedxscorrected.size(); + + if (dedxscorrected_size != outTable_size) { + LOG(fatal) << "Size of dEdx corrected table does not match size of tracks! dEdx size: " << dedxscorrected_size << ", tracks size: " << outTable_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(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); + + const uint64_t tracksForNet_size = (skipTPCOnly) ? notTPCStandaloneTracks.size() : tracksWithTPC.size(); + std::vector network_prediction; + + if (useNetworkCorrection) { + network_prediction = createNetworkPrediction(collisions, tracks, bcs, tracksForNet_size); + } + + uint64_t count_tracks = 0; + uint64_t count_tracks2 = 0; + + for (auto const& trk : tracks) { + // Loop on Tracks + + const auto& bc = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).bc_as() : bcs.begin(); + auto dedx_corr = dedxscorrected.iteratorAt(count_tracks2); + count_tracks2++; + 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(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"]; + response->PrintAll(); + } + auto makePidTablesDefault = [&trk, &dedx_corr, &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, dedx_corr.tpcSignalCorrected(), trk, collisions, network_prediction, count_tracks, tracksForNet_size); + }; + + 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) + } + } + } + PROCESS_SWITCH(tpcPid, processStandard2, "Creating PID tables with Corrected dEdx", false); 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 @@ -573,7 +739,7 @@ struct tpcPid { } 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); + 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(fatal, "Could not find ANY TPC response object for the timestamp {}!", bc.timestamp()); @@ -641,4 +807,8 @@ struct tpcPid { 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.cxx b/Common/TableProducer/PID/pidTPCBase.cxx index cf82ea0c9d5..75a5add7820 100644 --- a/Common/TableProducer/PID/pidTPCBase.cxx +++ b/Common/TableProducer/PID/pidTPCBase.cxx @@ -15,18 +15,27 @@ /// \brief Base to build tasks for TPC PID tasks. /// -#include -#include -#include - -// O2 includes -#include "CCDB/BasicCCDBManager.h" -#include "Framework/AnalysisTask.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/DataModel/FT0Corrected.h" -#include "TableHelper.h" #include "pidTPCBase.h" -#include "Framework/runDataProcessing.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -76,7 +85,105 @@ struct PidMultiplicity { PROCESS_SWITCH(PidMultiplicity, processStandard, "Process with tracks, needs propagated tracks", true); }; +struct DeDxCorrection { + Produces dEdxCorrected; + using BCsRun3 = soa::Join; + using ColEvSels = soa::Join; + using FullTracksIU = soa::Join; + + uint64_t minGlobalBC = 0; + Service ccdb; + ctpRateFetcher mRateFetcher; + + Str_dEdx_correction str_dedx_correction; + + // void init(InitContext& initContext) + void init(o2::framework::InitContext&) + { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + str_dedx_correction.init(); + } + + void processRun3( + ColEvSels const& cols, + FullTracksIU const& tracks, + aod::BCsWithTimestamps const& bcs) + { + const uint64_t outTable_size = tracks.size(); + dEdxCorrected.reserve(outTable_size); + + for (auto const& trk : tracks) { + double hadronicRate; + int multTPC; + int occupancy; + if (trk.has_collision()) { + auto collision = cols.iteratorAt(trk.collisionId()); + auto bc = collision.bc_as(); + const int runnumber = bc.runNumber(); + hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, "ZNC hadronic") * 1.e-3; // kHz + multTPC = collision.multTPC(); + occupancy = collision.trackOccupancyInTimeRange(); + } else { + auto bc = bcs.begin(); + const int runnumber = bc.runNumber(); + hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, "ZNC hadronic") * 1.e-3; // kHz + multTPC = 0; + occupancy = 0; + } + + float fTPCSignal = trk.tpcSignal(); + float fNormMultTPC = multTPC / 11000.; + + 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 = trk.tgl() > 0 ? 1 : 0; + float a1pt = std::abs(trk.signed1Pt()); + float a1pt2 = a1pt * a1pt; + float atgl = std::abs(trk.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; + + std::vector vec_occu = {fTrackOccN, fOccTPCN, fTrackOccMeanN}; + std::vector vec_track = {mbb0R, a1pt, atgl, atglmbb0R, a1ptmbb0R, side, a1pt2}; + + float fTPCSignalN_CR0 = str_dedx_correction.fReal_fTPCSignalN(vec_occu, vec_track); + + float mbb0R1 = 50 / (fTPCSignal / fTPCSignalN_CR0); + if (mbb0R1 > 1.05) + mbb0R1 = 1.05; + else if (mbb0R1 < 0.05) + mbb0R1 = 0.05; + + std::vector vec_track1 = {mbb0R1, a1pt, atgl, atgl * mbb0R1, a1pt * mbb0R1, side, a1pt2}; + float fTPCSignalN_CR1 = str_dedx_correction.fReal_fTPCSignalN(vec_occu, vec_track1); + + float corrected_dEdx = fTPCSignal / fTPCSignalN_CR1; + dEdxCorrected(corrected_dEdx); + } + } + PROCESS_SWITCH(DeDxCorrection, processRun3, "dEdx correction process", false); + + void processDummy(aod::Collisions const&) {} + + PROCESS_SWITCH(DeDxCorrection, processDummy, "Do nothing", true); +}; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/PID/pidTPCBase.h b/Common/TableProducer/PID/pidTPCBase.h index a882a598ef9..bd948bc99e6 100644 --- a/Common/TableProducer/PID/pidTPCBase.h +++ b/Common/TableProducer/PID/pidTPCBase.h @@ -19,15 +19,30 @@ #define COMMON_TABLEPRODUCER_PID_PIDTPCBASE_H_ #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" + +#include +#include + +#include // IWYU pragma: keep (do not replace with TMatrixDfwd.h) +#include + +#include +#include namespace o2::aod { +namespace pid +{ +DECLARE_SOA_COLUMN(TpcSignalCorrected, tpcSignalCorrected, float); //! +}; // namespace pid + DECLARE_SOA_TABLE(PIDMults, "AOD", "PIDMults", //! TPC auxiliary table for the PID o2::soa::Marker<1>, mult::MultTPC); +DECLARE_SOA_TABLE_FULL(DEdxsCorrected, "DEdxsCorrected", "AOD", "DEDXCORR", pid::TpcSignalCorrected); //! using PIDMult = PIDMults::iterator; +using DEdxCorrected = DEdxsCorrected::iterator; //! } // namespace o2::aod @@ -57,4 +72,41 @@ int getPIDIndex(const int pdgCode) // Get O2 PID index corresponding to MC PDG c } } +typedef struct Str_dEdx_correction { + TMatrixD fMatrix; + bool warning = true; + + // void init(std::vector& params) + void init() + { + double elements[32] = {0.99091, -0.015053, 0.0018912, -0.012305, + 0.081387, 0.003205, -0.0087404, -0.0028608, + 0.013066, 0.017012, -0.0018469, -0.0052177, + -0.0035655, 0.0017846, 0.0019127, -0.00012964, + 0.0049428, 0.0055592, -0.0010618, -0.0016134, + -0.0059098, 0.0013335, 0.00052133, 3.1119e-05, + -0.004882, 0.00077317, -0.0013827, 0.003249, + -0.00063689, 0.0016218, -0.00045215, -1.5815e-05}; + fMatrix.ResizeTo(4, 8); + fMatrix.SetMatrixArray(elements); + } + + float fReal_fTPCSignalN(std::vector vec1, std::vector vec2) + { + float result = 0.f; + // push 1. + vec1.insert(vec1.begin(), 1.0); + vec2.insert(vec2.begin(), 1.0); + for (int i = 0; i < fMatrix.GetNrows(); i++) { + for (int j = 0; j < fMatrix.GetNcols(); j++) { + double param = fMatrix(i, j); + double value1 = i > static_cast(vec1.size()) ? 0 : vec1[i]; + double value2 = j > static_cast(vec2.size()) ? 0 : vec2[j]; + result += param * value1 * value2; + } + } + return result; + } +} Str_dEdx_correction; + #endif // COMMON_TABLEPRODUCER_PID_PIDTPCBASE_H_ diff --git a/Common/TableProducer/PID/pidTPCService.cxx b/Common/TableProducer/PID/pidTPCService.cxx new file mode 100644 index 00000000000..6ad86916c1f --- /dev/null +++ b/Common/TableProducer/PID/pidTPCService.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. + +/// \file trackPropagationTester.cxx +/// \brief testing ground for track propagation +/// \author ALICE + +//=============================================================== +// +// Modularized version of TPC PID task +// +//=============================================================== + +#include "Common/Core/MetadataHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Tools/PID/pidTPCModule.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; + +o2::common::core::MetadataHelper metadataInfo; // Metadata helper + +struct pidTpcService { + + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + o2::aod::pid::pidTPCProducts products; + o2::aod::pid::pidTPCConfigurables pidTPCopts; + o2::aod::pid::pidTPCModule pidTPC; + + void init(o2::framework::InitContext& initContext) + { + // CCDB boilerplate init + ccdb->setURL(ccdburl.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()); + ccdbApi.init(ccdburl.value); + + // task-specific + pidTPC.init(ccdb, ccdbApi, initContext, pidTPCopts, metadataInfo); + } + + void processTracksIU(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs) + { + pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, static_cast(nullptr), products); + } + + void processTracksMCIU(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const&) + { + pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, static_cast(nullptr), products); + } + + void processTracksIUWithTracksQA(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs, aod::TracksQAVersion const& tracksQA) + { + pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, tracksQA, products); + } + + PROCESS_SWITCH(pidTpcService, processTracksIU, "Process TracksIU (Run 3)", true); + PROCESS_SWITCH(pidTpcService, processTracksIUWithTracksQA, "Process TracksIU (Run 3)", false); + PROCESS_SWITCH(pidTpcService, processTracksMCIU, "Process TracksIUMC (Run 3)", false); +}; + +//**************************************************************************************** +/** + * Workflow definition. + */ +//**************************************************************************************** +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata for later too + metadataInfo.initMetadata(cfgc); + + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/Common/TableProducer/PID/pidTPCServiceRun2.cxx b/Common/TableProducer/PID/pidTPCServiceRun2.cxx new file mode 100644 index 00000000000..184fb4eb6e0 --- /dev/null +++ b/Common/TableProducer/PID/pidTPCServiceRun2.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file trackPropagationTester.cxx +/// \brief testing ground for track propagation +/// \author ALICE + +//=============================================================== +// +// Modularized version of TPC PID task +// +//=============================================================== + +#include "Common/Core/MetadataHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Tools/PID/pidTPCModule.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; + +o2::common::core::MetadataHelper metadataInfo; // Metadata helper + +struct pidTpcServiceRun2 { + + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + o2::aod::pid::pidTPCProducts products; + o2::aod::pid::pidTPCConfigurables pidTPCopts; + o2::aod::pid::pidTPCModule pidTPC; + + void init(o2::framework::InitContext& initContext) + { + // CCDB boilerplate init + ccdb->setURL(ccdburl.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()); + ccdbApi.init(ccdburl.value); + + // task-specific + pidTPC.init(ccdb, ccdbApi, initContext, pidTPCopts, metadataInfo); + } + + void processTracks(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs) + { + pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, static_cast(nullptr), products); + } + + void processTracksMC(soa::Join const& collisions, soa::Join const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const&) + { + pidTPC.process(ccdb, ccdbApi, bcs, collisions, tracks, static_cast(nullptr), products); + } + + PROCESS_SWITCH(pidTpcServiceRun2, processTracks, "Process Tracks", true); + PROCESS_SWITCH(pidTpcServiceRun2, processTracksMC, "Process Tracks in MC (enables tune-on-data)", false); +}; + +//**************************************************************************************** +/** + * Workflow definition. + */ +//**************************************************************************************** +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata for later too + metadataInfo.initMetadata(cfgc); + + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/Common/TableProducer/caloClusterProducer.cxx b/Common/TableProducer/caloClusterProducer.cxx index b569cf7a58f..5227b133335 100644 --- a/Common/TableProducer/caloClusterProducer.cxx +++ b/Common/TableProducer/caloClusterProducer.cxx @@ -9,36 +9,55 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/CaloClusters.h" +/// \file caloClusterProducer.cxx +/// \brief Produces PHOS clusters from PHOS cells +/// +/// \author Dmitri Peresunko + +#include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" -#include "ReconstructionDataFormats/TrackParametrization.h" -#include "DetectorsBase/Propagator.h" - -#include "CommonUtils/NameConf.h" -#include "CCDB/BasicCCDBManager.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsPHOS/Cell.h" -#include "DataFormatsPHOS/Cluster.h" -#include "DataFormatsPHOS/TriggerRecord.h" -#include "DataFormatsPHOS/MCLabel.h" -#include "DataFormatsPHOS/BadChannelsMap.h" -#include "DataFormatsPHOS/CalibParams.h" -#include "PHOSBase/Geometry.h" -#include "PHOSReconstruction/Clusterer.h" +#include "Common/DataModel/CaloClusters.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include 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 +65,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 +90,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,16 +106,16 @@ 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 - int mStart[kCpvCells]; // X (phi) track coordinate in PHOS plane - int mEnd[kCpvCells]; // Z (theta) track coordinate in PHOS plane + int64_t mTR{-1}; // BC ref + int mStart[kCpvCells] = {0}; // X (phi) track coordinate in PHOS plane + int mEnd[kCpvCells] = {0}; // Z (theta) track coordinate in PHOS plane }; void init(o2::framework::InitContext&) @@ -123,25 +142,25 @@ struct caloClusterProducerTask { } std::map bcMap; int bcId = 0; - for (auto bc : bcs) { + for (const auto& bc : bcs) { bcMap[bc.globalBC()] = bcId; bcId++; } // If several collisions appear in BC, choose one with largers number of contributors std::map colMap; - int colId = 0; - for (auto cl : colls) { + int colIdOuter = 0; + 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; + colMap[cl.bc_as().globalBC()] = colIdOuter; } else { // not unique collision per BC auto coll2 = colls.begin() + colbc->second; if (cl.numContrib() > coll2.numContrib()) { - colMap[cl.bc_as().globalBC()] = colId; + colMap[cl.bc_as().globalBC()] = colIdOuter; } } - colId++; + colIdOuter++; } // Fill list of cells and cell TrigRecs per TF as an input for clusterizer @@ -149,11 +168,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 +201,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 +235,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 +264,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,19 +274,19 @@ struct caloClusterProducerTask { } // Fill output - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { int firstClusterInEvent = cluTR.getFirstEntry(); int lastClusterInEvent = firstClusterInEvent + cluTR.getNumberOfObjects(); // Extract primary vertex TVector3 vtx = {0., 0., 0.}; // default, if not collision will be found - int colId = -1; + int colIdInner = -1; auto coliter = colMap.find(cluTR.getBCData().toLong()); if (coliter != colMap.end()) { // get vertex from collision // find collision corresponding to current BC auto clvtx = colls.begin() + coliter->second; vtx.SetXYZ(clvtx.posX(), clvtx.posY(), clvtx.posZ()); - colId = coliter->second; + colIdInner = coliter->second; } bool cpvExist = false; @@ -293,7 +312,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 +325,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 +377,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) { @@ -370,7 +389,7 @@ struct caloClusterProducerTask { clu.getElipsAxis(lambdaShort, lambdaLong); // Clear Collision assignment - if (colId == -1) { + if (colIdInner == -1) { // Ambiguos Collision assignment cluambcursor( bcMap[cluTR.getBCData().toLong()], @@ -384,7 +403,7 @@ struct caloClusterProducerTask { clu.getDistanceToBadChannel()); } else { // Normal collision - auto col = colls.begin() + colId; + auto col = colls.begin() + colIdInner; clucursor( col, mom.X(), mom.Y(), mom.Z(), e, @@ -400,11 +419,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,25 +436,25 @@ struct caloClusterProducerTask { } std::map bcMap; int bcId = 0; - for (auto bc : bcs) { + for (auto const& bc : bcs) { bcMap[bc.globalBC()] = bcId; bcId++; } // If several collisions appear in BC, choose one with largers number of contributors std::map colMap; - int colId = 0; - for (auto cl : colls) { + int colIdOuter = 0; + 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; + colMap[cl.bc_as().globalBC()] = colIdOuter; } else { // not unique collision per BC auto coll2 = colls.begin() + colbc->second; if (cl.numContrib() > coll2.numContrib()) { - colMap[cl.bc_as().globalBC()] = colId; + colMap[cl.bc_as().globalBC()] = colIdOuter; } } - colId++; + colIdOuter++; } // Fill list of cells and cell TrigRecs per TF as an input for clusterizer @@ -443,11 +462,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 +496,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 +551,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 +580,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,19 +590,19 @@ struct caloClusterProducerTask { } // Fill output - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { int firstClusterInEvent = cluTR.getFirstEntry(); int lastClusterInEvent = firstClusterInEvent + cluTR.getNumberOfObjects(); // Extract primary vertex TVector3 vtx = {0., 0., 0.}; // default, if not collision will be found - int colId = -1; + int colIdInner = -1; auto coliter = colMap.find(cluTR.getBCData().toLong()); if (coliter != colMap.end()) { // get vertex from collision // find collision corresponding to current BC auto clvtx = colls.begin() + coliter->second; vtx.SetXYZ(clvtx.posX(), clvtx.posY(), clvtx.posZ()); - colId = coliter->second; + colIdInner = coliter->second; } bool cpvExist = false; @@ -609,7 +628,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 +641,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 +693,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,12 +708,12 @@ 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()); } // Clear Collision assignment - if (colId == -1) { + if (colIdInner == -1) { // Ambiguos Collision assignment cluambcursor( bcMap[cluTR.getBCData().toLong()], @@ -711,7 +730,7 @@ struct caloClusterProducerTask { mcamplitudes); } else { // Normal collision - auto col = colls.begin() + colId; + auto col = colls.begin() + colIdInner; clucursor( col, mom.X(), mom.Y(), mom.Z(), e, @@ -730,7 +749,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,36 +779,36 @@ struct caloClusterProducerTask { std::map bcMap; int bcId = 0; - for (auto bc : bcs) { + for (const auto& bc : bcs) { bcMap[bc.globalBC()] = bcId; bcId++; } // If several collisions appear in BC, choose one with largers number of contributors std::map colMap; - int colId = 0; - for (auto cl : colls) { + int colIdOuter = 0; + 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; + colMap[cl.bc_as().globalBC()] = colIdOuter; } else { // not unique collision per BC auto coll2 = colls.begin() + colbc->second; if (cl.numContrib() > coll2.numContrib()) { - colMap[cl.bc_as().globalBC()] = colId; + colMap[cl.bc_as().globalBC()] = colIdOuter; } } - colId++; + colIdOuter++; } // Fill list of cells and cell TrigRecs per TF as an input for clusterizer // clusterize // 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 +837,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 +871,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 +900,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 +909,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 +922,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 +949,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 +973,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,19 +984,19 @@ struct caloClusterProducerTask { } // Fill output tables - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { int firstClusterInEvent = cluTR.getFirstEntry(); int lastClusterInEvent = firstClusterInEvent + cluTR.getNumberOfObjects(); // Extract primary vertex TVector3 vtx = {0., 0., 0.}; // default, if not collision will be found - int colId = -1; + int colIdInner = -1; auto coliter = colMap.find(cluTR.getBCData().toLong()); if (coliter != colMap.end()) { // get vertex from collision // find collision corresponding to current BC auto clvtx = colls.begin() + coliter->second; vtx.SetXYZ(clvtx.posX(), clvtx.posY(), clvtx.posZ()); - colId = coliter->second; + colIdInner = coliter->second; } bool cpvExist = false; @@ -1012,7 +1031,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 +1044,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 +1102,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 +1113,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.; @@ -1108,7 +1127,7 @@ struct caloClusterProducerTask { if (cpvExist) { cpvindex = -1; // there were CPV clusters } - if (colId == -1) { + if (colIdInner == -1) { // Ambiguos Collision assignment cluambcursor( bcMap[cluTR.getBCData().toLong()], @@ -1122,7 +1141,7 @@ struct caloClusterProducerTask { clu.getDistanceToBadChannel()); } else { // Normal collision - auto col = colls.begin() + colId; + auto col = colls.begin() + colIdInner; clucursor( col, mom.X(), mom.Y(), mom.Z(), e, @@ -1140,12 +1159,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,36 +1188,36 @@ struct caloClusterProducerTask { std::map bcMap; int bcId = 0; - for (auto bc : bcs) { + for (const auto& bc : bcs) { bcMap[bc.globalBC()] = bcId; bcId++; } // If several collisions appear in BC, choose one with largers number of contributors std::map colMap; - int colId = 0; - for (auto cl : colls) { + int colIdOuter = 0; + 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; + colMap[cl.bc_as().globalBC()] = colIdOuter; } else { // not unique collision per BC auto coll2 = colls.begin() + colbc->second; if (cl.numContrib() > coll2.numContrib()) { - colMap[cl.bc_as().globalBC()] = colId; + colMap[cl.bc_as().globalBC()] = colIdOuter; } } - colId++; + colIdOuter++; } // Fill list of cells and cell TrigRecs per TF as an input for clusterizer // clusterize // 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 +1247,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 +1302,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 +1331,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 +1340,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 +1353,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 +1380,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 +1404,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,19 +1415,19 @@ struct caloClusterProducerTask { } // Fill output tables - for (auto& cluTR : outputPHOSClusterTrigRecs) { + for (const auto& cluTR : outputPHOSClusterTrigRecs) { int firstClusterInEvent = cluTR.getFirstEntry(); int lastClusterInEvent = firstClusterInEvent + cluTR.getNumberOfObjects(); // Extract primary vertex TVector3 vtx = {0., 0., 0.}; // default, if not collision will be found - int colId = -1; + int colIdInner = -1; auto coliter = colMap.find(cluTR.getBCData().toLong()); if (coliter != colMap.end()) { // get vertex from collision // find collision corresponding to current BC auto clvtx = colls.begin() + coliter->second; vtx.SetXYZ(clvtx.posX(), clvtx.posY(), clvtx.posZ()); - colId = coliter->second; + colIdInner = coliter->second; } bool cpvExist = false; @@ -1442,7 +1461,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 +1474,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 +1530,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 +1541,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,11 +1559,11 @@ 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()); } - if (colId == -1) { + if (colIdInner == -1) { // Ambiguos Collision assignment cluambcursor( bcMap[cluTR.getBCData().toLong()], @@ -1560,7 +1579,7 @@ struct caloClusterProducerTask { mclabels, mcamplitudes); } else { // Normal collision - auto col = colls.begin() + colId; + auto col = colls.begin() + colIdInner; clucursor( col, mom.X(), mom.Y(), mom.Z(), e, @@ -1581,17 +1600,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 +1631,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 +1646,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 +1675,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 +1684,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 +1701,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 +1717,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 +1729,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 +1782,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 871978a851c..94fcf14ff2a 100644 --- a/Common/TableProducer/centralityTable.cxx +++ b/Common/TableProducer/centralityTable.cxx @@ -8,28 +8,48 @@ // In applying this license CERN does not 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 "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/HistogramRegistry.h" -#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/MetadataHelper.h" +#include "Common/Core/TableHelper.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include -#include "TableHelper.h" -#include "TList.h" +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; +o2::common::core::MetadataHelper metadataInfo; // Metadata helper + static constexpr int kCentRun2V0Ms = 0; static constexpr int kCentRun2V0As = 1; static constexpr int kCentRun2SPDTrks = 2; @@ -40,10 +60,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", @@ -54,10 +77,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; @@ -70,23 +96,30 @@ 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 fatalizeMultCalibSanity{"fatalizeMultCalibSanity", false, {"Option to do fatalize the sanity check on the multiplicity calibration"}}; 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"}; + ConfigurableAxis binsPVcontr{"binsPVcontr", {100, 0.f, 100.f}, "PV mult."}; int mRunNumber; - struct tagRun2V0MCalibration { + struct TagRun2V0MCalibration { bool mCalibrationStored = false; TFormula* mMCScale = nullptr; float mMCScalePars[6] = {0.0}; @@ -94,39 +127,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), @@ -151,14 +184,17 @@ struct CentralityTable { 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}; @@ -170,25 +206,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; @@ -208,32 +244,33 @@ struct CentralityTable { 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("FT0M/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0M percentile"}, {binsPVcontr, "PV mult."}}); + histos.add("FT0M/MultvsPV", "FT0M mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0M mult."}, {binsPVcontr, "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("FT0A/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0A percentile"}, {binsPVcontr, "PV mult."}}); + histos.add("FT0A/MultvsPV", "FT0A mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0A mult."}, {binsPVcontr, "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.add("FT0C/percentilevsPV", "percentile vs PV mult.", HistType::kTH2D, {{binsPercentile, "FT0C percentile"}, {binsPVcontr, "PV mult."}}); + histos.add("FT0C/MultvsPV", "FT0C mult. vs PV mult.", HistType::kTH2D, {{1000, 0, 5000, "FT0C mult."}, {binsPVcontr, "PV mult."}}); histos.addClone("FT0M/", "sel8FT0M/"); histos.addClone("FT0C/", "sel8FT0C/"); histos.addClone("FT0A/", "sel8FT0A/"); - listCalib.setObject(new TList); + histos.print(); } using BCsWithTimestampsAndRun2Infos = soa::Join; @@ -243,8 +280,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; @@ -266,20 +317,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]) { @@ -289,7 +348,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]) { @@ -299,7 +362,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]) { @@ -310,7 +377,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]) { @@ -320,7 +391,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]) { @@ -330,24 +405,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]); + auto scaleMC = [](float x, const float pars[6]) { + return std::pow(((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); }; if (isTableEnabled[kCentRun2V0Ms]) { @@ -422,6 +497,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) { @@ -440,12 +517,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; @@ -456,20 +542,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) { @@ -487,42 +601,49 @@ 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(); } } } @@ -535,10 +656,10 @@ struct CentralityTable { * @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]); + auto scaleMC = [](float x, const 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; @@ -561,12 +682,12 @@ struct CentralityTable { switch (table) { case kCentFV0As: if constexpr (enableCentFV0) { - populateTable(centFV0A, FV0AInfo, collision.multZeqFV0A()); + populateTable(centFV0A, fv0aInfo, collision.multZeqFV0A()); } break; case kCentFT0Ms: if constexpr (enableCentFT0) { - const float perC = 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()); @@ -581,42 +702,57 @@ struct CentralityTable { break; case kCentFT0As: if constexpr (enableCentFT0) { - const float perC = 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.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.multNTracksPV()); + histos.fill(HIST("sel8FT0A/MultvsPV"), collision.multZeqFT0A() + collision.multZeqFT0C(), collision.multNTracksPV()); } } } break; case kCentFT0Cs: if constexpr (enableCentFT0) { - const float perC = 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.multZeqFT0C(), 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.multZeqFT0C(), 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: @@ -627,6 +763,11 @@ struct CentralityTable { } } + void processRun3Complete(soa::Join const& collisions, BCsWithTimestamps const&) + { + produceRun3Tables(collisions); + } + void processRun3(soa::Join const& collisions, BCsWithTimestamps const&) { produceRun3Tables(collisions); @@ -642,8 +783,13 @@ struct CentralityTable { // Process switches PROCESS_SWITCH(CentralityTable, processRun2, "Provide Run2 calibrated centrality/multiplicity percentiles tables", true); + PROCESS_SWITCH(CentralityTable, processRun3Complete, "Provide Run3 calibrated centrality/multiplicity percentiles tables using MFT and global tracks (requires extra subscriptions)", false); PROCESS_SWITCH(CentralityTable, processRun3, "Provide Run3 calibrated centrality/multiplicity percentiles tables", false); PROCESS_SWITCH(CentralityTable, processRun3FT0, "Provide Run3 calibrated centrality/multiplicity percentiles tables for FT0 only", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(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..bf27b23aa5d --- /dev/null +++ b/Common/TableProducer/eseTableProducer.cxx @@ -0,0 +1,372 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "FFitWeights.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EseTable.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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; + + Produces meanPts; + Produces meanPtShapes; + + OutputObj weightsFFit{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 cfgMeanPt{"cfgMeanPt", 0, "lvl, 0: First profile, 1: Second profile, 2: 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}; + + static constexpr float ThresholdAmplitude{1e-8f}; + static constexpr int Step1{1}; + static constexpr int Step2{2}; + + 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* eventShape{nullptr}; + + Service ccdb; + + struct Config { + TH1D* mEfficiency = nullptr; + bool correctionsLoaded = false; + } cfg; + + Configurable cfgVtxZ{"cfgVtxZ", 10.0f, "max z vertex position"}; + Configurable cfgEta{"cfgEta", 0.8f, "max eta"}; + Configurable cfgPtmin{"cfgPtmin", 0.2f, "min pt"}; + Configurable cfgPtmax{"cfgPtmax", 5.0f, "max pt"}; + Configurable cfgChi2PrITSCls{"cfgChi2PrITSCls", 4.0f, "max chi2 per ITS cluster"}; + Configurable cfgChi2PrTPCCls{"cfgChi2PrTPCCls", 2.5f, "max chi2 per TPC cluster"}; + Configurable cfgDCAz{"cfgDCAz", 2.0f, "max DCAz cut"}; + Configurable cfgEfficiency{"cfgEfficiency", "", "CCDB path to efficiency object"}; + + // o2::framework::expressions::Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; + o2::framework::expressions::Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == static_cast(true))) && (aod::track::itsChi2NCl < cfgChi2PrITSCls) && (aod::track::tpcChi2NCl < cfgChi2PrTPCCls) && nabs(aod::track::dcaZ) < cfgDCAz; + + Preslice perCollision = aod::track::collisionId; + using GFWTracks = soa::Filtered>; + + 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}}}); + registry.add("hMeanPtStat", "", {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)}); + } + } + weightsFFit->setBinAxis(cfgaxisqn->at(0), cfgaxisqn->at(1), cfgaxisqn->at(2)); + weightsFFit->setResolution(cfgnResolution); + weightsFFit->setQnType(veccfg); + weightsFFit->init(); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + + auto timestamp = bc.timestamp(); + + if (cfgESE) { + eventShape = ccdb->getForTimeStamp(cfgEsePath, timestamp); + if (!eventShape) + LOGF(fatal, "failed loading qSelection with ese flag"); + LOGF(info, "successfully loaded qSelection"); + } + if (!cfgEfficiency.value.empty()) { + cfg.mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (cfg.mEfficiency == nullptr) { + 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; + } + } + + float calcRedqn(const float& Qx, const float& Qy, const float& Mult) + { + float dqn{0.0f}; + float qn{0.0f}; + + dqn = Qx * Qx + Qy * Qy; + qn = std::sqrt(dqn) / std::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 > ThresholdAmplitude) { + float qnval = calcRedqn(QX * sumAmpl, QY * sumAmpl, sumAmpl); + weightsFFit->fillWeights(centr, qnval, nHarm, pf); + if (cfgESE) { + splineVal = eventShape->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 fQx{col.qvecRe()[detInd + cfgnCorrLevel]}; + const auto fQy{col.qvecIm()[detInd + cfgnCorrLevel]}; + const auto sumAmpl{col.qvecAmp()[detId]}; + return {fQx, fQy, 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); + } + } + } + } + }; + + template + std::pair calculateMeanPt(TTracks const& tracks, Cent const& centrality) + { + double meanPtEvent{0.0}; + double effEvent{0.0}; + for (const auto& track : tracks) { + double weff = getEfficiency(track); + effEvent += weff; + meanPtEvent += track.pt() * weff; + } + if (meanPtEvent == 0.0) + return std::make_pair(0.0, 0.0); + double mean = meanPtEvent / effEvent; + weightsFFit->fillPt(centrality, mean, effEvent, true); + return std::make_pair(mean, effEvent); + } + + template + double getEfficiency(TTrack track) + { + double eff = 1.; + if (cfg.mEfficiency) + eff = cfg.mEfficiency->GetBinContent(cfg.mEfficiency->FindBin(track.pt())); + if (eff == 0) + return -1.; + else + return 1. / eff; + } + + 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, "process q vectors to calculate reduced q-vector", true); + + void processMeanPt(soa::Join::iterator const& collision, aod::BCsWithTimestamps const&, GFWTracks const& tracks) + { + + std::vector meanPt{-1}; + std::vector meanPtShape{-1}; + if (collision.posZ() < -cfgVtxZ || collision.posZ() > cfgVtxZ) { + meanPts(meanPt); + meanPtShapes(meanPtShape); + return; + } + + registry.fill(HIST("hMeanPtStat"), 0.5); + const auto centrality = collision.centFT0C(); + const auto mean = calculateMeanPt(tracks, centrality); + + if (cfgMeanPt == 0) { + registry.fill(HIST("hMeanPtStat"), 1.5); + } else { + const auto avgpt = eventShape->getPtMult(centrality); + if (mean.first == 0.0) { + registry.fill(HIST("hMeanPtStat"), cfgMeanPt == Step1 ? 2.5 : 3.5); + } else { + const auto binval = (mean.first - avgpt) / avgpt; + weightsFFit->fillPt(centrality, binval, mean.second, false); + meanPt[0] = binval; + if (cfgMeanPt == Step1) { + registry.fill(HIST("hMeanPtStat"), 2.5); + } else if (cfgMeanPt == Step2) { + registry.fill(HIST("hMeanPtStat"), 3.5); + const auto value = eventShape->evalPt(centrality, binval); + meanPtShape[0] = value; + } + } + } + + meanPts(meanPt); + meanPtShapes(meanPtShape); + } + PROCESS_SWITCH(EseTableProducer, processMeanPt, "process mean pt selection", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/eventSelection.cxx b/Common/TableProducer/eventSelection.cxx index 8e0ad7e1544..e79c75a5c48 100644 --- a/Common/TableProducer/eventSelection.cxx +++ b/Common/TableProducer/eventSelection.cxx @@ -9,86 +9,121 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +/// \file eventSelection.cxx +/// \brief Event selection task +/// +/// \author Evgeny Kryshen and Igor Altsybeev + #include "Common/DataModel/EventSelection.h" + #include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.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 "TH1D.h" +#include "Common/Core/MetadataHelper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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::aod::evsel; -MetadataHelper metadataInfo; // Metadata helper +o2::common::core::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"}; + Configurable confNumberOfOrbitsPerTF{"NumberOfOrbitsPerTF", -1, "Number of orbits per Time Frame. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) + + 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 - + std::string strLPMProductionTag = ""; // MC production tag to be retrieved from AO2D metadata + + 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); ccdb->setLocalObjectValidityChecking(); + strLPMProductionTag = metadataInfo.get("LPMProductionTag"); // to extract info from ccdb by the tag - histos.add("hCounterTVX", "", kTH1D, {{1, 0., 1.}}); - histos.add("hCounterTCE", "", kTH1D, {{1, 0., 1.}}); - histos.add("hCounterZEM", "", kTH1D, {{1, 0., 1.}}); - histos.add("hCounterZNC", "", kTH1D, {{1, 0., 1.}}); - histos.add("hCounterTVXafterBCcuts", "", kTH1D, {{1, 0., 1.}}); - histos.add("hCounterTCEafterBCcuts", "", kTH1D, {{1, 0., 1.}}); - histos.add("hCounterZEMafterBCcuts", "", kTH1D, {{1, 0., 1.}}); - histos.add("hCounterZNCafterBCcuts", "", 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.}}); - histos.add("hLumiTVXafterBCcuts", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); - histos.add("hLumiTCEafterBCcuts", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); - histos.add("hLumiZEMafterBCcuts", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); - histos.add("hLumiZNCafterBCcuts", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterInvalidBCTimestamp", "", kTH1D, {{1, 0., 1.}}); } void processRun2( @@ -101,19 +136,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); } @@ -149,9 +184,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.}; @@ -211,8 +246,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); @@ -225,68 +261,122 @@ 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; + int run3min = 500000; + if (run < run3min) { // unanchored Run3 MC + auto runDuration = ccdb->getRunDuration(run, true); // fatalise if timestamps are not found + // SOR and EOR timestamps + sorTimestamp = runDuration.first; // timestamp of the SOR/SOX/STF in ms + eorTimestamp = runDuration.second; // timestamp of the EOR/EOX/ETF in ms + auto ctp = ccdb->getForTimeStamp>("CTP/Calib/OrbitReset", sorTimestamp / 2 + eorTimestamp / 2); + auto orbitResetMUS = (*ctp)[0]; + // first bc of the first orbit + bcSOR = static_cast((sorTimestamp * 1000 - orbitResetMUS) / o2::constants::lhc::LHCOrbitMUS) * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = 32; // hard-coded for Run3 MC (no info from ccdb at the moment) + } else { + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run, strLPMProductionTag); + // SOR and EOR timestamps + sorTimestamp = runInfo.sor; + eorTimestamp = runInfo.eor; + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = confNumberOfOrbitsPerTF < 0 ? runInfo.orbitsPerTF * nBCsPerOrbit : confNumberOfOrbitsPerTF * nBCsPerOrbit; + if (strLPMProductionTag == "LHC25f3") // temporary workaround for MC production LHC25f3 anchored to Pb-Pb 2023 apass5 (to be removed once the info is in ccdb) + nBCsPerTF = 8 * nBCsPerOrbit; + } + + // timestamp of the middle of the run used to access run-wise CCDB entries + int64_t ts = sorTimestamp / 2 + eorTimestamp / 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); + + // 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>("RCT/Flags/RunFlags", ts, metadata); + ccdb->setFatalWhenNull(1); + if (mapRCT == nullptr) { + LOGP(info, "rct object missing... inserting dummy rct flags"); + mapRCT = new std::map; + uint32_t dummyValue = 1u << 31; // setting bit 31 to indicate that rct object is missing + mapRCT->insert(std::pair(sorTimestamp, dummyValue)); + } + } // 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; + if (confTriggerBcShift == 999) { // o2-linter: disable=magic-number (special shift for early 2022 data) + triggerBcShift = (run <= 526766 || (run >= 526886 && run <= 527237) || (run >= 527259 && run <= 527518) || run == 527523 || run == 527734 || run >= 534091) ? 0 : 294; // o2-linter: disable=magic-number (magic list of runs) } - // 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); } @@ -318,12 +408,14 @@ struct BcSelectionTask { } --bc; backwardMoveCount++; - if (bc.globalBC() + 1 == globalBC) { + int bcDistanceToBeamGasForFT0 = 1; + int bcDistanceToBeamGasForFDD = 5; + if (bc.globalBC() + bcDistanceToBeamGasForFT0 == globalBC) { timeV0ABG = bc.has_fv0a() ? bc.fv0a().time() : -999.f; timeT0ABG = bc.has_ft0() ? bc.ft0().timeA() : -999.f; timeT0CBG = bc.has_ft0() ? bc.ft0().timeC() : -999.f; } - if (bc.globalBC() + 5 == globalBC) { + if (bc.globalBC() + bcDistanceToBeamGasForFDD == globalBC) { timeFDABG = bc.has_fdd() ? bc.fdd().timeA() : -999.f; timeFDCBG = bc.has_fdd() ? bc.fdd().timeC() : -999.f; } @@ -345,85 +437,71 @@ 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++) { // o2-linter: disable=magic-number (counting first 4 ITS layers) + 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; int32_t foundZDC = bc.has_zdc() ? bc.zdc().globalIndex() : -1; LOGP(debug, "foundFT0={}", foundFT0); - // 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.; - float csTCE = isPP ? -1. : 10.36e6; - float csZEM = isPP ? -1. : 415.2e6; // see AN: https://alice-notes.web.cern.ch/node/1515 - float csZNC = isPP ? -1. : 214.5e6; // see AN: https://alice-notes.web.cern.ch/node/1515 - if (run > 543437 && run < 543514) { - csTCE = 8.3e6; - } - if (run >= 543514) { - csTCE = 4.10e6; // see AN: https://alice-notes.web.cern.ch/node/1515 - } - - // Fill TVX (T0 vertex) counters - if (TESTBIT(selection, kIsTriggerTVX)) { - histos.get(HIST("hCounterTVX"))->Fill(srun, 1); - histos.get(HIST("hLumiTVX"))->Fill(srun, 1. / csTVX); - if (TESTBIT(selection, kNoITSROFrameBorder) && TESTBIT(selection, kNoTimeFrameBorder)) { - histos.get(HIST("hCounterTVXafterBCcuts"))->Fill(srun, 1); - histos.get(HIST("hLumiTVXafterBCcuts"))->Fill(srun, 1. / csTVX); - } - } - // Fill counters and lumi histograms for Pb-Pb lumi monitoring - // TODO: introduce pileup correction - if (bc.has_ft0() ? (TESTBIT(selection, kIsTriggerTVX) && TESTBIT(bc.ft0().triggerMask(), o2::ft0::Triggers::bitCen)) : 0) { - histos.get(HIST("hCounterTCE"))->Fill(srun, 1); - histos.get(HIST("hLumiTCE"))->Fill(srun, 1. / csTCE); - if (TESTBIT(selection, kNoITSROFrameBorder) && TESTBIT(selection, kNoTimeFrameBorder)) { - histos.get(HIST("hCounterTCEafterBCcuts"))->Fill(srun, 1); - histos.get(HIST("hLumiTCEafterBCcuts"))->Fill(srun, 1. / csTCE); - } - } - if (TESTBIT(selection, kIsBBZNA) || TESTBIT(selection, kIsBBZNC)) { - histos.get(HIST("hCounterZEM"))->Fill(srun, 1); - histos.get(HIST("hLumiZEM"))->Fill(srun, 1. / csZEM); - if (TESTBIT(selection, kNoITSROFrameBorder) && TESTBIT(selection, kNoTimeFrameBorder)) { - histos.get(HIST("hCounterZEMafterBCcuts"))->Fill(srun, 1); - histos.get(HIST("hLumiZEMafterBCcuts"))->Fill(srun, 1. / csZEM); - } - } - if (TESTBIT(selection, kIsBBZNC)) { - histos.get(HIST("hCounterZNC"))->Fill(srun, 1); - histos.get(HIST("hLumiZNC"))->Fill(srun, 1. / csZNC); - if (TESTBIT(selection, kNoITSROFrameBorder) && TESTBIT(selection, kNoTimeFrameBorder)) { - histos.get(HIST("hCounterZNCafterBCcuts"))->Fill(srun, 1); - histos.get(HIST("hLumiZNCafterBCcuts"))->Fill(srun, 1. / csZNC); + 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); @@ -432,31 +510,40 @@ 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"}; + 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"}; - Configurable confTimeIntervalForOccupancyCalculationMax{"TimeIntervalForOccupancyCalculationMax", 100, "Max time diff window for TPC occupancy calculation, us"}; - Configurable> confTimeBinsForOccupancyCalculation{"TimeBinsForOccupancyCalculation", {-40, -20, 0, 25, 50, 75, 100}, "Time bins for occupancy calculation and corresponding cuts (us)"}; - Configurable> confReferenceOccupanciesInTimeBins{"ReferenceOccupanciesInTimeBins", {3000, 1400, 750, 1000, 1750, 4000}, "Occupancy cuts in time bins (n tracks)"}; - Configurable confTimeRangeVetoOnCollStandard{"TimeRangeVetoOnCollStandard", 10, "Exclusion of a collision if there are other collisions nearby, +/- us"}; - Configurable confTimeRangeVetoOnCollNarrow{"TimeRangeVetoOnCollNarrow", 4, "Exclusion of a collision if there are other collisions nearby, +/- us"}; - Configurable confUseWeightsForOccupancyVariable{"UseWeightsForOccupancyEstimator", 1, "Use or not the delta-time weights for the occupancy estimator"}; + 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) + Configurable confNumberOfOrbitsPerTF{"NumberOfOrbitsPerTF", -1, "Number of orbits per Time Frame. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) + + Partition tracklets = (aod::track::trackType == static_cast(o2::aod::track::TrackTypeEnum::Run2Tracklet)); - 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 + 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 + std::string strLPMProductionTag = ""; // MC production tag to be retrieved from AO2D metadata - int32_t findClosest(int64_t globalBC, std::map& bcs) + int32_t findClosest(int64_t globalBC, const std::map& bcs) { auto it = bcs.lower_bound(globalBC); int64_t bc1 = it->first; @@ -470,18 +557,58 @@ 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&) { - 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; + if (metadataInfo.isFullyDefined()) { // Check if the metadata is initialized (only if not forced from the workflow configuration) + if (isMC == -1) { + LOG(info) << "Autosetting the MC mode based on metadata"; + if (metadataInfo.isMC()) { + isMC.value = 1; + } else { + isMC.value = 0; + } } } + strLPMProductionTag = metadataInfo.get("LPMProductionTag"); // to extract info from ccdb by the tag - // ccdb->setURL("http://ccdb-test.cern.ch:8080"); ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -489,7 +616,6 @@ struct EventSelectionTask { histos.add("hColCounterAll", "", kTH1D, {{1, 0., 1.}}); histos.add("hColCounterTVX", "", kTH1D, {{1, 0., 1.}}); histos.add("hColCounterAcc", "", kTH1D, {{1, 0., 1.}}); - // histos.add("hOccupancy", "", kTH1D, {{200, 0., 10000}}); } void process(aod::Collisions const& collisions) @@ -497,12 +623,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; @@ -538,7 +664,10 @@ struct EventSelectionTask { int spdClusters = bc.spdClustersL0() + bc.spdClustersL1(); selection |= (spdClusters < par->fSPDClsVsTklA + nTkl * par->fSPDClsVsTklB) ? BIT(kNoSPDClsVsTklBG) : 0; - selection |= !(nTkl < 6 && multV0C012 > par->fV0C012vsTklA + nTkl * par->fV0C012vsTklB) ? BIT(kNoV0C012vsTklBG) : 0; + selection |= !(nTkl < 6 && multV0C012 > par->fV0C012vsTklA + nTkl * par->fV0C012vsTklB) ? BIT(kNoV0C012vsTklBG) : 0; // o2-linter: disable=magic-number (nTkl dependent parameterization) + + // copy rct flags from bcsel table + uint32_t rct = bc.rct_raw(); // apply int7-like selections bool sel7 = 1; @@ -555,196 +684,302 @@ struct EventSelectionTask { sel1 = sel1 && bc.selection_bit(kNoTPCHVdip); // INT1 (SPDFO>0 | V0A | V0C) minimum bias trigger logic used in pp2010 and pp2011 - bool isINT1period = bc.runNumber() <= 136377 || (bc.runNumber() >= 144871 && bc.runNumber() <= 159582); + bool isINT1period = bc.runNumber() <= 136377 || (bc.runNumber() >= 144871 && bc.runNumber() <= 159582); // o2-linter: disable=magic-number (magic run numbers) // 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, 0); + 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) { + int run3min = 500000; + if (run != lastRun && run >= run3min) { lastRun = run; + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run, strLPMProductionTag); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = confNumberOfOrbitsPerTF < 0 ? runInfo.orbitsPerTF * nBCsPerOrbit : confNumberOfOrbitsPerTF * nBCsPerOrbit; + // colliding bc pattern int64_t ts = bcs.iteratorAt(0).timestamp(); auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); bcPatternB = grplhcif->getBunchFilling().getBCPattern(); - // - 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 timestamp 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; - } + // 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 or FT0-OR fired bcs - // to be used for closest TVX (FT0-OR) searches + // 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 >= run3min && 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, -1); + 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 - - // for the occupancy study - std::vector vFoundGlobalBC(cols.size(), 0); // global BCs for collisions - std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per found bc for occupancy studies + 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 - // const double timeWinOccupancyExclusionRangeNS = confExclusionIntervalForOccupancyCalculation * 1e3; // ns - const double bcNS = o2::constants::lhc::LHCBunchSpacingNS; - - // loop to find nearest bc with FT0 entry -> foundBC index - for (auto& col : cols) { + 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 nITS567cls = 0; - int nITSTPCtracks = 0; - int nTOFtracks = 0; - int nTRDtracks = 0; - double timeFromTOFtracks = 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(); - // calculate average time using TOF 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) // o2-linter: disable=magic-number (indeed counting layers 5 6 7) + 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()) { + 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++; + } } - - if (track.itsNCls() >= 5) - nITS567cls++; } - LOGP(debug, "nContrib={} nITSTPCtracks={} nTOFtracks={} nTRDtracks={}", col.numContrib(), nITSTPCtracks, nTOFtracks, nTRDtracks); - - 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 + 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]; + } } - int64_t minBC = meanBC - deltaBC; - int64_t maxBC = meanBC + deltaBC; + // 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; - 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); - } - } - int32_t foundBC = bc.globalIndex(); + // 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]++; - vTracksITS567perColl[colIndex] = nITS567cls; - vFoundGlobalBC[colIndex] = bc.globalBC(); - - // 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 > -timeWinOccupancyCalcMinNS) && ((nBCsPerTF - 4000 - bcInTF) * bcNS > timeWinOccupancyCalcMaxNS) ? true : false; + 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]]++; } - // save indices of collisions in time range for occupancy calculation + // 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 (auto& col : cols) { + 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; } - - 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; + // 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) + if (thisTFid != tfId) break; float dt = (thisBC - foundGlobalBC) * bcNS; // ns - // check if we are within the chosen time range if (dt < timeWinOccupancyCalcMinNS) break; @@ -753,11 +988,11 @@ struct EventSelectionTask { minColIndex--; } // find all collisions in time window after the current one - int32_t maxColIndex = colIndex + 1; + maxColIndex = colIndex + 1; while (maxColIndex < cols.size()) { int64_t thisBC = vFoundGlobalBC[maxColIndex]; int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; - if (thisTFid != TFid) + if (thisTFid != tfId) break; float dt = (thisBC - foundGlobalBC) * bcNS; // ns if (dt > timeWinOccupancyCalcMaxNS) @@ -770,86 +1005,114 @@ struct EventSelectionTask { vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); } - // perform the occupancy calculation in the pre-defined time window - std::vector vNumTracksITS567inFullTimeWin(cols.size(), 0); // counter of tracks in full time window for occupancy studies - std::vector vNoOccupAggressiveCuts(cols.size(), 0); // no occupancy according to the agressive cuts - std::vector vNoOccupStrictCuts(cols.size(), 0); // no occupancy according to the strict cuts - std::vector vNoOccupMediumCuts(cols.size(), 0); // no occupancy according to the medium cuts - std::vector vNoOccupRelaxedCuts(cols.size(), 0); // no occupancy according to the relaxed cuts - std::vector vNoOccupGentleCuts(cols.size(), 0); // no occupancy according to the gentle cuts - std::vector vNoCollInTimeRangeStandard(cols.size(), 0); // no collisions in a specified time range - std::vector vNoCollInTimeRangeNarrow(cols.size(), 0); // no collisions in a specified time range - - // time ranges for occupancy calculation - const int nTimeIntervals = 6; - const float coeffOccupInTimeBins[] = {0.2, 0.4, 0.6, 1.}; - - for (auto& col : cols) { + // 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]) { - vNumTracksITS567inFullTimeWin[colIndex] = -1; // occupancy in undefined (too close to 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; - int nITS567tracksInTimeBins[nTimeIntervals] = {}; - int nITS567tracksForVetoStandard = 0; // to veto events with nearby collisions - int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrower range) - for (int iCol = 0; iCol < vAssocToThisCol.size(); iCol++) { + 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]; - if (thisColIndex == colIndex) // skip the same collision - continue; float dt = vCollsTimeDeltaWrtGivenColl[iCol] / 1e3; // ns -> us - - if (!confUseWeightsForOccupancyVariable) { - nITS567tracksInFullTimeWindow += vTracksITS567perColl[thisColIndex]; - } else { + float wOccup = 1.; + if (confUseWeightsForOccupancyVariable) { // weighted occupancy - float 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 = 0; + if (dt >= -40 && dt < -5) // collisions in the past // o2-linter: disable=magic-number (to be checked by Igor) + wOccup = 1. / 1225 * (dt + 40) * (dt + 40); // o2-linter: disable=magic-number (to be checked by Igor) + else if (dt >= -5 && dt < 15) // collisions near a given one // o2-linter: disable=magic-number (to be checked by Igor) wOccup = 1; - else if (dt >= 15 && dt < 100) // collisions from the future - wOccup = -1. / 85 * dt + 20. / 17; - if (wOccup > 0) - nITS567tracksInFullTimeWindow += wOccup * vTracksITS567perColl[thisColIndex]; + // 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 // o2-linter: disable=magic-number (to be checked by Igor) + wOccup = -0.4 / 25 * dt + 1.24; // o2-linter: disable=magic-number (to be checked by Igor) + else if (dt >= 40 && dt < 100) // collisions from the distant future // o2-linter: disable=magic-number (to be checked by Igor) + wOccup = -0.4 / 60 * dt + 0.6 + 0.8 / 3; // o2-linter: disable=magic-number (to be checked by Igor) } - - for (int iTime = 0; iTime < nTimeIntervals; iTime++) { - if (confTimeBinsForOccupancyCalculation->at(iTime) < dt && dt <= confTimeBinsForOccupancyCalculation->at(iTime + 1)) - nITS567tracksInTimeBins[iTime] += vTracksITS567perColl[thisColIndex]; - if (fabs(dt) < confTimeRangeVetoOnCollStandard) - nITS567tracksForVetoStandard += vTracksITS567perColl[thisColIndex]; - if (fabs(dt) < confTimeRangeVetoOnCollNarrow) - nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex]; + 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 // o2-linter: disable=magic-number (to be checked by Igor) + nCollsWithFT0CAboveVetoStandard++; + } else if (dt > -4.0 && dt <= -2.0) { // us, strict veto to suppress fake ITS-TPC matches more // o2-linter: disable=magic-number (to be checked by Igor) + 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 // o2-linter: disable=magic-number (to be checked by Igor) + // counting number of other collisions with multiplicity above threshold + if (vAmpFT0CperColl[thisColIndex] > confFT0CamplCutVetoOnCollInTimeRange) + nCollsWithFT0CAboveVetoStandard++; } } - vNumTracksITS567inFullTimeWin[colIndex] = nITS567tracksInFullTimeWindow; // occupancy (without a current collision) - - // decisions based on occupancies in time bins - bool decisions[4]; - for (int iCut = 0; iCut < 4; iCut++) { - decisions[iCut] = true; - for (int iTime = 0; iTime < nTimeIntervals; iTime++) { - if (nITS567tracksInTimeBins[iTime] >= coeffOccupInTimeBins[iCut] * confReferenceOccupanciesInTimeBins->at(iTime)) { - decisions[iCut] = false; - break; - } - } - } - vNoOccupStrictCuts[colIndex] = decisions[0]; - vNoOccupMediumCuts[colIndex] = decisions[1]; - vNoOccupRelaxedCuts[colIndex] = decisions[2]; - vNoOccupGentleCuts[colIndex] = decisions[3]; - vNoOccupAggressiveCuts[colIndex] = ((nITS567tracksInTimeBins[0] < 300) && (nITS567tracksInTimeBins[1] == 0) && (nITS567tracksInTimeBins[2] == 0) && (nITS567tracksInTimeBins[3] == 0) && (nITS567tracksInTimeBins[4] < 200) && (nITS567tracksInTimeBins[5] < 400)); - vNoCollInTimeRangeStandard[colIndex] = (nITS567tracksForVetoStandard == 0); + 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 (auto& col : cols) { + for (const auto& col : cols) { int32_t colIndex = col.globalIndex(); int32_t foundBC = vFoundBCindex[colIndex]; auto bc = bcs.iteratorAt(foundBC); @@ -859,7 +1122,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(); @@ -872,14 +1135,18 @@ struct EventSelectionTask { selection |= vIsVertexTRDmatched[colIndex] ? BIT(kIsVertexTRDmatched) : 0; selection |= isGoodZvtxFT0vsPV ? BIT(kIsGoodZvtxFT0vsPV) : 0; - // selection bits based on occupancy pattern - selection |= vNoOccupAggressiveCuts[colIndex] ? BIT(kNoHighOccupancyAgressive) : 0; - selection |= vNoOccupStrictCuts[colIndex] && vNoCollInTimeRangeStandard[colIndex] ? BIT(kNoHighOccupancyStrict) : 0; - selection |= vNoOccupMediumCuts[colIndex] && vNoCollInTimeRangeStandard[colIndex] ? BIT(kNoHighOccupancyMedium) : 0; - selection |= vNoOccupRelaxedCuts[colIndex] && vNoCollInTimeRangeStandard[colIndex] ? BIT(kNoHighOccupancyRelaxed) : 0; - selection |= vNoOccupGentleCuts[colIndex] && vNoCollInTimeRangeNarrow[colIndex] ? BIT(kNoHighOccupancyGentle) : 0; - selection |= vNoCollInTimeRangeStandard[colIndex] ? BIT(kNoCollInTimeRangeStandard) : 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; @@ -898,16 +1165,331 @@ struct EventSelectionTask { histos.get(HIST("hColCounterAcc"))->Fill(Form("%d", bc.runNumber()), 1); } - int nTracksITS567inFullTimeWin = vNumTracksITS567inFullTimeWin[colIndex]; - // histos.get(HIST("hOccupancy"))->Fill(nTracksITS567inFullTimeWin); - - evsel(alias, selection, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, nTracksITS567inFullTimeWin); + evsel(alias, selection, rct, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, + vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); } } PROCESS_SWITCH(EventSelectionTask, processRun3, "Process Run3 event selection", false); }; +struct LumiTask { + Service ccdb; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + int lastRun = -1; // last run number (needed to access ccdb only if run!=lastRun) + float csTVX = -1; // dummy -1 for the visible TVX cross section (in ub) used in lumi accounting + float csTCE = -1; // dummy -1 for the visible TCE cross section (in ub) used in lumi accounting + float csZEM = -1; // dummy -1 for the visible ZEM cross section (in ub) used in lumi accounting + float csZNC = -1; // dummy -1 for the visible ZNC cross section (in ub) used in lumi accounting + + std::vector mOrbits; + std::vector mPileupCorrectionTVX; + std::vector mPileupCorrectionTCE; + std::vector mPileupCorrectionZEM; + std::vector mPileupCorrectionZNC; + + int64_t minOrbitInRange = std::numeric_limits::max(); + int64_t maxOrbitInRange = 0; + uint32_t currentOrbitIndex = 0; + std::bitset bcPatternB; // bc pattern of colliding bunches + std::vector mRCTFlagsCheckers; + + void init(InitContext&) + { + histos.add("hCounterTVX", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterTCE", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterZEM", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterZNC", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterTVXZDC", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterTVXafterBCcuts", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterTCEafterBCcuts", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterZEMafterBCcuts", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterZNCafterBCcuts", "", kTH1D, {{1, 0., 1.}}); + histos.add("hCounterTVXZDCafterBCcuts", "", 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.}}); + histos.add("hLumiTVXafterBCcuts", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); + histos.add("hLumiTCEafterBCcuts", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); + histos.add("hLumiZEMafterBCcuts", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); + histos.add("hLumiZNCafterBCcuts", ";;Luminosity, 1/#mub", kTH1D, {{1, 0., 1.}}); + + const int nLists = 6; + TString rctListNames[] = {"CBT", "CBT_hadronPID", "CBT_electronPID", "CBT_calo", "CBT_muon", "CBT_muon_glo"}; + histos.add("hLumiTVXafterBCcutsRCT", ";;Luminosity, 1/#mub", kTH2D, {{1, 0., 1.}, {4 * nLists, -0.5, 4. * nLists - 0.5}}); + histos.add("hLumiTCEafterBCcutsRCT", ";;Luminosity, 1/#mub", kTH2D, {{1, 0., 1.}, {4 * nLists, -0.5, 4. * nLists - 0.5}}); + histos.add("hLumiZEMafterBCcutsRCT", ";;Luminosity, 1/#mub", kTH2D, {{1, 0., 1.}, {4 * nLists, -0.5, 4. * nLists - 0.5}}); + histos.add("hLumiZNCafterBCcutsRCT", ";;Luminosity, 1/#mub", kTH2D, {{1, 0., 1.}, {4 * nLists, -0.5, 4. * nLists - 0.5}}); + + for (int i = 0; i < nLists; i++) { + const auto& rctListName = rctListNames[i]; + mRCTFlagsCheckers.emplace_back(rctListName.Data(), false, false); // disable zdc check, disable lim. acc. check + mRCTFlagsCheckers.emplace_back(rctListName.Data(), false, true); // disable zdc check, enable lim. acc. check + mRCTFlagsCheckers.emplace_back(rctListName.Data(), true, false); // enable zdc check, disable lim. acc. check + mRCTFlagsCheckers.emplace_back(rctListName.Data(), true, true); // enable zdc check, enable lim. acc. check + histos.get(HIST("hLumiTVXafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 1, rctListName.Data()); + histos.get(HIST("hLumiTCEafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 1, rctListName.Data()); + histos.get(HIST("hLumiZEMafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 1, rctListName.Data()); + histos.get(HIST("hLumiZNCafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 1, rctListName.Data()); + histos.get(HIST("hLumiTVXafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 2, (rctListName + "_fullacc").Data()); + histos.get(HIST("hLumiTCEafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 2, (rctListName + "_fullacc").Data()); + histos.get(HIST("hLumiZEMafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 2, (rctListName + "_fullacc").Data()); + histos.get(HIST("hLumiZNCafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 2, (rctListName + "_fullacc").Data()); + histos.get(HIST("hLumiTVXafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 3, (rctListName + "_zdc").Data()); + histos.get(HIST("hLumiTCEafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 3, (rctListName + "_zdc").Data()); + histos.get(HIST("hLumiZEMafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 3, (rctListName + "_zdc").Data()); + histos.get(HIST("hLumiZNCafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 3, (rctListName + "_zdc").Data()); + histos.get(HIST("hLumiTVXafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 4, (rctListName + "_zdc" + "_fullacc").Data()); + histos.get(HIST("hLumiTCEafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 4, (rctListName + "_zdc" + "_fullacc").Data()); + histos.get(HIST("hLumiZEMafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 4, (rctListName + "_zdc" + "_fullacc").Data()); + histos.get(HIST("hLumiZNCafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 4, (rctListName + "_zdc" + "_fullacc").Data()); + } + } + + void processRun2(aod::BCs const&) + { + LOGP(debug, "Dummy process function for Run 2"); + } + + PROCESS_SWITCH(LumiTask, processRun2, "Process Run2 lumi task", true); + + void processRun3(BCsWithBcSelsRun3 const& bcs, aod::FT0s const&) + { + if (bcs.size() == 0) + return; + int run = bcs.iteratorAt(0).runNumber(); + if (run < 500000) // o2-linter: disable=magic-number (skip for unanchored MCs) + return; + if (run != lastRun && run >= 520259) { // o2-linter: disable=magic-number (scalers available for runs above 520120) + lastRun = run; + int64_t ts = bcs.iteratorAt(0).timestamp(); + + // getting GRP LHCIF object to extract colliding system, energy and colliding bc pattern + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); + int beamZ1 = grplhcif->getBeamZ(constants::lhc::BeamA); + int beamZ2 = grplhcif->getBeamZ(constants::lhc::BeamC); + float sqrts = grplhcif->getSqrtS(); + int nCollidingBCs = grplhcif->getBunchFilling().getNBunches(); + bcPatternB = grplhcif->getBunchFilling().getBCPattern(); + + // visible cross sections in ub. Using dummy -1 if lumi estimator is not reliable for this colliding system + csTVX = -1; + csTCE = -1; + csZEM = -1; + csZNC = -1; + // Temporary workaround to get visible cross section. TODO: store run-by-run visible cross sections in CCDB + if (beamZ1 == 1 && beamZ2 == 1) { + if (std::fabs(sqrts - 900.) < 100.) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTVX = 0.0357e6; // ub + } else if (std::fabs(sqrts - 5360.) < 100.) { // pp-ref // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTVX = 0.0503e6; // ub + } else if (std::fabs(sqrts - 13600.) < 300.) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTVX = 0.0594e6; // ub + } else { + LOGP(warn, "Cross section for pp @ {} GeV is not defined", sqrts); + } + } else if (beamZ1 == 82 && beamZ2 == 82) { // o2-linter: disable=magic-number (PbPb colliding system) + // see AN: https://alice-notes.web.cern.ch/node/1515 + if (std::fabs(sqrts - 5360) < 20) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csZNC = 214.5e6; // ub + csZEM = 415.2e6; // ub + csTCE = 10.36e6; // ub + if (run > 543437 && run < 543514) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTCE = 8.3e6; // ub + } else if (run >= 543514 && run < 545367) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTCE = 4.10e6; // ub + } else if (run >= 559544) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTCE = 3.86e6; // ub + } + } else { + LOGP(warn, "Cross section for PbPb @ {} GeV is not defined", sqrts); + } + } else { + LOGP(warn, "Cross section for z={} + z={} @ {} GeV is not defined", beamZ1, beamZ2, sqrts); + } + // getting CTP config to extract lumi class indices (used for rate fetching and pileup correction) + std::map metadata; + metadata["runNumber"] = std::to_string(run); + auto config = ccdb->getSpecific("CTP/Config/Config", ts, metadata); + auto classes = config->getCTPClasses(); + TString lumiClassNameZNC = "C1ZNC-B-NOPF-CRU"; + TString lumiClassNameTCE = "CMTVXTCE-B-NOPF-CRU"; + TString lumiClassNameTVX1 = "MINBIAS_TVX"; // run >= 534467 + TString lumiClassNameTVX2 = "MINBIAS_TVX_NOMASK"; // run >= 534468 + TString lumiClassNameTVX3 = "CMTVX-NONE-NOPF-CRU"; // run >= 534996 + TString lumiClassNameTVX4 = "CMTVX-B-NOPF-CRU"; // run >= 543437 + + // find class indices + int classIdZNC = -1; + int classIdTCE = -1; + int classIdTVX = -1; + for (unsigned int i = 0; i < classes.size(); i++) { + TString clname = classes[i].name; + clname.ToUpper(); + // using position (i) in the vector of classes instead of classes[i].getIndex() + // due to bug or inconsistencies in scaler record and class indices + if (clname == lumiClassNameZNC) + classIdZNC = i; + if (clname == lumiClassNameTCE) + classIdTCE = i; + if (clname == lumiClassNameTVX4 || clname == lumiClassNameTVX3 || clname == lumiClassNameTVX2 || clname == lumiClassNameTVX1) + classIdTVX = i; + } + + // extract trigger counts from CTP scalers + auto scalers = ccdb->getSpecific("CTP/Calib/Scalers", ts, metadata); + scalers->convertRawToO2(); + std::vector mCounterTVX; + std::vector mCounterTCE; + std::vector mCounterZNC; + std::vector mCounterZEM; + mOrbits.clear(); + for (const auto& record : scalers->getScalerRecordO2()) { + mOrbits.push_back(record.intRecord.orbit); + mCounterTVX.push_back(classIdTVX >= 0 ? record.scalers[classIdTVX].lmBefore : 0); + mCounterTCE.push_back(classIdTCE >= 0 ? record.scalers[classIdTCE].lmBefore : 0); + if (run >= 543437 && run < 544448 && record.scalersInps.size() >= 26) { // o2-linter: disable=magic-number (ZNC class not defined for this run range) + mCounterZNC.push_back(record.scalersInps[25]); // see ZNC=1ZNC input index in https://indico.cern.ch/event/1153630/contributions/4844362/ + } else { + mCounterZNC.push_back(classIdZNC >= 0 ? record.scalers[classIdZNC].l1Before : 0); + } + // ZEM class not defined, using inputs instead + uint32_t indexZEM = 24; // see ZEM=1ZED input index in https://indico.cern.ch/event/1153630/contributions/4844362/ + mCounterZEM.push_back(record.scalersInps.size() >= indexZEM + 1 ? record.scalersInps[indexZEM] : 0); + } + + // calculate pileup corrections + mPileupCorrectionTVX.clear(); + mPileupCorrectionTCE.clear(); + mPileupCorrectionZEM.clear(); + mPileupCorrectionZNC.clear(); + for (uint32_t i = 0; i < mOrbits.size() - 1; i++) { + int64_t nOrbits = mOrbits[i + 1] - mOrbits[i]; + if (nOrbits <= 0 || nCollidingBCs == 0) + continue; + double perBcRateTVX = static_cast(mCounterTVX[i + 1] - mCounterTVX[i]) / nOrbits / nCollidingBCs; + double perBcRateTCE = static_cast(mCounterTCE[i + 1] - mCounterTCE[i]) / nOrbits / nCollidingBCs; + double perBcRateZNC = static_cast(mCounterZNC[i + 1] - mCounterZNC[i]) / nOrbits / nCollidingBCs; + double perBcRateZEM = static_cast(mCounterZEM[i + 1] - mCounterZEM[i]) / nOrbits / nCollidingBCs; + double muTVX = (perBcRateTVX < 1 && perBcRateTVX > 1e-10) ? -std::log(1 - perBcRateTVX) : 0; + double muTCE = (perBcRateTCE < 1 && perBcRateTCE > 1e-10) ? -std::log(1 - perBcRateTCE) : 0; + double muZNC = (perBcRateZNC < 1 && perBcRateZNC > 1e-10) ? -std::log(1 - perBcRateZNC) : 0; + double muZEM = (perBcRateZEM < 1 && perBcRateZEM > 1e-10) ? -std::log(1 - perBcRateZEM) : 0; + LOGP(debug, "orbit={} muTVX={} muTCE={} muZNC={} muZEM={}", mOrbits[i], muTVX, muTCE, muZNC, muZEM); + mPileupCorrectionTVX.push_back(muTVX > 1e-10 ? muTVX / (1 - std::exp(-muTVX)) : 1); + mPileupCorrectionTCE.push_back(muTCE > 1e-10 ? muTCE / (1 - std::exp(-muTCE)) : 1); + mPileupCorrectionZNC.push_back(muZNC > 1e-10 ? muZNC / (1 - std::exp(-muZNC)) : 1); + mPileupCorrectionZEM.push_back(muZEM > 1e-10 ? muZEM / (1 - std::exp(-muZEM)) : 1); + } + // filling last orbit range using previous orbit range + mPileupCorrectionTVX.push_back(mPileupCorrectionTVX.back()); + mPileupCorrectionTCE.push_back(mPileupCorrectionTCE.back()); + mPileupCorrectionZNC.push_back(mPileupCorrectionZNC.back()); + mPileupCorrectionZEM.push_back(mPileupCorrectionZEM.back()); + } // access ccdb once per run + + const char* srun = Form("%d", run); + + for (const auto& bc : bcs) { + auto& selection = bc.selection_raw(); + if (bcPatternB[bc.globalBC() % nBCsPerOrbit] == 0) // skip non-colliding bcs + continue; + + bool noBorder = TESTBIT(selection, kNoTimeFrameBorder) && TESTBIT(selection, kNoITSROFrameBorder); + bool isTriggerTVX = TESTBIT(selection, kIsTriggerTVX); + bool isTriggerTCE = bc.has_ft0() ? (TESTBIT(selection, kIsTriggerTVX) && TESTBIT(bc.ft0().triggerMask(), o2::ft0::Triggers::bitCen)) : 0; + bool isTriggerZNA = TESTBIT(selection, kIsBBZNA); + bool isTriggerZNC = TESTBIT(selection, kIsBBZNC); + bool isTriggerZEM = isTriggerZNA || isTriggerZNC; + + // determine pileup correction + int64_t orbit = bc.globalBC() / nBCsPerOrbit; + if ((orbit < minOrbitInRange || orbit > maxOrbitInRange) && mOrbits.size() > 1) { + auto it = std::lower_bound(mOrbits.begin(), mOrbits.end(), orbit); + uint32_t nextOrbitIndex = std::distance(mOrbits.begin(), it); + if (nextOrbitIndex == 0) // if orbit is below stored scaler orbits + nextOrbitIndex = 1; + else if (nextOrbitIndex == mOrbits.size()) // if orbit is above stored scaler orbits + nextOrbitIndex = mOrbits.size() - 1; + currentOrbitIndex = nextOrbitIndex - 1; + minOrbitInRange = mOrbits[currentOrbitIndex]; + maxOrbitInRange = mOrbits[nextOrbitIndex]; + } + double pileupCorrectionTVX = currentOrbitIndex < mPileupCorrectionTVX.size() ? mPileupCorrectionTVX[currentOrbitIndex] : 1.; + double pileupCorrectionTCE = currentOrbitIndex < mPileupCorrectionTCE.size() ? mPileupCorrectionTCE[currentOrbitIndex] : 1.; + double pileupCorrectionZNC = currentOrbitIndex < mPileupCorrectionZNC.size() ? mPileupCorrectionZNC[currentOrbitIndex] : 1.; + double pileupCorrectionZEM = currentOrbitIndex < mPileupCorrectionZEM.size() ? mPileupCorrectionZEM[currentOrbitIndex] : 1.; + + double lumiTVX = 1. / csTVX * pileupCorrectionTVX; + double lumiTCE = 1. / csTCE * pileupCorrectionTCE; + double lumiZNC = 1. / csZNC * pileupCorrectionZNC; + double lumiZEM = 1. / csZEM * pileupCorrectionZEM; + + if (isTriggerTVX) { + histos.get(HIST("hCounterTVX"))->Fill(srun, 1); + histos.get(HIST("hLumiTVX"))->Fill(srun, lumiTVX); + if (isTriggerZNA && isTriggerZNC) { + histos.get(HIST("hCounterTVXZDC"))->Fill(srun, 1); + } + if (noBorder) { + histos.get(HIST("hCounterTVXafterBCcuts"))->Fill(srun, 1); + histos.get(HIST("hLumiTVXafterBCcuts"))->Fill(srun, lumiTVX); + if (isTriggerZNA && isTriggerZNC) { + histos.get(HIST("hCounterTVXZDCafterBCcuts"))->Fill(srun, 1); + } + for (size_t i = 0; i < mRCTFlagsCheckers.size(); i++) { + if (mRCTFlagsCheckers[i](bc)) + histos.get(HIST("hLumiTVXafterBCcutsRCT"))->Fill(srun, i, lumiTVX); + } + } + } + + if (isTriggerTCE) { + histos.get(HIST("hCounterTCE"))->Fill(srun, 1); + histos.get(HIST("hLumiTCE"))->Fill(srun, lumiTCE); + if (noBorder) { + histos.get(HIST("hCounterTCEafterBCcuts"))->Fill(srun, 1); + histos.get(HIST("hLumiTCEafterBCcuts"))->Fill(srun, lumiTCE); + for (size_t i = 0; i < mRCTFlagsCheckers.size(); i++) { + if (mRCTFlagsCheckers[i](bc)) + histos.get(HIST("hLumiTCEafterBCcutsRCT"))->Fill(srun, i, lumiTCE); + } + } + } + + if (isTriggerZEM) { + histos.get(HIST("hCounterZEM"))->Fill(srun, 1); + histos.get(HIST("hLumiZEM"))->Fill(srun, lumiZEM); + if (noBorder) { + histos.get(HIST("hCounterZEMafterBCcuts"))->Fill(srun, 1); + histos.get(HIST("hLumiZEMafterBCcuts"))->Fill(srun, lumiZEM); + for (size_t i = 0; i < mRCTFlagsCheckers.size(); i++) { + if (mRCTFlagsCheckers[i](bc)) + histos.get(HIST("hLumiZEMafterBCcutsRCT"))->Fill(srun, i, lumiZEM); + } + } + } + + if (isTriggerZNC) { + histos.get(HIST("hCounterZNC"))->Fill(srun, 1); + histos.get(HIST("hLumiZNC"))->Fill(srun, lumiZNC); + if (noBorder) { + histos.get(HIST("hCounterZNCafterBCcuts"))->Fill(srun, 1); + histos.get(HIST("hLumiZNCafterBCcuts"))->Fill(srun, lumiZNC); + for (size_t i = 0; i < mRCTFlagsCheckers.size(); i++) { + if (mRCTFlagsCheckers[i](bc)) + histos.get(HIST("hLumiZNCafterBCcutsRCT"))->Fill(srun, i, lumiZNC); + } + } + } + + } // bcs + } // process + PROCESS_SWITCH(LumiTask, processRun3, "Process Run3 lumi task", false); +}; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { // Parse the metadata @@ -915,5 +1497,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) return WorkflowSpec{ adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/Common/TableProducer/eventSelectionService.cxx b/Common/TableProducer/eventSelectionService.cxx new file mode 100644 index 00000000000..55068b32fe7 --- /dev/null +++ b/Common/TableProducer/eventSelectionService.cxx @@ -0,0 +1,209 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file eventSelectionTester.cxx +/// \brief unified, self-configuring event selection task +/// \author ALICE + +//=============================================================== +// +// Unified, self-configuring event selection task +// +//=============================================================== + +#include "Common/Core/MetadataHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Tools/EventSelectionModule.h" +#include "Common/Tools/timestampModule.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +o2::common::core::MetadataHelper metadataInfo; // Metadata helper + +using BCsWithRun2InfosAndMatches = soa::Join; +using BCsWithRun3Matchings = soa::Join; +using FullTracks = soa::Join; +using FullTracksIU = soa::Join; + +struct eventselectionRun2 { + o2::common::timestamp::timestampConfigurables timestampConfigurables; + o2::common::timestamp::TimestampModule timestampMod; + + o2::common::eventselection::bcselConfigurables bcselOpts; + o2::common::eventselection::BcSelectionModule bcselmodule; + + o2::common::eventselection::evselConfigurables evselOpts; + o2::common::eventselection::EventSelectionModule evselmodule; + + Produces timestampTable; /// Table with SOR timestamps produced by the task + Produces bcsel; + Produces evsel; + + // for slicing + SliceCache cache; + + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // buffering intermediate results for passing + std::vector timestamps; + std::vector bcselsbuffer; + + // auxiliary + Partition tracklets = (aod::track::trackType == static_cast(o2::aod::track::TrackTypeEnum::Run2Tracklet)); + Preslice perCollision = aod::track::collisionId; + + void init(o2::framework::InitContext& context) + { + // CCDB boilerplate init + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setURL(ccdburl.value); + + // task-specific + timestampMod.init(timestampConfigurables, metadataInfo); + bcselmodule.init(context, bcselOpts, histos, metadataInfo); + evselmodule.init(context, evselOpts, histos, metadataInfo); + } + + void process(BCsWithRun2InfosAndMatches const& bcs, + aod::Collisions const& collisions, + aod::Zdcs const&, + aod::FV0As const&, + aod::FV0Cs const&, + aod::FT0s const&, + aod::FDDs const&, + FullTracks const&) + { + timestampMod.process(bcs, ccdb, timestamps, timestampTable); + bcselmodule.processRun2(ccdb, bcs, timestamps, bcselsbuffer, bcsel); + evselmodule.processRun2(ccdb, histos, collisions, tracklets, cache, timestamps, bcselsbuffer, evsel); + } +}; + +struct eventselectionRun3 { + o2::common::timestamp::timestampConfigurables timestampConfigurables; + o2::common::timestamp::TimestampModule timestampMod; + + o2::common::eventselection::bcselConfigurables bcselOpts; + o2::common::eventselection::BcSelectionModule bcselmodule; + + o2::common::eventselection::evselConfigurables evselOpts; + o2::common::eventselection::EventSelectionModule evselmodule; + + o2::common::eventselection::lumiConfigurables lumiOpts; + o2::common::eventselection::LumiModule lumimodule; + + Produces timestampTable; /// Table with SOR timestamps produced by the task + Produces bcsel; + Produces evsel; + + // for slicing + SliceCache cache; + + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // the best: have readable cursors + // this: a stopgap solution to avoid spawning yet another device + std::vector timestamps; + std::vector bcselsbuffer; + + // auxiliary + Partition pvTracks = ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + Preslice perCollisionIU = aod::track::collisionId; + + void init(o2::framework::InitContext& context) + { + // CCDB boilerplate init + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setURL(ccdburl.value); + + // task-specific + timestampMod.init(timestampConfigurables, metadataInfo); + bcselmodule.init(context, bcselOpts, histos, metadataInfo); + evselmodule.init(context, evselOpts, histos, metadataInfo); + lumimodule.init(context, lumiOpts, histos); + } + + void process(aod::Collisions const& collisions, + BCsWithRun3Matchings const& bcs, + aod::Zdcs const&, + aod::FV0As const&, + aod::FT0s const& ft0s, // to resolve iterator + aod::FDDs const&, + FullTracksIU const&) + { + timestampMod.process(bcs, ccdb, timestamps, timestampTable); + bcselmodule.processRun3(ccdb, histos, bcs, timestamps, bcselsbuffer, bcsel); + evselmodule.processRun3(ccdb, histos, bcs, collisions, pvTracks, ft0s, cache, timestamps, bcselsbuffer, evsel); + lumimodule.process(ccdb, histos, bcs, timestamps, bcselsbuffer); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata for later too + metadataInfo.initMetadata(cfgc); + + bool isRun3 = true, hasRunInfo = false; + if (cfgc.options().hasOption("aod-metadata-Run") == true) { + hasRunInfo = true; + if (cfgc.options().get("aod-metadata-Run") == "2") { + isRun3 = false; + } + } + + LOGF(info, "Event selection autoconfiguring from metadata. Availability of info for Run 2/3 is %i", hasRunInfo); + if (!hasRunInfo) { + LOGF(info, "Metadata info missing or incomplete. Make sure --aod-file is provided at the end of the last workflow and that the AO2D has metadata stored."); + LOGF(info, "Initializing with Run 3 data as default. Please note you will not be able to change settings manually."); + LOGF(info, "You should instead make sure the metadata is read in correctly."); + return WorkflowSpec{adaptAnalysisTask(cfgc)}; + } else { + LOGF(info, "Metadata successfully read in. Is this Run 3? %i - will self-configure.", isRun3); + if (isRun3) { + return WorkflowSpec{adaptAnalysisTask(cfgc)}; + } else { + LOGF(info, "******************************************************************"); + LOGF(info, " Event selection service self-configuring for Run 2."); + LOGF(info, " WARNING: THIS HAS NOT BEEN VALIDATED YET, USE WITH CAUTION"); + LOGF(info, " If this fails, please use event-selection-service-run2 instead."); + LOGF(info, "******************************************************************"); + return WorkflowSpec{adaptAnalysisTask(cfgc)}; + } + } + throw std::runtime_error("Unsupported run type / problem when configuring event selection!"); +} diff --git a/Common/TableProducer/eventSelectionServiceRun2.cxx b/Common/TableProducer/eventSelectionServiceRun2.cxx new file mode 100644 index 00000000000..554ec1ff480 --- /dev/null +++ b/Common/TableProducer/eventSelectionServiceRun2.cxx @@ -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. + +/// \file eventSelectionTester.cxx +/// \brief unified, self-configuring event selection task +/// \author ALICE + +//=============================================================== +// +// Unified, self-configuring event selection task +// +//=============================================================== + +#include "Common/Core/MetadataHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/Tools/EventSelectionModule.h" +#include "Common/Tools/timestampModule.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +o2::common::core::MetadataHelper metadataInfo; // Metadata helper + +using BCsWithRun2InfosAndMatches = soa::Join; +using BCsWithRun3Matchings = soa::Join; +using FullTracks = soa::Join; +using FullTracksIU = soa::Join; + +struct eventselectionRun2 { + o2::common::timestamp::timestampConfigurables timestampConfigurables; + o2::common::timestamp::TimestampModule timestampMod; + + o2::common::eventselection::bcselConfigurables bcselOpts; + o2::common::eventselection::BcSelectionModule bcselmodule; + + o2::common::eventselection::evselConfigurables evselOpts; + o2::common::eventselection::EventSelectionModule evselmodule; + + Produces timestampTable; /// Table with SOR timestamps produced by the task + Produces bcsel; + Produces evsel; + + // for slicing + SliceCache cache; + + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // buffering intermediate results for passing + std::vector timestamps; + std::vector bcselsbuffer; + + // auxiliary + Partition tracklets = (aod::track::trackType == static_cast(o2::aod::track::TrackTypeEnum::Run2Tracklet)); + Preslice perCollision = aod::track::collisionId; + + void init(o2::framework::InitContext& context) + { + // CCDB boilerplate init + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setURL(ccdburl.value); + + // task-specific + timestampMod.init(timestampConfigurables, metadataInfo); + bcselmodule.init(context, bcselOpts, histos, metadataInfo); + evselmodule.init(context, evselOpts, histos, metadataInfo); + } + + void process(BCsWithRun2InfosAndMatches const& bcs, + aod::Collisions const& collisions, + aod::Zdcs const&, + aod::FV0As const&, + aod::FV0Cs const&, + aod::FT0s const&, + aod::FDDs const&, + FullTracks const&) + { + timestampMod.process(bcs, ccdb, timestamps, timestampTable); + bcselmodule.processRun2(ccdb, bcs, timestamps, bcselsbuffer, bcsel); + evselmodule.processRun2(ccdb, histos, collisions, tracklets, cache, timestamps, bcselsbuffer, evsel); + } +}; + +struct eventselectionRun3 { + o2::common::timestamp::timestampConfigurables timestampConfigurables; + o2::common::timestamp::TimestampModule timestampMod; + + o2::common::eventselection::bcselConfigurables bcselOpts; + o2::common::eventselection::BcSelectionModule bcselmodule; + + o2::common::eventselection::evselConfigurables evselOpts; + o2::common::eventselection::EventSelectionModule evselmodule; + + o2::common::eventselection::lumiConfigurables lumiOpts; + o2::common::eventselection::LumiModule lumimodule; + + Produces timestampTable; /// Table with SOR timestamps produced by the task + Produces bcsel; + Produces evsel; + + // for slicing + SliceCache cache; + + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // the best: have readable cursors + // this: a stopgap solution to avoid spawning yet another device + std::vector timestamps; + std::vector bcselsbuffer; + + // auxiliary + Partition pvTracks = ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + Preslice perCollisionIU = aod::track::collisionId; + + void init(o2::framework::InitContext& context) + { + // CCDB boilerplate init + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setURL(ccdburl.value); + + // task-specific + timestampMod.init(timestampConfigurables, metadataInfo); + bcselmodule.init(context, bcselOpts, histos, metadataInfo); + evselmodule.init(context, evselOpts, histos, metadataInfo); + lumimodule.init(context, lumiOpts, histos); + } + + void process(aod::Collisions const& collisions, + BCsWithRun3Matchings const& bcs, + aod::Zdcs const&, + aod::FV0As const&, + aod::FT0s const& ft0s, // to resolve iterator + aod::FDDs const&, + FullTracksIU const&) + { + timestampMod.process(bcs, ccdb, timestamps, timestampTable); + bcselmodule.processRun3(ccdb, histos, bcs, timestamps, bcselsbuffer, bcsel); + evselmodule.processRun3(ccdb, histos, bcs, collisions, pvTracks, ft0s, cache, timestamps, bcselsbuffer, evsel); + lumimodule.process(ccdb, histos, bcs, timestamps, bcselsbuffer); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Parse the metadata for later too + metadataInfo.initMetadata(cfgc); + + LOGF(info, "Event selection with forced Run 2 mode engaging in unchecked mode."); + LOGF(info, "To be improved once metadata enabling in defineDataProcessing is worked out."); + + // force Run 2 mode + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/ft0CorrectedTable.cxx b/Common/TableProducer/ft0CorrectedTable.cxx index 49e6e8bea1c..d3396544e6c 100644 --- a/Common/TableProducer/ft0CorrectedTable.cxx +++ b/Common/TableProducer/ft0CorrectedTable.cxx @@ -9,39 +9,106 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include "Common/DataModel/FT0Corrected.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" +#include "Common/Core/CollisionTypeHelper.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisDataModel.h" -#include "CommonConstants/LHCConstants.h" -#include "CommonConstants/PhysicsConstants.h" -#include "DataFormatsFT0/Digit.h" +#include "Common/DataModel/FT0Corrected.h" + +#include +#include +#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::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; - void process(BCsWithMatchings const&, soa::Join const& collisions, aod::FT0s const&) + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(o2::framework::InitContext&) { - for (auto& collision : collisions) { - float vertexPV = collision.posZ(); - float vertex_corr = vertexPV / o2::constants::physics::LightSpeedCm2NS; - float t0A = 1e10; - float t0C = 1e10; + 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 processStandard(soa::Join const& collisions, + BCsWithMatchings const&, + aod::FT0s const&) + { + 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 +119,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/fwdtrackToCollisionAssociator.cxx b/Common/TableProducer/fwdtrackToCollisionAssociator.cxx index 0478b69b12d..862cee97872 100644 --- a/Common/TableProducer/fwdtrackToCollisionAssociator.cxx +++ b/Common/TableProducer/fwdtrackToCollisionAssociator.cxx @@ -16,11 +16,13 @@ #include "Common/Core/CollisionAssociation.h" #include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "CommonConstants/LHCConstants.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -64,6 +66,7 @@ struct FwdTrackToCollisionAssociation { collisionAssociator.setUsePvAssociation(false); collisionAssociator.setIncludeUnassigned(includeUnassigned); collisionAssociator.setFillTableOfCollIdsPerTrack(fillTableOfCollIdsPerTrack); + collisionAssociator.setBcWindow(bcWindowForOneSigma); } void processFwdAssocWithTime(Collisions const& collisions, diff --git a/Common/TableProducer/fwdtrackextension.cxx b/Common/TableProducer/fwdtrackextension.cxx index 4a78bf8de5f..c554b2c4fbf 100644 --- a/Common/TableProducer/fwdtrackextension.cxx +++ b/Common/TableProducer/fwdtrackextension.cxx @@ -13,19 +13,19 @@ // Task performing forward track DCA computation // -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Common/Core/TrackSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/Core/trackUtilities.h" -#include "ReconstructionDataFormats/DCA.h" -#include "DetectorsBase/Propagator.h" -#include "CommonUtils/NameConf.h" -#include "Math/SMatrix.h" -#include "ReconstructionDataFormats/TrackFwd.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/match-mft-ft0.cxx b/Common/TableProducer/match-mft-ft0.cxx new file mode 100644 index 00000000000..a6160cabe4b --- /dev/null +++ b/Common/TableProducer/match-mft-ft0.cxx @@ -0,0 +1,552 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 +/// \note https://github.com/AliceO2Group/AliceO2/blob/dev/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h + +#include "Common/DataModel/MatchMFTFT0.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //for propagate + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +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..2e801bc4040 --- /dev/null +++ b/Common/TableProducer/match-mft-mch-data-mc.cxx @@ -0,0 +1,862 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "Common/DataModel/MatchMFTFT0.h" +#include "Common/DataModel/MatchMFTMuonData.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +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..9541af4d5cc --- /dev/null +++ b/Common/TableProducer/match-mft-mch-data.cxx @@ -0,0 +1,862 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "Common/DataModel/MatchMFTFT0.h" +#include "Common/DataModel/MatchMFTMuonData.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +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 3ad7a143acd..b975e0d335e 100644 --- a/Common/TableProducer/mcCollsExtra.cxx +++ b/Common/TableProducer/mcCollsExtra.cxx @@ -12,38 +12,24 @@ // Quick and dirty task to correlate MC <-> data // -#include -#include -#include +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" -#include "Math/Vector4D.h" -#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 "Common/DataModel/McCollisionExtra.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 "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 +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -135,8 +121,8 @@ struct mcCollisionExtra { auto iter = std::find(sortedIndices.begin(), sortedIndices.end(), mcCollision.index()); if (iter != sortedIndices.end()) { auto index = std::distance(iter, sortedIndices.begin()); - for (size_t iMcColl = index + 1; iMcColl < index + 17; iMcColl++) { - if (iMcColl >= sortedIndices.size()) + 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 fba6c1464eb..9a5091d3eb9 100644 --- a/Common/TableProducer/mftmchMatchingML.cxx +++ b/Common/TableProducer/mftmchMatchingML.cxx @@ -1,4 +1,4 @@ -// Copyright 2020-2022 CERN and copyright holders of ALICE O2. +// Copyright 2020-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. // @@ -9,35 +9,42 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#if __has_include() -#include -#else -#include -#endif -#include -#include -#include #include "Common/DataModel/MftmchMatchingML.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/trackUtilities.h" -#include "Common/Core/TrackSelection.h" -#include "ReconstructionDataFormats/TrackFwd.h" -#include "Math/SMatrix.h" -#include "DetectorsBase/Propagator.h" -#include "MFTTracking/Tracker.h" -#include "MCHTracking/TrackParam.h" -#include "MCHTracking/TrackExtrap.h" -#include "GlobalTracking/MatchGlobalFwd.h" -#include "CCDB/CcdbApi.h" + #include "Tools/ML/model.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // FIXME: Replace M_PI + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -77,11 +84,7 @@ 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 @@ -158,12 +161,6 @@ 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()); @@ -177,7 +174,6 @@ struct mftmchMatchingML { 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; @@ -187,11 +183,6 @@ 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())); @@ -206,7 +197,6 @@ struct mftmchMatchingML { [&](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/multCentTable.cxx b/Common/TableProducer/multCentTable.cxx new file mode 100644 index 00000000000..a8bfa50ee9d --- /dev/null +++ b/Common/TableProducer/multCentTable.cxx @@ -0,0 +1,202 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file multCentTable.cxx +/// \brief unified, self-configuring mult/cent provider +/// \author ALICE + +//=============================================================== +// +// Unified, self-configuring multiplicity+centrality task +// still work in progress: use at your own discretion +// +//=============================================================== + +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" + +#include "Common/Core/MetadataHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Tools/Multiplicity/MultModule.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +o2::common::core::MetadataHelper metadataInfo; // Metadata helper + +struct MultCentTable { + o2::common::multiplicity::standardConfigurables opts; + o2::common::multiplicity::products products; + o2::common::multiplicity::MultModule module; + + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + Service pdg; + + // hold multiplicity values for layover to centrality calculation + std::vector mults; + + // slicers + Preslice> slicerTracksIU = o2::aod::track::collisionId; + Preslice> slicerTracksIUwithSelections = o2::aod::track::collisionId; + Preslice> slicerTrackRun2 = o2::aod::track::collisionId; + + void init(o2::framework::InitContext& initContext) + { + // CCDB boilerplate init + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setURL(ccdburl.value); + ccdb->setFatalWhenNull(false); // please never crash on your own, all exceptions captured (as they always should) + + // task-specific + module.init(metadataInfo, opts, initContext); + } + + void processRun2(soa::Join const& collisions, + soa::Join const& tracks, + soa::Join const& bcs, + aod::Zdcs const&, + aod::FV0As const&, + aod::FV0Cs const&, + aod::FT0s const&) + { + mults.clear(); + for (auto const& collision : collisions) { + o2::common::multiplicity::multEntry mult; + const auto& bc = bcs.rawIteratorAt(collision.getId()); + const uint64_t collIdx = collision.globalIndex(); + auto tracksThisCollision = tracks.sliceBy(slicerTrackRun2, collIdx); + mult = module.collisionProcessRun2(collision, tracksThisCollision, bc, products); + mults.push_back(mult); + } + } + + void processRun3(soa::Join const& collisions, + soa::Join const& tracks, + soa::Join const&, + aod::Zdcs const&, + aod::FV0As const&, + aod::FT0s const&, + aod::FDDs const&) + { + mults.clear(); + for (auto const& collision : collisions) { + o2::common::multiplicity::multEntry mult; + const auto& bc = collision.bc_as>(); + const uint64_t collIdx = collision.globalIndex(); + auto tracksThisCollision = tracks.sliceBy(slicerTracksIU, collIdx); + mult = module.collisionProcessRun3(ccdb, metadataInfo, collision, tracksThisCollision, bc, products); + mults.push_back(mult); + } + } + + void processRun3WithGlobalCounters(soa::Join const& collisions, + soa::Join const& tracks, + soa::Join const&, + aod::Zdcs const&, + aod::FV0As const&, + aod::FT0s const&, + aod::FDDs const&) + { + mults.clear(); + for (auto const& collision : collisions) { + o2::common::multiplicity::multEntry mult; + const auto& bc = collision.bc_as>(); + const uint64_t collIdx = collision.globalIndex(); + auto tracksThisCollision = tracks.sliceBy(slicerTracksIUwithSelections, collIdx); + mult = module.collisionProcessRun3(ccdb, metadataInfo, collision, tracksThisCollision, bc, products); + mults.push_back(mult); + } + } + void processMFT(soa::Join::iterator const& collision, + o2::aod::MFTTracks const& mfttracks, + soa::SmallGroups const& retracks) + { + if (opts.mEnabledTables[o2::common::multiplicity::kMFTMults]) { + // populates MFT information in the mults buffer (in addition to filling table) + module.collisionProcessMFT(collision, mfttracks, retracks, mults, products); + } + } + void processMonteCarlo(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + if (opts.mEnabledTables[o2::common::multiplicity::kMultMCExtras]) { + module.collisionProcessMonteCarlo(mcCollision, mcParticles, pdg, products); + } + } + void processMonteCarlo2Mults(soa::Join::iterator const& collision) + { + if (opts.mEnabledTables[o2::common::multiplicity::kMult2MCExtras]) { + // establish simple interlink for posterior analysis (derived data) + products.tableExtraMult2MCExtras(collision.mcCollisionId()); + } + } + void processCentralityRun2(aod::Collisions const& collisions, soa::Join const& bcs) + { + // it is important that this function is at the end of the other process functions. + // it requires `mults` to be properly set, which will only happen after the other process + // functions have been called. + + // internally, the function below will do nothing if no centrality is requested. + // it is thus safer to always keep the actual process function for centrality + // generation to true, since the requisites for being in this context are + // always fulfilled + if (collisions.size() != static_cast(mults.size())) { + LOGF(fatal, "Size of collisions doesn't match size of multiplicity buffer!"); + } + module.generateCentralitiesRun2(ccdb, metadataInfo, bcs, mults, products); + } + void processCentralityRun3(aod::Collisions const& collisions, soa::Join const& bcs, aod::FT0s const&) + { + // it is important that this function is at the end of the other process functions. + // it requires `mults` to be properly set, which will only happen after the other process + // functions have been called. + + // internally, the function below will do nothing if no centrality is requested. + // it is thus safer to always keep the actual process function for centrality + // generation to true, since the requisites for being in this context are + // always fulfilled + if (collisions.size() != static_cast(mults.size())) { + LOGF(fatal, "Size of collisions doesn't match size of multiplicity buffer!"); + } + module.generateCentralitiesRun3(ccdb, metadataInfo, bcs, mults, products); + } + + PROCESS_SWITCH(MultCentTable, processRun2, "Process Run 2", false); + PROCESS_SWITCH(MultCentTable, processRun3, "Process Run 3", true); + PROCESS_SWITCH(MultCentTable, processRun3WithGlobalCounters, "Process Run 3 + global tracking counters", false); + PROCESS_SWITCH(MultCentTable, processMFT, "Process MFT info", false); + PROCESS_SWITCH(MultCentTable, processMonteCarlo, "Process Monte Carlo information", false); + PROCESS_SWITCH(MultCentTable, processMonteCarlo2Mults, "Process Monte Carlo information", false); + PROCESS_SWITCH(MultCentTable, processCentralityRun2, "Generate Run 2 centralities", false); + PROCESS_SWITCH(MultCentTable, processCentralityRun3, "Generate Run 3 centralities", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(cfgc); + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/Common/TableProducer/multiplicityExtraTable.cxx b/Common/TableProducer/multiplicityExtraTable.cxx index cc37a39e34b..949d461298d 100644 --- a/Common/TableProducer/multiplicityExtraTable.cxx +++ b/Common/TableProducer/multiplicityExtraTable.cxx @@ -8,20 +8,30 @@ // In applying this license CERN does 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" -#include "Framework/AnalysisDataModel.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "DataFormatsFIT/Triggers.h" -#include "TableHelper.h" -#include "CCDB/CcdbApi.h" -#include "CommonDataFormat/BunchFilling.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPLHCIFData.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; @@ -30,12 +40,28 @@ using BCPattern = std::bitset; const int nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; struct MultiplicityExtraTable { - Produces multBC; + Produces multBC; Produces multNeigh; + Produces mult2bc; + Produces bc2mult; + + // auxiliary for MC + Produces multHepMCHIs; + // 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; @@ -59,117 +85,182 @@ struct MultiplicityExtraTable { using BCsWithRun3Matchings = soa::Join; - void processBCs(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) { - // downscale if requested to do so - if (bcDownscaleFactor < 1.f && (static_cast(rand_r(&randomSeed)) / static_cast(RAND_MAX)) > bcDownscaleFactor) { - return; + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // 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; } - 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) { - 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()) { - 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; - } - } else { - multFT0A = -999.0f; - multFT0C = -999.0f; + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // tag BCs that have a collision (from evsel foundBC) + for (const auto& collision : collisions) { + bcHasCollision[collision.foundBCId()] = true; } - 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; + 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; } - 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()); + 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 : fdd.chargeA()) { - multFDDA += amplitude; + if (multFT0C < minFT0CforBCTable) { + continue; // skip this event } - for (auto amplitude : fdd.chargeC()) { - multFDDC += amplitude; + + if (saveOnlyBCsWithCollisions && !bcHasCollision[bc.globalIndex()]) { + continue; // skip if no collision is assigned to this BC (from evSel assignment) } - } 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; + newBCindex[bc.globalIndex()] = atIndex++; } + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ - if (multFT0C < minFT0CforBCTable) { - return; // skip this event + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + // interlink: collision -> valid BC, BC -> collision + for (const auto& collision : collisions) { + mult2bc(newBCindex[collision.foundBCId()]); + bc2multArray[collision.foundBCId()] = collision.globalIndex(); } + //+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ + + for (const auto& bc : bcs) { + if (newBCindex[bc.globalIndex()] < 0) { + continue; // don't keep if low mult or downsampled out + } + + 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; + } - multBC(multFT0A, multFT0C, multFV0A, multFDDA, multFDDC, multZNA, multZNC, multZEM1, multZEM2, multZPA, multZPC, Tvx, isFV0OrA, multFV0TriggerBits, multFT0TriggerBits, multFDDTriggerBits, multBCTriggerMask, collidingBC); + 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()); + } } void processCollisionNeighbors(aod::Collisions const& collisions) @@ -199,9 +290,22 @@ struct MultiplicityExtraTable { } } + void processHepMCHeavyIons(aod::HepMCHeavyIons const& hepmchis) + { + for (auto const& hepmchi : hepmchis) { + multHepMCHIs(hepmchi.mcCollisionId(), + hepmchi.ncollHard(), + hepmchi.npartProj(), + hepmchi.npartTarg(), + hepmchi.ncoll(), + hepmchi.impactParameter()); + } + } + // Process switches PROCESS_SWITCH(MultiplicityExtraTable, processBCs, "Produce BC tables", true); PROCESS_SWITCH(MultiplicityExtraTable, processCollisionNeighbors, "Produce neighbor timing tables", true); + PROCESS_SWITCH(MultiplicityExtraTable, processHepMCHeavyIons, "Produce MultHepMCHIs tables", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/Common/TableProducer/multiplicityTable.cxx b/Common/TableProducer/multiplicityTable.cxx index baf9ab6eb4b..53882bb9d77 100644 --- a/Common/TableProducer/multiplicityTable.cxx +++ b/Common/TableProducer/multiplicityTable.cxx @@ -8,27 +8,56 @@ // In applying this license CERN does not 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 "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/DataModel/Multiplicity.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" + +#include "Common/Core/MetadataHelper.h" +#include "Common/Core/TableHelper.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "TableHelper.h" -#include "MetadataHelper.h" -#include "TList.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; -MetadataHelper metadataInfo; // Metadata helper +o2::common::core::MetadataHelper metadataInfo; // Metadata helper static constexpr int kFV0Mults = 0; static constexpr int kFT0Mults = 1; @@ -43,8 +72,8 @@ 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 kMultMCExtras = 13; +static constexpr int Ntables = 14; // Checking that the Zeq tables are after the normal ones static_assert(kFV0Mults < kFV0MultZeqs); @@ -52,7 +81,7 @@ static_assert(kFT0Mults < kFT0MultZeqs); static_assert(kFDDMults < kFDDMultZeqs); static_assert(kPVMults < kPVMultZeqs); -static constexpr int nParameters = 1; +static constexpr int Nparameters = 1; static const std::vector tableNames{"FV0Mults", // 0 "FT0Mults", // 1 "FDDMults", // 2 @@ -66,13 +95,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 @@ -85,8 +115,11 @@ struct MultiplicityTable { Produces tableFT0Zeqs; // 10 Produces tableFDDZeqs; // 11 Produces tablePVZeqs; // 12 - Produces tableExtraMc; // 13 - Produces multsGlobal; // Not accounted for, produced based on process function processGlobalTrackingCounters + Produces tableExtraMc; // 13 + Produces tableExtraMult2MCExtras; + Produces multHepMCHIs; // Not accounted for, produced using custom process function to avoid dependencies + 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 Service ccdb; @@ -95,10 +128,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; @@ -106,12 +140,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; @@ -120,6 +159,7 @@ struct MultiplicityTable { TProfile* hVtxZFT0A; TProfile* hVtxZFT0C; TProfile* hVtxZFDDA; + TProfile* hVtxZFDDC; TProfile* hVtxZNTracks; std::vector mEnabledTables; // Vector of enabled tables @@ -131,11 +171,15 @@ struct MultiplicityTable { unsigned int randomSeed = 0; void init(InitContext& context) { - 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 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; + } } } @@ -146,8 +190,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) { @@ -159,10 +204,10 @@ struct MultiplicityTable { } } // Handle the custom cases. - if (tEnabled[kMultsExtraMC]) { - if (enabledTables->get(tableNames[kMultsExtraMC].c_str(), "Enable") == -1) { + if (tEnabled[kMultMCExtras]) { + if (enabledTables->get(tableNames[kMultMCExtras].c_str(), "Enable") == -1) { doprocessMC.value = true; - LOG(info) << "Enabling MC processing due to " << tableNames[kMultsExtraMC] << " table being enabled."; + LOG(info) << "Enabling MC processing due to " << tableNames[kMultMCExtras] << " table being enabled."; } } @@ -195,11 +240,12 @@ 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; } @@ -207,8 +253,6 @@ struct MultiplicityTable { 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."}}); - - listCalib.setObject(new TList); } /// Dummy process function for BCs, needed in case both Run2 and Run3 process functions are disabled @@ -240,21 +284,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; } } @@ -264,7 +308,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); @@ -274,14 +331,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&, @@ -289,10 +347,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()); @@ -330,7 +389,7 @@ struct MultiplicityTable { case kPVMultZeqs: // Equalized multiplicity for PV tablePVZeqs.reserve(collisions.size()); break; - case kMultsExtraMC: // MC extra information (nothing to do in the data) + case kMultMCExtras: // MC extra information (nothing to do in the data) break; default: LOG(fatal) << "Unknown table requested: " << i; @@ -340,6 +399,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; @@ -372,7 +432,20 @@ 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()))); @@ -397,23 +470,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()) { const auto& fv0 = collision.foundFV0(); - for (auto amplitude : fv0.amplitude()) { + 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 @@ -423,10 +503,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 { @@ -443,10 +523,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 { @@ -458,12 +538,6 @@ struct MultiplicityTable { } break; case kZDCMults: // ZDC { - multZNA = -1.f; - multZNC = -1.f; - multZEM1 = -1.f; - multZEM2 = -1.f; - multZPA = -1.f; - multZPC = -1.f; if (bc.has_zdc()) { multZNA = bc.zdc().amplitudeZNA(); multZNC = bc.zdc().amplitudeZNC(); @@ -498,12 +572,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; @@ -514,7 +591,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()) @@ -535,7 +612,7 @@ struct MultiplicityTable { int nAllTracksTPCOnly = 0; int nAllTracksITSTPC = 0; - for (auto track : tpcTracksGrouped) { + for (const auto& track : tpcTracksGrouped) { if (track.hasITS()) { nAllTracksITSTPC++; } else { @@ -543,12 +620,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, collision.trackOccupancyInTimeRange()); + nAllTracksTPCOnly, nAllTracksITSTPC, + collision.trackOccupancyInTimeRange(), + collision.ft0cOccupancyInTimeRange(), + collision.flags()); } break; case kMultSelections: // Multiplicity selections { @@ -556,14 +634,14 @@ 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()); } @@ -577,7 +655,7 @@ struct MultiplicityTable { } 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()); } @@ -585,12 +663,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 @@ -605,13 +683,16 @@ 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; @@ -642,31 +723,117 @@ 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 processGlobalTrackingCounters(aod::Collision const&, - soa::Join const& tracks) + void processMC2Mults(soa::Join::iterator const& collision) + { + tableExtraMult2MCExtras(collision.mcCollisionId()); // interlink + } + + 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 processHepMCHeavyIons(aod::HepMCHeavyIons const& hepmchis) + { + for (auto const& hepmchi : hepmchis) { + multHepMCHIs(hepmchi.mcCollisionId(), + hepmchi.ncollHard(), + hepmchi.npartProj(), + hepmchi.npartTarg(), + hepmchi.ncoll(), + hepmchi.impactParameter()); + } + } + + 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, processHepMCHeavyIons, "Produce MultHepMCHIs tables", false); + PROCESS_SWITCH(MultiplicityTable, processRun3MFT, "Produce MFT mult tables", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/Common/TableProducer/muonRealignment.cxx b/Common/TableProducer/muonRealignment.cxx new file mode 100644 index 00000000000..3fa9b462c0f --- /dev/null +++ b/Common/TableProducer/muonRealignment.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. + +/// \file muonRealignment.cxx +/// \brief Task for muon re-alignment at analysis level +/// \author Chi Zhang , CEA-Saclay + +#include "Common/DataModel/FwdTrackReAlignTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::mch; +using namespace o2::framework::expressions; + +using MyMuonsWithCov = soa::Join; + +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 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 + + 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; + + 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(TMuons const& muons, TMuonCls const& clusters) + { + // Reserve storage for output table + realignFwdTrks.reserve(muons.size()); + realignFwdTrksCov.reserve(muons.size()); + + // Loop over forward tracks using association indices + FwdTrkCovRealignInfo fwdTrkCovRealignInfo; + for (auto const& muon : muons) { + int muonRealignId = muon.globalIndex(); + if (static_cast(muon.trackType() > 2)) { + + 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(muon.collisionId(), muon.trackType(), fwdtrack.getX(), fwdtrack.getY(), fwdtrack.getZ(), fwdtrack.getPhi(), fwdtrack.getTgl(), fwdtrack.getInvQPt(), convertedTrack.getNClusters(), muon.pDca(), muon.rAtAbsorberEnd(), removable, fwdtrack.getTrackChi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.matchScoreMCHMFT(), muon.matchMFTTrackId(), muon.matchMCHTrackId(), + muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), + muon.trackTime(), muon.trackTimeRes()); + 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 { + realignFwdTrks(muon.collisionId(), muon.trackType(), muon.x(), muon.y(), muon.z(), muon.phi(), muon.tgl(), muon.signed1Pt(), muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), 0, muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.matchScoreMCHMFT(), muon.matchMFTTrackId(), muon.matchMCHTrackId(), + muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), + muon.trackTime(), muon.trackTimeRes()); + realignFwdTrksCov(muon.sigmaX(), muon.sigmaY(), muon.sigmaPhi(), muon.sigmaTgl(), muon.sigma1Pt(), muon.rhoXY(), muon.rhoPhiY(), muon.rhoPhiX(), muon.rhoTglX(), muon.rhoTglY(), muon.rhoTglPhi(), muon.rho1PtX(), muon.rho1PtY(), muon.rho1PtPhi(), muon.rho1PtTgl()); + muonRealignId++; + } + } + } + + void processMuonReAlignment(aod::Collisions const& collisions, aod::BCsWithTimestamps const&, MyMuonsWithCov const& tracks, aod::FwdTrkCls const& clusters) + { + bool FirstEvent = true; + for (auto const& collision : collisions) { + + if (!FirstEvent) { + break; + } + + auto bc = collision.template bc_as(); + if (fCurrentRun != bc.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(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()); + } + + // 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); + } + + 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); + } + + fCurrentRun = bc.runNumber(); + } + FirstEvent = false; + } + + runMuonRealignment(tracks, clusters); + } + PROCESS_SWITCH(MuonRealignment, processMuonReAlignment, "Process to do muon realignment", 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..c3075e01d54 --- /dev/null +++ b/Common/TableProducer/occupancyTableProducer.cxx @@ -0,0 +1,2772 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/OccupancyTables.h" + +#include +#include +#include +#include +#include +#include +#include +#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; + +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 + +template +void sortVectorOfArray(std::vector>& myVector, const int& myIDX) +{ + std::sort(myVector.begin(), myVector.end(), [myIDX](const std::array& a, const std::array& b) { + return a[myIDX] < b[myIDX]; // sort at the required index + }); +} + +template +void checkUniqueness(const std::vector>& myVector, const int& myIDX) +{ + for (size_t i = 1; i < myVector.size(); i++) { + if (myVector[i][myIDX] <= myVector[i - 1][myIDX]) { + LOG(error) << "Duplicate Entries while creating Index tables :: (vec[" << i << "][" << myIDX << "]) " << myVector[i][myIDX] << " >= " << myVector[i - 1][myIDX] << " (vec[" << i - 1 << "][" << myIDX << "])"; + } + } +} + +struct OccupancyTableProducer { + + Service ccdb; + + // declare production of tables + Produces genBCTFinfoTable; + // 0 + Produces genOccIndexTable; + Produces genOccsBCsList; + // 1 + Produces genOccsPrim; + Produces genOccsMeanPrim; + // 2 + Produces genOccsT0V0; + Produces genOccsMeanT0V0; + ; + Produces genORT0V0Prim; + Produces genOccsMeanRobustT0V0Prim; + // 3 + Produces genOccsFDD; + Produces genOccsMeanFDD; + Produces genORFDDT0V0Prim; + Produces genOccsMeanRobustFDDT0V0Prim; + // 4 + Produces genOccsNTrackDet; + Produces genOccsMeanNTrkDet; + Produces genORNtrackDet; + Produces genOccsMeanRobustNtrackDet; + // 5 + Produces genOccsMultExtra; + Produces genOccsMnMultExtra; + Produces genORMultExtra; + Produces genOccsMeanRobustMultExtraTable; + + Configurable customOrbitOffset{"customOrbitOffset", 0, "customOrbitOffset for MC"}; + Configurable bcGrouping{"bcGrouping", 80, "bcGrouping of BCs"}; + Configurable nBCinTF{"nBCinTF", 114048, "nBCinTF"}; + Configurable occVecArraySize{"occVecArraySize", 10, "occVecArraySize"}; + + Configurable cfgNOrbitsPerTF0RunValue{"cfgNOrbitsPerTF0RunValue", 534133, "cfgNOrbitsPerTF0RunValue"}; + Configurable cfgNOrbitsPerTF1TrueValue{"cfgNOrbitsPerTF1TrueValue", 128, "cfgNOrbitsPerTF1TrueValue"}; + Configurable cfgNOrbitsPerTF2FalseValue{"cfgNOrbitsPerTF2FalseValue", 32, "ccfgNOrbitsPerTF2FalseValue"}; + + // declare production of tables + Configurable buildOnlyOccsPrim{"buildOnlyOccsPrim", true, "builder of table OccsPrim"}; + Configurable buildOnlyOccsT0V0Prim{"buildOnlyOccsT0V0Prim", true, "builder of table OccsT0V0Prim"}; + Configurable buildOnlyOccsFDDT0V0Prim{"buildOnlyOccsFDDT0V0Prim", true, "builder of table OccsFDDT0V0Prim"}; + Configurable buildOnlyOccsNtrackDet{"buildOnlyOccsNtrackDet", true, "builder of table OccsNtrackDet"}; + Configurable buildOnlyOccsMultExtra{"buildOnlyOccsMultExtra", true, "builder of table OccsMultExtra"}; + Configurable buildFullOccTableProducer{"buildFullOccTableProducer", true, "builder of all Occupancy Tables"}; + + Configurable buildFlag00OccTable{"buildFlag00OccTable", true, "switch of table Occ Table"}; + Configurable buildFlag01OccMeanTable{"buildFlag01OccMeanTable", true, "switch of table Occ MeanTable"}; + Configurable buildFlag02OccRobustTable{"buildFlag02OccRobustTable", true, "switch of table Occ RobustTable"}; + Configurable buildFlag03OccMeanRobustTable{"buildFlag03OccMeanRobustTable", true, "switch of table Occ MeanRobustTable"}; + + // Histogram registry; + HistogramRegistry recoEvent{"recoEvent", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry occupancyQA{"occupancyQA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + std::vector tfList; + std::vector> bcTFMap; + + 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 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; + + std::vector processStatus; + Configurable processStatusSize{"processStatusSize", 10, "processStatusSize"}; + void init(InitContext const&) + { + processStatus.resize(processStatusSize); + for (uint i = 0; i < processStatusSize; i++) { + processStatus[i] = false; + } + + // outer vector resized at runtime + tfList.resize(occVecArraySize); + bcTFMap.resize(occVecArraySize); + + if (buildFullOccTableProducer || buildOnlyOccsPrim || buildOnlyOccsT0V0Prim || buildOnlyOccsFDDT0V0Prim || buildOnlyOccsNtrackDet || buildOnlyOccsMultExtra) { + occPrimUnfm80.resize(occVecArraySize); + } + if (buildFullOccTableProducer || buildOnlyOccsT0V0Prim || buildOnlyOccsFDDT0V0Prim) { + occFV0AUnfm80.resize(occVecArraySize); + occFV0CUnfm80.resize(occVecArraySize); + occFT0AUnfm80.resize(occVecArraySize); + occFT0CUnfm80.resize(occVecArraySize); + } + if (buildFullOccTableProducer || buildOnlyOccsFDDT0V0Prim) { + occFDDAUnfm80.resize(occVecArraySize); + occFDDCUnfm80.resize(occVecArraySize); + } + if (buildFullOccTableProducer || buildOnlyOccsNtrackDet) { + occNTrackITSUnfm80.resize(occVecArraySize); + occNTrackTPCUnfm80.resize(occVecArraySize); + occNTrackTRDUnfm80.resize(occVecArraySize); + occNTrackTOFUnfm80.resize(occVecArraySize); + occNTrackSizeUnfm80.resize(occVecArraySize); + occNTrackTPCAUnfm80.resize(occVecArraySize); + occNTrackTPCCUnfm80.resize(occVecArraySize); + occNTrackITSTPCAUnfm80.resize(occVecArraySize); + occNTrackITSTPCCUnfm80.resize(occVecArraySize); + } + if (buildFullOccTableProducer || buildOnlyOccsNtrackDet || buildOnlyOccsMultExtra) { + occNTrackITSTPCUnfm80.resize(occVecArraySize); + } + if (buildFullOccTableProducer || buildOnlyOccsMultExtra) { + occMultNTracksHasITSUnfm80.resize(occVecArraySize); + occMultNTracksHasTPCUnfm80.resize(occVecArraySize); + occMultNTracksHasTOFUnfm80.resize(occVecArraySize); + occMultNTracksHasTRDUnfm80.resize(occVecArraySize); + occMultNTracksITSOnlyUnfm80.resize(occVecArraySize); + occMultNTracksTPCOnlyUnfm80.resize(occVecArraySize); + occMultNTracksITSTPCUnfm80.resize(occVecArraySize); + occMultAllTracksTPCOnlyUnfm80.resize(occVecArraySize); + } + + for (int i = 0; i < occVecArraySize; i++) { + bcTFMap[i].resize(nBCinTF / bcGrouping); + if (buildFullOccTableProducer || buildOnlyOccsPrim || buildOnlyOccsT0V0Prim || buildOnlyOccsFDDT0V0Prim || buildOnlyOccsNtrackDet || buildOnlyOccsMultExtra) { + occPrimUnfm80[i].resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsT0V0Prim || buildOnlyOccsFDDT0V0Prim) { + occFV0AUnfm80[i].resize(nBCinTF / bcGrouping); + occFV0CUnfm80[i].resize(nBCinTF / bcGrouping); + occFT0AUnfm80[i].resize(nBCinTF / bcGrouping); + occFT0CUnfm80[i].resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsFDDT0V0Prim) { + occFDDAUnfm80[i].resize(nBCinTF / bcGrouping); + occFDDCUnfm80[i].resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsNtrackDet) { + occNTrackITSUnfm80[i].resize(nBCinTF / bcGrouping); + occNTrackTPCUnfm80[i].resize(nBCinTF / bcGrouping); + occNTrackTRDUnfm80[i].resize(nBCinTF / bcGrouping); + occNTrackTOFUnfm80[i].resize(nBCinTF / bcGrouping); + occNTrackSizeUnfm80[i].resize(nBCinTF / bcGrouping); + occNTrackTPCAUnfm80[i].resize(nBCinTF / bcGrouping); + occNTrackTPCCUnfm80[i].resize(nBCinTF / bcGrouping); + occNTrackITSTPCAUnfm80[i].resize(nBCinTF / bcGrouping); + occNTrackITSTPCCUnfm80[i].resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsNtrackDet || buildOnlyOccsMultExtra) { + occNTrackITSTPCUnfm80[i].resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsMultExtra) { + occMultNTracksHasITSUnfm80[i].resize(nBCinTF / bcGrouping); + occMultNTracksHasTPCUnfm80[i].resize(nBCinTF / bcGrouping); + occMultNTracksHasTOFUnfm80[i].resize(nBCinTF / bcGrouping); + occMultNTracksHasTRDUnfm80[i].resize(nBCinTF / bcGrouping); + occMultNTracksITSOnlyUnfm80[i].resize(nBCinTF / bcGrouping); + occMultNTracksTPCOnlyUnfm80[i].resize(nBCinTF / bcGrouping); + occMultNTracksITSTPCUnfm80[i].resize(nBCinTF / bcGrouping); + occMultAllTracksTPCOnlyUnfm80[i].resize(nBCinTF / bcGrouping); + } + } + + if (buildFullOccTableProducer || buildOnlyOccsT0V0Prim || buildFlag02OccRobustTable || buildFlag03OccMeanRobustTable) { + vecRobustOccT0V0PrimUnfm80.resize(nBCinTF / bcGrouping); + vecRobustOccT0V0PrimUnfm80medianPosVec.resize(nBCinTF / bcGrouping); // Median => one for odd and two for even entries + } + if (buildFullOccTableProducer || buildOnlyOccsFDDT0V0Prim || buildFlag02OccRobustTable || buildFlag03OccMeanRobustTable) { + vecRobustOccFDDT0V0PrimUnfm80.resize(nBCinTF / bcGrouping); + vecRobustOccFDDT0V0PrimUnfm80medianPosVec.resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsNtrackDet || buildFlag02OccRobustTable || buildFlag03OccMeanRobustTable) { + vecRobustOccNtrackDetUnfm80.resize(nBCinTF / bcGrouping); + vecRobustOccNtrackDetUnfm80medianPosVec.resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsMultExtra || buildFlag02OccRobustTable || buildFlag03OccMeanRobustTable) { + vecRobustOccmultTableUnfm80.resize(nBCinTF / bcGrouping); + vecRobustOccmultTableUnfm80medianPosVec.resize(nBCinTF / bcGrouping); + } + + // 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}}}); + occupancyQA.add("h_TF_in_DataFrame", "h_TF_in_DataFrame", kTH1F, {{50, -1, 49}}); + occupancyQA.add("h_DFcount_Lvl0", "h_DFcount_Lvl0", kTH1F, {{1, 0, 1}}); + occupancyQA.add("h_DFcount_Lvl1", "h_DFcount_Lvl1", kTH1F, {{1, 0, 1}}); + occupancyQA.add("h_DFcount_Lvl2", "h_DFcount_Lvl2", kTH1F, {{1, 0, 1}}); + + recoEvent.print(); + occupancyQA.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; + int two = 2; + // Find the median + if (n % two == 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 < cfgNOrbitsPerTF0RunValue ? cfgNOrbitsPerTF1TrueValue : cfgNOrbitsPerTF2FalseValue; + 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 MyTracks = aod::Tracks; + + 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; + //_________________________Full Exection Function_______________________________________________________________________________________ + + enum ProcessTags { + kProcessOnlyBCTFinfoTable = 0, + kProcessOnlyOccPrim, + kProcessOnlyOccT0V0Prim, + kProcessOnlyOccFDDT0V0Prim, + kProcessOnlyOccNtrackDet, + kProcessOnlyOccMultExtra, + kProcessFullOccTableProducer + }; + + static constexpr std::string_view ProcessNames[]{ + "processOnlyBCTFinfoTable", + "processOnlyOccPrimUnfm", + "processOnlyOccT0V0PrimUnfm", + "processOnlyOccFDDT0V0PrimUnfm", + "processOnlyOccNtrackDet", + "processOnlyOccMultExtra", + "processFullOccTableProduer"}; + + enum FillMode { + checkTableMode = 0, + doNotFill, + fillOccTable, + fillMeanOccTable, + fillOccRobustTable, + fillOccMeanRobustTable + }; + + template + void executeCollisionCheckAndBCprocessing(B const& BCs, C const& collisions, bool& collisionsSizeIsZero) + { + 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); + genBCTFinfoTable(tfIdThis, bcInTF); + genOccIndexTable(BC.globalIndex(), -999); // BCId, OccId + } + collisionsSizeIsZero = true; + } + } + + int processTimeCounter = 0; + template + void executeOccProducerProcessing(B const& BCs, C const& collisions, T const& tracks) + { + if (tableMode == checkTableMode) { + if (buildFlag00OccTable) { + executeOccProducerProcessing(BCs, collisions, tracks); + } else { + executeOccProducerProcessing(BCs, collisions, tracks); + } + } + if constexpr (tableMode == checkTableMode) { + return; + } + + if (meanTableMode == checkTableMode) { + if (buildFlag01OccMeanTable) { + executeOccProducerProcessing(BCs, collisions, tracks); + } else { + executeOccProducerProcessing(BCs, collisions, tracks); + } + } + if constexpr (meanTableMode == checkTableMode) { + return; + } + + if (robustTableMode == checkTableMode) { + if (buildFlag02OccRobustTable) { + executeOccProducerProcessing(BCs, collisions, tracks); + } else { + executeOccProducerProcessing(BCs, collisions, tracks); + } + } + if constexpr (robustTableMode == checkTableMode) { + return; + } + + if (meanRobustTableMode == checkTableMode) { + if (buildFlag03OccMeanRobustTable) { + executeOccProducerProcessing(BCs, collisions, tracks); + } else { + executeOccProducerProcessing(BCs, collisions, tracks); + } + } + if constexpr (meanRobustTableMode == checkTableMode) { + return; + } + + if constexpr (tableMode == checkTableMode || meanTableMode == checkTableMode || robustTableMode == checkTableMode || meanRobustTableMode == checkTableMode) { + return; + } else { + + occupancyQA.fill(HIST("h_DFcount_Lvl2"), 0.5); + + // Initialisze the vectors components to zero + tfIDX = 0; + tfCounted = 0; + for (int i = 0; i < occVecArraySize; i++) { + tfList[i] = -1; + bcTFMap[i].clear(); // list of BCs used in one time frame; + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccPrim || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim || processMode == kProcessOnlyOccNtrackDet || processMode == kProcessOnlyOccMultExtra) { + std::fill(occPrimUnfm80[i].begin(), occPrimUnfm80[i].end(), 0.); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim) { + 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.); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccFDDT0V0Prim) { + std::fill(occFDDAUnfm80[i].begin(), occFDDAUnfm80[i].end(), 0.); + std::fill(occFDDCUnfm80[i].begin(), occFDDCUnfm80[i].end(), 0.); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet) { + 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(occNTrackITSTPCAUnfm80[i].begin(), occNTrackITSTPCAUnfm80[i].end(), 0.); + std::fill(occNTrackITSTPCCUnfm80[i].begin(), occNTrackITSTPCCUnfm80[i].end(), 0.); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet || processMode == kProcessOnlyOccMultExtra) { + std::fill(occNTrackITSTPCUnfm80[i].begin(), occNTrackITSTPCUnfm80[i].end(), 0.); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccMultExtra) { + 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; + int nTrackITS = 0; + int nTrackTPC = 0; + int nTrackTRD = 0; + int nTrackTOF = 0; + int nTrackTPCA = 0; + int nTrackTPCC = 0; + int nTrackITSTPCA = 0; + int nTrackITSTPCC = 0; + + ushort fNumContrib = 0; + + float fMultFV0A = -99999, fMultFV0C = -99999; + float fMultFT0A = -99999, fMultFT0C = -99999; + float fMultFDDA = -99999, fMultFDDC = -99999; + + int fNTrackITS = -9999; + int fNTrackTPC = -9999; + int fNTrackTRD = -9999; + int fNTrackTOF = -9999; + int fNTrackTPCA = -9999; + int fNTrackTPCC = -9999; + int fNTrackSize = -9999; + int fNTrackITSTPC = -9999; + int fNTrackITSTPCA = -9999; + int fNTrackITSTPCC = -9999; + + decltype(&occPrimUnfm80[0]) tfOccPrimUnfm80 = nullptr; + decltype(&occFV0AUnfm80[0]) tfOccFV0AUnfm80 = nullptr; + decltype(&occFV0CUnfm80[0]) tfOccFV0CUnfm80 = nullptr; + decltype(&occFT0AUnfm80[0]) tfOccFT0AUnfm80 = nullptr; + decltype(&occFT0CUnfm80[0]) tfOccFT0CUnfm80 = nullptr; + + decltype(&occFDDAUnfm80[0]) tfOccFDDAUnfm80 = nullptr; + decltype(&occFDDCUnfm80[0]) tfOccFDDCUnfm80 = nullptr; + + decltype(&occNTrackITSTPCUnfm80[0]) tfOccNTrackITSTPCUnfm80 = nullptr; + + decltype(&occNTrackITSUnfm80[0]) tfOccNTrackITSUnfm80 = nullptr; + decltype(&occNTrackTPCUnfm80[0]) tfOccNTrackTPCUnfm80 = nullptr; + decltype(&occNTrackTRDUnfm80[0]) tfOccNTrackTRDUnfm80 = nullptr; + decltype(&occNTrackTOFUnfm80[0]) tfOccNTrackTOFUnfm80 = nullptr; + decltype(&occNTrackSizeUnfm80[0]) tfOccNTrackSizeUnfm80 = nullptr; + decltype(&occNTrackTPCAUnfm80[0]) tfOccNTrackTPCAUnfm80 = nullptr; + decltype(&occNTrackTPCCUnfm80[0]) tfOccNTrackTPCCUnfm80 = nullptr; + decltype(&occNTrackITSTPCAUnfm80[0]) tfOccNTrackITSTPCAUnfm80 = nullptr; + decltype(&occNTrackITSTPCCUnfm80[0]) tfOccNTrackITSTPCCUnfm80 = nullptr; + + decltype(&occMultNTracksHasITSUnfm80[0]) tfOccMultNTracksHasITSUnfm80 = nullptr; + decltype(&occMultNTracksHasTPCUnfm80[0]) tfOccMultNTracksHasTPCUnfm80 = nullptr; + decltype(&occMultNTracksHasTOFUnfm80[0]) tfOccMultNTracksHasTOFUnfm80 = nullptr; + decltype(&occMultNTracksHasTRDUnfm80[0]) tfOccMultNTracksHasTRDUnfm80 = nullptr; + decltype(&occMultNTracksITSOnlyUnfm80[0]) tfOccMultNTracksITSOnlyUnfm80 = nullptr; + decltype(&occMultNTracksTPCOnlyUnfm80[0]) tfOccMultNTracksTPCOnlyUnfm80 = nullptr; + decltype(&occMultNTracksITSTPCUnfm80[0]) tfOccMultNTracksITSTPCUnfm80 = nullptr; + decltype(&occMultAllTracksTPCOnlyUnfm80[0]) tfOccMultAllTracksTPCOnlyUnfm80 = nullptr; + + for (const auto& collision : collisions) { + const auto& bc = collision.template 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"; + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet) { + const uint64_t collIdx = collision.globalIndex(); + const auto tracksTablePerColl = tracks.sliceBy(tracksPerCollisionPreslice, collIdx); + + fNTrackSize = tracksTablePerColl.size(); + + nTrackITS = 0; + nTrackTPC = 0; + nTrackTRD = 0; + nTrackTOF = 0; + nTrackTPCA = 0; + nTrackTPCC = 0; + nTrackITSTPCA = 0; + 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()); + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccPrim || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim || processMode == kProcessOnlyOccNtrackDet || processMode == kProcessOnlyOccMultExtra) { + tfOccPrimUnfm80 = &occPrimUnfm80[tfIDX]; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim) { + tfOccFV0AUnfm80 = &occFV0AUnfm80[tfIDX]; + tfOccFV0CUnfm80 = &occFV0CUnfm80[tfIDX]; + tfOccFT0AUnfm80 = &occFT0AUnfm80[tfIDX]; + tfOccFT0CUnfm80 = &occFT0CUnfm80[tfIDX]; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccFDDT0V0Prim) { + tfOccFDDAUnfm80 = &occFDDAUnfm80[tfIDX]; + tfOccFDDCUnfm80 = &occFDDCUnfm80[tfIDX]; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet) { + tfOccNTrackITSUnfm80 = &occNTrackITSUnfm80[tfIDX]; + tfOccNTrackTPCUnfm80 = &occNTrackTPCUnfm80[tfIDX]; + tfOccNTrackTRDUnfm80 = &occNTrackTRDUnfm80[tfIDX]; + tfOccNTrackTOFUnfm80 = &occNTrackTOFUnfm80[tfIDX]; + tfOccNTrackSizeUnfm80 = &occNTrackSizeUnfm80[tfIDX]; + tfOccNTrackTPCAUnfm80 = &occNTrackTPCAUnfm80[tfIDX]; + tfOccNTrackTPCCUnfm80 = &occNTrackTPCCUnfm80[tfIDX]; + tfOccNTrackITSTPCAUnfm80 = &occNTrackITSTPCAUnfm80[tfIDX]; + tfOccNTrackITSTPCCUnfm80 = &occNTrackITSTPCCUnfm80[tfIDX]; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet || processMode == kProcessOnlyOccMultExtra) { + tfOccNTrackITSTPCUnfm80 = &occNTrackITSTPCUnfm80[tfIDX]; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccMultExtra) { + tfOccMultNTracksHasITSUnfm80 = &occMultNTracksHasITSUnfm80[tfIDX]; + tfOccMultNTracksHasTPCUnfm80 = &occMultNTracksHasTPCUnfm80[tfIDX]; + tfOccMultNTracksHasTOFUnfm80 = &occMultNTracksHasTOFUnfm80[tfIDX]; + tfOccMultNTracksHasTRDUnfm80 = &occMultNTracksHasTRDUnfm80[tfIDX]; + tfOccMultNTracksITSOnlyUnfm80 = &occMultNTracksITSOnlyUnfm80[tfIDX]; + tfOccMultNTracksTPCOnlyUnfm80 = &occMultNTracksTPCOnlyUnfm80[tfIDX]; + tfOccMultNTracksITSTPCUnfm80 = &occMultNTracksITSTPCUnfm80[tfIDX]; + tfOccMultAllTracksTPCOnlyUnfm80 = &occMultAllTracksTPCOnlyUnfm80[tfIDX]; + } + + // current collision bin in 80/160 bcGrouping. + int bin80Zero = bcInTF / bcGrouping; + // int bin160_0=bcInTF/160; + + // float fbin80Zero =float(bcInTF)/80; + // float fbin160_0=float(bcInTF)/160; + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccPrim || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim || processMode == kProcessOnlyOccNtrackDet || processMode == kProcessOnlyOccMultExtra) { + fNumContrib = collision.numContrib(); // only aod::Collisions will be needed + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim) { + fMultFV0A = collision.multFV0A(); + fMultFV0C = collision.multFV0C(); // o2::aod::Mults will be needed + fMultFT0A = collision.multFT0A(); + fMultFT0C = collision.multFT0C(); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccFDDT0V0Prim) { + fMultFDDA = collision.multFDDA(); + fMultFDDC = collision.multFDDC(); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet) { + fNTrackITS = nTrackITS; + fNTrackTPC = nTrackTPC; + fNTrackTRD = nTrackTRD; + fNTrackTOF = nTrackTOF; + fNTrackTPCA = nTrackTPCA; + fNTrackTPCC = nTrackTPCC; + fNTrackITSTPC = collision.multAllTracksITSTPC(); + fNTrackITSTPCA = nTrackITSTPCA; + fNTrackITSTPCC = nTrackITSTPCC; + } + // Processing for bcGrouping of 80 BCs + for (int deltaBin = 0; deltaBin < nBCinDrift / bcGrouping; deltaBin++) { + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccPrim || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim || processMode == kProcessOnlyOccNtrackDet || processMode == kProcessOnlyOccMultExtra) { + (*tfOccPrimUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNumContrib * 1; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim) { + (*tfOccFV0AUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fMultFV0A * 1; + (*tfOccFV0CUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fMultFV0C * 1; + (*tfOccFT0AUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fMultFT0A * 1; + (*tfOccFT0CUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fMultFT0C * 1; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccFDDT0V0Prim) { + (*tfOccFDDAUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fMultFDDA * 1; + (*tfOccFDDCUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fMultFDDC * 1; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet) { + (*tfOccNTrackITSUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackITS * 1; + (*tfOccNTrackTPCUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackTPC * 1; + (*tfOccNTrackTRDUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackTRD * 1; + (*tfOccNTrackTOFUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackTOF * 1; + (*tfOccNTrackSizeUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackSize * 1; + (*tfOccNTrackTPCAUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackTPCA * 1; + (*tfOccNTrackTPCCUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackTPCC * 1; + (*tfOccNTrackITSTPCAUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackITSTPCA * 1; + (*tfOccNTrackITSTPCCUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackITSTPCC * 1; + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet || processMode == kProcessOnlyOccMultExtra) { + (*tfOccNTrackITSTPCUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += fNTrackITSTPC * 1; + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccMultExtra) { + (*tfOccMultNTracksHasITSUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += collision.multNTracksHasITS() * 1; + (*tfOccMultNTracksHasTPCUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += collision.multNTracksHasTPC() * 1; + (*tfOccMultNTracksHasTOFUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += collision.multNTracksHasTOF() * 1; + (*tfOccMultNTracksHasTRDUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += collision.multNTracksHasTRD() * 1; + (*tfOccMultNTracksITSOnlyUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += collision.multNTracksITSOnly() * 1; + (*tfOccMultNTracksTPCOnlyUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += collision.multNTracksTPCOnly() * 1; + (*tfOccMultNTracksITSTPCUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += collision.multNTracksITSTPC() * 1; + (*tfOccMultAllTracksTPCOnlyUnfm80)[(bin80Zero + deltaBin) % (nBCinTF / bcGrouping)] += collision.multAllTracksTPCOnly() * 1; + } + } + } + // collision Loop is over + + occupancyQA.fill(HIST("h_TF_in_DataFrame"), tfCounted); + + 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 < occVecArraySize; 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++) { + + genOccsBCsList(tfList[i], bcTFMap[i]); + + auto& vecOccPrimUnfm80 = occPrimUnfm80[i]; + float meanOccPrimUnfm80 = TMath::Mean(vecOccPrimUnfm80.size(), vecOccPrimUnfm80.data()); + normalizeVector(vecOccPrimUnfm80, meanOccPrimUnfm80 / meanOccPrimUnfm80); + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccPrim || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim || processMode == kProcessOnlyOccNtrackDet || processMode == kProcessOnlyOccMultExtra) { + if constexpr (tableMode == fillOccTable) { + genOccsPrim(vecOccPrimUnfm80); + } + if constexpr (meanTableMode == fillMeanOccTable) { + genOccsMeanPrim(meanOccPrimUnfm80); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim) { + auto& vecOccFV0AUnfm80 = occFV0AUnfm80[i]; + auto& vecOccFV0CUnfm80 = occFV0CUnfm80[i]; + auto& vecOccFT0AUnfm80 = occFT0AUnfm80[i]; + auto& vecOccFT0CUnfm80 = occFT0CUnfm80[i]; + + 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()); + + // Normalise the original vectors + normalizeVector(vecOccFV0AUnfm80, meanOccPrimUnfm80 / meanOccFV0AUnfm80); + normalizeVector(vecOccFV0CUnfm80, meanOccPrimUnfm80 / meanOccFV0CUnfm80); + normalizeVector(vecOccFT0AUnfm80, meanOccPrimUnfm80 / meanOccFT0AUnfm80); + normalizeVector(vecOccFT0CUnfm80, meanOccPrimUnfm80 / meanOccFT0CUnfm80); + + // Find Robust estimators + // T0A, T0C, V0A, Prim + if constexpr (robustTableMode == fillOccRobustTable || meanRobustTableMode == fillOccMeanRobustTable) { + getMedianOccVect(vecRobustOccT0V0PrimUnfm80, vecRobustOccT0V0PrimUnfm80medianPosVec, + vecOccPrimUnfm80, vecOccFV0AUnfm80, vecOccFT0AUnfm80, vecOccFT0CUnfm80); + for (const auto& vec : vecRobustOccT0V0PrimUnfm80medianPosVec) { + recoEvent.fill(HIST("h_RO_T0V0PrimUnfm80"), vec[0]); + recoEvent.fill(HIST("h_RO_T0V0PrimUnfm80"), vec[1]); + } + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccT0V0Prim || processMode == kProcessOnlyOccFDDT0V0Prim) { + if constexpr (tableMode == fillOccTable) { + genOccsT0V0(vecOccFV0AUnfm80, vecOccFV0CUnfm80, vecOccFT0AUnfm80, vecOccFT0CUnfm80); + } + if constexpr (meanTableMode == fillMeanOccTable) { + genOccsMeanT0V0(meanOccFV0AUnfm80, meanOccFV0CUnfm80, meanOccFT0AUnfm80, meanOccFT0CUnfm80); + } + if constexpr (robustTableMode == fillOccRobustTable) { + genORT0V0Prim(vecRobustOccT0V0PrimUnfm80); + } + if constexpr (meanRobustTableMode == fillOccMeanRobustTable) { + genOccsMeanRobustT0V0Prim(TMath::Mean(vecRobustOccT0V0PrimUnfm80.size(), vecRobustOccT0V0PrimUnfm80.data())); + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccFDDT0V0Prim) { + auto& vecOccFDDAUnfm80 = occFDDAUnfm80[i]; + auto& vecOccFDDCUnfm80 = occFDDCUnfm80[i]; + float meanOccFDDAUnfm80 = TMath::Mean(vecOccFDDAUnfm80.size(), vecOccFDDAUnfm80.data()); + float meanOccFDDCUnfm80 = TMath::Mean(vecOccFDDCUnfm80.size(), vecOccFDDCUnfm80.data()); + normalizeVector(vecOccFDDAUnfm80, meanOccPrimUnfm80 / meanOccFDDAUnfm80); + normalizeVector(vecOccFDDCUnfm80, meanOccPrimUnfm80 / meanOccFDDCUnfm80); + + // T0A, T0C, V0A, FDD, Prim + if constexpr (robustTableMode == fillOccRobustTable || meanRobustTableMode == fillOccMeanRobustTable) { + getMedianOccVect(vecRobustOccFDDT0V0PrimUnfm80, vecRobustOccFDDT0V0PrimUnfm80medianPosVec, + vecOccPrimUnfm80, vecOccFV0AUnfm80, vecOccFT0AUnfm80, vecOccFT0CUnfm80, vecOccFDDAUnfm80, vecOccFDDCUnfm80); + for (const auto& vec : vecRobustOccFDDT0V0PrimUnfm80medianPosVec) { + recoEvent.fill(HIST("h_RO_FDDT0V0PrimUnfm80"), vec[0]); + recoEvent.fill(HIST("h_RO_FDDT0V0PrimUnfm80"), vec[1]); + } + + if constexpr (tableMode == fillOccTable) { + genOccsFDD(vecOccFDDAUnfm80, vecOccFDDCUnfm80); + } + if constexpr (meanTableMode == fillMeanOccTable) { + genOccsMeanFDD(meanOccFDDAUnfm80, meanOccFDDCUnfm80); + } + if constexpr (robustTableMode == fillOccRobustTable) { + genORFDDT0V0Prim(vecRobustOccFDDT0V0PrimUnfm80); + } + if constexpr (meanRobustTableMode == fillOccMeanRobustTable) { + genOccsMeanRobustFDDT0V0Prim(TMath::Mean(vecRobustOccFDDT0V0PrimUnfm80.size(), vecRobustOccFDDT0V0PrimUnfm80.data())); + } + } + } // Block for FDDT0V0Prim + } // For T0V0Prim only and FDDT0V0Prim + } // Detector Occupancy block + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet) { + // NTrackDet + 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]; + 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()); + + 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); + + if constexpr (robustTableMode == fillOccRobustTable || meanRobustTableMode == fillOccMeanRobustTable) { + getMedianOccVect(vecRobustOccNtrackDetUnfm80, vecRobustOccNtrackDetUnfm80medianPosVec, + vecOccNTrackITSUnfm80, vecOccNTrackTPCUnfm80, vecOccNTrackTRDUnfm80, vecOccNTrackTOFUnfm80); + for (const auto& vec : vecRobustOccNtrackDetUnfm80medianPosVec) { + recoEvent.fill(HIST("h_RO_NtrackDetUnfm80"), vec[0]); + recoEvent.fill(HIST("h_RO_NtrackDetUnfm80"), vec[1]); + } + } + + if constexpr (tableMode == fillOccTable) { + genOccsNTrackDet(vecOccNTrackITSUnfm80, vecOccNTrackTPCUnfm80, + vecOccNTrackTRDUnfm80, vecOccNTrackTOFUnfm80, + vecOccNTrackSizeUnfm80, vecOccNTrackTPCAUnfm80, + vecOccNTrackTPCCUnfm80, vecOccNTrackITSTPCUnfm80, + vecOccNTrackITSTPCAUnfm80, vecOccNTrackITSTPCCUnfm80); + } + if constexpr (meanTableMode == fillMeanOccTable) { + genOccsMeanNTrkDet(meanOccNTrackITSUnfm80, meanOccNTrackTPCUnfm80, + meanOccNTrackTRDUnfm80, meanOccNTrackTOFUnfm80, + meanOccNTrackSizeUnfm80, meanOccNTrackTPCAUnfm80, + meanOccNTrackTPCCUnfm80, meanOccNTrackITSTPCUnfm80, + meanOccNTrackITSTPCAUnfm80, meanOccNTrackITSTPCCUnfm80); + } + if constexpr (robustTableMode == fillOccRobustTable) { + genORNtrackDet(vecRobustOccNtrackDetUnfm80); + } + if constexpr (meanRobustTableMode == fillOccMeanRobustTable) { + genOccsMeanRobustNtrackDet(TMath::Mean(vecRobustOccNtrackDetUnfm80.size(), vecRobustOccNtrackDetUnfm80.data())); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccMultExtra) { + auto& vecOccNTrackITSTPCUnfm80 = occNTrackITSTPCUnfm80[i]; + float meanOccNTrackITSTPCUnfm80 = TMath::Mean(vecOccNTrackITSTPCUnfm80.size(), vecOccNTrackITSTPCUnfm80.data()); + normalizeVector(vecOccNTrackITSTPCUnfm80, meanOccPrimUnfm80 / meanOccNTrackITSTPCUnfm80); + + 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 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()); + // multExtraTable + 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); + + if constexpr (robustTableMode == fillOccRobustTable || meanRobustTableMode == fillOccMeanRobustTable) { + getMedianOccVect(vecRobustOccmultTableUnfm80, vecRobustOccmultTableUnfm80medianPosVec, + vecOccPrimUnfm80, vecOccMultNTracksHasITSUnfm80, vecOccMultNTracksHasTPCUnfm80, + vecOccMultNTracksHasTOFUnfm80, vecOccMultNTracksHasTRDUnfm80, vecOccMultNTracksITSOnlyUnfm80, + vecOccMultNTracksTPCOnlyUnfm80, vecOccMultNTracksITSTPCUnfm80, vecOccMultAllTracksTPCOnlyUnfm80, + vecOccNTrackITSTPCUnfm80); + for (const auto& vec : vecRobustOccmultTableUnfm80medianPosVec) { + recoEvent.fill(HIST("h_RO_multTableUnfm80"), vec[0]); + recoEvent.fill(HIST("h_RO_multTableUnfm80"), vec[1]); + } + } + + if constexpr (tableMode == fillOccTable) { + genOccsMultExtra(vecOccMultNTracksHasITSUnfm80, vecOccMultNTracksHasTPCUnfm80, + vecOccMultNTracksHasTOFUnfm80, vecOccMultNTracksHasTRDUnfm80, + vecOccMultNTracksITSOnlyUnfm80, vecOccMultNTracksTPCOnlyUnfm80, + vecOccMultNTracksITSTPCUnfm80, vecOccMultAllTracksTPCOnlyUnfm80); + } + if constexpr (meanTableMode == fillMeanOccTable) { + genOccsMnMultExtra(meanOccMultNTracksHasITSUnfm80, meanOccMultNTracksHasTPCUnfm80, + meanOccMultNTracksHasTOFUnfm80, meanOccMultNTracksHasTRDUnfm80, + meanOccMultNTracksITSOnlyUnfm80, meanOccMultNTracksTPCOnlyUnfm80, + meanOccMultNTracksITSTPCUnfm80, meanOccMultAllTracksTPCOnlyUnfm80); + } + if constexpr (robustTableMode == fillOccRobustTable) { + genORMultExtra(vecRobustOccmultTableUnfm80); + } + if constexpr (meanRobustTableMode == fillOccMeanRobustTable) { + genOccsMeanRobustMultExtraTable(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 + } + + genBCTFinfoTable(tfIdThis, bcInTF); + genOccIndexTable(bc.globalIndex(), occIDX); // BCId, OccId + } + } // else block for constexpr + } + + void checkAllProcessFunctionStatus(std::vector const& processStatusVector, bool& singleProcessOn) + { + int nProcessOn = 0; + const uint size = processStatusVector.size(); + for (uint i = 0; i < size; i++) { + if (processStatusVector[i]) { + nProcessOn++; + } + } + + if (nProcessOn > 1) { + singleProcessOn = false; + std::ostringstream warningLine; + warningLine << "DEBUG :: More than one track-mean-occ-table-producer process function is on :: "; + for (uint i = 0; i < size; i++) { + if (processStatusVector[i]) { + warningLine << std::string(ProcessNames[processStatusVector[i]]) << " == true :: "; + } + } + LOG(error) << warningLine.str(); + } // check nProcess + } + + //________________________________________End of Exection Function_________________________________________________________________________ + + void processOnlyBCTFinfoTable(o2::aod::BCsWithTimestamps const& BCs) + { + occupancyQA.fill(HIST("h_DFcount_Lvl0"), 0.5); + processStatus[kProcessOnlyBCTFinfoTable] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (!singleProcessOn) { + return; + } + + for (const auto& BC : BCs) { + getTimingInfo(BC, lastRun, nBCsPerTF, bcSOR, time, tfIdThis, bcInTF); + genBCTFinfoTable(tfIdThis, bcInTF); + } + occupancyQA.fill(HIST("h_DFcount_Lvl1"), 0.5); + } + PROCESS_SWITCH(OccupancyTableProducer, processOnlyBCTFinfoTable, "processOnlyBCTFinfoTable", true); + + // // Process the Data + void processOnlyOccPrimUnfm(o2::aod::BCsWithTimestamps const& BCs, aod::Collisions const& collisions) + { + occupancyQA.fill(HIST("h_DFcount_Lvl0"), 0.5); + if (!buildOnlyOccsPrim) { + LOG(error) << " DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsPrim == false"; + } + processStatus[kProcessOnlyOccPrim] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (!singleProcessOn) { + return; + } + + bool collisionsSizeIsZero = false; + executeCollisionCheckAndBCprocessing(BCs, collisions, collisionsSizeIsZero); + if (collisionsSizeIsZero) { + return; + } + executeOccProducerProcessing(BCs, collisions, nullptr); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), 0.5); + } + PROCESS_SWITCH(OccupancyTableProducer, processOnlyOccPrimUnfm, "processOnlyOccPrimUnfm", false); + + void processOnlyOccT0V0PrimUnfm(o2::aod::BCsWithTimestamps const& BCs, soa::Join const& collisions) + { + occupancyQA.fill(HIST("h_DFcount_Lvl0"), 0.5); + if (!buildOnlyOccsT0V0Prim) { + LOG(error) << " DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsT0V0Prim == false"; + } + processStatus[kProcessOnlyOccT0V0Prim] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (!singleProcessOn) { + return; + } + + bool collisionsSizeIsZero = false; + executeCollisionCheckAndBCprocessing(BCs, collisions, collisionsSizeIsZero); + if (collisionsSizeIsZero) { + return; + } + executeOccProducerProcessing(BCs, collisions, nullptr); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), 0.5); + } + PROCESS_SWITCH(OccupancyTableProducer, processOnlyOccT0V0PrimUnfm, "processOnlyOccT0V0PrimUnfm", false); + + void processOnlyOccFDDT0V0PrimUnfm(o2::aod::BCsWithTimestamps const& BCs, soa::Join const& collisions) + { + occupancyQA.fill(HIST("h_DFcount_Lvl0"), 0.5); + if (!buildOnlyOccsFDDT0V0Prim) { + LOG(error) << " DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsFDDT0V0Prim == false"; + } + processStatus[kProcessOnlyOccFDDT0V0Prim] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (!singleProcessOn) { + return; + } + + bool collisionsSizeIsZero = false; + executeCollisionCheckAndBCprocessing(BCs, collisions, collisionsSizeIsZero); + if (collisionsSizeIsZero) { + return; + } + executeOccProducerProcessing(BCs, collisions, nullptr); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), 0.5); + } + PROCESS_SWITCH(OccupancyTableProducer, processOnlyOccFDDT0V0PrimUnfm, "processOnlyOccFDDT0V0PrimUnfm", false); + + void processOnlyOccNtrackDet(o2::aod::BCsWithTimestamps const& BCs, soa::Join const& collisions, soa::Join const& tracks) + { + occupancyQA.fill(HIST("h_DFcount_Lvl0"), 0.5); + if (!buildOnlyOccsNtrackDet) { + LOG(error) << " DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsNtrackDet == false"; + } + processStatus[kProcessOnlyOccNtrackDet] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (!singleProcessOn) { + return; + } + + bool collisionsSizeIsZero = false; + executeCollisionCheckAndBCprocessing(BCs, collisions, collisionsSizeIsZero); + if (collisionsSizeIsZero) { + return; + } + executeOccProducerProcessing(BCs, collisions, tracks); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), 0.5); + } + PROCESS_SWITCH(OccupancyTableProducer, processOnlyOccNtrackDet, "processOnlyOccNtrackDet", false); + + void processOnlyOccMultExtra(o2::aod::BCsWithTimestamps const& BCs, soa::Join const& collisions) + { + occupancyQA.fill(HIST("h_DFcount_Lvl0"), 0.5); + if (!buildOnlyOccsMultExtra) { + LOG(error) << " DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsMultExtra == false"; + } + processStatus[kProcessOnlyOccMultExtra] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (!singleProcessOn) { + return; + } + + bool collisionsSizeIsZero = false; + executeCollisionCheckAndBCprocessing(BCs, collisions, collisionsSizeIsZero); + if (collisionsSizeIsZero) { + return; + } + executeOccProducerProcessing(BCs, collisions, nullptr); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), 0.5); + } + PROCESS_SWITCH(OccupancyTableProducer, processOnlyOccMultExtra, "processOnlyOccMultExtra", false); + + void processFullOccTableProduer(o2::aod::BCsWithTimestamps const& BCs, soa::Join const& collisions, soa::Join const& tracks) + { + occupancyQA.fill(HIST("h_DFcount_Lvl0"), 0.5); + if (!buildFullOccTableProducer) { + LOG(error) << " DEBUG :: ERROR ERROR ERROR :: buildFullOccTableProducer == false"; + } + processStatus[kProcessFullOccTableProducer] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (!singleProcessOn) { + return; + } + + bool collisionsSizeIsZero = false; + executeCollisionCheckAndBCprocessing(BCs, collisions, collisionsSizeIsZero); + if (collisionsSizeIsZero) { + return; + } + executeOccProducerProcessing(BCs, collisions, tracks); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), 0.5); + } // Process function ends + PROCESS_SWITCH(OccupancyTableProducer, processFullOccTableProduer, "processFullOccTableProduer", false); +}; + +struct TrackMeanOccTableProducer { + + // //declare production of tables + Produces genTmoTrackId; + Produces genTmoToTrackQA; + Produces genTrackQAToTmo; + + Produces genTmoPrim; + Produces genTmoT0V0; + Produces genTmoFDD; + Produces genTmoNTrackDet; + Produces genTmoMultExtra; + Produces genTmoRT0V0Prim; + Produces genTmoRFDDT0V0Prim; + Produces genTmoRNtrackDet; + Produces genTmoRMultExtra; + + Produces genTwmoPrim; + Produces genTwmoT0V0; + Produces genTwmoFDD; + Produces genTwmoNTrackDet; + Produces genTwmoMultExtra; + Produces genTwmoRT0V0Prim; + Produces genTwmoRFDDT0V0Pri; + Produces genTwmoRNtrackDet; + Produces genTwmoRMultExtra; + + Service ccdb; + + HistogramRegistry occupancyQA{"occupancyQA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurables + Configurable customOrbitOffset{"customOrbitOffset", 0, "customOrbitOffset for MC"}; + Configurable bcGrouping{"bcGrouping", 80, "bcGrouping of BCs"}; + Configurable nBCinTF{"nBCinTF", 114048, "nBCinTF"}; + + Configurable cfgNOrbitsPerTF0RunValue{"cfgNOrbitsPerTF0RunValue", 534133, "cfgNOrbitsPerTF0RunValue"}; + Configurable cfgNOrbitsPerTF1TrueValue{"cfgNOrbitsPerTF1TrueValue", 128, "cfgNOrbitsPerTF1TrueValue"}; + Configurable cfgNOrbitsPerTF2FalseValue{"cfgNOrbitsPerTF2FalseValue", 32, "ccfgNOrbitsPerTF2FalseValue"}; + + Configurable buildOnlyOccsPrim{"buildOnlyOccsPrim", true, "builder of table OccsPrim"}; + Configurable buildOnlyOccsT0V0{"buildOnlyOccsT0V0", true, "builder of table OccsT0V0Prim"}; + Configurable buildOnlyOccsFDD{"buildOnlyOccsFDD", true, "builder of table OccsFDDT0V0Prim"}; + Configurable buildOnlyOccsNtrackDet{"buildOnlyOccsNtrackDet", true, "builder of table OccsNtrackDet"}; + Configurable buildOnlyOccsMultExtra{"buildOnlyOccsMultExtra", true, "builder of table OccsMultExtra"}; + + Configurable buildOnlyOccsRobustT0V0Prim{"buildOnlyOccsRobustT0V0Prim", true, "build buildOnlyOccsRobustT0V0Prim"}; + Configurable buildOnlyOccsRobustFDDT0V0Prim{"buildOnlyOccsRobustFDDT0V0Prim", true, "build buildOnlyOccsRobustFDDT0V0Prim"}; + Configurable buildOnlyOccsRobustNtrackDet{"buildOnlyOccsRobustNtrackDet", true, "build buildOnlyOccsRobustNtrackDet"}; + Configurable buildOnlyOccsRobustMultExtra{"buildOnlyOccsRobustMultExtra", true, "build buildOnlyOccsRobustMultExtra"}; + + Configurable buildFullOccTableProducer{"buildFullOccTableProducer", true, "builder of all Occupancy Tables"}; + + Configurable buildFlag00MeanTable{"buildFlag00MeanTable", true, "build Flag00MeanTable"}; + Configurable buildFlag01WeightMeanTable{"buildFlag01WeightMeanTable", true, "build Flag01WeightMeanTable"}; + + Configurable fillQA1{"fillQA1", true, "fill QA LOG Ratios"}; + Configurable fillQA2{"fillQA2", true, "fill QA condition dependent QAs"}; + + Configurable buildPointerTrackQAToTMOTable{"buildPointerTrackQAToTMOTable", true, "buildPointerTrackQAToTMOTable"}; + Configurable buildPointerTMOToTrackQATable{"buildPointerTMOToTrackQATable", true, "buildPointerTMOToTrackQATable"}; + + // 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; + + std::vector processStatus; + std::vector processInThisBlock; + void init(InitContext const&) + { + // CCDB related part to be added later + processStatus.resize(11); + processInThisBlock.resize(11); + + for (uint i = 0; i < processStatus.size(); i++) { + processStatus[i] = false; + processInThisBlock[i] = false; + } + + if (buildFullOccTableProducer || buildOnlyOccsPrim) { + occPrimUnfm80.resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsT0V0) { + occFV0AUnfm80.resize(nBCinTF / bcGrouping); + occFV0CUnfm80.resize(nBCinTF / bcGrouping); + occFT0AUnfm80.resize(nBCinTF / bcGrouping); + occFT0CUnfm80.resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsFDD) { + occFDDAUnfm80.resize(nBCinTF / bcGrouping); + occFDDCUnfm80.resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsNtrackDet) { + occNTrackITSUnfm80.resize(nBCinTF / bcGrouping); + occNTrackTPCUnfm80.resize(nBCinTF / bcGrouping); + occNTrackTRDUnfm80.resize(nBCinTF / bcGrouping); + occNTrackTOFUnfm80.resize(nBCinTF / bcGrouping); + occNTrackSizeUnfm80.resize(nBCinTF / bcGrouping); + occNTrackTPCAUnfm80.resize(nBCinTF / bcGrouping); + occNTrackTPCCUnfm80.resize(nBCinTF / bcGrouping); + occNTrackITSTPCUnfm80.resize(nBCinTF / bcGrouping); + occNTrackITSTPCAUnfm80.resize(nBCinTF / bcGrouping); + occNTrackITSTPCCUnfm80.resize(nBCinTF / bcGrouping); + } + + if (buildFullOccTableProducer || buildOnlyOccsMultExtra) { + occMultNTracksHasITSUnfm80.resize(nBCinTF / bcGrouping); + occMultNTracksHasTPCUnfm80.resize(nBCinTF / bcGrouping); + occMultNTracksHasTOFUnfm80.resize(nBCinTF / bcGrouping); + occMultNTracksHasTRDUnfm80.resize(nBCinTF / bcGrouping); + occMultNTracksITSOnlyUnfm80.resize(nBCinTF / bcGrouping); + occMultNTracksTPCOnlyUnfm80.resize(nBCinTF / bcGrouping); + occMultNTracksITSTPCUnfm80.resize(nBCinTF / bcGrouping); + occMultAllTracksTPCOnlyUnfm80.resize(nBCinTF / bcGrouping); + } + + if (buildFullOccTableProducer || buildOnlyOccsRobustT0V0Prim || fillQA1 || fillQA2) { + occRobustT0V0PrimUnfm80.resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsRobustFDDT0V0Prim) { + occRobustFDDT0V0PrimUnfm80.resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsRobustNtrackDet) { + occRobustNtrackDetUnfm80.resize(nBCinTF / bcGrouping); + } + if (buildFullOccTableProducer || buildOnlyOccsRobustMultExtra) { + occRobustMultTableUnfm80.resize(nBCinTF / bcGrouping); + } + + 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.add("h_DFcount_Lvl0", "h_DFcount_Lvl0", kTH1F, {{13, -1, 12}}); + occupancyQA.add("h_DFcount_Lvl1", "h_DFcount_Lvl1", kTH1F, {{13, -1, 12}}); + occupancyQA.add("h_DFcount_Lvl2", "h_DFcount_Lvl2", kTH1F, {{13, -1, 12}}); + + 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 < cfgNOrbitsPerTF0RunValue ? cfgNOrbitsPerTF1TrueValue : cfgNOrbitsPerTF2FalseValue; + 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) { + int two = 2, twenty = 20, fifty = 50, twoHundred = 200; + if (std::abs(std::log(occValue / occRobustValue)) < two) { // 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) > twoHundred) { + 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) > fifty) { + 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) > twenty) { + 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 MyTracksQA = aod::TracksQAVersion; // using MyTracksQA = aod::TracksQA_002; + + // 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; + + enum ProcessTags { + kProcessNothing = 0, + kProcessOnlyOccPrim, + kProcessOnlyOccT0V0, + kProcessOnlyOccFDD, + kProcessOnlyOccNtrackDet, + kProcessOnlyOccMultExtra, + kProcessOnlyRobustT0V0Prim, + kProcessOnlyRobustFDDT0V0Prim, + kProcessOnlyRobustNtrackDet, + kProcessOnlyRobustMultExtra, + kProcessFullOccTableProducer + }; + + enum FillMode { + checkTableMode = 0, + checkQAMode, + doNotFill, + fillOccRobustT0V0dependentQA, + fillMeanOccTable, + fillWeightMeanOccTable + }; + + std::vector> trackQAGIListforTMOList; + template + void executeTrackOccProducerProcessing(B const& BCs, C const& collisions, T const& tracks, U const& tracksQA, O const& occsRobustT0V0Prim, V const& occs, bool const& executeInThisBlock) + { + if (collisions.size() == 0) { + return; + } + + if (meanTableMode == checkTableMode) { + if (buildFlag00MeanTable) { + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, executeInThisBlock); + } else { + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, executeInThisBlock); + } + } + if constexpr (meanTableMode == checkTableMode) { + return; + } + + if (weightMeanTableMode == checkTableMode) { + if (buildFlag01WeightMeanTable) { + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, executeInThisBlock); + } else { + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, executeInThisBlock); + } + } + if constexpr (weightMeanTableMode == checkTableMode) { + return; + } + + if (qaMode == checkQAMode) { + if (fillQA1 || fillQA2) { + if (occsRobustT0V0Prim.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsRobustT0V0Prim.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsT0V0Prim == true\" & \"processOnlyOccT0V0PrimUnfm == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, executeInThisBlock); + } else { + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, executeInThisBlock); + } + } + if constexpr (qaMode == checkQAMode) { + return; + } + + // BCs.bindExternalIndices(&occsDet); + // BCs.bindExternalIndices(&occsNTrackDet); + // BCs.bindExternalIndices(&occsRobust); + + if constexpr (meanTableMode == checkTableMode || weightMeanTableMode == checkTableMode || qaMode == checkQAMode) { + return; + } else { + occupancyQA.fill(HIST("h_DFcount_Lvl2"), processMode); + + auto bc = BCs.begin(); + + int64_t oldTFid = -1; + + int64_t oldCollisionIndex = -100; + bool hasCollision = false; + bool isAmbgTrack = false; + bool lastTrackHadCollision = false; + bool doCollisionUpdate = false; + bool doAmbgUpdate = false; + + double rBegin = 90., rEnd = 245.; + double zBegin; // collision.posZ() + track.tgl()*rBegin; + double zEnd; // collision.posZ() + track.tgl()*rEnd; + double vdrift = 2.64; + + double dTbegin; // ((250.- TMath::Abs(zBegin))/vdrift)/0.025;//bin + double dTend; // ((250.- TMath::Abs(zEnd))/vdrift)/0.025; //bin + + double bcBegin; // tGlobalBC + dTbegin; + double bcEnd; // tGlobalBC + dTend ; + + int binBCbegin; + int binBCend; + + float meanOccPrimUnfm80 = 0; + float meanOccFV0AUnfm80 = 0; + float meanOccFV0CUnfm80 = 0; + float meanOccFT0AUnfm80 = 0; + float meanOccFT0CUnfm80 = 0; + float meanOccFDDAUnfm80 = 0; + float meanOccFDDCUnfm80 = 0; + + float meanOccNTrackITSUnfm80 = 0; + float meanOccNTrackTPCUnfm80 = 0; + float meanOccNTrackTRDUnfm80 = 0; + float meanOccNTrackTOFUnfm80 = 0; + float meanOccNTrackSizeUnfm80 = 0; + float meanOccNTrackTPCAUnfm80 = 0; + float meanOccNTrackTPCCUnfm80 = 0; + float meanOccNTrackITSTPCUnfm80 = 0; + float meanOccNTrackITSTPCAUnfm80 = 0; + float meanOccNTrackITSTPCCUnfm80 = 0; + + float meanOccMultNTracksHasITSUnfm80 = 0; + float meanOccMultNTracksHasTPCUnfm80 = 0; + float meanOccMultNTracksHasTOFUnfm80 = 0; + float meanOccMultNTracksHasTRDUnfm80 = 0; + float meanOccMultNTracksITSOnlyUnfm80 = 0; + float meanOccMultNTracksTPCOnlyUnfm80 = 0; + float meanOccMultNTracksITSTPCUnfm80 = 0; + float meanOccMultAllTracksTPCOnlyUnfm80 = 0; + + float meanOccRobustT0V0PrimUnfm80 = 0; + float meanOccRobustFDDT0V0PrimUnfm80 = 0; + float meanOccRobustNtrackDetUnfm80 = 0; + float meanOccRobustMultTableUnfm80 = 0; + + float weightMeanOccPrimUnfm80 = 0; + float weightMeanOccFV0AUnfm80 = 0; + float weightMeanOccFV0CUnfm80 = 0; + float weightMeanOccFT0AUnfm80 = 0; + float weightMeanOccFT0CUnfm80 = 0; + float weightMeanOccFDDAUnfm80 = 0; + float weightMeanOccFDDCUnfm80 = 0; + + float weightMeanOccNTrackITSUnfm80 = 0; + float weightMeanOccNTrackTPCUnfm80 = 0; + float weightMeanOccNTrackTRDUnfm80 = 0; + float weightMeanOccNTrackTOFUnfm80 = 0; + float weightMeanOccNTrackSizeUnfm80 = 0; + float weightMeanOccNTrackTPCAUnfm80 = 0; + float weightMeanOccNTrackTPCCUnfm80 = 0; + float weightMeanOccNTrackITSTPCUnfm80 = 0; + float weightMeanOccNTrackITSTPCAUnfm80 = 0; + float weightMeanOccNTrackITSTPCCUnfm80 = 0; + + float weightMeanOccMultNTracksHasITSUnfm80 = 0; + float weightMeanOccMultNTracksHasTPCUnfm80 = 0; + float weightMeanOccMultNTracksHasTOFUnfm80 = 0; + float weightMeanOccMultNTracksHasTRDUnfm80 = 0; + float weightMeanOccMultNTracksITSOnlyUnfm80 = 0; + float weightMeanOccMultNTracksTPCOnlyUnfm80 = 0; + float weightMeanOccMultNTracksITSTPCUnfm80 = 0; + float weightMeanOccMultAllTracksTPCOnlyUnfm80 = 0; + + float weightMeanOccRobustT0V0PrimUnfm80 = 0; + float weightMeanOccRobustFDDT0V0PrimUnfm80 = 0; + float weightMeanOccRobustNtrackDetUnfm80 = 0; + float weightMeanOccRobustMultTableUnfm80 = 0; + + int trackTMOcounter = -1; + trackQAGIListforTMOList.clear(); + + for (const auto& trackQA : tracksQA) { + auto const& track = trackQA.template track_as(); + auto collision = collisions.begin(); + + hasCollision = false; + isAmbgTrack = false; + + if (track.collisionId() >= 0) { // track has collision + collision = track.template collision_as(); // It will build but crash while running for tracks with track.collisionId()= -1;//ambg tracks/orphan tracks + if (track.collisionId() != collision.globalIndex()) { + LOG(error) << "DEBUG :: ERROR :: track collId and collID Mismatch"; + } + hasCollision = true; + } else { // track is ambiguous/orphan + isAmbgTrack = true; + } + + // Checking out of the range errors + if (trackQA.trackId() < 0 || tracks.size() <= trackQA.trackId()) { + LOG(error) << "DEBUG :: ERROR :: trackQA has index out of scope :: trackQA.trackId() = " << trackQA.trackId() << " :: track.collisionId() = " << track.collisionId() << " :: track.signed1Pt() = " << track.signed1Pt(); + } + if (!hasCollision && !isAmbgTrack) { + LOG(error) << "DEBUG :: ERROR :: A track with no collsiion and is not Ambiguous"; + } + if (hasCollision && isAmbgTrack) { + LOG(error) << "DEBUG :: ERROR :: A track has collision and is also ambiguous"; + } + + if (hasCollision) { + lastTrackHadCollision = true; + } + doCollisionUpdate = false; // default is false; + doAmbgUpdate = false; + if (hasCollision) { + if (lastTrackHadCollision) { + if (collision.globalIndex() == oldCollisionIndex) { // if collisions are same + doCollisionUpdate = false; + } else { // if collisions are different + doCollisionUpdate = true; + } + } else { // LastTrackWasAmbiguous + doCollisionUpdate = true; + } + } else if (isAmbgTrack) { + doAmbgUpdate = true; + // To be updated later + // if(LastTrackIsAmbg){ + // if( haveSameInfo ) { doAmbgUpdate = false;} + // else { doAmbgUpdate = true; } + // } + // else { doAmbgUpdate = true;} //Last track had Collisions + } + + if (doAmbgUpdate) { // sKipping ambiguous tracks for now, will be updated in future + continue; + } + if (doCollisionUpdate || doAmbgUpdate) { // collision.globalIndex() != oldCollisionIndex){ //don't update if info is same as old collision + if (doCollisionUpdate) { + oldCollisionIndex = collision.globalIndex(); + bc = collision.template bc_as(); + } + 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 occsList = occs.iteratorAt(bc.occId()); + + if constexpr (qaMode == fillOccRobustT0V0dependentQA) { + std::copy(occsRobustT0V0Prim.iteratorAt(bc.occId()).occRobustT0V0PrimUnfm80().begin(), occsRobustT0V0Prim.iteratorAt(bc.occId()).occRobustT0V0PrimUnfm80().end(), occRobustT0V0PrimUnfm80.begin()); + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccPrim) { + std::copy(occsList.occPrimUnfm80().begin(), occsList.occPrimUnfm80().end(), occPrimUnfm80.begin()); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccT0V0) { + std::copy(occsList.occFV0AUnfm80().begin(), occsList.occFV0AUnfm80().end(), occFV0AUnfm80.begin()); + std::copy(occsList.occFV0CUnfm80().begin(), occsList.occFV0CUnfm80().end(), occFV0CUnfm80.begin()); + std::copy(occsList.occFT0AUnfm80().begin(), occsList.occFT0AUnfm80().end(), occFT0AUnfm80.begin()); + std::copy(occsList.occFT0CUnfm80().begin(), occsList.occFT0CUnfm80().end(), occFT0CUnfm80.begin()); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccFDD) { + std::copy(occsList.occFDDAUnfm80().begin(), occsList.occFDDAUnfm80().end(), occFDDAUnfm80.begin()); + std::copy(occsList.occFDDCUnfm80().begin(), occsList.occFDDCUnfm80().end(), occFDDCUnfm80.begin()); + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet) { + std::copy(occsList.occNTrackITSUnfm80().begin(), occsList.occNTrackITSUnfm80().end(), occNTrackITSUnfm80.begin()); + std::copy(occsList.occNTrackTPCUnfm80().begin(), occsList.occNTrackTPCUnfm80().end(), occNTrackTPCUnfm80.begin()); + std::copy(occsList.occNTrackTRDUnfm80().begin(), occsList.occNTrackTRDUnfm80().end(), occNTrackTRDUnfm80.begin()); + std::copy(occsList.occNTrackTOFUnfm80().begin(), occsList.occNTrackTOFUnfm80().end(), occNTrackTOFUnfm80.begin()); + std::copy(occsList.occNTrackSizeUnfm80().begin(), occsList.occNTrackSizeUnfm80().end(), occNTrackSizeUnfm80.begin()); + std::copy(occsList.occNTrackTPCAUnfm80().begin(), occsList.occNTrackTPCAUnfm80().end(), occNTrackTPCAUnfm80.begin()); + std::copy(occsList.occNTrackTPCCUnfm80().begin(), occsList.occNTrackTPCCUnfm80().end(), occNTrackTPCCUnfm80.begin()); + std::copy(occsList.occNTrackITSTPCUnfm80().begin(), occsList.occNTrackITSTPCUnfm80().end(), occNTrackITSTPCUnfm80.begin()); + std::copy(occsList.occNTrackITSTPCAUnfm80().begin(), occsList.occNTrackITSTPCAUnfm80().end(), occNTrackITSTPCAUnfm80.begin()); + std::copy(occsList.occNTrackITSTPCCUnfm80().begin(), occsList.occNTrackITSTPCCUnfm80().end(), occNTrackITSTPCCUnfm80.begin()); + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccMultExtra) { + std::copy(occsList.occMultNTracksHasITSUnfm80().begin(), occsList.occMultNTracksHasITSUnfm80().end(), occMultNTracksHasITSUnfm80.begin()); + std::copy(occsList.occMultNTracksHasTPCUnfm80().begin(), occsList.occMultNTracksHasTPCUnfm80().end(), occMultNTracksHasTPCUnfm80.begin()); + std::copy(occsList.occMultNTracksHasTOFUnfm80().begin(), occsList.occMultNTracksHasTOFUnfm80().end(), occMultNTracksHasTOFUnfm80.begin()); + std::copy(occsList.occMultNTracksHasTRDUnfm80().begin(), occsList.occMultNTracksHasTRDUnfm80().end(), occMultNTracksHasTRDUnfm80.begin()); + std::copy(occsList.occMultNTracksITSOnlyUnfm80().begin(), occsList.occMultNTracksITSOnlyUnfm80().end(), occMultNTracksITSOnlyUnfm80.begin()); + std::copy(occsList.occMultNTracksTPCOnlyUnfm80().begin(), occsList.occMultNTracksTPCOnlyUnfm80().end(), occMultNTracksTPCOnlyUnfm80.begin()); + std::copy(occsList.occMultNTracksITSTPCUnfm80().begin(), occsList.occMultNTracksITSTPCUnfm80().end(), occMultNTracksITSTPCUnfm80.begin()); + std::copy(occsList.occMultAllTracksTPCOnlyUnfm80().begin(), occsList.occMultAllTracksTPCOnlyUnfm80().end(), occMultAllTracksTPCOnlyUnfm80.begin()); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyRobustT0V0Prim) { + std::copy(occsList.occRobustT0V0PrimUnfm80().begin(), occsList.occRobustT0V0PrimUnfm80().end(), occRobustT0V0PrimUnfm80.begin()); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyRobustFDDT0V0Prim) { + std::copy(occsList.occRobustFDDT0V0PrimUnfm80().begin(), occsList.occRobustFDDT0V0PrimUnfm80().end(), occRobustFDDT0V0PrimUnfm80.begin()); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyRobustNtrackDet) { + std::copy(occsList.occRobustNtrackDetUnfm80().begin(), occsList.occRobustNtrackDetUnfm80().end(), occRobustNtrackDetUnfm80.begin()); + } + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyRobustMultExtra) { + std::copy(occsList.occRobustMultExtraTableUnfm80().begin(), occsList.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 + float length = 250.0; + // clip the result at 250 + if (zBegin > length) { + zBegin = 250; + } else if (zBegin < -length) { + zBegin = -250; + } + + if (zEnd > length) { + zEnd = 250; + } else if (zEnd < -length) { + zEnd = -250; + } + + dTbegin = ((length - std::abs(zBegin)) / vdrift) / 0.025; + dTend = ((length - std::abs(zEnd)) / vdrift) / 0.025; + + bcBegin = bcInTF + dTbegin; + bcEnd = bcInTF + dTend; + + binBCbegin = bcBegin / 80; + binBCend = bcEnd / 80; + + // If multiple process are on, fill this table only once + if (executeInThisBlock) { + trackTMOcounter++; + genTmoTrackId(track.globalIndex()); + trackQAGIListforTMOList.push_back({trackQA.globalIndex(), trackTMOcounter}); + } + + if constexpr (qaMode == fillOccRobustT0V0dependentQA) { + if constexpr (meanTableMode == fillMeanOccTable) { + meanOccRobustT0V0PrimUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustT0V0PrimUnfm80); + } + if constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + weightMeanOccRobustT0V0PrimUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustT0V0PrimUnfm80); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccPrim) { + if constexpr (meanTableMode == fillMeanOccTable) { + meanOccPrimUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occPrimUnfm80); + genTmoPrim(meanOccPrimUnfm80); + fillQAInfo(meanOccPrimUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + weightMeanOccPrimUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occPrimUnfm80); + genTwmoPrim(weightMeanOccPrimUnfm80); + fillQAInfo(weightMeanOccPrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccPrimUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccT0V0) { + if constexpr (meanTableMode == fillMeanOccTable) { + meanOccFV0AUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFV0AUnfm80); + meanOccFV0CUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFV0CUnfm80); + meanOccFT0AUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFT0AUnfm80); + meanOccFT0CUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFT0CUnfm80); + genTmoT0V0(meanOccFV0AUnfm80, + meanOccFV0CUnfm80, + meanOccFT0AUnfm80, + meanOccFT0CUnfm80); + fillQAInfo(meanOccFV0AUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFV0CUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFT0AUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFT0CUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + weightMeanOccFV0AUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFV0AUnfm80); + weightMeanOccFV0CUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFV0CUnfm80); + weightMeanOccFT0AUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFT0AUnfm80); + weightMeanOccFT0CUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFT0CUnfm80); + genTwmoT0V0(weightMeanOccFV0AUnfm80, + weightMeanOccFV0CUnfm80, + weightMeanOccFT0AUnfm80, + weightMeanOccFT0CUnfm80); + fillQAInfo(weightMeanOccFV0AUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFV0CUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFT0AUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFT0CUnfm80, meanOccRobustT0V0PrimUnfm80); + + fillQAInfo(weightMeanOccFV0AUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFV0CUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFT0AUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFT0CUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccFDD) { + if constexpr (meanTableMode == fillMeanOccTable) { + meanOccFDDAUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFDDAUnfm80); + meanOccFDDCUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occFDDCUnfm80); + genTmoFDD(meanOccFDDAUnfm80, + meanOccFDDCUnfm80); + fillQAInfo(meanOccFDDAUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccFDDCUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + weightMeanOccFDDAUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFDDAUnfm80); + weightMeanOccFDDCUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occFDDCUnfm80); + genTwmoFDD(weightMeanOccFDDAUnfm80, + weightMeanOccFDDCUnfm80); + fillQAInfo(weightMeanOccFDDAUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFDDCUnfm80, meanOccRobustT0V0PrimUnfm80); + + fillQAInfo(weightMeanOccFDDAUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccFDDCUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccNtrackDet) { + if constexpr (meanTableMode == fillMeanOccTable) { + 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); + genTmoNTrackDet(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 constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + 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); + + genTwmoNTrackDet(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 constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyOccMultExtra) { + if constexpr (meanTableMode == fillMeanOccTable) { + 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); + genTmoMultExtra(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 constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + 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); + + genTwmoMultExtra(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 constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyRobustT0V0Prim) { + if constexpr (meanTableMode == fillMeanOccTable) { + meanOccRobustT0V0PrimUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustT0V0PrimUnfm80); + genTmoRT0V0Prim(meanOccRobustT0V0PrimUnfm80); + fillQAInfo(meanOccRobustT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + weightMeanOccRobustT0V0PrimUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustT0V0PrimUnfm80); + genTwmoRT0V0Prim(weightMeanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustT0V0PrimUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyRobustFDDT0V0Prim) { + if constexpr (meanTableMode == fillMeanOccTable) { + meanOccRobustFDDT0V0PrimUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustFDDT0V0PrimUnfm80); + genTmoRFDDT0V0Prim(meanOccRobustFDDT0V0PrimUnfm80); + fillQAInfo(meanOccRobustFDDT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + weightMeanOccRobustFDDT0V0PrimUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustFDDT0V0PrimUnfm80); + genTwmoRFDDT0V0Pri(weightMeanOccRobustFDDT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustFDDT0V0PrimUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustFDDT0V0PrimUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyRobustNtrackDet) { + if constexpr (meanTableMode == fillMeanOccTable) { + meanOccRobustNtrackDetUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustNtrackDetUnfm80); + genTmoRNtrackDet(meanOccRobustNtrackDetUnfm80); + fillQAInfo(meanOccRobustNtrackDetUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + weightMeanOccRobustNtrackDetUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustNtrackDetUnfm80); + genTwmoRNtrackDet(weightMeanOccRobustNtrackDetUnfm80); + fillQAInfo(weightMeanOccRobustNtrackDetUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustNtrackDetUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + } + + if constexpr (processMode == kProcessFullOccTableProducer || processMode == kProcessOnlyRobustMultExtra) { + if constexpr (meanTableMode == fillMeanOccTable) { + meanOccRobustMultTableUnfm80 = getMeanOccupancy(binBCbegin, binBCend, occRobustMultTableUnfm80); + genTmoRMultExtra(meanOccRobustMultTableUnfm80); + fillQAInfo(meanOccRobustMultTableUnfm80, meanOccRobustT0V0PrimUnfm80); + } + if constexpr (weightMeanTableMode == fillWeightMeanOccTable) { + weightMeanOccRobustMultTableUnfm80 = getWeightedMeanOccupancy(binBCbegin, binBCend, occRobustMultTableUnfm80); + genTwmoRMultExtra(weightMeanOccRobustMultTableUnfm80); + fillQAInfo(weightMeanOccRobustMultTableUnfm80, meanOccRobustT0V0PrimUnfm80); + fillQAInfo(weightMeanOccRobustMultTableUnfm80, weightMeanOccRobustT0V0PrimUnfm80); + } + } + } // end of trackQA loop + + // build the IndexTables here + if (executeInThisBlock) { + if (buildPointerTrackQAToTMOTable) { + // create pointer table from trackQA to TrackMeanOcc + sortVectorOfArray(trackQAGIListforTMOList, 0); // sort the list //Its easy to search in a sorted list + checkUniqueness(trackQAGIListforTMOList, 0); // check the uniqueness of track.globalIndex() + + int currentIDXforCheck = 0; + int listSize = trackQAGIListforTMOList.size(); + for (const auto& trackQA : tracksQA) { + while (trackQA.globalIndex() > trackQAGIListforTMOList[currentIDXforCheck][0]) { + currentIDXforCheck++; // increment the currentIDXforCheck for missing or invalid cases e.g. value = -1; + if (currentIDXforCheck >= listSize) { + break; + } + } + if (trackQA.globalIndex() == trackQAGIListforTMOList[currentIDXforCheck][0]) { + genTrackQAToTmo(trackQAGIListforTMOList[currentIDXforCheck][1]); + } else { + genTrackQAToTmo(-1); // put a dummy index when track is not found in trackQA + } + } + } + if (buildPointerTMOToTrackQATable) { + // create pointer table from TrackMeanOcc to trackQA + sortVectorOfArray(trackQAGIListforTMOList, 1); // sort the list //Its easy to search in a sorted list + checkUniqueness(trackQAGIListforTMOList, 1); // check the uniqueness of track.globalIndex() + + int currentIDXforCheck = 0; + int listSize = trackQAGIListforTMOList.size(); + for (int iCounter = 0; iCounter <= trackTMOcounter; iCounter++) { + while (iCounter > trackQAGIListforTMOList[currentIDXforCheck][1]) { + currentIDXforCheck++; // increment the currentIDXforCheck for missing or invalid cases e.g. value = -1; + if (currentIDXforCheck >= listSize) { + break; + } + } + if (iCounter == trackQAGIListforTMOList[currentIDXforCheck][1]) { + genTmoToTrackQA(trackQAGIListforTMOList[currentIDXforCheck][0]); + } else { + genTmoToTrackQA(-1); // put a dummy index when track is not found in trackQA + } + } + } + } // end of executeInThisBlock + } // end of else block of constexpr + } + + void checkAllProcessFunctionStatus(std::vector const& processStatusVector, bool& singleProcessOn) + { + int nProcessOn = 0; + const uint size = processStatusVector.size(); + for (uint i = 0; i < size; i++) { + if (processStatusVector[i]) { + nProcessOn++; + } + } + if (nProcessOn > 1) { + singleProcessOn = false; + } // check nProcess + } + + //_________________________________Process Functions start from here______________________________________________________________________________________ + void processNothing(aod::Collisions const&) + { + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessNothing); + return; + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessNothing); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processNothing, "process Nothing From Track Mean Occ Table Producer", true); + + void processOnlyOccPrim(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, aod::OccsPrim const& occs) + { + processStatus[kProcessOnlyOccPrim] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyOccPrim] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyOccPrim); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsPrim && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsPrim == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsPrim.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsPrim == true\" & \"processOnlyOccPrimUnfm == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessOnlyOccPrim]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyOccPrim); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyOccPrim, "processOnlyOccPrim", false); + + void processOnlyOccT0V0(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, aod::OccsT0V0 const& occs) + { + processStatus[kProcessOnlyOccT0V0] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyOccT0V0] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyOccT0V0); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsT0V0 && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsT0V0 == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsT0V0.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsT0V0Prim == true\" & \"processOnlyOccT0V0PrimUnfm == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessOnlyOccT0V0]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyOccT0V0); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyOccT0V0, "processOnlyOccT0V0", false); + + void processOnlyOccFDD(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, aod::OccsFDD const& occs) + { + processStatus[kProcessOnlyOccFDD] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyOccFDD] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyOccFDD); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsFDD && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsFDD == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsFDD.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsFDDT0V0Prim == true\" & \"processOnlyOccFDDT0V0PrimUnfm == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessOnlyOccFDD]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyOccFDD); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyOccFDD, "processOnlyOccFDD", false); + + void processOnlyOccNtrackDet(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, aod::OccsNTrackDet const& occs) + { + processStatus[kProcessOnlyOccNtrackDet] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyOccNtrackDet] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyOccNtrackDet); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsNtrackDet && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsNtrackDet == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsNtrackDet.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsNtrackDet == true\" & \"processOnlyOccNtrackDet == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessOnlyOccNtrackDet]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyOccNtrackDet); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyOccNtrackDet, "processOnlyOccNtrackDet", false); + + void processOnlyOccMultExtra(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, aod::OccsMultExtra const& occs) + { + processStatus[kProcessOnlyOccMultExtra] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyOccMultExtra] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyOccMultExtra); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsMultExtra && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsMultExtra == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsMultExtra.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsMultExtra == true\" & \"processOnlyOccMultExtra == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessOnlyOccMultExtra]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyOccMultExtra); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyOccMultExtra, "processOnlyOccMultExtra", false); + + void processOnlyRobustT0V0Prim(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim) + { + processStatus[kProcessOnlyRobustT0V0Prim] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyRobustT0V0Prim] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyRobustT0V0Prim); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsRobustT0V0Prim && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsRobustT0V0Prim == false"; + return; + } + if (occsRobustT0V0Prim.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsRobustT0V0Prim.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsT0V0Prim == true\" & \"processOnlyOccT0V0PrimUnfm == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occsRobustT0V0Prim, processInThisBlock[kProcessOnlyRobustT0V0Prim]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyRobustT0V0Prim); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyRobustT0V0Prim, "processOnlyRobustT0V0Prim", false); + + void processOnlyRobustFDDT0V0Prim(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, aod::ORFDDT0V0Prim const& occs) + { + processStatus[kProcessOnlyRobustFDDT0V0Prim] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyRobustFDDT0V0Prim] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyRobustFDDT0V0Prim); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsRobustFDDT0V0Prim && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsRobustFDDT0V0Prim == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsRobustFDDT0V0Prim.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsFDDT0V0Prim == true\" & \"processOnlyOccFDDT0V0PrimUnfm == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessOnlyRobustFDDT0V0Prim]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyRobustFDDT0V0Prim); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyRobustFDDT0V0Prim, "processOnlyRobustFDDT0V0Prim", false); + + void processOnlyRobustNtrackDet(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, aod::ORNtrackDet const& occs) + { + processStatus[kProcessOnlyRobustNtrackDet] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyRobustNtrackDet] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyRobustNtrackDet); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsRobustNtrackDet && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsRobustNtrackDet == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsRobustNtrackDet.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsNtrackDet == true\" & \"processOnlyOccNtrackDet == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessOnlyRobustNtrackDet]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyRobustNtrackDet); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyRobustNtrackDet, "processOnlyRobustNtrackDet", false); + + void processOnlyRobustMultExtra(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, aod::ORMultExtra const& occs) + { + processStatus[kProcessOnlyRobustMultExtra] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessOnlyRobustMultExtra] = true; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessOnlyRobustMultExtra); + if (collisions.size() == 0) { + return; + } + if (!buildOnlyOccsRobustMultExtra && !buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildOnlyOccsRobustMultExtra == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: OccsRobustMultExtra.size() == 0 :: Check \"occupancy-table-producer\" for \"buildOnlyOccsMultExtra == true\" & \"processOnlyOccMultExtra == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessOnlyRobustMultExtra]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessOnlyRobustMultExtra); + } + PROCESS_SWITCH(TrackMeanOccTableProducer, processOnlyRobustMultExtra, "processOnlyRobustMultExtra", false); + + using JoinedOccTables = soa::Join; + void processFullOccTableProduer(soa::Join const& BCs, aod::Collisions const& collisions, aod::Tracks const& tracks, MyTracksQA const& tracksQA, aod::ORT0V0Prim const& occsRobustT0V0Prim, JoinedOccTables const& occs) + { + processStatus[kProcessFullOccTableProducer] = true; + bool singleProcessOn = true; + checkAllProcessFunctionStatus(processStatus, singleProcessOn); + if (singleProcessOn) { + processInThisBlock[kProcessFullOccTableProducer] = true; + } + if (!singleProcessOn) { + LOG(error) << "More than one process functions are on in track-mean-occ-table-producer"; + return; + } + occupancyQA.fill(HIST("h_DFcount_Lvl0"), kProcessFullOccTableProducer); + if (collisions.size() == 0) { + return; + } + if (!buildFullOccTableProducer) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: buildFullOccTableProducer == false"; + return; + } + if (occs.size() == 0) { + LOG(error) << "DEBUG :: ERROR ERROR ERROR :: Full Occ Table Join size is 0 :: Check \"occupancy-table-producer\" for \"buildFullOccTableProducer == true\" & \"processFullOccTableProduer == true\""; + return; + } + executeTrackOccProducerProcessing(BCs, collisions, tracks, tracksQA, occsRobustT0V0Prim, occs, processInThisBlock[kProcessFullOccTableProducer]); + occupancyQA.fill(HIST("h_DFcount_Lvl1"), kProcessFullOccTableProducer); + } // Process function ends + PROCESS_SWITCH(TrackMeanOccTableProducer, processFullOccTableProduer, "processFullOccTableProduer", false); +}; + +struct CreatePointerTables { + + Produces genTrackToTracksQA; + Produces genTrackToTmo; + + void processNothing(aod::Collisions const&) + { + return; + } + PROCESS_SWITCH(CreatePointerTables, processNothing, "process Nothing", true); + + std::vector> trackGIForTrackQAIndexList; + using MyTracksQA = aod::TracksQAVersion; + void processTrackToTrackQAPointer(aod::Tracks const& tracks, MyTracksQA const& tracksQA) + { + trackGIForTrackQAIndexList.clear(); + for (const auto& trackQA : tracksQA) { + auto const& track = trackQA.template track_as(); + trackGIForTrackQAIndexList.push_back({track.globalIndex(), trackQA.globalIndex()}); + } + + sortVectorOfArray(trackGIForTrackQAIndexList, 0); // sort the list //Its easy to search in a sorted list + checkUniqueness(trackGIForTrackQAIndexList, 0); // check the uniqueness of track.globalIndex() + + // create pointer table + int currentIDXforCheck = 0; + int listSize = trackGIForTrackQAIndexList.size(); + bool breakOnOverflow = false; + + for (const auto& track : tracks) { + while (!breakOnOverflow && track.globalIndex() > trackGIForTrackQAIndexList[currentIDXforCheck][0]) { + currentIDXforCheck++; // increment the currentIDXforCheck for missing or invalid cases e.g. value = -1; + if (currentIDXforCheck >= listSize) { + breakOnOverflow = true; + break; + } + } + if (!breakOnOverflow && track.globalIndex() == trackGIForTrackQAIndexList[currentIDXforCheck][0]) { + genTrackToTracksQA(trackGIForTrackQAIndexList[currentIDXforCheck][1]); + } else { + genTrackToTracksQA(-1); // put a dummy index when track is not found in trackQA + } + } + } + PROCESS_SWITCH(CreatePointerTables, processTrackToTrackQAPointer, "processTrackToTrackQAPointer", false); + + std::vector> trackGIForTMOIndexList; + void processTrackToTrackMeanOccsPointer(aod::Tracks const& tracks, aod::TmoTrackIds const& tmoTrackIds) + { + trackGIForTMOIndexList.clear(); + int tmoCounter = -1; + for (const auto& tmoTrackId : tmoTrackIds) { + tmoCounter++; + auto const& track = tmoTrackId.template track_as(); + trackGIForTMOIndexList.push_back({track.globalIndex(), tmoCounter}); // tmoTrackId Global Index is not working :: tmoTrackId.globalIndex()}); + } + sortVectorOfArray(trackGIForTMOIndexList, 0); // sort the list //Its easy to search in a sorted list + checkUniqueness(trackGIForTMOIndexList, 0); // check the uniqueness of track.globalIndex() + + // create pointer table + int currentIDXforCheck = 0; + int listSize = trackGIForTMOIndexList.size(); + bool breakOnOverflow = false; + + for (const auto& track : tracks) { + while (!breakOnOverflow && track.globalIndex() > trackGIForTMOIndexList[currentIDXforCheck][0]) { + currentIDXforCheck++; // increment the currentIDXforCheck for missing or invalid cases e.g. value = -1; + if (currentIDXforCheck >= listSize) { + breakOnOverflow = true; + break; + } + } + if (!breakOnOverflow && track.globalIndex() == trackGIForTMOIndexList[currentIDXforCheck][0]) { + genTrackToTmo(trackGIForTMOIndexList[currentIDXforCheck][1]); + } else { + genTrackToTmo(-1); // put a dummy index when track is not found in trackQA + } + } + } + PROCESS_SWITCH(CreatePointerTables, processTrackToTrackMeanOccsPointer, "processTrackToTrackMeanOccsPointer", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/propagationService.cxx b/Common/TableProducer/propagationService.cxx new file mode 100644 index 00000000000..9eb3dba4c10 --- /dev/null +++ b/Common/TableProducer/propagationService.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. + +/// \file propagationService.cxx +/// \brief +/// \author ALICE + +//=============================================================== +// +// Merged track propagation + strangeness building task +// +// Provides a common task to deal with track propagation and +// strangeness building in a single DPL device that is particularly +// adequate for pipelining. +// +//=============================================================== + +#include "PWGLF/Utils/strangenessBuilderModule.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Tools/StandardCCDBLoader.h" +#include "Common/Tools/TrackPropagationModule.h" +#include "Common/Tools/TrackTuner.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/GeomConstants.h" +#include "CommonUtils/NameConf.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" + +#include + +using namespace o2; +using namespace o2::framework; +// using namespace o2::framework::expressions; + +// use parameters + cov mat non-propagated, aux info + (extension propagated) +using FullTracksExt = soa::Join; +using FullTracksExtIU = soa::Join; +using FullTracksExtWithPID = soa::Join; +using FullTracksExtIUWithPID = soa::Join; +using FullTracksExtLabeled = soa::Join; +using FullTracksExtLabeledIU = soa::Join; +using FullTracksExtLabeledWithPID = soa::Join; +using FullTracksExtLabeledIUWithPID = soa::Join; +using TracksWithExtra = soa::Join; + +// For dE/dx association in pre-selection +using TracksExtraWithPID = soa::Join; + +struct propagationService { + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + + // propagation stuff + o2::common::StandardCCDBLoaderConfigurables standardCCDBLoaderConfigurables; + o2::common::StandardCCDBLoader ccdbLoader; + + // boilerplate: strangeness builder stuff + o2::pwglf::strangenessbuilder::products products; + o2::pwglf::strangenessbuilder::coreConfigurables baseOpts; + o2::pwglf::strangenessbuilder::v0Configurables v0BuilderOpts; + o2::pwglf::strangenessbuilder::cascadeConfigurables cascadeBuilderOpts; + o2::pwglf::strangenessbuilder::preSelectOpts preSelectOpts; + o2::pwglf::strangenessbuilder::BuilderModule strangenessBuilderModule; + + // the track tuner object -> needs to be here as it inherits from ConfigurableGroup (+ has its own copy of ccdbApi) + TrackTuner trackTunerObj; + + // track propagation + o2::common::TrackPropagationProducts trackPropagationProducts; + o2::common::TrackPropagationConfigurables trackPropagationConfigurables; + o2::common::TrackPropagationModule trackPropagation; + + // registry + HistogramRegistry histos{"histos"}; + + void init(o2::framework::InitContext& initContext) + { + // CCDB boilerplate init + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setURL(ccdburl.value); + + // task-specific + trackPropagation.init(trackPropagationConfigurables, trackTunerObj, histos, initContext); + strangenessBuilderModule.init(baseOpts, v0BuilderOpts, cascadeBuilderOpts, preSelectOpts, histos, initContext); + } + + 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) + { + ccdbLoader.initCCDBfromBCs(standardCCDBLoaderConfigurables, ccdb, bcs); + trackPropagation.fillTrackTables(trackPropagationConfigurables, trackTunerObj, ccdbLoader, collisions, tracks, trackPropagationProducts, histos); + strangenessBuilderModule.dataProcess(ccdb, histos, collisions, static_cast(nullptr), v0s, cascades, trackedCascades, tracks, bcs, static_cast(nullptr), products); + } + + 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) + { + ccdbLoader.initCCDBfromBCs(standardCCDBLoaderConfigurables, ccdb, bcs); + trackPropagation.fillTrackTables(trackPropagationConfigurables, trackTunerObj, ccdbLoader, collisions, tracks, trackPropagationProducts, histos); + strangenessBuilderModule.dataProcess(ccdb, histos, collisions, mccollisions, v0s, cascades, trackedCascades, tracks, bcs, mcParticles, products); + } + + void processRealDataWithPID(soa::Join const& collisions, aod::V0s const& v0s, aod::Cascades const& cascades, aod::TrackedCascades const& trackedCascades, FullTracksExtIUWithPID const& tracks, aod::BCsWithTimestamps const& bcs) + { + ccdbLoader.initCCDBfromBCs(standardCCDBLoaderConfigurables, ccdb, bcs); + trackPropagation.fillTrackTables(trackPropagationConfigurables, trackTunerObj, ccdbLoader, collisions, tracks, trackPropagationProducts, histos); + strangenessBuilderModule.dataProcess(ccdb, histos, collisions, static_cast(nullptr), v0s, cascades, trackedCascades, tracks, bcs, static_cast(nullptr), products); + } + + void processMonteCarloWithPID(soa::Join const& collisions, aod::McCollisions const& mccollisions, aod::V0s const& v0s, aod::Cascades const& cascades, aod::TrackedCascades const& trackedCascades, FullTracksExtLabeledIUWithPID const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const& mcParticles) + { + ccdbLoader.initCCDBfromBCs(standardCCDBLoaderConfigurables, ccdb, bcs); + trackPropagation.fillTrackTables(trackPropagationConfigurables, trackTunerObj, ccdbLoader, collisions, tracks, trackPropagationProducts, histos); + strangenessBuilderModule.dataProcess(ccdb, histos, collisions, mccollisions, v0s, cascades, trackedCascades, tracks, bcs, mcParticles, products); + } + + PROCESS_SWITCH(propagationService, processRealData, "process real data", true); + PROCESS_SWITCH(propagationService, processMonteCarlo, "process monte carlo", false); + PROCESS_SWITCH(propagationService, processRealDataWithPID, "process real data", false); + PROCESS_SWITCH(propagationService, processMonteCarloWithPID, "process monte carlo", false); +}; + +//**************************************************************************************** +/** + * Workflow definition. + */ +//**************************************************************************************** +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/Common/TableProducer/propagationServiceRun2.cxx b/Common/TableProducer/propagationServiceRun2.cxx new file mode 100644 index 00000000000..a2075355200 --- /dev/null +++ b/Common/TableProducer/propagationServiceRun2.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 propagationService.cxx +/// \brief +/// \author ALICE + +//=============================================================== +// +// Merged track propagation + strangeness building task +// +// Provides a common task to deal with track propagation and +// strangeness building in a single DPL device that is particularly +// adequate for pipelining. +// +//=============================================================== + +#include "PWGLF/Utils/strangenessBuilderModule.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Tools/StandardCCDBLoader.h" +#include "Common/Tools/TrackPropagationModule.h" +#include "Common/Tools/TrackTuner.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/GeomConstants.h" +#include "CommonUtils/NameConf.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" + +#include + +using namespace o2; +using namespace o2::framework; +// using namespace o2::framework::expressions; + +// use parameters + cov mat non-propagated, aux info + (extension propagated) +using FullTracksExt = soa::Join; +using FullTracksExtIU = soa::Join; +using FullTracksExtWithPID = soa::Join; +using FullTracksExtIUWithPID = soa::Join; +using FullTracksExtLabeled = soa::Join; +using FullTracksExtLabeledIU = soa::Join; +using FullTracksExtLabeledWithPID = soa::Join; +using FullTracksExtLabeledIUWithPID = soa::Join; +using TracksWithExtra = soa::Join; + +// For dE/dx association in pre-selection +using TracksExtraWithPID = soa::Join; + +struct propagationServiceRun2 { + // CCDB boilerplate declarations + o2::framework::Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + + // propagation stuff + o2::common::StandardCCDBLoaderConfigurables standardCCDBLoaderConfigurables; + o2::common::StandardCCDBLoader ccdbLoader; + + // boilerplate: strangeness builder stuff + o2::pwglf::strangenessbuilder::products products; + o2::pwglf::strangenessbuilder::coreConfigurables baseOpts; + o2::pwglf::strangenessbuilder::v0Configurables v0BuilderOpts; + o2::pwglf::strangenessbuilder::cascadeConfigurables cascadeBuilderOpts; + o2::pwglf::strangenessbuilder::preSelectOpts preSelectOpts; + o2::pwglf::strangenessbuilder::BuilderModule strangenessBuilderModule; + + // registry + HistogramRegistry histos{"histos"}; + + void init(o2::framework::InitContext& initContext) + { + // CCDB boilerplate init + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setURL(ccdburl.value); + ccdb->setFatalWhenNull(false); + + // task-specific + strangenessBuilderModule.init(baseOpts, v0BuilderOpts, cascadeBuilderOpts, preSelectOpts, histos, initContext); + } + + void processRealData(soa::Join const& collisions, aod::V0s const& v0s, aod::Cascades const& cascades, FullTracksExt const& tracks, aod::BCsWithTimestamps const& bcs) + { + ccdbLoader.initCCDBfromBCs(standardCCDBLoaderConfigurables, ccdb, bcs); + strangenessBuilderModule.dataProcess(ccdb, histos, collisions, static_cast(nullptr), v0s, cascades, static_cast(nullptr), tracks, bcs, static_cast(nullptr), products); + } + + void processMonteCarlo(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) + { + ccdbLoader.initCCDBfromBCs(standardCCDBLoaderConfigurables, ccdb, bcs); + strangenessBuilderModule.dataProcess(ccdb, histos, collisions, mccollisions, v0s, cascades, static_cast(nullptr), tracks, bcs, mcParticles, products); + } + + void processRealDataWithPID(soa::Join const& collisions, aod::V0s const& v0s, aod::Cascades const& cascades, FullTracksExtWithPID const& tracks, aod::BCsWithTimestamps const& bcs) + { + ccdbLoader.initCCDBfromBCs(standardCCDBLoaderConfigurables, ccdb, bcs); + strangenessBuilderModule.dataProcess(ccdb, histos, collisions, static_cast(nullptr), v0s, cascades, static_cast(nullptr), tracks, bcs, static_cast(nullptr), products); + } + + void processMonteCarloWithPID(soa::Join const& collisions, aod::McCollisions const& mccollisions, aod::V0s const& v0s, aod::Cascades const& cascades, FullTracksExtLabeledWithPID const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const& mcParticles) + { + ccdbLoader.initCCDBfromBCs(standardCCDBLoaderConfigurables, ccdb, bcs); + strangenessBuilderModule.dataProcess(ccdb, histos, collisions, mccollisions, v0s, cascades, static_cast(nullptr), tracks, bcs, mcParticles, products); + } + + PROCESS_SWITCH(propagationServiceRun2, processRealData, "process real data", true); + PROCESS_SWITCH(propagationServiceRun2, processMonteCarlo, "process monte carlo", false); + PROCESS_SWITCH(propagationServiceRun2, processRealDataWithPID, "process real data", false); + PROCESS_SWITCH(propagationServiceRun2, processMonteCarloWithPID, "process monte carlo", false); +}; + +//**************************************************************************************** +/** + * Workflow definition. + */ +//**************************************************************************************** +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/Common/TableProducer/qVectorsTable.cxx b/Common/TableProducer/qVectorsTable.cxx index 5d582ae87c5..fb0213c60d5 100644 --- a/Common/TableProducer/qVectorsTable.cxx +++ b/Common/TableProducer/qVectorsTable.cxx @@ -18,32 +18,41 @@ /// (with or without corrections) and save the results in a dedicated table. /// -// C++/ROOT includes. -#include -#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/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" - #include "Common/DataModel/Qvectors.h" - -#include "Common/Core/TrackSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -// o2 includes. -#include "CCDB/BasicCCDBManager.h" -#include "DetectorsCommonDataFormats/AlignParam.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -59,9 +68,9 @@ struct qVectorsTable { kFT0A = 1, kFT0M, kFV0A, - kBPos, - kBNeg, - kBTot + kTPCpos, + kTPCneg, + kTPCall }; // Configurables. @@ -78,22 +87,29 @@ struct qVectorsTable { 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 cfgEtaMax{"cfgEtaMax", 0.8, "Maximum pseudorapidiy for charged track"}; + Configurable cfgEtaMin{"cfgEtaMin", -0.8, "Minimum pseudorapidiy for charged track"}; + 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"}; + Configurable cfgShiftCorr{"cfgShiftCorr", false, "configurable flag for shift correction"}; + Configurable cfgShiftPath{"cfgShiftPath", "", "CCDB path for shift correction"}; + 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 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."}; + 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; @@ -101,17 +117,26 @@ struct qVectorsTable { Produces qVectorFT0A; Produces qVectorFT0M; Produces qVectorFV0A; - Produces qVectorBPos; - Produces qVectorBNeg; - Produces qVectorBTot; + Produces qVectorTPCpos; + Produces qVectorTPCneg; + Produces qVectorTPCall; Produces qVectorFT0CVec; Produces qVectorFT0AVec; Produces qVectorFT0MVec; Produces qVectorFV0AVec; - Produces qVectorBPosVec; - Produces qVectorBNegVec; - Produces qVectorBTotVec; + Produces qVectorTPCposVec; + Produces qVectorTPCnegVec; + Produces qVectorTPCallVec; + + Produces qVectorShifted; + Produces qVectorFT0CShiftedVec; + Produces qVectorFT0AShiftedVec; + Produces qVectorFT0MShiftedVec; + Produces qVectorFV0AShiftedVec; + Produces qVectorTPCposShiftedVec; + Produces qVectorTPCnegShiftedVec; + Produces qVectorTPCallShiftedVec; std::vector FT0RelGainConst{}; std::vector FV0RelGainConst{}; @@ -133,11 +158,29 @@ struct qVectorsTable { float cent; std::vector objQvec{}; + std::vector shiftprofile{}; + + // 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."}; - std::unordered_map useDetector = { + 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}, @@ -146,17 +189,17 @@ struct qVectorsTable { void init(InitContext& initContext) { // Check the sub-detector used - auto& workflows = initContext.services().get(); + const 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) { + for (auto const& 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) { + for (auto const& 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; @@ -202,9 +245,10 @@ struct qVectorsTable { 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()); @@ -226,17 +270,30 @@ struct qVectorsTable { fullPath = cfgQvecCalibPath; fullPath += "/v"; fullPath += std::to_string(ind); - auto objqvec = ccdb->getForTimeStamp(fullPath, timestamp); + auto objqvec = getForTsOrRun(fullPath, timestamp, runnumber); if (!objqvec) { fullPath = cfgQvecCalibPath; fullPath += "/v2"; - objqvec = ccdb->getForTimeStamp(fullPath, timestamp); + objqvec = getForTsOrRun(fullPath, timestamp, runnumber); } objQvec.push_back(objqvec); } + + if (cfgShiftCorr) { + shiftprofile.clear(); + for (std::size_t i = 0; i < cfgnMods->size(); i++) { + int ind = cfgnMods->at(i); + fullPath = cfgShiftPath; + fullPath += "/v"; + fullPath += std::to_string(ind); + auto objshift = getForTsOrRun(fullPath, timestamp, runnumber); + shiftprofile.push_back(objshift); + } + } + fullPath = cfgGainEqPath; fullPath += "/FT0"; - auto objft0Gain = ccdb->getForTimeStamp>(fullPath, timestamp); + const auto objft0Gain = getForTsOrRun>(fullPath, timestamp, runnumber); if (!objft0Gain || cfgCorrLevel == 0) { for (auto i{0u}; i < 208; i++) { FT0RelGainConst.push_back(1.); @@ -247,7 +304,7 @@ struct qVectorsTable { fullPath = cfgGainEqPath; fullPath += "/FV0"; - auto objfv0Gain = ccdb->getForTimeStamp>(fullPath, timestamp); + const auto objfv0Gain = getForTsOrRun>(fullPath, timestamp, runnumber); if (!objfv0Gain || cfgCorrLevel == 0) { for (auto i{0u}; i < 48; i++) { FV0RelGainConst.push_back(1.); @@ -282,16 +339,31 @@ struct qVectorsTable { return true; } + /// 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) + { + if (useCorrectionForRun) { + return ccdb->getForRun(fullPath, runNumber); + } else { + return ccdb->getForTimeStamp(fullPath, timestamp); + } + } + template - void CalQvec(const Nmode nmode, const CollType& coll, const TrackType& track, std::vector& QvecRe, std::vector& QvecIm, std::vector& QvecAmp, std::vector& TrkBPosLabel, std::vector& TrkBNegLabel, std::vector& TrkBTotLabel) + 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.}; - float qVectBPos[2] = {0.}; - float qVectBNeg[2] = {0.}; - float qVectBTot[2] = {0.}; + float qVectTPCpos[2] = {0.}; + float qVectTPCneg[2] = {0.}; + float qVectTPCall[2] = {0.}; TComplex QvecDet(0); TComplex QvecFT0M(0); @@ -394,59 +466,62 @@ struct qVectorsTable { qVectFV0A[1] = -999.; } - int nTrkBPos = 0; - int nTrkBNeg = 0; - int nTrkBTot = 0; + int nTrkTPCpos = 0; + int nTrkTPCneg = 0; + int nTrkTPCall = 0; - for (auto& trk : track) { + for (auto const& trk : track) { if (!SelTrack(trk)) { continue; } histosQA.fill(HIST("ChTracks"), trk.pt(), trk.eta(), trk.phi(), cent); - if (std::abs(trk.eta()) > 0.8) { + if (trk.eta() > cfgEtaMax) { + continue; + } + if (trk.eta() < cfgEtaMin) { continue; } - qVectBTot[0] += trk.pt() * std::cos(trk.phi() * nmode); - qVectBTot[1] += trk.pt() * std::sin(trk.phi() * nmode); - TrkBTotLabel.push_back(trk.globalIndex()); - nTrkBTot++; + 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["QvectorBPoss"]) { - qVectBPos[0] += trk.pt() * std::cos(trk.phi() * nmode); - qVectBPos[1] += trk.pt() * std::sin(trk.phi() * nmode); - TrkBPosLabel.push_back(trk.globalIndex()); - nTrkBPos++; - } else if (trk.eta() < 0 && useDetector["QvectorBNegs"]) { - qVectBNeg[0] += trk.pt() * std::cos(trk.phi() * nmode); - qVectBNeg[1] += trk.pt() * std::sin(trk.phi() * nmode); - TrkBNegLabel.push_back(trk.globalIndex()); - nTrkBNeg++; + 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.; } - if (nTrkBTot > 0) { - qVectBTot[0] /= nTrkBTot; - qVectBTot[1] /= nTrkBTot; + if (nTrkTPCall > 0) { + qVectTPCall[0] /= nTrkTPCall; + qVectTPCall[1] /= nTrkTPCall; } else { - qVectBTot[0] = 999.; - qVectBTot[1] = 999.; + qVectTPCall[0] = 999.; + qVectTPCall[1] = 999.; } for (auto i{0u}; i < 4; i++) { @@ -466,32 +541,32 @@ struct qVectorsTable { QvecIm.push_back(qVectFV0A[1]); } for (auto i{0u}; i < 4; i++) { - QvecRe.push_back(qVectBPos[0]); - QvecIm.push_back(qVectBPos[1]); + QvecRe.push_back(qVectTPCpos[0]); + QvecIm.push_back(qVectTPCpos[1]); } for (auto i{0u}; i < 4; i++) { - QvecRe.push_back(qVectBNeg[0]); - QvecIm.push_back(qVectBNeg[1]); + QvecRe.push_back(qVectTPCneg[0]); + QvecIm.push_back(qVectTPCneg[1]); } for (auto i{0u}; i < 4; i++) { - QvecRe.push_back(qVectBTot[0]); - QvecIm.push_back(qVectBTot[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(static_cast(nTrkBTot)); + 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 TrkBPosLabel{}; - std::vector TrkBNegLabel{}; - std::vector TrkBTotLabel{}; + std::vector TrkTPCposLabel{}; + std::vector TrkTPCnegLabel{}; + std::vector TrkTPCallLabel{}; std::vector qvecRe{}; std::vector qvecIm{}; std::vector qvecAmp{}; @@ -504,12 +579,31 @@ struct qVectorsTable { std::vector qvecImFT0M{}; std::vector qvecReFV0A{}; std::vector qvecImFV0A{}; - std::vector qvecReBPos{}; - std::vector qvecImBPos{}; - std::vector qvecReBNeg{}; - std::vector qvecImBNeg{}; - std::vector qvecReBTot{}; - std::vector qvecImBTot{}; + std::vector qvecReTPCpos{}; + std::vector qvecImTPCpos{}; + std::vector qvecReTPCneg{}; + std::vector qvecImTPCneg{}; + std::vector qvecReTPCall{}; + std::vector qvecImTPCall{}; + + std::vector qvecShiftedRe{}; + std::vector qvecShiftedIm{}; + std::vector qvecShiftedAmp{}; + + std::vector qvecReShiftedFT0C{}; + std::vector qvecImShiftedFT0C{}; + std::vector qvecReShiftedFT0A{}; + std::vector qvecImShiftedFT0A{}; + std::vector qvecReShiftedFT0M{}; + std::vector qvecImShiftedFT0M{}; + std::vector qvecReShiftedFV0A{}; + std::vector qvecImShiftedFV0A{}; + std::vector qvecReShiftedTPCpos{}; + std::vector qvecImShiftedTPCpos{}; + std::vector qvecReShiftedTPCneg{}; + std::vector qvecImShiftedTPCneg{}; + std::vector qvecReShiftedTPCall{}; + std::vector qvecImShiftedTPCall{}; auto bc = coll.bc_as(); int currentRun = bc.runNumber(); @@ -518,7 +612,7 @@ struct qVectorsTable { runNumber = currentRun; } - float centAllEstim[4] = { + const float centAllEstim[4] = { coll.centFT0M(), coll.centFT0A(), coll.centFT0C(), coll.centFV0A()}; cent = centAllEstim[cfgCentEsti]; @@ -528,41 +622,114 @@ struct qVectorsTable { IsCalibrated = false; } for (std::size_t id = 0; id < cfgnMods->size(); id++) { - int ind = cfgnMods->at(id); - CalQvec(ind, coll, tracks, qvecRe, qvecIm, qvecAmp, TrkBPosLabel, TrkBNegLabel, TrkBTotLabel); + int nmode = cfgnMods->at(id); + CalQvec(nmode, coll, tracks, qvecRe, qvecIm, qvecAmp, TrkTPCposLabel, TrkTPCnegLabel, TrkTPCallLabel); if (cent < cfgMaxCentrality) { - for (auto i{0u}; i < kBTot + 1; i++) { - helperEP.DoRecenter(qvecRe[(kBTot + 1) * 4 * id + i * 4 + 1], qvecIm[(kBTot + 1) * 4 * id + i * 4 + 1], + 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[(kBTot + 1) * 4 * id + i * 4 + 2], qvecIm[(kBTot + 1) * 4 * id + i * 4 + 2], + 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[(kBTot + 1) * 4 * id + i * 4 + 2], qvecIm[(kBTot + 1) * 4 * id + i * 4 + 2], + 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[(kBTot + 1) * 4 * id + i * 4 + 3], qvecIm[(kBTot + 1) * 4 * id + i * 4 + 3], + 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[(kBTot + 1) * 4 * id + i * 4 + 3], qvecIm[(kBTot + 1) * 4 * id + i * 4 + 3], + 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[(kBTot + 1) * 4 * id + i * 4 + 3], qvecIm[(kBTot + 1) * 4 * id + i * 4 + 3], + 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)); } + if (cfgShiftCorr) { + auto deltapsiFT0C = 0.0; + auto deltapsiFT0A = 0.0; + auto deltapsiFT0M = 0.0; + auto deltapsiFV0A = 0.0; + auto deltapsiTPCpos = 0.0; + auto deltapsiTPCneg = 0.0; + auto deltapsiTPCall = 0.0; + + auto psidefFT0C = TMath::ATan2(qvecIm[(kTPCall + 1) * 4 * id + kFT0C * 4 + 3], qvecRe[(kTPCall + 1) * 4 * id + kFT0C * 4 + 3]) / static_cast(nmode); + auto psidefFT0A = TMath::ATan2(qvecIm[(kTPCall + 1) * 4 * id + kFT0A * 4 + 3], qvecRe[(kTPCall + 1) * 4 * id + kFT0A * 4 + 3]) / static_cast(nmode); + auto psidefFT0M = TMath::ATan2(qvecIm[(kTPCall + 1) * 4 * id + kFT0M * 4 + 3], qvecRe[(kTPCall + 1) * 4 * id + kFT0M * 4 + 3]) / static_cast(nmode); + auto psidefFV0A = TMath::ATan2(qvecIm[(kTPCall + 1) * 4 * id + kFV0A * 4 + 3], qvecRe[(kTPCall + 1) * 4 * id + kFV0A * 4 + 3]) / static_cast(nmode); + auto psidefTPCpos = TMath::ATan2(qvecIm[(kTPCall + 1) * 4 * id + kTPCpos * 4 + 3], qvecRe[(kTPCall + 1) * 4 * id + kTPCpos * 4 + 3]) / static_cast(nmode); + auto psidefTPCneg = TMath::ATan2(qvecIm[(kTPCall + 1) * 4 * id + kTPCneg * 4 + 3], qvecRe[(kTPCall + 1) * 4 * id + kTPCneg * 4 + 3]) / static_cast(nmode); + auto psidefTPCall = TMath::ATan2(qvecIm[(kTPCall + 1) * 4 * id + kTPCall * 4 + 3], qvecRe[(kTPCall + 1) * 4 * id + kTPCall * 4 + 3]) / static_cast(nmode); + + for (int ishift = 1; ishift <= 10; ishift++) { + auto coeffshiftxFT0C = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kFT0C, ishift - 0.5)); + auto coeffshiftyFT0C = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kFT0C + 1, ishift - 0.5)); + auto coeffshiftxFT0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kFT0A, ishift - 0.5)); + auto coeffshiftyFT0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kFT0A + 1, ishift - 0.5)); + auto coeffshiftxFT0M = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kFT0M, ishift - 0.5)); + auto coeffshiftyFT0M = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kFT0M + 1, ishift - 0.5)); + auto coeffshiftxFV0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kFV0A, ishift - 0.5)); + auto coeffshiftyFV0A = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kFV0A + 1, ishift - 0.5)); + auto coeffshiftxTPCpos = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kTPCpos, ishift - 0.5)); + auto coeffshiftyTPCpos = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kTPCpos + 1, ishift - 0.5)); + auto coeffshiftxTPCneg = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kTPCneg, ishift - 0.5)); + auto coeffshiftyTPCneg = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kTPCneg + 1, ishift - 0.5)); + auto coeffshiftxTPCall = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kTPCall, ishift - 0.5)); + auto coeffshiftyTPCall = shiftprofile.at(nmode - 2)->GetBinContent(shiftprofile.at(nmode - 2)->FindBin(cent, 2 * kTPCall + 1, ishift - 0.5)); + + deltapsiFT0C += ((2. / (1.0 * ishift)) * (-coeffshiftxFT0C * TMath::Cos(ishift * static_cast(nmode) * psidefFT0C) + coeffshiftyFT0C * TMath::Sin(ishift * static_cast(nmode) * psidefFT0C))) / static_cast(nmode); + deltapsiFT0A += ((2. / (1.0 * ishift)) * (-coeffshiftxFT0A * TMath::Cos(ishift * static_cast(nmode) * psidefFT0A) + coeffshiftyFT0A * TMath::Sin(ishift * static_cast(nmode) * psidefFT0A))) / static_cast(nmode); + deltapsiFT0M += ((2. / (1.0 * ishift)) * (-coeffshiftxFT0M * TMath::Cos(ishift * static_cast(nmode) * psidefFT0M) + coeffshiftyFT0M * TMath::Sin(ishift * static_cast(nmode) * psidefFT0M))) / static_cast(nmode); + deltapsiFV0A += ((2. / (1.0 * ishift)) * (-coeffshiftxFV0A * TMath::Cos(ishift * static_cast(nmode) * psidefFV0A) + coeffshiftyFV0A * TMath::Sin(ishift * static_cast(nmode) * psidefFV0A))) / static_cast(nmode); + deltapsiTPCpos += ((2. / (1.0 * ishift)) * (-coeffshiftxTPCpos * TMath::Cos(ishift * static_cast(nmode) * psidefTPCpos) + coeffshiftyTPCpos * TMath::Sin(ishift * static_cast(nmode) * psidefTPCpos))) / static_cast(nmode); + deltapsiTPCneg += ((2. / (1.0 * ishift)) * (-coeffshiftxTPCneg * TMath::Cos(ishift * static_cast(nmode) * psidefTPCneg) + coeffshiftyTPCneg * TMath::Sin(ishift * static_cast(nmode) * psidefTPCneg))) / static_cast(nmode); + deltapsiTPCall += ((2. / (1.0 * ishift)) * (-coeffshiftxTPCall * TMath::Cos(ishift * static_cast(nmode) * psidefTPCall) + coeffshiftyTPCall * TMath::Sin(ishift * static_cast(nmode) * psidefTPCall))) / static_cast(nmode); + } + + qvecReShiftedFT0C.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0C * 4 + 3] * TMath::Cos(deltapsiFT0C) - qvecIm[(kTPCall + 1) * 4 * id + kFT0C * 4 + 3] * TMath::Sin(deltapsiFT0C)); + qvecImShiftedFT0C.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0C * 4 + 3] * TMath::Sin(deltapsiFT0C) + qvecIm[(kTPCall + 1) * 4 * id + kFT0C * 4 + 3] * TMath::Cos(deltapsiFT0C)); + qvecReShiftedFT0A.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0A * 4 + 3] * TMath::Cos(deltapsiFT0A) - qvecIm[(kTPCall + 1) * 4 * id + kFT0A * 4 + 3] * TMath::Sin(deltapsiFT0A)); + qvecImShiftedFT0A.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0A * 4 + 3] * TMath::Sin(deltapsiFT0A) + qvecIm[(kTPCall + 1) * 4 * id + kFT0A * 4 + 3] * TMath::Cos(deltapsiFT0A)); + qvecReShiftedFT0M.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0M * 4 + 3] * TMath::Cos(deltapsiFT0M) - qvecIm[(kTPCall + 1) * 4 * id + kFT0M * 4 + 3] * TMath::Sin(deltapsiFT0M)); + qvecImShiftedFT0M.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFT0M * 4 + 3] * TMath::Sin(deltapsiFT0M) + qvecIm[(kTPCall + 1) * 4 * id + kFT0M * 4 + 3] * TMath::Cos(deltapsiFT0M)); + qvecReShiftedFV0A.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFV0A * 4 + 3] * TMath::Cos(deltapsiFV0A) - qvecIm[(kTPCall + 1) * 4 * id + kFV0A * 4 + 3] * TMath::Sin(deltapsiFV0A)); + qvecImShiftedFV0A.push_back(qvecRe[(kTPCall + 1) * 4 * id + kFV0A * 4 + 3] * TMath::Sin(deltapsiFV0A) + qvecIm[(kTPCall + 1) * 4 * id + kFV0A * 4 + 3] * TMath::Cos(deltapsiFV0A)); + qvecReShiftedTPCpos.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCpos * 4 + 3] * TMath::Cos(deltapsiTPCpos) - qvecIm[(kTPCall + 1) * 4 * id + kTPCpos * 4 + 3] * TMath::Sin(deltapsiTPCpos)); + qvecImShiftedTPCpos.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCpos * 4 + 3] * TMath::Sin(deltapsiTPCpos) + qvecIm[(kTPCall + 1) * 4 * id + kTPCpos * 4 + 3] * TMath::Cos(deltapsiTPCpos)); + qvecReShiftedTPCneg.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCneg * 4 + 3] * TMath::Cos(deltapsiTPCneg) - qvecIm[(kTPCall + 1) * 4 * id + kTPCneg * 4 + 3] * TMath::Sin(deltapsiTPCneg)); + qvecImShiftedTPCneg.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCneg * 4 + 3] * TMath::Sin(deltapsiTPCneg) + qvecIm[(kTPCall + 1) * 4 * id + kTPCneg * 4 + 3] * TMath::Cos(deltapsiTPCneg)); + qvecReShiftedTPCall.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCall * 4 + 3] * TMath::Cos(deltapsiTPCall) - qvecIm[(kTPCall + 1) * 4 * id + kTPCall * 4 + 3] * TMath::Sin(deltapsiTPCall)); + qvecImShiftedTPCall.push_back(qvecRe[(kTPCall + 1) * 4 * id + kTPCall * 4 + 3] * TMath::Sin(deltapsiTPCall) + qvecIm[(kTPCall + 1) * 4 * id + kTPCall * 4 + 3] * TMath::Cos(deltapsiTPCall)); + + qvecShiftedRe.push_back(qvecReShiftedFT0C[id]); + qvecShiftedRe.push_back(qvecReShiftedFT0A[id]); + qvecShiftedRe.push_back(qvecReShiftedFT0M[id]); + qvecShiftedRe.push_back(qvecReShiftedFV0A[id]); + qvecShiftedRe.push_back(qvecReShiftedTPCpos[id]); + qvecShiftedRe.push_back(qvecReShiftedTPCneg[id]); + qvecShiftedRe.push_back(qvecReShiftedTPCall[id]); + + qvecShiftedIm.push_back(qvecImShiftedFT0C[id]); + qvecShiftedIm.push_back(qvecImShiftedFT0A[id]); + qvecShiftedIm.push_back(qvecImShiftedFT0M[id]); + qvecShiftedIm.push_back(qvecImShiftedFV0A[id]); + qvecShiftedIm.push_back(qvecImShiftedTPCpos[id]); + qvecShiftedIm.push_back(qvecImShiftedTPCneg[id]); + qvecShiftedIm.push_back(qvecImShiftedTPCall[id]); + } } int CorrLevel = cfgCorrLevel == 0 ? 0 : cfgCorrLevel - 1; - qvecReFT0C.push_back(qvecRe[(kBTot + 1) * 4 * id + kFT0C * 4 + CorrLevel]); - qvecImFT0C.push_back(qvecIm[(kBTot + 1) * 4 * id + kFT0C * 4 + CorrLevel]); - qvecReFT0A.push_back(qvecRe[(kBTot + 1) * 4 * id + kFT0A * 4 + CorrLevel]); - qvecImFT0A.push_back(qvecIm[(kBTot + 1) * 4 * id + kFT0A * 4 + CorrLevel]); - qvecReFT0M.push_back(qvecRe[(kBTot + 1) * 4 * id + kFT0M * 4 + CorrLevel]); - qvecImFT0M.push_back(qvecIm[(kBTot + 1) * 4 * id + kFT0M * 4 + CorrLevel]); - qvecReFV0A.push_back(qvecRe[(kBTot + 1) * 4 * id + kFV0A * 4 + CorrLevel]); - qvecImFV0A.push_back(qvecIm[(kBTot + 1) * 4 * id + kFV0A * 4 + CorrLevel]); - qvecReBPos.push_back(qvecRe[(kBTot + 1) * 4 * id + kBPos * 4 + CorrLevel]); - qvecImBPos.push_back(qvecIm[(kBTot + 1) * 4 * id + kBPos * 4 + CorrLevel]); - qvecReBNeg.push_back(qvecRe[(kBTot + 1) * 4 * id + kBNeg * 4 + CorrLevel]); - qvecImBNeg.push_back(qvecIm[(kBTot + 1) * 4 * id + kBNeg * 4 + CorrLevel]); - qvecReBTot.push_back(qvecRe[(kBTot + 1) * 4 * id + kBTot * 4 + CorrLevel]); - qvecImBTot.push_back(qvecIm[(kBTot + 1) * 4 * id + kBTot * 4 + CorrLevel]); + 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. @@ -575,20 +742,45 @@ struct qVectorsTable { 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["QvectorBPoss"]) - qVectorBPos(IsCalibrated, qvecReBPos.at(0), qvecImBPos.at(0), qvecAmp[kBPos], TrkBPosLabel); - if (useDetector["QvectorBNegs"]) - qVectorBNeg(IsCalibrated, qvecReBNeg.at(0), qvecImBNeg.at(0), qvecAmp[kBNeg], TrkBNegLabel); - if (useDetector["QvectorBTots"]) - qVectorBTot(IsCalibrated, qvecReBTot.at(0), qvecImBTot.at(0), qvecAmp[kBTot], TrkBTotLabel); + 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]); - qVectorBPosVec(IsCalibrated, qvecReBPos, qvecImBPos, qvecAmp[kBPos], TrkBPosLabel); - qVectorBNegVec(IsCalibrated, qvecReBNeg, qvecImBNeg, qvecAmp[kBNeg], TrkBNegLabel); - qVectorBTotVec(IsCalibrated, qvecReBTot, qvecImBTot, qvecAmp[kBTot], TrkBTotLabel); + qVectorTPCposVec(IsCalibrated, qvecReTPCpos, qvecImTPCpos, qvecAmp[kTPCpos], TrkTPCposLabel); + qVectorTPCnegVec(IsCalibrated, qvecReTPCneg, qvecImTPCneg, qvecAmp[kTPCneg], TrkTPCnegLabel); + qVectorTPCallVec(IsCalibrated, qvecReTPCall, qvecImTPCall, qvecAmp[kTPCall], TrkTPCallLabel); + + if (cfgShiftCorr) { + qVectorShifted(cent, IsCalibrated, qvecShiftedRe, qvecShiftedIm, qvecAmp); + qVectorFT0CShiftedVec(IsCalibrated, qvecReShiftedFT0C, qvecImShiftedFT0C, qvecAmp[kFT0C]); + qVectorFT0AShiftedVec(IsCalibrated, qvecReShiftedFT0A, qvecImShiftedFT0A, qvecAmp[kFT0A]); + qVectorFT0MShiftedVec(IsCalibrated, qvecReShiftedFT0M, qvecImShiftedFT0M, qvecAmp[kFT0M]); + qVectorFV0AShiftedVec(IsCalibrated, qvecReShiftedFV0A, qvecImShiftedFV0A, qvecAmp[kFV0A]); + qVectorTPCposShiftedVec(IsCalibrated, qvecReShiftedTPCpos, qvecImShiftedTPCpos, qvecAmp[kTPCpos], TrkTPCposLabel); + qVectorTPCnegShiftedVec(IsCalibrated, qvecReShiftedTPCneg, qvecImShiftedTPCneg, qvecAmp[kTPCneg], TrkTPCnegLabel); + qVectorTPCallShiftedVec(IsCalibrated, qvecReShiftedTPCall, qvecImShiftedTPCall, 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/selectionStudyTable.cxx b/Common/TableProducer/selectionStudyTable.cxx new file mode 100644 index 00000000000..bd7febf9bb9 --- /dev/null +++ b/Common/TableProducer/selectionStudyTable.cxx @@ -0,0 +1,130 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file selectionStudyTable.cxx +/// \brief Produces tables for centrality selection bias studies +/// +/// \author ALICE +/// + +#include "Common/DataModel/SelectionStudyTables.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct SelectionStudyTable { + Produces pidpts; + + // could be done in a vector of vectors + // left for future iteration + std::vector ptpi; + std::vector ptka; + std::vector ptpr; + std::vector ptk0; + std::vector ptla; + std::vector ptxi; + std::vector ptom; + std::vector ptph; + std::vector ptks; + std::vector ptd; + std::vector ptlc; + std::vector ptjp; + + void init(InitContext&) + { + } + + void process(aod::McCollision const&, aod::McParticles const& mcParticles) + { + ptpi.clear(); + ptka.clear(); + ptpr.clear(); + ptk0.clear(); + ptla.clear(); + ptxi.clear(); + ptom.clear(); + ptph.clear(); + ptks.clear(); + ptd.clear(); + ptlc.clear(); + ptjp.clear(); + for (auto const& mcPart : mcParticles) { + if (std::fabs(mcPart.y()) > 0.5) { + continue; // only do midrapidity particles + } + + // handle resonances first to make sure phys prim crit does not reject them + if (mcPart.pdgCode() == 333) { + ptph.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 313) { + ptks.push_back(mcPart.pt()); + } + + // resonances handled, move to primaries + if (!mcPart.isPhysicalPrimary()) { + continue; + } + if (std::abs(mcPart.pdgCode()) == 211) { + ptpi.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 321) { + ptka.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 2212) { + ptpr.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 310) { + ptk0.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 3122) { + ptla.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 3312) { + ptxi.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 3334) { + ptom.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 3334) { + ptom.push_back(mcPart.pt()); + } + // inclusive HF for now + if (std::abs(mcPart.pdgCode()) == 421) { + ptd.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 4122) { + ptd.push_back(mcPart.pt()); + } + if (std::abs(mcPart.pdgCode()) == 443) { + ptjp.push_back(mcPart.pt()); + } + } + + pidpts(ptpi, ptka, ptpr, ptk0, ptla, ptxi, ptom, ptph, ptks, ptd, ptlc, ptjp); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/timestamp.cxx b/Common/TableProducer/timestamp.cxx index c108bf32713..30ad84150c5 100644 --- a/Common/TableProducer/timestamp.cxx +++ b/Common/TableProducer/timestamp.cxx @@ -16,32 +16,49 @@ /// \brief A task to fill the timestamp table from run number. /// Uses headers from CCDB /// -#include +#include "Common/Core/MetadataHelper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include #include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "CCDB/BasicCCDBManager.h" -#include "CommonDataFormat/InteractionRecord.h" -#include "DetectorsRaw/HBFUtils.h" +#include +#include +#include using namespace o2::framework; using namespace o2::header; using namespace o2; +o2::common::core::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 - std::map mapRunToOrbitReset; /// Cache of orbit reset timestamps - int lastRunNumber = 0; /// Last run number processed - int64_t orbitResetTimestamp = 0; /// Orbit-reset timestamp in us + 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 +68,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,14 +89,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"); - auto timestamps = ccdb->getRunDuration(runNumber, true); /// fatalise if timestamps are not found - int64_t sorTimestamp = timestamps.first; // timestamp of the SOR in ms - int64_t eorTimestamp = timestamps.second; // timestamp of the EOR in ms + 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 - 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 @@ -83,7 +109,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]; } @@ -93,18 +119,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/trackDcaCovFillerRun2.cxx b/Common/TableProducer/trackDcaCovFillerRun2.cxx new file mode 100644 index 00000000000..7fb77b96c87 --- /dev/null +++ b/Common/TableProducer/trackDcaCovFillerRun2.cxx @@ -0,0 +1,202 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file trackDcaCovFillerRun2.cxx +/// \author Aimeric Landou , CERN +/// \brief Fills DCA and DCA Cov tables for Run 2 tracks +// Run 2 AO2Ds cannot have their dcacov filled by the current track-propagation workflow as the workflow isn't designed for them, given Run 2 tracks are already propagated to the PV. +// This task fills the DCA Cov (and DCA) tables for Run 2 tracks by "propagating" the tracks (though given they are already at the PV it doesn't actually do the propagation) and retrieving the DCA and DCA cov given by the propagateToDCABxByBz function + +#include "Common/Core/TableHelper.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#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 TrackDcaCovFillerRun2 { + Produces tracksDCA; + Produces tracksDCACov; + + // Produces tunertable; + + Service ccdb; + + bool fillTracksDCA = false; + bool fillTracksDCACov = false; + int runNumber = -1; + + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; + o2::parameters::GRPMagField* grpmag = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "CCDB path of the grp file (run2)"}; + Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + + HistogramRegistry registry{"registry"}; + + void init(o2::framework::InitContext& initContext) + { + // Checking if the tables are requested in the workflow and enabling them + fillTracksDCA = isTableRequiredInWorkflow(initContext, "TracksDCA"); + fillTracksDCACov = isTableRequiredInWorkflow(initContext, "TracksDCACov"); + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (runNumber == bc.runNumber()) { + return; + } + + // Run 2 GRP object + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(ccdbPathGrp, bc.timestamp()); + if (grpo == nullptr) { + LOGF(fatal, "Run 2 GRP object (type o2::parameters::GRPObject) is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); + } + o2::base::Propagator::initFieldFromGRP(grpo); + LOGF(info, "Setting magnetic field to %d kG for run %d from its GRP CCDB object (type o2::parameters::GRPObject)", grpo->getNominalL3Field(), bc.runNumber()); + + mMeanVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); + runNumber = bc.runNumber(); + } + + // Running variables + std::array mDcaInfo; + o2::dataformats::DCA mDcaInfoCov; + o2::dataformats::VertexBase mVtx; + o2::track::TrackParametrization mTrackPar; + o2::track::TrackParametrizationWithError mTrackParCov; + + template + void fillTrackTables(TTrack const& tracks, + TParticle const&, + aod::Collisions const&, + aod::BCsWithTimestamps const& bcs) + { + if (bcs.size() == 0) { + return; + } + initCCDB(bcs.begin()); + + if constexpr (fillCovMat) { + if (fillTracksDCACov) { + tracksDCACov.reserve(tracks.size()); + } + } else { + if (fillTracksDCA) { + tracksDCA.reserve(tracks.size()); + } + } + + for (auto const& track : tracks) { + if constexpr (fillCovMat) { + if (fillTracksDCA || fillTracksDCACov) { + mDcaInfoCov.set(999, 999, 999, 999, 999); + } + setTrackParCov(track, mTrackParCov); + } else { + if (fillTracksDCA) { + mDcaInfo[0] = 999; + mDcaInfo[1] = 999; + } + setTrackPar(track, mTrackPar); + } + + 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); + } else { + 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); + } else { + o2::base::Propagator::Instance()->propagateToDCABxByBz({mMeanVtx->getX(), mMeanVtx->getY(), mMeanVtx->getZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); + } + } + + if constexpr (fillCovMat) { + if (fillTracksDCA) { + tracksDCA(mDcaInfoCov.getY(), mDcaInfoCov.getZ()); + } + if (fillTracksDCACov) { + tracksDCACov(mDcaInfoCov.getSigmaY2(), mDcaInfoCov.getSigmaZ2()); + } + } else { + if (fillTracksDCA) { + tracksDCA(mDcaInfo[0], mDcaInfo[1]); + } + } + } + } + + void processCovariance(soa::Join const& tracks, aod::Collisions const& collisions, aod::BCsWithTimestamps const& bcs) + { + fillTrackTables, /*Particle*/ soa::Join, /*isMc = */ false, /*fillCovMat =*/true>(tracks, tracks, collisions, bcs); + } + PROCESS_SWITCH(TrackDcaCovFillerRun2, processCovariance, "Process with covariance", false); + + void processStandard(soa::Join const& tracks, aod::Collisions const& collisions, aod::BCsWithTimestamps const& bcs) + { + fillTrackTables, /*Particle*/ soa::Join, /*isMc = */ false, /*fillCovMat =*/false>(tracks, tracks, collisions, bcs); + } + PROCESS_SWITCH(TrackDcaCovFillerRun2, processStandard, "Process without covariance", true); +}; + +//**************************************************************************************** +/** + * Workflow definition. + */ +//**************************************************************************************** +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/Common/TableProducer/trackPropagation.cxx b/Common/TableProducer/trackPropagation.cxx index ac8a4e60e0e..703265a8dab 100644 --- a/Common/TableProducer/trackPropagation.cxx +++ b/Common/TableProducer/trackPropagation.cxx @@ -13,9 +13,41 @@ // Task to add a table of track parameters propagated to the primary vertex // -#include "TableHelper.h" +#include "Common/Core/TableHelper.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/Tools/TrackTuner.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + // The Run 3 AO2D stores the tracks at the point of innermost update. For a track with ITS this is the innermost (or second innermost) // ITS layer. For a track without ITS, this is the TPC inner wall or for loopers in the TPC even a radius beyond that. // In order to use the track parameters, the tracks have to be propagated to the collision vertex which is done by this task. @@ -62,6 +94,7 @@ struct TrackPropagation { // for TrackTuner only (MC smearing) 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}; @@ -109,7 +142,6 @@ 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}); @@ -119,13 +151,23 @@ struct TrackPropagation { /// 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"); } } @@ -134,6 +176,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); @@ -143,7 +194,7 @@ struct TrackPropagation { } // Running variables - gpu::gpustd::array mDcaInfo; + std::array mDcaInfo; o2::dataformats::DCA mDcaInfoCov; o2::dataformats::VertexBase mVtx; o2::track::TrackParametrization mTrackPar; diff --git a/Common/TableProducer/trackPropagationTester.cxx b/Common/TableProducer/trackPropagationTester.cxx deleted file mode 100644 index 92139a4fceb..00000000000 --- a/Common/TableProducer/trackPropagationTester.cxx +++ /dev/null @@ -1,350 +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 add a table of track parameters propagated to the primary vertex -// -// FIXME: THIS IS AN EXPERIMENTAL TASK, MEANT ONLY FOR EXPLORATORY PURPOSES. -// FIXME: PLEASE ONLY USE IT WITH EXTREME CARE. IF IN DOUBT, STICK WITH THE DEFAULT -// FIXME: TRACKPROPAGATION - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/trackUtilities.h" -#include "ReconstructionDataFormats/DCA.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "CommonUtils/NameConf.h" -#include "CCDB/CcdbApi.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" -#include "DataFormatsCalibration/MeanVertexObject.h" -#include "CommonConstants/GeomConstants.h" -#include "trackSelectionRequest.h" - -// The Run 3 AO2D stores the tracks at the point of innermost update. For a track with ITS this is the innermost (or second innermost) -// ITS layer. For a track without ITS, this is the TPC inner wall or for loopers in the TPC even a radius beyond that. -// In order to use the track parameters, the tracks have to be propagated to the collision vertex which is done by this task. -// The task consumes the TracksIU and TracksCovIU tables and produces Tracks and TracksCov to which then the user analysis can subscribe. -// -// This task is not needed for Run 2 converted data. -// There are two versions of the task (see process flags), one producing also the covariance matrix and the other only the tracks table. - -using namespace o2; -using namespace o2::framework; -// using namespace o2::framework::expressions; - -struct TrackPropagationTester { - Produces tracksParPropagated; - Produces tracksParExtensionPropagated; - - Produces tracksParCovPropagated; - Produces tracksParCovExtensionPropagated; - - Produces tracksDCA; - - Service ccdb; - - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - bool fillTracksDCA = false; - int runNumber = -1; - - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - - const o2::dataformats::MeanVertexObject* mVtx = nullptr; - o2::parameters::GRPMagField* grpmag = nullptr; - o2::base::MatLayerCylSet* lut = nullptr; - - // Track selection object in this scope: not necessarily a configurable - trackSelectionRequest trackSels; - // Configurable based on a struct - // Configurable trackSels{"trackSels", {}, "track selections"}; - - 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"}; - 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"}; - - // Configurables regarding what to propagate - // FIXME: This is dangerous and error prone for general purpose use. It is meant ONLY for testing. - Configurable propagateUnassociated{"propagateUnassociated", false, "propagate tracks with no collision assoc"}; - Configurable propagateTPConly{"propagateTPConly", false, "propagate tracks with only TPC (no ITS, TRD, TOF)"}; - Configurable minTPCClusters{"minTPCClusters", 70, "min number of TPC clusters to propagate"}; - Configurable maxPropagStep{"maxPropagStep", 2.0, "max propag step"}; // to be checked systematically - // use auto-detect configuration - Configurable d_UseAutodetectMode{"d_UseAutodetectMode", false, "Autodetect requested track criteria"}; - - bool hasEnding(std::string const& fullString, std::string const& ending) - { - if (fullString.length() >= ending.length()) { - return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending)); - } else { - return false; - } - } - - void init(o2::framework::InitContext& initContext) - { - const AxisSpec axisX{(int)4, 0.0f, +4.0f, "Track counter"}; - histos.add("hTrackCounter", "hTrackCounter", kTH1F, {axisX}); - - if (doprocessCovariance == true && doprocessStandard == true) { - LOGF(fatal, "Cannot enable processStandard and processCovariance at the same time. Please choose one."); - } - - // Checking if the tables are requested in the workflow and enabling them - auto& workflows = initContext.services().get(); - for (DeviceSpec const& device : workflows.devices) { - for (auto const& input : device.inputs) { - if (input.matcher.binding == "TracksDCA") { - fillTracksDCA = true; - } - } - } - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - - if (d_UseAutodetectMode) { - LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); - LOGF(info, " Track propagator self-configuration"); - LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); - trackSels.SetTightSelections(); // Only loosen from this point forward - for (DeviceSpec const& device : workflows.devices) { - // Loop over options to find track selection - for (auto const& option : device.options) { - if (hasEnding(option.name, ".requireTPC")) { - bool lVal = option.defaultValue.get(); - LOGF(info, "Device %s, request TPC: %i", device.name, lVal); - if (trackSels.getRequireTPC() == false) - trackSels.setRequireTPC(lVal); - } - if (hasEnding(option.name, ".minTPCclusters")) { - int lVal = option.defaultValue.get(); - LOGF(info, "Device %s, min TPC clusters: %i", device.name, lVal); - if (trackSels.getMinTPCClusters() > lVal) - trackSels.setMinTPCClusters(lVal); - } - if (hasEnding(option.name, ".minTPCcrossedrows")) { - int lVal = option.defaultValue.get(); - LOGF(info, "Device %s, min TPC crossed rows: %i", device.name, lVal); - if (trackSels.getMinTPCCrossedRows() > lVal) - trackSels.setMinTPCCrossedRows(lVal); - } - if (hasEnding(option.name, ".minTPCcrossedrowsoverfindable")) { - float lVal = option.defaultValue.get(); - LOGF(info, "Device %s, min TPC crossed rows over findable: %.3f", device.name, lVal); - if (trackSels.getMinTPCCrossedRowsOverFindable() > lVal) - trackSels.setMinTPCCrossedRowsOverFindable(lVal); - } - if (hasEnding(option.name, ".requireITS")) { - bool lVal = option.defaultValue.get(); - LOGF(info, "Device %s, request ITS: %i", device.name, lVal); - if (trackSels.getRequireITS() == false) - trackSels.setRequireITS(lVal); - } - if (hasEnding(option.name, ".minITSclusters")) { - int lVal = option.defaultValue.get(); - LOGF(info, "Device %s, minimum ITS clusters: %i", device.name, lVal); - if (trackSels.getMinITSClusters() > lVal) - trackSels.setMinITSClusters(lVal); - } - if (hasEnding(option.name, ".maxITSChi2percluster")) { - float lVal = option.defaultValue.get(); - LOGF(info, "Device %s, max ITS chi2/clu: %.3f", device.name, lVal); - if (trackSels.getMaxITSChi2PerCluster() < lVal) - trackSels.setMaxITSChi2PerCluster(lVal); - } - } - } - LOGF(info, "-+*> Automatic self-config ended. Final settings:"); - trackSels.PrintSelections(); - } - } - - void initCCDB(aod::BCsWithTimestamps::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); - o2::base::Propagator::Instance()->setMatLUT(lut); - if (propagateUnassociated) - mVtx = ccdb->getForTimeStamp(mVtxPath, bc.timestamp()); - runNumber = bc.runNumber(); - } - - template - void FillTracksPar(TTrack& track, aod::track::TrackTypeEnum trackType, TTrackPar& trackPar) - { - tracksParPropagated(track.collisionId(), trackType, trackPar.getX(), trackPar.getAlpha(), trackPar.getY(), trackPar.getZ(), trackPar.getSnp(), trackPar.getTgl(), trackPar.getQ2Pt()); - tracksParExtensionPropagated(trackPar.getPt(), trackPar.getP(), trackPar.getEta(), trackPar.getPhi()); - } - - void processStandard(soa::Join const& tracks, aod::Collisions const&, aod::BCsWithTimestamps const& bcs) - { - if (bcs.size() == 0) { - return; - } - initCCDB(bcs.begin()); - - gpu::gpustd::array dcaInfo; - - int lNAll = 0; - int lNaccTPC = 0; - int lNaccNotTPCOnly = 0; - int lNPropagated = 0; - bool passTPCclu = kFALSE; - bool passNotTPCOnly = kFALSE; - - for (auto& track : tracks) { - // Selection criteria - passTPCclu = kFALSE; - passNotTPCOnly = kFALSE; - lNAll++; - if (track.tpcNClsFound() >= minTPCClusters) { - passTPCclu = kTRUE; - lNaccTPC++; - } - if ((track.hasTPC() && !track.hasITS() && !track.hasTRD() && !track.hasTOF()) || propagateTPConly) { - passNotTPCOnly = kTRUE; - lNaccNotTPCOnly++; - } - - dcaInfo[0] = 999; - dcaInfo[1] = 999; - aod::track::TrackTypeEnum trackType = (aod::track::TrackTypeEnum)track.trackType(); - auto trackPar = getTrackPar(track); - // 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 && passTPCclu && passNotTPCOnly) { - if (track.has_collision()) { - auto const& collision = track.collision(); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, maxPropagStep, matCorr, &dcaInfo); - trackType = aod::track::Track; - lNPropagated++; - } else { - if (propagateUnassociated) { - o2::base::Propagator::Instance()->propagateToDCABxByBz({mVtx->getX(), mVtx->getY(), mVtx->getZ()}, trackPar, maxPropagStep, matCorr, &dcaInfo); - trackType = aod::track::Track; - lNPropagated++; - } - } - } - FillTracksPar(track, trackType, trackPar); - if (fillTracksDCA) { - tracksDCA(dcaInfo[0], dcaInfo[1]); - } - } - // Fill only per table (not per track). ROOT FindBin is slow - histos.fill(HIST("hTrackCounter"), 0.5, lNAll); - histos.fill(HIST("hTrackCounter"), 1.5, lNaccTPC); - histos.fill(HIST("hTrackCounter"), 2.5, lNaccNotTPCOnly); - histos.fill(HIST("hTrackCounter"), 3.5, lNPropagated); - } - PROCESS_SWITCH(TrackPropagationTester, processStandard, "Process without covariance", true); - - void processCovariance(soa::Join const& tracks, aod::Collisions const&, aod::BCsWithTimestamps const& bcs) - { - if (bcs.size() == 0) { - return; - } - initCCDB(bcs.begin()); - - o2::dataformats::DCA dcaInfoCov; - o2::dataformats::VertexBase vtx; - - int lNAll = 0; - int lNaccTPC = 0; - int lNaccNotTPCOnly = 0; - int lNPropagated = 0; - bool passTPCclu = kFALSE; - bool passNotTPCOnly = kFALSE; - - for (auto& track : tracks) { - // Selection criteria - passTPCclu = kFALSE; - passNotTPCOnly = kFALSE; - lNAll++; - if (track.tpcNClsFound() >= minTPCClusters) { - passTPCclu = kTRUE; - lNaccTPC++; - } - if ((track.hasTPC() && !track.hasITS() && !track.hasTRD() && !track.hasTOF()) || propagateTPConly) { - passNotTPCOnly = kTRUE; - lNaccNotTPCOnly++; - } - - dcaInfoCov.set(999, 999, 999, 999, 999); - auto trackParCov = getTrackParCov(track); - aod::track::TrackTypeEnum trackType = (aod::track::TrackTypeEnum)track.trackType(); - // 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 && passTPCclu && passNotTPCOnly) { - if (track.has_collision()) { - auto const& collision = track.collision(); - vtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); - vtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - o2::base::Propagator::Instance()->propagateToDCABxByBz(vtx, trackParCov, maxPropagStep, matCorr, &dcaInfoCov); - trackType = aod::track::Track; - lNPropagated++; - } else { - if (propagateUnassociated) { - vtx.setPos({mVtx->getX(), mVtx->getY(), mVtx->getZ()}); - vtx.setCov(mVtx->getSigmaX() * mVtx->getSigmaX(), 0.0f, mVtx->getSigmaY() * mVtx->getSigmaY(), 0.0f, 0.0f, mVtx->getSigmaZ() * mVtx->getSigmaZ()); - o2::base::Propagator::Instance()->propagateToDCABxByBz(vtx, trackParCov, maxPropagStep, matCorr, &dcaInfoCov); - trackType = aod::track::Track; - lNPropagated++; - } - } - } - FillTracksPar(track, trackType, trackParCov); - if (fillTracksDCA) { - tracksDCA(dcaInfoCov.getY(), dcaInfoCov.getZ()); - } - // TODO do we keep the rho as 0? Also the sigma's are duplicated information - tracksParCovPropagated(std::sqrt(trackParCov.getSigmaY2()), std::sqrt(trackParCov.getSigmaZ2()), std::sqrt(trackParCov.getSigmaSnp2()), - std::sqrt(trackParCov.getSigmaTgl2()), std::sqrt(trackParCov.getSigma1Pt2()), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - tracksParCovExtensionPropagated(trackParCov.getSigmaY2(), trackParCov.getSigmaZY(), trackParCov.getSigmaZ2(), trackParCov.getSigmaSnpY(), - trackParCov.getSigmaSnpZ(), trackParCov.getSigmaSnp2(), trackParCov.getSigmaTglY(), trackParCov.getSigmaTglZ(), trackParCov.getSigmaTglSnp(), - trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), - trackParCov.getSigma1Pt2()); - } - // Fill only per table (not per track). ROOT FindBin is slow - histos.fill(HIST("hTrackCounter"), 0.5, lNAll); - histos.fill(HIST("hTrackCounter"), 1.5, lNaccTPC); - histos.fill(HIST("hTrackCounter"), 2.5, lNaccNotTPCOnly); - histos.fill(HIST("hTrackCounter"), 3.5, lNPropagated); - } - PROCESS_SWITCH(TrackPropagationTester, processCovariance, "Process with covariance", false); -}; - -//**************************************************************************************** -/** - * Workflow definition. - */ -//**************************************************************************************** -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; - return workflow; -} diff --git a/Common/TableProducer/trackToCollisionAssociator.cxx b/Common/TableProducer/trackToCollisionAssociator.cxx index 62d90edaa9f..f789c250cac 100644 --- a/Common/TableProducer/trackToCollisionAssociator.cxx +++ b/Common/TableProducer/trackToCollisionAssociator.cxx @@ -18,9 +18,13 @@ #include "Common/Core/CollisionAssociation.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/trackextension.cxx b/Common/TableProducer/trackextension.cxx index 205be621f76..e17965c1ed1 100644 --- a/Common/TableProducer/trackextension.cxx +++ b/Common/TableProducer/trackextension.cxx @@ -13,18 +13,23 @@ // Task performing basic track selection. // -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Multiplicity.h" #include "Common/Core/trackUtilities.h" -#include "ReconstructionDataFormats/DCA.h" -#include "DetectorsBase/Propagator.h" -#include "CommonUtils/NameConf.h" -#include "DataFormatsParameters/GRPObject.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; @@ -134,7 +139,7 @@ struct TrackExtension { } auto trackPar = getTrackPar(track); auto const& collision = track.collision(); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; if (o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, matCorr, &dcaInfo)) { dca[0] = dcaInfo[0]; dca[1] = dcaInfo[1]; diff --git a/Common/TableProducer/trackselection.cxx b/Common/TableProducer/trackselection.cxx index 8ce5a88e0bd..47b5cb3087b 100644 --- a/Common/TableProducer/trackselection.cxx +++ b/Common/TableProducer/trackselection.cxx @@ -17,14 +17,21 @@ /// \brief Task performing basic track selection. /// -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Common/Core/TrackSelection.h" + +#include "Common/Core/TableHelper.h" #include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/trackUtilities.h" -#include "TableHelper.h" + +#include +#include +#include +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; @@ -149,7 +156,7 @@ struct TrackSelectionTask { return; } if (isRun3) { - for (auto& track : tracks) { + for (const auto& track : tracks) { if (produceTable == 1) { filterTable((uint8_t)0, @@ -190,7 +197,7 @@ struct TrackSelectionTask { return; } - for (auto& track : tracks) { + for (const auto& track : tracks) { o2::aod::track::TrackSelectionFlags::flagtype trackflagGlob = globalTracks.IsSelectedMask(track); if (produceTable == 1) { filterTable((uint8_t)globalTracksSDD.IsSelected(track), diff --git a/Common/TableProducer/weakDecayIndices.cxx b/Common/TableProducer/weakDecayIndices.cxx index b2937e1c8a5..0c9a33345bc 100644 --- a/Common/TableProducer/weakDecayIndices.cxx +++ b/Common/TableProducer/weakDecayIndices.cxx @@ -8,9 +8,10 @@ // In applying this license CERN does 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 +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/TableProducer/zdcExtraTableProducer.cxx b/Common/TableProducer/zdcExtraTableProducer.cxx new file mode 100644 index 00000000000..500854b196b --- /dev/null +++ b/Common/TableProducer/zdcExtraTableProducer.cxx @@ -0,0 +1,329 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file zdcExtraTableProducer.cxx +/// \brief Task creating table with ZDC PMTs energies and calculated centroid (Q-vector) to be used for spectator plane measurement +/// \author Chiara Oppedisano , INFN Torino +/// \author Uliana Dmitrieva , INFN Torino + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/ZDCExtra.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::evsel; + +using BCsRun3 = soa::Join; +using ColEvSels = soa::Join; + +struct ZdcExtraTableProducer { + + Produces zdcextras; + + // 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"}; + Configurable cfgUsePMC{"cfgUsePMC", true, "Use common PM (true) or sum of PMs (false) "}; + // Event selections + Configurable cfgEvSelSel8{"cfgEvSelSel8", true, "Event selection: sel8"}; + Configurable cfgEvSelVtxZ{"cfgEvSelVtxZ", 10, "Event selection: zVtx"}; + Configurable cfgEvSelsDoOccupancySel{"cfgEvSelsDoOccupancySel", true, "Event selection: do occupancy selection"}; + Configurable cfgEvSelsMaxOccupancy{"cfgEvSelsMaxOccupancy", 10000, "Event selection: set max occupancy"}; + Configurable cfgEvSelsNoSameBunchPileupCut{"cfgEvSelsNoSameBunchPileupCut", true, "Event selection: no same bunch pileup cut"}; + Configurable cfgEvSelsIsGoodZvtxFT0vsPV{"cfgEvSelsIsGoodZvtxFT0vsPV", true, "Event selection: is good ZVTX FT0 vs PV"}; + Configurable cfgEvSelsNoCollInTimeRangeStandard{"cfgEvSelsNoCollInTimeRangeStandard", true, "Event selection: no collision in time range standard"}; + Configurable cfgEvSelsIsVertexITSTPC{"cfgEvSelsIsVertexITSTPC", true, "Event selection: is vertex ITSTPC"}; + Configurable cfgEvSelsIsGoodITSLayersAll{"cfgEvSelsIsGoodITSLayersAll", true, "Event selection: is good ITS layers all"}; + // Calibration settings + Configurable cfgCalibrationDownscaling{"cfgCalibrationDownscaling", 1.f, "Percentage of events to be saved to derived table"}; + + HistogramRegistry registry{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + enum SelectionCriteria { + evSel_zvtx, + evSel_sel8, + evSel_occupancy, + evSel_kNoSameBunchPileup, + evSel_kIsGoodZvtxFT0vsPV, + evSel_kNoCollInTimeRangeStandard, + evSel_kIsVertexITSTPC, + evSel_kIsGoodITSLayersAll, + evSel_allEvents, + nEventSelections + }; + + 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}}}); + + registry.add("ZNACentroid", "ZNA Centroid; X; Y", {HistType::kTH2F, {{50, -1.5, 1.5}, {50, -1.5, 1.5}}}); + registry.add("ZNCCentroid", "ZNC Centroid; X; Y", {HistType::kTH2F, {{50, -1.5, 1.5}, {50, -1.5, 1.5}}}); + + registry.add("hEventCount", "Number of Event; Cut; #Events Passed Cut", {HistType::kTH1D, {{nEventSelections, 0, nEventSelections}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_allEvents + 1, "All events"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_zvtx + 1, "vtxZ"); + 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_kIsGoodITSLayersAll + 1, "kIsGoodITSLayersAll"); + } + + template + uint8_t eventSelected(TCollision collision) + { + uint8_t selectionBits = 0; + bool selected; + + registry.fill(HIST("hEventCount"), evSel_allEvents); + + selected = std::fabs(collision.posZ()) < cfgEvSelVtxZ; + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_zvtx); + registry.fill(HIST("hEventCount"), evSel_zvtx); + } + + selected = collision.sel8(); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_sel8); + registry.fill(HIST("hEventCount"), evSel_sel8); + } + + auto occupancy = collision.trackOccupancyInTimeRange(); + selected = occupancy <= cfgEvSelsMaxOccupancy; + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_occupancy); + registry.fill(HIST("hEventCount"), evSel_occupancy); + } + + selected = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kNoSameBunchPileup); + registry.fill(HIST("hEventCount"), evSel_kNoSameBunchPileup); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kIsGoodZvtxFT0vsPV); + registry.fill(HIST("hEventCount"), evSel_kIsGoodZvtxFT0vsPV); + } + + selected = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kNoCollInTimeRangeStandard); + registry.fill(HIST("hEventCount"), evSel_kNoCollInTimeRangeStandard); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kIsVertexITSTPC); + registry.fill(HIST("hEventCount"), evSel_kIsVertexITSTPC); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kIsGoodITSLayersAll); + registry.fill(HIST("hEventCount"), evSel_kIsGoodITSLayersAll); + } + + return selectionBits; + } + + void process(ColEvSels const& cols, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcs*/) + { + // collision-based event selection + int nTowers = 4; // number of ZDC towers + + for (auto const& collision : cols) { + const auto& foundBC = collision.foundBC_as(); + if (foundBC.has_zdc()) { + const auto& zdc = foundBC.zdc(); + + uint8_t evSelection = eventSelected(collision); + + float centrality = collision.centFT0C(); + + // 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] = {}; + double pmqZNA[4] = {}; + // + if (isZNChit) { + for (int it = 0; it < nTowers; 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 < nTowers; 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); + } + + // Q-vectors (centroid) calculation + // kBeamEne -- LHC Run 3 Pb-Pb collision energy (5.36 TeV per nucleon pair) + constexpr float kBeamEne = 5.36 * 0.5; + + // Provide coordinates of centroid over ZN (side C) front face + 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 kAlpha = 0.395; // saturation correction + + float numXZNC = 0., numYZNC = 0., denZNC = 0.; + float numXZNA = 0., numYZNA = 0., denZNA = 0.; + + // Calculate weighted sums of the x and y coordinates + constexpr int kNTowers = 4; // number of ZDC towers + for (int i = 0; i < kNTowers; i++) { + if (pmqZNC[i] > 0.) { + float wZNC = std::pow(pmqZNC[i], kAlpha); + numXZNC -= X[i] * wZNC; // numerator x (minus sign due to opposite orientation of ZNC) + numYZNC += Y[i] * wZNC; // numerator y + denZNC += wZNC; // denominator + } + if (pmqZNA[i] > 0.) { + float wZNA = std::pow(pmqZNA[i], kAlpha); + numXZNA += X[i] * wZNA; // numerator x + numYZNA += Y[i] * wZNA; // numerator y + denZNA += wZNA; // denominator + } + } + // Calculate centroid coordinates (in cm) with correction factor c depending on the number of spectator nucleons (nSpec) + + float zncCommon = 0; + float znaCommon = 0; + + // Use sum of PMTs (cfgUsePMC == false) when common PMT is saturated + if (cfgUsePMC) { + zncCommon = pmcZNC; + znaCommon = pmcZNA; + } else { + zncCommon = sumZNC; + znaCommon = sumZNA; + } + + float centroidZNC[2], centroidZNA[2]; + + if (denZNC != 0.) { + float nSpecnC = zncCommon / kBeamEne; + float cZNC = 1.89358 - 0.71262 / (nSpecnC + 0.71789); + centroidZNC[0] = cZNC * numXZNC / denZNC; + centroidZNC[1] = cZNC * numYZNC / denZNC; + } else { + centroidZNC[0] = 999.; + centroidZNC[1] = 999.; + } + // + if (denZNA != 0.) { + float nSpecnA = znaCommon / kBeamEne; + float cZNA = 1.89358 - 0.71262 / (nSpecnA + 0.71789); + centroidZNA[0] = cZNA * numXZNA / denZNA; + centroidZNA[1] = cZNA * numYZNA / denZNA; + } else { + centroidZNA[0] = 999.; + centroidZNA[1] = 999.; + } + registry.get(HIST("ZNCCentroid"))->Fill(centroidZNC[0], centroidZNC[1]); + registry.get(HIST("ZNACentroid"))->Fill(centroidZNA[0], centroidZNA[1]); + + auto vz = collision.posZ(); + auto vx = collision.posX(); + auto vy = collision.posY(); + + if ((isZNAhit || isZNChit) && (gRandom->Uniform() < cfgCalibrationDownscaling)) { + zdcextras(pmcZNA, pmqZNA[0], pmqZNA[1], pmqZNA[2], pmqZNA[3], tdcZNA, centroidZNA[0], centroidZNA[1], pmcZNC, pmqZNC[0], pmqZNC[1], pmqZNC[2], pmqZNC[3], tdcZNC, centroidZNC[0], centroidZNC[1], centrality, vx, vy, vz, foundBC.timestamp(), foundBC.runNumber(), evSelection); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Common/TableProducer/zdcTaskLightIons.cxx b/Common/TableProducer/zdcTaskLightIons.cxx new file mode 100644 index 00000000000..2e496b3a5d2 --- /dev/null +++ b/Common/TableProducer/zdcTaskLightIons.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 zdcTaskLightIons.cxx +/// \brief Task for ZDC in light ions +/// \author chiara.oppedisano@cern.ch + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.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/ZDCLightIons.h" + +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::evsel; + +using BCsRun3 = soa::Join; +using ColEvSels = soa::Join; + +struct ZdcTaskLightIons { + + Produces zdcTableLI; + + // Configurable parameters + Configurable nBinsTiming{"nBinsTiming", 200, "n bins for debunching histo"}; + Configurable tdcCut{"tdcCut", true, "Flag for TDC cut"}; + Configurable tdcZNmincut{"tdcZNmincut", -2.5, "Min. ZN TDC cut value"}; + Configurable tdcZNmaxcut{"tdcZNmaxcut", 2.5, "Max. ZN TDC cut value"}; + // + // Event selections + Configurable cfgEvSelVtxZ{"cfgEvSelVtxZ", 10, "Event selection: zVtx"}; + Configurable cfgEvSelSel8{"cfgEvSelSel8", true, "Event selection: sel8"}; + Configurable cfgEvSelsDoOccupancySel{"cfgEvSelsDoOccupancySel", true, "Event selection: do occupancy selection"}; + Configurable cfgEvSelsMaxOccupancy{"cfgEvSelsMaxOccupancy", 10000, "Event selection: set max occupancy"}; + Configurable cfgEvSelsNoSameBunchPileupCut{"cfgEvSelsNoSameBunchPileupCut", true, "Event selection: no same bunch pileup cut"}; + Configurable cfgEvSelsIsGoodZvtxFT0vsPV{"cfgEvSelsIsGoodZvtxFT0vsPV", true, "Event selection: is good ZVTX FT0 vs PV"}; + Configurable cfgEvSelsNoCollInTimeRangeStandard{"cfgEvSelsNoCollInTimeRangeStandard", true, "Event selection: no collision in time range standard"}; + Configurable cfgEvSelsIsVertexITSTPC{"cfgEvSelsIsVertexITSTPC", true, "Event selection: is vertex ITSTPC"}; + Configurable cfgEvSelsIsGoodITSLayersAll{"cfgEvSelsIsGoodITSLayersAll", true, "Event selection: is good ITS layers all"}; + // + HistogramRegistry registry{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + enum SelectionCriteria { + evSel_zvtx, + evSel_sel8, + evSel_occupancy, + evSel_kNoSameBunchPileup, + evSel_kIsGoodZvtxFT0vsPV, + evSel_kNoCollInTimeRangeStandard, + evSel_kNoITSROFrameBorder, + evSel_kIsGoodITSLayersAll, + evSel_allEvents, + nEventSelections + }; + + void init(InitContext const&) + { + registry.add("zdcDebunchHist", "ZN sum vs. diff; ZNA-ZNC (ns); ZNA+ZNC (ns)", {HistType::kTH2D, {{nBinsTiming, -20., 20.}, {nBinsTiming, -20., 20.}}}); + + if (doprocessALICEcoll) { + registry.add("hEventCount", "Number of Event; Cut; #Events Passed Cut", {HistType::kTH1D, {{nEventSelections, 0, nEventSelections}}}); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_allEvents + 1, "All events"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_zvtx + 1, "vtxZ"); + 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_kNoITSROFrameBorder + 1, "kNoITSROFrameBorder"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayersAll + 1, "kkIsGoodITSLayersAll"); + } + } + + template + uint8_t eventSelected(TCollision collision) + { + uint8_t selectionBits = 0; + bool selected; + + registry.fill(HIST("hEventCount"), evSel_allEvents); + + selected = std::fabs(collision.posZ()) < cfgEvSelVtxZ; + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_zvtx); + registry.fill(HIST("hEventCount"), evSel_zvtx); + } + + selected = collision.sel8(); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_sel8); + registry.fill(HIST("hEventCount"), evSel_sel8); + } + + auto occupancy = collision.trackOccupancyInTimeRange(); + selected = occupancy <= cfgEvSelsMaxOccupancy; + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_occupancy); + registry.fill(HIST("hEventCount"), evSel_occupancy); + } + + selected = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kNoSameBunchPileup); + registry.fill(HIST("hEventCount"), evSel_kNoSameBunchPileup); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kIsGoodZvtxFT0vsPV); + registry.fill(HIST("hEventCount"), evSel_kIsGoodZvtxFT0vsPV); + } + + selected = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kNoCollInTimeRangeStandard); + registry.fill(HIST("hEventCount"), evSel_kNoCollInTimeRangeStandard); + } + + selected = collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kNoITSROFrameBorder); + registry.fill(HIST("hEventCount"), evSel_kNoITSROFrameBorder); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); + if (selected) { + selectionBits |= (uint8_t)(0x1u << evSel_kIsGoodITSLayersAll); + registry.fill(HIST("hEventCount"), evSel_kIsGoodITSLayersAll); + } + + return selectionBits; + } + + void processZDCBC(BCsRun3 const& bcs, aod::Zdcs const& /*zdcs*/) + { + for (const auto& bc : bcs) { + if (bc.has_zdc()) { + + auto tdcZNA = bc.zdc().timeZNA(); + auto tdcZNC = bc.zdc().timeZNC(); + auto tdcZPA = bc.zdc().timeZPA(); + auto tdcZPC = bc.zdc().timeZPC(); + auto tdcZEM1 = bc.zdc().timeZEM1(); + auto tdcZEM2 = bc.zdc().timeZEM2(); + // + double zna = bc.zdc().amplitudeZNA(); + double znc = bc.zdc().amplitudeZNC(); + double zpa = bc.zdc().amplitudeZPA(); + double zpc = bc.zdc().amplitudeZPC(); + double zem1 = bc.zdc().amplitudeZEM1(); + double zem2 = bc.zdc().amplitudeZEM2(); + // + double pmcZNA = bc.zdc().energyCommonZNA(); + double pmcZNC = bc.zdc().energyCommonZNC(); + double pmcZPA = bc.zdc().energyCommonZPA(); + double pmcZPC = bc.zdc().energyCommonZPC(); + double pmqZNC[4] = { + 0, + 0, + 0, + 0, + }; + double pmqZNA[4] = { + 0, + 0, + 0, + 0, + }; + const int noofZNsectors = 4; + for (int itow = 0; itow < noofZNsectors; itow++) { + pmqZNA[itow] = (bc.zdc().energySectorZNA())[itow]; + pmqZNC[itow] = (bc.zdc().energySectorZNC())[itow]; + } + + bool isZNChit = false, isZNAhit = false; + 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 > 0.) { + isZNChit = true; + } + if (pmcZNA > 0.) { + isZNAhit = true; + } + } + if (isZNChit && isZNAhit) { + registry.get(HIST("zdcDebunchHist"))->Fill(zna - znc, zna + znc); + } + + zdcTableLI(tdcZNA, zna, pmcZNA, pmqZNA[0], pmqZNA[1], pmqZNA[2], pmqZNA[3], + tdcZNC, znc, pmcZNC, pmqZNC[0], pmqZNC[1], pmqZNC[2], pmqZNC[3], + tdcZPA, zpa, pmcZPA, + tdcZPC, zpc, pmcZPC, + tdcZEM1, zem1, tdcZEM2, zem2, + -1, -1, -1, + -1., + -1, -1, -1, + bc.timestamp(), + -1); + } + } + } + /// name, description, function pointer, default value + /// note that it has to be declared after the function, so that the pointer is known + PROCESS_SWITCH(ZdcTaskLightIons, processZDCBC, "Processing ZDC 4 auto-triggered events", true); + + void processALICEcoll(ColEvSels const& cols, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0*/) + { + // collision-based event selection + for (auto const& collision : cols) { + + const auto& foundBC = collision.foundBC_as(); + uint8_t evSelection = eventSelected(collision); + auto zv = collision.posZ(); + auto centralityFT0C = collision.centFT0C(); + auto centralityFT0A = collision.centFT0A(); + auto centralityFT0M = collision.centFT0M(); + + // FT0 + float multFT0A = 0.; + float multFT0C = 0.; + if (foundBC.has_ft0()) { + for (auto const& amplitude : foundBC.ft0().amplitudeA()) { + multFT0A += amplitude; + } + for (auto const& amplitude : foundBC.ft0().amplitudeC()) { + multFT0C += amplitude; + } + } + // FV0 + float multV0A = 0; + if (foundBC.has_fv0a()) { + for (auto const& amplitude : foundBC.fv0a().amplitude()) { + multV0A += amplitude; + } + } + + if (foundBC.has_zdc()) { + const auto& zdc = foundBC.zdc(); + + auto tdcZNA = zdc.timeZNA(); + auto tdcZNC = zdc.timeZNC(); + auto tdcZPA = zdc.timeZPA(); + auto tdcZPC = zdc.timeZPC(); + auto tdcZEM1 = zdc.timeZEM1(); + auto tdcZEM2 = zdc.timeZEM2(); + // + double zna = zdc.amplitudeZNA(); + double znc = zdc.amplitudeZNC(); + double zpa = zdc.amplitudeZPA(); + double zpc = zdc.amplitudeZPC(); + double zem1 = zdc.amplitudeZEM1(); + double zem2 = zdc.amplitudeZEM2(); + // + double pmcZNA = zdc.energyCommonZNA(); + double pmcZNC = zdc.energyCommonZNC(); + double pmcZPA = zdc.energyCommonZPA(); + double pmcZPC = zdc.energyCommonZPC(); + double pmqZNC[4] = { + 0, + 0, + 0, + 0, + }; + double pmqZNA[4] = { + 0, + 0, + 0, + 0, + }; + const int noofZNsectors = 4; + for (int itow = 0; itow < noofZNsectors; itow++) { + pmqZNA[itow] = (zdc.energySectorZNA())[itow]; + pmqZNC[itow] = (zdc.energySectorZNC())[itow]; + } + + bool isZNChit = false, isZNAhit = false; + 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 > 0.) { + isZNChit = true; + } + if (pmcZNA > 0.) { + isZNAhit = true; + } + } + if (isZNChit && isZNAhit) { + registry.get(HIST("zdcDebunchHist"))->Fill(zna - znc, zna + znc); + } + + zdcTableLI(tdcZNA, zna, pmcZNA, pmqZNA[0], pmqZNA[1], pmqZNA[2], pmqZNA[3], + tdcZNC, znc, pmcZNC, pmqZNC[0], pmqZNC[1], pmqZNC[2], pmqZNC[3], + tdcZPA, zpa, pmcZPA, + tdcZPC, zpc, pmcZPC, + tdcZEM1, zem1, tdcZEM2, zem2, + multFT0A, multFT0C, multV0A, + zv, + centralityFT0C, centralityFT0A, centralityFT0M, + foundBC.timestamp(), + evSelection); + } + } + } + /// name, description, function pointer, default value + /// note that it has to be declared after the function, so that the pointer is known + PROCESS_SWITCH(ZdcTaskLightIons, processALICEcoll, "Processing ZDC for ALICE collisions", true); +}; + +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 2884d3b8b31..e60d7838882 100644 --- a/Common/Tasks/CMakeLists.txt +++ b/Common/Tasks/CMakeLists.txt @@ -81,5 +81,20 @@ o2physics_add_dpl_workflow(qvectors-correction o2physics_add_dpl_workflow(centrality-study SOURCES centralityStudy.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB + 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 qaMuon.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) + +o2physics_add_dpl_workflow(zdc-table-reader + SOURCES zdcTableReader.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/Common/Tasks/centralityQa.cxx b/Common/Tasks/centralityQa.cxx index 9e39194415c..51dc8875e08 100644 --- a/Common/Tasks/centralityQa.cxx +++ b/Common/Tasks/centralityQa.cxx @@ -8,13 +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. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/TriggerAliases.h" #include "Common/DataModel/Centrality.h" -#include "TH1F.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/Tasks/centralityStudy.cxx b/Common/Tasks/centralityStudy.cxx index f24fa99f9e2..a8765e488fc 100644 --- a/Common/Tasks/centralityStudy.cxx +++ b/Common/Tasks/centralityStudy.cxx @@ -13,59 +13,176 @@ // 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 "EventSelectionParams.h" + +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TH1F.h" -#include "TH2F.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using BCsWithRun3Matchings = soa::Join; +#define getHist(type, name) std::get>(histPointers[name]) struct centralityStudy { // Raw multiplicities HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::map histPointers; + std::string histPath; + Service ccdb; + ctpRateFetcher mRateFetcher; + int mRunNumber; + uint64_t startOfRunTimestamp; + + // vertex Z equalization + TList* hCalibObjects; + TProfile* hVtxZFV0A; + TProfile* hVtxZFT0A; + TProfile* hVtxZFT0C; + TProfile* hVtxZNTracks; + TProfile* hVtxZNGlobals; + TProfile* hVtxZMFT; + TProfile* hVtxZFDDA; + TProfile* hVtxZFDDC; // Configurables + Configurable applyVertexZEqualization{"applyVertexZEqualization", false, "0 - no, 1 - yes"}; + 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 doTimeStudies{"doTimeStudies", true, "0 - no, 1 - yes"}; + Configurable doTimeStudyFV0AOuterVsFT0A3d{"doTimeStudyFV0AOuterVsFT0A3d", 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 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 rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC"}; - Configurable minTimeDelta{"minTimeDelta", -1.0f, "reject collision if another collision is this close or less in time"}; - // Configurable Axes - ConfigurableAxis axisMultFT0C{"axisMultFT0C", {2000, 0, 100000}, "FT0C amplitude"}; + 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", -1.0f, "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"}; + + Configurable ccdbURL{"ccdbURL", "http://alice-ccdb.cern.ch", "ccdb url"}; + Configurable pathGRPECSObject{"pathGRPECSObject", "GLO/Config/GRPECS", "Path to GRPECS object"}; + Configurable pathVertexZ{"pathVertexZ", "Users/d/ddobrigk/Centrality/Calibration", "Path to vertexZ profiles"}; + Configurable irSource{"irSource", "ZNC hadronic", "Source of the interaction rate: (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + Configurable irCrashOnNull{"irCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; + Configurable irDoRateVsTime{"irDoRateVsTime", true, "Do IR plots"}; + + // _______________________________________ + // 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 axisMultMCCounts{"axisMultMCCounts", {1000, 0, 5000}, "N_{ch}"}; + + 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 axisImpactParameter{"axisImpactParameter", {200, 0.0f, 20.0f}, "b (fm)"}; ConfigurableAxis axisPVChi2{"axisPVChi2", {300, 0, 30}, "FT0C percentile"}; ConfigurableAxis axisDeltaTime{"axisDeltaTime", {300, 0, 300}, "#Delta time"}; + ConfigurableAxis axisDeltaTimestamp{"axisDeltaTimestamp", {1440, 0, 24}, "#Delta timestamp - sor (hours)"}; + ConfigurableAxis axisInteractionRate{"axisInteractionRate", {500, 0, 100}, "Binning for the interaction rate (kHz)"}; + ConfigurableAxis axisMultCoarseFV0A{"axisMultCoarseFV0A", {350, 0, 70000}, "FV0A amplitude"}; + + // 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&) { + hCalibObjects = nullptr; + hVtxZFV0A = nullptr; + hVtxZFT0A = nullptr; + hVtxZFT0C = nullptr; + hVtxZNTracks = nullptr; + hVtxZNGlobals = nullptr; + hVtxZMFT = nullptr; + hVtxZFDDA = nullptr; + hVtxZFDDC = nullptr; + if (doprocessCollisions || doprocessCollisionsWithCentrality) { const AxisSpec axisCollisions{100, -0.5f, 99.5f, "Number of collisions"}; histos.add("hCollisionSelection", "hCollisionSelection", kTH1D, {{20, -0.5f, +19.5f}}); @@ -80,29 +197,251 @@ struct centralityStudy { 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, {{10, -0.5, 9.5f}}); + 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", kTH2F, {axisPVz, axisPVz}); + histos.add("hZNAvsFT0C_BCs", "hZNAvsFT0C_BCs", kTH2F, {axisMultFT0C, axisZN}); + histos.add("hZNCvsFT0C_BCs", "hZNCvsFT0C_BCs", kTH2F, {axisMultFT0C, axisZN}); } if (do2DPlots) { - histos.add("hFT0CvsNContribs", "hFT0CvsNContribs", kTH2F, {axisMultPVContributors, axisMultFT0C}); + 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}); + histos.add("hNGlobalTracksVsNTPV", "hNGlobalTracksVsNTPV", kTH2F, {axisMultPVContributors, axisMultGlobalTracks}); + } + + if (doprocessCollisionsWithResolutionStudy) { + // histograms with detector signals + histos.add("hImpactParameterVsFT0A", "hImpactParameterVsFT0A", kTH2F, {axisMultFT0A, axisImpactParameter}); + histos.add("hImpactParameterVsFT0C", "hImpactParameterVsFT0C", kTH2F, {axisMultFT0C, axisImpactParameter}); + histos.add("hImpactParameterVsFT0M", "hImpactParameterVsFT0M", kTH2F, {axisMultFT0M, axisImpactParameter}); + histos.add("hImpactParameterVsFV0A", "hImpactParameterVsFV0A", kTH2F, {axisMultFV0A, axisImpactParameter}); + histos.add("hImpactParameterVsNMFTTracks", "hImpactParameterVsNMFTTracks", kTH2F, {axisMultMFTTracks, axisImpactParameter}); + histos.add("hImpactParameterVsNTPV", "hImpactParameterVsNTPV", kTH2F, {axisMultPVContributors, axisImpactParameter}); + + // histograms with actual MC counts in each region + histos.add("hImpactParameterVsMCFT0A", "hImpactParameterVsMCFT0A", kTH2F, {axisMultMCCounts, axisImpactParameter}); + histos.add("hImpactParameterVsMCFT0C", "hImpactParameterVsMCFT0C", kTH2F, {axisMultMCCounts, axisImpactParameter}); + histos.add("hImpactParameterVsMCFT0M", "hImpactParameterVsMCFT0M", kTH2F, {axisMultMCCounts, axisImpactParameter}); + histos.add("hImpactParameterVsMCFV0A", "hImpactParameterVsMCFV0A", kTH2F, {axisMultMCCounts, axisImpactParameter}); + } + + 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}); + } + } + + if (doTimeStudies) { + ccdb->setURL(ccdbURL); + // ccdb->setCaching(true); + // ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + if (doTimeStudyFV0AOuterVsFT0A3d) { + histos.add((histPath + "h3dFV0AVsTime").c_str(), "", {kTH3F, {{axisDeltaTimestamp, axisMultCoarseFV0A, axisMultCoarseFV0A}}}); + } + } + } + + template + void initRun(TCollision collision) + { + if (mRunNumber == collision.multRunNumber()) { + return; + } + + mRunNumber = collision.multRunNumber(); + LOGF(info, "Setting up for run: %i", mRunNumber); + + // only get object when switching runs + o2::parameters::GRPECSObject* grpo = ccdb->getForRun(pathGRPECSObject, mRunNumber); + startOfRunTimestamp = grpo->getTimeStart(); + + if (applyVertexZEqualization.value) { + // acquire vertex-Z equalization histograms if requested + LOGF(info, "Acquiring vertex-Z profiles for run %i", mRunNumber); + hCalibObjects = ccdb->getForRun(pathVertexZ, mRunNumber); + + hVtxZFV0A = static_cast(hCalibObjects->FindObject("hVtxZFV0A")); + hVtxZFT0A = static_cast(hCalibObjects->FindObject("hVtxZFT0A")); + hVtxZFT0C = static_cast(hCalibObjects->FindObject("hVtxZFT0C")); + // hVtxZFDDA = static_cast(hCalibObjects->FindObject("hVtxZFDDA")); + // hVtxZFDDC = static_cast(hCalibObjects->FindObject("hVtxZFDDC")); + hVtxZNTracks = static_cast(hCalibObjects->FindObject("hVtxZNTracksPV")); + hVtxZNGlobals = static_cast(hCalibObjects->FindObject("hVtxZNGlobals")); + hVtxZMFT = static_cast(hCalibObjects->FindObject("hVtxZMFT")); + + // Capture error + if (!hVtxZFV0A || !hVtxZFT0A || !hVtxZFT0C || !hVtxZNTracks || !hVtxZNGlobals || !hVtxZMFT) { + LOGF(error, "Problem loading CCDB objects! Please check"); + } + } + + histPath = std::format("Run_{}/", mRunNumber); + + if (doprocessCollisions || doprocessCollisionsWithCentrality) { + histPointers.insert({histPath + "hCollisionSelection", histos.add((histPath + "hCollisionSelection").c_str(), "hCollisionSelection", {kTH1D, {{20, -0.5f, +19.5f}}})}); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(1, "All collisions"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(2, "sel8 cut"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(3, "posZ cut"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(11, "Neighbour rejection"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(12, "no ITS in-ROF pileup (standard)"); + getHist(TH1, histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(13, "no ITS in-ROF pileup (strict)"); + + histPointers.insert({histPath + "hFT0C_Collisions", histos.add((histPath + "hFT0C_Collisions").c_str(), "hFT0C_Collisions", {kTH1D, {{axisMultUltraFineFT0C}}})}); + histPointers.insert({histPath + "hFT0M_Collisions", histos.add((histPath + "hFT0M_Collisions").c_str(), "hFT0M_Collisions", {kTH1D, {{axisMultUltraFineFT0M}}})}); + histPointers.insert({histPath + "hFV0A_Collisions", histos.add((histPath + "hFV0A_Collisions").c_str(), "hFV0A_Collisions", {kTH1D, {{axisMultUltraFineFV0A}}})}); + histPointers.insert({histPath + "hNGlobalTracks", histos.add((histPath + "hNGlobalTracks").c_str(), "hNGlobalTracks", {kTH1D, {{axisMultUltraFineGlobalTracks}}})}); + histPointers.insert({histPath + "hNMFTTracks", histos.add((histPath + "hNMFTTracks").c_str(), "hNMFTTracks", {kTH1D, {{axisMultUltraFineMFTTracks}}})}); + histPointers.insert({histPath + "hNPVContributors", histos.add((histPath + "hNPVContributors").c_str(), "hNPVContributors", {kTH1D, {{axisMultUltraFinePVContributors}}})}); + + if (applyVertexZEqualization) { + histPointers.insert({histPath + "hFT0C_Collisions_Unequalized", histos.add((histPath + "hFT0C_Collisions_Unequalized").c_str(), "hFT0C_Collisions_Unequalized", {kTH1D, {{axisMultUltraFineFT0C}}})}); + histPointers.insert({histPath + "hFT0M_Collisions_Unequalized", histos.add((histPath + "hFT0M_Collisions_Unequalized").c_str(), "hFT0M_Collisions_Unequalized", {kTH1D, {{axisMultUltraFineFT0M}}})}); + histPointers.insert({histPath + "hFV0A_Collisions_Unequalized", histos.add((histPath + "hFV0A_Collisions_Unequalized").c_str(), "hFV0A_Collisions_Unequalized", {kTH1D, {{axisMultUltraFineFV0A}}})}); + histPointers.insert({histPath + "hNGlobalTracks_Unequalized", histos.add((histPath + "hNGlobalTracks_Unequalized").c_str(), "hNGlobalTracks_Unequalized", {kTH1D, {{axisMultUltraFineGlobalTracks}}})}); + histPointers.insert({histPath + "hNMFTTracks_Unequalized", histos.add((histPath + "hNMFTTracks_Unequalized").c_str(), "hNMFTTracks_Unequalized", {kTH1D, {{axisMultUltraFineMFTTracks}}})}); + histPointers.insert({histPath + "hNPVContributors_Unequalized", histos.add((histPath + "hNPVContributors_Unequalized").c_str(), "hNPVContributors_Unequalized", {kTH1D, {{axisMultUltraFinePVContributors}}})}); + } + + histPointers.insert({histPath + "hFT0CvsPVz_Collisions_All", histos.add((histPath + "hFT0CvsPVz_Collisions_All").c_str(), "hFT0CvsPVz_Collisions_All", {kTProfile, {{axisPVz}}})}); + histPointers.insert({histPath + "hFT0AvsPVz_Collisions", histos.add((histPath + "hFT0AvsPVz_Collisions").c_str(), "hFT0AvsPVz_Collisions", {kTProfile, {{axisPVz}}})}); + histPointers.insert({histPath + "hFT0CvsPVz_Collisions", histos.add((histPath + "hFT0CvsPVz_Collisions").c_str(), "hFT0CvsPVz_Collisions", {kTProfile, {{axisPVz}}})}); + histPointers.insert({histPath + "hFV0AvsPVz_Collisions", histos.add((histPath + "hFV0AvsPVz_Collisions").c_str(), "hFV0AvsPVz_Collisions", {kTProfile, {{axisPVz}}})}); + histPointers.insert({histPath + "hNGlobalTracksvsPVz_Collisions", histos.add((histPath + "hNGlobalTracksvsPVz_Collisions").c_str(), "hNGlobalTracksvsPVz_Collisions", {kTProfile, {{axisPVz}}})}); + histPointers.insert({histPath + "hNMFTTracksvsPVz_Collisions", histos.add((histPath + "hNMFTTracksvsPVz_Collisions").c_str(), "hNMFTTracksvsPVz_Collisions", {kTProfile, {{axisPVz}}})}); + histPointers.insert({histPath + "hNTPVvsPVz_Collisions", histos.add((histPath + "hNTPVvsPVz_Collisions").c_str(), "hNTPVvsPVz_Collisions", {kTProfile, {{axisPVz}}})}); + } + + if (do2DPlots) { + histPointers.insert({histPath + "hNContribsVsFT0C", histos.add((histPath + "hNContribsVsFT0C").c_str(), "hNContribsVsFT0C", {kTH2F, {{axisMultFT0C, axisMultPVContributors}}})}); + histPointers.insert({histPath + "hNContribsVsFV0A", histos.add((histPath + "hNContribsVsFV0A").c_str(), "hNContribsVsFV0A", {kTH2F, {{axisMultFV0A, axisMultPVContributors}}})}); + histPointers.insert({histPath + "hMatchedVsITSOnly", histos.add((histPath + "hMatchedVsITSOnly").c_str(), "hMatchedVsITSOnly", {kTH2F, {{axisMultITSOnly, axisMultITSTPC}}})}); + + // 2d correlation of fit signals + histPointers.insert({histPath + "hFT0AVsFT0C", histos.add((histPath + "hFT0AVsFT0C").c_str(), "hFT0AVsFT0C", {kTH2F, {{axisMultFT0C, axisMultFT0A}}})}); + histPointers.insert({histPath + "hFV0AVsFT0C", histos.add((histPath + "hFV0AVsFT0C").c_str(), "hFV0AVsFT0C", {kTH2F, {{axisMultFT0C, axisMultFV0A}}})}); + histPointers.insert({histPath + "hFDDAVsFT0C", histos.add((histPath + "hFDDAVsFT0C").c_str(), "hFDDAVsFT0C", {kTH2F, {{axisMultFT0C, axisMultFDDA}}})}); + histPointers.insert({histPath + "hFDDCVsFT0C", histos.add((histPath + "hFDDCVsFT0C").c_str(), "hFDDCVsFT0C", {kTH2F, {{axisMultFT0C, axisMultFDDC}}})}); + } + + if (doprocessCollisionsWithCentrality) { + // in case requested: do vs centrality debugging + histPointers.insert({histPath + "hCentrality", histos.add((histPath + "hCentrality").c_str(), "hCentrality", {kTH1F, {{axisCentrality}}})}); + histPointers.insert({histPath + "hNContribsVsCentrality", histos.add((histPath + "hNContribsVsCentrality").c_str(), "hNContribsVsCentrality", {kTH2F, {{axisCentrality, axisMultPVContributors}}})}); + histPointers.insert({histPath + "hNITSTPCTracksVsCentrality", histos.add((histPath + "hNITSTPCTracksVsCentrality").c_str(), "hNITSTPCTracksVsCentrality", {kTH2F, {{axisCentrality, axisMultPVContributors}}})}); + histPointers.insert({histPath + "hNITSOnlyTracksVsCentrality", histos.add((histPath + "hNITSOnlyTracksVsCentrality").c_str(), "hNITSOnlyTracksVsCentrality", {kTH2F, {{axisCentrality, axisMultPVContributors}}})}); + histPointers.insert({histPath + "hNGlobalTracksVsCentrality", histos.add((histPath + "hNGlobalTracksVsCentrality").c_str(), "hNGlobalTracksVsCentrality", {kTH2F, {{axisCentrality, axisMultPVContributors}}})}); + histPointers.insert({histPath + "hNMFTTracksVsCentrality", histos.add((histPath + "hNMFTTracksVsCentrality").c_str(), "hNMFTTracksVsCentrality", {kTH2F, {{axisCentrality, axisMultMFTTracks}}})}); + histPointers.insert({histPath + "hPVChi2VsCentrality", histos.add((histPath + "hPVChi2VsCentrality").c_str(), "hPVChi2VsCentrality", {kTH2F, {{axisCentrality, axisPVChi2}}})}); + histPointers.insert({histPath + "hDeltaTimeVsCentrality", histos.add((histPath + "hDeltaTimeVsCentrality").c_str(), "hDeltaTimeVsCentrality", {kTH2F, {{axisCentrality, axisDeltaTime}}})}); + } + + if (doNGlobalTracksVsRawSignals) { + histPointers.insert({histPath + "hNGlobalTracksVsFT0A", histos.add((histPath + "hNGlobalTracksVsFT0A").c_str(), "hNGlobalTracksVsFT0A", {kTH2F, {{axisMultFT0A, axisMultGlobalTracks}}})}); + histPointers.insert({histPath + "hNGlobalTracksVsFT0C", histos.add((histPath + "hNGlobalTracksVsFT0C").c_str(), "hNGlobalTracksVsFT0C", {kTH2F, {{axisMultFT0C, axisMultGlobalTracks}}})}); + histPointers.insert({histPath + "hNGlobalTracksVsFT0M", histos.add((histPath + "hNGlobalTracksVsFT0M").c_str(), "hNGlobalTracksVsFT0M", {kTH2F, {{axisMultFT0M, axisMultGlobalTracks}}})}); + histPointers.insert({histPath + "hNGlobalTracksVsFV0A", histos.add((histPath + "hNGlobalTracksVsFV0A").c_str(), "hNGlobalTracksVsFV0A", {kTH2F, {{axisMultFV0A, axisMultGlobalTracks}}})}); + histPointers.insert({histPath + "hNGlobalTracksVsNMFTTracks", histos.add((histPath + "hNGlobalTracksVsNMFTTracks").c_str(), "hNGlobalTracksVsNMFTTracks", {kTH2F, {{axisMultMFTTracks, axisMultGlobalTracks}}})}); + histPointers.insert({histPath + "hNGlobalTracksVsNTPV", histos.add((histPath + "hNGlobalTracksVsNTPV").c_str(), "hNGlobalTracksVsNTPV", {kTH2F, {{axisMultPVContributors, axisMultGlobalTracks}}})}); + } + + if (doTimeStudies) { + histPointers.insert({histPath + "hFT0AVsTime", histos.add((histPath + "hFT0AVsTime").c_str(), "hFT0AVsTime", {kTH2F, {{axisDeltaTimestamp, axisMultFT0A}}})}); + histPointers.insert({histPath + "hFT0CVsTime", histos.add((histPath + "hFT0CVsTime").c_str(), "hFT0CVsTime", {kTH2F, {{axisDeltaTimestamp, axisMultFT0C}}})}); + histPointers.insert({histPath + "hFT0MVsTime", histos.add((histPath + "hFT0MVsTime").c_str(), "hFT0MVsTime", {kTH2F, {{axisDeltaTimestamp, axisMultFT0M}}})}); + histPointers.insert({histPath + "hFV0AVsTime", histos.add((histPath + "hFV0AVsTime").c_str(), "hFV0AVsTime", {kTH2F, {{axisDeltaTimestamp, axisMultFV0A}}})}); + histPointers.insert({histPath + "hFV0AOuterVsTime", histos.add((histPath + "hFV0AOuterVsTime").c_str(), "hFV0AOuterVsTime", {kTH2F, {{axisDeltaTimestamp, axisMultFV0A}}})}); + histPointers.insert({histPath + "hMFTTracksVsTime", histos.add((histPath + "hMFTTracksVsTime").c_str(), "hMFTTracksVsTime", {kTH2F, {{axisDeltaTimestamp, axisMultMFTTracks}}})}); + histPointers.insert({histPath + "hNGlobalVsTime", histos.add((histPath + "hNGlobalVsTime").c_str(), "hNGlobalVsTime", {kTH2F, {{axisDeltaTimestamp, axisMultGlobalTracks}}})}); + histPointers.insert({histPath + "hNTPVContributorsVsTime", histos.add((histPath + "hNTPVContributorsVsTime").c_str(), "hNTPVContributorsVsTime", {kTH2F, {{axisDeltaTimestamp, axisMultPVContributors}}})}); + histPointers.insert({histPath + "hPVzProfileCoVsTime", histos.add((histPath + "hPVzProfileCoVsTime").c_str(), "hPVzProfileCoVsTime", {kTProfile, {{axisDeltaTimestamp}}})}); + histPointers.insert({histPath + "hPVzProfileBcVsTime", histos.add((histPath + "hPVzProfileBcVsTime").c_str(), "hPVzProfileBcVsTime", {kTProfile, {{axisDeltaTimestamp}}})}); + if (irDoRateVsTime) { + histPointers.insert({histPath + "hIRProfileVsTime", histos.add((histPath + "hIRProfileVsTime").c_str(), "hIRProfileVsTime", {kTProfile, {{axisDeltaTimestamp}}})}); + } } } @@ -110,51 +449,126 @@ struct centralityStudy { void genericProcessCollision(TCollision collision) // process this collisions { - + initRun(collision); histos.fill(HIST("hCollisionSelection"), 0); // all collisions + getHist(TH1, histPath + "hCollisionSelection")->Fill(0); + if (applySel8 && !collision.multSel8()) return; histos.fill(HIST("hCollisionSelection"), 1); + getHist(TH1, histPath + "hCollisionSelection")->Fill(1); + + // calculate vertex-Z-equalized quantities if desired + float multFV0A = collision.multFV0A(); + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float multNTracksGlobal = collision.multNTracksGlobal(); + float mftNtracks = collision.mftNtracks(); + float multNTracksPV = collision.multNTracksPV(); + if (applyVertexZEqualization) { + float epsilon = 1e-2; // average value after which this collision will be disregarded + multFV0A = -1.0f; + multFT0A = -1.0f; + multFT0C = -1.0f; + multNTracksGlobal = -1.0f; + mftNtracks = -1.0f; + multNTracksPV = -1.0f; + + if (hVtxZFV0A->Interpolate(collision.multPVz()) > epsilon) { + multFV0A = hVtxZFV0A->Interpolate(0.0) * collision.multFV0A() / hVtxZFV0A->Interpolate(collision.multPVz()); + } + if (hVtxZFT0A->Interpolate(collision.multPVz()) > epsilon) { + multFT0A = hVtxZFT0A->Interpolate(0.0) * collision.multFT0A() / hVtxZFT0A->Interpolate(collision.multPVz()); + } + if (hVtxZFT0C->Interpolate(collision.multPVz()) > epsilon) { + multFT0C = hVtxZFT0C->Interpolate(0.0) * collision.multFT0C() / hVtxZFT0C->Interpolate(collision.multPVz()); + } + if (hVtxZNGlobals->Interpolate(collision.multPVz()) > epsilon) { + multNTracksGlobal = hVtxZNGlobals->Interpolate(0.0) * collision.multNTracksGlobal() / hVtxZNGlobals->Interpolate(collision.multPVz()); + } + if (hVtxZMFT->Interpolate(collision.multPVz()) > epsilon) { + mftNtracks = hVtxZMFT->Interpolate(0.0) * collision.mftNtracks() / hVtxZMFT->Interpolate(collision.multPVz()); + } + if (hVtxZNTracks->Interpolate(collision.multPVz()) > epsilon) { + multNTracksPV = hVtxZNTracks->Interpolate(0.0) * collision.multNTracksPV() / hVtxZNTracks->Interpolate(collision.multPVz()); + } + } + + bool passRejectITSROFBorder = !(rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)); + bool passRejectTFBorder = !(rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)); + bool passRequireIsVertexITSTPC = !(requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)); + bool passRequireIsGoodZvtxFT0VsPV = !(requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)); + bool passRequireIsVertexTOFmatched = !(requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)); + bool passRequireIsVertexTRDmatched = !(requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)); + bool passRejectSameBunchPileup = !(rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + bool passRejectITSinROFpileupStandard = !(rejectITSinROFpileupStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)); + bool passRejectITSinROFpileupStrict = !(rejectITSinROFpileupStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)); + bool passSelectUPCcollisions = !(selectUPCcollisions && collision.flags() < 1); + bool passRejectCollInTimeRangeNarrow = !(rejectCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)); + // _______________________________________________________ + // sidestep vertex-Z rejection for vertex-Z profile histograms + if (passRejectITSROFBorder && passRejectTFBorder && passRequireIsVertexITSTPC && passRequireIsGoodZvtxFT0VsPV && + passRequireIsVertexTOFmatched && passRequireIsVertexTRDmatched && passRejectSameBunchPileup && passRejectITSinROFpileupStandard && passRejectITSinROFpileupStrict && + passSelectUPCcollisions && passRejectCollInTimeRangeNarrow) { + getHist(TProfile, histPath + "hFT0CvsPVz_Collisions_All")->Fill(collision.multPVz(), multFT0C * scaleSignalFT0C); + getHist(TProfile, histPath + "hFT0CvsPVz_Collisions")->Fill(collision.multPVz(), multFT0C * scaleSignalFT0C); + getHist(TProfile, histPath + "hFT0AvsPVz_Collisions")->Fill(collision.multPVz(), multFT0A * scaleSignalFT0C); + getHist(TProfile, histPath + "hFV0AvsPVz_Collisions")->Fill(collision.multPVz(), multFV0A * scaleSignalFV0A); + getHist(TProfile, histPath + "hNGlobalTracksvsPVz_Collisions")->Fill(collision.multPVz(), multNTracksGlobal); + getHist(TProfile, histPath + "hNMFTTracksvsPVz_Collisions")->Fill(collision.multPVz(), mftNtracks); + getHist(TProfile, histPath + "hNTPVvsPVz_Collisions")->Fill(collision.multPVz(), multNTracksPV); + } + + // _______________________________________________________ + if (applyVtxZ && TMath::Abs(collision.multPVz()) > 10) return; histos.fill(HIST("hCollisionSelection"), 2); + getHist(TH1, histPath + "hCollisionSelection")->Fill(2); // _______________________________________________________ // Extra event selections start here - if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + if (!passRejectITSROFBorder) { return; } histos.fill(HIST("hCollisionSelection"), 3 /* Not at ITS ROF border */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(3); - if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + if (!passRejectTFBorder) { return; } histos.fill(HIST("hCollisionSelection"), 4 /* Not at TF border */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(4); - if (requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + if (!passRequireIsVertexITSTPC) { return; } histos.fill(HIST("hCollisionSelection"), 5 /* Contains at least one ITS-TPC track */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(5); - if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + if (!passRequireIsGoodZvtxFT0VsPV) { return; } histos.fill(HIST("hCollisionSelection"), 6 /* PV position consistency check */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(6); - if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + if (!passRequireIsVertexTOFmatched) { return; } histos.fill(HIST("hCollisionSelection"), 7 /* PV with at least one contributor matched with TOF */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(7); - if (requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + if (!passRequireIsVertexTRDmatched) { return; } histos.fill(HIST("hCollisionSelection"), 8 /* PV with at least one contributor matched with TRD */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(8); - if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + if (!passRejectSameBunchPileup) { return; } histos.fill(HIST("hCollisionSelection"), 9 /* Not at same bunch pile-up */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(9); // do this only if information is available if constexpr (requires { collision.timeToNext(); }) { @@ -166,63 +580,293 @@ struct centralityStudy { return; } histos.fill(HIST("hCollisionSelection"), 10 /* has suspicious neighbour */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(10); + } + + if (!passRejectITSinROFpileupStandard) { + return; + } + histos.fill(HIST("hCollisionSelection"), 11 /* Not ITS ROF pileup (standard) */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(11); + + if (!passRejectITSinROFpileupStrict) { + return; + } + histos.fill(HIST("hCollisionSelection"), 12 /* Not ITS ROF pileup (strict) */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(12); + + if (!passSelectUPCcollisions) { // if zero then NOT upc, otherwise UPC + return; + } + histos.fill(HIST("hCollisionSelection"), 13 /* is UPC event */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(13); + + if (!passRejectCollInTimeRangeNarrow) { + return; + } + histos.fill(HIST("hCollisionSelection"), 14 /* Not ITS ROF pileup (strict) */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(14); + + 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 */); + getHist(TH1, histPath + "hCollisionSelection")->Fill(15); // 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()); + histos.fill(HIST("hNPVContributors"), collision.multNTracksPV()); + 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()); + + // save vertex-Z equalized + getHist(TH1, histPath + "hNPVContributors")->Fill(multNTracksPV); + getHist(TH1, histPath + "hFT0C_Collisions")->Fill(multFT0C * scaleSignalFT0C); + getHist(TH1, histPath + "hFT0M_Collisions")->Fill((multFT0A + multFT0C) * scaleSignalFT0M); + getHist(TH1, histPath + "hFV0A_Collisions")->Fill(multFV0A * scaleSignalFV0A); + getHist(TH1, histPath + "hNGlobalTracks")->Fill(multNTracksGlobal); + getHist(TH1, histPath + "hNMFTTracks")->Fill(mftNtracks); + + if (applyVertexZEqualization.value) { + // save unequalized for cross-checks + getHist(TH1, histPath + "hNPVContributors_Unequalized")->Fill(collision.multNTracksPV()); + getHist(TH1, histPath + "hFT0C_Collisions_Unequalized")->Fill(collision.multFT0C() * scaleSignalFT0C); + getHist(TH1, histPath + "hFT0M_Collisions_Unequalized")->Fill((collision.multFT0A() + collision.multFT0C()) * scaleSignalFT0M); + getHist(TH1, histPath + "hFV0A_Collisions_Unequalized")->Fill(collision.multFV0A() * scaleSignalFV0A); + getHist(TH1, histPath + "hNGlobalTracks_Unequalized")->Fill(collision.multNTracksGlobal()); + getHist(TH1, histPath + "hNMFTTracks_Unequalized")->Fill(collision.mftNtracks()); + } if (do2DPlots) { - histos.fill(HIST("hFT0CvsNContribs"), collision.multNTracksPV(), collision.multFT0C()); + 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()); + getHist(TH2, histPath + "hNContribsVsFT0C")->Fill(collision.multFT0C() * scaleSignalFT0C, collision.multPVTotalContributors()); + getHist(TH2, histPath + "hNContribsVsFV0A")->Fill(collision.multFV0A() * scaleSignalFV0A, collision.multPVTotalContributors()); + getHist(TH2, histPath + "hMatchedVsITSOnly")->Fill(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()); + getHist(TH2, histPath + "hFT0AVsFT0C")->Fill(collision.multFT0C() * scaleSignalFT0C, collision.multFT0A()); + getHist(TH2, histPath + "hFV0AVsFT0C")->Fill(collision.multFT0C() * scaleSignalFT0C, collision.multFV0A()); + getHist(TH2, histPath + "hFDDAVsFT0C")->Fill(collision.multFT0C() * scaleSignalFT0C, collision.multFDDA()); + getHist(TH2, histPath + "hFDDCVsFT0C")->Fill(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"), multFT0A, multNTracksGlobal); + histos.fill(HIST("hNGlobalTracksVsFT0C"), multFT0C, multNTracksGlobal); + histos.fill(HIST("hNGlobalTracksVsFT0M"), (multFT0A + multFT0C), multNTracksGlobal); + histos.fill(HIST("hNGlobalTracksVsFV0A"), multFV0A, multNTracksGlobal); + histos.fill(HIST("hNGlobalTracksVsNMFTTracks"), mftNtracks, multNTracksGlobal); + histos.fill(HIST("hNGlobalTracksVsNTPV"), multNTracksPV, multNTracksGlobal); + + // per run + getHist(TH2, histPath + "hNGlobalTracksVsFT0A")->Fill(multFT0A, multNTracksGlobal); + getHist(TH2, histPath + "hNGlobalTracksVsFT0C")->Fill(multFT0C, multNTracksGlobal); + getHist(TH2, histPath + "hNGlobalTracksVsFT0M")->Fill(multFT0A + multFT0C, multNTracksGlobal); + getHist(TH2, histPath + "hNGlobalTracksVsFV0A")->Fill(multFV0A, multNTracksGlobal); + getHist(TH2, histPath + "hNGlobalTracksVsNMFTTracks")->Fill(mftNtracks, multNTracksGlobal); + getHist(TH2, histPath + "hNGlobalTracksVsNTPV")->Fill(multNTracksPV, multNTracksGlobal); + } + + if constexpr (requires { collision.multMCExtraId(); }) { + // requires monte carlo information + if (collision.multMCExtraId() > -1) { + auto mcCollision = collision.template multMCExtra_as>(); + histos.fill(HIST("hImpactParameterVsFT0A"), multFT0A, mcCollision.impactParameter()); + histos.fill(HIST("hImpactParameterVsFT0C"), multFT0C, mcCollision.impactParameter()); + histos.fill(HIST("hImpactParameterVsFT0M"), (multFT0A + multFT0C), mcCollision.impactParameter()); + histos.fill(HIST("hImpactParameterVsFV0A"), multFV0A, mcCollision.impactParameter()); + histos.fill(HIST("hImpactParameterVsNMFTTracks"), mftNtracks, mcCollision.impactParameter()); + histos.fill(HIST("hImpactParameterVsNTPV"), multNTracksPV, mcCollision.impactParameter()); + + histos.fill(HIST("hImpactParameterVsMCFT0A"), mcCollision.multMCFT0A(), mcCollision.impactParameter()); + histos.fill(HIST("hImpactParameterVsMCFT0C"), mcCollision.multMCFT0C(), mcCollision.impactParameter()); + histos.fill(HIST("hImpactParameterVsMCFT0M"), (mcCollision.multMCFT0A() + mcCollision.multMCFT0C()), mcCollision.impactParameter()); + histos.fill(HIST("hImpactParameterVsMCFV0A"), mcCollision.multMCFV0A(), mcCollision.impactParameter()); + } } // 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()); + getHist(TH1, histPath + "hCentrality")->Fill(collision.centFT0C()); + getHist(TH2, histPath + "hNContribsVsCentrality")->Fill(collision.centFT0C(), collision.multPVTotalContributors()); + getHist(TH2, histPath + "hNITSTPCTracksVsCentrality")->Fill(collision.centFT0C(), collision.multNTracksITSTPC()); + getHist(TH2, histPath + "hNITSOnlyTracksVsCentrality")->Fill(collision.centFT0C(), collision.multNTracksITSOnly()); + getHist(TH2, histPath + "hNGlobalTracksVsCentrality")->Fill(collision.centFT0C(), collision.multNTracksGlobal()); + getHist(TH2, histPath + "hNMFTTracksVsCentrality")->Fill(collision.centFT0C(), collision.mftNtracks()); + getHist(TH2, histPath + "hPVChi2VsCentrality")->Fill(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()); + } + } + + if constexpr (requires { collision.has_multBC(); }) { + if (doTimeStudies && collision.has_multBC()) { + initRun(collision); + auto multbc = collision.template multBC_as(); + uint64_t bcTimestamp = multbc.timestamp(); + float hoursAfterStartOfRun = static_cast(bcTimestamp - startOfRunTimestamp) / 3600000.0; + + getHist(TH2, histPath + "hFT0AVsTime")->Fill(hoursAfterStartOfRun, collision.multFT0A()); + getHist(TH2, histPath + "hFT0CVsTime")->Fill(hoursAfterStartOfRun, collision.multFT0C()); + getHist(TH2, histPath + "hFT0MVsTime")->Fill(hoursAfterStartOfRun, collision.multFT0M()); + getHist(TH2, histPath + "hFV0AVsTime")->Fill(hoursAfterStartOfRun, collision.multFV0A()); + getHist(TH2, histPath + "hFV0AOuterVsTime")->Fill(hoursAfterStartOfRun, collision.multFV0AOuter()); + getHist(TH2, histPath + "hMFTTracksVsTime")->Fill(hoursAfterStartOfRun, collision.mftNtracks()); + getHist(TH2, histPath + "hNGlobalVsTime")->Fill(hoursAfterStartOfRun, collision.multNTracksGlobal()); + getHist(TH2, histPath + "hNTPVContributorsVsTime")->Fill(hoursAfterStartOfRun, collision.multPVTotalContributors()); + getHist(TProfile, histPath + "hPVzProfileCoVsTime")->Fill(hoursAfterStartOfRun, collision.multPVz()); + getHist(TProfile, histPath + "hPVzProfileBcVsTime")->Fill(hoursAfterStartOfRun, multbc.multFT0PosZ()); + if (doTimeStudyFV0AOuterVsFT0A3d) { + histos.fill(HIST("h3dFV0AVsTime"), hoursAfterStartOfRun, collision.multFV0A(), collision.multFV0AOuter()); + } + + if (irDoRateVsTime) { + float interactionRate = mRateFetcher.fetch(ccdb.service, bcTimestamp, mRunNumber, irSource.value, irCrashOnNull) / 1000.; // kHz + getHist(TProfile, histPath + "hIRProfileVsTime")->Fill(hoursAfterStartOfRun, interactionRate); + } + } } } - void processCollisions(soa::Join::iterator const& collision) + void processCollisions(soa::Join::iterator const& collision, aod::MultBCs const&) + { + genericProcessCollision(collision); + } + + void processCollisionsWithResolutionStudy(soa::Join::iterator const& collision, soa::Join const&) { genericProcessCollision(collision); } - void processCollisionsWithCentrality(soa::Join::iterator const& collision) + void processCollisionsWithCentrality(soa::Join::iterator const& collision, aod::MultBCs const&) { genericProcessCollision(collision); } - void processCollisionsWithCentralityWithNeighbours(soa::Join::iterator const& collision) + void processCollisionsWithCentralityWithNeighbours(soa::Join::iterator const& collision) { genericProcessCollision(collision); } - void processBCs(aod::MultsBC::iterator const& multbc) + 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 (!multbc.multBCColliding()) + if (selectCollidingBCs && !multbc.multCollidingBC()) return; histos.fill(HIST("hBCSelection"), 1); // colliding - if (!multbc.multBCTVX()) + if (selectTVX && !multbc.multTVX()) return; histos.fill(HIST("hBCSelection"), 2); // TVX - if (!multbc.multBCFV0OrA()) + 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.multBCFT0C()); + 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, processCollisionsWithResolutionStudy, "per-collision analysis, with reso study", 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); diff --git a/Common/Tasks/checkDataModel.cxx b/Common/Tasks/checkDataModel.cxx index 33b059e870b..b5432bd76fa 100644 --- a/Common/Tasks/checkDataModel.cxx +++ b/Common/Tasks/checkDataModel.cxx @@ -13,10 +13,19 @@ /// \author /// \since -#include "Framework/ConfigParamSpec.h" +#include +#include +#include +#include +#include + +#include + +#include using namespace o2; using namespace o2::framework; +using namespace o2::framework::expressions; // custom configurable for switching between run2 and run3 selection types void customize(std::vector& workflowOptions) @@ -25,9 +34,7 @@ void customize(std::vector& workflowOptions) // workflowOptions.push_back(ConfigParamSpec{"isMC", VariantType::Bool, false, {"Check also MC tables if set"}}); } -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -using namespace o2::framework::expressions; +#include template struct LoadTable { diff --git a/Common/Tasks/checkDataModelMC.cxx b/Common/Tasks/checkDataModelMC.cxx index fb2762a02b7..612f2b8da1e 100644 --- a/Common/Tasks/checkDataModelMC.cxx +++ b/Common/Tasks/checkDataModelMC.cxx @@ -13,8 +13,20 @@ /// \author /// \since -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include using namespace o2; using namespace o2::framework; @@ -42,7 +54,7 @@ void checkDaughters(const T& particlesMC, LOG(fatal) << "MC particle " << particle.globalIndex() << " with PDG " << particle.pdgCode() << " has first and last daughter indices " << firstDauIdx << ", " << lastDauIdx; } } - for (auto& idxDau : particle.daughtersIds()) { + for (const auto& idxDau : particle.daughtersIds()) { if (idxDau >= 0 && ((unsigned long int)idxDau > offset + particlesMC.size() || (unsigned long int)idxDau < offset)) { if (debugMode) { debugHisto->Fill(1); @@ -88,7 +100,7 @@ struct CheckMcParticlesIndices { void process(aod::McParticles const& particlesMC) { long unsigned int offset = 0; - for (auto& particle : particlesMC) { + for (const auto& particle : particlesMC) { checkDaughters(particlesMC, particle, offset, debugMode.value, hDebug); } } @@ -112,7 +124,7 @@ struct CheckMcParticlesIndicesGrouped { void process(aod::McCollision const&, aod::McParticles const& particlesMC) { - for (auto& particle : particlesMC) { + for (const auto& particle : particlesMC) { checkDaughters(particlesMC, particle, particlesMC.offset(), debugMode.value, hDebug); } } diff --git a/Common/Tasks/cpvQa.cxx b/Common/Tasks/cpvQa.cxx index e549d89e33d..d6d41fa7cac 100644 --- a/Common/Tasks/cpvQa.cxx +++ b/Common/Tasks/cpvQa.cxx @@ -13,9 +13,21 @@ /// \author Sergey Evdokimov /// \since 25.10.2022 -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/StaticFor.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/Tasks/evtPlanesResolution.cxx b/Common/Tasks/evtPlanesResolution.cxx deleted file mode 100644 index e493ff3f00e..00000000000 --- a/Common/Tasks/evtPlanesResolution.cxx +++ /dev/null @@ -1,156 +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 evtPlanesResolution.cxx -/// \author Cindy Mordasini -/// \author Anna Önnerstad -/// -/// \brief ... -/// - -// C++/ROOT includes. -#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/EvtPlanes.h" -#include "Common/Core/EventPlaneHelper.h" - -// o2 includes. - -using namespace o2; -using namespace o2::framework; - -namespace ep -{ -static constexpr std::string_view centClasses[] = { - "Centrality_0-5/", "Centrality_5-10/", "Centrality_10-20/", "Centrality_20-30/", - "Centrality_30-40/", "Centrality_40-50/", "Centrality_50-60/", "Centrality_60-80/"}; -} // namespace ep - -struct evtPlanesResolution { - // Configurables. - - // Histogram registry for the output QA figures and list of centrality classes for it. - // Objects are NOT saved in alphabetical orders, and registry names are NOT saved - // as TDirectoryFile. - HistogramRegistry histosQA{"histosQA", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - - // Helper variables. - EventPlaneHelper helperEP; - - Configurable cfgMinTPCTracks{"cfgMinTPCTracks", 20, "minimum TPC tracks participating in Q-vector reconstruction"}; - Configurable cfgnMod{"cfgnMod", 2, "Modulation of interest"}; - - void init(InitContext const&) - { - // Fill the registry with the needed objects. - const AxisSpec axisEvtPl{360, -constants::math::PI, constants::math::PI}; - - histosQA.add("Centrality_0-5/histEvtPlUncor", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlRectr", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlTwist", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlFinal", "", {HistType::kTH1F, {axisEvtPl}}); - - histosQA.add("Centrality_0-5/histEvtPlBPosUncor", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlBPosRectr", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlBPosTwist", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlBPosFinal", "", {HistType::kTH1F, {axisEvtPl}}); - - histosQA.add("Centrality_0-5/histEvtPlBNegUncor", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlBNegRectr", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlBNegTwist", "", {HistType::kTH1F, {axisEvtPl}}); - histosQA.add("Centrality_0-5/histEvtPlBNegFinal", "", {HistType::kTH1F, {axisEvtPl}}); - - histosQA.add("Centrality_0-5/histEvtPlResolution", "", {HistType::kTH1F, {axisEvtPl}}); - - for (int iBin = 1; iBin < 8; iBin++) { - histosQA.addClone("Centrality_0-5/", ep::centClasses[iBin].data()); - } - } // End void init(InitContext const&) - - template - void fillHistosEvtPl(const T& vec) - { - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlUncor"), vec.evtPlUncor()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlRectr"), vec.evtPlRectr()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlTwist"), vec.evtPlTwist()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlFinal"), vec.evtPlFinal()); - - if (vec.nTrkBPos() < cfgMinTPCTracks || vec.nTrkBNeg() < cfgMinTPCTracks) - return; - - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlBPosUncor"), vec.evtPlBPosUncor()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlBPosRectr"), vec.evtPlBPosRectr()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlBPosTwist"), vec.evtPlBPosTwist()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlBPosFinal"), vec.evtPlBPosFinal()); - - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlBNegUncor"), vec.evtPlBNegUncor()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlBNegRectr"), vec.evtPlBNegRectr()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlBNegTwist"), vec.evtPlBNegTwist()); - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlBNegFinal"), vec.evtPlBNegFinal()); - - histosQA.fill(HIST(ep::centClasses[cBin]) + HIST("histEvtPlResolution"), - std::sqrt(std::cos((vec.evtPlFinal() - vec.evtPlBPosFinal()) * cfgnMod) * std::cos((vec.evtPlFinal() - vec.evtPlBNegFinal()) * cfgnMod) / - std::cos((vec.evtPlBPosFinal() - vec.evtPlBNegFinal()) * cfgnMod))); - } - - void process(aod::EvtPlane const& evPl) - { - int centBin = helperEP.GetCentBin(evPl.cent()); - switch (centBin) { - case 0: - fillHistosEvtPl<0>(evPl); - break; - case 1: - fillHistosEvtPl<1>(evPl); - break; - case 2: - fillHistosEvtPl<2>(evPl); - break; - case 3: - fillHistosEvtPl<3>(evPl); - break; - case 4: - fillHistosEvtPl<4>(evPl); - break; - case 5: - fillHistosEvtPl<5>(evPl); - break; - case 6: - fillHistosEvtPl<6>(evPl); - break; - case 7: - fillHistosEvtPl<7>(evPl); - break; - } // End switch(centBin) - } // End void process(...) -}; - -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..bfb42acff04 --- /dev/null +++ b/Common/Tasks/flowTest.cxx @@ -0,0 +1,294 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define bitcheck(var, nbit) ((var) & (1 << (nbit))) + +#include + +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/ft0Qa.cxx b/Common/Tasks/ft0Qa.cxx index f7dcb8d75c4..7b7857a9ba3 100644 --- a/Common/Tasks/ft0Qa.cxx +++ b/Common/Tasks/ft0Qa.cxx @@ -9,16 +9,22 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/Multiplicity.h" -#include "DataFormatsFT0/Digit.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "TH1F.h" -#include "TH2F.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; diff --git a/Common/Tasks/integrationTest.cxx b/Common/Tasks/integrationTest.cxx index 04e0ad4778e..c3915100f2a 100644 --- a/Common/Tasks/integrationTest.cxx +++ b/Common/Tasks/integrationTest.cxx @@ -15,23 +15,28 @@ // // Includes further QA if option enabled -#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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -#include "Framework/runDataProcessing.h" +#include using FullTracksIU = soa::Join; diff --git a/Common/Tasks/integrationTestCCDB.cxx b/Common/Tasks/integrationTestCCDB.cxx index 33dbc6dd3e4..c7096d5774c 100644 --- a/Common/Tasks/integrationTestCCDB.cxx +++ b/Common/Tasks/integrationTestCCDB.cxx @@ -22,26 +22,30 @@ // // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -#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 "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" +#include +#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; -#include "Framework/runDataProcessing.h" - struct integrationTestCCDB { // this is anyway what this is all about Service ccdb; diff --git a/Common/Tasks/multiplicityDerivedQa.cxx b/Common/Tasks/multiplicityDerivedQa.cxx index 78f229fa2d6..1d1f77e51b9 100644 --- a/Common/Tasks/multiplicityDerivedQa.cxx +++ b/Common/Tasks/multiplicityDerivedQa.cxx @@ -12,15 +12,21 @@ // This code does QA based on a saved derived dataset using the // tables provided by multiplicityTable. -#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" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/Tasks/multiplicityQa.cxx b/Common/Tasks/multiplicityQa.cxx index 72fc827606a..2178164854c 100644 --- a/Common/Tasks/multiplicityQa.cxx +++ b/Common/Tasks/multiplicityQa.cxx @@ -22,15 +22,24 @@ // - david.dobrigkeit.chinellato@cern.ch // -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "Common/DataModel/EventSelection.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" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; @@ -402,12 +411,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/orbitRangeTask.cxx b/Common/Tasks/orbitRangeTask.cxx index 250751c25ba..2db5ac27d6b 100644 --- a/Common/Tasks/orbitRangeTask.cxx +++ b/Common/Tasks/orbitRangeTask.cxx @@ -11,12 +11,17 @@ // This task finds minimum and maximum orbit among all processed bcs -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "CommonConstants/LHCConstants.h" #include "OrbitRange.h" -#include "TMath.h" + +#include +#include +#include +#include +#include + +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/Common/Tasks/propagatorQa.cxx b/Common/Tasks/propagatorQa.cxx index b5abade3ba5..dcdd50b87ce 100644 --- a/Common/Tasks/propagatorQa.cxx +++ b/Common/Tasks/propagatorQa.cxx @@ -14,27 +14,40 @@ // Work in progress! More to follow, use at your own peril // -#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 "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DetectorsBase/Propagator.h" -#include "trackSelectionRequest.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Tools/trackSelectionRequest.h" + +#include +#include +#include +#include +#include +#include +#include +#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; -#include "Framework/runDataProcessing.h" - struct propagatorQa { Service ccdb; @@ -100,12 +113,12 @@ struct propagatorQa { ccdb->setFatalWhenNull(false); // output objects - const AxisSpec axisX{(int)NbinsX, 0.0f, +250.0f, "X value"}; - const AxisSpec axisDCAxy{(int)NbinsDCA, -windowDCA, windowDCA, "DCA_{xy} (cm)"}; - const AxisSpec axisPt{(int)NbinsPt, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec axisPtCoarse{(int)NbinsPtCoarse, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec axisTanLambda{(int)NbinsTanLambda, -TanLambdaLimit, +TanLambdaLimit, "tan(#lambda)"}; - const AxisSpec axisDeltaPt{(int)NbinsDeltaPt, -DeltaPtLimit, +DeltaPtLimit, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisX{NbinsX, 0.0f, +250.0f, "X value"}; + const AxisSpec axisDCAxy{NbinsDCA, -windowDCA, windowDCA, "DCA_{xy} (cm)"}; + const AxisSpec axisPt{NbinsPt, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisPtCoarse{NbinsPtCoarse, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisTanLambda{NbinsTanLambda, -TanLambdaLimit, +TanLambdaLimit, "tan(#lambda)"}; + const AxisSpec axisDeltaPt{NbinsDeltaPt, -DeltaPtLimit, +DeltaPtLimit, "#it{p}_{T} (GeV/#it{c})"}; // All tracks histos.add("hTrackX", "hTrackX", kTH1F, {axisX}); @@ -145,8 +158,8 @@ struct propagatorQa { histos.add("hdcaXYusedInSVertexer", "hdcaXYusedInSVertexer", kTH1F, {axisDCAxy}); histos.add("hUpdateRadiiusedInSVertexer", "hUpdateRadiiusedInSVertexer", kTH1F, {axisX}); // bit packed ITS cluster map - const AxisSpec axisITSCluMap{(int)128, -0.5f, +127.5f, "Packed ITS map"}; - const AxisSpec axisRadius{(int)dQANBinsRadius, 0.0f, +50.0f, "Radius (cm)"}; + const AxisSpec axisITSCluMap{128, -0.5f, +127.5f, "Packed ITS map"}; + const AxisSpec axisRadius{dQANBinsRadius, 0.0f, +50.0f, "Radius (cm)"}; // Histogram to bookkeep cluster maps histos.add("h2dITSCluMap", "h2dITSCluMap", kTH3D, {axisITSCluMap, axisRadius, axisPtCoarse}); @@ -170,7 +183,7 @@ struct propagatorQa { 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); @@ -208,9 +221,9 @@ struct propagatorQa { /* check the previous run number */ auto bc = collision.bc_as(); initCCDB(bc); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; - for (auto& track : tracks) { + for (const auto& track : tracks) { if (track.tpcNClsFound() < minTPCClustersRequired) continue; @@ -273,7 +286,7 @@ struct propagatorQa { // ITS cluster map float lMCCreation = TMath::Sqrt(mctrack.vx() * mctrack.vx() + mctrack.vy() * mctrack.vy()); - histos.fill(HIST("h2dITSCluMap"), (float)track.itsClusterMap(), lMCCreation, track.pt()); + histos.fill(HIST("h2dITSCluMap"), static_cast(track.itsClusterMap()), lMCCreation, track.pt()); if (lIsPrimary) { histos.fill(HIST("hPrimaryDeltaTanLambdaVsPt"), track.tgl(), track.tgl() - lTrackParametrization.getTgl()); @@ -291,12 +304,12 @@ struct propagatorQa { histos.fill(HIST("hPrimaryDeltaDCAs"), lCircleDCA - lDCA); histos.fill(HIST("hPrimaryDeltaDCAsVsPt"), track.pt(), lCircleDCA - lDCA); histos.fill(HIST("hPrimaryRecalculatedDeltaDCAsVsPt"), track.pt(), lRecalculatedDCA - lDCA); - histos.fill(HIST("h2dITSCluMapPrimaries"), (float)track.itsClusterMap(), lMCCreation, track.pt()); + histos.fill(HIST("h2dITSCluMapPrimaries"), static_cast(track.itsClusterMap()), lMCCreation, track.pt()); } // determine if track was used in svertexer bool usedInSVertexer = false; bool lUsedByV0 = false, lUsedByCascade = false; - for (auto& V0 : V0s) { + for (const auto& V0 : V0s) { if (V0.posTrackId() == track.globalIndex()) { lUsedByV0 = true; break; @@ -306,7 +319,7 @@ struct propagatorQa { break; } } - for (auto& cascade : cascades) { + for (const auto& cascade : cascades) { if (cascade.bachelorId() == track.globalIndex()) { lUsedByCascade = true; break; @@ -315,10 +328,10 @@ struct propagatorQa { if (lUsedByV0 || lUsedByCascade) usedInSVertexer = true; - if (usedInSVertexer) + if (usedInSVertexer) { histos.fill(HIST("hUpdateRadiiusedInSVertexer"), lRadiusOfLastUpdate); - if (usedInSVertexer) histos.fill(HIST("hdcaXYusedInSVertexer"), lDCA); + } } } PROCESS_SWITCH(propagatorQa, processMC, "process MC", true); @@ -328,9 +341,9 @@ struct propagatorQa { /* check the previous run number */ auto bc = collision.bc_as(); initCCDB(bc); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; - for (auto& track : tracks) { + for (const auto& track : tracks) { if (track.tpcNClsFound() < minTPCClustersRequired) continue; @@ -388,7 +401,7 @@ struct propagatorQa { // ITS cluster map float lMCCreation = 0.1; // dummy value, we don't know - histos.fill(HIST("h2dITSCluMap"), (float)track.itsClusterMap(), lMCCreation, track.pt()); + histos.fill(HIST("h2dITSCluMap"), static_cast(track.itsClusterMap()), lMCCreation, track.pt()); // A hack: use DCA as equiv to primary if (TMath::Abs(lDCA) < 0.05) { // 500 microns @@ -406,13 +419,13 @@ struct propagatorQa { histos.fill(HIST("hPrimaryDeltaDCAs"), lCircleDCA - lDCA); histos.fill(HIST("hPrimaryDeltaDCAsVsPt"), track.pt(), lCircleDCA - lDCA); histos.fill(HIST("hPrimaryRecalculatedDeltaDCAsVsPt"), track.pt(), lRecalculatedDCA - lDCA); - histos.fill(HIST("h2dITSCluMapPrimaries"), (float)track.itsClusterMap(), lMCCreation, track.pt()); + histos.fill(HIST("h2dITSCluMapPrimaries"), static_cast(track.itsClusterMap()), lMCCreation, track.pt()); } // determine if track was used in svertexer bool usedInSVertexer = false; bool lUsedByV0 = false, lUsedByCascade = false; - for (auto& V0 : V0s) { + for (const auto& V0 : V0s) { if (V0.posTrackId() == track.globalIndex()) { lUsedByV0 = true; break; @@ -422,7 +435,7 @@ struct propagatorQa { break; } } - for (auto& cascade : cascades) { + for (const auto& cascade : cascades) { if (cascade.bachelorId() == track.globalIndex()) { lUsedByCascade = true; break; @@ -431,10 +444,10 @@ struct propagatorQa { if (lUsedByV0 || lUsedByCascade) usedInSVertexer = true; - if (usedInSVertexer) + if (usedInSVertexer) { histos.fill(HIST("hUpdateRadiiusedInSVertexer"), lRadiusOfLastUpdate); - if (usedInSVertexer) histos.fill(HIST("hdcaXYusedInSVertexer"), lDCA); + } } } PROCESS_SWITCH(propagatorQa, processData, "process data", false); @@ -444,9 +457,9 @@ struct propagatorQa { /* check the previous run number */ auto bc = collision.bc_as(); initCCDB(bc); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; - for (auto& trackIU : tracksIU) { + for (const auto& trackIU : tracksIU) { if (trackIU.tpcNClsFound() < minTPCClustersRequired) continue; // skip if not enough TPC clusters diff --git a/Common/Tasks/qVectorsCorrection.cxx b/Common/Tasks/qVectorsCorrection.cxx index 31c7f2ebbf8..042756e3c82 100644 --- a/Common/Tasks/qVectorsCorrection.cxx +++ b/Common/Tasks/qVectorsCorrection.cxx @@ -18,26 +18,30 @@ /// // C++/ROOT includes. -#include +#include +#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/CCDB/EventSelectionParams.h" #include "Common/Core/EventPlaneHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // o2 includes. @@ -45,6 +49,8 @@ using namespace o2; using namespace o2::framework; using MyCollisions = soa::Join; +using MyCollisionsWithSC = soa::Join; +using MyTracks = soa::Join; struct qVectorsCorrection { // No correction = recenter, recentered Qvectors = twist, twisted Qvectors = rescale. @@ -58,18 +64,39 @@ struct qVectorsCorrection { 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 cfgEvtSel{"cfgEvtSel", 0, "Event selection flags\n0: Sel8\n1: Sel8+kIsGoodZvtxFT0vsPV+kNoSameBunchPileup\n2: Sel8+kIsGoodZvtxFT0vsPV+kNoSameBunchPileup+kNoCollInTimeRangeStandard\n3: Sel8+kNoSameBunchPileup"}; + 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 cfgShiftCorPrep{"cfgShiftCorPrep", false, "configurable for shift correction"}; + + 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"}; + + 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}, ""}; - Configurable cfgQAAll{"cfgQAAll", false, "draw all q-vector steps"}; - Configurable cfgQAFinal{"cfgQAFinal", false, "draw final q-vector steps"}; + 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; @@ -81,6 +108,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") { @@ -89,17 +119,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 == "BTot") { + } 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); @@ -107,7 +160,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; @@ -117,12 +170,23 @@ 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"}; + + AxisSpec axisShift = {10, 0, 10, "shift"}; + AxisSpec axisBasis = {20, 0, 20, "basis"}; + AxisSpec axisVertex = {220, -11, 11, "vertex"}; - histosQA.add("histCentFull", "Centrality distribution for valid events", - HistType::kTH1F, {axisCent}); + histosQA.add("histCentFull", "Centrality distribution for valid events", HistType::kTH1F, {axisCent}); + histosQA.add("histCentSelected", "Centrality distribution for valid events", HistType::kTH1F, {axisCent}); + histosQA.add("histVtxSelected", "Centrality distribution for valid events", HistType::kTH1F, {axisVertex}); - for (auto i = 0; i < cfgnMods->size(); i++) { + 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}}); @@ -131,11 +195,31 @@ struct qVectorsCorrection { histosQA.add(Form("histEvtPlRefAUncorV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, axisCent}}); histosQA.add(Form("histEvtPlRefBUncorV%d", cfgnMods->at(i)), "", {HistType::kTH2F, {axisEvtPl, 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}}); + } + 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}}); + if (cfgShiftCorPrep) { + histosQA.add(Form("histShiftV%d", cfgnMods->at(i)), "", {HistType::kTProfile3D, {axisCent, axisBasis, axisShift}}); + } + + 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(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(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}}); @@ -144,6 +228,18 @@ struct qVectorsCorrection { 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}}); + 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}}); + + 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.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 (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}}); @@ -167,6 +263,224 @@ struct qVectorsCorrection { } } // End void init(InitContext const&) + template + void fillHistosShiftCor(const T& vec, int nmode) + { + int DetInd = DetId * 4 + cfgnTotalSystem * 4 * (nmode - 2) + 3; + int RefAInd = RefAId * 4 + cfgnTotalSystem * 4 * (nmode - 2) + 3; + int RefBInd = RefBId * 4 + cfgnTotalSystem * 4 * (nmode - 2) + 3; + + if (vec.qvecAmp()[DetId] < 1e-8 || vec.qvecAmp()[RefAId] < 1e-8 || vec.qvecAmp()[RefBId] < 1e-8) { + return; + } + + if (nmode == 2) { + for (int ishift = 1; ishift <= 10; ishift++) { + histosQA.fill(HIST("histShiftV2"), vec.cent(), 2.0 * DetId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[DetInd], vec.qvecRe()[DetInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV2"), vec.cent(), 2.0 * DetId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[DetInd], vec.qvecRe()[DetInd]) / static_cast(nmode))); + + histosQA.fill(HIST("histShiftV2"), vec.cent(), 2.0 * RefAId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefAInd], vec.qvecRe()[RefAInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV2"), vec.cent(), 2.0 * RefAId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefAInd], vec.qvecRe()[RefAInd]) / static_cast(nmode))); + + histosQA.fill(HIST("histShiftV2"), vec.cent(), 2.0 * RefBId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefBInd], vec.qvecRe()[RefBInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV2"), vec.cent(), 2.0 * RefBId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefBInd], vec.qvecRe()[RefBInd]) / static_cast(nmode))); + } + } else if (nmode == 3) { + for (int ishift = 1; ishift <= 10; ishift++) { + histosQA.fill(HIST("histShiftV3"), vec.cent(), 2.0 * DetId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[DetInd], vec.qvecRe()[DetInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV3"), vec.cent(), 2.0 * DetId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[DetInd], vec.qvecRe()[DetInd]) / static_cast(nmode))); + + histosQA.fill(HIST("histShiftV3"), vec.cent(), 2.0 * RefAId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefAInd], vec.qvecRe()[RefAInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV3"), vec.cent(), 2.0 * RefAId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefAInd], vec.qvecRe()[RefAInd]) / static_cast(nmode))); + + histosQA.fill(HIST("histShiftV3"), vec.cent(), 2.0 * RefBId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefBInd], vec.qvecRe()[RefBInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV3"), vec.cent(), 2.0 * RefBId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefBInd], vec.qvecRe()[RefBInd]) / static_cast(nmode))); + } + } else if (nmode == 4) { + for (int ishift = 1; ishift <= 10; ishift++) { + histosQA.fill(HIST("histShiftV4"), vec.cent(), 2.0 * DetId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[DetInd], vec.qvecRe()[DetInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV4"), vec.cent(), 2.0 * DetId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[DetInd], vec.qvecRe()[DetInd]) / static_cast(nmode))); + + histosQA.fill(HIST("histShiftV4"), vec.cent(), 2.0 * RefAId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefAInd], vec.qvecRe()[RefAInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV4"), vec.cent(), 2.0 * RefAId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefAInd], vec.qvecRe()[RefAInd]) / static_cast(nmode))); + + histosQA.fill(HIST("histShiftV4"), vec.cent(), 2.0 * RefBId + 0.5, ishift - 0.5, TMath::Sin(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefBInd], vec.qvecRe()[RefBInd]) / static_cast(nmode))); + histosQA.fill(HIST("histShiftV4"), vec.cent(), 2.0 * RefBId + 1.5, ishift - 0.5, TMath::Cos(ishift * static_cast(nmode) * TMath::ATan2(vec.qvecIm()[RefBInd], vec.qvecRe()[RefBInd]) / static_cast(nmode))); + } + } + } + + template + void fillHistosFlowWithSC(const CollType& coll, const TrackType& track, int nmode) + { + int DetInd = DetId + cfgnTotalSystem * (nmode - 2); + int RefAInd = RefAId + cfgnTotalSystem * (nmode - 2); + int RefBInd = RefBId + cfgnTotalSystem * (nmode - 2); + + if (coll.qvecAmp()[DetId] < 1e-8 || coll.qvecAmp()[RefAId] < 1e-8 || coll.qvecAmp()[RefBId] < 1e-8) { + return; + } + + 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.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_Det_v2"), coll.cent(), trk.pt(), std::sin(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_Det_v2"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefA_v2"), coll.cent(), trk.pt(), std::cos(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefA_v2"), coll.cent(), trk.pt(), std::sin(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefA_v2"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefB_v2"), coll.cent(), trk.pt(), std::cos(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefB_v2"), coll.cent(), trk.pt(), std::sin(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefB_v2"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(2.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], 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.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_Det_v3"), coll.cent(), trk.pt(), std::sin(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_Det_v3"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefA_v3"), coll.cent(), trk.pt(), std::cos(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefA_v3"), coll.cent(), trk.pt(), std::sin(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefA_v3"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefB_v3"), coll.cent(), trk.pt(), std::cos(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefB_v3"), coll.cent(), trk.pt(), std::sin(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefB_v3"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(3.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], 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.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_Det_v4"), coll.cent(), trk.pt(), std::sin(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_Det_v4"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[DetInd], coll.qvecShiftedIm()[DetInd], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefA_v4"), coll.cent(), trk.pt(), std::cos(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefA_v4"), coll.cent(), trk.pt(), std::sin(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefA_v4"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefAInd], coll.qvecShiftedIm()[RefAInd], nmode)))); + + histosQA.fill(HIST("hist_EP_cos_RefB_v4"), coll.cent(), trk.pt(), std::cos(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], nmode)))); + histosQA.fill(HIST("hist_EP_sin_RefB_v4"), coll.cent(), trk.pt(), std::sin(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], nmode)))); + histosQA.fill(HIST("hist_EP_azimuth_RefB_v4"), coll.cent(), trk.pt(), TVector2::Phi_0_2pi(4.0 * (trk.phi() - helperEP.GetEventPlane(coll.qvecShiftedRe()[RefBInd], coll.qvecShiftedIm()[RefBInd], nmode)))); + } + } + } + + 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)))); + } + } + } + + template + void fillHistosQvecWithSC(const T& vec, int nmode) + { + int DetInd = DetId + cfgnTotalSystem * (nmode - 2); + int RefAInd = RefAId + cfgnTotalSystem * (nmode - 2); + int RefBInd = RefBId + cfgnTotalSystem * (nmode - 2); + + if (vec.qvecAmp()[DetId] < 1e-8 || vec.qvecAmp()[RefAId] < 1e-8 || vec.qvecAmp()[RefBId] < 1e-8) { + return; + } + + if (nmode == 2) { + histosQA.fill(HIST("histQvecFinalV2"), vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], vec.cent()); + histosQA.fill(HIST("histEvtPlFinalV2"), helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), vec.cent()); + + histosQA.fill(HIST("histQvecRefAFinalV2"), vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAFinalV2"), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), vec.cent()); + + histosQA.fill(HIST("histQvecRefBFinalV2"), vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBFinalV2"), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), vec.cent()); + + histosQA.fill(HIST("histEvtPlRes_SigRefAV2"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_SigRefBV2"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_RefARefBV2"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), nmode), vec.cent()); + } else if (nmode == 3) { + histosQA.fill(HIST("histQvecFinalV3"), vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], vec.cent()); + histosQA.fill(HIST("histEvtPlFinalV3"), helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), vec.cent()); + + histosQA.fill(HIST("histQvecRefAFinalV3"), vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAFinalV3"), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), vec.cent()); + + histosQA.fill(HIST("histQvecRefBFinalV3"), vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBFinalV3"), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), vec.cent()); + + histosQA.fill(HIST("histEvtPlRes_SigRefAV3"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_SigRefBV3"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_RefARefBV3"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), nmode), vec.cent()); + } else if (nmode == 4) { + histosQA.fill(HIST("histQvecFinalV4"), vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], vec.cent()); + histosQA.fill(HIST("histEvtPlFinalV4"), helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), vec.cent()); + + histosQA.fill(HIST("histQvecRefAFinalV4"), vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefAFinalV4"), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), vec.cent()); + + histosQA.fill(HIST("histQvecRefBFinalV4"), vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], vec.cent()); + histosQA.fill(HIST("histEvtPlRefBFinalV4"), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), vec.cent()); + + histosQA.fill(HIST("histEvtPlRes_SigRefAV4"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_SigRefBV4"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[DetInd], vec.qvecShiftedIm()[DetInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), nmode), vec.cent()); + histosQA.fill(HIST("histEvtPlRes_RefARefBV4"), helperEP.GetResolution(helperEP.GetEventPlane(vec.qvecShiftedRe()[RefAInd], vec.qvecShiftedIm()[RefAInd], nmode), helperEP.GetEventPlane(vec.qvecShiftedRe()[RefBInd], vec.qvecShiftedIm()[RefBInd], nmode), nmode), vec.cent()); + } + } + // Definition of all the needed template functions. template void fillHistosQvec(const T& vec, int nmode) @@ -178,9 +492,15 @@ struct qVectorsCorrection { 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()); @@ -193,9 +513,15 @@ struct qVectorsCorrection { 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()); @@ -208,9 +534,15 @@ struct qVectorsCorrection { 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()); @@ -221,6 +553,10 @@ struct qVectorsCorrection { } } 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()); @@ -229,7 +565,13 @@ struct qVectorsCorrection { 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) { @@ -244,9 +586,15 @@ struct qVectorsCorrection { 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()); @@ -259,9 +607,15 @@ struct qVectorsCorrection { 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()); @@ -272,6 +626,10 @@ struct qVectorsCorrection { } } 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()); @@ -280,9 +638,15 @@ struct qVectorsCorrection { 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()); @@ -295,9 +659,15 @@ struct qVectorsCorrection { 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()); @@ -310,9 +680,15 @@ struct qVectorsCorrection { 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()); @@ -323,24 +699,107 @@ struct qVectorsCorrection { } } 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) + void processDefault(MyCollisions::iterator const& qVec, MyTracks const& tracks) { histosQA.fill(HIST("histCentFull"), qVec.cent()); - if (cfgAddEvtSel && (!qVec.sel8() || - !qVec.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || - !qVec.selection_bit(aod::evsel::kNoSameBunchPileup))) { - return; + if (cfgAddEvtSel) { + if (std::abs(qVec.posZ()) > 10.) + return; + switch (cfgEvtSel) { + case 0: // Sel8 + if (!qVec.sel8()) + return; + break; + case 1: // PbPb standard + if (!qVec.sel8() || !qVec.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !qVec.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + case 2: // PbPb with pileup + if (!qVec.sel8() || !qVec.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) || + !qVec.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !qVec.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + case 3: // Small systems (OO, NeNe, pp) + if (!qVec.sel8() || !qVec.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + default: + LOGF(warning, "Event selection flag was not found, continuing without basic event selections!\n"); + } + // Check occupancy + if (qVec.trackOccupancyInTimeRange() > cfgMaxOccupancy || qVec.trackOccupancyInTimeRange() < cfgMinOccupancy) + return; + } + histosQA.fill(HIST("histCentSelected"), qVec.cent()); + histosQA.fill(HIST("histVtxSelected"), qVec.posZ()); + + if (cfgShiftCorPrep) { + for (uint i = 0; i < cfgnMods->size(); i++) { + fillHistosShiftCor(qVec, cfgnMods->at(i)); + } } - for (auto i = 0; i < cfgnMods->size(); i++) { + + 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(...) + } + PROCESS_SWITCH(qVectorsCorrection, processDefault, "default process", true); + + void processWithSC(MyCollisionsWithSC::iterator const& qVec, MyTracks const& tracks) + { + histosQA.fill(HIST("histCentFull"), qVec.cent()); + if (cfgAddEvtSel) { + if (std::abs(qVec.posZ()) > 10.) + return; + switch (cfgEvtSel) { + case 0: // Sel8 + if (!qVec.sel8()) + return; + break; + case 1: // PbPb standard + if (!qVec.sel8() || !qVec.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !qVec.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + case 2: // PbPb with pileup + if (!qVec.sel8() || !qVec.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) || + !qVec.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !qVec.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + case 3: // Small systems (OO, NeNe, pp) + if (!qVec.sel8() || !qVec.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + default: + LOGF(warning, "Event selection flag was not found, continuing without basic event selections!\n"); + } + // Check occupancy + if (qVec.trackOccupancyInTimeRange() > cfgMaxOccupancy || qVec.trackOccupancyInTimeRange() < cfgMinOccupancy) + return; + } + histosQA.fill(HIST("histCentSelected"), qVec.cent()); + histosQA.fill(HIST("histVtxSelected"), qVec.posZ()); + + for (uint i = 0; i < cfgnMods->size(); i++) { + fillHistosQvecWithSC(qVec, cfgnMods->at(i)); + if (cfgQAFinal && cfgQAFlowStudy) { + fillHistosFlowWithSC(qVec, tracks, cfgnMods->at(i)); + } + } + } + PROCESS_SWITCH(qVectorsCorrection, processWithSC, "process with shift correction", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/Common/Tasks/qaMuon.cxx b/Common/Tasks/qaMuon.cxx new file mode 100644 index 00000000000..bf2659faf07 --- /dev/null +++ b/Common/Tasks/qaMuon.cxx @@ -0,0 +1,3508 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // FIXME: Replace M_PI + +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 { + std::vector> posClusters; // (x,y,z) + std::vector> errorClusters; // (ex,ey) + std::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"}; + Configurable fEnableQADimuonSameSignDCA{"cfgEnableQADimuonSameSignDCA", false, "Enable same sign dimuon DCA QA checks"}; + Configurable fEnableSingleMuonDiMuonCorrelations{"cfgEnableMuonDiMuonCorrelations", false, "Enable muon-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 selecting dimuon DCA candidates + Configurable fDimuonDCAMassLow{"cfgDimuonDCAMassLow", 2.8f, ""}; + Configurable fDimuonDCAMassHigh{"cfgDimuonDCAMassHigh", 3.4f, ""}; + + //// 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; + + // Derived version of mch::Track class that handles the associated clusters as internal objects and deletes them in the destructor + class TrackRealigned : public mch::Track + { + public: + TrackRealigned() = default; + ~TrackRealigned() + { + // delete the clusters associated to this track + for (const auto& par : *this) { + if (par.getClusterPtr()) { + delete par.getClusterPtr(); + } + } + } + }; + + //// 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; + std::map transformRef; // reference geometry w.r.t track data + std::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 registryDCAdiMuons{"registryDCAdiMuons", {}}; + 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; + std::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}}); + + // muon origin from MCH quadrants + registry.add("muons/TrackEtaPos", "MCH #mu^{+} track #eta", {HistType::kTH1F, {etaAxis}}); + registry.add("muons/TrackEtaNeg", "MCH #mu^{-} track #eta", {HistType::kTH1F, {etaAxis}}); + // -- pT and eta + registry.add("muons/TrackPt_TrackEtaPos", "track pT and #eta", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + registry.add("muons/TrackPt_TrackEtaNeg", "track pT and #eta", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + // top-bottom + registry.add("muons/TrackEtaPos_T", "MCH #mu^{+} track #eta, top MCH CH1", {HistType::kTH1F, {etaAxis}}); + registry.add("muons/TrackEtaPos_B", "MCH #mu^{+} track #eta, bottom MCH CH1", {HistType::kTH1F, {etaAxis}}); + registry.add("muons/TrackEtaNeg_T", "MCH #mu^{-} track #eta, top MCH CH1", {HistType::kTH1F, {etaAxis}}); + registry.add("muons/TrackEtaNeg_B", "MCH #mu^{-} track #eta, bottom MCH CH1", {HistType::kTH1F, {etaAxis}}); + // -- pT and eta + registry.add("muons/TrackPt_TrackEtaPos_T", "track p_{T} and #eta, top MCH CH1", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + registry.add("muons/TrackPt_TrackEtaPos_B", "track p_{T} and #eta, bottom MCH CH1", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + registry.add("muons/TrackPt_TrackEtaNeg_T", "track p_{T} and #eta, top MCH CH1", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + registry.add("muons/TrackPt_TrackEtaNeg_B", "track p_{T} and #eta, bottom MCH CH1", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + // left-right + registry.add("muons/TrackEtaPos_L", "MCH #mu^{+} track #eta, left MCH CH1", {HistType::kTH1F, {etaAxis}}); + registry.add("muons/TrackEtaPos_R", "MCH #mu^{+} track #eta, right MCH CH1", {HistType::kTH1F, {etaAxis}}); + registry.add("muons/TrackEtaNeg_L", "MCH #mu^{-} track #eta, left MCH CH1", {HistType::kTH1F, {etaAxis}}); + registry.add("muons/TrackEtaNeg_R", "MCH #mu^{-} track #eta, right MCH CH1", {HistType::kTH1F, {etaAxis}}); + // -- pT and eta + registry.add("muons/TrackPt_TrackEtaPos_L", "track p_{T} and #eta, top MCH CH1", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + registry.add("muons/TrackPt_TrackEtaPos_R", "track p_{T} and #eta, bottom MCH CH1", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + registry.add("muons/TrackPt_TrackEtaNeg_L", "track p_{T} and #eta, top MCH CH1", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + registry.add("muons/TrackPt_TrackEtaNeg_R", "track p_{T} and #eta, bottom MCH CH1", {HistType::kTH2F, {transverseMomentumAxis, etaAxis}}); + + // ====================== + // 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) { + // single muons + AxisSpec transverseMomentumAxis = {100, 0, 30, "p_{T} (GeV/c)"}; + AxisSpec etaAxis = {40, -5, -1, "#eta"}; + AxisSpec rAbsAxis = {10, 0., 100.0, "R_{abs} (cm)"}; + AxisSpec dcaAxis = {400, -10.0, 10.0, "DCA"}; + AxisSpec dcaAxisReduced = {40, -10.0, 10.0, "DCA"}; + AxisSpec phiAxis = {36, -180.0, 180.0, "#phi (degrees)"}; + // dimuons + 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})"}; + AxisSpec yPairAxis = {120, 0.0, 6.0, "#y_{pair}"}; + AxisSpec invMassAxis2D = {750, 0, 15, "M_{#mu^{+}#mu^{-}} (GeV/c^{2})"}; + AxisSpec pTAxis2D = {120, 0, 30, "p_{T} (GeV/c)"}; + // Jpsi candidate DCA histograms + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosDCAx_minus_MuNegDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} minus DCA_x #mu^{-} and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} top minus DCA_x #mu^{-} top and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} top minus DCA_x #mu^{-} bottom and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} bottom minus DCA_x #mu^{-} bottom and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} bottom minus DCA_x #mu^{-} top and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosDCAy_minus_MuNegDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} minus DCA_y #mu^{-} and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} top minus DCA_y #mu^{-} top and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} top minus DCA_y #mu^{-} bottom and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} bottom minus DCA_y #mu^{-} bottom and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} bottom minus DCA_y #mu^{-} top and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + if (configQAs.fEnableQADimuonSameSignDCA) { + // mu+mu+ + registryDimuon.add("dimuon/same-event/same-sign-PP/DCA/pT_Mu1DCAx_minus_Mu2DCAx_MuonKine_MuonCuts", "DCA_x #mu_{1} minus DCA_x #mu_{2} and #mu^{+}#mu^{+} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-PP/DCA/pT_Mu1TDCAx_minus_Mu2TDCAx_MuonKine_MuonCuts", "DCA_x #mu_{1} top minus DCA_x #mu_{2} top and #mu^{+}#mu^{+} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-PP/DCA/pT_MuTDCAx_minus_MuBDCAx_MuonKine_MuonCuts", "DCA_x #mu top minus DCA_x #mu bottom and #mu^{+}#mu^{+} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-PP/DCA/pT_Mu1BDCAx_minus_Mu2BDCAx_MuonKine_MuonCuts", "DCA_x #mu_{1} bottom minus DCA_x #mu_{2} bottom and #mu^{+}#mu^{+} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-PP/DCA/pT_Mu1DCAy_minus_Mu2DCAy_MuonKine_MuonCuts", "DCA_y #mu_{1} minus DCA_y #mu_{2} and #mu^{+}#mu^{+} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-PP/DCA/pT_Mu1TDCAy_minus_Mu2TDCAy_MuonKine_MuonCuts", "DCA_y #mu_{1} top minus DCA_y #mu_{2} top and #mu^{+}#mu^{+} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-PP/DCA/pT_MuTDCAy_minus_MuBDCAy_MuonKine_MuonCuts", "DCA_y #mu top minus DCA_y #mu bottom and #mu^{+}#mu^{+} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-PP/DCA/pT_Mu1BDCAy_minus_Mu2BDCAy_MuonKine_MuonCuts", "DCA_y #mu_{1} bottom minus DCA_y #mu_{2} bottom and #mu^{+}#mu^{+} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + // mu-mu- + registryDimuon.add("dimuon/same-event/same-sign-MM/DCA/pT_Mu1DCAx_minus_Mu2DCAx_MuonKine_MuonCuts", "DCA_x #mu_{1} minus DCA_x #mu_{2} and #mu^{-}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-MM/DCA/pT_Mu1TDCAx_minus_Mu2TDCAx_MuonKine_MuonCuts", "DCA_x #mu_{1} top minus DCA_x #mu_{2} top and #mu^{-}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-MM/DCA/pT_MuTDCAx_minus_MuBDCAx_MuonKine_MuonCuts", "DCA_x #mu top minus DCA_x #mu bottom and #mu^{-}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-MM/DCA/pT_Mu1BDCAx_minus_Mu2BDCAx_MuonKine_MuonCuts", "DCA_x #mu_{1} bottom minus DCA_x #mu_{2} bottom and #mu^{-}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-MM/DCA/pT_Mu1DCAy_minus_Mu2DCAy_MuonKine_MuonCuts", "DCA_y #mu_{1} minus DCA_y #mu_{-} and #mu^{-}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-MM/DCA/pT_Mu1TDCAy_minus_Mu2TDCAy_MuonKine_MuonCuts", "DCA_y #mu_{1} top minus DCA_y #mu_{2} top and #mu^{-}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-MM/DCA/pT_MuTDCAy_minus_MuBDCAy_MuonKine_MuonCuts", "DCA_y #mu top minus DCA_y #mu bottom and #mu^{-}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/same-event/same-sign-MM/DCA/pT_Mu1BDCAy_minus_Mu2BDCAy_MuonKine_MuonCuts", "DCA_y #mu_{1} bottom minus DCA_y #mu_{2} bottom and #mu^{-}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + } + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosDCAx_minus_MuNegDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} minus DCA_x #mu^{-} and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosTDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} top minus DCA_x #mu^{-} top and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosTDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} top minus DCA_x #mu^{-} bottom and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosBDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} bottom minus DCA_x #mu^{-} bottom and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosBDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts", "DCA_x #mu^{+} bottom minus DCA_x #mu^{-} top and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosDCAy_minus_MuNegDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} minus DCA_y #mu^{-} and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosTDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} top minus DCA_y #mu^{-} top and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosTDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} top minus DCA_y #mu^{-} bottom and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosBDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} bottom minus DCA_y #mu^{-} bottom and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + registryDimuon.add("dimuon/mixed-event/DCA/pT_MuPosBDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts", "DCA_y #mu^{+} bottom minus DCA_y #mu^{-} top and #mu^{+}#mu^{-} p_{T}", {HistType::kTH2F, {pTAxis2D, dcaAxis}}); + if (configQAs.fEnableSingleMuonDiMuonCorrelations) { + // Single muons - dimuons correlations + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosPt_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{+} p_{T}", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegPt_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{-} p_{T}", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, pTAxis2D}}); + // + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosEta_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{+} #eta", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, etaAxis}}); + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegEta_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{-} #eta", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, etaAxis}}); + // + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosRabs_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{+} R_{abs}", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, rAbsAxis}}); + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegRabs_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{-} R_{abs}", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, rAbsAxis}}); + // + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosDca_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{+} DCA", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, dcaAxisReduced}}); + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegDca_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{-} DCA", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, dcaAxisReduced}}); + // + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosPhi_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{+} #phi", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, phiAxis}}); + registryDimuon.add("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegPhi_MuonKine_MuonCuts", "#mu^{+}#mu^{-} and #mu^{-} #phi", {HistType::kTH3F, {invMassAxis2D, pTAxis2D, phiAxis}}); + } + // 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}}); + // -- Mass and pT + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + // 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_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {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_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {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}}); + // -- Mass and pT + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + // 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", "#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/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_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {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", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts", "#mu^{+}#mu^{-} invariant mass", {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_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {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}}); + // -- Mass and pT + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TPBN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} top and #mu^{-} bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TNBP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} top and #mu^{+} bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + // MCH-MID tracks with MCH acceptance cuts and combinations from the left and right halfs of MCH + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_MuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH1F, {invMassAxisFull}}); + // -- Mass and pT + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or left-right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + // MCH-MID tracks with MFT acceptance cuts and combinations from the left and right halfs of MCH + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH1F, {invMassAxisFull}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_RR", "#mu^{+}#mu^{-} invariant mass right-right", {HistType::kTH1F, {invMassAxisFull}}); + // -- Mass and pT + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LPRN", "#mu^{+}#mu^{-} invariant mass, #mu^{+} left and #mu^{-} right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LNRP", "#mu^{+}#mu^{-} invariant mass, #mu^{-} left and #mu^{+} right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + // 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/same-event/invariantMass_MuonKine_GlobalMatchesCuts_TT", "#mu^{+}#mu^{-} invariant mass, top - top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts_TB", "#mu^{+}#mu^{-} invariant mass, top - bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts_BT", "#mu^{+}#mu^{-} invariant mass, bottom - top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom - bottom", {HistType::kTH1F, {invMassAxis}}); + 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}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts_TT", "#mu^{+}#mu^{-} invariant mass, top - top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts_TB", "#mu^{+}#mu^{-} invariant mass, top - bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts_BT", "#mu^{+}#mu^{-} invariant mass, bottom - top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom - bottom", {HistType::kTH1F, {invMassAxis}}); + // -- Mass and pT + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_TT", "#mu^{+}#mu^{-} invariant mass, top - top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_TB", "#mu^{+}#mu^{-} invariant mass, top - bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_BT", "#mu^{+}#mu^{-} invariant mass, bottom - top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom - bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_TT", "#mu^{+}#mu^{-} invariant mass, top - top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_TB", "#mu^{+}#mu^{-} invariant mass, top - bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_BT", "#mu^{+}#mu^{-} invariant mass, bottom - top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom - bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + // 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/invariantMass_GlobalMuonKine_GlobalMatchesCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_BT", "#mu^{+}#mu^{-} invariant mass, bottom-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {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/invariantMass_GlobalMuonKine_GlobalMatchesCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_BT", "#mu^{+}#mu^{-} invariant mass, bottom-top", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH1F, {invMassAxis}}); + registryDimuon.add("dimuon/mixed-event/invariantMassFull_GlobalMuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH1F, {invMassAxisFull}}); + // -- Mass and pT + registryDimuon.add("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_BT", "#mu^{+}#mu^{-} invariant mass, bottom-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_BT", "#mu^{+}#mu^{-} invariant mass, bottom-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + // 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}}); + // -- Mass and pT + registryDimuon.add("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_TT", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, top-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_TB", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, top-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_BT", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, bottom-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_BB", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_TT", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, top-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_TB", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, top-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_BT", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, bottom-top", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + registryDimuon.add("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_BB", "M_{#mu^{+}#mu^{-}} - rescaled MFT momentum, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, pTAxis2D}}); + // 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}}); + + // pseudorapidity (only for MCH acceptance cuts) + // MCH-MID tracks with MCH acceptance cuts + registryDimuon.add("dimuon/same-event/rapPair_MuonKine_MuonCuts", "#eta of dimuon pair", {HistType::kTH1F, {yPairAxis}}); + // -- Mass and eta + registryDimuon.add("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts", "#mu^{+}#mu^{-} invariant mass", {HistType::kTH2F, {invMassAxis2D, yPairAxis}}); + // -- pT and eta + registryDimuon.add("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts", "#mu^{+}#mu^{-} p_{T} and #eta", {HistType::kTH2F, {pTAxis2D, yPairAxis}}); + // MCH-MID tracks with MCH acceptance cuts and combinations from the top and bottom halfs of MCH + registryDimuon.add("dimuon/same-event/rapPair_MuonKine_MuonCuts_TT", "#eta of dimuon pair, top-top", {HistType::kTH1F, {yPairAxis}}); + registryDimuon.add("dimuon/same-event/rapPair_MuonKine_MuonCuts_TB", "#eta of dimuon pair, top-bottom or bottom-top", {HistType::kTH1F, {yPairAxis}}); + registryDimuon.add("dimuon/same-event/rapPair_MuonKine_MuonCuts_BB", "#eta of dimuon pair, bottom-bottom", {HistType::kTH1F, {yPairAxis}}); + // -- Mass and eta + registryDimuon.add("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_TT", "#mu^{+}#mu^{-} invariant mass, top-top", {HistType::kTH2F, {invMassAxis2D, yPairAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_TB", "#mu^{+}#mu^{-} invariant mass, top-bottom or bottom-top", {HistType::kTH2F, {invMassAxis2D, yPairAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_BB", "#mu^{+}#mu^{-} invariant mass, bottom-bottom", {HistType::kTH2F, {invMassAxis2D, yPairAxis}}); + // -- pT and eta + registryDimuon.add("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_TT", "#mu^{+}#mu^{-} p_{T} and #eta, top-top", {HistType::kTH2F, {pTAxis2D, yPairAxis}}); + registryDimuon.add("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_TB", "#mu^{+}#mu^{-} p_{T} and #eta, top-bottom or bottom-top", {HistType::kTH2F, {pTAxis2D, yPairAxis}}); + registryDimuon.add("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_BB", "#mu^{+}#mu^{-} p_{T} and #eta, bottom-bottom", {HistType::kTH2F, {pTAxis2D, yPairAxis}}); + // MCH-MID tracks with MCH acceptance cuts and combinations from the left and right halfs of MCH + registryDimuon.add("dimuon/same-event/rapPair_MuonKine_MuonCuts_LL", "#eta of dimuon pair, left-left", {HistType::kTH1F, {yPairAxis}}); + registryDimuon.add("dimuon/same-event/rapPair_MuonKine_MuonCuts_LR", "#eta of dimuon pair, left-right or right-left", {HistType::kTH1F, {yPairAxis}}); + registryDimuon.add("dimuon/same-event/rapPair_MuonKine_MuonCuts_RR", "#eta of dimuon pair, right-right", {HistType::kTH1F, {yPairAxis}}); + // -- Mass and eta + registryDimuon.add("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_LL", "#mu^{+}#mu^{-} invariant mass, left-left", {HistType::kTH2F, {invMassAxis2D, yPairAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_LR", "#mu^{+}#mu^{-} invariant mass, left-right or right-left", {HistType::kTH2F, {invMassAxis2D, yPairAxis}}); + registryDimuon.add("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_RR", "#mu^{+}#mu^{-} invariant mass, right-right", {HistType::kTH2F, {invMassAxis2D, yPairAxis}}); + // -- pT and eta + // registryDimuon.add("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_LL", "#mu^{+}#mu^{-} p_{T} and #eta, left-left", {HistType::kTH2F, {pTAxis2D, yPairAxis}}); + // registryDimuon.add("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_LR", "#mu^{+}#mu^{-} p_{T} and #eta, left-right or right-left", {HistType::kTH2F, {pTAxis2D, yPairAxis}}); + // registryDimuon.add("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_RR", "#mu^{+}#mu^{-} p_{T} and #eta, right-right", {HistType::kTH2F, {pTAxis2D, yPairAxis}}); + } + } + + 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 (std::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 (std::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 + double GetMuMuPt(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.Pt(); + } + + template + double GetMuMuRap(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.Y(); + } + + 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 (const auto& [collisionIndex1, collisionInfo1] : collisionInfos) { + + // outer loop over muon tracks + auto muonCollision1 = muons.sliceBy(fwdtracksPerCollision, collisionInfo1.globalIndex); + for (const auto& muon1 : muonCollision1) { + + if (muon1.trackType() <= 2) { + continue; + } + auto mchIndex1 = muon1.globalIndex(); + + // inner loop over collisions + for (const 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 (const 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 (const auto& [collisionIndex1, collisionInfo1] : collisionInfos) { + + // outer loop over global muon tracks + auto muonCollision1 = muons.sliceBy(fwdtracksPerCollision, collisionInfo1.globalIndex); + for (const 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 (const 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 (const 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, TrackRealigned& convertedTrack) + { + int removable = 0; + auto clustersSliced = mchcls.sliceBy(perMuon, muon.globalIndex()); // Slice clusters by muon id + std::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 + std::vector posCls = {clusterMCH->x, clusterMCH->y, clusterMCH->z}; + std::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++) { + std::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() * std::sin(M_PI / 2 - std::atan(propmuon.getTgl())) * std::cos(propmuon.getPhi()); + fgValues.py = propmuon.getP() * std::sin(M_PI / 2 - std::atan(propmuon.getTgl())) * std::sin(propmuon.getPhi()); + fgValues.pz = propmuon.getP() * std::cos(M_PI / 2 - std::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 * std::sin(M_PI / 2 - std::atan(muon.tgl())) * std::cos(muon.phi()); + double py = pMCH * std::sin(M_PI / 2 - std::atan(muon.tgl())) * std::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()); + if (endPoint == kToDCA) { + fgValues.dcaX = (propmuon.getX() - collision.x); + fgValues.dcaY = (propmuon.getY() - collision.y); + } + } + + //// 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() * std::sin(M_PI / 2 - std::atan(propmuon.getTgl())) * std::cos(propmuon.getPhi()); + fgValues.py = propmuon.getP() * std::sin(M_PI / 2 - std::atan(propmuon.getTgl())) * std::sin(propmuon.getPhi()); + fgValues.pz = propmuon.getP() * std::cos(M_PI / 2 - std::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(fgValuesMCHpv.dcaX * fgValuesMCHpv.dcaX + fgValuesMCHpv.dcaY * fgValuesMCHpv.dcaY)); + } + + // muon origin for MCH top-bottom and left-right parts + if (IsGoodMuon(fgValuesMCH, fgValuesMCHpv, configMuons.fTrackChi2MchUp, configMuons.fPMchLow, configMuons.fPtMchLow, -1.E10, 1.E10, configMuons.fRabsLow, configMuons.fRabsUp, configMuons.fSigmaPdcaUp)) { + int Quadrant = GetQuadrantPhi(fgValuesMCH.phi * 180.0 / TMath::Pi()); + int TopBottom = (Quadrant == 0 || Quadrant == 1) ? 0 : 1; + int LeftRight = (Quadrant == 0 || Quadrant == 3) ? 0 : 1; + int PosNeg = fgValuesMCH.sign > 0 ? 0 : 1; + float eta = fgValuesMCH.eta; + float pT = fgValuesMCH.pT; + + // same-event case + if (PosNeg == 0) { + registry.get(HIST("muons/TrackEtaPos"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaPos"))->Fill(pT, eta); + + if (TopBottom == 0) { + registry.get(HIST("muons/TrackEtaPos_T"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaPos_T"))->Fill(pT, eta); + } else if (TopBottom == 1) { + registry.get(HIST("muons/TrackEtaPos_B"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaPos_B"))->Fill(pT, eta); + } + + if (LeftRight == 0) { + registry.get(HIST("muons/TrackEtaPos_L"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaPos_L"))->Fill(pT, eta); + } else if (LeftRight == 1) { + registry.get(HIST("muons/TrackEtaPos_R"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaPos_R"))->Fill(pT, eta); + } + } else if (PosNeg == 1) { + registry.get(HIST("muons/TrackEtaNeg"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaNeg"))->Fill(pT, eta); + if (TopBottom == 0) { + registry.get(HIST("muons/TrackEtaNeg_T"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaNeg_T"))->Fill(pT, eta); + } else if (TopBottom == 1) { + registry.get(HIST("muons/TrackEtaNeg_B"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaNeg_B"))->Fill(pT, eta); + } + + if (LeftRight == 0) { + registry.get(HIST("muons/TrackEtaNeg_L"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaNeg_L"))->Fill(pT, eta); + } else if (LeftRight == 1) { + registry.get(HIST("muons/TrackEtaNeg_R"))->Fill(eta); + registry.get(HIST("muons/TrackPt_TrackEtaNeg_R"))->Fill(pT, eta); + } + } + } + } + + 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(fgValuesMCHpv.dcaX * fgValuesMCHpv.dcaX + fgValuesMCHpv.dcaY * fgValuesMCHpv.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(fgValuesMCHpv.dcaX * fgValuesMCHpv.dcaX + fgValuesMCHpv.dcaY * fgValuesMCHpv.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 < static_cast(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 < static_cast(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, 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, 30., 4., 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, 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 + std::vector mchTrackExtrap; + for (const 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 + std::vector mftTrackExtrap; + for (const 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 + TrackRealigned mchrealignedTmp; + VarClusters fgValuesClsTmp; + if (!FillClusters(muon, clusters, fgValuesClsTmp, mchrealignedTmp)) { + continue; // Refit is not valid + } + + // Loop over attached clusters + for (int iCls = 0; iCls < static_cast(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, 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(); // unused parameter? + 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 + TrackRealigned 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, 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(static_cast(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 + TrackRealigned 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 < static_cast(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 required + if (configQAs.fEnableQAResidual) { + runResidual(collisions, muons, mfts, clusters, mchtrack, mchrealigned, mfttrack, fgValuesCollGlo, fgValuesMCH, fgValuesMCHpv, fgValuesMFT); + } + + //// Fill MFT DCA QA checks if required + if (configQAs.fEnableQADCA) { + runDCA<0, 1>(collisions, 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 (const 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; + TrackRealigned 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, fgValuesMuon2, fgValuesMuonPV2); + // Calculate DCA + FillPropagation<1>(muonTrack1, collision1, fgValuesMuon1, fgValuesMuonPV1, kToDCA); + FillPropagation<1>(muonTrack2, collision2, fgValuesMuon2, fgValuesMuonPV2, kToDCA); + } + + int sign1 = muonTrack1.sign(); + int sign2 = muonTrack2.sign(); + + // only consider opposite-sign pairs + if ((sign1 * sign2) >= 0) + continue; + + const auto& muonPos = fgValuesMuon1.sign > 0 ? fgValuesMuon1 : fgValuesMuon2; + const auto& muonNeg = fgValuesMuon1.sign < 0 ? fgValuesMuon1 : fgValuesMuon2; + // for DCA + const auto& muonPosPV = fgValuesMuon1.sign > 0 ? fgValuesMuonPV1 : fgValuesMuonPV2; + const auto& muonNegPV = fgValuesMuon1.sign < 0 ? fgValuesMuonPV1 : fgValuesMuonPV2; + // μ⁺ variables + double muPosPt = muonPos.pT; + double muPosEta = muonPos.eta; + double muPosRabs = muonPos.rabs; + double muPosPhi = muonPos.phi * 180.0 / TMath::Pi(); + double muPosDca = std::sqrt(muonPos.dcaX * muonPos.dcaX + muonPos.dcaY * muonPos.dcaY); + // μ⁻ variables + double muNegPt = muonNeg.pT; + double muNegEta = muonNeg.eta; + double muNegRabs = muonNeg.rabs; + double muNegPhi = muonNeg.phi * 180.0 / TMath::Pi(); + double muNegDca = std::sqrt(muonNeg.dcaX * muonNeg.dcaX + muonNeg.dcaY * muonNeg.dcaY); + + int Quadrant1 = GetQuadrantPhi(muonTrack1.phi() * 180.0 / TMath::Pi()); + int Quadrant2 = GetQuadrantPhi(muonTrack2.phi() * 180.0 / TMath::Pi()); + int TopBottom1 = (Quadrant1 == 0 || Quadrant1 == 1) ? 0 : 1; + int TopBottom2 = (Quadrant2 == 0 || Quadrant2 == 1) ? 0 : 1; + int LeftRight1 = (Quadrant1 == 0 || Quadrant1 == 3) ? 0 : 1; + int LeftRight2 = (Quadrant2 == 0 || Quadrant2 == 3) ? 0 : 1; + + bool goodMuonTracks = (IsGoodMuon(fgValuesMuon1, fgValuesMuonPV1) && IsGoodMuon(fgValuesMuon2, fgValuesMuonPV2)); + bool goodGlobalMuonTracks = (IsGoodGlobalMuon(fgValuesMuon1, fgValuesMuonPV1) && IsGoodGlobalMuon(fgValuesMuon2, fgValuesMuonPV2)); + + bool sameEvent = (collisionIndex1 == collisionIndex2); + + // dimuon variables + double mass = GetMuMuInvariantMass(fgValuesMuonPV1, fgValuesMuonPV2); + double pT = GetMuMuPt(fgValuesMuonPV1, fgValuesMuonPV2); + double yPair = GetMuMuRap(fgValuesMuonPV1, fgValuesMuonPV2); + double dcaXPair; + double dcaYPair; + if (configRealign.fDoRealign) { + dcaXPair = muonPos.dcaX - muonNeg.dcaX; + dcaYPair = muonPos.dcaY - muonNeg.dcaY; + } else { + dcaXPair = muonPosPV.dcaX - muonNegPV.dcaX; + dcaYPair = muonPosPV.dcaY - muonNegPV.dcaY; + } + if (goodMuonTracks) { + if (sameEvent) { + // same-event case + if (configQAs.fEnableSingleMuonDiMuonCorrelations) { + // single muons + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosPt_MuonKine_MuonCuts"))->Fill(mass, pT, muPosPt); + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegPt_MuonKine_MuonCuts"))->Fill(mass, pT, muNegPt); + // + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosEta_MuonKine_MuonCuts"))->Fill(mass, pT, muPosEta); + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegEta_MuonKine_MuonCuts"))->Fill(mass, pT, muNegEta); + // + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosRabs_MuonKine_MuonCuts"))->Fill(mass, pT, muPosRabs); + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegRabs_MuonKine_MuonCuts"))->Fill(mass, pT, muNegRabs); + // + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosDca_MuonKine_MuonCuts"))->Fill(mass, pT, muPosDca); + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegDca_MuonKine_MuonCuts"))->Fill(mass, pT, muNegDca); + // + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuPosPhi_MuonKine_MuonCuts"))->Fill(mass, pT, muPosPhi); + registryDimuon.get(HIST("dimuon/same-event/single-muon-dimuon-correlations/invariantMass_pT_MuNegPhi_MuonKine_MuonCuts"))->Fill(mass, pT, muNegPhi); + } + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts"))->Fill(mass, pT); + registryDimuon.get(HIST("dimuon/same-event/rapPair_MuonKine_MuonCuts"))->Fill(yPair); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts"))->Fill(mass, yPair); + registryDimuon.get(HIST("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts"))->Fill(pT, yPair); + + // dimuon DCA + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosDCAx_minus_MuNegDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosDCAy_minus_MuNegDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + + // dimuon top-bottom and left-right separation + if (TopBottom1 == 0 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TT"))->Fill(mass, pT); + registryDimuon.get(HIST("dimuon/same-event/rapPair_MuonKine_MuonCuts_TT"))->Fill(yPair); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_TT"))->Fill(mass, yPair); + registryDimuon.get(HIST("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_TT"))->Fill(pT, yPair); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } else if ((TopBottom1 == 0 && TopBottom2 == 1) || (TopBottom1 == 1 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TB"))->Fill(mass, pT); + registryDimuon.get(HIST("dimuon/same-event/rapPair_MuonKine_MuonCuts_TB"))->Fill(yPair); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_TB"))->Fill(mass, yPair); + registryDimuon.get(HIST("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_TB"))->Fill(pT, yPair); + if (TopBottom1 == 0 && TopBottom2 == 1) { + if (sign1 > 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TPBN"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } else { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TNBP"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } + } else if (TopBottom1 == 1 && TopBottom2 == 0) { + if (sign2 > 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TPBN"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosTDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } else { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_TNBP"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } + } + } else if (TopBottom1 == 1 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_BB"))->Fill(mass, pT); + registryDimuon.get(HIST("dimuon/same-event/rapPair_MuonKine_MuonCuts_BB"))->Fill(yPair); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_BB"))->Fill(mass, yPair); + registryDimuon.get(HIST("dimuon/same-event/pT_rapPair_MuonKine_MuonCuts_BB"))->Fill(pT, yPair); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/opposite-sign/DCA/pT_MuPosBDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } + + if (LeftRight1 == 0 && LeftRight2 == 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LL"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LL"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LL"))->Fill(mass, pT); + registryDimuon.get(HIST("dimuon/same-event/rapPair_MuonKine_MuonCuts_LL"))->Fill(yPair); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_LL"))->Fill(mass, yPair); + } else if ((LeftRight1 == 0 && LeftRight2 == 1) || (LeftRight1 == 1 && LeftRight2 == 0)) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LR"))->Fill(mass, pT); + registryDimuon.get(HIST("dimuon/same-event/rapPair_MuonKine_MuonCuts_LR"))->Fill(yPair); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_LR"))->Fill(mass, yPair); + if (LeftRight1 == 0 && LeftRight2 == 1) { + if (sign1 > 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LPRN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LNRP"))->Fill(mass, pT); + } + } else if (LeftRight1 == 1 && LeftRight2 == 0) { + if (sign2 > 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LPRN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_LNRP"))->Fill(mass, pT); + } + } + } else if (LeftRight1 == 1 && LeftRight2 == 1) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_MuonCuts_RR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_MuonCuts_RR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_MuonCuts_RR"))->Fill(mass, pT); + registryDimuon.get(HIST("dimuon/same-event/rapPair_MuonKine_MuonCuts_RR"))->Fill(yPair); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_rapPair_MuonKine_MuonCuts_RR"))->Fill(mass, yPair); + } + } 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts"))->Fill(mass, pT); + + // dimuon DCA + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosDCAx_minus_MuNegDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosDCAy_minus_MuNegDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + + // dimuon top-bottom and left-right separation + if (TopBottom1 == 0 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TT"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosTDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosTDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } else if ((TopBottom1 == 0 && TopBottom2 == 1) || (TopBottom1 == 1 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TB"))->Fill(mass, pT); + if (TopBottom1 == 0 && TopBottom2 == 1) { + if (sign1 > 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TPBN"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosTDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosTDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } else { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TNBP"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosBDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosBDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } + } else if (TopBottom1 == 1 && TopBottom2 == 0) { + if (sign2 > 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TPBN"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosTDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosTDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } else { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_TNBP"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosBDCAx_minus_MuNegTDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosBDCAy_minus_MuNegTDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } + } + } else if (TopBottom1 == 1 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_BB"))->Fill(mass, pT); + if (mass >= fDimuonDCAMassLow && mass <= fDimuonDCAMassHigh) { + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosBDCAx_minus_MuNegBDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/mixed-event/DCA/pT_MuPosBDCAy_minus_MuNegBDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } + + if (LeftRight1 == 0 && LeftRight2 == 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LL"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LL"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LL"))->Fill(mass, pT); + } else if ((LeftRight1 == 0 && LeftRight2 == 1) || (LeftRight1 == 1 && LeftRight2 == 0)) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LR"))->Fill(mass, pT); + if (LeftRight1 == 0 && LeftRight2 == 1) { + if (sign1 > 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LPRN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LNRP"))->Fill(mass, pT); + } + } else if (LeftRight1 == 1 && LeftRight2 == 0) { + if (sign2 > 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LPRN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_LNRP"))->Fill(mass, pT); + } + } + } else if (LeftRight1 == 1 && LeftRight2 == 1) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_MuonCuts_RR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_MuonCuts_RR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_MuonCuts_RR"))->Fill(mass, pT); + } + } + } + + 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); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts"))->Fill(mass, pT); + + if (TopBottom1 == 0 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TT"))->Fill(mass, pT); + } else if ((TopBottom1 == 0 && TopBottom2 == 1) || (TopBottom1 == 1 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TB"))->Fill(mass, pT); + if (TopBottom1 == 0 && TopBottom2 == 1) { + if (sign1 > 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass, pT); + } + } else if (TopBottom1 == 1 && TopBottom2 == 0) { + if (sign2 > 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass, pT); + } + } + } else if (TopBottom1 == 1 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_BB"))->Fill(mass, pT); + } + + if (LeftRight1 == 0 && LeftRight2 == 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LL"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LL"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LL"))->Fill(mass, pT); + } else if ((LeftRight1 == 0 && LeftRight2 == 1) || (LeftRight1 == 1 && LeftRight2 == 0)) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LR"))->Fill(mass, pT); + if (TopBottom1 == 0 && TopBottom2 == 1) { + if (sign1 > 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass, pT); + } + } else if (TopBottom1 == 1 && TopBottom2 == 0) { + if (sign2 > 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass, pT); + } + } + } else if (LeftRight1 == 1 && LeftRight2 == 1) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMuonCuts_RR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMassFull_MuonKine_GlobalMuonCuts_RR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMuonCuts_RR"))->Fill(mass, pT); + } + } 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts"))->Fill(mass, pT); + + if (TopBottom1 == 0 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TT"))->Fill(mass, pT); + } else if ((TopBottom1 == 0 && TopBottom2 == 1) || (TopBottom1 == 1 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TB"))->Fill(mass, pT); + if (TopBottom1 == 0 && TopBottom2 == 1) { + if (sign1 > 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass, pT); + } + } else if (TopBottom1 == 1 && TopBottom2 == 0) { + if (sign2 > 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TPBN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_TNBP"))->Fill(mass, pT); + } + } + } else if (TopBottom1 == 1 && TopBottom2 == 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_BB"))->Fill(mass, pT); + } + + if (LeftRight1 == 0 && LeftRight2 == 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LL"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LL"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LL"))->Fill(mass, pT); + } else if ((LeftRight1 == 0 && LeftRight2 == 1) || (LeftRight1 == 1 && LeftRight2 == 0)) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LR"))->Fill(mass, pT); + if (TopBottom1 == 0 && TopBottom2 == 1) { + if (sign1 > 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass, pT); + } + } else if (TopBottom1 == 1 && TopBottom2 == 0) { + if (sign2 > 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LPRN"))->Fill(mass, pT); + } else { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_LNRP"))->Fill(mass, pT); + } + } + } else if (LeftRight1 == 1 && LeftRight2 == 1) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMuonCuts_RR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMassFull_MuonKine_GlobalMuonCuts_RR"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMuonCuts_RR"))->Fill(mass, pT); + } + } + } + } + + if (configQAs.fEnableQADimuonSameSignDCA) { + for (const 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; + TrackRealigned 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, fgValuesMuon2, fgValuesMuonPV2); + // Calculate DCA + FillPropagation<1>(muonTrack1, collision1, fgValuesMuon1, fgValuesMuonPV1, kToDCA); + FillPropagation<1>(muonTrack2, collision2, fgValuesMuon2, fgValuesMuonPV2, kToDCA); + } + + int sign1 = muonTrack1.sign(); + int sign2 = muonTrack2.sign(); + + // only consider same-sign pairs + if ((sign1 * sign2) <= 0) + continue; + + bool isPP = false; + bool isMM = false; + if (sign1 > 0 && sign2 > 0) + isPP = true; + else + isMM = true; + + int Quadrant1 = GetQuadrantPhi(muonTrack1.phi() * 180.0 / TMath::Pi()); + int Quadrant2 = GetQuadrantPhi(muonTrack2.phi() * 180.0 / TMath::Pi()); + int TopBottom1 = (Quadrant1 == 0 || Quadrant1 == 1) ? 0 : 1; + int TopBottom2 = (Quadrant2 == 0 || Quadrant2 == 1) ? 0 : 1; + + bool goodMuonTracks = (IsGoodMuon(fgValuesMuon1, fgValuesMuonPV1) && IsGoodMuon(fgValuesMuon2, fgValuesMuonPV2)); + + // dimuon variables + double mass = GetMuMuInvariantMass(fgValuesMuonPV1, fgValuesMuonPV2); + double pT = GetMuMuPt(fgValuesMuonPV1, fgValuesMuonPV2); + double dcaXPair = 0.0; + double dcaYPair = 0.0; + if (TopBottom1 != TopBottom2) { // only mixed pairs + if (TopBottom1 == 0 && TopBottom2 == 1) { // muon1 = top, muon2 = bottom + if (configRealign.fDoRealign) { + dcaXPair = fgValuesMuon1.dcaX - fgValuesMuon2.dcaX; + dcaYPair = fgValuesMuon1.dcaY - fgValuesMuon2.dcaY; + } else { + dcaXPair = fgValuesMuonPV1.dcaX - fgValuesMuonPV2.dcaX; + dcaYPair = fgValuesMuonPV1.dcaY - fgValuesMuonPV2.dcaY; + } + } else if (TopBottom1 == 1 && TopBottom2 == 0) { // muon2 = top, muon1 = bottom + if (configRealign.fDoRealign) { + dcaXPair = fgValuesMuon2.dcaX - fgValuesMuon1.dcaX; + dcaYPair = fgValuesMuon2.dcaY - fgValuesMuon1.dcaY; + } else { + dcaXPair = fgValuesMuonPV2.dcaX - fgValuesMuonPV1.dcaX; + dcaYPair = fgValuesMuonPV2.dcaY - fgValuesMuonPV1.dcaY; + } + } else if (configRealign.fDoRealign) { // no redefinition necessary if both on same half + dcaXPair = fgValuesMuon1.dcaX - fgValuesMuon2.dcaX; + dcaYPair = fgValuesMuon1.dcaY - fgValuesMuon2.dcaY; + } else { + dcaXPair = fgValuesMuonPV1.dcaX - fgValuesMuonPV2.dcaX; + dcaYPair = fgValuesMuonPV1.dcaY - fgValuesMuonPV2.dcaY; + } + } + if (mass < fDimuonDCAMassLow || mass > fDimuonDCAMassHigh) + continue; + + if (goodMuonTracks) { + // dimuon DCA + if (isPP) { + registryDimuon.get(HIST("dimuon/same-event/same-sign-PP/DCA/pT_Mu1DCAx_minus_Mu2DCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/same-sign-PP/DCA/pT_Mu1DCAy_minus_Mu2DCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } else if (isMM) { + registryDimuon.get(HIST("dimuon/same-event/same-sign-MM/DCA/pT_Mu1DCAx_minus_Mu2DCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/same-sign-MM/DCA/pT_Mu1DCAy_minus_Mu2DCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + // dimuon top-bottom separation + // TODO: left-right ? + if (TopBottom1 == 0 && TopBottom2 == 0) { + if (isPP) { + registryDimuon.get(HIST("dimuon/same-event/same-sign-PP/DCA/pT_Mu1TDCAx_minus_Mu2TDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/same-sign-PP/DCA/pT_Mu1TDCAy_minus_Mu2TDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } else if (isMM) { + registryDimuon.get(HIST("dimuon/same-event/same-sign-MM/DCA/pT_Mu1TDCAx_minus_Mu2TDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/same-sign-MM/DCA/pT_Mu1TDCAy_minus_Mu2TDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } else if ((TopBottom1 == 0 && TopBottom2 == 1) || (TopBottom1 == 1 && TopBottom2 == 0)) { + if (isPP) { + registryDimuon.get(HIST("dimuon/same-event/same-sign-PP/DCA/pT_MuTDCAx_minus_MuBDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/same-sign-PP/DCA/pT_MuTDCAy_minus_MuBDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } else if (isMM) { + registryDimuon.get(HIST("dimuon/same-event/same-sign-MM/DCA/pT_MuTDCAx_minus_MuBDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/same-sign-MM/DCA/pT_MuTDCAy_minus_MuBDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } else if (TopBottom1 == 1 && TopBottom2 == 1) { + if (isPP) { + registryDimuon.get(HIST("dimuon/same-event/same-sign-PP/DCA/pT_Mu1BDCAx_minus_Mu2BDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/same-sign-PP/DCA/pT_Mu1BDCAy_minus_Mu2BDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } else if (isMM) { + registryDimuon.get(HIST("dimuon/same-event/same-sign-MM/DCA/pT_Mu1BDCAx_minus_Mu2BDCAx_MuonKine_MuonCuts"))->Fill(pT, dcaXPair); + registryDimuon.get(HIST("dimuon/same-event/same-sign-MM/DCA/pT_Mu1BDCAy_minus_Mu2BDCAy_MuonKine_MuonCuts"))->Fill(pT, dcaYPair); + } + } + } + } + } + + for (const 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); + + TrackRealigned mchrealigned1, mchrealigned2; + VarClusters fgValuesCls1, fgValuesCls2; + if (!FillClusters(mchTrack1, clusters, fgValuesCls1, mchrealigned1) || !FillClusters(mchTrack2, 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, fgValuesMCHpv1, fgValuesMFTpv1); + FillPropagation<0, 1>(mftTrack2, collision2, fgValuesMCHpv2, fgValuesMFTpv2); + + int sign1 = mchTrack1.sign(); + int sign2 = mchTrack2.sign(); + + // only consider opposite-sign pairs + if ((sign1 * sign2) >= 0) + continue; + + // OLD definition using MFT halves + // 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); + + // NEW definition using MCH tracks, as is done for MUON (MCH-MID) tracks above + int Quadrant1 = GetQuadrantPhi(muonTrack1.phi() * 180.0 / TMath::Pi()); + int Quadrant2 = GetQuadrantPhi(muonTrack2.phi() * 180.0 / TMath::Pi()); + int TopBottom1 = (Quadrant1 == 0 || Quadrant1 == 1) ? 0 : 1; + int TopBottom2 = (Quadrant2 == 0 || Quadrant2 == 1) ? 0 : 1; + // int LeftRight1 = (Quadrant1 == 0 || Quadrant1 == 3) ? 0 : 1; + // int LeftRight2 = (Quadrant2 == 0 || Quadrant2 == 3) ? 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 pTmch = GetMuMuPt(fgValuesMCHpv1, fgValuesMCHpv2); + double mass = GetMuMuInvariantMass(fgValuesMuonPV1, fgValuesMuonPV2); + // double pT = GetMuMuPt(fgValuesMuonPV1, fgValuesMuonPV2); + double massScaled = GetMuMuInvariantMass(fgValuesMFTpv1, fgValuesMFTpv2); + // double pTscaled = GetMuMuPt(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); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts"))->Fill(massScaled, pTmch); + + if (TopBottom1 == 0 && TopBottom2 == 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts_TT"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_TT"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TT"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_TT"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_TT"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_TT"))->Fill(massScaled, pTmch); + } else if (TopBottom1 == 0 && TopBottom2 == 1) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts_TB"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_TB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TB"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_TB"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_TB"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_TB"))->Fill(massScaled, pTmch); + } else if (TopBottom1 == 1 && TopBottom2 == 0) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts_BT"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_BT"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BT"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_BT"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_BT"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_BT"))->Fill(massScaled, pTmch); + } else if (TopBottom1 == 1 && TopBottom2 == 1) { + registryDimuon.get(HIST("dimuon/same-event/invariantMass_MuonKine_GlobalMatchesCuts_BB"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_BB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BB"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_BB"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_BB"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/same-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_BB"))->Fill(massScaled, pTmch); + } + + // 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); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts"))->Fill(massScaled, pTmch); + + if (TopBottom1 == 0 && TopBottom2 == 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts_TT"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_TT"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TT"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_TT"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_TT"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_TT"))->Fill(massScaled, pTmch); + } else if (TopBottom1 == 0 && TopBottom2 == 1) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts_TB"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_TB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_TB"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_TB"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_TB"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_TB"))->Fill(massScaled, pTmch); + } else if (TopBottom1 == 1 && TopBottom2 == 0) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts_BT"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_BT"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BT"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_BT"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_BT"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_BT"))->Fill(massScaled, pTmch); + } else if (TopBottom1 == 1 && TopBottom2 == 1) { + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_MuonKine_GlobalMatchesCuts_BB"))->Fill(massMCH); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_GlobalMuonKine_GlobalMatchesCuts_BB"))->Fill(mass); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_ScaledMftKine_GlobalMatchesCuts_BB"))->Fill(massScaled); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_MuonKine_GlobalMatchesCuts_BB"))->Fill(massMCH, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_GlobalMuonKine_GlobalMatchesCuts_BB"))->Fill(mass, pTmch); + registryDimuon.get(HIST("dimuon/mixed-event/invariantMass_pT_ScaledMftKine_GlobalMatchesCuts_BB"))->Fill(massScaled, pTmch); + } + } + } + + // 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, 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/trackqa.cxx b/Common/Tasks/trackqa.cxx index 7f5498e5a2a..e445ba65336 100644 --- a/Common/Tasks/trackqa.cxx +++ b/Common/Tasks/trackqa.cxx @@ -13,12 +13,25 @@ // Task producing basic tracking qa histograms // -#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 "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include // std::swap +#include + +#include // FIXME: Replace M_PI using namespace o2; using namespace o2::framework; @@ -31,7 +44,7 @@ void customize(std::vector& workflowOptions) {"add-cut-qa", VariantType::Int, 0, {"Add track cut QA histograms."}}}; std::swap(workflowOptions, options); } -#include "Framework/runDataProcessing.h" +#include //**************************************************************************************** /** @@ -101,8 +114,8 @@ struct TrackQa { histos.fill(HIST("TrackPar/signed1Pt"), track.signed1Pt()); histos.fill(HIST("TrackPar/snp"), track.snp()); histos.fill(HIST("TrackPar/tgl"), track.tgl()); - for (unsigned int i = 0; i < 64; i++) { - if (track.flags() & (1 << i)) { + for (unsigned int i = 0; i < 32; i++) { + if (track.flags() & (1u << i)) { histos.fill(HIST("TrackPar/flags"), i); } } @@ -161,13 +174,13 @@ struct TrackQaMc { HistogramRegistry resolution{"Resolution", {}, OutputObjHandlingPolicy::QAObject}; - void init(o2::framework::InitContext&){ - - }; - - void process(soa::Join::iterator const&){ + void init(o2::framework::InitContext&) + { + } - }; + void process(soa::Join::iterator const&) + { + } }; //**************************************************************************************** diff --git a/Common/Tasks/validation.cxx b/Common/Tasks/validation.cxx index 5c464aebb30..b6afe11f2f2 100644 --- a/Common/Tasks/validation.cxx +++ b/Common/Tasks/validation.cxx @@ -8,18 +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. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "ReconstructionDataFormats/Track.h" +#include +#include +#include +#include + +#include -#include -#include #include -#include -namespace o2::aod -{ -} // namespace o2::aod using namespace o2; using namespace o2::framework; diff --git a/Common/Tasks/zdcTableReader.cxx b/Common/Tasks/zdcTableReader.cxx new file mode 100644 index 00000000000..b4b16094d49 --- /dev/null +++ b/Common/Tasks/zdcTableReader.cxx @@ -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. +/// +/// \brief Read output table from ZDC light ion task +/// \author chiara.oppedisano@cern.ch +// + +#include "Common/DataModel/ZDCLightIons.h" + +#include +#include +#include +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +struct ZDCLIAnalysis { + + // Configurable number of bins + Configurable useZvtx{"useZvtx", false, "If true uses Z_vertex"}; + Configurable zVval{"zVval", 10., "Z_vertex cut value"}; + Configurable tStampMin{"tStampMin", 100000., "minimum value for timestamp"}; + Configurable tStampMax{"tStampMax", 100000., ",maximum value for timestamp"}; + // + Configurable nBinsADC{"nBinsADC", 1000, "n bins 4 ZDC ADCs"}; + Configurable nBinsAmp{"nBinsAmp", 1025, "n bins 4 ZDC amplitudes"}; + Configurable nBinsTDC{"nBinsTDC", 480, "n bins 4 TDCs"}; + Configurable nBinsFit{"nBinsFit", 1000, "n bins 4 FIT"}; + Configurable MaxZN{"MaxZN", 4099.5, "Max 4 ZN histos"}; + Configurable MaxZP{"MaxZP", 3099.5, "Max 4 ZP histos"}; + Configurable MaxZEM{"MaxZEM", 3099.5, "Max 4 ZEM histos"}; + // + Configurable MaxMultFV0{"MaxMultFV0", 3000, "Max 4 FV0 histos"}; + Configurable MaxMultFT0{"MaxMultFT0", 3000, "Max 4 FT0 histos"}; + // + HistogramRegistry registry{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + registry.add("hZNApmc", "ZNApmc; ZNA amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, MaxZN}}}); + registry.add("hZPApmc", "ZPApmc; ZPA amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, MaxZP}}}); + registry.add("hZNCpmc", "ZNCpmc; ZNC amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, MaxZN}}}); + registry.add("hZPCpmc", "ZPCpmc; ZPC amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, MaxZP}}}); + registry.add("hZEM", "ZEM; ZEM1+ZEM2 amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, MaxZEM}}}); + registry.add("hZNAamplvsADC", "ZNA amplitude vs. ADC; ZNA ADC; ZNA amplitude", {HistType::kTH2F, {{{nBinsAmp, -0.5, 3. * MaxZN}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNCamplvsADC", "ZNC amplitude vs. ADC; ZNC ADC; ZNC amplitude", {HistType::kTH2F, {{{nBinsAmp, -0.5, 3. * MaxZN}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZPAamplvsADC", "ZPA amplitude vs. ADC; ZPA ADC; ZPA amplitude", {HistType::kTH2F, {{{nBinsAmp, -0.5, 3. * MaxZP}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZPCamplvsADC", "ZPC amplitude vs. ADC; ZPC ADC; ZPC amplitude", {HistType::kTH2F, {{{nBinsAmp, -0.5, 3. * MaxZP}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZNvsZEM", "ZN vs ZEM; ZEM; ZNA+ZNC", {HistType::kTH2F, {{{nBinsAmp, -0.5, MaxZEM}, {nBinsAmp, -0.5, 2. * MaxZN}}}}); + registry.add("hZNAvsZNC", "ZNA vs ZNC; ZNC; ZNA", {HistType::kTH2F, {{{nBinsAmp, -0.5, MaxZN}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZPAvsZPC", "ZPA vs ZPC; ZPC; ZPA", {HistType::kTH2F, {{{nBinsAmp, -0.5, MaxZP}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZNAvsZPA", "ZNA vs ZPA; ZPA; ZNA", {HistType::kTH2F, {{{nBinsAmp, -0.5, MaxZP}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNCvsZPC", "ZNC vs ZPC; ZPC; ZNC", {HistType::kTH2F, {{{nBinsAmp, -0.5, MaxZP}, {nBinsAmp, -0.5, MaxZN}}}}); + // + registry.add("hZNCcvsZNCsum", "ZNC PMC vs PMsum; ZNCC ADC; ZNCsum", {HistType::kTH2F, {{{nBinsADC, -0.5, 3. * MaxZN}, {nBinsADC, -0.5, 3. * MaxZN}}}}); + registry.add("hZNAcvsZNAsum", "ZNA PMC vs PMsum; ZNAsum", {HistType::kTH2F, {{{nBinsADC, -0.5, 3. * MaxZN}, {nBinsADC, -0.5, 3. * MaxZN}}}}); + // + registry.add("hZNCvstdc", "ZNC vs tdc; ZNC amplitude; ZNC TDC", {HistType::kTH2F, {{{480, -13.5, 11.45}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNAvstdc", "ZNA vs tdc; ZNA amplitude; ZNA TDC", {HistType::kTH2F, {{{480, -13.5, 11.45}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZPCvstdc", "ZPC vs tdc; ZPC amplitude; ZPC TDC", {HistType::kTH2F, {{{480, -13.5, 11.45}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZPAvstdc", "ZPA vs tdc; ZPA amplitude; ZPA TDC", {HistType::kTH2F, {{{480, -13.5, 11.45}, {nBinsAmp, -0.5, MaxZP}}}}); + // + registry.add("hZNvsV0A", "ZN vs V0A", {HistType::kTH2F, {{{nBinsFit, 0., MaxMultFV0}, {nBinsAmp, -0.5, 2. * MaxZN}}}}); + registry.add("hZNAvsFT0A", "ZNA vs FT0A", {HistType::kTH2F, {{{nBinsFit, 0., MaxMultFT0}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNCvsFT0C", "ZNC vs FT0C", {HistType::kTH2F, {{{nBinsFit, 0., MaxMultFT0}, {nBinsAmp, -0.5, MaxZN}}}}); + // + registry.add("hZNAvscentrFT0A", "ZNA vs centrality FT0A", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNAvscentrFT0C", "ZNA vs centrality FT0C", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNAvscentrFT0M", "ZNA vs centrality FT0M", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZPAvscentrFT0A", "ZPA vs centrality FT0A", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZPAvscentrFT0C", "ZPA vs centrality FT0C", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZPAvscentrFT0M", "ZPA vs centrality FT0M", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZNCvscentrFT0A", "ZNC vs centrality FT0A", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNCvscentrFT0C", "ZNC vs centrality FT0C", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNCvscentrFT0M", "ZNC vs centrality FT0M", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZPCvscentrFT0A", "ZPC vs centrality FT0A", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZPCvscentrFT0C", "ZPC vs centrality FT0C", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZPCvscentrFT0M", "ZPC vs centrality FT0M", {HistType::kTH2F, {{{100, 0., 100.}, {nBinsAmp, -0.5, MaxZP}}}}); + // + registry.add("hZNAvstimestamp", "ZNA vs timestamp", {HistType::kTH2F, {{{100, tStampMin, tStampMax}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZNCvstimestamp", "ZNC vs timestamp", {HistType::kTH2F, {{{100, tStampMin, tStampMax}, {nBinsAmp, -0.5, MaxZN}}}}); + registry.add("hZPAvstimestamp", "ZPA vs timestamp", {HistType::kTH2F, {{{100, tStampMin, tStampMax}, {nBinsAmp, -0.5, MaxZP}}}}); + registry.add("hZPCvstimestamp", "ZPC vs timestamp", {HistType::kTH2F, {{{100, tStampMin, tStampMax}, {nBinsAmp, -0.5, MaxZP}}}}); + } + + void process(aod::ZDCLightIons const& zdclightions) + { + for (auto const& zdc : zdclightions) { + auto tdczna = zdc.znaTdc(); + auto tdcznc = zdc.zncTdc(); + auto tdczpa = zdc.zpaTdc(); + auto tdczpc = zdc.zpcTdc(); + auto zna = zdc.znaAmpl(); + auto znaADC = zdc.znaPmc(); + auto znapm1 = zdc.znaPm1(); + auto znapm2 = zdc.znaPm2(); + auto znapm3 = zdc.znaPm3(); + auto znapm4 = zdc.znaPm4(); + auto znc = zdc.zncAmpl(); + auto zncADC = zdc.zncPmc(); + auto zncpm1 = zdc.zncPm1(); + auto zncpm2 = zdc.zncPm2(); + auto zncpm3 = zdc.zncPm3(); + auto zncpm4 = zdc.zncPm4(); + auto zpa = zdc.zpaAmpl(); + auto zpaADC = zdc.zpaPmc(); + auto zpc = zdc.zpcAmpl(); + auto zpcADC = zdc.zpcPmc(); + auto zem1 = zdc.zem1Ampl(); + auto zem2 = zdc.zem2Ampl(); + auto multFT0A = zdc.multFt0a(); + auto multFT0C = zdc.multFt0c(); + auto multV0A = zdc.multV0a(); + auto zvtx = zdc.vertexZ(); + auto centrFT0C = zdc.centralityFt0c(); + auto centrFT0A = zdc.centralityFt0a(); + auto centrFT0M = zdc.centralityFt0m(); + auto timestamp = zdc.timestamp(); + // auto selectionBits = zdc.selectionBits(); + + if ((useZvtx && (zvtx < zVval)) || !useZvtx) { + registry.get(HIST("hZNApmc"))->Fill(zna); + registry.get(HIST("hZNCpmc"))->Fill(znc); + registry.get(HIST("hZPApmc"))->Fill(zpa); + registry.get(HIST("hZPCpmc"))->Fill(zpc); + registry.get(HIST("hZEM"))->Fill(zem1 + zem2); + // + registry.get(HIST("hZNAamplvsADC"))->Fill(znaADC, zna); + registry.get(HIST("hZNCamplvsADC"))->Fill(zncADC, znc); + registry.get(HIST("hZPAamplvsADC"))->Fill(zpaADC, zpa); + registry.get(HIST("hZPCamplvsADC"))->Fill(zpcADC, zpc); + // + registry.get(HIST("hZNvsZEM"))->Fill(zem1 + zem2, zna + znc); + registry.get(HIST("hZNAvsZNC"))->Fill(znc, zna); + registry.get(HIST("hZPAvsZPC"))->Fill(zpc, zpa); + registry.get(HIST("hZNAvsZPA"))->Fill(zpa, zna); + registry.get(HIST("hZNCvsZPC"))->Fill(zpc, znc); + // + registry.get(HIST("hZNAvstdc"))->Fill(tdczna, zna); + registry.get(HIST("hZNCvstdc"))->Fill(tdcznc, znc); + registry.get(HIST("hZPAvstdc"))->Fill(tdczpa, zpa); + registry.get(HIST("hZPCvstdc"))->Fill(tdczpc, zpc); + // + registry.get(HIST("hZNAcvsZNAsum"))->Fill(znapm1 + znapm2 + znapm3 + znapm4, zna); + registry.get(HIST("hZNCcvsZNCsum"))->Fill(zncpm1 + zncpm2 + zncpm3 + zncpm4, znc); + // + registry.get(HIST("hZNvsV0A"))->Fill(multV0A / 100., zna + znc); + registry.get(HIST("hZNAvsFT0A"))->Fill((multFT0A) / 100., zna); + registry.get(HIST("hZNCvsFT0C"))->Fill((multFT0C) / 100., znc); + // + registry.get(HIST("hZNAvscentrFT0A"))->Fill(centrFT0A, zna); + registry.get(HIST("hZNAvscentrFT0C"))->Fill(centrFT0C, zna); + registry.get(HIST("hZNAvscentrFT0M"))->Fill(centrFT0M, zna); + registry.get(HIST("hZPAvscentrFT0A"))->Fill(centrFT0A, zpa); + registry.get(HIST("hZPAvscentrFT0C"))->Fill(centrFT0C, zpa); + registry.get(HIST("hZPAvscentrFT0M"))->Fill(centrFT0M, zpa); + registry.get(HIST("hZNCvscentrFT0A"))->Fill(centrFT0A, znc); + registry.get(HIST("hZNCvscentrFT0C"))->Fill(centrFT0C, znc); + registry.get(HIST("hZNCvscentrFT0M"))->Fill(centrFT0M, znc); + registry.get(HIST("hZPCvscentrFT0A"))->Fill(centrFT0A, zpc); + registry.get(HIST("hZPCvscentrFT0C"))->Fill(centrFT0C, zpc); + registry.get(HIST("hZPCvscentrFT0M"))->Fill(centrFT0M, zpc); + // + registry.get(HIST("hZNAvstimestamp"))->Fill(timestamp, zna); + registry.get(HIST("hZNCvstimestamp"))->Fill(timestamp, znc); + registry.get(HIST("hZPAvstimestamp"))->Fill(timestamp, zpa); + registry.get(HIST("hZPCvstimestamp"))->Fill(timestamp, zpc); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc) // + }; +} diff --git a/Common/Tools/CMakeLists.txt b/Common/Tools/CMakeLists.txt index 5140596629d..29950466a85 100644 --- a/Common/Tools/CMakeLists.txt +++ b/Common/Tools/CMakeLists.txt @@ -12,9 +12,9 @@ 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(aod-data-model-graph +# SOURCES aodDataModelGraph.cxx +# PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) o2physics_add_library(trackSelectionRequest SOURCES trackSelectionRequest.cxx diff --git a/Common/Tools/EventSelectionModule.h b/Common/Tools/EventSelectionModule.h new file mode 100644 index 00000000000..da724b4a658 --- /dev/null +++ b/Common/Tools/EventSelectionModule.h @@ -0,0 +1,1866 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file EventSelectionModule.h +/// \brief +/// \author ALICE + +#ifndef COMMON_TOOLS_EVENTSELECTIONMODULE_H_ +#define COMMON_TOOLS_EVENTSELECTIONMODULE_H_ + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define bitcheck(var, nbit) ((var) & (static_cast(1) << (nbit))) +#define bitcheck64(var, nbit) ((var) & (static_cast(1) << (nbit))) + +//__________________________________________ +// MultModule + +namespace o2 +{ +namespace common +{ +namespace eventselection +{ +static const double bcNS = o2::constants::lhc::LHCBunchSpacingNS; +static const int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; + +// for providing temporary buffer +// FIXME ideally cursors could be readable +// to avoid duplicate memory allocation but ok +struct bcselEntry { + uint32_t alias{0}; + uint64_t selection{0}; + uint32_t rct{0}; + int foundFT0Id = -1; + int foundFV0Id = -1; + int foundFDDId = -1; + int foundZDCId = -1; +}; + +// bc selection configurables +struct bcselConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "bcselOpts"; + o2::framework::Configurable amIneeded{"amIneeded", -1, "run BC selection or not. -1: automatic; 0: no; 1: yes"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confTriggerBcShift{"triggerBcShift", 0, "set either custom shift or 999 for apass2/apass3 in LHC22o-t"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::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) + o2::framework::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) + o2::framework::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) + o2::framework::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) + o2::framework::Configurable confCheckRunDurationLimits{"checkRunDurationLimits", false, "Check if the BCs are within the run duration limits"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable> maxInactiveChipsPerLayer{"maxInactiveChipsPerLayer", {8, 8, 8, 111, 111, 195, 195}, "Maximum allowed number of inactive ITS chips per layer"}; + o2::framework::Configurable confNumberOfOrbitsPerTF{"NumberOfOrbitsPerTF", -1, "Number of orbits per Time Frame. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) +}; + +// event selection configurables +struct evselConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "evselOpts"; + bool isMC_metadata = false; + o2::framework::Configurable amIneeded{"amIneeded", -1, "run event selection or not. -1: automatic; 0: no; 1: yes"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable muonSelection{"muonSelection", 0, "0 - barrel, 1 - muon selection with pileup cuts, 2 - muon selection without pileup cuts"}; + o2::framework::Configurable maxDiffZvtxFT0vsPV{"maxDiffZvtxFT0vsPV", 1., "maximum difference (in cm) between z-vertex from FT0 and PV"}; + o2::framework::Configurable isMC{"isMC", -1, "-1 - autoset, 0 - data, 1 - MC"}; + o2::framework::Configurable confSigmaBCforHighPtTracks{"confSigmaBCforHighPtTracks", 4, "Custom sigma (in bcs) for collisions with high-pt tracks"}; + + // configurables for occupancy-based event selection + o2::framework::Configurable confTimeIntervalForOccupancyCalculationMin{"TimeIntervalForOccupancyCalculationMin", -40, "Min time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confTimeIntervalForOccupancyCalculationMax{"TimeIntervalForOccupancyCalculationMax", 100, "Max time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confTimeRangeVetoOnCollStrict{"TimeRangeVetoOnCollStrict", 10.0, "Exclusion of a collision if there are other collisions nearby, +/- us"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confTimeRangeVetoOnCollNarrow{"TimeRangeVetoOnCollNarrow", 0.25, "Exclusion of a collision if other collisions nearby, to suppress bc-collision mis-associations, +/- us"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confFT0CamplCutVetoOnCollInTimeRange{"FT0CamplPerCollCutVetoOnCollInTimeRange", 8000, "Max allowed FT0C amplitude for each nearby collision in +/- time range"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confFT0CamplCutVetoOnCollInROF{"FT0CamplPerCollCutVetoOnCollInROF", 5000, "Max allowed FT0C amplitude for each nearby collision inside this ITS ROF"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confEpsilonVzDiffVetoInROF{"EpsilonVzDiffVetoInROF", 0.3, "Minumum distance to nearby collisions along z inside this ITS ROF, cm"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confUseWeightsForOccupancyVariable{"UseWeightsForOccupancyEstimator", 1, "Use or not the delta-time weights for the occupancy estimator"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confNumberOfOrbitsPerTF{"NumberOfOrbitsPerTF", -1, "Number of orbits per Time Frame. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) + + // configurables for light-ion event selection + o2::framework::Configurable confLightIonsNsigmaOnVzDiff{"VzDiffNsigma", 3.0, "+/- nSigma on vZ difference by FT0 and by tracks"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confLightIonsMarginVzDiff{"VzDiffMargin", 0.2, "margin for +/- nSigma cut on vZ difference by FT0 and by tracks, cm"}; // o2-linter: disable=name/configurable (temporary fix) +}; + +// luminosity configurables +struct lumiConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "lumiOpts"; + o2::framework::Configurable amIneeded{"amIneeded", -1, "run BC selection or not. -1: automatic; 0: no; 1: yes"}; // o2-linter: disable=name/configurable (temporary fix) +}; + +class BcSelectionModule +{ + public: + BcSelectionModule() + { + // constructor + } + // declaration of structs here + // (N.B.: will be invisible to the outside, create your own copies) + o2::common::eventselection::bcselConfigurables bcselOpts; + + 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 + std::string strLPMProductionTag = ""; // MC production tag to be retrieved from AO2D metadata + + 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 + + template + void init(TContext& context, TBcSelOpts const& external_bcselopts, THistoRegistry& histos, TMetadataInfo const& metadataInfo) + { + // read in configurations from the task where it's used + bcselOpts = external_bcselopts; + + if (bcselOpts.amIneeded.value < 0) { + int bcSelNeeded = -1, evSelNeeded = -1; + bcselOpts.amIneeded.value = 0; + enableFlagIfTableRequired(context, "BcSels", bcSelNeeded); + enableFlagIfTableRequired(context, "EvSels", evSelNeeded); + if (bcSelNeeded == 1) { + bcselOpts.amIneeded.value = 1; + LOGF(info, "BC Selection / Autodetection for aod::BcSels: subscription present, will generate."); + } + if (evSelNeeded == 1 && bcSelNeeded == 0) { + bcselOpts.amIneeded.value = 1; + LOGF(info, "BC Selection / Autodetection for aod::BcSels: not there, but EvSel needed. Will generate."); + } + if (bcSelNeeded == 0 && evSelNeeded == 0) { + LOGF(info, "BC Selection / Autodetection for aod::BcSels: not required. Skipping generation."); + return; + } + } + strLPMProductionTag = metadataInfo.get("LPMProductionTag"); // to extract info from ccdb by the tag + + // add counter + histos.add("bcselection/hCounterInvalidBCTimestamp", "", o2::framework::kTH1D, {{1, 0., 1.}}); + } + + //__________________________________________________ + template + bool configure(TCCDB& ccdb, TBCs const& bcs) + { + if (bcs.size() == 0) { + return false; + } + int run = bcs.iteratorAt(0).runNumber(); + if (run != lastRun) { + lastRun = run; + int run3min = 500000; + if (run < run3min) { // unanchored Run3 MC + auto runDuration = ccdb->getRunDuration(run, true); // fatalise if timestamps are not found + // SOR and EOR timestamps + sorTimestamp = runDuration.first; // timestamp of the SOR/SOX/STF in ms + eorTimestamp = runDuration.second; // timestamp of the EOR/EOX/ETF in ms + auto ctp = ccdb->template getForTimeStamp>("CTP/Calib/OrbitReset", sorTimestamp / 2 + eorTimestamp / 2); + auto orbitResetMUS = (*ctp)[0]; + // first bc of the first orbit + bcSOR = static_cast((sorTimestamp * 1000 - orbitResetMUS) / o2::constants::lhc::LHCOrbitMUS) * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = 32; // hard-coded for Run3 MC (no info from ccdb at the moment) + } else { + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run, strLPMProductionTag); + // SOR and EOR timestamps + sorTimestamp = runInfo.sor; + eorTimestamp = runInfo.eor; + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = bcselOpts.confNumberOfOrbitsPerTF < 0 ? runInfo.orbitsPerTF * nBCsPerOrbit : bcselOpts.confNumberOfOrbitsPerTF * nBCsPerOrbit; + } + + // timestamp of the middle of the run used to access run-wise CCDB entries + int64_t ts = sorTimestamp / 2 + eorTimestamp / 2; + // access ITSROF and TF border margins + par = ccdb->template getForTimeStamp("EventSelection/EventSelectionParams", ts); + mITSROFrameStartBorderMargin = bcselOpts.confITSROFrameStartBorderMargin < 0 ? par->fITSROFrameStartBorderMargin : bcselOpts.confITSROFrameStartBorderMargin; + mITSROFrameEndBorderMargin = bcselOpts.confITSROFrameEndBorderMargin < 0 ? par->fITSROFrameEndBorderMargin : bcselOpts.confITSROFrameEndBorderMargin; + mTimeFrameStartBorderMargin = bcselOpts.confTimeFrameStartBorderMargin < 0 ? par->fTimeFrameStartBorderMargin : bcselOpts.confTimeFrameStartBorderMargin; + mTimeFrameEndBorderMargin = bcselOpts.confTimeFrameEndBorderMargin < 0 ? par->fTimeFrameEndBorderMargin : bcselOpts.confTimeFrameEndBorderMargin; + // ITSROF parameters + auto alppar = ccdb->template getForTimeStamp>("ITS/Config/AlpideParam", ts); + rofOffset = alppar->roFrameBiasInBC; + rofLength = alppar->roFrameLengthInBC; + // Trigger aliases + aliases = ccdb->template getForTimeStamp("EventSelection/TriggerAliases", ts); + + // prepare map of inactive chips + auto itsDeadMap = ccdb->template 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->template getSpecific>("RCT/Flags/RunFlags", ts, metadata); + ccdb->setFatalWhenNull(1); + if (mapRCT == nullptr) { + LOGP(info, "rct object missing... inserting dummy rct flags"); + mapRCT = new std::map; + uint32_t dummyValue = 1u << 31; // setting bit 31 to indicate that rct object is missing + mapRCT->insert(std::pair(sorTimestamp, dummyValue)); + } + } + return true; + } + + //__________________________________________________ + template + void processRun2(TCCDB const& ccdb, TBCs const& bcs, TTimestamps const& timestamps, TBcSelBuffer& bcselbuffer, TBcSelCursor& bcsel) + { + if (bcselOpts.amIneeded.value == 0) { + bcselbuffer.clear(); + return; + } + bcselbuffer.clear(); + for (const auto& bc : bcs) { + uint64_t timestamp = timestamps[bc.globalIndex()]; + par = ccdb->template getForTimeStamp("EventSelection/EventSelectionParams", timestamp); + aliases = ccdb->template getForTimeStamp("EventSelection/TriggerAliases", timestamp); + // fill fired aliases + uint32_t alias{0}; + uint64_t triggerMask = bc.triggerMask(); + for (const auto& al : aliases->GetAliasToTriggerMaskMap()) { + if (triggerMask & al.second) { + alias |= BIT(al.first); + } + } + uint64_t triggerMaskNext50 = bc.triggerMaskNext50(); + for (const auto& al : aliases->GetAliasToTriggerMaskNext50Map()) { + if (triggerMaskNext50 & al.second) { + alias |= BIT(al.first); + } + } + alias |= BIT(kALL); + + // get timing info from ZDC, FV0, FT0 and FDD + float timeZNA = bc.has_zdc() ? bc.zdc().timeZNA() : -999.f; + float timeZNC = bc.has_zdc() ? bc.zdc().timeZNC() : -999.f; + float timeV0A = bc.has_fv0a() ? bc.fv0a().time() : -999.f; + float timeV0C = bc.has_fv0c() ? bc.fv0c().time() : -999.f; + float timeT0A = bc.has_ft0() ? bc.ft0().timeA() : -999.f; + float timeT0C = bc.has_ft0() ? bc.ft0().timeC() : -999.f; + float timeFDA = bc.has_fdd() ? bc.fdd().timeA() : -999.f; + float timeFDC = bc.has_fdd() ? bc.fdd().timeC() : -999.f; + + LOGF(debug, "timeZNA=%f timeZNC=%f", timeZNA, timeZNC); + LOGF(debug, "timeV0A=%f timeV0C=%f", timeV0A, timeV0C); + LOGF(debug, "timeFDA=%f timeFDC=%f", timeFDA, timeFDC); + LOGF(debug, "timeT0A=%f timeT0C=%f", timeT0A, timeT0C); + + // fill time-based selection criteria + uint64_t selection{0}; + selection |= timeV0A > par->fV0ABBlower && timeV0A < par->fV0ABBupper ? BIT(aod::evsel::kIsBBV0A) : 0; + selection |= timeV0C > par->fV0CBBlower && timeV0C < par->fV0CBBupper ? BIT(aod::evsel::kIsBBV0C) : 0; + selection |= timeFDA > par->fFDABBlower && timeFDA < par->fFDABBupper ? BIT(aod::evsel::kIsBBFDA) : 0; + selection |= timeFDC > par->fFDCBBlower && timeFDC < par->fFDCBBupper ? BIT(aod::evsel::kIsBBFDC) : 0; + selection |= !(timeV0A > par->fV0ABGlower && timeV0A < par->fV0ABGupper) ? BIT(aod::evsel::kNoBGV0A) : 0; + selection |= !(timeV0C > par->fV0CBGlower && timeV0C < par->fV0CBGupper) ? BIT(aod::evsel::kNoBGV0C) : 0; + selection |= !(timeFDA > par->fFDABGlower && timeFDA < par->fFDABGupper) ? BIT(aod::evsel::kNoBGFDA) : 0; + selection |= !(timeFDC > par->fFDCBGlower && timeFDC < par->fFDCBGupper) ? BIT(aod::evsel::kNoBGFDC) : 0; + selection |= (timeT0A > par->fT0ABBlower && timeT0A < par->fT0ABBupper) ? BIT(aod::evsel::kIsBBT0A) : 0; + selection |= (timeT0C > par->fT0CBBlower && timeT0C < par->fT0CBBupper) ? BIT(aod::evsel::kIsBBT0C) : 0; + selection |= (timeZNA > par->fZNABBlower && timeZNA < par->fZNABBupper) ? BIT(aod::evsel::kIsBBZNA) : 0; + selection |= (timeZNC > par->fZNCBBlower && timeZNC < par->fZNCBBupper) ? BIT(aod::evsel::kIsBBZNC) : 0; + selection |= !(std::fabs(timeZNA) > par->fZNABGlower && std::fabs(timeZNA) < par->fZNABGupper) ? BIT(aod::evsel::kNoBGZNA) : 0; + selection |= !(std::fabs(timeZNC) > par->fZNCBGlower && std::fabs(timeZNC) < par->fZNCBGupper) ? BIT(aod::evsel::kNoBGZNC) : 0; + selection |= (std::pow((timeZNA + timeZNC - par->fZNSumMean) / par->fZNSumSigma, 2) + std::pow((timeZNA - timeZNC - par->fZNDifMean) / par->fZNDifSigma, 2) < 1) ? BIT(aod::evsel::kIsBBZAC) : 0; + + // Calculate V0 multiplicity per ring + float multRingV0A[5] = {0.}; + float multRingV0C[4] = {0.}; + float multFV0A = 0; + float multFV0C = 0; + if (bc.has_fv0a()) { + for (unsigned int i = 0; i < bc.fv0a().amplitude().size(); ++i) { + int ring = bc.fv0a().channel()[i] / 8; + multRingV0A[ring] += bc.fv0a().amplitude()[i]; + multFV0A += bc.fv0a().amplitude()[i]; + } + } + + if (bc.has_fv0c()) { + for (unsigned int i = 0; i < bc.fv0c().amplitude().size(); ++i) { + int ring = bc.fv0c().channel()[i] / 8; + multRingV0C[ring] += bc.fv0c().amplitude()[i]; + multFV0C += bc.fv0c().amplitude()[i]; + } + } + + // Calculate pileup and background related selection flags + // V0A0 excluded from online V0A charge sum => excluding also from offline sum for consistency + float ofV0M = multFV0A + multFV0C - multRingV0A[0]; + float onV0M = bc.v0TriggerChargeA() + bc.v0TriggerChargeC(); + float ofSPD = bc.spdFiredChipsL0() + bc.spdFiredChipsL1(); + float onSPD = bc.spdFiredFastOrL0() + bc.spdFiredFastOrL1(); + float multV0C012 = multRingV0C[0] + multRingV0C[1] + multRingV0C[2]; + + selection |= (onV0M > par->fV0MOnVsOfA + par->fV0MOnVsOfB * ofV0M) ? BIT(aod::evsel::kNoV0MOnVsOfPileup) : 0; + selection |= (onSPD > par->fSPDOnVsOfA + par->fSPDOnVsOfB * ofSPD) ? BIT(aod::evsel::kNoSPDOnVsOfPileup) : 0; + selection |= (multRingV0C[3] > par->fV0CasymA + par->fV0CasymB * multV0C012) ? BIT(aod::evsel::kNoV0Casymmetry) : 0; + selection |= (TESTBIT(selection, aod::evsel::kIsBBV0A) || TESTBIT(selection, aod::evsel::kIsBBV0C) || ofSPD) ? BIT(aod::evsel::kIsINT1) : 0; + selection |= (bc.has_ft0() ? TESTBIT(bc.ft0().triggerMask(), o2::ft0::Triggers::bitVertex) : 0) ? BIT(aod::evsel::kIsTriggerTVX) : 0; + + // copy remaining selection decisions from eventCuts + uint32_t eventCuts = bc.eventCuts(); + selection |= (eventCuts & 1 << aod::kTimeRangeCut) ? BIT(aod::evsel::kIsGoodTimeRange) : 0; + selection |= (eventCuts & 1 << aod::kIncompleteDAQ) ? BIT(aod::evsel::kNoIncompleteDAQ) : 0; + selection |= !(eventCuts & 1 << aod::kIsTPCLaserWarmUp) ? BIT(aod::evsel::kNoTPCLaserWarmUp) : 0; + selection |= !(eventCuts & 1 << aod::kIsTPCHVdip) ? BIT(aod::evsel::kNoTPCHVdip) : 0; + selection |= !(eventCuts & 1 << aod::kIsPileupFromSPD) ? BIT(aod::evsel::kNoPileupFromSPD) : 0; + selection |= !(eventCuts & 1 << aod::kIsV0PFPileup) ? BIT(aod::evsel::kNoV0PFPileup) : 0; + selection |= (eventCuts & 1 << aod::kConsistencySPDandTrackVertices) ? BIT(aod::evsel::kNoInconsistentVtx) : 0; + selection |= (eventCuts & 1 << aod::kPileupInMultBins) ? BIT(aod::evsel::kNoPileupInMultBins) : 0; + selection |= (eventCuts & 1 << aod::kPileUpMV) ? BIT(aod::evsel::kNoPileupMV) : 0; + selection |= (eventCuts & 1 << aod::kTPCPileUp) ? BIT(aod::evsel::kNoPileupTPC) : 0; + + 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; + int32_t foundZDC = bc.has_zdc() ? bc.zdc().globalIndex() : -1; + + // // Fill TVX (T0 vertex) counters FIXME - this is a bug, there's no hCounterTVX in this task + // if (TESTBIT(selection, aod::evsel::kIsTriggerTVX)) { + // histos.get(HIST("hCounterTVX"))->Fill(Form("%d", bc.runNumber()), 1); + // } + + uint32_t rct = 0; + + // initialize properties + o2::common::eventselection::bcselEntry entry; + entry.alias = alias; + entry.selection = selection; + entry.rct = rct; + entry.foundFT0Id = foundFT0; + entry.foundFV0Id = foundFV0; + entry.foundFDDId = foundFDD; + entry.foundZDCId = foundZDC; + bcselbuffer.push_back(entry); + + // Fill bc selection columns + bcsel(alias, selection, rct, foundFT0, foundFV0, foundFDD, foundZDC); + } // end bc loop + } // end processRun2 + + //__________________________________________________ + template + void processRun3(TCCDB const& ccdb, THistoRegistry& histos, TBCs const& bcs, TTimestamps const& timestamps, TBcSelBuffer& bcselbuffer, TBcSelCursor& bcsel) + { + if (bcselOpts.amIneeded.value == 0) { + bcselbuffer.clear(); + return; + } + bcselbuffer.clear(); + if (!configure(ccdb, bcs)) + return; // don't do anything in case configuration reported not ok + + int run = bcs.iteratorAt(0).runNumber(); + // map from GlobalBC to BcId needed to find triggerBc + std::map mapGlobalBCtoBcId; + for (const auto& bc : bcs) { + mapGlobalBCtoBcId[bc.globalBC()] = bc.globalIndex(); + } + + int triggerBcShift = bcselOpts.confTriggerBcShift; + if (bcselOpts.confTriggerBcShift == 999) { // o2-linter: disable=magic-number (special shift for early 2022 data) + triggerBcShift = (run <= 526766 || (run >= 526886 && run <= 527237) || (run >= 527259 && run <= 527518) || run == 527523 || run == 527734 || run >= 534091) ? 0 : 294; // o2-linter: disable=magic-number (magic list of runs) + } + + // bc loop + for (auto bc : bcs) { // o2-linter: disable=const-ref-in-for-loop (use bc as nonconst iterator) + uint64_t timestamp = timestamps[bc.globalIndex()]; + // 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(timestamp); + if (itrct != mapRCT->begin()) + itrct--; + rct = itrct->second; + LOGP(debug, "sor={} eor={} ts={} rct={}", sorTimestamp, eorTimestamp, timestamp, rct); + lastRCT = rct; + lastTF = thisTF; + } + + uint32_t alias{0}; + // workaround for pp2022 (trigger info is shifted by -294 bcs) + int32_t triggerBcId = mapGlobalBCtoBcId[bc.globalBC() + triggerBcShift]; + if (triggerBcId && aliases) { + auto triggerBc = bcs.iteratorAt(triggerBcId); + uint64_t triggerMask = triggerBc.triggerMask(); + for (const auto& al : aliases->GetAliasToTriggerMaskMap()) { + if (triggerMask & al.second) { + alias |= BIT(al.first); + } + } + } + alias |= BIT(kALL); + + // get timing info from ZDC, FV0, FT0 and FDD + float timeZNA = bc.has_zdc() ? bc.zdc().timeZNA() : -999.f; + float timeZNC = bc.has_zdc() ? bc.zdc().timeZNC() : -999.f; + float timeV0A = bc.has_fv0a() ? bc.fv0a().time() : -999.f; + float timeT0A = bc.has_ft0() ? bc.ft0().timeA() : -999.f; + float timeT0C = bc.has_ft0() ? bc.ft0().timeC() : -999.f; + float timeFDA = bc.has_fdd() ? bc.fdd().timeA() : -999.f; + float timeFDC = bc.has_fdd() ? bc.fdd().timeC() : -999.f; + float timeV0ABG = -999.f; + float timeT0ABG = -999.f; + float timeT0CBG = -999.f; + float timeFDABG = -999.f; + float timeFDCBG = -999.f; + + uint64_t globalBC = bc.globalBC(); + // move to previous bcs to check beam-gas in FT0, FV0 and FDD + int64_t backwardMoveCount = 0; + int64_t deltaBC = 6; // up to 6 bcs back + while (bc.globalBC() + deltaBC >= globalBC) { + if (bc == bcs.begin()) { + break; + } + --bc; + backwardMoveCount++; + int bcDistanceToBeamGasForFT0 = 1; + int bcDistanceToBeamGasForFDD = 5; + if (bc.globalBC() + bcDistanceToBeamGasForFT0 == globalBC) { + timeV0ABG = bc.has_fv0a() ? bc.fv0a().time() : -999.f; + timeT0ABG = bc.has_ft0() ? bc.ft0().timeA() : -999.f; + timeT0CBG = bc.has_ft0() ? bc.ft0().timeC() : -999.f; + } + if (bc.globalBC() + bcDistanceToBeamGasForFDD == globalBC) { + timeFDABG = bc.has_fdd() ? bc.fdd().timeA() : -999.f; + timeFDCBG = bc.has_fdd() ? bc.fdd().timeC() : -999.f; + } + } + // move back to initial position + bc.moveByIndex(backwardMoveCount); + + // fill time-based selection criteria + uint64_t selection{0}; + selection |= timeV0A > par->fV0ABBlower && timeV0A < par->fV0ABBupper ? BIT(aod::evsel::kIsBBV0A) : 0; + selection |= timeFDA > par->fFDABBlower && timeFDA < par->fFDABBupper ? BIT(aod::evsel::kIsBBFDA) : 0; + selection |= timeFDC > par->fFDCBBlower && timeFDC < par->fFDCBBupper ? BIT(aod::evsel::kIsBBFDC) : 0; + selection |= !(timeV0ABG > par->fV0ABGlower && timeV0ABG < par->fV0ABGupper) ? BIT(aod::evsel::kNoBGV0A) : 0; + selection |= !(timeFDABG > par->fFDABGlower && timeFDABG < par->fFDABGupper) ? BIT(aod::evsel::kNoBGFDA) : 0; + selection |= !(timeFDCBG > par->fFDCBGlower && timeFDCBG < par->fFDCBGupper) ? BIT(aod::evsel::kNoBGFDC) : 0; + selection |= !(timeT0ABG > par->fT0ABGlower && timeT0ABG < par->fT0ABGupper) ? BIT(aod::evsel::kNoBGT0A) : 0; + selection |= !(timeT0CBG > par->fT0CBGlower && timeT0CBG < par->fT0CBGupper) ? BIT(aod::evsel::kNoBGT0C) : 0; + selection |= (timeT0A > par->fT0ABBlower && timeT0A < par->fT0ABBupper) ? BIT(aod::evsel::kIsBBT0A) : 0; + selection |= (timeT0C > par->fT0CBBlower && timeT0C < par->fT0CBBupper) ? BIT(aod::evsel::kIsBBT0C) : 0; + selection |= (timeZNA > par->fZNABBlower && timeZNA < par->fZNABBupper) ? BIT(aod::evsel::kIsBBZNA) : 0; + selection |= (timeZNC > par->fZNCBBlower && timeZNC < par->fZNCBBupper) ? BIT(aod::evsel::kIsBBZNC) : 0; + selection |= (std::pow((timeZNA + timeZNC - par->fZNSumMean) / par->fZNSumSigma, 2) + std::pow((timeZNA - timeZNC - par->fZNDifMean) / par->fZNDifSigma, 2) < 1) ? BIT(aod::evsel::kIsBBZAC) : 0; + selection |= !(std::fabs(timeZNA) > par->fZNABGlower && std::fabs(timeZNA) < par->fZNABGupper) ? BIT(aod::evsel::kNoBGZNA) : 0; + selection |= !(std::fabs(timeZNC) > par->fZNCBGlower && std::fabs(timeZNC) < par->fZNCBGupper) ? BIT(aod::evsel::kNoBGZNC) : 0; + selection |= (bc.has_ft0() ? (bc.ft0().triggerMask() & BIT(o2::ft0::Triggers::bitVertex)) > 0 : 0) ? BIT(aod::evsel::kIsTriggerTVX) : 0; + + // 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 < rofLength - mITSROFrameEndBorderMargin ? BIT(aod::evsel::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(aod::evsel::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] <= bcselOpts.maxInactiveChipsPerLayer->at(3) && vNextInactiveChips[3] <= bcselOpts.maxInactiveChipsPerLayer->at(3); + isGoodITSLayer0123 = true; + for (int i = 0; i < 4; i++) { // o2-linter: disable=magic-number (counting first 4 ITS layers) + isGoodITSLayer0123 &= vPrevInactiveChips[i] <= bcselOpts.maxInactiveChipsPerLayer->at(i) && vNextInactiveChips[i] <= bcselOpts.maxInactiveChipsPerLayer->at(i); + } + isGoodITSLayersAll = true; + for (int i = 0; i < o2::itsmft::ChipMappingITS::NLayers; i++) { + isGoodITSLayersAll &= vPrevInactiveChips[i] <= bcselOpts.maxInactiveChipsPerLayer->at(i) && vNextInactiveChips[i] <= bcselOpts.maxInactiveChipsPerLayer->at(i); + } + } + + selection |= isGoodITSLayer3 ? BIT(aod::evsel::kIsGoodITSLayer3) : 0; + selection |= isGoodITSLayer0123 ? BIT(aod::evsel::kIsGoodITSLayer0123) : 0; + selection |= isGoodITSLayersAll ? BIT(aod::evsel::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; + int32_t foundZDC = bc.has_zdc() ? bc.zdc().globalIndex() : -1; + LOGP(debug, "foundFT0={}", foundFT0); + + const char* srun = Form("%d", run); + if (timestamp < sorTimestamp || timestamp > eorTimestamp) { + histos.template get(HIST("bcselection/hCounterInvalidBCTimestamp"))->Fill(srun, 1); + if (bcselOpts.confCheckRunDurationLimits.value) { + LOGF(warn, "Invalid BC timestamp: %d, run: %d, sor: %d, eor: %d", timestamp, run, sorTimestamp, eorTimestamp); + alias = 0u; + selection = 0u; + } + } + + // initialize properties + o2::common::eventselection::bcselEntry entry; + entry.alias = alias; + entry.selection = selection; + entry.rct = rct; + entry.foundFT0Id = foundFT0; + entry.foundFV0Id = foundFV0; + entry.foundFDDId = foundFDD; + entry.foundZDCId = foundZDC; + bcselbuffer.push_back(entry); + + // Fill bc selection columns + bcsel(alias, selection, rct, foundFT0, foundFV0, foundFDD, foundZDC); + } // end bc loop + } // end processRun3 +}; // end BcSelectionModule + +class EventSelectionModule +{ + public: + EventSelectionModule() + { + // constructor + } + + int run3min = 500000; + int lastRun = -1; // last run number (needed to access ccdb only if run!=lastRun) + std::bitset bcPatternB; // bc pattern of colliding bunches + std::vector bcsPattern; // pattern of colliding BCs + + 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 + std::string strLPMProductionTag = ""; // MC production tag to be retrieved from AO2D metadata + + // temporary (?) parameterizations for light ion runs + int runLightIons = -1; + int runListLightIons[11] = {564356, 564359, 564373, 564374, 564387, 564400, 564414, 564430, 564445, 564468, 564472}; + std::vector diffVzParMean; // parameterization for mean of diff vZ by FT0 vs by tracks + std::vector diffVzParSigma; // parameterization for stddev of diff vZ by FT0 vs by tracks + + int32_t findClosest(const int64_t globalBC, const 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; + } + + // 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; + } + + float calcWeightForOccupancy(float dt) + { + float wOccup = 0; + if (dt >= -40 && dt < -5) // collisions in the past // o2-linter: disable=magic-number + wOccup = 1. / 1225 * (dt + 40) * (dt + 40); // o2-linter: disable=magic-number + else if (dt >= -5 && dt < 15) // collisions near a given one // o2-linter: disable=magic-number + wOccup = 1; + else if (dt >= 15 && dt < 40) // collisions from the future // o2-linter: disable=magic-number + wOccup = -0.4 / 25 * dt + 1.24; // o2-linter: disable=magic-number + else if (dt >= 40 && dt < 100) // collisions from the distant future // o2-linter: disable=magic-number + wOccup = -0.4 / 60 * dt + 0.6 + 0.8 / 3; // o2-linter: disable=magic-number + return wOccup; + } + + // declaration of structs here + // (N.B.: will be invisible to the outside, create your own copies) + o2::common::eventselection::evselConfigurables evselOpts; + + template + void init(TContext& context, TEvSelOpts const& external_evselopts, THistoRegistry& histos, TMetadataInfo const& metadataInfo) + { + // read in configurations from the task where it's used + evselOpts = external_evselopts; + + if (evselOpts.amIneeded.value < 0) { + enableFlagIfTableRequired(context, "EvSels", evselOpts.amIneeded.value); + if (evselOpts.amIneeded.value == 0) { + LOGF(info, "Event Selection / Autodetecting for aod::EvSels: not required, won't generate."); + return; + } else { + LOGF(info, "Event Selection / Autodetecting for aod::EvSels: subscription present, will generate."); + } + } + + if (metadataInfo.isFullyDefined()) { // Check if the metadata is initialized (only if not forced from the workflow configuration) + if (evselOpts.isMC == -1) { + LOGF(info, "Autosetting the MC mode based on metadata (isMC? %i)", metadataInfo.isMC()); + if (metadataInfo.isMC()) { + evselOpts.isMC.value = 1; + } else { + evselOpts.isMC.value = 0; + } + } + } + strLPMProductionTag = metadataInfo.get("LPMProductionTag"); // to extract info from ccdb by the tag + + histos.add("eventselection/hColCounterAll", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("eventselection/hColCounterTVX", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("eventselection/hColCounterAcc", "", framework::kTH1D, {{1, 0., 1.}}); + } + + //__________________________________________________ + template + bool configure(TCCDB& ccdb, TTimestamps const& timestamps, TBCs const& bcs) + { + if (bcs.size() == 0) { + return false; + } + int run = bcs.iteratorAt(0).runNumber(); + // extract bc pattern from CCDB for data or anchored MC only + if (run != lastRun && run >= run3min) { + lastRun = run; + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), run, strLPMProductionTag); + // first bc of the first orbit + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; + // duration of TF in bcs + nBCsPerTF = evselOpts.confNumberOfOrbitsPerTF < 0 ? runInfo.orbitsPerTF * nBCsPerOrbit : evselOpts.confNumberOfOrbitsPerTF * nBCsPerOrbit; + // colliding bc pattern + int64_t ts = timestamps[0]; + + // getForTimeStamp replaced with getSpecific to set metadata to zero + // avoids crash related to specific run number + auto grplhcif = ccdb->template getSpecific("GLO/Config/GRPLHCIF", ts); + bcPatternB = grplhcif->getBunchFilling().getBCPattern(); + bcsPattern = grplhcif->getBunchFilling().getFilledBCs(); + if (runLightIons >= 0) { + for (uint32_t i = 0; i < bcsPattern.size(); i++) + LOGP(debug, "bcsPattern: i={} bc={}", i, bcsPattern.at(i)); + } + + // extract ITS ROF parameters + auto alppar = ccdb->template getForTimeStamp>("ITS/Config/AlpideParam", ts); + rofOffset = alppar->roFrameBiasInBC; + rofLength = alppar->roFrameLengthInBC; + LOGP(debug, "ITS ROF Offset={} ITS ROF Length={}", rofOffset, rofLength); + + // special treatment of light ion runs + if (lastRun >= 564356 && lastRun <= 564472) { + for (uint32_t i = 0; i < sizeof(runListLightIons) / sizeof(*runListLightIons); i++) { + if (runListLightIons[i] == lastRun) { + runLightIons = lastRun; + // extract parameterization for diff of vZ by FT0 vs by tracks + auto parMeans = ccdb->template getForTimeStamp>("Users/a/altsybee/diffVzCollVsFTOmeanPar", ts); + auto parSigmas = ccdb->template getForTimeStamp>("Users/a/altsybee/diffVzCollVsFTOsigmaPar", ts); + diffVzParMean = *parMeans; + diffVzParSigma = *parSigmas; + LOGP(info, ">>> special treatment for diffVz for light ion run {}", runLightIons); + for (int i = 0; i < 5; i++) + LOGP(info, " mean par {} = {}", i, diffVzParMean[i]); + for (int i = 0; i < 5; i++) + LOGP(info, " sigma par {} = {}", i, diffVzParSigma[i]); + break; + } + } + } + + } // if run != lastRun + return true; + } + + //__________________________________________________ + template + void processRun2(TCCDB const& ccdb, THistoRegistry& histos, TCollisions const& collisions, TTracklets const& tracklets, TSlicecache& cache, TTimestamps const& timestamps, TBcSelBuffer const& bcselbuffer, TEvselCursor& evsel) + { + if (evselOpts.amIneeded.value == 0) { + return; // dummy process + } + for (const auto& col : collisions) { + auto bc = col.template bc_as>(); + uint64_t timestamp = timestamps[bc.globalIndex()]; + EventSelectionParams* par = ccdb->template getForTimeStamp("EventSelection/EventSelectionParams", timestamp); + bool* applySelection = par->getSelection(evselOpts.muonSelection); + if (evselOpts.isMC == 1) { + applySelection[aod::evsel::kIsBBZAC] = 0; + applySelection[aod::evsel::kNoV0MOnVsOfPileup] = 0; + applySelection[aod::evsel::kNoSPDOnVsOfPileup] = 0; + applySelection[aod::evsel::kNoV0Casymmetry] = 0; + applySelection[aod::evsel::kNoV0PFPileup] = 0; + } + + int32_t foundBC = bc.globalIndex(); + int32_t foundFT0 = bcselbuffer[foundBC].foundFT0Id; + int32_t foundFV0 = bcselbuffer[foundBC].foundFV0Id; + int32_t foundFDD = bcselbuffer[foundBC].foundFDDId; + int32_t foundZDC = bcselbuffer[foundBC].foundZDCId; + + // copy alias decisions from bcsel table + uint32_t alias = bcselbuffer[foundBC].alias; + + // copy selection decisions from bcsel table + uint64_t selection = bcselbuffer[foundBC].selection; + + // copy rct flags from bcsel table + uint32_t rct = bcselbuffer[foundBC].rct; + + // calculate V0C012 multiplicity + float multRingV0C[4] = {0.}; + if (bc.has_fv0c()) { + for (unsigned int i = 0; i < bc.fv0c().amplitude().size(); ++i) { + int ring = bc.fv0c().channel()[i] / 8; + multRingV0C[ring] += bc.fv0c().amplitude()[i]; + } + } + float multV0C012 = multRingV0C[0] + multRingV0C[1] + multRingV0C[2]; + + // applying selections depending on the number of tracklets + auto trackletsGrouped = tracklets.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); + int nTkl = trackletsGrouped.size(); + int spdClusters = bc.spdClustersL0() + bc.spdClustersL1(); + + selection |= (spdClusters < par->fSPDClsVsTklA + nTkl * par->fSPDClsVsTklB) ? BIT(aod::evsel::kNoSPDClsVsTklBG) : 0; + selection |= !(nTkl < 6 && multV0C012 > par->fV0C012vsTklA + nTkl * par->fV0C012vsTklB) ? BIT(aod::evsel::kNoV0C012vsTklBG) : 0; // o2-linter: disable=magic-number (nTkl dependent parameterization) + + // apply int7-like selections + bool sel7 = 1; + for (int i = 0; i < aod::evsel::kNsel; i++) { + sel7 = sel7 && (applySelection[i] ? TESTBIT(selection, i) : 1); + } + + // TODO introduce array of sel[0]... sel[8] or similar? + bool sel8 = bitcheck64(selection, aod::evsel::kIsBBT0A) && bitcheck64(selection, aod::evsel::kIsBBT0C); // TODO apply other cuts for sel8 + bool sel1 = bitcheck64(selection, aod::evsel::kIsINT1); + sel1 = sel1 && bitcheck64(selection, aod::evsel::kNoBGV0A); + sel1 = sel1 && bitcheck64(selection, aod::evsel::kNoBGV0C); + sel1 = sel1 && bitcheck64(selection, aod::evsel::kNoTPCLaserWarmUp); + sel1 = sel1 && bitcheck64(selection, aod::evsel::kNoTPCHVdip); + + // INT1 (SPDFO>0 | V0A | V0C) minimum bias trigger logic used in pp2010 and pp2011 + bool isINT1period = bc.runNumber() <= 136377 || (bc.runNumber() >= 144871 && bc.runNumber() <= 159582); // o2-linter: disable=magic-number (magic run numbers) + + // fill counters + if (evselOpts.isMC == 1 || (!isINT1period && bitcheck(alias, kINT7)) || (isINT1period && bitcheck(alias, kINT1))) { + histos.template get(HIST("eventselection/hColCounterAll"))->Fill(Form("%d", bc.runNumber()), 1); + if ((!isINT1period && sel7) || (isINT1period && sel1)) { + histos.template get(HIST("eventselection/hColCounterAcc"))->Fill(Form("%d", bc.runNumber()), 1); + } + } + + evsel(alias, selection, rct, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, 0, 0); + } + } // end processRun2 + + //__________________________________________________ + template + void processRun3(TCCDB const& ccdb, THistoRegistry& histos, TBCs const& bcs, TCollisions const& cols, TPVTracks const& pvTracks, TFT0s const& ft0s, TSlicecache& cache, TTimestamps const& timestamps, TBcSelBuffer const& bcselbuffer, TEvselCursor& evsel) + { + if (evselOpts.amIneeded.value == 0) { + return; // dummy process + } + if (!configure(ccdb, timestamps, bcs)) + return; // don't do anything in case configuration reported not ok + + int run = bcs.iteratorAt(0).runNumber(); + // create maps from globalBC to bc index for TVX-fired bcs + // to be used for closest TVX searches + std::map mapGlobalBcWithTVX; + std::map mapGlobalBcWithOrInFT0; + std::map mapGlobalBcVtxZ; + for (const auto& bc : bcs) { + int64_t globalBC = bc.globalBC(); + // skip non-colliding bcs for data and anchored runs + if (run >= run3min && bcPatternB[globalBC % nBCsPerOrbit] == 0) { + continue; + } + + if (bc.has_ft0()) { + mapGlobalBcWithOrInFT0[globalBC] = bc.globalIndex(); + } + + auto selection = bcselbuffer[bc.globalIndex()].selection; + if (bitcheck64(selection, aod::evsel::kIsTriggerTVX)) { + mapGlobalBcWithTVX[globalBC] = bc.globalIndex(); + mapGlobalBcVtxZ[globalBC] = bc.has_ft0() ? bc.ft0().posZ() : 0; + } + } + + // protection against empty FT0 maps + if (mapGlobalBcWithTVX.size() == 0) { + LOGP(error, "FT0 table is empty or corrupted. Filling evsel table with dummy values"); + for (const auto& col : cols) { + auto bc = col.template bc_as>(); + int32_t foundBC = bc.globalIndex(); + int32_t foundFT0 = bcselbuffer[bc.globalIndex()].foundFT0Id; + int32_t foundFV0 = bcselbuffer[bc.globalIndex()].foundFV0Id; + int32_t foundFDD = bcselbuffer[bc.globalIndex()].foundFDDId; + int32_t foundZDC = bcselbuffer[bc.globalIndex()].foundZDCId; + uint32_t rct = 0; + evsel(bcselbuffer[bc.globalIndex()].alias, bcselbuffer[bc.globalIndex()].selection, rct, kFALSE, kFALSE, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, -1, -1); + } + return; + } + 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 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 vCollisionsPileupPerColl(cols.size(), 0); // counter of pileup in the same bc as a given collision + std::vector vBCinPatternPerColl(cols.size(), 0); // found nominal BCs for collisions + 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(); + vCollVz[colIndex] = col.posZ(); + + vTrackTimesTOF.clear(); + vTrackTimesTRDnoTOF.clear(); + int nPvTracksTPCnoTOFnoTRD = 0; + int nPvTracksHighPtTPCnoTOFnoTRD = 0; + const auto& colPvTracks = pvTracks.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); + float sumTime = 0, sumW = 0, sumHighPtTime = 0, sumHighPtW = 0; + for (const auto& track : colPvTracks) { + float trackTime = track.trackTime(); + if (track.itsNCls() >= 5) // o2-linter: disable=magic-number (indeed counting layers 5 6 7) + vTracksITS567perColl[colIndex]++; + if (track.hasTRD()) + vIsVertexTRDmatched[colIndex] = 1; + if (track.hasTPC()) + vIsVertexITSTPC[colIndex] = 1; + if (track.hasTOF()) { + vTrackTimesTOF.push_back(trackTime); + vIsVertexTOFmatched[colIndex] = 1; + } else if (track.hasTRD()) { + 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++; + } + } + } + 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; + + // collision-bc association, other bc-related routine + auto bc = col.template bc_as>(); + int64_t globalBC = bc.globalBC(); + int64_t foundGlobalBC = 0; + int32_t foundBCindex = -1; + + // alternative collision-BC matching (currently: test mode, the aim is to improve pileup rejection) + if (runLightIons >= 0) { + foundGlobalBC = globalBC; + // find closest nominal bc in pattern + for (uint32_t i = 0; i < bcsPattern.size(); i++) { + int32_t localBC = globalBC % nBCsPerOrbit; + int32_t bcFromPattern = bcsPattern.at(i); + int64_t bcDiff = bcFromPattern - localBC; + if (std::abs(bcDiff) <= 20) { + foundGlobalBC = (globalBC / nBCsPerOrbit) * nBCsPerOrbit + bcFromPattern; + break; // the bc in pattern is found + } + } + + // matched with TOF --> precise time, match to TVX, but keep the nominal foundGlobalBC from pattern + if (vIsVertexTOFmatched[colIndex]) { + std::map::iterator it = mapGlobalBcWithTVX.find(foundGlobalBC); + if (it != mapGlobalBcWithTVX.end()) { + foundBCindex = it->second; // TVX at foundGlobalBC is found + } else { // check if TVX is in nearby bcs + it = mapGlobalBcWithTVX.find(foundGlobalBC + 1); // next bc + if (it != mapGlobalBcWithTVX.end()) { + // foundGlobalBC += 1; + foundBCindex = it->second; + } else { + it = mapGlobalBcWithTVX.find(foundGlobalBC - 1); // previous bc + if (it != mapGlobalBcWithTVX.end()) { + // foundGlobalBC -= 1; + foundBCindex = it->second; + } else { + foundBCindex = bc.globalIndex(); // keep original BC index + } + } + } + } // end of if TOF-matched vertex + else { // for non-TOF and low-mult vertices, consider nearby nominal bcs + int64_t meanBC = globalBC + TMath::Nint(sumHighPtTime / sumHighPtW / bcNS); + int64_t bestGlobalBC = findBestGlobalBC(meanBC, evselOpts.confSigmaBCforHighPtTracks, vNcontributors[colIndex], col.posZ(), mapGlobalBcVtxZ); + if (bestGlobalBC > 0) { + foundGlobalBC = bestGlobalBC; + // find closest nominal bc in pattern + for (uint32_t j = 0; j < bcsPattern.size(); j++) { + int32_t bcFromPatternBest = bcsPattern.at(j); + int64_t bcDiff = bcFromPatternBest - (bestGlobalBC % nBCsPerOrbit); + if (std::abs(bcDiff) <= 20) { + foundGlobalBC = (bestGlobalBC / nBCsPerOrbit) * nBCsPerOrbit + bcFromPatternBest; + break; // the bc in pattern is found + } + } + foundBCindex = mapGlobalBcWithTVX[bestGlobalBC]; + } else { // failed to find a proper TVX with small vZ difference + foundBCindex = bc.globalIndex(); // keep original BC index + } + } // end of non-TOF matched vertices + // sanitity check: if BC was not found + if (foundBCindex == -1) { + foundBCindex = bc.globalIndex(); + } + vBCinPatternPerColl[colIndex] = foundGlobalBC; + // end of alternative coll-BC matching (test) + } else if (nPvTracksTOF > 0) { // "standard matching": + // 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, evselOpts.confSigmaBCforHighPtTracks, vNcontributors[colIndex], col.posZ(), mapGlobalBcVtxZ); + if (bestGlobalBC > 0) { + foundGlobalBC = bestGlobalBC; + foundBCindex = mapGlobalBcWithTVX[bestGlobalBC]; + } + } + + // 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); + } + // alternative matching: looking for collisions with the same nominal BC + if (runLightIons >= 0) { + for (uint32_t iCol = 0; iCol < vBCinPatternPerColl.size(); iCol++) { + int64_t foundNominalBC = vBCinPatternPerColl[iCol]; + for (uint32_t jCol = 0; jCol < vBCinPatternPerColl.size(); jCol++) { + int64_t foundNominalBC2 = vBCinPatternPerColl[jCol]; + if (foundNominalBC2 == foundNominalBC) { + vCollisionsPileupPerColl[iCol]++; + } + } + } + } else { // continue standard matching: second loop to match remaining low-pt TPCnoTOFnoTRD collisions + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + if (vIsVertexTPC[colIndex] > 0 && vIsVertexTOF[colIndex] == 0 && vIsVertexHighPtTPC[colIndex] == 0) { + float weightedTime = vWeightedTimesTPCnoTOFnoTRD[colIndex]; + float weightedSigma = vWeightedSigmaTPCnoTOFnoTRD[colIndex]; + auto bc = col.template 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]]++; + } + } + + // pre-loop for occupancy calculation + 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) + std::vector vIsCollAtROFborder(cols.size(), 0); // collision is close to ITS ROF border + std::vector vIsCollRejectedByTFborderCut(cols.size(), 0); // helper vector with + std::vector vCanHaveAssocCollsWithinLastDriftTime(cols.size(), 0); // to see if for some collisions in the occupancy calc (that are close to TF border) we will switch to FT0C based occupancy estimation + + const float timeWinOccupancyCalcMinNS = evselOpts.confTimeIntervalForOccupancyCalculationMin * 1e3; // ns + const float timeWinOccupancyCalcMaxNS = evselOpts.confTimeIntervalForOccupancyCalculationMax * 1e3; // ns + + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + int bcInTF = (foundGlobalBC - bcSOR) % nBCsPerTF; + vIsFullInfoForOccupancy[colIndex] = ((bcInTF - 10) * bcNS > -timeWinOccupancyCalcMinNS) && ((nBCsPerTF - 10 - bcInTF) * bcNS > timeWinOccupancyCalcMaxNS) ? true : false; // 10 BCs is margin + + int32_t foundBC = vFoundBCindex[colIndex]; + auto bcselEntry = bcselbuffer[foundBC]; + // check if we are close to ROF or TF borders => N tracks are not reliable, but FT0 can be used for occupancy estimation + if (!bitcheck64(bcselEntry.selection, aod::evsel::kNoITSROFrameBorder)) { + vIsCollAtROFborder[colIndex] = true; + } + + if (!bitcheck64(bcselEntry.selection, aod::evsel::kNoTimeFrameBorder)) { + vIsCollRejectedByTFborderCut[colIndex] = true; + } + if (nBCsPerTF - bcInTF < 4000 * 2) { + vCanHaveAssocCollsWithinLastDriftTime[colIndex] = true; + } + } + + // 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 bcselEntr = bcselbuffer[vFoundBCindex[colIndex]]; + if (bcselEntr.foundFT0Id > -1) { + // required: explicit ft0s table + auto foundFT0 = ft0s.rawIteratorAt(bcselEntr.foundFT0Id); + vAmpFT0CperColl[colIndex] = 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; + // 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] > evselOpts.confFT0CamplCutVetoOnCollInROF) + nCollsInRofWithFT0CAboveVetoStandard++; + if (std::fabs(vCollVz[thisColIndex] - vZ) < evselOpts.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 < evselOpts.confFT0CamplCutVetoOnCollInROF); + + // ### occupancy in time windows + 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 (narrow range) with per-collision multiplicity above threshold + int nITS567tracksForVetoStrict = 0; // to veto events with nearby collisions + int nCollsWithFT0CAboveVetoStandard = 0; // to veto events with nearby collisions that have per-collision multiplicity above threshold + int colIndexFirstRejectedByTFborderCut = -1; + for (uint32_t iCol = 0; iCol < vAssocToThisCol.size(); iCol++) { + int thisColIndex = vAssocToThisCol[iCol]; + float dt = vCollsTimeDeltaWrtGivenColl[iCol] / 1e3; // ns -> us + + // check if we are close to ITS ROF borders => N ITS tracks is not reliable, and FT0C ampl can be used for occupancy estimation + // denominator for vAmpFT0CperColl is the approximate conversion factor b/n FT0C ampl and number of PV tracks after cuts + int nItsTracksAssocColl = !vIsCollAtROFborder[thisColIndex] ? vTracksITS567perColl[thisColIndex] : vAmpFT0CperColl[thisColIndex] / 10.; + // counting tracks from other collisions in fixed time windows + if (std::fabs(dt) < evselOpts.confTimeRangeVetoOnCollNarrow) + nITS567tracksForVetoNarrow += nItsTracksAssocColl; + if (std::fabs(dt) < evselOpts.confTimeRangeVetoOnCollStrict) + nITS567tracksForVetoStrict += nItsTracksAssocColl; + + // veto on high-mult collisions nearby, where artificial structures in the dt-occupancy plots are observed + if (dt > -4.0 && dt < 2.0 && vAmpFT0CperColl[thisColIndex] > evselOpts.confFT0CamplCutVetoOnCollInTimeRange) { // dt in us // o2-linter: disable=magic-number + nCollsWithFT0CAboveVetoStandard++; + } + + // check if we are close to TF borders => N ITS tracks is not reliable, and FT0C ampl will be used for occupancy estimation (a loop below) + if (vIsCollRejectedByTFborderCut[thisColIndex]) { + if (colIndexFirstRejectedByTFborderCut == -1) + colIndexFirstRejectedByTFborderCut = thisColIndex; + continue; + } + + // weighted occupancy calc: + if (vIsFullInfoForOccupancy[colIndex]) { + float wOccup = 1.; + if (evselOpts.confUseWeightsForOccupancyVariable) { + // weighted occupancy + wOccup = calcWeightForOccupancy(dt); + } + nITS567tracksInFullTimeWindow += wOccup * nItsTracksAssocColl; + sumAmpFT0CInFullTimeWindow += wOccup * vAmpFT0CperColl[thisColIndex]; + } + } + + // if some associated collisions are close to TF border - take FT0C amplitude instead of nTracks, using BC table + if (vIsFullInfoForOccupancy[colIndex] && vCanHaveAssocCollsWithinLastDriftTime[colIndex] && colIndexFirstRejectedByTFborderCut >= 0) { + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + int64_t tfId = (foundGlobalBC - bcSOR) / nBCsPerTF; + std::map::iterator it = mapGlobalBcWithTVX.find(vFoundGlobalBC[colIndexFirstRejectedByTFborderCut]); + while (it != mapGlobalBcWithTVX.end()) { + int64_t thisFoundGlobalBC = it->first; + int32_t thisFoundBCindex = it->second; + auto bc = bcs.iteratorAt(thisFoundBCindex); + int64_t thisTFid = (bc.globalBC() - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + + float dt = (thisFoundGlobalBC - foundGlobalBC) * bcNS; // ns + if (dt > timeWinOccupancyCalcMaxNS) + break; + + float multT0C = -1; + if (bc.has_ft0()) { + multT0C = bc.ft0().sumAmpC(); + float wOccup = 1.; + if (evselOpts.confUseWeightsForOccupancyVariable) { + wOccup = calcWeightForOccupancy(dt / 1e3); // ns -> us + } + if (multT0C > 50.) // multiplicity in TVX is non-negligible, take it into occupancy calc + { + nITS567tracksInFullTimeWindow += wOccup * multT0C / 10.; + sumAmpFT0CInFullTimeWindow += wOccup * multT0C; + } + } + it++; + } + } + + // protection against TF borders + if (!vIsFullInfoForOccupancy[colIndex]) { // occupancy in undefined (too close to TF borders) + nITS567tracksInFullTimeWindow = -1; + sumAmpFT0CInFullTimeWindow = -1; + } + + 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 && nITS567tracksForVetoNarrow == 0); + } + + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + int32_t foundBC = vFoundBCindex[colIndex]; + auto bc = bcs.iteratorAt(foundBC); + auto bcselEntry = bcselbuffer[foundBC]; + int32_t foundFT0 = bcselEntry.foundFT0Id; + int32_t foundFV0 = bcselEntry.foundFV0Id; + int32_t foundFDD = bcselEntry.foundFDDId; + int32_t foundZDC = bcselEntry.foundZDCId; + + // compare zVtx from FT0 and from PV + bool isGoodZvtxFT0vsPV = 0; + if (bcselEntry.foundFT0Id > -1) { + auto foundFT0Inner = ft0s.rawIteratorAt(bcselEntry.foundFT0Id); + float diffVz = foundFT0Inner.posZ() - col.posZ(); + if (runLightIons == -1) { + isGoodZvtxFT0vsPV = std::fabs(diffVz) < evselOpts.maxDiffZvtxFT0vsPV; + } else { // special treatment of light ion runs + float multT0A = bc.ft0().sumAmpA(); + float multT0C = bc.ft0().sumAmpC(); + float T0M = multT0A + multT0C; + // calc mean at this T0 ampl. + float x = (T0M < 50 ? 50 : T0M); + double diffMean = diffVzParMean[0] + diffVzParMean[1] * pow(x, diffVzParMean[2]) + diffVzParMean[3] * pow(x, diffVzParMean[4]); + // calc sigma at this T0 ampl. + x = (T0M < 20 ? 20 : (T0M > 1.2e4 ? 1.2e4 : T0M)); + double diffSigma = diffVzParSigma[0] + diffVzParSigma[1] * pow(x, diffVzParSigma[2]) + diffVzParSigma[3] * pow(x, diffVzParSigma[4]); + float nSigma = evselOpts.confLightIonsNsigmaOnVzDiff; + float margin = evselOpts.confLightIonsMarginVzDiff; + isGoodZvtxFT0vsPV = (diffVz > diffMean - nSigma * diffSigma - margin && diffVz < diffMean + nSigma * diffSigma + margin); + } + } + + // copy alias decisions from bcsel table + uint32_t alias = bcselEntry.alias; + + // copy selection decisions from bcsel table + uint64_t selection = bcselbuffer[bc.globalIndex()].selection; + if (runLightIons >= 0) // for light ions, apply different condition to assign pileup flags + selection |= vCollisionsPileupPerColl[colIndex] <= 1 ? BIT(aod::evsel::kNoSameBunchPileup) : 0; + else + selection |= vCollisionsPerBc[foundBC] <= 1 ? BIT(aod::evsel::kNoSameBunchPileup) : 0; + selection |= vIsVertexITSTPC[colIndex] ? BIT(aod::evsel::kIsVertexITSTPC) : 0; + selection |= vIsVertexTOFmatched[colIndex] ? BIT(aod::evsel::kIsVertexTOFmatched) : 0; + selection |= vIsVertexTRDmatched[colIndex] ? BIT(aod::evsel::kIsVertexTRDmatched) : 0; + selection |= isGoodZvtxFT0vsPV ? BIT(aod::evsel::kIsGoodZvtxFT0vsPV) : 0; + + // selection bits based on occupancy time pattern + selection |= vNoCollInTimeRangeNarrow[colIndex] ? BIT(aod::evsel::kNoCollInTimeRangeNarrow) : 0; + selection |= vNoCollInTimeRangeStrict[colIndex] ? BIT(aod::evsel::kNoCollInTimeRangeStrict) : 0; + selection |= vNoHighMultCollInTimeRange[colIndex] ? BIT(aod::evsel::kNoCollInTimeRangeStandard) : 0; + + // selection bits based on ITS in-ROF occupancy + selection |= vNoCollInSameRofStrict[colIndex] ? BIT(aod::evsel::kNoCollInRofStrict) : 0; + selection |= (vNoCollInSameRofStandard[colIndex] && vNoCollInSameRofWithCloseVz[colIndex]) ? BIT(aod::evsel::kNoCollInRofStandard) : 0; + selection |= vNoHighMultCollInPrevRof[colIndex] ? BIT(aod::evsel::kNoHighMultCollInPrevRof) : 0; + + // copy rct flags from bcsel table + uint32_t rct = bcselEntry.rct; + + // apply int7-like selections + bool sel7 = 0; + + // TODO apply other cuts for sel8 + // TODO introduce sel1 etc? + // TODO introduce array of sel[0]... sel[8] or similar? + bool sel8 = bitcheck64(bcselEntry.selection, aod::evsel::kIsTriggerTVX) && bitcheck64(bcselEntry.selection, aod::evsel::kNoTimeFrameBorder) && bitcheck64(bcselEntry.selection, aod::evsel::kNoITSROFrameBorder); + + // fill counters + histos.template get(HIST("eventselection/hColCounterAll"))->Fill(Form("%d", bc.runNumber()), 1); + if (bitcheck64(bcselEntry.selection, aod::evsel::kIsTriggerTVX)) { + histos.template get(HIST("eventselection/hColCounterTVX"))->Fill(Form("%d", bc.runNumber()), 1); + } + if (sel8) { + histos.template get(HIST("eventselection/hColCounterAcc"))->Fill(Form("%d", bc.runNumber()), 1); + } + + evsel(alias, selection, rct, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, + vNumTracksITS567inFullTimeWin[colIndex], vSumAmpFT0CinFullTimeWin[colIndex]); + } + } // end processRun3 +}; // end EventSelectionModule + +class LumiModule +{ + public: + LumiModule() + { + // constructor + } + + int lastRun = -1; // last run number (needed to access ccdb only if run!=lastRun) + float csTVX = -1; // dummy -1 for the visible TVX cross section (in ub) used in lumi accounting + float csTCE = -1; // dummy -1 for the visible TCE cross section (in ub) used in lumi accounting + float csZEM = -1; // dummy -1 for the visible ZEM cross section (in ub) used in lumi accounting + float csZNC = -1; // dummy -1 for the visible ZNC cross section (in ub) used in lumi accounting + + std::vector mOrbits; + std::vector mPileupCorrectionTVX; + std::vector mPileupCorrectionTCE; + std::vector mPileupCorrectionZEM; + std::vector mPileupCorrectionZNC; + + int64_t minOrbitInRange = std::numeric_limits::max(); + int64_t maxOrbitInRange = 0; + uint32_t currentOrbitIndex = 0; + std::bitset bcPatternB; // bc pattern of colliding bunches + std::vector mRCTFlagsCheckers; + + // declaration of structs here + // (N.B.: will be invisible to the outside, create your own copies) + o2::common::eventselection::lumiConfigurables lumiOpts; + + template + void init(TContext& context, TLumiOpts const& external_lumiopts, THistoRegistry& histos) + { + lumiOpts = external_lumiopts; + + if (lumiOpts.amIneeded.value < 0) { + int bcSelNeeded = -1, evSelNeeded = -1; + lumiOpts.amIneeded.value = 0; + enableFlagIfTableRequired(context, "BcSels", bcSelNeeded); + enableFlagIfTableRequired(context, "EvSels", evSelNeeded); + if (bcSelNeeded == 1) { + lumiOpts.amIneeded.value = 1; + LOGF(info, "Luminosity / Autodetection for aod::BcSels: subscription present, will generate."); + } + if (evSelNeeded == 1 && bcSelNeeded == 0) { + lumiOpts.amIneeded.value = 1; + LOGF(info, "Luminosity / Autodetection for aod::BcSels: not there, but EvSel needed. Will generate."); + } + if (bcSelNeeded == 0 && evSelNeeded == 0) { + LOGF(info, "Luminosity / Autodetection for aod::BcSels: not required. Skipping generation."); + return; + } + } + + histos.add("luminosity/hCounterTVX", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterTCE", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterZEM", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterZNC", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterTVXZDC", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterTVXafterBCcuts", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterTCEafterBCcuts", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterZEMafterBCcuts", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterZNCafterBCcuts", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hCounterTVXZDCafterBCcuts", "", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hLumiTVX", ";;Luminosity, 1/#mub", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hLumiTCE", ";;Luminosity, 1/#mub", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hLumiZEM", ";;Luminosity, 1/#mub", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hLumiZNC", ";;Luminosity, 1/#mub", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hLumiTVXafterBCcuts", ";;Luminosity, 1/#mub", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hLumiTCEafterBCcuts", ";;Luminosity, 1/#mub", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hLumiZEMafterBCcuts", ";;Luminosity, 1/#mub", framework::kTH1D, {{1, 0., 1.}}); + histos.add("luminosity/hLumiZNCafterBCcuts", ";;Luminosity, 1/#mub", framework::kTH1D, {{1, 0., 1.}}); + + const int nLists = 6; + TString rctListNames[] = {"CBT", "CBT_hadronPID", "CBT_electronPID", "CBT_calo", "CBT_muon", "CBT_muon_glo"}; + histos.add("luminosity/hLumiTVXafterBCcutsRCT", ";;Luminosity, 1/#mub", framework::kTH2D, {{1, 0., 1.}, {4 * nLists, -0.5, 4. * nLists - 0.5}}); + histos.add("luminosity/hLumiTCEafterBCcutsRCT", ";;Luminosity, 1/#mub", framework::kTH2D, {{1, 0., 1.}, {4 * nLists, -0.5, 4. * nLists - 0.5}}); + histos.add("luminosity/hLumiZEMafterBCcutsRCT", ";;Luminosity, 1/#mub", framework::kTH2D, {{1, 0., 1.}, {4 * nLists, -0.5, 4. * nLists - 0.5}}); + histos.add("luminosity/hLumiZNCafterBCcutsRCT", ";;Luminosity, 1/#mub", framework::kTH2D, {{1, 0., 1.}, {4 * nLists, -0.5, 4. * nLists - 0.5}}); + + for (int i = 0; i < nLists; i++) { + const auto& rctListName = rctListNames[i]; + mRCTFlagsCheckers.emplace_back(rctListName.Data(), false, false); // disable zdc check, disable lim. acc. check + mRCTFlagsCheckers.emplace_back(rctListName.Data(), false, true); // disable zdc check, enable lim. acc. check + mRCTFlagsCheckers.emplace_back(rctListName.Data(), true, false); // enable zdc check, disable lim. acc. check + mRCTFlagsCheckers.emplace_back(rctListName.Data(), true, true); // enable zdc check, enable lim. acc. check + histos.template get(HIST("luminosity/hLumiTVXafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 1, rctListName.Data()); + histos.template get(HIST("luminosity/hLumiTCEafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 1, rctListName.Data()); + histos.template get(HIST("luminosity/hLumiZEMafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 1, rctListName.Data()); + histos.template get(HIST("luminosity/hLumiZNCafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 1, rctListName.Data()); + histos.template get(HIST("luminosity/hLumiTVXafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 2, (rctListName + "_fullacc").Data()); + histos.template get(HIST("luminosity/hLumiTCEafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 2, (rctListName + "_fullacc").Data()); + histos.template get(HIST("luminosity/hLumiZEMafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 2, (rctListName + "_fullacc").Data()); + histos.template get(HIST("luminosity/hLumiZNCafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 2, (rctListName + "_fullacc").Data()); + histos.template get(HIST("luminosity/hLumiTVXafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 3, (rctListName + "_zdc").Data()); + histos.template get(HIST("luminosity/hLumiTCEafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 3, (rctListName + "_zdc").Data()); + histos.template get(HIST("luminosity/hLumiZEMafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 3, (rctListName + "_zdc").Data()); + histos.template get(HIST("luminosity/hLumiZNCafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 3, (rctListName + "_zdc").Data()); + histos.template get(HIST("luminosity/hLumiTVXafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 4, (rctListName + "_zdc" + "_fullacc").Data()); + histos.template get(HIST("luminosity/hLumiTCEafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 4, (rctListName + "_zdc" + "_fullacc").Data()); + histos.template get(HIST("luminosity/hLumiZEMafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 4, (rctListName + "_zdc" + "_fullacc").Data()); + histos.template get(HIST("luminosity/hLumiZNCafterBCcutsRCT"))->GetYaxis()->SetBinLabel(4 * i + 4, (rctListName + "_zdc" + "_fullacc").Data()); + } + } + + template + bool configure(TCCDB& ccdb, TTimestamps const& timestamps, TBCs const& bcs) + { + if (bcs.size() == 0) { + return false; + } + int run = bcs.iteratorAt(0).runNumber(); + if (run < 500000) { // o2-linter: disable=magic-number (skip for unanchored MCs) + return false; + } + if (run != lastRun && run >= 520259) { // o2-linter: disable=magic-number (scalers available for runs above 520120) + lastRun = run; + int64_t ts = timestamps[0]; + + // getting GRP LHCIF object to extract colliding system, energy and colliding bc pattern + auto grplhcif = ccdb->template getForTimeStamp("GLO/Config/GRPLHCIF", ts); + int beamZ1 = grplhcif->getBeamZ(constants::lhc::BeamA); + int beamZ2 = grplhcif->getBeamZ(constants::lhc::BeamC); + float sqrts = grplhcif->getSqrtS(); + int nCollidingBCs = grplhcif->getBunchFilling().getNBunches(); + bcPatternB = grplhcif->getBunchFilling().getBCPattern(); + LOGP(info, "beamZ1={} beamZ2={} sqrts={}", beamZ1, beamZ2, sqrts); + // visible cross sections in ub. Using dummy -1 if lumi estimator is not reliable for this colliding system + csTVX = -1; + csTCE = -1; + csZEM = -1; + csZNC = -1; + // Temporary workaround to get visible cross section. TODO: store run-by-run visible cross sections in CCDB + if (beamZ1 == 8 && beamZ2 == 1) { + csTVX = 0.3874e6; // eff(TVX) = 0.807 (based on LHC25e6f); sigma(INEL)=0.48b; arxiv:2507.05853 + } else if (beamZ1 == 8 && beamZ2 == 8) { + csTVX = 1.2050e6; // eff(TVX) = 0.886 (based on LHC25e6b); sigma(INEL)=1.36b; arxiv:2507.05853 + } else if (beamZ1 == 10 && beamZ2 == 10) { + csTVX = 1.5411e6; // eff(TVX) = 0.896 (based on LHC25e6g); sigma(INEL)=1.72b; arxiv:2507.05853 + } else if (beamZ1 == 1 && beamZ2 == 1) { + if (std::fabs(sqrts - 900.) < 100.) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTVX = 0.0357e6; // ub + } else if (std::fabs(sqrts - 5360.) < 100.) { // pp-ref // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTVX = 0.0503e6; // ub + } else if (std::fabs(sqrts - 13600.) < 300.) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTVX = 0.0594e6; // ub + } else { + LOGP(warn, "Cross section for pp @ {} GeV is not defined", sqrts); + } + } else if (beamZ1 == 82 && beamZ2 == 82) { // o2-linter: disable=magic-number (PbPb colliding system) + // see AN: https://alice-notes.web.cern.ch/node/1515 + if (std::fabs(sqrts - 5360) < 20) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csZNC = 214.5e6; // ub + csZEM = 415.2e6; // ub + csTCE = 10.36e6; // ub + if (run > 543437 && run < 543514) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTCE = 8.3e6; // ub + } else if (run >= 543514 && run < 545367) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTCE = 4.10e6; // ub + } else if (run >= 559544) { // o2-linter: disable=magic-number (TODO store and extract cross sections from ccdb) + csTCE = 3.86e6; // ub + } + } else { + LOGP(warn, "Cross section for PbPb @ {} GeV is not defined", sqrts); + } + } else { + LOGP(warn, "Cross section for z={} + z={} @ {} GeV is not defined", beamZ1, beamZ2, sqrts); + } + // getting CTP config to extract lumi class indices (used for rate fetching and pileup correction) + std::map metadata; + metadata["runNumber"] = std::to_string(run); + auto config = ccdb->template getSpecific("CTP/Config/Config", ts, metadata); + auto classes = config->getCTPClasses(); + TString lumiClassNameZNC = "C1ZNC-B-NOPF-CRU"; + TString lumiClassNameTCE = "CMTVXTCE-B-NOPF-CRU"; + TString lumiClassNameTVX1 = "MINBIAS_TVX"; // run >= 534467 + TString lumiClassNameTVX2 = "MINBIAS_TVX_NOMASK"; // run >= 534468 + TString lumiClassNameTVX3 = "CMTVX-NONE-NOPF-CRU"; // run >= 534996 + TString lumiClassNameTVX4 = "CMTVX-B-NOPF-CRU"; // run >= 543437 + + // find class indices + int classIdZNC = -1; + int classIdTCE = -1; + int classIdTVX = -1; + for (unsigned int i = 0; i < classes.size(); i++) { + TString clname = classes[i].name; + clname.ToUpper(); + // using position (i) in the vector of classes instead of classes[i].getIndex() + // due to bug or inconsistencies in scaler record and class indices + if (clname == lumiClassNameZNC) + classIdZNC = i; + if (clname == lumiClassNameTCE) + classIdTCE = i; + if (clname == lumiClassNameTVX4 || clname == lumiClassNameTVX3 || clname == lumiClassNameTVX2 || clname == lumiClassNameTVX1) + classIdTVX = i; + } + + // extract trigger counts from CTP scalers + auto scalers = ccdb->template getSpecific("CTP/Calib/Scalers", ts, metadata); + scalers->convertRawToO2(); + std::vector mCounterTVX; + std::vector mCounterTCE; + std::vector mCounterZNC; + std::vector mCounterZEM; + mOrbits.clear(); + for (const auto& record : scalers->getScalerRecordO2()) { + mOrbits.push_back(record.intRecord.orbit); + mCounterTVX.push_back(classIdTVX >= 0 ? record.scalers[classIdTVX].lmBefore : 0); + mCounterTCE.push_back(classIdTCE >= 0 ? record.scalers[classIdTCE].lmBefore : 0); + if (run >= 543437 && run < 544448 && record.scalersInps.size() >= 26) { // o2-linter: disable=magic-number (ZNC class not defined for this run range) + mCounterZNC.push_back(record.scalersInps[25]); // see ZNC=1ZNC input index in https://indico.cern.ch/event/1153630/contributions/4844362/ + } else { + mCounterZNC.push_back(classIdZNC >= 0 ? record.scalers[classIdZNC].l1Before : 0); + } + // ZEM class not defined, using inputs instead + uint32_t indexZEM = 24; // see ZEM=1ZED input index in https://indico.cern.ch/event/1153630/contributions/4844362/ + mCounterZEM.push_back(record.scalersInps.size() >= indexZEM + 1 ? record.scalersInps[indexZEM] : 0); + } + + // calculate pileup corrections + mPileupCorrectionTVX.clear(); + mPileupCorrectionTCE.clear(); + mPileupCorrectionZEM.clear(); + mPileupCorrectionZNC.clear(); + for (uint32_t i = 0; i < mOrbits.size() - 1; i++) { + int64_t nOrbits = mOrbits[i + 1] - mOrbits[i]; + if (nOrbits <= 0 || nCollidingBCs == 0) + continue; + double perBcRateTVX = static_cast(mCounterTVX[i + 1] - mCounterTVX[i]) / nOrbits / nCollidingBCs; + double perBcRateTCE = static_cast(mCounterTCE[i + 1] - mCounterTCE[i]) / nOrbits / nCollidingBCs; + double perBcRateZNC = static_cast(mCounterZNC[i + 1] - mCounterZNC[i]) / nOrbits / nCollidingBCs; + double perBcRateZEM = static_cast(mCounterZEM[i + 1] - mCounterZEM[i]) / nOrbits / nCollidingBCs; + double muTVX = (perBcRateTVX < 1 && perBcRateTVX > 1e-10) ? -std::log(1 - perBcRateTVX) : 0; + double muTCE = (perBcRateTCE < 1 && perBcRateTCE > 1e-10) ? -std::log(1 - perBcRateTCE) : 0; + double muZNC = (perBcRateZNC < 1 && perBcRateZNC > 1e-10) ? -std::log(1 - perBcRateZNC) : 0; + double muZEM = (perBcRateZEM < 1 && perBcRateZEM > 1e-10) ? -std::log(1 - perBcRateZEM) : 0; + LOGP(debug, "orbit={} muTVX={} muTCE={} muZNC={} muZEM={}", mOrbits[i], muTVX, muTCE, muZNC, muZEM); + mPileupCorrectionTVX.push_back(muTVX > 1e-10 ? muTVX / (1 - std::exp(-muTVX)) : 1); + mPileupCorrectionTCE.push_back(muTCE > 1e-10 ? muTCE / (1 - std::exp(-muTCE)) : 1); + mPileupCorrectionZNC.push_back(muZNC > 1e-10 ? muZNC / (1 - std::exp(-muZNC)) : 1); + mPileupCorrectionZEM.push_back(muZEM > 1e-10 ? muZEM / (1 - std::exp(-muZEM)) : 1); + } + // filling last orbit range using previous orbit range + mPileupCorrectionTVX.push_back(mPileupCorrectionTVX.back()); + mPileupCorrectionTCE.push_back(mPileupCorrectionTCE.back()); + mPileupCorrectionZNC.push_back(mPileupCorrectionZNC.back()); + mPileupCorrectionZEM.push_back(mPileupCorrectionZEM.back()); + } // access ccdb once per run + return true; // carry on, please + } + + //__________________________________________________ + template + void process(TCCDB& ccdb, THistoRegistry& histos, TBCs const& bcs, TTimestamps const& timestamps, TBcSelBuffer const& bcselBuffer) + { + if (lumiOpts.amIneeded.value == 0) { + return; + } + + if (!configure(ccdb, timestamps, bcs)) + return; // don't do anything in case configuration reported not ok + + int run = bcs.iteratorAt(0).runNumber(); + const char* srun = Form("%d", run); + + // processing loop + for (const auto& bc : bcs) { + auto selection = bcselBuffer[bc.globalIndex()].selection; + if (bcPatternB[bc.globalBC() % nBCsPerOrbit] == 0) // skip non-colliding bcs + continue; + + bool noBorder = TESTBIT(selection, aod::evsel::kNoTimeFrameBorder) && TESTBIT(selection, aod::evsel::kNoITSROFrameBorder); + bool isTriggerTVX = TESTBIT(selection, aod::evsel::kIsTriggerTVX); + bool isTriggerTCE = bc.has_ft0() ? (TESTBIT(selection, aod::evsel::kIsTriggerTVX) && TESTBIT(bc.ft0().triggerMask(), o2::ft0::Triggers::bitCen)) : 0; + bool isTriggerZNA = TESTBIT(selection, aod::evsel::kIsBBZNA); + bool isTriggerZNC = TESTBIT(selection, aod::evsel::kIsBBZNC); + bool isTriggerZEM = isTriggerZNA || isTriggerZNC; + + // determine pileup correction + int64_t orbit = bc.globalBC() / nBCsPerOrbit; + if ((orbit < minOrbitInRange || orbit > maxOrbitInRange) && mOrbits.size() > 1) { + auto it = std::lower_bound(mOrbits.begin(), mOrbits.end(), orbit); + uint32_t nextOrbitIndex = std::distance(mOrbits.begin(), it); + if (nextOrbitIndex == 0) // if orbit is below stored scaler orbits + nextOrbitIndex = 1; + else if (nextOrbitIndex == mOrbits.size()) // if orbit is above stored scaler orbits + nextOrbitIndex = mOrbits.size() - 1; + currentOrbitIndex = nextOrbitIndex - 1; + minOrbitInRange = mOrbits[currentOrbitIndex]; + maxOrbitInRange = mOrbits[nextOrbitIndex]; + } + double pileupCorrectionTVX = currentOrbitIndex < mPileupCorrectionTVX.size() ? mPileupCorrectionTVX[currentOrbitIndex] : 1.; + double pileupCorrectionTCE = currentOrbitIndex < mPileupCorrectionTCE.size() ? mPileupCorrectionTCE[currentOrbitIndex] : 1.; + double pileupCorrectionZNC = currentOrbitIndex < mPileupCorrectionZNC.size() ? mPileupCorrectionZNC[currentOrbitIndex] : 1.; + double pileupCorrectionZEM = currentOrbitIndex < mPileupCorrectionZEM.size() ? mPileupCorrectionZEM[currentOrbitIndex] : 1.; + + double lumiTVX = 1. / csTVX * pileupCorrectionTVX; + double lumiTCE = 1. / csTCE * pileupCorrectionTCE; + double lumiZNC = 1. / csZNC * pileupCorrectionZNC; + double lumiZEM = 1. / csZEM * pileupCorrectionZEM; + + auto rct = bcselBuffer[bc.globalIndex()].rct; + + if (isTriggerTVX) { + histos.template get(HIST("luminosity/hCounterTVX"))->Fill(srun, 1); + histos.template get(HIST("luminosity/hLumiTVX"))->Fill(srun, lumiTVX); + if (isTriggerZNA && isTriggerZNC) { + histos.template get(HIST("luminosity/hCounterTVXZDC"))->Fill(srun, 1); + } + if (noBorder) { + histos.template get(HIST("luminosity/hCounterTVXafterBCcuts"))->Fill(srun, 1); + histos.template get(HIST("luminosity/hLumiTVXafterBCcuts"))->Fill(srun, lumiTVX); + if (isTriggerZNA && isTriggerZNC) { + histos.template get(HIST("luminosity/hCounterTVXZDCafterBCcuts"))->Fill(srun, 1); + } + for (size_t i = 0; i < mRCTFlagsCheckers.size(); i++) { + if ((rct & mRCTFlagsCheckers[i].value()) == 0) + histos.template get(HIST("luminosity/hLumiTVXafterBCcutsRCT"))->Fill(srun, i, lumiTVX); + } + } + } + + if (isTriggerTCE) { + histos.template get(HIST("luminosity/hCounterTCE"))->Fill(srun, 1); + histos.template get(HIST("luminosity/hLumiTCE"))->Fill(srun, lumiTCE); + if (noBorder) { + histos.template get(HIST("luminosity/hCounterTCEafterBCcuts"))->Fill(srun, 1); + histos.template get(HIST("luminosity/hLumiTCEafterBCcuts"))->Fill(srun, lumiTCE); + for (size_t i = 0; i < mRCTFlagsCheckers.size(); i++) { + if ((rct & mRCTFlagsCheckers[i].value()) == 0) + histos.template get(HIST("luminosity/hLumiTCEafterBCcutsRCT"))->Fill(srun, i, lumiTCE); + } + } + } + + if (isTriggerZEM) { + histos.template get(HIST("luminosity/hCounterZEM"))->Fill(srun, 1); + histos.template get(HIST("luminosity/hLumiZEM"))->Fill(srun, lumiZEM); + if (noBorder) { + histos.template get(HIST("luminosity/hCounterZEMafterBCcuts"))->Fill(srun, 1); + histos.template get(HIST("luminosity/hLumiZEMafterBCcuts"))->Fill(srun, lumiZEM); + for (size_t i = 0; i < mRCTFlagsCheckers.size(); i++) { + if ((rct & mRCTFlagsCheckers[i].value()) == 0) + histos.template get(HIST("luminosity/hLumiZEMafterBCcutsRCT"))->Fill(srun, i, lumiZEM); + } + } + } + + if (isTriggerZNC) { + histos.template get(HIST("luminosity/hCounterZNC"))->Fill(srun, 1); + histos.template get(HIST("luminosity/hLumiZNC"))->Fill(srun, lumiZNC); + if (noBorder) { + histos.template get(HIST("luminosity/hCounterZNCafterBCcuts"))->Fill(srun, 1); + histos.template get(HIST("luminosity/hLumiZNCafterBCcuts"))->Fill(srun, lumiZNC); + for (size_t i = 0; i < mRCTFlagsCheckers.size(); i++) { + if ((rct & mRCTFlagsCheckers[i].value()) == 0) + histos.template get(HIST("luminosity/hLumiZNCafterBCcutsRCT"))->Fill(srun, i, lumiZNC); + } + } + } + } // bcs + } // process +}; // end LumiModule + +} // namespace eventselection +} // namespace common +} // namespace o2 + +#endif // COMMON_TOOLS_EVENTSELECTIONMODULE_H_ diff --git a/Common/Tools/Multiplicity/MultModule.h b/Common/Tools/Multiplicity/MultModule.h new file mode 100644 index 00000000000..3fc13db0d7f --- /dev/null +++ b/Common/Tools/Multiplicity/MultModule.h @@ -0,0 +1,1460 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MultModule.h +/// \brief combined multiplicity + centrality module with autodetect features +/// \author ALICE + +#ifndef COMMON_TOOLS_MULTIPLICITY_MULTMODULE_H_ +#define COMMON_TOOLS_MULTIPLICITY_MULTMODULE_H_ + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//__________________________________________ +// MultModule + +namespace o2 +{ +namespace common +{ +namespace multiplicity +{ + +// statics necessary for the configurables in this namespace +static constexpr int nParameters = 1; +static const std::vector tableNames{ + // multiplicity subcomponent + "FV0Mults", + "FV0AOuterMults", + "FT0Mults", + "FDDMults", + "ZDCMults", + "TrackletMults", + "TPCMults", + "PVMults", + "MultsExtra", + "MultSelections", + "FV0MultZeqs", + "FT0MultZeqs", + "FDDMultZeqs", + "PVMultZeqs", + "GlobalMultZeqs", + "MFTMultZeqs", + "MultMCExtras", + "Mult2MCExtras", + "MFTMults", + "MultsGlobal", + + // centrality subcomponent + "CentRun2V0Ms", + "CentRun2V0As", + "CentRun2SPDTrks", + "CentRun2SPDClss", + "CentRun2CL0s", + "CentRun2CL1s", + "CentFV0As", + "CentFT0Ms", + "CentFT0As", + "CentFT0Cs", + "CentFT0CVariant1s", + "CentFT0CVariant2s", + "CentFDDMs", + "CentNTPVs", + "CentNGlobals", + "CentMFTs", + "BCCentFT0Ms", + "BCCentFT0As", + "BCCentFT0Cs"}; + +static constexpr int nTablesConst = 39; + +static const std::vector parameterNames{"enable"}; +static const int defaultParameters[nTablesConst][nParameters]{ + {-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}}; + +// table index : match order above +enum tableIndex { kFV0Mults, // standard + kFV0AOuterMults, // standard + kFT0Mults, // standard + kFDDMults, // standard + kZDCMults, // standard + kTrackletMults, // Run 2 + kTPCMults, // standard + kPVMults, // standard + kMultsExtra, // standard + kMultSelections, // event selection + kFV0MultZeqs, // zeq calib, standard + kFT0MultZeqs, // zeq calib, standard + kFDDMultZeqs, // zeq calib, standard + kPVMultZeqs, // zeq calib, standard + kGlobalMultZeqs, // zeq calib, extra + kMFTMultZeqs, // zeq calib, extra + kMultMCExtras, // MC exclusive + kMult2MCExtras, // MC exclusive + kMFTMults, // requires MFT task + kMultsGlobal, // requires track selection task + + // centrality subcomponent + kCentRun2V0Ms, // Run 2 + kCentRun2V0As, // Run 2 + kCentRun2SPDTrks, // Run 2 + kCentRun2SPDClss, // Run 2 + kCentRun2CL0s, // Run 2 + kCentRun2CL1s, // Run 2 + kCentFV0As, // standard Run 3 + kCentFT0Ms, // standard Run 3 + kCentFT0As, // standard Run 3 + kCentFT0Cs, // standard Run 3 + kCentFT0CVariant1s, // standard Run 3 + kCentFT0CVariant2s, // standard Run 3 + kCentFDDMs, // standard Run 3 + kCentNTPVs, // standard Run 3 + kCentNGlobals, // requires track selection task + kCentMFTs, // requires MFT task + kBCCentFT0Ms, // bc centrality + kBCCentFT0As, // bc centrality + kBCCentFT0Cs, // bc centrality + kNTables }; + +struct products : o2::framework::ProducesGroup { + //__________________________________________________ + // multiplicity tables + o2::framework::Produces tableFV0; + o2::framework::Produces tableFV0AOuter; + o2::framework::Produces tableFT0; + o2::framework::Produces tableFDD; + o2::framework::Produces tableZDC; + o2::framework::Produces tableTracklet; + o2::framework::Produces tableTpc; + o2::framework::Produces tablePv; + o2::framework::Produces tableExtra; + o2::framework::Produces multSelections; + o2::framework::Produces tableFV0Zeqs; + o2::framework::Produces tableFT0Zeqs; + o2::framework::Produces tableFDDZeqs; + o2::framework::Produces tablePVZeqs; + o2::framework::Produces tableNGlobalZeqs; + o2::framework::Produces tableNMFTZeqs; + o2::framework::Produces tableExtraMc; + o2::framework::Produces tableExtraMult2MCExtras; + o2::framework::Produces mftMults; + o2::framework::Produces multsGlobal; + + //__________________________________________________ + // centrality tables (per collision / default) + o2::framework::Produces centRun2V0M; + o2::framework::Produces centRun2V0A; + o2::framework::Produces centRun2SPDTracklets; + o2::framework::Produces centRun2SPDClusters; + o2::framework::Produces centRun2CL0; + o2::framework::Produces centRun2CL1; + o2::framework::Produces centFV0A; + o2::framework::Produces centFT0M; + o2::framework::Produces centFT0A; + o2::framework::Produces centFT0C; + o2::framework::Produces centFT0CVariant1; + o2::framework::Produces centFT0CVariant2; + o2::framework::Produces centFDDM; + o2::framework::Produces centNTPV; + o2::framework::Produces centNGlobals; + o2::framework::Produces centMFTs; + o2::framework::Produces bcCentFT0A; + o2::framework::Produces bcCentFT0C; + o2::framework::Produces bcCentFT0M; + + //__________________________________________________ + // centrality tables per BC + // FIXME - future development +}; + +// for providing temporary buffer +// FIXME ideally cursors could be readable +// to avoid duplicate memory allocation but ok +struct multEntry { + float multFV0A = 0.0f; + float multFV0C = 0.0f; + float multFV0AOuter = 0.0f; + float multFT0A = 0.0f; + float multFT0C = 0.0f; + float multFDDA = 0.0f; + float multFDDC = 0.0f; + float multZNA = 0.0f; + float multZNC = 0.0f; + float multZEM1 = 0.0f; + float multZEM2 = 0.0f; + float multZPA = 0.0f; + float multZPC = 0.0f; + int multTracklets = 0; + + int multNContribs = 0; // PVMult 0.8 + int multNContribsEta1 = 0; // PVMult 1.0 + int multNContribsEtaHalf = 0; // PVMult 0.5 + int multTPC = 0; // all TPC (PV contrib unchecked) + int multHasTPC = 0; // extras + int multHasITS = 0; // extras + int multHasTOF = 0; // extras + int multHasTRD = 0; // extras + int multITSOnly = 0; // extras + int multTPCOnly = 0; // extras + int multITSTPC = 0; // extras + int multAllTracksTPCOnly = 0; // extras + int multAllTracksITSTPC = 0; // extras + + float multFV0AZeq = -999.0f; + float multFV0CZeq = -999.0f; + float multFT0AZeq = -999.0f; + float multFT0CZeq = -999.0f; + float multFDDAZeq = -999.0f; + float multFDDCZeq = -999.0f; + float multNContribsZeq = 0; + float multMFTTracksZeq = 0; + float multGlobalTracksZeq = 0; + + int multGlobalTracks = 0; // multsGlobal + int multNbrContribsEta05GlobalTrackWoDCA = 0; // multsGlobal + int multNbrContribsEta08GlobalTrackWoDCA = 0; // multsGlobal + int multNbrContribsEta10GlobalTrackWoDCA = 0; // multsGlobal + + int multMFTAllTracks = 0; // mft + int multMFTTracks = 0; // mft + + // For Run2 only + float posZ = -999.0f; + uint16_t spdClustersL0 = 0; + uint16_t spdClustersL1 = 0; +}; + +// strangenessBuilder: 1st-order configurables +struct standardConfigurables : o2::framework::ConfigurableGroup { + // self-configuration configurables + o2::framework::Configurable> enabledTables{"enabledTables", + {defaultParameters[0], nTablesConst, nParameters, tableNames, parameterNames}, + "Produce this table: -1 for autodetect; otherwise, 0/1 is false/true"}; + std::vector mEnabledTables; // Vector of enabled tables + + // Autoconfigure process functions + o2::framework::Configurable autoConfigureProcess{"autoConfigureProcess", false, "if true, will configure process function switches based on metadata"}; + + // do vertex-Z equalized or not + o2::framework::Configurable doVertexZeq{"doVertexZeq", 1, "if 1: do vertex Z eq mult table"}; + + // global track counter configurables + o2::framework::Configurable minPtGlobalTrack{"minPtGlobalTrack", 0.15, "min. pT for global tracks"}; + o2::framework::Configurable maxPtGlobalTrack{"maxPtGlobalTrack", 1e+10, "max. pT for global tracks"}; + o2::framework::Configurable minNclsITSGlobalTrack{"minNclsITSGlobalTrack", 5, "min. number of ITS clusters for global tracks"}; + o2::framework::Configurable minNclsITSibGlobalTrack{"minNclsITSibGlobalTrack", 1, "min. number of ITSib clusters for global tracks"}; + + // ccdb information + o2::framework::Configurable ccdbPathVtxZ{"ccdbPathVtxZ", "Centrality/Calibration", "The CCDB path for vertex-Z calibration"}; + o2::framework::Configurable ccdbPathCentrality{"ccdbPathCentrality", "Centrality/Estimators", "The CCDB path for centrality information"}; + o2::framework::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."}}; + + // centrality operation + o2::framework::Configurable generatorName{"generatorName", "", {"Specify if and only if this is MC. Typical: PYTHIA"}}; + o2::framework::Configurable embedINELgtZEROselection{"embedINELgtZEROselection", false, {"Option to do percentile 100.5 if not INELgtZERO"}}; +}; + +class MultModule +{ + public: + MultModule() + { + // constructor + mRunNumber = 0; + mRunNumberCentrality = 0; + lCalibLoaded = false; + lCalibObjects = nullptr; + hVtxZFV0A = nullptr; + hVtxZFT0A = nullptr; + hVtxZFT0C = nullptr; + hVtxZFDDA = nullptr; + hVtxZFDDC = nullptr; + hVtxZNTracks = nullptr; + hVtxZNMFTTracks = nullptr; + hVtxZNGlobalTracks = nullptr; + } + + // internal: calib related, vtx-z profiles + int mRunNumber; + int mRunNumberCentrality; + bool lCalibLoaded; + TList* lCalibObjects; + TProfile* hVtxZFV0A; + TProfile* hVtxZFT0A; + TProfile* hVtxZFT0C; + TProfile* hVtxZFDDA; + TProfile* hVtxZFDDC; + TProfile* hVtxZNTracks; + TProfile* hVtxZNMFTTracks; // non-legacy, added August/2025 + TProfile* hVtxZNGlobalTracks; // non-legacy, added August/2025 + + // declaration of structs here + // (N.B.: will be invisible to the outside, create your own copies) + o2::common::multiplicity::standardConfigurables internalOpts; + + //_________________________________________________ + // centrality-related objects + 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 ft0cVariant2Info = CalibrationInfo("FT0Cvar2"); + CalibrationInfo fddmInfo = CalibrationInfo("FDD"); + CalibrationInfo ntpvInfo = CalibrationInfo("NTracksPV"); + CalibrationInfo nGlobalInfo = CalibrationInfo("NGlobal"); + CalibrationInfo mftInfo = CalibrationInfo("MFT"); + + template + void init(TMetadatainfo const& metadataInfo, TConfigurables& opts, TInitContext& context) + { + // read in configurations from the task where it's used + internalOpts = opts; + internalOpts.mEnabledTables.resize(nTablesConst, 0); + + LOGF(info, "Configuring tables to generate"); + LOGF(info, "Metadata information: isMC? %i", metadataInfo.isMC()); + const auto& workflows = context.services().template get(); + + TString listOfRequestors[nTablesConst]; + for (int i = 0; i < nTablesConst; i++) { + int f = internalOpts.enabledTables->get(tableNames[i].c_str(), "enable"); + if (f == 1) { + internalOpts.mEnabledTables[i] = 1; + listOfRequestors[i] = "manual enabling"; + } + if (f == -1) { + // autodetect this table in other devices + for (o2::framework::DeviceSpec const& device : workflows.devices) { + // Step 1: check if this device subscribed to the V0data table + for (auto const& input : device.inputs) { + if (o2::framework::DataSpecUtils::partialMatch(input.matcher, o2::header::DataOrigin("AOD"))) { + auto&& [origin, description, version] = o2::framework::DataSpecUtils::asConcreteDataMatcher(input.matcher); + std::string tableNameWithVersion = tableNames[i]; + if (version > 0) { + tableNameWithVersion += Form("_%03d", version); + } + if (input.matcher.binding == tableNameWithVersion) { + LOGF(info, "Device %s has subscribed to %s (version %i)", device.name, tableNames[i], version); + listOfRequestors[i].Append(Form("%s ", device.name.c_str())); + internalOpts.mEnabledTables[i] = 1; + } + } + } + } + } + } + + // dependency checker + if (internalOpts.mEnabledTables[kCentFV0As] && !internalOpts.mEnabledTables[kFV0MultZeqs]) { + internalOpts.mEnabledTables[kFV0MultZeqs] = 1; + listOfRequestors[kFV0MultZeqs].Append(Form("%s ", "dependency check")); + } + if ((internalOpts.mEnabledTables[kCentFT0As] || internalOpts.mEnabledTables[kCentFT0Cs] || internalOpts.mEnabledTables[kCentFT0Ms] || internalOpts.mEnabledTables[kCentFT0CVariant1s]) && !internalOpts.mEnabledTables[kFT0MultZeqs]) { + internalOpts.mEnabledTables[kFT0MultZeqs] = 1; + listOfRequestors[kFT0MultZeqs].Append(Form("%s ", "dependency check")); + } + if (internalOpts.mEnabledTables[kCentFDDMs] && !internalOpts.mEnabledTables[kFDDMultZeqs]) { + internalOpts.mEnabledTables[kFDDMultZeqs] = 1; + listOfRequestors[kFDDMultZeqs].Append(Form("%s ", "dependency check")); + } + if (internalOpts.mEnabledTables[kCentMFTs] && !internalOpts.mEnabledTables[kMFTMults]) { + internalOpts.mEnabledTables[kMFTMults] = 1; + listOfRequestors[kMFTMults].Append(Form("%s ", "dependency check")); + } + if (internalOpts.mEnabledTables[kCentMFTs] && !internalOpts.mEnabledTables[kMFTMultZeqs]) { + internalOpts.mEnabledTables[kMFTMultZeqs] = 1; + listOfRequestors[kMFTMultZeqs].Append(Form("%s ", "dependency check")); + } + if (internalOpts.mEnabledTables[kCentNGlobals] && !internalOpts.mEnabledTables[kMultsGlobal]) { + internalOpts.mEnabledTables[kMultsGlobal] = 1; + listOfRequestors[kMultsGlobal].Append(Form("%s ", "dependency check")); + } + if (internalOpts.mEnabledTables[kCentNGlobals] && !internalOpts.mEnabledTables[kGlobalMultZeqs]) { + internalOpts.mEnabledTables[kGlobalMultZeqs] = 1; + listOfRequestors[kGlobalMultZeqs].Append(Form("%s ", "dependency check")); + } + if (internalOpts.embedINELgtZEROselection.value > 0 && !internalOpts.mEnabledTables[kPVMults]) { + internalOpts.mEnabledTables[kPVMults] = 1; + listOfRequestors[kPVMults].Append(Form("%s ", "dependency check")); + } + + // list enabled tables + for (int i = 0; i < nTablesConst; i++) { + // printout to be improved in the future + if (internalOpts.mEnabledTables[i]) { + LOGF(info, " -~> Table enabled: %s, requested by %s", tableNames[i], listOfRequestors[i].Data()); + } + } + + mRunNumber = 0; + mRunNumberCentrality = 0; + lCalibLoaded = false; + hVtxZFV0A = nullptr; + hVtxZFT0A = nullptr; + hVtxZFT0C = nullptr; + hVtxZFDDA = nullptr; + hVtxZFDDC = nullptr; + hVtxZNTracks = nullptr; + hVtxZNMFTTracks = nullptr; + hVtxZNGlobalTracks = nullptr; + + opts = internalOpts; + } + + //__________________________________________________ + template + o2::common::multiplicity::multEntry collisionProcessRun2(TCollision const& collision, TTracks const& tracks, TBC const& bc, TOutputGroup& cursors) + { + // initialize properties + o2::common::multiplicity::multEntry mults; + + mults.posZ = collision.posZ(); + mults.spdClustersL0 = bc.spdClustersL0(); + mults.spdClustersL1 = bc.spdClustersL1(); + //_______________________________________________________________________ + // forward detector signals, raw + if (collision.has_fv0a()) { + for (const auto& amplitude : collision.fv0a().amplitude()) { + mults.multFV0A += amplitude; + } + } + if (collision.has_fv0c()) { + for (const auto& amplitude : collision.fv0c().amplitude()) { + mults.multFV0C += amplitude; + } + } + if (collision.has_ft0()) { + auto ft0 = collision.ft0(); + for (const auto& amplitude : ft0.amplitudeA()) { + mults.multFT0A += amplitude; + } + for (const auto& amplitude : ft0.amplitudeC()) { + mults.multFT0C += amplitude; + } + } + if (collision.has_zdc()) { + auto zdc = collision.zdc(); + mults.multZNA = zdc.energyCommonZNA(); + mults.multZNC = zdc.energyCommonZNC(); + } + + //_______________________________________________________________________ + // determine if barrel track loop is required, do it (once!) if so but save CPU if not + if (internalOpts.mEnabledTables[kPVMults] || internalOpts.mEnabledTables[kTPCMults] || internalOpts.mEnabledTables[kTrackletMults]) { + // Try to do something Similar to https://github.com/alisw/AliPhysics/blob/22862a945004f719f8e9664c0264db46e7186a48/OADB/AliPPVsMultUtils.cxx#L541C26-L541C37 + for (const auto& track : tracks) { + // check whether the track is a tracklet + if (track.trackType() == o2::aod::track::Run2Tracklet) { + if (internalOpts.mEnabledTables[kTrackletMults]) { + mults.multTracklets++; + } + if (internalOpts.mEnabledTables[kPVMults]) { + if (std::abs(track.eta()) < 1.0) { + mults.multNContribsEta1++; // pvmults + if (std::abs(track.eta()) < 0.8) { + mults.multNContribs++; // pvmults + if (std::abs(track.eta()) < 0.5) { + mults.multNContribsEtaHalf++; // pvmults + } + } + } + } + } + // check whether the track is a global ITS-TPC track + if (track.tpcNClsFindable() > 0) { + if (internalOpts.mEnabledTables[kTPCMults]) { + mults.multTPC++; + } + } + } + } + + // fill standard cursors if required + if (internalOpts.mEnabledTables[kFV0Mults]) { + cursors.tableFV0(mults.multFV0A, mults.multFV0C); + } + if (internalOpts.mEnabledTables[kFT0Mults]) { + cursors.tableFT0(mults.multFT0A, mults.multFT0C); + } + if (internalOpts.mEnabledTables[kFDDMults]) { + cursors.tableFDD(mults.multFDDA, mults.multFDDC); + } + if (internalOpts.mEnabledTables[kZDCMults]) { + cursors.tableZDC(mults.multZNA, mults.multZNC, 0.0f, 0.0f, 0.0f, 0.0f); + } + if (internalOpts.mEnabledTables[kTrackletMults]) { // Tracklets only Run2 + cursors.tableTracklet(mults.multTracklets); + } + if (internalOpts.mEnabledTables[kTPCMults]) { + cursors.tableTpc(mults.multTPC); + } + if (internalOpts.mEnabledTables[kPVMults]) { + cursors.tablePv(mults.multNContribs, mults.multNContribsEta1, mults.multNContribsEtaHalf); + } + + return mults; + } + + //__________________________________________________ + template + o2::common::multiplicity::multEntry collisionProcessRun3(TCCDB const& ccdb, TMetadataInfo const& metadataInfo, TCollision const& collision, TTracks const& tracks, TBC const& bc, TOutputGroup& cursors) + { + // initialize properties + o2::common::multiplicity::multEntry mults; + + //_______________________________________________________________________ + // preparatory steps + if (internalOpts.doVertexZeq > 0) { + if (bc.runNumber() != mRunNumber) { + mRunNumber = bc.runNumber(); // mark this run as at least tried + if (internalOpts.reconstructionPass.value == "") { + lCalibObjects = ccdb->template getForRun(internalOpts.ccdbPathVtxZ, mRunNumber); + } else if (internalOpts.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->template getSpecificForRun(internalOpts.ccdbPathVtxZ, mRunNumber, metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = internalOpts.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", internalOpts.reconstructionPass.value); + lCalibObjects = ccdb->template getSpecificForRun(internalOpts.ccdbPathVtxZ, mRunNumber, metadata); + } + + if (lCalibObjects) { + hVtxZFV0A = static_cast(lCalibObjects->FindObject("hVtxZFV0A")); + hVtxZFT0A = static_cast(lCalibObjects->FindObject("hVtxZFT0A")); + hVtxZFT0C = static_cast(lCalibObjects->FindObject("hVtxZFT0C")); + hVtxZFDDA = static_cast(lCalibObjects->FindObject("hVtxZFDDA")); + hVtxZFDDC = static_cast(lCalibObjects->FindObject("hVtxZFDDC")); + hVtxZNTracks = static_cast(lCalibObjects->FindObject("hVtxZNTracksPV")); + hVtxZNMFTTracks = static_cast(lCalibObjects->FindObject("hVtxZMFT")); + hVtxZNGlobalTracks = static_cast(lCalibObjects->FindObject("hVtxZNGlobals")); + lCalibLoaded = true; + // Capture error + if (!hVtxZFV0A || !hVtxZFT0A || !hVtxZFT0C || !hVtxZFDDA || !hVtxZFDDC || !hVtxZNTracks) { + LOGF(error, "Problem loading CCDB objects! Please check"); + lCalibLoaded = false; + } + if (!hVtxZNMFTTracks) { + LOGF(info, "MFT track counter: vertex-Z calibration not loaded, will run without."); + } + if (!hVtxZNGlobalTracks) { + LOGF(info, "Global track counter: vertex-Z calibration not loaded, will run without."); + } + } else { + LOGF(error, "Problem loading CCDB object! Please check"); + lCalibLoaded = false; + } + } + } + + //_______________________________________________________________________ + // forward detector signals, raw + if (collision.has_foundFV0()) { + 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]; + mults.multFV0A += amplitude; + if (channel > 7) { + mults.multFV0AOuter += amplitude; + } + } + } else { + mults.multFV0A = -999.f; + mults.multFV0AOuter = -999.f; + } + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + for (const auto& amplitude : ft0.amplitudeA()) { + mults.multFT0A += amplitude; + } + for (const auto& amplitude : ft0.amplitudeC()) { + mults.multFT0C += amplitude; + } + } else { + mults.multFT0A = -999.f; + mults.multFT0C = -999.f; + } + if (collision.has_foundFDD()) { + const auto& fdd = collision.foundFDD(); + for (const auto& amplitude : fdd.chargeA()) { + mults.multFDDA += amplitude; + } + for (const auto& amplitude : fdd.chargeC()) { + mults.multFDDC += amplitude; + } + } else { + mults.multFDDA = -999.f; + mults.multFDDC = -999.f; + } + if (bc.has_zdc()) { + mults.multZNA = bc.zdc().amplitudeZNA(); + mults.multZNC = bc.zdc().amplitudeZNC(); + mults.multZEM1 = bc.zdc().amplitudeZEM1(); + mults.multZEM2 = bc.zdc().amplitudeZEM2(); + mults.multZPA = bc.zdc().amplitudeZPA(); + mults.multZPC = bc.zdc().amplitudeZPC(); + } else { + mults.multZNA = -999.f; + mults.multZNC = -999.f; + mults.multZEM1 = -999.f; + mults.multZEM2 = -999.f; + mults.multZPA = -999.f; + mults.multZPC = -999.f; + } + + // fill standard cursors if required + if (internalOpts.mEnabledTables[kTrackletMults]) { // Tracklets (only Run2) nothing to do (to be removed!) + cursors.tableTracklet(0); + } + if (internalOpts.mEnabledTables[kFV0Mults]) { + cursors.tableFV0(mults.multFV0A, mults.multFV0C); + } + if (internalOpts.mEnabledTables[kFV0AOuterMults]) { + cursors.tableFV0AOuter(mults.multFV0AOuter); + } + if (internalOpts.mEnabledTables[kFT0Mults]) { + cursors.tableFT0(mults.multFT0A, mults.multFT0C); + } + if (internalOpts.mEnabledTables[kFDDMults]) { + cursors.tableFDD(mults.multFDDA, mults.multFDDC); + } + if (internalOpts.mEnabledTables[kZDCMults]) { + cursors.tableZDC(mults.multZNA, mults.multZNC, mults.multZEM1, mults.multZEM2, mults.multZPA, mults.multZPC); + } + + //_______________________________________________________________________ + // fill selections (for posterior derived analysis if requested) + if (internalOpts.mEnabledTables[kMultSelections]) { + cursors.multSelections(collision.selection_raw()); + } + + //_______________________________________________________________________ + // vertex-Z equalized signals + if (internalOpts.mEnabledTables[kFV0MultZeqs]) { + if (mults.multFV0A > -1.0f && std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + mults.multFV0AZeq = hVtxZFV0A->Interpolate(0.0) * mults.multFV0A / hVtxZFV0A->Interpolate(collision.posZ()); + } else { + mults.multFV0AZeq = 0.0f; + } + cursors.tableFV0Zeqs(mults.multFV0AZeq); + } + if (internalOpts.mEnabledTables[kFT0MultZeqs]) { + if (mults.multFT0A > -1.0f && std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + mults.multFT0AZeq = hVtxZFT0A->Interpolate(0.0) * mults.multFT0A / hVtxZFT0A->Interpolate(collision.posZ()); + } else { + mults.multFT0AZeq = 0.0f; + } + if (mults.multFT0C > -1.0f && std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + mults.multFT0CZeq = hVtxZFT0C->Interpolate(0.0) * mults.multFT0C / hVtxZFT0C->Interpolate(collision.posZ()); + } else { + mults.multFT0CZeq = 0.0f; + } + cursors.tableFT0Zeqs(mults.multFT0AZeq, mults.multFT0CZeq); + } + if (internalOpts.mEnabledTables[kFDDMultZeqs]) { + if (mults.multFDDA > -1.0f && std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + mults.multFDDAZeq = hVtxZFDDA->Interpolate(0.0) * mults.multFDDA / hVtxZFDDA->Interpolate(collision.posZ()); + } else { + mults.multFDDAZeq = 0.0f; + } + if (mults.multFDDC > -1.0f && std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + mults.multFDDCZeq = hVtxZFDDC->Interpolate(0.0) * mults.multFDDC / hVtxZFDDC->Interpolate(collision.posZ()); + } else { + mults.multFDDCZeq = 0.0f; + } + cursors.tableFDDZeqs(mults.multFDDAZeq, mults.multFDDCZeq); + } + + //_______________________________________________________________________ + // determine if barrel track loop is required, do it (once!) if so but save CPU if not + if (internalOpts.mEnabledTables[kTPCMults] || internalOpts.mEnabledTables[kPVMults] || internalOpts.mEnabledTables[kMultsExtra] || internalOpts.mEnabledTables[kPVMultZeqs] || internalOpts.mEnabledTables[kMultsGlobal] || internalOpts.mEnabledTables[kGlobalMultZeqs]) { + // single loop to calculate all + for (const auto& track : tracks) { + if (track.hasTPC()) { + mults.multTPC++; + if (track.hasITS()) { + mults.multAllTracksITSTPC++; // multsextra + } else { + mults.multAllTracksTPCOnly++; // multsextra + } + } + // PV contributor checked explicitly + if (track.isPVContributor()) { + if (std::abs(track.eta()) < 1.0) { + mults.multNContribsEta1++; // pvmults + if (std::abs(track.eta()) < 0.8) { + mults.multNContribs++; // pvmults + if (std::abs(track.eta()) < 0.5) { + mults.multNContribsEtaHalf++; // pvmults + } + } + } + if (track.hasITS()) { + mults.multHasITS++; // multsextra + if (track.hasTPC()) + mults.multITSTPC++; // multsextra + if (!track.hasTPC() && !track.hasTOF() && !track.hasTRD()) { + mults.multITSOnly++; // multsextra + } + } + if (track.hasTPC()) { + mults.multHasTPC++; // multsextra + if (!track.hasITS() && !track.hasTOF() && !track.hasTRD()) { + mults.multTPCOnly++; // multsextra + } + } + if (track.hasTOF()) { + mults.multHasTOF++; // multsextra + } + if (track.hasTRD()) { + mults.multHasTRD++; // multsextra + } + } + + // global counters: do them only in case information is provided in tracks table + if constexpr (requires { track.isQualityTrack(); }) { + if (track.pt() < internalOpts.maxPtGlobalTrack.value && track.pt() > internalOpts.minPtGlobalTrack.value && std::fabs(track.eta()) < 1.0f && track.isPVContributor() && track.isQualityTrack()) { + if (track.itsNCls() < internalOpts.minNclsITSGlobalTrack || track.itsNClsInnerBarrel() < internalOpts.minNclsITSibGlobalTrack) { + continue; + } + mults.multNbrContribsEta10GlobalTrackWoDCA++; + + if (std::abs(track.eta()) < 0.8) { + mults.multNbrContribsEta08GlobalTrackWoDCA++; + } + if (std::abs(track.eta()) < 0.5) { + mults.multNbrContribsEta05GlobalTrackWoDCA++; + } + } + if (std::fabs(track.eta()) < 0.8 && track.tpcNClsFound() >= 80 && track.tpcNClsCrossedRows() >= 100) { + if (track.isGlobalTrack()) { + mults.multGlobalTracks++; + } + } + } // end constexpr requires track selection stuff + } + + cursors.multsGlobal(mults.multGlobalTracks, mults.multNbrContribsEta08GlobalTrackWoDCA, mults.multNbrContribsEta10GlobalTrackWoDCA, mults.multNbrContribsEta05GlobalTrackWoDCA); + + if (!hVtxZNGlobalTracks || std::fabs(collision.posZ()) > 15.0f) { + mults.multGlobalTracksZeq = mults.multGlobalTracks; // if no equalization available, don't do it + } else { + mults.multGlobalTracksZeq = hVtxZNGlobalTracks->Interpolate(0.0) * mults.multGlobalTracks / hVtxZNGlobalTracks->Interpolate(collision.posZ()); + } + + // provide vertex-Z equalized Nglobals (or non-equalized if missing or beyond range) + if (internalOpts.mEnabledTables[kGlobalMultZeqs]) { + cursors.tableNGlobalZeqs(mults.multGlobalTracksZeq); + } + } + + // fill track counters at this stage if requested + if (internalOpts.mEnabledTables[kTPCMults]) { + cursors.tableTpc(mults.multTPC); + } + if (internalOpts.mEnabledTables[kPVMults]) { + cursors.tablePv(mults.multNContribs, mults.multNContribsEta1, mults.multNContribsEtaHalf); + } + if (internalOpts.mEnabledTables[kMultsExtra]) { + cursors.tableExtra(collision.numContrib(), collision.chi2(), collision.collisionTimeRes(), + bc.runNumber(), collision.posZ(), collision.sel8(), + mults.multHasITS, mults.multHasTPC, mults.multHasTOF, mults.multHasTRD, + mults.multITSOnly, mults.multTPCOnly, mults.multITSTPC, + mults.multAllTracksTPCOnly, mults.multAllTracksITSTPC, + collision.trackOccupancyInTimeRange(), + collision.ft0cOccupancyInTimeRange(), + collision.flags()); + } + if (internalOpts.mEnabledTables[kPVMultZeqs]) { + if (std::fabs(collision.posZ()) < 15.0f && lCalibLoaded) { + mults.multNContribsZeq = hVtxZNTracks->Interpolate(0.0) * mults.multNContribs / hVtxZNTracks->Interpolate(collision.posZ()); + } else { + mults.multNContribsZeq = 0.0f; + } + cursors.tablePVZeqs(mults.multNContribsZeq); + } + + // return multiplicity object such that it is handled properly when computing centrality + return mults; + } + + //__________________________________________________ + template + void collisionProcessMonteCarlo(TMCCollision const& mccollision, TMCParticles const& mcparticles, TPDGService const& pdg, TOutputGroup& cursors) + { + 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()) { + 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 + } + + if (std::abs(mcPart.eta()) < 1.0) { + multBarrelEta10++; + if (std::abs(mcPart.eta()) < 0.8) { + multBarrelEta08++; + if (std::abs(mcPart.eta()) < 0.5) { + multBarrelEta05++; + } + } + } + if (-3.3 < mcPart.eta() && mcPart.eta() < -2.1) + 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++; + } + cursors.tableExtraMc(multFT0A, multFT0C, multFV0A, multFDDA, multFDDC, multBarrelEta05, multBarrelEta08, multBarrelEta10, mccollision.posZ()); + } + + //__________________________________________________ + template + void collisionProcessMFT(TCollision const& collision, TMFTTracks const& mfttracks, TBestCollisionsFwd const& retracks, TMultBuffer& mults, TOutputGroup& cursors) + { + 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++; + } + } + cursors.mftMults(nAllTracks, nTracks); + mults[collision.globalIndex()].multMFTAllTracks = nAllTracks; + mults[collision.globalIndex()].multMFTTracks = nTracks; + + // vertex-Z equalized MFT + if (!hVtxZNMFTTracks || std::fabs(collision.posZ()) > 15.0f) { + mults[collision.globalIndex()].multMFTTracksZeq = mults[collision.globalIndex()].multMFTTracks; // if no equalization available, don't do it + } else { + mults[collision.globalIndex()].multMFTTracksZeq = hVtxZNMFTTracks->Interpolate(0.0) * mults[collision.globalIndex()].multMFTTracks / hVtxZNMFTTracks->Interpolate(collision.posZ()); + } + + // provide vertex-Z equalized Nglobals (or non-equalized if missing or beyond range) + if (internalOpts.mEnabledTables[kMFTMultZeqs]) { + cursors.tableNMFTZeqs(mults[collision.globalIndex()].multMFTTracksZeq); + } + } + + //__________________________________________________ + template + void ConfigureCentralityRun2(TCCDB& ccdb, TMetadata const& metadataInfo, TBC const& bc) + { + if (bc.runNumber() != mRunNumberCentrality) { + mRunNumberCentrality = bc.runNumber(); // mark that this run has been attempted already regardless of outcome + LOGF(info, "centrality loading procedure for timestamp=%llu, run number=%d", bc.timestamp(), bc.runNumber()); + TList* callst = nullptr; + // Check if the ccdb path is a root file + if (internalOpts.ccdbPathCentrality.value.find(".root") != std::string::npos) { + TFile f(internalOpts.ccdbPathCentrality.value.c_str(), "READ"); + f.GetObject(internalOpts.reconstructionPass.value.c_str(), callst); + if (!callst) { + f.ls(); + LOG(fatal) << "No calibration list " << internalOpts.reconstructionPass.value << " found."; + } + } else { + if (internalOpts.reconstructionPass.value == "") { + callst = ccdb->template getForRun(internalOpts.ccdbPathCentrality, bc.runNumber()); + } else if (internalOpts.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->template getSpecificForRun(internalOpts.ccdbPathCentrality, bc.runNumber(), metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = internalOpts.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", internalOpts.reconstructionPass.value); + callst = ccdb->template getSpecificForRun(internalOpts.ccdbPathCentrality, bc.runNumber(), metadata); + } + } + + Run2V0MInfo.mCalibrationStored = false; + Run2V0AInfo.mCalibrationStored = false; + Run2SPDTksInfo.mCalibrationStored = false; + Run2SPDClsInfo.mCalibrationStored = false; + Run2CL0Info.mCalibrationStored = false; + Run2CL1Info.mCalibrationStored = false; + 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; + }; + + if (internalOpts.mEnabledTables[kCentRun2V0Ms]) { + LOGF(debug, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); + 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", internalOpts.generatorName->c_str()).Data()); + if ((Run2V0MInfo.mhVtxAmpCorrV0A != nullptr) && (Run2V0MInfo.mhVtxAmpCorrV0C != nullptr) && (Run2V0MInfo.mhMultSelCalib != nullptr)) { + if (internalOpts.generatorName->length() != 0) { + if (Run2V0MInfo.mMCScale != nullptr) { + for (int ixpar = 0; ixpar < 6; ++ixpar) { + Run2V0MInfo.mMCScalePars[ixpar] = Run2V0MInfo.mMCScale->GetParameter(ixpar); + } + } else { + // 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 { + // 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 (internalOpts.mEnabledTables[kCentRun2V0As]) { + LOGF(debug, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); + Run2V0AInfo.mhVtxAmpCorrV0A = getccdb("hVtx_fAmplitude_V0A_Normalized"); + Run2V0AInfo.mhMultSelCalib = getccdb("hMultSelCalib_V0A"); + if ((Run2V0AInfo.mhVtxAmpCorrV0A != nullptr) && (Run2V0AInfo.mhMultSelCalib != nullptr)) { + Run2V0AInfo.mCalibrationStored = true; + } else { + // 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 (internalOpts.mEnabledTables[kCentRun2SPDTrks]) { + LOGF(debug, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); + Run2SPDTksInfo.mhVtxAmpCorr = getccdb("hVtx_fnTracklets_Normalized"); + Run2SPDTksInfo.mhMultSelCalib = getccdb("hMultSelCalib_SPDTracklets"); + if ((Run2SPDTksInfo.mhVtxAmpCorr != nullptr) && (Run2SPDTksInfo.mhMultSelCalib != nullptr)) { + Run2SPDTksInfo.mCalibrationStored = true; + } else { + // 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 (internalOpts.mEnabledTables[kCentRun2SPDClss]) { + LOGF(debug, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); + 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 { + // 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 (internalOpts.mEnabledTables[kCentRun2CL0s]) { + LOGF(debug, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); + Run2CL0Info.mhVtxAmpCorr = getccdb("hVtx_fnSPDClusters0_Normalized"); + Run2CL0Info.mhMultSelCalib = getccdb("hMultSelCalib_CL0"); + if ((Run2CL0Info.mhVtxAmpCorr != nullptr) && (Run2CL0Info.mhMultSelCalib != nullptr)) { + Run2CL0Info.mCalibrationStored = true; + } else { + // 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 (internalOpts.mEnabledTables[kCentRun2CL1s]) { + LOGF(debug, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); + Run2CL1Info.mhVtxAmpCorr = getccdb("hVtx_fnSPDClusters1_Normalized"); + Run2CL1Info.mhMultSelCalib = getccdb("hMultSelCalib_CL1"); + if ((Run2CL1Info.mhVtxAmpCorr != nullptr) && (Run2CL1Info.mhMultSelCalib != nullptr)) { + Run2CL1Info.mCalibrationStored = true; + } else { + // 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()); + } + } + } else { + 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()); + } + } + } + + //__________________________________________________ + template + void ConfigureCentralityRun3(TCCDB& ccdb, TMetadata const& metadataInfo, TBC const& bc) + { + if (bc.runNumber() != mRunNumberCentrality) { + mRunNumberCentrality = bc.runNumber(); // mark that this run has been attempted already regardless of outcome + LOGF(info, "centrality loading procedure for timestamp=%llu, run number=%d", bc.timestamp(), bc.runNumber()); + + // capture the need for PYTHIA calibration in Pb-Pb runs + if (metadataInfo.isMC() && mRunNumber >= 544013 && mRunNumber <= 545367) { + LOGF(info, "This is MC for Pb-Pb. Setting generatorName automatically to PYTHIA"); + internalOpts.generatorName.value = "PYTHIA"; + } + + // capture the need for PYTHIA calibration in light ion runs automatically + if (metadataInfo.isMC() && mRunNumber >= 564250 && mRunNumber <= 564472) { + LOGF(info, "This is MC for light ion runs. Setting generatorName automatically to PYTHIA"); + internalOpts.generatorName.value = "PYTHIA"; + } + + LOGF(info, "centrality loading procedure for timestamp=%llu, run number=%d", bc.timestamp(), bc.runNumber()); + TList* callst = nullptr; + // Check if the ccdb path is a root file + if (internalOpts.ccdbPathCentrality.value.find(".root") != std::string::npos) { + TFile f(internalOpts.ccdbPathCentrality.value.c_str(), "READ"); + f.GetObject(internalOpts.reconstructionPass.value.c_str(), callst); + if (!callst) { + f.ls(); + LOG(fatal) << "No calibration list " << internalOpts.reconstructionPass.value << " found."; + } + } else { + if (internalOpts.reconstructionPass.value == "") { + callst = ccdb->template getForRun(internalOpts.ccdbPathCentrality, bc.runNumber()); + } else if (internalOpts.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->template getSpecificForRun(internalOpts.ccdbPathCentrality, bc.runNumber(), metadata); + } else { + std::map metadata; + metadata["RecoPassName"] = internalOpts.reconstructionPass.value; + LOGF(info, "Loading CCDB for reconstruction pass (from provided argument): %s", internalOpts.reconstructionPass.value); + callst = ccdb->template getSpecificForRun(internalOpts.ccdbPathCentrality, bc.runNumber(), metadata); + } + } + + fv0aInfo.mCalibrationStored = false; + ft0mInfo.mCalibrationStored = false; + ft0aInfo.mCalibrationStored = false; + ft0cInfo.mCalibrationStored = false; + ft0cVariant1Info.mCalibrationStored = false; + ft0cVariant2Info.mCalibrationStored = false; + fddmInfo.mCalibrationStored = false; + ntpvInfo.mCalibrationStored = false; + nGlobalInfo.mCalibrationStored = false; + mftInfo.mCalibrationStored = false; + if (callst != nullptr) { + LOGF(info, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); + auto getccdb = [callst, bc](struct CalibrationInfo& estimator, const o2::framework::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) { + if (generatorName->length() != 0) { + LOGF(info, "Retrieving MC calibration for %d, generator name: %s", bc.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(), bc.runNumber()); + } + } + estimator.mCalibrationStored = true; + estimator.isSane(); + } else { + 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()); + } + }; + + // invoke loading only for requested centralities + if (internalOpts.mEnabledTables[kCentFV0As]) + getccdb(fv0aInfo, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentFT0Ms]) + getccdb(ft0mInfo, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentFT0As]) + getccdb(ft0aInfo, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentFT0Cs]) + getccdb(ft0cInfo, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentFT0CVariant1s]) + getccdb(ft0cVariant1Info, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentFT0CVariant2s]) + getccdb(ft0cVariant2Info, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentFDDMs]) + getccdb(fddmInfo, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentNTPVs]) + getccdb(ntpvInfo, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentNGlobals]) + getccdb(nGlobalInfo, internalOpts.generatorName); + if (internalOpts.mEnabledTables[kCentMFTs]) + getccdb(mftInfo, internalOpts.generatorName); + } else { + 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()); + } + } + } + + //__________________________________________________ + template + void generateCentralitiesRun3(TCCDB& ccdb, TMetadata const& metadataInfo, TBCs const& bcs, TMultBuffer const& mults, TOutputGroup& cursors) + { + // takes multiplicity buffer and generates the desirable centrality values (if any) + + // first step: did someone actually ask for it? Otherwise, go home + if ( + internalOpts.mEnabledTables[kCentFV0As] || internalOpts.mEnabledTables[kCentFT0Ms] || + internalOpts.mEnabledTables[kCentFT0As] || internalOpts.mEnabledTables[kCentFT0Cs] || + internalOpts.mEnabledTables[kCentFT0CVariant1s] || + internalOpts.mEnabledTables[kCentFT0CVariant2s] || + internalOpts.mEnabledTables[kCentFDDMs] || + internalOpts.mEnabledTables[kCentNTPVs] || internalOpts.mEnabledTables[kCentNGlobals] || + internalOpts.mEnabledTables[kCentMFTs] || internalOpts.mEnabledTables[kBCCentFT0Ms] || + internalOpts.mEnabledTables[kBCCentFT0As] || internalOpts.mEnabledTables[kBCCentFT0Cs]) { + // check and update centrality calibration objects for Run 3 + const auto& firstbc = bcs.begin(); + ConfigureCentralityRun3(ccdb, metadataInfo, firstbc); + + /************************************************************ + * @brief Populates a table with data based on the given calibration information and multiplicity. + * + * @param table The table to populate. + * @param estimator The calibration information. + * @param multiplicity The multiplicity value. + *************************************************************/ + + auto populateTable = [&](auto& table, struct CalibrationInfo& estimator, float multiplicity, bool isInelGt0) { + const bool assignOutOfRange = internalOpts.embedINELgtZEROselection && !isInelGt0; + auto scaleMC = [](float x, const float pars[6]) { + float core = ((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4]; + if (core < 0.0f) { + return 0.0f; // this should be marked as low multiplicity and not mapped, core^pars[5] would be NaN + } + 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); + table(percentile); + return percentile; + }; + + // populate centralities per event + for (size_t iEv = 0; iEv < mults.size(); iEv++) { + bool isInelGt0 = (mults[iEv].multNContribsEta1 > 0); + if (internalOpts.mEnabledTables[kCentFV0As]) + populateTable(cursors.centFV0A, fv0aInfo, mults[iEv].multFV0AZeq, isInelGt0); + if (internalOpts.mEnabledTables[kCentFT0Ms]) + populateTable(cursors.centFT0M, ft0mInfo, mults[iEv].multFT0AZeq + mults[iEv].multFT0CZeq, isInelGt0); + if (internalOpts.mEnabledTables[kCentFT0As]) + populateTable(cursors.centFT0A, ft0aInfo, mults[iEv].multFT0AZeq, isInelGt0); + if (internalOpts.mEnabledTables[kCentFT0Cs]) + populateTable(cursors.centFT0C, ft0cInfo, mults[iEv].multFT0CZeq, isInelGt0); + if (internalOpts.mEnabledTables[kCentFT0CVariant1s]) + populateTable(cursors.centFT0CVariant1, ft0cVariant1Info, mults[iEv].multFT0CZeq, isInelGt0); + if (internalOpts.mEnabledTables[kCentFT0CVariant2s]) + populateTable(cursors.centFT0CVariant2, ft0cVariant2Info, mults[iEv].multFT0CZeq, isInelGt0); + if (internalOpts.mEnabledTables[kCentFDDMs]) + populateTable(cursors.centFDDM, fddmInfo, mults[iEv].multFDDAZeq + mults[iEv].multFDDCZeq, isInelGt0); + if (internalOpts.mEnabledTables[kCentNTPVs]) + populateTable(cursors.centNTPV, ntpvInfo, mults[iEv].multNContribs, isInelGt0); + if (internalOpts.mEnabledTables[kCentNGlobals]) + populateTable(cursors.centNGlobals, nGlobalInfo, mults[iEv].multGlobalTracksZeq, isInelGt0); + if (internalOpts.mEnabledTables[kCentMFTs]) + populateTable(cursors.centMFTs, mftInfo, mults[iEv].multMFTTracksZeq, isInelGt0); + } + + // populate centralities per BC + for (size_t ibc = 0; ibc < static_cast(bcs.size()); ibc++) { + float bcMultFT0A = 0; + float bcMultFT0C = 0; + + const auto& bc = bcs.rawIteratorAt(ibc); + if (bc.has_foundFT0()) { + const auto& ft0 = bc.foundFT0(); + for (const auto& amplitude : ft0.amplitudeA()) { + bcMultFT0A += amplitude; + } + for (const auto& amplitude : ft0.amplitudeC()) { + bcMultFT0C += amplitude; + } + } else { + bcMultFT0A = -999.f; + bcMultFT0C = -999.f; + } + + if (internalOpts.mEnabledTables[kBCCentFT0Ms]) + populateTable(cursors.bcCentFT0M, ft0mInfo, bcMultFT0A + bcMultFT0C, true); + if (internalOpts.mEnabledTables[kBCCentFT0As]) + populateTable(cursors.bcCentFT0A, ft0aInfo, bcMultFT0A, true); + if (internalOpts.mEnabledTables[kBCCentFT0Cs]) + populateTable(cursors.bcCentFT0C, ft0cInfo, bcMultFT0C, true); + } + } + } + //__________________________________________________ + template + void generateCentralitiesRun2(TCCDB& ccdb, TMetadata const& metadataInfo, TBCs const& bcs, TMultBuffer const& mults, TOutputGroup& cursors) + { + // takes multiplicity buffer and generates the desirable centrality values (if any) + // For Run 2 + if ( + internalOpts.mEnabledTables[kCentRun2V0Ms] || internalOpts.mEnabledTables[kCentRun2V0As] || + internalOpts.mEnabledTables[kCentRun2SPDTrks] || internalOpts.mEnabledTables[kCentRun2SPDClss] || + internalOpts.mEnabledTables[kCentRun2CL0s] || internalOpts.mEnabledTables[kCentRun2CL1s]) { + // check and update centrality calibration objects for Run 3 + const auto& firstbc = bcs.begin(); + ConfigureCentralityRun2(ccdb, metadataInfo, firstbc); + + auto scaleMC = [](float x, const float pars[6]) { + float core = ((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4]; + if (core < 0.0f) { + return 0.0f; // this should be marked as low multiplicity and not mapped, core^pars[5] would be NaN + } + return std::pow(((pars[0] + pars[1] * std::pow(x, pars[2])) - pars[3]) / pars[4], 1.0f / pars[5]); + }; + + // populate centralities per event + for (size_t iEv = 0; iEv < mults.size(); iEv++) { + if (internalOpts.mEnabledTables[kCentRun2V0Ms]) { + float cV0M = 105.0f; + if (Run2V0MInfo.mCalibrationStored) { + float v0m; + if (Run2V0MInfo.mMCScale != nullptr) { + v0m = scaleMC(mults[iEv].multFV0A + mults[iEv].multFV0C, Run2V0MInfo.mMCScalePars); + LOGF(debug, "Unscaled v0m: %f, scaled v0m: %f", mults[iEv].multFV0A + mults[iEv].multFV0C, v0m); + } else { + v0m = mults[iEv].multFV0A * Run2V0MInfo.mhVtxAmpCorrV0A->GetBinContent(Run2V0MInfo.mhVtxAmpCorrV0A->FindFixBin(mults[iEv].posZ)) + + mults[iEv].multFV0C * Run2V0MInfo.mhVtxAmpCorrV0C->GetBinContent(Run2V0MInfo.mhVtxAmpCorrV0C->FindFixBin(mults[iEv].posZ)); + } + cV0M = Run2V0MInfo.mhMultSelCalib->GetBinContent(Run2V0MInfo.mhMultSelCalib->FindFixBin(v0m)); + } + LOGF(debug, "centRun2V0M=%.0f", cV0M); + // fill centrality columns + cursors.centRun2V0M(cV0M); + } + if (internalOpts.mEnabledTables[kCentRun2V0As]) { + float cV0A = 105.0f; + if (Run2V0AInfo.mCalibrationStored) { + float v0a = mults[iEv].multFV0A * Run2V0AInfo.mhVtxAmpCorrV0A->GetBinContent(Run2V0AInfo.mhVtxAmpCorrV0A->FindFixBin(mults[iEv].posZ)); + cV0A = Run2V0AInfo.mhMultSelCalib->GetBinContent(Run2V0AInfo.mhMultSelCalib->FindFixBin(v0a)); + } + LOGF(debug, "centRun2V0A=%.0f", cV0A); + // fill centrality columns + cursors.centRun2V0A(cV0A); + } + if (internalOpts.mEnabledTables[kCentRun2SPDTrks]) { + float cSPD = 105.0f; + if (Run2SPDTksInfo.mCalibrationStored) { + float spdm = mults[iEv].multTracklets * Run2SPDTksInfo.mhVtxAmpCorr->GetBinContent(Run2SPDTksInfo.mhVtxAmpCorr->FindFixBin(mults[iEv].posZ)); + cSPD = Run2SPDTksInfo.mhMultSelCalib->GetBinContent(Run2SPDTksInfo.mhMultSelCalib->FindFixBin(spdm)); + } + LOGF(debug, "centSPDTracklets=%.0f", cSPD); + cursors.centRun2SPDTracklets(cSPD); + } + if (internalOpts.mEnabledTables[kCentRun2SPDClss]) { + float cSPD = 105.0f; + if (Run2SPDClsInfo.mCalibrationStored) { + float spdm = mults[iEv].spdClustersL0 * Run2SPDClsInfo.mhVtxAmpCorrCL0->GetBinContent(Run2SPDClsInfo.mhVtxAmpCorrCL0->FindFixBin(mults[iEv].posZ)) + + mults[iEv].spdClustersL1 * Run2SPDClsInfo.mhVtxAmpCorrCL1->GetBinContent(Run2SPDClsInfo.mhVtxAmpCorrCL1->FindFixBin(mults[iEv].posZ)); + cSPD = Run2SPDClsInfo.mhMultSelCalib->GetBinContent(Run2SPDClsInfo.mhMultSelCalib->FindFixBin(spdm)); + } + LOGF(debug, "centSPDClusters=%.0f", cSPD); + cursors.centRun2SPDClusters(cSPD); + } + if (internalOpts.mEnabledTables[kCentRun2CL0s]) { + float cCL0 = 105.0f; + if (Run2CL0Info.mCalibrationStored) { + float cl0m = mults[iEv].spdClustersL0 * Run2CL0Info.mhVtxAmpCorr->GetBinContent(Run2CL0Info.mhVtxAmpCorr->FindFixBin(mults[iEv].posZ)); + cCL0 = Run2CL0Info.mhMultSelCalib->GetBinContent(Run2CL0Info.mhMultSelCalib->FindFixBin(cl0m)); + } + LOGF(debug, "centCL0=%.0f", cCL0); + cursors.centRun2CL0(cCL0); + } + if (internalOpts.mEnabledTables[kCentRun2CL1s]) { + float cCL1 = 105.0f; + if (Run2CL1Info.mCalibrationStored) { + float cl1m = mults[iEv].spdClustersL1 * Run2CL1Info.mhVtxAmpCorr->GetBinContent(Run2CL1Info.mhVtxAmpCorr->FindFixBin(mults[iEv].posZ)); + cCL1 = Run2CL1Info.mhMultSelCalib->GetBinContent(Run2CL1Info.mhMultSelCalib->FindFixBin(cl1m)); + } + LOGF(debug, "centCL1=%.0f", cCL1); + cursors.centRun2CL1(cCL1); + } + } + } + } +}; // end BuilderModule + +} // namespace multiplicity +} // namespace common +} // namespace o2 + +#endif // COMMON_TOOLS_MULTIPLICITY_MULTMODULE_H_ diff --git a/Common/Tools/Multiplicity/README.md b/Common/Tools/Multiplicity/README.md new file mode 100644 index 00000000000..c38f81a4f6e --- /dev/null +++ b/Common/Tools/Multiplicity/README.md @@ -0,0 +1,17 @@ +# Multiplicity/centrality tools in O2/O2Physics + +This directory serves to aggregate all files necessary for multiplicity +and centrality calibration going from pp to Pb-Pb. It offers functionality +to perform simple slicing in percentiles, such as what is done in +proton-proton collisions, as well as the Glauber + analytical NBD fitter +used to perform anchoring and hadronic event distribution estimates in +nucleus-nucleus collisions. + +## Files +* `README.md` this readme +* `CMakeLists.txt` definition of source files that need compiling +* `multCalibrator.cxx/h` a class to do percentile slicing of a given histogram. Used for all systems. +* `multMCCalibrator.cxx/h` a class to perform data-to-mc matching of average Nch. +* `multGlauberNBDFitter.cxx/h` a class to do glauber fits. +* `multModule.h` a class to perform calculations of multiplicity and centrality tables for analysis. Meant to be used inside the main core service wagon 'multcenttable'. + diff --git a/Common/Tools/Multiplicity/macros/README.md b/Common/Tools/Multiplicity/macros/README.md new file mode 100644 index 00000000000..1044342cd8b --- /dev/null +++ b/Common/Tools/Multiplicity/macros/README.md @@ -0,0 +1,69 @@ +# Example multiplicity calibration macros + +You will find some example macros in this directory that will allow for the calculation of a glauber fit and the corresponding calibration histograms. + +A simplified description of the procedure necessary to generate a +Glauber + NBD fit to a certain histogram is described below. + +## Performing a Glauber + NBD fit + +### First step: calculation of Glauber MC sample + +The Glauber + NBD model assumes that the multiplicity / amplitude +distribution that one intends to fit can be described as coming +from a certain number N_{ancestor} of particle-emitting sources called 'ancestors'. Each ancestor is assumed to produce particles +according to a negative binominal distribution. Further, +the number of ancestors is assumed to be related to the basic +glauber quantities N_{part} and N_{coll} via the formula: + +N_{ancestor} = f * N_{part} + (1-f) N_{coll} + +Usually, the value f is fixed at 0.8, and thus the range of +N_{ancestors} is typically 0-700 in Pb-Pb collisions. + +In order to allow for Glauber + NBD fitting, the correlation of +(N_{part}, N_{coll}) needs to be known. For that purpose, +a tree of Glauber MC needs to be generated using TGlauberMC using the relevant nuclei, which also involves choosing an appropriate nuclear profile. + +Once TGlauberMC has been used to produce a tree with N_{part} and +N_{coll} values, their correlation needs to be saved to a 2D histogram that serves as input to the Glauber + NBD fitter used in +O2/O2Physics. This is done using the macro called `saveCorrelation.C` contained in this directory, which produces a file named `baseHistos.root`. The file `saveCorrelation.C` serves as +an example for the Pb-Pb case and minor adaptation may be needed +in case other nuclei are to be used. + +### Second step: execution of Glauber + NBD fitter + +The fitting procedure is done via the macro ``. Because +the numerical fitting utilizes a convolution of a N_{ancestor} +distribution and NBD distributions, it will not be as fast +as typical one-dimensional fits: typical times of 10-100 seconds +are not unusual. The macro will produce an output file +that contains: + +* the original fitted histogram +* the actual glauber fit distribution, plotted all the way +to zero multiplicity + +This output can then be used to extract percentiles. + +### Third step: calculation of percentile boundaries + +Once both the data and glauber fit distributions are known, +the next step is to create a 'stitched' data/glauber distribution in +which the distribution at low multiplicities follows +the glauber fit and the distribution at higher multiplicities +follows the data. The multiplicity value in which the switch from +glauber to data takes place is called 'anchor point'. + +Because of the fact that this 'stitching' procedure may need to be tuned and the actual glauber fit is slow, the stitching is done +in a separate macro called `runCalibration.C`. It is provided +in this directory as well and it is the third and last step in calculating percentile boundaries. The macro will printout some +key boundaries as well as save an output file with the calibration. + +*Bonus*: at the stage in which the glauber fit has been done +and all information is available, a de-convolution process +can be used to calculate the average N_{part} and N_{coll} +in centrality slices. This functionality is also provided +in O2Physics as part of the `multGlauberNBDFitter` and the +`runCalibration.C` macro can optionally also perform that +deconvolution. *Warning*: this procedure might take a mooment. \ No newline at end of file diff --git a/Common/Tools/Multiplicity/macros/runCalibration.C b/Common/Tools/Multiplicity/macros/runCalibration.C new file mode 100644 index 00000000000..7a5e76c12d0 --- /dev/null +++ b/Common/Tools/Multiplicity/macros/runCalibration.C @@ -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. +// +/// \file saveCorrelation.C +/// \brief +/// \author ALICE + +#include + +/// @brief function to calibrate centrality +/// @param lInputFileName name of input file. +/// @param anchorPointPercentage anchor point percentage to use +/// @param matchRange width of region in which data/glauber matching is to be done in rolling anchoring test +/// @param doNpartNcoll wether or not to attempt calculating Npart, Ncoll in centrality bins +void runCalibration(TString lInputFileName = "results/AR_544122_glauberNBD_ancestorMode2_hFT0C_BCs.root", double anchorPointPercentage = 90.0, double matchRange = 200.0, bool doNpartNcoll = false) +{ + TFile* file = new TFile(lInputFileName.Data(), "READ"); + file->ls(); + + TH1F* hData = (TH1F*)file->Get("hV0MUltraFine"); + TH1F* hGlauberParameters = (TH1F*)file->Get("hGlauberParameters"); + TH1F* hGlauberFitRange = (TH1F*)file->Get("hGlauberFitRange"); + hData->SetName("hData"); + TH1F* hStitched = (TH1F*)hData->Clone("hStitched"); + TH1F* hFit = (TH1F*)file->Get("hGlauber"); + + TCanvas* c1 = new TCanvas("c1", "", 800, 600); + c1->SetLeftMargin(0.17); + c1->SetBottomMargin(0.17); + c1->SetRightMargin(0.15); + c1->SetTopMargin(0.05); + c1->SetTicks(1, 1); + c1->SetLogz(); + c1->SetFrameFillStyle(0); + c1->SetFillStyle(0); + + cout << "Data bin width: " << hData->GetBinWidth(1) << endl; + cout << "Fit bin width: " << hFit->GetBinWidth(1) << endl; + cout << "Match range to use: " << matchRange << endl; + + //____________________________________________ + double anchorPointFraction = anchorPointPercentage / 100.f; + double anchorPoint = -1; // the anchor point value in raw + + //____________________________________________ + // doing partial integration up to certain point for finding anchor point bin + for (int ii = 1; ii < hData->GetNbinsX() + 1; ii++) { + // renormalize data curve + int bin1 = ii + 1; + int bin2 = hData->FindBin(hData->GetBinLowEdge(ii + 1) + matchRange + 1e-3); + double matchRangeData = hData->Integral(bin1, bin2); + double matchRangeFit = hFit->Integral(bin1, bin2); + + // rescale fit to match in the vicinity of the region we're at + hFit->Scale(matchRangeData / matchRangeFit); + + double integralFit = hFit->Integral(1, ii); + double integralData = hData->Integral(ii + 1, hData->GetNbinsX() + 1); + double integralAll = integralFit + integralData; + + cout << "at bin #" << ii << ", integrated up to " << hData->GetBinLowEdge(ii + 1) << " fraction above this value is: " << integralData / integralAll << endl; + anchorPoint = hData->GetBinLowEdge(ii + 1); + + if (integralData / integralAll < anchorPointFraction) + break; + } + + //____________________________________________ + for (int ii = 1; ii < hData->GetNbinsX() + 1; ii++) { + // renormalize data curve + if (hData->GetBinCenter(ii) < anchorPoint) + hStitched->SetBinContent(ii, hFit->GetBinContent(ii)); + } + + cout << "Anchor point determined to be: " << anchorPoint << endl; + cout << "Preparing stitched histogram ... " << endl; + + hFit->SetLineColor(kRed); + hStitched->SetLineColor(kBlue); + + hData->GetYaxis()->SetTitleSize(0.055); + hData->GetXaxis()->SetTitleSize(0.055); + hData->GetYaxis()->SetLabelSize(0.04); + hData->GetXaxis()->SetLabelSize(0.04); + hData->SetTitle(""); + hData->Draw("hist"); + hFit->Draw("hist same"); + hStitched->Draw("hist same"); + + // All fine, let's try the calibrator + multCalibrator* lCalib = new multCalibrator("lCalib"); + lCalib->SetAnchorPointPercentage(100.0f); + lCalib->SetAnchorPointRaw(-1e-6); + + // Set standard Pb-Pb boundaries + lCalib->SetStandardOnePercentBoundaries(); + + TString calibFileName = lInputFileName.Data(); + calibFileName.ReplaceAll("glauberNBD", "calibration"); + TFile* fileCalib = new TFile(calibFileName.Data(), "RECREATE"); + + TH1F* hCalib = lCalib->GetCalibrationHistogram(hStitched, "hCalib"); + + TCanvas* c2 = new TCanvas("c2", "", 800, 600); + c2->SetLeftMargin(0.17); + c2->SetBottomMargin(0.17); + c2->SetRightMargin(0.15); + c2->SetTopMargin(0.05); + c2->SetTicks(1, 1); + // c2->SetLogz(); + c2->SetFrameFillStyle(0); + c2->SetFillStyle(0); + + hCalib->GetYaxis()->SetTitleSize(0.055); + hCalib->GetXaxis()->SetTitleSize(0.055); + hCalib->GetYaxis()->SetLabelSize(0.04); + hCalib->GetXaxis()->SetLabelSize(0.04); + hCalib->SetTitle(""); + hCalib->Draw(); + + fileCalib->cd(); + + hData->Write(); + hCalib->Write(); + hStitched->Write(); + hFit->Write(); + + if (doNpartNcoll) { + cout << "Will now attempt to calculate % -> Np, Nc map..." << endl; + + TProfile* hProfileNpart = new TProfile("hProfileNpart", "", 100, 0, 100); + TProfile* hProfileNcoll = new TProfile("hProfileNcoll", "", 100, 0, 100); + TH2F* h2dNpart = new TH2F("h2dNpart", "", 100, 0, 100, 500, -0.5f, 499.5f); + TH2F* h2dNcoll = new TH2F("h2dNcoll", "", 100, 0, 100, 3000, -0.5f, 2999.5); + + // Replay + multGlauberNBDFitter* g = new multGlauberNBDFitter("lglau"); + TF1* fitfunc = g->GetGlauberNBD(); + + // Step 1: open the (Npart, Ncoll) pair information, provide + TFile* fbasefile = new TFile("basehistos.root", "READ"); + TH2D* hNpNc = (TH2D*)fbasefile->Get("hNpNc"); + g->SetNpartNcollCorrelation(hNpNc); + g->InitializeNpNc(); + + fitfunc->SetParameter(0, hGlauberParameters->GetBinContent(1)); + fitfunc->SetParameter(1, hGlauberParameters->GetBinContent(2)); + fitfunc->SetParameter(2, hGlauberParameters->GetBinContent(3)); + fitfunc->SetParameter(3, hGlauberParameters->GetBinContent(4)); + fitfunc->SetParameter(4, hGlauberParameters->GetBinContent(5)); + + Double_t lMax = hData->GetBinLowEdge(hData->GetNbinsX() + 1); + + // uncomment if Np Nc needed -> Warning, slow! + g->CalculateAvNpNc(hProfileNpart, hProfileNcoll, h2dNpart, h2dNcoll, hCalib, 0, lMax); + + hProfileNpart->Write(); + hProfileNcoll->Write(); + h2dNpart->Write(); + h2dNcoll->Write(); + } + + fileCalib->Write(); +} diff --git a/Common/Tools/Multiplicity/macros/runGlauberFit.C b/Common/Tools/Multiplicity/macros/runGlauberFit.C new file mode 100755 index 00000000000..fe33c209308 --- /dev/null +++ b/Common/Tools/Multiplicity/macros/runGlauberFit.C @@ -0,0 +1,386 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file saveCorrelation.C +/// \brief +/// \author ALICE + +#include "multCalibrator.h" +#include "multGlauberNBDFitter.h" + +#include "TCanvas.h" +#include "TDirectory.h" +#include "TF1.h" +#include "TFile.h" +#include "TGraph.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TLatex.h" +#include "TLegend.h" +#include "TLine.h" +#include "TStopwatch.h" +#include "TStyle.h" +#include "TSystem.h" +#include "TTree.h" + +#include + +//________________________________________________________________ +Double_t FastIntegrate(TF1* f1, Double_t a, Double_t b, Int_t n = 5) +{ + // Do fast integration with N sampling points + const Int_t nc = n; + Double_t x[nc], y[nc]; + Double_t lWidth = (b - a) / ((double)(n - 1)); + for (Int_t ii = 0; ii < n; ii++) { + x[ii] = a + ((double)(ii)) * lWidth; + y[ii] = f1->Eval(x[ii]); + } + // Now go via trapezoids, please (this probably has a name) + Double_t lIntegral = 0; + for (Int_t ii = 0; ii < n - 1; ii++) { + lIntegral += 0.5 * lWidth * (y[ii] + y[ii + 1]); + } + return lIntegral / (b - a); +} + +Double_t GetBoundaryForPercentile(TH1* histo, Double_t lPercentileRequested) +{ + // This function returns the boundary for a specific percentile. + Double_t lReturnValue = 0.0; + Double_t lPercentile = 100.0 - lPercentileRequested; + + const Long_t lNBins = histo->GetNbinsX(); + Double_t lCountDesired = lPercentile * histo->GetEntries() / 100; + Long_t lCount = 0; + for (Long_t ibin = 1; ibin < lNBins; ibin++) { + lCount += histo->GetBinContent(ibin); + if (lCount >= lCountDesired) { + // Found bin I am looking for! + Double_t lWidth = histo->GetBinWidth(ibin); + Double_t lLeftPercentile = 100. * (lCount - histo->GetBinContent(ibin)) / histo->GetEntries(); + Double_t lRightPercentile = 100. * lCount / histo->GetEntries(); + + Double_t lProportion = (lPercentile - lLeftPercentile) / (lRightPercentile - lLeftPercentile); + + lReturnValue = histo->GetBinLowEdge(ibin) + lProportion * lWidth; + break; + } + } + return lReturnValue; +} + +/// @brief master glauber fit function +/// @param lInputFileName input file name (from the grid, typically centrality-studies task) +/// @param histogramName histogram name: histogram to use within the input file +/// @param ancestorMode ancestor mode: 0: truncation, 1: rounding, 2: effective / non-integer (default: 2) +/// @param lFreek free k: keep k value free (default Pb-Pb: fixed at 1.5) +/// @param use_dMu_dNanc use dMu/dNanc: allow for a varying production of Nch vs ancestor if Nancestor is large. Models detector saturation in effective manner. +/// @param lFreef free f: keep f value free (default Pb-Pb: fixed at 0.8) +/// @param lfvalue f value: the value to use for fixed f +/// @param outputFile name of output file +int runGlauberFit(TString lInputFileName = "AnalysisResultsLHC24ar.root", TString histogramName = "hFT0C_BCs", int ancestorMode = 2, Bool_t lFreek = kFALSE, Bool_t use_dMu_dNanc = kFALSE, Bool_t lFreef = kFALSE, Float_t lfvalue = 0.800, TString outputFile = "output.root") +{ + gStyle->SetLineScalePS(1); + gStyle->SetOptStat(0); + + cout << "Starting!" << endl; + TFile* file = new TFile(lInputFileName.Data(), "READ"); + if (!file) + cout << "Problem with file!" << endl; + TH1F* hV0Mfine = 0x0; + + hV0Mfine = (TH1F*)file->Get(Form("centrality-study/%s", histogramName.Data())); + + // disregard bin zero + cout << "Received bin zero content: " << hV0Mfine->GetBinContent(0) << ", will set to zero..." << endl; + hV0Mfine->SetBinContent(0, 0); + + if (!hV0Mfine) + cout << "Problem with histogram!" << endl; + + cout << "Input histogram has been received successfully! Information: " << endl; + + cout << "Counts: " << hV0Mfine->GetEntries() << endl; + cout << "NbinsX: " << hV0Mfine->GetNbinsX() << endl; + cout << "MaxX: " << hV0Mfine->GetBinLowEdge(hV0Mfine->GetNbinsX() + 1) << endl; + + cout << "Creating output file..." << endl; + TString lProcessedFileName = lInputFileName.Data(); + TString lkMode = "fixedK"; + if (lFreek) + lkMode = "freeK"; + TString lSaturationMode = "fixedMu"; + if (use_dMu_dNanc) + lSaturationMode = "freeMu"; + + TFile* fOutput = new TFile(outputFile.Data(), "RECREATE"); + + TH1F* hV0M = (TH1F*)hV0Mfine->Clone("hV0M"); + TH1F* hV0MUltraFine = (TH1F*)hV0Mfine->Clone("hV0MUltraFine"); + hV0M->SetName("hV0M"); + hV0M->SetTitle(""); + + //____________________________________________ + // maximum fit range estimate (avoid tails) + // may need adjusting + Double_t lFitRangeMax = GetBoundaryForPercentile(hV0Mfine, 0.008); + cout << "Fit range max estimated from histogram: " << lFitRangeMax << endl; + + // minimum fit range estimate (guess region that may be unfittable) + // may need adjusting + Double_t maxPercent = 0.01; + Double_t fractionOfMax = 0.012; + Double_t lFitRange = fractionOfMax * GetBoundaryForPercentile(hV0Mfine, maxPercent); + + // adjust if low mult (Ntracks, typically) + Double_t maxRangeForTracks = 10000; + Double_t fractionOfMaxBroader = 0.02; + if (lFitRangeMax < maxRangeForTracks) + lFitRange = fractionOfMaxBroader * GetBoundaryForPercentile(hV0Mfine, maxPercent); + + cout << "Fit range min estimated from histogram: " << lFitRange << endl; + + //____________________________________________ + // rebinning matters + int rebinFactor = 20; + if (lFitRangeMax < maxRangeForTracks) + rebinFactor = 1; + + cout << "Creating rebinned histogram with rebin factor: " << rebinFactor << endl; + hV0M->Rebin(rebinFactor); + + //____________________________________________ + // simple plots for inspection + TCanvas* c1 = new TCanvas("c1", "", 1300, 900); + c1->SetFrameFillStyle(0); + c1->SetFillStyle(0); + c1->Divide(1, 2); + c1->cd(1)->SetFrameFillStyle(0); + c1->cd(1)->SetFillStyle(0); + c1->cd(2)->SetFrameFillStyle(0); + c1->cd(2)->SetFillStyle(0); + + c1->cd(1); + c1->cd(1)->SetLogy(); + c1->cd(1)->SetTicks(1, 1); + c1->cd(1)->SetPad(0, 0.5, 1, 1); + c1->cd(2)->SetPad(0, 0.0, 1, .5); + + c1->cd(1)->SetBottomMargin(0.001); + c1->cd(1)->SetRightMargin(0.25); + c1->cd(1)->SetTopMargin(0.02); + c1->cd(1)->SetLeftMargin(0.07); + + c1->cd(2)->SetBottomMargin(0.14); + c1->cd(2)->SetRightMargin(0.25); + c1->cd(2)->SetTopMargin(0.001); + c1->cd(2)->SetLeftMargin(0.07); + c1->cd(2)->SetTicks(1, 1); + c1->cd(1); + + hV0M->GetXaxis()->SetRangeUser(0, lFitRangeMax); + hV0M->GetYaxis()->SetRangeUser(0.25, hV0M->GetMaximum() * 3); + hV0M->SetLineColor(kBlack); + hV0M->SetMarkerStyle(20); + hV0M->SetMarkerColor(kBlack); + hV0M->SetMarkerSize(0.5); + hV0M->GetYaxis()->SetTitleSize(0.07); + hV0M->GetYaxis()->SetLabelSize(0.05); + hV0M->GetYaxis()->SetTitle("Count"); + hV0M->GetYaxis()->SetTitleOffset(0.5); + hV0M->GetXaxis()->SetLabelSize(0.05); + hV0M->GetXaxis()->SetTitleSize(0.06); + hV0M->GetXaxis()->SetTitle("FT0A+C Amplitude"); + hV0M->GetYaxis()->SetTickLength(0.015); + hV0M->SetStats(0); + hV0M->Draw("E"); + + // Stand back! Imma gonna do GLAUBER FITTIN' + multGlauberNBDFitter* g = new multGlauberNBDFitter("lglau"); + g->SetAncestorMode(ancestorMode); + + // Step 1: open the (Npart, Ncoll) pair information, provide + TFile* fbasefile = new TFile("basehistos.root", "READ"); + TH2D* hNpNc = (TH2D*)fbasefile->Get("hNpNc"); + // return to proper scope + fOutput->cd(); + g->SetNpartNcollCorrelation(hNpNc); + g->SetInputV0M(hV0M); + g->SetFitRange(lFitRange, lFitRangeMax); + // Step 3: go for it ... + g->SetNorm(1.53527e+08); + TString lString = "REM0"; + g->SetFitOptions(lString.Data()); + g->SetFitNpx(100000); + + TF1* fitfunc = g->GetGlauberNBD(); + + //____________________________________________ + // + // set initial fit parameters here + // may require manual tuning depending on data! + + Double_t guessedMu = lFitRangeMax / 53968.4 * 0.175 * 3.53971e+02; + cout << "Guessed GlauberNBD mu value: " << guessedMu << endl; + + fitfunc->SetParameter(0, guessedMu); // mu value + fitfunc->SetParLimits(0, 0.25 * guessedMu, guessedMu * 2); + + if (!lFreek) { + fitfunc->FixParameter(1, 1.5); // k value + } else { + fitfunc->SetParLimits(1, 0.01, 35); + fitfunc->SetParameter(1, 1.5); + } + if (!lFreef) { + fitfunc->FixParameter(2, lfvalue); // f value + } else { + fitfunc->SetParLimits(2, 0.55, 0.97); + fitfunc->SetParameter(2, 0.800); + } + fitfunc->SetParLimits(3, 0.1e+5, 800e+10); // normalization + fitfunc->SetParameter(3, 0.80832e+08); + + // dMu/dNanc + fitfunc->SetParameter(4, 0); + if (!use_dMu_dNanc) { + fitfunc->FixParameter(4, 0); + } + + // fitfunc->SetParameter(4,-1.15443e-01); + // fitfunc->SetParameter(4,-4.55957e-02); + + // dk/dNanc + fitfunc->FixParameter(5, 0); + // fitfunc->SetParameter(5,1.63590e-03); + + // d2Mu/dNanc2 + fitfunc->FixParameter(6, 0.0); + // fitfunc->SetParameter(6,4.02271e-05); + + fitfunc->FixParameter(7, 0.0); + // fitfunc->SetParameter(7,-1.24349e-06); + + //____________________________________________ + // handle internals for fitting: needs to + // be done before the fit is attempted! + g->InitializeNpNc(); + g->InitAncestor(); + + cout << "WILL NOW ATTEMPT GLAUBER FIT" << endl; + cout << "This will take a while. Please wait..." << endl; + Int_t lFitStatus = 0; + lFitStatus = g->DoFit(); + Int_t lAttempts = 1; + Int_t lMaxAttempts = 10; + while (lAttempts < lMaxAttempts && lFitStatus == 0) { + // insist on fitting until it works + cout << "Attempting fit again (" << lAttempts << " attempt)..." << endl; + lFitStatus = g->DoFit(); + } + cout << "Final fit status: " << lFitStatus << endl; + + gStyle->SetOptStat(0); + // Do a ratio plot + TH1D* hGlauber = (TH1D*)hV0MUltraFine->Clone("hGlauber"); + TH1D* hRatio = (TH1D*)hV0MUltraFine->Clone("hRatio"); + hGlauber->Reset(); + + c1->cd(1); + fitfunc->SetLineColor(kRed); + fitfunc->SetLineWidth(2); + fitfunc->Draw("same"); + + cout << "Calculating glauber function histogram with the same binning as data input... please wait..." << endl; + for (Int_t ii = 1; ii < hGlauber->GetNbinsX() + 1; ii++) { + Double_t lFuncVal = FastIntegrate(fitfunc, hGlauber->GetBinLowEdge(ii), hGlauber->GetBinLowEdge(ii + 1), 4); + hGlauber->SetBinContent(ii, lFuncVal); + Int_t printEveryThisManyBins = 500; + if (ii % printEveryThisManyBins == 0) { + cout << "At integration #" << ii << "/" << hGlauber->GetNbinsX() + 1 << "..." << endl; + } + } + cout << "Glauber function evaluated. Should go quickly now." << endl; + + c1->cd(2); + Float_t lLoRangeRatio = 0.35; + Float_t lHiRangeRatio = 1.65; + hRatio->Divide(hGlauber); + hRatio->GetYaxis()->SetTitle("Data/Fit"); + hRatio->GetXaxis()->SetTitle("FT0C amplitude"); + hRatio->GetYaxis()->SetTitleSize(0.055); + hRatio->GetYaxis()->SetTitleOffset(0.7); + hRatio->GetXaxis()->SetTitleSize(0.055); + hRatio->GetYaxis()->SetLabelSize(0.045); + hRatio->GetXaxis()->SetLabelSize(0.045); + hRatio->GetYaxis()->SetRangeUser(lLoRangeRatio, lHiRangeRatio); + hRatio->GetXaxis()->SetRangeUser(0, lFitRangeMax); + hRatio->SetMarkerStyle(20); + hRatio->SetMarkerColor(kGray + 2); + hRatio->SetLineColor(kGray + 2); + // hRatio->SetMarkerSize(1.0); + hRatio->SetMarkerSize(.7); + hRatio->SetStats(0); + // hRatioWide->SetStats(0); + + hRatio->Draw("hist"); + + TLine* line = new TLine(0, 1, lFitRangeMax, 1); + line->SetLineStyle(7); + line->SetLineColor(kGray + 1); + line->Draw(); + + TLine* lFitRangeLine = new TLine(lFitRange, lLoRangeRatio, lFitRange, 0.9); + lFitRangeLine->SetLineColor(kBlue); + lFitRangeLine->SetLineWidth(1); + lFitRangeLine->SetLineStyle(2); + lFitRangeLine->Draw(); + + TH1D* hRatioGrayed = (TH1D*)hRatio->Clone("hRatioGrayed"); + hRatioGrayed->SetMarkerColor(kGray + 2); + hRatioGrayed->SetLineColor(kGray + 2); + hRatioGrayed->Draw("same"); + + hRatio->SetLineWidth(1); + hRatio->Draw("same hist"); + // hRatioWide->Draw("same"); + + c1->cd(1); + TLatex* lat = new TLatex(); + lat->SetNDC(); + Float_t lPosText = 0.76; + Float_t lYShift = 0.25; + lat->SetTextSize(0.042); + + // save the glauber parameters explicitly + TH1D* hGlauberParameters = new TH1D("hGlauberParameters", "", 10, 0, 10); + TH1D* hGlauberFitRange = new TH1D("hGlauberFitRange", "", 10, 0, 10); + + // fitfunc + hGlauberParameters->SetBinContent(1, fitfunc->GetParameter(0)); + hGlauberParameters->SetBinContent(2, fitfunc->GetParameter(1)); + hGlauberParameters->SetBinContent(3, fitfunc->GetParameter(2)); + hGlauberParameters->SetBinContent(4, fitfunc->GetParameter(3)); + hGlauberParameters->SetBinContent(5, fitfunc->GetParameter(4)); + hGlauberParameters->Write(); + + Double_t lLoRangeGlauber, lHiRangeGlauber; + fitfunc->GetRange(lLoRangeGlauber, lHiRangeGlauber); + hGlauberFitRange->SetBinContent(1, lLoRangeGlauber); + hGlauberFitRange->SetBinContent(2, lHiRangeGlauber); + hGlauberFitRange->Write(); + + hRatio->Write(); + fOutput->Write(); + + return 0; +} diff --git a/Common/Tools/Multiplicity/macros/saveCorrelation.C b/Common/Tools/Multiplicity/macros/saveCorrelation.C new file mode 100644 index 00000000000..b23415639ba --- /dev/null +++ b/Common/Tools/Multiplicity/macros/saveCorrelation.C @@ -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. +// +/// \file saveCorrelation.C +/// \brief This file provides a simple macro to convert TGlauberMC output tuples +/// into the 2D correlation histogram necessary for the ALICE machinery +/// that performs Glauber + NBD fits. +/// \author ALICE + +#include + +/// @brief function to save Npart x Ncoll correlation to file for glauber fits +/// @param filename input TGlauberMC ntuple file +/// @param outputFile output file for Npart x Ncoll correlation TH2D +void saveCorrelation(TString filename = "gmc-PbPb-snn68.21-md0.40-nd-1.0-rc1-smax99.0.root", TString outputFile = "basehistos.root") +{ + TFile* fin = new TFile(filename.Data(), "READ"); + TNtuple* ntup = (TNtuple*)fin->Get("nt_Pb_Pb"); + + // try other Pb nuclear profiles in case "Pb" - "Pb" not found + if (!ntup) { + ntup = (TNtuple*)fin->Get("nt_Pbpn_Pbpn"); + } + if (!ntup) { + ntup = (TNtuple*)fin->Get("nt_PbpnVar1_PbpnVar1"); + } + if (!ntup) { + ntup = (TNtuple*)fin->Get("nt_PbpnVar2_PbpnVar2"); + } + if (!ntup) { + ntup = (TNtuple*)fin->Get("nt_PbpnVar3_PbpnVar3"); + } + if (!ntup) { + ntup = (TNtuple*)fin->Get("nt_PbpnVar4_PbpnVar4"); + } + + if (!ntup) { + cout << "No tree found!" << endl; + return; + } + + cout << "Glauber tree entries: " << ntup->GetEntries() << endl; + + TFile* fout = new TFile(outputFile.Data(), "RECREATE"); + + // 2D correlation plot necessary for Glauber + NBD fitting + // The provided range should be enough for Pb-Pb + TH2D* hNpNc = new TH2D("hNpNc", "", 500, -0.5, 499.5, 2500, -0.5, 2499.5); + + // let's draw this on screen for inspection + TCanvas* c1 = new TCanvas("c1", "", 800, 600); + c1->SetTicks(1, 1); + c1->SetLogz(); + ntup->Draw("Ncoll:Npart>>hNpNc", "", "colz"); + fout->Write(); +} diff --git a/Common/Tools/Multiplicity/multCalibrator.cxx b/Common/Tools/Multiplicity/multCalibrator.cxx index e9931c0389f..e54a3d5a0aa 100644 --- a/Common/Tools/Multiplicity/multCalibrator.cxx +++ b/Common/Tools/Multiplicity/multCalibrator.cxx @@ -16,17 +16,21 @@ // - victor.gonzalez@cern.ch // - david.dobrigkeit.chinellato@cern.ch // -#include "TList.h" -#include "TDirectory.h" -#include "TFile.h" -#include "TH1F.h" -#include "TH1D.h" -#include "TProfile.h" -#include "TStopwatch.h" -#include "TArrayL64.h" -#include "TArrayF.h" #include "multCalibrator.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include // FIXME + using namespace std; const TString multCalibrator::fCentEstimName[kNCentEstim] = { @@ -100,10 +104,10 @@ Bool_t multCalibrator::Calibrate() return kFALSE; } - //Step 1: verify if input file contains desired histograms + // Step 1: verify if input file contains desired histograms TH1D* hRaw[kNCentEstim]; for (Int_t iv = 0; iv < kNCentEstim; iv++) { - hRaw[iv] = (TH1D*)fileInput->Get(Form("multiplicity-qa/multiplicityQa/h%s", fCentEstimName[iv].Data())); + hRaw[iv] = reinterpret_cast(fileInput->Get(Form("multiplicity-qa/multiplicityQa/h%s", fCentEstimName[iv].Data()))); if (!hRaw[iv]) { cout << Form("File does not contain histogram h%s, which is necessary for calibration!", fCentEstimName[iv].Data()) << endl; return kFALSE; @@ -112,7 +116,7 @@ Bool_t multCalibrator::Calibrate() cout << "Histograms loaded! Will now calibrate..." << endl; - //Create output file + // Create output file TFile* fOut = new TFile(fOutputFileName.Data(), "RECREATE"); TH1F* hCalib[kNCentEstim]; for (Int_t iv = 0; iv < kNCentEstim; iv++) { @@ -129,7 +133,7 @@ Bool_t multCalibrator::Calibrate() Double_t multCalibrator::GetRawMax(TH1* histo) { - //This function gets the max X value (right edge) which is filled. + // This function gets the max X value (right edge) which is filled. for (Int_t ii = histo->GetNbinsX(); ii > 0; ii--) { if (histo->GetBinContent(ii) < 1e-10) return histo->GetBinLowEdge(ii + 1); @@ -139,24 +143,24 @@ Double_t multCalibrator::GetRawMax(TH1* histo) Double_t multCalibrator::GetBoundaryForPercentile(TH1* histo, Double_t lPercentileRequested, Double_t& lPrecisionEstimate) { - //This function returns the boundary for a specific percentile. - //It uses a linear interpolation in an attempt to get more precision - //than the binning of the histogram used for quantiling. + // This function returns the boundary for a specific percentile. + // It uses a linear interpolation in an attempt to get more precision + // than the binning of the histogram used for quantiling. // - //It also estimates a certain level of precision of the procedure - //by explicitly comparing the bin content of the bins around the boundary - //with the entire cross section, effectively reporting back a percentage - //that corresponds to those bins. If this percentage is O(percentile bin - //width requested), then the user should worry and we print out a warning. + // It also estimates a certain level of precision of the procedure + // by explicitly comparing the bin content of the bins around the boundary + // with the entire cross section, effectively reporting back a percentage + // that corresponds to those bins. If this percentage is O(percentile bin + // width requested), then the user should worry and we print out a warning. const Double_t lPrecisionConstant = 2.0; Double_t lRawMax = GetRawMax(histo); if (lPercentileRequested < 1e-7) - return lRawMax; //safeguard + return lRawMax; // safeguard if (lPercentileRequested > 100 - 1e-7) - return 0.0; //safeguard + return 0.0; // safeguard Double_t lReturnValue = 0.0; Double_t lPercentile = 100.0 - lPercentileRequested; @@ -182,7 +186,7 @@ Double_t multCalibrator::GetBoundaryForPercentile(TH1* histo, Double_t lPercenti for (Long_t ibin = lFirstBin; ibin < lNBins; ibin++) { lCount += histo->GetBinContent(ibin); if (lCount >= lCountDesired) { - //Found bin I am looking for! + // Found bin I am looking for! Double_t lWidth = histo->GetBinWidth(ibin); Double_t lLeftPercentile = 100. * (lCount - histo->GetBinContent(ibin)) / lHadronicTotal; Double_t lRightPercentile = 100. * lCount / lHadronicTotal; @@ -200,12 +204,12 @@ Double_t multCalibrator::GetBoundaryForPercentile(TH1* histo, Double_t lPercenti //________________________________________________________________ void multCalibrator::SetStandardAdaptiveBoundaries() { - //Function to set standard adaptive boundaries - //Typically used in pp, goes to 0.001% binning for highest multiplicity + // Function to set standard adaptive boundaries + // Typically used in pp, goes to 0.001% binning for highest multiplicity lNDesiredBoundaries = 0; lDesiredBoundaries = new Double_t[1100]; lDesiredBoundaries[0] = 100; - //From Low To High Multiplicity + // From Low To High Multiplicity for (Int_t ib = 1; ib < 91; ib++) { lNDesiredBoundaries++; lDesiredBoundaries[lNDesiredBoundaries] = lDesiredBoundaries[lNDesiredBoundaries - 1] - 1.0; @@ -229,12 +233,12 @@ void multCalibrator::SetStandardAdaptiveBoundaries() //________________________________________________________________ void multCalibrator::SetStandardOnePercentBoundaries() { - //Function to set standard adaptive boundaries - //Typically used in pp, goes to 0.001% binning for highest multiplicity + // Function to set standard adaptive boundaries + // Typically used in pp, goes to 0.001% binning for highest multiplicity lNDesiredBoundaries = 101; lDesiredBoundaries = new Double_t[101]; lDesiredBoundaries[0] = 100; - //From Low To High Multiplicity + // From Low To High Multiplicity for (Int_t ib = 1; ib < 101; ib++) lDesiredBoundaries[ib] = lDesiredBoundaries[ib - 1] - 1.0; cout << "Set standard 1%-wide percentile boundaries! Nboundaries: " << lNDesiredBoundaries << endl; @@ -243,10 +247,10 @@ void multCalibrator::SetStandardOnePercentBoundaries() //________________________________________________________________ TH1F* multCalibrator::GetCalibrationHistogram(TH1* histoRaw, TString lHistoName) { - //This function returns a calibration histogram + // This function returns a calibration histogram //(pp or p-Pb like, no anchor point considered) - //Reset + recreate precision histogram + // Reset + recreate precision histogram ResetPrecisionHistogram(); // Consistency check @@ -256,10 +260,10 @@ TH1F* multCalibrator::GetCalibrationHistogram(TH1* histoRaw, TString lHistoName) cout << "Last boundary: " << lDesiredBoundaries[0] << endl; } - //Aux vars + // Aux vars Double_t lMiddleOfBins[1000]; for (Long_t lB = 1; lB < lNDesiredBoundaries; lB++) { - //place squarely at the middle to ensure it's all fine + // place squarely at the middle to ensure it's all fine lMiddleOfBins[lB - 1] = 0.5 * (lDesiredBoundaries[lB] + lDesiredBoundaries[lB - 1]); } Double_t lBounds[lNDesiredBoundaries + 1]; @@ -276,7 +280,7 @@ TH1F* multCalibrator::GetCalibrationHistogram(TH1* histoRaw, TString lHistoName) lBounds[lDisplacedii] = GetBoundaryForPercentile(histoRaw, lDesiredBoundaries[ii], lPrecision[ii]); TString lPrecisionString = "(Precision OK)"; if (ii != 0 && ii != lNDesiredBoundaries - 1) { - //check precision, please + // check precision, please if (lPrecision[ii] / TMath::Abs(lDesiredBoundaries[ii + 1] - lDesiredBoundaries[ii]) > fkPrecisionWarningThreshold) lPrecisionString = "(WARNING: BINNING MAY LEAD TO IMPRECISION!)"; if (lPrecision[ii] / TMath::Abs(lDesiredBoundaries[ii - 1] - lDesiredBoundaries[ii]) > fkPrecisionWarningThreshold) @@ -302,8 +306,8 @@ void multCalibrator::ResetPrecisionHistogram() delete fPrecisionHistogram; fPrecisionHistogram = 0x0; } - if (lNDesiredBoundaries > 0) { //only if initialized - //invert boundaries, please + if (lNDesiredBoundaries > 0) { // only if initialized + // invert boundaries, please Double_t lInverseDesiredBoundaries[1100]; for (Int_t ii = 0; ii < lNDesiredBoundaries; ii++) { lInverseDesiredBoundaries[ii] = lDesiredBoundaries[lNDesiredBoundaries - (ii + 1)]; diff --git a/Common/Tools/Multiplicity/multCalibrator.h b/Common/Tools/Multiplicity/multCalibrator.h index b5c618bdc3d..a4e38ae1fd2 100644 --- a/Common/Tools/Multiplicity/multCalibrator.h +++ b/Common/Tools/Multiplicity/multCalibrator.h @@ -16,33 +16,36 @@ // - victor.gonzalez@cern.ch // - david.dobrigkeit.chinellato@cern.ch // -#ifndef MULTCALIBRATOR_H -#define MULTCALIBRATOR_H +#ifndef COMMON_TOOLS_MULTIPLICITY_MULTCALIBRATOR_H_ +#define COMMON_TOOLS_MULTIPLICITY_MULTCALIBRATOR_H_ -#include -#include +#include +#include +#include + +#include +#include -#include "TNamed.h" -#include "TH1D.h" +#include class multCalibrator : public TNamed { public: - //Constructors/Destructor + // Constructors/Destructor multCalibrator(); - multCalibrator(const char* name, const char* title = "Multiplicity Calibration Class"); + explicit multCalibrator(const char* name, const char* title = "Multiplicity Calibration Class"); ~multCalibrator(); - //void Print(Option_t *option="") const; + // void Print(Option_t *option="") const; //_________________________________________________________________________ - //Interface: steering functions to be used in calibration macro + // Interface: steering functions to be used in calibration macro - //Set Filenames + // Set Filenames void SetInputFile(TString lFile) { fInputFileName = lFile.Data(); } void SetOutputFile(TString lFile) { fOutputFileName = lFile.Data(); } - //Set Boundaries to find + // Set Boundaries to find void SetBoundaries(Long_t lNB, Double_t* lB) { if (lNB < 2 || lNB > 1e+6) { @@ -56,24 +59,24 @@ class multCalibrator : public TNamed void SetAnchorPointRaw(Float_t lRaw) { fAnchorPointValue = lRaw; } void SetAnchorPointPercentage(Float_t lPer) { fAnchorPointPercentage = lPer; } - void SetStandardAdaptiveBoundaries(); //standard adaptive (pp-like) - void SetStandardOnePercentBoundaries(); //standard 1% (Pb-Pb like) + void SetStandardAdaptiveBoundaries(); // standard adaptive (pp-like) + void SetStandardOnePercentBoundaries(); // standard 1% (Pb-Pb like) - //Master Function in this Class: To be called once filenames are set + // Master Function in this Class: To be called once filenames are set Bool_t Calibrate(); - //Aux function. Keep public, accessible outside as rather useful utility + // Aux function. Keep public, accessible outside as rather useful utility TH1F* GetCalibrationHistogram(TH1* histoRaw, TString lHistoName = "hCalib"); - //Auxiliary functions + // Auxiliary functions Double_t GetRawMax(TH1* histo); Double_t GetBoundaryForPercentile(TH1* histo, Double_t lPercentileRequested, Double_t& lPrecisionEstimate); - //Precision bookkeeping - TH1D* GetPrecisionHistogram() { return fPrecisionHistogram; }; //gets precision histogram from current object - void ResetPrecisionHistogram(); //Reset precision histogram, if it exists + // Precision bookkeeping + TH1D* GetPrecisionHistogram() { return fPrecisionHistogram; } // gets precision histogram from current object + void ResetPrecisionHistogram(); // Reset precision histogram, if it exists - //Aliases for centrality estimators + // Aliases for centrality estimators enum fCentEstim { kCentRawV0M = 0, kCentRawT0M, @@ -89,7 +92,7 @@ class multCalibrator : public TNamed static const TString fCentEstimName[kNCentEstim]; //! name (internal) private: - //Calibration Boundaries to locate + // Calibration Boundaries to locate Double_t* lDesiredBoundaries; Long_t lNDesiredBoundaries; Double_t fkPrecisionWarningThreshold; @@ -105,11 +108,11 @@ class multCalibrator : public TNamed // TList object for storing histograms TList* fCalibHists; - TH1D* fPrecisionHistogram; //for bookkeeping of precision report + TH1D* fPrecisionHistogram; // for bookkeeping of precision report ClassDef(multCalibrator, 1); //(this classdef is only for bookkeeping, class will not usually // be streamed according to current workflow except in very specific // tests!) }; -#endif +#endif // COMMON_TOOLS_MULTIPLICITY_MULTCALIBRATOR_H_ diff --git a/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx b/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx index f4c47b60080..85c86e808fd 100644 --- a/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx +++ b/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx @@ -26,13 +26,24 @@ **********************************************/ #include "multGlauberNBDFitter.h" -#include "TList.h" -#include "TFile.h" -#include "TF1.h" -#include "TStopwatch.h" -#include "TVirtualFitter.h" -#include "TProfile.h" -#include "TFitResult.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include // FIXME using namespace std; @@ -42,6 +53,7 @@ multGlauberNBDFitter::multGlauberNBDFitter() : TNamed(), fNBD(0x0), fhNanc(0x0), fhNpNc(0x0), + fhV0M(0x0), ffChanged(kTRUE), fCurrentf(-1), fAncestorMode(2), @@ -63,14 +75,14 @@ multGlauberNBDFitter::multGlauberNBDFitter() : TNamed(), fNcoll = new Double_t[fMaxNpNcPairs]; fContent = new Long_t[fMaxNpNcPairs]; - //Ancestor histo + // Ancestor histo fhNanc = new TH1D("fhNanc", "", 1000, -0.5, 999.5); - //NBD + // NBD fNBD = new TF1("fNBD", "ROOT::Math::negative_binomial_pdf(x,[0],[1])", 0, 45000); fNBD->SetNpx(45000); - //master function + // master function fGlauberNBD = new TF1("fGlauberNBD", this, &multGlauberNBDFitter::ProbDistrib, 0, 50000, 4, "multGlauberNBDFitter", "ProbDistrib"); fGlauberNBD->SetParameter(0, fMu); @@ -89,6 +101,7 @@ multGlauberNBDFitter::multGlauberNBDFitter(const char* name, const char* title) fNBD(0x0), fhNanc(0x0), fhNpNc(0x0), + fhV0M(0x0), ffChanged(kTRUE), fCurrentf(-1), fAncestorMode(2), @@ -105,19 +118,19 @@ multGlauberNBDFitter::multGlauberNBDFitter(const char* name, const char* title) fFitOptions("R0"), fFitNpx(5000) { - //Named constructor + // Named constructor fNpart = new Double_t[fMaxNpNcPairs]; fNcoll = new Double_t[fMaxNpNcPairs]; fContent = new Long_t[fMaxNpNcPairs]; - //Ancestor histo - //fhNanc = new TH1D("fhNanc", "", fAncestorMode==2?10000:1000, -0.5, 999.5); + // Ancestor histo + // fhNanc = new TH1D("fhNanc", "", fAncestorMode==2?10000:1000, -0.5, 999.5); - //NBD + // NBD fNBD = new TF1("fNBD", "ROOT::Math::negative_binomial_pdf(x,[0],[1])", 0, 45000); fNBD->SetNpx(45000); - //master function + // master function fGlauberNBD = new TF1("fGlauberNBD", this, &multGlauberNBDFitter::ProbDistrib, 0, 50000, 5, "multGlauberNBDFitter", "ProbDistrib"); fGlauberNBD->SetParameter(0, fMu); @@ -157,18 +170,18 @@ multGlauberNBDFitter::~multGlauberNBDFitter() //______________________________________________________ Double_t multGlauberNBDFitter::ProbDistrib(Double_t* x, Double_t* par) -//Master fitter function +// Master fitter function { Double_t lMultValue = x[0]; Double_t lProbability = 0.0; ffChanged = kTRUE; const Double_t lAlmost0 = 1.e-13; - //Comment this line in order to make the code evaluate Nancestor all the time + // Comment this line in order to make the code evaluate Nancestor all the time if (TMath::Abs(fCurrentf - par[2]) < lAlmost0) ffChanged = kFALSE; //______________________________________________________ - //Recalculate the ancestor distribution in case f changed + // Recalculate the ancestor distribution in case f changed if (ffChanged) { fCurrentf = par[2]; fhNanc->Reset(); @@ -192,12 +205,12 @@ Double_t multGlauberNBDFitter::ProbDistrib(Double_t* x, Double_t* par) fhNanc->Scale(1. / fhNanc->Integral()); } //______________________________________________________ - //Actually evaluate function + // Actually evaluate function Int_t lStartBin = fhNanc->FindBin(0.0) + 1; for (Long_t iNanc = lStartBin; iNanc < fhNanc->GetNbinsX() + 1; iNanc++) { Double_t lNancestors = fhNanc->GetBinCenter(iNanc); Double_t lNancestorCount = fhNanc->GetBinContent(iNanc); - //if(lNancestorCount<1e-12&&lNancestors>10) break; + // if(lNancestorCount<1e-12&&lNancestors>10) break; // allow for variable mu in case requested Double_t lThisMu = (((Double_t)lNancestors)) * (par[0] + par[4] * lNancestors); @@ -219,7 +232,7 @@ Bool_t multGlauberNBDFitter::SetNpartNcollCorrelation(TH2* hNpNc) { Bool_t lReturnValue = kTRUE; if (hNpNc) { - fhNpNc = (TH2*)hNpNc; + fhNpNc = reinterpret_cast(hNpNc); } else { lReturnValue = kFALSE; } @@ -231,7 +244,7 @@ Bool_t multGlauberNBDFitter::SetInputV0M(TH1* hV0M) { Bool_t lReturnValue = kTRUE; if (hV0M) { - fhV0M = (TH1*)hV0M; + fhV0M = reinterpret_cast(hV0M); } else { lReturnValue = kFALSE; } @@ -279,7 +292,7 @@ void multGlauberNBDFitter::InitAncestor() Bool_t multGlauberNBDFitter::DoFit() { InitAncestor(); - //Try very hard, please + // Try very hard, please TVirtualFitter::SetMaxIterations(5000000); if (!InitializeNpNc()) { cout << "---> Initialization of Npart x Ncoll correlation info failed!" << endl; @@ -309,6 +322,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(); } @@ -316,12 +330,12 @@ Bool_t multGlauberNBDFitter::DoFit() //________________________________________________________________ Bool_t multGlauberNBDFitter::InitializeNpNc() { - //This function initializes fhNpNc - //Warning: X == Npart, Y == Ncoll + // This function initializes fhNpNc + // Warning: X == Npart, Y == Ncoll Bool_t lReturnValue = kFALSE; if (fhNpNc) { fNNpNcPairs = 0; - //Sweep all allowed values of Npart, Ncoll; find counters + // Sweep all allowed values of Npart, Ncoll; find counters for (int xbin = 1; xbin < 500; xbin++) { for (int ybin = 1; ybin < 3000; ybin++) { if (fhNpNc->GetBinContent(fhNpNc->FindBin(xbin, ybin)) != 0) { @@ -344,12 +358,12 @@ Bool_t multGlauberNBDFitter::InitializeNpNc() //________________________________________________________________ Double_t multGlauberNBDFitter::ContinuousNBD(Double_t n, Double_t mu, Double_t k) { - //Adaptation of the negative binomial distribution - //for non-integer arguments: analytical continuation + // Adaptation of the negative binomial distribution + // for non-integer arguments: analytical continuation // - //This function would actually also be fine with integers; - //in fact it is equivalent to that if 'n' is typecast as - //an integer prior to use + // This function would actually also be fine with integers; + // in fact it is equivalent to that if 'n' is typecast as + // an integer prior to use Double_t F; Double_t f; @@ -369,18 +383,35 @@ Double_t multGlauberNBDFitter::ContinuousNBD(Double_t n, Double_t mu, Double_t k return F; } -void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap) +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; - //2-fold nested loop: - // + looping over all Nancestor combinations - // + looping over all possible final multiplicities - // ^---> final product already multiplicity-binned + 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 + // + looping over all possible final multiplicities + // ^---> 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) diff --git a/Common/Tools/Multiplicity/multGlauberNBDFitter.h b/Common/Tools/Multiplicity/multGlauberNBDFitter.h index b6adb081151..218caf43fc3 100644 --- a/Common/Tools/Multiplicity/multGlauberNBDFitter.h +++ b/Common/Tools/Multiplicity/multGlauberNBDFitter.h @@ -9,59 +9,61 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -#ifndef MULTGLAUBERNBDFITTER_H -#define MULTGLAUBERNBDFITTER_H +#ifndef COMMON_TOOLS_MULTIPLICITY_MULTGLAUBERNBDFITTER_H_ +#define COMMON_TOOLS_MULTIPLICITY_MULTGLAUBERNBDFITTER_H_ -#include -#include "TNamed.h" -#include "TF1.h" -#include "TH1.h" -#include "TH1D.h" -#include "TH2.h" -#include "TProfile.h" +#include +#include +#include +#include +#include +#include + +#include +#include class multGlauberNBDFitter : public TNamed { public: - //basic functionality + // basic functionality multGlauberNBDFitter(); - multGlauberNBDFitter(const char* name, const char* title = "Glauber+NBD fitter"); + explicit multGlauberNBDFitter(const char* name, const char* title = "Glauber+NBD fitter"); ~multGlauberNBDFitter(); - //Master fitter function + // Master fitter function Double_t ProbDistrib(Double_t* x, Double_t* par); void InitAncestor(); - //Do Fit: where everything happens + // Do Fit: where everything happens Bool_t DoFit(); - //Set input characteristics: the 2D plot with Npart, Nanc + // Set input characteristics: the 2D plot with Npart, Nanc Bool_t SetNpartNcollCorrelation(TH2* hNpNc); - //Set main input to be fitted (the V0M distribution) + // Set main input to be fitted (the V0M distribution) Bool_t SetInputV0M(TH1* hV0M); - //Interface to get funtions if asked to + // Interface to get funtions if asked to TF1* GetNBD(); TF1* GetGlauberNBD(); - //Helper + // Helper Bool_t InitializeNpNc(); - //Interface for debug + // Interface for debug void SetAncestorMode(Int_t lAncMode = 0) { fAncestorMode = lAncMode; } Int_t GetAncestorMode() { return fAncestorMode; } TH1D* GetAncestorHistogram() { return fhNanc; } - //Interface to set vals + // Interface to set vals void SetMu(Double_t lVal) { fMu = lVal; } void Setk(Double_t lVal) { fk = lVal; } void Setf(Double_t lVal) { ff = lVal; } void SetNorm(Double_t lVal) { fnorm = lVal; } - //Interface to get vals + // Interface to get vals Double_t GetMu() { return fMu; } Double_t Getk() { return fk; } Double_t Getf() { return ff; } @@ -71,41 +73,41 @@ class multGlauberNBDFitter : public TNamed void SetFitOptions(TString lOpt); void SetFitNpx(Long_t lNpx); - //For ancestor mode 2 + // For ancestor mode 2 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, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap); + // For estimating Npart, Ncoll in multiplicity bins + 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; + // void Print(Option_t *option="") const; private: - //This function serves as the (analytical) NBD + // This function serves as the (analytical) NBD TF1* fNBD; - //This function is the key fitting function + // This function is the key fitting function TF1* fGlauberNBD; - //Reference histo - TH1D* fhNanc; //basic ancestor distribution - TH2* fhNpNc; //correlation between Npart and Ncoll - TH1* fhV0M; //basic ancestor distribution + // Reference histo + TH1D* fhNanc; // basic ancestor distribution + TH2* fhNpNc; // correlation between Npart and Ncoll + TH1* fhV0M; // basic ancestor distribution - //Fitting utilities + // Fitting utilities Bool_t ffChanged; Double_t fCurrentf; - //0: truncation, 1: rounding, 2: analytical continuation + // 0: truncation, 1: rounding, 2: analytical continuation Int_t fAncestorMode; - //Buffer for (Npart, Ncoll) pairs in memory + // Buffer for (Npart, Ncoll) pairs in memory Double_t* fNpart; Double_t* fNcoll; Long_t* fContent; - Long_t fNNpNcPairs; //number of pairs to use + Long_t fNNpNcPairs; // number of pairs to use Long_t fMaxNpNcPairs; - //The actual output: mu, k, f, norm + // The actual output: mu, k, f, norm Double_t fMu; Double_t fdMu; // variable mu option Double_t fk; @@ -117,4 +119,4 @@ class multGlauberNBDFitter : public TNamed ClassDef(multGlauberNBDFitter, 1); }; -#endif +#endif // COMMON_TOOLS_MULTIPLICITY_MULTGLAUBERNBDFITTER_H_ diff --git a/Common/Tools/Multiplicity/multMCCalibrator.cxx b/Common/Tools/Multiplicity/multMCCalibrator.cxx index 5b490daf77d..be3bd71596f 100644 --- a/Common/Tools/Multiplicity/multMCCalibrator.cxx +++ b/Common/Tools/Multiplicity/multMCCalibrator.cxx @@ -16,19 +16,22 @@ // - victor.gonzalez@cern.ch // - david.dobrigkeit.chinellato@cern.ch // -#include "TList.h" -#include "TDirectory.h" -#include "TFile.h" -#include "TF1.h" -#include "TH1F.h" -#include "TH1D.h" -#include "TProfile.h" -#include "TStopwatch.h" -#include "TArrayL64.h" -#include "TArrayF.h" -#include "multCalibrator.h" #include "multMCCalibrator.h" +#include "multCalibrator.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include // FIXME + using namespace std; multMCCalibrator::multMCCalibrator() : TNamed(), @@ -79,22 +82,22 @@ Bool_t multMCCalibrator::Calibrate() cout << " * Output File............: " << fOutputFileName.Data() << endl; cout << endl; - //Opening data and simulation file... + // Opening data and simulation file... TFile* fileData = new TFile(fDataInputFileName.Data(), "READ"); TFile* fileSim = new TFile(fSimInputFileName.Data(), "READ"); - //Step 1: verify if input file contains desired histograms + // Step 1: verify if input file contains desired histograms TProfile* hProfData[multCalibrator::kNCentEstim]; TProfile* hProfSim[multCalibrator::kNCentEstim]; cout << " * acquiring input profiles..." << endl; for (Int_t iv = 0; iv < multCalibrator::kNCentEstim; iv++) { - hProfData[iv] = (TProfile*)fileData->Get(Form("multiplicity-qa/multiplicityQa/hProf%s", multCalibrator::fCentEstimName[iv].Data())); + hProfData[iv] = reinterpret_cast(fileData->Get(Form("multiplicity-qa/multiplicityQa/hProf%s", multCalibrator::fCentEstimName[iv].Data()))); if (!hProfData[iv]) { cout << Form("Data file does not contain histogram h%s, which is necessary for calibration!", multCalibrator::fCentEstimName[iv].Data()) << endl; return kFALSE; } hProfData[iv]->SetName(Form("hProfData_%s", multCalibrator::fCentEstimName[iv].Data())); - hProfSim[iv] = (TProfile*)fileSim->Get(Form("multiplicity-qa/multiplicityQa/hProf%s", multCalibrator::fCentEstimName[iv].Data())); + hProfSim[iv] = reinterpret_cast(fileSim->Get(Form("multiplicity-qa/multiplicityQa/hProf%s", multCalibrator::fCentEstimName[iv].Data()))); if (!hProfSim[iv]) { cout << Form("Sim file does not contain histogram h%s, which is necessary for calibration!", multCalibrator::fCentEstimName[iv].Data()) << endl; return kFALSE; @@ -135,14 +138,14 @@ Bool_t multMCCalibrator::Calibrate() //________________________________________________________________ TF1* multMCCalibrator::GetFit(TProfile* fProf, Bool_t lQuadratic) { - TString fFormula = "[0]*x"; //old/deprecated (avoid if possible, please) + TString fFormula = "[0]*x"; // old/deprecated (avoid if possible, please) if (lQuadratic) fFormula = "[0]+[1]*TMath::Power(x,[2])"; // Function to return fit function to profile for posterior inversion TF1* fit = new TF1(Form("%s_fit", fProf->GetName()), fFormula.Data(), fProf->GetBinLowEdge(1), fProf->GetBinLowEdge(fProf->GetNbinsX())); - //Guesstimate inclination from data points in profile + // Guesstimate inclination from data points in profile Double_t lMeanInclination = 0; Long_t lInclinationCount = 0; for (Int_t ii = 2; ii < fProf->GetNbinsX(); ii++) { @@ -158,7 +161,7 @@ TF1* multMCCalibrator::GetFit(TProfile* fProf, Bool_t lQuadratic) if (lInclinationCount >= 5) lMeanInclination /= lInclinationCount; - //Give it a little nudge, cause life's hard + // Give it a little nudge, cause life's hard fit->SetParameter(0, 0.0); fit->SetParameter(1, lMeanInclination); fit->SetParameter(2, 1.0); diff --git a/Common/Tools/Multiplicity/multMCCalibrator.h b/Common/Tools/Multiplicity/multMCCalibrator.h index f88bddf98c3..c89fe728328 100644 --- a/Common/Tools/Multiplicity/multMCCalibrator.h +++ b/Common/Tools/Multiplicity/multMCCalibrator.h @@ -16,34 +16,36 @@ // - victor.gonzalez@cern.ch // - david.dobrigkeit.chinellato@cern.ch // -#ifndef MULTMCCALIBRATOR_H -#define MULTMCCALIBRATOR_H +#ifndef COMMON_TOOLS_MULTIPLICITY_MULTMCCALIBRATOR_H_ +#define COMMON_TOOLS_MULTIPLICITY_MULTMCCALIBRATOR_H_ -#include -#include "TNamed.h" -#include "TF1.h" -#include "TH1D.h" -#include "TProfile.h" -#include +#include +#include +#include +#include +#include + +#include +#include class multMCCalibrator : public TNamed { public: - //Constructors/Destructor + // Constructors/Destructor multMCCalibrator(); - multMCCalibrator(const char* name, const char* title = "MC Multiplicity Calibration Class"); + explicit multMCCalibrator(const char* name, const char* title = "MC Multiplicity Calibration Class"); ~multMCCalibrator(); //_________________________________________________________________________ - //Interface: steering functions to be used in calibration macro + // Interface: steering functions to be used in calibration macro - //Set Filenames + // Set Filenames void SetDataInputFile(TString lFile) { fDataInputFileName = lFile.Data(); } void SetSimInputFile(TString lFile) { fSimInputFileName = lFile.Data(); } void SetOutputFile(TString lFile) { fOutputFileName = lFile.Data(); } - //Master Function in this Class: To be called once filenames are set + // Master Function in this Class: To be called once filenames are set Bool_t Calibrate(); TF1* GetFit(TProfile* fProf, Bool_t lQuadratic = kTRUE); @@ -63,4 +65,4 @@ class multMCCalibrator : public TNamed // be streamed according to current workflow except in very specific // tests!) }; -#endif +#endif // COMMON_TOOLS_MULTIPLICITY_MULTMCCALIBRATOR_H_ diff --git a/Common/Tools/PID/checkPidPacking.cxx b/Common/Tools/PID/checkPidPacking.cxx index c503ee1b288..dc497240ef3 100644 --- a/Common/Tools/PID/checkPidPacking.cxx +++ b/Common/Tools/PID/checkPidPacking.cxx @@ -16,10 +16,18 @@ /// \since 03/05/2024 /// -#include "Common/DataModel/PIDResponse.h" -#include "TH1F.h" -#include "TCanvas.h" -#include "TRandom.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include + +#include +#include +#include +#include + +#include +#include using namespace o2; @@ -32,7 +40,7 @@ bool process(std::string outputName, int nevents = 100000) NsigmaContainer() {} void operator()(const int8_t& packed) { mPacked = packed; } int8_t mPacked = 0; - float unpack() { return aod::pidutils::unPackInTable(mPacked); } + float unpack() { return T::unPackInTable(mPacked); } } container; TH1F* hgaus = new TH1F("hgaus", "", 20 / T::bin_width, @@ -55,12 +63,12 @@ bool process(std::string outputName, int nevents = 100000) for (int i = 0; i < nevents; i++) { float nsigma = gRandom->Gaus(0, 1); hgaus->Fill(nsigma); - aod::pidutils::packInTable(nsigma, container); + T::packInTable(nsigma, container); hgausPacked->Fill(container.unpack()); nsigma = gRandom->Uniform(-10, 10); huniform->Fill(nsigma); - aod::pidutils::packInTable(nsigma, container); + T::packInTable(nsigma, container); huniformPacked->Fill(container.unpack()); } diff --git a/Common/Tools/PID/handleParamBase.h b/Common/Tools/PID/handleParamBase.h index 01c2a66ab8b..2362696d1b4 100644 --- a/Common/Tools/PID/handleParamBase.h +++ b/Common/Tools/PID/handleParamBase.h @@ -19,12 +19,20 @@ #ifndef COMMON_TOOLS_PID_HANDLEPARAMBASE_H_ #define COMMON_TOOLS_PID_HANDLEPARAMBASE_H_ +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include #include #include -#include "CCDB/CcdbApi.h" -#include -#include "Framework/Logger.h" -#include "TFile.h" // Global executable arguments namespace bpo = boost::program_options; @@ -79,9 +87,9 @@ void setStandardOpt(bpo::options_description& options) } template -T* retrieveFromCCDB(const std::string path, +T* retrieveFromCCDB(const std::string& path, const int64_t timestamp, - std::map metadata) + const std::map& metadata) { std::map headers; LOG(info) << "Object " << path << " for timestamp " << timestamp << " -> " << timeStampToHReadble(timestamp); @@ -99,7 +107,7 @@ T* retrieveFromCCDB(const std::string path, } template -T* retrieveFromCCDB(const std::string path, +T* retrieveFromCCDB(const std::string& path, const int64_t timestamp) { std::map metadata; diff --git a/Common/Tools/PID/handleParamTPCResponse.cxx b/Common/Tools/PID/handleParamTPCResponse.cxx index 64741503fae..74ade0f5f5a 100644 --- a/Common/Tools/PID/handleParamTPCResponse.cxx +++ b/Common/Tools/PID/handleParamTPCResponse.cxx @@ -14,14 +14,26 @@ /// \author Jeremy Wilkinson /// \brief exec for writing and reading TPC PID Response object +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Tools/PID/handleParamBase.h" + +#include +#include + +#include +#include + +#include +#include + #include #include +#include +#include #include -#include -#include "TFile.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "handleParamBase.h" -#include "Algorithm/RangeTokenizer.h" +#include +#include + using namespace o2::pid::tpc; bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv[]) @@ -48,7 +60,7 @@ bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv "paramMultNormalization", bpo::value()->default_value(11000.), "Multiplicity Normalization")( "paramnClNormalization", bpo::value()->default_value(152.), "Maximum nClusters for normalisation (159 for run 2, 152 for run 3)")( "useDefaultParam", bpo::value()->default_value(true), "Use default sigma parametrisation")( - "mode", bpo::value()->default_value(""), "Running mode ('read' from file, 'write' to file, 'pull' from CCDB, 'push' to CCDB)")( + "mode", bpo::value()->default_value(""), "Running mode ('read' from file, 'write' to file, 'pull' from CCDB, 'push' to CCDB)")( "help,h", "Produce help message."); setStandardOpt(options); try { diff --git a/Common/Tools/PID/pidTPCModule.h b/Common/Tools/PID/pidTPCModule.h new file mode 100644 index 00000000000..721fd86f826 --- /dev/null +++ b/Common/Tools/PID/pidTPCModule.h @@ -0,0 +1,962 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file pidTPCModule.h +/// \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. +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \author Christian Sonnabend christian.sonnabend@cern.ch +/// \author Annalena Kalteyer annalena.sophie.kalteyer@cern.ch +/// \author Jeremy Wilkinson jeremy.wilkinson@cern.ch + +#ifndef COMMON_TOOLS_PID_PIDTPCMODULE_H_ +#define COMMON_TOOLS_PID_PIDTPCMODULE_H_ + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/CollisionTypeHelper.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/TableProducer/PID/pidTPCBase.h" +#include "Tools/ML/model.h" + +#include +#include +#include +#include +#include +#include +#include + +#include // IWYU pragma: keep (do not replace with TMatrixDfwd.h) +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace o2::aod +{ +namespace pid +{ +struct pidTPCProducts : o2::framework::ProducesGroup { + // Intermediate tables (provide only if requested) + o2::framework::Produces dEdxCorrected; + o2::framework::Produces mult; + + // Tables produced by TPC component + o2::framework::Produces tablePIDFullEl; + o2::framework::Produces tablePIDFullMu; + o2::framework::Produces tablePIDFullPi; + o2::framework::Produces tablePIDFullKa; + o2::framework::Produces tablePIDFullPr; + o2::framework::Produces tablePIDFullDe; + o2::framework::Produces tablePIDFullTr; + o2::framework::Produces tablePIDFullHe; + o2::framework::Produces tablePIDFullAl; + + o2::framework::Produces tablePIDTinyEl; + o2::framework::Produces tablePIDTinyMu; + o2::framework::Produces tablePIDTinyPi; + o2::framework::Produces tablePIDTinyKa; + o2::framework::Produces tablePIDTinyPr; + o2::framework::Produces tablePIDTinyDe; + o2::framework::Produces tablePIDTinyTr; + o2::framework::Produces tablePIDTinyHe; + o2::framework::Produces tablePIDTinyAl; + o2::framework::Produces tableTuneOnData; +}; + +struct pidTPCConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "pidTPC"; + o2::framework::Configurable paramfile{"param-file", "", "Path to the parametrization object, if empty the parametrization is not taken from file"}; + o2::framework::Configurable ccdbPath{"ccdbPath", "Analysis/PID/TPC/Response", "Path of the TPC parametrization on the CCDB"}; + o2::framework::Configurable recoPass{"recoPass", "", "Reconstruction pass name for CCDB query (automatically takes latest object for timestamp if blank)"}; + o2::framework::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 + o2::framework::Configurable useNetworkCorrection{"useNetworkCorrection", 0, "(bool) Wether or not to use the network correction for the TPC dE/dx signal"}; + o2::framework::Configurable autofetchNetworks{"autofetchNetworks", 1, "(bool) Automatically fetches networks from CCDB for the correct run number"}; + o2::framework::Configurable skipTPCOnly{"skipTPCOnly", -1, "Flag to skip TPC only tracks (faster but affects the analyses that use TPC only tracks). 0: do not skip, 1: skip, -1: check if needed by specific tasks"}; + o2::framework::Configurable> devicesRequiringTPCOnlyPID{"devicesRequiringTPCOnlyPID", std::vector{"photon-conversion-builder"}, "List of device names of tasks requiring TPC-only tracks to have TPC PID calculated"}; + o2::framework::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"}; + o2::framework::Configurable networkPathCCDB{"networkPathCCDB", "Analysis/PID/TPC/ML", "Path on CCDB"}; + o2::framework::Configurable enableNetworkOptimizations{"enableNetworkOptimizations", 1, "(bool) If the neural network correction is used, this enables GraphOptimizationLevel::ORT_ENABLE_EXTENDED in the ONNX session"}; + o2::framework::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 + o2::framework::Configurable savedEdxsCorrected{"savedEdxsCorrected", -1, {"Save table with corrected dE/dx calculated on the spot. 0: off, 1: on, -1: auto"}}; + o2::framework::Configurable useCorrecteddEdx{"useCorrecteddEdx", false, "(bool) If true, use corrected dEdx value in Nsigma calculation instead of the one in the AO2D"}; + + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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)"}}; + o2::framework::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'"}}; + o2::framework::Configurable useNetworkEl{"useNetworkEl", 1, {"Switch for applying neural network on the electron mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable useNetworkMu{"useNetworkMu", 1, {"Switch for applying neural network on the muon mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable useNetworkPi{"useNetworkPi", 1, {"Switch for applying neural network on the pion mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable useNetworkKa{"useNetworkKa", 1, {"Switch for applying neural network on the kaon mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable useNetworkPr{"useNetworkPr", 1, {"Switch for applying neural network on the proton mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable useNetworkDe{"useNetworkDe", 1, {"Switch for applying neural network on the deuteron mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable useNetworkTr{"useNetworkTr", 1, {"Switch for applying neural network on the triton mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable useNetworkHe{"useNetworkHe", 1, {"Switch for applying neural network on the helium3 mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable useNetworkAl{"useNetworkAl", 1, {"Switch for applying neural network on the alpha mass hypothesis (if network enabled) (set to 0 to disable)"}}; + o2::framework::Configurable networkBetaGammaCutoff{"networkBetaGammaCutoff", 0.45, {"Lower value of beta-gamma to override the NN application"}}; + o2::framework::Configurable cfgPathGrpLhcIf{"ccdb-path-grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; +}; + +// helper getter - FIXME should be separate +int getPIDIndex(const int pdgCode) // Get O2 PID index corresponding to MC PDG code +{ + switch (std::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; + } +} + +typedef struct Str_dEdx_correction { + TMatrixD fMatrix; + bool warning = true; + + // void init(std::vector& params) + void init() + { + double elements[32] = {0.99091, -0.015053, 0.0018912, -0.012305, + 0.081387, 0.003205, -0.0087404, -0.0028608, + 0.013066, 0.017012, -0.0018469, -0.0052177, + -0.0035655, 0.0017846, 0.0019127, -0.00012964, + 0.0049428, 0.0055592, -0.0010618, -0.0016134, + -0.0059098, 0.0013335, 0.00052133, 3.1119e-05, + -0.004882, 0.00077317, -0.0013827, 0.003249, + -0.00063689, 0.0016218, -0.00045215, -1.5815e-05}; + fMatrix.ResizeTo(4, 8); + fMatrix.SetMatrixArray(elements); + } + + float fReal_fTPCSignalN(std::vector vec1, std::vector vec2) + { + float result = 0.f; + // push 1. + vec1.insert(vec1.begin(), 1.0); + vec2.insert(vec2.begin(), 1.0); + for (int i = 0; i < fMatrix.GetNrows(); i++) { + for (int j = 0; j < fMatrix.GetNcols(); j++) { + double param = fMatrix(i, j); + double value1 = i > static_cast(vec1.size()) ? 0 : vec1[i]; + double value2 = j > static_cast(vec2.size()) ? 0 : vec2[j]; + result += param * value1 * value2; + } + } + return result; + } +} Str_dEdx_correction; + +class pidTPCModule +{ + public: + pidTPCModule() + { + // constructor + } + o2::aod::pid::pidTPCConfigurables pidTPCopts; + + // TPC PID Response + o2::pid::tpc::Response* response; + + // Network correction for TPC PID response + ml::OnnxModel network; + std::map metadata; + std::map nullmetadata; + std::map headers; + std::vector speciesNetworkFlags = std::vector(9); + std::string networkVersion; + + // To get automatically the proper Hadronic Rate + std::string irSource = ""; + o2::common::core::CollisionSystemType::collType collsys = o2::common::core::CollisionSystemType::kCollSysUndef; + + // Parametrization configuration + bool useCCDBParam = false; + + // for dEdx correction + ctpRateFetcher mRateFetcher; + Str_dEdx_correction str_dedx_correction; + + //__________________________________________________ + template + void init(TCCDB& ccdb, TCCDBApi& ccdbApi, TContext& context, TpidTPCOpts const& external_pidtpcopts, TMetadataInfo const& metadataInfo) + { + // read in configurations from the task where it's used + pidTPCopts = external_pidtpcopts; + + if (pidTPCopts.useCorrecteddEdx.value) { + LOGF(info, "***************************************************"); + LOGF(info, " WARNING: YOU HAVE SWITCHED ON 'corrected dEdx!"); + LOGF(info, " This mode is still in development and it is meant"); + LOGF(info, " ONLY FOR EXPERTS at this time. Please switch "); + LOGF(info, " this option off UNLESS you are absolutely SURE"); + LOGF(info, " of what you're doing! You've been warned!"); + LOGF(info, "***************************************************"); + } + + if (pidTPCopts.skipTPCOnly.value == -1) { + LOGF(info, "***************************************************"); + LOGF(info, " the skipTPConly flag has a value of -1! "); + LOGF(info, " ---> autodetecting TPC-only track necessity now "); + LOGF(info, "***************************************************"); + // print list of devices that are being checked for + for (std::size_t devIdx{0}; devIdx < pidTPCopts.devicesRequiringTPCOnlyPID->size(); devIdx++) { + LOGF(info, "Will search for #%i device requiring TPC PID for TPC only: %s", devIdx, pidTPCopts.devicesRequiringTPCOnlyPID->at(devIdx)); + } + LOGF(info, "***************************************************"); + + // assume that TPC tracks are not needed, but check if tasks + // requiring them are present in the chain + pidTPCopts.skipTPCOnly.value = 1; + + // loop over devices in this execution + auto& workflows = context.services().template get(); + for (o2::framework::DeviceSpec const& device : workflows.devices) { + // Look for propagation service + if (device.name.compare("propagation-service") == 0) { + LOGF(info, " ---> propagation service detected, checking if photons enabled..."); + for (auto const& option : device.options) { + // check for photon generation enabled or not + if (option.name.compare("v0BuilderOpts.generatePhotonCandidates") == 0) { + if (option.defaultValue.get()) { + LOGF(info, " ---> propagation service: photons enabled, will calculate TPC PID for TPC only tracks."); + pidTPCopts.skipTPCOnly.value = 0; + } else { + LOGF(info, " ---> propagation service: photons disabled, TPC PID not required for TPC-only tracks"); + } + } + } + } + + // Check 2: specific tasks that require TPC PID based on configurable + for (std::size_t devIdx{0}; devIdx < pidTPCopts.devicesRequiringTPCOnlyPID->size(); devIdx++) { + if (device.name.compare(pidTPCopts.devicesRequiringTPCOnlyPID->at(devIdx)) == 0) { + LOGF(info, " ---> %s detected! ", pidTPCopts.devicesRequiringTPCOnlyPID->at(devIdx)); + LOGF(info, " ---> enabling TPC only track TPC PID calculations now."); + pidTPCopts.skipTPCOnly.value = 0; + } + } + } + + if (pidTPCopts.skipTPCOnly.value == 1) { + LOGF(info, "***************************************************"); + LOGF(info, "No need for TPC only information detected. Will not generate Nsigma for TPC only tracks"); + LOGF(info, "If this is unexpected behaviour and a necessity was not identified, please add the"); + LOGF(info, "corresponding task to the configurable 'devicesRequiringTPCOnlyPID' of this task"); + LOGF(info, "To do that, please get in touch with core service wagon maintainers and ask:"); + LOGF(info, "It is always best to use core service wagons instead of private copies"); + } + LOGF(info, "***************************************************"); + } + + // initialize PID response + response = new o2::pid::tpc::Response(); + + enableFlagIfTableRequired(context, "DEdxsCorrected", pidTPCopts.savedEdxsCorrected); + + // Checking the tables are requested in the workflow and enabling them + auto enableFlag = [&](const std::string particle, o2::framework::Configurable& flag) { + enableFlagIfTableRequired(context, "pidTPC" + particle, flag); + }; + enableFlag("FullEl", pidTPCopts.pidFullEl); + enableFlag("FullMu", pidTPCopts.pidFullMu); + enableFlag("FullPi", pidTPCopts.pidFullPi); + enableFlag("FullKa", pidTPCopts.pidFullKa); + enableFlag("FullPr", pidTPCopts.pidFullPr); + enableFlag("FullDe", pidTPCopts.pidFullDe); + enableFlag("FullTr", pidTPCopts.pidFullTr); + enableFlag("FullHe", pidTPCopts.pidFullHe); + enableFlag("FullAl", pidTPCopts.pidFullAl); + + enableFlag("El", pidTPCopts.pidTinyEl); + enableFlag("Mu", pidTPCopts.pidTinyMu); + enableFlag("Pi", pidTPCopts.pidTinyPi); + enableFlag("Ka", pidTPCopts.pidTinyKa); + enableFlag("Pr", pidTPCopts.pidTinyPr); + enableFlag("De", pidTPCopts.pidTinyDe); + enableFlag("Tr", pidTPCopts.pidTinyTr); + enableFlag("He", pidTPCopts.pidTinyHe); + enableFlag("Al", pidTPCopts.pidTinyAl); + + if (metadataInfo.isMC()) { + enableFlagIfTableRequired(context, "mcTPCTuneOnData", pidTPCopts.enableTuneOnDataTable); + } + + speciesNetworkFlags[0] = pidTPCopts.useNetworkEl; + speciesNetworkFlags[1] = pidTPCopts.useNetworkMu; + speciesNetworkFlags[2] = pidTPCopts.useNetworkPi; + speciesNetworkFlags[3] = pidTPCopts.useNetworkKa; + speciesNetworkFlags[4] = pidTPCopts.useNetworkPr; + speciesNetworkFlags[5] = pidTPCopts.useNetworkDe; + speciesNetworkFlags[6] = pidTPCopts.useNetworkTr; + speciesNetworkFlags[7] = pidTPCopts.useNetworkHe; + speciesNetworkFlags[8] = pidTPCopts.useNetworkAl; + + // Initialise metadata object for CCDB calls from AO2D metadata + if (pidTPCopts.recoPass.value == "") { + 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, "Setting reco pass for TPC response to user-defined name {}", pidTPCopts.recoPass.value); + metadata["RecoPassName"] = pidTPCopts.recoPass.value; + } + + /// TPC PID Response + const TString fname = pidTPCopts.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 = pidTPCopts.ccdbPath.value; + const auto time = pidTPCopts.ccdbTimestamp.value; + if (time != 0) { + LOGP(info, "Initialising TPC PID response for fixed timestamp {} and reco pass {}:", time, pidTPCopts.recoPass.value); + ccdb->setTimestamp(time); + response = ccdb->template 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->template 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 + o2::parameters::GRPLHCIFData* grpo = ccdb->template getForTimeStamp(pidTPCopts.cfgPathGrpLhcIf.value, time); + if (grpo) { + LOG(info) << " collision type::" << CollisionSystemType::getCollisionTypeFromGrp(grpo); + collsys = CollisionSystemType::getCollisionTypeFromGrp(grpo); + if (collsys == CollisionSystemType::kCollSyspp) { + irSource = std::string("T0VTX"); + } else { + irSource = std::string("ZNC hadronic"); + } + } else { + LOGF(info, "No grpo object found. irSource will remain undefined."); + } + response->PrintAll(); + } + } + + /// Neural network init for TPC PID + if (!pidTPCopts.useNetworkCorrection) { + return; + } else { + /// CCDB and auto-fetching + if (!pidTPCopts.autofetchNetworks) { + if (pidTPCopts.ccdbTimestamp > 0) { + /// Fetching network for specific timestamp + LOG(info) << "Fetching network for timestamp: " << pidTPCopts.ccdbTimestamp.value; + bool retrieveSuccess = ccdbApi.retrieveBlob(pidTPCopts.networkPathCCDB.value, ".", metadata, pidTPCopts.ccdbTimestamp.value, false, pidTPCopts.networkPathLocally.value); + headers = ccdbApi.retrieveHeaders(pidTPCopts.networkPathCCDB.value, metadata, pidTPCopts.ccdbTimestamp.value); + networkVersion = headers["NN-Version"]; + if (retrieveSuccess) { + network.initModel(pidTPCopts.networkPathLocally.value, pidTPCopts.enableNetworkOptimizations.value, pidTPCopts.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) << "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 + if (pidTPCopts.networkPathLocally.value == "") { + LOG(fatal) << "Local path must be set (flag networkPathLocally)! Aborting..."; + } + LOG(info) << "Using local file [" << pidTPCopts.networkPathLocally.value << "] for the TPC PID response correction."; + network.initModel(pidTPCopts.networkPathLocally.value, pidTPCopts.enableNetworkOptimizations.value, pidTPCopts.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; + } + } + + if (pidTPCopts.useCorrecteddEdx.value && networkVersion != "5") { + LOGF(fatal, "Using corrected dE/dx with a network version other than 5 will not work. Crashing now."); + } + } // end init + + //__________________________________________________ + template + std::vector createNetworkPrediction(TCCDB& ccdb, TCCDBApi& ccdbApi, soa::Join const& collisions, M const& mults, 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 (pidTPCopts.autofetchNetworks) { + const auto& bc = bcs.begin(); + // Initialise correct TPC response object before NN setup (for NCl normalisation) + if (useCCDBParam && pidTPCopts.ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(pidTPCopts.ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 + if (pidTPCopts.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(), pidTPCopts.recoPass.value); + } + response = ccdb->template getSpecific(pidTPCopts.ccdbPath.value, bc.timestamp(), metadata); + headers = ccdbApi.retrieveHeaders(pidTPCopts.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(pidTPCopts.ccdbPath.value, nullmetadata, bc.timestamp()); + response = ccdb->template getForTimeStamp(pidTPCopts.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 + o2::parameters::GRPLHCIFData* grpo = ccdb->template getForTimeStamp(pidTPCopts.cfgPathGrpLhcIf.value, bc.timestamp()); + if (grpo) { + LOG(info) << "Collision type::" << CollisionSystemType::getCollisionTypeFromGrp(grpo); + collsys = CollisionSystemType::getCollisionTypeFromGrp(grpo); + if (collsys == CollisionSystemType::kCollSyspp) { + irSource = std::string("T0VTX"); + } else { + irSource = std::string("ZNC hadronic"); + } + } else { + LOGF(info, "No grpo object found. irSource will remain undefined."); + } + 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(pidTPCopts.networkPathCCDB.value, ".", metadata, bc.timestamp(), false, pidTPCopts.networkPathLocally.value); + headers = ccdbApi.retrieveHeaders(pidTPCopts.networkPathCCDB.value, metadata, bc.timestamp()); + networkVersion = headers["NN-Version"]; + if (retrieveSuccess) { + network.initModel(pidTPCopts.networkPathLocally.value, pidTPCopts.enableNetworkOptimizations.value, pidTPCopts.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; + + // To load the Hadronic rate once for each collision + float hadronicRateBegin = 0.; + std::vector hadronicRateForCollision(collisions.size(), 0.0f); + size_t i = 0; + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); + if (irSource.compare("") != 0) { + hadronicRateForCollision[i] = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * 1.e-3; + } else { + hadronicRateForCollision[i] = 0.0f; + } + i++; + } + auto bc = bcs.begin(); + if (irSource.compare("") != 0) { + hadronicRateBegin = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * 1.e-3; // kHz + } else { + hadronicRateBegin = 0.0f; + } + + // 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 + static constexpr int NParticleTypes = 9; + constexpr int ExpectedInputDimensionsNNV2 = 7; + constexpr int ExpectedInputDimensionsNNV3 = 8; + constexpr auto NetworkVersionV2 = "2"; + constexpr auto NetworkVersionV3 = "3"; + for (int i = 0; i < NParticleTypes; i++) { // Loop over particle number for which network correction is used + for (auto const& trk : tracks) { + if (!trk.hasTPC()) { + continue; + } + if (pidTPCopts.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() ? mults[trk.collisionId()] / 11000. : 1.; + track_properties[counter_track_props + 5] = std::sqrt(nNclNormalization / trk.tpcNClsFound()); + if (input_dimensions == ExpectedInputDimensionsNNV2 && networkVersion == NetworkVersionV2) { + track_properties[counter_track_props + 6] = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).ft0cOccupancyInTimeRange() / 60000. : 1.; + } + if (input_dimensions == ExpectedInputDimensionsNNV3 && networkVersion == NetworkVersionV3) { + track_properties[counter_track_props + 6] = trk.has_collision() ? collisions.iteratorAt(trk.collisionId()).ft0cOccupancyInTimeRange() / 60000. : 1.; + if (trk.has_collision()) { + if (collsys == CollisionSystemType::kCollSyspp) { + track_properties[counter_track_props + 7] = hadronicRateForCollision[trk.collisionId()] / 1500.; + } else { + track_properties[counter_track_props + 7] = hadronicRateForCollision[trk.collisionId()] / 50.; + } + } else { + // asign Hadronic Rate at beginning of run if track does not belong to a collision + if (collsys == CollisionSystemType::kCollSyspp) { + track_properties[counter_track_props + 7] = hadronicRateBegin / 1500.; + } else { + track_properties[counter_track_props + 7] = hadronicRateBegin / 50.; + } + } + } + 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 int64_t multTPC, 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 (pidTPCopts.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->GetExpectedSigmaAtMultiplicity(multTPC, 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 + constexpr int NumOutputNodesSymmetricSigma = 2; + constexpr int NumOutputNodesAsymmetricSigma = 3; + if (pidTPCopts.useNetworkCorrection && speciesNetworkFlags[pid] && trk.has_collision() && bg > pidTPCopts.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() == NumOutputNodesSymmetricSigma) { // Symmetric sigma correction + expSigma = (network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid)]) * expSignal; + nSigma = (tpcSignal / expSignal - network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid)]); + } else if (network.getNumOutputNodes() == NumOutputNodesAsymmetricSigma) { // Asymmetric sigma corection + if (tpcSignal / expSignal >= network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) { + expSigma = (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) * expSignal; + nSigma = (tpcSignal / expSignal - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 1] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]); + } else { + expSigma = (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 2]) * expSignal; + nSigma = (tpcSignal / expSignal - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 2]); + } + } else { + LOGF(fatal, "Network output-dimensions incompatible!"); + } + } else { + nSigma = response->GetNumberOfSigmaMCTunedAtMultiplicity(multTPC, trk, pid, tpcSignal); + } + if (flagFull) + tableFull(expSigma, nSigma); + if (flagTiny) + aod::pidtpc_tiny::binning::packInTable(nSigma, tableTiny); + }; + + //__________________________________________________ + template + void process(TCCDB& ccdb, TCCDBApi& ccdbApi, TBCs const& bcs, soa::Join const& cols, TTracks const& tracks, TTracksQA const& tracksQA, TProducts& products) + { + if (tracks.size() == 0) { + return; // empty protection + } + auto trackiterator = tracks.begin(); + if constexpr (requires { trackiterator.mcParticleId(); }) { + gRandom->SetSeed(0); // Ensure unique seed from UUID for each process call + } + + // preparatory step: we need the multiplicities for each collision + std::vector pidmults; + int64_t totalTPCtracks = 0; + int64_t totalTPCnotStandalone = 0; + pidmults.resize(cols.size(), 0); + + // faster counting + for (const auto& track : tracks) { + if (track.hasTPC()) { + if (track.collisionId() > -1) { + pidmults[track.collisionId()]++; + } + totalTPCtracks++; + if (track.hasITS() || track.hasTOF() || track.hasTRD()) { + totalTPCnotStandalone++; + } + } + } + + const uint64_t outTable_size = tracks.size(); + + auto reserveTable = [&outTable_size](const o2::framework::Configurable& flag, auto& table) { + if (flag.value != 1) { + return; + } + table.reserve(outTable_size); + }; + + // Prepare memory for enabled tables + reserveTable(pidTPCopts.pidFullEl, products.tablePIDFullEl); + reserveTable(pidTPCopts.pidFullMu, products.tablePIDFullMu); + reserveTable(pidTPCopts.pidFullPi, products.tablePIDFullPi); + reserveTable(pidTPCopts.pidFullKa, products.tablePIDFullKa); + reserveTable(pidTPCopts.pidFullPr, products.tablePIDFullPr); + reserveTable(pidTPCopts.pidFullDe, products.tablePIDFullDe); + reserveTable(pidTPCopts.pidFullTr, products.tablePIDFullTr); + reserveTable(pidTPCopts.pidFullHe, products.tablePIDFullHe); + reserveTable(pidTPCopts.pidFullAl, products.tablePIDFullAl); + + reserveTable(pidTPCopts.pidTinyEl, products.tablePIDTinyEl); + reserveTable(pidTPCopts.pidTinyMu, products.tablePIDTinyMu); + reserveTable(pidTPCopts.pidTinyPi, products.tablePIDTinyPi); + reserveTable(pidTPCopts.pidTinyKa, products.tablePIDTinyKa); + reserveTable(pidTPCopts.pidTinyPr, products.tablePIDTinyPr); + reserveTable(pidTPCopts.pidTinyDe, products.tablePIDTinyDe); + reserveTable(pidTPCopts.pidTinyTr, products.tablePIDTinyTr); + reserveTable(pidTPCopts.pidTinyHe, products.tablePIDTinyHe); + reserveTable(pidTPCopts.pidTinyAl, products.tablePIDTinyAl); + + const uint64_t tracksForNet_size = (pidTPCopts.skipTPCOnly) ? totalTPCnotStandalone : totalTPCtracks; + std::vector network_prediction; + + if (pidTPCopts.useNetworkCorrection) { + network_prediction = createNetworkPrediction(ccdb, ccdbApi, cols, pidmults, tracks, bcs, tracksForNet_size); + } + + uint64_t count_tracks = 0; + + //_______________________________________ + // process tracksQA in case present + std::vector indexTrack2TrackQA(outTable_size, -1); + if constexpr (soa::is_table) { + for (const auto& trackQA : tracksQA) { + indexTrack2TrackQA[trackQA.trackId()] = trackQA.globalIndex(); + } + } + //_______________________________________ + + // Fill Hadronic rate per collision in case CorrectedDEdx is requested + std::vector hadronicRateForCollision(cols.size(), 0.0f); + float hadronicRateBegin = 0.0f; + if (pidTPCopts.useCorrecteddEdx) { + size_t i = 0; + for (const auto& collision : cols) { + const auto& bc = collision.template bc_as(); + if (irSource.compare("") != 0) { + hadronicRateForCollision[i] = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * 1.e-3; + } else { + hadronicRateForCollision[i] = 0.0f; + } + i++; + } + auto bc = bcs.begin(); + if (irSource.compare("") != 0) { + hadronicRateBegin = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * 1.e-3; // kHz + } else { + hadronicRateBegin = 0.0f; + } + } + + for (auto const& trk : tracks) { + // get the TPC signal to be used in the PID + float tpcSignalToEvaluatePID = trk.tpcSignal(); + + int64_t multTPC = 0; + if (trk.has_collision()) { + multTPC = pidmults[trk.collisionId()]; + } + + // if corrected dE/dx is requested, correct it here on the spot and use that + if (pidTPCopts.useCorrecteddEdx) { + + //_________________________________________________________ + // bypass TPC signal in case TracksQA information present + if constexpr (soa::is_table) { + tpcSignalToEvaluatePID = -999.f; + if (indexTrack2TrackQA[trk.globalIndex()] != -1) { + auto trackQA = tracksQA.rawIteratorAt(indexTrack2TrackQA[trk.globalIndex()]); + tpcSignalToEvaluatePID = trackQA.tpcdEdxNorm(); + } + } + //_________________________________________________________ + + double hadronicRate; + int occupancy; + if (trk.has_collision()) { + auto collision = cols.iteratorAt(trk.collisionId()); + hadronicRate = hadronicRateForCollision[trk.collisionId()]; + occupancy = collision.trackOccupancyInTimeRange(); + } else { + hadronicRate = hadronicRateBegin; + occupancy = 0; + } + + constexpr float kExpectedTPCSignalMIP = 50.0f; + constexpr float kMaxAllowedRatio = 1.05f; + constexpr float kMinAllowedRatio = 0.05f; + constexpr float kMaxAllowedOcc = 12.0f; + + float fTPCSignal = tpcSignalToEvaluatePID; + float fNormMultTPC = multTPC / 11000.; + + float fTrackOccN = occupancy / 1000.; + float fOccTPCN = fNormMultTPC * 10; //(fNormMultTPC*10).clip(0,12) + if (fOccTPCN > kMaxAllowedOcc) + fOccTPCN = kMaxAllowedOcc; + else if (fOccTPCN < 0) + fOccTPCN = 0; + + float fTrackOccMeanN = hadronicRate / 5; + float side = trk.tgl() > 0 ? 1 : 0; + float a1pt = std::abs(trk.signed1Pt()); + float a1pt2 = a1pt * a1pt; + float atgl = std::abs(trk.tgl()); + float mbb0R = kExpectedTPCSignalMIP / fTPCSignal; + if (mbb0R > kMaxAllowedRatio) + mbb0R = kMaxAllowedRatio; + else if (mbb0R < kMinAllowedRatio) + mbb0R = kMinAllowedRatio; + // float mbb0R = max(0.05, min(50 / fTPCSignal, 1.05)); + float a1ptmbb0R = a1pt * mbb0R; + float atglmbb0R = atgl * mbb0R; + + std::vector vec_occu = {fTrackOccN, fOccTPCN, fTrackOccMeanN}; + std::vector vec_track = {mbb0R, a1pt, atgl, atglmbb0R, a1ptmbb0R, side, a1pt2}; + + float fTPCSignalN_CR0 = str_dedx_correction.fReal_fTPCSignalN(vec_occu, vec_track); + + float mbb0R1 = kExpectedTPCSignalMIP / (fTPCSignal / fTPCSignalN_CR0); + if (mbb0R1 > kMaxAllowedRatio) + mbb0R1 = kMaxAllowedRatio; + else if (mbb0R1 < kMinAllowedRatio) + mbb0R1 = kMinAllowedRatio; + + std::vector vec_track1 = {mbb0R1, a1pt, atgl, atgl * mbb0R1, a1pt * mbb0R1, side, a1pt2}; + float fTPCSignalN_CR1 = str_dedx_correction.fReal_fTPCSignalN(vec_occu, vec_track1); + + // change the signal used for PID + tpcSignalToEvaluatePID = fTPCSignal / fTPCSignalN_CR1; + + if (pidTPCopts.savedEdxsCorrected) { + // populated cursor if requested or autodetected + products.dEdxCorrected(tpcSignalToEvaluatePID); + } + } + + const auto& bc = trk.has_collision() ? cols.rawIteratorAt(trk.collisionId()).template bc_as() : bcs.begin(); + if (useCCDBParam && pidTPCopts.ccdbTimestamp.value == 0 && !ccdb->isCachedObjectValid(pidTPCopts.ccdbPath.value, bc.timestamp())) { // Updating parametrisation only if the initial timestamp is 0 + if (pidTPCopts.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(), pidTPCopts.recoPass.value); + } + response = ccdb->template getSpecific(pidTPCopts.ccdbPath.value, bc.timestamp(), metadata); + headers = ccdbApi.retrieveHeaders(pidTPCopts.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->template getForTimeStamp(pidTPCopts.ccdbPath.value, bc.timestamp()); + headers = ccdbApi.retrieveHeaders(pidTPCopts.ccdbPath.value, nullmetadata, 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"]; + o2::parameters::GRPLHCIFData* grpo = ccdb->template getForTimeStamp(pidTPCopts.cfgPathGrpLhcIf.value, bc.timestamp()); + if (grpo) { + LOG(info) << "Collisions type::" << CollisionSystemType::getCollisionTypeFromGrp(grpo); + collsys = CollisionSystemType::getCollisionTypeFromGrp(grpo); + if (collsys == CollisionSystemType::kCollSyspp) { + irSource = std::string("T0VTX"); + } else { + irSource = std::string("ZNC hadronic"); + } + } else { + LOGF(info, "No grpo object found. irSource will remain undefined."); + } + response->PrintAll(); + } + + // if this is a MC process function, go for MC tune on data processing + if constexpr (requires { trk.mcParticleId(); }) { + // Perform TuneOnData sampling for MC dE/dx + if (!trk.has_mcParticle()) { + products.tableTuneOnData(-999.f); + tpcSignalToEvaluatePID = -999.f; // pass this for further eval + } else { + float mcTunedTPCSignal = 0.; + if (!trk.hasTPC()) { + mcTunedTPCSignal = -999.f; + } else { + if (pidTPCopts.skipTPCOnly) { + if (!trk.hasITS() && !trk.hasTRD() && !trk.hasTOF()) { + mcTunedTPCSignal = -999.f; + } + } + int pid = getPIDIndex(trk.mcParticle().pdgCode()); + + auto expSignal = response->GetExpectedSignal(trk, pid); + auto expSigma = response->GetExpectedSigmaAtMultiplicity(multTPC, 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 (pidTPCopts.useNetworkCorrection && speciesNetworkFlags[pid] && trk.has_collision() && bg > pidTPCopts.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 { + mcTunedTPCSignal = gRandom->Gaus(mean, sigma); + } + } else { + mcTunedTPCSignal = gRandom->Gaus(expSignal, expSigma); + } + } + tpcSignalToEvaluatePID = mcTunedTPCSignal; // pass this for further eval + if (pidTPCopts.enableTuneOnDataTable) + products.tableTuneOnData(mcTunedTPCSignal); + } + } + + auto makePidTablesDefault = [&trk, &tpcSignalToEvaluatePID, &multTPC, &network_prediction, &count_tracks, &tracksForNet_size, this](const int flagFull, auto& tableFull, const int flagTiny, auto& tableTiny, const o2::track::PID::ID pid) { + this->makePidTables(flagFull, tableFull, flagTiny, tableTiny, pid, tpcSignalToEvaluatePID, trk, multTPC, network_prediction, count_tracks, tracksForNet_size); + }; + + makePidTablesDefault(pidTPCopts.pidFullEl, products.tablePIDFullEl, pidTPCopts.pidTinyEl, products.tablePIDTinyEl, o2::track::PID::Electron); + makePidTablesDefault(pidTPCopts.pidFullMu, products.tablePIDFullMu, pidTPCopts.pidTinyMu, products.tablePIDTinyMu, o2::track::PID::Muon); + makePidTablesDefault(pidTPCopts.pidFullPi, products.tablePIDFullPi, pidTPCopts.pidTinyPi, products.tablePIDTinyPi, o2::track::PID::Pion); + makePidTablesDefault(pidTPCopts.pidFullKa, products.tablePIDFullKa, pidTPCopts.pidTinyKa, products.tablePIDTinyKa, o2::track::PID::Kaon); + makePidTablesDefault(pidTPCopts.pidFullPr, products.tablePIDFullPr, pidTPCopts.pidTinyPr, products.tablePIDTinyPr, o2::track::PID::Proton); + makePidTablesDefault(pidTPCopts.pidFullDe, products.tablePIDFullDe, pidTPCopts.pidTinyDe, products.tablePIDTinyDe, o2::track::PID::Deuteron); + makePidTablesDefault(pidTPCopts.pidFullTr, products.tablePIDFullTr, pidTPCopts.pidTinyTr, products.tablePIDTinyTr, o2::track::PID::Triton); + makePidTablesDefault(pidTPCopts.pidFullHe, products.tablePIDFullHe, pidTPCopts.pidTinyHe, products.tablePIDTinyHe, o2::track::PID::Helium3); + makePidTablesDefault(pidTPCopts.pidFullAl, products.tablePIDFullAl, pidTPCopts.pidTinyAl, products.tablePIDTinyAl, o2::track::PID::Alpha); + + if (trk.hasTPC() && (!pidTPCopts.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) + } + } + } // end process function +}; + +} // namespace pid +} // namespace o2::aod + +#endif // COMMON_TOOLS_PID_PIDTPCMODULE_H_ diff --git a/Common/Tools/StandardCCDBLoader.h b/Common/Tools/StandardCCDBLoader.h new file mode 100644 index 00000000000..058342ce527 --- /dev/null +++ b/Common/Tools/StandardCCDBLoader.h @@ -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 StandardCCDBLoader.cxx +/// \brief A simple object to handle ccdb queries +/// \author ALICE + +#ifndef COMMON_TOOLS_STANDARDCCDBLOADER_H_ +#define COMMON_TOOLS_STANDARDCCDBLOADER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +//__________________________________________ +// Standard class to load stuff +// such as matLUT, B and mean Vertex +// partial requests possible. + +namespace o2 +{ +namespace common +{ + +// ConfigurableGroup with locations +struct StandardCCDBLoaderConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "ccdb"; + o2::framework::Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + o2::framework::Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + o2::framework::Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; +}; + +class StandardCCDBLoader +{ + public: + StandardCCDBLoader() + { + // constructor - null pointers + mMeanVtx = nullptr; + grpmag = nullptr; + lut = nullptr; + }; + + // commonly needed objects + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; + o2::parameters::GRPMagField* grpmag = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + int runNumber = -1; + + template + void initCCDBfromBCs(TConfigurableGroup const& cGroup, TCCDB& ccdb, TBCs& bcs, bool getMeanVertex = true) + { + // instant load from BCs table. Bonus: protect also against empty bcs + if (bcs.size() == 0) { + return; + } + auto bc = bcs.begin(); + initCCDB(cGroup, ccdb, bc.runNumber(), getMeanVertex); + } + + template + void initCCDB(TConfigurableGroup const& cGroup, TCCDB& ccdb, int currentRunNumber, bool getMeanVertex = true) + { + if (runNumber == currentRunNumber) { + return; + } + + grpmag = ccdb->template getForRun(cGroup.grpmagPath.value, currentRunNumber); + if (grpmag) { + LOG(info) << "Setting global propagator magnetic field to current " << grpmag->getL3Current() << " A for run " << currentRunNumber << " from its GRPMagField CCDB object"; + o2::base::Propagator::initFieldFromGRP(grpmag); + } else { + LOGF(info, "GRPMagField object returned nullptr, will attempt alternate method"); + + o2::parameters::GRPObject* grpo = 0x0; + grpo = ccdb->template getForRun(cGroup.grpPath.value, currentRunNumber); + if (!grpo) { + LOG(fatal) << "Alternate path failed! Got nullptr from CCDB for path " << cGroup.grpPath << " of object GRPObject for run " << currentRunNumber; + } + o2::base::Propagator::initFieldFromGRP(grpo); + } + if (getMeanVertex) { + // only try this if explicitly requested + mMeanVtx = ccdb->template getForRun(cGroup.mVtxPath.value, currentRunNumber); + } else { + mMeanVtx = nullptr; + } + + // load matLUT for this timestamp + if (!lut) { + LOG(info) << "Loading material look-up table for timestamp: " << currentRunNumber; + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->template getForRun(cGroup.lutPath.value, currentRunNumber)); + } else { + LOG(info) << "Material look-up table already in place. Not reloading."; + } + LOG(info) << "Setting global propagator material propagation LUT"; + o2::base::Propagator::Instance()->setMatLUT(lut); + + runNumber = currentRunNumber; + } +}; + +} // namespace common +} // namespace o2 + +#endif // COMMON_TOOLS_STANDARDCCDBLOADER_H_ diff --git a/Common/Tools/TrackPropagationModule.h b/Common/Tools/TrackPropagationModule.h new file mode 100644 index 00000000000..22474641354 --- /dev/null +++ b/Common/Tools/TrackPropagationModule.h @@ -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 TrackPropagationModule.h +/// \brief track propagation module functionality to be used in core services +/// \author ALICE + +#ifndef COMMON_TOOLS_TRACKPROPAGATIONMODULE_H_ +#define COMMON_TOOLS_TRACKPROPAGATIONMODULE_H_ + +#include "Common/Core/TableHelper.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Tools/TrackTuner.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +//__________________________________________ +// track propagation module +// +// this class is capable of performing the usual track propagation +// and table creation it is a demonstration of core service +// plug-in functionality that could be used to reduce the number of +// heavyweight (e.g. mat-LUT-using, propagating) core services to +// reduce overhead and make it easier to pipeline / parallelize +// bottlenecks in core services + +namespace o2 +{ +namespace common +{ + +struct TrackPropagationProducts : o2::framework::ProducesGroup { + o2::framework::Produces tracksParPropagated; + o2::framework::Produces tracksParExtensionPropagated; + o2::framework::Produces tracksParCovPropagated; + o2::framework::Produces tracksParCovExtensionPropagated; + o2::framework::Produces tracksDCA; + o2::framework::Produces tracksDCACov; + o2::framework::Produces tunertable; +}; + +struct TrackPropagationConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "trackPropagation"; + o2::framework::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) + o2::framework::Configurable useTrackTuner{"useTrackTuner", false, "Apply track tuner corrections to MC"}; + o2::framework::Configurable useTrkPid{"useTrkPid", false, "use pid in tracking"}; + o2::framework::Configurable fillTrackTunerTable{"fillTrackTunerTable", false, "flag to fill track tuner table"}; + o2::framework::Configurable trackTunerConfigSource{"trackTunerConfigSource", aod::track_tuner::InputString, "1: input string; 2: TrackTuner Configurables"}; + o2::framework::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: =|=)"}; + o2::framework::ConfigurableAxis axisPtQA{"axisPtQA", {o2::framework::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"}; +}; + +class TrackPropagationModule +{ + public: + TrackPropagationModule() + { + // constructor + } + + // controls behaviour + bool fillTracks = false; + bool fillTracksCov = false; + bool fillTracksDCA = false; + bool fillTracksDCACov = false; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + + // pointers to objs needed for operation + std::shared_ptr trackTunedTracks; + + // Running variables + std::array mDcaInfo{}; + o2::dataformats::DCA mDcaInfoCov; + o2::dataformats::VertexBase mVtx; + o2::track::TrackParametrization mTrackPar; + o2::track::TrackParametrizationWithError mTrackParCov; + bool autoDetectDcaCalib = false; // track tuner setting + + template + void init(TConfigurableGroup const& cGroup, TrackTuner& trackTunerObj, THistoRegistry& registry, TInitContext& initContext) + { + // Checking if the tables are requested in the workflow and enabling them + fillTracks = isTableRequiredInWorkflow(initContext, "Tracks"); + fillTracksCov = isTableRequiredInWorkflow(initContext, "TracksCov"); + fillTracksDCA = isTableRequiredInWorkflow(initContext, "TracksDCA"); + fillTracksDCACov = isTableRequiredInWorkflow(initContext, "TracksDCACov"); + + // enable Tracks in case Tracks have been requested + if (fillTracksDCA && !fillTracks) { + LOGF(info, "******************************************************************"); + LOGF(info, " There is no task subscribed to Tracks, but I have detected a"); + LOGF(info, " subscription to TracksDCA. Now enabling tracks as algorithmic"); + LOGF(info, " dependency. Note: please be sure this is intentional! For"); + LOGF(info, " secondary analyses, the proper DCA to test against is the DCA"); + LOGF(info, " that the V0 or Cascade is assigned to and not necessarily the"); + LOGF(info, " the one that the Track is assigned to (if any). "); + LOGF(info, "******************************************************************"); + fillTracks = true; + } + + if (!fillTracks) { + LOGF(info, "Track propagation to PV not required. Suppressing all further processing and logs."); + } + + LOGF(info, " Track propagation table detection results:"); + if (fillTracks) { + LOGF(info, " ---> Will generate Tracks table."); + } + if (fillTracksCov) { + LOGF(info, " ---> Will generate TracksCov table."); + } + if (fillTracksDCA) { + LOGF(info, " ---> Will generate TracksDCA table."); + } + if (fillTracksDCACov) { + LOGF(info, " ---> Will generate TracksDCACov table."); + } + if (fillTracksCov) { + LOGF(info, "**************************************************************"); + LOGF(info, " Warning: TracksCov has been requested due to a subscription!"); + LOGF(info, " Please be mindful that generating track covariances requires"); + LOGF(info, " a significant extra amount of CPU and memory. If not strictly"); + LOGF(info, " necessary, requesting TracksCov should be avoided to save"); + LOGF(info, " these additional resouces."); + LOGF(info, "**************************************************************"); + } + + /// TrackTuner initialization + std::string outputStringParams = ""; + if (cGroup.useTrackTuner.value) { + switch (cGroup.trackTunerConfigSource.value) { + case o2::aod::track_tuner::InputString: + outputStringParams = trackTunerObj.configParams(cGroup.trackTunerParams.value); + break; + case o2::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; + } + + /// read the track tuner instance configurations, + /// to understand whether the TrackTuner::getDcaGraphs function can be called here (input path from string/configurables) + /// or inside the process function, to "auto-detect" the input file based on the run number + const auto& workflows = initContext.services().template get(); + for (const o2::framework::DeviceSpec& device : workflows.devices) { /// loop over devices + if (device.name == "propagation-service") { + // loop over the options + // to find the value of TrackTuner::autoDetectDcaCalib + for (const auto& option : device.options) { /// loop over options + if (option.name == "trackTuner.autoDetectDcaCalib") { + // found it! + autoDetectDcaCalib = option.defaultValue.get(); + break; + } + } /// end loop over options + break; + } + } /// end loop over devices + LOG(info) << "[TrackPropagationModule] trackTuner.autoDetectDcaCalib it's equal to " << autoDetectDcaCalib; + if (!autoDetectDcaCalib) { + LOG(info) << "[TrackPropagationModule] retrieve the graphs already (we are in propagationService::Init() function)"; + trackTunerObj.getDcaGraphs(); + } else { + LOG(info) << "[TrackPropagationModule] trackTunerObj.getDcaGraphs() function to be called later, in the process function!"; + } + } + + trackTunedTracks = registry.template add("trackTunedTracks", outputStringParams.c_str(), o2::framework::kTH1D, {{1, 0.5f, 1.5f}}); + + // Histograms for track tuner + o2::framework::AxisSpec axisBinsDCA = {600, -0.15f, 0.15f, "#it{dca}_{xy} (cm)"}; + registry.template add("hDCAxyVsPtRec", "hDCAxyVsPtRec", o2::framework::kTH2F, {axisBinsDCA, cGroup.axisPtQA}); + registry.template add("hDCAxyVsPtMC", "hDCAxyVsPtMC", o2::framework::kTH2F, {axisBinsDCA, cGroup.axisPtQA}); + registry.template add("hDCAzVsPtRec", "hDCAzVsPtRec", o2::framework::kTH2F, {axisBinsDCA, cGroup.axisPtQA}); + registry.template add("hDCAzVsPtMC", "hDCAzVsPtMC", o2::framework::kTH2F, {axisBinsDCA, cGroup.axisPtQA}); + } + + template + void fillTrackTables(TConfigurableGroup const& cGroup, TrackTuner& trackTunerObj, TCCDBLoader const& ccdbLoader, TCollisions const& collisions, TTracks const& tracks, TOutputGroup& cursors, THistoRegistry& registry) + { + + /// retrieve the TrackTuner calibration graphs *if not done yet* + /// i.e. if autodetect is required + if (cGroup.useTrackTuner.value && autoDetectDcaCalib && !trackTunerObj.areGraphsConfigured) { + + /// get the run number from the ccdb loader, already initialized + const int runNumber = ccdbLoader.runNumber; + trackTunerObj.setRunNumber(runNumber); + + /// setup the "auto-detected" path based on the run number + trackTunerObj.getPathInputFileAutomaticFromCCDB(); + trackTunedTracks->SetTitle(trackTunerObj.outputString.c_str()); + + /// now that the path is ok, retrieve the graphs + trackTunerObj.getDcaGraphs(); + } + + if (!fillTracks) { + return; // suppress everything + } + + if (fillTracksCov) { + cursors.tracksParCovPropagated.reserve(tracks.size()); + cursors.tracksParCovExtensionPropagated.reserve(tracks.size()); + if (fillTracksDCACov) { + cursors.tracksDCACov.reserve(tracks.size()); + } + } else { + cursors.tracksParPropagated.reserve(tracks.size()); + cursors.tracksParExtensionPropagated.reserve(tracks.size()); + if (fillTracksDCA) { + cursors.tracksDCA.reserve(tracks.size()); + } + } + + for (const auto& track : tracks) { + if (fillTracksCov) { + if (fillTracksDCA || fillTracksDCACov) { + mDcaInfoCov.set(999, 999, 999, 999, 999); + } + setTrackParCov(track, mTrackParCov); + if (cGroup.useTrkPid.value) { + mTrackParCov.setPID(track.pidForTracking()); + } + } else { + if (fillTracksDCA) { + mDcaInfo[0] = 999; + mDcaInfo[1] = 999; + } + setTrackPar(track, mTrackPar); + if (cGroup.useTrkPid.value) { + mTrackPar.setPID(track.pidForTracking()); + } + } + // auto trackParCov = getTrackParCov(track); + o2::aod::track::TrackTypeEnum trackType = (o2::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() == o2::aod::track::TrackIU && track.x() < cGroup.minPropagationRadius.value) { + if (fillTracksCov) { + if constexpr (isMc) { // checking MC and fillCovMat block begins + // bool hasMcParticle = track.has_mcParticle(); + if (cGroup.useTrackTuner.value) { + trackTunedTracks->Fill(1); // all tracks + bool hasMcParticle = track.has_mcParticle(); + if (hasMcParticle) { + auto mcParticle = track.mcParticle(); + trackTunerObj.tuneTrackParams(mcParticle, mTrackParCov, matCorr, &mDcaInfoCov, trackTunedTracks); + q2OverPtNew = mTrackParCov.getQ2Pt(); + } + } + } // MC and fillCovMat block ends + } + bool isPropagationOK = true; + + if (track.has_collision()) { + auto const& collision = collisions.rawIteratorAt(track.collisionId()); + if (fillTracksCov) { + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCov, 2.f, matCorr, &mDcaInfoCov); + } else { + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); + } + } else { + if (fillTracksCov) { + mVtx.setPos({ccdbLoader.mMeanVtx->getX(), ccdbLoader.mMeanVtx->getY(), ccdbLoader.mMeanVtx->getZ()}); + mVtx.setCov(ccdbLoader.mMeanVtx->getSigmaX() * ccdbLoader.mMeanVtx->getSigmaX(), 0.0f, ccdbLoader.mMeanVtx->getSigmaY() * ccdbLoader.mMeanVtx->getSigmaY(), 0.0f, 0.0f, ccdbLoader.mMeanVtx->getSigmaZ() * ccdbLoader.mMeanVtx->getSigmaZ()); + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCov, 2.f, matCorr, &mDcaInfoCov); + } else { + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz({ccdbLoader.mMeanVtx->getX(), ccdbLoader.mMeanVtx->getY(), ccdbLoader.mMeanVtx->getZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); + } + } + if (isPropagationOK) { + trackType = o2::aod::track::Track; + } + // filling some QA histograms for track tuner test purpose + if (fillTracksCov) { + if constexpr (isMc) { // 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 (cGroup.useTrackTuner.value && cGroup.fillTrackTunerTable.value) { + cursors.tunertable(q2OverPtNew); + } + // LOG(info) << " trackPropagation (this value filled in tuner table)--> " << q2OverPtNew; + if (fillTracksCov) { + cursors.tracksParPropagated(track.collisionId(), trackType, mTrackParCov.getX(), mTrackParCov.getAlpha(), mTrackParCov.getY(), mTrackParCov.getZ(), mTrackParCov.getSnp(), mTrackParCov.getTgl(), mTrackParCov.getQ2Pt()); + cursors.tracksParExtensionPropagated(mTrackParCov.getPt(), mTrackParCov.getP(), mTrackParCov.getEta(), mTrackParCov.getPhi()); + // TODO do we keep the rho as 0? Also the sigma's are duplicated information + cursors.tracksParCovPropagated(std::sqrt(mTrackParCov.getSigmaY2()), std::sqrt(mTrackParCov.getSigmaZ2()), std::sqrt(mTrackParCov.getSigmaSnp2()), + std::sqrt(mTrackParCov.getSigmaTgl2()), std::sqrt(mTrackParCov.getSigma1Pt2()), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + cursors.tracksParCovExtensionPropagated(mTrackParCov.getSigmaY2(), mTrackParCov.getSigmaZY(), mTrackParCov.getSigmaZ2(), mTrackParCov.getSigmaSnpY(), + mTrackParCov.getSigmaSnpZ(), mTrackParCov.getSigmaSnp2(), mTrackParCov.getSigmaTglY(), mTrackParCov.getSigmaTglZ(), mTrackParCov.getSigmaTglSnp(), + mTrackParCov.getSigmaTgl2(), mTrackParCov.getSigma1PtY(), mTrackParCov.getSigma1PtZ(), mTrackParCov.getSigma1PtSnp(), mTrackParCov.getSigma1PtTgl(), + mTrackParCov.getSigma1Pt2()); + if (fillTracksDCA) { + cursors.tracksDCA(mDcaInfoCov.getY(), mDcaInfoCov.getZ()); + } + if (fillTracksDCACov) { + cursors.tracksDCACov(mDcaInfoCov.getSigmaY2(), mDcaInfoCov.getSigmaZ2()); + } + } else { + cursors.tracksParPropagated(track.collisionId(), trackType, mTrackPar.getX(), mTrackPar.getAlpha(), mTrackPar.getY(), mTrackPar.getZ(), mTrackPar.getSnp(), mTrackPar.getTgl(), mTrackPar.getQ2Pt()); + cursors.tracksParExtensionPropagated(mTrackPar.getPt(), mTrackPar.getP(), mTrackPar.getEta(), mTrackPar.getPhi()); + if (fillTracksDCA) { + cursors.tracksDCA(mDcaInfo[0], mDcaInfo[1]); + } + } + } + } +}; + +} // namespace common +} // namespace o2 + +#endif // COMMON_TOOLS_TRACKPROPAGATIONMODULE_H_ diff --git a/Common/Tools/TrackTuner.h b/Common/Tools/TrackTuner.h index 617c2602c97..4eef7d6d434 100644 --- a/Common/Tools/TrackTuner.h +++ b/Common/Tools/TrackTuner.h @@ -18,44 +18,66 @@ #ifndef COMMON_TOOLS_TRACKTUNER_H_ #define COMMON_TOOLS_TRACKTUNER_H_ +#include +#include +#include +#include // FIXME: remove +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include #include #include #include #include #include -#include - -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" -#include "CommonConstants/GeomConstants.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "CommonUtils/NameConf.h" -#include "DataFormatsCalibration/MeanVertexObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/Track.h" -#include 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 { +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"}; + o2::framework::Configurable cfgAutoDetectDcaCalib{"autoDetectDcaCalib", false, "Flag to enable the dca-calibration file autodetect from CCDB (list of predefined cases)"}; /////////////////////////////// /// parameters to be configured bool debugInfo = false; @@ -66,43 +88,171 @@ struct TrackTuner { 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 and MC - std::string nameInputFile = ""; // Common Name of different files containing graphs, found in the above paths - std::string pathFileQoverPt = ""; // Path to file containing D0 sigma 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 qOverPtMC = -1.; // 1/pt old - float qOverPtData = -1.; // 1/pt new + float qOverPtMC = -1.; // 1/pt MC + float qOverPtData = -1.; // 1/pt data + bool autoDetectDcaCalib = false; // enable automatic pick-up of dca calibration files from CCDB (list of predefined cases) /////////////////////////////// + bool isConfigFromString = false; + bool isConfigFromConfigurables = false; + int nPhiBins = 1; + int runNumber = 0; // first run number considered in analysis (useful only if autoDetectDcaCalib = true) + bool areGraphsConfigured = false; + std::string outputString = ""; - o2::ccdb::CcdbApi ccdbApi; std::map metadata; - std::unique_ptr grDcaXYResVsPtPionMC; - std::unique_ptr grDcaXYResVsPtPionData; + std::vector> grDcaXYResVsPtPionMC; + std::vector> grDcaXYResVsPtPionData; - std::unique_ptr grDcaZResVsPtPionMC; - std::unique_ptr grDcaZResVsPtPionData; + std::vector> grDcaZResVsPtPionMC; + std::vector> grDcaZResVsPtPionData; - std::unique_ptr grDcaXYMeanVsPtPionMC; - std::unique_ptr grDcaXYMeanVsPtPionData; + std::vector> grDcaXYMeanVsPtPionMC; + std::vector> grDcaXYMeanVsPtPionData; - std::unique_ptr grDcaZMeanVsPtPionMC; - std::unique_ptr grDcaZMeanVsPtPionData; + std::vector> grDcaZMeanVsPtPionMC; + std::vector> grDcaZMeanVsPtPionData; std::unique_ptr grOneOverPtPionMC; // MC std::unique_ptr grOneOverPtPionData; // Data - std::unique_ptr grDcaXYPullVsPtPionMC; - std::unique_ptr grDcaXYPullVsPtPionData; + std::vector> grDcaXYPullVsPtPionMC; + std::vector> grDcaXYPullVsPtPionData; - std::unique_ptr grDcaZPullVsPtPionMC; - std::unique_ptr grDcaZPullVsPtPionData; + std::vector> grDcaZPullVsPtPionMC; + std::vector> grDcaZPullVsPtPionData; - /// @brief Function to configure the TrackTuner parameters + /// @brief Function to initialize the run number to that of the 1st considered bunch crossing (useful only if autoDetectDcaCalib = true) + void setRunNumber(int n) + { + runNumber = n; + } + + /// @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."; + } + } + + void getPathInputFileAutomaticFromCCDB() + { + + /// check: no CCDB autodetection if the desired input file is not in CCDB + if (!isInputFileFromCCDB) { + LOG(fatal) << "[TrackTuner::getPathInputFileAutomaticFromCCDB] Trying to auto detect the dca calibration file from CCDB, but you ask the input file to not come from CCDB (isInputFileFromCCDB==" << isInputFileFromCCDB << "). Fix it!"; + } + /// check that the run number has been already properly set + if (runNumber == 0) { + LOG(fatal) << "[TrackTuner::getPathInputFileAutomaticFromCCDB] runNumber==" << runNumber << ", automatic detection of dca calibration file from CCDB not possible. Did you call the function TrackTuner::setrunNumber()?"; + } + /// check than the number of phi bins for the track tuner calibrations is 24 + if (nPhiBins != 24) { + LOG(fatal) << "[TrackTuner::getPathInputFileAutomaticFromCCDB] nPhiBins==" << nPhiBins << ", but the automatic detection of dca calibration file from CCDB is supported only for nPhiBins==24. Either put nPhiBins=24, or disable the auto-detection (autoDetectDcaCalib=false)"; + } + + pathInputFile = "invalid"; + + /////////////////////////////////////////////////////////////////////////// + /// /// + /// establish some pre-defined cases based only on the run numbers /// + /// /// + /////////////////////////////////////////////////////////////////////////// + LOG(info) << ""; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ TrackTuner configuration +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Autodetect mode activated for the DCA calibration files +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ The DCA calibration files are picked-up from CCDB based on the analysed run number +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ NB: only the number of the first analysed run is considered to configure the TrackTuner object +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Supported cases: +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ [CASE 1]: pp, 13.6 TeV 2022, 2023: CCDB path Users/m/mfaggin/test/inputsTrackTuner/pp2023/pass4/vsPhi +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: (520259 (LHC22f) <= runNumber <= 529691 (LHC22t)) || (534998 (LHC23zc) <= runNumber <= 543113 (LHC23zw)) +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ [CASE 2]: Pb-Pb, 5.34 TeV 2022, 2023, 2024: CCDB path Users/m/mfaggin/test/inputsTrackTuner/PbPb2023/apass4/vsPhi +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: (529397 <= runNumber <= 529418 (LHC22o)) || (543437 (LHC23zx) <= runNumber <= 545367 (LHC23zzo)) +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ [CASE 3]: pp, 13.6 TeV 2024: CCDB path Users/m/mfaggin/test/inputsTrackTuner/pp2024/pass1_minBias/vsPhi +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: 549559 (LHC24ac) <= runNumber && runNumber <= 558807 (LHC24ao) +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ [CASE 4]: OO, 5.36 TeV 2025, period LHC25ae: CCDB path Users/m/mfaggin/test/inputsTrackTuner/OO/LHC25ae +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: 564356 <= runNumber && runNumber <= 564445 +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ [CASE 5]: OO, 5.36 TeV 2025, period LHC25af: CCDB path Users/m/mfaggin/test/inputsTrackTuner/OO/LHC25af +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++ Run list: 564468 <= runNumber && runNumber <= 564472 +++"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; + LOG(info) << ""; + + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: current run number = " << runNumber; + + if ((520259 <= runNumber && runNumber <= 529691) || (534998 <= runNumber && runNumber <= 543113)) { + /// + /// [CASE 1]: pp, 13.6 TeV 2022, 2023: CCDB path Users/m/mfaggin/test/inputsTrackTuner/pp2023/pass4/vsPhi + /// Run list: (520259 (LHC22f) <= runNumber <= 529691 (LHC22t)) || (534998 (LHC23zc) <= runNumber <= 543113 (LHC23zw)) + /// + pathInputFile = "Users/m/mfaggin/test/inputsTrackTuner/pp2023/pass4/vsPhi"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: >>> pp, 13.6 TeV 2022, 2023: CCDB path " << pathInputFile; + LOG(info) << " >>> Run list: (520259 (LHC22f) <= runNumber <= 529691 (LHC22t)) || (534998 (LHC23zc) <= runNumber <= 543113 (LHC23zw))"; + } else if ((529397 <= runNumber && runNumber <= 529418) || (543437 <= runNumber && runNumber <= 545367)) { + /// + /// [CASE 2]: Pb-Pb, 5.34 TeV 2022, 2023, 2024: CCDB path Users/m/mfaggin/test/inputsTrackTuner/PbPb2023/apass4/vsPhi + /// Run list: (529397 <= runNumber <= 529418 (LHC22o)) || (543437 (LHC23zx) <= runNumber <= 545367 (LHC23zzo)) + /// + pathInputFile = "Users/m/mfaggin/test/inputsTrackTuner/PbPb2023/apass4/vsPhi"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: >>> Pb-Pb, 5.34 TeV 2022, 2023, 2024: CCDB path " << pathInputFile; + LOG(info) << " >>> Run list: (529397 <= runNumber <= 529418 (LHC22o)) || (543437 (LHC23zx) <= runNumber <= 545367 (LHC23zzo))"; + } else if (549559 <= runNumber && runNumber <= 558807) { + /// + /// [CASE 3]: pp, 13.6 TeV 2024: CCDB path Users/m/mfaggin/test/inputsTrackTuner/pp2024/pass1_minBias/vsPhi + /// Run list: 549559 (LHC24ac) <= runNumber && runNumber <= 558807 (LHC24ao) + /// + pathInputFile = "Users/m/mfaggin/test/inputsTrackTuner/pp2024/pass1_minBias/vsPhi"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: >>> pp, 13.6 TeV 2024: CCDB path " << pathInputFile; + LOG(info) << " >>> Run list: 549559 (LHC24ac) <= runNumber && runNumber <= 558807 (LHC24ao)"; + } else if (564356 <= runNumber && runNumber <= 564445) { + /// + /// [CASE 4]: OO, 5.36 TeV 2025, period LHC25ae: CCDB path Users/m/mfaggin/test/inputsTrackTuner/OO/LHC25ae + /// Run list: 564356 <= runNumber && runNumber <= 564445 + /// + pathInputFile = "Users/m/mfaggin/test/inputsTrackTuner/OO/LHC25ae"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: >>> OO, 5.36 TeV 2025, period LHC25ae: CCDB path " << pathInputFile; + LOG(info) << " >>> Run list: 564356 <= runNumber && runNumber <= 564445"; + } else if (564468 <= runNumber && runNumber <= 564472) { + /// + /// [CASE 5]: OO, 5.36 TeV 2025, period LHC25af: CCDB path Users/m/mfaggin/test/inputsTrackTuner/OO/LHC25af + /// Run list: 564468 <= runNumber && runNumber <= 564472 + /// + pathInputFile = "Users/m/mfaggin/test/inputsTrackTuner/OO/LHC25af"; + LOG(info) << "[TrackTuner::getPathInputFileAutomaticFromCCDB]: >>> OO, 5.36 TeV 2025, period LHC25af: CCDB path " << pathInputFile; + LOG(info) << " >>> Run list: 564468 <= runNumber && runNumber <= 564472"; + } else { + LOG(fatal) << "runNumber " << runNumber << " not supported for the autodetection. Please switch to manual configuration of the TrackTuner object. Aborting..."; + } + + outputString += ", pathInputFile=" + pathInputFile; + } + + /// @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 = "="; @@ -147,6 +297,8 @@ struct TrackTuner { UsePvRefitCorrections, QOverPtMC, QOverPtData, + NPhiBins, + AutoDetectDcaCalib, NPars }; std::map mapParNames = { std::make_pair(DebugInfo, "debugInfo"), @@ -162,12 +314,14 @@ struct TrackTuner { std::make_pair(NameFileQoverPt, "nameFileQoverPt"), std::make_pair(UsePvRefitCorrections, "usePvRefitCorrections"), std::make_pair(QOverPtMC, "qOverPtMC"), - std::make_pair(QOverPtData, "qOverPtData")}; + std::make_pair(QOverPtData, "qOverPtData"), + std::make_pair(NPhiBins, "nPhiBins"), + std::make_pair(AutoDetectDcaCalib, "autoDetectDcaCalib")}; /////////////////////////////////////////////////////////////////////////////////// LOG(info) << "[TrackTuner]"; LOG(info) << "[TrackTuner] >>> Parameters before the custom settings"; LOG(info) << "[TrackTuner] debugInfo = " << debugInfo; - LOG(info) << "[TrackTuner] updateTrackDCAs = " << UpdateTrackDCAs; + LOG(info) << "[TrackTuner] updateTrackDCAs = " << updateTrackDCAs; LOG(info) << "[TrackTuner] updateTrackCovMat = " << updateTrackCovMat; LOG(info) << "[TrackTuner] updateCurvature = " << updateCurvature; LOG(info) << "[TrackTuner] updateCurvatureIU = " << updateCurvatureIU; @@ -180,6 +334,8 @@ struct TrackTuner { LOG(info) << "[TrackTuner] usePvRefitCorrections = " << usePvRefitCorrections; LOG(info) << "[TrackTuner] qOverPtMC = " << qOverPtMC; LOG(info) << "[TrackTuner] qOverPtData = " << qOverPtData; + LOG(info) << "[TrackTuner] nPhiBins = " << nPhiBins; + LOG(info) << "[TrackTuner] autoDetectDcaCalib = " << autoDetectDcaCalib; // ############################################################################################## // ######## split the original string, separating substrings delimited by "|" symbol ######## @@ -196,12 +352,12 @@ struct TrackTuner { LOG(info) << "[TrackTuner]"; LOG(info) << "[TrackTuner] >>> String slices:"; - for (std::string& s : slices) + for (const std::string& s : slices) LOG(info) << "[TrackTuner] " << s; /// 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!"; } // ################################################################################################################### @@ -210,7 +366,7 @@ struct TrackTuner { /// lambda expression to search for the parameter value (as string) in the configuration string auto getValueString = [&](uint8_t iPar) { /// this allows to search the parameter configuration even if they are not written in order - auto it = std::find_if(slices.begin(), slices.end(), [&](std::string s) { return s.find(mapParNames[iPar]) != std::string::npos; }); + auto it = std::find_if(slices.begin(), slices.end(), [&](const std::string& s) { return s.find(mapParNames[iPar]) != std::string::npos; }); if (it == std::end(slices)) { // parameter not found LOG(fatal) << "\"" << mapParNames[iPar] << "\" not found in the configuration string"; @@ -224,7 +380,7 @@ struct TrackTuner { }; /// further lambda expression to handle bool initialization - auto setBoolFromString = [=](bool& b, std::string str) { + auto setBoolFromString = [=](bool& b, const std::string& str) { if (!str.compare("1") || str.find("true") != std::string::npos || str.find("True") != std::string::npos || str.find("TRUE") != std::string::npos) { b = true; } else if (!str.compare("0") || str.find("false") != std::string::npos || str.find("False") != std::string::npos || str.find("FALSE") != std::string::npos) { @@ -234,13 +390,16 @@ struct TrackTuner { } }; - std::string outputString = ""; LOG(info) << "[TrackTuner] "; LOG(info) << "[TrackTuner] >>> Parameters after the custom settings"; + // Configure autoDetectDcaCalib + setBoolFromString(autoDetectDcaCalib, getValueString(AutoDetectDcaCalib)); + outputString += "autoDetectDcaCalib=" + std::to_string(autoDetectDcaCalib); + LOG(info) << "[TrackTuner] autoDetectDcaCalib = " << autoDetectDcaCalib; // Configure debugInfo setBoolFromString(debugInfo, getValueString(DebugInfo)); LOG(info) << "[TrackTuner] debugInfo = " << debugInfo; - outputString += "debugInfo=" + std::to_string(debugInfo); + outputString += ", debugInfo=" + std::to_string(debugInfo); // Configure updateTrackDCAs setBoolFromString(updateTrackDCAs, getValueString(UpdateTrackDCAs)); LOG(info) << "[TrackTuner] updateTrackDCAs = " << updateTrackDCAs; @@ -266,10 +425,6 @@ struct TrackTuner { LOG(info) << "[TrackTuner] isInputFileFromCCDB = " << isInputFileFromCCDB; outputString += ", isInputFileFromCCDB=" + std::to_string(isInputFileFromCCDB); // Configure pathInputFile - pathInputFile = getValueString(PathInputFile); - outputString += ", pathInputFile=" + pathInputFile; - LOG(info) << "[TrackTuner] pathInputFile = " << pathInputFile; - // Configure pathInputFile pathFileQoverPt = getValueString(PathFileQoverPt); outputString += ", pathFileQoverPt=" + pathFileQoverPt; LOG(info) << "[TrackTuner] pathFileQoverPt = " << pathFileQoverPt; @@ -293,109 +448,265 @@ struct TrackTuner { 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; + // Configure pathInputFile + if (!autoDetectDcaCalib) { + // path input file from the input string + pathInputFile = getValueString(PathInputFile); + outputString += ", pathInputFile=" + pathInputFile; + LOG(info) << "[TrackTuner] pathInputFile = " << pathInputFile; + } else { + LOG(info) << "[TrackTuner] pathInputFile still invalid for the moment --> it will be updated by the \"auto-detect\""; + } + /// declare that the configuration is done via an input string + isConfigFromString = true; - 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."; + /// 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] /=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/=/#/"; + + LOG(info) << "[TrackTuner] "; + LOG(info) << "[TrackTuner] >>> Parameters after the custom settings"; + // Configure autoDetectDcaCalib + autoDetectDcaCalib = cfgAutoDetectDcaCalib; + outputString += "autoDetectDcaCalib=" + std::to_string(autoDetectDcaCalib); + LOG(info) << "[TrackTuner] autoDetectDcaCalib = " << autoDetectDcaCalib; + // 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 pathQoverPt + 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 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; + // Configure pathInputFile + if (!autoDetectDcaCalib) { + // path input file from configurable + pathInputFile = cfgPathInputFile; + outputString += ", pathInputFile=" + pathInputFile; + LOG(info) << "[TrackTuner] pathInputFile = " << pathInputFile; + } else { + LOG(info) << "[TrackTuner] pathInputFile still invalid for the moment --> it will be updated by the \"auto-detect\""; } + /// declare that the configuration is done via the Configurables + isConfigFromConfigurables = true; + + /// sanity-checks on the configurations + checkConfig(); + return outputString; } void getDcaGraphs() { - std::string fullNameInputFile = ""; - std::string fullNameFileQoverPt = ""; + /// abort if the graphs were already loaded + if (areGraphsConfigured) { + LOG(fatal) << "[TrackTuner::getDcaGraphs()] Function already called, i.e. the calibrations are already loaded. This further call should never happen. Aborting..."; + } + + std::string fullNameInputFile = pathInputFile + std::string("/") + nameInputFile; + std::string fullNameFileQoverPt = pathFileQoverPt + std::string("/") + nameFileQoverPt; + TList* ccdb_object_dca = nullptr; + TList* ccdb_object_qoverpt = nullptr; + + std::string grOneOverPtPionNameMC = "sigmaVsPtMc"; + std::string grOneOverPtPionNameData = "sigmaVsPtData"; if (isInputFileFromCCDB) { /// use input correction file from CCDB - // properly init the ccdb - std::string tmpDir = "."; - ccdbApi.init("http://alice-ccdb.cern.ch"); - - // get the DCA correction file from CCDB - if (!ccdbApi.retrieveBlob(pathInputFile.data(), tmpDir, metadata, 0, false, nameInputFile.data())) { - LOG(fatal) << "[TrackTuner] input file for DCA corrections not found on CCDB, please check the pathInputFile and nameInputFile!"; - } + // get the TList from the DCA correction file present in CCDB + ccdb_object_dca = o2::ccdb::BasicCCDBManager::instance().get(pathInputFile); + LOG(info) << "[TrackTuner] ccdb_object_dca " << ccdb_object_dca; - // 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!"; + // get the TList from the Q/Pt correction file from CCDB + if (updateCurvature || updateCurvatureIU) { + ccdb_object_qoverpt = o2::ccdb::BasicCCDBManager::instance().get(pathFileQoverPt); + LOG(info) << "[TrackTuner] ccdb_object_qoverpt " << ccdb_object_qoverpt; } - // 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!"; + + /// open the input correction file - dca correction + TFile* inputFile = TFile::Open(fullNameInputFile.c_str(), "READ"); + if (!inputFile) { + LOG(fatal) << "[TrackTuner] Something wrong with the local input file" << fullNameInputFile << " for dca correction. Fix it!"; + } + ccdb_object_dca = dynamic_cast(inputFile->Get("ccdb_object")); + + /// open the input correction file - q/pt correction + TFile* inputFileQoverPt = TFile::Open(fullNameFileQoverPt.c_str(), "READ"); + if (!inputFileQoverPt && (updateCurvature || updateCurvatureIU)) { + LOG(fatal) << "Something wrong with the Q/Pt input file" << fullNameFileQoverPt << " for Q/Pt correction. Fix it!"; + } + ccdb_object_qoverpt = dynamic_cast(inputFileQoverPt->Get("ccdb_object")); } - // choose wheter to use corrections w/ PV refit or w/o it, and retrieve the proper TDirectory + // choose wheter to use corrections w/ PV refit or w/o it, and retrieve the proper TList std::string dir = "woPvRefit"; if (usePvRefitCorrections) { dir = "withPvRefit"; } - TDirectory* td = dynamic_cast(inputFile->Get(dir.c_str())); + TList* td = dynamic_cast(ccdb_object_dca->FindObject(dir.c_str())); if (!td) { - LOG(fatal) << "TDirectory " << td << " not found in input file" << inputFile->GetName() << ". Fix it!"; + LOG(fatal) << "[TrackTuner] TList " << td << " not found in ccdb_object_dca. Fix it!"; } - std::string grDcaXYResNameMC = "resCurrentDcaXY"; - std::string grDcaXYMeanNameMC = "meanCurrentDcaXY"; - std::string grDcaXYPullNameMC = "pullsCurrentDcaXY"; - std::string grDcaXYResNameData = "resUpgrDcaXY"; - std::string grDcaXYMeanNameData = "meanUpgrDcaXY"; - std::string grDcaXYPullNameData = "pullsUpgrDcaXY"; - - grDcaXYResVsPtPionMC.reset(dynamic_cast(td->Get(grDcaXYResNameMC.c_str()))); - grDcaXYResVsPtPionData.reset(dynamic_cast(td->Get(grDcaXYResNameData.c_str()))); - grDcaXYMeanVsPtPionMC.reset(dynamic_cast(td->Get(grDcaXYMeanNameMC.c_str()))); - grDcaXYMeanVsPtPionData.reset(dynamic_cast(td->Get(grDcaXYMeanNameData.c_str()))); - grDcaXYPullVsPtPionMC.reset(dynamic_cast(td->Get(grDcaXYPullNameMC.c_str()))); - grDcaXYPullVsPtPionData.reset(dynamic_cast(td->Get(grDcaXYPullNameData.c_str()))); - if (!grDcaXYResVsPtPionMC.get() || !grDcaXYResVsPtPionData.get() || !grDcaXYMeanVsPtPionMC.get() || !grDcaXYMeanVsPtPionData.get() || !grDcaXYPullVsPtPionMC.get() || !grDcaXYPullVsPtPionData.get()) { - LOG(fatal) << "Something wrong with the names of the correction graphs for dcaXY. Fix it!"; + int inputNphiBins = nPhiBins; + if (inputNphiBins == 0) + nPhiBins = 1; // old phi_independent settings + + // reserve memory and initialize vector for needed number of graphs + grDcaXYResVsPtPionMC.resize(nPhiBins); + grDcaXYResVsPtPionData.resize(nPhiBins); + + grDcaZResVsPtPionMC.resize(nPhiBins); + grDcaZResVsPtPionData.resize(nPhiBins); + + grDcaXYMeanVsPtPionMC.resize(nPhiBins); + grDcaXYMeanVsPtPionData.resize(nPhiBins); + + grDcaZMeanVsPtPionMC.resize(nPhiBins); + grDcaZMeanVsPtPionData.resize(nPhiBins); + + grDcaXYPullVsPtPionMC.resize(nPhiBins); + grDcaXYPullVsPtPionData.resize(nPhiBins); + + grDcaZPullVsPtPionMC.resize(nPhiBins); + grDcaZPullVsPtPionData.resize(nPhiBins); + + /// 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->FindObject(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); + }; + + if (inputNphiBins != 0) { + LOG(info) << "[TrackTuner] Loading phi-dependent XY TGraphErrors"; } + for (int iPhiBin = 0; iPhiBin < nPhiBins; ++iPhiBin) { - std::string grDcaZResNameMC = "resCurrentDcaZ"; - std::string grDcaZMeanNameMC = "meanCurrentDcaZ"; - std::string grDcaZPullNameMC = "pullsCurrentDcaZ"; - std::string grDcaZResNameData = "resUpgrDcaZ"; - std::string grDcaZMeanNameData = "meanUpgrDcaZ"; - std::string grDcaZPullNameData = "pullsUpgrDcaZ"; - - grDcaZResVsPtPionMC.reset(dynamic_cast(td->Get(grDcaZResNameMC.c_str()))); - grDcaZResVsPtPionData.reset(dynamic_cast(td->Get(grDcaZResNameData.c_str()))); - grDcaZMeanVsPtPionMC.reset(dynamic_cast(td->Get(grDcaZMeanNameMC.c_str()))); - grDcaZMeanVsPtPionData.reset(dynamic_cast(td->Get(grDcaZMeanNameData.c_str()))); - grDcaZPullVsPtPionMC.reset(dynamic_cast(td->Get(grDcaZPullNameMC.c_str()))); - grDcaZPullVsPtPionData.reset(dynamic_cast(td->Get(grDcaZPullNameData.c_str()))); - if (!grDcaZResVsPtPionMC.get() || !grDcaZResVsPtPionData.get() || !grDcaZMeanVsPtPionMC.get() || !grDcaZMeanVsPtPionData.get() || !grDcaZPullVsPtPionMC.get() || !grDcaZPullVsPtPionData.get()) { - LOG(fatal) << "Something wrong with the names of the correction graphs for dcaZ. Fix it!"; + 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")); + + 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; + } } - std::string grOneOverPtPionNameMC = "sigmaVsPtMc"; - std::string grOneOverPtPionNameData = "sigmaVsPtData"; + 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; + } + } if (updateCurvature || updateCurvatureIU) { - grOneOverPtPionMC.reset(dynamic_cast(inputFileQoverPt->Get(grOneOverPtPionNameMC.c_str()))); - grOneOverPtPionData.reset(dynamic_cast(inputFileQoverPt->Get(grOneOverPtPionNameData.c_str()))); + grOneOverPtPionMC.reset(dynamic_cast(ccdb_object_qoverpt->FindObject(grOneOverPtPionNameMC.c_str()))); + grOneOverPtPionData.reset(dynamic_cast(ccdb_object_qoverpt->FindObject(grOneOverPtPionNameData.c_str()))); } + + /// if we arrive here, it means that the graphs are all set + areGraphsConfigured = true; + } // getDcaGraphs() ends here template void tuneTrackParams(T1 const& mcparticle, T2& trackParCov, T3 const& matCorr, T4 dcaInfoCov, H hQA) { + /// abort if the calibrations are not loaded + if (!areGraphsConfigured) { + LOG(fatal) << "[TrackTuner::tuneTrackParams()] Function called, but calibration graphs not configured. Have you called the function TrackTuner::getDcaGraphs()? Aborting..."; + } + double ptMC = mcparticle.pt(); double dcaXYResMC = 0.0; // sd0rpo=0.; double dcaZResMC = 0.0; // sd0zo =0.; @@ -412,11 +723,17 @@ struct TrackTuner { double dcaZPullMC = 1.0; double dcaZPullData = 1.0; - dcaXYResMC = evalGraph(ptMC, grDcaXYResVsPtPionMC.get()); - dcaXYResData = evalGraph(ptMC, grDcaXYResVsPtPionData.get()); + // 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.get()); - dcaZResData = evalGraph(ptMC, grDcaZResVsPtPionData.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) { @@ -431,17 +748,18 @@ struct TrackTuner { 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 + } // updateCurvature, updateCurvatureIU block ends here if (updateTrackDCAs) { - dcaXYMeanMC = evalGraph(ptMC, grDcaXYMeanVsPtPionMC.get()); - dcaXYMeanData = evalGraph(ptMC, grDcaXYMeanVsPtPionData.get()); - dcaXYPullMC = evalGraph(ptMC, grDcaXYPullVsPtPionMC.get()); - dcaXYPullData = evalGraph(ptMC, grDcaXYPullVsPtPionData.get()); + dcaXYMeanMC = evalGraph(ptMC, grDcaXYMeanVsPtPionMC[phiBin].get()); + dcaXYMeanData = evalGraph(ptMC, grDcaXYMeanVsPtPionData[phiBin].get()); - dcaZPullMC = evalGraph(ptMC, grDcaZPullVsPtPionMC.get()); - dcaZPullData = evalGraph(ptMC, grDcaZPullVsPtPionData.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 ?? dcaXYResMC *= 1.e-4; @@ -550,12 +868,17 @@ struct TrackTuner { 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()); + if (debugInfo) { // LOG(info) << "mcVy " << mcparticle.vy() << std::endl; LOG(info) << "mcVxRotated " << mcVxRotated; @@ -596,7 +919,7 @@ struct TrackTuner { double deltaDcaXYmean = dcaXYMeanData - dcaXYMeanMC; // double d0rpn =d0rpmc+dd0rpn-dd0mrpn; - double trackParDcaXYTuned = trackParDcaXYMC + deltaDcaXYTuned - deltaDcaXYmean; + double trackParDcaXYTuned = trackParDcaXYMC + deltaDcaXYTuned + deltaDcaXYmean; if (debugInfo) { LOG(info) << dcaZResMC << ", " << dcaZResData << ", diff(DcaZ - DcaZMC): " << deltaDcaZ << ", diff upgraded: " << deltaDcaZTuned << ", DcaZ Data : " << trackParDcaZTuned; @@ -720,7 +1043,7 @@ struct TrackTuner { trackParCov.setCov(sigma1Pt2, 14); } } // ---> track cov matrix elements for 1/Pt ends here - } // ---> updateTrackCovMat block ends here + } // ---> updateTrackCovMat block ends here if (updatePulls) { double ratioDCAxyPulls = 1.0; @@ -828,7 +1151,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/aodDataModelGraph.cxx b/Common/Tools/aodDataModelGraph.cxx index 3b1afaba2ca..29695228220 100644 --- a/Common/Tools/aodDataModelGraph.cxx +++ b/Common/Tools/aodDataModelGraph.cxx @@ -8,16 +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. -#include -#include "Framework/AnalysisDataModel.h" + #include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "PWGJE/DataModel/Jet.h" #include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include + +#include + +#include +#include +#include + using namespace o2::framework; using namespace o2::aod; using namespace o2::soa; @@ -87,8 +96,13 @@ template Style getStyleFor() { auto label = MetadataTrait::metadata::tableLabel(); - auto entry = std::find_if(tableStyles.begin(), tableStyles.end(), [&](auto&& x) { if (std::string(label).find(x.first) != std::string::npos) { return true; -}return false; }); + auto entry = std::find_if(tableStyles.begin(), tableStyles.end(), + [&](auto&& x) { + if (std::string(label).find(x.first) != std::string::npos) { + return true; + } + return false; + }); if (entry != tableStyles.end()) { auto value = *entry; return styles[value.second]; diff --git a/Common/Tools/timestampModule.h b/Common/Tools/timestampModule.h new file mode 100644 index 00000000000..03981beccaf --- /dev/null +++ b/Common/Tools/timestampModule.h @@ -0,0 +1,157 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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_TOOLS_TIMESTAMPMODULE_H_ +#define COMMON_TOOLS_TIMESTAMPMODULE_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace o2 +{ +namespace common +{ +namespace timestamp +{ + +// timestamp configurables +struct timestampConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "timestamp"; + o2::framework::Configurable verbose{"verbose", false, "verbose mode"}; + o2::framework::Configurable fatalOnInvalidTimestamp{"fatalOnInvalidTimestamp", false, "Generate fatal error for invalid timestamps"}; + o2::framework::Configurable rct_path{"rct-path", "RCT/Info/RunInformation", "path to the ccdb RCT objects for the SOR timestamps"}; + o2::framework::Configurable orbit_reset_path{"orbit-reset-path", "CTP/Calib/OrbitReset", "path to the ccdb orbit-reset objects"}; + o2::framework::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)"}; // o2-linter: disable=name/configurable (temporary fix) +}; + +//__________________________________________ +// time stamp module +// +// class to acquire time stamps to be used in +// modular (plugin) fashion + +class TimestampModule +{ + public: + TimestampModule() + { + // constructor: initialize at defaults + lastRunNumber = 0; + orbitResetTimestamp = 0; + }; + + o2::common::timestamp::timestampConfigurables timestampOpts; + + // objects necessary during processing + std::map mapRunToOrbitReset; /// Cache of orbit reset timestamps + std::map> mapRunToRunDuration; /// Cache of run duration timestamps + int lastRunNumber; /// Last run number processed + int64_t orbitResetTimestamp; /// Orbit-reset timestamp in us + std::pair runDuration; /// Pair of SOR and EOR timestamps + + template + void init(TTimestampOpts const& external_timestampOpts, TMetadatahelper const& metadataInfo) + { + timestampOpts = external_timestampOpts; + + if (timestampOpts.isRun2MC.value == -1) { + if ((!metadataInfo.isRun3()) && metadataInfo.isMC()) { + timestampOpts.isRun2MC.value = 1; + LOG(info) << "Autosetting the Run2 MC mode based on metadata"; + } else { + timestampOpts.isRun2MC.value = 0; + } + } + } + + template + void process(TBCs const& bcs, Tccdb const& ccdb, TTimestampBuffer& timestampbuffer, TCursor& timestampTable) + { + timestampbuffer.clear(); + for (auto const& bc : bcs) { + int runNumber = bc.runNumber(); + // We need to set the orbit-reset timestamp for the run number. + // This is done with caching if the run number was already processed before. + // If not the orbit-reset timestamp for the run number is queried from CCDB and added to the cache + if (runNumber == lastRunNumber) { // The run number coincides to the last run processed + LOGF(debug, "Using orbit-reset timestamp from last call"); + } 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"); + 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 + + // clear cache to prevent interference with orbit reset queries from other code + // FIXME this should not have been a problem, to be investigated + ccdb->clearCache(timestampOpts.orbit_reset_path.value.data()); + + const bool isUnanchoredRun3MC = runNumber >= 300000 && runNumber < 500000; + if (timestampOpts.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 + orbitResetTimestamp = sorTimestamp * 1000; // from ms to us + } else if (runNumber < 300000) { // Run 2 + LOGF(debug, "Getting orbit-reset timestamp using start-of-run timestamp from CCDB"); + auto ctp = ccdb->template getSpecific>(timestampOpts.orbit_reset_path.value.data(), sorTimestamp); + orbitResetTimestamp = (*ctp)[0]; + } 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->template getSpecific>(timestampOpts.orbit_reset_path.value.data(), eorTimestamp / 2 + sorTimestamp / 2); + orbitResetTimestamp = (*ctp)[0]; + } + + // Adding the timestamp to the cache map + std::pair::iterator, bool> check; + check = mapRunToOrbitReset.insert(std::pair(runNumber, orbitResetTimestamp)); + if (!check.second) { + LOGF(fatal, "Run number %i already existed with a orbit-reset timestamp of %llu", runNumber, check.first->second); + } + 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 (timestampOpts.verbose) { + LOGF(info, "Orbit-reset timestamp for run number %i found: %llu us", runNumber, orbitResetTimestamp); + } + 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 (timestampOpts.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); + } + } + timestampbuffer.push_back(timestamp); // for buffering purposes + timestampTable(timestamp); + } + } +}; + +} // namespace timestamp +} // namespace common +} // namespace o2 + +#endif // COMMON_TOOLS_TIMESTAMPMODULE_H_ diff --git a/Common/Tools/trackSelectionRequest.cxx b/Common/Tools/trackSelectionRequest.cxx index 088eafab508..576b3bc042e 100644 --- a/Common/Tools/trackSelectionRequest.cxx +++ b/Common/Tools/trackSelectionRequest.cxx @@ -12,7 +12,9 @@ // see header for a more detailed description. #include "trackSelectionRequest.h" -#include "Framework/Logger.h" + +#include + #include std::ostream& operator<<(std::ostream& os, trackSelectionRequest const& c) @@ -108,6 +110,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 +169,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 +217,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..19d25405c38 100644 --- a/Common/Tools/trackSelectionRequest.h +++ b/Common/Tools/trackSelectionRequest.h @@ -21,18 +21,19 @@ // Because of this, it is particularly important that the cuts in this object // in an analysis! -#ifndef TRACKSELECTIONREQUEST_H -#define TRACKSELECTIONREQUEST_H +#ifndef COMMON_TOOLS_TRACKSELECTIONREQUEST_H_ +#define COMMON_TOOLS_TRACKSELECTIONREQUEST_H_ -#include #include -#include + +#include +#include class trackSelectionRequest { public: trackSelectionRequest() - : trackPhysicsType{0}, minPt{0.0}, maxPt{1e+6}, minEta{-100}, maxEta{+100}, maxDCAz{1e+6}, maxDCAxyPtDep{1e+6}, requireTPC{false}, minTPCclusters{-1}, minTPCcrossedrows{-1}, minTPCcrossedrowsoverfindable{0.0}, requireITS{false}, minITSclusters{-1}, maxITSChi2percluster{1e+6} + : trackPhysicsType{0}, minPt{0.0}, maxPt{1e+6}, minEta{-100}, maxEta{+100}, maxDCAz{1e+6}, maxDCAxyPtDep{1e+6}, requireTPC{false}, minTPCclusters{-1}, minTPCcrossedrows{-1}, minTPCcrossedrowsoverfindable{0.0}, maxTPCFractionSharedCls{0.0}, requireITS{false}, minITSclusters{-1}, maxITSChi2percluster{1e+6} { // constructor } @@ -60,6 +61,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; @@ -86,7 +89,7 @@ class trackSelectionRequest if (lTrack.eta() > maxEta) return false; // DCA to PV - if (fabs(lTrack.dcaXY()) < maxDCAz) + if (std::fabs(lTrack.dcaXY()) < maxDCAz) return false; // TracksExtra-based if (lTrack.hasTPC() == false && requireTPC) @@ -97,6 +100,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 +122,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 +153,7 @@ class trackSelectionRequest int minTPCclusters; int minTPCcrossedrows; float minTPCcrossedrowsoverfindable; + float maxTPCFractionSharedCls; // ITS parameters (TracksExtra) bool requireITS; // in Run 3, equiv to hasITS int minITSclusters; @@ -156,4 +164,4 @@ class trackSelectionRequest std::ostream& operator<<(std::ostream& os, trackSelectionRequest const& c); -#endif // TRACKSELECTIONREQUEST_H +#endif // COMMON_TOOLS_TRACKSELECTIONREQUEST_H_ diff --git a/DPG/Tasks/AOTEvent/CMakeLists.txt b/DPG/Tasks/AOTEvent/CMakeLists.txt index 97476f860a4..59e049e6356 100644 --- a/DPG/Tasks/AOTEvent/CMakeLists.txt +++ b/DPG/Tasks/AOTEvent/CMakeLists.txt @@ -11,7 +11,7 @@ o2physics_add_dpl_workflow(event-selection-qa SOURCES eventSelectionQa.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::DetectorsBase O2::DataFormatsITSMFT COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(lumi-qa @@ -19,8 +19,8 @@ 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) @@ -28,8 +28,28 @@ 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(light-ions-evsel-qa + SOURCES lightIonsEvSelQa.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..c87fd48bc99 --- /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 + +#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 index b41bc1faef4..3fc293c7e84 100644 --- a/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx +++ b/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx @@ -9,74 +9,113 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "map" +/// \file detectorOccupancyQa.cxx +/// \brief Occupancy QA task +/// +/// \author Igor Altsybeev -#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/CCDB/ctpRateFetcher.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 "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/BunchFilling.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" #include "TH1F.h" #include "TH2F.h" #include "TH3.h" -using namespace o2::framework; +#include +#include + 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"}; - Configurable confTimeIntervalForOccupancyCalculation{"TimeIntervalForOccupancyCalculation", 100, "Time interval for TPC occupancy calculation, us"}; - Configurable confOccupancyHistCoeffNtracksForOccupancy{"HistCoeffNtracksForOccupancy", 1., "Coefficient for max nTracks in occupancy histos"}; - Configurable confOccupancyHistCoeffNbins2D{"HistCoeffNbins2D", 1., "Coefficient for nBins in occupancy 2D histos"}; - Configurable confOccupancyHistCoeffNbins3D{"HistCoeffNbins3D", 1., "Coefficient for nBins in occupancy 3D histos"}; - Configurable confCoeffMaxNtracksThisEvent{"CoeffMaxNtracksThisEvent", 1., "Coefficient for max nTracks or FT0 ampl in histos in a given event"}; - Configurable confFlagApplyROFborderCut{"ApplyROFborderCut", true, "Use ROF border cut for a current event"}; - Configurable confFlagApplyTFborderCut{"ApplyTFborderCut", true, "Use TF border cut for a current event"}; - Configurable confFlagWhichTimeRange{"FlagWhichTimeRange", 0, "Whicn time range for occupancy calculation: 0 - symmetric, 1 - only past, 2 - only future"}; - Configurable confFlagUseGlobalTracks{"FlagUseGlobalTracks", 0, "For small time bins, use global tracks counter instead of ITSTPC tracks"}; + Configurable confAddBasicQAhistos{"FlagAddBasicQAhistos", true, "0 - add basic histograms, 1 - skip"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confAddTimeDependentHistos{"FlagAddTimeDependentHistos", true, "0 - add time-dependent 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) + Configurable confFlagIsTOFIsTRDdtStudy{"FlagIsTOFIsTRDdtStudy", false, "Fill THn dt historams with isTOF and isTRD condition"}; // 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"}; - Configurable confNumberOfSmallTimeBins{"nSmallTimeBins", 40, "Number of small time bins"}; + 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"}; - Configurable confCutVertZMaxThisEvent{"VzMaxThisEvent", 10, "vZ cut for a current event"}; - Configurable confCutPtMinThisEvent{"PtMinThisEvent", 0.2, "pt cut for particles in a current event"}; - Configurable confCutPtMaxThisEvent{"PtMaxThisEvent", 100., "pt cut for particles in a current event"}; - Configurable confCutEtaMinTracksThisEvent{"EtaMinTracksThisEvent", -0.8, "eta cut for particles in a current event"}; - Configurable confCutEtaMaxTracksThisEvent{"EtaMaxTracksThisEvent", 0.8, "eta cut for particles in a current event"}; - Configurable confCutMinTPCcls{"MinNumTPCcls", 70, "min number of TPC clusters for a current 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", 50, "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"}; - Configurable nBinsTracks{"nBinsTracks", 400, "N bins in n tracks histo"}; - Configurable nMaxTracks{"nMaxTracks", 8000, "N max in n tracks histo"}; - Configurable nMaxGlobalTracks{"nMaxGlobalTracks", 3000, "N max in n tracks histo"}; - Configurable nBinsMultFwd{"nBinsMultFwd", 400, "N bins in mult fwd histo"}; - Configurable nMaxMultFwd{"nMaxMultFwd", 200000, "N max in mult fwd histo"}; + Configurable confAddTracksVsFwdHistos{"FlagAddTracksVsFwdHistos", 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"}; - Configurable nMaxOccupancy{"nMaxOccupancy", 15000, "N for max of the occupancy axis"}; + 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) + + Configurable confNPhiBins{"nPhiBins", 810, "N phi bits for histograms"}; // o2-linter: disable=name/configurable (temporary fix) + + ConfigurableAxis confAxisPtBinsForPhiStudy{"PtBinsForPhiStudy", {VARIABLE_WIDTH, 0.2, 0.6, 1.0, 2.0, 10}, "pt axis"}; + ConfigurableAxis confAxisOccupForKine{"AxisOccupForKine", {VARIABLE_WIDTH, 0, 500, 1000, 2000, 4000, 6000, 8000, 10000, 20000}, "weighted occupancy"}; + + Configurable confUsePhiAtTPCinnerR{"UsePhiAtTPCinnerR", false, "0 - not use, 1 - use"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confUseAorCsideForPhiStudy{"UseAorCsideForPhiStudy", -1, "-1 - use full eta range, 0 - A, 1 - C sides"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confRadiusForPhiCorrection{"RadiusForPhiCorrection", 0.8, "default: inner TPC radius, cm"}; // o2-linter: disable=name/configurable (temporary fix) + + Configurable confApplyGoodITSstavesFlaginEvSel{"ApplyGoodITSstavesFlaginEvSel", 0, "0 - no, 1 - yes"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confMinITSclsPerTrack{"MinITSclsPerTrack", 5, "should be in 4..7"}; // o2-linter: disable=name/configurable (temporary fix) + + Configurable> confTimeSlicesForPastFutureStudies{"TimeSlicesForPastFutureStudies", {-40, -10, 20, 50, 80}, "Time slices for past/future studies, us"}; + + // configuration for THnD multi-dim histo(s): + Configurable confFlagFillTHn{"FlagFillTHn", false, "Fill THn historams for multi-dim QA"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTHnAxis_nPhiBins{"THn_nPhiBins", 180, "nPhiBins"}; // o2-linter: disable=name/configurable (temporary fix) + ConfigurableAxis confTHnAxis_R{"THn_R", {8, -0.5f, 7.5f}, "ids of radii"}; // o2-linter: disable=name/configurable (temporary fix) + ConfigurableAxis confTHnAxis_qOp{"THn_qOp", {16, -4.f, 4.f}, "qOp"}; // o2-linter: disable=name/configurable (temporary fix) + ConfigurableAxis confTHnAxis_IR{"THn_IR", {VARIABLE_WIDTH, 0, 12, 25, 38, 50}, "IR, kHz"}; // o2-linter: disable=name/configurable (temporary fix) + ConfigurableAxis confTHnAxis_occ{"THn_occupancy", {VARIABLE_WIDTH, 0, 500, 1000, 2000, 4000, 6000, 8000}, "weighted occupancy"}; // o2-linter: disable=name/configurable (temporary fix) + ConfigurableAxis confTHnAxis_centr{"THn_centr", {VARIABLE_WIDTH, 0, 500, 1000, 2000, 4000}, "centrality by nPVtracks"}; // o2-linter: disable=name/configurable (temporary fix) + ConfigurableAxis confTHnAxis_eta{"THn_eta", {8, -0.8f, 0.8f}, "eta"}; // o2-linter: disable=name/configurable (temporary fix) uint64_t minGlobalBC = 0; Service ccdb; @@ -86,8 +125,9 @@ struct DetectorOccupancyQaTask { 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 + int64_t bcSOR = 0; // global bc of the start of the first orbit, setting 0 by default for unanchored MC + int64_t nBCsPerTF = 32 * 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; @@ -101,22 +141,43 @@ struct DetectorOccupancyQaTask { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); + const AxisSpec axisBCinTF{static_cast(nBCsPerTF), 0, static_cast(nBCsPerTF), "bc in TF"}; + histos.add("hNcolVsBcInTF/hNcolVsBcInTF", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + histos.add("hNcolVsBcInTF/hNcolVsBcInTF_vertexTOFmatched", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + histos.add("hNcolVsBcInTF/hNcolVsBcInTFafterMaxBcCut", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + + // QA of occupancy-based event selection + histos.add("hOccupancy", "", kTH1D, {{15002, -1.5, 15000.5}}); + + 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}); + } + // 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"); + // histograms for occupancy-in-time-window study double kMaxOccup = confOccupancyHistCoeffNtracksForOccupancy; double kMaxThisEv = confCoeffMaxNtracksThisEvent; - AxisSpec axisBC{3601, -0.5, 3600.5, "bc"}; - histos.add("h2D_diff_FoundBC_vs_BC", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - histos.add("h2D_diff_FoundBC_vs_BC_multAbove10", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - histos.add("h2D_diff_FoundBC_vs_BC_multAbove20", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - histos.add("h2D_diff_FoundBC_vs_BC_multAbove50", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - histos.add("h2D_diff_FoundBC_vs_BC_multAbove100", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - histos.add("h2D_diff_FoundBC_vs_BC_hasTOF", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - histos.add("h2D_diff_FoundBC_vs_BC_hasTRD", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - histos.add("h2D_diff_FoundBC_vs_BC_hasTOF_multAbove10", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - histos.add("h2D_diff_FoundBC_vs_BC_hasTRD_multAbove10", "", kTH2D, {axisBC, {201, -100.5, 100.5, "foundBC-BC"}}); - + // 1D, dE/dx, etc. if (confAddBasicQAhistos) { + histos.add("hOccupancyVsOrbit", ";orbit id;weighted occupancy;n events", kTH2F, {{128, -0.5, 127.5}, {600, 0, 15000}}); + 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}}); @@ -132,8 +193,217 @@ struct DetectorOccupancyQaTask { 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}}); + + // 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 axisNTPCcls{160, 0, 160, "n TPC clusters"}; + histos.add("tpcNClsFound_vs_centr_vs_occup", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisNTPCcls}); + histos.add("tpcNClsFindable_vs_centr_vs_occup", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisNTPCcls}); + histos.add("tpcNClsShared_vs_centr_vs_occup", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisNTPCcls}); + histos.add("tpcNClsShared_vs_centr_vs_occup_Aside", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisNTPCcls}); + histos.add("tpcNClsShared_vs_centr_vs_occup_Cside", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisNTPCcls}); + histos.add("tpcNClsShared_vs_centr_vs_occup_pos", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisNTPCcls}); + histos.add("tpcNClsShared_vs_centr_vs_occup_neg", "", kTH3F, {{20, 0, 4000, "nITStrk cls567"}, axisOccupancyForDeDxStudies, axisNTPCcls}); + + // July 2025: more for data vs MC + AxisSpec axisChi2TPC{150, 0, 15, "chi2Ncl TPC"}; + histos.add("QA_noTPCcuts/nPV_10_200/tpcNClsFindable_vs_occup_pt_02_05", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_10_200/tpcNClsFindable_vs_occup_pt_05_10", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_10_200/tpcNClsFindable_vs_occup_pt_above1_0", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_10_200/tpcNClsFound_vs_occup_pt_02_05", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_10_200/tpcNClsFound_vs_occup_pt_05_10", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_10_200/tpcNClsFound_vs_occup_pt_above1_0", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_10_200/tpcChi2NCl_vs_occup_pt_02_05", "", kTH2F, {axisChi2TPC, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_10_200/tpcChi2NCl_vs_occup_pt_05_10", "", kTH2F, {axisChi2TPC, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_10_200/tpcChi2NCl_vs_occup_pt_above1_0", "", kTH2F, {axisChi2TPC, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcNClsFindable_vs_occup_pt_02_05", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcNClsFindable_vs_occup_pt_05_10", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcNClsFindable_vs_occup_pt_above1_0", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcNClsFound_vs_occup_pt_02_05", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcNClsFound_vs_occup_pt_05_10", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcNClsFound_vs_occup_pt_above1_0", "", kTH2F, {axisNTPCcls, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcChi2NCl_vs_occup_pt_02_05", "", kTH2F, {axisChi2TPC, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcChi2NCl_vs_occup_pt_05_10", "", kTH2F, {axisChi2TPC, axisOccupancyForDeDxStudies}); + histos.add("QA_noTPCcuts/nPV_above2000/tpcChi2NCl_vs_occup_pt_above1_0", "", kTH2F, {axisChi2TPC, axisOccupancyForDeDxStudies}); + + 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; + AxisSpec axisEta{nEtaBins, -1.0, 1.0, "#eta"}; // o2-linter: disable=external-pi (temporary fix) + histos.add("track_distr_nITStrThisEv_10_200/hEta_lowOccupInTPC", ";#eta;n tracks", kTH1D, {axisEta}); + histos.add("track_distr_nITStrThisEv_10_200/hEta_highOccupInRecentPast", ";#eta;n tracks", kTH1D, {axisEta}); + histos.add("track_distr_nITStrThisEv_10_200/hEta_highOccupInCloseFuture", ";#eta;n tracks", kTH1D, {axisEta}); + histos.add("track_distr_nITStrThisEv_10_200/hEta_highOccupInDistantFuture", ";#eta;n tracks", kTH1D, {axisEta}); + histos.add("track_distr_nITStrThisEv_10_200/hEta_highOccupInNeighbourEvents", ";#eta;n tracks", kTH1D, {axisEta}); + + histos.add("track_distr_nITStrThisEv_above_2000/hEta_lowOccupInTPC", ";#eta;n tracks", kTH1D, {axisEta}); + histos.add("track_distr_nITStrThisEv_above_2000/hEta_highOccupInRecentPast", ";#eta;n tracks", kTH1D, {axisEta}); + histos.add("track_distr_nITStrThisEv_above_2000/hEta_highOccupInCloseFuture", ";#eta;n tracks", kTH1D, {axisEta}); + histos.add("track_distr_nITStrThisEv_above_2000/hEta_highOccupInDistantFuture", ";#eta;n tracks", kTH1D, {axisEta}); + histos.add("track_distr_nITStrThisEv_above_2000/hEta_highOccupInNeighbourEvents", ";#eta;n tracks", kTH1D, {axisEta}); + + const int nPhiBins = confNPhiBins; // 810=18*45 + 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_10_200/hPhi_lowOccupInTPC_pos_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInRecentPast_pos_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInCloseFuture_pos_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInDistantFuture_pos_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInNeighbourEvents_pos_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + + histos.add("track_distr_nITStrThisEv_10_200/hPhi_lowOccupInTPC_neg_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInRecentPast_neg_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInCloseFuture_neg_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInDistantFuture_neg_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/hPhi_highOccupInNeighbourEvents_neg_vs_pt", ";#varphi;n tracks", kTH2D, {axisPhi, confAxisPtBinsForPhiStudy}); + + 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}); + + // July 2025: to compare data and MC (pt, eta, phi) + // AxisSpec confAxisOccupForKine{{0, 500, 1000, 2000, 4000, 6000, 20000}, "weighted occupancy"}; + // AxisSpec confAxisOccupForKine{{0, 500, 1000, 2000, 4000, 6000, 8000, 10000, 20000}, "weighted occupancy"}; + // AxisSpec confAxisPtBinsForPhiStudy{{0.2, 0.6, 1.0, 2.0, 10}, "pt bins for phi study"}; + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPt_pos", ";p_{T};weighted occupancy", kTH2D, {axisLogPt, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPt_neg", ";p_{T};weighted occupancy", kTH2D, {axisLogPt, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hEta_pos", ";#eta;weighted occupancy", kTH2D, {axisEta, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hEta_neg", ";#eta;weighted occupancy", kTH2D, {axisEta, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_pos", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_neg", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsFindable_pos", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsFound_pos", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsCrossedRows_pos", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsFindable_neg", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsFound_neg", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsCrossedRows_neg", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hPt_pos", ";p_{T};weighted occupancy", kTH2D, {axisLogPt, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hPt_neg", ";p_{T};weighted occupancy", kTH2D, {axisLogPt, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hEta_pos", ";#eta;weighted occupancy", kTH2D, {axisEta, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hEta_neg", ";#eta;weighted occupancy", kTH2D, {axisEta, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hPhi_pos", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hPhi_neg", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPt_pos", ";p_{T};weighted occupancy", kTH2D, {axisLogPt, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPt_neg", ";p_{T};weighted occupancy", kTH2D, {axisLogPt, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hEta_pos", ";#eta;weighted occupancy", kTH2D, {axisEta, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hEta_neg", ";#eta;weighted occupancy", kTH2D, {axisEta, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_pos", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_neg", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_posInitialQA", ";#varphi;n tracks", kTH1D, {{3 * 810, -TMath::TwoPi(), 2 * TMath::TwoPi(), "#varphi"}}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_posModifiedQA", ";#varphi;n tracks", kTH1D, {{3 * 810, -TMath::TwoPi(), 2 * TMath::TwoPi(), "#varphi"}}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_negInitialQA", ";#varphi;n tracks", kTH1D, {{3 * 810, -TMath::TwoPi(), 2 * TMath::TwoPi(), "#varphi"}}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_negModifiedQA", ";#varphi;n tracks", kTH1D, {{3 * 810, -TMath::TwoPi(), 2 * TMath::TwoPi(), "#varphi"}}); + + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hPt_pos", ";p_{T};weighted occupancy", kTH2D, {axisLogPt, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hPt_neg", ";p_{T};weighted occupancy", kTH2D, {axisLogPt, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hEta_pos", ";#eta;weighted occupancy", kTH2D, {axisEta, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hEta_neg", ";#eta;weighted occupancy", kTH2D, {axisEta, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hPhi_pos", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + histos.add("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hPhi_neg", ";#varphi;n tracks", kTH3D, {axisPhi, confAxisOccupForKine, confAxisPtBinsForPhiStudy}); + + // QA nTPCcls + AxisSpec axisNTPCclsPlusMinusQA{521, -260, 260, "n TPC clusters"}; + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/QA_tpcNClsFindable_pos", "", kTH1D, {axisNTPCclsPlusMinusQA}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/QA_tpcNClsFound_pos", "", kTH1D, {axisNTPCclsPlusMinusQA}); + histos.add("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/QA_tpcNClsCrossedRows_pos", "", kTH1D, {axisNTPCclsPlusMinusQA}); + + AxisSpec axisLogPtFor2D{50, 0.05, 10, "p_{T}"}; + AxisSpec axisLogPtTpcFor2D{50, 0.05, 10, "p_{T} TPC inner"}; + histos.add("track_distr_nITStrThisEv_10_200/hPt_vs_tpcInnerPt_vs_occup", ";p_{T};p_{T} TPC inner;weighted occupancy", kTH3D, {axisLogPtFor2D, axisLogPtTpcFor2D, confAxisOccupForKine}); + histos.add("track_distr_nITStrThisEv_above_2000/hPt_vs_tpcInnerPt_vs_occup", ";p_{T};p_{T} TPC inner;weighted occupancy", kTH3D, {axisLogPtFor2D, axisLogPtTpcFor2D, confAxisOccupForKine}); + + histos.add("hNcolVsBcInTF/hNcolVsBcInTF_vs_occupancy", ";bc in TF;weighted occupancy", kTH2F, {axisBCinTF, confAxisOccupForKine}); + histos.add("hNcolVsBcInTF/hNcolVsBcInTF_vs_occupancy_vertexTOFmatched", ";bc in TF;weighted occupancy", kTH2F, {axisBCinTF, confAxisOccupForKine}); + histos.add("hNcolVsBcInTF/hNcolVsBcInTF_vs_occupancy_nPV_10_200", ";bc in TF;weighted occupancy", kTH2F, {axisBCinTF, confAxisOccupForKine}); + histos.add("hNcolVsBcInTF/hNcolVsBcInTF_vs_occupancy_nPV_above2000", ";bc in TF;weighted occupancy", kTH2F, {axisBCinTF, confAxisOccupForKine}); + // end of July 2025: to compare data and MC (pt, eta, phi) + + // 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; @@ -156,8 +426,24 @@ struct DetectorOccupancyQaTask { 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_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_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}}); + } + + // THnD for Marian: + if (confFlagFillTHn) { + AxisSpec axis_THnF_phi{confTHnAxis_nPhiBins, 0, TMath::TwoPi(), ""}; // φ at radius: 360 bins + histos.add("THnD_histos/phi_R_qOp_IR_occ_centr_eta", ";phi;R;qOp;IR;occ;cent;eta", kTHnF, {axis_THnF_phi, confTHnAxis_R, confTHnAxis_qOp, confTHnAxis_IR, confTHnAxis_occ, confTHnAxis_centr, confTHnAxis_eta}); + + histos.add("THnD_histos/QA_under_asin", "", kTH1F, {{200, -4, 4}}); + histos.add("THnD_histos/QA_asin", "", kTH1F, {{200, -8, 8}}); } // nD, time bins to cover the range -confTimeIntervalForSmallBins... +confTimeIntervalForSmallBins (us) double timeBinSize = 2 * confTimeIntervalForSmallBins / confNumberOfSmallTimeBins; @@ -165,68 +451,78 @@ struct DetectorOccupancyQaTask { for (int i = 0; i < confNumberOfSmallTimeBins + 1; i++) arrTimeBins.push_back(-confTimeIntervalForSmallBins + i * timeBinSize); const AxisSpec axisTimeBins{arrTimeBins, "#Delta t, #mus"}; - 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, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3D, 0, kMaxThisEv * 8000}, {nBins3DoccupancyAxis, 0, kMaxOccup * 10000}}); - histos.add("thisEventITStracksInTimeBins", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); - histos.add("thisEventITSTPCtracksInTimeBins", ";time bin (#mus);n tracks", kTH1F, {axisTimeBins}); + int nBinsX = 20; + int nBinsY = 40; - // save dt information for several first collisions for QA - histos.add("histOccupInTimeBinsQA", ";dt;this coll id", kTH2F, {axisTimeBins, {nCollisionsForTimeBinQA, -0.5, nCollisionsForTimeBinQA - 0.5}}); + if (confAddTimeDependentHistos) { + 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}}); - // QA of occupancy-based event selection - histos.add("hOccupancy", "", kTH1D, {{15002, -1.5, 15000.5}}); + 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}}); - AxisSpec axisOccupancy{nBinsOccupancy, 0., nMaxOccupancy, "occupancy (n ITS tracks weighted)"}; - AxisSpec axisCentrality{100, 0, 100, "centrality, %"}; - histos.add("hCentrVsOccupancy", "hCentrVsOccupancy", kTH2F, {axisCentrality, axisOccupancy}); + 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}}); + } + if (confFlagIsTOFIsTRDdtStudy) { + histos.add("occupancyInTimeBins_nITSTOF_vs_FT0thisCol_kNoCollInTimeRangeNarrow", ";time bin (#mus);FT0C this collision, this collision;n ITSTOF 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_nITSTRD_vs_FT0thisCol_kNoCollInTimeRangeNarrow", ";time bin (#mus);FT0C this collision, this collision;n ITSTRD 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("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}}); + } + + 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}); if (confAddTracksVsFwdHistos) { AxisSpec axisNtracks{nBinsTracks, -0.5, nMaxTracks - 0.5, "n tracks"}; AxisSpec axisNtracksGlobal{nBinsTracks, -0.5, nMaxGlobalTracks - 0.5, "n tracks"}; - AxisSpec axisMultFw{nBinsMultFwd, 0., static_cast(nMaxMultFwd), "mult Fwd"}; - - histos.add("nTracksPV_vs_V0A_kNoHighOccupancyAgressive", "nTracksPV_vs_V0A_kNoHighOccupancyAgressive", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_kNoHighOccupancyStrict", "nTracksPV_vs_V0A_kNoHighOccupancyStrict", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_kNoHighOccupancyMedium", "nTracksPV_vs_V0A_kNoHighOccupancyMedium", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_kNoHighOccupancyRelaxed", "nTracksPV_vs_V0A_kNoHighOccupancyRelaxed", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_kNoHighOccupancyGentle", "nTracksPV_vs_V0A_kNoHighOccupancyGentle", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_kNoCollInTimeRangeStandard", "nTracksPV_vs_V0A_kNoCollInTimeRangeStandard", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_kNoCollInTimeRangeNarrow", "nTracksPV_vs_V0A_kNoCollInTimeRangeNarrow", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_occup_0_250", "nTracksPV_vs_V0A_occup_0_250", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_occup_0_500", "nTracksPV_vs_V0A_occup_0_500", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_occup_0_750", "nTracksPV_vs_V0A_occup_0_750", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard", "nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow", "nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_noOccupSel", "nTracksPV_vs_V0A_noOccupSel", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", "nTracksPV_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_occup_ABOVE_750", "nTracksPV_vs_V0A_occup_ABOVE_750", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_occup_Minus1", "nTracksPV_vs_V0A_occup_Minus1", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_AntiNoCollInTimeRangeStandard", "nTracksPV_vs_V0A_AntiNoCollInTimeRangeStandard", kTH2F, {axisMultFw, axisNtracks}); - histos.add("nTracksPV_vs_V0A_AntiNoCollInTimeRangeNarrow", "nTracksPV_vs_V0A_AntiNoCollInTimeRangeNarrow", kTH2F, {axisMultFw, axisNtracks}); - - histos.add("nTracksGlobal_vs_V0A_kNoHighOccupancyAgressive", "nTracksGlobal_vs_V0A_kNoHighOccupancyAgressive", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_kNoHighOccupancyStrict", "nTracksGlobal_vs_V0A_kNoHighOccupancyStrict", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_kNoHighOccupancyMedium", "nTracksGlobal_vs_V0A_kNoHighOccupancyMedium", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_kNoHighOccupancyRelaxed", "nTracksGlobal_vs_V0A_kNoHighOccupancyRelaxed", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_kNoHighOccupancyGentle", "nTracksGlobal_vs_V0A_kNoHighOccupancyGentle", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_kNoCollInTimeRangeStandard", "nTracksGlobal_vs_V0A_kNoCollInTimeRangeStandard", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_kNoCollInTimeRangeNarrow", "nTracksGlobal_vs_V0A_kNoCollInTimeRangeNarrow", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_occup_0_250", "nTracksGlobal_vs_V0A_occup_0_250", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_occup_0_500", "nTracksGlobal_vs_V0A_occup_0_500", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_occup_0_750", "nTracksGlobal_vs_V0A_occup_0_750", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard", "nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow", "nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeNarrow", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_noOccupSel", "nTracksGlobal_vs_V0A_noOccupSel", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", "nTracksGlobal_vs_V0A_occup_0_500_kNoCollInTimeRangeStandard_extraCuts", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_occup_ABOVE_750", "nTracksGlobal_vs_V0A_occup_ABOVE_750", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_occup_Minus1", "nTracksGlobal_vs_V0A_occup_Minus1", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeStandard", "nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeStandard", kTH2F, {axisMultFw, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeNarrow", "nTracksGlobal_vs_V0A_AntiNoCollInTimeRangeNarrow", kTH2F, {axisMultFw, axisNtracksGlobal}); - - histos.add("nTracksGlobal_vs_nPV_kNoHighOccupancyAgressive", "nTracksGlobal_vs_nPV_kNoHighOccupancyAgressive", kTH2F, {axisNtracks, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_nPV_kNoHighOccupancyStrict", "nTracksGlobal_vs_nPV_kNoHighOccupancyStrict", kTH2F, {axisNtracks, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_nPV_kNoHighOccupancyMedium", "nTracksGlobal_vs_nPV_kNoHighOccupancyMedium", kTH2F, {axisNtracks, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_nPV_kNoHighOccupancyRelaxed", "nTracksGlobal_vs_nPV_kNoHighOccupancyRelaxed", kTH2F, {axisNtracks, axisNtracksGlobal}); - histos.add("nTracksGlobal_vs_nPV_kNoHighOccupancyGentle", "nTracksGlobal_vs_nPV_kNoHighOccupancyGentle", kTH2F, {axisNtracks, axisNtracksGlobal}); + 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}); @@ -243,13 +539,33 @@ struct DetectorOccupancyQaTask { 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_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, axisOccupancy}); - histos.add("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeStandard", "nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeStandard", kTH3F, {axisNtracks, axisNtracksGlobal, axisOccupancy}); - histos.add("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeNarrow", "nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeNarrow", kTH3F, {axisNtracks, axisNtracksGlobal, axisOccupancy}); + 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_kNoCollInTimeRangeNarrow", "", 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_kNoCollInTimeRangeNarrow", "", 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}); } } @@ -262,40 +578,17 @@ struct DetectorOccupancyQaTask { aod::FT0s 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 - int64_t ts = bcs.iteratorAt(0).timestamp(); - - 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; + + 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 = nOrbitsPerTF * o2::constants::lhc::LHCMaxBunches; - LOGP(info, "tsOrbitReset={} us, SOR = {} ms, EOR = {} ms, orbitSOR = {}, nBCsPerTF = {}", tsOrbitReset, tsSOR, tsEOR, orbitSOR, nBCsPerTF); + nBCsPerTF = runInfo.orbitsPerTF * o2::constants::lhc::LHCMaxBunches; + + LOGP(info, "bcSOR = {}, nBCsPerTF = {}", bcSOR, nBCsPerTF); } } @@ -308,13 +601,20 @@ struct DetectorOccupancyQaTask { 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 vTracksITSTOFperCollPtEtaCuts(cols.size(), 0); // counter of tracks per found bc for occupancy studies + std::vector vTracksITSTRDperCollPtEtaCuts(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 (auto& col : cols) { + for (const auto& col : cols) { const auto& bc = col.foundBC_as(); // count tracks of different types @@ -323,33 +623,35 @@ struct DetectorOccupancyQaTask { int nGlobalPtEtaCuts = 0; int nITSTPCtracks = 0; int nITSTPCtracksPtEtaCuts = 0; + int nITSTOFtracksPtEtaCuts = 0; + int nITSTRDtracksPtEtaCuts = 0; int nTOFtracks = 0; - int nTRDtracks = 0; + // int nTRDtracks = 0; auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); - for (auto& track : tracksGrouped) { + for (const auto& track : tracksGrouped) { if (!track.isPVContributor()) { continue; } - if (track.itsNCls() >= 5) - nITS567cls++; + if (track.itsNCls() < confMinITSclsPerTrack) + continue; + 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++; + nITS567clsPtEtaCuts++; + nITSTOFtracksPtEtaCuts += track.hasITS() && track.hasTOF(); + nITSTRDtracksPtEtaCuts += track.hasITS() && track.hasTRD(); if (track.tpcNClsFound() < confCutMinTPCcls) continue; nITSTPCtracksPtEtaCuts += track.hasITS() && track.hasTPC(); - if (track.itsNCls() >= 5) - nGlobalPtEtaCuts += track.isGlobalTrack(); + nGlobalPtEtaCuts += track.isGlobalTrack(); } int32_t foundBC = bc.globalIndex(); @@ -358,57 +660,37 @@ struct DetectorOccupancyQaTask { 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; + vTracksITS567perColl[colIndex] = nITS567cls; + vTracksITS567perCollPtEtaCuts[colIndex] = nITS567clsPtEtaCuts; + vTracksGlobalPerCollPtEtaCuts[colIndex] = nGlobalPtEtaCuts; - vTracksITSTPCperColl[colIndex] += nITSTPCtracks; - vTracksITSTPCperCollPtEtaCuts[colIndex] += nITSTPCtracksPtEtaCuts; + vTracksITSTPCperColl[colIndex] = nITSTPCtracks; + vTracksITSTPCperCollPtEtaCuts[colIndex] = nITSTPCtracksPtEtaCuts; + vTracksITSTOFperCollPtEtaCuts[colIndex] = nITSTOFtracksPtEtaCuts; + vTracksITSTRDperCollPtEtaCuts[colIndex] = nITSTRDtracksPtEtaCuts; // TF ids within a given cols table - int TFid = (bc.globalBC() - bcSOR) / nBCsPerTF; - vTFids[colIndex] = TFid; + 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])); - - // additional QA: - if (col.selection_bit(kNoTimeFrameBorder) && col.selection_bit(kNoITSROFrameBorder)) { - auto bcFoundId = bc.globalBC() % 3564; - auto bcNonFound = col.bc_as(); - auto bcNonFoundId = bcNonFound.globalBC() % 3564; - int64_t diffFoundBC_vs_BC = (int64_t)bcFoundId - (int64_t)bcNonFoundId; - histos.fill(HIST("h2D_diff_FoundBC_vs_BC"), bcNonFoundId, diffFoundBC_vs_BC); - if (nITS567cls > 10) - histos.fill(HIST("h2D_diff_FoundBC_vs_BC_multAbove10"), bcNonFoundId, diffFoundBC_vs_BC); - if (nITS567cls > 20) - histos.fill(HIST("h2D_diff_FoundBC_vs_BC_multAbove20"), bcNonFoundId, diffFoundBC_vs_BC); - if (nITS567cls > 50) - histos.fill(HIST("h2D_diff_FoundBC_vs_BC_multAbove50"), bcNonFoundId, diffFoundBC_vs_BC); - if (nITS567cls > 100) - histos.fill(HIST("h2D_diff_FoundBC_vs_BC_multAbove100"), bcNonFoundId, diffFoundBC_vs_BC); - - if (nTOFtracks > 0) - histos.fill(HIST("h2D_diff_FoundBC_vs_BC_hasTOF"), bcNonFoundId, diffFoundBC_vs_BC); - if (nTRDtracks > 0) - histos.fill(HIST("h2D_diff_FoundBC_vs_BC_hasTRD"), bcNonFoundId, diffFoundBC_vs_BC); - - if (nITS567cls > 10 && nTOFtracks > 0) - histos.fill(HIST("h2D_diff_FoundBC_vs_BC_hasTOF_multAbove10"), bcNonFoundId, diffFoundBC_vs_BC); - if (nITS567cls > 10 && nTRDtracks > 0) - histos.fill(HIST("h2D_diff_FoundBC_vs_BC_hasTRD_multAbove10"), bcNonFoundId, diffFoundBC_vs_BC); - } } // find for each collision all collisions within the defined time window std::vector> vCollsInTimeWin; std::vector> vTimeDeltaForColls; // delta time wrt a given collision - for (auto& col : cols) { + for (const auto& col : cols) { int32_t colIndex = col.globalIndex(); std::vector vCollsAssocToGivenColl; std::vector vCollsTimeDeltaWrtGivenColl; @@ -421,7 +703,7 @@ struct DetectorOccupancyQaTask { } int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; - int64_t TFid = (foundGlobalBC - bcSOR) / nBCsPerTF; + 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; @@ -429,8 +711,8 @@ struct DetectorOccupancyQaTask { int64_t thisBC = vFoundGlobalBC[minColIndex]; // check if this is still the same TF - int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; - if (thisTFid != TFid) + int64_t thisTfId = (thisBC - bcSOR) / nBCsPerTF; + if (thisTfId != tfId) break; float dt = (thisBC - foundGlobalBC) * bcNS; // ns @@ -450,8 +732,8 @@ struct DetectorOccupancyQaTask { 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) + int64_t thisTfId = (thisBC - bcSOR) / nBCsPerTF; + if (thisTfId != tfId) break; float dt = (thisBC - foundGlobalBC) * bcNS; // ns @@ -469,23 +751,27 @@ struct DetectorOccupancyQaTask { // perform the occupancy calculation in the pre-defined time window uint32_t orbitAtCollIndexZero = 0; - for (auto& col : cols) { + 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)) + if (!col.selection_bit(kNoTimeFrameBorder)) continue; // skip if collision is close to ROF border - if (confFlagApplyROFborderCut && !col.selection_bit(kNoITSROFrameBorder)) + if (!col.selection_bit(kNoITSROFrameBorder)) continue; std::vector vCollsAssocToGivenColl = vCollsInTimeWin[colIndex]; @@ -509,20 +795,21 @@ struct DetectorOccupancyQaTask { int nCollInTimeWindowSelIfTOF = 0; double multFT0CmainCollision = 0.f; double multFT0CInTimeWindow = 0.f; - map mUniqueBC; + std::map mUniqueBC; bool sel = col.selection_bit(kIsTriggerTVX); // loop over nearby collisions - for (int iCol = 0; iCol < vCollsAssocToGivenColl.size(); iCol++) { + 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 && fabs(thisColTimeDiff) < confTimeIntervalForSmallBins) { + 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++; @@ -557,47 +844,93 @@ struct DetectorOccupancyQaTask { LOGP(debug, " --> ### summary: colIndex={}/{} BC={} orbit={} nCollInTimeWindow={} nCollInTimeWindowSel={} nITSTPCtracksInTimeWindow={} ", colIndex, cols.size(), foundGlobalBC, orbit - orbitAtCollIndexZero, nCollInTimeWindow, nCollInTimeWindowSel, nITSTPCtracksInTimeWindow); if (confAddBasicQAhistos) { - histos.get(HIST("hNumITS567tracksInTimeWindow"))->Fill(nITS567tracksInTimeWindow); - histos.get(HIST("hNumITSTPCtracksInTimeWindow"))->Fill(nITSTPCtracksInTimeWindow); + 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.get(HIST("hNumITSTPCtracksPerCollision"))->Fill(vTracksITSTPCperColl[colIndex]); - histos.get(HIST("hNumITS567tracksPerCollision"))->Fill(vTracksITS567perColl[colIndex]); + histos.fill(HIST("hNumCollInTimeWindow"), nCollInTimeWindow); - histos.get(HIST("hNumITSTPCtracksInTimeWindow_vs_TracksPerColl"))->Fill(vTracksITSTPCperColl[colIndex], nITSTPCtracksInTimeWindow); - histos.get(HIST("hNumITSTPCtracksInTimeWindow_vs_TracksPerColl_withoutThisCol"))->Fill(vTracksITSTPCperColl[colIndex], nITSTPCtracksInTimeWindow - vTracksITSTPCperColl[colIndex]); + int64_t bcInTF = (vFoundGlobalBC[colIndex] - bcSOR) % nBCsPerTF; + int orbitId = bcInTF / o2::constants::lhc::LHCMaxBunches; + histos.fill(HIST("hNumCollInTimeWindowVsOrbit"), orbitId, nCollInTimeWindow); - histos.get(HIST("hNumITS567tracksInTimeWindow_vs_TracksPerColl"))->Fill(vTracksITS567perColl[colIndex], nITS567tracksInTimeWindow); - histos.get(HIST("hNumITS567tracksInTimeWindow_vs_TracksPerColl_withoutThisCol"))->Fill(vTracksITS567perColl[colIndex], nITS567tracksInTimeWindow - vTracksITS567perColl[colIndex]); + histos.fill(HIST("hNumUniqueBCInTimeWindow"), mUniqueBC.size()); - histos.get(HIST("hNumCollInTimeWindow"))->Fill(nCollInTimeWindow); + // 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); - histos.get(HIST("hNumUniqueBCInTimeWindow"))->Fill(mUniqueBC.size()); + if (sel && std::fabs(col.posZ()) < 10) { + histos.fill(HIST("hNumITS567tracksInTimeWindowSel"), nITS567tracksInTimeWindowSel); + histos.fill(HIST("hNumITSTPCtracksInTimeWindowSel"), nITSTPCtracksInTimeWindowSel); - if (sel) { - histos.get(HIST("hNumITS567tracksInTimeWindowSel"))->Fill(nITS567tracksInTimeWindowSel); - histos.get(HIST("hNumITSTPCtracksInTimeWindowSel"))->Fill(nITSTPCtracksInTimeWindowSel); + histos.fill(HIST("hNumITS567tracksPerCollisionSel"), vTracksITS567perColl[colIndex]); + histos.fill(HIST("hNumITSTPCtracksPerCollisionSel"), vTracksITSTPCperCollPtEtaCuts[colIndex]); - histos.get(HIST("hNumITS567tracksPerCollisionSel"))->Fill(vTracksITS567perColl[colIndex]); - histos.get(HIST("hNumITSTPCtracksPerCollisionSel"))->Fill(vTracksITSTPCperCollPtEtaCuts[colIndex]); + histos.fill(HIST("hNumCollInTimeWindowSel"), nCollInTimeWindowSel); + histos.fill(HIST("hNumCollInTimeWindowSelITSTPC"), nCollInTimeWindowSelITSTPC); + histos.fill(HIST("hNumCollInTimeWindowSelIfTOF"), nCollInTimeWindowSelIfTOF); - histos.get(HIST("hNumCollInTimeWindowSel"))->Fill(nCollInTimeWindowSel); - histos.get(HIST("hNumCollInTimeWindowSelITSTPC"))->Fill(nCollInTimeWindowSelITSTPC); - histos.get(HIST("hNumCollInTimeWindowSelIfTOF"))->Fill(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.get(HIST("hNumITS567tracksInTimeWindow_vs_FT0Campl"))->Fill(multFT0CInTimeWindow, nITS567tracksInTimeWindow); - histos.get(HIST("hNumITSTPCtracksInTimeWindow_vs_FT0Campl"))->Fill(multFT0CInTimeWindow, nITSTPCtracksInTimeWindow); - histos.get(HIST("hNumITSTPCtracksInTimeWindow_vs_ITS567tracks"))->Fill(nITS567tracksInTimeWindow, nITSTPCtracksInTimeWindow); - - histos.get(HIST("hNumITS567tracks_vs_FT0Campl_ThisEvent"))->Fill(multFT0CmainCollision, vTracksITS567perCollPtEtaCuts[colIndex]); - histos.get(HIST("hNumITSTPCtracks_vs_FT0Campl_ThisEvent"))->Fill(multFT0CmainCollision, vTracksITSTPCperCollPtEtaCuts[colIndex]); - histos.get(HIST("hNumITSTPCtracks_vs_ITS567tracks_ThisEvent"))->Fill(vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex]); + histos.fill(HIST("hNumITS567tracksInTimeWindow_vs_FT0Campl"), multFT0CInTimeWindow, nITS567tracksInTimeWindow); + histos.fill(HIST("hNumITSTPCtracksInTimeWindow_vs_FT0Campl"), multFT0CInTimeWindow, nITSTPCtracksInTimeWindow); + histos.fill(HIST("hNumITSTPCtracksInTimeWindow_vs_ITS567tracks"), nITS567tracksInTimeWindow, nITSTPCtracksInTimeWindow); - // 3D histograms: ITS vs ITSTPC in this event vs occupancy from other events - histos.get(HIST("hNumITSTPC_vs_ITS567tracksThisCol_vs_FT0CamplInTimeWindow"))->Fill(vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex], multFT0CInTimeWindow - multFT0CmainCollision); - histos.get(HIST("hNumITSTPC_vs_ITS567tracksThisCol_vs_ITS567tracksInTimeWindow"))->Fill(vTracksITS567perCollPtEtaCuts[colIndex], vTracksITSTPCperCollPtEtaCuts[colIndex], nITS567tracksInTimeWindow - vTracksITS567perColl[colIndex]); + 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(confTimeSlicesForPastFutureStudies->at(0) + 0.5); // default was: -39.5 us + int binMax = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(confTimeSlicesForPastFutureStudies->at(1) - 0.5); // -10.5 + float integralPast = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(binMin, binMax); + binMin = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(confTimeSlicesForPastFutureStudies->at(2) + 0.5); // 20.5 + binMax = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(confTimeSlicesForPastFutureStudies->at(3) - 0.5); // 49.5 + float integralFuture1 = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(binMin, binMax); + binMin = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(confTimeSlicesForPastFutureStudies->at(3) + 0.5); // 50.5 + binMax = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(confTimeSlicesForPastFutureStudies->at(4) - 0.5); // 79.5 + float integralFuture2 = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(binMin, binMax); + binMin = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(confTimeSlicesForPastFutureStudies->at(1) + 0.5); // -9.5 + binMax = histos.get(HIST("thisEventITStracksInTimeBins"))->FindBin(confTimeSlicesForPastFutureStudies->at(2) - 0.5); // 19.5 + float integralNeighbourEvents = histos.get(HIST("thisEventITStracksInTimeBins"))->Integral(binMin, binMax); + + // recent past + if (integralFullDeltaTime < 200) // ~empty detector + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 1; + // recent past + if (integralPast > /*3000*/ 2500 && (integralFullDeltaTime - integralPast) < 180) // low occupancy outside the dt region of interest + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 2; + // close future + if (integralFuture1 > /*3000*/ 2500 && (integralFullDeltaTime - integralFuture1) < 180) + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 3; + // distant future + if (integralFuture2 > /*3000*/ 2500 && (integralFullDeltaTime - integralFuture2) < 180) + vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex] = 4; + // neighbour events + if (integralNeighbourEvents > /*3000*/ 2500 && (integralFullDeltaTime - integralNeighbourEvents) < 180) + 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); @@ -606,69 +939,600 @@ struct DetectorOccupancyQaTask { // int nITSTPCtInTimeBin = histos.get(HIST("thisEventITSTPCtracksInTimeBins"))->GetBinContent(iT + 1); float dt = histos.get(HIST("thisEventITStracksInTimeBins"))->GetBinCenter(iT + 1); - histos.get(HIST("occupancyInTimeBins"))->Fill(dt, vTracksITS567perCollPtEtaCuts[colIndex], confFlagUseGlobalTracks ? vTracksGlobalPerCollPtEtaCuts[colIndex] : vTracksITSTPCperCollPtEtaCuts[colIndex], nITStrInTimeBin); - if (counterQAtimeOccupHistos < nCollisionsForTimeBinQA) - histos.fill(HIST("histOccupInTimeBinsQA"), dt, counterQAtimeOccupHistos + 1, nITStrInTimeBin); + int nFT0CInTimeBin = histos.get(HIST("thisEventFT0CInTimeBins"))->GetBinContent(iT + 1); + + if (confAddTimeDependentHistos && 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 (confAddTimeDependentHistos) { + 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 (confFlagIsTOFIsTRDdtStudy) { + histos.fill(HIST("occupancyInTimeBins_nITSTOF_vs_FT0thisCol_kNoCollInTimeRangeNarrow"), dt, vAmpFT0CperColl[colIndex], vTracksITSTOFperCollPtEtaCuts[colIndex], nITStrInTimeBin); + histos.fill(HIST("occupancyInTimeBins_nITSTRD_vs_FT0thisCol_kNoCollInTimeRangeNarrow"), dt, vAmpFT0CperColl[colIndex], vTracksITSTRDperCollPtEtaCuts[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); + } // end of confAddTimeDependentHistos } + + // 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 (auto& col : cols) { - // if (!col.sel8()) { - // continue; - // } - if (!col.selection_bit(kIsTriggerTVX)) + for (const auto& col : cols) { + if (!col.sel8()) continue; + if (confApplyGoodITSstavesFlaginEvSel && !col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) + 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/hNcolVsBcInTF"), bcInTF); + if (col.selection_bit(kIsVertexTOFmatched)) + histos.fill(HIST("hNcolVsBcInTF/hNcolVsBcInTF_vertexTOFmatched"), 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("hNcolVsBcInTF/hNcolVsBcInTFafterMaxBcCut"), bcInTF); + auto multV0A = col.multFV0A(); // auto multT0A = col.multFT0A(); - // auto multT0C = col.multFT0C(); + auto multT0C = col.multFT0C(); int nPV = 0; // col.multNTracksPV(); int nGlobalTracks = 0; + int occupancy = col.trackOccupancyInTimeRange(); auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); - for (auto& track : tracksGrouped) { + + const auto& bc = col.foundBC_as(); + int64_t ts = bc.timestamp(); + double IR = mRateFetcher.fetch(ccdb.service, ts, runNumber, "ZNC hadronic") * 1.e-3; // kHz + + // 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) + if (track.itsNCls() < confMinITSclsPerTrack) continue; nPV++; + } + if (occupancy >= 0 && confAddBasicQAhistos) { + histos.fill(HIST("hNcolVsBcInTF/hNcolVsBcInTF_vs_occupancy"), bcInTF, occupancy); + if (col.selection_bit(kIsVertexTOFmatched)) + histos.fill(HIST("hNcolVsBcInTF/hNcolVsBcInTF_vs_occupancy_vertexTOFmatched"), bcInTF, occupancy); + if (nPV >= 10 && nPV < 200) + histos.fill(HIST("hNcolVsBcInTF/hNcolVsBcInTF_vs_occupancy_nPV_10_200"), bcInTF, occupancy); + else if (nPV >= 2000) + histos.fill(HIST("hNcolVsBcInTF/hNcolVsBcInTF_vs_occupancy_nPV_above2000"), bcInTF, occupancy); + } - if (track.isGlobalTrack() && track.tpcNClsFound() >= confCutMinTPCcls) + // 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() < confMinITSclsPerTrack) + continue; + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 4); + // nPV++; + + // July 2025: more for data vs MC: + if (track.hasTPC() && occupancy >= 0 && confAddBasicQAhistos) { + float pt = track.pt(); + // pt 0.2-0.5 + if (pt > 0.2 && pt < 0.5) { + if (nPV >= 10 && nPV < 400) { + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcNClsFindable_vs_occup_pt_02_05"), track.tpcNClsFindable(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcNClsFound_vs_occup_pt_02_05"), track.tpcNClsFound(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcChi2NCl_vs_occup_pt_02_05"), track.tpcChi2NCl(), occupancy); + } else if (nPV >= 2000) { + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcNClsFindable_vs_occup_pt_02_05"), track.tpcNClsFindable(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcNClsFound_vs_occup_pt_02_05"), track.tpcNClsFound(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcChi2NCl_vs_occup_pt_02_05"), track.tpcChi2NCl(), occupancy); + } + } + // pt 0.5-1.0 + else if (pt > 0.5 && pt < 1.0) { + if (nPV >= 10 && nPV < 400) { + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcNClsFindable_vs_occup_pt_05_10"), track.tpcNClsFindable(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcNClsFound_vs_occup_pt_05_10"), track.tpcNClsFound(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcChi2NCl_vs_occup_pt_05_10"), track.tpcChi2NCl(), occupancy); + } else if (nPV >= 2000) { + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcNClsFindable_vs_occup_pt_05_10"), track.tpcNClsFindable(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcNClsFound_vs_occup_pt_05_10"), track.tpcNClsFound(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcChi2NCl_vs_occup_pt_05_10"), track.tpcChi2NCl(), occupancy); + } + } + // pt > 1.0 + else if (pt > 1.0) { + if (nPV >= 10 && nPV < 400) { + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcNClsFindable_vs_occup_pt_above1_0"), track.tpcNClsFindable(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcNClsFound_vs_occup_pt_above1_0"), track.tpcNClsFound(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_10_200/tpcChi2NCl_vs_occup_pt_above1_0"), track.tpcChi2NCl(), occupancy); + } else if (nPV >= 2000) { + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcNClsFindable_vs_occup_pt_above1_0"), track.tpcNClsFindable(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcNClsFound_vs_occup_pt_above1_0"), track.tpcNClsFound(), occupancy); + histos.fill(HIST("QA_noTPCcuts/nPV_above2000/tpcChi2NCl_vs_occup_pt_above1_0"), track.tpcChi2NCl(), occupancy); + } + } + } + + if (track.isGlobalTrack() && track.tpcNClsFound() >= confCutMinTPCcls) { nGlobalTracks++; - } + histos.fill(HIST("nTrackCounter_after_cuts_QA"), 5); + + if (track.passedTPCRefit() && confAddBasicQAhistos) { + 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()); + } + + // nTPCcls vs nITStr vs occup + histos.fill(HIST("tpcNClsFound_vs_centr_vs_occup"), nPV, occupancy, track.tpcNClsFound()); + histos.fill(HIST("tpcNClsFindable_vs_centr_vs_occup"), nPV, occupancy, track.tpcNClsFindable()); + histos.fill(HIST("tpcNClsShared_vs_centr_vs_occup"), nPV, occupancy, track.tpcNClsShared()); + + // nTPCsharedCls for A and C separately + if (track.tgl() > 0.) // A side + histos.fill(HIST("tpcNClsShared_vs_centr_vs_occup_Aside"), nPV, occupancy, track.tpcNClsShared()); + else // C side + histos.fill(HIST("tpcNClsShared_vs_centr_vs_occup_Cside"), nPV, occupancy, track.tpcNClsShared()); + + // nTPCsharedCls for pos and neg + if (signedP > 0) + histos.fill(HIST("tpcNClsShared_vs_centr_vs_occup_pos"), nPV, occupancy, track.tpcNClsShared()); + else + histos.fill(HIST("tpcNClsShared_vs_centr_vs_occup_neg"), nPV, occupancy, track.tpcNClsShared()); + } + } + } + } // end of track loop - if (confAddTracksVsFwdHistos) - histos.fill(HIST("nTracksGlobal_vs_nPV_QA_onlyVzCut_noTFROFborderCuts"), nPV, nGlobalTracks); + // 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 (confFlagApplyTFborderCut && !col.selection_bit(kNoTimeFrameBorder)) + // continue; - if (confAddTracksVsFwdHistos) - histos.fill(HIST("nTracksGlobal_vs_nPV_QA_after_TFborderCut"), nPV, nGlobalTracks); + // 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; + // if (confFlagApplyROFborderCut && !col.selection_bit(kNoITSROFrameBorder)) + // continue; - int occupancy = col.trackOccupancyInTimeRange(); histos.fill(HIST("hOccupancy"), occupancy); + if (occupancy >= 0 && confAddBasicQAhistos) { + int orbitId = bcInTF / o2::constants::lhc::LHCMaxBunches; + histos.fill(HIST("hOccupancyVsOrbit"), orbitId, occupancy); + } - auto t0cCentr = col.centFT0C(); - histos.fill(HIST("hCentrVsOccupancy"), t0cCentr, occupancy); + // another track loop to fill track-level histograms + if (confAddBasicQAhistos) { + int flagWhichDeltaTimeWin = vFlagsForEtaQAvsOccupancyInDeltaTimeWins[colIndex]; + bool flagNoCollNearby = col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow); + + 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() < confMinITSclsPerTrack) + continue; + // if (!(track.isGlobalTrack() && track.tpcNClsFound() >= confCutMinTPCcls)) + // continue; + + bool isGoodGlobal = (track.isGlobalTrack() && track.tpcNClsFound() >= confCutMinTPCcls); + bool hasTPCspecCuts = (track.hasTPC() && track.tpcNClsFound() >= confCutMinTPCcls && track.tpcNClsCrossedRows() > 80 && track.tpcChi2NCl() < 4); + + // ### kine distr vs centr vs occup + float sign = track.sign(); + float pt = track.pt(); + float eta = track.eta(); + float phi = track.phi(); + float phiInitial = phi; + + if (confUsePhiAtTPCinnerR) { + phi -= asin(confRadiusForPhiCorrection /*inner TPC radius*/ / 2 * 0.3 * sign * 0.5 / pt); + if (phi < 0) + phi += TMath::TwoPi(); + else if (phi > TMath::TwoPi()) + phi -= TMath::TwoPi(); + } + + bool etaInRange = true; + if (confUseAorCsideForPhiStudy == 0 && eta < 0.1) // check if we are in A side + etaInRange = false; + if (confUseAorCsideForPhiStudy == 1 && eta > -0.1) // check if we are in C side + etaInRange = false; + + if (occupancy >= 0 && fabs(eta) < 0.8 && pt > 0.15 && etaInRange) { + if (nPV >= 10 && nPV < 200) { + if (isGoodGlobal) { + if (flagWhichDeltaTimeWin == 1 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_lowOccupInTPC"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_lowOccupInTPC"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_lowOccupInTPC"), pt); + + if (sign > 0) + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_lowOccupInTPC_pos_vs_pt"), phi, pt); + else + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_lowOccupInTPC_neg_vs_pt"), phi, pt); + } + if (flagWhichDeltaTimeWin == 2 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_highOccupInRecentPast"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInRecentPast"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_highOccupInRecentPast"), pt); + + if (sign > 0) + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInRecentPast_pos_vs_pt"), phi, pt); + else + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInRecentPast_neg_vs_pt"), phi, pt); + } + if (flagWhichDeltaTimeWin == 3 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_highOccupInCloseFuture"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInCloseFuture"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_highOccupInCloseFuture"), pt); + + if (sign > 0) + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInCloseFuture_pos_vs_pt"), phi, pt); + else + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInCloseFuture_neg_vs_pt"), phi, pt); + } + if (flagWhichDeltaTimeWin == 4 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_highOccupInDistantFuture"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInDistantFuture"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_highOccupInDistantFuture"), pt); + + if (sign > 0) + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInDistantFuture_pos_vs_pt"), phi, pt); + else + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInDistantFuture_neg_vs_pt"), phi, pt); + } + if (flagWhichDeltaTimeWin == 5) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hEta_highOccupInNeighbourEvents"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInNeighbourEvents"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_highOccupInNeighbourEvents"), pt); + + if (sign > 0) + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInNeighbourEvents_pos_vs_pt"), phi, pt); + else + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPhi_highOccupInNeighbourEvents_neg_vs_pt"), phi, pt); + } + histos.fill(HIST("track_distr_nITStrThisEv_10_200/hPt_vs_tpcInnerPt_vs_occup"), pt, track.tpcInnerParam(), occupancy); + } // end of TPC good global + + // July 2025: for data vs MC kine distr comparison + + int tpcNClsFindable = track.tpcNClsFindable(); + int tpcNClsFound = track.tpcNClsFound(); + int tpcNClsCrossedRows = track.tpcNClsCrossedRows(); + + if (sign > 0) // positive tracks + { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hPt_pos"), pt, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hEta_pos"), eta, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hPhi_pos"), phi, occupancy, pt); + if (hasTPCspecCuts) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPt_pos"), pt, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hEta_pos"), eta, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_pos"), phi, occupancy, pt); + + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsFindable_pos"), phi, occupancy, pt, tpcNClsFindable); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsFound_pos"), phi, occupancy, pt, tpcNClsFound); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsCrossedRows_pos"), phi, occupancy, pt, tpcNClsCrossedRows); + + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/QA_tpcNClsFindable_pos"), tpcNClsFindable); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/QA_tpcNClsFound_pos"), tpcNClsFound); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/QA_tpcNClsCrossedRows_pos"), tpcNClsCrossedRows); + } + } else // negative tracks + { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hPt_neg"), pt, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hEta_neg"), eta, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/PV_hPhi_neg"), phi, occupancy, pt); + if (hasTPCspecCuts) { + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPt_neg"), pt, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hEta_neg"), eta, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_neg"), phi, occupancy, pt); + + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsFindable_neg"), phi, occupancy, pt, tpcNClsFindable); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsFound_neg"), phi, occupancy, pt, tpcNClsFound); + histos.fill(HIST("track_distr_nITStrThisEv_10_200/kine_vs_weighted_occup/hPhi_tpcNClsCrossedRows_neg"), phi, occupancy, pt, tpcNClsCrossedRows); + } + } + // end of July 2025: for data vs MC kine distr comparison + + } else if (nPV >= 2000) { + if (isGoodGlobal) { + if (flagWhichDeltaTimeWin == 1 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_lowOccupInTPC"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_lowOccupInTPC"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_lowOccupInTPC"), pt); + } + if (flagWhichDeltaTimeWin == 2 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_highOccupInRecentPast"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInRecentPast"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_highOccupInRecentPast"), pt); + } + if (flagWhichDeltaTimeWin == 3 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_highOccupInCloseFuture"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInCloseFuture"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_highOccupInCloseFuture"), pt); + } + if (flagWhichDeltaTimeWin == 4 && flagNoCollNearby) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_highOccupInDistantFuture"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInDistantFuture"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_highOccupInDistantFuture"), pt); + } + if (flagWhichDeltaTimeWin == 5) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hEta_highOccupInNeighbourEvents"), eta); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPhi_highOccupInNeighbourEvents"), phi); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_highOccupInNeighbourEvents"), pt); + } + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/hPt_vs_tpcInnerPt_vs_occup"), pt, track.tpcInnerParam(), occupancy); + } // end of TPC good global + + // July 2025: for data vs MC kine distr comparison + if (sign > 0) // positive tracks + { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hPt_pos"), pt, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hEta_pos"), eta, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hPhi_pos"), phi, occupancy, pt); + if (hasTPCspecCuts) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPt_pos"), pt, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hEta_pos"), eta, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_pos"), phi, occupancy, pt); + if (pt > 0.7 && pt < 1.0) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_posInitialQA"), phiInitial); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_posModifiedQA"), phi); + } + } + } else // negative tracks + { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hPt_neg"), pt, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hEta_neg"), eta, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/PV_hPhi_neg"), phi, occupancy, pt); + if (hasTPCspecCuts) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPt_neg"), pt, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hEta_neg"), eta, occupancy); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_neg"), phi, occupancy, pt); + if (pt > 0.7 && pt < 1.0) { + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_negInitialQA"), phiInitial); + histos.fill(HIST("track_distr_nITStrThisEv_above_2000/kine_vs_weighted_occup/hPhi_negModifiedQA"), phi); + } + } + } + // end of July 2025: for data vs MC kine distr comparison + } // end of if (nPV >= 2000) + } // end of if (occupancy >= 0) && kine cuts + } // end of spec track loop to fill track histograms + } // end of if (confAddBasicQAhistos) + + // special loop to fill THn histograms + if (confFlagFillTHn && occupancy >= 0) { + for (const auto& track : tracksGrouped) { + if (!track.isPVContributor()) + continue; + if (track.itsNCls() < confMinITSclsPerTrack) + continue; + + float pt = track.pt(); + float eta = track.eta(); + + if (fabs(eta) > 0.8) + continue; + if (pt < 0.15) + continue; + + bool hasTPCspecCuts = (track.hasTPC() && track.tpcNClsFound() >= confCutMinTPCcls && track.tpcNClsCrossedRows() > 80 && track.tpcChi2NCl() < 4); + if (!hasTPCspecCuts) + continue; + + float sign = track.sign(); + // if (sign < 0) + // continue; + + float qpt = track.signed1Pt(); + + // fill THnF: + for (int iRadius = 0; iRadius < 8; iRadius++) { + float R = (iRadius == 0 ? 0 : 0.8 + iRadius * 0.2); // cm + float phiAtR = track.phi(); + if (iRadius > 0) { + histos.fill(HIST("THnD_histos/QA_under_asin"), R / 2 * 0.3 * sign * 0.5 / pt); + histos.fill(HIST("THnD_histos/QA_asin"), asin(R / 2 * 0.3 * sign * 0.5 / pt)); + + phiAtR -= asin(R / 2 * 0.3 * sign * 0.5 / pt); + if (phiAtR < 0) + phiAtR += TMath::TwoPi(); + else if (phiAtR > TMath::TwoPi()) + phiAtR -= TMath::TwoPi(); + } + histos.fill(HIST("THnD_histos/phi_R_qOp_IR_occ_centr_eta"), phiAtR, iRadius, qpt, IR, occupancy, nPV, eta); + } + } + } // end of confFlagFillTHn + + // 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; @@ -679,47 +1543,39 @@ struct DetectorOccupancyQaTask { histos.fill(HIST("nTracksGlobal_vs_V0A_noOccupSel"), multV0A, nGlobalTracks); histos.fill(HIST("nTracksGlobal_vs_nPV_noOccupSel"), nPV, nGlobalTracks); - if (occupancy >= 0) + 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); - if (col.selection_bit(o2::aod::evsel::kNoHighOccupancyAgressive)) { - histos.fill(HIST("nTracksPV_vs_V0A_kNoHighOccupancyAgressive"), multV0A, nPV); - histos.fill(HIST("nTracksGlobal_vs_V0A_kNoHighOccupancyAgressive"), multV0A, nGlobalTracks); - histos.fill(HIST("nTracksGlobal_vs_nPV_kNoHighOccupancyAgressive"), nPV, nGlobalTracks); - } - if (col.selection_bit(o2::aod::evsel::kNoHighOccupancyStrict)) { - histos.fill(HIST("nTracksPV_vs_V0A_kNoHighOccupancyStrict"), multV0A, nPV); - histos.fill(HIST("nTracksGlobal_vs_V0A_kNoHighOccupancyStrict"), multV0A, nGlobalTracks); - histos.fill(HIST("nTracksGlobal_vs_nPV_kNoHighOccupancyStrict"), nPV, nGlobalTracks); - } - if (col.selection_bit(o2::aod::evsel::kNoHighOccupancyMedium)) { - histos.fill(HIST("nTracksPV_vs_V0A_kNoHighOccupancyMedium"), multV0A, nPV); - histos.fill(HIST("nTracksGlobal_vs_V0A_kNoHighOccupancyMedium"), multV0A, nGlobalTracks); - histos.fill(HIST("nTracksGlobal_vs_nPV_kNoHighOccupancyMedium"), nPV, nGlobalTracks); - } - if (col.selection_bit(o2::aod::evsel::kNoHighOccupancyRelaxed)) { - histos.fill(HIST("nTracksPV_vs_V0A_kNoHighOccupancyRelaxed"), multV0A, nPV); - histos.fill(HIST("nTracksGlobal_vs_V0A_kNoHighOccupancyRelaxed"), multV0A, nGlobalTracks); - histos.fill(HIST("nTracksGlobal_vs_nPV_kNoHighOccupancyRelaxed"), nPV, nGlobalTracks); - } - if (col.selection_bit(o2::aod::evsel::kNoHighOccupancyGentle)) { - histos.fill(HIST("nTracksPV_vs_V0A_kNoHighOccupancyGentle"), multV0A, nPV); - histos.fill(HIST("nTracksGlobal_vs_V0A_kNoHighOccupancyGentle"), multV0A, nGlobalTracks); - histos.fill(HIST("nTracksGlobal_vs_nPV_kNoHighOccupancyGentle"), nPV, nGlobalTracks); + 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) + if (occupancy >= 0) { histos.fill(HIST("nTracksGlobal_vs_nPV_vs_occup_kNoCollInTimeRangeNarrow"), nPV, nGlobalTracks, occupancy); + histos.fill(HIST("nTracksGlobal_vs_V0A_vs_occup_kNoCollInTimeRangeNarrow"), multV0A, nGlobalTracks, occupancy); + histos.fill(HIST("nPV_vs_V0A_vs_occup_kNoCollInTimeRangeNarrow"), multV0A, nPV, occupancy); + } } if (occupancy >= 0 && occupancy < 250) { histos.fill(HIST("nTracksPV_vs_V0A_occup_0_250"), multV0A, nPV); @@ -739,6 +1595,15 @@ struct DetectorOccupancyQaTask { 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); diff --git a/DPG/Tasks/AOTEvent/eventSelectionQa.cxx b/DPG/Tasks/AOTEvent/eventSelectionQa.cxx index 9946e871840..5087a5459ed 100644 --- a/DPG/Tasks/AOTEvent/eventSelectionQa.cxx +++ b/DPG/Tasks/AOTEvent/eventSelectionQa.cxx @@ -9,20 +9,51 @@ // 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 and Igor Altsybeev -#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 "TH1F.h" -#include "TH2F.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2::framework; using namespace o2; @@ -32,30 +63,31 @@ 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)"}; + Configurable fillITSdeadStaveHists{"fillITSdeadStaveHists", 0, "0 - no, 1 - yes"}; + Configurable fillTPCnClsVsOccupancyHists{"fillTPCnClsVsOccupancyHists", 0, "0 - no, 1 - yes"}; - 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 +107,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 +305,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 +337,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 +352,56 @@ 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 axisNtracksPV{200, -0.5, 5000 - 0.5, "n ITS PV tracks"}; + const AxisSpec axisNtracksPVTPC{160, -0.5, 4000 - 0.5, "n ITS-TPC PV tracks"}; + const AxisSpec axisNtracksTPConly{160, -0.5, 8000 - 0.5, "n TPC-only 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, axisNtracksPV, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNtracksPVTPC, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPVTPCLooseCuts_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNtracksPVTPC, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksITS_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNtracksPV, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksITSTPC_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNtracksPVTPC, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPV_vs_V0A_vs_occupancy_NarrowDeltaTimeCut", "", kTH3F, {axisMultV0AForOccup, axisNtracksPV, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy_NarrowDeltaTimeCut", "", kTH3F, {axisMultV0AForOccup, axisNtracksPVTPC, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPV_vs_V0A_vs_occupancy_StandardDeltaTimeCut", "", kTH3F, {axisMultV0AForOccup, axisNtracksPV, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy_StandardDeltaTimeCut", "", kTH3F, {axisMultV0AForOccup, axisNtracksPVTPC, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPV_vs_V0A_vs_occupancy_GoodITSLayersAllCut", "", kTH3F, {axisMultV0AForOccup, axisNtracksPV, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy_GoodITSLayersAllCut", "", kTH3F, {axisMultV0AForOccup, axisNtracksPVTPC, axisOccupancyTracks}); + // requested by TPC experts: nTPConly tracks vs occupancy + histos.add("occupancyQA/hNumTracksTPConly_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNtracksTPConly, axisOccupancyTracks}); + histos.add("occupancyQA/hNumTracksTPConlyNoITS_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNtracksTPConly, axisOccupancyTracks}); + // request from experts to add track properties vs occupancy, to compare data vs MC + if (fillTPCnClsVsOccupancyHists) { + const AxisSpec axisOccupancyForTrackQA{60, 0., 15000, "occupancy (n ITS tracks weighted)"}; + const AxisSpec axisNTPCcls{150, 0, 150, "n TPC clusters"}; + histos.add("occupancyQA/tpcNClsFound_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNTPCcls, axisOccupancyForTrackQA}); + histos.add("occupancyQA/tpcNClsFindable_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNTPCcls, axisOccupancyForTrackQA}); + histos.add("occupancyQA/tpcNClsShared_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNTPCcls, axisOccupancyForTrackQA}); + histos.add("occupancyQA/tpcNCrossedRows_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisNTPCcls, axisOccupancyForTrackQA}); + const AxisSpec axisChi2TPC{150, 0, 15, "chi2Ncl TPC"}; + histos.add("occupancyQA/tpcChi2_vs_V0A_vs_occupancy", "", kTH3F, {axisMultV0AForOccup, axisChi2TPC, axisOccupancyForTrackQA}); + } + + // ITS in-ROF occupancy + 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 +414,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 +459,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 +531,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 +616,131 @@ 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; + // number of orbits per TF + nOrbitsPerTF = runInfo.orbitsPerTF; + // duration of TF in bcs + nBCsPerTF = nOrbitsPerTF * nBCsPerOrbit; + // 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(info, "rofOffset={} rofLength={}", rofOffset, rofLength); + LOGP(info, "nOrbitsPerTF={} nBCsPerTF={}", nOrbitsPerTF, nBCsPerTF); + + // 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); - } - if (bcPatternC[i]) { - histos.fill(HIST("hBcC"), i); - } - if (bcPatternB[i]) { - histos.fill(HIST("hBcB"), 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.); } - 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); - } + // fill ITS dead maps + if (fillITSdeadStaveHists) { + 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}); + } + + 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 + } + // 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]); + } + } + } // end of fill ITS dead maps + } // 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}); @@ -598,11 +757,12 @@ struct EventSelectionQaTask { 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.); - const AxisSpec axisSeconds{static_cast(maxSec - minSec), minSec, maxSec, "seconds"}; + const AxisSpec axisSeconds{maxSec - minSec < 1000 ? static_cast(maxSec - minSec) : 1000, minSec, maxSec, "seconds"}; const AxisSpec axisBcDif{600, -300., 300., "bc difference"}; histos.add("hSecondsTVXvsBcDif", "", kTH2F, {axisSeconds, axisBcDif}); histos.add("hSecondsTVXvsBcDifAll", "", kTH2F, {axisSeconds, axisBcDif}); @@ -623,12 +783,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(); } } @@ -665,7 +825,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(); @@ -684,7 +844,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)); } @@ -715,22 +875,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); @@ -741,8 +901,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(); @@ -768,15 +928,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); @@ -789,8 +951,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(); @@ -810,7 +972,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()]++; @@ -826,10 +988,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)) { @@ -844,6 +1006,12 @@ struct EventSelectionQaTask { for (const auto& track : tracks) { auto mapAmbTrIdsIt = mapAmbTrIds.find(track.globalIndex()); int ambTrId = mapAmbTrIdsIt == mapAmbTrIds.end() ? -1 : mapAmbTrIdsIt->second; + + // special check to avoid crashes (in particular, on some MC Pb-Pb datasets) + // (related to shifts in ambiguous tracks association to bc slices (off by 1) - see https://mattermost.web.cern.ch/alice/pl/g9yaaf3tn3g4pgn7c1yex9copy + if (ambTrId >= 0 && (ambTracks.iteratorAt(ambTrId).bcIds()[0] >= bcs.size())) + continue; + int indexBc = ambTrId < 0 ? track.collision_as().bc_as().globalIndex() : ambTracks.iteratorAt(ambTrId).bc_as().begin().globalIndex(); auto bc = bcs.iteratorAt(indexBc); int64_t globalBC = bc.globalBC() + floor(track.trackTime() / o2::constants::lhc::LHCBunchSpacingNS); @@ -859,7 +1027,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; @@ -879,48 +1051,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)) { @@ -974,7 +1128,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; } } @@ -982,10 +1136,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; } } @@ -1002,10 +1157,136 @@ 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 nTPConly = 0; + // int nTPConlyWithDeDxCut = 0; + int nTPConlyNoITS = 0; + int nContributorsAfterEtaTPCCuts = 0; + int nContributorsAfterEtaTPCLooseCuts = 0; + + int nTracksITS = 0; + int nTracksITSTPC = 0; + + bool isTVX = col.selection_bit(kIsTriggerTVX); + + int occupancyByTracks = col.trackOccupancyInTimeRange(); + float occupancyByFT0C = col.ft0cOccupancyInTimeRange(); + + for (const auto& track : tracksGrouped) { + int trackBcDiff = bcDiff + track.trackTime() / o2::constants::lhc::LHCBunchSpacingNS; + + if (track.hasTPC() && std::fabs(track.eta()) < 0.8 && track.pt() > 0.2 && track.tpcNClsFound() > 50 && track.tpcNClsCrossedRows() > 50 && track.tpcChi2NCl() < 4) { + nTPConly++; + // if (track.tpcSignal() > 20) + // nTPConlyWithDeDxCut++; + if (!track.hasITS()) + nTPConlyNoITS++; + } + + if (std::fabs(track.eta()) < 0.8 && track.pt() > 0.2) { + if (track.hasITS()) { + nTracksITS++; + if (track.hasTPC()) + nTracksITSTPC++; + } + } + + if (!track.isPVContributor()) + continue; + + if (track.itsNCls() >= 5) + vTracksITS567perColl[colIndex]++; + + // high-quality contributors for ROF border QA and occupancy study + if (std::fabs(track.eta()) < 0.8 && track.pt() > 0.2 && track.itsNCls() >= 5) { + nPV++; + if (track.hasTPC()) { + nContributorsAfterEtaTPCLooseCuts++; + + if (!isLowFlux && fillTPCnClsVsOccupancyHists && col.sel8() && col.selection_bit(kNoSameBunchPileup) && fabs(col.posZ()) < 10 && occupancyByTracks >= 0) { + histos.fill(HIST("occupancyQA/tpcNClsFound_vs_V0A_vs_occupancy"), multV0A, track.tpcNClsFound(), occupancyByTracks); + histos.fill(HIST("occupancyQA/tpcNClsFindable_vs_V0A_vs_occupancy"), multV0A, track.tpcNClsFindable(), occupancyByTracks); + histos.fill(HIST("occupancyQA/tpcNClsShared_vs_V0A_vs_occupancy"), multV0A, track.tpcNClsShared(), occupancyByTracks); + histos.fill(HIST("occupancyQA/tpcChi2_vs_V0A_vs_occupancy"), multV0A, track.tpcChi2NCl(), occupancyByTracks); + int tpcNClsFindableMinusCrossedRowsCorrected = track.tpcNClsFindableMinusCrossedRows(); + // correct for a buggy behaviour due to int8 and uint8 difference: + if (tpcNClsFindableMinusCrossedRowsCorrected < -70) + tpcNClsFindableMinusCrossedRowsCorrected += 256; + histos.fill(HIST("occupancyQA/tpcNCrossedRows_vs_V0A_vs_occupancy"), multV0A, track.tpcNClsFindable() - tpcNClsFindableMinusCrossedRowsCorrected, occupancyByTracks); + } + } // end of hasTPC + if (col.sel8() && fabs(col.posZ()) < 10 && track.tpcNClsFound() > 50 && 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() && col.selection_bit(kNoSameBunchPileup) && fabs(col.posZ()) < 10) { + histos.fill(HIST("occupancyQA/hOccupancyByTracks"), occupancyByTracks); + 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); + histos.fill(HIST("occupancyQA/hNumTracksPVTPCLooseCuts_vs_V0A_vs_occupancy"), multV0A, nContributorsAfterEtaTPCLooseCuts, occupancyByTracks); + histos.fill(HIST("occupancyQA/hNumTracksITS_vs_V0A_vs_occupancy"), multV0A, nTracksITS, occupancyByTracks); + histos.fill(HIST("occupancyQA/hNumTracksITSTPC_vs_V0A_vs_occupancy"), multV0A, nTracksITSTPC, occupancyByTracks); + if (col.selection_bit(kNoCollInTimeRangeNarrow)) { + histos.fill(HIST("occupancyQA/hNumTracksPV_vs_V0A_vs_occupancy_NarrowDeltaTimeCut"), multV0A, nPV, occupancyByTracks); + histos.fill(HIST("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy_NarrowDeltaTimeCut"), multV0A, nContributorsAfterEtaTPCCuts, occupancyByTracks); + } + if (col.selection_bit(kNoCollInTimeRangeStandard)) { + histos.fill(HIST("occupancyQA/hNumTracksPV_vs_V0A_vs_occupancy_StandardDeltaTimeCut"), multV0A, nPV, occupancyByTracks); + histos.fill(HIST("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy_StandardDeltaTimeCut"), multV0A, nContributorsAfterEtaTPCCuts, occupancyByTracks); + } + if (col.selection_bit(kIsGoodITSLayersAll)) { + histos.fill(HIST("occupancyQA/hNumTracksPV_vs_V0A_vs_occupancy_GoodITSLayersAllCut"), multV0A, nPV, occupancyByTracks); + histos.fill(HIST("occupancyQA/hNumTracksPVTPC_vs_V0A_vs_occupancy_GoodITSLayersAllCut"), multV0A, nContributorsAfterEtaTPCCuts, occupancyByTracks); + } + histos.fill(HIST("occupancyQA/hNumTracksTPConly_vs_V0A_vs_occupancy"), multV0A, nTPConly, occupancyByTracks); + histos.fill(HIST("occupancyQA/hNumTracksTPConlyNoITS_vs_V0A_vs_occupancy"), multV0A, nTPConlyNoITS, 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() > 50 && 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()) { @@ -1016,9 +1297,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)) { @@ -1026,16 +1314,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 @@ -1044,7 +1330,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); } @@ -1054,7 +1340,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); @@ -1071,21 +1357,104 @@ 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; int64_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; - histos.fill(HIST("hGlobalBcColMC"), globalBC - minGlobalBC); - histos.fill(HIST("hOrbitColMC"), orbit - minOrbit); + 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()); @@ -1093,19 +1462,40 @@ struct EventSelectionQaTask { 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/lightIonsEvSelQa.cxx b/DPG/Tasks/AOTEvent/lightIonsEvSelQa.cxx new file mode 100644 index 00000000000..e87ca9c73f3 --- /dev/null +++ b/DPG/Tasks/AOTEvent/lightIonsEvSelQa.cxx @@ -0,0 +1,1902 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +// #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/BunchFilling.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsFT0/RecPoints.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "TH1F.h" +#include "TH2F.h" +#include "TH3.h" + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::evsel; + +using BCsRun3 = soa::Join; +using ColEvSels = soa::Join; //, aod::CentFT0Cs>; +// using FullTracksIU = soa::Join; +using FullTracksIU = soa::Join; + +struct LightIonsEvSelQa { + Configurable confCutMinTPCcls{"MinNumTPCcls", 50, "min number of TPC clusters for a current event"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nBinsTracks{"nBinsTracks", 450, "N bins in n tracks histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nMaxTracks{"nMaxTracks", 450, "N max in n tracks histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nMaxGlobalTracks{"nMaxGlobalTracks", 450, "N max in n tracks histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nBinsMultFwd{"nBinsMultFwd", 800, "N bins in mult fwd histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable nMaxMultFwd{"nMaxMultFwd", 100000, "N max in mult fwd histo"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable timeBinWidthInSec{"TimeBinWidthInSec", 10, "Width of time bins in seconds"}; // o2-linter: disable=name/configurable (temporary fix) + + Configurable nSigmaForVzDiff{"nSigmaForVzDiff", 2.5, "n +/- sigma for diff vZ"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable safetyDiffVzMargin{"SafetyDiffVzMargin", 0.5, "margin for diff vZ, cm"}; // o2-linter: disable=name/configurable (temporary fix) + + Configurable confUseDiffVzCutFromEvSel{"UseDiffVzCutFromEvSel", 0, "0 - custom diffVz cut from this task, 1 - cut from event selection"}; // o2-linter: disable=name/configurable (temporary fix) + + Configurable isMC{"isMC", false, "Run MC"}; + + uint64_t minGlobalBC = 0; + Service ccdb; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + bool* applySelection = NULL; + int nBCsPerOrbit = 3564; + int lastRunNumber = -1; + double maxSec = 1; + double minSec = 0; + int64_t bcSOR = 0; // global bc of the start of the first orbit, setting 0 by default for unanchored MC + int64_t nBCsPerTF = 32 * 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/hNcolVsBcInTF", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + // histos.add("hNcolVsBcInTF/hNcolVsBcInTF_vertexTOFmatched", ";bc in TF; n collisions", kTH1F, {axisBCinTF}); + + // ############## + const AxisSpec axisBCs{nBCsPerOrbit, 0., static_cast(nBCsPerOrbit), ""}; + + histos.add("bcQA/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("bcQA/pastActivity/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("bcQA/futureActivity/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("bcQA/noPastActivity/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("bcQA/noFutureActivity/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("bcQA/noPastFutureActivity/hBcFV0", "", kTH1F, {axisBCs}); + + histos.add("bcQA/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("bcQA/pastActivity/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("bcQA/futureActivity/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("bcQA/noPastActivity/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("bcQA/noFutureActivity/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("bcQA/noPastFutureActivity/hBcFT0", "", kTH1F, {axisBCs}); + + histos.add("bcQA/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("bcQA/pastActivity/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("bcQA/futureActivity/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("bcQA/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("bcQA/pastActivity/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("bcQA/futureActivity/hBcZDC", "", kTH1F, {axisBCs}); + + histos.add("bcQA/specFT0bits/hBc_kIsActiveSideA", "", kTH1F, {axisBCs}); + histos.add("bcQA/specFT0bits/hBc_kIsActiveSideC", "", kTH1F, {axisBCs}); + histos.add("bcQA/specFT0bits/hBc_kIsFlangeEvent", "", kTH1F, {axisBCs}); + + histos.add("bcQA/specFT0bits/hBc_kIsActiveSideA_inTVX", "", kTH1F, {axisBCs}); + histos.add("bcQA/specFT0bits/hBc_kIsActiveSideC_inTVX", "", kTH1F, {axisBCs}); + histos.add("bcQA/specFT0bits/hBc_kIsFlangeEvent_inTVX", "", kTH1F, {axisBCs}); + + const AxisSpec axisNtracks{nBinsTracks, -0.5, nMaxTracks - 0.5, "n tracks"}; + const AxisSpec axisNtracksGlobal{nBinsTracks, -0.5, nMaxGlobalTracks - 0.5, "n tracks"}; + const AxisSpec axisMultV0A{nBinsMultFwd, 0., static_cast(nMaxMultFwd), "mult V0A"}; + const AxisSpec axisMultFT0A{nBinsMultFwd, 0., static_cast(nMaxMultFwd * 0.4), "mult FT0C"}; + const AxisSpec axisMultFT0C{nBinsMultFwd, 0., static_cast(nMaxMultFwd * 0.15), "mult FT0C"}; + const AxisSpec axisMultT0M{nBinsMultFwd * 2, 0., static_cast(nMaxMultFwd * 0.4), "mult FT0M"}; + + const AxisSpec axisVtxZ{800, -20., 20., ""}; + const AxisSpec axisBcDiff{601, -300.5, 300.5, "bc difference"}; + + const AxisSpec axisNcontrib{601, -0.5, 600.5, "n contributors"}; + const AxisSpec axisColTimeRes{1500, 0., 1500., "collision time resolution (ns)"}; + + AxisSpec axisVertexChi2{100, 0, 500, "Chi2 of vertex fit"}; + AxisSpec axisVertexChi2perContrib{100, 0, 10, "Chi2 of vertex fit"}; + + const AxisSpec axisTimeZN{800, -20., 20., ""}; + const AxisSpec axisTimeDiff{150, -10., 10., ""}; + const AxisSpec axisTimeSum{150, -10., 10., ""}; + const AxisSpec axisZNampl{200, 0, 10000, ""}; + + histos.add("noSpecSelections/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noSpecSelections/hBcOrigNoSel8", "", kTH1F, {axisBCs}); + // histos.add("noSpecSelections/hBcColNoSel8TOF", "", kTH1F, {axisBCs}); + histos.add("noSpecSelections/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noSpecSelections/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noSpecSelections/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noSpecSelections/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noSpecSelections/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("noSpecSelections/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noSpecSelections/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noSpecSelections/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noSpecSelections/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noSpecSelections/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noSpecSelections/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noSpecSelections/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noSpecSelections/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noSpecSelections/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noSpecSelections/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noSpecSelections/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noSpecSelections/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noSpecSelections/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noSpecSelections/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + histos.add("noSpecSelections/hTimeZN_AC_sum_vs_diff", ";ZNC-ZNA time (ns); ZNC+ZNA time (ns)", kTH2F, {axisTimeDiff, axisTimeSum}); + histos.add("noSpecSelections/hTimeZN_A_vs_C", ";ZNA time (ns); ZNC time (ns)", kTH2F, {axisTimeZN, axisTimeZN}); + histos.add("noSpecSelections/hTimeZNA", ";ZNA time (ns)", kTH1F, {axisTimeZN}); + histos.add("noSpecSelections/hTimeZNC", ";ZNC time (ns)", kTH1F, {axisTimeZN}); + + histos.add("noPU/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU/hBcOrigNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("noPU/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + histos.add("noPU/hTimeZN_AC_sum_vs_diff", ";ZNC-ZNA time (ns); ZNC+ZNA time (ns)", kTH2F, {axisTimeDiff, axisTimeSum}); + histos.add("noPU/hTimeZN_A_vs_C", ";ZNA time (ns); ZNC time (ns)", kTH2F, {axisTimeZN, axisTimeZN}); + histos.add("noPU/hTimeZNA", ";ZNA time (ns)", kTH1F, {axisTimeZN}); + histos.add("noPU/hTimeZNC", ";ZNC time (ns)", kTH1F, {axisTimeZN}); + histos.add("noPU/hAmplZNAC", "ZNC vs ZNA", kTH2F, {axisZNampl, axisZNampl}); + + histos.add("noPU_pvTOFmatched/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTOFmatched/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTOFmatched/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTOFmatched/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTOFmatched/hBcFV0", "", kTH1F, {axisBCs}); + // histos.add("noPU_pvTOFmatched/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTOFmatched/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTOFmatched/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_pvTOFmatched/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_pvTOFmatched/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_pvTOFmatched/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_pvTOFmatched/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_pvTOFmatched/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_pvTOFmatched/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_pvTOFmatched/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_pvTOFmatched/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_pvTOFmatched/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_pvTOFmatched/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_pvTOFmatched/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU_pvTOFmatched/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_pvTRDmatched/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTRDmatched/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTRDmatched/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTRDmatched/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTRDmatched/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTRDmatched/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTRDmatched/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_pvTRDmatched/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_pvTRDmatched/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_pvTRDmatched/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_pvTRDmatched/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_pvTRDmatched/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_pvTRDmatched/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_pvTRDmatched/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_pvTRDmatched/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_pvTRDmatched/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_pvTRDmatched/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_pvTRDmatched/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU_pvTRDmatched/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_notTRDmatched/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_notTRDmatched/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_notTRDmatched/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_notTRDmatched/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_notTRDmatched/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_notTRDmatched/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_notTRDmatched/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_notTRDmatched/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_notTRDmatched/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_notTRDmatched/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_notTRDmatched/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_notTRDmatched/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_notTRDmatched/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_notTRDmatched/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_notTRDmatched/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_notTRDmatched/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_notTRDmatched/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_notTRDmatched/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_pvTOFmatched_notTRDmatched/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_pvTOFmatched_notTRDmatched/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_pvTOFmatched_notTRDmatched/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_pvTOFmatched_notTRDmatched/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("bcDiffWrtClosestTVXCut/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("bcDiffWrtClosestTVXCut/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("bcDiffWrtClosestTVXCut/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("bcDiffWrtClosestTVXCut/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("bcDiffWrtClosestTVXCut/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("bcDiffWrtClosestTVXCut/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("bcDiffWrtClosestTVXCut/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("bcDiffWrtClosestTVXCut/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("bcDiffWrtClosestTVXCut/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("bcDiffWrtClosestTVXCut/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("bcDiffWrtClosestTVXCut/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + // histos.add("bcDiffWrtClosestTVXCut/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + // histos.add("bcDiffWrtClosestTVXCut/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + // histos.add("bcDiffWrtClosestTVXCut/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("bcDiffWrtClosestTVXCut/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("bcDiffWrtClosestTVXCut/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("bcDiffWrtClosestTVXCut/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("bcDiffWrtClosestTVXCut/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_bcDiffWrtOriginalBcCut/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_bcDiffWrtOriginalBcCut/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_bcDiffWrtOriginalBcCut/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_bcDiffWrtOriginalBcCut/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + // histos.add("noPU_bcDiffWrtOriginalBcCut/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + // histos.add("noPU_bcDiffWrtOriginalBcCut/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + // histos.add("noPU_bcDiffWrtOriginalBcCut/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_bcDiffWrtOriginalBcCut/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_goodVertexChi2/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVertexChi2/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVertexChi2/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVertexChi2/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVertexChi2/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVertexChi2/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVertexChi2/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_goodVertexChi2/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_goodVertexChi2/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_goodVertexChi2/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_goodVertexChi2/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + // histos.add("noPU_goodVertexChi2/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + // histos.add("noPU_goodVertexChi2/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + // histos.add("noPU_goodVertexChi2/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_goodVertexChi2/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_goodVertexChi2/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_goodVertexChi2/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_goodVertexChi2/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("narrowTimeVeto/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("narrowTimeVeto/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("narrowTimeVeto/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("narrowTimeVeto/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("narrowTimeVeto/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("narrowTimeVeto/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("narrowTimeVeto/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("narrowTimeVeto/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("narrowTimeVeto/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("narrowTimeVeto/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("narrowTimeVeto/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("narrowTimeVeto/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("narrowTimeVeto/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("narrowTimeVeto/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("narrowTimeVeto/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("narrowTimeVeto/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("narrowTimeVeto/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("narrowTimeVeto/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("strictTimeVeto/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("strictTimeVeto/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("strictTimeVeto/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("strictTimeVeto/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("strictTimeVeto/hBcFV0", "", kTH1F, {axisBCs}); + // histos.add("strictTimeVeto/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("strictTimeVeto/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("strictTimeVeto/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("strictTimeVeto/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("strictTimeVeto/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("strictTimeVeto/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("strictTimeVeto/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("strictTimeVeto/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("strictTimeVeto/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("strictTimeVeto/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("strictTimeVeto/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("strictTimeVeto/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("strictTimeVeto/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("strictTimeVeto/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noCollSameROF/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noCollSameROF/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noCollSameROF/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noCollSameROF/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noCollSameROF/hBcFV0", "", kTH1F, {axisBCs}); + // histos.add("noCollSameROF/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("noCollSameROF/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noCollSameROF/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noCollSameROF/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noCollSameROF/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noCollSameROF/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noCollSameROF/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noCollSameROF/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noCollSameROF/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noCollSameROF/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noCollSameROF/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noCollSameROF/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noCollSameROF/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noCollSameROF/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("lowMultCut/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("lowMultCut/hBcOrigNoSel8", "", kTH1F, {axisBCs}); + histos.add("lowMultCut/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + + histos.add("noPU_lowMultCut/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_lowMultCut/hBcOrigNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_lowMultCut/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_lowMultCut/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_lowMultCut/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_lowMultCut/hBcFV0", "", kTH1F, {axisBCs}); + // histos.add("noPU_lowMultCut/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("noPU_lowMultCut/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_lowMultCut/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_lowMultCut/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_lowMultCut/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_lowMultCut/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_lowMultCut/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_lowMultCut/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_lowMultCut/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_lowMultCut/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_lowMultCut/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_lowMultCut/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_lowMultCut/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_lowMultCut/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU_lowMultCut/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + histos.add("noPU_lowMultCut/hTimeZN_AC_sum_vs_diff", ";ZNC-ZNA time (ns); ZNC+ZNA time (ns)", kTH2F, {axisTimeDiff, axisTimeSum}); + histos.add("noPU_lowMultCut/hTimeZN_A_vs_C", ";ZNA time (ns); ZNC time (ns)", kTH2F, {axisTimeZN, axisTimeZN}); + histos.add("noPU_lowMultCut/hTimeZNA", ";ZNA time (ns)", kTH1F, {axisTimeZN}); + histos.add("noPU_lowMultCut/hTimeZNC", ";ZNC time (ns)", kTH1F, {axisTimeZN}); + + histos.add("highMultCloudCut/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("highMultCloudCut/hBcOrigNoSel8", "", kTH1F, {axisBCs}); + histos.add("highMultCloudCut/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + + histos.add("noPU_highMultCloudCut/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_highMultCloudCut/hBcOrigNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_highMultCloudCut/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_highMultCloudCut/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_highMultCloudCut/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_highMultCloudCut/hBcFV0", "", kTH1F, {axisBCs}); + // histos.add("noPU_highMultCloudCut/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("noPU_highMultCloudCut/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_highMultCloudCut/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_highMultCloudCut/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_highMultCloudCut/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_highMultCloudCut/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_highMultCloudCut/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_highMultCloudCut/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_highMultCloudCut/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_highMultCloudCut/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_highMultCloudCut/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_highMultCloudCut/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_highMultCloudCut/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_highMultCloudCut/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU_highMultCloudCut/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + histos.add("noPU_highMultCloudCut/hTimeZN_AC_sum_vs_diff", ";ZNC-ZNA time (ns); ZNC+ZNA time (ns)", kTH2F, {axisTimeDiff, axisTimeSum}); + histos.add("noPU_highMultCloudCut/hTimeZN_A_vs_C", ";ZNA time (ns); ZNC time (ns)", kTH2F, {axisTimeZN, axisTimeZN}); + histos.add("noPU_highMultCloudCut/hTimeZNA", ";ZNA time (ns)", kTH1F, {axisTimeZN}); + histos.add("noPU_highMultCloudCut/hTimeZNC", ";ZNC time (ns)", kTH1F, {axisTimeZN}); + + histos.add("noPU_badVzDiff/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_badVzDiff/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_badVzDiff/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_badVzDiff/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_badVzDiff/hBcFV0", "", kTH1F, {axisBCs}); + // histos.add("noPU_badVzDiff/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("noPU_badVzDiff/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_badVzDiff/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_badVzDiff/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_badVzDiff/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_badVzDiff/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_badVzDiff/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_badVzDiff/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_badVzDiff/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_badVzDiff/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_badVzDiff/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_badVzDiff/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_badVzDiff/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_badVzDiff/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU_badVzDiff/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_goodVzDiff/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_goodVzDiff/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_goodVzDiff/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_goodVzDiff/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_goodVzDiff/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_goodVzDiff/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_goodVzDiff/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_goodVzDiff/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_goodVzDiff/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU_goodVzDiff/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_goodVzDiff_narrowTimeVeto/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU_goodVzDiff_narrowTimeVeto/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_goodVzDiff_strictTimeVeto/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_goodVzDiff_strictTimeVeto/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_goodVzDiff_strictTimeVeto/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_goodVzDiff_strictTimeVeto/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_goodVzDiff_strictTimeVeto/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff_strictTimeVeto/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff_strictTimeVeto/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hVertexChi2VsNcontrib", "", kTH2F, {axisNcontrib, axisVertexChi2perContrib}); + histos.add("noPU_goodVzDiff_strictTimeVeto/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_noPastActivity/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_noPastActivity/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_noPastActivity/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_noPastActivity/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_noPastActivity/hBcFV0", "", kTH1F, {axisBCs}); + // histos.add("noPU_noPastActivity/hBcFDD", "", kTH1F, {axisBCs}); + histos.add("noPU_noPastActivity/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_noPastActivity/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_noPastActivity/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_noPastActivity/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_noPastActivity/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_noPastActivity/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + // histos.add("noPU_noPastActivity/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + // histos.add("noPU_noPastActivity/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + // histos.add("noPU_noPastActivity/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_noPastActivity/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_noPastActivity/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_noPastActivity/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_noPastActivity/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_noFT0activityNearby/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_noFT0activityNearby/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_noFT0activityNearby/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_noFT0activityNearby/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_noFT0activityNearby/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_noFT0activityNearby/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_noFT0activityNearby/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_noFT0activityNearby/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_noFT0activityNearby/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_noFT0activityNearby/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_noFT0activityNearby/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + // histos.add("noPU_noFT0activityNearby/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + // histos.add("noPU_noFT0activityNearby/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + // histos.add("noPU_noFT0activityNearby/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_noFT0activityNearby/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_noFT0activityNearby/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_noFT0activityNearby/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_noFT0activityNearby/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_cutByVzDiff_pvTOF/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_pvTOF/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_pvTOF/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_pvTOF/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_pvTOF/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_pvTOF/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_pvTOF/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_cutByVzDiff_pvTOF/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_cutByVzDiff_pvTOF/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_cutByVzDiff_pvTOF/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_cutByVzDiff_pvTOF/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_cutByVzDiff_pvTOF/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + histos.add("noPU_cutByVzDiff_pvTOF/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + histos.add("noPU_cutByVzDiff_pvTOF/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_cutByVzDiff_pvTOF/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_cutByVzDiff_pvTOF/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_cutByVzDiff_pvTOF/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_cutByVzDiff_pvTOF/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + histos.add("noPU_cutByVzDiff_pvTOF/hTimeZN_AC_sum_vs_diff", ";ZNC-ZNA time (ns); ZNC+ZNA time (ns)", kTH2F, {axisTimeDiff, axisTimeSum}); + histos.add("noPU_cutByVzDiff_pvTOF/hTimeZN_A_vs_C", ";ZNA time (ns); ZNC time (ns)", kTH2F, {axisTimeZN, axisTimeZN}); + histos.add("noPU_cutByVzDiff_pvTOF/hTimeZNA", ";ZNA time (ns)", kTH1F, {axisTimeZN}); + histos.add("noPU_cutByVzDiff_pvTOF/hTimeZNC", ";ZNC time (ns)", kTH1F, {axisTimeZN}); + + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + // histos.add("noPU_cutByVzDiff_noFT0activityNearby/nTracksGlobal_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracksGlobal}); + // histos.add("noPU_cutByVzDiff_noFT0activityNearby/nTracksGlobal_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracksGlobal}); + // histos.add("noPU_cutByVzDiff_noFT0activityNearby/nTracksGlobal_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracksGlobal}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_cutByVzDiff_noFT0activityNearby/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + + histos.add("noPU_CutOnZNACtime/hBcColNoSel8", "", kTH1F, {axisBCs}); + histos.add("noPU_CutOnZNACtime/hBcTVX", "", kTH1F, {axisBCs}); + histos.add("noPU_CutOnZNACtime/hBcOrig", "", kTH1F, {axisBCs}); + histos.add("noPU_CutOnZNACtime/hBcFT0", "", kTH1F, {axisBCs}); + histos.add("noPU_CutOnZNACtime/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_CutOnZNACtime/hBcZDC", "", kTH1F, {axisBCs}); + histos.add("noPU_CutOnZNACtime/hVtxFT0VsVtxCol", "", kTH2F, {axisVtxZ, axisVtxZ}); + histos.add("noPU_CutOnZNACtime/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_CutOnZNACtime/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_CutOnZNACtime/nTracksPV_vs_T0A", "", kTH2F, {axisMultFT0A, axisNtracks}); + histos.add("noPU_CutOnZNACtime/nTracksPV_vs_T0C", "", kTH2F, {axisMultFT0C, axisNtracks}); + histos.add("noPU_CutOnZNACtime/hTVXvsBcDiffwrtOrigBc", "", kTH1F, {axisBcDiff}); + histos.add("noPU_CutOnZNACtime/hColTimeResVsNcontrib", "", kTH2F, {axisNcontrib, axisColTimeRes}); + histos.add("noPU_CutOnZNACtime/hColBcDiffVsNcontrib", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("noPU_CutOnZNACtime/hNPVvsNch", "", kTH2F, {axisNcontrib, axisNcontrib}); + histos.add("noPU_CutOnZNACtime/hTimeZN_AC_sum_vs_diff", ";ZNC-ZNA time (ns); ZNC+ZNA time (ns)", kTH2F, {axisTimeDiff, axisTimeSum}); + histos.add("noPU_CutOnZNACtime/hAmplZNAC", "ZNC vs ZNA", kTH2F, {axisZNampl, axisZNampl}); + histos.add("noPU_CutOnZNACtime/hTimeZN_A_vs_C", ";ZNA time (ns); ZNC time (ns)", kTH2F, {axisTimeZN, axisTimeZN}); + histos.add("noPU_CutOnZNACtime/hTimeZNA", ";ZNA time (ns)", kTH1F, {axisTimeZN}); + histos.add("noPU_CutOnZNACtime/hTimeZNC", ";ZNC time (ns)", kTH1F, {axisTimeZN}); + + histos.add("noPU_AntiCutOnZNACtime/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_AntiCutOnZNACtime/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_AntiCutOnZNACtime/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_AntiCutOnZNACtime/hAmplZNAC", "ZNC vs ZNA", kTH2F, {axisZNampl, axisZNampl}); + + histos.add("noPU_AntiCutOnZNAampl/hBcFV0", "", kTH1F, {axisBCs}); + histos.add("noPU_AntiCutOnZNAampl/hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, {axisVtxZ, axisMultT0M}); + histos.add("noPU_AntiCutOnZNAampl/nTracksPV_vs_V0A", "", kTH2F, {axisMultV0A, axisNtracks}); + histos.add("noPU_AntiCutOnZNAampl/hAmplZNAC", "ZNC vs ZNA", kTH2F, {axisZNampl, axisZNampl}); + + // + histos.add("hNcontribColFromData", "", kTH1F, {axisNcontrib}); + histos.add("hNcontribAccFromData", "", kTH1F, {axisNcontrib}); + + // MC QA + const AxisSpec axisVtxZdiff{400, -10., 10., ""}; + histos.add("MC/hMCdataVzDiff", "", kTH2F, {axisNcontrib, axisVtxZdiff}); + histos.add("MC/hMCdataBcDiffVsMult", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("MC/hMCdataFoundBcDiffVsMult", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("MCsel8/hMCdataVzDiff", "", kTH2F, {axisNcontrib, axisVtxZdiff}); + histos.add("MCsel8/hMCdataVzDiff_vertTRDmatched", "", kTH2F, {axisNcontrib, axisVtxZdiff}); + histos.add("MCsel8/hMCdataVzDiff_vertTOFmatched", "", kTH2F, {axisNcontrib, axisVtxZdiff}); + histos.add("MCsel8/hMCdataBcDiffVsMult", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("MCsel8/hMCdataFoundBcDiffVsMult", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("MCsel8/hMCdataFoundBcDiffVsMult_vertTRDmatched", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("MCsel8/hMCdataFoundBcDiffVsMult_vertTOFmatched", "", kTH2F, {axisNcontrib, axisBcDiff}); + + histos.add("MCnonTVX/hMCdataVzDiff", "", kTH2F, {axisNcontrib, axisVtxZdiff}); + histos.add("MCnonTVX/hMCdataBcDiffVsMult", "", kTH2F, {axisNcontrib, axisBcDiff}); + histos.add("MCnonTVX/hMCdataFoundBcDiffVsMult", "", kTH2F, {axisNcontrib, axisBcDiff}); + + // + histos.add("MC_not_TF_ROF_borders/hNcontribColFromData", "", kTH1F, {axisNcontrib}); + histos.add("MC_not_TF_ROF_borders/hNcontribAccFromData", "", kTH1F, {axisNcontrib}); + histos.add("MC_not_TF_ROF_borders/hNcontribColFromData_foundBcDiff0", "", kTH1F, {axisNcontrib}); + histos.add("MC_not_TF_ROF_borders/hNcontribAccFromData_foundBcDiff0", "", kTH1F, {axisNcontrib}); + } + + Preslice perCollision = aod::track::collisionId; + + 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 processRun3( + ColEvSels const& cols, + FullTracksIU const& tracks, + BCsRun3 const& bcs, + aod::Zdcs const&, + aod::FT0s const&) + { + int runNumber = bcs.iteratorAt(0).runNumber(); + if (runNumber != lastRunNumber) { + lastRunNumber = runNumber; // do it only once + + 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 * o2::constants::lhc::LHCMaxBunches; + // duration of TF in bcs + nBCsPerTF = runInfo.orbitsPerTF * o2::constants::lhc::LHCMaxBunches; + + // start-of-run timestamp + tsSOR = runInfo.sor; + // end-of-run timestamp + tsEOR = runInfo.eor; + + LOGP(info, "bcSOR = {}, nBCsPerTF = {}", bcSOR, nBCsPerTF); + } + + minSec = floor(tsSOR / 1000.); + maxSec = ceil(tsEOR / 1000.); + int nTimeBins = static_cast((maxSec - minSec) / timeBinWidthInSec); + double timeInterval = nTimeBins * timeBinWidthInSec; + + const AxisSpec axisSeconds{nTimeBins, 0, timeInterval, "seconds"}; + histos.add("hSecondsCollisions/sel8", "", kTH1F, {axisSeconds}); + histos.add("hSecondsCollisions/noPU", "", kTH1F, {axisSeconds}); + histos.add("hSecondsCollisions/noPU_underLine", "", kTH1F, {axisSeconds}); + histos.add("hSecondsCollisions/noPU_grassOnTheRight", "", kTH1F, {axisSeconds}); + histos.add("hSecondsCollisions/noPU_good", "", kTH1F, {axisSeconds}); + + const AxisSpec axisDiffMeanVz{80, -4, 4, ""}; + const AxisSpec axisVzNarrow{40, -10, 10, ""}; + histos.add("hSecondsCollisions/noPU_meanDiffVz", "", kTH2F, {axisSeconds, axisDiffMeanVz}); + histos.add("hSecondsCollisions/noPU_meanDiffVz_lowMult", "", kTH2F, {axisSeconds, axisDiffMeanVz}); + histos.add("hSecondsCollisions/noPU_meanDiffVz_highMult", "", kTH2F, {axisSeconds, axisDiffMeanVz}); + histos.add("hSecondsCollisions/noPU_Vz", "", kTH2F, {axisSeconds, axisVzNarrow}); + histos.add("hSecondsCollisions/noPU_VzByFT0", "", kTH2F, {axisSeconds, axisVzNarrow}); + + const AxisSpec axisVz{200, -20, 20, ""}; + histos.add("noSpecSelections/Vz", "", kTH1F, {axisVz}); + histos.add("noPU/Vz", "", kTH1F, {axisVz}); + histos.add("noPU_badVzDiff/Vz", "", kTH1F, {axisVz}); + histos.add("noPU_goodVzDiff/Vz", "", kTH1F, {axisVz}); + + } // end of runNumber check + + // vectors of TVX flags used for past-future studies + int nBCs = bcs.size(); + std::vector vIsTVX(nBCs, 0); + std::vector vGlobalBCs(nBCs, 0); + + std::vector vPastActivity(nBCs, 0); + std::vector vFutureActivity(nBCs, 0); + std::vector vNearbyFT0activity(nBCs, 0); + + // create maps from globalBC to bc index for TVX or FT0-OR fired bcs + // to be used for closest TVX (FT0-OR) searches + std::map mapGlobalBcWithTVX; + std::map mapGlobalBcWithTOR; + + // ### BC loop + for (const auto& bc : bcs) { + uint64_t globalBC = bc.globalBC(); + + int indexBc = bc.globalIndex(); + + if (bc.selection_bit(kIsBBT0A) || bc.selection_bit(kIsBBT0C)) { + mapGlobalBcWithTOR[globalBC] = indexBc; + } + if (bc.selection_bit(kIsTriggerTVX)) { + mapGlobalBcWithTVX[globalBC] = indexBc; + } + + // fill TVX flags for past-future searches + vIsTVX[indexBc] = bc.selection_bit(kIsTriggerTVX); + vGlobalBCs[indexBc] = globalBC; + + // ### checking nearby activities + int deltaIndex = 0; // backward move counts + int deltaBC = 0; // current difference wrt globalBC + int maxDeltaBC = 30; // maximum difference + + bool nearbyFT0activity = 0; + + // past + bool pastActivityFT0 = 0; + // bool pastActivityFDD = 0; + bool pastActivityFV0 = 0; + while (deltaBC < maxDeltaBC) { + deltaIndex++; + if (bc.globalIndex() - deltaIndex < 0) { + break; + } + const auto& bcPast = bcs.iteratorAt(bc.globalIndex() - deltaIndex); + deltaBC = globalBC - bcPast.globalBC(); + if (deltaBC < maxDeltaBC) { + pastActivityFT0 |= bcPast.has_ft0(); + pastActivityFV0 |= bcPast.has_fv0a(); + // pastActivityFDD |= bcPast.has_fdd(); + } + if (deltaBC < 2) { + if (bcPast.has_ft0()) { + std::bitset<8> triggers = bcPast.ft0().triggerMask(); + nearbyFT0activity |= (triggers[o2::ft0::RecPoints::ETriggerBits::kIsActiveSideA] || triggers[o2::ft0::RecPoints::ETriggerBits::kIsActiveSideC]); + } + } + } + // bool pastActivity = pastActivityFT0 | pastActivityFV0 | pastActivityFDD; + bool pastActivity = pastActivityFT0 | pastActivityFV0; // | pastActivityFDD; + vPastActivity[indexBc] = pastActivity; + + // future + deltaIndex = 0; + deltaBC = 0; + bool futureActivityFT0 = 0; + bool futureActivityFDD = 0; + bool futureActivityFV0 = 0; + while (deltaBC < maxDeltaBC) { + deltaIndex++; + if (bc.globalIndex() + deltaIndex >= bcs.size()) { + break; + } + const auto& bcFuture = bcs.iteratorAt(bc.globalIndex() + deltaIndex); + deltaBC = bcFuture.globalBC() - globalBC; + if (deltaBC < maxDeltaBC) { + futureActivityFT0 |= bcFuture.has_ft0(); + futureActivityFV0 |= bcFuture.has_fv0a(); + futureActivityFDD |= bcFuture.has_fdd(); + } + if (deltaBC < 2) { + if (bcFuture.has_ft0()) { + std::bitset<8> triggers = bcFuture.ft0().triggerMask(); + nearbyFT0activity |= (triggers[o2::ft0::RecPoints::ETriggerBits::kIsActiveSideA] || triggers[o2::ft0::RecPoints::ETriggerBits::kIsActiveSideC]); + } + } + } + bool futureActivity = futureActivityFT0 | futureActivityFV0 | futureActivityFDD; + vFutureActivity[indexBc] = futureActivity; + vNearbyFT0activity[indexBc] = nearbyFT0activity; + + // monitor BCs with nearby activity: + + int localBC = globalBC % nBCsPerOrbit; + if (bc.has_fv0a()) { + histos.fill(HIST("bcQA/hBcFV0"), localBC); + if (pastActivity) + histos.fill(HIST("bcQA/pastActivity/hBcFV0"), localBC); + if (futureActivity) + histos.fill(HIST("bcQA/futureActivity/hBcFV0"), localBC); + if (!pastActivity) + histos.fill(HIST("bcQA/noPastActivity/hBcFV0"), localBC); + if (!futureActivity) + histos.fill(HIST("bcQA/noFutureActivity/hBcFV0"), localBC); + if (!pastActivity && !futureActivity) + histos.fill(HIST("bcQA/noPastFutureActivity/hBcFV0"), localBC); + } + if (bc.has_ft0()) { + histos.fill(HIST("bcQA/hBcFT0"), localBC); + if (pastActivity) + histos.fill(HIST("bcQA/pastActivity/hBcFT0"), localBC); + if (futureActivity) + histos.fill(HIST("bcQA/futureActivity/hBcFT0"), localBC); + if (!pastActivity) + histos.fill(HIST("bcQA/noPastActivity/hBcFT0"), localBC); + if (!futureActivity) + histos.fill(HIST("bcQA/noFutureActivity/hBcFT0"), localBC); + if (!pastActivity && !futureActivity) + histos.fill(HIST("bcQA/noPastFutureActivity/hBcFT0"), localBC); + + // spec bits: + std::bitset<8> triggers = bc.ft0().triggerMask(); + bool isTVX = bc.selection_bit(kIsTriggerTVX); + if (triggers[o2::ft0::RecPoints::ETriggerBits::kIsActiveSideA]) { + histos.fill(HIST("bcQA/specFT0bits/hBc_kIsActiveSideA"), localBC); + if (isTVX) + histos.fill(HIST("bcQA/specFT0bits/hBc_kIsActiveSideA_inTVX"), localBC); + } + if (triggers[o2::ft0::RecPoints::ETriggerBits::kIsActiveSideC]) { + histos.fill(HIST("bcQA/specFT0bits/hBc_kIsActiveSideC"), localBC); + if (isTVX) + histos.fill(HIST("bcQA/specFT0bits/hBc_kIsActiveSideC_inTVX"), localBC); + } + if (triggers[o2::ft0::RecPoints::ETriggerBits::kIsFlangeEvent]) { + histos.fill(HIST("bcQA/specFT0bits/hBc_kIsFlangeEvent"), localBC); + if (isTVX) + histos.fill(HIST("bcQA/specFT0bits/hBc_kIsFlangeEvent_inTVX"), localBC); + } + } + if (bc.has_fdd()) { + histos.fill(HIST("bcQA/hBcFDD"), localBC); + if (pastActivity) + histos.fill(HIST("bcQA/pastActivity/hBcFDD"), localBC); + if (futureActivity) + histos.fill(HIST("bcQA/futureActivity/hBcFDD"), localBC); + } + if (bc.has_zdc()) { + histos.fill(HIST("bcQA/hBcZDC"), localBC); + if (pastActivity) + histos.fill(HIST("bcQA/pastActivity/hBcZDC"), localBC); + if (futureActivity) + histos.fill(HIST("bcQA/futureActivity/hBcZDC"), localBC); + } + + } // end of bc loop + + // ### collision loop + for (const auto& col : cols) { + if (std::abs(col.posZ()) > 10) + continue; + + const auto& foundBC = col.foundBC_as(); + uint64_t globalBC = foundBC.globalBC(); + // uint64_t orbit = globalBC / nBCsPerOrbit; + int localBC = globalBC % nBCsPerOrbit; + + int64_t ts = foundBC.timestamp(); + double secFromSOR = ts / 1000. - minSec; + + // search for nearest ft0a&ft0c entry + uint64_t globalOrigBC = col.bc_as().globalBC(); + int32_t indexClosestTVX = findClosest(globalOrigBC, mapGlobalBcWithTVX); + int bcToClosestTVXdiff = static_cast(globalOrigBC - vGlobalBCs[indexClosestTVX]); + + // selection decisions: + bool noPU = col.selection_bit(kNoSameBunchPileup); + bool pvTOFmatched = col.selection_bit(kIsVertexTOFmatched); + bool pvTRDmatched = col.selection_bit(kIsVertexTRDmatched); + bool narrowTimeVeto = col.selection_bit(kNoCollInTimeRangeNarrow); + bool strictTimeVeto = col.selection_bit(kNoCollInTimeRangeStrict); + bool noCollSameROF = col.selection_bit(kNoCollInRofStrict); + bool bcDiffWrtClosestTVXCut = (bcToClosestTVXdiff == 0); + + auto bcIndex = foundBC.globalIndex(); + // bool noNearbyActivity = (vPastActivity[bcIndex] == 0 && vFutureActivity[bcIndex] == 0); + bool noPastActivity = (vPastActivity[bcIndex] == 0); + + // ### count tracks of different types + int nPVtracks = 0; + int nGlobalTracksPV = 0; + int nGlobalTracksAll = 0; + // int nTOFtracks = 0; + auto tracksGrouped = tracks.sliceBy(perCollision, col.globalIndex()); + for (const auto& track : tracksGrouped) { + if (track.itsNCls() < 5) + continue; + if (track.pt() < 0.2 || track.pt() > 10) + continue; + if (std::abs(track.eta()) > 0.8) + continue; + + if (track.hasITS() && track.hasTPC() && track.tpcNClsFound() > 50 && track.tpcNClsCrossedRows() > 50 && track.tpcChi2NCl() < 4) + nGlobalTracksAll++; + + if (!track.isPVContributor()) { + continue; + } + nPVtracks++; + if (track.hasITS() && track.hasTPC() && track.tpcNClsFound() > 50 && track.tpcNClsCrossedRows() > 50 && track.tpcChi2NCl() < 4) + nGlobalTracksPV++; + } // end of track loop + + if (col.selection_bit(kNoTimeFrameBorder) && col.selection_bit(kNoITSROFrameBorder)) { + histos.fill(HIST("hNcontribColFromData"), nPVtracks); + if (col.selection_bit(kIsTriggerTVX)) + histos.fill(HIST("hNcontribAccFromData"), nPVtracks); + } + + bool hasFT0 = foundBC.has_ft0(); + bool hasFV0A = foundBC.has_fv0a(); + + // bool noFT0activityNearby = false; + bool noFT0activityNearby = (vNearbyFT0activity[bcIndex] == 0); + // check kIsFlangeEvent + if (hasFT0) { + std::bitset<8> triggers = foundBC.ft0().triggerMask(); + if (triggers[o2::ft0::RecPoints::ETriggerBits::kIsFlangeEvent]) + noFT0activityNearby = false; + } + + float vZ = col.posZ(); + float vZft0 = hasFT0 ? foundBC.ft0().posZ() : -1000; + float diffVz = vZft0 - vZ; + + float multV0A = hasFV0A ? col.multFV0A() : 0; + + float multT0A = hasFT0 ? col.multFT0A() : 0; + float multT0C = hasFT0 ? col.multFT0C() : 0; + float multT0M = multT0A + multT0C; + + float timeZNA = foundBC.has_zdc() ? foundBC.zdc().timeZNA() : -999.f; + float timeZNC = foundBC.has_zdc() ? foundBC.zdc().timeZNC() : -999.f; + float znSum = timeZNA + timeZNC; + float znDiff = timeZNA - timeZNC; + // bool goodZNACtime = fabs(znSum) < 2 && fabs(znDiff) < 2; + bool goodZNACtime = (timeZNA > -5 && timeZNA < 2) && (timeZNC > -5 && timeZNC < 2); + + float multZNA = foundBC.has_zdc() ? foundBC.zdc().energyCommonZNA() : -999; + float multZNC = foundBC.has_zdc() ? foundBC.zdc().energyCommonZNC() : -999; + bool cutZNACampl = multZNA < 400 && multZNC < 400; + + // vZ diff (FT0 vs by tracks) + bool badVzDiff = 0; + if (confUseDiffVzCutFromEvSel) + badVzDiff = !col.selection_bit(kIsGoodZvtxFT0vsPV); + else { // tune by hand + float meanDiff = 0.0; // cm + // O-O + if (lastRunNumber == 564356) + meanDiff = -0.01; + if (lastRunNumber == 564359) + meanDiff = -0.17; + if (lastRunNumber == 564373) + meanDiff = 0.99; + if (lastRunNumber == 564374) + meanDiff = 0.57; + // Ne-Ne + if (lastRunNumber == 564468) + meanDiff = -0.51; + if (lastRunNumber == 564468) + meanDiff = -0.60; + + float stdDev = (multT0M > 10) ? 0.144723 + 13.5345 / sqrt(multT0M) : 1.5; // cm + if (multT0M > 5000) + stdDev = stdDev > 0.2 ? stdDev : 0.2; // 0.35; // cm + badVzDiff = diffVz < (meanDiff - stdDev * nSigmaForVzDiff - safetyDiffVzMargin) || diffVz > (meanDiff + stdDev * nSigmaForVzDiff + safetyDiffVzMargin); + } + + bool underLine = false; + if (hasFT0 && nPVtracks < 45. / 40000 * multV0A - 4 && nPVtracks < 20) { + underLine = true; + } + bool grassOnTheRight = false; + if (hasFT0 && nPVtracks < 220. / 40000 * multV0A - 100 && nPVtracks >= 25) { + grassOnTheRight = true; + } + + // study bc diff wrt original bc: + // auto bc = col.bc_as(); + auto bcOriginal = globalOrigBC % 3564; + float bcDiffWrtOriginal = bcOriginal - localBC; + bool bcDiffWrtOriginalBcCut = (bcDiffWrtOriginal == 0); + + // SPEC REMOVAL OF BC RANGES + // if (bcOriginal > 1200 && bcOriginal < 1300) + // continue; + // if (bcOriginal > 1700 && bcOriginal < 1900) + // continue; + + int nContributors = col.numContrib(); + float timeRes = col.collisionTimeRes(); + // int64_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; + // if (col.selection_bit(kIsVertexTOFmatched)) { + // histos.fill(HIST("hColBcDiffVsNcontribWithTOF"), nContributors, bcToClosestTVXdiff); + // histos.fill(HIST("hColTimeResVsNcontribWithTOF"), nContributors, timeRes); + // histos.fill(HIST("hBcColTOF"), localBC); + // } + + float vChi2 = col.chi2(); + float vChi2perContrib = nContributors > 0 ? vChi2 / nContributors : 0; + bool goodVertexChi2 = (vChi2perContrib < 3.5); + + histos.fill(HIST("noSpecSelections/hBcColNoSel8"), localBC); + histos.fill(HIST("noSpecSelections/hBcOrigNoSel8"), bcOriginal); + histos.fill(HIST("noSpecSelections/Vz"), vZ); + histos.fill(HIST("noSpecSelections/hTimeZN_AC_sum_vs_diff"), znDiff, znSum); + histos.fill(HIST("noSpecSelections/hTimeZN_A_vs_C"), timeZNA, timeZNC); + histos.fill(HIST("noSpecSelections/hTimeZNA"), timeZNA); + histos.fill(HIST("noSpecSelections/hTimeZNC"), timeZNC); + + if (noPU) { + histos.fill(HIST("noPU/hBcColNoSel8"), localBC); + histos.fill(HIST("noPU/hBcOrigNoSel8"), bcOriginal); + histos.fill(HIST("noPU/Vz"), vZ); + histos.fill(HIST("noPU/hTimeZN_AC_sum_vs_diff"), znDiff, znSum); + histos.fill(HIST("noPU/hTimeZN_A_vs_C"), timeZNA, timeZNC); + histos.fill(HIST("noPU/hAmplZNAC"), multZNA, multZNC); + histos.fill(HIST("noPU/hTimeZNA"), timeZNA); + histos.fill(HIST("noPU/hTimeZNC"), timeZNC); + } + if (noPU && pvTOFmatched) { + histos.fill(HIST("noPU_pvTOFmatched/hBcColNoSel8"), localBC); + } + if (noPU && pvTRDmatched) { + histos.fill(HIST("noPU_pvTRDmatched/hBcColNoSel8"), localBC); + } + if (noPU && !pvTRDmatched) { + histos.fill(HIST("noPU_notTRDmatched/hBcColNoSel8"), localBC); + } + if (bcDiffWrtClosestTVXCut) { + histos.fill(HIST("bcDiffWrtClosestTVXCut/hBcColNoSel8"), localBC); + } + if (noPU && bcDiffWrtOriginalBcCut) { + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hBcColNoSel8"), localBC); + } + if (noPU && noPastActivity) { + histos.fill(HIST("noPU_noPastActivity/hBcColNoSel8"), localBC); + } + if (noPU && noFT0activityNearby) { + histos.fill(HIST("noPU_noFT0activityNearby/hBcColNoSel8"), localBC); + } + if (noPU && badVzDiff) { + histos.fill(HIST("noPU_badVzDiff/hBcColNoSel8"), localBC); + histos.fill(HIST("noPU_badVzDiff/Vz"), vZ); + } + if (noPU && !badVzDiff) { + histos.fill(HIST("noPU_goodVzDiff/hBcColNoSel8"), localBC); + histos.fill(HIST("noPU_goodVzDiff/Vz"), vZ); + } + if (noPU && !badVzDiff && narrowTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hBcColNoSel8"), localBC); + } + if (noPU && !badVzDiff && strictTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hBcColNoSel8"), localBC); + } + if (noPU && goodVertexChi2) { + histos.fill(HIST("noPU_goodVertexChi2/hBcColNoSel8"), localBC); + } + if (narrowTimeVeto) { + histos.fill(HIST("narrowTimeVeto/hBcColNoSel8"), localBC); + } + if (strictTimeVeto) { + histos.fill(HIST("strictTimeVeto/hBcColNoSel8"), localBC); + } + if (noCollSameROF) { + histos.fill(HIST("noCollSameROF/hBcColNoSel8"), localBC); + } + if (underLine) { + histos.fill(HIST("lowMultCut/hBcColNoSel8"), localBC); + histos.fill(HIST("lowMultCut/hBcOrigNoSel8"), bcOriginal); + } + if (noPU && underLine) { + histos.fill(HIST("noPU_lowMultCut/hBcColNoSel8"), localBC); + histos.fill(HIST("noPU_lowMultCut/hBcOrigNoSel8"), bcOriginal); + histos.fill(HIST("noPU_lowMultCut/hTimeZN_AC_sum_vs_diff"), znDiff, znSum); + histos.fill(HIST("noPU_lowMultCut/hTimeZN_A_vs_C"), timeZNA, timeZNC); + histos.fill(HIST("noPU_lowMultCut/hTimeZNA"), timeZNA); + histos.fill(HIST("noPU_lowMultCut/hTimeZNC"), timeZNC); + } + if (grassOnTheRight) { + histos.fill(HIST("highMultCloudCut/hBcColNoSel8"), localBC); + histos.fill(HIST("highMultCloudCut/hBcOrigNoSel8"), bcOriginal); + } + if (noPU && grassOnTheRight) { + histos.fill(HIST("noPU_highMultCloudCut/hBcColNoSel8"), localBC); + histos.fill(HIST("noPU_highMultCloudCut/hBcOrigNoSel8"), bcOriginal); + histos.fill(HIST("noPU_highMultCloudCut/hTimeZN_AC_sum_vs_diff"), znDiff, znSum); + histos.fill(HIST("noPU_highMultCloudCut/hTimeZN_A_vs_C"), timeZNA, timeZNC); + histos.fill(HIST("noPU_highMultCloudCut/hTimeZNA"), timeZNA); + histos.fill(HIST("noPU_highMultCloudCut/hTimeZNC"), timeZNC); + } + if (noPU && !badVzDiff && pvTOFmatched) { // noPileup_cutByVzDiff_pvTOF_noFT0act + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hBcColNoSel8"), localBC); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hTimeZN_AC_sum_vs_diff"), znDiff, znSum); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hTimeZN_A_vs_C"), timeZNA, timeZNC); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hTimeZNA"), timeZNA); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hTimeZNC"), timeZNC); + } + + // only here cut on sel8: + if (!col.sel8()) + continue; + + // vs time + histos.fill(HIST("hSecondsCollisions/sel8"), secFromSOR); + if (noPU) { + histos.fill(HIST("hSecondsCollisions/noPU"), secFromSOR); + if (underLine) + histos.fill(HIST("hSecondsCollisions/noPU_underLine"), secFromSOR); + if (grassOnTheRight) + histos.fill(HIST("hSecondsCollisions/noPU_grassOnTheRight"), secFromSOR); + if (!underLine && !grassOnTheRight) + histos.fill(HIST("hSecondsCollisions/noPU_good"), secFromSOR); + + histos.fill(HIST("hSecondsCollisions/noPU_Vz"), secFromSOR, vZ); + histos.fill(HIST("hSecondsCollisions/noPU_VzByFT0"), secFromSOR, vZft0); + + if (std::abs(diffVz) < 4) { + histos.fill(HIST("hSecondsCollisions/noPU_meanDiffVz"), secFromSOR, diffVz); + if (multT0M < 1000) + histos.fill(HIST("hSecondsCollisions/noPU_meanDiffVz_lowMult"), secFromSOR, diffVz); + if (multT0M > 10000) + histos.fill(HIST("hSecondsCollisions/noPU_meanDiffVz_highMult"), secFromSOR, diffVz); + } + } + + histos.fill(HIST("noSpecSelections/hBcTVX"), localBC); + histos.fill(HIST("noSpecSelections/hBcOrig"), bcOriginal); + histos.fill(HIST("noSpecSelections/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noSpecSelections/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noSpecSelections/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noSpecSelections/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + + if (noPU) { + histos.fill(HIST("noPU/hBcTVX"), localBC); + histos.fill(HIST("noPU/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && pvTOFmatched) { + histos.fill(HIST("noPU_pvTOFmatched/hBcTVX"), localBC); + histos.fill(HIST("noPU_pvTOFmatched/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_pvTOFmatched/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_pvTOFmatched/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_pvTOFmatched/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU_pvTOFmatched/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && pvTRDmatched) { + histos.fill(HIST("noPU_pvTRDmatched/hBcTVX"), localBC); + histos.fill(HIST("noPU_pvTRDmatched/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_pvTRDmatched/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_pvTRDmatched/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_pvTRDmatched/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU_pvTRDmatched/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && !pvTRDmatched) { + histos.fill(HIST("noPU_notTRDmatched/hBcTVX"), localBC); + histos.fill(HIST("noPU_notTRDmatched/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_notTRDmatched/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_notTRDmatched/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_notTRDmatched/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (bcDiffWrtClosestTVXCut) { + histos.fill(HIST("bcDiffWrtClosestTVXCut/hBcTVX"), localBC); + histos.fill(HIST("bcDiffWrtClosestTVXCut/hBcOrig"), bcOriginal); + histos.fill(HIST("bcDiffWrtClosestTVXCut/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("bcDiffWrtClosestTVXCut/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("bcDiffWrtClosestTVXCut/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && bcDiffWrtOriginalBcCut) { + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hBcTVX"), localBC); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && noPastActivity) { + histos.fill(HIST("noPU_noPastActivity/hBcTVX"), localBC); + histos.fill(HIST("noPU_noPastActivity/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_noPastActivity/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_noPastActivity/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_noPastActivity/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && noFT0activityNearby) { + histos.fill(HIST("noPU_noFT0activityNearby/hBcTVX"), localBC); + histos.fill(HIST("noPU_noFT0activityNearby/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_noFT0activityNearby/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_noFT0activityNearby/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_noFT0activityNearby/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && badVzDiff) { + histos.fill(HIST("noPU_badVzDiff/hBcTVX"), localBC); + histos.fill(HIST("noPU_badVzDiff/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_badVzDiff/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_badVzDiff/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_badVzDiff/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU_badVzDiff/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && !badVzDiff) { + histos.fill(HIST("noPU_goodVzDiff/hBcTVX"), localBC); + histos.fill(HIST("noPU_goodVzDiff/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_goodVzDiff/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_goodVzDiff/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_goodVzDiff/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU_goodVzDiff/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && !badVzDiff && narrowTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hBcTVX"), localBC); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && !badVzDiff && strictTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hBcTVX"), localBC); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && goodVertexChi2) { + histos.fill(HIST("noPU_goodVertexChi2/hBcTVX"), localBC); + histos.fill(HIST("noPU_goodVertexChi2/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_goodVertexChi2/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_goodVertexChi2/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_goodVertexChi2/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (narrowTimeVeto) { + histos.fill(HIST("narrowTimeVeto/hBcTVX"), localBC); + histos.fill(HIST("narrowTimeVeto/hBcOrig"), bcOriginal); + histos.fill(HIST("narrowTimeVeto/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("narrowTimeVeto/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("narrowTimeVeto/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (strictTimeVeto) { + histos.fill(HIST("strictTimeVeto/hBcTVX"), localBC); + histos.fill(HIST("strictTimeVeto/hBcOrig"), bcOriginal); + histos.fill(HIST("strictTimeVeto/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("strictTimeVeto/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("strictTimeVeto/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noCollSameROF) { + histos.fill(HIST("noCollSameROF/hBcTVX"), localBC); + histos.fill(HIST("noCollSameROF/hBcOrig"), bcOriginal); + histos.fill(HIST("noCollSameROF/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noCollSameROF/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noCollSameROF/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && underLine) { + histos.fill(HIST("noPU_lowMultCut/hBcTVX"), localBC); + histos.fill(HIST("noPU_lowMultCut/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_lowMultCut/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_lowMultCut/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_lowMultCut/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU_lowMultCut/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && grassOnTheRight) { + histos.fill(HIST("noPU_highMultCloudCut/hBcTVX"), localBC); + histos.fill(HIST("noPU_highMultCloudCut/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_highMultCloudCut/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_highMultCloudCut/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_highMultCloudCut/hVertexChi2VsNcontrib"), nContributors, vChi2perContrib); + histos.fill(HIST("noPU_highMultCloudCut/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && !badVzDiff && pvTOFmatched) { // noPileup_cutByVzDiff_pvTOF_noFT0act + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hBcTVX"), localBC); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && !badVzDiff && noFT0activityNearby) { + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hBcTVX"), localBC); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + } + if (noPU && goodZNACtime) { + histos.fill(HIST("noPU_CutOnZNACtime/hBcTVX"), localBC); + histos.fill(HIST("noPU_CutOnZNACtime/hBcOrig"), bcOriginal); + histos.fill(HIST("noPU_CutOnZNACtime/hColBcDiffVsNcontrib"), nContributors, bcToClosestTVXdiff); + histos.fill(HIST("noPU_CutOnZNACtime/hColTimeResVsNcontrib"), nContributors, timeRes); + histos.fill(HIST("noPU_CutOnZNACtime/hNPVvsNch"), nPVtracks, nGlobalTracksAll); + histos.fill(HIST("noPU_CutOnZNACtime/hTimeZN_AC_sum_vs_diff"), znDiff, znSum); + histos.fill(HIST("noPU_CutOnZNACtime/hTimeZN_A_vs_C"), timeZNA, timeZNC); + histos.fill(HIST("noPU_CutOnZNACtime/hTimeZNA"), timeZNA); + histos.fill(HIST("noPU_CutOnZNACtime/hTimeZNC"), timeZNC); + } + + if (foundBC.has_ft0()) { + // float multT0A = foundBC.has_ft0() ? foundBC.ft0().sumAmpA() : -999.f; + // float multT0C = foundBC.has_ft0() ? foundBC.ft0().sumAmpC() : -999.f; + + histos.fill(HIST("noSpecSelections/hBcFT0"), localBC); + histos.fill(HIST("noSpecSelections/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noSpecSelections/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noSpecSelections/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noSpecSelections/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noSpecSelections/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noSpecSelections/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + + if (noPU) { + histos.fill(HIST("noPU/hBcFT0"), localBC); + histos.fill(HIST("noPU/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && pvTOFmatched) { + histos.fill(HIST("noPU_pvTOFmatched/hBcFT0"), localBC); + histos.fill(HIST("noPU_pvTOFmatched/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_pvTOFmatched/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_pvTOFmatched/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_pvTOFmatched/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_pvTOFmatched/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_pvTOFmatched/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && pvTRDmatched) { + histos.fill(HIST("noPU_pvTRDmatched/hBcFT0"), localBC); + histos.fill(HIST("noPU_pvTRDmatched/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_pvTRDmatched/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_pvTRDmatched/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_pvTRDmatched/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_pvTRDmatched/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_pvTRDmatched/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && !pvTRDmatched) { + histos.fill(HIST("noPU_notTRDmatched/hBcFT0"), localBC); + histos.fill(HIST("noPU_notTRDmatched/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_notTRDmatched/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_notTRDmatched/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_notTRDmatched/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_notTRDmatched/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_notTRDmatched/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (bcDiffWrtClosestTVXCut) { + histos.fill(HIST("bcDiffWrtClosestTVXCut/hBcFT0"), localBC); + histos.fill(HIST("bcDiffWrtClosestTVXCut/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("bcDiffWrtClosestTVXCut/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("bcDiffWrtClosestTVXCut/nTracksPV_vs_T0A"), multT0A, nPVtracks); + // histos.fill(HIST("bcDiffWrtClosestTVXCut/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("bcDiffWrtClosestTVXCut/nTracksPV_vs_T0C"), multT0C, nPVtracks); + // histos.fill(HIST("bcDiffWrtClosestTVXCut/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && bcDiffWrtOriginalBcCut) { + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hBcFT0"), localBC); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/nTracksPV_vs_T0A"), multT0A, nPVtracks); + // histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/nTracksPV_vs_T0C"), multT0C, nPVtracks); + // histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && badVzDiff) { + histos.fill(HIST("noPU_badVzDiff/hBcFT0"), localBC); + histos.fill(HIST("noPU_badVzDiff/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_badVzDiff/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_badVzDiff/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_badVzDiff/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_badVzDiff/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_badVzDiff/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && !badVzDiff) { + histos.fill(HIST("noPU_goodVzDiff/hBcFT0"), localBC); + histos.fill(HIST("noPU_goodVzDiff/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_goodVzDiff/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_goodVzDiff/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_goodVzDiff/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && !badVzDiff && narrowTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hBcFT0"), localBC); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && !badVzDiff && strictTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hBcFT0"), localBC); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && noPastActivity) { + histos.fill(HIST("noPU_noPastActivity/hBcFT0"), localBC); + histos.fill(HIST("noPU_noPastActivity/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_noPastActivity/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_noPastActivity/nTracksPV_vs_T0A"), multT0A, nPVtracks); + // histos.fill(HIST("noPU_noPastActivity/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_noPastActivity/nTracksPV_vs_T0C"), multT0C, nPVtracks); + // histos.fill(HIST("noPU_noPastActivity/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && noFT0activityNearby) { + histos.fill(HIST("noPU_noFT0activityNearby/hBcFT0"), localBC); + histos.fill(HIST("noPU_noFT0activityNearby/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_noFT0activityNearby/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_noFT0activityNearby/nTracksPV_vs_T0A"), multT0A, nPVtracks); + // histos.fill(HIST("noPU_noFT0activityNearby/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_noFT0activityNearby/nTracksPV_vs_T0C"), multT0C, nPVtracks); + // histos.fill(HIST("noPU_noFT0activityNearby/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && goodVertexChi2) { + histos.fill(HIST("noPU_goodVertexChi2/hBcFT0"), localBC); + histos.fill(HIST("noPU_goodVertexChi2/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_goodVertexChi2/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_goodVertexChi2/nTracksPV_vs_T0A"), multT0A, nPVtracks); + // histos.fill(HIST("noPU_goodVertexChi2/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_goodVertexChi2/nTracksPV_vs_T0C"), multT0C, nPVtracks); + // histos.fill(HIST("noPU_goodVertexChi2/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (narrowTimeVeto) { + histos.fill(HIST("narrowTimeVeto/hBcFT0"), localBC); + histos.fill(HIST("narrowTimeVeto/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("narrowTimeVeto/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("narrowTimeVeto/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("narrowTimeVeto/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("narrowTimeVeto/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("narrowTimeVeto/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (strictTimeVeto) { + histos.fill(HIST("strictTimeVeto/hBcFT0"), localBC); + histos.fill(HIST("strictTimeVeto/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("strictTimeVeto/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("strictTimeVeto/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("strictTimeVeto/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("strictTimeVeto/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("strictTimeVeto/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noCollSameROF) { + histos.fill(HIST("noCollSameROF/hBcFT0"), localBC); + histos.fill(HIST("noCollSameROF/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noCollSameROF/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noCollSameROF/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noCollSameROF/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noCollSameROF/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noCollSameROF/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && underLine) { + histos.fill(HIST("noPU_lowMultCut/hBcFT0"), localBC); + histos.fill(HIST("noPU_lowMultCut/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_lowMultCut/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_lowMultCut/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_lowMultCut/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_lowMultCut/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_lowMultCut/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && grassOnTheRight) { + histos.fill(HIST("noPU_highMultCloudCut/hBcFT0"), localBC); + histos.fill(HIST("noPU_highMultCloudCut/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_highMultCloudCut/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_highMultCloudCut/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_highMultCloudCut/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_highMultCloudCut/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_highMultCloudCut/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && !badVzDiff && pvTOFmatched) { // noPileup_cutByVzDiff_pvTOF_noFT0act + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hBcFT0"), localBC); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && !badVzDiff && noFT0activityNearby) { + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hBcFT0"), localBC); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/nTracksPV_vs_T0A"), multT0A, nPVtracks); + // histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/nTracksGlobal_vs_T0A"), multT0A, nGlobalTracksPV); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/nTracksPV_vs_T0C"), multT0C, nPVtracks); + // histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/nTracksGlobal_vs_T0C"), multT0C, nGlobalTracksPV); + } + if (noPU && goodZNACtime) { + histos.fill(HIST("noPU_CutOnZNACtime/hBcFT0"), localBC); + histos.fill(HIST("noPU_CutOnZNACtime/hVtxFT0VsVtxCol"), vZft0, vZ); + histos.fill(HIST("noPU_CutOnZNACtime/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_CutOnZNACtime/nTracksPV_vs_T0A"), multT0A, nPVtracks); + histos.fill(HIST("noPU_CutOnZNACtime/nTracksPV_vs_T0C"), multT0C, nPVtracks); + histos.fill(HIST("noPU_CutOnZNACtime/hAmplZNAC"), multZNA, multZNC); + } + } + + if (foundBC.has_fv0a()) { + histos.fill(HIST("noSpecSelections/hBcFV0"), localBC); + histos.fill(HIST("noSpecSelections/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noSpecSelections/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + if (noPU) { + histos.fill(HIST("noPU/hBcFV0"), localBC); + histos.fill(HIST("noPU/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && pvTOFmatched) { + histos.fill(HIST("noPU_pvTOFmatched/hBcFV0"), localBC); + histos.fill(HIST("noPU_pvTOFmatched/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_pvTOFmatched/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && pvTRDmatched) { + histos.fill(HIST("noPU_pvTRDmatched/hBcFV0"), localBC); + histos.fill(HIST("noPU_pvTRDmatched/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_pvTRDmatched/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && !pvTRDmatched) { + histos.fill(HIST("noPU_notTRDmatched/hBcFV0"), localBC); + histos.fill(HIST("noPU_notTRDmatched/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_notTRDmatched/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && pvTOFmatched && !pvTRDmatched) { // SPEC CHECK! + histos.fill(HIST("noPU_pvTOFmatched_notTRDmatched/hBcFV0"), localBC); + histos.fill(HIST("noPU_pvTOFmatched_notTRDmatched/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_pvTOFmatched_notTRDmatched/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (bcDiffWrtClosestTVXCut) { + histos.fill(HIST("bcDiffWrtClosestTVXCut/hBcFV0"), localBC); + histos.fill(HIST("bcDiffWrtClosestTVXCut/nTracksPV_vs_V0A"), multV0A, nPVtracks); + // histos.fill(HIST("bcDiffWrtClosestTVXCut/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && bcDiffWrtOriginalBcCut) { + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hBcFV0"), localBC); + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/nTracksPV_vs_V0A"), multV0A, nPVtracks); + // histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && badVzDiff) { + histos.fill(HIST("noPU_badVzDiff/hBcFV0"), localBC); + histos.fill(HIST("noPU_badVzDiff/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_badVzDiff/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && !badVzDiff) { + histos.fill(HIST("noPU_goodVzDiff/hBcFV0"), localBC); + histos.fill(HIST("noPU_goodVzDiff/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && !badVzDiff && narrowTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hBcFV0"), localBC); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && !badVzDiff && strictTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hBcFV0"), localBC); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && noPastActivity) { + histos.fill(HIST("noPU_noPastActivity/hBcFV0"), localBC); + histos.fill(HIST("noPU_noPastActivity/nTracksPV_vs_V0A"), multV0A, nPVtracks); + // histos.fill(HIST("noPU_noPastActivity/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && noFT0activityNearby) { + histos.fill(HIST("noPU_noFT0activityNearby/hBcFV0"), localBC); + histos.fill(HIST("noPU_noFT0activityNearby/nTracksPV_vs_V0A"), multV0A, nPVtracks); + // histos.fill(HIST("noPU_noFT0activityNearby/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && goodVertexChi2) { + histos.fill(HIST("noPU_goodVertexChi2/hBcFV0"), localBC); + histos.fill(HIST("noPU_goodVertexChi2/nTracksPV_vs_V0A"), multV0A, nPVtracks); + // histos.fill(HIST("noPU_goodVertexChi2/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (narrowTimeVeto) { + histos.fill(HIST("narrowTimeVeto/hBcFV0"), localBC); + histos.fill(HIST("narrowTimeVeto/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("narrowTimeVeto/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (strictTimeVeto) { + histos.fill(HIST("strictTimeVeto/hBcFV0"), localBC); + histos.fill(HIST("strictTimeVeto/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("strictTimeVeto/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noCollSameROF) { + histos.fill(HIST("noCollSameROF/hBcFV0"), localBC); + histos.fill(HIST("noCollSameROF/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noCollSameROF/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (underLine) { + histos.fill(HIST("lowMultCut/nTracksPV_vs_V0A"), multV0A, nPVtracks); + } + if (noPU && underLine) { + histos.fill(HIST("noPU_lowMultCut/hBcFV0"), localBC); + histos.fill(HIST("noPU_lowMultCut/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_lowMultCut/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (grassOnTheRight) { + histos.fill(HIST("highMultCloudCut/nTracksPV_vs_V0A"), multV0A, nPVtracks); + } + if (noPU && grassOnTheRight) { + histos.fill(HIST("noPU_highMultCloudCut/hBcFV0"), localBC); + histos.fill(HIST("noPU_highMultCloudCut/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_highMultCloudCut/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && !badVzDiff && pvTOFmatched) { // noPileup_cutByVzDiff_pvTOF_noFT0act + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hBcFV0"), localBC); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + if (noPU && !badVzDiff && noFT0activityNearby) { + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hBcFV0"), localBC); + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/nTracksPV_vs_V0A"), multV0A, nPVtracks); + // histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/nTracksGlobal_vs_V0A"), multV0A, nGlobalTracksPV); + } + + if (noPU && goodZNACtime) { + histos.fill(HIST("noPU_CutOnZNACtime/hBcFV0"), localBC); + histos.fill(HIST("noPU_CutOnZNACtime/nTracksPV_vs_V0A"), multV0A, nPVtracks); + } + if (noPU && !goodZNACtime) { + histos.fill(HIST("noPU_AntiCutOnZNACtime/hBcFV0"), localBC); + histos.fill(HIST("noPU_AntiCutOnZNACtime/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_AntiCutOnZNACtime/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_AntiCutOnZNACtime/hAmplZNAC"), multZNA, multZNC); + } + if (noPU && !cutZNACampl) { + histos.fill(HIST("noPU_AntiCutOnZNAampl/hBcFV0"), localBC); + histos.fill(HIST("noPU_AntiCutOnZNAampl/nTracksPV_vs_V0A"), multV0A, nPVtracks); + histos.fill(HIST("noPU_AntiCutOnZNAampl/hVtxFT0MinusVtxColVsMultT0M"), diffVz, multT0A + multT0C); + histos.fill(HIST("noPU_AntiCutOnZNAampl/hAmplZNAC"), multZNA, multZNC); + } + } + if (foundBC.has_zdc()) { + histos.fill(HIST("noSpecSelections/hBcZDC"), localBC); + if (noPU) { + histos.fill(HIST("noPU/hBcZDC"), localBC); + } + if (noPU && pvTOFmatched) { + histos.fill(HIST("noPU_pvTOFmatched/hBcZDC"), localBC); + } + if (noPU && pvTRDmatched) { + histos.fill(HIST("noPU_pvTRDmatched/hBcZDC"), localBC); + } + if (noPU && !pvTRDmatched) { + histos.fill(HIST("noPU_notTRDmatched/hBcZDC"), localBC); + } + if (bcDiffWrtClosestTVXCut) { + histos.fill(HIST("bcDiffWrtClosestTVXCut/hBcZDC"), localBC); + } + if (noPU && bcDiffWrtOriginalBcCut) { + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hBcZDC"), localBC); + } + if (noPU && badVzDiff) { + histos.fill(HIST("noPU_badVzDiff/hBcZDC"), localBC); + } + if (noPU && !badVzDiff) { + histos.fill(HIST("noPU_goodVzDiff/hBcZDC"), localBC); + } + if (noPU && !badVzDiff && narrowTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hBcZDC"), localBC); + } + if (noPU && !badVzDiff && strictTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hBcZDC"), localBC); + } + if (noPU && noPastActivity) { + histos.fill(HIST("noPU_noPastActivity/hBcZDC"), localBC); + } + if (noPU && noFT0activityNearby) { + histos.fill(HIST("noPU_noFT0activityNearby/hBcZDC"), localBC); + } + if (noPU && goodVertexChi2) { + histos.fill(HIST("noPU_goodVertexChi2/hBcZDC"), localBC); + } + if (narrowTimeVeto) { + histos.fill(HIST("narrowTimeVeto/hBcZDC"), localBC); + } + if (strictTimeVeto) { + histos.fill(HIST("strictTimeVeto/hBcZDC"), localBC); + } + if (noCollSameROF) { + histos.fill(HIST("noCollSameROF/hBcZDC"), localBC); + } + if (noPU && underLine) { + histos.fill(HIST("noPU_lowMultCut/hBcZDC"), localBC); + } + if (noPU && grassOnTheRight) { + histos.fill(HIST("noPU_highMultCloudCut/hBcZDC"), localBC); + } + if (noPU && !badVzDiff && pvTOFmatched) { // noPileup_cutByVzDiff_pvTOF_noFT0act + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hBcZDC"), localBC); + } + if (noPU && !badVzDiff && noFT0activityNearby) { + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hBcZDC"), localBC); + } + } + + // bc diff wrt original bc + histos.fill(HIST("noSpecSelections/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + if (noPU) { + histos.fill(HIST("noPU/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && pvTOFmatched) { + histos.fill(HIST("noPU_pvTOFmatched/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && pvTRDmatched) { + histos.fill(HIST("noPU_pvTRDmatched/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && !pvTRDmatched) { + histos.fill(HIST("noPU_notTRDmatched/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (bcDiffWrtClosestTVXCut) { + histos.fill(HIST("bcDiffWrtClosestTVXCut/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && bcDiffWrtOriginalBcCut) { + histos.fill(HIST("noPU_bcDiffWrtOriginalBcCut/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && badVzDiff) { + histos.fill(HIST("noPU_badVzDiff/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && !badVzDiff) { + histos.fill(HIST("noPU_goodVzDiff/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && !badVzDiff && narrowTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_narrowTimeVeto/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && !badVzDiff && strictTimeVeto) { + histos.fill(HIST("noPU_goodVzDiff_strictTimeVeto/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && noPastActivity) { + histos.fill(HIST("noPU_noPastActivity/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && noFT0activityNearby) { + histos.fill(HIST("noPU_noFT0activityNearby/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && goodVertexChi2) { + histos.fill(HIST("noPU_goodVertexChi2/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (narrowTimeVeto) { + histos.fill(HIST("narrowTimeVeto/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (strictTimeVeto) { + histos.fill(HIST("strictTimeVeto/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noCollSameROF) { + histos.fill(HIST("noCollSameROF/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && underLine) { + histos.fill(HIST("noPU_lowMultCut/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && grassOnTheRight) { + histos.fill(HIST("noPU_highMultCloudCut/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && !badVzDiff && pvTOFmatched) { // noPileup_cutByVzDiff_pvTOF_noFT0act + histos.fill(HIST("noPU_cutByVzDiff_pvTOF/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && !badVzDiff && noFT0activityNearby) { + histos.fill(HIST("noPU_cutByVzDiff_noFT0activityNearby/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + if (noPU && goodZNACtime) { + histos.fill(HIST("noPU_CutOnZNACtime/hTVXvsBcDiffwrtOrigBc"), bcDiffWrtOriginal); + } + } // end of collisions loop + } + PROCESS_SWITCH(LightIonsEvSelQa, processRun3, "Process Run3 tracking vs detector occupancy QA", true); + + // ### MC QA + using ColEvSelsWithMCLabels = soa::Join; //, aod::CentFT0Cs>; + using BCsInfo = soa::Join; + + void processMC(ColEvSelsWithMCLabels const& collisions, + BCsInfo const&, + aod::McCollisions const&) + { + for (const auto& col : collisions) { + if (fabs(col.posZ()) > 10) + continue; + bool isSel8 = col.sel8(); + if (col.has_mcCollision()) { + const auto mcCollision = col.mcCollision(); + LOGP(debug, "col.posZ() = {}, mcCollision.posZ() = {}", col.posZ(), mcCollision.posZ()); + + float diffVz = col.posZ() - mcCollision.posZ(); + histos.fill(HIST("MC/hMCdataVzDiff"), col.numContrib(), diffVz); + + auto bc = col.bc_as(); + auto mcBc = mcCollision.bc_as(); + auto foundBC = col.foundBC_as(); + + uint64_t globalBC = bc.globalBC(); + uint64_t foundGlobalBC = foundBC.globalBC(); + uint64_t mcGlobalBC = mcBc.globalBC(); + + int bcDiff = static_cast(globalBC - mcGlobalBC); + int foundBcDiff = static_cast(foundGlobalBC - mcGlobalBC); + + // restrict bc diff range - to see values in the diff histograms + if (bcDiff > 300) + bcDiff = 300; + if (bcDiff < -300) + bcDiff = -300; + if (foundBcDiff > 300) + foundBcDiff = 300; + if (foundBcDiff < -300) + foundBcDiff = -300; + + LOGP(debug, "globalBC = {}, mcGlobalBC = {}", globalBC, mcGlobalBC); + histos.fill(HIST("MC/hMCdataBcDiffVsMult"), col.numContrib(), bcDiff); + histos.fill(HIST("MC/hMCdataFoundBcDiffVsMult"), col.numContrib(), foundBcDiff); + + if (isSel8) { + histos.fill(HIST("MCsel8/hMCdataVzDiff"), col.numContrib(), diffVz); + histos.fill(HIST("MCsel8/hMCdataBcDiffVsMult"), col.numContrib(), bcDiff); + histos.fill(HIST("MCsel8/hMCdataFoundBcDiffVsMult"), col.numContrib(), foundBcDiff); + + if (col.selection_bit(kIsVertexTRDmatched)) { + histos.fill(HIST("MCsel8/hMCdataVzDiff_vertTRDmatched"), col.numContrib(), diffVz); + histos.fill(HIST("MCsel8/hMCdataFoundBcDiffVsMult_vertTRDmatched"), col.numContrib(), foundBcDiff); + } + if (col.selection_bit(kIsVertexTOFmatched)) { + histos.fill(HIST("MCsel8/hMCdataVzDiff_vertTOFmatched"), col.numContrib(), diffVz); + histos.fill(HIST("MCsel8/hMCdataFoundBcDiffVsMult_vertTOFmatched"), col.numContrib(), foundBcDiff); + } + } + if (col.selection_bit(kNoTimeFrameBorder) && col.selection_bit(kNoITSROFrameBorder) && !col.selection_bit(kIsTriggerTVX)) { + histos.fill(HIST("MCnonTVX/hMCdataVzDiff"), col.numContrib(), diffVz); + histos.fill(HIST("MCnonTVX/hMCdataBcDiffVsMult"), col.numContrib(), bcDiff); + histos.fill(HIST("MCnonTVX/hMCdataFoundBcDiffVsMult"), col.numContrib(), foundBcDiff); + } + + if (col.selection_bit(kNoTimeFrameBorder) && col.selection_bit(kNoITSROFrameBorder)) { + histos.fill(HIST("MC_not_TF_ROF_borders/hNcontribColFromData"), col.numContrib()); + if (col.selection_bit(kIsTriggerTVX)) + histos.fill(HIST("MC_not_TF_ROF_borders/hNcontribAccFromData"), col.numContrib()); + + if (foundBcDiff == 0) { + histos.fill(HIST("MC_not_TF_ROF_borders/hNcontribColFromData_foundBcDiff0"), col.numContrib()); + if (col.selection_bit(kIsTriggerTVX)) + histos.fill(HIST("MC_not_TF_ROF_borders/hNcontribAccFromData_foundBcDiff0"), col.numContrib()); + } + } + } + } + } + + PROCESS_SWITCH(LightIonsEvSelQa, processMC, "Process MC", false); +}; + +WorkflowSpec + defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTEvent/matchingQa.cxx b/DPG/Tasks/AOTEvent/matchingQa.cxx new file mode 100644 index 00000000000..3b266f047e9 --- /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; + +o2::common::core::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 index 83f704960b6..52b4a8228f0 100644 --- a/DPG/Tasks/AOTEvent/rofBorderQa.cxx +++ b/DPG/Tasks/AOTEvent/rofBorderQa.cxx @@ -12,29 +12,40 @@ /// \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/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include -using namespace std; using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; 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..6586d08f5ee --- /dev/null +++ b/DPG/Tasks/AOTEvent/timeDependentQa.cxx @@ -0,0 +1,877 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#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::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 confTimeMuchWiderBinFactor{"TimeMuchWiderBinFactor", 20, "Factor for even wider time bins for some 2D histograms"}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confTimeMuchMuchWiderBinFactor{"TimeMuchMuchWiderBinFactor", 120, "Factor for super wide 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) + + // for O-O and Ne-Ne run + Configurable confIncludeMultDistrVsTimeHistos{"IncludeMultDistrVsTimeHistos", 0, ""}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confMaxNtracksForTimeDepDistributions{"MaxNtracksForTimeDepDistributions", 800, ""}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confMaxZNACenergyForTimeDepDistributions{"MaxZNACenergyForTimeDepDistributions", 4000, ""}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confMaxT0ACamplForTimeDepDistributions{"MaxT0ACamplForTimeDepDistributions", 25000, ""}; // o2-linter: disable=name/configurable (temporary fix) + Configurable confMaxV0AamplForTimeDepDistributions{"MaxV0AamplForTimeDepDistributions", 40000, ""}; // 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::Zdcs const&, + 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); + int nTimeVeryWideBins = static_cast((maxSec - minSec) / confTimeBinWidthInSec / confTimeMuchWiderBinFactor); + int nTimeSuperWideBins = static_cast((maxSec - minSec) / confTimeBinWidthInSec / confTimeMuchMuchWiderBinFactor); + double timeInterval = nTimeBins * confTimeBinWidthInSec; + + const AxisSpec axisSeconds{nTimeBins, 0, timeInterval, "seconds"}; + const AxisSpec axisSecondsWideBins{nTimeWideBins, 0, timeInterval, "seconds"}; + const AxisSpec axisSecondsVeryWideBins{nTimeVeryWideBins, 0, timeInterval, "seconds"}; + const AxisSpec axisSecondsSuperWideBins{nTimeSuperWideBins, 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("hSecondsCollisionsNoPileup", "", 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"}}); + + const int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; + const AxisSpec axisBCs{nBCsPerOrbit, 0., static_cast(nBCsPerOrbit), ""}; + histos.add("hSecondsBCsMap", "", kTH2F, {axisSecondsSuperWideBins, axisBCs}); + + // shapes of distributions (added for the O-O run monitoring) + if (confIncludeMultDistrVsTimeHistos) { + int maxNtracks = confMaxNtracksForTimeDepDistributions; + float maxZNACenergyForTimeDepDistributions = confMaxZNACenergyForTimeDepDistributions; + float maxT0ACamplForTimeDepDistributions = confMaxT0ACamplForTimeDepDistributions; + float maxV0AamplForTimeDepDistributions = confMaxV0AamplForTimeDepDistributions; + histos.add("multDistributions/hSecondsDistrPVtracks", "", kTH2D, {axisSecondsVeryWideBins, {maxNtracks, -0.5, maxNtracks - 0.5, "n PV tracks"}}); + histos.add("multDistributions/hSecondsDistrT0A", "", kTH2D, {axisSecondsVeryWideBins, {250, 0, maxT0ACamplForTimeDepDistributions, "T0A ampl"}}); + histos.add("multDistributions/hSecondsDistrT0C", "", kTH2D, {axisSecondsVeryWideBins, {250, 0, maxT0ACamplForTimeDepDistributions, "T0C ampl"}}); + histos.add("multDistributions/hSecondsDistrV0A", "", kTH2D, {axisSecondsVeryWideBins, {400, 0, maxV0AamplForTimeDepDistributions, "V0A ampl"}}); + histos.add("multDistributions/hSecondsDistrZNA", "", kTH2D, {axisSecondsVeryWideBins, {320, 0, maxZNACenergyForTimeDepDistributions, "ZNA ampl"}}); + histos.add("multDistributions/hSecondsDistrZNC", "", kTH2D, {axisSecondsVeryWideBins, {320, 0, maxZNACenergyForTimeDepDistributions, "ZNC ampl"}}); + histos.add("multDistributions/hSecondsDistrZNACdiff", "", kTH2D, {axisSecondsVeryWideBins, {600, -maxZNACenergyForTimeDepDistributions, maxZNACenergyForTimeDepDistributions, "ZN A-C diff"}}); + histos.add("multDistributions/hSecondsDistrZNACdiffNorm", "", kTH2D, {axisSecondsVeryWideBins, {200, -1., 1., "ZN A-C diff"}}); + histos.add("multDistributions/hSecondsDistrZNAampl", "", kTH2D, {axisSecondsVeryWideBins, {320, 0, maxZNACenergyForTimeDepDistributions, "ZNA ampl"}}); + histos.add("multDistributions/hSecondsDistrZNCampl", "", kTH2D, {axisSecondsVeryWideBins, {320, 0, maxZNACenergyForTimeDepDistributions, "ZNC ampl"}}); + histos.add("multDistributions/hSecondsDistrZNACdiffAmpl", "", kTH2D, {axisSecondsVeryWideBins, {200, -1., 1., "ZN A-C diff"}}); + histos.add("multDistributions/hSecondsDistrZNACdiffNormAmpl", "", kTH2D, {axisSecondsVeryWideBins, {200, -1., 1., "ZN A-C diff"}}); + + histos.add("multDistributionsNoPileup/hSecondsDistrPVtracks", "", kTH2D, {axisSecondsVeryWideBins, {maxNtracks, -0.5, maxNtracks - 0.5, "n PV tracks"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrT0A", "", kTH2D, {axisSecondsVeryWideBins, {250, 0, maxT0ACamplForTimeDepDistributions, "T0A ampl"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrT0C", "", kTH2D, {axisSecondsVeryWideBins, {250, 0, maxT0ACamplForTimeDepDistributions, "T0C ampl"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrV0A", "", kTH2D, {axisSecondsVeryWideBins, {400, 0, maxV0AamplForTimeDepDistributions, "V0A ampl"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrZNA", "", kTH2D, {axisSecondsVeryWideBins, {320, 0, maxZNACenergyForTimeDepDistributions, "ZNA ampl"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrZNC", "", kTH2D, {axisSecondsVeryWideBins, {320, 0, maxZNACenergyForTimeDepDistributions, "ZNC ampl"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrZNACdiff", "", kTH2D, {axisSecondsVeryWideBins, {600, -maxZNACenergyForTimeDepDistributions, maxZNACenergyForTimeDepDistributions, "ZN A-C diff"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrZNACdiffNorm", "", kTH2D, {axisSecondsVeryWideBins, {200, -1., 1., "ZN A-C diff"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrZNAampl", "", kTH2D, {axisSecondsVeryWideBins, {320, 0, maxZNACenergyForTimeDepDistributions, "ZNA ampl"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrZNCampl", "", kTH2D, {axisSecondsVeryWideBins, {320, 0, maxZNACenergyForTimeDepDistributions, "ZNC ampl"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrZNACdiffAmpl", "", kTH2D, {axisSecondsVeryWideBins, {200, -1., 1., "ZN A-C diff"}}); + histos.add("multDistributionsNoPileup/hSecondsDistrZNACdiffNormAmpl", "", kTH2D, {axisSecondsVeryWideBins, {200, -1., 1., "ZN A-C diff"}}); + } + + // ### 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 + 2, -0.5, nRctFlagsTotal + 2 - 0.5, "Monitoring of RCT flags"}}); + axRctFlags = reinterpret_cast(histos.get(HIST("hSecondsRCTflags"))->GetYaxis()); + axRctFlags->SetBinLabel(1, "NcollisionsSel8"); + axRctFlags->SetBinLabel(2, "CcdbNotFound"); + axRctFlags->SetBinLabel(3 + kCPVBad, "CPVBad"); + axRctFlags->SetBinLabel(3 + kEMCBad, "EMCBad"); + axRctFlags->SetBinLabel(3 + kEMCLimAccMCRepr, "EMCLimAccMCRepr"); + axRctFlags->SetBinLabel(3 + kFDDBad, "FDDBad"); + axRctFlags->SetBinLabel(3 + kFT0Bad, "FT0Bad"); + axRctFlags->SetBinLabel(3 + kFV0Bad, "FV0Bad"); + axRctFlags->SetBinLabel(3 + kHMPBad, "HMPBad"); + axRctFlags->SetBinLabel(3 + kITSBad, "ITSBad"); + axRctFlags->SetBinLabel(3 + kITSLimAccMCRepr, "ITSLimAccMCRepr"); + axRctFlags->SetBinLabel(3 + kMCHBad, "MCHBad"); + axRctFlags->SetBinLabel(3 + kMCHLimAccMCRepr, "MCHLimAccMCRepr"); + axRctFlags->SetBinLabel(3 + kMFTBad, "MFTBad"); + axRctFlags->SetBinLabel(3 + kMFTLimAccMCRepr, "MFTLimAccMCRepr"); + axRctFlags->SetBinLabel(3 + kMIDBad, "MIDBad"); + axRctFlags->SetBinLabel(3 + kMIDLimAccMCRepr, "MIDLimAccMCRepr"); + axRctFlags->SetBinLabel(3 + kPHSBad, "PHSBad"); + axRctFlags->SetBinLabel(3 + kTOFBad, "TOFBad"); + axRctFlags->SetBinLabel(3 + kTOFLimAccMCRepr, "TOFLimAccMCRepr"); + axRctFlags->SetBinLabel(3 + kTPCBadTracking, "TPCBadTracking"); + axRctFlags->SetBinLabel(3 + kTPCBadPID, "TPCBadPID"); + axRctFlags->SetBinLabel(3 + kTPCLimAccMCRepr, "TPCLimAccMCRepr"); + axRctFlags->SetBinLabel(3 + kTRDBad, "TRDBad"); + axRctFlags->SetBinLabel(3 + kZDCBad, "ZDCBad"); + // combined flags + axRctFlags->SetBinLabel(3 + enCBT, "CBT"); + axRctFlags->SetBinLabel(3 + enCBT_hadronPID, "CBT_hadronPID"); + axRctFlags->SetBinLabel(3 + enCBT_electronPID, "CBT_electronPID"); + axRctFlags->SetBinLabel(3 + enCBT_calo, "CBT_calo"); + axRctFlags->SetBinLabel(3 + enCBT_muon, "CBT_muon"); + axRctFlags->SetBinLabel(3 + 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); + + uint64_t globalBC = bc.globalBC(); + int localBC = globalBC % nBCsPerOrbit; + histos.fill(HIST("hSecondsBCsMap"), secFromSOR, localBC); + + 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); + if (col.selection_bit(kNoSameBunchPileup)) + histos.fill(HIST("hSecondsCollisionsNoPileup"), 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 + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 1, col.rct_bit(kCcdbObjectLoaded)); // CCDB object not loaded + LOGP(debug, "i = 1, bitValue = {}, binLabel={}, binCenter={}", col.rct_bit(kCcdbObjectLoaded), axRctFlags->GetBinLabel(2), axRctFlags->GetBinCenter(2)); + for (int iFlag = 0; iFlag < kNRCTSelectionFlags; iFlag++) { + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 2 + iFlag, col.rct_bit(iFlag)); + LOGP(debug, "i = {}, bitValue = {}, binLabel={}, binCenter={}", iFlag, col.rct_bit(iFlag), axRctFlags->GetBinLabel(3 + iFlag), axRctFlags->GetBinCenter(3 + 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), 2 + enCBT_hadronPID, axRctFlags->GetBinLabel(3 + enCBT_hadronPID), axRctFlags->GetBinCenter(3 + enCBT_hadronPID)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 2 + enCBT, rctCheckerCBT(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 2 + enCBT_hadronPID, rctCheckerCBT_hadronPID(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 2 + enCBT_electronPID, rctCheckerCBT_electronPID(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 2 + enCBT_calo, rctCheckerCBT_calo(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 2 + enCBT_muon, rctCheckerCBT_muon(col)); + histos.fill(HIST("hSecondsRCTflags"), secFromSOR, 2 + 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()); + int nPVtracks = 0; + 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()); + + nPVtracks++; + } + + // ### 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 track loop + + // fill mult distributions vs time + if (confIncludeMultDistrVsTimeHistos) { + bool noPileup = col.selection_bit(kNoSameBunchPileup); + + histos.fill(HIST("multDistributions/hSecondsDistrPVtracks"), secFromSOR, nPVtracks); + + // ZNA,C + // float multZNA = bc.has_zdc() ? bc.zdc().energyCommonZNA() : -999.f; + // float multZNC = bc.has_zdc() ? bc.zdc().energyCommonZNC() : -999.f; + histos.fill(HIST("multDistributions/hSecondsDistrZNA"), secFromSOR, col.multZNA()); + histos.fill(HIST("multDistributions/hSecondsDistrZNC"), secFromSOR, col.multZNC()); + float ZNdiff = col.multZNA() - col.multZNC(); + float ZNsum = col.multZNA() + col.multZNC(); + histos.fill(HIST("multDistributions/hSecondsDistrZNACdiff"), secFromSOR, ZNdiff); + if (ZNsum > 0) + histos.fill(HIST("multDistributions/hSecondsDistrZNACdiffNorm"), secFromSOR, ZNdiff / ZNsum); + + // ZNA,C by amplitudes (suggested by Chiara O.) + float ZNAampl = bc.has_zdc() ? bc.zdc().amplitudeZNA() : 0; + float ZNCampl = bc.has_zdc() ? bc.zdc().amplitudeZNC() : 0; + histos.fill(HIST("multDistributions/hSecondsDistrZNAampl"), secFromSOR, ZNAampl); + histos.fill(HIST("multDistributions/hSecondsDistrZNCampl"), secFromSOR, ZNCampl); + float ZNdiffAmpl = ZNAampl - ZNCampl; + float ZNsumAmpl = ZNAampl + ZNCampl; + histos.fill(HIST("multDistributions/hSecondsDistrZNACdiffAmpl"), secFromSOR, ZNdiffAmpl); + if (ZNsumAmpl > 0) + histos.fill(HIST("multDistributions/hSecondsDistrZNACdiffNormAmpl"), secFromSOR, ZNdiffAmpl / ZNsumAmpl); + + // FT0A,C, V0A + // float multT0A = bc.has_ft0() ? bc.ft0().sumAmpA() : -999.f; + // float multT0C = bc.has_ft0() ? fbcundBC.ft0().sumAmpC() : -999.f; + histos.fill(HIST("multDistributions/hSecondsDistrT0A"), secFromSOR, col.multFT0A()); + histos.fill(HIST("multDistributions/hSecondsDistrT0C"), secFromSOR, col.multFT0C()); + histos.fill(HIST("multDistributions/hSecondsDistrV0A"), secFromSOR, col.multFV0A()); + + if (noPileup) { + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrPVtracks"), secFromSOR, nPVtracks); + + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrZNA"), secFromSOR, col.multZNA()); + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrZNC"), secFromSOR, col.multZNC()); + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrZNACdiff"), secFromSOR, ZNdiff); + if (ZNsum > 0) + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrZNACdiffNorm"), secFromSOR, ZNdiff / ZNsum); + + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrZNAampl"), secFromSOR, ZNAampl); + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrZNCampl"), secFromSOR, ZNCampl); + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrZNACdiffAmpl"), secFromSOR, ZNdiffAmpl); + if (ZNsumAmpl > 0) + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrZNACdiffNormAmpl"), secFromSOR, ZNdiffAmpl / ZNsumAmpl); + + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrT0A"), secFromSOR, col.multFT0A()); + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrT0C"), secFromSOR, col.multFT0C()); + histos.fill(HIST("multDistributionsNoPileup/hSecondsDistrV0A"), secFromSOR, col.multFV0A()); + } + } + } + } // 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 9974d3d6bc2..bd055664fd8 100644 --- a/DPG/Tasks/AOTTrack/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/CMakeLists.txt @@ -80,8 +80,18 @@ o2physics_add_dpl_workflow(qa-tracksplitting PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(unit-test-for-reconstruction + SOURCES unitTestForReconstruction.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 O2Physics::MLCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(derived-data-creator-d0-calibration + SOURCES derivedDataCreatorD0Calibration.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCore O2::DCAFitter O2Physics::MLCore + COMPONENT_NAME Analysis) + diff --git a/DPG/Tasks/AOTTrack/D0CalibTables.h b/DPG/Tasks/AOTTrack/D0CalibTables.h new file mode 100644 index 00000000000..33c9efdc2dd --- /dev/null +++ b/DPG/Tasks/AOTTrack/D0CalibTables.h @@ -0,0 +1,492 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file D0CalibTables.h +/// \brief Definitions of derived tables produced by data creator for D0 calibration studies +/// \author Fabrizio Grosa , CERN + +#ifndef DPG_TASKS_AOTTRACK_D0CALIBTABLES_H_ +#define DPG_TASKS_AOTTRACK_D0CALIBTABLES_H_ + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include + +#include + +#include +#include +#include +#include + +namespace o2 +{ +namespace hf_calib +{ +enum D0MassHypo : uint8_t { + D0 = 1, + D0Bar, + D0AndD0Bar, + ND0MassHypos +}; + +const float toMicrometers = 10000.; // from cm to µm + +/// It compresses a value to a int8_t with a given precision +///\param origValue is the original values +///\param precision is the desired precision +///\return The value compressed to a int8_t +template +int8_t getCompressedInt8(T origValue, double precision) +{ + int roundValue = static_cast(std::round(origValue / precision)); + return static_cast(std::clamp(roundValue, -128, 128)); +} + +/// It compresses a value to a uint8_t with a given precision +///\param origValue is the original values +///\param precision is the desired precision +///\return The value compressed to a uint8_t +template +uint8_t getCompressedUint8(T origValue, double precision) +{ + int roundValue = static_cast(std::round(origValue / precision)); + return static_cast(std::clamp(roundValue, 0, 255)); +} + +/// It compresses a value to a uint16_t with a given precision +///\param origValue is the original values +///\param precision is the desired precision +///\return The value compressed to a uint16_t +template +uint16_t getCompressedUint16(T origValue, double precision) +{ + int roundValue = static_cast(std::round(origValue / precision)); + return static_cast(std::clamp(roundValue, 0, 65535)); +} + +/// It uses a sinh-based scaling function, which provides a compromise between fixed-step and relative quantization. +// This approach reflects typical resolution formulas and is well-suited for detector calibration data. +///\param origValue is the original value +///\param sigma0 is a asinh parameter +///\param sigma1 is a asinh parameter +///\param clampMin is the maximum value +///\param clampMax is the minimum value +///\return The value compressed +int codeSqrtScaling(float origValue, float sigma0, float sigma1, int clampMin, int clampMax) +{ + float codeF = std::asinh((sigma1 * origValue) / sigma0) / sigma0; + return std::clamp(static_cast(std::round(codeF)), clampMin, clampMax); +} + +/// It compresses the decay length (10 micron precision) +///\param decLen is the decay length in cm +///\return The decay length compressed to a uint8_t with 10 micron precision +template +uint8_t getCompressedDecayLength(T decLen) +{ + return getCompressedUint8(decLen * hf_calib::toMicrometers, 10); +} + +/// It compresses the normalised decay length (0.5 precision) +///\param normDecLen is the normalised decay length +///\return The normalised decay length compressed to a uint8_t with 0.5 precision +template +uint8_t getCompressedNormDecayLength(T normDecLen) +{ + return getCompressedUint8(normDecLen, 0.5); +} + +/// It compresses the pointing angle (0.005 precision) +///\param pointAngle is the pointing angle +///\return The pointing angle compressed to a uint8_t with 0.005 precision +template +uint8_t getCompressedPointingAngle(T pointAngle) +{ + return getCompressedUint8(pointAngle, 0.005); +} + +/// It compresses the cosine of pointing angle (0.001 precision) +///\param cosPa is the cosine of pointing angle +///\return The cosine of pointing angle compressed to a uint8_t with 0.001 precision +template +int8_t getCompressedCosPa(T cosPa) +{ + return getCompressedUint8(cosPa - 0.75, 0.001); // in the range from 0.75 to 1 +} + +/// It compresses the chi2 +///\param chi2 is the chi2 +///\return The chi2 compressed to a uint8_t +template +int8_t getCompressedChi2(T chi2) +{ + uint8_t compressedChi2 = static_cast(codeSqrtScaling(chi2, 0.015, 0.015, 0, 255)); + return compressedChi2; +} + +/// It compresses the number of sigma +///\param numSigma is the number of sigma +///\return The number of sigma compressed to a int8_t +template +int8_t getCompressedNumSigmaPid(T numSigma) +{ + int8_t compressedNumSigma = static_cast(codeSqrtScaling(numSigma, 0.05, 0.05, -128, 128)); + return compressedNumSigma; +} + +/// It compresses the bdt score (1./65535 precision) +///\param bdtScore is the bdt score +///\return The bdt score compressed to a uint16_t with 1./65535 precision +template +uint16_t getCompressedBdtScoreBkg(T bdtScore) +{ + return getCompressedUint16(bdtScore, 1. / 65535); +} + +/// It compresses the bdt score (1./255 precision) +///\param bdtScore is the bdt score +///\return The bdt score compressed to a uint8_t with 1./255 precision +template +uint8_t getCompressedBdtScoreSgn(T bdtScore) +{ + return getCompressedUint8(bdtScore, 1. / 255); +} + +/// It compresses the occupancy value +///\param occupancy is the occupancy value +///\return The number of occupancy compressed to a uint8_t +template +uint8_t getCompressedOccupancy(T occupancy) +{ + uint8_t compressedOcc = static_cast(codeSqrtScaling(occupancy, 0.04, 0.04, 0, 255)); + return compressedOcc; +} + +static constexpr int NBinsPtTrack = 6; +static constexpr int NCutVarsTrack = 4; +constexpr float BinsPtTrack[NBinsPtTrack + 1] = { + 0, + 0.5, + 1.0, + 1.5, + 2.0, + 3.0, + 1000.0}; +auto vecBinsPtTrack = std::vector{BinsPtTrack, BinsPtTrack + NBinsPtTrack + 1}; + +// default values for the dca_xy and dca_z cuts of displaced tracks +constexpr float CutsTrack[NBinsPtTrack][NCutVarsTrack] = {{0.0015, 2., 0.0000, 2.}, /* 0 < pt < 0.5 */ + {0.0015, 2., 0.0000, 2.}, /* 0.5 < pt < 1 */ + {0.0015, 2., 0.0000, 2.}, /* 1 < pt < 1.5 */ + {0.0015, 2., 0.0000, 2.}, /* 1.5 < pt < 2 */ + {0.0000, 2., 0.0000, 2.}, /* 2 < pt < 3 */ + {0.0000, 2., 0.0000, 2.}}; /* 3 < pt < 1000 */ +// row labels +static const std::vector labelsPtTrack{}; + +// column labels +static const std::vector labelsCutVarTrack = {"min_dcaxytoprimary", "max_dcaxytoprimary", "min_dcaztoprimary", "max_dcaztoprimary"}; + +static constexpr int NBinsPtCand = 10; +static constexpr int NCutVarsCand = 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 float BinsPtCand[NBinsPtCand + 1] = { + 0, + 1.0, + 2.0, + 3.0, + 4.0, + 6.0, + 8.0, + 12.0, + 24.0, + 50.0, + 1000.0}; +auto vecBinsPtCand = std::vector{BinsPtCand, BinsPtCand + NBinsPtCand + 1}; + +// default values for the cuts +constexpr float CutsCand[NBinsPtCand][NCutVarsCand] = {{0.400, 0., 10., 10., 0.97, 0.97, 0, 2, 0.01, 0.01}, /* 0 < pT < 1 */ + {0.400, 0., 10., 10., 0.97, 0.97, 0, 2, 0.01, 0.01}, /* 1 < pT < 2 */ + {0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 2 < pT < 3 */ + {0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 3 < pT < 4 */ + {0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 4 < pT < 6 */ + {0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 6 < pT < 8 */ + {0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 8 < pT < 12 */ + {0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 12 < pT < 24 */ + {0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 24 < pT < 50 */ + {0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}}; /* 50 < pT < 1000 */ + +// row labels +static const std::vector labelsPtCand = { + "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 labelsCutVarCand = {"delta inv. mass", "max d0d0", "max pointing angle", "max pointing angle XY", "min cos pointing angle", "min cos pointing angle XY", "min norm decay length", "min norm decay length XY", "min decay length", "min decay length XY"}; + +static constexpr int NBinsPtMl = 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 BinsPtMl[NBinsPtMl + 1] = { + 0, + 1.0, + 2.0, + 3.0, + 4.0, + 6.0, + 8.0, + 12.0, + 24.0, + 50.0, + 1000.0}; +auto vecBinsPtMl = std::vector{BinsPtMl, BinsPtMl + NBinsPtMl + 1}; + +// default values for the cuts +constexpr double CutsMl[NBinsPtMl][3] = {{1., 0., 0.}, /* 0 < pT < 1 */ + {1., 0., 0.}, /* 1 < pT < 2 */ + {1., 0., 0.}, /* 2 < pT < 3 */ + {1., 0., 0.}, /* 3 < pT < 4 */ + {1., 0., 0.}, /* 4 < pT < 6 */ + {1., 0., 0.}, /* 6 < pT < 8 */ + {1., 0., 0.}, /* 8 < pT < 12 */ + {1., 0., 0.}, /* 12 < pT < 24 */ + {1., 0., 0.}, /* 24 < pT < 50 */ + {1., 0., 0.}}; /* 50 < pT < 1000 */ + +// row labels +static const std::vector labelsPtMl = { + "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 labelsCutMl = {"max BDT score bkg", "min BDT score prompt", "min BDT score nonprompt"}; +} // namespace hf_calib + +namespace aod +{ +namespace hf_calib +{ +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); //! Run number +DECLARE_SOA_COLUMN(Orbit, orbit, uint32_t); //! orbit ID +DECLARE_SOA_COLUMN(CentFT0C, centFT0C, uint8_t); //! FTOC centrality +DECLARE_SOA_COLUMN(OccupancyTracks, occupancyTracks, uint8_t); //! FT0 occupancy +DECLARE_SOA_COLUMN(OccupancyFT0C, occupancyFT0C, uint8_t); //! FT0 occupancy +} // namespace hf_calib + +DECLARE_SOA_TABLE(D0CalibColls, "AOD", "D0CALIBCOLL", + o2::soa::Index<>, + collision::PosX, + collision::PosY, + collision::PosZ, + collision::CovXX, + collision::CovXY, + collision::CovXZ, + collision::CovYY, + collision::CovYZ, + collision::CovZZ, + collision::NumContrib, + hf_calib::CentFT0C, + hf_calib::OccupancyTracks, + hf_calib::OccupancyFT0C, + hf_calib::Orbit, + hf_calib::RunNumber); + +namespace hf_calib +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Collision, collision, int, D0CalibColls, ""); //! Index of collision +DECLARE_SOA_COLUMN(TpcNumSigmaPi, tpcNumSigmaPi, int8_t); //! compressed NsigmaTPC for pions +DECLARE_SOA_COLUMN(TpcNumSigmaKa, tpcNumSigmaKa, int8_t); //! compressed NsigmaTPC for kaons +DECLARE_SOA_COLUMN(TofNumSigmaPi, tofNumSigmaPi, int8_t); //! compressed NsigmaTOF for pions +DECLARE_SOA_COLUMN(TofNumSigmaKa, tofNumSigmaKa, int8_t); //! compressed NsigmaTOF for kaons +DECLARE_SOA_COLUMN(ITSChi2NCl, itsChi2NCl, uint8_t); //! compressed NsigmaTOF for kaons // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(TPCChi2NCl, tpcChi2NCl, uint8_t); //! compressed NsigmaTOF for kaons // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(TRDChi2, trdChi2, uint8_t); //! compressed NsigmaTOF for kaons // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(TOFChi2, tofChi2, uint8_t); //! compressed NsigmaTOF for kaons // o2-linter: disable=name/o2-column +DECLARE_SOA_COLUMN(CmoPrimUnfm80, cmoPrimUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CmoFV0AUnfm80, cmoFV0AUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CmoFT0AUnfm80, cmoFT0AUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CmoFT0CUnfm80, cmoFT0CUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CwmoPrimUnfm80, cwmoPrimUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CwmoFV0AUnfm80, cwmoFV0AUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CwmoFT0AUnfm80, cwmoFT0AUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CwmoFT0CUnfm80, cwmoFT0CUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CmoRobustT0V0PrimUnfm80, cmoRobustT0V0PrimUnfm80, uint8_t); +DECLARE_SOA_COLUMN(CwmoRobustT0V0PrimUnfm80, cwmoRobustT0V0PrimUnfm80, uint8_t); +} // namespace hf_calib + +DECLARE_SOA_TABLE(D0CalibTracks, "AOD", "D0CALIBTRACK", + o2::soa::Index<>, + /// *** collision index + hf_calib::CollisionId, + /// *** track pars + track::X, + track::Alpha, + track::Y, + track::Z, + track::Snp, + track::Tgl, + track::Signed1Pt, + /// *** track covs + 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, + /// *** track extra (static) + track::TPCInnerParam, + track::Flags, + track::ITSClusterSizes, + track::TPCNClsFindable, + track::TPCNClsFindableMinusFound, + track::TPCNClsFindableMinusCrossedRows, + track::TPCNClsShared, + track::TRDPattern, + hf_calib::ITSChi2NCl, + hf_calib::TPCChi2NCl, + hf_calib::TRDChi2, + hf_calib::TOFChi2, + track::TPCSignal, + track::TRDSignal, + track::Length, + track::TOFExpMom, + track::TrackTime, + track::TrackTimeRes, + /// *** track QA + trackqa::TPCTime0, + trackqa::TPCdEdxNorm, + 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::DeltaRefContParamZ, + trackqa::DeltaRefContParamSnp, + trackqa::DeltaRefContParamTgl, + trackqa::DeltaRefContParamQ2Pt, + trackqa::DeltaRefGloParamY, + trackqa::DeltaRefGloParamZ, + trackqa::DeltaRefGloParamSnp, + trackqa::DeltaRefGloParamTgl, + trackqa::DeltaRefGloParamQ2Pt, + trackqa::DeltaTOFdX, + trackqa::DeltaTOFdZ, + /// *** DCA, Nsigma + track::DcaXY, + track::DcaZ, + hf_calib::TpcNumSigmaPi, + hf_calib::TpcNumSigmaKa, + hf_calib::TofNumSigmaPi, + hf_calib::TofNumSigmaKa, + /// *** Occupancy variables + hf_calib::CmoPrimUnfm80, + hf_calib::CmoFV0AUnfm80, + hf_calib::CmoFT0AUnfm80, + hf_calib::CmoFT0CUnfm80, + hf_calib::CwmoPrimUnfm80, + hf_calib::CwmoFV0AUnfm80, + hf_calib::CwmoFT0AUnfm80, + hf_calib::CwmoFT0CUnfm80, + hf_calib::CmoRobustT0V0PrimUnfm80, + hf_calib::CwmoRobustT0V0PrimUnfm80); + +namespace hf_calib +{ +DECLARE_SOA_INDEX_COLUMN_FULL(TrackPos, trackPos, int, D0CalibTracks, "_Pos"); //! Index of positive track +DECLARE_SOA_INDEX_COLUMN_FULL(TrackNeg, trackNeg, int, D0CalibTracks, "_Neg"); //! Index of negative track +DECLARE_SOA_COLUMN(MassHypo, massHypo, uint8_t); //! mass hypothesis for D0 (D0, D0bar, or both) +DECLARE_SOA_COLUMN(Pt, pt, float); //! D0-candidate pT +DECLARE_SOA_COLUMN(Eta, eta, float); //! D0-candidate eta +DECLARE_SOA_COLUMN(Phi, phi, float); //! D0-candidate phi +DECLARE_SOA_COLUMN(InvMassD0, invMassD0, float); //! invariant mass (D0 hypothesis) +DECLARE_SOA_COLUMN(InvMassD0bar, invMassD0bar, float); //! invariant mass (D0bar hypothesis) +DECLARE_SOA_COLUMN(DecLength, decLength, uint8_t); //! compressed decay length +DECLARE_SOA_COLUMN(DecLengthXY, decLengthXY, uint8_t); //! compressed decay length XY +DECLARE_SOA_COLUMN(NormDecLength, normDecLength, uint8_t); //! compressed normalised decay length +DECLARE_SOA_COLUMN(NormDecLengthXY, normDecLengthXY, uint8_t); //! compressed normalised decay length XY +DECLARE_SOA_COLUMN(CosPa, cosPa, uint8_t); //! compressed cosine of pointing angle +DECLARE_SOA_COLUMN(CosPaXY, cosPaXY, uint8_t); //! compressed cosine of pointing angle XY +DECLARE_SOA_COLUMN(PointingAngle, pointingAngle, uint8_t); //! compressed pointing angle +DECLARE_SOA_COLUMN(PointingAngleXY, pointingAngleXY, uint8_t); //! compressed pointing angle XY +DECLARE_SOA_COLUMN(DecVtxChi2, decVtxChi2, uint8_t); //! compressed decay vertex chi2 +DECLARE_SOA_COLUMN(BdtScoreBkgD0, bdtScoreBkgD0, uint16_t); //! compressed BDT score (bkg, D0 mass hypo) +DECLARE_SOA_COLUMN(BdtScorePromptD0, bdtScorePromptD0, uint8_t); //! compressed BDT score (prompt, D0 mass hypo) +DECLARE_SOA_COLUMN(BdtScoreNonpromptD0, bdtScoreNonpromptD0, uint8_t); //! compressed BDT score (non-prompt, D0 mass hypo) +DECLARE_SOA_COLUMN(BdtScoreBkgD0bar, bdtScoreBkgD0bar, uint16_t); //! compressed BDT score (bkg, D0bar mass hypo) +DECLARE_SOA_COLUMN(BdtScorePromptD0bar, bdtScorePromptD0bar, uint8_t); //! compressed BDT score (prompt, D0bar mass hypo) +DECLARE_SOA_COLUMN(BdtScoreNonpromptD0bar, bdtScoreNonpromptD0bar, uint8_t); //! compressed BDT score (non-prompt, D0bar mass hypo) +} // namespace hf_calib + +DECLARE_SOA_TABLE(D0CalibCands, "AOD", "D0CALIBCAND", + o2::soa::Index<>, + hf_calib::CollisionId, + hf_calib::TrackPosId, + hf_calib::TrackNegId, + hf_calib::MassHypo, + hf_calib::Pt, + hf_calib::Eta, + hf_calib::Phi, + hf_calib::InvMassD0, + hf_calib::InvMassD0bar, + hf_calib::DecLength, + hf_calib::DecLengthXY, + hf_calib::NormDecLength, + hf_calib::NormDecLengthXY, + hf_calib::CosPa, + hf_calib::CosPaXY, + hf_calib::PointingAngle, + hf_calib::PointingAngleXY, + hf_calib::DecVtxChi2, + hf_calib::BdtScoreBkgD0, + hf_calib::BdtScorePromptD0, + hf_calib::BdtScoreNonpromptD0, + hf_calib::BdtScoreBkgD0bar, + hf_calib::BdtScorePromptD0bar, + hf_calib::BdtScoreNonpromptD0bar); +} // namespace aod +} // namespace o2 +#endif // DPG_TASKS_AOTTRACK_D0CALIBTABLES_H_ diff --git a/DPG/Tasks/AOTTrack/PID/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/CMakeLists.txt index f38baceaaab..17f77acfa59 100644 --- a/DPG/Tasks/AOTTrack/PID/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/PID/CMakeLists.txt @@ -12,4 +12,5 @@ add_subdirectory(Combined) add_subdirectory(TOF) add_subdirectory(TPC) +add_subdirectory(ITS) add_subdirectory(HMPID) diff --git a/DPG/Tasks/AOTTrack/PID/Combined/qaPIDWithV0s.cxx b/DPG/Tasks/AOTTrack/PID/Combined/qaPIDWithV0s.cxx index 3f1ed2a8640..9b1d4f9c692 100644 --- a/DPG/Tasks/AOTTrack/PID/Combined/qaPIDWithV0s.cxx +++ b/DPG/Tasks/AOTTrack/PID/Combined/qaPIDWithV0s.cxx @@ -16,18 +16,21 @@ /// \brief Task to monitor the PID performance making use of V0s /// -#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/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::framework; diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/HMPID/CMakeLists.txt index 9d153069976..96bb9ab18c4 100644 --- a/DPG/Tasks/AOTTrack/PID/HMPID/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/PID/HMPID/CMakeLists.txt @@ -10,7 +10,17 @@ # or submit itself to any jurisdiction. # HMPID -o2physics_add_dpl_workflow(pid-hmpid-qa - SOURCES qaHMPID.cxx +o2physics_add_dpl_workflow(hmpid-qa + SOURCES hmpidQa.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDBase O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(hmpid-table-producer + SOURCES hmpidTableProducer.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(hmpid-deuteron + SOURCES hmpidDeuteron.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::ReconstructionDataFormats O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx new file mode 100644 index 00000000000..98ea08f7add --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.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. + +#include "tableHMPID.h" + +#include +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; + +struct HmpidDeuteron { + HistogramRegistry registryDA{"registryDA", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable nsigmaTPCMin{"nsigmaTPCMin", -3.0, "nsigmaTPCMin"}; + Configurable nsigmaTPCMax{"nsigmaTPCMax", +3.0, "nsigmaTPCMax"}; + Configurable nsigmaTOFMin{"nsigmaTOFMin", -3.0, "nsigmaTOFMin"}; + Configurable nsigmaTOFMax{"nsigmaTOFMax", +3.5, "nsigmaTOFMax"}; + Configurable minReqClusterITS{"minReqClusterITS", 4.0, "min number of clusters required in ITS"}; + Configurable minTPCnClsFound{"minTPCnClsFound", 50.0f, "minTPCnClsFound"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.0f, "min number of crossed rows TPC"}; + Configurable maxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; + Configurable maxDCAxy{"maxDCAxy", 0.5f, "maxDCAxy"}; + Configurable maxDCAz{"maxDCAz", 0.5f, "maxDCAz"}; + + void init(InitContext const&) + { + // Deuteron Pos + registryDA.add("incomingDe_Pos_8cm", "incomingDe_Pos_8cm", HistType::kTH1F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}}); + registryDA.add("incomingDe_Pos_4cm", "incomingDe_Pos_4cm", HistType::kTH1F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}}); + + registryDA.add("De_Pos_deltaR_8cm", "De_Pos_deltaR_8cm", HistType::kTH1F, {{300, 0.0, 30.0, "#Delta R (cm)"}}); + registryDA.add("De_Pos_deltaR_4cm", "De_Pos_deltaR_4cm", HistType::kTH1F, {{300, 0.0, 30.0, "#Delta R (cm)"}}); + + registryDA.add("survivingDe_Pos_8cm", "survivingDe_Pos_8cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {300, 0.0, 30.0, "#Delta R (cm)"}}); + registryDA.add("survivingDe_Pos_4cm", "survivingDe_Pos_4cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {300, 0.0, 30.0, "#Delta R (cm)"}}); + registryDA.add("De_Pos_Q_8cm", "De_Pos_Q_8cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {200, 0.0, 2000.0, "Q (ADC)"}}); + registryDA.add("De_Pos_Q_4cm", "De_Pos_Q_4cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {200, 0.0, 2000.0, "Q (ADC)"}}); + registryDA.add("De_Pos_ClsSize_8cm", "De_Pos_ClsSize_8cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, 0.0, 20., "Cls size"}}); + registryDA.add("De_Pos_ClsSize_4cm", "De_Pos_ClsSize_4cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, 0.0, 20.0, "Cls size"}}); + registryDA.add("De_Pos_momentum", "De_Pos_momentum", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{vtx} (GeV/#it{c})"}, {100, 0.0, 5.0, "#it{p}_{hmpid} (GeV/#it{c})"}}); + + registryDA.add("nSigmaTPC_vs_momHMPID_noCut_DePos", "nSigmaTPC_vs_momHMPID_noCut_DePos", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, -5., 5.0, "n#sigma_TPC"}}); + registryDA.add("nSigmaTOF_vs_momHMPID_noCut_DePos", "nSigmaTOF_vs_momHMPID_noCut_DePos", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, -5., 5.0, "n#sigma_TOF"}}); + registryDA.add("nSigmaTPC_vs_momHMPID_Cut_DePos", "nSigmaTPC_vs_momHMPID_Cut_DePos", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, -5., 5.0, "n#sigma_TPC"}}); + registryDA.add("nSigmaTOF_vs_momHMPID_Cut_DePos", "nSigmaTOF_vs_momHMPID_Cut_DePos", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, -5., 5.0, "n#sigma_TOF"}}); + + // Deuteron Neg + registryDA.add("incomingDe_Neg_8cm", "incomingDe_Neg_8cm", HistType::kTH1F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}}); + registryDA.add("incomingDe_Neg_4cm", "incomingDe_Neg_4cm", HistType::kTH1F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}}); + + // plot aggiunti + registryDA.add("De_Neg_deltaR_8cm", "De_Neg_deltaR_8cm", HistType::kTH1F, {{300, 0.0, 30.0, "#Delta R (cm)"}}); + registryDA.add("De_Neg_deltaR_4cm", "De_Neg_deltaR_4cm", HistType::kTH1F, {{300, 0.0, 30.0, "#Delta R (cm)"}}); + + registryDA.add("survivingDe_Neg_8cm", "survivingDe_Neg_8cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {300, 0.0, 30.0, "#Delta R (cm)"}}); + registryDA.add("survivingDe_Neg_4cm", "survivingDe_Neg_4cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {300, 0.0, 30.0, "#Delta R (cm)"}}); + registryDA.add("De_Neg_Q_8cm", "De_Neg_Q_8cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {200, 0.0, 2000.0, "Q (ADC)"}}); + registryDA.add("De_Neg_Q_4cm", "De_Neg_Q_4cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {200, 0.0, 2000.0, "Q (ADC)"}}); + registryDA.add("De_Neg_ClsSize_8cm", "De_Neg_ClsSize_8cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, 0.0, 20.0, "Cls size"}}); + registryDA.add("De_Neg_ClsSize_4cm", "De_Neg_ClsSize_4cm", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, 0.0, 20.0, "Cls size"}}); + registryDA.add("De_Neg_momentum", "De_Neg_momentum", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{vtx} (GeV/#it{c})"}, {100, 0.0, 5.0, "#it{p}_{hmpid} (GeV/#it{c})"}}); + + registryDA.add("nSigmaTPC_vs_momHMPID_noCut_DeNeg", "nSigmaTPC_vs_momHMPID_noCut_DeNeg", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, -5.0, 5.0, "n#sigma_TPC"}}); + registryDA.add("nSigmaTOF_vs_momHMPID_noCut_DeNeg", "nSigmaTOF_vs_momHMPID_noCut_DeNeg", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, -5., 5.0, "n#sigma_TOF"}}); + registryDA.add("nSigmaTPC_vs_momHMPID_Cut_DeNeg", "nSigmaTPC_vs_momHMPID_Cut_DeNeg", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, -5., 5.0, "n#sigma_TPC"}}); + registryDA.add("nSigmaTOF_vs_momHMPID_Cut_DeNeg", "nSigmaTOF_vs_momHMPID_Cut_DeNeg", HistType::kTH2F, {{490, 0.1, 5.0, "#it{p} (GeV/#it{c})"}, {20, -5., 5.0, "n#sigma_TOF"}}); + + registryDA.add("hmpidCkovvsMom", "hmpidCkovvsMom", kTH2F, {{500, 0, 10., "#it{p} (GeV/#it{c})"}, {800, 0., 0.8, "#theta_{Ch} (rad)"}}); + } + + void process(aod::HmpidAnalysis const& hmpidTable) + { + for (const auto& hmpid : hmpidTable) { + + // filters on primary tracks + if (hmpid.itsNCluster() < minReqClusterITS) + continue; + if (hmpid.tpcNCluster() < minTPCnClsFound) + continue; + if (hmpid.tpcNClsCrossedRows() < minNCrossedRowsTPC) + continue; + if (hmpid.tpcChi2() > maxChi2TPC) + continue; + if (hmpid.itsChi2() > maxChi2ITS) + continue; + if (TMath::Abs(hmpid.dcaXY()) > maxDCAxy) + continue; + if (TMath::Abs(hmpid.dcaZ()) > maxDCAz) + continue; + + // plots nsigma before cuts + if (hmpid.momentumHmpid() > 0) { + registryDA.fill(HIST("nSigmaTPC_vs_momHMPID_noCut_DePos"), std::fabs(hmpid.momentumHmpid()), hmpid.tpcNSigmaDe()); + registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_noCut_DePos"), std::fabs(hmpid.momentumHmpid()), hmpid.tofNSigmaDe()); + } + + if (hmpid.momentumHmpid() < 0) { + registryDA.fill(HIST("nSigmaTPC_vs_momHMPID_noCut_DeNeg"), std::fabs(hmpid.momentumHmpid()), hmpid.tpcNSigmaDe()); + registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_noCut_DeNeg"), std::fabs(hmpid.momentumHmpid()), hmpid.tofNSigmaDe()); + } + + // deuteron candidate cuts + if (hmpid.tpcNSigmaDe() < nsigmaTPCMin || hmpid.tpcNSigmaDe() > nsigmaTPCMax) + continue; + + if (hmpid.momentumHmpid() > 0) + registryDA.fill(HIST("nSigmaTPC_vs_momHMPID_Cut_DePos"), std::fabs(hmpid.momentumHmpid()), hmpid.tpcNSigmaDe()); + else + registryDA.fill(HIST("nSigmaTPC_vs_momHMPID_Cut_DeNeg"), std::fabs(hmpid.momentumHmpid()), hmpid.tpcNSigmaDe()); + + if (hmpid.tofNSigmaDe() < nsigmaTOFMin || hmpid.tofNSigmaDe() > nsigmaTOFMax) + continue; + + if (hmpid.momentumHmpid() > 0) + registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_Cut_DePos"), std::fabs(hmpid.momentumHmpid()), hmpid.tofNSigmaDe()); + else + registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_Cut_DeNeg"), std::fabs(hmpid.momentumHmpid()), hmpid.tofNSigmaDe()); + + // plot changle vs p + registryDA.fill(HIST("hmpidCkovvsMom"), hmpid.momentumHmpid(), hmpid.chAngle()); + + // absorbers + const float dx = hmpid.xTrack() - hmpid.xMip(); + const float dy = hmpid.yTrack() - hmpid.yMip(); + const float dr = TMath::Sqrt(dx * dx + dy * dy); + + int abs4cm = 2, abs8cm = 4; + bool hmpidAbs8cm = true, hmpidAbs4cm = true; + + if (hmpid.momentumHmpid() > 0) { + registryDA.fill(HIST("De_Pos_momentum"), hmpid.momentumTrack(), std::fabs(hmpid.momentumHmpid())); + + if (hmpidAbs8cm && hmpid.chamber() == abs8cm) { + registryDA.fill(HIST("incomingDe_Pos_8cm"), std::fabs(hmpid.momentumHmpid())); + registryDA.fill(HIST("survivingDe_Pos_8cm"), std::fabs(hmpid.momentumHmpid()), dr); + registryDA.fill(HIST("De_Pos_Q_8cm"), std::fabs(hmpid.momentumHmpid()), hmpid.chargeMip()); + registryDA.fill(HIST("De_Pos_ClsSize_8cm"), std::fabs(hmpid.momentumHmpid()), hmpid.clusterSize()); + registryDA.fill(HIST("De_Pos_deltaR_8cm"), dr); + } + if (hmpidAbs4cm && hmpid.chamber() == abs4cm) { + registryDA.fill(HIST("incomingDe_Pos_4cm"), std::fabs(hmpid.momentumHmpid())); + registryDA.fill(HIST("survivingDe_Pos_4cm"), std::fabs(hmpid.momentumHmpid()), dr); + registryDA.fill(HIST("De_Pos_Q_4cm"), std::fabs(hmpid.momentumHmpid()), hmpid.chargeMip()); + registryDA.fill(HIST("De_Pos_ClsSize_4cm"), std::fabs(hmpid.momentumHmpid()), hmpid.clusterSize()); + registryDA.fill(HIST("De_Pos_deltaR_4cm"), dr); + } + } + + if (hmpid.momentumHmpid() < 0) { + registryDA.fill(HIST("De_Neg_momentum"), hmpid.momentumTrack(), std::fabs(hmpid.momentumHmpid())); + + if (hmpidAbs8cm && hmpid.chamber() == abs8cm) { + registryDA.fill(HIST("incomingDe_Neg_8cm"), std::fabs(hmpid.momentumHmpid())); + registryDA.fill(HIST("survivingDe_Neg_8cm"), std::fabs(hmpid.momentumHmpid()), dr); + registryDA.fill(HIST("De_Neg_Q_8cm"), std::fabs(hmpid.momentumHmpid()), hmpid.chargeMip()); + registryDA.fill(HIST("De_Neg_ClsSize_8cm"), std::fabs(hmpid.momentumHmpid()), hmpid.clusterSize()); + registryDA.fill(HIST("De_Neg_deltaR_8cm"), dr); + } + if (hmpidAbs4cm && hmpid.chamber() == abs4cm) { + registryDA.fill(HIST("incomingDe_Neg_4cm"), std::fabs(hmpid.momentumHmpid())); + registryDA.fill(HIST("survivingDe_Neg_4cm"), std::fabs(hmpid.momentumHmpid()), dr); + registryDA.fill(HIST("De_Neg_Q_4cm"), std::fabs(hmpid.momentumHmpid()), hmpid.chargeMip()); + registryDA.fill(HIST("De_Neg_ClsSize_4cm"), std::fabs(hmpid.momentumHmpid()), hmpid.clusterSize()); + registryDA.fill(HIST("De_Neg_deltaR_4cm"), dr); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidQa.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidQa.cxx new file mode 100644 index 00000000000..5a1f821cda2 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidQa.cxx @@ -0,0 +1,1513 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "tableHMPID.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.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; +using namespace o2::constants::physics; + +double expectedSignal(double mass, float mom) +{ + // expected theoretical values + + double chAngleTh = -999.; + + const double nMean = 1.288; // radiator mean refraction index + + double cosChAngleTh = (TMath::Sqrt(mass * mass + mom * mom)) / (nMean * mom); + if (cosChAngleTh > 1) + return chAngleTh; + + chAngleTh = TMath::ACos(cosChAngleTh); + + return chAngleTh; +} + +double expectedSigma(int iPart, float mom) +{ + double sigmaRing = 0; + const int nMaxSigmas = 6; + + // fit parameters from sigma extrapolation + double fitSigmaExtraPions[nMaxSigmas] = {42.8961, -49.8723, 26.2311, -6.59093, 0.754578, -0.0286546}; + double fitSigmaExtraKaons[nMaxSigmas] = {76.9786, -103.655, 61.7533, -18.7436, 2.87855, -0.178318}; + double fitSigmaExtraProtons[nMaxSigmas] = {299.466, -383.277, 201.127, -52.2554, 6.67285, -0.334106}; + + // create sigma vs p functions + TF1* sigmaVsMomPions = new TF1("sigmaVsMomPions", "pol5", 0., 6.); + TF1* sigmaVsMomKaons = new TF1("sigmaVsMomKaons", "pol5", 0., 6.); + TF1* sigmaVsMomProtons = new TF1("sigmaVsMomProtons", "pol5", 0., 6.); + + for (int i = 0; i < nMaxSigmas; i++) { + sigmaVsMomPions->SetParameter(i, fitSigmaExtraPions[i]); + sigmaVsMomKaons->SetParameter(i, fitSigmaExtraKaons[i]); + sigmaVsMomProtons->SetParameter(i, fitSigmaExtraProtons[i]); + } + + const int idPions = 0, idKaons = 1, idProtons = 2; + + if (iPart == idPions) { + sigmaRing = gRandom->Gaus(sigmaVsMomPions->Eval(mom) / 1000., 0.1 * sigmaVsMomPions->Eval(mom) / 1000.); + } + if (iPart == idKaons) { + sigmaRing = 0.8 * gRandom->Gaus(sigmaVsMomKaons->Eval(mom) / 1000., 0.15 * sigmaVsMomKaons->Eval(mom) / 1000.); + } + if (iPart == idProtons) { + sigmaRing = 0.6 * gRandom->Gaus(sigmaVsMomProtons->Eval(mom) / 1000., 0.1 * sigmaVsMomProtons->Eval(mom) / 1000.); + } + + delete sigmaVsMomPions; + delete sigmaVsMomKaons; + delete sigmaVsMomProtons; + + return sigmaRing; +} + +void getProbability(float hmpidSignal, float hmpidMomentum, double* probs) +{ + // Calculates probability to be a pion-kaon-proton with the "amplitude" method + // from the given Cerenkov angle and momentum assuming no initial particle composition (class taken by AliROOT) + + int nSpecies = 3; + float angleZeroHeight = 900.; + + if (hmpidSignal <= 0) { + // HMPID does not find anything reasonable for this track, assign 0.33 for all species + for (int iPart = 0; iPart < nSpecies; iPart++) + probs[iPart] = 1.0 / nSpecies; + return; + } + + // assign mass in GeV/c^2 + double mass[] = {o2::constants::physics::MassPionCharged, o2::constants::physics::MassKaonCharged, o2::constants::physics::MassProton}; + + double hTot = 0; // Initialize the total height of the amplitude method + double* h = new double[nSpecies]; // number of charged particles to be considered + + bool desert = kTRUE; // Flag to evaluate if ThetaC is far ("desert") from the given Gaussians + + for (int iPart = 0; iPart < nSpecies; iPart++) { // for each particle + + h[iPart] = 0; // reset the height + double thetaCerTh = expectedSignal(mass[iPart], hmpidMomentum); // theoretical Theta Cherenkov + if (thetaCerTh > angleZeroHeight) + continue; // no light emitted, zero height + double sigmaRing = expectedSigma(iPart, hmpidMomentum); + float maxSigmaRing = 4 * sigmaRing; + + if (sigmaRing == 0) + continue; + + if (TMath::Abs(hmpidSignal - thetaCerTh) < maxSigmaRing) + desert = kFALSE; + h[iPart] = TMath::Gaus(thetaCerTh, hmpidSignal, sigmaRing, kTRUE); + hTot += h[iPart]; // total height of all theoretical heights for normalization + + } // species loop + + for (int iPart = 0; iPart < nSpecies; iPart++) { // species loop to assign probabilities + + if (!desert) + probs[iPart] = h[iPart] / hTot; + else + probs[iPart] = 1.0 / nSpecies; // all theoretical values are far away from experemental one + } + + delete[] h; +} + +struct HmpidQa { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable nBinsP{"nBinsP", 1200, "Number of momentum bins"}; + Configurable minP{"minP", -20.f, "Minimum momentum plotted (GeV/c)"}; + Configurable maxP{"maxP", 20.f, "Maximum momentum plotted (GeV/c)"}; + + Configurable nBinsCh{"nBinsCh", 800, "Number of ch angle bins"}; + Configurable minCh{"minCh", 0.f, "Minimum ch angle plotted (rad)"}; + Configurable maxCh{"maxCh", 0.8f, "Maximum ch angle plotted (rad)"}; + + /// filters configurables for primary tracks + Configurable nSigmaTpcMin{"nSigmaTpcMin", -3.0, "nSigmaTpcMin"}; + Configurable nSigmaTpcMax{"nSigmaTpcMax", +3.0, "nSigmaTpcMax"}; + Configurable nSigmaTofMin{"nSigmaTofMin", -3.0, "nSigmaTofMin"}; + Configurable nSigmaTofMax{"nSigmaTofMax", +3.5, "nSigmaTofMax"}; + Configurable minReqClusterIts{"minReqClusterIts", 4.0, "min number of clusters required in ITS"}; + Configurable minTpcNClsFound{"minTpcNClsFound", 50.0f, "minTpcNClsFound"}; + Configurable minNCrossedRowsTpc{"minNCrossedRowsTpc", 70.0f, "min number of crossed rows TPC"}; + Configurable maxChi2Its{"maxChi2Its", 36.0f, "max chi2 per cluster ITS"}; + Configurable maxChi2Tpc{"maxChi2Tpc", 4.0f, "max chi2 per cluster TPC"}; + Configurable maxDCAXY{"maxDCAXY", 0.5f, "maxDCAXY"}; + Configurable maxDCAZ{"maxDCAZ", 0.5f, "maxDCAZ"}; + + // QA filters + Configurable cutDistanceMipTrack{"cutDistanceMipTrack", 3.0f, "cut distance between MIP and track"}; + Configurable cutQmip{"cutQmip", 120.0f, "cut on Q MIP"}; + Configurable cutMinMomGlobalTrack{"cutMinMomGlobalTrack", 1.5f, "minimum momentum of global track"}; + Configurable minProbParticle{"minProbParticle", 0.7f, "minimum particle probability"}; + Configurable maxDistanceForProb{"maxDistanceForProb", 1.5f, "maximum distance for probability calculation"}; + Configurable maxBoxHit{"maxBoxHit", 100.0f, "maximum box hit position"}; + Configurable minBoxHit{"minBoxHit", 40.0f, "minimum box hit position"}; + + // variables for chamber_number and HVs/PCs + const int rich0 = 0, rich1 = 1, rich2 = 2, rich3 = 3, rich4 = 4, rich5 = 5, rich6 = 6; + const int hv0 = 0, hv1 = 1, hv2 = 2, hv3 = 3, hv4 = 4, hv5 = 5; + // total number of chambers and HVs/PCs + static const int nCh = 7, nSec = 6, nPc = 6; + + //////////////////////////////////// + //////////////////////////////////// + // load geometry + o2::hmpid::Param* fParam = o2::hmpid::Param::instanceNoGeo(); + + void init(InitContext const&) + { + AxisSpec momAxis{nBinsP, minP, maxP, "#it{p} (GeV/#it{c})"}; + AxisSpec cherenkAxis{nBinsCh, minCh, maxCh, "#theta_{Ch} (rad)"}; + + histos.add("nPhotons_vs_sin2Ch", "nPhotons_vs_sin2Ch", kTProfile, {{40, 0.0, 0.5}}); + + histos.add("ChAngle_LowPt", "ChAngle_LowPt", kTH1F, {cherenkAxis}); + histos.add("ChAngle_HighPt", "ChAngle_HighPt", kTH1F, {cherenkAxis}); + + histos.add("hmpidSignal", "hmpidSignal", kTH1F, {cherenkAxis}); + + // th2f for spectra + histos.add("pTvsChAngle", "pTvsChAngle", kTH2F, {{500, 0, 10., "#it{p}_{T} (GeV/#it{c})"}, {cherenkAxis}}); + + // charge identification + histos.add("pTvsChAnglePos", "pTvsChAnglePos", kTH2F, {{500, 0, 10., "#it{p}_{T} (GeV/#it{c})"}, {cherenkAxis}}); + histos.add("pTvsChAngleNeg", "pTvsChAngleNeg", kTH2F, {{500, 0, 10., "#it{p}_{T} (GeV/#it{c})"}, {cherenkAxis}}); + + histos.add("hmpidMomvsTrackMom", "hmpidMomvsTrackMom", kTH2F, {{1200, 0, 30, "Track #it{p} (GeV/#it{c})"}, {1200, 0, 30, "HMPID #it{p} (GeV/#it{c})"}}); + histos.add("hmpidCkovvsMom", "hmpidCkovvsMom", kTH2F, {{1000, 0, 10, "#it{p} (GeV/#it{c})"}, cherenkAxis}); + histos.add("TrackMom", "TrackMom", kTH1F, {momAxis}); + histos.add("hmpidMom", "hmpidMom", kTH1F, {momAxis}); + + histos.add("hmpidNPhotons", "hmpidNPhotons", kTH1F, {{50, 2, 50, "Number of photons"}}); + + histos.add("hmpidCkovvsMom_nocut", "hmpidCkovvsMom_nocut", kTH2F, {{1000, 0, 10, "#it{p} (GeV/#it{c})"}, cherenkAxis}); + + histos.add("hmpidPhotsCharge", "hmpidPhotsCharge", kTH1F, {{180, 4, 210}}); + histos.add("hmpidQMip", "hmpidQMip", kTH1F, {{1000, 200, 2200, "Charge (ADC)"}}); + + // information on particle position + histos.add("hmpidXTrack", "hmpidXTrack", kTH1F, {{270, 0, 135, "X track (cm)"}}); + histos.add("hmpidYTrack", "hmpidYTrack", kTH1F, {{270, 0, 135, "Y track (cm)"}}); + histos.add("hmpidXMip", "hmpidXMip", kTH1F, {{270, 0, 135, "X mip (cm)"}}); + histos.add("hmpidYMip", "hmpidYMip", kTH1F, {{270, 0, 135, "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)"}}); + // 2D map for the mip and the track + histos.add("hmpidXYTrack", "hmpidXYTrack", kTH2F, {{270, 0, 135, "X track (cm)"}, {270, 0, 135, "Y track (cm)"}}); + histos.add("hmpidXYMip", "hmpidXYMip", kTH2F, {{270, 0, 135, "X mip (cm)"}, {270, 0, 135, "Y mip (cm)"}}); + + // histos per chamber + for (int iCh = 0; iCh < nCh; iCh++) { + histos.add(Form("hmpidXTrack%i", iCh), Form("hmpidXTrack%i", iCh), kTH1F, {{270, 0, 135, "X track (cm)"}}); + histos.add(Form("hmpidYTrack%i", iCh), Form("hmpidYTrack%i", iCh), kTH1F, {{270, 0, 135, "Y track (cm)"}}); + histos.add(Form("hmpidXMip%i", iCh), Form("hmpidXMip%i", iCh), kTH1F, {{270, 0, 135, "X mip (cm)"}}); + histos.add(Form("hmpidYMip%i", iCh), Form("hmpidYMip%i", iCh), kTH1F, {{270, 0, 135, "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)"}}); + + // residuals discriminated for charge sign + histos.add(Form("hmpidXResidualsPos%i", iCh), Form("hmpidXResidualsPos%i", iCh), kTH1F, {{400, -20, 20, "X Residuals (cm)"}}); + histos.add(Form("hmpidYResidualsPos%i", iCh), Form("hmpidYResidualsPos%i", iCh), kTH1F, {{400, -20, 20, "Y Residuals (cm)"}}); + + histos.add(Form("hmpidXResidualsNeg%i", iCh), Form("hmpidXResidualsNeg%i", iCh), kTH1F, {{400, -20, 20, "X Residuals (cm)"}}); + histos.add(Form("hmpidYResidualsNeg%i", iCh), Form("hmpidYResidualsNeg%i", iCh), kTH1F, {{400, -20, 20, "Y Residuals (cm)"}}); + + histos.add(Form("hmpidNPhotons%i", iCh), Form("hmpidNPhotons%i", iCh), kTH1F, {{50, 2, 50, "Number of photons"}}); + + histos.add(Form("hmpidQMip%i", iCh), Form("hmpidQMip%i", iCh), kTH1F, {{1000, 200, 2200, "Charge (ADC)"}}); + 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, {momAxis}); + histos.add(Form("hmpidMom%i", iCh), Form("hmpidMom%i", iCh), kTH1F, {momAxis}); + + histos.add(Form("hmpidPhotsCharge%i", iCh), Form("hmpidPhotsCharge%i", iCh), kTH1F, {{180, 4, 210}}); + histos.add(Form("hmpidXYMip%i", iCh), Form("hmpidXYMip%i", iCh), kTH2F, {{270, 0, 135, "X mip (cm)"}, {270, 0, 135, "Y mip (cm)"}}); + + histos.add(Form("nPhotons_vs_sin2Ch%i", iCh), Form("N. of Photons vs sin^{2}(#theta_{Ch}) - chamber%i", iCh), kTProfile, {{40, 0.0, 0.5}}); + + // histos per HV sector + for (int iSec = 0; iSec < nSec; iSec++) { + histos.add(Form("hmpidQMip_RICH%i_HV%i", iCh, iSec), Form("hmpidQMip_RICH%i_HV%i", iCh, iSec), kTH1F, {{2000, 200, 2200, "Charge (ADC)"}}); + histos.add(Form("hmpidNPhotons_RICH%i_HV%i", iCh, iSec), Form("hmpidNPhotons_RICH%i_HV%i", iCh, iSec), kTH1F, {{50, 2, 50, "Number of photons"}}); + histos.add(Form("hmpidPhotsCharge_RICH%i_HV%i", iCh, iSec), Form("hmpidPhotsCharge_RICH%i_HV%i", iCh, iSec), kTH1F, {{180, 4, 210}}); + } + + // plot n_ph vs sin2Ch per PC + for (int iPc = 0; iPc < nPc; iPc++) { + histos.add(Form("nPhotons_vs_sin2Ch_RICH%i_PC%i", iCh, iPc), Form("N. of Photons vs sin^{2}(#theta_{Ch}) - chamber%i, photocathode%i", iCh, iPc), kTProfile, {{20, 0.0, 0.4}}); + } + } + } + + void process(aod::HmpidAnalysis const& hmpidtable) + { + // photocathods limits + static float xMinPc[nPc]; + static float yMinPc[nPc]; + static float xMaxPc[nPc]; + static float yMaxPc[nPc]; + + for (int iPc = 0; iPc < nPc; iPc++) { + xMaxPc[iPc] = (fParam->maxPcX(iPc)) - 10.; + yMaxPc[iPc] = (fParam->maxPcY(iPc)) - 10.; + xMinPc[iPc] = (fParam->minPcX(iPc)) + 10.; + yMinPc[iPc] = (fParam->minPcY(iPc)) + 10.; + } + + for (const auto& hmpid : hmpidtable) // loop on tracks contained in the table + { + + // filters on primary tracks + if (hmpid.itsNCluster() < minReqClusterIts) + continue; + if (hmpid.tpcNCluster() < minTpcNClsFound) + continue; + if (hmpid.tpcNClsCrossedRows() < minNCrossedRowsTpc) + continue; + if (hmpid.tpcChi2() > maxChi2Tpc) + continue; + if (hmpid.itsChi2() > maxChi2Its) + continue; + if (TMath::Abs(hmpid.dcaXY()) > maxDCAXY) + continue; + if (TMath::Abs(hmpid.dcaZ()) > maxDCAZ) + continue; + + // evaluate distance mip-track + const float distanceMipToTrack = std::hypot(hmpid.xTrack() - hmpid.xMip(), hmpid.yTrack() - hmpid.yMip()); + + // quality conditions to check + const bool physicalChAngle = (hmpid.chAngle() > 0); + const bool mipChargeCondition = (hmpid.chargeMip() > cutQmip); + const bool distanceCondition = (distanceMipToTrack < cutDistanceMipTrack); + + // fill histograms + histos.fill(HIST("hmpidMomvsTrackMom"), std::fabs(hmpid.momentumTrack()), std::fabs(hmpid.momentumHmpid())); + histos.fill(HIST("TrackMom"), std::fabs(hmpid.momentumTrack())); + histos.fill(HIST("hmpidMom"), std::fabs(hmpid.momentumHmpid())); + + histos.fill(HIST("hmpidSignal"), hmpid.chAngle()); + + if (physicalChAngle && distanceCondition && mipChargeCondition) { + double pT = static_cast(hmpid.momentumTrack() / TMath::CosH(hmpid.etaTrack())); + histos.fill(HIST("pTvsChAngle"), pT, hmpid.chAngle()); + if (hmpid.momentumHmpid() > 0) { + histos.fill(HIST("pTvsChAnglePos"), pT, hmpid.chAngle()); + } + if (hmpid.momentumHmpid() < 0) { + histos.fill(HIST("pTvsChAngleNeg"), pT, hmpid.chAngle()); + } + } + + float sin2changle = 0.; + + if (distanceCondition && mipChargeCondition) { + + histos.fill(HIST("hmpidNPhotons"), hmpid.nPhotons()); + + sin2changle = static_cast(TMath::Power(TMath::Sin(hmpid.chAngle()), 2)); + if (hmpid.xMip() <= maxBoxHit && hmpid.xMip() >= minBoxHit && hmpid.yMip() <= maxBoxHit && hmpid.yMip() >= minBoxHit) { + histos.fill(HIST("nPhotons_vs_sin2Ch"), sin2changle, hmpid.nPhotons()); + } + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge"), hmpid.photonsCharge()[i]); + } + } + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip"), hmpid.chargeMip()); + } + + histos.fill(HIST("hmpidXTrack"), hmpid.xTrack()); + histos.fill(HIST("hmpidYTrack"), hmpid.yTrack()); + histos.fill(HIST("hmpidXMip"), hmpid.xMip()); + histos.fill(HIST("hmpidYMip"), hmpid.yMip()); + if (hmpid.momentumTrack() > cutMinMomGlobalTrack) { + histos.fill(HIST("hmpidXResiduals"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResiduals"), hmpid.yMip() - hmpid.yTrack()); + } + histos.fill(HIST("hmpidXYTrack"), hmpid.xTrack(), hmpid.yTrack()); + histos.fill(HIST("hmpidXYMip"), hmpid.xMip(), hmpid.yMip()); + + ///////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////// + // fill histograms per chamber + if (hmpid.chamber() == rich0) { + histos.fill(HIST("hmpidXTrack0"), hmpid.xTrack()); + histos.fill(HIST("hmpidYTrack0"), hmpid.yTrack()); + histos.fill(HIST("hmpidXMip0"), hmpid.xMip()); + histos.fill(HIST("hmpidYMip0"), hmpid.yMip()); + histos.fill(HIST("hmpidXResiduals0"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResiduals0"), hmpid.yMip() - hmpid.yTrack()); + + if (hmpid.momentumTrack() > cutMinMomGlobalTrack) { + if (hmpid.momentumHmpid() > 0) { + // fill residual histos for positive charges + histos.fill(HIST("hmpidXResidualsPos0"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsPos0"), hmpid.yMip() - hmpid.yTrack()); + } + + if (hmpid.momentumHmpid() < 0) { + // fill residual histos for negative charges + histos.fill(HIST("hmpidXResidualsNeg0"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsNeg0"), hmpid.yMip() - hmpid.yTrack()); + } + } + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip0"), hmpid.chargeMip()); + } + histos.fill(HIST("hmpidClusSize0"), hmpid.clusterSize()); + histos.fill(HIST("TrackMom0"), hmpid.momentumTrack()); + histos.fill(HIST("hmpidMom0"), std::fabs(hmpid.momentumHmpid())); + histos.fill(HIST("hmpidXYMip0"), hmpid.xMip(), hmpid.yMip()); + + if (distanceCondition && mipChargeCondition) { + histos.fill(HIST("hmpidNPhotons0"), hmpid.nPhotons()); + sin2changle = static_cast(TMath::Power(TMath::Sin(hmpid.chAngle()), 2)); + if (hmpid.xMip() <= maxBoxHit && hmpid.xMip() >= minBoxHit && hmpid.yMip() <= maxBoxHit && hmpid.yMip() >= minBoxHit) { + histos.fill(HIST("nPhotons_vs_sin2Ch0"), sin2changle, hmpid.nPhotons()); + } + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge0"), hmpid.photonsCharge()[i]); + } + } + + ////////////////////////////////////////////////////////////////// + // plot per HV sector + if (fParam->inHVSector(hmpid.yMip()) == hv0) { + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH0_HV0"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH0_HV0"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH0_HV0"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv1) { + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH0_HV1"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH0_HV1"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH0_HV1"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv2) { + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH0_HV2"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH0_HV2"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH0_HV2"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv3) { + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH0_HV3"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH0_HV3"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH0_HV3"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv4) { + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH0_HV4"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH0_HV4"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH0_HV4"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv5) { + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH0_HV5"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH0_HV5"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH0_HV5"), hmpid.nPhotons()); + } + } + + ////////////////////////////////////////////////////////////////// + // fill plot photocathode + if (distanceCondition && mipChargeCondition && physicalChAngle) // condizione da verificare a priori + { + if (hmpid.xMip() >= xMinPc[0] && hmpid.xMip() <= xMaxPc[0] && hmpid.yMip() >= yMinPc[0] && hmpid.yMip() <= yMaxPc[0]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH0_PC0"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[1] && hmpid.xMip() <= xMaxPc[1] && hmpid.yMip() >= yMinPc[1] && hmpid.yMip() <= yMaxPc[1]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH0_PC1"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[2] && hmpid.xMip() <= xMaxPc[2] && hmpid.yMip() >= yMinPc[2] && hmpid.yMip() <= yMaxPc[2]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH0_PC2"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[3] && hmpid.xMip() <= xMaxPc[3] && hmpid.yMip() >= yMinPc[3] && hmpid.yMip() <= yMaxPc[3]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH0_PC3"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[4] && hmpid.xMip() <= xMaxPc[4] && hmpid.yMip() >= yMinPc[4] && hmpid.yMip() <= yMaxPc[4]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH0_PC4"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[5] && hmpid.xMip() <= xMaxPc[5] && hmpid.yMip() >= yMinPc[5] && hmpid.yMip() <= yMaxPc[5]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH0_PC5"), sin2changle, hmpid.nPhotons()); + } + } + } + + if (hmpid.chamber() == rich1) { + histos.fill(HIST("hmpidXTrack1"), hmpid.xTrack()); + histos.fill(HIST("hmpidYTrack1"), hmpid.yTrack()); + histos.fill(HIST("hmpidXMip1"), hmpid.xMip()); + histos.fill(HIST("hmpidYMip1"), hmpid.yMip()); + histos.fill(HIST("hmpidXResiduals1"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResiduals1"), hmpid.yMip() - hmpid.yTrack()); + + if (hmpid.momentumTrack() > cutMinMomGlobalTrack) { + if (hmpid.momentumHmpid() > 0) { + // fill residual histos for positive charges + histos.fill(HIST("hmpidXResidualsPos1"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsPos1"), hmpid.yMip() - hmpid.yTrack()); + } + + if (hmpid.momentumHmpid() < 0) { + // fill residual histos for negative charges + histos.fill(HIST("hmpidXResidualsNeg1"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsNeg1"), hmpid.yMip() - hmpid.yTrack()); + } + } + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip1"), hmpid.chargeMip()); + } + histos.fill(HIST("hmpidClusSize1"), hmpid.clusterSize()); + histos.fill(HIST("TrackMom1"), hmpid.momentumTrack()); + histos.fill(HIST("hmpidMom1"), std::fabs(hmpid.momentumHmpid())); + histos.fill(HIST("hmpidXYMip1"), hmpid.xMip(), hmpid.yMip()); + + if (distanceCondition && mipChargeCondition) { + histos.fill(HIST("hmpidNPhotons1"), hmpid.nPhotons()); + sin2changle = static_cast(TMath::Power(TMath::Sin(hmpid.chAngle()), 2)); + if (hmpid.xMip() <= maxBoxHit && hmpid.xMip() >= minBoxHit && hmpid.yMip() <= maxBoxHit && hmpid.yMip() >= minBoxHit) { + histos.fill(HIST("nPhotons_vs_sin2Ch1"), sin2changle, hmpid.nPhotons()); + } + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge1"), hmpid.photonsCharge()[i]); + } + } + + // plot per HV sector + if (fParam->inHVSector(hmpid.yMip()) == hv0) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH1_HV0"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH1_HV0"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH1_HV0"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv1) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH1_HV1"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH1_HV1"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH1_HV1"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv2) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH1_HV2"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH1_HV2"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH1_HV2"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv3) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH1_HV3"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH1_HV3"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH1_HV3"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv4) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH1_HV4"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH1_HV4"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH1_HV4"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv5) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH1_HV5"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH1_HV5"), hmpid.photonsCharge()[i]); + } // hmpidPhotsCharge_RICH%i_HV%i + } + histos.fill(HIST("hmpidNPhotons_RICH1_HV5"), hmpid.nPhotons()); + } + } + + ////////////////////////////////////////////////////////////////// + // fill plot photocathode + if (distanceCondition && mipChargeCondition && physicalChAngle) // condizione da verificare a priori + { + if (hmpid.xMip() >= xMinPc[0] && hmpid.xMip() <= xMaxPc[0] && hmpid.yMip() >= yMinPc[0] && hmpid.yMip() <= yMaxPc[0]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH1_PC0"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[1] && hmpid.xMip() <= xMaxPc[1] && hmpid.yMip() >= yMinPc[1] && hmpid.yMip() <= yMaxPc[1]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH1_PC1"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[2] && hmpid.xMip() <= xMaxPc[2] && hmpid.yMip() >= yMinPc[2] && hmpid.yMip() <= yMaxPc[2]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH1_PC2"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[3] && hmpid.xMip() <= xMaxPc[3] && hmpid.yMip() >= yMinPc[3] && hmpid.yMip() <= yMaxPc[3]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH1_PC3"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[4] && hmpid.xMip() <= xMaxPc[4] && hmpid.yMip() >= yMinPc[4] && hmpid.yMip() <= yMaxPc[4]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH1_PC4"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[5] && hmpid.xMip() <= xMaxPc[5] && hmpid.yMip() >= yMinPc[5] && hmpid.yMip() <= yMaxPc[5]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH1_PC5"), sin2changle, hmpid.nPhotons()); + } + } + } + + if (hmpid.chamber() == rich2) { + histos.fill(HIST("hmpidXTrack2"), hmpid.xTrack()); + histos.fill(HIST("hmpidYTrack2"), hmpid.yTrack()); + histos.fill(HIST("hmpidXMip2"), hmpid.xMip()); + histos.fill(HIST("hmpidYMip2"), hmpid.yMip()); + histos.fill(HIST("hmpidXResiduals2"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResiduals2"), hmpid.yMip() - hmpid.yTrack()); + + if (hmpid.momentumTrack() > cutMinMomGlobalTrack) { + if (hmpid.momentumHmpid() > 0) { + // fill residual histos for positive charges + histos.fill(HIST("hmpidXResidualsPos2"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsPos2"), hmpid.yMip() - hmpid.yTrack()); + } + + if (hmpid.momentumHmpid() < 0) { + // fill residual histos for negative charges + histos.fill(HIST("hmpidXResidualsNeg2"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsNeg2"), hmpid.yMip() - hmpid.yTrack()); + } + } + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip2"), hmpid.chargeMip()); + } + histos.fill(HIST("hmpidClusSize2"), hmpid.clusterSize()); + histos.fill(HIST("TrackMom2"), hmpid.momentumTrack()); + histos.fill(HIST("hmpidMom2"), std::fabs(hmpid.momentumHmpid())); + histos.fill(HIST("hmpidXYMip2"), hmpid.xMip(), hmpid.yMip()); + + if (distanceCondition && mipChargeCondition) { + histos.fill(HIST("hmpidNPhotons2"), hmpid.nPhotons()); + sin2changle = static_cast(TMath::Power(TMath::Sin(hmpid.chAngle()), 2)); + if (hmpid.xMip() <= maxBoxHit && hmpid.xMip() >= minBoxHit && hmpid.yMip() <= maxBoxHit && hmpid.yMip() >= minBoxHit) { + histos.fill(HIST("nPhotons_vs_sin2Ch2"), sin2changle, hmpid.nPhotons()); + } + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge2"), hmpid.photonsCharge()[i]); + } + } + + // plot per HV sector + if (fParam->inHVSector(hmpid.yMip()) == hv0) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH2_HV0"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH2_HV0"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH2_HV0"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv1) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH2_HV1"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH2_HV1"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH2_HV1"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv2) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH2_HV2"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH2_HV2"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH2_HV2"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv3) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH2_HV3"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH2_HV3"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH2_HV3"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv4) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH2_HV4"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH2_HV4"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH2_HV4"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv5) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH2_HV5"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH2_HV5"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH2_HV5"), hmpid.nPhotons()); + } + } + + ////////////////////////////////////////////////////////////////// + // fill plot photocathode + if (distanceCondition && mipChargeCondition && physicalChAngle) // condizione da verificare a priori + { + if (hmpid.xMip() >= xMinPc[0] && hmpid.xMip() <= xMaxPc[0] && hmpid.yMip() >= yMinPc[0] && hmpid.yMip() <= yMaxPc[0]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH2_PC0"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[1] && hmpid.xMip() <= xMaxPc[1] && hmpid.yMip() >= yMinPc[1] && hmpid.yMip() <= yMaxPc[1]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH2_PC1"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[2] && hmpid.xMip() <= xMaxPc[2] && hmpid.yMip() >= yMinPc[2] && hmpid.yMip() <= yMaxPc[2]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH2_PC2"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[3] && hmpid.xMip() <= xMaxPc[3] && hmpid.yMip() >= yMinPc[3] && hmpid.yMip() <= yMaxPc[3]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH2_PC3"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[4] && hmpid.xMip() <= xMaxPc[4] && hmpid.yMip() >= yMinPc[4] && hmpid.yMip() <= yMaxPc[4]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH2_PC4"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[5] && hmpid.xMip() <= xMaxPc[5] && hmpid.yMip() >= yMinPc[5] && hmpid.yMip() <= yMaxPc[5]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH2_PC5"), sin2changle, hmpid.nPhotons()); + } + } + } + + if (hmpid.chamber() == rich3) { + histos.fill(HIST("hmpidXTrack3"), hmpid.xTrack()); + histos.fill(HIST("hmpidYTrack3"), hmpid.yTrack()); + histos.fill(HIST("hmpidXMip3"), hmpid.xMip()); + histos.fill(HIST("hmpidYMip3"), hmpid.yMip()); + histos.fill(HIST("hmpidXResiduals3"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResiduals3"), hmpid.yMip() - hmpid.yTrack()); + + if (hmpid.momentumTrack() > cutMinMomGlobalTrack) { + if (hmpid.momentumHmpid() > 0) { + // fill residual histos for positive charges + histos.fill(HIST("hmpidXResidualsPos3"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsPos3"), hmpid.yMip() - hmpid.yTrack()); + } + + if (hmpid.momentumHmpid() < 0) { + // fill residual histos for negative charges + histos.fill(HIST("hmpidXResidualsNeg3"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsNeg3"), hmpid.yMip() - hmpid.yTrack()); + } + } + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip3"), hmpid.chargeMip()); + } + histos.fill(HIST("hmpidClusSize3"), hmpid.clusterSize()); + histos.fill(HIST("TrackMom3"), hmpid.momentumTrack()); + histos.fill(HIST("hmpidMom3"), std::fabs(hmpid.momentumHmpid())); + histos.fill(HIST("hmpidXYMip3"), hmpid.xMip(), hmpid.yMip()); + + if (distanceCondition && mipChargeCondition) { + histos.fill(HIST("hmpidNPhotons3"), hmpid.nPhotons()); + sin2changle = static_cast(TMath::Power(TMath::Sin(hmpid.chAngle()), 2)); + if (hmpid.xMip() <= maxBoxHit && hmpid.xMip() >= minBoxHit && hmpid.yMip() <= maxBoxHit && hmpid.yMip() >= minBoxHit) { + histos.fill(HIST("nPhotons_vs_sin2Ch3"), sin2changle, hmpid.nPhotons()); + } + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge3"), hmpid.photonsCharge()[i]); + } + } + } + + // plot per HV sector + if (fParam->inHVSector(hmpid.yMip()) == hv0) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH3_HV0"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH3_HV0"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH3_HV0"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv1) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH3_HV1"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH3_HV1"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH3_HV1"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv2) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH3_HV2"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH3_HV2"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH3_HV2"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv3) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH3_HV3"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH3_HV3"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH3_HV3"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv4) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH3_HV4"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH3_HV4"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH3_HV4"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv5) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH3_HV5"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH3_HV5"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH3_HV5"), hmpid.nPhotons()); + } + } + + ////////////////////////////////////////////////////////////////// + // fill plot photocathode + if (distanceCondition && mipChargeCondition && physicalChAngle) // condizione da verificare a priori + { + if (hmpid.xMip() >= xMinPc[0] && hmpid.xMip() <= xMaxPc[0] && hmpid.yMip() >= yMinPc[0] && hmpid.yMip() <= yMaxPc[0]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH3_PC0"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[1] && hmpid.xMip() <= xMaxPc[1] && hmpid.yMip() >= yMinPc[1] && hmpid.yMip() <= yMaxPc[1]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH3_PC1"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[2] && hmpid.xMip() <= xMaxPc[2] && hmpid.yMip() >= yMinPc[2] && hmpid.yMip() <= yMaxPc[2]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH3_PC2"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[3] && hmpid.xMip() <= xMaxPc[3] && hmpid.yMip() >= yMinPc[3] && hmpid.yMip() <= yMaxPc[3]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH3_PC3"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[4] && hmpid.xMip() <= xMaxPc[4] && hmpid.yMip() >= yMinPc[4] && hmpid.yMip() <= yMaxPc[4]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH3_PC4"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[5] && hmpid.xMip() <= xMaxPc[5] && hmpid.yMip() >= yMinPc[5] && hmpid.yMip() <= yMaxPc[5]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH3_PC5"), sin2changle, hmpid.nPhotons()); + } + } + } + + if (hmpid.chamber() == rich4) { + histos.fill(HIST("hmpidXTrack4"), hmpid.xTrack()); + histos.fill(HIST("hmpidYTrack4"), hmpid.yTrack()); + histos.fill(HIST("hmpidXMip4"), hmpid.xMip()); + histos.fill(HIST("hmpidYMip4"), hmpid.yMip()); + histos.fill(HIST("hmpidXResiduals4"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResiduals4"), hmpid.yMip() - hmpid.yTrack()); + + if (hmpid.momentumTrack() > cutMinMomGlobalTrack) { + if (hmpid.momentumHmpid() > 0) { + // fill residual histos for positive charges + histos.fill(HIST("hmpidXResidualsPos4"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsPos4"), hmpid.yMip() - hmpid.yTrack()); + } + + if (hmpid.momentumHmpid() < 0) { + // fill residual histos for negative charges + histos.fill(HIST("hmpidXResidualsNeg4"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsNeg4"), hmpid.yMip() - hmpid.yTrack()); + } + } + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip4"), hmpid.chargeMip()); + } + histos.fill(HIST("hmpidClusSize4"), hmpid.clusterSize()); + histos.fill(HIST("TrackMom4"), hmpid.momentumTrack()); + histos.fill(HIST("hmpidMom4"), std::fabs(hmpid.momentumHmpid())); + histos.fill(HIST("hmpidXYMip4"), hmpid.xMip(), hmpid.yMip()); + + if (distanceCondition && mipChargeCondition) { + histos.fill(HIST("hmpidNPhotons4"), hmpid.nPhotons()); + sin2changle = static_cast(TMath::Power(TMath::Sin(hmpid.chAngle()), 2)); + if (hmpid.xMip() <= maxBoxHit && hmpid.xMip() >= minBoxHit && hmpid.yMip() <= maxBoxHit && hmpid.yMip() >= minBoxHit) { + histos.fill(HIST("nPhotons_vs_sin2Ch4"), sin2changle, hmpid.nPhotons()); + } + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge4"), hmpid.photonsCharge()[i]); + } + } + + // plot per HV sector + if (fParam->inHVSector(hmpid.yMip()) == hv0) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH4_HV0"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH4_HV0"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH4_HV0"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv1) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH4_HV1"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH4_HV1"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH4_HV1"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv2) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH4_HV2"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH4_HV2"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH4_HV2"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv3) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH4_HV3"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH4_HV3"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH4_HV3"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv4) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH4_HV4"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH4_HV4"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH4_HV4"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv5) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH4_HV5"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH4_HV5"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH4_HV5"), hmpid.nPhotons()); + } + } + + ////////////////////////////////////////////////////////////////// + // fill plot photocathode + if (distanceCondition && mipChargeCondition && physicalChAngle) // condizione da verificare a priori + { + if (hmpid.xMip() >= xMinPc[0] && hmpid.xMip() <= xMaxPc[0] && hmpid.yMip() >= yMinPc[0] && hmpid.yMip() <= yMaxPc[0]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH4_PC0"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[1] && hmpid.xMip() <= xMaxPc[1] && hmpid.yMip() >= yMinPc[1] && hmpid.yMip() <= yMaxPc[1]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH4_PC1"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[2] && hmpid.xMip() <= xMaxPc[2] && hmpid.yMip() >= yMinPc[2] && hmpid.yMip() <= yMaxPc[2]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH4_PC2"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[3] && hmpid.xMip() <= xMaxPc[3] && hmpid.yMip() >= yMinPc[3] && hmpid.yMip() <= yMaxPc[3]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH4_PC3"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[4] && hmpid.xMip() <= xMaxPc[4] && hmpid.yMip() >= yMinPc[4] && hmpid.yMip() <= yMaxPc[4]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH4_PC4"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[5] && hmpid.xMip() <= xMaxPc[5] && hmpid.yMip() >= yMinPc[5] && hmpid.yMip() <= yMaxPc[5]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH4_PC5"), sin2changle, hmpid.nPhotons()); + } + } + } + + if (hmpid.chamber() == rich5) { + histos.fill(HIST("hmpidXTrack5"), hmpid.xTrack()); + histos.fill(HIST("hmpidYTrack5"), hmpid.yTrack()); + histos.fill(HIST("hmpidXMip5"), hmpid.xMip()); + histos.fill(HIST("hmpidYMip5"), hmpid.yMip()); + histos.fill(HIST("hmpidXResiduals5"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResiduals5"), hmpid.yMip() - hmpid.yTrack()); + + if (hmpid.momentumTrack() > cutMinMomGlobalTrack) { + if (hmpid.momentumHmpid() > 0) { + // fill residual histos for positive charges + histos.fill(HIST("hmpidXResidualsPos5"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsPos5"), hmpid.yMip() - hmpid.yTrack()); + } + + if (hmpid.momentumHmpid() < 0) { + // fill residual histos for negative charges + histos.fill(HIST("hmpidXResidualsNeg5"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsNeg5"), hmpid.yMip() - hmpid.yTrack()); + } + } + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip5"), hmpid.chargeMip()); + } + histos.fill(HIST("hmpidClusSize5"), hmpid.clusterSize()); + histos.fill(HIST("TrackMom5"), hmpid.momentumTrack()); + histos.fill(HIST("hmpidMom5"), std::fabs(hmpid.momentumHmpid())); + histos.fill(HIST("hmpidXYMip5"), hmpid.xMip(), hmpid.yMip()); + + if (distanceCondition && mipChargeCondition) { + histos.fill(HIST("hmpidNPhotons5"), hmpid.nPhotons()); + sin2changle = static_cast(TMath::Power(TMath::Sin(hmpid.chAngle()), 2)); + if (hmpid.xMip() <= maxBoxHit && hmpid.xMip() >= minBoxHit && hmpid.yMip() <= maxBoxHit && hmpid.yMip() >= minBoxHit) { + histos.fill(HIST("nPhotons_vs_sin2Ch5"), sin2changle, hmpid.nPhotons()); + } + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge5"), hmpid.photonsCharge()[i]); + } + } + + // plot per HV sector + if (fParam->inHVSector(hmpid.yMip()) == hv0) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH5_HV0"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH5_HV0"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH5_HV0"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv1) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH5_HV1"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH5_HV1"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH5_HV1"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv2) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH5_HV2"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH5_HV2"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH5_HV2"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv3) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH5_HV3"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH5_HV3"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH5_HV3"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv4) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH5_HV4"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH5_HV4"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH5_HV4"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv5) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH5_HV5"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH5_HV5"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH5_HV5"), hmpid.nPhotons()); + } + } + + ////////////////////////////////////////////////////////////////// + // fill plot photocathode + if (distanceCondition && mipChargeCondition && physicalChAngle) // condizione da verificare a priori + { + if (hmpid.xMip() >= xMinPc[0] && hmpid.xMip() <= xMaxPc[0] && hmpid.yMip() >= yMinPc[0] && hmpid.yMip() <= yMaxPc[0]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH5_PC0"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[1] && hmpid.xMip() <= xMaxPc[1] && hmpid.yMip() >= yMinPc[1] && hmpid.yMip() <= yMaxPc[1]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH5_PC1"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[2] && hmpid.xMip() <= xMaxPc[2] && hmpid.yMip() >= yMinPc[2] && hmpid.yMip() <= yMaxPc[2]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH5_PC2"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[3] && hmpid.xMip() <= xMaxPc[3] && hmpid.yMip() >= yMinPc[3] && hmpid.yMip() <= yMaxPc[3]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH5_PC3"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[4] && hmpid.xMip() <= xMaxPc[4] && hmpid.yMip() >= yMinPc[4] && hmpid.yMip() <= yMaxPc[4]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH5_PC4"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[5] && hmpid.xMip() <= xMaxPc[5] && hmpid.yMip() >= yMinPc[5] && hmpid.yMip() <= yMaxPc[5]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH5_PC5"), sin2changle, hmpid.nPhotons()); + } + } + } + + if (hmpid.chamber() == rich6) { + histos.fill(HIST("hmpidXTrack6"), hmpid.xTrack()); + histos.fill(HIST("hmpidYTrack6"), hmpid.yTrack()); + histos.fill(HIST("hmpidXMip6"), hmpid.xMip()); + histos.fill(HIST("hmpidYMip6"), hmpid.yMip()); + histos.fill(HIST("hmpidXResiduals6"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResiduals6"), hmpid.yMip() - hmpid.yTrack()); + + if (hmpid.momentumTrack() > cutMinMomGlobalTrack) { + if (hmpid.momentumHmpid() > 0) { + // fill residual histos for positive charges + histos.fill(HIST("hmpidXResidualsPos6"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsPos6"), hmpid.yMip() - hmpid.yTrack()); + } + + if (hmpid.momentumHmpid() < 0) { + // fill residual histos for negative charges + histos.fill(HIST("hmpidXResidualsNeg6"), hmpid.xMip() - hmpid.xTrack()); + histos.fill(HIST("hmpidYResidualsNeg6"), hmpid.yMip() - hmpid.yTrack()); + } + } + + if (distanceCondition) { + histos.fill(HIST("hmpidQMip6"), hmpid.chargeMip()); + } + histos.fill(HIST("hmpidClusSize6"), hmpid.clusterSize()); + histos.fill(HIST("TrackMom6"), hmpid.momentumTrack()); + histos.fill(HIST("hmpidMom6"), std::fabs(hmpid.momentumHmpid())); + histos.fill(HIST("hmpidXYMip6"), hmpid.xMip(), hmpid.yMip()); + + if (distanceCondition && mipChargeCondition) { + histos.fill(HIST("hmpidNPhotons6"), hmpid.nPhotons()); + sin2changle = static_cast(TMath::Power(TMath::Sin(hmpid.chAngle()), 2)); + if (hmpid.xMip() <= maxBoxHit && hmpid.xMip() >= minBoxHit && hmpid.yMip() <= maxBoxHit && hmpid.yMip() >= minBoxHit) { + histos.fill(HIST("nPhotons_vs_sin2Ch6"), sin2changle, hmpid.nPhotons()); + } + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) + histos.fill(HIST("hmpidPhotsCharge6"), hmpid.photonsCharge()[i]); + } + } + + // plot per HV sector + if (fParam->inHVSector(hmpid.yMip()) == hv0) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH6_HV0"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH6_HV0"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH6_HV0"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv1) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH6_HV1"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH6_HV1"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH6_HV1"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv2) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH6_HV2"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH6_HV2"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH6_HV2"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv3) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH6_HV3"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH6_HV3"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH6_HV3"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv4) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH6_HV4"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH6_HV4"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH6_HV4"), hmpid.nPhotons()); + } + } + + if (fParam->inHVSector(hmpid.yMip()) == hv5) { + if (distanceCondition) { + histos.fill(HIST("hmpidQMip_RICH6_HV5"), hmpid.chargeMip()); + } + if (distanceCondition && mipChargeCondition && physicalChAngle) { + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + if (hmpid.photonsCharge()[i] > 0) { + histos.fill(HIST("hmpidPhotsCharge_RICH6_HV5"), hmpid.photonsCharge()[i]); + } + } + histos.fill(HIST("hmpidNPhotons_RICH6_HV5"), hmpid.nPhotons()); + } + } + + ////////////////////////////////////////////////////////////////// + // fill plot photocathode + if (distanceCondition && mipChargeCondition && physicalChAngle) // condizione da verificare a priori + { + if (hmpid.xMip() >= xMinPc[0] && hmpid.xMip() <= xMaxPc[0] && hmpid.yMip() >= yMinPc[0] && hmpid.yMip() <= yMaxPc[0]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH6_PC0"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[1] && hmpid.xMip() <= xMaxPc[1] && hmpid.yMip() >= yMinPc[1] && hmpid.yMip() <= yMaxPc[1]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH6_PC1"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[2] && hmpid.xMip() <= xMaxPc[2] && hmpid.yMip() >= yMinPc[2] && hmpid.yMip() <= yMaxPc[2]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH6_PC2"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[3] && hmpid.xMip() <= xMaxPc[3] && hmpid.yMip() >= yMinPc[3] && hmpid.yMip() <= yMaxPc[3]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH6_PC3"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[4] && hmpid.xMip() <= xMaxPc[4] && hmpid.yMip() >= yMinPc[4] && hmpid.yMip() <= yMaxPc[4]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH6_PC4"), sin2changle, hmpid.nPhotons()); + } + + if (hmpid.xMip() >= xMinPc[5] && hmpid.xMip() <= xMaxPc[5] && hmpid.yMip() >= yMinPc[5] && hmpid.yMip() <= yMaxPc[5]) { + histos.fill(HIST("nPhotons_vs_sin2Ch_RICH6_PC5"), sin2changle, hmpid.nPhotons()); + } + } + } + + double probsHMP[3]; + + getProbability(hmpid.chAngle(), std::fabs(hmpid.momentumHmpid()), probsHMP); + + if (distanceMipToTrack > maxDistanceForProb || hmpid.chargeMip() < cutQmip) + continue; + + histos.fill(HIST("hmpidCkovvsMom_nocut"), std::fabs(hmpid.momentumHmpid()), hmpid.chAngle()); + + if (probsHMP[0] < minProbParticle && probsHMP[1] < minProbParticle && probsHMP[2] < minProbParticle) + continue; + // if(hmpid.momentumTrack()<0.75 && hmpid.nPhotons()<7 && hmpid.chAngle()<0.52) continue; + + histos.fill(HIST("hmpidCkovvsMom"), std::fabs(hmpid.momentumHmpid()), hmpid.chAngle()); + + } // close loop on tracks + + } // close process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) { return WorkflowSpec{adaptAnalysisTask(cfg)}; } diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx new file mode 100644 index 00000000000..76267171742 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.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. + +#include "tableHMPID.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct HmpidTableProducer { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + const AxisSpec axisEvtCounter{1, 0, +1, ""}; + + // CCDB configurable + Service ccdb; + struct : ConfigurableGroup { + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; + } ccdbConfig; + + Produces hmpidAnalysis; + + // using TrackCandidates = soa::Join; + + using CollisionCandidates = o2::soa::Join; + + using TrackCandidates = soa::Join; + + // using CentralityClass = o2::soa::Join; + + void init(o2::framework::InitContext&) + { + // Configure CCDB + ccdb->setURL(ccdbConfig.ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + histos.add("eventCounter", "eventCounter", kTH1F, {axisEvtCounter}); + } + + // function to manage ccdb + int mCCDBRunNumber = 0; + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mCCDBRunNumber == bc.runNumber()) { + return; + } + mCCDBRunNumber = bc.runNumber(); + } + + void process(soa::Join::iterator const& col, + const aod::HMPIDs& hmpids, + TrackCandidates const&, + aod::BCsWithTimestamps const&) + { + histos.fill(HIST("eventCounter"), 0.5); + + initCCDB(col.bc_as()); + + for (const auto& t : hmpids) { + + // global tracks associated to hmpid tracks + const auto& globalTrack = t.track_as(); + if (!globalTrack.isGlobalTrack()) + continue; + if (!globalTrack.hasITS() || !globalTrack.hasTPC() || !globalTrack.hasTOF()) + continue; + + // verify accessible collision + if (!globalTrack.has_collision()) { + continue; + } + + float hmpidPhotsCharge2[o2::aod::kDimPhotonsCharge]; + + for (int i = 0; i < o2::aod::kDimPhotonsCharge; i++) { + hmpidPhotsCharge2[i] = t.hmpidPhotsCharge()[i]; + } + + float centrality = col.centFV0A(); + + /////FILL TABLE + hmpidAnalysis( + t.hmpidSignal(), globalTrack.phi(), globalTrack.eta(), t.hmpidMom(), + globalTrack.p(), t.hmpidXTrack(), t.hmpidYTrack(), t.hmpidXMip(), + t.hmpidYMip(), t.hmpidNPhotons(), t.hmpidQMip(), (t.hmpidClusSize() % 1000000) / 1000, + t.hmpidClusSize() / 1000000, hmpidPhotsCharge2, globalTrack.eta(), globalTrack.phi(), + globalTrack.px(), globalTrack.py(), globalTrack.pz(), globalTrack.itsNCls(), + globalTrack.tpcNClsFound(), globalTrack.tpcNClsCrossedRows(), globalTrack.tpcChi2NCl(), globalTrack.itsChi2NCl(), + globalTrack.dcaXY(), globalTrack.dcaZ(), globalTrack.tpcNSigmaPi(), globalTrack.tofNSigmaPi(), + globalTrack.tpcNSigmaKa(), globalTrack.tofNSigmaKa(), globalTrack.tpcNSigmaPr(), globalTrack.tofNSigmaPr(), + globalTrack.tpcNSigmaDe(), globalTrack.tofNSigmaDe(), centrality); + } + } +}; + +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 deleted file mode 100644 index 9848784bbda..00000000000 --- a/DPG/Tasks/AOTTrack/PID/HMPID/qaHMPID.cxx +++ /dev/null @@ -1,307 +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/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(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); - -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; - } - - 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, - *t.hmpidPhotsCharge(), 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(), abs(t.hmpidMom())); - histos.fill(HIST("hmpidCkovvsMom"), 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"), 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"), 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"), 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"), 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"), 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"), 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"), 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"), 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/HMPID/tableHMPID.h b/DPG/Tasks/AOTTrack/PID/HMPID/tableHMPID.h new file mode 100644 index 00000000000..045282d3e0e --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/HMPID/tableHMPID.h @@ -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. + +#ifndef DPG_TASKS_AOTTRACK_PID_HMPID_TABLEHMPID_H_ +#define DPG_TASKS_AOTTRACK_PID_HMPID_TABLEHMPID_H_ + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ + +inline constexpr int kDimPhotonsCharge = 10; + +namespace variables_table +{ +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(PhotonsCharge, photonsCharge, float[kDimPhotonsCharge]); + +DECLARE_SOA_COLUMN(EtaTrack, etaTrack, float); +DECLARE_SOA_COLUMN(PhiTrack, phiTrack, float); +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, 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); + +DECLARE_SOA_COLUMN(Centrality, centrality, float); + +} // namespace variables_table + +DECLARE_SOA_TABLE(HmpidAnalysis, "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::PhotonsCharge, + variables_table::EtaTrack, + variables_table::PhiTrack, + variables_table::Px, + variables_table::Py, + variables_table::Pz, + 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, + variables_table::Centrality); + +} // namespace o2::aod + +#endif // DPG_TASKS_AOTTRACK_PID_HMPID_TABLEHMPID_H_ diff --git a/ALICE3/Tools/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/ITS/CMakeLists.txt similarity index 70% rename from ALICE3/Tools/CMakeLists.txt rename to DPG/Tasks/AOTTrack/PID/ITS/CMakeLists.txt index 7aecd79362b..1550742c0f4 100644 --- a/ALICE3/Tools/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/PID/ITS/CMakeLists.txt @@ -9,7 +9,8 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -o2physics_add_executable(pidparam-tof-reso-alice3 - SOURCES handleParamTOFResoALICE3.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::ALICE3Core - ) +# 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..8b74a7beb77 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/ITS/qaPIDITS.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. +/// +/// \file qaPIDITS.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Implementation for QA tasks of the ITS PID quantities +/// + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +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& context) + { + o2::aod::ITSResponse::setParameters(context); + 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 index f4f799d4f5b..87af80a68dd 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt @@ -20,6 +20,11 @@ o2physics_add_dpl_workflow(pid-tof-qa-beta PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(pid-tof-qa-beta-imp + SOURCES qaPIDTOFBetaImp.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(pid-tof-qa-mc SOURCES qaPIDTOFMC.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx index 8c1aeca6483..95f9016d388 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx @@ -15,16 +15,17 @@ /// \brief Implementation for QA tasks of the TOF PID quantities /// -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/TableProducer/PID/pidTOFBase.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -135,8 +136,10 @@ struct tofPidQa { Configurable ptDeltaTEtaPhiMapMin{"ptDeltaTEtaPhiMapMin", 1.45f, "Threshold in pT to build the map of the delta time as a function of eta and phi"}; Configurable ptDeltaTEtaPhiMapMax{"ptDeltaTEtaPhiMapMax", 1.55f, "Threshold in pT to build the map of the delta time as a function of eta and phi"}; 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 enableVsMomentumHistograms{"enableVsMomentumHistograms", 0, "1: Enables plots vs momentum instead of just pT 2: Enables plots vs momentum vs eta 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, @@ -236,11 +239,16 @@ struct tofPidQa { return; } - if (enableVsMomentumHistograms) { + if (enableVsMomentumHistograms == 1) { histos.add(hdelta_evtime_fill[id].data(), axisTitle, kTH2F, {pAxis, deltaAxis}); histos.add(hdelta_evtime_tof[id].data(), axisTitle, kTH2F, {pAxis, deltaAxis}); histos.add(hdelta_evtime_ft0[id].data(), axisTitle, kTH2F, {pAxis, deltaAxis}); histos.add(hdelta_evtime_tofft0[id].data(), axisTitle, kTH2F, {pAxis, deltaAxis}); + } else if (enableVsMomentumHistograms == 2) { + histos.add(hdelta_evtime_fill[id].data(), axisTitle, kTH3F, {pAxis, etaAxis, deltaAxis}); + histos.add(hdelta_evtime_tof[id].data(), axisTitle, kTH3F, {pAxis, etaAxis, deltaAxis}); + histos.add(hdelta_evtime_ft0[id].data(), axisTitle, kTH3F, {pAxis, etaAxis, deltaAxis}); + histos.add(hdelta_evtime_tofft0[id].data(), axisTitle, kTH3F, {pAxis, etaAxis, deltaAxis}); } if (splitSignalPerCharge) { @@ -260,6 +268,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 +291,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 +302,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 +387,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 +537,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; } } @@ -572,8 +604,10 @@ struct tofPidQa { // Filling info split per ev. time if (enableEvTimeSplitting) { if (t.isEvTimeTOF() && t.isEvTimeT0AC()) { // TOF + FT0 Ev. Time - if (enableVsMomentumHistograms) { + if (enableVsMomentumHistograms == 1) { histos.fill(HIST(hdelta_evtime_tofft0[id]), t.p(), diff); + } else if (enableVsMomentumHistograms == 2) { + histos.fill(HIST(hdelta_evtime_tofft0[id]), t.p(), t.eta(), diff); } if (splitSignalPerCharge) { histos.fill(HIST(hdelta_pt_evtime_tofft0[id]), t.pt(), diff, t.sign()); @@ -581,8 +615,10 @@ struct tofPidQa { histos.fill(HIST(hdelta_pt_evtime_tofft0[id]), t.pt(), diff); } } else if (t.isEvTimeT0AC()) { // FT0 Ev. Time - if (enableVsMomentumHistograms) { + if (enableVsMomentumHistograms == 1) { histos.fill(HIST(hdelta_evtime_ft0[id]), t.p(), diff); + } else if (enableVsMomentumHistograms == 2) { + histos.fill(HIST(hdelta_evtime_ft0[id]), t.p(), t.eta(), diff); } if (splitSignalPerCharge) { histos.fill(HIST(hdelta_pt_evtime_ft0[id]), t.pt(), diff, t.sign()); @@ -590,8 +626,10 @@ struct tofPidQa { histos.fill(HIST(hdelta_pt_evtime_ft0[id]), t.pt(), diff); } } else if (t.isEvTimeTOF()) { // TOF Ev. Time - if (enableVsMomentumHistograms) { + if (enableVsMomentumHistograms == 1) { histos.fill(HIST(hdelta_evtime_tof[id]), t.p(), diff); + } else if (enableVsMomentumHistograms == 2) { + histos.fill(HIST(hdelta_evtime_tof[id]), t.p(), t.eta(), diff); } if (splitSignalPerCharge) { histos.fill(HIST(hdelta_pt_evtime_tof[id]), t.pt(), diff, t.sign()); @@ -599,8 +637,10 @@ struct tofPidQa { histos.fill(HIST(hdelta_pt_evtime_tof[id]), t.pt(), diff); } } else { // No Ev. Time -> Fill Ev. Time - if (enableVsMomentumHistograms) { + if (enableVsMomentumHistograms == 1) { histos.fill(HIST(hdelta_evtime_fill[id]), t.p(), diff); + } else if (enableVsMomentumHistograms == 2) { + histos.fill(HIST(hdelta_evtime_fill[id]), t.p(), t.eta(), diff); } if (splitSignalPerCharge) { histos.fill(HIST(hdelta_pt_evtime_fill[id]), t.pt(), diff, t.sign()); diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBeta.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBeta.cxx index a550dfbd120..a1461cb0509 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBeta.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBeta.cxx @@ -15,16 +15,17 @@ /// \brief Task to produce the TOF QA plots for Beta /// -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/TableProducer/PID/pidTOFBase.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -48,6 +49,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 +64,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 +129,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 +196,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 +208,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 +248,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 +331,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 +389,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 +416,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/qaPIDTOFBetaImp.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBetaImp.cxx new file mode 100644 index 00000000000..4fe9551d434 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBetaImp.cxx @@ -0,0 +1,427 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file qaPIDTOFBetaImp.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Task to produce the TOF QA plots for Beta. Version using dynamic columns. Interim solution for test and benchmarking +/// + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Task to produce the TOF Beta QA plots +struct tofPidBetaQaImp { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable logAxis{"logAxis", 0, "Flag to use a log momentum axis"}; + Configurable nBinsP{"nBinsP", 400, "Number of bins for the momentum"}; + Configurable minP{"minP", 0.1f, "Minimum momentum in range"}; + Configurable maxP{"maxP", 5.f, "Maximum momentum in range"}; + Configurable applyEvSel{"applyEvSel", 2, "Flag to apply event selection cut: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; + Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable splitTrdTracks{"splitTrdTracks", false, "Flag to fill histograms for tracks with TRD match"}; + Configurable splitSignalPerCharge{"splitSignalPerCharge", true, "Split the signal per charge (reduces memory footprint if off)"}; + Configurable splitSignalPerEvTime{"splitSignalPerEvTime", true, "Split the signal per event time (reduces memory footprint if off)"}; + Configurable lastTrdLayerForTrdMatch{"lastTrdLayerForTrdMatch", 5, "Last TRD layer to consider for TRD match"}; + + ConfigurableAxis tofMassBins{"tofMassBins", {1000, 0, 3.f}, "Binning in the TOF mass plot"}; + ConfigurableAxis tofBetaBins{"tofBetaBins", {4000, 0, 2.f}, "Binning in the TOF beta plot"}; + ConfigurableAxis trackLengthBins{"trackLengthBins", {100, 0, 1000.f}, "Binning in track length plot"}; + Configurable requireGoodMatchTracks{"requireGoodMatchTracks", false, "Require good match tracks"}; + Configurable mMaxTOFChi2{"maxTOFChi2", 3.f, "Maximum TOF Chi2"}; + Configurable mEtaWindow{"etaWindow", 0.8f, "Window in eta for tracks"}; + + void init(o2::framework::InitContext&) + { + const AxisSpec vtxZAxis{100, -20, 20, "Vtx_{z} (cm)"}; + const AxisSpec tofAxis{10000, 0, 2e6, "TOF Signal"}; + const AxisSpec betaAxis{tofBetaBins, "TOF #beta"}; + const AxisSpec massAxis{tofMassBins, "TOF mass (GeV/#it{c}^{2})"}; + const AxisSpec trdAxis{10, -0.5, 9.5, "Last TRD cluster"}; + const AxisSpec etaAxis{100, -2, 2, "#it{#eta}"}; + const AxisSpec colTimeAxis{100, -2000, 2000, "Collision time (ps)"}; + const AxisSpec lAxis{trackLengthBins, "Track length (cm)"}; + const AxisSpec tofChi2Axis{1000, 0, 20, "TOF residual (cm)"}; + const AxisSpec ptResoAxis{100, 0, 0.1, "#sigma_{#it{p}_{T}}"}; + const AxisSpec pAxisPosNeg{2 * nBinsP, -maxP, maxP, "signed #it{p} (GeV/#it{c})"}; + AxisSpec ptAxis{nBinsP, minP, maxP, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pAxis{nBinsP, minP, maxP, "#it{p} (GeV/#it{c})"}; + if (logAxis) { + ptAxis.makeLogarithmic(); + pAxis.makeLogarithmic(); + } + + // Event properties + histos.add("event/tofsignal", "", HistType::kTH2F, {pAxis, tofAxis}); + const AxisSpec chargeAxis{2, -2.f, 2.f, "Charge"}; + + // TOF mass + if (splitSignalPerCharge) { + histos.add("tofmass/inclusive", "", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/EvTimeTOF", "Ev. Time TOF", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + } + if (splitTrdTracks) { + histos.add("tofmass/trd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + } + histos.add("tofmass/notrd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + } + } + } else { + histos.add("tofmass/inclusive", "", HistType::kTH2F, {pAxis, massAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxis, massAxis}); + } + if (splitTrdTracks) { + histos.add("tofmass/trd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + } + histos.add("tofmass/notrd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + } + } + } + + // TOF beta + if (splitSignalPerCharge) { + histos.add("tofbeta/inclusive", "", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + } + if (splitTrdTracks) { + histos.add("tofbeta/trd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + } + histos.add("tofbeta/notrd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + } + } + } else { + histos.add("tofbeta/inclusive", "", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + } + if (splitTrdTracks) { + histos.add("tofbeta/trd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + } + histos.add("tofbeta/notrd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + } + } + } + + histos.add("event/tofchi2", "", HistType::kTH1F, {tofChi2Axis}); + histos.add("event/eta", "", HistType::kTH1F, {etaAxis}); + histos.add("event/length", "", HistType::kTH1F, {lAxis}); + if (splitTrdTracks) { + histos.add("event/trd/length", "", HistType::kTH2F, {lAxis, trdAxis}); + histos.add("event/notrd/length", "", HistType::kTH1F, {lAxis}); + } + histos.add("event/pt", "", HistType::kTH1F, {ptAxis}); + histos.add("event/p", "", HistType::kTH1F, {pAxis}); + auto h = histos.add("event/evsel", "", kTH1F, {{10, 0.5, 10.5, "Ev. Sel."}}); + h->GetXaxis()->SetBinLabel(1, "Events read"); + h->GetXaxis()->SetBinLabel(2, "Passed ev. sel."); + h->GetXaxis()->SetBinLabel(3, "Passed vtx Z"); + + h = histos.add("event/trackselection", "", kTH1F, {{10, 0.5, 10.5, "Selection passed"}}); + h->GetXaxis()->SetBinLabel(1, "Tracks read"); + h->GetXaxis()->SetBinLabel(2, "hasTOF"); + h->GetXaxis()->SetBinLabel(3, "isGlobalTrack"); + h->GetXaxis()->SetBinLabel(4, TString::Format("TOF chi2 < %.2f", mMaxTOFChi2.value)); + } + + Filter eventFilter = (applyEvSel.node() == 0) || + ((applyEvSel.node() == 1) && (o2::aod::evsel::sel7 == true)) || + ((applyEvSel.node() == 2) && (o2::aod::evsel::sel8 == true)); + Filter trackFilter = (trackSelection.node() == 0) || + ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || + ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || + ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || + ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || + ((trackSelection.node() == 5) && requireInAcceptanceTracksInFilter()); + Filter etaFilter = (nabs(o2::aod::track::eta) < mEtaWindow); + + using CollisionCandidate = soa::Filtered>::iterator; + using TrackCandidates = soa::Join; + void process(CollisionCandidate const& collision, + soa::Filtered const& tracks) + { + + auto tracksWithPid = soa::Attach, aod::TOFMass, aod::TOFBeta>(tracks); + histos.fill(HIST("event/evsel"), 1); + if (applyEvSel == 1) { + if (!collision.sel7()) { + return; + } + } else if (applyEvSel == 2) { + if (!collision.sel8()) { + return; + } + } + + histos.fill(HIST("event/evsel"), 2); + + if (std::abs(collision.posZ()) > 10.f) { + return; + } + + histos.fill(HIST("event/evsel"), 3); + for (auto const& t : tracks) { + auto track = tracksWithPid.iteratorAt(t.globalIndex() - tracksWithPid.iteratorAt(0).globalIndex()); + // Check consistency + if (track.hasTOF() != t.hasTOF()) { + LOG(fatal) << "Mismatch in TOF availability!"; + } + if (track.pt() != t.pt()) { + LOG(fatal) << "Mismatch in pt!"; + } + histos.fill(HIST("event/trackselection"), 1.f); + if (!track.hasTOF()) { // Skipping tracks without TOF + continue; + } + histos.fill(HIST("event/trackselection"), 2.f); + if (!track.isGlobalTrack()) { + continue; + } + histos.fill(HIST("event/trackselection"), 3.f); + if (track.tofChi2() > mMaxTOFChi2) { // Skipping tracks with large Chi2 + continue; + } + histos.fill(HIST("event/trackselection"), 4.f); + const float tofMass = track.tofMass(); + const float tofBeta = track.tofBeta(); + if (splitSignalPerCharge) { + histos.fill(HIST("tofmass/inclusive"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/inclusive"), track.p(), tofBeta, track.sign()); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/EvTimeTOF"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/EvTimeTOF"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/EvTimeTOFOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/EvTimeTOFOnly"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/EvTimeT0AC"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/EvTimeT0AC"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/EvTimeT0ACOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/EvTimeT0ACOnly"), track.p(), tofBeta, track.sign()); + } + } + } else { + histos.fill(HIST("tofmass/inclusive"), track.p(), tofMass); + histos.fill(HIST("tofbeta/inclusive"), track.p(), tofBeta); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/EvTimeTOF"), track.p(), tofMass); + histos.fill(HIST("tofbeta/EvTimeTOF"), track.p(), tofBeta); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/EvTimeTOFOnly"), track.p(), tofMass); + histos.fill(HIST("tofbeta/EvTimeTOFOnly"), track.p(), tofBeta); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/EvTimeT0AC"), track.p(), tofMass); + histos.fill(HIST("tofbeta/EvTimeT0AC"), track.p(), tofBeta); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/EvTimeT0ACOnly"), track.p(), tofMass); + histos.fill(HIST("tofbeta/EvTimeT0ACOnly"), track.p(), tofBeta); + } + } + } + histos.fill(HIST("event/length"), track.length()); + histos.fill(HIST("event/tofchi2"), track.tofChi2()); + histos.fill(HIST("event/eta"), track.eta()); + histos.fill(HIST("event/tofsignal"), track.p(), track.tofSignal()); + histos.fill(HIST("event/pt"), track.pt()); + histos.fill(HIST("event/p"), track.p()); + + if (!splitTrdTracks) { // If splitting of TRD tracks is not enabled, skip + continue; + } + + if (!track.hasTRD()) { + histos.fill(HIST("event/notrd/length"), track.length()); + if (splitSignalPerCharge) { + histos.fill(HIST("tofmass/notrd/inclusive"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/inclusive"), track.p(), tofBeta, track.sign()); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/notrd/EvTimeTOF"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/EvTimeTOF"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/notrd/EvTimeTOFOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/EvTimeTOFOnly"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/notrd/EvTimeT0AC"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/EvTimeT0AC"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/notrd/EvTimeT0ACOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/EvTimeT0ACOnly"), track.p(), tofBeta, track.sign()); + } + } + } else { + const float signedp = track.p() * track.sign(); + histos.fill(HIST("tofmass/notrd/inclusive"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/inclusive"), signedp, tofBeta); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/notrd/EvTimeTOF"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/EvTimeTOF"), signedp, tofBeta); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/notrd/EvTimeTOFOnly"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/EvTimeTOFOnly"), signedp, tofBeta); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/notrd/EvTimeT0AC"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/EvTimeT0AC"), signedp, tofBeta); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/notrd/EvTimeT0ACOnly"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/EvTimeT0ACOnly"), signedp, tofBeta); + } + } + } + } else { + + int lastLayer = 0; + for (int l = 7; l >= 0; l--) { + if (track.trdPattern() & (1 << l)) { + lastLayer = l; + break; + } + } + + histos.fill(HIST("event/trd/length"), track.length(), lastLayer); + if (lastLayer < lastTrdLayerForTrdMatch) { + continue; + } + if (splitSignalPerCharge) { + histos.fill(HIST("tofmass/trd/inclusive"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/inclusive"), track.p(), tofBeta, track.sign()); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/trd/EvTimeTOF"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/EvTimeTOF"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/trd/EvTimeTOFOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/EvTimeTOFOnly"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/trd/EvTimeT0AC"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/EvTimeT0AC"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/trd/EvTimeT0ACOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/EvTimeT0ACOnly"), track.p(), tofBeta, track.sign()); + } + } + } else { + const float signedp = track.p() * track.sign(); + histos.fill(HIST("tofmass/trd/inclusive"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/inclusive"), signedp, tofBeta); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/trd/EvTimeTOF"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/EvTimeTOF"), signedp, tofBeta); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/trd/EvTimeTOFOnly"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/EvTimeTOFOnly"), signedp, tofBeta); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/trd/EvTimeT0AC"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/EvTimeT0AC"), signedp, tofBeta); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/trd/EvTimeT0ACOnly"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/EvTimeT0ACOnly"), signedp, tofBeta); + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx index 99046cbb716..b9ead03b14f 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx @@ -15,19 +15,21 @@ /// \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/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/TableProducer/PID/pidTOFBase.h" -#include "Framework/runDataProcessing.h" + #include "CommonConstants/LHCConstants.h" +#include "DataFormatsFT0/Digit.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + +#include "TEfficiency.h" +#include "THashList.h" using namespace o2; using namespace o2::framework; @@ -68,166 +70,170 @@ struct tofPidCollisionTimeQa { 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}); - } + 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)); - }; + 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"); + 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", "", HistType::kTH1F, {diffAxis}); + 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/pdg211/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/pdgNeg211/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/prm/pdg211/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/prm/pdgNeg211/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); + 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.add("MC/pdg321/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/pdgNeg321/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/prm/pdg321/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/prm/pdgNeg321/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); + histos.addClone("MC/particle/pdg211/", "MC/particle/pdg321/"); + histos.addClone("MC/particle/pdg211/", "MC/particle/pdgNeg321/"); // proton - histos.add("MC/pdg2212/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/pdgNeg2212/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/prm/pdg2212/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - histos.add("MC/prm/pdgNeg2212/particleDiff", "", HistType::kTH2F, {pAxis, diffAxis}); - - histos.add("MC/t", "", HistType::kTH1F, {{1000, -1000, 1000, "MC time"}}); + 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 Trks = soa::Join; + using TrksData = soa::Join; using EvTimeCollisions = soa::Join; // Define slice per collision Preslice perCollision = aod::track::collisionId; - void processData(Trks const& tracks, EvTimeCollisions const&) + void processData(TrksData const& tracks, EvTimeCollisions const&) { static int ncolls = 0; int lastCollisionId = -1; // Last collision ID analysed @@ -330,17 +336,17 @@ struct tofPidCollisionTimeQa { 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& 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& 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); + 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()); @@ -362,6 +368,10 @@ struct tofPidCollisionTimeQa { 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()); @@ -370,10 +380,6 @@ struct tofPidCollisionTimeQa { 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()); @@ -435,77 +441,162 @@ struct tofPidCollisionTimeQa { 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& t : tracks) { - if (!t.has_collision()) { // Track was not assigned to a collision - continue; - } else if (t.collisionId() == lastCollisionId) { // Event was already processed + for (auto& trk : tracks) { + if (!trk.has_collision()) { // Track was not assigned to a collision continue; } - lastCollisionId = t.collisionId(); /// Cache last collision ID - const auto& collision = t.collision_as(); + const auto& collision = trk.collision_as(); if (!collision.has_mcCollision()) { continue; } const auto& collisionMC = collision.mcCollision_as(); - // timeInBCNS + bc2ns(); - const auto& mcBC = collisionMC.bc(); - // bc* o2::constants::lhc::LHCBunchSpacingNS + orbit* o2::constants::lhc::LHCOrbitNS; - // int64_t(mcBC.globalBC() * o2::constants::lhc::LHCBunchSpacingNS * 1e-3)) - const int64_t bcMCtime = static_cast((collisionMC.t() + 2.f) / o2::constants::lhc::LHCBunchSpacingNS); - const float eventtimeMC = collisionMC.t() - bcMCtime * o2::constants::lhc::LHCBunchSpacingNS; - LOG(info) << mcBC.globalBC() - bcMCtime << " MC collision time: " << eventtimeMC << " collision time: " << collision.collisionTime() << " TOF event time: " << t.tofEvTime(); - histos.fill(HIST("MC/t"), eventtimeMC); - histos.fill(HIST("MC/diff"), eventtimeMC - t.tofEvTime()); - if (!t.has_mcParticle()) { + 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; } - const auto& particle = t.mcParticle(); - LOG(info) << "Track " << particle.vt() << " vs " << eventtimeMC; - switch (particle.pdgCode()) { - case 211: - histos.fill(HIST("MC/pdg211/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - if (particle.isPhysicalPrimary()) { - histos.fill(HIST("MC/prm/pdg211/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - } - break; - case -211: - histos.fill(HIST("MC/pdgNeg211/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - if (particle.isPhysicalPrimary()) { - histos.fill(HIST("MC/prm/pdgNeg211/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - } - break; - case 321: - histos.fill(HIST("MC/pdg321/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - if (particle.isPhysicalPrimary()) { - histos.fill(HIST("MC/prm/pdg321/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - } - break; - case -321: - histos.fill(HIST("MC/pdgNeg321/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - if (particle.isPhysicalPrimary()) { - histos.fill(HIST("MC/prm/pdgNeg321/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - } - break; - case 2212: - histos.fill(HIST("MC/pdg2212/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - if (particle.isPhysicalPrimary()) { - histos.fill(HIST("MC/prm/pdg2212/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - } - break; - case -2212: - histos.fill(HIST("MC/pdgNeg2212/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - if (particle.isPhysicalPrimary()) { - histos.fill(HIST("MC/prm/pdgNeg2212/particleDiff"), particle.pt(), collisionMC.t() - particle.vt()); - } - break; - default: - break; + 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); diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFMC.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFMC.cxx index e841e057497..2e6987ce034 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFMC.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFMC.cxx @@ -12,14 +12,16 @@ /// /// \file qaPIDTOFMC.cxx /// \author Nicolò Jacazio -/// \brief Task to produce QA output of the PID with TOF running on the MC. +/// \brief Task to produce QA output of the PID with TOF running on the MC e.g. to compute purity. /// // O2 includes +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/StaticFor.h" -#include "Common/DataModel/PIDResponse.h" #include "Framework/runDataProcessing.h" using namespace o2; @@ -27,169 +29,71 @@ 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 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 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}; @@ -207,6 +111,7 @@ struct pidTofQaMc { 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"}; @@ -271,33 +176,50 @@ struct pidTofQaMc { 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 - histos.add(hparticlept[mcID].data(), "", kTH1F, {pAxis}); - histos.add(hparticlep[mcID].data(), "", kTH1F, {pAxis}); - histos.add(hparticleeta[mcID].data(), "", kTH1F, {pAxis}); + 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 - 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}); + 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 - histos.add(hnsigma[mcID].data(), pT[mcID], HistType::kTH2F, {ptAxis, nSigmaAxis}); - histos.add(hsignalMC[mcID].data(), pT[mcID], HistType::kTH2F, {pAxis, signalAxis}); + 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}); - 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}); + 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}); - 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}); + 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 @@ -355,11 +277,11 @@ struct pidTofQaMc { 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}); + hNSigmaMC[mcID * Np + massID] = histos.add(Form("nsigmaMC/%s/%s", pName[mcID], pName[massID]), 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}); + 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}); } } @@ -376,6 +298,8 @@ struct pidTofQaMc { 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) { @@ -401,7 +325,7 @@ struct pidTofQaMc { { switch (pdgSign.value) { case 0: - if (abs(particle.pdgCode()) != PDGs[mcID]) { + if (std::abs(particle.pdgCode()) != PDGs[mcID]) { return; } break; @@ -468,9 +392,9 @@ struct pidTofQaMc { 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()); + hParticlePt[mcID]->Fill(particle.pt()); + hParticleP[mcID]->Fill(particle.p()); + hParticleEta[mcID]->Fill(particle.p()); } template @@ -529,23 +453,61 @@ struct pidTofQaMc { const float nsigma = o2::aod::pidutils::tofNSigma(track); // Fill for all - histos.fill(HIST(hnsigma[mcID]), track.pt(), nsigma); + 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) { - histos.fill(HIST(hnsigmastr[mcID]), track.pt(), nsigma); + hNSigmastr[mcID]->Fill(track.pt(), nsigma); + hDeltaMCEvTimestr[mcID]->Fill(track.pt(), delta); } else { - histos.fill(HIST(hnsigmamat[mcID]), track.pt(), nsigma); + hNSigmamat[mcID]->Fill(track.pt(), nsigma); + hDeltaMCEvTimemat[mcID]->Fill(track.pt(), delta); } } else { - histos.fill(HIST(hnsigmaprm[mcID]), track.pt(), nsigma); + hNSigmaprm[mcID]->Fill(track.pt(), nsigma); + hDeltaMCEvTimeprm[mcID]->Fill(track.pt(), delta); } } switch (pdgSign.value) { case 0: - if (abs(particle.pdgCode()) != PDGs[mcID]) { + if (std::abs(particle.pdgCode()) != PDGs[mcID]) { return; } break; @@ -564,22 +526,48 @@ struct pidTofQaMc { } // 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()); + hTrackPt[mcID]->Fill(track.pt()); + hTrackP[mcID]->Fill(track.p()); + hTrackEta[mcID]->Fill(track.eta()); + hTrackLength[mcID]->Fill(track.length()); // PID info - histos.fill(HIST(hsignalMC[mcID]), track.p(), track.beta()); + 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) { - histos.fill(HIST(hsignalMCstr[mcID]), track.p(), track.beta()); + hSignalMCstr[mcID]->Fill(track.p(), beta); + hDeltaMCEvTimeMCstr[mcID]->Fill(track.pt(), delta); } else { - histos.fill(HIST(hsignalMCmat[mcID]), track.p(), track.beta()); + hSignalMCmat[mcID]->Fill(track.p(), beta); + hDeltaMCEvTimeMCmat[mcID]->Fill(track.pt(), delta); } } else { - histos.fill(HIST(hsignalMCprm[mcID]), track.p(), track.beta()); + hSignalMCprm[mcID]->Fill(track.p(), beta); + hDeltaMCEvTimeMCprm[mcID]->Fill(track.pt(), delta); } } } @@ -639,7 +627,7 @@ struct pidTofQaMc { switch (pdgSign.value) { case 0: - if (abs(particle.pdgCode()) != PDGs[mcID]) { + if (std::abs(particle.pdgCode()) != PDGs[mcID]) { return; } break; @@ -659,29 +647,31 @@ struct pidTofQaMc { const float nsigmaMassID = o2::aod::pidutils::tofNSigma(track); - histos.fill(HIST(hnsigmaMC[mcID * Np + massID]), track.pt(), nsigmaMassID); + hNSigmaMC[mcID * Np + massID]->Fill(track.pt(), nsigmaMassID); if (checkPrimaries) { if (!particle.isPhysicalPrimary()) { if (particle.getProcess() == 4) { - histos.fill(HIST(hnsigmaMCstr[mcID * Np + massID]), track.pt(), nsigmaMassID); + hNSigmaMCstr[mcID * Np + massID]->Fill(track.pt(), nsigmaMassID); } else { - histos.fill(HIST(hnsigmaMCmat[mcID * Np + massID]), track.pt(), nsigmaMassID); + hNSigmaMCmat[mcID * Np + massID]->Fill(track.pt(), nsigmaMassID); } } else { - histos.fill(HIST(hnsigmaMCprm[mcID * Np + massID]), track.pt(), nsigmaMassID); + hNSigmaMCprm[mcID * Np + massID]->Fill(track.pt(), nsigmaMassID); } } } - Preslice perCol = aod::track::collisionId; - Preslice perMCCol = aod::mcparticle::mcCollisionId; - - void process(soa::Join const& collisions, - soa::Join& tracks, + aod::TOFSignal, aod::McTrackLabels, aod::pidTOFbeta>; + 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&) { @@ -689,10 +679,12 @@ struct pidTofQaMc { if (collision.numContrib() < nMinNumberOfContributors) { return; } + if (!collision.sel8()) { + continue; + } 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) { @@ -701,52 +693,66 @@ struct pidTofQaMc { }); } + 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& t : tracksInCollision) { + for (const auto& track : tracksInCollision) { // - if (!t.hasTOF()) { // Skipping tracks without TOF + if (!track.hasTOF()) { // Skipping tracks without TOF continue; } - if (t.eta() < minEta || t.eta() > maxEta) { + if (track.eta() < minEta || track.eta() > maxEta) { continue; } nTracksWithTOF++; // Fill for all - histos.fill(HIST("event/tofbeta"), t.p(), t.beta()); - if (!t.has_mcParticle()) { + // const float beta = track.tofBeta(); + const float beta = track.beta(); + histos.fill(HIST("event/tofbeta"), track.p(), beta); + if (!track.has_mcParticle()) { continue; } - const auto& particle = t.mcParticle(); + 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"), t.p(), t.beta()); + // histos.fill(HIST("event/tofbetaSec"), track.p(), beta); if (particle.getProcess() == 4) { - histos.fill(HIST("event/tofbetaStr"), t.tpcInnerParam(), t.tpcSignal()); + histos.fill(HIST("event/tofbetaStr"), track.tpcInnerParam(), track.tpcSignal()); } else { - histos.fill(HIST("event/tofbetaMat"), t.tpcInnerParam(), t.tpcSignal()); + histos.fill(HIST("event/tofbetaMat"), track.tpcInnerParam(), track.tpcSignal()); } } else { - histos.fill(HIST("event/tofbetaPrm"), t.p(), t.beta()); + 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(t, particle); + fillPIDInfoForPdg(track, particle); }); - fillTrackInfoForPdg(t, particle); + fillTrackInfoForPdg(track, particle); }); } // track loop histos.fill(HIST("event/T0"), nTracksWithTOF, collisionTime_ps); histos.fill(HIST("event/vertexz"), collision.posZ()); } // collision loop - } // process() + } // process() }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPC.cxx b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPC.cxx index 40913b39b79..53c03e6c338 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPC.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPC.cxx @@ -15,13 +15,15 @@ /// \brief Implementation for QA tasks of the TPC PID quantities /// +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #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 "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; @@ -299,7 +301,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 +398,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/TPC/qaPIDTPCMC.cxx b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCMC.cxx index e99f6a9116c..e05023b4b3a 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCMC.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCMC.cxx @@ -16,10 +16,11 @@ /// // O2 includes +#include "Common/DataModel/PIDResponseTPC.h" + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/StaticFor.h" -#include "Common/DataModel/PIDResponse.h" #include "Framework/runDataProcessing.h" using namespace o2; @@ -303,6 +304,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/TPC/qaPIDTPCSignal.cxx b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCSignal.cxx index bbae2f60cd5..bf8492b8036 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCSignal.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/qaPIDTPCSignal.cxx @@ -171,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); @@ -219,7 +219,7 @@ struct tpcPidQaSignal { if (!t.has_collision()) { continue; } - if (abs(t.collision().posZ()) > 10.f) { + if (std::abs(t.collision().posZ()) > 10.f) { continue; } if (!isTrackSelected(t)) { @@ -269,7 +269,7 @@ 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); @@ -281,7 +281,7 @@ struct tpcPidQaSignal { void processNoEvSel(soa::Filtered const& tracks, aod::Collisions const& collisions) { histos.fill(HIST("event/evsel"), 1, collisions.size()); - LOG(info) << "Processing " << collisions.size() << " collisions with " << tracks.size() << " tracks"; + LOG(debug) << "Processing " << collisions.size() << " collisions with " << tracks.size() << " tracks"; processTracks(tracks); } PROCESS_SWITCH(tpcPidQaSignal, processNoEvSel, "Process without event selection", true); @@ -290,7 +290,7 @@ struct tpcPidQaSignal { void processMoreTrkSel(soa::Filtered> const& tracks, aod::Collisions const& collisions) { histos.fill(HIST("event/evsel"), 1, collisions.size()); - LOG(info) << "Processing " << collisions.size() << " collisions with " << tracks.size() << " tracks"; + LOG(debug) << "Processing " << collisions.size() << " collisions with " << tracks.size() << " tracks"; processTracks(tracks); } PROCESS_SWITCH(tpcPidQaSignal, processMoreTrkSel, "Process without event selection", false); diff --git a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx index 2769289a732..1ab36ad9f71 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx @@ -8,29 +8,71 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +// +/// \file perfK0sResolution.cxx +/// \brief V0s (K0s, Lambda and antiLambda) analysis task +/// +/// \author Nicolò Jacazio , Universita del Piemonte Orientale +/// \author Roman Nepeivoda , Lund University +/// \author Romain Schotter , Austrian Academy of Sciences & MBI +// -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/PID.h" -#include "Common/Core/trackUtilities.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/Tools/TrackTuner.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + using namespace o2; using namespace o2::track; using namespace o2::framework; using namespace o2::framework::expressions; -using PIDTracks = soa::Join; +using PIDTracksIU = soa::Join; using PIDTracksIUMC = soa::Join; -using SelectedCollisions = soa::Join; +using SelectedCollisions = soa::Join; + +enum CentEstimator { + kCentFT0C = 0, + kCentFT0M, + kCentFT0CVariant1, + kCentMFT, + kCentNGlobal +}; struct perfK0sResolution { // Configurable bins @@ -45,38 +87,89 @@ struct perfK0sResolution { ConfigurableAxis etaBinsDauthers{"etaBinsDauthers", {100, -1.f, 1.f}, "eta binning for daughters"}; ConfigurableAxis phiBins{"phiBins", {100, 0.f, 6.28f}, "phi binning"}; ConfigurableAxis relpTResBins{"relpTResBins", {200, 0.f, 0.5f}, "rel. pT resolution binning"}; - - // Selection criteria - Configurable v0setting_cospa{"v0setting_cospa", 0.995, "V0 CosPA"}; // shoudl be double in future - Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 1., "DCA V0 Daughters"}; - Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.1, "DCA Pos To PV"}; - Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.1, "DCA Neg To PV"}; - Configurable v0setting_radius{"v0setting_radius", 0.9, "V0 Radius"}; - Configurable v0setting_rapidity{"v0setting_rapidity", 0.5, "rapidity"}; - - 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 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"}; - Configurable tofSelectionNeg{"tofSelectionNeg", 0, "Flag for the TOF selection on negative daughters: -1 no TOF, 0 no selection, 1 TOF"}; - Configurable pidHypoPos{"pidHypoPos", -1, "Index for the PID hypothesis used in tracking for the positive daughters: -1 no selection, 0 Electron, 1 Muon, 2 Pion, 3 Kaon, 4 Proton"}; - Configurable pidHypoNeg{"pidHypoNeg", -1, "Index for the PID hypothesis used in tracking for the negative daughters: -1 no selection, 0 Electron, 1 Muon, 2 Pion, 3 Kaon, 4 Proton"}; - Configurable extraCutTPCClusters{"extraCutTPCClusters", -1.0f, "Extra cut on daugthers for TPC clusters"}; + ConfigurableAxis centralityAxis{"centralityAxis", {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, 101.f}, "Centrality"}; + ConfigurableAxis occupancyAxis{"occupancyAxis", {VARIABLE_WIDTH, -1.0f, 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"}; + + struct : ConfigurableGroup { + std::string prefix = "eventSelections"; // JSON group name + 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 centralityEstimator{"centralityEstimator", kCentFT0C, "Run 3 centrality estimator (0:CentFT0C, 1:CentFT0M, 2:CentFT0CVariant1, 3:CentMFT, 4:CentNGlobal)"}; + 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; + + static constexpr float DefaultLifetimeCuts[1][2] = {{30., 20.}}; + + struct : ConfigurableGroup { + std::string prefix = "v0Selections"; // JSON group name + 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.995, "min V0 CosPA"}; + Configurable dcav0dau{"dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; + Configurable dcanegtopv{"dcanegtopv", 0.1, "min DCA Neg To PV (cm)"}; + Configurable dcapostopv{"dcapostopv", 0.1, "min DCA Pos To PV (cm)"}; + Configurable v0radius{"v0radius", 1.2, "minimum V0 radius (cm)"}; + Configurable v0radiusMax{"v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + Configurable> lifetimecut{"lifetimecut", {DefaultLifetimeCuts[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecut"}; + + // 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 requirePosITSib{"requirePosITSib", 0, "require ITS IB selection on positive daughters? -1: no ITS IB, 0: no selection, 1: ITS IB"}; + Configurable requireNegITSib{"requireNegITSib", 0, "require ITS IB selection on negative daughters? -1: no ITS IB, 0: no selection, 1: ITS IB"}; + Configurable requirePosITSafterburner{"requirePosITSafterburner", 0, "require positive track formed out of afterburner ITS tracks? -1: no AB, 0: no selection, 1: AB"}; + Configurable requireNegITSafterburner{"requireNegITSafterburner", 0, "require negative track formed out of afterburner ITS tracks? -1: no AB, 0: no selection, 1: AB"}; + Configurable requirePosTRD{"requirePosTRD", 0, "require TRD selection on positive daughters? -1: no TRD, 0: no selection, 1: TRD"}; + Configurable requireNegTRD{"requireNegTRD", 0, "require TRD selection on negative daughters? -1: no TRD, 0: no selection, 1: TRD"}; + Configurable requirePosTOF{"requirePosTOF", 0, "require TOF selection on positive daughters? -1: no TOF, 0: no selection, 1: TOF"}; + Configurable requireNegTOF{"requireNegTOF", 0, "require TOF selection on negative daughters? -1: no TOF, 0: no selection, 1: TOF"}; + Configurable requirePosPIDforTracking{"requirePosPIDforTracking", -1, "require specific PID hypothesis used in tracking for the positive daughters? -1: no selection, 0: Electron, 1: Muon, 2: Pion, 3: Kaon, 4: Proton"}; + Configurable requireNegPIDforTracking{"requireNegPIDforTracking", -1, "require specific PID hypothesis used in tracking for the negative daughters? -1: no selection, 0: Electron, 1: Muon, 2: Pion, 3: Kaon, 4: Proton"}; + + // PID (TPC/TOF) + Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 10., "tpcPidNsigmaCut"}; + Configurable tofPidNsigmaCut{"tofPidNsigmaCut", 1e+6, "tofPidNsigmaCut"}; + } v0Selections; // Configure plots to enable Configurable useMultidimHisto{"useMultidimHisto", false, "use multidimentional histograms"}; Configurable enableTPCPlot{"enableTPCPlot", false, "Enable the TPC plot"}; - Configurable computeInvMassFromDaughters{"computeInvMassFromDaughters", false, "Compute the invariant mass from the daughters"}; - Configurable requireTrueK0s{"requireTrueK0s", false, "require rec. v0 to be true K0s"}; - - // Configurable for event selection - Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; - Configurable eventSelection{"eventSelection", true, "event selection"}; + Configurable requireTrueK0s{"requireTrueK0s", true, "require rec. v0 to be true K0s"}; + Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; HistogramRegistry rK0sResolution{"K0sResolution", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry rK0sDauResolution{"K0sDauResolution", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; @@ -92,11 +185,9 @@ struct perfK0sResolution { Configurable useTrackTuner{"useTrackTuner", false, "Apply Improver/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: =|=)"}; OutputObj trackTunedTracks{TH1D("trackTunedTracks", "", 4, 0.5, 4.5), OutputObjHandlingPolicy::AnalysisObject}; - 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 lutPath{"lutPath", "GLO/Param/MatLUTInner", "Path of the Lut parametrization"}; + 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 minOccupancyCut{"minOccupancyCut", 1, "Minimum occupancy cut. Enabled if min < max"}; - Configurable maxOccupancyCut{"maxOccupancyCut", -1, "Maximum occupancy cut. Enabled if min < max"}; int runNumber = -1; @@ -117,45 +208,71 @@ struct perfK0sResolution { const AxisSpec phiAxis{phiBins, "#phi"}; const AxisSpec trueK0Axis{2, -0.5, 1.5, "True K0"}; - rK0sResolution.add("h1_stats", "h1_stats", {HistType::kTH1F, {statAxis}}); + // Event Counters + rK0sResolution.add("hEventSelection", "hEventSelection", kTH1D, {{21, -0.5f, +20.5f}}); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min occup."); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max occup."); + + rK0sResolution.add("hEventCentrality", "hEventCentrality", kTH1D, {{101, 0.0f, 101.0f}}); + rK0sResolution.add("hEventOccupancy", "hEventOccupancy", kTH1D, {occupancyAxis}); + + rK0sResolution.add("h1_stats", "h1_stats", {HistType::kTH1D, {statAxis}}); TString hStatsLabels[5] = {"Selected Events", "All V0s", "Selected V0s", "Daughters have MC particles", "Daughters corr. rec."}; - for (Int_t n = 1; n <= rK0sResolution.get(HIST("h1_stats"))->GetNbinsX(); n++) { + for (int n = 1; n <= rK0sResolution.get(HIST("h1_stats"))->GetNbinsX(); n++) { rK0sResolution.get(HIST("h1_stats"))->GetXaxis()->SetBinLabel(n, hStatsLabels[n - 1]); } if (doprocessMC) { - rK0sDauResolution.add("h2_massPosPtRes", "h2_massPosPtRes", {HistType::kTH2F, {mAxis, pTResAxis}}); - rK0sDauResolution.add("h2_massNegPtRes", "h2_massNegPtRes", {HistType::kTH2F, {mAxis, pTResAxis}}); - - rK0sDauResolution.add("h2_genPtPosPtResNorm", "h2_genPtPosPtResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPxPosPxResNorm", "h2_genPxPosPxResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPyPosPyResNorm", "h2_genPyPosPyResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPzPosPzResNorm", "h2_genPzPosPzResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - - rK0sDauResolution.add("h2_genPtNegPtResNorm", "h2_genPtNegPtResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPxNegPxResNorm", "h2_genPxNegPxResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPyNegPyResNorm", "h2_genPyNegPyResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPzNegPzResNorm", "h2_genPzNegPzResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - - rK0sDauResolution.add("h2_genPtPosPtRes", "h2_genPtPosPtRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPxPosPxRes", "h2_genPxPosPxRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPyPosPyRes", "h2_genPyPosPyRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPzPosPzRes", "h2_genPzPosPzRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - - rK0sDauResolution.add("h2_genPtNegPtRes", "h2_genPtNegPtRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPxNegPxRes", "h2_genPxNegPxRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPyNegPyRes", "h2_genPyNegPyRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPzNegPzRes", "h2_genPzNegPzRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - - rK0sDauResolution.add("h2_genPtPosPulls", "h2_GenPtPosPulls", {HistType::kTH2F, {invpTResNormAxis, invpTAxis}}); - rK0sDauResolution.add("h2_genPtNegPulls", "h2_GenPtNegPulls", {HistType::kTH2F, {invpTResNormAxis, invpTAxis}}); - - rK0sDauResolution.add("h2_PosRelPtRes", "h2_PosRelPtRes", {HistType::kTH2F, {pTAxis, relpTResAxis}}); - rK0sDauResolution.add("h2_NegRelPtRes", "h2_NegRelPtRes", {HistType::kTH2F, {pTAxis, relpTResAxis}}); - } - rK0sResolution.add("h2_masspT", "h2_masspT", {HistType::kTH2F, {mAxis, pTAxis}}); - rK0sResolution.add("h2_masseta", "h2_masseta", {HistType::kTH2F, {mAxis, etaAxis}}); - rK0sResolution.add("h2_massphi", "h2_massphi", {HistType::kTH2F, {mAxis, phiAxis}}); + rK0sDauResolution.add("h2_massPosPtRes", "h2_massPosPtRes", {HistType::kTH2D, {mAxis, pTResAxis}}); + rK0sDauResolution.add("h2_massNegPtRes", "h2_massNegPtRes", {HistType::kTH2D, {mAxis, pTResAxis}}); + + rK0sDauResolution.add("h2_genPtPosPtResNorm", "h2_genPtPosPtResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPxPosPxResNorm", "h2_genPxPosPxResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPyPosPyResNorm", "h2_genPyPosPyResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPzPosPzResNorm", "h2_genPzPosPzResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + + rK0sDauResolution.add("h2_genPtNegPtResNorm", "h2_genPtNegPtResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPxNegPxResNorm", "h2_genPxNegPxResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPyNegPyResNorm", "h2_genPyNegPyResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPzNegPzResNorm", "h2_genPzNegPzResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + + rK0sDauResolution.add("h2_genPtPosPtRes", "h2_genPtPosPtRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPxPosPxRes", "h2_genPxPosPxRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPyPosPyRes", "h2_genPyPosPyRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPzPosPzRes", "h2_genPzPosPzRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + + rK0sDauResolution.add("h2_genPtNegPtRes", "h2_genPtNegPtRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPxNegPxRes", "h2_genPxNegPxRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPyNegPyRes", "h2_genPyNegPyRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPzNegPzRes", "h2_genPzNegPzRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + + rK0sDauResolution.add("h2_genPtPosPulls", "h2_GenPtPosPulls", {HistType::kTH2D, {invpTResNormAxis, invpTAxis}}); + rK0sDauResolution.add("h2_genPtNegPulls", "h2_GenPtNegPulls", {HistType::kTH2D, {invpTResNormAxis, invpTAxis}}); + + rK0sDauResolution.add("h2_PosRelPtRes", "h2_PosRelPtRes", {HistType::kTH2D, {pTAxis, relpTResAxis}}); + rK0sDauResolution.add("h2_NegRelPtRes", "h2_NegRelPtRes", {HistType::kTH2D, {pTAxis, relpTResAxis}}); + } + rK0sResolution.add("h2_masspT", "h2_masspT", {HistType::kTH2D, {mAxis, pTAxis}}); + rK0sResolution.add("h2_masseta", "h2_masseta", {HistType::kTH2D, {mAxis, etaAxis}}); + rK0sResolution.add("h2_massphi", "h2_massphi", {HistType::kTH2D, {mAxis, phiAxis}}); if (useMultidimHisto) { if (doprocessMC) { rK0sResolution.add("thn_mass", "thn_mass", kTHnSparseF, {mAxis, pTAxis, etaAxis, phiAxis, etaAxisPosD, etaAxisNegD, invpTResAxis, invpTResAxis, trueK0Axis}); @@ -163,14 +280,16 @@ struct perfK0sResolution { rK0sResolution.add("thn_mass", "thn_mass", kTHnSparseF, {mAxis, pTAxis, etaAxis, phiAxis, etaAxisPosD, etaAxisNegD}); } } + rK0sResolution.add("h3_centralitypTmass", "h3_centralitypTmass", kTH3D, {centralityAxis, pTAxis, mAxis}); + rK0sResolution.add("h3_occupancypTmass", "h3_occupancypTmass", kTH3D, {occupancyAxis, pTAxis, mAxis}); if (enableTPCPlot) { - rK0sDauResolution.add("h3_tpc_vs_pid_hypothesis", "h3_tpc_vs_pid_hypothesis", {HistType::kTH3F, {{200, -10.f, 10.f, "#it{p}/Z (GeV/#it{c})"}, {1000, 0, 1000.f, "dE/dx (a.u.)"}, {10, -0.5, 9.5f, "PID hypothesis"}}}); + rK0sDauResolution.add("h3_tpc_vs_pid_hypothesis", "h3_tpc_vs_pid_hypothesis", {HistType::kTH3D, {{200, -10.f, 10.f, "#it{p}/Z (GeV/#it{c})"}, {1000, 0, 1000.f, "dE/dx (a.u.)"}, {10, -0.5, 9.5f, "PID hypothesis"}}}); } /// TrackTuner initialization if (useTrackTuner) { - ccdb->setURL(ccdburl); + ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); @@ -184,6 +303,10 @@ struct perfK0sResolution { trackTunedTracks->GetXaxis()->SetBinLabel(3, "untouched tracks due to negative detXY"); trackTunedTracks->GetXaxis()->SetBinLabel(4, "original detXY<0"); } + + // inspect histogram sizes, please + rK0sResolution.print(); + rK0sDauResolution.print(); } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -201,250 +324,332 @@ struct perfK0sResolution { runNumber = bc.runNumber(); } + // ______________________________________________________ + // Return slicing output + template + float getCentralityRun3(TCollision const& collision) + { + if (eventSelections.centralityEstimator == kCentFT0C) + return collision.centFT0C(); + else if (eventSelections.centralityEstimator == kCentFT0M) + return collision.centFT0M(); + else if (eventSelections.centralityEstimator == kCentFT0CVariant1) + return collision.centFT0CVariant1(); + else if (eventSelections.centralityEstimator == kCentMFT) + return collision.centMFT(); + else if (eventSelections.centralityEstimator == kCentNGlobal) + return collision.centNGlobal(); + + return -1.f; + } + + template + bool isEventAccepted(TCollision collision, bool fillHists) + // check whether the collision passes our collision selections + { + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 0. /* all collisions */); + + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) + rK0sResolution.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) + rK0sResolution.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHists) + rK0sResolution.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) + rK0sResolution.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHists) + rK0sResolution.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) + rK0sResolution.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) + rK0sResolution.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); + + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillHists) + rK0sResolution.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) + rK0sResolution.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 10 microseconds */); + + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 13 /* No other collision within +/- 2 microseconds */); + + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (fillHists) + rK0sResolution.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) + rK0sResolution.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); + + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 18 /* Below min occupancy */); + + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 19 /* Above max occupancy */); + + return true; + } + template bool acceptV0(const T1& v0, const T2& ntrack, const T2& ptrack, const C& collision) { // Apply selections on V0 - if (TMath::Abs(v0.yK0Short()) > v0setting_rapidity) { + if (std::abs(v0.yK0Short()) > v0Selections.rapidityCut) { return false; } - if (v0.v0radius() < v0setting_radius) { + + if (std::abs(v0.negativeeta()) > v0Selections.daughterEtaCut || std::abs(v0.positiveeta()) > v0Selections.daughterEtaCut) + return false; + + if (v0Selections.v0TypeSelection > -1 && v0.v0Type() != v0Selections.v0TypeSelection) + return false; // skip V0s that are not standard + + // Base topological variables + if (v0.v0radius() < v0Selections.v0radius) + return false; + if (v0.v0radius() > v0Selections.v0radiusMax) + return false; + if (std::abs(v0.dcapostopv()) < v0Selections.dcapostopv) + return false; + if (std::abs(v0.dcanegtopv()) < v0Selections.dcanegtopv) + return false; + if (v0.v0cosPA() < v0Selections.v0cospa) + return false; + if (v0.dcaV0daughters() > v0Selections.dcav0dau) + return false; + + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short > v0Selections.lifetimecut->get("lifetimecutK0S")) { return false; } - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * pid_constants::sMasses[PID::K0] > 2.684 * nV0lifetime) { + + if (v0Selections.armPodCut > 1e-4 && v0.qtarm() * v0Selections.armPodCut < std::abs(v0.alpha())) { return false; } // Apply selections on V0 daughters - // ITS selection - switch (itsIbSelectionPos) { - case -1: - if (ptrack.itsNClsInnerBarrel() > 0) { - return false; - } - break; - case 0: - break; - case 1: - if (ptrack.itsNClsInnerBarrel() < 1) { - return false; - } - break; - default: - LOG(fatal) << "Invalid ITS selection for positive daughter"; - break; - } - switch (itsIbSelectionNeg) { - case -1: - if (ntrack.itsNClsInnerBarrel() > 0) { - return false; - } - break; - case 0: - break; - case 1: - if (ntrack.itsNClsInnerBarrel() < 1) { - return false; - } - break; - default: - 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; + // ITS quality flags + // check minium ITS clusters + if (ptrack.itsNCls() < v0Selections.minITSclusters) + return false; + if (ntrack.itsNCls() < v0Selections.minITSclusters) + return false; + // check maximum ITS chi2 per clusters + if (ptrack.itsChi2NCl() > v0Selections.maxITSchi2PerNcls) + return false; + if (ntrack.itsChi2NCl() > v0Selections.maxITSchi2PerNcls) + return false; + + // TPC quality flags + // check minimum TPC crossed rows + if (ptrack.tpcNClsCrossedRows() < v0Selections.minTPCrows) + return false; + if (ntrack.tpcNClsCrossedRows() < v0Selections.minTPCrows) + return false; + // check maximum TPC chi2 per clusters + if (ptrack.tpcChi2NCl() > v0Selections.maxTPCchi2PerNcls) + return false; + if (ntrack.tpcChi2NCl() > v0Selections.maxTPCchi2PerNcls) + return false; + // check minimum fraction of TPC rows over findable + if (ptrack.tpcCrossedRowsOverFindableCls() < v0Selections.minTPCrowsOverFindableClusters) + return false; + if (ntrack.tpcCrossedRowsOverFindableCls() < v0Selections.minTPCrowsOverFindableClusters) + return false; + // check minimum fraction of found over findable TPC clusters + if (ptrack.tpcFoundOverFindableCls() < v0Selections.minTPCfoundOverFindableClusters) + return false; + if (ntrack.tpcFoundOverFindableCls() < v0Selections.minTPCfoundOverFindableClusters) + return false; + // check the maximum fraction of allowed shared TPC clusters + if (ptrack.tpcChi2NCl() > v0Selections.maxFractionTPCSharedClusters) + return false; + if (ntrack.tpcChi2NCl() > v0Selections.maxFractionTPCSharedClusters) + return false; + + // ITS Inner Barrel selection + if (std::abs(v0Selections.requirePosITSib) > 0) { + if (v0Selections.requirePosITSib < 0 && ptrack.itsNClsInnerBarrel() > 0) // require no ITS IB + return false; + if (v0Selections.requirePosITSib > 0 && ptrack.itsNClsInnerBarrel() < 1) // require ITS IB + return false; + } + if (std::abs(v0Selections.requireNegITSib) > 0) { + if (v0Selections.requireNegITSib < 0 && ntrack.itsNClsInnerBarrel() > 0) // require no ITS IB + return false; + if (v0Selections.requireNegITSib > 0 && ntrack.itsNClsInnerBarrel() < 1) // require ITS IB + return false; + } + + // ITS AfterBurner selection + if (std::abs(v0Selections.requirePosITSafterburner) > 0) { + if (v0Selections.requirePosITSafterburner < 0 && ptrack.isITSAfterburner()) // require no ITS AB + return false; + if (v0Selections.requirePosITSafterburner > 0 && !ptrack.isITSAfterburner()) // require ITS AB + return false; + } + if (std::abs(v0Selections.requireNegITSafterburner) > 0) { + if (v0Selections.requireNegITSafterburner < 0 && ntrack.isITSAfterburner()) // require no ITS AB + return false; + if (v0Selections.requireNegITSafterburner > 0 && !ntrack.isITSAfterburner()) // require ITS AB + return false; } - // TPC selection - if (!ntrack.hasTPC() || !ptrack.hasTPC()) { + // TPC PID selection + if (std::abs(ptrack.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) { return false; } - if (abs(ntrack.tpcNSigmaPi()) > nMaxTPCNsigma) { + if (std::abs(ntrack.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) { return false; } - if (abs(ptrack.tpcNSigmaPi()) > nMaxTPCNsigma) { + + // TOF PID selection + if (ptrack.hasTOF() && std::fabs(v0.tofNSigmaK0PiPlus()) > v0Selections.tofPidNsigmaCut) { return false; } - if (ntrack.tpcNClsCrossedRows() < extraCutTPCClusters || ptrack.tpcNClsCrossedRows() < extraCutTPCClusters) { + if (ntrack.hasTOF() && std::fabs(v0.tofNSigmaK0PiMinus()) > v0Selections.tofPidNsigmaCut) { return false; } // TOF selection - switch (tofSelectionPos) { - case -1: - if (ptrack.hasTOF()) { - return false; - } - break; - case 0: - break; - case 1: - if (!ptrack.hasTOF()) { - return false; - } - break; - default: - LOG(fatal) << "Invalid TOF selection for positive daughter"; - break; - } - switch (tofSelectionNeg) { - case -1: - if (ntrack.hasTOF()) { - return false; - } - break; - case 0: - break; - case 1: - if (!ntrack.hasTOF()) { - return false; - } - break; - default: - LOG(fatal) << "Invalid TOF selection for negative daughter"; - break; + if (std::abs(v0Selections.requirePosTOF) > 0) { + if (v0Selections.requirePosTOF < 0 && ptrack.hasTOF()) // require no TOF + return false; + if (v0Selections.requirePosTOF > 0 && !ptrack.hasTOF()) // require TOF + return false; + } + if (std::abs(v0Selections.requireNegTOF) > 0) { + if (v0Selections.requireNegTOF < 0 && ntrack.hasTOF()) // require no TOF + return false; + if (v0Selections.requireNegTOF > 0 && !ntrack.hasTOF()) // require TOF + return false; } // TRD selection - switch (trdSelectionPos) { - case -1: - if (ptrack.hasTRD()) { - return false; - } - break; - case 0: - break; - case 1: - if (!ptrack.hasTRD()) { - return false; - } - break; - default: - LOG(fatal) << "Invalid TRD selection for positive daughter"; - break; - } - switch (trdSelectionNeg) { - case -1: - if (ntrack.hasTRD()) { - return false; - } - break; - case 0: - break; - case 1: - if (!ntrack.hasTRD()) { - return false; - } - break; - default: - LOG(fatal) << "Invalid TRD selection for negative daughter"; - break; - } - - // PID hypothesis selection - switch (pidHypoPos) { - case -1: - break; - case 0: - case 1: - case 2: - case 3: - case 4: - if (ptrack.pidForTracking() != static_cast(pidHypoPos)) { - return false; - } - break; - default: - LOG(fatal) << "Invalid PID selection for positive daughter"; - break; - } - switch (pidHypoNeg) { - case -1: - break; - case 0: - case 1: - case 2: - case 3: - case 4: - if (ntrack.pidForTracking() != static_cast(pidHypoNeg)) { - return false; - } - break; - default: - LOG(fatal) << "Invalid PID selection for negative daughter"; - break; + if (std::abs(v0Selections.requirePosTRD) > 0) { + if (v0Selections.requirePosTRD < 0 && ptrack.hasTRD()) // require no TRD + return false; + if (v0Selections.requirePosTRD > 0 && !ptrack.hasTRD()) // require TRD + return false; + } + if (std::abs(v0Selections.requireNegTRD) > 0) { + if (v0Selections.requireNegTRD < 0 && ntrack.hasTRD()) // require no TRD + return false; + if (v0Selections.requireNegTRD > 0 && !ntrack.hasTRD()) // require TRD + return false; } - return true; - } - // Filters on V0s - Filter v0Filter = (nabs(aod::v0data::dcapostopv) > v0setting_dcapostopv && - nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv && - aod::v0data::dcaV0daughters < v0setting_dcav0dau && - aod::v0data::v0cosPA > v0setting_cospa); + // Specific PID for tracking selection + if (v0Selections.requirePosPIDforTracking > -1 && ptrack.pidForTracking() != static_cast(v0Selections.requirePosPIDforTracking)) { + return false; + } + if (v0Selections.requireNegPIDforTracking > -1 && ntrack.pidForTracking() != static_cast(v0Selections.requireNegPIDforTracking)) { + return false; + } - // Event selection - Filter eventFilter = (eventSelection && o2::aod::evsel::sel8 == true); - Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + return true; + } - void processData(soa::Filtered::iterator const& collision, - soa::Filtered const& fullV0s, - PIDTracks const&) + void processData(SelectedCollisions::iterator const& collision, + soa::Join const& fullV0s, + PIDTracksIU const&) { - const int occupancy = collision.trackOccupancyInTimeRange(); - if (minOccupancyCut < maxOccupancyCut) { - if (occupancy < minOccupancyCut || occupancy > maxOccupancyCut) { - return; - } - } + if (!isEventAccepted(collision, true)) + return; + + float centrality = getCentralityRun3(collision); + float occupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + rK0sResolution.fill(HIST("hEventCentrality"), centrality); + rK0sResolution.fill(HIST("hEventOccupancy"), occupancy); rK0sResolution.fill(HIST("h1_stats"), 0.5); - for (auto& v0 : fullV0s) { + for (const auto& v0 : fullV0s) { rK0sResolution.fill(HIST("h1_stats"), 1.5); - const auto& posTrack = v0.posTrack_as(); - const auto& negTrack = v0.negTrack_as(); + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); if (!acceptV0(v0, negTrack, posTrack, collision)) continue; rK0sResolution.fill(HIST("h1_stats"), 2.5); float mass = v0.mK0Short(); - if (computeInvMassFromDaughters) { - mass = RecoDecay::m(std::array{std::array{posTrack.px(), posTrack.py(), posTrack.pz()}, - std::array{negTrack.px(), negTrack.py(), negTrack.pz()}}, - std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); - } rK0sResolution.fill(HIST("h2_masspT"), mass, v0.pt()); rK0sResolution.fill(HIST("h2_masseta"), mass, v0.eta()); @@ -452,6 +657,8 @@ struct perfK0sResolution { if (useMultidimHisto) { rK0sResolution.fill(HIST("thn_mass"), mass, v0.pt(), v0.eta(), v0.phi(), posTrack.eta(), negTrack.eta()); } + rK0sResolution.fill(HIST("h3_centralitypTmass"), centrality, v0.pt(), mass); + rK0sResolution.fill(HIST("h3_occupancypTmass"), occupancy, v0.pt(), mass); if (enableTPCPlot) { rK0sDauResolution.fill(HIST("h3_tpc_vs_pid_hypothesis"), posTrack.tpcInnerParam(), posTrack.tpcSignal(), posTrack.pidForTracking()); rK0sDauResolution.fill(HIST("h3_tpc_vs_pid_hypothesis"), -negTrack.tpcInnerParam(), negTrack.tpcSignal(), negTrack.pidForTracking()); @@ -496,14 +703,22 @@ struct perfK0sResolution { o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCovNeg, 2.f, matCorr, &mDcaInfoCovNeg); } - void processMC(soa::Filtered::iterator const& collision, - soa::Filtered> const& fullV0s, + void processMC(SelectedCollisions::iterator const& collision, + soa::Join const& fullV0s, PIDTracksIUMC const&, aod::McParticles const& mcParticles, aod::BCsWithTimestamps const& bcs) { + if (!isEventAccepted(collision, true)) + return; + + float centrality = getCentralityRun3(collision); + float occupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + rK0sResolution.fill(HIST("hEventCentrality"), centrality); + rK0sResolution.fill(HIST("hEventOccupancy"), occupancy); + rK0sResolution.fill(HIST("h1_stats"), 0.5); - for (auto& v0 : fullV0s) { + for (const auto& v0 : fullV0s) { bool daughtersHaveMCParticles = false; bool daughtersCorrRec = false; rK0sResolution.fill(HIST("h1_stats"), 1.5); @@ -516,7 +731,9 @@ struct perfK0sResolution { if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { daughtersHaveMCParticles = true; rK0sResolution.fill(HIST("h1_stats"), 3.5); - if (posTrack.mcParticle().pdgCode() == 211 && negTrack.mcParticle().pdgCode() == -211) { + bool isPositivePion = posTrack.mcParticle().pdgCode() == PDG_t::kPiPlus || (doTreatPiToMuon && posTrack.mcParticle().pdgCode() == PDG_t::kMuonPlus); + bool isNegativePion = negTrack.mcParticle().pdgCode() == PDG_t::kPiMinus || (doTreatPiToMuon && negTrack.mcParticle().pdgCode() == PDG_t::kMuonMinus); + if (isPositivePion && isNegativePion) { daughtersCorrRec = true; rK0sResolution.fill(HIST("h1_stats"), 4.5); } @@ -528,11 +745,6 @@ struct perfK0sResolution { float mass = v0.mK0Short(); - if (computeInvMassFromDaughters) { - mass = RecoDecay::m(std::array{std::array{posTrack.px(), posTrack.py(), posTrack.pz()}, - std::array{negTrack.px(), negTrack.py(), negTrack.pz()}}, - std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); - } if (useTrackTuner && daughtersHaveMCParticles) { std::array pPos{0., 0., 0.}; std::array pNeg{0., 0., 0.}; @@ -543,8 +755,8 @@ struct perfK0sResolution { std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); } - const bool isTrueK0s = (v0.has_mcParticle() && v0.mcParticle().pdgCode() == 310); - if (!isTrueK0s && requireTrueK0s) { + bool isTrueK0s = (v0.has_mcParticle() && std::abs(v0.mcParticle().pdgCode()) == PDG_t::kK0Short && v0.mcParticle().isPhysicalPrimary() && daughtersCorrRec); + if (requireTrueK0s && !isTrueK0s) { continue; } @@ -590,6 +802,8 @@ struct perfK0sResolution { rK0sResolution.fill(HIST("h2_masspT"), mass, v0.pt()); rK0sResolution.fill(HIST("h2_masseta"), mass, v0.eta()); rK0sResolution.fill(HIST("h2_massphi"), mass, v0.phi()); + rK0sResolution.fill(HIST("h3_centralitypTmass"), centrality, v0.pt(), mass); + rK0sResolution.fill(HIST("h3_occupancypTmass"), occupancy, v0.pt(), mass); } } PROCESS_SWITCH(perfK0sResolution, processMC, "Process MC", false); diff --git a/DPG/Tasks/AOTTrack/V0Cascades/qaCascades.cxx b/DPG/Tasks/AOTTrack/V0Cascades/qaCascades.cxx index 4e42b50da2a..2513ad92a91 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/qaCascades.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/qaCascades.cxx @@ -16,20 +16,23 @@ /// \brief QA task for basic quantities on cascades /// -#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/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::framework; diff --git a/DPG/Tasks/AOTTrack/V0Cascades/qaK0sTrackingEfficiency.cxx b/DPG/Tasks/AOTTrack/V0Cascades/qaK0sTrackingEfficiency.cxx index 6ee7c4e7a5c..64b84711d90 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/qaK0sTrackingEfficiency.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/qaK0sTrackingEfficiency.cxx @@ -9,18 +9,21 @@ // 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/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" #include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::framework; diff --git a/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.cxx index d1b20636bea..4fbf9fc68c5 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.cxx @@ -14,23 +14,42 @@ /// \author Carolina Reetz c.reetz@cern.ch /// \brief QA task to study momentum resolution of Lambda daughter tracks -#include +#include "DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/PID.h" -#include "Common/Core/trackUtilities.h" #include "PWGLF/DataModel/LFStrangenessTables.h" -#include "DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/Tools/TrackTuner.h" +#include +#include +#include +#include +#include +#include +#include +#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; @@ -339,7 +358,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); @@ -540,8 +559,8 @@ struct qaLamMomResolution { } } } // end Anti-Lambda - } // end MC - } // end V0 loop + } // end MC + } // end V0 loop } PROCESS_SWITCH(qaLamMomResolution, processMC, "Process MC", true); }; diff --git a/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h b/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h index 603195404d4..7c7d135ac55 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h +++ b/DPG/Tasks/AOTTrack/V0Cascades/qaLamMomResolution.h @@ -14,9 +14,7 @@ #ifndef DPG_TASKS_AOTTRACK_V0CASCADES_QALAMMOMRESOLUTION_H_ #define DPG_TASKS_AOTTRACK_V0CASCADES_QALAMMOMRESOLUTION_H_ -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/Core/trackUtilities.h" +#include namespace o2::aod { diff --git a/DPG/Tasks/AOTTrack/derivedDataCreatorD0Calibration.cxx b/DPG/Tasks/AOTTrack/derivedDataCreatorD0Calibration.cxx new file mode 100644 index 00000000000..a8bd2c6d321 --- /dev/null +++ b/DPG/Tasks/AOTTrack/derivedDataCreatorD0Calibration.cxx @@ -0,0 +1,862 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file derivedDataCreatorD0Calibration.cxx +/// \brief Producer of derived tables of D0 candidates, daughter tracks and collisions for calibration studies +/// +/// \author Fabrizio Grosa , CERN + +#include "D0CalibTables.h" + +#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelectorPID.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/OccupancyTables.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/ML/MlResponse.h" + +#include "CommonDataFormat/InteractionRecord.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +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_calib; + +struct DerivedDataCreatorD0Calibration { + + Produces collTable; + Produces trackTable; + Produces candTable; + + struct : ConfigurableGroup { + Configurable ptMin{"ptMin", 0.4, "min. track pT"}; + Configurable absEtaMax{"absEtaMax", 1., "max. track absolute eta"}; + Configurable> binsPt{"binsPt", std::vector{hf_calib::vecBinsPtTrack}, "track pT bin limits for DCA pT-dependent cut"}; + Configurable> limitsDca{"limitsDca", {hf_calib::CutsTrack[0], hf_calib::NBinsPtTrack, hf_calib::NCutVarsTrack, hf_calib::labelsPtTrack, hf_calib::labelsCutVarTrack}, "Single-track selections per pT bin"}; + // TPC PID + Configurable ptPidTpcMin{"ptPidTpcMin", 0., "Lower bound of track pT for TPC PID"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 1000., "Upper bound of track pT for TPC PID"}; + Configurable nSigmaTpcMax{"nSigmaTpcMax", 3., "Nsigma cut on TPC only"}; + Configurable usePidTpcOnly{"usePidTpcOnly", false, "Only use TPC PID"}; + // TOF PID + Configurable ptPidTofMin{"ptPidTofMin", 0., "Lower bound of track pT for TOF PID"}; + Configurable ptPidTofMax{"ptPidTofMax", 1000., "Upper bound of track pT for TOF PID"}; + Configurable nSigmaTofMax{"nSigmaTofMax", 3., "Nsigma cut on TOF only"}; + std::string prefix = "trackCuts"; + } cfgTrackCuts; + + struct : ConfigurableGroup { + Configurable ptMin{"ptMin", 0., "min. D0-candidate pT"}; + Configurable> binsPt{"binsPt", std::vector{hf_calib::vecBinsPtCand}, "pT bin limits"}; + Configurable> topologicalCuts{"topologicalCuts", {hf_calib::CutsCand[0], hf_calib::NBinsPtCand, hf_calib::NCutVarsCand, hf_calib::labelsPtCand, hf_calib::labelsCutVarCand}, "D0 candidate selection per pT bin"}; + std::string prefix = "candidateCuts"; + } cfgCandCuts; + + struct : ConfigurableGroup { + Configurable apply{"apply", false, "flag to apply downsampling"}; + Configurable pathCcdbWeights{"pathCcdbWeights", "", "CCDB path containing pT-differential weights"}; + std::string prefix = "downsampling"; + } cfgDownsampling; + + struct : ConfigurableGroup { + Configurable apply{"apply", false, "flag to apply downsampling"}; + Configurable> binsPt{"binsPt", std::vector{hf_calib::vecBinsPtMl}, "pT bin limits for ML models inference"}; + Configurable> thresholdMlScores{"thresholdMlScores", {hf_calib::CutsMl[0], hf_calib::NBinsPtMl, 3, hf_calib::labelsPtMl, hf_calib::labelsCutMl}, "Threshold values for Ml output scores of D0 candidates"}; + Configurable loadMlModelsFromCCDB{"loadMlModelsFromCCDB", true, "Flag to enable or disable the loading of ML models from CCDB"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/f/fgrosa/D0Calib/BDT/Pt0_1"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_pT_0_1.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + std::string prefix = "ml"; + } cfgMl; + + using TracksWCovExtraPid = soa::Join; + using TracksWCovExtraPidAndQa = soa::Join; + using CollisionsWEvSel = soa::Join; + using TrackMeanOccs = soa::Join; + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + + o2::vertexing::DCAFitterN<2> df; // 2-prong vertex fitter + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + o2::analysis::MlResponse mlResponse; + + TrackSelectorPi selectorPion; + TrackSelectorKa selectorKaon; + + int runNumber{0}; + double bz{0.}; + const float zVtxMax{10.f}; + // tolerances for preselections before vertex reconstruction + const float ptTolerance{0.1f}; + const float invMassTolerance{0.05f}; + uint32_t precisionCovMask{0xFFFFE000}; // 10 bits + uint32_t precisionDcaMask{0xFFFFFC00}; // 13 bits + + OutputObj histDownSampl{"histDownSampl"}; + + void init(InitContext const&) + { + // First we set the CCDB manager + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + if (cfgDownsampling.apply) { + histDownSampl.setObject(reinterpret_cast(ccdb->getSpecific(cfgDownsampling.pathCcdbWeights))); + } + + if (cfgMl.apply) { + std::vector cutDir = {o2::cuts_ml::CutDirection::CutGreater, o2::cuts_ml::CutDirection::CutSmaller, o2::cuts_ml::CutDirection::CutSmaller}; + mlResponse.configure(cfgMl.binsPt, cfgMl.thresholdMlScores, cutDir, 3); + if (cfgMl.loadMlModelsFromCCDB) { + ccdbApi.init("http://alice-ccdb.cern.ch"); + mlResponse.setModelPathsCCDB(cfgMl.onnxFileNames, ccdbApi, cfgMl.modelPathsCCDB, -1); + } else { + mlResponse.setModelPathsLocal(cfgMl.onnxFileNames); + } + mlResponse.init(); + } + + df.setPropagateToPCA(true); + df.setMaxR(200.f); + df.setMaxDZIni(4.f); + df.setMinParamChange(1.e-3f); + df.setMinRelChi2Change(0.9f); + df.setUseAbsDCA(false); + df.setWeightedFinalPCA(false); + df.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); // we are always inside the beampipe + + selectorPion.setRangePtTpc(cfgTrackCuts.ptPidTpcMin, cfgTrackCuts.ptPidTpcMax); + selectorPion.setRangeNSigmaTpc(-cfgTrackCuts.nSigmaTpcMax, cfgTrackCuts.nSigmaTpcMax); + selectorPion.setRangePtTof(cfgTrackCuts.ptPidTofMin, cfgTrackCuts.ptPidTofMax); + selectorPion.setRangeNSigmaTof(-cfgTrackCuts.nSigmaTofMax, cfgTrackCuts.nSigmaTofMax); + selectorKaon = selectorPion; + } + + // main function + template + void runDataCreation(CollisionsWEvSel const& collisions, + aod::TrackAssoc const& trackIndices, + TTracks const&, + aod::BCsWithTimestamps const&, + TrackMeanOccs const&, + TTrackQa const&) + { + std::map selectedCollisions; // map with indices of selected collisions (key: original AOD Collision table index, value: D0 collision index) + std::map selectedTracks; // map with indices of selected tracks (key: original AOD Track table index, value: D0 daughter track index) + + for (auto const& collision : collisions) { + + // minimal event selection + if (!collision.sel8()) { + continue; + } + auto primaryVertex = getPrimaryVertex(collision); + if (std::abs(primaryVertex.getZ()) > zVtxMax) { + continue; + } + + auto covMatrixPV = primaryVertex.getCov(); + + auto bc = collision.template bc_as(); + if (runNumber != bc.runNumber()) { + initCCDB(bc, runNumber, ccdb, "GLO/Config/GRPMagField", nullptr, false); + bz = o2::base::Propagator::Instance()->getNominalBz(); + } + o2::InteractionRecord eventIR; + eventIR.setFromLong(bc.globalBC()); + + auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (auto const& trackIndexPos : groupedTrackIndices) { + auto trackPos = trackIndexPos.template track_as(); + // track selections + if (trackPos.sign() < 0) { // first positive track + continue; + } + if (!trackPos.isGlobalTrackWoDCA()) { + continue; + } + if (trackPos.pt() < cfgTrackCuts.ptMin) { + continue; + } + if (std::abs(trackPos.eta()) > cfgTrackCuts.absEtaMax) { + continue; + } + auto trackParCovPos = getTrackParCov(trackPos); + o2::dataformats::DCA dcaPos; + trackParCovPos.propagateToDCA(primaryVertex, bz, &dcaPos); + if (!isSelectedTrackDca(cfgTrackCuts.binsPt, cfgTrackCuts.limitsDca, trackParCovPos.getPt(), dcaPos.getY(), dcaPos.getZ())) { + continue; + } + + int pidTrackPosKaon{-1}; + int pidTrackPosPion{-1}; + if (cfgTrackCuts.usePidTpcOnly) { + /// kaon TPC PID positive daughter + pidTrackPosKaon = selectorKaon.statusTpc(trackPos); + /// pion TPC PID positive daughter + pidTrackPosPion = selectorPion.statusTpc(trackPos); + } else { + /// kaon TPC, TOF PID positive daughter + pidTrackPosKaon = selectorKaon.statusTpcAndTof(trackPos); + /// pion TPC, TOF PID positive daughter + pidTrackPosPion = selectorPion.statusTpcAndTof(trackPos); + } + + for (auto const& trackIndexNeg : groupedTrackIndices) { + auto trackNeg = trackIndexNeg.template track_as(); + // track selections + if (trackNeg.sign() > 0) { // second negative track + continue; + } + if (!trackNeg.isGlobalTrackWoDCA()) { + continue; + } + if (trackNeg.pt() < cfgTrackCuts.ptMin) { + continue; + } + if (std::abs(trackNeg.eta()) > cfgTrackCuts.absEtaMax) { + continue; + } + auto trackParCovNeg = getTrackParCov(trackNeg); + o2::dataformats::DCA dcaNeg; + trackParCovNeg.propagateToDCA(primaryVertex, bz, &dcaNeg); + if (!isSelectedTrackDca(cfgTrackCuts.binsPt, cfgTrackCuts.limitsDca, trackParCovNeg.getPt(), dcaNeg.getY(), dcaNeg.getZ())) { + continue; + } + + int pidTrackNegKaon{-1}; + int pidTrackNegPion{-1}; + if (cfgTrackCuts.usePidTpcOnly) { + /// kaon TPC PID negative daughter + pidTrackNegKaon = selectorKaon.statusTpc(trackNeg); + /// pion TPC PID negative daughter + pidTrackNegPion = selectorPion.statusTpc(trackNeg); + } else { + /// kaon TPC, TOF PID negative daughter + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg); + /// pion TPC, TOF PID negative daughter + pidTrackNegPion = selectorPion.statusTpcAndTof(trackNeg); + } + + // preselections + // PID + uint8_t massHypo{D0MassHypo::D0AndD0Bar}; // both mass hypotheses a priori + if (pidTrackPosPion == TrackSelectorPID::Rejected || pidTrackNegKaon == TrackSelectorPID::Rejected) { + massHypo -= D0MassHypo::D0; // exclude D0 + } + if (pidTrackNegPion == TrackSelectorPID::Rejected || pidTrackPosKaon == TrackSelectorPID::Rejected) { + massHypo -= D0MassHypo::D0Bar; // exclude D0Bar + } + if (massHypo == 0) { + continue; + } + + // pt + std::array pVecNoVtxD0 = RecoDecay::pVec(trackPos.pVector(), trackNeg.pVector()); + float ptNoVtxD0 = RecoDecay::pt(pVecNoVtxD0); + if (ptNoVtxD0 - ptTolerance < cfgCandCuts.ptMin) { + continue; + } + int ptBinNoVtxD0 = findBin(cfgTrackCuts.binsPt, ptNoVtxD0 + ptTolerance); // assuming tighter selections at lower pT + if (ptBinNoVtxD0 < 0) { + continue; + } + + // d0xd0 + if (dcaPos.getY() * dcaNeg.getY() > cfgCandCuts.topologicalCuts->get(ptBinNoVtxD0, "max d0d0")) { + continue; + } + + // invariant mass + if (massHypo == D0MassHypo::D0 || massHypo == D0MassHypo::D0AndD0Bar) { + float invMassNoVtxD0 = RecoDecay::m(std::array{trackPos.pVector(), trackNeg.pVector()}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}); + if (std::abs(invMassNoVtxD0 - o2::constants::physics::MassD0) > cfgCandCuts.topologicalCuts->get(ptBinNoVtxD0, "delta inv. mass") + invMassTolerance) { + massHypo -= D0MassHypo::D0; + } + } + if (massHypo >= D0MassHypo::D0Bar) { + float invMassNoVtxD0bar = RecoDecay::m(std::array{trackNeg.pVector(), trackPos.pVector()}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}); + if (std::abs(invMassNoVtxD0bar - o2::constants::physics::MassD0) > cfgCandCuts.topologicalCuts->get(ptBinNoVtxD0, "delta inv. mass") + invMassTolerance) { + massHypo -= D0MassHypo::D0Bar; + } + } + if (massHypo == 0) { + continue; + } + + // reconstruct vertex + if (df.process(trackParCovPos, trackParCovNeg) == 0) { + continue; + } + const auto& secondaryVertex = df.getPCACandidate(); + auto chi2PCA = df.getChi2AtPCACandidate(); + auto covMatrixPCA = df.calcPCACovMatrixFlat(); + auto trackParAtSecVtxPos = df.getTrack(0); + auto trackParAtSecVtxNeg = df.getTrack(1); + + std::array pVecPos{}; + std::array pVecNeg{}; + trackParAtSecVtxPos.getPxPyPzGlo(pVecPos); + trackParAtSecVtxNeg.getPxPyPzGlo(pVecNeg); + std::array pVecD0 = RecoDecay::pVec(pVecPos, pVecNeg); + + // select D0 + // pt + float ptD0 = RecoDecay::pt(pVecD0); + if (ptD0 < cfgCandCuts.ptMin) { + continue; + } + int ptBinD0 = findBin(cfgTrackCuts.binsPt, ptD0); + if (ptBinD0 < 0) { + continue; + } + + // random downsampling already here + if (cfgDownsampling.apply) { + int ptBinWeights{0}; + if (ptD0 < histDownSampl->GetBinLowEdge(1)) { + ptBinWeights = 1; + } else if (ptD0 > histDownSampl->GetXaxis()->GetBinUpEdge(histDownSampl->GetNbinsX())) { + ptBinWeights = histDownSampl->GetNbinsX(); + } else { + ptBinWeights = histDownSampl->GetXaxis()->FindBin(ptD0); + } + float weight = histDownSampl->GetBinContent(ptBinWeights); + if (gRandom->Rndm() > weight) { + continue; + } + } + + // d0xd0 + if (dcaPos.getY() * dcaNeg.getY() > cfgCandCuts.topologicalCuts->get(ptBinD0, "max d0d0")) { + continue; + } + // cospa + float cosPaD0 = RecoDecay::cpa(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, secondaryVertex, pVecD0); + if (cosPaD0 < cfgCandCuts.topologicalCuts->get(ptBinD0, "min cos pointing angle")) { + continue; + } + // pointing angle + float paD0 = std::acos(cosPaD0); + if (paD0 > cfgCandCuts.topologicalCuts->get(ptBinD0, "max pointing angle")) { + continue; + } + // cospa XY + float cosPaXYD0 = RecoDecay::cpaXY(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, secondaryVertex, pVecD0); + if (cosPaXYD0 < cfgCandCuts.topologicalCuts->get(ptBinD0, "min cos pointing angle XY")) { + continue; + } + // pointing angle XY + float paXYD0 = std::acos(cosPaXYD0); + if (paXYD0 > cfgCandCuts.topologicalCuts->get(ptBinD0, "max pointing angle XY")) { + continue; + } + // decay length + float decLenD0 = RecoDecay::distance(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, secondaryVertex); + if (decLenD0 < cfgCandCuts.topologicalCuts->get(ptBinD0, "min decay length")) { + continue; + } + // decay length XY + float decLenXYD0 = RecoDecay::distanceXY(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, secondaryVertex); + if (decLenXYD0 < cfgCandCuts.topologicalCuts->get(ptBinD0, "min decay length XY")) { + continue; + } + // normalised decay length + float phi{0.f}, theta{0.f}; + getPointDirection(std::array{primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, secondaryVertex, phi, theta); + float errorDecayLengthD0 = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + if (decLenD0 / errorDecayLengthD0 < cfgCandCuts.topologicalCuts->get(ptBinD0, "min norm decay length")) { + continue; + } + // normalised decay length XY + float errorDecayLengthXYD0 = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.f) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.f)); + if (decLenXYD0 / errorDecayLengthXYD0 < cfgCandCuts.topologicalCuts->get(ptBinD0, "min norm decay length XY")) { + continue; + } + + float invMassD0{0.f}, invMassD0bar{0.f}; + std::vector bdtScoresD0{0.f, 1.f, 1.f}, bdtScoresD0bar{0.f, 1.f, 1.f}; // always selected a priori + if (massHypo == D0MassHypo::D0 || massHypo == D0MassHypo::D0AndD0Bar) { + invMassD0 = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}); + if (std::abs(invMassD0 - o2::constants::physics::MassD0) > cfgCandCuts.topologicalCuts->get(ptBinD0, "delta inv. mass")) { + massHypo -= D0MassHypo::D0; + bdtScoresD0 = std::vector{1.f, 0.f, 0.f}; + } else { + // apply BDT models + if (cfgMl.apply) { + std::vector featuresCandD0 = {dcaPos.getY(), dcaNeg.getY(), chi2PCA, cosPaD0, cosPaXYD0, decLenXYD0, decLenD0, dcaPos.getY() * dcaNeg.getY(), aod::pid_tpc_tof_utils::combineNSigma(trackPos.tpcNSigmaPi(), trackPos.tofNSigmaPi()), aod::pid_tpc_tof_utils::combineNSigma(trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaKa()), trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma(trackPos.tpcNSigmaKa(), trackPos.tofNSigmaKa()), trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma(trackNeg.tpcNSigmaPi(), trackNeg.tofNSigmaPi())}; + if (!mlResponse.isSelectedMl(featuresCandD0, ptD0, bdtScoresD0)) { + massHypo -= D0MassHypo::D0; + } + } + } + } + if (massHypo >= D0MassHypo::D0Bar) { + invMassD0bar = RecoDecay::m(std::array{pVecNeg, pVecPos}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}); + if (std::abs(invMassD0bar - o2::constants::physics::MassD0) > cfgCandCuts.topologicalCuts->get(ptBinD0, "delta inv. mass")) { + massHypo -= D0MassHypo::D0Bar; + bdtScoresD0bar = std::vector{1.f, 0.f, 0.f}; + } else { + // apply BDT models + if (cfgMl.apply) { + std::vector featuresCandD0bar = {dcaPos.getY(), dcaNeg.getY(), chi2PCA, cosPaD0, cosPaXYD0, decLenXYD0, decLenD0, dcaPos.getY() * dcaNeg.getY(), aod::pid_tpc_tof_utils::combineNSigma(trackNeg.tpcNSigmaPi(), trackNeg.tofNSigmaPi()), aod::pid_tpc_tof_utils::combineNSigma(trackPos.tpcNSigmaKa(), trackPos.tofNSigmaKa()), trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma(trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaKa()), trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma(trackPos.tpcNSigmaPi(), trackPos.tofNSigmaPi())}; + if (!mlResponse.isSelectedMl(featuresCandD0bar, ptD0, bdtScoresD0bar)) { + massHypo -= D0MassHypo::D0Bar; + } + } + } + } + if (massHypo == 0) { + continue; + } + + float etaD0 = RecoDecay::eta(pVecD0); + float phiD0 = RecoDecay::phi(pVecD0); + + // fill tables + // collision + if (!selectedCollisions.count(collision.globalIndex())) { + // fill collision table if not yet present + collTable(collision.posX(), + collision.posY(), + collision.posZ(), + collision.covXX(), + collision.covXY(), + collision.covXZ(), + collision.covYY(), + collision.covYZ(), + collision.covZZ(), + collision.numContrib(), + uint8_t(std::round(collision.centFT0C())), + getCompressedOccupancy(collision.trackOccupancyInTimeRange()), + getCompressedOccupancy(collision.ft0cOccupancyInTimeRange()), + eventIR.orbit, + runNumber); + selectedCollisions[collision.globalIndex()] = collTable.lastIndex(); + } + // tracks + if (!selectedTracks.count(trackPos.globalIndex())) { + // fill track table with positive track if not yet present + uint8_t tmoPrimUnfm80{0u}; + uint8_t tmoFV0AUnfm80{0u}; + uint8_t tmoFT0AUnfm80{0u}; + uint8_t tmoFT0CUnfm80{0u}; + uint8_t twmoPrimUnfm80{0u}; + uint8_t twmoFV0AUnfm80{0u}; + uint8_t twmoFT0AUnfm80{0u}; + uint8_t twmoFT0CUnfm80{0u}; + uint8_t tmoRobustT0V0PrimUnfm80{0u}; + uint8_t twmoRobustT0V0PrimUnfm80{0u}; + if (trackPos.has_tmo()) { + auto tmoFromTrack = trackPos.template tmo_as(); // obtain track mean occupancies + tmoPrimUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoPrimUnfm80()); + tmoFV0AUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoFV0AUnfm80()); + tmoFT0AUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoFT0AUnfm80()); + tmoFT0CUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoFT0CUnfm80()); + twmoPrimUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoPrimUnfm80()); + twmoFV0AUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoFV0AUnfm80()); + twmoFT0AUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoFT0AUnfm80()); + twmoFT0CUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoFT0CUnfm80()); + tmoRobustT0V0PrimUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoRobustT0V0PrimUnfm80()); + twmoRobustT0V0PrimUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoRobustT0V0PrimUnfm80()); + } + float tpcTime0{0.f}; + float tpcdEdxNorm{0.f}; + int16_t tpcDcaR{0}; + int16_t tpcDcaZ{0}; + uint8_t tpcClusterByteMask{0u}; + uint8_t tpcdEdxMax0R{0u}; + uint8_t tpcdEdxMax1R{0u}; + uint8_t tpcdEdxMax2R{0u}; + uint8_t tpcdEdxMax3R{0u}; + uint8_t tpcdEdxTot0R{0u}; + uint8_t tpcdEdxTot1R{0u}; + uint8_t tpcdEdxTot2R{0u}; + uint8_t tpcdEdxTot3R{0u}; + int8_t deltaRefContParamY{0}; + int8_t deltaRefITSParamZ{0}; + int8_t deltaRefContParamSnp{0}; + int8_t deltaRefContParamTgl{0}; + int8_t deltaRefContParamQ2Pt{0}; + int8_t deltaRefGloParamY{0}; + int8_t deltaRefGloParamZ{0}; + int8_t deltaRefGloParamSnp{0}; + int8_t deltaRefGloParamTgl{0}; + int8_t deltaRefGloParamQ2Pt{0}; + int8_t deltaTOFdX{0}; + int8_t deltaTOFdZ{0}; + if constexpr (withTrackQa) { + if (trackPos.has_trackQA()) { + auto trackQA = trackPos.template trackQA_as(); // obtain track QA + tpcTime0 = trackQA.tpcTime0(); + tpcdEdxNorm = trackQA.tpcdEdxNorm(); + tpcDcaR = trackQA.tpcdcaR(); + tpcDcaZ = trackQA.tpcdcaZ(); + tpcClusterByteMask = trackQA.tpcClusterByteMask(); + tpcdEdxMax0R = trackQA.tpcdEdxMax0R(); + tpcdEdxMax1R = trackQA.tpcdEdxMax1R(); + tpcdEdxMax2R = trackQA.tpcdEdxMax2R(); + tpcdEdxMax3R = trackQA.tpcdEdxMax3R(); + tpcdEdxTot0R = trackQA.tpcdEdxTot0R(); + tpcdEdxTot1R = trackQA.tpcdEdxTot1R(); + tpcdEdxTot2R = trackQA.tpcdEdxTot2R(); + tpcdEdxTot3R = trackQA.tpcdEdxTot3R(); + deltaRefContParamY = trackQA.deltaRefContParamY(); + deltaRefITSParamZ = trackQA.deltaRefITSParamZ(); + deltaRefContParamSnp = trackQA.deltaRefContParamSnp(); + deltaRefContParamTgl = trackQA.deltaRefContParamTgl(); + deltaRefContParamQ2Pt = trackQA.deltaRefContParamQ2Pt(); + deltaRefGloParamY = trackQA.deltaRefGloParamY(); + deltaRefGloParamZ = trackQA.deltaRefGloParamZ(); + deltaRefGloParamSnp = trackQA.deltaRefGloParamSnp(); + deltaRefGloParamTgl = trackQA.deltaRefGloParamTgl(); + deltaRefGloParamQ2Pt = trackQA.deltaRefGloParamQ2Pt(); + deltaTOFdX = trackQA.deltaTOFdX(); + deltaTOFdZ = trackQA.deltaTOFdZ(); + } + } + + trackTable(selectedCollisions[collision.globalIndex()], // stored at PV + trackPos.x(), + trackPos.alpha(), + trackPos.y(), + trackPos.z(), + trackPos.snp(), + trackPos.tgl(), + trackPos.signed1Pt(), + o2::math_utils::detail::truncateFloatFraction(trackPos.cYY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cZY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cZZ(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cSnpY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cSnpZ(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cSnpSnp(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cTglY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cTglZ(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cTglSnp(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.cTglTgl(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.c1PtY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.c1PtZ(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.c1PtSnp(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.c1PtTgl(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackPos.c1Pt21Pt2(), precisionCovMask), + trackPos.tpcInnerParam(), + trackPos.flags(), + trackPos.itsClusterSizes(), + trackPos.tpcNClsFindable(), + trackPos.tpcNClsFindableMinusFound(), + trackPos.tpcNClsFindableMinusCrossedRows(), + trackPos.tpcNClsShared(), + trackPos.trdPattern(), + getCompressedChi2(trackPos.itsChi2NCl()), + getCompressedChi2(trackPos.tpcChi2NCl()), + getCompressedChi2(trackPos.trdChi2()), + getCompressedChi2(trackPos.tofChi2()), + trackPos.tpcSignal(), + trackPos.trdSignal(), + trackPos.length(), + trackPos.tofExpMom(), + trackPos.trackTime(), + trackPos.trackTimeRes(), + tpcTime0, + tpcdEdxNorm, + tpcDcaR, + tpcDcaZ, + tpcClusterByteMask, + tpcdEdxMax0R, + tpcdEdxMax1R, + tpcdEdxMax2R, + tpcdEdxMax3R, + tpcdEdxTot0R, + tpcdEdxTot1R, + tpcdEdxTot2R, + tpcdEdxTot3R, + deltaRefContParamY, + deltaRefITSParamZ, + deltaRefContParamSnp, + deltaRefContParamTgl, + deltaRefContParamQ2Pt, + deltaRefGloParamY, + deltaRefGloParamZ, + deltaRefGloParamSnp, + deltaRefGloParamTgl, + deltaRefGloParamQ2Pt, + deltaTOFdX, + deltaTOFdZ, + o2::math_utils::detail::truncateFloatFraction(dcaPos.getY(), precisionDcaMask), + o2::math_utils::detail::truncateFloatFraction(dcaPos.getZ(), precisionDcaMask), + getCompressedNumSigmaPid(trackPos.tpcNSigmaPi()), + getCompressedNumSigmaPid(trackPos.tpcNSigmaKa()), + getCompressedNumSigmaPid(trackPos.tofNSigmaPi()), + getCompressedNumSigmaPid(trackPos.tofNSigmaKa()), + tmoPrimUnfm80, + tmoFV0AUnfm80, + tmoFT0AUnfm80, + tmoFT0CUnfm80, + twmoPrimUnfm80, + twmoFV0AUnfm80, + twmoFT0AUnfm80, + twmoFT0CUnfm80, + tmoRobustT0V0PrimUnfm80, + twmoRobustT0V0PrimUnfm80); + selectedTracks[trackPos.globalIndex()] = trackTable.lastIndex(); + } + if (!selectedTracks.count(trackNeg.globalIndex())) { + // fill track table with negative track if not yet present + uint8_t tmoPrimUnfm80{0u}; + uint8_t tmoFV0AUnfm80{0u}; + uint8_t tmoFT0AUnfm80{0u}; + uint8_t tmoFT0CUnfm80{0u}; + uint8_t twmoPrimUnfm80{0u}; + uint8_t twmoFV0AUnfm80{0u}; + uint8_t twmoFT0AUnfm80{0u}; + uint8_t twmoFT0CUnfm80{0u}; + uint8_t tmoRobustT0V0PrimUnfm80{0u}; + uint8_t twmoRobustT0V0PrimUnfm80{0u}; + if (trackNeg.has_tmo()) { + auto tmoFromTrack = trackNeg.template tmo_as(); // obtain track mean occupancies + tmoPrimUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoPrimUnfm80()); + tmoFV0AUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoFV0AUnfm80()); + tmoFT0AUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoFT0AUnfm80()); + tmoFT0CUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoFT0CUnfm80()); + twmoPrimUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoPrimUnfm80()); + twmoFV0AUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoFV0AUnfm80()); + twmoFT0AUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoFT0AUnfm80()); + twmoFT0CUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoFT0CUnfm80()); + tmoRobustT0V0PrimUnfm80 = getCompressedOccupancy(tmoFromTrack.tmoRobustT0V0PrimUnfm80()); + twmoRobustT0V0PrimUnfm80 = getCompressedOccupancy(tmoFromTrack.twmoRobustT0V0PrimUnfm80()); + } + float tpcTime0{0.f}; + float tpcdEdxNorm{0.f}; + int16_t tpcDcaR{0}; + int16_t tpcDcaZ{0}; + uint8_t tpcClusterByteMask{0u}; + uint8_t tpcdEdxMax0R{0u}; + uint8_t tpcdEdxMax1R{0u}; + uint8_t tpcdEdxMax2R{0u}; + uint8_t tpcdEdxMax3R{0u}; + uint8_t tpcdEdxTot0R{0u}; + uint8_t tpcdEdxTot1R{0u}; + uint8_t tpcdEdxTot2R{0u}; + uint8_t tpcdEdxTot3R{0u}; + int8_t deltaRefContParamY{0}; + int8_t deltaRefITSParamZ{0}; + int8_t deltaRefContParamSnp{0}; + int8_t deltaRefContParamTgl{0}; + int8_t deltaRefContParamQ2Pt{0}; + int8_t deltaRefGloParamY{0}; + int8_t deltaRefGloParamZ{0}; + int8_t deltaRefGloParamSnp{0}; + int8_t deltaRefGloParamTgl{0}; + int8_t deltaRefGloParamQ2Pt{0}; + int8_t deltaTOFdX{0}; + int8_t deltaTOFdZ{0}; + if constexpr (withTrackQa) { + if (trackNeg.has_trackQA()) { + auto trackQA = trackNeg.template trackQA_as(); // obtain track QA + tpcTime0 = trackQA.tpcTime0(); + tpcdEdxNorm = trackQA.tpcdEdxNorm(); + tpcDcaR = trackQA.tpcdcaR(); + tpcDcaZ = trackQA.tpcdcaZ(); + tpcClusterByteMask = trackQA.tpcClusterByteMask(); + tpcdEdxMax0R = trackQA.tpcdEdxMax0R(); + tpcdEdxMax1R = trackQA.tpcdEdxMax1R(); + tpcdEdxMax2R = trackQA.tpcdEdxMax2R(); + tpcdEdxMax3R = trackQA.tpcdEdxMax3R(); + tpcdEdxTot0R = trackQA.tpcdEdxTot0R(); + tpcdEdxTot1R = trackQA.tpcdEdxTot1R(); + tpcdEdxTot2R = trackQA.tpcdEdxTot2R(); + tpcdEdxTot3R = trackQA.tpcdEdxTot3R(); + deltaRefContParamY = trackQA.deltaRefContParamY(); + deltaRefITSParamZ = trackQA.deltaRefITSParamZ(); + deltaRefContParamSnp = trackQA.deltaRefContParamSnp(); + deltaRefContParamTgl = trackQA.deltaRefContParamTgl(); + deltaRefContParamQ2Pt = trackQA.deltaRefContParamQ2Pt(); + deltaRefGloParamY = trackQA.deltaRefGloParamY(); + deltaRefGloParamZ = trackQA.deltaRefGloParamZ(); + deltaRefGloParamSnp = trackQA.deltaRefGloParamSnp(); + deltaRefGloParamTgl = trackQA.deltaRefGloParamTgl(); + deltaRefGloParamQ2Pt = trackQA.deltaRefGloParamQ2Pt(); + deltaTOFdX = trackQA.deltaTOFdX(); + deltaTOFdZ = trackQA.deltaTOFdZ(); + } + } + + trackTable(selectedCollisions[collision.globalIndex()], // stored at PV + trackNeg.x(), + trackNeg.alpha(), + trackNeg.y(), + trackNeg.z(), + trackNeg.snp(), + trackNeg.tgl(), + trackNeg.signed1Pt(), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cYY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cZY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cZZ(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cSnpY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cSnpZ(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cSnpSnp(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cTglY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cTglZ(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cTglSnp(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.cTglTgl(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.c1PtY(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.c1PtZ(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.c1PtSnp(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.c1PtTgl(), precisionCovMask), + o2::math_utils::detail::truncateFloatFraction(trackNeg.c1Pt21Pt2(), precisionCovMask), + trackNeg.tpcInnerParam(), + trackNeg.flags(), + trackNeg.itsClusterSizes(), + trackNeg.tpcNClsFindable(), + trackNeg.tpcNClsFindableMinusFound(), + trackNeg.tpcNClsFindableMinusCrossedRows(), + trackNeg.tpcNClsShared(), + trackNeg.trdPattern(), + getCompressedChi2(trackNeg.itsChi2NCl()), + getCompressedChi2(trackNeg.tpcChi2NCl()), + getCompressedChi2(trackNeg.trdChi2()), + getCompressedChi2(trackNeg.tofChi2()), + trackNeg.tpcSignal(), + trackNeg.trdSignal(), + trackNeg.length(), + trackNeg.tofExpMom(), + trackNeg.trackTime(), + trackNeg.trackTimeRes(), + tpcTime0, + tpcdEdxNorm, + tpcDcaR, + tpcDcaZ, + tpcClusterByteMask, + tpcdEdxMax0R, + tpcdEdxMax1R, + tpcdEdxMax2R, + tpcdEdxMax3R, + tpcdEdxTot0R, + tpcdEdxTot1R, + tpcdEdxTot2R, + tpcdEdxTot3R, + deltaRefContParamY, + deltaRefITSParamZ, + deltaRefContParamSnp, + deltaRefContParamTgl, + deltaRefContParamQ2Pt, + deltaRefGloParamY, + deltaRefGloParamZ, + deltaRefGloParamSnp, + deltaRefGloParamTgl, + deltaRefGloParamQ2Pt, + deltaTOFdX, + deltaTOFdZ, + o2::math_utils::detail::truncateFloatFraction(dcaNeg.getY(), precisionDcaMask), + o2::math_utils::detail::truncateFloatFraction(dcaNeg.getZ(), precisionDcaMask), + getCompressedNumSigmaPid(trackNeg.tpcNSigmaPi()), + getCompressedNumSigmaPid(trackNeg.tpcNSigmaKa()), + getCompressedNumSigmaPid(trackNeg.tofNSigmaPi()), + getCompressedNumSigmaPid(trackNeg.tofNSigmaKa()), + tmoPrimUnfm80, + tmoFV0AUnfm80, + tmoFT0AUnfm80, + tmoFT0CUnfm80, + twmoPrimUnfm80, + twmoFV0AUnfm80, + twmoFT0AUnfm80, + twmoFT0CUnfm80, + tmoRobustT0V0PrimUnfm80, + twmoRobustT0V0PrimUnfm80); + selectedTracks[trackNeg.globalIndex()] = trackTable.lastIndex(); + } + + // candidate + candTable(selectedCollisions[collision.globalIndex()], + selectedTracks[trackPos.globalIndex()], + selectedTracks[trackNeg.globalIndex()], + massHypo, + ptD0, + etaD0, + phiD0, + invMassD0, + invMassD0bar, + getCompressedDecayLength(decLenD0), + getCompressedDecayLength(decLenXYD0), + getCompressedNormDecayLength(decLenD0 / errorDecayLengthD0), + getCompressedNormDecayLength(decLenXYD0 / errorDecayLengthXYD0), + getCompressedCosPa(cosPaD0), + getCompressedCosPa(cosPaXYD0), + getCompressedPointingAngle(paD0), + getCompressedPointingAngle(paXYD0), + getCompressedChi2(chi2PCA), + getCompressedBdtScoreBkg(bdtScoresD0[0]), + getCompressedBdtScoreSgn(bdtScoresD0[1]), + getCompressedBdtScoreSgn(bdtScoresD0[2]), + getCompressedBdtScoreBkg(bdtScoresD0bar[0]), + getCompressedBdtScoreSgn(bdtScoresD0bar[1]), + getCompressedBdtScoreSgn(bdtScoresD0bar[2])); + } // end loop over negative tracks + } // end loop over positive tracks + } // end loop over collisions tracks + } + + // process functions + void processWithTrackQa(CollisionsWEvSel const& collisions, + aod::TrackAssoc const& trackIndices, + TracksWCovExtraPidAndQa const& tracks, + aod::BCsWithTimestamps const& bcs, + TrackMeanOccs const& occ, + aod::TracksQAVersion const& trackQa) + { + runDataCreation(collisions, trackIndices, tracks, bcs, occ, trackQa); + } + PROCESS_SWITCH(DerivedDataCreatorD0Calibration, processWithTrackQa, "Process with trackQA enabled", false); + + void processNoTrackQa(CollisionsWEvSel const& collisions, + aod::TrackAssoc const& trackIndices, + TracksWCovExtraPid const& tracks, + aod::BCsWithTimestamps const& bcs, + TrackMeanOccs const& occ) + { + runDataCreation(collisions, trackIndices, tracks, bcs, occ, nullptr); + } + PROCESS_SWITCH(DerivedDataCreatorD0Calibration, processNoTrackQa, "Process without trackQA enabled", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTTrack/qaDcaMC.cxx b/DPG/Tasks/AOTTrack/qaDcaMC.cxx index a71bbff8dcd..4054c59b33a 100644 --- a/DPG/Tasks/AOTTrack/qaDcaMC.cxx +++ b/DPG/Tasks/AOTTrack/qaDcaMC.cxx @@ -110,7 +110,8 @@ struct QaDcaMc { 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 dcaBins{"dcaBins", {2000, -1.f, 1.f}, "DCA 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 @@ -149,8 +150,8 @@ struct QaDcaMc { const AxisSpec axisEta{etaBins, "#it{#eta}"}; const AxisSpec axisY{yBins, "#it{y}"}; const AxisSpec axisPhi{phiBins, "#it{#varphi} (rad)"}; - const AxisSpec axisDCAxy{dcaBins, "DCA_{xy} (cm)"}; - const AxisSpec axisDCAz{dcaBins, "DCA_{z} (cm)"}; + 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; diff --git a/DPG/Tasks/AOTTrack/qaEfficiency.cxx b/DPG/Tasks/AOTTrack/qaEfficiency.cxx index 24f8d2ce9ce..20896f0476a 100644 --- a/DPG/Tasks/AOTTrack/qaEfficiency.cxx +++ b/DPG/Tasks/AOTTrack/qaEfficiency.cxx @@ -16,25 +16,43 @@ /// In MC the efficiency for particles is computed according to the PDG code (sign included and not charge). /// -// 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 "PWGLF/DataModel/LFParticleIdentification.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/EventSelection.h" #include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; using namespace o2::framework; // Indices for the track cut histogram @@ -66,13 +84,15 @@ static constexpr int trkCutIdxN = 23; 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 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}; -// Histograms - // Pt std::array, nParticles> hPtIts; std::array, nParticles> hPtTpc; @@ -100,6 +120,8 @@ 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; @@ -159,6 +181,21 @@ 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 { // Track/particle selection Configurable numSameCollision{"numSameCollision", false, "Flag to ask that the numerator is in the same collision as the denominator"}; @@ -183,6 +220,7 @@ struct QaEfficiency { 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"}; @@ -198,12 +236,15 @@ struct QaEfficiency { 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"}; + Configurable applyTimeFrameBorderCut{"applyTimeFrameBorderCut", false, "Flag to apply the TF border cut"}; // Custom track cuts for debug purposes TrackSelection customTrackCuts; struct : ConfigurableGroup { @@ -226,14 +267,18 @@ struct QaEfficiency { 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 CollisionCandidates = o2::soa::Join; using CollisionCandidatesMC = o2::soa::Join; using TrackCandidates = o2::soa::Join; using TrackCandidatesMC = o2::soa::Join; + using BCsInfo = soa::Join; // Histograms HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -266,6 +311,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) { @@ -276,6 +322,7 @@ struct QaEfficiency { 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; @@ -337,6 +384,8 @@ struct QaEfficiency { 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}); @@ -396,6 +445,18 @@ struct QaEfficiency { 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; @@ -515,6 +576,12 @@ struct QaEfficiency { 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"; @@ -597,6 +664,24 @@ struct QaEfficiency { 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); @@ -701,6 +786,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, @@ -712,6 +799,20 @@ struct QaEfficiency { 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, kTH1D, {axisPt}); histos.add("Data/neg/pt/its_tpc_tof", "ITS-TPC-TOF Negative " + tagPt, kTH1D, {axisPt}); @@ -886,6 +987,7 @@ struct QaEfficiency { histos.get(HIST("eventSelection"))->GetXaxis()->SetBinLabel(3, "Passed Contrib."); histos.get(HIST("eventSelection"))->GetXaxis()->SetBinLabel(4, "Passed Position"); + histos.get(HIST("eventSelection"))->GetXaxis()->SetBinLabel(5, "Passed Time Frame border cut"); if (doprocessMC) { histos.add("MC/generatedCollisions", "Generated Collisions", kTH1D, {{10, 0.5, 10.5, "Generated collisions"}}); @@ -1058,6 +1160,12 @@ struct QaEfficiency { 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 // Checking mothers @@ -1069,6 +1177,9 @@ struct QaEfficiency { 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) { @@ -1083,6 +1194,12 @@ struct QaEfficiency { if (passedTOF) { 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) { @@ -1091,6 +1208,12 @@ struct QaEfficiency { 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 @@ -1144,17 +1267,22 @@ struct QaEfficiency { hPtGeneratedPrm[histogramIndex]->Fill(mcParticle.pt()); hEtaGeneratedPrm[histogramIndex]->Fill(mcParticle.eta()); hPhiGeneratedPrm[histogramIndex]->Fill(mcParticle.phi()); + if (doPtRadius) { + hPtRadiusGeneratedPrm[histogramIndex]->Fill(mcParticle.pt(), radius); + } } else { if (mcParticle.getProcess() == 4) { // Particle decay - // Checking mothers 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; + motherIsAccepted = true; // Mother matches the list of specified PDGs + hPtmotherGenerated[histogramIndex]->Fill(mother.pt()); // Fill generated pT for mother break; } if (motherIsAccepted) { @@ -1165,8 +1293,14 @@ struct QaEfficiency { } 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 @@ -1303,6 +1437,12 @@ struct QaEfficiency { } 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) @@ -1330,6 +1470,12 @@ struct QaEfficiency { if constexpr (doFillHistograms) { histos.fill(HIST("eventSelection"), 4); } + if (applyTimeFrameBorderCut && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if constexpr (doFillHistograms) { + histos.fill(HIST("eventSelection"), 5); + } return true; } @@ -1561,6 +1707,54 @@ 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; @@ -1571,7 +1765,8 @@ struct QaEfficiency { // o2::soa::SmallGroups const& collisions, CollisionCandidatesMC const& collisions, TrackCandidatesMC const& tracks, - o2::aod::McParticles const& mcParticles) + o2::aod::McParticles const& mcParticles, + BCsInfo const&) { /// loop over generated collisions @@ -1586,6 +1781,12 @@ struct QaEfficiency { 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; @@ -1605,6 +1806,11 @@ struct QaEfficiency { } histos.fill(HIST("MC/generatedCollisions"), 3); + if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { + LOG(debug) << "Skipping event with different type of generator than the one requested"; + continue; + } + /// loop over reconstructed collisions for (const auto& collision : groupedCollisions) { histos.fill(HIST("MC/generatedCollisions"), 4); @@ -1612,6 +1818,14 @@ struct QaEfficiency { 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()); @@ -1628,6 +1842,33 @@ struct QaEfficiency { continue; } + 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) { @@ -1656,6 +1897,13 @@ struct QaEfficiency { continue; } } + // apply time-frame border cut also to the generated collision + if (applyTimeFrameBorderCut) { + auto bc = mcCollision.bc_as(); + if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; + } + } } /// only to fill denominator of ITS-TPC matched primary tracks only in MC events with at least 1 reco. vtx @@ -1671,6 +1919,17 @@ struct QaEfficiency { 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); @@ -1693,6 +1952,13 @@ struct QaEfficiency { continue; } } + // apply time-frame border cut also to the generated collision + if (applyTimeFrameBorderCut) { + auto bc = mcCollision.bc_as(); + if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; + } + } // Loop on particles to fill the denominator float dNdEta = 0; // Multiplicity @@ -1747,7 +2013,8 @@ struct QaEfficiency { void processMCWithoutCollisions(TrackCandidatesMC const& tracks, o2::aod::Collisions const&, o2::aod::McParticles const& mcParticles, - o2::aod::McCollisions const&) + o2::aod::McCollisions const&, + BCsInfo const&) { // Track loop for (const auto& track : tracks) { @@ -1799,6 +2066,14 @@ struct QaEfficiency { continue; } } + // apply time-frame border cut also to the generated collision + if (applyTimeFrameBorderCut) { + const auto mcCollision = mcParticle.mcCollision(); + auto bc = mcCollision.bc_as(); + if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; + } + } // search for particles from HF decays if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, /*searchUpToQuark*/ true)) { @@ -1848,76 +2123,124 @@ 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); } } } @@ -1936,7 +2259,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()); diff --git a/DPG/Tasks/AOTTrack/qaEventTrack.cxx b/DPG/Tasks/AOTTrack/qaEventTrack.cxx index afab3403224..b4baddb2685 100644 --- a/DPG/Tasks/AOTTrack/qaEventTrack.cxx +++ b/DPG/Tasks/AOTTrack/qaEventTrack.cxx @@ -23,26 +23,41 @@ #include "qaEventTrack.h" -#include "Framework/AnalysisTask.h" -#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/CCDB/EventSelectionParams.h" +#include "Common/Core/MetadataHelper.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/TableProducer/PID/pidTOFBase.h" -#include "string" -#include "vector" +#include +#include +#include +#include +#include +#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; -using namespace o2::dataformats; + +o2::common::core::MetadataHelper metadataInfo; // TODO: add PID wagons as dependency + include impact parameter studies (same or separate task in workflow??) @@ -68,6 +83,9 @@ struct qaEventTrack { // option to apply a timeframe cut Configurable tfCut{"tfCut", false, "applies timeframe cut"}; + // option to add run info to the histograms + Configurable addRunInfo{"addRunInfo", true, "add run info (pass, data) to the histograms"}; + // options to select only specific tracks Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; Configurable selectCharge{"selectCharge", 0, "select charge +1 or -1 (0 means no selection)"}; @@ -93,6 +111,13 @@ struct qaEventTrack { // 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}, ""}; @@ -152,6 +177,21 @@ 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!"); + } + } + + if (addRunInfo) { + auto hRunInfo = histos.add("hRunInfo", "Run info", kTH1D, {{1, 0.5, 1.5, "Run info"}}); + // hRunInfo->SetBit(TH1::kCanRebin); // allow dynamic bin creation based on label + if (metadataInfo.isFullyDefined()) { + hRunInfo->Fill(metadataInfo.makeMetadataLabel().c_str(), 1.0); + } + } + // // Next section setups overwrite of configurableAxis if overwriteAxisRangeForPbPb is used. // @@ -231,9 +271,12 @@ struct qaEventTrack { histos.add("Events/nContrib", "", kTH1D, {axisVertexNumContrib}); histos.add("Events/nContribVsFilteredMult", "", kTH2D, {axisVertexNumContrib, axisTrackMultiplicity}); histos.add("Events/nContribVsMult", "", kTH2D, {axisVertexNumContrib, axisTrackMultiplicity}); + histos.add("Events/nContribVsAtLeastITSMult", "", kTH2D, {axisVertexNumContrib, axisTrackMultiplicity}); histos.add("Events/nContribWithTOFvsWithTRD", ";PV contrib. with TOF; PV contrib. with TRD;", kTH2D, {axisVertexNumContrib, axisVertexNumContrib}); histos.add("Events/nContribAllvsWithTRD", ";PV contrib. all; PV contrib. with TRD;", kTH2D, {axisVertexNumContrib, axisVertexNumContrib}); histos.add("Events/vertexChi2", ";#chi^{2}", kTH1D, {{100, 0, 100}}); + histos.add("Events/vertexChi2OvernContrib", ";#chi^{2} / n contrib.", kTH1D, {{100, 0, 100}}); + histos.add("Events/vertexChi2VsnContrib", ";#chi^{2};n contrib.", kTH2D, {{100, 0, 100}, axisVertexNumContrib}); histos.add("Events/covXX", ";Cov_{xx} [cm^{2}]", kTH1D, {axisVertexCov}); histos.add("Events/covXY", ";Cov_{xy} [cm^{2}]", kTH1D, {axisVertexCov}); @@ -1136,6 +1179,8 @@ struct qaEventTrack { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + // Parse the metadata + metadataInfo.initMetadata(cfgc); return WorkflowSpec{adaptAnalysisTask(cfgc)}; } @@ -1272,11 +1317,15 @@ void qaEventTrack::fillRecoHistogramsGroupedTracks(const C& collision, const T& } int nFilteredTracks = 0; + int atLeastITSTracks = 0; for (const auto& track : tracks) { if (checkOnlyPVContributor && !track.isPVContributor()) { continue; } histos.fill(HIST("Tracks/selection"), 1.f); + if (track.hasITS()) { + atLeastITSTracks++; + } if (!isSelectedTrack(track)) { continue; } @@ -1423,7 +1472,10 @@ void qaEventTrack::fillRecoHistogramsGroupedTracks(const C& collision, const T& histos.fill(HIST("Events/nContrib"), collision.numContrib()); histos.fill(HIST("Events/nContribVsFilteredMult"), collision.numContrib(), nFilteredTracks); histos.fill(HIST("Events/nContribVsMult"), collision.numContrib(), tracksUnfiltered.size()); + histos.fill(HIST("Events/nContribVsAtLeastITSMult"), collision.numContrib(), atLeastITSTracks); histos.fill(HIST("Events/vertexChi2"), collision.chi2()); + histos.fill(HIST("Events/vertexChi2OvernContrib"), collision.chi2() / collision.numContrib()); + histos.fill(HIST("Events/vertexChi2VsnContrib"), collision.chi2(), collision.numContrib()); histos.fill(HIST("Events/covXX"), collision.covXX()); histos.fill(HIST("Events/covXY"), collision.covXY()); @@ -1498,6 +1550,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) { @@ -1537,7 +1600,7 @@ void qaEventTrack::fillRecoHistogramsGroupedTracks(const C& collision, const T& histos.fill(HIST("Tracks/signed1Pt"), track.signed1Pt()); histos.fill(HIST("Tracks/snp"), track.snp()); histos.fill(HIST("Tracks/tgl"), track.tgl()); - for (unsigned int i = 0; i < 64; i++) { + for (unsigned int i = 0; i < 32; i++) { if (track.flags() & (1 << i)) { histos.fill(HIST("Tracks/flags"), i); } @@ -1593,7 +1656,7 @@ void qaEventTrack::fillRecoHistogramsGroupedTracks(const C& collision, const T& 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()); @@ -1626,7 +1689,7 @@ void qaEventTrack::fillRecoHistogramsGroupedTracks(const C& collision, const T& } // optionally check for PID in tracking: select tracks with correct PID in tracking - if (checkPIDforTracking && track.pidForTracking() != std::abs(PartIdentifier)) { + if (checkPIDforTracking && track.pidForTracking() != static_cast(std::abs(PartIdentifier))) { continue; } 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 index ee913462785..1da3a6a6674 100644 --- a/DPG/Tasks/AOTTrack/qaFakeHits.cxx +++ b/DPG/Tasks/AOTTrack/qaFakeHits.cxx @@ -114,7 +114,6 @@ struct QaFakeHits { 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}); diff --git a/DPG/Tasks/AOTTrack/qaImpPar.cxx b/DPG/Tasks/AOTTrack/qaImpPar.cxx index 452e6448d70..7e758dd7ec2 100644 --- a/DPG/Tasks/AOTTrack/qaImpPar.cxx +++ b/DPG/Tasks/AOTTrack/qaImpPar.cxx @@ -9,68 +9,72 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// \author Mattia Faggin , Padova University and INFN -/// -/// Event selection: o2-analysis-timestamp --aod-file AO2D.root -b | o2-analysis-event-selection -b | ---> not working with Run2 converted data/MC -/// Track selection: o2-analysis-trackextension | o2-analysis-trackselection | ---> add --isRun3 1 with Run 3 data/MC (then global track selection works) -/// PID: o2-analysis-pid-tpc-full | o2-analysis-pid-tof-full -/// Working configuration (2021 Oct 20th): o2-analysis-trackextension -b --aod-file ./AO2D.root | o2-analysis-trackselection -b --isRun3 1 | o2-analysis-pid-tpc-full -b | o2-analysis-pid-tof-full -b | o2-analysis-pp-qa-impact-parameter -b - -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "ReconstructionDataFormats/DCA.h" -#include "Common/Core/trackUtilities.h" // for propagation to primary vertex +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" // for propagation to primary vertex #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "CommonUtils/NameConf.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/Core/TrackSelection.h" -#include "DetectorsVertexing/PVertexer.h" -#include "ReconstructionDataFormats/Vertex.h" -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "Framework/RunningWorkflowInfo.h" -#include "CCDB/CcdbApi.h" -#include "DataFormatsCalibration/MeanVertexObject.h" -#include "CommonConstants/GeomConstants.h" - -#include "iostream" -#include "vector" -#include "set" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2::framework; using namespace o2::framework::expressions; -// void customize(std::vector& workflowOptions) -//{ -// ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, false, {"Fill MC histograms."}}; -// workflowOptions.push_back(optionDoMC); -// } - -#include "Framework/runDataProcessing.h" - /// QA task for impact parameter distribution monitoring struct QaImpactPar { /// Input parameters Configurable fDebug{"fDebug", false, "Debug flag enabling outputs"}; Configurable fEnablePulls{"fEnablePulls", false, "Enable storage of pulls"}; + Configurable fEnableNuclei{"fEnableNuclei", false, "Enable storage of nuclei"}; ConfigurableAxis binningImpPar{"binningImpPar", {200, -500.f, 500.f}, "Impact parameter binning"}; ConfigurableAxis binningPulls{"binningPulls", {200, -10.f, 10.f}, "Pulls binning"}; ConfigurableAxis binningPt{"binningPt", {100, 0.f, 10.f}, "Pt binning"}; ConfigurableAxis binningEta{"binningEta", {40, -2.f, 2.f}, "Eta binning"}; - 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 binningPhi{"binningPhi", {24, 0.f, o2::constants::math::TwoPI}, "Phi binning"}; 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"}; @@ -89,27 +93,29 @@ struct QaImpactPar { Configurable nSigmaTOFProtonMax{"nSigmaTOFProtonMax", 99999.f, "Maximum nSigma value in TOF, proton hypothesis"}; // PV refit Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbpath_lut{"ccdbpath_lut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathLut{"ccdbpath_lut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; // Configurable ccdbpath_geo{"ccdbpath_geo", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable ccdbpath_grp{"ccdbpath_grp", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable ccdbPathGrp{"ccdbpath_grp", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable doPVrefit{"doPVrefit", true, "Do PV refit"}; - Configurable nBins_DeltaX_PVrefit{"nBins_DeltaX_PVrefit", 1000, "Number of bins of DeltaX for PV refit"}; - Configurable nBins_DeltaY_PVrefit{"nBins_DeltaY_PVrefit", 1000, "Number of bins of DeltaY for PV refit"}; - Configurable nBins_DeltaZ_PVrefit{"nBins_DeltaZ_PVrefit", 1000, "Number of bins of DeltaZ for PV refit"}; - Configurable minDeltaX_PVrefit{"minDeltaX_PVrefit", -0.5, "Min. DeltaX value for PV refit (cm)"}; - Configurable maxDeltaX_PVrefit{"maxDeltaX_PVrefit", 0.5, "Max. DeltaX value for PV refit (cm)"}; - Configurable minDeltaY_PVrefit{"minDeltaY_PVrefit", -0.5, "Min. DeltaY value for PV refit (cm)"}; - Configurable maxDeltaY_PVrefit{"maxDeltaY_PVrefit", 0.5, "Max. DeltaY value for PV refit (cm)"}; - Configurable minDeltaZ_PVrefit{"minDeltaZ_PVrefit", -0.5, "Min. DeltaZ value for PV refit (cm)"}; - Configurable maxDeltaZ_PVrefit{"maxDeltaZ_PVrefit", 0.5, "Max. DeltaZ value for PV refit (cm)"}; + Configurable nBinsDeltaXPVrefit{"nBins_DeltaX_PVrefit", 1000, "Number of bins of DeltaX for PV refit"}; + Configurable nBinsDeltaYPVrefit{"nBins_DeltaY_PVrefit", 1000, "Number of bins of DeltaY for PV refit"}; + Configurable nBinsDeltaZPVrefit{"nBins_DeltaZ_PVrefit", 1000, "Number of bins of DeltaZ for PV refit"}; + Configurable minDeltaXPVrefit{"minDeltaX_PVrefit", -0.5, "Min. DeltaX value for PV refit (cm)"}; + Configurable maxDeltaXPVrefit{"maxDeltaX_PVrefit", 0.5, "Max. DeltaX value for PV refit (cm)"}; + Configurable minDeltaYPVrefit{"minDeltaY_PVrefit", -0.5, "Min. DeltaY value for PV refit (cm)"}; + Configurable maxDeltaYPVrefit{"maxDeltaY_PVrefit", 0.5, "Max. DeltaY value for PV refit (cm)"}; + Configurable minDeltaZPVrefit{"minDeltaZ_PVrefit", -0.5, "Min. DeltaZ value for PV refit (cm)"}; + Configurable maxDeltaZPVrefit{"maxDeltaZ_PVrefit", 0.5, "Max. DeltaZ value for PV refit (cm)"}; Configurable minPVcontrib{"minPVcontrib", 0, "Minimum number of PV contributors"}; Configurable maxPVcontrib{"maxPVcontrib", 10000, "Maximum number of PV contributors"}; Configurable removeDiamondConstraint{"removeDiamondConstraint", true, "Remove the diamond constraint for the PV refit"}; Configurable keepAllTracksPVrefit{"keepAllTracksPVrefit", false, "Keep all tracks for PV refit (for debug)"}; - Configurable use_customITSHitMap{"use_customITSHitMap", false, "Use custom ITS hitmap selection"}; + Configurable useCustomITSHitMap{"use_customITSHitMap", false, "Use custom ITS hitmap selection"}; Configurable customITShitmap{"customITShitmap", 0, "Custom ITS hitmap (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"}; + Configurable customITShitmap_exclude{"customITShitmap_exclude", 0, "Custom ITS hitmap of layers to be excluded (consider the binary representation)"}; + Configurable nCustomMinITShits{"n_customMinITShits", 0, "Minimum number of layers crossed by a track among those in \"customITShitmap\""}; + Configurable customForceITSTPCmatching{"custom_forceITSTPCmatching", false, "Consider or not only ITS-TPC macthed tracks when using custom ITS hitmap"}; + Configurable downsamplingFraction{"downsamplingFraction", 1.1, "Fraction of tracks to be used to fill the output objects"}; /// Custom cut selection objects TrackSelection selector_ITShitmap; @@ -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; @@ -146,41 +153,78 @@ struct QaImpactPar { ///////////////////////////////////////////////////////////// /// Data - using collisionRecoTable = o2::soa::Join; - using trackTable = o2::soa::Join; - using trackFullTable = o2::soa::Join; + using TrackTable = o2::soa::Join; + using TrackFullTableNoPid = o2::soa::Join; + using TrackFullTable = o2::soa::Join; - void processData(o2::soa::Filtered::iterator& collision, - const trackTable& tracksUnfiltered, - const o2::soa::Filtered& tracks, + using TrackTableIU = o2::soa::Join; + /// + /// @brief process function in data, without the usage of PID info + void processData(o2::soa::Filtered::iterator const& 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); + /// + /// @brief process function in data, with the possibility to use PID info + void processDataWithPid(o2::soa::Filtered::iterator const& 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, tracksIU, 0, bc); + } + PROCESS_SWITCH(QaImpactPar, processDataWithPid, "process data with PID", false); /// MC - using collisionMCRecoTable = o2::soa::Join; - using trackMCFullTable = o2::soa::Join; - void processMC(o2::soa::Filtered::iterator& collision, - trackTable const& tracksUnfiltered, - o2::soa::Filtered const& tracks, + using CollisionMCRecoTable = o2::soa::Join; + using TrackMCFullTableNoPid = o2::soa::Join; + using TrackMCFullTable = o2::soa::Join; + /// + /// @brief process function in MC, without the usage of PID info + void processMC(o2::soa::Filtered::iterator const& 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); + /// + /// @brief process function in MC,with the possibility to use PID info + void processMCWithPid(o2::soa::Filtered::iterator const& 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, tracksIU, mcParticles, bc); + } + PROCESS_SWITCH(QaImpactPar, processMCWithPid, "process MC with PID", false); /// core template process function /// template - /// void processReco(const C& collision, const trackTable& unfilteredTracks, const T& tracks, + /// void processReco(const C& collision, const TrackTable& unfilteredTracks, const T& tracks, /// const T_MC& mcParticles, /// o2::aod::BCsWithTimestamps const& bcs); @@ -189,6 +233,11 @@ struct QaImpactPar { /// init function - declare and define histograms void init(InitContext&) { + std::array processes = {doprocessData, doprocessDataWithPid, doprocessMC, doprocessMCWithPid}; + if (std::accumulate(processes.begin(), processes.end(), 0) != 1) { + LOGP(fatal, "One and only one process function for collision study must be enabled at a time."); + } + // Primary vertex const AxisSpec collisionXAxis{100, -20.f, 20.f, "X (cm)"}; const AxisSpec collisionYAxis{100, -20.f, 20.f, "Y (cm)"}; @@ -197,9 +246,9 @@ struct QaImpactPar { const AxisSpec collisionYOrigAxis{1000, -20.f, 20.f, "Y original PV (cm)"}; const AxisSpec collisionZOrigAxis{1000, -20.f, 20.f, "Z original PV (cm)"}; const AxisSpec collisionNumberContributorAxis{1000, 0, 1000, "Number of contributors"}; - const AxisSpec collisionDeltaX_PVrefit{nBins_DeltaX_PVrefit, minDeltaX_PVrefit, maxDeltaX_PVrefit, "#Delta x_{PV} (cm)"}; - const AxisSpec collisionDeltaY_PVrefit{nBins_DeltaY_PVrefit, minDeltaY_PVrefit, maxDeltaY_PVrefit, "#Delta y_{PV} (cm)"}; - const AxisSpec collisionDeltaZ_PVrefit{nBins_DeltaZ_PVrefit, minDeltaZ_PVrefit, maxDeltaZ_PVrefit, "#Delta z_{PV} (cm)"}; + const AxisSpec collisionDeltaX_PVrefit{nBinsDeltaXPVrefit, minDeltaXPVrefit, maxDeltaXPVrefit, "#Delta x_{PV} (cm)"}; + const AxisSpec collisionDeltaY_PVrefit{nBinsDeltaYPVrefit, minDeltaYPVrefit, maxDeltaYPVrefit, "#Delta y_{PV} (cm)"}; + const AxisSpec collisionDeltaZ_PVrefit{nBinsDeltaZPVrefit, minDeltaZPVrefit, maxDeltaZPVrefit, "#Delta z_{PV} (cm)"}; histograms.add("Reco/vertices", "", kTH1D, {{2, 0.5f, 2.5f, ""}}); histograms.get(HIST("Reco/vertices"))->GetXaxis()->SetBinLabel(1, "All PV"); @@ -226,22 +275,23 @@ struct QaImpactPar { ccdb->setURL(ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbpath_lut)); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); // if (!o2::base::GeometryManager::isGeometryLoaded()) { // ccdb->get(ccdbpath_geo); // } 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++) { - if ((customITShitmap & (1 << index_ITSlayer)) > 0) { - set_customITShitmap.insert(static_cast(index_ITSlayer)); + constexpr std::size_t NLayersIts = 7; + if (useCustomITSHitMap) { + for (std::size_t indexItsLayer = 0; indexItsLayer < NLayersIts; indexItsLayer++) { + if ((customITShitmap & (1 << indexItsLayer)) > 0) { + set_customITShitmap.insert(static_cast(indexItsLayer)); } } LOG(info) << "### customITShitmap: " << customITShitmap; - LOG(info) << "### n_customMinITShits: " << n_customMinITShits; + LOG(info) << "### nCustomMinITShits: " << nCustomMinITShits; LOG(info) << "### set_customITShitmap.size(): " << set_customITShitmap.size(); LOG(info) << "### Custom ITS hitmap checked: "; for (std::set::iterator it = set_customITShitmap.begin(); it != set_customITShitmap.end(); it++) { @@ -249,13 +299,36 @@ struct QaImpactPar { } LOG(info) << "############"; - selector_ITShitmap.SetRequireHitsInITSLayers(n_customMinITShits, set_customITShitmap); + selector_ITShitmap.SetRequireHitsInITSLayers(nCustomMinITShits, set_customITShitmap); + } + /// Custom cut selection objects - ITS layers that must be absent + std::set set_customITShitmap_exclude; // = {}; + if (useCustomITSHitMap) { + for (std::size_t indexItsLayer = 0; indexItsLayer < NLayersIts; indexItsLayer++) { + if ((customITShitmap_exclude & (1 << indexItsLayer)) > 0) { + set_customITShitmap_exclude.insert(static_cast(indexItsLayer)); + } + } + 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}})"}; @@ -266,7 +339,13 @@ struct QaImpactPar { const AxisSpec trackNSigmaTOFPionAxis{20, -10.f, 10.f, "Number of #sigma TOF #pi^{#pm}"}; const AxisSpec trackNSigmaTOFKaonAxis{20, -10.f, 10.f, "Number of #sigma TOF K^{#pm}"}; const AxisSpec trackNSigmaTOFProtonAxis{20, -10.f, 10.f, "Number of #sigma TOF proton"}; - const AxisSpec trackPDGAxis{binningPDG, "species (-1: not matched, 0: unknown, 1: pi, 2: K, 3: p)"}; + AxisSpec trackPDGAxis{5, -1.5f, 3.5f, "species (-1: not matched, 0: unknown, 1: pi, 2: K, 3: p)"}; + if (fEnableNuclei) { + trackPDGAxis.nBins = 9; + trackPDGAxis.binEdges[1] = 7.5; + trackPDGAxis.title = "species (-1: not matched, 0: unknown, 1: pi, 2: K, 3: p, 4: d, 5: t, 6: he3, 7: alpha)"; + } + const AxisSpec trackChargeAxis{binningCharge, "charge binning (-1: negative; +1: positive)"}; const AxisSpec axisVertexNumContrib{binsNumPvContrib, "Number of original PV contributors"}; const AxisSpec trackIsPvContrib{2, -0.5f, 1.5f, "is PV contributor: 1=yes, 0=no"}; @@ -281,6 +360,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 +372,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}); } @@ -318,9 +414,9 @@ struct QaImpactPar { } /// core template process function - template - void processReco(const C& collision, const trackTable& unfilteredTracks, const T& tracks, - const T_MC& /*mcParticles*/, + template + void processReco(const C& collision, const TrackTable& unfilteredTracks, const T& tracks, + const TrackTableIU& tracksIU, const T_MC& /*mcParticles*/, o2::aod::BCsWithTimestamps::iterator const& bc) { constexpr float toMicrometers = 10000.f; // Conversion from [cm] to [mum] @@ -333,6 +429,14 @@ struct QaImpactPar { return 2; case 2212: // proton return 3; + case o2::constants::physics::Pdg::kDeuteron: // deuteron + return 4; + case o2::constants::physics::Pdg::kTriton: // triton + return 5; + case o2::constants::physics::Pdg::kHelium3: // helium-3 + return 6; + case o2::constants::physics::Pdg::kAlpha: // alpha + return 7; default: // not identified return 0; } @@ -401,7 +505,7 @@ struct QaImpactPar { o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; // auto bc = collision.bc_as(); if (mRunNumber != bc.runNumber()) { - o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp(ccdbpath_grp, bc.timestamp()); + o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp(ccdbPathGrp, bc.timestamp()); if (grpo != nullptr) { o2::base::Propagator::initFieldFromGRP(grpo); o2::base::Propagator::Instance()->setMatLUT(lut); @@ -441,6 +545,12 @@ struct QaImpactPar { /// loop over tracks float pt = -999.f; + float p = -999.f; + float eta = -999.f; + float phi = -999.f; + int8_t sign = -1; + bool isPvContributor = false; + int nContributors = -1; float impParRPhi = -999.f; float impParZ = -999.f; float impParRPhiSigma = 999.f; @@ -451,11 +561,17 @@ 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) { - if (keepOnlyPvContrib && !track.isPVContributor()) { + isPvContributor = track.isPVContributor(); + if (keepOnlyPvContrib && !isPvContributor) { /// let's skip all tracks that were not PV contributors originally /// this let us ignore tracks flagged as ambiguous continue; @@ -470,7 +586,7 @@ struct QaImpactPar { continue; } auto particle = track.mcParticle(); - if (keepOnlyPhysPrimary && particle.isPhysicalPrimary()) { + if (!particle.isPhysicalPrimary()) { continue; } pdgIndex = PDGtoIndex(std::abs(particle.pdgCode())); @@ -491,12 +607,12 @@ struct QaImpactPar { ///} /// apply custom ITS hitmap selections, if asked - if (use_customITSHitMap && !selector_ITShitmap.IsSelected(track, TrackSelection::TrackCuts::kITSHits)) { + if (useCustomITSHitMap && !selector_ITShitmap.IsSelected(track, TrackSelection::TrackCuts::kITSHits)) { /// skip this track and go on, because it does not satisfy the ITS hit requirements continue; } - if (use_customITSHitMap && custom_forceITSTPCmatching && (!track.hasITS() || !track.hasTPC())) { - // if (use_customITSHitMap && custom_forceITSTPCmatching && track.hasITS()) { ///ATTEMPT: REMOVE TRACKS WITH ITS + if (useCustomITSHitMap && customForceITSTPCmatching && (!track.hasITS() || !track.hasTPC())) { + // if (useCustomITSHitMap && customForceITSTPCmatching && track.hasITS()) { ///ATTEMPT: REMOVE TRACKS WITH ITS /// skip this track because it is not global (no matching ITS-TPC) continue; } @@ -534,12 +650,15 @@ struct QaImpactPar { } pt = track.pt(); - tpcNSigmaPion = track.tpcNSigmaPi(); - tpcNSigmaKaon = track.tpcNSigmaKa(); - tpcNSigmaProton = track.tpcNSigmaPr(); - tofNSigmaPion = track.tofNSigmaPi(); - tofNSigmaKaon = track.tofNSigmaKa(); - tofNSigmaProton = track.tofNSigmaPr(); + p = track.p(); + if constexpr (USE_PID) { + tpcNSigmaPion = track.tpcNSigmaPi(); + tpcNSigmaKaon = track.tpcNSigmaKa(); + tpcNSigmaProton = track.tpcNSigmaPr(); + tofNSigmaPion = track.tofNSigmaPi(); + tofNSigmaKaon = track.tofNSigmaKa(); + tofNSigmaProton = track.tofNSigmaPr(); + } histograms.fill(HIST("Reco/pt"), pt); histograms.fill(HIST("Reco/hNSigmaTPCPion"), pt, tpcNSigmaPion); @@ -630,7 +749,7 @@ struct QaImpactPar { } } else { auto trackPar = getTrackPar(track); - o2::gpu::gpustd::array dcaInfo{-999., -999.}; + std::array dcaInfo{-999., -999.}; if (o2::base::Propagator::Instance()->propagateToDCABxByBz({PVbase_recalculated.getX(), PVbase_recalculated.getY(), PVbase_recalculated.getZ()}, trackPar, 2.f, matCorr, &dcaInfo)) { impParRPhi = dcaInfo[0] * toMicrometers; impParZ = dcaInfo[1] * toMicrometers; @@ -638,32 +757,68 @@ 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 ((pt * 1000 - static_cast(pt * 1000)) > downsamplingFraction) { + // downsampling - do not consider the current track + continue; + } + eta = track.eta(); + phi = track.phi(); + sign = track.sign(); + nContributors = collision.numContrib(); + histograms.fill(HIST("Reco/h4ImpPar"), pt, impParRPhi, eta, phi, pdgIndex, sign, nContributors, isPvContributor); + histograms.fill(HIST("Reco/h4ImpParZ"), pt, impParZ, eta, phi, pdgIndex, sign, nContributors, 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()); + histograms.fill(HIST("Reco/h4ImpParPulls"), pt, impParRPhi / impParRPhiSigma, eta, phi, pdgIndex, sign, nContributors, isPvContributor); + histograms.fill(HIST("Reco/h4ImpParZPulls"), pt, impParZ / impParZSigma, eta, phi, pdgIndex, sign, nContributors, isPvContributor); } if (isPIDPionApplied && nSigmaTPCPionMin < tpcNSigmaPion && tpcNSigmaPion < nSigmaTPCPionMax && nSigmaTOFPionMin < tofNSigmaPion && tofNSigmaPion < nSigmaTOFPionMax) { /// PID selected pions - 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()); + if (addTrackIUinfo) { + histograms.fill(HIST("Reco/h4ClusterSizeIU_Pion"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ, clusterSizeInLayer0); + } + histograms.fill(HIST("Reco/h4ImpPar_Pion"), pt, impParRPhi, eta, phi, pdgIndex, sign, nContributors, isPvContributor); + histograms.fill(HIST("Reco/h4ImpParZ_Pion"), pt, impParZ, eta, phi, pdgIndex, sign, nContributors, isPvContributor); histograms.fill(HIST("Reco/hNSigmaTPCPion_afterPID"), pt, tpcNSigmaPion); histograms.fill(HIST("Reco/hNSigmaTOFPion_afterPID"), pt, tofNSigmaPion); } if (isPIDKaonApplied && nSigmaTPCKaonMin < tpcNSigmaKaon && tpcNSigmaKaon < nSigmaTPCKaonMax && nSigmaTOFKaonMin < tofNSigmaKaon && tofNSigmaKaon < nSigmaTOFKaonMax) { /// PID selected kaons - 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()); + if (addTrackIUinfo) { + histograms.fill(HIST("Reco/h4ClusterSizeIU_Kaon"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ, clusterSizeInLayer0); + } + histograms.fill(HIST("Reco/h4ImpPar_Kaon"), pt, impParRPhi, eta, phi, pdgIndex, sign, nContributors, isPvContributor); + histograms.fill(HIST("Reco/h4ImpParZ_Kaon"), pt, impParZ, eta, phi, pdgIndex, sign, nContributors, isPvContributor); histograms.fill(HIST("Reco/hNSigmaTPCKaon_afterPID"), pt, tpcNSigmaKaon); histograms.fill(HIST("Reco/hNSigmaTOFKaon_afterPID"), pt, tofNSigmaKaon); } if (isPIDProtonApplied && nSigmaTPCProtonMin < tpcNSigmaProton && tpcNSigmaProton < nSigmaTPCProtonMax && nSigmaTOFProtonMin < tofNSigmaProton && tofNSigmaProton < nSigmaTOFProtonMax) { /// PID selected Protons - 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()); + if (addTrackIUinfo) { + histograms.fill(HIST("Reco/h4ClusterSizeIU_Proton"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ, clusterSizeInLayer0); + } + histograms.fill(HIST("Reco/h4ImpPar_Proton"), pt, impParRPhi, eta, phi, pdgIndex, sign, nContributors, isPvContributor); + histograms.fill(HIST("Reco/h4ImpParZ_Proton"), pt, impParZ, eta, phi, pdgIndex, sign, nContributors, isPvContributor); histograms.fill(HIST("Reco/hNSigmaTPCProton_afterPID"), pt, tpcNSigmaProton); histograms.fill(HIST("Reco/hNSigmaTOFProton_afterPID"), pt, tofNSigmaProton); } @@ -674,6 +829,6 @@ struct QaImpactPar { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec w{ - adaptAnalysisTask(cfgc, TaskName{"qa-impact-par"})}; + adaptAnalysisTask(cfgc)}; return w; } diff --git a/DPG/Tasks/AOTTrack/qaMatchEff.cxx b/DPG/Tasks/AOTTrack/qaMatchEff.cxx index 086b1818364..4b6d3e87d13 100644 --- a/DPG/Tasks/AOTTrack/qaMatchEff.cxx +++ b/DPG/Tasks/AOTTrack/qaMatchEff.cxx @@ -19,20 +19,46 @@ // // Internal version number: 6.3 // + +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "CommonConstants/MathConstants.h" -#include "CCDB/BasicCCDBManager.h" -// -#include "Framework/AnalysisTask.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/runDataProcessing.h" -// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + namespace extConfPar { static constexpr int nParDCA = 1; @@ -139,6 +165,7 @@ 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"}; @@ -1504,6 +1531,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)) @@ -2363,7 +2395,7 @@ 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 @@ -2703,7 +2735,7 @@ struct qaMatchEff { // } } } // end if ITS - } // end if TPC + } // end if TPC // // // if (trkWITS) { @@ -2830,9 +2862,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) { @@ -2857,9 +2889,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(); @@ -2883,7 +2915,7 @@ struct qaMatchEff { 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) { // @@ -2905,7 +2937,7 @@ struct qaMatchEff { 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 { // @@ -2927,8 +2959,8 @@ struct qaMatchEff { 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) { @@ -2995,7 +3027,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 @@ -3063,7 +3095,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()) { @@ -3076,7 +3108,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) { // @@ -3090,7 +3122,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 { // @@ -3104,9 +3136,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()))) { @@ -3130,8 +3162,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) { @@ -3198,7 +3230,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 @@ -3212,7 +3244,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 } } // diff --git a/DPG/Tasks/AOTTrack/qaSignChargeMC.cxx b/DPG/Tasks/AOTTrack/qaSignChargeMC.cxx index 8190b075bbe..e40dd0e76e9 100644 --- a/DPG/Tasks/AOTTrack/qaSignChargeMC.cxx +++ b/DPG/Tasks/AOTTrack/qaSignChargeMC.cxx @@ -60,7 +60,7 @@ struct QaSignChargeMC { o2::aod::McParticles const&) { for (auto const& track : tracks) { - if (abs(track.eta()) > 0.8) { + if (std::abs(track.eta()) > 0.8) { continue; } if (!track.hasITS()) { @@ -73,7 +73,7 @@ struct QaSignChargeMC { continue; } if (absPDG) { - if (abs(track.mcParticle().pdgCode()) != PDG) { + if (std::abs(track.mcParticle().pdgCode()) != PDG) { continue; } } else { 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 index ca73e9006fd..3125f1e7c03 100644 --- a/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx +++ b/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx @@ -22,7 +22,9 @@ #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"}; @@ -40,6 +42,14 @@ struct qaTrackSplitting { 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 @@ -51,6 +61,7 @@ struct qaTrackSplitting { 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); @@ -69,16 +80,46 @@ struct qaTrackSplitting { customTrackCuts.print(); } - // Global process - using TrackCandidates = o2::soa::Join; - void process(o2::soa::Join::iterator const& collision, - TrackCandidates const& tracks, - o2::aod::McParticles const&) + 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; + typedef std::shared_ptr trkType; std::map> particleUsageCounter; for (auto track : tracks) { @@ -87,11 +128,12 @@ struct qaTrackSplitting { continue; } histos.fill(HIST("tracks"), 1); - if (track.mcParticle().pdgCode() != pdg) { + const auto& mcParticle = track.mcParticle(); + if (mcParticle.pdgCode() != pdg) { continue; } histos.fill(HIST("tracks"), 2); - if (!track.mcParticle().isPhysicalPrimary()) { + if (!mcParticle.isPhysicalPrimary()) { continue; } histos.fill(HIST("tracks"), 3); @@ -101,21 +143,28 @@ struct qaTrackSplitting { histos.fill(HIST("tracks"), 4); particleUsageCounter[track.mcParticleId()].push_back(std::make_shared(track)); } - for (const auto& [mcId, tracks] : particleUsageCounter) { - histos.fill(HIST("numberOfRecoed"), tracks.size()); - if (tracks.size() > 1) { + for (const auto& [mcId, tracksMatched] : particleUsageCounter) { + histos.fill(HIST("numberOfRecoed"), tracksMatched.size()); + if (tracksMatched.size() > 1) { bool isFirst = true; - for (const auto& track : tracks) { + 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()); + 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() - tracks[0]->eta(), track->phi() - tracks[0]->phi(), track->pt() - tracks[0]->pt()); + 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 a23b41cca1e..ce88ae505b6 100644 --- a/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx +++ b/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx @@ -14,24 +14,32 @@ /// /// \author Fabrizio Grosa , CERN -#include "CCDB/BasicCCDBManager.h" -#include "CommonConstants/PhysicsConstants.h" +#include "PWGHF/Utils/utilsAnalysis.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" -#include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGHF/Utils/utilsAnalysis.h" -#include "Tools/ML/MlResponse.h" + #include +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -61,7 +69,8 @@ enum SignalFlags : uint8_t { Bkg = 0, Prompt, NonPrompt, - Resonant + Resonant, + BkgFromNoHf }; static constexpr int nBinsPt = 7; @@ -188,7 +197,7 @@ struct TagTwoProngDisplacedVertices { Produces tagVarsTable; SliceCache cache; - Configurable fillTopoVarsTable{"fillTopoVarsTable", 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"}; @@ -418,7 +427,9 @@ 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(); @@ -490,7 +501,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; } } @@ -719,8 +739,10 @@ struct TagTwoProngDisplacedVertices { 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); + float pseudoRndm = trackFirst.pt() * 1000. - static_cast(trackFirst.pt() * 1000); if (ptTag < ptTagMaxForDownsampling && pseudoRndm >= downsamplingForTopoVarTable) { fillTable = false; } @@ -882,8 +904,10 @@ struct TagTwoProngDisplacedVertices { 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); + float pseudoRndm = trackPos.pt() * 1000. - static_cast(trackPos.pt() * 1000); if (ptTag < ptTagMaxForDownsampling && pseudoRndm >= downsamplingForTopoVarTable) { fillTable = false; } @@ -1133,6 +1157,19 @@ struct ProbeThirdTrack { 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"}; + Configurable fillTpcOnlyCase{"fillTpcOnlyCase", true, "Fill output for TPC only case (not needed for thinned data or Pb-Pb)"}; + + 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); @@ -1161,6 +1198,8 @@ struct ProbeThirdTrack { 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{}; @@ -1212,16 +1251,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 axisYD{20, -1.f, 1.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}; - const AxisSpec axisPtMinTagdaught{10, 0.f, 1.f}; - const AxisSpec axisAbsEtaMaxTagdaught{10, 0.f, 1.f}; 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}}; @@ -1230,9 +1259,15 @@ struct ProbeThirdTrack { for (int iChannel{0}; iChannel < aod::tagandprobe::TagChannels::NTagChannels; ++iChannel) { for (int iTrackType{0}; iTrackType < aod::tagandprobe::TrackTypes::NTrackTypes; ++iTrackType) { + if (!fillTpcOnlyCase && iTrackType == aod::tagandprobe::TrackTypes::GlobalWoDcaWoIts) { + continue; + } 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) { @@ -1315,16 +1350,17 @@ 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 constexpr (channel == aod::tagandprobe::TagChannels::DstarPlusToDzeroPi || channel == aod::tagandprobe::TagChannels::DstarMinusToDzeroBarPi) { - if (invMass > 0.17f) { - continue; - } - } else if constexpr (channel == aod::tagandprobe::TagChannels::DplusToKPiPi || channel == aod::tagandprobe::TagChannels::DsOrDplusToKKPi) { - if ((invMass < 1.65f || invMass > 2.10f)) { - continue; - } + if (invMass < minInvMass[channel] || invMass > maxInvMass[channel]) { + continue; + } + 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) { + if (!fillTpcOnlyCase && iTrackType == aod::tagandprobe::TrackTypes::GlobalWoDcaWoIts) { + continue; + } if (trackSelector[iTrackType].IsSelected(trackThird)) { histos[channel][iTrackType]->Fill(ptD, ptTag, ptTrackThird, ptTpcInnerTrackThird, invMass, invMassTag, etaTrackThird, numTpcCrossRowTrackThird, numTpcChi2NumCluTrackThird, numItsCluTrackThird); } diff --git a/DPG/Tasks/AOTTrack/unitTestForReconstruction.cxx b/DPG/Tasks/AOTTrack/unitTestForReconstruction.cxx new file mode 100644 index 00000000000..a5e6016d9fb --- /dev/null +++ b/DPG/Tasks/AOTTrack/unitTestForReconstruction.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. +/// +/// \file unitTestForReconstruction.cxx +/// +/// \brief Unit test for validating the reconstruction software +/// \author Alberto Caliva (alberto.caliva@cern.ch), Catalin-Lucian Ristea (catalin.ristea@cern.ch) +/// \since September 9, 2025 + +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +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; + +struct UnitTestForReconstruction { + + // Histogram registry + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // global IDs of events to be inspected + Configurable> eventNr{"eventNr", {1, 5, 12, 44, 76, 99, 102, 115, 180, 220}, "eventNr"}; + std::unordered_set eventSet; + + void init(InitContext const&) + { + // Define histogram to monitor event counts at different selection stages + registryData.add("eventCounter", "eventCounter", HistType::kTH1F, {{10, 0, 10, ""}}); + + // Define histogram for the transverse momentum spectrum of reconstructed charged tracks + registryData.add("ptChargedTracks", "ptChargedTracks", HistType::kTH2F, {{11, 0, 11, "event"}, {1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}}); + + // Fast lookup set from configurable event list + eventSet = std::unordered_set(eventNr->begin(), eventNr->end()); + } + + // Process Data + void processData(o2::aod::Collisions const& collisions, o2::aod::Tracks const& tracks) + { + // Event index + int eventIndex = 0; + static constexpr int indexAllEvts = 0; + + // Loop over reconstructed events + for (const auto& collision : collisions) { + + // Event counter: before event selection + registryData.fill(HIST("eventCounter"), 0.5); + + // Check if event global index is in the list of events to process + int ev = collision.globalIndex(); + if (eventSet.count(ev)) { + + // Increment event index + eventIndex++; + + // Fill event counter + registryData.fill(HIST("eventCounter"), 1.5); + + // Loop over reconstructed tracks + for (auto const& track : tracks) { + registryData.fill(HIST("ptChargedTracks"), indexAllEvts, track.pt()); + registryData.fill(HIST("ptChargedTracks"), eventIndex, track.pt()); + } + } + } + } + PROCESS_SWITCH(UnitTestForReconstruction, processData, "Process Data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/CMakeLists.txt b/DPG/Tasks/CMakeLists.txt index 959ed3e5637..642f8d6e772 100644 --- a/DPG/Tasks/CMakeLists.txt +++ b/DPG/Tasks/CMakeLists.txt @@ -18,3 +18,4 @@ add_subdirectory(FDD) add_subdirectory(MFT) add_subdirectory(Monitor) add_subdirectory(FT0) +add_subdirectory(ITS) diff --git a/DPG/Tasks/FT0/ft0AnalysisTask.cxx b/DPG/Tasks/FT0/ft0AnalysisTask.cxx index a7d487fbdff..0d2b0f083be 100644 --- a/DPG/Tasks/FT0/ft0AnalysisTask.cxx +++ b/DPG/Tasks/FT0/ft0AnalysisTask.cxx @@ -9,22 +9,32 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + #include +#include #include -#include +#include #include - -#include "TH1.h" - -#include "Common/DataModel/EventSelection.h" -#include "DataFormatsFT0/Digit.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +#include using namespace o2; using namespace o2::framework; using namespace o2::aod::evsel; + struct ft0AnalysisTask { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; constexpr static int sNtriggers = 5; // Number of produced triggers 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/ITS/CMakeLists.txt b/DPG/Tasks/ITS/CMakeLists.txt new file mode 100644 index 00000000000..fc835ea769d --- /dev/null +++ b/DPG/Tasks/ITS/CMakeLists.txt @@ -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. + +o2physics_add_dpl_workflow(its-impact-parameter-studies + SOURCES itsImpParStudies.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + O2::ReconstructionDataFormats + O2::DetectorsCommonDataFormats + O2::DetectorsVertexing + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(filtertracks + SOURCES filterTracks.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/ITS/filterTracks.cxx b/DPG/Tasks/ITS/filterTracks.cxx new file mode 100644 index 00000000000..b97c48d4f5c --- /dev/null +++ b/DPG/Tasks/ITS/filterTracks.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 filterTracks.cxx +/// \brief Simple task to filter tracks and save infos to trees for DCA-related studies (alignment, HF-related issues, ...) +/// +/// \author Andrea Rossi + +#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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::track; +using namespace o2::aod::mctracklabel; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace filtertracks +{ + +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision index +DECLARE_SOA_COLUMN(IsInsideBeamPipe, isInsideBeamPipe, int); //! is within beam pipe +DECLARE_SOA_COLUMN(Pt, pt, float); //! track pt +DECLARE_SOA_COLUMN(Px, px, float); //! track px +DECLARE_SOA_COLUMN(Py, py, float); //! track py +DECLARE_SOA_COLUMN(Pz, pz, float); //! track pz +// DECLARE_SOA_COLUMN(Eta, eta, float); //! track eta +// DECLARE_SOA_COLUMN(X, x, float); //! track x position at the DCA to the primary vertex +// DECLARE_SOA_COLUMN(Y, y, float); //! track y position at the DCA to the primary vertex +// DECLARE_SOA_COLUMN(Z, z, float); //! track z position at the DCA to the primary vertex +// DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); //! track distance of closest approach at the primary vertex: in xy plane +// DECLARE_SOA_COLUMN(DcaZ, dcaz, float); //! track distance of closest approach at the primary vertex: along z (beam line) direction +DECLARE_SOA_COLUMN(Charge, charge, int); //! track sign, not really charge +DECLARE_SOA_COLUMN(NsigmaTPCpi, nsigmaTPCpi, float); //! TPC nsigma w.r.t. pion mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTPCka, nsigmaTPCka, float); //! TPC nsigma w.r.t. kaon mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTPCpr, nsigmaTPCpr, float); //! TPC nsigma w.r.t. proton mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTOFpi, nsigmaTOFpi, float); //! TOF nsigma w.r.t. pion mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTOFka, nsigmaTOFka, float); //! TOF nsigma w.r.t. kaon mass hypothesis +DECLARE_SOA_COLUMN(NsigmaTOFpr, nsigmaTOFpr, float); //! TOF nsigma w.r.t. proton mass hypothesis +DECLARE_SOA_COLUMN(TpcNCluster, tpcNCluster, int); //! TOF nsigma w.r.t. proton mass hypothesis + +///// MC INFO +DECLARE_SOA_COLUMN(MainHfMotherPdgCode, mainHfMotherPdgCode, int); //! mother pdg code for particles coming from HF, skipping intermediate resonance states. Not trustable when mother is not HF. Not suited for Sc->Lc decays, since Sc are never pointed to +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! is phyiscal primary according to ALICE definition +DECLARE_SOA_COLUMN(MainBeautyAncestorPdgCode, mainBeautyAncestorPdgCode, int); //! pdgcode of beauty particle when this is an ancestor, otherwise -1 +DECLARE_SOA_COLUMN(MainMotherOrigIndex, mainMotherOrigIndex, int); //! original index in MCParticle tree of main mother: needed when checking if particles come from same mother +DECLARE_SOA_COLUMN(MainMotherNfinalStateDaught, mainMotherNfinalStateDaught, int); //! number of final state (we consider only pions, kaons, muons, electrons, protons) daughter in main mother decay. To be noted that this is computed only for decays of particles of interest (D0, Lc, K0s). If the sign is negative, it means that the decay is not in one of the desired channels (K0s->pi pi, Lc->pKpi, D0->K-pi+) + +DECLARE_SOA_COLUMN(MainMotherPt, mainMotherPt, float); //! original index in MCParticle tree of main mother: needed when chekcing if particles come from same mother +DECLARE_SOA_COLUMN(MainMotherY, mainMotherY, float); //! original index in MCParticle tree of main mother: needed when chekcing if particles come from same mother +DECLARE_SOA_COLUMN(MainBeautyAncestorPt, mainBeautyAncestorPt, float); //! original index in MCParticle tree of main mother: needed when chekcing if particles come from same mother +DECLARE_SOA_COLUMN(MainBeautyAncestorY, mainBeautyAncestorY, float); //! original index in MCParticle tree of main mother: needed when chekcing if particles come from same mother +DECLARE_SOA_COLUMN(MaxEtaDaughter, maxEtaDaughter, float); //! max (abs) eta of daughter particles, needed to reproduce acceptance cut +} // namespace filtertracks +DECLARE_SOA_TABLE(FilterColl, "AOD", "FILTERCOLL", + o2::aod::collision::BCId, + o2::aod::collision::PosX, + o2::aod::collision::PosY, + o2::aod::collision::PosZ, + o2::aod::collision::CovXX, + o2::aod::collision::CovXY, + o2::aod::collision::CovYY, + o2::aod::collision::CovXZ, + o2::aod::collision::CovYZ, + o2::aod::collision::CovZZ, + o2::aod::collision::Flags, + o2::aod::collision::Chi2, + o2::aod::collision::NumContrib, + o2::aod::collision::CollisionTime, + o2::aod::collision::CollisionTimeRes); +DECLARE_SOA_TABLE(FilterCollLite, "AOD", "FILTERCOLLLITE", + o2::aod::collision::PosX, + o2::aod::collision::PosY, + o2::aod::collision::PosZ, + o2::aod::collision::CovXX, + o2::aod::collision::CovXY, + o2::aod::collision::CovYY, + o2::aod::collision::CovXZ, + o2::aod::collision::CovYZ, + o2::aod::collision::CovZZ, + o2::aod::collision::Chi2, + o2::aod::collision::NumContrib, + o2::aod::collision::CollisionTime); +DECLARE_SOA_TABLE(FilterCollPos, "AOD", "FILTERCOLLPOS", + o2::aod::collision::PosX, + o2::aod::collision::PosY, + o2::aod::collision::PosZ, + o2::aod::collision::Chi2, + o2::aod::collision::NumContrib, + o2::aod::collision::CollisionTime); +DECLARE_SOA_TABLE(FiltTrackColIdx, "AOD", "FILTTRACKCOLIDX", + o2::aod::track::CollisionId); +DECLARE_SOA_TABLE(FilterTrack, "AOD", "FILTERTRACK", + aod::filtertracks::IsInsideBeamPipe, + o2::aod::track::TrackType, + o2::aod::track::X, + o2::aod::track::Alpha, + o2::aod::track::Y, + o2::aod::track::Z, + o2::aod::track::Snp, + o2::aod::track::Tgl, + o2::aod::track::Signed1Pt); +DECLARE_SOA_TABLE(FilterTrackExtr, "AOD", "FILTERTRACKEXTR", + // aod::filtertracks::Px,aod::filtertracks::Py, aod::filtertracks::Pz, + aod::filtertracks::Pt, o2::aod::track::Eta, + o2::aod::filtertracks::Charge, + o2::aod::track::DcaXY, + o2::aod::track::DcaZ, + o2::aod::track::SigmaDcaXY2, + o2::aod::track::SigmaDcaZ2, + aod::filtertracks::NsigmaTPCpi, aod::filtertracks::NsigmaTPCka, aod::filtertracks::NsigmaTPCpr, + aod::filtertracks::NsigmaTOFpi, aod::filtertracks::NsigmaTOFka, aod::filtertracks::NsigmaTOFpr); +DECLARE_SOA_TABLE(FiltTracExtDet, "AOD", "FILTTRACEXTDET", + o2::aod::track::ITSClusterSizes, + o2::aod::track::ITSChi2NCl, + o2::aod::track::TPCChi2NCl, + aod::filtertracks::TpcNCluster, + o2::aod::track::TrackTime); +DECLARE_SOA_TABLE(FilterTrackMC, "AOD", "FILTERTRACKMC", + // aod::filtertracks::Px,aod::filtertracks::Py, aod::filtertracks::Pz, + o2::aod::mcparticle::PdgCode, + o2::aod::filtertracks::IsPhysicalPrimary, + o2::aod::filtertracks::MainHfMotherPdgCode, + o2::aod::filtertracks::MainBeautyAncestorPdgCode, + o2::aod::filtertracks::MainMotherOrigIndex, + o2::aod::filtertracks::MainMotherNfinalStateDaught, + o2::aod::filtertracks::MainMotherPt, + o2::aod::filtertracks::MainMotherY, + o2::aod::filtertracks::MainBeautyAncestorPt, + o2::aod::filtertracks::MainBeautyAncestorY); +DECLARE_SOA_TABLE(GenParticles, "AOD", "GENPARTICLES", + // aod::filtertracks::Px,aod::filtertracks::Py, aod::filtertracks::Pz, + o2::aod::mcparticle::PdgCode, + o2::aod::mcparticle::McCollisionId, + o2::aod::filtertracks::MainBeautyAncestorPdgCode, + o2::aod::filtertracks::MainMotherPt, + o2::aod::filtertracks::MainMotherY, + o2::aod::filtertracks::MaxEtaDaughter, + o2::aod::filtertracks::MainBeautyAncestorPt, + o2::aod::filtertracks::MainBeautyAncestorY); +} // namespace o2::aod + +struct FilterTracks { + const static int nStudiedParticlesMc = 3; + + Produces filteredTracksCollIdx; + Produces filteredTracksTableExtra; + Produces filteredTracksTable; + Produces filteredTracksTableExtraDet; + Produces filteredTracksMC; + Produces selectedGenParticles; + Produces filterCollTable; + Produces filterCollLiteTable; + Produces filterCollPosTable; + + SliceCache cache; + // Configurable dummy{"dummy", 0, "dummy"}; + Configurable minTrackPt{"minTrackPt", 0.25, "min track pt"}; + Configurable trackDcaXyMax{"trackDcaXyMax", 0.5, "max track pt"}; + Configurable trackPtSampling{"trackPtSampling", 0, "track sampling mode"}; + Configurable produceCollTableFull{"produceCollTableFull", false, "produce full collision table"}; + Configurable produceCollTableLite{"produceCollTableLite", false, "produce lite collision table"}; + Configurable produceCollTableExtraLite{"produceCollTableExtraLite", 2, "produce extra lite collision table"}; + Configurable trackPtWeightLowPt{"trackPtWeightLowPt", 0.01f, "trackPtWeightLowPt"}; + Configurable trackPtWeightMidPt{"trackPtWeightMidPt", 0.10f, "trackPtWeightMidPt"}; + Configurable collFilterFraction{"collFilterFraction", 0.05f, "collFilterFraction"}; + + Filter trackFilter = requireGlobalTrackWoDCAInFilter() && aod::track::pt > minTrackPt&& nabs(aod::track::dcaXY) < trackDcaXyMax; + Filter collFilter = nabs(aod::collision::posZ * 10000.f - nround(aod::collision::posZ * 10000.f)) < collFilterFraction.node() * 2.f; + using CollisionsWithEvSel = soa::Join; + using TracksWithSelAndDca = soa::Join; + using TracksWithSelAndDcaMc = soa::Join; + using FilterCollisionsWithEvSel = soa::Filtered; + + float lowPtThreshold = 2.; + float midPtThreshold = 5.; + float nDigitScaleFactor = 10000.; + Partition> lowPtTracks = aod::track::pt < lowPtThreshold && (nabs(aod::track::pt * nDigitScaleFactor - nround(aod::track::pt * nDigitScaleFactor)) < trackPtWeightLowPt.node() * lowPtThreshold); + Partition> midPtTracks = aod::track::pt > lowPtThreshold&& aod::track::pt < midPtThreshold && (nabs(aod::track::pt * nDigitScaleFactor - nround(aod::track::pt * nDigitScaleFactor)) < trackPtWeightMidPt.node() * lowPtThreshold); + Partition> highPtTracks = aod::track::pt > midPtThreshold; + + Partition> lowPtTracksMC = aod::track::pt < lowPtThreshold && (nabs(aod::track::pt * nDigitScaleFactor - nround(aod::track::pt * nDigitScaleFactor)) < trackPtWeightLowPt.node() * lowPtThreshold); + Partition> midPtTracksMC = aod::track::pt > lowPtThreshold&& aod::track::pt < midPtThreshold && (nabs(aod::track::pt * nDigitScaleFactor - nround(aod::track::pt * nDigitScaleFactor)) < trackPtWeightMidPt.node() * lowPtThreshold); + Partition> highPtTracksMC = aod::track::pt > midPtThreshold; + + std::array pdgSignalParticleArray = {kK0Short, o2::constants::physics::Pdg::kD0, o2::constants::physics::Pdg::kLambdaCPlus}; // K0s, D0 and Lc + std::array pdgDecayLc = {kProton, kKMinus, kPiPlus}; + std::array pdgDecayDzero = {kKMinus, kPiPlus}; + std::array pdgDecayKzero = {kPiMinus, kPiPlus}; + const int nK0sShortDaught = 2; + + void init(InitContext&) + { + } + + void fillTableData(auto track) + { + + filteredTracksCollIdx(track.collisionId()); + filteredTracksTableExtra(track.pt(), track.eta(), track.sign(), track.dcaXY(), track.dcaZ(), track.sigmaDcaXY2(), track.sigmaDcaZ2(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()); + filteredTracksTable(track.isWithinBeamPipe() ? 1 : 0, track.trackType(), track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt()); + + filteredTracksTableExtraDet(track.itsClusterSizes(), track.itsChi2NCl(), track.tpcChi2NCl(), track.tpcNClsFound(), track.trackTime()); + } + + void fillTableDataMC(auto track, aod::McParticles const& mcParticles) + { + + fillTableData(track); + bool hasMcParticle = track.has_mcParticle(); + if (hasMcParticle) { + /// the track is not fake + + // check whether the particle comes from a charm or beauty hadron and store its index + + auto mcparticle = track.mcParticle(); + int pdgParticleMother = 0; + for (int iSignPart = 0; iSignPart < nStudiedParticlesMc; iSignPart++) { + pdgParticleMother = pdgSignalParticleArray[iSignPart]; + auto motherIndex = RecoDecay::getMother(mcParticles, mcparticle, pdgParticleMother, true); // check whether mcparticle derives from a particle with pdg = pdgparticlemother, accepting also antiparticle (<- the true parameter) + if (motherIndex != -1) { + auto particleMother = mcParticles.rawIteratorAt(motherIndex); + // just for internal check + // double mass=particleMother.e()*particleMother.e()-particleMother.pt()*particleMother.pt()-particleMother.pz()*particleMother.pz(); + // filteredTracksMC(mcparticle.pdgCode(),mcparticle.isPhysicalPrimary(),particleMother.pdgCode(),0,motherIndex,0,particleMother.pt(),particleMother.y(),std::sqrt(mass),0); + if (pdgParticleMother == kK0Short) { + auto daughtersSlice = mcparticle.template daughters_as(); + int ndaught = daughtersSlice.size(); // might not be accurate in case K0s interact with material before decaying + if (ndaught != nK0sShortDaught) + ndaught *= -1; + filteredTracksMC(mcparticle.pdgCode(), mcparticle.isPhysicalPrimary(), particleMother.pdgCode(), 0, motherIndex, ndaught, particleMother.pt(), particleMother.y(), 0, 0); + // std::cout<<"FOUND K0s, MATCHED! size array "< indxDaughers; + if (pdgParticleMother == o2::constants::physics::Pdg::kD0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particleMother, pdgParticleMother, pdgDecayDzero, true, nullptr, 3, &indxDaughers)) { + ndaught = 2; + // std::cout<<"######## FOUND D0, MATCHED! pdg: " <(mcParticles, particleMother, pdgParticleMother, pdgDecayLc, true, nullptr, 3, &indxDaughers)) { + ndaught = 3; + } else { + ndaught = -indxDaughers.size(); + } + } + // now check whether the charm hadron is prompt or comes from beauty decay + std::vector idxBhadMothers; + if (RecoDecay::getCharmHadronOrigin(mcParticles, particleMother, false, &idxBhadMothers) == RecoDecay::OriginType::NonPrompt) { + if (idxBhadMothers.size() > 1) { + LOG(info) << "more than 1 B mother hadron found, should not be: "; + for (uint64_t iBhM = 0; iBhM < idxBhadMothers.size(); iBhM++) { + auto particleBhadr = mcParticles.rawIteratorAt(idxBhadMothers[iBhM]); + LOG(info) << particleBhadr.pdgCode(); + } + } + auto particleBhadr = mcParticles.rawIteratorAt(idxBhadMothers[0]); + // int pdgBhad=particleBhadr.pdgCode(); + filteredTracksMC(mcparticle.pdgCode(), mcparticle.isPhysicalPrimary(), particleMother.pdgCode(), particleBhadr.pdgCode(), motherIndex, ndaught, particleMother.pt(), particleMother.y(), particleBhadr.pt(), particleBhadr.y()); + } else { + filteredTracksMC(mcparticle.pdgCode(), mcparticle.isPhysicalPrimary(), particleMother.pdgCode(), 0, motherIndex, ndaught, particleMother.pt(), particleMother.y(), 0, 0); + } + break; + } + pdgParticleMother = 0; + } + if (pdgParticleMother == 0) + filteredTracksMC(mcparticle.pdgCode(), mcparticle.isPhysicalPrimary(), 0, 0, -1, 0, 0, 0, 0, 0); + // std::cout< const& tracks) + { + if (trackPtSampling == 0) { + for (auto const& track : tracks) { + fillTableData(track); + if (produceCollTableExtraLite == 2) { + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); + }; + } + } else { + auto lowPtTracksThisColl = lowPtTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto const& track : lowPtTracksThisColl) { + fillTableData(track); + if (produceCollTableExtraLite == 2) { + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); + }; + } + auto midPtTracksThisColl = midPtTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto const& track : midPtTracksThisColl) { + fillTableData(track); + if (produceCollTableExtraLite == 2) { + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); + }; + } + auto highPtTracksThisColl = highPtTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto const& track : highPtTracksThisColl) { + fillTableData(track); + if (produceCollTableExtraLite == 2) { + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); + }; + } + } + } + PROCESS_SWITCH(FilterTracks, processData, "process data", true); + void processCollisions(FilterCollisionsWithEvSel::iterator const& collision) + { + if (produceCollTableFull) + filterCollTable(collision.bcId(), 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()); + if (produceCollTableLite) + filterCollLiteTable(collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); + if (produceCollTableExtraLite == 1) + filterCollPosTable(collision.posX(), collision.posY(), collision.posZ(), collision.chi2(), collision.numContrib(), collision.collisionTime()); + } + PROCESS_SWITCH(FilterTracks, processCollisions, "process collisions", true); + + void processMC(FilterCollisionsWithEvSel::iterator const& collision, soa::Filtered const& tracks, aod::McParticles const& mcParticles) + { + if (trackPtSampling == 0) { + for (auto const& track : tracks) { + fillTableDataMC(track, mcParticles); + } + } else { + auto lowPtTracksMCThisColl = lowPtTracksMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto const& track : lowPtTracksMCThisColl) { + fillTableDataMC(track, mcParticles); + } + auto midPtTracksMCThisColl = midPtTracksMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto const& track : midPtTracksMCThisColl) { + fillTableDataMC(track, mcParticles); + } + auto highPtTracksMCThisColl = highPtTracksMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + for (auto const& track : highPtTracksMCThisColl) { + fillTableDataMC(track, mcParticles); + } + } + + for (auto const& mcpart : mcParticles) { // NOTE THAT OF COURSE IN CASE OF SAMPLING THE GEN TABLE WON'T MATCH THE RECO EVEN CONSIDERING EFFICIENCY + int pdgCode = mcpart.pdgCode(); + // for(int iSignPart=0;iSignPart<3;iSignPart++){ + + std::vector indxDaughers; + float etamax = 0; + bool isMatchedToSignal = false; + if (std::abs(pdgCode) == kK0Short) { + isMatchedToSignal = RecoDecay::isMatchedMCGen(mcParticles, mcpart, kK0Short, pdgDecayKzero, true, nullptr, 1, &indxDaughers); + } + if (std::abs(pdgCode) == o2::constants::physics::Pdg::kD0) { + isMatchedToSignal = RecoDecay::isMatchedMCGen(mcParticles, mcpart, o2::constants::physics::Pdg::kD0, pdgDecayDzero, true, nullptr, 3, &indxDaughers); + } else if (std::abs(pdgCode) == o2::constants::physics::Pdg::kLambdaCPlus) { + isMatchedToSignal = RecoDecay::isMatchedMCGen(mcParticles, mcpart, o2::constants::physics::Pdg::kLambdaCPlus, pdgDecayLc, true, nullptr, 3, &indxDaughers); + // std::cout<<"Lc found, matched to MC? "<(); + // int ndaught = daughtersLxSlice.size(); + // for(auto lcDaught : daughtersLxSlice){ + // std::cout<<"Lc daught, total daught "< etamax) { + etamax = eta; + } + } + if (pdgCode == kK0Short) { + selectedGenParticles(mcpart.pdgCode(), mcpart.mcCollisionId(), 0, mcpart.pt(), mcpart.y(), etamax, 0, 0); + continue; + } + std::vector idxBhadMothers; + if (RecoDecay::getCharmHadronOrigin(mcParticles, mcpart, false, &idxBhadMothers) == RecoDecay::OriginType::NonPrompt) { + if (idxBhadMothers.size() > 1) { + LOG(info) << "loop on gen particles: more than 1 B mother hadron found, should not be: "; + for (uint64_t iBhM = 0; iBhM < idxBhadMothers.size(); iBhM++) { + auto particleBhadr = mcParticles.rawIteratorAt(idxBhadMothers[iBhM]); + LOG(info) << particleBhadr.pdgCode(); + } + } + auto particleBhadr = mcParticles.rawIteratorAt(idxBhadMothers[0]); + // int pdgBhad=particleBhadr.pdgCode(); + selectedGenParticles(mcpart.pdgCode(), mcpart.mcCollisionId(), particleBhadr.pdgCode(), mcpart.pt(), mcpart.y(), etamax, particleBhadr.pt(), particleBhadr.y()); + } else { + selectedGenParticles(mcpart.pdgCode(), mcpart.mcCollisionId(), 0, mcpart.pt(), mcpart.y(), etamax, 0, 0); + } + } + // + } + } + PROCESS_SWITCH(FilterTracks, processMC, "process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/ITS/itsImpParStudies.cxx b/DPG/Tasks/ITS/itsImpParStudies.cxx new file mode 100644 index 00000000000..3bbce0487e4 --- /dev/null +++ b/DPG/Tasks/ITS/itsImpParStudies.cxx @@ -0,0 +1,699 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 Samuele Cattaruzzi + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" // for propagation to primary vertex +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// QA task for impact parameter distribution monitoring +struct ItsImpactParStudies { + + /// Input parameters + Configurable fDebug{"fDebug", false, "Debug flag enabling outputs"}; + Configurable fEnablePulls{"fEnablePulls", false, "Enable storage of pulls"}; + ConfigurableAxis binningImpPar{"binningImpPar", {200, -500.f, 500.f}, "Impact parameter binning"}; + ConfigurableAxis binningPulls{"binningPulls", {200, -10.f, 10.f}, "Pulls binning"}; + ConfigurableAxis binningPt{"binningPt", {100, 0.f, 10.f}, "Pt binning"}; + ConfigurableAxis binningEta{"binningEta", {40, -2.f, 2.f}, "Eta binning"}; + ConfigurableAxis binningPhi{"binningPhi", {24, 0.f, o2::constants::math::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"}; + Configurable ptMin{"ptMin", 0.1f, "Minimum track pt [GeV/c]"}; + Configurable nSigmaTPCPionMin{"nSigmaTPCPionMin", -99999.f, "Minimum nSigma value in TPC, pion hypothesis"}; + Configurable nSigmaTPCPionMax{"nSigmaTPCPionMax", 99999.f, "Maximum nSigma value in TPC, pion hypothesis"}; + Configurable nSigmaTPCKaonMin{"nSigmaTPCKaonMin", -99999.f, "Minimum nSigma value in TPC, kaon hypothesis"}; + Configurable nSigmaTPCKaonMax{"nSigmaTPCKaonMax", 99999.f, "Maximum nSigma value in TPC, kaon hypothesis"}; + Configurable nSigmaTPCProtonMin{"nSigmaTPCProtonMin", -99999.f, "Minimum nSigma value in TPC, proton hypothesis"}; + Configurable nSigmaTPCProtonMax{"nSigmaTPCProtonMax", 99999.f, "Maximum nSigma value in TPC, proton hypothesis"}; + Configurable nSigmaTOFPionMin{"nSigmaTOFPionMin", -99999.f, "Minimum nSigma value in TOF, pion hypothesis"}; + Configurable nSigmaTOFPionMax{"nSigmaTOFPionMax", 99999.f, "Maximum nSigma value in TOF, pion hypothesis"}; + Configurable nSigmaTOFKaonMin{"nSigmaTOFKaonMin", -99999.f, "Minimum nSigma value in TOF, kaon hypothesis"}; + Configurable nSigmaTOFKaonMax{"nSigmaTOFKaonMax", 99999.f, "Maximum nSigma value in TOF, kaon hypothesis"}; + Configurable nSigmaTOFProtonMin{"nSigmaTOFProtonMin", -99999.f, "Minimum nSigma value in TOF, proton hypothesis"}; + Configurable nSigmaTOFProtonMax{"nSigmaTOFProtonMax", 99999.f, "Maximum nSigma value in TOF, proton hypothesis"}; + // PV refit + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbpath_lut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + // Configurable ccdbpath_geo{"ccdbpath_geo", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable ccdbPathGrp{"ccdbpath_grp", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable doPVrefit{"doPVrefit", true, "Do PV refit"}; + Configurable fillHistoPVrefit{"fillHistoPVrefit", false, "Do PV refit"}; + Configurable nBinsDeltaXPVrefit{"nBins_DeltaX_PVrefit", 1000, "Number of bins of DeltaX for PV refit"}; + Configurable nBinsDeltaYPVrefit{"nBins_DeltaY_PVrefit", 1000, "Number of bins of DeltaY for PV refit"}; + Configurable nBinsDeltaZPVrefit{"nBins_DeltaZ_PVrefit", 1000, "Number of bins of DeltaZ for PV refit"}; + Configurable minDeltaXPVrefit{"minDeltaX_PVrefit", -0.5, "Min. DeltaX value for PV refit (cm)"}; + Configurable maxDeltaXPVrefit{"maxDeltaX_PVrefit", 0.5, "Max. DeltaX value for PV refit (cm)"}; + Configurable minDeltaYPVrefit{"minDeltaY_PVrefit", -0.5, "Min. DeltaY value for PV refit (cm)"}; + Configurable maxDeltaYPVrefit{"maxDeltaY_PVrefit", 0.5, "Max. DeltaY value for PV refit (cm)"}; + Configurable minDeltaZPVrefit{"minDeltaZ_PVrefit", -0.5, "Min. DeltaZ value for PV refit (cm)"}; + Configurable maxDeltaZPVrefit{"maxDeltaZ_PVrefit", 0.5, "Max. DeltaZ value for PV refit (cm)"}; + Configurable minPVcontrib{"minPVcontrib", 0, "Minimum number of PV contributors"}; + Configurable maxPVcontrib{"maxPVcontrib", 10000, "Maximum number of PV contributors"}; + Configurable removeDiamondConstraint{"removeDiamondConstraint", true, "Remove the diamond constraint for the PV refit"}; + Configurable keepAllTracksPVrefit{"keepAllTracksPVrefit", false, "Keep all tracks for PV refit (for debug)"}; + Configurable useCustomITSHitMap{"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 nCustomMinITShits{"n_customMinITShits", 0, "Minimum number of layers crossed by a track among those in \"customITShitmap\""}; + Configurable customForceITSTPCmatching{"custom_forceITSTPCmatching", false, "Consider or not only ITS-TPC macthed tracks when using custom ITS hitmap"}; + Configurable downsamplingFraction{"downsamplingFraction", 1.1, "Fraction of tracks to be used to fill the output objects"}; + + /// Custom cut selection objects + TrackSelection selector_ITShitmap; + + /// Selections with Filter (from o2::framework::expressions) + // Primary vertex |z_vtx| ptMin; + + /// Histogram registry (from o2::framework) + HistogramRegistry histograms{"HistogramsImpParQA"}; + bool isPIDPionApplied; + bool isPIDKaonApplied; + bool isPIDProtonApplied; + + // Needed for PV refitting + Service ccdb; + o2::base::MatLayerCylSet* lut = nullptr; + // o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + int mRunNumber; + + ///////////////////////////////////////////////////////////// + /// Process functions /// + ///////////////////////////////////////////////////////////// + + /// Data + using CollisionRecoTable = o2::soa::Join; + using TrackTable = o2::soa::Join; + using TrackFullTable = o2::soa::Join; + using TrackTableIU = o2::soa::Join; + void processData(o2::soa::Filtered::iterator const& 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, tracksIU, 0, bc); + } + PROCESS_SWITCH(ItsImpactParStudies, processData, "process data", true); + + /// MC + using CollisionMCRecoTable = o2::soa::Join; + using TrackMCFullTable = o2::soa::Join; + void processMC(o2::soa::Filtered::iterator const& 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, tracksIU, mcParticles, bc); + } + PROCESS_SWITCH(ItsImpactParStudies, processMC, "process MC", false); + + /// core template process function + /// template + /// void processReco(const C& collision, const TrackTable& unfilteredTracks, const T& tracks, + /// const T_MC& mcParticles, + /// o2::aod::BCsWithTimestamps const& bcs); + + ///////////////////////////////////////////////////////////// + + /// init function - declare and define histograms + void init(InitContext&) + { + // Primary vertex + const AxisSpec collisionXAxis{100, -20.f, 20.f, "X (cm)"}; + const AxisSpec collisionYAxis{100, -20.f, 20.f, "Y (cm)"}; + const AxisSpec collisionZAxis{100, -20.f, 20.f, "Z (cm)"}; + const AxisSpec collisionXOrigAxis{1000, -20.f, 20.f, "X original PV (cm)"}; + const AxisSpec collisionYOrigAxis{1000, -20.f, 20.f, "Y original PV (cm)"}; + const AxisSpec collisionZOrigAxis{1000, -20.f, 20.f, "Z original PV (cm)"}; + const AxisSpec collisionNumberContributorAxis{1000, 0, 1000, "Number of contributors"}; + const AxisSpec collisionDeltaX_PVrefit{nBinsDeltaXPVrefit, minDeltaXPVrefit, maxDeltaXPVrefit, "#Delta x_{PV} (cm)"}; + const AxisSpec collisionDeltaY_PVrefit{nBinsDeltaYPVrefit, minDeltaYPVrefit, maxDeltaYPVrefit, "#Delta y_{PV} (cm)"}; + const AxisSpec collisionDeltaZ_PVrefit{nBinsDeltaZPVrefit, minDeltaZPVrefit, maxDeltaZPVrefit, "#Delta z_{PV} (cm)"}; + + histograms.add("Reco/vertices", "", kTH1D, {{2, 0.5f, 2.5f, ""}}); + histograms.get(HIST("Reco/vertices"))->GetXaxis()->SetBinLabel(1, "All PV"); + histograms.get(HIST("Reco/vertices"))->GetXaxis()->SetBinLabel(2, "PV refit doable"); + histograms.add("Reco/vertices_perTrack", "", kTH1D, {{3, 0.5f, 3.5f, ""}}); + histograms.get(HIST("Reco/vertices_perTrack"))->GetXaxis()->SetBinLabel(1, "All PV"); + histograms.get(HIST("Reco/vertices_perTrack"))->GetXaxis()->SetBinLabel(2, "PV refit doable"); + histograms.get(HIST("Reco/vertices_perTrack"))->GetXaxis()->SetBinLabel(3, "PV refit #chi^{2}!=-1"); + histograms.add("Reco/vertexZ", "", kTH1D, {collisionZAxis}); + histograms.add("Reco/numberContributors", "", kTH1D, {collisionNumberContributorAxis}); + if (doPVrefit && fillHistoPVrefit) { + histograms.add("Reco/nContrib_vs_DeltaX_PVrefit", "", kTH2D, {collisionNumberContributorAxis, collisionDeltaX_PVrefit}); + histograms.add("Reco/nContrib_vs_DeltaY_PVrefit", "", kTH2D, {collisionNumberContributorAxis, collisionDeltaY_PVrefit}); + histograms.add("Reco/nContrib_vs_DeltaZ_PVrefit", "", kTH2D, {collisionNumberContributorAxis, collisionDeltaZ_PVrefit}); + histograms.add("Reco/nContrib_vs_Chi2PVrefit", "", kTH2D, {collisionNumberContributorAxis, {102, -1.5, 100.5, "#chi^{2} PV refit"}}); + histograms.add("Reco/X_PVrefitChi2minus1", "PV refit with #chi^{2}==-1", kTH2D, {collisionXAxis, collisionXOrigAxis}); + histograms.add("Reco/Y_PVrefitChi2minus1", "PV refit with #chi^{2}==-1", kTH2D, {collisionYAxis, collisionYOrigAxis}); + histograms.add("Reco/Z_PVrefitChi2minus1", "PV refit with #chi^{2}==-1", kTH2D, {collisionZAxis, collisionZOrigAxis}); + histograms.add("Reco/nContrib_PVrefitNotDoable", "N. contributors for PV refit not doable", kTH1D, {collisionNumberContributorAxis}); + histograms.add("Reco/nContrib_PVrefitChi2minus1", "N. contributors original PV for PV refit #chi^{2}==-1", kTH1D, {collisionNumberContributorAxis}); + } + + // Needed for PV refitting + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + + mRunNumber = -1; + + /// Custom cut selection objects - ITS layers that must be present + std::set set_customITShitmap; // = {}; + constexpr std::size_t NLayersIts = 7; + if (useCustomITSHitMap) { + for (std::size_t indexItsLayer = 0; indexItsLayer < NLayersIts; indexItsLayer++) { + if ((customITShitmap & (1 << indexItsLayer)) > 0) { + set_customITShitmap.insert(static_cast(indexItsLayer)); + } + } + LOG(info) << "### customITShitmap: " << customITShitmap; + LOG(info) << "### nCustomMinITShits: " << nCustomMinITShits; + LOG(info) << "### set_customITShitmap.size(): " << set_customITShitmap.size(); + LOG(info) << "### Custom ITS hitmap checked: "; + for (std::set::iterator it = set_customITShitmap.begin(); it != set_customITShitmap.end(); it++) { + LOG(info) << "Layer " << static_cast(*it) << " "; + } + LOG(info) << "############"; + + selector_ITShitmap.SetRequireHitsInITSLayers(nCustomMinITShits, set_customITShitmap); + } + /// Custom cut selection objects - ITS layers that must be absent + std::set set_customITShitmap_exclude; // = {}; + if (useCustomITSHitMap) { + for (std::size_t indexItsLayer = 0; indexItsLayer < NLayersIts; indexItsLayer++) { + if ((customITShitmap_exclude & (1 << indexItsLayer)) > 0) { + set_customITShitmap_exclude.insert(static_cast(indexItsLayer)); + } + } + 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}})"}; + const AxisSpec trackImpParZPullsAxis{binningPulls, "#it{d}_{z} / #sigma(#it{d}_{z})"}; + const AxisSpec trackNSigmaTPCPionAxis{20, -10.f, 10.f, "Number of #sigma TPC #pi^{#pm}"}; + const AxisSpec trackNSigmaTPCKaonAxis{20, -10.f, 10.f, "Number of #sigma TPC K^{#pm}"}; + const AxisSpec trackNSigmaTPCProtonAxis{20, -10.f, 10.f, "Number of #sigma TPC proton"}; + const AxisSpec trackNSigmaTOFPionAxis{20, -10.f, 10.f, "Number of #sigma TOF #pi^{#pm}"}; + const AxisSpec trackNSigmaTOFKaonAxis{20, -10.f, 10.f, "Number of #sigma TOF K^{#pm}"}; + const AxisSpec trackNSigmaTOFProtonAxis{20, -10.f, 10.f, "Number of #sigma TOF proton"}; + const AxisSpec trackPDGAxis{binningPDG, "species (-1: not matched, 0: unknown, 1: pi, 2: K, 3: p)"}; + const AxisSpec trackChargeAxis{binningCharge, "charge binning (-1: negative; +1: positive)"}; + const AxisSpec axisVertexNumContrib{binsNumPvContrib, "Number of original PV contributors"}; + const AxisSpec trackIsPvContrib{2, -0.5f, 1.5f, "is PV contributor: 1=yes, 0=no"}; + + histograms.add("Reco/pt", "", kTH1D, {trackPtAxis}); + histograms.add("Reco/itsHits", "Number of hits vs ITS layer;layer ITS", kTH2D, {{8, -1.5, 6.5, "ITS layer"}, {8, -0.5, 7.5, "Number of hits"}}); + + if (addTrackIUinfo) { + histograms.add("Reco/h4ClusterSizeIU", "", kTHnSparseD, {trackPaxis, trackImpParRPhiAxis, trackIUposXaxis, trackIUposYaxis, trackIUposZaxis, trackIUclusterSize}); + histograms.add("Reco/h4ImpParZIU", "", kTHnSparseD, {trackPaxis, trackImpParZAxis, trackIUposXaxis, trackIUposYaxis, trackIUposZaxis}); + } + + 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}); + } + } + 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}); + } + } + 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/hNSigmaTPCPion", "", kTH2D, {trackPtAxis, trackNSigmaTPCPionAxis}); + histograms.add("Reco/hNSigmaTPCKaon", "", kTH2D, {trackPtAxis, trackNSigmaTPCKaonAxis}); + histograms.add("Reco/hNSigmaTPCProton", "", kTH2D, {trackPtAxis, trackNSigmaTPCProtonAxis}); + histograms.add("Reco/hNSigmaTOFPion", "", kTH2D, {trackPtAxis, trackNSigmaTOFPionAxis}); + histograms.add("Reco/hNSigmaTOFKaon", "", kTH2D, {trackPtAxis, trackNSigmaTOFKaonAxis}); + histograms.add("Reco/hNSigmaTOFProton", "", kTH2D, {trackPtAxis, trackNSigmaTOFProtonAxis}); + histograms.add("Reco/hNSigmaTPCPion_afterPID", "", kTH2D, {trackPtAxis, trackNSigmaTPCPionAxis}); + histograms.add("Reco/hNSigmaTPCKaon_afterPID", "", kTH2D, {trackPtAxis, trackNSigmaTPCKaonAxis}); + histograms.add("Reco/hNSigmaTPCProton_afterPID", "", kTH2D, {trackPtAxis, trackNSigmaTPCProtonAxis}); + histograms.add("Reco/hNSigmaTOFPion_afterPID", "", kTH2D, {trackPtAxis, trackNSigmaTOFPionAxis}); + histograms.add("Reco/hNSigmaTOFKaon_afterPID", "", kTH2D, {trackPtAxis, trackNSigmaTOFKaonAxis}); + histograms.add("Reco/hNSigmaTOFProton_afterPID", "", kTH2D, {trackPtAxis, trackNSigmaTOFProtonAxis}); + + histograms.add("MC/vertexZ_MCColl", "", kTH1D, {collisionZAxis}); + histograms.add("MC/ptMC", "", kTH1D, {trackPtAxis}); + } + + /// core template process function + template + void processReco(const C& collision, const TrackTable& unfilteredTracks, const T& tracks, + const TrackTableIU& tracksIU, const T_MC& /*mcParticles*/, + o2::aod::BCsWithTimestamps::iterator const& bc) + { + constexpr float toMicrometers = 10000.f; // Conversion from [cm] to [mum] + + /// trigger selection + if (useTriggerkINT7) { + // from Tutorial/src/multiplicityEventTrackSelection.cxx + if (!collision.alias_bit(kINT7)) { + return; + } + } + /// offline event selections + if (usesel8 && !collision.sel8()) { + return; + } + + histograms.fill(HIST("Reco/vertices"), 1); + histograms.fill(HIST("Reco/vertexZ"), collision.posZ()); + histograms.fill(HIST("Reco/numberContributors"), collision.numContrib()); + if constexpr (IS_MC) { + if (collision.has_mcCollision()) { + histograms.fill(HIST("MC/vertexZ_MCColl"), collision.mcCollision().posZ()); + } + } + + /////////////////////////////////// + /// For PV refit /// + /////////////////////////////////// + /// retrieve the tracks contributing to the primary vertex fitting + std::vector vec_globID_contr = {}; + std::vector vec_TrkContributos = {}; + if (fDebug) { + LOG(info) << "\n === New collision"; + } + const int nTrk = unfilteredTracks.size(); + int nContrib = 0; + int nNonContrib = 0; + for (const auto& unfilteredTrack : unfilteredTracks) { + if (!unfilteredTrack.isPVContributor()) { + /// the track di not contribute to fit the primary vertex + nNonContrib++; + continue; + } + vec_globID_contr.push_back(unfilteredTrack.globalIndex()); + vec_TrkContributos.push_back(getTrackParCov(unfilteredTrack)); + nContrib++; + if (fDebug) { + LOG(info) << "---> a contributor! stuff saved"; + LOG(info) << "vec_contrib size: " << vec_TrkContributos.size() << ", nContrib: " << nContrib; + } + } + if (fDebug) { + LOG(info) << "===> nTrk: " << nTrk << ", nContrib: " << nContrib << ", nNonContrib: " << nNonContrib; + } + + if (vec_TrkContributos.size() != collision.numContrib()) { + LOG(info) << "!!! something wrong in the number of contributor tracks for PV fit !!! " << vec_TrkContributos.size() << " vs. " << collision.numContrib(); + return; + } + + std::vector vec_useTrk_PVrefit(vec_globID_contr.size(), true); + + /// Prepare the vertex refitting + // Get the magnetic field for the Propagator + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + // auto bc = collision.bc_as(); + if (mRunNumber != bc.runNumber()) { + o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp(ccdbPathGrp, bc.timestamp()); + if (grpo != nullptr) { + o2::base::Propagator::initFieldFromGRP(grpo); + o2::base::Propagator::Instance()->setMatLUT(lut); + LOG(info) << "Setting magnetic field to current " << grpo->getL3Current() << " A for run " << bc.runNumber() << " from its GRP CCDB object"; + } else { + LOGF(fatal, "GRP object is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); + } + mRunNumber = bc.runNumber(); + } + // build the VertexBase to initialize the vertexer + o2::dataformats::VertexBase Pvtx; + Pvtx.setX(collision.posX()); + Pvtx.setY(collision.posY()); + Pvtx.setZ(collision.posZ()); + Pvtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + // configure PVertexer + o2::vertexing::PVertexer vertexer; + if (removeDiamondConstraint) { + o2::conf::ConfigurableParam::updateFromString("pvertexer.useMeanVertexConstraint=false"); // we want to refit w/o MeanVertex constraint + } + vertexer.init(); + bool PVrefit_doable = vertexer.prepareVertexRefit(vec_TrkContributos, Pvtx); + if (!PVrefit_doable) { + LOG(info) << "Not enough tracks accepted for the refit"; + if (doPVrefit) { + histograms.fill(HIST("Reco/nContrib_PVrefitNotDoable"), collision.numContrib()); + } + } else { + histograms.fill(HIST("Reco/vertices"), 2); + } + + if (fDebug) { + LOG(info) << "prepareVertexRefit = " << PVrefit_doable << " Ncontrib= " << vec_TrkContributos.size() << " Ntracks= " << collision.numContrib() << " Vtx= " << Pvtx.asString(); + } + /////////////////////////////////// + /////////////////////////////////// + + /// loop over tracks + float pt = -999.f; + float p = -999.f; + bool isPvContributor = false; + float impParRPhi = -999.f; + float impParZ = -999.f; + float tpcNSigmaPion = -999.f; + float tpcNSigmaKaon = -999.f; + float tpcNSigmaProton = -999.f; + 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) { + + isPvContributor = track.isPVContributor(); + if (keepOnlyPvContrib && !isPvContributor) { + /// let's skip all tracks that were not PV contributors originally + /// this let us ignore tracks flagged as ambiguous + continue; + } + + /// Specific MC selections + if constexpr (IS_MC) { + if (keepOnlyPhysPrimary) { + /// we want only physical primary particles + if (!track.has_mcParticle()) { + continue; + } + auto particle = track.mcParticle(); + if (keepOnlyPhysPrimary && !(particle.isPhysicalPrimary())) { + continue; + } + histograms.fill(HIST("MC/ptMC"), particle.pt()); + } else { + if (track.has_mcParticle()) { + auto particle = track.mcParticle(); + histograms.fill(HIST("MC/ptMC"), particle.pt()); + } + } + } + + /// Using the Filter instead + /// if ((keepOnlyGlobalTracks) && (!track.isGlobalTrack())) { + /// /// not a global track (FB 4 with tight DCA cuts) + /// continue; + ///} + + /// apply custom ITS hitmap selections, if asked + if (useCustomITSHitMap && !selector_ITShitmap.IsSelected(track, TrackSelection::TrackCuts::kITSHits)) { + /// skip this track and go on, because it does not satisfy the ITS hit requirements + continue; + } + if (useCustomITSHitMap && customForceITSTPCmatching && (!track.hasITS() || !track.hasTPC())) { + // if (useCustomITSHitMap && customForceITSTPCmatching && track.hasITS()) { ///ATTEMPT: REMOVE TRACKS WITH ITS + /// skip this track because it is not global (no matching ITS-TPC) + continue; + } + 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; + histograms.fill(HIST("Reco/itsHits"), i, itsNhits); + } + } + if (!trkHasITS) { + histograms.fill(HIST("Reco/itsHits"), -1, itsNhits); + } + + pt = track.pt(); + p = track.p(); + tpcNSigmaPion = track.tpcNSigmaPi(); + tpcNSigmaKaon = track.tpcNSigmaKa(); + tpcNSigmaProton = track.tpcNSigmaPr(); + tofNSigmaPion = track.tofNSigmaPi(); + tofNSigmaKaon = track.tofNSigmaKa(); + tofNSigmaProton = track.tofNSigmaPr(); + + histograms.fill(HIST("Reco/pt"), pt); + histograms.fill(HIST("Reco/hNSigmaTPCPion"), pt, tpcNSigmaPion); + histograms.fill(HIST("Reco/hNSigmaTPCKaon"), pt, tpcNSigmaKaon); + histograms.fill(HIST("Reco/hNSigmaTPCProton"), pt, tpcNSigmaProton); + histograms.fill(HIST("Reco/hNSigmaTOFPion"), pt, tofNSigmaPion); + histograms.fill(HIST("Reco/hNSigmaTOFKaon"), pt, tofNSigmaKaon); + histograms.fill(HIST("Reco/hNSigmaTOFProton"), pt, tofNSigmaProton); + + histograms.fill(HIST("Reco/vertices_perTrack"), 1); + if (PVrefit_doable) { + histograms.fill(HIST("Reco/vertices_perTrack"), 2); + } + /// PV refitting, if the tracks contributed to this at the beginning + o2::dataformats::VertexBase PVbase_recalculated; + bool recalc_imppar = false; + if (doPVrefit && PVrefit_doable) { + auto it_trk = std::find(vec_globID_contr.begin(), vec_globID_contr.end(), track.globalIndex()); /// track global index + // if( it_trk==vec_globID_contr.end() ) { + // /// not found: this track did not contribute to the initial PV fitting + // continue; + // } + if (it_trk != vec_globID_contr.end()) { + /// this track contributed to the PV fit: let's do the refit without it + const int entry = std::distance(vec_globID_contr.begin(), it_trk); + if (!keepAllTracksPVrefit) { + vec_useTrk_PVrefit[entry] = false; /// remove the track from the PV refitting + } + auto Pvtx_refitted = vertexer.refitVertex(vec_useTrk_PVrefit, Pvtx); // vertex refit + if (fDebug) { + LOG(info) << "refit " << cnt << "/" << ntr << " result = " << Pvtx_refitted.asString(); + } + + /// enable the dca recalculation for the current PV contributor, after removing it from the PV refit + recalc_imppar = true; + + if (Pvtx_refitted.getChi2() < 0 && fillHistoPVrefit) { + LOG(info) << "---> Refitted vertex has bad chi2 = " << Pvtx_refitted.getChi2(); + histograms.fill(HIST("Reco/X_PVrefitChi2minus1"), Pvtx_refitted.getX(), collision.posX()); + histograms.fill(HIST("Reco/Y_PVrefitChi2minus1"), Pvtx_refitted.getY(), collision.posY()); + histograms.fill(HIST("Reco/Z_PVrefitChi2minus1"), Pvtx_refitted.getZ(), collision.posZ()); + histograms.fill(HIST("Reco/nContrib_PVrefitChi2minus1"), collision.numContrib()); + recalc_imppar = false; + } else if (fillHistoPVrefit) { + histograms.fill(HIST("Reco/vertices_perTrack"), 3); + } + // histograms.fill(HIST("Reco/nContrib_vs_Chi2PVrefit"), /*Pvtx_refitted.getNContributors()*/collision.numContrib()-1, Pvtx_refitted.getChi2()); + histograms.fill(HIST("Reco/nContrib_vs_Chi2PVrefit"), vec_useTrk_PVrefit.size() - 1, Pvtx_refitted.getChi2()); + + vec_useTrk_PVrefit[entry] = true; /// restore the track for the next PV refitting + + if (recalc_imppar) { + // fill the histograms for refitted PV with good Chi2 + const double DeltaX = Pvtx.getX() - Pvtx_refitted.getX(); + const double DeltaY = Pvtx.getY() - Pvtx_refitted.getY(); + const double DeltaZ = Pvtx.getZ() - Pvtx_refitted.getZ(); + if (fillHistoPVrefit) { + histograms.fill(HIST("Reco/nContrib_vs_DeltaX_PVrefit"), collision.numContrib(), DeltaX); + histograms.fill(HIST("Reco/nContrib_vs_DeltaY_PVrefit"), collision.numContrib(), DeltaY); + histograms.fill(HIST("Reco/nContrib_vs_DeltaZ_PVrefit"), collision.numContrib(), DeltaZ); + } + // fill the newly calculated PV + PVbase_recalculated.setX(Pvtx_refitted.getX()); + PVbase_recalculated.setY(Pvtx_refitted.getY()); + PVbase_recalculated.setZ(Pvtx_refitted.getZ()); + PVbase_recalculated.setCov(Pvtx_refitted.getSigmaX2(), Pvtx_refitted.getSigmaXY(), Pvtx_refitted.getSigmaY2(), Pvtx_refitted.getSigmaXZ(), Pvtx_refitted.getSigmaYZ(), Pvtx_refitted.getSigmaZ2()); + } + + cnt++; + } + } /// end 'if (doPVrefit && PVrefit_doable)' + + /// impact parameter to the PV + // value calculated wrt global PV (not recalculated) ---> coming from trackextension workflow + impParRPhi = toMicrometers * track.dcaXY(); // dca.getY(); + impParZ = toMicrometers * track.dcaZ(); // dca.getY(); + // updated value after PV recalculation + if (recalc_imppar) { + if (fEnablePulls) { + auto trackParCov = getTrackParCov(track); + o2::dataformats::DCA dcaInfoCov{999, 999, 999, 999, 999}; + if (o2::base::Propagator::Instance()->propagateToDCABxByBz(PVbase_recalculated, trackParCov, 2.f, matCorr, &dcaInfoCov)) { + impParRPhi = dcaInfoCov.getY() * toMicrometers; + impParZ = dcaInfoCov.getZ() * toMicrometers; + } + } else { + auto trackPar = getTrackPar(track); + std::array dcaInfo{-999., -999.}; + if (o2::base::Propagator::Instance()->propagateToDCABxByBz({PVbase_recalculated.getX(), PVbase_recalculated.getY(), PVbase_recalculated.getZ()}, trackPar, 2.f, matCorr, &dcaInfo)) { + impParRPhi = dcaInfo[0] * toMicrometers; + impParZ = dcaInfo[1] * toMicrometers; + } + } + } + + /// 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 + if ((pt * 1000 - static_cast(pt * 1000)) > downsamplingFraction) { + // downsampling - do not consider the current track + continue; + } + + if (addTrackIUinfo) { + histograms.fill(HIST("Reco/h4ClusterSizeIU"), p, impParRPhi, trackIuPosX, trackIuPosY, trackIuPosZ, clusterSizeInLayer0); + histograms.fill(HIST("Reco/h4ImpParZIU"), p, impParZ, trackIuPosX, trackIuPosY, trackIuPosZ); + } + + 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/hNSigmaTPCPion_afterPID"), pt, tpcNSigmaPion); + histograms.fill(HIST("Reco/hNSigmaTOFPion_afterPID"), pt, tofNSigmaPion); + } + 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/hNSigmaTPCKaon_afterPID"), pt, tpcNSigmaKaon); + histograms.fill(HIST("Reco/hNSigmaTOFKaon_afterPID"), pt, tofNSigmaKaon); + } + 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/hNSigmaTPCProton_afterPID"), pt, tpcNSigmaProton); + histograms.fill(HIST("Reco/hNSigmaTOFProton_afterPID"), pt, tofNSigmaProton); + } + } + } /// end processReco +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec w{ + adaptAnalysisTask(cfgc)}; + return w; +} diff --git a/DPG/Tasks/MFT/aQCMFTTracks.cxx b/DPG/Tasks/MFT/aQCMFTTracks.cxx index 8b264102150..5b5f4a71aa4 100644 --- a/DPG/Tasks/MFT/aQCMFTTracks.cxx +++ b/DPG/Tasks/MFT/aQCMFTTracks.cxx @@ -16,46 +16,73 @@ /// \author David Grund /// \since +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + #include "CCDB/BasicCCDBManager.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsITSMFT/ROFRecord.h" #include "Framework/ASoAHelpers.h" - +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/DataTypes.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "CommonConstants/LHCConstants.h" #include "Framework/TimingInfo.h" -#include "DataFormatsITSMFT/ROFRecord.h" +#include "Framework/runDataProcessing.h" #include #include +#include + using namespace o2; using namespace o2::framework; using namespace o2::aod; struct CheckMFT { - HistogramRegistry registry{"registry", - {// 2d histograms - {"mMFTTrackEtaPhi_5_MinClusters", "Track #eta , #phi (NCls >= 5); #eta; #phi", {HistType::kTH2F, {{50, -4, -2}, {100, -3.2, 3.2}}}}, - {"mMFTTrackXY_5_MinClusters", "Track Position (NCls >= 5); x; y", {HistType::kTH2F, {{320, -16, 16}, {320, -16, 16}}}}, - {"mMFTTrackEtaPhi_7_MinClusters", "Track #eta , #phi (NCls >= 7); #eta; #phi", {HistType::kTH2F, {{50, -4, -2}, {100, -3.2, 3.2}}}}, - {"mMFTTrackXY_7_MinClusters", "Track Position (NCls >= 7); x; y", {HistType::kTH2F, {{320, -16, 16}, {320, -16, 16}}}}, - {"mMFTTrackEtaPhi_8_MinClusters", "Track #eta , #phi (NCls >= 8); #eta; #phi", {HistType::kTH2F, {{50, -4, -2}, {100, -3.2, 3.2}}}}, - {"mMFTTrackXY_8_MinClusters", "Track Position (NCls >= 8); x; y", {HistType::kTH2F, {{320, -16, 16}, {320, -16, 16}}}}, - // 1d histograms - {"mMFTTrackEta", "Track #eta; #eta; # entries", {HistType::kTH1F, {{50, -4, -2}}}}, - {"mMFTTrackNumberOfClusters", "Number Of Clusters Per Track; # clusters; # entries", {HistType::kTH1F, {{10, 0.5, 10.5}}}}, - {"mMFTTrackPhi", "Track #phi; #phi; # entries", {HistType::kTH1F, {{100, -3.2, 3.2}}}}, - {"mMFTTrackTanl", "Track tan #lambda; tan #lambda; # entries", {HistType::kTH1F, {{100, -25, 0}}}}, - {"mMFTTrackInvQPt", "Track q/p_{T}; q/p_{T} [1/GeV]; # entries", {HistType::kTH1F, {{250, -10, 10}}}}}}; + HistogramRegistry registry{"registry"}; + Configurable avClsPlots{"avClsPlots", false, "Enable average cluster plots"}; + + void init(o2::framework::InitContext&) + { + + const AxisSpec etaAxis{50, -4, -2, "#eta"}; + const AxisSpec phiAxis{100, -3.2, 3.2, "#phi"}; + const AxisSpec xAxis{320, -16, 16, "x"}; + const AxisSpec clsAxis{10, 0.5, 10.5, "# clusters"}; + const AxisSpec yAxis{320, -16, 16, "y"}; + const AxisSpec tanLamAxis{100, -25, 0, "tan #lambda"}; + const AxisSpec invQPtAxis{250, -10, 10, "q/p_{T} [1/GeV]"}; + + registry.add("mMFTTrackPhi", "Track #phi", {HistType::kTH1F, {phiAxis}}); + registry.add("mMFTTrackTanl", "Track tan #lambda", {HistType::kTH1F, {tanLamAxis}}); + registry.add("mMFTTrackInvQPt", "Track q/p_{T}", {HistType::kTH1F, {invQPtAxis}}); + registry.add("mMFTTrackEta", "Track #eta", {HistType::kTH1F, {etaAxis}}); + + registry.add("mMFTTrackEtaPhi_5_MinClusters", "Track Position (NCls >= 5)", {HistType::kTH2F, {etaAxis, phiAxis}}); + registry.add("mMFTTrackEtaPhi_6_MinClusters", "Track Position (NCls >= 6)", {HistType::kTH2F, {etaAxis, phiAxis}}); + registry.add("mMFTTrackEtaPhi_7_MinClusters", "Track Position (NCls >= 7)", {HistType::kTH2F, {etaAxis, phiAxis}}); + registry.add("mMFTTrackEtaPhi_8_MinClusters", "Track Position (NCls >= 8)", {HistType::kTH2F, {etaAxis, phiAxis}}); + + registry.add("mMFTTrackXY_5_MinClusters", "Track Position (NCls >= 5)", {HistType::kTH2F, {xAxis, yAxis}}); + registry.add("mMFTTrackXY_6_MinClusters", "Track Position (NCls >= 6)", {HistType::kTH2F, {xAxis, yAxis}}); + registry.add("mMFTTrackXY_7_MinClusters", "Track Position (NCls >= 7)", {HistType::kTH2F, {xAxis, yAxis}}); + registry.add("mMFTTrackXY_8_MinClusters", "Track Position (NCls >= 8)", {HistType::kTH2F, {xAxis, yAxis}}); + registry.add("mMFTTrackNumberOfClusters", "Number Of Clusters Per Track", {HistType::kTH1F, {clsAxis}}); + + if (avClsPlots) { + registry.add("mMFTTrackAvgClusters", "Average number of clusters per track; p;# clusters; # entries", {HistType::kTH2F, {{100, 0, 100}, {100, 0, 100}}}); + registry.add("mMFTTrackAvgClustersTru", "Average number of clusters per track; p;# clusters; # entries", {HistType::kTH2F, {{100, 0, 100}, {100, 0, 100}}}); + if (doprocessMC) { + registry.add("mMFTTrackAvgClustersHe", "Average number of clusters per track; p;# clusters; # entries", {HistType::kTH2F, {{100, 0, 100}, {100, 0, 100}}}); + registry.add("mMFTTrackAvgClustersTruHe", "Average number of clusters per track; p;# clusters; # entries", {HistType::kTH2F, {{100, 0, 100}, {100, 0, 100}}}); + } + } + } void process(aod::MFTTracks const& mfttracks) { - for (auto& track : mfttracks) { + for (const auto& track : mfttracks) { // 2d histograms float x = track.x(); float y = track.y(); @@ -65,14 +92,48 @@ struct CheckMFT { if (nCls >= 5) { registry.fill(HIST("mMFTTrackXY_5_MinClusters"), x, y); registry.fill(HIST("mMFTTrackEtaPhi_5_MinClusters"), eta, phi); - if (nCls >= 7) { - registry.fill(HIST("mMFTTrackXY_7_MinClusters"), x, y); - registry.fill(HIST("mMFTTrackEtaPhi_7_MinClusters"), eta, phi); - if (nCls >= 8) { - registry.fill(HIST("mMFTTrackXY_8_MinClusters"), x, y); - registry.fill(HIST("mMFTTrackEtaPhi_8_MinClusters"), eta, phi); + if (nCls >= 6) { + registry.fill(HIST("mMFTTrackXY_6_MinClusters"), x, y); + registry.fill(HIST("mMFTTrackEtaPhi_6_MinClusters"), eta, phi); + if (nCls >= 7) { + registry.fill(HIST("mMFTTrackXY_7_MinClusters"), x, y); + registry.fill(HIST("mMFTTrackEtaPhi_7_MinClusters"), eta, phi); + if (nCls >= 8) { + registry.fill(HIST("mMFTTrackXY_8_MinClusters"), x, y); + registry.fill(HIST("mMFTTrackEtaPhi_8_MinClusters"), eta, phi); + } + } + } + } + if (avClsPlots) { + static constexpr int kNcls = 10; + std::array clsSize; + for (unsigned int layer = 0; layer < kNcls; layer++) { + clsSize[layer] = (track.mftClusterSizesAndTrackFlags() >> (layer * 6)) & 0x3f; + // LOG(info) << "Layer " << layer << ": " << clsSize[layer]; + } + float avgCls = 0; + for (unsigned int layer = 0; layer < kNcls; layer++) { + avgCls += clsSize[layer]; + } + avgCls /= track.nClusters(); + + std::sort(clsSize.begin(), clsSize.end()); + float truncatedAvgCls = 0; + int ncls = 0; + for (unsigned int layer = 0; layer < kNcls; layer++) { + if (clsSize[layer] > 0) { + truncatedAvgCls += clsSize[layer]; + ncls++; + if (ncls >= 3) { + break; // we take the average of the first 5 non-zero clusters + } } } + truncatedAvgCls /= ncls; + + registry.fill(HIST("mMFTTrackAvgClusters"), track.p(), avgCls); + registry.fill(HIST("mMFTTrackAvgClustersTru"), track.p(), truncatedAvgCls); } // 1d histograms registry.fill(HIST("mMFTTrackEta"), eta); @@ -82,6 +143,49 @@ struct CheckMFT { registry.fill(HIST("mMFTTrackInvQPt"), track.signed1Pt()); } } + + void processMC(soa::Join const& mfttracks, + aod::McParticles const&) + { + static constexpr int kNcls = 10; + for (const auto& track : mfttracks) { + if (avClsPlots) { + std::array clsSize; + for (unsigned int layer = 0; layer < kNcls; layer++) { + clsSize[layer] = (track.mftClusterSizesAndTrackFlags() >> (layer * 6)) & 0x3f; + // LOG(info) << "Layer " << layer << ": " << clsSize[layer]; + } + float avgCls = 0; + for (unsigned int layer = 0; layer < kNcls; layer++) { + avgCls += clsSize[layer]; + } + avgCls /= track.nClusters(); + + std::sort(clsSize.begin(), clsSize.end()); + float truncatedAvgCls = 0; + int ncls = 0; + for (unsigned int layer = 0; layer < kNcls; layer++) { + if (clsSize[layer] > 0) { + truncatedAvgCls += clsSize[layer]; + ncls++; + if (ncls >= 3) { + break; // we take the average of the first 5 non-zero clusters + } + } + } + truncatedAvgCls /= ncls; + + if (track.has_mcParticle()) { + const auto& mcParticle = track.mcParticle(); + if (std::abs(mcParticle.pdgCode()) == 1000020040) { // He4 + registry.fill(HIST("mMFTTrackAvgClustersHe"), track.p(), avgCls); + registry.fill(HIST("mMFTTrackAvgClustersTruHe"), track.p(), truncatedAvgCls); + } + } + } + } + } + PROCESS_SWITCH(CheckMFT, processMC, "Process MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/DPG/Tasks/TOF/tofOfflineCalib.cxx b/DPG/Tasks/TOF/tofOfflineCalib.cxx index ccfea13f1b1..950efc83e07 100644 --- a/DPG/Tasks/TOF/tofOfflineCalib.cxx +++ b/DPG/Tasks/TOF/tofOfflineCalib.cxx @@ -16,15 +16,17 @@ /// \brief Task to produce calibration objects for the TOF. Based on AO2D or TOF skimmed data /// -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "tofSkimsTableCreator.h" + #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "tofSkimsTableCreator.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; diff --git a/DPG/Tasks/TOF/tofSkimsTableCreator.cxx b/DPG/Tasks/TOF/tofSkimsTableCreator.cxx index 1c2d1a79608..c61a3336982 100644 --- a/DPG/Tasks/TOF/tofSkimsTableCreator.cxx +++ b/DPG/Tasks/TOF/tofSkimsTableCreator.cxx @@ -16,15 +16,16 @@ /// \brief Task to defined the skimmed data format for the TOF skims /// -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "tofSkimsTableCreator.h" + #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "tofSkimsTableCreator.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; 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..7d2afbfec96 100644 --- a/DPG/Tasks/TPC/tpcSkimsTableCreator.cxx +++ b/DPG/Tasks/TPC/tpcSkimsTableCreator.cxx @@ -15,81 +15,242 @@ /// \author Annalena Kalteyer /// \author Christian Sonnabend /// \author Jeremy Wilkinson +/// \author Oleksii Lubynets #include "tpcSkimsTableCreator.h" -#include -#include -/// ROOT -#include "TRandom3.h" -/// O2 -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" -/// O2Physics -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "utilsTpcSkimsTableCreator.h" + #include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "Common/DataModel/Multiplicity.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/OccupancyTables.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTPCBase.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include using namespace o2; +using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::track; using namespace o2::dataformats; +using namespace o2::dpg_tpcskimstablecreator; struct TreeWriterTpcV0 { + Service ccdb; + using Trks = soa::Join; - using Coll = soa::Join; + using TrksWithDEdxCorrection = soa::Join; + using Colls = soa::Join; + using MyBCTable = soa::Join; + using V0sWithID = soa::Join; + using CascsWithID = soa::Join; /// Tables to be produced Produces rowTPCTree; + Produces rowTPCTreeWithdEdxTrkQA; + Produces rowTPCTreeWithTrkQA; + + constexpr static o2::track::PID::ID PidElectron{o2::track::PID::Electron}; + constexpr static o2::track::PID::ID PidPion{o2::track::PID::Pion}; + constexpr static o2::track::PID::ID PidKaon{o2::track::PID::Kaon}; + constexpr static o2::track::PID::ID PidProton{o2::track::PID::Proton}; + + // an arbitrary value of N sigma TOF assigned by TOF task to tracks which are not matched to TOF hits + constexpr static float NSigmaTofUnmatched{-1e6f}; + constexpr static float NSigmaTofUnmatchedEqualityTolerance{1000.f}; + + // an arbitrary value of "N sigma TOF" assigned to electorns (for uniformity reasons) + constexpr static float NSigmaTofElectorn{1000.f}; /// Configurables - Configurable nSigmaTOFdautrack{"nSigmaTOFdautrack", 5., "n-sigma TOF cut on the daughter tracks. Set 0 to switch it off."}; + Configurable nSigmaTofDauTrackPi{"nSigmaTofDauTrackPi", 999.f, "n-sigma TOF cut on the pion daughter tracks"}; + Configurable nSigmaTofDauTrackPr{"nSigmaTofDauTrackPr", 999.f, "n-sigma TOF cut on the proton daughter tracks"}; + Configurable nSigmaTofDauTrackKa{"nSigmaTofDauTrackKa", 999.f, "n-sigma TOF cut on the kaon daughter tracks"}; + Configurable rejectNoTofDauTrackPi{"rejectNoTofDauTrackPi", false, "reject not matched to TOF pion daughter tracks"}; + Configurable rejectNoTofDauTrackPr{"rejectNoTofDauTrackPr", false, "reject not matched to TOF proton daughter tracks"}; + Configurable rejectNoTofDauTrackKa{"rejectNoTofDauTrackKa", false, "reject not matched to TOF kaon daughter tracks"}; 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"}; + Configurable trackSelection{"trackSelection", 0, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; /// Configurables downsampling - Configurable dwnSmplFactor_Pi{"dwnSmplFactor_Pi", 1., "downsampling factor for pions, default fraction to keep is 1."}; - Configurable dwnSmplFactor_Pr{"dwnSmplFactor_Pr", 1., "downsampling factor for protons, default fraction to keep is 1."}; - Configurable dwnSmplFactor_El{"dwnSmplFactor_El", 1., "downsampling factor for electrons, default fraction to keep is 1."}; - Configurable sqrtSNN{"sqrt_s_NN", 0., "sqrt(s_NN), used for downsampling with the Tsallis distribution"}; + Configurable dwnSmplFactorPi{"dwnSmplFactorPi", 1., "downsampling factor for pions, default fraction to keep is 1."}; + Configurable dwnSmplFactorPr{"dwnSmplFactorPr", 1., "downsampling factor for protons, default fraction to keep is 1."}; + Configurable dwnSmplFactorEl{"dwnSmplFactorEl", 1., "downsampling factor for electrons, default fraction to keep is 1."}; + Configurable dwnSmplFactorKa{"dwnSmplFactorKa", 1., "downsampling factor for kaons, default fraction to keep is 1."}; + Configurable sqrtSNN{"sqrtSNN", 5360., "sqrt(s_NN), used for downsampling with the Tsallis distribution"}; 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 downsamplingTsalisKaons{"downsamplingTsalisKaons", -1., "Downsampling factor to reduce the number of kaons"}; + 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"}; + Configurable maxPt4dwnsmplTsalisKaons{"maxPt4dwnsmplTsalisKaons", 100., "Maximum Pt for applying downsampling factor of kaons"}; + + enum { // Reconstructed V0 and cascade + MotherUndef = -1, + MotherGamma = 0, + MotherK0S, + MotherLambda, + MotherAntiLambda, + MotherOmega, + MotherAntiOmega + }; - Filter trackFilter = (trackSelection.node() == 0) || - ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || - ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || - ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || - ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || - ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); + enum { + DaughterElectron = 0, + DaughterPion, + DaughterKaon, + DaughterProton + }; + + ctpRateFetcher mRateFetcher; + + struct V0Daughter { + double downsamplingTsalis{-999.}; + double mass{-999.}; + double maxPt4dwnsmplTsalis{-999.}; + double tpcNSigma{-999.}; + double tofNSigma{-999.}; + double tpcExpSignal{-999.}; + o2::track::PID::ID id{0}; + double dwnSmplFactor{-999.}; + double nSigmaTofDauTrack{-999.}; + bool rejectNoTofDauTrack{false}; + }; - /// 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) + template + V0Daughter createV0Daughter(const V0Casc& v0Casc, const T& track, const int motherId, const int daughterId, const bool isPositive = true) + { + switch (daughterId) { + case DaughterElectron: + return V0Daughter{downsamplingTsalisElectrons, MassElectron, maxPt4dwnsmplTsalisElectrons, track.tpcNSigmaEl(), getStrangenessTofNSigma(v0Casc, motherId, daughterId, isPositive), track.tpcExpSignalEl(tpcSignalGeneric(track)), PidElectron, dwnSmplFactorEl, NSigmaTofElectorn + 1.f, false}; + case DaughterPion: + return V0Daughter{downsamplingTsalisPions, MassPiPlus, maxPt4dwnsmplTsalisPions, track.tpcNSigmaPi(), getStrangenessTofNSigma(v0Casc, motherId, daughterId, isPositive), track.tpcExpSignalPi(tpcSignalGeneric(track)), PidPion, dwnSmplFactorPi, nSigmaTofDauTrackPi, rejectNoTofDauTrackPi}; + case DaughterProton: + return V0Daughter{downsamplingTsalisProtons, MassProton, maxPt4dwnsmplTsalisProtons, track.tpcNSigmaPr(), getStrangenessTofNSigma(v0Casc, motherId, daughterId, isPositive), track.tpcExpSignalPr(tpcSignalGeneric(track)), PidProton, dwnSmplFactorPr, nSigmaTofDauTrackPr, rejectNoTofDauTrackPr}; + case DaughterKaon: + return V0Daughter{downsamplingTsalisKaons, MassKPlus, maxPt4dwnsmplTsalisKaons, track.tpcNSigmaKa(), getStrangenessTofNSigma(v0Casc, motherId, daughterId, isPositive), track.tpcExpSignalKa(tpcSignalGeneric(track)), PidKaon, dwnSmplFactorKa, nSigmaTofDauTrackKa, rejectNoTofDauTrackKa}; + default: { + LOGP(fatal, "createV0Daughter: unknown daughterId"); + return V0Daughter(); + } + } + } + + struct V0Mother { + int posDaughterId{-999}; + int negDaughterId{-999}; + }; + + V0Mother createV0Mother(const int motherId) + { + switch (motherId) { + case MotherGamma: + return V0Mother{DaughterElectron, DaughterElectron}; + case MotherK0S: + return V0Mother{DaughterPion, DaughterPion}; + case MotherLambda: + return V0Mother{DaughterProton, DaughterPion}; + case MotherAntiLambda: + return V0Mother{DaughterPion, DaughterProton}; + default: { + LOGP(fatal, "createV0Mother: unknown motherId"); + return V0Mother(); + } + } + } + + float getStrangenessTofNSigma(V0sWithID::iterator const& v0, const int motherId, const int daughterId, const bool isPositive) + { + if (motherId == MotherGamma && daughterId == DaughterElectron) { + return NSigmaTofElectorn; + } else if (motherId == MotherK0S && daughterId == DaughterPion) { + if (isPositive) + return v0.tofNSigmaK0PiPlus(); + else + return v0.tofNSigmaK0PiMinus(); + } else if (motherId == MotherLambda) { + if (daughterId == DaughterProton && isPositive) + return v0.tofNSigmaLaPr(); + else if (daughterId == DaughterPion && !isPositive) + return v0.tofNSigmaLaPi(); + } else if (motherId == MotherAntiLambda) { + if (daughterId == DaughterProton && !isPositive) + return v0.tofNSigmaALaPr(); + else if (daughterId == DaughterPion && isPositive) + return v0.tofNSigmaALaPi(); + } + + LOGP(fatal, "getStrangenessTofNSigma for V0: wrong combination of motherId, daughterId and sign"); + return -999.f; + } + + float getStrangenessTofNSigma(CascsWithID::iterator const& casc, const int motherId, const int daughterId, bool) + { + if ((motherId == MotherOmega || motherId == MotherAntiOmega) && daughterId == DaughterKaon) + return casc.tofNSigmaOmKa(); + + LOGP(fatal, "getStrangenessTofNSigma for cascade: wrong combination of motherId and daughterId"); + return -999.f; + } + + /// Function to fill skimmed tables + template + void fillSkimmedV0Table(V0Casc const& v0casc, T const& track, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float dEdxExp, const o2::track::PID::ID id, const int runnumber, const double dwnSmplFactor, const float hadronicRate) { const double ncl = track.tpcNClsFound(); + const double nclPID = track.tpcNClsFindableMinusPID(); const double p = track.tpcInnerParam(); const double mass = o2::track::pid_constants::sMasses[id]; const double bg = p / mass; const int multTPC = collision.multTPC(); + const auto trackOcc = collision.trackOccupancyInTimeRange(); + const 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 float alpha = v0casc.alpha(); + const float qt = v0casc.qtarm(); + const float cosPA = getCosPA(v0casc, collision); + const float pT = v0casc.pt(); + const float v0radius = getRadius(v0casc); + const float gammapsipair = v0casc.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(), + float usedDedx; + if constexpr (DoUseCorrectedDeDx) { + usedDedx = track.tpcSignalCorrected(); + } else { + usedDedx = track.tpcSignal(); + } + rowTPCTree(usedDedx, 1. / dEdxExp, track.tpcInnerParam(), track.tgl(), @@ -101,227 +262,486 @@ struct TreeWriterTpcV0 { bg, multTPC / 11000., std::sqrt(nClNorm / ncl), + nclPID, id, nSigmaTPC, nSigmaTOF, + runnumber, + trackOcc, + ft0Occ, + hadronicRate, alpha, qt, cosPA, pT, v0radius, - gammapsipair, - runnumber); + gammapsipair); } }; - double tsalisCharged(double pt, double mass, double sqrts) + template + void fillSkimmedV0TableWithTrQAGeneric(V0Casc const& v0casc, T const& track, TQA const& trackQA, const bool existTrkQA, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float dEdxExp, const o2::track::PID::ID id, const int runnumber, const double dwnSmplFactor, const float hadronicRate, const int bcGlobalIndex, const int bcTimeFrameId, const int bcBcInTimeFrame) { - const double a = 6.81, b = 59.24; - const double c = 0.082, d = 0.151; - const double mt = std::sqrt(mass * mass + pt * pt); - const double n = a + b / sqrts; - const double T = c + d / sqrts; - const double p0 = n * T; - const double result = std::pow((1. + mt / p0), -n); - return result; - }; + const double ncl = track.tpcNClsFound(); + const double nclPID = track.tpcNClsFindableMinusPID(); + const double p = track.tpcInnerParam(); + const double mass = o2::track::pid_constants::sMasses[id]; + const double bg = p / mass; + const int multTPC = collision.multTPC(); + const auto trackOcc = collision.trackOccupancyInTimeRange(); + const auto ft0Occ = collision.ft0cOccupancyInTimeRange(); - /// 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) - { - if (factor1Pt < 0.) { - 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) { - return false; - } else { - return true; - } - }; + const float alpha = v0casc.alpha(); + const float qt = v0casc.qtarm(); + const float cosPA = getCosPA(v0casc, collision); + const float pT = v0casc.pt(); + const float v0radius = getRadius(v0casc); + const float gammapsipair = v0casc.psipair(); - /// Event selection - template - bool isEventSelected(const CollisionType& collision, const TrackType& /*tracks*/) - { - if (applyEvSel == 1) { - if (!collision.sel7()) { - return false; + const double pseudoRndm = track.pt() * 1000. - static_cast(track.pt() * 1000); + if (pseudoRndm < dwnSmplFactor) { + float usedDedx; + if constexpr (DoUseCorrectedDeDx) { + usedDedx = track.tpcSignalCorrected(); + } else { + usedDedx = track.tpcSignal(); } - } else if (applyEvSel == 2) { - if (!collision.sel8()) { - return false; + if constexpr (IsWithdEdx) { + rowTPCTreeWithdEdxTrkQA(usedDedx, + 1. / dEdxExp, + track.tpcInnerParam(), + track.tgl(), + track.signed1Pt(), + track.eta(), + track.phi(), + track.y(), + mass, + bg, + multTPC / 11000., + std::sqrt(nClNorm / ncl), + nclPID, + id, + nSigmaTPC, + nSigmaTOF, + runnumber, + trackOcc, + ft0Occ, + hadronicRate, + alpha, + qt, + cosPA, + pT, + v0radius, + gammapsipair, + existTrkQA ? trackQA.tpcdEdxNorm() : -999); + } else { + rowTPCTreeWithTrkQA(usedDedx, + 1. / dEdxExp, + track.tpcInnerParam(), + track.tgl(), + track.signed1Pt(), + track.eta(), + track.phi(), + track.y(), + mass, + bg, + multTPC / 11000., + std::sqrt(nClNorm / ncl), + nclPID, + id, + nSigmaTPC, + nSigmaTOF, + runnumber, + trackOcc, + ft0Occ, + hadronicRate, + alpha, + qt, + cosPA, + pT, + v0radius, + gammapsipair, + 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, + existTrkQA ? trackQA.tpcdEdxNorm() : -999); } } - return true; - }; + } + + TRandom3* fRndm = new TRandom3(0); void init(o2::framework::InitContext&) { + const std::array doprocess{doprocessStandard, doprocessStandardWithCorrecteddEdx, doprocessWithdEdxTrQA, doprocessWithdEdxTrQAWithCorrecteddEdx, doprocessWithTrQA, doprocessWithTrQAWithCorrecteddEdx, doprocessDummy}; + if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { + LOGP(fatal, "One and only one process function should be enabled"); + } + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + } + + /// Evaluate cosPA of the v0 + template + double getCosPA(V0sWithID::iterator const& v0, CollisionType const&) + { + return v0.v0cosPA(); } - /// 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&) + /// Evaluate cosPA of the cascade + template + double getCosPA(CascsWithID::iterator const& casc, CollisionType const& collision) + { + return casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + } + + /// Evaluate radius of the v0 + double getRadius(V0sWithID::iterator const& v0) + { + return v0.v0radius(); + } + + /// Evaluate radius of the cascade + double getRadius(CascsWithID::iterator const& casc) + { + return casc.cascradius(); + } + + /// Evaluate tpcSignal with or without correction + template + double tpcSignalGeneric(const TrkType& track) + { + if constexpr (IsCorrectedDeDx) { + return track.tpcSignalCorrected(); + } else { + return track.tpcSignal(); + } + } + + template + void runStandard(Colls::iterator const& collision, V0sWithID const& v0s, CascsWithID const& cascs) { /// Check event slection - if (!isEventSelected(collision, tracks)) { + if (!isEventSelected(collision, applyEvSel)) { return; } - auto bc = collision.bc_as(); + const auto& bc = collision.bc_as(); const int runnumber = bc.runNumber(); + const float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, irSource) * 1.e-3; + + rowTPCTree.reserve(2 * v0s.size() + cascs.size()); - rowTPCTree.reserve(tracks.size()); + auto fillDaughterTrack = [&](const auto& mother, const TrksType::iterator& dauTrack, const V0Daughter& daughter) { + const bool passTrackSelection = isTrackSelected(dauTrack, trackSelection); + const bool passDownsamplig = downsampleTsalisCharged(fRndm, dauTrack.pt(), daughter.downsamplingTsalis, daughter.mass, sqrtSNN, daughter.maxPt4dwnsmplTsalis); + const bool passNSigmaTofCut = std::fabs(daughter.tofNSigma) < daughter.nSigmaTofDauTrack || std::fabs(daughter.tofNSigma - NSigmaTofUnmatched) < NSigmaTofUnmatchedEqualityTolerance; + const bool passMatchTofRequirement = !daughter.rejectNoTofDauTrack || std::fabs(daughter.tofNSigma - NSigmaTofUnmatched) > NSigmaTofUnmatchedEqualityTolerance; + if (passTrackSelection && passDownsamplig && passNSigmaTofCut && passMatchTofRequirement) { + fillSkimmedV0Table(mother, dauTrack, collision, daughter.tpcNSigma, daughter.tofNSigma, daughter.tpcExpSignal, daughter.id, runnumber, daughter.dwnSmplFactor, hadronicRate); + } + }; /// Loop over v0 candidates - for (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(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); - } + for (const auto& v0 : v0s) { + const auto v0Id = v0.v0addid(); + if (v0Id == MotherUndef) { + continue; } - // 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(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); - } + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + + const V0Mother v0Mother = createV0Mother(v0Id); + const V0Daughter posDaughter = createV0Daughter(v0, posTrack, v0Id, v0Mother.posDaughterId, true); + const V0Daughter negDaughter = createV0Daughter(v0, negTrack, v0Id, v0Mother.negDaughterId, false); + + fillDaughterTrack(v0, posTrack, posDaughter); + fillDaughterTrack(v0, negTrack, negDaughter); + } + + /// Loop over cascade candidates + for (const auto& casc : cascs) { + const auto cascId = casc.cascaddid(); + if (cascId == MotherUndef) { + continue; } - // 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); + const auto& bachTrack = casc.bachelor_as(); + const V0Daughter bachDaughter = createV0Daughter(casc, bachTrack, cascId, DaughterKaon); + // Omega and antiomega + fillDaughterTrack(casc, bachTrack, bachDaughter); + } + } + + /// Apply a track quality selection with a filter! + void processStandard(Colls::iterator const& collision, Trks const&, V0sWithID const& v0s, CascsWithID const& cascs, aod::BCsWithTimestamps const&) + { + runStandard(collision, v0s, cascs); + } /// process Standard + PROCESS_SWITCH(TreeWriterTpcV0, processStandard, "Standard V0 Samples for PID", true); + + void processStandardWithCorrecteddEdx(Colls::iterator const& collision, TrksWithDEdxCorrection const&, V0sWithID const& v0s, CascsWithID const& cascs, aod::BCsWithTimestamps const&) + { + runStandard(collision, v0s, cascs); + } /// process StandardWithCorrecteddEdx + PROCESS_SWITCH(TreeWriterTpcV0, processStandardWithCorrecteddEdx, "Standard V0 Samples for PID with corrected dEdx", false); + + Preslice perCollisionV0s = aod::v0data::collisionId; + Preslice perCollisionCascs = aod::cascdata::collisionId; + + template + void runWithTrQAGeneric(Colls const& collisions, TrksType const& myTracks, V0sWithID const& myV0s, CascsWithID const& myCascs, aod::TracksQAVersion const& tracksQA) + { + std::vector labelTrack2TrackQA(myTracks.size(), -1); + for (const auto& trackQA : tracksQA) { + const int64_t trackId = trackQA.trackId(); + labelTrack2TrackQA.at(trackId) = trackQA.globalIndex(); + } + for (const auto& collision : collisions) { + /// Check event slection + if (!isEventSelected(collision, applyEvSel)) { + continue; + } + const auto& v0s = myV0s.sliceBy(perCollisionV0s, collision.globalIndex()); + const auto& cascs = myCascs.sliceBy(perCollisionCascs, collision.globalIndex()); + const auto& bc = collision.bc_as(); + const int runnumber = bc.runNumber(); + const float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, irSource) * 1.e-3; + const int bcGlobalIndex = bc.globalIndex(); + int bcTimeFrameId, bcBcInTimeFrame; + if constexpr (IsWithdEdx) { + bcTimeFrameId = -999; + bcBcInTimeFrame = -999; + } else { + bcTimeFrameId = bc.tfId(); + bcBcInTimeFrame = bc.bcInTF(); + } + if constexpr (IsWithdEdx) { + rowTPCTreeWithdEdxTrkQA.reserve(2 * v0s.size() + cascs.size()); + } else { + rowTPCTreeWithTrkQA.reserve(2 * v0s.size() + cascs.size()); + } + + auto fillDaughterTrack = [&](const auto& mother, const TrksType::iterator& dauTrack, const V0Daughter& daughter, const aod::TracksQA& trackQAInstance, const bool existTrkQA) { + const bool passTrackSelection = isTrackSelected(dauTrack, trackSelection); + const bool passDownsamplig = downsampleTsalisCharged(fRndm, dauTrack.pt(), daughter.downsamplingTsalis, daughter.mass, sqrtSNN, daughter.maxPt4dwnsmplTsalis); + const bool passNSigmaTofCut = std::fabs(daughter.tofNSigma) < daughter.nSigmaTofDauTrack || std::fabs(daughter.tofNSigma - NSigmaTofUnmatched) < NSigmaTofUnmatchedEqualityTolerance; + const bool passMatchTofRequirement = !daughter.rejectNoTofDauTrack || std::fabs(daughter.tofNSigma - NSigmaTofUnmatched) > NSigmaTofUnmatchedEqualityTolerance; + if (passTrackSelection && passDownsamplig && passNSigmaTofCut && passMatchTofRequirement) { + fillSkimmedV0TableWithTrQAGeneric(mother, dauTrack, trackQAInstance, existTrkQA, collision, daughter.tpcNSigma, daughter.tofNSigma, daughter.tpcExpSignal, daughter.id, runnumber, daughter.dwnSmplFactor, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); } - 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); + }; + + auto getTrackQA = [&](const TrksType::iterator& track) { + const auto trackGlobalIndex = track.globalIndex(); + const auto label = labelTrack2TrackQA.at(trackGlobalIndex); + const bool existTrkQA = (label != -1); + const int64_t trkIndex = existTrkQA ? label : 0; + const aod::TracksQA& trkQA = tracksQA.iteratorAt(trkIndex); + + return std::make_pair(trkQA, existTrkQA); + }; + + /// Loop over v0 candidates + for (const auto& v0 : v0s) { + const auto v0Id = v0.v0addid(); + if (v0Id == MotherUndef) { + continue; } + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + + const auto& [posTrackQA, existPosTrkQA] = getTrackQA(posTrack); + const auto& [negTrackQA, existNegTrkQA] = getTrackQA(negTrack); + + const V0Mother v0Mother = createV0Mother(v0Id); + const V0Daughter posDaughter = createV0Daughter(v0, posTrack, v0Id, v0Mother.posDaughterId, true); + const V0Daughter negDaughter = createV0Daughter(v0, negTrack, v0Id, v0Mother.negDaughterId, false); + + fillDaughterTrack(v0, posTrack, posDaughter, posTrackQA, existPosTrkQA); + fillDaughterTrack(v0, negTrack, negDaughter, negTrackQA, existNegTrkQA); } - // 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(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); + + /// Loop over cascade candidates + for (const auto& casc : cascs) { + const auto cascId = casc.cascaddid(); + if (cascId == MotherUndef) { + continue; } + const auto& bachTrack = casc.bachelor_as(); + const V0Daughter bachDaughter = createV0Daughter(casc, bachTrack, cascId, DaughterKaon); + const auto& [bachTrackQA, existBachTrkQA] = getTrackQA(bachTrack); + // Omega and antiomega + fillDaughterTrack(casc, bachTrack, bachDaughter, bachTrackQA, existBachTrkQA); } } - } /// process -}; /// struct TreeWriterTpcV0 + } + + void processWithdEdxTrQA(Colls const& collisions, Trks const& myTracks, V0sWithID const& myV0s, CascsWithID const& myCascs, aod::BCsWithTimestamps const&, aod::TracksQAVersion const& tracksQA) + { + runWithTrQAGeneric(collisions, myTracks, myV0s, myCascs, tracksQA); + } /// process with dEdx from TrackQA + PROCESS_SWITCH(TreeWriterTpcV0, processWithdEdxTrQA, "Standard V0 Samples with dEdx from Track QA for PID", false); -struct TreeWriterTPCTOF { - using Trks = soa::Join; - using Coll = soa::Join; + void processWithdEdxTrQAWithCorrecteddEdx(Colls const& collisions, TrksWithDEdxCorrection const& myTracks, V0sWithID const& myV0s, CascsWithID const& myCascs, aod::BCsWithTimestamps const&, aod::TracksQAVersion const& tracksQA) + { + runWithTrQAGeneric(collisions, myTracks, myV0s, myCascs, tracksQA); + } /// process with dEdx from TrackQA + PROCESS_SWITCH(TreeWriterTpcV0, processWithdEdxTrQAWithCorrecteddEdx, "Standard V0 Samples with dEdx from Track QA for PID with corrected dEdx", false); + + void processWithTrQA(Colls const& collisions, Trks const& myTracks, V0sWithID const& myV0s, CascsWithID const& myCascs, MyBCTable const&, aod::TracksQAVersion const& tracksQA) + { + runWithTrQAGeneric(collisions, myTracks, myV0s, myCascs, tracksQA); + } /// process with TrackQA + PROCESS_SWITCH(TreeWriterTpcV0, processWithTrQA, "Standard V0 Samples with Track QA for PID", false); + + void processWithTrQAWithCorrecteddEdx(Colls const& collisions, TrksWithDEdxCorrection const& myTracks, V0sWithID const& myV0s, CascsWithID const& myCascs, MyBCTable const&, aod::TracksQAVersion const& tracksQA) + { + runWithTrQAGeneric(collisions, myTracks, myV0s, myCascs, tracksQA); + } /// process with TrackQA + PROCESS_SWITCH(TreeWriterTpcV0, processWithTrQAWithCorrecteddEdx, "Standard V0 Samples with Track QA for PID with corrected dEdx", false); + + void processDummy(Colls const&) {} + PROCESS_SWITCH(TreeWriterTpcV0, processDummy, "Dummy function", false); + +}; /// struct TreeWriterTpcV0 + +struct TreeWriterTpcTof { + + Service ccdb; + + using Trks = soa::Join; + using TrksWithDEdxCorrection = soa::Join; + using Colls = soa::Join; + using MyBCTable = soa::Join; /// Tables to be produced Produces rowTPCTOFTree; + Produces rowTPCTOFTreeWithdEdxTrkQA; + Produces rowTPCTOFTreeWithTrkQA; + + constexpr static o2::track::PID::ID PidPion{o2::track::PID::Pion}; + constexpr static o2::track::PID::ID PidKaon{o2::track::PID::Kaon}; + constexpr static o2::track::PID::ID PidProton{o2::track::PID::Proton}; + constexpr static o2::track::PID::ID PidDeuteron{o2::track::PID::Deuteron}; + constexpr static o2::track::PID::ID PidTriton{o2::track::PID::Triton}; /// Configurables 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 applyTrkSel{"applyTrkSel", 1, "Flag to apply track selection: 0 -> no track selection, 1 -> track selection"}; Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; /// Triton Configurable maxMomTPCOnlyTr{"maxMomTPCOnlyTr", 1.5, "Maximum momentum for TPC only cut triton"}; Configurable maxMomHardCutOnlyTr{"maxMomHardCutOnlyTr", 50, "Maximum TPC inner momentum for triton"}; Configurable nSigmaTPCOnlyTr{"nSigmaTPCOnlyTr", 4., "number of sigma for TPC only cut triton"}; - Configurable nSigmaTPC_TPCTOF_Tr{"nSigmaTPC_TPCTOF_Tr", 4., "number of sigma for TPC cut for TPC and TOF combined triton"}; - Configurable nSigmaTOF_TPCTOF_Tr{"nSigmaTOF_TPCTOF_Tr", 3., "number of sigma for TOF cut for TPC and TOF combined triton"}; - Configurable dwnSmplFactor_Tr{"dwnSmplFactor_Tr", 1., "downsampling factor for triton, default fraction to keep is 1."}; + Configurable nSigmaTpcTpctofTr{"nSigmaTpcTpctofTr", 4., "number of sigma for TPC cut for TPC and TOF combined triton"}; + Configurable nSigmaTofTpctofTr{"nSigmaTofTpctofTr", 3., "number of sigma for TOF cut for TPC and TOF combined triton"}; + Configurable dwnSmplFactorTr{"dwnSmplFactorTr", 1., "downsampling factor for triton, default fraction to keep is 1."}; /// Deuteron Configurable maxMomTPCOnlyDe{"maxMomTPCOnlyDe", 1.0, "Maximum momentum for TPC only cut deuteron"}; Configurable maxMomHardCutOnlyDe{"maxMomHardCutOnlyDe", 50, "Maximum TPC inner momentum for deuteron"}; Configurable nSigmaTPCOnlyDe{"nSigmaTPCOnlyDe", 4., "number of sigma for TPC only cut deuteron"}; - Configurable nSigmaTPC_TPCTOF_De{"nSigmaTPC_TPCTOF_De", 4., "number of sigma for TPC cut for TPC and TOF combined deuteron"}; - Configurable nSigmaTOF_TPCTOF_De{"nSigmaTOF_TPCTOF_De", 3., "number of sigma for TOF cut for TPC and TOF combined deuteron"}; - Configurable dwnSmplFactor_De{"dwnSmplFactor_De", 1., "downsampling factor for deuteron, default fraction to keep is 1."}; + Configurable nSigmaTpcTpctofDe{"nSigmaTpcTpctofDe", 4., "number of sigma for TPC cut for TPC and TOF combined deuteron"}; + Configurable nSigmaTofTpctofDe{"nSigmaTofTpctofDe", 3., "number of sigma for TOF cut for TPC and TOF combined deuteron"}; + Configurable dwnSmplFactorDe{"dwnSmplFactorDe", 1., "downsampling factor for deuteron, default fraction to keep is 1."}; /// Proton Configurable maxMomTPCOnlyPr{"maxMomTPCOnlyPr", 0.6, "Maximum momentum for TPC only cut proton"}; Configurable nSigmaTPCOnlyPr{"nSigmaTPCOnlyPr", 4., "number of sigma for TPC only cut proton"}; - Configurable nSigmaTPC_TPCTOF_Pr{"nSigmaTPC_TPCTOF_Pr", 4., "number of sigma for TPC cut for TPC and TOF combined proton"}; - Configurable nSigmaTOF_TPCTOF_Pr{"nSigmaTOF_TPCTOF_Pr", 3., "number of sigma for TOF cut for TPC and TOF combined proton"}; - Configurable dwnSmplFactor_Pr{"dwnSmplFactor_Pr", 1., "downsampling factor for protons, default fraction to keep is 1."}; + Configurable nSigmaTpcTpctofPr{"nSigmaTpcTpctofPr", 4., "number of sigma for TPC cut for TPC and TOF combined proton"}; + Configurable nSigmaTofTpctofPr{"nSigmaTofTpctofPr", 3., "number of sigma for TOF cut for TPC and TOF combined proton"}; + Configurable dwnSmplFactorPr{"dwnSmplFactorPr", 1., "downsampling factor for protons, default fraction to keep is 1."}; /// Kaon Configurable maxMomTPCOnlyKa{"maxMomTPCOnlyKa", 0.3, "Maximum momentum for TPC only cut kaon"}; Configurable maxMomHardCutOnlyKa{"maxMomHardCutOnlyKa", 50, "Maximum TPC inner momentum for kaons"}; Configurable nSigmaTPCOnlyKa{"nSigmaTPCOnlyKa", 4., "number of sigma for TPC only cut kaon"}; - Configurable nSigmaTPC_TPCTOF_Ka{"nSigmaTPC_TPCTOF_Ka", 4., "number of sigma for TPC cut for TPC and TOF combined kaon"}; - Configurable nSigmaTOF_TPCTOF_Ka{"nSigmaTOF_TPCTOF_Ka", 3., "number of sigma for TOF cut for TPC and TOF combined kaon"}; - Configurable dwnSmplFactor_Ka{"dwnSmplFactor_Ka", 1., "downsampling factor for kaons, default fraction to keep is 1."}; + Configurable nSigmaTpcTpctofKa{"nSigmaTpcTpctofKa", 4., "number of sigma for TPC cut for TPC and TOF combined kaon"}; + Configurable nSigmaTofTpctofKa{"nSigmaTofTpctofKa", 3., "number of sigma for TOF cut for TPC and TOF combined kaon"}; + Configurable dwnSmplFactorKa{"dwnSmplFactorKa", 1., "downsampling factor for kaons, default fraction to keep is 1."}; /// Pion Configurable maxMomTPCOnlyPi{"maxMomTPCOnlyPi", 0.5, "Maximum momentum for TPC only cut pion"}; Configurable nSigmaTPCOnlyPi{"nSigmaTPCOnlyPi", 4., "number of sigma for TPC only cut pion"}; - Configurable nSigmaTPC_TPCTOF_Pi{"nSigmaTPC_TPCTOF_Pi", 4., "number of sigma for TPC cut for TPC and TOF combined pion"}; - Configurable nSigmaTOF_TPCTOF_Pi{"nSigmaTOF_TPCTOF_Pi", 4., "number of sigma for TOF cut for TPC and TOF combined pion"}; - Configurable dwnSmplFactor_Pi{"dwnSmplFactor_Pi", 1., "downsampling factor for pions, default fraction to keep is 1."}; + Configurable nSigmaTpcTpctofPi{"nSigmaTpcTpctofPi", 4., "number of sigma for TPC cut for TPC and TOF combined pion"}; + Configurable nSigmaTofTpctofPi{"nSigmaTofTpctofPi", 4., "number of sigma for TOF cut for TPC and TOF combined pion"}; + Configurable dwnSmplFactorPi{"dwnSmplFactorPi", 1., "downsampling factor for pions, default fraction to keep is 1."}; /// pT dependent downsampling - Configurable sqrtSNN{"sqrt_s_NN", 0., "sqrt(s_NN), used for downsampling with the Tsallis distribution"}; + Configurable sqrtSNN{"sqrtSNN", 5360., "sqrt(s_NN), used for downsampling with the Tsallis distribution"}; Configurable downsamplingTsalisTritons{"downsamplingTsalisTritons", -1., "Downsampling factor to reduce the number of tritons"}; Configurable downsamplingTsalisDeuterons{"downsamplingTsalisDeuterons", -1., "Downsampling factor to reduce the number of deuterons"}; Configurable downsamplingTsalisProtons{"downsamplingTsalisProtons", -1., "Downsampling factor to reduce the number of protons"}; Configurable downsamplingTsalisKaons{"downsamplingTsalisKaons", -1., "Downsampling factor to reduce the number of kaons"}; Configurable downsamplingTsalisPions{"downsamplingTsalisPions", -1., "Downsampling factor to reduce the number of pions"}; - Filter trackFilter = (trackSelection.node() == 0) || - ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || - ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || - ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || - ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || - ((trackSelection.node() == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); - - double tsalisCharged(double pt, double mass, double sqrts) - { - const double a = 6.81, b = 59.24; - const double c = 0.082, d = 0.151; - double mt = std::sqrt(mass * mass + pt * pt); - double n = a + b / sqrts; - double T = c + d / sqrts; - double p0 = n * T; - double result = pow((1. + mt / p0), -n); - return result; + Filter trackFilter = (trackSelection.node() == static_cast(TrackSelectionNoCut)) || + ((trackSelection.node() == static_cast(TrackSelectionGlobalTrack)) && requireGlobalTrackInFilter()) || + ((trackSelection.node() == static_cast(TrackSelectionTrackWoPtEta)) && requireGlobalTrackWoPtEtaInFilter()) || + ((trackSelection.node() == static_cast(TrackSelectionGlobalTrackWoDCA)) && requireGlobalTrackWoDCAInFilter()) || + ((trackSelection.node() == static_cast(TrackSelectionQualityTracks)) && requireQualityTracksInFilter()) || + ((trackSelection.node() == static_cast(TrackSelectionInAcceptanceTracks)) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); + + ctpRateFetcher mRateFetcher; + + struct TofTrack { + bool isApplyHardCutOnly; + double maxMomHardCutOnly; + double maxMomTPCOnly; + double tpcNSigma; + double nSigmaTPCOnly; + double downsamplingTsalis; + double mass; + double tofNSigma; + double itsNSigma; + double tpcExpSignal; + o2::track::PID::ID pid; + double dwnSmplFactor; + double nSigmaTofTpctof; + double nSigmaTpcTpctof; }; - /// 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, float factor1Pt, double sqrts, double mass) - { - if (factor1Pt < 0.) { - 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) { - return false; - } else { - return true; - } - }; /// 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) + template + void fillSkimmedTPCTOFTable(T const& track, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float nSigmaITS, const float dEdxExp, const o2::track::PID::ID id, const int runnumber, const double dwnSmplFactor, const double hadronicRate) { const double ncl = track.tpcNClsFound(); + const double nclPID = track.tpcNClsFindableMinusPID(); const double p = track.tpcInnerParam(); const double mass = o2::track::pid_constants::sMasses[id]; const double bg = p / mass; const int multTPC = collision.multTPC(); + const auto trackOcc = collision.trackOccupancyInTimeRange(); + const 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(), + float usedEdx; + if constexpr (DoCorrectDeDx) { + usedEdx = track.tpcSignalCorrected(); + } else { + usedEdx = track.tpcSignal(); + } + rowTPCTOFTree(usedEdx, 1. / dEdxExp, track.tpcInnerParam(), track.tgl(), @@ -333,81 +753,269 @@ struct TreeWriterTPCTOF { bg, multTPC / 11000., std::sqrt(nClNorm / ncl), + nclPID, id, nSigmaTPC, nSigmaTOF, - runnumber); + runnumber, + trackOcc, + ft0Occ, + hadronicRate, + nSigmaITS); } }; - /// Event selection - template - bool isEventSelected(const CollisionType& collision, const TrackType& /*tracks*/) + template + void fillSkimmedTPCTOFTableWithTrkQAGeneric(T const& track, TQA const& trackQA, const bool existTrkQA, C const& collision, const float nSigmaTPC, const float nSigmaTOF, const float nSigmaITS, const float dEdxExp, const o2::track::PID::ID id, const int runnumber, const double dwnSmplFactor, const double hadronicRate, const int bcGlobalIndex, const int bcTimeFrameId, const int bcBcInTimeFrame) { - if (applyEvSel == 1) { - if (!collision.sel7()) { - return false; + const double ncl = track.tpcNClsFound(); + const double nclPID = track.tpcNClsFindableMinusPID(); + const double p = track.tpcInnerParam(); + const double mass = o2::track::pid_constants::sMasses[id]; + const double bg = p / mass; + const int multTPC = collision.multTPC(); + const auto trackOcc = collision.trackOccupancyInTimeRange(); + const auto ft0Occ = collision.ft0cOccupancyInTimeRange(); + + const double pseudoRndm = track.pt() * 1000. - static_cast(track.pt() * 1000); + if (pseudoRndm < dwnSmplFactor) { + float usedEdx; + if constexpr (DoCorrectDeDx) { + usedEdx = track.tpcSignalCorrected(); + } else { + usedEdx = track.tpcSignal(); } - } else if (applyEvSel == 2) { - if (!collision.sel8()) { - return false; + if constexpr (IsWithdEdx) { + rowTPCTOFTreeWithdEdxTrkQA(usedEdx, + 1. / dEdxExp, + track.tpcInnerParam(), + track.tgl(), + track.signed1Pt(), + track.eta(), + track.phi(), + track.y(), + mass, + bg, + multTPC / 11000., + std::sqrt(nClNorm / ncl), + nclPID, + id, + nSigmaTPC, + nSigmaTOF, + runnumber, + trackOcc, + ft0Occ, + hadronicRate, + nSigmaITS, + existTrkQA ? trackQA.tpcdEdxNorm() : -999); + } else { + rowTPCTOFTreeWithTrkQA(usedEdx, + 1. / dEdxExp, + track.tpcInnerParam(), + track.tgl(), + track.signed1Pt(), + track.eta(), + track.phi(), + track.y(), + mass, + bg, + multTPC / 11000., + std::sqrt(nClNorm / ncl), + nclPID, + id, + nSigmaTPC, + nSigmaTOF, + runnumber, + trackOcc, + ft0Occ, + hadronicRate, + nSigmaITS, + 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, + existTrkQA ? trackQA.tpcdEdxNorm() : -999); } } - return true; - }; + } void init(o2::framework::InitContext&) { + const std::array doprocess{doprocessStandard, doprocessStandardWithCorrecteddEdx, doprocessWithdEdxTrQA, doprocessWithdEdxTrQAWithCorrecteddEdx, doprocessWithTrQA, doprocessWithTrQAWithCorrecteddEdx, doprocessDummy}; + if (std::accumulate(doprocess.begin(), doprocess.end(), 0) != 1) { + LOGP(fatal, "One and only one process function should be enabled"); + } + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + } + + /// Evaluate tpcSignal with or without correction + template + double tpcSignalGeneric(const TrkType& track) + { + if constexpr (IsCorrectedDeDx) { + return track.tpcSignalCorrected(); + } else { + return track.tpcSignal(); + } } - void process(Coll::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + template + void runStandard(Colls::iterator const& collision, soa::Filtered const& tracks) { /// Check event selection - if (!isEventSelected(collision, tracks)) { + if (!isEventSelected(collision, applyEvSel)) { return; } - - auto bc = collision.bc_as(); + const auto& bc = collision.bc_as(); const int runnumber = bc.runNumber(); + const float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, irSource) * 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); - } 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); - } - /// 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); - } 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); - } - /// 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); - } 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); + + TofTrack tofTriton(true, maxMomHardCutOnlyTr, maxMomTPCOnlyTr, trk.tpcNSigmaTr(), nSigmaTPCOnlyTr, downsamplingTsalisTritons, MassTriton, trk.tofNSigmaTr(), -999., trk.tpcExpSignalTr(tpcSignalGeneric(trk)), PidTriton, dwnSmplFactorTr, nSigmaTofTpctofTr, nSigmaTpcTpctofTr); + + TofTrack tofDeuteron(true, maxMomHardCutOnlyDe, maxMomTPCOnlyDe, trk.tpcNSigmaDe(), nSigmaTPCOnlyDe, downsamplingTsalisDeuterons, MassDeuteron, trk.tofNSigmaDe(), -999., trk.tpcExpSignalDe(tpcSignalGeneric(trk)), PidDeuteron, dwnSmplFactorDe, nSigmaTofTpctofDe, nSigmaTpcTpctofDe); + + TofTrack tofProton(false, -999., maxMomTPCOnlyPr, trk.tpcNSigmaPr(), nSigmaTPCOnlyPr, downsamplingTsalisProtons, MassProton, trk.tofNSigmaPr(), -999., trk.tpcExpSignalPr(tpcSignalGeneric(trk)), PidProton, dwnSmplFactorPr, nSigmaTofTpctofPr, nSigmaTpcTpctofPr); + + TofTrack tofKaon(true, maxMomHardCutOnlyKa, maxMomTPCOnlyKa, trk.tpcNSigmaKa(), nSigmaTPCOnlyKa, downsamplingTsalisKaons, MassKPlus, trk.tofNSigmaKa(), -999., trk.tpcExpSignalKa(tpcSignalGeneric(trk)), PidKaon, dwnSmplFactorKa, nSigmaTofTpctofKa, nSigmaTpcTpctofKa); + + TofTrack tofPion(false, -999., maxMomTPCOnlyPi, trk.tpcNSigmaPi(), nSigmaTPCOnlyPi, downsamplingTsalisPions, MassPiPlus, trk.tofNSigmaPi(), -999., trk.tpcExpSignalPi(tpcSignalGeneric(trk)), PidPion, dwnSmplFactorPi, nSigmaTofTpctofPi, nSigmaTpcTpctofPi); + + for (const auto& tofTrack : {&tofTriton, &tofDeuteron, &tofProton, &tofKaon, &tofPion}) { + if ((!tofTrack->isApplyHardCutOnly || trk.tpcInnerParam() < tofTrack->maxMomHardCutOnly) && + ((trk.tpcInnerParam() <= tofTrack->maxMomTPCOnly && std::fabs(tofTrack->tpcNSigma) < tofTrack->nSigmaTPCOnly) || + (trk.tpcInnerParam() > tofTrack->maxMomTPCOnly && std::fabs(tofTrack->tofNSigma) < tofTrack->nSigmaTofTpctof && std::fabs(tofTrack->tpcNSigma) < tofTrack->nSigmaTpcTpctof)) && + downsampleTsalisCharged(fRndm, trk.pt(), tofTrack->downsamplingTsalis, tofTrack->mass, sqrtSNN)) { + fillSkimmedTPCTOFTable(trk, collision, tofTrack->tpcNSigma, tofTrack->tofNSigma, tofTrack->itsNSigma, tofTrack->tpcExpSignal, tofTrack->pid, runnumber, tofTrack->dwnSmplFactor, 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); - } 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); + } /// Loop tracks + } + + void processStandard(Colls::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + { + runStandard(collision, tracks); + } /// process + PROCESS_SWITCH(TreeWriterTpcTof, processStandard, "Standard Samples for PID", true); + + void processStandardWithCorrecteddEdx(Colls::iterator const& collision, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + { + runStandard(collision, tracks); + } /// process + PROCESS_SWITCH(TreeWriterTpcTof, processStandardWithCorrecteddEdx, "Standard Samples for PID with corrected dEdx", false); + + Preslice perCollisionTracks = aod::track::collisionId; + Preslice perCollisionTracksWithCorrecteddEdx = aod::track::collisionId; + + template + void runWithTrQAGeneric(Colls const& collisions, TrksType const& myTracks, aod::TracksQAVersion const& tracksQA, Preslice const& perCollisionTracksType) + { + std::vector labelTrack2TrackQA(myTracks.size(), -1); + for (const auto& trackQA : tracksQA) { + const int64_t trackId = trackQA.trackId(); + labelTrack2TrackQA.at(trackId) = trackQA.globalIndex(); + } + for (const auto& collision : collisions) { + /// Check event selection + const auto& tracks = myTracks.sliceBy(perCollisionTracksType, collision.globalIndex()); + if (!isEventSelected(collision, applyEvSel)) { + continue; } - /// 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); - } 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); + const auto& tracksWithITSPid = soa::Attach(tracks); + + const auto& bc = collision.bc_as(); + const int runnumber = bc.runNumber(); + float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), runnumber, irSource) * 1.e-3; + int bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame; + if constexpr (IsWithdEdx) { + bcGlobalIndex = -999; + bcTimeFrameId = -999; + bcBcInTimeFrame = -999; + } else { + bcGlobalIndex = bc.globalIndex(); + bcTimeFrameId = bc.tfId(); + bcBcInTimeFrame = bc.bcInTF(); } - } /// Loop tracks - } /// process -}; /// struct TreeWriterTPCTOF + rowTPCTOFTreeWithTrkQA.reserve(tracks.size()); + for (auto const& trk : tracksWithITSPid) { + if (!isTrackSelected(trk, trackSelection)) { + continue; + } + // get the corresponding trackQA using labelTracks2TracKQA and get variables of interest + const auto label = labelTrack2TrackQA.at(trk.globalIndex()); + const bool existTrkQA = (label != -1); + const int64_t trkIndex = existTrkQA ? label : 0; + const aod::TracksQA& trackQA = tracksQA.iteratorAt(trkIndex); + + TofTrack tofTriton(true, maxMomHardCutOnlyTr, maxMomTPCOnlyTr, trk.tpcNSigmaTr(), nSigmaTPCOnlyTr, downsamplingTsalisTritons, MassTriton, trk.tofNSigmaTr(), trk.itsNSigmaTr(), trk.tpcExpSignalTr(tpcSignalGeneric(trk)), PidTriton, dwnSmplFactorTr, nSigmaTofTpctofTr, nSigmaTpcTpctofTr); + + TofTrack tofDeuteron(true, maxMomHardCutOnlyDe, maxMomTPCOnlyDe, trk.tpcNSigmaDe(), nSigmaTPCOnlyDe, downsamplingTsalisDeuterons, MassDeuteron, trk.tofNSigmaDe(), trk.itsNSigmaDe(), trk.tpcExpSignalDe(tpcSignalGeneric(trk)), PidDeuteron, dwnSmplFactorDe, nSigmaTofTpctofDe, nSigmaTpcTpctofDe); + + TofTrack tofProton(false, -999., maxMomTPCOnlyPr, trk.tpcNSigmaPr(), nSigmaTPCOnlyPr, downsamplingTsalisProtons, MassProton, trk.tofNSigmaPr(), trk.itsNSigmaPr(), trk.tpcExpSignalPr(tpcSignalGeneric(trk)), PidProton, dwnSmplFactorPr, nSigmaTofTpctofPr, nSigmaTpcTpctofPr); + + TofTrack tofKaon(true, maxMomHardCutOnlyKa, maxMomTPCOnlyKa, trk.tpcNSigmaKa(), nSigmaTPCOnlyKa, downsamplingTsalisKaons, MassKPlus, trk.tofNSigmaKa(), trk.itsNSigmaKa(), trk.tpcExpSignalKa(tpcSignalGeneric(trk)), PidKaon, dwnSmplFactorKa, nSigmaTofTpctofKa, nSigmaTpcTpctofKa); + + TofTrack tofPion(false, -999., maxMomTPCOnlyPi, trk.tpcNSigmaPi(), nSigmaTPCOnlyPi, downsamplingTsalisPions, MassPiPlus, trk.tofNSigmaPi(), trk.itsNSigmaPi(), trk.tpcExpSignalPi(tpcSignalGeneric(trk)), PidPion, dwnSmplFactorPi, nSigmaTofTpctofPi, nSigmaTpcTpctofPi); + + for (const auto& tofTrack : {&tofTriton, &tofDeuteron, &tofProton, &tofKaon, &tofPion}) { + if ((!tofTrack->isApplyHardCutOnly || trk.tpcInnerParam() < tofTrack->maxMomHardCutOnly) && + ((trk.tpcInnerParam() <= tofTrack->maxMomTPCOnly && std::fabs(tofTrack->tpcNSigma) < tofTrack->nSigmaTPCOnly) || + (trk.tpcInnerParam() > tofTrack->maxMomTPCOnly && std::fabs(tofTrack->tofNSigma) < tofTrack->nSigmaTofTpctof && std::fabs(tofTrack->tpcNSigma) < tofTrack->nSigmaTpcTpctof)) && + downsampleTsalisCharged(fRndm, trk.pt(), tofTrack->downsamplingTsalis, tofTrack->mass, sqrtSNN)) { + fillSkimmedTPCTOFTableWithTrkQAGeneric(trk, trackQA, existTrkQA, collision, tofTrack->tpcNSigma, tofTrack->tofNSigma, tofTrack->itsNSigma, tofTrack->tpcExpSignal, tofTrack->pid, runnumber, tofTrack->dwnSmplFactor, hadronicRate, bcGlobalIndex, bcTimeFrameId, bcBcInTimeFrame); + } + } + } /// Loop tracks + } + } + + void processWithdEdxTrQA(Colls const& collisions, Trks const& myTracks, aod::BCsWithTimestamps const&, aod::TracksQAVersion const& tracksQA) + { + runWithTrQAGeneric(collisions, myTracks, tracksQA, perCollisionTracks); + } /// process + PROCESS_SWITCH(TreeWriterTpcTof, processWithdEdxTrQA, "Samples for PID with TrackQA info", false); + + void processWithdEdxTrQAWithCorrecteddEdx(Colls const& collisions, TrksWithDEdxCorrection const& myTracks, aod::BCsWithTimestamps const&, aod::TracksQAVersion const& tracksQA) + { + runWithTrQAGeneric(collisions, myTracks, tracksQA, perCollisionTracksWithCorrecteddEdx); + } /// process + PROCESS_SWITCH(TreeWriterTpcTof, processWithdEdxTrQAWithCorrecteddEdx, "Samples for PID with TrackQA info with corrected dEdx", false); + + void processWithTrQA(Colls const& collisions, Trks const& myTracks, MyBCTable const&, aod::TracksQAVersion const& tracksQA) + { + runWithTrQAGeneric(collisions, myTracks, tracksQA, perCollisionTracks); + } /// process + PROCESS_SWITCH(TreeWriterTpcTof, processWithTrQA, "Samples for PID with TrackQA info", false); + + void processWithTrQAWithCorrecteddEdx(Colls const& collisions, TrksWithDEdxCorrection const& myTracks, MyBCTable const&, aod::TracksQAVersion const& tracksQA) + { + runWithTrQAGeneric(collisions, myTracks, tracksQA, perCollisionTracksWithCorrecteddEdx); + } /// process + PROCESS_SWITCH(TreeWriterTpcTof, processWithTrQAWithCorrecteddEdx, "Samples for PID with TrackQA info with correced dEdx", false); + + void processDummy(Colls const&) {} + PROCESS_SWITCH(TreeWriterTpcTof, processDummy, "Dummy function", false); +}; /// struct TreeWriterTpcTof WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc)}; + auto workflow = WorkflowSpec{adaptAnalysisTask(cfgc)}; workflow.push_back(adaptAnalysisTask(cfgc)); return workflow; } diff --git a/DPG/Tasks/TPC/tpcSkimsTableCreator.h b/DPG/Tasks/TPC/tpcSkimsTableCreator.h index c8cce4750de..f47a784dfb5 100644 --- a/DPG/Tasks/TPC/tpcSkimsTableCreator.h +++ b/DPG/Tasks/TPC/tpcSkimsTableCreator.h @@ -13,27 +13,33 @@ /// \author Annalena Kalteyer /// \author Christian Sonnabend /// \author Jeremy Wilkinson +/// \author Ana Marin +/// \author Oleksii Lubynets +/// \brief Creates clean samples of particles for PID fits #ifndef DPG_TASKS_TPC_TPCSKIMSTABLECREATOR_H_ #define DPG_TASKS_TPC_TPCSKIMSTABLECREATOR_H_ -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/PIDResponse.h" +#include +#include + namespace o2::aod { namespace tpcskims { -DECLARE_SOA_COLUMN(InvDeDxExpTPC, invdEdxExpTPC, float); +DECLARE_SOA_COLUMN(InvDeDxExpTPC, invDeDxExpTPC, float); DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_COLUMN(BetaGamma, bg, float); +DECLARE_SOA_COLUMN(BetaGamma, betaGamma, float); DECLARE_SOA_COLUMN(NormMultTPC, normMultTPC, float); 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(NormNClustersTPCPID, normNClustersTPCPID, float); +DECLARE_SOA_COLUMN(PidIndex, pidIndex, 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,47 +47,90 @@ 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 + +#define TPCSKIMS_COLUMNS_BASE \ + 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::NormNClustersTPCPID, \ + tpcskims::PidIndex, \ + tpcskims::NSigTPC, \ + tpcskims::NSigTOF, \ + tpcskims::RunNumber, \ + tpcskims::TrackOcc, \ + tpcskims::Ft0Occ, \ + tpcskims::HadronicRate + +#define TPCSKIMS_COLUMNS_V0 \ + TPCSKIMS_COLUMNS_BASE, \ + tpcskims::AlphaV0, \ + tpcskims::QtV0, \ + tpcskims::CosPAV0, \ + tpcskims::PtV0, \ + tpcskims::RadiusV0, \ + tpcskims::GammaPsiPair + +#define TPCSKIMS_COLUMNS_TOF \ + TPCSKIMS_COLUMNS_BASE, \ + tpcskims::NSigITS + +#define TPCSKIMS_COLUMNS_TRACK_QA \ + 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(SkimmedTPCV0Tree, "AOD", "TPCSKIMV0TREE", - 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_COLUMNS_V0); + +DECLARE_SOA_TABLE(SkimmedTPCV0TreeWithdEdxTrkQA, "AOD", "TPCSKIMV0WdE", + TPCSKIMS_COLUMNS_V0, + o2::aod::trackqa::TPCdEdxNorm); + +DECLARE_SOA_TABLE(SkimmedTPCV0TreeWithTrkQA, "AOD", "TPCSKIMV0WQA", + TPCSKIMS_COLUMNS_V0, + TPCSKIMS_COLUMNS_TRACK_QA, + o2::aod::trackqa::TPCdEdxNorm); DECLARE_SOA_TABLE(SkimmedTPCTOFTree, "AOD", "TPCTOFSKIMTREE", - 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::RunNumber); + TPCSKIMS_COLUMNS_TOF); + +DECLARE_SOA_TABLE(SkimmedTPCTOFTreeWithdEdxTrkQA, "AOD", "TPCTOFSKIMWdE", + TPCSKIMS_COLUMNS_TOF, + o2::aod::trackqa::TPCdEdxNorm); + +DECLARE_SOA_TABLE(SkimmedTPCTOFTreeWithTrkQA, "AOD", "TPCTOFSKIMWQA", + TPCSKIMS_COLUMNS_TOF, + TPCSKIMS_COLUMNS_TRACK_QA, + o2::aod::trackqa::TPCdEdxNorm); + +#undef TPCSKIMS_COLUMNS_TRACK_QA +#undef TPCSKIMS_COLUMNS_TOF +#undef TPCSKIMS_COLUMNS_V0 +#undef TPCSKIMS_COLUMNS_BASE } // namespace o2::aod #endif // DPG_TASKS_TPC_TPCSKIMSTABLECREATOR_H_ diff --git a/DPG/Tasks/TPC/tpcTreeCreatorLight.cxx b/DPG/Tasks/TPC/tpcTreeCreatorLight.cxx index 807c85ba414..a0871336051 100644 --- a/DPG/Tasks/TPC/tpcTreeCreatorLight.cxx +++ b/DPG/Tasks/TPC/tpcTreeCreatorLight.cxx @@ -17,7 +17,9 @@ /// \author Jeremy Wilkinson #include "tpcTreeCreatorLight.h" + #include + #include /// ROOT #include "TRandom3.h" @@ -27,10 +29,11 @@ #include "Framework/runDataProcessing.h" /// O2Physics #include "Common/Core/trackUtilities.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" using namespace o2; using namespace o2::framework; @@ -197,8 +200,8 @@ struct TreeWriterTPCTOF { } } /// Loop tracks - } /// process -}; /// struct TreeWriterTPCTOF + } /// process +}; /// struct TreeWriterTPCTOF WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/DPG/Tasks/TPC/utilsTpcSkimsTableCreator.h b/DPG/Tasks/TPC/utilsTpcSkimsTableCreator.h new file mode 100644 index 00000000000..99c304959f0 --- /dev/null +++ b/DPG/Tasks/TPC/utilsTpcSkimsTableCreator.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. + +/// \file utilsTpcSkimsTableCreator.h +/// \author Annalena Kalteyer +/// \author Christian Sonnabend +/// \author Jeremy Wilkinson +/// \author Ana Marin +/// \author Oleksii Lubynets +/// \brief Helper functions used both in V0 and TOF structs of tpcSkimsTableCreator.cxx + +#ifndef DPG_TASKS_TPC_UTILSTPCSKIMSTABLECREATOR_H_ +#define DPG_TASKS_TPC_UTILSTPCSKIMSTABLECREATOR_H_ + +#include + +namespace o2::dpg_tpcskimstablecreator +{ +enum { + TrackSelectionNoCut = 0, + TrackSelectionGlobalTrack, + TrackSelectionTrackWoPtEta, + TrackSelectionGlobalTrackWoDCA, + TrackSelectionQualityTracks, + TrackSelectionInAcceptanceTracks +}; + +enum { + EventSelectionNo = 0, + EventSelectionRun2, + EventSelectionRun3 +}; + +/// Event selection +template +inline bool isEventSelected(const CollisionType& collision, const int applyEvSel) +{ + if (applyEvSel == EventSelectionRun2) { + if (!collision.sel7()) { + return false; + } + } else if (applyEvSel == EventSelectionRun3) { + if (!collision.sel8()) { + return false; + } + } + return true; +}; + +/// 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 +inline bool downsampleTsalisCharged(TRandom3* fRndm, const double pt, const double factor1Pt, const double mass, const double sqrtSNN, const double maxPt = 1e9) +{ + if (factor1Pt < 0. || pt > maxPt) { + return true; + } + + auto tsalisCharged = [&](const double pT) { + const double a = 6.81, b = 59.24; + const double c = 0.082, d = 0.151; + const double mt = std::sqrt(mass * mass + pT * pT); + const double n = a + b / sqrtSNN; + const double t = c + d / sqrtSNN; + const double p0 = n * t; + const double result = std::pow((1. + mt / p0), -n); + return result; + }; + + const double prob = tsalisCharged(pt) * pt; + const double probNorm = tsalisCharged(1.); + if ((fRndm->Rndm() * ((prob / probNorm) * pt * pt)) > factor1Pt) { + return false; + } else { + return true; + } +}; + +// Track selection +template +inline bool isTrackSelected(const TrackType& track, const int trackSelection) +{ + bool isSelected{false}; + isSelected |= trackSelection == TrackSelectionNoCut; + isSelected |= (trackSelection == TrackSelectionGlobalTrack) && track.isGlobalTrack(); + isSelected |= (trackSelection == TrackSelectionTrackWoPtEta) && track.isGlobalTrackWoPtEta(); + isSelected |= (trackSelection == TrackSelectionGlobalTrackWoDCA) && track.isGlobalTrackWoDCA(); + isSelected |= (trackSelection == TrackSelectionQualityTracks) && track.isQualityTrack(); + isSelected |= (trackSelection == TrackSelectionInAcceptanceTracks) && track.isInAcceptanceTrack(); + + return isSelected; +} + +} // namespace o2::dpg_tpcskimstablecreator +#endif // DPG_TASKS_TPC_UTILSTPCSKIMSTABLECREATOR_H_ diff --git a/EventFiltering/CMakeLists.txt b/EventFiltering/CMakeLists.txt index 4f5ab9ed153..7ed2450830c 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 @@ -39,32 +39,22 @@ o2physics_add_header_only_library(HFFilterHelpers o2physics_add_dpl_workflow(hf-filter SOURCES PWGHF/HFFilter.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore ONNXRuntime::ONNXRuntime O2Physics::HFFilterHelpers O2::DetectorsBase + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::HFFilterHelpers O2::DetectorsBase COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hf-filter-charm-hadron-signals SOURCES PWGHF/HFFilterCharmHadronSignals.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore ONNXRuntime::ONNXRuntime O2Physics::HFFilterHelpers + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::HFFilterHelpers COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hf-filter-prepare-ml-samples SOURCES PWGHF/HFFilterPrepareMLSamples.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore ONNXRuntime::ONNXRuntime O2Physics::HFFilterHelpers O2::DetectorsBase + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::HFFilterHelpers O2::DetectorsBase COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(cf-filter SOURCES PWGCF/CFFilterAll.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(cf-filter-qa - SOURCES PWGCF/CFFilterQA.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(cf-filter-ppphi - SOURCES PWGCF/CFFilterPPPhi.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle O2::ReconstructionDataFormats O2::DetectorsBase COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(je-filter @@ -84,7 +74,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 @@ -102,16 +92,17 @@ 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 + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle O2::DetectorsBase COMPONENT_NAME Analysis) -o2physics_add_library(EventFilteringUtils - SOURCES Zorro.cxx - INSTALL_HEADERS ZorroHelper.h - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore Arrow::arrow_shared) - -o2physics_target_root_dictionary(EventFilteringUtils - HEADERS ZorroHelper.h - LINKDEF EventFilteringUtilsLinkDef.h) \ No newline at end of file + o2physics_add_dpl_workflow(lf-doublephi-filter + SOURCES PWGLF/filterdoublephi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) diff --git a/EventFiltering/PWGCF/CFFilter.cxx b/EventFiltering/PWGCF/CFFilter.cxx deleted file mode 100644 index 7219ba03d45..00000000000 --- a/EventFiltering/PWGCF/CFFilter.cxx +++ /dev/null @@ -1,595 +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 CFFilter.cxx -/// \brief Selection of events with triplets for femtoscopic studies -/// -/// \author Laura Serksnyte, TU München, laura.serksnyte@cern.ch - -#include - -#include "../filterTables.h" -#include "../../PWGCF/FemtoDream/FemtoUtils.h" - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" - -#include "PWGCF/DataModel/FemtoDerived.h" -#include "PWGCF/FemtoDream/FemtoDreamParticleHisto.h" -#include "PWGCF/FemtoDream/FemtoDreamMath.h" -#include "PWGCF/FemtoDream/FemtoDreamPairCleaner.h" -#include "PWGCF/FemtoDream/FemtoDreamDetaDphiStar.h" -#include "PWGCF/FemtoDream/FemtoDreamContainer.h" - -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" - -namespace -{ - -enum CFTriggers { - kPPP = 0, - kPPL, - kPLL, - kLLL, - kNTriggers -}; - -static const std::vector CfTriggerNames{"ppp", "ppL", "pLL", "LLL"}; -// uint8_t trackTypeSel = o2::aod::femtodreamparticle::ParticleType::kTrack; Fix this to work instead of below hardcoded lines -// uint V0TypeSel = o2::aod::femtodreamparticle::ParticleType::kV0; Fix this to work instead of below hardcoded lines -static constexpr uint8_t Track = 0; // Track -static constexpr uint8_t V0 = 1; // V0 -// static constexpr uint8_t V0Daughter = 2; // V0 daughters -static constexpr uint32_t kSignMinusMask = 1; -static constexpr uint32_t kSignPlusMask = 2; -// static constexpr uint32_t knSigmaProton = 48; -static constexpr uint32_t kValue0 = 0; - -} // namespace - -namespace o2::aod -{ -using FullCollision = soa::Join::iterator; -} // namespace o2::aod - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::analysis::femtoDream; - -struct CFFilter { - SliceCache cache; - - Produces tags; - - Configurable> confQ3TriggerLimit{"Q3TriggerLimitC", std::vector{0.6f, 0.6f, 0.6f, 0.6f}, "Q3 limit for selection"}; - Configurable Q3Trigger{"Q3Trigger", 0, "Choice which trigger to run"}; - Configurable performCPR{"performCPR", true, "Perform or not the close pair rejection"}; - Configurable ldeltaPhiMax{"ldeltaPhiMax", 0.010, "Max limit of delta phi"}; - Configurable ldeltaEtaMax{"ldeltaEtaMax", 0.010, "Max limit of delta eta"}; - Configurable> ConfPIDnSigmaMax{"PIDnSigmaMax", - std::vector{4.f, 3.f}, - "Vector of all possible nSigma values for Acceptance and Rejection (this needs to be in sync with FemtoDreamProducerTask.ConfTrkPIDnSigmaMax)"}; - Configurable ConfPIDProtonIndex{"PIDProtonIndex", 2, "Index of Proton PID in ConfTrkTPIDspecies of the FemtoDreamProducerTask"}; - Configurable ConfPIDIndexMax{"PIDIndexMax", 4, "Number of Indices in ConfTrkTPIDspecies of the FemtoDreamProducerTask"}; - Configurable ConfPIDThreshold{"PThreshold", 0.75f, "P threshold for TPC/TPC&TOF selection"}; - Configurable ConfPIDnSigma{"PIDnSigma", 4.f, "nSigma value for Proton PID"}; - - // Obtain particle and antiparticle candidates of protons and lambda hyperons for current femto collision - Partition partsProton0Part = (o2::aod::femtodreamparticle::partType == Track) && ((o2::aod::femtodreamparticle::cut & kSignPlusMask) > kValue0); // Consider later: && ((o2::aod::femtodreamparticle::pidcut & knSigmaProton) > kValue0); - Partition partsLambda0Part = (o2::aod::femtodreamparticle::partType == V0) && ((o2::aod::femtodreamparticle::cut & kSignPlusMask) > kValue0); - Partition partsProton1Part = (o2::aod::femtodreamparticle::partType == Track) && ((o2::aod::femtodreamparticle::cut & kSignMinusMask) > kValue0); // Consider later: && ((o2::aod::femtodreamparticle::pidcut & knSigmaProton) > kValue0); - Partition partsLambda1Part = (o2::aod::femtodreamparticle::partType == V0) && ((o2::aod::femtodreamparticle::cut & kSignMinusMask) > kValue0); - - Preslice perCol = aod::femtodreamparticle::femtoDreamCollisionId; - - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registryQA{"registryQA", {}, OutputObjHandlingPolicy::AnalysisObject}; - - // FemtoDreamPairCleaner pairCleanerTT; Currently not used, will be needed later - FemtoDreamPairCleaner pairCleanerTV; - FemtoDreamDetaDphiStar closePairRejectionTT; - FemtoDreamDetaDphiStar closePairRejectionTV0; - - void init(o2::framework::InitContext&) - { - bool plotPerRadii = true; - - closePairRejectionTT.init(®istry, ®istryQA, ldeltaPhiMax, ldeltaEtaMax, plotPerRadii); - closePairRejectionTV0.init(®istry, ®istryQA, ldeltaPhiMax, ldeltaEtaMax, plotPerRadii); - registry.add("fProcessedEvents", "CF - event filtered;;events", HistType::kTH1F, {{6, -0.5, 5.5}}); - // dont use hardcoded 6 - std::array eventTitles = {"all", "rejected", "p-p-p", "p-p-L", "p-L-L", "L-L-L"}; - for (size_t iBin = 0; iBin < eventTitles.size(); iBin++) { - registry.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(iBin + 1, eventTitles[iBin].data()); - } - registry.add("fMultiplicityBefore", "Multiplicity of all processed events", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("fMultiplicityAfter", "Multiplicity of events which passed ppp trigger", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("fZvtxBefore", "Zvtx of all processed events", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("fZvtxAfter", "Zvtx of events which passed ppp trigger", HistType::kTH1F, {{1000, -15, 15}}); - - registry.add("fPtBeforePPP", "Transverse momentum of all processed tracks", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("fPtAfterPPP", "Transverse momentum of processed tracks which passed selections", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("fPtBeforeAntiPPP", "Transverse momentum of all processed antitracks", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("fPtAfterAntiPPP", "Transverse momentum of processed antitracks passed selection", HistType::kTH1F, {{1000, 0, 10}}); - - if (Q3Trigger == 0 || Q3Trigger == 11 || Q3Trigger == 1111) { - registry.add("fSameEventPartPPP", "CF - same event ppp distribution for particles;;events", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("fSameEventAntiPartPPP", "CF - same event ppp distribution for antiparticles;;events", HistType::kTH1F, {{8000, 0, 8}}); - } - if (Q3Trigger == 1 || Q3Trigger == 11 || Q3Trigger == 1111) { - registry.add("fSameEventPartPPL", "CF - same event ppL distribution for particles;;events", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("fSameEventAntiPartPPL", "CF - same event ppL distribution for antiparticles;;events", HistType::kTH1F, {{8000, 0, 8}}); - - registry.add("fPtPPL", "Transverse momentum of all processed tracks", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("fPtAntiPPL", "Transverse momentum of all processed antitracks", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("fMinvLambda", "Invariant mass of lambdas ", HistType::kTH1F, {{1000, 0.7, 1.5}}); - registry.add("fMinvAntiLambda", "Invariant mass of antilambdas ", HistType::kTH1F, {{1000, 0.7, 1.5}}); - registry.add("fMinvLambdaBefore", "Invariant mass of lambdas before ", HistType::kTH1F, {{1000, 0.7, 1.5}}); - registry.add("fMinvAntiLambdaBefore", "Invariant mass of antilambdas before", HistType::kTH1F, {{1000, 0.7, 1.5}}); - } - if (Q3Trigger == 2 || Q3Trigger == 1111) { - registry.add("fSameEventPartPLL", "CF - same event pLL distribution for particles;;events", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("fSameEventAntiPartPLL", "CF - same event pLL distribution for antiparticles;;events", HistType::kTH1F, {{8000, 0, 8}}); - } - if (Q3Trigger == 3 || Q3Trigger == 1111) { - registry.add("fSameEventPartLLL", "CF - same event LLL distribution for particles;;events", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("fSameEventAntiPartLLL", "CF - same event LLL distribution for antiparticles;;events", HistType::kTH1F, {{8000, 0, 8}}); - } - } - - float mMassProton = TDatabasePDG::Instance()->GetParticle(2212)->Mass(); - float mMassLambda = TDatabasePDG::Instance()->GetParticle(3122)->Mass(); - - void process(o2::aod::FemtoDreamCollision& col, o2::aod::FemtoDreamParticles& partsFemto) - { - auto partsProton0 = partsProton0Part->sliceByCached(aod::femtodreamparticle::femtoDreamCollisionId, col.globalIndex(), cache); - auto partsLambda0 = partsLambda0Part->sliceByCached(aod::femtodreamparticle::femtoDreamCollisionId, col.globalIndex(), cache); - auto partsProton1 = partsProton1Part->sliceByCached(aod::femtodreamparticle::femtoDreamCollisionId, col.globalIndex(), cache); - auto partsLambda1 = partsLambda1Part->sliceByCached(aod::femtodreamparticle::femtoDreamCollisionId, col.globalIndex(), cache); - - auto magneticField = col.magField(); - - registry.get(HIST("fProcessedEvents"))->Fill(0); - registry.get(HIST("fMultiplicityBefore"))->Fill(col.multV0M()); - registry.get(HIST("fZvtxBefore"))->Fill(col.posZ()); - - int prot = 0; - int antiprot = 0; - for (auto p1pt : partsProton0) { - registry.get(HIST("fPtBeforePPP"))->Fill(p1pt.pt()); - if (isFullPIDSelected(p1pt.pidcut(), - p1pt.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value)) { - registry.get(HIST("fPtAfterPPP"))->Fill(p1pt.pt()); - prot++; - } - } - for (auto p1pt : partsProton1) { - registry.get(HIST("fPtBeforeAntiPPP"))->Fill(p1pt.pt()); - if (isFullPIDSelected(p1pt.pidcut(), - p1pt.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value)) { - registry.get(HIST("fPtAfterAntiPPP"))->Fill(p1pt.pt()); - antiprot++; - } - } - - for (auto lambda : partsLambda0) { - registry.get(HIST("fMinvLambdaBefore"))->Fill(lambda.mLambda()); - } - for (auto antilambda : partsLambda1) { - registry.get(HIST("fMinvAntiLambdaBefore"))->Fill(antilambda.mAntiLambda()); - } - - bool keepEvent[kNTriggers] = {false, false, false, false}; - int lowQ3Triplets[kNTriggers] = {0, 0, 0, 0}; - - if (partsFemto.size() != 0) { - registry.get(HIST("fMultiplicityAfter"))->Fill(col.multV0M()); - registry.get(HIST("fZvtxAfter"))->Fill(col.posZ()); - auto Q3TriggerLimit = (std::vector)confQ3TriggerLimit; - // __________________________________________________________________________________________________________ - // TRIGGER FOR PPP TRIPLETS - if (Q3Trigger == 0 || Q3Trigger == 1111 || Q3Trigger == 11) { - if (prot >= 3) { - // test default combinations options - for (auto& [p1, p2, p3] : combinations(partsProton0, partsProton0, partsProton0)) { - if (!isFullPIDSelected(p1.pidcut(), - p1.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value) || - !isFullPIDSelected(p2.pidcut(), - p2.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value) || - !isFullPIDSelected(p3.pidcut(), - p3.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value)) { - continue; - } - // Think if pair cleaning is needed in current framework - // Run close pair rejection - if (performCPR) { - if (closePairRejectionTT.isClosePair(p1, p2, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTT.isClosePair(p1, p3, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTT.isClosePair(p2, p3, partsFemto, magneticField)) { - continue; - } - } - auto Q3 = FemtoDreamMath::getQ3(p1, mMassProton, p2, mMassProton, p3, mMassProton); - registry.get(HIST("fSameEventPartPPP"))->Fill(Q3); - if (Q3 < Q3TriggerLimit.at(0)) { - lowQ3Triplets[0]++; - } - } - } // end if - - if (lowQ3Triplets[0] == 0) { // Use this in final version only, for testing comment { // if at least one triplet found in particles, no need to check antiparticles - if (antiprot >= 3) { - for (auto& [p1, p2, p3] : combinations(partsProton1, partsProton1, partsProton1)) { - - if (!isFullPIDSelected(p1.pidcut(), - p1.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value) || - !isFullPIDSelected(p2.pidcut(), - p2.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value) || - !isFullPIDSelected(p3.pidcut(), - p3.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value)) { - continue; - } - // Think if pair cleaning is needed in current framework - // Run close pair rejection - if (performCPR) { - if (closePairRejectionTT.isClosePair(p1, p2, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTT.isClosePair(p1, p3, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTT.isClosePair(p2, p3, partsFemto, magneticField)) { - continue; - } - } - auto Q3 = FemtoDreamMath::getQ3(p1, mMassProton, p2, mMassProton, p3, mMassProton); - registry.get(HIST("fSameEventAntiPartPPP"))->Fill(Q3); - if (Q3 < Q3TriggerLimit.at(0)) { - lowQ3Triplets[0]++; - } - } - } - } // end if - //} - } - // __________________________________________________________________________________________________________ - // TRIGGER FOR PPL TRIPLETS - if (Q3Trigger == 1 || Q3Trigger == 1111 || Q3Trigger == 11) { - if (partsLambda0.size() >= 1 && prot >= 2) { - for (auto& partLambda : partsLambda0) { - registry.get(HIST("fPtPPL"))->Fill(partLambda.pt()); - registry.get(HIST("fMinvLambda"))->Fill(partLambda.mLambda()); - if (!pairCleanerTV.isCleanPair(partLambda, partLambda, partsFemto)) { - continue; - } - for (auto& [p1, p2] : combinations(partsProton0, partsProton0)) { - if (!isFullPIDSelected(p1.pidcut(), - p1.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value) || - !isFullPIDSelected(p2.pidcut(), - p2.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value)) { - continue; - } - if (performCPR) { - if (closePairRejectionTT.isClosePair(p1, p2, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTV0.isClosePair(p1, partLambda, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTV0.isClosePair(p2, partLambda, partsFemto, magneticField)) { - continue; - } - } - auto Q3 = FemtoDreamMath::getQ3(p1, mMassProton, p2, mMassProton, partLambda, mMassLambda); - registry.get(HIST("fSameEventPartPPL"))->Fill(Q3); - if (Q3 < Q3TriggerLimit.at(1)) { - lowQ3Triplets[1]++; - } - } - } - } // end if - - if (lowQ3Triplets[1] == 0) { // if at least one triplet found in particles, no need to check antiparticles - if (partsLambda1.size() >= 1 && antiprot >= 2) { - for (auto& partLambda : partsLambda1) { - registry.get(HIST("fPtAntiPPL"))->Fill(partLambda.pt()); - registry.get(HIST("fMinvAntiLambda"))->Fill(partLambda.mAntiLambda()); - if (!pairCleanerTV.isCleanPair(partLambda, partLambda, partsFemto)) { - continue; - } - for (auto& [p1, p2] : combinations(partsProton1, partsProton1)) { - if (!isFullPIDSelected(p1.pidcut(), - p1.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value) || - !isFullPIDSelected(p2.pidcut(), - p2.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value)) { - continue; - } - if (performCPR) { - if (closePairRejectionTT.isClosePair(p1, p2, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTV0.isClosePair(p1, partLambda, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTV0.isClosePair(p2, partLambda, partsFemto, magneticField)) { - continue; - } - } - auto Q3 = FemtoDreamMath::getQ3(p1, mMassProton, p2, mMassProton, partLambda, mMassLambda); - registry.get(HIST("fSameEventAntiPartPPL"))->Fill(Q3); - if (Q3 < Q3TriggerLimit.at(1)) { - lowQ3Triplets[1]++; - } - } - } - } // end if - } - } - - // __________________________________________________________________________________________________________ - // TRIGGER FOR PLL TRIPLETS - if (Q3Trigger == 2 || Q3Trigger == 1111) { - if (partsLambda0.size() >= 2 && prot >= 1) { - for (auto& p1 : partsProton0) { - if (!isFullPIDSelected(p1.pidcut(), - p1.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value)) { - continue; - } - for (auto& [partLambda1, partLambda2] : combinations(partsLambda0, partsLambda0)) { - // maybe implement L1-L2 no shared tracks - if (!pairCleanerTV.isCleanPair(partLambda1, partLambda1, partsFemto)) { - continue; - } - if (!pairCleanerTV.isCleanPair(partLambda2, partLambda2, partsFemto)) { - continue; - } - - if (performCPR) { - if (closePairRejectionTV0.isClosePair(p1, partLambda1, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTV0.isClosePair(p1, partLambda2, partsFemto, magneticField)) { - continue; - } - // maybe implement L-L cpr - } - auto Q3 = FemtoDreamMath::getQ3(p1, mMassProton, partLambda1, mMassLambda, partLambda2, mMassLambda); - registry.get(HIST("fSameEventPartPLL"))->Fill(Q3); - if (Q3 < Q3TriggerLimit.at(2)) { - lowQ3Triplets[2]++; - } - } - } - } // end if - - if (lowQ3Triplets[2] == 0) { // if at least one triplet found in particles, no need to check antiparticles - if (partsLambda1.size() >= 2 && antiprot >= 1) { - for (auto& p1 : partsProton1) { - if (!isFullPIDSelected(p1.pidcut(), - p1.p(), - ConfPIDThreshold.value, - std::vector{ConfPIDProtonIndex.value}, - ConfPIDIndexMax.value, - ConfPIDnSigmaMax.value, - ConfPIDnSigma.value, - ConfPIDnSigma.value)) { - continue; - } - for (auto& [partLambda1, partLambda2] : combinations(partsLambda1, partsLambda1)) { - // maybe implement L1-L2 no shared tracks - if (!pairCleanerTV.isCleanPair(partLambda1, partLambda1, partsFemto)) { - continue; - } - if (!pairCleanerTV.isCleanPair(partLambda2, partLambda2, partsFemto)) { - continue; - } - - if (performCPR) { - if (closePairRejectionTV0.isClosePair(p1, partLambda1, partsFemto, magneticField)) { - continue; - } - if (closePairRejectionTV0.isClosePair(p1, partLambda2, partsFemto, magneticField)) { - continue; - } - // maybe implement L-L cpr - } - auto Q3 = FemtoDreamMath::getQ3(p1, mMassProton, partLambda1, mMassLambda, partLambda2, mMassLambda); - registry.get(HIST("fSameEventAntiPartPLL"))->Fill(Q3); - if (Q3 < Q3TriggerLimit.at(2)) { - lowQ3Triplets[2]++; - } - } - } - } // end if - } - } - - // __________________________________________________________________________________________________________ - // TRIGGER FOR LLL TRIPLETS - if (Q3Trigger == 3 || Q3Trigger == 1111) { - if (partsLambda0.size() >= 3) { - // test default combinations options - for (auto& [partLambda1, partLambda2, partLambda3] : combinations(partsLambda0, partsLambda0, partsLambda0)) { - if (!pairCleanerTV.isCleanPair(partLambda1, partLambda1, partsFemto)) { - continue; - } - if (!pairCleanerTV.isCleanPair(partLambda2, partLambda2, partsFemto)) { - continue; - } - if (!pairCleanerTV.isCleanPair(partLambda3, partLambda3, partsFemto)) { - continue; - } - // Run close pair rejection - if (performCPR) { - // check close pair rejection for L-L - } - auto Q3 = FemtoDreamMath::getQ3(partLambda1, mMassLambda, partLambda2, mMassLambda, partLambda3, mMassLambda); - registry.get(HIST("fSameEventPartLLL"))->Fill(Q3); - if (Q3 < Q3TriggerLimit.at(3)) { - lowQ3Triplets[3]++; - } - } - } // end if - - if (lowQ3Triplets[3] == 0) { // Use this in final version only, for testing comment { // if at least one triplet found in particles, no need to check antiparticles - - if (partsLambda1.size() >= 3) { - // test default combinations options - for (auto& [partLambda1, partLambda2, partLambda3] : combinations(partsLambda1, partsLambda1, partsLambda1)) { - if (!pairCleanerTV.isCleanPair(partLambda1, partLambda1, partsFemto)) { - continue; - } - if (!pairCleanerTV.isCleanPair(partLambda2, partLambda2, partsFemto)) { - continue; - } - if (!pairCleanerTV.isCleanPair(partLambda3, partLambda3, partsFemto)) { - continue; - } - // Run close pair rejection - if (performCPR) { - // check close pair rejection for L-L - } - auto Q3 = FemtoDreamMath::getQ3(partLambda1, mMassLambda, partLambda2, mMassLambda, partLambda3, mMassLambda); - registry.get(HIST("fSameEventAntiPartLLL"))->Fill(Q3); - if (Q3 < Q3TriggerLimit.at(3)) { - lowQ3Triplets[3]++; - } - } - } - - } // end if - //} - } - } - - if (lowQ3Triplets[0] > 0) { - keepEvent[kPPP] = true; - } - - if (lowQ3Triplets[1] > 0) { - keepEvent[kPPL] = true; - } - - if (lowQ3Triplets[2] > 0) { - keepEvent[kPLL] = true; - } - - if (lowQ3Triplets[3] > 0) { - keepEvent[kLLL] = true; - } - - tags(keepEvent[kPPP], keepEvent[kPPL], keepEvent[kPLL], keepEvent[kLLL]); - - if (!keepEvent[kPPP] && !keepEvent[kPPL] && !keepEvent[kPLL] && !keepEvent[kLLL]) { - registry.get(HIST("fProcessedEvents"))->Fill(1); - } else { - for (int iTrigger{0}; iTrigger < kNTriggers; iTrigger++) { - if (keepEvent[iTrigger]) { - registry.get(HIST("fProcessedEvents"))->Fill(iTrigger + 2); - } - } - } // end else - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfg) -{ - return WorkflowSpec{adaptAnalysisTask(cfg)}; -} diff --git a/EventFiltering/PWGCF/CFFilterAll.cxx b/EventFiltering/PWGCF/CFFilterAll.cxx index ca7b90fc0ca..84807d4d257 100644 --- a/EventFiltering/PWGCF/CFFilterAll.cxx +++ b/EventFiltering/PWGCF/CFFilterAll.cxx @@ -12,1169 +12,1197 @@ /// \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 -#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 "../filterTables.h" -#include "Framework/ASoAHelpers.h" +#include "PWGLF/Utils/strangenessBuilderHelper.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/Propagator.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 "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" +#include "TMath.h" + +#include "fairlogger/Logger.h" + +#include +#include 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 CFTriggers { + kPPP, + kPPL, + kPLL, + kLLL, + kPPPhi, + kPPRho, + kPD, + kLD, + kPhiD, + kRhoD, + kNTriggers }; -enum ParticleSpecies { - kProton, - kDeuteron, - kLambda, - kNParticleSpecies -}; -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.4f, 1.4f, 1.4f, 1.4f, 1.4f, 1.4f, 1.0f, 1.0f, 1.0f, 1.0f}}; - Configurable ConfRngSeed{"ConfRngSeed", 69, "Seed for downsampling"}; - TRandom3* rng; +using FullCollisions = soa::Join; +using FullCollision = FullCollisions::iterator; + +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", 10.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)"}; - - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - // HistogramRegistry registryQA{"registryQA", {}, OutputObjHandlingPolicy::AnalysisObject}; - - std::vector BBProton, BBAntiproton, BBDeuteron, BBAntideuteron, BBPion, BBAntipion, BBElectron, BBAntielectron, TPCTOFAvg; + 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", {600, 0.7, 1.3}, "Binning Invariant Mass Phi"}; + + ConfigurableAxis invMassRho{"invMassRho", {600, 0.47, 1.07}, "Binning Invariant Mass Rho"}; + + ConfigurableAxis q3{"q3", {300, 0, 3}, "Binning Decay Q3"}; + ConfigurableAxis kstar{"kstar", {300, 0, 3}, "Binning Decay Kstar"}; + + } Binning; + + // define histogram registry + // because we have so many histograms, we need to have 2 registries + HistogramRegistry registryParticleQA{"ParticleQA", {}, OutputObjHandlingPolicy::AnalysisObject}; // for particle histograms + HistogramRegistry registryTriggerQA{"TriggerQA", {}, OutputObjHandlingPolicy::AnalysisObject}; // for trigger histograms + + // 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"}; + + registryTriggerQA.add("fProcessedEvents", "CF - event filtered;;Events", HistType::kTH1F, {{prossedEventsBins, -0.5, prossedEventsBins - 0.5}}); + registryTriggerQA.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(1, "all"); + registryTriggerQA.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(2, "accepted_loose"); + registryTriggerQA.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(3, "accepted_tight"); + + registryTriggerQA.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++) { + registryTriggerQA.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(iBin + 4, triggerTitles[iBin].data()); // start triggers from 4th bin + registryTriggerQA.get(HIST("fTriggerCorrelations"))->GetXaxis()->SetBinLabel(iBin + 1, triggerTitles[iBin].data()); + registryTriggerQA.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()}}); + registryParticleQA.add("EventQA/Before/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryParticleQA.add("EventQA/Before/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + + registryParticleQA.add("EventQA/After/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryParticleQA.add("EventQA/After/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + + // all tracks before cuts + registryParticleQA.add("TrackQA/Before/Particle/fPt", "Transverse;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/Before/Particle/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/Before/Particle/fPhi", "Azimuthal;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("TrackQA/Before/Particle/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/Before/Particle/fItsSignal", "ITSSignal;p_{TPC} (GeV/c);ITS Signal", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/Before/Particle/fTpcSignal", "TPCSignal;p_{TPC} (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/Before/Particle/fTofSignal", "TOFSignal;p_{TPC} (GeV/c);TOF Signal", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/Before/AntiParticle/fPt", "Transverse momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/Before/AntiParticle/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/Before/AntiParticle/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("TrackQA/Before/AntiParticle/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/Before/AntiParticle/fItsSignal", "ITSSignal;p_{TPC} (GeV/c);ITS Signal", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/Before/AntiParticle/fTpcSignal", "TPCSignal;p_{TPC} (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.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}}}); + registryParticleQA.add("TrackQA/Before/Pion/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Pion/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Pion/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Pion/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/Before/AntiPion/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiPion/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiPion/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiPion/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/Before/Kaon/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Kaon/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Kaon/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Kaon/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/Before/AntiKaon/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiKaon/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiKaon/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiKaon/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/Before/Proton/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Proton/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Proton/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Proton/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/Before/AntiProton/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiProton/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiProton/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiProton/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/Before/Deuteron/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Deuteron/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Deuteron/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/Deuteron/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/Before/AntiDeuteron/fNsigmaITS", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiDeuteron/fNsigmaTPC", "NSigmaTPC;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiDeuteron/fNsigmaTOF", "NSigmaTOF;p_{TPC} (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/Before/AntiDeuteron/fNsigmaTPCTOF", "NsigmaTPCTOF;p_{TPC} (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + // Pion + registryParticleQA.add("TrackQA/After/Pion/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/Pion/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/Pion/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/After/Pion/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/After/Pion/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registryParticleQA.add("TrackQA/After/Pion/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Pion/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Pion/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Pion/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/After/Pion/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/After/Pion/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/After/Pion/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/After/Pion/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("TrackQA/After/Pion/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registryParticleQA.add("TrackQA/After/Pion/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Pion/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Pion/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Pion/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/Pion/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/Pion/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registryParticleQA.add("TrackQA/After/Pion/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registryParticleQA.add("TrackQA/After/Pion/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registryParticleQA.add("TrackQA/After/Pion/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // antiPion + registryParticleQA.add("TrackQA/After/AntiPion/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/AntiPion/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/AntiPion/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/After/AntiPion/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/After/AntiPion/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registryParticleQA.add("TrackQA/After/AntiPion/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiPion/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiPion/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiPion/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/After/AntiPion/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/After/AntiPion/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/After/AntiPion/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/After/AntiPion/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("TrackQA/After/AntiPion/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registryParticleQA.add("TrackQA/After/AntiPion/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiPion/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiPion/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiPion/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/AntiPion/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/AntiPion/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registryParticleQA.add("TrackQA/After/AntiPion/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registryParticleQA.add("TrackQA/After/AntiPion/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registryParticleQA.add("TrackQA/After/AntiPion/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // Kaon + registryParticleQA.add("TrackQA/After/Kaon/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/Kaon/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/Kaon/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/After/Kaon/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/After/Kaon/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registryParticleQA.add("TrackQA/After/Kaon/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Kaon/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Kaon/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Kaon/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/After/Kaon/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/After/Kaon/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/After/Kaon/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/After/Kaon/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("TrackQA/After/Kaon/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registryParticleQA.add("TrackQA/After/Kaon/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Kaon/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Kaon/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Kaon/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/Kaon/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/Kaon/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registryParticleQA.add("TrackQA/After/Kaon/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registryParticleQA.add("TrackQA/After/Kaon/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registryParticleQA.add("TrackQA/After/Kaon/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // antiKaon + registryParticleQA.add("TrackQA/After/AntiKaon/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/AntiKaon/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/AntiKaon/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/After/AntiKaon/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/After/AntiKaon/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registryParticleQA.add("TrackQA/After/AntiKaon/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiKaon/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiKaon/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiKaon/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/After/AntiKaon/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/After/AntiKaon/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/After/AntiKaon/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/After/AntiKaon/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("TrackQA/After/AntiKaon/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registryParticleQA.add("TrackQA/After/AntiKaon/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiKaon/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiKaon/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiKaon/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/AntiKaon/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/AntiKaon/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registryParticleQA.add("TrackQA/After/AntiKaon/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registryParticleQA.add("TrackQA/After/AntiKaon/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registryParticleQA.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}}); + registryParticleQA.add("TrackQA/After/Proton/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/Proton/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/Proton/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/After/Proton/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/After/Proton/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registryParticleQA.add("TrackQA/After/Proton/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Proton/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Proton/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Proton/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/After/Proton/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/After/Proton/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/After/Proton/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/After/Proton/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("TrackQA/After/Proton/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registryParticleQA.add("TrackQA/After/Proton/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Proton/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Proton/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Proton/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/Proton/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/Proton/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registryParticleQA.add("TrackQA/After/Proton/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registryParticleQA.add("TrackQA/After/Proton/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registryParticleQA.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}}}); + registryParticleQA.add("TrackQA/After/AntiProton/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/AntiProton/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/AntiProton/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/After/AntiProton/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/After/AntiProton/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registryParticleQA.add("TrackQA/After/AntiProton/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiProton/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiProton/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiProton/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/After/AntiProton/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/After/AntiProton/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/After/AntiProton/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/After/AntiProton/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("TrackQA/After/AntiProton/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registryParticleQA.add("TrackQA/After/AntiProton/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiProton/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiProton/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiProton/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/AntiProton/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/AntiProton/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registryParticleQA.add("TrackQA/After/AntiProton/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registryParticleQA.add("TrackQA/After/AntiProton/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registryParticleQA.add("TrackQA/After/AntiProton/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // Deuteron + registryParticleQA.add("TrackQA/After/Deuteron/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/Deuteron/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/Deuteron/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/After/Deuteron/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/After/Deuteron/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registryParticleQA.add("TrackQA/After/Deuteron/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Deuteron/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Deuteron/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/Deuteron/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/After/Deuteron/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/After/Deuteron/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/After/Deuteron/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/After/Deuteron/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("TrackQA/After/Deuteron/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registryParticleQA.add("TrackQA/After/Deuteron/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Deuteron/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Deuteron/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/Deuteron/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/Deuteron/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/Deuteron/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registryParticleQA.add("TrackQA/After/Deuteron/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registryParticleQA.add("TrackQA/After/Deuteron/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registryParticleQA.add("TrackQA/After/Deuteron/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // AntiDeuteron + registryParticleQA.add("TrackQA/After/AntiDeuteron/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fPTpc", "Momentum at TPC inner wall;p_{TPC} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fMomCor", "Momentum correlation;p_{reco} (GeV/c); p_{TPC} - p_{reco} / p_{reco}", {HistType::kTH2F, {Binning.momentum, Binning.momCor}}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fPhi", "Azimuthal angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + registryParticleQA.add("TrackQA/After/AntiDeuteron/fNsigmaIts", "NSigmaITS;p (GeV/c);n#sigma_{ITS}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fNsigmaTpc", "NSigmaTPC;p (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fNsigmaTof", "NSigmaTOF;p (GeV/c);n#sigma_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fNsigmaTpcTof", "NSigmaTPCTOF;p (GeV/c);n#sigma_{comb}", {HistType::kTH2F, {Binning.momentum, Binning.nsigmaComb}}); + + registryParticleQA.add("TrackQA/After/AntiDeuteron/fItsSignal", "ITS Signal;p (GeV/c); (cm)", {HistType::kTH2F, {Binning.momentum, Binning.itsSignal}}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fTpcSignal", "TPC Signal;p (GeV/c);TPC Signal", {HistType::kTH2F, {Binning.momentum, Binning.tpcSignal}}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fTofBeta", "TOF #beta;p (GeV/c);#beta_{TOF}", {HistType::kTH2F, {Binning.momentum, Binning.tofSignal}}); + + registryParticleQA.add("TrackQA/After/AntiDeuteron/fDcaXy", "DCA_{xy};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fDcaZ", "DCA_{z};p_{T} (GeV/c); DCA_{Z};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + + registryParticleQA.add("TrackQA/After/AntiDeuteron/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fTpcCrossedRows", "TPC Crossed Rows;TPC Crossed Rows;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fTpcSharedClusters", "TPC Shared Clusters;TPC Shared Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fTpcSharedClusterOverClusterss", "TPC Shared Clusters/Clusters;TPC Shared Clusters/Clusters;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fTpcFindableOverRows", "TPC Findabled/Crossed Rows;TPC Findable/CrossedRows;Entries", HistType::kTH1F, {Binning.ratio}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fTpcChi2OverCluster", "TPC #chi^{2}/Cluster;TPC #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.tpcChi2}); + + registryParticleQA.add("TrackQA/After/AntiDeuteron/fItsClusters", "ITS Clusters;ITS Clusters;Entries", HistType::kTH1F, {Binning.itsCluster}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fItsIbClusters", "ITS Inner Barrel Clusters;ITS Inner Barrel Clusters;Entries", HistType::kTH1F, {Binning.itsIbCluster}); + registryParticleQA.add("TrackQA/After/AntiDeuteron/fItsChi2OverCluster", "ITS #chi^{2}/Cluster;ITS #chi^{2}/Cluster;Entries", HistType::kTH1F, {Binning.itsChi2}); + + // Lambda before + registryParticleQA.add("LambdaQA/Before/fPt", "Transverse momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/Before/fEta", "Psedurapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/Before/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/Before/fInvMassLambda", "Invariant mass Lambda;M_{#pi p};Entries", HistType::kTH1F, {Binning.invMassLambda}); + registryParticleQA.add("LambdaQA/Before/fInvMassAntiLambda", "Invariant mass AntiLambda;M_{#pi p};Entries", HistType::kTH1F, {Binning.invMassLambda}); + registryParticleQA.add("LambdaQA/Before/fInvMassLambdaVsAntiLambda", "Invariant mass of Lambda vs AntiLambda;M_{#pi p};Entries", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassLambda}); + registryParticleQA.add("LambdaQA/Before/fInvMassLambdaVsKaon", "Invariant mass of Lambda vs K0;M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassK0short}); + registryParticleQA.add("LambdaQA/Before/fInvMassAntiLambdaVsKaon", "Invariant mass of AntiLambda vs K0;M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassK0short}); + registryParticleQA.add("LambdaQA/Before/fDcaDaugh", "DCA_{Daugh};DCA_{daugh};Entries", HistType::kTH1F, {Binning.dcaDaugh}); + registryParticleQA.add("LambdaQA/Before/fCpa", "Cosine of pointing angle;CPA;Entries", HistType::kTH1F, {Binning.cpa}); + registryParticleQA.add("LambdaQA/Before/fTranRad", "Transverse Radisu;TranRad;Entries", HistType::kTH1F, {Binning.transRad}); + registryParticleQA.add("LambdaQA/Before/fDecVtx", "Decay vertex displacement;DecVtx;Entries", HistType::kTH1F, {Binning.decayVtx}); + registryParticleQA.add("LambdaQA/Before/PosDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/Before/PosDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/Before/PosDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/Before/PosDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("LambdaQA/Before/PosDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("LambdaQA/Before/PosDaughter/fNsigmaTpcProton", "NSigmaTPC Proton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("LambdaQA/Before/PosDaughter/fNsigmaTpcPion", "NSigmaTPC Pion;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("LambdaQA/Before/NegDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/Before/NegDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/Before/NegDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/Before/NegDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("LambdaQA/Before/NegDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("LambdaQA/Before/NegDaughter/fNsigmaTpcProton", "NSigmaTPC AnitProton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("LambdaQA/Before/NegDaughter/fNsigmaTpcPion", "NSigmaTPC AntiPion;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + + // Lambda after + registryParticleQA.add("LambdaQA/After/Lambda/fPt", "Transverse momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/After/Lambda/fEta", "Psedurapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/After/Lambda/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/After/Lambda/fInvMass", "Invariant mass;M_{#pi p};Entries", HistType::kTH1F, {Binning.invMassLambda}); + registryParticleQA.add("LambdaQA/After/Lambda/fInvMassLambdaVsAntiLambda", "Invariant mass of Lambda vs AntiLambda;M_{#pi p};Entries", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassLambda}); + registryParticleQA.add("LambdaQA/After/Lambda/fInvMassLambdaVsKaon", "Invariant mass of rejected K0 vs V0s;M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassK0short}); + registryParticleQA.add("LambdaQA/After/Lambda/fDcaDaugh", "DCA_{Daugh};DCA_{daugh};Entries", HistType::kTH1F, {Binning.dcaDaugh}); + registryParticleQA.add("LambdaQA/After/Lambda/fCpa", "Cosine of pointing angle;CPA;Entries", HistType::kTH1F, {Binning.cpa}); + registryParticleQA.add("LambdaQA/After/Lambda/fTranRad", "Transverse Radisu;TranRad;Entries", HistType::kTH1F, {Binning.transRad}); + registryParticleQA.add("LambdaQA/After/Lambda/fDecVtx", "Decay vertex displacement;DecVtx;Entries", HistType::kTH1F, {Binning.decayVtx}); + registryParticleQA.add("LambdaQA/After/Lambda/PosDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/After/Lambda/PosDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/After/Lambda/PosDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/After/Lambda/PosDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("LambdaQA/After/Lambda/PosDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("LambdaQA/After/Lambda/PosDaughter/fNsigmaTpc", "NSigmaTPC Proton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("LambdaQA/After/Lambda/NegDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/After/Lambda/NegDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/After/Lambda/NegDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/After/Lambda/NegDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("LambdaQA/After/Lambda/NegDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("LambdaQA/After/Lambda/NegDaughter/fNsigmaTpc", "NSigmaTPC AntiPion;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + + // AntiLambda after + registryParticleQA.add("LambdaQA/After/AntiLambda/fPt", "Transverse momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fEta", "Psedurapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fInvMass", "Invariant mass;M_{#pi p};Entries", HistType::kTH1F, {Binning.invMassLambda}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fInvMassAntiLambdaVsLambda", "Invariant mass of Lambda vs AntiLambda;M_{#pi p};Entries", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassLambda}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fInvMassAntiLambdaVsKaon", "Invariant mass of rejected K0 vs V0s;M_{#pi p};;M_{#pi #pi}", HistType::kTH2F, {Binning.invMassLambda, Binning.invMassK0short}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fDcaDaugh", "DCA_{Daugh};DCA_{daugh};Entries", HistType::kTH1F, {Binning.dcaDaugh}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fCpa", "Cosine of pointing angle;CPA;Entries", HistType::kTH1F, {Binning.cpa}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fTranRad", "Transverse Radisu;TranRad;Entries", HistType::kTH1F, {Binning.transRad}); + registryParticleQA.add("LambdaQA/After/AntiLambda/fDecVtx", "Decay vertex displacement;DecVtx;Entries", HistType::kTH1F, {Binning.decayVtx}); + registryParticleQA.add("LambdaQA/After/AntiLambda/PosDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/After/AntiLambda/PosDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/After/AntiLambda/PosDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/After/AntiLambda/PosDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("LambdaQA/After/AntiLambda/PosDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("LambdaQA/After/AntiLambda/PosDaughter/fNsigmaTpc", "NSigmaTPC Proton;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + registryParticleQA.add("LambdaQA/After/AntiLambda/NegDaughter/fPt", "Transverse Momentum;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("LambdaQA/After/AntiLambda/NegDaughter/fEta", "Pseudorapidity;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("LambdaQA/After/AntiLambda/NegDaughter/fPhi", "Azimuthal Angle;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + registryParticleQA.add("LambdaQA/After/AntiLambda/NegDaughter/fDcaXy", "DCA_{XY};p_{T} (GeV/c); DCA_{XY};Entries", HistType::kTH2F, {Binning.momentum, Binning.dca}); + registryParticleQA.add("LambdaQA/After/AntiLambda/NegDaughter/fTpcClusters", "TPC Clusters;TPC Clusters;Entries", HistType::kTH1F, {Binning.tpcCluster}); + registryParticleQA.add("LambdaQA/After/AntiLambda/NegDaughter/fNsigmaTpc", "NSigmaTPC AntiPion;p_{TPC} (GeV/c);n#sigma_{TPC}", {HistType::kTH2F, {Binning.momentum, Binning.nsigma}}); + + // Phi before + registryParticleQA.add("PhiQA/Before/fInvMass", "Invariant mass #phi;M_{KK};Entries", HistType::kTH1F, {Binning.invMassPhi}); + registryParticleQA.add("PhiQA/Before/fPt", "Transverse momentum #phi;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("PhiQA/Before/fEta", "Pseudorapidity of V0;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("PhiQA/Before/fPhi", "Azimuthal angle of #phi;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + // Phi after + registryParticleQA.add("PhiQA/After/fInvMass", "Invariant mass #phi;M_{KK};Entries", HistType::kTH1F, {Binning.invMassPhi}); + registryParticleQA.add("PhiQA/After/fPt", "Transverse momentum #phi;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("PhiQA/After/fEta", "Pseudorapidity of #phi;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("PhiQA/After/fPhi", "Azimuthal angle of #Phi;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + // Rho before + registryParticleQA.add("RhoQA/Before/fInvMass", "Invariant mass #rho;M_{#pi#pi};Entries", HistType::kTH1F, {Binning.invMassRho}); + registryParticleQA.add("RhoQA/Before/fPt", "Transverse momentum #rho;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("RhoQA/Before/fEta", "Pseudorapidity of #rho;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.add("RhoQA/Before/fPhi", "Azimuthal angle of #rho;#varphi;Entries", HistType::kTH1F, {Binning.phi}); + + // Rho after + registryParticleQA.add("RhoQA/After/fInvMass", "Invariant mass #rho;M_{#pi#pi};Entries", HistType::kTH1F, {Binning.invMassRho}); + registryParticleQA.add("RhoQA/After/fPt", "Transverse momentum #rho;p_{T} (GeV/c);Entries", HistType::kTH1F, {Binning.momentum}); + registryParticleQA.add("RhoQA/After/fEta", "Pseudorapidity of #rho;#eta;Entries", HistType::kTH1F, {Binning.eta}); + registryParticleQA.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}}}); + registryTriggerQA.add("PPP/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPP/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPP/all/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPP/all/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPP/all/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPP/all/fAntiProtonQ3VsPt", "Q_{3} vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPP/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPP/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPP/loose/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPP/loose/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPP/loose/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPP/loose/fAntiProtonQ3VsPt", "Q_{3} vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPP/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPP/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPP/tight/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPP/tight/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPP/tight/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPP/tight/fAntiProtonQ3VsPt", "Q_{3} vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); // 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}}}); + registryTriggerQA.add("PPL/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPL/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPL/all/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPL/all/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPL/all/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/all/fAntiProtonQ3VsPt", "Q_{3} vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/all/fLambdaQ3VsPt", "Q_{3} vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/all/fAntiLambdaQ3VsPt", "Q_{3} vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPL/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPL/loose/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPL/loose/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPL/loose/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/loose/fAntiProtonQ3VsPt", "Q_{3} vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/loose/fLambdaQ3VsPt", "Q_{3} vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/loose/fAntiLambdaQ3VsPt", "Q_{3} vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPL/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPL/tight/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPL/tight/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPL/tight/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/tight/fAntiProtonQ3VsPt", "Q_{3} vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/tight/fLambdaQ3VsPt", "Q_{3} vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PPL/tight/fAntiLambdaQ3VsPt", "Q_{3} vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); // 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}}}); + registryTriggerQA.add("PLL/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PLL/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PLL/all/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PLL/all/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PLL/all/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/all/fAntiProtonQ3VsPt", "Q3 vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/all/fLambdaQ3VsPt", "Q3 vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/all/fAntiLambdaQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PLL/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PLL/loose/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PLL/loose/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PLL/loose/fProtonQ3VsPt", "Q3 vs pT vs Proton p;Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/loose/fAntiProtonQ3VsPt", "Q3 vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/loose/fLambdaQ3VsPt", "Q3 vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/loose/fAntiLambdaQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PLL/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PLL/tight/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PLL/tight/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PLL/tight/fProtonQ3VsPt", "Q3 vs pT vs Proton p;Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/tight/fAntiProtonQ3VsPt", "Q3 vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/tight/fLambdaQ3VsPt", "Q3 vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("PLL/tight/fAntiLambdaQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); // 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}}}); + registryTriggerQA.add("LLL/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("LLL/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("LLL/all/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("LLL/all/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("LLL/all/fLambdaQ3VsPt", "Q3 vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("LLL/all/fAntiLambdaQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("LLL/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("LLL/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("LLL/loose/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("LLL/loose/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("LLL/loose/fLambdaQ3VsPt", "Q3 vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("LLL/loose/fAntiLambdaQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("LLL/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("LLL/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("LLL/tight/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("LLL/tight/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("LLL/tight/fLambdaQ3VsPt", "Q3 vs Lambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + registryTriggerQA.add("LLL/tight/fAntiLambdaQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.q3, Binning.momentum}}); + + // for ppPhi + registryTriggerQA.add("PPPhi/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPPhi/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPPhi/all/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPPhi/all/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPPhi/all/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/all/fAntiProtonQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/all/fPhiQ3VsPt", "Q_{3} vs #phi p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/all/fPhiQ3VsInvMass", "Q_{3} vs #phi mass;Q_{3} (GeV/c);M_{K^{+}K^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.q3, Binning.invMassPhi}); + registryTriggerQA.add("PPPhi/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPPhi/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPPhi/loose/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPPhi/loose/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPPhi/loose/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/loose/fAntiProtonQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/loose/fPhiQ3VsPt", "Q_{3} vs #phi p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/loose/fPhiQ3VsInvMass", "Q_{3} vs #phi mass;Q_{3} (GeV/c);M_{K^{+}K^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.q3, Binning.invMassPhi}); + registryTriggerQA.add("PPPhi/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPPhi/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPPhi/tight/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPPhi/tight/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);Entries", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPPhi/tight/fProtonQ3VsPt", "Q_{3} vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/tight/fAntiProtonQ3VsPt", "Q3 vs AntiLambda p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/tight/fPhiQ3VsPt", "Q_{3} vs #phi p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPPhi/tight/fPhiQ3VsInvMass", "Q_{3} vs #phi mass;Q_{3} (GeV/c);M_{K^{+}K^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.q3, Binning.invMassPhi}); + + // for ppRho + registryTriggerQA.add("PPRho/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPRho/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPRho/all/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPRho/all/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPRho/all/fProtonQ3VsPt", "Q3 vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/all/fAntiProtonQ3VsPt", "Q3 vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/all/fRhoQ3VsPt", "Q3 vs #rho p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/all/fRhoQ3VsInvMass", "Q_{3} vs #rho mass;Q_{3} (GeV/c);M_{#pi^{+}#pi^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.q3, Binning.invMassRho}); + registryTriggerQA.add("PPRho/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPRho/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPRho/loose/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPRho/loose/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPRho/loose/fProtonQ3VsPt", "Q3 vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/loose/fAntiProtonQ3VsPt", "Q3 vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/loose/fRhoQ3VsPt", "Q3 vs #rho p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/loose/fRhoQ3VsInvMass", "Q_{3} vs #rho mass;Q_{3} (GeV/c);M_{#pi^{+}#pi^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.q3, Binning.invMassRho}); + registryTriggerQA.add("PPRho/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PPRho/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PPRho/tight/fSE_particle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPRho/tight/fSE_antiparticle", "Same Event distribution;Q_{3} (GeV/c);SE", HistType::kTH1F, {Binning.q3}); + registryTriggerQA.add("PPRho/tight/fProtonQ3VsPt", "Q3 vs Proton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/tight/fAntiProtonQ3VsPt", "Q3 vs AntiProton p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/tight/fRhoQ3VsPt", "Q3 vs #rho p_{T};Q_{3} (GeV/c);p_{T} (GeV/c)", HistType::kTH2F, {Binning.q3, Binning.momentum}); + registryTriggerQA.add("PPRho/tight/fRhoQ3VsInvMass", "Q_{3} vs #rho mass;Q_{3} (GeV/c);M_{#pi^{+}#pi^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.q3, Binning.invMassRho}); // 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}}}); + registryTriggerQA.add("PD/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PD/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PD/all/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PD/all/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PD/all/fProtonKstarVsPt", "k* vs Proton p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/all/fAntiProtonKstarVsPt", "k* vs AntiProton p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/all/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/all/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PD/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PD/loose/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PD/loose/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PD/loose/fProtonKstarVsPt", "k* vs Proton p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/loose/fAntiProtonKstarVsPt", "k* vs AntiProton p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/loose/fDeuteronKstarVsPt", "k* Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/loose/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PD/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PD/tight/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PD/tight/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PD/tight/fProtonKstarVsPt", "k* vs Proton p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/tight/fAntiProtonKstarVsPt", "k* vs AntiProton p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/tight/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PD/tight/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); // 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}}}); + registryTriggerQA.add("LD/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("LD/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("LD/all/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("LD/all/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("LD/all/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/all/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/all/fLambdaKstarVsPt", "k* vs Lambda p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/all/fAntiLambdaKstarVsPt", "k* vs AntiLambda p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("LD/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("LD/loose/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("LD/loose/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("LD/loose/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/loose/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/loose/fLambdaKstarVsPt", "k* vs Lambda p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/loose/fAntiLambdaKstarVsPt", "k* vs AntiLambda p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("LD/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("LD/tight/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("LD/tight/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("LD/tight/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/tight/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/tight/fLambdaKstarVsPt", "k* vs Lambda p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("LD/tight/fAntiLambdaKstarVsPt", "k* vs AntiLambda p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + + // for phid + registryTriggerQA.add("PhiD/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PhiD/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PhiD/all/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PhiD/all/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PhiD/all/fPhiKstarVsPt", "k* vs Phi p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/all/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/all/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/all/fPhiKstarVsInvMass", "k* vs #phi mass;k* (GeV/c);M_{K^{+}K^{-}} (GeV/c^{2});", HistType::kTH2F, {Binning.kstar, Binning.invMassPhi}); + registryTriggerQA.add("PhiD/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PhiD/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PhiD/loose/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PhiD/loose/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PhiD/loose/fPhiKstarVsPt", "k* vs Phi p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/loose/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/loose/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/loose/fPhiKstarVsInvMass", "k* vs #phi mass;k* (GeV/c);M_{K^{+}K^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.kstar, Binning.invMassPhi}); + registryTriggerQA.add("PhiD/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("PhiD/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("PhiD/tight/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PhiD/tight/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("PhiD/tight/fPhiKstarVsPt", "k* vs Phi p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/tight/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/tight/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("PhiD/tight/fPhiKstarVsInvMass", "k* vs #phi mass;k* (GeV/c);M_{K^{+}K^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.kstar, Binning.invMassPhi}); + + // for rhod + registryTriggerQA.add("RhoD/all/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("RhoD/all/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("RhoD/all/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("RhoD/all/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("RhoD/all/fRhoKstarVsPt", "k* vs Rho p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/all/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/all/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/all/fRhoKstarVsInvMass", "k* vs #rho mass;k* (GeV/c);M_{#pi^{+}#pi^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.kstar, Binning.invMassRho}); + registryTriggerQA.add("RhoD/loose/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("RhoD/loose/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("RhoD/loose/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("RhoD/loose/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("RhoD/loose/fRhoKstarVsPt", "k* vs Rho p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/loose/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/loose/fAntiDeuteronKstarVsPt", "k* vs AntiDeuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/loose/fRhoKstarVsInvMass", "k* vs #rho mass;k* (GeV/c);M_{#pi^{+}#pi^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.kstar, Binning.invMassRho}); + registryTriggerQA.add("RhoD/tight/fMultiplicity", "Multiplicity;Mult;Entries", HistType::kTH1F, {Binning.multiplicity}); + registryTriggerQA.add("RhoD/tight/fZvtx", "Zvtx;Z_{vtx};Entries", HistType::kTH1F, {Binning.zvtx}); + registryTriggerQA.add("RhoD/tight/fSE_particle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("RhoD/tight/fSE_antiparticle", "Same Event distribution;k* (GeV/c);Entries", HistType::kTH1F, {Binning.kstar}); + registryTriggerQA.add("RhoD/tight/fRhoKstarVsPt", "k* vs Rho p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/tight/fDeuteronKstarVsPt", "k* vs Deuteron p_{T};k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/tight/fAntiDeuteronKstarVsPt", "AntiDeuteron p_{T} vs k*;k* (GeV/c);p_{T} (GeV/c)", {HistType::kTH2F, {Binning.kstar, Binning.momentum}}); + registryTriggerQA.add("RhoD/tight/fRhoKstarVsInvMass", "k* vs #rho mass;k* (GeV/c);M_{#pi^{+}#pi^{-}} (GeV/c^{2})", HistType::kTH2F, {Binning.kstar, Binning.invMassRho}); } - 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) { - return false; - } - if (ConfEvtOfflineCheck && !col.sel8()) { + if (std::abs(col.posZ()) > EventSelection.zvtx.value) { return false; } - // if event is close to the timeframe border, return false - if (ConfEvtTimeFrameBorderCheck && !col.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (EventSelection.eventSel.value && !col.sel8()) { 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) { + if (track.pt() < TrackSelections.momentum->get(trackName.c_str(), "PtMin")) { return false; } - if (tpcNClsF < ConfTPCNClustersMin->get("TPCNClusMin", partSpecies)) { + if (track.pt() > TrackSelections.momentum->get(trackName.c_str(), "PtMax")) { 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; + float momentum = -99; - 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; - } - - 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 (nSigmaTPC < ConfDaughPIDCuts->get(species, "TPC min") || - nSigmaTPC > ConfDaughPIDCuts->get(species, "TPC max")) { - return false; + if (TrackSelections.momentum->get(trackName.c_str(), "UseInnerParam") < 0) { + momentum = track.p(); + } else { + momentum = track.tpcInnerParam(); } - 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 = std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi()); + } else if (trackName == std::string("Kaon")) { + nsigmaITS = track.itsNSigmaKa(); + nsigmaTPC = track.tpcNSigmaKa(); + nsigmaTPCTOF = std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa()); + } else if (trackName == std::string("Proton")) { + nsigmaITS = track.itsNSigmaPr(); + nsigmaTPC = track.tpcNSigmaPr(); + nsigmaTPCTOF = std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr()); + } else if (trackName == std::string("Deuteron")) { + nsigmaITS = track.itsNSigmaDe(); + nsigmaTPC = track.tpcNSigmaDe(); + nsigmaTPCTOF = std::hypot(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 +1217,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 +1237,1374 @@ 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); - } - - std::vector setValuesBB(aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) - { - 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) - { - 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; + float q32 = q12.M2() + q23.M2() + q31.M2(); + return std::sqrt(-q32); } template - double updatePID(T const& track, double bgScaling, std::vector BB) + float itsSignal(T const& track) { - 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); - } - - void process(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, aod::FemtoFullTracks const& tracks, o2::aod::V0Datas const& fullV0s) + 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) { - if (!ConfIsRun3) { - LOG(fatal) << "Run 2 processing is not implemented!"; + auto tracksWithItsPid = soa::Attach(tracks); + + // reset all arrays + keepEventTightLimit.fill(false); + keepEventLooseLimit.fill(false); + signalTightLimit.fill(0); + signalLooseLimit.fill(0); + + registryTriggerQA.fill(HIST("fProcessedEvents"), 0); + registryParticleQA.fill(HIST("EventQA/Before/fMultiplicity"), col.multNTracksPV()); + registryParticleQA.fill(HIST("EventQA/Before/fZvtx"), col.posZ()); + + if (!checkEvent(col)) { + 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]); + 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); - } - if (ConfUseManualPIDdeuteron) { - BBDeuteron = setValuesBB(bc, ConfPIDBBDeuteron); - BBAntideuteron = setValuesBB(bc, ConfPIDBBAntiDeuteron); + registryParticleQA.fill(HIST("EventQA/After/fMultiplicity"), col.multNTracksPV()); + registryParticleQA.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) { + registryParticleQA.fill(HIST("TrackQA/Before/Particle/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/Before/Particle/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/Before/Particle/fPhi"), track.phi()); + registryParticleQA.fill(HIST("TrackQA/Before/Particle/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/Before/Particle/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/Before/Particle/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/Before/Particle/fTofSignal"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/Before/Pion/fNsigmaITS"), track.p(), track.itsNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/Before/Pion/fNsigmaTPC"), track.p(), track.tpcNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/Before/Pion/fNsigmaTOF"), track.p(), track.tofNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/Before/Pion/fNsigmaTPCTOF"), track.p(), std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi())); + + registryParticleQA.fill(HIST("TrackQA/Before/Kaon/fNsigmaITS"), track.p(), track.itsNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/Before/Kaon/fNsigmaTPC"), track.p(), track.tpcNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/Before/Kaon/fNsigmaTOF"), track.p(), track.tofNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/Before/Kaon/fNsigmaTPCTOF"), track.p(), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa())); + + registryParticleQA.fill(HIST("TrackQA/Before/Proton/fNsigmaITS"), track.p(), track.itsNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/Before/Proton/fNsigmaTPC"), track.p(), track.tpcNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/Before/Proton/fNsigmaTOF"), track.p(), track.tofNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/Before/Proton/fNsigmaTPCTOF"), track.p(), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())); + + registryParticleQA.fill(HIST("TrackQA/Before/Deuteron/fNsigmaITS"), track.p(), track.itsNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/Before/Deuteron/fNsigmaTPC"), track.p(), track.tpcNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/Before/Deuteron/fNsigmaTOF"), track.p(), track.tofNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/Before/Deuteron/fNsigmaTPCTOF"), track.p(), std::hypot(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()); + + registryParticleQA.fill(HIST("TrackQA/After/Pion/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fPTpc"), track.tpcInnerParam()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fPhi"), track.phi()); + + registryParticleQA.fill(HIST("TrackQA/After/Pion/fNsigmaIts"), track.p(), track.itsNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fNsigmaTpc"), track.p(), track.tpcNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fNsigmaTof"), track.p(), track.tofNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fNsigmaTpcTof"), track.p(), std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi())); + + registryParticleQA.fill(HIST("TrackQA/After/Pion/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fTofBeta"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/After/Pion/fDcaXy"), track.pt(), track.dcaXY()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fDcaZ"), track.pt(), track.dcaZ()); + + registryParticleQA.fill(HIST("TrackQA/After/Pion/fTpcClusters"), track.tpcNClsFound()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fTpcSharedClusters"), track.tpcNClsShared()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registryParticleQA.fill(HIST("TrackQA/After/Pion/fItsClusters"), track.itsNCls()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fItsIbClusters"), track.itsNClsInnerBarrel()); + registryParticleQA.fill(HIST("TrackQA/After/Pion/fItsChi2OverCluster"), track.itsChi2NCl()); } - 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()); + + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fPTpc"), track.tpcInnerParam()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fPhi"), track.phi()); + + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fNsigmaIts"), track.p(), track.itsNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fNsigmaTpc"), track.p(), track.tpcNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fNsigmaTof"), track.p(), track.tofNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fNsigmaTpcTof"), track.p(), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa())); + + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fTofBeta"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fDcaXy"), track.pt(), track.dcaXY()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fDcaZ"), track.pt(), track.dcaZ()); + + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fTpcClusters"), track.tpcNClsFound()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fTpcSharedClusters"), track.tpcNClsShared()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fItsClusters"), track.itsNCls()); + registryParticleQA.fill(HIST("TrackQA/After/Kaon/fItsIbClusters"), track.itsNClsInnerBarrel()); + registryParticleQA.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()); + + registryParticleQA.fill(HIST("TrackQA/After/Proton/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fPTpc"), track.tpcInnerParam()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fPhi"), track.phi()); + + registryParticleQA.fill(HIST("TrackQA/After/Proton/fNsigmaIts"), track.p(), track.itsNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fNsigmaTpc"), track.p(), track.tpcNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fNsigmaTof"), track.p(), track.tofNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fNsigmaTpcTof"), track.p(), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())); + + registryParticleQA.fill(HIST("TrackQA/After/Proton/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fTofBeta"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/After/Proton/fDcaXy"), track.pt(), track.dcaXY()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fDcaZ"), track.pt(), track.dcaZ()); + + registryParticleQA.fill(HIST("TrackQA/After/Proton/fTpcClusters"), track.tpcNClsFound()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fTpcSharedClusters"), track.tpcNClsShared()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registryParticleQA.fill(HIST("TrackQA/After/Proton/fItsClusters"), track.itsNCls()); + registryParticleQA.fill(HIST("TrackQA/After/Proton/fItsIbClusters"), track.itsNClsInnerBarrel()); + registryParticleQA.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()); + + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fPTpc"), track.tpcInnerParam()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fPhi"), track.phi()); + + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fNsigmaIts"), track.p(), track.itsNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fNsigmaTpc"), track.p(), track.tpcNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fNsigmaTof"), track.p(), track.tofNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fNsigmaTpcTof"), track.p(), std::hypot(track.tpcNSigmaDe(), track.tofNSigmaDe())); + + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fTofBeta"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fDcaXy"), track.pt(), track.dcaXY()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fDcaZ"), track.pt(), track.dcaZ()); + + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fTpcClusters"), track.tpcNClsFound()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fTpcSharedClusters"), track.tpcNClsShared()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fItsClusters"), track.itsNCls()); + registryParticleQA.fill(HIST("TrackQA/After/Deuteron/fItsIbClusters"), track.itsNClsInnerBarrel()); + registryParticleQA.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) { + registryParticleQA.fill(HIST("TrackQA/Before/AntiParticle/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiParticle/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiParticle/fPhi"), track.phi()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiParticle/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiParticle/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/Before/AntiParticle/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiParticle/fTofSignal"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/Before/AntiPion/fNsigmaITS"), track.p(), track.itsNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiPion/fNsigmaTPC"), track.p(), track.tpcNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiPion/fNsigmaTOF"), track.p(), track.tofNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiPion/fNsigmaTPCTOF"), track.p(), std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi())); + + registryParticleQA.fill(HIST("TrackQA/Before/AntiKaon/fNsigmaITS"), track.p(), track.itsNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiKaon/fNsigmaTPC"), track.p(), track.tpcNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiKaon/fNsigmaTOF"), track.p(), track.tofNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiKaon/fNsigmaTPCTOF"), track.p(), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa())); + + registryParticleQA.fill(HIST("TrackQA/Before/AntiProton/fNsigmaITS"), track.p(), track.itsNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiProton/fNsigmaTPC"), track.p(), track.tpcNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiProton/fNsigmaTOF"), track.p(), track.tofNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiProton/fNsigmaTPCTOF"), track.p(), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())); + + registryParticleQA.fill(HIST("TrackQA/Before/AntiDeuteron/fNsigmaITS"), track.p(), track.itsNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiDeuteron/fNsigmaTPC"), track.p(), track.tpcNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiDeuteron/fNsigmaTOF"), track.p(), track.tofNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/Before/AntiDeuteron/fNsigmaTPCTOF"), track.p(), std::hypot(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()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fPTpc"), track.tpcInnerParam()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fPhi"), track.phi()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fNsigmaIts"), track.p(), track.itsNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fNsigmaTpc"), track.p(), track.tpcNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fNsigmaTof"), track.p(), track.tofNSigmaPi()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fNsigmaTpcTof"), track.p(), std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi())); + + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fTofBeta"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fDcaXy"), track.pt(), track.dcaXY()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fDcaZ"), track.pt(), track.dcaZ()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fTpcClusters"), track.tpcNClsFound()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fTpcSharedClusters"), track.tpcNClsShared()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fItsClusters"), track.itsNCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiPion/fItsIbClusters"), track.itsNClsInnerBarrel()); + registryParticleQA.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()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fPTpc"), track.tpcInnerParam()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fPhi"), track.phi()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fNsigmaIts"), track.p(), track.itsNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fNsigmaTpc"), track.p(), track.tpcNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fNsigmaTof"), track.p(), track.tofNSigmaKa()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fNsigmaTpcTof"), track.p(), std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa())); + + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fTofBeta"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fDcaXy"), track.pt(), track.dcaXY()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fDcaZ"), track.pt(), track.dcaZ()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fTpcClusters"), track.tpcNClsFound()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fTpcSharedClusters"), track.tpcNClsShared()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fItsClusters"), track.itsNCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiKaon/fItsIbClusters"), track.itsNClsInnerBarrel()); + registryParticleQA.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()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fPTpc"), track.tpcInnerParam()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fPhi"), track.phi()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fNsigmaIts"), track.p(), track.itsNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fNsigmaTpc"), track.p(), track.tpcNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fNsigmaTof"), track.p(), track.tofNSigmaPr()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fNsigmaTpcTof"), track.p(), std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr())); + + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fTofBeta"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fDcaXy"), track.pt(), track.dcaXY()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fDcaZ"), track.pt(), track.dcaZ()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fTpcClusters"), track.tpcNClsFound()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fTpcSharedClusters"), track.tpcNClsShared()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fItsClusters"), track.itsNCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiProton/fItsIbClusters"), track.itsNClsInnerBarrel()); + registryParticleQA.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()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fPt"), track.pt()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fPTpc"), track.tpcInnerParam()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fMomCor"), track.p(), (track.tpcInnerParam() - track.p()) / track.p()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fEta"), track.eta()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fPhi"), track.phi()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fNsigmaIts"), track.p(), track.itsNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fNsigmaTpc"), track.p(), track.tpcNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fNsigmaTof"), track.p(), track.tofNSigmaDe()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fNsigmaTpcTof"), track.p(), std::hypot(track.tpcNSigmaDe(), track.tofNSigmaDe())); + + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fItsSignal"), track.p(), itsSignal(track)); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fTpcSignal"), track.p(), track.tpcSignal()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fTofBeta"), track.p(), track.beta()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fDcaXy"), track.pt(), track.dcaXY()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fDcaZ"), track.pt(), track.dcaZ()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fTpcClusters"), track.tpcNClsFound()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fTpcCrossedRows"), track.tpcNClsCrossedRows()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fTpcSharedClusters"), track.tpcNClsShared()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fTpcSharedClusterOverClusterss"), track.tpcFractionSharedCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fTpcFindableOverRows"), track.tpcCrossedRowsOverFindableCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fTpcChi2OverCluster"), track.tpcChi2NCl()); + + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fItsClusters"), track.itsNCls()); + registryParticleQA.fill(HIST("TrackQA/After/AntiDeuteron/fItsIbClusters"), track.itsNClsInnerBarrel()); + registryParticleQA.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 = std::hypot(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; + + registryParticleQA.fill(HIST("LambdaQA/Before/fPt"), lambdaPt); + registryParticleQA.fill(HIST("LambdaQA/Before/fEta"), lambdaEta); + registryParticleQA.fill(HIST("LambdaQA/Before/fPhi"), lambdaPhi); + registryParticleQA.fill(HIST("LambdaQA/Before/fInvMassLambda"), lambdaMass); + registryParticleQA.fill(HIST("LambdaQA/Before/fInvMassAntiLambda"), antiLambdaMass); + registryParticleQA.fill(HIST("LambdaQA/Before/fInvMassLambdaVsAntiLambda"), lambdaMass, antiLambdaMass); + registryParticleQA.fill(HIST("LambdaQA/Before/fInvMassLambdaVsKaon"), lambdaMass, kaonMass); + registryParticleQA.fill(HIST("LambdaQA/Before/fInvMassAntiLambdaVsKaon"), antiLambdaMass, kaonMass); + registryParticleQA.fill(HIST("LambdaQA/Before/fDcaDaugh"), lambdaDauDca); + registryParticleQA.fill(HIST("LambdaQA/Before/fCpa"), lambdaCpa); + registryParticleQA.fill(HIST("LambdaQA/Before/fTranRad"), lambdaRadius); + registryParticleQA.fill(HIST("LambdaQA/Before/fDecVtx"), lambdaPos); + + registryParticleQA.fill(HIST("LambdaQA/Before/PosDaughter/fPt"), posTrack.pt()); + registryParticleQA.fill(HIST("LambdaQA/Before/PosDaughter/fEta"), posTrackEta); + registryParticleQA.fill(HIST("LambdaQA/Before/PosDaughter/fPhi"), posTrack.phi()); + registryParticleQA.fill(HIST("LambdaQA/Before/PosDaughter/fDcaXy"), posTrack.pt(), posTrackDca); + registryParticleQA.fill(HIST("LambdaQA/Before/PosDaughter/fTpcClusters"), posTrack.tpcNClsFound()); + registryParticleQA.fill(HIST("LambdaQA/Before/PosDaughter/fNsigmaTpcProton"), posTrack.p(), posTrack.tpcNSigmaPr()); + registryParticleQA.fill(HIST("LambdaQA/Before/PosDaughter/fNsigmaTpcPion"), posTrack.p(), posTrack.tpcNSigmaPi()); + + registryParticleQA.fill(HIST("LambdaQA/Before/NegDaughter/fPt"), negTrack.pt()); + registryParticleQA.fill(HIST("LambdaQA/Before/NegDaughter/fEta"), negTrackEta); + registryParticleQA.fill(HIST("LambdaQA/Before/NegDaughter/fPhi"), negTrack.phi()); + registryParticleQA.fill(HIST("LambdaQA/Before/NegDaughter/fDcaXy"), negTrack.pt(), negTrackDca); + registryParticleQA.fill(HIST("LambdaQA/Before/NegDaughter/fTpcClusters"), negTrack.tpcNClsFound()); + registryParticleQA.fill(HIST("LambdaQA/Before/NegDaughter/fNsigmaTpcProton"), negTrack.p(), negTrack.tpcNSigmaPr()); + registryParticleQA.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()); + + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fPt"), lambdaPt); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fEta"), lambdaEta); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fPhi"), lambdaPhi); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fInvMass"), lambdaMass); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fInvMassLambdaVsAntiLambda"), lambdaMass, antiLambdaMass); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fInvMassLambdaVsKaon"), lambdaMass, kaonMass); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fDcaDaugh"), lambdaDauDca); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fCpa"), lambdaCpa); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fTranRad"), lambdaRadius); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/fDecVtx"), lambdaPos); + + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fPt"), posTrack.pt()); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fEta"), posTrackEta); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fPhi"), posTrack.phi()); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fDcaXy"), posTrack.pt(), posTrackDca); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fTpcClusters"), posTrack.tpcNClsFound()); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/PosDaughter/fNsigmaTpc"), posTrack.p(), posTrack.tpcNSigmaPr()); + + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fPt"), negTrack.pt()); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fEta"), negTrackEta); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fPhi"), negTrack.phi()); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fDcaXy"), negTrack.pt(), negTrackDca); + registryParticleQA.fill(HIST("LambdaQA/After/Lambda/NegDaughter/fTpcClusters"), negTrack.tpcNClsFound()); + registryParticleQA.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()); + + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fPt"), lambdaPt); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fEta"), lambdaEta); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fPhi"), lambdaPhi); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fInvMass"), antiLambdaMass); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fInvMassAntiLambdaVsLambda"), antiLambdaMass, lambdaMass); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fInvMassAntiLambdaVsKaon"), antiLambdaMass, kaonMass); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fDcaDaugh"), lambdaDauDca); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fCpa"), lambdaCpa); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fTranRad"), lambdaRadius); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/fDecVtx"), lambdaPos); + + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fPt"), posTrack.pt()); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fEta"), posTrackEta); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fPhi"), posTrack.phi()); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fDcaXy"), posTrack.pt(), posTrackDca); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fTpcClusters"), posTrack.tpcNClsFound()); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/PosDaughter/fNsigmaTpc"), posTrack.p(), posTrack.tpcNSigmaPr()); + + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fPt"), negTrack.pt()); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fEta"), negTrackEta); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fPhi"), negTrack.phi()); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fDcaXy"), negTrack.pt(), negTrackDca); + registryParticleQA.fill(HIST("LambdaQA/After/AntiLambda/NegDaughter/fTpcClusters"), negTrack.tpcNClsFound()); + registryParticleQA.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); + + registryParticleQA.fill(HIST("PhiQA/Before/fInvMass"), phi.M()); + registryParticleQA.fill(HIST("PhiQA/Before/fPt"), phi.Pt()); + registryParticleQA.fill(HIST("PhiQA/Before/fEta"), phi.Eta()); + registryParticleQA.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)); + + registryParticleQA.fill(HIST("PhiQA/After/fInvMass"), phi.M()); + registryParticleQA.fill(HIST("PhiQA/After/fPt"), phi.Pt()); + registryParticleQA.fill(HIST("PhiQA/After/fEta"), phi.Eta()); + registryParticleQA.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); + + registryParticleQA.fill(HIST("RhoQA/Before/fInvMass"), rho.M()); + registryParticleQA.fill(HIST("RhoQA/Before/fPt"), rho.Pt()); + registryParticleQA.fill(HIST("RhoQA/Before/fEta"), rho.Eta()); + registryParticleQA.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)); + + registryParticleQA.fill(HIST("RhoQA/After/fInvMass"), rho.M()); + registryParticleQA.fill(HIST("RhoQA/After/fPt"), rho.Pt()); + registryParticleQA.fill(HIST("RhoQA/After/fEta"), rho.Eta()); + registryParticleQA.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()); + 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)); + registryTriggerQA.fill(HIST("PPP/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPP/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPP/all/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPP/all/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPP/all/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPP/all/fProtonQ3VsPt"), q3, vecProton.at(p3).Pt()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPP")) { + signalLooseLimit[cf_trigger::kPPP] += 1; + registryTriggerQA.fill(HIST("PPP/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPP/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPP/loose/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPP/loose/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPP/loose/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPP/loose/fProtonQ3VsPt"), q3, vecProton.at(p3).Pt()); + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPP")) { + signalTightLimit[cf_trigger::kPPP] += 1; + registryTriggerQA.fill(HIST("PPP/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPP/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPP/tight/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPP/tight/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPP/tight/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPP/tight/fProtonQ3VsPt"), q3, vecProton.at(p3).Pt()); + } + } } } } - - // 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)); + registryTriggerQA.fill(HIST("PPP/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPP/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPP/all/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPP/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPP/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPP/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p3).Pt()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPP")) { + signalLooseLimit[cf_trigger::kPPP] += 1; + registryTriggerQA.fill(HIST("PPP/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPP/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPP/loose/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPP/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPP/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPP/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p3).Pt()); + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPP")) { + signalTightLimit[cf_trigger::kPPP] += 1; + registryTriggerQA.fill(HIST("PPP/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPP/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPP/tight/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPP/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPP/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPP/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p3).Pt()); + } + } + } } } - - 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)); + registryTriggerQA.fill(HIST("PPL/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPL/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPL/all/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPL/all/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPL/all/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPL/all/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPL")) { + signalLooseLimit[cf_trigger::kPPL] += 1; + registryTriggerQA.fill(HIST("PPL/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPL/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPL/loose/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPL/loose/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPL/loose/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPL/loose/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPL")) { + signalTightLimit[cf_trigger::kPPL] += 1; + registryTriggerQA.fill(HIST("PPL/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPL/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPL/tight/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPL/tight/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPL/tight/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPL/tight/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); } } } } - 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)); + registryTriggerQA.fill(HIST("PPL/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPL/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPL/all/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPL/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPL/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPL/all/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPL")) { + signalLooseLimit[cf_trigger::kPPL] += 1; + registryTriggerQA.fill(HIST("PPL/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPL/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPL/loose/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPL/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPL/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPL/loose/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); + if (q3 < TriggerSelections.limits->get("Tight Limit", "PPL")) { + signalTightLimit[cf_trigger::kPPL] += 1; + registryTriggerQA.fill(HIST("PPL/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPL/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPL/tight/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPL/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPL/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPL/tight/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); } } } } } - 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)); + registryTriggerQA.fill(HIST("PLL/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PLL/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PLL/all/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PLL/all/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("PLL/all/fLambdaQ3VsPt"), q3, vecLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("PLL/all/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PLL")) { + signalLooseLimit[cf_trigger::kPLL] += 1; + registryTriggerQA.fill(HIST("PLL/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PLL/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PLL/loose/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PLL/loose/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("PLL/loose/fLambdaQ3VsPt"), q3, vecLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("PLL/loose/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + if (q3 < TriggerSelections.limits->get("Tight Limit", "PLL")) { + signalTightLimit[cf_trigger::kPLL] += 1; + registryTriggerQA.fill(HIST("PLL/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PLL/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PLL/tight/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PLL/tight/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("PLL/tight/fLambdaQ3VsPt"), q3, vecLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("PLL/tight/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); } } } } - 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)); + registryTriggerQA.fill(HIST("PLL/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PLL/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PLL/all/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PLL/all/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("PLL/all/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("PLL/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PLL")) { + signalLooseLimit[cf_trigger::kPLL] += 1; + registryTriggerQA.fill(HIST("PLL/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PLL/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PLL/loose/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PLL/loose/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("PLL/loose/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("PLL/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + if (q3 < TriggerSelections.limits->get("Tight Limit", "PLL")) { + signalTightLimit[cf_trigger::kPLL] += 1; + registryTriggerQA.fill(HIST("PLL/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PLL/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PLL/tight/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PLL/tight/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("PLL/tight/fAntiLambdaQ3VsPt"), q3, vecAntiLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("PLL/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); } } } } } - 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)); + registryTriggerQA.fill(HIST("LLL/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LLL/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LLL/all/fSE_particle"), q3); + registryTriggerQA.fill(HIST("LLL/all/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LLL/all/fLambdaQ3VsPt"), q3, vecLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("LLL/all/fLambdaQ3VsPt"), q3, vecLambda.at(l3).Pt()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "LLL")) { + signalLooseLimit[cf_trigger::kLLL] += 1; + registryTriggerQA.fill(HIST("LLL/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LLL/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LLL/loose/fSE_particle"), q3); + registryTriggerQA.fill(HIST("LLL/loose/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LLL/loose/fLambdaQ3VsPt"), q3, vecLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("LLL/loose/fLambdaQ3VsPt"), q3, vecLambda.at(l3).Pt()); + if (q3 < TriggerSelections.limits->get("Tight Limit", "LLL")) { + signalTightLimit[cf_trigger::kLLL] += 1; + registryTriggerQA.fill(HIST("LLL/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LLL/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LLL/tight/fSE_particle"), q3); + registryTriggerQA.fill(HIST("LLL/tight/fLambdaQ3VsPt"), q3, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LLL/tight/fLambdaQ3VsPt"), q3, vecLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("LLL/tight/fLambdaQ3VsPt"), q3, vecLambda.at(l3).Pt()); } } } } - 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)); + registryTriggerQA.fill(HIST("LLL/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LLL/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LLL/all/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("LLL/all/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LLL/all/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("LLL/all/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l3).Pt()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "LLL")) { + signalLooseLimit[cf_trigger::kLLL] += 1; + registryTriggerQA.fill(HIST("LLL/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LLL/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LLL/loose/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("LLL/loose/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LLL/loose/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("LLL/loose/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l3).Pt()); + if (q3 < TriggerSelections.limits->get("Tight Limit", "LLL")) { + signalTightLimit[cf_trigger::kLLL] += 1; + registryTriggerQA.fill(HIST("LLL/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LLL/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LLL/tight/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("LLL/tight/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LLL/tight/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l2).Pt()); + registryTriggerQA.fill(HIST("LLL/tight/fLambdaQ3VsPt"), q3, vecAntiLambda.at(l3).Pt()); } } } } } - 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)); + registryTriggerQA.fill(HIST("PPPhi/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPPhi/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPPhi/all/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPPhi/all/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/all/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPPhi/all/fPhiQ3VsPt"), q3, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/all/fPhiQ3VsInvMass"), q3, vecPhi.at(phi1).M()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPPhi")) { + signalLooseLimit[cf_trigger::kPPPhi] += 1; + registryTriggerQA.fill(HIST("PPPhi/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPPhi/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPPhi/loose/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPPhi/loose/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/loose/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPPhi/loose/fPhiQ3VsPt"), q3, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/loose/fPhiQ3VsInvMass"), q3, vecPhi.at(phi1).M()); + 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; + registryTriggerQA.fill(HIST("PPPhi/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPPhi/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPPhi/tight/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPPhi/tight/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/tight/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPPhi/tight/fPhiQ3VsPt"), q3, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/tight/fPhiQ3VsInvMass"), q3, vecPhi.at(phi1).M()); } } } } - 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)); + registryTriggerQA.fill(HIST("PPPhi/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPPhi/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPPhi/all/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPPhi/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPPhi/all/fPhiQ3VsPt"), q3, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/all/fPhiQ3VsInvMass"), q3, vecPhi.at(phi1).M()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPPhi")) { + signalLooseLimit[cf_trigger::kPPPhi] += 1; + registryTriggerQA.fill(HIST("PPPhi/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPPhi/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPPhi/loose/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPPhi/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPPhi/loose/fPhiQ3VsPt"), q3, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/loose/fPhiQ3VsInvMass"), q3, vecPhi.at(phi1).M()); + 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; + registryTriggerQA.fill(HIST("PPPhi/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPPhi/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPPhi/tight/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPPhi/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPPhi/tight/fPhiQ3VsPt"), q3, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PPPhi/tight/fPhiQ3VsInvMass"), q3, vecPhi.at(phi1).M()); } } } } } - 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)); + registryTriggerQA.fill(HIST("PPRho/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPRho/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPRho/all/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPRho/all/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPRho/all/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPRho/all/fRhoQ3VsPt"), q3, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("PPRho/all/fRhoQ3VsInvMass"), q3, vecRho.at(r1).M()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPRho")) { + signalLooseLimit[cf_trigger::kPPRho] += 1; + registryTriggerQA.fill(HIST("PPRho/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPRho/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPRho/loose/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPRho/loose/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPRho/loose/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPRho/loose/fRhoQ3VsPt"), q3, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("PPRho/loose/fRhoQ3VsInvMass"), q3, vecRho.at(r1).M()); + 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; + registryTriggerQA.fill(HIST("PPRho/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPRho/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPRho/tight/fSE_particle"), q3); + registryTriggerQA.fill(HIST("PPRho/tight/fProtonQ3VsPt"), q3, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPRho/tight/fProtonQ3VsPt"), q3, vecProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPRho/tight/fRhoQ3VsPt"), q3, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("PPRho/tight/fRhoQ3VsInvMass"), q3, vecRho.at(r1).M()); } } } } - - 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)); + registryTriggerQA.fill(HIST("PPRho/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPRho/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPRho/all/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPRho/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPRho/all/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPRho/all/fRhoQ3VsPt"), q3, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("PPRho/all/fRhoQ3VsInvMass"), q3, vecRho.at(r1).M()); + if (q3 < TriggerSelections.limits->get("Loose Limit", "PPRho")) { + signalLooseLimit[cf_trigger::kPPRho] += 1; + registryTriggerQA.fill(HIST("PPRho/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPRho/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPRho/loose/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPRho/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPRho/loose/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPRho/loose/fRhoQ3VsPt"), q3, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("PPRho/loose/fRhoQ3VsInvMass"), q3, vecRho.at(r1).M()); + 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; + registryTriggerQA.fill(HIST("PPRho/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PPRho/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PPRho/tight/fSE_antiparticle"), q3); + registryTriggerQA.fill(HIST("PPRho/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PPRho/tight/fAntiProtonQ3VsPt"), q3, vecAntiProton.at(p2).Pt()); + registryTriggerQA.fill(HIST("PPRho/tight/fRhoQ3VsPt"), q3, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("PPRho/tight/fRhoQ3VsInvMass"), q3, vecRho.at(r1).M()); } } } } } - 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)); + registryTriggerQA.fill(HIST("PD/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PD/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PD/all/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("PD/all/fProtonKstarVsPt"), kstar, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PD/all/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + if (kstar < TriggerSelections.limits->get("Loose Limit", "PD")) { + signalLooseLimit[cf_trigger::kPD] += 1; + registryTriggerQA.fill(HIST("PD/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PD/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PD/loose/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("PD/loose/fProtonKstarVsPt"), kstar, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PD/loose/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + if (kstar < TriggerSelections.limits->get("Tight Limit", "PD")) { + signalTightLimit[cf_trigger::kPD] += 1; + registryTriggerQA.fill(HIST("PD/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PD/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PD/tight/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("PD/tight/fProtonKstarVsPt"), kstar, vecProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PD/tight/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); } } } - 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)); + registryTriggerQA.fill(HIST("PD/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PD/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PD/all/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("PD/all/fAntiProtonKstarVsPt"), kstar, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PD/all/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + if (kstar < TriggerSelections.limits->get("Loose Limit", "PD")) { + signalLooseLimit[cf_trigger::kPD] += 1; + registryTriggerQA.fill(HIST("PD/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PD/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PD/loose/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("PD/loose/fAntiProtonKstarVsPt"), kstar, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PD/loose/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + if (kstar < TriggerSelections.limits->get("Tight Limit", "PD")) { + signalTightLimit[cf_trigger::kPD] += 1; + registryTriggerQA.fill(HIST("PD/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PD/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PD/tight/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("PD/tight/fAntiProtonKstarVsPt"), kstar, vecAntiProton.at(p1).Pt()); + registryTriggerQA.fill(HIST("PD/tight/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); } } } } - } // 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)); + registryTriggerQA.fill(HIST("LD/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LD/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LD/all/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("LD/all/fLambdaKstarVsPt"), kstar, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LD/all/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + if (kstar < TriggerSelections.limits->get("Loose Limit", "LD")) { + signalLooseLimit[cf_trigger::kLD] += 1; + registryTriggerQA.fill(HIST("LD/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LD/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LD/loose/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("LD/loose/fLambdaKstarVsPt"), kstar, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LD/loose/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + if (kstar < TriggerSelections.limits->get("Tight Limit", "LD")) { + signalTightLimit[cf_trigger::kLD] += 1; + registryTriggerQA.fill(HIST("LD/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LD/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LD/tight/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("LD/tight/fLambdaKstarVsPt"), kstar, vecLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LD/tight/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + } + } + } + } + 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)); + registryTriggerQA.fill(HIST("LD/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LD/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LD/all/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("LD/all/fAntiLambdaKstarVsPt"), kstar, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LD/all/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + if (kstar < TriggerSelections.limits->get("Loose Limit", "LD")) { + signalLooseLimit[cf_trigger::kLD] += 1; + registryTriggerQA.fill(HIST("LD/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LD/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LD/loose/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("LD/loose/fAntiLambdaKstarVsPt"), kstar, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LD/loose/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + if (kstar < TriggerSelections.limits->get("Tight Limit", "LD")) { + signalTightLimit[cf_trigger::kLD] += 1; + registryTriggerQA.fill(HIST("LD/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("LD/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("LD/tight/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("LD/tight/fAntiLambdaKstarVsPt"), kstar, vecAntiLambda.at(l1).Pt()); + registryTriggerQA.fill(HIST("LD/tight/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + } + } + } + } } - 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)); + registryTriggerQA.fill(HIST("PhiD/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PhiD/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PhiD/all/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("PhiD/all/fPhiKstarVsPt"), kstar, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PhiD/all/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("PhiD/all/fPhiKstarVsInvMass"), kstar, vecPhi.at(phi1).M()); + if (kstar < TriggerSelections.limits->get("Loose Limit", "PhiD")) { + signalLooseLimit[cf_trigger::kPhiD] += 1; + registryTriggerQA.fill(HIST("PhiD/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PhiD/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PhiD/loose/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("PhiD/loose/fPhiKstarVsPt"), kstar, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PhiD/loose/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("PhiD/loose/fPhiKstarVsInvMass"), kstar, vecPhi.at(phi1).M()); + 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; + registryTriggerQA.fill(HIST("PhiD/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PhiD/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PhiD/tight/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("PhiD/tight/fPhiKstarVsPt"), kstar, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PhiD/tight/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("PhiD/tight/fPhiKstarVsInvMass"), kstar, vecPhi.at(phi1).M()); + } + } + } + } + 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)); + registryTriggerQA.fill(HIST("PhiD/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PhiD/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PhiD/all/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("PhiD/all/fPhiKstarVsPt"), kstar, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PhiD/all/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("PhiD/all/fPhiKstarVsInvMass"), kstar, vecPhi.at(phi1).M()); + if (kstar < TriggerSelections.limits->get("Loose Limit", "PhiD")) { + signalLooseLimit[cf_trigger::kPhiD] += 1; + registryTriggerQA.fill(HIST("PhiD/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PhiD/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PhiD/loose/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("PhiD/loose/fPhiKstarVsPt"), kstar, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PhiD/loose/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("PhiD/loose/fPhiKstarVsInvMass"), kstar, vecPhi.at(phi1).M()); + 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; + registryTriggerQA.fill(HIST("PhiD/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("PhiD/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("PhiD/tight/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("PhiD/tight/fPhiKstarVsPt"), kstar, vecPhi.at(phi1).Pt()); + registryTriggerQA.fill(HIST("PhiD/tight/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("PhiD/tight/fPhiKstarVsInvMass"), kstar, vecPhi.at(phi1).M()); + } + } + } + } } - 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)); + registryTriggerQA.fill(HIST("RhoD/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("RhoD/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("RhoD/all/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("RhoD/all/fRhoKstarVsPt"), kstar, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("RhoD/all/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("RhoD/all/fRhoKstarVsInvMass"), kstar, vecRho.at(r1).M()); + if (kstar < TriggerSelections.limits->get("Loose Limit", "RhoD")) { + signalLooseLimit[cf_trigger::kRhoD] += 1; + registryTriggerQA.fill(HIST("RhoD/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("RhoD/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("RhoD/loose/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("RhoD/loose/fRhoKstarVsPt"), kstar, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("RhoD/loose/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("RhoD/loose/fRhoKstarVsInvMass"), kstar, vecRho.at(r1).M()); + 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; + registryTriggerQA.fill(HIST("RhoD/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("RhoD/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("RhoD/tight/fSE_particle"), kstar); + registryTriggerQA.fill(HIST("RhoD/tight/fRhoKstarVsPt"), kstar, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("RhoD/tight/fDeuteronKstarVsPt"), kstar, vecDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("RhoD/tight/fRhoKstarVsInvMass"), kstar, vecRho.at(r1).M()); + } + } + } + } + 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)); + registryTriggerQA.fill(HIST("RhoD/all/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("RhoD/all/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("RhoD/all/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("RhoD/all/fRhoKstarVsPt"), kstar, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("RhoD/all/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("RhoD/all/fRhoKstarVsInvMass"), kstar, vecRho.at(r1).M()); + if (kstar < TriggerSelections.limits->get("Loose Limit", "RhoD")) { + signalLooseLimit[cf_trigger::kRhoD] += 1; + registryTriggerQA.fill(HIST("RhoD/loose/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("RhoD/loose/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("RhoD/loose/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("RhoD/loose/fRhoKstarVsPt"), kstar, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("RhoD/loose/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("RhoD/loose/fRhoKstarVsInvMass"), kstar, vecRho.at(r1).M()); + 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; + registryTriggerQA.fill(HIST("RhoD/tight/fMultiplicity"), col.multNTracksPV()); + registryTriggerQA.fill(HIST("RhoD/tight/fZvtx"), col.posZ()); + registryTriggerQA.fill(HIST("RhoD/tight/fSE_antiparticle"), kstar); + registryTriggerQA.fill(HIST("RhoD/tight/fRhoKstarVsPt"), kstar, vecRho.at(r1).Pt()); + registryTriggerQA.fill(HIST("RhoD/tight/fAntiDeuteronKstarVsPt"), kstar, vecAntiDeuteron.at(d1).Pt()); + registryTriggerQA.fill(HIST("RhoD/tight/fRhoKstarVsInvMass"), kstar, vecRho.at(r1).M()); + } + } + } + } } - // 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) { + registryTriggerQA.fill(HIST("fProcessedEvents"), 3 + 2 * i); // need offset for filling + keepEventLooseLimit[i] = true; + } + if (signalTightLimit[i] > 0) { + registryTriggerQA.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]) { + registryTriggerQA.fill(HIST("fTriggerCorrelations"), 2 * i, 2 * j); + } + if (signalLooseLimit[i] > 0 && signalTightLimit[j]) { // only one combination needed, fill only entries above diagonal + registryTriggerQA.fill(HIST("fTriggerCorrelations"), 2 * i, 2 * j + 1); + } + if (signalTightLimit[i] > 0 && signalTightLimit[j]) { + registryTriggerQA.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 (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]) { + registryTriggerQA.fill(HIST("fProcessedEvents"), 1); + } - if (!keepEvent3N[CFTrigger::kPPP] && !keepEvent3N[CFTrigger::kPPL] && !keepEvent3N[CFTrigger::kPLL] && !keepEvent3N[CFTrigger::kLLL] && - !keepEvent2N[CFTrigger::kPD] && !keepEvent2N[CFTrigger::kLD]) { - 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]) { + registryTriggerQA.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 deleted file mode 100644 index 623b5cb9086..00000000000 --- a/EventFiltering/PWGCF/CFFilterPPPhi.cxx +++ /dev/null @@ -1,543 +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 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/PWGCF/CFFilterQA.cxx b/EventFiltering/PWGCF/CFFilterQA.cxx deleted file mode 100644 index 70e80b74e78..00000000000 --- a/EventFiltering/PWGCF/CFFilterQA.cxx +++ /dev/null @@ -1,1726 +0,0 @@ -// 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 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 - -#include "../filterTables.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 "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGCF/DataModel/FemtoDerived.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -namespace CFTrigger -{ -// enums -enum CFThreeBodyTriggers { kPPP, - kPPL, - kPLL, - kLLL, - kNThreeBodyTriggers }; -enum CFTwoBodyTriggers { kPP, - kPL, - kNTwoBodyTriggers -}; -enum ParticleSpecies { - kProton, - kDeuteron, - kLambda, - kNParticleSpecies -}; -enum V0Daughters { - kDaughPion, - kDaughProton, - kNV0Daughters -}; -enum ParticleRejection { kRejProton, - kRejPion, - kRejElectron, - kNParticleRejection -}; -enum PIDLimits { kTPCMin, - kTPCMax, - kTOFMin, - kTOFMax, - kTPCTOF, - kNPIDLimits -}; - -// For configurable tables -static const std::vector CFTriggerNamesALL{"ppp", "ppL", "pLL", "LLL", "pp", "pL"}; -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", "Pt max", "P thres"}; -static const std::vector ThreeBodyFilterNames{"PPP", "PPL", "PLL", "LLL"}; -static const std::vector TwoBodyFilterNames{"pp", "pL"}; - -static const int nPidRejection = 2; -static const int nTracks = 2; -static const int nPidAvg = 4; -static const int nPidCutsDaughers = 2; -static const int nPtCuts = 3; -static const int nAllTriggers = 6; - -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 float 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.75f}, - {0.35f, 1.6f, 99.f}, - {0.35f, 6.f, 99.f}}; -static const float NClustersMin[1][nTracks]{ - {60.0f, 60.0f}}; - -static const float triggerSwitches[1][kNThreeBodyTriggers]{ - {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}}; -} // namespace CFTrigger - -namespace o2::aod -{ -using FemtoFullCollision = - soa::Join::iterator; - -using FemtoFullTracks = - soa::Join; -} // namespace o2::aod - -struct CFFilterQA { - - Produces outputCollision; - Produces outputParts; - - Service ccdb; - o2::ccdb::CcdbApi ccdbApi; - - // 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 ConfAutocorRejection{ - "ConfAutocorRejection", - true, - "Rejection autocorrelation pL pairs"}; - - Configurable ConfCutBitPart{ - "ConfCutBitPart", - 8190, - "Cutbit for particle (charge +1)"}; - Configurable ConfCutBitAntiPart{ - "ConfCutBitAntiPart", - 8189, - "Cutbit for antiparticle"}; - Configurable ConfCutBitV0{ - "ConfCutBitV0", - 8190, - "Cutbit for V0 "}; - Configurable ConfCutBitAntiV0{ - "ConfCutBitAntiV0", - 8190, - "Cutbit for Anti V0 "}; - Configurable ConfPidBitProton{ - "ConfPidBitProton", - 1, - "Pidbit for Proton"}; - Configurable ConfPidBitV0{ - "ConfPidBitV0", - 1, - "Pidbit for V0"}; - Configurable ConfKeepAllSelectedParticles{ - "ConfKeepAllSelectedParticles", - true, - "Switch to keep all particles, not only the ones in triggered events"}; - // 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", - 0, - "Minimum number of ITS clusters"}; - Configurable ConfTrkITSnclsIbMin{ - "ConfTrkITSnclsIbMin", - 0, - "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> ConfPtCuts{ - "ConfPtCuts", - {CFTrigger::ptcutsTable[0], CFTrigger::kNParticleRejection, CFTrigger::nPtCuts, CFTrigger::SpeciesNameAll, CFTrigger::PtCutsName}, - "Particle Momentum selections"}; - 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"}; - - // 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"}; - - // 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"}; - - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - // HistogramRegistry registryQA{"registryQA", {}, OutputObjHandlingPolicy::AnalysisObject}; - - std::vector BBProton, BBAntiproton, BBDeuteron, BBAntideuteron, BBPion, BBAntipion, BBElectron, BBAntielectron, TPCTOFAvg; - void init(o2::framework::InitContext&) - { - - // 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")}; - } - - registry.add("fProcessedEvents", "CF - event filtered;;Events", HistType::kTH1F, {{8, -0.5, 7.5}}); - std::vector eventTitles = {"all", "accepted", "ppp", "ppL", "pLL", "LLL", "pp", "pL"}; - 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}}); - - // 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()}}); - - // 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}}}); - - // 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/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}}}); - - // 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/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}}); - - // antiproton - registry.add("TrackCuts/AntiProton/fPtAntiProton", "Transverse momentum of all processed tracks", HistType::kTH1F, {{1000, 0, 10}}); - registry.add("TrackCuts/AntiProton/fEtaAntiProton", "Pseudorapidity of all processed tracks", HistType::kTH1F, {{1000, -2, 2}}); - registry.add("TrackCuts/AntiProton/fPhiAntiProton", "Azimuthal angle of all processed tracks", HistType::kTH1F, {{720, 0, TMath::TwoPi()}}); - registry.add("TrackCuts/AntiProton/fNsigmaTPCvsPAntiProton", "NSigmaTPC AntiProton", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiProton/fNsigmaTOFvsPAntiProton", "NSigmaTOF AntiProton", {HistType::kTH2F, {{100, 0.0f, 10.0f}, {100, -10.f, 10.f}}}); - registry.add("TrackCuts/AntiProton/fNsigmaTPCTOFvsPAntiProton", "NSigmaTPCTOF AntiProton", {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}}); - - // 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("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_antiparticle", "Same Event distribution", HistType::kTH1F, {{8000, 0, 8}}); - - // 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_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - - // 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_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - - // for pll - 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_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - - // for pp - registry.add("pp/fMultiplicity", "Multiplicity of all processed events;Mult;Entries", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("pp/fZvtx", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("pp/fSE_particle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pp/fSE_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - - // for pl - registry.add("pl/fMultiplicity", "Multiplicity of all processed events", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("pl/fZvtx", "Zvtx of all processed events;Z_{vtx};Entries", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("pl/fSE_particle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("pl/fSE_antiparticle", "Same Event distribution;SE;Q_{3} (GeV/c)", HistType::kTH1F, {{8000, 0, 8}}); - } - - 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; - - 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 isSelectedTrack(T const& track, CFTrigger::ParticleSpecies partSpecies) - { - const auto pT = track.pt(); - 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 (pT < ConfPtCuts->get(partSpecies, "Pt min")) { - return false; - } - if (pT > ConfPtCuts->get(partSpecies, "Pt max")) { - return false; - } - if (std::abs(eta) > ConfTrkEta) { - return false; - } - if (tpcNClsF < ConfTPCNClustersMin->get("TPCNClusMin", partSpecies)) { - return false; - } - if (tpcRClsC < ConfTrkTPCfCls) { - return false; - } - if (tpcNClsC < ConfTrkTPCcRowsMin) { - return false; - } - if (tpcNClsS > ConfTrkTPCsClsMax) { - return false; - } - if (itsNCls < ConfTrkITSnclsMin) { - return false; - } - if (itsNClsIB < ConfTrkITSnclsIbMin) { - return false; - } - if (std::abs(dcaXY) > ConfTrkDCAxyMax) { - return false; - } - if (std::abs(dcaZ) > ConfTrkDCAzMax) { - return false; - } - // TODO: which dca, put dcaxy for now - if (ConfRejectNotPropagatedTracks && std::abs(dcaXY) > 1e3) { - return false; - } - if (ConfTrkRequireChi2MaxTPC && track.tpcChi2NCl() >= ConfTrkMaxChi2PerClusterTPC) { - return false; - } - if (ConfTrkRequireChi2MaxITS && track.itsChi2NCl() >= ConfTrkMaxChi2PerClusterITS) { - return false; - } - if (ConfTrkTPCRefit && !track.hasTPC()) { - return false; - } - if (ConfTrkITSRefit && !track.hasITS()) { - return false; - } - return true; - } - - template - bool isSelectedV0Daughter(T const& track, float charge, CFTrigger::V0Daughters species, double nSigmaTPCDaug[2]) - { - const auto eta = track.eta(); - const auto tpcNClsF = track.tpcNClsFound(); - const auto dcaXY = track.dcaXY(); - 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(dcaXY) < ConfDaughDCAMin) { - return false; - } - - 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 (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 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; - } - } 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)) { - return false; - } - } - return isSelected; - } - - template - bool isSelectedMinimalV0(C const& /*col*/, V const& v0, T const& posTrack, - T const& negTrack, float charge, double nSigmaTPCPos[2], double nSigmaTPCNeg[2]) - { - 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"; - } - 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)) { - return false; - } - if (charge < 0 && (invMassAntiLambda < ConfV0InvMassLowLimit || invMassAntiLambda > ConfV0InvMassUpLimit)) { - return false; - } - if (ConfV0RejectKaons) { - const float invMassKaon = v0.mK0Short(); - if (invMassKaon > ConfV0InvKaonMassLowLimit && invMassKaon < ConfV0InvKaonMassUpLimit) { - 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; - } - for (size_t i = 0; i < decVtx.size(); i++) { - if (decVtx.at(i) > ConfV0DecVtxMax) { - return false; - } - } - if (charge > 0) { - if (!isSelectedV0Daughter(posTrack, 1, CFTrigger::kDaughProton, nSigmaTPCPos)) { - return false; - } - if (!isSelectedV0Daughter(negTrack, -1, CFTrigger::kDaughPion, nSigmaTPCNeg)) { - return false; - } - } - if (charge < 0) { - if (!isSelectedV0Daughter(posTrack, 1, CFTrigger::kDaughPion, nSigmaTPCPos)) { - return false; - } - if (!isSelectedV0Daughter(negTrack, -1, CFTrigger::kDaughProton, nSigmaTPCNeg)) { - 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 sqrt(-Q32); - } - - std::vector setValuesBB(aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) - { - 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) - { - 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); - } - - void process(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, aod::FemtoFullTracks const& tracks, o2::aod::V0Datas const& fullV0s) - { - - if (!ConfIsRun3) { - LOG(fatal) << "Run 2 processing is not implemented!"; - } - 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); - } - if (ConfUseManualPIDdeuteron) { - BBDeuteron = setValuesBB(bc, ConfPIDBBDeuteron); - BBAntideuteron = setValuesBB(bc, ConfPIDBBAntiDeuteron); - } - if (ConfUseManualPIDpion || ConfUseManualPIDdaughterPion) { - BBPion = setValuesBB(bc, ConfPIDBBPion); - BBAntipion = setValuesBB(bc, ConfPIDBBAntiPion); - } - if (ConfUseManualPIDpion) { - BBElectron = setValuesBB(bc, ConfPIDBBElectron); - BBAntielectron = setValuesBB(bc, ConfPIDBBAntiElectron); - } - if (ConfUseAvgFromCCDB) { - TPCTOFAvg = setValuesAvg(bc, ConfAvgPath); - } - lastRunNumber = currentRunNumber; - } - } - - registry.fill(HIST("fProcessedEvents"), 0); - registry.fill(HIST("EventCuts/fMultiplicityBefore"), col.multNTracksPV()); - registry.fill(HIST("EventCuts/fZvtxBefore"), col.posZ()); - - bool keepEvent3N[CFTrigger::kNThreeBodyTriggers] = {false, false, false, false}; - int lowQ3Triplets[CFTrigger::kNThreeBodyTriggers] = {0, 0, 0, 0}; - - bool keepEvent2N[CFTrigger::kNTwoBodyTriggers] = {false, false}; - int lowKstarPairs[CFTrigger::kNTwoBodyTriggers] = {0, 0}; - - std::vector childIDs = {0, 0}; - - // keep track of proton indices - std::vector ProtonIndex = {}; - std::vector AntiProtonIndex = {}; - - // keep track of daugher indices to avoid selfcorrelations - std::vector LambdaPosDaughIndex = {}; - std::vector LambdaNegDaughIndex = {}; - std::vector AntiLambdaPosDaughIndex = {}; - std::vector AntiLambdaNegDaughIndex = {}; - - // Prepare vectors for different species - std::vector protons, antiprotons, deuterons, antideuterons, lambdas, antilambdas; - - if (isSelectedEvent(col)) { - - registry.fill(HIST("EventCuts/fMultiplicityAfter"), col.multNTracksPV()); - registry.fill(HIST("EventCuts/fZvtxAfter"), col.posZ()); - - // create deuteron and proton vectors (and corresponding antiparticles) for pair and triplet creation - for (auto& track : tracks) { - - double nTPCSigmaP[2]{track.tpcNSigmaPr(), track.tpcNSigmaDe()}; - double nTPCSigmaN[2]{track.tpcNSigmaPr(), track.tpcNSigmaDe()}; - - 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); - } - - 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/TracksBefore/fMomCorrelationPos"), track.p(), track.tpcInnerParam()); - } - 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))); - } - - // 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/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/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()); - } - } - } - - 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]); - } - } - 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); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPPP)) { - lowQ3Triplets[CFTrigger::kPPP] += 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); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPPP)) { - lowQ3Triplets[CFTrigger::kPPP] += 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); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPPL)) { - lowQ3Triplets[CFTrigger::kPPL] += 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); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPPL)) { - lowQ3Triplets[CFTrigger::kPPL] += 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))) { - 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); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPLL)) { - lowQ3Triplets[CFTrigger::kPLL] += 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))) { - 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); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kPLL)) { - lowQ3Triplets[CFTrigger::kPLL] += 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))) { - 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); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kLLL)) { - lowQ3Triplets[CFTrigger::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))) { - 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); - if (Q3 < ConfQ3Limits->get(static_cast(0), CFTrigger::kLLL)) { - lowQ3Triplets[CFTrigger::kLLL] += 1; - } - } - } - } - } - if (ConfTriggerSwitches->get("Switch", "pp") > 0.) { - // pp trigger - for (auto iProton1 = protons.begin(); iProton1 != protons.end(); ++iProton1) { - auto iProton2 = iProton1 + 1; - for (; iProton2 != protons.end(); ++iProton2) { - kstar = getkstar(*iProton1, *iProton2); - registry.fill(HIST("pp/fSE_particle"), kstar); - if (kstar < ConfKstarLimits->get(static_cast(0), CFTrigger::kPP)) { - lowKstarPairs[CFTrigger::kPP] += 1; - } - } - } - for (auto iAntiProton1 = antiprotons.begin(); iAntiProton1 != antiprotons.end(); ++iAntiProton1) { - auto iAntiProton2 = iAntiProton1 + 1; - for (; iAntiProton2 != antiprotons.end(); ++iAntiProton2) { - kstar = getkstar(*iAntiProton1, *iAntiProton2); - registry.fill(HIST("pp/fSE_antiparticle"), kstar); - if (kstar < ConfKstarLimits->get(static_cast(0), CFTrigger::kPP)) { - lowKstarPairs[CFTrigger::kPP] += 1; - } - } - } - } - if (ConfTriggerSwitches->get("Switch", "pL") > 0.) { - // pL trigger - for (auto iProton = protons.begin(); iProton != protons.end(); ++iProton) { - auto i1 = std::distance(protons.begin(), iProton); - for (auto iLambda = lambdas.begin(); iLambda != lambdas.end(); ++iLambda) { - auto i2 = std::distance(lambdas.begin(), iLambda); - if (ConfAutocorRejection.value && - ProtonIndex.at(i1) == LambdaPosDaughIndex.at(i2)) { - continue; - } - kstar = getkstar(*iProton, *iLambda); - if (kstar < ConfKstarLimits->get(static_cast(0), CFTrigger::kPL)) { - registry.fill(HIST("pl/fSE_particle"), kstar); - lowKstarPairs[CFTrigger::kPL] += 1; - } - } - } - for (auto iAntiProton = antiprotons.begin(); iAntiProton != antiprotons.end(); ++iAntiProton) { - auto i1 = std::distance(antiprotons.begin(), iAntiProton); - for (auto iAntiLambda = antilambdas.begin(); iAntiLambda != antilambdas.end(); ++iAntiLambda) { - auto i2 = std::distance(antilambdas.begin(), iAntiLambda); - if (ConfAutocorRejection.value && - AntiProtonIndex.at(i1) == AntiLambdaNegDaughIndex.at(i2)) { - continue; - } - kstar = getkstar(*iAntiProton, *iAntiLambda); - if (kstar < ConfKstarLimits->get(static_cast(0), CFTrigger::kPL)) { - registry.fill(HIST("pl/fSE_antiparticle"), kstar); - lowKstarPairs[CFTrigger::kPL] += 1; - } - } - } - } - - // 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()); - } - 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()); - } - 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()); - } - // create tags for two body triggers - if (lowKstarPairs[CFTrigger::kPP] > 0) { - keepEvent2N[CFTrigger::kPP] = true; - registry.fill(HIST("fProcessedEvents"), 6); - registry.fill(HIST("pp/fMultiplicity"), col.multNTracksPV()); - registry.fill(HIST("pp/fZvtx"), col.posZ()); - } - if (lowKstarPairs[CFTrigger::kPL] > 0) { - keepEvent2N[CFTrigger::kPL] = true; - registry.fill(HIST("fProcessedEvents"), 7); - registry.fill(HIST("pl/fMultiplicity"), col.multNTracksPV()); - registry.fill(HIST("pl/fZvtx"), col.posZ()); - } - - if (ConfKeepAllSelectedParticles.value || - keepEvent3N[CFTrigger::kPPP] || keepEvent3N[CFTrigger::kPPL] || keepEvent3N[CFTrigger::kPLL] || keepEvent3N[CFTrigger::kLLL] || - keepEvent2N[CFTrigger::kPP] || keepEvent2N[CFTrigger::kPL]) { - - outputCollision(col.posZ(), col.multFV0M(), col.multNTracksPV(), -2, -2); - - registry.fill(HIST("fProcessedEvents"), 1); - - for (auto proton : protons) { - outputParts(outputCollision.lastIndex(), - proton.pt(), - proton.eta(), - proton.phi(), - aod::femtodreamparticle::ParticleType::kTrack, - static_cast(ConfCutBitPart.value), // cutbit for particle - static_cast(ConfPidBitProton.value), - 0.f, - childIDs, - 0.f, - 0.f); - } - - for (auto antiproton : antiprotons) { - outputParts(outputCollision.lastIndex(), - antiproton.pt(), - antiproton.eta(), - antiproton.phi(), - aod::femtodreamparticle::ParticleType::kTrack, - static_cast(ConfCutBitAntiPart.value), // cutbit for antiparticle - static_cast(ConfPidBitProton.value), - 0.f, - childIDs, - 0.f, - 0.f); - } - - for (auto lambda : lambdas) { - outputParts(outputCollision.lastIndex(), - lambda.pt(), - lambda.eta(), - lambda.phi(), - aod::femtodreamparticle::ParticleType::kV0, - static_cast(ConfCutBitV0.value), - static_cast(ConfPidBitV0.value), - 0.f, - childIDs, - 0.f, - 0.f); - } - - for (auto antilambda : antilambdas) { - outputParts(outputCollision.lastIndex(), - antilambda.pt(), - antilambda.eta(), - antilambda.phi(), - aod::femtodreamparticle::ParticleType::kV0, - static_cast(ConfCutBitAntiV0.value), - static_cast(ConfPidBitV0.value), - 0.f, - childIDs, - 0.f, - 0.f); - } - } - } - } -}; - -WorkflowSpec - defineDataProcessing(ConfigContext const& cfg) -{ - return WorkflowSpec{adaptAnalysisTask(cfg)}; -} diff --git a/EventFiltering/PWGCF/CFFilterTwoN.cxx b/EventFiltering/PWGCF/CFFilterTwoN.cxx deleted file mode 100644 index 2d2b64a1088..00000000000 --- a/EventFiltering/PWGCF/CFFilterTwoN.cxx +++ /dev/null @@ -1,550 +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 CFFilterTwoN.cxx -/// \brief Selection of events with different kind of pairs for femtoscopic studies -/// -/// \author Anton Riedel, TU München, anton.riedel@cern.ch - -#include -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" - -#include "../filterTables.h" -#include "../../PWGCF/FemtoDream/FemtoUtils.h" - -#include "PWGCF/DataModel/FemtoDerived.h" -#include "PWGCF/FemtoDream/FemtoDreamParticleHisto.h" -#include "PWGCF/FemtoDream/FemtoDreamPairCleaner.h" -#include "PWGCF/FemtoDream/FemtoDreamContainer.h" -#include "PWGCF/FemtoDream/FemtoDreamMath.h" -#include "PWGCF/FemtoDream/FemtoDreamPairCleaner.h" -#include "PWGCF/FemtoDream/FemtoDreamDetaDphiStar.h" -#include "PWGCF/FemtoDream/FemtoDreamContainer.h" - -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "CommonConstants/PhysicsConstants.h" - -#include - -namespace -{ - -enum kCFTwoBodyTriggers { - kPD, //=0 - kLD, //=1 - kLAST_CFTwoBodyTriggers -}; - -static const std::vector CfTriggerNames{"kPD", "kLD"}; -static constexpr uint8_t Track = 0; -static constexpr uint8_t V0 = 1; -// static constexpr uint8_t V0Daughter = 2; // V0 daughters - -static constexpr uint32_t kSignMinusMask = 1; -static constexpr uint32_t kSignPlusMask = 2; - -// static constexpr uint32_t knSigmaProton = 48; -static constexpr uint32_t kValue0 = 0; - -} // namespace - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::analysis::femtoDream; - -struct CFFilterTwoN { - SliceCache cache; - - Produces tags; - - Configurable confKstarTriggerLimit{"KstarTriggerLimitUpper", 1.0f, "Kstar limit for selection"}; - Configurable KstarTrigger{"KstarTrigger", 0, "Choice which trigger to run"}; - // 0 for pd - // 1 for ld - // 10 for both - - Configurable confProtonPtMin{"ProtonPtMin", 0.5, "Minimal Pt for Protons"}; - Configurable confProtonPtMax{"ProtonPtMax", 4.05, "Maximal Pt for Protons"}; - Configurable confPIDThreshold{"PThreshold", 0.75f, "P threshold for TPC/TPC&TOF selection (Protons only)"}; - - Configurable confDeuteronPtMin{"DeuteronPtMin", 0.5, "Minimal Pt for Deuterons"}; - Configurable confDeuteronPtMax{"DeuteronPtMax", 1.4, "Maximal Pt for Deuterons"}; - - Configurable confPIDnSigmaTPCAcceptance{"PIDnSigmaTPCPIDAcceptance", - 3., - "nSigmaTPC for accepting Protons and Deuterons (this value needs to be listed in PIDnSgimaTPCMax)"}; - // the value used in this configurable needs to one of the values listed in ConfPIDnSigmaTPCMax! - Configurable confPIDnSigmTPCTOFAcceptance{"PIDnSigmaTPCTOFPIDAcceptance", - 3., - "nSigmaTPCTOF for accepting Protons (this values needs to be listed in PIDnSigmaTPCMax)"}; - // the value used in this configurable needs to one of the values listed in ConfPIDnSigmaTPCMax! - - Configurable> ConfPIDnSigmaTPCMax{"PIDnSigmaTPCMax", - std::vector{3.5f, 3.f, 2.5f}, - "Vector of all possible nSigma values for Acceptance and Rejection (this needs to be in sync with FemtoDreamProducerTask.ConfTrkPIDnSigmaMax)"}; - // this configurable needs to be in sync with FemtoDreamProducerTask.ConfTrkPIDnSigmaMax - // do not use more than 3 values, otherwise the FemtoDreamProducerTask will break! - - Configurable confPIDRejection{"PIDRejection", 3.5, "nSigma for rejection bogus Deuterons (set it to a negative value to disable the rejection)"}; - // the value used in this configurable needs to one of the values listed in ConfPIDnSigmaTPCMax - // set it to a negative value to disable the rejection - - // suggestion for setting ConfTrkTPIDspecies of the FemtoDreamProducerTask - // ConfTrkTPIDspecies = {0, <- Electron PID at Index 0 - // 2, <- Pion PID at Index 1 - // 4, <- Proton PID at Index 2 - // 5} <- Deuteron PID at Index 3 - // total of 4 indices - // will become clear in the following - - Configurable confPIDProtonIndex{"PIDProtonIndex", 2, "Index of Proton PID in ConfTrkTPIDspecies of the FemtoDreamProducerTask"}; - Configurable confPIDDeuteronIndex{"PIDDeuteronIndex", 3, "Index of Deuteron PID in ConfTrkTPIDspecies of the FemtoDreamProducerTask"}; - Configurable confPIDIndexMax{"PIDIndexMax", 4, "Number of Indices in ConfTrkTPIDspecies of the FemtoDreamProducerTask"}; - - Configurable> ConfPIDRejectionSpeciesIndex{"PIDRejectionSpeciesIndex", std::vector{0, 1, 2}, "Indices of the particles we want to reject from the Deuteron signal"}; - // when configuring the FemtoDreamProducerTask, select for ConfTrkTPIDspecies at least Protons (=4) and Deuterons (=5) - // for the rejection to work properly also select electron (=0) and pions (=2) - // suppose the FemtoDreamProducerTask is configured as above - // and we want to rejection electrons (at index 0), pions (at index 1) and proton (at index 2) - // set this configurable to PIDRejectionSpeciesIndex = {1,2,3} - - Configurable ConfClosePairRejection{"ClosePairRejection", true, "Reject close pairs or not"}; - Configurable - ldeltaPhiMax{"ldeltaPhiMax", 0.010, "Max limit of delta phi"}; - Configurable ldeltaEtaMax{"ldeltaEtaMax", 0.010, "Max limit of delta eta"}; - - // obtain particle candidates of protons, deuterons as well as antiprotons and antideuterons - Partition partPD = (o2::aod::femtodreamparticle::partType == Track) && - ((o2::aod::femtodreamparticle::cut & kSignPlusMask) > kValue0); - Partition partAntiPD = (o2::aod::femtodreamparticle::partType == Track) && - ((o2::aod::femtodreamparticle::cut & kSignMinusMask) > kValue0); - // obtain lambdas and antilambdas - Partition partL = (o2::aod::femtodreamparticle::partType == V0) && - ((o2::aod::femtodreamparticle::cut & kSignPlusMask) > kValue0); - Partition partAntiL = (o2::aod::femtodreamparticle::partType == V0) && - ((o2::aod::femtodreamparticle::cut & kSignMinusMask) > kValue0); - - Preslice perCol = aod::femtodreamparticle::femtoDreamCollisionId; - - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry registryQA{"registryQA", {}, OutputObjHandlingPolicy::AnalysisObject}; - - // containers for close pair rejection - FemtoDreamDetaDphiStar closePairRejectionTT; - FemtoDreamDetaDphiStar closePairRejectionTV0; - - bool SelectParticlePID(aod::femtodreamparticle::cutContainerType const& pidCut, int vSpecies, float momentum) - { - bool pidSelection = false; - bool rejectDeuteron = false; - if (vSpecies == o2::track::PID::Proton) { - // use momentum dependend (TPC or TPC&TOF) pid selection for protons - pidSelection = isFullPIDSelected(pidCut, - momentum, - confPIDThreshold.value, - std::vector{confPIDProtonIndex.value}, - confPIDIndexMax.value, - ConfPIDnSigmaTPCMax.value, - confPIDnSigmaTPCAcceptance.value, - confPIDnSigmTPCTOFAcceptance.value); - } else if (vSpecies == o2::track::PID::Deuteron) { - // use additional rejection for deuterons - if (confPIDRejection.value > 0.) { - for (auto rejectSpecies : ConfPIDRejectionSpeciesIndex.value) { - // if the PID is selected for another particle species, reject this candidate - rejectDeuteron = isPIDSelected(pidCut, std::vector{rejectSpecies}, - confPIDIndexMax.value, - confPIDRejection.value, - ConfPIDnSigmaTPCMax.value, - kDetector::kTPC); - // if a deuteron candidate is found which could also be another particle we want to reject, break out of the loop - if (rejectDeuteron) { - break; - } - } - } - // and reject the candidate, otherwise check if it is fullfills the deuteron hypothesis - if (!rejectDeuteron) { - pidSelection = isPIDSelected(pidCut, - std::vector{confPIDDeuteronIndex.value}, - confPIDIndexMax.value, - confPIDnSigmaTPCAcceptance.value, - ConfPIDnSigmaTPCMax.value, - kDetector::kTPC); - } - } else { - LOG(fatal) << "Other PID selections are not supported by this trigger" << std::endl; - } - return pidSelection; - } - - void - init(o2::framework::InitContext&) - { - registry.add("fProcessedEvents", "CF Two Body - event filtered;;events}", HistType::kTH1F, {{2 + kLAST_CFTwoBodyTriggers, 0, 2 + kLAST_CFTwoBodyTriggers}}); - - std::array eventTitles = {"all", "rejected", "p-d", "l-d"}; - for (size_t iBin = 0; iBin < eventTitles.size(); iBin++) { - registry.get(HIST("fProcessedEvents"))->GetXaxis()->SetBinLabel(iBin + 1, eventTitles[iBin].data()); - } - - registry.add("fMultiplicityBefore", "Multiplicity before trigger", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("fMultiplicityAfter", "Multiplicity after trigger", HistType::kTH1F, {{1000, 0, 1000}}); - registry.add("fZvtxBefore", "Zvtx before trigger", HistType::kTH1F, {{1000, -15, 15}}); - registry.add("fZvtxAfter", "Zvtx after trigger", HistType::kTH1F, {{1000, -15, 15}}); - - registry.add("fPtBeforeSel", "Transverse momentum of positive tracks", HistType::kTH1F, {{6000, 0, 6}}); - registry.add("fEtaBeforeSel", "Pseudorapidity of positive tracks", HistType::kTH1F, {{1000, -1, 1}}); - registry.add("fPhiBeforeSel", "Azimuthal angle of positive tracks", HistType::kTH1F, {{1000, 0, TMath::TwoPi()}}); - - registry.add("fPtAntiBeforeSel", "Transverse momentum of negative tracks", HistType::kTH1F, {{6000, 0, 6}}); - registry.add("fEtaAntiBeforeSel", "Pseudorapidity of negative tracks", HistType::kTH1F, {{1000, -1, 1}}); - registry.add("fPhiAntiBeforeSel", "Azimuthal angle of negative tracks", HistType::kTH1F, {{1000, 0, TMath::TwoPi()}}); - - bool plotPerRadii = true; - - if (KstarTrigger.value == 0 || KstarTrigger.value == 10) { - registry.add("fKstarPD", "CF - same event pd distribution for particles;;events", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("fKstarAntiPD", "CF - same event pd distribution for antiparticles;;events", HistType::kTH1F, {{8000, 0, 8}}); - - registry.add("fPtProtonAfterSel", "Transverse momentum of Protons which passed selections", HistType::kTH1F, {{6000, 0, 6}}); - registry.add("fEtaProtonAfterSel", "Pseudorapidity of Protons which passed selections", HistType::kTH1F, {{1000, -1, 1}}); - registry.add("fPhiProtonAfterSel", "Azimuthal angle of Protons which passed selections", HistType::kTH1F, {{1000, 0, TMath::TwoPi()}}); - - registry.add("fPtAntiProtonAfterSel", "Transverse momentum of Protons which passed selections", HistType::kTH1F, {{6000, 0, 6}}); - registry.add("fEtaAntiProtonAfterSel", "Pseudorapidity of AntiProtons which passed selections", HistType::kTH1F, {{1000, -1, 1}}); - registry.add("fPhiAntiProtonAfterSel", "Azimuthal angle of AntiProtons which passed selections", HistType::kTH1F, {{1000, 0, TMath::TwoPi()}}); - - closePairRejectionTT.init(®istry, ®istryQA, ldeltaPhiMax, ldeltaEtaMax, plotPerRadii); - } - - if (KstarTrigger.value == 1 || KstarTrigger.value == 10) { - registry.add("fKstarLD", "CF - same event ld distribution for particles;;events", HistType::kTH1F, {{8000, 0, 8}}); - registry.add("fKstarAntiLD", "CF - same event ld distribution for antiparticles;;events", HistType::kTH1F, {{8000, 0, 8}}); - - registry.add("fPtLambdaAfterSel", "Transverse momentum of Lambdas which passed selections", HistType::kTH1F, {{6000, 0, 6}}); - registry.add("fPtAntiLambdaAfterSel", "Transverse momentum of AntidLambdas which passed selections", HistType::kTH1F, {{6000, 0, 6}}); - - registry.add("fMinvLambda", "Invariant mass of lambdas ", HistType::kTH1F, {{1000, 0.7, 1.5}}); - registry.add("fMinvAntiLambda", "Invariant mass of antilambdas ", HistType::kTH1F, {{1000, 0.7, 1.5}}); - - closePairRejectionTV0.init(®istry, ®istryQA, ldeltaPhiMax, ldeltaEtaMax, plotPerRadii); - } - - registry.add("fPtDeuteronAfterSel", "Transverse momentum of Deuterons which passed selections", HistType::kTH1F, {{6000, 0, 6}}); - registry.add("fEtaDeuteronAfterSel", "Pseudorapidity of Deuterons which passed selections", HistType::kTH1F, {{1000, -1, 1}}); - registry.add("fPhiDeuteronAfterSel", "Azimuthal angle of Deuterons which passed selections", HistType::kTH1F, {{1000, 0, TMath::TwoPi()}}); - - registry.add("fPtAntiDeuteronAfterSel", "Transverse momentum of Antideuterons which passed selections", HistType::kTH1F, {{6000, 0, 6}}); - registry.add("fEtaAntiDeuteronAfterSel", "Pseudorapidity of AntiDeuterons which passed selections", HistType::kTH1F, {{1000, -1, 1}}); - registry.add("fPhiAntiDeuteronAfterSel", "Azimuthal angle of AntiDeuterons which passed selections", HistType::kTH1F, {{1000, 0, TMath::TwoPi()}}); - } - - float mMassProton = TDatabasePDG::Instance()->GetParticle(2212)->Mass(); - float mMassDeuteron = o2::constants::physics::MassDeuteron; - float mMassLambda = TDatabasePDG::Instance()->GetParticle(3122)->Mass(); - - void process(o2::aod::FemtoDreamCollision& col, o2::aod::FemtoDreamParticles& partsFemto) - { - // get partitions of all paritcles and antiparticles - auto partsPD = partPD->sliceByCached(aod::femtodreamparticle::femtoDreamCollisionId, col.globalIndex(), cache); - auto partsAntiPD = partAntiPD->sliceByCached(aod::femtodreamparticle::femtoDreamCollisionId, col.globalIndex(), cache); - - // get partions of V0s - auto partsL = partL->sliceByCached(aod::femtodreamparticle::femtoDreamCollisionId, col.globalIndex(), cache); - auto partsAntiL = partAntiL->sliceByCached(aod::femtodreamparticle::femtoDreamCollisionId, col.globalIndex(), cache); - - // magnetic field is need for close pair rejection - auto magneticField = col.magField(); - - registry.fill(HIST("fProcessedEvents"), 0); - registry.fill(HIST("fMultiplicityBefore"), col.multV0M()); - registry.fill(HIST("fZvtxBefore"), col.posZ()); - - // pass through the particles once to check if there are any particles of interest in the first place - int Nproton = 0; - int Nantiproton = 0; - int Nlambda = 0; - int Nantilambda = 0; - int Ndeuteron = 0; - int Nantideuteron = 0; - - for (auto pd : partsPD) { - registry.fill(HIST("fPtBeforeSel"), pd.pt()); - registry.fill(HIST("fEtaBeforeSel"), pd.eta()); - registry.fill(HIST("fPhiBeforeSel"), pd.phi()); - - // select deuterons - if (SelectParticlePID(pd.pidcut(), o2::track::PID::Deuteron, pd.p()) && - pd.pt() < confDeuteronPtMax.value && - pd.pt() > confDeuteronPtMin.value) { - registry.fill(HIST("fPtDeuteronAfterSel"), pd.pt()); - registry.fill(HIST("fEtaDeuteronAfterSel"), pd.eta()); - registry.fill(HIST("fPhiDeuteronAfterSel"), pd.phi()); - Ndeuteron++; - } - - // select protons - if (KstarTrigger.value == 0 || KstarTrigger.value == 10) { - if (SelectParticlePID(pd.pidcut(), o2::track::PID::Proton, pd.p()) && - pd.pt() < confProtonPtMax.value && - pd.pt() > confProtonPtMin.value) { - registry.fill(HIST("fPtProtonAfterSel"), pd.pt()); - registry.fill(HIST("fEtaProtonAfterSel"), pd.eta()); - registry.fill(HIST("fPhiProtonAfterSel"), pd.phi()); - Nproton++; - } - } - } - - for (auto antipd : partsAntiPD) { - registry.fill(HIST("fPtAntiBeforeSel"), antipd.pt()); - registry.fill(HIST("fEtaAntiBeforeSel"), antipd.eta()); - registry.fill(HIST("fPhiAntiBeforeSel"), antipd.phi()); - - // select antideuterons - if (SelectParticlePID(antipd.pidcut(), o2::track::PID::Deuteron, antipd.p()) && - antipd.pt() < confDeuteronPtMax.value && - antipd.pt() > confDeuteronPtMin.value) { - registry.fill(HIST("fPtAntiDeuteronAfterSel"), antipd.pt()); - registry.fill(HIST("fEtaAntiDeuteronAfterSel"), antipd.eta()); - registry.fill(HIST("fPhiAntiDeuteronAfterSel"), antipd.phi()); - Nantideuteron++; - } - - // select antiprotons - if (KstarTrigger.value == 0 || KstarTrigger.value == 10) { - if (SelectParticlePID(antipd.pidcut(), o2::track::PID::Proton, antipd.p()) && - antipd.pt() < confProtonPtMax.value && - antipd.pt() > confProtonPtMin.value) { - registry.fill(HIST("fPtAntiProtonAfterSel"), antipd.pt()); - registry.fill(HIST("fEtaAntiProtonAfterSel"), antipd.eta()); - registry.fill(HIST("fPhiAntiProtonAfterSel"), antipd.phi()); - Nantiproton++; - } - } - } - - if (KstarTrigger.value == 1 || KstarTrigger.value == 10) { - // select lambdas - for (auto lambda : partsL) { - registry.fill(HIST("fPtLambdaAfterSel"), lambda.pt()); - registry.fill(HIST("fMinvLambda"), lambda.mLambda()); - Nlambda++; - } - for (auto antilambda : partsAntiL) { - // select antilambdas - registry.fill(HIST("fPtAntiLambdaAfterSel"), antilambda.pt()); - registry.fill(HIST("fMinvAntiLambda"), antilambda.mAntiLambda()); - Nantilambda++; - } - } - - bool keepEvent[kLAST_CFTwoBodyTriggers] = {false, false}; - int lowKstarPairs[kLAST_CFTwoBodyTriggers] = {0, 0}; - - bool pdPair = false; - bool dpPair = false; - double kStar = 0.; - - // trigger for pd pairs - if (KstarTrigger.value == 0 || KstarTrigger.value == 10) { - if (Ndeuteron > 0 && Nproton > 0) { - // loop over all unique combinations of particles, excluding the self combinations - for (auto& [p1, p2] : combinations(soa::CombinationsStrictlyUpperIndexPolicy(partsPD, partsPD))) { - - // check if it is a pd pair - // p1 => proton - // p2 => deuteron - if (SelectParticlePID(p1.pidcut(), o2::track::PID::Proton, p1.p()) && - SelectParticlePID(p2.pidcut(), o2::track::PID::Deuteron, p2.p()) && - p1.pt() < confProtonPtMax.value && - p1.pt() > confProtonPtMin.value && - p2.pt() < confDeuteronPtMax.value && - p2.pt() > confDeuteronPtMin.value) { - pdPair = true; - } else { - pdPair = false; - } - - // check if it is dp pair - // p1 => deuteron - // p2 => proton - if (SelectParticlePID(p1.pidcut(), o2::track::PID::Deuteron, p1.p()) && - SelectParticlePID(p2.pidcut(), o2::track::PID::Proton, p2.p()) && - p1.pt() < confDeuteronPtMax.value && - p1.pt() > confDeuteronPtMin.value && - p2.pt() < confProtonPtMax.value && - p2.pt() > confProtonPtMin.value) { - dpPair = true; - } else { - dpPair = false; - } - - // if neither is the case, skip - if (!(pdPair || dpPair)) { - continue; - } - - // reject close pairs - if (ConfClosePairRejection.value && closePairRejectionTT.isClosePair(p1, p2, partsFemto, magneticField)) { - continue; - } - - // compute kstar depending on the pairing - if (pdPair) { - kStar = FemtoDreamMath::getkstar(p1, mMassProton, p2, mMassDeuteron); - } else if (dpPair) { - kStar = FemtoDreamMath::getkstar(p1, mMassDeuteron, p2, mMassProton); - } else { - kStar = confKstarTriggerLimit; - } - // check if the kstar is below threshold - if (kStar < confKstarTriggerLimit.value) { - lowKstarPairs[kPD]++; - registry.fill(HIST("fKstarPD"), kStar); - } - } - } - - if (Nantideuteron > 0 && Nantiproton > 0) { - // loop over all unique combinations of antiparticles, excluding the self combinations - for (auto& [p1, p2] : combinations(soa::CombinationsStrictlyUpperIndexPolicy(partsAntiPD, partsAntiPD))) { - - // check if it is a (anti)pd pair - // p1 => antiproton - // p2 => antideuteron - if (SelectParticlePID(p1.pidcut(), o2::track::PID::Proton, p1.p()) && - SelectParticlePID(p2.pidcut(), o2::track::PID::Deuteron, p2.p()) && - p1.pt() < confProtonPtMax.value && - p1.pt() > confProtonPtMin.value && - p2.pt() < confDeuteronPtMax.value && - p2.pt() > confDeuteronPtMin.value) { - pdPair = true; - } else { - pdPair = false; - } - - // check if it is (anti)dp pair - // p1 => antideuteron - // p2 => antiproton - if (SelectParticlePID(p1.pidcut(), o2::track::PID::Deuteron, p1.p()) && - SelectParticlePID(p2.pidcut(), o2::track::PID::Proton, p2.p()) && - p1.pt() < confDeuteronPtMax.value && - p1.pt() > confDeuteronPtMin.value && - p2.pt() < confProtonPtMax.value && - p2.pt() > confProtonPtMin.value) { - dpPair = true; - } else { - dpPair = false; - } - - // if neither is the case, skip - if (!(pdPair || dpPair)) { - continue; - } - - // reject close pairs - if (ConfClosePairRejection.value && closePairRejectionTT.isClosePair(p1, p2, partsFemto, magneticField)) { - continue; - } - - // compute kstar depending on the pairing - if (pdPair) { - kStar = FemtoDreamMath::getkstar(p1, mMassProton, p2, mMassDeuteron); - } else if (dpPair) { - kStar = FemtoDreamMath::getkstar(p1, mMassDeuteron, p2, mMassProton); - } else { - kStar = confKstarTriggerLimit; - } - - // check if the kstar is below threshold - if (kStar < confKstarTriggerLimit.value) { - lowKstarPairs[kPD]++; - registry.fill(HIST("fKstarAntiPD"), kStar); - } - } - } - } - - // trigger for ld pairs - if (KstarTrigger.value == 1 || KstarTrigger.value == 10) { - if (Ndeuteron > 0 && Nlambda > 0) { - // loop over all unique combinations - for (auto& [p1, p2] : combinations(soa::CombinationsUpperIndexPolicy(partsPD, partsL))) { - // check if the particle is a deuteron - // we do not need to check the V0s - if (!SelectParticlePID(p1.pidcut(), o2::track::PID::Deuteron, p1.p())) { - continue; - } - if (ConfClosePairRejection.value && closePairRejectionTV0.isClosePair(p1, p2, partsFemto, magneticField)) { - continue; - } - kStar = FemtoDreamMath::getkstar(p1, mMassDeuteron, p2, mMassLambda); - // check if kstar is below threshold - if (kStar < confKstarTriggerLimit.value) { - lowKstarPairs[1]++; - registry.fill(HIST("fKstarLD"), kStar); - } - } - } - if (Nantideuteron > 0 && Nantilambda > 0) { - for (auto& [p1, p2] : combinations(soa::CombinationsStrictlyUpperIndexPolicy(partsAntiPD, partsAntiL))) { - // check if the particle is a antideuteron - if (!SelectParticlePID(p1.pidcut(), o2::track::PID::Deuteron, p1.p())) { - continue; - } - if (ConfClosePairRejection.value && closePairRejectionTV0.isClosePair(p1, p2, partsFemto, magneticField)) { - continue; - } - auto kstar = FemtoDreamMath::getkstar(p1, mMassDeuteron, p2, mMassLambda); - // check if kstar is below threshold - if (kStar < confKstarTriggerLimit.value) { - lowKstarPairs[1]++; - registry.fill(HIST("fKstarAntiLD"), kstar); - } - } - } - } - - // if we found any pair below the kstar limit, keep the event - if (lowKstarPairs[kPD] > 0) { - keepEvent[kPD] = true; - registry.fill(HIST("fProcessedEvents"), 2 + kPD); // first two bins are counter of all and rejected events - } - if (lowKstarPairs[kLD] > 0) { - keepEvent[kLD] = true; - registry.fill(HIST("fProcessedEvents"), 2 + kLD); // first two bins are counter of all and rejected events - } - - // fill table for the trigger - tags(keepEvent[kPD], keepEvent[kLD]); - - if (keepEvent[kPD] > 0 || keepEvent[kLD] > 0) { - registry.fill(HIST("fMultiplicityAfter"), col.multV0M()); - registry.fill(HIST("fZvtxAfter"), 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 a254c7245a1..3e88524a89b 100644 --- a/EventFiltering/PWGEM/EMPhotonFilter.cxx +++ b/EventFiltering/PWGEM/EMPhotonFilter.cxx @@ -12,16 +12,19 @@ // \brief software trigger for EM photon // \author daiki.sekihata@cern.ch -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/CaloClusters.h" -#include "DataFormatsPHOS/TriggerRecord.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Common/DataModel/CaloClusters.h" #include "EventFiltering/filterTables.h" + +#include "DataFormatsPHOS/TriggerRecord.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" using namespace o2; using namespace o2::soa; @@ -128,7 +131,7 @@ struct EMPhotonFilter { return false; } - if (track.pt() < minpt || abs(track.eta()) > maxeta) { + if (track.pt() < minpt || std::fabs(track.eta()) > maxeta) { return false; } @@ -158,7 +161,7 @@ struct EMPhotonFilter { 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.); + dca_3d = std::sqrt(std::fabs(chi2) / 2.); } if (dca_3d > dca_3d_sigma_max) { return false; @@ -174,23 +177,23 @@ struct EMPhotonFilter { template void runFilter(TCollisions const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPhotons3 const& /*photons3*/, TV0Legs const&, TDielectrons const& dielectrons, TEMPrimaryElectrons const& /*emprimaryelectrons*/) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { mHistManager.fill(HIST("hEventCounter"), 1.); bool keepEvent[kNtrg]{false}; if (collision.sel8()) { mHistManager.fill(HIST("hEventCounter"), 2.); } - if (abs(collision.posZ()) < 10.f) { + if (std::fabs(collision.posZ()) < 10.f) { mHistManager.fill(HIST("hEventCounter"), 3.); } if (collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { mHistManager.fill(HIST("hEventCounter"), 4.); } - if (collision.sel8() && abs(collision.posZ()) < 10.f) { + if (collision.sel8() && std::fabs(collision.posZ()) < 10.f) { mHistManager.fill(HIST("hEventCounter"), 5.); } - if (collision.sel8() && abs(collision.posZ()) < 10.f && collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (collision.sel8() && std::fabs(collision.posZ()) < 10.f && collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { mHistManager.fill(HIST("hEventCounter"), 6.); } @@ -203,7 +206,7 @@ struct EMPhotonFilter { auto photons1_per_coll = photons1.sliceBy(perCollision_pcm, collision.globalIndex()); auto dielectrons_per_coll = dielectrons.sliceBy(perCollision_ee, collision.globalIndex()); - for (auto& v0photon : photons1_per_coll) { + for (const auto& v0photon : photons1_per_coll) { auto pos_sv = v0photon.template posTrack_as(); auto ele_sv = v0photon.template negTrack_as(); if (!isSelectedSecondary(pos_sv) || !isSelectedSecondary(ele_sv)) { @@ -215,7 +218,7 @@ struct EMPhotonFilter { } } // end of single v0 photon loop - for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_coll, dielectrons_per_coll))) { + for (const auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_coll, dielectrons_per_coll))) { auto pos_sv = g1.template posTrack_as(); auto ele_sv = g1.template negTrack_as(); if (!isSelectedSecondary(pos_sv) || !isSelectedSecondary(ele_sv)) { @@ -279,8 +282,8 @@ struct EMPhotonFilter { if (clu2.trackdist() < 1.) { // select neutral clusters. Disp, Ncell cuts? continue; } - double m = pow(clu.e() + clu2.e(), 2) - pow(clu.px() + clu2.px(), 2) - - pow(clu.py() + clu2.py(), 2) - pow(clu.pz() + clu2.pz(), 2); + double m = std::pow(clu.e() + clu2.e(), 2) - std::pow(clu.px() + clu2.px(), 2) - + std::pow(clu.py() + clu2.py(), 2) - std::pow(clu.pz() + clu2.pz(), 2); if (m > ePair * ePair) { keepEvent[kPHOS_Pair] |= true; break; @@ -325,13 +328,10 @@ struct EMPhotonFilter { } // end of collision loop } - Filter PCMFilter = o2::aod::v0photonkf::dcaXYtopv < max_dcatopv_xy_v0 && o2::aod::v0photonkf::dcaZtopv < max_dcatopv_z_v0; - using filteredV0PhotonsKF = Filtered; - Filter DalitzEEFilter = o2::aod::dalitzee::sign == 0; // analyze only uls using filteredDalitzEEs = Filtered; - void process_PCM(MyCollisions const& collisions, filteredV0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, filteredDalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons) + void process_PCM(MyCollisions const& collisions, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, filteredDalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons) { const uint8_t system = EM_Filter_PhotonType::kPCM; runFilter(collisions, v0photons, nullptr, nullptr, v0legs, dielectrons, emprimaryelectrons); @@ -351,7 +351,7 @@ struct EMPhotonFilter { runFilter(collisions, nullptr, nullptr, clusters, nullptr, nullptr, nullptr); } - void process_PCM_PHOS(MyCollisions const& collisions, filteredV0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, filteredDalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons, CluCandidates const& clusters) + void process_PCM_PHOS(MyCollisions const& collisions, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, filteredDalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons, CluCandidates const& clusters) { const uint8_t system = EM_Filter_PhotonType::kPCM | EM_Filter_PhotonType::kPHOS; runFilter(collisions, v0photons, clusters, nullptr, v0legs, dielectrons, emprimaryelectrons); diff --git a/EventFiltering/PWGEM/HeavyNeutralMesonFilter.cxx b/EventFiltering/PWGEM/HeavyNeutralMesonFilter.cxx new file mode 100644 index 00000000000..013bee26a88 --- /dev/null +++ b/EventFiltering/PWGEM/HeavyNeutralMesonFilter.cxx @@ -0,0 +1,1301 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "EventFiltering/filterTables.h" +// +#include "PWGEM/PhotonMeson/Utils/HNMUtilities.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include // IWYU pragma: keep +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +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 +// these are need [[maybe_unused]] to silence a warning from clangd, since the compiler will inline them directly to the configs down below and then say: Variable 'X' is not needed and will not be emitted +[[maybe_unused]] 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}}; + +[[maybe_unused]] const float ptcutsTable[kNFemtoPartners][3]{ + {0.35f, 6.f, 0.75f}, + {0.55f, 2.f, 1.2f}, + {0.35f, 6.f, 0.75f}}; + +[[maybe_unused]] const float nClusterMinTPC[1][kNFemtoPartners]{{80.0f, 80.0f, 80.0f}}; +[[maybe_unused]] const float nClusterMinITS[1][kNFemtoPartners]{{4, 4, 4}}; + +[[maybe_unused]] static const float triggerSwitches[1][kNFemtoTriggers]{{1, 1, 1, 1, 1, 1}}; +[[maybe_unused]] 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 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}}}); + mHistManager.add(Form("%s%s/fInvMassVsKStar_%s", iHNM, iFemtoPartner, iEMCPCM), "Invariant mass and K* of heavy neutral meson candidates;#bf{#it{M}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{K}^{*} (GeV/#it{c})}", HistType::kTH2F, {{600, 0.6, 1.2}, {250, 0., 1.}}); + } + } + } + + // --> 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}}}); + mHistManager.add(Form("pp%s/fInvMassVsQ3_%s", iHNM, iEMCPCM), "Invariant mass and Q3 of heavy neutral meson candidates;#bf{#it{M}^{#pi^{+}#pi^{-}#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{Q}_{3} (GeV/#it{c})}", HistType::kTH2F, {{600, 0.6, 1.2}, {250, 0., 1.}}); + } + } + + 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 + bool keepFemtoEvent[hnmtrigger::kNFemtoTriggers] = {false, false, false, false, false, false}; // Set based on number of found pairs (see above) - used to flag femto events + if (!isSelectedEvent(collision)) { + tags(keepFemtoEvent[hnmtrigger::kOmegaP], keepFemtoEvent[hnmtrigger::kPPOmega], keepFemtoEvent[hnmtrigger::kOmegaD], keepFemtoEvent[hnmtrigger::kEtaPrimeP], keepFemtoEvent[hnmtrigger::kPPEtaPrime], keepFemtoEvent[hnmtrigger::kEtaPrimeD]); + 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 + + // 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()); + mHistManager.fill(HIST("ppomega/fInvMassVsQ3_PCM"), omegaParticles.M(), q3); + + 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()); + mHistManager.fill(HIST("ppomega/fInvMassVsQ3_EMC"), omegaParticles.M(), q3); + + 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()); + mHistManager.fill(HIST("ppomega/fInvMassVsQ3_PCM"), omegaParticles.M(), q3); + + 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()); + mHistManager.fill(HIST("ppomega/fInvMassVsQ3_EMC"), omegaParticles.M(), q3); + + 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()); + mHistManager.fill(HIST("ppetaprime/fInvMassVsQ3_PCM"), etaParticles.M(), q3); + + 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()); + mHistManager.fill(HIST("ppetaprime/fInvMassVsQ3_EMC"), etaParticles.M(), q3); + + 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()); + mHistManager.fill(HIST("ppetaprime/fInvMassVsQ3_PCM"), etaParticles.M(), q3); + + 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()); + mHistManager.fill(HIST("ppetaprime/fInvMassVsQ3_EMC"), etaParticles.M(), q3); + + 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()); + mHistManager.fill(HIST("omegad/fInvMassVsKStar_PCM"), (*iomega).M(), kstar); + + 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()); + mHistManager.fill(HIST("omegad/fInvMassVsKStar_PCM"), (*iomega).M(), kstar); + + 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()); + mHistManager.fill(HIST("omegad/fInvMassVsKStar_EMC"), (*iomega).M(), kstar); + + 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()); + mHistManager.fill(HIST("omegad/fInvMassVsKStar_EMC"), (*iomega).M(), kstar); + + 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()); + mHistManager.fill(HIST("etaprimed/fInvMassVsKStar_PCM"), (*ietaprime).M(), kstar); + + 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()); + mHistManager.fill(HIST("etaprimed/fInvMassVsKStar_PCM"), (*ietaprime).M(), kstar); + + 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()); + mHistManager.fill(HIST("etaprimed/fInvMassVsKStar_EMC"), (*ietaprime).M(), kstar); + + 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()); + mHistManager.fill(HIST("etaprimed/fInvMassVsKStar_EMC"), (*ietaprime).M(), kstar); + + 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()); + mHistManager.fill(HIST("omegap/fInvMassVsKStar_PCM"), (*iomega).M(), kstar); + + 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()); + mHistManager.fill(HIST("omegap/fInvMassVsKStar_PCM"), (*iomega).M(), kstar); + + 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()); + mHistManager.fill(HIST("omegap/fInvMassVsKStar_EMC"), (*iomega).M(), kstar); + + 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()); + mHistManager.fill(HIST("omegap/fInvMassVsKStar_EMC"), (*iomega).M(), kstar); + + 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()); + mHistManager.fill(HIST("etaprimep/fInvMassVsKStar_PCM"), (*ietaprime).M(), kstar); + + 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()); + mHistManager.fill(HIST("etaprimep/fInvMassVsKStar_PCM"), (*ietaprime).M(), kstar); + + 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()); + mHistManager.fill(HIST("etaprimep/fInvMassVsKStar_EMC"), (*ietaprime).M(), kstar); + + 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()); + mHistManager.fill(HIST("etaprimep/fInvMassVsKStar_EMC"), (*ietaprime).M(), kstar); + + 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(keepFemtoEvent[hnmtrigger::kOmegaP], keepFemtoEvent[hnmtrigger::kPPOmega], keepFemtoEvent[hnmtrigger::kOmegaD], keepFemtoEvent[hnmtrigger::kEtaPrimeP], keepFemtoEvent[hnmtrigger::kPPEtaPrime], keepFemtoEvent[hnmtrigger::kEtaPrimeD]); + // tags(colContainsPCMOmega, colContainsEMCOmega, colContainsPCMEtaPrime, colContainsEMCEtaPrime, keepFemtoEvent[hnmtrigger::kOmegaP], keepFemtoEvent[hnmtrigger::kEtaPrimeP], + // keepFemtoEvent[hnmtrigger::kPPOmega] || keepFemtoEvent[hnmtrigger::kOmegaD], keepFemtoEvent[hnmtrigger::kPPEtaPrime] || keepFemtoEvent[hnmtrigger::kEtaPrimeD]); + + if (!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()), massHNM); + 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()), massHNM); + 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()), massHNM); + 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()), massHNM); + 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 82293e0138c..beaddd9fd07 100644 --- a/EventFiltering/PWGHF/HFFilter.cxx +++ b/EventFiltering/PWGHF/HFFilter.cxx @@ -8,7 +8,6 @@ // In applying this license CERN does 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 /// \file HFFilter.cxx /// \brief task for selection of events with HF signals @@ -18,29 +17,66 @@ /// \author Alexandre Bigot , Strasbourg University /// \author Biao Zhang , CCNU /// \author Federica Zanone , Heidelberg University +/// \author Antonio Palasciano , INFN Bari -#include "CommonConstants/PhysicsConstants.h" -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.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 "EventFiltering/PWGHF/HFFilterHelpers.h" +#include "EventFiltering/filterTables.h" +// +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +// +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.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 "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; +using namespace o2::soa; using namespace o2::analysis; using namespace o2::aod::hffilters; using namespace o2::framework; @@ -55,63 +91,73 @@ 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)"}; + Configurable> trackQaulityCuts{"trackQaulityCuts", {cutsTrackQuality[0], 2, 7, labelsColumnsPtThresholdsForFemto, labelsColumnsTrackQuality}, "Track quality cuts for proton and deuteron)"}; // 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"}; // CCDB configuration - o2::ccdb::CcdbApi ccdbApi; - Service ccdb; Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - int currentRun{0}; // needed to detect if the run changed and trigger update of calibrations etc. // TPC PID calibrations Configurable setTPCCalib{"setTPCCalib", 0, "0 is not use re-calibrations, 1 is compute TPC post-calibrated n-sigmas, 2 is using TPC Spline"}; @@ -121,30 +167,66 @@ struct HfFilter { // Main struct for HF triggers Configurable ccdbBBAntiPion{"ccdbBBAntiPion", "Users/l/lserksny/PIDAntiPion", "Path to the CCDB ocject for antiPion BB param"}; Configurable ccdbBBKaon{"ccdbBBKaon", "Users/l/lserksny/PIDPion", "Path to the CCDB ocject for Kaon BB param"}; Configurable ccdbBBAntiKaon{"ccdbBBAntiKaon", "Users/l/lserksny/PIDAntiPion", "Path to the CCDB ocject for antiKaon BB param"}; - Configurable ccdbPathTPC{"ccdbPathTPC", "Users/i/iarsene/Calib/TPCpostCalib", "base path to the CCDB object"}; + Configurable ccdbPathTPC{"ccdbPathTPC", "Users/i/iarsene/Calib/TPCpostCalib", "base path to the CCDB object"}; // 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)"}; + + Service ccdb; + + 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::v0::collisionId; + Preslice hf2ProngPerCollision = aod::track_association::collisionId; + Preslice hf3ProngPerCollision = aod::track_association::collisionId; + Preslice cascPerCollision = aod::cascade::collisionId; + Preslice photonsPerCollision = aod::v0photonkf::collisionId; + PresliceUnsorted trackedCascadesPerCollision = aod::track::collisionId; + + o2::ccdb::CcdbApi ccdbApi; + int currentRun{0}; // needed to detect if the run changed and trigger update of calibrations etc. + // array of BDT thresholds std::array, kNCharmParticles> thresholdBDTScores; - HistogramRegistry registry{"registry"}; + 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) + o2::vertexing::DCAFitterN<3> dfStrangeness3; // fitter for Xic+ -> XiPiPi + std::shared_ptr hProcessedEvents; // QA histos 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; @@ -154,23 +236,36 @@ struct HfFilter { // Main struct for HF triggers // helper object HfFilterHelper helper; - void init(InitContext&) + HistogramRegistry registry{"registry"}; + + void init(InitContext& 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.setDeuteronTrackSelectionForFemto(trackQaulityCuts->get(1u, 0u), trackQaulityCuts->get(1u, 1u), trackQaulityCuts->get(1u, 2u), trackQaulityCuts->get(1u, 3u), trackQaulityCuts->get(1u, 4u), trackQaulityCuts->get(1u, 5u), trackQaulityCuts->get(1u, 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 +273,43 @@ 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) + helper.setVtxConfiguration(dfStrangeness3, true); // (DCAFitterN, useAbsDCA) + dfStrangeness.setMatCorrType(matCorr); + dfStrangeness3.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}}); + // fetch config of track-index-skim-creator to apply the same cut on DeltaMassKK for Ds + std::vector ptBinsDsSkimCreator{}; + LabeledArray cutsDsSkimCreator{}; + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name.compare("hf-track-index-skim-creator") == 0) { + for (const auto& option : device.options) { + if (option.name.compare("binsPtDsToKKPi") == 0) { + auto ptBins = option.defaultValue.get(); + double lastEl{-1.e6}; + int iPt{0}; + while (ptBins[iPt] > lastEl) { + ptBinsDsSkimCreator.push_back(ptBins[iPt]); + lastEl = ptBins[iPt]; + iPt++; + } + } else if (option.name.compare("cutsDsToKKPi") == 0) { + cutsDsSkimCreator = option.defaultValue.get>(); + } + } + } + } + helper.setPreselDsToKKPi(ptBinsDsSkimCreator, cutsDsSkimCreator); + + 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 +318,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 +426,24 @@ struct HfFilter { // Main struct for HF triggers thresholdBDTScores = {thresholdBDTScoreD0ToKPi, thresholdBDTScoreDPlusToPiKPi, thresholdBDTScoreDSToPiKK, thresholdBDTScoreLcToPiKP, thresholdBDTScoreXicToPiKP}; } - using BigTracksMCPID = soa::Join; - using BigTracksPID = 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 hf2ProngPerCollision = aod::track_association::collisionId; - Preslice hf3ProngPerCollision = aod::track_association::collisionId; - Preslice cascPerCollision = aod::cascdata::collisionId; - Preslice photonsPerCollision = aod::v0photonkf::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 +466,18 @@ 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); + dfStrangeness3.setBz(bz); + df2.setBz(bz); + df3.setBz(bz); + df4.setBz(bz); + if (activateSecVtxForB) { + dfB.setBz(bz); + dfBtoDstar.setBz(bz); } currentRun = bc.runNumber(); @@ -321,26 +485,28 @@ 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); - o2::gpu::gpustd::array dcaPos{trackPos.dcaXY(), trackPos.dcaZ()}; - o2::gpu::gpustd::array dcaNeg{trackNeg.dcaXY(), trackNeg.dcaZ()}; + auto trackParPos = getTrackParCov(trackPos); + auto trackParNeg = getTrackParCov(trackNeg); + std::array dcaPos{trackPos.dcaXY(), trackPos.dcaZ()}; + std::array dcaNeg{trackNeg.dcaXY(), trackNeg.dcaZ()}; std::array pVecPos{trackPos.pVector()}; std::array pVecNeg{trackNeg.pVector()}; if (trackPos.collisionId() != thisCollId) { @@ -352,126 +518,282 @@ 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); - o2::gpu::gpustd::array dcaThird{track.dcaXY(), track.dcaZ()}; + auto trackParThird = getTrackParCov(track); + std::array dcaThird{track.dcaXY(), track.dcaZ()}; std::array pVecThird = track.pVector(); if (track.collisionId() != thisCollId) { o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParThird, 2.f, noMatCorr, &dcaThird); 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); + if (isBplusInMass) + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::Skimmed, kBplus); + if (isBcInMass) + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::Skimmed, kBc); } - } 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; - } - 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 { + int nVtxD{0}; + try { + nVtxD = df2.process(trackParPos, trackParNeg); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for charm 2-prong!"; + nVtxD = 0; + } + if (nVtxD != 0) { + 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); + int nVtxB{0}; + try { + nVtxB = dfB.process(trackParD, trackParThird); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for beauty 3-prong!"; + nVtxB = 0; } - 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); + if (nVtxB != 0) { + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::BeautyVertex, kBplus); + } + const auto& secondaryVertexBtoD0h = dfB.getPCACandidate(); + std::array pVecThirdVtx{}; + dfB.getTrack(0).getPxPyPzGlo(pVec2ProngVtx); + dfB.getTrack(1).getPxPyPzGlo(pVecThirdVtx); + std::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); + std::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 { + int nVtxD{0}; + try { + nVtxD = df2.process(trackParPos, trackParNeg); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for charm 2-prong!"; + nVtxD = 0; + } + if (nVtxD > 0) { + 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); + int nVtxB{0}; + try { + nVtxB = dfBtoDstar.process(trackParD, trackParThird, trackParFourth); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for beauty to D*!"; + nVtxB = 0; + } + if (nVtxB != 0) { + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::BeautyVertex, kB0toDStar); + } + 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 +803,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 +819,86 @@ 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]) { + int nVtxB{0}; + try { + nVtxB = df3.process(trackParPos, trackParNeg, trackParThird); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for beauty to JPsi 3-prong!"; + nVtxB = 0; + } + if (nVtxB != 0) { + 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); + std::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; + } + int nVtxB{0}; + try { + nVtxB = df4.process(trackParPos, trackParNeg, trackParThird, trackParFourth); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for beauty to JPsi 4-prong!"; + nVtxB = 0; + } + if (nVtxB != 0) { + 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(); @@ -508,7 +906,7 @@ struct HfFilter { // Main struct for HF triggers if (!helper.isSelectedPhoton(photon, std::array{posTrack, negTrack}, activateQA, hV0Selected, hArmPod)) { continue; } - gpu::gpustd::array dcaInfo; + std::array dcaInfo; std::array pVecPhoton = {photon.px(), photon.py(), photon.pz()}; std::array posVecPhoton = {photon.vx(), photon.vy(), photon.vz()}; auto trackParPhoton = o2::track::TrackPar(posVecPhoton, pVecPhoton, 0, true); @@ -521,11 +919,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,46 +947,37 @@ 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; } auto trackParBachelor = getTrackPar(trackBachelor); - o2::gpu::gpustd::array dcaBachelor{trackBachelor.dcaXY(), trackBachelor.dcaZ()}; + std::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); } - 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 +995,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 +1014,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 } @@ -653,14 +1037,14 @@ struct HfFilter { // Main struct for HF triggers if (isGoodXicStar) { if (isRightSignXicStar) { hMassVsPtC[kNCharmParticles + 7]->Fill(ptCand, massDiffXicStarCand); - } else if (!isRightSignXicStar && keepAlsoWrongDmesLambdaPairs) { + } else if (keepAlsoWrongDmesLambdaPairs) { hMassVsPtC[kNCharmParticles + 8]->Fill(ptCand, massDiffXicStarBarCand); } } if (isGoodXicStarBar) { if (isRightSignXicStarBar) { hMassVsPtC[kNCharmParticles + 7]->Fill(ptCand, massDiffXicStarCand); - } else if (!isRightSignXicStarBar && keepAlsoWrongDmesLambdaPairs) { + } else if (keepAlsoWrongDmesLambdaPairs) { hMassVsPtC[kNCharmParticles + 8]->Fill(ptCand, massDiffXicStarBarCand); } } @@ -674,9 +1058,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; + } + std::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); + std::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 (keepAlsoWrongDmesProtonPairs) { + hMassVsPtC[kNCharmParticles + 22]->Fill(ptCand, massDiffThetacBarCand); + } + } + if (isGoodThetacBar) { + if (isRightSignThetaCBar) { + hMassVsPtC[kNCharmParticles + 21]->Fill(ptCand, massDiffThetacCand); + } else if (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 (keepAlsoWrongDmesProtonPairs) { + hMassVsPtC[kNCharmParticles + 20]->Fill(ptCand, massDiffLcStarBarCand); + } + } + if (isGoodLcStarBar) { + if (isRightSignLcStarBar) { + hMassVsPtC[kNCharmParticles + 19]->Fill(ptCand, massDiffLcStarCand); + } else if (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,16 +1223,16 @@ 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); - 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()}; + auto trackParFirst = getTrackParCov(trackFirst); + auto trackParSecond = getTrackParCov(trackSecond); + auto trackParThird = getTrackParCov(trackThird); + std::array dcaFirst{trackFirst.dcaXY(), trackFirst.dcaZ()}; + std::array dcaSecond{trackSecond.dcaXY(), trackSecond.dcaZ()}; + std::array dcaThird{trackThird.dcaXY(), trackThird.dcaZ()}; std::array pVecFirst = trackFirst.pVector(); std::array pVecSecond = trackSecond.pVector(); std::array pVecThird = trackThird.pVector(); @@ -768,8 +1303,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,40 +1364,94 @@ 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); - o2::gpu::gpustd::array dcaFourth{track.dcaXY(), track.dcaZ()}; + auto trackParFourth = getTrackParCov(track); + std::array dcaFourth{track.dcaXY(), track.dcaZ()}; std::array pVecFourth = track.pVector(); if (track.collisionId() != thisCollId) { o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParFourth, 2.f, noMatCorr, &dcaFourth); 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 { + int nVtxD{0}; + try { + nVtxD = df3.process(trackParFirst, trackParSecond, trackParThird); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for charm 3-prong!"; + nVtxD = 0; + } + if (nVtxD != 0) { + 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); + int nVtxB{0}; + try { + nVtxB = dfB.process(trackParD, trackParFourth); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call for B 4-prong!"; + nVtxB = 0; + } + if (nVtxB != 0) { + if (activateQA) { + registry.fill(HIST("fHfVtxStages"), 1 + HfVtxStage::BeautyVertex, iHypo + 3); + } + const auto& secondaryVertexB = dfB.getPCACandidate(); + std::array pVecFourtVtx{}; + dfB.getTrack(0).getPxPyPzGlo(pVec3ProngVtx); + dfB.getTrack(1).getPxPyPzGlo(pVecFourtVtx); + std::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 +1459,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 +1477,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 +1503,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 @@ -904,7 +1526,7 @@ struct HfFilter { // Main struct for HF triggers // select soft pion candidates auto trackParSoftPi = getTrackPar(trackSoftPi); - o2::gpu::gpustd::array dcaSoftPi{trackSoftPi.dcaXY(), trackSoftPi.dcaZ()}; + std::array dcaSoftPi{trackSoftPi.dcaXY(), trackSoftPi.dcaZ()}; std::array pVecSoftPi = trackSoftPi.pVector(); if (trackSoftPi.collisionId() != thisCollId) { // This is a track reassociated to this PV by the track-to-collision-associator @@ -912,7 +1534,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 +1594,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); @@ -989,7 +1611,7 @@ struct HfFilter { // Main struct for HF triggers if (!helper.isSelectedPhoton(photon, std::array{posTrack, negTrack}, activateQA, hV0Selected, hArmPod)) { continue; } - gpu::gpustd::array dcaInfo; + std::array dcaInfo; std::array pVecPhoton = {photon.px(), photon.py(), photon.pz()}; std::array posVecPhoton = {photon.vx(), photon.vy(), photon.vz()}; auto trackParPhoton = o2::track::TrackPar(posVecPhoton, pVecPhoton, 0, true); @@ -1038,28 +1660,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,22 +1686,17 @@ 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)) { if (activateQA) { if (isRightSign) { hMassVsPtC[kNCharmParticles + 5]->Fill(ptCand, massDiffXicStar); - } else if (!isRightSign && keepAlsoWrongDmesLambdaPairs) { + } else if (keepAlsoWrongDmesLambdaPairs) { hMassVsPtC[kNCharmParticles + 6]->Fill(ptCand, massDiffXicStar); } } @@ -1104,12 +1714,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; } @@ -1122,7 +1732,7 @@ struct HfFilter { // Main struct for HF triggers // select soft pion candidates auto trackParSoftPi = getTrackPar(trackSoftPi); - o2::gpu::gpustd::array dcaSoftPi{trackSoftPi.dcaXY(), trackSoftPi.dcaZ()}; + std::array dcaSoftPi{trackSoftPi.dcaXY(), trackSoftPi.dcaZ()}; std::array pVecSoftPi = trackSoftPi.pVector(); if (trackSoftPi.collisionId() != thisCollId) { // This is a track reassociated to this PV by the track-to-collision-associator @@ -1130,7 +1740,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 +1752,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 +1798,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 + std::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); + std::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, dfStrangeness, 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); + std::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, dfStrangeness3, 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 +1938,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 +1952,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..e136856c33e 100644 --- a/EventFiltering/PWGHF/HFFilterCharmHadronSignals.cxx +++ b/EventFiltering/PWGHF/HFFilterCharmHadronSignals.cxx @@ -8,32 +8,53 @@ // In applying this license CERN does 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 /// \file HFFilterCharmHadronSignals.cxx /// \brief task for the quality control of the signals of D0, D+, Ds+, Lc+, and D*+ selected in the HFFilter.cxx task /// /// \author Fabrizio Grosa , CERN -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.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 "EventFiltering/PWGHF/HFFilterHelpers.h" +// +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +// +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" - -#include "EventFiltering/filterTables.h" -#include "EventFiltering/PWGHF/HFFilterHelpers.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -49,11 +70,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 +84,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 +118,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); @@ -159,8 +180,8 @@ struct HfFilterCharmHadronSignals { // Main struct for HF triggers 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 dcaPos{trackPos.dcaXY(), trackPos.dcaZ()}; + std::array dcaNeg{trackNeg.dcaXY(), trackNeg.dcaZ()}; std::array pVecPos{trackPos.pVector()}; std::array pVecNeg{trackNeg.pVector()}; if (trackPos.collisionId() != thisCollId) { @@ -215,13 +236,13 @@ struct HfFilterCharmHadronSignals { // Main struct for HF triggers } auto trackParThird = getTrackPar(track); - o2::gpu::gpustd::array dcaThird{track.dcaXY(), track.dcaZ()}; + std::array dcaThird{track.dcaXY(), track.dcaZ()}; std::array pVecThird = track.pVector(); if (track.collisionId() != thisCollId) { 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; @@ -265,9 +286,9 @@ struct HfFilterCharmHadronSignals { // Main struct for HF triggers 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 dcaFirst{trackFirst.dcaXY(), trackFirst.dcaZ()}; + std::array dcaSecond{trackSecond.dcaXY(), trackSecond.dcaZ()}; + std::array dcaThird{trackThird.dcaXY(), trackThird.dcaZ()}; std::array pVecFirst = trackFirst.pVector(); std::array pVecSecond = trackSecond.pVector(); std::array pVecThird = trackThird.pVector(); diff --git a/EventFiltering/PWGHF/HFFilterHelpers.h b/EventFiltering/PWGHF/HFFilterHelpers.h index e0dd03f3b75..b000ad228d6 100644 --- a/EventFiltering/PWGHF/HFFilterHelpers.h +++ b/EventFiltering/PWGHF/HFFilterHelpers.h @@ -8,7 +8,6 @@ // In applying this license CERN does 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 /// \file HFFilterHelpers.h /// \brief Header file with definition of variables, methods, and tables used in the HFFilter.cxx task @@ -18,40 +17,52 @@ /// \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_ +#include "EventFiltering/filterTables.h" +// +#include "PWGHF/Core/SelectorCuts.h" +// +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include +#include +#include +#include + +#include + #include #include #include +#include +#include #include -#include #include +#include #include -#include "Math/GenVector/Boost.h" -#include "Math/Vector3D.h" -#include "Math/Vector4D.h" - -#include "CCDB/CcdbApi.h" -#include "CCDB/BasicCCDBManager.h" -#include "CommonConstants/MathConstants.h" -#include "CommonConstants/PhysicsConstants.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/DataTypes.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/AnalysisHelpers.h" -#include "Framework/O2DatabasePDGPlugin.h" - -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "EventFiltering/filterTables.h" - namespace o2::aod { @@ -75,6 +86,17 @@ enum HfTriggers { kSigmaC0K0, kPhotonCharm2P, kPhotonCharm3P, + kSingleCharm2P, + kSingleCharm3P, + kSingleNonPromptCharm2P, + kSingleNonPromptCharm3P, + kCharmBarToXi2Bach, + kPrCharm2P, + kBtoJPsiKa, + kBtoJPsiKstar, + kBtoJPsiPhi, + kBtoJPsiPrKa, + kBtoJPsiPi, kNtriggersHF }; @@ -90,6 +112,7 @@ enum charmParticles { enum beautyParticles { kBplus = 0, kB0toDStar, + kBc, kB0, kBs, kLb, @@ -97,6 +120,15 @@ enum beautyParticles { kNBeautyParticles }; +enum beautyToJPsiParticles { + kBplusToJPsi = 0, + kB0ToJPsi, + kBsToJPsi, + kLbToJPsi, + kBcToJPsi, + kNBeautyParticlesToJPsi +}; + enum bachelorTrackSelection { kRejected = 0, kSoftPion, @@ -104,6 +136,7 @@ enum bachelorTrackSelection { kSoftPionForBeauty, kPionForCharmBaryon, kKaonForCharmBaryon, + kProtonForCharmBaryon, kSoftPionForSigmaC }; @@ -114,7 +147,14 @@ enum PIDSpecies { kKa, kAntiKa, kPr, - kAntiPr + kAntiPr, + kDe, + kAntiDe +}; + +enum trackSpecies { + kProtonForFemto, + kDeuteronForFemto }; enum V0Species { @@ -125,11 +165,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 +260,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,57 +278,97 @@ 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 = o2::constants::physics::MassBCPlus; 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}; -static const o2::framework::AxisSpec kstarAxis{100, 0.f, 1.f}; +static const o2::framework::AxisSpec kstarAxis{200, 0.f, 2.f}; static const o2::framework::AxisSpec etaAxis{30, -1.5f, 1.5f}; static const o2::framework::AxisSpec nSigmaAxis{100, -10.f, 10.f}; 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"}; + +// track cut +constexpr float cutsTrackQuality[2][7] = {{0., 0., 0., 999., 999., 0., 0.}, + {90, 80, 0.83, 160., 1., 5., 0.}}; +static const std::vector labelsColumnsTrackQuality = {"minTpcCluster", "minTpcRow", "minTpcCrossedOverFound", "maxTpcShared", "maxTpcFracShared", "minItsCluster", "minItsIbCluster"}; // 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 +376,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 +405,54 @@ class HfFilterHelper mPtThresholdHighPt2Prongs = threshold2Prongs; mPtThresholdHighPt3Prongs = threshold3Prongs; } - void setPtBinsSingleTracks(std::vector ptBins) { mPtBinsTracks = ptBins; } - void setCutsSingleTrackBeauty(o2::framework::LabeledArray cutsSingleTrack3P, o2::framework::LabeledArray cutsSingleTrack4P) + void setPtTriggerThresholdsForFemto(float thresholdProtons, float thresholdDeuterons) + { + mPtThresholdProtonForFemto = thresholdProtons; + mPtThresholdDeuteronForFemto = thresholdDeuterons; + } + void setForceTofForFemto(bool forceTofProtons, bool forceTofDeuterons) + { + mForceTofProtonForFemto = forceTofProtons; + mForceTofDeuteronForFemto = forceTofDeuterons; + } + void setPtBinsSingleTracks(const std::vector& ptBins) { mPtBinsTracks = ptBins; } + void setPtBinsBeautyHadrons(const std::vector& ptBins) { mPtBinsBeautyHadrons = ptBins; } + void setCutsSingleTrackBeauty(const o2::framework::LabeledArray& cutsSingleTrack3P, const o2::framework::LabeledArray& cutsSingleTrack4P, const o2::framework::LabeledArray& cutsSingleToJPsi) { mCutsSingleTrackBeauty3Prong = cutsSingleTrack3P; mCutsSingleTrackBeauty4Prong = cutsSingleTrack4P; + mCutsSingleTrackBeautyToJPsi = cutsSingleToJPsi; + } + void setCutsBhadrons(const o2::framework::LabeledArray& cutsBplus, const o2::framework::LabeledArray& cutsB0toDstar, const o2::framework::LabeledArray& cutsBc, const o2::framework::LabeledArray& cutsB0, const o2::framework::LabeledArray& cutsBs, const o2::framework::LabeledArray& cutsLb, const 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(const 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 +489,31 @@ 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 setNsigmaProtonCutsForFemto(std::array nSigmaCuts) { mNSigmaPrCutsForFemto = nSigmaCuts; } + void setNsigmaDeuteronCutsForFemto(std::array nSigmaCuts) { mNSigmaDeCutsForFemto = nSigmaCuts; } + + void setDeuteronTrackSelectionForFemto(float minTpcCluster, float minTpcRow, float minTpcCrossedOverFound, float maxTpcShared, float maxTpcFracShared, float minItsCluster, float minItsIbCluster) + { + mMinTpcCluster = minTpcCluster; + mMinTpcRow = minTpcRow; + mMinTpcCrossedOverFound = minTpcCrossedOverFound; + mMaxTpcShared = maxTpcShared; + mMaxTpcFracShared = maxTpcFracShared; + mMinItsCluster = minItsCluster; + mMinItsIbCluster = minItsIbCluster; + } - void setPtThresholdPidStrategyForFemto(float ptThreshold) { mPtThresholdPidStrategyForFemto = ptThreshold; } - void setNsigmaProtonCutsForFemto(std::array nSigmaCuts) { mNSigmaPrCutsForFemto = nSigmaCuts; } void setNsigmaProtonCutsForCharmBaryons(float nSigmaTpc, float nSigmaTof) { mNSigmaTpcPrCutForCharmBaryons = nSigmaTpc; @@ -309,6 +529,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; @@ -329,7 +554,7 @@ class HfFilterHelper mMaxDcaXyXi = maxDcaxyXi; mMaxNsigmaXiDau = nSigma; } - void setCutsSingleTrackCharmBaryonBachelor(o2::framework::LabeledArray cutsSingleTrack) { mCutsSingleTrackCharmBaryonBachelor = cutsSingleTrack; } + void setCutsSingleTrackCharmBaryonBachelor(const o2::framework::LabeledArray& cutsSingleTrack) { mCutsSingleTrackCharmBaryonBachelor = cutsSingleTrack; } void setNsigmaPiCutsForCharmBaryonBachelor(float nSigmaTpc, float nSigmaTof) { mNSigmaTpcPiCharmBaryonBachelor = nSigmaTpc; @@ -341,9 +566,24 @@ 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) + void setMassResolParametrisation(const std::string& recoPass) { if (recoPass == "2023_pass3") { mSigmaPars2Prongs[0] = 0.01424f; @@ -354,6 +594,15 @@ class HfFilterHelper mSigmaPars3Prongs[1] = 0.00176f; mDeltaMassPars3Prongs[0] = -0.0025f; mDeltaMassPars3Prongs[1] = 0.0001f; + } else if (recoPass == "2025_pass1") { + mSigmaPars2Prongs[0] = 0.01424f; + mSigmaPars2Prongs[1] = 0.00178f; + mDeltaMassPars2Prongs[0] = -0.013f; + mDeltaMassPars2Prongs[1] = 0.00029f; + mSigmaPars3Prongs[0] = 0.00796f; + mSigmaPars3Prongs[1] = 0.00176f; + mDeltaMassPars3Prongs[0] = -0.013f; + mDeltaMassPars3Prongs[1] = 0.00029f; } else { LOGP(fatal, "Mass resolution parametrisation {} not supported! Please set 2023_pass3", recoPass.data()); } @@ -361,15 +610,21 @@ class HfFilterHelper void setNumSigmaForDeltaMassCharmHadCut(float nSigma) { mNumSigmaDeltaMassCharmHad = nSigma; } + void setPreselDsToKKPi(const std::vector& ptBins, const o2::framework::LabeledArray& preselections) + { + mPtBinsPreselDsToKKPi = ptBins; + mPreselDsToKKPi = preselections; + } + // helper functions for selections template 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 +645,169 @@ 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); + int computeNumberOfCandidates(const 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) + float mMinTpcCluster{90.}; // Minimum number of TPC clusters required on a track + float mMinTpcRow{80.}; // Minimum number of TPC rows (pad rows) traversed by the track + float mMinTpcCrossedOverFound{0.83}; // Minimum ratio of crossed TPC rows over findable clusters + float mMaxTpcShared{160.}; // Maximum allowed number of shared TPC clusters between tracks + float mMaxTpcFracShared{1.}; // Maximum allowed fraction of shared TPC clusters relative to total clusters + float mMinItsCluster{1.}; // Minimum required number of ITS clusters + float mMinItsIbCluster{1.}; // Minimum required number of ITS clusters for IB // 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 + // Ds cuts from track-index-skim-creator + std::vector mPtBinsPreselDsToKKPi{}; // pT bins for pre-selections for Ds from track-index-skim-creator + o2::framework::LabeledArray mPreselDsToKKPi{}; // pre-selections for Ds from track-index-skim-creator }; /// Selection of high-pt 2-prong candidates @@ -526,11 +837,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 +867,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 +885,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 +922,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 +970,83 @@ 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); + float momentum = track.p(); + if (trackSpecies == kProtonForFemto) { + if (momentum <= ptThresholdPidStrategy) { + if (NSigma > nSigmaCuts[2]) { + return false; + } + } else { + if (std::fabs(NSigmaTPC) > nSigmaCuts[0] || std::fabs(NSigmaTOF) > nSigmaCuts[1]) { + return false; + } + } + } + // For deuterons: Determine whether to apply TOF based on pt threshold + if (trackSpecies == kDeuteronForFemto) { - if (trackPar.getPt() <= mPtThresholdPidStrategyForFemto) { - if (NSigma > mNSigmaPrCutsForFemto[2]) { + if (track.tpcNClsFound() < mMinTpcCluster) { return false; } - } else { - if (std::fabs(NSigmaTPC) > mNSigmaPrCutsForFemto[0] || std::fabs(NSigmaTOF) > mNSigmaPrCutsForFemto[1]) { + if (track.tpcNClsCrossedRows() < mMinTpcRow) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < mMinTpcCrossedOverFound) { + return false; + } + if (track.tpcNClsShared() > mMaxTpcShared) { + return false; + } + if (track.tpcFractionSharedCls() > mMaxTpcFracShared) { + return false; + } + if (track.itsNCls() < mMinItsCluster) { return false; } + if (track.itsNClsInnerBarrel() < mMinItsIbCluster) { + return false; + } + + // Apply different PID strategy in different pt range + // one side selection only + if (momentum <= ptThresholdPidStrategy) { + if (std::fabs(NSigmaTPC) > nSigmaCuts[0] || NSigmaITS < -nSigmaCuts[3]) { // Use TPC and ITS below the threshold, NSigmaITS for deuteron with a lower limit + return false; + } + } else { + if (NSigma > nSigmaCuts[2]) { // 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(momentum, NSigmaTOF); + else if (trackSpecies == kDeuteronForFemto && momentum > ptThresholdPidStrategy) + hTOFPID->Fill(momentum, NSigmaTOF); } } @@ -673,7 +1064,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,18 +1084,25 @@ 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; } // check delta-mass for phi resonance + auto ptDs = RecoDecay::pt(pTrackSameChargeFirst, pTrackSameChargeSecond, pTrackOppositeCharge); + auto ptBinDs = findBin(mPtBinsPreselDsToKKPi, ptDs); + if (ptBinDs == -1) { + return retValue; + } + auto invMassKKFirst = RecoDecay::m(std::array{pTrackSameChargeFirst, pTrackOppositeCharge}, std::array{massKa, massKa}); auto invMassKKSecond = RecoDecay::m(std::array{pTrackSameChargeSecond, pTrackOppositeCharge}, std::array{massKa, massKa}); - if (std::fabs(invMassKKFirst - massPhi) < 0.02) { + float cutValueMassKK = mPreselDsToKKPi.get(ptBinDs, 4u); + if (std::fabs(invMassKKFirst - massPhi) < cutValueMassKK) { retValue |= BIT(0); } - if (std::fabs(invMassKKSecond - massPhi) < 0.02) { + if (std::fabs(invMassKKSecond - massPhi) < cutValueMassKK) { retValue |= BIT(1); } @@ -721,13 +1119,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 +1380,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 +1420,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 +1436,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 +1446,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 +1455,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 +1465,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 +1486,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 +1501,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}; if (mTpcPidCalibrationOption == 1) { + float nClsTpc[2] = {v0.nClsFoundTpcPos, v0.nClsFoundTpcNeg}; + float etaDaus[2] = {v0.etaPos, v0.etaNeg}; 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) { + float signalTpc[2] = {v0.signalTpcPos, v0.signalTpcNeg}; 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 +1533,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 +1595,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}; if (mTpcPidCalibrationOption == 1) { + float etaDaus[3] = {casc.etaBach, casc.v0.etaPos, casc.v0.etaNeg}; 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) { + float signalTpc[3] = {casc.signalTpcBach, casc.v0.signalTpcPos, casc.v0.signalTpcNeg}; 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], 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 +1728,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; @@ -1435,7 +1838,7 @@ inline T HfFilterHelper::computeRelativeMomentum(const std::array& pTrack, /// Computation of the number of candidates in an event that do not share daughter tracks /// \return 0 or 1 in case of less than 2 independent candidates in a single event, 2 otherwise template -inline int HfFilterHelper::computeNumberOfCandidates(std::vector> indices) +inline int HfFilterHelper::computeNumberOfCandidates(const std::vector>& indices) { if (indices.size() < 2) { return indices.size(); @@ -1479,9 +1882,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 +1893,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 +1912,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 +1933,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 +1949,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 +1984,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 +1993,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 +2009,494 @@ 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(); + 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{}; + 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 +2505,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 +2600,276 @@ 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()}; + std::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 + 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); + std::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; + } + + std::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 + 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); + std::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 +2996,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 +3024,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 1441782031e..1b2db23c907 100644 --- a/EventFiltering/PWGHF/HFFilterPrepareMLSamples.cxx +++ b/EventFiltering/PWGHF/HFFilterPrepareMLSamples.cxx @@ -8,7 +8,6 @@ // In applying this license CERN does 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 /// \file HFFilterPrepareMLSamples.cxx /// \brief task for trainings of ML models to be used in the HFFilter.cxx task @@ -17,29 +16,41 @@ /// \author Marcel Lesch , TUM /// \author Alexandre Bigot , Strasbourg University /// \author Biao Zhang , CCNU - -#if __has_include() -#include // needed for HFFilterHelpers, to be fixed -#else -#include -#endif - -#include "CommonConstants/PhysicsConstants.h" -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.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 "Common/Core/trackUtilities.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +/// \author Antonio Palasciano , INFN Bari #include "EventFiltering/PWGHF/HFFilterHelpers.h" +// +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +// +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -53,9 +64,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; @@ -67,8 +82,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(); @@ -76,14 +98,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); + std::array dcaPos{trackPos.dcaXY(), trackPos.dcaZ()}; + std::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); + std::array dcaFirst{trackFirst.dcaXY(), trackFirst.dcaZ()}; + std::array dcaSecond{trackSecond.dcaXY(), trackSecond.dcaZ()}; + std::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 @@ -102,8 +257,8 @@ struct HfFilterPrepareMlSamples { // Main struct 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 dcaPos{trackPos.dcaXY(), trackPos.dcaZ()}; + std::array dcaNeg{trackNeg.dcaXY(), trackNeg.dcaZ()}; std::array pVecPos{trackPos.pVector()}; std::array pVecNeg{trackNeg.pVector()}; if (trackPos.collisionId() != thisCollId) { @@ -126,7 +281,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); @@ -136,13 +299,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(); @@ -163,9 +332,9 @@ struct HfFilterPrepareMlSamples { // Main struct 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 dcaFirst{trackFirst.dcaXY(), trackFirst.dcaZ()}; + std::array dcaSecond{trackSecond.dcaXY(), trackSecond.dcaZ()}; + std::array dcaThird{trackThird.dcaXY(), trackThird.dcaZ()}; std::array pVecFirst{trackFirst.pVector()}; std::array pVecSecond{trackSecond.pVector()}; std::array pVecThird{trackThird.pVector()}; @@ -207,32 +376,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); @@ -243,16 +419,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..47761d62c1e 100644 --- a/EventFiltering/PWGJE/jetFilter.cxx +++ b/EventFiltering/PWGJE/jetFilter.cxx @@ -11,31 +11,33 @@ // Author: Filip Krizek -#include -#include -#include +#include "../filterTables.h" -#include "Framework/ASoA.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/Track.h" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.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/FastJetUtilities.h" -#include "PWGJE/Core/JetBkgSubUtils.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGJE/DataModel/Jet.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" -#include "../filterTables.h" +#include -#include "Framework/HistogramRegistry.h" +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -94,13 +96,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)"}}); @@ -188,7 +190,7 @@ struct jetFilter { // collision process loop bool keepEvent[kTriggerObjects]{false, false, false, false}; - if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits(static_cast("NoTimeFrameBorder")))) { tags(keepEvent[kJetChLowPt], keepEvent[kJetChHighPt], keepEvent[kTrackLowPt], keepEvent[kTrackHighPt]); return; } @@ -196,7 +198,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 +288,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(aod::JetCollision 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..07c59d43150 --- /dev/null +++ b/EventFiltering/PWGLF/filterdoublephi.cxx @@ -0,0 +1,287 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "../filterTables.h" + +#include "PWGLF/DataModel/ReducedDoublePhiTables.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include + +#include +#include +#include // FIXME +#include +#include // FIXME + +#include + +#include +#include +#include +#include + +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() < 2.0) { + return true; + } + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * 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 && candidate.pt() < 5.0) { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF) { + return true; + } + } + if (candidate.pt() >= 5.0 && candidate.tpcNSigmaKa() > nsigmaCutTPC && candidate.tpcNSigmaKa() < 2.0) { + 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/filterf1proton.cxx b/EventFiltering/PWGLF/filterf1proton.cxx index 0d3d643207e..ef47f431ca6 100644 --- a/EventFiltering/PWGLF/filterf1proton.cxx +++ b/EventFiltering/PWGLF/filterf1proton.cxx @@ -14,32 +14,48 @@ /// /// \author Sourav Kundu, sourav.kundu@cern.ch +#include "../filterTables.h" + +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/strangenessBuilderHelper.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/TrackParametrization.h" #include + #include #include +#include #include + #include + #include #include #include - -#include "../filterTables.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 "PWGLF/DataModel/LFStrangenessTables.h" -#include "CommonConstants/PhysicsConstants.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" +#include using namespace o2; using namespace o2::framework; @@ -151,8 +167,22 @@ struct filterf1proton { }, OutputObjHandlingPolicy::AnalysisObject}; + // helper object + o2::pwglf::strangenessBuilderHelper mStraHelper; + int mRunNumber = 0; + float mBz = 0.; + void init(o2::framework::InitContext&) { + // set V0 parameters in the helper + mStraHelper.v0selections.minCrossedRows = ConfDaughTPCnclsMin; + mStraHelper.v0selections.dcanegtopv = ConfDaughDCAMin; + mStraHelper.v0selections.dcapostopv = ConfDaughDCAMin; // get the minimum one + mStraHelper.v0selections.v0cospa = ConfV0CPAMin; + mStraHelper.v0selections.dcav0dau = ConfV0DCADaughMax; + mStraHelper.v0selections.v0radius = ConfV0TranRadV0Min; + mStraHelper.v0selections.maxDaughterEta = ConfDaughEta; + ccdb->setURL(url.value); ccdbApi.init(url); ccdb->setCaching(true); @@ -163,6 +193,26 @@ struct filterf1proton { hProcessedEvents->GetXaxis()->SetBinLabel(3, aod::filtering::TriggerEventF1Proton::columnLabel()); } + 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(url.value); + 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) { @@ -257,10 +307,10 @@ struct filterf1proton { bool isSelectedV0Daughter(T const& track, float charge, double nsigmaV0Daughter) { const auto eta = track.eta(); - const auto tpcNClsF = track.tpcNClsFound(); + // 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) { return false; } @@ -276,7 +326,6 @@ struct filterf1proton { if (std::abs(dcaXY) < ConfDaughDCAMin) { return false; } - if (std::abs(nsigmaV0Daughter) > ConfDaughPIDCuts) { return false; } @@ -393,7 +442,7 @@ struct filterf1proton { std::vector setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) { - map metadata; + std::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) { @@ -439,6 +488,7 @@ struct filterf1proton { aod::pidTPCFullPi, aod::pidTOFFullPi, aod::pidTPCFullKa, aod::pidTOFFullKa, aod::pidTPCFullPr, aod::pidTOFFullPr>>; + using PrimaryTrackCandidatesIU = soa::Filtered>; void processF1Proton(EventCandidates::iterator const& collision, aod::BCsWithTimestamps const&, PrimaryTrackCandidates const& tracks, ResoV0s const& V0s) { @@ -572,8 +622,8 @@ struct filterf1proton { if (!SelectionV0(collision, v0)) { continue; } - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); + auto postrack = v0.posTrack_as(); + auto negtrack = v0.negTrack_as(); double nTPCSigmaPos[1]{postrack.tpcNSigmaPi()}; double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; if (ConfUseManualPIDdaughterPion) { @@ -655,7 +705,207 @@ struct filterf1proton { } tags(keepEventF1Proton); } - PROCESS_SWITCH(filterf1proton, processF1Proton, "Process for trigger", true); + PROCESS_SWITCH(filterf1proton, processF1Proton, "Process for trigger", false); + TLorentzVector v0Dummy; + void processF1ProtonHelper(EventCandidates::iterator const& collision, aod::BCs const&, PrimaryTrackCandidatesIU const& tracks, aod::V0s const& V0s) + { + initCCDB(collision.bc().runNumber()); + bool keepEventF1Proton = false; + int numberF1 = 0; + if (isSelectedEvent(collision)) { + + // keep track of indices + std::vector PionIndex = {}; + std::vector KaonIndex = {}; + std::vector ProtonIndex = {}; + + // keep charge of track + std::vector PionCharge = {}; + std::vector KaonCharge = {}; + std::vector ProtonCharge = {}; + + // Prepare vectors for different species + std::vector protons, kaons, pions, kshorts; + float kstar = 999.f; + + 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 ((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()); + if (track.sign() > 0) { + qaRegistry.fill(HIST("hNsigmaPtpionTPC"), nTPCSigmaP[0], track.pt()); + } + if (track.sign() < 0) { + qaRegistry.fill(HIST("hNsigmaPtpionTPC"), nTPCSigmaN[0], track.pt()); + } + if (track.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtpionTOF"), track.tofNSigmaPi(), track.pt()); + } + } + + 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()); + if (track.sign() > 0) { + qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), nTPCSigmaP[1], track.pt()); + } + if (track.sign() < 0) { + qaRegistry.fill(HIST("hNsigmaPtkaonTPC"), nTPCSigmaN[1], track.pt()); + } + if (track.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtkaonTOF"), track.tofNSigmaKa(), track.pt()); + } + } + + 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); + qaRegistry.fill(HIST("hMommentumCorr"), track.p() / track.sign(), track.p() - track.tpcInnerParam()); + if (ConfFakeProton && !isFakeProton(track)) { + 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()); + } + if (track.sign() < 0) { + qaRegistry.fill(HIST("hNsigmaPtprotonTPC"), nTPCSigmaN[2], track.pt()); + } + if (track.hasTOF()) { + qaRegistry.fill(HIST("hNsigmaPtprotonTOF"), track.tofNSigmaPr(), track.pt()); + } + } + } // track loop end + + // keep track of daugher indices to avoid selfcorrelations + std::vector KshortPosDaughIndex = {}; + std::vector KshortNegDaughIndex = {}; + + for (auto& v0 : V0s) { + + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + auto trackparpos = getTrackParCov(postrack); + auto trackparneg = getTrackParCov(negtrack); + if (!mStraHelper.buildV0Candidate(v0.collisionId(), collision.posX(), collision.posY(), collision.posZ(), postrack, negtrack, trackparpos, trackparneg)) { + continue; + } + + if (fabs(mStraHelper.v0.dcaToPV) > cMaxV0DCA) { + continue; + } + auto v0px = mStraHelper.v0.momentum[0]; + auto v0py = mStraHelper.v0.momentum[1]; + auto v0pz = mStraHelper.v0.momentum[2]; + auto pT = std::sqrt(v0px * v0px + v0py * v0py); + if (pT < ConfV0PtMin) { + continue; + } + if (std::hypot(mStraHelper.v0.position[0], mStraHelper.v0.position[1]) < ConfV0TranRadV0Min) { + continue; + } + if (std::hypot(mStraHelper.v0.position[0], mStraHelper.v0.position[1]) > ConfV0TranRadV0Max) { + continue; + } + 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::MassK0Short > cMaxV0LifeTime) { + continue; + } + float lowmasscutks0 = 0.497 - 2.0 * cSigmaMassKs0; + float highmasscutks0 = 0.497 + 2.0 * cSigmaMassKs0; + if (mStraHelper.v0.massK0Short < lowmasscutks0 || mStraHelper.v0.massK0Short > highmasscutks0) { + continue; + } + double nTPCSigmaPos[1]{postrack.tpcNSigmaPi()}; + double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; + if (!isSelectedV0Daughter(postrack, 1, nTPCSigmaPos[0])) { + continue; + } + if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { + continue; + } + v0Dummy.SetXYZM(v0px, v0py, v0pz, mStraHelper.v0.massK0Short); + qaRegistry.fill(HIST("hInvMassk0"), v0Dummy.M(), pT); + ROOT::Math::PtEtaPhiMVector temp(pT, v0Dummy.Eta(), v0Dummy.Phi(), mStraHelper.v0.massK0Short); + 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(PionCharge.at(i1)*KaonCharge.at(i2)>0)continue; + 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) + continue; + F1Vector = KKs0Vector + pions.at(i1); + if (F1Vector.M() > cMaxMassF1) + continue; + if (F1Vector.Pt() < cMinF1Pt) + continue; + if (PionCharge.at(i1) * KaonCharge.at(i2) > 0) { + qaRegistry.fill(HIST("hInvMassf1Like"), F1Vector.M(), F1Vector.Pt()); + continue; + } + 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; + } + } + } + } + } + } + hProcessedEvents->Fill(0.5); + if (numberF1 > 0) { + hProcessedEvents->Fill(1.5); + } + if (keepEventF1Proton) { + hProcessedEvents->Fill(2.5); + } + tags(keepEventF1Proton); + } + PROCESS_SWITCH(filterf1proton, processF1ProtonHelper, "Process for trigger with helper v0 task", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfg) diff --git a/EventFiltering/PWGLF/nucleiFilter.cxx b/EventFiltering/PWGLF/nucleiFilter.cxx index 1d10c195a6f..1122cfca441 100644 --- a/EventFiltering/PWGLF/nucleiFilter.cxx +++ b/EventFiltering/PWGLF/nucleiFilter.cxx @@ -10,33 +10,53 @@ // or submit itself to any jurisdiction. // O2 includes -#include -#include +#include "../filterTables.h" +#include "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/Vtx3BodyTables.h" +#include "PWGLF/Utils/pidTOFGeneric.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsTOF/ParameterContainers.h" #include "DataFormatsTPC/BetheBlochAleph.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.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/Vtx3BodyTables.h" -#include "../filterTables.h" +#include "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +o2::common::core::MetadataHelper metadataInfo; + namespace { static constexpr int nNuclei{3}; -static constexpr int nHyperNuclei{1}; -static constexpr int nITStriggers{2}; static constexpr int nCutsPID{5}; static constexpr std::array masses{ constants::physics::MassDeuteron, constants::physics::MassTriton, @@ -45,7 +65,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{o2::aod::filtering::H2::columnLabel(), "fH3", o2::aod::filtering::He::columnLabel(), o2::aod::filtering::H3L3Body::columnLabel(), o2::aod::filtering::ITSmildIonisation::columnLabel(), o2::aod::filtering::ITSextremeIonisation::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]{ @@ -88,39 +108,66 @@ struct nucleiFilter { 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; + // TOF response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + o2::aod::pidtofgeneric::TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration // 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.15, "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", 999, "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"}; + } trgH3L3Body; HistogramRegistry qaHists{"qaHists", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - OutputObj hProcessedEvents{TH1D("hProcessedEvents", ";;Number of filtered events", nNuclei + nHyperNuclei + nITStriggers + 1, -0.5, nNuclei + nHyperNuclei + nITStriggers + 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& 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.}; @@ -130,7 +177,10 @@ 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) { @@ -142,28 +192,131 @@ 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); + + // Initialization of TOF PID parameters for fH3L3Body + mTOFCalibConfig.metadataInfo = metadataInfo; + mTOFCalibConfig.inheritFromBaseTask(initContext); + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); // Getting the parametrization parameters } - 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); + } + + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bc); + } + + 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 + nITStriggers]{false}; + std::array keepEvent{false}; // qaHists.fill(HIST("fCollZpos"), collision.posZ()); hProcessedEvents->Fill(0); // if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - tags(keepEvent[0], keepEvent[2], keepEvent[3], keepEvent[4], keepEvent[5]); + 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()))}; @@ -172,8 +325,8 @@ struct nucleiFilter { } avgClsSize = avgClsSize * cosL / track.itsNCls(); qaHists.fill(HIST("fExtremeIonisationITS"), track.itsNCls(), avgClsSize, track.p()); - keepEvent[4] = track.p() > cfgMomentumCutExtremeIonisation && avgClsSize > cfgCutClsSizeMildIonisation; - keepEvent[5] = track.p() > cfgMomentumCutExtremeIonisation && avgClsSize > cfgCutClsSizeExtremeIonisation; + keepEvent[kITSmildIonisation] = track.p() > cfgMomentumCutExtremeIonisation && avgClsSize > cfgCutClsSizeMildIonisation; + keepEvent[kITSextremeIonisation] = track.p() > cfgMomentumCutExtremeIonisation && avgClsSize > cfgCutClsSizeExtremeIonisation; } if (track.itsNCls() < cfgCutNclusITS || track.tpcNClsFound() < cfgCutNclusTPC) { @@ -184,10 +337,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()}; @@ -195,7 +346,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()); @@ -207,9 +358,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)) { @@ -218,12 +367,18 @@ 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()); } } - // // fill QA histograms // @@ -231,55 +386,240 @@ struct nucleiFilter { } // end loop over tracks - // hypertriton 3body loop - for (auto& vtx : vtx3bodydatas) { + 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; + } + } + } - auto track0 = vtx.track0_as(); - auto track1 = vtx.track1_as(); - auto track2 = vtx.track2_as(); + 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 (vtx.vtxcosPA(collision.posX(), collision.posY(), collision.posZ()) < minCosPA3body) { + bool isHe3 = nSigmas[0] > cfgCutsPID->get(2, 0u) && nSigmas[0] < cfgCutsPID->get(2, 1u); + bool isAntiHe3 = nSigmas[1] > cfgCutsPID->get(2, 0u) && nSigmas[1] < cfgCutsPID->get(2, 1u); + if (!isHe3 && !isAntiHe3) { continue; } - float ct = vtx.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * constants::physics::MassHyperTriton; - if (ct > lifetimecut) { + auto& he3Track = isHe3 ? posTrack : negTrack; + auto& piTrack = isHe3 ? negTrack : posTrack; + + int n2bodyVtx = fitter2body.process(getTrackParCov(he3Track), getTrackParCov(piTrack)); + if (n2bodyVtx == 0) { + continue; + } + auto vtxXYZ = fitter2body.getPCACandidate(); + vtxXYZ[0] -= collision.posX(); + vtxXYZ[1] -= collision.posY(); + vtxXYZ[2] -= collision.posZ(); + + std::array momHe3 = {0.}; + std::array momPi = {0.}; + std::array momTot = {0.}; + auto& hePropTrack = fitter2body.getTrack(0); + auto& piPropTrack = fitter2body.getTrack(1); + hePropTrack.getPxPyPzGlo(momHe3); + piPropTrack.getPxPyPzGlo(momPi); + for (int i = 0; i < 3; ++i) { + momHe3[i] *= 2; + momTot[i] = momHe3[i] + momPi[i]; + } + double cosPA = (vtxXYZ[0] * momTot[0] + vtxXYZ[1] * momTot[1] + vtxXYZ[2] * momTot[2]) / + std::sqrt((vtxXYZ[0] * vtxXYZ[0] + vtxXYZ[1] * vtxXYZ[1] + vtxXYZ[2] * vtxXYZ[2]) * + (momTot[0] * momTot[0] + momTot[1] * momTot[1] + momTot[2] * momTot[2])); + if (cosPA < cfgCutCosPAheV0) { continue; } - if (vtx.dcaVtxdaughters() > dcavtxdau) { + keepEvent[kHeV0] = true; + break; + } + + // fH3L3Body trigger + auto bc = collision.bc_as(); + initCCDB(bc); + + for (const auto& decay3body : decay3bodys) { + auto track0 = decay3body.track0_as(); + auto track1 = decay3body.track1_as(); + auto track2 = decay3body.track2_as(); + + // 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; } - if ((track2.tofNSigmaDe() < TofPidNsigmaMin || track2.tofNSigmaDe() > TofPidNsigmaMax) && track2.p() > minDeuteronPUseTOF) { + + if (std::abs(track0.eta()) > trgH3L3Body.minDaughtersEta || std::abs(track1.eta()) > trgH3L3Body.minDaughtersEta || std::abs(track2.eta()) > trgH3L3Body.minDaughtersEta) { 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()); + + 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()) < 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 (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; } } } - } // end loop over hypertriton 3body decay candidates + 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 (std::abs(track2.tpcNSigmaDe()) > trgH3L3Body.tpcPIDNSigmaCut || track2.p() < trgH3L3Body.minDeuteronPt || track2.p() > trgH3L3Body.maxDeuteronPt) { + continue; + } + + float tofNSigmaDeuteron = -999; + if (track2.has_collision() && track2.hasTOF()) { + auto originalcol = track2.collision_as(); + tofNSigmaDeuteron = bachelorTOFPID.GetTOFNSigma(mRespParamsV3, 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 + std::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 = std::sqrt(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 (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; + } + } + } + + keepEvent[kTracked3Body] = tracked3Bodys.size() > 0; - for (int iDecision{0}; iDecision < nNuclei + nHyperNuclei + nITStriggers; ++iDecision) { + for (int iDecision{0}; iDecision < kNtriggers; ++iDecision) { if (keepEvent[iDecision]) { hProcessedEvents->Fill(iDecision + 1); } } - tags(keepEvent[0], keepEvent[2], keepEvent[3], keepEvent[4], keepEvent[5]); + + tags(keepEvent[kH2], keepEvent[kHe], keepEvent[kHeV0], keepEvent[kTritonFemto], keepEvent[kH3L3Body], keepEvent[kTracked3Body], keepEvent[kITSmildIonisation], keepEvent[kITSextremeIonisation]); } }; WorkflowSpec defineDataProcessing(ConfigContext const& cfg) { + metadataInfo.initMetadata(cfg); return WorkflowSpec{ adaptAnalysisTask(cfg)}; } diff --git a/EventFiltering/PWGLF/strangenessFilter.cxx b/EventFiltering/PWGLF/strangenessFilter.cxx index 106e0f90bb7..33d83d92d6f 100644 --- a/EventFiltering/PWGLF/strangenessFilter.cxx +++ b/EventFiltering/PWGLF/strangenessFilter.cxx @@ -14,29 +14,36 @@ /// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) /// \since June 1, 2021 -#include +#include "../filterTables.h" + +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/strangenessBuilderHelper.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/TrackSelectionTables.h" + #include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" -#include "DCAFitter/DCAFitterN.h" #include "DetectorsBase/Propagator.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Multiplicity.h" -#include "CommonConstants/PhysicsConstants.h" -#include "../filterTables.h" +#include "ReconstructionDataFormats/TrackParametrization.h" + +#include "TVector3.h" + +#include using namespace o2; using namespace o2::framework; @@ -56,11 +63,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 +79,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 +145,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 +164,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"}; @@ -157,29 +195,126 @@ struct strangenessFilter { {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 +330,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 +353,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 +415,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 +455,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 +513,41 @@ 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()); + if (useNormalisedMult) + mMeanMultT0C = ccdb->getForRun>("Users/e/ekryshen/meanT0C", run); + if (useNormalisedMult) + 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 +556,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; - if (kint7 && !collision.alias_bit(kINT7)) { + initCCDB(collision.bc().runNumber()); + + 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 +678,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(); + // strangeness tracking selection + const auto primaryVertex = getPrimaryVertex(collision); + o2::dataformats::DCA impactParameterTrk; - bool isXi = false; - bool isXiYN = false; - bool isOmega = false; - bool isOmegalargeR = false; + std::vector> v0sSelTuple; + for (auto& v00 : v0Base) { // loop over v0 for pre selection + hCandidate->Fill(0.5); // All candidates - // 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); - - 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 + for (auto& casc : cascadesBase) { // loop over cascades + hCandidate->Fill(0.5); // All candidates - // 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; + const auto bachTrack = casc.bachelor_as(); + const auto v0Dau = casc.v0_as(); + const auto negTrack = v0Dau.negTrack_as(); + const auto posTrack = v0Dau.posTrack_as(); - for (auto& casc : fullCasc) { // loop over cascades - triggcounterForEstimates = 0; - - 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 +800,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 +1103,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 +1162,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 +1190,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 +1231,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; @@ -1292,12 +1351,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/PWGMM/multFilter.cxx b/EventFiltering/PWGMM/multFilter.cxx index cf9057a28a3..fe641438a43 100644 --- a/EventFiltering/PWGMM/multFilter.cxx +++ b/EventFiltering/PWGMM/multFilter.cxx @@ -8,24 +8,23 @@ // In applying this license CERN does 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/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" - +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "EventFiltering/filterTables.h" #include "CCDB/BasicCCDBManager.h" #include "CCDB/CcdbApi.h" #include "DataFormatsFT0/Digit.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/TrackSelection.h" + +#include +#include using namespace o2; using namespace o2::framework; @@ -58,6 +57,9 @@ struct multFilter { Configurable sel8{"sel8", 1, "apply sel8 event selection"}; Configurable selt0time{"selt0time", 0, "apply 1ns cut T0A and T0C"}; Configurable selt0vtx{"selt0vtx", 0, "apply T0 vertext trigger"}; + Configurable isTimeFrameBorderCut{"isTimeFrameBorderCut", 1, "apply timeframe border cut"}; + Configurable isSameBunchPileup{"isSameBunchPileup", 1, "apply same bunch pileup cut"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", 1, "apply good vtx FT0vsPV cut"}; Configurable avPyT0A{"avPyT0A", 8.16, "nch from pythia T0A"}; Configurable avPyT0C{"avPyT0C", 8.83, "nch from pythia T0C"}; @@ -358,6 +360,19 @@ struct multFilter { return; } + if (isTimeFrameBorderCut && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + tags(false, false, false, false, false, false, false); + return; + } + if (isSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + tags(false, false, false, false, false, false, false); + return; + } + if (isGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + tags(false, false, false, false, false, false, false); + return; + } + multiplicity.fill(HIST("hMultFV0sel"), sumAmpFV0); multiplicity.fill(HIST("hMultFV01to4Ringsel"), sumAmpFV01to4Ring); multiplicity.fill(HIST("hMultFV05Ringsel"), sumAmpFV05Ring); diff --git a/EventFiltering/PWGUD/diffractionFilter.cxx b/EventFiltering/PWGUD/diffractionFilter.cxx index 4ea29ab18a0..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*/, @@ -162,6 +167,7 @@ struct DGFilterRun3 { // apply DG selection auto isDGEvent = dgSelector.IsSelected(diffCuts, collision, bcRange, tracks, fwdtracks); + LOGF(debug, "isDGEvent %d", isDGEvent); // update after cut histogram registry.fill(HIST("stat/aftercuts"), isDGEvent + 2); @@ -226,8 +232,9 @@ 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); diff --git a/EventFiltering/cefpTask.cxx b/EventFiltering/cefpTask.cxx index 92d0ed8f6bc..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 { @@ -214,8 +214,10 @@ struct centralEventFilterTask { 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); @@ -226,6 +228,7 @@ struct centralEventFilterTask { FILTER_CONFIGURABLE(MultFilters); FILTER_CONFIGURABLE(FullJetFilters); FILTER_CONFIGURABLE(PhotonFilters); + FILTER_CONFIGURABLE(HeavyNeutralMesonFilters); void init(o2::framework::InitContext& initc) { @@ -272,11 +275,11 @@ struct centralEventFilterTask { { // 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)}; @@ -357,21 +360,24 @@ struct centralEventFilterTask { mFiltered->SetBinContent(1, mFiltered->GetBinContent(1) + nEvents - startCollision); for (uint64_t iE{0}; iE < outTrigger.size(); ++iE) { + const auto& triggerWord{outTrigger[iE]}; bool triggered{false}, selected{false}; - for (uint64_t iD{0}; iD < outTrigger[0].size(); ++iD) { + 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 (uint64_t 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); } } } } - triggered = triggered || outTrigger[iE][iD]; + triggered = triggered || triggerWord[iD]; selected = selected || outDecision[iE][iD]; } if (triggered) { @@ -390,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 48bf53fc364..1371d152e75 100644 --- a/EventFiltering/filterTables.h +++ b/EventFiltering/filterTables.h @@ -15,15 +15,42 @@ #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(H2, hasH2, bool); //! deuteron trigger for the helium normalisation (to be downscaled) -DECLARE_SOA_COLUMN(He, hasHe, bool); //! helium -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 @@ -42,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 @@ -104,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 @@ -111,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 @@ -134,6 +194,19 @@ 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(OmegaP, hasOmegaP, bool); //! omegaP meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(OmegaPP, hasOmegaPP, bool); //! omegaPP meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(Omegad, hasOmegad, bool); //! omegad meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(EtaPrimeP, hasEtaPrimeP, bool); //! eta'P meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(EtaPrimePP, hasEtaPrimePP, bool); //! eta'PP meson candidate (3pi) in the collision +DECLARE_SOA_COLUMN(EtaPrimed, hasEtaPrimed, bool); //! eta'd meson candidate (3pi) in the collision + } // namespace filtering namespace decision @@ -160,7 +233,7 @@ DECLARE_SOA_COLUMN(BCend, hasBCend, uint64_t); //! CEFP bcrange // nuclei DECLARE_SOA_TABLE(NucleiFilters, "AOD", "NucleiFilters", //! - filtering::H2, filtering::He, filtering::H3L3Body, filtering::ITSmildIonisation, + filtering::H2, filtering::He, filtering::HeV0, filtering::TritonFemto, filtering::H3L3Body, filtering::Tracked3Body, filtering::ITSmildIonisation, filtering::ITSextremeIonisation); using NucleiFilter = NucleiFilters::iterator; @@ -175,17 +248,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 @@ -212,7 +321,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; @@ -221,6 +330,11 @@ DECLARE_SOA_TABLE(F1ProtonFilters, "AOD", "F1ProtonFilters", //! filtering::TriggerEventF1Proton); using F1ProtonFilter = F1ProtonFilters::iterator; +// Double Phi +DECLARE_SOA_TABLE(DoublePhiFilters, "AOD", "LF2PhiFilters", //! + 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); @@ -233,6 +347,13 @@ DECLARE_SOA_TABLE(PhotonFilters, "AOD", "PhotonFilters", //! using PhotonFilter = PhotonFilters::iterator; +// heavy mesons +DECLARE_SOA_TABLE(HeavyNeutralMesonFilters, "AOD", "HNMesonFilters", //! + filtering::OmegaP, filtering::OmegaPP, filtering::Omegad, + filtering::EtaPrimeP, filtering::EtaPrimePP, filtering::EtaPrimed); + +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); @@ -244,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", "LF2PhiFilters", "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-neutral-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 @@ -271,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 index 59520484b4f..f71212238c3 100644 --- a/EventFiltering/macros/checkBCrangesSkimming.C +++ b/EventFiltering/macros/checkBCrangesSkimming.C @@ -10,13 +10,14 @@ // or submit itself to any jurisdiction. // O2 includes -#include -#include -#include #include #include -#include #include +#include +#include +#include +#include +#include #include "CommonDataFormat/InteractionRecord.h" #include "CommonDataFormat/IRFrame.h" @@ -24,9 +25,7 @@ using o2::InteractionRecord; using o2::dataformats::IRFrame; // Set the bit of trigger which need to be checked -const ULong64_t Trigger0BIT = BIT(61); -const ULong64_t Trigger1BIT = 0; -const ULong64_t bcDiffTolerance = 100; +const ULong64_t bcDiffTolerance = 0; const char outputFileName[15] = "output.root"; struct bcTuple { @@ -40,28 +39,51 @@ struct bcTuple { }; 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 SetNum(int n) { numSameTriggerInNearbyBCs = n; } - int GetNum() { return numSameTriggerInNearbyBCs; } + 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() < b.getMin() - bcDiffTolerance) + if (a.getMin() > b.getMax() + bcDiffTolerance || a.getMax() + bcDiffTolerance < b.getMin()) return false; else return true; } -std::vector getSelectedFrames(TFile& file, ULong64_t trigger0Bit, ULong64_t trigger1Bit) +std::vector> getFrames(std::unique_ptr& file, int trgIDStart, int N) { - std::vector selectedFrames; ULong64_t bcAO2D{0ull}, bcEvSel{0ull}, triMask[2]{0ull}, selMask[2]{0ull}; - for (auto key : *file.GetListOfKeys()) { - auto dir = dynamic_cast(file.Get(key->GetName())); + std::vector> frames; + frames.resize(N); + for (auto key : *file->GetListOfKeys()) { + auto dir = dynamic_cast(file->Get(key->GetName())); if (!dir) { continue; } @@ -86,69 +108,274 @@ std::vector getSelectedFrames(TFile& file, ULong64_t trigger0Bit if (!selMask[0] && !selMask[1]) { continue; } - 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); - selectedFrames.push_back({bcAO2D, bcEvSel, triMask, selMask, frame}); + 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 selectedFrames; + + 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) { - return a.getMin() < b.getMin(); + if (a.getMin() != b.getMin()) { + return a.getMin() < b.getMin(); + } else { + return a.getMax() < b.getMax(); + } }); - int firstID = 0; + int firstTrg = 0; for (auto& currentFrame : frames) { int num = 0; - bool isFirst = true; - for (int i = firstID; i < frames.size(); i++) { + 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)) { - isFirst = false; + shouldUpdate = false; bool found = currentFrame.selMask[0] & frame.selMask[0] || currentFrame.selMask[1] & frame.selMask[1]; if (found) { num++; } } else { - if (isFirst) { - firstID = i; + if (shouldUpdate) { + firstTrg = i; } } } - currentFrame.SetNum(num); + currentFrame.SetNInNearbyBC(num); } } -// Calulate the ratio of duplicate triggers -void checkDuplicateTriggerAndBCs(std::string AnaFileName = "AnalysisResults.root", std::string originalFileName = "bcRanges_fullrun.root", std::string skimmedFileName = "bcRanges_fullrun_skimmed.root") +// Get RunNumber +std::string getRunNumber(std::string fileName) { - - // Get RunNumber std::string runNumber = ""; std::regex re("/5[0-9]*"); std::smatch match; - if (std::regex_search(originalFileName, match, re)) { + 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); + } - // Checks for BC difference between original and skimming data, and the ratio of triggers which have BCdiff==0 - TH1D hPairedNumCounterTotal("hPairedNumCounterTotal", "hPairedNumCounterTotal", 10, -0.5, 9.5); - TH1D hBCDiffAO2DTotal("hBCDiffAO2DTotal", "hBCDiffAO2DTotal", 21, -10.5, 10.5); - TH1D hBCDiffEvSelTotal("hBCDiffEvSelTotal", "hBCDiffEvSelTotal", 21, -10.5, 10.5); + //------------------------------ 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 - TFile AnaFile(AnaFileName.c_str(), "READ"); - TH1* hist0 = dynamic_cast(AnaFile.Get("central-event-filter-task/scalers/mFiltered;1")); + 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++) { @@ -156,381 +383,298 @@ void checkDuplicateTriggerAndBCs(std::string AnaFileName = "AnalysisResults.root 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(); + AnaFile->Close(); - TFile originalFile(originalFileName.c_str(), "READ"); - TFile skimmedFile(skimmedFileName.c_str(), "READ"); + // 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; + std::vector numOriginal, numSkimmed, numOriginalSingle, numSkimmedSingle, numOriginalDouble, numSkimmedDouble, numOriginalMultiple, numSkimmedMultiple, numCloseSkimmed; std::vector numpair, numpairedBCAO2D, numpairedBCEvSel; - for (int i = 0; i < labels.size(); i++) { - // std::cout << "i:" << i << std::endl; - ULong64_t trigger0Bit = 0, trigger1Bit = 0; - int triggerBit = binNum[i] - 2; - if (triggerBit < 64) { - trigger0Bit = BIT(triggerBit); - } else { - trigger1Bit = BIT(triggerBit - 64); - } + 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 - // For Original dataset - std::vector bcSet; - std::vector bcFullSet; int noriginal{0}, nskimmed{0}, noriginalsingle{0}, nskimmedsingle{0}, noriginaldouble{0}, nskimmeddouble{0}, noriginalmultiple{0}, nskimmedmultiple{0}; - auto originalFrames = getSelectedFrames(originalFile, trigger0Bit, trigger1Bit); - checkNearbyBCs(originalFrames, bcDiffTolerance); + // 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.GetNum() == 0) { + if (originalFrame.GetNInNearbyBC() == 0) { std::cerr << "Unexpected trigger!!! " << std::endl; - } else if (originalFrame.GetNum() == 1) { + } else if (originalFrame.GetNInNearbyBC() == 1) { noriginalsingle++; - } else if (originalFrame.GetNum() == 2) { + } else if (originalFrame.GetNInNearbyBC() == 2) { noriginaldouble++; } else { noriginalmultiple++; } } // For skimmed dataset - auto skimmedFrames = getSelectedFrames(skimmedFile, trigger0Bit, trigger1Bit); - checkNearbyBCs(skimmedFrames, bcDiffTolerance); + auto& skimmedFrames = skimmedAllFrames[trgID]; + checkNearbyBCs(skimmedFrames, bcDiffTolerance); // include sorting nskimmed = skimmedFrames.size(); for (auto& skimmedFrame : skimmedFrames) { - if (skimmedFrame.GetNum() == 0) { + if (skimmedFrame.GetNInNearbyBC() == 0) { std::cerr << "Unexpected trigger!!! " << std::endl; - } else if (skimmedFrame.GetNum() == 1) { + } else if (skimmedFrame.GetNInNearbyBC() == 1) { nskimmedsingle++; - } else if (skimmedFrame.GetNum() == 2) { + } else if (skimmedFrame.GetNInNearbyBC() == 2) { nskimmeddouble++; } else { nskimmedmultiple++; } } - sel_labels.push_back(labels[i]); - 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); - // Check BC differences - int npair{0}, npairedBCAO2D{0}, npairedBCEvSel{0}; - int firstID = 0; - for (auto frame : originalFrames) { - if (frame.selMask[0] & trigger0Bit || frame.selMask[1] & trigger1Bit) { - // std::cout << "------------------------------------------------" << std::endl; - if (frame.GetNum() != 1) { + 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 } - std::vector skimmedbcs; - int n = 0; - bool isFirst = true; - for (int i = firstID; i < skimmedFrames.size(); i++) { - auto& skimmedFrame = skimmedFrames[i]; - if (skimmedFrame.getMin() > frame.getMax()) { - break; - } - if (skimmedFrame.GetNum() != 1) { - continue; // Only check singles - } - if (isClose(frame, skimmedFrame, bcDiffTolerance)) { - isFirst = false; - bool found = frame.selMask[0] & skimmedFrame.selMask[0] || frame.selMask[1] & skimmedFrame.selMask[1]; - // found = found && (frame.bcAO2D == skimmedFrame.bcAO2D || frame.bcEvSel == skimmedFrame.bcEvSel); - if (found) { - skimmedbcs.push_back({skimmedFrame.bcAO2D, skimmedFrame.bcEvSel}); - n++; + 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; } - } else { - if (isFirst) { - firstID = i; + 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++; } - } - if (n == 1) { - npair++; - hBCDiffAO2DTotal.Fill(frame.bcAO2D - skimmedbcs[0].bcAO2D); - hBCDiffEvSelTotal.Fill(frame.bcEvSel - skimmedbcs[0].bcEvSel); - if (frame.bcAO2D == skimmedbcs[0].bcAO2D) { - npairedBCAO2D++; - } - if (frame.bcEvSel == skimmedbcs[0].bcEvSel) { - npairedBCEvSel++; + } else { + if (shouldUpdate) { + firstTrg = j; } } - hPairedNumCounterTotal.Fill(n); } + 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 + " AO2D 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 hOriginalSinglesRatio("hOriginalSinglesRatio", (runNumber + " Original;;Singles / Total").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 hOriginalDoublesRatio("hOriginalDoublesRatio", (runNumber + " Original;;Doubles / Total").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 hOriginalMultiplesRatio("hOriginalMultiplesRatio", (runNumber + " Original;;Multiples / Total").data(), sel_labels.size(), 0, sel_labels.size()); - - TH1D hSkimmedTotal("hSkimmedTotal", (runNumber + " AO2D 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 hSkimmedSinglesRatio("hSkimmedSinglesRatio", (runNumber + " Skimmed;;Singles / Total").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 hSkimmedDoublesRatio("hSkimmedDoublesRatio", (runNumber + " Skimmed;;Doubles / Total").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 hSkimmedMultiplesRatio("hSkimmedMultiplesRatio", (runNumber + " Skimmed;;Multiples / Total").data(), sel_labels.size(), 0, sel_labels.size()); - - TH1D hPairedBCAO2DRatio("hPairedBCAO2DRatio", (runNumber + " One-to-One Pairs;; Pairs with same BCAO2D / Total").data(), sel_labels.size(), 0, sel_labels.size()); - TH1D hPairedBCEvSelRatio("hPairedBCEvSelRatio", (runNumber + " One-to-One Pairs;; Pairs with same BCEvSel / Total").data(), sel_labels.size(), 0, sel_labels.size()); + 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()); - hOriginalSinglesRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); - hOriginalDoublesRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); - hOriginalMultiplesRatio.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]); - if (numOriginal[i] > 0) { - hOriginalSinglesRatio.SetBinContent(i + 1, static_cast(numOriginalSingle[i]) / numOriginal[i]); - hOriginalDoublesRatio.SetBinContent(i + 1, static_cast(numOriginalSingle[i]) / numOriginal[i]); - hOriginalMultiplesRatio.SetBinContent(i + 1, static_cast(numOriginalMultiple[i]) / numOriginal[i]); - } else { - hOriginalSinglesRatio.SetBinContent(i + 1, 0); - hOriginalDoublesRatio.SetBinContent(i + 1, 0); - hOriginalMultiplesRatio.SetBinContent(i + 1, 0); - } + 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()); - hSkimmedSinglesRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); - hSkimmedDoublesRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); - hSkimmedMultiplesRatio.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]); - if (numSkimmed[i] > 0) { - hSkimmedSinglesRatio.SetBinContent(i + 1, static_cast(numSkimmedSingle[i]) / numSkimmed[i]); - hSkimmedDoublesRatio.SetBinContent(i + 1, static_cast(numSkimmedDouble[i]) / numSkimmed[i]); - hSkimmedMultiplesRatio.SetBinContent(i + 1, static_cast(numSkimmedMultiple[i]) / numSkimmed[i]); - } else { - hSkimmedSinglesRatio.SetBinContent(i + 1, 0); - hSkimmedDoublesRatio.SetBinContent(i + 1, 0); - hSkimmedMultiplesRatio.SetBinContent(i + 1, 0); - } + 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()); - hPairedBCAO2DRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); - hPairedBCEvSelRatio.GetXaxis()->SetBinLabel(i + 1, sel_labels[i].c_str()); if (numpair[i] > 0) { - hPairedBCAO2DRatio.SetBinContent(i + 1, static_cast(numpairedBCAO2D[i]) / numpair[i]); - hPairedBCEvSelRatio.SetBinContent(i + 1, static_cast(numpairedBCEvSel[i]) / numpair[i]); + 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(); + hOriginalSinglesRatio->Write(); + hOriginalDoublesRatio->Write(); + hOriginalMultiplesRatio->Write(); hSkimmedTotal.Write(); hSkimmedSingles.Write(); hSkimmedDoubles.Write(); hSkimmedMultiples.Write(); - hSkimmedSinglesRatio.Write(); - hSkimmedDoublesRatio.Write(); - hSkimmedMultiplesRatio.Write(); - hPairedNumCounterTotal.Write(); - hBCDiffAO2DTotal.Write(); - hBCDiffEvSelTotal.Write(); - hPairedBCAO2DRatio.Write(); - hPairedBCEvSelRatio.Write(); + hSkimmedSinglesRatio->Write(); + hSkimmedDoublesRatio->Write(); + hSkimmedMultiplesRatio->Write(); + hMatchesSameBCAO2DRatio.Write(); + hMatchesSameBCEvSelRatio.Write(); fout.Close(); -} -void checkBCrangesSkimming(std::string originalFileName = "bcRanges_fullrun.root", std::string skimmedFileName = "bcRanges_fullrun_skimmed.root") -{ - //---------------------------------For specific trigger---------------------------------- - TH1D hTriggerCounter("hTriggerCounter", "hTriggerCounter", 3, 0.5, 3.5); - hTriggerCounter.GetXaxis()->SetBinLabel(1, "Original"); - hTriggerCounter.GetXaxis()->SetBinLabel(2, "Skimmed"); - TH1D hNumCounter("hNumCounter", "hNumCounter", 10, -0.5, 9.5); - TH1D hSinglePairCheck("hSinglePairCheck", "hSinglePairCheck", 4, 0.5, 4.5); - hSinglePairCheck.GetXaxis()->SetBinLabel(1, "Total"); - hSinglePairCheck.GetXaxis()->SetBinLabel(2, "Same AO2D BC"); - hSinglePairCheck.GetXaxis()->SetBinLabel(3, "Same EvSel BC"); - hSinglePairCheck.GetXaxis()->SetBinLabel(4, "Same Both BC"); - TH1D hMultiPairCheck("hMultiPairCheck", "hMultiPairCheck", 5, 0.5, 5.5); - hMultiPairCheck.GetXaxis()->SetBinLabel(1, "Total"); - hMultiPairCheck.GetXaxis()->SetBinLabel(2, "Total Pair"); - hMultiPairCheck.GetXaxis()->SetBinLabel(3, "Same AO2D BC"); - hMultiPairCheck.GetXaxis()->SetBinLabel(4, "Same EvSel BC"); - hMultiPairCheck.GetXaxis()->SetBinLabel(5, "Same Both BC"); - TH1D hBCDiffAO2D("hBCDiffAO2D", "hBCDiffAO2D", 21, -10.5, 10.5); - TH1D hBCDiffEvSel("hBCDiffEvSel", "hBCDiffEvSel", 21, -10.5, 10.5); - - TH1D hBCOriginal("hBCOriginal", "hBCOriginal", 4, 0.5, 4.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", "hBCSkimmed", 4, 0.5, 4.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"); - - auto t1 = std::chrono::steady_clock::now(); - TFile originalFile(originalFileName.c_str(), "READ"); - TFile skimmedFile(skimmedFileName.c_str(), "READ"); - auto originalFrames = getSelectedFrames(originalFile, Trigger0BIT, Trigger1BIT); - auto skimmedFrames = getSelectedFrames(skimmedFile, Trigger0BIT, Trigger1BIT); - originalFile.Close(); - skimmedFile.Close(); - auto t2 = std::chrono::steady_clock::now(); - int d1 = std::chrono::duration_cast(t2 - t1).count(); - std::cout << "Readin Time: " << d1 << std::endl; - - auto t3 = std::chrono::steady_clock::now(); - checkNearbyBCs(originalFrames, bcDiffTolerance); - checkNearbyBCs(skimmedFrames, bcDiffTolerance); - auto t4 = std::chrono::steady_clock::now(); - int d2 = std::chrono::duration_cast(t4 - t3).count(); - std::cout << "Sort Time: " << d2 << std::endl; - - auto t5 = std::chrono::steady_clock::now(); - std::vector bcSet; - for (auto frame : originalFrames) { - if (frame.selMask[0] & Trigger0BIT || frame.selMask[1] & Trigger1BIT) { - hTriggerCounter.Fill(1); - hBCOriginal.Fill(1); - auto p1 = std::find_if(bcSet.begin(), bcSet.end(), [&](const auto& val) { return val.bcAO2D == frame.bcAO2D; }); - if (p1 != bcSet.end()) { - hBCOriginal.Fill(2); - } - auto p2 = std::find_if(bcSet.begin(), bcSet.end(), [&](const auto& val) { return val.bcEvSel == frame.bcEvSel; }); - if (p2 != bcSet.end()) { - hBCOriginal.Fill(3); - } - 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(4); - } - // std::cout << "------------------------------------------------" << std::endl; - if (frame.GetNum() != 1) { - continue; // Only check singles - } - std::vector skimmedbcs; - int n = 0; - for (auto& skimmedFrame : skimmedFrames) { - if (skimmedFrame.getMin() > frame.getMax()) { - break; - } - if (skimmedFrame.GetNum() != 1) { - continue; // Only check singles - } - if (isClose(frame, skimmedFrame, bcDiffTolerance)) { - bool found = frame.selMask[0] & skimmedFrame.selMask[0] || frame.selMask[1] & skimmedFrame.selMask[1]; - // found = found && (frame.bcAO2D == skimmedFrame.bcAO2D || frame.bcEvSel == skimmedFrame.bcEvSel); - if (found) { - skimmedbcs.push_back({skimmedFrame.bcAO2D, skimmedFrame.bcEvSel}); - n++; - } - } - } - if (n == 0) { - // std::cout << "Trigger not found!!!" << std::endl; - } else if (n == 1) { - hSinglePairCheck.Fill(1); - hBCDiffAO2D.Fill(frame.bcAO2D - skimmedbcs[0].bcAO2D); - hBCDiffEvSel.Fill(frame.bcEvSel - skimmedbcs[0].bcEvSel); - if (frame.bcAO2D == skimmedbcs[0].bcAO2D) { - hSinglePairCheck.Fill(2); - } - if (frame.bcEvSel == skimmedbcs[0].bcEvSel) { - hSinglePairCheck.Fill(3); - if (frame.bcAO2D == skimmedbcs[0].bcAO2D) { - hSinglePairCheck.Fill(4); - } - } - } else { - // std::cout << "Unexpected trigger!!! n=" << n << std::endl; - hMultiPairCheck.Fill(1); - for (auto skimmedbc : skimmedbcs) { - hMultiPairCheck.Fill(2); - if (frame.bcAO2D == skimmedbc.bcAO2D) { - hMultiPairCheck.Fill(3); - } - if (frame.bcEvSel == skimmedbc.bcEvSel) { - hMultiPairCheck.Fill(4); - if (frame.bcAO2D == skimmedbc.bcAO2D) { - hMultiPairCheck.Fill(5); - } - } - } - } - hNumCounter.Fill(n); - } - } - auto t6 = std::chrono::steady_clock::now(); - int d3 = std::chrono::duration_cast(t6 - t5).count(); - std::cout << "Search Time: " << d3 << std::endl; - - bcSet.clear(); - for (auto& skimmedFrame : skimmedFrames) { - if (skimmedFrame.selMask[0] & Trigger0BIT || skimmedFrame.selMask[1] & Trigger1BIT) { - hTriggerCounter.Fill(2); - hBCSkimmed.Fill(1); - auto p1 = std::find_if(bcSet.begin(), bcSet.end(), [&](const auto& val) { return val.bcAO2D == skimmedFrame.bcAO2D; }); - if (p1 != bcSet.end()) { - hBCSkimmed.Fill(2); - } - auto p2 = std::find_if(bcSet.begin(), bcSet.end(), [&](const auto& val) { return val.bcEvSel == skimmedFrame.bcEvSel; }); - if (p2 != bcSet.end()) { - hBCSkimmed.Fill(3); - } - 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(4); - } - } + // 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]); + //} } - - TFile fout(outputFileName, "RECREATE"); - fout.cd(); - hTriggerCounter.Write(); - hBCOriginal.Write(); - hBCSkimmed.Write(); - hNumCounter.Write(); - hSinglePairCheck.Write(); - hBCDiffAO2D.Write(); - hBCDiffEvSel.Write(); - hMultiPairCheck.Write(); - fout.Close(); } diff --git a/EventFiltering/macros/getMenu.C b/EventFiltering/macros/getMenu.C new file mode 100644 index 00000000000..02386a68870 --- /dev/null +++ b/EventFiltering/macros/getMenu.C @@ -0,0 +1,123 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void getMenu(int runNumber, std::string baseCCDBPath = "Users/m/mpuccio/EventFiltering/OTS/Chunked/") +{ + auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); + TH1* counters = ccdb.getForRun(baseCCDBPath + "FilterCounters", runNumber); + TAxis* axis = counters->GetXaxis(); + + std::vector binLabels(axis->GetNbins() - 2); // skip first and last bins + std::cout << "Menu for run " << runNumber << ":\n"; + for (int i = 2; i < axis->GetNbins(); ++i) { + binLabels[i - 1] = axis->GetBinLabel(i); + std::cout << "Id " << i - 2 << ": " << axis->GetBinLabel(i) << "\n"; + } +} + +std::vector getMenuForPeriod(std::string period) +{ + std::regex pattern(R"(LHC(\d{2})[A-Za-z]{1,2})"); + std::smatch match; + + int year{2000}; + if (!std::regex_match(period, match, pattern)) { + std::cout << "Invalid format for period: " << period << std::endl; + return {}; + } + + year += std::stoi(match[1]); + gSystem->Exec(Form("alien_find /alice/data/%i/%s/ ctf_skim_full/AnalysisResults_fullrun.root > list_tmp_%s.txt", year, period.data(), period.data())); + + std::ifstream file(Form("list_tmp_%s.txt", period.data())); + if (!file) { + std::cerr << "Error: could not open file for period " << period << "\n"; + return {}; + } + + std::string firstLine; + if (!std::getline(file, firstLine)) { + std::cerr << "Error: file is empty or read failed for period " << period << "\n"; + return {}; + } + + TGrid::Connect("alien://"); + TFile* scalersFile = TFile::Open((std::string("alien://") + firstLine).data(), "READ"); + TH1D* counters = (TH1D*)scalersFile->Get("central-event-filter-task/scalers/mFiltered"); + TAxis* axis = counters->GetXaxis(); + + std::vector binLabels(axis->GetNbins() - 2); + for (int i = 2; i < axis->GetNbins(); ++i) { + binLabels[i - 2] = axis->GetBinLabel(i); + } + + scalersFile->Close(); + delete scalersFile; + gSystem->Exec(Form("rm list_tmp_%s.txt", period.data())); + + return binLabels; +} + +void getMenu(std::string periods) +{ + std::stringstream ss(periods); + std::string period; + std::vector periodList; + + // Parse comma-separated periods + while (std::getline(ss, period, ',')) { + // Trim whitespace + period.erase(0, period.find_first_not_of(" \t")); + period.erase(period.find_last_not_of(" \t") + 1); + periodList.push_back(period); + } + + std::map, std::vector> menuGroups; + + // Get menus for each period + for (const auto& p : periodList) { + auto menu = getMenuForPeriod(p); + if (!menu.empty()) { + menuGroups[menu].push_back(p); + } + } + + // Report different menus + int menuId = 1; + for (const auto& [menu, periods] : menuGroups) { + std::cout << "\n=== Menu " << menuId++ << " (periods: "; + for (size_t i = 0; i < periods.size(); ++i) { + std::cout << periods[i]; + if (i < periods.size() - 1) + std::cout << ", "; + } + std::cout << ") ===\n"; + + for (size_t i = 0; i < menu.size(); ++i) { + std::cout << "Id " << i << ": " << menu[i] << "\n"; + } + } +} diff --git a/EventFiltering/macros/uploadOTSobjects.C b/EventFiltering/macros/uploadOTSobjects.C index 132f1b618da..ec60c44ec0a 100644 --- a/EventFiltering/macros/uploadOTSobjects.C +++ b/EventFiltering/macros/uploadOTSobjects.C @@ -10,12 +10,10 @@ // or submit itself to any jurisdiction. // -#include -#include -#include -#include -#include -#include +#include "Common/Core/ZorroHelper.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" #include "TFile.h" #include "TGrid.h" @@ -24,18 +22,26 @@ #include "TSystem.h" #include "TTree.h" -#include "CCDB/BasicCCDBManager.h" -#include "EventFiltering/ZorroHelper.h" +#include +#include +#include +#include +#include +#include +#include + +constexpr uint32_t chunkSize = 1000000; -void uploadOTSobjects(std::string inputList, std::string passName, bool useAlien) +void uploadOTSobjects(std::string inputList, std::string passName, bool useAlien, bool chunkedProcessing = true) { - const std::string kBaseCCDBPath = "Users/m/mpuccio/EventFiltering/OTS/"; + const std::string kBaseCCDBPath = "EventFiltering/Zorro/"; std::string baseCCDBpath = passName.empty() ? kBaseCCDBPath : kBaseCCDBPath + passName + "/"; 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; @@ -47,17 +53,26 @@ void uploadOTSobjects(std::string inputList, std::string passName, bool useAlien const int runNumber = std::stoi(runString); metadata["runNumber"] = runString; std::pair duration = o2::ccdb::BasicCCDBManager::getRunDuration(api, runNumber); - duration.first -= 10000; // subtract 3 minutes from the run start - duration.second += 180000; // add 3 minutes to the run duration + 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); - api.storeAsTFile(filters, baseCCDBpath + "SelectionCounters", metadata, duration.first, duration.second); + 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); + if (!hCounterTVX) { + hCounterTVX = static_cast(scalersFile->Get("lumi-task/hCounterTVX")); + if (!hCounterTVX) { + std::cout << "No hCounterTVX histogram found in the file, skipping upload for run " << runString << std::endl; + continue; + } + } + 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")}; @@ -85,7 +100,42 @@ void uploadOTSobjects(std::string inputList, std::string passName, bool useAlien } } } - api.storeAsTFileAny(&zorroHelpers, baseCCDBpath + "ZorroHelpers", metadata, duration.first, duration.second); + 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(); + } + } } } @@ -93,5 +143,5 @@ void uploadOTSobjects(std::string periodName) { 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); + uploadOTSobjects(Form("list_%s.txt", periodName.data()), "", true, true); } 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/CMakeLists.txt b/PWGCF/CMakeLists.txt index 7432d5c21b1..84f1b6c6d41 100644 --- a/PWGCF/CMakeLists.txt +++ b/PWGCF/CMakeLists.txt @@ -24,3 +24,4 @@ add_subdirectory(TwoParticleCorrelations) add_subdirectory(JCorran) add_subdirectory(Femto3D) add_subdirectory(EbyEFluctuations) +add_subdirectory(Femto) diff --git a/PWGCF/Core/AnalysisConfigurableCuts.h b/PWGCF/Core/AnalysisConfigurableCuts.h index c35d24430c6..820911c5832 100644 --- a/PWGCF/Core/AnalysisConfigurableCuts.h +++ b/PWGCF/Core/AnalysisConfigurableCuts.h @@ -8,15 +8,22 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. + +/// \file AnalysisConfigurableCuts.h +/// \brief Convenience classes to support configurable cuts +/// \author victor.gonzalez.sebastian@gmail.com + #ifndef PWGCF_CORE_ANALYSISCONFIGURABLECUTS_H_ #define PWGCF_CORE_ANALYSISCONFIGURABLECUTS_H_ +#include +#include +#include + +#include + #include #include -#include -#include -#include -#include namespace o2 { @@ -86,27 +93,30 @@ 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 mITSclusters = 0; ///< minimum number of ITS clusters + bool mUseITSclusters = false; ///< use or not the number of ITS 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 diff --git a/PWGCF/Core/CorrelationContainer.cxx b/PWGCF/Core/CorrelationContainer.cxx index a910cf2d1b9..3267cda3988 100644 --- a/PWGCF/Core/CorrelationContainer.cxx +++ b/PWGCF/Core/CorrelationContainer.cxx @@ -115,7 +115,7 @@ CorrelationContainer::CorrelationContainer(const char* name, const char* objTitl triggerAxis.insert(triggerAxis.end(), userAxis.begin(), userAxis.end()); mTriggerHist = HistFactory::createHist({"mTriggerHist", "d^{2}N_{ch}/d#varphid#eta", {HistType::kStepTHnF, triggerAxis, fgkCFSteps}}).release(); - mTrackHistEfficiency = HistFactory::createHist({"mTrackHistEfficiency", "Tracking efficiency", {HistType::kStepTHnD, {efficiencyAxis[0], efficiencyAxis[1], {4, -0.5, 3.5, "species"}, correlationAxis[3], efficiencyAxis[2]}, fgkCFSteps}}).release(); + mTrackHistEfficiency = HistFactory::createHist({"mTrackHistEfficiency", "Tracking efficiency", {HistType::kStepTHnF, {efficiencyAxis[0], efficiencyAxis[1], {5, -0.5, 4.5, "species"}, correlationAxis[3], efficiencyAxis[2]}, fgkCFSteps}}).release(); mEventCount = HistFactory::createHist({"mEventCount", ";step;centrality;count", {HistType::kTH2F, {{fgkCFSteps + 2, -2.5, -0.5 + fgkCFSteps, "step"}, correlationAxis[3]}}}).release(); } @@ -309,7 +309,7 @@ void CorrelationContainer::resetBinLimits(THnBase* grid, int max_dimension) for (Int_t i = 0; i < max_dimension; i++) { if (grid->GetAxis(i)->TestBit(TAxis::kAxisRange)) { - grid->GetAxis(i)->SetRangeUser(0, -1); + grid->GetAxis(i)->SetRange(0, 0); // reset range } } } @@ -681,8 +681,11 @@ TH2* CorrelationContainer::getSumOfRatios(CorrelationContainer* mixed, Correlati Double_t sums[] = {0, 0, 0}; Double_t errors[] = {0, 0, 0}; + Int_t checkBinYBegin = 1; // tracksSame->GetXaxis()->FindBin(-0.79); + Int_t checkBinYEnd = tracksSame->GetNbinsY(); // tracksSame->GetXaxis()->FindBin(0.79); + for (Int_t x = 1; x <= tracksSame->GetNbinsX(); x++) { - for (Int_t y = 1; y <= tracksSame->GetNbinsY(); y++) { + for (Int_t y = checkBinYBegin; y <= checkBinYEnd; y++) { sums[0] += tracksSame->GetBinContent(x, y); errors[0] += tracksSame->GetBinError(x, y); sums[1] += tracksMixed->GetBinContent(x, y); @@ -693,7 +696,7 @@ TH2* CorrelationContainer::getSumOfRatios(CorrelationContainer* mixed, Correlati tracksSame->Divide(tracksMixed); for (Int_t x = 1; x <= tracksSame->GetNbinsX(); x++) { - for (Int_t y = 1; y <= tracksSame->GetNbinsY(); y++) { + for (Int_t y = checkBinYBegin; y <= checkBinYEnd; y++) { sums[2] += tracksSame->GetBinContent(x, y); errors[2] += tracksSame->GetBinError(x, y); } diff --git a/PWGCF/DataModel/CorrelationsDerived.h b/PWGCF/DataModel/CorrelationsDerived.h index d690518012a..b49818891f3 100644 --- a/PWGCF/DataModel/CorrelationsDerived.h +++ b/PWGCF/DataModel/CorrelationsDerived.h @@ -11,9 +11,12 @@ #ifndef PWGCF_DATAMODEL_CORRELATIONSDERIVED_H_ #define PWGCF_DATAMODEL_CORRELATIONSDERIVED_H_ +#include "Common/DataModel/Centrality.h" + #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/Centrality.h" + +#include namespace o2::aod { @@ -83,6 +86,24 @@ 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 +//------multiplicity set +namespace cfmultset +{ +DECLARE_SOA_COLUMN(Multiplicities, multiplicities, std::vector); //! List of auxiliary multiplicities +enum MultiplicityEstimators : uint8_t { + CentFT0C = 0x1, + MultFV0A = 0x2, + MultNTracksPV = 0x4, + MultNTracksGlobal = 0x8 +}; + +} // namespace cfmultset +DECLARE_SOA_TABLE(CFMultSets, "AOD", "CFMULTSET", cfmultset::Multiplicities); //! Auxilary multiplicity set table + +using CFMultSet = CFMultSets::iterator; + +// Reco + using CFCollRef = CFCollRefs::iterator; namespace cftrackref @@ -92,6 +113,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 +138,22 @@ enum ParticleDecay { D0ToPiK, D0barToKPi, JPsiToEE, - JPsiToMuMu + JPsiToMuMu, + Generic2Prong, + PhiToKKPID1, + PhiToKKPID2, + PhiToKKPID3, + PhiToKKPID3Loose, + PhiToKKPID3Tight, + K0stoPiPi, + LambdatoPPi, + AntiLambdatoPiP, + K0stoPiPiLoose, + K0stoPiPiTight, + LambdaToPPiLoose, + LambdaToPPiTight, + AntiLambdaToPiPLoose, + AntiLambdaToPiPTight }; } // namespace cf2prongtrack DECLARE_SOA_TABLE(CF2ProngTracks, "AOD", "CF2PRONGTRACK", //! Reduced track table @@ -117,6 +163,38 @@ 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 +DECLARE_SOA_COLUMN(Decay, decay, uint8_t); //! Particle decay and flags +DECLARE_SOA_DYNAMIC_COLUMN(McDecay, mcDecay, [](uint8_t decay) -> uint8_t { return decay & 0x7f; }); //! MC particle decay +enum ParticleDecayFlags { + Prompt = 0x80 +}; +} // 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, + cf2prongmcpart::Decay, + cf2prongmcpart::McDecay) +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 fb8fdaba809..d04785961b0 100644 --- a/PWGCF/DataModel/FemtoDerived.h +++ b/PWGCF/DataModel/FemtoDerived.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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,22 +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. - #ifndef PWGCF_DATAMODEL_FEMTODERIVED_H_ #define PWGCF_DATAMODEL_FEMTODERIVED_H_ -#include -#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 "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/DataTypes.h" #include "Framework/Expressions.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" +#include "MathUtils/Utils.h" + +#include namespace o2::aod { @@ -35,6 +37,8 @@ enum CollisionBinning { kMult, //! Bin collision in number of charged tracks for mixing kMultPercentile, //! Bin collision in multiplicity percentile for mixing kMultMultPercentile, //! Bin collision in number of charged tracks and multiplicity percentile for mixing + kMultPercentileQn, //! Bin collision in multiplicity percentile and qn value for mixing + kMultPercentileEP, //! Bin collision in multiplicity percentile and event plane (deg) for mixing kNCollisionBinning }; @@ -50,17 +54,28 @@ DECLARE_SOA_COLUMN(BitMaskTrackTwo, bitmaskTrackTwo, BitMaskType); //! Bit f DECLARE_SOA_COLUMN(BitMaskTrackThree, bitmaskTrackThree, BitMaskType); //! Bit for track three DECLARE_SOA_COLUMN(Downsample, downsample, bool); //! Flag for downsampling + +DECLARE_SOA_COLUMN(QnVal, qnVal, double); //! qn values for dividing events +DECLARE_SOA_COLUMN(Occupancy, occupancy, int); //! Occupancy of the event +DECLARE_SOA_COLUMN(EventPlane, eventPlane, double); //! Event-plane of the event (deg) } // 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(FDExtQnCollisions, "AOD", "FDEXTQNCOLLISION", + femtodreamcollision::QnVal, + femtodreamcollision::Occupancy); + +DECLARE_SOA_TABLE(FDExtEPCollisions, "AOD", "FDEXTEPCOLLISION", + femtodreamcollision::EventPlane); + DECLARE_SOA_TABLE(FDColMasks, "AOD", "FDCOLMASK", femtodreamcollision::BitMaskTrackOne, femtodreamcollision::BitMaskTrackTwo, @@ -74,29 +89,49 @@ 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 +/// Distinguishes the different particle types enum ParticleType { - kTrack, //! Track - kV0, //! V0 - kV0Child, //! Child track of a V0 - kCascade, //! Cascade - kCascadeBachelor, //! Bachelor track of a cascade - kCharmHadron, //! Bachelor track of a cascade - kNParticleTypes //! Number of particle types + 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 + kReso, //! Resonances (phi) + kResoChild, // Child track of a Resonance + kResoPosdaughTPC_NegdaughTPC, // cases for Phi-daughters for TPC or TOF combinations + kResoPosdaughTPC_NegdaughTOF, + kResoPosdaughTOF_NegdaughTPC, + kResoPosdaughTOF_NegdaughTOF, + kResoKStarPosdaughTPC_NegdaughTPC, // cases for KStar-daughters for TPC or TOF combinations + kResoKStarPosdaughTPC_NegdaughTOF, + kResoKStarPosdaughTOF_NegdaughTPC, + kResoKStarPosdaughTOF_NegdaughTOF, + kV0K0Short, + kV0K0ShortChild, + kResoKStarChild, + kResoKStar, + kOmega, + kOmegaV0, + kOmegaV0Child, + kOmegaBachelor, + kNParticleTypes //! Number of particle types }; enum MomentumType { @@ -105,19 +140,21 @@ 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", "CharmHadron"}; //! Naming of the different particle types -static constexpr std::string_view TempFitVarName[kNParticleTypes] = {"/hDCAxy", "/hCPA", "/hDCAxy", "/hCPA", "/hDCAxy", "/hCPA"}; +static constexpr std::string_view ParticleTypeName[kNParticleTypes] = {"Track", "V0", "V0Child", "Cascade", "CascadeV0", "CascadeV0Child", "CascadeBachelor", "CharmHadron", "Reso", "ResoChild", "ResoPosdaughTPC_NegdaughTPC", "ResoPosdaughTPC_NegdaughTOF", "ResoPosdaughTOF_NegdaughTPC", "ResoPosdaughTOF_NegdaughTOF", "ResoKStarPosdaughTPC_NegdaughTPC", "ResoKStarPosdaughTPC_NegdaughTOF", "ResoKStarPosdaughTOF_NegdaughTPC", "ResoKStarPosdaughTOF_NegdaughTOF", "V0K0Short", "V0K0ShortChild", "ResoKStarChild", "ResoKStar", "Omega", "OmegaV0", "OmegaV0Child", "OmegaBachelor"}; //! Naming of the different particle types + +static constexpr std::string_view TempFitVarName[kNParticleTypes] = {"/hDCAxy", "/hCPA", "/hDCAxy", "/hCPA", "/hCPA", "/hDCAxy", "/hDCAxy", "/hCPA", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hCPA", "/hDCAxy", "/hDCAxy", "/hDCAxy", "/hCPA", "/hCPA", "/hDCAxy", "/hDCAxy"}; 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) @@ -137,11 +174,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 { @@ -166,17 +203,37 @@ 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 namespace fdhf @@ -185,42 +242,50 @@ namespace fdhf enum CharmHadronMassHypo { wrongParticle = 0, lcToPKPi = 1, - lcToPiKP = 2 + lcToPiKP = 2, + dplusToPiKPi = 4 }; - -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, //! +DECLARE_SOA_COLUMN(GIndexCol, gIndexCol, int); //! Global index for the collision +DECLARE_SOA_COLUMN(TimeStamp, timeStamp, int64_t); //! Timestamp for the collision +DECLARE_SOA_COLUMN(VertexZ, vertexZ, float); //! VertexZ for the collision +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, int); //! Selection of mass hypothesis for charm hadron (1 for Lc -> pkpi, 2 for Lc -> pikp, 4 for D+ -> pikpi) +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, int); //! To select MC particle among charm hadrons, { DplusToPiKPi = 1, LcToPKPi = 17, DsToKKPi = 6, XicToPKPi = 21, N3ProngD = 2ecays }; +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int); //! flag for reconstruction level matching (1 for prompt, 2 for non-prompt) +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int); //! flag for generator level matching (1 for prompt, 2 for non-prompt) +DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int); //! swapping of the prongs order (0 for Lc -> pkpi, 1 for Lc -> pikp) +DECLARE_SOA_COLUMN(TrkPt, trkPt, float); //! Transverse momentum of associate femto particle +DECLARE_SOA_COLUMN(TrkEta, trkEta, float); //! Eta of associate femto particle +DECLARE_SOA_COLUMN(TrkPhi, trkPhi, float); //! Phi 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(CharmTrkM, charmtrkM, float); //! Charm hadron track mass +DECLARE_SOA_COLUMN(CharmPt, charmPt, float); //! Transverse momentum of charm hadron for result task +DECLARE_SOA_COLUMN(CharmEta, charmEta, float); //! Eta of charm hadron for result task +DECLARE_SOA_COLUMN(CharmPhi, charmPhi, float); //! Phi 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), @@ -258,6 +323,7 @@ DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, DECLARE_SOA_TABLE(FDHfCand, "AOD", "FDHFCAND", //! Table to store the derived data for charm hadron candidates o2::soa::Index<>, femtodreamparticle::FDCollisionId, + fdhf::TimeStamp, fdhf::Charge, fdhf::Prong0Id, fdhf::Prong1Id, @@ -282,10 +348,10 @@ DECLARE_SOA_TABLE(FDHfCand, "AOD", "FDHFCAND", //! Table to store the derived da fdhf::Phi, fdhf::Pt); -DECLARE_SOA_TABLE(FDResultsHF, "AOD", "FDRESULTSHF", //! table to store results for HF femtoscopy +DECLARE_SOA_TABLE(FDHfPairs, "AOD", "FDHFPAIRS", //! table to store results for HF femtoscopy fdhf::CharmM, fdhf::CharmPt, - fdhf::PtAssoc, + fdhf::TrkPt, fdhf::BDTBkg, fdhf::BDTPrompt, fdhf::BDTFD, @@ -296,10 +362,46 @@ DECLARE_SOA_TABLE(FDResultsHF, "AOD", "FDRESULTSHF", //! table to store results fdhf::MultPercentile, fdhf::Charge, fdhf::PairSign, + fdhf::CharmTrkM, fdhf::ProcessType, fdhf::FlagMc, fdhf::OriginMcRec); +DECLARE_SOA_TABLE(FDHfCharm, "AOD", "FDHFCHARM", //! table to store results for HF femtoscopy + fdhf::GIndexCol, + fdhf::TimeStamp, + fdhf::CharmM, + fdhf::CharmPt, + fdhf::CharmEta, + fdhf::CharmPhi, + fdhf::Prong0Id, + fdhf::Prong1Id, + fdhf::Prong2Id, + fdhf::Charge, + fdhf::BDTBkg, + fdhf::BDTPrompt, + fdhf::BDTFD); + +DECLARE_SOA_TABLE(FDHfTrk, "AOD", "FDHFTRK", //! table to store results for HF femtoscopy + fdhf::GIndexCol, + fdhf::TimeStamp, + fdhf::TrkPt, + fdhf::TrkEta, + fdhf::TrkPhi, + fdhf::TrackId, + femtodreamparticle::Sign, + femtodreamparticle::TPCNClsFound, + track::TPCNClsFindable, + femtodreamparticle::TPCNClsCrossedRows, + femtodreamparticle::TPCNSigmaPr, + femtodreamparticle::TOFNSigmaPr); + +DECLARE_SOA_TABLE(FDHfColl, "AOD", "FDHFCOLL", //! table to store results for HF femtoscopy + fdhf::GIndexCol, + fdhf::TimeStamp, + fdhf::VertexZ, + fdhf::Mult); + DECLARE_SOA_TABLE(FDHfCandMC, "AOD", "FDHFCANDMC", //! Table for reconstructed MC charm hadron candidates o2::soa::Index<>, fdhf::FlagMc, @@ -308,56 +410,78 @@ DECLARE_SOA_TABLE(FDHfCandMC, "AOD", "FDHFCANDMC", //! Table for reconstructed M 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(FDParticles, "AOD", "FDPARTICLE", +DECLARE_SOA_TABLE(FDTrkTimeStamp, "AOD", "FDHFTRKTIMESTAMP", //! Time Stampe of track associate event 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::TimeStamp); + +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 @@ -373,6 +497,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 }; @@ -403,25 +530,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 @@ -443,9 +570,10 @@ 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..6e732ee562e --- /dev/null +++ b/PWGCF/DataModel/SPTableZDC.h @@ -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 SPTableZDC.h +/// \author Noor Koster +/// \since 11/2024 +/// \brief Table to hold Q-vectors and neccesary information for the ZDC q-vector calibration. + +#ifndef PWGCF_DATAMODEL_SPTABLEZDC_H_ +#define PWGCF_DATAMODEL_SPTABLEZDC_H_ + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisDataModel.h" + +#include +#include + +namespace o2::aod +{ +namespace sptablezdc +{ +DECLARE_SOA_COLUMN(Runnumber, runnumber, int); +DECLARE_SOA_COLUMN(Cents, cents, std::vector); +DECLARE_SOA_COLUMN(Vertex, vertex, std::vector); +DECLARE_SOA_COLUMN(Timestamp, timestamp, int64_t); +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(EventSelectionFlags, eventSelectionFlags, uint16_t); + +} // namespace sptablezdc + +DECLARE_SOA_TABLE(SPTableZDC, "AOD", "SPZDC", + sptablezdc::Runnumber, + sptablezdc::Cents, + sptablezdc::Vertex, + sptablezdc::Timestamp, + sptablezdc::QxA, + sptablezdc::QyA, + sptablezdc::QxC, + sptablezdc::QyC, + sptablezdc::IsSelected, + sptablezdc::EventSelectionFlags); +} // namespace o2::aod +#endif // PWGCF_DATAMODEL_SPTABLEZDC_H_ diff --git a/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt b/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt index 1332c9ef1dd..c65d1705a93 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,8 +24,18 @@ o2physics_add_dpl_workflow(netproton-cumulants PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(identified-meanpt-fluctuations - SOURCES IdentifiedMeanPtFluctuations.cxx +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(event-mean-pt-id + SOURCES eventMeanPtId.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) @@ -43,3 +53,33 @@ 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) + +o2physics_add_dpl_workflow(v0pt-had-pi-ka-prot + SOURCES v0ptHadPiKaProt.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(part-num-fluc + SOURCES partNumFluc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(radial-flow-decorr + SOURCES radialFlowDecorr.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/EbyEFluctuations/Tasks/Diff_pT_fluct_PID.cxx b/PWGCF/EbyEFluctuations/Tasks/Diff_pT_fluct_PID.cxx index 5710ab1e864..8d01f25b5cd 100644 --- a/PWGCF/EbyEFluctuations/Tasks/Diff_pT_fluct_PID.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/Diff_pT_fluct_PID.cxx @@ -13,37 +13,38 @@ /// v0(pT) along with its statistical uncertainity using subsampling technique. /// \author Anna Binoy (anna.binoy@niser.ac.in) -#include -#include -#include -#include -#include +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -#include "Framework/RunningWorkflowInfo.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/HistogramSpec.h" +#include "Framework/RunningWorkflowInfo.h" #include "Framework/StaticFor.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 "Framework/runDataProcessing.h" +#include #include "TDatabasePDG.h" -#include "TLorentzVector.h" +#include "TF1.h" +#include "TH1D.h" +#include "TH2D.h" #include "TList.h" +#include "TLorentzVector.h" +#include "TMath.h" #include "TProfile.h" #include "TProfile2D.h" -#include "TH2D.h" -#include "TH1D.h" #include "TRandom3.h" -#include "TMath.h" -#include "TF1.h" + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/PWGCF/EbyEFluctuations/Tasks/FactorialMomentsTask.cxx b/PWGCF/EbyEFluctuations/Tasks/FactorialMomentsTask.cxx index f235859360a..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" @@ -33,11 +34,11 @@ 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"}; @@ -77,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}}}}, @@ -137,9 +140,16 @@ struct FactorialMoments { { 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()); @@ -182,8 +192,9 @@ 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>; void processRun3(soa::Filtered>::iterator const& coll, TracksFMs const& tracks) { @@ -217,41 +228,32 @@ struct FactorialMoments { fqEvent = {{{{{0, 0, 0, 0, 0, 0}}}}}; binConEvent = {{{0, 0, 0, 0, 0}}}; for (auto const& track : tracks) { - if (includeGlobalTracks && (!track.isGlobalTrack())) { - continue; - } - if (includeTPCTracks && (!track.hasTPC())) { - continue; - } - if (includeITSTracks && (!track.hasITS())) { - 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); } - if ((track.pt() < confPtMin) || (track.tpcNClsFindable() < confMinTPCCls)) { - continue; - } - 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]); } diff --git a/PWGCF/EbyEFluctuations/Tasks/IdentifiedMeanPtFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/IdentifiedMeanPtFluctuations.cxx deleted file mode 100644 index 2217a2c1f4f..00000000000 --- a/PWGCF/EbyEFluctuations/Tasks/IdentifiedMeanPtFluctuations.cxx +++ /dev/null @@ -1,1173 +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 Sweta Singh (sweta.singh@cern.ch) - -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/trackUtilities.h" -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Centrality.h" -#include "CommonConstants/MathConstants.h" -#include "Common/DataModel/FT0Corrected.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/RunningWorkflowInfo.h" -#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; -using namespace o2::framework::expressions; -using namespace std; - -namespace o2::aod -{ - -using MyCollisions = soa::Join; -using MyTracks = soa::Join; - -using MyMCRecoCollisions = soa::Join; - -using MyMCRecoTracks = soa::Join; - -using MyCollision = MyCollisions::iterator; -using MyTrack = MyTracks::iterator; -} // namespace o2::aod - -double massPi = TDatabasePDG::Instance()->GetParticle(211)->Mass(); -double massKa = TDatabasePDG::Instance()->GetParticle(321)->Mass(); -double massPr = TDatabasePDG::Instance()->GetParticle(2212)->Mass(); - -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)"}; - AxisSpec dcaAxis = {1002, -5.01, 5.01, "DCA_{xy} (cm)"}; - AxisSpec dcazAxis = {1002, -5.01, 5.01, "DCA_{z} (cm)"}; - AxisSpec ptAxis = {400, 0.0, 4.0, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec pAxis = {400, 0.0, 4.0, "#it{p} (GeV/#it{c})"}; - 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 = {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 = {4000, 0., 4000., "nch"}; - AxisSpec varAxis1 = {400, 0., 4., "var1"}; - AxisSpec varAxis2 = {400, 0., 4., "var2"}; - AxisSpec Chi2Axis = {100, 0., 100., "Chi2"}; - AxisSpec CrossedrowTPCAxis = {600, 0., 600., "TPC Crossed rows"}; - AxisSpec Counter = {10, 0., 10., "events"}; - - // QA Plots - histos.add("hEventCounter", "event counts", kTH1D, {Counter}); - - auto h = histos.add("tracksel", "tracksel", HistType::kTH1D, {{10, 0.5, 10.5}}); - h->GetXaxis()->SetBinLabel(1, "Tracks read"); - h->GetXaxis()->SetBinLabel(2, "Global track passed"); - h->GetXaxis()->SetBinLabel(3, "DCAxy passed"); - h->GetXaxis()->SetBinLabel(4, "DCAz passed"); - h->GetXaxis()->SetBinLabel(5, "Eta-cut passed"); - h->GetXaxis()->SetBinLabel(6, "pT-cut passed"); - h->GetXaxis()->SetBinLabel(7, "TPC crossed rows passed"); - 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}); - histos.add("hP", "hP", kTH1D, {pAxis}); - histos.add("hEta", ";hEta", kTH1D, {etaAxis}); - histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); - histos.add("hNsigmaTPC", "hNsigmaTPC", kTH2D, - {pAxis, nSigmaTPCAxis}); - histos.add("hDCAxy", "hDCAxy", kTH1D, {dcaAxis}); - histos.add("hDCAz", "hDCAz", kTH1D, {dcazAxis}); - - histos.add("hPtDCAxy", "hPtDCAxy", kTH2D, {ptAxis, dcaAxis}); - histos.add("hPtDCAz", "hPtDCAz", kTH2D, {ptAxis, dcazAxis}); - histos.add("NSigamaTPCpion", "NSigamaTPCpion", kTH2D, {ptAxis, nSigmaTPCAxispid}); - histos.add("NSigamaTPCkaon", "NSigamaTPCkaon", kTH2D, {ptAxis, nSigmaTPCAxispid}); - histos.add("NSigamaTPCproton", "NSigamaTPCproton", kTH2D, {ptAxis, nSigmaTPCAxispid}); - - histos.add("NSigamaTOFpion", "NSigamaTOFpion", kTH2D, {ptAxis, nSigmaTOFAxispid}); - 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}); - - histos.add("hEtaPion", ";hEta", kTH1D, {etaAxis}); - histos.add("hEtaKaon", ";hEta", kTH1D, {etaAxis}); - histos.add("hEtaProton", ";hEta", kTH1D, {etaAxis}); - //=====================rapidity===================================== - histos.add("hyPion", ";hyPion", kTH1D, {etaAxis}); - histos.add("hyKaon", ";hyKaon", kTH1D, {etaAxis}); - histos.add("hyProton", ";hyProton", kTH1D, {etaAxis}); - - histos.add("hPtCh", "hPtCh", kTH2D, {nchAxis, ptAxis}); - histos.add("hPtChPion", "hPtChPion", kTH2D, {nchAxis, ptAxis}); - histos.add("hPtChKaon", "hPtChKaon", kTH2D, {nchAxis, ptAxis}); - histos.add("hPtChProton", "hPtChProton", kTH2D, {nchAxis, ptAxis}); - - histos.add("hPtCent", "hPtCent", kTH2D, {centAxis, ptAxis}); - histos.add("hPtCentPion", "hPtCentPion", kTH2D, {centAxis, ptAxis}); - histos.add("hPtCentKaon", "hPtCentKaon", kTH2D, {centAxis, ptAxis}); - histos.add("hPtCentProton", "hPtCentProton", kTH2D, {centAxis, ptAxis}); - - histos.add("hMeanPtCh", "hMeanPtCh", kTH2D, {nchAxis, ptAxis}); - histos.add("hCent", "hCent", kTH2D, {nchAxis, centAxis}); - - histos.add("hVar1", "hVar1", kTH2D, {subAxis, centAxis}); - histos.add("hVar2", "hVar2", kTH2D, {subAxis, centAxis}); - histos.add("hVar2meanpt", "hVar2meanpt", kTH2D, {centAxis, varAxis2}); - histos.add("hVar", "hVar", kTH2D, {subAxis, centAxis}); - histos.add("hVarc", "hVarc", kTH2D, {subAxis, centAxis}); - - histos.add("hVar1pi", "hVar1pi", kTH2D, {subAxis, centAxis}); - histos.add("hVar2pi", "hVar2pi", kTH2D, {subAxis, centAxis}); - histos.add("hVarpi", "hVarpi", kTH2D, {subAxis, centAxis}); - histos.add("hVar2meanptpi", "hVar2meanptpi", kTH2D, {centAxis, varAxis2}); - - histos.add("hVar1k", "hVar1k", kTH2D, {subAxis, centAxis}); - histos.add("hVar2k", "hVar2k", kTH2D, {subAxis, centAxis}); - histos.add("hVark", "hVark", kTH2D, {subAxis, centAxis}); - histos.add("hVar2meanptk", "hVar2meanptk", kTH2D, {centAxis, varAxis2}); - - histos.add("hVar1p", "hVar1p", kTH2D, {subAxis, centAxis}); - histos.add("hVar2p", "hVar2p", kTH2D, {subAxis, centAxis}); - histos.add("hVarp", "hVarp", kTH2D, {subAxis, centAxis}); - histos.add("hVar2meanptp", "hVar2meanptp", kTH2D, {centAxis, varAxis2}); - - //--------------------------------nch---------------------------------- - histos.add("hVar1x", "hVar1x", kTH2D, {subAxis, nchAxis}); - histos.add("hVar2x", "hVar2x", kTH2D, {subAxis, nchAxis}); - histos.add("hVarx", "hVarx", kTH2D, {subAxis, nchAxis}); - histos.add("hVar2meanptx", "hVar2meanptx", kTH2D, {nchAxis, varAxis2}); - - histos.add("hVar1pix", "hVar1pix", kTH2D, {subAxis, nchAxis}); - histos.add("hVar2pix", "hVar2pix", kTH2D, {subAxis, nchAxis}); - histos.add("hVarpix", "hVarpix", kTH2D, {subAxis, nchAxis}); - histos.add("hVar2meanptpix", "hVar2meanptpix", kTH2D, {nchAxis, varAxis2}); - - histos.add("hVar1kx", "hVar1kx", kTH2D, {subAxis, nchAxis}); - histos.add("hVar2kx", "hVar2kx", kTH2D, {subAxis, nchAxis}); - histos.add("hVarkx", "hVarkx", kTH2D, {subAxis, nchAxis}); - histos.add("hVar2meanptkx", "hVar2meanptkx", kTH2D, {nchAxis, varAxis2}); - - histos.add("hVar1px", "hVar1px", kTH2D, {subAxis, nchAxis}); - histos.add("hVar2px", "hVar2px", kTH2D, {subAxis, nchAxis}); - histos.add("hVarpx", "hVarpx", kTH2D, {subAxis, nchAxis}); - histos.add("hVar2meanptpx", "hVar2meanptpx", kTH2D, {nchAxis, varAxis2}); - - histos.add("ht", "ht", kTH1D, {centAxis}); - - histos.add("hCentrality", "hCentrality", kTH1D, {centAxis}); - - histos.add("hPEta", "hPEta", kTH2D, {pAxis, etaAxis}); - histos.add("hPtEta", "hPtEta", kTH2D, {ptAxis, etaAxis}); - histos.add("hPy", "hPy", kTH2D, {pAxis, etaAxis}); - histos.add("hPty", "hPty", kTH2D, {ptAxis, etaAxis}); - - histos.add("hPtyPion", "hPtyPion", kTH2D, {ptAxis, etaAxis}); - 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}); - - histos.add("hTOFbeta_afterselection", "hTOFbeta_afterselection", kTH2D, {pAxis, betaAxis}); - histos.add("hdEdx_afterselection", "hdEdx_afterselection", kTH2D, {pAxis, dEdxAxis}); - - 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}); - - 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) - - { - histos.fill(HIST("hEventCounter"), 1.); - - histos.fill(HIST("hZvtx_before_sel"), coll.posZ()); - if (fabs(coll.posZ()) > 10.f) { - return; - } - - histos.fill(HIST("hEventCounter"), 2.); - - histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); - - if (!coll.sel8()) { - return; - } - histos.fill(HIST("hZvtx_after_sel8"), coll.posZ()); - - histos.fill(HIST("hEventCounter"), 3.); - - const auto cent = coll.centFT0C(); - histos.fill(HIST("hCentrality"), cent); - - double nCh = 0.; - double nChpi = 0.; - 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.; - // cent = 0; - - // sampling - int sample = histos.get(HIST("hZvtx_after_sel8"))->GetEntries(); - sample = sample % 30; - - // Perfroming the track selection========================================== - for (auto track : inputTracks) { - // Loop over tracks - - // inital tracks - histos.fill(HIST("tracksel"), 1); - - histos.fill(HIST("hTPCchi2perCluster_before"), track.tpcChi2NCl()); - histos.fill(HIST("hITSchi2perCluster_before"), track.itsChi2NCl()); - histos.fill(HIST("hTPCCrossedrows_before"), track.tpcNClsCrossedRows()); - - // tracks passed after GlobalTrackcut - if (!track.isGlobalTrack()) - continue; - histos.fill(HIST("tracksel"), 2); - - // tracks passed after DCAxy - // if (!(fabs(track.dcaXY()) < 0.12)) continue;//global cut already includes - histos.fill(HIST("tracksel"), 3); - - // tracks passed after DCAz - // - histos.fill(HIST("hDCAxy"), track.dcaXY()); - histos.fill(HIST("hDCAz"), track.dcaZ()); - - // if (!(fabs(track.dcaZ()) < 1.)) continue;//global cut already includes (DCAz< 2.0) cm - histos.fill(HIST("tracksel"), 4); - - // tracks passed after Eta-cut - if (!(fabs(track.eta()) < 0.8)) - continue; - histos.fill(HIST("tracksel"), 5); - - // tracks passed after pT-cut - if (!(track.pt() > 0.15 && track.pt() < 2.)) - continue; // pt = 0.15 - histos.fill(HIST("tracksel"), 6); - - // if (track.tpcNClsCrossedRows() < 70.0) continue; - histos.fill(HIST("hTPCCrossedrows_after"), track.tpcNClsCrossedRows()); - histos.fill(HIST("tracksel"), 7); - - // if (track.tpcChi2NCl() > 4.0) continue; - histos.fill(HIST("hTPCchi2perCluster_after"), track.tpcChi2NCl()); - histos.fill(HIST("tracksel"), 8); - - // if (track.itsChi2NCl() > 36.0) continue; - histos.fill(HIST("hITSchi2perCluster_after"), track.itsChi2NCl()); - histos.fill(HIST("tracksel"), 9); - - nCh += 1.; - - Q1 += track.pt(); - Q2 += (track.pt() * track.pt()); - - histos.fill(HIST("hP"), track.p()); - histos.fill(HIST("hPt"), track.pt()); - histos.fill(HIST("hEta"), track.eta()); - histos.fill(HIST("hPtDCAxy"), track.pt(), track.dcaXY()); - histos.fill(HIST("hPtDCAz"), track.pt(), track.dcaZ()); - - histos.fill(HIST("hPtEta"), track.pt(), track.eta()); - histos.fill(HIST("hPEta"), track.p(), track.eta()); - - histos.fill(HIST("hNsigmaTPC"), track.p(), track.tpcNSigmaPr()); - - // only TPC tracks: Pion, Kaon, Proton - if (track.hasTPC() && abs(track.tpcNSigmaPi()) < 2.) - histos.fill(HIST("NSigamaTPCpion"), track.pt(), track.tpcNSigmaPi()); - if (track.hasTPC() && abs(track.tpcNSigmaKa()) < 2.) - histos.fill(HIST("NSigamaTPCkaon"), track.pt(), track.tpcNSigmaKa()); - if (track.hasTPC() && abs(track.tpcNSigmaPr()) < 2.) - histos.fill(HIST("NSigamaTPCproton"), track.pt(), track.tpcNSigmaPr()); - - // only TOF tracks: Pion, Kaon, Proton - if (track.hasTOF() && abs(track.tofNSigmaPi()) < 2.) - histos.fill(HIST("NSigamaTOFpion"), track.pt(), track.tofNSigmaPi()); - if (track.hasTOF() && abs(track.tofNSigmaKa()) < 2.) - histos.fill(HIST("NSigamaTOFkaon"), track.pt(), track.tofNSigmaKa()); - if (track.hasTOF() && abs(track.tofNSigmaPr()) < 2.) - histos.fill(HIST("NSigamaTOFproton"), track.pt(), track.tofNSigmaPr()); - - if (track.hasTPC()) - histos.fill(HIST("hdEdx"), track.p(), track.tpcSignal()); - if (track.hasTOF()) - histos.fill(HIST("hTOFbeta"), track.p(), track.beta()); - - //=============================pion============================================================== - // only TPC+TOF tracks: Pion, Kaon, Proton - if ((track.hasTPC() && abs(track.tpcNSigmaPi()) < 2.) && (track.hasTOF() && abs(track.tofNSigmaPi()) < 2.)) { - histos.fill(HIST("NSigamaTPCTOFpion"), track.tpcNSigmaPi(), track.tofNSigmaPi()); - - histos.fill(HIST("hdEdx_afterselection"), track.p(), track.tpcSignal()); - histos.fill(HIST("hTOFbeta_afterselection"), track.p(), track.beta()); - } - - // 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.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()); - histos.fill(HIST("hyPion"), track.rapidity(massPi)); - histos.fill(HIST("hPtyPion"), track.pt(), track.rapidity(massPi)); - - nChpi += 1.; - 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.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()); - histos.fill(HIST("hyPion"), track.rapidity(massPi)); - histos.fill(HIST("hPtyPion"), track.pt(), track.rapidity(massPi)); - - nChpi += 1.; - 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()); - } - - //===========================kaon=============================================================== - - if ((track.hasTPC() && abs(track.tpcNSigmaKa()) < 2.) && (track.hasTOF() && abs(track.tofNSigmaKa()) < 2.)) { - histos.fill(HIST("NSigamaTPCTOFkaon"), track.tpcNSigmaKa(), track.tofNSigmaKa()); - histos.fill(HIST("hdEdx_afterselection"), track.p(), track.tpcSignal()); - 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.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()); - histos.fill(HIST("hyKaon"), track.rapidity(massKa)); - histos.fill(HIST("hPtyKaon"), track.pt(), track.rapidity(massKa)); - - nChk += 1.; - 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.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()); - histos.fill(HIST("hyKaon"), track.rapidity(massKa)); - histos.fill(HIST("hPtyKaon"), track.pt(), track.rapidity(massKa)); - - nChk += 1.; - 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()); - } - - //============================proton=========================================================== - - if ((track.hasTPC() && abs(track.tpcNSigmaPr()) < 2.) && (track.hasTOF() && abs(track.tofNSigmaPr()) < 2.)) { - histos.fill(HIST("NSigamaTPCTOFproton"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - - histos.fill(HIST("hdEdx_afterselection"), track.p(), track.tpcSignal()); - 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.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()); - histos.fill(HIST("hyProton"), track.rapidity(massPr)); - histos.fill(HIST("hPtyProton"), track.pt(), track.rapidity(massPr)); - - nChp += 1.; - 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.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()); - histos.fill(HIST("hyProton"), track.rapidity(massPr)); - histos.fill(HIST("hPtyProton"), track.pt(), track.rapidity(massPr)); - - nChp += 1.; - 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! - - if (nCh < 2) - return; - - //------------------ all charges------------------------------------- - var1 = (Q1 * Q1 - Q2) / (nCh * (nCh - 1)); - histos.fill(HIST("hVar1"), sample, cent, var1); - var2 = (Q1 / nCh); - histos.fill(HIST("hVar2"), sample, cent, var2); - histos.fill(HIST("hVarc"), sample, cent); - histos.fill(HIST("hVar2meanpt"), cent, var2); - - twopar_allcharge = (var1 - var2); - histos.fill(HIST("hVar"), nCh, twopar_allcharge); - - //---------------------- pions ---------------------------------------- - - if (nChpi > 2) { - var1pi = (Q1pi * Q1pi - Q2pi) / (nChpi * (nChpi - 1)); - var2pi = (Q1pi / nChpi); - } - - //----------------------- kaons --------------------------------------- - if (nChk > 2) { - var1k = (Q1k * Q1k - Q2k) / (nChk * (nChk - 1)); - var2k = (Q1k / nChk); - } - - //---------------------------- protons ---------------------------------- - if (nChp > 2) { - var1p = (Q1p * Q1p - Q2p) / (nChp * (nChp - 1)); - var2p = (Q1p / nChp); - } - - //========================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); - histos.fill(HIST("hVarx"), sample, nCh); - histos.fill(HIST("hVar2meanptx"), nCh, var2); - - histos.fill(HIST("hVar1pix"), sample, nCh, var1pi); - histos.fill(HIST("hVar2pix"), sample, nCh, var2pi); - histos.fill(HIST("hVarpix"), sample, nChpi); - histos.fill(HIST("hVar2meanptpix"), nCh, var2pi); - - histos.fill(HIST("hVar1kx"), sample, nCh, var1k); - histos.fill(HIST("hVar2kx"), sample, nCh, var2k); - histos.fill(HIST("hVarkx"), sample, nChk); - histos.fill(HIST("hVar2meanptkx"), nCh, var2k); - - histos.fill(HIST("hVar1px"), sample, nCh, var1p); - histos.fill(HIST("hVar2px"), sample, nCh, var2p); - histos.fill(HIST("hVarpx"), sample, nChp); - histos.fill(HIST("hVar2meanptpx"), nCh, var2p); - - } // event loop ends! - - PROCESS_SWITCH(IdentifiedMeanPtFluctuations, process, "process real data information", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; - return workflow; -} diff --git a/PWGCF/EbyEFluctuations/Tasks/MeanPtFlucIdentified.cxx b/PWGCF/EbyEFluctuations/Tasks/MeanPtFlucIdentified.cxx deleted file mode 100644 index b61c8de928d..00000000000 --- a/PWGCF/EbyEFluctuations/Tasks/MeanPtFlucIdentified.cxx +++ /dev/null @@ -1,843 +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 cumulant 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 "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 "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", 250, ""}; - Configurable nCentBins{"nCentBins", 101, ""}; - Configurable nEtaBins{"nEtaBins", 100, ""}; - Configurable nTpNBins{"nTpNBins", 200, ""}; - Configurable nTpDBins{"nTpDBins", 100, ""}; - Configurable cfgCutPtMax{"cfgCutPtMax", 2.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 cfgCutDcaXY{"cfgCutDcaXY", 0.12, "DCAxy cut"}; - Configurable cfgCutDcaZ{"cfgCutDcaZ", 0.3, "DCAz cut"}; - Configurable cfgCutPosZ{"cfgCutPosZ", 10.0, "cut for vertex Z"}; - Configurable cfgCutNSigTpcEl{"cfgCutNSigTpcEl", 1.5, "TPC nSigma Electron veto cut"}; - Configurable cfgCutNSigTofEl{"cfgCutNSigTofEl", 1.5, "TOF nSigma Electron veto cut"}; - 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 cfgCutPiP1{"cfgCutPiP1", 0.65, "pion p cut-1"}; - Configurable cfgCutPiP2{"cfgCutPiP2", 0.75, "pion p cut-2"}; - Configurable cfgCutKaP1{"cfgCutKaP1", 0.50, "kaon p cut-1"}; - Configurable cfgCutKaP2{"cfgCutKaP2", 0.60, "kaon p cut-2"}; - Configurable cfgCutKaP3{"cfgCutKaP3", 1.60, "kaon p cut-3"}; - Configurable cfgCutPrP1{"cfgCutPrP1", 0.90, "proton p cut-1"}; - Configurable cfgCutPrP2{"cfgCutPrP2", 1.00, "proton p cut-2"}; - Configurable cfgSelPi{"cfgSelPi", true, "PID selection cut for Pions"}; - Configurable cfgSelKa{"cfgSelKa", true, "PID selection cut for Kaons"}; - Configurable cfgSelPr{"cfgSelPr", true, "PID selection cut for Protons"}; - Configurable cfgSelPiInnerParam{"cfgSelPiInnerParam", false, "PID selection cut for Pions by using Momentum at inner wall of the TPC"}; - Configurable cfgSelKaInnerParam{"cfgSelKaInnerParam", false, "PID selection cut for Kaons by using Momentum at inner wall of the TPC"}; - Configurable cfgSelPrInnerParam{"cfgSelPrInnerParam", false, "PID selection cut for Protons by using Momentum at inner wall of the TPC"}; - ConfigurableAxis multTPCBins{"multTPCBins", {150, 0, 150}, "TPC Multiplicity bins"}; - ConfigurableAxis multFT0CBins{"multFT0CBins", {200, 0, 2000}, "Forward Multiplicity bins"}; - ConfigurableAxis multFT0CMCBins{"multFT0CMCBins", {250, 0, 250}, "Forward Multiplicity bins"}; // made change fore Gen - ConfigurableAxis dcaXYBins{"dcaXYBins", {100, -0.15, 0.15}, "dcaXY bins"}; - ConfigurableAxis dcaZBins{"dcaZBins", {100, -1.2, 1.2}, "dcaZ bins"}; - ConfigurableAxis QnBins{"QnBins", {100, 0., 100.}, "nth moments bins"}; - - using MyAllTracks = soa::Join; - using MyCollisions = soa::Join; - using MyMCCollisions = soa::Join; - using MyMCTracks = soa::Join; - - Service pdg; - - 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 axisInnerParam{nPtBins, 0., 3., "p_{InnerParam } (GeV/c)"}; - const AxisSpec axisPart{nPartBins, 0., 20., " "}; - const AxisSpec axisQn{QnBins, ""}; - const AxisSpec axisTpN{nTpNBins, 0., 3000, " (Q_{1}^{2} - Q_{2}"}; - const AxisSpec axisTpD{nTpDBins, 0., 2000, " 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 axisMultFT0C{multFT0CBins, "N_{FT0C}"}; - const AxisSpec axisMultFT0CMC{multFT0CMCBins, "N_{FT0C}"}; - 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{180, 20., 200., "#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, axisMultFT0C}}); - HistogramConfigSpec PartHist({HistType::kTHnSparseD, {axisMultTPC, axisPart, axisMultFT0C}}); - HistogramConfigSpec DenoHist({HistType::kTHnSparseD, {axisMultTPC, axisDeno, axisMultFT0C}}); - HistogramConfigSpec QnMCHist({HistType::kTHnSparseD, {axisMultTPC, axisQn, axisMultFT0CMC}}); - HistogramConfigSpec PartMCHist({HistType::kTHnSparseD, {axisMultTPC, axisPart, axisMultFT0CMC}}); - HistogramConfigSpec DenoMCHist({HistType::kTHnSparseD, {axisMultTPC, axisDeno, axisMultFT0CMC}}); - 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_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/h2_PvsPinner", "p_{InnerParam} vs p", kTH2D, {{axisP}, {axisInnerParam}}); - 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/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_NFT0C", "FT0C Multiplicity", kTH1D, {axisMultFT0C}); - hist.add("QA/before/h_Cent", "FT0C (%)", kTH1D, {axisCentFT0C}); - hist.add("QA/before/h2_NTPC_Cent", "N_{TPC} vs FT0C(%)", kTH2D, {{axisCentFT0C}, {axisMultTPC}}); - hist.add("QA/before/h2_NTPC_NFT0C", "N_{TPC} vs N_{FT0C}", kTH2D, {{axisMultFT0C}, {axisMultTPC}}); - - 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/p_NTPC_NFT0C", "N_{TPC} vs N_{FT0C} (Profile)", kTProfile, {{axisMultFT0C}}); - hist.add("QA/after/p_NTPC_Cent", "N_{TPC} vs FT0C(%) (Profile)", kTProfile, {{axisCentFT0C}}); - hist.add("QA/after/h2_NTPC_Nch", "N_{ch} vs N_{TPC}", kTH2D, {{axisMultTPC}, {axisMult}}); - - hist.add("QA/Pion/h_Pt", "p_{T} ", kTH1D, {axisPt}); - hist.add("QA/Pion/h_rap", "y ", kTH1D, {axisY}); - hist.add("QA/Pion/h_Eta", "Pseudorapidity ", kTH1D, {axisY}); - hist.add("QA/Pion/h2_Pt_rap", "p_{T} vs y", kTH2D, {{axisY}, {axisPt}}); - hist.add("QA/Pion/h_DcaZ", "DCA_{z}", kTH1D, {axisDCAz}); - hist.add("QA/Pion/h_DcaXY", "DCA_{xy}", kTH1D, {axisDCAxy}); - 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 ", 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_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, axisMultFT0C}); - hist.add("Analysis/Charged/h_twopart_nume_Mult_var", "twopart numerator", kTHnSparseD, {axisMultTPC, axisTpN, axisMultFT0C}); - hist.add("Analysis/Charged/h_twopart_deno_Mult_var", "twopart denominator", kTHnSparseD, {axisMultTPC, axisTpD, axisMultFT0C}); - 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.addClone("Analysis/Charged/", "Analysis/Pion/"); - hist.addClone("Analysis/Charged/", "Analysis/Kaon/"); - hist.addClone("Analysis/Charged/", "Analysis/Proton/"); - - hist.add("QA/Reco/Pion/h_allPt", "p_{T} ", kTH1D, {axisPt}); - hist.add("QA/Reco/Kaon/h_allPt", "p_{T} ", kTH1D, {axisPt}); - hist.add("QA/Reco/Proton/h_allPt", "p_{T} ", kTH1D, {axisPt}); - - // MC Generated - 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/NFT0C", "Forward Multiplicity", kTH1D, {axisMultFT0C}); - hist.add("Gen/h2_NTPC_NFT0C", "N_{TPC} vs N_{FT0C}", kTH2D, {{axisMultFT0CMC}, {axisMultTPC}}); - hist.add("Gen/Charged/h_Pt", "p_{T} ", kTH1D, {axisPt}); - - hist.add("Gen/Charged/h_Mult", "Multiplicity", kTH1D, {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, axisMultFT0CMC}); - hist.add("Gen/Charged/h_twopart_nume_Mult_var", "twopart numerator", kTHnSparseD, {axisMultTPC, axisTpN, axisMultFT0CMC}); - hist.add("Gen/Charged/h_twopart_deno_Mult_var", "twopart denominator", kTHnSparseD, {axisMultTPC, axisTpD, axisMultFT0CMC}); - - 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.addClone("Gen/Charged/", "Gen/Pion/"); - hist.addClone("Gen/Charged/", "Gen/Kaon/"); - hist.addClone("Gen/Charged/", "Gen/Proton/"); - } - - enum mode { - QA_Pion = 0, - 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/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) - { - if (std::abs(col.posZ()) > cfgCutPosZ) - return false; - - if (!col.sel8()) - return false; - - if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) - return false; - - if (!col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) - return false; - - if (!col.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) - return false; - - return true; - } - - // Track selection cuts: - template - bool selTrack(T const& track) - { - if (!track.isGlobalTrackWoPtEta()) - return false; - - if (track.pt() < cfgCutPtMin) - return false; - - if (track.pt() > cfgCutPtMax) - return false; - - if (track.sign() == 0) - return false; - - if (std::abs(track.dcaZ()) > cfgCutDcaZ) - return false; - - if (std::abs(track.dcaXY()) > cfgCutDcaXY) - return false; - - return true; - } - - // Cuts to rejects the tracks - template - bool rejectTracks(T const& track) - { - if (track.tpcNSigmaEl() > -3. && track.tpcNSigmaEl() < 5. && std::abs(track.tpcNSigmaPi()) > 3 && std::abs(track.tpcNSigmaKa()) > 3 && std::abs(track.tpcNSigmaPr()) > 3) { - return true; - } - return false; - } - - // PID selection tpc (!tof) or (tof + tpc) - // PID selction cuts for Pions - template - bool selPions(T const& track, double innerParam) - { - if (track.pt() >= cfgCutPiPtMin && ((!track.hasTOF() && std::abs(track.tpcNSigmaEl()) > cfgCutNSigTpcEl && - ((std::abs(track.tpcNSigmaPi()) < cfgCutNSig3 && innerParam <= cfgCutPiP1) || (std::abs(track.tpcNSigmaPi()) < cfgCutNSig2 && innerParam > cfgCutPiP1 && innerParam <= cfgCutPiP2))) || - (track.hasTOF() && std::abs(track.tpcNSigmaPi()) < cfgCutNSig3 && std::abs(track.tofNSigmaEl()) > cfgCutNSigTofEl && (std::abs(track.tofNSigmaPi()) < cfgCutNSig3)))) { - if (abs(track.rapidity(massPi)) < cfgCutRap) - return true; - } - return false; - } - - // PID selction cuts for Kaons - template - bool selKaons(T const& track, double innerParam) - { - if (track.pt() >= cfgCutKaPtMin && (((!track.hasTOF()) && std::abs(track.tpcNSigmaEl()) > cfgCutNSigTpcEl && - ((std::abs(track.tpcNSigmaKa()) < cfgCutNSig3 && innerParam <= cfgCutKaP1) || (std::abs(track.tpcNSigmaKa()) < cfgCutNSig2 && innerParam > cfgCutKaP1 && innerParam <= cfgCutKaP2))) || - (track.hasTOF() && std::abs(track.tpcNSigmaKa()) < cfgCutNSig3 && std::abs(track.tofNSigmaEl()) > cfgCutNSigTofEl && - ((std::abs(track.tofNSigmaKa()) < cfgCutNSig3 && track.p() <= cfgCutKaP3) || (std::abs(track.tofNSigmaKa()) < cfgCutNSig2 && track.p() > cfgCutKaP3))))) { - if (abs(track.rapidity(massKa)) < cfgCutRap) - return true; - } - - return false; - } - - // PID selction cuts for Protons - template - bool selProtons(T const& track, double innerParam) - { - if (track.pt() >= cfgCutPrPtMin && (((!track.hasTOF()) && std::abs(track.tpcNSigmaEl()) > cfgCutNSigTpcEl && - ((std::abs(track.tpcNSigmaPr()) < cfgCutNSig3 && innerParam <= cfgCutPrP1) || (std::abs(track.tpcNSigmaPr()) < cfgCutNSig2 && innerParam > cfgCutPrP1 && innerParam <= cfgCutPrP2))) || - (track.hasTOF() && std::abs(track.tpcNSigmaPr()) < cfgCutNSig3 && std::abs(track.tofNSigmaEl()) > cfgCutNSigTofEl && std::abs(track.tofNSigmaPr()) < cfgCutNSig3))) { - if (abs(track.rapidity(massPr)) < cfgCutRap) - return true; - } - - return false; - } - - // Fill hist before selection cuts: - template - void FillBeforeQAHistos(T const& col, U const& tracks) - { - 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_PvsPinner"), myTrack.p(), myTrack.tpcInnerParam()); - 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/h_DcaXY"), myTrack.dcaXY()); - hist.fill(HIST("QA/before/h_DcaZ"), myTrack.dcaZ()); - 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); - - int NTPC = col.multNTracksHasTPC(); - int N_FT0C = col.multFT0C(); - double cent_FT0C = col.centFT0C(); - - if (NTPC != 0 && N_FT0C != 0) { - hist.fill(HIST("QA/before/h_NTPC"), NTPC); - hist.fill(HIST("QA/before/h_Cent"), cent_FT0C); - hist.fill(HIST("QA/before/h_NFT0C"), N_FT0C); - hist.fill(HIST("QA/before/h2_NTPC_NFT0C"), N_FT0C, NTPC); - hist.fill(HIST("QA/before/h2_NTPC_Cent"), cent_FT0C, NTPC); - } - } - - // Fill hist after selection cuts: - template - void FillAfterQAHistos(T const& col) - { - int NTPC = col.multNTracksHasTPC(); - int N_FT0C = col.multFT0C(); - double cent_FT0C = col.centFT0C(); - - hist.fill(HIST("QA/after/h_VtxZ"), col.posZ()); - hist.fill(HIST("QA/after/h_Counts"), 2); - if (NTPC != 0 && N_FT0C != 0) { - hist.fill(HIST("QA/after/h_NTPC"), NTPC); - hist.fill(HIST("QA/after/h_Cent"), cent_FT0C); - hist.fill(HIST("QA/after/h_NFT0C"), N_FT0C); - hist.fill(HIST("QA/after/h2_NTPC_NFT0C"), 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_NFT0C"), N_FT0C, NTPC); - } - } - - // Fill Charged particles QA: - template - void FillChargedQAHistos(T const& track) - { - hist.fill(HIST("QA/after/h_Eta"), track.eta()); - hist.fill(HIST("QA/after/h_Pt"), track.pt()); - 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()); - } - - // Fill Proton QA hist: - template - void FillIdParticleQAHistos(T const& track, double rap, double nSigmaTPC, double nSigmaTOF) - { - - hist.fill(HIST(dire[mode]) + HIST("h_Pt"), track.pt()); - hist.fill(HIST(dire[mode]) + HIST("h_Eta"), track.eta()); - hist.fill(HIST(dire[mode]) + HIST("h_rap"), rap); - hist.fill(HIST(dire[mode]) + HIST("h2_Pt_rap"), rap, track.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"), track.pt(), track.dcaZ()); - hist.fill(HIST(dire[mode]) + HIST("h2_DcaXY"), track.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()); - } - - // Moments Calculation: - 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; - } - - template - void FillAnalysisHistos(int NTPC, int N_FT0C, int N, double Q1, double Q2, double Q3, double Q4) - { - 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_Q1"), NTPC, Q1, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_Q2"), NTPC, Q2, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_Q3"), NTPC, Q3, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_Q4"), NTPC, Q4, N_FT0C); - - if (N > 0) { - double mean_pT = Q1 / static_cast(N); - hist.fill(HIST(dire[mode]) + HIST("h_mean_pT"), mean_pT); - hist.fill(HIST(dire[mode]) + HIST("p_mean_pT_Mult_var"), NTPC, mean_pT); - - if (N > 1) { - double N_pair = (static_cast(N) * (static_cast(N) - 1)); - double twopart = twopart1 / N_pair; - double checkN_deno_var = (1 / std::sqrt(1 - (1 / static_cast(N)))); - hist.fill(HIST(dire[mode]) + HIST("h_Q1_var"), NTPC, Q1, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_N_var"), NTPC, N, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_twopart_nume_Mult_var"), NTPC, twopart1, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_twopart_deno_Mult_var"), NTPC, N_pair, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_mean_pT_Mult_var"), NTPC, mean_pT, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_twopart_Mult_var"), NTPC, twopart, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("p_CheckNCH"), NTPC, checkN_deno_var); - hist.fill(HIST(dire[mode]) + HIST("h_CheckNCH"), NTPC, checkN_deno_var, N_FT0C); - - if (N > 2) { - double N_triplet = (static_cast(N) * (static_cast(N) - 1) * (static_cast(N) - 2)); - double threepart = threepart1 / N_triplet; - hist.fill(HIST(dire[mode]) + HIST("h_mean_pT_Mult_skew"), NTPC, mean_pT, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_twopart_Mult_skew"), NTPC, twopart, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_threepart_Mult_skew"), NTPC, threepart, N_FT0C); - - if (N > 3) { - double N_quad = (static_cast(N) * (static_cast(N) - 1) * (static_cast(N) - 2) * (static_cast(N) - 3)); - double fourpart = fourpart1 / N_quad; - hist.fill(HIST(dire[mode]) + HIST("h_mean_pT_Mult_kurto"), NTPC, mean_pT, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_twopart_Mult_kurto"), NTPC, twopart, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_threepart_Mult_kurto"), NTPC, threepart, N_FT0C); - hist.fill(HIST(dire[mode]) + HIST("h_fourpart_Mult_kurto"), NTPC, fourpart, N_FT0C); - } - } - } - } - } - - 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 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; - - for (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(massPi); - double rapKa = track.rapidity(massKa); - double rapPr = track.rapidity(massPr); - double innerParam = track.tpcInnerParam(); - - 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); - FillChargedQAHistos(track); - } - - FillBeforePIDQAHistos(track); - - if (rejectTracks(track)) { - return; - } - - // For Pions: - if (selPions(track, innerParam) == cfgSelPi) { - N_Pi++; - pt_Pi = track.pt(); - moments(pt_Pi, &Q1_Pi, &Q2_Pi, &Q3_Pi, &Q4_Pi); - FillIdParticleQAHistos(track, rapPi, nSigmaTPCPi, nSigmaTOFPi); - } - - // For Kaons: - if (selKaons(track, innerParam) == cfgSelKa) { - N_Ka++; - pt_Ka = track.pt(); - moments(pt_Ka, &Q1_Ka, &Q2_Ka, &Q3_Ka, &Q4_Ka); - FillIdParticleQAHistos(track, rapKa, nSigmaTPCKa, nSigmaTOFKa); - } - - // For Protons: - if (selProtons(track, innerParam) == cfgSelPr) { - N_Pr++; - pt_Pr = track.pt(); - moments(pt_Pr, &Q1_Pr, &Q2_Pr, &Q3_Pr, &Q4_Pr); - FillIdParticleQAHistos(track, rapPr, nSigmaTPCPr, nSigmaTOFPr); - } - - } 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); - FillChargedQAHistos(track); - } - FillBeforePIDQAHistos(track); - - if (rejectTracks(track)) - return; - - if (selPions(track, innerParam) == cfgSelPi) { - hist.fill(HIST("QA/Reco/Pion/h_allPt"), track.pt()); - if (std::abs(track.mcParticle().pdgCode()) == 211) { - N_Pi++; - pt_Pi = track.pt(); - moments(pt_Pi, &Q1_Pi, &Q2_Pi, &Q3_Pi, &Q4_Pi); - FillIdParticleQAHistos(track, rapPi, nSigmaTPCPi, nSigmaTOFPi); - } - } - - if (selKaons(track, innerParam) == cfgSelKa) { - hist.fill(HIST("QA/Reco/Kaon/h_allPt"), track.pt()); - if (std::abs(track.mcParticle().pdgCode()) == 321) { - N_Ka++; - pt_Ka = track.pt(); - moments(pt_Ka, &Q1_Ka, &Q2_Ka, &Q3_Ka, &Q4_Ka); - FillIdParticleQAHistos(track, rapKa, nSigmaTPCKa, nSigmaTOFKa); - } - } - - if (selProtons(track, innerParam) == cfgSelPr) { - hist.fill(HIST("QA/Reco/Proton/h_allPt"), track.pt()); - if (std::abs(track.mcParticle().pdgCode()) == 2212) { - N_Pr++; - pt_Pr = track.pt(); - moments(pt_Pr, &Q1_Pr, &Q2_Pr, &Q3_Pr, &Q4_Pr); - FillIdParticleQAHistos(track, rapPr, nSigmaTPCPr, nSigmaTOFPr); - } - } - } - } - } - - N_FT0C = col.multFT0C(); - NTPC = col.multNTracksHasTPC(); - - FillAfterQAHistos(col); - if (NTPC != 0 && Nch != 0) - hist.fill(HIST("QA/after/h2_NTPC_Nch"), NTPC, Nch); - - FillAnalysisHistos(NTPC, N_FT0C, Nch, Q1_ch, Q2_ch, Q3_ch, Q4_ch); - FillAnalysisHistos(NTPC, N_FT0C, N_Pi, Q1_Pi, Q2_Pi, Q3_Pi, Q4_Pi); - FillAnalysisHistos(NTPC, N_FT0C, N_Ka, Q1_Ka, Q2_Ka, Q3_Ka, Q4_Ka); - FillAnalysisHistos(NTPC, N_FT0C, N_Pr, Q1_Pr, Q2_Pr, Q3_Pr, Q4_Pr); - } - - void process_Run3(MyCollisions::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, process_Run3, "Process for Run3", false); - - void process_MCRecoRun3(MyMCCollisions::iterator const& col, aod::McCollisions const&, MyMCTracks const& tracks, aod::McParticles const&) - { - // Before Collision and Track Cuts: - FillBeforeQAHistos(col, tracks); - - // After Collision and Track Cuts: - if (selRun3Col(col)) { - if (!col.has_mcCollision()) { - return; - } - 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, N_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; - - if (abs(mccol.posZ()) > cfgCutPosZ) - return; - - for (auto& mcParticle : McParticles) { - if (!mcParticle.isPhysicalPrimary()) - continue; - - auto charge = 0.; - auto* p = pdg->GetParticle(mcParticle.pdgCode()); - if (p != nullptr) { - charge = p->Charge(); - } - if (std::abs(charge) < 1e-3) { - continue; // reject neutral particles in counters - } - - if (mcParticle.pt() > cfgCutPtMin && mcParticle.pt() < cfgCutPtMax && abs(mcParticle.y()) < cfgCutRap) { - 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 && mcParticle.pt() >= cfgCutPiPtMin) { - 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 && mcParticle.pt() >= cfgCutKaPtMin) { - 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 && mcParticle.pt() >= cfgCutPrPtMin) { - 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(); - N_FT0C = mccol.multMCFT0C(); - hist.fill(HIST("Gen/Counts"), 2); - hist.fill(HIST("Gen/vtxZ"), mccol.posZ()); - hist.fill(HIST("Gen/NTPC"), NTPC); - hist.fill(HIST("Gen/NFT0C"), N_FT0C); - hist.fill(HIST("Gen/h2_NTPC_NFT0C"), N_FT0C, NTPC); - - FillAnalysisHistos(NTPC, N_FT0C, Nch, Q1_ch, Q2_ch, Q3_ch, Q4_ch); - FillAnalysisHistos(NTPC, N_FT0C, N_Pi, Q1_Pi, Q2_Pi, Q3_Pi, Q4_Pi); - FillAnalysisHistos(NTPC, N_FT0C, N_Ka, Q1_Ka, Q2_Ka, Q3_Ka, Q4_Ka); - FillAnalysisHistos(NTPC, N_FT0C, N_Pr, Q1_Pr, Q2_Pr, Q3_Pr, Q4_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/MeanptFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx index 99ed000b01a..77706f1bfd6 100644 --- a/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx @@ -9,45 +9,53 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#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" +/// \file MeanptFluctuations.cxx +/// \brief Task for analyzing fluctuation upto fourth order of inclusive hadrons +/// \author Swati Saha -#include "Common/DataModel/EventSelection.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 "CommonConstants/MathConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include +#include "TF1.h" +#include "TH1D.h" +#include "TH2D.h" #include "TList.h" +#include "TMath.h" #include "TProfile.h" #include "TProfile2D.h" -#include "TH2D.h" -#include "TH1D.h" #include "TRandom3.h" -#include "TMath.h" -#include "TF1.h" + +#include +#include +#include +#include +#include +#include +#include namespace o2::aod { -namespace ptQn +namespace pt_qn { DECLARE_SOA_COLUMN(Q1, q1, float); //! sum of pT of tracks in an event DECLARE_SOA_COLUMN(Q2, q2, float); //! sum of (pT)^2 of tracks in an event DECLARE_SOA_COLUMN(Q3, q3, float); //! sum of (pT)^3 of tracks in an event DECLARE_SOA_COLUMN(Q4, q4, float); //! sum of (pT)^4 of tracks in an event -DECLARE_SOA_COLUMN(N_ch, n_ch, float); //! no of charged particles/multiplicity in an event +DECLARE_SOA_COLUMN(Nch, nch, float); //! no of charged particles/multiplicity in an event DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Centrality of event -} // namespace ptQn -DECLARE_SOA_TABLE(MultPtQn, "AOD", "PTQN", ptQn::Q1, ptQn::Q2, ptQn::Q3, ptQn::Q4, ptQn::N_ch, ptQn::Centrality); //! table to store e-by-e sum of pT, (pT)^2, (pT)^3, (pT)^4 of tracks, multiplicity and centrality +} // namespace pt_qn +DECLARE_SOA_TABLE(MultPtQn, "AOD", "PTQN", pt_qn::Q1, pt_qn::Q2, pt_qn::Q3, pt_qn::Q4, pt_qn::Nch, pt_qn::Centrality); //! table to store e-by-e sum of pT, (pT)^2, (pT)^3, (pT)^4 of tracks, multiplicity and centrality } // namespace o2::aod using namespace o2; @@ -56,34 +64,85 @@ using namespace o2::framework::expressions; #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; -struct MeanptFluctuations_QA_QnTable { +struct MeanptFluctuationsQAQnTable { Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutPreSelEta{"cfgCutPreSelEta", 0.8f, "|eta| cfgCutPreSelPt{"cfgCutPreSelPt", 5.0f, "Maximum allowed pT"}; Configurable cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut"}; Configurable cfgCutPtUpper{"cfgCutPtUpper", 3.0f, "Higher pT cut"}; Configurable cfgCutTpcChi2NCl{"cfgCutTpcChi2NCl", 2.5f, "Maximum TPCchi2NCl"}; - // Configurable cfgCutTrackDcaXY{"cfgCutTrackDcaXY", 0.2f, "Maximum DcaXY"}; + Configurable cfgCutItsChi2NCl{"cfgCutItsChi2NCl", 36.0f, "Maximum ITSchi2NCl"}; Configurable cfgCutTrackDcaZ{"cfgCutTrackDcaZ", 2.0f, "Maximum DcaZ"}; - ConfigurableAxis nchAxis{"nchAxis", {5000, 0.5, 5000.5}, ""}; + 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"}; + ConfigurableAxis nchAxis{"nchAxis", {500, 0.5, 500.5}, "Axis for multiplicity of GlobalTracks/PVTracks"}; + ConfigurableAxis nchAxis2{"nchAxis2", {1000, 0.5, 30000.5}, "Axis for multiplicity of FT0A/FT0C/FV0A"}; + ConfigurableAxis nchAxis3{"nchAxis3", {1000, 0.5, 100000.5}, "Axis for multiplicity of FT0A/FT0C/FV0A"}; + ConfigurableAxis centAxis{"centAxis", {90, 0., 90.0}, ""}; + Configurable cfgEvSelkNoSameBunchPileup{"cfgEvSelkNoSameBunchPileup", true, "Pileup removal"}; + Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Remove time interval with dead ITS zone"}; + Configurable cfgEvSelkNoITSROFrameBorder{"cfgEvSelkNoITSROFrameBorder", true, "ITSROFrame border event selection cut"}; + Configurable cfgEvSelkNoTimeFrameBorder{"cfgEvSelkNoTimeFrameBorder", true, "TimeFrame border event selection cut"}; + Configurable cfgEvSelUseGoodZvtxFT0vsPV{"cfgEvSelUseGoodZvtxFT0vsPV", true, "GoodZvertex and FT0 vs PV cut"}; + Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 1, "Centrlaity estimatore choice: 1-->FT0C, 2-->FT0A; 3-->FT0M, 4-->FV0A"}; + + O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") + O2_DEFINE_CONFIGURABLE(cfgEvSelV0AT0ACut, bool, true, "V0A T0A 5 sigma cut") + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgMultCentHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 10.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCentLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultT0CCutEnabled, bool, false, "Enable Global multiplicity vs T0C centrality cut") + Configurable> cfgMultT0CCutPars{"cfgMultT0CCutPars", std::vector{143.04, -4.58368, 0.0766055, -0.000727796, 2.86153e-06, 23.3108, -0.36304, 0.00437706, -4.717e-05, 1.98332e-07}, "Global multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultPVT0CCutEnabled, bool, false, "Enable PV multiplicity vs T0C centrality cut") + Configurable> cfgMultPVT0CCutPars{"cfgMultPVT0CCutPars", std::vector{195.357, -6.15194, 0.101313, -0.000955828, 3.74793e-06, 30.0326, -0.43322, 0.00476265, -5.11206e-05, 2.13613e-07}, "PV multiplicity vs T0C centrality cut parameter values"}; + + O2_DEFINE_CONFIGURABLE(cfgMultMultPVHighCutFunction, std::string, "[0]+[1]*x + 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultPVLowCutFunction, std::string, "[0]+[1]*x - 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCutEnabled, bool, false, "Enable global multiplicity vs PV multiplicity cut") + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", std::vector{-0.140809, 0.734344, 2.77495, 0.0165935}, "PV multiplicity vs T0C centrality cut parameter values"}; + + O2_DEFINE_CONFIGURABLE(cfgMultMultV0AHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 4.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ALowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ACutEnabled, bool, false, "Enable global multiplicity vs V0A multiplicity cut") + Configurable> cfgMultMultV0ACutPars{"cfgMultMultV0ACutPars", std::vector{534.893, 184.344, 0.423539, -0.00331436, 5.34622e-06, 871.239, 53.3735, -0.203528, 0.000122758, 5.41027e-07}, "Global multiplicity vs V0A multiplicity cut parameter values"}; + + std::vector multT0CCutPars; + std::vector multPVT0CCutPars; + std::vector multGlobalPVCutPars; + std::vector multMultV0ACutPars; + TF1* fMultPVT0CCutLow = nullptr; + TF1* fMultPVT0CCutHigh = nullptr; + TF1* fMultT0CCutLow = nullptr; + TF1* fMultT0CCutHigh = nullptr; + TF1* fMultGlobalPVCutLow = nullptr; + TF1* fMultGlobalPVCutHigh = nullptr; + TF1* fMultMultV0ACutLow = nullptr; + TF1* fMultMultV0ACutHigh = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + + } cfgFuncParas; O2_DEFINE_CONFIGURABLE(cfgUse22sEventCut, bool, true, "Use 22s event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgUseSmallIonAdditionalEventCut, bool, true, "Use additional event cut on mult correlations for small ions") // Filter command*********** Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; - Filter trackFilter = (nabs(aod::track::eta) < 0.8f) && (aod::track::pt > cfgCutPtLower) && (aod::track::pt < 5.0f) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutTpcChi2NCl) && (nabs(aod::track::dcaZ) < cfgCutTrackDcaZ); - // Filter trackFilter = (nabs(aod::track::eta) < 0.8f) && (aod::track::pt > cfgCutPtLower) && (aod::track::pt < 5.0f) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::tpcChi2NCl < cfgCutTpcChi2NCl) && (nabs(aod::track::dcaXY) < cfgCutTrackDcaZ) && (nabs(aod::track::dcaZ) < cfgCutTrackDcaZ); + Filter trackFilter = (nabs(aod::track::eta) < cfgCutPreSelEta) && (aod::track::pt > cfgCutPtLower) && (aod::track::pt < cfgCutPreSelPt) && (requireGlobalTrackInFilter()) && (aod::track::tpcChi2NCl < cfgCutTpcChi2NCl) && (aod::track::itsChi2NCl < cfgCutItsChi2NCl) && (nabs(aod::track::dcaZ) < cfgCutTrackDcaZ); // 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"}; + 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://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // filtering collisions and tracks*********** - using aodCollisions = soa::Filtered>; + using AodCollisions = soa::Filtered>; // using aodCollisions = soa::Filtered>; - using aodTracks = soa::Filtered>; + using AodTracks = soa::Filtered>; // Event selection cuts - Alex TF1* fMultPVCutLow = nullptr; @@ -101,14 +160,12 @@ struct MeanptFluctuations_QA_QnTable { // 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.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; - std::vector centBining = {0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}; - AxisSpec centAxis = {centBining, "centrality (%)"}; // Add histograms to histogram manager (as in the output object of in AliPhysics) histos.add("hZvtx_after_sel", ";Z (cm)", kTH1F, {vtxZAxis}); histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.2, 4.}}); histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); - histos.add("hPhi", ";#phi", kTH1F, {{100, 0., 2. * M_PI}}); + histos.add("hPhi", ";#phi", kTH1F, {{100, 0., o2::constants::math::TwoPI}}); histos.add("hEta", ";#eta", kTH1F, {{100, -2.01, 2.01}}); histos.add("hCentrality", ";centrality (%)", kTH1F, {{90, 0, 90}}); histos.add("hDcaXY", ";#it{dca}_{XY}", kTH1F, {{1000, -5, 5}}); @@ -116,6 +173,22 @@ struct MeanptFluctuations_QA_QnTable { histos.add("hMeanPt", "", kTProfile, {centAxis}); histos.add("Hist2D_globalTracks_PVTracks", "", {HistType::kTH2D, {nchAxis, nchAxis}}); histos.add("Hist2D_cent_nch", "", {HistType::kTH2D, {nchAxis, centAxis}}); + // before selection + histos.add("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_PVTracks_beforeSel", "", {HistType::kTH2D, {nchAxis, nchAxis}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_centFT0C_beforeSel", "", {HistType::kTH2D, {centAxis, nchAxis}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_PVTracks_centFT0C_beforeSel", "", {HistType::kTH2D, {centAxis, nchAxis}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_V0ATracks_beforeSel", "", {HistType::kTH2D, {nchAxis3, nchAxis}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_T0ATracks_beforeSel", "", {HistType::kTH2D, {nchAxis2, nchAxis}}); + histos.add("MultCorrelationPlots/BeforeSelection/His2D_V0ATracks_T0CTracks_beforeSel", "", {HistType::kTH2D, {nchAxis2, nchAxis3}}); + // after selection + if (cfgUseSmallIonAdditionalEventCut) { + histos.add("MultCorrelationPlots/AfterSelection/His2D_globalTracks_PVTracks_afterSel", "", {HistType::kTH2D, {nchAxis, nchAxis}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_globalTracks_centFT0C_afterSel", "", {HistType::kTH2D, {centAxis, nchAxis}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_PVTracks_centFT0C_afterSel", "", {HistType::kTH2D, {centAxis, nchAxis}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_globalTracks_V0ATracks_afterSel", "", {HistType::kTH2D, {nchAxis3, nchAxis}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_globalTracks_T0ATracks_afterSel", "", {HistType::kTH2D, {nchAxis2, nchAxis}}); + histos.add("MultCorrelationPlots/AfterSelection/His2D_V0ATracks_T0CTracks_afterSel", "", {HistType::kTH2D, {nchAxis2, nchAxis3}}); + } // Event selection - Alex if (cfgUse22sEventCut) { @@ -132,6 +205,33 @@ struct MeanptFluctuations_QA_QnTable { fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05); } + if (cfgEvSelMultCorrelation) { + cfgFuncParas.multT0CCutPars = cfgFuncParas.cfgMultT0CCutPars; + cfgFuncParas.multPVT0CCutPars = cfgFuncParas.cfgMultPVT0CCutPars; + cfgFuncParas.multGlobalPVCutPars = cfgFuncParas.cfgMultGlobalPVCutPars; + cfgFuncParas.multMultV0ACutPars = cfgFuncParas.cfgMultMultV0ACutPars; + cfgFuncParas.fMultPVT0CCutLow = new TF1("fMultPVT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutLow->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultPVT0CCutHigh = new TF1("fMultPVT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutHigh->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultT0CCutLow = new TF1("fMultT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutLow->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultT0CCutHigh = new TF1("fMultT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutHigh->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultGlobalPVCutLow = new TF1("fMultGlobalPVCutLow", cfgFuncParas.cfgMultMultPVLowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutLow->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultGlobalPVCutHigh = new TF1("fMultGlobalPVCutHigh", cfgFuncParas.cfgMultMultPVHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutHigh->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultMultV0ACutLow = new TF1("fMultMultV0ACutLow", cfgFuncParas.cfgMultMultV0ALowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutLow->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fMultMultV0ACutHigh = new TF1("fMultMultV0ACutHigh", cfgFuncParas.cfgMultMultV0AHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutHigh->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + cfgFuncParas.fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + cfgFuncParas.fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + cfgFuncParas.fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + } //! end init function template @@ -144,8 +244,10 @@ struct MeanptFluctuations_QA_QnTable { float vtxz = -999; if (collision.numContrib() > 1) { vtxz = collision.posZ(); - float zRes = TMath::Sqrt(collision.covZZ()); - if (zRes > 0.25 && collision.numContrib() < 20) + float zRes = std::sqrt(collision.covZZ()); + float zResMax = 0.25; + float numContribMin = 20; + if (zRes > zResMax && collision.numContrib() < numContribMin) vtxz = -999; } auto multNTracksPV = collision.multNTracksPV(); @@ -166,35 +268,138 @@ struct MeanptFluctuations_QA_QnTable { return 1; } - Produces mult_ptQn; + template + bool eventSelectedSmallion(TCollision collision, const int multTrk, const float centrality) + { + auto multNTracksPV = collision.multNTracksPV(); + + if (cfgEvSelMultCorrelation) { + if (cfgFuncParas.cfgMultPVT0CCutEnabled) { + if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(centrality)) + return 0; + } + + if (cfgFuncParas.cfgMultT0CCutEnabled) { + if (multTrk < cfgFuncParas.fMultT0CCutLow->Eval(centrality)) + return 0; + if (multTrk > cfgFuncParas.fMultT0CCutHigh->Eval(centrality)) + return 0; + } + + if (cfgFuncParas.cfgMultGlobalPVCutEnabled) { + if (multTrk < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) + return 0; + if (multTrk > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) + return 0; + } + + if (cfgFuncParas.cfgMultMultV0ACutEnabled) { + if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(multTrk)) + return 0; + if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(multTrk)) + return 0; + } + } + + float sigma = 5.0; + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > sigma * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + + return 1; + } + + Produces multPtQn; // void process(aod::Collision const& coll, aod::Tracks const& inputTracks) - void process(aodCollisions::iterator const& coll, aod::BCsWithTimestamps const&, aodTracks const& inputTracks) + void process(AodCollisions::iterator const& coll, aod::BCsWithTimestamps const&, AodTracks const& inputTracks) { - if (!coll.sel8()) + if (!coll.sel8()) { + return; + } + if (cfgUseGoodITSLayerAllCut && !(coll.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + return; + } + if (cfgEvSelkNoSameBunchPileup && !(coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { return; + } + if (cfgEvSelkNoITSROFrameBorder && !(coll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + return; + } + if (cfgEvSelkNoTimeFrameBorder && !(coll.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { + return; + } + if (cfgEvSelUseGoodZvtxFT0vsPV && !(coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_PVTracks_beforeSel"), coll.multNTracksPV(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_centFT0C_beforeSel"), coll.centFT0C(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_PVTracks_centFT0C_beforeSel"), coll.centFT0C(), coll.multNTracksPV()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_V0ATracks_beforeSel"), coll.multFV0A(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_globalTracks_T0ATracks_beforeSel"), coll.multFT0A(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/BeforeSelection/His2D_V0ATracks_T0CTracks_beforeSel"), coll.multFT0C(), coll.multFV0A()); - const auto CentralityFT0C = coll.centFT0C(); - if (cfgUse22sEventCut && !eventSelected(coll, inputTracks.size(), CentralityFT0C)) + const auto centralityFT0C = coll.centFT0C(); + if (cfgUse22sEventCut && !eventSelected(coll, inputTracks.size(), centralityFT0C)) + return; + if (cfgUseSmallIonAdditionalEventCut && !eventSelectedSmallion(coll, inputTracks.size(), centralityFT0C)) return; + if (cfgUseSmallIonAdditionalEventCut) { + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_globalTracks_PVTracks_afterSel"), coll.multNTracksPV(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_globalTracks_centFT0C_afterSel"), coll.centFT0C(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_PVTracks_centFT0C_afterSel"), coll.centFT0C(), coll.multNTracksPV()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_globalTracks_V0ATracks_afterSel"), coll.multFV0A(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_globalTracks_T0ATracks_afterSel"), coll.multFT0A(), inputTracks.size()); + histos.fill(HIST("MultCorrelationPlots/AfterSelection/His2D_V0ATracks_T0CTracks_afterSel"), coll.multFT0C(), coll.multFV0A()); + } + histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); - histos.fill(HIST("hCentrality"), coll.centFT0C()); + + double cent = 0.0; + int centChoiceFT0C = 1; + int centChoiceFT0A = 2; + int centChoiceFT0M = 3; + int centChoiceFV0A = 4; + if (cfgCentralityEstimator == centChoiceFT0C) + cent = coll.centFT0C(); + else if (cfgCentralityEstimator == centChoiceFT0A) + cent = coll.centFT0A(); + else if (cfgCentralityEstimator == centChoiceFT0M) + cent = coll.centFT0M(); + else if (cfgCentralityEstimator == centChoiceFV0A) + cent = coll.centFV0A(); + + histos.fill(HIST("hCentrality"), cent); + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), inputTracks.size()); - histos.fill(HIST("Hist2D_cent_nch"), inputTracks.size(), CentralityFT0C); + histos.fill(HIST("Hist2D_cent_nch"), inputTracks.size(), centralityFT0C); // variables - double cent = coll.centFT0C(); - double pT_sum = 0.0; - double N = 0.0; + double pTsum = 0.0; + double nN = 0.0; float q1 = 0.0; float q2 = 0.0; float q3 = 0.0; float q4 = 0.0; - float n_ch = 0.0; + float nCh = 0.0; - for (auto track : inputTracks) { // Loop over tracks + for (const auto& track : inputTracks) { // Loop over tracks + + if (!track.has_collision()) { + continue; + } + + if (!track.isPVContributor()) { + continue; + } + + if (!(track.itsNCls() > cfgITScluster) || !(track.tpcNClsFound() >= cfgTPCcluster) || !(track.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) { + continue; + } histos.fill(HIST("hP"), track.p()); histos.fill(HIST("hPt"), track.pt()); @@ -203,44 +408,45 @@ struct MeanptFluctuations_QA_QnTable { histos.fill(HIST("hDcaXY"), track.dcaXY()); histos.fill(HIST("hDcaZ"), track.dcaZ()); - pT_sum += track.pt(); - N += 1.0; + pTsum += track.pt(); + nN += 1.0; float pT = track.pt(); - // calculating Q1, Q2, Q3, Q4. N_ch + // calculating Q1, Q2, Q3, Q4. Nch if (track.pt() > cfgCutPtLower && track.pt() < cfgCutPtUpper && track.sign() != 0) { - q1 = q1 + pow(pT, 1.0); - q2 = q2 + pow(pT, 2.0); - q3 = q3 + pow(pT, 3.0); - q4 = q4 + pow(pT, 4.0); - n_ch = n_ch + 1; + q1 = q1 + std::pow(pT, 1.0); + q2 = q2 + std::pow(pT, 2.0); + q3 = q3 + std::pow(pT, 3.0); + q4 = q4 + std::pow(pT, 4.0); + nCh = nCh + 1; } } - mult_ptQn(q1, q2, q3, q4, n_ch, cent); + multPtQn(q1, q2, q3, q4, nCh, cent); // MeanPt - if (N > 0.0f) - histos.fill(HIST("hMeanPt"), cent, pT_sum / N); + if (nN > 0.0f) + histos.fill(HIST("hMeanPt"), cent, pTsum / nN); } }; -struct MeanptFluctuations_analysis { +struct MeanptFluctuationsAnalysis { - Configurable cfgNSubsample{"cfgNSubsample", 10, "Number of subsamples"}; + Configurable cfgNsubSample{"cfgNsubSample", 10, "Number of subsamples"}; ConfigurableAxis centAxis{"centAxis", {90, 0, 90}, ""}; ConfigurableAxis multAxis{"multAxis", {5000, 0.5, 5000.5}, ""}; ConfigurableAxis meanpTAxis{"meanpTAxis", {500, 0, 5.0}, ""}; - expressions::Filter Nch_filter = aod::ptQn::n_ch > 3.0f; + float minNch = 3.0f; + expressions::Filter nchFilter = aod::pt_qn::nch > minNch; using FilteredMultPtQn = soa::Filtered; // 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"}; + 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://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; // Define output HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - std::vector>> Subsample; + std::vector>> subSample; TRandom3* fRndm = new TRandom3(0); void init(o2::framework::InitContext&) @@ -256,49 +462,49 @@ struct MeanptFluctuations_analysis { registry.add("Hist2D_meanpt_centrality", "", {HistType::kTH2D, {centAxis, meanpTAxis}}); // initial array - Subsample.resize(cfgNSubsample); - for (int i = 0; i < cfgNSubsample; i++) { - Subsample[i].resize(4); + subSample.resize(cfgNsubSample); + for (int i = 0; i < cfgNsubSample; i++) { + subSample[i].resize(4); } - for (int i = 0; i < cfgNSubsample; i++) { - Subsample[i][0] = std::get>(registry.add(Form("Subsample_%d/Prof_mean_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); - Subsample[i][1] = std::get>(registry.add(Form("Subsample_%d/Prof_var_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); - Subsample[i][2] = std::get>(registry.add(Form("Subsample_%d/Prof_skew_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); - Subsample[i][3] = std::get>(registry.add(Form("Subsample_%d/Prof_kurt_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); + for (int i = 0; i < cfgNsubSample; i++) { + subSample[i][0] = std::get>(registry.add(Form("subSample_%d/Prof_mean_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); + subSample[i][1] = std::get>(registry.add(Form("subSample_%d/Prof_var_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); + subSample[i][2] = std::get>(registry.add(Form("subSample_%d/Prof_skew_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); + subSample[i][3] = std::get>(registry.add(Form("subSample_%d/Prof_kurt_t1", i), "", {HistType::kTProfile2D, {centAxis, multAxis}})); } } - float mean_term1; - float variance_term1; - float skewness_term1; - float kurtosis_term1; + float meanTerm1; + float varianceTerm1; + float skewnessTerm1; + float kurtosisTerm1; // void process(aod::MultPtQn::iterator const& event_ptqn) void process(FilteredMultPtQn::iterator const& event_ptqn) { - // LOGF(info, "Centrality= %f Nch= %f Q1= %f Q2= %f", event_ptqn.centrality(), event_ptqn.n_ch(), event_ptqn.q1(), event_ptqn.q2()); + // LOGF(info, "Centrality= %f Nch= %f Q1= %f Q2= %f", event_ptqn.centrality(), event_ptqn.nch(), event_ptqn.q1(), event_ptqn.q2()); // calculating observables - mean_term1 = event_ptqn.q1() / event_ptqn.n_ch(); - variance_term1 = (TMath::Power(event_ptqn.q1(), 2.0f) - event_ptqn.q2()) / (event_ptqn.n_ch() * (event_ptqn.n_ch() - 1.0f)); - skewness_term1 = (TMath::Power(event_ptqn.q1(), 3.0f) - 3.0f * event_ptqn.q2() * event_ptqn.q1() + 2.0f * event_ptqn.q3()) / (event_ptqn.n_ch() * (event_ptqn.n_ch() - 1.0f) * (event_ptqn.n_ch() - 2.0f)); - kurtosis_term1 = (TMath::Power(event_ptqn.q1(), 4.0f) - (6.0f * event_ptqn.q4()) + (8.0f * event_ptqn.q1() * event_ptqn.q3()) - (6.0f * TMath::Power(event_ptqn.q1(), 2.0f) * event_ptqn.q2()) + (3.0f * TMath::Power(event_ptqn.q2(), 2.0f))) / (event_ptqn.n_ch() * (event_ptqn.n_ch() - 1.0f) * (event_ptqn.n_ch() - 2.0f) * (event_ptqn.n_ch() - 3.0f)); + meanTerm1 = event_ptqn.q1() / event_ptqn.nch(); + varianceTerm1 = (std::pow(event_ptqn.q1(), 2.0f) - event_ptqn.q2()) / (event_ptqn.nch() * (event_ptqn.nch() - 1.0f)); + skewnessTerm1 = (std::pow(event_ptqn.q1(), 3.0f) - 3.0f * event_ptqn.q2() * event_ptqn.q1() + 2.0f * event_ptqn.q3()) / (event_ptqn.nch() * (event_ptqn.nch() - 1.0f) * (event_ptqn.nch() - 2.0f)); + kurtosisTerm1 = (std::pow(event_ptqn.q1(), 4.0f) - (6.0f * event_ptqn.q4()) + (8.0f * event_ptqn.q1() * event_ptqn.q3()) - (6.0f * std::pow(event_ptqn.q1(), 2.0f) * event_ptqn.q2()) + (3.0f * std::pow(event_ptqn.q2(), 2.0f))) / (event_ptqn.nch() * (event_ptqn.nch() - 1.0f) * (event_ptqn.nch() - 2.0f) * (event_ptqn.nch() - 3.0f)); // filling profiles and histograms for central values - registry.get(HIST("Prof_mean_t1"))->Fill(event_ptqn.centrality(), event_ptqn.n_ch(), mean_term1); - registry.get(HIST("Prof_var_t1"))->Fill(event_ptqn.centrality(), event_ptqn.n_ch(), variance_term1); - registry.get(HIST("Prof_skew_t1"))->Fill(event_ptqn.centrality(), event_ptqn.n_ch(), skewness_term1); - registry.get(HIST("Prof_kurt_t1"))->Fill(event_ptqn.centrality(), event_ptqn.n_ch(), kurtosis_term1); - registry.fill(HIST("Hist2D_Nch_centrality"), event_ptqn.centrality(), event_ptqn.n_ch()); - registry.fill(HIST("Hist2D_meanpt_centrality"), event_ptqn.centrality(), mean_term1); + registry.get(HIST("Prof_mean_t1"))->Fill(event_ptqn.centrality(), event_ptqn.nch(), meanTerm1); + registry.get(HIST("Prof_var_t1"))->Fill(event_ptqn.centrality(), event_ptqn.nch(), varianceTerm1); + registry.get(HIST("Prof_skew_t1"))->Fill(event_ptqn.centrality(), event_ptqn.nch(), skewnessTerm1); + registry.get(HIST("Prof_kurt_t1"))->Fill(event_ptqn.centrality(), event_ptqn.nch(), kurtosisTerm1); + registry.fill(HIST("Hist2D_Nch_centrality"), event_ptqn.centrality(), event_ptqn.nch()); + registry.fill(HIST("Hist2D_meanpt_centrality"), event_ptqn.centrality(), meanTerm1); // selecting subsample and filling profiles - float l_Random = fRndm->Rndm(); - int SampleIndex = static_cast(cfgNSubsample * l_Random); - Subsample[SampleIndex][0]->Fill(event_ptqn.centrality(), event_ptqn.n_ch(), mean_term1); - Subsample[SampleIndex][1]->Fill(event_ptqn.centrality(), event_ptqn.n_ch(), variance_term1); - Subsample[SampleIndex][2]->Fill(event_ptqn.centrality(), event_ptqn.n_ch(), skewness_term1); - Subsample[SampleIndex][3]->Fill(event_ptqn.centrality(), event_ptqn.n_ch(), kurtosis_term1); + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNsubSample * lRandom); + subSample[sampleIndex][0]->Fill(event_ptqn.centrality(), event_ptqn.nch(), meanTerm1); + subSample[sampleIndex][1]->Fill(event_ptqn.centrality(), event_ptqn.nch(), varianceTerm1); + subSample[sampleIndex][2]->Fill(event_ptqn.centrality(), event_ptqn.nch(), skewnessTerm1); + subSample[sampleIndex][3]->Fill(event_ptqn.centrality(), event_ptqn.nch(), kurtosisTerm1); } }; @@ -306,7 +512,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { // Equivalent to the AddTask in AliPhysics return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; } diff --git a/PWGCF/EbyEFluctuations/Tasks/NetProtonCumulants.cxx b/PWGCF/EbyEFluctuations/Tasks/NetProtonCumulants.cxx index a18b0b97df9..f8db71203fa 100644 --- a/PWGCF/EbyEFluctuations/Tasks/NetProtonCumulants.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/NetProtonCumulants.cxx @@ -9,26 +9,28 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include -#include -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.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/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include #include "TList.h" +#include "TMath.h" #include "TProfile.h" #include "TProfile2D.h" #include "TRandom3.h" -#include "TMath.h" + +#include +#include namespace o2::aod { diff --git a/PWGCF/EbyEFluctuations/Tasks/RobustFluctuationObservables.cxx b/PWGCF/EbyEFluctuations/Tasks/RobustFluctuationObservables.cxx index 191158c7ba0..82e77dc45f8 100644 --- a/PWGCF/EbyEFluctuations/Tasks/RobustFluctuationObservables.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/RobustFluctuationObservables.cxx @@ -12,32 +12,35 @@ /// \brief This task is a QA task to accumulate basic event- and track-level plots. /// \author Igor Altsybeev, Igor.Altsybeev@cern.ch -#include -#include - -#include "TF1.h" -#include "TGraphErrors.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.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 "DataFormatsFT0/Digit.h" #include "DataFormatsParameters/GRPECSObject.h" #include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" -#include "Common/DataModel/FT0Corrected.h" -#include "DataFormatsFT0/Digit.h" +#include "TF1.h" +#include "TGraphErrors.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include +#include +#include +#include +#include using namespace std; using namespace o2; @@ -82,7 +85,7 @@ 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; @@ -101,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; @@ -154,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"}; @@ -163,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; @@ -968,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); @@ -1474,23 +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 = (int32_t)bcInTF - (int32_t)prevBcInTF; + int32_t diffBcInTF = static_cast(bcInTF) - static_cast(prevBcInTF); histosEvent.fill(HIST("hBCinTF_DIFF_to_previous"), diffBcInTF); } if (prevFoundBcInTF >= 0) { - int32_t diffGlobalBcInTF = (int32_t)foundBcInTF - (int32_t)prevFoundBcInTF; + 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) { @@ -1620,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; @@ -1680,11 +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; + 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, (int64_t)foundBcInTF - (int64_t)bcInTF); + histosEvent.fill(HIST("h2D_diffFoundBC_vs_BC_inTF"), collBC, static_cast(foundBcInTF) - static_cast(bcInTF)); // with FT0 conditions if (isFT0) { @@ -2290,8 +2293,8 @@ struct RobustFluctuationObservables { } } // end of v0 loop - } // end of if (flagIncludeQAHistK0S) - } // end of processRobustFluctuationObservables() + } // end of if (flagIncludeQAHistK0S) + } // end of processRobustFluctuationObservables() // shortcut function to fill 2D histograms void fillHistForThisCut(string cutName, int multNTracksPV, int multTrk, int nTracksGlobalAccepted, double multT0A, double multT0C, double multV0A, double /*t0cCentr*/, int bc) diff --git a/PWGCF/EbyEFluctuations/Tasks/antiprotonCumulantsMc.cxx b/PWGCF/EbyEFluctuations/Tasks/antiprotonCumulantsMc.cxx new file mode 100644 index 00000000000..6bc72a2c9e2 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/antiprotonCumulantsMc.cxx @@ -0,0 +1,2952 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include +#include +#include +#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/eventMeanPtId.cxx b/PWGCF/EbyEFluctuations/Tasks/eventMeanPtId.cxx new file mode 100644 index 00000000000..693c057ad9b --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/eventMeanPtId.cxx @@ -0,0 +1,1476 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file eventMeanPtId.cxx +/// \brief Analysis task to study Mean pT Fluctuations using two particle correlator using Cumulant Method +/// \author Sweta Singh (sweta.singh@cern.ch) + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include "TF1.h" +#include + +#include +#include +#include +#include + +double massPi = o2::constants::physics::MassPionCharged; +double massKa = o2::constants::physics::MassKaonCharged; +double massPr = o2::constants::physics::MassProton; + +using namespace o2::constants::physics; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; +using o2::constants::physics::Pdg; + +struct EventMeanPtId { + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + // Configurables + Configurable cVtxZcut{"cVtxZcut", 10.0f, "Vertex Z"}; + Configurable cEtacut{"cEtacut", 0.8f, "Eta cut"}; + Configurable cPtmincut{"cPtmincut", 0.15f, "Pt min cut"}; + Configurable cPtmaxcut{"cPtmaxcut", 2.0f, "Pt max cut"}; + Configurable cPtmincut1{"cPtmincut1", 0.15f, " Pt min cut"}; + Configurable cPtmaxcut1{"cPtmaxcut1", 2.0f, " Pt max cut"}; + Configurable cDcaXYcut{"cDcaXYcut", 0.3f, "DCA XY cut"}; + Configurable cDcaZcut{"cDcaZcut", 2.0f, "DCA Z cut"}; + Configurable cCentmincut{"cCentmincut", 0.0, "Min cent cut"}; + Configurable cCentmaxcut{"cCentmaxcut", 90.0, "Max cent cut"}; + Configurable csyTPCcrosscut{"csyTPCcrosscut", 70, "TPC crossrows cut"}; + Configurable csysItsChiCut{"csysItsChiCut", 36, "ITS chi2 cluster cut"}; + Configurable csysTpcChiCut{"csysTpcChiCut", 4, "TPC chi2 cluster cut"}; + Configurable csysnITSClustersCut{"csysnITSClustersCut", 5, "Number of ITS clusters cut"}; + Configurable csystpcNClsCut{"csystpcNClsCut", 80, "No. of TPC clusters cut"}; + Configurable threshold{"threshold", 1e-6, "Delta eta bin count"}; + Configurable ptMax{"ptMax", 2.0, "maximum pT"}; + Configurable ptMin{"ptMin", 0.15, "minimum pT"}; + 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"}; + // Event selections + Configurable cSel8Trig{"cSel8Trig", true, "Sel8 (T0A + T0C) Selection Run3"}; + Configurable cpileupTFBorder{"cpileupTFBorder", true, "Timeframe Border Selection"}; + Configurable cpileupNoItsROBorder{"cpileupNoItsROBorder", true, "No ITSRO Border Cut"}; + Configurable cpileupItsTpcVtx{"cpileupItsTpcVtx", true, "ITS+TPC Vertex Selection"}; + Configurable cpileupSameBunch{"cpileupSameBunch", true, "Pileup rejection"}; + Configurable cpileupZVtxTimeDiff{"cpileupZVtxTimeDiff", true, "z-vtx time diff selection"}; + Configurable cIsGoodITSLayers{"cIsGoodITSLayers", true, "Good ITS Layers All"}; + Configurable cpileupItslayerall{"cpileupItslayerall", true, "dead staves of ITS removed"}; + Configurable cpileupvtxtofmatched{"cpileupvtxtofmatched", true, "TOF vertex matched"}; + Configurable citsNCluster{"citsNCluster", false, "Enable Number of ITS clusters"}; + Configurable ctpcNClusterFound{"ctpcNClusterFound", false, "Enable Number of TPC clusters"}; + Configurable cPVContributor{"cPVContributor", false, "Enable Primary Vertex Contributor"}; + Configurable csyDCAxy{"csyDCAxy", true, "DCAxy cut"}; + Configurable csyDCAz{"csyDCAz", true, "DCAz cut"}; + Configurable csyTPCcr{"csyTPCcr", true, "tpc crossed rows"}; + Configurable csyITSchi{"csyITSchi", true, "ITS chi2"}; + Configurable csyTPCchi{"csyTPCchi", true, "TPC chi2"}; + Configurable ccentFT0C{"ccentFT0C", true, "Use FT0C centraity"}; + Configurable pidSwitch{"pidSwitch", false, "pid calculations"}; + Configurable pidSwitchHistoFill{"pidSwitchHistoFill", false, "pid histogram filling"}; + Configurable effSwitch{"effSwitch", false, "efficiency calculations"}; + Configurable effSwitchHistoFill{"effSwitchHistoFill", false, "efficiency histogram filling"}; + // PID selection configurables + Configurable cpidPionPmincut{"cpidPionPmincut", 0.15, "pion min cut of pion"}; + Configurable cpidKaonPmincut{"cpidKaonPmincut", 0.15, "kaon min cut of kaon"}; + Configurable cpidProtonPmincut{"cpidProtonPmincut", 0.15, "proton min cut of proton"}; + Configurable cpidPionPmaxcut{"cpidPionPmaxcut", 2.0, "pion min cut of pion"}; + Configurable cpidKaonPmaxcut{"cpidKaonPmaxcut", 2.0, "kaon min cut of kaon"}; + Configurable cpidProtonPmaxcut{"cpidProtonPmaxcut", 2.0, "proton min cut of proton"}; + Configurable cpidPionPthcut{"cpidPionPthcut", 0.65, "pion threshold cut of pion"}; + Configurable cpidKaonPthcut{"cpidKaonPthcut", 0.65, "kaon threshold cut of kaon"}; + Configurable cpidProtonPthcut{"cpidProtonPthcut", 1.0, "proton threshold cut of proton"}; + Configurable cNSigCut2{"cNSigCut2", 2.0, "nSigma cut (2)"}; + Configurable cNSigCut3{"cNSigCut3", 3.0, "nSigma cut (3)"}; + Configurable cElMinCut{"cElMinCut", -3.0, "electron min cut"}; + Configurable cElMaxCut{"cElMaxCut", 5.0, "electron max cut"}; + Configurable cTwoPtlCut2{"cTwoPtlCut2", 2.0, "n2ptl cut"}; + Configurable cRapidityCut05{"cRapidityCut05", 0.5, "rapidity cut"}; + Configurable nchBins{"nchBins", 4000, "Number of bins for nch axis"}; + Configurable nchMin{"nchMin", 0.0, "Minimum value for nch axis"}; + Configurable nchMax{"nchMax", 4000.0, "Maximum value for nch axis"}; + Configurable cSigmaLowHighcut{"cSigmaLowHighcut", 3.0f, "lower and upper sigma cut"}; + O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgMultPVFT0CCutEnabled, bool, true, "Enable PV multiplicity vs FT0C centrality cut") + O2_DEFINE_CONFIGURABLE(cfgMultGlobalFT0CCutEnabled, bool, true, "Enable globalTracks vs FT0C centrality cut") + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCutEnabled, bool, true, "Enable globalTracks vs PV multiplicity cut") + Configurable> cfgMultPVFT0CCutPars{"cfgMultPVFT0CCutPars", + std::vector{3303.11, -121.316, 1.90207, -0.0152644, 5.10121e-05, 190.633, -4.32972, 0.0340001, -5.83261e-05, -3.19566e-07}, + "PV multiplicity vs T0C centrality cut parameter values"}; + Configurable> cfgMultGlobalFT0CCutPars{"cfgMultGlobalFT0CCutPars", + std::vector{1893.97, -61.3423, 0.790664, -0.00507208, 1.41683e-05, 167.997, -5.29125, 0.0840145, -0.000748102, 2.75743e-06}, + "globalTracks vs FT0C cut parameter values"}; + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", + std::vector{65.0322, 0.557725, -0.772828, 0.059224, -1.96379e-05, 4.46295e-09}, + "globalTracks vs PV cut parameter values"}; + std::vector multPVFT0CCutPars; + std::vector multGlobalFT0CPars; + std::vector multGlobalPVCutPars; + TF1* fMultPVFT0CCutLow = nullptr; + TF1* fMultPVFT0CCutHigh = nullptr; + TF1* fMultGlobalFT0CCutLow = nullptr; + TF1* fMultGlobalFT0CCutHigh = nullptr; + TF1* fMultGlobalPVCutLow = nullptr; + TF1* fMultGlobalPVCutHigh = nullptr; + } cfgFunCoeff; + + Service ccdb; + Service pdg; + + Filter collisionFilter = nabs(aod::collision::posZ) <= cVtxZcut; + Filter trackFilter = (nabs(aod::track::eta) < cEtacut) && (aod::track::pt > ptMin) && (aod::track::pt < ptMax) && (requireGlobalTrackInFilter()); + + using MyCollisions = soa::Filtered>; + using MyCollision = MyCollisions::iterator; + using MyTracks = soa::Filtered>; + using MyTrack = MyTracks::iterator; + using MyMCRecoCollisions = soa::Filtered>; + using MyMCRecoCollision = MyMCRecoCollisions::iterator; + using MyMCRecoTracks = soa::Filtered>; + using MyMCRecoTrack = MyMCRecoTracks::iterator; + using EventCandidatesMC = soa::Join; + + 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 cfgUrlCCDB{"cfgUrlCCDB", "http://alice-ccdb.cern.ch", "url of ccdb"}; + Configurable cfgPathCCDB{"cfgPathCCDB", "Users/s/swsingh/My/Object/GlobalRun3DCAcuts", "Path for ccdb-object"}; + Configurable cfgLoadEff{"cfgLoadEff", true, "Load efficiency"}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + TH2D* ptHistogramAllchargeRec = nullptr; + + void init(o2::framework::InitContext&) + { + if (cfgLoadEff) { + // Set CCDB url + ccdb->setURL(cfgUrlCCDB.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + // LOGF(info, "Getting object %s", ccdbPath.value.data()); + TList* lst = ccdb->getForTimeStamp(cfgPathCCDB.value, -1); + ptHistogramAllchargeRec = reinterpret_cast(lst->FindObject("hPtEta_rec")); + } + 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 vtxZAxis = {100, -20.0, 20.0, "Z (cm)"}; + AxisSpec dcaAxis = {1002, -5.01, 5.01, "DCA_{xy} (cm)"}; + AxisSpec dcazAxis = {1002, -5.01, 5.01, "DCA_{z} (cm)"}; + AxisSpec ptAxis = {600, 0.0, 6.0, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pAxis = {400, 0.0, 4.0, "#it{p} (GeV/#it{c})"}; + 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 = {300, -1.5, 1.5, "#eta"}; // 300, -1.5, 1.5 + 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 centAxis = {100, 0., 100., "centrality"}; + AxisSpec subAxis = {30, 0., 30., "sample"}; + AxisSpec tnchAxis = {40, 0., 4000., "nch"}; + AxisSpec nchAxis = {nchBins, nchMin, nchMax, "nch"}; + AxisSpec varAxis1 = {400, 0., 4., "var1"}; + AxisSpec varAxis2 = {400, 0., 4., "var2"}; + AxisSpec tpcchi2Axis = {700, 0., 7., "tpc Chi2"}; + AxisSpec itschi2Axis = {400, 0., 40., "its Chi2"}; + AxisSpec crossedRowTpcAxis = {1600, 0., 160., "TPC Crossed rows"}; + AxisSpec counter = {10, 0., 10., "events"}; + // QA Plots + histos.add("hEventcounter", "event counts", kTH1D, {counter}); + auto h = histos.add("tracksel", "tracksel", HistType::kTH1D, {{15, 0.5, 15.5}}); + h->GetXaxis()->SetBinLabel(1, "Tracks read"); + h->GetXaxis()->SetBinLabel(2, "Global track passed"); + h->GetXaxis()->SetBinLabel(3, "DCAxy passed"); + h->GetXaxis()->SetBinLabel(4, "DCAz passed"); + h->GetXaxis()->SetBinLabel(5, "Eta-cut passed"); + h->GetXaxis()->SetBinLabel(6, "pT-cut passed"); + h->GetXaxis()->SetBinLabel(7, "TPC crossed rows passed"); + h->GetXaxis()->SetBinLabel(8, "TPC Chai2cluster passed"); + h->GetXaxis()->SetBinLabel(9, "ITS Chai2cluster passed"); + h->GetXaxis()->SetBinLabel(10, "No. of ITS cluster 5 passed"); + h->GetXaxis()->SetBinLabel(11, "No. of TPC cluster 80 passed"); + auto hRec = histos.add("trackSelRec", "trackSelRec", HistType::kTH1D, {{10, 0.5, 10.5}}); + hRec->GetXaxis()->SetBinLabel(1, "has_mcCollision() read"); + hRec->GetXaxis()->SetBinLabel(2, "Vertex Z > 10cm passed"); + hRec->GetXaxis()->SetBinLabel(3, "sel 8 passed"); + hRec->GetXaxis()->SetBinLabel(4, "kNoSameBunchPileup passed"); + hRec->GetXaxis()->SetBinLabel(5, "kNoITSROFrameBorder passed"); + hRec->GetXaxis()->SetBinLabel(6, "klsGoodZvtxFT0vsPV passed"); + hRec->GetXaxis()->SetBinLabel(7, "klsVertexITSTPC passed"); + histos.add("Data/hZvtx_before_sel", "hZvtx_before_sel", kTH1D, {vtxZAxis}); + histos.add("Data/hZvtx_after_sel8", "hZvtx_after_sel8", kTH1D, {vtxZAxis}); + histos.add("Data/hP", "hP", kTH1D, {pAxis}); + histos.add("Data/hEta", ";hEta", kTH1D, {etaAxis}); + histos.add("Data/hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); + histos.add("Data/hPtvar", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); + histos.add("Data/hDCAxy", "hDCAxy", kTH1D, {dcaAxis}); + histos.add("Data/hDCAz", "hDCAz", kTH1D, {dcazAxis}); + histos.add("Data/hPtDCAxy", "hPtDCAxy", kTH2D, {ptAxis, dcaAxis}); + histos.add("Data/hPtDCAz", "hPtDCAz", kTH2D, {ptAxis, dcazAxis}); + histos.add("Data/hVar1", "hVar1", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVar2", "hVar2", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVar2meanpt", "hVar2meanpt", kTH2D, {centAxis, varAxis2}); + histos.add("Data/hVarc", "hVarc", kTH2D, {subAxis, centAxis}); + histos.add("Data/hnchAll", ";hnchAll", kTH1D, {nchAxis}); + histos.add("Data/hnchAll_bf_cut", ";hnchAll_bf_cut", kTH1D, {nchAxis}); + histos.add("Data/hnch", ";hnch", kTH1D, {nchAxis}); + histos.add("Data/hnchTrue", ";hnchTrue", kTH1D, {nchAxis}); + histos.add("Data/hnchTrue_pt", ";hnchTrue_pt", kTH1D, {nchAxis}); + histos.add("Data/hVar1x", "hVar1x", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVar2x", "hVar2x", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVarx", "hVarx", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hdiffVar1x", "hdiffVar1x", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hdiffVar2x", "hdiffVar2x", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hdiffVarx", "hdiffVarx", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVar2meanptx", "hVar2meanptx", kTH2D, {nchAxis, varAxis2}); + histos.add("Data/hCentrality", "hCentrality", kTH1D, {centAxis}); + histos.add("Data/hPEta", "hPEta", kTH2D, {pAxis, etaAxis}); + histos.add("Data/hPtEta", "hPtEta", kTH2D, {ptAxis, etaAxis}); + histos.add("Data/hTPCchi2perCluster_before", "TPC #Chi^{2}/Cluster", kTH1D, {tpcchi2Axis}); + histos.add("Data/hITSchi2perCluster_before", "ITS #Chi^{2}/Cluster", kTH1D, {itschi2Axis}); + histos.add("Data/hTPCCrossedrows_before", "Crossed TPC rows", kTH1D, {crossedRowTpcAxis}); + histos.add("Data/hTPCchi2perCluster_after", "TPC #Chi^{2}/Cluster", kTH1D, {tpcchi2Axis}); + histos.add("Data/hITSchi2perCluster_after", "ITS #Chi^{2}/Cluster", kTH1D, {itschi2Axis}); + histos.add("Data/hTPCCrossedrows_after", "Crossed TPC rows", kTH1D, {crossedRowTpcAxis}); + histos.add("Data/hcent_nacc", "hcent_nacc", kTH2D, {centAxis, nchAxis}); + histos.add("Data/hcentFT0A_nacc", "hcentFT0A_nacc", kTH2D, {centAxis, nchAxis}); + histos.add("Data/hcentFT0M_nacc", "hcentFT0M_nacc", kTH2D, {centAxis, nchAxis}); + histos.add("Data/hcentFV0A_nacc", "hcentFV0A_nacc", kTH2D, {centAxis, nchAxis}); + histos.add("Data/hNchPV_NchGlobal_before", "hNchPV_NchGlobal_before", kTH2D, {nchAxis, nchAxis}); + histos.add("Data/hcentFT0C_GlobalNch_before", "hcentFT0C_GlobalNch_before", kTH2D, {centAxis, nchAxis}); + histos.add("Data/hcentFT0C_NchPV_before", "hcentFT0C_NchPV_before", kTH2D, {centAxis, nchAxis}); + histos.add("Data/hNchPV_NchGlobal_after", "hNchPV_NchGlobal_after", kTH2D, {nchAxis, nchAxis}); + histos.add("Data/hcentFT0C_GlobalNch_after", "hcentFT0C_GlobalNch_after", kTH2D, {centAxis, nchAxis}); + histos.add("Data/hcentFT0C_NchPV_after", "hcentFT0C_NchPV_after", kTH2D, {centAxis, nchAxis}); + histos.add("ptHistogramAllchargeRec", "ptHistogramAllchargeRec", kTH1D, {ptAxis}); + histos.add("hEta_rec", "", kTH1F, {etaAxis}); + histos.add("hPt_rec", "", kTH1F, {ptAxis}); + histos.add("hPtEta_rec", "hPtEta_rec", kTH2D, {ptAxis, etaAxis}); + histos.add("hNch_vs_Nch", "hNch_vs_Nch", kTH2D, {subAxis, nchAxis}); + histos.add("hterm1", "hterm1", kTProfile, {tnchAxis}); + histos.add("hterm2", "hterm2", kTProfile, {tnchAxis}); + histos.add("hCentrality_rec_before", "hCentrality_rec_before", kTH1D, {centAxis}); + histos.add("hEta1", ";hEta1", kTH1D, {etaAxis}); + if (effSwitchHistoFill) { + histos.add("hEffVar1x_data", "hEffVar1x_data", kTH2D, {subAxis, nchAxis}); + histos.add("hEffVar2x_data", "hEffVar2x_data", kTH2D, {subAxis, nchAxis}); + histos.add("hEffVarx_data", "hEffVarx_data", kTH2D, {subAxis, nchAxis}); + histos.add("hEffVar2Meanptx_data", "hEffVar2Meanptx_data", kTH2D, {nchAxis, varAxis2}); + histos.add("hEffVar1x_Naccorr_data", "hEffVar1x_Naccorr_data", kTH2D, {subAxis, nchAxis}); + histos.add("hEffVar2x_Naccorr_data", "hEffVar2x_Naccorr_data", kTH2D, {subAxis, nchAxis}); + histos.add("hEffVarx_Naccorr_data", "hEffVarx_Naccorr_data", kTH2D, {subAxis, nchAxis}); + histos.add("hEffVar1x_Naccorr_xaxis_data", "hEffVar1x_Naccorr_xaxis_data", kTH2D, {subAxis, nchAxis}); + histos.add("hEffVar2x_Naccorr_xaxis_data", "hEffVar2x_Naccorr_xaxis_data", kTH2D, {subAxis, nchAxis}); + histos.add("hEta_rec_corr", "", kTH1F, {etaAxis}); + histos.add("hPt_rec_corr", "", kTH1F, {ptAxis}); + histos.add("hcent_nacc_corr", "hcent_nacc_corr", kTH2D, {centAxis, nchAxis}); + histos.add("hNch_vs_corr", "hNch_vs_corr", kTH2D, {subAxis, nchAxis}); + } + if (pidSwitchHistoFill) { + histos.add("Data/NSigamaTPCpion", "NSigamaTPCpion", kTH2D, {ptAxis, nSigmaTPCAxispid}); + histos.add("Data/NSigamaTPCkaon", "NSigamaTPCkaon", kTH2D, {ptAxis, nSigmaTPCAxispid}); + histos.add("Data/NSigamaTPCproton", "NSigamaTPCproton", kTH2D, {ptAxis, nSigmaTPCAxispid}); + histos.add("Data/NSigamaTOFpion", "NSigamaTOFpion", kTH2D, {ptAxis, nSigmaTOFAxispid}); + histos.add("Data/NSigamaTOFkaon", "NSigamaTOFkaon", kTH2D, {ptAxis, nSigmaTOFAxispid}); + histos.add("Data/NSigamaTOFproton", "NSigamaTOFproton", kTH2D, {ptAxis, nSigmaTOFAxispid}); + histos.add("Data/NSigamaTPCTOFpion", "NSigamaTPCTOFpion", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("Data/NSigamaTPCTOFkaon", "NSigamaTPCTOFkaon", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("Data/NSigamaTPCTOFproton", "NSigamaTPCTOFproton", kTH2D, {nSigmaTPCAxispid, nSigmaTOFAxispid}); + histos.add("Data/hPtPion", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); + histos.add("Data/hPtKaon", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); + histos.add("Data/hPtProton", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); + histos.add("Data/hEtaPion", ";hEta", kTH1D, {etaAxis}); + histos.add("Data/hEtaKaon", ";hEta", kTH1D, {etaAxis}); + histos.add("Data/hEtaProton", ";hEta", kTH1D, {etaAxis}); + histos.add("Data/hyPion", ";hyPion", kTH1D, {etaAxis}); + histos.add("Data/hyKaon", ";hyKaon", kTH1D, {etaAxis}); + histos.add("Data/hyProton", ";hyProton", kTH1D, {etaAxis}); + histos.add("Data/hVar1pix", "hVar1pix", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVar2pix", "hVar2pix", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVarpix", "hVarpix", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVar2meanptpix", "hVar2meanptpix", kTH2D, {nchAxis, varAxis2}); + histos.add("Data/hVar1kx", "hVar1kx", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVar2kx", "hVar2kx", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVarkx", "hVarkx", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVar2meanptkx", "hVar2meanptkx", kTH2D, {nchAxis, varAxis2}); + histos.add("Data/hVar1px", "hVar1px", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVar2px", "hVar2px", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVarpx", "hVarpx", kTH2D, {subAxis, nchAxis}); + histos.add("Data/hVar2meanptpx", "hVar2meanptpx", kTH2D, {nchAxis, varAxis2}); + histos.add("Data/hPtyPion", "hPtyPion", kTH2D, {ptAxis, etaAxis}); + histos.add("Data/hPtyKaon", "hPtyKaon", kTH2D, {ptAxis, etaAxis}); + histos.add("Data/hPtyProton", "hPtyProton", kTH2D, {ptAxis, etaAxis}); + histos.add("Data/hTOFbeta", "hTOFbeta", kTH2D, {pAxis, betaAxis}); + histos.add("Data/hdEdx", "hdEdx", kTH2D, {pAxis, dEdxAxis}); + histos.add("Data/hTOFbeta_afterselection", "hTOFbeta_afterselection", kTH2D, {pAxis, betaAxis}); + histos.add("Data/hdEdx_afterselection", "hdEdx_afterselection", kTH2D, {pAxis, dEdxAxis}); + histos.add("Data/hTOFbeta_afterselection1", "hTOFbeta_afterselection1", kTH2D, {pAxis, betaAxis}); + histos.add("Data/hdEdx_afterselection1", "hdEdx_afterselection1", kTH2D, {pAxis, dEdxAxis}); + histos.add("Data/hVar1pi", "hVar1pi", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVar2pi", "hVar2pi", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVar2meanptpi", "hVar2meanptpi", kTH2D, {centAxis, varAxis2}); + histos.add("Data/hVar1k", "hVar1k", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVar2k", "hVar2k", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVar2meanptk", "hVar2meanptk", kTH2D, {centAxis, varAxis2}); + histos.add("Data/hVar1p", "hVar1p", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVar2p", "hVar2p", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVarp", "hVarp", kTH2D, {subAxis, centAxis}); + histos.add("Data/hVar2meanptp", "hVar2meanptp", kTH2D, {centAxis, varAxis2}); + //===============reco level pid histograms==============================// + 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_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("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_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("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("hPtEta_pi_rec", "hPtEta_pi_rec", kTH2D, {ptAxis, etaAxis}); + histos.add("hPtEta_ka_rec", "hPtEta_ka_rec", kTH2D, {ptAxis, etaAxis}); + histos.add("hPtEta_pr_rec", "hPtEta_pr_rec", kTH2D, {ptAxis, etaAxis}); + //===============generated level pid histograms==============================// + 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}); + histos.add("hPty_pi_gen", "hPty_pi_gen", kTH2D, {ptAxis, etaAxis}); + histos.add("hPty_ka_gen", "hPty_ka_gen", kTH2D, {ptAxis, etaAxis}); + histos.add("hPty_pr_gen", "hPty_pr_gen", kTH2D, {ptAxis, etaAxis}); + histos.add("hPtEta_pi_gen", "hPtEta_pi_gen", kTH2D, {ptAxis, etaAxis}); + histos.add("hPtEta_ka_gen", "hPtEta_ka_gen", kTH2D, {ptAxis, etaAxis}); + histos.add("hPtEta_pr_gen", "hPtEta_pr_gen", kTH2D, {ptAxis, etaAxis}); + histos.add("ptHistogramPion", "ptHistogramPion", kTH1D, {ptAxis}); + histos.add("ptHistogramKaon", "ptHistogramKaon", kTH1D, {ptAxis}); + histos.add("ptHistogramProton", "ptHistogramProton", kTH1D, {ptAxis}); + histos.add("hnch_pi", ";hnch_pi", kTH1D, {nchAxis}); + histos.add("hnch_ka", ";hnch_ka", kTH1D, {nchAxis}); + histos.add("hnch_pr", ";hnch_pr", kTH1D, {nchAxis}); + } + //===============generated level allharons histograms==============================// + histos.add("ptHistogram_allcharge_gen", "ptHistogram_allcharge_gen", kTH1D, {ptAxis}); + histos.add("hnch_gen_all", ";hnch_gen_all", kTH1D, {nchAxis}); + histos.add("hnch_gen_after_etacut", ";hnch_gen_after_etacut", kTH1D, {nchAxis}); + histos.add("hnch_afterPhysPrimary", ";hnch_afterPhysPrimary", kTH1D, {nchAxis}); + histos.add("hnch_gen", ";hnch_gen", kTH1D, {nchAxis}); + histos.add("hPtvar_gen", ";#it{p}_{T} (GeV/#it{c})", kTH1D, {ptAxis}); + 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("hdiffVar1x_gen", "hdiffVar1x_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hdiffVar2x_gen", "hdiffVar2x_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hdiffVarx_gen", "hdiffVarx_gen", kTH2D, {subAxis, nchAxis}); + histos.add("hVar2meanptx_gen", "hVar2meanptx_gen", kTH2D, {nchAxis, varAxis2}); + histos.add("hcent_nacc_gen", "hcent_nacc_gen", kTH2D, {centAxis, nchAxis}); + histos.add("hVtxZ_before_gen", "", kTH1F, {vtxZAxis}); + histos.add("hVtxZ_after_gensim", "", kTH1F, {vtxZAxis}); + histos.add("hEta_gen", "", kTH1F, {etaAxis}); + histos.add("hPt_gen", "", kTH1F, {ptAxis}); + histos.add("hPtEta_gen", "hPtEta_gen", kTH2D, {ptAxis, etaAxis}); + histos.add("hVar1_gen", "hVar1_gen", kTH2D, {subAxis, centAxis}); + histos.add("hVar2_gen", "hVar2_gen", kTH2D, {subAxis, centAxis}); + histos.add("hVarc_gen", "hVarc_gen", kTH2D, {subAxis, centAxis}); + histos.add("hterm1_gen", "hterm1_gen", kTProfile, {tnchAxis}); + histos.add("hterm2_gen", "hterm2_gen", kTProfile, {tnchAxis}); + cfgFunCoeff.multPVFT0CCutPars = cfgFunCoeff.cfgMultPVFT0CCutPars; + cfgFunCoeff.multGlobalFT0CPars = cfgFunCoeff.cfgMultGlobalFT0CCutPars; + cfgFunCoeff.multGlobalPVCutPars = cfgFunCoeff.cfgMultGlobalPVCutPars; + cfgFunCoeff.fMultPVFT0CCutLow = + new TF1("fMultPVFT0CCutLow", + "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.0*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", + 0, 100); + cfgFunCoeff.fMultPVFT0CCutLow->SetParameters(&(cfgFunCoeff.multPVFT0CCutPars[0])); + cfgFunCoeff.fMultPVFT0CCutHigh = + new TF1("fMultPVFT0CCutHigh", + "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.0*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", + 0, 100); + cfgFunCoeff.fMultPVFT0CCutHigh->SetParameters(&(cfgFunCoeff.multPVFT0CCutPars[0])); + cfgFunCoeff.fMultGlobalFT0CCutLow = + new TF1("fMultGlobalFT0CCutLow", + "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x - 3.0*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", + 0, 100); + cfgFunCoeff.fMultGlobalFT0CCutLow->SetParameters(&(cfgFunCoeff.multGlobalFT0CPars[0])); + cfgFunCoeff.fMultGlobalFT0CCutHigh = + new TF1("fMultGlobalFT0CCutHigh", + "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + 3.0*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", + 0, 100); + cfgFunCoeff.fMultGlobalFT0CCutHigh->SetParameters(&(cfgFunCoeff.multGlobalFT0CPars[0])); + cfgFunCoeff.fMultGlobalPVCutLow = + new TF1("fMultGlobalPVCutLow", + "[0] + [1]*x - 3.0*([2] + [3]*x + [4]*x*x + [5]*x*x*x)", + 0, 100); + cfgFunCoeff.fMultGlobalPVCutLow->SetParameters(&(cfgFunCoeff.multGlobalPVCutPars[0])); + cfgFunCoeff.fMultGlobalPVCutHigh = + new TF1("fMultGlobalPVCutHigh", + "[0] + [1]*x + 3.0*([2] + [3]*x + [4]*x*x + [5]*x*x*x)", + 0, 100); + cfgFunCoeff.fMultGlobalPVCutHigh->SetParameters(&(cfgFunCoeff.multGlobalPVCutPars[0])); + LOG(info) << "Printing Stored Registry Information"; + histos.print(); + } + + bool eventSelected(const float& globalNch, const float& pvTrack, const float& centrality) + { + if (cfgFunCoeff.cfgMultPVFT0CCutEnabled) { + if (pvTrack < cfgFunCoeff.fMultPVFT0CCutLow->Eval(centrality)) + return false; + if (pvTrack > cfgFunCoeff.fMultPVFT0CCutHigh->Eval(centrality)) + return false; + } + if (cfgFunCoeff.cfgMultGlobalFT0CCutEnabled) { + if (globalNch < cfgFunCoeff.fMultGlobalFT0CCutLow->Eval(centrality)) + return false; + if (globalNch > cfgFunCoeff.fMultGlobalFT0CCutHigh->Eval(centrality)) + return false; + } + if (cfgFunCoeff.cfgMultGlobalPVCutEnabled) { + if (globalNch < cfgFunCoeff.fMultGlobalPVCutLow->Eval(pvTrack)) + return false; + if (globalNch > cfgFunCoeff.fMultGlobalPVCutHigh->Eval(pvTrack)) + return false; + } + return true; + } + + template + bool selCollision(C const& coll, float& cent) + { + if (std::abs(coll.posZ()) >= cVtxZcut) { + return false; + } // Reject the collisions with large vertex-z + histos.fill(HIST("hEventcounter"), 2.); + + if (ccentFT0C) { + cent = coll.centFT0C(); // centrality from FT0C + } else { + cent = coll.centFT0M(); // centrality from FT0M + } + + if (cSel8Trig && !coll.sel8()) { + return false; + } // require min bias trigger + histos.fill(HIST("hEventcounter"), 3.); + + if (cpileupTFBorder && !coll.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (cpileupNoItsROBorder && !coll.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + histos.fill(HIST("trackSelRec"), 4); + + if (cpileupSameBunch && !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("trackSelRec"), 5); + + if (cpileupZVtxTimeDiff && !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + histos.fill(HIST("trackSelRec"), 6); + + if (cpileupItsTpcVtx && !coll.selection_bit(aod::evsel::kIsVertexITSTPC)) { + return false; + } + histos.fill(HIST("trackSelRec"), 7); + + // if (cpileupItslayerall && !coll.selection_bit(aod::evsel::kIsGoodITSLayersAll)) {return false;} + histos.fill(HIST("trackSelRec"), 8); + + if (cpileupvtxtofmatched && !coll.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + histos.fill(HIST("trackSelRec"), 9); + + return true; // if all checks pass, accept the collision + } + + template + bool selTrack(T const& track) + { + if (!track.isGlobalTrack()) { + return false; + } // accept only global tracks + histos.fill(HIST("tracksel"), 2); + + if (csyDCAxy && std::fabs(track.dcaXY()) > cDcaXYcut) { + return false; + } + histos.fill(HIST("tracksel"), 3); + + if (csyDCAz && std::fabs(track.dcaZ()) > cDcaZcut) { + return false; + } + histos.fill(HIST("tracksel"), 4); + + if (std::fabs(track.eta()) >= cEtacut) { + return false; + } + histos.fill(HIST("tracksel"), 5); + + if (csyTPCcr && track.tpcNClsCrossedRows() < csyTPCcrosscut) { + return false; + } + histos.fill(HIST("tracksel"), 6); + + if (csyITSchi && track.itsChi2NCl() >= csysItsChiCut) { + return false; + } + histos.fill(HIST("tracksel"), 7); + + if (csyTPCchi && track.tpcChi2NCl() >= csysTpcChiCut) { + return false; + } + histos.fill(HIST("tracksel"), 8); + + if (track.sign() == 0) { + return false; + } + + if (cPVContributor) { + if (!(track.isPVContributor())) { + return false; + } + histos.fill(HIST("tracksel"), 9); + } + + if (citsNCluster) { + if (track.itsNCls() < csysnITSClustersCut) { + return false; + } + histos.fill(HIST("tracksel"), 10); + } + + if (ctpcNClusterFound) { + if (track.tpcNClsFound() < csystpcNClsCut) { + return false; + } + histos.fill(HIST("tracksel"), 11); + } + + return true; // if all checks pass, accept the collision + } + + template + bool rejEl(T const& track) + { + if (track.tpcNSigmaEl() > cElMinCut && track.tpcNSigmaEl() < cElMaxCut && std::fabs(track.tpcNSigmaPi()) > cNSigCut3 && std::fabs(track.tpcNSigmaKa()) > cNSigCut3 && std::fabs(track.tpcNSigmaPr()) > cNSigCut3) { + return true; + } + return false; + } + + template + bool selProton(T const& track) + { + //! if pt < threshold (For tracks without TOF information) + if (track.p() > cpidProtonPmincut && track.p() <= cpidProtonPthcut) { + if (track.hasTPC() && std::fabs(track.tpcNSigmaPr()) < cNSigCut2 && std::fabs(track.tpcNSigmaPi()) > cNSigCut2 && std::fabs(track.tpcNSigmaKa()) > cNSigCut2) { + return true; + } + } + + //! if pt < threshold (For tracks with TOF information) + if (track.p() > cpidProtonPmincut && track.p() <= cpidProtonPthcut) { + if (track.hasTOF() && std::fabs(track.tpcNSigmaPr()) < cNSigCut2 && std::fabs(track.tofNSigmaPr()) < cNSigCut2 && std::fabs(track.tpcNSigmaPi()) > cNSigCut2 && std::fabs(track.tpcNSigmaKa()) > cNSigCut2) { + return true; + } + } + + //! if pt > threshold (For tracks with TOF information) + if (track.p() > cpidProtonPthcut && track.p() <= cpidProtonPmaxcut) { + if (track.hasTPC() && track.hasTOF() && std::fabs(track.tpcNSigmaPr()) < cNSigCut2 && std::fabs(track.tofNSigmaPr()) < cNSigCut2 && std::hypot(track.tofNSigmaPi(), track.tpcNSigmaPi()) > cNSigCut2 && std::hypot(track.tofNSigmaKa(), track.tpcNSigmaKa()) > cNSigCut2) { + return true; + } + } + + return false; + } + + template + bool selKaon(T const& track) + { + //! if pt < threshold (For tracks without TOF information) + if (track.p() > cpidKaonPmincut && track.p() <= cpidKaonPthcut) { + if (track.hasTPC() && std::fabs(track.tpcNSigmaKa()) < cNSigCut2 && std::fabs(track.tpcNSigmaPi()) > cNSigCut2 && std::fabs(track.tpcNSigmaPr()) > cNSigCut2) { + return true; + } + } + + //! if pt < threshold (For tracks with TOF information) + if (track.p() > cpidKaonPmincut && track.p() <= cpidKaonPthcut) { + if (track.hasTOF() && std::fabs(track.tpcNSigmaKa()) < cNSigCut2 && std::fabs(track.tofNSigmaKa()) < cNSigCut2 && std::fabs(track.tpcNSigmaPi()) > cNSigCut2 && std::fabs(track.tpcNSigmaPr()) > cNSigCut2) { + return true; + } + } + + //! if pt > threshold (For tracks with TOF information) + if (track.p() > cpidKaonPthcut && track.p() <= cpidKaonPmaxcut) { + if (track.hasTPC() && track.hasTOF() && std::fabs(track.tpcNSigmaKa()) < cNSigCut2 && std::fabs(track.tofNSigmaKa()) < cNSigCut2 && std::hypot(track.tofNSigmaPi(), track.tpcNSigmaPi()) > cNSigCut2 && std::hypot(track.tofNSigmaPr(), track.tpcNSigmaPr()) > cNSigCut2) { + return true; + } + } + + return false; + } + + template + bool selPion(T const& track) + { + //! if pt < threshold (For tracks without TOF information) + if (track.p() > cpidPionPmincut && track.p() <= cpidPionPthcut) { + if (track.hasTPC() && std::fabs(track.tpcNSigmaPi()) < cNSigCut2 && std::fabs(track.tpcNSigmaKa()) > cNSigCut2 && std::fabs(track.tpcNSigmaPr()) > cNSigCut2) { + return true; + } + } + + //! if pt < threshold (For tracks with TOF information) + if (track.p() > cpidPionPmincut && track.p() <= cpidPionPthcut) { + if (track.hasTOF() && std::fabs(track.tpcNSigmaPi()) < cNSigCut2 && std::fabs(track.tofNSigmaPi()) < cNSigCut2 && std::fabs(track.tpcNSigmaKa()) > cNSigCut2 && std::fabs(track.tpcNSigmaPr()) > cNSigCut2) { + return true; + } + } + + //! if pt > threshold (For tracks with TOF information) + if (track.p() > cpidPionPthcut && track.p() <= cpidPionPmaxcut) { + if (track.hasTPC() && track.hasTOF() && std::fabs(track.tpcNSigmaPi()) < cNSigCut2 && std::fabs(track.tofNSigmaPi()) < cNSigCut2 && std::hypot(track.tofNSigmaKa(), track.tpcNSigmaKa()) > cNSigCut2 && std::hypot(track.tofNSigmaPr(), track.tpcNSigmaPr()) > cNSigCut2) { + return true; + } + } + + return false; + } + + double getEfficiency(double pt, double eta, TH2D* ptHistogramAllchargeRec) + { + int xbin = ptHistogramAllchargeRec->GetXaxis()->FindBin(pt); + int ybin = ptHistogramAllchargeRec->GetYaxis()->FindBin(eta); + + if (xbin < 1 || xbin > ptHistogramAllchargeRec->GetNbinsX() || ybin < 1 || ybin > ptHistogramAllchargeRec->GetNbinsY()) { + LOGF(warn, "pt or eta out of histograms bounds : %f, eta = %f", pt, eta); + return 1e-6; + } + double eff = ptHistogramAllchargeRec->GetBinContent(xbin, ybin); + return (eff > 0) ? eff : 1e-6; // Avoid division by zero + } + + //++++++++++++++++++++++++++++++++++++DATA CALCULATION +++++++++++++++++++++++++++++++++++++++++++++++++++++// + void processData(MyCollision const& coll, MyTracks const& inputTracks) + + { + float cent = -1; + histos.fill(HIST("hEventcounter"), 1.); + histos.fill(HIST("Data/hZvtx_before_sel"), coll.posZ()); + + if (!selCollision(coll, cent)) + return; + { + histos.fill(HIST("Data/hZvtx_after_sel8"), coll.posZ()); + } + + histos.fill(HIST("Data/hCentrality"), cent); + + float globalNch = inputTracks.size(); + float pvTrack = coll.multNTracksPV(); + + histos.fill(HIST("Data/hNchPV_NchGlobal_before"), pvTrack, globalNch); + histos.fill(HIST("Data/hcentFT0C_GlobalNch_before"), coll.centFT0C(), globalNch); + histos.fill(HIST("Data/hcentFT0C_NchPV_before"), coll.centFT0C(), pvTrack); + + if (cfgEvSelMultCorrelation && !eventSelected(globalNch, pvTrack, cent)) { + return; + } + + histos.fill(HIST("Data/hNchPV_NchGlobal_after"), pvTrack, globalNch); + histos.fill(HIST("Data/hcentFT0C_GlobalNch_after"), coll.centFT0C(), globalNch); + histos.fill(HIST("Data/hcentFT0C_NchPV_after"), coll.centFT0C(), pvTrack); + + double nchAll = 0., nchAllBfCut = 0., nchEta = 0., nchPt = 0., nch = 0., nchPi = 0., nchKa = 0., nchPr = 0.; + double q1 = 0., q2 = 0., var1 = 0., var2 = 0.; + double sumPtWeight = 0., sumWeight = 0., sumPtPtWeight = 0., var1Eff = 0., var2Eff = 0.; + double q1Pi = 0., q2Pi = 0., var1Pi = 0., var2Pi = 0.; + double q1Ka = 0., q2Ka = 0., var1Ka = 0., var2Ka = 0.; + double q1Pr = 0., q2Pr = 0., var1Pr = 0., var2Pr = 0.; + + int sample = histos.get(HIST("Data/hZvtx_after_sel8"))->GetEntries(); + sample = sample % 30; + + for (const auto& track : inputTracks) { + nchAllBfCut += 1.; + histos.fill(HIST("Data/hnchAll_bf_cut"), nchAllBfCut); + + histos.fill(HIST("tracksel"), 1); + histos.fill(HIST("Data/hTPCchi2perCluster_before"), track.tpcChi2NCl()); + histos.fill(HIST("Data/hITSchi2perCluster_before"), track.itsChi2NCl()); + histos.fill(HIST("Data/hTPCCrossedrows_before"), track.tpcNClsCrossedRows()); + + if (std::fabs(track.eta()) <= cEtacut) { + nchEta++; + histos.fill(HIST("Data/hnchTrue"), nchEta); + } + if (track.pt() >= cPtmincut && track.pt() <= cPtmaxcut) { + nchPt += 1.; + histos.fill(HIST("Data/hnchTrue_pt"), nchPt); + } + if (!selTrack(track)) + continue; + + if (track.pt() >= cPtmincut1 && track.pt() <= cPtmaxcut1) { + nch += 1.; + histos.fill(HIST("Data/hnch"), nch); + histos.fill(HIST("Data/hPtvar"), track.pt()); + } + + if (track.pt() < cPtmincut || track.pt() > cPtmaxcut) + continue; + + nchAll += 1.; + q1 += track.pt(); + q2 += (track.pt() * track.pt()); + + histos.fill(HIST("Data/hnchAll"), nchAll); + histos.fill(HIST("Data/hPt"), track.pt()); + histos.fill(HIST("Data/hEta"), track.eta()); + histos.fill(HIST("Data/hDCAxy"), track.dcaXY()); + histos.fill(HIST("Data/hDCAz"), track.dcaZ()); + histos.fill(HIST("Data/hTPCCrossedrows_after"), track.tpcNClsCrossedRows()); + histos.fill(HIST("Data/hTPCchi2perCluster_after"), track.tpcChi2NCl()); + histos.fill(HIST("Data/hITSchi2perCluster_after"), track.itsChi2NCl()); + histos.fill(HIST("Data/hP"), track.p()); + histos.fill(HIST("Data/hPtDCAxy"), track.pt(), track.dcaXY()); + histos.fill(HIST("Data/hPtDCAz"), track.pt(), track.dcaZ()); + histos.fill(HIST("Data/hPtEta"), track.pt(), track.eta()); + histos.fill(HIST("Data/hPEta"), track.p(), track.eta()); + + if (effSwitch) { + double eff = getEfficiency(track.pt(), track.eta(), ptHistogramAllchargeRec); + if (eff < threshold) + continue; + double weight = 1. / eff; + sumPtWeight += track.pt() / eff; + sumPtPtWeight += (track.pt() * track.pt()) / (eff * eff); + sumWeight += weight; + } + + if (pidSwitch) { + // only TPC tracks: Pion, Kaon, Proton + if (track.hasTPC() && std::abs(track.tpcNSigmaPi()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTPCpion"), track.pt(), track.tpcNSigmaPi()); + if (track.hasTPC() && std::abs(track.tpcNSigmaKa()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTPCkaon"), track.pt(), track.tpcNSigmaKa()); + if (track.hasTPC() && std::abs(track.tpcNSigmaPr()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTPCproton"), track.pt(), track.tpcNSigmaPr()); + + // only TOF tracks: Pion, Kaon, Proton + if (track.hasTOF() && std::abs(track.tofNSigmaPi()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTOFpion"), track.pt(), track.tofNSigmaPi()); + if (track.hasTOF() && std::abs(track.tofNSigmaKa()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTOFkaon"), track.pt(), track.tofNSigmaKa()); + if (track.hasTOF() && std::abs(track.tofNSigmaPr()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTOFproton"), track.pt(), track.tofNSigmaPr()); + + if (track.hasTPC()) + histos.fill(HIST("Data/hdEdx"), track.p(), track.tpcSignal()); + if (track.hasTOF()) + histos.fill(HIST("Data/hTOFbeta"), track.p(), track.beta()); + + //===================================pion=========================================================== + // only TPC+TOF tracks: Pion, Kaon, Proton + if ((track.hasTPC() && std::abs(track.tpcNSigmaPi()) < cNSigCut3) && (track.hasTOF() && std::abs(track.tofNSigmaPi()) < cNSigCut3)) { + histos.fill(HIST("Data/NSigamaTPCTOFpion"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + histos.fill(HIST("Data/hdEdx_afterselection"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection"), track.p(), track.beta()); + } + if (selPion(track)) { + histos.fill(HIST("Data/hPtPion"), track.pt()); + histos.fill(HIST("Data/hEtaPion"), track.eta()); + histos.fill(HIST("Data/hyPion"), track.rapidity(massPi)); + histos.fill(HIST("Data/hPtyPion"), track.pt(), track.rapidity(massPi)); + nchPi += 1.; + q1Pi += track.pt(); + q2Pi += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("Data/hdEdx_afterselection1"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection1"), track.p(), track.beta()); + } + + //===========================kaon=============================================================== + if ((track.hasTPC() && std::abs(track.tpcNSigmaKa()) < cNSigCut3) && (track.hasTOF() && std::abs(track.tofNSigmaKa()) < cNSigCut3)) { + histos.fill(HIST("Data/NSigamaTPCTOFkaon"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + histos.fill(HIST("Data/hdEdx_afterselection"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection"), track.p(), track.beta()); + } + if (selKaon(track)) { + histos.fill(HIST("Data/hPtKaon"), track.pt()); + histos.fill(HIST("Data/hEtaKaon"), track.eta()); + histos.fill(HIST("Data/hyKaon"), track.rapidity(massKa)); + histos.fill(HIST("Data/hPtyKaon"), track.pt(), track.rapidity(massKa)); + nchKa += 1.; + q1Ka += track.pt(); + q2Ka += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("Data/hdEdx_afterselection1"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection1"), track.p(), track.beta()); + } + + //============================proton=========================================================== + if ((track.hasTPC() && std::abs(track.tpcNSigmaPr()) < cNSigCut3) && (track.hasTOF() && std::abs(track.tofNSigmaPr()) < cNSigCut3)) { + histos.fill(HIST("Data/NSigamaTPCTOFproton"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + histos.fill(HIST("Data/hdEdx_afterselection"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection"), track.p(), track.beta()); + } + if (selProton(track)) { + histos.fill(HIST("Data/hPtProton"), track.pt()); + histos.fill(HIST("Data/hEtaProton"), track.eta()); + histos.fill(HIST("Data/hyProton"), track.rapidity(massPr)); + histos.fill(HIST("Data/hPtyProton"), track.pt(), track.rapidity(massPr)); + nchPr += 1.; + q1Pr += track.pt(); + q2Pr += (track.pt() * track.pt()); + if (track.beta() > 1) + continue; + histos.fill(HIST("Data/hdEdx_afterselection1"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection1"), track.p(), track.beta()); + } + } + + } // Track loop ends! + histos.fill(HIST("Data/hcentFV0A_nacc"), coll.multFV0A(), nchAll); + histos.fill(HIST("Data/hcentFT0A_nacc"), coll.multFT0A(), nchAll); + histos.fill(HIST("Data/hcentFT0M_nacc"), coll.centFT0M(), nchAll); + histos.fill(HIST("Data/hcent_nacc"), cent, nchAll); + + if (nchAll < cTwoPtlCut2) + return; + var1 = (q1 * q1 - q2) / (nchAll * (nchAll - 1)); + var2 = (q1 / nchAll); + + //---------------------- pions ---------------------------------------- + if (nchPi >= cTwoPtlCut2) { + var1Pi = (q1Pi * q1Pi - q2Pi) / (nchPi * (nchPi - 1)); + var2Pi = (q1Pi / nchPi); + } + //----------------------- kaons --------------------------------------- + if (nchKa >= cTwoPtlCut2) { + var1Ka = (q1Ka * q1Ka - q2Ka) / (nchKa * (nchKa - 1)); + var2Ka = (q1Ka / nchKa); + } + //---------------------------- protons ---------------------------------- + if (nchPr >= cTwoPtlCut2) { + var1Pr = (q1Pr * q1Pr - q2Pr) / (nchPr * (nchPr - 1)); + var2Pr = (q1Pr / nchPr); + } + + //------------------ all charges------------------------------------- + histos.fill(HIST("Data/hVar1"), sample, cent, var1); + histos.fill(HIST("Data/hVar2"), sample, cent, var2); + histos.fill(HIST("Data/hVarc"), sample, cent); + histos.fill(HIST("Data/hVar2meanpt"), cent, var2); + + //-----------------------nch------------------------------------- + histos.fill(HIST("Data/hVar1x"), sample, nchAll, var1); + histos.fill(HIST("Data/hVar2x"), sample, nchAll, var2); + histos.fill(HIST("Data/hVarx"), sample, nchAll); + histos.fill(HIST("Data/hVar2meanptx"), nchAll, var2); + histos.fill(HIST("Data/hdiffVar1x"), sample, nch, var1); + histos.fill(HIST("Data/hdiffVar2x"), sample, nch, var2); + histos.fill(HIST("Data/hdiffVarx"), sample, nch); + + if (effSwitchHistoFill) { + //------------------ Efficiency corrected histograms --------------- + var1Eff = (sumPtWeight * sumPtWeight - sumPtPtWeight) / (sumWeight * (sumWeight - 1)); + var2Eff = (sumPtWeight / sumWeight); + + histos.fill(HIST("hEffVar1x_data"), sample, nchAll, var1Eff); + histos.fill(HIST("hEffVar2x_data"), sample, nchAll, var2Eff); + histos.fill(HIST("hEffVarx_data"), sample, nchAll); + histos.fill(HIST("hEffVar2Meanptx_data"), nchAll, var2Eff); + histos.fill(HIST("hEffVar1x_Naccorr_data"), sample, sumWeight, var1Eff); + histos.fill(HIST("hEffVar2x_Naccorr_data"), sample, sumWeight, var2Eff); + histos.fill(HIST("hEffVarx_Naccorr_data"), sample, sumWeight); + histos.fill(HIST("hEffVar1x_Naccorr_xaxis_data"), sample, sumWeight, var1); + histos.fill(HIST("hEffVar2x_Naccorr_xaxis_data"), sample, sumWeight, var2); + } + + if (pidSwitchHistoFill) { + histos.fill(HIST("Data/hVar1pi"), sample, cent, var1Pi); + histos.fill(HIST("Data/hVar2pi"), sample, cent, var2Pi); + histos.fill(HIST("Data/hVar2meanptpi"), cent, var2Pi); + histos.fill(HIST("Data/hVar1k"), sample, cent, var1Ka); + histos.fill(HIST("Data/hVar2k"), sample, cent, var2Ka); + histos.fill(HIST("Data/hVar2meanptk"), cent, var2Ka); + histos.fill(HIST("Data/hVar1p"), sample, cent, var1Pr); + histos.fill(HIST("Data/hVar2p"), sample, cent, var2Pr); + histos.fill(HIST("Data/hVar2meanptp"), cent, var2Pr); + histos.fill(HIST("Data/hVar1pix"), sample, nchAll, var1Pi); + histos.fill(HIST("Data/hVar2pix"), sample, nchAll, var2Pi); + histos.fill(HIST("Data/hVarpix"), sample, nchPi); + histos.fill(HIST("Data/hVar2meanptpix"), nchAll, var2Pi); + histos.fill(HIST("Data/hVar1kx"), sample, nchAll, var1Ka); + histos.fill(HIST("Data/hVar2kx"), sample, nchAll, var2Ka); + histos.fill(HIST("Data/hVarkx"), sample, nchKa); + histos.fill(HIST("Data/hVar2meanptkx"), nchAll, var2Ka); + histos.fill(HIST("Data/hVar1px"), sample, nchAll, var1Pr); + histos.fill(HIST("Data/hVar2px"), sample, nchAll, var2Pr); + histos.fill(HIST("Data/hVarpx"), sample, nchPr); + histos.fill(HIST("Data/hVar2meanptpx"), nchAll, var2Pr); + } + + } // event loop ends! + + PROCESS_SWITCH(EventMeanPtId, processData, "process real data information", true); + + //++++++++++++++++++++++++++++++++++++MC Reconstructed +++++++++++++++++++++++++++++++++++++++++++++++++++++// + SliceCache cache; + Preslice mcTrack = o2::aod::mcparticle::mcCollisionId; + void processMcReco(MyMCRecoCollision const& coll, MyMCRecoTracks const& inputTracks, aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + float cent = -1; + (void)mcCollisions; + if (!coll.has_mcCollision()) { + return; + } + + histos.fill(HIST("Data/hZvtx_before_sel"), coll.posZ()); + histos.fill(HIST("hVtxZ_before_gen"), coll.mcCollision().posZ()); + histos.fill(HIST("hCentrality_rec_before"), cent); + + if (!selCollision(coll, cent)) + return; + + histos.fill(HIST("Data/hZvtx_after_sel8"), coll.posZ()); + histos.fill(HIST("Data/hCentrality"), cent); + + float globalNch = inputTracks.size(); + float pvTrack = coll.multNTracksPV(); + + histos.fill(HIST("Data/hNchPV_NchGlobal_before"), pvTrack, globalNch); + histos.fill(HIST("Data/hcentFT0C_GlobalNch_before"), coll.centFT0C(), globalNch); + histos.fill(HIST("Data/hcentFT0C_NchPV_before"), coll.centFT0C(), pvTrack); + + if (cfgEvSelMultCorrelation && !eventSelected(globalNch, pvTrack, cent)) { + return; + } + + histos.fill(HIST("Data/hNchPV_NchGlobal_after"), pvTrack, globalNch); + histos.fill(HIST("Data/hcentFT0C_GlobalNch_after"), coll.centFT0C(), globalNch); + histos.fill(HIST("Data/hcentFT0C_NchPV_after"), coll.centFT0C(), pvTrack); + + double nch = 0., nchPi = 0., nchKa = 0., nchPr = 0., nchAll = 0., nchAllBfCut = 0., nchEta = 0., nchPt = 0.; + double q1 = 0., q2 = 0.; + double q1Pi = 0., q2Pi = 0., q1Ka = 0., q2Ka = 0., q1Pr = 0., q2Pr = 0.; + double var1 = 0., var2 = 0.; + double var1Pi = 0., var2Pi = 0., var1Ka = 0., var2Ka = 0., var1Pr = 0., var2Pr = 0.; + double sumPtWeight = 0., sumWeight = 0., sumPtPtWeight = 0., var1Eff = 0., var2Eff = 0.; + + int sample = histos.get(HIST("Data/hZvtx_after_sel8"))->GetEntries(); + sample = sample % 30; + + for (const auto& track : inputTracks) { + nchAllBfCut += 1.; + histos.fill(HIST("Data/hnchAll_bf_cut"), nchAllBfCut); + histos.fill(HIST("Data/hTPCchi2perCluster_before"), track.tpcChi2NCl()); + histos.fill(HIST("Data/hITSchi2perCluster_before"), track.itsChi2NCl()); + histos.fill(HIST("Data/hTPCCrossedrows_before"), track.tpcNClsCrossedRows()); + + if (std::fabs(track.eta()) <= cEtacut) { + nchEta++; + histos.fill(HIST("Data/hnchTrue"), nchEta); + } + if (track.pt() >= cPtmincut && track.pt() <= cPtmaxcut) { + nchPt += 1.; + histos.fill(HIST("Data/hnchTrue_pt"), nchPt); + } + + if (!selTrack(track)) + continue; + + if (track.pt() >= cPtmincut1 && track.pt() <= cPtmaxcut1) { + nch += 1.; + histos.fill(HIST("Data/hnch"), nch); + histos.fill(HIST("Data/hPtvar"), track.pt()); + } + if (track.pt() < cPtmincut || track.pt() > cPtmaxcut) + continue; + + // if (std::fabs(track.y()) > 0.5) continue; + histos.fill(HIST("hPt_rec"), track.pt()); + histos.fill(HIST("hEta_rec"), track.eta()); + + if (effSwitch) { + double eff = getEfficiency(track.pt(), track.eta(), ptHistogramAllchargeRec); + if (eff < threshold) + continue; + double weight = 1.0 / eff; + sumPtWeight += track.pt() * weight; + sumPtPtWeight += (track.pt() * track.pt() * weight * weight); + sumWeight += weight; + + histos.fill(HIST("hPt_rec_corr"), track.pt(), weight); + histos.fill(HIST("hEta_rec_corr"), track.eta(), weight); + } + + auto mcParticle = track.mcParticle(); + nchAll += 1.; + q1 += track.pt(); + q2 += (track.pt() * track.pt()); + + histos.fill(HIST("Data/hnchAll"), nchAll); + histos.fill(HIST("ptHistogramAllchargeRec"), track.pt()); + histos.fill(HIST("Data/hDCAxy"), track.dcaXY()); + histos.fill(HIST("Data/hDCAz"), track.dcaZ()); + histos.fill(HIST("Data/hTPCCrossedrows_after"), track.tpcNClsCrossedRows()); + histos.fill(HIST("Data/hTPCchi2perCluster_after"), track.tpcChi2NCl()); + histos.fill(HIST("Data/hITSchi2perCluster_after"), track.itsChi2NCl()); + histos.fill(HIST("Data/hP"), track.p()); + histos.fill(HIST("Data/hPt"), track.pt()); + histos.fill(HIST("Data/hEta"), track.eta()); + histos.fill(HIST("Data/hPtDCAxy"), track.pt(), track.dcaXY()); + histos.fill(HIST("Data/hPtDCAz"), track.pt(), track.dcaZ()); + histos.fill(HIST("Data/hPtEta"), track.pt(), track.eta()); + histos.fill(HIST("Data/hPEta"), track.p(), track.eta()); + histos.fill(HIST("hPtEta_rec"), track.pt(), track.eta()); + + if (pidSwitch) { + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus) + histos.fill(HIST("ptHistogramPionrec_pdg"), track.pt()); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus) + histos.fill(HIST("ptHistogramKaonrec_pdg"), track.pt()); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kProton) + histos.fill(HIST("ptHistogramProtonrec_pdg"), track.pt()); + + // only TPC tracks: Pion, Kaon, Proton + if (track.hasTPC() && std::abs(track.tpcNSigmaPi()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTPCpion"), track.pt(), track.tpcNSigmaPi()); + if (track.hasTPC() && std::abs(track.tpcNSigmaKa()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTPCkaon"), track.pt(), track.tpcNSigmaKa()); + if (track.hasTPC() && std::abs(track.tpcNSigmaPr()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTPCproton"), track.pt(), track.tpcNSigmaPr()); + + // only TOF tracks: Pion, Kaon, Proton + if (track.hasTOF() && std::abs(track.tofNSigmaPi()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTOFpion"), track.pt(), track.tofNSigmaPi()); + if (track.hasTOF() && std::abs(track.tofNSigmaKa()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTOFkaon"), track.pt(), track.tofNSigmaKa()); + if (track.hasTOF() && std::abs(track.tofNSigmaPr()) < cNSigCut3) + histos.fill(HIST("Data/NSigamaTOFproton"), track.pt(), track.tofNSigmaPr()); + + if (track.hasTPC()) + histos.fill(HIST("Data/hdEdx"), track.p(), track.tpcSignal()); + if (track.hasTOF()) + histos.fill(HIST("Data/hTOFbeta"), track.p(), track.beta()); + if (track.hasTPC()) + histos.fill(HIST("hdEdx_afterselection_rec_beforepidcut"), track.p(), track.tpcSignal()); + if (track.hasTOF()) + histos.fill(HIST("hTOFbeta_afterselection_rec_beforepidcut"), track.p(), track.beta()); + + //===================================pion============================================================== + if ((track.hasTPC() && std::abs(track.tpcNSigmaPi()) < cNSigCut3) && (track.hasTOF() && std::abs(track.tofNSigmaPi()) < cNSigCut3)) { + histos.fill(HIST("Data/NSigamaTPCTOFpion"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + + histos.fill(HIST("Data/hdEdx_afterselection"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection"), track.p(), track.beta()); + } + + if (selPion(track)) { + if (std::fabs(track.y()) > cRapidityCut05) + continue; + if (track.beta() > 1) + continue; + histos.fill(HIST("ptHistogramPionrec"), track.pt()); + histos.fill(HIST("hPtEta_pi_rec"), track.pt(), track.eta()); + histos.fill(HIST("Data/hPtPion"), track.pt()); + histos.fill(HIST("Data/hEtaPion"), track.eta()); + histos.fill(HIST("Data/hyPion"), track.rapidity(massPi)); + histos.fill(HIST("Data/hPtyPion"), track.pt(), track.rapidity(massPi)); + histos.fill(HIST("NSigamaTPCpion_rec"), track.p(), track.tpcNSigmaPi()); + histos.fill(HIST("NSigamaTOFpion_rec"), track.p(), track.tofNSigmaPi()); + histos.fill(HIST("NSigamaTPCTOFpion_rec"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + histos.fill(HIST("Data/hdEdx_afterselection1"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection1"), track.p(), track.beta()); + if (std::abs(track.mcParticle().pdgCode()) == PDG_t::kPiPlus) { + histos.fill(HIST("ptHistogramPionrec_purity"), track.pt()); + } + nchPi += 1.; + q1Pi += track.pt(); + q2Pi += (track.pt() * track.pt()); + + histos.fill(HIST("hPyPion_rec"), track.p(), track.rapidity(massPi)); + histos.fill(HIST("hPtyPion_rec"), track.pt(), track.rapidity(massPi)); + } + + //===========================kaon=============================================================== + + if ((track.hasTPC() && std::abs(track.tpcNSigmaKa()) < cNSigCut3) && (track.hasTOF() && std::abs(track.tofNSigmaKa()) < cNSigCut3)) { + histos.fill(HIST("Data/NSigamaTPCTOFkaon"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + histos.fill(HIST("Data/hdEdx_afterselection"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection"), track.p(), track.beta()); + } + + if (selKaon(track)) { + if (std::fabs(track.y()) > cRapidityCut05) + continue; + if (track.beta() > 1) + continue; + histos.fill(HIST("ptHistogramKaonrec"), track.pt()); + histos.fill(HIST("hPtEta_ka_rec"), track.pt(), track.eta()); + histos.fill(HIST("Data/hPtKaon"), track.pt()); + histos.fill(HIST("Data/hEtaKaon"), track.eta()); + histos.fill(HIST("Data/hyKaon"), track.rapidity(massKa)); + histos.fill(HIST("Data/hPtyKaon"), track.pt(), track.rapidity(massKa)); + histos.fill(HIST("NSigamaTPCkaon_rec"), track.p(), track.tpcNSigmaKa()); + histos.fill(HIST("NSigamaTOFkaon_rec"), track.p(), track.tofNSigmaKa()); + histos.fill(HIST("NSigamaTPCTOFkaon_rec"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + histos.fill(HIST("Data/hdEdx_afterselection1"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection1"), track.p(), track.beta()); + if (std::abs(track.mcParticle().pdgCode()) == PDG_t::kKPlus) { + histos.fill(HIST("ptHistogramKaonrec_purity"), track.pt()); + } + nchKa += 1.; + q1Ka += track.pt(); + q2Ka += (track.pt() * track.pt()); + + histos.fill(HIST("hPyKaon_rec"), track.p(), track.rapidity(massKa)); + histos.fill(HIST("hPtyKaon_rec"), track.pt(), track.rapidity(massKa)); + } + + //============================proton=========================================================== + + if ((track.hasTPC() && std::abs(track.tpcNSigmaPr()) < cNSigCut3) && (track.hasTOF() && std::abs(track.tofNSigmaPr()) < cNSigCut3)) { + histos.fill(HIST("Data/NSigamaTPCTOFproton"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + histos.fill(HIST("Data/hdEdx_afterselection"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection"), track.p(), track.beta()); + } + + if (selProton(track)) { + if (std::fabs(track.y()) > cRapidityCut05) + continue; + if (track.beta() > 1) + continue; + histos.fill(HIST("ptHistogramProtonrec"), track.pt()); + histos.fill(HIST("hPtEta_pr_rec"), track.pt(), track.eta()); + histos.fill(HIST("Data/hPtProton"), track.pt()); + histos.fill(HIST("Data/hEtaProton"), track.eta()); + histos.fill(HIST("Data/hyProton"), track.rapidity(massPr)); + histos.fill(HIST("Data/hPtyProton"), track.pt(), track.rapidity(massPr)); + histos.fill(HIST("NSigamaTPCproton_rec"), track.p(), track.tpcNSigmaPr()); + histos.fill(HIST("NSigamaTOFproton_rec"), track.p(), track.tofNSigmaPr()); + histos.fill(HIST("NSigamaTPCTOFproton_rec"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + histos.fill(HIST("Data/hdEdx_afterselection1"), track.p(), track.tpcSignal()); + histos.fill(HIST("Data/hTOFbeta_afterselection1"), track.p(), track.beta()); + if (std::abs(track.mcParticle().pdgCode()) == PDG_t::kProton) { + histos.fill(HIST("ptHistogramProtonrec_purity"), track.pt()); + } + nchPr += 1.; + q1Pr += track.pt(); + q2Pr += (track.pt() * track.pt()); + + histos.fill(HIST("hPyProton_rec"), track.p(), track.rapidity(massPr)); + histos.fill(HIST("hPtyProton_rec"), track.pt(), track.rapidity(massPr)); + } + } + + } // loop over tracks + histos.fill(HIST("Data/hcent_nacc"), cent, nchAll); + histos.fill(HIST("hNch_vs_Nch"), sample, nchAll, nchAll); + + if (nchAll < cTwoPtlCut2) + return; + var1 = (q1 * q1 - q2) / (nchAll * (nchAll - 1)); + var2 = (q1 / nchAll); + + histos.fill(HIST("hterm1"), nchAll, var1); + histos.fill(HIST("hterm2"), nchAll, var2); + + histos.fill(HIST("Data/hVar1"), sample, cent, var1); + histos.fill(HIST("Data/hVar2"), sample, cent, var2); + histos.fill(HIST("Data/hVarc"), sample, cent); + histos.fill(HIST("Data/hVar2meanpt"), cent, var2); + + //---------------------- pions ---------------------------------------- + if (nchPi >= cTwoPtlCut2) { + var1Pi = (q1Pi * q1Pi - q2Pi) / (nchPi * (nchPi - 1)); + var2Pi = (q1Pi / nchPi); + } + //----------------------- kaons --------------------------------------- + if (nchKa >= cTwoPtlCut2) { + var1Ka = (q1Ka * q1Ka - q2Ka) / (nchKa * (nchKa - 1)); + var2Ka = (q1Ka / nchKa); + } + //---------------------------- protons ---------------------------------- + if (nchPr >= cTwoPtlCut2) { + var1Pr = (q1Pr * q1Pr - q2Pr) / (nchPr * (nchPr - 1)); + var2Pr = (q1Pr / nchPr); + } + + //-----------------------nch------------------------------------- + histos.fill(HIST("Data/hVar1x"), sample, nchAll, var1); + histos.fill(HIST("Data/hVar2x"), sample, nchAll, var2); + histos.fill(HIST("Data/hVarx"), sample, nchAll); + histos.fill(HIST("Data/hdiffVar1x"), sample, nch, var1); + histos.fill(HIST("Data/hdiffVar2x"), sample, nch, var2); + histos.fill(HIST("Data/hdiffVarx"), sample, nch); + histos.fill(HIST("Data/hVar2meanptx"), nchAll, var2); + + if (pidSwitchHistoFill) { + histos.fill(HIST("Data/hVar1pi"), sample, cent, var1Pi); + histos.fill(HIST("Data/hVar2pi"), sample, cent, var2Pi); + histos.fill(HIST("Data/hVar2meanptpi"), cent, var2Pi); + histos.fill(HIST("Data/hVar1k"), sample, cent, var1Ka); + histos.fill(HIST("Data/hVar2k"), sample, cent, var2Ka); + histos.fill(HIST("Data/hVar2meanptk"), cent, var2Ka); + histos.fill(HIST("Data/hVar1p"), sample, cent, var1Pr); + histos.fill(HIST("Data/hVar2p"), sample, cent, var2Pr); + histos.fill(HIST("Data/hVar2meanptp"), cent, var2Pr); + histos.fill(HIST("Data/hVar1pix"), sample, nchAll, var1Pi); + histos.fill(HIST("Data/hVar2pix"), sample, nchAll, var2Pi); + histos.fill(HIST("Data/hVarpix"), sample, nchPi); + histos.fill(HIST("Data/hVar2meanptpix"), nchAll, var2Pi); + histos.fill(HIST("Data/hVar1kx"), sample, nchAll, var1Ka); + histos.fill(HIST("Data/hVar2kx"), sample, nchAll, var2Ka); + histos.fill(HIST("Data/hVarkx"), sample, nchKa); + histos.fill(HIST("Data/hVar2meanptkx"), nchAll, var2Ka); + histos.fill(HIST("Data/hVar1px"), sample, nchAll, var1Pr); + histos.fill(HIST("Data/hVar2px"), sample, nchAll, var2Pr); + histos.fill(HIST("Data/hVarpx"), sample, nchPr); + histos.fill(HIST("Data/hVar2meanptpx"), nchAll, var2Pr); + } + + if (effSwitchHistoFill) { + var1Eff = (sumPtWeight * sumPtWeight - sumPtPtWeight) / (sumWeight * (sumWeight - 1)); + var2Eff = (sumPtWeight / sumWeight); + + histos.fill(HIST("hEffVar1x_data"), sample, nchAll, var1Eff); + histos.fill(HIST("hEffVar2x_data"), sample, nchAll, var2Eff); + histos.fill(HIST("hEffVarx_data"), sample, nchAll); + histos.fill(HIST("hEffVar2Meanptx_data"), nchAll, var2Eff); + histos.fill(HIST("hEffVar1x_Naccorr_data"), sample, sumWeight, var1Eff); + histos.fill(HIST("hEffVar2x_Naccorr_data"), sample, sumWeight, var2Eff); + histos.fill(HIST("hEffVarx_Naccorr_data"), sample, sumWeight); + histos.fill(HIST("hEffVar1x_Naccorr_xaxis_data"), sample, sumWeight, var1); + histos.fill(HIST("hEffVar2x_Naccorr_xaxis_data"), sample, sumWeight, var2); + histos.fill(HIST("hcent_nacc_corr"), cent, sumWeight); + histos.fill(HIST("hNch_vs_corr"), sample, nchAll, sumWeight); + } + //================= generated level============================== + + const auto& mccolgen = coll.mcCollision_as(); + if (std::abs(mccolgen.posZ()) > cVtxZcut) { + return; + } + const auto& mcpartgen = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolgen.globalIndex(), cache); + histos.fill(HIST("hVtxZ_after_gensim"), mccolgen.posZ()); + + double nchGenAll = 0., nchGenTrue = 0., nch1 = 0., nchgen = 0.; + double nchPiGen = 0., nchKaGen = 0., nchPrGen = 0.; + double q1AllGen = 0, q2AllGen = 0.; + double q1PiGen = 0, q2PiGen = 0, q1KaGen = 0, q2KaGen = 0, q1PrGen = 0, q2PrGen = 0; + double var1AllGen = 0, var2AllGen = 0.; + double var1PiGen = 0, var2PiGen = 0, var1KaGen = 0, var2KaGen = 0, var1PrGen = 0, var2PrGen = 0; + + int sampleGen = histos.get(HIST("hVtxZ_after_gensim"))->GetEntries(); + sampleGen = sampleGen % 30; + + for (const auto& mcpart : mcpartgen) { + // auto pdgcode = std::abs(mcpart.pdgCode()); + if (!mcpart.isPhysicalPrimary()) { + continue; + } + nch1++; + histos.fill(HIST("hnch_afterPhysPrimary"), nch1); + + int pid = mcpart.pdgCode(); + auto sign = 0; + auto* pd = pdg->GetParticle(pid); + if (pd != nullptr) { + sign = pd->Charge() / 3.; + } + if (sign == 0) { + continue; + } + // histos.fill(HIST("gen_hSign"), sign); + if (std::fabs(mcpart.eta()) > cEtacut) + continue; + nchGenTrue++; + histos.fill(HIST("hnch_gen_after_etacut"), nchGenTrue); + + if (mcpart.pt() >= cPtmincut1 && mcpart.pt() <= cPtmaxcut1) { + nchgen += 1.; + histos.fill(HIST("hnch_gen"), nchgen); + histos.fill(HIST("hPtvar_gen"), mcpart.pt()); + } + + if ((mcpart.pt() < cPtmincut) || (mcpart.pt() > cPtmaxcut)) + continue; + histos.fill(HIST("hPt_gen"), mcpart.pt()); + histos.fill(HIST("hEta_gen"), mcpart.eta()); + histos.fill(HIST("ptHistogram_allcharge_gen"), mcpart.pt()); + nchGenAll += 1.; + q1AllGen += mcpart.pt(); + q2AllGen += (mcpart.pt() * mcpart.pt()); + histos.fill(HIST("hnch_gen_all"), nchGenAll); + histos.fill(HIST("hPtEta_gen"), mcpart.pt(), mcpart.eta()); + + if (pidSwitch) { + if (std::fabs(mcpart.y()) < cRapidityCut05) { + + if (mcpart.pdgCode() == PDG_t::kPiPlus || mcpart.pdgCode() == PDG_t::kPiMinus) { + histos.fill(HIST("ptHistogramPion"), mcpart.pt()); + histos.fill(HIST("hPtEta_pi_gen"), mcpart.pt(), mcpart.eta()); + histos.fill(HIST("hPty_pi_gen"), mcpart.pt(), mcpart.y()); + nchPiGen += 1.; + q1PiGen += mcpart.pt(); + q2PiGen += (mcpart.pt() * mcpart.pt()); + histos.fill(HIST("hnch_pi"), nchPiGen); + } + + if (mcpart.pdgCode() == PDG_t::kKPlus || mcpart.pdgCode() == PDG_t::kKMinus) { + histos.fill(HIST("ptHistogramKaon"), mcpart.pt()); + histos.fill(HIST("hPtEta_ka_gen"), mcpart.pt(), mcpart.eta()); + histos.fill(HIST("hPty_ka_gen"), mcpart.pt(), mcpart.y()); + nchKaGen += 1.; + q1KaGen += mcpart.pt(); + q2KaGen += (mcpart.pt() * mcpart.pt()); + histos.fill(HIST("hnch_ka"), nchKaGen); + } + + if (mcpart.pdgCode() == PDG_t::kProton || mcpart.pdgCode() == PDG_t::kProtonBar) { + histos.fill(HIST("ptHistogramProton"), mcpart.pt()); + histos.fill(HIST("hPtEta_pr_gen"), mcpart.pt(), mcpart.eta()); + histos.fill(HIST("hPty_pr_gen"), mcpart.pt(), mcpart.y()); + nchPrGen += 1.; + q1PrGen += mcpart.pt(); + q2PrGen += (mcpart.pt() * mcpart.pt()); + histos.fill(HIST("hnch_pr"), nchPrGen); + } + + } //|y| < 0.5 cut ends! + } // pid flag + } // track loop ends! + histos.fill(HIST("hcent_nacc_gen"), cent, nchGenAll); + + if (nchGenAll < cTwoPtlCut2) + return; + var1AllGen = (q1AllGen * q1AllGen - q2AllGen) / (nchGenAll * (nchGenAll - 1)); + var2AllGen = (q1AllGen / nchGenAll); + + histos.fill(HIST("hVar1_gen"), sampleGen, cent, var1AllGen); + histos.fill(HIST("hVar2_gen"), sampleGen, cent, var2AllGen); + histos.fill(HIST("hVarc_gen"), sampleGen, cent); + + histos.fill(HIST("hterm1_gen"), nchGenAll, var1AllGen); + histos.fill(HIST("hterm2_gen"), nchGenAll, var2AllGen); + //-----------------------nch------------------------------------- + histos.fill(HIST("hVar1x_gen"), sampleGen, nchGenAll, var1AllGen); + histos.fill(HIST("hVar2x_gen"), sampleGen, nchGenAll, var2AllGen); + histos.fill(HIST("hVarx_gen"), sampleGen, nchGenAll); + histos.fill(HIST("hdiffVar1x_gen"), sampleGen, nchgen, var1AllGen); + histos.fill(HIST("hdiffVar2x_gen"), sampleGen, nchgen, var2AllGen); + histos.fill(HIST("hdiffVarx_gen"), sampleGen, nchgen); + histos.fill(HIST("hVar2meanptx_gen"), nchGenAll, var2AllGen); + + if (pidSwitchHistoFill) { + //--------------------------Pions------------------------------------------- + if (nchPiGen >= cTwoPtlCut2) { + var1PiGen = (q1PiGen * q1PiGen - q2PiGen) / (nchPiGen * (nchPiGen - 1)); + var2PiGen = (q1PiGen / nchPiGen); + } + //----------------------- kaons --------------------------------------- + if (nchKaGen >= cTwoPtlCut2) { + var1KaGen = (q1KaGen * q1KaGen - q2KaGen) / (nchKaGen * (nchKaGen - 1)); + var2KaGen = (q1KaGen / nchKaGen); + } + //---------------------------- protons ---------------------------------- + if (nchPrGen >= cTwoPtlCut2) { + var1PrGen = (q1PrGen * q1PrGen - q2PrGen) / (nchPrGen * (nchPrGen - 1)); + var2PrGen = (q1PrGen / nchPrGen); + } + histos.fill(HIST("hVar1pix_gen"), sampleGen, nchGenAll, var1PiGen); + histos.fill(HIST("hVar2pix_gen"), sampleGen, nchGenAll, var2PiGen); + histos.fill(HIST("hVarpix_gen"), sampleGen, nchPiGen); + histos.fill(HIST("hVar2meanptpix_gen"), nchGenAll, var2PiGen); + histos.fill(HIST("hVar1kx_gen"), sampleGen, nchGenAll, var1KaGen); + histos.fill(HIST("hVar2kx_gen"), sampleGen, nchGenAll, var2KaGen); + histos.fill(HIST("hVarkx_gen"), sampleGen, nchKaGen); + histos.fill(HIST("hVar2meanptkx_gen"), nchGenAll, var2KaGen); + histos.fill(HIST("hVar1px_gen"), sampleGen, nchGenAll, var1PrGen); + histos.fill(HIST("hVar2px_gen"), sampleGen, nchGenAll, var2PrGen); + histos.fill(HIST("hVarpx_gen"), sampleGen, nchPrGen); + histos.fill(HIST("hVar2meanptpx_gen"), nchGenAll, var2PrGen); + } + + } // void process + PROCESS_SWITCH(EventMeanPtId, processMcReco, "Process reconstructed", 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..987f540c37a --- /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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +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..9b3e0d943bb --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx @@ -0,0 +1,997 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include + +#include +#include +#include + +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", 100, ""}; + Configurable nPhiBins{"nPhiBins", 100, ""}; + Configurable cfgCutPtMax{"cfgCutPtMax", 2.0, "maximum pT"}; + Configurable cfgCutPtMin{"cfgCutPtMin", 0.2, "minimum pT"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut"}; + Configurable cfgCutRap{"cfgCutRap", 0.5, "Rapidity Cut"}; + Configurable cfgCutDcaZ{"cfgCutDcaZ", 0.15, "DCAz cut"}; + Configurable cfgCutPosZ{"cfgCutPosZ", 7.0, "cut for vertex Z"}; + Configurable cfgPosZ{"cfgPosZ", true, "Position Z"}; + Configurable cfgCutNSig2{"cfgCutNSig2", 2.0, "nSigma cut: 2"}; + Configurable cfgCutNSig3{"cfgCutNSig3", 3.0, "nSigma cut: 3"}; + Configurable cfgCutNSig5{"cfgCutNSig5", 5.0, "nSigma cut: 5"}; + Configurable cfgSelCutNSigPi{"cfgSelCutNSigPi", 2.0, "nSigma cut for pion selection"}; + Configurable cfgSelCutNSigKa{"cfgSelCutNSigKa", 3.0, "nSigma cut for kaon selection"}; + Configurable cfgSelCutNSigPr{"cfgSelCutNSigPr", 2.0, "nSigma cut for proton selection"}; + Configurable cfgRejCutNSigPi{"cfgRejCutNSigPi", 3.0, "nSigma cut for rejection of other particles while selecting pion"}; + 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 cfgSel8{"cfgSel8", true, "Sel8 trigger"}; + Configurable cfgMinWeight{"cfgMinWeight", 1e-6, "Minimum weight for efficiency correction"}; + Configurable cfgNoSameBunchPileup{"cfgNoSameBunchPileup", true, "kNoSameBunchPileup"}; + Configurable cfgIsVertexITSTPC{"cfgIsVertexITSTPC", true, "kIsVertexITSTPC"}; + Configurable cfgRejTrk{"cfgRejTrk", true, "Rejected Tracks"}; + Configurable cfgLoadEff{"cfgLoadEff", true, "Load efficiency"}; + Configurable cfgCorrection{"cfgCorrection", true, "Correction"}; + Configurable cfgWeightPtCh{"cfgWeightPtCh", true, "Efficiency correction (pT) for charged particles"}; + Configurable cfgWeightPtId{"cfgWeightPtId", false, "Efficiency correction (pT) "}; + Configurable cfgWeightPtEtaId{"cfgWeightPtEtaId", false, "Efficiency correction (pT) "}; + Configurable cfgPurityId{"cfgPurityId", false, "Purity correction"}; + ConfigurableAxis multTPCBins{"multTPCBins", {150, 0, 150}, "TPC Multiplicity bins"}; + ConfigurableAxis multFT0MBins{"multFT0MBins", {1000, 0, 5000}, "Forward Multiplicity bins"}; + ConfigurableAxis qNBins{"qNBins", {1000, 0., 100.}, "nth moments bins"}; + ConfigurableAxis nPairBins{"nPairBins", {2000, 0, 10000}, "nPair bins"}; + ConfigurableAxis dcaXYBins{"dcaXYBins", {100, -0.15, 0.15}, "dcaXY bins"}; + ConfigurableAxis dcaZBins{"dcaZBins", {500, -1.2, 1.2}, "dcaZ bins"}; + + 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 cfgUrlCCDB{"cfgUrlCCDB", "http://ccdb-test.cern.ch:8080", "url of ccdb"}; + Configurable cfgPathCCDB{"cfgPathCCDB", "Users/t/tgahlaut/weightCorr/", "Path for ccdb-object"}; + + Service ccdb; + Service pdg; + + HistogramRegistry hist{"hist", {}, OutputObjHandlingPolicy::AnalysisObject}; + + TH1D* hWeightPt = nullptr; + TH1D* hPurePt = nullptr; + TH1D* hWeightPtPi = nullptr; + TH1D* hWeightPtKa = nullptr; + TH1D* hWeightPtPr = nullptr; + TH1D* hPurePtPi = nullptr; + TH1D* hPurePtKa = nullptr; + TH1D* hPurePtPr = nullptr; + + enum CollisionLabels { + kTotCol = 1, + kPassSelCol + }; + + enum TrackLabels { + kTracksBeforeHasMcParticle = 1, + kAllTracks, + kAllSelPassed + }; + + enum SelCollisionLabels { + kBeforeSelCol = 1, + kSelColPosZ, + kSelColSel8, + kSelColNoSameBunchPileup, + kSelColIsVertexITSTPC, + }; + + enum class PIDType { + kNone, + kPions, + kKaons, + kProtons + }; + + 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/"}; + + 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")); + + if (!hWeightPt || !hWeightPtPi || !hWeightPtKa || !hWeightPtPr || !hPurePtPi || !hPurePtKa || !hPurePtPr) { + LOGF(info, "FATAL!! Could not find required histograms in CCDB"); + } + } + + const AxisSpec axisCol{3, 1, 4, ""}; + const AxisSpec axisTrack{5, 1, 6, ""}; + const AxisSpec axisEvents{10, 1, 11, "Counts"}; + const AxisSpec axisEta{etaBins, "#eta"}; + const AxisSpec axisPhi{nPhiBins, 0., +7., "#phi (rad)"}; + const AxisSpec axisY{100, -0.6, 0.6, "y"}; + const AxisSpec axisPt{ptBins, "p_{T} (GeV/c)"}; + 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 axisNpair{nPairBins, "N_{pairs}"}; + 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{101, 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{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}"}; + const AxisSpec axisPid{300, 0, 3000, "PID"}; + + HistogramConfigSpec qNHist({HistType::kTHnSparseD, {axisCentFT0M, axisQn}}); + HistogramConfigSpec partHist({HistType::kTHnSparseD, {axisCentFT0M, axisPart}}); + HistogramConfigSpec qNMCHist({HistType::kTHnSparseD, {axisCentFT0M, axisQn}}); + HistogramConfigSpec partMCHist({HistType::kTHnSparseD, {axisCentFT0M, axisPart}}); + 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 tpcSignalHist1({HistType::kTH2D, {axisInnerParam, axisTPCSignal}}); + 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_NTPC", "N_{TPC}", kTH1D, {axisMultTPC}); + hist.add("QA/before/h_NFT0M", "FT0M Multiplicity", kTH1D, {axisMultFT0M}); + hist.add("QA/before/h_CentM", "FT0M (%)", kTH1D, {axisCentFT0M}); + + 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.addClone("QA/before/", "QA/after/"); + + 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/after/h_counts_evSelCuts", "Event selection cuts", kTH1D, {axisEvents}); + 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/h2_NTPC_CentM", "N_{TPC} vs FT0M(%)", kTH2D, {{axisCentFT0M}, {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_CentM", "N_{TPC} vs FT0M(%) (Profile)", kTProfile, {axisCentFT0M}); + hist.add("QA/after/h_DCAxy_primary", "DCA_{XY} (Primary)", kTH1D, {axisDCAxy}); + hist.add("QA/after/h_DCAz_primary", "DCA_{Z} (Primary)", kTH1D, {axisDCAz}); + hist.add("QA/after/h_DCAxy_secondary", "DCA_{XY} (Secondary)", kTH1D, {axisDCAxy}); + hist.add("QA/after/h_DCAz_secondary", "DCA_{Z} (Secondary)", kTH1D, {axisDCAz}); + hist.add("QA/after/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); + + hist.add("QA/Charged/h_Pt", "p_{T}", kTH1D, {axisPt}); + hist.add("QA/Charged/h_Eta", "#eta ", kTH1D, {axisEta}); + hist.add("QA/Charged/h_Phi", "#phi ", kTH1D, {axisPhi}); + hist.add("QA/Charged/h_DcaZ", "DCA_{Z}", kTH1D, {axisDCAz}); + hist.add("QA/Charged/h_DcaXY", "DCA_{XY}", kTH1D, {axisDCAxy}); + hist.add("QA/Charged/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); + hist.add("QA/Charged/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); + hist.add("QA/Charged/h_Pt_weighted", "weighted pT distribution", kTH1D, {axisPt}); + hist.add("QA/Charged/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPt}}); + hist.add("QA/Charged/h2_Pt_centFT0M", "p_{T} in centrality Classes ", kTH2D, {{axisCentFT0M}, {axisPt}}); + hist.add("QA/Charged/h3_PtEtaPhi", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); + + hist.addClone("QA/Charged/", "QA/Pion/"); + + hist.add("QA/Pion/before/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); + hist.add("QA/Pion/before/h2_TPCNsigma_tof", "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_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} (Truth)", kTH1D, {axisPt}); + hist.add("QA/Pion/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPt}); + hist.add("QA/Pion/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPt}); + hist.add("QA/Pion/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); + 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/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); + hist.add("QA/Pion/h2_pvsm2", "p vs m^{2}", pvsM2Hist); + hist.add("QA/Pion/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPt}); + hist.add("QA/Pion/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPt}); + hist.addClone("QA/Pion/", "QA/Kaon/"); + hist.addClone("QA/Pion/", "QA/Proton/"); + + // AnalysisPlots + hist.add("Analysis/Charged/h_Mult", "Multiplicity", kTH1D, {axisMult}); + hist.add("Analysis/Charged/h_N_CentFT0M", "Multiplicity vs CentFT0M", kTHnSparseD, {axisCentFT0M, axisMult}); + hist.add("Analysis/Charged/h_Npair_CentFT0M", "Npair vs CentFT0M", kTHnSparseD, {axisCentFT0M, axisNpair}); + hist.add("Analysis/Charged/h_Q1_CentFT0M", "Q1 vs CentFT0M", qNHist); + hist.add("Analysis/Charged/h_Q2_CentFT0M", "Q2 vs CentFT0M", qNHist); + hist.add("Analysis/Charged/h_twopart1_CentFT0M", "twopart (neum)", qNMCHist); + hist.add("Analysis/Charged/h_mean_pT_Mult_var", " vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/h_twopart_Mult_var", "Twopart vs N_{TPC} ", partHist); + hist.add("Analysis/Charged/p_twopart_CentFT0M", "Twopart vs cent_{FT0M} ", kTProfile, {axisCentFT0M}); + hist.add("Analysis/Charged/p_mean_pT_CentFT0M", " vs cent_{FT0M} ", kTProfile, {axisCentFT0M}); + + 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_NSim", "Truth Multiplicity TPC", kTH1D, {axisMultTPC}); + hist.add("Gen/h2_NTPC_NSim", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultTPC}}); + + 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/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPt}}); + hist.add("Gen/Charged/h2_PtTruth_centFT0M", "p_{T} in centrality Classes ", kTH2D, {{axisCentFT0M}, {axisPt}}); + hist.add("Gen/Charged/h_PtEtaPhiTruth", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); + + hist.add("Gen/Charged/h_Mult", "Multiplicity", kTH1D, {axisMult}); + hist.add("Gen/Charged/h_N_CentFT0M", "Multiplicity vs CentFT0M", kTHnSparseD, {axisCentFT0M, axisMult}); + hist.add("Gen/Charged/h_Npair_CentFT0M", "Npair vs CentFT0M", kTHnSparseD, {axisCentFT0M, axisNpair}); + hist.add("Gen/Charged/h_Q1_CentFT0M", "Q1", qNMCHist); + hist.add("Gen/Charged/h_Q2_CentFT0M", "Q2", qNMCHist); + hist.add("Gen/Charged/h_twopart1_CentFT0M", "twopart (neum)", qNMCHist); + hist.add("Gen/Charged/h_mean_pT_Mult_var", " vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/h_twopart_Mult_var", "Twopart vs N_{TPC} ", partMCHist); + hist.add("Gen/Charged/p_twopart_CentFT0M", "Twopart vs CentFT0M ", kTProfile, {axisCentFT0M}); + hist.add("Gen/Charged/p_mean_pT_CentFT0M", " vs CentFT0M ", kTProfile, {axisCentFT0M}); + + hist.addClone("Gen/Charged/", "Gen/Pion/"); + + hist.add("Gen/Pion/h_RapTruth", "y", kTH1D, {axisY}); + 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/"); + + hist.add("QA/h_collisions_info", "Collisions info", kTH1D, {axisCol}); + hist.add("Gen/h_collisions_info", "Collisions info", kTH1D, {axisCol}); + hist.add("Gen/h_collision_recgen", "Number of Collisions ", kTH1D, {axisCol}); + hist.add("Gen/h2_collision_posZ", "Reco vs truth posZ ", kTH2D, {{axisVtxZ}, {axisVtxZ}}); + hist.add("Tracks/h_tracks_info", "Track info", kTH1D, {axisTrack}); + hist.add("Tracks/h2_tracks_pid_before_sel", "Track pid info before selection", kTH2D, {{axisPid}, {axisPt}}); + + hist.get(HIST("QA/h_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kTotCol, "kTotCol"); + hist.get(HIST("QA/h_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kPassSelCol, "kPassSelCol"); + hist.get(HIST("Gen/h_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kTotCol, "kTotCol"); + hist.get(HIST("Gen/h_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kPassSelCol, "kPassSelCol"); + hist.get(HIST("Tracks/h_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kTracksBeforeHasMcParticle, "kTracksBeforeHasMcParticle"); + hist.get(HIST("Tracks/h_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kAllTracks, "kAllTracks"); + hist.get(HIST("Tracks/h_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kAllSelPassed, "kAllSelPassed"); + hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kBeforeSelCol, "kBeforeSelCol"); + hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColPosZ, "kSelColPosZ"); + hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColSel8, "kSelColSel8"); + hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColNoSameBunchPileup, "kSelColNoSameBunchPileup"); + hist.get(HIST("QA/after/h_counts_evSelCuts"))->GetXaxis()->SetBinLabel(SelCollisionLabels::kSelColIsVertexITSTPC, "kSelColIsVertexITSTPC"); + } + + float centFT0M = 0.; + int nTPC = 0, nFT0M = 0; + + // Event selection cuts: + template + bool selRun3Col(T const& col) + { + hist.fill(HIST("QA/after/h_counts_evSelCuts"), kBeforeSelCol); + + if (cfgPosZ) { + if (std::abs(col.posZ()) > cfgCutPosZ) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), kSelColPosZ); + } + + centFT0M = col.centFT0M(); + nTPC = col.multNTracksHasTPC(); + nFT0M = col.multFT0M(); + + if (cfgSel8) { + if (!col.sel8()) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), kSelColSel8); + } + if (cfgNoSameBunchPileup) { + if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), kSelColNoSameBunchPileup); + } + + if (cfgIsVertexITSTPC) { + if (!col.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + hist.fill(HIST("QA/after/h_counts_evSelCuts"), kSelColIsVertexITSTPC); + } + + 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))) + return false; + + if (std::abs(track.eta()) >= cfgCutEta) + return false; + + return true; + } + + // Cuts to reject the tracks + template + bool rejectTracks(T const& track) + { + if (((track.tpcNSigmaEl()) > -cfgCutNSig3 && + (track.tpcNSigmaEl()) < cfgCutNSig5) && + (std::fabs(track.tpcNSigmaPi()) > cfgCutNSig3 && + std::fabs(track.tpcNSigmaKa()) > cfgCutNSig3 && + std::fabs(track.tpcNSigmaPr()) > cfgCutNSig3)) { + return true; + } + + return false; + } + + template + bool identifyParticle(T const& track, float momThreshold) + { + + const int sp = static_cast(s1); + const int sq = static_cast(s2); + const int sr = static_cast(s3); + std::vector vTpcNSigma = {-999., track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::vector vTofNSigma = {-999., track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + bool isTofPidFlag = false, isTpcPidFlag = false; + + float nSigmaSelCut = 0.; + float nSigmaTofRejCut = 0.; + float nSigmaTpcRejCut = 0.; + if constexpr (s1 == PIDType::kProtons) { + nSigmaSelCut = cfgSelCutNSigPr; + nSigmaTofRejCut = std::fabs(vTofNSigma[sp]); + nSigmaTpcRejCut = std::fabs(vTpcNSigma[sp]); + } else if constexpr (s1 == PIDType::kKaons) { + nSigmaSelCut = cfgSelCutNSigKa; + nSigmaTofRejCut = std::fabs(vTofNSigma[sp]); + nSigmaTpcRejCut = std::fabs(vTpcNSigma[sp]); + } else if constexpr (s1 == PIDType::kPions) { + nSigmaSelCut = cfgSelCutNSigPi; + nSigmaTofRejCut = cfgRejCutNSigPi; + nSigmaTpcRejCut = cfgRejCutNSigPi; + } + + if (track.hasTOF()) { + if (std::fabs(vTofNSigma[sp]) < nSigmaSelCut && + std::fabs(vTofNSigma[sq]) > nSigmaTofRejCut && + std::fabs(vTofNSigma[sr]) > nSigmaTofRejCut) { + isTofPidFlag = true; + } + if (std::fabs(vTpcNSigma[sp]) < cfgCutNSig2) { + isTpcPidFlag = true; + } + } else { // select from TPC Only + if (track.p() >= momThreshold) { + return false; + } + if (std::fabs(vTpcNSigma[sp]) < nSigmaSelCut && + std::fabs(vTpcNSigma[sq]) > nSigmaTpcRejCut && + std::fabs(vTpcNSigma[sr]) > nSigmaTpcRejCut) { + isTofPidFlag = true; + isTpcPidFlag = true; + } + } + + if (isTofPidFlag && isTpcPidFlag) { + return true; // Track is identified as one of the particles + } + + return false; // Track is not identified as any of the particles + } + + // Get corrected weight for the track: + template + float getCorrectedWeight(T1 hWeightPt, T1 hPurePt, float pt, bool cfgWeightPt, bool cfgPurity) + { + float weight = 1.0; + float purity = 1.0; + + if (cfgPurity) { + purity = hPurePt->GetBinContent(hPurePt->FindBin(pt)); + } + + if (cfgWeightPt) { + float weightPt = hWeightPt->GetBinContent(hWeightPt->FindBin(pt)); + weight = purity * weightPt; + } + + return weight; + } + + // 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_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"), nTPC); + hist.fill(HIST("QA/after/h_CentM"), centFT0M); + hist.fill(HIST("QA/after/h_NFT0M"), nFT0M); + hist.fill(HIST("QA/after/h2_NTPC_NFT0M"), nFT0M, nTPC); + hist.fill(HIST("QA/after/h2_NTPC_CentM"), centFT0M, nTPC); + hist.fill(HIST("QA/after/p_NTPC_CentM"), centFT0M, nTPC); + hist.fill(HIST("QA/after/p_NTPC_NFT0M"), nFT0M, nTPC); + } + + // Fill Charged particles QA: + template + void fillChargedQAHistos(T const& track, float centFT0M) + { + hist.fill(HIST("QA/Charged/h_Eta"), track.eta()); + hist.fill(HIST("QA/Charged/h_Phi"), track.phi()); + hist.fill(HIST("QA/Charged/h2_Pt_centFT0M"), centFT0M, track.pt()); + hist.fill(HIST("QA/Charged/h3_PtEtaPhi"), track.pt(), track.eta(), track.phi()); + hist.fill(HIST("QA/Charged/h2_Pt_Eta"), track.eta(), track.pt()); + hist.fill(HIST("QA/Charged/h_DcaZ"), track.dcaZ()); + hist.fill(HIST("QA/Charged/h_DcaXY"), track.dcaXY()); + hist.fill(HIST("QA/Charged/h2_DcaXY"), track.pt(), track.dcaXY()); + hist.fill(HIST("QA/Charged/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()); + + if (!track.hasTOF()) + hist.fill(HIST("QA/Pion/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPi()); + if (track.hasTOF()) + hist.fill(HIST("QA/Pion/before/h2_TPCNsigma_tof"), 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()); + if (!track.hasTOF()) + hist.fill(HIST("QA/Proton/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPr()); + if (track.hasTOF()) + hist.fill(HIST("QA/Proton/before/h2_TPCNsigma_tof"), 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()); + if (!track.hasTOF()) + hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaKa()); + if (track.hasTOF()) + hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma_tof"), 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()); + } + + // Moments Calculation: + void moments(float pt, float weight, double& Q1, double& Q2) + { + Q1 += pt * weight; + Q2 += pt * pt * weight * weight; + } + + template + void fillIdParticleQAHistos(T const& track, float rap, float nSigmaTPC, float nSigmaTOF, float centFT0M, T1 hWeightPt, T1 hPurePt, bool cfgWeightPtId, bool cfgPurityId, double& NW, double& NW2, double& Q1, double& Q2) + { + float pt = track.pt(); + float eta = track.eta(); + float phi = track.phi(); + float weight = getCorrectedWeight(hWeightPt, hPurePt, pt, cfgWeightPtId, cfgPurityId); + + if (std::abs(weight) < cfgMinWeight) + return; + + NW += weight; + NW2 += weight * weight; + moments(pt, weight, Q1, Q2); + + 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); + } + + 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("h2_Pt_centFT0M"), centFT0M, pt); + hist.fill(HIST(Dire[Mode]) + HIST("h3_PtEtaPhi"), pt, eta, phi); + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_Eta"), eta, pt); + hist.fill(HIST(Dire[Mode]) + HIST("h_Eta"), eta); + hist.fill(HIST(Dire[Mode]) + HIST("h_Phi"), phi); + hist.fill(HIST(Dire[Mode]) + HIST("h_Rap"), rap); + 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"), 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("innerParam/h2_TPCSignal"), track.tpcInnerParam(), 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/innerParam/h2_TPCSignal"), track.tpcInnerParam(), 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()); + } + + template + void fillPtMCHist(bool cfgGen, float pt, float eta, float rap, float phi, float centFT0M, int pid, int pdgCodePos, int pdgCodeNeg) + { + if (cfgGen) { + 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_centFT0M"), centFT0M, pt); + hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_EtaTruth"), eta, pt); + hist.fill(HIST(Dire[Mode]) + HIST("h_PhiTruth"), phi); + hist.fill(HIST(Dire[Mode]) + HIST("h_PtEtaPhiTruth"), pt, eta, phi); + } + + 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(bool cfgCorrection, float centFT0M, double nW, double nW2, double Q1, double Q2) + { + if (nW == 0) { + return; + } + + hist.fill(HIST(Dire[Mode]) + HIST("h_Mult"), nW); + + double nPair = 0., meanPt = 0., twopart1 = 0., twopart = 0.; + + if (cfgCorrection) { + nPair = nW * nW - nW2; + } else { + if (nW > 1) { + nPair = nW * (nW - 1); + } + } + + if (nPair > 0) { + meanPt = Q1 / nW; + twopart1 = (Q1 * Q1 - Q2); + twopart = twopart1 / nPair; + + hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Mult_var"), centFT0M, meanPt); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Mult_var"), centFT0M, twopart); + hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_CentFT0M"), centFT0M, meanPt); + hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_CentFT0M"), centFT0M, twopart); + hist.fill(HIST(Dire[Mode]) + HIST("h_twopart1_CentFT0M"), centFT0M, twopart1); + } + + hist.fill(HIST(Dire[Mode]) + HIST("h_Mult"), nW); + hist.fill(HIST(Dire[Mode]) + HIST("h_N_CentFT0M"), centFT0M, nW); + hist.fill(HIST(Dire[Mode]) + HIST("h_Npair_CentFT0M"), centFT0M, nPair); + hist.fill(HIST(Dire[Mode]) + HIST("h_Q1_CentFT0M"), centFT0M, Q1); + hist.fill(HIST(Dire[Mode]) + HIST("h_Q2_CentFT0M"), centFT0M, Q2); + } + + template + void fillRecoHistos(C const& col, T const& tracks) + { + double nChW = 0., nChW2 = 0., q1Ch = 0., q2Ch = 0.; + float wghtCh = 1.0; + double nPiW = 0., nPiW2 = 0., q1Pi = 0., q2Pi = 0.; + double nKaW = 0., nKaW2 = 0., q1Ka = 0., q2Ka = 0.; + double nPrW = 0., nPrW2 = 0., q1Pr = 0., q2Pr = 0.; + float pt = 0., eta = 0., phi = 0.; + + hist.fill(HIST("QA/h_collisions_info"), kTotCol); + + if constexpr (DataFlag) { + if (!selRun3Col(col)) { + return; + } + } + + hist.fill(HIST("QA/h_collisions_info"), kPassSelCol); + + fillAfterQAHistos(col); + + for (auto const& track : tracks) { + float nSigmaTPCPi = track.tpcNSigmaPi(); + float nSigmaTPCKa = track.tpcNSigmaKa(); + float nSigmaTPCPr = track.tpcNSigmaPr(); + float nSigmaTOFPi = track.tofNSigmaPi(); + float nSigmaTOFKa = track.tofNSigmaKa(); + float nSigmaTOFPr = track.tofNSigmaPr(); + float rapPi = track.rapidity(MassPiPlus); + float rapKa = track.rapidity(MassKPlus); + float rapPr = track.rapidity(MassProton); + + if constexpr (RecoFlag) { + if (!track.has_mcParticle()) { + hist.fill(HIST("Tracks/h_tracks_info"), kTracksBeforeHasMcParticle); + continue; + } + } + hist.fill(HIST("Tracks/h_tracks_info"), kAllTracks); + + if (!selTrack(track)) { + continue; + } + hist.fill(HIST("Tracks/h_tracks_info"), kAllSelPassed); + + pt = track.pt(); + if constexpr (RecoFlag) { + hist.fill(HIST("Tracks/h2_tracks_pid_before_sel"), track.mcParticle().pdgCode(), track.pt()); + + auto mc = track.template mcParticle_as(); + pt = mc.pt(); + eta = mc.eta(); + phi = mc.phi(); + + if (mc.isPhysicalPrimary()) { + hist.fill(HIST("QA/after/h_DCAxy_primary"), track.dcaXY()); + hist.fill(HIST("QA/after/h_DCAz_primary"), track.dcaZ()); + } else { + hist.fill(HIST("QA/after/h_DCAxy_secondary"), track.dcaXY()); + hist.fill(HIST("QA/after/h_DCAz_secondary"), track.dcaZ()); + } + } + + // Charged particles: + wghtCh = getCorrectedWeight(hWeightPt, hPurePt, pt, cfgWeightPtCh, false); + + if (std::abs(wghtCh) < cfgMinWeight) + return; + + nChW += wghtCh; + nChW2 += wghtCh * wghtCh; + moments(pt, wghtCh, q1Ch, q2Ch); + hist.fill(HIST("QA/Charged/h_Pt"), track.pt()); + fillChargedQAHistos(track, centFT0M); + + fillBeforePIDQAHistos(track); + + // identified particles: + if (cfgRejTrk && rejectTracks(track)) { + continue; + } + auto selIDPion = identifyParticle(track, cfgCutPiThrsldP); + auto selIDKaon = identifyParticle(track, cfgCutKaThrsldP); + auto selIDProton = identifyParticle(track, cfgCutPrThrsldP); + if (selIDPion && pt >= cfgCutPiPtMin) { + hist.fill(HIST("QA/Pion/h_Pt"), track.pt()); + fillIdParticleQAHistos(track, rapPi, nSigmaTPCPi, nSigmaTOFPi, centFT0M, hWeightPtPi, hPurePtPi, cfgWeightPtId, cfgPurityId, nPiW, nPiW2, q1Pi, q2Pi); + } + if (selIDKaon && pt >= cfgCutKaPtMin) { + hist.fill(HIST("QA/Kaon/h_Pt"), track.pt()); + fillIdParticleQAHistos(track, rapKa, nSigmaTPCKa, nSigmaTOFKa, centFT0M, hWeightPtKa, hPurePtKa, cfgWeightPtId, cfgPurityId, nKaW, nKaW2, q1Ka, q2Ka); + } + if (selIDProton && pt >= cfgCutPrPtMin) { + hist.fill(HIST("QA/Proton/h_Pt"), track.pt()); + fillIdParticleQAHistos(track, rapPr, nSigmaTPCPr, nSigmaTOFPr, centFT0M, hWeightPtPr, hPurePtPr, cfgWeightPtId, cfgPurityId, nPrW, nPrW2, q1Pr, q2Pr); + } + + if constexpr (RecoFlag) { + auto mc = track.template mcParticle_as(); + int pid = mc.pdgCode(); + if (selIDPion && pt >= cfgCutPiPtMin) { + if (std::abs(pid) == kPiPlus) { + hist.fill(HIST("QA/Pion/h_PtTruth"), pt); + fillPtMCHist(false, pt, eta, rapPi, phi, centFT0M, pid, kPiPlus, kPiMinus); + if (mc.isPhysicalPrimary()) { + hist.fill(HIST("QA/Pion/h_PtTruth_primary"), pt); + } else { + hist.fill(HIST("QA/Pion/h_PtTruth_secondary"), pt); + } + } + } + if (selIDKaon && pt >= cfgCutKaPtMin) { + if (std::abs(pid) == kKPlus) { + hist.fill(HIST("QA/Kaon/h_PtTruth"), pt); + fillPtMCHist(false, pt, eta, rapKa, phi, centFT0M, pid, kKPlus, kKMinus); + if (mc.isPhysicalPrimary()) { + hist.fill(HIST("QA/Kaon/h_PtTruth_primary"), pt); + } else { + hist.fill(HIST("QA/Kaon/h_PtTruth_secondary"), pt); + } + } + } + if (selIDProton && pt >= cfgCutPrPtMin) { + if (std::abs(pid) == kProton) { + hist.fill(HIST("QA/Proton/h_PtTruth"), pt); + fillPtMCHist(false, pt, eta, rapPr, phi, centFT0M, pid, kProton, kProtonBar); + if (mc.isPhysicalPrimary()) { + hist.fill(HIST("QA/Proton/h_PtTruth_primary"), pt); + } else { + hist.fill(HIST("QA/Proton/h_PtTruth_secondary"), pt); + } + } + } + } + } + fillAnalysisHistos(cfgCorrection, centFT0M, nChW, nChW2, q1Ch, q2Ch); + fillAnalysisHistos(cfgCorrection, centFT0M, nPiW, nPiW2, q1Pi, q2Pi); + fillAnalysisHistos(cfgCorrection, centFT0M, nKaW, nKaW2, q1Ka, q2Ka); + fillAnalysisHistos(cfgCorrection, centFT0M, nPrW, nPrW2, q1Pr, q2Pr); + } + + template + void fillGenHistos(C const& mcCol, M const& mcParticles) + { + int nSim = 0; + double nChSim = 0., q1ChSim = 0., q2ChSim = 0.; + double nPiSim = 0., q1PiSim = 0., q2PiSim = 0.; + double nKaSim = 0., q1KaSim = 0., q2KaSim = 0.; + double nPrSim = 0., q1PrSim = 0., q2PrSim = 0.; + float pt = 0, eta = 0, phi = 0, rap = 0; + for (auto const& mcPart : mcParticles) { + if (!mcPart.isPhysicalPrimary()) { + continue; + } + + auto pid = mcPart.pdgCode(); + if (std::abs(pid) != kElectron && std::abs(pid) != kMuonMinus && std::abs(pid) != kPiPlus && std::abs(pid) != kKPlus && std::abs(pid) != kProton) { + continue; + } + + pt = mcPart.pt(); + eta = mcPart.eta(); + phi = mcPart.phi(); + if (std::abs(eta) < cfgCutEta) { + nSim++; + } + + if (pt >= cfgCutPtMin && pt < cfgCutPtMax && std::abs(eta) < cfgCutEta) { + nChSim++; + moments(pt, 1.0, q1ChSim, q2ChSim); + hist.fill(HIST("Gen/Charged/h_PtTruth"), pt); + hist.fill(HIST("Gen/Charged/h_EtaTruth"), eta); + hist.fill(HIST("Gen/Charged/h_PhiTruth"), phi); + hist.fill(HIST("Gen/Charged/h2_Pt_EtaTruth"), eta, pt); + hist.fill(HIST("Gen/Charged/h2_PtTruth_centFT0M"), centFT0M, pt); + hist.fill(HIST("Gen/Charged/h_PtEtaPhiTruth"), pt, eta, phi); + + rap = mcPart.y(); + if (std::abs(pid) == kPiPlus && mcPart.pt() > cfgCutPiPtMin) { + nPiSim++; + moments(pt, 1.0, q1PiSim, q2PiSim); + hist.fill(HIST("Gen/Pion/h_PtTruth"), pt); + fillPtMCHist(true, pt, eta, rap, phi, centFT0M, pid, kPiMinus, kPiMinus); + } + if (std::abs(pid) == kKPlus && mcPart.pt() > cfgCutKaPtMin) { + nKaSim++; + moments(pt, 1.0, q1KaSim, q2KaSim); + hist.fill(HIST("Gen/Kaon/h_PtTruth"), pt); + fillPtMCHist(true, pt, eta, rap, phi, centFT0M, pid, kKMinus, kKMinus); + } + if (std::abs(pid) == kProton && mcPart.pt() > cfgCutPrPtMin) { + nPrSim++; + moments(pt, 1.0, q1PrSim, q2PrSim); + hist.fill(HIST("Gen/Proton/h_PtTruth"), pt); + fillPtMCHist(true, pt, eta, rap, phi, centFT0M, pid, kProtonBar, kProtonBar); + } + } + } + fillAnalysisHistos(false, centFT0M, nChSim, nChSim, q1ChSim, q2ChSim); + fillAnalysisHistos(false, centFT0M, nPiSim, nPiSim, q1PiSim, q2PiSim); + fillAnalysisHistos(false, centFT0M, nKaSim, nKaSim, q1KaSim, q2KaSim); + fillAnalysisHistos(false, centFT0M, nPrSim, nPrSim, q1PrSim, q2PrSim); + hist.fill(HIST("Gen/h_Counts"), 2); + hist.fill(HIST("Gen/h_VtxZ"), mcCol.posZ()); + hist.fill(HIST("Gen/h_NSim"), nSim); + hist.fill(HIST("Gen/h2_NTPC_NSim"), nSim, nTPC); + } + + template + void analyzeMC(M const& mcCol, C const& cols, T const& tracks, P const& mcParts) + { + // fillBeforeQAHistos(cols.begin(), tracks); + hist.fill(HIST("Gen/h_VtxZ_b"), mcCol.posZ()); + int nRecCols = cols.size(); + if (nRecCols == 0) { + hist.fill(HIST("Gen/h_collision_recgen"), nRecCols); + } + // Do not analyze if more than one reco collision is accociated to one mc gen collision + if (nRecCols != 1) { + return; + } + hist.fill(HIST("Gen/h_collisions_info"), kTotCol); + + // Check the reco collision + if (!cols.begin().has_mcCollision() || !selRun3Col(cols.begin()) || cols.begin().mcCollisionId() != mcCol.globalIndex()) { + return; + } + + hist.fill(HIST("Gen/h_collisions_info"), kPassSelCol); + hist.fill(HIST("Gen/h2_collision_posZ"), mcCol.posZ(), cols.begin().posZ()); + + auto sTracks = tracks.sliceBy(perCollision, cols.begin().globalIndex()); + fillRecoHistos(cols.begin(), sTracks); + fillGenHistos(mcCol, mcParts); + } + + using MyAllTracks = soa::Join; + using MyRun3Collisions = soa::Join; + using MyRun3MCCollisions = soa::Join; + using MyMCTracks = soa::Join; + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + + void processRun3(MyRun3Collisions::iterator const& col, MyAllTracks const& tracks) + { + fillBeforeQAHistos(col, tracks); + fillRecoHistos(col, tracks); + } + PROCESS_SWITCH(MeanPtFlucId, processRun3, "Process for Run-3", false); + + void processMCRecoSimRun3(aod::McCollisions::iterator const& mcCol, soa::SmallGroups const& cols, MyMCTracks const& tracks, aod::McParticles const& mcParts) + { + analyzeMC(mcCol, cols, tracks, mcParts); + } + 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..0ccf2544364 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/nchCumulantsId.cxx @@ -0,0 +1,761 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 +/// \author Pravata Panigrahi :: Sadhana Dash(sadhana@phy.iitb.ac.in) + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +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"}; + Configurable cfgCutPtMax{"cfgCutPtMax", 3.0, "max cut for pT"}; + Configurable cfgCutPtMin{"cfgCutPtMin", 0.15, "min cut for pT"}; + + // Configurables for particle Identification + Configurable cfgId01CheckVetoCut{"cfgId01CheckVetoCut", false, "cfgId01CheckVetoCut"}; + Configurable cfgId02DoElRejection{"cfgId02DoElRejection", true, "cfgId02DoElRejection"}; + Configurable cfgId03DoDeRejection{"cfgId03DoDeRejection", false, "cfgId03DoDeRejection"}; + Configurable cfgId04DoPdependentId{"cfgId04DoPdependentId", true, "cfgId04DoPdependentId"}; + Configurable cfgId05DoTpcInnerParamId{"cfgId05DoTpcInnerParamId", false, "cfgId05DoTpcInnerParamId"}; + + Configurable cfgIdPi01ThrPforTOF{"cfgIdPi01ThrPforTOF", 0.7, "cfgIdPi01ThrPforTOF"}; + Configurable cfgIdPi02IdCutTypeLowP{"cfgIdPi02IdCutTypeLowP", 0, "cfgIdPi02IdCutTypeLowP"}; + Configurable cfgIdPi03NSigmaTPCLowP{"cfgIdPi03NSigmaTPCLowP", 2.0, "cfgIdPi03NSigmaTPCLowP"}; + Configurable cfgIdPi04NSigmaTOFLowP{"cfgIdPi04NSigmaTOFLowP", 2.0, "cfgIdPi04NSigmaTOFLowP"}; + Configurable cfgIdPi05NSigmaRadLowP{"cfgIdPi05NSigmaRadLowP", 4.0, "cfgIdPi05NSigmaRadLowP"}; + Configurable cfgIdPi06IdCutTypeHighP{"cfgIdPi06IdCutTypeHighP", 0, "cfgIdPi06IdCutTypeHighP"}; + Configurable cfgIdPi07NSigmaTPCHighP{"cfgIdPi07NSigmaTPCHighP", 2.0, "cfgIdPi07NSigmaTPCHighP"}; + Configurable cfgIdPi08NSigmaTOFHighP{"cfgIdPi08NSigmaTOFHighP", 2.0, "cfgIdPi08NSigmaTOFHighP"}; + Configurable cfgIdPi09NSigmaRadHighP{"cfgIdPi09NSigmaRadHighP", 4.0, "cfgIdPi09NSigmaRadHighP"}; + + Configurable cfgIdKa01ThrPforTOF{"cfgIdKa01ThrPforTOF", 0.8, "cfgIdKa01ThrPforTOF"}; + Configurable cfgIdKa02IdCutTypeLowP{"cfgIdKa02IdCutTypeLowP", 0, "cfgIdKa02IdCutTypeLowP"}; + Configurable cfgIdKa03NSigmaTPCLowP{"cfgIdKa03NSigmaTPCLowP", 2.0, "cfgIdKa03NSigmaTPCLowP"}; + Configurable cfgIdKa04NSigmaTOFLowP{"cfgIdKa04NSigmaTOFLowP", 2.0, "cfgIdKa04NSigmaTOFLowP"}; + Configurable cfgIdKa05NSigmaRadLowP{"cfgIdKa05NSigmaRadLowP", 4.0, "cfgIdKa05NSigmaRadLowP"}; + Configurable cfgIdKa06IdCutTypeHighP{"cfgIdKa06IdCutTypeHighP", 0, "cfgIdKa06IdCutTypeHighP"}; + Configurable cfgIdKa07NSigmaTPCHighP{"cfgIdKa07NSigmaTPCHighP", 2.0, "cfgIdKa07NSigmaTPCHighP"}; + Configurable cfgIdKa08NSigmaTOFHighP{"cfgIdKa08NSigmaTOFHighP", 2.0, "cfgIdKa08NSigmaTOFHighP"}; + Configurable cfgIdKa09NSigmaRadHighP{"cfgIdKa09NSigmaRadHighP", 4.0, "cfgIdKa09NSigmaRadHighP"}; + + Configurable cfgIdPr01ThrPforTOF{"cfgIdPr01ThrPforTOF", 0.8, "cfgIdPr01ThrPforTOF"}; + Configurable cfgIdPr02IdCutTypeLowP{"cfgIdPr02IdCutTypeLowP", 0, "cfgIdPr02IdCutTypeLowP"}; + Configurable cfgIdPr03NSigmaTPCLowP{"cfgIdPr03NSigmaTPCLowP", 2.0, "cfgIdPr03NSigmaTPCLowP"}; + Configurable cfgIdPr04NSigmaTOFLowP{"cfgIdPr04NSigmaTOFLowP", 2.0, "cfgIdPr04NSigmaTOFLowP"}; + Configurable cfgIdPr05NSigmaRadLowP{"cfgIdPr05NSigmaRadLowP", 4.0, "cfgIdPr05NSigmaRadLowP"}; + Configurable cfgIdPr06IdCutTypeHighP{"cfgIdPr06IdCutTypeHighP", 0, "cfgIdPr06IdCutTypeHighP"}; + Configurable cfgIdPr07NSigmaTPCHighP{"cfgIdPr07NSigmaTPCHighP", 2.0, "cfgIdPr07NSigmaTPCHighP"}; + Configurable cfgIdPr08NSigmaTOFHighP{"cfgIdPr08NSigmaTOFHighP", 2.0, "cfgIdPr08NSigmaTOFHighP"}; + Configurable cfgIdPr09NSigmaRadHighP{"cfgIdPr09NSigmaRadHighP", 4.0, "cfgIdPr09NSigmaRadHighP"}; + + struct : ConfigurableGroup { + Configurable cfgVetoId01PiTPC{"cfgVetoId01PiTPC", 3.0, "cfgVetoId01PiTPC"}; + Configurable cfgVetoId02PiTOF{"cfgVetoId02PiTOF", 3.0, "cfgVetoId02PiTOF"}; + Configurable cfgVetoId03KaTPC{"cfgVetoId03KaTPC", 3.0, "cfgVetoId03KaTPC"}; + Configurable cfgVetoId04KaTOF{"cfgVetoId04KaTOF", 3.0, "cfgVetoId04KaTOF"}; + Configurable cfgVetoId05PrTPC{"cfgVetoId05PrTPC", 3.0, "cfgVetoId05PrTPC"}; + Configurable cfgVetoId06PrTOF{"cfgVetoId06PrTOF", 3.0, "cfgVetoId06PrTOF"}; + Configurable cfgVetoId07ElTPC{"cfgVetoId07ElTPC", 3.0, "cfgVetoId07ElTPC"}; + Configurable cfgVetoId08ElTOF{"cfgVetoId08ElTOF", 3.0, "cfgVetoId08ElTOF"}; + Configurable cfgVetoId09DeTPC{"cfgVetoId09DeTPC", 3.0, "cfgVetoId09DeTPC"}; + Configurable cfgVetoId10DeTOF{"cfgVetoId10DeTOF", 3.0, "cfgVetoId10DeTOF"}; + } cfgVetoIdCut; + + 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/tpctofId/"); + 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 + + enum IdentificationType { + kTPCidentified = 0, + kTOFidentified, + kTPCTOFidentified, + kUnidentified + }; + + enum TpcTofCutType { + kRectangularCut = 0, + kCircularCut, + kEllipsoidalCut + }; + + enum DetEnum { + tpcId = 0, + tofId, + tpctofId, + NoId + }; + + static constexpr std::string_view DetDire[] = { + "tpcId/", + "tofId/", + "tpctofId/", + "NoId/"}; + + 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/"}; + + // particle identifications + // tpc Selections + + template + bool vetoIdOthersTPC(const T& track) + { + if (pidMode != kPi) { + if (std::fabs(track.tpcNSigmaPi()) < cfgVetoIdCut.cfgVetoId01PiTPC) + return false; + } + if (pidMode != kKa) { + if (std::fabs(track.tpcNSigmaKa()) < cfgVetoIdCut.cfgVetoId03KaTPC) + return false; + } + if (pidMode != kPr) { + if (std::fabs(track.tpcNSigmaPr()) < cfgVetoIdCut.cfgVetoId05PrTPC) + return false; + } + if (cfgId02DoElRejection) { + if (pidMode != kEl) { + if (std::fabs(track.tpcNSigmaEl()) < cfgVetoIdCut.cfgVetoId07ElTPC) + return false; + } + } + if (cfgId03DoDeRejection) { + if (pidMode != kDe) { + if (std::fabs(track.tpcNSigmaDe()) < cfgVetoIdCut.cfgVetoId09DeTPC) + return false; + } + } + return true; + } + + template + bool vetoIdOthersTOF(const T& track) + { + if (pidMode != kPi) { + if (std::fabs(track.tofNSigmaPi()) < cfgVetoIdCut.cfgVetoId02PiTOF) + return false; + } + if (pidMode != kKa) { + if (std::fabs(track.tofNSigmaKa()) < cfgVetoIdCut.cfgVetoId04KaTOF) + return false; + } + if (pidMode != kPr) { + if (std::fabs(track.tofNSigmaPr()) < cfgVetoIdCut.cfgVetoId06PrTOF) + return false; + } + if (cfgId02DoElRejection) { + if (pidMode != kEl) { + if (std::fabs(track.tofNSigmaEl()) < cfgVetoIdCut.cfgVetoId08ElTOF) + return false; + } + } + if (cfgId03DoDeRejection) { + if (pidMode != kDe) { + if (std::fabs(track.tofNSigmaDe()) < cfgVetoIdCut.cfgVetoId10DeTOF) + return false; + } + } + return true; + } + + template + bool vetoIdOthersTPCTOF(const T& track) + { + if (pidMode != kPi) { + if (std::fabs(track.tpcNSigmaPi()) < cfgVetoIdCut.cfgVetoId01PiTPC && std::fabs(track.tofNSigmaPi()) < cfgVetoIdCut.cfgVetoId02PiTOF) + return false; + } + if (pidMode != kKa) { + if (std::fabs(track.tpcNSigmaKa()) < cfgVetoIdCut.cfgVetoId03KaTPC && std::fabs(track.tofNSigmaKa()) < cfgVetoIdCut.cfgVetoId04KaTOF) + return false; + } + if (pidMode != kPr) { + if (std::fabs(track.tpcNSigmaPr()) < cfgVetoIdCut.cfgVetoId05PrTPC && std::fabs(track.tofNSigmaPr()) < cfgVetoIdCut.cfgVetoId06PrTOF) + return false; + } + if (cfgId02DoElRejection) { + if (pidMode != kEl) { + if (std::fabs(track.tpcNSigmaEl()) < cfgVetoIdCut.cfgVetoId07ElTPC && std::fabs(track.tofNSigmaEl()) < cfgVetoIdCut.cfgVetoId08ElTOF) + return false; + } + } + if (cfgId03DoDeRejection) { + if (pidMode != kDe) { + if (std::fabs(track.tpcNSigmaDe()) < cfgVetoIdCut.cfgVetoId09DeTPC && std::fabs(track.tofNSigmaDe()) < cfgVetoIdCut.cfgVetoId10DeTOF) + 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 (cfgId01CheckVetoCut && !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 (cfgId01CheckVetoCut && !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 selPdependent(const T& track, int& IdMethod, const float& cfgIdThrPforTOF, + const int& idCutTypeLowP, const float& nSigmaTPCLowP, const float& nSigmaTOFLowP, const float& nSigmaRadLowP, + const int& idCutTypeHighP, const float& nSigmaTPCHighP, const float& nSigmaTOFHighP, const float& nSigmaRadHighP) + { + if (track.p() < cfgIdThrPforTOF) { + if (checkReliableTOF(track)) { + if (idTPCTOF(track, idCutTypeLowP, nSigmaTPCLowP, nSigmaTOFLowP, nSigmaRadLowP)) { + IdMethod = kTPCTOFidentified; + return true; + } + return false; + } else { + if (idTPC(track, nSigmaTPCLowP)) { + IdMethod = kTPCidentified; + return true; + } + return false; + } + } else { + if (checkReliableTOF(track)) { + if (idTPCTOF(track, idCutTypeHighP, nSigmaTPCHighP, nSigmaTOFHighP, nSigmaRadHighP)) { + IdMethod = kTPCTOFidentified; + return true; + } + return false; + } + return false; + } + } + + // + //______________________________Identification Functions________________________________________________________________ + // Pion + template + bool selPion(const T& track, int& IdMethod) + { + if (cfgId04DoPdependentId) { + return selPdependent(track, IdMethod, + cfgIdPi01ThrPforTOF, cfgIdPi02IdCutTypeLowP, cfgIdPi03NSigmaTPCLowP, cfgIdPi04NSigmaTOFLowP, cfgIdPi05NSigmaRadLowP, + cfgIdPi06IdCutTypeHighP, cfgIdPi07NSigmaTPCHighP, cfgIdPi08NSigmaTOFHighP, cfgIdPi09NSigmaRadHighP); + } + return false; + } + + // Kaon + template + bool selKaon(const T& track, int& IdMethod) + { + if (cfgId04DoPdependentId) { + return selPdependent(track, IdMethod, + cfgIdKa01ThrPforTOF, cfgIdKa02IdCutTypeLowP, cfgIdKa03NSigmaTPCLowP, cfgIdKa04NSigmaTOFLowP, cfgIdKa05NSigmaRadLowP, + cfgIdKa06IdCutTypeHighP, cfgIdKa07NSigmaTPCHighP, cfgIdKa08NSigmaTOFHighP, cfgIdKa09NSigmaRadHighP); + } + return false; + } + + // Proton + template + bool selProton(const T& track, int& IdMethod) + { + if (cfgId04DoPdependentId) { + return selPdependent(track, IdMethod, + cfgIdPr01ThrPforTOF, cfgIdPr02IdCutTypeLowP, cfgIdPr03NSigmaTPCLowP, cfgIdPr04NSigmaTOFLowP, cfgIdPr05NSigmaRadLowP, + cfgIdPr06IdCutTypeHighP, cfgIdPr07NSigmaTPCHighP, cfgIdPr08NSigmaTOFHighP, cfgIdPr09NSigmaRadHighP); + } + return false; + } + + 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 > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax); + 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 == kTPCidentified) + fillIdentificationQA(hist, track); + if (idMethod == kTPCTOFidentified) + fillIdentificationQA(hist, track); + } + // kaon + if (selKaon(track, idMethod)) { + if (track.sign() == 1) { + nKa++; + } + if (track.sign() == -1) { + nAKa++; + } + + if (idMethod == kTPCidentified) + fillIdentificationQA(hist, track); + if (idMethod == kTPCTOFidentified) + fillIdentificationQA(hist, track); + } + // proton + if (selProton(track, idMethod)) { + if (track.sign() == 1) { + nPr++; + } + if (track.sign() == -1) { + nAPr++; + } + + if (idMethod == kTPCidentified) + fillIdentificationQA(hist, track); + if (idMethod == kTPCTOFidentified) + 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..c94a99a1670 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/netchargeFluctuations.cxx @@ -0,0 +1,1098 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file netchargeFluctuations.cxx +/// \brief Calculate net-charge fluctuations using nu_dyn observable +/// For charged particles +/// For RUN-3 +/// +/// \author Nida Malik +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include "TF1.h" +#include "TProfile.h" +#include "TProfile2D.h" +#include "TRandom3.h" + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; +using namespace o2::constants::physics; + +enum RunType { + kRun3 = 0, + kRun2 +}; + +// Structure to handle net charge fluctuation analysis +struct NetchargeFluctuations { + + // Macro to define configurable parameters with default values and help text + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + + // Services for PDG and CCDB (Calibration and Condition Database) + Service pdgService; // Particle data group service + Service ccdb; // CCDB manager service + + // Random number generator for statistical fluctuations, initialized with seed 0 + TRandom3* fRndm = new TRandom3(0); + + // Registry for histograms used in analysis + HistogramRegistry histogramRegistry{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // ------------------- + // Configurable parameters + // ------------------- + // CCDB related configurations + 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 cfgUrlCCDB{"cfgUrlCCDB", "http://alice-ccdb.cern.ch", "url of ccdb"}; + Configurable cfgPathCCDB{"cfgPathCCDB", "Users/n/nimalik/netcharge/p/Run3/LHC24f3d", "Path for ccdb-object"}; + Configurable cfgLoadEff{"cfgLoadEff", true, "Load efficiency"}; + + // Track and event selection cuts + Configurable vertexZcut{"vertexZcut", 10.f, "Vertex Z"}; + Configurable etaCut{"etaCut", 0.8f, "Eta cut"}; + Configurable ptMinCut{"ptMinCut", 0.2, "Pt min cut"}; + Configurable ptMaxCut{"ptMaxCut", 5.0, "Pt max cut"}; + Configurable dcaXYCut{"dcaXYCut", 0.2, "DCA XY cut"}; + Configurable dcaZCut{"dcaZCut", 2.0, "DCA Z cut"}; + Configurable tpcCrossCut{"tpcCrossCut", 70., "TPC crossrows cut"}; + Configurable itsChiCut{"itsChiCut", 36., "ITS chi2 cluster cut"}; + Configurable tpcChiCut{"tpcChiCut", 4., "TPC chi2 cluster cut"}; + Configurable centMin{"centMin", 0.0f, "cenrality min for delta eta"}; + Configurable centMax{"centMax", 10.0f, "cenrality max for delta eta"}; + Configurable cfgNSubsample{"cfgNSubsample", 30, "Number of subsamples for Error"}; + Configurable deltaEta{"deltaEta", 8, "Delta eta bin count"}; + Configurable threshold{"threshold", 1e-6, "Delta eta bin count"}; + + // Event selections + Configurable cSel8Trig{"cSel8Trig", true, "Sel8 (T0A + T0C) Selection Run3"}; // sel8 + Configurable cInt7Trig{"cInt7Trig", true, "kINT7 MB Trigger"}; // kINT7 + Configurable cSel7Trig{"cSel7Trig", true, "Sel7 (V0A + V0C) Selection Run2"}; // sel7 + Configurable cDcaXy{"cDcaXy", true, "Dca XY cut"}; + Configurable cDcaZ{"cDcaZ", true, "Dca Z cut"}; + Configurable cTpcCr{"cTpcCr", true, "tpc crossrows"}; + Configurable cItsChi{"cItsChi", true, "ITS chi"}; + Configurable cTpcChi{"cTpcChi", true, "TPC chi"}; + Configurable cFT0C{"cFT0C", true, "cent FT0C"}; + Configurable cFT0M{"cFT0M", false, "cent FT0M"}; + + // Centrality binning configuration + ConfigurableAxis centBining{"centBining", {0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, "Centrality/Multiplicity percentile bining"}; + Configurable cPileupReject{"cPileupReject", false, "Pileup rejection"}; // pileup + Configurable cfgUseGoodItsLayerAllCut{"cfgUseGoodItsLayerAllCut", false, "Good ITS Layers All"}; // pileup + Configurable cTFBorder{"cTFBorder", false, "Timeframe Border Selection"}; // pileup + Configurable cNoItsROBorder{"cNoItsROBorder", false, "No ITSRO Border Cut"}; // pileup + Configurable cItsTpcVtx{"cItsTpcVtx", false, "ITS+TPC Vertex Selection"}; // pileup + Configurable cZVtxTimeDiff{"cZVtxTimeDiff", false, "z-vtx time diff selection"}; // pileup + Configurable cPVcont{"cPVcont", false, "primary vertex contributor"}; + + // Configurable to enable multiplicity correlation cuts + O2_DEFINE_CONFIGURABLE(cfgEvSelMultCorrelation, bool, true, "Multiplicity correlation cut") + + // Struct grouping multiplicity vs centrality/vertex cuts and related parameters + struct : ConfigurableGroup { + + // Flags to enable specific multiplicity correlation cuts + O2_DEFINE_CONFIGURABLE(cfgMultPVT0CCutEnabled, bool, true, "Enable PV multiplicity vs T0C centrality cut") + O2_DEFINE_CONFIGURABLE(cfgMultGlobalFT0CCutEnabled, bool, true, "Enable globalTracks vs FT0C multiplicity cut") + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCutEnabled, bool, true, "Enable globalTracks vs PV multiplicity cut") + + // Parameter values for PV multiplicity vs FT0C centrality cut (polynomial coefficients, etc.) + Configurable> cfgMultPVT0CCutPars{"cfgMultPVT0CCutPars", + std::vector{30.434, -0.917137, 0.0185032, -0.000198425, 7.94381e-07, 13.7406, -0.282656, 0.00556147, -6.32766e-05, 2.51648e-07}, + "PV multiplicity vs T0C centrality cut parameter values"}; + + // Parameter values for globalTracks vs FT0C multiplicity cut + Configurable> cfgMultGlobalFT0CCutPars{"cfgMultGlobalFT0CCutPars", + std::vector{18.9628, -0.576466, 0.0117324, -0.000126086, 5.05365e-07, 8.99921, -0.188022, 0.0037089, -4.20275e-05, 1.68234e-07}, + "globalTracks vs FT0C cut parameter values"}; + + // Parameter values for globalTracks vs PV multiplicity cut + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", + std::vector{0.148031, 0.616699, 0.603083, 0.112751, -0.0013846, 8.38211e-06}, + "globalTracks vs PV cut parameter values"}; + + // Local vectors to store the above parameters + std::vector multPVT0CCutPars; + std::vector multGlobalFT0CPars; + std::vector multGlobalPVCutPars; + + // TF1 objects to represent low/high cut functions for the above correlations + TF1* fMultPVT0CCutLow = nullptr; + TF1* fMultPVT0CCutHigh = nullptr; + TF1* fMultGlobalFT0CCutLow = nullptr; + TF1* fMultGlobalFT0CCutHigh = nullptr; + TF1* fMultGlobalPVCutLow = nullptr; + TF1* fMultGlobalPVCutHigh = nullptr; + + } cfgFunCoeff; + + // Histogram pointer for CCDB efficiency + TH1D* efficiency = nullptr; + + // Filters for selecting collisions and tracks + Filter collisionFilter = nabs(aod::collision::posZ) <= vertexZcut; + Filter trackFilter = (nabs(aod::track::eta) < etaCut) && (aod::track::pt > ptMinCut) && (aod::track::pt < ptMaxCut) && (requireGlobalTrackInFilter()); + + using MyCollisionsRun2 = soa::Filtered>; + using MyCollisionRun2 = MyCollisionsRun2::iterator; + + using MyCollisionsRun3 = soa::Filtered>; + using MyCollisionRun3 = MyCollisionsRun3::iterator; + + using MyTracks = soa::Filtered>; + using MyTrack = MyTracks::iterator; + + using MyMCCollisionsRun2 = soa::Filtered>; + using MyMCCollisionRun2 = MyMCCollisionsRun2::iterator; + + using MyMCCollisionsRun3 = soa::Filtered>; + using MyMCCollisionRun3 = MyMCCollisionsRun3::iterator; + + using MyMCTracks = soa::Filtered>; + using MyMCTrack = MyMCTracks::iterator; + + void init(o2::framework::InitContext&) + { + // ------------------------------- + // Define histogram axes specifications + // ------------------------------- + const AxisSpec vtxzAxis = {800, -20, 20, "V_{Z} (cm)"}; + const AxisSpec dcaAxis = {1000, -0.5, 0.5, "DCA_{xy} (cm)"}; + const AxisSpec dcazAxis = {600, -3, 3, "DCA_{z} (cm)"}; + const AxisSpec phiAxis = {70, 0, 7, "#phi "}; + const AxisSpec ptAxis = {70, 0.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec etaAxis = {20, -1., 1., "#eta"}; + const AxisSpec deltaEtaAxis = {9, 0, 1.8, "#eta"}; + const AxisSpec centAxis = {100, 0., 100., "centrality"}; + const AxisSpec multAxis = {100000, 0., 100000., "FT0M Amplitude"}; + const AxisSpec tpcChiAxis = {700, 0., 7., "Chi2"}; + const AxisSpec itsChiAxis = {400, 0., 40., "Chi2"}; + const AxisSpec crossedRowAxis = {1600, 0., 160., "TPC Crossed rows"}; + const AxisSpec eventsAxis = {10, 0, 10, ""}; + const AxisSpec signAxis = {20, -10, 10, ""}; + const AxisSpec nchAxis = {5000, 0, 5000, "Nch"}; + const AxisSpec nch1Axis = {1500, 0, 1500, "Nch"}; + const AxisSpec nchpAxis = {50000, 0, 50000, "Nch"}; + const AxisSpec cent1Axis{centBining, "Multiplicity percentile from FT0M (%)"}; + + // Subsample axis (used for error estimation from subsamples) + auto noSubsample = static_cast(cfgNSubsample); + float maxSubsample = 1.0 * noSubsample; + AxisSpec subsampleAxis = {noSubsample, 0.0, maxSubsample, "subsample no."}; + + // Add QA histograms + histogramRegistry.add("QA/hVtxZ_before", "", kTH1F, {vtxzAxis}); + histogramRegistry.add("QA/hDcaXY_before", "", kTH1F, {dcaAxis}); + histogramRegistry.add("QA/hphi", "", kTH1F, {phiAxis}); + histogramRegistry.add("QA/hDcaZ_before", "", kTH1F, {dcazAxis}); + histogramRegistry.add("QA/hTPCchi2perCluster_before", "", kTH1D, {tpcChiAxis}); + histogramRegistry.add("QA/hITSchi2perCluster_before", "", kTH1D, {itsChiAxis}); + histogramRegistry.add("QA/hTPCCrossedrows_before", "", kTH1D, {crossedRowAxis}); + histogramRegistry.add("QA/hPtDcaXY_before", "", kTH2D, {ptAxis, dcaAxis}); + histogramRegistry.add("QA/hPtDcaZ_before", "", kTH2D, {ptAxis, dcazAxis}); + histogramRegistry.add("QA/hVtxZ_after", "", kTH1F, {vtxzAxis}); + histogramRegistry.add("QA/hDcaXY_after", "", kTH1F, {dcaAxis}); + histogramRegistry.add("QA/hDcaZ_after", "", kTH1F, {dcazAxis}); + histogramRegistry.add("QA/hTPCchi2perCluster_after", "", kTH1D, {tpcChiAxis}); + histogramRegistry.add("QA/hITSchi2perCluster_after", "", kTH1D, {itsChiAxis}); + histogramRegistry.add("QA/hTPCCrossedrows_after", "", kTH1D, {crossedRowAxis}); + histogramRegistry.add("QA/hPtDcaXY_after", "", kTH2D, {ptAxis, dcaAxis}); + histogramRegistry.add("QA/hPtDcaZ_after", "", kTH2D, {ptAxis, dcazAxis}); + histogramRegistry.add("QA/hEta", "", kTH1F, {etaAxis}); + histogramRegistry.add("QA/cent_hEta", "", kTH2F, {cent1Axis, etaAxis}); + histogramRegistry.add("QA/hPt", "", kTH1F, {ptAxis}); + histogramRegistry.add("QA/cent_hPt", "", kTH2F, {cent1Axis, ptAxis}); + histogramRegistry.add("QA/hPt_eta", "", kTH2F, {ptAxis, etaAxis}); + histogramRegistry.add("QA/hCentrality", "", kTH1F, {centAxis}); + histogramRegistry.add("QA/hMultiplicity", "", kTH1F, {multAxis}); + + histogramRegistry.add("gen/hVtxZ_before", "", kTH1F, {vtxzAxis}); + histogramRegistry.add("gen/hVtxZ_after", "", kTH1F, {vtxzAxis}); + histogramRegistry.add("gen/hPt", "", kTH1F, {ptAxis}); + histogramRegistry.add("gen/cent_hPt", "", kTH2F, {centAxis, ptAxis}); + histogramRegistry.add("gen/hEta", "", kTH1F, {etaAxis}); + histogramRegistry.add("gen/cent_hEta", "", kTH2F, {centAxis, etaAxis}); + histogramRegistry.add("gen/hSign", "", kTH1F, {signAxis}); + histogramRegistry.add("gen/hPt_eta", "", kTH2F, {ptAxis, etaAxis}); + histogramRegistry.add("gen/cent_pos", "cent vs fpos", kTProfile, {cent1Axis}); + histogramRegistry.add("gen/cent_neg", "cent vs fneg", kTProfile, {cent1Axis}); + histogramRegistry.add("gen/cent_termp", "cent vs termp", kTProfile, {cent1Axis}); + histogramRegistry.add("gen/cent_termn", "cent vs termn", kTProfile, {cent1Axis}); + histogramRegistry.add("gen/cent_pos_sq", "cent vs sqfpos", kTProfile, {cent1Axis}); + histogramRegistry.add("gen/cent_neg_sq", "cent vs sqfneg", kTProfile, {cent1Axis}); + histogramRegistry.add("gen/cent_posneg", "cent vs fpos*fneg", kTProfile, {cent1Axis}); + histogramRegistry.add("gen/cent_nch", "cent vs nch", kTProfile, {cent1Axis}); + histogramRegistry.add("gen/nch", "", kTH1F, {nchAxis}); + histogramRegistry.add("gen/delta_eta_eta", "delta_eta ", kTH1F, {etaAxis}); + histogramRegistry.add("gen/delta_eta_pos", "delta_eta vs fpos ", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("gen/delta_eta_neg", "delta_eta vs fneg ", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("gen/delta_eta_termp", "delta_eta vs termp ", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("gen/delta_eta_termn", "delta_eta vs termn ", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("gen/delta_eta_pos_sq", "delta_eta vs pos_sq ", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("gen/delta_eta_neg_sq", "delta_eta vs neg_sq ", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("gen/delta_eta_posneg", "delta_eta vs posneg ", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("gen/delta_eta_nch", "delta_eta vs nchGen ", kTProfile, {deltaEtaAxis}); + + histogramRegistry.add("data/nch", "", kTH1D, {nchAxis}); + histogramRegistry.add("data/cent_nch", "", kTProfile, {cent1Axis}); + histogramRegistry.add("data/nch_pos", "", kTH1D, {nchAxis}); + histogramRegistry.add("data/cent_nch_pos", "", kTH2D, {centAxis, nchAxis}); + histogramRegistry.add("data/nch_neg", "", kTH1D, {nchAxis}); + histogramRegistry.add("data/cent_nch_neg", "", kTH2D, {centAxis, nchAxis}); + histogramRegistry.add("data/nch_negpos", "", kTH1D, {nchpAxis}); + histogramRegistry.add("data/cent_nch_negpos", "", kTH2D, {centAxis, nchpAxis}); + histogramRegistry.add("data/cent_pos", "cent vs fpos", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_neg", "cent vs fneg", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_termp", "cent vs termp", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_termn", "cent vs termn", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_pos_sq", "cent vs sqfpos", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_neg_sq", "cent vs sqfneg", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_posneg", "cent vs fpos*fneg", kTProfile, {cent1Axis}); + histogramRegistry.add("data/hPt_cor", "", kTH1F, {ptAxis}); + histogramRegistry.add("data/hEta_cor", "", kTH1F, {etaAxis}); + histogramRegistry.add("data/cent_nchTotal", "cent vs nchTotal", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_nchTotalCor", "cent vs nchTotalCor", kTProfile, {cent1Axis}); + histogramRegistry.add("data/nch_nchCor", "", kTProfile, {nchAxis}); + histogramRegistry.add("data/nchCor", "", kTH1F, {nchAxis}); + histogramRegistry.add("data/cent_nchCor", "", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_pos_cor", "", kTProfile, {cent1Axis}); + histogramRegistry.add("data/cent_neg_cor", "", kTProfile, {cent1Axis}); + histogramRegistry.add("data/delta_eta_cent", "Centrality", kTH1F, {cent1Axis}); + histogramRegistry.add("data/delta_eta_eta", "eta", kTH1F, {etaAxis}); + histogramRegistry.add("data/delta_eta_nchTotal", "delta_eta vs nchTotal", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_nch", "delta_eta vs nch", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_nchCor", "delta_eta vs nchCor", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_pos", "delta_eta vs fpos", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_neg", "delta_eta vs fneg", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_termp", "delta_eta vs termp", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_termn", "delta_eta vs termn", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_pos_sq", "delta_eta vs sqfpos", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_neg_sq", "delta_eta vs sqfneg", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_posneg", "delta_eta vs fpos*fneg", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_pos_cor", "delta_eta vs fpos_cor", kTProfile, {deltaEtaAxis}); + histogramRegistry.add("data/delta_eta_neg_cor", "delta_eta vs fneg_cor", kTProfile, {deltaEtaAxis}); + + histogramRegistry.add("subsample/pos", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/neg", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/termp", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/termn", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/pos_sq", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/neg_sq", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/posneg", "", kTProfile2D, {cent1Axis, subsampleAxis}); + + histogramRegistry.add("subsample/gen/pos", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/gen/neg", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/gen/termp", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/gen/termn", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/gen/pos_sq", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/gen/neg_sq", "", kTProfile2D, {cent1Axis, subsampleAxis}); + histogramRegistry.add("subsample/gen/posneg", "", kTProfile2D, {cent1Axis, subsampleAxis}); + + histogramRegistry.add("subsample/delta_eta/pos", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/neg", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/termp", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/termn", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/pos_sq", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/neg_sq", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/posneg", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + + histogramRegistry.add("subsample/delta_eta/gen/pos", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/gen/neg", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/gen/termp", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/gen/termn", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/gen/pos_sq", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/gen/neg_sq", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + histogramRegistry.add("subsample/delta_eta/gen/posneg", "", kTProfile2D, {deltaEtaAxis, subsampleAxis}); + + histogramRegistry.add("QA/hCentFT0C", "", kTH1F, {centAxis}); + histogramRegistry.add("QA/hNchGlobal", "", kTH1F, {nchAxis}); + histogramRegistry.add("QA/hNchPV", "", kTH1F, {nchAxis}); + + // QA histograms for multiplicity correlations + histogramRegistry.add("MultCorrelationPlots/globalTracks_PV_bef", "", {HistType::kTH2D, {nchAxis, nchAxis}}); + histogramRegistry.add("MultCorrelationPlots/globalTracks_FT0C_bef", "", {HistType::kTH2D, {centAxis, nchAxis}}); + histogramRegistry.add("MultCorrelationPlots/PV_FT0C_bef", "", {HistType::kTH2D, {centAxis, nchAxis}}); + + histogramRegistry.add("MultCorrelationPlots/globalTracks_PV_aft", "", {HistType::kTH2D, {nchAxis, nchAxis}}); + histogramRegistry.add("MultCorrelationPlots/globalTracks_FT0C_aft", "", {HistType::kTH2D, {centAxis, nchAxis}}); + histogramRegistry.add("MultCorrelationPlots/PV_FT0C_aft", "", {HistType::kTH2D, {centAxis, nchAxis}}); + + cfgFunCoeff.multPVT0CCutPars = cfgFunCoeff.cfgMultPVT0CCutPars; + cfgFunCoeff.multGlobalFT0CPars = cfgFunCoeff.cfgMultGlobalFT0CCutPars; + cfgFunCoeff.multGlobalPVCutPars = cfgFunCoeff.cfgMultGlobalPVCutPars; + + // --- Initialize PV vs FT0C multiplicity cut functions --- + // Lower cut function: 4th-order polynomial minus 3.5 sigma deviation + + cfgFunCoeff.fMultPVT0CCutLow = + new TF1("fMultPVT0CCutLow", + "[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); + cfgFunCoeff.fMultPVT0CCutLow->SetParameters(&(cfgFunCoeff.multPVT0CCutPars[0])); + + // Upper cut function: 4th-order polynomial plus 3.5 sigma deviation + cfgFunCoeff.fMultPVT0CCutHigh = + new TF1("fMultPVT0CCutHigh", + "[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); + cfgFunCoeff.fMultPVT0CCutHigh->SetParameters(&(cfgFunCoeff.multPVT0CCutPars[0])); + + // --- Initialize globalTracks vs FT0C multiplicity cut functions --- + // Lower cut function + cfgFunCoeff.fMultGlobalFT0CCutLow = + new TF1("fMultGlobalFT0CCutLow", + "[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); + cfgFunCoeff.fMultGlobalFT0CCutLow->SetParameters(&(cfgFunCoeff.multGlobalFT0CPars[0])); + + // Upper cut function + cfgFunCoeff.fMultGlobalFT0CCutHigh = + new TF1("fMultGlobalFT0CCutHigh", + "[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); + cfgFunCoeff.fMultGlobalFT0CCutHigh->SetParameters(&(cfgFunCoeff.multGlobalFT0CPars[0])); + + // --- Initialize globalTracks vs PV multiplicity cut functions --- + // Lower cut: linear + cubic term minus 3.5 sigma + + cfgFunCoeff.fMultGlobalPVCutLow = + new TF1("fMultGlobalPVCutLow", + "[0]+[1]*x - 3.5*([2]+[3]*x+[4]*x*x+[5]*x*x*x)", + 0, 100); + cfgFunCoeff.fMultGlobalPVCutLow->SetParameters(&(cfgFunCoeff.multGlobalPVCutPars[0])); + + // Upper cut: linear + cubic term plus 3.5 sigma + cfgFunCoeff.fMultGlobalPVCutHigh = + new TF1("fMultGlobalPVCutHigh", + "[0]+[1]*x + 3.5*([2]+[3]*x+[4]*x*x+[5]*x*x*x)", + 0, 100); + cfgFunCoeff.fMultGlobalPVCutHigh->SetParameters(&(cfgFunCoeff.multGlobalPVCutPars[0])); + + // --- Load efficiency histogram from CCDB + if (cfgLoadEff) { + ccdb->setURL(cfgUrlCCDB.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + TList* list = ccdb->getForTimeStamp(cfgPathCCDB.value, -1); + efficiency = reinterpret_cast(list->FindObject("efficiency_Run3")); + // Log fatal error if efficiency histogram is not found + if (!efficiency) { + LOGF(info, "FATAL!! Could not find required histograms in CCDB"); + } + } + } + + bool eventSelected(const float& globalNch, const float& pvTrack, const float& centrality) + { + if (cfgFunCoeff.cfgMultPVT0CCutEnabled) { + + if (pvTrack < cfgFunCoeff.fMultPVT0CCutLow->Eval(centrality)) + return false; + if (pvTrack > cfgFunCoeff.fMultPVT0CCutHigh->Eval(centrality)) + return false; + } + + if (cfgFunCoeff.cfgMultGlobalFT0CCutEnabled) { + + if (globalNch < cfgFunCoeff.fMultGlobalFT0CCutLow->Eval(centrality)) + return false; + if (globalNch > cfgFunCoeff.fMultGlobalFT0CCutHigh->Eval(centrality)) + return false; + } + + if (cfgFunCoeff.cfgMultGlobalPVCutEnabled) { + + if (globalNch < cfgFunCoeff.fMultGlobalPVCutLow->Eval(pvTrack)) + return false; + if (globalNch > cfgFunCoeff.fMultGlobalPVCutHigh->Eval(pvTrack)) + return false; + } + + return true; + } + + template + bool selCollision(C const& coll, float& cent, float& mult) + { + + if (std::abs(coll.posZ()) >= vertexZcut) + return false; + if constexpr (run == kRun3) { + if (cSel8Trig && !coll.sel8()) { + return false; + } + if (cFT0M) { + cent = coll.centFT0M(); // centrality for run3 using FT0M + mult = coll.multFT0M(); + } else if (cFT0C) { + cent = coll.centFT0C(); // centrality for run3 using FT0C + mult = coll.multFT0C(); + } + + } else if constexpr (run == kRun2) { + if (cInt7Trig && !coll.alias_bit(kINT7)) { + return false; + } + if (cSel7Trig && !coll.sel7()) { + return false; + } + cent = coll.centRun2V0M(); // centrality for run2 + mult = coll.multFV0M(); // multiplicity for run2 + } + + if (cNoItsROBorder && !coll.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (cTFBorder && !coll.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + if (cPileupReject && !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + if (cZVtxTimeDiff && !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (cItsTpcVtx && !coll.selection_bit(aod::evsel::kIsVertexITSTPC)) + return false; + if (cfgUseGoodItsLayerAllCut && !(coll.selection_bit(aod::evsel::kIsGoodITSLayersAll))) + return false; + + return true; + } + + template + void fillBeforeQA(T const& track) + { + histogramRegistry.fill(HIST("QA/hTPCchi2perCluster_before"), track.tpcChi2NCl()); + histogramRegistry.fill(HIST("QA/hITSchi2perCluster_before"), track.itsChi2NCl()); + histogramRegistry.fill(HIST("QA/hTPCCrossedrows_before"), track.tpcNClsCrossedRows()); + histogramRegistry.fill(HIST("QA/hDcaXY_before"), track.dcaXY()); + histogramRegistry.fill(HIST("QA/hDcaZ_before"), track.dcaZ()); + histogramRegistry.fill(HIST("QA/hPtDcaXY_before"), track.pt(), track.dcaXY()); + histogramRegistry.fill(HIST("QA/hPtDcaZ_before"), track.pt(), track.dcaZ()); + } + + template + void fillAfterQA(T const& track) + { + histogramRegistry.fill(HIST("QA/hphi"), track.phi()); + histogramRegistry.fill(HIST("QA/hDcaXY_after"), track.dcaXY()); + histogramRegistry.fill(HIST("QA/hDcaZ_after"), track.dcaZ()); + histogramRegistry.fill(HIST("QA/hPt"), track.pt()); + histogramRegistry.fill(HIST("QA/hEta"), track.eta()); + histogramRegistry.fill(HIST("QA/hPt_eta"), track.pt(), track.eta()); + histogramRegistry.fill(HIST("QA/hPtDcaXY_after"), track.pt(), track.dcaXY()); + histogramRegistry.fill(HIST("QA/hPtDcaZ_after"), track.pt(), track.dcaZ()); + histogramRegistry.fill(HIST("QA/hTPCCrossedrows_after"), track.tpcNClsCrossedRows()); + histogramRegistry.fill(HIST("QA/hTPCchi2perCluster_after"), track.tpcChi2NCl()); + histogramRegistry.fill(HIST("QA/hITSchi2perCluster_after"), track.itsChi2NCl()); + } + + template + bool selTrack(T const& track) + { + if (!track.isGlobalTrack()) + return false; + if (cPVcont && !track.isPVContributor()) + return false; + if (std::fabs(track.eta()) >= etaCut) + return false; + if (track.pt() <= ptMinCut || track.pt() >= ptMaxCut) + return false; + if (track.sign() == 0) + return false; + if (cDcaXy && std::fabs(track.dcaXY()) >= dcaXYCut) + return false; + if (cDcaZ && std::fabs(track.dcaZ()) >= dcaZCut) + return false; + if (cTpcCr && track.tpcNClsCrossedRows() <= tpcCrossCut) + return false; + if (cItsChi && track.itsChi2NCl() >= itsChiCut) + return false; + if (cTpcChi && track.tpcChi2NCl() >= tpcChiCut) + return false; + + return true; + } + + double getEfficiency(float pt, TH1D* hEff) + { + if (!hEff) { + return 1e-6; + } + int bin = hEff->GetXaxis()->FindBin(pt); + if (bin < 1 || bin > hEff->GetNbinsX()) { + return 1e-6; + } + double eff = hEff->GetBinContent(bin); + return eff; + } + + void fillHistograms(float nch, float cent, float fpos, float fneg, float posneg, float termp, float termn) + { + histogramRegistry.fill(HIST("data/nch"), nch); + histogramRegistry.fill(HIST("data/cent_nch"), cent, nch); + histogramRegistry.fill(HIST("data/nch_pos"), fpos); + histogramRegistry.fill(HIST("data/cent_nch_pos"), cent, fpos); + histogramRegistry.fill(HIST("data/nch_neg"), fneg); + histogramRegistry.fill(HIST("data/cent_nch_neg"), cent, fneg); + histogramRegistry.fill(HIST("data/nch_negpos"), posneg); + histogramRegistry.fill(HIST("data/cent_nch_negpos"), cent, posneg); + + histogramRegistry.fill(HIST("data/cent_pos"), cent, fpos); + histogramRegistry.fill(HIST("data/cent_neg"), cent, fneg); + histogramRegistry.fill(HIST("data/cent_termp"), cent, termp); + histogramRegistry.fill(HIST("data/cent_termn"), cent, termn); + histogramRegistry.fill(HIST("data/cent_pos_sq"), cent, fpos * fpos); + histogramRegistry.fill(HIST("data/cent_neg_sq"), cent, fneg * fneg); + histogramRegistry.fill(HIST("data/cent_posneg"), cent, posneg); + + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histogramRegistry.fill(HIST("subsample/pos"), cent, sampleIndex, fpos); + histogramRegistry.fill(HIST("subsample/neg"), cent, sampleIndex, fneg); + histogramRegistry.fill(HIST("subsample/termp"), cent, sampleIndex, termp); + histogramRegistry.fill(HIST("subsample/termn"), cent, sampleIndex, termn); + histogramRegistry.fill(HIST("subsample/pos_sq"), cent, sampleIndex, fpos * fpos); + histogramRegistry.fill(HIST("subsample/neg_sq"), cent, sampleIndex, fneg * fneg); + histogramRegistry.fill(HIST("subsample/posneg"), cent, sampleIndex, posneg); + } + + template + void calculationData(C const& coll, T const& tracks) + { + float cent = -1, mult = -1; + histogramRegistry.fill(HIST("QA/hVtxZ_before"), coll.posZ()); + if (!selCollision(coll, cent, mult)) { + return; + } + + float globalNch = tracks.size(); + float pvTrack = coll.multNTracksPV(); + + histogramRegistry.fill(HIST("QA/hCentFT0C"), cent); + histogramRegistry.fill(HIST("QA/hNchGlobal"), globalNch); + histogramRegistry.fill(HIST("QA/hNchPV"), pvTrack); + + histogramRegistry.fill(HIST("MultCorrelationPlots/globalTracks_PV_bef"), pvTrack, globalNch); + histogramRegistry.fill(HIST("MultCorrelationPlots/globalTracks_FT0C_bef"), cent, globalNch); + histogramRegistry.fill(HIST("MultCorrelationPlots/PV_FT0C_bef"), cent, pvTrack); + + if (cfgEvSelMultCorrelation && !eventSelected(globalNch, pvTrack, cent)) { + return; + } + histogramRegistry.fill(HIST("MultCorrelationPlots/globalTracks_PV_aft"), pvTrack, globalNch); + histogramRegistry.fill(HIST("MultCorrelationPlots/globalTracks_FT0C_aft"), cent, globalNch); + histogramRegistry.fill(HIST("MultCorrelationPlots/PV_FT0C_aft"), cent, pvTrack); + histogramRegistry.fill(HIST("QA/hVtxZ_after"), coll.posZ()); + histogramRegistry.fill(HIST("QA/hCentrality"), cent); + histogramRegistry.fill(HIST("QA/hMultiplicity"), mult); + + int fpos = 0, fneg = 0, posneg = 0, termn = 0, termp = 0; + int nch = 0, nchTotal = 0; + double posWeight = 0, negWeight = 0, nchCor = 0, nchTotalCor = 0; + for (const auto& track : tracks) { + + double eff = getEfficiency(track.pt(), efficiency); + if (eff < threshold) + continue; + double weight = 1.0 / eff; + + fillBeforeQA(track); + nchTotal += 1; + nchTotalCor += weight; + if (!selTrack(track)) + continue; + nch += 1; + fillAfterQA(track); + histogramRegistry.fill(HIST("QA/cent_hEta"), cent, track.eta()); + histogramRegistry.fill(HIST("QA/cent_hPt"), cent, track.pt()); + histogramRegistry.fill(HIST("data/hPt_cor"), track.pt(), weight); + histogramRegistry.fill(HIST("data/hEta_cor"), track.eta(), weight); + + nchCor += weight; + if (track.sign() == 1) { + fpos += 1; + posWeight += weight; + } else if (track.sign() == -1) { + fneg += 1; + negWeight += weight; + } + + } // track + termp = fpos * (fpos - 1); + termn = fneg * (fneg - 1); + posneg = fpos * fneg; + + histogramRegistry.fill(HIST("data/cent_nchTotal"), cent, nchTotal); + histogramRegistry.fill(HIST("data/cent_nchTotalCor"), cent, nchTotalCor); + histogramRegistry.fill(HIST("data/nch_nchCor"), nch, nchCor); + histogramRegistry.fill(HIST("data/nchCor"), nchCor); + histogramRegistry.fill(HIST("data/cent_nchCor"), cent, nchCor); + histogramRegistry.fill(HIST("data/cent_pos_cor"), cent, posWeight); + histogramRegistry.fill(HIST("data/cent_neg_cor"), cent, negWeight); + fillHistograms(nch, cent, fpos, fneg, posneg, termp, termn); + } + + template + void calculationMc(C const& coll, T const& inputTracks, M const& mcCollisions, P const& mcParticles) + { + (void)mcCollisions; + if (!coll.has_mcCollision()) { + return; + } + histogramRegistry.fill(HIST("gen/hVtxZ_before"), coll.mcCollision().posZ()); + float cent = -1, mult = -1; + histogramRegistry.fill(HIST("QA/hVtxZ_before"), coll.posZ()); + if (!selCollision(coll, cent, mult)) { + return; + } + + int globalNch = inputTracks.size(); + int pvTrack = coll.multNTracksPV(); + + histogramRegistry.fill(HIST("QA/hCentFT0C"), cent); + histogramRegistry.fill(HIST("QA/hNchGlobal"), globalNch); + histogramRegistry.fill(HIST("QA/hNchPV"), pvTrack); + + histogramRegistry.fill(HIST("MultCorrelationPlots/globalTracks_PV_bef"), pvTrack, globalNch); + histogramRegistry.fill(HIST("MultCorrelationPlots/globalTracks_FT0C_bef"), cent, globalNch); + histogramRegistry.fill(HIST("MultCorrelationPlots/PV_FT0C_bef"), cent, pvTrack); + + if (cfgEvSelMultCorrelation && !eventSelected(globalNch, pvTrack, cent)) { + return; + } + histogramRegistry.fill(HIST("MultCorrelationPlots/globalTracks_PV_aft"), pvTrack, globalNch); + histogramRegistry.fill(HIST("MultCorrelationPlots/globalTracks_FT0C_aft"), cent, globalNch); + histogramRegistry.fill(HIST("MultCorrelationPlots/PV_FT0C_aft"), cent, pvTrack); + + histogramRegistry.fill(HIST("QA/hVtxZ_after"), coll.posZ()); + histogramRegistry.fill(HIST("QA/hCentrality"), cent); + histogramRegistry.fill(HIST("QA/hMultiplicity"), mult); + + int fpos = 0, fneg = 0, posneg = 0, termn = 0, termp = 0; + int nch = 0, nchCor = 0; + double posRecWeight = 0, negRecWeight = 0; + + for (const auto& track : inputTracks) { + fillBeforeQA(track); + if (!selTrack(track)) + continue; + nch += 1; + fillAfterQA(track); + histogramRegistry.fill(HIST("QA/cent_hEta"), cent, track.eta()); + histogramRegistry.fill(HIST("QA/cent_hPt"), cent, track.pt()); + + double eff = getEfficiency(track.pt(), efficiency); + if (eff < threshold) + continue; + double weight = 1.0 / eff; + histogramRegistry.fill(HIST("data/hPt_cor"), track.pt(), weight); + histogramRegistry.fill(HIST("data/hEta_cor"), track.eta(), weight); + + if (track.sign() == 1) { + fpos += 1; + posRecWeight += weight; + } else if (track.sign() == -1) { + fneg += 1; + negRecWeight += weight; + } + nchCor = posRecWeight + negRecWeight; + } // track + termp = fpos * (fpos - 1); + termn = fneg * (fneg - 1); + posneg = fpos * fneg; + histogramRegistry.fill(HIST("data/nch_nchCor"), nch, nchCor); + histogramRegistry.fill(HIST("data/nchCor"), nchCor); + histogramRegistry.fill(HIST("data/cent_nchCor"), cent, nchCor); + histogramRegistry.fill(HIST("data/cent_pos_cor"), cent, posRecWeight); + histogramRegistry.fill(HIST("data/cent_neg_cor"), cent, negRecWeight); + + fillHistograms(nch, cent, fpos, fneg, posneg, termp, termn); + + int posGen = 0, negGen = 0, posNegGen = 0, termNGen = 0, termPGen = 0, nchGen = 0; + + const auto& mccolgen = coll.template mcCollision_as(); + if (std::abs(mccolgen.posZ()) >= vertexZcut) + return; + const auto& mcpartgen = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolgen.globalIndex(), cache); + histogramRegistry.fill(HIST("gen/hVtxZ_after"), mccolgen.posZ()); + for (const auto& mcpart : mcpartgen) { + if (std::fabs(mcpart.eta()) >= etaCut) + continue; + if (!mcpart.isPhysicalPrimary()) + continue; + int pid = mcpart.pdgCode(); + auto sign = 0; + auto* pd = pdgService->GetParticle(pid); + if (pd != nullptr) { + sign = pd->Charge() / 3.; + } + if (sign == 0) + 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()) >= etaCut) + continue; + if ((mcpart.pt() <= ptMinCut) || (mcpart.pt() >= ptMaxCut)) + continue; + histogramRegistry.fill(HIST("gen/hPt"), mcpart.pt()); + histogramRegistry.fill(HIST("gen/cent_hPt"), cent, mcpart.pt()); + histogramRegistry.fill(HIST("gen/hEta"), mcpart.eta()); + histogramRegistry.fill(HIST("gen/cent_hEta"), cent, mcpart.eta()); + histogramRegistry.fill(HIST("gen/hSign"), sign); + histogramRegistry.fill(HIST("gen/hPt_eta"), mcpart.pt(), mcpart.eta()); + nchGen += 1; + if (sign == 1) { + posGen += 1; + } + if (sign == -1) { + negGen += 1; + } + } + termPGen = posGen * (posGen - 1); + termNGen = negGen * (negGen - 1); + posNegGen = posGen * negGen; + histogramRegistry.fill(HIST("gen/cent_pos"), cent, posGen); + histogramRegistry.fill(HIST("gen/cent_neg"), cent, negGen); + histogramRegistry.fill(HIST("gen/cent_termp"), cent, termPGen); + histogramRegistry.fill(HIST("gen/cent_termn"), cent, termNGen); + histogramRegistry.fill(HIST("gen/cent_pos_sq"), cent, posGen * posGen); + histogramRegistry.fill(HIST("gen/cent_neg_sq"), cent, negGen * negGen); + histogramRegistry.fill(HIST("gen/cent_posneg"), cent, posNegGen); + histogramRegistry.fill(HIST("gen/cent_nch"), cent, nchGen); + histogramRegistry.fill(HIST("gen/nch"), nchGen); + + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histogramRegistry.fill(HIST("subsample/gen/pos"), cent, sampleIndex, posGen); + histogramRegistry.fill(HIST("subsample/gen/neg"), cent, sampleIndex, negGen); + histogramRegistry.fill(HIST("subsample/gen/termp"), cent, sampleIndex, termPGen); + histogramRegistry.fill(HIST("subsample/gen/termn"), cent, sampleIndex, termNGen); + histogramRegistry.fill(HIST("subsample/gen/pos_sq"), cent, sampleIndex, posGen * posGen); + histogramRegistry.fill(HIST("subsample/gen/neg_sq"), cent, sampleIndex, negGen * negGen); + histogramRegistry.fill(HIST("subsample/gen/posneg"), cent, sampleIndex, posNegGen); + + } // void + + template + void calculationDeltaEta(C const& coll, T const& tracks, float deta1, float deta2) + { + float cent = -1, mult = -1; + if (!selCollision(coll, cent, mult)) + return; + + int globalNch = tracks.size(); + int pvTrack = coll.multNTracksPV(); + if (cfgEvSelMultCorrelation && !eventSelected(globalNch, pvTrack, cent)) + return; + + if (!(cent >= centMin && cent < centMax)) + return; + histogramRegistry.fill(HIST("data/delta_eta_cent"), cent); + + int fpos = 0, fneg = 0, posneg = 0, termn = 0, termp = 0, nch = 0, nchTotal = 0; + double nchCor = 0, posWeight = 0, negWeight = 0; + for (const auto& track : tracks) { + nchTotal += 1; + if (!selTrack(track)) + continue; + nch += 1; + double eff = getEfficiency(track.pt(), efficiency); + if (eff < threshold) + continue; + double weight = 1.0 / eff; + nchCor += weight; + double eta = track.eta(); + if (eta < deta1 || eta > deta2) + continue; + + histogramRegistry.fill(HIST("data/delta_eta_eta"), eta); + + if (track.sign() == 1) { + fpos++; + posWeight += weight; + } else if (track.sign() == -1) { + fneg++; + negWeight += weight; + } + } + termp = fpos * (fpos - 1); + termn = fneg * (fneg - 1); + posneg = fpos * fneg; + + float deltaEtaWidth = deta2 - deta1 + 1e-5f; + + histogramRegistry.fill(HIST("data/delta_eta_nchTotal"), deltaEtaWidth, nchTotal); + histogramRegistry.fill(HIST("data/delta_eta_nch"), deltaEtaWidth, nch); + histogramRegistry.fill(HIST("data/delta_eta_nchCor"), deltaEtaWidth, nchCor); + histogramRegistry.fill(HIST("data/delta_eta_pos"), deltaEtaWidth, fpos); + histogramRegistry.fill(HIST("data/delta_eta_pos_cor"), deltaEtaWidth, posWeight); + histogramRegistry.fill(HIST("data/delta_eta_neg"), deltaEtaWidth, fneg); + histogramRegistry.fill(HIST("data/delta_eta_neg_cor"), deltaEtaWidth, negWeight); + histogramRegistry.fill(HIST("data/delta_eta_termp"), deltaEtaWidth, termp); + histogramRegistry.fill(HIST("data/delta_eta_termn"), deltaEtaWidth, termn); + histogramRegistry.fill(HIST("data/delta_eta_pos_sq"), deltaEtaWidth, fpos * fpos); + histogramRegistry.fill(HIST("data/delta_eta_neg_sq"), deltaEtaWidth, fneg * fneg); + histogramRegistry.fill(HIST("data/delta_eta_posneg"), deltaEtaWidth, posneg); + + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histogramRegistry.fill(HIST("subsample/delta_eta/pos"), deltaEtaWidth, sampleIndex, fpos); + histogramRegistry.fill(HIST("subsample/delta_eta/neg"), deltaEtaWidth, sampleIndex, fneg); + histogramRegistry.fill(HIST("subsample/delta_eta/termp"), deltaEtaWidth, sampleIndex, termp); + histogramRegistry.fill(HIST("subsample/delta_eta/termn"), deltaEtaWidth, sampleIndex, termn); + histogramRegistry.fill(HIST("subsample/delta_eta/pos_sq"), deltaEtaWidth, sampleIndex, fpos * fpos); + histogramRegistry.fill(HIST("subsample/delta_eta/neg_sq"), deltaEtaWidth, sampleIndex, fneg * fneg); + histogramRegistry.fill(HIST("subsample/delta_eta/posneg"), deltaEtaWidth, sampleIndex, posneg); + } + + template + void calculationMcDeltaEta(C const& coll, T const& inputTracks, M const& mcCollisions, P const& mcParticles, float deta1, float deta2) + { + (void)mcCollisions; + + if (!coll.has_mcCollision()) + return; + + float cent = -1, mult = -1; + if (!selCollision(coll, cent, mult)) + return; + + int globalNch = inputTracks.size(); + int pvTrack = coll.multNTracksPV(); + if (cfgEvSelMultCorrelation && !eventSelected(globalNch, pvTrack, cent)) + return; + + if (!(cent >= centMin && cent < centMax)) + return; + histogramRegistry.fill(HIST("data/delta_eta_cent"), cent); + + float deltaEtaWidth = deta2 - deta1 + 1e-5f; + + int fpos = 0, fneg = 0, posneg = 0, termn = 0, termp = 0; + int nch = 0, nchTotal = 0; + double nchCor = 0, posRecWeight = 0, negRecWeight = 0; + + for (const auto& track : inputTracks) { + nchTotal += 1; + if (!selTrack(track)) + continue; + double eta = track.eta(); + if (eta < deta1 || eta > deta2) + continue; + + histogramRegistry.fill(HIST("data/delta_eta_eta"), eta); + double eff = getEfficiency(track.pt(), efficiency); + if (eff < threshold) + continue; + double weight = 1.0 / eff; + nch += 1; + nchCor += weight; + if (track.sign() == 1) { + fpos += 1; + posRecWeight += weight; + } else if (track.sign() == -1) { + fneg += 1; + negRecWeight += weight; + } + } // tracks + + termp = fpos * (fpos - 1); + termn = fneg * (fneg - 1); + posneg = fpos * fneg; + + histogramRegistry.fill(HIST("data/delta_eta_nchTotal"), deltaEtaWidth, nchTotal); + histogramRegistry.fill(HIST("data/delta_eta_nch"), deltaEtaWidth, nch); + histogramRegistry.fill(HIST("data/delta_eta_nchCor"), deltaEtaWidth, nchCor); + histogramRegistry.fill(HIST("data/delta_eta_pos"), deltaEtaWidth, fpos); + histogramRegistry.fill(HIST("data/delta_eta_pos_cor"), deltaEtaWidth, posRecWeight); + histogramRegistry.fill(HIST("data/delta_eta_neg"), deltaEtaWidth, fneg); + histogramRegistry.fill(HIST("data/delta_eta_neg_cor"), deltaEtaWidth, negRecWeight); + histogramRegistry.fill(HIST("data/delta_eta_termp"), deltaEtaWidth, termp); + histogramRegistry.fill(HIST("data/delta_eta_termn"), deltaEtaWidth, termn); + histogramRegistry.fill(HIST("data/delta_eta_pos_sq"), deltaEtaWidth, fpos * fpos); + histogramRegistry.fill(HIST("data/delta_eta_neg_sq"), deltaEtaWidth, fneg * fneg); + histogramRegistry.fill(HIST("data/delta_eta_posneg"), deltaEtaWidth, posneg); + + const auto& mccolgen = coll.template mcCollision_as(); + + if (std::abs(mccolgen.posZ()) >= vertexZcut) + return; + + const auto& mcpartgen = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolgen.globalIndex(), cache); + + int posGen = 0, negGen = 0, posNegGen = 0, termNGen = 0, termPGen = 0, nchGen = 0; + for (const auto& mcpart : mcpartgen) { + if (!mcpart.isPhysicalPrimary()) + continue; + + int pid = mcpart.pdgCode(); + auto sign = 0; + auto* pd = pdgService->GetParticle(pid); + if (pd != nullptr) { + sign = pd->Charge() / 3.; + } + if (sign == 0) + 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()) >= etaCut) + continue; + if ((mcpart.pt() <= ptMinCut) || (mcpart.pt() >= ptMaxCut)) + continue; + + double mcEta = mcpart.eta(); + if (mcEta < deta1 || mcEta > deta2) + continue; + + histogramRegistry.fill(HIST("gen/delta_eta_eta"), mcpart.eta()); + + nchGen += 1; + if (sign == 1) { + posGen += 1; + } + if (sign == -1) { + negGen += 1; + } + } + + termPGen = posGen * (posGen - 1); + termNGen = negGen * (negGen - 1); + posNegGen = posGen * negGen; + + histogramRegistry.fill(HIST("gen/delta_eta_pos"), deltaEtaWidth, posGen); + histogramRegistry.fill(HIST("gen/delta_eta_neg"), deltaEtaWidth, negGen); + histogramRegistry.fill(HIST("gen/delta_eta_termp"), deltaEtaWidth, termPGen); + histogramRegistry.fill(HIST("gen/delta_eta_termn"), deltaEtaWidth, termNGen); + histogramRegistry.fill(HIST("gen/delta_eta_pos_sq"), deltaEtaWidth, posGen * posGen); + histogramRegistry.fill(HIST("gen/delta_eta_neg_sq"), deltaEtaWidth, negGen * negGen); + histogramRegistry.fill(HIST("gen/delta_eta_posneg"), deltaEtaWidth, posNegGen); + histogramRegistry.fill(HIST("gen/delta_eta_nch"), deltaEtaWidth, nchGen); + + float lRandom = fRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + histogramRegistry.fill(HIST("subsample/delta_eta/gen/pos"), deltaEtaWidth, sampleIndex, posGen); + histogramRegistry.fill(HIST("subsample/delta_eta/gen/neg"), deltaEtaWidth, sampleIndex, negGen); + histogramRegistry.fill(HIST("subsample/delta_eta/gen/termp"), deltaEtaWidth, sampleIndex, termPGen); + histogramRegistry.fill(HIST("subsample/delta_eta/gen/termn"), deltaEtaWidth, sampleIndex, termNGen); + histogramRegistry.fill(HIST("subsample/delta_eta/gen/pos_sq"), deltaEtaWidth, sampleIndex, posGen * posGen); + histogramRegistry.fill(HIST("subsample/delta_eta/gen/neg_sq"), deltaEtaWidth, sampleIndex, negGen * negGen); + histogramRegistry.fill(HIST("subsample/delta_eta/gen/posneg"), deltaEtaWidth, sampleIndex, posNegGen); + + } // void + + SliceCache cache; + Preslice mcTrack = aod::mcparticle::mcCollisionId; + + // process function for Data Run3 + void processDataRun3(MyCollisionRun3 const& coll, MyTracks const& tracks) + { + calculationData(coll, tracks); + for (int ii = 0; ii < deltaEta; ii++) { + float etaMin = -0.1f * (ii + 1); + float etaMax = 0.1f * (ii + 1); + + calculationDeltaEta(coll, tracks, etaMin, etaMax); + } + } + + PROCESS_SWITCH(NetchargeFluctuations, processDataRun3, "Process for Run3 DATA", false); + + // process function for Data Run2 + void processDataRun2(MyCollisionRun2 const& coll, MyTracks const& tracks) + { + calculationData(coll, tracks); + for (int ii = 0; ii < deltaEta; ii++) { + float etaMin = -0.1f * (ii + 1); // -0.1, -0.2, ..., -0.8 + float etaMax = 0.1f * (ii + 1); // +0.1, +0.2, ..., +0.8 + + calculationDeltaEta(coll, tracks, etaMin, etaMax); + } + } + + PROCESS_SWITCH(NetchargeFluctuations, processDataRun2, "Process for Run2 DATA", true); + + // process function for MC Run3 + + void processMcRun3(MyMCCollisionRun3 const& coll, MyMCTracks const& inputTracks, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + calculationMc(coll, inputTracks, mcCollisions, mcParticles); + for (int ii = 0; ii < deltaEta; ii++) { + float etaMin = -0.1f * (ii + 1); + float etaMax = 0.1f * (ii + 1); + calculationMcDeltaEta(coll, inputTracks, mcCollisions, mcParticles, etaMin, etaMax); + } + } + PROCESS_SWITCH(NetchargeFluctuations, processMcRun3, "Process reconstructed", false); + + // process function for MC Run2 + + void processMcRun2(MyMCCollisionRun2 const& coll, MyMCTracks const& inputTracks, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + calculationMc(coll, inputTracks, mcCollisions, mcParticles); + for (int ii = 0; ii < deltaEta; ii++) { + float etaMin = -0.1f * (ii + 1); + float etaMax = 0.1f * (ii + 1); + calculationMcDeltaEta(coll, inputTracks, mcCollisions, mcParticles, etaMin, etaMax); + } + } + + PROCESS_SWITCH(NetchargeFluctuations, processMcRun2, "Process reconstructed", false); +}; + +// struct +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + {adaptAnalysisTask(cfgc)}}; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/netprotonCumulantsMc.cxx b/PWGCF/EbyEFluctuations/Tasks/netprotonCumulantsMc.cxx new file mode 100644 index 00000000000..71659684daa --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/netprotonCumulantsMc.cxx @@ -0,0 +1,2951 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include +#include +#include +#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/EbyEFluctuations/Tasks/partNumFluc.cxx b/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx new file mode 100644 index 00000000000..916fabd1213 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx @@ -0,0 +1,2315 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file partNumFluc.cxx +/// \brief Task for particle number fluctuation analysis +/// \author Fan Si + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#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; + +namespace o2 +{ +namespace aod +{ +using JoinedCollisions = soa::Join; +using JoinedTracks = soa::Join; +using JoinedCollisionsWithMc = soa::Join; +using JoinedTracksWithMc = soa::Join; +using JoinedMcCollisions = soa::Join; +} // namespace aod +} // namespace o2 + +namespace fluctuation_calculator_base +{ +inline constexpr std::int8_t MaxOrder = 8; +inline constexpr std::uint8_t NExponentPairs = 36; +inline constexpr std::uint16_t NOrderVectors = 342; +inline constexpr std::array, NExponentPairs> ExponentPairs = {{{1, 1}, {2, 1}, {2, 2}, {3, 1}, {3, 2}, {3, 3}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {6, 1}, {6, 2}, {6, 3}, {6, 4}, {6, 5}, {6, 6}, {7, 1}, {7, 2}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {8, 1}, {8, 2}, {8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}}}; +inline constexpr std::array, NOrderVectors> OrderVectors = {{{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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 2, 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, 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, 1, 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, 2, 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, 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, 1, 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, 1, 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, 2, 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, 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, 1, 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, 1, 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, 1, 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, 2, 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, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 2, 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, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 2, 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, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 2, 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, 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, 1, 0, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 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, 1, 0, 0, 0, 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, 1, 0, 0, 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, 1, 0, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 0, 0, 2, 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, 1, 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, 1, 0, 1, 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, 1, 0, 2, 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, 1, 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, 1, 1, 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, 1, 1, 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, 1, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 3, 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, 4, 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, 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, 1, 0, 0, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 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, 1, 0, 0, 0, 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, 1, 0, 0, 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, 1, 0, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 0, 0, 0, 2, 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, 1, 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, 1, 0, 0, 1, 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, 1, 0, 0, 2, 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, 1, 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, 1, 0, 1, 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, 1, 0, 1, 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, 1, 0, 2, 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, 1, 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, 1, 1, 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, 1, 1, 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, 1, 1, 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, 1, 1, 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, 1, 1, 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, 1, 1, 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, 1, 1, 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, 1, 2, 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, 1, 3, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 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, 2, 2, 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, 3, 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, 3, 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, 4, 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}, + {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}, + {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, 1, 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, 1, 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, 1, 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, 1, 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, 1, 0, 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, 1, 0, 0, 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, 1, 0, 0, 0, 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, 1, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 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}, + {1, 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}, + {1, 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}, + {1, 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}, + {1, 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}, + {1, 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}, + {1, 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}, + {1, 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}, + {1, 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}, + {1, 0, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 0, 2, 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}, + {1, 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}, + {1, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 1, 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}, + {1, 0, 0, 0, 2, 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}, + {1, 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}, + {1, 0, 0, 1, 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}, + {1, 0, 0, 1, 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}, + {1, 0, 0, 1, 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}, + {1, 0, 0, 1, 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}, + {1, 0, 0, 1, 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}, + {1, 0, 0, 1, 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}, + {1, 0, 0, 2, 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}, + {1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 1, 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}, + {1, 0, 2, 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}, + {1, 0, 2, 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}, + {1, 0, 2, 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}, + {1, 0, 2, 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}, + {1, 0, 3, 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}, + {1, 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}, + {1, 1, 0, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 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}, + {1, 1, 1, 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}, + {1, 1, 1, 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}, + {1, 1, 1, 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}, + {1, 1, 2, 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}, + {1, 2, 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}, + {1, 2, 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}, + {1, 2, 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}, + {1, 2, 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}, + {1, 2, 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}, + {1, 3, 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}, + {2, 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}, + {2, 0, 0, 0, 0, 0, 0, 0, 0, 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}, + {2, 0, 0, 0, 0, 0, 0, 0, 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}, + {2, 0, 0, 0, 0, 0, 0, 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}, + {2, 0, 0, 0, 0, 0, 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}, + {2, 0, 0, 0, 0, 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}, + {2, 0, 0, 0, 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}, + {2, 0, 0, 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}, + {2, 0, 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}, + {2, 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}, + {2, 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}, + {2, 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}, + {2, 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}, + {2, 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}, + {2, 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}, + {2, 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}, + {2, 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}, + {2, 0, 0, 0, 0, 2, 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}, + {2, 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}, + {2, 0, 0, 0, 1, 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}, + {2, 0, 0, 0, 2, 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}, + {2, 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}, + {2, 0, 0, 1, 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}, + {2, 0, 0, 1, 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}, + {2, 0, 0, 2, 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}, + {2, 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}, + {2, 0, 1, 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}, + {2, 0, 1, 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}, + {2, 0, 1, 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}, + {2, 0, 1, 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}, + {2, 0, 1, 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}, + {2, 0, 1, 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}, + {2, 0, 1, 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}, + {2, 0, 2, 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}, + {2, 0, 3, 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}, + {2, 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}, + {2, 1, 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}, + {2, 1, 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}, + {2, 1, 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}, + {2, 1, 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}, + {2, 1, 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}, + {2, 1, 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}, + {2, 1, 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}, + {2, 1, 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}, + {2, 1, 2, 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}, + {2, 2, 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}, + {2, 2, 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}, + {2, 3, 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}, + {3, 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}, + {3, 0, 0, 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}, + {3, 0, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 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}, + {3, 0, 1, 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}, + {3, 0, 1, 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}, + {3, 0, 1, 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}, + {3, 0, 2, 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}, + {3, 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}, + {3, 1, 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}, + {3, 1, 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}, + {3, 1, 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}, + {3, 1, 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}, + {3, 2, 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}, + {4, 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}, + {4, 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}, + {4, 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}, + {4, 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}, + {4, 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}, + {4, 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}, + {4, 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}, + {4, 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}, + {4, 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}, + {4, 0, 2, 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}, + {4, 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}, + {4, 1, 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}, + {4, 2, 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}, + {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}, + {5, 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}, + {5, 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}, + {5, 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}, + {5, 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}, + {5, 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}, + {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, 0, 0}, + {6, 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}, + {6, 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}, + {7, 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}, + {8, 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}}}; +} // namespace fluctuation_calculator_base + +class FluctuationCalculatorTrack +{ + public: + FluctuationCalculatorTrack() : mQs{} {} + virtual ~FluctuationCalculatorTrack() {} + + double getProductFast(const std::int32_t orderVectorIndex, const double weight = 1.) const + { + double product = 1.; + for (std::int32_t const& iExponentPair : std::views::iota(0, static_cast(fluctuation_calculator_base::NExponentPairs))) { + if (fluctuation_calculator_base::OrderVectors[orderVectorIndex][iExponentPair]) { + product *= std::pow(mQs[iExponentPair], fluctuation_calculator_base::OrderVectors[orderVectorIndex][iExponentPair]); + } + } + return product * weight; + } + void init() { mQs.fill(0.); } + void fill(const double charge, const double efficiency, const double weight = 1.) + { + for (std::int32_t const& iExponentPair : std::views::iota(0, static_cast(fluctuation_calculator_base::NExponentPairs))) { + mQs[iExponentPair] += std::pow(charge, fluctuation_calculator_base::ExponentPairs[iExponentPair].first) / std::pow(efficiency, fluctuation_calculator_base::ExponentPairs[iExponentPair].second) * weight; + } + } + + protected: + std::array mQs; +}; + +struct HolderCcdb { + std::vector runNumbers; + std::vector runNumbersBad; + + TH3* hCentralityPtEtaShiftTpcNSigmaPiP = nullptr; + TH3* hCentralityPtEtaShiftTpcNSigmaPiM = nullptr; + TH3* hCentralityPtEtaShiftTpcNSigmaKaP = nullptr; + TH3* hCentralityPtEtaShiftTpcNSigmaKaM = nullptr; + TH3* hCentralityPtEtaShiftTpcNSigmaPrP = nullptr; + TH3* hCentralityPtEtaShiftTpcNSigmaPrM = nullptr; + TH3* hCentralityPtEtaShiftTofNSigmaPiP = nullptr; + TH3* hCentralityPtEtaShiftTofNSigmaPiM = nullptr; + TH3* hCentralityPtEtaShiftTofNSigmaKaP = nullptr; + TH3* hCentralityPtEtaShiftTofNSigmaKaM = nullptr; + TH3* hCentralityPtEtaShiftTofNSigmaPrP = nullptr; + TH3* hCentralityPtEtaShiftTofNSigmaPrM = nullptr; + + std::vector pCentralityPtEtaEfficiencyTpcPiP; + std::vector pCentralityPtEtaEfficiencyTpcPiM; + std::vector pCentralityPtEtaEfficiencyTpcKaP; + std::vector pCentralityPtEtaEfficiencyTpcKaM; + std::vector pCentralityPtEtaEfficiencyTpcPrP; + std::vector pCentralityPtEtaEfficiencyTpcPrM; + std::vector pCentralityPtEtaEfficiencyTpcTofPiP; + std::vector pCentralityPtEtaEfficiencyTpcTofPiM; + std::vector pCentralityPtEtaEfficiencyTpcTofKaP; + std::vector pCentralityPtEtaEfficiencyTpcTofKaM; + std::vector pCentralityPtEtaEfficiencyTpcTofPrP; + std::vector pCentralityPtEtaEfficiencyTpcTofPrM; +}; + +struct HolderEvent { + std::int32_t runNumber = 0; + std::int32_t runIndex = 0; + double vz = 0.; + std::int32_t vzBinIndex = 0; + std::int32_t nGlobalTracks = 0; + std::int32_t nPvContributors = 0; + double meanDcaXy = 0.; + double meanSquareDcaXy = 0.; + double meanDcaZ = 0.; + double meanSquareDcaZ = 0.; + std::int32_t nTofBeta = 0; + double centrality = 0.; + std::int32_t subgroupIndex = 0; + std::int32_t nChPMc = 0; + std::int32_t nChMMc = 0; + std::int32_t nKaPMc = 0; + std::int32_t nKaMMc = 0; + std::int32_t nPrPMc = 0; + std::int32_t nPrMMc = 0; + std::int32_t nChP = 0; + std::int32_t nChM = 0; + std::int32_t nKaP = 0; + std::int32_t nKaM = 0; + std::int32_t nPrP = 0; + std::int32_t nPrM = 0; + std::vector mcParticleIndicesMatchedTpcPiP; + std::vector mcParticleIndicesMatchedTpcPiM; + std::vector mcParticleIndicesMatchedTpcKaP; + std::vector mcParticleIndicesMatchedTpcKaM; + std::vector mcParticleIndicesMatchedTpcPrP; + std::vector mcParticleIndicesMatchedTpcPrM; + std::vector mcParticleIndicesMatchedTpcTofPiP; + std::vector mcParticleIndicesMatchedTpcTofPiM; + std::vector mcParticleIndicesMatchedTpcTofKaP; + std::vector mcParticleIndicesMatchedTpcTofKaM; + std::vector mcParticleIndicesMatchedTpcTofPrP; + std::vector mcParticleIndicesMatchedTpcTofPrM; + + void clear() + { + runNumber = 0; + runIndex = 0; + vz = 0.; + vzBinIndex = 0; + nGlobalTracks = 0; + nPvContributors = 0; + meanDcaXy = 0.; + meanSquareDcaXy = 0.; + meanDcaZ = 0.; + meanSquareDcaZ = 0.; + nTofBeta = 0; + centrality = 0.; + subgroupIndex = 0; + nChPMc = 0; + nChMMc = 0; + nKaPMc = 0; + nKaMMc = 0; + nPrPMc = 0; + nPrMMc = 0; + nChP = 0; + nChM = 0; + nKaP = 0; + nKaM = 0; + nPrP = 0; + nPrM = 0; + mcParticleIndicesMatchedTpcPiP.clear(); + mcParticleIndicesMatchedTpcPiM.clear(); + mcParticleIndicesMatchedTpcKaP.clear(); + mcParticleIndicesMatchedTpcKaM.clear(); + mcParticleIndicesMatchedTpcPrP.clear(); + mcParticleIndicesMatchedTpcPrM.clear(); + mcParticleIndicesMatchedTpcTofPiP.clear(); + mcParticleIndicesMatchedTpcTofPiM.clear(); + mcParticleIndicesMatchedTpcTofKaP.clear(); + mcParticleIndicesMatchedTpcTofKaM.clear(); + mcParticleIndicesMatchedTpcTofPrP.clear(); + mcParticleIndicesMatchedTpcTofPrM.clear(); + } +}; + +struct HolderTrack { + static constexpr double TruncationAbsNSigmaPid = 999.; + static constexpr double truncateNSigmaPid(const double value) { return (!(std::abs(value) < TruncationAbsNSigmaPid) ? -TruncationAbsNSigmaPid : value); } + + std::int32_t sign = 0; + double p = 0.; + double pt = 0.; + double eta = 0.; + double phi = 0.; + double pOverQ = 0.; + double ptOverQ = 0.; + double rapidityPi = 0.; + double rapidityKa = 0.; + double rapidityPr = 0.; + bool hasTpcPid = false; + double tpcNSigmaPi = 0.; + double tpcNSigmaKa = 0.; + double tpcNSigmaPr = 0.; + bool hasTofPid = false; + double tofNSigmaPi = 0.; + double tofNSigmaKa = 0.; + double tofNSigmaPr = 0.; + double tpcTofNSigmaPi = 0.; + double tpcTofNSigmaKa = 0.; + double tpcTofNSigmaPr = 0.; + std::int32_t mcParticleId = 0; + + void clear() + { + sign = 0; + p = 0.; + pt = 0.; + eta = 0.; + phi = 0.; + pOverQ = 0.; + ptOverQ = 0.; + rapidityPi = 0.; + rapidityKa = 0.; + rapidityPr = 0.; + hasTpcPid = false; + tpcNSigmaPi = 0.; + tpcNSigmaKa = 0.; + tpcNSigmaPr = 0.; + hasTofPid = false; + tofNSigmaPi = 0.; + tofNSigmaKa = 0.; + tofNSigmaPr = 0.; + tpcTofNSigmaPi = 0.; + tpcTofNSigmaKa = 0.; + tpcTofNSigmaPr = 0.; + mcParticleId = 0; + } +}; + +struct HolderMcParticle { + std::int32_t globalIndex = 0; + std::int32_t pdgCode = 0; + double pt = 0.; + double eta = 0.; + + void clear() + { + globalIndex = 0; + pdgCode = 0; + pt = 0.; + eta = 0.; + } +}; + +struct PartNumFluc { + enum class CentralityDefinitionIndices { kFV0A = 0, + kFT0M, + kFT0A, + kFT0C, + kNIndices }; + + Configurable cfgCcdbUrl{"cfgCcdbUrl", "https://alice-ccdb.cern.ch", "Url of CCDB"}; + Configurable cfgCcdbPath{"cfgCcdbPath", "Users/f/fasi/test", "Path in CCDB"}; + + Configurable cfgFlagQaRun{"cfgFlagQaRun", false, "Run QA flag"}; + Configurable cfgFlagQaEvent{"cfgFlagQaEvent", false, "Event QA flag"}; + Configurable cfgFlagQaCentrality{"cfgFlagQaCentrality", false, "Centrality QA flag"}; + Configurable cfgFlagQaTrack{"cfgFlagQaTrack", false, "Track QA flag"}; + Configurable cfgFlagQaAcceptance{"cfgFlagQaAcceptance", false, "Acceptance QA flag"}; + Configurable cfgFlagQaPid{"cfgFlagQaPid", false, "PID QA flag"}; + Configurable cfgFlagCalculationPurityPi{"cfgFlagCalculationPurityPi", false, "Pion purity calculation flag"}; + Configurable cfgFlagCalculationPurityKa{"cfgFlagCalculationPurityKa", false, "Kaon purity calculation flag"}; + Configurable cfgFlagCalculationPurityPr{"cfgFlagCalculationPurityPr", false, "(Anti)proton purity calculation flag"}; + Configurable cfgFlagCalculationEfficiencyPi{"cfgFlagCalculationEfficiencyPi", false, "Pion efficiency calculation flag"}; + Configurable cfgFlagCalculationEfficiencyKa{"cfgFlagCalculationEfficiencyKa", false, "Kaon efficiency calculation flag"}; + Configurable cfgFlagCalculationEfficiencyPr{"cfgFlagCalculationEfficiencyPr", false, "(Anti)proton efficiency calculation flag"}; + Configurable cfgFlagCalculationFluctuationCh{"cfgFlagCalculationFluctuationCh", false, "Charge number fluctuation calculation flag"}; + Configurable cfgFlagCalculationFluctuationKa{"cfgFlagCalculationFluctuationKa", false, "Kaon number fluctuation calculation flag"}; + Configurable cfgFlagCalculationFluctuationPr{"cfgFlagCalculationFluctuationPr", false, "(Anti)proton number fluctuation calculation flag"}; + + Configurable cfgFlagRejectionRunBad{"cfgFlagRejectionRunBad", false, "Bad run rejection flag"}; + Configurable cfgFlagSelectionEvent{"cfgFlagSelectionEvent", 0b00000000001111110100000000000000000000000000000000ULL, "Event selection flag"}; + Configurable cfgCutMaxAbsVertexZ{"cfgCutMaxAbsVertexZ", 6., "Maximum absolute vertex z position (cm)"}; + Configurable cfgCutMinDeviationNPvContributors{"cfgCutMinDeviationNPvContributors", -4, "Minimum nPvContributors deviation from nGlobalTracks"}; + Configurable cfgIndexDefinitionCentrality{"cfgIndexDefinitionCentrality", 1, "Centrality definition index"}; + + Configurable cfgFlagPvContributor{"cfgFlagPvContributor", true, "Flag of requiring PV contributor"}; + Configurable cfgCutMinItsNCls{"cfgCutMinItsNCls", 5, "Minimum number of clusters ITS"}; + Configurable cfgCutMaxItsChi2NCls{"cfgCutMaxItsChi2NCls", 30., "Maximum chi2 per cluster ITS"}; + Configurable cfgCutMinTpcNCls{"cfgCutMinTpcNCls", 55, "Minimum number of clusters TPC"}; // 50, 60 + Configurable cfgCutMaxTpcChi2NCls{"cfgCutMaxTpcChi2NCls", 3.5, "Maximum chi2 per cluster TPC"}; // 3., 4. + Configurable cfgCutMaxTpcNClsSharedRatio{"cfgCutMaxTpcNClsSharedRatio", 0.2, "Maximum ratio of shared clusters over clusters TPC"}; + Configurable cfgCutMinTpcNClsCrossedRows{"cfgCutMinTpcNClsCrossedRows", 75, "Minimum number of crossed rows TPC"}; // 70, 80 + Configurable cfgCutMinTpcNClsCrossedRowsRatio{"cfgCutMinTpcNClsCrossedRowsRatio", 0.8, "Minimum ratio of crossed rows over findable clusters TPC"}; + Configurable> cfgParSigmaDcaXy{"cfgParSigmaDcaXy", {0.0015, 0.005, 1.1}, "Parameters of sigma of DCAxy (cm) in [0]+[1]*pt^[2]"}; + Configurable cfgCutMaxAbsNSigmaDcaXy{"cfgCutMaxAbsNSigmaDcaXy", 6., "Maximum absolute nSigma of DCAxy (cm)"}; // 5., 7. + Configurable cfgCutMaxAbsDcaZ{"cfgCutMaxAbsDcaZ", 0.2, "Maximum absolute DCAz (cm)"}; // 0.15, 0.25 + Configurable cfgCutMinPt{"cfgCutMinPt", 0.4, "Minimum pT (GeV/c)"}; + Configurable cfgCutMaxPt{"cfgCutMaxPt", 2., "Maximum pT (GeV/c)"}; + Configurable cfgCutMaxAbsEta{"cfgCutMaxAbsEta", 0.8, "Maximum absolute eta"}; + Configurable cfgThresholdPtTofPi{"cfgThresholdPtTofPi", 0.5, "pT (GeV/c) threshold for TOF pions"}; + Configurable cfgThresholdPtTofKa{"cfgThresholdPtTofKa", 0.5, "pT (GeV/c) threshold for TOF kaons"}; + Configurable cfgThresholdPtTofPr{"cfgThresholdPtTofPr", 0.8, "pT (GeV/c) threshold for TOF (anti)protons"}; + Configurable cfgFlagRecalibrationNSigmaPi{"cfgFlagRecalibrationNSigmaPi", false, "nSigmaPi recalibration flag"}; + Configurable cfgFlagRecalibrationNSigmaKa{"cfgFlagRecalibrationNSigmaKa", false, "nSigmaKa recalibration flag"}; + Configurable cfgFlagRecalibrationNSigmaPr{"cfgFlagRecalibrationNSigmaPr", false, "nSigmaPr recalibration flag"}; + Configurable cfgCutMaxAbsNSigmaPid{"cfgCutMaxAbsNSigmaPid", 2., "Maximum absolute nSigma for PID"}; // 1.5, 2.5 + + Configurable cfgNCentralityBins{"cfgNCentralityBins", 20, "Number of centrality bins in fluctuation calculation"}; + Configurable cfgNSubgroups{"cfgNSubgroups", 20, "Number of subgroups in fluctuation calculation"}; + + Service ccdb; + + HolderCcdb holderCcdb; + HolderEvent holderEvent; + HolderTrack holderTrack; + HolderMcParticle holderMcParticle; + + std::vector> pCentralityPtEtaEfficiencyTpcPiP; + std::vector> pCentralityPtEtaEfficiencyTpcPiM; + std::vector> pCentralityPtEtaEfficiencyTpcKaP; + std::vector> pCentralityPtEtaEfficiencyTpcKaM; + std::vector> pCentralityPtEtaEfficiencyTpcPrP; + std::vector> pCentralityPtEtaEfficiencyTpcPrM; + std::vector> pCentralityPtEtaEfficiencyTpcTofPiP; + std::vector> pCentralityPtEtaEfficiencyTpcTofPiM; + std::vector> pCentralityPtEtaEfficiencyTpcTofKaP; + std::vector> pCentralityPtEtaEfficiencyTpcTofKaM; + std::vector> pCentralityPtEtaEfficiencyTpcTofPrP; + std::vector> pCentralityPtEtaEfficiencyTpcTofPrM; + + std::unique_ptr fluctuationCalculatorTrackChP; + std::unique_ptr fluctuationCalculatorTrackChM; + std::unique_ptr fluctuationCalculatorTrackChT; + std::unique_ptr fluctuationCalculatorTrackChN; + std::unique_ptr fluctuationCalculatorTrackKaP; + std::unique_ptr fluctuationCalculatorTrackKaM; + std::unique_ptr fluctuationCalculatorTrackKaT; + std::unique_ptr fluctuationCalculatorTrackKaN; + std::unique_ptr fluctuationCalculatorTrackPrP; + std::unique_ptr fluctuationCalculatorTrackPrM; + std::unique_ptr fluctuationCalculatorTrackPrT; + std::unique_ptr fluctuationCalculatorTrackPrN; + + HistogramRegistry hrCalculationFluctuation{"hrCalculationFluctuation", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrCalculationEfficiency{"hrCalculationEfficiency", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrCalculationPurity{"hrCalculationPurity", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrQaAcceptance{"hrQaAcceptance", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrQaPid{"hrQaPid", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrQaTrack{"hrQaTrack", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrQaCentrality{"hrQaCentrality", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrQaEvent{"hrQaEvent", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrQaRun{"hrQaRun", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hrCounter{"hrCounter", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Filter filterCollision = (aod::evsel::sel8 == true); + Filter filterfTrack = requireGlobalTrackWoPtEtaInFilter(); + Filter filterfMcCollision = (aod::mccollisionprop::numRecoCollision > 0); + + Preslice presliceTracksPerCollision = aod::track::collisionId; + + void init(InitContext&) + { + gRandom->SetSeed(0); + + assert(doprocessRaw.value ^ doprocessMc.value); + if (doprocessRaw.value) { + LOG(info) << "Enabling raw data process."; + } else if (doprocessMc.value) { + LOG(info) << "Enabling MC data process."; + } + + ccdb->setURL(cfgCcdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(true); + + const TList* const ccdbObject = ccdb->getForTimeStamp(cfgCcdbPath.value, -1); + assert(ccdbObject && ccdbObject->IsA() == TList::Class()); + + const TGraph* const gRunNumberIsBad = static_cast(ccdbObject->FindObject("gRunNumberIsBad")); + assert(gRunNumberIsBad && gRunNumberIsBad->IsA() == TGraph::Class()); + holderCcdb.runNumbers.reserve(gRunNumberIsBad->GetN()); + holderCcdb.runNumbersBad.reserve(gRunNumberIsBad->GetN()); + for (std::int32_t const& iRun : std::views::iota(0, gRunNumberIsBad->GetN())) { + holderCcdb.runNumbers.push_back(static_cast(std::llrint(gRunNumberIsBad->GetX()[iRun]))); + if (cfgFlagRejectionRunBad.value && gRunNumberIsBad->GetY()[iRun]) { + holderCcdb.runNumbersBad.push_back(static_cast(std::llrint(gRunNumberIsBad->GetX()[iRun]))); + } + } + + if (holderCcdb.runNumbers.empty()) { + LOG(info) << "No run process enabled."; + } else { + LOG(info) << "Number of runs: " << holderCcdb.runNumbers.size(); + for (std::int32_t const& runNumber : holderCcdb.runNumbers) { + LOG(info) << "Enabling processing run: " << runNumber; + } + } + + if (holderCcdb.runNumbersBad.empty()) { + LOG(info) << "No run rejection enabled."; + } else { + LOG(info) << "Number of bad runs: " << holderCcdb.runNumbersBad.size(); + for (std::int32_t const& runNumberBad : holderCcdb.runNumbersBad) { + LOG(info) << "Enabling rejecting run: " << runNumberBad; + } + } + + if ((cfgFlagSelectionEvent.value & ((1ULL << aod::evsel::EventSelectionFlags::kNsel) - 1)) == 0) { + LOG(info) << "No event selection bit enabled."; + } else { + for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { + if ((cfgFlagSelectionEvent.value >> iEvSel) & 1) { + LOG(info) << "Enabling event selection bit: " << aod::evsel::selectionLabels[iEvSel]; + } + } + } + + switch (cfgIndexDefinitionCentrality) { + default: + LOG(info) << "Enabling centrality definition: FV0A"; + break; + case static_cast(CentralityDefinitionIndices::kFT0M): + LOG(info) << "Enabling centrality definition: FT0M"; + break; + case static_cast(CentralityDefinitionIndices::kFT0A): + LOG(info) << "Enabling centrality definition: FT0A"; + break; + case static_cast(CentralityDefinitionIndices::kFT0C): + LOG(info) << "Enabling centrality definition: FT0C"; + break; + } + + if (cfgFlagRecalibrationNSigmaPi.value) { + LOG(info) << "Enabling nSigmaPi recalibration."; + + holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPiP%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP && holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP->GetName(); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPiM%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM && holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM->GetName(); + holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPiP%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP && holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP->GetName(); + holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPiM%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM && holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM->GetName(); + } + + if (cfgFlagRecalibrationNSigmaKa.value) { + LOG(info) << "Enabling nSigmaKa recalibration."; + + holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaKaP%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP && holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP->GetName(); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaKaM%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM && holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM->GetName(); + holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTofNSigmaKaP%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP && holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP->GetName(); + holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTofNSigmaKaM%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM && holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM->GetName(); + } + + if (cfgFlagRecalibrationNSigmaPr.value) { + LOG(info) << "Enabling nSigmaPr recalibration."; + + holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPrP%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP && holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP->GetName(); + holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTpcNSigmaPrM%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM && holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM->GetName(); + holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPrP%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP && holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP->GetName(); + holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM = static_cast(ccdbObject->FindObject(Form("hCentralityPtEtaShiftTofNSigmaPrM%s", doprocessMc.value ? "_mc" : ""))); + assert(holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM && holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM->InheritsFrom(TH3::Class())); + LOG(info) << "Reading from CCDB: " << holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM->GetName(); + } + + hrCounter.add("hNEvents", ";;No. of Events", {HistType::kTH1D, {{10 + aod::evsel::EventSelectionFlags::kNsel, -0.5, 9.5 + static_cast(aod::evsel::EventSelectionFlags::kNsel), "Selection"}}}); + + if (cfgFlagQaRun.value) { + LOG(info) << "Enabling run QA."; + + HistogramConfigSpec hcsQaRun(HistType::kTProfile, {{static_cast(holderCcdb.runNumbers.size()), -0.5, holderCcdb.runNumbers.size() - 0.5, "Run Index"}}); + hrQaRun.add("QaRun/pRunIndexVx", ";;#LT#it{V}_{#it{x}}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexVy", ";;#LT#it{V}_{#it{y}}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexVz", ";;#LT#it{V}_{#it{z}}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMultFv0a", ";;FV0A #LTMultiplicity#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMultFt0a", ";;FT0A #LTMultiplicity#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMultFt0c", ";;FT0C #LTMultiplicity#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNGlobalTracks", ";;#LTnGlobalTracks#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNPvContributors", ";;#LTnPvContributors#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMeanDcaXy", ";;#LT#LTDCA_{#it{xy}}#GT_{event}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexSigmaDcaXy", ";;#LT#it{#sigma}(DCA_{#it{xy}})_{event}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexMeanDcaZ", ";;#LT#LTDCA_{#it{z}}#GT_{event}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexSigmaDcaZ", ";;#LT#it{#sigma}(DCA_{#it{z}})_{event}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNTofBeta", ";;#LTnTofBeta#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexItsNCls", ";;ITS #LTnClusters#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexItsChi2NCls", ";;ITS #LT#it{#chi}^{2}/nClusters#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcNCls", ";;TPC #LTnClusters#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcChi2NCls", ";;TPC #LT#it{#chi}^{2}/nClusters#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcNClsSharedRatio", ";;TPC #LTnSharedClusters/nClusters#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcNClsCrossedRows", ";;TPC #LTnCrossedRows#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcNClsCrossedRowsRatio", ";;TPC #LTnCrossedRows/nFindableClusters#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexDcaXy", ";;#LTDCA_{#it{xy}}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexDcaZ", ";;#LTDCA_{#it{z}}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexPt", ";;#LT#it{p}_{T}#GT (GeV/#it{c})", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexEta", ";;#LT#it{#eta}#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexPhi", ";;#LT#it{#varphi}#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcDeDx", ";;TPC #LTd#it{E}/d#it{x}#GT (a.u.)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcNSigmaPi", ";;TPC #LT#it{n}#it{#sigma}_{#pi}#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcNSigmaKa", ";;TPC #LT#it{n}#it{#sigma}_{K}#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTpcNSigmaPr", ";;TPC #LT#it{n}#it{#sigma}_{p}#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTofInverseBeta", ";;TOF #LT1/#it{#beta}#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTofNSigmaPi", ";;TOF #LT#it{n}#it{#sigma}_{#pi}#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTofNSigmaKa", ";;TOF #LT#it{n}#it{#sigma}_{K}#GT", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexTofNSigmaPr", ";;TOF #LT#it{n}#it{#sigma}_{p}#GT", hcsQaRun); + } + + if (cfgFlagQaEvent.value) { + LOG(info) << "Enabling event QA."; + + AxisSpec asRunIndex(static_cast(holderCcdb.runNumbers.size()), -0.5, holderCcdb.runNumbers.size() - 0.5, "Run Index"); + AxisSpec asNGlobalTracks(180, -0.5, 179.5, "nGlobalTracks"); + hrQaEvent.add("QaEvent/hRunIndexVxVy", "", {HistType::kTHnSparseF, {asRunIndex, {150, -0.15, 0.15, "#it{V}_{#it{x}} (cm)"}, {150, -0.15, 0.15, "#it{V}_{#it{y}} (cm)"}}}); + hrQaEvent.add("QaEvent/hRunIndexVz", "", {HistType::kTH2F, {asRunIndex, {300, -15., 15., "#it{V}_{#it{z}} (cm)"}}}); + hrQaEvent.add("QaEvent/hRunIndexNPvContributorsNGlobalTracks", "", {HistType::kTHnSparseF, {asRunIndex, {180, -0.5, 179.5, "nPvContributors"}, asNGlobalTracks}}); + hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaXy", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -0.5, 0.5, "#LTDCA_{#it{xy}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaXy_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaZ", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaZ_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hRunIndexNTofBetaNGlobalTracks", "", {HistType::kTHnSparseF, {asRunIndex, {60, -0.5, 59.5, "nTofBeta"}, asNGlobalTracks}}); + hrQaEvent.add("QaEvent/hRunIndexNTofBetaNGlobalTracks_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, {60, -0.5, 59.5, "nTofBeta"}, asNGlobalTracks}}); + } + + if (cfgFlagQaCentrality.value) { + LOG(info) << "Enabling centrality QA."; + + AxisSpec asQaCentrality(20, 0., 100., "Centrality (%)"); + hrQaCentrality.add("QaCentrality/hCentralityFv0a", "", {HistType::kTHnSparseF, {asQaCentrality, {2400, 0., 24000., "FV0A Multiplicity"}}}); + hrQaCentrality.add("QaCentrality/hCentralityFt0a", "", {HistType::kTHnSparseF, {asQaCentrality, {1600, 0., 8000., "FT0A Multiplicity"}}}); + hrQaCentrality.add("QaCentrality/hCentralityFt0c", "", {HistType::kTHnSparseF, {asQaCentrality, {400, 0., 2000., "FT0C Multiplicity"}}}); + hrQaCentrality.add("QaCentrality/hCentralityFt0m", "", {HistType::kTHnSparseF, {asQaCentrality, {2000, 0., 10000., "FT0A+FT0C Multiplicity"}}}); + } + + if (cfgFlagQaTrack.value) { + LOG(info) << "Enabling track QA."; + + AxisSpec asPt(200, 0., 2., "#it{p}_{T} (GeV/#it{c})"); + hrQaTrack.add("QaTrack/hItsNCls", "", {HistType::kTH1D, {{10, -0.5, 9.5, "ITS nClusters"}}}); + hrQaTrack.add("QaTrack/hItsChi2NCls", "", {HistType::kTH1D, {{80, 0., 40., "ITS #it{#chi}^{2}/nClusters"}}}); + hrQaTrack.add("QaTrack/hTpcNClsNClsSharedNClsFindableNClsCrossedRows", "", {HistType::kTHnSparseF, {{180, -0.5, 179.5, "TPC nClusters"}, {180, -0.5, 179.5, "TPC nSharedClusters"}, {180, -0.5, 179.5, "TPC nFindableClusters"}, {180, -0.5, 179.5, "TPC nCrossedRows"}}}); + hrQaTrack.add("QaTrack/hTpcChi2NCls", "", {HistType::kTH1D, {{100, 0., 5., "TPC #it{#chi}^{2}/nClusters"}}}); + hrQaTrack.add("QaTrack/hPtDcaXy", "", {HistType::kTH2D, {asPt, {200, -0.5, 0.5, "DCA_{#it{xy}} (cm)"}}}); + hrQaTrack.add("QaTrack/hPtDcaXy_pvContributor", "", {HistType::kTH2D, {asPt, {200, -0.5, 0.5, "DCA_{#it{xy}} (cm)"}}}); + hrQaTrack.add("QaTrack/hPtDcaZ", "", {HistType::kTH2D, {asPt, {200, -2., 2., "DCA_{#it{z}} (cm)"}}}); + hrQaTrack.add("QaTrack/hPtDcaZ_pvContributor", "", {HistType::kTH2D, {asPt, {200, -0.5, 0.5, "DCA_{#it{xy}} (cm)"}}}); + } + + if (cfgFlagQaAcceptance.value) { + LOG(info) << "Enabling acceptance QA."; + + AxisSpec asPt(250, 0., 2.5, "#it{p}_{T} (GeV/#it{c})"); + HistogramConfigSpec hcsQaAcceptanceEta(HistType::kTH2D, {{300, -1.5, 1.5, "#it{#eta}"}, asPt}); + HistogramConfigSpec hcsQaAcceptancePhi(HistType::kTH1D, {{360, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}); + HistogramConfigSpec hcsQaAcceptanceY(HistType::kTH2D, {{300, -1.5, 1.5, "#it{y}"}, asPt}); + hrQaAcceptance.add("QaAcceptance/hEtaPt_tpc", "", hcsQaAcceptanceEta); + hrQaAcceptance.add("QaAcceptance/hPhi_tpc", "", hcsQaAcceptancePhi); + hrQaAcceptance.add("QaAcceptance/hYPt_tpcPi", "", hcsQaAcceptanceY); + hrQaAcceptance.add("QaAcceptance/hYPt_tpcKa", "", hcsQaAcceptanceY); + hrQaAcceptance.add("QaAcceptance/hYPt_tpcPr", "", hcsQaAcceptanceY); + hrQaAcceptance.add("QaAcceptance/hEtaPt_tpcTof", "", hcsQaAcceptanceEta); + hrQaAcceptance.add("QaAcceptance/hPhi_tpcTof", "", hcsQaAcceptancePhi); + hrQaAcceptance.add("QaAcceptance/hYPt_tpcTofPi", "", hcsQaAcceptanceY); + hrQaAcceptance.add("QaAcceptance/hYPt_tpcTofKa", "", hcsQaAcceptanceY); + hrQaAcceptance.add("QaAcceptance/hYPt_tpcTofPr", "", hcsQaAcceptanceY); + } + + if (cfgFlagQaPid.value) { + LOG(info) << "Enabling PID QA."; + + AxisSpec asQaCentrality(20, 0., 100., "Centrality (%)"); + AxisSpec asPOverQ(350, -3.5, 3.5, "#it{p}/#it{q} (GeV/#it{c})"); + AxisSpec asPtOverQ(80, -2., 2., "#it{p}_{T}/#it{q} (GeV/#it{c})"); + AxisSpec asEta(48, -1.2, 1.2, "#it{#eta}"); + HistogramConfigSpec hcsQaPid(HistType::kTHnSparseF, {asQaCentrality, asPtOverQ, asEta, {200, -10., 10.}}); + hrQaPid.add("QaPid/hCentralityPOverQEtaTpcLnDeDx", "", {HistType::kTHnSparseF, {asQaCentrality, asPOverQ, asEta, {240, 3., 9., "TPC ln(d#it{E}/d#it{x} (a.u.))"}}}); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTpcNSigmaPi_tofPi", ";;;;TPC #it{n}#it{#sigma}_{#pi}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTpcNSigmaKa_tofKa", ";;;;TPC #it{n}#it{#sigma}_{K}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTpcNSigmaPr_tofPr", ";;;;TPC #it{n}#it{#sigma}_{p}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPOverQEtaTofInverseBeta", "", {HistType::kTHnSparseF, {asQaCentrality, asPOverQ, asEta, {120, 0.5, 3.5, "TOF 1/#it{#beta}"}}}); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTofNSigmaPi_tpcPi", ";;;;TOF #it{n}#it{#sigma}_{#pi}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTofNSigmaKa_tpcKa", ";;;;TOF #it{n}#it{#sigma}_{K}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTofNSigmaPr_tpcPr", ";;;;TOF #it{n}#it{#sigma}_{p}", hcsQaPid); + } + + if (doprocessMc.value) { + if (cfgFlagCalculationPurityPi.value || cfgFlagCalculationPurityKa.value || cfgFlagCalculationPurityPr.value) { + AxisSpec asQaCentrality(20, 0., 100., "Centrality (%)"); + AxisSpec asEta(24, -1.2, 1.2, "#it{#eta}"); + HistogramConfigSpec hcsCalculationPurityP(HistType::kTProfile3D, {asQaCentrality, {35, 0., 3.5, "#it{p} (GeV/#it{c})"}, asEta}); + HistogramConfigSpec hcsCalculationPurityPt(HistType::kTProfile3D, {asQaCentrality, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, asEta}); + + if (cfgFlagCalculationPurityPi.value) { + LOG(info) << "Enabling pion purity calculation."; + + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcPiP", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcPiM", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcTofPiP", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcTofPiM", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcPiP", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcPiM", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofPiP", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofPiM", "", hcsCalculationPurityPt); + } + + if (cfgFlagCalculationPurityKa.value) { + LOG(info) << "Enabling kaon purity calculation."; + + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcKaP", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcKaM", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcTofKaP", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcTofKaM", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcKaP", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcKaM", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofKaP", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofKaM", "", hcsCalculationPurityPt); + } + + if (cfgFlagCalculationPurityPr.value) { + LOG(info) << "Enabling (anti)proton purity calculation."; + + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcPrP", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcPrM", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcTofPrP", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPEtaPurityTpcTofPrM", "", hcsCalculationPurityP); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcPrP", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcPrM", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofPrP", "", hcsCalculationPurityPt); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofPrM", "", hcsCalculationPurityPt); + } + } + + if (cfgFlagCalculationEfficiencyPi.value || cfgFlagCalculationEfficiencyKa.value || cfgFlagCalculationEfficiencyPr.value) { + HistogramConfigSpec hcsCalculationEfficiency(HistType::kTProfile3D, {{20, 0., 100., "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}}); + + if (cfgFlagCalculationEfficiencyPi.value) { + LOG(info) << "Enabling pion efficiency calculation."; + + holderEvent.mcParticleIndicesMatchedTpcPiP.reserve(60); + holderEvent.mcParticleIndicesMatchedTpcPiM.reserve(60); + holderEvent.mcParticleIndicesMatchedTpcTofPiP.reserve(40); + holderEvent.mcParticleIndicesMatchedTpcTofPiM.reserve(40); + + pCentralityPtEtaEfficiencyTpcPiP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcPiM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofPiP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofPiM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + pCentralityPtEtaEfficiencyTpcPiP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcPiP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcPiM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcPiM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofPiP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofPiM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + } + } + + if (cfgFlagCalculationEfficiencyKa.value) { + LOG(info) << "Enabling kaon efficiency calculation."; + + holderEvent.mcParticleIndicesMatchedTpcKaP.reserve(30); + holderEvent.mcParticleIndicesMatchedTpcKaM.reserve(30); + holderEvent.mcParticleIndicesMatchedTpcTofKaP.reserve(20); + holderEvent.mcParticleIndicesMatchedTpcTofKaM.reserve(20); + + pCentralityPtEtaEfficiencyTpcKaP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcKaM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofKaP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofKaM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + pCentralityPtEtaEfficiencyTpcKaP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcKaP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcKaM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcKaM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofKaP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofKaM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + } + } + + if (cfgFlagCalculationEfficiencyPr.value) { + LOG(info) << "Enabling (anti)proton efficiency calculation."; + + holderEvent.mcParticleIndicesMatchedTpcPrP.reserve(30); + holderEvent.mcParticleIndicesMatchedTpcPrM.reserve(30); + holderEvent.mcParticleIndicesMatchedTpcTofPrP.reserve(20); + holderEvent.mcParticleIndicesMatchedTpcTofPrM.reserve(20); + + pCentralityPtEtaEfficiencyTpcPrP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcPrM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofPrP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofPrM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + pCentralityPtEtaEfficiencyTpcPrP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcPrP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcPrM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcPrM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofPrP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofPrM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + } + } + } + } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + HistogramConfigSpec hcsCalculationFluctuation(HistType::kTH3D, {{cfgNCentralityBins.value, 0., 100., "Centrality (%)"}, {40, -0.5, 39.5}, {40, -0.5, 39.5}}); + HistogramConfigSpec hcsFluctuationCalculator(HistType::kTH3D, {{cfgNCentralityBins.value, 0., 100., "Centrality (%)"}, {cfgNSubgroups.value, -0.5, cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderVectors, -0.5, fluctuation_calculator_base::NOrderVectors - 0.5, "Order Vector Index"}}); + + if (cfgFlagCalculationFluctuationCh.value) { + holderCcdb.pCentralityPtEtaEfficiencyTpcPiP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcPiM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcPiP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcPiM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofPiP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofPiM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin]->GetName(); + } + } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value) { + holderCcdb.pCentralityPtEtaEfficiencyTpcKaP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcKaM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcKaP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcKaM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofKaP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofKaM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin]->GetName(); + } + } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationPr.value) { + holderCcdb.pCentralityPtEtaEfficiencyTpcPrP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcPrM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcPrP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcPrM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofPrP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin]->GetName(); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofPrM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin]->IsA() == TProfile3D::Class()); + LOG(info) << "Reading from CCDB: " << holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin]->GetName(); + } + } + + if (cfgFlagCalculationFluctuationCh.value) { + LOG(info) << "Enabling charge number fluctuation calculation."; + + fluctuationCalculatorTrackChP = std::make_unique(); + fluctuationCalculatorTrackChM = std::make_unique(); + fluctuationCalculatorTrackChT = std::make_unique(); + fluctuationCalculatorTrackChN = std::make_unique(); + + if (doprocessMc.value) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNChPNChM_mc", ";;#it{N}(h^{+});#it{N}(h^{#minus})", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNChPNChM", ";;#it{N}(h^{+});#it{N}(h^{#minus})", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChN", "", hcsFluctuationCalculator); + } + + if (cfgFlagCalculationFluctuationKa.value) { + LOG(info) << "Enabling kaon number fluctuation calculation."; + + fluctuationCalculatorTrackKaP = std::make_unique(); + fluctuationCalculatorTrackKaM = std::make_unique(); + fluctuationCalculatorTrackKaT = std::make_unique(); + fluctuationCalculatorTrackKaN = std::make_unique(); + + if (doprocessMc.value) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNKaPNKaM_mc", ";;#it{N}(K^{+});#it{N}(K^{#minus})", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNKaPNKaM", ";;#it{N}(K^{+});#it{N}(K^{#minus})", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaN", "", hcsFluctuationCalculator); + } + + if (cfgFlagCalculationFluctuationPr.value) { + LOG(info) << "Enabling (anti)proton number fluctuation calculation."; + + fluctuationCalculatorTrackPrP = std::make_unique(); + fluctuationCalculatorTrackPrM = std::make_unique(); + fluctuationCalculatorTrackPrT = std::make_unique(); + fluctuationCalculatorTrackPrN = std::make_unique(); + + if (doprocessMc.value) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNPrPNPrM_mc", ";;#it{N}(p);#it{N}(#bar{p})", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNPrPNPrM", ";;#it{N}(p);#it{N}(#bar{p})", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrN", "", hcsFluctuationCalculator); + } + } + } + + double getShiftNSigmaPid(const bool flagRecalibrationNSigmaPid, const TH3* const hCentralityPtEtaShiftNSigmaPidP, const TH3* const hCentralityPtEtaShiftNSigmaPidM) + { + const TH3* const hCentralityPtEtaShiftNSigmaPid = [&]() -> const TH3* { + switch (static_cast(flagRecalibrationNSigmaPid) * holderTrack.sign) { + case 1: + return hCentralityPtEtaShiftNSigmaPidP; + case -1: + return hCentralityPtEtaShiftNSigmaPidM; + default: + return nullptr; + } + }(); + return hCentralityPtEtaShiftNSigmaPid ? hCentralityPtEtaShiftNSigmaPid->Interpolate(std::max(std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetXaxis()->GetBinCenter(1), std::numeric_limits::infinity()), std::min(holderEvent.centrality, std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetXaxis()->GetBinCenter(hCentralityPtEtaShiftNSigmaPid->GetNbinsX()), -std::numeric_limits::infinity()))), std::max(std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetYaxis()->GetBinCenter(1), std::numeric_limits::infinity()), std::min(holderTrack.pt, std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetYaxis()->GetBinCenter(hCentralityPtEtaShiftNSigmaPid->GetNbinsY()), -std::numeric_limits::infinity()))), std::max(std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetZaxis()->GetBinCenter(1), std::numeric_limits::infinity()), std::min(holderTrack.eta, std::nextafter(hCentralityPtEtaShiftNSigmaPid->GetZaxis()->GetBinCenter(hCentralityPtEtaShiftNSigmaPid->GetNbinsZ()), -std::numeric_limits::infinity())))) : 0.; + } + + template + double getEfficiency(const std::vector& pCentralityPtEtaEfficiency) + { + if constexpr (doProcessingMc) { + return pCentralityPtEtaEfficiency[holderEvent.vzBinIndex]->GetBinContent(pCentralityPtEtaEfficiency[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), pCentralityPtEtaEfficiency[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderMcParticle.pt), pCentralityPtEtaEfficiency[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderMcParticle.eta)); + } + return pCentralityPtEtaEfficiency[holderEvent.vzBinIndex]->GetBinContent(pCentralityPtEtaEfficiency[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), pCentralityPtEtaEfficiency[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), pCentralityPtEtaEfficiency[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + } + + template + std::int32_t isPi() + { + if constexpr (doRequiringTof && doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcTofNSigmaPi) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcTofNSigmaKa), std::fabs(holderTrack.tpcTofNSigmaPr))))) { + return 0; + } + } + if constexpr (doRequiringTof && !doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcTofNSigmaPi) < cfgCutMaxAbsNSigmaPid.value)) { + return 0; + } + } + if constexpr (!doRequiringTof && doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcNSigmaPi) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcNSigmaKa), std::fabs(holderTrack.tpcNSigmaPr))))) { + return 0; + } + } + if constexpr (!doRequiringTof && !doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcNSigmaPi) < cfgCutMaxAbsNSigmaPid.value)) { + return 0; + } + } + return holderTrack.sign; + } + + template + std::int32_t isKa() + { + if constexpr (doRequiringTof && doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcTofNSigmaKa) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcTofNSigmaPi), std::fabs(holderTrack.tpcTofNSigmaPr))))) { + return 0; + } + } + if constexpr (doRequiringTof && !doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcTofNSigmaKa) < cfgCutMaxAbsNSigmaPid.value)) { + return 0; + } + } + if constexpr (!doRequiringTof && doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcNSigmaKa) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcNSigmaPi), std::fabs(holderTrack.tpcNSigmaPr))))) { + return 0; + } + } + if constexpr (!doRequiringTof && !doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcNSigmaKa) < cfgCutMaxAbsNSigmaPid.value)) { + return 0; + } + } + return holderTrack.sign; + } + + template + std::int32_t isPr() + { + if constexpr (doRequiringTof && doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcTofNSigmaPr) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcTofNSigmaPi), std::fabs(holderTrack.tpcTofNSigmaKa))))) { + return 0; + } + } + if constexpr (doRequiringTof && !doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcTofNSigmaPr) < cfgCutMaxAbsNSigmaPid.value)) { + return 0; + } + } + if constexpr (!doRequiringTof && doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcNSigmaPr) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcNSigmaPi), std::fabs(holderTrack.tpcNSigmaKa))))) { + return 0; + } + } + if constexpr (!doRequiringTof && !doRejectingOthers) { + if (!(std::fabs(holderTrack.tpcNSigmaPr) < cfgCutMaxAbsNSigmaPid.value)) { + return 0; + } + } + return holderTrack.sign; + } + + template + bool isGoodMomentum() + { + if constexpr (doProcessingMc) { + if (!(cfgCutMinPt.value < holderMcParticle.pt && holderMcParticle.pt < cfgCutMaxPt.value)) { + return false; + } + if (!(std::fabs(holderMcParticle.eta) < cfgCutMaxAbsEta.value)) { + return false; + } + } else { + if (!(cfgCutMinPt.value < holderTrack.pt && holderTrack.pt < cfgCutMaxPt.value)) { + return false; + } + if (!(std::fabs(holderTrack.eta) < cfgCutMaxAbsEta.value)) { + return false; + } + } + return true; + } + + template + bool isGoodTrack(const T& track) + { + if ((cfgFlagPvContributor.value && !track.isPVContributor())) { + return false; + } + if (!(track.itsNCls() > cfgCutMinItsNCls.value)) { + return false; + } + if (!(track.itsChi2NCl() < cfgCutMaxItsChi2NCls.value)) { + return false; + } + if (!(track.tpcNClsFound() > cfgCutMinTpcNCls.value)) { + return false; + } + if (!(track.tpcChi2NCl() < cfgCutMaxTpcChi2NCls.value)) { + return false; + } + if (!(track.tpcFractionSharedCls() < cfgCutMaxTpcNClsSharedRatio.value)) { + return false; + } + if (!(track.tpcNClsCrossedRows() > cfgCutMinTpcNClsCrossedRows.value)) { + return false; + } + if (!(track.tpcCrossedRowsOverFindableCls() > cfgCutMinTpcNClsCrossedRowsRatio.value)) { + return false; + } + if (!(std::fabs(track.dcaXY()) < cfgCutMaxAbsNSigmaDcaXy.value * (cfgParSigmaDcaXy.value[0] + cfgParSigmaDcaXy.value[1] * std::pow(track.pt(), cfgParSigmaDcaXy.value[2])))) { + return false; + } + if (!(std::fabs(track.dcaZ()) < cfgCutMaxAbsDcaZ.value)) { + return false; + } + return true; + } + + template + bool isGoodMcParticle(const MP& mcParticle) + { + if (!mcParticle.isPhysicalPrimary()) { + return false; + } + return true; + } + + template + bool initMcParticle(const MP& mcParticle) + { + holderMcParticle.clear(); + holderMcParticle.globalIndex = mcParticle.globalIndex(); + holderMcParticle.pdgCode = mcParticle.pdgCode(); + holderMcParticle.pt = mcParticle.pt(); + holderMcParticle.eta = mcParticle.eta(); + + if (!isGoodMcParticle(mcParticle)) { + return false; + } + + return true; + } + + template + bool initTrack(const T& track) + { + holderTrack.clear(); + holderTrack.sign = track.sign(); + holderTrack.p = track.p(); + holderTrack.pt = track.pt(); + holderTrack.eta = track.eta(); + holderTrack.phi = track.phi(); + holderTrack.pOverQ = holderTrack.p / holderTrack.sign; + holderTrack.ptOverQ = holderTrack.pt / holderTrack.sign; + holderTrack.rapidityPi = track.rapidity(constants::physics::MassPiPlus); + holderTrack.rapidityKa = track.rapidity(constants::physics::MassKPlus); + holderTrack.rapidityPr = track.rapidity(constants::physics::MassProton); + holderTrack.hasTpcPid = (track.hasTPC() && track.tpcSignal() > 0.); + holderTrack.tpcNSigmaPi = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPi() - getShiftNSigmaPid(cfgFlagRecalibrationNSigmaPi.value, holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiP, holderCcdb.hCentralityPtEtaShiftTpcNSigmaPiM)); + holderTrack.tpcNSigmaKa = HolderTrack::truncateNSigmaPid(track.tpcNSigmaKa() - getShiftNSigmaPid(cfgFlagRecalibrationNSigmaKa.value, holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaP, holderCcdb.hCentralityPtEtaShiftTpcNSigmaKaM)); + holderTrack.tpcNSigmaPr = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPr() - getShiftNSigmaPid(cfgFlagRecalibrationNSigmaPr.value, holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrP, holderCcdb.hCentralityPtEtaShiftTpcNSigmaPrM)); + holderTrack.hasTofPid = (track.hasTOF() && track.beta() > 0.); + holderTrack.tofNSigmaPi = HolderTrack::truncateNSigmaPid(track.tofNSigmaPi() - getShiftNSigmaPid(cfgFlagRecalibrationNSigmaPi.value, holderCcdb.hCentralityPtEtaShiftTofNSigmaPiP, holderCcdb.hCentralityPtEtaShiftTofNSigmaPiM)); + holderTrack.tofNSigmaKa = HolderTrack::truncateNSigmaPid(track.tofNSigmaKa() - getShiftNSigmaPid(cfgFlagRecalibrationNSigmaKa.value, holderCcdb.hCentralityPtEtaShiftTofNSigmaKaP, holderCcdb.hCentralityPtEtaShiftTofNSigmaKaM)); + holderTrack.tofNSigmaPr = HolderTrack::truncateNSigmaPid(track.tofNSigmaPr() - getShiftNSigmaPid(cfgFlagRecalibrationNSigmaPr.value, holderCcdb.hCentralityPtEtaShiftTofNSigmaPrP, holderCcdb.hCentralityPtEtaShiftTofNSigmaPrM)); + holderTrack.tpcTofNSigmaPi = HolderTrack::truncateNSigmaPid(std::sqrt(std::pow(holderTrack.tpcNSigmaPi, 2.) + std::pow(holderTrack.tofNSigmaPi, 2.))); + holderTrack.tpcTofNSigmaKa = HolderTrack::truncateNSigmaPid(std::sqrt(std::pow(holderTrack.tpcNSigmaKa, 2.) + std::pow(holderTrack.tofNSigmaKa, 2.))); + holderTrack.tpcTofNSigmaPr = HolderTrack::truncateNSigmaPid(std::sqrt(std::pow(holderTrack.tpcNSigmaPr, 2.) + std::pow(holderTrack.tofNSigmaPr, 2.))); + if constexpr (doProcessingMc) { + holderTrack.mcParticleId = track.mcParticleId(); + } + + if constexpr (doInitingEvent) { + holderEvent.nGlobalTracks++; + if (track.isPVContributor()) { + holderEvent.nPvContributors++; + } + holderEvent.meanDcaXy += track.dcaXY(); + holderEvent.meanSquareDcaXy += std::pow(track.dcaXY(), 2.); + holderEvent.meanDcaZ += track.dcaZ(); + holderEvent.meanSquareDcaZ += std::pow(track.dcaZ(), 2.); + if (holderTrack.hasTofPid) { + holderEvent.nTofBeta++; + } + } + + if constexpr (doInitingEvent) { + if (cfgFlagQaRun.value) { + hrQaRun.fill(HIST("QaRun/pRunIndexItsNCls"), holderEvent.runIndex, track.itsNCls()); + hrQaRun.fill(HIST("QaRun/pRunIndexItsChi2NCls"), holderEvent.runIndex, track.itsChi2NCl()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNCls"), holderEvent.runIndex, track.tpcNClsFound()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcChi2NCls"), holderEvent.runIndex, track.tpcChi2NCl()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsSharedRatio"), holderEvent.runIndex, track.tpcFractionSharedCls()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsCrossedRows"), holderEvent.runIndex, track.tpcNClsCrossedRows()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsCrossedRowsRatio"), holderEvent.runIndex, track.tpcCrossedRowsOverFindableCls()); + hrQaRun.fill(HIST("QaRun/pRunIndexDcaXy"), holderEvent.runIndex, track.dcaXY()); + hrQaRun.fill(HIST("QaRun/pRunIndexDcaZ"), holderEvent.runIndex, track.dcaZ()); + hrQaRun.fill(HIST("QaRun/pRunIndexPt"), holderEvent.runIndex, holderTrack.pt); + hrQaRun.fill(HIST("QaRun/pRunIndexEta"), holderEvent.runIndex, holderTrack.eta); + hrQaRun.fill(HIST("QaRun/pRunIndexPhi"), holderEvent.runIndex, holderTrack.phi); + if (holderTrack.hasTpcPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTpcDeDx"), holderEvent.runIndex, track.tpcSignal()); + if (std::fabs(holderTrack.tpcNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPi"), holderEvent.runIndex, holderTrack.tpcNSigmaPi); + } + if (std::fabs(holderTrack.tpcNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaKa"), holderEvent.runIndex, holderTrack.tpcNSigmaKa); + } + if (std::fabs(holderTrack.tpcNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPr"), holderEvent.runIndex, holderTrack.tpcNSigmaPr); + } + } + if (holderTrack.hasTofPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTofInverseBeta"), holderEvent.runIndex, 1. / track.beta()); + if (std::fabs(holderTrack.tofNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPi"), holderEvent.runIndex, holderTrack.tofNSigmaPi); + } + if (std::fabs(holderTrack.tofNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaKa"), holderEvent.runIndex, holderTrack.tofNSigmaKa); + } + if (std::fabs(holderTrack.tofNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPr"), holderEvent.runIndex, holderTrack.tofNSigmaPr); + } + } + } + } + + if constexpr (!doInitingEvent) { + if (cfgFlagQaTrack.value) { + hrQaTrack.fill(HIST("QaTrack/hItsNCls"), track.itsNCls()); + hrQaTrack.fill(HIST("QaTrack/hItsChi2NCls"), track.itsChi2NCl()); + hrQaTrack.fill(HIST("QaTrack/hTpcNClsNClsSharedNClsFindableNClsCrossedRows"), track.tpcNClsFound(), track.tpcNClsShared(), track.tpcNClsFindable(), track.tpcNClsCrossedRows()); + hrQaTrack.fill(HIST("QaTrack/hTpcChi2NCls"), track.tpcChi2NCl()); + hrQaTrack.fill(HIST("QaTrack/hPtDcaXy"), holderTrack.pt, track.dcaXY()); + hrQaTrack.fill(HIST("QaTrack/hPtDcaZ"), holderTrack.pt, track.dcaZ()); + if (track.isPVContributor()) { + hrQaTrack.fill(HIST("QaTrack/hPtDcaXy_pvContributor"), holderTrack.pt, track.dcaXY()); + hrQaTrack.fill(HIST("QaTrack/hPtDcaZ_pvContributor"), holderTrack.pt, track.dcaZ()); + } + } + } + + if (!isGoodTrack(track)) { + return false; + } + + if constexpr (doProcessingMc && doInitingEvent) { + if ((cfgFlagCalculationEfficiencyPi.value || cfgFlagCalculationEfficiencyKa.value || cfgFlagCalculationEfficiencyPr.value) && holderTrack.hasTpcPid) { + if (cfgFlagCalculationEfficiencyPi.value) { + switch (isPi()) { + case 1: + holderEvent.mcParticleIndicesMatchedTpcPiP.push_back(holderTrack.mcParticleId); + break; + case -1: + holderEvent.mcParticleIndicesMatchedTpcPiM.push_back(holderTrack.mcParticleId); + break; + } + } + + if (cfgFlagCalculationEfficiencyKa.value) { + switch (isKa()) { + case 1: + holderEvent.mcParticleIndicesMatchedTpcKaP.push_back(holderTrack.mcParticleId); + break; + case -1: + holderEvent.mcParticleIndicesMatchedTpcKaM.push_back(holderTrack.mcParticleId); + break; + } + } + + if (cfgFlagCalculationEfficiencyPr.value) { + switch (isPr()) { + case 1: + holderEvent.mcParticleIndicesMatchedTpcPrP.push_back(holderTrack.mcParticleId); + break; + case -1: + holderEvent.mcParticleIndicesMatchedTpcPrM.push_back(holderTrack.mcParticleId); + break; + } + } + + if (holderTrack.hasTofPid) { + if (cfgFlagCalculationEfficiencyPi.value) { + switch (isPi()) { + case 1: + holderEvent.mcParticleIndicesMatchedTpcTofPiP.push_back(holderTrack.mcParticleId); + break; + case -1: + holderEvent.mcParticleIndicesMatchedTpcTofPiM.push_back(holderTrack.mcParticleId); + break; + } + } + + if (cfgFlagCalculationEfficiencyKa.value) { + switch (isKa()) { + case 1: + holderEvent.mcParticleIndicesMatchedTpcTofKaP.push_back(holderTrack.mcParticleId); + break; + case -1: + holderEvent.mcParticleIndicesMatchedTpcTofKaM.push_back(holderTrack.mcParticleId); + break; + } + } + + if (cfgFlagCalculationEfficiencyPr.value) { + switch (isPr()) { + case 1: + holderEvent.mcParticleIndicesMatchedTpcTofPrP.push_back(holderTrack.mcParticleId); + break; + case -1: + holderEvent.mcParticleIndicesMatchedTpcTofPrM.push_back(holderTrack.mcParticleId); + break; + } + } + } + } + } + + if constexpr (!doInitingEvent) { + if (cfgFlagQaAcceptance.value && ((holderTrack.eta > 0. && holderEvent.vz > cfgCutMaxAbsVertexZ.value - 0.5) || (holderTrack.eta < 0. && holderEvent.vz < -cfgCutMaxAbsVertexZ.value + 0.5)) && holderTrack.hasTpcPid) { + hrQaAcceptance.fill(HIST("QaAcceptance/hEtaPt_tpc"), holderTrack.eta, holderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hPhi_tpc"), holderTrack.phi); + if (std::abs(isPi()) == 1) { + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcPi"), holderTrack.rapidityPi, holderTrack.pt); + } + if (std::abs(isKa()) == 1) { + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcKa"), holderTrack.rapidityKa, holderTrack.pt); + } + if (std::abs(isPr()) == 1) { + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcPr"), holderTrack.rapidityPr, holderTrack.pt); + } + if (holderTrack.hasTofPid) { + hrQaAcceptance.fill(HIST("QaAcceptance/hEtaPt_tpcTof"), holderTrack.eta, holderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hPhi_tpcTof"), holderTrack.phi); + if (std::abs(isPi()) == 1) { + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofPi"), holderTrack.rapidityPi, holderTrack.pt); + } + if (std::abs(isKa()) == 1) { + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofKa"), holderTrack.rapidityKa, holderTrack.pt); + } + if (std::abs(isPr()) == 1) { + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofPr"), holderTrack.rapidityPr, holderTrack.pt); + } + } + } + + if (cfgFlagQaPid.value && holderTrack.hasTpcPid) { + hrQaPid.fill(HIST("QaPid/hCentralityPOverQEtaTpcLnDeDx"), holderEvent.centrality, holderTrack.pOverQ, holderTrack.eta, std::log(track.tpcSignal())); + if (std::fabs(holderTrack.tofNSigmaPi) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTpcNSigmaPi_tofPi"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tpcNSigmaPi); + } + if (std::fabs(holderTrack.tofNSigmaKa) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTpcNSigmaKa_tofKa"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tpcNSigmaKa); + } + if (std::fabs(holderTrack.tofNSigmaPr) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTpcNSigmaPr_tofPr"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tpcNSigmaPr); + } + if (track.beta() > 0.) { + hrQaPid.fill(HIST("QaPid/hCentralityPOverQEtaTofInverseBeta"), holderEvent.centrality, holderTrack.pOverQ, holderTrack.eta, 1. / track.beta()); + if (std::fabs(holderTrack.tpcNSigmaPi) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTofNSigmaPi_tpcPi"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tofNSigmaPi); + } + if (std::fabs(holderTrack.tpcNSigmaKa) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTofNSigmaKa_tpcKa"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tofNSigmaKa); + } + if (std::fabs(holderTrack.tpcNSigmaPr) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTofNSigmaPr_tpcPr"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tofNSigmaPr); + } + } + } + } + + return true; + } + + template + bool initEvent(const C& collision, const Ts& tracks) + { + holderEvent.clear(); + holderEvent.vz = collision.posZ(); + holderEvent.vzBinIndex = std::llrint(std::floor(holderEvent.vz - std::floor(-cfgCutMaxAbsVertexZ.value))); + switch (cfgIndexDefinitionCentrality) { + default: + holderEvent.centrality = collision.centFV0A(); + break; + case static_cast(CentralityDefinitionIndices::kFT0M): + holderEvent.centrality = collision.centFT0M(); + break; + case static_cast(CentralityDefinitionIndices::kFT0A): + holderEvent.centrality = collision.centFT0A(); + break; + case static_cast(CentralityDefinitionIndices::kFT0C): + holderEvent.centrality = collision.centFT0C(); + break; + } + + hrCounter.fill(HIST("hNEvents"), 0.); + + if (!collision.has_foundBC()) { + hrCounter.fill(HIST("hNEvents"), 2.); + return false; + } + + const auto& bc = collision.template bc_as(); + holderEvent.runNumber = bc.runNumber(); + holderEvent.runIndex = std::distance(holderCcdb.runNumbers.begin(), std::ranges::find(holderCcdb.runNumbers, holderEvent.runNumber)); + + if (std::ranges::find(holderCcdb.runNumbers, holderEvent.runNumber) == holderCcdb.runNumbers.end() || std::ranges::find(holderCcdb.runNumbersBad, holderEvent.runNumber) != holderCcdb.runNumbersBad.end()) { + hrCounter.fill(HIST("hNEvents"), 2.); + return false; + } + + for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { + if (((cfgFlagSelectionEvent.value >> iEvSel) & 1) && !collision.selection_bit(iEvSel)) { + hrCounter.fill(HIST("hNEvents"), 3); + hrCounter.fill(HIST("hNEvents"), 10 + iEvSel); + return false; + } + } + + if (cfgFlagQaEvent.value) { + hrQaEvent.fill(HIST("QaEvent/hRunIndexVxVy"), holderEvent.runIndex, collision.posX(), collision.posY()); + hrQaEvent.fill(HIST("QaEvent/hRunIndexVz"), holderEvent.runIndex, holderEvent.vz); + } + + if (!(std::fabs(holderEvent.vz) < cfgCutMaxAbsVertexZ.value)) { + hrCounter.fill(HIST("hNEvents"), 4); + return false; + } + + if (cfgFlagQaRun.value) { + hrQaRun.fill(HIST("QaRun/pRunIndexVx"), holderEvent.runIndex, collision.posX()); + hrQaRun.fill(HIST("QaRun/pRunIndexVy"), holderEvent.runIndex, collision.posY()); + hrQaRun.fill(HIST("QaRun/pRunIndexVz"), holderEvent.runIndex, holderEvent.vz); + hrQaRun.fill(HIST("QaRun/pRunIndexMultFv0a"), holderEvent.runIndex, collision.multZeqFV0A()); + hrQaRun.fill(HIST("QaRun/pRunIndexMultFt0a"), holderEvent.runIndex, collision.multZeqFT0A()); + hrQaRun.fill(HIST("QaRun/pRunIndexMultFt0c"), holderEvent.runIndex, collision.multZeqFT0C()); + } + + for (const auto& track : tracks) { + if (!track.has_collision()) { + continue; + } + + initTrack(track); + } + if (holderEvent.nGlobalTracks > 0.) { + holderEvent.meanDcaXy /= holderEvent.nGlobalTracks; + holderEvent.meanSquareDcaXy /= holderEvent.nGlobalTracks; + holderEvent.meanDcaZ /= holderEvent.nGlobalTracks; + holderEvent.meanSquareDcaZ /= holderEvent.nGlobalTracks; + } + + if (cfgFlagQaRun.value) { + hrQaRun.fill(HIST("QaRun/pRunIndexNGlobalTracks"), holderEvent.runIndex, holderEvent.nGlobalTracks); + hrQaRun.fill(HIST("QaRun/pRunIndexNPvContributors"), holderEvent.runIndex, holderEvent.nPvContributors); + if (holderEvent.nGlobalTracks > 0) { + hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaXy"), holderEvent.runIndex, holderEvent.meanDcaXy); + hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaXy"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaXy - std::pow(holderEvent.meanDcaXy, 2.))); + hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaZ"), holderEvent.runIndex, holderEvent.meanDcaZ); + hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaZ"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaZ - std::pow(holderEvent.meanDcaZ, 2.))); + } + hrQaRun.fill(HIST("QaRun/pRunIndexNTofBeta"), holderEvent.runIndex, holderEvent.nTofBeta); + } + + if (cfgFlagQaEvent.value) { + hrQaEvent.fill(HIST("QaEvent/hRunIndexNPvContributorsNGlobalTracks"), holderEvent.runIndex, holderEvent.nPvContributors, holderEvent.nGlobalTracks); + if (holderEvent.nGlobalTracks > 0) { + hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaXy"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaXy); + hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaZ"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaZ); + } + hrQaEvent.fill(HIST("QaEvent/hRunIndexNTofBetaNGlobalTracks"), holderEvent.runIndex, holderEvent.nTofBeta, holderEvent.nGlobalTracks); + } + + if (!(holderEvent.nPvContributors - holderEvent.nGlobalTracks > cfgCutMinDeviationNPvContributors.value)) { + hrCounter.fill(HIST("hNEvents"), 5); + return false; + } + + hrCounter.fill(HIST("hNEvents"), 1.); + + if (cfgFlagQaEvent.value) { + if (holderEvent.nGlobalTracks > 0) { + hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaXy_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaXy); + hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaZ_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaZ); + } + hrQaEvent.fill(HIST("QaEvent/hRunIndexNTofBetaNGlobalTracks_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nTofBeta, holderEvent.nGlobalTracks); + } + + if (cfgFlagQaCentrality.value) { + hrQaCentrality.fill(HIST("QaCentrality/hCentralityFv0a"), collision.centFV0A(), collision.multZeqFV0A()); + hrQaCentrality.fill(HIST("QaCentrality/hCentralityFt0a"), collision.centFT0A(), collision.multZeqFT0A()); + hrQaCentrality.fill(HIST("QaCentrality/hCentralityFt0c"), collision.centFT0C(), collision.multZeqFT0C()); + hrQaCentrality.fill(HIST("QaCentrality/hCentralityFt0m"), collision.centFT0M(), collision.multZeqFT0A() + collision.multZeqFT0C()); + } + + return true; + } + + template + void calculateFluctuation() + { + if (isGoodMomentum() && holderTrack.hasTpcPid) { + if (cfgFlagCalculationFluctuationCh.value) { + if (holderTrack.pt < cfgThresholdPtTofPi.value) { + switch (isPi()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcPiP); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcPiM); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isPi()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } + if (holderTrack.pt < cfgThresholdPtTofKa.value) { + switch (isKa()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcKaP); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcKaM); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isKa()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } + if (holderTrack.pt < cfgThresholdPtTofPr.value) { + switch (isPr()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcPrP); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcPrM); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isPr()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } + } + + if (cfgFlagCalculationFluctuationKa.value) { + if (holderTrack.pt < cfgThresholdPtTofKa.value) { + switch (isKa()) { + case 1: { + holderEvent.nKaP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcKaP); + + fluctuationCalculatorTrackKaP->fill(1., efficiency); + fluctuationCalculatorTrackKaT->fill(1., efficiency); + fluctuationCalculatorTrackKaN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nKaM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcKaM); + + fluctuationCalculatorTrackKaM->fill(1., efficiency); + fluctuationCalculatorTrackKaT->fill(1., efficiency); + fluctuationCalculatorTrackKaN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isKa()) { + case 1: { + holderEvent.nKaP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP); + + fluctuationCalculatorTrackKaP->fill(1., efficiency); + fluctuationCalculatorTrackKaT->fill(1., efficiency); + fluctuationCalculatorTrackKaN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nKaM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM); + + fluctuationCalculatorTrackKaM->fill(1., efficiency); + fluctuationCalculatorTrackKaT->fill(1., efficiency); + fluctuationCalculatorTrackKaN->fill(-1., efficiency); + } break; + } + } + } + + if (cfgFlagCalculationFluctuationPr.value) { + if (holderTrack.pt < cfgThresholdPtTofPr.value) { + switch (isPr()) { + case 1: { + holderEvent.nPrP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcPrP); + + fluctuationCalculatorTrackPrP->fill(1., efficiency); + fluctuationCalculatorTrackPrT->fill(1., efficiency); + fluctuationCalculatorTrackPrN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nPrM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcPrM); + + fluctuationCalculatorTrackPrM->fill(1., efficiency); + fluctuationCalculatorTrackPrT->fill(1., efficiency); + fluctuationCalculatorTrackPrN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isPr()) { + case 1: { + holderEvent.nPrP++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP); + + fluctuationCalculatorTrackPrP->fill(1., efficiency); + fluctuationCalculatorTrackPrT->fill(1., efficiency); + fluctuationCalculatorTrackPrN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nPrM++; + + const double efficiency = getEfficiency(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM); + + fluctuationCalculatorTrackPrM->fill(1., efficiency); + fluctuationCalculatorTrackPrT->fill(1., efficiency); + fluctuationCalculatorTrackPrN->fill(-1., efficiency); + } break; + } + } + } + } + } + + void processRaw(const soa::Filtered::iterator& collision, const soa::Filtered& tracks, const aod::BCsWithTimestamps&) + { + if (!initEvent(collision, tracks)) { + return; + } + + if (!cfgFlagQaTrack.value && !cfgFlagQaAcceptance.value && !cfgFlagQaPid.value && !cfgFlagCalculationFluctuationCh.value && !cfgFlagCalculationFluctuationKa.value && !cfgFlagCalculationFluctuationPr.value) { + return; + } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + holderEvent.subgroupIndex = gRandom->Integer(cfgNSubgroups.value); + if (cfgFlagCalculationFluctuationCh.value) { + fluctuationCalculatorTrackChP->init(); + fluctuationCalculatorTrackChM->init(); + fluctuationCalculatorTrackChT->init(); + fluctuationCalculatorTrackChN->init(); + } + if (cfgFlagCalculationFluctuationKa.value) { + fluctuationCalculatorTrackKaP->init(); + fluctuationCalculatorTrackKaM->init(); + fluctuationCalculatorTrackKaT->init(); + fluctuationCalculatorTrackKaN->init(); + } + if (cfgFlagCalculationFluctuationPr.value) { + fluctuationCalculatorTrackPrP->init(); + fluctuationCalculatorTrackPrM->init(); + fluctuationCalculatorTrackPrT->init(); + fluctuationCalculatorTrackPrN->init(); + } + } + + for (const auto& track : tracks) { + if (!track.has_collision() || !initTrack(track)) { + continue; + } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + calculateFluctuation(); + } + } + + if (cfgFlagCalculationFluctuationCh.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNChPNChM"), holderEvent.centrality, holderEvent.nChP, holderEvent.nChM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChN->getProductFast(iOrderVector)); + } + } + if (cfgFlagCalculationFluctuationKa.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNKaPNKaM"), holderEvent.centrality, holderEvent.nKaP, holderEvent.nKaM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaN->getProductFast(iOrderVector)); + } + } + if (cfgFlagCalculationFluctuationPr.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNPrPNPrM"), holderEvent.centrality, holderEvent.nPrP, holderEvent.nPrM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrN->getProductFast(iOrderVector)); + } + } + } + PROCESS_SWITCH(PartNumFluc, processRaw, "Process raw data", true); + + void processMc(const soa::Filtered::iterator& mcCollision, const aod::McParticles& mcParticles, const soa::SmallGroups& collisions, const soa::Filtered& tracksUngrouped, const aod::BCsWithTimestamps&) + { + for (const auto& collision : collisions) { + if (collision.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + + const auto& tracks = tracksUngrouped.sliceBy(presliceTracksPerCollision, collision.globalIndex()); + + if (!initEvent(collision, tracks)) { + continue; + } + + if (cfgFlagCalculationEfficiencyPi.value || cfgFlagCalculationEfficiencyKa.value || cfgFlagCalculationEfficiencyPr.value || cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + for (const auto& mcParticle : mcParticles) { + if (!initMcParticle(mcParticle)) { + continue; + } + + switch (holderMcParticle.pdgCode) { + case PDG_t::kPiPlus: + if (cfgFlagCalculationEfficiencyPi.value) { + pCentralityPtEtaEfficiencyTpcPiP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcPiP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcPiP.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofPiP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofPiP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofPiP.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value && isGoodMomentum()) { + holderEvent.nChPMc++; + } + break; + case PDG_t::kPiMinus: + if (cfgFlagCalculationEfficiencyPi.value) { + pCentralityPtEtaEfficiencyTpcPiM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcPiM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcPiM.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofPiM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofPiM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofPiM.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value && isGoodMomentum()) { + holderEvent.nChMMc++; + } + break; + case PDG_t::kKPlus: + if (cfgFlagCalculationEfficiencyKa.value) { + pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcKaP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcKaP.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofKaP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofKaP.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value && isGoodMomentum()) { + holderEvent.nChPMc++; + } + if (cfgFlagCalculationFluctuationKa.value && isGoodMomentum()) { + holderEvent.nKaPMc++; + } + break; + case PDG_t::kKMinus: + if (cfgFlagCalculationEfficiencyKa.value) { + pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcKaM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcKaM.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofKaM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofKaM.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value && isGoodMomentum()) { + holderEvent.nChMMc++; + } + if (cfgFlagCalculationFluctuationKa.value && isGoodMomentum()) { + holderEvent.nKaMMc++; + } + break; + case PDG_t::kProton: + if (cfgFlagCalculationEfficiencyPr.value) { + pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcPrP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcPrP.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofPrP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofPrP.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value && isGoodMomentum()) { + holderEvent.nChPMc++; + } + if (cfgFlagCalculationFluctuationPr.value && isGoodMomentum()) { + holderEvent.nPrPMc++; + } + break; + case PDG_t::kProtonBar: + if (cfgFlagCalculationEfficiencyPr.value) { + pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcPrM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcPrM.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofPrM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofPrM.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value && isGoodMomentum()) { + holderEvent.nChMMc++; + } + if (cfgFlagCalculationFluctuationPr.value && isGoodMomentum()) { + holderEvent.nPrMMc++; + } + break; + } + } + + if (cfgFlagCalculationFluctuationCh.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNChPNChM_mc"), holderEvent.centrality, holderEvent.nChPMc, holderEvent.nChMMc); + } + if (cfgFlagCalculationFluctuationKa.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNKaPNKaM_mc"), holderEvent.centrality, holderEvent.nKaPMc, holderEvent.nKaMMc); + } + if (cfgFlagCalculationFluctuationPr.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNPrPNPrM_mc"), holderEvent.centrality, holderEvent.nPrPMc, holderEvent.nPrMMc); + } + } + + if ((cfgFlagCalculationPurityPi.value || cfgFlagCalculationPurityKa.value || cfgFlagCalculationPurityPr.value || cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value)) { + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + holderEvent.subgroupIndex = gRandom->Integer(cfgNSubgroups.value); + if (cfgFlagCalculationFluctuationCh.value) { + fluctuationCalculatorTrackChP->init(); + fluctuationCalculatorTrackChM->init(); + fluctuationCalculatorTrackChT->init(); + fluctuationCalculatorTrackChN->init(); + } + if (cfgFlagCalculationFluctuationKa.value) { + fluctuationCalculatorTrackKaP->init(); + fluctuationCalculatorTrackKaM->init(); + fluctuationCalculatorTrackKaT->init(); + fluctuationCalculatorTrackKaN->init(); + } + if (cfgFlagCalculationFluctuationPr.value) { + fluctuationCalculatorTrackPrP->init(); + fluctuationCalculatorTrackPrM->init(); + fluctuationCalculatorTrackPrT->init(); + fluctuationCalculatorTrackPrN->init(); + } + } + + for (const auto& track : tracks) { + if (!track.has_collision() || !track.has_mcParticle()) { + continue; + } + + const auto& mcParticle = track.template mcParticle_as(); + if (!mcParticle.has_mcCollision()) { + continue; + } + + if (!initTrack(track) || !initMcParticle(mcParticle)) { + continue; + } + + if ((cfgFlagCalculationPurityPi.value || cfgFlagCalculationPurityKa.value || cfgFlagCalculationPurityPr.value) && holderTrack.hasTpcPid) { + if (cfgFlagCalculationPurityPi.value) { + switch (isPi()) { + case 1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcPiP"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiPlus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcPiP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiPlus ? 1. : 0.); + break; + case -1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcPiM"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiMinus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcPiM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiMinus ? 1. : 0.); + break; + } + } + + if (cfgFlagCalculationPurityKa.value) { + switch (isKa()) { + case 1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcKaP"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKPlus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcKaP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKPlus ? 1. : 0.); + break; + case -1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcKaM"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKMinus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcKaM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKMinus ? 1. : 0.); + break; + } + } + + if (cfgFlagCalculationPurityPr.value) { + switch (isPr()) { + case 1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcPrP"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProton ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcPrP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProton ? 1. : 0.); + break; + case -1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcPrM"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProtonBar ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcPrM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProtonBar ? 1. : 0.); + break; + } + } + + if (holderTrack.hasTofPid) { + if (cfgFlagCalculationPurityPi.value) { + switch (isPi()) { + case 1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcTofPiP"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiPlus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofPiP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiPlus ? 1. : 0.); + break; + case -1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcTofPiM"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiMinus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofPiM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiMinus ? 1. : 0.); + break; + } + } + + if (cfgFlagCalculationPurityKa.value) { + switch (isKa()) { + case 1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcTofKaP"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKPlus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofKaP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKPlus ? 1. : 0.); + break; + case -1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcTofKaM"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKMinus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofKaM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKMinus ? 1. : 0.); + break; + } + } + + if (cfgFlagCalculationPurityPr.value) { + switch (isPr()) { + case 1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcTofPrP"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProton ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofPrP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProton ? 1. : 0.); + break; + case -1: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPEtaPurityTpcTofPrM"), holderEvent.centrality, holderTrack.p, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProtonBar ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofPrM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProtonBar ? 1. : 0.); + break; + } + } + } + } + + if ((cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value)) { + calculateFluctuation(); + } + } + + if (cfgFlagCalculationFluctuationCh.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNChPNChM"), holderEvent.centrality, holderEvent.nChP, holderEvent.nChM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChN->getProductFast(iOrderVector)); + } + } + if (cfgFlagCalculationFluctuationKa.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNKaPNKaM"), holderEvent.centrality, holderEvent.nKaP, holderEvent.nKaM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaN->getProductFast(iOrderVector)); + } + } + if (cfgFlagCalculationFluctuationPr.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNPrPNPrM"), holderEvent.centrality, holderEvent.nPrP, holderEvent.nPrM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrN->getProductFast(iOrderVector)); + } + } + } + } + } + PROCESS_SWITCH(PartNumFluc, processMc, "Process MC data", false); +}; + +WorkflowSpec defineDataProcessing(const ConfigContext& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx b/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx new file mode 100644 index 00000000000..a3e9bd56fcd --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx @@ -0,0 +1,2345 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file radialFlowDecorr.cxx +/// \brief Analysis task for event-by-event radial-flow decorrelation measurement. +/// \author Somadutta Bhatta + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" + +#include "TDirectory.h" +#include "TFile.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TH3F.h" +#include "TMath.h" +#include "TProfile.h" +#include "TProfile2D.h" +#include "TProfile3D.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace constants::math; + +struct RadialFlowDecorr { + + static constexpr int KIntM = 3; + static constexpr int KIntK = 3; + + static constexpr int KNEta = 17; + static constexpr int KNpT = 3; + + static constexpr float KFloatEpsilon = 1e-6f; + static constexpr int KPiPlus = 211; + static constexpr int KKPlus = 321; + static constexpr int KProton = 2212; + + static constexpr float KCentTestMin = 10.f; + static constexpr float KCentTestMaxLo = 60.f; + static constexpr float KCentTestMaxHi = 70.f; + static constexpr float KCentCovCut = 1.0f; + static constexpr float KBinOffset = 0.5f; + static constexpr float KHalf = 0.5f; + static constexpr float KPhiMin = 0.f; + + static constexpr int KNbinsZvtx = 240; + static constexpr float KZvtxMin = -12.f; + static constexpr float KZvtxMax = 12.f; + static constexpr int KNbinsP = 100; + static constexpr float KPMin = 0.f; + static constexpr float KPMax = 10.f; + static constexpr int KNbinsPt = 200; + static constexpr float KPtMin = 0.f; + static constexpr float KPtMax = 10.f; + static constexpr int KNbinsEta = 120; + static constexpr float KEtaMin = -1.2f; + static constexpr float KEtaMax = 1.2f; + static constexpr int KNbinsPhi = 64; + static constexpr float KEtaAxisMin = -0.8f; + static constexpr float KEtaAxisMax = 0.8f; + static constexpr int KNbinsPhiFine = 30; + static constexpr int KNbinsPtRes = 50; + static constexpr float KPtResMax = 1.f; + static constexpr int KNbinsEtaRes = 100; + static constexpr float KEtaResMax = 0.5f; + static constexpr int KNbinsVz = 80; + static constexpr float KVzMin = -40.f; + static constexpr float KVzMax = 40.f; + static constexpr float KVzResMax = 20.f; + static constexpr int KNbinsEtaFine = 20; + static constexpr float KEtaFineMax = 1.f; + static constexpr int KNbinsDca = 400; + static constexpr float KDcaMax = 0.2f; + static constexpr int KNbinsPtCoarse = 50; + static constexpr float KPtMinDefault = 0.2f; + static constexpr float KPtMidMax = 3.0f; + static constexpr float KPtHighMax = 5.0f; + static constexpr float KPtFullMax = 10.0f; + static constexpr float KCentMax = 90; + enum PID { kInclusive = 0, + kCombinedPID, + kNumPID }; + enum ECentralityEstimator { + kCentFT0C = 1, + kCentFT0A = 2, + kCentFT0M = 3, + kCentFV0A = 4 + }; + static constexpr float KinvalidCentrality = -1.0f; + const std::vector pidSuffix = {"", "_PID"}; + + const std::vector etaLw = { + -0.8, + -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}; + const std::vector etaUp = { + 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}; + + const std::vector pTLw = {KPtMinDefault, KPtMinDefault, KPtMinDefault}; + const std::vector pTUp = {KPtMidMax, KPtHighMax, KPtFullMax}; + + Configurable cfgVtxZCut{"cfgVtxZCut", 10.f, "z-vertex range"}; + Configurable cfgPtMin{"cfgPtMin", 0.2f, "min pT"}; + Configurable cfgPtMax{"cfgPtMax", 10.0f, "max pT"}; + Configurable cfgEtaCut{"cfgEtaCut", 0.8f, "|η| cut"}; + Configurable cfgDCAXY{"cfgDCAXY", 2.4f, "DCAxy cut"}; + Configurable cfgDCAZ{"cfgDCAZ", 3.2f, "DCAz cut"}; + Configurable cfgTPCClsMin{"cfgTPCClsMin", 70.f, "min TPC clusters"}; + Configurable cfgChi2TPCMax{"cfgChi2TPCMax", 4.0f, "max TPC χ²"}; + Configurable cfgPIDnSigmaCut{"cfgPIDnSigmaCut", 3.f, "TPC PID |nσ| cut"}; + + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutTpcChi2NCl{"cfgCutTpcChi2NCl", 2.5f, "Maximum TPCchi2NCl"}; + Configurable cfgCutItsChi2NCl{"cfgCutItsChi2NCl", 36.0f, "Maximum ITSchi2NCl"}; + Configurable cfgCutTracKDcaMaxZ{"cfgCutTracKDcaMaxZ", 2.0f, "Maximum DcaZ"}; + Configurable cfgCutTracKDcaMaxXY{"cfgCutTracKDcaMaxXY", 0.2f, "Maximum DcaZ"}; + + 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 cfgCutPtUpperTPC{"cfgCutPtUpperTPC", 0.6f, "Upper pT cut for PID using TPC only"}; + Configurable cfgnSigmaOtherParticles{"cfgnSigmaOtherParticles", 3.0f, "PID nSigma cut to remove other particles (default:3)"}; + 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 cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut"}; + Configurable cfgCutPtLowerProt{"cfgCutPtLowerProt", 0.2f, "Lower pT cut"}; + Configurable cfgCutPtUpper{"cfgCutPtUpper", 10.0f, "Higher pT cut for inclusive hadron analysis"}; + Configurable cfgCutPtUpperPID{"cfgCutPtUpperPID", 6.0f, "Higher pT cut for identified particle analysis"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "absolute Eta cut"}; + Configurable cfgCutEtaLeft{"cfgCutEtaLeft", 0.8f, "Left end of eta gap"}; + Configurable cfgCutEtaRight{"cfgCutEtaRight", 0.8f, "Right end of eta gap"}; + Configurable cfgNSubsample{"cfgNSubsample", 10, "Number of subsamples"}; + Configurable cfgCentralityChoice{"cfgCentralityChoice", 1, "Which centrality estimator? 1-->FT0C, 2-->FT0A, 3-->FT0M, 4-->FV0A"}; + Configurable cfgEvSelkNoSameBunchPileup{"cfgEvSelkNoSameBunchPileup", true, "Pileup removal"}; + Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Remove time interval with dead ITS zone"}; + Configurable cfgEvSelkNoITSROFrameBorder{"cfgEvSelkNoITSROFrameBorder", true, "ITSROFrame border event selection cut"}; + Configurable cfgEvSelkNoTimeFrameBorder{"cfgEvSelkNoTimeFrameBorder", true, "TimeFrame border event selection cut"}; + + Service ccdb; + Service pdg; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + std::array hEff{}; + std::array hFake{}; + std::array hWeightMap3D{}; + + TProfile3D* pmeanTruNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanRecoNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanRecoMatchedNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanRecoEffcorrNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanRecoMatchedEffcorrNchEtabinPtbinStep2 = nullptr; + + TProfile3D* pmeanEtTruNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanEtRecoNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanEtRecoMatchedNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanEtRecoEffcorrNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanEtRecoMatchedEffcorrNchEtabinPtbinStep2 = nullptr; + + TProfile3D* pmeanNchEtabinPtbinStep2 = nullptr; + TProfile3D* pmeanEtNchEtabinPtbinStep2 = nullptr; + + template + bool isEventSelected(const T& col) + { + if (!col.sel8()) + return false; + if (std::abs(col.posZ()) > cfgCutVertex) + return false; + if (cfgEvSelkNoSameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return false; + if (cfgEvSelkNoITSROFrameBorder && !col.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + return false; + if (cfgEvSelkNoTimeFrameBorder && !col.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + return false; + return true; + } + + template + bool isTrackSelected(const T& trk) + { + if (trk.sign() == 0) + return false; + if (!trk.has_collision()) + return false; + if (!trk.isPVContributor()) + return false; + if (!(trk.itsNCls() > cfgITScluster)) + return false; + if (!(trk.tpcNClsFound() >= cfgTPCcluster)) + return false; + if (!(trk.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) + return false; + + if (trk.pt() < cfgCutPtLower || trk.pt() > cfgCutPtUpper || std::abs(trk.eta()) > cfgCutEta) + return false; + if (std::abs(trk.dcaXY()) > cfgCutTracKDcaMaxXY || std::abs(trk.dcaZ()) > cfgCutTracKDcaMaxZ) + return false; + return true; + } + + template + bool isParticleSelected(const T& particle) + { + auto* pd = pdg->GetParticle(particle.pdgCode()); + if (!pd) + return false; + // if (dpt::isStrangeBaryonPDG(particle.pdgCode())) return false; + if (std::abs(pd->Charge()) == 0) + return false; + if (particle.pt() < cfgCutPtLower || particle.pt() > cfgCutPtUpper || std::abs(particle.eta()) > cfgCutEta) + return false; + if (std::abs(particle.vz()) > cfgCutVertex) + return false; + return true; + } + + template + bool selectionProton(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + int flag = 0; + + if (candidate.pt() > cfgCutPtLower && 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() < cfgCutPtUpperPID) { + float combNSigmaPr = std::sqrt(std::pow(candidate.tpcNSigmaPr(), 2.0) + std::pow(candidate.tofNSigmaPr(), 2.0)); + float combNSigmaPi = std::sqrt(std::pow(candidate.tpcNSigmaPi(), 2.0) + std::pow(candidate.tofNSigmaPi(), 2.0)); + float combNSigmaKa = std::sqrt(std::pow(candidate.tpcNSigmaKa(), 2.0) + std::pow(candidate.tofNSigmaKa(), 2.0)); + + int flag2 = 0; + if (combNSigmaPr < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaPi < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaKa < cfgnSigmaOtherParticles) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaPr > combNSigmaPi) && !(combNSigmaPr > combNSigmaKa)) { + if (combNSigmaPr < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + template + bool selectionPion(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + int flag = 0; + + if (candidate.pt() > cfgCutPtLower && candidate.pt() <= cfgCutPtUpperTPC) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < cfgnSigmaCutTPC) { + flag = 1; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPi()) < cfgnSigmaCutTOF) { + flag = 1; + } + } + if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < cfgCutPtUpperPID) { + float combNSigmaPr = std::sqrt(std::pow(candidate.tpcNSigmaPr(), 2.0) + std::pow(candidate.tofNSigmaPr(), 2.0)); + float combNSigmaPi = std::sqrt(std::pow(candidate.tpcNSigmaPi(), 2.0) + std::pow(candidate.tofNSigmaPi(), 2.0)); + float combNSigmaKa = std::sqrt(std::pow(candidate.tpcNSigmaKa(), 2.0) + std::pow(candidate.tofNSigmaKa(), 2.0)); + + int flag2 = 0; + if (combNSigmaPr < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaPi < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaKa < cfgnSigmaOtherParticles) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaPi > combNSigmaPr) && !(combNSigmaPi > combNSigmaKa)) { + if (combNSigmaPi < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + template + bool selectionKaon(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + int flag = 0; + + if (candidate.pt() > cfgCutPtLower && candidate.pt() <= cfgCutPtUpperTPC) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < cfgnSigmaCutTPC) { + flag = 1; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaKa()) < cfgnSigmaCutTOF) { + flag = 1; + } + } + if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < cfgCutPtUpperPID) { + float combNSigmaPr = std::sqrt(std::pow(candidate.tpcNSigmaPr(), 2.0) + std::pow(candidate.tofNSigmaPr(), 2.0)); + float combNSigmaPi = std::sqrt(std::pow(candidate.tpcNSigmaPi(), 2.0) + std::pow(candidate.tofNSigmaPi(), 2.0)); + float combNSigmaKa = std::sqrt(std::pow(candidate.tpcNSigmaKa(), 2.0) + std::pow(candidate.tofNSigmaKa(), 2.0)); + + int flag2 = 0; + if (combNSigmaPr < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaPi < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaKa < cfgnSigmaOtherParticles) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaKa > combNSigmaPi) && !(combNSigmaKa > combNSigmaPr)) { + if (combNSigmaKa < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + float getCentrality(const auto& col) const + { + if (cfgCentralityChoice.value == kCentFT0C) + return col.centFT0C(); + if (cfgCentralityChoice.value == kCentFT0A) + return col.centFT0A(); + if (cfgCentralityChoice.value == kCentFT0M) + return col.centFT0M(); + if (cfgCentralityChoice.value == kCentFV0A) + return col.centFV0A(); + return KinvalidCentrality; + } + + float getEfficiency(float mult, float pt, float eta, PID pidType, int effidx) const + { + TH3F* h = nullptr; + if (effidx == 0) + h = hEff[pidType]; + if (effidx == 1) + h = hFake[pidType]; + + if (!h) + return -1; + const int ibx = h->GetXaxis()->FindBin(mult); + const int iby = h->GetYaxis()->FindBin(pt); + const int ibz = h->GetZaxis()->FindBin(eta); + float val = h->GetBinContent(ibx, iby, ibz); + return val; + } + + float getFlatteningWeight(float cent, float eta, float phi, PID pidType) const + { + TH3F* h = hWeightMap3D[pidType]; + if (!h) + return -1; + const int ibx = h->GetXaxis()->FindBin(cent); + const int iby = h->GetYaxis()->FindBin(eta); + const int ibz = h->GetZaxis()->FindBin(phi); + float val = h->GetBinContent(ibx, iby, ibz); + return val; + } + + template + std::pair calculateMeanAndC2FromSums(const double sumpmwk[KIntM][KIntK], const double sumwk[KIntK], float referenceMeanPt) const + { + if (sumwk[1] == 0.) { + return {0.f, 0.f}; + } + + double tau1 = sumwk[2] / (sumwk[1] * sumwk[1]); + double denom2 = 1. - tau1; + + if (std::abs(denom2) < KFloatEpsilon) { + double pmk11safe = sumpmwk[1][1] / sumwk[1]; + return {static_cast(pmk11safe), 0.f}; + } + + double pmk11 = sumpmwk[1][1] / sumwk[1]; + + double pmk12 = 0.f; + if (sumwk[2] != 0.f) { + pmk12 = sumpmwk[1][2] / sumwk[2]; + } + + double pmk22 = 0.f; + if (sumwk[2] != 0.f) { + pmk22 = sumpmwk[2][2] / sumwk[2]; + } + + float calculatedMeanPt = pmk11; + + double p1kBar1 = pmk11 - referenceMeanPt; + double p2kBar2 = pmk22 - 2.0f * pmk12 * referenceMeanPt + referenceMeanPt * referenceMeanPt; + + double p1kBar1sq = p1kBar1 * p1kBar1; + double numerator2 = p1kBar1sq - (tau1 * p2kBar2); + + float twopcorr = numerator2 / denom2; + return {calculatedMeanPt, twopcorr}; + } + + ConfigurableAxis cfgAxisCent{"cfgAxisCent", {0.0, 1.0, 3.0, 5.0, 10, 20, 30, 40, 50, 60, 70, 80, 100}, "centrality axis (percentile)"}; // FT0*/FV0A style + const AxisSpec centAxis{cfgAxisCent, "Centrality (%)"}; + static constexpr int KNbinsNch = 5000; + static constexpr float KNchMax = 5000.5f; + static constexpr int KNbinsNchCoarse = 500; + ConfigurableAxis nChAxis{"nChAxis", {KNbinsNch, KBinOffset, KNchMax}, "PV-contributor track multiplicity axis"}; + ConfigurableAxis nChAxis2{"nChAxis2", {KNbinsNchCoarse, KBinOffset, KNchMax}, "PV-contributor track multiplicity axis"}; + + Configurable cfgRunGetEff{"cfgRunGetEff", false, "Run MC pass to build efficiency/fake maps"}; + Configurable cfgRunMCMean{"cfgRunMCMean", false, "Run MC mean(pT) & mean(Et)"}; + Configurable cfgRunMCFluc{"cfgRunMCFluc", false, "Run MC fluctuations (C2, subevent)"}; + Configurable cfgRunGetFlat{"cfgRunGetFlat", false, "Run Data Get Flattening Weights"}; + Configurable cfgRunDataMean{"cfgRunDataMean", false, "Run DATA mean(pT) & mean(Et)"}; + Configurable cfgRunDataFluc{"cfgRunDataFluc", false, "Run DATA fluctuations (C2, subevent)"}; + + using GeneralCollisions = soa::Join< + aod::Collisions, + aod::EvSels, + aod::Mults, + aod::CentFT0As, aod::CentFT0Cs, aod::CentFT0Ms, aod::CentFV0As, + aod::CentNGlobals>; + Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZCut; + using AodCollisionsSel = soa::Filtered; + + using UnfilteredTracks = soa::Join< + aod::Tracks, + aod::TracksExtra, + aod::TrackSelection, + aod::TracksDCA, + aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, + aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>; + Filter trackFilter = nabs(aod::track::eta) < cfgEtaCut && + aod::track::pt > cfgPtMin&& + aod::track::pt < cfgPtMax&& + nabs(aod::track::dcaXY) < cfgDCAXY&& nabs(aod::track::dcaZ) < cfgDCAZ; + using AodTracksSel = soa::Filtered; + using TCs = soa::Join; + using FilteredTCs = soa::Filtered; + + using MyRun3MCCollisions = soa::Join< + aod::Collisions, aod::EvSels, aod::Mults, aod::MultsExtra, + aod::CentFT0As, aod::CentFT0Cs, aod::CentFT0Ms, aod::CentFV0As, + aod::CentNGlobals, aod::McCollisionLabels>; + + using MyMCTracks = soa::Join< + aod::Tracks, aod::TrackSelection, aod::TracksExtra, aod::TracksDCA, + aod::McTrackLabels, + aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, + aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>; + + PresliceUnsorted partPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted trackPerMcParticle = aod::mctracklabel::mcParticleId; + Preslice perCollision = aod::track::collisionId; + Preslice trackPerCollision = aod::track::collisionId; + + void declareCommonQA() + { + histos.add("hZvtx_after_sel", ";z_{vtx} (cm)", kTH1F, {{KNbinsZvtx, KZvtxMin, KZvtxMax}}); + histos.add("hVtxZ", ";z_{vtx} (cm)", kTH1F, {{KNbinsZvtx, KZvtxMin, KZvtxMax}}); + histos.add("hCentrality", ";centrality (%)", kTH1F, {{centAxis}}); + histos.add("Hist2D_globalTracks_PVTracks", ";N_{global};N_{PV}", kTH2F, {{nChAxis2}, {nChAxis2}}); + histos.add("Hist2D_cent_nch", ";N_{PV};cent (%)", kTH2F, {{nChAxis2}, {centAxis}}); + histos.add("hP", ";p (GeV/c)", kTH1F, {{KNbinsP, KPMin, KPMax}}); + histos.add("hPt", ";p_{T} (GeV/c)", kTH1F, {{KNbinsPt, KPtMin, KPtMax}}); + histos.add("hEta", ";#eta", kTH1F, {{KNbinsEta, KEtaMin, KEtaMax}}); + histos.add("hPhi", ";#phi", kTH1F, {{KNbinsPhi, KPhiMin, TwoPI}}); + + histos.add("hCentEtaPhi", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCent1EtaPhi", ";#eta;#phi", kTH2F, {{(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCent7EtaPhi", ";#eta;#phi", kTH2F, {{(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCentEtaPhiWtd", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCent1EtaPhiWtd", ";#eta;#phi", kTH2F, {{(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCent7EtaPhiWtd", ";#eta;#phi", kTH2F, {{(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + + histos.add("hCentEtaPhiWtd_PID", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCent1EtaPhiWtd_PID", ";#eta;#phi", kTH2F, {{(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCent7EtaPhiWtd_PID", ";#eta;#phi", kTH2F, {{(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + + histos.add("hCentEtaPhiTrue", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCentEtaPhiReco", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCentEtaPhiRecoMatched", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + + histos.add("hCentEtaPhiTrue_PID", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCentEtaPhiReco_PID", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + histos.add("hCentEtaPhiRecoMatched_PID", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, KPhiMin, TwoPI}}); + } + void declareMCCommonHists() + { + + histos.add("ptResolution", ";p_{T}^{MC};p_{T}^{MC}-p_{T}^{reco}", kTH2F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsPtRes, -KPtResMax, KPtResMax}}); + histos.add("ptTruthReco", ";p_{T}^{MC};p_{T}^{reco}", kTH2F, {{KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsPtRes, cfgPtMin, cfgPtMax}}); + histos.add("etaResolution", ";#eta^{MC};#eta^{MC}-#eta^{reco}", kTH2F, {{KNbinsEtaRes, -KEtaFineMax, KEtaFineMax}, {KNbinsPtRes, -KEtaResMax, KEtaResMax}}); + histos.add("etaTruthReco", ";#eta^{MC};#eta^{reco}", kTH2F, {{KNbinsPtRes, -KEtaFineMax, KEtaFineMax}, {KNbinsPtRes, -KEtaFineMax, KEtaFineMax}}); + + histos.add("TruthTracKVz", ";Vz^{MC};Vz^{Reco}", kTH2F, {{KNbinsVz, KVzMin, KVzMax}, {KNbinsVz, KVzMin, KVzMax}}); + histos.add("vzResolution", ";Vz^{MC};Vz^{MC}-Vz^{Reco}", kTH2F, {{KNbinsVz, KVzMin, KVzMax}, {KNbinsVz, -KVzResMax, KVzResMax}}); + + histos.add("h3_AllPrimary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoMatchedToPrimary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoUnMatchedToPrimary_Secondary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoUnMatchedToPrimary_Fake", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_AllReco", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + + histos.add("h3_AllPrimary_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoMatchedToPrimary_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoUnMatchedToPrimary_Secondary_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoUnMatchedToPrimary_Fake_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_AllReco_PID", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + + histos.add("h_AllPrimary", ";p_{T}", kTH1F, {{KNbinsP, cfgPtMin, cfgPtMax}}); + histos.add("h_RecoMatchedToPrimary", ";p_{T}", kTH1F, {{KNbinsPt, KPtMin, KPtMax}}); + histos.add("h_RecoUnMatchedToPrimary", ";p_{T}", kTH1F, {{KNbinsPt, KPtMin, KPtMax}}); + histos.add("h_AllReco", ";p_{T}", kTH1F, {{KNbinsPt, KPtMin, KPtMax}}); + + histos.add("hReco_ParticleWeight", ";cent;p_{T};#eta", kTH3F, {{centAxis}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsPtRes, -KEtaFineMax, KEtaFineMax}}); + histos.add("hTruth_ParticleWeight", ";cent;p_{T};#eta", kTH3F, {{centAxis}, {KNbinsPtRes, cfgPtMin, cfgPtMax}, {KNbinsPtRes, -KEtaFineMax, KEtaFineMax}}); + + histos.add("hDCAxy_Unmatched", ";DCA_{xy} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); + histos.add("hDCAz_Unmatched", ";DCA_{z} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); + histos.add("hDCAxy_NotPrimary", ";DCA_{xy} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); + histos.add("hDCAz_NotPrimary", ";DCA_{z} (cm)", kTH1F, {{KNbinsDca, -KDcaMax, KDcaMax}}); + } + + void declareMCMeanHists() + { + histos.add("Eff_cent", ";cent;#epsilon", kTProfile, {centAxis}); + histos.add("Fake_cent", ";cent;f_{fake}", kTProfile, {centAxis}); + histos.add("wgt_cent", ";cent;w", kTProfile, {centAxis}); + histos.add("Eff_Ntrk", ";N_{PV};#epsilon", kTProfile, {nChAxis2}); + histos.add("Fake_Ntrk", ";N_{PV};f_{fake}", kTProfile, {nChAxis2}); + histos.add("wgt_Ntrk", ";N_{PV};w", kTProfile, {nChAxis2}); + histos.add("Eff_pT", ";p_{T};#epsilon", kTProfile, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); + histos.add("Fake_pT", ";p_{T};f_{fake}", kTProfile, {{KNbinsPtRes, cfgPtMin, cfgPtMax}}); + histos.add("wgt_pT", ";p_{T};w", kTProfile, {{KNbinsPtRes, KPtMin, KPtMax}}); + histos.add("Eff_eta", ";#eta;#epsilon", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("Fake_eta", ";#eta;f_{fake}", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("wgt_eta", ";#eta;w", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + // MC mean profiles (pT & Et) for various selections + histos.add("MCGen/Prof_cent_Nchrec", ";cent;#LT N_{PV}#GT", kTProfile, {centAxis}); + histos.add("MCGen/Prof_MeanpT_Cent", ";cent;#LT p_{T}#GT", kTProfile, {centAxis}); + histos.add("MCGen/Prof_MeanpT_Mult", ";N_{PV};#LT p_{T}#GT", kTProfile, {nChAxis}); + histos.add("pmeanTruNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanRecoNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanRecoMatchedNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanRecoEffcorrNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanRecoMatchedEffcorrNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + + histos.add("MCGen/Prof_MeanEt_Cent", ";cent;#LT E_{T}#GT", kTProfile, {centAxis}); + histos.add("MCGen/Prof_MeanEt_Mult", ";N_{PV};#LT E_{T}#GT", kTProfile, {nChAxis}); + histos.add("pmeanEtTruNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanEtRecoNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanEtRecoMatchedNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanEtRecoEffcorrNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanEtRecoMatchedEffcorrNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + + histos.addClone("MCGen/", "MCReco/"); + histos.addClone("MCGen/", "MCRecoMatched/"); + histos.addClone("MCGen/", "MCRecoEffCorr/"); + histos.addClone("MCGen/", "MCRecoMatchedEffCorr/"); + } + void declareMCFlucHists() + { + static constexpr int KNbinsNchFluc = 1000; + + ConfigurableAxis nChAxis{"nChAxis", {KNbinsNch, KBinOffset, KNchMax}, "PV-contributor track multiplicity axis"}; + ConfigurableAxis nChAxis2{"nChAxis2", {KNbinsNchCoarse, KBinOffset, KNchMax}, "PV-contributor track multiplicity axis"}; + + // pT cumulants + histos.add("MCGen/Prof_C2_Cent", ";cent;C_{2}", kTProfile, {centAxis}); + histos.add("MCGen/Prof_C2_Mult", ";N_{PV};C_{2}", kTProfile, {nChAxis}); + histos.add("MCGen/Prof_C2Sub_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{KNbinsNchFluc, KBinOffset, KNchMax}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("MCGen/Prof_ipt0_C2Sub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt1_C2Sub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt2_C2Sub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt0_Cov_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt0_Cov_Eta", ";#eta;cov", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt1_Cov_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt1_Cov_Eta", ";#eta;cov", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt2_Cov_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt2_Cov_Eta", ";#eta;cov", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("MCGen/Prof_C2Et_Cent", ";cent;C_{2}^{E_{T}}", kTProfile, {centAxis}); + histos.add("MCGen/Prof_C2Et_Mult", ";N_{PV};C_{2}^{E_{T}}", kTProfile, {nChAxis}); + histos.add("MCGen/Prof_C2EtSub_Mult_etabin_ptbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{KNbinsNchFluc, KBinOffset, KNchMax}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("MCGen/Prof_ipt0_C2EtSub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt1_C2EtSub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt2_C2EtSub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt0_CovEt_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt0_CovEt_Eta", ";#eta;cov^{E_{T}}", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt1_CovEt_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt1_CovEt_Eta", ";#eta;cov^{E_{T}}", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt2_CovEt_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("MCGen/Prof_ipt2_CovEt_Eta", ";#eta;cov^{E_{T}}", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + + histos.add("MCGen/Prof_cent_Nchrec", ";cent;#LT N_{PV}#GT", kTProfile, {centAxis}); + histos.add("MCGen/Prof_MeanpT_Cent", ";cent;#LT p_{T}#GT", kTProfile, {centAxis}); + histos.add("MCGen/Prof_MeanpT_Mult", ";N_{PV};#LT p_{T}#GT", kTProfile, {nChAxis}); + + histos.add("pmeanTruNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanRecoNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanRecoMatchedNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanRecoEffcorrNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanRecoMatchedEffcorrNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + + histos.add("MCGen/Prof_MeanEt_Cent", ";cent;#LT E_{T}#GT", kTProfile, {centAxis}); + histos.add("MCGen/Prof_MeanEt_Mult", ";N_{PV};#LT E_{T}#GT", kTProfile, {nChAxis}); + histos.add("pmeanEtTruNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanEtRecoNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanEtRecoMatchedNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanEtRecoEffcorrNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("pmeanEtRecoMatchedEffcorrNchEtabinPtbin", ";N_{PV};#eta-bin; p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + } + void declareDataMeanHists() + { + histos.add("Prof_cent_Nchrec", ";cent;#LT N_{PV}#GT", kTProfile, {centAxis}); + histos.add("Prof_MeanpT_Cent", ";cent;#LT p_{T}#GT", kTProfile, {centAxis}); + histos.add("pmean_nch_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + // Et + histos.add("Prof_MeanEt_Cent", ";cent;#LT E_{T}#GT", kTProfile, {centAxis}); + histos.add("pmeanEt_nch_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + } + + void declareDataGetFlatHists() + { + histos.add("hCentEtaPhi_PID", ";cent;#eta;#phi", kTH3F, {{centAxis}, {(KNEta - 1), KEtaAxisMin, KEtaAxisMax}, {KNbinsPhiFine, 0, TwoPI}}); + } + + void declareDataFlucHists() + { + histos.add("pmean_nch_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + histos.add("Prof_MeanEt_Cent", ";cent;#LT E_{T}#GT", kTProfile, {centAxis}); + histos.add("pmeanEt_nch_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + + histos.add("Prof_C2_Cent", ";cent;C_{2}", kTProfile, {centAxis}); + histos.add("Prof_MeanpT_Cent", ";cent;#LT p_{T}#GT", kTProfile, {centAxis}); + histos.add("Prof_MeanpT_Mult", ";N_{PV};#LT p_{T}#GT", kTProfile, {nChAxis}); + histos.add("Prof_C2_Mult_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + + histos.add("Prof_ipt0_Cov_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("Prof_ipt0_Cov_Eta", ";#eta;cov", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("Prof_ipt1_Cov_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("Prof_ipt1_Cov_Eta", ";#eta;cov", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("Prof_ipt2_Cov_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("Prof_ipt2_Cov_Eta", ";#eta;cov", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + + histos.add("Prof_C2Et_Cent", ";cent;C_{2}^{E_{T}}", kTProfile, {centAxis}); + histos.add("Prof_MeanEt_Mult", ";N_{PV};#LT E_{T}#GT", kTProfile, {nChAxis}); + histos.add("Prof_C2Et_Mult_etabin_ptbin", ";N_{PV};#eta-bin;p_{T}-bin", kTProfile3D, {{nChAxis}, {KNEta + 1, -KBinOffset, KNEta + KBinOffset}, {KNpT + 1, -KBinOffset, KNpT + KBinOffset}}); + + histos.add("Prof_ipt0_CovEt_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("Prof_ipt0_CovEt_Eta", ";#eta;cov^{E_{T}}", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("Prof_ipt1_CovEt_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("Prof_ipt1_CovEt_Eta", ";#eta;cov^{E_{T}}", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + histos.add("Prof_ipt2_CovEt_Cent_eta", ";cent;#eta", kTProfile2D, {{centAxis}, {(KNEta - 1) / 2, 0, KEtaAxisMax}}); + histos.add("Prof_ipt2_CovEt_Eta", ";#eta;cov^{E_{T}}", kTProfile, {{(KNEta - 1) / 2, 0., KEtaAxisMax}}); + + histos.add("Prof_ipt0_C2Sub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("Prof_ipt1_C2Sub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("Prof_ipt2_C2Sub2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("Prof_ipt0_C2SubEt2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("Prof_ipt1_C2SubEt2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + histos.add("Prof_ipt2_C2SubEt2D_Mult_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}, {KNEta - 1, KEtaAxisMin, KEtaAxisMax}}); + } + + TH3F* buildWeightMapFromRaw(TH3F* hRaw, const char* mapName) + { + if (!hRaw) { + LOGF(error, "Raw eta-phi map for '%s' is null; no flattening will be applied.", mapName); + return nullptr; + } + auto hWeightMap = reinterpret_cast(hRaw->Clone(mapName)); + hWeightMap->SetTitle(Form("Flattening Weight Map %s (w_{#phi} = / N_{#phi})", mapName)); + hWeightMap->SetDirectory(nullptr); + hWeightMap->Reset(); + auto axC = hRaw->GetXaxis(); + auto axE = hRaw->GetYaxis(); + auto axP = hRaw->GetZaxis(); + for (int ic = 1; ic <= axC->GetNbins(); ++ic) { + for (int ie = 1; ie <= axE->GetNbins(); ++ie) { + // average over phi at fixed (cent,eta) + double sum = 0.0; + int nphi = axP->GetNbins(); + for (int ip = 1; ip <= nphi; ++ip) + sum += hRaw->GetBinContent(ic, ie, ip); + const double avg = (nphi > 0 ? sum / nphi : 0.0); + for (int ip = 1; ip <= nphi; ++ip) { + const double raw = hRaw->GetBinContent(ic, ie, ip); + const double w = (avg > 0.0 && raw > 0.0) ? (avg / raw) : 1.0; + hWeightMap->SetBinContent(ic, ie, ip, w); + } + } + } + LOGF(info, "Flattening weight map '%s' built.", mapName); + return hWeightMap; + } + + inline void loadTProfile3D(TDirectory* dir, const char* name, TProfile3D*& target) + { + if (!dir) { + LOGF(error, "loadTProfile3D: directory is null for object %s", name); + return; + } + + auto* obj = dir->Get(name); + if (!obj) { + LOGF(error, "loadTProfile3D: object '%s' not found in directory %s", name, dir->GetName()); + return; + } + + auto* prof = dynamic_cast(obj); + if (!prof) { + LOGF(error, "loadTProfile3D: object '%s' is not a TProfile3D (it is %s)", name, obj->ClassName()); + return; + } + + target = reinterpret_cast(prof->Clone(Form("%s_clone", name))); + target->SetDirectory(nullptr); + LOGF(info, "Loaded TProfile3D '%s' with entries = %.0f", name, target->GetEntries()); + } + + void init(InitContext&) + { + ccdb->setURL("https://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); + + declareCommonQA(); + + const std::string userCcdbPath = "/Users/s/somadutt/PbPbTest/"; + + if (cfgRunMCMean || cfgRunMCFluc || cfgRunGetEff) { + declareMCCommonHists(); + } + if (cfgRunMCMean) { + declareMCMeanHists(); + } + if (cfgRunMCFluc) { + declareMCFlucHists(); + + histos.addClone("MCGen/", "MCReco/"); + histos.addClone("MCGen/", "MCRecoMatched/"); + histos.addClone("MCGen/", "MCRecoEffCorr/"); + histos.addClone("MCGen/", "MCRecoMatchedEffCorr/"); + } + if (cfgRunGetFlat) { + declareDataGetFlatHists(); + } + if (cfgRunDataMean) { + declareDataMeanHists(); + } + if (cfgRunDataFluc) { + declareDataFlucHists(); + } + + const bool needEffMaps = cfgRunMCMean || cfgRunMCFluc || cfgRunDataMean || cfgRunDataFluc; + if (needEffMaps && !cfgRunGetEff) { + + LOGF(info, "Loading Eff/Fake maps from CCDB path: %s", userCcdbPath.c_str()); + + auto loadEffFakeForPID = [&](PID pidType) { + std::string suffix = pidSuffix[pidType]; + std::string hEffNumName = "h3_RecoMatchedToPrimary" + suffix; + std::string hEffDenName = "h3_AllPrimary" + suffix; + std::string hFakeNumSecName = "h3_RecoUnMatchedToPrimary_Secondary" + suffix; + std::string hFakeNumFakName = "h3_RecoUnMatchedToPrimary_Fake" + suffix; + std::string hFakeDenName = "h3_AllReco" + suffix; + + // --- Efficiency --- + auto* hNum = ccdb->get(userCcdbPath + hEffNumName); + auto* hDen = ccdb->get(userCcdbPath + hEffDenName); + if (hNum && hDen) { + hEff[pidType] = reinterpret_cast(hNum->Clone(Form("hEff%s", suffix.c_str()))); + hEff[pidType]->SetDirectory(nullptr); + hEff[pidType]->Divide(hDen); + } else { + LOGF(error, "Missing CCDB objects for efficiency. Checked:\n%s\n%s", + (userCcdbPath + hEffNumName).c_str(), + (userCcdbPath + hEffDenName).c_str()); + } + + // --- Fakes --- + auto* hNumS = ccdb->get(userCcdbPath + hFakeNumSecName); + auto* hNumF = ccdb->get(userCcdbPath + hFakeNumFakName); + auto* hDenF = ccdb->get(userCcdbPath + hFakeDenName); + if (hNumS && hNumF && hDenF) { + hFake[pidType] = reinterpret_cast(hNumS->Clone(Form("hFake%s", suffix.c_str()))); + hFake[pidType]->Add(hNumF); + hFake[pidType]->SetDirectory(nullptr); + hFake[pidType]->Divide(hDenF); + } else { + LOGF(error, "Missing CCDB object(s) for fakes for %s. Checked path prefix: %s", + suffix.c_str(), userCcdbPath.c_str()); + } + }; + + loadEffFakeForPID(kInclusive); + loadEffFakeForPID(kCombinedPID); + + const bool isDataRun = cfgRunDataMean || cfgRunDataFluc; + if (isDataRun) { + LOGF(info, "Data Run: Loading flattening maps from CCDB path: %s", userCcdbPath.c_str()); + + auto* hRawIncl = ccdb->get(userCcdbPath + "hCentEtaPhi"); + if (hRawIncl) { + hWeightMap3D[kInclusive] = buildWeightMapFromRaw(hRawIncl, "hWeightMap3D"); + } else { + LOGF(error, "Data flattening 'hCentEtaPhi' not found at path %s", + (userCcdbPath + "hCentEtaPhi").c_str()); + } + + auto* hRawPID = ccdb->get(userCcdbPath + "hCentEtaPhi_PID"); + if (hRawPID) { + hWeightMap3D[kCombinedPID] = buildWeightMapFromRaw(hRawPID, "hWeightMap3D_PID"); + } else { + LOGF(error, "Data flattening 'hCentEtaPhi_PID' not found at path %s", + (userCcdbPath + "hCentEtaPhi_PID").c_str()); + } + } else { + LOGF(info, "MC Run: Loading flattening maps from CCDB path: %s", userCcdbPath.c_str()); + + auto loadFlatForPID = [&](PID pidType) { + std::string suffix = pidSuffix[pidType]; + std::string hFlatSrcName = "hCentEtaPhiReco" + suffix; + auto* hRaw = ccdb->get(userCcdbPath + hFlatSrcName); + if (hRaw) { + hWeightMap3D[pidType] = buildWeightMapFromRaw(hRaw, Form("hWeightMap3D%s", suffix.c_str())); + } else { + LOGF(warning, "MC flattening source '%s' not found at %s; skipping this PID.", + hFlatSrcName.c_str(), (userCcdbPath + hFlatSrcName).c_str()); + } + }; + loadFlatForPID(kInclusive); + loadFlatForPID(kCombinedPID); + } + } + + auto loadTProfile3DFromCCDB = [&](const std::string& ccdbPath, const char* objName, TProfile3D*& target) { + std::string fullPath = ccdbPath + objName; + LOGF(info, "Loading TProfile3D from CCDB: %s", fullPath.c_str()); + if (auto* tp = ccdb->get(fullPath)) { + target = reinterpret_cast(tp->Clone()); + target->SetDirectory(nullptr); + } else { + LOGF(error, "Histogram %s missing in CCDB at path: %s", objName, fullPath.c_str()); + } + }; + + if (cfgRunMCFluc) { + LOGF(info, "Loading MC Mean profiles from CCDB path: %s", userCcdbPath.c_str()); + + loadTProfile3DFromCCDB(userCcdbPath, "pmeanTruNchEtabinPtbin", pmeanTruNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanRecoNchEtabinPtbin", pmeanRecoNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanRecoMatchedNchEtabinPtbin", pmeanRecoMatchedNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanRecoEffcorrNchEtabinPtbin", pmeanRecoEffcorrNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanRecoMatchedEffcorrNchEtabinPtbin", pmeanRecoMatchedEffcorrNchEtabinPtbinStep2); + + loadTProfile3DFromCCDB(userCcdbPath, "pmeanEtTruNchEtabinPtbin", pmeanEtTruNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanEtRecoNchEtabinPtbin", pmeanEtRecoNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanEtRecoMatchedNchEtabinPtbin", pmeanEtRecoMatchedNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanEtRecoEffcorrNchEtabinPtbin", pmeanEtRecoEffcorrNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanEtRecoMatchedEffcorrNchEtabinPtbin", pmeanEtRecoMatchedEffcorrNchEtabinPtbinStep2); + } + + if (cfgRunDataFluc) { + LOGF(info, "Loading Data Mean profiles from CCDB path: %s", userCcdbPath.c_str()); + loadTProfile3DFromCCDB(userCcdbPath, "pmean_nch_etabin_ptbin", pmeanNchEtabinPtbinStep2); + loadTProfile3DFromCCDB(userCcdbPath, "pmeanEt_nch_etabin_ptbin", pmeanEtNchEtabinPtbinStep2); + } + + LOGF(info, "CCDB initialization complete for RadialFlowDecorr."); + } + + void processGetEffHists(aod::McCollisions const& mcColl, soa::SmallGroups const& collisions, TCs const& tracks, FilteredTCs const& /*filteredTracks*/, aod::McParticles const& mcParticles) + { + for (const auto& mcCollision : mcColl) { + auto colSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + if (colSlice.size() != 1) + continue; + + for (const auto& col : colSlice) { + if (!col.has_mcCollision()) + continue; + if (!isEventSelected(col)) + continue; + + auto trackSlice = tracks.sliceBy(trackPerCollision, col.globalIndex()); + if (trackSlice.size() < 1) + continue; + + auto partSlice = mcParticles.sliceBy(partPerMcCollision, mcCollision.globalIndex()); + if (partSlice.size() < 1) + continue; + if (col.globalIndex() >= trackSlice.size()) { + LOGF(warning, "Skipping invalid globalIndex=%d for tracks (tracks.size=%d)", col.globalIndex(), tracks.size()); + continue; + } + + float cent = getCentrality(col); + if (cent > KCentMax) + continue; + + for (const auto& particle : partSlice) { + if (!isParticleSelected(particle)) + continue; + if (!particle.isPhysicalPrimary()) + continue; + + const int absPdgId = std::abs(particle.pdgCode()); + const bool isPion = (absPdgId == KPiPlus); + const bool isKaon = (absPdgId == KKPlus); + const bool isProton = (absPdgId == KProton); + const bool isPid = (isPion || isKaon || isProton); + + histos.fill(HIST("hTruth_ParticleWeight"), cent, particle.pt(), particle.eta(), particle.weight()); + histos.fill(HIST("hCentEtaPhiTrue"), cent, particle.eta(), particle.phi()); + histos.fill(HIST("h3_AllPrimary"), col.multNTracksPV(), particle.pt(), particle.eta()); + + if (cent < KCentTestMin) + histos.fill(HIST("hCent1EtaPhi"), particle.eta(), particle.phi()); + if (cent > KCentTestMaxLo && cent < KCentTestMaxHi) + histos.fill(HIST("hCent7EtaPhi"), particle.eta(), particle.phi()); + + if (isPid) { + histos.fill(HIST("hCentEtaPhiTrue_PID"), cent, particle.eta(), particle.phi()); + histos.fill(HIST("h3_AllPrimary_PID"), col.multNTracksPV(), particle.pt(), particle.eta()); + } + } + histos.fill(HIST("TruthTracKVz"), mcCollision.posZ(), col.posZ()); + histos.fill(HIST("vzResolution"), mcCollision.posZ(), mcCollision.posZ() - col.posZ()); + + // Reconstructed + for (const auto& track : trackSlice) { + if (!isTrackSelected(track)) + continue; + + const bool isPion = selectionPion(track); + const bool isKaon = selectionKaon(track); + const bool isProton = selectionProton(track); + const bool isPid = (isPion || isKaon || isProton); + + histos.fill(HIST("h3_AllReco"), col.multNTracksPV(), track.pt(), track.eta()); + histos.fill(HIST("hCentEtaPhiReco"), cent, track.eta(), track.phi()); + + if (isPid) { + histos.fill(HIST("h3_AllReco_PID"), col.multNTracksPV(), track.pt(), track.eta()); + histos.fill(HIST("hCentEtaPhiReco_PID"), cent, track.eta(), track.phi()); + } + + if (track.has_mcParticle()) { + auto mcPart2 = track.mcParticle(); + if (mcPart2.isPhysicalPrimary()) { + const int absPdgId = std::abs(mcPart2.pdgCode()); + const bool isPionTrue = (absPdgId == kPiPlus); + const bool isKaonTrue = (absPdgId == kKPlus); + const bool isProtonTrue = (absPdgId == kProton); + const bool isPidTrue = (isPionTrue || isKaonTrue || isProtonTrue); + + histos.fill(HIST("hReco_ParticleWeight"), cent, mcPart2.pt(), mcPart2.eta(), mcPart2.weight()); + histos.fill(HIST("ptResolution"), mcPart2.pt(), mcPart2.pt() - track.pt()); + histos.fill(HIST("ptTruthReco"), mcPart2.pt(), track.pt()); + histos.fill(HIST("etaResolution"), mcPart2.eta(), mcPart2.eta() - track.eta()); + histos.fill(HIST("etaTruthReco"), mcPart2.eta(), track.eta()); + histos.fill(HIST("h3_RecoMatchedToPrimary"), col.multNTracksPV(), mcPart2.pt(), mcPart2.eta()); + histos.fill(HIST("hCentEtaPhiRecoMatched"), cent, mcPart2.eta(), mcPart2.phi()); + + if (isPid && isPidTrue) { + histos.fill(HIST("h3_RecoMatchedToPrimary_PID"), col.multNTracksPV(), mcPart2.pt(), mcPart2.eta()); + histos.fill(HIST("hCentEtaPhiRecoMatched_PID"), cent, mcPart2.eta(), mcPart2.phi()); + } + + } else { + // Matched to secondary + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary"), col.multNTracksPV(), track.pt(), track.eta()); + histos.fill(HIST("hDCAxy_Unmatched"), track.dcaXY()); + histos.fill(HIST("hDCAz_Unmatched"), track.dcaZ()); + if (isPid) { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PID"), col.multNTracksPV(), track.pt(), track.eta()); + } + } + } else { + // Fake track + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake"), col.multNTracksPV(), track.pt(), track.eta()); + histos.fill(HIST("hDCAxy_NotPrimary"), track.dcaXY()); + histos.fill(HIST("hDCAz_NotPrimary"), track.dcaZ()); + if (isPid) { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PID"), col.multNTracksPV(), track.pt(), track.eta()); + } + } + } // tracks + } // cols + } // mcColl + LOGF(info, "FINISHED RUNNING processGetEffHists"); + } + PROCESS_SWITCH(RadialFlowDecorr, processGetEffHists, "process MC to calculate Eff and Fakes", cfgRunGetEff); + + void processMCMean(aod::McCollisions const& mcColl, MyRun3MCCollisions const& collisions, TCs const& tracks, FilteredTCs const& /*filteredTracks*/, aod::McParticles const& mcParticles) + { + float sumWiTruth[KNEta][KNpT], sumWiptiTruth[KNEta][KNpT]; + float sumWiReco[KNEta][KNpT], sumWiptiReco[KNEta][KNpT]; + float sumWiRecoMatched[KNEta][KNpT], sumWiptiRecoMatched[KNEta][KNpT]; + float sumWiRecoEffCorr[KNEta][KNpT], sumWiptiRecoEffCorr[KNEta][KNpT]; + float sumWiRecoMatchedEffCorr[KNEta][KNpT], sumWiptiRecoMatchedEffCorr[KNEta][KNpT]; + float sumWiTruthEt[KNEta][KNpT], sumWiptiTruthEt[KNEta][KNpT]; + float sumWiRecoEt[KNEta][KNpT], sumWiptiRecoEt[KNEta][KNpT]; + float sumWiRecoMatchedEt[KNEta][KNpT], sumWiptiRecoMatchedEt[KNEta][KNpT]; + float sumWiRecoEffCorrEt[KNEta][KNpT], sumWiptiRecoEffCorrEt[KNEta][KNpT]; + float sumWiRecoMatchedEffCorrEt[KNEta][KNpT], sumWiptiRecoMatchedEffCorrEt[KNEta][KNpT]; + + for (const auto& mcCollision : mcColl) { + auto colSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + + if (colSlice.size() != 1) + continue; + for (const auto& col : colSlice) { + if (!col.has_mcCollision()) + continue; + if (!isEventSelected(col)) + continue; + + auto trackSlice = tracks.sliceBy(trackPerCollision, col.globalIndex()); + if (trackSlice.size() < 1) + continue; + + auto partSlice = mcParticles.sliceBy(partPerMcCollision, mcCollision.globalIndex()); + if (partSlice.size() < 1) + continue; + if (col.globalIndex() >= trackSlice.size()) { + LOGF(warning, "Skipping invalid globalIndex=%d for tracks (tracks.size=%d)", col.globalIndex(), tracks.size()); + continue; + } + + float cent = getCentrality(col); + if (cent > KCentMax) + continue; + + if (col.globalIndex() >= trackSlice.size()) { + LOGF(warning, "Skipping invalid globalIndex=%d for tracks (tracks.size=%d)", col.globalIndex(), tracks.size()); + continue; + } + + LOGF(info, "Event Check: cent = %.1f, nTracks = %d", cent, (int)trackSlice.size()); + memset(sumWiTruth, 0, sizeof(sumWiTruth)); + memset(sumWiptiTruth, 0, sizeof(sumWiptiTruth)); + memset(sumWiReco, 0, sizeof(sumWiReco)); + memset(sumWiptiReco, 0, sizeof(sumWiptiReco)); + memset(sumWiRecoMatched, 0, sizeof(sumWiRecoMatched)); + memset(sumWiptiRecoMatched, 0, sizeof(sumWiptiRecoMatched)); + memset(sumWiRecoEffCorr, 0, sizeof(sumWiRecoEffCorr)); + memset(sumWiptiRecoEffCorr, 0, sizeof(sumWiptiRecoEffCorr)); + memset(sumWiRecoMatchedEffCorr, 0, sizeof(sumWiRecoMatchedEffCorr)); + memset(sumWiptiRecoMatchedEffCorr, 0, sizeof(sumWiptiRecoMatchedEffCorr)); + memset(sumWiTruthEt, 0, sizeof(sumWiTruthEt)); + memset(sumWiptiTruthEt, 0, sizeof(sumWiptiTruthEt)); + memset(sumWiRecoEt, 0, sizeof(sumWiRecoEt)); + memset(sumWiptiRecoEt, 0, sizeof(sumWiptiRecoEt)); + memset(sumWiRecoMatchedEt, 0, sizeof(sumWiRecoMatchedEt)); + memset(sumWiptiRecoMatchedEt, 0, sizeof(sumWiptiRecoMatchedEt)); + memset(sumWiRecoEffCorrEt, 0, sizeof(sumWiRecoEffCorrEt)); + memset(sumWiptiRecoEffCorrEt, 0, sizeof(sumWiptiRecoEffCorrEt)); + memset(sumWiRecoMatchedEffCorrEt, 0, sizeof(sumWiRecoMatchedEffCorrEt)); + memset(sumWiptiRecoMatchedEffCorrEt, 0, sizeof(sumWiptiRecoMatchedEffCorrEt)); + + // Truth + for (const auto& particle : partSlice) { + if (!isParticleSelected(particle)) + continue; + if (!particle.isPhysicalPrimary()) + continue; + + const int absPdgId = std::abs(particle.pdgCode()); + const bool isPion = (absPdgId == kPiPlus); + const bool isKaon = (absPdgId == kKPlus); + const bool isProton = (absPdgId == kProton); + + float pt = particle.pt(); + float eta = particle.eta(); + float p = particle.p(); + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + sumWiTruth[ieta][ipt]++; + sumWiptiTruth[ieta][ipt] += pt; + if (isPion || isKaon || isProton) { + float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus + : o2::constants::physics::MassProton; + float energy = std::sqrt(p * p + m * m); + float et = energy * (pt / p); // E_T = E * sin(theta) = E * (pT / p) + sumWiTruthEt[ieta][ipt]++; + sumWiptiTruthEt[ieta][ipt] += et; + } + } + } + } + + for (const auto& track : trackSlice) { + if (!isTrackSelected(track)) + continue; + + float pt = track.pt(); + float eta = track.eta(); + float p = track.p(); + float phi = track.phi(); + + histos.fill(HIST("hCentEtaPhi"), cent, eta, phi); + if (cent < KCentTestMin) + histos.fill(HIST("hCent1EtaPhi"), eta, phi); + if (cent > KCentTestMaxLo && cent < KCentTestMaxHi) + histos.fill(HIST("hCent7EtaPhi"), eta, phi); + + float effIncl = getEfficiency(col.multNTracksPV(), pt, eta, kInclusive, 0); + float fakeIncl = getEfficiency(col.multNTracksPV(), pt, eta, kInclusive, 1); + float flatWeightIncl = getFlatteningWeight(cent, eta, phi, kInclusive); + float wIncl = flatWeightIncl * (1.0 - fakeIncl) / effIncl; + + histos.fill(HIST("hCentEtaPhiWtd"), cent, eta, track.phi(), flatWeightIncl); + if (cent < KCentTestMin) + histos.fill(HIST("hCent1EtaPhiWtd"), track.eta(), track.phi(), flatWeightIncl); + if (cent > KCentTestMaxLo && cent < KCentTestMaxHi) + histos.fill(HIST("hCent7EtaPhiWtd"), track.eta(), track.phi(), flatWeightIncl); + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + sumWiReco[ieta][ipt] += 1.0; + sumWiptiReco[ieta][ipt] += pt; + } + } + + if (effIncl <= 0 || !std::isfinite(wIncl) || !std::isfinite(fakeIncl) || !std::isfinite(flatWeightIncl)) + continue; + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + sumWiRecoEffCorr[ieta][ipt] += wIncl; + sumWiptiRecoEffCorr[ieta][ipt] += wIncl * pt; + } + } + + const bool isPion = selectionPion(track); + const bool isKaon = selectionKaon(track); + const bool isProton = selectionProton(track); + if (isPion || isKaon || isProton) { + float effPid = getEfficiency(col.multNTracksPV(), pt, eta, kCombinedPID, 0); + float fakePid = getEfficiency(col.multNTracksPV(), pt, eta, kCombinedPID, 1); + float flatWeightPid = getFlatteningWeight(cent, eta, phi, kCombinedPID); + float wPid = flatWeightPid * (1.0 - fakePid) / effPid; + + histos.fill(HIST("hCentEtaPhiWtd_PID"), cent, eta, track.phi(), flatWeightPid); + if (cent < KCentTestMin) + histos.fill(HIST("hCent1EtaPhiWtd_PID"), track.eta(), track.phi(), flatWeightPid); + if (cent > KCentTestMaxLo && cent < KCentTestMaxHi) + histos.fill(HIST("hCent7EtaPhiWtd_PID"), track.eta(), track.phi(), flatWeightPid); + + float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus + : o2::constants::physics::MassProton; + float energy = std::sqrt(p * p + m * m); + float et = energy * (pt / p); // E_T = E * sin(theta) + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + sumWiRecoEt[ieta][ipt] += 1.0; + sumWiptiRecoEt[ieta][ipt] += et; + } + } + + if (effPid <= KFloatEpsilon || !std::isfinite(wPid) || !std::isfinite(fakePid) || !std::isfinite(flatWeightPid)) + continue; + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + sumWiRecoEffCorrEt[ieta][ipt] += wPid; + sumWiptiRecoEffCorrEt[ieta][ipt] += wPid * et; + } + } + } + + if (std::isfinite(wIncl)) { + if (cent < KCentTestMin) { + histos.fill(HIST("wgt_pT"), pt, wIncl); + histos.fill(HIST("Eff_pT"), pt, effIncl); + histos.fill(HIST("Fake_pT"), pt, fakeIncl); + histos.fill(HIST("Eff_eta"), eta, effIncl); + histos.fill(HIST("Fake_eta"), eta, fakeIncl); + histos.fill(HIST("wgt_eta"), eta, wIncl); + } + histos.fill(HIST("Eff_cent"), cent, effIncl); + histos.fill(HIST("Eff_Ntrk"), col.multNTracksPV(), effIncl); + histos.fill(HIST("Fake_cent"), cent, fakeIncl); + histos.fill(HIST("Fake_Ntrk"), col.multNTracksPV(), fakeIncl); + histos.fill(HIST("wgt_cent"), cent, wIncl); + histos.fill(HIST("wgt_Ntrk"), col.multNTracksPV(), wIncl); + } + + } // end track loop + + if (std::isfinite(sumWiTruth[0][0])) { + float meanPtTruth = sumWiptiTruth[0][0] / sumWiTruth[0][0]; + if (!std::isfinite(meanPtTruth)) + LOGF(info, "meanPtTruth = %.3f, num = %.3f, den =%.3f", meanPtTruth, sumWiptiTruth[0][0], sumWiTruth[0][0]); + if (!std::isfinite(meanPtTruth)) + continue; + histos.fill(HIST("MCGen/Prof_cent_Nchrec"), cent, sumWiTruth[0][0]); + histos.fill(HIST("MCGen/Prof_MeanpT_Cent"), cent, meanPtTruth); + histos.fill(HIST("MCGen/Prof_MeanpT_Mult"), col.multNTracksPV(), meanPtTruth); + } + if (std::isfinite(sumWiReco[0][0])) { + float meanPtReco = sumWiptiReco[0][0] / sumWiReco[0][0]; + if (!std::isfinite(meanPtReco)) + LOGF(info, "meanPtReco = %.3f, num = %.3f, den =%.3f", meanPtReco, sumWiptiReco[0][0], sumWiReco[0][0]); + if (!std::isfinite(meanPtReco)) + continue; + histos.fill(HIST("MCReco/Prof_cent_Nchrec"), cent, sumWiReco[0][0]); + histos.fill(HIST("MCReco/Prof_MeanpT_Cent"), cent, meanPtReco); + histos.fill(HIST("MCReco/Prof_MeanpT_Mult"), col.multNTracksPV(), meanPtReco); + } + if (std::isfinite(sumWiRecoEffCorr[0][0])) { + float meanpTeffcorr = sumWiptiRecoEffCorr[0][0] / sumWiRecoEffCorr[0][0]; + if (!std::isfinite(meanpTeffcorr)) + LOGF(info, "meanPtRecoEffcorr = %.3f, num = %.3f, den =%.3f", meanpTeffcorr, sumWiptiRecoEffCorr[0][0], sumWiRecoEffCorr[0][0]); + if (!std::isfinite(meanpTeffcorr)) + continue; + histos.fill(HIST("MCRecoEffCorr/Prof_cent_Nchrec"), cent, sumWiRecoEffCorr[0][0]); + histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Cent"), cent, meanpTeffcorr); + histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Mult"), col.multNTracksPV(), meanpTeffcorr); + } + + if (std::isfinite(sumWiTruthEt[0][0])) { + float meanEt = sumWiptiTruthEt[0][0] / sumWiTruthEt[0][0]; + if (!std::isfinite(meanEt)) + LOGF(info, "meanEtTruthEt = %.3f, num = %.3f, den =%.3f", meanEt, sumWiptiTruthEt[0][0], sumWiTruthEt[0][0]); + if (!std::isfinite(meanEt)) + continue; + histos.fill(HIST("MCGen/Prof_MeanEt_Cent"), cent, meanEt); + histos.fill(HIST("MCGen/Prof_MeanEt_Mult"), col.multNTracksPV(), meanEt); + } + // "MCReco" + if (std::isfinite(sumWiRecoEt[0][0])) { + float meanEt = sumWiptiRecoEt[0][0] / sumWiRecoEt[0][0]; + if (!std::isfinite(meanEt)) + LOGF(info, "meanEtRecoEt = %.3f, num = %.3f, den =%.3f", meanEt, sumWiptiRecoEt[0][0], sumWiRecoEt[0][0]); + if (!std::isfinite(meanEt)) + continue; + histos.fill(HIST("MCReco/Prof_MeanEt_Cent"), cent, meanEt); + histos.fill(HIST("MCReco/Prof_MeanEt_Mult"), col.multNTracksPV(), meanEt); + } + // "MCRecoEffCorr" + if (std::isfinite(sumWiRecoEffCorrEt[0][0])) { + float meanEt = sumWiptiRecoEffCorrEt[0][0] / sumWiRecoEffCorrEt[0][0]; + if (!std::isfinite(meanEt)) + LOGF(info, "meanEtRecoEffcorrEt = %.3f, num = %.3f, den =%.3f", meanEt, sumWiptiRecoEffCorrEt[0][0], sumWiRecoEffCorrEt[0][0]); + if (!std::isfinite(meanEt)) + continue; + histos.fill(HIST("MCRecoEffCorr/Prof_MeanEt_Cent"), cent, meanEt); + histos.fill(HIST("MCRecoEffCorr/Prof_MeanEt_Mult"), col.multNTracksPV(), meanEt); + } + + for (int ieta = 0; ieta < KNEta; ++ieta) { + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (std::isfinite(sumWiTruth[ieta][ipt])) + histos.fill(HIST("pmeanTruNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiTruth[ieta][ipt] / sumWiTruth[ieta][ipt]); + if (std::isfinite(sumWiReco[ieta][ipt])) + histos.fill(HIST("pmeanRecoNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiReco[ieta][ipt] / sumWiReco[ieta][ipt]); + if (std::isfinite(sumWiRecoEffCorr[ieta][ipt])) + histos.fill(HIST("pmeanRecoEffcorrNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiRecoEffCorr[ieta][ipt] / sumWiRecoEffCorr[ieta][ipt]); + + if (std::isfinite(sumWiTruthEt[ieta][ipt])) + histos.fill(HIST("pmeanEtTruNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiTruthEt[ieta][ipt] / sumWiTruthEt[ieta][ipt]); + if (std::isfinite(sumWiRecoEt[ieta][ipt])) + histos.fill(HIST("pmeanEtRecoNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiRecoEt[ieta][ipt] / sumWiRecoEt[ieta][ipt]); + if (std::isfinite(sumWiRecoEffCorrEt[ieta][ipt])) + histos.fill(HIST("pmeanEtRecoEffcorrNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, sumWiptiRecoEffCorrEt[ieta][ipt] / sumWiRecoEffCorrEt[ieta][ipt]); + } + } + } // end col loop + } + + LOGF(info, "FINISHED RUNNING processMCMean (pT + Et)"); + } + PROCESS_SWITCH(RadialFlowDecorr, processMCMean, "process MC to calculate mean pt/Et and Eff Hists", cfgRunMCMean); + + void processMCFluc(aod::McCollisions const& mcColl, MyRun3MCCollisions const& collisions, TCs const& tracks, FilteredTCs const& /*filteredTracks*/, aod::McParticles const& mcParticles) + { + double sumPmwkTru[KNEta][KNpT][KIntM][KIntK]{}; + double sumWkTru[KNEta][KNpT][KIntK]{}; + double sumPmwkReco[KNEta][KNpT][KIntM][KIntK]{}; + double sumWkReco[KNEta][KNpT][KIntK]{}; + double sumPmwkRecoEffCor[KNEta][KNpT][KIntM][KIntK]{}; + double sumWkRecoEffCor[KNEta][KNpT][KIntK]{}; + double sumPmwkTruEt[KNEta][KNpT][KIntM][KIntK]{}; + double sumWkTruEt[KNEta][KNpT][KIntK]{}; + double sumPmwkRecoEt[KNEta][KNpT][KIntM][KIntK]{}; + double sumWkRecoEt[KNEta][KNpT][KIntK]{}; + double sumPmwkRecoEffCorEt[KNEta][KNpT][KIntM][KIntK]{}; + double sumWkRecoEffCorEt[KNEta][KNpT][KIntK]{}; + double meanTru[KNEta][KNpT]{}, c2Tru[KNEta][KNpT]{}; + double meanReco[KNEta][KNpT]{}, c2Reco[KNEta][KNpT]{}; + double meanRecoEffCor[KNEta][KNpT]{}, c2RecoEffCor[KNEta][KNpT]{}; + double meanTruEt[KNEta][KNpT]{}, c2TruEt[KNEta][KNpT]{}; + double meanRecoEt[KNEta][KNpT]{}, c2RecoEt[KNEta][KNpT]{}; + double meanRecoEffCorEt[KNEta][KNpT]{}, c2RecoEffCorEt[KNEta][KNpT]{}; + + for (const auto& mcCollision : mcColl) { + auto partSlice = mcParticles.sliceBy(partPerMcCollision, mcCollision.globalIndex()); + auto colSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + if (colSlice.size() != 1) + continue; + // histos.fill(HIST("MCGen/hVtxZ"), mcCollision.posZ()); + for (const auto& col : colSlice) { + + auto trackSlice = tracks.sliceBy(trackPerCollision, col.globalIndex()); + if (trackSlice.size() < 1) + continue; + + memset(sumPmwkTru, 0, sizeof(sumPmwkTru)); + memset(sumWkTru, 0, sizeof(sumWkTru)); + memset(sumPmwkReco, 0, sizeof(sumPmwkReco)); + memset(sumWkReco, 0, sizeof(sumWkReco)); + memset(sumPmwkRecoEffCor, 0, sizeof(sumPmwkRecoEffCor)); + memset(sumWkRecoEffCor, 0, sizeof(sumWkRecoEffCor)); + + memset(sumPmwkTruEt, 0, sizeof(sumPmwkTruEt)); + memset(sumWkTruEt, 0, sizeof(sumWkTruEt)); + memset(sumPmwkRecoEt, 0, sizeof(sumPmwkRecoEt)); + memset(sumWkRecoEt, 0, sizeof(sumWkRecoEt)); + memset(sumPmwkRecoEffCorEt, 0, sizeof(sumPmwkRecoEffCorEt)); + memset(sumWkRecoEffCorEt, 0, sizeof(sumWkRecoEffCorEt)); + + memset(meanTru, 0, sizeof(meanTru)); + memset(c2Tru, 0, sizeof(c2Tru)); + memset(meanReco, 0, sizeof(meanReco)); + memset(c2Reco, 0, sizeof(c2Reco)); + memset(meanRecoEffCor, 0, sizeof(meanRecoEffCor)); + memset(c2RecoEffCor, 0, sizeof(c2RecoEffCor)); + + memset(meanTruEt, 0, sizeof(meanTruEt)); + memset(c2TruEt, 0, sizeof(c2TruEt)); + memset(meanRecoEt, 0, sizeof(meanRecoEt)); + memset(c2RecoEt, 0, sizeof(c2RecoEt)); + memset(meanRecoEffCorEt, 0, sizeof(meanRecoEffCorEt)); + memset(c2RecoEffCorEt, 0, sizeof(c2RecoEffCorEt)); + + if (!col.has_mcCollision() || !isEventSelected(col)) + continue; + float cent = getCentrality(col); + if (cent > KCentMax) + continue; + + // truth + for (const auto& particle : partSlice) { + if (!isParticleSelected(particle)) + continue; + if (!particle.isPhysicalPrimary()) + continue; + float pt = particle.pt(); + float eta = particle.eta(); + float p = particle.p(); + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumPmwkTru[ieta][ipt][m][k] += std::pow(pt, m); + } + sumWkTru[ieta][ipt][k]++; + } + } + } + const int absPdgId = std::abs(particle.pdgCode()); + const bool isPion = (absPdgId == kPiPlus); + const bool isKaon = (absPdgId == kKPlus); + const bool isProton = (absPdgId == kProton); + if (isPion || isKaon || isProton) { + + float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus + : o2::constants::physics::MassProton; + float energy = std::sqrt(p * p + m * m); + float et = energy * (pt / p); + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumPmwkTruEt[ieta][ipt][m][k] += std::pow(et, m); + } + sumWkTruEt[ieta][ipt][k]++; + } + } + } + } + + } // end truth loop + + for (const auto& track : trackSlice) { + if (!isTrackSelected(track)) + continue; + float pt = track.pt(); + float eta = track.eta(); + float p = track.p(); + float phi = track.phi(); + + float effIncl = getEfficiency(col.multNTracksPV(), pt, eta, kInclusive, 0); + float fakeIncl = getEfficiency(col.multNTracksPV(), pt, eta, kInclusive, 1); + float flatWeightIncl = getFlatteningWeight(cent, eta, phi, kInclusive); + float wIncl = flatWeightIncl * (1.0 - fakeIncl) / effIncl; + if (!std::isfinite(wIncl) || wIncl <= 0.f) + continue; + if (effIncl <= 0 || !std::isfinite(effIncl) || !std::isfinite(fakeIncl) || !std::isfinite(flatWeightIncl)) + continue; + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumPmwkReco[ieta][ipt][m][k] += std::pow(1.0f, k) * std::pow(pt, m); + sumPmwkRecoEffCor[ieta][ipt][m][k] += std::pow(wIncl, k) * std::pow(pt, m); + } + sumWkReco[ieta][ipt][k] += std::pow(1.0f, k); + sumWkRecoEffCor[ieta][ipt][k] += std::pow(wIncl, k); + } + } + } + + const bool isPion = selectionPion(track); + const bool isKaon = selectionKaon(track); + const bool isProton = selectionProton(track); + + if (isPion || isKaon || isProton) { + float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus + : o2::constants::physics::MassProton; + float energy = std::sqrt(p * p + m * m); + float et = energy * (pt / p); // E_T = E * sin(theta) + float effPid = getEfficiency(col.multNTracksPV(), pt, eta, kCombinedPID, 0); + float fakePid = getEfficiency(col.multNTracksPV(), pt, eta, kCombinedPID, 1); + float flatWeightPid = getFlatteningWeight(cent, eta, phi, kCombinedPID); + float wPid = flatWeightPid * (1.0 - fakePid) / effPid; + if (effPid >= 1.f || fakePid >= 1.f || !std::isfinite(effPid) || effPid <= KFloatEpsilon || !std::isfinite(fakePid) || !std::isfinite(flatWeightPid)) + continue; + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumPmwkRecoEt[ieta][ipt][m][k] += std::pow(1.0f, k) * std::pow(et, m); + sumPmwkRecoEffCorEt[ieta][ipt][m][k] += std::pow(wPid, k) * std::pow(et, m); + } + sumWkRecoEt[ieta][ipt][k] += std::pow(1.0f, k); + sumWkRecoEffCorEt[ieta][ipt][k] += std::pow(wPid, k); + } + } + } + } + + for (int ieta = 0; ieta < KNEta; ++ieta) { + for (int ipt = 0; ipt < KNpT; ++ipt) { + const int ibx = pmeanTruNchEtabinPtbinStep2->GetXaxis()->FindBin(col.multNTracksPV()); + const int iby = ieta + 1; + const int ibz = ipt + 1; + + float mmptTru = pmeanTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmptReco = pmeanRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmptRecoEffCor = pmeanRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmetTru = pmeanEtTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmetReco = pmeanEtRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmetRecoEffCor = pmeanEtRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + + if (std::isfinite(mmptTru)) + std::tie(meanTru[ieta][ipt], c2Tru[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkTru[ieta][ipt], sumWkTru[ieta][ipt], mmptTru); + if (std::isfinite(mmptReco)) + std::tie(meanReco[ieta][ipt], c2Reco[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkReco[ieta][ipt], sumWkReco[ieta][ipt], mmptReco); + if (std::isfinite(mmptRecoEffCor)) + std::tie(meanRecoEffCor[ieta][ipt], c2RecoEffCor[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkRecoEffCor[ieta][ipt], sumWkRecoEffCor[ieta][ipt], mmptRecoEffCor); + + if (std::isfinite(mmetTru)) + std::tie(meanTruEt[ieta][ipt], c2TruEt[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkTruEt[ieta][ipt], sumWkTruEt[ieta][ipt], mmetTru); + if (std::isfinite(mmetReco)) + std::tie(meanRecoEt[ieta][ipt], c2RecoEt[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkRecoEt[ieta][ipt], sumWkRecoEt[ieta][ipt], mmetReco); + if (std::isfinite(mmetRecoEffCor)) + std::tie(meanRecoEffCorEt[ieta][ipt], c2RecoEffCorEt[ieta][ipt]) = calculateMeanAndC2FromSums(sumPmwkRecoEffCorEt[ieta][ipt], sumWkRecoEffCorEt[ieta][ipt], mmetRecoEffCor); + } + } + } + if (std::isfinite(c2Tru[0][0])) { + histos.fill(HIST("MCGen/Prof_C2_Cent"), cent, c2Tru[0][0]); + histos.fill(HIST("MCGen/Prof_C2_Mult"), col.multNTracksPV(), c2Tru[0][0]); + } + if (std::isfinite(c2TruEt[0][0])) { + histos.fill(HIST("MCGen/Prof_C2Et_Cent"), cent, c2TruEt[0][0]); + histos.fill(HIST("MCGen/Prof_C2Et_Mult"), col.multNTracksPV(), c2TruEt[0][0]); + } + // "MCReco" + if (std::isfinite(c2Reco[0][0])) { + histos.fill(HIST("MCReco/Prof_C2_Cent"), cent, c2Reco[0][0]); + histos.fill(HIST("MCReco/Prof_C2_Mult"), col.multNTracksPV(), c2Reco[0][0]); + } + if (std::isfinite(c2RecoEt[0][0])) { + histos.fill(HIST("MCReco/Prof_C2Et_Cent"), cent, c2RecoEt[0][0]); + histos.fill(HIST("MCReco/Prof_C2Et_Mult"), col.multNTracksPV(), c2RecoEt[0][0]); + } + + if (std::isfinite(c2RecoEffCor[0][0])) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2_Cent"), cent, c2RecoEffCor[0][0]); + histos.fill(HIST("MCRecoEffCorr/Prof_C2_Mult"), col.multNTracksPV(), c2RecoEffCor[0][0]); + } + if (std::isfinite(c2RecoEffCorEt[0][0])) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Et_Cent"), cent, c2RecoEffCorEt[0][0]); + histos.fill(HIST("MCRecoEffCorr/Prof_C2Et_Mult"), col.multNTracksPV(), c2RecoEffCorEt[0][0]); + } + + if (std::isfinite(sumWkTru[0][0][1])) { + histos.fill(HIST("MCGen/Prof_cent_Nchrec"), cent, sumWkTru[0][0][1]); + histos.fill(HIST("MCGen/Prof_MeanpT_Cent"), cent, meanTru[0][0]); + histos.fill(HIST("MCGen/Prof_MeanpT_Mult"), col.multNTracksPV(), meanTru[0][0]); + } + if (std::isfinite(sumWkTruEt[0][0][1])) { + histos.fill(HIST("MCGen/Prof_MeanEt_Cent"), cent, meanTruEt[0][0]); + histos.fill(HIST("MCGen/Prof_MeanEt_Mult"), col.multNTracksPV(), meanTruEt[0][0]); + } + // "MCReco" + if (std::isfinite(sumWkReco[0][0][1])) { + histos.fill(HIST("MCReco/Prof_cent_Nchrec"), cent, sumWkReco[0][0][1]); + histos.fill(HIST("MCReco/Prof_MeanpT_Cent"), cent, meanReco[0][0]); + histos.fill(HIST("MCReco/Prof_MeanpT_Mult"), col.multNTracksPV(), meanReco[0][0]); + } + if (std::isfinite(sumWkRecoEt[0][0][1])) { + histos.fill(HIST("MCReco/Prof_MeanEt_Cent"), cent, meanRecoEt[0][0]); + histos.fill(HIST("MCReco/Prof_MeanEt_Mult"), col.multNTracksPV(), meanRecoEt[0][0]); + } + // "MCRecoEffCorr" + if (std::isfinite(sumWkRecoEffCor[0][0][1])) { + histos.fill(HIST("MCRecoEffCorr/Prof_cent_Nchrec"), cent, sumWkRecoEffCor[0][0][1]); + histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Cent"), cent, meanRecoEffCor[0][0]); + histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Mult"), col.multNTracksPV(), meanRecoEffCor[0][0]); + } + if (std::isfinite(sumWkRecoEffCorEt[0][0][1])) { + histos.fill(HIST("MCRecoEffCorr/Prof_MeanEt_Cent"), cent, meanRecoEffCorEt[0][0]); + histos.fill(HIST("MCRecoEffCorr/Prof_MeanEt_Mult"), col.multNTracksPV(), meanRecoEffCorEt[0][0]); + } + + for (int ieta = 0; ieta < KNEta; ++ieta) { + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (std::isfinite(sumWkTru[ieta][ipt][1])) + histos.fill(HIST("pmeanTruNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, meanTru[ieta][ipt]); + if (std::isfinite(sumWkReco[ieta][ipt][1])) + histos.fill(HIST("pmeanRecoNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, meanReco[ieta][ipt]); + if (std::isfinite(sumWkRecoEffCor[ieta][ipt][1])) + histos.fill(HIST("pmeanRecoEffcorrNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, meanRecoEffCor[ieta][ipt]); + if (std::isfinite(sumWkTruEt[ieta][ipt][1])) + histos.fill(HIST("pmeanEtTruNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, meanTruEt[ieta][ipt]); + if (std::isfinite(sumWkRecoEt[ieta][ipt][1])) + histos.fill(HIST("pmeanEtRecoNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, meanRecoEt[ieta][ipt]); + if (std::isfinite(sumWkRecoEffCorEt[ieta][ipt][1])) + histos.fill(HIST("pmeanEtRecoEffcorrNchEtabinPtbin"), col.multNTracksPV(), ieta, ipt, meanRecoEffCorEt[ieta][ipt]); + } + } + + float p1kBarTru[KNEta][KNpT]{}, p1kBarReco[KNEta][KNpT]{}, p1kBarRecoEffCor[KNEta][KNpT]{}; + float p1kBarTruEt[KNEta][KNpT]{}, p1kBarRecoEt[KNEta][KNpT]{}, p1kBarRecoEffCorEt[KNEta][KNpT]{}; + for (int ieta = 0; ieta < KNEta; ++ieta) { + for (int ipt = 0; ipt < KNpT; ++ipt) { + const int ibx = pmeanTruNchEtabinPtbinStep2->GetXaxis()->FindBin(col.multNTracksPV()); + const int iby = ieta + 1; + const int ibz = ipt + 1; + + float mmptTru = pmeanTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmptReco = pmeanRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmptRecoEffCor = pmeanRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmetTru = pmeanEtTruNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmetReco = pmeanEtRecoNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmetRecoEffCor = pmeanEtRecoEffcorrNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + + if (mmptTru != 0.0f) + p1kBarTru[ieta][ipt] = meanTru[ieta][ipt] - mmptTru; + if (mmptReco != 0.0f) + p1kBarReco[ieta][ipt] = meanReco[ieta][ipt] - mmptReco; + if (mmptRecoEffCor != 0.0f) + p1kBarRecoEffCor[ieta][ipt] = meanRecoEffCor[ieta][ipt] - mmptRecoEffCor; + + if (mmetTru != 0.0f) + p1kBarTruEt[ieta][ipt] = meanTruEt[ieta][ipt] - mmetTru; + if (mmetReco != 0.0f) + p1kBarRecoEt[ieta][ipt] = meanRecoEt[ieta][ipt] - mmetReco; + if (mmetRecoEffCor != 0.0f) + p1kBarRecoEffCorEt[ieta][ipt] = meanRecoEffCorEt[ieta][ipt] - mmetRecoEffCor; + } + } + + // 1D Covariance (vs eta) + for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { + int ietaC = KNEta - ietaA; + float valy = KHalf * (etaLw[ietaC] + etaUp[ietaC]); + { + const int ipt = 0; + float c2Sub = p1kBarTru[ietaA][ipt] * p1kBarTru[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCGen/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCGen/Prof_ipt0_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCGen/Prof_ipt0_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarTruEt[ietaA][ipt] * p1kBarTruEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCGen/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCGen/Prof_ipt0_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCGen/Prof_ipt0_CovEt_Eta"), valy, c2SubEt); + } + } + // ipt = 1 + { + const int ipt = 1; + float c2Sub = p1kBarTru[ietaA][ipt] * p1kBarTru[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCGen/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCGen/Prof_ipt1_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCGen/Prof_ipt0_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarTruEt[ietaA][ipt] * p1kBarTruEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCGen/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCGen/Prof_ipt1_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCGen/Prof_ipt1_CovEt_Eta"), valy, c2SubEt); + } + } + // ipt = 2 + { + const int ipt = 2; + float c2Sub = p1kBarTru[ietaA][ipt] * p1kBarTru[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCGen/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCGen/Prof_ipt2_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCGen/Prof_ipt2_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarTruEt[ietaA][ipt] * p1kBarTruEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCGen/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCGen/Prof_ipt2_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCGen/Prof_ipt2_CovEt_Eta"), valy, c2SubEt); + } + } + } + + for (int ietaA = 1; ietaA < KNEta; ++ietaA) { + for (int ietaC = 1; ietaC < KNEta; ++ietaC) { + float valx = KHalf * (etaLw[ietaA] + etaUp[ietaA]); + float valy = KHalf * (etaLw[ietaC] + etaUp[ietaC]); + // ipt = 0 + { + const int ipt = 0; + float c2Sub = p1kBarTru[ietaA][ipt] * p1kBarTru[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCGen/Prof_ipt0_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarTruEt[ietaA][ipt] * p1kBarTruEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCGen/Prof_ipt0_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + // ipt = 1 + { + const int ipt = 1; + float c2Sub = p1kBarTru[ietaA][ipt] * p1kBarTru[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCGen/Prof_ipt1_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarTruEt[ietaA][ipt] * p1kBarTruEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCGen/Prof_ipt1_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + // ipt = 2 + { + const int ipt = 2; + float c2Sub = p1kBarTru[ietaA][ipt] * p1kBarTru[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCGen/Prof_ipt2_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarTruEt[ietaA][ipt] * p1kBarTruEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCGen/Prof_ipt2_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + } + } + + for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { + int ietaC = KNEta - ietaA; + float valy = KHalf * (etaLw[ietaC] + etaUp[ietaC]); + // ipt = 0 + { + const int ipt = 0; + float c2Sub = p1kBarReco[ietaA][ipt] * p1kBarReco[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCReco/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCReco/Prof_ipt0_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCReco/Prof_ipt0_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarRecoEt[ietaA][ipt] * p1kBarRecoEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCReco/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCReco/Prof_ipt0_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCReco/Prof_ipt0_CovEt_Eta"), valy, c2SubEt); + } + } + + // ipt = 1 + { + const int ipt = 1; + float c2Sub = p1kBarReco[ietaA][ipt] * p1kBarReco[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCReco/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCReco/Prof_ipt1_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCReco/Prof_ipt1_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarRecoEt[ietaA][ipt] * p1kBarRecoEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCReco/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCReco/Prof_ipt1_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCReco/Prof_ipt1_CovEt_Eta"), valy, c2SubEt); + } + } + + // ipt = 2 + { + const int ipt = 2; + float c2Sub = p1kBarReco[ietaA][ipt] * p1kBarReco[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCReco/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCReco/Prof_ipt2_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCReco/Prof_ipt2_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarRecoEt[ietaA][ipt] * p1kBarRecoEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCReco/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCReco/Prof_ipt2_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCReco/Prof_ipt2_CovEt_Eta"), valy, c2SubEt); + } + } + } + + for (int ietaA = 1; ietaA < KNEta; ++ietaA) { + for (int ietaC = 1; ietaC < KNEta; ++ietaC) { + float valx = KHalf * (etaLw[ietaA] + etaUp[ietaA]); + float valy = KHalf * (etaLw[ietaC] + etaUp[ietaC]); + + // ipt = 0 + { + const int ipt = 0; + float c2Sub = p1kBarReco[ietaA][ipt] * p1kBarReco[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCReco/Prof_ipt0_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarRecoEt[ietaA][ipt] * p1kBarRecoEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCReco/Prof_ipt0_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + + // ipt = 1 + { + const int ipt = 1; + float c2Sub = p1kBarReco[ietaA][ipt] * p1kBarReco[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCReco/Prof_ipt1_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarRecoEt[ietaA][ipt] * p1kBarRecoEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCReco/Prof_ipt1_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + + // ipt = 2 + { + const int ipt = 2; + float c2Sub = p1kBarReco[ietaA][ipt] * p1kBarReco[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCReco/Prof_ipt2_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarRecoEt[ietaA][ipt] * p1kBarRecoEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCReco/Prof_ipt2_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + } + } + + for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { + int ietaC = KNEta - ietaA; + float valy = KHalf * (etaLw[ietaC] + etaUp[ietaC]); + + // ipt = 0 + { + const int ipt = 0; + float c2Sub = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarRecoEffCorEt[ietaA][ipt] * p1kBarRecoEffCorEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_CovEt_Eta"), valy, c2SubEt); + } + } + + // ipt = 1 + { + const int ipt = 1; + float c2Sub = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarRecoEffCorEt[ietaA][ipt] * p1kBarRecoEffCorEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_CovEt_Eta"), valy, c2SubEt); + } + } + + // ipt = 2 + { + const int ipt = 2; + float c2Sub = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2Sub); + histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarRecoEffCorEt[ietaA][ipt] * p1kBarRecoEffCorEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2EtSub_Mult_etabin_ptbin"), col.multNTracksPV(), ietaA, ipt, c2SubEt); + histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_CovEt_Eta"), valy, c2SubEt); + } + } + } + + for (int ietaA = 1; ietaA < KNEta; ++ietaA) { + for (int ietaC = 1; ietaC < KNEta; ++ietaC) { + float valx = 0.5f * (etaLw[ietaA] + etaUp[ietaA]); + float valy = KHalf * (etaLw[ietaC] + etaUp[ietaC]); + + // ipt = 0 + { + const int ipt = 0; + float c2Sub = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarRecoEffCorEt[ietaA][ipt] * p1kBarRecoEffCorEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt0_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + + // ipt = 1 + { + const int ipt = 1; + float c2Sub = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarRecoEffCorEt[ietaA][ipt] * p1kBarRecoEffCorEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt1_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + + // ipt = 2 + { + const int ipt = 2; + float c2Sub = p1kBarRecoEffCor[ietaA][ipt] * p1kBarRecoEffCor[ietaC][ipt]; + if (std::isfinite(c2Sub)) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, c2Sub); + float c2SubEt = p1kBarRecoEffCorEt[ietaA][ipt] * p1kBarRecoEffCorEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) + histos.fill(HIST("MCRecoEffCorr/Prof_ipt2_C2EtSub2D_Mult_etaA_etaC"), cent, valx, valy, c2SubEt); + } + } + } + } + } + LOGF(info, "FINISHED RUNNING processMCFluc (pT + Et)"); + } + PROCESS_SWITCH(RadialFlowDecorr, processMCFluc, "process MC to calculate pt/Et fluc", cfgRunMCFluc); + + void processGetFlat(AodCollisionsSel::iterator const& coll, aod::BCsWithTimestamps const&, AodTracksSel const& tracks) + { + if (!isEventSelected(coll)) + return; + float cent = getCentrality(coll); + if (cent > KCentMax) + return; + for (const auto& track : tracks) { + if (!isTrackSelected(track)) + continue; + float p = track.p(); + float eta = track.eta(); + float phi = track.phi(); + if (p < KFloatEpsilon) + continue; + histos.fill(HIST("hCentEtaPhi"), cent, eta, phi); + const bool isPion = selectionPion(track); + const bool isKaon = selectionKaon(track); + const bool isProton = selectionProton(track); + if (isPion || isKaon || isProton) { + histos.fill(HIST("hCentEtaPhi_PID"), cent, eta, phi); + } + } + } + PROCESS_SWITCH(RadialFlowDecorr, processGetFlat, "process real data to calculate mean pT and Et", cfgRunGetFlat); + + void processDataMean(AodCollisionsSel::iterator const& coll, aod::BCsWithTimestamps const&, AodTracksSel const& tracks) + { + float sumWi[KNEta][KNpT]{}, sumWipti[KNEta][KNpT]{}; + float sumWiEt[KNEta][KNpT]{}, sumWiEtVal[KNEta][KNpT]{}; + if (!isEventSelected(coll)) + return; + + float cent = getCentrality(coll); + if (cent > KCentMax) + return; + + histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + histos.fill(HIST("hCentrality"), cent); + + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); + + for (const auto& track : tracks) { + if (!isTrackSelected(track)) + continue; + float pt = track.pt(); + float eta = track.eta(); + float p = track.p(); + float phi = track.phi(); + if (p < KFloatEpsilon) + continue; + histos.fill(HIST("hP"), p); + histos.fill(HIST("hPt"), pt); + histos.fill(HIST("hEta"), eta); + histos.fill(HIST("hPhi"), track.phi()); + + float effIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 0); + float fakeIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 1); + float flatWeightIncl = getFlatteningWeight(cent, eta, phi, kInclusive); + float wIncl = flatWeightIncl * (1.0 - fakeIncl) / effIncl; + if (!std::isfinite(wIncl) || wIncl <= KFloatEpsilon || effIncl <= KFloatEpsilon) + continue; + + histos.fill(HIST("hCentEtaPhi"), cent, eta, track.phi()); + histos.fill(HIST("hCentEtaPhiWtd"), cent, eta, track.phi(), flatWeightIncl); + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + sumWi[ieta][ipt] += wIncl; + sumWipti[ieta][ipt] += wIncl * pt; + } + } + + const bool isPion = selectionPion(track); + const bool isKaon = selectionKaon(track); + const bool isProton = selectionProton(track); + if (isPion || isKaon || isProton) { + + float effPid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 0); + float fakePid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 1); + float flatWeightPid = getFlatteningWeight(cent, eta, phi, kCombinedPID); + float wPid = flatWeightPid * (1.0 - fakePid) / effPid; + if (!std::isfinite(wPid) || wPid <= KFloatEpsilon || effPid <= KFloatEpsilon) + continue; + + histos.fill(HIST("hCentEtaPhiWtd_PID"), cent, eta, track.phi(), flatWeightPid); + float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus + : o2::constants::physics::MassProton; + float energy = std::sqrt(p * p + m * m); + float et = energy * (pt / p); // E_T = E * sin(theta) + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + sumWiEt[ieta][ipt] += wPid; + sumWiEtVal[ieta][ipt] += wPid * et; + } + } + } + } + histos.fill(HIST("Prof_cent_Nchrec"), cent, sumWi[0][0]); + if (std::isfinite(sumWi[0][0])) + histos.fill(HIST("Prof_MeanpT_Cent"), cent, sumWipti[0][0] / sumWi[0][0]); + if (std::isfinite(sumWiEt[0][0])) + histos.fill(HIST("Prof_MeanEt_Cent"), cent, sumWiEtVal[0][0] / sumWiEt[0][0]); + + for (int ieta = 0; ieta < KNEta; ++ieta) { + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (std::isfinite(sumWi[ieta][ipt])) + histos.fill(HIST("pmean_nch_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, sumWipti[ieta][ipt] / sumWi[ieta][ipt]); + if (std::isfinite(sumWiEt[ieta][ipt])) + histos.fill(HIST("pmeanEt_nch_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, sumWiEtVal[ieta][ipt] / sumWiEt[ieta][ipt]); + } + } + } + PROCESS_SWITCH(RadialFlowDecorr, processDataMean, "process real data to calculate mean pT and Et", cfgRunDataMean); + + void processDataFluc(AodCollisionsSel::iterator const& coll, aod::BCsWithTimestamps const&, AodTracksSel const& tracks) + { + if (!isEventSelected(coll)) + return; + float cent = getCentrality(coll); + if (cent > KCentMax) + return; + if (!pmeanNchEtabinPtbinStep2 || !pmeanEtNchEtabinPtbinStep2) { + LOGF(warning, "Data fluc: Mean pT or Et map missing"); + return; + } + + if (!hEff[kInclusive] || !hFake[kInclusive] || !hWeightMap3D[kInclusive] || !hEff[kCombinedPID] || !hFake[kCombinedPID] || !hWeightMap3D[kCombinedPID]) { + LOGF(warning, "Data fluc: Inclusive or PID correction maps are null"); + return; + } + double sumpmwk[KNEta][KNpT][KIntM][KIntK]{}; + double sumwk[KNEta][KNpT][KIntK]{}; + double sumpmwkEt[KNEta][KNpT][KIntM][KIntK]{}; + double sumwkEt[KNEta][KNpT][KIntK]{}; + double mean[KNEta][KNpT]{}, c2[KNEta][KNpT]{}; + double p1kBar[KNEta][KNpT]{}; + double meanEt[KNEta][KNpT]{}, c2Et[KNEta][KNpT]{}; + double p1kBarEt[KNEta][KNpT]{}; + + for (const auto& track : tracks) { + if (!isTrackSelected(track)) + continue; + float pt = track.pt(); + float eta = track.eta(); + float p = track.p(); + float phi = track.phi(); + if (p < KFloatEpsilon) + continue; + + float effIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 0); + float fakeIncl = getEfficiency(coll.multNTracksPV(), pt, eta, kInclusive, 1); + float flatWeightIncl = getFlatteningWeight(cent, eta, phi, kInclusive); + + float wIncl = flatWeightIncl * (1.0 - fakeIncl) / effIncl; + if (!std::isfinite(wIncl) || wIncl <= KFloatEpsilon || effIncl <= KFloatEpsilon) + continue; + + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) + sumpmwk[ieta][ipt][m][k] += std::pow(wIncl, k) * std::pow(pt, m); + sumwk[ieta][ipt][k] += std::pow(wIncl, k); + } + } + } + + const bool isPion = selectionPion(track); + const bool isKaon = selectionKaon(track); + const bool isProton = selectionProton(track); + if (isPion || isKaon || isProton) { + float effPid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 0); + float fakePid = getEfficiency(coll.multNTracksPV(), pt, eta, kCombinedPID, 1); + float flatWeightPid = getFlatteningWeight(cent, eta, phi, kCombinedPID); + + float wPid = flatWeightPid * (1.0 - fakePid) / effPid; + if (!std::isfinite(wPid) || wPid <= KFloatEpsilon || effPid <= KFloatEpsilon) + continue; + + float m = isPion ? o2::constants::physics::MassPiPlus : isKaon ? o2::constants::physics::MassKPlus + : o2::constants::physics::MassProton; + + float energy = std::sqrt(p * p + m * m); + float et = energy * (pt / p); // E_T = E * sin(theta) + for (int ieta = 0; ieta < KNEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + continue; + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (pt <= pTLw[ipt] || pt > pTUp[ipt]) + continue; + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) + sumpmwkEt[ieta][ipt][m][k] += std::pow(wPid, k) * std::pow(et, m); + sumwkEt[ieta][ipt][k] += std::pow(wPid, k); + } + } + } + } + } + + for (int ieta = 0; ieta < KNEta; ++ieta) { + for (int ipt = 0; ipt < KNpT; ++ipt) { + const int ibx = pmeanNchEtabinPtbinStep2->GetXaxis()->FindBin(coll.multNTracksPV()); + const int iby = ieta + 1; + const int ibz = ipt + 1; + float mmpt = pmeanNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + float mmet = pmeanEtNchEtabinPtbinStep2->GetBinContent(ibx, iby, ibz); + + mean[ieta][ipt] = sumpmwk[ieta][ipt][1][1] / sumwk[ieta][ipt][1]; + meanEt[ieta][ipt] = sumpmwkEt[ieta][ipt][1][1] / sumwkEt[ieta][ipt][1]; + + if (std::isfinite(mmpt)) { + std::tie(mean[ieta][ipt], c2[ieta][ipt]) = + calculateMeanAndC2FromSums(sumpmwk[ieta][ipt], sumwk[ieta][ipt], mmpt); + p1kBar[ieta][ipt] = mean[ieta][ipt] - mmpt; + } + if (std::isfinite(mmet)) { + std::tie(meanEt[ieta][ipt], c2Et[ieta][ipt]) = + calculateMeanAndC2FromSums(sumpmwkEt[ieta][ipt], sumwkEt[ieta][ipt], mmet); + p1kBarEt[ieta][ipt] = meanEt[ieta][ipt] - mmet; + } + } + } + + if (std::isfinite(c2[0][0])) + histos.fill(HIST("Prof_C2_Cent"), cent, c2[0][0]); + if (std::isfinite(c2Et[0][0])) + histos.fill(HIST("Prof_C2Et_Cent"), cent, c2Et[0][0]); + if (std::isfinite(sumwk[0][0][1])) { + histos.fill(HIST("Prof_MeanpT_Cent"), cent, mean[0][0]); + histos.fill(HIST("Prof_MeanpT_Mult"), coll.multNTracksPV(), mean[0][0]); + } + if (std::isfinite(sumwkEt[0][0][1])) { + histos.fill(HIST("Prof_MeanEt_Cent"), cent, meanEt[0][0]); + histos.fill(HIST("Prof_MeanEt_Mult"), coll.multNTracksPV(), meanEt[0][0]); + } + + for (int ieta = 0; ieta < KNEta; ++ieta) { + for (int ipt = 0; ipt < KNpT; ++ipt) { + if (std::isfinite(c2[ieta][ipt])) + histos.fill(HIST("Prof_C2_Mult_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, c2[ieta][ipt]); + if (std::isfinite(c2Et[ieta][ipt])) + histos.fill(HIST("Prof_C2Et_Mult_etabin_ptbin"), coll.multNTracksPV(), ieta, ipt, c2Et[ieta][ipt]); + } + } + + for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { + int ietaC = KNEta - ietaA; + float valy = KHalf * (etaLw[ietaC] + etaUp[ietaC]); + + { + const int ipt = 0; + float c2Sub = p1kBar[ietaA][ipt] * p1kBar[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_ipt0_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("Prof_ipt0_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarEt[ietaA][ipt] * p1kBarEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("Prof_ipt0_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("Prof_ipt0_CovEt_Eta"), valy, c2SubEt); + } + } + + { + const int ipt = 1; + float c2Sub = p1kBar[ietaA][ipt] * p1kBar[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_ipt1_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("Prof_ipt1_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarEt[ietaA][ipt] * p1kBarEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("Prof_ipt1_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("Prof_ipt1_CovEt_Eta"), valy, c2SubEt); + } + } + + { + const int ipt = 2; + float c2Sub = p1kBar[ietaA][ipt] * p1kBar[ietaC][ipt]; + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_ipt2_Cov_Cent_eta"), cent, valy, c2Sub); + if (cent < KCentCovCut) + histos.fill(HIST("Prof_ipt2_Cov_Eta"), valy, c2Sub); + } + float c2SubEt = p1kBarEt[ietaA][ipt] * p1kBarEt[ietaC][ipt]; + if (std::isfinite(c2SubEt)) { + histos.fill(HIST("Prof_ipt2_CovEt_Cent_eta"), cent, valy, c2SubEt); + if (cent < KCentCovCut) + histos.fill(HIST("Prof_ipt2_CovEt_Eta"), valy, c2SubEt); + } + } + } + + for (int ietaA = 1; ietaA < KNEta; ++ietaA) { + for (int ietaC = 1; ietaC < KNEta; ++ietaC) { + float valx = KHalf * (etaLw[ietaA] + etaUp[ietaA]); + float valy = KHalf * (etaLw[ietaC] + etaUp[ietaC]); + { + const int ipt = 0; + float covpt = p1kBar[ietaA][ipt] * p1kBar[ietaC][ipt]; + if (std::isfinite(covpt)) + histos.fill(HIST("Prof_ipt0_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, covpt); + + float covet = p1kBarEt[ietaA][ipt] * p1kBarEt[ietaC][ipt]; + if (std::isfinite(covet)) + histos.fill(HIST("Prof_ipt0_C2SubEt2D_Mult_etaA_etaC"), cent, valx, valy, covet); + } + + { + const int ipt = 1; + float covpt = p1kBar[ietaA][ipt] * p1kBar[ietaC][ipt]; + if (std::isfinite(covpt)) + histos.fill(HIST("Prof_ipt1_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, covpt); + + float covet = p1kBarEt[ietaA][ipt] * p1kBarEt[ietaC][ipt]; + if (std::isfinite(covet)) + histos.fill(HIST("Prof_ipt1_C2SubEt2D_Mult_etaA_etaC"), cent, valx, valy, covet); + } + { + const int ipt = 2; + + float covpt = p1kBar[ietaA][ipt] * p1kBar[ietaC][ipt]; + if (std::isfinite(covpt)) + histos.fill(HIST("Prof_ipt2_C2Sub2D_Mult_etaA_etaC"), cent, valx, valy, covpt); + + float covet = p1kBarEt[ietaA][ipt] * p1kBarEt[ietaC][ipt]; + if (std::isfinite(covet)) + histos.fill(HIST("Prof_ipt2_C2SubEt2D_Mult_etaA_etaC"), cent, valx, valy, covet); + } + } + } + } + PROCESS_SWITCH(RadialFlowDecorr, processDataFluc, "process real data to calculate fluc pT and Et", cfgRunDataFluc); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/v0ptHadPiKaProt.cxx b/PWGCF/EbyEFluctuations/Tasks/v0ptHadPiKaProt.cxx new file mode 100644 index 00000000000..6bdeab9fe76 --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/v0ptHadPiKaProt.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 v0ptHadPiKaProt.cxx +/// \brief Task for analyzing v0(pT) of inclusive hadrons, pions, kaons, and, protons +/// \author Swati Saha + +#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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include +#include +#include +#include +#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; + +static constexpr float LongArrayFloat[3][20] = {{1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {2.1, 2.2, 2.3, -2.1, -2.2, -2.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {3.1, 3.2, 3.3, -3.1, -3.2, -3.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}}; + +struct V0ptHadPiKaProt { + + // ITS response + o2::aod::ITSResponse itsResponse; + // 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://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; + + enum Particles { + PIONS = 0, + KAONS, + PROTONS + }; + enum ParticleNsigma { + kPionUpCut = 0, + kKaonUpCut, + kProtonUpCut, + kPionLowCut, + kKaonLowCut, + kProtonLowCut + }; + enum DetectorType { + kTPC = 0, + kTOF, + kITS + }; + enum CentralityEstimator { + kFT0C = 0, + kFT0A, + kFT0M, + kFV0A + }; + + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutTpcChi2NCl{"cfgCutTpcChi2NCl", 2.5f, "Maximum TPCchi2NCl"}; + Configurable cfgCutItsChi2NCl{"cfgCutItsChi2NCl", 36.0f, "Maximum ITSchi2NCl"}; + Configurable cfgCutTrackDcaZ{"cfgCutTrackDcaZ", 2.0f, "Maximum DcaZ"}; + 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 cfgCutPtUpperTPC{"cfgCutPtUpperTPC", 0.6f, "Upper pT cut for PID using TPC only"}; + Configurable cfgnSigmaOtherParticles{"cfgnSigmaOtherParticles", 3.0f, "PID nSigma cut to remove other particles (default:3)"}; + 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"}; + ConfigurableAxis nchAxis{"nchAxis", {5000, 0.5, 5000.5}, ""}; + ConfigurableAxis centAxis{"centAxis", {90, 0., 90.}, "Centrality/Multiplicity percentile bining"}; + Configurable cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut"}; + Configurable cfgCutPtLowerProt{"cfgCutPtLowerProt", 0.2f, "Lower pT cut"}; + Configurable cfgCutPtUpper{"cfgCutPtUpper", 10.0f, "Higher pT cut for inclusive hadron analysis"}; + Configurable cfgCutPtUpperPID{"cfgCutPtUpperPID", 6.0f, "Higher pT cut for identified particle analysis"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "absolute Eta cut"}; + Configurable cfgCutEtaLeft{"cfgCutEtaLeft", 0.8f, "Left end of eta gap"}; + Configurable cfgCutEtaRight{"cfgCutEtaRight", 0.8f, "Right end of eta gap"}; + Configurable cfgNSubsample{"cfgNSubsample", 10, "Number of subsamples"}; + Configurable cfgCentralityChoice{"cfgCentralityChoice", 0, "Which centrality estimator? 0-->FT0C, 1-->FT0A, 2-->FT0M, 3-->FV0A"}; + Configurable cfgEvSelkNoSameBunchPileup{"cfgEvSelkNoSameBunchPileup", true, "Pileup removal"}; + Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Remove time interval with dead ITS zone"}; + Configurable cfgEvSelkNoITSROFrameBorder{"cfgEvSelkNoITSROFrameBorder", true, "ITSROFrame border event selection cut"}; + Configurable cfgEvSelkNoTimeFrameBorder{"cfgEvSelkNoTimeFrameBorder", true, "TimeFrame border event selection cut"}; + Configurable cfgEvSelUseGoodZvtxFT0vsPV{"cfgEvSelUseGoodZvtxFT0vsPV", true, "GoodZvertex and FT0 vs PV cut"}; + Configurable cfgUseItsPID{"cfgUseItsPID", false, "Use ITS PID for particle identification"}; + Configurable cfgPtCutTOF{"cfgPtCutTOF", 0.3f, "Minimum pt to use TOF N-sigma"}; + Configurable> nSigmas{"nSigmas", {LongArrayFloat[0], 3, 6, {"TPC", "TOF", "ITS"}, {"pos_pi", "pos_ka", "pos_pr", "neg_pi", "neg_ka", "neg_pr"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; + Configurable cfgUseRun3V2PID{"cfgUseRun3V2PID", true, "True if PID cuts to be used are similar to Run3 v2 PID analysis"}; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::vector>> subSample; + TRandom3* funRndm = new TRandom3(0); + + // Filter command*********** + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtLower) && (aod::track::pt < cfgCutPtUpper) && (requireGlobalTrackInFilter()) && (aod::track::tpcChi2NCl < cfgCutTpcChi2NCl) && (aod::track::itsChi2NCl < cfgCutItsChi2NCl) && (nabs(aod::track::dcaZ) < cfgCutTrackDcaZ); + + // Filtering collisions and tracks*********** + using AodCollisions = soa::Filtered>; + using AodTracks = soa::Filtered>; + + std::array tofNsigmaCut; + std::array itsNsigmaCut; + std::array tpcNsigmaCut; + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Get nSigma values of TPC, TOF, ITS for various particles from the matrix "nSigmas" + tpcNsigmaCut[kPionUpCut] = nSigmas->getData()[kTPC][kPionUpCut]; + tpcNsigmaCut[kKaonUpCut] = nSigmas->getData()[kTPC][kKaonUpCut]; + tpcNsigmaCut[kProtonUpCut] = nSigmas->getData()[kTPC][kProtonUpCut]; + tpcNsigmaCut[kPionLowCut] = nSigmas->getData()[kTPC][kPionLowCut]; + tpcNsigmaCut[kKaonLowCut] = nSigmas->getData()[kTPC][kKaonLowCut]; + tpcNsigmaCut[kProtonLowCut] = nSigmas->getData()[kTPC][kProtonLowCut]; + + tofNsigmaCut[kPionUpCut] = nSigmas->getData()[kTOF][kPionUpCut]; + tofNsigmaCut[kKaonUpCut] = nSigmas->getData()[kTOF][kKaonUpCut]; + tofNsigmaCut[kProtonUpCut] = nSigmas->getData()[kTOF][kProtonUpCut]; + tofNsigmaCut[kPionLowCut] = nSigmas->getData()[kTOF][kPionLowCut]; + tofNsigmaCut[kKaonLowCut] = nSigmas->getData()[kTOF][kKaonLowCut]; + tofNsigmaCut[kProtonLowCut] = nSigmas->getData()[kTOF][kProtonLowCut]; + + itsNsigmaCut[kPionUpCut] = nSigmas->getData()[kITS][kPionUpCut]; + itsNsigmaCut[kKaonUpCut] = nSigmas->getData()[kITS][kKaonUpCut]; + itsNsigmaCut[kProtonUpCut] = nSigmas->getData()[kITS][kProtonUpCut]; + itsNsigmaCut[kPionLowCut] = nSigmas->getData()[kITS][kPionLowCut]; + itsNsigmaCut[kKaonLowCut] = nSigmas->getData()[kITS][kKaonLowCut]; + itsNsigmaCut[kProtonLowCut] = nSigmas->getData()[kITS][kProtonLowCut]; + + // Define axes + std::vector ptBin = {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.5, 4.0, 5.0, 6.0, 8.0, 10.0}; + AxisSpec ptAxis = {ptBin, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec noAxis = {1, 0, 1, "no axis"}; + AxisSpec nSigmaAxis = {200, -5.0, 5.0, "n#sigma"}; + + // Add histograms to histogram manager (as in the output object of in AliPhysics) + + // QA hists + histos.add("hZvtx_after_sel", ";Z (cm)", kTH1F, {{240, -12, 12}}); + histos.add("hCentrality", ";centrality (%)", kTH1F, {{90, 0, 90}}); + histos.add("Hist2D_globalTracks_PVTracks", "", {HistType::kTH2D, {nchAxis, nchAxis}}); + histos.add("Hist2D_cent_nch", "", {HistType::kTH2D, {nchAxis, centAxis}}); + histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.2, 4.}}); + histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hPhi", ";#phi", kTH1F, {{100, 0., o2::constants::math::TwoPI}}); + histos.add("hEta", ";#eta", kTH1F, {{100, -2.01, 2.01}}); + histos.add("hDcaXY", ";#it{dca}_{XY}", kTH1F, {{1000, -5, 5}}); + histos.add("hDcaZ", ";#it{dca}_{Z}", kTH1F, {{1000, -5, 5}}); + histos.add("hMeanPt", "", kTProfile, {centAxis}); + + // 2D histograms of nSigma + // before cut + histos.add("h2DnsigmaPionTpcVsPtBeforeCut", "2D hist of nSigmaTPC vs. pT (pion)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaKaonTpcVsPtBeforeCut", "2D hist of nSigmaTPC vs. pT (kaon)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaProtonTpcVsPtBeforeCut", "2D hist of nSigmaTPC vs. pT (proton)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaPionTofVsPtBeforeCut", "2D hist of nSigmaTOF vs. pT (pion)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaKaonTofVsPtBeforeCut", "2D hist of nSigmaTOF vs. pT (kaon)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaProtonTofVsPtBeforeCut", "2D hist of nSigmaTOF vs. pT (proton)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaPionTpcVsTofBeforeCut", "2D hist of nSigmaTPC vs. nSigmaTOF (pion)", kTH2F, {nSigmaAxis, nSigmaAxis}); + histos.add("h2DnsigmaKaonTpcVsTofBeforeCut", "2D hist of nSigmaTPC vs. nSigmaTOF (kaon)", kTH2F, {nSigmaAxis, nSigmaAxis}); + histos.add("h2DnsigmaProtonTpcVsTofBeforeCut", "2D hist of nSigmaTPC vs. nSigmaTOF (proton)", kTH2F, {nSigmaAxis, nSigmaAxis}); + // after cut + histos.add("h2DnsigmaPionTpcVsPtAfterCut", "2D hist of nSigmaTPC vs. pT (pion)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaKaonTpcVsPtAfterCut", "2D hist of nSigmaTPC vs. pT (kaon)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaProtonTpcVsPtAfterCut", "2D hist of nSigmaTPC vs. pT (proton)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaPionTofVsPtAfterCut", "2D hist of nSigmaTOF vs. pT (pion)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaKaonTofVsPtAfterCut", "2D hist of nSigmaTOF vs. pT (kaon)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaProtonTofVsPtAfterCut", "2D hist of nSigmaTOF vs. pT (proton)", kTH2F, {ptAxis, nSigmaAxis}); + histos.add("h2DnsigmaPionTpcVsTofAfterCut", "2D hist of nSigmaTPC vs. nSigmaTOF (pion)", kTH2F, {nSigmaAxis, nSigmaAxis}); + histos.add("h2DnsigmaKaonTpcVsTofAfterCut", "2D hist of nSigmaTPC vs. nSigmaTOF (kaon)", kTH2F, {nSigmaAxis, nSigmaAxis}); + histos.add("h2DnsigmaProtonTpcVsTofAfterCut", "2D hist of nSigmaTPC vs. nSigmaTOF (proton)", kTH2F, {nSigmaAxis, nSigmaAxis}); + + // Analysis profiles + + histos.add("Prof_A_had", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_C_had", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_D_had", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_Bone_had", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_Btwo_had", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + + histos.add("Prof_A_pi", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_C_pi", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_D_pi", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_Bone_pi", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_Btwo_pi", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + + histos.add("Prof_A_ka", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_C_ka", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_D_ka", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_Bone_ka", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_Btwo_ka", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + + histos.add("Prof_A_prot", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_C_prot", "", {HistType::kTProfile2D, {centAxis, ptAxis}}); + histos.add("Prof_D_prot", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_Bone_prot", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + histos.add("Prof_Btwo_prot", "", {HistType::kTProfile2D, {centAxis, noAxis}}); + + // initial array + subSample.resize(cfgNSubsample); + for (int i = 0; i < cfgNSubsample; i++) { + subSample[i].resize(20); + } + for (int i = 0; i < cfgNSubsample; i++) { + subSample[i][0] = std::get>(histos.add(Form("subSample_%d/Prof_A_had", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSample[i][1] = std::get>(histos.add(Form("subSample_%d/Prof_C_had", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSample[i][2] = std::get>(histos.add(Form("subSample_%d/Prof_D_had", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSample[i][3] = std::get>(histos.add(Form("subSample_%d/Prof_Bone_had", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSample[i][4] = std::get>(histos.add(Form("subSample_%d/Prof_Btwo_had", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + + subSample[i][5] = std::get>(histos.add(Form("subSample_%d/Prof_A_pi", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSample[i][6] = std::get>(histos.add(Form("subSample_%d/Prof_C_pi", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSample[i][7] = std::get>(histos.add(Form("subSample_%d/Prof_D_pi", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSample[i][8] = std::get>(histos.add(Form("subSample_%d/Prof_Bone_pi", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSample[i][9] = std::get>(histos.add(Form("subSample_%d/Prof_Btwo_pi", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + + subSample[i][10] = std::get>(histos.add(Form("subSample_%d/Prof_A_ka", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSample[i][11] = std::get>(histos.add(Form("subSample_%d/Prof_C_ka", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSample[i][12] = std::get>(histos.add(Form("subSample_%d/Prof_D_ka", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSample[i][13] = std::get>(histos.add(Form("subSample_%d/Prof_Bone_ka", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSample[i][14] = std::get>(histos.add(Form("subSample_%d/Prof_Btwo_ka", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + + subSample[i][15] = std::get>(histos.add(Form("subSample_%d/Prof_A_prot", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSample[i][16] = std::get>(histos.add(Form("subSample_%d/Prof_C_prot", i), "", {HistType::kTProfile2D, {centAxis, ptAxis}})); + subSample[i][17] = std::get>(histos.add(Form("subSample_%d/Prof_D_prot", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSample[i][18] = std::get>(histos.add(Form("subSample_%d/Prof_Bone_prot", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + subSample[i][19] = std::get>(histos.add(Form("subSample_%d/Prof_Btwo_prot", i), "", {HistType::kTProfile2D, {centAxis, noAxis}})); + } + } // end init + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + bool selectionProton(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + int flag = 0; //! pid check main flag + + if (candidate.pt() > cfgCutPtLower && 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() < cfgCutPtUpperPID) { + 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 < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaPi < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaKa < cfgnSigmaOtherParticles) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaPr > combNSigmaPi) && !(combNSigmaPr > combNSigmaKa)) { + if (combNSigmaPr < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + template + bool selectionPion(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + int flag = 0; //! pid check main flag + + if (candidate.pt() > cfgCutPtLower && candidate.pt() <= cfgCutPtUpperTPC) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < cfgnSigmaCutTPC) { + flag = 1; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaPi()) < cfgnSigmaCutTOF) { + flag = 1; + } + } + if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < cfgCutPtUpperPID) { + 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 < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaPi < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaKa < cfgnSigmaOtherParticles) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaPi > combNSigmaPr) && !(combNSigmaPi > combNSigmaKa)) { + if (combNSigmaPi < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + template + bool selectionKaon(const T& candidate) + { + if (!candidate.hasTPC()) + return false; + int flag = 0; //! pid check main flag + + if (candidate.pt() > cfgCutPtLower && candidate.pt() <= cfgCutPtUpperTPC) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < cfgnSigmaCutTPC) { + flag = 1; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < cfgnSigmaCutTPC && std::abs(candidate.tofNSigmaKa()) < cfgnSigmaCutTOF) { + flag = 1; + } + } + if (candidate.hasTOF() && candidate.pt() > cfgCutPtUpperTPC && candidate.pt() < cfgCutPtUpperPID) { + 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 < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaPi < cfgnSigmaOtherParticles) + flag2 += 1; + if (combNSigmaKa < cfgnSigmaOtherParticles) + flag2 += 1; + if (!(flag2 > 1) && !(combNSigmaKa > combNSigmaPi) && !(combNSigmaKa > combNSigmaPr)) { + if (combNSigmaKa < cfgnSigmaCutCombTPCTOF) { + flag = 1; + } + } + } + if (flag == 1) + return true; + else + return false; + } + + template + int getNsigmaPID(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaTOF = {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + std::array nSigmaITS = {itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track)}; + int pid = 0; // 0 = not identified, 1 = pion, 2 = kaon, 3 = proton + + std::array nSigmaToUse = cfgUseItsPID ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS + std::array detectorNsigmaCut = cfgUseItsPID ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS + + bool isPion, isKaon, isProton; + bool isDetectedPion = nSigmaToUse[PIONS] < detectorNsigmaCut[kPionUpCut] && nSigmaToUse[PIONS] > detectorNsigmaCut[kPionLowCut]; + bool isDetectedKaon = nSigmaToUse[KAONS] < detectorNsigmaCut[kKaonUpCut] && nSigmaToUse[KAONS] > detectorNsigmaCut[kKaonLowCut]; + bool isDetectedProton = nSigmaToUse[PROTONS] < detectorNsigmaCut[kProtonUpCut] && nSigmaToUse[PROTONS] > detectorNsigmaCut[kProtonLowCut]; + + bool isTofPion = nSigmaTOF[PIONS] < tofNsigmaCut[kPionUpCut] && nSigmaTOF[PIONS] > tofNsigmaCut[kPionLowCut]; + bool isTofKaon = nSigmaTOF[KAONS] < tofNsigmaCut[kKaonUpCut] && nSigmaTOF[KAONS] > tofNsigmaCut[kKaonLowCut]; + bool isTofProton = nSigmaTOF[PROTONS] < tofNsigmaCut[kProtonUpCut] && nSigmaTOF[PROTONS] > tofNsigmaCut[kProtonLowCut]; + + if (track.pt() > cfgPtCutTOF && !track.hasTOF()) { + return 0; + } else if (track.pt() > cfgPtCutTOF && track.hasTOF()) { + isPion = isTofPion && isDetectedPion; + isKaon = isTofKaon && isDetectedKaon; + isProton = isTofProton && isDetectedProton; + } else { + isPion = isDetectedPion; + isKaon = isDetectedKaon; + isProton = isDetectedProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + return 0; // more than one particle satisfy the criteria + } + + if (isPion) { + pid = PIONS + 1; + } else if (isKaon) { + pid = KAONS + 1; + } else if (isProton) { + pid = PROTONS + 1; + } else { + return 0; // no particle satisfies the criteria + } + + return pid; // 0 = not identified, 1 = pion, 2 = kaon, 3 = proton + } + + // process Data + void process(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))) { + return; + } + if (cfgEvSelkNoITSROFrameBorder && !(coll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + return; + } + if (cfgEvSelkNoTimeFrameBorder && !(coll.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { + return; + } + if (cfgEvSelUseGoodZvtxFT0vsPV && !(coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + + // Centrality + double cent = 0.0; + if (cfgCentralityChoice == kFT0C) + cent = coll.centFT0C(); + else if (cfgCentralityChoice == kFT0A) + cent = coll.centFT0A(); + else if (cfgCentralityChoice == kFT0M) + cent = coll.centFT0M(); + else if (cfgCentralityChoice == kFV0A) + cent = coll.centFV0A(); + + histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + histos.fill(HIST("hCentrality"), cent); + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), inputTracks.size()); + histos.fill(HIST("Hist2D_cent_nch"), inputTracks.size(), cent); + + // Analysis variables + int nbinsHad = 20; + int nbinsPid = 18; + double binsarray[21] = {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.5, 4.0, 5.0, 6.0, 8.0, 10.0}; + TH1D* fPtProfileHad = new TH1D("fPtProfileHad", "fPtProfileHad", 20, binsarray); + TH1D* fPtProfilePi = new TH1D("fPtProfilePi", "fPtProfilePi", 20, binsarray); + TH1D* fPtProfileKa = new TH1D("fPtProfileKa", "fPtProfileKa", 20, binsarray); + TH1D* fPtProfileProt = new TH1D("fPtProfileProt", "fPtProfileProt", 20, binsarray); + double pTsumEtaLeftHad = 0.0; + double nSumEtaLeftHad = 0.0; + double pTsumEtaRightHad = 0.0; + double nSumEtaRightHad = 0.0; + double nSumEtaLeftPi = 0.0; + double nSumEtaLeftKa = 0.0; + double nSumEtaLeftProt = 0.0; + + for (const auto& track : inputTracks) { // Loop over tracks + + if (!track.has_collision()) { + continue; + } + + if (!track.isPVContributor()) { + continue; + } + + if (!(track.itsNCls() > cfgITScluster) || !(track.tpcNClsFound() >= cfgTPCcluster) || !(track.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) { + continue; + } + + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hPhi"), track.phi()); + histos.fill(HIST("hDcaXY"), track.dcaXY()); + histos.fill(HIST("hDcaZ"), track.dcaZ()); + + double trkPt = track.pt(); + double trkEta = track.eta(); + + // inclusive charged particles + if (track.sign() != 0) { + if (trkEta < cfgCutEtaLeft) { + fPtProfileHad->Fill(trkPt); + pTsumEtaLeftHad += trkPt; + nSumEtaLeftHad += 1.0; + } + if (trkEta > cfgCutEtaRight) { + pTsumEtaRightHad += trkPt; + nSumEtaRightHad += 1.0; + } + } + + // PID QAs before selection + double nSigmaTpcPi = track.tpcNSigmaPi(); + double nSigmaTpcKa = track.tpcNSigmaKa(); + double nSigmaTpcProt = track.tpcNSigmaPr(); + double nSigmaTofPi = track.tofNSigmaPi(); + double nSigmaTofKa = track.tofNSigmaKa(); + double nSigmaTofProt = track.tofNSigmaPr(); + histos.fill(HIST("h2DnsigmaPionTpcVsPtBeforeCut"), trkPt, nSigmaTpcPi); + histos.fill(HIST("h2DnsigmaKaonTpcVsPtBeforeCut"), trkPt, nSigmaTpcKa); + histos.fill(HIST("h2DnsigmaProtonTpcVsPtBeforeCut"), trkPt, nSigmaTpcProt); + histos.fill(HIST("h2DnsigmaPionTofVsPtBeforeCut"), trkPt, nSigmaTofPi); + histos.fill(HIST("h2DnsigmaKaonTofVsPtBeforeCut"), trkPt, nSigmaTofKa); + histos.fill(HIST("h2DnsigmaProtonTofVsPtBeforeCut"), trkPt, nSigmaTofProt); + histos.fill(HIST("h2DnsigmaPionTpcVsTofBeforeCut"), nSigmaTpcPi, nSigmaTofPi); + histos.fill(HIST("h2DnsigmaKaonTpcVsTofBeforeCut"), nSigmaTpcKa, nSigmaTofKa); + histos.fill(HIST("h2DnsigmaProtonTpcVsTofBeforeCut"), nSigmaTpcProt, nSigmaTofProt); + + // identified particles selection + bool isPion = false; + bool isKaon = false; + bool isProton = false; + + if (cfgUseRun3V2PID) { + int pidVal = getNsigmaPID(track); + if (pidVal == PIONS + 1) + isPion = true; + if (pidVal == KAONS + 1) + isKaon = true; + if (pidVal == PROTONS + 1) + isProton = true; + } else { + isPion = selectionPion(track); + isKaon = selectionKaon(track); + isProton = selectionProton(track); + } + + // PID QAs after selection + if (isPion) { + histos.fill(HIST("h2DnsigmaPionTpcVsPtAfterCut"), trkPt, nSigmaTpcPi); + histos.fill(HIST("h2DnsigmaPionTofVsPtAfterCut"), trkPt, nSigmaTofPi); + histos.fill(HIST("h2DnsigmaPionTpcVsTofAfterCut"), nSigmaTpcPi, nSigmaTofPi); + } + if (isKaon) { + histos.fill(HIST("h2DnsigmaKaonTpcVsPtAfterCut"), trkPt, nSigmaTpcKa); + histos.fill(HIST("h2DnsigmaKaonTofVsPtAfterCut"), trkPt, nSigmaTofKa); + histos.fill(HIST("h2DnsigmaKaonTpcVsTofAfterCut"), nSigmaTpcKa, nSigmaTofKa); + } + if (isProton) { + histos.fill(HIST("h2DnsigmaProtonTpcVsPtAfterCut"), trkPt, nSigmaTpcProt); + histos.fill(HIST("h2DnsigmaProtonTofVsPtAfterCut"), trkPt, nSigmaTofProt); + histos.fill(HIST("h2DnsigmaProtonTpcVsTofAfterCut"), nSigmaTpcProt, nSigmaTofProt); + } + + if (track.sign() != 0) { + if (trkPt < cfgCutPtUpperPID) { + if (trkEta < cfgCutEtaLeft) { + if (isPion) { + fPtProfilePi->Fill(trkPt); + nSumEtaLeftPi += 1.0; + } + if (isKaon) { + fPtProfileKa->Fill(trkPt); + nSumEtaLeftKa += 1.0; + } + if (isProton && trkPt > cfgCutPtLowerProt) { + fPtProfileProt->Fill(trkPt); + nSumEtaLeftProt += 1.0; + } + } + } + } + + } // End track loop + + // selecting subsample and filling profiles + float lRandom = funRndm->Rndm(); + int sampleIndex = static_cast(cfgNSubsample * lRandom); + + if (nSumEtaRightHad > 0 && nSumEtaLeftHad > 0) { + for (int i = 0; i < nbinsHad; i++) { + histos.get(HIST("Prof_A_had"))->Fill(cent, fPtProfileHad->GetBinCenter(i + 1), (fPtProfileHad->GetBinContent(i + 1) / nSumEtaLeftHad)); + histos.get(HIST("Prof_C_had"))->Fill(cent, fPtProfileHad->GetBinCenter(i + 1), ((fPtProfileHad->GetBinContent(i + 1) / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + histos.get(HIST("Prof_Bone_had"))->Fill(cent, 0.5, (pTsumEtaLeftHad / nSumEtaLeftHad)); + histos.get(HIST("Prof_Btwo_had"))->Fill(cent, 0.5, (pTsumEtaRightHad / nSumEtaRightHad)); + histos.get(HIST("Prof_D_had"))->Fill(cent, 0.5, ((pTsumEtaLeftHad / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + + subSample[sampleIndex][0]->Fill(cent, fPtProfileHad->GetBinCenter(i + 1), (fPtProfileHad->GetBinContent(i + 1) / nSumEtaLeftHad)); + subSample[sampleIndex][1]->Fill(cent, fPtProfileHad->GetBinCenter(i + 1), ((fPtProfileHad->GetBinContent(i + 1) / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + subSample[sampleIndex][2]->Fill(cent, 0.5, ((pTsumEtaLeftHad / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + subSample[sampleIndex][3]->Fill(cent, 0.5, (pTsumEtaLeftHad / nSumEtaLeftHad)); + subSample[sampleIndex][4]->Fill(cent, 0.5, (pTsumEtaRightHad / nSumEtaRightHad)); + } + } + + if (nSumEtaRightHad > 0 && nSumEtaLeftHad > 0 && nSumEtaLeftPi > 0) { + for (int i = 0; i < nbinsPid; i++) { + histos.get(HIST("Prof_A_pi"))->Fill(cent, fPtProfilePi->GetBinCenter(i + 1), (fPtProfilePi->GetBinContent(i + 1) / nSumEtaLeftPi)); + histos.get(HIST("Prof_C_pi"))->Fill(cent, fPtProfilePi->GetBinCenter(i + 1), ((fPtProfilePi->GetBinContent(i + 1) / nSumEtaLeftPi) * (pTsumEtaRightHad / nSumEtaRightHad))); + histos.get(HIST("Prof_Bone_pi"))->Fill(cent, 0.5, (pTsumEtaLeftHad / nSumEtaLeftHad)); + histos.get(HIST("Prof_Btwo_pi"))->Fill(cent, 0.5, (pTsumEtaRightHad / nSumEtaRightHad)); + histos.get(HIST("Prof_D_pi"))->Fill(cent, 0.5, ((pTsumEtaLeftHad / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + + subSample[sampleIndex][5]->Fill(cent, fPtProfilePi->GetBinCenter(i + 1), (fPtProfilePi->GetBinContent(i + 1) / nSumEtaLeftPi)); + subSample[sampleIndex][6]->Fill(cent, fPtProfilePi->GetBinCenter(i + 1), ((fPtProfilePi->GetBinContent(i + 1) / nSumEtaLeftPi) * (pTsumEtaRightHad / nSumEtaRightHad))); + subSample[sampleIndex][7]->Fill(cent, 0.5, ((pTsumEtaLeftHad / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + subSample[sampleIndex][8]->Fill(cent, 0.5, (pTsumEtaLeftHad / nSumEtaLeftHad)); + subSample[sampleIndex][9]->Fill(cent, 0.5, (pTsumEtaRightHad / nSumEtaRightHad)); + } + } + + if (nSumEtaRightHad > 0 && nSumEtaLeftHad > 0 && nSumEtaLeftKa > 0) { + for (int i = 0; i < nbinsPid; i++) { + histos.get(HIST("Prof_A_ka"))->Fill(cent, fPtProfileKa->GetBinCenter(i + 1), (fPtProfileKa->GetBinContent(i + 1) / nSumEtaLeftKa)); + histos.get(HIST("Prof_C_ka"))->Fill(cent, fPtProfileKa->GetBinCenter(i + 1), ((fPtProfileKa->GetBinContent(i + 1) / nSumEtaLeftKa) * (pTsumEtaRightHad / nSumEtaRightHad))); + histos.get(HIST("Prof_Bone_ka"))->Fill(cent, 0.5, (pTsumEtaLeftHad / nSumEtaLeftHad)); + histos.get(HIST("Prof_Btwo_ka"))->Fill(cent, 0.5, (pTsumEtaRightHad / nSumEtaRightHad)); + histos.get(HIST("Prof_D_ka"))->Fill(cent, 0.5, ((pTsumEtaLeftHad / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + + subSample[sampleIndex][10]->Fill(cent, fPtProfileKa->GetBinCenter(i + 1), (fPtProfileKa->GetBinContent(i + 1) / nSumEtaLeftKa)); + subSample[sampleIndex][11]->Fill(cent, fPtProfileKa->GetBinCenter(i + 1), ((fPtProfileKa->GetBinContent(i + 1) / nSumEtaLeftKa) * (pTsumEtaRightHad / nSumEtaRightHad))); + subSample[sampleIndex][12]->Fill(cent, 0.5, ((pTsumEtaLeftHad / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + subSample[sampleIndex][13]->Fill(cent, 0.5, (pTsumEtaLeftHad / nSumEtaLeftHad)); + subSample[sampleIndex][14]->Fill(cent, 0.5, (pTsumEtaRightHad / nSumEtaRightHad)); + } + } + if (nSumEtaRightHad > 0 && nSumEtaLeftHad > 0 && nSumEtaLeftProt > 0) { + for (int i = 1; i < nbinsPid; i++) { + histos.get(HIST("Prof_A_prot"))->Fill(cent, fPtProfileProt->GetBinCenter(i + 1), (fPtProfileProt->GetBinContent(i + 1) / nSumEtaLeftProt)); + histos.get(HIST("Prof_C_prot"))->Fill(cent, fPtProfileProt->GetBinCenter(i + 1), ((fPtProfileProt->GetBinContent(i + 1) / nSumEtaLeftProt) * (pTsumEtaRightHad / nSumEtaRightHad))); + histos.get(HIST("Prof_Bone_prot"))->Fill(cent, 0.5, (pTsumEtaLeftHad / nSumEtaLeftHad)); + histos.get(HIST("Prof_Btwo_prot"))->Fill(cent, 0.5, (pTsumEtaRightHad / nSumEtaRightHad)); + histos.get(HIST("Prof_D_prot"))->Fill(cent, 0.5, ((pTsumEtaLeftHad / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + + subSample[sampleIndex][15]->Fill(cent, fPtProfileProt->GetBinCenter(i + 1), (fPtProfileProt->GetBinContent(i + 1) / nSumEtaLeftProt)); + subSample[sampleIndex][16]->Fill(cent, fPtProfileProt->GetBinCenter(i + 1), ((fPtProfileProt->GetBinContent(i + 1) / nSumEtaLeftProt) * (pTsumEtaRightHad / nSumEtaRightHad))); + subSample[sampleIndex][17]->Fill(cent, 0.5, ((pTsumEtaLeftHad / nSumEtaLeftHad) * (pTsumEtaRightHad / nSumEtaRightHad))); + subSample[sampleIndex][18]->Fill(cent, 0.5, (pTsumEtaLeftHad / nSumEtaLeftHad)); + subSample[sampleIndex][19]->Fill(cent, 0.5, (pTsumEtaRightHad / nSumEtaRightHad)); + } + } + + fPtProfileHad->Delete(); + fPtProfilePi->Delete(); + fPtProfileKa->Delete(); + fPtProfileProt->Delete(); + + } // End process loop +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Femto/CMakeLists.txt b/PWGCF/Femto/CMakeLists.txt new file mode 100644 index 00000000000..d43e99e58fb --- /dev/null +++ b/PWGCF/Femto/CMakeLists.txt @@ -0,0 +1,16 @@ +# 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. + +add_subdirectory(Core) +add_subdirectory(TableProducer) +add_subdirectory(Tasks) + +add_subdirectory(FemtoNuclei) diff --git a/PWGCF/Femto/Core/CMakeLists.txt b/PWGCF/Femto/Core/CMakeLists.txt new file mode 100644 index 00000000000..4c182222bf2 --- /dev/null +++ b/PWGCF/Femto/Core/CMakeLists.txt @@ -0,0 +1,10 @@ +# 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. diff --git a/PWGCF/Femto/Core/baseSelection.h b/PWGCF/Femto/Core/baseSelection.h new file mode 100644 index 00000000000..ceb2184a96a --- /dev/null +++ b/PWGCF/Femto/Core/baseSelection.h @@ -0,0 +1,433 @@ +// 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 baseSelection.h +/// \brief Defines the BaseSelection class for managing and evaluating multiple selections over multiple observables. +/// \author Anton Riedel, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_BASESELECTION_H_ +#define PWGCF_FEMTO_CORE_BASESELECTION_H_ + +#include "PWGCF/Femto/Core/selectionContainer.h" + +#include "Framework/HistogramRegistry.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ + +/// \class BaseSelection +/// \brief Template class for managing selection criteria across multiple observables. +/// +/// This class manages an array of SelectionContainer objects, each corresponding to a specific observable. +/// It evaluates which selections are fulfilled, assembles a final bitmask, and tracks required vs. optional cuts. +/// +/// \tparam T Type of observable values (mostly floats). +/// \tparam BitmaskType Type used for internal bitmask operations (e.g., uint32_t, uint64_t). +/// \tparam NumObservables Total number of observables handled. +template +class BaseSelection +{ + public: + /// \brief Default constructor. + BaseSelection() = default; + + /// \brief Destructor + virtual ~BaseSelection() = default; + + /// \brief Add a static-value based selection for a specific observable. + /// \param selectionValues Vector of threshold values. + /// \param observableIndex Index of the observable. + /// \param limitType Type of limit (from limits::LimitType). + /// \param skipMostPermissiveBit Whether to skip the loosest threshold in the bitmask. + /// \param isMinimalCut Whether this cut is mandatory or optional. + void addSelection(int observableIndex, + std::string const& selectionName, + std::vector const& selectionValues, + limits::LimitType limitType, + bool skipMostPermissiveBit, + bool isMinimalCut, + bool isOptionCut) + { + // check index + if (static_cast(observableIndex) >= NumObservables) { + LOG(fatal) << "Observable is not valid. Observable (index) has to be smaller than " << NumObservables; + } + // init selection container for selection at given index + mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, selectionValues, limitType, skipMostPermissiveBit, isMinimalCut, isOptionCut); + + // check if any selections are configured + if (mSelectionContainers.at(observableIndex).isEmpty()) { + return; + } + + // keep track of selections and bits + mNSelectionBits += mSelectionContainers.at(observableIndex).getShift(); + mNSelection += mSelectionContainers.at(observableIndex).getNSelections(); + + if (mNSelectionBits > sizeof(BitmaskType) * CHAR_BIT) { + LOG(fatal) << "Too many selections. At most " << sizeof(BitmaskType) * CHAR_BIT << " number of bits are supported"; + } + // check if any selection is minimal + if (mSelectionContainers.at(observableIndex).isMinimalCut()) { + mHasMinimalSelection = true; + } + // check if selection is optional + if (mSelectionContainers.at(observableIndex).isOptionalCut()) { + mHasOptionalSelection = true; + } + } + + /// \brief Add a function-based selection for a specific observable. + /// \param baseName Base name for TF1 functions. + /// \param lowerLimit Lower bound for the TF1 domain. + /// \param upperLimit Upper bound for the TF1 domain. + /// \param selectionValues Function definitions as strings. + /// \param observableIndex Index of the observable. + /// \param limitType Type of limit. + /// \param skipMostPermissiveBit Whether to skip the loosest threshold in the bitmask. + /// \param isMinimalCut Whether this cut is mandatory or optional. + void addSelection(int observableIndex, + std::string const& selectionName, + T lowerLimit, + T upperLimit, + std::vector const& functions, + limits::LimitType limitType, + bool skipMostPermissiveBit, + bool isMinimalCut, + bool isOptionalCut) + { + if (static_cast(observableIndex) >= NumObservables) { + LOG(fatal) << "Observable is not valid. Observable (index) has to be smaller than " << NumObservables; + } + mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, lowerLimit, upperLimit, functions, limitType, skipMostPermissiveBit, isMinimalCut, isOptionalCut); + + // check if any selections are configured + if (mSelectionContainers.at(observableIndex).isEmpty()) { + return; + } + + // advance mNSelections so we can use it as offset for next selection + mNSelectionBits += mSelectionContainers.at(observableIndex).getShift(); + mNSelection += mSelectionContainers.at(observableIndex).getNSelections(); + + if (mNSelectionBits > sizeof(BitmaskType) * CHAR_BIT) { + LOG(fatal) << "Too many selections. At most " << sizeof(BitmaskType) * CHAR_BIT << " are supported"; + } + // keep track of selection selections + // check if any cut is minimal + if (mSelectionContainers.at(observableIndex).isMinimalCut()) { + mHasMinimalSelection = true; + } + // check if any selection is optional + if (mSelectionContainers.at(observableIndex).isOptionalCut()) { + mHasOptionalSelection = true; + } + } + + /// \brief Add a boolean based selection for a specific observable. + /// \param mode Whether the selection is not applied, minimal or optional cut + /// \param observableIndex Index of the observable. + void addSelection(int observableIndex, + std::string const& selectionName, + int mode) + { + switch (mode) { + case -1: // cut is optional and we store bit for the cut + mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, std::vector{1}, limits::LimitType::kEqual, false, false, true); + mHasOptionalSelection = true; + mNSelectionBits += 1; + mNSelection += 1; + break; + case 0: // cut is not applied, initalize with empty vector, so we bail out later + mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, std::vector{}, limits::LimitType::kEqual, false, false, false); + break; + case 1: // cut is added as mininal selection (since it is only one value, no extra bit is stored) + mSelectionContainers.at(observableIndex) = SelectionContainer(selectionName, std::vector{1}, limits::LimitType::kEqual, true, true, false); + mHasMinimalSelection = true; + mNSelection += 1; + break; + default: + LOG(fatal) << "Invalid switch for boolean selection"; + } + if (mNSelectionBits > sizeof(BitmaskType) * CHAR_BIT) { + LOG(fatal) << "Too many selections. At most " << sizeof(BitmaskType) * CHAR_BIT << " are supported"; + } + } + + /// \brief Update the limits of a function-based selection for a specific observable. + /// \param observable Index of the observable. + /// \param value Value at which to evaluate the selection functions. + void updateLimits(int observable, T value) + { + mSelectionContainers.at(observable).updateLimits(value); + } + + /// \brief Reset the internal bitmask and evaluation flags before evaluating a new event. + void reset() + { + mFinalBitmask.reset(); + for (std::size_t i = 0; i < mSelectionContainers.size(); i++) { + mSelectionContainers.at(i).reset(); + } + if (mHasMinimalSelection) { + mPassesMinimalSelections = true; + } + if (mHasOptionalSelection) { + mPassesOptionalSelections = false; + } + } + + void reset(int observableIndex) { mSelectionContainers.at(observableIndex).reset(); } + + /// \brief Evaluate a single observable against its configured selections. + /// \param observableIndex Index of the observable. + /// \param value Value of the observable. + void evaluateObservable(int observableIndex, T value) + { + // if there are no selections configured, bail out + if (mSelectionContainers.at(observableIndex).isEmpty()) { + return; + } + // if any previous observable did not pass minimal selections, there is no point in setting bitmask for other observables + // minimal selection for each observable is computed after adding it + if (!mPassesMinimalSelections) { + return; + } + // set bitmask for given observable + mSelectionContainers.at(observableIndex).evaluate(value); + // check if minimal selction for this observable holds + // if one minimal selection is not fullfilled, the condition failes + if (mHasMinimalSelection) { + if (!mSelectionContainers.at(observableIndex).passesAsMinimalCut()) { + mPassesMinimalSelections = false; + } + } + // check if any optional selection holds + // if one optional selection is fullfilled, the condition succeeds + if (mHasOptionalSelection) { + if (mSelectionContainers.at(observableIndex).passesAsOptionalCut()) { + mPassesOptionalSelections = true; + } + } + } + + /// \brief Evaluate a single observable against its configured selections. + /// \param observableIndex Index of the observable. + /// \param values vector of values of the observable. + void evaluateObservable(int observableIndex, std::vector values) + { + // if there are no selections configured, bail out + if (mSelectionContainers.at(observableIndex).isEmpty()) { + return; + } + // if any previous observable did not pass minimal selections, there is no point in setting bitmask for other observables + // minimal selection for each observable is computed after adding it + if (!mPassesMinimalSelections) { + return; + } + // set bitmask for given observable + mSelectionContainers.at(observableIndex).evaluate(values); + // check if minimal selction for this observable holds + if (mHasMinimalSelection) { + if (mSelectionContainers.at(observableIndex).passesAsMinimalCut() == false) { + mPassesMinimalSelections = false; + } + } + // check if any optional selection holds + if (mHasOptionalSelection) { + if (mSelectionContainers.at(observableIndex).passesAsOptionalCut() == true) { + mPassesOptionalSelections = true; + } + } + } + + /// \brief Add comments to specific observabel + void addComments(int observableIndex, std::vector const& comments) { mSelectionContainers.at(observableIndex).addComments(comments); } + + /// \brief Check if all required (minimal) and optional cuts are passed. + /// \return True if all required and at least one optional cut (if present) is passed. + bool passesAllRequiredSelections() const + { + if (mHasMinimalSelection && !mHasOptionalSelection) { + return mPassesMinimalSelections; + } + if (!mHasMinimalSelection && mHasOptionalSelection) { + return mPassesOptionalSelections; + } + if (mHasMinimalSelection && mHasOptionalSelection) { + return mPassesMinimalSelections && mPassesOptionalSelections; + } + return true; + } + + /// \brief Check if the optional selection for a specific observable is passed. + /// \param observableIndex Index of the observable. + /// \return True if at least one optional selection is fulfilled. + bool passesOptionalSelection(int observableIndex) const + { + return mSelectionContainers.at(observableIndex).passesAsOptionalCut(); + } + + /// \brief Assemble the global selection bitmask from individual observable selections. + template + void assembleBitmask() + { + mHistRegistry->fill(HIST(HistName), mNSelection); + // if the required selections are not passed, we can break early + if (!this->passesAllRequiredSelections()) { + mFinalBitmask.reset(); + return; + } + mHistRegistry->fill(HIST(HistName), mNSelection + 1); + + int binCenter = 0; + // to assemble bitmask, convert all bitmask into integers + // shift the current one and add the new bits + for (auto const& selectionContainer : mSelectionContainers) { + // if there are no selections for a certain observable, skip + if (selectionContainer.isEmpty()) { + continue; + } + // Shift the result to its offset and add the new values + mFinalBitmask |= (selectionContainer.getBitmask() << selectionContainer.getOffset()); + + for (int j = 0; j < selectionContainer.getNSelections(); ++j) { + if (j == 0 && selectionContainer.isMinimalCut()) { + // minimal cuts are always filled + mHistRegistry->fill(HIST(HistName), binCenter); + } else { + // use container's internal offset for checking the bit + if (mFinalBitmask.test(selectionContainer.getBitPosition(j))) { + mHistRegistry->fill(HIST(HistName), binCenter); + } + } + binCenter++; + } + } + } + + /// \brief Retrieve the assembled bitmask as an integer value. + /// \return The combined selection bitmask. + BitmaskType getBitmask() const { return static_cast(mFinalBitmask.to_ullong()); } + + /// \brief Retrieve the assembled bitmask as an integer value. + /// \return The combined selection bitmask. + BitmaskType getBitmask(int observableIndex) const { return static_cast(mSelectionContainers.at(observableIndex).getBitmask().to_ullong()); } + + /// \brief Set the assembled bitmask for on observable + /// \return The combined selection bitmask. + template + void setBitmask(int observableIndex, R bitmask) + { + mSelectionContainers.at(observableIndex).setBitmask(bitmask); + } + + T getLoosestSelection(int observableIndex) const { return mSelectionContainers.at(observableIndex).getLoosestSelection(); } + + void printSelections(const std::string& objectName) const + { + LOG(info) << "Printing Configuration of " << objectName; + for (size_t idx = 0; idx < mSelectionContainers.size(); ++idx) { + const auto& container = mSelectionContainers[idx]; + if (container.isEmpty()) { + continue; + } + + LOG(info) << " Observable: " << container.getSelectionName() << " (index " << idx << ")"; + LOG(info) << " Limit type : " << container.getLimitTypeAsString(); + LOG(info) << " Skip most permissive Bit : " << (container.skipMostPermissiveBit() ? "yes" : "no"); + LOG(info) << " Minimal cut : " << (container.isMinimalCut() ? "yes" : "no"); + LOG(info) << " Optional cut : " << (container.isOptionalCut() ? "yes" : "no"); + LOG(info) << " Bitmask offset : " << container.getOffset(); + LOG(info) << " Bitmask shift : " << container.getShift(); + LOG(info) << " Selections:"; + + const bool useFunctions = container.isUsingFunctions(); + const auto& values = container.getSelectionValues(); + const auto& functions = container.getSelectionFunction(); + const auto& comments = container.getComments(); + + for (int j = 0; j < container.getNSelections(); ++j) { + + std::stringstream line; + std::string sel = useFunctions ? std::string(functions[j].GetExpFormula().Data()) : std::to_string(values[j]); + + line << " " << std::left << std::setw(25) << sel; + + if (j == 0 && container.isMinimalCut()) { + line << "-> minimal cut, no bit saved"; + } else { + int bit = container.getOffset() + (j - (container.isMinimalCut() ? 1 : 0)); + line << "-> Bit: 0x" << std::hex << std::uppercase << (1ULL << bit) << std::dec; + } + + if (!comments.empty()) { + line << " (" << comments.at(j) << ")"; + } + LOG(info) << line.str(); + } + LOG(info) << ""; + } + LOG(info) << "Number of occupied bits: " << mNSelectionBits << " / " << sizeof(BitmaskType) * CHAR_BIT; + LOG(info) << "Printing done"; + } + + template + void setupContainers(o2::framework::HistogramRegistry* registry) + { + mHistRegistry = registry; + // Create histogram with correct number of bins + int nBins = mNSelection + 2; + mHistRegistry->add(HistName, "; Selection Bits; Entries", o2::framework::kTH1F, {{nBins, -0.5, nBins - 0.5}}); + + size_t binIndex = 0; + int offset = 0; + for (size_t idx = 0; idx < mSelectionContainers.size(); ++idx) { + auto& container = mSelectionContainers[idx]; + if (container.isEmpty()) { + continue; + } + container.setOffset(offset); + offset += container.getShift(); + for (int j = 0; j < container.getNSelections(); j++) { + std::string label = container.getBinLabel(j); + mHistRegistry->get(HIST(HistName))->GetXaxis()->SetBinLabel(binIndex + 1, label.c_str()); + binIndex++; + } + } + mHistRegistry->get(HIST(HistName))->GetXaxis()->SetBinLabel(mNSelection + 1, "All analyzed"); + mHistRegistry->get(HIST(HistName))->GetXaxis()->SetBinLabel(mNSelection + 2, "All passed"); + } + + protected: + o2::framework::HistogramRegistry* mHistRegistry = nullptr; + std::array, NumObservables> mSelectionContainers = {}; ///< Array containing all selections + std::bitset mFinalBitmask = {}; ///< final bitmaks + std::size_t mNSelectionBits = 0; ///< Number of selections (all - minimal selections) + int mNSelection = 0; ///< Number of selections all selections + bool mHasMinimalSelection = false; ///< Set to true if all minimal (mandatory) selections are passed + bool mPassesMinimalSelections = true; ///< Set to true if all minimal (mandatory) selections are passed + bool mHasOptionalSelection = false; ///< Set to true if at least one selections is optional + bool mPassesOptionalSelections = false; ///< Set to true if at least one optional (non-mandatory) selections is passed +}; +} // namespace o2::analysis::femto + +#endif // PWGCF_FEMTO_CORE_BASESELECTION_H_ diff --git a/PWGCF/Femto/Core/cascadeBuilder.h b/PWGCF/Femto/Core/cascadeBuilder.h new file mode 100644 index 00000000000..a76d43d5cd2 --- /dev/null +++ b/PWGCF/Femto/Core/cascadeBuilder.h @@ -0,0 +1,487 @@ +// 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 cascadeBuilder.h +/// \brief cascade builder +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_CASCADEBUILDER_H_ +#define PWGCF_FEMTO_CORE_CASCADEBUILDER_H_ + +#include "PWGCF/Femto/Core/baseSelection.h" +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/selectionContainer.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace cascadebuilder +{ + +struct ConfCascadeFilters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CascadeFilters"); + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 99.f, "Maximum pT"}; + o2::framework::Configurable etaMin{"etaMin", -10.f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 10.f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + o2::framework::Configurable massXiMin{"massXiMin", 1.2f, "Minimum Xi mass"}; + o2::framework::Configurable massXiMax{"massXiMax", 1.4f, "Maximum Xi mass"}; + o2::framework::Configurable rejectMassXiMin{"rejectMassXiMin", 1.317f, "Reject Minimum Xi mass for Omega hypothesis"}; + o2::framework::Configurable rejectMassXiMax{"rejectMassXiMax", 1.325f, "Rejection Maximum Xi mass for Omega hypothesis"}; + o2::framework::Configurable massOmegaMin{"massOmegaMin", 1.5f, "Minimum Omega mass"}; + o2::framework::Configurable massOmegaMax{"massOmegaMax", 1.9f, "Maximum Omega mass"}; + o2::framework::Configurable rejectMassOmegaMin{"rejectMassOmegaMin", 1.668f, "Reject minimum Omega mass for Xi hypothesis"}; + o2::framework::Configurable rejectMassOmegaMax{"rejectMassOmegaMax", 1.676f, "Reject maximum Omega mass for Xi hypothesis"}; + o2::framework::Configurable massLambdaMin{"massLambdaMin", 1.0f, "Minimum Lambda mass"}; + o2::framework::Configurable massLambdaMax{"massLambdaMax", 1.2f, "Maximum Lambda mass"}; +}; + +#define CASCADE_DEFAULT_BITS \ + o2::framework::Configurable> cascadeCpaMin{"cascadeCpaMin", {0.95f}, "Minimum cosine of pointing angle"}; \ + o2::framework::Configurable> cascadeTransRadMin{"cascadeTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ + o2::framework::Configurable> cascadeDcaDauMax{"cascadeDcaDauMax", {0.25f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> lambdaCpaMin{"lambdaCpaMin", {0.78f}, "Minimum cosine of pointing angle"}; \ + o2::framework::Configurable> lambdaTransRadMin{"lambdaTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ + o2::framework::Configurable> lambdaDcaDauMax{"lambdaDcaDauMax", {0.5f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> lambdaDcaToPvMin{"lambdaDcaToPvMin", {0.3f}, "Minimum DCA between the lambda and primary vertex"}; \ + o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Minimum DCA of the daughters from primary vertex (cm)"}; \ + o2::framework::Configurable> dauDcaMin{"dauDcaMin", {0.05f}, "Minimum DCA of the daughters from primary vertex (cm)"}; \ + o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; \ + o2::framework::Configurable> posDauTpc{"posDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for positive daughter tracks"}; \ + o2::framework::Configurable> negDauTpc{"negDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for negative daughter tracks"}; + +struct ConfXiBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("XiBits"); + CASCADE_DEFAULT_BITS + o2::framework::Configurable> bachelorTpcPion{"bachelorTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for bachelor tracks"}; +}; + +struct ConfOmegaBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("OmegaBits"); + CASCADE_DEFAULT_BITS + o2::framework::Configurable> bachelorTpcKaon{"bachelorTpcKaon", {5.f}, "Maximum |nsimga_Kaon| TPC for bachelor tracks"}; +}; + +#undef CASCADE_DEFAULT_BITS + +#define CASCADE_DEFAULT_SELECTION(defaultMassMin, defaultMassMax, defaultPdgCode) \ + o2::framework::Configurable pdgCode{"pdgCode", defaultPdgCode, "Track PDG code"}; \ + o2::framework::Configurable sign{"sign", 1, "Sign of the charge of the Cascade "}; \ + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; \ + o2::framework::Configurable ptMax{"ptMax", 999.f, "Maximum pT"}; \ + o2::framework::Configurable etaMin{"etaMin", -10.f, "Minimum eta"}; \ + o2::framework::Configurable etaMax{"etaMax", 10.f, "Maximum eta"}; \ + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum eta"}; \ + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; \ + o2::framework::Configurable massMin{"massMin", defaultMassMin, "Minimum invariant mass for Cascade"}; \ + o2::framework::Configurable massMax{"massMax", defaultMassMax, "Maximum invariant mass for Cascade"}; \ + o2::framework::Configurable mask{"mask", 0x0, "Bitmask for cascade selection"}; + +struct ConfXiSelection : o2::framework::ConfigurableGroup { + std::string prefix = std::string("XiSelection"); + CASCADE_DEFAULT_SELECTION(1.22, 1.42, 3312) +}; + +struct ConfOmegaSelection : o2::framework::ConfigurableGroup { + std::string prefix = std::string("OmegaSelection"); + CASCADE_DEFAULT_SELECTION(1.57, 1.77, 3334) +}; + +/// The different selections this task is capable of doing +enum CascadeSels { + // selections for cascades + kCascadeCpaMin, ///< Min. CPA (cosine pointing angle) + kCascadeDcaDaughMax, ///< Max. DCA of the daughers at decay vertex + kCascadeTransRadMin, ///< max. transverse radius + + // selection for lambda daughter + kLambdaCpaMin, ///< Min. DCA of the lambda daughers at primary vertex + kLambdaDcaDauMax, ///< TPC PID for daughters (Pion/Proton) + kLambdaTransRadMin, ///< Min. number of TPC clusters of daughter + kLambdaDcaToPvMin, ///< Min. DCA to primary vertex of daughter lambda + + // selection for bachelor/daugthers + kDauAbsEtaMax, ///< Min. DCA of the daughers/bachelor at primary vertex + kDauTpcClsMin, ///< Min. number of TPC clusters of daughters/bachelor + kDauDcaMin, ///< TPC Pion PID for negative daughter + + // PID selection for cascade bachelor + kBachelorTpcPion, ///< TPC Pion PID for bachelor + kBachelorTpcKaon, ///< TPC Kaon PID for bachelor + /// + // PID selection for lambda daughers + kPosDauTpc, ///< TPC PID for positive daughter + kNegDauTpc, ///< TPC PID for negative daughter + + kCascadeSelsMax +}; + +constexpr char XiSelHistName[] = "hXiSelection"; +constexpr char OmegaSelHistName[] = "hOmegaSelection"; +constexpr char CascadeSelsName[] = "Cascade Selection Object"; +const std::unordered_map cascadeSelectionNames = { + {kCascadeCpaMin, "Cascade CPA Min"}, + {kCascadeDcaDaughMax, "Cascade DCA Daughters Max"}, + {kCascadeTransRadMin, "Cascade Transverse Radius Min"}, + + {kLambdaCpaMin, "Lambda CPA Min"}, + {kLambdaDcaDauMax, "Lambda DCA Daughter Max"}, + {kLambdaTransRadMin, "Lambda Transverse Radius Min"}, + {kLambdaDcaToPvMin, "Lambda DCA to PV Min"}, + + {kDauAbsEtaMax, "Daughter Abs Eta Max"}, + {kDauTpcClsMin, "Daughter TPC Clusters Min"}, + {kDauDcaMin, "Daughter DCA Min"}, + + {kBachelorTpcPion, "Bachelor TPC Pion PID"}, + {kBachelorTpcKaon, "Bachelor TPC Kaon PID"}, + + {kPosDauTpc, "Positive Daughter TPC PID"}, + {kNegDauTpc, "Negative Daughter TPC PID"}, + + {kCascadeSelsMax, "Cascade Selections Max"}}; + +/// \class FemtoDreamTrackCuts +/// \brief Cut class to contain and execute all cuts applied to tracks +template +class CascadeSelection : public BaseSelection +{ + public: + CascadeSelection() = default; + ~CascadeSelection() = default; + + template + void configure(o2::framework::HistogramRegistry* registry, T1 const& config, T2 const& filter) + { + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { + mXiMassLowerLimit = filter.massXiMin.value; + mXiMassUpperLimit = filter.massXiMax.value; + mOmegaMassLowerLimit = filter.rejectMassOmegaMin.value; + mOmegaMassUpperLimit = filter.rejectMassOmegaMax.value; + this->addSelection(kBachelorTpcPion, cascadeSelectionNames.at(kBachelorTpcPion), config.bachelorTpcPion.value, limits::kAbsUpperLimit, true, true, false); + } + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { + mOmegaMassLowerLimit = filter.massOmegaMin.value; + mOmegaMassUpperLimit = filter.massOmegaMax.value; + mXiMassLowerLimit = filter.rejectMassXiMin.value; + mXiMassUpperLimit = filter.rejectMassXiMax.value; + this->addSelection(kBachelorTpcKaon, cascadeSelectionNames.at(kBachelorTpcKaon), config.bachelorTpcKaon.value, limits::kAbsUpperLimit, true, true, false); + } + + mPtMin = filter.ptMin.value; + mPtMax = filter.ptMax.value; + mEtaMin = filter.etaMin.value; + mEtaMax = filter.etaMax.value; + mPhiMin = filter.phiMin.value; + mPhiMax = filter.phiMax.value; + mLambdaMassMin = filter.massLambdaMin.value; + mLambdaMassMax = filter.massLambdaMax.value; + + this->addSelection(kPosDauTpc, cascadeSelectionNames.at(kPosDauTpc), config.posDauTpc.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kNegDauTpc, cascadeSelectionNames.at(kNegDauTpc), config.negDauTpc.value, limits::kAbsUpperLimit, true, true, false); + + this->addSelection(kCascadeCpaMin, cascadeSelectionNames.at(kCascadeCpaMin), config.cascadeCpaMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kCascadeTransRadMin, cascadeSelectionNames.at(kCascadeTransRadMin), config.cascadeTransRadMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kCascadeDcaDaughMax, cascadeSelectionNames.at(kCascadeDcaDaughMax), config.cascadeDcaDauMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kLambdaCpaMin, cascadeSelectionNames.at(kLambdaCpaMin), config.lambdaCpaMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kLambdaTransRadMin, cascadeSelectionNames.at(kLambdaTransRadMin), config.lambdaTransRadMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kLambdaDcaDauMax, cascadeSelectionNames.at(kLambdaDcaDauMax), config.lambdaDcaDauMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kLambdaDcaToPvMin, cascadeSelectionNames.at(kLambdaDcaToPvMin), config.lambdaDcaToPvMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kDauAbsEtaMax, cascadeSelectionNames.at(kDauAbsEtaMax), config.dauAbsEtaMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kDauDcaMin, cascadeSelectionNames.at(kDauDcaMin), config.dauDcaMin.value, limits::kAbsLowerLimit, true, true, false); + this->addSelection(kDauTpcClsMin, cascadeSelectionNames.at(kDauTpcClsMin), config.dauTpcClustersMin.value, limits::kLowerLimit, true, true, false); + + this->setupContainers(registry); + }; + + template + void applySelections(T1 const& cascade, T2 const& /*tracks*/, T3 const& col) + { + this->reset(); + // cascade selections + this->evaluateObservable(kCascadeCpaMin, cascade.casccosPA(col.posX(), col.posY(), col.posZ())); + this->evaluateObservable(kCascadeDcaDaughMax, cascade.dcacascdaughters()); + this->evaluateObservable(kCascadeTransRadMin, cascade.cascradius()); + + // lambda selection + this->evaluateObservable(kLambdaCpaMin, cascade.v0cosPA(col.posX(), col.posY(), col.posZ())); + this->evaluateObservable(kLambdaDcaDauMax, cascade.dcaV0daughters()); + this->evaluateObservable(kLambdaTransRadMin, cascade.v0radius()); + this->evaluateObservable(kLambdaDcaToPvMin, cascade.dcav0topv(col.posX(), col.posY(), col.posZ())); + + auto bachelor = cascade.template bachelor_as(); + auto posDaughter = cascade.template posTrack_as(); + auto negDaughter = cascade.template negTrack_as(); + + // daughter selections + std::array etaDaughters = {std::fabs(bachelor.eta()), std::fabs(posDaughter.eta()), std::fabs(negDaughter.eta())}; + this->evaluateObservable(kDauAbsEtaMax, *std::max_element(etaDaughters.begin(), etaDaughters.end())); + + std::array dcaDaughters = {std::hypot(bachelor.dcaXY(), bachelor.dcaZ()), + std::hypot(posDaughter.dcaXY(), posDaughter.dcaZ()), + std::hypot(negDaughter.dcaXY(), negDaughter.dcaZ())}; + this->evaluateObservable(kDauDcaMin, *std::min_element(dcaDaughters.begin(), dcaDaughters.end())); + + std::array clustersDaughters = {1.f * bachelor.tpcNClsFound(), 1.f * posDaughter.tpcNClsFound(), 1.f * negDaughter.tpcNClsFound()}; + this->evaluateObservable(kDauTpcClsMin, *std::min_element(clustersDaughters.begin(), clustersDaughters.end())); + + // bachelor pid selection + // check both pion and kaon PID for xi and omega + this->evaluateObservable(kBachelorTpcPion, bachelor.tpcNSigmaPi()); + this->evaluateObservable(kBachelorTpcKaon, bachelor.tpcNSigmaKa()); + + // depending on the charge, we check lambda or antilambda hypothesis + if (cascade.sign() < 0) { + this->evaluateObservable(kPosDauTpc, posDaughter.tpcNSigmaPr()); + this->evaluateObservable(kNegDauTpc, negDaughter.tpcNSigmaPi()); + } else if (cascade.sign() > 0) { + this->evaluateObservable(kPosDauTpc, posDaughter.tpcNSigmaPi()); + this->evaluateObservable(kNegDauTpc, negDaughter.tpcNSigmaPr()); + } else { + LOG(warn) << "Encountered Cascade candidate with 0 charge"; + } + + this->assembleBitmask(); + }; + + template + bool checkFilters(const T& cascade) const + { + // check kinematics + const bool kinematicsOK = + (cascade.pt() > mPtMin && cascade.pt() < mPtMax) && + (cascade.eta() > mEtaMin && cascade.eta() < mEtaMax) && + (cascade.phi() > mPhiMin && cascade.phi() < mPhiMax); + + if (!kinematicsOK) { + return false; + } + + // check mass of daughter lambda + const bool lambdaOK = + (cascade.mLambda() > mLambdaMassMin && cascade.mLambda() < mLambdaMassMax); + + if (!lambdaOK) { + return false; + } + + // check mass hypothesis + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { + // Xi candidate must be inside Xi window and outside Omega + return (cascade.mXi() > mXiMassLowerLimit && cascade.mXi() < mXiMassUpperLimit) && + (cascade.mOmega() < mOmegaMassLowerLimit || cascade.mOmega() > mOmegaMassUpperLimit); + } + + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { + // Omega candidate must be inside Omega window and outside Xi + return (cascade.mOmega() > mOmegaMassLowerLimit && cascade.mOmega() < mOmegaMassUpperLimit) && + (cascade.mXi() < mXiMassLowerLimit || cascade.mXi() > mXiMassUpperLimit); + } + + return false; // should never happen + } + + protected: + float mXiMassLowerLimit = 0.f; + float mXiMassUpperLimit = 999.f; + + float mOmegaMassLowerLimit = 0.f; + float mOmegaMassUpperLimit = 999.f; + + // kinematic filters + float mPtMin = 0.f; + float mPtMax = 6.f; + float mEtaMin = -0.9f; + float mEtaMax = 0.9f; + float mPhiMin = 0.f; + float mPhiMax = o2::constants::math::TwoPI; + float mLambdaMassMin = 1.f; + float mLambdaMassMax = 1.2f; +}; + +struct CascadeBuilderProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedXis; + o2::framework::Produces producedXiMasks; + o2::framework::Produces producedXiExtras; + o2::framework::Produces producedOmegas; + o2::framework::Produces producedOmegaMasks; + o2::framework::Produces producedOmegaExtras; +}; + +struct ConfCascadeTables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CascadeTables"); + o2::framework::Configurable produceXis{"produceXis", -1, "Produce Xis (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceXiMasks{"produceXiMasks", -1, "Produce XiMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceXiExtras{"produceXiExtras", -1, "Produce XiExtras (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceOmegas{"produceOmegas", -1, "Produce Omegas (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceOmegaMasks{"produceOmegaMasks", -1, "Produce OmegaMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceOmegaExtras{"produceOmegaExtras", -1, "Produce OmegaExtras (-1: auto; 0 off; 1 on)"}; +}; + +template +class CascadeBuilder +{ + public: + CascadeBuilder() = default; + ~CascadeBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + { + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { + LOG(info) << "Initialize femto Xi builder..."; + mProduceXis = utils::enableTable("FXis_001", table.produceXis.value, initContext); + mProduceXiMasks = utils::enableTable("FXiMasks_001", table.produceXiMasks.value, initContext); + mProduceXiExtras = utils::enableTable("FXiExtras_001", table.produceXiExtras.value, initContext); + } + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { + LOG(info) << "Initialize femto Omega builder..."; + mProduceOmegas = utils::enableTable("FOmegas_001", table.produceOmegas.value, initContext); + mProduceOmegaMasks = utils::enableTable("FOmegaMasks_001", table.produceOmegaMasks.value, initContext); + mProduceOmegaExtras = utils::enableTable("FOmegaExtras_001", table.produceOmegaExtras.value, initContext); + } + + if (mProduceXis || mProduceXiExtras || mProduceXiMasks || mProduceOmegas || mProduceOmegaMasks || mProduceOmegaExtras) { + mFillAnyTable = true; + } else { + LOG(info) << "No tables configured, Selection object will not be configured..."; + LOG(info) << "Initialization done..."; + return; + } + mCascadeSelection.configure(registry, config, filter); + mCascadeSelection.printSelections(CascadeSelsName); + LOG(info) << "Initialization done..."; + } + + template + void fillCascades(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, T5& cascadeProducts, T6 const& fullCascades, T7 const& fullTracks, T8& trackBuilder, T9& indexMap) + { + if (!mFillAnyTable) { + return; + } + + int64_t bachelorIndex = 0; + int64_t posDaughterIndex = 0; + int64_t negDaughterIndex = 0; + for (const auto& cascade : fullCascades) { + if (!mCascadeSelection.checkFilters(cascade)) { + continue; + } + mCascadeSelection.applySelections(cascade, fullTracks, col); + if (!mCascadeSelection.passesAllRequiredSelections()) { + continue; + } + + auto bachelor = cascade.template bachelor_as(); + auto posDaughter = cascade.template posTrack_as(); + auto negDaughter = cascade.template negTrack_as(); + + collisionBuilder.template fillCollision(collisionProducts, col); + + bachelorIndex = trackBuilder.template getDaughterIndex(bachelor, trackProducts, collisionProducts, indexMap); + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionProducts, indexMap); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionProducts, indexMap); + + fillCascade(collisionProducts, cascadeProducts, cascade, col, bachelorIndex, posDaughterIndex, negDaughterIndex); + } + } + + template + void fillCascade(T1& collisionProducts, T2& cascadeProducts, T3 const& cascade, T4 const& col, int bachelorIndex, int posDaughterIndex, int negDaughterIndex) + { + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { + if (mProduceXis) { + cascadeProducts.producedXis(collisionProducts.producedCollision.lastIndex(), + cascade.sign() * cascade.pt(), + cascade.eta(), + cascade.phi(), + cascade.mXi(), + bachelorIndex, + posDaughterIndex, + negDaughterIndex); + } + if (mProduceXiMasks) { + cascadeProducts.producedXiMasks(mCascadeSelection.getBitmask()); + } + if (mProduceXiExtras) { + cascadeProducts.producedXiExtras( + cascade.mOmega(), + cascade.casccosPA(col.posX(), col.posY(), col.posZ()), + cascade.dcacascdaughters(), + cascade.cascradius(), + cascade.v0cosPA(col.posX(), col.posY(), col.posZ()), + cascade.dcaV0daughters(), + cascade.v0radius(), + cascade.dcav0topv(col.posY(), col.posY(), col.posZ())); + } + } + if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) { + if (mProduceOmegas) { + cascadeProducts.producedOmegas(collisionProducts.producedCollision.lastIndex(), + cascade.sign() * cascade.pt(), + cascade.eta(), + cascade.phi(), + cascade.mOmega(), + bachelorIndex, + posDaughterIndex, + negDaughterIndex); + } + if (mProduceOmegaMasks) { + cascadeProducts.producedOmegaMasks(mCascadeSelection.getBitmask()); + } + if (mProduceOmegaExtras) { + cascadeProducts.producedOmegaExtras( + cascade.mXi(), + cascade.casccosPA(col.posX(), col.posY(), col.posZ()), + cascade.dcacascdaughters(), + cascade.cascradius(), + cascade.v0cosPA(col.posX(), col.posY(), col.posZ()), + cascade.dcaV0daughters(), + cascade.v0radius(), + cascade.dcav0topv(col.posY(), col.posY(), col.posZ())); + } + } + } + + bool fillAnyTable() { return mFillAnyTable; } + + private: + CascadeSelection mCascadeSelection; + bool mFillAnyTable = false; + bool mProduceXis = false; + bool mProduceXiMasks = false; + bool mProduceXiExtras = false; + bool mProduceOmegas = false; + bool mProduceOmegaMasks = false; + bool mProduceOmegaExtras = false; +}; + +} // namespace cascadebuilder +} // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_CASCADEBUILDER_H_ diff --git a/PWGCF/Femto/Core/cascadeHistManager.h b/PWGCF/Femto/Core/cascadeHistManager.h new file mode 100644 index 00000000000..358c72292ff --- /dev/null +++ b/PWGCF/Femto/Core/cascadeHistManager.h @@ -0,0 +1,319 @@ +// 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 cascadeHistManager.h +/// \brief histogram manager for cascade histograms +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_CORE_CASCADEHISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_CASCADEHISTMANAGER_H_ + +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/trackHistManager.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace cascadehistmanager +{ +// enum for track histograms +enum CascadeHist { + // analysis + kPt, + kEta, + kPhi, + kMass, + kSign, + // qa variables + kMassXi, + kMassOmega, + kCosPa, + kDecayDauDca, + kTransRadius, + // 2d qa + kPtVsEta, + kPtVsPhi, + kPhiVsEta, + kPtVsCosPa, + kPtVsMassXi, + kPtVsMassOmega, + kMassXiVsMassOmega, + kCascadeHistLast +}; + +template +struct ConfCascadeBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::ConfigurableAxis pt{"pt", {{600, 0, 6}}, "Pt"}; + o2::framework::ConfigurableAxis eta{"eta", {{300, -1.5, 1.5}}, "Eta"}; + o2::framework::ConfigurableAxis phi{"phi", {{720, 0, 1.f * o2::constants::math::TwoPI}}, "Phi"}; + o2::framework::ConfigurableAxis mass{"mass", {{1000, 1.f, 2.f}}, "Mass"}; + o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; +}; + +constexpr const char PrefixXiBinning[] = "XiBinning"; +using ConfXiBinning = ConfCascadeBinning; +constexpr const char PrefixOmegaBinning[] = "OmegaBinning"; +using ConfOmegaBinning = ConfCascadeBinning; + +template +struct ConfCascadeQaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable plot2d{"plot2d", true, "Enable 2d Qa histograms"}; + o2::framework::ConfigurableAxis cosPa{"cosPa", {{100, 0.9, 1}}, "Cosine of poiting angle"}; + o2::framework::ConfigurableAxis dauDcaAtDecay{"dauDcaAtDecay", {{150, 0, 1.5}}, "Daughter DCA at decay vertex"}; + o2::framework::ConfigurableAxis transRadius{"transRadius", {{100, 0, 100}}, "Transverse radius"}; + o2::framework::ConfigurableAxis massXi{"massXi", {{400, 1.2f, 1.6f}}, "mass for antiparticle hypothesis"}; + o2::framework::ConfigurableAxis massOmega{"massOmega", {{400, 1.4f, 1.8f}}, "mass for antiparticle hypothesis"}; +}; + +constexpr const char PrefixXiQaBinning[] = "XiQaBinning"; +using ConfXiQaBinning = ConfCascadeQaBinning; + +constexpr const char PrefixOmegatQaBinning[] = "OmegaQaBinning"; +using ConfOmegaQaBinning = ConfCascadeQaBinning; + +// must be in sync with enum TrackVariables +// the enum gives the correct index in the array +constexpr std::array, kCascadeHistLast> HistTable = { + {{kPt, o2::framework::kTH1F, "hPt", "Transverse Momentum; p_{T} (GeV/#it{c}); Entries"}, + {kEta, o2::framework::kTH1F, "hEta", "Pseudorapdity; #eta; Entries"}, + {kPhi, o2::framework::kTH1F, "hPhi", "Azimuthal angle; #varphi; Entries"}, + {kMass, o2::framework::kTH1F, "hMass", "Invariant Mass; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kSign, o2::framework::kTH1F, "hSign", "Sign (-1 -> antiparticle, 0 -> self conjugate, +1 -> particle); sign; Entries"}, + {kMassXi, o2::framework::kTH1F, "hMassXi", "Mass #Xi; m_{#Lambda#pi} (GeV/#it{c}^{2}); Entries"}, + {kMassOmega, o2::framework::kTH1F, "hMassOmega", "mass #Omega; m_{#LambdaK} (GeV/#it{c}^{2}); Entries"}, + {kCosPa, o2::framework::kTH1F, "hCosPa", "Cosine of pointing angle; coa(#alpha); Entries"}, + {kDecayDauDca, o2::framework::kTH1F, "hDauDca", "Daughter DCA at decay vertex ; DCA_{Decay vertex} (cm); Entries"}, + {kTransRadius, o2::framework::kTH1F, "hTransRadius", "Transverse radius ; r_{xy} (cm); Entries"}, + {kPtVsEta, o2::framework::kTH2F, "hPtVsEta", "p_{T} vs #eta; p_{T} (GeV/#it{c}) ; #eta"}, + {kPtVsPhi, o2::framework::kTH2F, "hPtVsPhi", "p_{T} vs #varphi; p_{T} (GeV/#it{c}) ; #varphi"}, + {kPhiVsEta, o2::framework::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi ; #eta"}, + {kPtVsCosPa, o2::framework::kTH2F, "hPtVsCosPa", "Cosine of poiting angle vs p_{T}; cos(#alpha); p_{T} (GeV/#it{c})"}, + {kPtVsMassXi, o2::framework::kTH2F, "hPtVsMassXi", "p_{T} vs mass #Xi; p_{T} (GeV/#it{c}); m_{#Lambda#pi} (GeV/#it{c}^{2})"}, + {kPtVsMassOmega, o2::framework::kTH2F, "hPtVsMassOmega", "p_{T} vs mass #Omega; p_{T} (GeV/#it{c}); m_{#LambdaK} (GeV/#it{c}^{2})"}, + {kMassXiVsMassOmega, o2::framework::kTH2F, "hMassXiVsMassOmega", "mass #Xi vs mass #Omega; m_{#Lambda#pi} (GeV/#it{c}^{2}); m_{#LambdaK} (GeV/#it{c}^{2})"}}}; + +template +auto makeCascadeHistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kMass, {confBinningAnalysis.mass}}, + {kSign, {confBinningAnalysis.sign}}}; +} + +template +std::map> makeCascadeQaHistSpecMap(T1 const& confBinningAnalysis, T2 const& confBinningQa) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kMass, {confBinningAnalysis.mass}}, + {kSign, {confBinningAnalysis.sign}}, + {kCosPa, {confBinningQa.cosPa}}, + {kDecayDauDca, {confBinningQa.dauDcaAtDecay}}, + {kTransRadius, {confBinningQa.transRadius}}, + {kPtVsEta, {confBinningAnalysis.pt, confBinningAnalysis.eta}}, + {kPtVsPhi, {confBinningAnalysis.pt, confBinningAnalysis.phi}}, + {kPhiVsEta, {confBinningAnalysis.phi, confBinningAnalysis.eta}}, + {kPtVsCosPa, {confBinningAnalysis.pt, confBinningQa.cosPa}}, + {kMassXi, {confBinningQa.massXi}}, + {kMassOmega, {confBinningQa.massOmega}}, + {kPtVsMassXi, {confBinningAnalysis.pt, confBinningQa.massXi}}, + {kPtVsMassOmega, {confBinningAnalysis.pt, confBinningQa.massOmega}}, + {kMassXiVsMassOmega, {confBinningQa.massXi, confBinningQa.massOmega}}}; +}; + +constexpr char PrefixXiQa[] = "XiQA/"; +constexpr char PrefixXi[] = "Xi/"; +constexpr char PrefixOmegaQa[] = "OmegaQa/"; +constexpr char PrefixOmega[] = "Omega/"; + +constexpr char PrefixLambdaCascade[] = "LambdaCascadeQa/"; + +constexpr std::string_view AnalysisDir = "Kinematics/"; +constexpr std::string_view QaDir = "QA/"; + +/// \class FemtoDreamEventHisto +/// \brief Class for histogramming event properties +// template +template +class CascadeHistManager +{ + public: + CascadeHistManager() = default; + ~CascadeHistManager() = default; + + void init(o2::framework::HistogramRegistry* registry, + std::map> const& cascadeSpecs, + std::map> const& BachelorSpecs, + std::map> const& PosDauSpecs, + std::map> const& NegDauSpecs) + { + mHistogramRegistry = registry; + mBachelorManager.init(registry, BachelorSpecs); + mPosDauManager.init(registry, PosDauSpecs); + mNegDauManager.init(registry, NegDauSpecs); + if constexpr (modes::isFlagSet(mode, modes::Mode::kAnalysis)) { + initAnalysis(cascadeSpecs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + initQa(cascadeSpecs); + } + } + + template + void enableOptionalHistograms(T1 const& CascadeConfBinningQa, T2 const& BachelorConfBinningQa, T3 const& PosDauConfBinningQa, T4 const& NegDauConfBinningQa) + { + mBachelorManager.enableOptionalHistograms(BachelorConfBinningQa); + mPosDauManager.enableOptionalHistograms(PosDauConfBinningQa); + mNegDauManager.enableOptionalHistograms(NegDauConfBinningQa); + mPlot2d = CascadeConfBinningQa.plot2d.value; + } + + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& cascadeSpecs, + T1 const& CascadeConfBinningQa, + std::map> const& BachelorSpecs, + T2 const& BachelorConfBinningQa, + std::map> const& PosDauSpecs, + T3 const& PosDauConfBinningQa, + std::map> const& NegDauSpecs, + T4 const& NegDauConfBinningQa) + { + enableOptionalHistograms(CascadeConfBinningQa, BachelorConfBinningQa, PosDauConfBinningQa, NegDauConfBinningQa); + init(registry, cascadeSpecs, BachelorSpecs, PosDauSpecs, NegDauSpecs); + } + + template + void fill(T1 const& cascadeCandidate, T2 const& tracks) + { + // this used to work, still under investigation + // auto bachelor = cascadeCandidate.template bachelor_as(); + // auto posDaughter = cascadeCandidate.template posDau_as(); + // auto negDaughter = cascadeCandidate.template negDau_as(); + auto posDaughter = tracks.rawIteratorAt(cascadeCandidate.posDauId() - tracks.offset()); + mPosDauManager.fill(posDaughter, tracks); + auto negDaughter = tracks.rawIteratorAt(cascadeCandidate.negDauId() - tracks.offset()); + mNegDauManager.fill(negDaughter, tracks); + auto bachelor = tracks.rawIteratorAt(cascadeCandidate.bachelorId() - tracks.offset()); + mBachelorManager.fill(bachelor, tracks); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kAnalysis)) { + fillAnalysis(cascadeCandidate); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + fillQa(cascadeCandidate); + } + } + + private: + void initAnalysis(std::map> const& cascadeSpecs) + { + std::string analysisDir = std::string(cascadePrefix) + std::string(AnalysisDir); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt, HistTable), getHistDesc(kPt, HistTable), getHistType(kPt, HistTable), {cascadeSpecs.at(kPt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kEta, HistTable), getHistDesc(kEta, HistTable), getHistType(kEta, HistTable), {cascadeSpecs.at(kEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhi, HistTable), getHistDesc(kPhi, HistTable), getHistType(kPhi, HistTable), {cascadeSpecs.at(kPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMass, HistTable), getHistDesc(kMass, HistTable), getHistType(kMass, HistTable), {cascadeSpecs.at(kMass)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kSign, HistTable), getHistDesc(kSign, HistTable), getHistType(kSign, HistTable), {cascadeSpecs.at(kSign)}); + } + + void initQa(std::map> const& cascadeSpecs) + { + std::string qaDir = std::string(cascadePrefix) + std::string(QaDir); + mHistogramRegistry->add(qaDir + getHistNameV2(kCosPa, HistTable), getHistDesc(kCosPa, HistTable), getHistType(kCosPa, HistTable), {cascadeSpecs.at(kCosPa)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayDauDca, HistTable), getHistDesc(kDecayDauDca, HistTable), getHistType(kDecayDauDca, HistTable), {cascadeSpecs.at(kDecayDauDca)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTransRadius, HistTable), getHistDesc(kTransRadius, HistTable), getHistType(kTransRadius, HistTable), {cascadeSpecs.at(kTransRadius)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassXi, HistTable), getHistDesc(kMassXi, HistTable), getHistType(kMassXi, HistTable), {cascadeSpecs.at(kMassXi)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassOmega, HistTable), getHistDesc(kMassOmega, HistTable), getHistType(kMassOmega, HistTable), {cascadeSpecs.at(kMassOmega)}); + + if (mPlot2d) { + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsEta, HistTable), getHistDesc(kPtVsEta, HistTable), getHistType(kPtVsEta, HistTable), {cascadeSpecs.at(kPtVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsPhi, HistTable), getHistDesc(kPtVsPhi, HistTable), getHistType(kPtVsPhi, HistTable), {cascadeSpecs.at(kPtVsPhi)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPhiVsEta, HistTable), getHistDesc(kPhiVsEta, HistTable), getHistType(kPhiVsEta, HistTable), {cascadeSpecs.at(kPhiVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsCosPa, HistTable), getHistDesc(kPtVsCosPa, HistTable), getHistType(kPtVsCosPa, HistTable), {cascadeSpecs.at(kPtVsCosPa)}); + + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsMassXi, HistTable), getHistDesc(kPtVsMassXi, HistTable), getHistType(kPtVsMassXi, HistTable), {cascadeSpecs.at(kPtVsMassXi)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsMassOmega, HistTable), getHistDesc(kPtVsMassOmega, HistTable), getHistType(kPtVsMassOmega, HistTable), {cascadeSpecs.at(kPtVsMassOmega)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassXiVsMassOmega, HistTable), getHistDesc(kMassXiVsMassOmega, HistTable), getHistType(kMassXiVsMassOmega, HistTable), {cascadeSpecs.at(kMassXiVsMassOmega)}); + } + } + + template + void fillAnalysis(T const& cascadeCandidate) + { + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(AnalysisDir) + HIST(getHistName(kPt, HistTable)), cascadeCandidate.pt()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(AnalysisDir) + HIST(getHistName(kEta, HistTable)), cascadeCandidate.eta()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(AnalysisDir) + HIST(getHistName(kPhi, HistTable)), cascadeCandidate.phi()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(AnalysisDir) + HIST(getHistName(kMass, HistTable)), cascadeCandidate.mass()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), cascadeCandidate.sign()); + } + + template + void fillQa(T const& cascadeCandidate) + { + float massXi = 0.f; + float massOmega = 0.f; + if constexpr (modes::isEqual(cascade, modes::Cascade::kXi)) { + massXi = cascadeCandidate.mass(); + massOmega = cascadeCandidate.massOmega(); + } + if constexpr (modes::isEqual(cascade, modes::Cascade::kOmega)) { + massXi = cascadeCandidate.massXi(); + massOmega = cascadeCandidate.mass(); + } + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kCosPa, HistTable)), cascadeCandidate.cascadeCosPa()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kDecayDauDca, HistTable)), cascadeCandidate.cascadeDauDca()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kTransRadius, HistTable)), cascadeCandidate.cascadeTransRadius()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kMassXi, HistTable)), massXi); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kMassOmega, HistTable)), massOmega); + + if (mPlot2d) { + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPtVsEta, HistTable)), cascadeCandidate.pt(), cascadeCandidate.eta()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPtVsPhi, HistTable)), cascadeCandidate.pt(), cascadeCandidate.phi()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPhiVsEta, HistTable)), cascadeCandidate.phi(), cascadeCandidate.eta()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPtVsCosPa, HistTable)), cascadeCandidate.pt(), cascadeCandidate.cascadeCosPa()); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPtVsMassXi, HistTable)), cascadeCandidate.pt(), massXi); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kPtVsMassOmega, HistTable)), cascadeCandidate.pt(), massOmega); + mHistogramRegistry->fill(HIST(cascadePrefix) + HIST(QaDir) + HIST(getHistName(kMassXiVsMassOmega, HistTable)), massXi, massOmega); + } + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + bool mPlot2d = true; + trackhistmanager::TrackHistManager mBachelorManager; + trackhistmanager::TrackHistManager mPosDauManager; + trackhistmanager::TrackHistManager mNegDauManager; +}; +}; // namespace cascadehistmanager +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_CASCADEHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/closePairRejection.h b/PWGCF/Femto/Core/closePairRejection.h new file mode 100644 index 00000000000..9ac2ea0ad8b --- /dev/null +++ b/PWGCF/Femto/Core/closePairRejection.h @@ -0,0 +1,533 @@ +// 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 closePairRejection.h +/// \brief Definition of ClosePairRejection class +/// \author Anton Riedel, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_CLOSEPAIRREJECTION_H_ +#define PWGCF_FEMTO_CORE_CLOSEPAIRREJECTION_H_ + +#include "RecoDecay.h" + +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/histManager.h" + +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace closepairrejection +{ +// enum for track histograms +enum CprHist { + // kinemtics + kAverage, + kRadius0, + kRadius1, + kRadius2, + kRadius3, + kRadius4, + kRadius5, + kRadius6, + kRadius7, + kRadius8, + kCprHistogramLast +}; + +// template configurable group for Cpr +template +struct ConfCpr : o2::framework::ConfigurableGroup { + std::string prefix = std::string(Prefix); + o2::framework::Configurable cutAverage{"cutAverage", true, "Apply CPR if the average deta-dphistar is below the configured values"}; + o2::framework::Configurable cutAnyRadius{"cutAnyRadius", false, "Apply CPR if the deta-dphistar is below the configured values at any radius"}; + o2::framework::Configurable plotAllRadii{"plotAllRadii", true, "Plot deta-dphi distribution at all radii"}; + o2::framework::Configurable plotAverage{"plotAverage", true, "Plot average deta dphi distribution"}; + o2::framework::Configurable detaMax{"detaMax", 0.01f, "Maximium deta"}; + o2::framework::Configurable dphistarMax{"dphistarMax", 0.01f, "Maximum dphistar"}; + o2::framework::Configurable detaCenter{"detaCenter", 0.f, "Center of deta cut"}; + o2::framework::Configurable dphistarCenter{"dphistarCenter", 0.f, "Center of dphistar cut"}; + o2::framework::Configurable kstarMin{"kstarMin", -1.f, "Minimum kstar of pair for plotting (Set to negative value to turn off the cut)"}; + o2::framework::Configurable kstarMax{"kstarMax", -1.f, "Maximum kstar of pair for plotting (Set to negative value to turn off the cut)"}; + o2::framework::ConfigurableAxis binningDeta{"binningDeta", {{250, -0.5, 0.5}}, "deta"}; + o2::framework::ConfigurableAxis binningDphistar{"binningDphistar", {{250, -0.5, 0.5}}, "dphi"}; +}; + +constexpr const char PrefixCprTrackTrack[] = "CprTrackTrack"; +constexpr const char PrefixCprTrackV0Daughter[] = "CprTrackV0Daughter"; +constexpr const char PrefixCprTrackResonanceDaughter[] = "CprTrackResonanceDaughter"; +constexpr const char PrefixCprTrackKinkDaughter[] = "CprTrackKinkDaughter"; +constexpr const char PrefixCprV0DaughterV0DaughterPos[] = "CprV0DaughterV0DaughterPos"; +constexpr const char PrefixCprV0DaughterV0DaughterNeg[] = "CprV0DaughterV0DaughterNeg"; +constexpr const char PrefixCprTrackCascadeBachelor[] = "CprTrackCascadeBachelor"; + +using ConfCprTrackTrack = ConfCpr; +using ConfCprTrackV0Daughter = ConfCpr; +using ConfCprTrackResonanceDaughter = ConfCpr; +using ConfCprTrackKinkDaughter = ConfCpr; +using ConfCprV0DaugherV0DaughterPos = ConfCpr; +using ConfCprV0DaugherV0DaughterNeg = ConfCpr; +using ConfCprTrackCascadeBachelor = ConfCpr; + +// tpc radii for computing phistar +constexpr int Nradii = 9; +constexpr std::array TpcRadii = {85., 105., 125., 145., 165., 185., 205., 225., 245.}; // in cm + +// directory names +constexpr char PrefixTrackTrackSe[] = "CPR_TrackTrack/SE/"; +constexpr char PrefixTrackTrackMe[] = "CPR_TrackTrack/ME/"; +constexpr char PrefixTrackV0DaughterSe[] = "CPR_TrackV0Dau/SE/"; +constexpr char PrefixTrackV0DaughterMe[] = "CPR_TrackV0Dau/ME/"; +constexpr char PrefixV0V0PosSe[] = "CPR_V0V0_PosDau/SE/"; +constexpr char PrefixV0V0NegSe[] = "CPR_V0V0_NegDau/SE/"; +constexpr char PrefixV0V0PosMe[] = "CPR_V0V0_PosDau/ME/"; +constexpr char PrefixV0V0NegMe[] = "CPR_V0V0_NegDau/ME/"; +constexpr char PrefixTrackTwoTrackResonanceSe[] = "CPR_TrackResonanceDau/SE/"; +constexpr char PrefixTrackTwoTrackResonanceMe[] = "CPR_TrackResonanceDau/ME/"; +constexpr char PrefixTrackCascadeBachelorSe[] = "CPR_TrackCascadeBachelor/SE/"; +constexpr char PrefixTrackCascadeBachelorMe[] = "CPR_TrackCascadeBachelor/ME/"; +constexpr char PrefixTrackKinkSe[] = "CPR_TrackKink/SE/"; +constexpr char PrefixTrackKinkMe[] = "CPR_TrackKink/ME/"; + +// must be in sync with enum TrackVariables +// the enum gives the correct index in the array +constexpr std::array, kCprHistogramLast> HistTable = { + {{kAverage, o2::framework::kTH2F, "hAverage", "#Delta #eta vs #Delta #phi* (averaged over all radii); #Delta #eta; #Delta #phi*"}, + {kRadius0, o2::framework::kTH2F, "hRadius0", "Radius 0: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kRadius1, o2::framework::kTH2F, "hRadius1", "Radius 1: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kRadius2, o2::framework::kTH2F, "hRadius2", "Radius 2: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kRadius3, o2::framework::kTH2F, "hRadius3", "Radius 3: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kRadius4, o2::framework::kTH2F, "hRadius4", "Radius 4: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kRadius5, o2::framework::kTH2F, "hRadius5", "Radius 5: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kRadius6, o2::framework::kTH2F, "hRadius6", "Radius 6: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kRadius7, o2::framework::kTH2F, "hRadius7", "Radius 7: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kRadius8, o2::framework::kTH2F, "hRadius8", "Radius 8: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}}}; + +template +auto makeCprHistSpecMap(const T& confCpr) +{ + return std::map>{ + {kAverage, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius0, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius1, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius2, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius3, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius4, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius5, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius6, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius7, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kRadius8, {confCpr.binningDeta, confCpr.binningDphistar}}}; +}; + +template +class CloseTrackRejection +{ + public: + CloseTrackRejection() = default; + ~CloseTrackRejection() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& specs, + T const& confCpr, + int chargeAbsTrack1, + int chargeAbsTrack2) + { + mDetaMax = confCpr.detaMax.value; + mDphistarMax = confCpr.dphistarMax.value; + + // check the limits + if (mDetaMax <= 0 || mDphistarMax <= 0) { + LOG(fatal) << "Limits for Close Pair Rejection are invalid (0 or negative). Breaking..."; + } + + mDetaCenter = confCpr.detaCenter.value; + mDphistarCenter = confCpr.dphistarCenter.value; + + mChargeAbsTrack1 = std::abs(chargeAbsTrack1); + mChargeAbsTrack2 = std::abs(chargeAbsTrack2); + + mCutAverage = confCpr.cutAverage.value; + mCutAnyRadius = confCpr.cutAnyRadius.value; + + mKstarMin = confCpr.kstarMin.value; + mKstarMax = confCpr.kstarMax.value; + + mPlotAverage = confCpr.plotAverage.value; + mPlotAllRadii = confCpr.plotAllRadii.value; + + // check if we need to apply any cut a plot is requested + mIsActivated = mCutAverage || mCutAnyRadius || mPlotAverage || mPlotAllRadii; + + mHistogramRegistry = registry; + + if (mPlotAverage) { + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kAverage, HistTable), getHistDesc(kAverage, HistTable), getHistType(kAverage, HistTable), {specs.at(kAverage)}); + } + if (mPlotAllRadii) { + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius0, HistTable), getHistDesc(kRadius0, HistTable), getHistType(kRadius0, HistTable), {specs.at(kRadius0)}); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius1, HistTable), getHistDesc(kRadius1, HistTable), getHistType(kRadius1, HistTable), {specs.at(kRadius1)}); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius2, HistTable), getHistDesc(kRadius2, HistTable), getHistType(kRadius2, HistTable), {specs.at(kRadius2)}); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius3, HistTable), getHistDesc(kRadius3, HistTable), getHistType(kRadius3, HistTable), {specs.at(kRadius3)}); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius4, HistTable), getHistDesc(kRadius4, HistTable), getHistType(kRadius4, HistTable), {specs.at(kRadius4)}); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius5, HistTable), getHistDesc(kRadius5, HistTable), getHistType(kRadius5, HistTable), {specs.at(kRadius5)}); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius6, HistTable), getHistDesc(kRadius6, HistTable), getHistType(kRadius6, HistTable), {specs.at(kRadius6)}); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius7, HistTable), getHistDesc(kRadius7, HistTable), getHistType(kRadius7, HistTable), {specs.at(kRadius7)}); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kRadius8, HistTable), getHistDesc(kRadius8, HistTable), getHistType(kRadius8, HistTable), {specs.at(kRadius8)}); + } + } + + void setMagField(float magField) { mMagField = magField; } + + template + void compute(T1 const& track1, T2 const& track2) + { + if (!mIsActivated) { + return; + } + // reset values + mAverageDphistar = 0.f; + int count = 0; + mDeta = 0.f; + mDphistar.fill(0.f); + mDphistarMask.fill(false); + + mDeta = track1.eta() - track2.eta(); + + for (size_t i = 0; i < TpcRadii.size(); i++) { + auto phistar1 = utils::dphistar(mMagField, TpcRadii[i], mChargeAbsTrack1 * track1.signedPt(), track1.phi()); + auto phistar2 = utils::dphistar(mMagField, TpcRadii[i], mChargeAbsTrack2 * track2.signedPt(), track2.phi()); + if (phistar1 && phistar2) { + mDphistar.at(i) = RecoDecay::constrainAngle(phistar1.value() - phistar2.value(), -o2::constants::math::PI); // constrain angular difference between -pi and pi + mDphistarMask.at(i) = true; + count++; + } + } + // for small momemeta the calculation of phistar might fail, if the particle did not reach a certain radius + if (count > 0) { + mAverageDphistar = std::accumulate(mDphistar.begin(), mDphistar.end(), 0.f) / count; // only average values if phistar could be computed + } else { + mAverageDphistar = 0.f; // if computation at all radii fail, set it 0 + } + } + + void fill(float kstar) + { + if (!mIsActivated) { + return; + } + + if (mKstarMin > 0.f && kstar < mKstarMin) { + return; + } + + if (mKstarMax > 0.f && kstar > mKstarMax) { + return; + } + + // fill average hist + if (mPlotAverage) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kAverage, HistTable)), mDeta, mAverageDphistar); + } + + // fill radii hists + if (mPlotAllRadii) { + if (mDphistarMask.at(0)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius0, HistTable)), mDeta, mDphistar.at(0)); + } + if (mDphistarMask.at(1)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius1, HistTable)), mDeta, mDphistar.at(1)); + } + if (mDphistarMask.at(2)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius2, HistTable)), mDeta, mDphistar.at(2)); + } + if (mDphistarMask.at(3)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius3, HistTable)), mDeta, mDphistar.at(3)); + } + if (mDphistarMask.at(4)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius4, HistTable)), mDeta, mDphistar.at(4)); + } + if (mDphistarMask.at(5)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius5, HistTable)), mDeta, mDphistar.at(5)); + } + if (mDphistarMask.at(6)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius6, HistTable)), mDeta, mDphistar.at(6)); + } + if (mDphistarMask.at(7)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius7, HistTable)), mDeta, mDphistar.at(7)); + } + if (mDphistarMask.at(8)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius8, HistTable)), mDeta, mDphistar.at(8)); + } + } + } + + bool isClosePair() const + { + if (!mIsActivated) { + return false; + } + bool isCloseAverage = false; + bool isCloseAnyRadius = false; + + if (mCutAverage) { + isCloseAverage = std::hypot((mAverageDphistar - mDphistarCenter) / mDphistarMax, (mDeta - mDetaCenter) / mDetaMax) < 1.f; + } + + if (mCutAnyRadius) { + for (size_t i = 0; i < TpcRadii.size(); i++) { + if (isCloseAnyRadius) { + break; + } + if (mDphistarMask.at(i)) { + isCloseAnyRadius = std::hypot((mDphistar.at(i) - mDphistarCenter) / mDphistarMax, (mDeta - mDetaCenter) / mDetaMax) < 1.f; + } + } + } + return isCloseAverage || isCloseAnyRadius; + } + + bool isActivated() const { return mIsActivated; } + + private: + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + bool mPlotAllRadii = false; + bool mPlotAverage = false; + + float mKstarMin = -1.f; + float mKstarMax = -1.f; + + bool mCutAverage = false; + bool mCutAnyRadius = false; + + bool mIsActivated = false; + + int mChargeAbsTrack1 = 0; + int mChargeAbsTrack2 = 0; + float mMagField = 0.f; + float mDetaMax = 0.f; + float mDphistarMax = 0.f; + float mDetaCenter = 0.f; + float mDphistarCenter = 0.f; + + float mAverageDphistar = 0.f; + float mDeta = 0.f; + std::array mDphistar = {0.f}; + std::array mDphistarMask = {false}; +}; + +template +class ClosePairRejectionTrackTrack +{ + public: + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& specs, + T const& confCpr, + int absChargeTrack1, + int absChargeTrack2) + { + mCtr.init(registry, specs, confCpr, absChargeTrack1, absChargeTrack2); + } + + void setMagField(float magField) { mCtr.setMagField(magField); } + template + void setPair(T1 const& track1, T2 const& track2, T3 const& /*tracks*/) + { + mCtr.compute(track1, track2); + } + bool isClosePair() const { return mCtr.isClosePair(); } + void fill(float kstar) { mCtr.fill(kstar); } + + private: + CloseTrackRejection mCtr; +}; + +template +class ClosePairRejectionV0V0 +{ + public: + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& specsPos, + std::map> const& specsNeg, + T1 const& confCprPos, + T2 const& confCprNeg) + { + mCtrPos.init(registry, specsPos, confCprPos, 1, 1); + mCtrNeg.init(registry, specsNeg, confCprNeg, 1, 1); + } + + void setMagField(float magField) + { + mCtrPos.setMagField(magField); + mCtrNeg.setMagField(magField); + } + + template + void setPair(T1 const& v01, T2 const& v02, T3 const& tracks) + { + auto posDau1 = tracks.rawIteratorAt(v01.posDauId() - tracks.offset()); + auto posDau2 = tracks.rawIteratorAt(v02.posDauId() - tracks.offset()); + mCtrPos.compute(posDau1, posDau2); + + auto negDau1 = tracks.rawIteratorAt(v01.negDauId() - tracks.offset()); + auto negDau2 = tracks.rawIteratorAt(v02.negDauId() - tracks.offset()); + mCtrNeg.compute(negDau1, negDau2); + } + + bool isClosePair() const { return mCtrPos.isClosePair() || mCtrNeg.isClosePair(); } + + void fill(float kstar) + { + mCtrPos.fill(kstar); + mCtrNeg.fill(kstar); + } + + private: + CloseTrackRejection mCtrPos; + CloseTrackRejection mCtrNeg; +}; + +template +class ClosePairRejectionTrackV0 // can also be used for any particle type that has pos/neg daughters, like resonances +{ + public: + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& specs, + T const& confCpr, + int absChargeTrack) + { + mCtr.init(registry, specs, confCpr, absChargeTrack, 1); + } + + void setMagField(float magField) { mCtr.setMagField(magField); } + + template + void setPair(T1 const& track, T2 const& v0, T3 const& trackTable) + { + if (track.sign() > 0) { + auto posDau = trackTable.rawIteratorAt(v0.posDauId() - trackTable.offset()); + mCtr.compute(track, posDau); + } else { + auto negDau = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); + mCtr.compute(track, negDau); + } + } + + bool isClosePair() const { return mCtr.isClosePair(); } + + void fill(float kstar) { mCtr.fill(kstar); } + + private: + CloseTrackRejection mCtr; +}; + +template +class ClosePairRejectionTrackCascade +{ + public: + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& specsBachelor, + std::map> const& specsV0Daughter, + T1 const& confCprBachelor, + T2 const& confCprV0Daughter, + int absChargeTrack) + { + mCtrBachelor.init(registry, specsBachelor, confCprBachelor, absChargeTrack, 1); + mCtrV0Daughter.init(registry, specsV0Daughter, confCprV0Daughter, absChargeTrack, 1); + } + + void setMagField(float magField) + { + mCtrBachelor.setMagField(magField); + mCtrV0Daughter.setMagField(magField); + } + + template + void setPair(T1 const& track, T2 const& cascade, T3 const& trackTable) + { + auto bachelor = trackTable.rawIteratorAt(cascade.bachelorId() - trackTable.offset()); + mCtrBachelor.compute(track, bachelor); + + if (track.sign() > 0) { + auto posDau = trackTable.rawIteratorAt(cascade.posDauId() - trackTable.offset()); + mCtrV0Daughter.compute(track, posDau); + } else { + auto negDau = trackTable.rawIteratorAt(cascade.negDauId() - trackTable.offset()); + mCtrV0Daughter.compute(track, negDau); + } + } + + bool + isClosePair() const + { + return mCtrBachelor.isClosePair() || mCtrBachelor.isClosePair(); + } + + void fill(float kstar) + { + mCtrBachelor.fill(kstar); + mCtrV0Daughter.fill(kstar); + } + + private: + CloseTrackRejection mCtrBachelor; + CloseTrackRejection mCtrV0Daughter; +}; + +template +class ClosePairRejectionTrackKink +{ + public: + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& specs, + T const& confCpr, + int absChargeTrack) + { + mCtr.init(registry, specs, confCpr, absChargeTrack, 1); + } + + void setMagField(float magField) + { + mCtr.setMagField(magField); + } + + template + void setPair(T1 const& track, T2 const& kink, T3 const& trackTable) + { + auto daughter = trackTable.rawIteratorAt(kink.chaDauId() - trackTable.offset()); + mCtr.compute(track, daughter); + } + + bool isClosePair() const { return mCtr.isClosePair(); } + void fill(float kstar) { mCtr.fill(kstar); } + + private: + CloseTrackRejection mCtr; +}; + +}; // namespace closepairrejection +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_CLOSEPAIRREJECTION_H_ diff --git a/PWGCF/Femto/Core/collisionBuilder.h b/PWGCF/Femto/Core/collisionBuilder.h new file mode 100644 index 00000000000..412f2cab555 --- /dev/null +++ b/PWGCF/Femto/Core/collisionBuilder.h @@ -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 collisionBuilder.h +/// \brief collision builder +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_CORE_COLLISIONBUILDER_H_ +#define PWGCF_FEMTO_CORE_COLLISIONBUILDER_H_ + +#include "PWGCF/Femto/Core/baseSelection.h" +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/selectionContainer.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/Zorro.h" + +#include "DataFormatsParameters/GRPMagField.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace collisionbuilder +{ + +// configurables for collision selection +struct ConfCollisionFilters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CollisionFilter"); + o2::framework::Configurable vtxZMin{"vtxZMin", -10.f, "Minimum vertex Z position (cm)"}; + o2::framework::Configurable vtxZMax{"vtxZMax", 10.f, "Maximum vertex Z position (cm)"}; + o2::framework::Configurable multMin{"multMin", 0.f, "Minimum multiplicity"}; + o2::framework::Configurable multMax{"multMax", 5000.f, "Maximum multiplicity"}; + o2::framework::Configurable centMin{"centMin", 0.f, "Minimum centrality (multiplicity percentile)"}; + o2::framework::Configurable centMax{"centMax", 100.f, "Maximum centrality (multiplicity percentile)"}; + o2::framework::Configurable sphericityMin{"sphericityMin", 0.f, "Minimum sphericity"}; + o2::framework::Configurable sphericityMax{"sphericityMax", 1.f, "Maximum sphericity"}; + o2::framework::Configurable magFieldMin{"magFieldMin", -5, "Minimum magnetic field strength (kG)"}; + o2::framework::Configurable magFieldMax{"magFieldMax", 5, "Maximum magnetic field strength (kG)"}; +}; + +struct ConfCollisionBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CollisionBits"); + o2::framework::Configurable sel8{"sel8", 1, "Use sel8 (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable noSameBunchPileup{"noSameBunchPileup", 0, "Reject collisions in case of pileup with another collision in the same foundBC (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable isVertexItsTpc{"isVertexItsTpc", 0, "At least one ITS-TPC track found for the vertex (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable isGoodZvtxFt0VsPv{"isGoodZvtxFt0VsPv", 0, "small difference between z-vertex from PV and from FT0 (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable noCollInTimeRangeNarrow{"noCollInTimeRangeNarrow", 0, "no other collisions in specified time range (narrower than Strict)(-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable noCollInTimeRangeStrict{"noCollInTimeRangeStrict", 0, "no other collisions in specified time range strict (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable noCollInTimeRangeStandard{"noCollInTimeRangeStandard", 0, "no other collisions in specified time range with per-collision multiplicity above threshold (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable noCollInRofStrict{"noCollInRofStrict", 0, "no other collisions in this Readout Frame strict (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable noCollInRofStandard{"noCollInRofStandard", 0, "no other collisions in this Readout Frame with per-collision multiplicity above threshold (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable noHighMultCollInPrevRof{"noHighMultCollInPrevRof", 0, "veto an event if FT0C amplitude in previous ITS ROF is above threshold (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable isGoodItsLayer3{"isGoodItsLayer3", 0, "number of inactive chips on ITS layer 3 is below maximum allowed value (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable isGoodItsLayer0123{"isGoodItsLayer0123", 0, "numbers of inactive chips on ITS layers 0-3 are below maximum allowed values (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable isGoodItsLayersAll{"isGoodItsLayersAll", 0, "numbers of inactive chips on all ITS layers are below maximum allowed values (-1: stored in bitmaks; 0 off; 1 on)"}; + o2::framework::Configurable> occupancyMin{"occupancyMin", {}, "Minimum occpancy"}; + o2::framework::Configurable> occupancyMax{"occupancyMax", {}, "Maximum occpancy"}; + o2::framework::Configurable> sphericityMin{"sphericityMin", {}, "Minimum sphericity"}; + o2::framework::Configurable> sphericityMax{"sphericityMax", {}, "Maximum sphericity"}; + o2::framework::Configurable> triggers{"triggers", {}, "List of all triggers to be used"}; +}; + +struct ConfCcdb : o2::framework::ConfigurableGroup { + std::string prefix = std::string("ConfCcdb"); + o2::framework::Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "URL to ccdb"}; + o2::framework::Configurable grpPath{"grpPath", "GLO/Config/GRPMagField", "Path to GRP object (Run3 -> GLO/Config/GRPMagField/Run2 -> GLO/GRP/GRP"}; + o2::framework::Configurable triggerPath{"triggerPath", "EventFiltering/Zorro/", "CCDB path for trigger information"}; +}; + +struct ConfCollisionRctFlags : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CollisionRctFlags"); + o2::framework::Configurable useRctFlags{"useRctFlags", true, "Set to true to use RCT flags"}; + o2::framework::Configurable label{"label", std::string("CBT_hadronPID"), "Which RCT flag to check"}; + o2::framework::Configurable useZdc{"useZdc", false, "Whether to use ZDC (only use for PbPb)"}; + o2::framework::Configurable treatLimitedAcceptanceAsBad{"treatLimitedAcceptanceAsBad", false, "Whether to treat limited acceptance as bad or not"}; +}; + +// configurables for collision selection +struct ConfCollisionSelection : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CollisionSelection"); + o2::framework::Configurable vtxZMin{"vtxZMin", -10.f, "Minimum vertex Z position (cm)"}; + o2::framework::Configurable vtxZMax{"vtxZMax", 10.f, "Maximum vertex Z position (cm)"}; + o2::framework::Configurable multMin{"multMin", 0.f, "Minimum multiplicity"}; + o2::framework::Configurable multMax{"multMax", 5000.f, "Maximum multiplicity"}; + o2::framework::Configurable centMin{"centMin", 0.f, "Minimum centrality (multiplicity percentile)"}; + o2::framework::Configurable centMax{"centMax", 100.f, "Maximum centrality (multiplicity percentile)"}; + o2::framework::Configurable magFieldMin{"magFieldMin", -5, "Minimum magnetic field strength (kG)"}; + o2::framework::Configurable magFieldMax{"magFieldMax", 5, "Maximum magnetic field strength (kG)"}; + o2::framework::Configurable collisionMask{"collisionMask", 0x0, "Bitmask for collision"}; +}; + +/// enum for all collision selections +enum CollisionSels { + // collsion selection flags + kSel8, ///< Sel8 + kNoSameBunchPileUp, ///< Reject collisions in case of pileup with another collision in the same foundBC + kIsVertexItsTpc, ///< At least one ITS-TPC track found for the vertex + kIsGoodZvtxFt0VsPv, ///< small difference between z-vertex from PV and from FT0 + kNoCollInTimeRangeNarrow, ///< no other collisions in specified time range (narrower than Strict) + kNoCollInTimeRangeStrict, ///< no other collisions in specified time range strict + kNoCollInTimeRangeStandard, ///< no other collisions in specified time range + kNoCollInRofStrict, ///< no other collisions in this Readout Frame strict + kNoCollInRofStandard, ///< no other collisions in this Readout Frame + 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 + kOccupancyMin, ///< Min. occupancy + kOccupancyMax, ///< Max. occupancy + kSphericityMin, ///< Min. sphericity + kSphericityMax, ///< Max. sphericity + + kTriggers, + + kCollisionSelsMax +}; + +constexpr char ColSelHistName[] = "hCollisionSelection"; +const char colSelsName[] = "Collision Selection Object"; +const std::unordered_map collisionSelectionNames = { + {kSel8, "Sel8"}, + {kNoSameBunchPileUp, "No same bunch pileup"}, + {kIsVertexItsTpc, "Is vertex ITS TPC"}, + {kIsGoodZvtxFt0VsPv, "Is good zvtx FT0 vs PV"}, + {kNoCollInTimeRangeNarrow, "No collision in time range narrow"}, + {kNoCollInTimeRangeStrict, "No collision in time range strict"}, + {kNoCollInTimeRangeStandard, "No collission in time range standard"}, + {kNoCollInRofStrict, "No collsion in ROF strict"}, + {kNoCollInRofStandard, "No collision in ROF standard"}, + {kNoHighMultCollInPrevRof, "No high mult collsions in previous ROF"}, + {kIsGoodItsLayer3, "Is good ITS layer 3"}, + {kIsGoodItsLayer0123, "Is good ITS layer 0-3"}, + {kIsGoodItsLayersAll, "Is good ITS layer all"}, + {kOccupancyMin, "Minimum Occupancy"}, + {kOccupancyMax, "Maximum Occupancy"}, + {kSphericityMin, "Minimum Sphericity"}, + {kSphericityMax, "Maximum Sphericity"}, + + {kTriggers, "Triggers"} + +}; + +template +class CollisionSelection : public BaseSelection +{ + public: + CollisionSelection() = default; + ~CollisionSelection() = default; + + template + void configure(o2::framework::HistogramRegistry* registry, T1 const& filter, T2 const& config) + { + // cuts + mVtxZMin = filter.vtxZMin.value; + mVtxZMax = filter.vtxZMax.value; + mMagFieldMin = filter.magFieldMin.value; + mMagFieldMax = filter.magFieldMax.value; + mMultMin = filter.multMin.value; + mMultMax = filter.multMax.value; + mCentMin = filter.centMin.value; + mCentMax = filter.centMax.value; + mSphericityMin = filter.sphericityMin.value; + mSphericityMax = filter.sphericityMax.value; + + // flags + this->addSelection(kSel8, collisionSelectionNames.at(kSel8), config.sel8.value); + this->addSelection(kNoSameBunchPileUp, collisionSelectionNames.at(kNoSameBunchPileUp), config.noSameBunchPileup.value); + this->addSelection(kIsGoodZvtxFt0VsPv, collisionSelectionNames.at(kIsGoodZvtxFt0VsPv), config.isGoodZvtxFt0VsPv.value); + this->addSelection(kNoCollInTimeRangeNarrow, collisionSelectionNames.at(kNoCollInTimeRangeNarrow), config.noCollInTimeRangeNarrow.value); + this->addSelection(kNoCollInTimeRangeStrict, collisionSelectionNames.at(kNoCollInTimeRangeStrict), config.noCollInTimeRangeStrict.value); + this->addSelection(kNoCollInTimeRangeStandard, collisionSelectionNames.at(kNoCollInTimeRangeStandard), config.noCollInTimeRangeStandard.value); + this->addSelection(kNoCollInRofStrict, collisionSelectionNames.at(kNoCollInRofStrict), config.noCollInRofStrict.value); + this->addSelection(kNoCollInRofStandard, collisionSelectionNames.at(kNoCollInRofStandard), config.noCollInRofStandard.value); + this->addSelection(kNoHighMultCollInPrevRof, collisionSelectionNames.at(kNoHighMultCollInPrevRof), config.noHighMultCollInPrevRof.value); + this->addSelection(kIsGoodItsLayer3, collisionSelectionNames.at(kIsGoodItsLayer3), config.isGoodItsLayer3.value); + this->addSelection(kIsGoodItsLayer0123, collisionSelectionNames.at(kIsGoodItsLayer0123), config.isGoodItsLayer0123.value); + this->addSelection(kIsGoodItsLayersAll, collisionSelectionNames.at(kIsGoodItsLayersAll), config.isGoodItsLayersAll.value); + this->addSelection(kOccupancyMin, collisionSelectionNames.at(kOccupancyMin), config.occupancyMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kOccupancyMax, collisionSelectionNames.at(kOccupancyMax), config.occupancyMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kSphericityMin, collisionSelectionNames.at(kSphericityMin), config.sphericityMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kSphericityMax, collisionSelectionNames.at(kSphericityMax), config.sphericityMax.value, limits::kUpperLimit, true, true, false); + + std::vector triggerValues(config.triggers.value.size(), 1.f); + this->addSelection(kTriggers, collisionSelectionNames.at(kTriggers), triggerValues, limits::kEqualArray, false, false, true); + this->addComments(kTriggers, config.triggers.value); + + this->setupContainers(registry); + }; + + void setMagneticField(int MagField) + { + mMagField = MagField; + } + + float getMagneticField() + { + return mMagField; + } + + template + void setSphericity(T tracks) + { + mSphericity = utils::sphericity(tracks); + } + + float getSphericity() const { return mSphericity; } + + template + void setCentrality(const T& col) + { + if constexpr (modes::isFlagSet(system, modes::System::kPP)) { + mCentrality = col.centFT0M(); + } + if constexpr (modes::isFlagSet(system, modes::System::kPbPb)) { + mCentrality = col.centFT0C(); + } + } + float getCentrality() const { return mCentrality; } + + template + void setMultiplicity(const T& col) + { + if constexpr (modes::isFlagSet(system, modes::System::kPP)) { + mMultiplicity = col.multNTracksPV(); + } + if constexpr (modes::isFlagSet(system, modes::System::kPbPb)) { + // change multiplicity estimator for PbPb? + mMultiplicity = col.multNTracksPV(); + } + } + float getMultiplicity() const { return mMultiplicity; } + + template + bool checkFilters(T const& col) const + { + if (col.posZ() < mVtxZMin || col.posZ() > mVtxZMax) { + return false; + } + if (mMultiplicity < mMultMin || mMultiplicity > mMultMax) { + return false; + } + if (mCentrality < mCentMin || mCentrality > mCentMax) { + return false; + } + if (mMagField < mMagFieldMin || mMagField > mMagFieldMax) { + return false; + } + if (mSphericity < mSphericityMin || mSphericity > mSphericityMax) { + return false; + } + return true; + } + + template + void applySelections(T const& col, std::vector const& triggerDecisions) + { + this->reset(); + + // casting bool to float gurantees false -> 0 and true -> 1 + // and we check for equality to 1, so evaluation succeeds if the selection bit is true + this->evaluateObservable(kSel8, static_cast(col.sel8())); + this->evaluateObservable(kNoSameBunchPileUp, static_cast(col.selection_bit(o2::aod::evsel::kNoSameBunchPileup))); + this->evaluateObservable(kIsVertexItsTpc, static_cast(col.selection_bit(o2::aod::evsel::kIsVertexITSTPC))); + this->evaluateObservable(kIsGoodZvtxFt0VsPv, static_cast(col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))); + this->evaluateObservable(kNoCollInTimeRangeNarrow, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow))); + this->evaluateObservable(kNoCollInTimeRangeStrict, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict))); + this->evaluateObservable(kNoCollInRofStrict, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInRofStrict))); + this->evaluateObservable(kNoCollInRofStandard, static_cast(col.selection_bit(o2::aod::evsel::kNoCollInRofStandard))); + this->evaluateObservable(kNoHighMultCollInPrevRof, static_cast(col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof))); + this->evaluateObservable(kIsGoodItsLayer3, static_cast(col.selection_bit(o2::aod::evsel::kIsGoodITSLayer3))); + this->evaluateObservable(kIsGoodItsLayer0123, static_cast(col.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123))); + this->evaluateObservable(kIsGoodItsLayersAll, static_cast(col.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))); + + this->evaluateObservable(kOccupancyMin, col.trackOccupancyInTimeRange()); + this->evaluateObservable(kOccupancyMax, col.trackOccupancyInTimeRange()); + this->evaluateObservable(kSphericityMin, mSphericity); + this->evaluateObservable(kSphericityMax, mSphericity); + + // for the trigger we need to pass an vector of 0 (false) and 1 (true) for all configured trigger selections + if (!triggerDecisions.empty()) { + std::vector trigger(triggerDecisions.size()); + std::transform(triggerDecisions.begin(), triggerDecisions.end(), trigger.begin(), [](bool b) { return b ? 1.0f : 0.0f; }); + this->evaluateObservable(kTriggers, trigger); + } + + this->assembleBitmask(); + }; + + protected: + // filter cuts + float mVtxZMin = -12.f; + float mVtxZMax = -12.f; + float mSphericityMin = 0.f; + float mSphericityMax = 1.f; + float mMagFieldMin = -5.f; + float mMagFieldMax = 5.f; + float mMultMin = 0.f; + float mMultMax = 5000.f; + float mCentMin = 0.f; + float mCentMax = 100.f; + + int mMagField = 0.f; + float mSphericity = 0.f; + float mCentrality = 0.f; + float mMultiplicity = 0.f; +}; + +struct CollisionBuilderProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedCollision; + o2::framework::Produces producedCollisionMask; + o2::framework::Produces producedPositions; + o2::framework::Produces producedSphericities; + o2::framework::Produces producedMultiplicityEstimators; + o2::framework::Produces producedCentralityEstimators; + o2::framework::Produces producedQns; +}; + +struct ConfCollisionTables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CollisionTables"); + o2::framework::Configurable produceCollisions{"produceCollisions", -1, "Produce Collisions (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceCollisionMasks{"produceCollisionMasks", -1, "Produce Collision Masks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable producePositions{"producePositions", -1, "Produce Positions (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceSphericities{"produceSphericities", -1, "Produce Sphericity (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceMults{"produceMults", -1, "Produce Multiplicities (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceCents{"produceCents", -1, "Produce Centralities (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceQns{"produceQns", -1, "Produce Qn (-1: auto; 0 off; 1 on)"}; +}; + +template +class CollisionBuilder +{ + public: + CollisionBuilder() = default; + ~CollisionBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, T1& confFilter, T2& confBits, T3& confRct, T4& confCcdb, T5& confTable, T6& initContext) + { + LOG(info) << "Initialize femto collision builder..."; + mProducedCollisions = utils::enableTable("FCols_001", confTable.produceCollisions.value, initContext); + mProducedCollisionMasks = utils::enableTable("FColMasks_001", confTable.produceCollisionMasks.value, initContext); + mProducedPositions = utils::enableTable("FColPos_001", confTable.producePositions.value, initContext); + mProducedSphericities = utils::enableTable("FColSphericities_001", confTable.produceSphericities.value, initContext); + mProducedMultiplicities = utils::enableTable("FColMults_001", confTable.produceMults.value, initContext); + mProducedCentralities = utils::enableTable("FColCents_001", confTable.produceCents.value, initContext); + mProduceQns = utils::enableTable("FColQnBins_001", confTable.produceQns.value, initContext); + if (mProducedCollisions || mProducedCollisionMasks || mProducedPositions || mProducedSphericities || mProducedMultiplicities || mProducedCentralities) { + mFillAnyTable = true; + } else { + LOG(info) << "No tables configured, Selection object will not be configured..."; + LOG(info) << "Initialization done..."; + return; + } + + if (!confBits.triggers.value.empty()) { + mUseTrigger = true; + for (size_t i = 0; i < confBits.triggers.value.size(); ++i) { + mTriggerNames += confBits.triggers.value[i]; + if (i != confBits.triggers.value.size() - 1) { + mTriggerNames += ","; + } + } + mZorro.setBaseCCDBPath(confCcdb.triggerPath.value); + } + if (confRct.useRctFlags.value) { + mUseRctFlags = true; + mRctFlagsChecker.init(confRct.label.value, confRct.useZdc.value, confRct.treatLimitedAcceptanceAsBad.value); + } + mGrpPath = confCcdb.grpPath.value; + + mCollisionSelection.configure(registry, confFilter, confBits); + mCollisionSelection.printSelections(colSelsName); + LOG(info) << "Initialization done..."; + } + + template + void initCollision(T1& bc, T2& col, T3& tracks, T4& ccdb, T5& histRegistry) + { + if (mRunNumber != bc.runNumber()) { + mRunNumber = bc.runNumber(); + static o2::parameters::GRPMagField* grpo = nullptr; + grpo = ccdb->template getForRun(mGrpPath, mRunNumber); + if (grpo == nullptr) { + LOG(fatal) << "GRP object not found for Run " << mRunNumber; + } + mMagField = static_cast(grpo->getNominalL3Field()); // get magnetic field in kG + + if (mUseTrigger) { + mZorro.initCCDB(ccdb.service, mRunNumber, bc.timestamp(), mTriggerNames); + mZorro.populateHistRegistry(histRegistry, mRunNumber); + } + } + + mCollisionSelection.setMagneticField(mMagField); + mCollisionSelection.setSphericity(tracks); + mCollisionSelection.template setMultiplicity(col); + mCollisionSelection.template setCentrality(col); + + std::vector triggerDecisions = {}; + if (mUseTrigger) { + triggerDecisions = mZorro.getTriggerOfInterestResults(bc.globalBC()); + } + + mCollisionSelection.applySelections(col, triggerDecisions); + } + + template + bool checkCollision(T1 const& col) + { + // check RCT flags first + if (mUseRctFlags && !mRctFlagsChecker(col)) { + return false; + } + // make other checks + return mCollisionSelection.checkFilters(col) && + mCollisionSelection.passesAllRequiredSelections(); + } + + template + void fillCollision(T1& collisionProducts, T2 const& col) + { + if (!mFillAnyTable) { + return; + } + + if (mCollisionAleadyFilled) { + return; + } + + if (mProducedCollisions) { + collisionProducts.producedCollision(col.posZ(), + col.multNTracksPV(), + mCollisionSelection.getCentrality(), + static_cast(mCollisionSelection.getMagneticField())); + } + if (mProducedCollisionMasks) { + collisionProducts.producedCollisionMask(mCollisionSelection.getBitmask()); + } + if (mProducedPositions) { + collisionProducts.producedPositions(col.posX(), + col.posY()); + } + if (mProducedSphericities) { + collisionProducts.producedSphericities(mCollisionSelection.getSphericity()); + } + if (mProducedMultiplicities) { + collisionProducts.producedMultiplicityEstimators( + col.multFT0A(), + col.multFT0C(), + col.multNTracksPVeta1(), + col.multNTracksPVetaHalf(), + col.trackOccupancyInTimeRange(), + col.ft0cOccupancyInTimeRange()); + } + if (mProducedCentralities) { + collisionProducts.producedCentralityEstimators( + col.centFT0A(), + col.centFT0C()); + } + + // PbPb specific columns + if constexpr (modes::isFlagSet(system, modes::System::kPbPb)) { + if (mProduceQns) { + collisionProducts.producedQns(utils::qn(col)); + } + } + + mCollisionAleadyFilled = true; + } + + void reset() + { + mCollisionAleadyFilled = false; + } + + private: + CollisionSelection mCollisionSelection; + bool mCollisionAleadyFilled = false; + Zorro mZorro; + bool mUseTrigger = false; + int mRunNumber = -1; + std::string mGrpPath = std::string(""); + int mMagField = 0; + aod::rctsel::RCTFlagsChecker mRctFlagsChecker; + bool mUseRctFlags = false; + std::string mTriggerNames = std::string(""); + bool mFillAnyTable = false; + bool mProducedCollisions = false; + bool mProducedCollisionMasks = false; + bool mProducedPositions = false; + bool mProducedSphericities = false; + bool mProducedMultiplicities = false; + bool mProducedCentralities = false; + bool mProduceQns = false; +}; + +struct CollisionBuilderDerivedToDerivedProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedCollision; + o2::framework::Produces producedCollisionMask; +}; + +class CollisionBuilderDerivedToDerived +{ + public: + CollisionBuilderDerivedToDerived() = default; + ~CollisionBuilderDerivedToDerived() = default; + + template + void processCollision(T1& col, T2& newCollisionTable) + { + newCollisionTable.producedCollision(col.posZ(), + col.mult(), + col.cent(), + col.magField()); + newCollisionTable.producedCollisionMask(col.mask()); + } +}; + +} // namespace collisionbuilder +} // namespace o2::analysis::femto +; +#endif // PWGCF_FEMTO_CORE_COLLISIONBUILDER_H_ diff --git a/PWGCF/Femto/Core/collisionHistManager.h b/PWGCF/Femto/Core/collisionHistManager.h new file mode 100644 index 00000000000..0cadaa6e380 --- /dev/null +++ b/PWGCF/Femto/Core/collisionHistManager.h @@ -0,0 +1,226 @@ +// 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 collisionHistManager.h +/// \brief collision histogram manager +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_COLLISIONHISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_COLLISIONHISTMANAGER_H_ + +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" + +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace colhistmanager +{ + +enum ColHist { + kPosZ, + kMult, + kCent, + kMagField, + // qa + kPosX, + kPosY, + kPos, + kOccupancy, + kSphericity, + // 2d + kPoszVsMult, + kPoszVsCent, + kCentVsMult, + kCentVsSphericity, + kMultVsSphericity, + kColHistLast +}; + +constexpr std::string_view ColAnalysisDir = "Collisions/Analysis/"; +constexpr std::string_view ColQaDir = "Collisions/QA/"; + +constexpr std::array, kColHistLast> HistTable = { + { + {kPosZ, o2::framework::kTH1F, "hPosZ", "Vertex Z; V_{Z} (cm); Entries"}, + {kMult, o2::framework::kTH1F, "hMult", "Multiplicity; Multiplicity; Entries"}, + {kCent, o2::framework::kTH1F, "hCent", "Centrality; Centrality (%); Entries"}, + {kMagField, o2::framework::kTH1F, "hMagField", "Magnetic Field; B (kG); Entries"}, + {kPosX, o2::framework::kTH1F, "hPosX", "Vertex X; V_{X} (cm); Entries"}, + {kPosY, o2::framework::kTH1F, "hPosY", "Vertex Z; V_{Y} (cm); Entries"}, + {kPos, o2::framework::kTH1F, "hPos", "Primary vertex; V_{pos} (cm); Entries"}, + {kSphericity, o2::framework::kTH1F, "hSphericity", "Sphericity; Sphericity; Entries"}, + {kOccupancy, o2::framework::kTH1F, "hOccupancy", "Occupancy; Occupancy; Entries"}, + {kPoszVsMult, o2::framework::kTH2F, "hPoszVsMult", "Vertex Z vs Multiplicity; V_{Z} (cm); Multiplicity"}, + {kPoszVsCent, o2::framework::kTH2F, "hPoszVsCent", "Vertex Z vs Centrality; V_{Z} (cm); Centrality (%)"}, + {kCentVsMult, o2::framework::kTH2F, "hCentVsMult", "Centrality vs Multiplicity; Centrality (%); Multiplicity"}, + {kMultVsSphericity, o2::framework::kTH2F, "hMultVsSphericity", "Multiplicity vs Sphericity; Multiplicity; Sphericity"}, + {kCentVsSphericity, o2::framework::kTH2F, "hCentVsSphericity", "Centrality vs Sphericity; Centrality (%); Sphericity"}, + }}; + +template +auto makeColHistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + {kPosZ, {confBinningAnalysis.vtxZ}}, + {kMult, {confBinningAnalysis.mult}}, + {kCent, {confBinningAnalysis.cent}}, + {kMagField, {confBinningAnalysis.magField}}}; +} + +template +auto makeColQaHistSpecMap(const T1& confBinningAnalysis, const T2& confBinningQa) +{ + return std::map>{ + {kPosZ, {confBinningAnalysis.vtxZ}}, + {kMult, {confBinningAnalysis.mult}}, + {kCent, {confBinningAnalysis.cent}}, + {kMagField, {confBinningAnalysis.magField}}, + {kPosX, {confBinningQa.vtxXY}}, + {kPosY, {confBinningQa.vtxXY}}, + {kPos, {confBinningQa.vtx}}, + {kSphericity, {confBinningQa.sphericity}}, + {kOccupancy, {confBinningQa.occupancy}}, + {kPoszVsMult, {confBinningAnalysis.vtxZ, confBinningAnalysis.mult}}, + {kPoszVsCent, {confBinningAnalysis.vtxZ, confBinningAnalysis.cent}}, + {kCentVsMult, {confBinningAnalysis.cent, confBinningAnalysis.mult}}, + {kMultVsSphericity, {confBinningAnalysis.mult, confBinningQa.sphericity}}, + {kCentVsSphericity, {confBinningAnalysis.cent, confBinningQa.sphericity}}}; +} + +struct ConfCollisionBinning : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CollisionBinning"); + o2::framework::ConfigurableAxis vtxZ{"vtxZ", {200, -10, 10}, "Vertex Z binning"}; + o2::framework::ConfigurableAxis mult{"mult", {200, 0, 200}, "Multiplicity binning"}; + o2::framework::ConfigurableAxis cent{"cent", {100, 0.0f, 100.0f}, "Centrality (multiplicity percentile) binning"}; + o2::framework::ConfigurableAxis magField{"magField", {11, -5.5, 5.5}, "Magnetic field binning"}; +}; + +struct ConfCollisionQaBinning : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CollisionQaBinning"); + o2::framework::Configurable plot2d{"plot2d", true, "Enable 2d QA histograms"}; + o2::framework::ConfigurableAxis vtx{"vtx", {120, 0.f, 12.f}, "Vertex position binning"}; + o2::framework::ConfigurableAxis vtxXY{"vtxXY", {100, -1.f, 1.f}, "Vertex X/Y binning"}; + o2::framework::ConfigurableAxis sphericity{"sphericity", {100, 0.f, 1.f}, "Spericity Binning"}; + o2::framework::ConfigurableAxis occupancy{"occupancy", {500, 0.f, 5000.f}, "Spericity Binning"}; +}; + +template +class CollisionHistManager +{ + public: + CollisionHistManager() = default; + ~CollisionHistManager() = default; + /// Initializes histograms for the task + /// \param registry Histogram registry to be passed + void init(o2::framework::HistogramRegistry* registry, std::map> const& Specs) + { + mHistogramRegistry = registry; + if constexpr (isFlagSet(mode, modes::Mode::kAnalysis)) { + initAnalysis(Specs); + } + if constexpr (isFlagSet(mode, modes::Mode::kQa)) { + initQa(Specs); + } + } + + template + void enableOptionalHistograms(T const& ConfBinningQa) + { + mPlot2d = ConfBinningQa.plot2d.value; + } + + template + void init(o2::framework::HistogramRegistry* registry, std::map> const& Specs, T const& ConfBinningQa) + { + enableOptionalHistograms(ConfBinningQa); + init(registry, Specs); + } + + template + void fill(T const& col) + { + if constexpr (isFlagSet(mode, modes::Mode::kAnalysis)) { + fillAnalysis(col); + } + if constexpr (isFlagSet(mode, modes::Mode::kQa)) { + fillQa(col); + } + } + + private: + void initAnalysis(std::map> const& Specs) + { + std::string analysisDir = std::string(ColAnalysisDir); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPosZ, HistTable), getHistDesc(kPosZ, HistTable), getHistType(kPosZ, HistTable), {Specs.at(kPosZ)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMult, HistTable), getHistDesc(kMult, HistTable), getHistType(kMult, HistTable), {Specs.at(kMult)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kCent, HistTable), getHistDesc(kCent, HistTable), getHistType(kCent, HistTable), {Specs.at(kCent)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMagField, HistTable), getHistDesc(kMagField, HistTable), getHistType(kMagField, HistTable), {Specs.at(kMagField)}); + } + + void initQa(std::map> const& Specs) + { + std::string qaDir = std::string(ColQaDir); + mHistogramRegistry->add(qaDir + getHistNameV2(kPosX, HistTable), getHistDesc(kPosX, HistTable), getHistType(kPosX, HistTable), {Specs.at(kPosX)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPosY, HistTable), getHistDesc(kPosY, HistTable), getHistType(kPosY, HistTable), {Specs.at(kPosY)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPos, HistTable), getHistDesc(kPos, HistTable), getHistType(kPos, HistTable), {Specs.at(kPos)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kSphericity, HistTable), getHistDesc(kSphericity, HistTable), getHistType(kSphericity, HistTable), {Specs.at(kSphericity)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kOccupancy, HistTable), getHistDesc(kOccupancy, HistTable), getHistType(kOccupancy, HistTable), {Specs.at(kOccupancy)}); + if (mPlot2d) { + mHistogramRegistry->add(qaDir + getHistNameV2(kPoszVsMult, HistTable), getHistDesc(kPoszVsMult, HistTable), getHistType(kPoszVsMult, HistTable), {Specs.at(kPoszVsMult)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPoszVsCent, HistTable), getHistDesc(kPoszVsCent, HistTable), getHistType(kPoszVsCent, HistTable), {Specs.at(kPoszVsCent)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kCentVsMult, HistTable), getHistDesc(kCentVsMult, HistTable), getHistType(kCentVsMult, HistTable), {Specs.at(kCentVsMult)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMultVsSphericity, HistTable), getHistDesc(kMultVsSphericity, HistTable), getHistType(kMultVsSphericity, HistTable), {Specs.at(kMultVsSphericity)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kCentVsSphericity, HistTable), getHistDesc(kCentVsSphericity, HistTable), getHistType(kCentVsSphericity, HistTable), {Specs.at(kCentVsSphericity)}); + } + } + + template + void fillAnalysis(T const& col) + { + mHistogramRegistry->fill(HIST(ColAnalysisDir) + HIST(getHistName(kPosZ, HistTable)), col.posZ()); + mHistogramRegistry->fill(HIST(ColAnalysisDir) + HIST(getHistName(kMult, HistTable)), col.mult()); + mHistogramRegistry->fill(HIST(ColAnalysisDir) + HIST(getHistName(kCent, HistTable)), col.cent()); + mHistogramRegistry->fill(HIST(ColAnalysisDir) + HIST(getHistName(kMagField, HistTable)), col.magField()); + } + + template + void fillQa(T const& col) + { + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kPosX, HistTable)), col.posX()); + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kPosY, HistTable)), col.posY()); + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kPos, HistTable)), std::hypot(col.posX(), col.posY(), col.posZ())); + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kSphericity, HistTable)), col.sphericity()); + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kOccupancy, HistTable)), col.trackOccupancyInTimeRange()); + if (mPlot2d) { + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kPoszVsMult, HistTable)), col.posZ(), col.mult()); + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kPoszVsCent, HistTable)), col.posZ(), col.cent()); + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kCentVsMult, HistTable)), col.cent(), col.mult()); + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kMultVsSphericity, HistTable)), col.mult(), col.sphericity()); + mHistogramRegistry->fill(HIST(ColQaDir) + HIST(getHistName(kCentVsSphericity, HistTable)), col.cent(), col.sphericity()); + } + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + bool mPlot2d = true; +}; // namespace femtounitedcolhistmanager +}; // namespace colhistmanager +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_COLLISIONHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/dataTypes.h b/PWGCF/Femto/Core/dataTypes.h new file mode 100644 index 00000000000..6a1dd58da37 --- /dev/null +++ b/PWGCF/Femto/Core/dataTypes.h @@ -0,0 +1,63 @@ +// 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 dataTypes.h +/// \brief datatypes for bitmasks +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_DATATYPES_H_ +#define PWGCF_FEMTO_CORE_DATATYPES_H_ + +#include + +namespace o2::aod +{ +namespace femtodatatypes +{ +// Note: Length of the bitmask is the limit of how many selections can be configured + +// datatypes for collsions +using CollisionTagType = uint64_t; +using CollisionMaskType = uint16_t; + +// datatypes for tracks +using TrackMaskType = uint64_t; +using TrackType = uint16_t; + +// datatypes for v0s +using V0MaskType = uint16_t; +using V0Type = uint16_t; + +// datatypes for kinks +using KinkMaskType = uint32_t; +using KinkType = uint8_t; + +// datatypes for two track resonances +using TwoTrackResonanceMaskType = uint32_t; +// two track resonance types +using TwoTrackResonanceType = uint16_t; + +// datatypes for cascades +using CascadeMaskType = uint16_t; +using CascadeType = uint16_t; + +// datatype for particles +using ParticleType = uint16_t; + +// datatypes for different observables +using MomentumType = uint16_t; +using TransverseMassType = uint16_t; + +} // namespace femtodatatypes + +} // namespace o2::aod + +#endif // PWGCF_FEMTO_CORE_DATATYPES_H_ diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h new file mode 100644 index 00000000000..28c380adb27 --- /dev/null +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -0,0 +1,212 @@ +// 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 femtoUtils.h +/// \brief Collision selection +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_CORE_FEMTOUTILS_H_ +#define PWGCF_FEMTO_CORE_FEMTOUTILS_H_ + +#include "RecoDecay.h" + +#include "Common/Core/TableHelper.h" + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/InitContext.h" + +#include "TPDGCode.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace utils +{ + +template +inline std::optional getIndex(const T1& index, const std::unordered_map& map) +{ + auto it = map.find(index); + if (it != map.end()) { + return it->second; + } + return std::nullopt; +} + +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 = clSizeLayer0 + clSizeLayer1 + clSizeLayer2 + clSizeLayer3 + clSizeLayer4 + clSizeLayer5 + clSizeLayer6; + float cosLamnda = 1. / std::cosh(track.eta()); + return (static_cast(sumClusterSizes) / numLayers) * cosLamnda; +}; + +template +float sphericity(T const& tracks) +{ + + int minNumberTracks = 2; + float maxSphericity = 2.f; + + if (tracks.size() <= minNumberTracks) { + return maxSphericity; + } + + // Initialize the transverse momentum tensor components + float sxx = 0.f; + float syy = 0.f; + float sxy = 0.f; + float sumPt = 0.f; + + // Loop over the tracks to compute the tensor components + for (const auto& track : tracks) { + sxx += (track.px() * track.px()) / track.pt(); + syy += (track.py() * track.py()) / track.pt(); + sxy += (track.px() * track.py()) / track.pt(); + sumPt += track.pt(); + } + sxx /= sumPt; + syy /= sumPt; + sxy /= sumPt; + + // Compute the eigenvalues (real values) + float lambda1 = ((sxx + syy) + std::sqrt((sxx + syy) * (sxx + syy) - 4 * (sxx * syy - sxy * sxy))) / 2; + float lambda2 = ((sxx + syy) - std::sqrt((sxx + syy) * (sxx + syy) - 4 * (sxx * syy - sxy * sxy))) / 2; + + if (lambda1 <= 0.f || lambda2 <= 0.f) { + return maxSphericity; + } + + // Compute sphericity + return 2.f * lambda2 / (lambda1 + lambda2); +} + +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.f; + // add new particles if necessary here + switch (std::abs(pdgCode)) { + 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 kLambda0: + mass = o2::constants::physics::MassLambda; + break; + case o2::constants::physics::Pdg::kPhi: + mass = o2::constants::physics::MassPhi; + break; + case kRho770_0: + mass = 775.26; // not defined in O2? + break; + case kRho770Plus: + mass = 775.11; // not defined in O2? + break; + case o2::constants::physics::Pdg::kK0Star892: + mass = o2::constants::physics::MassK0Star892; + break; + 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; + case kSigmaMinus: + mass = o2::constants::physics::MassSigmaMinus; + break; + case kSigmaPlus: + mass = o2::constants::physics::MassSigmaPlus; + break; + case kXiMinus: + mass = o2::constants::physics::MassXiMinus; + break; + case kOmegaMinus: + mass = o2::constants::physics::MassOmegaMinus; + break; + default: + LOG(fatal) << "PDG code is not suppored"; + } + return mass; +} + +template +float qn(T const& col) +{ + float qn = std::sqrt(col.qvecFT0CReVec()[0] * col.qvecFT0CReVec()[0] + col.qvecFT0CImVec()[0] * col.qvecFT0CImVec()[0]) * std::sqrt(col.sumAmplFT0C()); + return qn; +} + +inline std::optional dphistar(float magfield, float radius, float signedPt, float phi) +{ + float arg = 0.3f * (0.1f * magfield) * (0.01 * radius) / (2.f * signedPt); + if (std::fabs(arg) <= 1.f) { + return RecoDecay::constrainAngle(phi - std::asin(arg)); + } + return std::nullopt; +} + +inline bool enableTable(const char* tableName, int userSetting, o2::framework::InitContext& initContext) +{ + if (userSetting == 1) { + LOG(info) << "Enabled femto table (forced on): " << tableName; + return true; + } + if (userSetting == 0) { + LOG(info) << "Disabled femto table (forced off): " << tableName; + return false; + } + bool required = o2::common::core::isTableRequiredInWorkflow(initContext, tableName); + if (required) { + LOG(info) << "Enabled femto table (auto): " << tableName; + } + return required; +} + +template +using HasMass = decltype(std::declval().mass()); + +template +using HasSign = decltype(std::declval().sign()); + +}; // namespace utils +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_FEMTOUTILS_H_ diff --git a/PWGCF/Femto/Core/histManager.h b/PWGCF/Femto/Core/histManager.h new file mode 100644 index 00000000000..55630d1bb75 --- /dev/null +++ b/PWGCF/Femto/Core/histManager.h @@ -0,0 +1,78 @@ +// 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 histManager.h +/// \brief common structs for histogram managers +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_HISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_HISTMANAGER_H_ + +#include "Framework/HistogramSpec.h" + +#include +#include + +namespace o2::analysis::femto +{ +namespace histmanager +{ + +template +struct HistInfo { + Hist hist; + o2::framework::HistType histtype; + std::string_view histname; + std::string_view histdesc; +}; + +template +constexpr o2::framework::HistType getHistType(EnumType variable, const ArrayType& array) +{ + const auto it = std::find_if(array.begin(), array.end(), [=](const auto& entry) { + return entry.hist == variable; + }); + + return it != array.end() ? it->histtype : o2::framework::kUndefinedHist; +} + +template +constexpr std::string_view getHistName(EnumType variable, const ArrayType& array) +{ + auto it = std::find_if(array.begin(), array.end(), [=](const auto& entry) { + return entry.hist == variable; + }); + + return (it != array.end()) ? it->histname : std::string_view{}; +} + +template +std::string getHistNameV2(EnumType variable, const ArrayType& array) +{ + auto it = std::find_if(array.begin(), array.end(), [=](const auto& entry) { + return entry.hist == variable; + }); + + return (it != array.end()) ? std::string(it->histname) : std::string{}; +} + +template +constexpr const char* getHistDesc(EnumType variable, const ArrayType& array) +{ + auto it = std::find_if(array.begin(), array.end(), [=](const auto& entry) { + return entry.hist == variable; + }); + + return it != array.end() ? it->histdesc.data() : ""; +} +} // namespace histmanager +} // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_HISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/kinkBuilder.h b/PWGCF/Femto/Core/kinkBuilder.h new file mode 100644 index 00000000000..4152d6fcf9a --- /dev/null +++ b/PWGCF/Femto/Core/kinkBuilder.h @@ -0,0 +1,564 @@ +// 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 kinkBuilder.h +/// \brief kink builder +/// \author Anton Riedel, TU München, anton.riedel@cern.ch +/// \author Henrik Fribert, TU München, henrik.fribert@cern.ch + +#ifndef PWGCF_FEMTO_CORE_KINKBUILDER_H_ +#define PWGCF_FEMTO_CORE_KINKBUILDER_H_ + +#include "PWGCF/Femto/Core/baseSelection.h" +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/selectionContainer.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Common/Core/RecoDecay.h" + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace kinkbuilder +{ + +// filters applied in the producer task +struct ConfKinkFilters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("KinkFilters"); + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 99.f, "Maximum pT"}; + o2::framework::Configurable etaMin{"etaMin", -10.f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 10.f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + o2::framework::Configurable massMinSigma{"massMinSigma", 1.1f, "Minimum mass for Sigma hypothesis"}; + o2::framework::Configurable massMaxSigma{"massMaxSigma", 1.3f, "Maximum mass for Sigma hypothesis"}; + o2::framework::Configurable massMinSigmaPlus{"massMinSigmaPlus", 1.1f, "Minimum mass for SigmaPlus hypothesis"}; + o2::framework::Configurable massMaxSigmaPlus{"massMaxSigmaPlus", 1.3f, "Maximum mass for SigmaPlus hypothesis"}; +}; + +// selections bits for all kinks +#define KINK_DEFAULT_BITS \ + o2::framework::Configurable> kinkTopoDcaMax{"kinkTopoDcaMax", {2.0f}, "Maximum kink topological DCA"}; \ + o2::framework::Configurable> transRadMin{"transRadMin", {0.2f}, "Minimum transverse radius (cm)"}; \ + o2::framework::Configurable> transRadMax{"transRadMax", {100.f}, "Maximum transverse radius (cm)"}; \ + o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Maximum absolute pseudorapidity for daughter track"}; \ + o2::framework::Configurable> dauDcaPvMin{"dauDcaPvMin", {0.0f}, "Minimum DCA of daughter from primary vertex (cm)"}; \ + o2::framework::Configurable> mothDcaPvMax{"mothDcaPvMax", {1.0f}, "Maximum DCA of mother from primary vertex (cm)"}; \ + o2::framework::Configurable> alphaAPMin{"alphaAPMin", {-1.0f}, "Minimum Alpha_AP for Sigma candidates"}; \ + o2::framework::Configurable> alphaAPMax{"alphaAPMax", {0.0f}, "Maximum Alpha_AP for Sigma candidates"}; \ + o2::framework::Configurable> qtAPMin{"qtAPMin", {0.15f}, "Minimum qT_AP for Sigma candidates"}; \ + o2::framework::Configurable> qtAPMax{"qtAPMax", {0.2f}, "Maximum qT_AP for Sigma candidates"}; \ + o2::framework::Configurable> cosPointingAngleMin{"cosPointingAngleMin", {0.0f}, "Minimum cosine of pointing angle"}; + +// derived selection bits for sigma +struct ConfSigmaBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("SigmaBits"); + KINK_DEFAULT_BITS + o2::framework::Configurable> chaDauTpcPion{"chaDauTpcPion", {5.f}, "Maximum |nsigma_Pion| TPC for charged daughter tracks"}; +}; + +// derived selection bits for sigma plus +struct ConfSigmaPlusBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("SigmaPlusBits"); + KINK_DEFAULT_BITS + o2::framework::Configurable> chaDauTpcProton{"chaDauTpcProton", {5.f}, "Maximum |nsigma_Proton| TPC for charged daughter tracks"}; + o2::framework::Configurable> chaDauTofProton{"chaDauTofProton", {5.f}, "Maximum combined |nsigma_Proton| (TPC+TOF) for charged daughter tracks"}; + o2::framework::Configurable pidThres{"pidThres", 0.75f, "Momentum threshold for using TOF/combined pid for daughter tracks (GeV/c)"}; +}; + +#undef KINK_DEFAULT_BITS + +// base selection for analysis task for kinks +#define KINK_DEFAULT_SELECTIONS(defaultMassMin, defaultMassMax, defaultPdgCode) \ + o2::framework::Configurable pdgCode{"pdgCode", defaultPdgCode, "Kink PDG code"}; \ + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; \ + o2::framework::Configurable ptMax{"ptMax", 999.f, "Maximum pT"}; \ + o2::framework::Configurable etaMin{"etaMin", -10.f, "Minimum eta"}; \ + o2::framework::Configurable etaMax{"etaMax", 10.f, "Maximum eta"}; \ + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; \ + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; \ + o2::framework::Configurable massMin{"massMin", defaultMassMin, "Minimum invariant mass for Sigma"}; \ + o2::framework::Configurable massMax{"massMax", defaultMassMax, "Maximum invariant mass for Sigma"}; \ + o2::framework::Configurable mask{"mask", 0x0, "Bitmask for kink selection"}; + +// base selection for analysis task for sigmas +template +struct ConfSigmaSelection : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + KINK_DEFAULT_SELECTIONS(1.1, 1.3, 3112) + o2::framework::Configurable sign{"sign", -1, "Sign of the Sigma mother track (e.g. -1 for Sigma- or +1 for AntiSigma-)"}; +}; + +// base selection for analysis task for sigma plus +template +struct ConfSigmaPlusSelection : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + KINK_DEFAULT_SELECTIONS(1.1, 1.3, 3222) + o2::framework::Configurable sign{"sign", 1, "Sign of the Sigma mother track (e.g. +1 for Sigma+ or -1 for AntiSigma+)"}; +}; + +#undef KINK_DEFAULT_SELECTIONS + +constexpr const char PrefixSigmaSelection1[] = "SigmaSelection1"; +constexpr const char PrefixSigmaSelection2[] = "SigmaSelection2"; +using ConfSigmaSelection1 = ConfSigmaSelection; +using ConfSigmaSelection2 = ConfSigmaSelection; +constexpr const char PrefixSigmaPlusSelection1[] = "SigmaPlusSelection1"; +constexpr const char PrefixSigmaPlusSelection2[] = "SigmaPlusSelection2"; +using ConfSigmaPlusSelection1 = ConfSigmaPlusSelection; +using ConfSigmaPlusSelection2 = ConfSigmaPlusSelection; + +/// The different selections for kinks +enum KinkSeles { + kKinkTopoDcaMax, + kTransRadMin, + kTransRadMax, + + kDauAbsEtaMax, + kDauDcaPvMin, + kMothDcaPvMax, + + kChaDaughTpcPion, + kChaDaughTpcProton, + kChaDaughTofProton, + + kAlphaAPMin, + kAlphaAPMax, + kQtAPMin, + kQtAPMax, + kCosPointingAngleMin, + + kKinkSelsMax +}; + +constexpr char SigmaSelHistName[] = "hSigmaSelection"; +constexpr char SigmaPlusSelHistName[] = "hSigmaPlusSelection"; +const char kinkSelsName[] = "Kink selection object"; +const std::unordered_map kinkSelectionNames = { + {kKinkTopoDcaMax, "kinkTopoDcaMax"}, + {kTransRadMin, "transRadMin"}, + {kTransRadMax, "transRadMax"}, + {kDauAbsEtaMax, "dauAbsEtaMax"}, + {kDauDcaPvMin, "dauDcaPvMin"}, + {kMothDcaPvMax, "mothDcaPvMax"}, + {kChaDaughTpcPion, "chaDauTpcPion"}, + {kChaDaughTpcProton, "chaDauTpcProton"}, + {kChaDaughTofProton, "chaDauTofProton"}, + {kAlphaAPMin, "alphaAPMin"}, + {kAlphaAPMax, "alphaAPMax"}, + {kQtAPMin, "qtAPMin"}, + {kQtAPMax, "qtAPMax"}, + {kCosPointingAngleMin, "cosPointingAngleMin"}}; + +/// \class KinkCuts +/// \brief Cut class to contain and execute all cuts applied to kinks +template +class KinkSelection : public BaseSelection +{ + public: + KinkSelection() = default; + ~KinkSelection() = default; + + template + void configure(o2::framework::HistogramRegistry* registry, T1& config, T2& filter) + { + mPtMin = filter.ptMin.value; + mPtMax = filter.ptMax.value; + mEtaMin = filter.etaMin.value; + mEtaMax = filter.etaMax.value; + mPhiMin = filter.phiMin.value; + mPhiMax = filter.phiMax.value; + + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { + mMassSigmaLowerLimit = filter.massMinSigma.value; + mMassSigmaUpperLimit = filter.massMaxSigma.value; + // Only add PID selection if we need it - will be checked at runtime + this->addSelection(kChaDaughTpcPion, kinkSelectionNames.at(kChaDaughTpcPion), config.chaDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); + } + + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { + mMassSigmaPlusLowerLimit = filter.massMinSigmaPlus.value; + mMassSigmaPlusUpperLimit = filter.massMaxSigmaPlus.value; + mPidThreshold = config.pidThres.value; + this->addSelection(kChaDaughTpcProton, kinkSelectionNames.at(kChaDaughTpcProton), config.chaDauTpcProton.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kChaDaughTofProton, kinkSelectionNames.at(kChaDaughTofProton), config.chaDauTofProton.value, limits::kUpperLimit, false, false, true); + } + + this->addSelection(kKinkTopoDcaMax, kinkSelectionNames.at(kKinkTopoDcaMax), config.kinkTopoDcaMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kTransRadMin, kinkSelectionNames.at(kTransRadMin), config.transRadMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kTransRadMax, kinkSelectionNames.at(kTransRadMax), config.transRadMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kDauAbsEtaMax, kinkSelectionNames.at(kDauAbsEtaMax), config.dauAbsEtaMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kDauDcaPvMin, kinkSelectionNames.at(kDauDcaPvMin), config.dauDcaPvMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kMothDcaPvMax, kinkSelectionNames.at(kMothDcaPvMax), config.mothDcaPvMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kAlphaAPMin, kinkSelectionNames.at(kAlphaAPMin), config.alphaAPMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kAlphaAPMax, kinkSelectionNames.at(kAlphaAPMax), config.alphaAPMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kQtAPMin, kinkSelectionNames.at(kQtAPMin), config.qtAPMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kQtAPMax, kinkSelectionNames.at(kQtAPMax), config.qtAPMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kCosPointingAngleMin, kinkSelectionNames.at(kCosPointingAngleMin), config.cosPointingAngleMin.value, limits::kLowerLimit, true, true, false); + + this->setupContainers(registry); + }; + + template + void applySelections(T1 const& kinkCand, T2 const& /*tracks*/) + { + this->reset(); + // kink selections + std::array momMother = {kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth()}; + std::array momDaughter = {kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug()}; + + // Alpha_AP + std::array momMissing = {momMother[0] - momDaughter[0], momMother[1] - momDaughter[1], momMother[2] - momDaughter[2]}; + float lQlP = std::inner_product(momMother.begin(), momMother.end(), momDaughter.begin(), 0.f); + float lQlN = std::inner_product(momMother.begin(), momMother.end(), momMissing.begin(), 0.f); + float alphaAP = (lQlP + lQlN != 0.f) ? (lQlP - lQlN) / (lQlP + lQlN) : 0.f; + this->evaluateObservable(kAlphaAPMin, alphaAP); + this->evaluateObservable(kAlphaAPMax, alphaAP); + + // qT_AP + float dp = lQlP; + float p2V0 = std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f); + float p2A = std::inner_product(momDaughter.begin(), momDaughter.end(), momDaughter.begin(), 0.f); + float qtAP = std::sqrt(std::max(0.f, p2A - dp * dp / p2V0)); + this->evaluateObservable(kQtAPMin, qtAP); + this->evaluateObservable(kQtAPMax, qtAP); + + std::array vMother = {kinkCand.xDecVtx(), kinkCand.yDecVtx(), kinkCand.zDecVtx()}; + float pMother = std::sqrt(std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f)); + float vMotherNorm = std::sqrt(std::inner_product(vMother.begin(), vMother.end(), vMother.begin(), 0.f)); + float cosPointingAngle = (vMotherNorm > 0.f && pMother > 0.f) ? (std::inner_product(momMother.begin(), momMother.end(), vMother.begin(), 0.f)) / (pMother * vMotherNorm) : 0.f; + this->evaluateObservable(kCosPointingAngleMin, cosPointingAngle); + + this->evaluateObservable(kKinkTopoDcaMax, kinkCand.dcaKinkTopo()); + + // Compute transRadius + float transRadius = std::hypot(kinkCand.xDecVtx(), kinkCand.yDecVtx()); + this->evaluateObservable(kTransRadMin, transRadius); + this->evaluateObservable(kTransRadMax, transRadius); + + // Compute daughter eta + float pxDaug = kinkCand.pxDaug(); + float pyDaug = kinkCand.pyDaug(); + float pzDaug = kinkCand.pzDaug(); + float pDaug = std::sqrt(pxDaug * pxDaug + pyDaug * pyDaug + pzDaug * pzDaug); + float etaDaug = (pDaug > 0.f) ? 0.5f * std::log((pDaug + pzDaug) / (pDaug - pzDaug)) : 0.f; + this->evaluateObservable(kDauAbsEtaMax, std::fabs(etaDaug)); + + this->evaluateObservable(kDauDcaPvMin, std::abs(kinkCand.dcaDaugPv())); + this->evaluateObservable(kMothDcaPvMax, std::abs(kinkCand.dcaMothPv())); + + auto chaDaughter = kinkCand.template trackDaug_as(); + + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { + this->evaluateObservable(kChaDaughTpcPion, chaDaughter.tpcNSigmaPi()); + } + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { + if (pDaug < mPidThreshold) { + this->evaluateObservable(kChaDaughTpcProton, chaDaughter.tpcNSigmaPr()); + } else { + if (chaDaughter.hasTOF()) { + this->evaluateObservable(kChaDaughTofProton, std::abs(chaDaughter.tofNSigmaPr())); + } else { + this->evaluateObservable(kChaDaughTofProton, 999.f); + } + } + } + + this->assembleBitmask(); + }; + + template + bool checkFilters(const T& kink) const + { + float pt = kink.ptMoth(); + // Compute mother eta and phi + float px = kink.pxMoth(); + float py = kink.pyMoth(); + float pz = kink.pzMoth(); + float p = std::sqrt(px * px + py * py + pz * pz); + float eta = (p > 0.f) ? 0.5f * std::log((p + pz) / (p - pz)) : 0.f; + float phi = RecoDecay::constrainAngle(std::atan2(py, px)); + + return ((pt > mPtMin && pt < mPtMax) && + (eta > mEtaMin && eta < mEtaMax) && + (phi > mPhiMin && phi < mPhiMax)); + } + + template + bool checkMass(T const& kinkCand) const + { + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { + float sigmaMass = kinkCand.mSigmaMinus(); + return (sigmaMass > mMassSigmaLowerLimit && sigmaMass < mMassSigmaUpperLimit); + } + + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { + float sigmaMass = kinkCand.mSigmaPlus(); + return (sigmaMass > mMassSigmaPlusLowerLimit && sigmaMass < mMassSigmaPlusUpperLimit); + } + return false; + } + + public: + float mMassSigmaLowerLimit = 1.15f; + float mMassSigmaUpperLimit = 1.25f; + float mMassSigmaPlusLowerLimit = 1.15f; + float mMassSigmaPlusUpperLimit = 1.25f; + float mPidThreshold = 0.75f; + + // kinematic filters + float mPtMin = 0.f; + float mPtMax = 6.f; + float mEtaMin = -1.f; + float mEtaMax = 1.f; + float mPhiMin = 0.f; + float mPhiMax = o2::constants::math::TwoPI; +}; + +struct KinkBuilderProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedSigmas; + o2::framework::Produces producedSigmaMasks; + o2::framework::Produces producedSigmaExtras; + o2::framework::Produces producedSigmaPlus; + o2::framework::Produces producedSigmaPlusMasks; + o2::framework::Produces producedSigmaPlusExtras; +}; + +struct ConfKinkTables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("KinkTables"); + o2::framework::Configurable produceSigmas{"produceSigmas", -1, "Produce Sigmas (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceSigmaMasks{"produceSigmaMasks", -1, "Produce SigmaMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceSigmaExtras{"produceSigmaExtras", -1, "Produce SigmaExtras (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceSigmaPlus{"produceSigmaPlus", -1, "Produce SigmaPlus (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceSigmaPlusMasks{"produceSigmaPlusMasks", -1, "Produce SigmaPlusMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceSigmaPlusExtras{"produceSigmaPlusExtras", -1, "Produce SigmaPlusExtras (-1: auto; 0 off; 1 on)"}; +}; + +template +class KinkBuilder +{ + public: + KinkBuilder() = default; + ~KinkBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + { + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { + LOG(info) << "Initialize femto Sigma builder..."; + mProduceSigmas = utils::enableTable("FSigmas_001", table.produceSigmas.value, initContext); + mProduceSigmaMasks = utils::enableTable("FSigmaMasks_001", table.produceSigmaMasks.value, initContext); + mProduceSigmaExtras = utils::enableTable("FSigmaExtras_001", table.produceSigmaExtras.value, initContext); + } + + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { + LOG(info) << "Initialize femto SigmaPlus builder..."; + mProduceSigmaPlus = utils::enableTable("FSigmaPlus_001", table.produceSigmaPlus.value, initContext); + mProduceSigmaPlusMasks = utils::enableTable("FSigmaPlusMasks_001", table.produceSigmaPlusMasks.value, initContext); + mProduceSigmaPlusExtras = utils::enableTable("FSigmaPlusExtras_001", table.produceSigmaPlusExtras.value, initContext); + } + + if (mProduceSigmas || mProduceSigmaMasks || mProduceSigmaExtras || mProduceSigmaPlus || mProduceSigmaPlusMasks || mProduceSigmaPlusExtras) { + mFillAnyTable = true; + } else { + LOG(info) << "No tables configured, Selection object will not be configured..."; + LOG(info) << "Initialization done..."; + return; + } + mKinkSelection.configure(registry, config, filter); + mKinkSelection.printSelections(kinkSelsName); + LOG(info) << "Initialization done..."; + } + + template + void fillKinks(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, T5& kinkProducts, T6 const& kinks, T7 const& tracks, T8& trackBuilder, T9& indexMap) + { + if (!mFillAnyTable) { + return; + } + int64_t daughterIndex = 0; + + for (const auto& kink : kinks) { + if (!mKinkSelection.checkFilters(kink)) { + continue; + } + + if (!mKinkSelection.checkMass(kink)) { + continue; + } + + // Apply selections + mKinkSelection.applySelections(kink, tracks); + + if (!mKinkSelection.passesAllRequiredSelections()) { + continue; + } + + auto daughter = kink.template trackDaug_as(); + collisionBuilder.template fillCollision(collisionProducts, col); + daughterIndex = trackBuilder.template getDaughterIndex(daughter, trackProducts, collisionProducts, indexMap); + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { + fillSigma(collisionProducts, kinkProducts, kink, daughterIndex); + } + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { + fillSigmaPlus(collisionProducts, kinkProducts, kink, daughterIndex); + } + } + } + + template + void fillSigma(T1& collisionProducts, T2& kinkProducts, T3 const& kink, int64_t daughterIndex) + { + float mass = kink.mSigmaMinus(); + + if (mProduceSigmas) { + float pt = kink.ptMoth(); + // Compute mother eta and phi + float px = kink.pxMoth(); + float py = kink.pyMoth(); + float pz = kink.pzMoth(); + float p = std::sqrt(px * px + py * py + pz * pz); + float eta = (p > 0.f) ? 0.5f * std::log((p + pz) / (p - pz)) : 0.f; + float phi = RecoDecay::constrainAngle(std::atan2(py, px)); + + kinkProducts.producedSigmas(collisionProducts.producedCollision.lastIndex(), + kink.mothSign() * pt, + eta, + phi, + mass, + daughterIndex); + } + if (mProduceSigmaMasks) { + kinkProducts.producedSigmaMasks(mKinkSelection.getBitmask()); + } + if (mProduceSigmaExtras) { + // Compute kink angle using momentum components + float pxmoth = kink.pxMoth(); + float pymoth = kink.pyMoth(); + float pzmoth = kink.pzMoth(); + float pxch = kink.pxDaug(); + float pych = kink.pyDaug(); + float pzch = kink.pzDaug(); + + float pMoth = std::sqrt(pxmoth * pxmoth + pymoth * pymoth + pzmoth * pzmoth); + float pDaug = std::sqrt(pxch * pxch + pych * pych + pzch * pzch); + float kinkAngle = 0.f; + if (pMoth > 0.f && pDaug > 0.f) { + float dotProduct = pxmoth * pxch + pymoth * pych + pzmoth * pzch; + float cosAngle = dotProduct / (pMoth * pDaug); + cosAngle = std::max(-1.0f, std::min(1.0f, cosAngle)); // Clamp + kinkAngle = std::acos(cosAngle); + } + + float transRadius = std::hypot(kink.xDecVtx(), kink.yDecVtx()); + + kinkProducts.producedSigmaExtras( + kinkAngle, + kink.dcaDaugPv(), + kink.dcaMothPv(), + kink.xDecVtx(), + kink.yDecVtx(), + kink.zDecVtx(), + transRadius); + } + } + + template + void fillSigmaPlus(T1& collisionProducts, T2& kinkProducts, T3 const& kink, int64_t daughterIndex) + { + float mass = kink.mSigmaPlus(); + + if (mProduceSigmaPlus) { + float pt = kink.ptMoth(); + // Compute mother eta and phi + float px = kink.pxMoth(); + float py = kink.pyMoth(); + float pz = kink.pzMoth(); + float p = std::sqrt(px * px + py * py + pz * pz); + float eta = (p > 0.f) ? 0.5f * std::log((p + pz) / (p - pz)) : 0.f; + float phi = RecoDecay::constrainAngle(std::atan2(py, px)); + + kinkProducts.producedSigmaPlus(collisionProducts.producedCollision.lastIndex(), + kink.mothSign() * pt, + eta, + phi, + mass, + daughterIndex); + } + if (mProduceSigmaPlusMasks) { + kinkProducts.producedSigmaPlusMasks(mKinkSelection.getBitmask()); + } + if (mProduceSigmaPlusExtras) { + // Compute kink angle using momentum components + float pxmoth = kink.pxMoth(); + float pymoth = kink.pyMoth(); + float pzmoth = kink.pzMoth(); + float pxch = kink.pxDaug(); + float pych = kink.pyDaug(); + float pzch = kink.pzDaug(); + + float pMoth = std::sqrt(pxmoth * pxmoth + pymoth * pymoth + pzmoth * pzmoth); + float pDaug = std::sqrt(pxch * pxch + pych * pych + pzch * pzch); + float kinkAngle = 0.f; + if (pMoth > 0.f && pDaug > 0.f) { + float dotProduct = pxmoth * pxch + pymoth * pych + pzmoth * pzch; + float cosAngle = dotProduct / (pMoth * pDaug); + cosAngle = std::max(-1.0f, std::min(1.0f, cosAngle)); // Clamp + kinkAngle = std::acos(cosAngle); + } + + float transRadius = std::hypot(kink.xDecVtx(), kink.yDecVtx()); + + kinkProducts.producedSigmaPlusExtras( + kinkAngle, + kink.dcaDaugPv(), + kink.dcaMothPv(), + kink.xDecVtx(), + kink.yDecVtx(), + kink.zDecVtx(), + transRadius); + } + } + + bool fillAnyTable() { return mFillAnyTable; } + + private: + KinkSelection mKinkSelection; + bool mFillAnyTable = false; + bool mProduceSigmas = false; + bool mProduceSigmaMasks = false; + bool mProduceSigmaExtras = false; + bool mProduceSigmaPlus = false; + bool mProduceSigmaPlusMasks = false; + bool mProduceSigmaPlusExtras = false; +}; + +} // namespace kinkbuilder +} // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_KINKBUILDER_H_ diff --git a/PWGCF/Femto/Core/kinkHistManager.h b/PWGCF/Femto/Core/kinkHistManager.h new file mode 100644 index 00000000000..d52d5cb08ec --- /dev/null +++ b/PWGCF/Femto/Core/kinkHistManager.h @@ -0,0 +1,310 @@ +// 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 kinkHistManager.h +/// \brief histogram manager for kink histograms +/// \author Anton Riedel, TU München, anton.riedel@cern.ch +/// \author Henrik Fribert, TU München, henrik.fribert@cern.ch + +#ifndef PWGCF_FEMTO_CORE_KINKHISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_KINKHISTMANAGER_H_ + +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/trackHistManager.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace kinkhistmanager +{ +// enum for kink histograms +enum KinkHist { + // analysis + kPt, + kEta, + kPhi, + kMass, + kSign, + // qa variables + kKinkAngle, + kDcaMothToPV, + kDcaDaugToPV, + kDecayVtxX, + kDecayVtxY, + kDecayVtxZ, + kDecayVtx, + kTransRadius, + // 2d qa + kPtVsEta, + kPtVsPhi, + kPhiVsEta, + kPtVsKinkAngle, + kPtVsDecayRadius, + kKinkHistLast +}; + +#define KINK_DEFAULT_BINNING(defaultMassMin, defaultMassMax) \ + o2::framework::ConfigurableAxis pt{"pt", {{600, 0, 6}}, "Pt"}; \ + o2::framework::ConfigurableAxis eta{"eta", {{300, -1.5, 1.5}}, "Eta"}; \ + o2::framework::ConfigurableAxis phi{"phi", {{720, 0, 1.f * o2::constants::math::TwoPI}}, "Phi"}; \ + o2::framework::ConfigurableAxis mass{"mass", {{200, defaultMassMin, defaultMassMax}}, "Mass"}; \ + o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; + +template +struct ConfSigmaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + KINK_DEFAULT_BINNING(1.1, 1.3) +}; +template +struct ConfSigmaPlusBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + KINK_DEFAULT_BINNING(1.1, 1.3) +}; +#undef KINK_DEFAULT_BINNING + +constexpr const char PrefixSigmaBinning1[] = "SigmaBinning1"; +using ConfSigmaBinning1 = ConfSigmaBinning; + +constexpr const char PrefixSigmaPlusBinning1[] = "SigmaPlusBinning1"; +using ConfSigmaPlusBinning1 = ConfSigmaPlusBinning; + +template +struct ConfKinkQaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable plot2d{"plot2d", true, "Enable 2d QA h histograms"}; + o2::framework::ConfigurableAxis kinkAngle{"kinkAngle", {{100, 0, 3.15}}, "Kink Angle (rad)"}; + o2::framework::ConfigurableAxis dcaMothToPV{"dcaMothToPV", {{150, 0, 1.5}}, "Mother DCA to PV (cm)"}; + o2::framework::ConfigurableAxis dcaDaugToPV{"dcaDaugToPV", {{1000, 0, 100}}, "Daughter DCA to PV (cm)"}; + o2::framework::ConfigurableAxis decayVertex{"decayVertex", {{100, 0, 100}}, "Decay vertex position (cm)"}; + o2::framework::ConfigurableAxis transRadius{"transRadius", {{100, 0, 100}}, "Transverse radius (cm)"}; +}; + +constexpr const char PrefixSigmaQaBinning1[] = "SigmaQaBinning1"; +using ConfSigmaQaBinning1 = ConfKinkQaBinning; + +constexpr const char PrefixSigmaPlusQaBinning1[] = "SigmaPlusQaBinning1"; +using ConfSigmaPlusQaBinning1 = ConfKinkQaBinning; + +// must be in sync with enum KinkHist +// the enum gives the correct index in the array +constexpr std::array, kKinkHistLast> HistTable = { + {{kPt, o2::framework::kTH1F, "hPt", "Transverse Momentum; p_{T} (GeV/#it{c}); Entries"}, + {kEta, o2::framework::kTH1F, "hEta", "Pseudorapidity; #eta; Entries"}, + {kPhi, o2::framework::kTH1F, "hPhi", "Azimuthal angle; #varphi; Entries"}, + {kMass, o2::framework::kTH1F, "hMass", "Invariant Mass; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kSign, o2::framework::kTH1F, "hSign", "Sign; sign; Entries"}, + {kKinkAngle, o2::framework::kTH1F, "hKinkAngle", "Kink Angle; Angle (rad); Entries"}, + {kDcaMothToPV, o2::framework::kTH1F, "hDcaMothToPV", "Mother DCA to PV; DCA (cm); Entries"}, + {kDcaDaugToPV, o2::framework::kTH1F, "hDcaDaugToPV", "Daughter DCA to PV; DCA (cm); Entries"}, + {kDecayVtxX, o2::framework::kTH1F, "hDecayVtxX", "Decay Vertex X; x (cm); Entries"}, + {kDecayVtxY, o2::framework::kTH1F, "hDecayVtxY", "Decay Vertex Y; y (cm); Entries"}, + {kDecayVtxZ, o2::framework::kTH1F, "hDecayVtxZ", "Decay Vertex Z; z (cm); Entries"}, + {kDecayVtx, o2::framework::kTH1F, "hDecayVtx", "Decay Distance from PV; r (cm); Entries"}, + {kTransRadius, o2::framework::kTH1F, "hTransRadius", "Transverse Decay Radius; r_{xy} (cm); Entries"}, + {kPtVsEta, o2::framework::kTH2F, "hPtVsEta", "p_{T} vs #eta; p_{T} (GeV/#it{c}); #eta"}, + {kPtVsPhi, o2::framework::kTH2F, "hPtVsPhi", "p_{T} vs #varphi; p_{T} (GeV/#it{c}); #varphi"}, + {kPhiVsEta, o2::framework::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi; #eta"}, + {kPtVsKinkAngle, o2::framework::kTH2F, "hPtVsKinkAngle", "p_{T} vs kink angle; p_{T} (GeV/#it{c}); kink angle (rad)"}, + {kPtVsDecayRadius, o2::framework::kTH2F, "hPtVsDecayRadius", "p_{T} vs transverse decay radius; p_{T} (GeV/#it{c}); r_{xy} (cm)"}}}; + +template +auto makeKinkHistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kMass, {confBinningAnalysis.mass}}, + {kSign, {confBinningAnalysis.sign}}}; +} + +template +std::map> makeKinkQaHistSpecMap(T1 const& confBinningAnalysis, T2 const& confBinningQa) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kMass, {confBinningAnalysis.mass}}, + {kSign, {confBinningAnalysis.sign}}, + {kKinkAngle, {confBinningQa.kinkAngle}}, + {kDcaMothToPV, {confBinningQa.dcaMothToPV}}, + {kDcaDaugToPV, {confBinningQa.dcaDaugToPV}}, + {kDecayVtxX, {confBinningQa.decayVertex}}, + {kDecayVtxY, {confBinningQa.decayVertex}}, + {kDecayVtxZ, {confBinningQa.decayVertex}}, + {kDecayVtx, {confBinningQa.decayVertex}}, + {kTransRadius, {confBinningQa.transRadius}}, + {kPtVsEta, {confBinningAnalysis.pt, confBinningAnalysis.eta}}, + {kPtVsPhi, {confBinningAnalysis.pt, confBinningAnalysis.phi}}, + {kPhiVsEta, {confBinningAnalysis.phi, confBinningAnalysis.eta}}, + {kPtVsKinkAngle, {confBinningAnalysis.pt, confBinningQa.kinkAngle}}, + {kPtVsDecayRadius, {confBinningAnalysis.pt, confBinningQa.transRadius}}}; +} + +constexpr char PrefixSigmaQa[] = "SigmaQA/"; +constexpr char PrefixSigma1[] = "Sigma1/"; +constexpr char PrefixSigma2[] = "Sigma2/"; +constexpr char PrefixSigmaPlusQa[] = "SigmaPlusQA/"; +constexpr char PrefixSigmaPlus1[] = "SigmaPlus1/"; +constexpr char PrefixSigmaPlus2[] = "SigmaPlus2/"; + +constexpr std::string_view AnalysisDir = "Kinematics/"; +constexpr std::string_view QaDir = "QA/"; + +/// \class KinkHistManager +/// \brief Class for histogramming event properties +// template +template +class KinkHistManager +{ + public: + KinkHistManager() = default; + ~KinkHistManager() = default; + + void init(o2::framework::HistogramRegistry* registry, + std::map> const& KinkSpecs, + std::map> const& ChaDauSpecs) + { + mHistogramRegistry = registry; + mChaDauManager.init(registry, ChaDauSpecs); + if constexpr (isFlagSet(mode, modes::Mode::kAnalysis)) { + initAnalysis(KinkSpecs); + } + if constexpr (isFlagSet(mode, modes::Mode::kQa)) { + initQa(KinkSpecs); + } + } + + template + void enableOptionalHistograms(T1 const& KinkConfBinningQa, T2 const& ChaDauConfBinningQa) + { + mChaDauManager.enableOptionalHistograms(ChaDauConfBinningQa); + mPlot2d = KinkConfBinningQa.plot2d.value; + } + + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& KinkSpecs, + T1 const& KinkConfBinningQa, + std::map> const& ChaDauSpecs, + T2 const& ChaDauConfBinningQa) + { + enableOptionalHistograms(KinkConfBinningQa, ChaDauConfBinningQa); + init(registry, KinkSpecs, ChaDauSpecs); + } + + template + void fill(T1 const& kinkcandidate, T2 const& tracks) + { + // this used to work, still under investigation + // auto chaDaughter = kinkcandidate.template chaDau_as(); + auto chaDaughter = tracks.rawIteratorAt(kinkcandidate.chaDauId() - tracks.offset()); + mChaDauManager.fill(chaDaughter, tracks); + if constexpr (isFlagSet(mode, modes::Mode::kAnalysis)) { + fillAnalysis(kinkcandidate); + } + if constexpr (isFlagSet(mode, modes::Mode::kQa)) { + fillQa(kinkcandidate); + } + } + + private: + void initAnalysis(std::map> const& KinkSpecs) + { + std::string analysisDir = std::string(kinkPrefix) + std::string(AnalysisDir); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt, HistTable), getHistDesc(kPt, HistTable), getHistType(kPt, HistTable), {KinkSpecs.at(kPt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kEta, HistTable), getHistDesc(kEta, HistTable), getHistType(kEta, HistTable), {KinkSpecs.at(kEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhi, HistTable), getHistDesc(kPhi, HistTable), getHistType(kPhi, HistTable), {KinkSpecs.at(kPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMass, HistTable), getHistDesc(kMass, HistTable), getHistType(kMass, HistTable), {KinkSpecs.at(kMass)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kSign, HistTable), getHistDesc(kSign, HistTable), getHistType(kSign, HistTable), {KinkSpecs.at(kSign)}); + } + + void initQa(std::map> const& KinkSpecs) + { + std::string qaDir = std::string(kinkPrefix) + std::string(QaDir); + // Kink-specific QA histograms + mHistogramRegistry->add(qaDir + getHistNameV2(kKinkAngle, HistTable), getHistDesc(kKinkAngle, HistTable), getHistType(kKinkAngle, HistTable), {KinkSpecs.at(kKinkAngle)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDcaMothToPV, HistTable), getHistDesc(kDcaMothToPV, HistTable), getHistType(kDcaMothToPV, HistTable), {KinkSpecs.at(kDcaMothToPV)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDcaDaugToPV, HistTable), getHistDesc(kDcaDaugToPV, HistTable), getHistType(kDcaDaugToPV, HistTable), {KinkSpecs.at(kDcaDaugToPV)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxX, HistTable), getHistDesc(kDecayVtxX, HistTable), getHistType(kDecayVtxX, HistTable), {KinkSpecs.at(kDecayVtxX)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxY, HistTable), getHistDesc(kDecayVtxY, HistTable), getHistType(kDecayVtxY, HistTable), {KinkSpecs.at(kDecayVtxY)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxZ, HistTable), getHistDesc(kDecayVtxZ, HistTable), getHistType(kDecayVtxZ, HistTable), {KinkSpecs.at(kDecayVtxZ)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtx, HistTable), getHistDesc(kDecayVtx, HistTable), getHistType(kDecayVtx, HistTable), {KinkSpecs.at(kDecayVtx)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTransRadius, HistTable), getHistDesc(kTransRadius, HistTable), getHistType(kTransRadius, HistTable), {KinkSpecs.at(kTransRadius)}); + if (mPlot2d) { + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsEta, HistTable), getHistDesc(kPtVsEta, HistTable), getHistType(kPtVsEta, HistTable), {KinkSpecs.at(kPtVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsPhi, HistTable), getHistDesc(kPtVsPhi, HistTable), getHistType(kPtVsPhi, HistTable), {KinkSpecs.at(kPtVsPhi)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPhiVsEta, HistTable), getHistDesc(kPhiVsEta, HistTable), getHistType(kPhiVsEta, HistTable), {KinkSpecs.at(kPhiVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsKinkAngle, HistTable), getHistDesc(kPtVsKinkAngle, HistTable), getHistType(kPtVsKinkAngle, HistTable), {KinkSpecs.at(kPtVsKinkAngle)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsDecayRadius, HistTable), getHistDesc(kPtVsDecayRadius, HistTable), getHistType(kPtVsDecayRadius, HistTable), {KinkSpecs.at(kPtVsDecayRadius)}); + } + } + + /// Fill histograms for kink candidates + /// \param kinkcandidate Kink candidate to fill histograms for + template + void fillAnalysis(T const& kinkcandidate) + { + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPt, HistTable)), kinkcandidate.pt()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(AnalysisDir) + HIST(getHistName(kEta, HistTable)), kinkcandidate.eta()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPhi, HistTable)), kinkcandidate.phi()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(AnalysisDir) + HIST(getHistName(kMass, HistTable)), kinkcandidate.mass()); + + if constexpr (isEqual(kink, modes::Kink::kSigma) || isEqual(kink, modes::Kink::kSigmaPlus)) { + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), kinkcandidate.sign()); + } + } + + template + void fillQa(T const& kinkcandidate) + { + // Kink-specific QA histograms + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kKinkAngle, HistTable)), kinkcandidate.kinkAngle()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kDcaMothToPV, HistTable)), kinkcandidate.dcaMothToPV()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kDcaDaugToPV, HistTable)), kinkcandidate.dcaDaugToPV()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxX, HistTable)), kinkcandidate.decayVtxX()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxY, HistTable)), kinkcandidate.decayVtxY()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxZ, HistTable)), kinkcandidate.decayVtxZ()); + // Calculate decay distance from PV + float decayDistance = std::hypot(kinkcandidate.decayVtxX(), kinkcandidate.decayVtxY(), kinkcandidate.decayVtxZ()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kDecayVtx, HistTable)), decayDistance); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kTransRadius, HistTable)), kinkcandidate.transRadius()); + if (mPlot2d) { + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kPtVsEta, HistTable)), kinkcandidate.pt(), kinkcandidate.eta()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kPtVsPhi, HistTable)), kinkcandidate.pt(), kinkcandidate.phi()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kPhiVsEta, HistTable)), kinkcandidate.phi(), kinkcandidate.eta()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kPtVsKinkAngle, HistTable)), kinkcandidate.pt(), kinkcandidate.kinkAngle()); + mHistogramRegistry->fill(HIST(kinkPrefix) + HIST(QaDir) + HIST(getHistName(kPtVsDecayRadius, HistTable)), kinkcandidate.pt(), kinkcandidate.transRadius()); + } + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + trackhistmanager::TrackHistManager mChaDauManager; + bool mPlot2d = true; +}; +}; // namespace kinkhistmanager +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_KINKHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/modes.h b/PWGCF/Femto/Core/modes.h new file mode 100644 index 00000000000..e4104c7f343 --- /dev/null +++ b/PWGCF/Femto/Core/modes.h @@ -0,0 +1,135 @@ +// 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 modes.h +/// \brief common modes +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_MODES_H_ +#define PWGCF_FEMTO_CORE_MODES_H_ + +#include "PWGCF/Femto/Core/dataTypes.h" + +#include + +#include +#include + +namespace o2::analysis::femto +{ +namespace modes +{ + +// check if flag is set +template +constexpr bool isFlagSet(T value, T flag) +{ + using U = std::underlying_type_t; + return (static_cast(value) & static_cast(flag)) != 0; +} + +// check if flag is equal +template +constexpr bool isEqual(T lhs, T rhs) +{ + using U = std::underlying_type_t; + return static_cast(lhs) == static_cast(rhs); +} + +enum class Mode : uint32_t { + kAnalysis = BIT(0), + kQa = BIT(1), + kMc = BIT(2), + kAnalysis_Qa = kAnalysis | kQa, + kAnalysis_Mc = kAnalysis | kMc, + kAnalysis_Qa_Mc = kAnalysis | kQa | kMc, +}; + +enum class System : uint32_t { + kPP = BIT(0), + kPbPb = BIT(1), + kMC = BIT(2), + kRun3 = BIT(3), + kRun2 = BIT(4), + kPP_Run3 = kPP | kRun3, + kPP_Run2 = kPP | kRun2, + kPbPb_Run3 = kPbPb | kRun3, + kPbPb_Run2 = kPbPb | kRun2, +}; + +enum class MomentumType : o2::aod::femtodatatypes::MomentumType { + kPt = 0, // transverse momentum + kPAtPv = 1, // momentum at primary vertex + kPTpc = 2, // momentum at inner wall of tpc +}; + +enum class TransverseMassType : o2::aod::femtodatatypes::TransverseMassType { + kAveragePdgMass = 0, + kReducedPdgMass = 1, + kMt4Vector = 2 +}; + +enum class Particle : o2::aod::femtodatatypes::ParticleType { + kTrack, + kTwoTrackResonance, + kV0, + kKink, + kCascade, +}; + +constexpr bool hasMass(Particle p) +{ + switch (p) { + case Particle::kV0: + case Particle::kTwoTrackResonance: + case Particle::kKink: + case Particle::kCascade: + return true; + default: + return false; + } +} + +enum class Track : o2::aod::femtodatatypes::TrackType { + kPrimaryTrack, + kV0Daughter, + kCascadeBachelor, + kResonanceDaughter, + kKinkDaughter +}; + +enum class V0 : o2::aod::femtodatatypes::V0Type { + kLambda, + kAntiLambda, + kK0short +}; + +enum class Kink : o2::aod::femtodatatypes::KinkType { + kSigma, + kSigmaPlus +}; + +enum class Cascade : o2::aod::femtodatatypes::CascadeType { + kXi, + kOmega +}; + +// enum of supported resonances +enum class TwoTrackResonance : o2::aod::femtodatatypes::TwoTrackResonanceType { + kRho0, + kPhi, + kKstar0, + kKstar0Bar +}; + +}; // namespace modes +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_MODES_H_ diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h new file mode 100644 index 00000000000..9af6fcd0a13 --- /dev/null +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -0,0 +1,829 @@ +// 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 pairBuilder.h +/// \brief histogram manager for pair tasks +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_PAIRBUILDER_H_ +#define PWGCF_FEMTO_CORE_PAIRBUILDER_H_ + +#include "PWGCF/Femto/Core/cascadeHistManager.h" +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/kinkHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairCleaner.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/pairProcessHelpers.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/Core/twoTrackResonanceHistManager.h" +#include "PWGCF/Femto/Core/v0HistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace pairbuilder +{ + +template < + const char* prefixTrack1, + const char* prefixTrack2, + const char* prefixSe, + const char* prefixMe, + const char* prefixCprSe, + const char* prefixCprMe, + modes::Mode mode> +class PairTrackTrackBuilder +{ + public: + PairTrackTrackBuilder() = default; + ~PairTrackTrackBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confTrackSelection1, + T2 const& confTrackSelection2, + T3 const& confCpr, + T4 const& confMixing, + T5 const& confPairBinning, + T6 const& confPairCuts, + std::map> const& colHistSpec, + std::map> const& trackHistSpec1, + std::map> const& trackHistSpec2, + std::map> const& pairHistSpec, + std::map> const& cprHistSpec) + { + + // check if correlate the same tracks or not + mSameSpecies = confMixing.sameSpecies.value; + + mColHistManager.init(registry, colHistSpec); + mPairHistManagerSe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerMe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + + if (mSameSpecies) { + mTrackHistManager1.init(registry, trackHistSpec1, confTrackSelection1.chargeAbs.value); + + mPairHistManagerSe.setMass(confTrackSelection1.pdgCode.value, confTrackSelection1.pdgCode.value); + mPairHistManagerSe.setCharge(confTrackSelection1.chargeAbs.value, confTrackSelection1.chargeAbs.value); + mCprSe.init(registry, cprHistSpec, confCpr, confTrackSelection1.chargeAbs.value, confTrackSelection1.chargeAbs.value); + + mPairHistManagerMe.setMass(confTrackSelection1.pdgCode.value, confTrackSelection1.pdgCode.value); + mPairHistManagerMe.setCharge(confTrackSelection1.chargeAbs.value, confTrackSelection1.chargeAbs.value); + mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection1.chargeAbs.value, confTrackSelection1.chargeAbs.value); + } else { + mTrackHistManager1.init(registry, trackHistSpec1, confTrackSelection1.chargeAbs.value); + mTrackHistManager2.init(registry, trackHistSpec2, confTrackSelection2.chargeAbs.value); + + mPairHistManagerSe.setMass(confTrackSelection1.pdgCode.value, confTrackSelection2.pdgCode.value); + mPairHistManagerSe.setCharge(confTrackSelection1.chargeAbs.value, confTrackSelection2.chargeAbs.value); + mCprSe.init(registry, cprHistSpec, confCpr, confTrackSelection1.chargeAbs.value, confTrackSelection2.chargeAbs.value); + + mPairHistManagerMe.setMass(confTrackSelection1.pdgCode.value, confTrackSelection2.pdgCode.value); + mPairHistManagerMe.setCharge(confTrackSelection1.chargeAbs.value, confTrackSelection2.chargeAbs.value); + mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection1.chargeAbs.value, confTrackSelection2.chargeAbs.value); + } + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + + // setup rng if necessary + if (confMixing.seed.value >= 0) { + uint64_t randomSeed = 0; + mMixIdenticalParticles = true; + if (confMixing.seed.value == 0) { + randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } else { + randomSeed = static_cast(confMixing.seed.value); + } + mRng = std::mt19937(randomSeed); + } + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& partition1, T4& partition2, T5& cache) + { + if (mSameSpecies) { + auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice1.size() == 0) { + return; + } + mColHistManager.fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice1, trackTable, col, mTrackHistManager1, mPairHistManagerSe, mCprSe, mPc, mRng, mMixIdenticalParticles); + } else { + auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice1.size() == 0 || trackSlice2.size() == 0) { + return; + } + mColHistManager.fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackTable, col, mTrackHistManager1, mTrackHistManager2, mPairHistManagerSe, mCprSe, mPc); + } + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& partition1, T4& partition2, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + + if (mSameSpecies) { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } else { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + trackhistmanager::TrackHistManager mTrackHistManager1; + trackhistmanager::TrackHistManager mTrackHistManager2; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionTrackTrack mCprSe; + closepairrejection::ClosePairRejectionTrackTrack mCprMe; + paircleaner::TrackTrackPairCleaner mPc; + std::mt19937 mRng; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + bool mSameSpecies = false; + int mMixingDepth = 5; + bool mMixIdenticalParticles = false; +}; + +template < + const char* prefixV01, + const char* prefixPosDau1, + const char* prefixNegDau1, + const char* prefixV02, + const char* prefixPosDau2, + const char* prefixNegDau2, + const char* prefixSe, + const char* prefixMe, + const char* prefixCprPosSe, + const char* prefixCprNegSe, + const char* prefixCprPosMe, + const char* prefixCprNegMe, + modes::V0 v0Type1, + modes::V0 v0Type2, + modes::Mode mode> +class PairV0V0Builder +{ + public: + PairV0V0Builder() = default; + ~PairV0V0Builder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confV0Selection1, + T2 const& confV0Selection2, + T3 const& confCprPos, + T4 const& confCprNeg, + T5 const& confMixing, + T6 const& confPairBinning, + T7 const& confPairCuts, + std::map> const& colHistSpec, + std::map> const& V0HistSpec1, + std::map> const& V0HistSpec2, + std::map> const& PosDauHistSpec, + std::map> const& NegDauHistSpec, + std::map> const& pairHistSpec, + std::map> const& cprHistSpecPos, + std::map> const& cprHistSpecNeg) + { + + // check if correlate the same tracks or not + mSameSpecies = confMixing.sameSpecies.value; + + mColHistManager.init(registry, colHistSpec); + mPairHistManagerSe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerMe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + + if (mSameSpecies) { + mV0HistManager1.init(registry, V0HistSpec1, PosDauHistSpec, NegDauHistSpec); + + mPairHistManagerSe.setMass(confV0Selection1.pdgCode.value, confV0Selection1.pdgCode.value); + mPairHistManagerSe.setCharge(1, 1); + mCprSe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprPos); + + mPairHistManagerMe.setMass(confV0Selection1.pdgCode.value, confV0Selection1.pdgCode.value); + mPairHistManagerMe.setCharge(1, 1); + mCprMe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); + } else { + mV0HistManager1.init(registry, V0HistSpec1, PosDauHistSpec, NegDauHistSpec); + mV0HistManager2.init(registry, V0HistSpec2, PosDauHistSpec, NegDauHistSpec); + + mPairHistManagerSe.setMass(confV0Selection1.pdgCode.value, confV0Selection2.pdgCode.value); + mPairHistManagerSe.setCharge(1, 1); + mCprSe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); + + mPairHistManagerMe.setMass(confV0Selection1.pdgCode.value, confV0Selection2.pdgCode.value); + mPairHistManagerMe.setCharge(1, 1); + mCprMe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); + } + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + + // setup rng if necessary + if (confMixing.seed.value >= 0) { + uint64_t randomSeed = 0; + mMixIdenticalParticles = true; + if (confMixing.seed.value == 0) { + randomSeed = static_cast(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } else { + randomSeed = static_cast(confMixing.seed.value); + } + mRng = std::mt19937(randomSeed); + } + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& /*lambdaTable*/, T4& partition1, T5& partition2, T6& cache) + { + if (mSameSpecies) { + auto v0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (v0Slice1.size() == 0) { + return; + } + mColHistManager.fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(v0Slice1, trackTable, col, mV0HistManager1, mPairHistManagerSe, mCprSe, mPc, mRng, mMixIdenticalParticles); + } else { + auto v0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto v0Slice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (v0Slice1.size() == 0 || v0Slice2.size() == 0) { + return; + } + mColHistManager.fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(v0Slice1, v0Slice2, trackTable, col, mV0HistManager1, mV0HistManager2, mPairHistManagerSe, mCprSe, mPc); + } + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& partition1, T4& partition2, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + + if (mSameSpecies) { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } else { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + v0histmanager::V0HistManager mV0HistManager1; + v0histmanager::V0HistManager mV0HistManager2; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionV0V0 mCprSe; + closepairrejection::ClosePairRejectionV0V0 mCprMe; + paircleaner::V0V0PairCleaner mPc; + std::mt19937 mRng; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + bool mSameSpecies = false; + int mMixingDepth = 5; + bool mMixIdenticalParticles = false; +}; + +template < + const char* prefixTrack, + const char* prefixV0, + const char* prefixPosDau, + const char* prefixNegDau, + const char* prefixSe, + const char* prefixMe, + const char* prefixCprSe, + const char* prefixCprMe, + modes::Mode mode, + modes::V0 v0Type> +class PairTrackV0Builder +{ + public: + PairTrackV0Builder() = default; + ~PairTrackV0Builder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confTrackSelection, + T2 const& confV0Selection, + T3 const& confCpr, + T4 const& confMixing, + T5 const& confPairBinning, + T6 const& confPairCuts, + std::map>& colHistSpec, + std::map>& trackHistSpec, + std::map>& v0HistSpec, + std::map>& posDauHistSpec, + std::map>& negDauHistSpec, + std::map>& pairHistSpec, + std::map>& cprHistSpec) + { + mColHistManager.init(registry, colHistSpec); + + mTrackHistManager.init(registry, trackHistSpec, confTrackSelection.chargeAbs.value); + mV0HistManager.init(registry, v0HistSpec, posDauHistSpec, negDauHistSpec); + + mPairHistManagerSe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerSe.setMass(confTrackSelection.pdgCode.value, confV0Selection.pdgCode.value); + mPairHistManagerSe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprSe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + + mPairHistManagerMe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerMe.setMass(confTrackSelection.pdgCode.value, confV0Selection.pdgCode.value); + mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& trackPartition, T4& /*v0table*/, T5& v0Partition, T6& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto v0Slice = v0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() == 0 || v0Slice.size() == 0) { + return; + } + mColHistManager.fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, v0Slice, trackTable, col, mTrackHistManager, mV0HistManager, mPairHistManagerSe, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& trackPartition, T4& v0Partition, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + trackhistmanager::TrackHistManager mTrackHistManager; + v0histmanager::V0HistManager mV0HistManager; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionTrackV0 mCprSe; + closepairrejection::ClosePairRejectionTrackV0 mCprMe; + paircleaner::TrackV0PairCleaner mPc; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + int mMixingDepth = 5; +}; + +template < + const char* prefixTrack, + const char* prefixResonance, + const char* prefixPosDau, + const char* prefixNegDau, + const char* prefixSe, + const char* prefixMe, + const char* prefixCprSe, + const char* prefixCprMe, + modes::Mode mode, + modes::TwoTrackResonance resonanceType> +class PairTrackTwoTrackResonanceBuilder +{ + public: + PairTrackTwoTrackResonanceBuilder() = default; + ~PairTrackTwoTrackResonanceBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confTrackSelection, + T2 const& confResonanceSelection, + T3 const& confCpr, + T4 const& confMixing, + T5 const& confPairBinning, + T6 const& confPairCuts, + std::map> const& colHistSpec, + std::map> const& trackHistSpec, + std::map> const& resonanceHistSpec, + std::map> const& posDauHistSpec, + std::map> const& negDauHistSpec, + std::map> const& pairHistSpec, + std::map> const& cprHistSpec) + { + mColHistManager.init(registry, colHistSpec); + + mTrackHistManager.init(registry, trackHistSpec, confTrackSelection.chargeAbs.value); + mResonanceHistManager.init(registry, resonanceHistSpec, posDauHistSpec, negDauHistSpec); + + mPairHistManagerSe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerSe.setMass(confTrackSelection.pdgCode.value, confResonanceSelection.pdgCode.value); + mPairHistManagerSe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprSe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + + mPairHistManagerMe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerMe.setMass(confTrackSelection.pdgCode.value, confResonanceSelection.pdgCode.value); + mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& trackPartition, T4& /*resonanceTable*/, T5& resonancePartition, T6& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto v0Slice = resonancePartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() == 0 || v0Slice.size() == 0) { + return; + } + mColHistManager.fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, v0Slice, trackTable, col, mTrackHistManager, mResonanceHistManager, mPairHistManagerSe, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& trackPartition, T4& resonancePartition, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + trackhistmanager::TrackHistManager mTrackHistManager; + twotrackresonancehistmanager::TwoTrackResonanceHistManager mResonanceHistManager; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionTrackV0 mCprSe; // cpr for twotrackresonances and v0 work the same way + closepairrejection::ClosePairRejectionTrackV0 mCprMe; // cpr for twotrackresonances and v0 work the same way + paircleaner::TrackV0PairCleaner mPc; // pc for twotrackresonances and v0 work the same way + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + int mMixingDepth = 5; +}; + +template < + const char* prefixTrack, + const char* prefixKink, + const char* prefixChaDau, + const char* prefixSe, + const char* prefixMe, + const char* prefixCprSe, + const char* prefixCprMe, + modes::Mode mode, + modes::Kink kinkType> +class PairTrackKinkBuilder +{ + public: + PairTrackKinkBuilder() = default; + ~PairTrackKinkBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confTrackSelection, + T2 const& confKinkSelection, + T3 const& confCpr, + T4 const& confMixing, + T5 const& confPairBinning, + T6 const& confPairCuts, + std::map> const& colHistSpec, + std::map> const& trackHistSpec, + std::map> const& kinkHistSpec, + std::map> const& chaDauHistSpec, + std::map> const& pairHistSpec, + std::map> const& cprHistSpec) + { + mColHistManager.init(registry, colHistSpec); + + mTrackHistManager.init(registry, trackHistSpec, confTrackSelection.chargeAbs.value); + mKinkHistManager.init(registry, kinkHistSpec, chaDauHistSpec); + + mPairHistManagerSe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerSe.setMass(confTrackSelection.pdgCode.value, confKinkSelection.pdgCode.value); + mPairHistManagerSe.setCharge(confTrackSelection.chargeAbs.value, 1); // abs charge of kink daughter is always 1 + mCprSe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + + mPairHistManagerMe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerMe.setMass(confTrackSelection.pdgCode.value, confKinkSelection.pdgCode.value); + mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); // abs charge of kink daughter is always 1 + mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& trackPartition, T4& /*kinktable*/, T5& kinkPartition, T6& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto kinkSlice = kinkPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() == 0 || kinkSlice.size() == 0) { + return; + } + mColHistManager.fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, kinkSlice, trackTable, col, mTrackHistManager, mKinkHistManager, mPairHistManagerSe, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& trackPartition, T4& kinkPartition, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + trackhistmanager::TrackHistManager mTrackHistManager; + kinkhistmanager::KinkHistManager mKinkHistManager; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionTrackKink mCprSe; + closepairrejection::ClosePairRejectionTrackKink mCprMe; + paircleaner::TrackKinkPairCleaner mPc; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + int mMixingDepth = 5; +}; + +template < + const char* prefixTrack, + const char* prefixCascade, + const char* prefixBachelor, + const char* prefixPosDau, + const char* prefixNegDau, + const char* prefixSe, + const char* prefixMe, + const char* prefixCprBachelorSe, + const char* prefixCprV0DaughterSe, + const char* prefixCprBachelorMe, + const char* prefixCprV0DaughterMe, + modes::Mode mode, + modes::Cascade cascadeType> +class PairTrackCascadeBuilder +{ + public: + PairTrackCascadeBuilder() = default; + ~PairTrackCascadeBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confTrackSelection, + T2 const& confCascadeSelection, + T3 const& confCprBachelor, + T4 const& confCprV0Daughter, + T5 const& confMixing, + T6 const& confPairBinning, + T7 const& confPairCuts, + std::map> const& colHistSpec, + std::map> const& trackHistSpec, + std::map> const& cascadeHistSpec, + std::map> const& bachelorHistSpec, + std::map> const& posDauHistSpec, + std::map> const& negDauHistSpec, + std::map> const& pairHistSpec, + std::map> const& cprHistSpecBachelor, + std::map> const& cprHistSpecV0Daughter) + { + mColHistManager.init(registry, colHistSpec); + + mTrackHistManager.init(registry, trackHistSpec, confTrackSelection.chargeAbs.value); + mCascadeHistManager.init(registry, cascadeHistSpec, bachelorHistSpec, posDauHistSpec, negDauHistSpec); + + mPairHistManagerSe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerSe.setMass(confTrackSelection.pdgCode.value, confCascadeSelection.pdgCode.value); + mPairHistManagerSe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprSe.init(registry, cprHistSpecBachelor, cprHistSpecV0Daughter, confCprBachelor, confCprV0Daughter, confTrackSelection.chargeAbs.value); + + mPairHistManagerMe.init(registry, pairHistSpec, confPairBinning, confPairCuts); + mPairHistManagerMe.setMass(confTrackSelection.pdgCode.value, confCascadeSelection.pdgCode.value); + mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprMe.init(registry, cprHistSpecBachelor, cprHistSpecV0Daughter, confCprBachelor, confCprV0Daughter, confTrackSelection.chargeAbs.value); + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& trackPartition, T4& /*cascadeTable*/, T5& v0Partition, T6& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto v0Slice = v0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() == 0 || v0Slice.size() == 0) { + return; + } + mColHistManager.fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, v0Slice, trackTable, col, mTrackHistManager, mCascadeHistManager, mPairHistManagerSe, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& trackPartition, T4& v0Partition, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + trackhistmanager::TrackHistManager mTrackHistManager; + cascadehistmanager::CascadeHistManager mCascadeHistManager; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionTrackCascade mCprSe; + closepairrejection::ClosePairRejectionTrackCascade mCprMe; + paircleaner::TrackCascadePairCleaner mPc; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + int mMixingDepth = 5; +}; + +} // namespace pairbuilder +} // namespace o2::analysis::femto + +#endif // PWGCF_FEMTO_CORE_PAIRBUILDER_H_ diff --git a/PWGCF/Femto/Core/pairCleaner.h b/PWGCF/Femto/Core/pairCleaner.h new file mode 100644 index 00000000000..d0ff785fcdc --- /dev/null +++ b/PWGCF/Femto/Core/pairCleaner.h @@ -0,0 +1,105 @@ +// 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 pairCleaner.h +/// \brief pair cleaner class +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_PAIRCLEANER_H_ +#define PWGCF_FEMTO_CORE_PAIRCLEANER_H_ + +namespace o2::analysis::femto +{ +namespace paircleaner +{ + +class BasePairCleaner +{ + public: + BasePairCleaner() = default; + virtual ~BasePairCleaner() = default; + + protected: + template + bool isCleanTrackPair(T1 const& track1, T2 const& track2) const + { + return track1.globalIndex() != track2.globalIndex(); + }; +}; + +class TrackTrackPairCleaner : public BasePairCleaner +{ + public: + TrackTrackPairCleaner() = default; + template + bool isCleanPair(T1 const& track1, T2 const& track2, T3 const& /*trackTable*/) const + { + return this->isCleanTrackPair(track1, track2); + } +}; + +class V0V0PairCleaner : public BasePairCleaner +{ + public: + V0V0PairCleaner() = default; + template + bool isCleanPair(const T1& v01, const T2& v02, const T3& trackTable) const + { + auto posDaughter1 = trackTable.rawIteratorAt(v01.posDauId() - trackTable.offset()); + auto negDaughter1 = trackTable.rawIteratorAt(v01.negDauId() - trackTable.offset()); + auto posDaughter2 = trackTable.rawIteratorAt(v02.posDauId() - trackTable.offset()); + auto negDaughter2 = trackTable.rawIteratorAt(v02.negDauId() - trackTable.offset()); + return this->isCleanTrackPair(posDaughter1, posDaughter2) && this->isCleanTrackPair(negDaughter1, negDaughter2); + } +}; + +class TrackV0PairCleaner : public BasePairCleaner // also works for particles decaying into a positive and negative daughter, like resonances +{ + public: + TrackV0PairCleaner() = default; + template + bool isCleanPair(const T1& track, const T2& v0, const T3& trackTable) const + { + auto posDaughter = trackTable.rawIteratorAt(v0.posDauId() - trackTable.offset()); + auto negDaughter = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); + return (this->isCleanTrackPair(posDaughter, track) && this->isCleanTrackPair(negDaughter, track)); + } +}; + +class TrackKinkPairCleaner : public BasePairCleaner +{ + public: + TrackKinkPairCleaner() = default; + template + bool isCleanPair(const T1& track, const T2& kink, const T3& trackTable) const + { + auto chaDaughter = trackTable.rawIteratorAt(kink.chaDauId() - trackTable.offset()); + return this->isCleanTrackPair(chaDaughter, track); + } +}; + +class TrackCascadePairCleaner : public BasePairCleaner +{ + public: + TrackCascadePairCleaner() = default; + template + bool isCleanPair(const T1& track, const T2& cascade, const T3& trackTable) const + { + auto bachelor = trackTable.rawIteratorAt(cascade.bachelorId() - trackTable.offset()); + auto posDaughter = trackTable.rawIteratorAt(cascade.posDauId() - trackTable.offset()); + auto negDaughter = trackTable.rawIteratorAt(cascade.posDauId() - trackTable.offset()); + return (this->isCleanTrackPair(bachelor, track) && this->isCleanTrackPair(posDaughter, track) && this->isCleanTrackPair(negDaughter, track)); + } +}; +} // namespace paircleaner +} // namespace o2::analysis::femto + +#endif // PWGCF_FEMTO_CORE_PAIRCLEANER_H_ diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h new file mode 100644 index 00000000000..52adbee6a78 --- /dev/null +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -0,0 +1,557 @@ +// 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 pairHistManager.h +/// \brief histogram manager for pair tasks +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_PAIRHISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_PAIRHISTMANAGER_H_ + +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" + +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace pairhistmanager +{ +// enum for pair histograms +enum PairHist { + // standard 1D + kKstar, + kKt, + kMt, + // standard 2D + kPt1VsPt2, + kPt1VsKstar, + kPt2VsKstar, + kPt1VsKt, + kPt2VsKt, + kPt1VsMt, + kPt2VsMt, + kKstarVsKt, + kKstarVsMt, + kKstarVsMult, + kKstarVsCent, + // 2D with mass + kKstarVsMass1, + kKstarVsMass2, + kMass1VsMass2, + // higher dimensions + kKstarVsMtVsMult, + kKstarVsMtVsMultVsCent, + kKstarVsMtVsPt1VsPt2VsMult, + kKstarVsMtVsPt1VsPt2VsMultVsCent, + // higher dimensions with mass + kKstarVsMass1VsMass2, + kKstarVsMass1VsMult, + kKstarVsMass2VsMult, + kKstarVsMass1VsMass2VsMult, + + kPairHistogramLast +}; + +enum MixingPolicy { + kVtxMult, + kVtxCent, + kVtxMultCent, + kMixingPolicyLast +}; + +// Mixing configurables +struct ConfMixing : o2::framework::ConfigurableGroup { + std::string prefix = std::string("Mixing"); + o2::framework::ConfigurableAxis multBins{"multBins", {o2::framework::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"}; + o2::framework::ConfigurableAxis centBins{"centBins", {o2::framework::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 - centrality"}; + o2::framework::ConfigurableAxis vtxBins{"vtxBins", {o2::framework::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"}; + o2::framework::Configurable depth{"depth", 5, "Number of events for mixing"}; + o2::framework::Configurable policy{"policy", 0, "Binning policy for mixing (alywas in combination with z-vertex) -> 0: multiplicity, -> 1: centrality, -> 2: both"}; + o2::framework::Configurable sameSpecies{"sameSpecies", false, "Enable if particle 1 and particle 2 are the same"}; + o2::framework::Configurable seed{"seed", -1, "Seed to randomize particle 1 and particle 2 (if they are identical). Set to negative value to deactivate. Set to 0 to generate unique seed in time."}; +}; + +struct ConfPairBinning : o2::framework::ConfigurableGroup { + std::string prefix = std::string("PairBinning"); + o2::framework::Configurable plot1D{"plot1D", true, "Enable 1D histograms"}; + o2::framework::Configurable plot2D{"plot2D", true, "Enable 2D histograms"}; + o2::framework::Configurable plotKstarVsMtVsMult{"plotKstarVsMtVsMult", false, "Enable 3D histogram (Kstar Vs Mt Vs Mult)"}; + o2::framework::Configurable plotKstarVsMtVsMultVsCent{"plotKstarVsMtVsMultVsCent", false, "Enable 4D histogram (Kstar Vs Mt Vs Mult Vs Cent)"}; + o2::framework::Configurable plotKstarVsMtVsPt1VsPt2VsMult{"plotKstarVsMtVsPt1VsPt2VsMult", false, "Enable 5D histogram (Kstar Vs Mt Vs Pt1 Vs Pt2 Vs Mult)"}; + o2::framework::Configurable plotKstarVsMtVsPt1VsPt2VsMultVsCent{"plotKstarVsMtVsPt1VsPt2VsMultVsCent", false, "Enable 6D histogram (Kstar Vs Mt Vs Pt1 Vs Pt2 Vs Mult Vs Cent)"}; + o2::framework::Configurable plotKstarVsMass1VsMass2{"plotKstarVsMass1VsMass2", false, "Enable 3D histogram (Kstar Vs Mass1 Vs Mass2)"}; + o2::framework::Configurable plotKstarVsMass1VsMult{"plotKstarVsMass1VsMult", false, "Enable 3D histogram (Kstar Vs Mass1 Vs Mult)"}; + o2::framework::Configurable plotKstarVsMass2VsMult{"plotKstarVsMass2VsMult", false, "Enable 3D histogram (Kstar Vs Mass2 Vs Mult)"}; + o2::framework::Configurable plotKstarVsMass1VsMass2VsMult{"plotKstarVsMass1VsMass2VsMult", false, "Enable 4D histogram (Kstar Vs Mass1 Vs Mass2 Vs Mult)"}; + o2::framework::ConfigurableAxis kstar{"kstar", {{600, 0, 6}}, "kstar"}; + o2::framework::ConfigurableAxis kt{"kt", {{600, 0, 6}}, "kt"}; + o2::framework::ConfigurableAxis mt{"mt", {{500, 0.8, 5.8}}, "mt"}; + o2::framework::ConfigurableAxis multiplicity{"multiplicity", {{50, 0, 200}}, "multiplicity"}; + o2::framework::ConfigurableAxis centrality{"centrality", {{10, 0, 100}}, "centrality (mult. percentile)"}; + o2::framework::ConfigurableAxis pt1{"pt1", {{100, 0, 6}}, "Pt binning for particle 1"}; + o2::framework::ConfigurableAxis pt2{"pt2", {{100, 0, 6}}, "Pt binning for particle 2"}; + o2::framework::ConfigurableAxis mass1{"mass1", {{100, 0, 2}}, "Mass binning for particle 1 (if particle has mass getter)"}; + o2::framework::ConfigurableAxis mass2{"mass2", {{100, 0, 2}}, "Mass binning for particle 2 (if particle has mass getter)"}; + o2::framework::Configurable transverseMassType{"transverseMassType", static_cast(modes::TransverseMassType::kAveragePdgMass), "Type of transverse mass (0-> Average Pdg Mass, 1-> Reduced Pdg Mass, 2-> Mt from combined 4 vector)"}; +}; + +struct ConfPairCuts : o2::framework::ConfigurableGroup { + std::string prefix = std::string("PairCuts"); + o2::framework::Configurable kstarMax{"kstarMax", -1, "Maximal kstar (set to -1 to deactivate)"}; + o2::framework::Configurable kstarMin{"kstarMin", -1, "Minimal kstar (set to -1 to deactivate)"}; + o2::framework::Configurable ktMax{"ktMax", -1, "Maximal kt (set to -1 to deactivate)"}; + o2::framework::Configurable ktMin{"ktMin", -1, "Minimal kt (set to -1 to deactivate)"}; + o2::framework::Configurable mtMax{"mtMax", -1, "Maximal mt (set to -1 to deactivate)"}; + o2::framework::Configurable mtMin{"mtMin", -1, "Minimal mt (set to -1 to deactivate)"}; +}; + +// the enum gives the correct index in the array +constexpr std::array, kPairHistogramLast> + HistTable = { + { + // 1D + {kKstar, o2::framework::kTH1F, "hKstar", "k*; k* (GeV/#it{c}); Entries"}, + {kKt, o2::framework::kTH1F, "hKt", "transverse momentum; k_{T} (GeV/#it{c}); Entries"}, + {kMt, o2::framework::kTH1F, "hMt", "transverse mass; m_{T} (GeV/#it{c}^{2}); Entries"}, + // 2D + {kPt1VsPt2, o2::framework::kTH2F, "hPt1VsPt2", " p_{T,1} vs p_{T,2}; p_{T,1} (GeV/#it{c}); p_{T,2} (GeV/#it{c})"}, + {kPt1VsKstar, o2::framework::kTH2F, "hPt1VsKstar", "p_{T,1} vs k*; p_{T,2} (GeV/#it{c}); k* (GeV/#it{c})"}, + {kPt2VsKstar, o2::framework::kTH2F, "hPt2VsKstar", "p_{T,2} vs k*; p_{T,2} (GeV/#it{c}); k* (GeV/#it{c})"}, + {kPt1VsKt, o2::framework::kTH2F, "hPt1VsKt", "p_{T,1} vs k_{T}; p_{T,1} (GeV/#it{c}); k_{T} (GeV/#it{c})"}, + {kPt2VsKt, o2::framework::kTH2F, "hPt2VsKt", "p_{T,2} vs k_{T}; p_{T,2} (GeV/#it{c}); k_{T} (GeV/#it{c})"}, + {kPt1VsMt, o2::framework::kTH2F, "hPt1VsMt", "p_{T,1} vs m_{T}; p_{T,1} (GeV/#it{c}); m_{T} (GeV/#it{c}^{2})"}, + {kPt2VsMt, o2::framework::kTH2F, "hPt2VsMt", "p_{T,2} vs m_{T}; p_{T,2} (GeV/#it{c}); m_{T} (GeV/#it{c}^{2})"}, + {kKstarVsKt, o2::framework::kTH2F, "hKstarVsKt", "k* vs k_{T}; k* (GeV/#it{c}); k_{T} (GeV/#it{c})"}, + {kKstarVsMt, o2::framework::kTH2F, "hKstarVsMt", "k* vs m_{T}; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2})"}, + {kKstarVsCent, o2::framework::kTH2F, "hKstarVsCent", "k* vs Centrality (Mult. Percentile); k* (GeV/#it{c}); Centrality (%)"}, + {kKstarVsMult, o2::framework::kTH2F, "hKstarVsMult", "k* vs Multiplicity; k* (GeV/#it{c}); Multiplicity"}, + // 2D with mass + {kKstarVsMass1, o2::framework::kTH2F, "hKstarVsMass1", "k* vs m_{1}; k* (GeV/#it{c}); m_{1} (GeV/#it{c}^{2})"}, + {kKstarVsMass2, o2::framework::kTH2F, "hKstarVsMass2", "k* vs m_{2}; k* (GeV/#it{c}); m_{2} (GeV/#it{c}^{2})"}, + {kMass1VsMass2, o2::framework::kTH2F, "hMass1VsMass2", "m_{1} vs m_{2}; m_{1} (GeV/#it{c}^{2}); m_{2} (GeV/#it{c}^{2})"}, + // n-D + {kKstarVsMtVsMult, o2::framework::kTHnSparseF, "hKstarVsMtVsMult", "k* vs m_{T} vs multiplicity; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2}); Multiplicity"}, + {kKstarVsMtVsMultVsCent, o2::framework::kTHnSparseF, "hKstarVsMtVsMultVsCent", "k* vs m_{T} vs multiplicity vs centrality; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2}); Multiplicity; Centrality (%)"}, + {kKstarVsMtVsPt1VsPt2VsMult, o2::framework::kTHnSparseF, "hKstarVsMtVsPt1VsPt2VsMult", "k* vs m_{T} vs p_{T,1} vs p_{T,2} vs multiplicity; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2}); p_{T,1} (GeV/#it{c}); p_{T,2} (GeV/#it{c}); Multiplicity"}, + {kKstarVsMtVsPt1VsPt2VsMultVsCent, o2::framework::kTHnSparseF, "hKstarVsMtVsPt1VsPt2VsMultVsCent", "k* vs m_{T} vs p_{T,1} vs p_{T,2} vs multiplicity vs centrality; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2}); p_{T,1} (GeV/#it{c}); p_{T,2} (GeV/#it{c}); Multiplicity; Centrality"}, + // n-D with mass + {kKstarVsMass1VsMass2, o2::framework::kTHnSparseF, "hKstarVsMass1VsMass2", "k* vs m_{1} vs m_{2}; k* (GeV/#it{c}); m_{1} (GeV/#it{c}^{2}); m_{2} (GeV/#it{c}^{2})"}, + {kKstarVsMass1VsMult, o2::framework::kTHnSparseF, "hKstarVsMass1VsMult", "k* vs m_{1} vs multiplicity; k* (GeV/#it{c}); m_{1} (GeV/#it{c}^{2}); Multiplicity"}, + {kKstarVsMass2VsMult, o2::framework::kTHnSparseF, "hKstarVsMass2VsMult", "k* vs m_{2} vs multiplicity; k* (GeV/#it{c}); m_{2} (GeV/#it{c}^{2}); Multiplicity"}, + {kKstarVsMass1VsMass2VsMult, o2::framework::kTHnSparseF, "hKstarVsMass1VsMass2VsMult", "k* vs m_{1} vs m_{2} vs multiplicity; k* (GeV/#it{c}); m_{1} (GeV/#it{c}^{2}); m_{2} (GeV/#it{c}^{2}); Multiplicity"}, + + }}; + +template +auto makePairHistSpecMap(const T& confPairBinning) +{ + return std::map>{ + {kKstar, {confPairBinning.kstar}}, + {kKt, {confPairBinning.kt}}, + {kMt, {confPairBinning.mt}}, + {kPt1VsPt2, {confPairBinning.pt1, confPairBinning.pt2}}, + {kPt1VsKstar, {confPairBinning.pt1, confPairBinning.kstar}}, + {kPt2VsKstar, {confPairBinning.pt2, confPairBinning.kstar}}, + {kPt1VsKt, {confPairBinning.pt1, confPairBinning.kt}}, + {kPt2VsKt, {confPairBinning.pt2, confPairBinning.kt}}, + {kPt1VsMt, {confPairBinning.pt1, confPairBinning.mt}}, + {kPt2VsMt, {confPairBinning.pt2, confPairBinning.mt}}, + {kKstarVsKt, {confPairBinning.kstar, confPairBinning.kt}}, + {kKstarVsMt, {confPairBinning.kstar, confPairBinning.mt}}, + {kKstarVsMult, {confPairBinning.kstar, confPairBinning.multiplicity}}, + {kKstarVsCent, {confPairBinning.kstar, confPairBinning.centrality}}, + + {kKstarVsMass1, {confPairBinning.kstar, confPairBinning.mass1}}, + {kKstarVsMass2, {confPairBinning.kstar, confPairBinning.mass2}}, + {kMass1VsMass2, {confPairBinning.mass1, confPairBinning.mass2}}, + + {kKstarVsMtVsMult, {confPairBinning.kstar, confPairBinning.mt, confPairBinning.multiplicity}}, + {kKstarVsMtVsMultVsCent, {confPairBinning.kstar, confPairBinning.mt, confPairBinning.multiplicity, confPairBinning.centrality}}, + {kKstarVsMtVsPt1VsPt2VsMult, {confPairBinning.kstar, confPairBinning.mt, confPairBinning.pt1, confPairBinning.pt2, confPairBinning.multiplicity}}, + {kKstarVsMtVsPt1VsPt2VsMultVsCent, {confPairBinning.kstar, confPairBinning.mt, confPairBinning.pt1, confPairBinning.pt2, confPairBinning.multiplicity, confPairBinning.centrality}}, + + {kKstarVsMass1VsMass2, {confPairBinning.kstar, confPairBinning.mass1, confPairBinning.mass2}}, + {kKstarVsMass1VsMult, {confPairBinning.kstar, confPairBinning.mass1, confPairBinning.multiplicity}}, + {kKstarVsMass2VsMult, {confPairBinning.kstar, confPairBinning.mass2, confPairBinning.multiplicity}}, + {kKstarVsMass1VsMass2VsMult, {confPairBinning.kstar, confPairBinning.mass1, confPairBinning.mass2, confPairBinning.multiplicity}}, + + }; +}; + +constexpr char PrefixTrackTrackSe[] = "TrackTrack/SE/"; +constexpr char PrefixTrackTrackMe[] = "TrackTrack/ME/"; + +constexpr char PrefixTrackV0Se[] = "TrackV0/SE/"; +constexpr char PrefixTrackV0Me[] = "TrackV0/ME/"; + +constexpr char PrefixV0V0Se[] = "V0V0/SE/"; +constexpr char PrefixV0V0Me[] = "V0V0/ME/"; + +constexpr char PrefixTrackResonanceSe[] = "TrackResonance/SE/"; +constexpr char PrefixTrackResonanceMe[] = "TrackResonance/ME/"; + +constexpr char PrefixTrackCascadeSe[] = "TrackCascade/SE/"; +constexpr char PrefixTrackCascadeMe[] = "TrackCascade/ME/"; + +constexpr char PrefixTrackKinkSe[] = "TrackKink/SE/"; +constexpr char PrefixTrackKinkMe[] = "TrackKink/ME/"; + +constexpr std::string_view AnalysisDir = "Analysis/"; +constexpr std::string_view QaDir = "QA/"; + +/// \class FemtoDreamEventHisto +/// \brief Class for histogramming event properties +// template +template +class PairHistManager +{ + public: + PairHistManager() = default; + ~PairHistManager() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& Specs, + T1 const& ConfPairBinning, + T2 const& ConfPairCuts) + { + mHistogramRegistry = registry; + + // flags for histograms + mPlot1d = ConfPairBinning.plot1D.value; + mPlot2d = ConfPairBinning.plot2D.value; + mPlotKstarVsMtVsMult = ConfPairBinning.plotKstarVsMtVsMult.value; + mPlotKstarVsMtVsMultVsCent = ConfPairBinning.plotKstarVsMtVsMultVsCent.value; + mPlotKstarVsMtVsPt1VsP2VsMult = ConfPairBinning.plotKstarVsMtVsPt1VsPt2VsMult.value; + mPlotKstarVsMtVsPt1VsP2VsMultVsCent = ConfPairBinning.plotKstarVsMtVsPt1VsPt2VsMultVsCent.value; + + mPlotKstarVsMass1VsMass2 = ConfPairBinning.plotKstarVsMass1VsMass2.value; + mPlotKstarVsMass1VsMult = ConfPairBinning.plotKstarVsMass1VsMult.value; + mPlotKstarVsMass2VsMult = ConfPairBinning.plotKstarVsMass2VsMult.value; + mPlotKstarVsMass1VsMass2VsMult = ConfPairBinning.plotKstarVsMass1VsMass2VsMult.value; + + // transverse mass type + mMtType = static_cast(ConfPairBinning.transverseMassType.value); + + // values for cuts + mKstarMin = ConfPairCuts.kstarMin.value; + mKstarMax = ConfPairCuts.kstarMax.value; + mKtMin = ConfPairCuts.ktMin.value; + mKtMax = ConfPairCuts.ktMax.value; + mMtMin = ConfPairCuts.mtMin.value; + mMtMax = ConfPairCuts.mtMax.value; + + if constexpr (isFlagSet(mode, modes::Mode::kAnalysis)) { + initAnalysis(Specs); + } + + // if constexpr (isFlagSet(mode, modes::Mode::kQA)) { + // std::string qaDir = std::string(prefix) + std::string(QaDir); + // } + } + + void setMass(int PdgParticle1, int PdgParticle2) + { + mPdgMass1 = o2::analysis::femto::utils::getMass(PdgParticle1); + mPdgMass2 = o2::analysis::femto::utils::getMass(PdgParticle2); + mAverageMass = (mPdgMass1 + mPdgMass2) / 2.f; + mReducedMass = 2.f * (mPdgMass1 * mPdgMass2) / (mPdgMass1 + mPdgMass2); + } + void setCharge(int chargeAbsParticle1, int chargeAbsParticle2) + { + // the pt stored is actually as pt/z for tracks, so in case of particles with z > 1, we have to rescale the pt (this is so far only for He3 the case) + // similarly, for neutral particles, no reason to rescale so we just set absolute charge to 1 + mAbsCharge1 = std::abs(chargeAbsParticle1); + mAbsCharge2 = std::abs(chargeAbsParticle2); + } + + template + void setPair(const T1& particle1, const T2& particle2) + { + // pt in track table is calculated from 1/signedPt from the original track table + // in case of He with Z=2, we have to rescale the pt with the absolute charge + mParticle1 = ROOT::Math::PtEtaPhiMVector{mAbsCharge1 * particle1.pt(), particle1.eta(), particle1.phi(), mPdgMass1}; + mParticle2 = ROOT::Math::PtEtaPhiMVector{mAbsCharge2 * particle2.pt(), particle2.eta(), particle2.phi(), mPdgMass2}; + auto partSum = mParticle1 + mParticle2; + + // set kT + mKt = partSum.Pt() / 2.f; + + // set mT + computeMt(partSum); + + // Boost particle to the pair rest frame (Prf) and calculate k* (would be equivalent using particle 2) + // make a copy of particle 1 + auto particle1Prf = ROOT::Math::PtEtaPhiMVector(mParticle1); + // get lorentz boost into pair rest frame + ROOT::Math::Boost boostPrf(partSum.BoostToCM()); + // boost particle 1 into pair rest frame and calculate its momentum, which has the same value as k* + mKstar = boostPrf(particle1Prf).P(); + + // if one of the particles has a mass getter, we cache the value for the filling later + if constexpr (modes::hasMass(particleType1)) { + mMass1 = particle1.mass(); + } + if constexpr (modes::hasMass(particleType2)) { + mMass2 = particle2.mass(); + } + } + + template + void setPair(const T1& particle1, const T2& particle2, const T3& col) + { + mMult = col.mult(); + mCent = col.cent(); + setPair(particle1, particle2); + } + + template + void setPair(const T1& particle1, const T2& particle2, const T3& col1, const T4& col2) + { + mMult = 0.5f * (col1.mult() + col2.mult()); // if mixing with multiplicity, should be in the same mixing bin + mCent = 0.5f * (col1.cent() + col2.cent()); // if mixing with centrality, should be in the same mixing bin + setPair(particle1, particle2); + } + + bool checkPairCuts() const + { + return (!(mKstarMin > 0.f) || mKstar > mKstarMin) && + (!(mKstarMax > 0.f) || mKstar < mKstarMax) && + (!(mKtMin > 0.f) || mKt > mKtMin) && + (!(mKtMax > 0.f) || mKt < mKtMax) && + (!(mMtMin > 0.f) || mMt > mMtMin) && + (!(mMtMax > 0.f) || mMt < mMtMax); + } + + void fill() + { + if constexpr (isFlagSet(mode, modes::Mode::kAnalysis)) { + fillAnalysis(); + } + } + + float getKstar() const { return mKstar; } + + private: + void initAnalysis(std::map> const& Specs) + { + std::string analysisDir = std::string(prefix) + std::string(AnalysisDir); + if (mPlot1d) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstar, HistTable), getHistDesc(kKstar, HistTable), getHistType(kKstar, HistTable), {Specs.at(kKstar)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kKt, HistTable), getHistDesc(kKt, HistTable), getHistType(kKt, HistTable), {Specs.at(kKt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMt, HistTable), getHistDesc(kMt, HistTable), getHistType(kMt, HistTable), {Specs.at(kMt)}); + } + if (mPlot2d) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt1VsPt2, HistTable), getHistDesc(kPt1VsPt2, HistTable), getHistType(kPt1VsPt2, HistTable), {Specs.at(kPt1VsPt2)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt1VsKstar, HistTable), getHistDesc(kPt1VsKstar, HistTable), getHistType(kPt1VsKstar, HistTable), {Specs.at(kPt1VsKstar)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt2VsKstar, HistTable), getHistDesc(kPt2VsKstar, HistTable), getHistType(kPt2VsKstar, HistTable), {Specs.at(kPt2VsKstar)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt1VsKt, HistTable), getHistDesc(kPt1VsKt, HistTable), getHistType(kPt1VsKt, HistTable), {Specs.at(kPt1VsKt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt2VsKt, HistTable), getHistDesc(kPt2VsKt, HistTable), getHistType(kPt2VsKt, HistTable), {Specs.at(kPt2VsKt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt1VsMt, HistTable), getHistDesc(kPt1VsMt, HistTable), getHistType(kPt1VsMt, HistTable), {Specs.at(kPt1VsMt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt2VsMt, HistTable), getHistDesc(kPt2VsMt, HistTable), getHistType(kPt2VsMt, HistTable), {Specs.at(kPt2VsMt)}); + + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsKt, HistTable), getHistDesc(kKstarVsKt, HistTable), getHistType(kKstarVsKt, HistTable), {Specs.at(kKstarVsKt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMt, HistTable), getHistDesc(kKstarVsMt, HistTable), getHistType(kKstarVsMt, HistTable), {Specs.at(kKstarVsMt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMult, HistTable), getHistDesc(kKstarVsMult, HistTable), getHistType(kKstarVsMult, HistTable), {Specs.at(kKstarVsMult)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsCent, HistTable), getHistDesc(kKstarVsCent, HistTable), getHistType(kKstarVsCent, HistTable), {Specs.at(kKstarVsCent)}); + + // special care for mass plots since not all particles have "mass" + if constexpr (modes::hasMass(particleType1)) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMass1, HistTable), getHistDesc(kKstarVsMass1, HistTable), getHistType(kKstarVsMass1, HistTable), {Specs.at(kKstarVsMass1)}); + } + if constexpr (modes::hasMass(particleType2)) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMass2, HistTable), getHistDesc(kKstarVsMass2, HistTable), getHistType(kKstarVsMass2, HistTable), {Specs.at(kKstarVsMass2)}); + } + if constexpr (modes::hasMass(particleType1) && modes::hasMass(particleType2)) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kMass1VsMass2, HistTable), getHistDesc(kMass1VsMass2, HistTable), getHistType(kMass1VsMass2, HistTable), {Specs.at(kMass1VsMass2)}); + } + } + + if (mPlotKstarVsMtVsMult) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMtVsMult, HistTable), getHistDesc(kKstarVsMtVsMult, HistTable), getHistType(kKstarVsMtVsMult, HistTable), {Specs.at(kKstarVsMtVsMult)}); + } + if (mPlotKstarVsMtVsMultVsCent) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMtVsMultVsCent, HistTable), getHistDesc(kKstarVsMtVsMultVsCent, HistTable), getHistType(kKstarVsMtVsMultVsCent, HistTable), {Specs.at(kKstarVsMtVsMultVsCent)}); + } + if (mPlotKstarVsMtVsPt1VsP2VsMult) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMtVsPt1VsPt2VsMult, HistTable), getHistDesc(kKstarVsMtVsPt1VsPt2VsMult, HistTable), getHistType(kKstarVsMtVsPt1VsPt2VsMult, HistTable), {Specs.at(kKstarVsMtVsPt1VsPt2VsMult)}); + } + if (mPlotKstarVsMtVsPt1VsP2VsMultVsCent) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMtVsPt1VsPt2VsMultVsCent, HistTable), getHistDesc(kKstarVsMtVsPt1VsPt2VsMultVsCent, HistTable), getHistType(kKstarVsMtVsPt1VsPt2VsMultVsCent, HistTable), {Specs.at(kKstarVsMtVsPt1VsPt2VsMultVsCent)}); + } + + // again special care for particles with "mass" + if constexpr (modes::hasMass(particleType1)) { + if (mPlotKstarVsMass1VsMult) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMass1VsMult, HistTable), getHistDesc(kKstarVsMass1VsMult, HistTable), getHistType(kKstarVsMass1VsMult, HistTable), {Specs.at(kKstarVsMass1VsMult)}); + } + } + if constexpr (modes::hasMass(particleType2)) { + if (mPlotKstarVsMass2VsMult) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMass2VsMult, HistTable), getHistDesc(kKstarVsMass2VsMult, HistTable), getHistType(kKstarVsMass2VsMult, HistTable), {Specs.at(kKstarVsMass2VsMult)}); + } + } + if constexpr (modes::hasMass(particleType1) && modes::hasMass(particleType2)) { + if (mPlotKstarVsMass1VsMass2) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMass1VsMass2, HistTable), getHistDesc(kKstarVsMass1VsMass2, HistTable), getHistType(kKstarVsMass1VsMass2, HistTable), {Specs.at(kKstarVsMass1VsMass2)}); + } + if (mPlotKstarVsMass1VsMass2VsMult) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMass1VsMass2VsMult, HistTable), getHistDesc(kKstarVsMass1VsMass2VsMult, HistTable), getHistType(kKstarVsMass1VsMass2VsMult, HistTable), {Specs.at(kKstarVsMass1VsMass2VsMult)}); + } + } + } + + void fillAnalysis() + { + if (mPlot1d) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstar, HistTable)), mKstar); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kMt, HistTable)), mMt); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKt, HistTable)), mKt); + } + if (mPlot2d) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt1VsPt2, HistTable)), mParticle1.Pt(), mParticle2.Pt()); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt1VsKstar, HistTable)), mParticle1.Pt(), mKstar); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt1VsMt, HistTable)), mParticle1.Pt(), mMt); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt1VsKt, HistTable)), mParticle1.Pt(), mKt); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt2VsKstar, HistTable)), mParticle2.Pt(), mKstar); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt2VsMt, HistTable)), mParticle2.Pt(), mMt); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt2VsKt, HistTable)), mParticle2.Pt(), mKt); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsKt, HistTable)), mKstar, mKt); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMt, HistTable)), mKstar, mMt); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMult, HistTable)), mKstar, mMult); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsCent, HistTable)), mKstar, mCent); + + // // special care for mass plots since not all particles have "mass" + if constexpr (modes::hasMass(particleType1)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMass1, HistTable)), mKstar, mMass1); + } + if constexpr (modes::hasMass(particleType2)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMass2, HistTable)), mKstar, mMass2); + } + if constexpr (modes::hasMass(particleType1) && modes::hasMass(particleType2)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kMass1VsMass2, HistTable)), mMass1, mMass2); + } + } + + // n-D histograms are only filled if enabled + if (mPlotKstarVsMtVsMult) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMtVsMult, HistTable)), mKstar, mMt, mMult); + } + if (mPlotKstarVsMtVsMultVsCent) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMtVsMultVsCent, HistTable)), mKstar, mMt, mMult, mCent); + } + if (mPlotKstarVsMtVsPt1VsP2VsMult) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMtVsPt1VsPt2VsMult, HistTable)), mKstar, mMt, mParticle1.Pt(), mParticle2.pt(), mMult); + } + if (mPlotKstarVsMtVsPt1VsP2VsMultVsCent) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMtVsPt1VsPt2VsMultVsCent, HistTable)), mKstar, mMt, mParticle1.Pt(), mParticle2.pt(), mMult, mCent); + } + + // again special care for particles with "mass" + if constexpr (modes::hasMass(particleType1)) { + if (mPlotKstarVsMass1VsMult) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMass1VsMult, HistTable)), mKstar, mMass1, mMult); + } + } + if constexpr (modes::hasMass(particleType2)) { + if (mPlotKstarVsMass2VsMult) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMass2VsMult, HistTable)), mKstar, mMass2, mMult); + } + } + if constexpr (modes::hasMass(particleType1) && modes::hasMass(particleType2)) { + if (mPlotKstarVsMass1VsMass2) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMass1VsMass2, HistTable)), mKstar, mMass1, mMass2); + } + if (mPlotKstarVsMass1VsMass2VsMult) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMass1VsMass2VsMult, HistTable)), mKstar, mMass1, mMass2, mMult); + } + } + } + + void computeMt(ROOT::Math::PtEtaPhiMVector const& PairMomentum) + { + switch (mMtType) { + case modes::TransverseMassType::kAveragePdgMass: + mMt = std::hypot(PairMomentum.Pt() / 2.f, mAverageMass); + break; + case modes::TransverseMassType::kReducedPdgMass: + mMt = std::hypot(PairMomentum.Pt() / 2.f, mReducedMass); + break; + case modes::TransverseMassType::kMt4Vector: + mMt = PairMomentum.Mt() / 2.f; + break; + default: + mMt = std::hypot(mKt, mAverageMass); + } + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + float mPdgMass1 = 0.f; + float mPdgMass2 = 0.f; + + modes::TransverseMassType mMtType = modes::TransverseMassType::kAveragePdgMass; + float mAverageMass = 0.f; + float mReducedMass = 0.f; + + int mAbsCharge1 = 1; + int mAbsCharge2 = 1; + ROOT::Math::PtEtaPhiMVector mParticle1{}; + ROOT::Math::PtEtaPhiMVector mParticle2{}; + float mMass1 = 0.f; + float mMass2 = 0.f; + float mKstar = 0.f; + float mKt = 0.f; + float mMt = 0.f; + float mMult = 0.f; + float mCent = 0.f; + + // cuts + float mKstarMin = -1.f; + float mKstarMax = -1.f; + float mKtMin = -1.f; + float mKtMax = -1.f; + float mMtMin = -1.f; + float mMtMax = -1.f; + + // flags + bool mPlot1d = true; + bool mPlot2d = true; + bool mPlotKstarVsMtVsMult = false; + bool mPlotKstarVsMtVsMultVsCent = false; + bool mPlotKstarVsMtVsPt1VsP2VsMult = false; + bool mPlotKstarVsMtVsPt1VsP2VsMultVsCent = false; + + bool mPlotKstarVsMass1VsMass2 = false; + bool mPlotKstarVsMass1VsMult = false; + bool mPlotKstarVsMass2VsMult = false; + bool mPlotKstarVsMass1VsMass2VsMult = false; +}; + +}; // namespace pairhistmanager +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_PAIRHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/pairProcessHelpers.h b/PWGCF/Femto/Core/pairProcessHelpers.h new file mode 100644 index 00000000000..a4b69c85a4d --- /dev/null +++ b/PWGCF/Femto/Core/pairProcessHelpers.h @@ -0,0 +1,228 @@ +// 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 pairProcessHelpers.h +/// \brief process functions used in pair tasks +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_PAIRPROCESSHELPERS_H_ +#define PWGCF_FEMTO_CORE_PAIRPROCESSHELPERS_H_ + +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoAHelpers.h" + +#include + +namespace o2::analysis::femto +{ +namespace pairprocesshelpers +{ + +// process same event for identical particles +template +void processSameEvent(T1 const& SliceParticle, + T2 const& TrackTable, + T3 const& Collision, + T4& ParticleHistManager, + T5& PairHistManager, + T6& CprManager, + T7& PcManager, + T8& rng, + bool randomize) +{ + for (auto const& part : SliceParticle) { + ParticleHistManager.fill(part, TrackTable); + } + std::uniform_real_distribution dist(0.f, 1.f); + for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(SliceParticle, SliceParticle))) { + // check if pair is clean + if (!PcManager.isCleanPair(p1, p2, TrackTable)) { + continue; + } + // check if pair is close + CprManager.setPair(p1, p2, TrackTable); + if (CprManager.isClosePair()) { + continue; + } + // Randomize pair order if enabled + float threshold = 0.5f; + bool swapPair = randomize ? (dist(rng) > threshold) : false; + if (swapPair) { + PairHistManager.setPair(p2, p1, Collision); + } else { + PairHistManager.setPair(p1, p2, Collision); + } + // fill deta-dphi histograms with kstar cutoff + CprManager.fill(PairHistManager.getKstar()); + // if pair cuts are configured check them before filling + if (PairHistManager.checkPairCuts()) { + PairHistManager.fill(); + } + } +} + +// process same event for non-identical particles +template +void processSameEvent(T1 const& SliceParticle1, + T2 const& SliceParticle2, + T3 const& TrackTable, + T4 const& Collision, + T5& ParticleHistManager1, + T6& ParticleHistManager2, + T7& PairHistManager, + T8& CprManager, + T9& PcManager) +{ + // Fill single particle histograms + for (auto const& part : SliceParticle1) { + ParticleHistManager1.fill(part, TrackTable); + } + for (auto const& part : SliceParticle2) { + ParticleHistManager2.fill(part, TrackTable); + } + for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(SliceParticle1, SliceParticle2))) { + // pair cleaning + if (!PcManager.isCleanPair(p1, p2, TrackTable)) { + continue; + } + // Close pair rejection + CprManager.setPair(p1, p2, TrackTable); + if (CprManager.isClosePair()) { + continue; + } + PairHistManager.setPair(p1, p2, Collision); + CprManager.fill(PairHistManager.getKstar()); + if (PairHistManager.checkPairCuts()) { + PairHistManager.fill(); + } + } +} + +// process mixed event for identical particles +template +void processMixedEvent(T1& Collisions, + T2& Partition, + T3& TrackTable, + T4& cache, + T5& policy, + T6& depth, + T7& PairHistManager, + T8& CprManager, + T9& PcManager) +{ + for (auto const& [collision1, collision2] : o2::soa::selfCombinations(policy, depth, -1, Collisions, Collisions)) { + if (!(std::fabs(collision1.magField() - collision2.magField()) < o2::constants::math::Epsilon)) { + continue; + } + CprManager.setMagField(collision1.magField()); + auto sliceParticle1 = Partition->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache); + auto sliceParticle2 = Partition->sliceByCached(o2::aod::femtobase::stored::fColId, collision2.globalIndex(), cache); + if (sliceParticle1.size() == 0 || sliceParticle2.size() == 0) { + continue; + } + for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(sliceParticle1, sliceParticle2))) { + // pair cleaning + if (!PcManager.isCleanPair(p1, p2, TrackTable)) { + continue; + } + // Close pair rejection + CprManager.setPair(p1, p2, TrackTable); + if (CprManager.isClosePair()) { + continue; + } + PairHistManager.setPair(p1, p2, collision1, collision2); + CprManager.fill(PairHistManager.getKstar()); + if (PairHistManager.checkPairCuts()) { + PairHistManager.fill(); + } + } + } +} + +// process mixed event different particles +template +void processMixedEvent(T1& Collisions, + T2& Partition1, + T3& Partition2, + T4& TrackTable, + T5& cache, + T6& policy, + T7& depth, + T8& PairHistManager, + T9& CprManager, + T10& PcManager) +{ + for (auto const& [collision1, collision2] : o2::soa::selfCombinations(policy, depth, -1, Collisions, Collisions)) { + if (!(std::fabs(collision1.magField() - collision2.magField()) < o2::constants::math::Epsilon)) { + continue; + } + CprManager.setMagField(collision1.magField()); + auto sliceParticle1 = Partition1->sliceByCached(o2::aod::femtobase::stored::fColId, collision1.globalIndex(), cache); + auto sliceParticle2 = Partition2->sliceByCached(o2::aod::femtobase::stored::fColId, collision2.globalIndex(), cache); + if (sliceParticle1.size() == 0 || sliceParticle2.size() == 0) { + continue; + } + for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(sliceParticle1, sliceParticle2))) { + // pair cleaning + if (!PcManager.isCleanPair(p1, p2, TrackTable)) { + continue; + } + // Close pair rejection + CprManager.setPair(p1, p2, TrackTable); + if (CprManager.isClosePair()) { + continue; + } + PairHistManager.setPair(p1, p2, collision1, collision2); + CprManager.fill(PairHistManager.getKstar()); + if (PairHistManager.checkPairCuts()) { + PairHistManager.fill(); + } + } + } +} +} // namespace pairprocesshelpers +} // namespace o2::analysis::femto + +#endif // PWGCF_FEMTO_CORE_PAIRPROCESSHELPERS_H_ diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h new file mode 100644 index 00000000000..d399729d66b --- /dev/null +++ b/PWGCF/Femto/Core/partitions.h @@ -0,0 +1,142 @@ +// 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 partitions.h +/// \brief common partition definitons +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_PARTITIONS_H_ +#define PWGCF_FEMTO_CORE_PARTITIONS_H_ + +// collsion selection +#define MAKE_COLLISION_FILTER(selection) \ + (femtocollisions::posZ >= selection.vtxZMin && femtocollisions::posZ <= selection.vtxZMax) && \ + (femtocollisions::mult >= selection.multMin && femtocollisions::mult <= selection.multMax) && \ + (femtocollisions::cent >= selection.centMin && femtocollisions::cent <= selection.centMax) && \ + (femtocollisions::magField >= static_cast(selection.magFieldMin) && femtocollisions::magField <= static_cast(selection.magFieldMax)) && \ + ncheckbit(femtocollisions::mask, selection.collisionMask) + +// standard track partition +#define MAKE_TRACK_PARTITION(selection) \ + ifnode(selection.chargeSign.node() != 0, ifnode(selection.chargeSign.node() > 0, femtobase::stored::signedPt > 0.f, femtobase::stored::signedPt < 0.f), true) && \ + (nabs(selection.chargeAbs.node() * femtobase::stored::signedPt) > selection.ptMin) && \ + (nabs(selection.chargeAbs.node() * femtobase::stored::signedPt) < selection.ptMax) && \ + (femtobase::stored::eta > selection.etaMin) && \ + (femtobase::stored::eta < selection.etaMax) && \ + (femtobase::stored::phi > selection.phiMin) && \ + (femtobase::stored::phi < selection.phiMax) && \ + ifnode(nabs(selection.chargeAbs.node() * femtobase::stored::signedPt) * (nexp(femtobase::stored::eta) + nexp(-1.f * femtobase::stored::eta)) / (2.f) <= selection.pidThres, \ + ncheckbit(femtotracks::mask, selection.maskLowMomentum), \ + ncheckbit(femtotracks::mask, selection.maskHighMomentum)) + +// partition for phis and rhos, i.e. resonance that are their own antiparticle +#define MAKE_RESONANCE_0_PARTITON(selection) \ + (femtobase::stored::pt > selection.ptMin) && \ + (femtobase::stored::pt < selection.ptMax) && \ + (femtobase::stored::eta > selection.etaMin) && \ + (femtobase::stored::eta < selection.etaMax) && \ + (femtobase::stored::phi > selection.phiMin) && \ + (femtobase::stored::phi < selection.phiMax) && \ + (femtobase::stored::mass > selection.massMin) && \ + (femtobase::stored::mass < selection.massMax) && \ + ifnode(ncheckbit(femtotwotrackresonances::mask, selection.posDauBitForThres), \ + ncheckbit(femtotwotrackresonances::mask, selection.posDauMaskAboveThres), \ + ncheckbit(femtotwotrackresonances::mask, selection.posDauMaskBelowThres)) && \ + ifnode(ncheckbit(femtotwotrackresonances::mask, selection.negDauBitForThres), \ + ncheckbit(femtotwotrackresonances::mask, selection.negDauMaskAboveThres), \ + ncheckbit(femtotwotrackresonances::mask, selection.negDauMaskBelowThres)) + +// partition for kstars, they have distinct antiparticle +#define MAKE_RESONANCE_1_PARTITON(selection) \ + ifnode(selection.sign.node() != 0, \ + ifnode(selection.sign.node() > 0, femtobase::stored::signedPt > 0.f, femtobase::stored::signedPt < 0.f), true) && \ + (nabs(femtobase::stored::signedPt) > selection.ptMin) && \ + (nabs(femtobase::stored::signedPt) < selection.ptMax) && \ + (femtobase::stored::eta > selection.etaMin) && \ + (femtobase::stored::eta < selection.etaMax) && \ + (femtobase::stored::phi > selection.phiMin) && \ + (femtobase::stored::phi < selection.phiMax) && \ + (femtobase::stored::mass > selection.massMin) && \ + (femtobase::stored::mass < selection.massMax) && \ + ifnode(ncheckbit(femtotwotrackresonances::mask, selection.posDauBitForThres), \ + ncheckbit(femtotwotrackresonances::mask, selection.posDauMaskAboveThres), \ + ncheckbit(femtotwotrackresonances::mask, selection.posDauMaskBelowThres)) && \ + ifnode(ncheckbit(femtotwotrackresonances::mask, selection.negDauBitForThres), \ + ncheckbit(femtotwotrackresonances::mask, selection.negDauMaskAboveThres), \ + ncheckbit(femtotwotrackresonances::mask, selection.negDauMaskBelowThres)) + +// partition for lambdas +#define MAKE_LAMBDA_PARTITION(selection) \ + ifnode(selection.sign.node() != 0, \ + ifnode(selection.sign.node() > 0, femtobase::stored::signedPt > 0.f, femtobase::stored::signedPt < 0.f), true) && \ + (nabs(femtobase::stored::signedPt) > selection.ptMin) && \ + (nabs(femtobase::stored::signedPt) < selection.ptMax) && \ + (femtobase::stored::eta > selection.etaMin) && \ + (femtobase::stored::eta < selection.etaMax) && \ + (femtobase::stored::phi > selection.phiMin) && \ + (femtobase::stored::phi < selection.phiMax) && \ + (femtobase::stored::mass > selection.massMin) && \ + (femtobase::stored::mass < selection.massMax) && \ + ncheckbit(femtov0s::mask, selection.mask) + +// partition for k0shorts +// need special partition since k0shorts have no antiparticle +#define MAKE_K0SHORT_PARTITION(selection) \ + (femtobase::stored::pt > selection.ptMin) && \ + (femtobase::stored::pt < selection.ptMax) && \ + (femtobase::stored::eta > selection.etaMin) && \ + (femtobase::stored::eta < selection.etaMax) && \ + (femtobase::stored::phi > selection.phiMin) && \ + (femtobase::stored::phi < selection.phiMax) && \ + (femtobase::stored::mass > selection.massMin) && \ + (femtobase::stored::mass < selection.massMax) && \ + ncheckbit(femtov0s::mask, selection.mask) + +#define MAKE_CASCADE_PARTITION(selection) \ + ifnode(selection.sign.node() != 0, \ + ifnode(selection.sign.node() > 0, femtobase::stored::signedPt > 0.f, femtobase::stored::signedPt < 0.f), true) && \ + (nabs(femtobase::stored::signedPt) > selection.ptMin) && \ + (nabs(femtobase::stored::signedPt) < selection.ptMax) && \ + (femtobase::stored::eta > selection.etaMin) && \ + (femtobase::stored::eta < selection.etaMax) && \ + (femtobase::stored::phi > selection.phiMin) && \ + (femtobase::stored::phi < selection.phiMax) && \ + (femtobase::stored::mass > selection.massMin) && \ + (femtobase::stored::mass < selection.massMax) && \ + ncheckbit(femtocascades::mask, selection.mask) + +#define MAKE_SIGMA_PARTITION(selection) \ + ifnode(selection.sign.node() != 0, \ + ifnode(selection.sign.node() > 0, femtobase::stored::signedPt > 0.f, femtobase::stored::signedPt < 0.f), true) && \ + (nabs(femtobase::stored::signedPt) > selection.ptMin) && \ + (nabs(femtobase::stored::signedPt) < selection.ptMax) && \ + (femtobase::stored::eta > selection.etaMin) && \ + (femtobase::stored::eta < selection.etaMax) && \ + (femtobase::stored::phi > selection.phiMin) && \ + (femtobase::stored::phi < selection.phiMax) && \ + (femtobase::stored::mass > selection.massMin) && \ + (femtobase::stored::mass < selection.massMax) && \ + ncheckbit(femtokinks::mask, selection.mask) + +#define MAKE_SIGMAPLUS_PARTITION(selection) \ + ifnode(selection.sign.node() != 0, \ + ifnode(selection.sign.node() > 0, femtobase::stored::signedPt > 0.f, femtobase::stored::signedPt < 0.f), true) && \ + (nabs(femtobase::stored::signedPt) > selection.ptMin) && \ + (nabs(femtobase::stored::signedPt) < selection.ptMax) && \ + (femtobase::stored::eta > selection.etaMin) && \ + (femtobase::stored::eta < selection.etaMax) && \ + (femtobase::stored::phi > selection.phiMin) && \ + (femtobase::stored::phi < selection.phiMax) && \ + (femtobase::stored::mass > selection.massMin) && \ + (femtobase::stored::mass < selection.massMax) && \ + ncheckbit(femtokinks::mask, selection.mask) + +#endif // PWGCF_FEMTO_CORE_PARTITIONS_H_ diff --git a/PWGCF/Femto/Core/selectionContainer.h b/PWGCF/Femto/Core/selectionContainer.h new file mode 100644 index 00000000000..e9d67e6354a --- /dev/null +++ b/PWGCF/Femto/Core/selectionContainer.h @@ -0,0 +1,431 @@ +// 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 selectionContainer.h +/// \brief Defines the SelectionContainer class for managing selection criteria in analysis. +/// \author Anton Riedel, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_SELECTIONCONTAINER_H_ +#define PWGCF_FEMTO_CORE_SELECTIONCONTAINER_H_ + +#include "CommonConstants/MathConstants.h" + +#include "TF1.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ + +/// Limit type for selections +namespace limits +{ +enum LimitType { kUpperLimit, ///< simple upper limit for the value, e.g. p_T < 1 GeV/c + kAbsUpperLimit, ///< upper limit of the absolute value, e.g. |eta| < 0.8 + kLowerLimit, ///< simple lower limit for the value, e.g. p_T > 0.2 GeV/c + kAbsLowerLimit, ///< lower limit of the absolute value, e.g. |DCA_xyz| > 0.05 cm + kUpperFunctionLimit, ///< simple upper limit of a function value, e.g. DCA_xy > f(pt) + kAbsUpperFunctionLimit, ///< upper limit of an absolute value given by a function, e.g. |DCA_xy| > f(pt) + kLowerFunctionLimit, ///< simple lower limit of a function value, e.g. DCA_xy < f(pt) + kAbsLowerFunctionLimit, ///< lower limit of an absolute value given by a function, e.g. |DCA_xy| < f(pt) + kEqual, ///< values need to be equal, e.g. sign = 1 + kEqualArray, ///< values inside an array need to be equal + kLimitTypeLast +}; + +std::unordered_map limitTypeAsStrings = { + {kUpperLimit, "Upper Limit"}, + {kAbsUpperLimit, "Absolute Upper Limit"}, + {kLowerLimit, "Lower Limit"}, + {kAbsLowerLimit, "Absolute Lower Limit"}, + {kUpperFunctionLimit, "Upper Function Limit"}, + {kAbsUpperFunctionLimit, "Absolute Upper Function Limit"}, + {kLowerFunctionLimit, "Lower Function Limit"}, + {kAbsLowerFunctionLimit, "Absolute Lower Function Limit"}, + {kEqual, "Equal"}, + {kEqualArray, "EqualArray"}, + +}; + +}; // namespace limits + +/// \class SelectionContainer +/// \brief Class for storing and evaluating multiple selection thresholds for a single observable. +/// \tparam T Data type for selection values (mostly floats) +/// \tparam BitmaskType Type used for bitmask storage (e.g., uint8_t, uint32_t). +template +class SelectionContainer +{ + public: + /// Default constructor + SelectionContainer() = default; + ~SelectionContainer() = default; + + /// \brief Constructor for static value-based selection. + /// \param SelectionValues Vector of values for the selection. + /// \param limitType Type of limit (from limits::LimitType). + /// \param SkipMostPermissiveBit Whether to skip the most permissive bit in the bitmask. + /// \param IsMinimalCut Whether this selection should be treated as a minimal required cut. + SelectionContainer(std::string const& SelectionName, + std::vector const& SelectionValues, + limits::LimitType limitType, + bool SkipMostPermissiveBit, + bool IsMinimalCut, + bool isOptionalCut) + : mSelectionName(SelectionName), + mSelectionValues(SelectionValues), + mLimitType(limitType), + mSkipMostPermissiveBit(SkipMostPermissiveBit), + mIsMinimalCut(IsMinimalCut), + mIsOptionalCut(isOptionalCut) + { + if (mSelectionValues.size() > sizeof(BitmaskType) * CHAR_BIT) { + LOG(fatal) << "Too many selections for single a observable. Limit is " << sizeof(BitmaskType) * CHAR_BIT; + } + // values for selection are not necessarily ordered correctly + sortSelections(); + } + + /// \brief Constructor for function-based dynamic selection. + /// \param baseName Base name for TF1 functions. + /// \param lowerLimit Lower bound for TF1 domain. + /// \param upperLimit Upper bound for TF1 domain. + /// \param functions Vector of strings defining TF1 functions. + /// \param limitType Type of limit. + /// \param skipMostPermissiveBit Whether to skip the most permissive bit in the bitmask. + /// \param IsMinimalCut Whether this selection should be treated as a minimal required cut. + SelectionContainer(std::string const& SelectionName, + T lowerLimit, + T upperLimit, + std::vector const& functions, + limits::LimitType limitType, + bool skipMostPermissiveBit, + bool IsMinimalCut, + bool isOptionalCut) + : mSelectionName(SelectionName), + mLimitType(limitType), + mSkipMostPermissiveBit(skipMostPermissiveBit), + mIsMinimalCut(IsMinimalCut), + mIsOptionalCut(isOptionalCut) + { + if (functions.size() > sizeof(BitmaskType) * CHAR_BIT) { + LOG(fatal) << "Too many selections for single a observable. Limit is " << sizeof(BitmaskType) * CHAR_BIT; + } + for (std::size_t i = 0; i < functions.size(); i++) { + mSelectionFunctions.emplace_back((mSelectionName + std::to_string(i)).c_str(), functions.at(i).c_str(), lowerLimit, upperLimit); + } + // functions for selection are not necessarily ordered correctly + // use value at midpoint to order them + // here we rely on the user that the functions can be ordered like this over the whole interval + T midPoint = (lowerLimit + upperLimit) / 2.; + sortFunctions(midPoint); + // initialize the values also to the midpoint + for (std::size_t i = 0; i < functions.size(); i++) { + mSelectionValues.push_back(mSelectionFunctions.at(i).Eval(midPoint)); + } + } + + /// \brief Sort static selection values based on the limit type. + void sortSelections() + { + switch (mLimitType) { + case (limits::kUpperLimit): + case (limits::kAbsUpperLimit): + std::sort(mSelectionValues.begin(), mSelectionValues.end(), [](T a, T b) { return a > b; }); + break; + case (limits::kLowerLimit): + case (limits::kAbsLowerLimit): + std::sort(mSelectionValues.begin(), mSelectionValues.end(), [](T a, T b) { return a < b; }); + break; + default: + break; + } + } + + /// \brief Sort selection functions based on evaluation at a given point. + /// \param value Point at which to evaluate the functions for ordering. + void sortFunctions(T value) + { + switch (mLimitType) { + case (limits::kUpperFunctionLimit): + case (limits::kAbsUpperFunctionLimit): + std::sort(mSelectionFunctions.begin(), mSelectionFunctions.end(), [value](TF1 const& a, TF1 const& b) { return a.Eval(value) > b.Eval(value); }); + break; + case (limits::kLowerFunctionLimit): + case (limits::kAbsLowerFunctionLimit): + std::sort(mSelectionFunctions.begin(), mSelectionFunctions.end(), [value](TF1 const& a, TF1 const& b) { return a.Eval(value) < b.Eval(value); }); + break; + default: + break; + } + } + + /// \brief Add comments to the selection values + /// \param comments Vector of comments + void addComments(std::vector const& comments) + { + // make sure that the comments are in correct order + // the values passed to the selection container can be reordered based on the limit type + mComments = comments; + } + + std::vector const& getComments() const { return mComments; } + std::string const& getSelectionName() const { return mSelectionName; } + + /// \brief Update selection limits using internal functions evaluated at a given value. + /// \param value Input value to evaluate functions at. + void updateLimits(T value) + { + // functions are ordered so just add the values in the same order + for (std::size_t i = 0; i < mSelectionValues.size(); i++) { + mSelectionValues.at(i) = mSelectionFunctions.at(i).Eval(value); + } + } + + /// \brief Evaluate which selection criteria are fulfilled for a given value. + /// \param value Value of the observable to evaluate. + void evaluate(T value) + { + // better safe than sorry and reset the bitmask before you evaluate and set minimal selection to true + mBitmask.reset(); + // the values are ordered, from most loose to most tight, as soon as one comparison is not true, we can break out of the loop + bool breakLoop = false; + // iterate over all limits and set the corresponding bit if we pass the selection, otherwise break out as soon as we can + // only break if the observable is used for the minimal selection + for (size_t i = 0; i < mSelectionValues.size(); i++) { + switch (mLimitType) { + case (limits::kUpperLimit): + case (limits::kUpperFunctionLimit): + if (value <= mSelectionValues.at(i)) { + mBitmask.set(i); + } else { + breakLoop = true; + } + break; + case (limits::kAbsUpperLimit): + case (limits::kAbsUpperFunctionLimit): + if (std::abs(value) <= mSelectionValues.at(i)) { + mBitmask.set(i); + } else { + breakLoop = true; + } + break; + case (limits::kLowerLimit): + case (limits::kLowerFunctionLimit): + if (value >= mSelectionValues.at(i)) { + mBitmask.set(i); + } else { + breakLoop = true; + } + break; + case (limits::kAbsLowerLimit): + case (limits::kAbsLowerFunctionLimit): + if (std::abs(value) >= mSelectionValues.at(i)) { + mBitmask.set(i); + } else { + breakLoop = true; + } + break; + case (limits::kEqual): + // special case for kEqual since here we cannot really establish an order so we need to check all cases explicitly and we cannot bail early + if (std::fabs(value - mSelectionValues.at(i)) < constants::math::Epsilon) { + mBitmask.set(i); + } + break; + default: + breakLoop = true; + } + // bail early if a comparison fails + // the values are ordered, so all following we also fail, there there is no point in contiuing + if (breakLoop) { + break; + } + } + } + + /// \brief Evaluate which selection criteria are fulfilled for a given value. + /// \param values Values of the observable to evaluate + void evaluate(std::vector const& values) + { + if (values.size() != mSelectionValues.size()) { + LOG(fatal) << "Wrong number of values have been passed"; + } + for (size_t i = 0; i < mSelectionValues.size(); i++) { + switch (mLimitType) { + case (limits::kEqualArray): + if (std::fabs(values.at(i) - mSelectionValues.at(i)) < constants::math::Epsilon) { + mBitmask.set(i); + } + break; + default: + continue; + } + } + } + + /// \brief Retrieve the bitmask indicating which selections were passed. + /// \return Bitset representing passed selections. + std::bitset getBitmask() const + { + // if we do not skip the last bit, return full bitmask + if (mSkipMostPermissiveBit == false) { + return mBitmask; + } else { + // for the other selections we can remove the first bit since it is the minimal selection and therefore always true + return mBitmask >> 1; + } + } + template + void setBitmask(R bitmask) + { + mBitmask = std::bitset(bitmask); + } + + /// \brief Check whether the minimal cut condition is fulfilled. + /// \return True if minimal selection is fulfilled, false otherwise. + bool passesAsMinimalCut() const + { + if (mIsMinimalCut) { + // check if any bit is set + // in case were bits are evaluted in order, if the loosests fails, all fail, so testing any is safe here + return mBitmask.any(); + } + // if a selection is not marked as minimal cut we return true by default + return true; + } + + /// \brief Check whether any optional cuts are fulfilled. + /// \return True if at least one optional cut is passed. + bool passesAsOptionalCut() const + { + if (mIsOptionalCut) { + // check if any bit is set + // in case were bits are evaluted in order, if the loosests fails, all fail, so testing any is safe here + return mBitmask.any(); + } + // if a selection is not marked as optional cut we return false by default + return false; + } + + /// \brief Get the loosest (most permissive) selection value. + /// \return First (loosest) selection value. + T getLoosestSelection() const { return mSelectionValues.at(0); } + + /// \brief Check if there are any selection values configured. We also init values in case of function so this is safe + /// \return True if no selections are configured. + bool isEmpty() const { return mSelectionValues.empty(); } + + /// \brief Check if there are any selection values configured. + /// \return True if no selections are configured. + bool isUsingFunctions() const { return !mSelectionFunctions.empty(); } + + /// \brief Get the number of bits to shift for the final bitmask. + /// \return Number of bits to shift. + int getShift() const + { + if (mSelectionValues.empty()) { + return 0; + } + if (mSkipMostPermissiveBit) { + return static_cast(mSelectionValues.size() - 1); + } else { + return static_cast(mSelectionValues.size()); + } + } + + void setOffset(int offset) { mOffset = offset; } + int getOffset() const { return mOffset; } + + int getNSelections() const { return mSelectionValues.size(); } + + std::string getBinLabel(int selectionIndex) const + { + std::ostringstream oss; + std::string sectionDelimiter = ":::"; + std::string valueDelimiter = "___"; + std::string noValue = "X"; + oss << "SelectionName" << valueDelimiter << mSelectionName << sectionDelimiter + << "LimitType" << valueDelimiter << getLimitTypeAsString() << sectionDelimiter + << "MinimalCut" << valueDelimiter << (mIsMinimalCut ? "1" : "0") << sectionDelimiter + << "SkipMostPermissiveBit" << valueDelimiter << (mSkipMostPermissiveBit ? "1" : "0") << sectionDelimiter + << "OptionalCut" << valueDelimiter << (mIsOptionalCut ? "1" : "0") << sectionDelimiter + << "Shift" << valueDelimiter << getShift() << sectionDelimiter + << "Offset" << valueDelimiter << mOffset << sectionDelimiter + << "Value" << valueDelimiter << (mSelectionFunctions.empty() ? std::to_string(mSelectionValues.at(selectionIndex)) : mSelectionFunctions.at(selectionIndex).GetExpFormula().Data()) << sectionDelimiter + << "BitPosition" << valueDelimiter << (mSkipMostPermissiveBit ? (selectionIndex == 0 ? noValue : std::to_string(mOffset + selectionIndex - 1)) : std::to_string(mOffset + selectionIndex)) << sectionDelimiter + << "Comment" << valueDelimiter << (mComments.empty() ? noValue : mComments.at(selectionIndex)); + return oss.str(); + } + + int getBitPosition(int selectionIndex) const + { + if (selectionIndex == 0 && mSkipMostPermissiveBit) { + LOG(fatal) << "Trying to accessed the bit position of a skipped selection. Breaking..."; + return -1; + } + if (mSkipMostPermissiveBit) { + return mOffset + selectionIndex - 1; + } else { + return mOffset + selectionIndex; + } + } + + /// \brief Get string representation of the limit type. + /// \return String name of the limit type. + std::string getLimitTypeAsString() const { return limits::limitTypeAsStrings[mLimitType]; } + + /// \brief Get a copy of all selection values. + /// \return Vector of selection values. + std::vector const& getSelectionValues() const { return mSelectionValues; } + + /// \brief Get a copy of all selection values. + /// \return Vector of selection values. + std::vector const& getSelectionFunction() const { return mSelectionFunctions; } + + /// \brief Check if this container is marked as minimal cut + /// \return True if minimal cut, false otherwise. + bool isMinimalCut() const { return mIsMinimalCut; } + + /// \brief Check if this container is marked as optional cut + /// \return True if minimal cut, false otherwise. + bool isOptionalCut() const { return mIsOptionalCut; } + + /// \brief Check whether the most permissive bit is skipped. + /// \return True if skipped, false otherwise. + bool skipMostPermissiveBit() const { return mSkipMostPermissiveBit; } + + void reset() { mBitmask.reset(); } + + private: + std::string mSelectionName = std::string(""); + std::vector mSelectionValues = {}; ///< Values used for the selection + std::vector mSelectionFunctions = {}; ///< Function used for the selection + limits::LimitType mLimitType = limits::kLimitTypeLast; ///< Limit type of selection + bool mSkipMostPermissiveBit = false; ///< whether to skip the last bit or not + bool mIsMinimalCut = false; ///< whether to use this observable for minimal selection or not + bool mIsOptionalCut = false; ///< whether to use this observable for minimal selection or not + std::vector mComments = {}; ///< Comments for the values + std::bitset mBitmask = {}; ///< bitmask for the observable + int mOffset = 0; +}; + +} // namespace o2::analysis::femto + +#endif // PWGCF_FEMTO_CORE_SELECTIONCONTAINER_H_ diff --git a/PWGCF/Femto/Core/trackBuilder.h b/PWGCF/Femto/Core/trackBuilder.h new file mode 100644 index 00000000000..8547847fb86 --- /dev/null +++ b/PWGCF/Femto/Core/trackBuilder.h @@ -0,0 +1,807 @@ +// 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 trackBuilder.h +/// \brief track builder +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_CORE_TRACKBUILDER_H_ +#define PWGCF_FEMTO_CORE_TRACKBUILDER_H_ + +#include "PWGCF/Femto/Core/baseSelection.h" +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/selectionContainer.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace trackbuilder +{ + +struct ConfTrackFilters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("TrackFilters"); + // kinematic cuts for filtering tracks + o2::framework::Configurable ptMin{"ptMin", 0.2f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 6.f, "Maximum pT"}; + o2::framework::Configurable etaMin{"etaMin", -0.9f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 0.9f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; +}; + +struct ConfTrackBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("TrackBits"); + // track quality cuts + o2::framework::Configurable> tpcClustersMin{"tpcClustersMin", {90.f}, "Minimum number of clusters in TPC"}; + o2::framework::Configurable> tpcCrossedRowsMin{"tpcCrossedRowsMin", {80.f}, "Minimum number of crossed rows in TPC"}; + o2::framework::Configurable> tpcClustersOverCrossedRows{"tpcClustersOverCrossedRows", {0.83f}, "Minimum fraction of clusters over crossed rows in TPC"}; + o2::framework::Configurable> tpcSharedClustersMax{"tpcSharedClustersMax", {160.f}, "Maximum number of shared clusters in TPC"}; + o2::framework::Configurable> tpcSharedClusterFractionMax{"tpcSharedClusterFractionMax", {1.f}, "Maximum fraction of shared clusters in TPC"}; + o2::framework::Configurable> itsClustersMin{"itsClustersMin", {5.f}, "Minimum number of clusters in ITS"}; + o2::framework::Configurable> itsIbClustersMin{"itsIbClustersMin", {3.f}, "Minimum number of clusters in inner barrel (max 3) of ITS"}; + o2::framework::Configurable> dcaxyMax{"dcaxyMax", {"0.004 + 0.013*pow(x, -1)"}, "Maximum |dca_xy| as a function of pT. Has to be a valid TForumal, where x=pt"}; + o2::framework::Configurable> dcazMax{"dcazMax", {"0.004 + 0.013*pow(x, -1)"}, "Maximum |dca_z| as a function of pT. Has to be a valid TForumal, where x=pt"}; + + // Electron PID cuts + o2::framework::Configurable pidIsOptionalElectron{"pidIsOptionalElectron", false, "Make election PID optional"}; + o2::framework::Configurable minMomTofElectron{"minMomTofElectron", 0.3, "Minimum momentum to required TOF PID for Electron"}; + o2::framework::Configurable> itsElectron{"itsElectron", {}, "Maximum |nsigma| for Electron PID"}; + o2::framework::Configurable> tpcElectron{"tpcElectron", {}, "Maximum |nsigma| for Electron PID"}; + o2::framework::Configurable> tofElectron{"tofElectron", {}, "Maximum |nsigma| for Electron PID"}; + o2::framework::Configurable> tpcitsElectron{"tpcitsElectron", {}, "Maximum |nsigma| for Electron PID"}; + o2::framework::Configurable> tpctofElectron{"tpctofElectron", {}, "Maximum |nsigma| for Electron PID"}; + + // Pion PID cuts + o2::framework::Configurable pidIsOptionalPion{"pidIsOptionalPion", false, "Make election PID optional"}; + o2::framework::Configurable minMomTofPion{"minMomTofPion", 0.5, "Minimum momentum to required TOF PID for Pion"}; + o2::framework::Configurable> itsPion{"itsPion", {}, "Maximum |nsigma| for Pion PID"}; + o2::framework::Configurable> tpcPion{"tpcPion", {}, "Maximum |nsigma| for Pion PID"}; + o2::framework::Configurable> tofPion{"tofPion", {}, "Maximum |nsigma| for Pion PID"}; + o2::framework::Configurable> tpcitsPion{"tpcitsPion", {}, "Maximum |nsigma| for Pion PID"}; + o2::framework::Configurable> tpctofPion{"tpctofPion", {}, "Maximum |nsigma| for Pion PID"}; + + // Kaon PID cuts + o2::framework::Configurable pidIsOptionalKaon{"pidIsOptionalKaon", false, "Make election PID optional"}; + o2::framework::Configurable minMomTofKaon{"minMomTofKaon", 0.4, "Minimum momentum to required TOF PID for Kaon"}; + o2::framework::Configurable> itsKaon{"itsKaon", {}, "Maximum |nsigma| for Kaon PID"}; + o2::framework::Configurable> tpcKaon{"tpcKaon", {}, "Maximum |nsigma| for Kaon PID"}; + o2::framework::Configurable> tofKaon{"tofKaon", {}, "Maximum |nsigma| for Kaon PID"}; + o2::framework::Configurable> tpcitsKaon{"tpcitsKaon", {}, "Maximum |nsigma| for Kaon PID"}; + o2::framework::Configurable> tpctofKaon{"tpctofKaon", {}, "Maximum |nsigma| for Kaon PID"}; + + // Proton PID cuts + o2::framework::Configurable pidIsOptionalProton{"pidIsOptionalProton", true, "Make election PID optional"}; + o2::framework::Configurable minMomTofProton{"minMomTofProton", 0.75, "Minimum momentum to required TOF PID for Proton"}; + o2::framework::Configurable> itsProton{"itsProton", {}, "Maximum |nsigma| for Proton PID"}; + o2::framework::Configurable> tpcProton{"tpcProton", {}, "Maximum |nsigma| for Proton PID"}; + o2::framework::Configurable> tofProton{"tofProton", {}, "Maximum |nsigma| for Proton PID"}; + o2::framework::Configurable> tpcitsProton{"tpcitsProton", {3.f}, "Maximum |nsigma| for Proton PID"}; + o2::framework::Configurable> tpctofProton{"tpctofProton", {3.f}, "Maximum |nsigma| for Proton PID"}; + + // Deuteron PID cuts + o2::framework::Configurable pidIsOptionalDeuteron{"pidIsOptionalDeuteron", false, "Make election PID optional"}; + o2::framework::Configurable minMomTofDeuteron{"minMomTofDeuteron", 1.2, "Minimum momentum to required TOF PID for Deuteron"}; + o2::framework::Configurable> itsDeuteron{"itsDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; + o2::framework::Configurable> tpcDeuteron{"tpcDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; + o2::framework::Configurable> tofDeuteron{"tofDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; + o2::framework::Configurable> tpcitsDeuteron{"tpcitsDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; + o2::framework::Configurable> tpctofDeuteron{"tpctofDeuteron", {}, "Maximum |nsigma| for Deuteron PID"}; + + // Triton PID cuts + o2::framework::Configurable pidIsOptionalTriton{"pidIsOptionalTriton", false, "Make election PID optional"}; + o2::framework::Configurable minMomTofTriton{"minMomTofTriton", 1.4, "Minimum momentum to required TOF PID for Triton"}; + o2::framework::Configurable> itsTriton{"itsTriton", {}, "Maximum |nsigma| for Triton PID"}; + o2::framework::Configurable> tpcTriton{"tpcTriton", {}, "Maximum |nsigma| for Triton PID"}; + o2::framework::Configurable> tofTriton{"tofTriton", {}, "Maximum |nsigma| for Triton PID"}; + o2::framework::Configurable> tpcitsTriton{"tpcitsTriton", {}, "Maximum |nsigma| for Triton PID"}; + o2::framework::Configurable> tpctofTriton{"tpctofTriton", {}, "Maximum |nsigma| for Triton PID"}; + + // Helium PID cuts + o2::framework::Configurable pidIsOptionalHelium{"pidIsOptionalHelium", false, "Make election PID optional"}; + o2::framework::Configurable minMomTofHelium{"minMomTofHelium", 1.6, "Minimum momentum to required TOF PID for Helium"}; + o2::framework::Configurable> itsHelium{"itsHelium", {}, "Maximum |nsigma| for Helium PID"}; + o2::framework::Configurable> tpcHelium{"tpcHelium", {}, "Maximum |nsigma| for Helium PID"}; + o2::framework::Configurable> tofHelium{"tofHelium", {}, "Maximum |nsigma| for Helium PID"}; + o2::framework::Configurable> tpcitsHelium{"tpcitsHelium", {}, "Maximum |nsigma| for Helium PID"}; + o2::framework::Configurable> tpctofHelium{"tpctofHelium", {}, "Maximum |nsigma| for Helium PID"}; +}; + +// define the template structure for TrackSelection +template +struct ConfTrackSelection : public o2::framework::ConfigurableGroup { + std::string prefix = Prefix; // Unique prefix based on the template argument + // configuration parameters + o2::framework::Configurable pdgCode{"pdgCode", 2212, "Track PDG code"}; + o2::framework::Configurable chargeAbs{"chargeAbs", 1, "Absolute value of charge (e.g. 1 for most tracks, 2 for He3)"}; + o2::framework::Configurable chargeSign{"chargeSign", 1, "Track charge sign: +1 for positive, -1 for negative, 0 for both"}; + // filters for kinematics + o2::framework::Configurable ptMin{"ptMin", 0.2f, "Minimum pT (GeV/c)"}; + o2::framework::Configurable ptMax{"ptMax", 6.f, "Maximum pT (GeV/c)"}; + o2::framework::Configurable etaMin{"etaMin", -0.9f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 0.9f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + // track selection masks + o2::framework::Configurable maskLowMomentum{"maskLowMomentum", 0x2u, "Bitmask for selections below momentum threshold"}; + o2::framework::Configurable maskHighMomentum{"maskHighMomentum", 0x1u, "Bitmask for selections above momentum threshold"}; + // momentum threshold for PID usage + o2::framework::Configurable pidThres{"pidThres", 1.2f, "Momentum threshold for using TPCTOF/TOF pid for tracks with large momentum (GeV/c)"}; +}; + +// Define unique prefixes as constexpr string literals +constexpr const char PrefixTrackSelection1[] = "TrackSelection1"; +constexpr const char PrefixTrackSelection2[] = "TrackSelection2"; +constexpr const char PrefixTrackSelection3[] = "TrackSelection3"; + +// Instantiate different instances with unique prefixes +using ConfTrackSelection1 = ConfTrackSelection; +using ConfTrackSelection2 = ConfTrackSelection; +using ConfTrackSelection3 = ConfTrackSelection; + +/// enum for all track selections +enum TrackSels { + // track quality cuts + kTPCnClsMin, ///< Min. number of TPC clusters + kTPCcRowsMin, ///< Min. number of crossed TPC rows + kTPCnClsOvercRowsMin, ///< Min. fraction of TPC clusters of TPC crossed rows + kTPCsClsMax, ///< Max. number of shared TPC clusters + kTPCsClsFracMax, ///< Max. fractions 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) as a function of pT + kDCAzMax, ///< Max. |DCA_z| (cm) as a function of pT + + /// track pid cuts + kItsElectron, ///< ITS Electon PID + kItsPion, ///< ITS Pion PID + kItsKaon, ///< ITS Kaon PID + kItsProton, ///< ITS Proton PID + kItsDeuteron, ///< ITS Deuteron PID + kItsTriton, ///< ITS Triton PID + kItsHelium, ///< ITS He3 PID + + kTpcElectron, ///< TPC Electon PID + kTpcPion, ///< TPC Pion PID + kTpcKaon, ///< TPC Kaon PID + kTpcProton, ///< TPC Proton PID + kTpcDeuteron, ///< TPC Deuteron PID + kTpcTriton, ///< TPC Triton PID + kTpcHelium, ///< TPC He3 PID + + kTofElectron, ///< TOF Electon PID + kTofPion, ///< TOF Pion PID + kTofKaon, ///< TOF Kaon PID + kTofProton, ///< TOF Proton PID + kTofDeuteron, ///< TOF Deuteron PID + kTofTriton, ///< TOF Triton PID + kTofHelium, ///< TOF He3 PID + + kTpcitsElectron, ///< TPC+ITS Electon PID + kTpcitsPion, ///< TPC+ITS Pion PID + kTpcitsKaon, ///< TPC+ITS Kaon PID + kTpcitsProton, ///< TPC+ITS Proton PID + kTpcitsDeuteron, ///< TPC+ITS Deuteron PID + kTpcitsTriton, ///< TPC+ITS Triton PID + kTpcitsHelium, ///< TPC+ITS He3 PID + + kTpctofElectron, ///< TPC+TOF Electon PID + kTpctofPion, ///< TPC+TOF Pion PID + kTpctofKaon, ///< TPC+TOF Kaon PID + kTpctofProton, ///< TPC+TOF Proton PID + kTpctofDeuteron, ///< TPC+TOF Deuteron PID + kTpctofTriton, ///< TPC+TOF Triton PID + kTpctofHelium, ///< TPC+TOF He3 PID + + kTrackSelsMax +}; + +constexpr char TrackSelHistName[] = "hTrackSelection"; +constexpr char TrackSelsName[] = "Track Selection Object"; +const std::unordered_map trackSelectionNames = { + {kTPCnClsMin, "Min. number of TPC clusters"}, + {kTPCcRowsMin, "Min. number of crossed TPC rows"}, + {kTPCnClsOvercRowsMin, "Min. fraction of TPC clusters over TPC crossed rows"}, + {kTPCsClsMax, "Max. number of shared TPC clusters"}, + {kTPCsClsMax, "Max. number of shared TPC clusters"}, + {kTPCsClsFracMax, "Max. fractions 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) as a function of pT"}, + {kDCAzMax, "Max. |DCA_z| (cm) as a function of pT"}, + + {kItsElectron, "ITS Electron PID"}, + {kItsPion, "ITS Pion PID"}, + {kItsKaon, "ITS Kaon PID"}, + {kItsProton, "ITS Proton PID"}, + {kItsDeuteron, "ITS Deuteron PID"}, + {kItsTriton, "ITS Triton PID"}, + {kItsHelium, "ITS He3 PID"}, + + {kTpcElectron, "TPC Electron PID"}, + {kTpcPion, "TPC Pion PID"}, + {kTpcKaon, "TPC Kaon PID"}, + {kTpcProton, "TPC Proton PID"}, + {kTpcDeuteron, "TPC Deuteron PID"}, + {kTpcTriton, "TPC Triton PID"}, + {kTpcHelium, "TPC He3 PID"}, + + {kTofElectron, "TOF Electron PID"}, + {kTofPion, "TOF Pion PID"}, + {kTofKaon, "TOF Kaon PID"}, + {kTofProton, "TOF Proton PID"}, + {kTofDeuteron, "TOF Deuteron PID"}, + {kTofTriton, "TOF Triton PID"}, + {kTofHelium, "TOF He3 PID"}, + + {kTpcitsElectron, "TPC+ITS Electron PID"}, + {kTpcitsPion, "TPC+ITS Pion PID"}, + {kTpcitsKaon, "TPC+ITS Kaon PID"}, + {kTpcitsProton, "TPC+ITS Proton PID"}, + {kTpcitsDeuteron, "TPC+ITS Deuteron PID"}, + {kTpcitsTriton, "TPC+ITS Triton PID"}, + {kTpcitsHelium, "TPC+ITS He PID"}, + + {kTpctofElectron, "TPC+TOF Electron PID"}, + {kTpctofPion, "TPC+TOF Pion PID"}, + {kTpctofKaon, "TPC+TOF Kaon PID"}, + {kTpctofProton, "TPC+TOF Proton PID"}, + {kTpctofDeuteron, "TPC+TOF Deuteron PID"}, + {kTpctofTriton, "TPC+TOF Triton PID"}, + {kTpctofHelium, "TPC+TOF He3 PID"}}; + +/// \class FemtoDreamTrackCuts +/// \brief Cut class to contain and execute all cuts applied to tracks +template +class TrackSelection : public BaseSelection +{ + public: + TrackSelection() = default; + ~TrackSelection() = default; + + template + void configure(o2::framework::HistogramRegistry* registry, T1& config, T2& filter) + { + mPtMin = filter.ptMin; + mPtMax = filter.ptMax; + mEtaMin = filter.etaMin; + mEtaMax = filter.etaMax; + mPhiMin = filter.phiMin; + mPhiMax = filter.phiMax; + + // add selections for track quality + this->addSelection(kTPCnClsMin, trackSelectionNames.at(kTPCnClsMin), config.tpcClustersMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kTPCcRowsMin, trackSelectionNames.at(kTPCcRowsMin), config.tpcCrossedRowsMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kTPCnClsOvercRowsMin, trackSelectionNames.at(kTPCnClsOvercRowsMin), config.tpcClustersOverCrossedRows.value, limits::kLowerLimit, true, true, false); + this->addSelection(kTPCsClsMax, trackSelectionNames.at(kTPCsClsMax), config.tpcSharedClustersMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kTPCsClsFracMax, trackSelectionNames.at(kTPCsClsFracMax), config.tpcSharedClusterFractionMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kITSnClsMin, trackSelectionNames.at(kITSnClsMin), config.itsClustersMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kITSnClsIbMin, trackSelectionNames.at(kITSnClsIbMin), config.itsIbClustersMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kDCAxyMax, trackSelectionNames.at(kDCAxyMax), filter.ptMin, filter.ptMax.value, config.dcaxyMax.value, limits::kAbsUpperFunctionLimit, true, true, false); + this->addSelection(kDCAzMax, trackSelectionNames.at(kDCAzMax), filter.ptMin.value, filter.ptMax.value, config.dcazMax.value, limits::kAbsUpperFunctionLimit, true, true, false); + + // add selections for Electron pid + this->addSelection(kItsElectron, trackSelectionNames.at(kItsElectron), config.itsElectron.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalElectron); + this->addSelection(kTpcElectron, trackSelectionNames.at(kTpcElectron), config.tpcElectron.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalElectron); + this->addSelection(kTofElectron, trackSelectionNames.at(kTofElectron), config.tofElectron.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalElectron); + this->addSelection(kTpcitsElectron, trackSelectionNames.at(kTpcitsElectron), config.tpcitsElectron.value, limits::kUpperLimit, false, false, config.pidIsOptionalElectron); + this->addSelection(kTpctofElectron, trackSelectionNames.at(kTpctofElectron), config.tpctofElectron.value, limits::kUpperLimit, false, false, config.pidIsOptionalElectron); + mElectronTofThres = config.minMomTofElectron.value; + + // add selections for Pion pid + this->addSelection(kItsPion, trackSelectionNames.at(kItsPion), config.itsPion.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalPion); + this->addSelection(kTpcPion, trackSelectionNames.at(kTpcPion), config.tpcPion.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalPion); + this->addSelection(kTofPion, trackSelectionNames.at(kTofPion), config.tofPion.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalPion); + this->addSelection(kTpcitsPion, trackSelectionNames.at(kTpcitsPion), config.tpcitsPion.value, limits::kUpperLimit, false, false, config.pidIsOptionalPion); + this->addSelection(kTpctofPion, trackSelectionNames.at(kTpctofPion), config.tpctofPion.value, limits::kUpperLimit, false, false, config.pidIsOptionalPion); + mPionTofThres = config.minMomTofPion.value; + + // add selections for Kaon pid + this->addSelection(kItsKaon, trackSelectionNames.at(kItsKaon), config.itsKaon.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalKaon); + this->addSelection(kTpcKaon, trackSelectionNames.at(kTpcKaon), config.tpcKaon.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalKaon); + this->addSelection(kTofKaon, trackSelectionNames.at(kTofKaon), config.tofKaon.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalKaon); + this->addSelection(kTpcitsKaon, trackSelectionNames.at(kTpcitsKaon), config.tpcitsKaon.value, limits::kUpperLimit, false, false, config.pidIsOptionalKaon); + this->addSelection(kTpctofKaon, trackSelectionNames.at(kTpctofKaon), config.tpctofKaon.value, limits::kUpperLimit, false, false, config.pidIsOptionalKaon); + mKaonTofThres = config.minMomTofKaon.value; + + // add selections for Proton pid + this->addSelection(kItsProton, trackSelectionNames.at(kItsProton), config.itsProton.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalProton); + this->addSelection(kTpcProton, trackSelectionNames.at(kTpcProton), config.tpcProton.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalProton); + this->addSelection(kTofProton, trackSelectionNames.at(kTofProton), config.tofProton.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalProton); + this->addSelection(kTpcitsProton, trackSelectionNames.at(kTpcitsProton), config.tpcitsProton.value, limits::kUpperLimit, false, false, config.pidIsOptionalProton); + this->addSelection(kTpctofProton, trackSelectionNames.at(kTpctofProton), config.tpctofProton.value, limits::kUpperLimit, false, false, config.pidIsOptionalProton); + mProtonTofThres = config.minMomTofProton.value; + + // add selections for Deuteron pid + this->addSelection(kItsDeuteron, trackSelectionNames.at(kItsDeuteron), config.itsDeuteron.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalDeuteron); + this->addSelection(kTpcDeuteron, trackSelectionNames.at(kTpcDeuteron), config.tpcDeuteron.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalDeuteron); + this->addSelection(kTofDeuteron, trackSelectionNames.at(kTofDeuteron), config.tofDeuteron.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalDeuteron); + this->addSelection(kTpcitsDeuteron, trackSelectionNames.at(kTpcitsDeuteron), config.tpcitsDeuteron.value, limits::kUpperLimit, false, false, config.pidIsOptionalDeuteron); + this->addSelection(kTpctofDeuteron, trackSelectionNames.at(kTpctofDeuteron), config.tpctofDeuteron.value, limits::kUpperLimit, false, false, config.pidIsOptionalDeuteron); + mDeuteronTofThres = config.minMomTofDeuteron.value; + + // add selections for Triton pid + this->addSelection(kItsTriton, trackSelectionNames.at(kItsTriton), config.itsTriton.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalTriton); + this->addSelection(kTpcTriton, trackSelectionNames.at(kTpcTriton), config.tpcTriton.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalTriton); + this->addSelection(kTofTriton, trackSelectionNames.at(kTofTriton), config.tofTriton.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalTriton); + this->addSelection(kTpcitsTriton, trackSelectionNames.at(kTpcitsTriton), config.tpcitsTriton.value, limits::kUpperLimit, false, false, config.pidIsOptionalTriton); + this->addSelection(kTpctofTriton, trackSelectionNames.at(kTpctofTriton), config.tpctofTriton.value, limits::kUpperLimit, false, false, config.pidIsOptionalTriton); + mTritonTofThres = config.minMomTofTriton.value; + + // add selections for Helium pid + this->addSelection(kItsHelium, trackSelectionNames.at(kItsHelium), config.itsHelium.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalHelium); + this->addSelection(kTpcHelium, trackSelectionNames.at(kTpcHelium), config.tpcHelium.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalHelium); + this->addSelection(kTofHelium, trackSelectionNames.at(kTofHelium), config.tofHelium.value, limits::kAbsUpperLimit, false, false, config.pidIsOptionalHelium); + this->addSelection(kTpcitsHelium, trackSelectionNames.at(kTpcitsHelium), config.tpcitsHelium.value, limits::kUpperLimit, false, false, config.pidIsOptionalHelium); + this->addSelection(kTpctofHelium, trackSelectionNames.at(kTpctofHelium), config.tpctofHelium.value, limits::kUpperLimit, false, false, config.pidIsOptionalHelium); + mHeliumTofThres = config.minMomTofHelium.value; + + this->setupContainers(registry); + } + + template + bool checkFilters(T const& track) const + { + return ((track.pt() > mPtMin && track.pt() < mPtMax) && + (track.eta() > mEtaMin && track.eta() < mEtaMax) && + (track.phi() > mPhiMin && track.phi() < mPhiMax)); + } + + template + void evaluatePid(T1 const& Track, + float tofThreshold, + float nsigmaIts, + float nsigmaTpc, + float nsigmaTof, + TrackSels its, + TrackSels tpc, + TrackSels tof, + TrackSels tpcits, + TrackSels tpctof) + { + // if track is below threshold, just check every PID + if (Track.p() < tofThreshold) { + this->evaluateObservable(its, nsigmaIts); + this->evaluateObservable(tpc, nsigmaTpc); + this->evaluateObservable(tpcits, std::hypot(nsigmaTpc, nsigmaIts)); + this->evaluateObservable(tof, nsigmaTof); + this->evaluateObservable(tpctof, std::hypot(nsigmaTpc, nsigmaTof)); + return; + } + // if track is above threshold, check if TOF PID is available + // if not, we dont check any selection and they stay at reseted values, i.e. the cut fails + if (Track.hasTOF()) { + // if tof inforamtion is available, check them first + this->evaluateObservable(tof, nsigmaTof); + this->evaluateObservable(tpctof, std::hypot(nsigmaTpc, nsigmaTof)); + // if both failed, the bitmask will be 0 and there is no need to check tpc and its information since we do not want to have this track + // so if we just bail out here, the PID for this particle type will failed for its, tpc and tof + if (this->passesOptionalSelection(tof) || this->passesOptionalSelection(tpctof)) { + this->evaluateObservable(its, nsigmaIts); + this->evaluateObservable(tpc, nsigmaTpc); + this->evaluateObservable(tpcits, std::hypot(nsigmaTpc, nsigmaIts)); + } + } + } + + template + void applySelections(T const& Track) + { + this->reset(); + this->evaluateObservable(kTPCnClsMin, Track.tpcNClsFound()); + this->evaluateObservable(kTPCcRowsMin, Track.tpcNClsCrossedRows()); + this->evaluateObservable(kTPCnClsOvercRowsMin, static_cast(Track.tpcNClsFound()) / static_cast(Track.tpcNClsCrossedRows())); + this->evaluateObservable(kTPCsClsMax, Track.tpcNClsShared()); + this->evaluateObservable(kTPCsClsFracMax, static_cast(Track.tpcNClsShared()) / static_cast(Track.tpcNClsFound())); + this->evaluateObservable(kITSnClsMin, Track.itsNCls()); + this->evaluateObservable(kITSnClsIbMin, Track.itsNClsInnerBarrel()); + + // evalue bitmask for pt dependent dca cuts + this->updateLimits(kDCAxyMax, Track.pt()); + this->evaluateObservable(kDCAxyMax, Track.dcaXY()); + + this->updateLimits(kDCAzMax, Track.pt()); + this->evaluateObservable(kDCAzMax, Track.dcaZ()); + + this->evaluatePid(Track, + mElectronTofThres, + Track.itsNSigmaEl(), + Track.tpcNSigmaEl(), + Track.tofNSigmaEl(), + kItsElectron, + kTpcElectron, + kTofElectron, + kTpcitsElectron, + kTpctofElectron); + + this->evaluatePid(Track, + mPionTofThres, + Track.itsNSigmaPi(), + Track.tpcNSigmaPi(), + Track.tofNSigmaPi(), + kItsPion, + kTpcPion, + kTofPion, + kTpcitsPion, + kTpctofPion); + + this->evaluatePid(Track, + mKaonTofThres, + Track.itsNSigmaKa(), + Track.tpcNSigmaKa(), + Track.tofNSigmaKa(), + kItsKaon, + kTpcKaon, + kTofKaon, + kTpcitsKaon, + kTpctofKaon); + + this->evaluatePid(Track, + mProtonTofThres, + Track.itsNSigmaPr(), + Track.tpcNSigmaPr(), + Track.tofNSigmaPr(), + kItsProton, + kTpcProton, + kTofProton, + kTpcitsProton, + kTpctofProton); + + this->evaluatePid(Track, + mDeuteronTofThres, + Track.itsNSigmaDe(), + Track.tpcNSigmaDe(), + Track.tofNSigmaDe(), + kItsDeuteron, + kTpcDeuteron, + kTofDeuteron, + kTpcitsDeuteron, + kTpctofDeuteron); + + this->evaluatePid(Track, + mTritonTofThres, + Track.itsNSigmaTr(), + Track.tpcNSigmaTr(), + Track.tofNSigmaTr(), + kItsTriton, + kTpcTriton, + kTofTriton, + kTpcitsTriton, + kTpctofTriton); + + this->evaluatePid(Track, + mHeliumTofThres, + Track.itsNSigmaHe(), + Track.tpcNSigmaHe(), + Track.tofNSigmaHe(), + kItsHelium, + kTpcHelium, + kTofHelium, + kTpcitsHelium, + kTpctofHelium); + + this->assembleBitmask(); + } + + protected: + float mElectronTofThres = 99.f; + float mPionTofThres = 99.f; + float mKaonTofThres = 99.f; + float mProtonTofThres = 99.f; + float mDeuteronTofThres = 99.f; + float mTritonTofThres = 99.f; + float mHeliumTofThres = 99.f; + + float mPtMin = 0.f; + float mPtMax = 99.f; + float mEtaMin = -0.9; + float mEtaMax = 0.9; + float mPhiMin = 0; + float mPhiMax = o2::constants::math::TwoPI; +}; + +struct TrackBuilderProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedTracks; + o2::framework::Produces producedTrackMasks; + o2::framework::Produces producedTrackDcas; + o2::framework::Produces producedTrackExtras; + o2::framework::Produces producedElectronPids; + o2::framework::Produces producedPionPids; + o2::framework::Produces producedKaonPids; + o2::framework::Produces producedProtonPids; + o2::framework::Produces producedDeuteronPids; + o2::framework::Produces producedTritonPids; + o2::framework::Produces producedHeliumPids; +}; + +struct ConfTrackTables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("TrackTables"); + o2::framework::Configurable produceTracks{"produceTracks", -1, "Produce Tracks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceTrackMasks{"produceTrackMasks", -1, "Produce TrackMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceTrackDcas{"produceTrackDcas", -1, "Produce TrackDcas (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceTrackExtras{"produceTrackExtras", -1, "Produce TrackExtras (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceElectronPids{"produceElectronPids", -1, "Produce ElectronPids (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable producePionPids{"producePionPids", -1, "Produce PionPids (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceKaonPids{"produceKaonPids", -1, "Produce KaonPids (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceProtonPids{"produceProtonPids", -1, "Produce ProtonPids (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceDeuteronPids{"produceDeuteronPids", -1, "Produce DeuteronPids (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceTritonPids{"produceTritonPids", -1, "Produce TritonPids (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceHeliumPids{"produceHeliumPids", -1, "Produce HeliumPids (-1: auto; 0 off; 1 on)"}; +}; + +template +class TrackBuilder +{ + public: + TrackBuilder() = default; + ~TrackBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + { + LOG(info) << "Initialize femto track builder..."; + + mProduceTracks = utils::enableTable("FTracks_001", table.produceTracks.value, initContext); + mProduceTrackMasks = utils::enableTable("FTrackMasks_001", table.produceTrackMasks.value, initContext); + mProduceTrackDcas = utils::enableTable("FTrackDcas_001", table.produceTrackDcas.value, initContext); + mProduceTrackExtras = utils::enableTable("FTrackExtras_001", table.produceTrackExtras.value, initContext); + mProduceElectronPids = utils::enableTable("FElectronPids_001", table.produceElectronPids.value, initContext); + mProducePionPids = utils::enableTable("FPionPids_001", table.producePionPids.value, initContext); + mProduceKaonPids = utils::enableTable("FKaonPids_001", table.produceKaonPids.value, initContext); + mProduceProtonPids = utils::enableTable("FProtonPids_001", table.produceProtonPids.value, initContext); + mProduceDeuteronPids = utils::enableTable("FDeuteronPids_001", table.produceDeuteronPids.value, initContext); + mProduceTritonPids = utils::enableTable("FTritonPids_001", table.produceTritonPids.value, initContext); + mProduceHeliumPids = utils::enableTable("FHeliumPids_001", table.produceHeliumPids.value, initContext); + + if (mProduceTracks || mProduceTrackMasks || mProduceTrackDcas || mProduceTrackExtras || mProduceElectronPids || mProducePionPids || mProduceKaonPids || mProduceProtonPids || mProduceDeuteronPids || mProduceTritonPids || mProduceHeliumPids) { + mFillAnyTable = true; + } else { + LOG(info) << "No tables configured, Selection object will not be configured..."; + LOG(info) << "Initialization done..."; + return; + } + mTrackSelection.configure(registry, config, filter); + mTrackSelection.printSelections(TrackSelsName); + LOG(info) << "Initialization done..."; + } + + template + void fillTracks(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4 const& tracks, T5& trackProducts, T6& indexMap) + { + if (!mFillAnyTable) { + return; + } + for (const auto& track : tracks) { + if (!mTrackSelection.checkFilters(track)) { + continue; + } + mTrackSelection.applySelections(track); + if (!mTrackSelection.passesAllRequiredSelections()) { + continue; + } + + collisionBuilder.template fillCollision(collisionProducts, col); + this->fillTrack(track, trackProducts, collisionProducts, indexMap); + } + } + + template + void fillTrack(T1 const& track, T2& trackProducts, T3& collisionProducts, T4& indexMap) + { + if (mProduceTracks) { + trackProducts.producedTracks(collisionProducts.producedCollision.lastIndex(), + track.pt() * track.sign(), + track.eta(), + track.phi()); + indexMap.emplace(track.globalIndex(), trackProducts.producedTracks.lastIndex()); + } + if (mProduceTrackMasks) { + if constexpr (type == modes::Track::kPrimaryTrack) { + trackProducts.producedTrackMasks(mTrackSelection.getBitmask()); + } else { + trackProducts.producedTrackMasks(static_cast(0u)); + } + } + if (mProduceTrackDcas) { + trackProducts.producedTrackDcas(track.dcaXY(), track.dcaZ()); + } + if (mProduceTrackExtras) { + trackProducts.producedTrackExtras(track.isPVContributor(), + track.itsNCls(), + track.itsNClsInnerBarrel(), + track.itsChi2NCl(), + track.itsClusterSizes(), + track.tpcSignal(), + track.tpcInnerParam(), + track.tpcNClsFound(), + track.tpcNClsCrossedRows(), + track.tpcNClsShared(), + track.beta(), + track.mass()); + } + if (mProduceElectronPids) { + if constexpr (type == modes::Track::kPrimaryTrack) { + trackProducts.producedElectronPids(track.itsNSigmaEl(), track.tpcNSigmaEl(), track.tofNSigmaEl()); + } else { + trackProducts.producedElectronPids(0, track.tpcNSigmaEl(), track.tofNSigmaEl()); + } + } + if (mProducePionPids) { + if constexpr (type == modes::Track::kPrimaryTrack) { + trackProducts.producedPionPids(track.itsNSigmaPi(), track.tpcNSigmaPi(), track.tofNSigmaPi()); + } else { + trackProducts.producedPionPids(0, track.tpcNSigmaPi(), track.tofNSigmaPi()); + } + } + if (mProduceKaonPids) { + if constexpr (type == modes::Track::kPrimaryTrack) { + trackProducts.producedKaonPids(track.itsNSigmaKa(), track.tpcNSigmaKa(), track.tofNSigmaKa()); + } else { + trackProducts.producedKaonPids(0, track.tpcNSigmaKa(), track.tofNSigmaKa()); + } + } + if (mProduceProtonPids) { + if constexpr (type == modes::Track::kPrimaryTrack) { + trackProducts.producedProtonPids(track.itsNSigmaPr(), track.tpcNSigmaPr(), track.tofNSigmaPr()); + } else { + trackProducts.producedProtonPids(0, track.tpcNSigmaPr(), track.tofNSigmaPr()); + } + } + if (mProduceDeuteronPids) { + if constexpr (type == modes::Track::kPrimaryTrack) { + trackProducts.producedDeuteronPids(track.itsNSigmaDe(), track.tpcNSigmaDe(), track.tofNSigmaDe()); + } else { + trackProducts.producedDeuteronPids(0, track.tpcNSigmaDe(), track.tofNSigmaDe()); + } + } + if (mProduceTritonPids) { + if constexpr (type == modes::Track::kPrimaryTrack) { + trackProducts.producedTritonPids(track.itsNSigmaTr(), track.tpcNSigmaTr(), track.tofNSigmaTr()); + } else { + trackProducts.producedTritonPids(0, track.tpcNSigmaTr(), track.tofNSigmaTr()); + } + } + if (mProduceHeliumPids) { + if constexpr (type == modes::Track::kPrimaryTrack) { + trackProducts.producedHeliumPids(track.itsNSigmaHe(), track.tpcNSigmaHe(), track.tofNSigmaHe()); + } else { + trackProducts.producedHeliumPids(0, track.tpcNSigmaHe(), track.tofNSigmaHe()); + } + } + } + + template + int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionProducts, T4& indexMap) + { + auto result = utils::getIndex(daughter.globalIndex(), indexMap); + if (result) { + return result.value(); + } else { + this->fillTrack(daughter, trackProducts, collisionProducts, indexMap); + int64_t idx = trackProducts.producedTracks.lastIndex(); + indexMap.emplace(daughter.globalIndex(), idx); + return idx; + } + } + + private: + TrackSelection mTrackSelection; + bool mFillAnyTable = false; + bool mProduceTracks = false; + bool mProduceTrackMasks = false; + bool mProduceTrackDcas = false; + bool mProduceTrackExtras = false; + bool mProduceElectronPids = false; + bool mProducePionPids = false; + bool mProduceKaonPids = false; + bool mProduceProtonPids = false; + bool mProduceDeuteronPids = false; + bool mProduceTritonPids = false; + bool mProduceHeliumPids = false; +}; + +struct TrackBuilderDerivedToDerivedProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedTracks; + o2::framework::Produces producedTrackMasks; +}; + +struct ConfTrackTablesDerivedToDerived : o2::framework::ConfigurableGroup { + std::string prefix = std::string("TrackTables"); + o2::framework::Configurable limitTrack1{"limitTrack1", 1, "At least this many tracks of type 1 need to be in the collision"}; + o2::framework::Configurable limitTrack2{"limitTrack2", 0, "At least this many tracks of type 2 need to be in the collision"}; +}; + +class TrackBuilderDerivedToDerived +{ + public: + TrackBuilderDerivedToDerived() = default; + ~TrackBuilderDerivedToDerived() = default; + + template + void init(T& config) + { + mLimitTrack1 = config.limitTrack1.value; + mLimitTrack2 = config.limitTrack2.value; + } + + template + bool collisionHasTooFewTracks(T1& col, T2& /*trackTable*/, T3& partitionTrack1, T4& partitionTrack2, T5& cache) + { + auto trackSlice1 = partitionTrack1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto trackSlice2 = partitionTrack2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice1.size() >= mLimitTrack1 && trackSlice2.size() >= mLimitTrack2) { + return false; + } + return true; + } + + template + void processTracks(T1& col, T2& /*trackTable*/, T3& partitionTrack1, T4& partitionTrack2, T5& indexMap, T6& cache, T7& newTrackTable, T8& newCollisionTable) + { + auto trackSlice1 = partitionTrack1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto trackSlice2 = partitionTrack2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + + for (auto const& track : trackSlice1) { + this->fillTrack(track, newTrackTable, newCollisionTable, indexMap); + } + for (auto const& track : trackSlice2) { + this->fillTrack(track, newTrackTable, newCollisionTable, indexMap); + } + } + + template + void fillTrack(T1 const& track, T2& trackProducts, T3& collisionProducts, T4& indexMap) + { + trackProducts.producedTracks(collisionProducts.producedCollision.lastIndex(), + track.signedPt(), + track.eta(), + track.phi()); + trackProducts.producedTrackMasks(track.mask()); + indexMap.emplace(track.globalIndex(), trackProducts.producedTracks.lastIndex()); + } + + template + int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionProducts, T4& indexMap) + { + auto result = utils::getIndex(daughter.globalIndex(), indexMap); + if (result) { + return result.value(); + } else { + this->fillTrack(daughter, trackProducts, collisionProducts, indexMap); + int64_t idx = trackProducts.producedTracks.lastIndex(); + indexMap.emplace(daughter.globalIndex(), idx); + return idx; + } + } + + private: + int mLimitTrack1 = 0; + int mLimitTrack2 = 0; +}; + +} // namespace trackbuilder +// +} // namespace o2::analysis::femto + +#endif // PWGCF_FEMTO_CORE_TRACKBUILDER_H_ diff --git a/PWGCF/Femto/Core/trackHistManager.h b/PWGCF/Femto/Core/trackHistManager.h new file mode 100644 index 00000000000..b5cf3dae112 --- /dev/null +++ b/PWGCF/Femto/Core/trackHistManager.h @@ -0,0 +1,712 @@ +// 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 trackHistManager.h +/// \brief histogram manager for track histograms +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_CORE_TRACKHISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_TRACKHISTMANAGER_H_ + +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace trackhistmanager +{ + +// enum for track histograms +enum TrackHist { + // kinemtics + kPt, + kEta, + kPhi, + kSign, + // qa variables + kPAtPv, + kPTpc, + kItsCluster, + kItsClusterIb, + kTpcCrossedRows, + kTpcCluster, + kTpcClusterOverCrossedRows, + kTpcClusterShared, + kTpcClusterFractionShared, + // kDcaxy, + // kDcaz, + // kDca, + // 2d qa + kPtVsEta, + kPtVsPhi, + kPhiVsEta, + kPtVsItsCluster, + kPtVsTpcCluster, + kPtVsTpcCrossedRows, + kPtVsTpcClusterOverCrossedRows, + kPtVsTpcClusterShared, + kPtVsTpcClusterFractionShared, + kTpcClusterVsTpcCrossedRows, + kTpcClusterVsTpcClusterShared, + kPtVsDcaxy, + kPtVsDcaz, + kPtVsDca, + // its pid + kItsSignal, + kItsElectron, + kItsPion, + kItsKaon, + kItsProton, + kItsDeuteron, + kItsTriton, + kItsHelium, + // tpc pid + kTpcSignal, + kTpcElectron, + kTpcPion, + kTpcKaon, + kTpcProton, + kTpcDeuteron, + kTpcTriton, + kTpcHelium, + // tof pid + kTofBeta, + kTofMass, + kTofElectron, + kTofPion, + kTofKaon, + kTofProton, + kTofDeuteron, + kTofTriton, + kTofHelium, + // tpc+its pid + kTpcitsElectron, + kTpcitsPion, + kTpcitsKaon, + kTpcitsProton, + kTpcitsDeuteron, + kTpcitsTriton, + kTpcitsHelium, + // tpc+tof pid + kTpctofElectron, + kTpctofPion, + kTpctofKaon, + kTpctofProton, + kTpctofDeuteron, + kTpctofTriton, + kTpctofHelium, + kTrackHistLast +}; + +template +struct ConfTrackBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::ConfigurableAxis pt{"pt", {{600, 0, 6}}, "Pt"}; + o2::framework::ConfigurableAxis eta{"eta", {{300, -1.5, 1.5}}, "Eta"}; + o2::framework::ConfigurableAxis phi{"phi", {{720, 0, 1.f * o2::constants::math::TwoPI}}, "Phi"}; + o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; +}; + +constexpr const char PrefixTrackBinning1[] = "TrackBinning1"; +constexpr const char PrefixTrackBinning2[] = "TrackBinning2"; +constexpr const char PrefixResonancePosDauBinning[] = "ResonancePosDauBinning"; +constexpr const char PrefixResonanceNegDauBinning[] = "ResonanceNegDauBinning"; +constexpr const char PrefixV0PosDauBinning[] = "V0PosDauBinning"; +constexpr const char PrefixV0NegDauBinning[] = "V0NegDauBinning"; +constexpr const char PrefixCascadePosDauBinning[] = "CascadePosDauBinning"; +constexpr const char PrefixCascadeNegDauBinning[] = "CascadeNegDauBinning"; +constexpr const char PrefixCascadeBachelorBinning[] = "CascadeBachelorBinning"; +constexpr const char PrefixKinkChaDauBinning[] = "KinkChaDauBinning"; + +using ConfTrackBinning1 = ConfTrackBinning; +using ConfTrackBinning2 = ConfTrackBinning; +using ConfResonancePosDauBinning = ConfTrackBinning; +using ConfResonanceNegDauBinning = ConfTrackBinning; +using ConfV0PosDauBinning = ConfTrackBinning; +using ConfV0NegDauBinning = ConfTrackBinning; +using ConfCascadePosDauBinning = ConfTrackBinning; +using ConfCascadeNegDauBinning = ConfTrackBinning; +using ConfCascadeBachelorBinning = ConfTrackBinning; +using ConfKinkChaDauBinning = ConfTrackBinning; + +template +struct ConfTrackQaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable momentumType{"momentumType", static_cast(modes::MomentumType::kPAtPv), "Momentum on x-axis (0->Pt, 1->P at PV, 2->P at TPC inner wall)"}; + o2::framework::Configurable plot2d{"plot2d", true, "Generate various 2D QA plots"}; + o2::framework::Configurable plotElectronPid{"plotElectronPid", true, "Generate plots for Electron PID"}; + o2::framework::Configurable plotPionPid{"plotPionPid", true, "Generate plots for Pion PID"}; + o2::framework::Configurable plotKaonPid{"plotKaonPid", true, "Generate plots for Kaon PID"}; + o2::framework::Configurable plotProtonPid{"plotProtonPid", true, "Generate plots for Proton PID"}; + o2::framework::Configurable plotDeuteronPid{"plotDeuteronPid", true, "Generate plots for Deuteron PID"}; + o2::framework::Configurable plotTritonPid{"plotTritonPid", true, "Generate plots for Triton PID"}; + o2::framework::Configurable plotHeliumPid{"plotHeliumPid", true, "Generate plots for Helium PID"}; + o2::framework::ConfigurableAxis itsCluster{"itsCluster", {{8, -0.5, 7.5}}, "ITS cluster"}; + o2::framework::ConfigurableAxis itsClusterIb{"itsClusterIb", {{4, -0.5, 3.5}}, "ITS cluster in inner barrel"}; + o2::framework::ConfigurableAxis tpcCrossedRows{"tpcCrossedRows", {{161, -0.5, 160.5}}, "TPC cluster"}; + o2::framework::ConfigurableAxis tpcCluster{"tpcCluster", {{161, -0.5, 160.5}}, "TPC cluster"}; + o2::framework::ConfigurableAxis tpcClusterOverCrossedRows{"tpcClusterOverCrossedRows", {{75, 0, 1.5}}, "TPC cluster over TPC crossed rows"}; + o2::framework::ConfigurableAxis tpcClusterShared{"tpcClusterShared", {{161, -0.5, 160.5}}, "TPC cluster shared"}; + o2::framework::ConfigurableAxis tpcClusterFractionShared{"tpcClusterFractionShared", {{60, 0, 1.2}}, "TPC cluster fraction shared"}; + o2::framework::ConfigurableAxis dcaXy{"dcaXy", {{300, -0.3, 0.3}}, "DCA_xy"}; + o2::framework::ConfigurableAxis dcaZ{"dcaZ", {{300, -0.3, 0.3}}, "DCA_Z"}; + o2::framework::ConfigurableAxis dca{"dca", {{300, 0, 0.3}}, "DCA"}; + o2::framework::ConfigurableAxis p{"p", {{300, 0, 6}}, "Momentum axis"}; + o2::framework::ConfigurableAxis itsSignal{"itsSignal", {{150, 0, 15}}, "ITS Signal"}; + o2::framework::ConfigurableAxis itsElectron{"itsElectron", {{300, -3, 3}}, "ITS PID for electron"}; + o2::framework::ConfigurableAxis itsPion{"itsPion", {{300, -3, 3}}, "ITS PID for pion"}; + o2::framework::ConfigurableAxis itsKaon{"itsKaon", {{300, -3, 3}}, "ITS PID for kaon"}; + o2::framework::ConfigurableAxis itsProton{"itsProton", {{300, -3, 3}}, "ITS PID for proton"}; + o2::framework::ConfigurableAxis itsDeuteron{"itsDeuteron", {{300, -3, 3}}, "ITS PID for deuteron"}; + o2::framework::ConfigurableAxis itsTriton{"itsTriton", {{300, -3, 3}}, "ITS PID for triton"}; + o2::framework::ConfigurableAxis itsHelium{"itsHelium", {{300, -3, 3}}, "ITS PID for helium"}; + o2::framework::ConfigurableAxis tpcSignal{"tpcSignal", {{150, 0, 150}}, "TPC Signal"}; + o2::framework::ConfigurableAxis tpcElectron{"tpcElectron", {{300, -3, 3}}, "TPC PID for electron"}; + o2::framework::ConfigurableAxis tpcPion{"tpcPion", {{300, -3, 3}}, "TPC PID for pion"}; + o2::framework::ConfigurableAxis tpcKaon{"tpcKaon", {{300, -3, 3}}, "TPC PID for kaon"}; + o2::framework::ConfigurableAxis tpcProton{"tpcProton", {{300, -3, 3}}, "TPC PID for proton"}; + o2::framework::ConfigurableAxis tpcDeuteron{"tpcDeuteron", {{300, -3, 3}}, "TPC PID for deuteron"}; + o2::framework::ConfigurableAxis tpcTriton{"tpcTriton", {{300, -3, 3}}, "TPC PID for triton"}; + o2::framework::ConfigurableAxis tpcHelium{"tpcHelium", {{300, -3, 3}}, "TPC PID for helium"}; + o2::framework::ConfigurableAxis tofBeta{"tofBeta", {{150, 0, 1.5}}, "TOF Signal"}; + o2::framework::ConfigurableAxis tofMass{"tofMass", {{150, 0, 1.5}}, "TOF Mass"}; + o2::framework::ConfigurableAxis tofElectron{"tofElectron", {{300, -3, 3}}, "TOF PID for electron"}; + o2::framework::ConfigurableAxis tofPion{"tofPion", {{300, -3, 3}}, "TOF PID for pion"}; + o2::framework::ConfigurableAxis tofKaon{"tofKaon", {{300, -3, 3}}, "TOF PID for kaon"}; + o2::framework::ConfigurableAxis tofProton{"tofProton", {{300, -3, 3}}, "TOF PID for proton"}; + o2::framework::ConfigurableAxis tofDeuteron{"tofDeuteron", {{300, -3, 3}}, "TOF PID for deuteron"}; + o2::framework::ConfigurableAxis tofTriton{"tofTriton", {{300, -3, 3}}, "TOF PID for triton"}; + o2::framework::ConfigurableAxis tofHelium{"tofHelium", {{300, -3, 3}}, "TOF PID for helium"}; + o2::framework::ConfigurableAxis tpcitsElectron{"tpcitsElectron", {{300, 0, 3}}, "tpcits PID for electron"}; + o2::framework::ConfigurableAxis tpcitsPion{"tpcitsPion", {{300, 0, 3}}, "TPCITS PID for pion"}; + o2::framework::ConfigurableAxis tpcitsKaon{"tpcitsKaon", {{300, 0, 3}}, "TPCITS PID for kaon"}; + o2::framework::ConfigurableAxis tpcitsProton{"tpcitsProton", {{300, 0, 3}}, "TPCITS PID for proton"}; + o2::framework::ConfigurableAxis tpcitsDeuteron{"tpcitsDeuteron", {{300, 0, 3}}, "TPCITS PID for deuteron"}; + o2::framework::ConfigurableAxis tpcitsTriton{"tpcitsTriton", {{300, 0, 3}}, "TPCITS PID for triton"}; + o2::framework::ConfigurableAxis tpcitsHelium{"tpcitsHelium", {{300, 0, 3}}, "TPCITS PID for helium"}; + o2::framework::ConfigurableAxis tpctofElectron{"tpctofElectron", {{300, 0, 3}}, "TPCTOF PID for electron"}; + o2::framework::ConfigurableAxis tpctofPion{"tpctofPion", {{300, 0, 3}}, "TPCTOF PID for pion"}; + o2::framework::ConfigurableAxis tpctofKaon{"tpctofKaon", {{300, 0, 3}}, "TPCTOF PID for kaon"}; + o2::framework::ConfigurableAxis tpctofProton{"tpctofProton", {{300, 0, 3}}, "TPCTOF PID for proton"}; + o2::framework::ConfigurableAxis tpctofDeuteron{"tpctofDeuteron", {{300, 0, 3}}, "TPCTOF PID for deuteron"}; + o2::framework::ConfigurableAxis tpctofTriton{"tpctofTriton", {{300, 0, 3}}, "TPCTOF PID for triton"}; + o2::framework::ConfigurableAxis tpctofHelium{"tpctofHelium", {{300, 0, 3}}, "TPCTOF PID for helium"}; +}; + +constexpr const char PrefixTrackQaBinning1[] = "TrackQaBinning1"; +constexpr const char PrefixTrackQaBinning2[] = "TrackQaBinning1"; +constexpr const char PrefixResonancePosDauQaBinning[] = "ResonancePosDauQaBinning"; +constexpr const char PrefixResonanceNegDauQaBinning[] = "ResonanceNegDauQaBinning"; +constexpr const char PrefixV0PosDauQaBinning[] = "V0PosDauQaBinning"; +constexpr const char PrefixV0NegDauQaBinning[] = "V0NegDauQaBinning"; +constexpr const char PrefixCascadePosDauQaBinning[] = "CascadePosDauQaBinning"; +constexpr const char PrefixCascadeNegDauQaBinning[] = "CascadeNegDauQaBinning"; +constexpr const char PrefixCascadeBachelorQaBinning[] = "CascadeBachelorQaBinning"; +constexpr const char PrefixKinkChaDauQaBinning[] = "KinkChaDauQaBinning"; + +using ConfTrackQaBinning1 = ConfTrackQaBinning; +using ConfTrackQaBinning2 = ConfTrackQaBinning; +using ConfResonancePosDauQaBinning = ConfTrackQaBinning; +using ConfResonanceNegDauQaBinning = ConfTrackQaBinning; +using ConfV0PosDauQaBinning = ConfTrackQaBinning; +using ConfV0NegDauQaBinning = ConfTrackQaBinning; +using ConfCascadePosDauQaBinning = ConfTrackQaBinning; +using ConfCascadeNegDauQaBinning = ConfTrackQaBinning; +using ConfCascadeBachelorQaBinning = ConfTrackQaBinning; +using ConfKinkChaDauQaBinning = ConfTrackQaBinning; + +// must be in sync with enum TrackVariables +// the enum gives the correct index in the array +constexpr std::array, kTrackHistLast> HistTable = { + {{kPt, o2::framework::kTH1F, "hPt", "Transverse Momentum; p_{T} (GeV/#it{c}); Entries"}, + {kEta, o2::framework::kTH1F, "hEta", "Pseudorapdity; #eta; Entries"}, + {kPhi, o2::framework::kTH1F, "hPhi", "Azimuthal angle; #varphi; Entries"}, + {kSign, o2::framework::kTH1F, "hSign", "Sign of charge ; Sign; Entries"}, + {kPAtPv, o2::framework::kTH1F, "hPAtPv", "Momentum at Primary vertex; p_{vertex}; Entries"}, + {kPTpc, o2::framework::kTH1F, "hPTpc", "Momentum at inner wall of TPC; p_{TPC}; Entries"}, + {kItsCluster, o2::framework::kTH1F, "hItsCluster", "ITS cluster; ITS cluster; Entries"}, + {kItsClusterIb, o2::framework::kTH1F, "hItsClusterIb", "ITS cluster in inner barrel; ITS IB cluster; Entries"}, + {kTpcCrossedRows, o2::framework::kTH1F, "hTpcCrossedRows", "TPC crossed rows; TPC crossed rows; Entries"}, + {kTpcCluster, o2::framework::kTH1F, "hTpcCluster", "TPC cluster found; TPC cluster found; Entries"}, + {kTpcClusterOverCrossedRows, o2::framework::kTH1F, "hTpcClusterOverCrossedRows", "TPC cluster found over TPC crossed rows; TPC cluster found / Tpc crossed rows; Entries"}, + {kTpcClusterShared, o2::framework::kTH1F, "hTpcClusterShared", "TPC cluster shared; TPC cluster shared ; Entries"}, + {kTpcClusterFractionShared, o2::framework::kTH1F, "hTpcClusterFractionShared", "TPC cluster fraction shared; TPC cluster found / TPC cluster shared ; Entries"}, + {kPtVsEta, o2::framework::kTH2F, "hPtVsEta", "p_{T} vs #eta; p_{T} (GeV/#it{c}) ; #eta"}, + {kPtVsPhi, o2::framework::kTH2F, "hPtVsPhi", "p_{T} vs #varphi; p_{T} (GeV/#it{c}) ; #varphi"}, + {kPhiVsEta, o2::framework::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi ; #eta"}, + {kPtVsItsCluster, o2::framework::kTH2F, "hPtVsItsCluster", "p_{T} vs ITS cluster; p_{T} (GeV/#it{c}) ; ITS cluster"}, + {kPtVsTpcCluster, o2::framework::kTH2F, "hPtVsTpcCluster", "p_{T} vs TPC cluster found; p_{T} (GeV/#it{c}) ; TPC cluster found"}, + {kPtVsTpcCrossedRows, o2::framework::kTH2F, "hPtVsTpcCrossedRows", "p_{T} vs TPC crossed rows; p_{T} (GeV/#it{c}) ; TPC crossed rows"}, + {kPtVsTpcClusterOverCrossedRows, o2::framework::kTH2F, "hPtVsTpcClusterOverCrossedRows", "p_{T} vs TPC cluster found over crossed rows; p_{T} (GeV/#it{c}) ; TPC cluster found / TPC crossed rows"}, + {kPtVsTpcClusterShared, o2::framework::kTH2F, "hPtVsTpcClusterShared", "p_{T} vs TPC cluster shared; p_{T} (GeV/#it{c}) ; TPC cluster shared"}, + {kPtVsTpcClusterFractionShared, o2::framework::kTH2F, "hPtVsTpcClusterSharedFraction", "p_{T} vs TPC cluster shared over TPC cluster found; p_{T} (GeV/#it{c}) ; TPC cluster shared / TPC cluster found"}, + {kTpcClusterVsTpcCrossedRows, o2::framework::kTH2F, "hTpcClusterVsTpcCrossedRows", "TPC cluster found vs TPC crossed rows; TPC cluster found; TPC crossed rows"}, + {kTpcClusterVsTpcClusterShared, o2::framework::kTH2F, "hTpcClusterVsTpcClusterShared", "TPC cluster found vs TPC cluster shared; TPC cluster found; TPC cluster shared"}, + {kPtVsDcaxy, o2::framework::kTH2F, "hPtVsDcaxy", "p_{T} vs DCA_{XY}; p_{T} (GeV/#it{c}); DCA_{XY} (cm)"}, + {kPtVsDcaz, o2::framework::kTH2F, "hPtVsDcaz", "p_{T} vs DCA_{Z}; p_{T} (GeV/#it{c}); DCA_{Z} (cm)"}, + {kPtVsDca, o2::framework::kTH2F, "hPtVsDca", "p_{T} vs DCA; p_{T} (GeV/#it{c}); DCA (cm)"}, + {kItsSignal, o2::framework::kTH2F, "hItsSignal", "ITS Signal; p (GeV/#it{c}) ; x "}, + {kItsElectron, o2::framework::kTH2F, "hItsPidElectron", "TPC PID Electron; p (GeV/#it{c}) ; n#sigma_{TPC,el}"}, + {kItsPion, o2::framework::kTH2F, "hItsPidPion", "ITS PID Pion; p (GeV/#it{c}) ; n#sigma_{ITS,pi}"}, + {kItsKaon, o2::framework::kTH2F, "hItsPidKaon", "ITS PID Kaon; p (GeV/#it{c}) ; n#sigma_{ITS,ka}"}, + {kItsProton, o2::framework::kTH2F, "hItsPidProton", "ITS PID Proton; p (GeV/#it{c}) ; n#sigma_{ITS,pr}"}, + {kItsDeuteron, o2::framework::kTH2F, "hItsPidDeuteron", "ITS PID Deuteron; p (GeV/#it{c}) ; n#sigma_{ITS,de}"}, + {kItsTriton, o2::framework::kTH2F, "hItsPidTriton", "ITS PID Triton; p (GeV/#it{c}) ; n#sigma_{ITS,tr}"}, + {kItsHelium, o2::framework::kTH2F, "hItsPidHelium", "ITS PID Helium; p (GeV/#it{c}) ; n#sigma_{ITS,he}"}, + {kTpcSignal, o2::framework::kTH2F, "hTpcSignal", "TPC Signal; p (GeV/#it{c}) ; TPC Signal"}, + {kTpcElectron, o2::framework::kTH2F, "hTpcPidElectron", "TPC PID Electron; p (GeV/#it{c}) ; n#sigma_{TPC,el}"}, + {kTpcPion, o2::framework::kTH2F, "hTpcPidPion", "TPC PID Pion; p (GeV/#it{c}) ; n#sigma_{TPC,pi}"}, + {kTpcKaon, o2::framework::kTH2F, "hTpcPidKaon", "TPC PID Kaon; p (GeV/#it{c}) ; n#sigma_{TPC,ka}"}, + {kTpcProton, o2::framework::kTH2F, "hTpcPidProton", "TPC PID Proton; p (GeV/#it{c}) ; n#sigma_{TPC,pr}"}, + {kTpcDeuteron, o2::framework::kTH2F, "hTpcPidDeuteron", "TPC PID Deuteron; p (GeV/#it{c}) ; n#sigma_{TPC,de}"}, + {kTpcTriton, o2::framework::kTH2F, "hTpcPidTriton", "TPC PID Triton; p (GeV/#it{c}) ; n#sigma_{TPC,tr}"}, + {kTpcHelium, o2::framework::kTH2F, "hTpcPidHelium", "TPC PID Helium; p (GeV/#it{c}) ; n#sigma_{TPC,he}"}, + {kTofBeta, o2::framework::kTH2F, "hTofBeta", "TOF #beta; p (GeV/#it{c}) ; TOF #beta"}, + {kTofMass, o2::framework::kTH2F, "hTofMass", "TOF mass; p (GeV/#it{c}) ; m_{TOF} (GeV/#it{c}^{2})"}, + {kTofElectron, o2::framework::kTH2F, "hTofPidElectron", "TOF PID Electron; p (GeV/#it{c}) ; n#sigma_{TOF,el}"}, + {kTofPion, o2::framework::kTH2F, "hTofPidPion", "TOF PID Pion; p (GeV/#it{c}) ; n#sigma_{TOF,pi}"}, + {kTofKaon, o2::framework::kTH2F, "hTofPidKaon", "TOF PID Kaon; p (GeV/#it{c}) ; n#sigma_{TOF,ka}"}, + {kTofProton, o2::framework::kTH2F, "hTofPidProton", "TOF PID Proton; p (GeV/#it{c}) ; n#sigma_{TOF,pr}"}, + {kTofDeuteron, o2::framework::kTH2F, "hTofPidDeuteron", "TOF PID Deuteron; p (GeV/#it{c}) ; n#sigma_{TOF,de}"}, + {kTofTriton, o2::framework::kTH2F, "hTofPidTriton", "TOF PID Triton; p (GeV/#it{c}) ; n#sigma_{TOF,tr}"}, + {kTofHelium, o2::framework::kTH2F, "hTofPidHelium", "TOF PID Helium; p (GeV/#it{c}) ; n#sigma_{TOF,he}"}, + {kTpcitsElectron, o2::framework::kTH2F, "hTpcitsPidElectron", "its PID Electron; p (GeV/#it{c}) ; n#sigma_{its,el}"}, + {kTpcitsPion, o2::framework::kTH2F, "hTpcitsPidPion", "TPC+ITS PID Pion; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,pi}^{2}+n#sigma_{its,pi}^{2}}"}, + {kTpcitsKaon, o2::framework::kTH2F, "hTpcitsPidKaon", "TPC+ITS PID Kaon; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,ka}^{2}+n#sigma_{its,ka}^{2}}"}, + {kTpcitsProton, o2::framework::kTH2F, "hTpcitsPidProton", "TPC+ITS PID Proton; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,pr}^{2}+n#sigma_{its,pr}^{2}}"}, + {kTpcitsDeuteron, o2::framework::kTH2F, "hTpcitsPidDeuteron", "TPC+ITS PID Deuteron; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,de}^{2}+n#sigma_{its,de}^{2}}"}, + {kTpcitsTriton, o2::framework::kTH2F, "hTpcitsPidTriton", "TPC+ITS PID Triton; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,tr}^{2}+n#sigma_{its,tr}^{2}}"}, + {kTpcitsHelium, o2::framework::kTH2F, "hTpcitsPidHelium", "TPC+ITS PID Helium; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,he}^{2}+n#sigma_{its,he}^{2}}"}, + {kTpctofElectron, o2::framework::kTH2F, "hTpctofPidElectron", "TOF PID Electron; p (GeV/#it{c}) ; n#sigma_{TOF,el}"}, + {kTpctofPion, o2::framework::kTH2F, "hTpctofPidPion", "TPC+TOF PID Pion; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,pi}^{2}+n#sigma_{TOF,pi}^{2}}"}, + {kTpctofKaon, o2::framework::kTH2F, "hTpctofPidKaon", "TPC+TOF PID Kaon; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,ka}^{2}+n#sigma_{TOF,ka}^{2}}"}, + {kTpctofProton, o2::framework::kTH2F, "hTpctofPidProton", "TPC+TOF PID Proton; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,pr}^{2}+n#sigma_{TOF,pr}^{2}}"}, + {kTpctofDeuteron, o2::framework::kTH2F, "hTpctofPidDeuteron", "TPC+TOF PID Deuteron; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,de}^{2}+n#sigma_{TOF,de}^{2}}"}, + {kTpctofTriton, o2::framework::kTH2F, "hTpctofPidTriton", "TPC+TOF PID Triton; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,tr}^{2}+n#sigma_{TOF,tr}^{2}}"}, + {kTpctofHelium, o2::framework::kTH2F, "hTpctofPidHelium", "TPC+TOF PID Helium; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,he}^{2}+n#sigma_{TOF,he}^{2}}"}}}; + +template +auto makeTrackHistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kSign, {confBinningAnalysis.sign}}}; +}; + +template +auto makeTrackQaHistSpecMap(const T1& confBinningAnalysis, const T2 confiBinningQa) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kSign, {confBinningAnalysis.sign}}, + {kPAtPv, {confiBinningQa.p}}, + {kPTpc, {confiBinningQa.p}}, + {kItsCluster, {confiBinningQa.itsCluster}}, + {kItsClusterIb, {confiBinningQa.itsClusterIb}}, + {kPtVsEta, {confBinningAnalysis.pt, confBinningAnalysis.eta}}, + {kPtVsPhi, {confBinningAnalysis.pt, confBinningAnalysis.phi}}, + {kPhiVsEta, {confBinningAnalysis.phi, confBinningAnalysis.eta}}, + {kPtVsItsCluster, {confBinningAnalysis.pt, confiBinningQa.itsCluster}}, + {kPtVsTpcCluster, {confBinningAnalysis.pt, confiBinningQa.tpcCluster}}, + {kPtVsTpcCrossedRows, {confBinningAnalysis.pt, confiBinningQa.tpcCrossedRows}}, + {kPtVsTpcClusterOverCrossedRows, {confBinningAnalysis.pt, confiBinningQa.tpcClusterOverCrossedRows}}, + {kPtVsTpcClusterShared, {confBinningAnalysis.pt, confiBinningQa.tpcClusterShared}}, + {kPtVsTpcClusterFractionShared, {confBinningAnalysis.pt, confiBinningQa.tpcClusterFractionShared}}, + {kTpcClusterVsTpcCrossedRows, {confiBinningQa.tpcCluster, confiBinningQa.tpcCrossedRows}}, + {kTpcClusterVsTpcClusterShared, {confiBinningQa.tpcCluster, confiBinningQa.tpcClusterShared}}, + {kTpcCrossedRows, {confiBinningQa.tpcCrossedRows}}, + {kTpcCluster, {confiBinningQa.tpcCluster}}, + {kTpcClusterOverCrossedRows, {confiBinningQa.tpcClusterOverCrossedRows}}, + {kTpcClusterShared, {confiBinningQa.tpcClusterShared}}, + {kTpcClusterFractionShared, {confiBinningQa.tpcClusterFractionShared}}, + {kPtVsDcaxy, {confBinningAnalysis.pt, confiBinningQa.dcaXy}}, + {kPtVsDcaz, {confBinningAnalysis.pt, confiBinningQa.dcaZ}}, + {kPtVsDca, {confBinningAnalysis.pt, confiBinningQa.dca}}, + {kItsSignal, {confiBinningQa.p, confiBinningQa.itsSignal}}, + {kItsElectron, {confiBinningQa.p, confiBinningQa.itsElectron}}, + {kItsPion, {confiBinningQa.p, confiBinningQa.itsPion}}, + {kItsKaon, {confiBinningQa.p, confiBinningQa.itsKaon}}, + {kItsProton, {confiBinningQa.p, confiBinningQa.itsProton}}, + {kItsDeuteron, {confiBinningQa.p, confiBinningQa.itsDeuteron}}, + {kItsTriton, {confiBinningQa.p, confiBinningQa.itsTriton}}, + {kItsHelium, {confiBinningQa.p, confiBinningQa.itsHelium}}, + {kTpcSignal, {confiBinningQa.p, confiBinningQa.tpcSignal}}, + {kTpcElectron, {confiBinningQa.p, confiBinningQa.tpcElectron}}, + {kTpcPion, {confiBinningQa.p, confiBinningQa.tpcPion}}, + {kTpcKaon, {confiBinningQa.p, confiBinningQa.tpcKaon}}, + {kTpcProton, {confiBinningQa.p, confiBinningQa.tpcProton}}, + {kTpcDeuteron, {confiBinningQa.p, confiBinningQa.tpcDeuteron}}, + {kTpcTriton, {confiBinningQa.p, confiBinningQa.tpcTriton}}, + {kTpcHelium, {confiBinningQa.p, confiBinningQa.tpcHelium}}, + {kTofBeta, {confiBinningQa.p, confiBinningQa.tofBeta}}, + {kTofMass, {confiBinningQa.p, confiBinningQa.tofMass}}, + {kTofElectron, {confiBinningQa.p, confiBinningQa.tofElectron}}, + {kTofPion, {confiBinningQa.p, confiBinningQa.tofPion}}, + {kTofKaon, {confiBinningQa.p, confiBinningQa.tofKaon}}, + {kTofProton, {confiBinningQa.p, confiBinningQa.tofProton}}, + {kTofDeuteron, {confiBinningQa.p, confiBinningQa.tofDeuteron}}, + {kTofTriton, {confiBinningQa.p, confiBinningQa.tofTriton}}, + {kTofHelium, {confiBinningQa.p, confiBinningQa.tofHelium}}, + {kTpcitsElectron, {confiBinningQa.p, confiBinningQa.tpcitsElectron}}, + {kTpcitsPion, {confiBinningQa.p, confiBinningQa.tpcitsPion}}, + {kTpcitsKaon, {confiBinningQa.p, confiBinningQa.tpcitsKaon}}, + {kTpcitsProton, {confiBinningQa.p, confiBinningQa.tpcitsProton}}, + {kTpcitsDeuteron, {confiBinningQa.p, confiBinningQa.tpcitsDeuteron}}, + {kTpcitsTriton, {confiBinningQa.p, confiBinningQa.tpcitsTriton}}, + {kTpcitsHelium, {confiBinningQa.p, confiBinningQa.tpcitsHelium}}, + {kTpctofElectron, {confiBinningQa.p, confiBinningQa.tpctofElectron}}, + {kTpctofPion, {confiBinningQa.p, confiBinningQa.tpctofPion}}, + {kTpctofKaon, {confiBinningQa.p, confiBinningQa.tpctofKaon}}, + {kTpctofProton, {confiBinningQa.p, confiBinningQa.tpctofProton}}, + {kTpctofDeuteron, {confiBinningQa.p, confiBinningQa.tpctofDeuteron}}, + {kTpctofTriton, {confiBinningQa.p, confiBinningQa.tpctofTriton}}, + {kTpctofHelium, {confiBinningQa.p, confiBinningQa.tpctofHelium}}}; +}; + +constexpr char PrefixTrackQa[] = "TrackQA/"; +constexpr char PrefixTrack1[] = "Track1/"; +constexpr char PrefixTrack2[] = "Track2/"; +constexpr char PrefixTrack3[] = "Track3/"; + +constexpr char PrefixResonancePosDaughter[] = "ResonancePosDau/"; +constexpr char PrefixResonanceNegDaughter[] = "ResonanceNegDau/"; +constexpr char PrefixResonancePosDaughterQa[] = "ResonancePosDauQa/"; +constexpr char PrefixResonanceNegDaughterQa[] = "ResonanceNegDauQa/"; + +constexpr char PrefixV0PosDaughter1[] = "V0PosDau1/"; +constexpr char PrefixV0NegDaughter1[] = "V0NegDau1/"; +constexpr char PrefixV0PosDaughter2[] = "V0PosDau2/"; +constexpr char PrefixV0NegDaughter2[] = "V0NegDau2/"; +constexpr char PrefixV0PosDaughterQa[] = "V0PosDauQa/"; +constexpr char PrefixV0NegDaughterQa[] = "V0NegDauQa/"; + +constexpr char PrefixCascadePosDaughter[] = "CascadePosDau/"; +constexpr char PrefixCascadeNegDaughter[] = "CascadeNegDau/"; +constexpr char PrefixCascadeBachelor[] = "CascadeBachelor/"; +constexpr char PrefixCascadePosDaughterQa[] = "CascadePosDauQa/"; +constexpr char PrefixCascadeNegDaughterQa[] = "CascadeNegDauQa/"; +constexpr char PrefixCascadeBachelorQa[] = "CascadeBachelorQa/"; + +constexpr char PrefixKinkChaDaughter[] = "KinkChaDau/"; +constexpr char PrefixKinkChaDaughterQa[] = "KinkChaDauQa/"; + +constexpr std::string_view AnalysisDir = "Kinematics/"; +constexpr std::string_view QaDir = "QA/"; +constexpr std::string_view PidDir = "PID/"; + +/// \class FemtoDreamEventHisto +/// \brief Class for histogramming event properties +// template +template +class TrackHistManager +{ + public: + TrackHistManager() = default; + ~TrackHistManager() = default; + + void init(o2::framework::HistogramRegistry* registry, std::map> const& Specs, int AbsCharge = 1) + { + mHistogramRegistry = registry; + mAbsCharge = std::abs(AbsCharge); + if constexpr (isFlagSet(mode, modes::Mode::kAnalysis)) { + initAnalysis(Specs); + } + if constexpr (isFlagSet(mode, modes::Mode::kQa)) { + initQa(Specs); + } + } + + template + void enableOptionalHistograms(T const& ConfBinningQa) + { + mPlot2d = ConfBinningQa.plot2d.value; + mPlotElectronPid = ConfBinningQa.plotElectronPid.value; + mPlotPionPid = ConfBinningQa.plotPionPid.value; + mPlotKaonPid = ConfBinningQa.plotKaonPid.value; + mPlotProtonPid = ConfBinningQa.plotProtonPid.value; + mPlotDeuteronPid = ConfBinningQa.plotDeuteronPid.value; + mPlotTritonPid = ConfBinningQa.plotTritonPid.value; + mPlotHeliumPid = ConfBinningQa.plotHeliumPid.value; + mMomentumType = static_cast(ConfBinningQa.momentumType.value); + } + + // special init function for Qa + // passing config group for qa so we can optionally enable histograms via falgsc + template + void init(o2::framework::HistogramRegistry* registry, std::map> const& Specs, T const& ConfBinningQa, int AbsCharge) + { + enableOptionalHistograms(ConfBinningQa); + init(registry, Specs, AbsCharge); + } + + template + void fill(T1 const& track, T2 const& /*trackTable*/) + { + if constexpr (isFlagSet(mode, modes::Mode::kAnalysis)) { + fillAnalysis(track); + } + if constexpr (isFlagSet(mode, modes::Mode::kQa)) { + fillQa(track); + } + } + + private: + void initAnalysis(std::map> const& Specs) + { + std::string analysisDir = std::string(prefix) + std::string(AnalysisDir); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt, HistTable), getHistDesc(kPt, HistTable), getHistType(kPt, HistTable), {Specs.at(kPt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kEta, HistTable), getHistDesc(kEta, HistTable), getHistType(kEta, HistTable), {Specs.at(kEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhi, HistTable), getHistDesc(kPhi, HistTable), getHistType(kPhi, HistTable), {Specs.at(kPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kSign, HistTable), getHistDesc(kSign, HistTable), getHistType(kSign, HistTable), {Specs.at(kSign)}); + } + + void initQa(std::map> const& Specs) + { + std::string qaDir = std::string(prefix) + std::string(QaDir); + + mHistogramRegistry->add(qaDir + getHistNameV2(kPAtPv, HistTable), getHistDesc(kPAtPv, HistTable), getHistType(kPAtPv, HistTable), {Specs.at(kPAtPv)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPTpc, HistTable), getHistDesc(kPTpc, HistTable), getHistType(kPTpc, HistTable), {Specs.at(kPTpc)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kItsCluster, HistTable), getHistDesc(kItsCluster, HistTable), getHistType(kItsCluster, HistTable), {Specs.at(kItsCluster)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kItsClusterIb, HistTable), getHistDesc(kItsClusterIb, HistTable), getHistType(kItsClusterIb, HistTable), {Specs.at(kItsClusterIb)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTpcCrossedRows, HistTable), getHistDesc(kTpcCrossedRows, HistTable), getHistType(kTpcCrossedRows, HistTable), {Specs.at(kTpcCrossedRows)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTpcCluster, HistTable), getHistDesc(kTpcCluster, HistTable), getHistType(kTpcCluster, HistTable), {Specs.at(kTpcCluster)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTpcClusterOverCrossedRows, HistTable), getHistDesc(kTpcClusterOverCrossedRows, HistTable), getHistType(kTpcClusterOverCrossedRows, HistTable), {Specs.at(kTpcClusterOverCrossedRows)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTpcClusterShared, HistTable), getHistDesc(kTpcClusterShared, HistTable), getHistType(kTpcClusterShared, HistTable), {Specs.at(kTpcClusterShared)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTpcClusterFractionShared, HistTable), getHistDesc(kTpcClusterFractionShared, HistTable), getHistType(kTpcClusterFractionShared, HistTable), {Specs.at(kTpcClusterFractionShared)}); + + // qa 2d + if (mPlot2d) { + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsEta, HistTable), getHistDesc(kPtVsEta, HistTable), getHistType(kPtVsEta, HistTable), {Specs.at(kPtVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsPhi, HistTable), getHistDesc(kPtVsPhi, HistTable), getHistType(kPtVsPhi, HistTable), {Specs.at(kPtVsPhi)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPhiVsEta, HistTable), getHistDesc(kPhiVsEta, HistTable), getHistType(kPhiVsEta, HistTable), {Specs.at(kPhiVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsItsCluster, HistTable), getHistDesc(kPtVsItsCluster, HistTable), getHistType(kPtVsItsCluster, HistTable), {Specs.at(kPtVsItsCluster)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsTpcCluster, HistTable), getHistDesc(kPtVsTpcCluster, HistTable), getHistType(kPtVsTpcCluster, HistTable), {Specs.at(kPtVsTpcCluster)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsTpcCrossedRows, HistTable), getHistDesc(kPtVsTpcCrossedRows, HistTable), getHistType(kPtVsTpcCrossedRows, HistTable), {Specs.at(kPtVsTpcCrossedRows)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsTpcClusterOverCrossedRows, HistTable), getHistDesc(kPtVsTpcClusterOverCrossedRows, HistTable), getHistType(kPtVsTpcClusterOverCrossedRows, HistTable), {Specs.at(kPtVsTpcClusterOverCrossedRows)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsTpcClusterShared, HistTable), getHistDesc(kPtVsTpcClusterShared, HistTable), getHistType(kPtVsTpcClusterShared, HistTable), {Specs.at(kPtVsTpcClusterShared)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsTpcClusterFractionShared, HistTable), getHistDesc(kPtVsTpcClusterFractionShared, HistTable), getHistType(kPtVsTpcClusterFractionShared, HistTable), {Specs.at(kPtVsTpcClusterFractionShared)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTpcClusterVsTpcCrossedRows, HistTable), getHistDesc(kTpcClusterVsTpcCrossedRows, HistTable), getHistType(kTpcClusterVsTpcCrossedRows, HistTable), {Specs.at(kTpcClusterVsTpcCrossedRows)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTpcClusterVsTpcClusterShared, HistTable), getHistDesc(kTpcClusterVsTpcClusterShared, HistTable), getHistType(kTpcClusterVsTpcClusterShared, HistTable), {Specs.at(kTpcClusterVsTpcClusterShared)}); + // dca + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsDcaxy, HistTable), getHistDesc(kPtVsDcaxy, HistTable), getHistType(kPtVsDcaxy, HistTable), {Specs.at(kPtVsDcaxy)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsDcaz, HistTable), getHistDesc(kPtVsDcaz, HistTable), getHistType(kPtVsDcaz, HistTable), {Specs.at(kPtVsDcaz)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsDca, HistTable), getHistDesc(kPtVsDca, HistTable), getHistType(kPtVsDca, HistTable), {Specs.at(kPtVsDca)}); + } + + std::string pidDir = std::string(prefix) + std::string(PidDir); + + mHistogramRegistry->add(pidDir + getHistNameV2(kItsSignal, HistTable), getHistDesc(kItsSignal, HistTable), getHistType(kItsSignal, HistTable), {Specs.at(kItsSignal)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcSignal, HistTable), getHistDesc(kTpcSignal, HistTable), getHistType(kTpcSignal, HistTable), {Specs.at(kTpcSignal)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofBeta, HistTable), getHistDesc(kTofBeta, HistTable), getHistType(kTofBeta, HistTable), {Specs.at(kTofBeta)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofMass, HistTable), getHistDesc(kTofMass, HistTable), getHistType(kTofMass, HistTable), {Specs.at(kTofMass)}); + + if (mPlotElectronPid) { + mHistogramRegistry->add(pidDir + getHistNameV2(kItsElectron, HistTable), getHistDesc(kItsElectron, HistTable), getHistType(kItsElectron, HistTable), {Specs.at(kItsElectron)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcElectron, HistTable), getHistDesc(kTpcElectron, HistTable), getHistType(kTpcElectron, HistTable), {Specs.at(kTpcElectron)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofElectron, HistTable), getHistDesc(kTofElectron, HistTable), getHistType(kTofElectron, HistTable), {Specs.at(kTofElectron)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcitsElectron, HistTable), getHistDesc(kTpcitsElectron, HistTable), getHistType(kTpcitsElectron, HistTable), {Specs.at(kTpcitsElectron)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpctofElectron, HistTable), getHistDesc(kTpctofElectron, HistTable), getHistType(kTpctofElectron, HistTable), {Specs.at(kTpctofElectron)}); + } + + if (mPlotPionPid) { + mHistogramRegistry->add(pidDir + getHistNameV2(kItsPion, HistTable), getHistDesc(kItsPion, HistTable), getHistType(kItsPion, HistTable), {Specs.at(kItsPion)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcPion, HistTable), getHistDesc(kTpcPion, HistTable), getHistType(kTpcPion, HistTable), {Specs.at(kTpcPion)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofPion, HistTable), getHistDesc(kTofPion, HistTable), getHistType(kTofPion, HistTable), {Specs.at(kTofPion)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcitsPion, HistTable), getHistDesc(kTpcitsPion, HistTable), getHistType(kTpcitsPion, HistTable), {Specs.at(kTpcitsPion)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpctofPion, HistTable), getHistDesc(kTpctofPion, HistTable), getHistType(kTpctofPion, HistTable), {Specs.at(kTpctofPion)}); + } + + if (mPlotKaonPid) { + mHistogramRegistry->add(pidDir + getHistNameV2(kItsKaon, HistTable), getHistDesc(kItsKaon, HistTable), getHistType(kItsKaon, HistTable), {Specs.at(kItsKaon)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcKaon, HistTable), getHistDesc(kTpcKaon, HistTable), getHistType(kTpcKaon, HistTable), {Specs.at(kTpcKaon)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofKaon, HistTable), getHistDesc(kTofKaon, HistTable), getHistType(kTofKaon, HistTable), {Specs.at(kTofKaon)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcitsKaon, HistTable), getHistDesc(kTpcitsKaon, HistTable), getHistType(kTpcitsKaon, HistTable), {Specs.at(kTpcitsKaon)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpctofKaon, HistTable), getHistDesc(kTpctofKaon, HistTable), getHistType(kTpctofKaon, HistTable), {Specs.at(kTpctofKaon)}); + } + + if (mPlotProtonPid) { + mHistogramRegistry->add(pidDir + getHistNameV2(kItsProton, HistTable), getHistDesc(kItsProton, HistTable), getHistType(kItsProton, HistTable), {Specs.at(kItsProton)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcProton, HistTable), getHistDesc(kTpcProton, HistTable), getHistType(kTpcProton, HistTable), {Specs.at(kTpcProton)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofProton, HistTable), getHistDesc(kTofProton, HistTable), getHistType(kTofProton, HistTable), {Specs.at(kTofProton)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcitsProton, HistTable), getHistDesc(kTpcitsProton, HistTable), getHistType(kTpcitsProton, HistTable), {Specs.at(kTpcitsProton)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpctofProton, HistTable), getHistDesc(kTpctofProton, HistTable), getHistType(kTpctofProton, HistTable), {Specs.at(kTpctofProton)}); + } + + if (mPlotDeuteronPid) { + mHistogramRegistry->add(pidDir + getHistNameV2(kItsDeuteron, HistTable), getHistDesc(kItsDeuteron, HistTable), getHistType(kItsDeuteron, HistTable), {Specs.at(kItsDeuteron)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcDeuteron, HistTable), getHistDesc(kTpcDeuteron, HistTable), getHistType(kTpcDeuteron, HistTable), {Specs.at(kTpcDeuteron)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofDeuteron, HistTable), getHistDesc(kTofDeuteron, HistTable), getHistType(kTofDeuteron, HistTable), {Specs.at(kTofDeuteron)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcitsDeuteron, HistTable), getHistDesc(kTpcitsDeuteron, HistTable), getHistType(kTpcitsDeuteron, HistTable), {Specs.at(kTpcitsDeuteron)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpctofDeuteron, HistTable), getHistDesc(kTpctofDeuteron, HistTable), getHistType(kTpctofDeuteron, HistTable), {Specs.at(kTpctofDeuteron)}); + } + + if (mPlotTritonPid) { + mHistogramRegistry->add(pidDir + getHistNameV2(kItsTriton, HistTable), getHistDesc(kItsTriton, HistTable), getHistType(kItsTriton, HistTable), {Specs.at(kItsTriton)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcTriton, HistTable), getHistDesc(kTpcTriton, HistTable), getHistType(kTpcTriton, HistTable), {Specs.at(kTpcTriton)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofTriton, HistTable), getHistDesc(kTofTriton, HistTable), getHistType(kTofTriton, HistTable), {Specs.at(kTofTriton)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcitsTriton, HistTable), getHistDesc(kTpcitsTriton, HistTable), getHistType(kTpcitsTriton, HistTable), {Specs.at(kTpcitsTriton)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpctofTriton, HistTable), getHistDesc(kTpctofTriton, HistTable), getHistType(kTpctofTriton, HistTable), {Specs.at(kTpctofTriton)}); + } + + if (mPlotHeliumPid) { + mHistogramRegistry->add(pidDir + getHistNameV2(kItsHelium, HistTable), getHistDesc(kItsHelium, HistTable), getHistType(kItsHelium, HistTable), {Specs.at(kItsHelium)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcHelium, HistTable), getHistDesc(kTpcHelium, HistTable), getHistType(kTpcHelium, HistTable), {Specs.at(kTpcHelium)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTofHelium, HistTable), getHistDesc(kTofHelium, HistTable), getHistType(kTofHelium, HistTable), {Specs.at(kTofHelium)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpcitsHelium, HistTable), getHistDesc(kTpcitsHelium, HistTable), getHistType(kTpcitsHelium, HistTable), {Specs.at(kTpcitsHelium)}); + mHistogramRegistry->add(pidDir + getHistNameV2(kTpctofHelium, HistTable), getHistDesc(kTpctofHelium, HistTable), getHistType(kTpctofHelium, HistTable), {Specs.at(kTpctofHelium)}); + } + } + + template + void fillAnalysis(T const& track) + { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt, HistTable)), mAbsCharge * track.pt()); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kEta, HistTable)), track.eta()); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPhi, HistTable)), track.phi()); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), track.sign()); + } + + template + void fillQa(T const& track) + { + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPAtPv, HistTable)), track.p()); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPTpc, HistTable)), track.tpcInnerParam()); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kItsCluster, HistTable)), static_cast(track.itsNCls())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kItsClusterIb, HistTable)), static_cast(track.itsNClsInnerBarrel())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kTpcCrossedRows, HistTable)), static_cast(track.tpcNClsCrossedRows())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kTpcCluster, HistTable)), static_cast(track.tpcNClsFound())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kTpcClusterOverCrossedRows, HistTable)), static_cast(track.tpcNClsFound()) / static_cast(track.tpcNClsCrossedRows())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kTpcClusterShared, HistTable)), static_cast(track.tpcNClsShared())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kTpcClusterFractionShared, HistTable)), track.tpcSharedOverFound()); + + if (mPlot2d) { + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsEta, HistTable)), mAbsCharge * track.pt(), track.eta()); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsPhi, HistTable)), mAbsCharge * track.pt(), track.phi()); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPhiVsEta, HistTable)), track.phi(), track.eta()); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsItsCluster, HistTable)), mAbsCharge * track.pt(), static_cast(track.itsNCls())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsTpcCluster, HistTable)), mAbsCharge * track.pt(), static_cast(track.tpcNClsFound())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsTpcCrossedRows, HistTable)), mAbsCharge * track.pt(), static_cast(track.tpcNClsCrossedRows())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsTpcClusterOverCrossedRows, HistTable)), mAbsCharge * track.pt(), static_cast(track.tpcNClsFound()) / static_cast(track.tpcNClsCrossedRows())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsTpcClusterShared, HistTable)), mAbsCharge * track.pt(), static_cast(track.tpcNClsShared())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsTpcClusterFractionShared, HistTable)), mAbsCharge * track.pt(), static_cast(track.tpcNClsShared()) / static_cast(track.tpcNClsFound())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kTpcClusterVsTpcCrossedRows, HistTable)), static_cast(track.tpcNClsFound()), static_cast(track.tpcNClsCrossedRows())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kTpcClusterVsTpcClusterShared, HistTable)), static_cast(track.tpcNClsFound()), static_cast(track.tpcNClsShared())); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsDcaxy, HistTable)), mAbsCharge * track.pt(), track.dcaXY()); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsDcaz, HistTable)), mAbsCharge * track.pt(), track.dcaZ()); + mHistogramRegistry->fill(HIST(prefix) + HIST(QaDir) + HIST(getHistName(kPtVsDca, HistTable)), mAbsCharge * track.pt(), track.dca()); + } + + float momentum = 0.f; + if (mMomentumType == modes::MomentumType::kPt) { + momentum = mAbsCharge * track.p(); + } else if (mMomentumType == modes::MomentumType::kPAtPv) { + momentum = mAbsCharge * track.pt(); + } else if (mMomentumType == modes::MomentumType::kPTpc) { + momentum = track.tpcInnerParam(); + } else { + LOG(warn) << "Invalid momentum type for PID plots"; + momentum = 0; + } + + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kItsSignal, HistTable)), momentum, o2::analysis::femto::utils::itsSignal(track)); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcSignal, HistTable)), momentum, track.tpcSignal()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofBeta, HistTable)), momentum, track.tofBeta()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofMass, HistTable)), momentum, track.tofMass()); + + if (mPlotElectronPid) { + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kItsElectron, HistTable)), momentum, track.itsNSigmaEl()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcElectron, HistTable)), momentum, track.tpcNSigmaEl()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofElectron, HistTable)), momentum, track.tofNSigmaEl()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsElectron, HistTable)), momentum, track.tpcitsNSigmaEl()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofElectron, HistTable)), momentum, track.tpctofNSigmaEl()); + } + + if (mPlotPionPid) { + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kItsPion, HistTable)), momentum, track.itsNSigmaPi()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcPion, HistTable)), momentum, track.tpcNSigmaPi()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofPion, HistTable)), momentum, track.tofNSigmaPi()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsPion, HistTable)), momentum, track.tpcitsNSigmaPi()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofPion, HistTable)), momentum, track.tpctofNSigmaPi()); + } + + if (mPlotKaonPid) { + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kItsKaon, HistTable)), momentum, track.itsNSigmaKa()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcKaon, HistTable)), momentum, track.tpcNSigmaKa()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofKaon, HistTable)), momentum, track.tofNSigmaKa()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsKaon, HistTable)), momentum, track.tpcitsNSigmaKa()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofKaon, HistTable)), momentum, track.tpctofNSigmaKa()); + } + + if (mPlotProtonPid) { + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kItsProton, HistTable)), momentum, track.itsNSigmaPr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcProton, HistTable)), momentum, track.tpcNSigmaPr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofProton, HistTable)), momentum, track.tofNSigmaPr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsProton, HistTable)), momentum, track.tpcitsNSigmaPr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofProton, HistTable)), momentum, track.tpctofNSigmaPr()); + } + + if (mPlotDeuteronPid) { + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kItsDeuteron, HistTable)), momentum, track.itsNSigmaDe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcDeuteron, HistTable)), momentum, track.tpcNSigmaDe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofDeuteron, HistTable)), momentum, track.tofNSigmaDe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsDeuteron, HistTable)), momentum, track.tpcitsNSigmaDe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofDeuteron, HistTable)), momentum, track.tpctofNSigmaDe()); + } + + if (mPlotTritonPid) { + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kItsTriton, HistTable)), momentum, track.itsNSigmaTr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcTriton, HistTable)), momentum, track.tpcNSigmaTr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofTriton, HistTable)), momentum, track.tofNSigmaTr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsTriton, HistTable)), momentum, track.tpcitsNSigmaTr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofTriton, HistTable)), momentum, track.tpctofNSigmaTr()); + } + + if (mPlotHeliumPid) { + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kItsHelium, HistTable)), momentum, track.itsNSigmaHe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcHelium, HistTable)), momentum, track.tpcNSigmaHe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofHelium, HistTable)), momentum, track.tofNSigmaHe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsHelium, HistTable)), momentum, track.tpcitsNSigmaHe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofHelium, HistTable)), momentum, track.tpctofNSigmaHe()); + } + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + int mAbsCharge = 1; + bool mPlot2d = false; + bool mPlotElectronPid = false; + bool mPlotPionPid = false; + bool mPlotKaonPid = false; + bool mPlotProtonPid = false; + bool mPlotDeuteronPid = false; + bool mPlotTritonPid = false; + bool mPlotHeliumPid = false; + modes::MomentumType mMomentumType = modes::MomentumType::kPAtPv; +}; +}; // namespace trackhistmanager +// aespace trackhistmanager +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_TRACKHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/twoTrackResonanceBuilder.h b/PWGCF/Femto/Core/twoTrackResonanceBuilder.h new file mode 100644 index 00000000000..a1add5f0a27 --- /dev/null +++ b/PWGCF/Femto/Core/twoTrackResonanceBuilder.h @@ -0,0 +1,621 @@ +// 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 twoTrackResonanceBuilder.h +/// \brief two track resonance builder +/// \author anton.riedel@tum.de, TU München, anton.riedel@tum.de + +#ifndef PWGCF_FEMTO_CORE_TWOTRACKRESONANCEBUILDER_H_ +#define PWGCF_FEMTO_CORE_TWOTRACKRESONANCEBUILDER_H_ + +#include "RecoDecay.h" + +#include "PWGCF/Femto/Core/baseSelection.h" +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/selectionContainer.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" + +#include + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace twotrackresonancebuilder +{ + +struct ConfTwoTrackResonanceDaughterFilters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("TwoTrackResonanceDaughterFilter"); + o2::framework::Configurable ptMin{"ptMin", 0.2f, "Minimum pT of daughters"}; + o2::framework::Configurable ptMax{"ptMax", 6.f, "Maximum pT of daughters"}; + o2::framework::Configurable etaMin{"etaMin", -0.9f, "Minimum eta of daughters"}; + o2::framework::Configurable etaMax{"etaMax", 0.9f, "Maximum eta of daughters"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi of daughters"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi of daughters"}; +}; + +template +struct ConfTwoTrackResonanceFilters : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable ptMin{"ptMin", 0.2f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 6.f, "Maximum pT"}; + o2::framework::Configurable etaMin{"etaMin", -0.9f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 0.9f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + o2::framework::Configurable massMin{"massMin", 0.f, "Minimum invariant mass for Resonance"}; + o2::framework::Configurable massMax{"massMax", 6.f, "Maximum invariant mass for Resonance"}; +}; +constexpr const char PrefixRhoFilters[] = "Rho0Filters1"; +constexpr const char PrefixPhiFilters[] = "PhiFilters1"; +constexpr const char PrefixKstarFilters[] = "Kstar0Filters1"; +using ConfRhoFilters = ConfTwoTrackResonanceFilters; +using ConfPhiFilters = ConfTwoTrackResonanceFilters; +using ConfKstarFilters = ConfTwoTrackResonanceFilters; + +#define TWOTRACKRESONANCE_DEFAULT_BITS(posThres, negThres) \ + o2::framework::Configurable> dauEtaMax{"dauEtaMax", {0.8f}, "Maximum |eta| "}; \ + o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {90.f}, "Minimum number of clusters in TPC"}; \ + o2::framework::Configurable> dauDcaxyMax{"dauDcaxyMax", {"0.004 + 0.013*pow(x, -1)"}, "Maximum |dca_xy| as a function of pT"}; \ + o2::framework::Configurable> dauDcazMax{"dauDcazMax", {"0.004 + 0.013*pow(x, -1)"}, "Maximum |dca_z| as a function of pT"}; \ + o2::framework::Configurable> posDauPtMin{"posDauPtMin", {0.2f}, "Minimum pT of positive daughter "}; \ + o2::framework::Configurable> posDauPtMax{"posDauPtMax", {6.f}, "Maximum pT of the positive daughter"}; \ + o2::framework::Configurable> negDauPtMin{"negDauPtMin", {0.2f}, "Minimum pT of negative daughter "}; \ + o2::framework::Configurable> negDauPtMax{"negDauPtMax", {6.f}, "Maximum pT of the negative daughter"}; \ + o2::framework::Configurable> posDauMinMomForTof{"posDauMinMomForTof", {posThres}, "Minimum momentum to require TOF PID (positive daughters)"}; \ + o2::framework::Configurable> negDauMinMomForTof{"negDauMinMomForTof", {negThres}, "Minimum momentum to require TOF PID (negative daughters)"}; + +#define TWOTRACKRESONANCE_PIONPID_BITS \ + o2::framework::Configurable> posDauTpcPion{"posDauTpcPion", {3.f}, "Maximum |nsimga_Pion| TPC for positive daughter tracks"}; \ + o2::framework::Configurable> posDauTofPion{"posDauTofPion", {}, "Maximum |nsimga_Pion| TOF for positive daughter tracks"}; \ + o2::framework::Configurable> posDauTpctofPion{"posDauTpctofPion", {3.f}, "Maximum |nsimga_Pion| TPCTOF for positive daughter tracks"}; \ + o2::framework::Configurable> negDauTpcPion{"negDauTpcPion", {3.f}, "Maximum |nsimga_Pion| TPC for negative daughter tracks"}; \ + o2::framework::Configurable> negDauTofPion{"negDauTofPion", {}, "Maximum |nsimga_Pion| TOF for negative daughter tracks"}; \ + o2::framework::Configurable> negDauTpctofPion{"negDauTpctofPion", {3.f}, "Maximum |nsimga_Pion| TPCTOF for negative daughter tracks"}; + +#define TWOTRACKRESONANCE_KAONPID_BITS \ + o2::framework::Configurable> posDauTpcKaon{"posDauTpcKaon", {3.f}, "Maximum |nsimga_Kaon| TPC for positive daughter tracks"}; \ + o2::framework::Configurable> posDauTofKaon{"posDauTofKaon", {}, "Maximum |nsimga_Kaon| TOF for positive daughter tracks"}; \ + o2::framework::Configurable> posDauTpctofKaon{"posDauTpctofKaon", {3.f}, "Maximum |nsimga_Kaon| TPCTOF for positive daughter tracks"}; \ + o2::framework::Configurable> negDauTpcKaon{"negDauTpcKaon", {3.f}, "Maximum |nsimga_Kaon| TPC for negative daughter tracks"}; \ + o2::framework::Configurable> negDauTofKaon{"negDauTofKaon", {}, "Maximum |nsimga_Kaon| TOF for negative daughter tracks"}; \ + o2::framework::Configurable> negDauTpctofKaon{"negDauTpctofKaon", {3.f}, "Maximum |nsimga_Kaon| TPCTOF for negative daughter tracks"}; + +struct ConfPhiBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("PhiBits"); + TWOTRACKRESONANCE_DEFAULT_BITS(0.4f, 0.4f) + TWOTRACKRESONANCE_KAONPID_BITS +}; + +struct ConfRho0Bits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("Rho0Bits"); + TWOTRACKRESONANCE_DEFAULT_BITS(0.5f, 0.5f) + TWOTRACKRESONANCE_PIONPID_BITS +}; + +struct ConfKstar0Bits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("Kstar0Bits"); + TWOTRACKRESONANCE_DEFAULT_BITS(0.5f, 0.4f) + TWOTRACKRESONANCE_PIONPID_BITS + TWOTRACKRESONANCE_KAONPID_BITS +}; + +#undef TWOTRACKRESONANCE_DEFAULT_BITS +#undef TWOTRACKRESONANCE_KAONPID_BITS +#undef TWOTRACKRESONANCE_PIONPID_BITS + +#define TWOTRACKRESONANCE_DEFAULT_SELECTION(defaultPdgCode, defaultMassMin, defaultMassMax) \ + o2::framework::Configurable pdgCode{"pdgCode", defaultPdgCode, "Resonance PDG code"}; \ + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; \ + o2::framework::Configurable ptMax{"ptMax", 6.f, "Maximum pT"}; \ + o2::framework::Configurable etaMin{"etaMin", -0.9f, "Minimum eta"}; \ + o2::framework::Configurable etaMax{"etaMax", 0.9f, "Maximum eta"}; \ + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; \ + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; \ + o2::framework::Configurable massMin{"massMin", defaultMassMin, "Minimum invariant mass for Resonance"}; \ + o2::framework::Configurable massMax{"massMax", defaultMassMax, "Maximum invariant mass for Resonance"}; \ + o2::framework::Configurable posDauBitForThres{"posDauBitForThres", 0x20u, "Bit marking momentum threshold for positive daughter"}; \ + o2::framework::Configurable posDauMaskBelowThres{"posDauMaskBelowThres", 0x10u, "Bitmask for positive daughter below threshold"}; \ + o2::framework::Configurable posDauMaskAboveThres{"posDauMaskAboveThres", 0x8u, "Bitmask for positive daughter above threshold"}; \ + o2::framework::Configurable negDauBitForThres{"negDauBitForThres", 0x4u, "Bit marking momentum threshold for negative daughter"}; \ + o2::framework::Configurable negDauMaskBelowThres{"negDauMaskBelowThres", 0x2u, "Bitmask for negative daughter below threshold"}; \ + o2::framework::Configurable negDauMaskAboveThres{"negDauMaskAboveThres", 0x1u, "Bitmask for negative daughter above threshold"}; + +struct ConfPhiSelection : o2::framework::ConfigurableGroup { + std::string prefix = std::string("PhiSelection"); + TWOTRACKRESONANCE_DEFAULT_SELECTION(333, 0.95f, 1.05f) +}; + +struct ConfRho0Selection : o2::framework::ConfigurableGroup { + std::string prefix = std::string("Rho0Selection"); + TWOTRACKRESONANCE_DEFAULT_SELECTION(113, 0.7f, 0.84f) +}; + +struct ConfKstar0Selection : o2::framework::ConfigurableGroup { + std::string prefix = std::string("Kstar0Selection"); + o2::framework::Configurable sign{"sign", 1, "Sign (+1 for Kstar0 and -1 for Kstar0Bar) "}; + TWOTRACKRESONANCE_DEFAULT_SELECTION(313, 0.8f, 1.0f) +}; + +#undef TWOTRACKRESONANCE_DEFAULT_SELECTION + +/// The different selections this task is capable of doing +enum TwoTrackResonanceSels { + + // common selections for both daughters + kDauEtaAbsMax, ///< max |eta| + kDauTpcClusterMin, ///< min number of TPC cluster + kDauDcaxyAbsMax, ///< max |DCA_xy| + kDauDcazAbsMax, ///< max |DCA_z| + + // selection for positive daughter + // add one bit for the momentum threshold + // when the partition for a resonance is build, we do not have information about the daughter tracks so have to store everything needed for the selection here + kPosDauMinMomForTof, ///< min p for TOF + kPosDauPtMin, ///< min pt + kPosDauPtMax, ///< max pt + kPosDauTpcPion, /// < max |nsigma_TPC| for pion + kPosDauTofPion, /// < max |nsigma_TOF| for pion + kPosDauTpctofPion, /// < max |nsigma_TPC+TOF| for pion + kPosDauTpcKaon, /// < max |nsigma_TPC| for kaon + kPosDauTofKaon, /// < max |nsigma_TOF| for kaon + kPosDauTpctofKaon, /// < max |nsigma_TPC+TOF| for kaon + + // selection for negative daughter + kNegDauMinMomForTof, ///< min p for TOF + kNegDauPtMin, ///< min pt + kNegDauPtMax, ///< max pt + kNegDauTpcPion, /// < max |nsigma_TPC| for pion + kNegDauTofPion, /// < max |nsigma_TOF| for pion + kNegDauTpctofPion, /// < max |nsigma_TPC+TOF| for pion + kNegDauTpcKaon, /// < max |nsigma_TPC| for kaon + kNegDauTofKaon, /// < max |nsigma_TOF| for kaon + kNegDauTpctofKaon, /// < max |nsigma_TPC+TOF| for kaon + + kResonanceSelsMax +}; + +constexpr char PhiSelHistName[] = "hPhiSelection"; +constexpr char RhoSelHistName[] = "hRhoSelection"; +constexpr char Kstar0SelHistName[] = "hKstar0Selection"; +constexpr char Kstar0barSelHistName[] = "hKstar0BarSelection"; +constexpr char TwoTrackResonanceSelsName[] = "TwoTrackResonance Selection Object"; +const std::unordered_map twoTrackResonanceSelectionNames = { + {kDauEtaAbsMax, "Max. |eta| of daughters"}, + {kDauTpcClusterMin, "Min. number of TPC clusters of daughters"}, + {kDauDcaxyAbsMax, "Max. |DCA_xy| of daughters"}, + {kDauDcazAbsMax, "Max. |DCA_z| of the daughters"}, + {kPosDauMinMomForTof, "Min. p of TOF PID of positive daughter"}, + {kPosDauPtMin, "Min. pt of positive daughter"}, + {kPosDauPtMax, "Max. pt of positive daughter"}, + {kPosDauTpcPion, "Max. |sigma_TPC| for pion of positive daughter"}, + {kPosDauTofPion, "Max. |sigma_TOF| for pion of positive daughter"}, + {kPosDauTpctofPion, "Max. |sigma_TPCTOF| for pion of positive daughter"}, + {kPosDauTpcKaon, "Max. |sigma_TPC| for kaon of positive daughter"}, + {kPosDauTofKaon, "Max. |sigma_TOF| for kaon of positive daughter"}, + {kPosDauTpctofKaon, "Max. |sigma_TPCTOF| for kaon of positive daughter"}, + {kNegDauMinMomForTof, "Min. p for TOF PID of negative daughter"}, + {kNegDauPtMin, "Min. pt of negative daughter"}, + {kNegDauPtMax, "Max. pt of negative daughter"}, + {kNegDauTpcPion, "Max. |sigma_TPC| for pion of negative daughter"}, + {kNegDauTofPion, "Max. |sigma_TOF| for pion of negative daughter"}, + {kNegDauTpctofPion, "Max. |sigma_TPCTOF| for pion of negative daughter"}, + {kNegDauTpcKaon, "Max. |sigma_TPC| for kaon of negative daughter"}, + {kNegDauTofKaon, "Max. |sigma_TOF| for kaon of negative daughter"}, + {kNegDauTpctofKaon, "Max. |sigma_TPCTOF| for kaon of negative daughter"}}; + +/// \class FemtoDreamTrackCuts +/// \brief Cut class to contain and execute all cuts applied to tracks +template +class TwoTrackResonanceSelection : public BaseSelection +{ + public: + TwoTrackResonanceSelection() = default; + ~TwoTrackResonanceSelection() = default; + + template + void configure(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& daughterFilter) + { + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kPhi)) { + mPosDaughterMass = o2::constants::physics::MassKPlus; + mNegDaughterMass = o2::constants::physics::MassKMinus; + this->addSelection(kPosDauTpcKaon, twoTrackResonanceSelectionNames.at(kPosDauTpcKaon), config.posDauTpcKaon.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kPosDauTofKaon, twoTrackResonanceSelectionNames.at(kPosDauTofKaon), config.posDauTofKaon.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kPosDauTpctofKaon, twoTrackResonanceSelectionNames.at(kPosDauTpctofKaon), config.posDauTpctofKaon.value, limits::kUpperLimit, false, false, true); + this->addSelection(kNegDauTpcKaon, twoTrackResonanceSelectionNames.at(kNegDauTpcKaon), config.negDauTpcKaon.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kNegDauTofKaon, twoTrackResonanceSelectionNames.at(kNegDauTofKaon), config.negDauTofKaon.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kNegDauTpctofKaon, twoTrackResonanceSelectionNames.at(kNegDauTpctofKaon), config.negDauTpctofKaon.value, limits::kUpperLimit, false, false, true); + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kRho0)) { + mPosDaughterMass = o2::constants::physics::MassPiPlus; + mNegDaughterMass = o2::constants::physics::MassPiMinus; + this->addSelection(kPosDauTpcPion, twoTrackResonanceSelectionNames.at(kPosDauTpcPion), config.posDauTpcPion.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kPosDauTofPion, twoTrackResonanceSelectionNames.at(kPosDauTofPion), config.posDauTofPion.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kPosDauTpctofPion, twoTrackResonanceSelectionNames.at(kPosDauTpctofPion), config.posDauTpctofPion.value, limits::kUpperLimit, false, false, true); + this->addSelection(kNegDauTpcPion, twoTrackResonanceSelectionNames.at(kNegDauTpcPion), config.negDauTpcPion.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kNegDauTofPion, twoTrackResonanceSelectionNames.at(kNegDauTofPion), config.negDauTofPion.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kNegDauTpctofPion, twoTrackResonanceSelectionNames.at(kNegDauTpctofPion), config.negDauTpctofPion.value, limits::kUpperLimit, false, false, true); + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kKstar0)) { + mPosDaughterMass = o2::constants::physics::MassKPlus; + mNegDaughterMass = o2::constants::physics::MassPiMinus; + this->addSelection(kPosDauTpcKaon, twoTrackResonanceSelectionNames.at(kPosDauTpcKaon), config.posDauTpcKaon.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kPosDauTofKaon, twoTrackResonanceSelectionNames.at(kPosDauTofKaon), config.posDauTofKaon.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kPosDauTpctofKaon, twoTrackResonanceSelectionNames.at(kPosDauTpctofKaon), config.posDauTpctofKaon.value, limits::kUpperLimit, false, false, true); + this->addSelection(kNegDauTpcPion, twoTrackResonanceSelectionNames.at(kNegDauTpcPion), config.negDauTpcPion.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kNegDauTofPion, twoTrackResonanceSelectionNames.at(kNegDauTofPion), config.negDauTofPion.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kNegDauTpctofPion, twoTrackResonanceSelectionNames.at(kNegDauTpctofPion), config.negDauTpctofPion.value, limits::kUpperLimit, false, false, true); + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kKstar0Bar)) { + mPosDaughterMass = o2::constants::physics::MassPiPlus; + mNegDaughterMass = o2::constants::physics::MassKMinus; + this->addSelection(kPosDauTpcPion, twoTrackResonanceSelectionNames.at(kPosDauTpcPion), config.posDauTpcPion.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kPosDauTofPion, twoTrackResonanceSelectionNames.at(kPosDauTofPion), config.posDauTofPion.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kPosDauTpctofPion, twoTrackResonanceSelectionNames.at(kPosDauTpctofPion), config.posDauTpctofPion.value, limits::kUpperLimit, false, false, true); + this->addSelection(kNegDauTpcKaon, twoTrackResonanceSelectionNames.at(kNegDauTpcKaon), config.negDauTpcKaon.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kNegDauTofKaon, twoTrackResonanceSelectionNames.at(kNegDauTofKaon), config.negDauTofKaon.value, limits::kAbsUpperLimit, false, false, true); + this->addSelection(kNegDauTpctofKaon, twoTrackResonanceSelectionNames.at(kNegDauTpctofKaon), config.negDauTpctofKaon.value, limits::kUpperLimit, false, false, true); + } + + mMassMin = filter.massMin.value; + mMassMax = filter.massMax.value; + mPtMin = filter.ptMin.value; + mPtMax = filter.ptMax.value; + mEtaMin = filter.etaMin.value; + mEtaMax = filter.etaMax.value; + mPhiMin = filter.phiMin.value; + mPhiMax = filter.phiMax.value; + + this->addSelection(kDauEtaAbsMax, twoTrackResonanceSelectionNames.at(kDauEtaAbsMax), config.dauEtaMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kDauTpcClusterMin, twoTrackResonanceSelectionNames.at(kDauTpcClusterMin), config.dauTpcClustersMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kDauDcaxyAbsMax, twoTrackResonanceSelectionNames.at(kDauDcaxyAbsMax), daughterFilter.ptMin.value, daughterFilter.ptMax.value, config.dauDcaxyMax.value, limits::kAbsUpperFunctionLimit, true, true, false); + this->addSelection(kDauDcazAbsMax, twoTrackResonanceSelectionNames.at(kDauDcazAbsMax), daughterFilter.ptMin.value, daughterFilter.ptMax.value, config.dauDcazMax.value, limits::kAbsUpperFunctionLimit, true, true, false); + this->addSelection(kPosDauMinMomForTof, twoTrackResonanceSelectionNames.at(kPosDauMinMomForTof), config.posDauMinMomForTof.value, limits::kUpperLimit, false, false, false); // momentum threshold for TOF is no minimal/optional cut + this->addSelection(kPosDauPtMin, twoTrackResonanceSelectionNames.at(kPosDauPtMin), config.posDauPtMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kPosDauPtMax, twoTrackResonanceSelectionNames.at(kPosDauPtMax), config.posDauPtMax.value, limits::kUpperLimit, true, true, false); + + this->addSelection(kNegDauMinMomForTof, twoTrackResonanceSelectionNames.at(kNegDauMinMomForTof), config.negDauMinMomForTof.value, limits::kUpperLimit, false, false, false); // momentum threshold for TOF is no minimal/optional cut + this->addSelection(kNegDauPtMin, twoTrackResonanceSelectionNames.at(kNegDauPtMin), config.negDauPtMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kNegDauPtMax, twoTrackResonanceSelectionNames.at(kNegDauPtMax), config.negDauPtMax.value, limits::kUpperLimit, true, true, false); + + this->setupContainers(registry); + }; + + template + void reconstructResonance(Tracks const& posDaughter, Tracks const& negDaughter) + { + + ROOT::Math::PtEtaPhiMVector vecPosDaughter{posDaughter.pt(), posDaughter.eta(), posDaughter.phi(), mPosDaughterMass}; + ROOT::Math::PtEtaPhiMVector vecNegDaughter{negDaughter.pt(), negDaughter.eta(), negDaughter.phi(), mNegDaughterMass}; + ROOT::Math::PtEtaPhiMVector vecResonance = vecPosDaughter + vecNegDaughter; + + // cache kinematics + mMass = vecResonance.M(); + mPt = vecResonance.Pt(); + mEta = vecResonance.Eta(); + mPhi = RecoDecay::constrainAngle(vecResonance.Phi()); + } + + bool checkFilters() const + { + return ((mMass > mMassMin && mMass < mMassMax) && + (mPt > mPtMin && mPt < mPtMax) && + (mEta > mEtaMin && mEta < mEtaMax) && + (mPhi > mPhiMin && mPhi < mPhiMax)); + } + + float getPt() const { return mPt; } + float getEta() const { return mEta; } + float getPhi() const { return mPhi; } + float getMass() const { return mMass; } + + template + void applySelections(Tracks const& posDaughter, Tracks const& negDaughter) + { + this->reset(); + // for resonances, topological selection are in general not possible, so only selections on the daughters are performed + + // common daugher selections + std::array etaDaughters = {std::fabs(posDaughter.eta()), std::fabs(negDaughter.eta())}; + this->evaluateObservable(kDauEtaAbsMax, *std::max_element(etaDaughters.begin(), etaDaughters.end())); + std::array tpcClusterDaughters = {1.f * posDaughter.tpcNClsFound(), 1.f * negDaughter.tpcNClsFound()}; + this->evaluateObservable(kDauTpcClusterMin, *std::min_element(tpcClusterDaughters.begin(), tpcClusterDaughters.end())); + + // check pt dependend dca cut on both daughters + // we apply the same cut to both daughters so we only want to store the result were both daughters survive the cut + // since momenta of daughters are different, we compute the bitmask for both, combine them with logical AND and keep the result + uint64_t bitmaskDcaPos, bitmaskDcaNeg, bitmaskDca; + this->updateLimits(kDauDcaxyAbsMax, posDaughter.pt()); + this->evaluateObservable(kDauDcaxyAbsMax, posDaughter.dcaXY()); + bitmaskDcaPos = this->getBitmask(kDauDcaxyAbsMax); + this->updateLimits(kDauDcaxyAbsMax, negDaughter.pt()); + this->evaluateObservable(kDauDcaxyAbsMax, negDaughter.dcaXY()); + bitmaskDcaNeg = this->getBitmask(kDauDcaxyAbsMax); + bitmaskDca = bitmaskDcaPos & bitmaskDcaNeg; + this->setBitmask(kDauDcaxyAbsMax, bitmaskDca); + + this->updateLimits(kDauDcazAbsMax, posDaughter.pt()); + this->evaluateObservable(kDauDcazAbsMax, posDaughter.dcaZ()); + bitmaskDcaPos = this->getBitmask(kDauDcazAbsMax); + this->updateLimits(kDauDcazAbsMax, negDaughter.pt()); + this->evaluateObservable(kDauDcazAbsMax, negDaughter.dcaZ()); + bitmaskDcaNeg = this->getBitmask(kDauDcazAbsMax); + bitmaskDca = bitmaskDcaPos & bitmaskDcaNeg; + this->setBitmask(kDauDcazAbsMax, bitmaskDca); + + float tofThreshold = 99.; + + // positive daughter selections + this->evaluateObservable(kPosDauMinMomForTof, posDaughter.p()); + this->evaluateObservable(kPosDauPtMin, posDaughter.pt()); + this->evaluateObservable(kPosDauPtMax, posDaughter.pt()); + + tofThreshold = this->getLoosestSelection(kPosDauMinMomForTof); + if (posDaughter.p() <= tofThreshold) { + this->evaluateObservable(kPosDauTpcPion, posDaughter.tpcNSigmaPi()); + this->evaluateObservable(kPosDauTofPion, posDaughter.tofNSigmaPi()); + this->evaluateObservable(kPosDauTpctofPion, std::hypot(posDaughter.tpcNSigmaPi(), posDaughter.tofNSigmaPi())); + this->evaluateObservable(kPosDauTpcKaon, posDaughter.tpcNSigmaKa()); + this->evaluateObservable(kPosDauTofKaon, posDaughter.tofNSigmaKa()); + this->evaluateObservable(kPosDauTpctofKaon, std::hypot(posDaughter.tpcNSigmaKa(), posDaughter.tofNSigmaKa())); + } else if (posDaughter.p() > tofThreshold && posDaughter.hasTOF()) { + this->evaluateObservable(kPosDauTofPion, posDaughter.tofNSigmaPi()); + this->evaluateObservable(kPosDauTpctofPion, std::hypot(posDaughter.tpcNSigmaPi(), posDaughter.tofNSigmaPi())); + this->evaluateObservable(kPosDauTofKaon, posDaughter.tofNSigmaKa()); + this->evaluateObservable(kPosDauTpctofKaon, std::hypot(posDaughter.tpcNSigmaKa(), posDaughter.tofNSigmaKa())); + if (this->passesOptionalSelection(kPosDauTofPion) || + this->passesOptionalSelection(kPosDauTpctofPion) || + this->passesOptionalSelection(kPosDauTofKaon) || + this->passesOptionalSelection(kPosDauTpctofKaon)) { + this->evaluateObservable(kPosDauTpcPion, posDaughter.tpcNSigmaPi()); + this->evaluateObservable(kPosDauTpcKaon, posDaughter.tpcNSigmaKa()); + } + } + + // negative daughter selections + this->evaluateObservable(kNegDauMinMomForTof, negDaughter.p()); + this->evaluateObservable(kNegDauPtMin, negDaughter.pt()); + this->evaluateObservable(kNegDauPtMax, negDaughter.pt()); + + tofThreshold = this->getLoosestSelection(kNegDauMinMomForTof); + if (negDaughter.p() < tofThreshold) { + this->evaluateObservable(kNegDauTpcPion, negDaughter.tpcNSigmaPi()); + this->evaluateObservable(kNegDauTofPion, negDaughter.tofNSigmaPi()); + this->evaluateObservable(kNegDauTpctofPion, std::hypot(negDaughter.tpcNSigmaPi(), negDaughter.tofNSigmaPi())); + this->evaluateObservable(kNegDauTpcKaon, negDaughter.tpcNSigmaKa()); + this->evaluateObservable(kNegDauTofKaon, negDaughter.tofNSigmaKa()); + this->evaluateObservable(kNegDauTpctofKaon, std::hypot(negDaughter.tpcNSigmaKa(), negDaughter.tofNSigmaKa())); + } else if (negDaughter.p() > tofThreshold && negDaughter.hasTOF()) { + this->evaluateObservable(kNegDauTofPion, negDaughter.tofNSigmaPi()); + this->evaluateObservable(kNegDauTpctofPion, std::hypot(negDaughter.tpcNSigmaPi(), negDaughter.tofNSigmaPi())); + this->evaluateObservable(kNegDauTofKaon, negDaughter.tofNSigmaKa()); + this->evaluateObservable(kNegDauTpctofKaon, std::hypot(negDaughter.tpcNSigmaKa(), negDaughter.tofNSigmaKa())); + if (this->passesOptionalSelection(kNegDauTofPion) || + this->passesOptionalSelection(kNegDauTpctofPion) || + this->passesOptionalSelection(kNegDauTofKaon) || + this->passesOptionalSelection(kNegDauTpctofKaon)) { + this->evaluateObservable(kNegDauTpcPion, negDaughter.tpcNSigmaPi()); + this->evaluateObservable(kNegDauTpcKaon, negDaughter.tpcNSigmaKa()); + } + } + + this->assembleBitmask(); + }; + + protected: + // (cached) kinematic variables of the resonance + float mPt = 0.f; + float mEta = 0.f; + float mPhi = 0.f; + float mMass = 0.f; + + // kinematic selections of the resonance + float mMassMin = 0.f; + float mMassMax = 6.f; + float mPtMin = 0.f; + float mPtMax = 6.f; + float mEtaMin = -0.9f; + float mEtaMax = 0.9f; + float mPhiMin = 0.f; + float mPhiMax = o2::constants::math::TwoPI; + + // daughter masses + float mPosDaughterMass = 0.f; + float mNegDaughterMass = 0.f; +}; + +struct TwoTrackResonanceBuilderProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedPhis; + o2::framework::Produces producedPhiMasks; + o2::framework::Produces producedKstars; + o2::framework::Produces producedKstarMasks; + o2::framework::Produces producedRhos; + o2::framework::Produces producedRhoMasks; +}; + +struct ConfTwoTrackResonanceTables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("TwoTrackResonanceTables"); + o2::framework::Configurable producePhis{"producePhis", -1, "Produce Phis (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable producePhiMasks{"producePhiMasks", -1, "Produce PhiMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceKstar0s{"produceKstar0s", -1, "Produce K0stars (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceKstar0Masks{"produceKstar0Masks", -1, "Produce Kstar0Masks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceRho0s{"produceRho0s", -1, "Produce Rho0s (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceRho0Masks{"produceRho0Masks", -1, "Produce Rho0Masks (-1: auto; 0 off; 1 on)"}; +}; + +template +class TwoTrackResonanceBuilder +{ + public: + TwoTrackResonanceBuilder() = default; + ~TwoTrackResonanceBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& daughterFilter, T4& table, T5 initContext) + { + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kPhi)) { + LOG(info) << "Initialize femto Phi builder..."; + mProducePhis = utils::enableTable("FPhis_001", table.producePhis.value, initContext); + mProducePhiMasks = utils::enableTable("FPhiMasks_001", table.producePhiMasks.value, initContext); + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kKstar0) || modes::isEqual(resoType, modes::TwoTrackResonance::kKstar0Bar)) { + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kKstar0)) { + LOG(info) << "Initialize femto Kstar0 builder..."; + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kKstar0Bar)) { + LOG(info) << "Initialize femto Kstar0Bar builder..."; + } + mProduceKstar0s = utils::enableTable("FKstar0s_001", table.produceKstar0s.value, initContext); + mProduceKstar0Masks = utils::enableTable("FKstar0Masks_001", table.produceKstar0Masks.value, initContext); + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kRho0)) { + LOG(info) << "Initialize femto Rho0 builder..."; + mProduceRho0s = utils::enableTable("FRho0s_001", table.produceRho0s.value, initContext); + mProduceRho0Masks = utils::enableTable("FRho0Masks_001", table.produceRho0Masks.value, initContext); + } + + if (mProducePhis || mProducePhiMasks || mProduceKstar0s || mProduceKstar0Masks || mProduceRho0s || mProduceRho0Masks) { + mFillAnyTable = true; + } else { + LOG(info) << "No tables configured, Selection object will not be configured..."; + LOG(info) << "Initialization done..."; + return; + } + mTwoTrackResonanceSelection.configure(registry, config, filter, daughterFilter); + mTwoTrackResonanceSelection.printSelections(TwoTrackResonanceSelsName); + LOG(info) << "Initialization done..."; + } + + template + void fillResonances(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, T5& resonanceProducts, T6& groupPositiveTracks, T7& groupNegativeTracks, T8& trackBuilder, T9& indexMap) + { + if (!mFillAnyTable) { + return; + } + for (auto const& [positiveTrack, negativeTrack] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupPositiveTracks, groupNegativeTracks))) { + this->fillResonance(col, collisionBuilder, collisionProducts, trackProducts, resonanceProducts, positiveTrack, negativeTrack, trackBuilder, indexMap); + } + } + + template + void fillResonance(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, T5& resonanceProducts, T6 const& posDaughter, T7 const& negDaughter, T8& trackBuilder, T9& indexMap) + { + + mTwoTrackResonanceSelection.reconstructResonance(posDaughter, negDaughter); + if (!mTwoTrackResonanceSelection.checkFilters()) { + return; + } + mTwoTrackResonanceSelection.applySelections(posDaughter, negDaughter); // for resonances selection are only applied to daughter tracks + + if (!mTwoTrackResonanceSelection.passesAllRequiredSelections()) { + return; + } + + int64_t posDaughterIndex = 0; + int64_t negDaughterIndex = 0; + + collisionBuilder.template fillCollision(collisionProducts, col); + + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionProducts, indexMap); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionProducts, indexMap); + + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kRho0)) { + if (mProduceRho0s) { + resonanceProducts.producedRhos( + collisionProducts.producedCollision.lastIndex(), + mTwoTrackResonanceSelection.getPt(), + mTwoTrackResonanceSelection.getEta(), + mTwoTrackResonanceSelection.getPhi(), + mTwoTrackResonanceSelection.getMass(), + posDaughterIndex, + negDaughterIndex); + } + if (mProduceRho0Masks) { + resonanceProducts.producedRhoMasks(mTwoTrackResonanceSelection.getBitmask()); + } + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kPhi)) { + if (mProducePhis) { + resonanceProducts.producedPhis( + collisionProducts.producedCollision.lastIndex(), + mTwoTrackResonanceSelection.getPt(), + mTwoTrackResonanceSelection.getEta(), + mTwoTrackResonanceSelection.getPhi(), + mTwoTrackResonanceSelection.getMass(), + posDaughterIndex, + negDaughterIndex); + } + if (mProducePhiMasks) { + resonanceProducts.producedPhiMasks(mTwoTrackResonanceSelection.getBitmask()); + } + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kKstar0)) { + if (mProduceKstar0s) { + resonanceProducts.producedKstars( + collisionProducts.producedCollision.lastIndex(), + mTwoTrackResonanceSelection.getPt(), + mTwoTrackResonanceSelection.getEta(), + mTwoTrackResonanceSelection.getPhi(), + mTwoTrackResonanceSelection.getMass(), + posDaughterIndex, + negDaughterIndex); + } + if (mProduceKstar0Masks) { + resonanceProducts.producedKstarMasks(mTwoTrackResonanceSelection.getBitmask()); + } + } + if constexpr (modes::isEqual(resoType, modes::TwoTrackResonance::kKstar0Bar)) { + if (mProduceKstar0s) { + resonanceProducts.producedKstars( + collisionProducts.producedCollision.lastIndex(), + -1.f * mTwoTrackResonanceSelection.getPt(), + mTwoTrackResonanceSelection.getEta(), + mTwoTrackResonanceSelection.getPhi(), + mTwoTrackResonanceSelection.getMass(), + posDaughterIndex, + negDaughterIndex); + } + if (mProduceKstar0Masks) { + resonanceProducts.producedKstarMasks(mTwoTrackResonanceSelection.getBitmask()); + } + } + } + + private: + TwoTrackResonanceSelection mTwoTrackResonanceSelection; + bool mFillAnyTable = false; + bool mProducePhis = false; + bool mProducePhiMasks = false; + bool mProduceKstar0s = false; + bool mProduceKstar0Masks = false; + bool mProduceRho0s = false; + bool mProduceRho0Masks = false; +}; // namespace twotrackresonancebuilder + +} // namespace twotrackresonancebuilder +} // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_TWOTRACKRESONANCEBUILDER_H_ diff --git a/PWGCF/Femto/Core/twoTrackResonanceHistManager.h b/PWGCF/Femto/Core/twoTrackResonanceHistManager.h new file mode 100644 index 00000000000..4852a0357a5 --- /dev/null +++ b/PWGCF/Femto/Core/twoTrackResonanceHistManager.h @@ -0,0 +1,230 @@ +// 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 twoTrackResonanceHistManager.h +/// \brief histogram manager for two track resonances +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_CORE_TWOTRACKRESONANCEHISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_TWOTRACKRESONANCEHISTMANAGER_H_ + +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/trackHistManager.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace twotrackresonancehistmanager +{ +// enum for track histograms +enum TwoTrackResonanceHist { + // analysis + kPt, + kEta, + kPhi, + kMass, + kSign, + // 2d qa + kPtVsEta, + kPtVsPhi, + kPhiVsEta, + kPtVsMass, + kTwoTrackResonanceHistLast +}; + +#define TWOTRACKRESONANCE_DEFAULT_BINNING(defaultMassMin, defaultMassMax) \ + o2::framework::ConfigurableAxis pt{"pt", {{600, 0, 6}}, "Pt"}; \ + o2::framework::ConfigurableAxis eta{"eta", {{300, -1.5, 1.5}}, "Eta"}; \ + o2::framework::ConfigurableAxis phi{"phi", {{720, 0, 1.f * o2::constants::math::TwoPI}}, "Phi"}; \ + o2::framework::ConfigurableAxis mass{"mass", {{200, defaultMassMin, defaultMassMax}}, "Mass"}; \ + o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; + +struct ConfPhiBinning : o2::framework::ConfigurableGroup { + std::string prefix = std::string("PhiBinning"); + TWOTRACKRESONANCE_DEFAULT_BINNING(0.8f, 1.2f) +}; + +struct ConfRho0Binning : o2::framework::ConfigurableGroup { + std::string prefix = std::string("Rho0Binning"); + TWOTRACKRESONANCE_DEFAULT_BINNING(0.5f, 1.f) +}; + +struct ConfKstar0Binning : o2::framework::ConfigurableGroup { + std::string prefix = std::string("Kstar0Binning"); + TWOTRACKRESONANCE_DEFAULT_BINNING(0.6f, 1.f) +}; +#undef TWOTRACKRESONANCE_DEFAULT_BINNING + +constexpr std::array, kTwoTrackResonanceHistLast> HistTable = { + {{kPt, o2::framework::kTH1F, "hPt", "Transverse Momentum; p_{T} (GeV/#it{c}); Entries"}, + {kEta, o2::framework::kTH1F, "hEta", "Pseudorapdity; #eta; Entries"}, + {kPhi, o2::framework::kTH1F, "hPhi", "Azimuthal angle; #varphi; Entries"}, + {kMass, o2::framework::kTH1F, "hMass", "Invariant mass; m (GeV/#it{c}^{2}); Entries"}, + {kSign, o2::framework::kTH1F, "hSign", "Sign (-1 -> antiparticle, 0 -> self conjugate, +1 -> particle); sign; Entries"}, + {kPtVsEta, o2::framework::kTH2F, "hPtVsEta", "p_{T} vs #eta; p_{T} (GeV/#it{c}) ; #eta"}, + {kPtVsPhi, o2::framework::kTH2F, "hPtVsPhi", "p_{T} vs #varphi;p_{T} (GeV/#it{c});#varphi"}, + {kPhiVsEta, o2::framework::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi ; #eta"}, + {kPtVsMass, o2::framework::kTH2F, "hPtVsMass", "p_{T} vs invariant mass; p_{T} (GeV/#it{c}); m (GeV/#it{c}^{2})"}}}; + +template +std::map> makeTwoTrackResonanceHistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kMass, {confBinningAnalysis.mass}}, + {kSign, {confBinningAnalysis.sign}}}; +}; + +template +auto makeTwoTrackResonanceQaHistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kMass, {confBinningAnalysis.mass}}, + {kSign, {confBinningAnalysis.sign}}, + {kPtVsEta, {confBinningAnalysis.pt, confBinningAnalysis.eta}}, + {kPtVsPhi, {confBinningAnalysis.pt, confBinningAnalysis.phi}}, + {kPhiVsEta, {confBinningAnalysis.phi, confBinningAnalysis.eta}}, + {kPtVsMass, {confBinningAnalysis.pt, confBinningAnalysis.mass}}}; +}; + +constexpr char PrefixRho[] = "Rho0/"; +constexpr char PrefixPhi[] = "Phi/"; +constexpr char PrefixKstar[] = "Kstar0/"; + +constexpr std::string_view AnalysisDir = "Kinematics/"; +constexpr std::string_view QaDir = "QA/"; + +template +class TwoTrackResonanceHistManager +{ + public: + TwoTrackResonanceHistManager() = default; + ~TwoTrackResonanceHistManager() = default; + + void init(o2::framework::HistogramRegistry* registry, + std::map> const& ResoSpecs, + std::map> const& PosDauSpecs, + std::map> const& NegDauSpecs) + { + mHistogramRegistry = registry; + mPosDauManager.init(registry, PosDauSpecs); + mNegDauManager.init(registry, NegDauSpecs); + if constexpr (modes::isFlagSet(mode, modes::Mode::kAnalysis)) { + initAnalysis(ResoSpecs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + initQa(ResoSpecs); + } + } + + template + void enableOptionalHistograms(T1 const& PosDauConfBinningQa, T2 const& NegDauConfBinningQa) + { + mPosDauManager.enableOptionalHistograms(PosDauConfBinningQa); + mNegDauManager.enableOptionalHistograms(NegDauConfBinningQa); + } + + template + void init(o2::framework::HistogramRegistry* registry, + std::map> ResoSpecs, + std::map> PosDauSpecs, + T1 const& PosDauConfBinningQa, + std::map> NegDauSpecs, + T2 const& NegDauConfBinningQa) + { + enableOptionalHistograms(PosDauConfBinningQa, NegDauConfBinningQa); + init(registry, ResoSpecs, PosDauSpecs, NegDauSpecs); + } + + template + void fill(T1 const& resonance, T2 const& tracks) + { + // this used to work, still under investigation + // auto posDaughter = resonance.template posDau_as(); + // auto negDaughter = resonance.template negDau_as(); + auto posDaughter = tracks.rawIteratorAt(resonance.posDauId() - tracks.offset()); + mPosDauManager.fill(posDaughter, tracks); + auto negDaughter = tracks.rawIteratorAt(resonance.negDauId() - tracks.offset()); + mNegDauManager.fill(negDaughter, tracks); + if constexpr (modes::isFlagSet(mode, modes::Mode::kAnalysis)) { + fillAnalysis(resonance); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + fillQa(resonance); + } + } + + private: + void initAnalysis(std::map> const& ResoSpecs) + { + std::string analysisDir = std::string(resoPrefix) + std::string(AnalysisDir); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt, HistTable), getHistDesc(kPt, HistTable), getHistType(kPt, HistTable), {ResoSpecs.at(kPt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kEta, HistTable), getHistDesc(kEta, HistTable), getHistType(kEta, HistTable), {ResoSpecs.at(kEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhi, HistTable), getHistDesc(kPhi, HistTable), getHistType(kPhi, HistTable), {ResoSpecs.at(kPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMass, HistTable), getHistDesc(kMass, HistTable), getHistType(kMass, HistTable), {ResoSpecs.at(kMass)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kSign, HistTable), getHistDesc(kSign, HistTable), getHistType(kSign, HistTable), {ResoSpecs.at(kSign)}); + } + void initQa(std::map> const& ResoSpecs) + { + std::string qaDir = std::string(resoPrefix) + std::string(QaDir); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsEta, HistTable), getHistDesc(kPtVsEta, HistTable), getHistType(kPtVsEta, HistTable), {ResoSpecs.at(kPtVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsPhi, HistTable), getHistDesc(kPtVsPhi, HistTable), getHistType(kPtVsPhi, HistTable), {ResoSpecs.at(kPtVsPhi)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPhiVsEta, HistTable), getHistDesc(kPhiVsEta, HistTable), getHistType(kPhiVsEta, HistTable), {ResoSpecs.at(kPhiVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsMass, HistTable), getHistDesc(kPtVsMass, HistTable), getHistType(kPtVsMass, HistTable), {ResoSpecs.at(kPtVsMass)}); + } + + template + void fillAnalysis(T const& resonance) + { + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPt, HistTable)), resonance.pt()); + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(AnalysisDir) + HIST(getHistName(kEta, HistTable)), resonance.eta()); + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPhi, HistTable)), resonance.phi()); + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(AnalysisDir) + HIST(getHistName(kMass, HistTable)), resonance.mass()); + if constexpr (modes::isEqual(reso, modes::TwoTrackResonance::kPhi) || modes::isEqual(reso, modes::TwoTrackResonance::kRho0)) { + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), 0); + } + if constexpr (modes::isEqual(reso, modes::TwoTrackResonance::kKstar0) || modes::isEqual(reso, modes::TwoTrackResonance::kKstar0Bar)) { + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), resonance.sign()); + } + } + + template + void fillQa(T const& resonance) + { + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(QaDir) + HIST(getHistName(kPtVsEta, HistTable)), resonance.pt(), resonance.eta()); + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(QaDir) + HIST(getHistName(kPtVsPhi, HistTable)), resonance.pt(), resonance.phi()); + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(QaDir) + HIST(getHistName(kPhiVsEta, HistTable)), resonance.phi(), resonance.eta()); + mHistogramRegistry->fill(HIST(resoPrefix) + HIST(QaDir) + HIST(getHistName(kPtVsMass, HistTable)), resonance.pt(), resonance.mass()); + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + trackhistmanager::TrackHistManager mPosDauManager; + trackhistmanager::TrackHistManager mNegDauManager; +}; +}; // namespace twotrackresonancehistmanager +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_TWOTRACKRESONANCEHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/v0Builder.h b/PWGCF/Femto/Core/v0Builder.h new file mode 100644 index 00000000000..64eb59bd960 --- /dev/null +++ b/PWGCF/Femto/Core/v0Builder.h @@ -0,0 +1,588 @@ +// 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 v0Builder.h +/// \brief v0 builder +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_CORE_V0BUILDER_H_ +#define PWGCF_FEMTO_CORE_V0BUILDER_H_ + +#include "PWGCF/Femto/Core/baseSelection.h" +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/selectionContainer.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace v0builder +{ + +// filters applied in the producer task +struct ConfV0Filters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("V0Filters"); + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 99.f, "Maximum pT"}; + o2::framework::Configurable etaMin{"etaMin", -10.f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 10.f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + o2::framework::Configurable massMinLambda{"massMinLambda", 1.f, "Minimum mass for Lambda hypothesis"}; + o2::framework::Configurable massMaxLambda{"massMaxLambda", 1.2f, "Maximum mass for Lambda hypothesis"}; + o2::framework::Configurable massMinK0short{"massMinK0short", 0.45f, "Minimum mass for K0Short hypothesis"}; + o2::framework::Configurable massMaxK0short{"massMaxK0short", 0.53f, "Maximum mass for K0Short hypothesis"}; + o2::framework::Configurable rejectMassMinLambda{"rejectMassMinLambda", 1.11f, "Minimum mass to rejection K0short hypothesis for Lambda candidates"}; + o2::framework::Configurable rejectMassMaxLambda{"rejectMassMaxLambda", 1.12f, "Maximum mass to rejection K0short hypothesis for Lambda candidates"}; + o2::framework::Configurable rejectMassMinK0short{"rejectMassMinK0short", 0.48f, "Minimum mass to rejection K0short hypothesis for Lambda candidates"}; + o2::framework::Configurable rejectMassMaxK0short{"rejectMassMaxK0short", 0.5f, "Maximum mass to rejection K0short hypothesis for Lambda candidates"}; +}; + +// selections bits for all v0s +#define V0_DEFAULT_BITS \ + o2::framework::Configurable> dcaDauMax{"dcaDauMax", {1.5f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> cpaMin{"cpaMin", {0.99f}, "Minimum cosine of pointing angle"}; \ + o2::framework::Configurable> transRadMin{"transRadMin", {0.2f}, "Minimum transverse radius (cm)"}; \ + o2::framework::Configurable> transRadMax{"transRadMax", {100.f}, "Maximum transverse radius (cm)"}; \ + o2::framework::Configurable> decayVtxMax{"decayVtxMax", {100.f}, "Maximum distance in x,y,z of the decay vertex from primary vertex (cm)"}; \ + o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Maximum |eta| for daughter tracks"}; \ + o2::framework::Configurable> dauDcaMin{"dauDcaMin", {0.05f}, "Minimum DCA of the daughters from primary vertex (cm)"}; \ + o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; + +// derived selection bits for lambda +struct ConfLambdaBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("LambdaBits"); + V0_DEFAULT_BITS + o2::framework::Configurable> posDauTpcPion{"posDauTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for positive daughter tracks"}; + o2::framework::Configurable> posDauTpcProton{"posDauTpcProton", {5.f}, "Maximum |nsimga_Proton| TPC for positive daughter tracks"}; + o2::framework::Configurable> negDauTpcPion{"negDauTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for negative daughter tracks"}; + o2::framework::Configurable> negDauTpcProton{"negDauTpcProton", {5.f}, "Maximum |nsimga_Proton| TPC negative for daughter tracks"}; +}; + +// derived selection bits for K0Short +struct ConfK0shortBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("K0shortBits"); + V0_DEFAULT_BITS + o2::framework::Configurable> posDauTpcPion{"posDauTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for positive daughter tracks"}; + o2::framework::Configurable> negDauTpcPion{"negDauTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for negative daughter tracks"}; +}; + +#undef V0_DEFAULT_BITS + +// base selection for analysis task for v0s +#define V0_DEFAULT_SELECTIONS(defaultMassMin, defaultMassMax, defaultPdgCode) \ + o2::framework::Configurable pdgCode{"pdgCode", defaultPdgCode, "V0 PDG code"}; \ + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; \ + o2::framework::Configurable ptMax{"ptMax", 999.f, "Maximum pT"}; \ + o2::framework::Configurable etaMin{"etaMin", -10.f, "Minimum eta"}; \ + o2::framework::Configurable etaMax{"etaMax", 10.f, "Maximum eta"}; \ + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum eta"}; \ + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; \ + o2::framework::Configurable massMin{"massMin", defaultMassMin, "Minimum invariant mass for Lambda"}; \ + o2::framework::Configurable massMax{"massMax", defaultMassMax, "Maximum invariant mass for Lambda"}; \ + o2::framework::Configurable mask{"mask", 0, "Bitmask for v0 selection"}; + +// base selection for analysis task for lambdas +template +struct ConfLambdaSelection : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + V0_DEFAULT_SELECTIONS(1.0, 1.2, 3122) + o2::framework::Configurable sign{"sign", 1, "Sign of the Lambda (+1: Lambda; -1: Antilambda; 0: both)"}; +}; + +// base selection for analysis task for k0short +template +struct ConfK0shortSelection : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + V0_DEFAULT_SELECTIONS(0.47, 0.51, 310) +}; + +#undef V0_DEFAULT_SELECTIONS + +constexpr const char PrefixLambdaSelection1[] = "LambdaSelection1"; +constexpr const char PrefixLambdaSelection2[] = "LambdaSelection2"; +using ConfLambdaSelection1 = ConfLambdaSelection; +using ConfLambdaSelection2 = ConfLambdaSelection; +constexpr const char PrefixK0shortSelection1[] = "K0shortSelection1"; +constexpr const char PrefixK0shortSelection2[] = "K0shortSelection2"; +using ConfK0shortSelection1 = ConfK0shortSelection; +using ConfK0shortSelection2 = ConfK0shortSelection; + +/// The different selections for v0s +enum V0Sels { + // selections for lambdas + kCpaMin, ///< Min. CPA (cosine pointing angle) + kDcaDaughMax, ///< Max. DCA of the daughters at decay vertex + kDecayVtxMax, ///< Max. distance of decay vertex in x,y,z + kTransRadMin, ///< Min. transverse radius + kTransRadMax, ///< max. transverse radius + + // selection for daughter + kDauAbsEtaMax, ///< Max. absolute pseudo rapidity + kDauDcaMin, ///< Min. DCA of the positive daughters at primary vertex + kDauTpcClsMin, ///< Min. number of TPC clusters of positive daughter + + // pid selection for daughters + kPosDaughTpcPion, ///< TPC Pion PID for positive daughter + kPosDaughTpcProton, ///< TPC Proton PID for positive daughter + kNegDaughTpcPion, ///< TPC Pion PID for negative daughter + kNegDaughTpcProton, ///< TPC Proton PID for negative daughter + + kV0SelsMax +}; + +constexpr char LambdaSelHistName[] = "hLambdaSelection"; +constexpr char AntilambdaSelHistName[] = "hAntiLambdaSelection"; +constexpr char K0shortSelHistName[] = "hK0shortSelection"; +constexpr char V0SelsName[] = "V0 selection object"; +const std::unordered_map v0SelectionNames = { + {kCpaMin, "Min. CPA (cosine pointing angle)"}, + {kDcaDaughMax, "Max. DCA of the daughters at decay vertex"}, + {kDecayVtxMax, "Max. distance of decay vertex in x,y,z"}, + {kTransRadMin, "Min. transverse radius"}, + {kTransRadMax, "Max. transverse radius"}, + + {kDauAbsEtaMax, "Max. absolute pseudo rapidity"}, + {kDauDcaMin, "Min. DCA of the positive daughters at primary vertex"}, + {kDauTpcClsMin, "Min. number of TPC clusters of positive daughter"}, + + {kPosDaughTpcPion, "TPC Pion PID for positive daughter"}, + {kPosDaughTpcProton, "TPC Proton PID for positive daughter"}, + {kNegDaughTpcPion, "TPC Pion PID for negative daughter"}, + {kNegDaughTpcProton, "TPC Proton PID for negative daughter"}}; + +/// \class FemtoDreamTrackCuts +/// \brief Cut class to contain and execute all cuts applied to tracks +template +class V0Selection : public BaseSelection +{ + public: + V0Selection() = default; + ~V0Selection() = default; + + template + void configure(o2::framework::HistogramRegistry* registry, T1& config, T2& filter) + { + mPtMin = filter.ptMin.value; + mPtMax = filter.ptMax.value; + mEtaMin = filter.etaMin.value; + mEtaMax = filter.etaMax.value; + mPhiMin = filter.phiMin.value; + mPhiMax = filter.phiMax.value; + + if constexpr (modes::isEqual(v0Type, modes::V0::kLambda) || modes::isEqual(v0Type, modes::V0::kAntiLambda)) { + mMassLambdaLowerLimit = filter.massMinLambda.value; + mMassLambdaUpperLimit = filter.massMaxLambda.value; + mMassK0shortLowerLimit = filter.rejectMassMinK0short.value; + mMassK0shortUpperLimit = filter.rejectMassMaxK0short.value; + + if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { + this->addSelection(kPosDaughTpcProton, v0SelectionNames.at(kPosDaughTpcProton), config.posDauTpcProton.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kNegDaughTpcPion, v0SelectionNames.at(kNegDaughTpcPion), config.negDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); + } + + if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) { + this->addSelection(kPosDaughTpcPion, v0SelectionNames.at(kPosDaughTpcPion), config.posDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kNegDaughTpcProton, v0SelectionNames.at(kNegDaughTpcProton), config.negDauTpcProton.value, limits::kAbsUpperLimit, true, true, false); + } + } + if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { + mMassK0shortLowerLimit = filter.massMinK0short.value; + mMassK0shortUpperLimit = filter.massMaxK0short.value; + mMassLambdaLowerLimit = filter.rejectMassMinLambda.value; + mMassLambdaUpperLimit = filter.rejectMassMaxLambda.value; + this->addSelection(kPosDaughTpcPion, v0SelectionNames.at(kPosDaughTpcPion), config.posDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kNegDaughTpcPion, v0SelectionNames.at(kNegDaughTpcPion), config.negDauTpcPion.value, limits::kAbsUpperLimit, true, true, false); + } + + this->addSelection(kDcaDaughMax, v0SelectionNames.at(kDcaDaughMax), config.dcaDauMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kCpaMin, v0SelectionNames.at(kCpaMin), config.cpaMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kTransRadMin, v0SelectionNames.at(kTransRadMin), config.transRadMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kTransRadMax, v0SelectionNames.at(kTransRadMax), config.transRadMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kDauAbsEtaMax, v0SelectionNames.at(kDauAbsEtaMax), config.dauAbsEtaMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kDauDcaMin, v0SelectionNames.at(kDauDcaMin), config.dauDcaMin.value, limits::kAbsLowerFunctionLimit, true, true, false); + this->addSelection(kDauTpcClsMin, v0SelectionNames.at(kDauTpcClsMin), config.dauTpcClustersMin.value, limits::kLowerLimit, true, true, false); + + this->setupContainers(registry); + } + + template + void applySelections(T1 const& v0candidate, T2 const& /*tracks*/) + { + this->reset(); + // v0 selections + this->evaluateObservable(kCpaMin, v0candidate.v0cosPA()); + this->evaluateObservable(kDcaDaughMax, v0candidate.dcaV0daughters()); + // for decay vertex, the x,y and z coordinate have to be below a certain threshold + // compare the largest of the 3 to the limit set by the bit + std::array decayCoordinates = {std::fabs(v0candidate.x()), std::fabs(v0candidate.y()), std::fabs(v0candidate.z())}; + this->evaluateObservable(kDecayVtxMax, *std::max_element(decayCoordinates.begin(), decayCoordinates.end())); + this->evaluateObservable(kTransRadMin, v0candidate.v0radius()); + this->evaluateObservable(kTransRadMax, v0candidate.v0radius()); + + // daughter selection + // for daughter selections, both have to fit the same track quality selection, so we store only one bit for both + // take largest/smallest from both daughters and evaluate the observable with this value + auto posDaughter = v0candidate.template posTrack_as(); + auto negDaughter = v0candidate.template negTrack_as(); + + std::array etaDaughters = {std::fabs(posDaughter.eta()), std::fabs(negDaughter.eta())}; + this->evaluateObservable(kDauAbsEtaMax, *std::max_element(etaDaughters.begin(), etaDaughters.end())); + + std::array dcaDaughters = {std::hypot(posDaughter.dcaXY(), posDaughter.dcaZ()), std::hypot(negDaughter.dcaXY(), negDaughter.dcaZ())}; + this->evaluateObservable(kDauDcaMin, *std::min_element(dcaDaughters.begin(), dcaDaughters.end())); + + std::array clustersDaughters = {1.f * posDaughter.tpcNClsFound(), 1.f * negDaughter.tpcNClsFound()}; + this->evaluateObservable(kDauTpcClsMin, *std::min_element(clustersDaughters.begin(), clustersDaughters.end())); + + // daughter pid selections + this->evaluateObservable(kPosDaughTpcPion, posDaughter.tpcNSigmaPi()); + this->evaluateObservable(kPosDaughTpcProton, posDaughter.tpcNSigmaPr()); + this->evaluateObservable(kNegDaughTpcPion, negDaughter.tpcNSigmaPi()); + this->evaluateObservable(kNegDaughTpcProton, negDaughter.tpcNSigmaPr()); + + this->assembleBitmask(); + } + + template + bool checkFilters(const T& v0) const + { + // check kinematics first + const bool kinematicsOK = + (v0.pt() > mPtMin && v0.pt() < mPtMax) && + (v0.eta() > mEtaMin && v0.eta() < mEtaMax) && + (v0.phi() > mPhiMin && v0.phi() < mPhiMax); + if (!kinematicsOK) { + return false; + } + // now check mass hypothesis + if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { + return (v0.mLambda() > mMassLambdaLowerLimit && v0.mLambda() < mMassLambdaUpperLimit) && // inside Λ + (v0.mK0Short() < mMassK0shortLowerLimit || v0.mK0Short() > mMassK0shortUpperLimit); // outside K0s + } + + if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) { + return (v0.mAntiLambda() > mMassLambdaLowerLimit && v0.mAntiLambda() < mMassLambdaUpperLimit) && // inside Λbar + (v0.mK0Short() < mMassK0shortLowerLimit || v0.mK0Short() > mMassK0shortUpperLimit); // outside K0s + } + + if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { + return (v0.mK0Short() > mMassK0shortLowerLimit && v0.mK0Short() < mMassK0shortUpperLimit) && // inside K0s + (v0.mLambda() < mMassLambdaLowerLimit || v0.mLambda() > mMassLambdaUpperLimit) && // outside Λ + (v0.mAntiLambda() < mMassLambdaLowerLimit || v0.mAntiLambda() > mMassLambdaUpperLimit); // outside Λbar + } + return false; + } + + protected: + float mMassK0shortLowerLimit = 0.483f; + float mMassK0shortUpperLimit = 0.503f; + + float mMassLambdaLowerLimit = 1.105f; + float mMassLambdaUpperLimit = 1.125f; + + // kinematic filters + float mPtMin = 0.f; + float mPtMax = 6.f; + float mEtaMin = -1.f; + float mEtaMax = 1.f; + float mPhiMin = 0.f; + float mPhiMax = o2::constants::math::TwoPI; +}; + +struct V0BuilderProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedLambdas; + o2::framework::Produces producedLambdaMasks; + o2::framework::Produces producedLambdaExtras; + o2::framework::Produces producedK0shorts; + o2::framework::Produces producedK0shortMasks; + o2::framework::Produces producedK0shortExtras; +}; + +struct ConfV0Tables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("V0Tables"); + o2::framework::Configurable produceLambdas{"produceLambdas", -1, "Produce Lambdas (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLambdaMasks{"produceLambdaMasks", -1, "Produce LambdaMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLambdaExtras{"produceLambdaExtras", -1, "Produce LambdaExtras (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceK0shorts{"produceK0shorts", -1, "Produce K0shorts (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceK0shortMasks{"produceK0shortMasks", -1, "Produce K0shortMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceK0shortExtras{"produceK0shortExtras", -1, "Produce K0shortExtras (-1: auto; 0 off; 1 on)"}; +}; + +template +class V0Builder +{ + public: + V0Builder() = default; + ~V0Builder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + { + if constexpr (modes::isEqual(v0Type, modes::V0::kLambda) || modes::isEqual(v0Type, modes::V0::kAntiLambda)) { + if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { + LOG(info) << "Initialize femto Lambda builder..."; + } + if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) { + LOG(info) << "Initialize femto AntiLambda builder..."; + } + mProduceLambdas = utils::enableTable("FLambdas_001", table.produceLambdas.value, initContext); + mProduceLambdaMasks = utils::enableTable("FLambdaMasks_001", table.produceLambdaMasks.value, initContext); + mProduceLambdaExtras = utils::enableTable("FLambdaExtras_001", table.produceLambdaExtras.value, initContext); + } + if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { + LOG(info) << "Initialize femto K0short builder..."; + mProduceK0shorts = utils::enableTable("FK0shorts_001", table.produceK0shorts.value, initContext); + mProduceK0shortMasks = utils::enableTable("FK0shortMasks_001", table.produceK0shortMasks.value, initContext); + mProduceK0shortExtras = utils::enableTable("FK0shortExtras_001", table.produceK0shortExtras.value, initContext); + } + if (mProduceLambdas || mProduceLambdaMasks || mProduceLambdaExtras || mProduceK0shorts || mProduceK0shortMasks || mProduceK0shortExtras) { + mFillAnyTable = true; + } else { + LOG(info) << "No tables configured, Selection object will not be configured..."; + LOG(info) << "Initialization done..."; + return; + } + mV0Selection.configure(registry, config, filter); + mV0Selection.printSelections(V0SelsName); + LOG(info) << "Initialization done..."; + } + + template + void fillV0s(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, T5& v0products, T6 const& v0s, T7 const& tracks, T8& trackBuilder, T9& indexMap) + { + if (!mFillAnyTable) { + return; + } + int64_t posDaughterIndex = 0; + int64_t negDaughterIndex = 0; + for (const auto& v0 : v0s) { + if (!mV0Selection.checkFilters(v0)) { + continue; + } + mV0Selection.applySelections(v0, tracks); + if (!mV0Selection.passesAllRequiredSelections()) { + continue; + } + auto posDaughter = v0.template posTrack_as(); + auto negDaughter = v0.template negTrack_as(); + + collisionBuilder.template fillCollision(collisionProducts, col); + + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionProducts, indexMap); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionProducts, indexMap); + + if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { + fillLambda(collisionProducts, v0products, v0, 1.f, posDaughterIndex, negDaughterIndex); + } + if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) { + fillLambda(collisionProducts, v0products, v0, -1.f, posDaughterIndex, negDaughterIndex); + } + if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) { + fillK0short(collisionProducts, v0products, v0, posDaughterIndex, negDaughterIndex); + } + } + } + + template + void fillLambda(T1& collisionProducts, T2& v0products, T3 const& v0, float sign, int64_t posDaughterIndex, int64_t negDaughterIndex) + { + float mass, massAnti; + if (sign > 0.f) { + mass = v0.mLambda(); + massAnti = v0.mAntiLambda(); + } else { + mass = v0.mAntiLambda(); + massAnti = v0.mLambda(); + } + if (mProduceLambdas) { + v0products.producedLambdas(collisionProducts.producedCollision.lastIndex(), + sign * v0.pt(), + v0.eta(), + v0.phi(), + mass, + posDaughterIndex, + negDaughterIndex); + } + if (mProduceLambdaMasks) { + v0products.producedLambdaMasks(mV0Selection.getBitmask()); + } + if (mProduceLambdaExtras) { + v0products.producedLambdaExtras( + massAnti, + v0.mK0Short(), + v0.v0cosPA(), + v0.dcaV0daughters(), + v0.v0radius(), + v0.x(), + v0.y(), + v0.z()); + } + } + + template + void fillK0short(T1& collisionProducts, T2& v0products, T3 const& v0, int64_t posDaughterIndex, int64_t negDaughterIndex) + { + if (mProduceK0shorts) { + v0products.producedK0shorts(collisionProducts.producedCollision.lastIndex(), + v0.pt(), + v0.eta(), + v0.phi(), + v0.mK0Short(), + posDaughterIndex, + negDaughterIndex); + } + if (mProduceK0shortMasks) { + v0products.producedK0shortMasks(mV0Selection.getBitmask()); + } + if (mProduceK0shortExtras) { + v0products.producedK0shortExtras( + v0.mLambda(), + v0.mAntiLambda(), + v0.v0cosPA(), + v0.dcaV0daughters(), + v0.v0radius(), + v0.x(), + v0.y(), + v0.z()); + } + } + + bool fillAnyTable() { return mFillAnyTable; } + + private: + V0Selection mV0Selection; + bool mFillAnyTable = false; + bool mProduceLambdas = false; + bool mProduceLambdaMasks = false; + bool mProduceLambdaExtras = false; + bool mProduceK0shorts = false; + bool mProduceK0shortMasks = false; + bool mProduceK0shortExtras = false; +}; + +struct ConfV0TablesDerivedToDerived : o2::framework::ConfigurableGroup { + std::string prefix = std::string("V0Tables"); + o2::framework::Configurable limitLambda{"limitLambda", 1, "At least this many lambdas need to be in the collision"}; + o2::framework::Configurable limitK0short{"limitK0short", 0, "At least this many k0short need to be in the collision"}; +}; + +struct V0BuilderDerivedToDerivedProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedLambdas; + o2::framework::Produces producedLambdaMasks; + o2::framework::Produces producedK0shorts; + o2::framework::Produces producedK0shortMasks; +}; + +class V0BuilderDerivedToDerived +{ + public: + V0BuilderDerivedToDerived() = default; + ~V0BuilderDerivedToDerived() = default; + + template + void init(T& config) + { + mLimitLambda = config.limitLambda.value; + mLimitK0short = config.limitK0short.value; + } + + template + bool collisionHasTooFewLambdas(T1& col, T2& /*lambdaTable*/, T3& partitionLambda, T4& cache) + { + auto lambdaSlice = partitionLambda->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (lambdaSlice.size() >= mLimitLambda) { + return false; + } + return true; + } + + template + bool collisionHasTooFewK0shorts(T1& col, T2& /*k0shortTable*/, T3& partitionK0short, T4& cache) + { + auto k0shortSlice = partitionK0short->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (k0shortSlice.size() >= mLimitK0short) { + return false; + } + return true; + } + + template + void processLambdas(T1& col, T2& /*lambdaTable*/, T3& /*oldTrackTable*/, T4& partitionLambda, T5& trackBuilder, T6& indexMap, T7& cache, T8& newLambdaTable, T9& newTrackTable, T10& newCollisionTable) + { + auto lambdaSlice = partitionLambda->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + + for (auto const& lambda : lambdaSlice) { + + auto posDaughter = lambda.template posDau_as(); + auto negDaughter = lambda.template negDau_as(); + + int posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable, indexMap); + int negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable, indexMap); + + newLambdaTable.producedLambdas(newCollisionTable.producedCollision.lastIndex(), + lambda.signedPt(), + lambda.eta(), + lambda.phi(), + lambda.mass(), + posDaughterIndex, + negDaughterIndex); + newLambdaTable.producedLambdaMasks(lambda.mask()); + } + } + + template + void processK0shorts(T1& col, T2& /*k0shortTable*/, T3& /*oldTrackTable*/, T4& partitionK0short, T5& trackBuilder, T6& indexMap, T7& cache, T8& newK0shortTable, T9& newTrackTable, T10& newCollisionTable) + { + auto k0shortSlice = partitionK0short->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + + for (auto const& k0short : k0shortSlice) { + + auto posDaughter = k0short.template posDau_as(); + auto negDaughter = k0short.template negDau_as(); + + int posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable, indexMap); + int negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable, indexMap); + + newK0shortTable.producedK0shorts(newCollisionTable.producedCollision.lastIndex(), + k0short.pt(), + k0short.eta(), + k0short.phi(), + k0short.mass(), + posDaughterIndex, + negDaughterIndex); + newK0shortTable.producedK0shortMasks(k0short.mask()); + } + } + + private: + int mLimitLambda = 0; + int mLimitK0short = 0; +}; + +} // namespace v0builder +} // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_V0BUILDER_H_ diff --git a/PWGCF/Femto/Core/v0HistManager.h b/PWGCF/Femto/Core/v0HistManager.h new file mode 100644 index 00000000000..769210aa9b2 --- /dev/null +++ b/PWGCF/Femto/Core/v0HistManager.h @@ -0,0 +1,383 @@ +// 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 v0HistManager.h +/// \brief histogram manager for vzero histograms +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_CORE_V0HISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_V0HISTMANAGER_H_ + +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/trackHistManager.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto +{ +namespace v0histmanager +{ +// enum for track histograms +enum V0Hist { + // analysis + kPt, + kEta, + kPhi, + kMass, + kSign, + // qa variables + kMassLambda, + kMassAntiLambda, + kMassK0short, + kCosPa, + kDecayDauDca, + kDecayVtxX, + kDecayVtxY, + kDecayVtxZ, + kDecayVtx, + kTransRadius, + // 2d qa + kPtVsEta, + kPtVsPhi, + kPhiVsEta, + kPtVsCosPa, + kPtVsLambdaMass, + kPtVsAntiLambdaMass, + kPtVsK0shortMass, + kLambdaMassVsAntiLambdaMass, + kK0shortMassVsLambdaMass, + kK0shortMassVsAntiLambdaMass, + kV0HistLast +}; + +#define V0_DEFAULT_BINNING(defaultMassMin, defaultMassMax) \ + o2::framework::ConfigurableAxis pt{"pt", {{600, 0, 6}}, "Pt"}; \ + o2::framework::ConfigurableAxis eta{"eta", {{300, -1.5, 1.5}}, "Eta"}; \ + o2::framework::ConfigurableAxis phi{"phi", {{720, 0, 1.f * o2::constants::math::TwoPI}}, "Phi"}; \ + o2::framework::ConfigurableAxis mass{"mass", {{200, defaultMassMin, defaultMassMax}}, "Mass"}; \ + o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; + +template +struct ConfLambdaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + V0_DEFAULT_BINNING(1.0, 1.2) +}; +template +struct ConfK0shortBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + V0_DEFAULT_BINNING(0.475, 0.515) +}; +#undef V0_DEFAULT_BINNING + +constexpr const char PrefixLambdaBinning1[] = "LambdaBinning1"; +using ConfLambdaBinning1 = ConfLambdaBinning; +constexpr const char PrefixK0shortBinning1[] = "K0shortBinning1"; +using ConfK0shortBinning1 = ConfK0shortBinning; + +template +struct ConfV0QaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable plot2d{"plot2d", true, "Generate various 2D QA plots"}; + o2::framework::ConfigurableAxis cosPa{"cosPa", {{100, 0.9, 1}}, "Cosine of poiting angle"}; + o2::framework::ConfigurableAxis dauDcaAtDecay{"dauDcaAtDecay", {{150, 0, 1.5}}, "Daughter DCA at decay vertex"}; + o2::framework::ConfigurableAxis decayVertex{"decayVertex", {{100, 0, 100}}, "Decay vertex"}; + o2::framework::ConfigurableAxis transRadius{"transRadius", {{100, 0, 100}}, "Transverse radius"}; + o2::framework::ConfigurableAxis massLambda{"massLambda", {{200, 1, 1.2}}, "mass for antiparticle hypothesis"}; + o2::framework::ConfigurableAxis massAntiLambda{"massAntiLambda", {{100, 1, 1.2}}, "mass for antiparticle hypothesis"}; + o2::framework::ConfigurableAxis massK0short{"massK0short", {{200, 0.45, 0.55}}, "Mass for k0short hypothesis"}; +}; + +constexpr const char PrefixLambdaQaBinning1[] = "LambdaQaBinning1"; +using ConfLambdaQaBinning1 = ConfV0QaBinning; + +constexpr const char PrefixK0shortQaBinning1[] = "K0shortQaBinning1"; +using ConfK0shortQaBinning1 = ConfV0QaBinning; + +// must be in sync with enum TrackVariables +// the enum gives the correct index in the array +constexpr std::array, kV0HistLast> HistTable = { + {{kPt, o2::framework::kTH1F, "hPt", "Transverse Momentum; p_{T} (GeV/#it{c}); Entries"}, + {kEta, o2::framework::kTH1F, "hEta", "Pseudorapdity; #eta; Entries"}, + {kPhi, o2::framework::kTH1F, "hPhi", "Azimuthal angle; #varphi; Entries"}, + {kMass, o2::framework::kTH1F, "hMass", "Invariant Mass; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kSign, o2::framework::kTH1F, "hSign", "Sign (-1 -> antiparticle, 0 -> self conjugate, +1 -> particle); sign; Entries"}, + {kMassLambda, o2::framework::kTH1F, "hMassLambda", "#Lambda mass; m_{p#pi^{-}} (GeV/#it{c}^{2}); Entries"}, + {kMassAntiLambda, o2::framework::kTH1F, "hMassAntiLambda", "#bar{#Lambda} mass; m_{#bar{p}#pi^{+}} (GeV/#it{c}^{2}); Entries"}, + {kMassK0short, o2::framework::kTH1F, "hMassK0short", "K^{0}_{s} mass; m_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2}); Entries"}, + {kCosPa, o2::framework::kTH1F, "hCosPa", "Cosine of pointing angle; coa(#alpha); Entries"}, + {kDecayDauDca, o2::framework::kTH1F, "hDauDca", "Daughter DCA at decay vertex ; DCA_{Decay vertex} (cm); Entries"}, + {kDecayVtxX, o2::framework::kTH1F, "hDecayVtxX", "X coordinate of decay vertex ; DV_{X} (cm); Entries"}, + {kDecayVtxY, o2::framework::kTH1F, "hDecayVtxY", "Y coordinate of decay vertex ; DV_{Y} (cm); Entries"}, + {kDecayVtxZ, o2::framework::kTH1F, "hDecayVtxZ", "Z coordinate of decay vertex ; DV_{Z} (cm); Entries"}, + {kDecayVtx, o2::framework::kTH1F, "hDecayVtx", "Distance of decay vertex from primary vertex ; DV (cm); Entries"}, + {kTransRadius, o2::framework::kTH1F, "hTransRadius", "Transverse radius ; r_{xy} (cm); Entries"}, + {kPtVsEta, o2::framework::kTH2F, "hPtVsEta", "p_{T} vs #eta; p_{T} (GeV/#it{c}) ; #eta"}, + {kPtVsPhi, o2::framework::kTH2F, "hPtVsPhi", "p_{T} vs #varphi; p_{T} (GeV/#it{c}) ; #varphi"}, + {kPhiVsEta, o2::framework::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi ; #eta"}, + {kPtVsCosPa, o2::framework::kTH2F, "hPtVsCosPa", "Cosine of poiting angle vs p_{T}; cos(#alpha); p_{T} (GeV/#it{c})"}, + {kPtVsLambdaMass, o2::framework::kTH2F, "hPtVsLambdaMass", "p_{T} vs #Lambda mass; p_{T} (GeV/#it{c}); m_{p#pi^{-}} (GeV/#it{c}^{2})"}, + {kPtVsAntiLambdaMass, o2::framework::kTH2F, "hPtVsAntiLambdaMass", "p_{T} vs #bar{#Lambda} mass; p_{T} (GeV/#it{c}); m_{#bar{p}#pi^{+}} (GeV/#it{c}^{2})"}, + {kPtVsK0shortMass, o2::framework::kTH2F, "hPtVsK0shortMass", "p_{T} vs K^{0}_{S} mass; p_{T} (GeV/#it{c}); m_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2})"}, + {kK0shortMassVsLambdaMass, o2::framework::kTH2F, "hK0shortMassVsLambdaMass", " K^{0}_{S} mass vs #Lambda mass; m_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2}); m_{p#pi^{-}} (GeV/#it{c}^{2})"}, + {kK0shortMassVsAntiLambdaMass, o2::framework::kTH2F, "hK0shortMassVsAntiLambdaMass", "K^{0}_{S} mass vs #bar{#Lambda} mass; m_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2}); m_{#bar{p}#pi^{+}} (GeV/#it{c}^{2})"}, + {kLambdaMassVsAntiLambdaMass, o2::framework::kTH2F, "hLambdaMassVsAntiLambdaMass", "#Lambda mass vs #bar{#Lambda}; m_{p#pi^{-}} (GeV/#it{c}^{2}); m_{#bar{p}#pi^{+}} (GeV/#it{c}^{2})"}}}; + +template +auto makeV0HistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kMass, {confBinningAnalysis.mass}}, + {kSign, {confBinningAnalysis.sign}}}; +} + +template +std::map> makeV0QaHistSpecMap(T1 const& confBinningAnalysis, T2 const& confBinningQa) +{ + return std::map>{ + {kPt, {confBinningAnalysis.pt}}, + {kEta, {confBinningAnalysis.eta}}, + {kPhi, {confBinningAnalysis.phi}}, + {kMass, {confBinningAnalysis.mass}}, + {kSign, {confBinningAnalysis.sign}}, + {kCosPa, {confBinningQa.cosPa}}, + {kDecayDauDca, {confBinningQa.dauDcaAtDecay}}, + {kDecayVtxX, {confBinningQa.decayVertex}}, + {kDecayVtxY, {confBinningQa.decayVertex}}, + {kDecayVtxZ, {confBinningQa.decayVertex}}, + {kDecayVtx, {confBinningQa.decayVertex}}, + {kTransRadius, {confBinningQa.transRadius}}, + {kPtVsEta, {confBinningAnalysis.pt, confBinningAnalysis.eta}}, + {kPtVsPhi, {confBinningAnalysis.pt, confBinningAnalysis.phi}}, + {kPhiVsEta, {confBinningAnalysis.phi, confBinningAnalysis.eta}}, + {kPtVsCosPa, {confBinningAnalysis.pt, confBinningQa.cosPa}}, + {kMassLambda, {confBinningQa.massLambda}}, + {kMassAntiLambda, {confBinningQa.massAntiLambda}}, + {kMassK0short, {confBinningQa.massK0short}}, + {kPtVsLambdaMass, {confBinningAnalysis.pt, confBinningQa.massLambda}}, + {kPtVsAntiLambdaMass, {confBinningAnalysis.pt, confBinningQa.massAntiLambda}}, + {kPtVsK0shortMass, {confBinningAnalysis.pt, confBinningQa.massK0short}}, + {kLambdaMassVsAntiLambdaMass, {confBinningQa.massLambda, confBinningQa.massAntiLambda}}, + {kK0shortMassVsLambdaMass, {confBinningQa.massK0short, confBinningQa.massLambda}}, + {kK0shortMassVsAntiLambdaMass, {confBinningQa.massK0short, confBinningQa.massAntiLambda}}}; +}; + +constexpr char PrefixLambdaQa[] = "LambdaQA/"; +constexpr char PrefixLambda1[] = "Lambda1/"; +constexpr char PrefixLambda2[] = "Lambda2/"; +constexpr char PrefixK0shortQa[] = "K0shortQa/"; +constexpr char PrefixK0short1[] = "K0short1/"; +constexpr char PrefixK0short2[] = "K0short2/"; + +constexpr char PrefixLambdaCascade[] = "LambdaCascadeQa/"; + +constexpr std::string_view AnalysisDir = "Kinematics/"; +constexpr std::string_view QaDir = "QA/"; + +/// \class FemtoDreamEventHisto +/// \brief Class for histogramming event properties +// template +template +class V0HistManager +{ + public: + V0HistManager() = default; + ~V0HistManager() = default; + + void init(o2::framework::HistogramRegistry* registry, + std::map> const& V0Specs, + std::map> const& PosDauSpecs, + std::map> const& NegDauSpecs) + { + mHistogramRegistry = registry; + mPosDauManager.init(registry, PosDauSpecs); + mNegDauManager.init(registry, NegDauSpecs); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kAnalysis)) { + initAnalysis(V0Specs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + initQa(V0Specs); + } + } + + template + void enableOptionalHistograms(T1 const& V0ConfBinningQa, T2 const& PosDauConfBinningQa, T3 const& NegDauConfBinningQa) + { + mPosDauManager.enableOptionalHistograms(PosDauConfBinningQa); + mNegDauManager.enableOptionalHistograms(NegDauConfBinningQa); + mPlot2d = V0ConfBinningQa.plot2d.value; + } + + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& V0Specs, + T1 const& V0ConfBinningQa, + std::map> const& PosDauSpecs, + T2 const& PosDauConfBinningQa, + std::map> const& NegDauSpecs, + T3 const& NegDauConfBinningQa) + { + enableOptionalHistograms(V0ConfBinningQa, PosDauConfBinningQa, NegDauConfBinningQa); + init(registry, V0Specs, PosDauSpecs, NegDauSpecs); + } + + template + void fill(T1 const& v0candidate, T2 const& tracks) + { + // this used to work, still under investigation + // auto posDaughter = v0candidate.template posDau_as(); + // auto negDaughter = v0candidate.template negDau_as(); + auto posDaughter = tracks.rawIteratorAt(v0candidate.posDauId() - tracks.offset()); + mPosDauManager.fill(posDaughter, tracks); + auto negDaughter = tracks.rawIteratorAt(v0candidate.negDauId() - tracks.offset()); + mNegDauManager.fill(negDaughter, tracks); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kAnalysis)) { + fillAnalysis(v0candidate); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + fillQa(v0candidate); + } + } + + private: + void initAnalysis(std::map> const& V0Specs) + { + std::string analysisDir = std::string(v0Prefix) + std::string(AnalysisDir); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt, HistTable), getHistDesc(kPt, HistTable), getHistType(kPt, HistTable), {V0Specs.at(kPt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kEta, HistTable), getHistDesc(kEta, HistTable), getHistType(kEta, HistTable), {V0Specs.at(kEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhi, HistTable), getHistDesc(kPhi, HistTable), getHistType(kPhi, HistTable), {V0Specs.at(kPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMass, HistTable), getHistDesc(kMass, HistTable), getHistType(kMass, HistTable), {V0Specs.at(kMass)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kSign, HistTable), getHistDesc(kSign, HistTable), getHistType(kSign, HistTable), {V0Specs.at(kSign)}); + } + + void initQa(std::map> const& V0Specs) + { + std::string qaDir = std::string(v0Prefix) + std::string(QaDir); + + mHistogramRegistry->add(qaDir + getHistNameV2(kCosPa, HistTable), getHistDesc(kCosPa, HistTable), getHistType(kCosPa, HistTable), {V0Specs.at(kCosPa)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayDauDca, HistTable), getHistDesc(kDecayDauDca, HistTable), getHistType(kDecayDauDca, HistTable), {V0Specs.at(kDecayDauDca)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxX, HistTable), getHistDesc(kDecayVtxX, HistTable), getHistType(kDecayVtxX, HistTable), {V0Specs.at(kDecayVtxX)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxY, HistTable), getHistDesc(kDecayVtxY, HistTable), getHistType(kDecayVtxY, HistTable), {V0Specs.at(kDecayVtxY)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtxZ, HistTable), getHistDesc(kDecayVtxZ, HistTable), getHistType(kDecayVtxZ, HistTable), {V0Specs.at(kDecayVtxZ)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayVtx, HistTable), getHistDesc(kDecayVtx, HistTable), getHistType(kDecayVtx, HistTable), {V0Specs.at(kDecayVtx)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kTransRadius, HistTable), getHistDesc(kTransRadius, HistTable), getHistType(kTransRadius, HistTable), {V0Specs.at(kTransRadius)}); + + if (mPlot2d) { + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsEta, HistTable), getHistDesc(kPtVsEta, HistTable), getHistType(kPtVsEta, HistTable), {V0Specs.at(kPtVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsPhi, HistTable), getHistDesc(kPtVsPhi, HistTable), getHistType(kPtVsPhi, HistTable), {V0Specs.at(kPtVsPhi)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPhiVsEta, HistTable), getHistDesc(kPhiVsEta, HistTable), getHistType(kPhiVsEta, HistTable), {V0Specs.at(kPhiVsEta)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsCosPa, HistTable), getHistDesc(kPtVsCosPa, HistTable), getHistType(kPtVsCosPa, HistTable), {V0Specs.at(kPtVsCosPa)}); + + mHistogramRegistry->add(qaDir + getHistNameV2(kMassLambda, HistTable), getHistDesc(kMassLambda, HistTable), getHistType(kMassLambda, HistTable), {V0Specs.at(kMassLambda)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassAntiLambda, HistTable), getHistDesc(kMassAntiLambda, HistTable), getHistType(kMassAntiLambda, HistTable), {V0Specs.at(kMassAntiLambda)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassK0short, HistTable), getHistDesc(kMassK0short, HistTable), getHistType(kMassK0short, HistTable), {V0Specs.at(kMassK0short)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsLambdaMass, HistTable), getHistDesc(kPtVsLambdaMass, HistTable), getHistType(kPtVsLambdaMass, HistTable), {V0Specs.at(kPtVsLambdaMass)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsAntiLambdaMass, HistTable), getHistDesc(kPtVsAntiLambdaMass, HistTable), getHistType(kPtVsAntiLambdaMass, HistTable), {V0Specs.at(kPtVsAntiLambdaMass)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kPtVsK0shortMass, HistTable), getHistDesc(kPtVsK0shortMass, HistTable), getHistType(kPtVsK0shortMass, HistTable), {V0Specs.at(kPtVsK0shortMass)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kLambdaMassVsAntiLambdaMass, HistTable), getHistDesc(kLambdaMassVsAntiLambdaMass, HistTable), getHistType(kLambdaMassVsAntiLambdaMass, HistTable), {V0Specs.at(kLambdaMassVsAntiLambdaMass)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kK0shortMassVsLambdaMass, HistTable), getHistDesc(kK0shortMassVsLambdaMass, HistTable), getHistType(kK0shortMassVsLambdaMass, HistTable), {V0Specs.at(kK0shortMassVsLambdaMass)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kK0shortMassVsAntiLambdaMass, HistTable), getHistDesc(kK0shortMassVsAntiLambdaMass, HistTable), getHistType(kK0shortMassVsAntiLambdaMass, HistTable), {V0Specs.at(kK0shortMassVsAntiLambdaMass)}); + } + } + + template + void fillAnalysis(T const& v0candidate) + { + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt, HistTable)), v0candidate.pt()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(AnalysisDir) + HIST(getHistName(kEta, HistTable)), v0candidate.eta()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(AnalysisDir) + HIST(getHistName(kPhi, HistTable)), v0candidate.phi()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(AnalysisDir) + HIST(getHistName(kMass, HistTable)), v0candidate.mass()); + + if constexpr (modes::isEqual(v0, modes::V0::kLambda) || modes::isEqual(v0, modes::V0::kAntiLambda)) { + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), v0candidate.sign()); + } + if constexpr (modes::isEqual(v0, modes::V0::kK0short)) { + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), 0); + } + } + + template + void fillQa(T const& v0candidate) + { + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kCosPa, HistTable)), v0candidate.cosPa()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayDauDca, HistTable)), v0candidate.dauDca()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxX, HistTable)), v0candidate.decayVtxX()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxY, HistTable)), v0candidate.decayVtxY()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayVtxZ, HistTable)), v0candidate.decayVtxZ()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kDecayVtx, HistTable)), v0candidate.decayVtx()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kTransRadius, HistTable)), v0candidate.transRadius()); + + if (mPlot2d) { + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsEta, HistTable)), v0candidate.pt(), v0candidate.eta()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsPhi, HistTable)), v0candidate.pt(), v0candidate.phi()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPhiVsEta, HistTable)), v0candidate.phi(), v0candidate.eta()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsCosPa, HistTable)), v0candidate.pt(), v0candidate.cosPa()); + + if constexpr (modes::isEqual(v0, modes::V0::kLambda) || modes::isEqual(v0, modes::V0::kAntiLambda)) { + float massLambda, massAntiLambda; + if (v0candidate.sign() > 0) { + massLambda = v0candidate.mass(); + massAntiLambda = v0candidate.massAnti(); + } else { + massLambda = v0candidate.massAnti(); + massAntiLambda = v0candidate.mass(); + } + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kMassLambda, HistTable)), massLambda); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kMassAntiLambda, HistTable)), massAntiLambda); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kMassK0short, HistTable)), v0candidate.massK0short()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsLambdaMass, HistTable)), v0candidate.pt(), massLambda); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsAntiLambdaMass, HistTable)), v0candidate.pt(), massAntiLambda); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsK0shortMass, HistTable)), v0candidate.pt(), v0candidate.massK0short()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kLambdaMassVsAntiLambdaMass, HistTable)), massLambda, massAntiLambda); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kK0shortMassVsLambdaMass, HistTable)), v0candidate.massK0short(), massLambda); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kK0shortMassVsAntiLambdaMass, HistTable)), v0candidate.massK0short(), massAntiLambda); + } + + if constexpr (modes::isEqual(v0, modes::V0::kK0short)) { + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kMassLambda, HistTable)), v0candidate.massLambda()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kMassAntiLambda, HistTable)), v0candidate.massAntiLambda()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kMassK0short, HistTable)), v0candidate.mass()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsLambdaMass, HistTable)), v0candidate.pt(), v0candidate.massLambda()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsAntiLambdaMass, HistTable)), v0candidate.pt(), v0candidate.massAntiLambda()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kPtVsK0shortMass, HistTable)), v0candidate.pt(), v0candidate.mass()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kLambdaMassVsAntiLambdaMass, HistTable)), v0candidate.massLambda(), v0candidate.massAntiLambda()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kK0shortMassVsLambdaMass, HistTable)), v0candidate.mass(), v0candidate.massLambda()); + mHistogramRegistry->fill(HIST(v0Prefix) + HIST(QaDir) + HIST(getHistName(kK0shortMassVsAntiLambdaMass, HistTable)), v0candidate.mass(), v0candidate.massAntiLambda()); + } + } + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + bool mPlot2d = true; + trackhistmanager::TrackHistManager mPosDauManager; + trackhistmanager::TrackHistManager mNegDauManager; +}; +}; // namespace v0histmanager +}; // namespace o2::analysis::femto +#endif // PWGCF_FEMTO_CORE_V0HISTMANAGER_H_ diff --git a/PWGCF/Femto/DataModel/CMakeLists.txt b/PWGCF/Femto/DataModel/CMakeLists.txt new file mode 100644 index 00000000000..4c182222bf2 --- /dev/null +++ b/PWGCF/Femto/DataModel/CMakeLists.txt @@ -0,0 +1,10 @@ +# 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. diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h new file mode 100644 index 00000000000..f5ffde686e9 --- /dev/null +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -0,0 +1,673 @@ +// 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 FemtoTables.h +/// \brief Datamodel for femto analysis +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#ifndef PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_ +#define PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_ + +#include "PWGCF/Femto/Core/dataTypes.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/Expressions.h" + +#include +#include + +namespace o2::aod +{ +namespace femtocollisions +{ +DECLARE_SOA_COLUMN(Mask, mask, femtodatatypes::CollisionMaskType); //! Bitmask for collision selections +DECLARE_SOA_COLUMN(CollisionTag, collisionTag, femtodatatypes::CollisionTagType); //! Bitmask for collision selections + +DECLARE_SOA_COLUMN(PosX, posX, float); //! x coordinate of vertex +DECLARE_SOA_COLUMN(PosY, posY, float); //! y coordinate of vertex +DECLARE_SOA_COLUMN(PosZ, posZ, float); //! z coordinate of vertex +DECLARE_SOA_COLUMN(Mult, mult, float); //! Multiplicity estimator set by producer +DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (~= multiplicity percentile) estimator set by producer +DECLARE_SOA_COLUMN(MagField, magField, int8_t); //! Magnetic field in kG (5 kG at normal configuration and 2kG in low B field configuration) +DECLARE_SOA_COLUMN(Sphericity, sphericity, float); //! Sphericity of the event +DECLARE_SOA_COLUMN(Qn, qn, float); //! qn bins for dividing eventsfemtab +} // namespace femtocollisions + +// table for basic collision information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FCols_001, "FCOL", 1, //! femto collisions + o2::soa::Index<>, + femtocollisions::PosZ, + femtocollisions::Mult, + femtocollisions::Cent, + femtocollisions::MagField); +using FCols = FCols_001; +using FCol = FCols::iterator; +using StoredFCols = StoredFCols_001; + +// table for collisions selections +DECLARE_SOA_TABLE_STAGED_VERSIONED(FColMasks_001, "FCOLMASK", 1, //! track masks + femtocollisions::Mask); +using FColMasks = FColMasks_001; +using StoredFColMasks = StoredFColMasks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FColSphericities_001, "FCOLSPHERICITY", 1, //! sphericity + femtocollisions::Sphericity); +using FColSphericities = FColSphericities_001; + +// table for qn values +DECLARE_SOA_TABLE_STAGED_VERSIONED(FColQns_001, "FCOLQN", 1, //! qn vector + femtocollisions::Qn); +using FColQns = FColQns_001; + +// table for primary vertex location +DECLARE_SOA_TABLE_STAGED_VERSIONED(FColPos_001, "FCOLPOS", 1, //! full vertex position + femtocollisions::PosX, + femtocollisions::PosY); +using FColPos = FColPos_001; + +// table for different multiplicity estimators +DECLARE_SOA_TABLE_STAGED_VERSIONED(FColMults_001, "FCOLMULT", 1, //! multiplicities + mult::MultFT0A, mult::MultFT0C, //! FIT detectors + mult::MultNTracksPVeta1, //! number of PV contribs total + mult::MultNTracksPVetaHalf, //! global track multiplicities + evsel::NumTracksInTimeRange, //! occupancy (number of track in time range) + evsel::SumAmpFT0CInTimeRange); //! occupancy (FT0C amplitude in time range) +using FColMults = FColMults_001; + +// table for different centrality (multiplicity percentile) estimators +DECLARE_SOA_TABLE_STAGED_VERSIONED(FColCents_001, "FCOLCENT", 1, //! centralities + cent::CentFT0A, //! centrality from FT0A + cent::CentFT0C); //! centrality from FT0C +using FColCents = FColCents_001; + +namespace femtobase +// all "basic" information to perform femto analysis, i.e. collision index and kinematics +// split kinematics in stored, i.e. stored in derived data, and dynmaic, i.e. can be computed on the fly +{ +namespace stored +{ +// static columns +DECLARE_SOA_INDEX_COLUMN(FCol, fCol); //! collision index of femto collision table +DECLARE_SOA_COLUMN(SignedPt, signedPt, float); //! signed pt +DECLARE_SOA_COLUMN(Pt, pt, float); //! pt +DECLARE_SOA_COLUMN(Eta, eta, float); //! eta +DECLARE_SOA_COLUMN(Phi, phi, float); //! phi +DECLARE_SOA_COLUMN(Mass, mass, float); //! mass of particle +DECLARE_SOA_COLUMN(MassAnti, massAnti, float); //! mass of antiparticle +} // namespace stored + +namespace dynamic +{ +// dynamic columns +DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, //! sign of the track + [](float signedPt) -> int { + return signedPt > 0.f ? 1 : -1; + }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! transverse momentum + [](float signedPt) -> float { + return std::fabs(signedPt); + }); +// use fabs for pt so it can also be used with signed pt +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! momentum in x + [](float pt, float phi) -> float { + return std::fabs(pt) * std::sin(phi); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! momentum in y + [](float pt, float phi) -> float { + return std::fabs(pt) * std::cos(phi); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! momentum in z + [](float pt, float eta) -> float { + return std::fabs(pt) * std::sinh(eta); + }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! momentum + [](float pt, float eta) -> float { + return std::fabs(pt) * std::cosh(eta); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Theta, theta, //! theta + [](float eta) -> float { + return 2.f * std::atan(std::exp(-eta)); + }); +} // namespace dynamic +} // namespace femtobase + +namespace femtotracks +{ +// columns for track selections +DECLARE_SOA_COLUMN(Mask, mask, femtodatatypes::TrackMaskType); //! Bitmask for track selections + +// columns for DCA +DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); //! Dca in XY plane +DECLARE_SOA_COLUMN(DcaZ, dcaZ, float); //! Dca in Z direction +DECLARE_SOA_DYNAMIC_COLUMN(Dca, dca, [](float dcaXY, float dcaZ) -> float { return std::hypot(dcaXY, dcaZ); }); //! Dca + +// its related information +DECLARE_SOA_COLUMN(IsPVContributor, isPVContributor, bool); //! True if track is PV contributer +DECLARE_SOA_COLUMN(ItsNCls, itsNCls, uint8_t); //! Number of Its clusters (max 7) +DECLARE_SOA_COLUMN(ItsNClsInnerBarrel, itsNClsInnerBarrel, uint8_t); //! Number of Its clusters in the inner barrel (max 3) +DECLARE_SOA_COLUMN(ItsChi2NCl, itsChi2NCl, float); //! Its chi2 / cluster +DECLARE_SOA_COLUMN(ItsClusterSizes, itsClusterSizes, uint32_t); //! Its cluster sizes (4 bits per layer) + +// tpc related information +DECLARE_SOA_COLUMN(TpcSignal, tpcSignal, float); //! Tpc signal +DECLARE_SOA_COLUMN(TpcInnerParam, tpcInnerParam, float); //! Momentum at inner wall of Tpc +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_DYNAMIC_COLUMN(TpcCrossedRowsOverFound, tpcCrossedRowsOverFound, //! Number of crossed rows over found Tpc clusters + [](uint8_t tpcNClsFound, uint8_t tpcNClsCrossedRows) -> float { return static_cast(tpcNClsCrossedRows) / static_cast(tpcNClsFound); }); +DECLARE_SOA_COLUMN(TpcNClsShared, tpcNClsShared, uint8_t); //! Number of shared Tpc clusters +DECLARE_SOA_DYNAMIC_COLUMN(TpcSharedOverFound, tpcSharedOverFound, //! Number of crossed rows over found Tpc clusters + [](uint8_t tpcNclsFound, uint8_t tpcNClsShared) -> float { return static_cast(tpcNClsShared) / static_cast(tpcNclsFound); }); +DECLARE_SOA_COLUMN(TpcChi2NCl, tpcChi2NCl, float); //! Tpc chi2 + +// tof related information +DECLARE_SOA_COLUMN(TofBeta, tofBeta, float); //! Tof beta +DECLARE_SOA_COLUMN(TofMass, tofMass, float); //! Tof mass + +// PID information +// ITS PID information +DECLARE_SOA_COLUMN(ItsNSigmaEl, itsNSigmaEl, float); //! Nsigma separation with the Its for electron +DECLARE_SOA_COLUMN(ItsNSigmaPi, itsNSigmaPi, float); //! Nsigma separation with the Its for pion +DECLARE_SOA_COLUMN(ItsNSigmaKa, itsNSigmaKa, float); //! Nsigma separation with the Its for kaon +DECLARE_SOA_COLUMN(ItsNSigmaPr, itsNSigmaPr, float); //! Nsigma separation with the Its for proton +DECLARE_SOA_COLUMN(ItsNSigmaDe, itsNSigmaDe, float); //! Nsigma separation with the Its for deuteron +DECLARE_SOA_COLUMN(ItsNSigmaTr, itsNSigmaTr, float); //! Nsigma separation with the Its for triton +DECLARE_SOA_COLUMN(ItsNSigmaHe, itsNSigmaHe, float); //! Nsigma separation with the Its for helium3 + +// TPC PID information +DECLARE_SOA_COLUMN(TpcNSigmaEl, tpcNSigmaEl, float); //! Nsigma separation with the Tpc for electron +DECLARE_SOA_COLUMN(TpcNSigmaPi, tpcNSigmaPi, float); //! Nsigma separation with the Tpc for pion +DECLARE_SOA_COLUMN(TpcNSigmaKa, tpcNSigmaKa, float); //! Nsigma separation with the Tpc for kaon +DECLARE_SOA_COLUMN(TpcNSigmaPr, tpcNSigmaPr, float); //! Nsigma separation with the Tpc for proton +DECLARE_SOA_COLUMN(TpcNSigmaDe, tpcNSigmaDe, float); //! Nsigma separation with the Tpc for deuteron +DECLARE_SOA_COLUMN(TpcNSigmaTr, tpcNSigmaTr, float); //! Nsigma separation with the Tpc for triton +DECLARE_SOA_COLUMN(TpcNSigmaHe, tpcNSigmaHe, float); //! Nsigma separation with the Tpc for helium3 + +// TOF PID information +DECLARE_SOA_COLUMN(TofNSigmaEl, tofNSigmaEl, float); //! Nsigma separation with the Tof for electron +DECLARE_SOA_COLUMN(TofNSigmaPi, tofNSigmaPi, float); //! Nsigma separation with the Tof for pion +DECLARE_SOA_COLUMN(TofNSigmaKa, tofNSigmaKa, float); //! Nsigma separation with the Tof for kaon +DECLARE_SOA_COLUMN(TofNSigmaPr, tofNSigmaPr, float); //! Nsigma separation with the Tof for proton +DECLARE_SOA_COLUMN(TofNSigmaDe, tofNSigmaDe, float); //! Nsigma separation with the Tof for deuteron +DECLARE_SOA_COLUMN(TofNSigmaTr, tofNSigmaTr, float); //! Nsigma separation with the Tof for triton +DECLARE_SOA_COLUMN(TofNSigmaHe, tofNSigmaHe, float); //! Nsigma separation with the Tof for helium3 + +DECLARE_SOA_DYNAMIC_COLUMN(TpcitsNSigmaEl, tpcitsNSigmaEl, [](float tpc, float its) -> float { return std::hypot(tpc, its); }); //! Combined Nsigma separation with Tpc and Its for electon +DECLARE_SOA_DYNAMIC_COLUMN(TpcitsNSigmaPi, tpcitsNSigmaPi, [](float tpc, float its) -> float { return std::hypot(tpc, its); }); //! Combined Nsigma separation with Tpc and Its for pion +DECLARE_SOA_DYNAMIC_COLUMN(TpcitsNSigmaKa, tpcitsNSigmaKa, [](float tpc, float its) -> float { return std::hypot(tpc, its); }); //! Combined Nsigma separation with Tpc and Its for kaon +DECLARE_SOA_DYNAMIC_COLUMN(TpcitsNSigmaPr, tpcitsNSigmaPr, [](float tpc, float its) -> float { return std::hypot(tpc, its); }); //! Combined Nsigma separation with Tpc and Its for proton +DECLARE_SOA_DYNAMIC_COLUMN(TpcitsNSigmaDe, tpcitsNSigmaDe, [](float tpc, float its) -> float { return std::hypot(tpc, its); }); //! Combined Nsigma separation with Tpc and Its for deuteron +DECLARE_SOA_DYNAMIC_COLUMN(TpcitsNSigmaTr, tpcitsNSigmaTr, [](float tpc, float its) -> float { return std::hypot(tpc, its); }); //! Combined Nsigma separation with Tpc and Its for trition +DECLARE_SOA_DYNAMIC_COLUMN(TpcitsNSigmaHe, tpcitsNSigmaHe, [](float tpc, float its) -> float { return std::hypot(tpc, its); }); //! Combined Nsigma separation with Tpc and Its for helium3 + +DECLARE_SOA_DYNAMIC_COLUMN(TpctofNSigmaEl, tpctofNSigmaEl, [](float tpc, float tof) -> float { return std::hypot(tpc, tof); }); //! Combined Nsigma separation with Tpc and Tof for electons +DECLARE_SOA_DYNAMIC_COLUMN(TpctofNSigmaPi, tpctofNSigmaPi, [](float tpc, float tof) -> float { return std::hypot(tpc, tof); }); //! Combined Nsigma separation with Tpc and Tof for pion +DECLARE_SOA_DYNAMIC_COLUMN(TpctofNSigmaKa, tpctofNSigmaKa, [](float tpc, float tof) -> float { return std::hypot(tpc, tof); }); //! Combined Nsigma separation with Tpc and Tof for kaon +DECLARE_SOA_DYNAMIC_COLUMN(TpctofNSigmaPr, tpctofNSigmaPr, [](float tpc, float tof) -> float { return std::hypot(tpc, tof); }); //! Combined Nsigma separation with Tpc and Tof for proton +DECLARE_SOA_DYNAMIC_COLUMN(TpctofNSigmaDe, tpctofNSigmaDe, [](float tpc, float tof) -> float { return std::hypot(tpc, tof); }); //! Combined Nsigma separation with Tpc and Tof for deuteron +DECLARE_SOA_DYNAMIC_COLUMN(TpctofNSigmaTr, tpctofNSigmaTr, [](float tpc, float tof) -> float { return std::hypot(tpc, tof); }); //! Combined Nsigma separation with Tpc and Tof for triton +DECLARE_SOA_DYNAMIC_COLUMN(TpctofNSigmaHe, tpctofNSigmaHe, [](float tpc, float tof) -> float { return std::hypot(tpc, tof); }); //! Combined Nsigma separation with Tpc and Tof for helium3 + +} // namespace femtotracks + +// table for basic track information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FTracks_001, "FTRACK", 1, //! femto tracks + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::SignedPt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FTracks = FTracks_001; +using FTrack = FTracks::iterator; +using StoredFTracks = StoredFTracks_001; + +// table for track selections and PID selections +DECLARE_SOA_TABLE_STAGED_VERSIONED(FTrackMasks_001, "FTRACKMASK", 1, //! track masks + femtotracks::Mask); +using FTrackMasks = FTrackMasks_001; +using StoredFTrackMasks = StoredFTrackMasks_001; + +// table for track DCA +DECLARE_SOA_TABLE_STAGED_VERSIONED(FTrackDcas_001, "FTRACKDCAS", 1, //! track dcas + femtotracks::DcaXY, + femtotracks::DcaZ, + femtotracks::Dca); +using FTrackDcas = FTrackDcas_001; + +// table for extra track information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FTrackExtras_001, "FTRACKEXTRA", 1, //! track extra information + femtotracks::IsPVContributor, + femtotracks::ItsNCls, + femtotracks::ItsNClsInnerBarrel, + femtotracks::ItsChi2NCl, + femtotracks::ItsClusterSizes, + femtotracks::TpcSignal, + femtotracks::TpcInnerParam, + femtotracks::TpcNClsFound, + femtotracks::TpcNClsCrossedRows, + femtotracks::TpcNClsShared, + femtotracks::TofBeta, + femtotracks::TofMass, + femtotracks::TpcCrossedRowsOverFound, + femtotracks::TpcSharedOverFound); +using FTrackExtras = FTrackExtras_001; + +// table for extra PID information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FElectronPids_001, "FELECTRONPID", 1, //! full electron pid + femtotracks::ItsNSigmaEl, + femtotracks::TpcNSigmaEl, + femtotracks::TofNSigmaEl, + femtotracks::TpcitsNSigmaEl, + femtotracks::TpctofNSigmaEl); +using FElectronPids = FElectronPids_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FPionPids_001, "FPIONPID", 1, //! full pion pid + femtotracks::ItsNSigmaPi, + femtotracks::TpcNSigmaPi, + femtotracks::TofNSigmaPi, + femtotracks::TpcitsNSigmaPi, + femtotracks::TpctofNSigmaPi); +using FPionPids = FPionPids_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FKaonPids_001, "FKAONPID", 1, //! full kaon pid + femtotracks::ItsNSigmaKa, + femtotracks::TpcNSigmaKa, + femtotracks::TofNSigmaKa, + femtotracks::TpcitsNSigmaKa, + femtotracks::TpctofNSigmaKa); +using FKaonPids = FKaonPids_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FProtonPids_001, "FPROTONPID", 1, //! full proton pid + femtotracks::ItsNSigmaPr, + femtotracks::TpcNSigmaPr, + femtotracks::TofNSigmaPr, + femtotracks::TpcitsNSigmaPr, + femtotracks::TpctofNSigmaPr); +using FProtonPids = FProtonPids_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FDeuteronPids_001, "FDEUTERONPID", 1, //! full deuteron pid + femtotracks::ItsNSigmaDe, + femtotracks::TpcNSigmaDe, + femtotracks::TofNSigmaDe, + femtotracks::TpcitsNSigmaDe, + femtotracks::TpctofNSigmaDe); +using FDeuteronPids = FDeuteronPids_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FTritonPids_001, "FTRITONPID", 1, //! full triton pid + femtotracks::ItsNSigmaTr, + femtotracks::TpcNSigmaTr, + femtotracks::TofNSigmaTr, + femtotracks::TpcitsNSigmaTr, + femtotracks::TpctofNSigmaTr); +using FTritonPids = FTritonPids_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FHeliumPids_001, "FHELIUMPID", 1, //! full helium3 pid + femtotracks::ItsNSigmaHe, + femtotracks::TpcNSigmaHe, + femtotracks::TofNSigmaHe, + femtotracks::TpcitsNSigmaHe, + femtotracks::TpctofNSigmaHe); +using FHeliumPids = FHeliumPids_001; + +using FTrackPids = soa::Join; + +namespace femtotwotrackresonances +{ +// columns for resonance bit masks +DECLARE_SOA_COLUMN(Mask, mask, femtodatatypes::TwoTrackResonanceMaskType); //! Bitmask for resonance selections + +// id columns for resonance daughter tracks +DECLARE_SOA_INDEX_COLUMN_FULL(PosDau, posDau, int32_t, FTracks, "_PosDau"); //! index column for positive daughter track +DECLARE_SOA_INDEX_COLUMN_FULL(NegDau, negDau, int32_t, FTracks, "_NegDau"); //! index column for negative daughter track +} // namespace femtotwotrackresonances +// table for phis +DECLARE_SOA_TABLE_STAGED_VERSIONED(FPhis_001, "FPHI", 1, //! femto phis + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::Pt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtotwotrackresonances::PosDauId, + femtotwotrackresonances::NegDauId, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FPhis = FPhis_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FPhiMasks_001, "FPHIMASK", 1, //! mask for phis + femtotwotrackresonances::Mask); +using FPhiMasks = FPhiMasks_001; + +// table for kstars +DECLARE_SOA_TABLE_STAGED_VERSIONED(FKstar0s_001, "FKSTAR0", 1, //! femto k0star + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::SignedPt, //! +1 for k0star and -1 for k0starbar + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtotwotrackresonances::PosDauId, + femtotwotrackresonances::NegDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FKstar0s = FKstar0s_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FKstar0Masks_001, "FKSTAR0MASK", 1, //! k0star masks + femtotwotrackresonances::Mask); +using FKstar0Masks = FKstar0Masks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FRho0s_001, "FRHO0", 1, //! femto rho0s + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::Pt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtotwotrackresonances::PosDauId, + femtotwotrackresonances::NegDauId, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FRho0s = FRho0s_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FRho0Masks_001, "FRHO0MASK", 1, //! rho0s masks + femtotwotrackresonances::Mask); +using FRho0Masks = FRho0Masks_001; + +namespace femtov0s +{ +// columns for bit masks +DECLARE_SOA_COLUMN(Mask, mask, femtodatatypes::V0MaskType); //! Bitmask for v0 selections + +// columns for debug information +DECLARE_SOA_COLUMN(MassLambda, massLambda, float); //! Mass of Lambda +DECLARE_SOA_COLUMN(MassAntiLambda, massAntiLambda, float); //! Mass of AntiLambda +DECLARE_SOA_COLUMN(MassK0short, massK0short, float); //! Mass of K0short +DECLARE_SOA_COLUMN(CosPa, cosPa, float); //! Lambda daughter DCA at decay vertex +DECLARE_SOA_COLUMN(DauDca, dauDca, float); //! Lambda daughter DCA at decay vertex +DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Lambda transvers radius +DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! x coordinate of Lambda decay vertex +DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! y coordinate of Lambda decay vertex +DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! z coordinate of Lambda decay vertex +DECLARE_SOA_DYNAMIC_COLUMN(DecayVtx, decayVtx, //! distance of decay vertex from nominal interaction point + [](float vtxX, float vtxY, float vtxZ) -> float { + return std::hypot(vtxX, vtxY, vtxZ); + }); + +// id columns for Lambda daughter tracks +DECLARE_SOA_INDEX_COLUMN_FULL(PosDau, posDau, int32_t, FTracks, "_PosDau"); //! index column for positive daughter track +DECLARE_SOA_INDEX_COLUMN_FULL(NegDau, negDau, int32_t, FTracks, "_NegDau"); //! index column for negative daughter track + +} // namespace femtov0s + +// table for basic lambda information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdas_001, "FLAMBDA", 1, //! femto lambdas + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::SignedPt, // use sign to differentiate between lambda (+1) and antilambda (-1) + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, // mass of the lambda/antilambda depending on the sign of the pt + femtov0s::PosDauId, + femtov0s::NegDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FLambdas = FLambdas_001; +using StoredFLambdas = StoredFLambdas_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdaMasks_001, "FLAMBDAMASK", 1, //! lambda masks + femtov0s::Mask); +using FLambdaMasks = FLambdaMasks_001; +using StoredFLambdaMasks = StoredFLambdaMasks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdaExtras_001, "FLAMBDAEXTRA", 1, //! lambda extra information + femtobase::stored::MassAnti, // put mass of antiparticle, i.e. antilambda mass for lambdas and vice versa + femtov0s::MassK0short, + femtov0s::CosPa, + femtov0s::DauDca, + femtov0s::TransRadius, + femtov0s::DecayVtxX, + femtov0s::DecayVtxY, + femtov0s::DecayVtxZ, + femtov0s::DecayVtx); + +using FLambdaExtras = FLambdaExtras_001; + +// table for basic k0short information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shorts_001, "FK0SHORT", 1, //! femto k0shorts + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::Pt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtov0s::PosDauId, + femtov0s::NegDauId, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FK0shorts = FK0shorts_001; +using StoredFK0shorts = StoredFK0shorts_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shortMasks_001, "FK0SHORTMASK", 1, //! k0short masks + femtov0s::Mask); +using FK0shortMasks = FK0shortMasks_001; +using StoredFK0shortMasks = StoredFK0shortMasks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shortExtras_001, "FK0SHORTEXTRA", 1, //! k0short extra information + femtov0s::MassLambda, + femtov0s::MassAntiLambda, + femtov0s::CosPa, + femtov0s::DauDca, + femtov0s::TransRadius, + femtov0s::DecayVtxX, + femtov0s::DecayVtxY, + femtov0s::DecayVtxZ, + femtov0s::DecayVtx); + +using FK0shortExtras = FK0shortExtras_001; + +namespace femtokinks +{ +// columns for bit masks +DECLARE_SOA_COLUMN(Mask, mask, femtodatatypes::KinkMaskType); //! Bitmask for kink selections + +// columns for debug information +DECLARE_SOA_COLUMN(KinkAngle, kinkAngle, float); //! Kink angle between mother and charged daughter at decay vertex +DECLARE_SOA_COLUMN(DcaMothToPV, dcaMothToPV, float); //! DCA of the mother track to the primary vertex +DECLARE_SOA_COLUMN(DcaDaugToPV, dcaDaugToPV, float); //! DCA of the charged daughter track to the primary vertex +DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); //! x coordinate of decay vertex (relative to PV) +DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); //! y coordinate of decay vertex (relative to PV) +DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! z coordinate of decay vertex (relative to PV) +DECLARE_SOA_COLUMN(TransRadius, transRadius, float); //! Transverse decay radius from PV + +// id column for charged daughter track +DECLARE_SOA_INDEX_COLUMN_FULL(ChaDau, chaDau, int32_t, FTracks, "_ChaDau"); //! +} // namespace femtokinks + +// table for basic sigma information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmas_001, "FSIGMA", 1, + o2::soa::Index<>, + femtobase::stored::FColId, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) + femtobase::stored::SignedPt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtokinks::ChaDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FSigmas = FSigmas_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaMasks_001, "FSIGMAMASKS", 1, + femtokinks::Mask); +using FSigmaMasks = FSigmaMasks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaExtras_001, "FSIGMAEXTRAS", 1, + femtokinks::KinkAngle, + femtokinks::DcaDaugToPV, + femtokinks::DcaMothToPV, + femtokinks::DecayVtxX, + femtokinks::DecayVtxY, + femtokinks::DecayVtxZ, + femtokinks::TransRadius); + +using FSigmaExtras = FSigmaExtras_001; + +// table for basic sigma plus information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlus_001, "FSIGMAPLUS", 1, + o2::soa::Index<>, + femtobase::stored::FColId, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) + femtobase::stored::SignedPt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtokinks::ChaDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FSigmaPlus = FSigmaPlus_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlusMasks_001, "FSIGMAPLUSMASKS", 1, + femtokinks::Mask); +using FSigmaPlusMasks = FSigmaPlusMasks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlusExtras_001, "FSIGMAPLUSEXTRAS", 1, + femtokinks::KinkAngle, + femtokinks::DcaDaugToPV, + femtokinks::DcaMothToPV, + femtokinks::DecayVtxX, + femtokinks::DecayVtxY, + femtokinks::DecayVtxZ, + femtokinks::TransRadius); + +using FSigmaPlusExtras = FSigmaPlusExtras_001; + +namespace femtocascades +{ +// columns for cascade bit masks +DECLARE_SOA_COLUMN(Mask, mask, femtodatatypes::CascadeMaskType); //! Bitmask for cascade selections + +// columns for cascad debug information +DECLARE_SOA_COLUMN(MassXi, massXi, float); //! Mass of xi +DECLARE_SOA_COLUMN(MassOmega, massOmega, float); //! Mass of omega +DECLARE_SOA_COLUMN(CascadeCosPa, cascadeCosPa, float); //! cosine of the poiting angle at decay vertex +DECLARE_SOA_COLUMN(CascadeDauDca, cascadeDauDca, float); //! Lambda daughter DCA at decay vertex +DECLARE_SOA_COLUMN(CascadeTransRadius, cascadeTransRadius, float); //! Lambda transvers radius +DECLARE_SOA_COLUMN(LambdaCosPa, lambdaCosPa, float); //! cosine of the poiting angle at decay vertex +DECLARE_SOA_COLUMN(LambdaDauDca, lambdaDauDca, float); //! Lambda daughter DCA at decay vertex +DECLARE_SOA_COLUMN(LambdaTransRadius, lambdaTransRadius, float); //! Lambda transvers radius +DECLARE_SOA_COLUMN(LambdaDcaToPv, lambdaDcaToPv, float); //! Lambda transvers radius + +// id columns for bachelor +// following same style as strangeness tables were we do not store the id of the lambda, but its daughters +DECLARE_SOA_INDEX_COLUMN_FULL(Bachelor, bachelor, int32_t, FTracks, "_Bachelor"); //! bachelor id + +} // namespace femtocascades + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FXis_001, "FXI", 1, //! femto xis + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::SignedPt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtocascades::BachelorId, + femtov0s::PosDauId, + femtov0s::NegDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FXis = FXis_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiMasks_001, "FXIMASK", 1, //! xi masks + femtocascades::Mask); +using FXiMasks = FXiMasks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiExtras_001, "FXIEXTRA", 1, //! xi extra information + femtocascades::MassOmega, + femtocascades::CascadeCosPa, + femtocascades::CascadeDauDca, + femtocascades::CascadeTransRadius, + femtocascades::LambdaCosPa, + femtocascades::LambdaDauDca, + femtocascades::LambdaTransRadius, + femtocascades::LambdaDcaToPv); +using FXiExtras = FXiExtras_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegas_001, "FOMEGA", 1, //! femto omegas + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::SignedPt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtocascades::BachelorId, + femtov0s::PosDauId, + femtov0s::NegDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FOmegas = FOmegas_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaMasks_001, "FOMEGAMASK", 1, //! omega masks + femtocascades::Mask); +using FOmegaMasks = FOmegaMasks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaExtras_001, "FOMEGAEXTRA", 1, //! omega extra information + femtocascades::MassXi, + femtocascades::CascadeCosPa, + femtocascades::CascadeDauDca, + femtocascades::CascadeTransRadius, + femtocascades::LambdaCosPa, + femtocascades::LambdaDauDca, + femtocascades::LambdaTransRadius, + femtocascades::LambdaDcaToPv); +using FOmegaExtras = FOmegaExtras_001; + +} // namespace o2::aod +#endif // PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_ diff --git a/PWGCF/Femto/FemtoNuclei/CMakeLists.txt b/PWGCF/Femto/FemtoNuclei/CMakeLists.txt new file mode 100644 index 00000000000..27462d99baf --- /dev/null +++ b/PWGCF/Femto/FemtoNuclei/CMakeLists.txt @@ -0,0 +1,12 @@ +# 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. + +add_subdirectory(TableProducer) diff --git a/PWGCF/Femto/FemtoNuclei/DataModel/PionNucleiTables.h b/PWGCF/Femto/FemtoNuclei/DataModel/PionNucleiTables.h new file mode 100644 index 00000000000..7c0d3efc7a6 --- /dev/null +++ b/PWGCF/Femto/FemtoNuclei/DataModel/PionNucleiTables.h @@ -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 PionNucleiTables.h +/// \brief Slim tables for piNuclei +/// \author CMY +/// \date 2025-04-10 + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +#ifndef PWGCF_FEMTO_FEMTONUCLEI_DATAMODEL_PIONNUCLEITABLES_H_ +#define PWGCF_FEMTO_FEMTONUCLEI_DATAMODEL_PIONNUCLEITABLES_H_ + +namespace o2::aod +{ +namespace pion_nuclei_tables +{ + +DECLARE_SOA_COLUMN(PtNu, ptNu, float); +DECLARE_SOA_COLUMN(EtaNu, etaNu, float); +DECLARE_SOA_COLUMN(PhiNu, phiNu, float); +DECLARE_SOA_COLUMN(PtHyp, ptHyp, float); +DECLARE_SOA_COLUMN(PtHe3, ptHe3, float); +DECLARE_SOA_COLUMN(EtaHyp, etaHyp, float); +DECLARE_SOA_COLUMN(EtaHe3, etaHe3, float); +DECLARE_SOA_COLUMN(PhiHyp, phiHyp, float); +DECLARE_SOA_COLUMN(PtPi, ptPi, float); +DECLARE_SOA_COLUMN(EtaPi, etaPi, float); +DECLARE_SOA_COLUMN(PhiPi, phiPi, float); + +DECLARE_SOA_COLUMN(DcaxyNu, dcaxyNu, float); +DECLARE_SOA_COLUMN(DcazNu, dcazNu, float); +DECLARE_SOA_COLUMN(DcaxyPi, dcaxyPi, float); +DECLARE_SOA_COLUMN(DcazPi, dcazPi, float); + +DECLARE_SOA_COLUMN(SignalTPCNu, signalTPCNu, float); +DECLARE_SOA_COLUMN(InnerParamTPCNu, innerParamTPCNu, float); +DECLARE_SOA_COLUMN(SignalTPCPi, signalTPCPi, float); +DECLARE_SOA_COLUMN(InnerParamTPCPi, innerParamTPCPi, float); +DECLARE_SOA_COLUMN(NClsTPCNu, nClsTPCNu, uint8_t); +DECLARE_SOA_COLUMN(NSigmaTPCNu, nSigmaTPCNu, float); +DECLARE_SOA_COLUMN(NSigmaTPCPi, nSigmaTPCPi, float); +DECLARE_SOA_COLUMN(Chi2TPCNu, chi2TPCNu, float); +DECLARE_SOA_COLUMN(Chi2TPCPi, chi2TPCPi, float); +DECLARE_SOA_COLUMN(MassTOFNu, massTOFNu, float); +DECLARE_SOA_COLUMN(MassTOFPi, massTOFPi, float); +DECLARE_SOA_COLUMN(PidTrkNu, pidTrkNu, uint32_t); +DECLARE_SOA_COLUMN(PidTrkPi, pidTrkPi, uint32_t); +DECLARE_SOA_COLUMN(TrackIDPi, trackIDPi, int); +DECLARE_SOA_COLUMN(TrackIDNu, trackIDNu, int); + +DECLARE_SOA_COLUMN(ItsClusterSizeNu, itsClusterSizeNu, uint32_t); +DECLARE_SOA_COLUMN(ItsClusterSizePi, itsClusterSizePi, uint32_t); + +DECLARE_SOA_COLUMN(SharedClustersNu, sharedClustersNu, uint8_t); +DECLARE_SOA_COLUMN(SharedClustersPi, sharedClustersPi, uint8_t); + +DECLARE_SOA_COLUMN(IsBkgUS, isBkgUS, bool); +DECLARE_SOA_COLUMN(IsBkgEM, isBkgEM, bool); + +DECLARE_SOA_COLUMN(CollisionId, collisionId, int64_t); +DECLARE_SOA_COLUMN(ZVertex, zVertex, float); +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, uint16_t); +DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); +DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0C, float); + +} // namespace pion_nuclei_tables + +DECLARE_SOA_TABLE(PionNucleiTable, "AOD", "PINUCLEITABLE", + pion_nuclei_tables::TrackIDPi, + pion_nuclei_tables::TrackIDNu) +DECLARE_SOA_TABLE(PionHyperTable, "AOD", "PIHYPERTABLE", + pion_nuclei_tables::PtHyp, + pion_nuclei_tables::EtaHyp, + pion_nuclei_tables::PtHe3, + pion_nuclei_tables::EtaHe3, + pion_nuclei_tables::PhiHyp, + pion_nuclei_tables::PtPi, + pion_nuclei_tables::EtaPi, + pion_nuclei_tables::PhiPi, + pion_nuclei_tables::DcaxyPi, + pion_nuclei_tables::DcazPi, + pion_nuclei_tables::SignalTPCPi, + pion_nuclei_tables::SignalTPCNu, + pion_nuclei_tables::InnerParamTPCPi, + pion_nuclei_tables::NSigmaTPCPi, + pion_nuclei_tables::NSigmaTPCNu, + pion_nuclei_tables::Chi2TPCPi, + pion_nuclei_tables::Chi2TPCNu, + pion_nuclei_tables::MassTOFPi, + pion_nuclei_tables::PidTrkPi, + pion_nuclei_tables::ItsClusterSizePi, + pion_nuclei_tables::ItsClusterSizeNu, + pion_nuclei_tables::SharedClustersPi, + pion_nuclei_tables::TrackIDPi, + pion_nuclei_tables::IsBkgUS, + pion_nuclei_tables::IsBkgEM) +DECLARE_SOA_TABLE(PionNucleiMult, "AOD", "PINUCLEIMULT", + pion_nuclei_tables::CollisionId, + pion_nuclei_tables::ZVertex, + pion_nuclei_tables::Multiplicity, + pion_nuclei_tables::CentFT0C, + pion_nuclei_tables::MultiplicityFT0C) + +} // namespace o2::aod + +#endif // PWGCF_FEMTO_FEMTONUCLEI_DATAMODEL_PIONNUCLEITABLES_H_ diff --git a/PWGCF/Femto/FemtoNuclei/TableProducer/CMakeLists.txt b/PWGCF/Femto/FemtoNuclei/TableProducer/CMakeLists.txt new file mode 100644 index 00000000000..4c6576278a5 --- /dev/null +++ b/PWGCF/Femto/FemtoNuclei/TableProducer/CMakeLists.txt @@ -0,0 +1,15 @@ +# 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. + +o2physics_add_dpl_workflow(pinucleifemto + SOURCES PiNucleiFemto.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/FemtoNuclei/TableProducer/PiNucleiFemto.cxx b/PWGCF/Femto/FemtoNuclei/TableProducer/PiNucleiFemto.cxx new file mode 100644 index 00000000000..348948916b8 --- /dev/null +++ b/PWGCF/Femto/FemtoNuclei/TableProducer/PiNucleiFemto.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. +// + +/// \file PiNucleiFemto.cxx +/// \brief Analysis task for Nuclei-Pion femto analysis +/// \author CMY +/// \date 2025-04-10 + +#include "PWGCF/Femto/FemtoNuclei/DataModel/PionNucleiTables.h" +#include "PWGCF/FemtoWorld/Core/FemtoWorldMath.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFHypernucleiTables.h" +#include "PWGLF/Utils/svPoolCreator.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/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "CCDB/BasicCCDBManager.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/Boost.h" +#include "Math/Vector4D.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include // std::prev +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +using CollBracket = o2::math_utils::Bracket; +using CollisionsFull = soa::Join; +using CollisionsFullMC = soa::Join; +using TrackCandidates = soa::Join; + +namespace +{ +constexpr double betheBlochDefault[1][6]{{-136.71, 0.441, 0.2269, 1.347, 0.8035, 0.09}}; +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; + +enum Selections { + kNoCuts = 0, + kTrackCuts, + kPID, + kAll +}; + +} // namespace + +struct PiNucandidate { + + float recoPtNu() const { return signNu * std::hypot(momNu[0], momNu[1]); } + float recoPhiNu() const { return std::atan2(momNu[1], momNu[0]); } + float recoEtaNu() const { return std::asinh(momNu[2] / std::abs(recoPtNu())); } + float recoPtPi() const { return signPi * std::hypot(momPi[0], momPi[1]); } + float recoPhiPi() const { return std::atan2(momPi[1], momPi[0]); } + float recoEtaPi() const { return std::asinh(momPi[2] / std::abs(recoPtPi())); } + + std::array momNu = {99.f, 99.f, 99.f}; + std::array momPi = {99.f, 99.f, 99.f}; + + float ptHe3 = 1.f; + float etaHe3 = 1.f; + float signNu = 1.f; + float signPi = 1.f; + float invMass = -10.f; + float dcaxyNu = -10.f; + float dcazNu = -10.f; + float dcaxyPi = -10.f; + float dcazPi = -10.f; + + uint16_t tpcSignalNu = 0u; + uint16_t tpcSignalPi = 0u; + float momNuTPC = -99.f; + float momPiTPC = -99.f; + uint8_t nTPCClustersNu = 0u; + uint8_t sharedClustersNu = 0u; + uint8_t sharedClustersPi = 0u; + float chi2TPCNu = -10.f; + float chi2TPCPi = -10.f; + float nSigmaNu = -10.f; + float nSigmaPi = -10.f; + float tpcPrnsigma = -10.f; + float tofPrnsigma = -10.f; + uint32_t pidTrkNu = 0xFFFFF; // PID in tracking + uint32_t pidTrkPi = 0xFFFFF; + float massTOFNu = -10; + float massTOFPi = -10; + uint32_t itsClSizeNu = 0u; + uint32_t itsClSizePi = 0u; + + uint8_t nClsItsNu = 0u; + uint8_t nClsItsPi = 0u; + + bool isBkgUS = false; // unlike sign + bool isBkgEM = false; // event mixing + + int trackIDNu = -1; + int trackIDPi = -1; + + float kstar = 1.f; + float mT = 1.f; + + // collision information + int32_t collisionID = 0; + float cent = 1.f; +}; + +struct PiNucleiFemto { + + Produces mOutputDataTable; + Produces mOutputHyperDataTable; + Produces mOutputMultiplicityTable; + + // Selections + Configurable settingCutVertex{"settingCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable settingCutPinMinDe{"settingCutPinMinDe", 0.0f, "Minimum Pin for De"}; + Configurable settingCutEta{"settingCutEta", 0.8f, "Eta cut on daughter track"}; + Configurable settingCutChi2tpcLow{"settingCutChi2tpcLow", 0.0f, "Low cut on TPC chi2"}; + Configurable settingCutChi2tpcHigh{"settingCutChi2tpcHigh", 999.f, "High cut on TPC chi2"}; + Configurable settingCutChi2tpcLowPion{"settingCutChi2tpcLowPion", 0.5f, "Low cut on TPC chi2 only for pion"}; + Configurable settingCutChi2tpcHighPion{"settingCutChi2tpcHighPion", 4.f, "High cut on TPC chi2 only for pion"}; + Configurable settingCutInvMass{"settingCutInvMass", 0.0f, "Invariant mass upper limit"}; + Configurable settingCutPtMinDePi{"settingCutPtMinDePi", 0.0f, "Minimum PT cut on DePi4"}; + Configurable settingCutClSizeItsDe{"settingCutClSizeItsDe", 4.0f, "Minimum ITS cluster size for De"}; + Configurable settingCutNCls{"settingCutNCls", 5.0f, "Minimum ITS Ncluster for tracks"}; + Configurable settingCutTPCChi2He{"settingCutTPCChi2He", 0.0f, "Minimum tpcChi2He for Hyper He3"}; + Configurable settingCutAverClsSizeHe{"settingCutAverClsSizeHe", 0.0f, "Minimum averClusSizeHe for Hyper He3"}; + Configurable settingCutChi2NClITS{"settingCutChi2NClITS", 999.f, "Maximum ITS Chi2 for tracks"}; + Configurable settingCutChi2NClITSPion{"settingCutChi2NClITSPion", 36.f, "Maximum ITS Chi2 for tracks only for pion"}; + Configurable settingCutNsigmaTPCPi{"settingCutNsigmaTPCPi", 3.0f, "Value of the TPC Nsigma cut on Pi"}; + Configurable settingCutNsigmaTPCDe{"settingCutNsigmaTPCDe", 2.5f, "Value of the TPC Nsigma cut on De"}; + Configurable settingCutNsigmaITSDe{"settingCutNsigmaITSDe", 2.5f, "Value of the ITD Nsigma cut on De"}; + Configurable settingCutPinMinTOFPi{"settingCutPinMinTOFPi", 0.5f, "Minimum Pin to apply the TOF cut on Pions"}; + Configurable settingCutPinMinTOFITSDe{"settingCutPinMinTOFITSDe", 1.2f, "Minimum p to apply the TOF ITS cut on De"}; + Configurable settingCutNsigmaTOFTPCDe{"settingCutNsigmaTOFTPCDe", 2.5f, "Value of the De TOF TPC Nsigma cut"}; + Configurable settingCutNsigmaTOFTPCPi{"settingCutNsigmaTOFTPCPi", 3.0f, "Value of the Pion TOF TPC Nsigma cut"}; + Configurable settingNoMixedEvents{"settingNoMixedEvents", 5, "Number of mixed events per event"}; + Configurable settingEnableBkgUS{"settingEnableBkgUS", false, "Enable US background"}; + Configurable settingSaferME{"settingSaferME", false, "For Safer ME"}; + + Configurable settingFillTable{"settingFillTable", false, "Enable table filling"}; + Configurable settingCutPiptMin{"settingCutPiptMin", 0.14f, "Minimum PT cut on Pi"}; + Configurable settingCutPiptMax{"settingCutPiptMax", 4.0f, "Maximum PT cut on Pi"}; + Configurable settingCutDeptMin{"settingCutDeptMin", 0.6f, "Minimum PT cut on De"}; + Configurable settingCutDeptMax{"settingCutDeptMax", 1.6f, "Maximum PT cut on De"}; + Configurable settingCutPiDCAxyMin{"settingCutPiDCAxyMin", 0.3f, "DCAxy Min for Pi"}; + Configurable settingCutPiDCAzMin{"settingCutPiDCAzMin", 0.3f, "DCAz Min for Pi"}; + Configurable settingCutDeDCAzMin{"settingCutDeDCAzMin", 0.2f, "DCAxy Min for De"}; + Configurable settingCutNsigTPCPrMin{"settingCutNsigTPCPrMin", 3.0f, "Minimum TPC Pr Nsigma cut on Pi"}; + Configurable settingCutNsigTOFPrMin{"settingCutNsigTOFPrMin", 3.0f, "Minimum TOF Pr Nsigma cut on Pi"}; + + Configurable settingSaveUSandLS{"settingSaveUSandLS", true, "Save All Pairs"}; + Configurable settingFillMultiplicity{"settingFillMultiplicity", false, "Fill multiplicity table"}; + Configurable settingUseBBcomputeDeNsigma{"settingUseBBcomputeDeNsigma", false, "Use BB params to compute De TPC Nsigma"}; + + // Zorro + Configurable settingSkimmedProcessing{"settingSkimmedProcessing", false, "Skimmed dataset processing"}; + + // CCDB options + Configurable settingDbz{"settingDbz", -999, "bz field, -999 is automatic"}; + Configurable settingCcdburl{"settingCcdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable settingGrpPath{"settingGrpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable settingGrpmagPath{"settingGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable settingLutPath{"settingLutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable settingGeoPath{"settingGeoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable settingPidPath{"settingPidPath", "", "Path to the PID response object"}; + + Configurable> settingBetheBlochParams{"settingBetheBlochParams", {betheBlochDefault[0], 1, 6, {"De"}, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for De"}; + Configurable settingCompensatePIDinTracking{"settingCompensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; + Configurable settingMaterialCorrection{"settingMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Material correction type"}; + + Preslice mPerCol = aod::track::collisionId; + PresliceUnsorted hypPerCol = o2::aod::hyperrec::collisionId; + + // binning for EM background + ConfigurableAxis axisVertex{"axisVertex", {30, -10, 10}, "Binning for vtxz"}; + ConfigurableAxis axisCentrality{"axisCentrality", {40, 0, 100}, "Binning for centrality"}; + using BinningType = ColumnBinningPolicy; + BinningType binningPolicy{{axisVertex, axisCentrality}, true}; + SliceCache cache; + SameKindPair mPair{binningPolicy, settingNoMixedEvents, -1, &cache}; + // Pair hyperPair{binningPolicy, settingNoMixedEvents, -1, &cache}; + + std::array mBBparamsDe; + + std::vector mRecoCollisionIDs; + std::vector mGoodCollisions; + std::vector mTrackPairs; + std::vector mTrackHypPairs; + o2::vertexing::DCAFitterN<2> mFitter; + + int mRunNumber; + float mDbz; + Service mCcdb; + Zorro mZorro; + OutputObj mZorroSummary{"zorroSummary"}; + + HistogramRegistry mQaRegistry{ + "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}}}}, + {"hCentrality", "Centrality", {HistType::kTH1F, {{100, 0.0f, 100.0f}}}}, + {"hTrackSel", "Accepted tracks", {HistType::kTH1F, {{Selections::kAll, -0.5, static_cast(Selections::kAll) - 0.5}}}}, + {"hSkipReasons", "Why storedEvent skipped;Reason;Counts", {HistType::kTH1F, {{5, -0.5, 4.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}}}}, + {"hdcaxyNu", ";DCA_{xy} (cm)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"hdcazNu", ";DCA_{z} (cm)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"hdcazNu_min", ";DCA_{z}-min (cm)", {HistType::kTH1F, {{20, -1.0f, 1.0f}}}}, + {"hNClsNuITS", ";N_{ITS} Cluster", {HistType::kTH1F, {{20, -10.0f, 10.0f}}}}, + {"hNClsPiITS", ";N_{ITS} Cluster", {HistType::kTH1F, {{20, -10.0f, 10.0f}}}}, + {"hNuPitInvMass", "; M(Nu + p) (GeV/#it{c}^{2})", {HistType::kTH1F, {{300, 3.74f, 4.34f}}}}, + {"hNuPt", "#it{p}_{T} distribution; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{240, -6.0f, 6.0f}}}}, + {"hPiPt", "Pt distribution; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{120, -3.0f, 3.0f}}}}, + {"hSingleNuPt", "#it{p}_{T} distribution; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{240, -6.0f, 6.0f}}}}, + {"hSinglePiPt", "Pt distribution; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{120, -3.0f, 3.0f}}}}, + {"hHe3TPCnsigma", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(He3)", {HistType::kTH2F, {{100, -2.0f, 2.0f}, {200, -5.0f, 5.0f}}}}, + {"hHe3P", "Pin distribution; p (GeV/#it{c})", {HistType::kTH1F, {{120, -3.0f, 3.0f}}}}, + {"hHe3P_preselected", "Pin distribution_preselected; p (GeV/#it{c})", {HistType::kTH1F, {{120, -3.0f, 3.0f}}}}, + {"hNuEta", "eta distribution; #eta(Nu)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"hPiEta", "eta distribution; #eta(#pi)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"hNuPhi", "phi distribution; phi(Nu)", {HistType::kTH1F, {{600, -4.0f, 4.0f}}}}, + {"hPiPhi", "phi distribution; phi(#pi)", {HistType::kTH1F, {{600, -4.0f, 4.0f}}}}, + {"h2dEdxNucandidates", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, + {"h2dEdx", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, + {"h2NsigmaNuTPC", "NsigmaNu TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(Nu)", {HistType::kTH2F, {{100, -2.0f, 2.0f}, {200, -5.0f, 5.0f}}}}, + {"h2NsigmaNuComb", "NsigmaNu TPCTOF comb distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{comb}(Nu)", {HistType::kTH2F, {{100, -2.0f, 2.0f}, {100, 0.0f, 5.0f}}}}, + {"h2NsigmaPiComb", "NsigmaPi TPCTOF comb distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{comb}(#pi)", {HistType::kTH2F, {{100, -2.0f, 2.0f}, {100, 0.0f, 5.0f}}}}, + {"h2NsigmaNuTPC_preselection", "NsigmaNu TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(Nu)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"h2NsigmaNuTPC_preselecComp", "NsigmaNu TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(Nu)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"h2NSigmaNuITS_preselection", "NsigmaNu ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} Nu", {HistType::kTH2F, {{50, -5.0f, 5.0f}, {120, -3.0f, 3.0f}}}}, + {"h2NSigmaNuITS", "NsigmaNu ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} Nu", {HistType::kTH2F, {{100, -2.0f, 2.0f}, {120, -3.0f, 3.0f}}}}, + {"h2NsigmaPiTPC", "NsigmaPi TPC distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{TPC}(p)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"h2NsigmaPiTPC_preselection", "NsigmaNu TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(Nu)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"h2NsigmaPiTOF", "NsigmaPi TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(p)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"h2NsigmaNuTOF", "NsigmaNu TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(Nu)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"h2NsigmaPiTOF_preselection", "NsigmaPi TOF distribution; #iit{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(p)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"hkStaVsmTVsCent_LS_M", ";kStar (GeV/c);mT (GeV/#it{c}^{2});Centrality", {HistType::kTH3F, {{300, 0.0f, 3.0f}, {100, 0.2, 3.2}, {100, 0.0f, 100.0f}}}}, + {"hkStaVsmTVsCent_LS_A", ";kStar (GeV/c);mT (GeV/#it{c}^{2});Centrality", {HistType::kTH3F, {{300, 0.0f, 3.0f}, {100, 0.2, 3.2}, {100, 0.0f, 100.0f}}}}, + {"hkStaVsmTVsCent_US_M", ";kStar (GeV/c);mT (GeV/#it{c}^{2});Centrality", {HistType::kTH3F, {{300, 0.0f, 3.0f}, {100, 0.2, 3.2}, {100, 0.0f, 100.0f}}}}, + {"hkStaVsmTVsCent_US_A", ";kStar (GeV/c);mT (GeV/#it{c}^{2});Centrality", {HistType::kTH3F, {{300, 0.0f, 3.0f}, {100, 0.2, 3.2}, {100, 0.0f, 100.0f}}}}, + {"hkStaVsmT_LS_M", ";kStar (GeV/c);mT (GeV/#it{c}^{2})", {HistType::kTH2F, {{300, 0.0f, 3.0f}, {2000, 0.8, 2.0}}}}, + {"hkStaVsmT_LS_A", ";kStar (GeV/c);mT (GeV/#it{c}^{2})", {HistType::kTH2F, {{300, 0.0f, 3.0f}, {2000, 0.8, 2.0}}}}, + {"hkStaVsmT_US_M", ";kStar (GeV/c);mT (GeV/#it{c}^{2})", {HistType::kTH2F, {{300, 0.0f, 3.0f}, {2000, 0.8, 2.0}}}}, + {"hkStaVsmT_US_A", ";kStar (GeV/c);mT (GeV/#it{c}^{2})", {HistType::kTH2F, {{300, 0.0f, 3.0f}, {2000, 0.8, 2.0}}}}, + {"hCollIDVsCentEachPion", ";CollisionID;Centrality", {HistType::kTH2F, {{4000, 0.0f, 4000.0f}, {100, 0.0f, 100.0f}}}}, + {"hCollIDVsCentEachDe", ";CollisionID;Centrality", {HistType::kTH2F, {{4000, 0.0f, 4000.0f}, {100, 0.0f, 100.0f}}}}, + {"hNHypsPerPrevColl", "Number of V0Hypers in previous collision used for mixing;N_{V0Hypers};Entries", {HistType::kTH2F, {{4000, 0.0f, 4000.0f}, {50, -0.5, 49.5}}}}, + {"hkStar_LS_M", ";kStar (GeV/c)", {HistType::kTH1F, {{300, 0.0f, 3.0f}}}}, + {"hkStar_LS_A", ";kStar (GeV/c)", {HistType::kTH1F, {{300, 0.0f, 3.0f}}}}, + {"hkStar_US_M", ";kStar (GeV/c)", {HistType::kTH1F, {{300, 0.0f, 3.0f}}}}, + {"hkStar_US_A", ";kStar (GeV/c)", {HistType::kTH1F, {{300, 0.0f, 3.0f}}}}, + {"h2NsigmaPiPrTPC", "NsigmaPi TPC distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{TPC}(p)", {HistType::kTH1F, {{200, -5.0f, 5.0f}}}}, + {"h2NsigmaPiPrTOF", "NsigmaPi TOF distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{TPC}(p)", {HistType::kTH1F, {{200, -5.0f, 5.0f}}}}, + {"hisBkgEM", "; isBkgEM;", {HistType::kTH1F, {{3, -1, 2}}}}}, + OutputObjHandlingPolicy::AnalysisObject, + false, + true}; + + int numOfCentBins = 40; + int numOfVertexZBins = 30; + float Vz_low = -10.0f; + float Vz_high = 10.0f; + float Vz_step = (Vz_high - Vz_low) / numOfVertexZBins; + + struct EventRef { + uint64_t collisionId; + }; + + struct PoolBin { + std::deque events; + }; + + std::vector All_Event_pool; + bool isInitialized = false; + + int nPoolBins() const { return numOfVertexZBins * numOfCentBins; } + + void initializePools() + { + All_Event_pool.clear(); + All_Event_pool.resize(nPoolBins()); + isInitialized = true; + } + + int where_pool(float vz, float v0Centr) const + { + float CentBinWidth = 100.0 / numOfCentBins; // = 2.5 + + int iy = static_cast(std::floor(v0Centr / CentBinWidth)); + if (iy < 0) + iy = 0; + if (iy >= numOfCentBins) + iy = numOfCentBins - 1; + + int ix = static_cast(std::floor((vz - Vz_low) / Vz_step)); + if (ix < 0) + ix = 0; + if (ix >= numOfVertexZBins) + ix = numOfVertexZBins - 1; + + int bin = ix + numOfVertexZBins * iy; + return bin; + } + + void init(o2::framework::InitContext&) + { + mZorroSummary.setObject(mZorro.getZorroSummary()); + mRunNumber = 0; + + mCcdb->setURL(settingCcdburl); + mCcdb->setCaching(true); + mCcdb->setLocalObjectValidityChecking(); + mCcdb->setFatalWhenNull(false); + + mFitter.setPropagateToPCA(true); + mFitter.setMaxR(200.); + mFitter.setMinParamChange(1e-3); + mFitter.setMinRelChi2Change(0.9); + mFitter.setMaxDZIni(1e9); + mFitter.setMaxChi2(1e9); + mFitter.setUseAbsDCA(true); + int mat{static_cast(settingMaterialCorrection)}; + mFitter.setMatCorrType(static_cast(mat)); + + const int numParticles = 5; + for (int i = 0; i < numParticles; i++) { + mBBparamsDe[i] = settingBetheBlochParams->get("De", Form("p%i", i)); + } + mBBparamsDe[5] = settingBetheBlochParams->get("De", "resolution"); + + std::vector selectionLabels = {"All", "Track selection", "PID"}; + for (int i = 0; i < Selections::kAll; i++) { + mQaRegistry.get(HIST("hTrackSel"))->GetXaxis()->SetBinLabel(i + 1, selectionLabels[i].c_str()); + } + + std::vector eventsLabels = {"All", "Selected", "Zorro De events"}; + for (int i = 0; i < Selections::kAll; i++) { + mQaRegistry.get(HIST("hEvents"))->GetXaxis()->SetBinLabel(i + 1, eventsLabels[i].c_str()); + } + + mQaRegistry.get(HIST("hEmptyPool"))->GetXaxis()->SetBinLabel(1, "False"); + mQaRegistry.get(HIST("hEmptyPool"))->GetXaxis()->SetBinLabel(2, "True"); + } + + void initCCDB(const aod::BCsWithTimestamps::iterator& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + if (settingSkimmedProcessing) { + mZorro.initCCDB(mCcdb.service, bc.runNumber(), bc.timestamp(), "fDe"); + mZorro.populateHistRegistry(mQaRegistry, bc.runNumber()); + } + mRunNumber = bc.runNumber(); + const float defaultBzValue = -999.0f; + auto run3GrpTimestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = mCcdb->getForTimeStamp(settingGrpPath, run3GrpTimestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + if (settingDbz < defaultBzValue) { + // Fetch magnetic field from ccdb for current collision + mDbz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << mDbz << " kZG"; + } else { + mDbz = settingDbz; + } + } else { + grpmag = mCcdb->getForTimeStamp(settingGrpmagPath, run3GrpTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << settingGrpmagPath << " of object GRPMagField and " << settingGrpPath << " of object GRPObject for timestamp " << run3GrpTimestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + if (settingDbz < defaultBzValue) { + // Fetch magnetic field from ccdb for current collision + mDbz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << mDbz << " kZG"; + } else { + mDbz = settingDbz; + } + } + } + + // ================================================================================================================== + + template + bool selectCollision(const Tcollision& collision, const aod::BCsWithTimestamps&) + { + mQaRegistry.fill(HIST("hEvents"), 0); + + if constexpr (isMC) { + if (/*!collision.sel8() ||*/ std::abs(collision.posZ()) > settingCutVertex) { + return false; + } + } else { + auto bc = collision.template bc_as(); + initCCDB(bc); + + if (!collision.sel8() || std::abs(collision.posZ()) > settingCutVertex) { + return false; + } + if (settingSkimmedProcessing) { + bool zorroSelected = mZorro.isSelected(collision.template bc_as().globalBC()); + if (zorroSelected) { + mQaRegistry.fill(HIST("hEvents"), 2); + } + } + } + + mQaRegistry.fill(HIST("hEvents"), 1); + mQaRegistry.fill(HIST("hNcontributor"), collision.numContrib()); + mQaRegistry.fill(HIST("hVtxZ"), collision.posZ()); + return true; + } + + template + bool selectTrack(const Ttrack& candidate) + { + if (std::abs(candidate.eta()) > settingCutEta) { + return false; + } + const int minTPCNClsFound = 90; + const int minTPCNClsCrossedRows = 100; + const float crossedRowsToFindableRatio = 0.83f; + if (candidate.itsNCls() < settingCutNCls || + candidate.tpcNClsFound() < minTPCNClsFound || + candidate.tpcNClsCrossedRows() < minTPCNClsCrossedRows || + candidate.tpcNClsCrossedRows() < crossedRowsToFindableRatio * candidate.tpcNClsFindable() || + candidate.tpcChi2NCl() > settingCutChi2tpcHigh || + candidate.tpcChi2NCl() < settingCutChi2tpcLow || + candidate.itsChi2NCl() > settingCutChi2NClITS) { + return false; + } + + return true; + } + + template + bool selectionPIDPion(const Ttrack& candidate) + { + if (candidate.tpcChi2NCl() > settingCutChi2tpcHighPion || candidate.tpcChi2NCl() < settingCutChi2tpcLowPion || candidate.itsChi2NCl() > settingCutChi2NClITSPion) + return false; + if (abs(candidate.dcaXY()) > settingCutPiDCAxyMin || abs(candidate.dcaZ()) > settingCutPiDCAzMin) + return false; + + auto tpcNSigmaPi = candidate.tpcNSigmaPi(); + mQaRegistry.fill(HIST("h2NsigmaPiTPC_preselection"), candidate.tpcInnerParam(), tpcNSigmaPi); + if (std::abs(candidate.pt()) < settingCutPiptMin || std::abs(candidate.pt()) > settingCutPiptMax) + return false; + // reject protons + if (std::abs(candidate.tpcNSigmaPr()) < settingCutNsigTPCPrMin) + return false; + mQaRegistry.fill(HIST("h2NsigmaPiPrTPC"), candidate.tpcNSigmaPr()); + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < settingCutNsigTOFPrMin) + return false; + mQaRegistry.fill(HIST("h2NsigmaPiPrTOF"), candidate.tofNSigmaPr()); + + if (candidate.hasTOF() && candidate.tpcInnerParam() >= settingCutPinMinTOFPi) { + auto tofNSigmaPi = candidate.tofNSigmaPi(); + auto combNsigma = std::sqrt(tofNSigmaPi * tofNSigmaPi + tpcNSigmaPi * tpcNSigmaPi); + + mQaRegistry.fill(HIST("h2NsigmaPiTOF_preselection"), candidate.pt(), tofNSigmaPi); + if (combNsigma > settingCutNsigmaTOFTPCPi) { + return false; + } + mQaRegistry.fill(HIST("h2NsigmaPiTPC"), candidate.sign() * candidate.pt(), tpcNSigmaPi); + mQaRegistry.fill(HIST("h2NsigmaPiTOF"), candidate.sign() * candidate.pt(), tofNSigmaPi); + mQaRegistry.fill(HIST("h2NsigmaPiComb"), candidate.sign() * candidate.pt(), combNsigma); + return true; + } else if (candidate.tpcInnerParam() < settingCutPinMinTOFPi) { + if (std::abs(tpcNSigmaPi) > settingCutNsigmaTPCPi) { + return false; + } + mQaRegistry.fill(HIST("h2NsigmaPiTPC"), candidate.sign() * candidate.pt(), tpcNSigmaPi); + return true; + } + return false; + } + + template + float computeNSigmaDe(const Ttrack& candidate) + { + float expTPCSignal = o2::tpc::BetheBlochAleph(static_cast(candidate.tpcInnerParam() / constants::physics::MassDeuteron), mBBparamsDe[0], mBBparamsDe[1], mBBparamsDe[2], mBBparamsDe[3], mBBparamsDe[4]); + double resoTPC{expTPCSignal * mBBparamsDe[5]}; + return static_cast((candidate.tpcSignal() - expTPCSignal) / resoTPC); + } + + template + bool selectionPIDDe(const Ttrack& candidate) + { + float tpcInnerParam = candidate.tpcInnerParam(); + mQaRegistry.fill(HIST("h2dEdx"), candidate.sign() * tpcInnerParam, candidate.tpcSignal()); + + float DeDCAxyMin = 0.015 + 0.0305 / TMath::Power(candidate.pt(), 1.1); + if (abs(candidate.dcaXY()) > DeDCAxyMin || abs(candidate.dcaXY()) > settingCutDeDCAzMin) + return false; + + if (std::abs(tpcInnerParam) < settingCutPinMinDe) { + return false; + } + float tpcNSigmaDe; + if (settingUseBBcomputeDeNsigma) { + tpcNSigmaDe = computeNSigmaDe(candidate); + } else { + tpcNSigmaDe = candidate.tpcNSigmaDe(); + } + + mQaRegistry.fill(HIST("h2NsigmaNuTPC_preselection"), candidate.sign() * candidate.pt(), tpcNSigmaDe); + mQaRegistry.fill(HIST("h2NsigmaNuTPC_preselecComp"), candidate.sign() * candidate.pt(), candidate.tpcNSigmaDe()); + if (std::abs(candidate.pt()) < settingCutDeptMin || std::abs(candidate.pt()) > settingCutDeptMax) + return false; + if (candidate.hasTOF() && candidate.tpcInnerParam() > settingCutPinMinTOFITSDe) { + auto tofNSigmaDe = candidate.tofNSigmaDe(); + auto combNsigma = std::sqrt(tofNSigmaDe * tofNSigmaDe + tpcNSigmaDe * tpcNSigmaDe); + if (combNsigma > settingCutNsigmaTOFTPCDe) { + return false; + } + mQaRegistry.fill(HIST("h2dEdxNucandidates"), candidate.sign() * tpcInnerParam, candidate.tpcSignal()); + mQaRegistry.fill(HIST("h2NsigmaNuComb"), candidate.sign() * candidate.pt(), combNsigma); + mQaRegistry.fill(HIST("h2NsigmaNuTPC"), candidate.sign() * candidate.pt(), tpcNSigmaDe); + mQaRegistry.fill(HIST("h2NsigmaNuTOF"), candidate.sign() * candidate.pt(), tofNSigmaDe); + return true; + } else if (candidate.tpcInnerParam() <= settingCutPinMinTOFITSDe) { + if (std::abs(tpcNSigmaDe) > settingCutNsigmaTPCDe) { + return false; + } + o2::aod::ITSResponse mResponseITS; + auto itsnSigmaDe = mResponseITS.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + mQaRegistry.fill(HIST("h2NSigmaNuITS_preselection"), candidate.sign() * candidate.pt(), itsnSigmaDe); + if (std::abs(itsnSigmaDe) > settingCutNsigmaITSDe) { + return false; + } + mQaRegistry.fill(HIST("h2NsigmaNuTPC"), candidate.sign() * candidate.pt(), tpcNSigmaDe); + mQaRegistry.fill(HIST("h2NSigmaNuITS"), candidate.sign() * candidate.pt(), itsnSigmaDe); + // mQaRegistry.fill(HIST("h2NsigmaNuComb"), candidate.sign() * candidate.pt(), combNsigma); + mQaRegistry.fill(HIST("h2dEdxNucandidates"), candidate.sign() * tpcInnerParam, candidate.tpcSignal()); + return true; + } + return false; + } + + float averageClusterSizeCosl(uint32_t itsClusterSizes, float eta) + { + float average = 0; + int nclusters = 0; + const float cosl = 1. / std::cosh(eta); + const int nlayerITS = 7; + + for (int layer = 0; layer < nlayerITS; layer++) { + if ((itsClusterSizes >> (layer * 4)) & 0xf) { + nclusters++; + average += (itsClusterSizes >> (layer * 4)) & 0xf; + } + } + if (nclusters == 0) { + return 0; + } + return average * cosl / nclusters; + }; + + bool selectionPIDHyper(const aod::DataHypCandsWColl::iterator& V0Hyper) + { + mQaRegistry.fill(HIST("hHe3P_preselected"), V0Hyper.tpcMomHe()); + float averClusSizeHe = averageClusterSizeCosl(V0Hyper.itsClusterSizesHe(), V0Hyper.etaHe3()); + if (averClusSizeHe <= settingCutAverClsSizeHe) { + return false; + } + if (V0Hyper.tpcChi2He() <= settingCutTPCChi2He) { + return false; + } + mQaRegistry.fill(HIST("hHe3P"), V0Hyper.tpcMomHe()); + mQaRegistry.fill(HIST("hHe3TPCnsigma"), V0Hyper.ptHe3(), V0Hyper.nSigmaHe()); + + return true; + } + + // ================================================================================================================== + + template + bool fillCandidateInfo(const Ttrack& trackDe, const Ttrack& trackPi, const CollBracket& collBracket, const Tcollisions& collisions, PiNucandidate& piNucand, const Ttracks& /*trackTable*/, bool isMixedEvent) + { + const int numCoordinates = 3; + if (!isMixedEvent) { + auto trackCovDe = getTrackParCov(trackDe); + auto trackCovPi = getTrackParCov(trackPi); + int nCand = 0; + try { + nCand = mFitter.process(trackCovDe, trackCovPi); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + mQaRegistry.fill(HIST("hSkipReasons"), 0); + return false; + } + if (nCand == 0) { + mQaRegistry.fill(HIST("hSkipReasons"), 1); + 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 = mFitter.getPCACandidate(); + float distance = 0; + for (int i = 0; i < numCoordinates; i++) { + distance += (pca[i] - collVtx[i]) * (pca[i] - collVtx[i]); + } + if (distanceMin < 0 || distance < distanceMin) { + distanceMin = distance; + collIdxMin = collIdx; + } + } + + if (!mGoodCollisions[collIdxMin]) { + mQaRegistry.fill(HIST("hSkipReasons"), 2); + return false; + } + piNucand.collisionID = collIdxMin; + } else { + piNucand.collisionID = collBracket.getMin(); + } + + piNucand.momNu = std::array{trackDe.px(), trackDe.py(), trackDe.pz()}; + piNucand.momPi = std::array{trackPi.px(), trackPi.py(), trackPi.pz()}; + float invMass = 0; + invMass = RecoDecay::m(std::array{piNucand.momNu, piNucand.momPi}, std::array{o2::constants::physics::MassDeuteron, o2::constants::physics::MassPiPlus}); + if (settingCutInvMass > 0 && invMass > settingCutInvMass) { + mQaRegistry.fill(HIST("hSkipReasons"), 3); + return false; + } + float ptDePi = std::hypot(piNucand.momNu[0] + piNucand.momPi[0], piNucand.momNu[1] + piNucand.momPi[1]); + if (ptDePi < settingCutPtMinDePi) { + mQaRegistry.fill(HIST("hSkipReasons"), 4); + return false; + } + + piNucand.signNu = trackDe.sign(); + piNucand.signPi = trackPi.sign(); + + piNucand.dcaxyNu = trackDe.dcaXY(); + piNucand.dcaxyPi = trackPi.dcaXY(); + + piNucand.dcazNu = trackDe.dcaZ(); + piNucand.dcazPi = trackPi.dcaZ(); + + piNucand.tpcSignalNu = trackDe.tpcSignal(); + piNucand.momNuTPC = trackDe.tpcInnerParam(); + piNucand.tpcSignalPi = trackPi.tpcSignal(); + piNucand.momPiTPC = trackPi.tpcInnerParam(); + + piNucand.nTPCClustersNu = trackDe.tpcNClsFound(); + piNucand.nSigmaNu = computeNSigmaDe(trackDe); + piNucand.nSigmaPi = trackPi.tpcNSigmaPi(); + + piNucand.chi2TPCNu = trackDe.tpcChi2NCl(); + piNucand.chi2TPCPi = trackPi.tpcChi2NCl(); + + piNucand.pidTrkNu = trackDe.pidForTracking(); + piNucand.pidTrkPi = trackPi.pidForTracking(); + + piNucand.itsClSizeNu = trackDe.itsClusterSizes(); + piNucand.itsClSizePi = trackPi.itsClusterSizes(); + + piNucand.nClsItsNu = trackDe.itsNCls(); + piNucand.nClsItsPi = trackPi.itsNCls(); + + piNucand.sharedClustersNu = trackDe.tpcNClsShared(); + piNucand.sharedClustersPi = trackPi.tpcNClsShared(); + + piNucand.isBkgUS = trackDe.sign() * trackPi.sign() < 0; + piNucand.isBkgEM = isMixedEvent; + + piNucand.invMass = invMass; + + piNucand.trackIDNu = trackDe.globalIndex(); + piNucand.trackIDPi = trackPi.globalIndex(); + + if (trackDe.hasTOF()) { + float beta = o2::pid::tof::Beta::GetBeta(trackDe); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + float tpcInnerParamDe = trackDe.tpcInnerParam(); + piNucand.massTOFNu = tpcInnerParamDe * std::sqrt(1.f / (beta * beta) - 1.f); + } + if (trackPi.hasTOF()) { + float beta = o2::pid::tof::Beta::GetBeta(trackPi); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + piNucand.massTOFPi = trackPi.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); + } + + piNucand.kstar = o2::analysis::femtoWorld::FemtoWorldMath::getkstar(trackPi, o2::constants::physics::MassPiPlus, trackDe, o2::constants::physics::MassDeuteron); + piNucand.mT = o2::analysis::femtoWorld::FemtoWorldMath::getmT(trackPi, o2::constants::physics::MassPiPlus, trackDe, o2::constants::physics::MassDeuteron); + + return true; + } + + template + bool fillCandidateInfoHyper(const aod::DataHypCandsWColl::iterator& V0Hyper, const Ttrack& trackPi, PiNucandidate& piHypercand, bool isMixedEvent) + { + piHypercand.collisionID = V0Hyper.collisionId(); + // get hypertriton information + // constexpr double mHe3 = o2::constants::physics::MassHelium3; + // constexpr double mPi = o2::constants::physics::MassPiPlus; + // --- He3 + float pxHe3 = V0Hyper.ptHe3() * std::cos(V0Hyper.phiHe3()); + float pyHe3 = V0Hyper.ptHe3() * std::sin(V0Hyper.phiHe3()); + float pzHe3 = V0Hyper.ptHe3() * std::sinh(V0Hyper.etaHe3()); + // float pHe3 = V0Hyper.ptHe3() * std::cosh(V0Hyper.etaHe3()); + // float enHe3 = std::sqrt(pHe3 * pHe3 + mHe3 * mHe3); + // --- pi + float pxPi = V0Hyper.ptPi() * std::cos(V0Hyper.phiPi()); + float pyPi = V0Hyper.ptPi() * std::sin(V0Hyper.phiPi()); + float pzPi = V0Hyper.ptPi() * std::sinh(V0Hyper.etaPi()); + // float pPi = V0Hyper.ptPi() * std::cosh(V0Hyper.etaPi()); + // float enPi = std::sqrt(pPi * pPi + mPi * mPi); + // --- hypertriton + float px = pxHe3 + pxPi; + float py = pyHe3 + pyPi; + float pz = pzHe3 + pzPi; + piHypercand.momNu = std::array{px, py, pz}; + piHypercand.momPi = std::array{trackPi.px(), trackPi.py(), trackPi.pz()}; + + float invMass = 0; + invMass = RecoDecay::m(std::array{piHypercand.momNu, piHypercand.momPi}, std::array{o2::constants::physics::MassHelium3, o2::constants::physics::MassPiPlus}); + if (settingCutInvMass > 0 && invMass > settingCutInvMass) { + return false; + } + + piHypercand.signPi = trackPi.sign(); + if (V0Hyper.isMatter()) { + piHypercand.signNu = 1; + } else { + piHypercand.signNu = -1; + } + piHypercand.etaHe3 = V0Hyper.etaHe3(); + piHypercand.ptHe3 = V0Hyper.ptHe3(); + piHypercand.dcaxyPi = trackPi.dcaXY(); + piHypercand.dcazPi = trackPi.dcaZ(); + piHypercand.tpcSignalPi = trackPi.tpcSignal(); + piHypercand.tpcSignalNu = V0Hyper.tpcSignalHe(); + piHypercand.momPiTPC = trackPi.tpcInnerParam(); + piHypercand.nSigmaPi = trackPi.tpcNSigmaPi(); + piHypercand.nSigmaNu = V0Hyper.nSigmaHe(); + piHypercand.chi2TPCPi = trackPi.tpcChi2NCl(); + piHypercand.chi2TPCNu = V0Hyper.tpcChi2He(); + piHypercand.pidTrkPi = trackPi.pidForTracking(); + piHypercand.itsClSizePi = trackPi.itsClusterSizes(); + piHypercand.itsClSizeNu = V0Hyper.itsClusterSizesHe(); + piHypercand.nClsItsPi = trackPi.itsNCls(); + piHypercand.sharedClustersPi = trackPi.tpcNClsShared(); + + piHypercand.isBkgUS = piHypercand.signNu * trackPi.sign() < 0; + piHypercand.isBkgEM = isMixedEvent; + piHypercand.invMass = invMass; + + piHypercand.trackIDPi = trackPi.globalIndex(); + + if (trackPi.hasTOF()) { + float beta = o2::pid::tof::Beta::GetBeta(trackPi); + beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + piHypercand.massTOFPi = trackPi.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); + } + return true; + } + + template + void pairTracksSameEvent(const Ttrack& tracks, float cent) + { + bool filledAllOnce = false; + // LOG(info) << "Number of tracks: " << tracks.size(); + for (const auto& track0 : tracks) { + + mQaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); + + if (!selectTrack(track0)) { + continue; + } + mQaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); + + if (!selectionPIDDe(track0)) { + continue; + } + mQaRegistry.fill(HIST("hTrackSel"), Selections::kPID); + mQaRegistry.fill(HIST("hSingleNuPt"), track0.pt() * track0.sign()); + mQaRegistry.fill(HIST("hCollIDVsCentEachDe"), track0.collisionId(), cent); + + for (const auto& track1 : tracks) { + if (track0 == track1) { + continue; + } + + if (!settingSaveUSandLS) { + if (!settingEnableBkgUS && (track0.sign() * track1.sign() < 0)) { + continue; + } + if (settingEnableBkgUS && (track0.sign() * track1.sign() > 0)) { + continue; + } + } + + if (!selectTrack(track1) || !selectionPIDPion(track1)) { + continue; + } + + if (!filledAllOnce) { + mQaRegistry.fill(HIST("hCollIDVsCentEachPion"), track1.collisionId(), cent); + mQaRegistry.fill(HIST("hSinglePiPt"), track1.pt() * track1.sign()); + } + + SVCand trackPair; + trackPair.tr0Idx = track0.globalIndex(); + trackPair.tr1Idx = track1.globalIndex(); + const int collIdx = track0.collisionId(); + CollBracket collBracket{collIdx, collIdx}; + trackPair.collBracket = collBracket; + mTrackPairs.push_back(trackPair); + } + filledAllOnce = true; + } + } + + template + void pairTracksSameEventHyper(const Ttrack& piTracks, const Thypers& V0Hypers) + { + for (const auto& V0Hyper : V0Hypers) { + if (!selectionPIDHyper(V0Hyper)) { + continue; + } + for (const auto& piTrack : piTracks) { + + mQaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); + + if (!selectTrack(piTrack)) { + continue; + } + mQaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); + + if (!selectionPIDPion(piTrack)) { + continue; + } + mQaRegistry.fill(HIST("hTrackSel"), Selections::kPID); + + SVCand pair; + pair.tr0Idx = V0Hyper.globalIndex(); + pair.tr1Idx = piTrack.globalIndex(); + const int collIdx = V0Hyper.collisionId(); + CollBracket collBracket{collIdx, collIdx}; + pair.collBracket = collBracket; + mTrackHypPairs.push_back(pair); + } + } + } + + template + void pairTracksEventMixing(T& DeCands, T& pionCands) + { + for (const auto& DeCand : DeCands) { + if (!selectTrack(DeCand) || !selectionPIDDe(DeCand)) { + continue; + } + for (const auto& pionCand : pionCands) { + if (!selectTrack(pionCand) || !selectionPIDPion(pionCand)) { + continue; + } + + SVCand trackPair; + trackPair.tr0Idx = DeCand.globalIndex(); + trackPair.tr1Idx = pionCand.globalIndex(); + const int collIdx = DeCand.collisionId(); + CollBracket collBracket{collIdx, collIdx}; + trackPair.collBracket = collBracket; + mTrackPairs.push_back(trackPair); + } + } + } + + template + void pairHyperEventMixing(T1& pionCands, T2& hypCands) + { + for (const auto& hypCand : hypCands) { + if (!selectionPIDHyper(hypCand)) { + continue; + } + for (const auto& pionCand : pionCands) { + if (!selectTrack(pionCand) || !selectionPIDPion(pionCand)) { + continue; + } + + SVCand pair; + pair.tr0Idx = hypCand.globalIndex(); + pair.tr1Idx = pionCand.globalIndex(); + const int collIdx = hypCand.collisionId(); + CollBracket collBracket{collIdx, collIdx}; + pair.collBracket = collBracket; + mTrackHypPairs.push_back(pair); + } + } + } + + template + void fillTable(const PiNucandidate& piNucand, const Tcoll& collision) + { + mOutputDataTable( + piNucand.trackIDPi, + piNucand.trackIDNu); + if (settingFillMultiplicity) { + mOutputMultiplicityTable( + collision.globalIndex(), + collision.posZ(), + collision.numContrib(), + collision.centFT0C(), + collision.multFT0C()); + } + } + + template + void fillTableHyper(const PiNucandidate& piNucand, const Tcoll& collision) + { + mOutputHyperDataTable( + piNucand.recoPtNu(), + piNucand.recoEtaNu(), + piNucand.ptHe3, + piNucand.etaHe3, + piNucand.recoPhiNu(), + piNucand.recoPtPi(), + piNucand.recoEtaPi(), + piNucand.recoPhiPi(), + piNucand.dcaxyPi, + piNucand.dcazPi, + piNucand.tpcSignalPi, + piNucand.tpcSignalNu, + piNucand.momPiTPC, + piNucand.nSigmaPi, + piNucand.nSigmaNu, + piNucand.chi2TPCPi, + piNucand.chi2TPCNu, + piNucand.massTOFPi, + piNucand.pidTrkPi, + piNucand.itsClSizePi, + piNucand.itsClSizeNu, + piNucand.sharedClustersPi, + piNucand.trackIDPi, + piNucand.isBkgUS, + piNucand.isBkgEM); + if (settingFillMultiplicity) { + mOutputMultiplicityTable( + collision.globalIndex(), + collision.posZ(), + collision.numContrib(), + collision.centFT0C(), + collision.multFT0C()); + } + } + + void fillHistograms(const PiNucandidate& piNucand) + { + mQaRegistry.fill(HIST("hNuPt"), piNucand.recoPtNu()); + mQaRegistry.fill(HIST("hPiPt"), piNucand.recoPtPi()); + mQaRegistry.fill(HIST("hNuEta"), piNucand.recoEtaNu()); + mQaRegistry.fill(HIST("hPiEta"), piNucand.recoEtaPi()); + mQaRegistry.fill(HIST("hNuPhi"), piNucand.recoPhiNu()); + mQaRegistry.fill(HIST("hPiPhi"), piNucand.recoPhiPi()); + mQaRegistry.fill(HIST("hNuPitInvMass"), piNucand.invMass); + mQaRegistry.fill(HIST("hdcaxyNu"), piNucand.dcaxyNu); + mQaRegistry.fill(HIST("hdcazNu"), piNucand.dcazNu); + mQaRegistry.fill(HIST("hdcazNu_min"), (abs(piNucand.dcazNu) - settingCutDeDCAzMin)); + mQaRegistry.fill(HIST("hNClsNuITS"), piNucand.nClsItsNu); + mQaRegistry.fill(HIST("hNClsPiITS"), piNucand.nClsItsPi); + mQaRegistry.fill(HIST("hisBkgEM"), piNucand.isBkgEM); + } + + template + void fillKstar(const PiNucandidate& piNucand, const Tcoll& collision) + { + if (piNucand.isBkgUS == 0) { + if (piNucand.recoPtNu() > 0) { + mQaRegistry.fill(HIST("hkStar_LS_M"), piNucand.kstar); + mQaRegistry.fill(HIST("hkStaVsmTVsCent_LS_M"), piNucand.kstar, piNucand.mT, collision.centFT0C()); + mQaRegistry.fill(HIST("hkStaVsmT_LS_M"), piNucand.kstar, piNucand.mT); + } else { + mQaRegistry.fill(HIST("hkStar_LS_A"), piNucand.kstar); + mQaRegistry.fill(HIST("hkStaVsmTVsCent_LS_A"), piNucand.kstar, piNucand.mT, collision.centFT0C()); + mQaRegistry.fill(HIST("hkStaVsmT_LS_A"), piNucand.kstar, piNucand.mT); + } + } else { + if (piNucand.recoPtNu() > 0) { + mQaRegistry.fill(HIST("hkStar_US_M"), piNucand.kstar); + mQaRegistry.fill(HIST("hkStaVsmTVsCent_US_M"), piNucand.kstar, piNucand.mT, collision.centFT0C()); + mQaRegistry.fill(HIST("hkStaVsmT_US_M"), piNucand.kstar, piNucand.mT); + } else { + mQaRegistry.fill(HIST("hkStar_US_A"), piNucand.kstar); + mQaRegistry.fill(HIST("hkStaVsmTVsCent_US_A"), piNucand.kstar, piNucand.mT, collision.centFT0C()); + mQaRegistry.fill(HIST("hkStaVsmT_US_A"), piNucand.kstar, piNucand.mT); + } + } + } + + // ================================================================================================================== + + template + void fillPairs(const Tcollisions& collisions, const Ttracks& tracks, const bool isMixedEvent) + { + for (const auto& trackPair : mTrackPairs) { + + auto deTrack = tracks.rawIteratorAt(trackPair.tr0Idx); + auto piTrack = tracks.rawIteratorAt(trackPair.tr1Idx); + auto collBracket = trackPair.collBracket; + + PiNucandidate piNucand; + if (!fillCandidateInfo(deTrack, piTrack, collBracket, collisions, piNucand, tracks, isMixedEvent)) { + continue; + } + + auto collision = collisions.rawIteratorAt(piNucand.collisionID); + fillKstar(piNucand, collision); + fillHistograms(piNucand); + + if (settingFillTable) { + fillTable(piNucand, collision); + } + } + } + + template + void fillPairsHyper(const Tcollisions& collisions, const Ttracks& piTracks, const o2::aod::DataHypCandsWColl& V0Hypers, const bool isMixedEvent) + { + for (const auto& trackPair : mTrackHypPairs) { + + auto v0hyper = V0Hypers.rawIteratorAt(trackPair.tr0Idx); + auto piTrack = piTracks.rawIteratorAt(trackPair.tr1Idx); + // auto collBracket = trackPair.collBracket; + + PiNucandidate piNucand; + if (!fillCandidateInfoHyper(v0hyper, piTrack, piNucand, isMixedEvent)) { + continue; + } + + mQaRegistry.fill(HIST("hNuPt"), piNucand.recoPtNu()); + mQaRegistry.fill(HIST("hPiPt"), piNucand.recoPtPi()); + mQaRegistry.fill(HIST("hNuEta"), piNucand.recoEtaNu()); + mQaRegistry.fill(HIST("hPiEta"), piNucand.recoEtaPi()); + mQaRegistry.fill(HIST("hNuPhi"), piNucand.recoPhiNu()); + mQaRegistry.fill(HIST("hPiPhi"), piNucand.recoPhiPi()); + mQaRegistry.fill(HIST("hNuPitInvMass"), piNucand.invMass); + mQaRegistry.fill(HIST("hNClsPiITS"), piNucand.nClsItsPi); + mQaRegistry.fill(HIST("hisBkgEM"), piNucand.isBkgEM); + + auto collision = collisions.rawIteratorAt(piNucand.collisionID); + + if (settingFillTable) { + fillTableHyper(piNucand, collision); + } + } + } + + // ================================================================================================================== + + void processSameEvent(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::BCsWithTimestamps& bcs) + { + mGoodCollisions.clear(); + mGoodCollisions.resize(collisions.size(), false); + + for (const auto& collision : collisions) { + + mTrackPairs.clear(); + + if (!selectCollision(collision, bcs)) { + continue; + } + + mGoodCollisions[collision.globalIndex()] = true; + const uint64_t collIdx = collision.globalIndex(); + auto trackTableThisCollision = tracks.sliceBy(mPerCol, collIdx); + trackTableThisCollision.bindExternalIndices(&tracks); + + pairTracksSameEvent(trackTableThisCollision, collision.centFT0C()); + + if (mTrackPairs.size() == 0) { + continue; + } + + fillPairs(collisions, tracks, /*isMixedEvent*/ false); + } + } + PROCESS_SWITCH(PiNucleiFemto, processSameEvent, "Process Same event", false); + + void processSameEventHyper(const CollisionsFull& collisions, const TrackCandidates& pitracks, o2::aod::DataHypCandsWColl const& V0Hypers, const aod::BCsWithTimestamps& bcs) + { + mGoodCollisions.clear(); + mGoodCollisions.resize(collisions.size(), false); + // LOG(info) << "Number of hyperCandidates read = " << V0Hypers.size(); + + for (const auto& collision : collisions) { + + mTrackHypPairs.clear(); + + if (!selectCollision(collision, bcs)) { + continue; + } + + mGoodCollisions[collision.globalIndex()] = true; + const uint64_t collIdx = collision.globalIndex(); + auto trackTableThisCollision = pitracks.sliceBy(mPerCol, collIdx); + auto hypdTableThisCollision = V0Hypers.sliceBy(hypPerCol, collIdx); + trackTableThisCollision.bindExternalIndices(&pitracks); + hypdTableThisCollision.bindExternalIndices(&V0Hypers); + + pairTracksSameEventHyper(trackTableThisCollision, hypdTableThisCollision); + + if (mTrackHypPairs.size() == 0) { + continue; + } + + fillPairsHyper(collisions, pitracks, V0Hypers, /*isMixedEvent*/ false); + } + } + PROCESS_SWITCH(PiNucleiFemto, processSameEventHyper, "Process Same event", false); + + void processMixedEvent(const CollisionsFull& collisions, const TrackCandidates& tracks) + { + LOG(debug) << "Processing mixed event"; + mTrackPairs.clear(); + + for (const auto& [c1, tracks1, c2, tracks2] : mPair) { + if (!c1.sel8() || !c2.sel8()) { + continue; + } + + mQaRegistry.fill(HIST("hNcontributor"), c1.numContrib()); + mQaRegistry.fill(HIST("hVtxZ"), c1.posZ()); + + pairTracksEventMixing(tracks1, tracks2); + pairTracksEventMixing(tracks2, tracks1); + } + + fillPairs(collisions, tracks, /*isMixedEvent*/ true); + } + PROCESS_SWITCH(PiNucleiFemto, processMixedEvent, "Process Mixed event", false); + + /*void processMixedEventHyper(const CollisionsFull& collisions, o2::aod::DataHypCandsWColl const& V0Hypers, const TrackCandidates& pitracks) + { + LOG(debug) << "Processing mixed event for hypertriton"; + mTrackHypPairs.clear(); + + for (const auto& [c1, tracks1, c2, V0Hypers2] : hyperPair) { + if (!c1.sel8() || !c2.sel8()) { + continue; + } + + mQaRegistry.fill(HIST("hNcontributor"), c2.numContrib()); + //mQaRegistry.fill(HIST("hCentrality"), c2.centFT0C()); + mQaRegistry.fill(HIST("hVtxZ"), c2.posZ()); + + pairHyperEventMixing(tracks1, V0Hypers2); + } +} +PROCESS_SWITCH(PiNucleiFemto, processMixedEventHyper, "Process Mixed event", false);*/ + + void processMixedEventHyperPool(const CollisionsFull& collisions, o2::aod::DataHypCandsWColl const& V0Hypers, const TrackCandidates& pitracks) + { + mTrackHypPairs.clear(); + if (!isInitialized) { + initializePools(); + LOG(info) << "Initialized event pool with size = " << All_Event_pool.size(); + } + for (auto const& collision : collisions) { + if (!collision.sel8()) { + mQaRegistry.fill(HIST("hSkipReasons"), 0); + continue; + } + mQaRegistry.fill(HIST("hNcontributor"), collision.numContrib()); + mQaRegistry.fill(HIST("hCentrality"), collision.centFT0C()); + mQaRegistry.fill(HIST("hVtxZ"), collision.posZ()); + + int poolIndexPi = where_pool(collision.posZ(), collision.centFT0C()); + if (poolIndexPi < 0 || static_cast(poolIndexPi) >= All_Event_pool.size()) { + continue; + } + auto& pool = All_Event_pool[poolIndexPi]; + + const uint64_t collIdxPi = collision.globalIndex(); + auto trackTableThisCollision = pitracks.sliceBy(mPerCol, collIdxPi); + trackTableThisCollision.bindExternalIndices(&pitracks); + + for (auto const& storedEvent : pool.events) { + const uint64_t collIdxHyp = storedEvent.collisionId; + if (settingSaferME) { + if (static_cast(collIdxHyp) > collisions.size()) { + mQaRegistry.fill(HIST("hSkipReasons"), 4); + continue; + } + } + + auto hypdTablepreviousCollision = V0Hypers.sliceBy(hypPerCol, collIdxHyp); + hypdTablepreviousCollision.bindExternalIndices(&V0Hypers); + if (hypdTablepreviousCollision.size() == 0) { + mQaRegistry.fill(HIST("hSkipReasons"), 1); + continue; + } + + auto firstHyp = hypdTablepreviousCollision.iteratorAt(0); + int poolIndexHyp = where_pool(firstHyp.zPrimVtx(), firstHyp.centralityFT0C()); + if (poolIndexHyp != poolIndexPi) { + mQaRegistry.fill(HIST("hSkipReasons"), 2); + continue; + } + mQaRegistry.fill(HIST("hNHypsPerPrevColl"), collIdxHyp, hypdTablepreviousCollision.size()); + + pairHyperEventMixing(trackTableThisCollision, hypdTablepreviousCollision); + } + + if (static_cast(pool.events.size()) >= settingNoMixedEvents) { + pool.events.pop_front(); + } + pool.events.push_back({collIdxPi}); + } + fillPairsHyper(collisions, pitracks, V0Hypers, /*isMixedEvent*/ true); + } + PROCESS_SWITCH(PiNucleiFemto, processMixedEventHyperPool, "Process Mixed event", false); +}; + +WorkflowSpec defineDataProcessing(const ConfigContext& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Femto/Macros/cutculator.py b/PWGCF/Femto/Macros/cutculator.py new file mode 100755 index 00000000000..c1c6a4bf9e3 --- /dev/null +++ b/PWGCF/Femto/Macros/cutculator.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 + +# 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. + +"""! +@brief CutCulator (Compute bitmask for selecting particles in the Femto Framework) +@author Anton Riedel , Technical University of Munich +""" + +import ROOT +import argparse + +VALUE_DELIM = "___" +SECTION_DELIM = ":::" + + +def parse_bin_label(label): + """Parse a bin label into a dictionary.""" + result = {} + sections = label.split(SECTION_DELIM) + for sec in sections: + if VALUE_DELIM not in sec: + continue + key, value = sec.split(VALUE_DELIM, 1) + result[key] = value + return result + + +def format_value_with_comment(b): + """Return Value plus optional (comment=...) suffix.""" + val = b.get("Value", "") + comment = b.get("Comment", "") + if comment and comment.upper() != "X": + return f"{val} (comment={comment})" + return val + + +def ask_user_selection(group): + """ + Prompt user to select bin(s) for this selection group. + - If minimal selections contain exactly 1 entry → auto-select it. + - Optional selections remain user-selectable. + """ + selection_name = group[0].get("SelectionName", "unknown") + + # Separate minimal and optional bins + minimal_bins = [b for b in group if b.get("MinimalCut", "0") == "1" and b.get("OptionalCut", "0") == "0"] + optional_bins = [b for b in group if b.get("OptionalCut", "0") == "1"] + + selected_bins = [] + + # ----- Minimal selection ----- + if minimal_bins: + if len(minimal_bins) == 1: + only = minimal_bins[0] + print( + f"\nSelection: {selection_name} — only one minimal option → auto-selecting: " + f"{format_value_with_comment(only)}" + ) + selected_bins.append(only) + else: + print(f"\nSelection: {selection_name}") + for idx, b in enumerate(minimal_bins): + print(f" [{idx}] {format_value_with_comment(b)}") + while True: + sel_input = input("Enter index for minimal cut (0 = loosest minimal): ") + if sel_input.strip() == "": + sel_input = "0" + try: + sel_idx = int(sel_input) + if 0 <= sel_idx < len(minimal_bins): + choice = minimal_bins[sel_idx] + selected_bins.append(choice) + print(f"Selected: {format_value_with_comment(choice)}") + break + except ValueError: + pass + print("Invalid input. Please enter a valid index.") + + # ----- Optional selection ----- + if optional_bins: + print(f"\nSelection: {selection_name} (optional selection, 0 to skip)") + for idx, b in enumerate(optional_bins, start=1): + print(f" [{idx}] {format_value_with_comment(b)}") + + while True: + sel_input = input("Enter indices separated by space (0 to skip): ") + if not sel_input.strip() or sel_input.strip() == "0": + print("Selected: (skipped)") + break + + try: + indices = [int(x) for x in sel_input.split()] + if all(0 <= i <= len(optional_bins) for i in indices): + chosen = [] + for i in indices: + if i != 0: + b = optional_bins[i - 1] + selected_bins.append(b) + chosen.append(format_value_with_comment(b)) + + print("Selected: " + ", ".join(chosen)) + break + except ValueError: + pass + + print("Invalid input. Please enter valid indices separated by space.") + + return selected_bins + + +def main(rootfile_path, tdir_path="femto-producer"): + print(f"Opening ROOT file: {rootfile_path}") + f = ROOT.TFile.Open(rootfile_path) + if not f: + print("Cannot open ROOT file") + return + + print(f"Accessing directory: {tdir_path}") + d = f.Get(tdir_path) + if not d: + print(f"Cannot access directory {tdir_path}") + return + + histograms = [k.GetName() for k in d.GetListOfKeys() if k.ReadObj().InheritsFrom("TH1")] + if not histograms: + print("No histograms found") + return + + print("\nHistograms found in directory:") + for i, hname in enumerate(histograms): + print(f" [{i}] {hname}") + hidx = int(input("\nSelect histogram index: ")) + hname = histograms[hidx] + hist = d.Get(hname) + nbins = hist.GetNbinsX() + print(f"\nUsing histogram: {hname}") + print(f"Histogram contains {nbins} bins.\n") + + # parse all bins, ignoring the last 2 special bins + bins = [] + for i in range(1, nbins - 2 + 1): + label = hist.GetXaxis().GetBinLabel(i) + if not label: + continue + bdict = parse_bin_label(label) + bdict["_bin_index"] = i + bins.append(bdict) + + # group by SelectionName + groups = {} + for b in bins: + sel_name = b.get("SelectionName", f"unknown_{b['_bin_index']}") + groups.setdefault(sel_name, []).append(b) + + selected_bins = [] + + for group in groups.values(): + res = ask_user_selection(group) + if res: + selected_bins.extend(res) + + # compute bitmask from selected bins + bitmask = 0 + for b in selected_bins: + pos = b.get("BitPosition", "") + if pos.upper() == "X": + continue + bitmask |= 1 << int(pos) + + print("\n=======================================") + print("Summary of your selections:") + print("=======================================\n") + + summary = {} + for b in selected_bins: + sel = b.get("SelectionName", "unknown") + summary.setdefault(sel, []).append(format_value_with_comment(b)) + + for sel, values in summary.items(): + print(f" {sel}: {', '.join(values)}") + + print("\nFinal selected bitmask:") + print(f" Decimal: {bitmask}") + print(f" Binary: {bin(bitmask)}") + print(f" Hex: {hex(bitmask)}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("rootfile", help="Path to ROOT file") + parser.add_argument("--dir", default="femto-producer", help="TDirectory path in ROOT file") + args = parser.parse_args() + main(args.rootfile, args.dir) diff --git a/PWGCF/Femto/TableProducer/CMakeLists.txt b/PWGCF/Femto/TableProducer/CMakeLists.txt new file mode 100644 index 00000000000..fc9a5f82013 --- /dev/null +++ b/PWGCF/Femto/TableProducer/CMakeLists.txt @@ -0,0 +1,20 @@ +# 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. + +o2physics_add_dpl_workflow(femto-producer + SOURCES femtoProducer.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-producer-derived-to-derived + SOURCES ./femtoProducerDerivedToDerived.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx new file mode 100644 index 00000000000..f28a7cc265b --- /dev/null +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -0,0 +1,366 @@ +// 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 femtoProducer.cxx +/// \brief Tasks that produces the all femto tables +/// \author Anton Riedel, TU München, anton.riedel@tum.de + +#include "PWGCF/Femto/Core/cascadeBuilder.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/kinkBuilder.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/twoTrackResonanceBuilder.h" +#include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include + +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +namespace o2::analysis::femto +{ +namespace consumeddata +{ +using Run3PpCollisions = soa::Join; + +using Run3FullPidTracks = + soa::Join; + +using Run3PpVzeros = V0Datas; + +using Run3PpCascades = CascDatas; + +using Run3PpKinks = KinkCands; + +} // namespace consumeddata +} // namespace o2::analysis::femto + +struct FemtoProducer { + + // ccdb + collisionbuilder::ConfCcdb confCcdb; + + // collision builder + collisionbuilder::CollisionBuilderProducts collisionBuilderProducts; + collisionbuilder::ConfCollisionTables confCollisionTables; + collisionbuilder::ConfCollisionFilters confCollisionFilters; + collisionbuilder::ConfCollisionBits confCollisionBits; + collisionbuilder::ConfCollisionRctFlags confCollisionRctFlags; + collisionbuilder::CollisionBuilder collisionBuilder; + + // track builder + trackbuilder::TrackBuilderProducts trackBuilderProducts; + trackbuilder::ConfTrackTables confTrackTables; + trackbuilder::TrackBuilder trackBuilder; + trackbuilder::ConfTrackBits confTrackBits; + trackbuilder::ConfTrackFilters confTrackFilters; + + // v0 builders + v0builder::V0BuilderProducts v0builderProducts; + v0builder::ConfV0Tables confV0Tables; + v0builder::ConfV0Filters confV0Filters; + v0builder::ConfK0shortBits confK0shortBits; + v0builder::V0Builder k0shortBuilder; + v0builder::ConfLambdaBits confLambdaBits; + v0builder::V0Builder lambdaBuilder; + v0builder::V0Builder antilambdaBuilder; + + // cascade builder + cascadebuilder::CascadeBuilderProducts cascadeBuilderProducts; + cascadebuilder::ConfCascadeTables confCascadeTables; + cascadebuilder::ConfCascadeFilters confCascadeFilters; + cascadebuilder::ConfXiBits confXiBits; + cascadebuilder::CascadeBuilder xiBuilder; + cascadebuilder::ConfOmegaBits confOmegaBits; + cascadebuilder::CascadeBuilder omegaBuilder; + + // kink builder + kinkbuilder::KinkBuilderProducts kinkBuilderProducts; + kinkbuilder::ConfKinkTables confKinkTables; + kinkbuilder::ConfKinkFilters confKinkFilters; + kinkbuilder::ConfSigmaBits confSigmaBits; + kinkbuilder::KinkBuilder sigmaBuilder; + kinkbuilder::ConfSigmaPlusBits confSigmaPlusBits; + kinkbuilder::KinkBuilder sigmaPlusBuilder; + + // resonance daughter filters and partitions + twotrackresonancebuilder::ConfTwoTrackResonanceDaughterFilters confResonanceDaughterFilters; + // caching and preslicing + SliceCache cache; + Preslice perColTracks = track::collisionId; + Partition partitionPositiveDaughters = + (track::signed1Pt > 0.f) && + (track::pt > confResonanceDaughterFilters.ptMin && track::pt < confResonanceDaughterFilters.ptMax) && + (track::eta > confResonanceDaughterFilters.etaMin && track::eta < confResonanceDaughterFilters.etaMax) && + (track::phi > confResonanceDaughterFilters.phiMin && track::phi < confResonanceDaughterFilters.phiMax); + Partition partitionNegativeDaughters = + (track::signed1Pt < 0.f) && + (track::pt > confResonanceDaughterFilters.ptMin && track::pt < confResonanceDaughterFilters.ptMax) && + (track::eta > confResonanceDaughterFilters.etaMin && track::eta < confResonanceDaughterFilters.etaMax) && + (track::phi > confResonanceDaughterFilters.phiMin && track::phi < confResonanceDaughterFilters.phiMax); + + // resonance builders + twotrackresonancebuilder::TwoTrackResonanceBuilderProducts twoTrackResonanceBuilderProducts; + twotrackresonancebuilder::ConfTwoTrackResonanceTables confTwoTrackResonanceTables; + twotrackresonancebuilder::ConfRhoFilters confRhoFilters; + twotrackresonancebuilder::ConfRho0Bits confRho0Bits; + twotrackresonancebuilder::TwoTrackResonanceBuilder rho0Builder; + twotrackresonancebuilder::ConfPhiFilters confPhiFilters; + twotrackresonancebuilder::ConfPhiBits confPhiBits; + twotrackresonancebuilder::TwoTrackResonanceBuilder phiBuilder; + twotrackresonancebuilder::ConfKstarFilters confKstarFilters; + twotrackresonancebuilder::ConfKstar0Bits confKstar0Bits; + twotrackresonancebuilder::TwoTrackResonanceBuilder kstar0Builder; + twotrackresonancebuilder::TwoTrackResonanceBuilder kstar0barBuilder; + + // histogramming + // add histograms in next iteration + HistogramRegistry hRegistry{"FemtoProducer", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // data members + Service ccdb; /// Accessing the CCDB + std::unordered_map indexMapTracks; // for mapping tracks to lambdas, cascades and resonances + + void init(InitContext& context) + { + // init ccdb + ccdb->setURL(confCcdb.ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + // collision selection + collisionBuilder.init(&hRegistry, confCollisionFilters, confCollisionBits, confCollisionRctFlags, confCcdb, confCollisionTables, context); + + // configure track builder + trackBuilder.init(&hRegistry, confTrackBits, confTrackFilters, confTrackTables, context); + + // configure v0 builder + k0shortBuilder.init(&hRegistry, confK0shortBits, confV0Filters, confV0Tables, context); + lambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context); + antilambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context); + + // configure kink builder + sigmaBuilder.init(&hRegistry, confSigmaBits, confKinkFilters, confKinkTables, context); + sigmaPlusBuilder.init(&hRegistry, confSigmaPlusBits, confKinkFilters, confKinkTables, context); + + // cascade selections + xiBuilder.init(&hRegistry, confXiBits, confCascadeFilters, confCascadeTables, context); + omegaBuilder.init(&hRegistry, confOmegaBits, confCascadeFilters, confCascadeTables, context); + + // configure resonance selections + rho0Builder.init(&hRegistry, confRho0Bits, confRhoFilters, confResonanceDaughterFilters, confTwoTrackResonanceTables, context); + phiBuilder.init(&hRegistry, confPhiBits, confPhiFilters, confResonanceDaughterFilters, confTwoTrackResonanceTables, context); + kstar0Builder.init(&hRegistry, confKstar0Bits, confKstarFilters, confResonanceDaughterFilters, confTwoTrackResonanceTables, context); + kstar0barBuilder.init(&hRegistry, confKstar0Bits, confKstarFilters, confResonanceDaughterFilters, confTwoTrackResonanceTables, context); + + if ((xiBuilder.fillAnyTable() || omegaBuilder.fillAnyTable()) && (!doprocessTracksV0sCascadesRun3pp && !doprocessTracksV0sCascadesKinksRun3pp)) { + LOG(fatal) << "At least one cascade table is enabled, but wrong process function is enabled. Breaking..."; + } + if ((lambdaBuilder.fillAnyTable() || antilambdaBuilder.fillAnyTable() || k0shortBuilder.fillAnyTable()) && (!doprocessTracksV0sCascadesRun3pp && !doprocessTracksV0sRun3pp && !doprocessTracksV0sCascadesKinksRun3pp)) { + LOG(fatal) << "At least one v0 table is enabled, but wrong process function is enabled. Breaking..."; + } + if ((sigmaBuilder.fillAnyTable() || sigmaPlusBuilder.fillAnyTable()) && (!doprocessTracksKinksRun3pp && !doprocessTracksV0sCascadesKinksRun3pp)) { + LOG(fatal) << "At least one kink table is enabled, but wrong process function is enabled. Breaking..."; + } + } + + // Core implementations + template + bool processCollisions(T1 const& col, T2 const& /* bcs*/, T3 const& tracks) + { + collisionBuilder.reset(); + auto bc = col.template bc_as(); + collisionBuilder.initCollision(bc, col, tracks, ccdb, hRegistry); + if (!collisionBuilder.checkCollision(col)) { + return false; + } + return true; + } + + template + void processTracks(T1 const& col, T2 const& tracksWithItsPid) + { + trackBuilder.fillTracks(col, collisionBuilder, collisionBuilderProducts, tracksWithItsPid, trackBuilderProducts, indexMapTracks); + } + + template + void processResonances(T1 const& col, T2 const& /*tracks*/) + { + auto groupPositiveTracks = partitionPositiveDaughters->sliceByCached(track::collisionId, col.globalIndex(), cache); + auto groupNegativeTracks = partitionNegativeDaughters->sliceByCached(track::collisionId, col.globalIndex(), cache); + rho0Builder.fillResonances(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, twoTrackResonanceBuilderProducts, groupPositiveTracks, groupNegativeTracks, trackBuilder, indexMapTracks); + phiBuilder.fillResonances(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, twoTrackResonanceBuilderProducts, groupPositiveTracks, groupNegativeTracks, trackBuilder, indexMapTracks); + kstar0Builder.fillResonances(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, twoTrackResonanceBuilderProducts, groupPositiveTracks, groupNegativeTracks, trackBuilder, indexMapTracks); + kstar0barBuilder.fillResonances(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, twoTrackResonanceBuilderProducts, groupPositiveTracks, groupNegativeTracks, trackBuilder, indexMapTracks); + } + + // add v0s + template + void processV0s(T1 const& col, T2 const& tracks, T3 const& v0s) + { + lambdaBuilder.fillV0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, v0builderProducts, v0s, tracks, trackBuilder, indexMapTracks); + antilambdaBuilder.fillV0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, v0builderProducts, v0s, tracks, trackBuilder, indexMapTracks); + k0shortBuilder.fillV0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, v0builderProducts, v0s, tracks, trackBuilder, indexMapTracks); + } + + // add kinks + template + void processKinks(T1 const& col, T2 const& tracks, T3 const& kinks) + { + sigmaBuilder.fillKinks(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, kinkBuilderProducts, kinks, tracks, trackBuilder, indexMapTracks); + sigmaPlusBuilder.fillKinks(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, kinkBuilderProducts, kinks, tracks, trackBuilder, indexMapTracks); + } + + // add cascades + template + void processCascades(T1 const& col, T2 const& tracks, T3 const& cascades) + { + xiBuilder.fillCascades(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, cascadeBuilderProducts, + cascades, tracks, trackBuilder, indexMapTracks); + omegaBuilder.fillCascades(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, cascadeBuilderProducts, + cascades, tracks, trackBuilder, indexMapTracks); + } + + // proccess functions + void processTracksRun3pp(consumeddata::Run3PpCollisions::iterator const& col, + BCsWithTimestamps const& bcs, + consumeddata::Run3FullPidTracks const& tracks) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + indexMapTracks.clear(); + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processResonances(col, tracks); + } + PROCESS_SWITCH(FemtoProducer, processTracksRun3pp, "Process tracks", true); + + // process tracks and v0s + void processTracksV0sRun3pp(consumeddata::Run3PpCollisions::iterator const& col, + BCsWithTimestamps const& bcs, + consumeddata::Run3FullPidTracks const& tracks, + consumeddata::Run3PpVzeros const& v0s) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + indexMapTracks.clear(); + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processResonances(col, tracks); + processV0s(col, tracks, v0s); + }; + PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3pp, "Process tracks and v0s", false); + + // process tracks and kinks + void processTracksKinksRun3pp(consumeddata::Run3PpCollisions::iterator const& col, + BCsWithTimestamps const& bcs, + consumeddata::Run3FullPidTracks const& tracks, + consumeddata::Run3PpKinks const& kinks) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + indexMapTracks.clear(); + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processResonances(col, tracks); + processKinks(col, tracks, kinks); + } + PROCESS_SWITCH(FemtoProducer, processTracksKinksRun3pp, "Process tracks and kinks", false); + + // process tracks, v0s and cascades + void processTracksV0sCascadesRun3pp(consumeddata::Run3PpCollisions::iterator const& col, + BCsWithTimestamps const& bcs, + consumeddata::Run3FullPidTracks const& tracks, + consumeddata::Run3PpVzeros const& v0s, + consumeddata::Run3PpCascades const& cascades) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + indexMapTracks.clear(); + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processResonances(col, tracks); + processV0s(col, tracks, v0s); + processCascades(col, tracks, cascades); + } + PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3pp, "Provide Tracks, V0s and Cascades for Run3", false); + + // process tracks, v0s, cascades and kinks + void processTracksV0sCascadesKinksRun3pp(consumeddata::Run3PpCollisions::iterator const& col, + BCsWithTimestamps const& bcs, + consumeddata::Run3FullPidTracks const& tracks, + consumeddata::Run3PpVzeros const& v0s, + consumeddata::Run3PpCascades const& cascades, + consumeddata::Run3PpKinks const& kinks) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + indexMapTracks.clear(); + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processResonances(col, tracks); + processV0s(col, tracks, v0s); + processKinks(col, tracks, kinks); + processCascades(col, tracks, cascades); + } + PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesKinksRun3pp, "Provide Tracks, V0s and Cascades for Run3", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx new file mode 100644 index 00000000000..d3806ae5f78 --- /dev/null +++ b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx @@ -0,0 +1,143 @@ +// 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 femtoProducerDerivedToDerived.cxx +/// \brief Tasks that produces the femto tables from derived data +/// \author Anton Riedel, TU München, anton.riedel@tum.de + +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/InitContext.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoProducerDerivedToDerived { + + // setup tables + using Collisions = Join; + using Collision = Collisions::iterator; + + using FilteredCollisions = o2::soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + + using Tracks = o2::soa::Join; + using Lambdas = o2::soa::Join; + using K0shorts = o2::soa::Join; + + SliceCache cache; + + // collision builder + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + collisionbuilder::CollisionBuilderDerivedToDerivedProducts collisionBuilderProducts; + collisionbuilder::CollisionBuilderDerivedToDerived collisionBuilder; + + // track builder + trackbuilder::TrackBuilderDerivedToDerived trackBuilder; + trackbuilder::TrackBuilderDerivedToDerivedProducts trackBuilderProducts; + trackbuilder::ConfTrackTablesDerivedToDerived confTrackBuilder; + trackbuilder::ConfTrackSelection1 trackSelections1; + trackbuilder::ConfTrackSelection2 trackSelections2; + + Partition trackPartition1 = MAKE_TRACK_PARTITION(trackSelections1); + Partition trackPartition2 = MAKE_TRACK_PARTITION(trackSelections2); + Preslice perColTracks = femtobase::stored::fColId; + + // v0 builder + v0builder::V0BuilderDerivedToDerived v0Builder; + v0builder::V0BuilderDerivedToDerivedProducts v0BuilderProducts; + v0builder::ConfV0TablesDerivedToDerived confV0Builder; + + v0builder::ConfLambdaSelection1 lambdaSelection1; + Partition lambdaPartition = MAKE_LAMBDA_PARTITION(lambdaSelection1); + Preslice perColLambdas = femtobase::stored::fColId; + + v0builder::ConfK0shortSelection1 k0shortSelection1; + Partition k0shortPartition = MAKE_K0SHORT_PARTITION(k0shortSelection1); + Preslice perColK0shorts = femtobase::stored::fColId; + + std::unordered_map + indexMapTracks; // for mapping tracks to lambdas, cascades and resonances + + void init(InitContext& /*context*/) + { + trackBuilder.init(confTrackBuilder); + v0Builder.init(confV0Builder); + + if ((doprocessTracks + doprocessLambdas + doprocessK0shorts) > 1) { + LOG(fatal) << "Only one proccess function can be activated"; + } + } + + // proccess functions + void processTracks(FilteredCollision const& col, Tracks const& tracks) + { + if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { + return; + } + indexMapTracks.clear(); + collisionBuilder.processCollision(col, collisionBuilderProducts); + trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, indexMapTracks, cache, trackBuilderProducts, collisionBuilderProducts); + } + PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracks, "Process tracks", true); + + void processLambdas(FilteredCollision const& col, Tracks const& tracks, Lambdas const& lambdas) + { + if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) && v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { + return; + } + indexMapTracks.clear(); + if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { + collisionBuilder.processCollision(col, collisionBuilderProducts); + trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, indexMapTracks, cache, trackBuilderProducts, collisionBuilderProducts); + v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, trackBuilder, indexMapTracks, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } + } + PROCESS_SWITCH(FemtoProducerDerivedToDerived, processLambdas, "Process lambdas and tracks", false); + + void processK0shorts(FilteredCollision const& col, Tracks const& tracks, K0shorts const& k0shorts) + { + if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) && v0Builder.collisionHasTooFewK0shorts(col, k0shorts, k0shortPartition, cache)) { + return; + } + indexMapTracks.clear(); + if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { + collisionBuilder.processCollision(col, collisionBuilderProducts); + trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, indexMapTracks, cache, trackBuilderProducts, collisionBuilderProducts); + v0Builder.processK0shorts(col, k0shorts, tracks, k0shortPartition, trackBuilder, indexMapTracks, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } + } + PROCESS_SWITCH(FemtoProducerDerivedToDerived, processK0shorts, "Process k0short and tracks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/CMakeLists.txt b/PWGCF/Femto/Tasks/CMakeLists.txt new file mode 100644 index 00000000000..1cee38e9eee --- /dev/null +++ b/PWGCF/Femto/Tasks/CMakeLists.txt @@ -0,0 +1,65 @@ +# 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. + +o2physics_add_dpl_workflow(femto-track-qa + SOURCES femtoTrackQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-twotrackresonance-qa + SOURCES femtoTwotrackresonanceQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-v0-qa + SOURCES femtoV0Qa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-kink-qa + SOURCES femtoKinkQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-cascade-qa + SOURCES femtoCascadeQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-track-track + SOURCES femtoPairTrackTrack.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-track-v0 + SOURCES femtoPairTrackV0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-track-two-track-resonance + SOURCES femtoPairTrackTwoTrackResonance.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-track-cascade + SOURCES femtoPairTrackCascade.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-track-kink + SOURCES femtoPairTrackKink.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-pair-v0-v0 + SOURCES femtoPairV0V0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/Tasks/femtoCascadeQa.cxx b/PWGCF/Femto/Tasks/femtoCascadeQa.cxx new file mode 100644 index 00000000000..274e572c5bc --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoCascadeQa.cxx @@ -0,0 +1,160 @@ +// 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 femtoCascadeQa.cxx +/// \brief Tasks for Qa of cascades +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/cascadeBuilder.h" +#include "PWGCF/Femto/Core/cascadeHistManager.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoCascadeQa { + + // setup tables + using FemtoCollisions = o2::soa::Join; + using FemtoCollision = FemtoCollisions::iterator; + + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + using FemtoXis = o2::soa::Join; + using FemtoOmegas = o2::soa::Join; + using FemtoTracks = o2::soa::Join; + + SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::CollisionHistManager colHistManager; + colhistmanager::ConfCollisionBinning confCollisionBinning; + colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; + + // setup for xis + cascadebuilder::ConfXiSelection confXiSelection; + Partition xiPartition = MAKE_CASCADE_PARTITION(confXiSelection); + Preslice preColXis = femtobase::stored::fColId; + + cascadehistmanager::ConfXiBinning confXiBinning; + cascadehistmanager::ConfXiQaBinning confXiQaBinning; + cascadehistmanager::CascadeHistManager< + cascadehistmanager::PrefixXiQa, + trackhistmanager::PrefixCascadeBachelorQa, + trackhistmanager::PrefixV0PosDaughterQa, + trackhistmanager::PrefixV0NegDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::Cascade::kXi> + xiHistManager; + + // setup for omegas + cascadebuilder::ConfOmegaSelection confOmegaSelection; + Partition omegaPartition = MAKE_CASCADE_PARTITION(confOmegaSelection); + Preslice preColOmegas = femtobase::stored::fColId; + + cascadehistmanager::ConfOmegaBinning confOmegaBinning; + cascadehistmanager::ConfOmegaQaBinning confOmegaQaBinning; + cascadehistmanager::CascadeHistManager< + cascadehistmanager::PrefixOmegaQa, + trackhistmanager::PrefixCascadeBachelorQa, + trackhistmanager::PrefixV0PosDaughterQa, + trackhistmanager::PrefixV0NegDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::Cascade::kOmega> + omegaHistManager; + + // setup for daughters/bachelor + trackhistmanager::ConfCascadePosDauBinning confPosDaughterBinning; + trackhistmanager::ConfCascadePosDauQaBinning confPosDaughterQaBinning; + trackhistmanager::ConfCascadeNegDauBinning confNegDaughterBinning; + trackhistmanager::ConfCascadeNegDauQaBinning confNegDaughterQaBinning; + trackhistmanager::ConfCascadeBachelorBinning confBachelorBinning; + trackhistmanager::ConfCascadeBachelorQaBinning confBachelorQaBinning; + + HistogramRegistry hRegistry{"FemtoCascadeQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + // create a map for histogram specs + auto colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionQaBinning); + + auto bachelorHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confBachelorBinning, confBachelorQaBinning); + auto posDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confPosDaughterBinning, confPosDaughterQaBinning); + auto negDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confNegDaughterBinning, confNegDaughterQaBinning); + + if ((doprocessXis + doprocessOmegas) > 1) { + LOG(fatal) << "Only one process can be activated"; + } + + if (doprocessXis) { + auto xiHistSpec = cascadehistmanager::makeCascadeQaHistSpecMap(confXiBinning, confXiQaBinning); + xiHistManager.init(&hRegistry, xiHistSpec, confXiQaBinning, bachelorHistSpec, confBachelorQaBinning, posDaughterHistSpec, confPosDaughterQaBinning, negDaughterHistSpec, confNegDaughterQaBinning); + } + + if (doprocessOmegas) { + auto omegaHistSpec = cascadehistmanager::makeCascadeQaHistSpecMap(confOmegaBinning, confOmegaQaBinning); + omegaHistManager.init(&hRegistry, omegaHistSpec, confOmegaQaBinning, bachelorHistSpec, confBachelorQaBinning, posDaughterHistSpec, confPosDaughterQaBinning, negDaughterHistSpec, confNegDaughterQaBinning); + } + }; + + void processXis(FilteredFemtoCollision const& col, FemtoXis const& /*xis*/, FemtoTracks const& tracks) + { + colHistManager.fill(col); + auto xiSlice = xiPartition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& xi : xiSlice) { + xiHistManager.fill(xi, tracks); + } + } + PROCESS_SWITCH(FemtoCascadeQa, processXis, "Process Xis", true); + + void processOmegas(FilteredFemtoCollision const& col, FemtoOmegas const& /*omegas*/, FemtoTracks const& tracks) + { + colHistManager.fill(col); + auto omegaSlice = omegaPartition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& omega : omegaSlice) { + omegaHistManager.fill(omega, tracks); + } + } + PROCESS_SWITCH(FemtoCascadeQa, processOmegas, "Process Omegas", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoKinkQa.cxx b/PWGCF/Femto/Tasks/femtoKinkQa.cxx new file mode 100644 index 00000000000..e2fe8146b30 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoKinkQa.cxx @@ -0,0 +1,157 @@ +// 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 femtoKinkQa.cxx +/// \brief QA task for kinks +/// \author Anton Riedel, TU München, anton.riedel@cern.ch +/// \author Henrik Fribert, TU München, henrik.fribert@cern.ch + +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/kinkBuilder.h" +#include "PWGCF/Femto/Core/kinkHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" +#include "PWGLF/DataModel/LFKinkDecayTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoKinkQa { + + // setup for collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + + colhistmanager::CollisionHistManager colHistManager; + colhistmanager::ConfCollisionBinning confCollisionBinning; + colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; + + using FemtoCollisions = o2::soa::Join; + using FemtoCollision = FemtoCollisions::iterator; + + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + // Define kink/sigma tables (joining tables for comprehensive information) + using FemtoSigmas = o2::soa::Join; + using FemtoSigmaPlus = o2::soa::Join; + using FemtoTracks = o2::soa::Join; + + SliceCache cache; + + // setup for sigmas + kinkbuilder::ConfSigmaSelection1 confSigmaSelection; + + Partition sigmaPartition = MAKE_SIGMA_PARTITION(confSigmaSelection); + Preslice perColSigmas = femtobase::stored::fColId; + + kinkhistmanager::ConfSigmaBinning1 confSigmaBinning; + kinkhistmanager::ConfSigmaQaBinning1 confSigmaQaBinning; + kinkhistmanager::KinkHistManager< + kinkhistmanager::PrefixSigmaQa, + trackhistmanager::PrefixKinkChaDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::Kink::kSigma> + sigmaHistManager; + + // setup for sigma plus + kinkbuilder::ConfSigmaPlusSelection1 confSigmaPlusSelection; + + Partition sigmaPlusPartition = MAKE_SIGMAPLUS_PARTITION(confSigmaPlusSelection); + Preslice perColSigmaPlus = femtobase::stored::fColId; + + kinkhistmanager::ConfSigmaPlusBinning1 confSigmaPlusBinning; + kinkhistmanager::ConfSigmaPlusQaBinning1 confSigmaPlusQaBinning; + kinkhistmanager::KinkHistManager< + kinkhistmanager::PrefixSigmaPlusQa, + trackhistmanager::PrefixKinkChaDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::Kink::kSigmaPlus> + sigmaPlusHistManager; + + // setup for daughters + trackhistmanager::ConfKinkChaDauBinning confKinkChaDaughterBinning; + trackhistmanager::ConfKinkChaDauQaBinning confKinkChaDaughterQaBinning; + + HistogramRegistry hRegistry{"FemtoKinkQa", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + // create a map for histogram specs + auto colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionQaBinning); + + auto chaDauHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confKinkChaDaughterBinning, confKinkChaDaughterQaBinning); + + if ((doprocessSigma + doprocessSigmaPlus > 1)) { + LOG(fatal) << "Only one process can be activated"; + } + + if (doprocessSigma) { + auto sigmaHistSpec = kinkhistmanager::makeKinkQaHistSpecMap(confSigmaBinning, confSigmaQaBinning); + sigmaHistManager.init(&hRegistry, sigmaHistSpec, confSigmaQaBinning, chaDauHistSpec, confKinkChaDaughterQaBinning); + } + + if (doprocessSigmaPlus) { + auto sigmaPlusHistSpec = kinkhistmanager::makeKinkQaHistSpecMap(confSigmaPlusBinning, confSigmaPlusQaBinning); + sigmaPlusHistManager.init(&hRegistry, sigmaPlusHistSpec, confSigmaPlusQaBinning, chaDauHistSpec, confKinkChaDaughterQaBinning); + } + }; + + void processSigma(FilteredFemtoCollision const& col, FemtoSigmas const& /*sigmas*/, FemtoTracks const& tracks) + { + colHistManager.fill(col); + auto sigmaSlice = sigmaPartition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& sigma : sigmaSlice) { + sigmaHistManager.fill(sigma, tracks); + } + } + PROCESS_SWITCH(FemtoKinkQa, processSigma, "Process sigmas", true); + + void processSigmaPlus(FilteredFemtoCollision const& col, FemtoSigmaPlus const& /*sigmaplus*/, FemtoTracks const& tracks) + { + colHistManager.fill(col); + + auto sigmaplusSlice = sigmaPlusPartition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + + for (auto const& sp : sigmaplusSlice) { + sigmaPlusHistManager.fill(sp, tracks); + } + } + PROCESS_SWITCH(FemtoKinkQa, processSigmaPlus, "Process sigma plus", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx b/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx new file mode 100644 index 00000000000..cfb6b801148 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx @@ -0,0 +1,213 @@ +// 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 femtoPairTrackCascade.cxx +/// \brief Tasks that computes correlation between tracks and cascades +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/cascadeBuilder.h" +#include "PWGCF/Femto/Core/cascadeHistManager.h" +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoPairTrackCascade { + + // setup tables + using Collisions = Join; + using Collision = Collisions::iterator; + + using FilteredCollisions = o2::soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + + using Tracks = o2::soa::Join; + using Xis = o2::soa::Join; + using Omegas = o2::soa::Join; + + SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup tracks + trackbuilder::ConfTrackSelection1 trackSelection; + trackhistmanager::ConfTrackBinning1 confTrackBinning; + Partition trackPartition = MAKE_TRACK_PARTITION(trackSelection); + Preslice perColTracks = aod::femtobase::stored::fColId; + + // setup for daughters/bachelor + trackhistmanager::ConfCascadePosDauBinning confPosDauBinning; + trackhistmanager::ConfCascadeNegDauBinning confNegDauBinning; + trackhistmanager::ConfCascadeBachelorBinning confBachelorBinning; + + // setup xis + cascadebuilder::ConfXiSelection xiSelection; + cascadehistmanager::ConfXiBinning confXiBinning; + Partition xiPartition = MAKE_CASCADE_PARTITION(xiSelection); + Preslice perColXis = aod::femtobase::stored::fColId; + + // setup omegas + cascadebuilder::ConfOmegaSelection omegaSelection; + cascadehistmanager::ConfOmegaBinning confOmegaBinning; + Partition omegaPartition = MAKE_CASCADE_PARTITION(omegaSelection); + Preslice perColOmegas = aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + pairbuilder::PairTrackCascadeBuilder< + trackhistmanager::PrefixTrack1, + cascadehistmanager::PrefixXi, + trackhistmanager::PrefixCascadeBachelor, + trackhistmanager::PrefixCascadePosDaughter, + trackhistmanager::PrefixCascadeNegDaughter, + pairhistmanager::PrefixTrackCascadeSe, + pairhistmanager::PrefixTrackCascadeMe, + closepairrejection::PrefixTrackCascadeBachelorSe, + closepairrejection::PrefixTrackV0DaughterSe, + closepairrejection::PrefixTrackCascadeBachelorMe, + closepairrejection::PrefixTrackV0DaughterMe, + modes::Mode::kAnalysis, + modes::Cascade::kXi> + pairTrackXiBuilder; + + pairbuilder::PairTrackCascadeBuilder< + trackhistmanager::PrefixTrack1, + cascadehistmanager::PrefixOmega, + trackhistmanager::PrefixCascadeBachelor, + trackhistmanager::PrefixCascadePosDaughter, + trackhistmanager::PrefixCascadeNegDaughter, + pairhistmanager::PrefixTrackCascadeSe, + pairhistmanager::PrefixTrackCascadeMe, + closepairrejection::PrefixTrackCascadeBachelorSe, + closepairrejection::PrefixTrackV0DaughterSe, + closepairrejection::PrefixTrackCascadeBachelorMe, + closepairrejection::PrefixTrackV0DaughterMe, + modes::Mode::kAnalysis, + modes::Cascade::kOmega> + pairTrackOmegaBuilder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + HistogramRegistry hRegistry{"FemtoTrackCascade", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprTrackCascadeBachelor confCprBachelor; + closepairrejection::ConfCprTrackV0Daughter confCprV0Daughter; + + void init(InitContext&) + { + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histograms + auto colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + auto trackHistSpec = trackhistmanager::makeTrackHistSpecMap(confTrackBinning); + auto bachelorHistSpec = trackhistmanager::makeTrackHistSpecMap(confBachelorBinning); + auto posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + auto negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + auto pairHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + auto cprHistSpecBachelor = closepairrejection::makeCprHistSpecMap(confCprBachelor); + auto cprHistSpecV0Daughter = closepairrejection::makeCprHistSpecMap(confCprV0Daughter); + + // setup for xis + if (doprocessXiSameEvent || doprocessXiMixedEvent) { + auto xiHistSpec = cascadehistmanager::makeCascadeHistSpecMap(confXiBinning); + auto pairTrackXiHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackXiBuilder.init(&hRegistry, trackSelection, xiSelection, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackXiHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter); + } + + // setup for omegas + if (doprocessOmegaSameEvent || doprocessOmegaMixedEvent) { + auto omegaHistSpec = cascadehistmanager::makeCascadeHistSpecMap(confOmegaBinning); + auto pairTrackOmegaHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackOmegaBuilder.init(&hRegistry, trackSelection, xiSelection, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackOmegaHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter); + } + + if (((doprocessXiSameEvent || doprocessXiMixedEvent) + (doprocessOmegaSameEvent || doprocessOmegaMixedEvent)) > 1) { + LOG(fatal) << "Can only process xi-tracks Or omega-tracks"; + } + }; + + void processXiSameEvent(FilteredCollision const& col, Tracks const& tracks, Xis const& xis) + { + pairTrackXiBuilder.processSameEvent(col, tracks, trackPartition, xis, xiPartition, cache); + } + PROCESS_SWITCH(FemtoPairTrackCascade, processXiSameEvent, "Enable processing same event processing for tracks and xis", true); + + void processXiMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, Xis const& /*xis*/) + { + pairTrackXiBuilder.processMixedEvent(cols, tracks, trackPartition, xiPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackCascade, processXiMixedEvent, "Enable processing mixed event processing for tracks and xis", true); + + void processOmegaSameEvent(FilteredCollision const& col, Tracks const& tracks, Omegas const& omegas) + { + pairTrackOmegaBuilder.processSameEvent(col, tracks, trackPartition, omegas, omegaPartition, cache); + } + PROCESS_SWITCH(FemtoPairTrackCascade, processOmegaSameEvent, "Enable processing same event processing for tracks and omegas", false); + + void processOmegaMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, Omegas const& /*omegas*/) + { + pairTrackOmegaBuilder.processMixedEvent(cols, tracks, trackPartition, omegaPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackCascade, processOmegaMixedEvent, "Enable processing mixed event processing for tracks and omegas", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx b/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx new file mode 100644 index 00000000000..b09207a1e88 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx @@ -0,0 +1,200 @@ +// 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 femtoPairTrackKink.cxx +/// \brief Tasks that computes correlation between tracks and kinks +/// \author Anton Riedel, TU München, anton.riedel@cern.ch +/// \author Henrik Fribert, TU München, henrik.fribert@cern.ch + +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/kinkBuilder.h" +#include "PWGCF/Femto/Core/kinkHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoPairTrackKink { + + // setup tables + using Collisions = Join; + using Collision = Collisions::iterator; + + using FilteredCollisions = o2::soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + + using Tracks = o2::soa::Join; + using Sigmas = o2::soa::Join; + using SigmaPlus = o2::soa::Join; + + SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup tracks + trackbuilder::ConfTrackSelection1 trackSelection; + trackhistmanager::ConfTrackBinning1 confTrackBinning; + Partition trackPartition = MAKE_TRACK_PARTITION(trackSelection); + Preslice perColTracks = aod::femtobase::stored::fColId; + + // setup for daughters + trackhistmanager::ConfKinkChaDauBinning confChaDauBinning; + + // setup sigmas + kinkbuilder::ConfSigmaSelection1 sigmaSelection; + kinkhistmanager::ConfSigmaBinning1 confSigmaBinning; + Partition sigmaPartition = MAKE_SIGMA_PARTITION(sigmaSelection); + Preslice perColSigmas = aod::femtobase::stored::fColId; + + // setup for sigma plus + kinkbuilder::ConfSigmaPlusSelection1 sigmaPlusSelection; + kinkhistmanager::ConfSigmaPlusBinning1 confSigmaPlusBinning; + Partition sigmaPlusPartition = MAKE_SIGMAPLUS_PARTITION(sigmaPlusSelection); + Preslice perColSigmaPlus = aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + pairbuilder::PairTrackKinkBuilder< + trackhistmanager::PrefixTrack1, + kinkhistmanager::PrefixSigma1, + trackhistmanager::PrefixKinkChaDaughter, + pairhistmanager::PrefixTrackKinkSe, + pairhistmanager::PrefixTrackKinkMe, + closepairrejection::PrefixTrackKinkSe, + closepairrejection::PrefixTrackKinkMe, + modes::Mode::kAnalysis, + modes::Kink::kSigma> + pairTrackSigmaBuilder; + + pairbuilder::PairTrackKinkBuilder< + trackhistmanager::PrefixTrack1, + kinkhistmanager::PrefixSigmaPlus1, + trackhistmanager::PrefixKinkChaDaughter, + pairhistmanager::PrefixTrackKinkSe, + pairhistmanager::PrefixTrackKinkMe, + closepairrejection::PrefixTrackKinkSe, + closepairrejection::PrefixTrackKinkMe, + modes::Mode::kAnalysis, + modes::Kink::kSigmaPlus> + pairTrackSigmaPlusBuilder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + HistogramRegistry hRegistry{"FemtoTrackKink", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprTrackKinkDaughter confCpr; + + void init(InitContext&) + { + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histograms + auto colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + auto trackHistSpec = trackhistmanager::makeTrackHistSpecMap(confTrackBinning); + auto chaDauSpec = trackhistmanager::makeTrackHistSpecMap(confChaDauBinning); + auto pairHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + auto cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + + // setup for sigma + if (doprocessSigmaSameEvent || doprocessSigmaMixedEvent) { + auto sigmaHistSpec = kinkhistmanager::makeKinkHistSpecMap(confSigmaBinning); + auto pairTrackSigmaHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackSigmaBuilder.init(&hRegistry, trackSelection, sigmaSelection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaHistSpec, chaDauSpec, pairTrackSigmaHistSpec, cprHistSpec); + } + + // setup for sigma plus + if (doprocessSigmaPlusSameEvent || doprocessSigmaPlusMixedEvent) { + auto sigmaplusHistSpec = kinkhistmanager::makeKinkHistSpecMap(confSigmaPlusBinning); + auto pairTrackSigmaPlusHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackSigmaPlusBuilder.init(&hRegistry, trackSelection, sigmaPlusSelection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaplusHistSpec, chaDauSpec, pairTrackSigmaPlusHistSpec, cprHistSpec); + } + + if (((doprocessSigmaSameEvent || doprocessSigmaMixedEvent) + (doprocessSigmaPlusSameEvent || doprocessSigmaPlusMixedEvent)) > 1) { + LOG(fatal) << "Can only process sigma-tracks Or sigmaplus-tracks"; + } + }; + + void processSigmaSameEvent(FilteredCollision const& col, Tracks const& tracks, Sigmas const& sigmas) + { + pairTrackSigmaBuilder.processSameEvent(col, tracks, trackPartition, sigmas, sigmaPartition, cache); + } + PROCESS_SWITCH(FemtoPairTrackKink, processSigmaSameEvent, "Enable processing same event processing for tracks and sigmas", true); + + void processSigmaMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, Sigmas const& /*sigmas*/) + { + pairTrackSigmaBuilder.processMixedEvent(cols, tracks, trackPartition, sigmaPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackKink, processSigmaMixedEvent, "Enable processing mixed event processing for tracks and sigmas", true); + // + void processSigmaPlusSameEvent(FilteredCollision const& col, Tracks const& tracks, SigmaPlus const& sigmaplus) + { + pairTrackSigmaPlusBuilder.processSameEvent(col, tracks, trackPartition, sigmaplus, sigmaPlusPartition, cache); + } + PROCESS_SWITCH(FemtoPairTrackKink, processSigmaPlusSameEvent, "Enable processing same event processing for tracks and sigma plus", false); + + void processSigmaPlusMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, SigmaPlus const& /*sigmaplus*/) + { + pairTrackSigmaPlusBuilder.processMixedEvent(cols, tracks, trackPartition, sigmaPlusPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackKink, processSigmaPlusMixedEvent, "Enable processing mixed event processing for tracks and sigma plus", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx new file mode 100644 index 00000000000..f980f9d5694 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx @@ -0,0 +1,141 @@ +// 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 femtoPairTrackTrack.cxx +/// \brief Tasks that computes correlation between two tracks +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoPairTrackTrack { + + // setup tables + using Collisions = Join; + using Collision = Collisions::iterator; + + using FilteredCollisions = o2::soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + + using Tracks = o2::soa::Join; + + SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup tracks + trackbuilder::ConfTrackSelection1 trackSelections1; + trackhistmanager::ConfTrackBinning1 confTrackBinning1; + trackbuilder::ConfTrackSelection2 trackSelections2; + trackhistmanager::ConfTrackBinning2 confTrackBinning2; + + Partition trackPartition1 = MAKE_TRACK_PARTITION(trackSelections1); + Partition trackPartition2 = MAKE_TRACK_PARTITION(trackSelections2); + + Preslice perColReco = aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + closepairrejection::ConfCprTrackTrack confCpr; + + pairbuilder::PairTrackTrackBuilder< + trackhistmanager::PrefixTrack1, + trackhistmanager::PrefixTrack2, + pairhistmanager::PrefixTrackTrackSe, + pairhistmanager::PrefixTrackTrackMe, + closepairrejection::PrefixTrackTrackSe, + closepairrejection::PrefixTrackTrackMe, + modes::Mode::kAnalysis> + pairTrackTrackBuilder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + HistogramRegistry hRegistry{"FemtoTrackTrack", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histogram specs + auto colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + auto trackHistSpec1 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning1); + auto trackHistSpec2 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning2); + auto pairHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + auto cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + + pairTrackTrackBuilder.init(&hRegistry, trackSelections1, trackSelections2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec); + }; + + void processSameEvent(FilteredCollision const& col, Tracks const& tracks) + { + pairTrackTrackBuilder.processSameEvent(col, tracks, trackPartition1, trackPartition2, cache); + } + PROCESS_SWITCH(FemtoPairTrackTrack, processSameEvent, "Enable processing same event processing", true); + + void processMixedEvent(FilteredCollisions const& cols, Tracks const& tracks) + { + pairTrackTrackBuilder.processMixedEvent(cols, tracks, trackPartition1, trackPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackTrack, processMixedEvent, "Enable processing mixed event processing", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairTrackTwoTrackResonance.cxx b/PWGCF/Femto/Tasks/femtoPairTrackTwoTrackResonance.cxx new file mode 100644 index 00000000000..2b23c68ba5c --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairTrackTwoTrackResonance.cxx @@ -0,0 +1,244 @@ +// 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 femtoPairTrackTwoTrackResonance.cxx +/// \brief Tasks that computes correlation between tracks and resonances decaying into two tracks +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/Core/twoTrackResonanceBuilder.h" +#include "PWGCF/Femto/Core/twoTrackResonanceHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoPairTrackTwoTrackResonance { + + // setup tables + using Collisions = Join; + using Collision = Collisions::iterator; + + using FilteredCollisions = o2::soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + + using Tracks = o2::soa::Join; + using Phis = o2::soa::Join; + using Kstar0s = o2::soa::Join; + using Rho0s = o2::soa::Join; + + SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup tracks + trackbuilder::ConfTrackSelection1 trackSelection; + trackhistmanager::ConfTrackBinning1 confTrackBinning; + Partition trackPartition = MAKE_TRACK_PARTITION(trackSelection); + Preslice perColTracks = aod::femtobase::stored::fColId; + + // setup for daughters + trackhistmanager::ConfResonancePosDauBinning confPosDauBinning; + trackhistmanager::ConfResonanceNegDauBinning confNegDauBinning; + + // setup phis + twotrackresonancebuilder::ConfPhiSelection phiSelection; + twotrackresonancehistmanager::ConfPhiBinning confPhiBinning; + Partition phiPartition = MAKE_RESONANCE_0_PARTITON(phiSelection); + Preslice perColPhis = aod::femtobase::stored::fColId; + + // setup kstar0 + twotrackresonancebuilder::ConfKstar0Selection kstar0Selection; + twotrackresonancehistmanager::ConfKstar0Binning confKstar0Binning; + Partition kstar0Partition = MAKE_RESONANCE_1_PARTITON(kstar0Selection); + Preslice perColKstar0s = aod::femtobase::stored::fColId; + + // rho0s + twotrackresonancebuilder::ConfRho0Selection rho0Selection; + twotrackresonancehistmanager::ConfRho0Binning confRho0Binning; + Partition rho0Partition = MAKE_RESONANCE_0_PARTITON(rho0Selection); + Preslice perColRho0s = aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + // setup for track-phi pairs + pairbuilder::PairTrackTwoTrackResonanceBuilder< + trackhistmanager::PrefixTrack1, + twotrackresonancehistmanager::PrefixPhi, + trackhistmanager::PrefixResonancePosDaughter, + trackhistmanager::PrefixResonanceNegDaughter, + pairhistmanager::PrefixTrackResonanceSe, + pairhistmanager::PrefixTrackResonanceMe, + closepairrejection::PrefixTrackTwoTrackResonanceSe, + closepairrejection::PrefixTrackTwoTrackResonanceMe, + modes::Mode::kAnalysis, + modes::TwoTrackResonance::kPhi> + pairTrackPhiBuilder; + + // setup for track-kstar0 pairs + pairbuilder::PairTrackTwoTrackResonanceBuilder< + trackhistmanager::PrefixTrack1, + twotrackresonancehistmanager::PrefixKstar, + trackhistmanager::PrefixResonancePosDaughter, + trackhistmanager::PrefixResonanceNegDaughter, + pairhistmanager::PrefixTrackResonanceSe, + pairhistmanager::PrefixTrackResonanceMe, + closepairrejection::PrefixTrackTwoTrackResonanceSe, + closepairrejection::PrefixTrackTwoTrackResonanceMe, + modes::Mode::kAnalysis, + modes::TwoTrackResonance::kKstar0> + pairTrackKstar0Builder; + + // setup for track-rho0 pairs + pairbuilder::PairTrackTwoTrackResonanceBuilder< + trackhistmanager::PrefixTrack1, + twotrackresonancehistmanager::PrefixRho, + trackhistmanager::PrefixResonancePosDaughter, + trackhistmanager::PrefixResonanceNegDaughter, + pairhistmanager::PrefixTrackResonanceSe, + pairhistmanager::PrefixTrackResonanceMe, + closepairrejection::PrefixTrackTwoTrackResonanceSe, + closepairrejection::PrefixTrackTwoTrackResonanceMe, + modes::Mode::kAnalysis, + modes::TwoTrackResonance::kRho0> + pairTrackRho0Builder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + HistogramRegistry hRegistry{"FemtoTrackTwoTrackResonance", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprTrackResonanceDaughter confCpr; + + void init(InitContext&) + { + + if (((doprocessPhiSameEvent || doprocessPhiMixedEvent) + (doprocessKstar0SameEvent || doprocessKstar0MixedEvent)) + (doprocessRho0SameEvent || doprocessRho0MixedEvent) > 1) { + LOG(fatal) << "Can only process lambda-tracks Or k0short-tracks"; + } + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histograms + auto colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + auto trackHistSpec = trackhistmanager::makeTrackHistSpecMap(confTrackBinning); + auto posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + auto negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + auto cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + + // setup for phi + if (doprocessPhiSameEvent || doprocessPhiMixedEvent) { + auto phiHistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confPhiBinning); + auto pairTrackPhiHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackPhiBuilder.init(&hRegistry, trackSelection, phiSelection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, phiHistSpec, posDauSpec, negDauSpec, pairTrackPhiHistSpec, cprHistSpec); + } + + // setup for kstar0 + if (doprocessKstar0SameEvent || doprocessKstar0MixedEvent) { + auto kstar0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confKstar0Binning); + auto pairTrackKstar0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackKstar0Builder.init(&hRegistry, trackSelection, kstar0Selection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, kstar0HistSpec, posDauSpec, negDauSpec, pairTrackKstar0HistSpec, cprHistSpec); + } + + // setup for kstar0 + if (doprocessRho0SameEvent || doprocessRho0MixedEvent) { + auto rho0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confRho0Binning); + auto pairTrackRho0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackRho0Builder.init(&hRegistry, trackSelection, rho0Selection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, rho0HistSpec, posDauSpec, negDauSpec, pairTrackRho0HistSpec, cprHistSpec); + } + }; + + void processPhiSameEvent(FilteredCollision const& col, Tracks const& tracks, Phis const& phis) + { + pairTrackPhiBuilder.processSameEvent(col, tracks, trackPartition, phis, phiPartition, cache); + } + PROCESS_SWITCH(FemtoPairTrackTwoTrackResonance, processPhiSameEvent, "Enable processing same event processing for tracks and phis", true); + + void processPhiMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, Phis const& /*phis*/) + { + pairTrackPhiBuilder.processMixedEvent(cols, tracks, trackPartition, phiPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackTwoTrackResonance, processPhiMixedEvent, "Enable processing mixed event processing for tracks and phis", true); + + void processKstar0SameEvent(FilteredCollision const& col, Tracks const& tracks, Kstar0s const& kstar0s) + { + pairTrackKstar0Builder.processSameEvent(col, tracks, trackPartition, kstar0s, kstar0Partition, cache); + } + PROCESS_SWITCH(FemtoPairTrackTwoTrackResonance, processKstar0SameEvent, "Enable processing same event processing for tracks and kstar0s", false); + + void processKstar0MixedEvent(FilteredCollisions const& cols, Tracks const& tracks, Kstar0s const& /*kstar0s*/) + { + pairTrackKstar0Builder.processMixedEvent(cols, tracks, trackPartition, kstar0Partition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackTwoTrackResonance, processKstar0MixedEvent, "Enable processing mixed event processing for tracks and kstar0s", false); + + void processRho0SameEvent(FilteredCollision const& col, Tracks const& tracks, Rho0s const& rho0s) + { + pairTrackRho0Builder.processSameEvent(col, tracks, trackPartition, rho0s, rho0Partition, cache); + } + PROCESS_SWITCH(FemtoPairTrackTwoTrackResonance, processRho0SameEvent, "Enable processing same event processing for tracks and rho0s", false); + + void processRho0MixedEvent(FilteredCollisions const& cols, Tracks const& tracks, Rho0s const& /*rho0s*/) + { + pairTrackRho0Builder.processMixedEvent(cols, tracks, trackPartition, rho0Partition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackTwoTrackResonance, processRho0MixedEvent, "Enable processing mixed event processing for tracks and rho0s", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx new file mode 100644 index 00000000000..547dfb0aec8 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx @@ -0,0 +1,202 @@ +// 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 femtoPairTrackV0.cxx +/// \brief Tasks that computes correlation between tracks and v0s +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGCF/Femto/Core/v0HistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoPairTrackV0 { + + // setup tables + using Collisions = Join; + using Collision = Collisions::iterator; + + using FilteredCollisions = o2::soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + + using Tracks = o2::soa::Join; + using Lambdas = o2::soa::Join; + using K0shorts = o2::soa::Join; + + SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup tracks + trackbuilder::ConfTrackSelection1 trackSelection; + trackhistmanager::ConfTrackBinning1 confTrackBinning; + Partition trackPartition = MAKE_TRACK_PARTITION(trackSelection); + Preslice perColTracks = aod::femtobase::stored::fColId; + + // setup for daughters + trackhistmanager::ConfV0PosDauBinning confPosDauBinning; + trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + + // setup lambdas + v0builder::ConfLambdaSelection1 lambdaSelection; + v0histmanager::ConfLambdaBinning1 confLambdaBinning; + Partition lambdaPartition = MAKE_LAMBDA_PARTITION(lambdaSelection); + Preslice perColLambdas = aod::femtobase::stored::fColId; + + // setup k0shorts + v0builder::ConfK0shortSelection1 k0shortSelection; + v0histmanager::ConfK0shortBinning1 confK0shortBinning; + Partition k0shortPartition = MAKE_K0SHORT_PARTITION(k0shortSelection); + Preslice perColk0shorts = aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + pairbuilder::PairTrackV0Builder< + trackhistmanager::PrefixTrack1, + v0histmanager::PrefixLambda1, + trackhistmanager::PrefixV0PosDaughter1, + trackhistmanager::PrefixV0NegDaughter1, + pairhistmanager::PrefixTrackV0Se, + pairhistmanager::PrefixTrackV0Me, + closepairrejection::PrefixTrackV0DaughterSe, + closepairrejection::PrefixTrackV0DaughterMe, + modes::Mode::kAnalysis, + modes::V0::kLambda> + pairTrackLambdaBuilder; + + pairbuilder::PairTrackV0Builder< + trackhistmanager::PrefixTrack1, + v0histmanager::PrefixK0short1, + trackhistmanager::PrefixV0PosDaughter1, + trackhistmanager::PrefixV0NegDaughter1, + pairhistmanager::PrefixTrackV0Se, + pairhistmanager::PrefixTrackV0Me, + closepairrejection::PrefixTrackV0DaughterSe, + closepairrejection::PrefixTrackV0DaughterMe, + modes::Mode::kAnalysis, + modes::V0::kK0short> + pairTrackK0shortBuilder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + HistogramRegistry hRegistry{"FemtoTrackV0", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprTrackV0Daughter confCpr; + + void init(InitContext&) + { + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histograms + auto colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + auto trackHistSpec = trackhistmanager::makeTrackHistSpecMap(confTrackBinning); + auto posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + auto negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + auto cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + + // setup for lambda + if (doprocessLambdaSameEvent || doprocessLambdaMixedEvent) { + auto lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); + auto pairTrackLambdaHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackLambdaBuilder.init(&hRegistry, trackSelection, lambdaSelection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairTrackLambdaHistSpec, cprHistSpec); + } + + // setup for k0short + if (doprocessK0shortSameEvent || doprocessK0shortMixedEvent) { + auto k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); + auto pairTrackK0shortHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairTrackK0shortBuilder.init(&hRegistry, trackSelection, lambdaSelection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairTrackK0shortHistSpec, cprHistSpec); + } + + if (((doprocessLambdaSameEvent || doprocessLambdaMixedEvent) + (doprocessK0shortSameEvent || doprocessK0shortMixedEvent)) > 1) { + LOG(fatal) << "Can only process lambda-tracks Or k0short-tracks"; + } + }; + + void processLambdaSameEvent(FilteredCollision const& col, Tracks const& tracks, Lambdas const& lambdas) + { + pairTrackLambdaBuilder.processSameEvent(col, tracks, trackPartition, lambdas, lambdaPartition, cache); + } + PROCESS_SWITCH(FemtoPairTrackV0, processLambdaSameEvent, "Enable processing same event processing for tracks and lambdas", true); + + void processLambdaMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, Lambdas const& /*lambas*/) + { + pairTrackLambdaBuilder.processMixedEvent(cols, tracks, trackPartition, lambdaPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackV0, processLambdaMixedEvent, "Enable processing mixed event processing for tracks and lambdas", true); + // + void processK0shortSameEvent(FilteredCollision const& col, Tracks const& tracks, K0shorts const& k0shorts) + { + pairTrackK0shortBuilder.processSameEvent(col, tracks, trackPartition, k0shorts, k0shortPartition, cache); + } + PROCESS_SWITCH(FemtoPairTrackV0, processK0shortSameEvent, "Enable processing same event processing for tracks and k0shorts", false); + + void processK0shortMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, K0shorts const& /*k0shorts*/) + { + pairTrackK0shortBuilder.processMixedEvent(cols, tracks, trackPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackV0, processK0shortMixedEvent, "Enable processing mixed event processing for tracks and k0shorts", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairV0V0.cxx b/PWGCF/Femto/Tasks/femtoPairV0V0.cxx new file mode 100644 index 00000000000..1544b131013 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairV0V0.cxx @@ -0,0 +1,207 @@ +// 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 femtoPairV0V0.cxx +/// \brief Tasks that computes correlation between two v0s +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGCF/Femto/Core/v0HistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoPairV0V0 { + + // setup tables + using Collisions = Join; + using Collision = Collisions::iterator; + + using FilteredCollisions = o2::soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + + using Tracks = o2::soa::Join; + using Lambdas = o2::soa::Join; + using K0shorts = o2::soa::Join; + + SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup for daughters + trackhistmanager::ConfV0PosDauBinning confPosDauBinning; + trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + + // setup lambdas + v0builder::ConfLambdaSelection1 lambdaSelection; + v0histmanager::ConfLambdaBinning1 confLambdaBinning; + Partition lambdaPartition = MAKE_LAMBDA_PARTITION(lambdaSelection); + Preslice perColLambdas = aod::femtobase::stored::fColId; + + // setup k0shorts + v0builder::ConfK0shortSelection1 k0shortSelection; + v0histmanager::ConfK0shortBinning1 confK0shortBinning; + Partition k0shortPartition = MAKE_K0SHORT_PARTITION(k0shortSelection); + Preslice perColk0shorts = aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + pairbuilder::PairV0V0Builder< + v0histmanager::PrefixLambda1, + trackhistmanager::PrefixV0PosDaughter1, + trackhistmanager::PrefixV0NegDaughter2, + v0histmanager::PrefixLambda2, + trackhistmanager::PrefixV0PosDaughter1, + trackhistmanager::PrefixV0NegDaughter2, + pairhistmanager::PrefixV0V0Se, + pairhistmanager::PrefixV0V0Me, + closepairrejection::PrefixV0V0PosSe, + closepairrejection::PrefixV0V0NegSe, + closepairrejection::PrefixV0V0PosMe, + closepairrejection::PrefixV0V0NegMe, + modes::V0::kLambda, + modes::V0::kLambda, + modes::Mode::kAnalysis> + pairLambdaLambdaBuilder; + + pairbuilder::PairV0V0Builder< + v0histmanager::PrefixK0short1, + trackhistmanager::PrefixV0PosDaughter1, + trackhistmanager::PrefixV0NegDaughter2, + v0histmanager::PrefixK0short2, + trackhistmanager::PrefixV0PosDaughter1, + trackhistmanager::PrefixV0NegDaughter2, + pairhistmanager::PrefixV0V0Se, + pairhistmanager::PrefixV0V0Me, + closepairrejection::PrefixV0V0PosSe, + closepairrejection::PrefixV0V0NegSe, + closepairrejection::PrefixV0V0PosMe, + closepairrejection::PrefixV0V0NegMe, + modes::V0::kK0short, + modes::V0::kK0short, + modes::Mode::kAnalysis> + pairK0shortK0shortBuilder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + HistogramRegistry hRegistry{"FemtoTrackV0", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprV0DaugherV0DaughterPos confCprPos; + closepairrejection::ConfCprV0DaugherV0DaughterNeg confCprNeg; + + void init(InitContext&) + { + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + // setup histograms + auto colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + auto posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + auto negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + auto cprHistSpecPos = closepairrejection::makeCprHistSpecMap(confCprPos); + auto cprHistSpecNeg = closepairrejection::makeCprHistSpecMap(confCprNeg); + + // setup for lambda + if (doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent) { + auto lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); + auto pairLambdaLambdaHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairLambdaLambdaBuilder.init(&hRegistry, lambdaSelection, lambdaSelection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairLambdaLambdaHistSpec, cprHistSpecPos, cprHistSpecNeg); + } + + // setup for k0short + if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { + auto k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); + auto pairLambdaLambdaHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning); + pairLambdaLambdaBuilder.init(&hRegistry, k0shortSelection, k0shortSelection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairLambdaLambdaHistSpec, cprHistSpecPos, cprHistSpecNeg); + } + + if (((doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent) + (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent)) > 1) { + LOG(fatal) << "Can only process lambda-tracks Or k0short-tracks"; + } + }; + + void processLambdaLambdaSameEvent(FilteredCollision const& col, Tracks const& tracks, Lambdas const& lambdas) + { + pairLambdaLambdaBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition, lambdaPartition, cache); + } + PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaSameEvent, "Enable processing same event processing for lambdas", true); + + void processLambdaLambdaMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, Lambdas const& /*lambas*/) + { + pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdaPartition, lambdaPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaMixedEvent, "Enable processing mixed event processing for lambdas", true); + + void processK0shortK0shortSameEvent(FilteredCollision const& col, Tracks const& tracks, K0shorts const& k0shorts) + { + pairK0shortK0shortBuilder.processSameEvent(col, tracks, k0shorts, k0shortPartition, lambdaPartition, cache); + } + PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortSameEvent, "Enable processing same event processing for lambdas", true); + + void processK0shortK0shortMixedEvent(FilteredCollisions const& cols, Tracks const& tracks, K0shorts const& /*k0shorts*/) + { + pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shortPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortMixedEvent, "Enable processing mixed event processing for lambdas", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoTrackQa.cxx b/PWGCF/Femto/Tasks/femtoTrackQa.cxx new file mode 100644 index 00000000000..ddc9aeb4806 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoTrackQa.cxx @@ -0,0 +1,98 @@ +// 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 femtoTrackQa.cxx +/// \brief QA task for tracks +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoTrackQa { + + // setup tables + using FemtoCollisions = o2::soa::Join; + using FemtoCollision = FemtoCollisions::iterator; + + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + using FemtoTracks = o2::soa::Join; + + SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; + colhistmanager::CollisionHistManager colHistManager; + + // setup tracks + trackbuilder::ConfTrackSelection1 trackSelections; + trackhistmanager::ConfTrackBinning1 confTrackBinning; + trackhistmanager::ConfTrackQaBinning1 confTrackQaBinning; + trackhistmanager::TrackHistManager trackHistManager; + + Partition trackPartition = MAKE_TRACK_PARTITION(trackSelections); + Preslice perColReco = femtobase::stored::fColId; + + HistogramRegistry hRegistry{"FemtoTrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + // create a map for histogram specs + auto colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionQaBinning); + auto trackHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confTrackBinning, confTrackQaBinning); + trackHistManager.init(&hRegistry, trackHistSpec, confTrackQaBinning, trackSelections.chargeAbs.value); + }; + + void process(FilteredFemtoCollision const& col, FemtoTracks const& tracks) + { + colHistManager.fill(col); + auto trackSlice = trackPartition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& track : trackSlice) { + trackHistManager.fill(track, tracks); + } + } +}; + +WorkflowSpec + defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoTwotrackresonanceQa.cxx b/PWGCF/Femto/Tasks/femtoTwotrackresonanceQa.cxx new file mode 100644 index 00000000000..501312fb3f0 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoTwotrackresonanceQa.cxx @@ -0,0 +1,182 @@ +// 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 femtoTwotrackresonanceQa.cxx +/// \brief Qa task for two track resonances +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/Core/twoTrackResonanceBuilder.h" +#include "PWGCF/Femto/Core/twoTrackResonanceHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoTwotrackresonanceQa { + + // setup tables + using FemtoCollisions = o2::soa::Join; + using FemtoCollision = FemtoCollisions::iterator; + + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + using FemtoPhis = o2::soa::Join; + using FemtoRho0s = o2::soa::Join; + using FemtoKstar0s = o2::soa::Join; + using FemtoTracks = o2::soa::Join; + + SliceCache cache; + + // setup for collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::CollisionHistManager colHistManager; + colhistmanager::ConfCollisionBinning confCollisionBinning; + colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; + + // setup for phis + twotrackresonancebuilder::ConfPhiSelection confPhiSelection; + Partition phiPartition = MAKE_RESONANCE_0_PARTITON(confPhiSelection); + Preslice perColPhis = femtobase::stored::fColId; + + twotrackresonancehistmanager::ConfPhiBinning confPhiBinning; + twotrackresonancehistmanager::TwoTrackResonanceHistManager< + twotrackresonancehistmanager::PrefixPhi, + trackhistmanager::PrefixResonancePosDaughterQa, + trackhistmanager::PrefixResonanceNegDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::TwoTrackResonance::kPhi> + phiHistManager; + + // setup for rho0s + twotrackresonancebuilder::ConfRho0Selection confRho0Selection; + Partition rho0Partition = MAKE_RESONANCE_0_PARTITON(confRho0Selection); + Preslice perColRhos = femtobase::stored::fColId; + + twotrackresonancehistmanager::ConfRho0Binning confRho0Binning; + twotrackresonancehistmanager::TwoTrackResonanceHistManager< + twotrackresonancehistmanager::PrefixRho, + trackhistmanager::PrefixResonancePosDaughterQa, + trackhistmanager::PrefixResonanceNegDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::TwoTrackResonance::kRho0> + rho0HistManager; + + // setup for kstar0s + twotrackresonancebuilder::ConfKstar0Selection confKstar0Selection; + Partition kstar0Partition = MAKE_RESONANCE_1_PARTITON(confKstar0Selection); + Preslice perColKstars = femtobase::stored::fColId; + + twotrackresonancehistmanager::ConfKstar0Binning confKstar0Binning; + twotrackresonancehistmanager::TwoTrackResonanceHistManager< + twotrackresonancehistmanager::PrefixKstar, + trackhistmanager::PrefixResonancePosDaughterQa, + trackhistmanager::PrefixResonanceNegDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::TwoTrackResonance::kKstar0> + kstar0HistManager; + + // setup for daughters + trackhistmanager::ConfResonancePosDauBinning confPosDaughterBinning; + trackhistmanager::ConfResonancePosDauQaBinning confPosDaughterQaBinning; + trackhistmanager::ConfResonanceNegDauBinning confNegDaughterBinning; + trackhistmanager::ConfResonanceNegDauQaBinning confNegDaughterQaBinning; + + HistogramRegistry hRegistry{"ResonanceQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + // create a map for histogram specs + auto colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionQaBinning); + + auto posDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confPosDaughterBinning, confPosDaughterQaBinning); + auto negDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confNegDaughterBinning, confNegDaughterQaBinning); + + if ((doprocessPhis + doprocessRho0s + doprocessKstar0s) > 1) { + LOG(fatal) << "Only one process can be activated"; + } + + if (doprocessPhis) { + auto phiHistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceQaHistSpecMap(confPhiBinning); + phiHistManager.init(&hRegistry, phiHistSpec, posDaughterHistSpec, confPosDaughterQaBinning, negDaughterHistSpec, confNegDaughterQaBinning); + } + if (doprocessRho0s) { + auto rho0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceQaHistSpecMap(confRho0Binning); + rho0HistManager.init(&hRegistry, rho0HistSpec, posDaughterHistSpec, confPosDaughterQaBinning, negDaughterHistSpec, confNegDaughterQaBinning); + } + + if (doprocessKstar0s) { + auto kstar0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceQaHistSpecMap(confKstar0Binning); + kstar0HistManager.init(&hRegistry, kstar0HistSpec, posDaughterHistSpec, confPosDaughterQaBinning, negDaughterHistSpec, confNegDaughterQaBinning); + } + }; + + void processPhis(FilteredFemtoCollision const& col, FemtoPhis const& /*phis*/, FemtoTracks const& tracks) + { + colHistManager.fill(col); + auto phiSlice = phiPartition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& phi : phiSlice) { + phiHistManager.fill(phi, tracks); + } + }; + PROCESS_SWITCH(FemtoTwotrackresonanceQa, processPhis, "Process Phis", true); + + void processRho0s(FilteredFemtoCollision const& col, FemtoRho0s const& /*rho0s*/, FemtoTracks const& tracks) + { + colHistManager.fill(col); + auto rho0Slice = rho0Partition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& rho0 : rho0Slice) { + rho0HistManager.fill(rho0, tracks); + } + }; + PROCESS_SWITCH(FemtoTwotrackresonanceQa, processRho0s, "Process Rho0s", false); + + void processKstar0s(FilteredFemtoCollision const& col, FemtoKstar0s const& /*kstar0s*/, FemtoTracks const& tracks) + { + colHistManager.fill(col); + auto kstar0Slice = kstar0Partition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& kstar0 : kstar0Slice) { + kstar0HistManager.fill(kstar0, tracks); + } + }; + PROCESS_SWITCH(FemtoTwotrackresonanceQa, processKstar0s, "Process Kstar0s", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoV0Qa.cxx b/PWGCF/Femto/Tasks/femtoV0Qa.cxx new file mode 100644 index 00000000000..20f6f1d0d0e --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoV0Qa.cxx @@ -0,0 +1,156 @@ +// 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 femtoV0Qa.cxx +/// \brief QA task for v0s +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGCF/Femto/Core/v0HistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/InitContext.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femto; + +struct FemtoV0Qa { + + using FemtoCollisions = o2::soa::Join; + + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + using FemtoLambdas = o2::soa::Join; + using FemtoK0shorts = o2::soa::Join; + using FemtoTracks = o2::soa::Join; + + SliceCache cache; + + // setup for collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::CollisionHistManager colHistManager; + colhistmanager::ConfCollisionBinning confCollisionBinning; + colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; + + // setup for lambdas + v0builder::ConfLambdaSelection1 confLambdaSelection; + + Partition lambdaPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); + Preslice perColLambdas = femtobase::stored::fColId; + + v0histmanager::ConfLambdaBinning1 confLambdaBinning; + v0histmanager::ConfLambdaQaBinning1 confLambdaQaBinning; + v0histmanager::V0HistManager< + v0histmanager::PrefixLambdaQa, + trackhistmanager::PrefixV0PosDaughterQa, + trackhistmanager::PrefixV0NegDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::V0::kLambda> + lambdaHistManager; + + // setup for k0shorts + v0builder::ConfK0shortSelection1 confK0shortSelection; + + Partition k0shortPartition = MAKE_K0SHORT_PARTITION(confK0shortSelection); + Preslice perColK0shorts = femtobase::stored::fColId; + + v0histmanager::ConfK0shortBinning1 confK0shortBinning; + v0histmanager::ConfK0shortQaBinning1 confK0shortQaBinning; + v0histmanager::V0HistManager< + v0histmanager::PrefixK0shortQa, + trackhistmanager::PrefixV0PosDaughterQa, + trackhistmanager::PrefixV0NegDaughterQa, + modes::Mode::kAnalysis_Qa, + modes::V0::kK0short> + k0shortHistManager; + + // setup for daughters + trackhistmanager::ConfV0PosDauBinning confV0PosDaughterBinning; + trackhistmanager::ConfV0PosDauQaBinning confV0PosDaughterQaBinning; + + trackhistmanager::ConfV0NegDauBinning confV0NegDaughterBinning; + trackhistmanager::ConfV0NegDauQaBinning confV0NegDaughterQaBinning; + + HistogramRegistry hRegistry{"FemtoV0Qa", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + // create a map for histogram specs + auto colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionQaBinning); + + auto posDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confV0PosDaughterBinning, confV0PosDaughterQaBinning); + auto negDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confV0NegDaughterBinning, confV0NegDaughterQaBinning); + + if ((doprocessK0short + doprocessLambda) > 1) { + LOG(fatal) << "Only one process can be activated"; + } + + if (doprocessLambda) { + auto lambdaHistSpec = v0histmanager::makeV0QaHistSpecMap(confLambdaBinning, confLambdaQaBinning); + lambdaHistManager.init(&hRegistry, lambdaHistSpec, confLambdaQaBinning, posDaughterHistSpec, confV0PosDaughterQaBinning, negDaughterHistSpec, confV0NegDaughterQaBinning); + } + + if (doprocessK0short) { + auto k0shortHistSpec = v0histmanager::makeV0QaHistSpecMap(confK0shortBinning, confK0shortQaBinning); + k0shortHistManager.init(&hRegistry, k0shortHistSpec, confK0shortQaBinning, posDaughterHistSpec, confV0PosDaughterQaBinning, negDaughterHistSpec, confV0NegDaughterQaBinning); + } + }; + + void processK0short(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoK0shorts const& /*k0shorts*/) + { + colHistManager.fill(col); + auto k0shortSlice = k0shortPartition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& k0short : k0shortSlice) { + k0shortHistManager.fill(k0short, tracks); + } + } + PROCESS_SWITCH(FemtoV0Qa, processK0short, "Process k0shorts", false); + + void processLambda(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/) + { + colHistManager.fill(col); + auto lambdaSlice = lambdaPartition->sliceByCached(femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& lambda : lambdaSlice) { + lambdaHistManager.fill(lambda, tracks); + } + } + PROCESS_SWITCH(FemtoV0Qa, processLambda, "Process lambdas", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/Femto/Utils/CMakeLists.txt b/PWGCF/Femto/Utils/CMakeLists.txt new file mode 100644 index 00000000000..4c182222bf2 --- /dev/null +++ b/PWGCF/Femto/Utils/CMakeLists.txt @@ -0,0 +1,10 @@ +# 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. diff --git a/PWGCF/Femto3D/Core/femto3dPairTask.h b/PWGCF/Femto3D/Core/femto3dPairTask.h index 8480cbcbadd..db5949f4ae0 100755 --- a/PWGCF/Femto3D/Core/femto3dPairTask.h +++ b/PWGCF/Femto3D/Core/femto3dPairTask.h @@ -16,8 +16,7 @@ #ifndef PWGCF_FEMTO3D_CORE_FEMTO3DPAIRTASK_H_ #define PWGCF_FEMTO3D_CORE_FEMTO3DPAIRTASK_H_ -#define THETA(eta) 2.0 * atan(exp(-eta)) - +#define THETA(eta) 2.0 * std::atan(std::exp(-eta)) // #include "Framework/ASoA.h" // #include "Framework/DataTypes.h" // #include "Framework/AnalysisDataModel.h" @@ -31,13 +30,28 @@ #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) { - // if(PDGcode == 2212) return TDatabasePDG::Instance()->GetParticle(2212)->Mass(); - if (PDGcode == 1000010020) - return 1.87561294257; - else - return TDatabasePDG::Instance()->GetParticle(PDGcode)->Mass(); + 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 @@ -71,7 +85,7 @@ inline std::unique_ptr calc_var_bins(const int& N, const float& xmax, bins[N - 1] = xmax; for (int i = 1; i < 0.5 * N - 1; i++) { - bin_edge += winit * pow(q, i); + bin_edge += winit * std::pow(q, i); bins[0.5 * N - 1 - i] = -bin_edge; bins[0.5 * N + i] = bin_edge; } @@ -109,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()); } } @@ -194,6 +208,7 @@ class FemtoPair bool IsIdentical() { return _isidentical; } 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; @@ -207,15 +222,20 @@ class FemtoPair } float GetPhiStarDiff(const float& radius = 1.2) const { - if (_first != NULL && _second != NULL) - return _first->phiStar(_magfield1, radius) - _second->phiStar(_magfield2, radius); - else + if (_first != NULL && _second != NULL) { + float dphi = _first->phiStar(_magfield1, radius) - _second->phiStar(_magfield2, radius); + return std::fabs(dphi) > o2::constants::math::PI ? (1.0 - 2.0 * o2::constants::math::PI / std::fabs(dphi)) * dphi : dphi; + } 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; @@ -252,14 +272,32 @@ bool FemtoPair::IsClosePair(const float& deta, const float& dphi, con return true; if (_magfield1 * _magfield2 == 0) return true; - if (std::pow(abs(GetEtaDiff()) / deta, 2) + std::pow(abs(GetPhiStarDiff(radius)) / dphi, 2) < 1.0f) + const float relEtaDiff = GetEtaDiff() / deta; + const float relPhiStarDiff = GetPhiStarDiff(radius) / dphi; + if ((relEtaDiff * relEtaDiff + relPhiStarDiff * relPhiStarDiff) < 1.0f) return true; - // if (abs(GetEtaDiff()) < deta && abs(GetPhiStarDiff(radius)) < dphi) + // 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 { @@ -272,12 +310,31 @@ float FemtoPair::GetAvgSep() const float res = 0.0; for (const auto& radius : TPCradii) { - res += sqrt(pow(2.0 * radius * sin(0.5 * GetPhiStarDiff(radius)), 2) + pow(2.0 * radius * sin(0.5 * dtheta), 2)); + 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) { + res += GetPhiStarDiff(radius); + } + + return res / TPCradii.size(); +} + template float FemtoPair::GetKstar() const { @@ -323,8 +380,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 @@ -346,6 +404,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 index 5c78911a3e1..d7f4f0822d3 100644 --- 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,6 +57,32 @@ 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 { @@ -70,6 +98,7 @@ struct binningParent { 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() { @@ -78,32 +107,35 @@ struct binningParent { } }; -using nsigma = binningParent(-10.f, 10.f)>; -using dca_v0 = binningParent(-1.f, 1.f)>; -using dca_v1 = binningParent(-1.f, 1.f), int16_t>; -using dca = dca_v1; +// 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; + +// 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; + 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); }); - +DECLARE_SOA_DYNAMIC_COLUMN(dIsGoodITSLayersAll, isGoodITSLayersAll, [](uint64_t selBit) -> bool { return TESTBIT(selBit, evsel::kIsGoodITSLayersAll); }); } // namespace singletrackselector DECLARE_SOA_TABLE(SingleCollSels, "AOD", "SINGLECOLLSEL", // Table of the variables for single track selection. @@ -113,12 +145,6 @@ DECLARE_SOA_TABLE(SingleCollSels, "AOD", "SINGLECOLLSEL", // Table of the variab singletrackselector::PosZ, singletrackselector::MagField); -DECLARE_SOA_TABLE(SingleCollExtras_v0, "AOD", "SINGLECOLLEXTRA", // Joinable collision table with Pile-Up flags - singletrackselector::IsNoSameBunchPileup, - singletrackselector::IsGoodZvtxFT0vsPV, - singletrackselector::IsVertexITSTPC, - singletrackselector::HadronicRate); - DECLARE_SOA_TABLE(SingleCollExtras_v1, "AOD", "SINGLECOLLEXTR1", // Joinable collision table with Pile-Up flags evsel::Selection, singletrackselector::HadronicRate, @@ -128,20 +154,27 @@ DECLARE_SOA_TABLE(SingleCollExtras_v1, "AOD", "SINGLECOLLEXTR1", // Joinable col singletrackselector::dIsGoodZvtxFT0vsPV, singletrackselector::dIsVertexITSTPC, singletrackselector::dIsVertexTOForTRDmatched, - singletrackselector::dNoCollInTimeRangeStandard); + singletrackselector::dNoCollInTimeRangeStandard, + singletrackselector::dIsGoodITSLayersAll); 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 (only stored in v0) +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_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++) { @@ -150,202 +183,295 @@ DECLARE_SOA_DYNAMIC_COLUMN(ITSNClsDyn, itsNCls, [](uint32_t itsClusterSizes) -> } return itsNcls; }); -DECLARE_SOA_COLUMN(ITSclsMap, itsClsMap, uint8_t); -DECLARE_SOA_COLUMN(ITSclusterSizes, itsClusterSizes, uint32_t); - -DECLARE_SOA_COLUMN(StoredDcaXY, storedDcaXY, binning::dca_v0::binned_t); // impact parameter of the track with 8 bits (v0) -DECLARE_SOA_COLUMN(StoredDcaZ, storedDcaZ, binning::dca_v0::binned_t); // impact parameter of the track with 8 bits (v0) -DECLARE_SOA_COLUMN(StoredDcaXY_v1, storedDcaXY_v1, binning::dca_v1::binned_t); // impact parameter of the track with 16 bits (v1) -DECLARE_SOA_COLUMN(StoredDcaZ_v1, storedDcaZ_v1, binning::dca_v1::binned_t); // impact parameter of the track with 16 bits (v1) -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(StoredTOFNSigmaHe, storedTofNSigmaHe, binning::nsigma::binned_t); -DECLARE_SOA_COLUMN(StoredTPCNSigmaHe, storedTpcNSigmaHe, binning::nsigma::binned_t); -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_DYNAMIC_COLUMN(DcaXY_v0, dcaXY, - [](binning::dca_v0::binned_t dca_binned) -> float { return singletrackselector::unPack(dca_binned); }); -DECLARE_SOA_DYNAMIC_COLUMN(DcaZ_v0, dcaZ, - [](binning::dca_v0::binned_t dca_binned) -> float { return singletrackselector::unPack(dca_binned); }); -DECLARE_SOA_DYNAMIC_COLUMN(DcaXY_v1, dcaXY, - [](binning::dca_v1::binned_t dca_binned) -> float { return singletrackselector::unPack(dca_binned); }); -DECLARE_SOA_DYNAMIC_COLUMN(DcaZ_v1, dcaZ, - [](binning::dca_v1::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); }); + +//------------------------------------ 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::unPack(nsigma_binned); }); + [](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::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 +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_v0, "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_v0, - singletrackselector::DcaZ_v0, - 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_FULL(SingleTrackSels_v1, "SelTracks", "AOD", "SINGLETRACKSEL1", // 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_v1, - singletrackselector::StoredDcaZ_v1, - singletrackselector::StoredTPCChi2NCl, - singletrackselector::StoredITSChi2NCl, - singletrackselector::StoredTPCCrossedRowsOverFindableCls, - - singletrackselector::StoredTOFNSigmaPi, - singletrackselector::StoredTPCNSigmaPi, - singletrackselector::StoredTOFNSigmaKa, - singletrackselector::StoredTPCNSigmaKa, - singletrackselector::StoredTOFNSigmaPr, - singletrackselector::StoredTPCNSigmaPr, - singletrackselector::StoredTOFNSigmaDe, - singletrackselector::StoredTPCNSigmaDe, - singletrackselector::StoredTOFNSigmaHe, - singletrackselector::StoredTPCNSigmaHe, - - singletrackselector::ITSNClsDyn, - track::v001::ITSClsSizeInLayer, - singletrackselector::DcaXY_v1, - singletrackselector::DcaZ_v1, - 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_v1; +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, @@ -365,6 +491,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 @@ -378,80 +508,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 1000020030: - Nsigma = track.tpcNSigmaHe(); - 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, 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 = -1000; - switch (PDG) { - case 2212: - Nsigma = track.tofNSigmaPr(); - break; - case 1000010020: - Nsigma = track.tofNSigmaDe(); - break; - case 1000020030: - Nsigma = track.tofNSigmaHe(); - 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 index aba3d3c728f..a8176ef1ad0 100644 --- a/PWGCF/Femto3D/TableProducer/CMakeLists.txt +++ b/PWGCF/Femto3D/TableProducer/CMakeLists.txt @@ -9,17 +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 O2Physics::AnalysisCore O2Physics::AnalysisCCDB + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(single-track-selector-converter - SOURCES singleTrackSelectorConverter.cxx +o2physics_add_dpl_workflow(single-track-selector-extra + SOURCES singleTrackSelectorExtra.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(single-track-selector-extra - SOURCES singleTrackSelectorExtra.cxx +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 + COMPONENT_NAME Analysis) 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/singleTrackSelectorConverter.cxx b/PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverter.cxx similarity index 98% rename from PWGCF/Femto3D/TableProducer/singleTrackSelectorConverter.cxx rename to PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverter.cxx index 2fe7126ff95..4a44e331e9b 100644 --- a/PWGCF/Femto3D/TableProducer/singleTrackSelectorConverter.cxx +++ b/PWGCF/Femto3D/TableProducer/Converters/singleTrackSelectorConverter.cxx @@ -26,7 +26,7 @@ using namespace o2::aod; //::singletrackselector; // the namespace defined in .h struct singleTrackSelectorConverter { - Produces tableRow; + Produces tableRow; void init(InitContext&) {} 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 8172d07bbf0..2710513529f 100644 --- a/PWGCF/Femto3D/TableProducer/singleTrackSelector.cxx +++ b/PWGCF/Femto3D/TableProducer/singleTrackSelector.cxx @@ -13,26 +13,32 @@ /// \author Sofia Tomassini, Gleb Romanenko, Nicolò Jacazio /// \since 31 May 2023 -#include -#include - -#include - #include "PWGCF/Femto3D/DataModel/singletrackselector.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/CCDB/ctpRateFetcher.h" -#include "DetectorsBase/Propagator.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include + +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -44,9 +50,15 @@ 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 CBThadronPID{"CBThadronPID", false, "Apply ev. sel. based on RCT flag `hadronPID`"}; // more in Common/CCDB/RCTSelectionFlags.h 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"}; @@ -62,9 +74,12 @@ struct singleTrackSelector { 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)"}; + Configurable> _ptRemoveTofOutOfRange{"ptRemoveTofOutOfRange", {100.f, -10.f, 10.f}, "transverse momentum starting from which request TOF nSigma to be within the stored range (-10 < Nsigma < 10)"}; Configurable _min_P{"min_P", 0.f, "lower mometum limit"}; Configurable _max_P{"max_P", 100.f, "upper mometum limit"}; + Configurable _min_Pt{"min_Pt", 0.f, "lower trasnverse mometum limit"}; + Configurable _max_Pt{"max_Pt", 100.f, "upper trasnverse mometum limit"}; 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"}; @@ -76,9 +91,9 @@ struct singleTrackSelector { using Trks = soa::Join; using CollRun2 = soa::Join; @@ -89,7 +104,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)) || @@ -98,9 +123,10 @@ struct singleTrackSelector { Filter trackFilter = ((o2::aod::track::itsChi2NCl <= 36.f) && (o2::aod::track::itsChi2NCl >= 0.f) && (o2::aod::track::tpcChi2NCl >= 0.f) && (o2::aod::track::tpcChi2NCl <= 4.f)); Filter pFilter = o2::aod::track::p > _min_P&& o2::aod::track::p < _max_P; + Filter ptFilter = o2::aod::track::pt > _min_Pt&& o2::aod::track::pt < _max_Pt; Filter etaFilter = nabs(o2::aod::track::eta) < _eta; Filter dcaFilter = ((nabs(o2::aod::track::dcaXY) <= _dcaXY) && (nabs(o2::aod::track::dcaZ) <= _dcaZ)) && - ((o2::aod::track::dcaXY >= _dcaXYmin) && (o2::aod::track::dcaZ >= _dcaZmin)); + ((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 @@ -110,28 +136,43 @@ struct singleTrackSelector { std::vector particlesToKeep; std::vector particlesToReject; - HistogramRegistry registry{"registry"}; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; SliceCache cache; + rctsel::RCTFlagsChecker myChecker{"CBT_hadronPID"}; + void init(InitContext&) { particlesToKeep = _particlesToKeep; particlesToReject = _particlesToReject; + if (applySkimming) { + zorroSummary.setObject(zorro.getZorroSummary()); + } ccdb->setURL(ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + myChecker.init("CBT_hadronPID", true); + + 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"}}}); + registry.add("hGen_EtaPhiPt_Proton", "Gen (anti)protons in true collisions", {HistType::kTH3F, {{100, -1., 1., "#eta"}, {157, 0., o2::constants::math::TwoPI, "#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., o2::constants::math::TwoPI, "#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., o2::constants::math::TwoPI, "#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., o2::constants::math::TwoPI, "#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., o2::constants::math::TwoPI, "#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., o2::constants::math::TwoPI, "#phi"}, {100, -5.f, 5.f, "p_{T} GeV/c"}}}); } } @@ -142,6 +183,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; @@ -164,12 +210,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; @@ -189,11 +236,14 @@ 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 (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; + if (track.pt() > _ptRemoveTofOutOfRange.value[0] && !o2::aod::singletrackselector::TOFselection(track, std::make_pair(ii, std::vector{_ptRemoveTofOutOfRange.value[1], _ptRemoveTofOutOfRange.value[2]}), std::vector{-10.f, +10.f})) + continue; tableRow(tableRowColl.lastIndex(), track.p(), @@ -204,27 +254,37 @@ struct singleTrackSelector { track.tpcNClsShared(), track.itsClusterMap(), track.itsClusterSizes(), - - singletrackselector::packInTable(track.dcaXY()), - singletrackselector::packInTable(track.dcaZ()), + 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.tofNSigmaHe()), - singletrackselector::packInTable(track.tpcNSigmaHe())); + 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()) { @@ -244,14 +304,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); @@ -285,10 +352,25 @@ 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); + + if (!myChecker(*collision) && CBThadronPID) + return; + + 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 @@ -352,8 +434,11 @@ struct singleTrackSelector { } 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); @@ -386,8 +471,12 @@ 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.; @@ -492,7 +581,7 @@ struct singleTrackSelector { return; } - if (abs(mcCollision.posZ()) > _vertexZ) { + if (std::fabs(mcCollision.posZ()) > _vertexZ) { return; } diff --git a/PWGCF/Femto3D/TableProducer/singleTrackSelectorExtra.cxx b/PWGCF/Femto3D/TableProducer/singleTrackSelectorExtra.cxx index d83568a18a5..0f065371ca8 100644 --- a/PWGCF/Femto3D/TableProducer/singleTrackSelectorExtra.cxx +++ b/PWGCF/Femto3D/TableProducer/singleTrackSelectorExtra.cxx @@ -34,27 +34,13 @@ struct singleTrackSelectorDummy { Produces tableRowCollExtra; - void processDefault(aod::SingleCollSels::iterator const&) + void process(aod::SingleCollSels::iterator const&) { uint64_t selection = 0; tableRowCollExtra(selection, 0.0, 0); } - PROCESS_SWITCH(singleTrackSelectorDummy, processDefault, "filling the CollExtra table with dummy values", true); - - void processExtra_v0(soa::Join::iterator const& collision) - { - uint64_t selection = 0; - selection |= collision.isNoSameBunchPileup() ? BIT(evsel::kNoSameBunchPileup) : 0; - selection |= collision.isGoodZvtxFT0vsPV() ? BIT(evsel::kIsGoodZvtxFT0vsPV) : 0; - selection |= collision.isVertexITSTPC() ? BIT(evsel::kIsVertexITSTPC) : 0; - - tableRowCollExtra(selection, - collision.hadronicRate(), - 0); - } - PROCESS_SWITCH(singleTrackSelectorDummy, processExtra_v0, "process using info from the previous version of stored CollExtra table", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) 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 index 62a7b310690..4090fea6795 100644 --- a/PWGCF/Femto3D/Tasks/CMakeLists.txt +++ b/PWGCF/Femto3D/Tasks/CMakeLists.txt @@ -22,4 +22,9 @@ o2physics_add_dpl_workflow(femto3d-pair-task o2physics_add_dpl_workflow(femto3d-pair-task-mc SOURCES femto3dPairTaskMC.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) \ No newline at end of file + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto3d-pid-optimization + SOURCES PIDoptimization.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto3D/Tasks/PIDoptimization.cxx b/PWGCF/Femto3D/Tasks/PIDoptimization.cxx new file mode 100644 index 00000000000..b79d3ca8b55 --- /dev/null +++ b/PWGCF/Femto3D/Tasks/PIDoptimization.cxx @@ -0,0 +1,305 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 optimization of particle identification for femtoscopic analysis. +/// \author Sofia Tomassini +/// \since July 2025 + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" +#include "TMath.h" +#include "TRandom3.h" +#include + +#include "fairlogger/Logger.h" + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +namespace o2::aod +{ +using SelectedTracks = soa::Join; +} +struct PidOptimization { + + HistogramRegistry histos{"Histos"}; + + 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", 20.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", 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"}; + Configurable _tpcFractionSharedCls{"maxTpcFractionSharedCls", 0.4, "maximum fraction of TPC shared clasters"}; + Configurable _itsNCls{"minItsNCls", 0, "minimum allowed number of ITS clasters for a track"}; + 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::pair{-100, 100}, "Nsigma range in TPC before the TOF is used"}; + Configurable> _itsNSigma{"itsNSigma", std::pair{-100, 100}, "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::pair{-100, 100}, "Nsigma range in TOF"}; + Configurable> _tpcNSigmaResidual{"tpcNSigmaResidual", std::pair{-10, 10}, "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::pair{-10, 10}, "TOF rejection Nsigma range for particles specified with PDG to be rejected"}; + + std::shared_ptr ITShisto; + std::shared_ptr TPChisto; + std::shared_ptr TOFhisto; + std::shared_ptr ITSvsTPChisto; + std::shared_ptr dcaxy_p; + std::shared_ptr dcaxy_pt; + std::shared_ptr dcaz_p; + std::shared_ptr dcaz_pt; + + void init(o2::framework::InitContext& context) + { + o2::aod::ITSResponse::setParameters(context); + histos.add("vtz", "vtz", kTH1F, {{100, -20., 20., "vtxz"}}); + histos.add("eta", "eta", kTH1F, {{200, -2.5, 2.5, "eta"}}); + histos.add("phi", "phi", kTH1F, {{200, 0., 2. * M_PI, "phi"}}); + histos.add("px", "px", kTH1F, {{100, 0., 5., "px"}}); + histos.add("py", "py", kTH1F, {{100, 0., 5., "py"}}); + histos.add("pz", "pz", kTH1F, {{100, 0., 5., "pz"}}); + histos.add("p", "p", kTH1F, {{100, 0., 5., "p"}}); + histos.add("pt", "pt", kTH1F, {{100, 0., 5., "pt"}}); + histos.add("sign", "sign", kTH1F, {{3, -1.5, 1.5, "sign"}}); + histos.add("TPCClusters", "TPCClusters", kTH1F, {{163, -0.5, 162.5, "NTPCClust"}}); + histos.add("TPCCrossedRowsOverFindableCls", "TPCCrossedRowsOverFindableCls", kTH1F, {{100, 0.0, 10.0, "NcrossedRowsOverFindable"}}); + histos.add("TPCFractionSharedCls", "TPCFractionSharedCls", kTH1F, {{100, 0.0, 1.0, "TPCsharedFraction"}}); + histos.add("ITSClusters", "ITSClusters", kTH1F, {{10, -0.5, 9.5, "NITSClust"}}); + histos.add("ITSchi2", "ITSchi2", kTH1F, {{100, 0.0, 40., "ITSchi2"}}); + histos.add("TPCchi2", "TPCchi2", kTH1F, {{100, 0.0, 6., "TPCchi2"}}); + + dcaxy_p = histos.add("dcaxy_p", "dcaxy_p", kTH2F, {{100, 0., 5.0, "p"}, {500, -0.5, 0.5, "dcaxy"}}); + dcaxy_pt = histos.add("dcaxy_pt", "dcaxy_pt", kTH2F, {{100, 0., 5.0, "pt"}, {500, -0.5, 0.5, "dcaxy"}}); + dcaz_p = histos.add("dcaz_p", "dcaz_p", kTH2F, {{100, 0., 5.0, "p"}, {500, -0.5, 0.5, "dcaz"}}); + dcaz_pt = histos.add("dcaz_pt", "dcaz_pt", kTH2F, {{100, 0., 5.0, "pt"}, {500, -0.5, 0.5, "dcaxy"}}); + + ITShisto = histos.add(Form("nsigmaITS_PDG%i", _particlePDG.value), Form("nsigmaITS_PDG%i", _particlePDG.value), kTH2F, {{100, 0., 10.}, {1000, -50., 50.}}); + TPChisto = histos.add(Form("nsigmaTPC_PDG%i", _particlePDG.value), Form("nsigmaTPC_PDG%i", _particlePDG.value), kTH2F, {{100, 0., 10.}, {1000, -50., 50.}}); + TOFhisto = histos.add(Form("nsigmaTOF_PDG%i", _particlePDG.value), Form("nsigmaTOF_PDG%i", _particlePDG.value), kTH2F, {{100, 0., 10.}, {2000, -100., 100.}}); + + ITSvsTPChisto = histos.add(Form("nsigmaITSvsTPC_PDG%i", _particlePDG.value), Form("nsigmaITSvsTPC_PDG%i", _particlePDG.value), kTH2F, {{1000, -50., 50.}, {1000, -50., 50.}}); + } + + 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 0: + return -1000.0; + default: + LOG(fatal) << "Cannot interpret PDG for ITS selection: " << PDG; + return -1000.0; + } + } + template + inline float getTPCNsigma(TrackType const& track, int const& PDG) + { + switch (PDG) { + case 211: + return track.tpcNSigmaPi(); + case 321: + return track.tpcNSigmaKa(); + case 2212: + return track.tpcNSigmaPr(); + case 1000010020: + return track.tpcNSigmaDe(); + case 0: + return -1000.0; + default: + LOG(fatal) << "Cannot interpret PDG for TPC selection: " << PDG; + return -1000.0; + } + } + template + inline float getTOFNsigma(TrackType const& track, int const& PDG) + { + switch (PDG) { + case 211: + return track.tofNSigmaPi(); + case 321: + return track.tofNSigmaKa(); + case 2212: + return track.tofNSigmaPr(); + case 1000010020: + return track.tofNSigmaDe(); + case 0: + return -1000.0; + default: + LOG(fatal) << "Cannot interpret PDG for TOF selection: " << PDG; + return -1000.0; + } + } + + bool isInRange(float value, std::pair range) + { + return value > range.first && value < range.second; + } + + void process(soa::Join const& collisions, aod::SelectedTracks const& tracks) + { + auto tracksWithItsPid = soa::Attach(tracks); + + for (auto& collision : collisions) { + if (!collision.sel8() || abs(collision.posZ()) > _vertexZ) + continue; + if (_requestGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) + continue; + if (_removeSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + continue; + if (_requestGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + if (_requestVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + continue; + // if (_requestVertexTOForTRDmatched > collision.selection_bit(o2::aod::evsel::kisVertexTOForTRDmatched())) + // continue; + if (_requestNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + 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.trackOccupancyInTimeRange() < _OccupancyCut.value.first || collision.trackOccupancyInTimeRange() >= _OccupancyCut.value.second) + continue; + + histos.fill(HIST("vtz"), collision.posZ()); + } + + for (auto& track : tracksWithItsPid) { + if (track.sign() != _sign) + continue; + if (track.p() < _min_P || track.p() > _max_P || abs(track.eta()) > _eta) + continue; + if ((track.itsChi2NCl() >= _itsChi2NCl) || (track.itsChi2NCl() <= 0.f) || (track.tpcChi2NCl() <= 0.f) || (track.tpcChi2NCl() >= _tpcChi2NCl)) + continue; + if ((track.tpcFractionSharedCls()) > _tpcFractionSharedCls || (track.tpcNClsFound()) < _tpcNClsFound || (track.tpcCrossedRowsOverFindableCls()) < _tpcCrossedRowsOverFindableCls || (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; + + bool belowThreshold = track.p() < _PIDtrshld; + float tpcSigma = getTPCNsigma(track, _particlePDG); + float itsSigma = getITSNsigma(track, _particlePDG); + float tofSigma = getTOFNsigma(track, _particlePDG); + float tofRejection = getTOFNsigma(track, _particlePDGtoReject); + + bool passTPC = belowThreshold ? isInRange(tpcSigma, _tpcNSigma.value) : isInRange(tpcSigma, _tpcNSigmaResidual.value); + + bool passITS = belowThreshold ? isInRange(itsSigma, _itsNSigma.value) : true; + + bool passTOF = belowThreshold ? true : (isInRange(tofSigma, _tofNSigma.value) && !isInRange(tofRejection, _rejectWithinNsigmaTOF.value)); + + if (passTPC && passITS && passTOF) { + histos.fill(HIST("eta"), track.eta()); + histos.fill(HIST("phi"), track.phi()); + histos.fill(HIST("px"), track.px()); + histos.fill(HIST("py"), track.py()); + histos.fill(HIST("pz"), track.pz()); + histos.fill(HIST("p"), track.p()); + histos.fill(HIST("pt"), track.pt()); + histos.fill(HIST("sign"), track.sign()); + histos.fill(HIST("dcaxy_p"), track.p(), track.dcaXY()); + histos.fill(HIST("dcaxy_pt"), track.pt(), track.dcaXY()); + histos.fill(HIST("dcaz_p"), track.p(), track.dcaZ()); + histos.fill(HIST("dcaz_pt"), track.pt(), track.dcaZ()); + histos.fill(HIST("TPCClusters"), track.tpcNClsFound()); + histos.fill(HIST("TPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("TPCFractionSharedCls"), track.tpcFractionSharedCls()); + histos.fill(HIST("ITSClusters"), track.itsNCls()); + histos.fill(HIST("ITSchi2"), track.itsChi2NCl()); + histos.fill(HIST("TPCchi2"), track.tpcChi2NCl()); + + switch (_particlePDG) { + case 211: + ITShisto->Fill(track.p(), track.itsNSigmaPi()); + TPChisto->Fill(track.p(), track.tpcNSigmaPi()); + TOFhisto->Fill(track.p(), track.tofNSigmaPi()); + ITSvsTPChisto->Fill(track.itsNSigmaPi(), track.tpcNSigmaPi()); + break; + case 321: + ITShisto->Fill(track.p(), track.itsNSigmaKa()); + TPChisto->Fill(track.p(), track.tpcNSigmaKa()); + TOFhisto->Fill(track.p(), track.tofNSigmaKa()); + ITSvsTPChisto->Fill(track.itsNSigmaKa(), track.tpcNSigmaKa()); + break; + case 2212: + ITShisto->Fill(track.p(), track.itsNSigmaPr()); + TPChisto->Fill(track.p(), track.tpcNSigmaPr()); + TOFhisto->Fill(track.p(), track.tofNSigmaPr()); + ITSvsTPChisto->Fill(track.itsNSigmaPr(), track.tpcNSigmaPr()); + break; + case 1000010020: + ITShisto->Fill(track.p(), track.itsNSigmaDe()); + TPChisto->Fill(track.p(), track.tpcNSigmaDe()); + TOFhisto->Fill(track.p(), track.tofNSigmaDe()); + ITSvsTPChisto->Fill(track.itsNSigmaDe(), track.tpcNSigmaDe()); + break; + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Femto3D/Tasks/femto3dPairTask.cxx b/PWGCF/Femto3D/Tasks/femto3dPairTask.cxx index e3f5fa8f0c3..db6c12dc14c 100644 --- a/PWGCF/Femto3D/Tasks/femto3dPairTask.cxx +++ b/PWGCF/Femto3D/Tasks/femto3dPairTask.cxx @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include #include @@ -52,6 +55,7 @@ struct FemtoCorrelations { 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 _requestIsGoodITSLayersAll{"requestIsGoodITSLayersAll", false, "cut time intervals with dead ITS staves"}; 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"}; @@ -71,6 +75,7 @@ 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", std::vector{-5.0f, 5.0f}, "first particle PID: residual TPC Nsigma cut to use with the TOF"}; @@ -78,6 +83,7 @@ struct FemtoCorrelations { 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", std::vector{-5.0f, 5.0f}, "second particle PID: residual TPC Nsigma cut to use with the TOF"}; @@ -85,9 +91,10 @@ struct FemtoCorrelations { 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 _dPhiMode{"dPhiMode", 0, "Flag to choose how to calc. dphi*: 0 - at a fixed TPC radius; 1 - average over different TPC radii;"}; + Configurable _radiusTPC{"radiusTPC", 1.2, "TPC radius to calculate phi_star for"}; 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 _avgSepTPC{"avgSepTPC", 10, "average sep. (cm) in TPC"}; Configurable _vertexNbinsToMix{"vertexNbinsToMix", 10, "Number of vertexZ bins for the mixing"}; @@ -97,6 +104,7 @@ 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 _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 @@ -117,7 +125,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; @@ -139,6 +148,16 @@ struct FemtoCorrelations { 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 @@ -147,7 +166,7 @@ struct FemtoCorrelations { std::vector>> SEhistos_3D; std::vector>> MEhistos_3D; - std::vector>> qLCMSvskStar; + std::vector>> Add3dHistos; std::vector>> DoubleTrack_SE_histos_BC; // BC -- before cutting std::vector>> DoubleTrack_ME_histos_BC; // BC -- before cutting @@ -204,19 +223,26 @@ 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 > -1) { @@ -249,13 +275,16 @@ struct FemtoCorrelations { } } - 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.}}); } } @@ -283,15 +312,15 @@ struct FemtoCorrelations { LOGF(fatal, "kTbin value obtained for a pair exceeds the configured number of kT bins (3D)"); if (_fillDetaDphi % 2 == 0) - DoubleTrack_SE_histos_BC[multBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_SE_histos_BC[multBin][kTbin]->Fill(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); - if (_deta > 0 && _dphi > 0 && Pair->IsClosePair(_deta, _dphi, _radiusTPC)) + if (_deta > 0 && _dphi > 0 && (_dPhiMode.value == 0 ? Pair->IsClosePair(_deta, _dphi, _radiusTPC) : Pair->IsClosePair(_deta, _dphi))) continue; if (_avgSepTPC > 0 && Pair->IsClosePair(_avgSepTPC)) continue; if (_fillDetaDphi > 0) - DoubleTrack_SE_histos_AC[multBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_SE_histos_AC[multBin][kTbin]->Fill(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); kThistos[multBin][kTbin]->Fill(pair_kT); mThistos[multBin][kTbin]->Fill(Pair->GetMt()); // test @@ -332,21 +361,21 @@ struct FemtoCorrelations { if (_fillDetaDphi % 2 == 0) { if (!SE_or_ME) - DoubleTrack_SE_histos_BC[multBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_SE_histos_BC[multBin][kTbin]->Fill(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); else - DoubleTrack_ME_histos_BC[multBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_ME_histos_BC[multBin][kTbin]->Fill(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); } - if (_deta > 0 && _dphi > 0 && Pair->IsClosePair(_deta, _dphi, _radiusTPC)) + if (_deta > 0 && _dphi > 0 && (_dPhiMode.value == 0 ? Pair->IsClosePair(_deta, _dphi, _radiusTPC) : 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->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_SE_histos_AC[multBin][kTbin]->Fill(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); else - DoubleTrack_ME_histos_AC[multBin][kTbin]->Fill(Pair->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_ME_histos_AC[multBin][kTbin]->Fill(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); } if (!SE_or_ME) { @@ -366,7 +395,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(); @@ -379,8 +411,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; @@ -392,6 +424,8 @@ struct FemtoCorrelations { continue; if (_requestNoCollInTimeRangeStandard && !track.template singleCollSel_as>().noCollInTimeRangeStandard()) continue; + if (_requestIsGoodITSLayersAll && !track.template singleCollSel_as>().isGoodITSLayersAll()) + 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)) @@ -400,57 +434,31 @@ struct FemtoCorrelations { continue; if (track.template singleCollSel_as>().occupancy() < _OccupancyCut.value.first || track.template singleCollSel_as>().occupancy() >= _OccupancyCut.value.second) continue; - if (abs(track.dcaXY()) > _dcaXY.value[0] + _dcaXY.value[1] * std::pow(track.pt(), _dcaXY.value[2]) || abs(track.dcaZ()) > _dcaZ.value[0] + _dcaZ.value[1] * std::pow(track.pt(), _dcaZ.value[2])) + 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.value))) { // 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.value))) { // 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) @@ -468,7 +476,8 @@ struct FemtoCorrelations { continue; if (_requestNoCollInTimeRangeStandard && !collision.noCollInTimeRangeStandard()) continue; - + if (_requestIsGoodITSLayersAll && !collision.isGoodITSLayersAll()) + continue; if (selectedtracks_1.find(collision.globalIndex()) == selectedtracks_1.end()) { if (IsIdentical) continue; @@ -478,7 +487,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 index c9da488f56d..252fb5fc410 100644 --- 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 @@ -48,6 +51,7 @@ struct FemtoCorrelationsMC { 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 _requestIsGoodITSLayersAll{"requestIsGoodITSLayersAll", false, "cut time intervals with dead ITS staves"}; 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"}; @@ -67,6 +71,7 @@ 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", std::vector{-5.0f, 5.0f}, "first particle PID: residual TPC Nsigma cut to use with the TOF"}; @@ -74,6 +79,7 @@ struct FemtoCorrelationsMC { 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", std::vector{-5.0f, 5.0f}, "second particle PID: residual TPC Nsigma cut to use with the TOF"}; @@ -81,6 +87,7 @@ struct FemtoCorrelationsMC { 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 _dPhiMode{"dPhiMode", 0, "Flag to choose how to calc. dphi*: 0 - at a fixed TPC radius; 1 - average over different TPC radii;"}; Configurable _radiusTPC{"radiusTPC", 1.2, "TPC radius to calculate phi_star for"}; Configurable _vertexNbinsToMix{"vertexNbinsToMix", 10, "Number of vertexZ bins for the mixing"}; @@ -100,7 +107,8 @@ struct FemtoCorrelationsMC { std::pair> TOFcuts_2; using FilteredCollisions = soa::Join; - using FilteredTracks = soa::Join; + using FilteredTracks = soa::Join; + // using FilteredTracks = soa::Join; typedef std::shared_ptr::iterator> trkType; typedef std::shared_ptr::iterator> colType; @@ -138,6 +146,8 @@ struct FemtoCorrelationsMC { void init(o2::framework::InitContext&) { + o2::aod::ITSResponse::setMCDefaultParameters(); // set MC parametrisation for the ITS PID + IsIdentical = (_sign_1 * _particlePDG_1 == _sign_2 * _particlePDG_2); Pair->SetIdentical(IsIdentical); @@ -249,7 +259,7 @@ 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(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); AvgSep_SE_histos[centBin][kTbin]->Fill(Pair->GetAvgSep()); Pair->ResetPair(); } @@ -273,7 +283,7 @@ 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(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : Pair->GetAvgPhiStarDiff(), Pair->GetEtaDiff()); AvgSep_SE_histos[centBin][kTbin]->Fill(Pair->GetAvgSep()); Pair->ResetPair(); } @@ -296,7 +306,7 @@ 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->GetPhiStarDiff(_radiusTPC), Pair->GetEtaDiff()); + DoubleTrack_ME_histos[centBin][kTbin]->Fill(_dPhiMode.value == 0 ? Pair->GetPhiStarDiff(_radiusTPC) : 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) @@ -321,7 +331,7 @@ 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; @@ -341,17 +351,18 @@ struct FemtoCorrelationsMC { continue; if (_requestNoCollInTimeRangeStandard && !track.template singleCollSel_as>().noCollInTimeRangeStandard()) continue; - + if (_requestIsGoodITSLayersAll && !track.template singleCollSel_as>().isGoodITSLayersAll()) + 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.value))) { + 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.value[0] + _dcaXY.value[1] * std::pow(track.pt(), _dcaXY.value[2]) || abs(track.dcaZ()) > _dcaZ.value[0] + _dcaZ.value[1] * std::pow(track.pt(), _dcaZ.value[2])) + 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()); @@ -365,14 +376,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.value))) { // 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.value[0] + _dcaXY.value[1] * std::pow(track.pt(), _dcaXY.value[2]) || abs(track.dcaZ()) > _dcaZ.value[0] + _dcaZ.value[1] * std::pow(track.pt(), _dcaZ.value[2])) + 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()); @@ -403,7 +414,8 @@ struct FemtoCorrelationsMC { continue; if (_requestNoCollInTimeRangeStandard && !collision.noCollInTimeRangeStandard()) continue; - + if (_requestIsGoodITSLayersAll && !collision.isGoodITSLayersAll()) + continue; if (selectedtracks_1.find(collision.globalIndex()) == selectedtracks_1.end()) { if (IsIdentical) continue; diff --git a/PWGCF/Femto3D/Tasks/femto3dQA.cxx b/PWGCF/Femto3D/Tasks/femto3dQA.cxx index ba04c6c61a0..f9f164d9ae3 100644 --- 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; @@ -40,11 +45,14 @@ struct QAHistograms { /// Construct a registry object with direct declaration HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable _isMC{"isMC", false, ""}; + 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 _requestIsGoodITSLayersAll{"requestIsGoodITSLayersAll", false, "cut time intervals with dead ITS staves"}; 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"}; @@ -63,6 +71,7 @@ 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", std::vector{-5.0f, 5.0f}, "residual TPC Nsigma cut to use with the TOF"}; @@ -72,10 +81,15 @@ struct QAHistograms { 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; - Filter signFilter = o2::aod::singletrackselector::sign == _sign; + std::shared_ptr ITShisto; + std::shared_ptr TPChisto; + std::shared_ptr TOFhisto; + Filter pFilter = o2::aod::singletrackselector::p > _min_P&& o2::aod::singletrackselector::p < _max_P; Filter etaFilter = nabs(o2::aod::singletrackselector::eta) < _eta; @@ -89,9 +103,37 @@ struct QAHistograms { void init(o2::framework::InitContext&) { + + if (_isMC.value) + o2::aod::ITSResponse::setMCDefaultParameters(); // set MC parametrisation for the ITS PID + 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"}}}); @@ -103,10 +145,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"}, {501, -0.5, 0.5, "dcaxy"}}); - registry.add("dcaxy_to_pt", "dcaxy_to_pt", kTH2F, {{100, 0., 5., "pt"}, {501, -0.5, 0.5, "dcaxy"}}); - registry.add("dcaz_to_p", "dcaz_to_p", kTH2F, {{100, 0., 5., "p"}, {501, -0.5, 0.5, "dcaz"}}); - registry.add("dcaz_to_pt", "dcaz_to_pt", kTH2F, {{100, 0., 5., "pt"}, {501, -0.5, 0.5, "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"}}); @@ -117,26 +155,9 @@ 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"}; @@ -160,6 +181,8 @@ struct QAHistograms { continue; if (_requestNoCollInTimeRangeStandard && !collision.noCollInTimeRangeStandard()) continue; + if (_requestIsGoodITSLayersAll && !collision.isGoodITSLayersAll()) + continue; if (collision.multPerc() < _centCut.value.first || collision.multPerc() >= _centCut.value.second) continue; if (collision.hadronicRate() < _IRcut.value.first || collision.hadronicRate() >= _IRcut.value.second) @@ -173,8 +196,9 @@ struct QAHistograms { registry.fill(HIST("IRvsOccupancy"), collision.occupancy(), collision.hadronicRate()); } - for (auto& track : tracks) { - + for (const auto& track : tracks) { + if (track.sign() != _sign) + continue; if (_removeSameBunchPileup && !track.template singleCollSel_as().isNoSameBunchPileup()) continue; if (_requestGoodZvtxFT0vsPV && !track.template singleCollSel_as().isGoodZvtxFT0vsPV()) @@ -185,8 +209,9 @@ struct QAHistograms { continue; if (_requestNoCollInTimeRangeStandard && !track.template singleCollSel_as().noCollInTimeRangeStandard()) continue; - - if (abs(track.template singleCollSel_as().posZ()) > _vertexZ) + if (_requestIsGoodITSLayersAll && !track.template singleCollSel_as().isGoodITSLayersAll()) + continue; + 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; @@ -196,7 +221,7 @@ struct QAHistograms { continue; if ((track.tpcFractionSharedCls()) > _tpcFractionSharedCls || (track.itsNCls()) < _itsNCls) continue; - if (abs(track.dcaXY()) > _dcaXY.value[0] + _dcaXY.value[1] * std::pow(track.pt(), _dcaXY.value[2]) || abs(track.dcaZ()) > _dcaZ.value[0] + _dcaZ.value[1] * std::pow(track.pt(), _dcaZ.value[2])) + 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) { @@ -204,7 +229,7 @@ struct QAHistograms { 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.value))) { + 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()); @@ -224,26 +249,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()); @@ -253,13 +261,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/checkPacking.cxx b/PWGCF/Femto3D/Tools/checkPacking.cxx index baa4322e553..51d26443200 100644 --- a/PWGCF/Femto3D/Tools/checkPacking.cxx +++ b/PWGCF/Femto3D/Tools/checkPacking.cxx @@ -24,22 +24,45 @@ using namespace o2; template -bool process(std::string outputName, int nevents = 100000) +bool process(const TString outputName, const int nevents = 100000) { class Container { public: Container() {} - void operator()(const float toPack) { mPacked = aod::singletrackselector::packInTable(toPack); } + 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::unPack(mPacked); } + float unpack() { return aod::singletrackselector::unPackSymmetric(mPacked); } } container; - const float min = T::binned_min - 2; - const float max = T::binned_max + 2; + 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", "", (max - min) / T::bin_width, - min, 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); @@ -56,31 +79,47 @@ bool process(std::string outputName, int nevents = 100000) huniformPacked->SetLineStyle(2); for (int i = 0; i < nevents; i++) { - float nsigma = gRandom->Gaus(0, 1); - hgaus->Fill(nsigma); - aod::pidutils::packInTable(nsigma, container); + float randomValue = gRandom->Gaus(0, 1); + hgaus->Fill(randomValue); + container(randomValue); hgausPacked->Fill(container.unpack()); - nsigma = gRandom->Uniform(-10, 10); - huniform->Fill(nsigma); - aod::pidutils::packInTable(nsigma, container); + randomValue = gRandom->Uniform(-10, 10); + huniform->Fill(randomValue); + container(randomValue); 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()); + 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(outputName.c_str()); - can->SaveAs(Form("%s]", outputName.c_str())); + 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))); - return gausOk && uniformOk; + 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*/[]) @@ -93,4 +132,11 @@ int main(int /*argc*/, char* /*argv*/[]) 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/CMakeLists.txt b/PWGCF/FemtoDream/CMakeLists.txt index d9a4175dd3a..549fb52a6f6 100644 --- a/PWGCF/FemtoDream/CMakeLists.txt +++ b/PWGCF/FemtoDream/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. # diff --git a/PWGCF/FemtoDream/Core/CMakeLists.txt b/PWGCF/FemtoDream/Core/CMakeLists.txt index 4c182222bf2..da01f4ab983 100644 --- a/PWGCF/FemtoDream/Core/CMakeLists.txt +++ b/PWGCF/FemtoDream/Core/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. # diff --git a/PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h b/PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h new file mode 100644 index 00000000000..da74e7bda3a --- /dev/null +++ b/PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h @@ -0,0 +1,699 @@ +// 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 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 "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" + +#include // FIXME + +#include +#include +#include + +using namespace o2::framework; +using namespace o2::analysis::femtoDream::femtoDreamSelection; + +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()); + const float invMass = isCascOmega ? casc.mOmega() : casc.mXi(); + + 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"), invMass); + 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..4e67c43b40c 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -16,13 +16,20 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMCOLLISIONSELECTION_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMCOLLISIONSELECTION_H_ -#include -#include #include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/EventPlaneHelper.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" + #include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" +#include "TMath.h" + +#include +#include +#include + using namespace o2::framework; namespace o2::analysis::femtoDream @@ -41,7 +48,7 @@ class FemtoDreamCollisionSelection /// \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 addCheckOffline, bool checkRun3) + void setCuts(float zvtxMax, bool checkTrigger, int trig, bool checkOffline, bool addCheckOffline, bool checkRun3, float minSphericity, float sphericityPtmin) { mCutsSet = true; mZvtxMax = zvtxMax; @@ -50,6 +57,8 @@ class FemtoDreamCollisionSelection mCheckOffline = checkOffline; mAddCheckOffline = addCheckOffline; mCheckIsRun3 = checkRun3; + mMinSphericity = minSphericity; + mSphericityPtmin = sphericityPtmin; } /// Initializes histograms for the task @@ -66,6 +75,7 @@ class FemtoDreamCollisionSelection mHistogramRegistry->add("Event/MultNTracksPV", "; MultNTracksPV; Entries", kTH1F, {{200, 0, 200}}); mHistogramRegistry->add("Event/MultNTracklets", "; MultNTrackslets; Entries", kTH1F, {{300, 0, 300}}); mHistogramRegistry->add("Event/MultTPC", "; MultTPC; Entries", kTH1F, {{600, 0, 600}}); + mHistogramRegistry->add("Event/Sphericity", "; Sphericity; Entries", kTH1F, {{100, 0, 1}}); } /// Print some debug information @@ -76,6 +86,8 @@ class FemtoDreamCollisionSelection LOG(info) << "Check trigger: " << mCheckTrigger; LOG(info) << "Trigger: " << mTrigger; LOG(info) << " Check offline: " << mCheckOffline; + LOG(info) << "Min sphericity: " << mMinSphericity; + LOG(info) << "Min Pt (sphericity): " << mSphericityPtmin; } /// Check whether the collisions fulfills the specified selections @@ -136,6 +148,51 @@ 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; + } + + /// Pile-up selection of PbPb collisions + /// \tparam T type of the collision + /// \param col Collision + /// \return whether or not the collisions fulfills the specified selections + template + bool isPileUpCollisionPbPb(C const& col, + bool noSameBunchPileup, bool isGoodITSLayersAll) + { + if ((noSameBunchPileup && !col.selection_bit(aod::evsel::kNoSameBunchPileup)) || (isGoodITSLayersAll && !col.selection_bit(aod::evsel::kIsGoodITSLayersAll))) { + return false; + } + + return true; + } + + /// occupancy selection + /// \tparam T type of the collision + /// \param col Collision + /// \return whether or not the collisions fulfills the specified selections + template + bool occupancySelection(C const& col, + int tpcOccupancyMin, int tpcOccupancyMax) + { + const auto occupancy = col.trackOccupancyInTimeRange(); + if ((occupancy < tpcOccupancyMin || occupancy > tpcOccupancyMax)) { + return false; + } + return true; + } + /// Some basic QA of the event /// \tparam T type of the collision /// \param col Collision @@ -155,6 +212,47 @@ class FemtoDreamCollisionSelection } } + /// Initializes histograms for qn bin + /// \param registry Histogram registry to be passed + void initEPQA(HistogramRegistry* registry) + { + mHistogramQn = registry; + mHistogramQn->add("Event/centFT0CBeforeQn", "; cent", kTH1F, {{10, 0, 100}}); + mHistogramQn->add("Event/centFT0CAfterQn", "; cent", kTH1F, {{10, 0, 100}}); + mHistogramQn->add("Event/centVsqn", "; cent; qn", kTH2F, {{10, 0, 100}, {100, 0, 1000}}); + mHistogramQn->add("Event/centVsqnVsSpher", "; cent; qn; Sphericity", kTH3F, {{10, 0, 100}, {100, 0, 1000}, {100, 0, 1}}); + mHistogramQn->add("Event/qnBin", "; qnBin; entries", kTH1F, {{20, 0, 20}}); + mHistogramQn->add("Event/psiEP", "; #Psi_{EP} (deg); entries", kTH1F, {{100, 0, 180}}); + + return; + } + + /// Initializes histograms for the flow calculation + /// \param registry Histogram registry to be passed + void initFlow(HistogramRegistry* registry, bool doQnSeparation, int mumQnBins = 10, int binPt = 100, int binEta = 32) + { + if (!mCutsSet) { + LOGF(error, "Event selection not set - quitting!"); + } + mReQthisEvt = new TH2D("ReQthisEvt", "", binPt, 0., 5., binEta, -0.8, 0.8); + mImQthisEvt = new TH2D("ImQthisEvt", "", binPt, 0., 5., binEta, -0.8, 0.8); + mReQ2thisEvt = new TH2D("ReQ2thisEvt", "", binPt, 0., 5., binEta, -0.8, 0.8); + mImQ2thisEvt = new TH2D("ImQ2thisEvt", "", binPt, 0., 5., binEta, -0.8, 0.8); + mMQthisEvt = new TH2D("MQthisEvt", "", binPt, 0., 5., binEta, -0.8, 0.8); + mMQWeightthisEvt = new TH2D("MQWeightthisEvt", "", binPt, 0., 5., binEta, -0.8, 0.8); + + mHistogramQn = registry; + mHistogramQn->add("Event/profileC22", "; cent; c22", kTProfile, {{10, 0, 100}}, "s"); + mHistogramQn->add("Event/profileC24", "; cent; c24", kTProfile, {{10, 0, 100}}, "s"); + + if (doQnSeparation) { + for (int iqn(0); iqn < mumQnBins; ++iqn) { + profilesC22.push_back(mHistogramQn->add(("Qn/profileC22_" + std::to_string(iqn)).c_str(), "; cent; c22", kTProfile, {{10, 0, 100}}, "s")); + } + } + return; + } + /// \todo to be implemented! /// Compute the sphericity of an event /// Important here is that the filter on tracks does not interfere here! @@ -165,9 +263,244 @@ class FemtoDreamCollisionSelection /// \param tracks All tracks /// \return value of the sphericity of the event template - float computeSphericity(T1 const& /*col*/, T2 const& /*tracks*/) + float computeSphericity(T1 const& col, T2 const& tracks) + { + double ptTot = 0.; + double s00 = 0.; // elements of the sphericity matrix taken form EPJC72:2124 + double s01 = 0.; + // double s10 = 0.; + double s11 = 0.; + + int numOfTracks = col.numContrib(); + if (numOfTracks < 3) + return -9999.; + + for (auto const& track : tracks) { + double pt = track.pt(); + double eta = track.eta(); + double px = track.px(); + double py = track.py(); + if (TMath::Abs(pt) < mSphericityPtmin || TMath::Abs(eta) > 0.8) { + continue; + } + + ptTot += pt; + + s00 += px * px / pt; + s01 += px * py / pt; + // s10 = s01; + s11 += py * py / pt; + } + + // normalize to total Pt to obtain a linear form: + if (ptTot == 0.) + return -9999.; + s00 /= ptTot; + s11 /= ptTot; + s01 /= ptTot; + + // Calculate the trace of the sphericity matrix: + double T = s00 + s11; + // Calculate the determinant of the sphericity matrix: + double D = s00 * s11 - s01 * s01; // S10 = S01 + + // Calculate the eigenvalues of the sphericity matrix: + double lambda1 = 0.5 * (T + std::sqrt(T * T - 4. * D)); + double lambda2 = 0.5 * (T - std::sqrt(T * T - 4. * D)); + + if ((lambda1 + lambda2) == 0.) + return -9999.; + + double spt = -1.; + + if (lambda2 > lambda1) { + spt = 2. * lambda1 / (lambda1 + lambda2); + } else { + spt = 2. * lambda2 / (lambda1 + lambda2); + } + + mHistogramRegistry->fill(HIST("Event/Sphericity"), spt); + + return spt; + } + + /// Compute the qn-vector(FT0C) of an event + /// \tparam T type of the collision + /// \param col Collision + /// \return value of the qn-vector of FT0C of the event + template + float computeqnVec(T const& col) + { + double qn = std::sqrt(col.qvecFT0CReVec()[0] * col.qvecFT0CReVec()[0] + col.qvecFT0CImVec()[0] * col.qvecFT0CImVec()[0]) * std::sqrt(col.sumAmplFT0C()); + return qn; + } + + /// Compute the event plane of an event + /// \tparam T type of the collision + /// \param col Collision + /// \param nmode EP in which harmonic(default 2nd harmonic) + /// \return angle of the event plane (rad) of FT0C of the event + template + float computeEP(T const& col, int nmode) + { + double EP = ((1. / nmode) * (TMath::ATan2(col.qvecFT0CImVec()[0], col.qvecFT0CReVec()[0]))); + if (EP < 0) + EP += TMath::Pi(); + // atan2 return in rad -pi/2-pi/2, then make it 0-pi + return EP; + } + + /// \return the 1-d qn-vector separator to 2-d + std::vector> getQnBinSeparator2D(std::vector flat, const int numQnBins = 10) + { + size_t nBins = numQnBins + 1; + + if (flat.empty() || flat.size() % nBins != 0) { + LOGP(error, "ConfQnBinSeparator size = {} is not divisible by {}", + flat.size(), nBins); + return {{-999, -999}}; + } + + size_t nCent = flat.size() / nBins; + std::vector> res(nCent, std::vector(nBins)); + + for (size_t i = 0; i < nCent; ++i) { + for (size_t j = 0; j < nBins; ++j) { + res[i][j] = flat[i * nBins + j]; + } + } + return res; + } + + /// Get the bin number of qn-vector(FT0C) of an event + /// \param centBinWidth centrality bin width, example: per 1%, per 10% ... + /// \return bin number of qn-vector of the event + // add a param : bool doFillHisto ? + int myqnBin(float centrality, float centMax, bool doFillCent, std::vector qnBinSeparator, float qn, const int numQnBins, float centBinWidth = 1.f) + { + auto twoDSeparator = getQnBinSeparator2D(qnBinSeparator, numQnBins); + if (twoDSeparator.empty() || twoDSeparator[0][0] == -999.) { + LOGP(warning, "ConfQnBinSeparator not set, using default fallback!"); + return -999; // safe fallback + } + + // if (doFillHisto) + // mHistogramQn->fill(HIST("Event/centFT0CBefore"), centrality); + // add a param : bool doFillHisto ? + int qnBin = -999; + int mycentBin = static_cast(centrality / centBinWidth); + if (mycentBin >= static_cast(centMax / centBinWidth)) + return qnBin; + + if (mycentBin > static_cast(twoDSeparator.size()) - 1) + return qnBin; + + if (doFillCent) + mHistogramQn->fill(HIST("Event/centFT0CAfterQn"), centrality); + + for (int iqn(0); iqn < static_cast(twoDSeparator[mycentBin].size()) - 1; ++iqn) { + if (qn > twoDSeparator[mycentBin][iqn] && qn <= twoDSeparator[mycentBin][iqn + 1]) { + qnBin = iqn; + break; + } else { + continue; + } + } + + mQnBin = qnBin; + return qnBin; + } + + /// \fill event-wise informations + void fillEPQA(float centrality, float fSpher, float qn, float psiEP) + { + mHistogramQn->fill(HIST("Event/centFT0CBeforeQn"), centrality); + mHistogramQn->fill(HIST("Event/centVsqn"), centrality, qn); + mHistogramQn->fill(HIST("Event/centVsqnVsSpher"), centrality, qn, fSpher); + mHistogramQn->fill(HIST("Event/qnBin"), mQnBin + 0.f); + mHistogramQn->fill(HIST("Event/psiEP"), psiEP); + } + + /// \todo to be implemented! + /// Fill cumulants histo for flow calculation + /// Reset hists event-by-event + /// \tparam T1 type of the collision + /// \tparam T2 type of the tracks + /// \param tracks All tracks + template + bool fillCumulants(T1 const& col, T2 const& tracks, float fHarmonic = 2.f) + { + int numOfTracks = col.numContrib(); + if (numOfTracks < 3) + return false; + + mReQthisEvt->Reset(); + mImQthisEvt->Reset(); + mReQ2thisEvt->Reset(); + mImQ2thisEvt->Reset(); + mMQthisEvt->Reset(); + mMQWeightthisEvt->Reset(); + + for (auto const& track : tracks) { + double weight = 1; // Will implement NUA&NUE correction + double phi = track.phi(); + double pt = track.pt(); + double eta = track.eta(); + double cosnphi = weight * TMath::Cos(fHarmonic * phi); + double sinnphi = weight * TMath::Sin(fHarmonic * phi); + double cos2nphi = weight * TMath::Cos(2 * fHarmonic * phi); + double sin2nphi = weight * TMath::Sin(2 * fHarmonic * phi); + mReQthisEvt->Fill(pt, eta, cosnphi); + mImQthisEvt->Fill(pt, eta, sinnphi); + mReQ2thisEvt->Fill(pt, eta, cos2nphi); + mImQ2thisEvt->Fill(pt, eta, sin2nphi); + mMQthisEvt->Fill(pt, eta); + mMQWeightthisEvt->Fill(pt, eta, weight); + } + return true; + } + + /// \todo to be implemented! + /// Do cumulants for flow calculation + /// \tparam T type of the collision + /// \param doQnSeparation to fill flow in divied qn bins + /// \param qnBin should be in 0-9 + /// \param fEtaGap eta gap for flow cumulant + template + void doCumulants(T1 const& col, T2 const& tracks, float centrality, bool doQnSeparation = false, int numQnBins = 10, float fEtaGap = 0.3f, int binPt = 100, int binEta = 32) { - return 2.f; + if (!fillCumulants(col, tracks)) + return; + + if (mMQthisEvt->Integral(1, binPt, 1, binEta) < 2) + return; + + double allReQ = mReQthisEvt->Integral(1, binPt, 1, binEta); + double allImQ = mImQthisEvt->Integral(1, binPt, 1, binEta); + TComplex Q(allReQ, allImQ); + TComplex QStar = TComplex::Conjugate(Q); + + double posEtaRe = mReQthisEvt->Integral(1, binPt, mReQthisEvt->GetYaxis()->FindBin(fEtaGap + 1e-6), binEta); + double posEtaIm = mImQthisEvt->Integral(1, binPt, mImQthisEvt->GetYaxis()->FindBin(fEtaGap + 1e-6), binEta); + if (mMQthisEvt->Integral(1, binPt, mMQthisEvt->GetYaxis()->FindBin(fEtaGap + 1e-6), binEta) < 2) + return; + float posEtaMQ = mMQWeightthisEvt->Integral(1, binPt, mMQthisEvt->GetYaxis()->FindBin(fEtaGap + 1e-6), binEta); + TComplex posEtaQ = TComplex(posEtaRe, posEtaIm); + TComplex posEtaQStar = TComplex::Conjugate(posEtaQ); + + double negEtaRe = mReQthisEvt->Integral(1, binPt, 1, mReQthisEvt->GetYaxis()->FindBin(-1 * fEtaGap - 1e-6)); + double negEtaIm = mImQthisEvt->Integral(1, binPt, 1, mImQthisEvt->GetYaxis()->FindBin(-1 * fEtaGap - 1e-6)); + if (mMQthisEvt->Integral(1, binPt, 1, mMQthisEvt->GetYaxis()->FindBin(-1 * fEtaGap - 1e-6)) < 2) + return; + float negEtaMQ = mMQWeightthisEvt->Integral(1, binPt, 1, mMQthisEvt->GetYaxis()->FindBin(-1 * fEtaGap - 1e-6)); + TComplex negEtaQ = TComplex(negEtaRe, negEtaIm); + TComplex negEtaQStar = TComplex::Conjugate(negEtaQ); + + mHistogramQn->get(HIST("Event/profileC22"))->Fill(centrality, (negEtaQ * posEtaQStar).Re() / (negEtaMQ * posEtaMQ), (negEtaMQ * posEtaMQ)); + if (doQnSeparation && mQnBin >= 0 && mQnBin < numQnBins) { + std::get>(profilesC22[mQnBin])->Fill(centrality, (negEtaQ * posEtaQStar).Re() / (negEtaMQ * posEtaMQ), (negEtaMQ * posEtaMQ)); + } + return; } private: @@ -179,6 +512,17 @@ class FemtoDreamCollisionSelection bool mCheckIsRun3 = false; ///< Check if running on Pilot Beam triggerAliases mTrigger = kINT7; ///< Trigger to check for float mZvtxMax = 999.f; ///< Maximal deviation from nominal z-vertex (cm) + float mMinSphericity = 0.f; + float mSphericityPtmin = 0.f; + int mQnBin = -999; + HistogramRegistry* mHistogramQn = nullptr; ///< For flow cumulant output + std::vector profilesC22; /// Pofile Histograms of c22 per Qn bin + TH2D* mReQthisEvt = nullptr; ///< For flow cumulant in an event + TH2D* mImQthisEvt = nullptr; ///< For flow cumulant in an event + TH2D* mReQ2thisEvt = nullptr; ///< For flow cumulant in an event + TH2D* mImQ2thisEvt = nullptr; ///< For flow cumulant in an event + TH2D* mMQthisEvt = nullptr; ///< For flow cumulant in an event + TH2D* mMQWeightthisEvt = nullptr; ///< For flow cumulant in an event }; } // namespace o2::analysis::femtoDream diff --git a/PWGCF/FemtoDream/Core/femtoDreamContainer.h b/PWGCF/FemtoDream/Core/femtoDreamContainer.h index 8a9038e6198..ca8d99492bf 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamContainer.h +++ b/PWGCF/FemtoDream/Core/femtoDreamContainer.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FemtoDreamContainer.h +/// \file femtoDreamContainer.h /// \brief Definition of the FemtoDreamContainer /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Valentina Mantovani Sarti, valentina.mantovani-sarti@tum.de @@ -19,18 +19,20 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMCONTAINER_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMCONTAINER_H_ -#include -#include -#include - -#include "Framework/HistogramRegistry.h" +#include "PWGCF/DataModel/FemtoDerived.h" #include "PWGCF/FemtoDream/Core/femtoDreamMath.h" #include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" -#include "PWGCF/DataModel/FemtoDerived.h" + +#include "Framework/HistogramRegistry.h" #include "Math/Vector4D.h" #include "TMath.h" +#include + +#include +#include + using namespace o2::framework; namespace o2::analysis::femtoDream @@ -99,6 +101,7 @@ class FemtoDreamContainer } if (extendedplots) { 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}); + mHistogramRegistry->add((folderName + "/invMassPart1invMassPart2kstar").c_str(), (";#it{m} (GeV/#it{c}^{2}); #it{m} (GeV/#it{c}^{2}), " + femtoObs).c_str(), kTHnSparseF, {mP2Axis, mP2Axis, femtoObsAxis}); } } @@ -180,6 +183,82 @@ class FemtoDreamContainer } } + /// Initialize the histograms for pairs in divided qn or phi-psi bins + template + void init_base_EP(std::string folderName, std::string femtoObs, + T& femtoObsAxis, T& mTAxi4D, T& multPercentileAxis4D, T& epObsAxis, std::string epObs) + { + mHistogramRegistry->add((folderName + "/relPairkstarmTMultMultPercentileQn").c_str(), ("; " + femtoObs + "; #it{m}_{T} (GeV/#it{c}); Centrality;" + epObs).c_str(), kTHnSparseF, {femtoObsAxis, mTAxi4D, multPercentileAxis4D, epObsAxis}); + } + + template + void init_EP(HistogramRegistry* registry, + T& kstarBins4D, T& mTBins4D, T& multPercentileBins4D, T& epObsBins, std::string epObs, + bool isMC, float highkstarCut) + { + mHistogramRegistry = registry; + std::string femtoObs; + if constexpr (mFemtoObs == femtoDreamContainer::Observable::kstar) { + femtoObs = "#it{k*} (GeV/#it{c})"; + } + mHighkstarCut = highkstarCut; + + framework::AxisSpec kstarAxis4D = {kstarBins4D, femtoObs}; + framework::AxisSpec mTAxis4D = {mTBins4D, "#it{m}_{T} (GeV/#it{c})"}; + framework::AxisSpec multPercentileAxis4D = {multPercentileBins4D, "Centralty(%)"}; + framework::AxisSpec epObsAxis = {epObsBins, epObs}; + + std::string folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kRecon]) + static_cast("_EP"); + + init_base_EP(folderName, femtoObs, + kstarAxis4D, mTAxis4D, multPercentileAxis4D, epObsAxis, epObs); + + if (isMC) { + folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + static_cast("_EP"); + init_base_EP(folderName, femtoObs, + kstarAxis4D, mTAxis4D, multPercentileAxis4D, epObsAxis, epObs); + } + } + + /// Initialize the histograms for pairs with 3D component in divided qn bins + template + void init_base_3Dqn(std::string folderName, std::string femtoDKout, std::string femtoDKside, std::string femtoDKlong, + T& femtoDKoutAxis, T& femtoDKsideAxis, T& femtoDKlongAxis, T& mTAxi4D, T& multPercentileAxis4D, T& qnAxis, T& pairPhiAxis) + { + mHistogramRegistry->add((folderName + "/relPair3dRmTMultPercentileQnPairphi").c_str(), ("; " + femtoDKout + femtoDKside + femtoDKlong + "; #it{m}_{T} (GeV/#it{c}); Centrality; qn; #varphi_{pair} - #Psi_{EP}").c_str(), kTHnSparseF, {femtoDKoutAxis, femtoDKsideAxis, femtoDKlongAxis, mTAxi4D, multPercentileAxis4D, qnAxis, pairPhiAxis}); + } + + template + void init_3Dqn(HistogramRegistry* registry, + T& DKoutBins, T& DKsideBins, T& DKlongBins, T& mTBins4D, T& multPercentileBins4D, + bool isMC, ConfigurableAxis qnBins = {"qnBins", {10, 0, 10}, "qn binning"}, ConfigurableAxis pairPhiBins = {"phiBins", {10, 0 - 0.05, TMath::Pi() + 0.05}, "pair phi binning"}) + { + mHistogramRegistry = registry; + + std::string femtoObsDKout = "DK_{out} (GeV/#it{c})"; + std::string femtoObsDKside = "DK_{side} (GeV/#it{c})"; + std::string femtoObsDKlong = "DK_{long} (GeV/#it{c})"; + + framework::AxisSpec DKoutAxis = {DKoutBins, femtoObsDKout}; + framework::AxisSpec DKsideAxis = {DKsideBins, femtoObsDKside}; + framework::AxisSpec DKlongAxis = {DKlongBins, femtoObsDKlong}; + framework::AxisSpec mTAxis4D = {mTBins4D, "#it{m}_{T} (GeV/#it{c})"}; + framework::AxisSpec multPercentileAxis4D = {multPercentileBins4D, "Centralty(%)"}; + framework::AxisSpec qnAxis = {qnBins, "qn"}; + framework::AxisSpec pairPhiAxis = {pairPhiBins, "#varphi_{pair} - #Psi_{EP} (rad)"}; + + std::string folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kRecon]) + static_cast("_3Dqn"); + + init_base_3Dqn(folderName, femtoObsDKout, femtoObsDKside, femtoObsDKlong, + DKoutAxis, DKsideAxis, DKlongAxis, mTAxis4D, multPercentileAxis4D, qnAxis, pairPhiAxis); + + if (isMC) { + folderName = static_cast(mFolderSuffix[mEventType]) + static_cast(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + static_cast("_3Dqn"); + init_base_3Dqn(folderName, femtoObsDKout, femtoObsDKside, femtoObsDKlong, + DKoutAxis, DKsideAxis, DKlongAxis, mTAxis4D, multPercentileAxis4D, qnAxis, pairPhiAxis); + } + } + /// Set the PDG codes of the two particles involved /// \param pdg1 PDG code of particle one /// \param pdg2 PDG code of particle two @@ -202,10 +281,12 @@ class FemtoDreamContainer { const float kT = FemtoDreamMath::getkT(part1, mMassOne, part2, mMassTwo); if constexpr (isHF) { - float mP2; - if (part2.candidateSelFlag() == o2::aod::fdhf::lcToPKPi) { + float mP2 = 0.0; + if (part2.candidateSelFlag() == o2::aod::fdhf::dplusToPiKPi) { + mP2 = part2.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } else 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 { + } else if (part2.candidateSelFlag() == o2::aod::fdhf::lcToPiKP) { 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); @@ -228,6 +309,9 @@ class FemtoDreamContainer } if (extendedplots) { mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/relPairkstarmTPtPart1PtPart2MultPercentile"), femtoObs, mT, part1.pt(), part2.pt(), multPercentile); + if constexpr (requires { part1.mLambda(); part2.mLambda(); }) { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/invMassPart1invMassPart2kstar"), part1.mLambda(), part2.mLambda(), femtoObs); + } } } @@ -287,7 +371,7 @@ class FemtoDreamContainer } 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 + if (std::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 { @@ -301,7 +385,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 + if (std::abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne && std::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_MC(femtoObsMC, femtoObs, mT, mult, part1.fdMCParticle().partOriginMCTruth(), part2.fdMCParticle().partOriginMCTruth(), smearingByOrigin); } else { @@ -315,6 +399,179 @@ class FemtoDreamContainer } } + /// Pass a pair to the container and compute all the relevant observables in divided qn&phi-psi bins + template + void setPair_EP_base(const float femtoObs, const float mT, const float multPercentile, const float myEPObs) + { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("_EP") + HIST("/relPairkstarmTMultMultPercentileQn"), femtoObs, mT, multPercentile, myEPObs); + } + + template + void setPair_EP(T1 const& part1, T2 const& part2, const float multPercentile, const bool doQnSeparation, float myEPObs) + { + float femtoObs, femtoObsMC; + // Calculate femto observable and the mT with reconstructed information + if constexpr (mFemtoObs == femtoDreamContainer::Observable::kstar) { + femtoObs = FemtoDreamMath::getkstar(part1, mMassOne, part2, mMassTwo); + } + if (mHighkstarCut > 0) { + if (femtoObs > mHighkstarCut) { + return; + } + } + const float mT = FemtoDreamMath::getmT(part1, mMassOne, part2, mMassTwo); + + if (!doQnSeparation) { + myEPObs = FemtoDreamMath::getPairPhiEP(part1, mMassOne, part2, mMassTwo, myEPObs); + } + + if (mHistogramRegistry) { + setPair_EP_base(femtoObs, mT, multPercentile, myEPObs); + + if constexpr (isMC) { + 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); + } + const float mTMC = FemtoDreamMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + + if (std::abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne && std::abs(part2.fdMCParticle().pdgMCTruth()) == mPDGTwo) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates + setPair_EP_base(femtoObsMC, mTMC, multPercentile, myEPObs); + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); + } + + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hNoMCtruthPairsCounter"), 0); + } + } + } + } + + // while doing mixing for EP, we have to compute the phi angular of a pair according to plane-calibarated second particle + template + void setPair_EP(T1 const& part1, T2 const& part2, const float multPercentile, const bool doQnSeparation, float EP1, float EP2) + { + float femtoObs, femtoObsMC; + // Calculate femto observable and the mT with reconstructed information + if constexpr (mFemtoObs == femtoDreamContainer::Observable::kstar) { + femtoObs = FemtoDreamMath::getkstar(part1, mMassOne, part2, mMassTwo); + } + if (mHighkstarCut > 0) { + if (femtoObs > mHighkstarCut) { + return; + } + } + const float mT = FemtoDreamMath::getmT(part1, mMassOne, part2, mMassTwo); + + if (doQnSeparation) + LOG(fatal) << "Wrong usage of setPair_EP_mix, this is only for phi-psi mixing"; + EP1 = FemtoDreamMath::getPairPhiEP(part1, mMassOne, part2, mMassTwo, EP1, EP2); + + if (mHistogramRegistry) { + setPair_EP_base(femtoObs, mT, multPercentile, EP1); + + if constexpr (isMC) { + 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); + } + const float mTMC = FemtoDreamMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + + if (std::abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne && std::abs(part2.fdMCParticle().pdgMCTruth()) == mPDGTwo) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates + setPair_EP_base(femtoObsMC, mTMC, multPercentile, EP1); + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); + } + + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hNoMCtruthPairsCounter"), 0); + } + } + } + } + + /// Pass a pair to the container and compute all the relevant observables in divided qn bins + template + void setPair_3Dqn_base(const float femtoDKout, const float femtoDKside, const float femtoDKlong, const float mT, const float multPercentile, const float myQnBin, const float pairPhiEP) + { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("_3Dqn") + HIST("/relPair3dRmTMultPercentileQnPairphi"), femtoDKout, femtoDKside, femtoDKlong, mT, multPercentile, myQnBin, pairPhiEP); + } + + template + void setPair_3Dqn(T1 const& part1, T2 const& part2, const float multPercentile, bool IsSameSpecies, const float myQnBin, const float eventPlane) + { + + std::vector k3d = FemtoDreamMath::newpairfunc(part1, mMassOne, part2, mMassTwo, IsSameSpecies); + float DKout = k3d[1]; + float DKside = k3d[2]; + float DKlong = k3d[3]; + + const float mT = FemtoDreamMath::getmT(part1, mMassOne, part2, mMassTwo); + + const float pairPhiEP = FemtoDreamMath::getPairPhiEP(part1, mMassOne, part2, mMassTwo, eventPlane); + + if (mHistogramRegistry) { + setPair_3Dqn_base(DKout, DKside, DKlong, mT, multPercentile, myQnBin, pairPhiEP); + + if constexpr (isMC) { + if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { + + std::vector k3dMC = FemtoDreamMath::newpairfunc(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, IsSameSpecies); + const float mTMC = FemtoDreamMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + const float pairPhiEPMC = FemtoDreamMath::getPairPhiEP(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, eventPlane); + + if (std::abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne && std::abs(part2.fdMCParticle().pdgMCTruth()) == mPDGTwo) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates + setPair_3Dqn_base(k3dMC[1], k3dMC[2], k3dMC[3], mTMC, multPercentile, myQnBin, pairPhiEPMC); + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); + } + + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hNoMCtruthPairsCounter"), 0); + } + } + } + } + + template + void setPair_3Dqn(T1 const& part1, T2 const& part2, const float multPercentile, bool IsSameSpecies, const float myQnBin, const float EP1, const float EP2) + { + + std::vector k3d = FemtoDreamMath::newpairfunc(part1, mMassOne, part2, mMassTwo, IsSameSpecies); + float DKout = k3d[1]; + float DKside = k3d[2]; + float DKlong = k3d[3]; + + const float mT = FemtoDreamMath::getmT(part1, mMassOne, part2, mMassTwo); + + const float pairPhiEP = FemtoDreamMath::getPairPhiEP(part1, mMassOne, part2, mMassTwo, EP1, EP2); + + if (mHistogramRegistry) { + setPair_3Dqn_base(DKout, DKside, DKlong, mT, multPercentile, myQnBin, pairPhiEP); + + if constexpr (isMC) { + if (part1.has_fdMCParticle() && part2.has_fdMCParticle()) { + + std::vector k3dMC = FemtoDreamMath::newpairfunc(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, IsSameSpecies); + const float mTMC = FemtoDreamMath::getmT(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo); + const float pairPhiEPMC = FemtoDreamMath::getPairPhiEP(part1.fdMCParticle(), mMassOne, part2.fdMCParticle(), mMassTwo, EP1, EP2); + + if (std::abs(part1.fdMCParticle().pdgMCTruth()) == mPDGOne && std::abs(part2.fdMCParticle().pdgMCTruth()) == mPDGTwo) { // Note: all pair-histogramms are filled with MC truth information ONLY in case of non-fake candidates + setPair_3Dqn_base(k3dMC[1], k3dMC[2], k3dMC[3], mTMC, multPercentile, myQnBin, pairPhiEPMC); + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::MCType::kTruth]) + HIST("/hFakePairsCounter"), 0); + } + + } else { + mHistogramRegistry->fill(HIST(mFolderSuffix[mEventType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[o2::aod::femtodreamMCparticle::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 diff --git a/PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h b/PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h index c4d1ebe5e66..a6c60793060 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h +++ b/PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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 9d1e55aadf1..a11506ba567 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h +++ b/PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h @@ -9,18 +9,20 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FemtoDreamDetaDphiStar.h +/// \file femtoDreamDetaDphiStar.h /// \brief FemtoDreamDetaDphiStar - Checks particles for the close pair rejection. /// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMDETADPHISTAR_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMDETADPHISTAR_H_ +#include "PWGCF/DataModel/FemtoDerived.h" + +#include "Framework/HistogramRegistry.h" + #include #include #include -#include "PWGCF/DataModel/FemtoDerived.h" -#include "Framework/HistogramRegistry.h" using namespace o2; using namespace o2::framework; @@ -64,7 +66,7 @@ class FemtoDreamDetaDphiStar 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}}); @@ -98,6 +100,24 @@ class FemtoDreamDetaDphiStar } } } + if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kV0 && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kV0) { + for (int i = 0; i < 4; 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][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]); @@ -116,6 +136,43 @@ class FemtoDreamDetaDphiStar } } } + 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}}); + } + } + } + if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kV0 && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kReso) { + + for (int i = 0; i < 4; i++) { + std::string dirName = static_cast(dirNames[4]); + 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 @@ -123,11 +180,12 @@ class FemtoDreamDetaDphiStar { 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(); @@ -152,7 +210,7 @@ class FemtoDreamDetaDphiStar } if (sameCharge) { if (atWhichRadiiToSelect == 1) { - if (pow(dphiAvg, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphiAvg, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { return true; } else { if (Q3 == 999) { @@ -165,7 +223,7 @@ class FemtoDreamDetaDphiStar return false; } } else if (atWhichRadiiToSelect == 0) { - if (pow(dphi_AT_PV, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphi_AT_PV, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { return true; } else { if (Q3 == 999) { @@ -178,7 +236,7 @@ class FemtoDreamDetaDphiStar return false; } } else if (atWhichRadiiToSelect == 2) { - if (pow(dphi_AT_SpecificRadii, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphi_AT_SpecificRadii, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { return true; } else { if (Q3 == 999) { @@ -197,6 +255,88 @@ class FemtoDreamDetaDphiStar return false; } + } else if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kV0 && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kReso) { + /// V0-Reso combination + // check if provided particles are in agreement with the class instantiation + if (part1.partType() != o2::aod::femtodreamparticle::ParticleType::kV0 || (part2.partType() != o2::aod::femtodreamparticle::ParticleType::kResoPosdaughTOF_NegdaughTOF && + part2.partType() != o2::aod::femtodreamparticle::ParticleType::kResoPosdaughTOF_NegdaughTPC && + part2.partType() != o2::aod::femtodreamparticle::ParticleType::kResoPosdaughTPC_NegdaughTOF && + part2.partType() != o2::aod::femtodreamparticle::ParticleType::kResoPosdaughTPC_NegdaughTPC)) { + LOG(fatal) << "FemtoDreamDetaDphiStar: passed arguments don't agree with FemtoDreamDetaDphiStar instantiation! Please provide kV0, kResoPosdaughTOF_NegdaughTOF, kResoPosdaughTOF_NegdaughTPC, kResoPosdaughTPC_NegdaughTOF, kResoPosdaughTPC_NegdaughTPC candidates."; + return false; + } + + bool pass = false; + int nhist = 0; + for (int i = 0; i < 2; i++) { + int indexOfDaughterPart1, indexOfDaughterPart2; + for (int j = 0; j < 2; j++) { + if (isMixedEventLambda) { + indexOfDaughterPart1 = part1.globalIndex() - 2 + i; + indexOfDaughterPart2 = part2.globalIndex() - 2 + j; + } else { + indexOfDaughterPart1 = part1.index() - 2 + i; + indexOfDaughterPart2 = part2.index() - 2 + j; + } + + auto daughterPart1 = particles.begin() + indexOfDaughterPart1; + auto daughterPart2 = particles.begin() + indexOfDaughterPart2; + auto deta = daughterPart1.eta() - daughterPart2.eta(); + auto dphi_AT_PV = daughterPart1.phi() - daughterPart2.phi(); + auto dphi_AT_SpecificRadii = PhiAtSpecificRadiiTPC(daughterPart1, radiiTPC) - PhiAtSpecificRadiiTPC(daughterPart2, radiiTPC); + bool sameCharge = false; + auto dphiAvg = AveragePhiStar(*daughterPart1, *daughterPart2, nhist, &sameCharge); + if (Q3 == 999) { + histdetadpi[nhist][0]->Fill(deta, dphiAvg); + histdetadpi[nhist][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[nhist]->Fill(deta, dphiAvg, daughterPart1.eta(), daughterPart2.eta()); + histdetadpi_phi[nhist]->Fill(deta, dphiAvg, daughterPart1.phi(), daughterPart2.phi()); + } + } + if (sameCharge) { + if (atWhichRadiiToSelect == 1) { + if (std::pow(dphiAvg, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 0) { + if (std::pow(dphi_AT_PV, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 2) { + if (std::pow(dphi_AT_SpecificRadii, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } + } + } + } + nhist += 1; + } + } + return pass; } else if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kV0) { /// Track-V0 combination // check if provided particles are in agreement with the class instantiation @@ -236,7 +376,7 @@ class FemtoDreamDetaDphiStar } if (sameCharge) { if (atWhichRadiiToSelect == 1) { - if (pow(dphiAvg, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphiAvg, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { pass = true; } else { if (Q3 == 999) { @@ -248,7 +388,7 @@ class FemtoDreamDetaDphiStar } } } else if (atWhichRadiiToSelect == 0) { - if (pow(dphi_AT_PV, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphi_AT_PV, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { pass = true; } else { if (Q3 == 999) { @@ -260,7 +400,7 @@ class FemtoDreamDetaDphiStar } } } else if (atWhichRadiiToSelect == 2) { - if (pow(dphi_AT_SpecificRadii, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphi_AT_SpecificRadii, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { pass = true; } else { if (Q3 == 999) { @@ -274,6 +414,86 @@ class FemtoDreamDetaDphiStar } } } + return pass; + } else if constexpr (mPartOneType == o2::aod::femtodreamparticle::ParticleType::kV0 && mPartTwoType == o2::aod::femtodreamparticle::ParticleType::kV0) { + /// V0-V0 combination + // check if provided particles are in agreement with the class instantiation + if (part1.partType() != o2::aod::femtodreamparticle::ParticleType::kV0 || part2.partType() != o2::aod::femtodreamparticle::ParticleType::kV0) { + LOG(fatal) << "FemtoDreamDetaDphiStar: passed arguments don't agree with FemtoDreamDetaDphiStar instantiation! Please provide kV0,kV0 candidates."; + return false; + } + + bool pass = false; + int nhist = 0; + for (int i = 0; i < 2; i++) { + int indexOfDaughterPart1, indexOfDaughterPart2; + for (int j = 0; j < 2; j++) { + if (isMixedEventLambda) { + indexOfDaughterPart1 = part1.globalIndex() - 2 + i; + indexOfDaughterPart2 = part2.globalIndex() - 2 + j; + } else { + indexOfDaughterPart1 = part1.index() - 2 + i; + indexOfDaughterPart2 = part2.index() - 2 + j; + } + + auto daughterPart1 = particles.begin() + indexOfDaughterPart1; + auto daughterPart2 = particles.begin() + indexOfDaughterPart2; + auto deta = daughterPart1.eta() - daughterPart2.eta(); + auto dphi_AT_PV = daughterPart1.phi() - daughterPart2.phi(); + auto dphi_AT_SpecificRadii = PhiAtSpecificRadiiTPC(daughterPart1, radiiTPC) - PhiAtSpecificRadiiTPC(daughterPart2, radiiTPC); + bool sameCharge = false; + auto dphiAvg = AveragePhiStar(*daughterPart1, *daughterPart2, nhist, &sameCharge); + if (Q3 == 999) { + histdetadpi[nhist][0]->Fill(deta, dphiAvg); + histdetadpi[nhist][2]->Fill(deta, dphi_AT_PV); + if (fillQA) { + histdetadpi_eta[nhist]->Fill(deta, dphiAvg, daughterPart1.eta(), daughterPart2.eta()); + histdetadpi_phi[nhist]->Fill(deta, dphiAvg, daughterPart1.phi(), daughterPart2.phi()); + } + } + if (sameCharge) { + if (atWhichRadiiToSelect == 1) { + if (std::pow(dphiAvg, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 0) { + if (std::pow(dphi_AT_PV, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } + } + } else if (atWhichRadiiToSelect == 2) { + if (std::pow(dphi_AT_SpecificRadii, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { + pass = true; + } else { + if (Q3 == 999) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } else if (Q3 < upperQ3LimitForPlotting) { + histdetadpi[nhist][1]->Fill(deta, dphiAvg); + histdetadpi[nhist][3]->Fill(deta, dphi_AT_PV); + } + } + } + } + nhist += 1; + } + } + 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 @@ -336,7 +556,7 @@ class FemtoDreamDetaDphiStar } if (atWhichRadiiToSelect == 1) { - if (pow(dphiAvg, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphiAvg, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { pass = true; } else { if (Q3 == 999) { @@ -348,7 +568,7 @@ class FemtoDreamDetaDphiStar } } } else if (atWhichRadiiToSelect == 0) { - if (pow(dphi_AT_PV, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphi_AT_PV, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { pass = true; } else { if (Q3 == 999) { @@ -360,7 +580,7 @@ class FemtoDreamDetaDphiStar } } } else if (atWhichRadiiToSelect == 2) { - if (pow(dphi_AT_SpecificRadii, 2) / pow(deltaPhiMax, 2) + pow(deta, 2) / pow(deltaEtaMax, 2) < 1.) { + if (std::pow(dphi_AT_SpecificRadii, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::pow(deltaEtaMax, 2) < 1.) { pass = true; } else { if (Q3 == 999) { @@ -376,6 +596,85 @@ class FemtoDreamDetaDphiStar 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 (std::pow(dphiAvg, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::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 (std::pow(dphi_AT_PV, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::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 (std::pow(dphi_AT_SpecificRadii, 2) / std::pow(deltaPhiMax, 2) + std::pow(deta, 2) / std::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 { LOG(fatal) << "FemtoDreamPairCleaner: Combination of objects not defined - quitting!"; return false; @@ -385,14 +684,14 @@ class FemtoDreamDetaDphiStar private: HistogramRegistry* mHistogramRegistry = nullptr; ///< For main output HistogramRegistry* mHistogramRegistryQA = nullptr; ///< For QA output - static constexpr std::string_view dirNames[3] = {"kTrack_kTrack/", "kTrack_kV0/", "kTrack_kCharmHadron/"}; + static constexpr std::string_view dirNames[5] = {"kTrack_kTrack/", "kTrack_kV0/", "kTrack_kCharmHadron/", "kTrack_kCascade/", "kV0_kReso/"}; static constexpr std::string_view histNameSEorME[3] = {"_SEandME", "_SE", "_ME"}; - static constexpr std::string_view histNames[2][3] = {{"detadphidetadphi0Before_0", "detadphidetadphi0Before_1", "detadphidetadphi0Before_2"}, - {"detadphidetadphi0After_0", "detadphidetadphi0After_1", "detadphidetadphi0After_2"}}; + 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[3][9] = { + 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"}, @@ -401,7 +700,10 @@ class FemtoDreamDetaDphiStar "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_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 @@ -457,7 +759,7 @@ 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); @@ -517,7 +819,7 @@ class FemtoDreamDetaDphiStar 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 (abs(arg) < 1) { + if (std::fabs(arg) < 1) { phiAtRadii = phi0 - std::asin(0.3 * charge * magfield * radii * 0.01 / (2. * pt)); } else { phiAtRadii = 999.; @@ -560,7 +862,7 @@ 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); diff --git a/PWGCF/FemtoDream/Core/femtoDreamEventHisto.h b/PWGCF/FemtoDream/Core/femtoDreamEventHisto.h index 4f70555a849..2d668d15c58 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamEventHisto.h +++ b/PWGCF/FemtoDream/Core/femtoDreamEventHisto.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // diff --git a/PWGCF/FemtoDream/Core/femtoDreamMath.h b/PWGCF/FemtoDream/Core/femtoDreamMath.h index 441e49066cd..02d8d715a34 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamMath.h +++ b/PWGCF/FemtoDream/Core/femtoDreamMath.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -16,12 +16,15 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMMATH_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMMATH_H_ -#include - -#include "Math/Vector4D.h" #include "Math/Boost.h" +#include "Math/Vector4D.h" #include "TLorentzVector.h" #include "TMath.h" +#include "TVector2.h" +#include + +#include +#include namespace o2::analysis::femtoDream { @@ -136,6 +139,137 @@ class FemtoDreamMath { 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(); + } + + /// Compute the 3d components of the pair momentum in LCMS and PRF + /// Copy from femto universe + /// \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 + /// \param isiden Identical or non-identical particle pair + template + static std::vector newpairfunc(const T& part1, const float mass1, const T& part2, const float mass2, bool isiden) + { + 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 trackSum = vecpart1 + vecpart2; + + std::vector vect; + + const double tPx = trackSum.px(); + const double tPy = trackSum.py(); + const double tPz = trackSum.pz(); + const double tE = trackSum.E(); + + 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_LCMS = tPz / tE; + const double gamma_LCMS = tE / tMt; + + const double fDKOut = (part1.px() * tPx + part1.py() * tPy) / tPt; + const double fDKSide = (-part1.px() * tPy + part1.py() * tPx) / tPt; + const double fDKLong = gamma_LCMS * (part1.pz() - beta_LCMS * e1); + const double fDE = gamma_LCMS * (e1 - beta_LCMS * part1.pz()); + + const double px1LCMS = fDKOut; + const double py1LCMS = fDKSide; + const double pz1LCMS = fDKLong; + const double pE1LCMS = fDE; + + const double px2LCMS = (part2.px() * tPx + part2.py() * tPy) / tPt; + const double py2LCMS = (part2.py() * tPx - part2.px() * tPy) / tPt; + const double pz2LCMS = gamma_LCMS * (part2.pz() - beta_LCMS * e2); + const double pE2LCMS = gamma_LCMS * (e2 - beta_LCMS * part2.pz()); + + 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 / tM; + + 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 (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(kstar); + vect.push_back(fDKOut); + vect.push_back(fDKSide); + vect.push_back(fDKLong); + } + return vect; + } + + /// Compute the phi angular of a pair with respect to the event plane + /// \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 getPairPhiEP(const T1& part1, const float mass1, const T2& part2, const float mass2, const float Psi_ep) + { + 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; + float phi_pair_onPsi = TVector2::Phi_mpi_pi(trackSum.Phi() - Psi_ep); + phi_pair_onPsi = TMath::Abs(phi_pair_onPsi); + return phi_pair_onPsi; + } + + /// Compute the phi angular of a pair according to plane-calibarated second particle + template + static float getPairPhiEP(const T1& part1, const float mass1, const T2& part2, const float mass2, const float Psi_ep1, const float Psi_ep2) + { + 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 float psidiff = Psi_ep2 - Psi_ep1; + // rotate phi of part2 + const float newPhi2 = TVector2::Phi_mpi_pi(vecpart2.Phi() - psidiff); + const ROOT::Math::PtEtaPhiMVector vecpart2_calibd(vecpart2.Pt(), vecpart2.Eta(), newPhi2, vecpart2.M()); + const ROOT::Math::PtEtaPhiMVector trackSum = vecpart1 + vecpart2_calibd; + // reCalibrate part2 phi with respect to part1 event plane + float phi_pair_onPsi = TVector2::Phi_mpi_pi(trackSum.Phi() - Psi_ep1); + phi_pair_onPsi = TMath::Abs(phi_pair_onPsi); + return phi_pair_onPsi; + } }; } // namespace o2::analysis::femtoDream diff --git a/PWGCF/FemtoDream/Core/femtoDreamObjectSelection.h b/PWGCF/FemtoDream/Core/femtoDreamObjectSelection.h index 21440f35414..ef77ff8a7df 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamObjectSelection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamObjectSelection.h @@ -16,15 +16,16 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMOBJECTSELECTION_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMOBJECTSELECTION_H_ +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamSelection.h" + +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/PID.h" + #include #include #include -#include "PWGCF/FemtoDream/Core/femtoDreamSelection.h" -#include "ReconstructionDataFormats/PID.h" -#include "Framework/HistogramRegistry.h" -#include "PWGCF/DataModel/FemtoDerived.h" - using namespace o2; using namespace o2::framework; @@ -69,7 +70,7 @@ class FemtoDreamObjectSelection { std::vector tmpSelVals = selVals; // necessary due to some features of the Configurable std::vector> tempVec; - for (const selValDataType selVal : tmpSelVals) { + for (const selValDataType& selVal : tmpSelVals) { tempVec.push_back(FemtoDreamSelection(selVal, selVar, selType)); } setSelection(tempVec); @@ -97,7 +98,7 @@ class FemtoDreamObjectSelection } /// Then, the sorted selections are added to the overall container of cuts - for (auto& sel : sels) { + for (const auto& sel : sels) { mSelections.push_back(sel); } } @@ -121,7 +122,7 @@ class FemtoDreamObjectSelection break; } - for (auto sel : mSelections) { + for (auto& sel : mSelections) { if (sel.getSelectionVariable() == selVar) { switch (sel.getSelectionType()) { case (femtoDreamSelection::SelectionType::kUpperLimit): @@ -164,7 +165,7 @@ class FemtoDreamObjectSelection std::vector> getSelections(selVariable selVar) { std::vector> selValVec; - for (auto it : mSelections) { + for (auto& it : mSelections) { if (it.getSelectionVariable() == selVar) { selValVec.push_back(it); } @@ -177,9 +178,11 @@ class FemtoDreamObjectSelection std::vector getSelectionVariables() { std::vector selVarVec; - for (auto it : mSelections) { + for (auto& it : mSelections) { auto selVar = it.getSelectionVariable(); - if (std::none_of(selVarVec.begin(), selVarVec.end(), [selVar](selVariable a) { return a == selVar; })) { + if (std::none_of(selVarVec.begin(), + selVarVec.end(), + [selVar](selVariable a) { return a == selVar; })) { selVarVec.push_back(selVar); } } diff --git a/PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h b/PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h index 42828b1c38b..3b248657b1f 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h +++ b/PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -70,7 +70,7 @@ 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; @@ -85,6 +85,19 @@ class FemtoDreamPairCleaner 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; } else { LOG(fatal) << "FemtoDreamPairCleaner: Combination of objects not defined - quitting!"; return false; diff --git a/PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h b/PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h index 65bc644ea24..8cdf1cfbb60 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h +++ b/PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FemtoDreamParticleHisto.h +/// \file femtoDreamParticleHisto.h /// \brief FemtoDreamParticleHisto - Histogram class for tracks, V0s and cascades /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de @@ -18,11 +18,15 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMPARTICLEHISTO_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMPARTICLEHISTO_H_ -#include -#include #include "PWGCF/DataModel/FemtoDerived.h" + +#include "CommonConstants/PhysicsConstants.h" #include "Framework/HistogramRegistry.h" +#include + +#include + using namespace o2::framework; namespace o2::analysis::femtoDream @@ -60,18 +64,35 @@ 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}); + } + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kReso) { + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassReso").c_str(), "; M_{Reso}; Entries", kTH1F, {InvMassAxis}); // added for Phi !! + mHistogramRegistry->add((folderName + folderSuffix + "/hpTInvMassReso").c_str(), "; p_{T} (GeV/#it{c{}); M_{Reso}", kTH2F, {pTAxis, InvMassAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassAntiReso").c_str(), "; M_{Reso}; Entries", kTH1F, {InvMassAxis}); // added for Phi !! + mHistogramRegistry->add((folderName + folderSuffix + "/hpTInvMassAntiReso").c_str(), "; p_{T} (GeV/#it{c{}); M_{Reso}", kTH2F, {pTAxis, InvMassAxis}); + } + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kResoChild) { + + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassReso").c_str(), "; M_{Reso}; Entries", kTH1F, {InvMassAxis}); // added for Phi !! + mHistogramRegistry->add((folderName + folderSuffix + "/hpTInvMassReso").c_str(), "; p_{T} (GeV/#it{c{}); M_{Reso}", kTH2F, {pTAxis, InvMassAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassAntiReso").c_str(), "; M_{Reso}; Entries", kTH1F, {InvMassAxis}); // added for Phi !! + mHistogramRegistry->add((folderName + folderSuffix + "/hpTInvMassAntiReso").c_str(), "; p_{T} (GeV/#it{c{}); M_{Reso}", 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 +101,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 +121,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 +154,41 @@ 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}); + } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kResoChild) { + 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}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hTPCcrossedOverFindable").c_str(), "; TPC ratio findable over crossed; Entries", kTH1F, {{100, 0.5, 1.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hTPCcrossedRows").c_str(), "; TPC crossed rows; Entries", kTH1F, {{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 + "/hTPCsharedOverFound").c_str(), "; TPC ratio shared over found; Entries", kTH1F, {{1000, 0, 1}}); + 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 + "/hTPCfoundVsShared").c_str(), ";TPC found clusters ; TPC shared clusters;", kTH2F, {{163, -0.5, 162.5}, {163, -0.5, 162.5}}); + 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} (GeV/#it{c}); DCA_{z} (cm)", kTH2F, {pTAxis, dcazAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCA").c_str(), "; #it{p} (GeV/#it{c}); DCA (cm)", kTH2F, {pTAxis, {300, 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_pi").c_str(), "n#sigma_{TPC}^{#pi}", kTH2F, {pTAxis, NsigmaTPCAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_K").c_str(), "n#sigma_{TPC}^{K}", kTH2F, {pTAxis, NsigmaTPCAxis}); + 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 + "/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 + "/ITSSignal").c_str(), "x", 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}); } } @@ -143,7 +213,7 @@ class FemtoDreamParticleHisto 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}}); @@ -175,7 +245,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}); @@ -183,6 +253,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}); @@ -190,6 +263,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 @@ -210,17 +286,20 @@ 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::kResoChild || mParticleType == o2::aod::femtodreamparticle::ParticleType::kReso) { // mParticleType == o2::aod::femtodreamparticle::ParticleType::kReso || Phi has no TempFitVar!! + /// Reso histograms added!! + tempFitVarAxisTitle = "DCA_{xy} (cm)"; + } 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) { @@ -240,15 +319,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); @@ -273,13 +353,31 @@ 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()); + } + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kReso) { + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassReso"), part.mLambda()); // currently no MC for Phi!! + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassReso"), part.pt(), part.mLambda()); // getter from FDPArticles now!! + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassAntiReso"), part.mAntiLambda()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassAntiReso"), part.pt(), part.mAntiLambda()); + } + if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kResoChild) { + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassReso"), part.mLambda()); // currently no MC for Phi!! + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassReso"), part.pt(), part.mLambda()); // getter from FDPArticles now!! + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hInvMassAntiReso"), part.mAntiLambda()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hpTInvMassAntiReso"), part.pt(), part.mAntiLambda()); + } } template @@ -307,7 +405,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()); @@ -327,43 +425,65 @@ 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) { float pidTPC = 0.; float pidTOF = 0.; - switch (abs(mPDG)) { - case 11: + switch (std::abs(mPDG)) { + 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."; } @@ -384,9 +504,43 @@ 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()); + } else if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kResoChild) { + 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()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCcrossedOverFindable"), part.tpcCrossedRowsOverFindableCls()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCcrossedRows"), part.tpcNClsCrossedRows()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCfindableVsCrossed"), part.tpcNClsFindable(), part.tpcNClsCrossedRows()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCshared"), part.tpcNClsShared()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCsharedOverFound"), static_cast(part.tpcNClsShared()) / static_cast(part.tpcNClsFound())); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCfoundVsShared"), part.tpcNClsFound(), part.tpcNClsShared()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hITSclusters"), part.itsNCls()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hITSclustersIB"), part.itsNClsInnerBarrel()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hDCAz"), momentum, part.dcaZ()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hDCA"), momentum, std::sqrt(std::pow(part.dcaXY(), 2.) + std::pow(part.dcaZ(), 2.))); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/hTPCdEdX"), momentum, part.tpcSignal()); + mHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[mParticleType]) + HIST(mFolderSuffix[mFolderSuffixType]) + HIST(o2::aod::femtodreamMCparticle::MCTypeName[mc]) + HIST("/nSigmaTPC_pi"), momentum, part.tpcNSigmaPi()); + 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("/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("/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("/ITSSignal"), momentum, part.itsSignal()); + 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()); } } - /// Filling specialized histograms for Monte Carlo truth /// internal function called by init only in case of Monte Carlo truth /// \tparam T Data type of the particle @@ -407,7 +561,7 @@ class FemtoDreamParticleHisto 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 + if (std::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()); } if constexpr (mParticleType == o2::aod::femtodreamparticle::ParticleType::kTrack || mParticleType == o2::aod::femtodreamparticle::ParticleType::kV0Child) { @@ -523,6 +677,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!"; } @@ -552,6 +718,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!"; } @@ -590,11 +768,13 @@ 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[12] = {"", "_one", "_two", "_pos", "_neg", + "_allSelected", "_allSelected_pos", "_allSelected_neg", "_bach", + "_two_pos", "_two_neg", "_two_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/femtoDreamResoSelection.h b/PWGCF/FemtoDream/Core/femtoDreamResoSelection.h new file mode 100644 index 00000000000..f61786deb88 --- /dev/null +++ b/PWGCF/FemtoDream/Core/femtoDreamResoSelection.h @@ -0,0 +1,649 @@ +// 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 femtoDreamResoSelection.h +/// \brief Definition of the FemtoDreamResoSelection +/// \author Christopher Klumm, TU München, christopher.klumm@cern.ch +/// \author Nils Fabian Konert, TU München, nils.fabian.konert@cern.ch + +#ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMRESOSELECTION_H_ +#define PWGCF_FEMTODREAM_CORE_FEMTODREAMRESOSELECTION_H_ + +#include "PWGCF/DataModel/FemtoDerived.h" +#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" + +#include "Math/Vector4D.h" +#include "TMath.h" + +#include +#include +#include +#include +#include + +namespace o2::analysis::femtoDream // o2-linter: disable=name/namespace (Previously defined namespace) +{ +namespace femto_dream_reso_selection +{ + +enum ResoSel { + kResoSign +}; +/// If you add a new selection, adjust kNresoSelection + +enum Daughtertype { + kPosdaugh, + kNegdaugh +}; +} // namespace femto_dream_reso_selection + +class FemtoDreamResoSelection + : public FemtoDreamObjectSelection +{ + + public: + FemtoDreamResoSelection() /// initialization currently kind of random change this!!! + : mDaughPTPCThr{99.f, 99.f}, mPIDoffsetTPC(0.f), mPIDoffsetTOF(0.f), mSigmaPIDMax(99.f) + { + } + + virtual ~FemtoDreamResoSelection() = default; + + template + int getType(V const& track1, V const& track2, bool resoIsNotAnti); + + /// assigns value from configurbale to private class member + template + void assign(V& selVals) + { + mDaughPTPCThr = selVals; + }; + + template + size_t numBitsUsed(V const& origvalue); + + template + void init(HistogramRegistry* QAregistry, HistogramRegistry* Registry); + + template + void fillQA(T const& track1, T const& track2); + + template + void fillMassSelectedQA(float const& mass, bool const& isNotAnti); + + template + void fillResoQA(T const& trackPos, T const& trackNeg, bool const& isNotAnti, float const& mass, float const& massOtherHypothesis, V const& pidVector, o2::track::PID::ID const& extraPID); + + template + void fillLikeSignHistos(T const& trackPos, T const& trackNeg, V const& pidVector, o2::track::PID::ID const& extraPID, bool resoIsNotAnti); + + template + void setDaughterCuts(femto_dream_reso_selection::Daughtertype child, T selVal, + V selVar, femtoDreamSelection::SelectionType selType); + + template + void setDaughterPIDSpecies(T const& daugh, V& pids); + + template + bool daughterSelectionPos(V const& track1); + + template + bool daughterSelectionNeg(V const& track2); + + template + bool isSelectedMinimalPIDPos(V const& track1, T const& pidVector); + + template + bool isSelectedMinimalPIDNeg(V const& track2, T const& pidVector); + + template + std::array getCutContainer(V const& track1, V const& track2, float sign); + + template + std::pair checkCombination(T const& PosTrack, T const& NegTrack, V const& pidVector); + + template + float getNSigTotal(T const& track, V const& pid, float const& threshold); + + void updateSigmaPIDMax() + { + mSigmaPIDMax = posDaughTrack.getMinimalSelection(o2::analysis::femtoDream::femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); // the same for pos and neg + }; + + void setDaughternSigmaPIDOffset(femto_dream_reso_selection::Daughtertype daugh, float offsetTPC, float offsetTOF) + { + if (daugh == femto_dream_reso_selection::kPosdaugh) { + posDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); + } else if (daugh == femto_dream_reso_selection::kNegdaugh) { + negDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); + } + mPIDoffsetTPC = offsetTPC; + mPIDoffsetTOF = offsetTOF; + }; + + /// The following functions might not be needed, as right now there is only one ResoSel (sign). + /// However all the other selections are implemented this way (also in the CutCulator). + /// So for now this is implemented analogous (migth also be beneficial if further ResoSels want to be implemented). + + /// Helper function to obtain the name of a given selection criterion for consistent naming of the configurables + /// \param iSel Reso 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_dream_reso_selection::ResoSel iSel, + std::string_view prefix = "", + std::string_view suffix = "") + { + std::string outString = static_cast(prefix); + outString += static_cast(kSelectionNames[iSel]); + outString += suffix; + return outString; + } + + /// Helper function to obtain the index of a given selection variable for consistent naming of the configurables + /// \param obs Reso selection variable (together with prefix) got from file + /// \param prefix Additional prefix for the output of the configurable + static int findSelectionIndex(std::string_view obs, + std::string_view prefix = "") + { + for (int index = 0; index < kNresoSelection; index++) { + std::string comp = static_cast(prefix) + + static_cast(kSelectionNames[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 Reso selection variable whose type is returned + static femtoDreamSelection::SelectionType // o2-linter: disable=name/function-variable (defined with UpperCamelCase in femtoDreamSelection) + getSelectionType(femto_dream_reso_selection::ResoSel iSel) + { + return kSelectionTypes[iSel]; + } + + /// 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_dream_reso_selection::ResoSel iSel, + std::string_view prefix = "") + { + std::string outString = static_cast(prefix); + outString += static_cast(kSelectionHelper[iSel]); + return outString; + } + + private: + std::vector mDaughPTPCThr; + float mPIDoffsetTPC; + float mPIDoffsetTOF; + float mSigmaPIDMax; + + FemtoDreamTrackSelection posDaughTrack; + FemtoDreamTrackSelection negDaughTrack; + + static constexpr int kNresoSelection = 1; + + static constexpr std::string_view kSelectionNames[kNresoSelection] = {"Sign"}; + + static constexpr femtoDreamSelection::SelectionType kSelectionTypes[kNresoSelection]{ + femtoDreamSelection::kEqual}; + + static constexpr std::string_view kSelectionHelper[kNresoSelection] = { + "+1 for Reso, -1 for AntiReso"}; + +}; // namespace femtoDream + +template +int FemtoDreamResoSelection::getType(V const& track1, V const& track2, bool resoIsNotAnti) +{ + float posThresh = 0.; + float negThresh = 0.; + if (resoIsNotAnti) { + posThresh = mDaughPTPCThr[0]; + negThresh = mDaughPTPCThr[1]; + } else { + posThresh = mDaughPTPCThr[1]; + negThresh = mDaughPTPCThr[0]; + } + + if (part == aod::femtodreamparticle::kReso) { // Phi + if (track1.pt() <= posThresh && track2.pt() <= negThresh) { + return aod::femtodreamparticle::kResoPosdaughTPC_NegdaughTPC; + } + if (track1.pt() <= posThresh && track2.pt() > negThresh) { + return aod::femtodreamparticle::kResoPosdaughTPC_NegdaughTOF; + } + if (track1.pt() > posThresh && track2.pt() <= negThresh) { + return aod::femtodreamparticle::kResoPosdaughTOF_NegdaughTPC; + } + if (track1.pt() > posThresh && track2.pt() > negThresh) { + return aod::femtodreamparticle::kResoPosdaughTOF_NegdaughTOF; + } + return 255; // as error filler + } + if (part == aod::femtodreamparticle::kResoKStar) { // KStar + if (track1.pt() <= posThresh && track2.pt() <= negThresh) { + return aod::femtodreamparticle::kResoKStarPosdaughTPC_NegdaughTPC; + } + if (track1.pt() <= posThresh && track2.pt() > negThresh) { + return aod::femtodreamparticle::kResoKStarPosdaughTPC_NegdaughTOF; + } + if (track1.pt() > posThresh && track2.pt() <= negThresh) { + return aod::femtodreamparticle::kResoKStarPosdaughTOF_NegdaughTPC; + } + if (track1.pt() > posThresh && track2.pt() > negThresh) { + return aod::femtodreamparticle::kResoKStarPosdaughTOF_NegdaughTOF; + } + return 255; // as error filler + } + return 255; +} + +template +size_t FemtoDreamResoSelection::numBitsUsed(V const& origvalue) +{ + size_t bits = 0; + auto value = origvalue; + while (value != 0) { + ++bits; + value >>= 1; + } + return bits; +} + +template +void FemtoDreamResoSelection::init(HistogramRegistry* QAregistry, HistogramRegistry* Registry) +{ + if (QAregistry && Registry) { + mHistogramRegistry = Registry; + mQAHistogramRegistry = QAregistry; + fillSelectionHistogram(); + fillSelectionHistogram(); + + AxisSpec massAxisReso = {3000, 0.0f, 3.0f, "m_{#Reso} (GeV/#it{c}^{2})"}; + AxisSpec massAxisAntiReso = {3000, 0.0f, 3.0f, + "m_{#bar{#Reso}} (GeV/#it{c}^{2})"}; + + // initialize Histograms + std::string folderName = static_cast( + o2::aod::femtodreamparticle::ParticleTypeName[part]); + + /* + int cutBits = 8 * sizeof(o2::aod::femtodreamparticle::cutContainerType); + mQAHistogramRegistry->add((folderName + "/CutCounter"), "; Bit; Counter", kTH1F, {{cutBits + 1, -0.5, cutBits + 0.5}}); + */ + + // mass histos + mQAHistogramRegistry->add((folderName + "/InvMass"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); + mQAHistogramRegistry->add((folderName + "/InvMassAnti"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); + mQAHistogramRegistry->add((folderName + "/InvMass_phi_selected"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); + mQAHistogramRegistry->add((folderName + "/InvMassAnti_phi_selected"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); + + // ResoQA + // Histos for PosDaughter + mQAHistogramRegistry->add((folderName + "/ResoQA/PosDaughter/Pt"), "Transverse momentum of all tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/ResoQA/PosDaughter/Eta"), "Pseudorapidity of all tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + mQAHistogramRegistry->add((folderName + "/ResoQA/PosDaughter/Phi"), "Azimuthal angle of all tracks;#phi;Entries", HistType::kTH1F, {{720, 0, o2::constants::math::TwoPI}}); + mQAHistogramRegistry->add((folderName + "/ResoQA/PosDaughter/DcaXY"), "dcaXY of all tracks;d_{XY} (cm);Entries", HistType::kTH1F, {{1000, 0, 1}}); // check if cm is correct here + mQAHistogramRegistry->add((folderName + "/ResoQA/PosDaughter/DcaZ"), "dcaZ of all tracks;d_{Z} (cm);Entries", HistType::kTH1F, {{1000, 0, 1}}); // check if cm is correct here + // Histos for NegDaughter + mQAHistogramRegistry->add((folderName + "/ResoQA/NegDaughter/Pt"), "Transverse momentum of all tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/ResoQA/NegDaughter/Eta"), "Pseudorapidity of all tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + mQAHistogramRegistry->add((folderName + "/ResoQA/NegDaughter/Phi"), "Azimuthal angle of all tracks;#phi;Entries", HistType::kTH1F, {{720, 0, o2::constants::math::TwoPI}}); + mQAHistogramRegistry->add((folderName + "/ResoQA/NegDaughter/DcaXY"), "dcaXY of all tracks;d_{XY} (cm);Entries", HistType::kTH1F, {{1000, 0, 1}}); // check if cm is correct here + mQAHistogramRegistry->add((folderName + "/ResoQA/NegDaughter/DcaZ"), "dcaZ of all tracks;d_{Z} (cm);Entries", HistType::kTH1F, {{1000, 0, 1}}); // check if cm is correct here + // Histos for massQA + mQAHistogramRegistry->add((folderName + "/ResoQA/InvMassSwitched"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // for opposite mass hypothesis (Reso is anti) + mQAHistogramRegistry->add((folderName + "/ResoQA/InvMassBothPID1"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // both particles are of type confDaughterPIDspecies[0] + mQAHistogramRegistry->add((folderName + "/ResoQA/InvMassBothPID2"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // both particles are of type confDaughterPIDspecies[1] + + // AntiResoQA + // Histos for PosDaughter + mQAHistogramRegistry->add((folderName + "/AntiResoQA/PosDaughter/Pt"), "Transverse momentum of all tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/AntiResoQA/PosDaughter/Eta"), "Pseudorapidity of all tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + mQAHistogramRegistry->add((folderName + "/AntiResoQA/PosDaughter/Phi"), "Azimuthal angle of all tracks;#phi;Entries", HistType::kTH1F, {{720, 0, o2::constants::math::TwoPI}}); + mQAHistogramRegistry->add((folderName + "/AntiResoQA/PosDaughter/DcaXY"), "dcaXY of all tracks;d_{XY} (cm);Entries", HistType::kTH1F, {{1000, 0, 1}}); // check if cm is correct here + mQAHistogramRegistry->add((folderName + "/AntiResoQA/PosDaughter/DcaZ"), "dcaZ of all tracks;d_{Z} (cm);Entries", HistType::kTH1F, {{1000, 0, 1}}); // check if cm is correct here + // Histos for NegDaughter + mQAHistogramRegistry->add((folderName + "/AntiResoQA/NegDaughter/Pt"), "Transverse momentum of all tracks;p_{T} (GeV/c);Entries", HistType::kTH1F, {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/AntiResoQA/NegDaughter/Eta"), "Pseudorapidity of all tracks;#eta;Entries", HistType::kTH1F, {{1000, -2, 2}}); + mQAHistogramRegistry->add((folderName + "/AntiResoQA/NegDaughter/Phi"), "Azimuthal angle of all tracks;#phi;Entries", HistType::kTH1F, {{720, 0, o2::constants::math::TwoPI}}); + mQAHistogramRegistry->add((folderName + "/AntiResoQA/NegDaughter/DcaXY"), "dcaXY of all tracks;d_{XY} (cm);Entries", HistType::kTH1F, {{1000, 0, 1}}); // check if cm is correct here + mQAHistogramRegistry->add((folderName + "/AntiResoQA/NegDaughter/DcaZ"), "dcaZ of all tracks;d_{Z} (cm);Entries", HistType::kTH1F, {{1000, 0, 1}}); // check if cm is correct here + // Histos for massQA + mQAHistogramRegistry->add((folderName + "/AntiResoQA/InvMassSwitched"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // for opposite mass hypothesis (Reso is anti) + mQAHistogramRegistry->add((folderName + "/AntiResoQA/InvMassBothPID1"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // both particles are of type confDaughterPIDspecies[0] + mQAHistogramRegistry->add((folderName + "/AntiResoQA/InvMassBothPID2"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // both particles are of type confDaughterPIDspecies[1] + + // likeSign MassHistos + mQAHistogramRegistry->add((folderName + "/ResoLikeSign/ResoQA/InvMass"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); + mQAHistogramRegistry->add((folderName + "/ResoLikeSign/ResoQA/InvMassSwitched"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // for opposite mass hypothesis (Reso is anti) + mQAHistogramRegistry->add((folderName + "/ResoLikeSign/ResoQA/InvMassBothPID1"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // both particles are of type confDaughterPIDspecies[0] + mQAHistogramRegistry->add((folderName + "/ResoLikeSign/ResoQA/InvMassBothPID2"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // both particles are of type confDaughterPIDspecies[1] + + mQAHistogramRegistry->add((folderName + "/ResoLikeSign/AntiResoQA/InvMass"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); + mQAHistogramRegistry->add((folderName + "/ResoLikeSign/AntiResoQA/InvMassSwitched"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // for opposite mass hypothesis (Reso is anti) + mQAHistogramRegistry->add((folderName + "/ResoLikeSign/AntiResoQA/InvMassBothPID1"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // both particles are of type confDaughterPIDspecies[0] + mQAHistogramRegistry->add((folderName + "/ResoLikeSign/AntiResoQA/InvMassBothPID2"), "Invariant mass V0s;M_{KK};Entries", HistType::kTH1F, {massAxisReso}); // both particles are of type confDaughterPIDspecies[1] + + posDaughTrack.init( + mQAHistogramRegistry, mHistogramRegistry); + + negDaughTrack.init( + mQAHistogramRegistry, mHistogramRegistry); + } +} + +template +void FemtoDreamResoSelection::fillQA(T const& track1, T const& track2) +{ + // Also fill mass_selected histos + posDaughTrack.fillQA(track1); + negDaughTrack.fillQA(track2); +} + +template +void FemtoDreamResoSelection::fillMassSelectedQA(float const& mass, bool const& isNotAnti) +{ + if (isNotAnti) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/InvMass_phi_selected"), + mass); + } else { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/InvMassAnti_phi_selected"), + mass); + } +} + +template +void FemtoDreamResoSelection::fillResoQA(T const& trackPos, T const& trackNeg, bool const& isNotAnti, float const& mass, float const& massOtherHypothesis, V const& pidVector, o2::track::PID::ID const& extraPID) +{ + // calculate invMass + float massPart1 = o2::track::PID::getMass(pidVector[0]); + float massPart2 = o2::track::PID::getMass(extraPID); + if (pidVector.size() > 1 && pidVector[0] != pidVector[1]) { + massPart2 = o2::track::PID::getMass(pidVector[1]); + } + + ROOT::Math::PtEtaPhiMVector tempDaughter1MassQA1(trackPos.pt(), trackPos.eta(), trackPos.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempDaughter2MassQA1(trackNeg.pt(), trackNeg.eta(), trackNeg.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempMassBothPID1 = tempDaughter1MassQA1 + tempDaughter2MassQA1; + + ROOT::Math::PtEtaPhiMVector tempDaughter1MassQA2(trackPos.pt(), trackPos.eta(), trackPos.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempDaughter2MassQA2(trackNeg.pt(), trackNeg.eta(), trackNeg.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempMassBothPID2 = tempDaughter1MassQA2 + tempDaughter2MassQA2; + + if (isNotAnti) { + /// filling mass histograms + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/InvMass"), mass); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/InvMassSwitched"), massOtherHypothesis); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/InvMassBothPID1"), tempMassBothPID1.M()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/InvMassBothPID2"), tempMassBothPID2.M()); + + // filling daughter histos + // pos + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/PosDaughter/Pt"), trackPos.pt()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/PosDaughter/Eta"), trackPos.eta()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/PosDaughter/Phi"), trackPos.phi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/PosDaughter/DcaXY"), trackPos.dcaXY()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/PosDaughter/DcaZ"), trackPos.dcaZ()); + // neg + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/NegDaughter/Eta"), trackNeg.eta()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/NegDaughter/Phi"), trackNeg.phi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/NegDaughter/Pt"), trackNeg.pt()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/NegDaughter/DcaXY"), trackNeg.dcaXY()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoQA/NegDaughter/DcaZ"), trackNeg.dcaZ()); + } else { + /// filling mass histograms + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/InvMassAnti"), mass); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/InvMassSwitched"), massOtherHypothesis); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/InvMassBothPID1"), tempMassBothPID1.M()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/InvMassBothPID2"), tempMassBothPID2.M()); + + // filling daughter histos + // pos + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/PosDaughter/Pt"), trackPos.pt()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/PosDaughter/Eta"), trackPos.eta()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/PosDaughter/Phi"), trackPos.phi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/PosDaughter/DcaXY"), trackPos.dcaXY()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/PosDaughter/DcaZ"), trackPos.dcaZ()); + // neg + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/NegDaughter/Eta"), trackNeg.eta()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/NegDaughter/Phi"), trackNeg.phi()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/NegDaughter/Pt"), trackNeg.pt()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/NegDaughter/DcaXY"), trackNeg.dcaXY()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/AntiResoQA/NegDaughter/DcaZ"), trackNeg.dcaZ()); + } +} + +template +void FemtoDreamResoSelection::fillLikeSignHistos(T const& trackPos, T const& trackNeg, V const& pidVector, o2::track::PID::ID const& extraPID, bool resoIsNotAnti) +{ + float massPart1 = o2::track::PID::getMass(pidVector[0]); + float massPart2 = massPart1; + if (pidVector.size() > 1) + massPart2 = o2::track::PID::getMass(pidVector[1]); + + /// Resonance + ROOT::Math::PtEtaPhiMVector tempD1(trackPos.pt(), trackPos.eta(), trackPos.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempD2(trackNeg.pt(), trackNeg.eta(), trackNeg.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempReso = tempD1 + tempD2; + /// Anti-resonance + ROOT::Math::PtEtaPhiMVector tempDA1(trackPos.pt(), trackPos.eta(), trackPos.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempDA2(trackNeg.pt(), trackNeg.eta(), trackNeg.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempAntiReso = tempDA1 + tempDA2; + + if (pidVector.size() < 1 || pidVector[0] == pidVector[1]) { + massPart2 = o2::track::PID::getMass(extraPID); + } + + ROOT::Math::PtEtaPhiMVector tempDaughter1MassQA1(trackPos.pt(), trackPos.eta(), trackPos.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempDaughter2MassQA1(trackNeg.pt(), trackNeg.eta(), trackNeg.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempMassBothPID1 = tempDaughter1MassQA1 + tempDaughter2MassQA1; + + ROOT::Math::PtEtaPhiMVector tempDaughter1MassQA2(trackPos.pt(), trackPos.eta(), trackPos.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempDaughter2MassQA2(trackNeg.pt(), trackNeg.eta(), trackNeg.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempMassBothPID2 = tempDaughter1MassQA2 + tempDaughter2MassQA2; + + if (resoIsNotAnti) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoLikeSign/ResoQA/InvMass"), tempReso.M()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoLikeSign/ResoQA/InvMassSwitched"), tempAntiReso.M()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoLikeSign/ResoQA/InvMassBothPID1"), tempMassBothPID1.M()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoLikeSign/ResoQA/InvMassBothPID2"), tempMassBothPID2.M()); + } else { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoLikeSign/AntiResoQA/InvMass"), tempAntiReso.M()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoLikeSign/AntiResoQA/InvMassSwitched"), tempReso.M()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoLikeSign/AntiResoQA/InvMassBothPID1"), tempMassBothPID1.M()); + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("/ResoLikeSign/AntiResoQA/InvMassBothPID2"), tempMassBothPID2.M()); + } +} + +template +void FemtoDreamResoSelection::setDaughterCuts(femto_dream_reso_selection::Daughtertype daugh, T selVal, + V selVar, femtoDreamSelection::SelectionType selType) +{ + if (daugh == femto_dream_reso_selection::kPosdaugh) { + posDaughTrack.setSelection(selVal, selVar, selType); + } + if (daugh == femto_dream_reso_selection::kNegdaugh) { + negDaughTrack.setSelection(selVal, selVar, selType); + } +} + +template +void FemtoDreamResoSelection::setDaughterPIDSpecies(T const& daugh, V& pids) +{ + if (daugh == femto_dream_reso_selection::kPosdaugh) { + posDaughTrack.setPIDSpecies(pids); + } + if (daugh == femto_dream_reso_selection::kNegdaugh) { + negDaughTrack.setPIDSpecies(pids); + } +} + +template +bool FemtoDreamResoSelection::daughterSelectionPos(V const& track1) +{ + return posDaughTrack.isSelectedMinimal(track1); +} + +template +bool FemtoDreamResoSelection::daughterSelectionNeg(V const& track2) +{ + return negDaughTrack.isSelectedMinimal(track2); +} + +template +bool FemtoDreamResoSelection::isSelectedMinimalPIDPos(V const& track1, T const& pidVector) +{ + int pidVecSize = pidVector.size(); + for (int i = 0; i < pidVecSize; i++) { + const float pidTPC = posDaughTrack.getNsigmaTPC(track1, pidVector[i]); + const float pidTOF = posDaughTrack.getNsigmaTOF(track1, pidVector[i]); + + if (track1.pt() < mDaughPTPCThr[i]) { + if (std::fabs(pidTPC) < mSigmaPIDMax) { + return true; + } + } else if ((std::sqrt(pidTPC * pidTPC + pidTOF * pidTOF) < mSigmaPIDMax)) { + return true; + } + } + return false; +} + +template +bool FemtoDreamResoSelection::isSelectedMinimalPIDNeg(V const& track2, T const& pidVector) +{ + int pidVecSize = pidVector.size(); + for (int i = 0; i < pidVecSize; i++) { + const float pidTPC = negDaughTrack.getNsigmaTPC(track2, pidVector[i]); + const float pidTOF = negDaughTrack.getNsigmaTOF(track2, pidVector[i]); + + if (track2.pt() < mDaughPTPCThr[i]) { + if (std::fabs(pidTPC) < mSigmaPIDMax) { + return true; + } + } else if ((std::sqrt(pidTPC * pidTPC + pidTOF * pidTOF) < mSigmaPIDMax)) { + return true; + } + } + return false; +} + +template +std::pair FemtoDreamResoSelection::checkCombination(T const& PosTrack, T const& NegTrack, V const& pidVector) +{ + /// first bool: true (normal resonance) / false (anti resonance) + /// second bool: is not a valid combination + + const auto part1 = pidVector[0]; /// particle type 1 + const auto part2 = pidVector[1]; /// particle type 2 + + float nSigPosPart1Total = getNSigTotal(PosTrack, part1, mDaughPTPCThr[0]); /// Total propability that PosTrack is of particle type 1 + float nSigPosPart2Total = getNSigTotal(PosTrack, part2, mDaughPTPCThr[1]); /// Total propability that PosTrack is of particle type 2 + float nSigNegPart1Total = getNSigTotal(NegTrack, part1, mDaughPTPCThr[0]); + float nSigNegPart2Total = getNSigTotal(NegTrack, part2, mDaughPTPCThr[1]); + + // check if PosTrack is more likely to be part1 than part2 (and vice versa for NegTrack) -> normal resonance + bool couldBeNormal = nSigPosPart1Total < nSigPosPart2Total && nSigNegPart2Total < nSigNegPart1Total; + // check if PosTrack is more likely to be part2 than part1 (and vice versa for NegTrack) -> anti resonance + bool couldBeAnti = nSigPosPart2Total < nSigPosPart1Total && nSigNegPart1Total < nSigNegPart2Total; + + /* + if (useMassDiff) { + couldBeNormal = couldBeNormal && massDiff < massDiffAnti; + couldBeAnti = couldBeAnti && massDiffAnti < massDiff; + } + */ + + if (couldBeNormal && !couldBeAnti) { + return {true, false}; + } + if (!couldBeNormal && couldBeAnti) { + return {false, false}; + } + // if ambiguous (both true) or invalid (both false) + return {false, true}; +} + +template +float FemtoDreamResoSelection::getNSigTotal(T const& track, V const& pid, float const& threshold) +{ + float nSigTPC = o2::aod::pidutils::tpcNSigma(pid, track); + float pTtrack = track.pt(); + + if (pTtrack < threshold) { + return std::abs(nSigTPC); + } + + float nSigTOF = track.hasTOF() ? o2::aod::pidutils::tofNSigma(pid, track) : 999.f; + + return std::hypot(nSigTPC, nSigTOF); +} + +//// new getCutContainer +template +std::array FemtoDreamResoSelection::getCutContainer(V const& track1, V const& track2, float sign) +{ + cutContainerType outputSign = 0; + cutContainerType outputPID = 0; + size_t counter = 0; + for (auto& sel : mSelections) { // o2-linter: disable=const-ref-in-for-loop (femtoDreamObjectSelection has no const getter) + const auto selVariable = sel.getSelectionVariable(); + if (selVariable == femto_dream_reso_selection::kResoSign) { + sel.checkSelectionSetBit(sign, outputSign, counter, nullptr); + } + } + + const auto dCA1 = std::sqrt(track1.dcaXY() * track1.dcaXY() + track1.dcaZ() * track1.dcaZ()); + const auto dCA2 = std::sqrt(track2.dcaXY() * track2.dcaXY() + track2.dcaZ() * track2.dcaZ()); + + auto outputPosTrack = posDaughTrack.getCutContainer(track1, track1.pt(), track1.eta(), dCA1); // false for useItsPid + auto outputNegTrack = negDaughTrack.getCutContainer(track2, track2.pt(), track2.eta(), dCA2); + + const auto shiftvalue = numBitsUsed(outputSign); + outputPID = (outputNegTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID) << shiftvalue) | outputSign; + + std::array bitmask = {outputPID, + outputPosTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + outputPosTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID), + outputNegTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + outputNegTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID)}; + return bitmask; +} +} // namespace o2::analysis::femtoDream + +#endif // PWGCF_FEMTODREAM_CORE_FEMTODREAMRESOSELECTION_H_ diff --git a/PWGCF/FemtoDream/Core/femtoDreamSelection.h b/PWGCF/FemtoDream/Core/femtoDreamSelection.h index 73d29ff7d51..90fd8f58046 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamSelection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamSelection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -16,10 +16,12 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMSELECTION_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMSELECTION_H_ -#include -#include "Framework/HistogramRegistry.h" #include "PWGCF/DataModel/FemtoDerived.h" +#include "Framework/HistogramRegistry.h" + +#include + using namespace o2; using namespace o2::framework; @@ -36,6 +38,9 @@ enum SelectionType { kUpperLimit, ///< simple upper limit for the value, e.g. kEqual ///< values need to be equal, e.g. sign = 1 }; +static constexpr int kNcutStages = 2; +static constexpr std::string_view mCutStage[kNcutStages] = {"BeforeSel", "AfterSel"}; + } // namespace femtoDreamSelection /// Simple class taking care of individual selections @@ -84,16 +89,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 221988a4d3f..b0041a2e12d 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h @@ -17,20 +17,24 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMTRACKSELECTION_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMTRACKSELECTION_H_ -#include -#include -#include -#include - #include "PWGCF/DataModel/FemtoDerived.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGCF/FemtoDream/Core/femtoDreamObjectSelection.h" + #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "PWGCF/FemtoDream/Core/femtoDreamObjectSelection.h" -#include "ReconstructionDataFormats/PID.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/PID.h" + +#include +#include +#include using namespace o2::framework; +using namespace o2::analysis::femtoDream::femtoDreamSelection; namespace o2::analysis::femtoDream { @@ -108,7 +112,7 @@ class FemtoDreamTrackSelection : public FemtoDreamObjectSelection tmpPids = pids; /// necessary due to some features of the configurable - for (o2::track::PID pid : tmpPids) { + for (const o2::track::PID pid : tmpPids) { mPIDspecies.push_back(pid); } } @@ -129,11 +133,19 @@ 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 /// \return Whether the most open combination of all selection criteria is fulfilled - template + template bool isSelectedMinimal(T const& track); /// Obtain the bit-wise container for the selections @@ -146,7 +158,7 @@ class FemtoDreamTrackSelection : public FemtoDreamObjectSelection + template std::array getCutContainer(T const& track, R Pt, R Eta, R Dcaxy); /// Some basic QA histograms @@ -154,7 +166,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 +286,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 @@ -384,6 +399,28 @@ auto FemtoDreamTrackSelection::getNsigmaTOF(T const& track, o2::track::PID pid) 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 bool FemtoDreamTrackSelection::isSelectedMinimal(T const& track) { @@ -400,7 +437,7 @@ bool FemtoDreamTrackSelection::isSelectedMinimal(T const& track) const auto dca = track.dcaXY(); // Accordingly to FemtoDream 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 : mPIDspecies) { pidTPC.push_back(getNsigmaTPC(track, it)); pidTOF.push_back(getNsigmaTOF(track, it)); } @@ -411,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) { @@ -432,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; } @@ -449,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; } } @@ -457,10 +494,11 @@ bool FemtoDreamTrackSelection::isSelectedMinimal(T const& track) return isFulfilled; } } + return true; } -template +template std::array FemtoDreamTrackSelection::getCutContainer(T const& track, R Pt, R Eta, R Dca) { cutContainerType output = 0; @@ -479,23 +517,30 @@ std::array FemtoDreamTrackSelection::getCutContainer(T cons const auto dcaZ = track.dcaZ(); const auto dca = Dca; - std::vector pidTPC, pidTOF; - for (auto it : mPIDspecies) { + std::vector pidTPC, pidTOF, pidITS; + for (const 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(); + 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 @@ -546,43 +591,42 @@ 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_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("/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("/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("/") + 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("/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("/nSigmaTOF_el"), track.p(), track.tofNSigmaEl()); - 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_d"), track.p(), track.tpcNSigmaDe()); - 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("/nSigmaTOF_d"), track.p(), track.tofNSigmaDe()); + 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 1d6cb84b78c..53cd9e6a36b 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamUtils.h +++ b/PWGCF/FemtoDream/Core/femtoDreamUtils.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -16,88 +16,15 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMUTILS_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMUTILS_H_ -#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); -} +#include "CommonConstants/PhysicsConstants.h" -/// 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; -}; +#include +#include -/// 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) +namespace o2::analysis::femtoDream { - 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 @@ -109,26 +36,51 @@ inline float getMass(int pdgCode) float mass = 0; // add new particles if necessary here switch (std::abs(pdgCode)) { - case kPiPlus: // charged pions, changed magic number as per their pdg name + case kPiPlus: mass = o2::constants::physics::MassPiPlus; break; - case kKPlus: // charged kaon + case kKPlus: mass = o2::constants::physics::MassKPlus; break; - case kProton: // proton + case kProton: mass = o2::constants::physics::MassProton; break; - case kLambda0: // Lambda + case kLambda0: mass = o2::constants::physics::MassLambda; break; - case o2::constants::physics::Pdg::kLambdaCPlus: // Charm Lambda + case kXiMinus: + mass = o2::constants::physics::MassXiMinus; + break; + case o2::constants::physics::Pdg::kPhi: + mass = o2::constants::physics::MassPhi; + break; + case o2::constants::physics::Pdg::kDPlus: + mass = o2::constants::physics::MassDPlus; + break; + case o2::constants::physics::Pdg::kLambdaCPlus: mass = o2::constants::physics::MassLambdaCPlus; break; - case o2::constants::physics::Pdg::kDeuteron: // Deuteron + 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; + // case o2::constants::physics::Pdg::kOmegaMinus: + case kOmegaMinus: + mass = o2::constants::physics::MassOmegaMinus; + break; + case o2::constants::physics::Pdg::kK0Star892: + mass = o2::constants::physics::MassK0Star892; + break; + case 310: /// K0Short is not implemented in o2::physics::constants::Pdg + mass = o2::constants::physics::MassK0Short; + break; default: - LOG(fatal) << "PDG code is not suppored"; + LOG(fatal) << "PDG code is not supported"; } return mass; } @@ -137,11 +89,11 @@ inline int checkDaughterType(o2::aod::femtodreamparticle::ParticleType partType, { int partOrigin = 0; if (partType == o2::aod::femtodreamparticle::ParticleType::kTrack) { - switch (abs(motherPDG)) { - case 3122: + switch (std::abs(motherPDG)) { + case kLambda0: partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterLambda; break; - case 3222: + case kSigmaPlus: partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryDaughterSigmaplus; break; default: @@ -149,14 +101,26 @@ inline int checkDaughterType(o2::aod::femtodreamparticle::ParticleType partType, } // switch } else if (partType == o2::aod::femtodreamparticle::ParticleType::kV0) { - partOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondary; + switch (std::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: @@ -184,5 +148,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..3cd52ebd219 100644 --- a/PWGCF/FemtoDream/Core/femtoDreamV0Selection.h +++ b/PWGCF/FemtoDream/Core/femtoDreamV0Selection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -18,19 +18,21 @@ #ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMV0SELECTION_H_ #define PWGCF_FEMTODREAM_CORE_FEMTODREAMV0SELECTION_H_ -#include -#include -#include - #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" +#include +#include +#include + using namespace o2::framework; +using namespace o2::analysis::femtoDream::femtoDreamSelection; namespace o2::analysis::femtoDream { @@ -91,7 +93,8 @@ class FemtoDreamV0Selection T const& posTrack, T const& negTrack); - template void fillQA(C const& col, V const& v0, T const& posTrack, T const& negTrack); @@ -296,43 +299,46 @@ void FemtoDreamV0Selection::init(HistogramRegistry* QAregistry, HistogramRegistr LOG(fatal) << "FemtoDreamV0Cuts: Number of selections to large for your " "container - quitting!"; } - std::string folderName = static_cast( - o2::aod::femtodreamparticle::ParticleTypeName[part]); - /// \todo initialize histograms for children tracks of v0s - mQAHistogramRegistry->add((folderName + "/hPt").c_str(), - "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, - {{1000, 0, 10}}); - mQAHistogramRegistry->add((folderName + "/hEta").c_str(), "; #eta; Entries", - kTH1F, {{1000, -1, 1}}); - mQAHistogramRegistry->add((folderName + "/hPhi").c_str(), "; #phi; Entries", - kTH1F, {{1000, 0, 2. * M_PI}}); - mQAHistogramRegistry->add((folderName + "/hDaughDCA").c_str(), - "; DCA^{daugh} (cm); Entries", kTH1F, - {{1000, 0, 10}}); - mQAHistogramRegistry->add((folderName + "/hTransRadius").c_str(), - "; #it{r}_{xy} (cm); Entries", kTH1F, - {{1500, 0, 150}}); - mQAHistogramRegistry->add((folderName + "/hDecayVtxX").c_str(), - "; #it{Vtx}_{x} (cm); Entries", kTH1F, - {{2000, 0, 200}}); - mQAHistogramRegistry->add((folderName + "/hDecayVtxY").c_str(), - "; #it{Vtx}_{y} (cm)); Entries", kTH1F, - {{2000, 0, 200}}); - mQAHistogramRegistry->add((folderName + "/hDecayVtxZ").c_str(), - "; #it{Vtx}_{z} (cm); Entries", kTH1F, - {{2000, 0, 200}}); - mQAHistogramRegistry->add((folderName + "/hCPA").c_str(), - "; #it{cos #theta_{p}}; Entries", kTH1F, - {{1000, 0.9, 1.}}); - mQAHistogramRegistry->add((folderName + "/hCPAvsPt").c_str(), - "; #it{p}_{T} (GeV/#it{c}); #it{cos #theta_{p}}", - kTH2F, {{8, 0.3, 4.3}, {1000, 0.9, 1.}}); - mQAHistogramRegistry->add((folderName + "/hInvMassLambda").c_str(), "", kTH1F, - {massAxisLambda}); - mQAHistogramRegistry->add((folderName + "/hInvMassAntiLambda").c_str(), "", - kTH1F, {massAxisAntiLambda}); - mQAHistogramRegistry->add((folderName + "/hInvMassLambdaAntiLambda").c_str(), - "", kTH2F, {massAxisLambda, massAxisAntiLambda}); + for (int istage = 0; istage < kNcutStages; istage++) { + std::string folderName = + static_cast(o2::aod::femtodreamparticle::ParticleTypeName[part]) + "/" + + static_cast(mCutStage[istage]); + /// \todo initialize histograms for children tracks of v0s + mQAHistogramRegistry->add((folderName + "/hPt").c_str(), + "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, + {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/hEta").c_str(), "; #eta; Entries", + kTH1F, {{1000, -1, 1}}); + mQAHistogramRegistry->add((folderName + "/hPhi").c_str(), "; #phi; Entries", + kTH1F, {{1000, 0, 2. * M_PI}}); + mQAHistogramRegistry->add((folderName + "/hDaughDCA").c_str(), + "; DCA^{daugh} (cm); Entries", kTH1F, + {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/hTransRadius").c_str(), + "; #it{r}_{xy} (cm); Entries", kTH1F, + {{1500, 0, 150}}); + mQAHistogramRegistry->add((folderName + "/hDecayVtxX").c_str(), + "; #it{Vtx}_{x} (cm); Entries", kTH1F, + {{2000, 0, 200}}); + mQAHistogramRegistry->add((folderName + "/hDecayVtxY").c_str(), + "; #it{Vtx}_{y} (cm)); Entries", kTH1F, + {{2000, 0, 200}}); + mQAHistogramRegistry->add((folderName + "/hDecayVtxZ").c_str(), + "; #it{Vtx}_{z} (cm); Entries", kTH1F, + {{2000, 0, 200}}); + mQAHistogramRegistry->add((folderName + "/hCPA").c_str(), + "; #it{cos #theta_{p}}; Entries", kTH1F, + {{1000, 0.9, 1.}}); + mQAHistogramRegistry->add((folderName + "/hCPAvsPt").c_str(), + "; #it{p}_{T} (GeV/#it{c}); #it{cos #theta_{p}}", + kTH2F, {{8, 0.3, 4.3}, {1000, 0.9, 1.}}); + mQAHistogramRegistry->add((folderName + "/hInvMassLambda").c_str(), "", kTH1F, + {massAxisLambda}); + mQAHistogramRegistry->add((folderName + "/hInvMassAntiLambda").c_str(), "", + kTH1F, {massAxisAntiLambda}); + mQAHistogramRegistry->add((folderName + "/hInvMassLambdaAntiLambda").c_str(), + "", kTH2F, {massAxisLambda, massAxisAntiLambda}); + } PosDaughTrack.init 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 +574,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.; } } @@ -636,7 +642,8 @@ std::array outputNegTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID)}; } -template void FemtoDreamV0Selection::fillQA(C const& /*col*/, V const& v0, T const& posTrack, @@ -645,62 +652,62 @@ void FemtoDreamV0Selection::fillQA(C const& /*col*/, V const& v0, T const& posTr if (mQAHistogramRegistry) { mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hPt"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hPt"), v0.pt()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hEta"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hEta"), v0.eta()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hPhi"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hPhi"), v0.phi()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hDaughDCA"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDaughDCA"), v0.dcaV0daughters()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hTransRadius"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hTransRadius"), v0.v0radius()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hDecayVtxX"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDecayVtxX"), v0.x()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hDecayVtxY"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDecayVtxY"), v0.y()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hDecayVtxZ"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hDecayVtxZ"), v0.z()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hCPA"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hCPA"), v0.v0cosPA()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hCPAvsPt"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hCPAvsPt"), v0.pt(), v0.v0cosPA()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hInvMassLambda"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hInvMassLambda"), v0.mLambda()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hInvMassAntiLambda"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hInvMassAntiLambda"), v0.mAntiLambda()); mQAHistogramRegistry->fill( HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + - HIST("/hInvMassLambdaAntiLambda"), + HIST("/") + HIST(mCutStage[cutstage]) + HIST("/hInvMassLambdaAntiLambda"), v0.mLambda(), v0.mAntiLambda()); } PosDaughTrack.fillQA(posTrack); + aod::femtodreamparticle::TrackType::kPosChild, cutstage>(posTrack); NegDaughTrack.fillQA(negTrack); + aod::femtodreamparticle::TrackType::kNegChild, cutstage>(negTrack); } } // namespace o2::analysis::femtoDream diff --git a/PWGCF/FemtoDream/Core/femtoDreamV0SelectionK0Short.h b/PWGCF/FemtoDream/Core/femtoDreamV0SelectionK0Short.h new file mode 100644 index 00000000000..b404f9f5b06 --- /dev/null +++ b/PWGCF/FemtoDream/Core/femtoDreamV0SelectionK0Short.h @@ -0,0 +1,774 @@ +// 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 femtoDreamV0SelectionK0Short.h +/// \brief Definition of the FemtoDreamV0Selection +/// \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 Christopher Klumm, TU München, christopher.klumm@cern.ch +/// \author Nils Fabian Konert, TU München, nils.fabian.konert@cern.ch + +#ifndef PWGCF_FEMTODREAM_CORE_FEMTODREAMV0SELECTIONK0SHORT_H_ +#define PWGCF_FEMTODREAM_CORE_FEMTODREAMV0SELECTIONK0SHORT_H_ + +#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" + +#include +#include + +namespace o2::analysis::femtoDream +{ + +namespace femto_dream_v0_selection +{ +/// The different selections this task is capable of doing +enum V0Sel { + kV0Sign, ///< +1 particle, -1 antiparticle + kV0pTMin, + kV0pTMax, + kV0etaMax, + kV0DCADaughMax, + kV0CPAMin, + kV0TranRadMin, + kV0TranRadMax, + kV0DecVtxMax, +}; + +enum ChildTrackType { kPosTrack, + kNegTrack }; + +enum V0ContainerPosition { + kV0, + kPosCuts, + kPosPID, + kNegCuts, + kNegPID, +}; /// Position in the full VO cut container + +} // namespace femto_dream_v0_selection + +/// \class FemtoDreamV0Selection +/// \brief Cut class to contain and execute all cuts applied to V0s +class FemtoDreamV0Selection + : public FemtoDreamObjectSelection +{ + public: + FemtoDreamV0Selection() + : 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), fRejectLambda(false), fInvMassKaonLowLimit(0.48), fInvMassKaonUpLimit(0.515), nSigmaPIDOffsetTPC(0.), fMotherIsLambda(true) {} + + /// Initializes histograms for the task + template + void init(HistogramRegistry* QAregistry, HistogramRegistry* Registry); + + template + bool isSelectedMinimal(C const& col, V const& v0, T const& posTrack, + T const& negTrack); + + template + void fillLambdaQA(C const& col, V const& v0, T const& posTrack, + T const& negTrack); + + /// \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, + T const& posTrack, + T const& negTrack); + + template + void fillQA(C const& col, V const& v0, T const& posTrack, T const& negTrack); + + template + void setChildCuts(femto_dream_v0_selection::ChildTrackType child, T1 selVal, T2 selVar, femtoDreamSelection::SelectionType selType) + { + if (child == femto_dream_v0_selection::kPosTrack) { + posDaughTrack.setSelection(selVal, selVar, selType); + } else if (child == femto_dream_v0_selection::kNegTrack) { + negDaughTrack.setSelection(selVal, selVar, selType); + } + } + + template + void setChildPIDSpecies(femto_dream_v0_selection::ChildTrackType child, T& pids) + { + if (child == femto_dream_v0_selection::kPosTrack) { + posDaughTrack.setPIDSpecies(pids); + } else if (child == femto_dream_v0_selection::kNegTrack) { + negDaughTrack.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_dream_v0_selection::V0Sel 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 index of a given selection variable for consistent naming of the configurables + /// \param obs V0 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 < kNv0Selection; index++) { + std::string comp = static_cast(prefix) + + static_cast(SelectionNames[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 V0 selection variable whose type is returned + static femtoDreamSelection::SelectionType getSelectionType(femto_dream_v0_selection::V0Sel iSel) + { // o2-linter: disable=name/function-variable (defined with UpperCamelCase in femtoDreamSelection) + 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(femto_dream_v0_selection::V0Sel 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 kaon rejection on the invariant mass + /// \param lowLimit Lower limit for the invariant mass distribution + /// \param upLimit Upper limit for the invariant mass distribution + void setKaonInvMassLimits(float lowLimit, float upLimit) + { + fRejectKaon = true; + fInvMassKaonLowLimit = lowLimit; + fInvMassKaonUpLimit = upLimit; + } + + void setnSigmaPIDOffsetTPC(float offsetTPC) + { + nSigmaPIDOffsetTPC = offsetTPC; + } + + void setChildRejectNotPropagatedTracks(femto_dream_v0_selection::ChildTrackType child, bool reject) + { + if (child == femto_dream_v0_selection::kPosTrack) { + posDaughTrack.setRejectNotPropagatedTracks(reject); + } else if (child == femto_dream_v0_selection::kNegTrack) { + negDaughTrack.setRejectNotPropagatedTracks(reject); + } + } + + void setChildnSigmaPIDOffset(femto_dream_v0_selection::ChildTrackType child, float offsetTPC, float offsetTOF) + { + if (child == femto_dream_v0_selection::kPosTrack) { + posDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); + } else if (child == femto_dream_v0_selection::kNegTrack) { + negDaughTrack.setnSigmaPIDOffset(offsetTPC, offsetTOF); + } + } + + void setIsMother(bool IsMother) + { + fMotherIsLambda = IsMother; + } + + void setRejectLambda(bool reject) + { + fRejectLambda = reject; + } + + private: + int nPtV0MinSel; + int nPtV0MaxSel; + int nEtaV0MaxSel; + int nDCAV0DaughMax; + int nCPAV0Min; + int nTranRadV0Min; + int nTranRadV0Max; + int nDecVtxMax; + float pTV0Min; + float pTV0Max; + float etaV0Max; + float dCAV0DaughMax; + float cPAV0Min; + float tranRadV0Min; + float tranRadV0Max; + float decVtxMax; + + float fInvMassLowLimit; + float fInvMassUpLimit; + + bool fRejectKaon; + bool fRejectLambda; + float fInvMassKaonLowLimit; + float fInvMassKaonUpLimit; + + float nSigmaPIDOffsetTPC; + + bool fMotherIsLambda; + + FemtoDreamTrackSelection posDaughTrack; + FemtoDreamTrackSelection negDaughTrack; + + static constexpr int kNv0Selection = 9; + + static constexpr std::string_view SelectionNames[kNv0Selection] = { + "Sign", "PtMin", "PtMax", "EtaMax", "DCAdaughMax", "CPAMin", + "TranRadMin", "TranRadMax", "DecVecMax"}; ///< Name of the different + ///< selections + + static constexpr femtoDreamSelection::SelectionType + mSelectionTypes[kNv0Selection]{ + femtoDreamSelection::kEqual, + femtoDreamSelection::kLowerLimit, + femtoDreamSelection::kUpperLimit, + femtoDreamSelection::kUpperLimit, + femtoDreamSelection::kUpperLimit, + femtoDreamSelection::kLowerLimit, + femtoDreamSelection::kLowerLimit, + femtoDreamSelection::kUpperLimit, + femtoDreamSelection::kUpperLimit}; ///< Map to match a variable with + ///< its type + + static constexpr std::string_view SelectionHelper[kNv0Selection] = { + "+1 for lambda, -1 for antilambda", + "Minimum pT (GeV/c)", + "Maximum pT (GeV/c)", + "Maximum |Eta|", + "Maximum DCA between daughters (cm)", + "Minimum Cosine of Pointing Angle", + "Minimum transverse radius (cm)", + "Maximum transverse radius (cm)", + "Maximum distance from primary vertex"}; ///< Helper information for the + ///< different selections + +}; // namespace femtoDream + +template +void FemtoDreamV0Selection::init(HistogramRegistry* QAregistry, HistogramRegistry* Registry) +{ + if (QAregistry && Registry) { + mHistogramRegistry = Registry; + mQAHistogramRegistry = QAregistry; + fillSelectionHistogram(); + fillSelectionHistogram(); + + AxisSpec massAxisLambda = {600, 0.0f, 3.0f, "m_{#Lambda} (GeV/#it{c}^{2})"}; /// paramters for K0Short + AxisSpec massAxisAntiLambda = {600, 0.0f, 3.0f, + "m_{#bar{#Lambda}} (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)) { // o2-linter: disable=magic-number (number represents bitsize) + LOG(fatal) << "FemtoDreamV0Cuts: Number of selections to large for your " + "container - quitting!"; + } + + std::string folderName = static_cast( + o2::aod::femtodreamparticle::ParticleTypeName[part]); + /// \todo initialize histograms for children tracks of v0s + mQAHistogramRegistry->add((folderName + "/hPt").c_str(), + "; #it{p}_{T} (GeV/#it{c}); Entries", kTH1F, + {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/hEta").c_str(), "; #eta; Entries", + kTH1F, {{1000, -1, 1}}); + mQAHistogramRegistry->add((folderName + "/hPhi").c_str(), "; #phi; Entries", + kTH1F, {{1000, 0, o2::constants::math::TwoPI}}); + mQAHistogramRegistry->add((folderName + "/hDaughDCA").c_str(), + "; DCA^{daugh} (cm); Entries", kTH1F, + {{1000, 0, 10}}); + mQAHistogramRegistry->add((folderName + "/hTransRadius").c_str(), + "; #it{r}_{xy} (cm); Entries", kTH1F, + {{1500, 0, 150}}); + mQAHistogramRegistry->add((folderName + "/hDecayVtxX").c_str(), + "; #it{Vtx}_{x} (cm); Entries", kTH1F, + {{2000, 0, 200}}); + mQAHistogramRegistry->add((folderName + "/hDecayVtxY").c_str(), + "; #it{Vtx}_{y} (cm)); Entries", kTH1F, + {{2000, 0, 200}}); + mQAHistogramRegistry->add((folderName + "/hDecayVtxZ").c_str(), + "; #it{Vtx}_{z} (cm); Entries", kTH1F, + {{2000, 0, 200}}); + mQAHistogramRegistry->add((folderName + "/hCPA").c_str(), + "; #it{cos #theta_{p}}; Entries", kTH1F, + {{1000, 0.9, 1.}}); + mQAHistogramRegistry->add((folderName + "/hCPAvsPt").c_str(), + "; #it{p}_{T} (GeV/#it{c}); #it{cos #theta_{p}}", + kTH2F, {{8, 0.3, 4.3}, {1000, 0.9, 1.}}); + mQAHistogramRegistry->add((folderName + "/hInvMassLambda").c_str(), "", kTH1F, + {massAxisLambda}); + mQAHistogramRegistry->add((folderName + "/hInvMassAntiLambda").c_str(), "", + kTH1F, {massAxisAntiLambda}); + mQAHistogramRegistry->add((folderName + "/hInvMassLambdaAntiLambda").c_str(), + "", kTH2F, {massAxisLambda, massAxisAntiLambda}); + + posDaughTrack.init( + mQAHistogramRegistry, mHistogramRegistry); + negDaughTrack.init( + mQAHistogramRegistry, mHistogramRegistry); + + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaNoCuts", "No cuts", kTH1F, + {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaInvMassCut", + "Invariant mass cut", kTH1F, {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaPtMin", "Minimum Pt cut", + kTH1F, {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaPtMax", "Maximum Pt cut", + kTH1F, {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaEtaMax", "Maximum Eta cut", + kTH1F, {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaDCAV0Daugh", + "V0-daughters DCA cut", kTH1F, {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaCPA", "CPA cut", kTH1F, + {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaTranRadMin", + "Minimum transverse radius cut", kTH1F, + {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaTranRadMax", + "Maximum transverse radius cut", kTH1F, + {massAxisLambda}); + mQAHistogramRegistry->add(folderName + "QA/hInvMassLambdaDecVtxMax", + "Maximum distance on decay vertex cut", kTH1F, + {massAxisLambda}); + } + + /// check whether the most open cuts are fulfilled - most of this should have + /// already be done by the filters + nPtV0MinSel = getNSelections(femto_dream_v0_selection::kV0pTMin); + nPtV0MaxSel = getNSelections(femto_dream_v0_selection::kV0pTMax); + nEtaV0MaxSel = getNSelections(femto_dream_v0_selection::kV0etaMax); + nDCAV0DaughMax = getNSelections(femto_dream_v0_selection::kV0DCADaughMax); + nCPAV0Min = getNSelections(femto_dream_v0_selection::kV0CPAMin); + nTranRadV0Min = getNSelections(femto_dream_v0_selection::kV0TranRadMin); + nTranRadV0Max = getNSelections(femto_dream_v0_selection::kV0TranRadMax); + nDecVtxMax = getNSelections(femto_dream_v0_selection::kV0DecVtxMax); + + pTV0Min = getMinimalSelection(femto_dream_v0_selection::kV0pTMin, + femtoDreamSelection::kLowerLimit); + pTV0Max = getMinimalSelection(femto_dream_v0_selection::kV0pTMax, + femtoDreamSelection::kUpperLimit); + etaV0Max = getMinimalSelection(femto_dream_v0_selection::kV0etaMax, + femtoDreamSelection::kAbsUpperLimit); + dCAV0DaughMax = getMinimalSelection(femto_dream_v0_selection::kV0DCADaughMax, + femtoDreamSelection::kUpperLimit); + cPAV0Min = getMinimalSelection(femto_dream_v0_selection::kV0CPAMin, + femtoDreamSelection::kLowerLimit); + tranRadV0Min = getMinimalSelection(femto_dream_v0_selection::kV0TranRadMin, + femtoDreamSelection::kLowerLimit); + tranRadV0Max = getMinimalSelection(femto_dream_v0_selection::kV0TranRadMax, + femtoDreamSelection::kUpperLimit); + decVtxMax = getMinimalSelection(femto_dream_v0_selection::kV0DecVtxMax, + femtoDreamSelection::kAbsUpperLimit); +} + +template +bool FemtoDreamV0Selection::isSelectedMinimal(C const& /*col*/, V const& v0, + T const& posTrack, + T 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"; + } + // asfaf + const float pT = v0.pt(); + const float eta = v0.eta(); + 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(); + + const float invMassKaon = v0.mK0Short(); + + if (fMotherIsLambda) { /// Lambda + if ((invMassLambda < fInvMassLowLimit || invMassLambda > fInvMassUpLimit) && + (invMassAntiLambda < fInvMassLowLimit || + invMassAntiLambda > fInvMassUpLimit)) { + return false; + } + if (fRejectKaon) { + if (invMassKaon > fInvMassKaonLowLimit && + invMassKaon < fInvMassKaonUpLimit) { + return false; + } + } + } else { /// K0Short + if ((invMassKaon < fInvMassKaonLowLimit || invMassKaon > fInvMassKaonUpLimit)) { + return false; + } + if (fRejectLambda) { + if ((invMassLambda > fInvMassLowLimit && + invMassLambda < fInvMassUpLimit) || + (invMassAntiLambda > fInvMassLowLimit && + invMassAntiLambda < fInvMassUpLimit)) { + return false; + } + } + } + + if (nPtV0MinSel > 0 && pT < pTV0Min) { + return false; + } + if (nPtV0MaxSel > 0 && pT > pTV0Max) { + return false; + } + if (nEtaV0MaxSel > 0 && std::abs(eta) > etaV0Max) { + return false; + } + if (nDCAV0DaughMax > 0 && dcaDaughv0 > dCAV0DaughMax) { + return false; + } + if (nCPAV0Min > 0 && cpav0 < cPAV0Min) { + return false; + } + if (nTranRadV0Min > 0 && tranRad < tranRadV0Min) { + return false; + } + if (nTranRadV0Max > 0 && tranRad > tranRadV0Max) { + return false; + } + for (size_t i = 0; i < decVtx.size(); i++) { + if (nDecVtxMax > 0 && decVtx.at(i) > decVtxMax) { + return false; + } + } + if (!posDaughTrack.isSelectedMinimal(posTrack)) { + return false; + } + if (!negDaughTrack.isSelectedMinimal(negTrack)) { + return false; + } + + // check that track combinations for V0 or antiV0 would be fulfilling PID + int nSigmaPIDMax = posDaughTrack.getSigmaPIDMax(); + if (fMotherIsLambda) { /// Lambda + // 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; + } + } else { /// K0SHort + auto nSigmaPiNeg = negTrack.tpcNSigmaPi(); + auto nSigmaPiPos = posTrack.tpcNSigmaPi(); + if (!(std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && + std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax)) { + return false; + } + } + + return true; +} + +template +void FemtoDreamV0Selection::fillLambdaQA(C const& /*col*/, V const& v0, + T const& posTrack, T 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 float pT = v0.pt(); + const float eta = v0.eta(); + 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 invMassKaon = v0.mK0Short(); + + float fillMass = 0.; + if (fMotherIsLambda) { + fillMass = v0.mLambda(); + } else { + fillMass = v0.mK0Short(); + } + + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaNoCuts"), fillMass); + + if (fMotherIsLambda) { /// Lambda + if (invMassLambda > fInvMassLowLimit && invMassLambda < fInvMassUpLimit) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaInvMassCut"), + v0.mLambda()); + } + } else { /// K0Short + if (invMassKaon > fInvMassKaonLowLimit && invMassKaon < fInvMassKaonUpLimit) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaInvMassCut"), + v0.mK0Short()); + } + } + + if (pT > pTV0Min) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaPtMin"), + fillMass); + } + if (pT < pTV0Max) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaPtMax"), + fillMass); + } + if (std::abs(eta) < etaV0Max) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaEtaMax"), + fillMass); + } + if (dcaDaughv0 < dCAV0DaughMax) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaDCAV0Daugh"), + fillMass); + } + if (cpav0 > cPAV0Min) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaCPA"), fillMass); + } + if (tranRad > tranRadV0Min) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaTranRadMin"), + fillMass); + } + if (tranRad < tranRadV0Max) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaTranRadMax"), + fillMass); + } + bool write = true; + for (size_t i = 0; i < decVtx.size(); i++) { + write = write && (decVtx.at(i) < decVtxMax); + } + if (write) { + mQAHistogramRegistry->fill(HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + HIST("QA/hInvMassLambdaDecVtxMax"), + fillMass); + } +} + +/// the CosPA of V0 needs as argument the posXYZ of collisions vertex so we need +/// to pass the collsion as well +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()); + cutContainerType output = 0; + size_t counter = 0; + + float sign = 0.; + /// Lambda + if (fMotherIsLambda) { + auto lambdaMassNominal = o2::constants::physics::MassLambda; + auto lambdaMassHypothesis = v0.mLambda(); + auto antiLambdaMassHypothesis = v0.mAntiLambda(); + auto diffLambda = std::abs(lambdaMassNominal - lambdaMassHypothesis); + auto diffAntiLambda = std::abs(antiLambdaMassHypothesis - lambdaMassHypothesis); + + 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 (std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && diffAntiLambda > diffLambda) { + sign = -1.; + } 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 (std::abs(nSigmaPrNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + sign = -1.; + } else if (std::abs(nSigmaPrPos - nSigmaPIDOffsetTPC) < nSigmaPIDMax && std::abs(nSigmaPiNeg - nSigmaPIDOffsetTPC) < nSigmaPIDMax) { + sign = 1.; + } + } + } else { + sign = 1.; // for the K0Short arbitrarily set the sign to 1 + } + + const auto pT = v0.pt(); + const auto eta = v0.eta(); + const auto tranRad = v0.v0radius(); + const auto dcaDaughv0 = v0.dcaV0daughters(); + const auto cpav0 = v0.v0cosPA(); + const std::vector decVtx = {v0.x(), v0.y(), v0.z()}; + + float observable = 0.; + for (auto& sel : mSelections) { // o2-linter: disable=const-ref-in-for-loop (femtoDreamObjectSelection has no const getter) + const auto selVariable = sel.getSelectionVariable(); + if (selVariable == femto_dream_v0_selection::kV0DecVtxMax) { + for (size_t i = 0; i < decVtx.size(); ++i) { + auto decVtxValue = decVtx.at(i); + sel.checkSelectionSetBit(decVtxValue, output, counter, nullptr); + } + } else { + switch (selVariable) { + case (femto_dream_v0_selection::kV0Sign): + observable = sign; + break; + case (femto_dream_v0_selection::kV0pTMin): + observable = pT; + break; + case (femto_dream_v0_selection::kV0pTMax): + observable = pT; + break; + case (femto_dream_v0_selection::kV0etaMax): + observable = eta; + break; + case (femto_dream_v0_selection::kV0DCADaughMax): + observable = dcaDaughv0; + break; + case (femto_dream_v0_selection::kV0CPAMin): + observable = cpav0; + break; + case (femto_dream_v0_selection::kV0TranRadMin): + observable = tranRad; + break; + case (femto_dream_v0_selection::kV0TranRadMax): + observable = tranRad; + break; + case (femto_dream_v0_selection::kV0DecVtxMax): + break; + } + sel.checkSelectionSetBit(observable, output, counter, nullptr); + } + } + return { + output, + outputPosTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + outputPosTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID), + outputNegTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kCuts), + outputNegTrack.at(femtoDreamTrackSelection::TrackContainerPosition::kPID)}; +} + +template +void FemtoDreamV0Selection::fillQA(C const& /*col*/, V const& v0, T const& posTrack, + T const& negTrack) +{ + if (mQAHistogramRegistry) { + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hPt"), + v0.pt()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hEta"), + v0.eta()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hPhi"), + v0.phi()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hDaughDCA"), + v0.dcaV0daughters()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hTransRadius"), + v0.v0radius()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hDecayVtxX"), + v0.x()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hDecayVtxY"), + v0.y()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hDecayVtxZ"), + v0.z()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hCPA"), + v0.v0cosPA()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hCPAvsPt"), + v0.pt(), v0.v0cosPA()); + + if (fMotherIsLambda) { /// Lambda + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hInvMassLambda"), + v0.mLambda()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hInvMassAntiLambda"), + v0.mAntiLambda()); + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hInvMassLambdaAntiLambda"), + v0.mLambda(), v0.mAntiLambda()); + } else { /// K0Short + mQAHistogramRegistry->fill( + HIST(o2::aod::femtodreamparticle::ParticleTypeName[part]) + + HIST("/hInvMassLambda"), + v0.mK0Short()); + } + } + + posDaughTrack.fillQA(posTrack); + negDaughTrack.fillQA(negTrack); +} + +} // namespace o2::analysis::femtoDream + +#endif // PWGCF_FEMTODREAM_CORE_FEMTODREAMV0SELECTIONK0SHORT_H_ diff --git a/PWGCF/FemtoDream/DataModel/CMakeLists.txt b/PWGCF/FemtoDream/DataModel/CMakeLists.txt index 4c182222bf2..da01f4ab983 100644 --- a/PWGCF/FemtoDream/DataModel/CMakeLists.txt +++ b/PWGCF/FemtoDream/DataModel/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. # diff --git a/PWGCF/FemtoDream/TableProducer/CMakeLists.txt b/PWGCF/FemtoDream/TableProducer/CMakeLists.txt index 0f8d87d9570..7984fd632b7 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(femto-dream-producer-task-reso + SOURCES femtoDreamProducerTaskReso.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..dc5fcc8a862 100644 --- a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerReducedTask.cxx +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerReducedTask.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -15,27 +15,34 @@ /// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de /// \author Anton Riedel, TU München, anton.riedel@tum.de -#include "TMath.h" -#include +#include "PWGCF/DataModel/FemtoDerived.h" #include "PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" -#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" + #include "Math/Vector4D.h" +#include "TMath.h" + +#include using namespace o2; using namespace o2::analysis::femtoDream; @@ -50,10 +57,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 { @@ -77,6 +84,8 @@ struct femtoDreamProducerReducedTask { 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 ConfEvtMinSphericity{"ConfEvtMinSphericity", 0.0f, "Evt sel: Min. sphericity of event"}; + Configurable ConfEvtSphericityPtmin{"ConfEvtSphericityPtmin", 0.0f, "Evt sel: Min. Pt for sphericity calculation"}; Configurable ConfTrkRejectNotPropagated{"ConfTrkRejectNotPropagated", false, "True: reject not propagated tracks"}; @@ -114,7 +123,7 @@ struct femtoDreamProducerReducedTask { int CutBits = 8 * sizeof(o2::aod::femtodreamparticle::cutContainerType); Registry.add("AnalysisQA/CutCounter", "; Bit; Counter", kTH1F, {{CutBits + 1, -0.5, CutBits + 0.5}}); - colCuts.setCuts(ConfEvtZvtx.value, ConfEvtTriggerCheck.value, ConfEvtTriggerSel.value, ConfEvtOfflineCheck.value, ConfEvtAddOfflineCheck.value, ConfIsRun3.value); + colCuts.setCuts(ConfEvtZvtx.value, ConfEvtTriggerCheck.value, ConfEvtTriggerSel.value, ConfEvtOfflineCheck.value, ConfEvtAddOfflineCheck.value, ConfIsRun3.value, ConfEvtMinSphericity.value, ConfEvtSphericityPtmin.value); colCuts.init(&qaRegistry); trackCuts.setSelection(ConfTrkCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); @@ -266,7 +275,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 +307,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 +335,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 +350,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 +364,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 43edde0e6ca..d200d2caeee 100644 --- a/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTask.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -13,34 +13,46 @@ /// \brief Tasks that produces the track tables used for the pairing /// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de -#include -#include +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" +#include "PWGCF/FemtoDream/Core/femtoDreamV0Selection.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/Zorro.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.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/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 "PWGCF/DataModel/FemtoDerived.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" +#include + +#include "Math/Vector4D.h" #include "TMath.h" +#include + +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; using namespace o2::analysis::femtoDream; namespace o2::aod @@ -48,15 +60,20 @@ namespace o2::aod using FemtoFullCollision = soa::Join::iterator; using FemtoFullCollision_noCent = soa::Join::iterator; +using FemtoFullCollision_CentPbPb = soa::Join::iterator; +using FemtoFullCollision_CentPbPb_qvec = 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 template @@ -74,7 +91,11 @@ int getRowDaughters(int daughID, T const& vecID) struct femtoDreamProducerTask { + Zorro zorro; + Produces outputCollision; + Produces outputExtQnCollision; + Produces outputExtEPCollision; Produces outputMCCollision; Produces outputCollsMCLabels; Produces outputParts; @@ -85,11 +106,17 @@ 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 ConfSoftwareTriggerNames{"ConfSoftwareTriggerNames", "fPPL", "Names of the software triggers, use comma and no space"}; + 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"}; @@ -97,6 +124,9 @@ struct femtoDreamProducerTask { 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 ConfEvtMinSphericity{"ConfEvtMinSphericity", 0.0f, "Evt sel: Min. sphericity of event"}; + Configurable ConfEvtSphericityPtmin{"ConfEvtSphericityPtmin", 0.0f, "Evt sel: Min. Pt for sphericity calculation"}; Configurable ConfTrkRejectNotPropagated{"ConfTrkRejectNotPropagated", false, "True: reject not propagated tracks"}; // Configurable ConfRejectITSHitandTOFMissing{ "ConfRejectITSHitandTOFMissing", false, "True: reject if neither ITS hit nor TOF timing satisfied"}; @@ -143,21 +173,72 @@ 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"}; - 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"}; + 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 + struct : o2::framework::ConfigurableGroup { + 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"}; + } ConfResoSel; /// \todo should we add filter on min value pT/eta of V0 and daughters? /*Filter v0Filter = (nabs(aod::v0data::x) < V0DecVtxMax.value) && @@ -166,21 +247,63 @@ 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"}; + Configurable ConfCutTPCFracSharedCls{"ConfCutTPCFracSharedCls", false, "Cut fraction of shared TPC clusters"}; + Configurable ConfTPCFracSharedClsMax{"ConfTPCFracSharedClsMax", 1000.f, "Maximum value for fraction of shared TPC clusters"}; + } OptionTrackSpecialSelections; + + struct : o2::framework::ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", false, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + + struct : o2::framework::ConfigurableGroup { + std::string prefix = std::string("epCal"); + Configurable ConfFillFlowQA{"ConfFillFlowQA", false, "Evt sel: fill flow/event-plane related observables"}; + Configurable ConfQnSeparation{"ConfQnSeparation", false, "Evt sel: do qn separation of events"}; + Configurable ConfHarmonicOrder{"ConfHarmonicOrder", 2, "harmonic order for event plane calculation"}; + Configurable> ConfQnBinSeparator{"ConfQnBinSeparator", std::vector{-999.f, -999.f, -999.f}, "qn bin separator"}; + Configurable ConfDoCumlant{"ConfDoCumlant", false, "do cumulant for flow calculation"}; + Configurable ConfCentralityMax{"ConfCentralityMax", 100.f, "Evt sel: Maximum Centrality cut"}; + Configurable ConfCentBinWidth{"ConfCentBinWidth", 1.f, "Centrality bin length for qn separator"}; + Configurable ConfNumQnBins{"ConfNumQnBins", 10, "Number of qn bins"}; + } epCal; + + struct : o2::framework::ConfigurableGroup { + std::string prefix = std::string("OptionEvtSpecialSelections"); + Configurable ConfIsUsePileUpPbPb{"ConfIsUsePileUpPbPb", false, "Required for choosing whether to run the pile-up cuts"}; + Configurable ConfEvNoSameBunchPileup{"ConfEvNoSameBunchPileup", false, "Require kNoSameBunchPileup selection on Events."}; + Configurable ConfEvIsGoodITSLayersAll{"ConfEvIsGoodITSLayersAll", false, "Require kIsGoodITSLayersAll selection on Events."}; + Configurable ConfIsUseOccupancy{"ConfIsUseOccupancy", false, "Required for choosing whether to run the pile-up cuts"}; + Configurable ConfTPCOccupancyMin{"ConfTPCOccupancyMin", 0, "Minimum value for TPC Occupancy selection"}; + Configurable ConfTPCOccupancyMax{"ConfTPCOccupancyMax", 5000, "Maximum value for TPC Occupancy selection"}; + } OptionEvtSpecialSelections; + 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}; + HistogramRegistry FlowRegistry{"Flow", {}, OutputObjHandlingPolicy::AnalysisObject}; int mRunNumber; float mMagField; Service ccdb; /// Accessing the CCDB + RCTFlagsChecker rctChecker; void init(InitContext&) { - if (doprocessData == false && doprocessData_noCentrality == false && doprocessMC == false && doprocessMC_noCentrality == false) { + if (doprocessData == false && doprocessData_noCentrality == false && doprocessData_CentPbPb == false && doprocessData_CentPbPb_EP == 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)) { + 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) || (doprocessData_CentPbPb_EP == true && doprocessData == true) || (doprocessData_CentPbPb_EP == true && doprocessData_noCentrality == true) || (doprocessData_CentPbPb_EP == true && doprocessMC == true) || (doprocessData_CentPbPb_EP == true && doprocessMC_noCentrality == true) || (doprocessData_CentPbPb_EP == true && doprocessMC_CentPbPb == true) || (doprocessData_CentPbPb_EP == true && doprocessData_CentPbPb == true)) { LOGF(fatal, "Cannot enable more than one process switch at the same time. " "Please choose one."); @@ -188,7 +311,14 @@ 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}}); + 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}}); @@ -200,7 +330,9 @@ struct femtoDreamProducerTask { 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}}); - colCuts.setCuts(ConfEvtZvtx.value, ConfEvtTriggerCheck.value, ConfEvtTriggerSel.value, ConfEvtOfflineCheck.value, ConfEvtAddOfflineCheck.value, ConfIsRun3.value); + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, false, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + colCuts.setCuts(ConfEvtZvtx.value, ConfEvtTriggerCheck.value, ConfEvtTriggerSel.value, ConfEvtOfflineCheck.value, ConfEvtAddOfflineCheck.value, ConfIsRun3.value, ConfEvtMinSphericity.value, ConfEvtSphericityPtmin.value); colCuts.init(&qaRegistry); trackCuts.setSelection(ConfTrkCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); @@ -239,6 +371,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); @@ -260,6 +393,63 @@ struct femtoDreamProducerTask { 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); + } + } + + if (epCal.ConfFillFlowQA) { + colCuts.initFlow(&FlowRegistry, epCal.ConfQnSeparation); + colCuts.initEPQA(&FlowRegistry); + } mRunNumber = 0; mMagField = 0.0; @@ -273,7 +463,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 @@ -307,47 +497,123 @@ 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, ConfSoftwareTriggerNames.value); + } } - 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 } } + 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) { @@ -355,11 +621,14 @@ 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; 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 @@ -377,6 +646,7 @@ struct femtoDreamProducerTask { // 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 @@ -417,16 +687,28 @@ struct femtoDreamProducerTask { outputCollsMCLabels(-1); } } - template - void fillCollisionsAndTracksAndV0(CollisionType const& col, TrackType const& tracks, V0Type const& fullV0s) + 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) { - mult = col.centFT0M(); + if constexpr (analysePbPb) { + mult = col.centFT0C(); + } else { + mult = col.centFT0M(); + } } else { mult = 0; } @@ -443,6 +725,12 @@ struct femtoDreamProducerTask { if (!colCuts.isSelectedCollision(col)) { return; } + // bool emptyCollision = false; + if (ConfIsActivateCascade.value) { + if (colCuts.isEmptyCollision(col, tracks, trackCuts) && colCuts.isCollisionWithoutTrkCasc(col, fullCascades, cascadeCuts, tracks)) { + return; + } + } if (ConfIsActivateV0.value) { if (colCuts.isEmptyCollision(col, tracks, trackCuts) && colCuts.isEmptyCollision(col, fullV0s, v0Cuts, tracks)) { return; @@ -453,24 +741,68 @@ struct femtoDreamProducerTask { } } + if (rctCut.requireRCTFlagChecker && !rctChecker(col)) { + return; + } + + // Pileup rejection in PbPb data + if constexpr (analysePbPb) { + if (OptionEvtSpecialSelections.ConfIsUsePileUpPbPb && + !colCuts.isPileUpCollisionPbPb(col, OptionEvtSpecialSelections.ConfEvNoSameBunchPileup, OptionEvtSpecialSelections.ConfEvIsGoodITSLayersAll)) { + return; + } + if (OptionEvtSpecialSelections.ConfIsUseOccupancy && + !colCuts.occupancySelection(col, OptionEvtSpecialSelections.ConfTPCOccupancyMin, OptionEvtSpecialSelections.ConfTPCOccupancyMax)) { + 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 tmpIDtrack; // this vector keeps track of the matching of the primary track table row <-> aod::track table global index - std::vector Daughter1, Daughter2; + if constexpr (doFlow) { + fillCollisionsFlow(col, tracks, mult, spher, epCal.ConfHarmonicOrder); + } + + 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 : 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); + + if constexpr (analysePbPb) { + if (OptionTrackSpecialSelections.ConfCutTPCFracSharedCls && track.tpcFractionSharedCls() > OptionTrackSpecialSelections.ConfTPCFracSharedClsMax) { + 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 - 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(), @@ -483,7 +815,7 @@ struct femtoDreamProducerTask { track.dcaXY(), childIDs, 0, 0); tmpIDtrack.push_back(track.globalIndex()); if (ConfIsDebug.value) { - fillDebugParticle(track); + fillDebugParticle(track); } if constexpr (isMC) { @@ -495,9 +827,9 @@ struct femtoDreamProducerTask { // 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])) { + if (track.sign() == ConfResoSel.ConfDaughterCharge.value[0] && track.pt() <= ConfResoSel.ConfDaughterPtUp.value[0] && track.pt() >= ConfResoSel.ConfDaughterPtLow.value[0] && std::abs(track.eta()) <= ConfResoSel.ConfDaughterEta.value[0] && std::abs(track.dcaXY()) <= ConfResoSel.ConfDaughterDCAxy.value[0] && std::abs(track.dcaZ()) <= ConfResoSel.ConfDaughterDCAz.value[0] && track.tpcNClsCrossedRows() >= ConfResoSel.ConfDaughterNCrossed.value[0] && track.tpcNClsFound() >= ConfResoSel.ConfDaughterNClus.value[0] && track.tpcCrossedRowsOverFindableCls() >= ConfResoSel.ConfDaughterTPCfCls.value[0]) { + if ((track.tpcInnerParam() < ConfResoSel.ConfDaughterPTPCThr.value[0] && std::abs(o2::aod::pidutils::tpcNSigma(ConfResoSel.ConfDaughterPIDspecies.value[0], track)) <= ConfResoSel.ConfDaughterPIDnSigmaMax.value[0]) || + (track.tpcInnerParam() >= ConfResoSel.ConfDaughterPTPCThr.value[0] && std::abs(std::sqrt(o2::aod::pidutils::tpcNSigma(ConfResoSel.ConfDaughterPIDspecies.value[0], track) * o2::aod::pidutils::tpcNSigma(ConfResoSel.ConfDaughterPIDspecies.value[0], track) + o2::aod::pidutils::tofNSigma(ConfResoSel.ConfDaughterPIDspecies.value[0], track) * o2::aod::pidutils::tofNSigma(ConfResoSel.ConfDaughterPIDspecies.value[0], track))) <= ConfResoSel.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()); @@ -505,9 +837,9 @@ struct femtoDreamProducerTask { } } // 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])) { + if (track.sign() == ConfResoSel.ConfDaughterCharge.value[1] && track.pt() <= ConfResoSel.ConfDaughterPtUp.value[1] && track.pt() >= ConfResoSel.ConfDaughterPtLow.value[1] && std::abs(track.eta()) <= ConfResoSel.ConfDaughterEta.value[1] && std::abs(track.dcaXY()) <= ConfResoSel.ConfDaughterDCAxy.value[1] && std::abs(track.dcaZ()) <= ConfResoSel.ConfDaughterDCAz.value[1] && track.tpcNClsCrossedRows() >= ConfResoSel.ConfDaughterNCrossed.value[1] && track.tpcNClsFound() >= ConfResoSel.ConfDaughterNClus.value[1] && track.tpcCrossedRowsOverFindableCls() >= ConfResoSel.ConfDaughterTPCfCls.value[1]) { + if ((track.tpcInnerParam() < ConfResoSel.ConfDaughterPTPCThr.value[1] && std::abs(o2::aod::pidutils::tpcNSigma(ConfResoSel.ConfDaughterPIDspecies.value[1], track)) <= ConfResoSel.ConfDaughterPIDnSigmaMax.value[1]) || + (track.tpcInnerParam() >= ConfResoSel.ConfDaughterPTPCThr.value[1] && std::abs(std::sqrt(o2::aod::pidutils::tpcNSigma(ConfResoSel.ConfDaughterPIDspecies.value[1], track) * o2::aod::pidutils::tpcNSigma(ConfResoSel.ConfDaughterPIDspecies.value[1], track) + o2::aod::pidutils::tofNSigma(ConfResoSel.ConfDaughterPIDspecies.value[1], track) * o2::aod::pidutils::tofNSigma(ConfResoSel.ConfDaughterPIDspecies.value[1], track))) <= ConfResoSel.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()); @@ -519,6 +851,7 @@ struct femtoDreamProducerTask { 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 @@ -526,6 +859,8 @@ struct femtoDreamProducerTask { // const auto dcaXYpos = postrack.dcaXY(); // const auto dcaZpos = postrack.dcaZ(); // const auto dcapos = std::sqrt(pow(dcaXYpos, 2.) + pow(dcaZpos, 2.)); + + v0Cuts.fillQA<0, aod::femtodreamparticle::ParticleType::kV0, aod::femtodreamparticle::ParticleType::kV0Child>(col, v0, postrack, negtrack); v0Cuts.fillLambdaQA(col, v0, postrack, negtrack); if (!v0Cuts.isSelectedMinimal(col, v0, postrack, negtrack)) { @@ -540,7 +875,7 @@ struct femtoDreamProducerTask { // TrackSelection::TrackCuts::kITSHits); // } - v0Cuts.fillQA(col, v0, postrack, negtrack); ///\todo fill QA also for daughters + v0Cuts.fillQA<1, aod::femtodreamparticle::ParticleType::kV0, aod::femtodreamparticle::ParticleType::kV0Child>(col, v0, postrack, negtrack); ///\todo fill QA also for daughters auto cutContainerV0 = v0Cuts.getCutContainer(col, v0, postrack, negtrack); int postrackID = v0.posTrackId(); @@ -594,30 +929,137 @@ struct femtoDreamProducerTask { v0.mLambda(), v0.mAntiLambda()); if (ConfIsDebug.value) { - fillDebugParticle(postrack); // QA for positive daughter - fillDebugParticle(negtrack); // QA for negative daughter - fillDebugParticle(v0); // QA for v0 + 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, aod::femtodreamparticle::ParticleType::kCascadeV0Child, aod::femtodreamparticle::ParticleType::kCascadeBachelor>(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); + if (!cascadeCuts.isSelectedMinimal(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc)) { + continue; + } + cascadeCuts.fillQA<1, aod::femtodreamparticle::ParticleType::kCascade, aod::femtodreamparticle::ParticleType::kCascadeV0Child, aod::femtodreamparticle::ParticleType::kCascadeBachelor>(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 + float invMassCasc = ConfCascSel.ConfCascIsSelectedOmega ? casc.mOmega() : casc.mXi(); + 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, + invMassCasc, + 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 (auto iDaug1 = 0; iDaug1 < Daughter1.size(); ++iDaug1) { - for (auto iDaug2 = 0; iDaug2 < Daughter2.size(); ++iDaug2) { + 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 tempD1(Daughter1.at(iDaug1).pt(), Daughter1.at(iDaug1).eta(), Daughter1.at(iDaug1).phi(), ConfResoSel.ConfDaug1Daugh2ResoMass.value[0]); + ROOT::Math::PtEtaPhiMVector tempD2(Daughter2.at(iDaug2).pt(), Daughter2.at(iDaug2).eta(), Daughter2.at(iDaug2).phi(), ConfResoSel.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)) { + if ((tempPhi.M() >= ConfResoSel.ConfResoInvMassLowLimit.value) && (tempPhi.M() <= ConfResoSel.ConfResoInvMassUpLimit.value)) { ResoRegistry.fill(HIST("AnalysisQA/Reso/InvMass_selected"), tempPhi.M()); ResoRegistry.fill(HIST("AnalysisQA/Reso/PtD1_selected"), Daughter1.at(iDaug1).pt()); @@ -656,12 +1098,15 @@ struct femtoDreamProducerTask { 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., -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 Reso + 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 } } } @@ -669,16 +1114,48 @@ struct femtoDreamProducerTask { } } + template + void fillCollisionsFlow(CollisionType const& col, TrackType const& tracks, float mult, float spher, int EPHarmonic) + { + float myqn = colCuts.computeqnVec(col); + float myEP = TMath::RadToDeg() * colCuts.computeEP(col, EPHarmonic); + // psi from rad(0-pi) to deg, in table psi would be in deg,from 0-180 + + if ((myqn >= 0 && myqn < 1e6) || (myEP >= 0 && myEP < 180)) { + outputExtQnCollision(myqn, col.trackOccupancyInTimeRange()); + outputExtEPCollision(myEP); + } + + // Calculate flow via cumulant + + if (epCal.ConfQnSeparation) { + colCuts.myqnBin(mult, epCal.ConfCentralityMax, epCal.ConfFillFlowQA, epCal.ConfQnBinSeparator, myqn, epCal.ConfNumQnBins, epCal.ConfCentBinWidth); + } + if (epCal.ConfFillFlowQA) { + colCuts.fillEPQA(mult, spher, myqn, myEP); + if (epCal.ConfDoCumlant) { + colCuts.doCumulants(col, tracks, mult, epCal.ConfQnSeparation); + } + } + } + void processData(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, aod::FemtoFullTracks const& tracks, - o2::aod::V0Datas const& fullV0s) + o2::aod::V0Datas const& fullV0s, + o2::aod::CascDatas const& fullCascades) { // 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) { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracksWithItsPid, fullV0s, fullCascades); + } else { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } } PROCESS_SWITCH(femtoDreamProducerTask, processData, "Provide experimental data", true); @@ -687,27 +1164,75 @@ struct femtoDreamProducerTask { processData_noCentrality(aod::FemtoFullCollision_noCent const& col, aod::BCsWithTimestamps const&, aod::FemtoFullTracks const& tracks, - o2::aod::V0Datas const& fullV0s) + o2::aod::V0Datas const& fullV0s, + o2::aod::CascDatas const& fullCascades) { // 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) { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracksWithItsPid, fullV0s, fullCascades); + } else { + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } } 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, + 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(femtoDreamProducerTask, processData_CentPbPb, + "Provide experimental data with centrality information for PbPb collisions", false); + + void processData_CentPbPb_EP(aod::FemtoFullCollision_CentPbPb_qvec 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(femtoDreamProducerTask, processData_CentPbPb_EP, + "Provide experimental data with centrality and q-vector table 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& fullV0s, /// \todo with FilteredFullV0s + soa::Join const& fullCascades) { // get magnetic field for run - getMagneticFieldTesla(col.bc_as()); + initCCDB_Mag_Trig(col.bc_as()); // fill the tables - fillCollisionsAndTracksAndV0(col, tracks, fullV0s); + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); } PROCESS_SWITCH(femtoDreamProducerTask, processMC, "Provide MC data", false); @@ -716,16 +1241,31 @@ struct femtoDreamProducerTask { soa::Join const& tracks, aod::FemtoFullMCgenCollisions const&, aod::McParticles const&, - soa::Join const& fullV0s) /// \todo with FilteredFullV0s + soa::Join const& fullV0s, /// \todo with FilteredFullV0s + soa::Join const& fullCascades) { // get magnetic field for run - getMagneticFieldTesla(col.bc_as()); + initCCDB_Mag_Trig(col.bc_as()); // fill the tables - fillCollisionsAndTracksAndV0(col, tracks, fullV0s); + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); } 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 + 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(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..33f07d2772e --- /dev/null +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskForSpecificAnalysis.cxx @@ -0,0 +1,397 @@ +// 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 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 "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +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; + + // Require bitmask selection for candidates + Configurable confRequireBitmask{"confRequireBitmask", false, "Require bitmask selection for candidates"}; + + // Number of candidates required + 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"}; + Configurable confCutPart{"confCutPart", 0, "Track - Selection bit from cutCulator for part"}; + Configurable confCutPartAntiPart{"confCutPartAntiPart", 0, "Track - Selection bit from cutCulator for antipart"}; + + /// 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 confMinInvMassV0{"confMinInvMassV0", 1.08, "Minimum invariant mass of V0 (particle)"}; + Configurable confMaxInvMassV0{"confMaxInvMassV0", 1.15, "Maximum invariant mass of V0 (particle)"}; + Configurable confMinInvMassAntiV0{"confMinInvMassAntiV0", 1.08, "Minimum invariant mass of V0 (antiparticle)"}; + Configurable confMaxInvMassAntiV0{"confMaxInvMassAntiV0", 1.15, "Maximum invariant mass of V0 (antiparticle)"}; + Configurable confCutV0SameForAntipart{"confCutV0SameForAntipart", 0, "V0 - Selection bit from cutCulator for part/antipart"}; + Configurable confChildPosCutV0{"confChildPosCutV0", 149, "Selection bit for positive child of V0"}; + Configurable confChildPosTPCBitV0{"confChildPosTPCBitV0", 2, "PID TPC bit for positive child of V0"}; + Configurable confChildNegCutV0{"confChildNegCutV0", 149, "Selection bit for negative child of V0"}; + Configurable confChildNegTPCBitV0{"confChildNegTPCBitV0", 2, "PID TPC bit for negative child of V0"}; + + /// Cascade selection + Configurable confMinInvMassCascade{"confMinInvMassCascade", 1.2, "Minimum invariant mass of Cascade (particle)"}; + Configurable confMaxInvMassCascade{"confMaxInvMassCascade", 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}}); + // Never run V0s and Cascades together as this will DOUBLE the track number and induce self correlations + if ((doprocessCollisionsWithNTracksAndNCascades && doprocessCollisionsWithNTracksAndNV0)) { + LOG(fatal) << "Never run V0s and Cascades together as this will DOUBLE the track number and induce self correlations!"; + } + } + + /// 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(const o2::aod::FDCollision& col, PartitionType groupSelectedTracks, PartitionType groupSelectedV0s, PartType parts) + { + /// check tracks + int tracksCount = 0; + int antitracksCount = 0; + for (const auto& part : groupSelectedTracks) { + if (part.cut() & 1) { + if (!confRequireBitmask || ncheckbit(part.cut(), confCutPartAntiPart)) { + antitracksCount++; + } + } else { + if (!confRequireBitmask || ncheckbit(part.cut(), confCutPart)) { + tracksCount++; + } + } + } + + /// check V0s + int v0Count = 0; + int antiV0Count = 0; + for (const auto& V0 : groupSelectedV0s) { + if ((V0.mLambda() > confMinInvMassV0) && (V0.mLambda() < confMaxInvMassV0)) { + if (confRequireBitmask) { + if (ncheckbit(V0.cut(), confCutV0SameForAntipart)) { + const auto& posChild = parts.iteratorAt(V0.index() - 2); + const auto& negChild = parts.iteratorAt(V0.index() - 1); + if (((posChild.cut() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0 && + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0)) { + v0Count++; + } + } + } else { + v0Count++; + } + } else if ((V0.mAntiLambda() > confMinInvMassAntiV0) && (V0.mAntiLambda() < confMaxInvMassAntiV0)) { + if (confRequireBitmask) { + if (ncheckbit(V0.cut(), confCutV0SameForAntipart)) { + const auto& posChild = parts.iteratorAt(V0.index() - 2); + const auto& negChild = parts.iteratorAt(V0.index() - 1); + if (((posChild.cut() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0 && // exchanged values because checking antiparticle daughters and pid of particles exchange + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0)) { // exchanged values because checking antiparticle daughters and pid of particles exchange + antiV0Count++; + } + } + } else { + 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 (const 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(const o2::aod::FDCollision& col, + const 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 createSpecifiedDerivedDataTrkCascade(const o2::aod::FDCollision& col, PartitionType groupSelectedTracks, PartitionType groupSelectedCascades, PartType parts) + { + + /// check tracks + int tracksCount = 0; + int antitracksCount = 0; + for (const auto& part : groupSelectedTracks) { + if (part.cut() & 1) { + antitracksCount++; + } else { + tracksCount++; + } + } + + /// check Cascades + int ascadeCount = 0; + int antiCascadeCount = 0; + for (const auto& casc : groupSelectedCascades) { + if ((casc.cut() & kSignPlusMask) == kSignPlusMask) { + ascadeCount++; + } else { + antiCascadeCount++; + } + } + + std::vector tmpIDtrack; + + if ((ascadeCount >= confNumberOfCascades && tracksCount >= confNumberOfTracks) || (antiCascadeCount >= confNumberOfCascades && antitracksCount >= confNumberOfTracks)) { + eventRegistry.fill(HIST("hStatistiscs"), 1); + outputCollision(col.posZ(), col.multV0M(), col.multNtr(), col.sphericity(), col.magField()); + + for (const 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(const o2::aod::FDCollision& col, + const 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); + + createSpecifiedDerivedDataTrkCascade(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/femtoDreamProducerTaskReso.cxx b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskReso.cxx new file mode 100644 index 00000000000..ecb1d3b4eac --- /dev/null +++ b/PWGCF/FemtoDream/TableProducer/femtoDreamProducerTaskReso.cxx @@ -0,0 +1,1912 @@ +// 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 femtoDreamProducerTaskReso.cxx +/// \brief Tasks that produces the track tables used for the pairing +/// \author Laura Serksnyte, TU München, laura.serksnyte@tum.de + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCascadeSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamResoSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" +#include "PWGCF/FemtoDream/Core/femtoDreamV0SelectionK0Short.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/Zorro.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include "Math/Vector4D.h" +#include "TMath.h" + +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; +using namespace o2::analysis::femtoDream; + +namespace o2::aod +{ +using FemtoFullCollision = soa::Join::iterator; +using FemtoFullCollisionNoCent = soa::Join::iterator; +using FemtoFullCollisionCentPbPb = soa::Join::iterator; +using FemtoFullCollisionMC = soa::Join::iterator; +using FemtoFullCollisionNoCentMC = soa::Join::iterator; +using FemtoFullCollisionMCCentPbPb = soa::Join::iterator; +using FemtoFullMCgenCollisions = soa::Join; +using FemtoFullMCgenCollision = FemtoFullMCgenCollisions::iterator; + +using FemtoFullTracks = + soa::Join; + +} // namespace o2::aod + +namespace software_triggers +{ +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 software_triggers + +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 FemtoDreamProducerTaskReso { + + SliceCache cache; // o2::framework, included in ASoAHelpers.h + Preslice perCol = aod::track::collisionId; // o2::framework included in ASoAHelpers.h + Partition daughter1 = aod::track::signed1Pt > 0.f; // o2::framework included in AnalysisHelper.h + Partition daughter2 = aod::track::signed1Pt < 0.f; // o2::framework included in AnalysisHelper.h + + 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"}; // true? + 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", {software_triggers::triggerSwitches[0], 1, software_triggers::nTriggers, std::vector{"Switch"}, software_triggers::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 (Lambdas) into femtodream tables"}; + Configurable confIsActivateV0K0S{"confIsActivateV0K0S", true, "Activate filling of V0 into femtodream tables"}; + Configurable confIsActivateKStar{"confIsActivateKStar", true, "Activate filling of KStars into femtodream tables"}; + Configurable confIsActivatePhi{"confIsActivatePhi", true, "Activates cuts on Phi's and fills tables"}; + Configurable confIsActivateXi{"confIsActivateXi", false, "Activate filling of Xis into femtodream tables"}; + Configurable confIsActivateOmega{"confIsActivateOmega", false, "Activate filling of Omegas into femtodream tables"}; + Configurable confEvtMinSphericity{"confEvtMinSphericity", 0.0f, "Evt sel: Min. sphericity of event"}; + Configurable confEvtSphericityPtmin{"confEvtSphericityPtmin", 0.0f, "Evt sel: Min. Pt for sphericity calculation"}; + + 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; + struct : ConfigurableGroup { + std::string prefix = std::string("Track"); + 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.1f, 0.15f, 0.2f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMin, "Track selection: ")}; + Configurable> confTrkPtmax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMax, "confTrk"), std::vector{4.4f, 4.6f, 4.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMax, "Track selection: ")}; + Configurable> confTrkEta{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kEtaMax, "confTrk"), std::vector{0.8f, 0.85f, 0.9f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kEtaMax, "Track selection: ")}; + Configurable> confTrkTPCnclsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCnClsMin, "confTrk"), std::vector{80.f, 90.f, 100.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.2f, 0.5f}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAxyMax, "Track selection: ")}; + Configurable> confTrkDCAzMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAzMax, "confTrk"), std::vector{0.2f, 0.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"}; // set to zero for run3 or so + 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"}; + // missing DCA Configurable?? because implemented in TrackSelection.h + } Track; + + FemtoDreamV0Selection LambdaCuts; + FemtoDreamV0Selection K0SCuts; + struct : o2::framework::ConfigurableGroup { + Configurable> confLambdaSign{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0Sign, "confLambda"), std::vector{-1, 1}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0Sign, "V0 selection: ")}; + Configurable> confLambdaPtMin{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0pTMin, "confLambda"), std::vector{0.3f, 0.4f, 0.5f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0pTMin, "V0 selection: ")}; + Configurable> confLambdaPtMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0pTMax, "confLambda"), std::vector{3.3f, 3.4f, 3.5f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0pTMax, "V0 selection: ")}; + Configurable> confLambdaEtaMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0etaMax, "confLambda"), std::vector{0.8f, 0.7f, 0.9f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0etaMax, "V0 selection: ")}; + Configurable> confLambdaDCADaughMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0DCADaughMax, "confLambda"), std::vector{1.2f, 1.5f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0DCADaughMax, "V0 selection: ")}; + Configurable> confLambdaCPAMin{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0CPAMin, "confLambda"), std::vector{0.99f, 0.995f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0CPAMin, "V0 selection: ")}; + Configurable> confLambdaTranRadMin{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0TranRadMin, "confLambda"), std::vector{0.2f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0TranRadMin, "V0 selection: ")}; + Configurable> confLambdaTranRadMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0TranRadMax, "confLambda"), std::vector{100.f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0TranRadMax, "V0 selection: ")}; + Configurable> confLambdaDecVtxMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0DecVtxMax, "confLambda"), std::vector{100.f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0DecVtxMax, "V0 selection: ")}; + + Configurable confLambdaInvMassLowLimit{"confLambdaInvMassLowLimit", 1.05, "Lower limit of the V0 invariant mass"}; + Configurable confLambdaInvMassUpLimit{"confLambdaInvMassUpLimit", 1.30, "Upper limit of the V0 invariant mass"}; + Configurable confLambdaRejectKaons{"confLambdaRejectKaons", false, "Switch to reject kaons"}; + Configurable confLambdaRejectLambdas{"confLambdaRejectLambdas", false, "Switch to reject lambdas (if mother is kaon)"}; + Configurable confLambdaInvKaonMassLowLimit{"confLambdaInvKaonMassLowLimit", 0.48, "Lower limit of the V0 invariant mass for Kaon rejection"}; + Configurable confLambdaInvKaonMassUpLimit{"confLambdaInvKaonMassUpLimit", 0.515, "Upper limit of the V0 invariant mass for Kaon rejection"}; + + Configurable> confLambdaChildSign{"confLambdaChildSign", std::vector{-1, 1}, "V0 Child sel: Charge"}; + Configurable> confLambdaChildEtaMax{"confLambdaChildEtaMax", std::vector{0.8f}, "V0 Child sel: max eta"}; + Configurable> confLambdaChildTPCnClsMin{"confLambdaChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "V0 Child sel: Min. nCls TPC"}; + Configurable> confLambdaChildDCAMin{"confLambdaChildDCAMin", std::vector{0.05f, 0.06f}, "V0 Child sel: Max. DCA Daugh to PV (cm)"}; + Configurable> confLambdaChildPIDnSigmaMax{"confLambdaChildPIDnSigmaMax", std::vector{5.f, 4.f}, "V0 Child sel: Max. PID nSigma TPC"}; + Configurable> confLambdaChildPIDspecies{"confLambdaChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "V0 Child sel: Particles species for PID"}; + + // cuts and object for v0 2 + Configurable> confK0shortSign{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0Sign, "confK0short"), std::vector{-1, 1}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0Sign, "V0 selection: ")}; + Configurable> confK0shortPtMin{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0pTMin, "confK0short"), std::vector{0.3f, 0.4f, 0.5f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0pTMin, "V0 selection: ")}; + Configurable> confK0shortPtMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0pTMax, "confK0short"), std::vector{3.3f, 3.4f, 3.5f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0pTMax, "V0 selection: ")}; + Configurable> confK0shortEtaMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0etaMax, "confK0short"), std::vector{0.8f, 0.7f, 0.9f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0etaMax, "V0 selection: ")}; + Configurable> confK0shortDCADaughMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0DCADaughMax, "confK0short"), std::vector{1.2f, 1.5f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0DCADaughMax, "V0 selection: ")}; + Configurable> confK0shortCPAMin{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0CPAMin, "confK0short"), std::vector{0.99f, 0.995f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0CPAMin, "V0 selection: ")}; + Configurable> confK0shortTranRadMin{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0TranRadMin, "confK0short"), std::vector{0.2f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0TranRadMin, "V0 selection: ")}; + Configurable> confK0shortTranRadMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0TranRadMax, "confK0short"), std::vector{100.f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0TranRadMax, "V0 selection: ")}; + Configurable> confK0shortDecVtxMax{FemtoDreamV0Selection::getSelectionName(femto_dream_v0_selection::kV0DecVtxMax, "confK0short"), std::vector{100.f}, FemtoDreamV0Selection::getSelectionHelper(femto_dream_v0_selection::kV0DecVtxMax, "V0 selection: ")}; + + Configurable confK0shortInvMassLowLimit{"confK0shortInvMassLowLimit", 1.05, "Lower limit of the V0 invariant mass"}; + Configurable confK0shortInvMassUpLimit{"confK0shortInvMassUpLimit", 1.30, "Upper limit of the V0 invariant mass"}; + Configurable confK0shortRejectKaons{"confK0shortRejectKaons", false, "Switch to reject kaons"}; + Configurable confK0shortRejectLambdas{"confK0shortRejectLambdas", false, "Switch to reject lambdas (if mother is kaon)"}; + Configurable confK0shortInvKaonMassLowLimit{"confK0shortInvKaonMassLowLimit", 0.48, "Lower limit of the V0 invariant mass for Kaon rejection"}; + Configurable confK0shortInvKaonMassUpLimit{"confK0shortInvKaonMassUpLimit", 0.515, "Upper limit of the V0 invariant mass for Kaon rejection"}; + + Configurable> confK0shortChildSign{"confK0shortChildSign", std::vector{-1, 1}, "V0 Child sel: Charge"}; + Configurable> confK0shortChildEtaMax{"confK0shortChildEtaMax", std::vector{0.8f}, "V0 Child sel: max eta"}; + Configurable> confK0shortChildTPCnClsMin{"confK0shortChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "V0 Child sel: Min. nCls TPC"}; + Configurable> confK0shortChildDCAMin{"confK0shortChildDCAMin", std::vector{0.05f, 0.06f}, "V0 Child sel: Max. DCA Daugh to PV (cm)"}; + Configurable> confK0shortChildPIDnSigmaMax{"confK0shortChildPIDnSigmaMax", std::vector{5.f, 4.f}, "V0 Child sel: Max. PID nSigma TPC"}; + Configurable> confK0shortChildPIDspecies{"confK0shortChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "V0 Child sel: Particles species for PID"}; + } V0Sel; + + FemtoDreamCascadeSelection xiCuts; + FemtoDreamCascadeSelection omegaCuts; + struct : o2::framework::ConfigurableGroup { + std::string prefix = std::string("Cascade"); + // Xi Selection + Configurable confXiInvMassLowLimit{"confXiInvMassLowLimit", 1.2, "Lower limit of the Cascade invariant mass"}; + Configurable confXiInvMassUpLimit{"confXiInvMassUpLimit", 1.5, "Upper limit of the Cascade invariant mass"}; + // Cascade + Configurable> confXiSign{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeSign, "confXi"), std::vector{-1, 1}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeSign, "Cascade selection: ")}; + Configurable> confXiPtMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadePtMin, "confXi"), std::vector{0.3f, 0.4f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadePtMin, "Cascade selection: ")}; + Configurable> confXiPtMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadePtMax, "confXi"), std::vector{5.5f, 6.0f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadePtMax, "Cascade selection: ")}; + Configurable> confXiEtaMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeEtaMax, "confXi"), std::vector{0.8f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeEtaMax, "Cascade selection: ")}; + Configurable> confXiDCADaughMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeDCADaughMax, "confXi"), std::vector{1.f, 1.2f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeDCADaughMax, "Cascade selection: ")}; + Configurable> confXiCPAMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeCPAMin, "confXi"), std::vector{0.99f, 0.95f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeCPAMin, "Cascade selection: ")}; + Configurable> confXiTranRadMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeTranRadMin, "confXi"), std::vector{0.2f, 0.5f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeTranRadMin, "Cascade selection: ")}; + Configurable> confXiTranRadMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeTranRadMax, "confXi"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeTranRadMax, "Cascade selection: ")}; + Configurable> confXiDecVtxMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeDecVtxMax, "confXi"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeDecVtxMax, "Cascade selection: ")}; + + // Cascade v0 daughters + Configurable> confXiV0DCADaughMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCADaughMax, "confXi"), std::vector{1.2f, 1.5f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCADaughMax, "CascV0 selection: ")}; + Configurable> confXiV0CPAMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0CPAMin, "confXi"), std::vector{0.99f, 0.995f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0CPAMin, "CascV0 selection: ")}; + Configurable> confXiV0TranRadMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0TranRadMin, "confXi"), std::vector{0.2f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0TranRadMin, "CascV0 selection: ")}; + Configurable> confXiV0TranRadMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0TranRadMax, "confXi"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0TranRadMax, "CascV0 selection: ")}; + Configurable> confXiV0DCAtoPVMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, "confXi"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, "CascV0 selection: ")}; + Configurable> confXiV0DCAtoPVMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, "confXi"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, "CascV0 selection: ")}; + Configurable confXiV0InvMassLowLimit{"confXiV0InvMassLowLimit", 1.011461, "Lower limit of the Cascade invariant mass"}; + Configurable confXiV0InvMassUpLimit{"confXiV0InvMassUpLimit", 1.027461, "Upper limit of the Cascade invariant mass"}; + // Cascade Daughter Tracks + Configurable> confXiV0ChildSign{"confXiV0ChildSign", std::vector{-1, 1}, "CascV0 Child sel: Charge"}; + Configurable> confXiV0ChildPtMin{"confXiV0ChildPtMin", std::vector{0.8f}, "CascV0 Child sel: min pt"}; + Configurable> confXiV0ChildEtaMax{"confXiV0ChildEtaMax", std::vector{0.8f}, "CascV0 Child sel: max eta"}; + Configurable> confXiV0ChildTPCnClsMin{"confXiV0ChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "CascV0 Child sel: Min. nCls TPC"}; + Configurable> confXiV0ChildDCAMin{"confXiV0ChildDCAMin", std::vector{0.05f, 0.06f}, "CascV0 Child sel: Max. DCA Daugh to PV (cm)"}; + Configurable> confXiV0ChildPIDnSigmaMax{"confXiV0ChildPIDnSigmaMax", std::vector{5.f, 4.f}, "CascV0 Child sel: Max. PID nSigma TPC"}; + Configurable> confXiV0ChildPIDspecies{"confXiV0ChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "CascV0 Child sel: Particles species for PID"}; + // Cascade Bachelor Track + Configurable> confXiBachelorSign{"confXiBachelorSign", std::vector{-1, 1}, "Cascade Bachelor sel: Charge"}; + Configurable> confXiBachelorPtMin{"confXiBachelorPtMin", std::vector{0.8f}, "Cascade Bachelor sel: min pt"}; + Configurable> confXiBachelorEtaMax{"confXiBachelorEtaMax", std::vector{0.8f}, "Cascade Bachelor sel: max eta"}; + Configurable> confXiBachelorTPCnClsMin{"confXiBachelorTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "Cascade Bachelor sel: Min. nCls TPC"}; + Configurable> confXiBachelorDCAMin{"confXiBachelorDCAMin", std::vector{0.05f, 0.06f}, "Cascade Bachelor sel: Max. DCA Daugh to PV (cm)"}; + Configurable> confXiBachelorPIDnSigmaMax{"confXiBachelorPIDnSigmaMax", std::vector{5.f, 4.f}, "Cascade Bachelor sel: Max. PID nSigma TPC"}; + Configurable> confXiBachelorPIDspecies{"confXiBachelorPIDspecies", std::vector{o2::track::PID::Pion}, "Cascade Bachelor sel: Particles species for PID"}; + + Configurable confXiRejectCompetingMass{"confXiRejectCompetingMass", false, "Switch on to reject Omegas (for Xi) or Xis (for Omegas)"}; + Configurable confXiInvCompetingMassLowLimit{"confXiInvCompetingMassLowLimit", 1.66, "Lower limit of the cascade invariant mass for competing mass rejection"}; + Configurable confXiInvCompetingMassUpLimit{"confXiInvCompetingMassUpLimit", 1.68, "Upper limit of the cascade invariant mass for competing mass rejection"}; + + // Omega selection + Configurable confOmegaInvMassLowLimit{"confOmegaInvMassLowLimit", 1.2, "Lower limit of the Cascade invariant mass"}; + Configurable confOmegaInvMassUpLimit{"confOmegaInvMassUpLimit", 1.5, "Upper limit of the Cascade invariant mass"}; + // Cascade + Configurable> confOmegaSign{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeSign, "confOmega"), std::vector{-1, 1}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeSign, "Cascade selection: ")}; + Configurable> confOmegaPtMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadePtMin, "confOmega"), std::vector{0.3f, 0.4f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadePtMin, "Cascade selection: ")}; + Configurable> confOmegaPtMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadePtMax, "confOmega"), std::vector{5.5f, 6.0f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadePtMax, "Cascade selection: ")}; + Configurable> confOmegaEtaMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeEtaMax, "confOmega"), std::vector{0.8f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeEtaMax, "Cascade selection: ")}; + Configurable> confOmegaDCADaughMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeDCADaughMax, "confOmega"), std::vector{1.f, 1.2f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeDCADaughMax, "Cascade selection: ")}; + Configurable> confOmegaCPAMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeCPAMin, "confOmega"), std::vector{0.99f, 0.95f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeCPAMin, "Cascade selection: ")}; + Configurable> confOmegaTranRadMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeTranRadMin, "confOmega"), std::vector{0.2f, 0.5f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeTranRadMin, "Cascade selection: ")}; + Configurable> confOmegaTranRadMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeTranRadMax, "confOmega"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeTranRadMax, "Cascade selection: ")}; + Configurable> confOmegaDecVtxMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeDecVtxMax, "confOmega"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeDecVtxMax, "Cascade selection: ")}; + + // Cascade v0 daughters + Configurable> confOmegaV0DCADaughMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCADaughMax, "confOmega"), std::vector{1.2f, 1.5f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCADaughMax, "CascV0 selection: ")}; + Configurable> confOmegaV0CPAMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0CPAMin, "confOmega"), std::vector{0.99f, 0.995f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0CPAMin, "CascV0 selection: ")}; + Configurable> confOmegaV0TranRadMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0TranRadMin, "confOmega"), std::vector{0.2f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0TranRadMin, "CascV0 selection: ")}; + Configurable> confOmegaV0TranRadMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0TranRadMax, "confOmega"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0TranRadMax, "CascV0 selection: ")}; + Configurable> confOmegaV0DCAtoPVMin{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, "confOmega"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, "CascV0 selection: ")}; + Configurable> confOmegaV0DCAtoPVMax{FemtoDreamCascadeSelection::getSelectionName(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, "confOmega"), std::vector{100.f}, FemtoDreamCascadeSelection::getSelectionHelper(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, "CascV0 selection: ")}; + Configurable confOmegaV0InvMassLowLimit{"confOmegaV0InvMassLowLimit", 1.011461, "Lower limit of the Cascade invariant mass"}; + Configurable confOmegaV0InvMassUpLimit{"confOmegaV0InvMassUpLimit", 1.027461, "Upper limit of the Cascade invariant mass"}; + // Cascade Daughter Tracks + Configurable> confOmegaV0ChildSign{"confOmegaV0ChildSign", std::vector{-1, 1}, "CascV0 Child sel: Charge"}; + Configurable> confOmegaV0ChildPtMin{"confOmegaV0ChildPtMin", std::vector{0.8f}, "CascV0 Child sel: min pt"}; + Configurable> confOmegaV0ChildEtaMax{"confOmegaV0ChildEtaMax", std::vector{0.8f}, "CascV0 Child sel: max eta"}; + Configurable> confOmegaV0ChildTPCnClsMin{"confOmegaV0ChildTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "CascV0 Child sel: Min. nCls TPC"}; + Configurable> confOmegaV0ChildDCAMin{"confOmegaV0ChildDCAMin", std::vector{0.05f, 0.06f}, "CascV0 Child sel: Max. DCA Daugh to PV (cm)"}; + Configurable> confOmegaV0ChildPIDnSigmaMax{"confOmegaV0ChildPIDnSigmaMax", std::vector{5.f, 4.f}, "CascV0 Child sel: Max. PID nSigma TPC"}; + Configurable> confOmegaV0ChildPIDspecies{"confOmegaV0ChildPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Proton}, "CascV0 Child sel: Particles species for PID"}; + // Cascade Bachelor Track + Configurable> confOmegaBachelorSign{"confOmegaBachelorSign", std::vector{-1, 1}, "Cascade Bachelor sel: Charge"}; + Configurable> confOmegaBachelorPtMin{"confOmegaBachelorPtMin", std::vector{0.8f}, "Cascade Bachelor sel: min pt"}; + Configurable> confOmegaBachelorEtaMax{"confOmegaBachelorEtaMax", std::vector{0.8f}, "Cascade Bachelor sel: max eta"}; + Configurable> confOmegaBachelorTPCnClsMin{"confOmegaBachelorTPCnClsMin", std::vector{80.f, 70.f, 60.f}, "Cascade Bachelor sel: Min. nCls TPC"}; + Configurable> confOmegaBachelorDCAMin{"confOmegaBachelorDCAMin", std::vector{0.05f, 0.06f}, "Cascade Bachelor sel: Max. DCA Daugh to PV (cm)"}; + Configurable> confOmegaBachelorPIDnSigmaMax{"confOmegaBachelorPIDnSigmaMax", std::vector{5.f, 4.f}, "Cascade Bachelor sel: Max. PID nSigma TPC"}; + Configurable> confOmegaBachelorPIDspecies{"confOmegaBachelorPIDspecies", std::vector{o2::track::PID::Pion}, "Cascade Bachelor sel: Particles species for PID"}; + + Configurable confOmegaRejectCompetingMass{"confOmegaRejectCompetingMass", false, "Switch on to reject Omegas (for Xi) or Xis (for Omegas)"}; + Configurable confOmegaInvCompetingMassLowLimit{"confOmegaInvCompetingMassLowLimit", 1.66, "Lower limit of the cascade invariant mass for competing mass rejection"}; + Configurable confOmegaInvCompetingMassUpLimit{"confOmegaInvCompetingMassUpLimit", 1.68, "Upper limit of the cascade invariant mass for competing mass rejection"}; + } confCascadeSel; + + // Resonances + FemtoDreamResoSelection resoCuts; // Phi + FemtoDreamResoSelection resoCutsKStar; // KStar + struct : ConfigurableGroup { + std::string prefix = std::string("Resonance"); + + // PhiCuts + Configurable confPhiInvMassLowLimit{"confPhiInvMassLowLimit", 0.9, "Lower limit of the Reso invariant mass"}; // 1.011461 + Configurable confPhiInvMassUpLimit{"confPhiInvMassUpLimit", 1.15, "Upper limit of the Reso invariant mass"}; // 1.027461 + Configurable confDoLikeSignPhi{"confDoLikeSignPhi", false, "(De)activates likeSign histo filling"}; + Configurable confMassQAPhiPart2PID{"confMassQAPhiPart2PID", o2::track::PID::Pion, "Daughter PID for massQAPart2 (bothPID2) histograms"}; + Configurable> confPhiSign{"confPhiSign", std::vector{-1., 1.}, "Reso Sign selection"}; + + Configurable> confPhiDaughterCharge{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kSign, "confPhiDaughter"), std::vector{-1, 1}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kSign, "Reso selection: ")}; + Configurable> confPhiDaughterPtMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMin, "confPhiDaughter"), std::vector{0.1, 0.15, 0.2}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMin, "Reso selection: ")}; + Configurable> confPhiDaughterPtMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMax, "confPhiDaughter"), std::vector{5.0, 4.0}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMax, "Reso selection: ")}; + Configurable> confPhiDaughterEtaMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kEtaMax, "confPhiDaughter"), std::vector{0.8, 0.85, 0.9}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kEtaMax, "Reso selection: ")}; + Configurable> confPhiDaughterTPCnClsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCnClsMin, "confPhiDaughter"), std::vector{75, 85, 100}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCnClsMin, "Reso selection: ")}; + Configurable> confPhiDaughterTPCfClsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCfClsMin, "confPhiDaughter"), std::vector{0.7, 0.8, 0.9}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCfClsMin, "Reso selection: ")}; + Configurable> confPhiDaughterTPCcRowsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCcRowsMin, "confPhiDaughter"), std::vector{75, 85, 100}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCcRowsMin, "Reso selection: ")}; + Configurable> confPhiDaughterDCAxyMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAxyMax, "confPhiDaughter"), std::vector{0.2, 0.15, 0.1}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAxyMax, "Reso selection: ")}; + Configurable> confPhiDaughterDCAzMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAzMax, "confPhiDaughter"), std::vector{0.2, 0.15, 0.1}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAzMax, "Reso selection: ")}; + Configurable> confPhiDaughterPIDnSigmaMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kPIDnSigmaMax, "confPhiDaughter"), std::vector{3.0, 2.5, 2.0}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kPIDnSigmaMax, "Reso selection: ")}; + Configurable> confPhiDaughterPIDspecies{"confPhiDaughterPIDspecies", std::vector{o2::track::PID::Kaon, o2::track::PID::Kaon}, "Reso Daughter sel: Particles species for PID"}; + Configurable> confPhiDaughterPTPCThr{"confPhiDaughterPTPCThr", std::vector{0.5, 0.5}, "p_T (GeV/c) & pid dependent Thresholds for case distinction between TPC/TPCTOF"}; + + // KStarCuts + Configurable confKstarInvMassLowLimit{"confKstarInvMassLowLimit", 0.9, "Lower limit of the Reso invariant mass"}; // 1.011461 + Configurable confKstarInvMassUpLimit{"confKstarInvMassUpLimit", 1.15, "Upper limit of the Reso invariant mass"}; // 1.027461 + Configurable confDoLikeSignKstar{"confDoLikeSignKstar", false, "(De)activates likeSign histo filling"}; + Configurable confMassQAKstarPart2PID{"confMassQAKstarPart2PID", o2::track::PID::Pion, "Daughter PID for massQAPart2 (bothPID2) histograms"}; + Configurable> confKstarSign{"confKstarSign", std::vector{-1., 1.}, "Reso Sign selection"}; + + Configurable> confKstarDaughterCharge{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kSign, "confKstarDaughter"), std::vector{-1, 1}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kSign, "Reso selection: ")}; + Configurable> confKstarDaughterPtMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMin, "confKstarDaughter"), std::vector{0.1, 0.15, 0.2}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMin, "Reso selection: ")}; + Configurable> confKstarDaughterPtMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kpTMax, "confKstarDaughter"), std::vector{5.0, 4.0}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kpTMax, "Reso selection: ")}; + Configurable> confKstarDaughterEtaMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kEtaMax, "confKstarDaughter"), std::vector{0.8, 0.85, 0.9}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kEtaMax, "Reso selection: ")}; + Configurable> confKstarDaughterTPCnClsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCnClsMin, "confKstarDaughter"), std::vector{75, 85, 100}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCnClsMin, "Reso selection: ")}; + Configurable> confKstarDaughterTPCfClsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCfClsMin, "confKstarDaughter"), std::vector{0.7, 0.8, 0.9}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCfClsMin, "Reso selection: ")}; + Configurable> confKstarDaughterTPCcRowsMin{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kTPCcRowsMin, "confKstarDaughter"), std::vector{75, 85, 100}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kTPCcRowsMin, "Reso selection: ")}; + Configurable> confKstarDaughterDCAxyMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAxyMax, "confKstarDaughter"), std::vector{0.2, 0.15, 0.1}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAxyMax, "Reso selection: ")}; + Configurable> confKstarDaughterDCAzMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kDCAzMax, "confKstarDaughter"), std::vector{0.2, 0.15, 0.1}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kDCAzMax, "Reso selection: ")}; + Configurable> confKstarDaughterPIDnSigmaMax{FemtoDreamTrackSelection::getSelectionName(femtoDreamTrackSelection::kPIDnSigmaMax, "confKstarDaughter"), std::vector{3.0, 2.5, 2.0}, FemtoDreamTrackSelection::getSelectionHelper(femtoDreamTrackSelection::kPIDnSigmaMax, "Reso selection: ")}; + Configurable> confKstarDaughterPIDspecies{"confKstarDaughterPIDspecies", std::vector{o2::track::PID::Kaon, o2::track::PID::Kaon}, "Reso Daughter sel: Particles species for PID"}; + Configurable> confKstarDaughterPTPCThr{"confKstarDaughterPTPCThr", std::vector{0.5, 0.5}, "p_T (GeV/c) & pid dependent Thresholds for case distinction between TPC/TPCTOF"}; + } 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; + + struct : o2::framework::ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry qaRegistryV0{"QAHistosV0", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry qaRegistryCascade{"QAHistosCascade", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry qaRegistryReso{"QAHistosReso", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry trackRegistry{"Tracks", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry v0Registry{"V0", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry cascadeRegistry{"Cascade", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resoRegistry{"Reso", {}, OutputObjHandlingPolicy::AnalysisObject}; + + int mRunNumber; + float mMagField; + std::string zorroTriggerNames = ""; + Service ccdb; /// Accessing the CCDB + RCTFlagsChecker rctChecker; + + void init(InitContext&) + { + if (doprocessData == false && doprocessData_noCentrality == false && doprocessDataCentPbPb == false && doprocessMC == false && doprocessMCnoCentrality == false && doprocessMCCentPbPb == false) { + LOGF(fatal, "Neither processData nor processMC enabled. Please choose one."); + } + if ((doprocessData == true && doprocessMC == true) || (doprocessData == true && doprocessMCnoCentrality == true) || (doprocessMC == true && doprocessMCnoCentrality == true) || (doprocessData_noCentrality == true && doprocessData == true) || (doprocessData_noCentrality == true && doprocessMC == true) || (doprocessData_noCentrality == true && doprocessMCnoCentrality == true) || (doprocessDataCentPbPb == true && doprocessData == true) || (doprocessDataCentPbPb == true && doprocessData_noCentrality == true) || (doprocessDataCentPbPb == true && doprocessMC == true) || (doprocessDataCentPbPb == true && doprocessMCnoCentrality == true) || (doprocessDataCentPbPb == true && doprocessMCCentPbPb == 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}}); + resoRegistry.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}}); + + if (confEnableTriggerSelection) { + for (const auto& triggerName : software_triggers::triggerNames) { + if (confTriggerSwitches->get("Switch", triggerName.c_str())) { + zorroTriggerNames += triggerName + ","; + } + } + zorroTriggerNames.pop_back(); + } + + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, false, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + colCuts.setCuts(confEvtZvtx.value, confEvtTriggerCheck.value, confEvtTriggerSel.value, confEvtOfflineCheck.value, confEvtAddOfflineCheck.value, confIsRun3.value, confEvtMinSphericity.value, confEvtSphericityPtmin.value); + colCuts.init(&qaRegistry); + + trackCuts.setSelection(Track.confTrkCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + trackCuts.setSelection(Track.confTrkPtmin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(Track.confTrkPtmax, femtoDreamTrackSelection::kpTMax, femtoDreamSelection::kUpperLimit); + trackCuts.setSelection(Track.confTrkEta, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(Track.confTrkTPCnclsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(Track.confTrkTPCfCls, femtoDreamTrackSelection::kTPCfClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(Track.confTrkTPCcRowsMin, femtoDreamTrackSelection::kTPCcRowsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(Track.confTrkTPCsCls, femtoDreamTrackSelection::kTPCsClsMax, femtoDreamSelection::kUpperLimit); + trackCuts.setSelection(Track.confTrkITSnclsMin, femtoDreamTrackSelection::kITSnClsMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(Track.confTrkITSnclsIbMin, femtoDreamTrackSelection::kITSnClsIbMin, femtoDreamSelection::kLowerLimit); + trackCuts.setSelection(Track.confTrkDCAxyMax, femtoDreamTrackSelection::kDCAxyMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(Track.confTrkDCAzMax, femtoDreamTrackSelection::kDCAzMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setSelection(Track.confTrkPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + trackCuts.setPIDSpecies(Track.confTrkPIDspecies); + trackCuts.setnSigmaPIDOffset(Track.confTrkPIDnSigmaOffsetTPC, Track.confTrkPIDnSigmaOffsetTOF); + trackCuts.init(&qaRegistry, &trackRegistry); + + /// \todo fix how to pass array to setSelection, getRow() passing a + /// different type! + // v0Cuts.setSelection(confV0Selection->getRow(0), + // femto_dream_v0_selection::kDecVtxMax, femtoDreamSelection::kAbsUpperLimit); + if (confIsActivateV0) { + LambdaCuts.setSelection(V0Sel.confLambdaSign, femto_dream_v0_selection::kV0Sign, femtoDreamSelection::kEqual); + LambdaCuts.setSelection(V0Sel.confLambdaPtMin, femto_dream_v0_selection::kV0pTMin, femtoDreamSelection::kLowerLimit); + LambdaCuts.setSelection(V0Sel.confLambdaPtMax, femto_dream_v0_selection::kV0pTMax, femtoDreamSelection::kUpperLimit); + LambdaCuts.setSelection(V0Sel.confLambdaEtaMax, femto_dream_v0_selection::kV0etaMax, femtoDreamSelection::kAbsUpperLimit); + LambdaCuts.setSelection(V0Sel.confLambdaDCADaughMax, femto_dream_v0_selection::kV0DCADaughMax, femtoDreamSelection::kUpperLimit); + LambdaCuts.setSelection(V0Sel.confLambdaCPAMin, femto_dream_v0_selection::kV0CPAMin, femtoDreamSelection::kLowerLimit); + LambdaCuts.setSelection(V0Sel.confLambdaTranRadMin, femto_dream_v0_selection::kV0TranRadMin, femtoDreamSelection::kLowerLimit); + LambdaCuts.setSelection(V0Sel.confLambdaTranRadMax, femto_dream_v0_selection::kV0TranRadMax, femtoDreamSelection::kUpperLimit); + LambdaCuts.setSelection(V0Sel.confLambdaDecVtxMax, femto_dream_v0_selection::kV0DecVtxMax, femtoDreamSelection::kUpperLimit); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confLambdaChildSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confLambdaChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confLambdaChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confLambdaChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confLambdaChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + + LambdaCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confLambdaChildSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confLambdaChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confLambdaChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confLambdaChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + LambdaCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confLambdaChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + LambdaCuts.setChildPIDSpecies(femto_dream_v0_selection::kPosTrack, V0Sel.confLambdaChildPIDspecies); + LambdaCuts.setChildPIDSpecies(femto_dream_v0_selection::kNegTrack, V0Sel.confLambdaChildPIDspecies); + LambdaCuts.init(&qaRegistryV0, &v0Registry); + LambdaCuts.setInvMassLimits(V0Sel.confLambdaInvMassLowLimit, V0Sel.confLambdaInvMassUpLimit); + LambdaCuts.setIsMother(true); + + LambdaCuts.setChildRejectNotPropagatedTracks(femto_dream_v0_selection::kPosTrack, confTrkRejectNotPropagated); + LambdaCuts.setChildRejectNotPropagatedTracks(femto_dream_v0_selection::kNegTrack, confTrkRejectNotPropagated); + + LambdaCuts.setnSigmaPIDOffsetTPC(Track.confTrkPIDnSigmaOffsetTPC); + LambdaCuts.setChildnSigmaPIDOffset(femto_dream_v0_selection::kPosTrack, Track.confTrkPIDnSigmaOffsetTPC, Track.confTrkPIDnSigmaOffsetTOF); + LambdaCuts.setChildnSigmaPIDOffset(femto_dream_v0_selection::kNegTrack, Track.confTrkPIDnSigmaOffsetTPC, Track.confTrkPIDnSigmaOffsetTOF); + + if (V0Sel.confLambdaRejectKaons) { + LambdaCuts.setKaonInvMassLimits(V0Sel.confLambdaInvKaonMassLowLimit, V0Sel.confLambdaInvKaonMassUpLimit); + } + } + + if (confIsActivateV0K0S) { + K0SCuts.setSelection(V0Sel.confK0shortSign, femto_dream_v0_selection::kV0Sign, femtoDreamSelection::kEqual); + K0SCuts.setSelection(V0Sel.confK0shortPtMin, femto_dream_v0_selection::kV0pTMin, femtoDreamSelection::kLowerLimit); + K0SCuts.setSelection(V0Sel.confK0shortPtMax, femto_dream_v0_selection::kV0pTMax, femtoDreamSelection::kUpperLimit); + K0SCuts.setSelection(V0Sel.confK0shortEtaMax, femto_dream_v0_selection::kV0etaMax, femtoDreamSelection::kAbsUpperLimit); + K0SCuts.setSelection(V0Sel.confK0shortDCADaughMax, femto_dream_v0_selection::kV0DCADaughMax, femtoDreamSelection::kUpperLimit); + K0SCuts.setSelection(V0Sel.confK0shortCPAMin, femto_dream_v0_selection::kV0CPAMin, femtoDreamSelection::kLowerLimit); + K0SCuts.setSelection(V0Sel.confK0shortTranRadMin, femto_dream_v0_selection::kV0TranRadMin, femtoDreamSelection::kLowerLimit); + K0SCuts.setSelection(V0Sel.confK0shortTranRadMax, femto_dream_v0_selection::kV0TranRadMax, femtoDreamSelection::kUpperLimit); + K0SCuts.setSelection(V0Sel.confK0shortDecVtxMax, femto_dream_v0_selection::kV0DecVtxMax, femtoDreamSelection::kUpperLimit); + K0SCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confK0shortChildSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + K0SCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confK0shortChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + K0SCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confK0shortChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + K0SCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confK0shortChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + K0SCuts.setChildCuts(femto_dream_v0_selection::kPosTrack, V0Sel.confK0shortChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + + K0SCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confK0shortChildSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + K0SCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confK0shortChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + K0SCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confK0shortChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + K0SCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confK0shortChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + K0SCuts.setChildCuts(femto_dream_v0_selection::kNegTrack, V0Sel.confK0shortChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + K0SCuts.setChildPIDSpecies(femto_dream_v0_selection::kPosTrack, V0Sel.confK0shortChildPIDspecies); + K0SCuts.setChildPIDSpecies(femto_dream_v0_selection::kNegTrack, V0Sel.confK0shortChildPIDspecies); + K0SCuts.init(&qaRegistryV0, &v0Registry); + K0SCuts.setInvMassLimits(V0Sel.confK0shortInvMassLowLimit, V0Sel.confK0shortInvMassUpLimit); + K0SCuts.setIsMother(false); + + K0SCuts.setChildRejectNotPropagatedTracks(femto_dream_v0_selection::kPosTrack, confTrkRejectNotPropagated); + K0SCuts.setChildRejectNotPropagatedTracks(femto_dream_v0_selection::kNegTrack, confTrkRejectNotPropagated); + + K0SCuts.setnSigmaPIDOffsetTPC(Track.confTrkPIDnSigmaOffsetTPC); + K0SCuts.setChildnSigmaPIDOffset(femto_dream_v0_selection::kPosTrack, Track.confTrkPIDnSigmaOffsetTPC, Track.confTrkPIDnSigmaOffsetTOF); + K0SCuts.setChildnSigmaPIDOffset(femto_dream_v0_selection::kNegTrack, Track.confTrkPIDnSigmaOffsetTPC, Track.confTrkPIDnSigmaOffsetTOF); + + K0SCuts.setRejectLambda(V0Sel.confK0shortRejectLambdas); + K0SCuts.setKaonInvMassLimits(V0Sel.confK0shortInvKaonMassLowLimit, V0Sel.confK0shortInvKaonMassUpLimit); + } + + if (confIsActivateXi) { + // Cascades + xiCuts.setSelection(confCascadeSel.confXiSign, femtoDreamCascadeSelection::kCascadeSign, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeSign)); + xiCuts.setSelection(confCascadeSel.confXiPtMin, femtoDreamCascadeSelection::kCascadePtMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadePtMin)); + xiCuts.setSelection(confCascadeSel.confXiPtMax, femtoDreamCascadeSelection::kCascadePtMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadePtMax)); + xiCuts.setSelection(confCascadeSel.confXiEtaMax, femtoDreamCascadeSelection::kCascadeEtaMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeEtaMax)); + xiCuts.setSelection(confCascadeSel.confXiDCADaughMax, femtoDreamCascadeSelection::kCascadeDCADaughMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeDCADaughMax)); + xiCuts.setSelection(confCascadeSel.confXiCPAMin, femtoDreamCascadeSelection::kCascadeCPAMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeCPAMin)); + xiCuts.setSelection(confCascadeSel.confXiTranRadMin, femtoDreamCascadeSelection::kCascadeTranRadMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeTranRadMin)); + xiCuts.setSelection(confCascadeSel.confXiTranRadMax, femtoDreamCascadeSelection::kCascadeTranRadMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeTranRadMax)); + xiCuts.setSelection(confCascadeSel.confXiDecVtxMax, femtoDreamCascadeSelection::kCascadeDecVtxMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeDecVtxMax)); + // Cascade v0 + xiCuts.setSelection(confCascadeSel.confXiV0DCADaughMax, femtoDreamCascadeSelection::kCascadeV0DCADaughMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCADaughMax)); + xiCuts.setSelection(confCascadeSel.confXiV0CPAMin, femtoDreamCascadeSelection::kCascadeV0CPAMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0CPAMin)); + xiCuts.setSelection(confCascadeSel.confXiV0TranRadMin, femtoDreamCascadeSelection::kCascadeV0TranRadMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0TranRadMin)); + xiCuts.setSelection(confCascadeSel.confXiV0TranRadMax, femtoDreamCascadeSelection::kCascadeV0TranRadMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0TranRadMax)); + xiCuts.setSelection(confCascadeSel.confXiV0DCAtoPVMin, femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin)); + xiCuts.setSelection(confCascadeSel.confXiV0DCAtoPVMax, femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax)); + + // Cascade Daughter Tracks + xiCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confXiV0ChildSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confXiV0ChildPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confXiV0ChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confXiV0ChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confXiV0ChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confXiV0ChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + xiCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confXiV0ChildPIDspecies); + + xiCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confXiV0ChildSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confXiV0ChildPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confXiV0ChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confXiV0ChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confXiV0ChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confXiV0ChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + xiCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confXiV0ChildPIDspecies); + + // Cascade Bachelor Track + xiCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confXiBachelorSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confXiBachelorPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confXiBachelorEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confXiBachelorTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confXiBachelorDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + xiCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confXiBachelorPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + xiCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confXiBachelorPIDspecies); + + xiCuts.init(&qaRegistryCascade, &cascadeRegistry, false); + xiCuts.setInvMassLimits(confCascadeSel.confXiInvMassLowLimit, confCascadeSel.confXiInvMassUpLimit); + xiCuts.setV0InvMassLimits(confCascadeSel.confXiV0InvMassLowLimit, confCascadeSel.confXiV0InvMassUpLimit); + if (confCascadeSel.confXiRejectCompetingMass) { + xiCuts.setCompetingInvMassLimits(confCascadeSel.confXiInvCompetingMassLowLimit, confCascadeSel.confXiInvCompetingMassUpLimit); + } + } + + if (confIsActivateOmega) { + // Cascades + omegaCuts.setSelection(confCascadeSel.confOmegaSign, femtoDreamCascadeSelection::kCascadeSign, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeSign)); + omegaCuts.setSelection(confCascadeSel.confOmegaPtMin, femtoDreamCascadeSelection::kCascadePtMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadePtMin)); + omegaCuts.setSelection(confCascadeSel.confOmegaPtMax, femtoDreamCascadeSelection::kCascadePtMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadePtMax)); + omegaCuts.setSelection(confCascadeSel.confOmegaEtaMax, femtoDreamCascadeSelection::kCascadeEtaMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeEtaMax)); + omegaCuts.setSelection(confCascadeSel.confOmegaDCADaughMax, femtoDreamCascadeSelection::kCascadeDCADaughMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeDCADaughMax)); + omegaCuts.setSelection(confCascadeSel.confOmegaCPAMin, femtoDreamCascadeSelection::kCascadeCPAMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeCPAMin)); + omegaCuts.setSelection(confCascadeSel.confOmegaTranRadMin, femtoDreamCascadeSelection::kCascadeTranRadMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeTranRadMin)); + omegaCuts.setSelection(confCascadeSel.confOmegaTranRadMax, femtoDreamCascadeSelection::kCascadeTranRadMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeTranRadMax)); + omegaCuts.setSelection(confCascadeSel.confOmegaDecVtxMax, femtoDreamCascadeSelection::kCascadeDecVtxMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeDecVtxMax)); + // Cascade v0 + omegaCuts.setSelection(confCascadeSel.confOmegaV0DCADaughMax, femtoDreamCascadeSelection::kCascadeV0DCADaughMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCADaughMax)); + omegaCuts.setSelection(confCascadeSel.confOmegaV0CPAMin, femtoDreamCascadeSelection::kCascadeV0CPAMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0CPAMin)); + omegaCuts.setSelection(confCascadeSel.confOmegaV0TranRadMin, femtoDreamCascadeSelection::kCascadeV0TranRadMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0TranRadMin)); + omegaCuts.setSelection(confCascadeSel.confOmegaV0TranRadMax, femtoDreamCascadeSelection::kCascadeV0TranRadMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0TranRadMax)); + omegaCuts.setSelection(confCascadeSel.confOmegaV0DCAtoPVMin, femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMin)); + omegaCuts.setSelection(confCascadeSel.confOmegaV0DCAtoPVMax, femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax, FemtoDreamCascadeSelection::getSelectionType(femtoDreamCascadeSelection::kCascadeV0DCAtoPVMax)); + + // Cascade Daughter Tracks + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confOmegaV0ChildSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confOmegaV0ChildPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confOmegaV0ChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confOmegaV0ChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confOmegaV0ChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confOmegaV0ChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + omegaCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kPosTrack, confCascadeSel.confOmegaV0ChildPIDspecies); + + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confOmegaV0ChildSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confOmegaV0ChildPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confOmegaV0ChildEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confOmegaV0ChildTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confOmegaV0ChildDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confOmegaV0ChildPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + omegaCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kNegTrack, confCascadeSel.confOmegaV0ChildPIDspecies); + + // Cascade Bachelor Track + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confOmegaBachelorSign, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confOmegaBachelorPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confOmegaBachelorEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confOmegaBachelorTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confOmegaBachelorDCAMin, femtoDreamTrackSelection::kDCAMin, femtoDreamSelection::kAbsLowerLimit); + omegaCuts.setChildCuts(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confOmegaBachelorPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + omegaCuts.setChildPIDSpecies(femtoDreamCascadeSelection::kBachTrack, confCascadeSel.confOmegaBachelorPIDspecies); + + omegaCuts.init(&qaRegistryCascade, &cascadeRegistry, true); + omegaCuts.setInvMassLimits(confCascadeSel.confOmegaInvMassLowLimit, confCascadeSel.confOmegaInvMassUpLimit); + omegaCuts.setV0InvMassLimits(confCascadeSel.confOmegaV0InvMassLowLimit, confCascadeSel.confOmegaV0InvMassUpLimit); + if (confCascadeSel.confOmegaRejectCompetingMass) { + omegaCuts.setCompetingInvMassLimits(confCascadeSel.confOmegaInvCompetingMassLowLimit, confCascadeSel.confOmegaInvCompetingMassUpLimit); + } + } + + if (confIsActivatePhi.value) { + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterPtMax, femtoDreamTrackSelection::kpTMax, femtoDreamSelection::kUpperLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterTPCfClsMin, femtoDreamTrackSelection::kTPCfClsMin, femtoDreamSelection::kLowerLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterTPCcRowsMin, femtoDreamTrackSelection::kTPCcRowsMin, femtoDreamSelection::kLowerLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterDCAxyMax, femtoDreamTrackSelection::kDCAxyMax, femtoDreamSelection::kAbsUpperLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterDCAzMax, femtoDreamTrackSelection::kDCAzMax, femtoDreamSelection::kAbsUpperLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterPtMax, femtoDreamTrackSelection::kpTMax, femtoDreamSelection::kUpperLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterTPCfClsMin, femtoDreamTrackSelection::kTPCfClsMin, femtoDreamSelection::kLowerLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterTPCcRowsMin, femtoDreamTrackSelection::kTPCcRowsMin, femtoDreamSelection::kLowerLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterDCAxyMax, femtoDreamTrackSelection::kDCAxyMax, femtoDreamSelection::kAbsUpperLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterDCAzMax, femtoDreamTrackSelection::kDCAzMax, femtoDreamSelection::kAbsUpperLimit); + resoCuts.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + + resoCuts.init(&qaRegistryReso, &resoRegistry); + + resoCuts.assign(Resonance.confPhiDaughterPTPCThr); // assigns Configurable value to class member + resoCuts.setDaughterPIDSpecies(femto_dream_reso_selection::kPosdaugh, Resonance.confPhiDaughterPIDspecies); + resoCuts.setDaughterPIDSpecies(femto_dream_reso_selection::kNegdaugh, Resonance.confPhiDaughterPIDspecies); + resoCuts.setDaughternSigmaPIDOffset(femto_dream_reso_selection::kPosdaugh, 0.f, 0.f); + resoCuts.setDaughternSigmaPIDOffset(femto_dream_reso_selection::kNegdaugh, 0.f, 0.f); + + resoCuts.setSelection(Resonance.confPhiSign, femto_dream_reso_selection::kResoSign, femtoDreamSelection::kEqual); + } + + if (confIsActivateKStar.value) { + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterPtMax, femtoDreamTrackSelection::kpTMax, femtoDreamSelection::kUpperLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterTPCfClsMin, femtoDreamTrackSelection::kTPCfClsMin, femtoDreamSelection::kLowerLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterTPCcRowsMin, femtoDreamTrackSelection::kTPCcRowsMin, femtoDreamSelection::kLowerLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterDCAxyMax, femtoDreamTrackSelection::kDCAxyMax, femtoDreamSelection::kAbsUpperLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterDCAzMax, femtoDreamTrackSelection::kDCAzMax, femtoDreamSelection::kAbsUpperLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterCharge, femtoDreamTrackSelection::kSign, femtoDreamSelection::kEqual); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterPtMin, femtoDreamTrackSelection::kpTMin, femtoDreamSelection::kLowerLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterPtMax, femtoDreamTrackSelection::kpTMax, femtoDreamSelection::kUpperLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterEtaMax, femtoDreamTrackSelection::kEtaMax, femtoDreamSelection::kAbsUpperLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterTPCnClsMin, femtoDreamTrackSelection::kTPCnClsMin, femtoDreamSelection::kLowerLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterTPCfClsMin, femtoDreamTrackSelection::kTPCfClsMin, femtoDreamSelection::kLowerLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterTPCcRowsMin, femtoDreamTrackSelection::kTPCcRowsMin, femtoDreamSelection::kLowerLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterDCAxyMax, femtoDreamTrackSelection::kDCAxyMax, femtoDreamSelection::kAbsUpperLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterDCAzMax, femtoDreamTrackSelection::kDCAzMax, femtoDreamSelection::kAbsUpperLimit); + resoCutsKStar.setDaughterCuts(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); + + resoCutsKStar.init(&qaRegistryReso, &resoRegistry); + + resoCutsKStar.assign(Resonance.confKstarDaughterPTPCThr); // assigns Configurable value to class member + resoCutsKStar.setDaughterPIDSpecies(femto_dream_reso_selection::kPosdaugh, Resonance.confKstarDaughterPIDspecies); + resoCutsKStar.setDaughterPIDSpecies(femto_dream_reso_selection::kNegdaugh, Resonance.confKstarDaughterPIDspecies); + resoCutsKStar.setDaughternSigmaPIDOffset(femto_dream_reso_selection::kPosdaugh, 0.f, 0.f); + resoCutsKStar.setDaughternSigmaPIDOffset(femto_dream_reso_selection::kNegdaugh, 0.f, 0.f); + + resoCutsKStar.setSelection(Resonance.confKstarSign, femto_dream_reso_selection::kResoSign, femtoDreamSelection::kEqual); + } + + 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 initCcdbMagTrig(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 if constexpr (isReso) { + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., -999., // for the moment + -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., -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()) { + + constexpr int ProcessDirectMother = 4; + constexpr int ProcessInelasticHadronic = 23; + constexpr int GenStatusTransport = -1; + + // 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 (std::abs(pdgCode) == std::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() == ProcessDirectMother && particleMC.getGenStatusCode() == GenStatusTransport && !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() == ProcessInelasticHadronic && particleMC.getGenStatusCode() == GenStatusTransport) { + 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 fillLikeSign(P const& sliceDaughters, FemtoDreamResoSelection& resoSelectionObject, V const& pidVector, E const& extraPID) + { + for (const auto& track1 : sliceDaughters) { + if (!resoSelectionObject.daughterSelectionPos(track1) || !resoSelectionObject.isSelectedMinimalPIDPos(track1, pidVector)) { + continue; + } + for (const auto& track2 : sliceDaughters) { + if (!resoSelectionObject.daughterSelectionPos(track2) || !resoSelectionObject.isSelectedMinimalPIDPos(track2, pidVector)) { + continue; + } + bool resoIsNotAnti = true; /// bool for differentianting between particle/antiparticle + if ((pidVector.size() > 1) && (pidVector[0] != pidVector[1])) { + auto [isNormal, WrongCombination] = resoSelectionObject.checkCombination(track1, track2, pidVector); + if (WrongCombination) { + continue; + } + resoIsNotAnti = isNormal; + } + /// Resos, where both daughters have the same PID are defaulted to sign 1. and resoIsNotAnti = true + resoSelectionObject.fillLikeSignHistos(track1, track2, pidVector, extraPID, resoIsNotAnti); + } // for (const &auto track2 : sliceDaughters) + } // for (const &auto track1 : sliceDaughters) + } + + 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; + } + + // minimal selection + bool bEmptyColl = true; + if (!colCuts.isEmptyCollision(col, tracks, trackCuts)) { + bEmptyColl = false; + } + if (bEmptyColl && confIsActivateXi.value) { + if (!colCuts.isCollisionWithoutTrkCasc(col, fullCascades, xiCuts, tracks)) { + bEmptyColl = false; + } + } + if (bEmptyColl && confIsActivateOmega.value) { + if (!colCuts.isCollisionWithoutTrkCasc(col, fullCascades, omegaCuts, tracks)) { + bEmptyColl = false; + } + } + if (bEmptyColl && confIsActivateV0.value) { + if (!colCuts.isEmptyCollision(col, fullV0s, LambdaCuts, tracks)) { + bEmptyColl = false; + } + } + if (bEmptyColl && confIsActivateV0K0S.value) { + if (!colCuts.isEmptyCollision(col, fullV0s, K0SCuts, tracks)) { + bEmptyColl = false; + } + } + if (bEmptyColl) { + return; + } + + if (rctCut.requireRCTFlagChecker && !rctChecker(col)) { + 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 + + for (const 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); + } + } + + // v01 (Lambdas) + if (confIsActivateV0.value) { + 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 + /// 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.)); + LambdaCuts.fillLambdaQA(col, v0, postrack, negtrack); + + if (!LambdaCuts.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); + // } + + LambdaCuts.fillQA(col, v0, postrack, negtrack); ///\todo fill QA also for daughters + auto cutContainerV0 = LambdaCuts.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(femto_dream_v0_selection::V0ContainerPosition::kPosCuts), + cutContainerV0.at(femto_dream_v0_selection::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(femto_dream_v0_selection::V0ContainerPosition::kNegCuts), + cutContainerV0.at(femto_dream_v0_selection::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(femto_dream_v0_selection::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); + } + } + } + + // v02 (K0S) + if (confIsActivateV0K0S.value) { + 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 + /// 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.)); + K0SCuts.fillLambdaQA(col, v0, postrack, negtrack); + + if (!K0SCuts.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); + // } + + K0SCuts.fillQA(col, v0, postrack, negtrack); ///\todo fill QA also for daughters + auto cutContainerV0 = K0SCuts.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(femto_dream_v0_selection::V0ContainerPosition::kPosCuts), + cutContainerV0.at(femto_dream_v0_selection::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(femto_dream_v0_selection::V0ContainerPosition::kNegCuts), + cutContainerV0.at(femto_dream_v0_selection::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::kV0K0Short, + cutContainerV0.at(femto_dream_v0_selection::V0ContainerPosition::kV0), + 0, + v0.v0cosPA(), + indexChildID, + v0.mK0Short(), + v0.mK0Short()); + 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); /// change particle Type here as well? + } + } + } + + // Cascades (Xi and Omega) + if (confIsActivateXi.value || confIsActivateOmega.value) { + for (const 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(); + + if (confIsActivateXi.value) { + xiCuts.fillQA<0, aod::femtodreamparticle::ParticleType::kCascade, aod::femtodreamparticle::ParticleType::kCascadeV0Child, aod::femtodreamparticle::ParticleType::kCascadeBachelor>(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); + + if (xiCuts.isSelectedMinimal(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc)) { + xiCuts.fillQA<1, aod::femtodreamparticle::ParticleType::kCascade, aod::femtodreamparticle::ParticleType::kCascadeV0Child, aod::femtodreamparticle::ParticleType::kCascadeBachelor>(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); + auto cutContainerCasc = xiCuts.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 + } + + // continue; + } // if xiCuts.isSelectedMinimal + } // if confIsActivateXi + if (confIsActivateOmega.value) { + omegaCuts.fillQA<0, aod::femtodreamparticle::ParticleType::kOmega, aod::femtodreamparticle::ParticleType::kOmegaV0Child, aod::femtodreamparticle::ParticleType::kOmegaBachelor>(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); + + if (omegaCuts.isSelectedMinimal(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc)) { + + omegaCuts.fillQA<1, aod::femtodreamparticle::ParticleType::kOmega, aod::femtodreamparticle::ParticleType::kOmegaV0Child, aod::femtodreamparticle::ParticleType::kOmegaBachelor>(col, casc, posTrackCasc, negTrackCasc, bachTrackCasc); + auto cutContainerCasc = omegaCuts.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::kOmegaV0Child, + 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::kOmegaV0Child, + 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::kOmegaBachelor, + 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::kOmega, + cutContainerCasc.at(femtoDreamCascadeSelection::CascadeContainerPosition::kCascade), + 0, + casc.casccosPA(col.posX(), col.posY(), col.posZ()), + indexCascadeChildID, + casc.mOmega(), + 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 + } + + // continue; + } // if omegaCuts.isSelectedMinimal + } // if confIsActivateOmega + } // loop over cascades + } // at least one cascade active + + if (confIsActivatePhi.value) { + + resoCuts.updateSigmaPIDMax(); + + auto slicePosdaugh = daughter1.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); // o2::framework defined in AnalysisHelper.h + auto sliceNegdaugh = daughter2.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); + + for (const auto& track1 : slicePosdaugh) { + if (!resoCuts.daughterSelectionPos(track1) || !resoCuts.isSelectedMinimalPIDPos(track1, Resonance.confPhiDaughterPIDspecies.value)) { + continue; + } + + for (const auto& track2 : sliceNegdaugh) { + if (!resoCuts.daughterSelectionNeg(track2) || !resoCuts.isSelectedMinimalPIDNeg(track2, Resonance.confPhiDaughterPIDspecies.value)) { + continue; /// loosest cuts for track2 + } + + /// This only works for the case where the mass of opposite charged particles are the same (for example K+/K- have same mass) + float massPart1 = o2::track::PID::getMass(Resonance.confPhiDaughterPIDspecies.value[0]); + float massPart2 = massPart1; + if (Resonance.confPhiDaughterPIDspecies->size() > 1) + massPart2 = o2::track::PID::getMass(Resonance.confPhiDaughterPIDspecies.value[1]); + + /// Resonance + ROOT::Math::PtEtaPhiMVector tempD1(track1.pt(), track1.eta(), track1.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempD2(track2.pt(), track2.eta(), track2.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempReso = tempD1 + tempD2; + /// Anti-resonance + ROOT::Math::PtEtaPhiMVector tempDA1(track1.pt(), track1.eta(), track1.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempDA2(track2.pt(), track2.eta(), track2.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempAntiReso = tempDA1 + tempDA2; + + bool resoIsNotAnti = true; /// bool for differentianting between particle/antiparticle + float resoSign = 1.; + if ((Resonance.confPhiDaughterPIDspecies->size() > 1) && (Resonance.confPhiDaughterPIDspecies.value[0] != Resonance.confPhiDaughterPIDspecies.value[1])) { + auto [isNormal, WrongCombination] = resoCuts.checkCombination(track1, track2, Resonance.confPhiDaughterPIDspecies.value); + if (WrongCombination) { + continue; + } + if (!isNormal) { + resoSign = -1.; + } + resoIsNotAnti = isNormal; + } + /// Resos, where both daughters have the same PID are defaulted to sign 1. and resoIsNotAnti = true + + if (resoIsNotAnti) { + resoCuts.fillResoQA(track1, track2, true, tempReso.M(), tempAntiReso.M(), Resonance.confPhiDaughterPIDspecies.value, Resonance.confMassQAPhiPart2PID.value); + if (!(tempReso.M() > Resonance.confPhiInvMassLowLimit.value && tempReso.M() < Resonance.confPhiInvMassUpLimit.value)) + continue; + resoCuts.fillMassSelectedQA(tempReso.M(), true); + } else { + resoCuts.fillResoQA(track1, track2, false, tempAntiReso.M(), tempReso.M(), Resonance.confPhiDaughterPIDspecies.value, Resonance.confMassQAPhiPart2PID.value); + if (!(tempAntiReso.M() > Resonance.confPhiInvMassLowLimit.value && tempAntiReso.M() < Resonance.confPhiInvMassUpLimit.value)) + continue; + resoCuts.fillMassSelectedQA(tempAntiReso.M(), false); + } + + resoCuts.fillQA(track1, track2); + + auto type = resoCuts.getType(track1, track2, resoIsNotAnti); // kResoPosdaughTPC_NegdaughTPC + // kResoPosdaughTPC_NegdaughTOF + // kResoPosdaughTPC_NegdaughTPC + // kResoPosdaughTOF_NegdaughTOF as possible output + + auto bitmask = resoCuts.getCutContainer(track1, track2, resoSign); + + /// Get Variables for Output + auto outputReso = tempReso; + auto outputDaugh1 = tempD1; + auto outputDaugh2 = tempD2; + if (!resoIsNotAnti) { + outputReso = tempAntiReso; + outputDaugh1 = tempDA1; + outputDaugh2 = tempDA2; + } + + // fill FDParticles + int postrkId = track1.globalIndex(); + int rowOfPosTrack = -1; + rowOfPosTrack = getRowDaughters(postrkId, tmpIDtrack); + + childIDs[0] = rowOfPosTrack; // should give me the row + childIDs[1] = 0; + outputParts(outputCollision.lastIndex(), + track1.pt(), + track1.eta(), + track1.phi(), + aod::femtodreamparticle::ParticleType::kResoChild, + bitmask[1], + bitmask[2], + track1.dcaXY(), + childIDs, + outputDaugh1.M(), + outputDaugh2.M()); // fill tempFitVar with dcaXY? + const int rowPosTrk = outputParts.lastIndex(); + + int negtrkId = track2.globalIndex(); + int rowOfNegTrack = -1; + rowOfNegTrack = getRowDaughters(negtrkId, tmpIDtrack); + + childIDs[0] = 0; + childIDs[1] = rowOfNegTrack; + outputParts(outputCollision.lastIndex(), + track2.pt(), + track2.eta(), + track2.phi(), + aod::femtodreamparticle::ParticleType::kResoChild, + bitmask[3], + bitmask[4], + track2.dcaXY(), + childIDs, + outputDaugh2.M(), + outputDaugh1.M()); // maybe CPA instead of dcaXY()? as tempFitVar? + const int rowNegTrk = outputParts.lastIndex(); + + // Reso + std::vector indexChildIds = {rowPosTrk, rowNegTrk}; + outputParts(outputCollision.lastIndex(), + outputReso.pt(), + outputReso.eta(), + outputReso.phi(), + type, + bitmask[0], // PIDBit of neg_daugh merged with sign cutBit + bitmask[2], // PIDBit of pos_daugh + -999.f, + indexChildIds, + tempReso.M(), + tempAntiReso.M()); // no TempFitVar !! + // needed? + if (confIsDebug.value) { + fillDebugParticle(track1); // QA for positive daughter + fillDebugParticle(track2); // QA for negative daughter + fillDebugParticle(outputReso); + } + } // for (const auto& track2 : sliceNegdaugh) + } // for (const auto& track1 : slicePosdaugh) + + if (Resonance.confDoLikeSignPhi.value) { + fillLikeSign(slicePosdaugh, resoCuts, Resonance.confPhiDaughterPIDspecies.value, Resonance.confMassQAPhiPart2PID.value); + fillLikeSign(sliceNegdaugh, resoCuts, Resonance.confPhiDaughterPIDspecies.value, Resonance.confMassQAPhiPart2PID.value); + } + } // if (confIsActivatePhi.value) + + if (confIsActivateKStar.value) { + + resoCutsKStar.updateSigmaPIDMax(); + + auto slicePosdaugh = daughter1.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); // o2::framework defined in AnalysisHelper.h + auto sliceNegdaugh = daughter2.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); + + for (const auto& track1 : slicePosdaugh) { + if (!resoCutsKStar.daughterSelectionPos(track1) || !resoCutsKStar.isSelectedMinimalPIDPos(track1, Resonance.confKstarDaughterPIDspecies.value)) { + continue; + } + + for (const auto& track2 : sliceNegdaugh) { + if (!resoCutsKStar.daughterSelectionNeg(track2) || !resoCutsKStar.isSelectedMinimalPIDNeg(track2, Resonance.confKstarDaughterPIDspecies.value)) { + continue; /// loosest cuts for track2 + } + + /// This only works for the case where the mass of opposite charged particles are the same (for example K+/K- have same mass) + float massPart1 = o2::track::PID::getMass(Resonance.confKstarDaughterPIDspecies.value[0]); + float massPart2 = massPart1; + if (Resonance.confKstarDaughterPIDspecies->size() > 1) + massPart2 = o2::track::PID::getMass(Resonance.confKstarDaughterPIDspecies.value[1]); + + /// Resonance + ROOT::Math::PtEtaPhiMVector tempD1(track1.pt(), track1.eta(), track1.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempD2(track2.pt(), track2.eta(), track2.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempReso = tempD1 + tempD2; + /// Anti-resonance + ROOT::Math::PtEtaPhiMVector tempDA1(track1.pt(), track1.eta(), track1.phi(), massPart2); + ROOT::Math::PtEtaPhiMVector tempDA2(track2.pt(), track2.eta(), track2.phi(), massPart1); + ROOT::Math::PtEtaPhiMVector tempAntiReso = tempDA1 + tempDA2; + + bool resoIsNotAnti = true; /// bool for differentianting between particle/antiparticle + float resoSign = 1.; + if ((Resonance.confKstarDaughterPIDspecies->size() > 1) && (Resonance.confKstarDaughterPIDspecies.value[0] != Resonance.confKstarDaughterPIDspecies.value[1])) { + auto [isNormal, WrongCombination] = resoCutsKStar.checkCombination(track1, track2, Resonance.confKstarDaughterPIDspecies.value); + if (WrongCombination) { + continue; + } + if (!isNormal) { + resoSign = -1.; + } + resoIsNotAnti = isNormal; + } + /// Resos, where both daughters have the same PID are defaulted to sign 1. and resoIsNotAnti = true + + if (resoIsNotAnti) { + resoCutsKStar.fillResoQA(track1, track2, true, tempReso.M(), tempAntiReso.M(), Resonance.confKstarDaughterPIDspecies.value, Resonance.confMassQAKstarPart2PID.value); + if (!(tempReso.M() > Resonance.confKstarInvMassLowLimit.value && tempReso.M() < Resonance.confKstarInvMassUpLimit.value)) + continue; + resoCutsKStar.fillMassSelectedQA(tempReso.M(), true); + } else { + resoCutsKStar.fillResoQA(track1, track2, false, tempAntiReso.M(), tempReso.M(), Resonance.confKstarDaughterPIDspecies.value, Resonance.confMassQAKstarPart2PID.value); + if (!(tempAntiReso.M() > Resonance.confKstarInvMassLowLimit.value && tempAntiReso.M() < Resonance.confKstarInvMassUpLimit.value)) + continue; + resoCutsKStar.fillMassSelectedQA(tempAntiReso.M(), false); + } + + resoCutsKStar.fillQA(track1, track2); + + auto type = resoCutsKStar.getType(track1, track2, resoIsNotAnti); // kResoPosdaughTPC_NegdaughTPC + // kResoPosdaughTPC_NegdaughTOF + // kResoPosdaughTPC_NegdaughTPC + // kResoPosdaughTOF_NegdaughTOF as possible output + + auto bitmask = resoCutsKStar.getCutContainer(track1, track2, resoSign); + + /// Get Variables for Output + auto outputReso = tempReso; + auto outputDaugh1 = tempD1; + auto outputDaugh2 = tempD2; + if (!resoIsNotAnti) { + outputReso = tempAntiReso; + outputDaugh1 = tempDA1; + outputDaugh2 = tempDA2; + } + + // fill FDParticles + int postrkId = track1.globalIndex(); + int rowOfPosTrack = -1; + rowOfPosTrack = getRowDaughters(postrkId, tmpIDtrack); + + childIDs[0] = rowOfPosTrack; // should give me the row + childIDs[1] = 0; + outputParts(outputCollision.lastIndex(), + track1.pt(), + track1.eta(), + track1.phi(), + aod::femtodreamparticle::ParticleType::kResoChild, + bitmask[1], + bitmask[2], + track1.dcaXY(), + childIDs, + outputDaugh1.M(), + outputDaugh2.M()); // fill tempFitVar with dcaXY? + const int rowPosTrk = outputParts.lastIndex(); + + int negtrkId = track2.globalIndex(); + int rowOfNegTrack = -1; + rowOfNegTrack = getRowDaughters(negtrkId, tmpIDtrack); + + childIDs[0] = 0; + childIDs[1] = rowOfNegTrack; + outputParts(outputCollision.lastIndex(), + track2.pt(), + track2.eta(), + track2.phi(), + aod::femtodreamparticle::ParticleType::kResoChild, + bitmask[3], + bitmask[4], + track2.dcaXY(), + childIDs, + outputDaugh2.M(), + outputDaugh1.M()); // maybe CPA instead of dcaXY()? as tempFitVar? + const int rowNegTrk = outputParts.lastIndex(); + + // Reso + std::vector indexChildIds = {rowPosTrk, rowNegTrk}; + outputParts(outputCollision.lastIndex(), + outputReso.pt(), + outputReso.eta(), + outputReso.phi(), + type, + bitmask[0], // PIDBit of neg_daugh merged with sign cutBit + bitmask[2], // PIDBit of pos_daugh + -999.f, + indexChildIds, + tempReso.M(), + tempAntiReso.M()); // no TempFitVar !! + // needed? + if (confIsDebug.value) { + fillDebugParticle(track1); // QA for positive daughter + fillDebugParticle(track2); // QA for negative daughter + fillDebugParticle(outputReso); + } + } // for (const auto& track2 : sliceNegdaugh) + } // for (const auto& track1 : slicePosdaugh) + + if (Resonance.confDoLikeSignKstar.value) { + fillLikeSign(slicePosdaugh, resoCutsKStar, Resonance.confKstarDaughterPIDspecies.value, Resonance.confMassQAKstarPart2PID.value); + fillLikeSign(sliceNegdaugh, resoCutsKStar, Resonance.confKstarDaughterPIDspecies.value, Resonance.confMassQAKstarPart2PID.value); + } + } // if (confIsActivateKStar.value) + } // void fillCollisionsAndTracksAndV0(...) + + void + processData(aod::FemtoFullCollision const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks, + o2::aod::V0Datas const& fullV0s, + o2::aod::CascDatas const& fullCascades) + { + // get magnetic field for run + initCcdbMagTrig(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(FemtoDreamProducerTaskReso, processData, + "Provide experimental data", true); + + void + processData_noCentrality(aod::FemtoFullCollisionNoCent const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks, + o2::aod::V0Datas const& fullV0s, + o2::aod::CascDatas const& fullCascades) + { + // get magnetic field for run + initCcdbMagTrig(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(FemtoDreamProducerTaskReso, processData_noCentrality, + "Provide experimental data without centrality information", false); + + void processDataCentPbPb(aod::FemtoFullCollisionCentPbPb const& col, + aod::BCsWithTimestamps const&, + aod::FemtoFullTracks const& tracks, + o2::aod::V0Datas const& fullV0s, + o2::aod::CascDatas const& fullCascades) + { + // get magnetic field for run + initCcdbMagTrig(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(FemtoDreamProducerTaskReso, processDataCentPbPb, + "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 + initCcdbMagTrig(col.bc_as()); + // fill the tables + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + PROCESS_SWITCH(FemtoDreamProducerTaskReso, processMC, "Provide MC data", false); + + void processMCnoCentrality(aod::FemtoFullCollisionNoCentMC 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 + initCcdbMagTrig(col.bc_as()); + // fill the tables + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + PROCESS_SWITCH(FemtoDreamProducerTaskReso, processMCnoCentrality, "Provide MC data without requiring a centrality calibration", false); + + void processMCCentPbPb(aod::FemtoFullCollisionMCCentPbPb 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 + initCcdbMagTrig(col.bc_as()); + // fill the tables + fillCollisionsAndTracksAndV0AndCascade(col, tracks, tracks, fullV0s, fullCascades); + } + PROCESS_SWITCH(FemtoDreamProducerTaskReso, processMCCentPbPb, "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..4e1485f4133 100644 --- a/PWGCF/FemtoDream/Tasks/CMakeLists.txt +++ b/PWGCF/FemtoDream/Tasks/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. # @@ -19,16 +19,41 @@ o2physics_add_dpl_workflow(femtodream-triplet-track-track-track PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-dream-triplet-task-track-track-track-pb-pb + SOURCES femtoDreamTripletTaskTrackTrackTrackPbPb.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femtodream-pair-track-v0 SOURCES femtoDreamPairTaskTrackV0.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-dream-pair-task-v0-reso + SOURCES femtoDreamPairTaskV0Reso.cxx + 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-pair-casdcade-cascade + SOURCES femtodreamPairCascadeCascade.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 COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-dream-triplet-task-track-track-v0-pb-pb + SOURCES femtoDreamTripletTaskTrackTrackV0PbPb.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femtodream-debug-track SOURCES femtoDreamDebugTrack.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore @@ -39,6 +64,16 @@ o2physics_add_dpl_workflow(femtodream-debug-v0 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-dream-debug-reso + SOURCES femtoDreamDebugReso.cxx + 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 @@ -48,3 +83,13 @@ o2physics_add_dpl_workflow(femtodream-hash SOURCES femtoDreamHashTask.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femtodream-pair-v0-v0 + SOURCES femtoDreamPairTaskV0V0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-dream-pair-efficiency + SOURCES femtoDreamPairEfficiency.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamCollisionMasker.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamCollisionMasker.cxx index 63d817a8afc..1cb8c18caef 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamCollisionMasker.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamCollisionMasker.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2023 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. // @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -243,7 +244,7 @@ struct femoDreamCollisionMasker { NegChildPIDTPCBits.at(CollisionMasks::kPartTwo).push_back(option.defaultValue.get()); } } - } else if (device.name.find("femto-dream-triplet-task-track-track-track") != std::string::npos) { + } else if ((device.name.find("femto-dream-triplet-task-track-track-track") != std::string::npos) || (device.name.find("femto-dream-triplet-task-track-track-track-pb-pb") != std::string::npos)) { LOG(info) << "Matched workflow: " << device.name; TaskFinder = CollisionMasks::kTrackTrackTrack; for (auto const& option : device.options) { @@ -263,9 +264,11 @@ 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) { + } else if ((device.name.find("femto-dream-triplet-task-track-track-v0") != std::string::npos) || (device.name.find("femto-dream-triplet-task-track-track-v0-pb-pb") != std::string::npos)) { LOG(info) << "Matched workflow: " << device.name; TaskFinder = CollisionMasks::kTrackTrackV0; for (auto const& option : device.options) { @@ -307,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()); } } } @@ -332,16 +337,18 @@ struct femoDreamCollisionMasker { // 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)) { - // check if we apply pt dependend dca cut - 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; - } + 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 @@ -385,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)) { diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamDebugCascade.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamDebugCascade.cxx new file mode 100644 index 00000000000..54324361ec0 --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamDebugCascade.cxx @@ -0,0 +1,188 @@ +// 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 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/femtoDreamDebugReso.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamDebugReso.cxx new file mode 100644 index 00000000000..3e000bf69fa --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamDebugReso.cxx @@ -0,0 +1,171 @@ +// 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 femtoDreamDebugReso.cxx +/// \brief Tasks that reads the particle tables and fills QA histograms for V0s +/// \author Christopher Klumm, TU München, christopher.klumm@cern.ch + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include "TVector3.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::analysis::femtoDream; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct FemtoDreamDebugReso { + SliceCache cache; + + struct : ConfigurableGroup { + std::string prefix = std::string("resonance"); + + Configurable confResoPDGCode{"confResoPDGCode", 333, "Reso - PDG code"}; + Configurable confResoChildPosPDGCode{"confResoChildPosPDGCode", 321, "Positive Child - PDG code"}; + Configurable confResoChildNegPDGCode{"confResoChildNegPDGCode", 321, "Negative Child- PDG code"}; + + ConfigurableAxis confResoTempFitVarBins{"confResoTempFitVarBins", {300, 0.95, 1.}, "Reso: binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confResoTempFitVarMomentumBins{"confResoTempFitVarMomentumBins", {20, 0.5, 4.05}, "Reso: 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 confTempFitVarMomentum{"confTempFitVarMomentum", 0, "Momentum used for binning: 0 -> pt; 1 -> preco; 2 -> ptpc"}; + ConfigurableAxis confResoInvMassBins{"confResoInvMassBins", {200, 1, 1.2}, "Reso: InvMass binning"}; + + ConfigurableAxis confResoChildTempFitVarMomentumBins{"confResoChildTempFitVarMomentumBins", {600, 0, 6}, "p binning for the p vs Nsigma TPC/TOF plot"}; + ConfigurableAxis confResoChildNsigmaTPCBins{"confResoChildNsigmaTPCBins", {1600, -8, 8}, "binning of Nsigma TPC plot"}; // TPC and TOf seperate doen't make sense really right?? + ConfigurableAxis confResoChildNsigmaTOFBins{"confResoChildNsigmaTOFBins", {3000, -15, 15}, "binning of the Nsigma TOF plot"}; + ConfigurableAxis confResoChildNsigmaTPCTOFBins{"confResoChildNsigmaTPCTOFBins", {1000, 0, 10}, "binning of the Nsigma TPC+TOF plot"}; + ConfigurableAxis confResoChildNsigmaITSBins{"confResoChildNsigmaITSBins", {600, -3, 3}, "binning of the Nsigma ITS plot"}; + + Configurable confChildPosCutBit{"confChildPosCutBit", 4860458, "Positive Child of Reso - Selection bit from cutCulator"}; + Configurable confResoChildPosTPCBit{"confResoChildPosTPCBit", 64, "Positive Child of Reso - PID bit from cutCulator"}; + Configurable confResoChildPosTPCTOFBit{"confResoChildPosTPCTOFBit", 32, "Positive Child of Reso - PID bit from cutCulator"}; + Configurable confChildNegCutBit{"confChildNegCutBit", 4860457, "Negative Child of Reso - PID bit from cutCulator"}; + Configurable confResoChildNegMergedTPCBit{"confResoChildNegMergedTPCBit", 258, "Negative Child of Reso - PID bit from cutCulator"}; // change + Configurable confResoChildNegMergedTPCTOFBit{"confResoChildNegMergedTPCTOFBit", 130, "Negative Child of Reso - PID bit from cutCulator"}; // change + 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"}; + } resonance; + + using FemtoFullParticles = soa::Join; + + Partition partsPhi = (ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTPC_NegdaughTPC), ncheckbit(aod::femtodreamparticle::pidcut, resonance.confResoChildPosTPCBit) && ncheckbit(aod::femtodreamparticle::cut, resonance.confResoChildNegMergedTPCBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTOF_NegdaughTOF), ncheckbit(aod::femtodreamparticle::pidcut, resonance.confResoChildPosTPCTOFBit) && ncheckbit(aod::femtodreamparticle::cut, resonance.confResoChildNegMergedTPCTOFBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTOF_NegdaughTPC), ncheckbit(aod::femtodreamparticle::pidcut, resonance.confResoChildPosTPCTOFBit) && ncheckbit(aod::femtodreamparticle::cut, resonance.confResoChildNegMergedTPCBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTPC_NegdaughTOF), ncheckbit(aod::femtodreamparticle::pidcut, resonance.confResoChildPosTPCBit) && ncheckbit(aod::femtodreamparticle::cut, resonance.confResoChildNegMergedTPCTOFBit), false)); + + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + + Partition partsKstar = (ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoKStarPosdaughTPC_NegdaughTPC), ncheckbit(aod::femtodreamparticle::pidcut, resonance.confResoChildPosTPCBit) && ncheckbit(aod::femtodreamparticle::cut, resonance.confResoChildNegMergedTPCBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoKStarPosdaughTOF_NegdaughTOF), ncheckbit(aod::femtodreamparticle::pidcut, resonance.confResoChildPosTPCTOFBit) && ncheckbit(aod::femtodreamparticle::cut, resonance.confResoChildNegMergedTPCTOFBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoKStarPosdaughTOF_NegdaughTPC), ncheckbit(aod::femtodreamparticle::pidcut, resonance.confResoChildPosTPCTOFBit) && ncheckbit(aod::femtodreamparticle::cut, resonance.confResoChildNegMergedTPCBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoKStarPosdaughTPC_NegdaughTOF), ncheckbit(aod::femtodreamparticle::pidcut, resonance.confResoChildPosTPCBit) && ncheckbit(aod::femtodreamparticle::cut, resonance.confResoChildNegMergedTPCTOFBit), false)); + /// Histogramming + FemtoDreamEventHisto eventHisto; + FemtoDreamParticleHisto posChildHistos; + FemtoDreamParticleHisto negChildHistos; + FemtoDreamParticleHisto motherHistos; + + /// Histogram output + HistogramRegistry eventRegistry{"Event", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resoRegistry{"FullResoQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + posChildHistos.init(&resoRegistry, resonance.confBinmult, resonance.confDummy, resonance.confResoChildTempFitVarMomentumBins, resonance.confDummy, resonance.confDummy, resonance.confChildTempFitVarBins, resonance.confResoChildNsigmaTPCBins, resonance.confResoChildNsigmaTOFBins, resonance.confResoChildNsigmaTPCTOFBins, resonance.confResoChildNsigmaITSBins, resonance.confResoInvMassBins, resonance.confDummy, false, resonance.confResoChildPosPDGCode.value, true); // isDebug == TRUE + negChildHistos.init(&resoRegistry, resonance.confBinmult, resonance.confDummy, resonance.confResoChildTempFitVarMomentumBins, resonance.confDummy, resonance.confDummy, resonance.confChildTempFitVarBins, resonance.confResoChildNsigmaTPCBins, resonance.confResoChildNsigmaTOFBins, resonance.confResoChildNsigmaTPCTOFBins, resonance.confResoChildNsigmaITSBins, resonance.confResoInvMassBins, resonance.confDummy, false, resonance.confResoChildNegPDGCode.value, true); // isDebug == TRUE + motherHistos.init(&resoRegistry, resonance.confBinmult, resonance.confDummy, resonance.confResoTempFitVarMomentumBins, resonance.confDummy, resonance.confDummy, resonance.confResoTempFitVarBins, resonance.confResoChildNsigmaTPCBins, resonance.confResoChildNsigmaTOFBins, resonance.confResoChildNsigmaTPCTOFBins, resonance.confResoChildNsigmaITSBins, resonance.confResoInvMassBins, resonance.confDummy, false, resonance.confResoPDGCode.value, true); // isDebug == TRUE, isMc ==FALSE for all + resoRegistry.add("hArmenterosPodolanski/hArmenterosPodolanskiPlot", "; #alpha; p_{T} (MeV/#it{c})", kTH2F, {{100, -1, 1}, {500, -0.3, 2}}); + } + + /// Porduce QA plots for V0 & Reso selection in FemtoDream framework + template + void processDebug(CollisionType const& col, PartType const& parts, PartitionType const& PartsTwo) + { + + auto groupPartsTwo = PartsTwo.sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); // maybe . instead of -> ?? + for (const auto& part : groupPartsTwo) { + if (!part.has_children()) { + LOG(warn) << " Particle has no children"; + continue; + } + + const auto& posresoChild = parts.iteratorAt(part.index() - 2); + const auto& negresoChild = parts.iteratorAt(part.index() - 1); + if (posresoChild.globalIndex() != part.childrenIds()[0] || negresoChild.globalIndex() != part.childrenIds()[1]) { + continue; + } + if (posresoChild.partType() == uint8_t(aod::femtodreamparticle::ParticleType::kResoChild) && + (posresoChild.cut() & resonance.confChildPosCutBit.value) == resonance.confChildPosCutBit.value && + negresoChild.partType() == uint8_t(aod::femtodreamparticle::ParticleType::kResoChild) && + (negresoChild.cut() & resonance.confChildNegCutBit.value) == resonance.confChildNegCutBit.value) { + + TVector3 pparent(part.px(), part.py(), part.pz()); // Parent momentum (px, py, pz) + TVector3 pplus(posresoChild.px(), posresoChild.py(), posresoChild.pz()); // Daughter 1 momentum (px, py, pz) + TVector3 pminus(negresoChild.px(), negresoChild.py(), negresoChild.pz()); // Daughter 2 momentum (px, py, pz) + + double pLplus = pplus.Dot(pparent) / pparent.Mag(); + double pLminus = pminus.Dot(pparent) / pparent.Mag(); + float alpha = (pLplus - pLminus) / (pLplus + pLminus); + + TVector3 pperp = pplus - (pparent * (pLplus / pparent.Mag())); + double qtarm = pperp.Mag(); + + resoRegistry.fill(HIST("hArmenterosPodolanski/hArmenterosPodolanskiPlot"), alpha, qtarm); + + motherHistos.fillQA(part, static_cast(resonance.confTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + posChildHistos.fillQA(posresoChild, static_cast(resonance.confTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + negChildHistos.fillQA(negresoChild, static_cast(resonance.confTempFitVarMomentum.value), col.multNtr(), col.multV0M()); + } + } + } + + void processPhi(o2::aod::FDCollision const& col, FemtoFullParticles const& parts) + { + processDebug(col, parts, partsPhi); + } + + PROCESS_SWITCH(FemtoDreamDebugReso, processPhi, "Enable processing Phi", true); + + void processKStar(o2::aod::FDCollision const& col, FemtoFullParticles const& parts) + { + processDebug(col, parts, partsKstar); + } + + PROCESS_SWITCH(FemtoDreamDebugReso, processKStar, "Enable processing KStar", false); +}; + +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 efeadded366..77b1c245b67 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamDebugTrack.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamDebugTrack.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -50,6 +50,7 @@ struct femtoDreamDebugTrack { Configurable ConfTrk1_PIDThres{"ConfTrk1_PIDThres", 0.75, "Particle 1 - Read from cutCulator"}; Configurable ConfOptDCACutPtDep{"ConfOptDCACutPtDep", false, "Use pt dependent dca cut"}; + Configurable ConfUseRun2Function{"ConfUseRun2Function", true, "Use Run2 pT dependent DCA selection function"}; 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"}; @@ -61,10 +62,15 @@ 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"}; + Configurable ConfdoCentCut{"ConfdoCentCut", false, "Enable centrality cut"}; + Configurable ConfCentMax{"ConfCentMax", 100., "Upper limit of centrality cut"}; + Configurable ConfCentMin{"ConfCentMin", 0., "Lower limit of centrality cut"}; + using FemtoMCCollisions = Join; using FemtoMCCollision = FemtoMCCollisions::iterator; @@ -77,7 +83,7 @@ struct femtoDreamDebugTrack { (aod::femtodreamparticle::pt < ConfTrk1_maxPt) && (aod::femtodreamparticle::eta > ConfTrk1_minEta) && (aod::femtodreamparticle::eta < ConfTrk1_maxEta) && - ifnode(ConfOptDCACutPtDep, nabs(aod::femtodreamparticle::tempFitVar) < 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f)), + ifnode(ConfOptDCACutPtDep, ifnode(ConfUseRun2Function, nabs(aod::femtodreamparticle::tempFitVar) < 0.0105f + (0.035f / npow(aod::femtodreamparticle::pt, 1.1f)), nabs(aod::femtodreamparticle::tempFitVar) < 0.004f + (0.013f / aod::femtodreamparticle::pt)), (aod::femtodreamparticle::tempFitVar > ConfTrk1_TempFitVarMin) && (aod::femtodreamparticle::tempFitVar < ConfTrk1_TempFitVarMax)); @@ -101,7 +107,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 @@ -109,6 +115,11 @@ struct femtoDreamDebugTrack { void FillDebugHistos(CollisionType& col, PartitionType& groupPartsOne) { eventHisto.fillQA(col); + + if (ConfdoCentCut.value && (col.multV0M() > ConfCentMax || col.multV0M() < ConfCentMin)) { + return; + } + for (auto& part : groupPartsOne) { trackHisto.fillQA(part, static_cast(ConfTempFitVarMomentum.value), col.multNtr(), col.multV0M(), ConfOptCorrelatedPlots); } diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamDebugV0.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamDebugV0.cxx index 9f422751008..69c2aa46bf7 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamDebugV0.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamDebugV0.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -13,21 +13,25 @@ /// \brief Tasks that reads the particle tables and fills QA histograms for V0s /// \author Luca Barioglio, TU München, luca.barioglio@cern.ch -#include -#include -#include +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.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 "DataFormatsParameters/GRPObject.h" +#include "Framework/runDataProcessing.h" + +#include "TVector3.h" + #include "fairlogger/Logger.h" -#include "PWGCF/DataModel/FemtoDerived.h" -#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" -#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include +#include +#include using namespace o2; using namespace o2::analysis::femtoDream; @@ -55,6 +59,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"}; @@ -64,14 +69,16 @@ struct femtoDreamDebugV0 { ConfigurableAxis ConfChildTempFitVarpTBins{"ConfChildTempFitVarpTBins", {20, 0.5, 4.05}, "V0 child: pT binning of the pT vs. TempFitVar plot"}; using FemtoFullParticles = soa::Join; - Partition partsOne = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && (ncheckbit(aod::femtodreamparticle::cut, ConfV01_CutBit)); + Partition partsV0 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && (ncheckbit(aod::femtodreamparticle::cut, ConfV01_CutBit)); Preslice perCol = aod::femtodreamparticle::fdCollisionId; + Partition partsK0Short = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0K0Short)) && (ncheckbit(aod::femtodreamparticle::cut, ConfV01_CutBit)); + /// Histogramming FemtoDreamEventHisto eventHisto; FemtoDreamParticleHisto posChildHistos; FemtoDreamParticleHisto negChildHistos; - FemtoDreamParticleHisto V0Histos; + FemtoDreamParticleHisto motherHistos; /// Histogram output HistogramRegistry EventRegistry{"Event", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -80,15 +87,17 @@ 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); + motherHistos.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 - void process(o2::aod::FDCollision const& col, FemtoFullParticles const& parts) + template + void processDebug(CollisionType const& col, PartType const& parts, PartitionType const& Partition) { - auto groupPartsOne = partsOne->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsOne = Partition.sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); eventHisto.fillQA(col); for (auto& part : groupPartsOne) { if (!part.has_children()) { @@ -111,12 +120,40 @@ 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) { - V0Histos.fillQA(part, static_cast(ConfV0TempFitVarMomentum.value), col.multNtr(), col.multV0M()); + + 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); + + motherHistos.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()); } } } + + void processV0(o2::aod::FDCollision const& col, FemtoFullParticles const& parts) + { + processDebug(col, parts, partsV0); + } + + PROCESS_SWITCH(femtoDreamDebugV0, processV0, "Enable processing Lambda", true); + + void processK0Short(o2::aod::FDCollision const& col, FemtoFullParticles const& parts) + { + processDebug(col, parts, partsK0Short); + } + + PROCESS_SWITCH(femtoDreamDebugV0, processK0Short, "Enable processing K0Short", false); }; WorkflowSpec diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamHashTask.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamHashTask.cxx index cc449887df1..fe0aa6c0e3d 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamHashTask.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamHashTask.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -31,7 +31,7 @@ struct femtoDreamPairHashTask { std::vector CastCfgVtxBins, CastCfgMultBins; - Produces hashes; + Produces hashes; void init(InitContext&) { diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairEfficiency.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairEfficiency.cxx new file mode 100644 index 00000000000..620c7b33839 --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairEfficiency.cxx @@ -0,0 +1,831 @@ +// 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 femtoDreamPairEfficiency.cxx +/// \brief Task to produce dNdeta for pair triggered events +/// \author Anton Riedel, TU München, anton.riedel@cern.ch +/// heaviyly inspiered by phik0shortanalysis.cxx + +#include "PWGCF/FemtoDream/Core/femtoDreamMath.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "TPDGCode.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; +using namespace o2::aod::track; + +struct FemtoDreamPairEfficiency { + + using Collisions = soa::Join; + using RecoCollisions = soa::Join; + using GenCollisions = soa::Join; + + // Defining the type of the tracks for data and MC + using FullTracks = soa::Join; + using FullMCTracks = soa::Join; + // filter for tracks + 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; + + 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) && + ncheckbit(aod::track::trackCutFlag, TrackSelectionDCA) && + ncheckbit(aod::track::trackCutFlag, TrackSelectionFlags::kInAcceptanceTracks); + + using FilteredFullTracks = soa::Filtered; + using FilteredFullMCTracks = soa::Filtered; + + Service pdgDB; + + SliceCache cache; + Preslice perColMc = mcparticle::mcCollisionId; + + struct : ConfigurableGroup { + std::string prefix = std::string("Mode"); + Configurable countPairs{"countPairs", true, "Count Pairs"}; + Configurable countTriplets{"countTriplets", false, "Count Triplets"}; + } mode; + + // Event Selections + struct : ConfigurableGroup { + std::string prefix = std::string("EventSelection"); + Configurable zvtxAbsMax{"zvtxAbsMax", 10.f, "|z-Vertex| max"}; + Configurable offlineCheck{"offlineCheck", true, "Check for Sel8"}; + Configurable etaAbsMax{"etaAbsMax", 0.8f, "Common eta cut for particles in dNdEta distribution"}; + Configurable kstarMax{"kstarMax", 999.f, "Cut on kstar"}; + Configurable q3Max{"q3Max", 999.f, "Cut on Q3"}; + } eventSelection; + + struct : ConfigurableGroup { + std::string prefix = std::string("EventBinning"); + ConfigurableAxis zvtxBinning{"zvtxBinning", {240, -12, 12}, "z-vertex Binning"}; + ConfigurableAxis centBinning{"centBinning", {120, 0, 120}, "Centrality Binning"}; + ConfigurableAxis multBinning{"multBinning", {300, 0, 300}, "Multiplicity Binning"}; + ConfigurableAxis dNdetaBinning{"dNdetaBinning", {200, -1, 1}, "dNdeta Binning"}; + ConfigurableAxis kstarBinning{"kstarBinning", {200, 0, 2}, "dNdeta Binning"}; + ConfigurableAxis pairBinning{"pairBinning", {50, 0, 50}, "pair Binning"}; + } eventBinning; + + // Track 1 selections + struct : ConfigurableGroup { + std::string prefix = std::string("SelectionTrack1"); + Configurable sign{"sign", 1, "Sign of charge"}; + Configurable ptMin{"ptMin", 0.0f, "pt min"}; + Configurable ptMax{"ptMax", 3.0f, "pt max"}; + Configurable etaAbsMax{"etaAbsMax", 0.8f, "|eta| max"}; + Configurable dcazAbsMax{"dcazAbsMax", 0.1f, "|dca_z| max"}; + Configurable useDcaxyPtDepCut{"useDcaxyPtDepCut", true, "|dca_z| max"}; + Configurable tpcClusterMin{"tpcClusterMin", 80.f, "TPC clusters min"}; + Configurable tpcCrossedOverClusterMin{"tpcCrossedOverClusterMin", 0.83f, "TPC clusters/TPC crossed rows min"}; + Configurable tpcCrossedMin{"tpcCrossedMin", 70.f, "TPC crossed rows min"}; + Configurable tpcSharedMax{"tpcSharedMax", 160.f, "TPC shared clusters max"}; + Configurable itsClusterMin{"itsClusterMin", 0.f, "ITS clusters min"}; + Configurable itsIbClusterMin{"itsIbClusterMin", 0.f, "ITS inner barrle min"}; + Configurable pdgCode{"pdgCode", 2212, "PDG code"}; + Configurable pidThreshold{"pidThreshold", 0.75f, "Momentum threshold for PID"}; + Configurable itsNsigmaMax{"itsNsigmaMax", 99.f, "its nsigma max"}; + Configurable tpcNsigmaMax{"tpcNsigmaMax", 3.f, "TPC nsigma max"}; + Configurable tpctofNsigmaMax{"tpctofNsigmaMax", 3.f, "TPCTOC nsigma max"}; + } trackCuts1; + + // Track 2 selections + struct : ConfigurableGroup { + std::string prefix = std::string("SelectionTrack2"); + Configurable sign{"sign", 1, "Sign of charge"}; + Configurable ptMin{"ptMin", 0.0f, "pt min"}; + Configurable ptMax{"ptMax", 3.0f, "pt max"}; + Configurable etaAbsMax{"etaAbsMax", 0.8f, "|eta| max"}; + Configurable dcazAbsMax{"dcazAbsMax", 0.1f, "|dca_z| max"}; + Configurable useDcaxyPtDepCut{"useDcaxyPtDepCut", true, "|dca_z| max"}; + Configurable tpcClusterMin{"tpcClusterMin", 80.f, "TPC clusters min"}; + Configurable tpcCrossedOverClusterMin{"tpcCrossedOverClusterMin", 0.83f, "TPC clusters/TPC crossed rows min"}; + Configurable tpcCrossedMin{"tpcCrossedMin", 70.f, "TPC crossed rows min"}; + Configurable tpcSharedMax{"tpcSharedMax", 160.f, "TPC shared clusters max"}; + Configurable itsClusterMin{"itsClusterMin", 0.f, "ITS clusters min"}; + Configurable itsIbClusterMin{"itsIbClusterMin", 0.f, "ITS inner barrle min"}; + Configurable pdgCode{"pdgCode", 2212, "PDG code"}; + Configurable pidThreshold{"pidThreshold", 0.75f, "Momentum threshold for PID"}; + Configurable itsNsigmaMax{"itsNsigmaMax", 99.f, "its nsigma max"}; + Configurable tpcNsigmaMax{"tpcNsigmaMax", 3.f, "TPC nsigma max"}; + Configurable tpctofNsigmaMax{"tpctofNsigmaMax", 3.f, "TPCTOC nsigma max"}; + } trackCuts2; + + struct : ConfigurableGroup { + std::string prefix = std::string("SelectionTrack3"); + Configurable sign{"sign", 1, "Sign of charge"}; + Configurable ptMin{"ptMin", 0.0f, "pt min"}; + Configurable ptMax{"ptMax", 3.0f, "pt max"}; + Configurable etaAbsMax{"etaAbsMax", 0.8f, "|eta| max"}; + Configurable dcazAbsMax{"dcazAbsMax", 0.1f, "|dca_z| max"}; + Configurable useDcaxyPtDepCut{"useDcaxyPtDepCut", true, "|dca_z| max"}; + Configurable tpcClusterMin{"tpcClusterMin", 80.f, "TPC clusters min"}; + Configurable tpcCrossedOverClusterMin{"tpcCrossedOverClusterMin", 0.83f, "TPC clusters/TPC crossed rows min"}; + Configurable tpcCrossedMin{"tpcCrossedMin", 70.f, "TPC crossed rows min"}; + Configurable tpcSharedMax{"tpcSharedMax", 160.f, "TPC shared clusters max"}; + Configurable itsClusterMin{"itsClusterMin", 0.f, "ITS clusters min"}; + Configurable itsIbClusterMin{"itsIbClusterMin", 0.f, "ITS inner barrle min"}; + Configurable pdgCode{"pdgCode", 2212, "PDG code"}; + Configurable pidThreshold{"pidThreshold", 0.75f, "Momentum threshold for PID"}; + Configurable itsNsigmaMax{"itsNsigmaMax", 99.f, "its nsigma max"}; + Configurable tpcNsigmaMax{"tpcNsigmaMax", 3.f, "TPC nsigma max"}; + Configurable tpctofNsigmaMax{"tpctofNsigmaMax", 3.f, "TPCTOC nsigma max"}; + } trackCuts3; + + HistogramRegistry dataEventHist{"dataEventHist", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry mcEventHist{"mcEventHist", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + HistogramRegistry dataTrackHist{"dataTrackHist", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + void init(InitContext&) + { + + if (mode.countPairs.value && mode.countTriplets.value) { + LOG(fatal) << "We cannot count pairs and triplets at the same time. Turn one of the off."; + } + + dataEventHist.add("hDataEventSelection", "hDataEventSelection", kTH1F, {{6, -0.5f, 5.5f}}); + dataEventHist.get(HIST("hDataEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + dataEventHist.get(HIST("hDataEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + dataEventHist.get(HIST("hDataEventSelection"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + dataEventHist.get(HIST("hDataEventSelection"))->GetXaxis()->SetBinLabel(4, "INEL>0 cut"); + dataEventHist.get(HIST("hDataEventSelection"))->GetXaxis()->SetBinLabel(5, "With at least a pair"); + dataEventHist.get(HIST("hDataEventSelection"))->GetXaxis()->SetBinLabel(6, "With at least a lowkstar pair"); + + // Event information + dataEventHist.add("hDataVertexZ", "hVertexZ", kTH1F, {eventBinning.zvtxBinning}); + dataEventHist.add("hDataMultiplicity", "hMultiplicity", kTH1F, {eventBinning.multBinning}); + dataEventHist.add("hDataCentrality", "Centrality", kTH1F, {eventBinning.centBinning}); + + // Eta distribution for dN/deta values estimation in Data + dataEventHist.add("hDataCentralityVsEtaDistribtion", "Eta vs multiplicity in Data", kTH2F, {eventBinning.centBinning, eventBinning.dNdetaBinning}); + + dataTrackHist.add("Track1/pt", "Track 1 pt", kTH1F, {{600, 0, 6}}); + dataTrackHist.add("Track1/eta", "Track 1 eta", kTH1F, {{200, -1, 1}}); + dataTrackHist.add("Track1/phi", "Track 1 phi", kTH1F, {{720, 0, o2::constants::math::TwoPI}}); + dataTrackHist.add("Track1/tpcCluster", "Track 1 cluster", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track1/tpcCrossed", "Track 1 crossed rows", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track1/tpcShared", "Track 1 cluster shared", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track1/itsCluster", "Track 1 its cluster", kTH1F, {{7, 0, 7}}); + dataTrackHist.add("Track1/itsIbCluster", "Track 1 its cluster inner barrel", kTH1F, {{3, 0, 3}}); + dataTrackHist.add("Track1/itsNsigma", "Track 1 nsigma its", kTH2F, {{600, 0, 6}, {1000, -5, 5}}); + dataTrackHist.add("Track1/tpcNsigma", "Track 1 nsigma tpc", kTH2F, {{600, 0, 6}, {1000, -5, 5}}); + dataTrackHist.add("Track1/tpctofNsigma", "Track 1 nsigma tpctof", kTH2F, {{600, 0, 6}, {500, 0, 5}}); + + dataTrackHist.add("Track2/pt", "Track 2 pt", kTH1F, {{600, 0, 6}}); + dataTrackHist.add("Track2/eta", "Track 2 eta", kTH1F, {{200, -1, 1}}); + dataTrackHist.add("Track2/phi", "Track 2 phi", kTH1F, {{720, 0, o2::constants::math::TwoPI}}); + dataTrackHist.add("Track2/tpcCluster", "Track 2 cluster", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track2/tpcCrossed", "Track 2 crossed rows", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track2/tpcShared", "Track 2 cluster shared", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track2/itsCluster", "Track 2 its cluster", kTH1F, {{0, 0, 7}}); + dataTrackHist.add("Track2/itsIbCluster", "Track 2 its cluster inner barrel", kTH1F, {{3, 0, 3}}); + dataTrackHist.add("Track2/itsNsigma", "Track 2 nsigma its", kTH2F, {{600, 0, 6}, {1000, -5, 5}}); + dataTrackHist.add("Track2/tpcNsigma", "Track 2 nsigma tpc", kTH2F, {{600, 0, 6}, {1000, -5, 5}}); + dataTrackHist.add("Track2/tpctofNsigma", "Track 2 nsigma tpctof", kTH2F, {{600, 0, 6}, {500, 0, 5}}); + + if (mode.countTriplets) { + dataTrackHist.add("Track3/pt", "Track 3 pt", kTH1F, {{600, 0, 6}}); + dataTrackHist.add("Track3/eta", "Track 3 eta", kTH1F, {{200, -1, 1}}); + dataTrackHist.add("Track3/phi", "Track 3 phi", kTH1F, {{720, 0, o2::constants::math::TwoPI}}); + dataTrackHist.add("Track3/tpcCluster", "Track 3 cluster", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track3/tpcCrossed", "Track 3 crossed rows", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track3/tpcShared", "Track 3 cluster shared", kTH1F, {{160, 0, 160}}); + dataTrackHist.add("Track3/itsCluster", "Track 3 its cluster", kTH1F, {{0, 0, 7}}); + dataTrackHist.add("Track3/itsIbCluster", "Track 3 its cluster inner barrel", kTH1F, {{3, 0, 3}}); + dataTrackHist.add("Track3/itsNsigma", "Track 3 nsigma its", kTH2F, {{600, 0, 6}, {1000, -5, 5}}); + dataTrackHist.add("Track3/tpcNsigma", "Track 3 nsigma tpc", kTH2F, {{600, 0, 6}, {1000, -5, 5}}); + dataTrackHist.add("Track3/tpctofNsigma", "Track 3 nsigma tpctof", kTH2F, {{600, 0, 6}, {500, 0, 5}}); + } + + mcEventHist.add("hRecoEventSelection", "hRecoEventSelection", kTH1F, {{7, -0.5f, 6.5f}}); + mcEventHist.get(HIST("hRecoEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + mcEventHist.get(HIST("hRecoEventSelection"))->GetXaxis()->SetBinLabel(2, "Sel8 cut"); + mcEventHist.get(HIST("hRecoEventSelection"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + mcEventHist.get(HIST("hRecoEventSelection"))->GetXaxis()->SetBinLabel(4, "INEL>0 cut"); + mcEventHist.get(HIST("hRecoEventSelection"))->GetXaxis()->SetBinLabel(5, "With at least a gen coll"); + mcEventHist.get(HIST("hRecoEventSelection"))->GetXaxis()->SetBinLabel(6, "With at least a pair/triplet"); + mcEventHist.get(HIST("hRecoEventSelection"))->GetXaxis()->SetBinLabel(7, "With at least a lowkstar pair/lowq3 triplet"); + + mcEventHist.add("hGenEventSelection", "hGenEventSelection", kTH1F, {{6, -0.5f, 5.5f}}); + mcEventHist.get(HIST("hGenEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + mcEventHist.get(HIST("hGenEventSelection"))->GetXaxis()->SetBinLabel(2, "posZ cut"); + mcEventHist.get(HIST("hGenEventSelection"))->GetXaxis()->SetBinLabel(3, "INEL>0 cut"); + mcEventHist.get(HIST("hGenEventSelection"))->GetXaxis()->SetBinLabel(4, "With at least a pair/triplet"); + mcEventHist.get(HIST("hGenEventSelection"))->GetXaxis()->SetBinLabel(5, "With at least a lowkstar pair/lowq3 triplet"); + mcEventHist.get(HIST("hGenEventSelection"))->GetXaxis()->SetBinLabel(6, "With at least a reco coll"); + + // MC Event information for Rec and Gen + mcEventHist.add("hRecoMcVertexZ", "McVertexZ of reconstructed collision", kTH1F, {eventBinning.zvtxBinning}); + mcEventHist.add("hRecoMcMultiplicity", "McMultiplicity of reconstructed collision", kTH1F, {eventBinning.multBinning}); + mcEventHist.add("hRecoMcCentrality", "McCentrality of reconstructed collision", kTH1F, {eventBinning.centBinning}); + mcEventHist.add("hRecoMcKstar", "Mck* in reconstructed collision", kTH1F, {eventBinning.kstarBinning}); + mcEventHist.add("hRecoMcNumberOfPair", "McNumber of pairs in reconstructed collision", kTH1F, {eventBinning.pairBinning}); + + mcEventHist.add("hRecoMcCentralityVsEtaDistribution", "McCentrality vs Eta in Reco", kTH2F, {eventBinning.centBinning, eventBinning.dNdetaBinning}); + mcEventHist.add("hRecoMcCentralityVsMcEtaDistribution", "McCentrality vs McEta in Reco (Check)", kTH2F, {eventBinning.centBinning, eventBinning.dNdetaBinning}); + + mcEventHist.add("hGenMcVertexZ", "McVertex of generated collision", kTH1F, {eventBinning.zvtxBinning}); + mcEventHist.add("hGenMcMultiplicity", "McMultiplicity fo generated collision", kTH1F, {eventBinning.multBinning}); + mcEventHist.add("hGenMcCentrality", "McCentrality of generated collision", kTH1F, {eventBinning.centBinning}); + mcEventHist.add("hGenMcKstar", "Mckk* of generated collision", kTH1F, {eventBinning.kstarBinning}); + mcEventHist.add("hGenMcNumberOfPair", "McNumber of pairs in generated collision", kTH1F, {eventBinning.pairBinning}); + + mcEventHist.add("hGenMcCentralityWithAllAssoc", "McCentrality in all associated collision", kTH1F, {eventBinning.centBinning}); + mcEventHist.add("hGenMcCentralityWithAssoc", "McCentrality in associated collision", kTH1F, {eventBinning.centBinning}); + mcEventHist.add("hGenMcCentralityVsMcEtaDistribution", "McCentrality vs McdNdEta in generated collision", kTH2F, {eventBinning.centBinning, eventBinning.dNdetaBinning}); + mcEventHist.add("hGenMcCentralityVsMcEtaDistributionWithAllAssoc", "McCentrality vs McdNdEta in all associated collisions", kTH2F, {eventBinning.centBinning, eventBinning.dNdetaBinning}); + mcEventHist.add("hGenMcCentralityVsMcEtaDistributionWithAssoc", "McCentrality vs McdNdEta in associated collisions", kTH2F, {eventBinning.centBinning, eventBinning.dNdetaBinning}); + } + + int pairsFound = 0; + std::vector vecKstar{}; + + int tripletsFound = 0; + std::vector vecq3{}; + + template + bool checkRecoTrackSelections(const T1& track, const T2& sel) + { + if (track.sign() != sel.sign.value) { + return false; + } + if (track.pt() < sel.ptMin.value || track.pt() > sel.ptMax.value) { + return false; + } + if (std::fabs(track.eta()) > sel.etaAbsMax.value) { + return false; + } + if (sel.useDcaxyPtDepCut.value && std::fabs(track.dcaXY()) > (0.0105 + (0.035 / std::powf(track.pt(), 1.1f)))) { + return false; + } + if (std::fabs(track.dcaZ()) > sel.dcazAbsMax.value) { + return false; + } + if (track.tpcNClsFound() < sel.tpcClusterMin.value) { + return false; + } + if (track.tpcNClsCrossedRows() < sel.tpcCrossedMin.value) { + return false; + } + if (track.tpcNClsShared() > sel.tpcSharedMax.value) { + return false; + } + if (track.itsNCls() < sel.itsClusterMin.value) { + return false; + } + if (track.itsNClsInnerBarrel() < sel.itsIbClusterMin.value) { + return false; + } + return true; + } + + template + std::array getNSigmaValues(const T& track, int pdgCode) + { + std::array nsigma; + switch (std::abs(pdgCode)) { + case kPiPlus: + nsigma[0] = track.itsNSigmaPi(); + nsigma[1] = track.tpcNSigmaPi(); + nsigma[2] = track.tofNSigmaPi(); + break; + case kKPlus: + nsigma[0] = track.itsNSigmaKa(); + nsigma[1] = track.tpcNSigmaKa(); + nsigma[2] = track.tofNSigmaKa(); + break; + case kProton: + nsigma[0] = track.itsNSigmaPr(); + nsigma[1] = track.tpcNSigmaPr(); + nsigma[2] = track.tofNSigmaPr(); + break; + case constants::physics::kDeuteron: + nsigma[0] = track.itsNSigmaDe(); + nsigma[1] = track.tpcNSigmaDe(); + nsigma[2] = track.tofNSigmaDe(); + break; + default: + LOG(fatal) << "PDG code " << pdgCode << " is not supported"; + } + return nsigma; + } + + template + bool checkRecoTrackPidSelections(const T1& track, const T2& sel) + { + auto nsigma = getNSigmaValues(track, sel.pdgCode.value); + if (track.p() < sel.pidThreshold.value) { + if (std::fabs(nsigma[1]) > sel.tpcNsigmaMax.value || std::fabs(nsigma[0]) > sel.itsNsigmaMax.value) { + return false; + } + } else { + if (std::hypot(nsigma[1], nsigma[2]) > sel.tpctofNsigmaMax.value) { + return false; + } + } + return true; + } + + template + bool checkEventSelections(const T& col, bool qa) + { + if constexpr (!isMc) { + if (qa) { + dataEventHist.fill(HIST("hDataEventSelection"), 0); // all collisins + } + if (!col.sel8()) { + return false; + } + if (qa) { + dataEventHist.fill(HIST("hDataEventSelection"), 1); // sel8 collisions + } + if (std::fabs(col.posZ()) > eventSelection.zvtxAbsMax.value) { + return false; + } + if (qa) { + dataEventHist.fill(HIST("hDataEventSelection"), 2); // vertex-Z selected + } + if (!col.isInelGt0()) { + return false; + } + if (qa) { + dataEventHist.fill(HIST("hDataEventSelection"), 3); // INEL>0 collisions + } + } else { + if (qa) { + mcEventHist.fill(HIST("hRecoEventSelection"), 0); // all collisions + } + if (!col.sel8()) { + return false; + } + if (qa) { + mcEventHist.fill(HIST("hRecoEventSelection"), 1); // sel8 collisions + } + if (std::fabs(col.posZ()) > eventSelection.zvtxAbsMax.value) { + return false; + } + if (qa) { + mcEventHist.fill(HIST("hRecoEventSelection"), 2); // vertex-Z selected + } + if (!col.isInelGt0()) { + return false; + } + if (qa) { + mcEventHist.fill(HIST("hRecoEventSelection"), 3); // INEL>0 collisions + } + } + return true; + } + + template + int countRecoPairs(const T& tracks) + { + int pairs = 0; + for (auto track1 = tracks.begin(); track1 != tracks.end(); track1++) { + if (!checkRecoTrackSelections(track1, trackCuts1) || !checkRecoTrackPidSelections(track1, trackCuts1)) { + continue; + } + for (auto track2 = track1 + 1; track2 != tracks.end(); track2++) { + if (!checkRecoTrackSelections(track2, trackCuts2) || !checkRecoTrackPidSelections(track2, trackCuts2)) { + continue; + } + + auto nsigma1 = getNSigmaValues(track1, trackCuts1.pdgCode.value); + dataTrackHist.fill(HIST("Track1/pt"), track1.pt()); + dataTrackHist.fill(HIST("Track1/eta"), track1.eta()); + dataTrackHist.fill(HIST("Track1/phi"), track1.phi()); + dataTrackHist.fill(HIST("Track1/tpcCluster"), track1.tpcNClsFound()); + dataTrackHist.fill(HIST("Track1/tpcCrossed"), track1.tpcNClsCrossedRows()); + dataTrackHist.fill(HIST("Track1/tpcShared"), track1.tpcNClsShared()); + dataTrackHist.fill(HIST("Track1/itsCluster"), track1.itsNCls()); + dataTrackHist.fill(HIST("Track1/itsIbCluster"), track1.itsNClsInnerBarrel()); + dataTrackHist.fill(HIST("Track1/itsNsigma"), track1.p(), nsigma1[0]); + dataTrackHist.fill(HIST("Track1/tpcNsigma"), track1.p(), nsigma1[1]); + dataTrackHist.fill(HIST("Track1/tpctofNsigma"), track1.p(), std::hypot(nsigma1[1], nsigma1[2])); + + auto nsigma2 = getNSigmaValues(track2, trackCuts2.pdgCode.value); + dataTrackHist.fill(HIST("Track2/pt"), track2.pt()); + dataTrackHist.fill(HIST("Track2/eta"), track2.eta()); + dataTrackHist.fill(HIST("Track2/phi"), track2.phi()); + dataTrackHist.fill(HIST("Track2/tpcCluster"), track2.tpcNClsFound()); + dataTrackHist.fill(HIST("Track2/tpcCrossed"), track2.tpcNClsCrossedRows()); + dataTrackHist.fill(HIST("Track2/tpcShared"), track2.tpcNClsShared()); + dataTrackHist.fill(HIST("Track2/itsCluster"), track2.itsNCls()); + dataTrackHist.fill(HIST("Track2/itsIbCluster"), track2.itsNClsInnerBarrel()); + dataTrackHist.fill(HIST("Track2/itsNsigma"), track2.p(), nsigma2[0]); + dataTrackHist.fill(HIST("Track2/tpcNsigma"), track2.p(), nsigma2[1]); + dataTrackHist.fill(HIST("Track2/tpctofNsigma"), track1.p(), std::hypot(nsigma2[1], nsigma2[2])); + + pairs++; + + vecKstar.push_back(femtoDream::FemtoDreamMath::getkstar(track1, femtoDream::getMass(trackCuts1.pdgCode.value), track2, femtoDream::getMass(trackCuts2.pdgCode.value))); + } + } + return pairs; + } + + template + int countRecoTriplets(const T& tracks) + { + int triplets = 0; + for (auto track1 = tracks.begin(); track1 != tracks.end(); track1++) { + if (!checkRecoTrackSelections(track1, trackCuts1) || !checkRecoTrackPidSelections(track1, trackCuts1)) { + continue; + } + for (auto track2 = track1 + 1; track2 != tracks.end(); track2++) { + if (!checkRecoTrackSelections(track2, trackCuts2) || !checkRecoTrackPidSelections(track2, trackCuts2)) { + continue; + } + + for (auto track3 = track2 + 1; track3 != tracks.end(); track3++) { + if (!checkRecoTrackSelections(track3, trackCuts3) || !checkRecoTrackPidSelections(track3, trackCuts3)) { + continue; + } + + auto nsigma1 = getNSigmaValues(track1, trackCuts1.pdgCode.value); + dataTrackHist.fill(HIST("Track1/pt"), track1.pt()); + dataTrackHist.fill(HIST("Track1/eta"), track1.eta()); + dataTrackHist.fill(HIST("Track1/phi"), track1.phi()); + dataTrackHist.fill(HIST("Track1/tpcCluster"), track1.tpcNClsFound()); + dataTrackHist.fill(HIST("Track1/tpcCrossed"), track1.tpcNClsCrossedRows()); + dataTrackHist.fill(HIST("Track1/tpcShared"), track1.tpcNClsShared()); + dataTrackHist.fill(HIST("Track1/itsCluster"), track1.itsNCls()); + dataTrackHist.fill(HIST("Track1/itsIbCluster"), track1.itsNClsInnerBarrel()); + dataTrackHist.fill(HIST("Track1/itsNsigma"), track1.p(), nsigma1[0]); + dataTrackHist.fill(HIST("Track1/tpcNsigma"), track1.p(), nsigma1[1]); + dataTrackHist.fill(HIST("Track1/tpctofNsigma"), track1.p(), std::hypot(nsigma1[1], nsigma1[2])); + + auto nsigma2 = getNSigmaValues(track2, trackCuts2.pdgCode.value); + dataTrackHist.fill(HIST("Track2/pt"), track2.pt()); + dataTrackHist.fill(HIST("Track2/eta"), track2.eta()); + dataTrackHist.fill(HIST("Track2/phi"), track2.phi()); + dataTrackHist.fill(HIST("Track2/tpcCluster"), track2.tpcNClsFound()); + dataTrackHist.fill(HIST("Track2/tpcCrossed"), track2.tpcNClsCrossedRows()); + dataTrackHist.fill(HIST("Track2/tpcShared"), track2.tpcNClsShared()); + dataTrackHist.fill(HIST("Track2/itsCluster"), track2.itsNCls()); + dataTrackHist.fill(HIST("Track2/itsIbCluster"), track2.itsNClsInnerBarrel()); + dataTrackHist.fill(HIST("Track2/itsNsigma"), track2.p(), nsigma2[0]); + dataTrackHist.fill(HIST("Track2/tpcNsigma"), track2.p(), nsigma2[1]); + dataTrackHist.fill(HIST("Track2/tpctofNsigma"), track2.p(), std::hypot(nsigma2[1], nsigma2[2])); + + auto nsigma3 = getNSigmaValues(track3, trackCuts3.pdgCode.value); + dataTrackHist.fill(HIST("Track3/pt"), track3.pt()); + dataTrackHist.fill(HIST("Track3/eta"), track3.eta()); + dataTrackHist.fill(HIST("Track3/phi"), track3.phi()); + dataTrackHist.fill(HIST("Track3/tpcCluster"), track3.tpcNClsFound()); + dataTrackHist.fill(HIST("Track3/tpcCrossed"), track3.tpcNClsCrossedRows()); + dataTrackHist.fill(HIST("Track3/tpcShared"), track3.tpcNClsShared()); + dataTrackHist.fill(HIST("Track3/itsCluster"), track3.itsNCls()); + dataTrackHist.fill(HIST("Track3/itsIbCluster"), track3.itsNClsInnerBarrel()); + dataTrackHist.fill(HIST("Track3/itsNsigma"), track3.p(), nsigma2[0]); + dataTrackHist.fill(HIST("Track3/tpcNsigma"), track3.p(), nsigma2[1]); + dataTrackHist.fill(HIST("Track3/tpctofNsigma"), track3.p(), std::hypot(nsigma3[1], nsigma3[2])); + + triplets++; + + vecq3.push_back(femtoDream::FemtoDreamMath::getQ3(track1, femtoDream::getMass(trackCuts1.pdgCode.value), track2, femtoDream::getMass(trackCuts2.pdgCode.value), track3, femtoDream::getMass(trackCuts3.pdgCode.value))); + } + } + } + return triplets; + } + + template + int countGenPairs(const T& tracks) + { + int pairs = 0; + for (auto track1 = tracks.begin(); track1 != tracks.end(); track1++) { + if (!track1.isPhysicalPrimary() || + track1.pdgCode() != trackCuts1.pdgCode.value || + track1.pt() < trackCuts1.ptMin.value || + track1.pt() > trackCuts1.ptMax.value || + std::fabs(track1.eta()) > trackCuts1.etaAbsMax.value) { + continue; + } + for (auto track2 = track1 + 1; track2 != tracks.end(); track2++) { + if (!track2.isPhysicalPrimary() || + track2.pdgCode() != trackCuts2.pdgCode.value || + track2.pt() < trackCuts2.ptMin.value || + track2.pt() > trackCuts2.ptMax.value || + std::fabs(track2.eta()) > trackCuts2.etaAbsMax.value) { + continue; + } + vecKstar.push_back(femtoDream::FemtoDreamMath::getkstar(track1, femtoDream::getMass(trackCuts1.pdgCode.value), track2, femtoDream::getMass(trackCuts2.pdgCode.value))); + pairs++; + } + } + return pairs; + } + + template + int countGenTriplets(const T& tracks) + { + int triplets = 0; + for (auto track1 = tracks.begin(); track1 != tracks.end(); track1++) { + if (!track1.isPhysicalPrimary() || + track1.pdgCode() != trackCuts1.pdgCode.value || + track1.pt() < trackCuts1.ptMin.value || + track1.pt() > trackCuts1.ptMax.value || + std::fabs(track1.eta()) > trackCuts1.etaAbsMax.value) { + continue; + } + for (auto track2 = track1 + 1; track2 != tracks.end(); track2++) { + if (!track2.isPhysicalPrimary() || + track2.pdgCode() != trackCuts2.pdgCode.value || + track2.pt() < trackCuts2.ptMin.value || + track2.pt() > trackCuts2.ptMax.value || + std::fabs(track2.eta()) > trackCuts2.etaAbsMax.value) { + continue; + } + for (auto track3 = track2 + 1; track3 != tracks.end(); track3++) { + if (!track3.isPhysicalPrimary() || + track3.pdgCode() != trackCuts3.pdgCode.value || + track3.pt() < trackCuts3.ptMin.value || + track3.pt() > trackCuts3.ptMax.value || + std::fabs(track3.eta()) > trackCuts3.etaAbsMax.value) { + continue; + } + vecq3.push_back(femtoDream::FemtoDreamMath::getQ3(track1, femtoDream::getMass(trackCuts1.pdgCode.value), track2, femtoDream::getMass(trackCuts2.pdgCode.value), track3, femtoDream::getMass(trackCuts3.pdgCode.value))); + triplets++; + } + } + } + return triplets; + } + + void processdNdetaData(Collisions::iterator const& collision, FilteredFullTracks const& tracks) + { + if (!checkEventSelections(collision, true)) + return; + + auto tracksWithItsPid = soa::Attach(tracks); + + if (mode.countPairs.value) { + vecKstar.clear(); + pairsFound = countRecoPairs(tracksWithItsPid); + if (pairsFound == 0) { + return; + } + } + if (mode.countTriplets.value) { + vecq3.clear(); + tripletsFound = countRecoTriplets(tracksWithItsPid); + if (tripletsFound == 0) { + return; + } + } + + dataEventHist.fill(HIST("hDataEventSelection"), 4); // found a pair + + if (mode.countPairs.value) { + if (*std::min_element(vecKstar.begin(), vecKstar.end()) > eventSelection.kstarMax) { + return; + } + } + + if (mode.countTriplets.value) { + if (*std::min_element(vecq3.begin(), vecq3.end()) > eventSelection.q3Max) { + return; + } + } + + dataEventHist.fill(HIST("hDataEventSelection"), 5); // found a lowkstar pair + + float centrality = collision.centFT0M(); + + dataEventHist.fill(HIST("hDataVertexZ"), collision.posZ()); + dataEventHist.fill(HIST("hDataMultiplicity"), collision.multNTracksPV()); + dataEventHist.fill(HIST("hDataCentrality"), centrality); + + for (const auto& track : tracks) + dataEventHist.fill(HIST("hDataCentralityVsEtaDistribtion"), centrality, track.eta()); + } + + PROCESS_SWITCH(FemtoDreamPairEfficiency, processdNdetaData, "Process function for dN/deta values in MCReco", true); + + void processdNdetaMCReco(RecoCollisions::iterator const& collision, FilteredFullMCTracks const& McTracks, GenCollisions const&, McParticles const& mcParticles) + { + if (!checkEventSelections(collision, true)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + mcEventHist.fill(HIST("hRecoEventSelection"), 4); + + const auto& mcCollision = collision.mcCollision_as(); + auto mcParticlesThisColl = mcParticles.sliceByCached(mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + + if (mode.countPairs.value) { + vecKstar.clear(); + pairsFound = countGenPairs(mcParticlesThisColl); + if (pairsFound == 0) { + return; + } + } + if (mode.countTriplets.value) { + vecq3.clear(); + tripletsFound = countGenTriplets(mcParticlesThisColl); + if (tripletsFound == 0) { + return; + } + } + + mcEventHist.fill(HIST("hRecoEventSelection"), 5); + + if (mode.countPairs.value) { + if (*std::min_element(vecKstar.begin(), vecKstar.end()) > eventSelection.kstarMax) { + return; + } + } + + if (mode.countTriplets.value) { + if (*std::min_element(vecq3.begin(), vecq3.end()) > eventSelection.q3Max) { + return; + } + } + + mcEventHist.fill(HIST("hRecoEventSelection"), 6); + + float genCentrality = mcCollision.centFT0M(); + + mcEventHist.fill(HIST("hRecoMcVertexZ"), mcCollision.posZ()); + mcEventHist.fill(HIST("hRecoMcMultiplicity"), mcCollision.multMCNParticlesEta08()); + mcEventHist.fill(HIST("hRecoMcCentrality"), mcCollision.centFT0M()); + mcEventHist.fill(HIST("hRecoMcNumberOfPair"), vecKstar.size()); + for (const auto& kstar : vecKstar) { + mcEventHist.fill(HIST("hRecoMcKstar"), kstar); + } + + for (const auto& track : McTracks) { + if (!track.has_mcParticle()) + continue; + auto mcTrack = track.mcParticle_as(); + if (!mcTrack.isPhysicalPrimary() || std::fabs(mcTrack.eta()) > eventSelection.etaAbsMax.value) + continue; + + mcEventHist.fill(HIST("hRecoMcCentralityVsEtaDistribution"), genCentrality, mcTrack.eta()); + } + + for (const auto& mcParticle : mcParticlesThisColl) { + if (!mcParticle.isPhysicalPrimary() || std::fabs(mcParticle.eta()) > eventSelection.etaAbsMax.value) { + continue; + } + auto pdgTrack = pdgDB->GetParticle(mcParticle.pdgCode()); + if (pdgTrack == nullptr) { + continue; + } + if (pdgTrack->Charge() == 0) { + continue; + } + mcEventHist.fill(HIST("hRecoMcCentralityVsMcEtaDistribution"), genCentrality, mcParticle.eta()); + } + } + PROCESS_SWITCH(FemtoDreamPairEfficiency, processdNdetaMCReco, "Process function for dN/deta values in MCReco", true); + + void processdNdetaMCGen(GenCollisions::iterator const& mcCollision, soa::SmallGroups const& collisions, McParticles const& mcParticles) + { + mcEventHist.fill(HIST("hGenEventSelection"), 0); + if (std::fabs(mcCollision.posZ()) > eventSelection.zvtxAbsMax.value) { + return; + } + mcEventHist.fill(HIST("hGenEventSelection"), 1); + if (!pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { + return; + } + mcEventHist.fill(HIST("hGenEventSelection"), 2); + + if (mode.countPairs.value) { + vecKstar.clear(); + pairsFound = countGenPairs(mcParticles); + if (pairsFound == 0) { + return; + } + } + if (mode.countTriplets.value) { + vecq3.clear(); + tripletsFound = countGenTriplets(mcParticles); + if (tripletsFound == 0) { + return; + } + } + + mcEventHist.fill(HIST("hGenEventSelection"), 3); + + if (mode.countPairs.value) { + if (*std::min_element(vecKstar.begin(), vecKstar.end()) > eventSelection.kstarMax) { + return; + } + } + + if (mode.countTriplets.value) { + if (*std::min_element(vecq3.begin(), vecq3.end()) > eventSelection.q3Max) { + return; + } + } + + mcEventHist.fill(HIST("hGenEventSelection"), 4); + mcEventHist.fill(HIST("hGenMcVertexZ"), mcCollision.posZ()); + mcEventHist.fill(HIST("hGenMcMultiplicity"), mcCollision.multMCNParticlesEta08()); + mcEventHist.fill(HIST("hGenMcCentrality"), mcCollision.centFT0M()); + mcEventHist.fill(HIST("hGenMcNumberOfPair"), vecKstar.size()); + + for (const auto& kstar : vecKstar) { + mcEventHist.fill(HIST("hGenMcKstar"), kstar); + } + + float genCentrality = mcCollision.centFT0M(); + uint64_t numberAssocCollisions = 0; + + for (const auto& collision : collisions) { + if (checkEventSelections(collision, false)) { + mcEventHist.fill(HIST("hGenMcCentralityWithAllAssoc"), genCentrality); + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary() || std::abs(mcParticle.eta()) > eventSelection.etaAbsMax.value) + continue; + auto pdgTrack = pdgDB->GetParticle(mcParticle.pdgCode()); + if (pdgTrack == nullptr) + continue; + if (pdgTrack->Charge() == 0) + continue; + mcEventHist.fill(HIST("hGenMcCentralityVsMcEtaDistributionWithAllAssoc"), genCentrality, mcParticle.eta()); + } + numberAssocCollisions++; + } + } + + if (numberAssocCollisions > 0) { + mcEventHist.fill(HIST("hGenMcCentralityWithAssoc"), genCentrality); + mcEventHist.fill(HIST("hGenEventSelection"), 5); + } + + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary() || std::abs(mcParticle.eta()) > eventSelection.etaAbsMax.value) + continue; + + auto pdgTrack = pdgDB->GetParticle(mcParticle.pdgCode()); + if (pdgTrack == nullptr) { + continue; + } + if (pdgTrack->Charge() == 0) { + continue; + } + + mcEventHist.fill(HIST("hGenMcCentralityVsMcEtaDistribution"), genCentrality, mcParticle.eta()); + if (numberAssocCollisions > 0) { + mcEventHist.fill(HIST("hGenMcCentralityVsMcEtaDistributionWithAssoc"), genCentrality, mcParticle.eta()); + } + } + } + PROCESS_SWITCH(FemtoDreamPairEfficiency, processdNdetaMCGen, "Process function for dN/deta values in MCReco", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackCascade.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackCascade.cxx new file mode 100644 index 00000000000..9dbdf1b2a8b --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackCascade.cxx @@ -0,0 +1,397 @@ +// 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 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 "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainer.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include + +#include +#include +#include +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.globalIndex() - 3); + const auto& negChild = parts.iteratorAt(p2.globalIndex() - 2); + const auto& bachChild = parts.iteratorAt(p2.globalIndex() - 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 44c1bb69990..f2100431efd 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackTrack.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -15,27 +15,31 @@ /// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de /// \author Anton Riedel, TU München, anton.riedel@tum.de -#include -#include -#include -#include "TRandom3.h" +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamCollisionSelection.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainer.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/Configurable.h" -#include "Framework/Expressions.h" +#include "Framework/runDataProcessing.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" +#include "TRandom3.h" + +#include +#include +#include +#include using namespace o2::aod; using namespace o2::soa; @@ -75,15 +79,40 @@ struct femtoDreamPairTaskTrackTrack { Configurable MultMax{"MultMax", 99999, "Maximum Multiplicity (MultNtr)"}; Configurable MultPercentileMin{"MultPercentileMin", 0, "Maximum Multiplicity Percentile"}; Configurable MultPercentileMax{"MultPercentileMax", 100, "Minimum Multiplicity Percentile"}; + Configurable SphericityMin{"SphericityMin", 0, "Minimum event sphericity"}; } EventSel; - Filter EventMultiplicity = aod::femtodreamcollision::multNtr >= EventSel.MultMin && aod::femtodreamcollision::multNtr <= EventSel.MultMax; + Filter EventMultiplicity = aod::femtodreamcollision::multNtr >= EventSel.MultMin && aod::femtodreamcollision::multNtr <= EventSel.MultMax && aod::femtodreamcollision::sphericity >= EventSel.SphericityMin; Filter EventMultiplicityPercentile = aod::femtodreamcollision::multV0M >= EventSel.MultPercentileMin && aod::femtodreamcollision::multV0M <= EventSel.MultPercentileMax; + /// qn&event_plane separator + FemtoDreamCollisionSelection epCalculator; + struct : ConfigurableGroup { + std::string prefix = std::string("EPCal"); + Configurable do1DFemto{"do1DFemto", false, "Do 1D femtoscopy"}; + Configurable do3DFemto{"do3DFemto", false, "Do 3D femtoscopy"}; + Configurable fillFlowQA{"fillFlowQA", false, "Fill QA histos for flow/event-plane related observables"}; + Configurable storeEvtTrkInfo{"storeEvtTrkInfo", false, "Fill info of track1 and track2 while pariing in divided qn bins"}; + Configurable doQnSeparation{"doQnSeparation", false, "Do qn separation"}; + Configurable doEPReClibForMixing{"doEPReClibForMixing", false, "While mixing, using respective event plane for participating particles azimuthal angle caulculation"}; + Configurable> qnBinSeparator{"qnBinSeparator", std::vector{-999.f, -999.f, -999.f}, "Qn bin separator"}; + Configurable numQnBins{"numQnBins", 10, "Number of qn bins"}; + Configurable qnBinMin{"qnBinMin", 0, "Number of qn bins"}; + Configurable centMax{"centMax", 100.f, "Evt sel: Maximum Centrality cut"}; + Configurable centBinWidth{"centBinWidth", 1.f, "Centrality bin length for qn separator"}; + ConfigurableAxis DKout{"DKout", {500, -2., 2.}, "binning DKout for the 3-D femtoscopy plot: R_out(LCMS) vs mT vs multiplicity percentile vs qnBin vs pait phi wrt EP (set <> to true)"}; + ConfigurableAxis DKside{"DKside", {500, -2., 2.}, "binning DKside for the 3-D femtoscopy plot: R_side(LCMS) vs mT vs multiplicity percentile vs qnBin vs pait phi wrt EP (set <> to true)"}; + ConfigurableAxis DKlong{"DKlong", {500, -2., 2.}, "binning DKlong for the 3-D femtoscopy plot: R_long(LCMS) vs mT vs multiplicity percentile vs qnBin vs pait phi wrt EP (set <> to true)"}; + ConfigurableAxis qnBins{"qnBins", {10, 0, 10}, "binning of qn interval"}; + ConfigurableAxis pairPhiBins{"pairPhiBins", {12, 0., TMath::Pi()}, "binning of pair phi"}; + } EPCal; + using FilteredCollisions = soa::Filtered; using FilteredCollision = FilteredCollisions::iterator; using FilteredMCCollisions = soa::Filtered>; using FilteredMCCollision = FilteredMCCollisions::iterator; + using FilteredQnCollisions = soa::Filtered>; + using FilteredQnCollision = FilteredQnCollisions::iterator; using FilteredMaskedCollisions = soa::Filtered>; using FilteredMaskedCollision = FilteredMaskedCollisions::iterator; @@ -211,19 +240,28 @@ struct femtoDreamPairTaskTrackTrack { ConfigurableAxis MultMixBins{"MultMixBins", {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 MultPercentileMixBins{"MultPercentileMixBins", {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 percentile"}; ConfigurableAxis VztxMixBins{"VztxMixBins", {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 QnMixBins{"QnMixBins", {VARIABLE_WIDTH, 0.50f, 68.50f, 100.50f, 126.50f, 151.50f, 176.50f, 203.50f, 232.50f, 269.50f, 322.50f, 833.50f}, "Mixing bins - qn-value"}; + ConfigurableAxis EPMixBins{"EPMixBins", {VARIABLE_WIDTH, 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., 110., 120., 130., 140., 150., 160., 170., 180.}, "Mixing bins - event plane (deg)"}; Configurable Depth{"Depth", 5, "Number of events for mixing"}; - Configurable Policy{"Policy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; + Configurable Policy{"Policy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both, 3: multipliciy percentile and qn value, 4: multipliciy percentile and event plane"}; } Mixing; ColumnBinningPolicy colBinningMult{{Mixing.VztxMixBins, Mixing.MultMixBins}, true}; ColumnBinningPolicy colBinningMultPercentile{{Mixing.VztxMixBins, Mixing.MultPercentileMixBins}, true}; ColumnBinningPolicy colBinningMultMultPercentile{{Mixing.VztxMixBins, Mixing.MultMixBins, Mixing.MultPercentileMixBins}, true}; + ColumnBinningPolicy colBinningMultPercentileqn{{Mixing.VztxMixBins, Mixing.MultPercentileMixBins, Mixing.QnMixBins}, true}; + ColumnBinningPolicy colBinningMultPercentileEP{{Mixing.VztxMixBins, Mixing.MultPercentileMixBins, Mixing.EPMixBins}, true}; FemtoDreamContainer sameEventCont; FemtoDreamContainer mixedEventCont; FemtoDreamPairCleaner pairCleaner; FemtoDreamDetaDphiStar pairCloseRejectionSE; FemtoDreamDetaDphiStar pairCloseRejectionME; + + // Container for correlation functions in devided qn bins + FemtoDreamContainer sameEventQnCont; + FemtoDreamContainer mixedEventQnCont; + /// Histogram output HistogramRegistry Registry{"Output", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -231,13 +269,21 @@ struct femtoDreamPairTaskTrackTrack { 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}; + colBinningMultPercentileqn = {{Mixing.VztxMixBins, Mixing.MultPercentileMixBins, Mixing.QnMixBins}, true}; + colBinningMultPercentileEP = {{Mixing.VztxMixBins, Mixing.MultPercentileMixBins, Mixing.EPMixBins}, true}; + if (Option.RandomizePair.value) { random = new TRandom3(0); } 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.IsMC, Track1.PDGCode); + 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(&Registry, 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(&Registry, @@ -260,6 +306,32 @@ struct femtoDreamPairTaskTrackTrack { pairCloseRejectionME.init(&Registry, &Registry, Option.CPRdeltaPhiMax.value, Option.CPRdeltaEtaMax.value, Option.CPRPlotPerRadii.value, 2, Option.CPROld.value); } + if (EPCal.do1DFemto) { + sameEventQnCont.init_EP(&Registry, + Binning4D.kstar, Binning4D.mT, Binning4D.multPercentile, EPCal.doQnSeparation ? EPCal.qnBins : EPCal.pairPhiBins, EPCal.doQnSeparation ? "qnBin" : "#phi_{pair}-#Psi_{EP} (rad)", + Option.IsMC, Option.HighkstarCut); + mixedEventQnCont.init_EP(&Registry, + Binning4D.kstar, Binning4D.mT, Binning4D.multPercentile, EPCal.doQnSeparation ? EPCal.qnBins : EPCal.pairPhiBins, EPCal.doQnSeparation ? "qnBin" : "#phi_{pair}-#Psi_{EP} (rad)", + Option.IsMC, Option.HighkstarCut); + sameEventQnCont.setPDGCodes(Track1.PDGCode, Track2.PDGCode); + mixedEventQnCont.setPDGCodes(Track1.PDGCode, Track2.PDGCode); + if (EPCal.fillFlowQA) { + epCalculator.initEPQA(&Registry); + } + } + + if (EPCal.do3DFemto) { + sameEventQnCont.init_3Dqn(&Registry, EPCal.DKout, EPCal.DKside, EPCal.DKlong, + Binning4D.mT, Binning4D.multPercentile, Option.IsMC, EPCal.qnBins, EPCal.pairPhiBins); + mixedEventQnCont.init_3Dqn(&Registry, EPCal.DKout, EPCal.DKside, EPCal.DKlong, + Binning4D.mT, Binning4D.multPercentile, Option.IsMC, EPCal.qnBins, EPCal.pairPhiBins); + sameEventQnCont.setPDGCodes(Track1.PDGCode, Track2.PDGCode); + mixedEventQnCont.setPDGCodes(Track1.PDGCode, Track2.PDGCode); + if (EPCal.fillFlowQA) { + epCalculator.initEPQA(&Registry); + } + } + // get bit for the collision mask std::bitset<8 * sizeof(femtodreamcollision::BitMaskType)> mask; int index = 0; @@ -299,7 +371,11 @@ struct femtoDreamPairTaskTrackTrack { } } if ((doprocessSameEvent && doprocessSameEventMasked) || + (doprocessSameEvent && doprocessSameEventEP) || + (doprocessSameEventMasked && doprocessSameEventEP) || (doprocessMixedEvent && doprocessMixedEventMasked) || + (doprocessMixedEvent && doprocessMixedEventEP) || + (doprocessMixedEventMasked && doprocessMixedEventEP) || (doprocessSameEventMC && doprocessSameEventMCMasked) || (doprocessMixedEventMC && doprocessMixedEventMCMasked)) { LOG(fatal) << "Normal and masked processing cannot be activated simultaneously!"; @@ -610,8 +686,176 @@ struct femtoDreamPairTaskTrackTrack { } } PROCESS_SWITCH(femtoDreamPairTaskTrackTrack, processMixedEventMCMasked, "Enable processing mixed events MC with masked collisions", false); -}; + /// This function processes the same event in divided qn bins + /// col.multV0M() get the event centrality from ft0c for PbPb data + template + void doSameEventEP(PartitionType SliceTrk1, PartitionType SliceTrk2, PartType parts, Collision col) + { + if (EPCal.storeEvtTrkInfo) { + for (auto& part : SliceTrk1) { + trackHistoPartOne.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + + if (!Option.SameSpecies.value) { + for (auto& part : SliceTrk2) { + trackHistoPartTwo.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + } + } + + auto myEP = TMath::DegToRad() * col.eventPlane(); + int myqnBin = -999; + if (EPCal.doQnSeparation || EPCal.do3DFemto) { + myqnBin = epCalculator.myqnBin(col.multV0M(), EPCal.centMax, EPCal.fillFlowQA, EPCal.qnBinSeparator, col.qnVal(), EPCal.numQnBins, EPCal.centBinWidth); + if (myqnBin < EPCal.qnBinMin || myqnBin > EPCal.numQnBins) { + myqnBin = -999; + } + } + + if (EPCal.fillFlowQA) { + epCalculator.fillEPQA(col.multV0M(), col.sphericity(), col.qnVal(), col.eventPlane()); + } + + /// Now build the combinations + float rand = 0.; + if (Option.SameSpecies.value) { + for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(SliceTrk1, SliceTrk2))) { + if (Option.CPROn.value) { + if (pairCloseRejectionSE.isClosePair(p1, p2, parts, col.magField())) { + continue; + } + } + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (Option.RandomizePair.value) { + rand = random->Rndm(); + } + if (rand <= 0.5) { + if (EPCal.do1DFemto) { + sameEventQnCont.setPair_EP(p1, p2, col.multV0M(), EPCal.doQnSeparation, EPCal.doQnSeparation ? myqnBin + 0.f : myEP); + } + if (EPCal.do3DFemto) { + sameEventQnCont.setPair_3Dqn(p1, p2, col.multV0M(), Option.SameSpecies.value, myqnBin + 0.f, myEP); + } + } else { + if (EPCal.do1DFemto) { + sameEventQnCont.setPair_EP(p2, p1, col.multV0M(), EPCal.doQnSeparation, EPCal.doQnSeparation ? myqnBin + 0.f : myEP); + } + if (EPCal.do3DFemto) { + sameEventQnCont.setPair_3Dqn(p2, p1, col.multV0M(), Option.SameSpecies.value, myqnBin + 0.f, myEP); + } + } + } + } else { + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceTrk2))) { + if (Option.CPROn.value) { + if (pairCloseRejectionSE.isClosePair(p1, p2, parts, col.magField())) { + continue; + } + } + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (EPCal.do1DFemto) { + sameEventQnCont.setPair_EP(p1, p2, col.multV0M(), EPCal.doQnSeparation, EPCal.doQnSeparation ? myqnBin + 0.f : myEP); + } + if (EPCal.do3DFemto) { + sameEventQnCont.setPair_3Dqn(p1, p2, col.multV0M(), Option.SameSpecies.value, myEP, myqnBin); + } + } + } + } + + /// process function for to call doSameEventEP with Data + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processSameEventEP(FilteredQnCollision& col, o2::aod::FDParticles& parts) + { + if (EPCal.storeEvtTrkInfo) { + fillCollision(col); + } + auto SliceTrk1 = PartitionTrk1->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto SliceTrk2 = PartitionTrk2->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + if (SliceTrk1.size() == 0 && SliceTrk2.size() == 0) { + return; + } + if (EPCal.do1DFemto || EPCal.do3DFemto) { + doSameEventEP(SliceTrk1, SliceTrk2, parts, col); + } + } + PROCESS_SWITCH(femtoDreamPairTaskTrackTrack, processSameEventEP, "Enable processing same event wrt azimuthal angle and event-plane ", false); + + template + void doMixedEvent_NotMaskedEP(CollisionType& cols, PartType& parts, PartitionType& part1, PartitionType& part2, BinningType policy) + { + for (auto const& [collision1, collision2] : soa::selfCombinations(policy, Mixing.Depth.value, -1, cols, cols)) { + auto SliceTrk1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto SliceTrk2 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + if (SliceTrk1.size() == 0 || SliceTrk2.size() == 0) { + continue; + } + + auto myEP_event1 = TMath::DegToRad() * collision1.eventPlane(); + auto myEP_event2 = TMath::DegToRad() * collision2.eventPlane(); + + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceTrk1, SliceTrk2))) { + if (Option.CPROn.value) { + if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { + continue; + } + } + if (EPCal.doEPReClibForMixing) { + if (EPCal.do1DFemto) { + if (EPCal.doQnSeparation) + mixedEventQnCont.setPair_EP(p1, p2, collision1.multV0M(), EPCal.doQnSeparation, 0.f); + else + mixedEventQnCont.setPair_EP(p1, p2, collision1.multV0M(), EPCal.doQnSeparation, myEP_event1, myEP_event2); + } + if (EPCal.do3DFemto) { + mixedEventQnCont.setPair_3Dqn(p1, p2, collision1.multV0M(), Option.SameSpecies.value, 0.f, myEP_event1, myEP_event2); + } + } else { + if (EPCal.do1DFemto) + mixedEventQnCont.setPair_EP(p1, p2, collision1.multV0M(), EPCal.doQnSeparation, EPCal.doQnSeparation ? 0.f : myEP_event1); + if (EPCal.do3DFemto) { + mixedEventQnCont.setPair_3Dqn(p1, p2, collision1.multV0M(), Option.SameSpecies.value, 0.f, myEP_event1); + } + } + } + } + }; + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoDreamParticleTable + void processMixedEventEP(FilteredQnCollisions& cols, o2::aod::FDParticles& parts) + { + switch (Mixing.Policy.value) { + case femtodreamcollision::kMult: + doMixedEvent_NotMaskedEP(cols, parts, PartitionTrk1, PartitionTrk2, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent_NotMaskedEP(cols, parts, PartitionTrk1, PartitionTrk2, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent_NotMaskedEP(cols, parts, PartitionTrk1, PartitionTrk2, colBinningMultMultPercentile); + break; + case femtodreamcollision::kMultPercentileQn: + doMixedEvent_NotMaskedEP(cols, parts, PartitionTrk1, PartitionTrk2, colBinningMultPercentileqn); + break; + case femtodreamcollision::kMultPercentileEP: + doMixedEvent_NotMaskedEP(cols, parts, PartitionTrk1, PartitionTrk2, colBinningMultPercentileEP); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(femtoDreamPairTaskTrackTrack, processMixedEventEP, "Enable processing mixed events wrt azimuthal angle and event-plane", false); +}; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackV0.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackV0.cxx index 7b6fe7ec1ab..7798f3d59c8 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackV0.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskTrackV0.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -16,6 +16,7 @@ #include #include #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" @@ -227,11 +228,16 @@ struct femtoDreamPairTaskTrackV0 { void init(InitContext& context) { + // 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.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.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, 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, false, 0); + 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, diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskV0Reso.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskV0Reso.cxx new file mode 100644 index 00000000000..572c6ea45c6 --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskV0Reso.cxx @@ -0,0 +1,490 @@ +// 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 femtoDreamPairTaskV0Reso.cxx +/// \brief Tasks that reads the track tables used for the pairing and builds pairs of two tracks +/// \author Christopher Klumm, TU München, christopher.klumm@cern.ch +/// \author Anton Riedel, TU München, anton.riedel@cern.ch +/// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@cern.ch + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainer.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include "TRandom3.h" + +#include +#include +#include +#include + +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 FemtoDreamPairTaskV0Reso { + SliceCache cache; + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + + /// Histogramming for Event + FemtoDreamEventHisto eventHisto; + + FemtoDreamContainer sameEventCont; + FemtoDreamContainer mixedEventCont; + // FemtoDreamPairCleaner pairCleaner; + FemtoDreamDetaDphiStar pairCloseRejectionSE; + FemtoDreamDetaDphiStar pairCloseRejectionME; + + using FilteredMCCollisions = soa::Filtered>; + using FilteredMCCollision = FilteredMCCollisions::iterator; + + using FDMCParts = soa::Join; + using FDMCPart = FDMCParts::iterator; + + /// 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", true, "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", false, "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", true, "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; + + /// Binning configurables + struct : ConfigurableGroup { + std::string prefix = std::string("Binning"); + ConfigurableAxis tempFitVarReso{"tempFitVarReso", {300, 0.9, 1}, "binning of the TempFitVar in the pT vs. TempFitVar plot (V0)"}; + ConfigurableAxis tempFitVarV0{"tempFitVarV0", {300, 0.9, 1}, "binning of the TempFitVar in the pT vs. TempFitVar plot (Reso))"}; + ConfigurableAxis tempFitVarV0Child{"tempFitVarV0Child", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (V0 child)"}; + ConfigurableAxis tempFitVarResoChild{"tempFitVarResoChild", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (Reso child)"}; + ConfigurableAxis invMass{"invMass", {1500, 0.9, 1.13}, "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 pTReso{"pTReso", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (Reso)"}; + ConfigurableAxis pTV0Child{"pTV0Child", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (V0 Child)"}; + ConfigurableAxis pTResoChild{"pTResoChild", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot (Reso Child)"}; + 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{"policy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; + } Mixing; + + /// particle 1 (V01), Λ + struct : ConfigurableGroup { + std::string prefix = std::string("V01"); + Configurable pdgCode{"pdgCode", 3122, "PDG code of particle 1 (V0)"}; + Configurable cutBit{"cutBit", 7518, "Selection bit for particle 1 (V0)"}; + Configurable childPosCutBit{"childPosCutBit", 210, "Selection bit for positive child of V01"}; + Configurable childPosTPCBit{"childPosTPCBit", 64, "PID TPC bit for positive child of V01"}; + Configurable childNegCutBit{"childNegCutBit", 209, "Selection bit for negative child of V01"}; + Configurable childNegTPCBit{"childNegTPCBit", 256, "PID TPC bit for negative child of V01"}; + + Configurable invMassMin{"invMassMin", 1.08, "Minimum invariant mass of Partricle 1 (particle) (V0)"}; + Configurable invMassMax{"invMassMax", 1.3, "Maximum invariant mass of Partricle 1 (particle) (V0)"}; + Configurable invMassAntiMin{"invMassAntiMin", 0., "Minimum invariant mass of Partricle 1 (antiparticle) (V0)"}; // should be the same as for Lambda... + Configurable invMassAntiMax{"invMassAntiMax", 999., "Maximum invariant mass of Partricle 1 (antiparticle) (V0)"}; + + Configurable ptMin{"ptMin", 0., "Minimum pT of Partricle 1 (V0)"}; + Configurable ptMax{"ptMax", 999., "Maximum pT of Partricle 1 (V0)"}; + Configurable etaMin{"etaMin", -10., "Minimum eta of Partricle 1 (V0)"}; + Configurable etaMax{"etaMax", 10., "Maximum eta of Partricle 1 (V0)"}; + } V01; + + /// particle 2, (Resonance) (needs implementation phi in cut bit ) + struct : ConfigurableGroup { + std::string prefix = std::string("Reso2"); + Configurable pdgCode{"pdgCode", 333, "PDG code of particle 2 (V0)"}; + + Configurable invMassMin{"invMassMin", 0.86, "Minimum invariant mass of Partricle 2 (particle) (V0)"}; // phi values for inv mass + Configurable invMassMax{"invMassMax", 1.3, "Maximum invariant mass of Partricle 2 (particle) (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)"}; // change values + Configurable etaMax{"etaMax", 10., "Maximum eta of Partricle 2 (V0)"}; // change values + + Configurable daughPosCutBit{"daughPosCutBit", 2401446, "Selection bit for positive child of V02"}; // K+ + Configurable daughPosTPCBit{"daughPosTPCBit", 4096, "PID TPC bit for positive child of V02"}; + Configurable daughPosTPCTOFBit{"daughPosTPCTOFBit", 2048, "PID TOF bit for positive child of V02"}; + Configurable daughNegCutBit{"daughNegCutBit", 2401445, "Selection bit for negative child of V02"}; // K- + Configurable daughNegMergedTPCBit{"daughNegMergedTPCBit", 16386, "PID TPC bit for negative child of V02"}; + Configurable daughNegMergedTPCTOFBit{"daughNegMergedTPCTOFBit", 8194, "PID TOF bit for negative child of V02"}; + + Configurable dcaXYPar0{"dcaXYPar0", 0.004, "first parameter for pt dependent dcaXY cut"}; + Configurable dcaXYPar1{"dcaXYPar1", 0.013, "second parameter for pt dependent dcaXY cut"}; + } Reso2; + + /// Partition for particle Lambda + Partition partitionV01 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && + ((aod::femtodreamparticle::cut & V01.cutBit) == V01.cutBit) && + (aod::femtodreamparticle::pt > V01.ptMin) && + (aod::femtodreamparticle::pt < V01.ptMax) && + (aod::femtodreamparticle::eta > V01.etaMin) && + (aod::femtodreamparticle::eta < V01.etaMax) && + (aod::femtodreamparticle::mLambda > V01.invMassMin) && + (aod::femtodreamparticle::mLambda < V01.invMassMax) && + (aod::femtodreamparticle::mAntiLambda > V01.invMassAntiMin) && + (aod::femtodreamparticle::mAntiLambda < V01.invMassAntiMax); + + /// Partition for particle Phi + Partition partitionReso2 = (ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTPC_NegdaughTPC), ncheckbit(aod::femtodreamparticle::pidcut, Reso2.daughPosTPCBit) && ncheckbit(aod::femtodreamparticle::cut, Reso2.daughNegMergedTPCBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTOF_NegdaughTOF), ncheckbit(aod::femtodreamparticle::pidcut, Reso2.daughPosTPCTOFBit) && ncheckbit(aod::femtodreamparticle::cut, Reso2.daughNegMergedTPCTOFBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTOF_NegdaughTPC), ncheckbit(aod::femtodreamparticle::pidcut, Reso2.daughPosTPCTOFBit) && ncheckbit(aod::femtodreamparticle::cut, Reso2.daughNegMergedTPCBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTPC_NegdaughTOF), ncheckbit(aod::femtodreamparticle::pidcut, Reso2.daughPosTPCBit) && ncheckbit(aod::femtodreamparticle::cut, Reso2.daughNegMergedTPCTOFBit), false)) && + (aod::femtodreamparticle::pt < Reso2.ptMax) && + (aod::femtodreamparticle::eta > Reso2.etaMin) && + (aod::femtodreamparticle::eta < Reso2.etaMax) && + (aod::femtodreamparticle::mLambda > Reso2.invMassMin) && + (aod::femtodreamparticle::mLambda < Reso2.invMassMax); + + /// Partitions for K0Short and KStar + + /// Partition for particle K0Short + Partition partitionK0Short1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && + ((aod::femtodreamparticle::cut & V01.cutBit) == V01.cutBit) && + (aod::femtodreamparticle::pt > V01.ptMin) && + (aod::femtodreamparticle::pt < V01.ptMax) && + (aod::femtodreamparticle::eta > V01.etaMin) && + (aod::femtodreamparticle::eta < V01.etaMax) && + (aod::femtodreamparticle::mLambda > V01.invMassMin) && + (aod::femtodreamparticle::mLambda < V01.invMassMax) && + (aod::femtodreamparticle::mAntiLambda > V01.invMassAntiMin) && + (aod::femtodreamparticle::mAntiLambda < V01.invMassAntiMax); + + /// Partition for particle KStar + Partition partitionKStar2 = (ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTPC_NegdaughTPC), ncheckbit(aod::femtodreamparticle::pidcut, Reso2.daughPosTPCBit) && ncheckbit(aod::femtodreamparticle::cut, Reso2.daughNegMergedTPCBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTOF_NegdaughTOF), ncheckbit(aod::femtodreamparticle::pidcut, Reso2.daughPosTPCTOFBit) && ncheckbit(aod::femtodreamparticle::cut, Reso2.daughNegMergedTPCTOFBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTOF_NegdaughTPC), ncheckbit(aod::femtodreamparticle::pidcut, Reso2.daughPosTPCTOFBit) && ncheckbit(aod::femtodreamparticle::cut, Reso2.daughNegMergedTPCBit), false) || + ifnode(aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kResoPosdaughTPC_NegdaughTOF), ncheckbit(aod::femtodreamparticle::pidcut, Reso2.daughPosTPCBit) && ncheckbit(aod::femtodreamparticle::cut, Reso2.daughNegMergedTPCTOFBit), false)) && + (aod::femtodreamparticle::pt < Reso2.ptMax) && + (aod::femtodreamparticle::eta > Reso2.etaMin) && + (aod::femtodreamparticle::eta < Reso2.etaMax) && + (aod::femtodreamparticle::mLambda > Reso2.invMassMin) && + (aod::femtodreamparticle::mLambda < Reso2.invMassMax); + + ColumnBinningPolicy colBinningMult{{Mixing.binVztx, Mixing.binMult}, true}; + ColumnBinningPolicy colBinningMultPercentile{{Mixing.binVztx, Mixing.binMultPercentile}, true}; + ColumnBinningPolicy colBinningMultMultPercentile{{Mixing.binVztx, Mixing.binMult, Mixing.binMultPercentile}, true}; + + Filter eventMultiplicity = aod::femtodreamcollision::multNtr >= EventSel.multMin && aod::femtodreamcollision::multNtr <= EventSel.multMax; + Filter eventMultiplicityPercentile = aod::femtodreamcollision::multV0M >= EventSel.multPercentileMin && aod::femtodreamcollision::multV0M <= EventSel.multPercentileMax; + + using FilteredCollisions = soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + + /// Histogramming for particle 1 + FemtoDreamParticleHisto v0HistoPartOne; + FemtoDreamParticleHisto posChildHistos; + FemtoDreamParticleHisto negChildHistos; + + /// Histogramming for particle 2 + FemtoDreamParticleHisto resoHistoPartTwo; + FemtoDreamParticleHisto resoposChildHistos; + FemtoDreamParticleHisto resonegChildHistos; + + /// Histogram output + HistogramRegistry registry{"Output", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resoRegistry{"ResodcaXY", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) // InitContext& context + { + + // 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(®istry, Option.isMC); + + v0HistoPartOne.init(®istry, Binning.multTempFit, Option.dummy, Binning.pTTrack, Option.dummy, Option.dummy, Binning.tempFitVarV0, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.isMC, V01.pdgCode); + posChildHistos.init(®istry, 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(®istry, 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); + + resoHistoPartTwo.init(®istry, Binning.multTempFit, Option.dummy, Binning.pTReso, Option.dummy, Option.dummy, Binning.tempFitVarReso, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Binning.invMass, Option.dummy, Option.isMC, Reso2.pdgCode); + resoposChildHistos.init(®istry, Binning.multTempFit, Option.dummy, Binning.pTResoChild, Option.dummy, Option.dummy, Binning.tempFitVarResoChild, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.dummy, false, 0); + resonegChildHistos.init(®istry, Binning.multTempFit, Option.dummy, Binning.pTResoChild, Option.dummy, Option.dummy, Binning.tempFitVarResoChild, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.dummy, false, 0); + + sameEventCont.init(®istry, + 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, Binning.invMass); + + sameEventCont.setPDGCodes(V01.pdgCode, Reso2.pdgCode); + mixedEventCont.init(®istry, + 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, Binning.invMass); + + mixedEventCont.setPDGCodes(V01.pdgCode, Reso2.pdgCode); + + resoRegistry.add("Before/DCAxyPt", "DCAxyvsPt", HistType::kTH2F, {{100, -0.8, 0.8}, {100, 0.0, 4}}); + resoRegistry.add("After/DCAxyPt", "DCAxyvsPt", HistType::kTH2F, {{100, -0.8, 0.8}, {100, 0.0, 4}}); + + // pairCleaner.init(®istry); + if (Option.cPROn.value) { + pairCloseRejectionSE.init(®istry, ®istry, Option.cPRdeltaPhiMax.value, Option.cPRdeltaEtaMax.value, Option.cPRPlotPerRadii.value, 1, Option.cPROld.value); + pairCloseRejectionME.init(®istry, ®istry, Option.cPRdeltaPhiMax.value, Option.cPRdeltaEtaMax.value, Option.cPRPlotPerRadii.value, 2, Option.cPROld.value, 99, true); + } + } + + template + void doSameEvent(sliceType1& sliceV01, sliceType2& sliceReso2, TableTracks const& parts, Collision const& col) + { + /// Histogramming for same event missing + + for (const auto& v0 : sliceV01) { + const auto& posChild = parts.iteratorAt(v0.index() - 2); + const auto& negChild = parts.iteratorAt(v0.index() - 1); + + if (((posChild.cut() & V01.childPosCutBit) == V01.childPosCutBit) && + ((posChild.pidcut() & V01.childPosTPCBit) == V01.childPosTPCBit) && + ((negChild.cut() & V01.childNegCutBit) == V01.childNegCutBit) && + ((negChild.pidcut() & V01.childNegTPCBit) == V01.childNegTPCBit)) { + v0HistoPartOne.fillQA(v0, 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()); + } + } + + for (const auto& reso : sliceReso2) { + const auto& posresoChild = parts.iteratorAt(reso.index() - 2); + const auto& negresoChild = parts.iteratorAt(reso.index() - 1); + + resoRegistry.fill(HIST("Before/DCAxyPt"), posresoChild.tempFitVar(), posresoChild.pt()); + resoRegistry.fill(HIST("Before/DCAxyPt"), negresoChild.tempFitVar(), negresoChild.pt()); + + if ((std::abs(posresoChild.tempFitVar()) > Reso2.dcaXYPar0 + Reso2.dcaXYPar1 * std::pow(posresoChild.pt(), -1)) || (std::abs(negresoChild.tempFitVar()) > Reso2.dcaXYPar0 + Reso2.dcaXYPar1 * std::pow(negresoChild.pt(), -1))) { + continue; + } + + resoRegistry.fill(HIST("After/DCAxyPt"), posresoChild.tempFitVar(), posresoChild.pt()); + resoRegistry.fill(HIST("After/DCAxyPt"), negresoChild.tempFitVar(), negresoChild.pt()); + + if (ncheckbit(posresoChild.cut(), Reso2.daughPosCutBit)) { + resoposChildHistos.fillQA(posresoChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + + if (ncheckbit(negresoChild.cut(), Reso2.daughNegCutBit)) { + resonegChildHistos.fillQA(negresoChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + + if (((posresoChild.cut() & Reso2.daughPosCutBit) == Reso2.daughPosCutBit) && + ((negresoChild.cut() & Reso2.daughNegCutBit) == Reso2.daughNegCutBit)) { + resoHistoPartTwo.fillQA(reso, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); // improve + } + } + + /// build particle combinations + for (auto const& [p1, p2] : combinations(CombinationsFullIndexPolicy(sliceV01, sliceReso2))) { + + const auto& posChild = parts.iteratorAt(p1.index() - 2); + const auto& negChild = parts.iteratorAt(p1.index() - 1); + + const auto& posresoChild = parts.iteratorAt(p2.index() - 2); + const auto& negresoChild = parts.iteratorAt(p2.index() - 1); + + if (((posChild.cut() & V01.childPosCutBit) == V01.childPosCutBit) && + ((posChild.pidcut() & V01.childPosTPCBit) == V01.childPosTPCBit) && + ((negChild.cut() & V01.childNegCutBit) == V01.childNegCutBit) && + ((negChild.pidcut() & V01.childNegTPCBit) == V01.childNegTPCBit) && + + ((posresoChild.cut() & Reso2.daughPosCutBit) == Reso2.daughPosCutBit) && + ((negresoChild.cut() & Reso2.daughNegCutBit) == Reso2.daughNegCutBit)) { + + if (Option.cPROn.value) { + if (pairCloseRejectionSE.isClosePair(p1, p2, parts, col.magField())) { + continue; + } + } + sameEventCont.setPair(p1, p2, col.multNtr(), col.multV0M(), Option.use4D, Option.extendedPlots, Option.smearingByOrigin); + } + } + } + + template + void doMixedEvent(CollisionType const& cols, PartType const& parts, PartitionType& part1, PartitionType& part2, BinningType policy) + { + + if (Option.mixEventWithPairs.value) { + 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 sliceV01 = part1.sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); // maybe use . + auto sliceReso2 = part2.sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + + if (sliceV01.size() == 0 || sliceReso2.size() == 0) { + continue; + } + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(sliceV01, sliceReso2))) { + + const auto& posChild = parts.iteratorAt(p1.globalIndex() - 2); + const auto& negChild = parts.iteratorAt(p1.globalIndex() - 1); + + const auto& posresoChild = parts.iteratorAt(p2.globalIndex() - 2); + const auto& negresoChild = parts.iteratorAt(p2.globalIndex() - 1); + + if ((std::abs(posresoChild.tempFitVar()) > Reso2.dcaXYPar0 + Reso2.dcaXYPar1 * std::pow(posresoChild.pt(), -1)) || (std::abs(negresoChild.tempFitVar()) > Reso2.dcaXYPar0 + Reso2.dcaXYPar1 * std::pow(negresoChild.pt(), -1))) { + continue; + } + + // why pass if fullfilled?? + if ((((posChild.cut() & V01.childPosCutBit) == V01.childPosCutBit) && + ((posChild.pidcut() & V01.childPosTPCBit) == V01.childPosTPCBit) && + ((negChild.cut() & V01.childNegCutBit) == V01.childNegCutBit) && + ((negChild.pidcut() & V01.childNegTPCBit) == V01.childNegTPCBit) && + + ((posresoChild.cut() & Reso2.daughPosCutBit) == Reso2.daughPosCutBit) && + ((negresoChild.cut() & Reso2.daughNegCutBit) == Reso2.daughNegCutBit))) { + + if (Option.cPROn.value) { + if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { + continue; + } + } + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.use4D, Option.extendedPlots, Option.smearingByOrigin); + } + } + } + } + } + + void processSameEvent(const FilteredCollision& col, const FDParticles& parts) + { + // fillCollision(col); + auto sliceV01 = partitionV01.sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto sliceReso2 = partitionReso2.sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + + // if (sliceV01.size() == 0 && sliceReso2.size() == 0) { + // return; + // } + eventHisto.fillQA(col); + doSameEvent(sliceV01, sliceReso2, parts, col); + } + PROCESS_SWITCH(FemtoDreamPairTaskV0Reso, processSameEvent, "Enable processing same event", true); + + void processMixedEvent(const FilteredCollisions& cols, const FDParticles& parts) + { + switch (Mixing.policy.value) { + case femtodreamcollision::kMult: + doMixedEvent(cols, parts, partitionV01, partitionReso2, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, parts, partitionV01, partitionReso2, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, parts, partitionV01, partitionReso2, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(FemtoDreamPairTaskV0Reso, processMixedEvent, "Enable processing mixed event", true); + + ////////////////////////////////////// + /// procees functions for K0Short-KStar + + void processSameEventK0ShortKStar(const FilteredCollision& col, const FDParticles& parts) + { + auto sliceV01 = partitionK0Short1.sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto sliceReso2 = partitionKStar2.sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + + eventHisto.fillQA(col); + doSameEvent(sliceV01, sliceReso2, parts, col); + } + PROCESS_SWITCH(FemtoDreamPairTaskV0Reso, processSameEventK0ShortKStar, "Enable processing same event K0Short-KStar", false); + + void processMixedEventK0ShortKStar(const FilteredCollisions& cols, const FDParticles& parts) + { + switch (Mixing.policy.value) { + case femtodreamcollision::kMult: + doMixedEvent(cols, parts, partitionK0Short1, partitionKStar2, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, parts, partitionK0Short1, partitionKStar2, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, parts, partitionK0Short1, partitionKStar2, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(FemtoDreamPairTaskV0Reso, processMixedEventK0ShortKStar, "Enable processing mixed event K0Short-KStar", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskV0V0.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskV0V0.cxx new file mode 100644 index 00000000000..869a7124191 --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamPairTaskV0V0.cxx @@ -0,0 +1,426 @@ +// 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 femtoDreamPairTaskV0V0.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 +/// \author Georgios Mantzaridis, TU München, georgios.mantzaridis@tum.de +/// \author Anton Riedel, TU München, anton.riedel@tum.de +/// \author Bianca Popa, TU München, bianca.popa@tum.de + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainer.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include "TRandom3.h" + +#include +#include +#include +#include + +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::analysis::femtoDream; + +struct femtoDreamPairTaskV0V0 { + 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 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", true, "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", false, "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 { + 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; + Filter EventMultiplicityPercentile = aod::femtodreamcollision::multV0M >= EventSel.MultPercentileMin && aod::femtodreamcollision::multV0M <= EventSel.MultPercentileMax; + + using FilteredCollisions = soa::Filtered; + using FilteredCollision = FilteredCollisions::iterator; + using FilteredMCCollisions = soa::Filtered>; + using FilteredMCCollision = FilteredMCCollisions::iterator; + + using FilteredMaskedCollisions = soa::Filtered>; + using FilteredMaskedCollision = FilteredMaskedCollisions::iterator; + using FilteredMaskedMCCollisions = soa::Filtered>; + using FilteredMaskedMCCollision = FilteredMaskedMCCollisions::iterator; + + femtodreamcollision::BitMaskType BitMask = 0; + + /// Particle 1 (V0) + struct : ConfigurableGroup { + std::string prefix = std::string("V01"); + Configurable PDGCode{"PDGCode", 3122, "PDG code of particle 1 (V0)"}; + Configurable CutBit{"CutBit", 7518, "Selection bit for particle 1 (V0)"}; + Configurable ChildPos_CutBit{"ChildPos_CutBit", 210, "Selection bit for positive child of V0"}; + Configurable ChildPos_TPCBit{"ChildPos_TPCBit", 64, "PID TPC bit for positive child of V0"}; + Configurable ChildNeg_CutBit{"ChildNeg_CutBit", 209, "Selection bit for negative child of V0"}; + Configurable ChildNeg_TPCBit{"ChildNeg_TPCBit", 256, "PID TPC bit for negative child of V0"}; + + Configurable InvMassMin{"InvMassMin", 1.08, "Minimum invariant mass of Partricle 1 (particle) (V0)"}; + Configurable InvMassMax{"InvMassMax", 1.15, "Maximum invariant mass of Partricle 1 (particle) (V0)"}; + Configurable InvMassAntiMin{"InvMassAntiMin", 0., "Minimum invariant mass of Partricle 1 (antiparticle) (V0)"}; + Configurable InvMassAntiMax{"InvMassAntiMax", 999., "Maximum invariant mass of Partricle 1 (antiparticle) (V0)"}; + + Configurable PtMin{"PtMin", 0., "Minimum pT of Partricle 1 (V0)"}; + Configurable PtMax{"PtMax", 999., "Maximum pT of Partricle 1 (V0)"}; + Configurable EtaMin{"EtaMin", -10., "Minimum eta of Partricle 1 (V0)"}; + Configurable EtaMax{"EtaMax", 10., "Maximum eta of Partricle 1 (V0)"}; + } V01; + + /// Partition for particle 1 + Partition PartitionV01 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && + ((aod::femtodreamparticle::cut & V01.CutBit) == V01.CutBit) && + (aod::femtodreamparticle::pt > V01.PtMin) && + (aod::femtodreamparticle::pt < V01.PtMax) && + (aod::femtodreamparticle::eta > V01.EtaMin) && + (aod::femtodreamparticle::eta < V01.EtaMax) && + (aod::femtodreamparticle::mLambda > V01.InvMassMin) && + (aod::femtodreamparticle::mLambda < V01.InvMassMax) && + (aod::femtodreamparticle::mAntiLambda > V01.InvMassAntiMin) && + (aod::femtodreamparticle::mAntiLambda < V01.InvMassAntiMax); + + /// Histogramming for particle 1 + FemtoDreamParticleHisto trackHistoPartOne; + FemtoDreamParticleHisto posChildHistos; + FemtoDreamParticleHisto negChildHistos; + + /// Particle 2 (V0) + struct : ConfigurableGroup { + std::string prefix = std::string("V02"); + Configurable PDGCode{"PDGCode", 3122, "PDG code of particle 2 (V0)"}; + Configurable CutBit{"CutBit", 7518, "Selection bit for particle 2 (V0)"}; + Configurable ChildPos_CutBit{"ChildPos_CutBit", 210, "Selection bit for positive child of V0"}; + Configurable ChildPos_TPCBit{"ChildPos_TPCBit", 64, "PID TPC bit for positive child of V0"}; + Configurable ChildNeg_CutBit{"ChildNeg_CutBit", 209, "Selection bit for negative child of V0"}; + Configurable ChildNeg_TPCBit{"ChildNeg_TPCBit", 256, "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; + + /// 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); + + /// Histogramming for Event + FemtoDreamEventHisto eventHisto; + + /// 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 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 { + std::string prefix = "Binning4D"; + ConfigurableAxis kstar{"kstar", {1500, 0., 6.}, "binning kstar for the 4Dimensional plot: k* vs multiplicity vs multiplicity percentile vs mT (set <> to true)"}; + 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)"}; + 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)"}; + 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)"}; + } Binning4D; + + // Mixing configurables + struct : ConfigurableGroup { + std::string prefix = "Mixing"; + ConfigurableAxis MultMixBins{"MultMixBins", {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 MultPercentileMixBins{"MultPercentileMixBins", {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 percentile"}; + ConfigurableAxis VztxMixBins{"VztxMixBins", {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{"Depth", 5, "Number of events for mixing"}; + Configurable Policy{"Policy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; + } Mixing; + + ColumnBinningPolicy colBinningMult{{Mixing.VztxMixBins, Mixing.MultMixBins}, true}; + ColumnBinningPolicy colBinningMultPercentile{{Mixing.VztxMixBins, Mixing.MultPercentileMixBins}, true}; + ColumnBinningPolicy colBinningMultMultPercentile{{Mixing.VztxMixBins, Mixing.MultMixBins, Mixing.MultPercentileMixBins}, true}; + + FemtoDreamContainer sameEventCont; + FemtoDreamContainer mixedEventCont; + // FemtoDreamPairCleaner pairCleaner; + FemtoDreamDetaDphiStar pairCloseRejectionSE; + FemtoDreamDetaDphiStar pairCloseRejectionME; + /// Histogram output + HistogramRegistry Registry{"Output", {}, OutputObjHandlingPolicy::AnalysisObject}; + + TRandom3* random; + + void init(InitContext&) + { + // 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(&Registry, Option.IsMC); + trackHistoPartOne.init(&Registry, Binning.multTempFit, Option.Dummy, Binning.pT, Option.Dummy, Option.Dummy, Binning.TempFitVarV0, Option.Dummy, Option.Dummy, Option.Dummy, Option.Dummy, Binning.InvMass, Option.Dummy, Option.IsMC, V01.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.MultMixBins, Mixing.MultPercentileMixBins, + Binning4D.kstar, Binning4D.mT, Binning4D.mult, Binning4D.multPercentile, + Option.IsMC, Option.Use4D, Option.ExtendedPlots, + Option.HighkstarCut, + Option.SmearingByOrigin); + + 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, + Option.HighkstarCut, + Option.SmearingByOrigin); + sameEventCont.setPDGCodes(V01.PDGCode, V02.PDGCode); + mixedEventCont.setPDGCodes(V01.PDGCode, V02.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); + } + }; + + template + void fillCollision(CollisionType col) + { + 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 femtoDreamParticles table (in case of Monte Carlo joined with FemtoDreamMCLabels) + /// @param magFieldTesla magnetic field of the collision + /// @param multCol multiplicity of the collision + template + void doSameEvent(PartitionType SliceV01, PartitionType SliceV02, PartType parts, Collision col) + { + for (auto& v0 : SliceV01) { + const auto& posChild = parts.iteratorAt(v0.index() - 2); + const auto& negChild = parts.iteratorAt(v0.index() - 1); + if (((posChild.cut() & V01.ChildPos_CutBit) == V01.ChildPos_CutBit) && + ((posChild.pidcut() & V01.ChildPos_TPCBit) == V01.ChildPos_TPCBit) && + ((negChild.cut() & V01.ChildNeg_CutBit) == V01.ChildNeg_CutBit) && + ((negChild.pidcut() & V01.ChildNeg_TPCBit) == V01.ChildNeg_TPCBit)) { + trackHistoPartOne.fillQA(v0, 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()); + } + } + + /// Now build the combinations + float rand = 0.; + if (Option.SameSpecies.value) { + for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(SliceV01, SliceV02))) { + const auto& posChild_1 = parts.iteratorAt(p1.index() - 2); + const auto& negChild_1 = parts.iteratorAt(p1.index() - 1); + const auto& posChild_2 = parts.iteratorAt(p2.index() - 2); + const auto& negChild_2 = parts.iteratorAt(p2.index() - 1); + if (((posChild_1.cut() & V01.ChildPos_CutBit) == V01.ChildPos_CutBit) && + ((posChild_1.pidcut() & V01.ChildPos_TPCBit) == V01.ChildPos_TPCBit) && + ((negChild_1.cut() & V01.ChildNeg_CutBit) == V01.ChildNeg_CutBit) && + ((negChild_1.pidcut() & V01.ChildNeg_TPCBit) == V01.ChildNeg_TPCBit) && + ((posChild_2.cut() & V02.ChildPos_CutBit) == V02.ChildPos_CutBit) && + ((posChild_2.pidcut() & V02.ChildPos_TPCBit) == V02.ChildPos_TPCBit) && + ((negChild_2.cut() & V02.ChildNeg_CutBit) == V02.ChildNeg_CutBit) && + ((negChild_2.pidcut() & V02.ChildNeg_TPCBit) == V02.ChildNeg_TPCBit)) { + + if (Option.CPROn.value) { + if (pairCloseRejectionSE.isClosePair(p1, p2, parts, col.magField())) { + continue; + } + } + /* + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + */ + + if (Option.RandomizePair.value) { + rand = random->Rndm(); + } + if (rand <= 0.5) { + sameEventCont.setPair(p1, p2, col.multNtr(), col.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.SmearingByOrigin); + } else { + sameEventCont.setPair(p2, p1, col.multNtr(), col.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.SmearingByOrigin); + } + } + } + } else { + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceV01, SliceV02))) { + if (Option.CPROn.value) { + if (pairCloseRejectionSE.isClosePair(p1, p2, parts, col.magField())) { + continue; + } + } + /* + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + */ + sameEventCont.setPair(p1, p2, col.multNtr(), col.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.SmearingByOrigin); + } + } + } + + /// process function for to call doSameEvent with Data + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processSameEvent(FilteredCollision& col, o2::aod::FDParticles& parts) + { + fillCollision(col); + auto SliceV01 = PartitionV01->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto SliceV02 = PartitionV02->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + if (SliceV01.size() == 0 && SliceV02.size() == 0) { + return; + } + doSameEvent(SliceV01, SliceV02, parts, col); + } + PROCESS_SWITCH(femtoDreamPairTaskV0V0, processSameEvent, "Enable processing same event", true); + + template + void doMixedEvent_NotMasked(CollisionType& cols, PartType& parts, PartitionType& part1, PartitionType& part2, BinningType policy) + { + for (auto const& [collision1, collision2] : soa::selfCombinations(policy, Mixing.Depth.value, -1, cols, cols)) { + auto SliceV01 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto SliceV02 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + if (SliceV01.size() == 0 || SliceV02.size() == 0) { + continue; + } + for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(SliceV01, SliceV02))) { + const auto& posChild_1 = parts.iteratorAt(p1.globalIndex() - 2); + const auto& negChild_1 = parts.iteratorAt(p1.globalIndex() - 1); + const auto& posChild_2 = parts.iteratorAt(p2.globalIndex() - 2); + const auto& negChild_2 = parts.iteratorAt(p2.globalIndex() - 1); + if (((posChild_1.cut() & V01.ChildPos_CutBit) == V01.ChildPos_CutBit) && + ((posChild_1.pidcut() & V01.ChildPos_TPCBit) == V01.ChildPos_TPCBit) && + ((negChild_1.cut() & V01.ChildNeg_CutBit) == V01.ChildNeg_CutBit) && + ((negChild_1.pidcut() & V01.ChildNeg_TPCBit) == V01.ChildNeg_TPCBit) && + ((posChild_2.cut() & V02.ChildPos_CutBit) == V02.ChildPos_CutBit) && + ((posChild_2.pidcut() & V02.ChildPos_TPCBit) == V02.ChildPos_TPCBit) && + ((negChild_2.cut() & V02.ChildNeg_CutBit) == V02.ChildNeg_CutBit) && + ((negChild_2.pidcut() & V02.ChildNeg_TPCBit) == V02.ChildNeg_TPCBit)) { + + if (Option.CPROn.value) { + if (pairCloseRejectionME.isClosePair(p1, p2, parts, collision1.magField())) { + continue; + } + } + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.Use4D, Option.ExtendedPlots, Option.SmearingByOrigin); + } + } + } + } + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoDreamParticleTable + void processMixedEvent(FilteredCollisions& cols, o2::aod::FDParticles& parts) + { + switch (Mixing.Policy.value) { + case femtodreamcollision::kMult: + doMixedEvent_NotMasked(cols, parts, PartitionV01, PartitionV02, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent_NotMasked(cols, parts, PartitionV01, PartitionV02, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent_NotMasked(cols, parts, PartitionV01, PartitionV02, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(femtoDreamPairTaskV0V0, processMixedEvent, "Enable processing mixed events", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrack.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrack.cxx index 4667ed15972..48eb15ec7fe 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrack.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrack.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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" @@ -64,6 +65,7 @@ struct femtoDreamTripletTaskTrackTrackTrack { 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"}; @@ -75,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.004f + (0.013f / aod::femtodreamparticle::pt)), + ((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.004f + (0.013f / aod::femtodreamparticle::pt)), + ((aod::femtodreamparticle::tempFitVar >= ConfMinDCAxy) && + (aod::femtodreamparticle::tempFitVar <= ConfMaxDCAxy))); + ; /// Histogramming of Selected Particles FemtoDreamParticleHisto trackHistoSelectedParts; @@ -128,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}}); @@ -138,9 +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); @@ -209,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); @@ -239,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 @@ -337,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)) { @@ -377,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); } @@ -410,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/femtoDreamTripletTaskTrackTrackTrackPbPb.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrackPbPb.cxx new file mode 100644 index 00000000000..698aa5e6c63 --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackTrackPbPb.cxx @@ -0,0 +1,530 @@ +// 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 femtoDreamTripletTaskTrackTrackTrackPbPb.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 "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include "TDatabasePDG.h" + +#include +#include + +using namespace o2; +using namespace o2::analysis::femtoDream; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct femtoDreamTripletTaskTrackTrackTrackPbPb { + SliceCache cache; + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + + Configurable ConfCentralityMin{"ConfCentralityMin", 0, "Minimum Centrality Percentile"}; + Configurable ConfCentralityMax{"ConfCentralityMax", 10, "Maximum Centrality Percentile"}; + + Filter EventCentrality = aod::femtodreamcollision::multV0M >= ConfCentralityMin && aod::femtodreamcollision::multV0M <= ConfCentralityMax; + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; + + using MaskedCollisions = soa::Filtered>; + using MaskedCollision = MaskedCollisions::iterator; + aod::femtodreamcollision::BitMaskType MaskBit = -1; + float mMassOne = -999, mMassTwo = -999, mMassThree = -999; + + /// Particle selection part + + // 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."}; + + /// Table for both particles + Configurable ConfTracksInMixedEvent{"ConfTracksInMixedEvent", 1, "Number of tracks of interest, contained in the mixed event sample: 1 - only events with at least one track of interest are used in mixing; ...; 3 - only events with at least three track of interest are used in mixing. Max value is 3"}; + Configurable ConfMaxpT{"ConfMaxpT", 4.05f, "Maximum transverse momentum of the particles"}; + Configurable ConfMinpT{"ConfMinpT", 0.3f, "Minimum transverse momentum of the particles"}; + 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"}; + Configurable ConfCutPart{"ConfCutPart", 5542474, "Track - Selection 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)) && + (ncheckbit(aod::femtodreamparticle::cut, ConfCutPart)) && + (aod::femtodreamparticle::pt < ConfMaxpT) && + (aod::femtodreamparticle::pt > ConfMinpT) && + ifnode(ConfDCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) < 0.004f + (0.013f / aod::femtodreamparticle::pt)), + ((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) && + ifnode(ConfDCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) < 0.004f + (0.013f / aod::femtodreamparticle::pt)), + ((aod::femtodreamparticle::tempFitVar >= ConfMinDCAxy) && + (aod::femtodreamparticle::tempFitVar <= ConfMaxDCAxy))); + ; + + /// Histogramming of Selected Particles + FemtoDreamParticleHisto trackHistoSelectedParts; + FemtoDreamParticleHisto trackHistoALLSelectedParts; + + /// Histogramming for Event + FemtoDreamEventHisto eventHisto; + + /// 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"}; + ConfigurableAxis ConfBinmultTempFit{"ConfBinmultTempFit", {1, 0, 1}, "multiplicity Binning for the TempFitVar plot"}; + + /// Correlation part + 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"}; + + ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; + + ConfigurableAxis ConfQ3Bins{"ConfQ3Bins", {2000, 0., 8.}, "binning Q3"}; + 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 ConfMaxQ3IncludedInCPRPlots{"ConfMaxQ3IncludedInCPRPlots", 8., "Maximum Q3, for which the pair CPR is included in plots"}; + ConfigurableAxis ConfDummy{"ConfDummy", {1, 0, 1}, "Dummy axis"}; + + FemtoDreamContainerThreeBody sameEventCont; + FemtoDreamContainerThreeBody mixedEventCont; + FemtoDreamPairCleaner pairCleaner; + FemtoDreamDetaDphiStar pairCloseRejectionSE; + FemtoDreamDetaDphiStar pairCloseRejectionME; + /// Histogram output + HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry ThreeBodyQARegistry{"ThreeBodyQARegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext& context) + { + + eventHisto.init(&qaRegistry, false); + + 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}}); + ThreeBodyQARegistry.add("TripletTaskQA/particle_pT_in_Triplet_SE", "; p_{T1} ; p_{T2} ; p_{T3} ; Q_{3}", kTHnSparseF, {ConfTempFitVarpTBins, ConfTempFitVarpTBins, ConfTempFitVarpTBins, ConfQ3BinsFor4D}); + ThreeBodyQARegistry.add("TripletTaskQA/particle_pT_in_Triplet_ME", "; p_{T1} ; p_{T2} ; p_{T3} ; Q_{3}", kTHnSparseF, {ConfTempFitVarpTBins, ConfTempFitVarpTBins, ConfTempFitVarpTBins, ConfQ3BinsFor4D}); + 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}); + ThreeBodyQARegistry.add("TripletTaskQA/hCentralityME", ";Centrality;Entries", kTH1F, {{100, 0.0, 100.0}}); + + sameEventCont.init(&resultRegistry, ConfQ3Bins, ConfMultBins, ConfIsMC); + mixedEventCont.init(&resultRegistry, ConfQ3Bins, ConfMultBins, ConfIsMC); + sameEventCont.setPDGCodes(ConfPDGCodePart, ConfPDGCodePart, ConfPDGCodePart); + 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, 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 + mMassOne = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePart)->Mass(); + mMassTwo = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePart)->Mass(); + mMassThree = TDatabasePDG::Instance()->GetParticle(ConfPDGCodePart)->Mass(); + + // get bit for the collision mask + std::bitset<8 * sizeof(aod::femtodreamcollision::BitMaskType)> mask; + int index = 0; + auto& workflows = context.services().get(); + for (DeviceSpec const& device : workflows.devices) { + if (device.name.find("femto-dream-triplet-task-track-track-track-pb-pb") != std::string::npos) { + if (containsNameValuePair(device.options, "ConfCutPart", ConfCutPart.value) && + containsNameValuePair(device.options, "ConfTPCPIDBit", ConfTPCPIDBit.value) && + containsNameValuePair(device.options, "ConfTPCTOFPIDBit", ConfTPCTOFPIDBit.value) && + containsNameValuePair(device.options, "ConfPIDthrMom", ConfPIDthrMom.value) && + containsNameValuePair(device.options, "ConfMaxpT", ConfMaxpT.value) && + containsNameValuePair(device.options, "ConfMinpT", ConfMinpT.value) && + containsNameValuePair(device.options, "ConfMaxDCAxy", ConfMaxDCAxy.value) && + containsNameValuePair(device.options, "ConfMinDCAxy", ConfMinDCAxy.value)) { + mask.set(index); + MaskBit = static_cast(mask.to_ulong()); + LOG(info) << "Device name matched: " << device.name; + LOG(info) << "Bitmask for collisions: " << mask.to_string(); + break; + } else { + index++; + } + } + } + + if ((doprocessSameEvent && doprocessSameEventMasked) || + (doprocessMixedEvent && doprocessMixedEventMasked) || + (doprocessSameEventMC && doprocessSameEventMCMasked) || + (doprocessMixedEventMC && doprocessMixedEventMCMasked)) { + LOG(fatal) << "Normal and masked processing cannot be activated simultaneously!"; + } + } + + template + void fillCollision(CollisionType col) + { + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); + eventHisto.fillQA(col); + } + + /// This function processes the same event and takes care of all the histogramming + /// @tparam PartitionType + /// @tparam PartType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @param groupSelectedParts partition for the first particle passed by the process function + /// @param parts femtoDreamParticles table (in case of Monte Carlo joined with FemtoDreamMCLabels) + /// @param magFieldTesla magnetic field of the collision + /// @param multCol multiplicity of the collision + template + 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); + + if (ConfIsCPR.value) { + if (pairCloseRejectionSE.isClosePair(p1, p2, parts, magFieldTesla, Q3)) { + continue; + } + if (pairCloseRejectionSE.isClosePair(p2, p3, parts, magFieldTesla, Q3)) { + continue; + } + if (pairCloseRejectionSE.isClosePair(p1, p3, parts, magFieldTesla, Q3)) { + continue; + } + } + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (!pairCleaner.isCleanPair(p2, p3, parts)) { + continue; + } + 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 + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processSameEvent(FilteredFDCollision& col, + o2::aod::FDParticles& parts) + { + fillCollision(col); + auto thegroupSelectedParts = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (auto& part : thegroupSelectedParts) { + trackHistoALLSelectedParts.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + + if (thegroupSelectedParts.size() < 3) { + return; + } + doSameEvent(thegroupSelectedParts, parts, col.magField(), col.multNtr(), col.multV0M()); + } + PROCESS_SWITCH(femtoDreamTripletTaskTrackTrackTrackPbPb, processSameEvent, "Enable processing same event", true); + + /// process function to call doSameEvent with Data which has a mask for containing particles or not + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processSameEventMasked(MaskedCollision& col, o2::aod::FDParticles& parts) + { + fillCollision(col); + auto thegroupSelectedParts = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (auto& part : thegroupSelectedParts) { + trackHistoALLSelectedParts.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + if (thegroupSelectedParts.size() < 3) { + return; + } + doSameEvent(thegroupSelectedParts, parts, col.magField(), col.multNtr(), col.multV0M()); + } + PROCESS_SWITCH(femtoDreamTripletTaskTrackTrackTrackPbPb, processSameEventMasked, "Enable processing same event with masks", 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(o2::aod::FDCollision& col, + soa::Join& parts, + o2::aod::FDMCParticles&) + { + fillCollision(col); + 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; + } + doSameEvent(thegroupSelectedParts, parts, col.magField(), col.multNtr(), col.multV0M()); + } + PROCESS_SWITCH(femtoDreamTripletTaskTrackTrackTrackPbPb, processSameEventMC, "Enable processing same event for Monte Carlo", false); + + /// process function for to call doSameEvent with Monte Carlo which has a mask for containing particles or not + /// \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 processSameEventMCMasked(MaskedCollision& col, + soa::Join& parts, + o2::aod::FDMCParticles&) + { + fillCollision(col); + 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; + } + doSameEvent(thegroupSelectedParts, parts, col.magField(), col.multNtr(), col.multV0M()); + } + PROCESS_SWITCH(femtoDreamTripletTaskTrackTrackTrackPbPb, processSameEventMCMasked, "Enable processing same event for Monte Carlo", false); + + /// This function processes the mixed event + /// \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 groupPartsThree partition for the third particle passed by the process function + /// \param parts femtoDreamParticles table (in case of Monte Carlo joined with FemtoDreamMCLabels) + /// \param magFieldTesla magnetic field of the collision + /// \param multCol multiplicity of the collision + template + 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)) { + continue; + } + if (pairCloseRejectionME.isClosePair(p2, p3, parts, magFieldTesla, Q3)) { + continue; + } + + if (pairCloseRejectionME.isClosePair(p1, p3, parts, magFieldTesla, Q3)) { + continue; + } + } + // fill pT of all three particles as a function of Q3 for lambda calculations + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/particle_pT_in_Triplet_ME"), p1.pt(), p2.pt(), p3.pt(), Q3); + mixedEventCont.setTriplet(p1, p2, p3, multCol, Q3); + } + } + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoDreamParticleTable + void processMixedEvent(FilteredFDCollisions& cols, + o2::aod::FDParticles& parts) + { + for (auto& [collision1, collision2, collision3] : soa::selfCombinations(colBinning, ConfNEventsMix, -1, cols, cols, cols)) { + const int multiplicityCol = collision1.multNtr(); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision1.multV0M()); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision2.multV0M()); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision3.multV0M()); + + auto groupPartsOne = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsThree = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision3.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + const auto& magFieldTesla3 = collision3.magField(); + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } + PROCESS_SWITCH(femtoDreamTripletTaskTrackTrackTrackPbPb, processMixedEvent, "Enable processing mixed events", true); + + /// process function for to call doMixedEvent with Data which has a mask for containing particles or not + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoDreamParticleTable + void processMixedEventMasked(MaskedCollisions& cols, o2::aod::FDParticles& parts) + { + Partition PartitionMaskedCol1 = (ConfTracksInMixedEvent == 1 && (aod::femtodreamcollision::bitmaskTrackOne & MaskBit) == MaskBit) || + (ConfTracksInMixedEvent == 2 && (aod::femtodreamcollision::bitmaskTrackTwo & MaskBit) == MaskBit) || + (ConfTracksInMixedEvent == 3 && (aod::femtodreamcollision::bitmaskTrackThree & MaskBit) == MaskBit); + + PartitionMaskedCol1.bindTable(cols); + for (auto& [collision1, collision2, collision3] : soa::selfCombinations(colBinning, ConfNEventsMix, -1, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol1.mFiltered)) { + const int multiplicityCol = collision1.multNtr(); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision1.multV0M()); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision2.multV0M()); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision3.multV0M()); + + auto groupPartsOne = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsThree = SelectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision3.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + const auto& magFieldTesla3 = collision3.magField(); + + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } + PROCESS_SWITCH(femtoDreamTripletTaskTrackTrackTrackPbPb, processMixedEventMasked, "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 FemtoDreamParticles and FemtoDreamMCLables to access Monte Carlo truth + /// @param FemtoDreamMCParticles subscribe to the Monte Carlo truth table + void processMixedEventMC(o2::aod::FDCollisions& cols, + soa::Join& parts, + o2::aod::FDMCParticles&) + { + for (auto& [collision1, collision2, collision3] : soa::selfCombinations(colBinning, ConfNEventsMix, -1, cols, cols, cols)) { + + const int multiplicityCol = collision1.multNtr(); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + + auto groupPartsOne = SelectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = SelectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsThree = SelectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision3.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + const auto& magFieldTesla3 = collision3.magField(); + + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + // CONSIDER testing different strategies to which events to use + + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } + PROCESS_SWITCH(femtoDreamTripletTaskTrackTrackTrackPbPb, processMixedEventMC, "Enable processing mixed events MC", false); + + /// brief process function for to call doMixedEvent with Monte Carlo which has a mask for containing particles or not + /// @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 processMixedEventMCMasked(MaskedCollisions& cols, + soa::Join& parts, + o2::aod::FDMCParticles&) + { + Partition PartitionMaskedCol1 = (ConfTracksInMixedEvent == 1 && (aod::femtodreamcollision::bitmaskTrackOne & MaskBit) == MaskBit) || + (ConfTracksInMixedEvent == 2 && (aod::femtodreamcollision::bitmaskTrackTwo & MaskBit) == MaskBit) || + (ConfTracksInMixedEvent == 3 && (aod::femtodreamcollision::bitmaskTrackThree & MaskBit) == MaskBit); + PartitionMaskedCol1.bindTable(cols); + + for (auto& [collision1, collision2, collision3] : soa::selfCombinations(colBinning, ConfNEventsMix, -1, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol1.mFiltered, *PartitionMaskedCol1.mFiltered)) { + + const int multiplicityCol = collision1.multNtr(); + ThreeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + + auto groupPartsOne = SelectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = SelectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsThree = SelectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision3.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + const auto& magFieldTesla3 = collision3.magField(); + + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + // CONSIDER testing different strategies to which events to use + + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } + PROCESS_SWITCH(femtoDreamTripletTaskTrackTrackTrackPbPb, processMixedEventMCMasked, "Enable processing mixed events MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0.cxx index afeeaa36c9d..136b8f9d5ff 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -15,6 +15,7 @@ #include #include +#include #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" @@ -68,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)) && @@ -75,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; @@ -179,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}}); @@ -196,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); @@ -308,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 && @@ -316,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) { @@ -340,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); } } } @@ -548,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/Tasks/femtoDreamTripletTaskTrackTrackV0PbPb.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0PbPb.cxx new file mode 100644 index 00000000000..84ec7dc9cd8 --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackV0PbPb.cxx @@ -0,0 +1,776 @@ +// 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 femtoDreamTripletTaskTrackTrackV0PbPb.cxx +/// \brief Tasks that reads the track and V0 tables and creates triplets; only two identical tracks and a V0 can be used +/// \author Laura Serksnyte, CERN, laura.serksnyte@cern.ch +/// \author Wioleta Rzęsa, TU München, wioleta.rzesa@cern.ch + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::analysis::femtoDream; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct FemtoDreamTripletTaskTrackTrackV0PbPb { + SliceCache cache; + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + Configurable confCentralityMin{"confCentralityMin", 0, "Event sel: Minimum Centrality Percentile"}; + Configurable confCentralityMax{"confCentralityMax", 10, "Event sel: Maximum Centrality Percentile"}; + Configurable confZVertexCut{"confZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; + Filter eventCentrality = aod::femtodreamcollision::multV0M >= confCentralityMin && aod::femtodreamcollision::multV0M <= confCentralityMax; + Filter eventVertex = (nabs(aod::collision::posZ) < confZVertexCut); + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; + using MaskedCollisions = soa::Filtered>; + using MaskedCollision = MaskedCollisions::iterator; + + aod::femtodreamcollision::BitMaskType maskBit = -1; + float mMassOne = -999, mMassTwo = -999, mMassThree = -999; + + // Pair/triplet cuts + Configurable confMixIfTripletPresent{"confMixIfTripletPresent", true, "Use for mixing only events which have a TTV0 triplet"}; + Configurable confMixIfTVOPairPresent{"confMixIfTVOPairPresent", false, "Use for mixing only events which have a TV0 pair (at least one track and one V0)"}; + Configurable confMixIfTOrVOPartsPresent{"confMixIfTOrVOPartsPresent", false, "Use for mixing only events which have at least one particle of interest"}; + Configurable confMinTrackNumber{"confMinTrackNumber", 2, "Minimum number of tracks in the event"}; + Configurable confMinV0Number{"confMinV0Number", 1, "Minimum number of V0 in the event"}; + + // which CPR to use, old is with a possible bug and new is fixed + Configurable confUseOLDPossiblyWrongCPR{"confUseOLDPossiblyWrongCPR", 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"}; + + /// First 2 tracks of the triplet + Configurable confPDGCodePart{"confPDGCodePart", 2212, "Particle PDG code"}; // proton + Configurable confCutPart{"confCutPart", 5542474, "Track - Selection bit from cutCulator"}; + Configurable confTPCPIDBit{"confTPCPIDBit", 16, "PID TPC bit from cutCulator "}; + Configurable confTPCTOFPIDBit{"confTPCTOFPIDBit", 8, "PID TPCTOF bit from cutCulator"}; + Configurable confMaxpT{"confMaxpT", 4.0f, "Maximum transverse momentum of the particles"}; + Configurable confMinpT{"confMinpT", 0.5f, "Minimum transverse momentum of the particles"}; + Configurable confMaxDCAxy{"confMaxDCAxy", 0.1f, "Maximum DCAxy of the particles"}; + Configurable confMinDCAxy{"confMinDCAxy", -0.1f, "Minimum DCAxy of the particles"}; + Configurable confPIDthrMom{"confPIDthrMom", 0.75f, "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"}; + Configurable confDCACutPtDepPar0{"confDCACutPtDepPar0", 0.0105, "Parameter par[0] of the pt dep cut, par[0] + par[1]/(pT/(GeV/c)−1.1) cm"}; + Configurable confDCACutPtDepPar1{"confDCACutPtDepPar1", 0.035, "Parameter par[1] of the pt dep cut, par[0] + par[1]/(pT/(GeV/c)−1.1) cm"}; + + /// Partition for selected particles + Partition selectedParts = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && + ifnode(aod::femtodreamparticle::pt * (0.5f * nexp(aod::femtodreamparticle::eta) + 0.5f * nexp(-1.f * aod::femtodreamparticle::eta)) <= confPIDthrMom, ncheckbit(aod::femtodreamparticle::pidcut, confTPCPIDBit), ncheckbit(aod::femtodreamparticle::pidcut, confTPCTOFPIDBit)) && + (ncheckbit(aod::femtodreamparticle::cut, confCutPart)) && + (aod::femtodreamparticle::pt < confMaxpT) && + (aod::femtodreamparticle::pt > confMinpT) && + ifnode(confDCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= confDCACutPtDepPar0 + (confDCACutPtDepPar1 / 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 * (0.5f * nexp(aod::femtodreamparticle::eta) + 0.5f * nexp(-1.f * aod::femtodreamparticle::eta)) <= confPIDthrMom, ncheckbit(aod::femtodreamparticle::pidcut, confTPCPIDBit), ncheckbit(aod::femtodreamparticle::pidcut, confTPCTOFPIDBit)) && + (ncheckbit(aod::femtodreamparticle::cut, confCutPart)) && + (aod::femtodreamparticle::pt < confMaxpT) && + (aod::femtodreamparticle::pt > confMinpT) && + ifnode(confDCACutPtDep, (nabs(aod::femtodreamparticle::tempFitVar) <= confDCACutPtDepPar0 + (confDCACutPtDepPar1 / npow(aod::femtodreamparticle::pt, 1.1f))), + ((aod::femtodreamparticle::tempFitVar >= confMinDCAxy) && + (aod::femtodreamparticle::tempFitVar <= confMaxDCAxy))); + ; + + /// Histogramming of selected tracks + FemtoDreamParticleHisto trackHistoselectedParts; + FemtoDreamParticleHisto trackHistoALLselectedParts; + + /// V0 selection + Configurable confPDGCodeV0{"confPDGCodeV0", 3122, "V0 PDG code"}; + Configurable confCutV0{"confCutV0", 7518, "V0 - Selection bit from cutCulator"}; + Configurable confChildPosCutV0{"confChildPosCutV0", 8234, "Selection bit for positive child of V0"}; + Configurable confChildPosTPCBitV0{"confChildPosTPCBitV0", 1024, "PID TPC bit for positive child of V0"}; + Configurable confChildNegCutV0{"confChildNegCutV0", 8233, "Selection bit for negative child of V0"}; + Configurable confChildNegTPCBitV0{"confChildNegTPCBitV0", 4096, "PID TPC bit for negative child of V0"}; + + Configurable confMinInvMassV0{"confMinInvMassV0", 1.08, "Minimum invariant mass of V0 (particle)"}; + Configurable confMaxInvMassV0{"confMaxInvMassV0", 1.15, "Maximum invariant mass of V0 (particle)"}; + Configurable confMinInvMassAntiV0{"confMinInvMassAntiV0", 1.08, "Minimum invariant mass of V0 (antiparticle)"}; + Configurable confMaxInvMassAntiV0{"confMaxInvMassAntiV0", 1.15, "Maximum invariant mass of V0 (antiparticle)"}; + + Configurable confMinPtV0{"confMinPtV0", 0.0, "Minimum pT of V0"}; + Configurable confMaxPtV0{"confMaxPtV0", 999.0, "Maximum pT of V0"}; + + // Partition for selected particles + Partition selectedV0s = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && + (ncheckbit(aod::femtodreamparticle::cut, confCutV0)) && + (aod::femtodreamparticle::mLambda > confMinInvMassV0) && + (aod::femtodreamparticle::mLambda < confMaxInvMassV0) && + (aod::femtodreamparticle::mAntiLambda > confMinInvMassAntiV0) && + (aod::femtodreamparticle::mAntiLambda < confMaxInvMassAntiV0) && + (aod::femtodreamparticle::pt > confMinPtV0) && + (aod::femtodreamparticle::pt < confMaxPtV0); + Partition> selectedV0sMC = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kV0)) && + (ncheckbit(aod::femtodreamparticle::cut, confCutV0)) && + (aod::femtodreamparticle::mLambda > confMinInvMassV0) && + (aod::femtodreamparticle::mLambda < confMaxInvMassV0) && + (aod::femtodreamparticle::mAntiLambda > confMinInvMassAntiV0) && + (aod::femtodreamparticle::mAntiLambda < confMaxInvMassAntiV0) && + (aod::femtodreamparticle::pt > confMinPtV0) && + (aod::femtodreamparticle::pt < confMaxPtV0); + + /// Histogramming of selected V0s + FemtoDreamParticleHisto particleHistoselectedV0s; + FemtoDreamParticleHisto particleHistoPosChild; + FemtoDreamParticleHisto particleHistoNegChild; + FemtoDreamParticleHisto particleHistoALLselectedV0s; + FemtoDreamParticleHisto particleHistoALLPosChild; + FemtoDreamParticleHisto particleHistoALLNegChild; + + /// Histogramming for Event + FemtoDreamEventHisto eventHisto; + + /// Particles + ConfigurableAxis confTempFitVarBinsTrack{"confTempFitVarBinsTrack", {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 (track)"}; + ConfigurableAxis confTempFitVarBinsV0{"confTempFitVarBinsV0", {300, 0.9, 1}, "binning of the TempFitVar in the pT vs. TempFitVar plot (V0)"}; + ConfigurableAxis confTempFitVarBinsV0Child{"confTempFitVarBinsV0Child", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot (V0 child)"}; + ConfigurableAxis confTempFitVarpTV0Bins{"confTempFitVarpTV0Bins", {35, 0, 6}, "pT binning of the pT vs. TempFitVar plot (V0)"}; + ConfigurableAxis confTempFitVarpTV0Child{"confTempFitVarpTV0Child", {35, 0, 6}, "pT binning of the pT vs. TempFitVar plot (V0 child)"}; + ConfigurableAxis confInvMassBins{"confInvMassBins", {200, 1, 1.2}, "InvMass binning"}; + + /// Correlations + ConfigurableAxis confMultBins{"confMultBins", {VARIABLE_WIDTH, 0.0f, 23.0f, 38.0f, 53.0f, 81.0f, 110.0f, 157.0f, 205.0f, 278.0f, 351.0f, 455.0f, 559.0f, 703.0f, 848.0f, 1050.0f, 1253.0f, 1530.0f, 1668.0f, 1857.0f, 2047.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"}; + + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + ConfigurableAxis confQ3Bins{"confQ3Bins", {2000, 0., 8.}, "binning Q3"}; + 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 confCPRdeltaPhiMaxpp{"confCPRdeltaPhiMaxpp", 0.01, "Max. Delta Phi for Close Pair Rejection of pp"}; + Configurable confCPRdeltaEtaMaxpp{"confCPRdeltaEtaMaxpp", 0.01, "Max. Delta Eta for Close Pair Rejection of pp"}; + Configurable confCPRdeltaPhiMaxpL{"confCPRdeltaPhiMaxpL", 0.1, "Max. Delta Phi for Close Pair Rejection of p and Lambda daughter"}; + Configurable confCPRdeltaEtaMaxpL{"confCPRdeltaEtaMaxpL", 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"}; + + FemtoDreamContainerThreeBody sameEventCont; + FemtoDreamContainerThreeBody mixedEventCont; + FemtoDreamPairCleaner pairCleanerTrackTrack; + FemtoDreamPairCleaner pairCleanerTrackV0; + FemtoDreamDetaDphiStar pairCloseRejectionTrackTrackSE; + FemtoDreamDetaDphiStar pairCloseRejectionTrackV0SE; + FemtoDreamDetaDphiStar pairCloseRejectionTrackTrackME; + FemtoDreamDetaDphiStar pairCloseRejectionTrackV0ME; + /// Histogram output + HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry threeBodyQARegistry{"threeBodyQARegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext& context) + { + + eventHisto.init(&qaRegistry, false); + + 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}}); + threeBodyQARegistry.add("TripletTaskQA/hMinvSE_Lambda", ";Q_{3};M_{inv}", kTH2F, {confQ3Bins, confInvMassBins}); + threeBodyQARegistry.add("TripletTaskQA/hMinvME_Lambda", ";Q_{3};M_{inv}", kTH2F, {confQ3Bins, confInvMassBins}); + threeBodyQARegistry.add("TripletTaskQA/hMinvSE_AntiLambda", ";Q_{3};M_{inv}", kTH2F, {confQ3Bins, confInvMassBins}); + 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}}); + threeBodyQARegistry.add("TripletTaskQA/hCentralityME", ";Centrality;Entries", kTH1F, {{100, 0.0, 100.0}}); + sameEventCont.init(&resultRegistry, confQ3Bins, confMultBins, confIsMC); + mixedEventCont.init(&resultRegistry, confQ3Bins, confMultBins, confIsMC); + sameEventCont.setPDGCodes(confPDGCodePart, confPDGCodePart, confPDGCodeV0); + mixedEventCont.setPDGCodes(confPDGCodePart, confPDGCodePart, confPDGCodeV0); + + pairCleanerTrackTrack.init(&qaRegistry); + pairCleanerTrackV0.init(&qaRegistry); + if (confIsCPR.value) { + pairCloseRejectionTrackTrackSE.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiMaxpp.value, confCPRdeltaEtaMaxpp.value, confCPRPlotPerRadii.value, 1, confUseOLDPossiblyWrongCPR, confMaxQ3IncludedInCPRPlots, false, confAtWhichRadiiToCut, confAtWhichTPCRadii, confFillCPRQA); + pairCloseRejectionTrackV0SE.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiMaxpL.value, confCPRdeltaEtaMaxpL.value, confCPRPlotPerRadii.value, 1, confUseOLDPossiblyWrongCPR, confMaxQ3IncludedInCPRPlots, false, confAtWhichRadiiToCut, confAtWhichTPCRadii, confFillCPRQA); + pairCloseRejectionTrackTrackME.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiMaxpp.value, confCPRdeltaEtaMaxpp.value, confCPRPlotPerRadii.value, 2, confUseOLDPossiblyWrongCPR, confMaxQ3IncludedInCPRPlots, false, confAtWhichRadiiToCut, confAtWhichTPCRadii, confFillCPRQA); + pairCloseRejectionTrackV0ME.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiMaxpL.value, confCPRdeltaEtaMaxpL.value, confCPRPlotPerRadii.value, 2, confUseOLDPossiblyWrongCPR, confMaxQ3IncludedInCPRPlots, true, confAtWhichRadiiToCut, confAtWhichTPCRadii, confFillCPRQA); + } + + // get masses + mMassOne = o2::constants::physics::MassProton; + mMassTwo = o2::constants::physics::MassProton; + mMassThree = o2::constants::physics::MassLambda; + + // get bit for the collision mask + std::bitset<8 * sizeof(aod::femtodreamcollision::BitMaskType)> mask; + int index = 0; + auto& workflows = context.services().get(); + for (DeviceSpec const& device : workflows.devices) { + if (device.name.find("femto-dream-triplet-task-track-track-v0-pb-pb") != std::string::npos) { + if (containsNameValuePair(device.options, "confCutPart", confCutPart.value) && + containsNameValuePair(device.options, "confTPCPIDBit", confTPCPIDBit.value) && + containsNameValuePair(device.options, "confTPCTOFPIDBit", confTPCTOFPIDBit.value) && + containsNameValuePair(device.options, "confPIDthrMom", confPIDthrMom.value) && + containsNameValuePair(device.options, "confMaxpT", confMaxpT.value) && + containsNameValuePair(device.options, "confMinpT", confMinpT.value) && + containsNameValuePair(device.options, "confCutV0", confCutV0.value) && + containsNameValuePair(device.options, "confChildPosCutV0", confChildPosCutV0.value) && + containsNameValuePair(device.options, "confChildPosTPCBitV0", confChildPosTPCBitV0.value) && + containsNameValuePair(device.options, "confChildNegCutV0", confChildNegCutV0.value) && + containsNameValuePair(device.options, "confChildNegTPCBitV0", confChildNegTPCBitV0.value) && + containsNameValuePair(device.options, "confMinInvMassV0", confMinInvMassV0.value) && + containsNameValuePair(device.options, "confMaxInvMassV0", confMaxInvMassV0.value) && + containsNameValuePair(device.options, "confMinInvMassAntiV0", confMinInvMassAntiV0.value) && + containsNameValuePair(device.options, "confMaxInvMassAntiV0", confMaxInvMassAntiV0.value) && + containsNameValuePair(device.options, "confMinPtV0", confMinPtV0.value) && + containsNameValuePair(device.options, "confMaxPtV0", confMaxPtV0.value)) { + mask.set(index); + maskBit = static_cast(mask.to_ulong()); + LOG(info) << "Device name matched: " << device.name; + LOG(info) << "Bitmask for collisions: " << mask.to_string(); + break; + } else { + index++; + } + } + } + + if ((doprocessSameEvent && doprocessSameEventMasked) || + (doprocessMixedEvent && doprocessMixedEventMasked) || + (doprocessSameEventMC && doprocessSameEventMCMasked) || + (doprocessMixedEventMC && doprocessMixedEventMCMasked)) { + LOG(fatal) << "Normal and masked processing cannot be activated simultaneously!"; + } + + if ((confMixIfTripletPresent && confMixIfTVOPairPresent) || + (confMixIfTripletPresent && confMixIfTOrVOPartsPresent) || + (confMixIfTVOPairPresent && confMixIfTOrVOPartsPresent)) { + LOG(fatal) << "Only one method of mixing can be chosen!"; + } + } + + template + void fillCollision(CollisionType col) + { + threeBodyQARegistry.fill(HIST("TripletTaskQA/hSECollisionBins"), colBinning.getBin({col.posZ(), col.multNtr()})); + eventHisto.fillQA(col); + } + + /// This function processes the same event and takes care of all the histogramming + /// @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 parts femtoDreamParticles table (in case of Monte Carlo joined with FemtoDreamMCLabels) + /// @param magFieldTesla magnetic field of the collision + /// @param multCol multiplicity of the collision + template + void doSameEvent(PartitionType groupSelectedTracks, PartitionType groupselectedV0s, PartType parts, float magFieldTesla, int multCol, float centCol) + { + /// Histograming tracks + for (const auto& part : groupSelectedTracks) { + trackHistoselectedParts.fillQA(part, aod::femtodreamparticle::kPt, multCol, centCol); + } + /// Histograming V0s + for (const auto& V0 : groupselectedV0s) { + const auto& posChild = parts.iteratorAt(V0.index() - 2); + const auto& negChild = parts.iteratorAt(V0.index() - 1); + + if (((posChild.cut() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0 && + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0)) { + particleHistoselectedV0s.fillQA(V0, aod::femtodreamparticle::kPt, multCol, centCol); + particleHistoPosChild.fillQA(posChild, aod::femtodreamparticle::kPt, multCol, centCol); + particleHistoNegChild.fillQA(negChild, aod::femtodreamparticle::kPt, multCol, centCol); + } + } + + /// Now build the combinations + for (const 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() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0 && + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0)) { + continue; + } + + for (const 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) { + if (pairCloseRejectionTrackTrackSE.isClosePair(T1, T2, parts, magFieldTesla, q3)) { + continue; + } + if (pairCloseRejectionTrackV0SE.isClosePair(T1, V0, parts, magFieldTesla, q3)) { + continue; + } + if (pairCloseRejectionTrackV0SE.isClosePair(T2, V0, parts, magFieldTesla, q3)) { + continue; + } + } + + // track cleaning + if (!pairCleanerTrackTrack.isCleanPair(T1, T2, parts)) { + continue; + } + if (!pairCleanerTrackV0.isCleanPair(T2, V0, parts)) { + continue; + } + 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); + } + } + } + + /// process function to call doSameEvent with Data + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processSameEvent(const FilteredFDCollision& col, const o2::aod::FDParticles& parts) + { + fillCollision(col); + auto thegroupSelectedTracks = selectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (const auto& part : thegroupSelectedTracks) { + trackHistoALLselectedParts.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + auto thegroupselectedV0s = selectedV0s->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); /// Histograming V0s + for (const auto& V0 : thegroupselectedV0s) { + const auto& posChild = parts.iteratorAt(V0.index() - 2); + const auto& negChild = parts.iteratorAt(V0.index() - 1); + + if (((posChild.cut() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0 && + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0)) { + particleHistoALLselectedV0s.fillQA(V0, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + particleHistoALLPosChild.fillQA(posChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + particleHistoALLNegChild.fillQA(negChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + } + if (thegroupSelectedTracks.size() < confMinTrackNumber || thegroupselectedV0s.size() < confMinV0Number) { + return; + } + doSameEvent(thegroupSelectedTracks, thegroupselectedV0s, parts, col.magField(), col.multNtr(), col.multV0M()); + } + PROCESS_SWITCH(FemtoDreamTripletTaskTrackTrackV0PbPb, processSameEvent, "Enable processing same event", true); + + /// process function to call doSameEvent with Data which has a mask for containing particles or not + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoDreamParticleTable + void processSameEventMasked(const MaskedCollision& col, const o2::aod::FDParticles& parts) + { + fillCollision(col); + auto thegroupSelectedTracks = selectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (const auto& part : thegroupSelectedTracks) { + trackHistoALLselectedParts.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + auto thegroupselectedV0s = selectedV0s->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (const auto& V0 : thegroupselectedV0s) { + const auto& posChild = parts.iteratorAt(V0.index() - 2); + const auto& negChild = parts.iteratorAt(V0.index() - 1); + + if (((posChild.cut() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0 && + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0)) { + particleHistoALLselectedV0s.fillQA(V0, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + particleHistoALLPosChild.fillQA(posChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + particleHistoALLNegChild.fillQA(negChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + } + if (thegroupSelectedTracks.size() < confMinTrackNumber || thegroupselectedV0s.size() < confMinV0Number) { + return; + } + doSameEvent(thegroupSelectedTracks, thegroupselectedV0s, parts, col.magField(), col.multNtr(), col.multV0M()); + } + PROCESS_SWITCH(FemtoDreamTripletTaskTrackTrackV0PbPb, processSameEventMasked, "Enable processing same event with masks", 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(const o2::aod::FDCollision& col, + const soa::Join& parts, + const o2::aod::FDMCParticles&) + { + fillCollision(col); + auto thegroupSelectedTracks = selectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (const auto& part : thegroupSelectedTracks) { + 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()); + } + auto thegroupselectedV0s = selectedV0sMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (const auto& V0 : thegroupselectedV0s) { + const auto& posChild = parts.iteratorAt(V0.index() - 2); + const auto& negChild = parts.iteratorAt(V0.index() - 1); + + if (((posChild.cut() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0 && + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0)) { + particleHistoALLselectedV0s.fillQA(V0, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + particleHistoALLPosChild.fillQA(posChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + particleHistoALLNegChild.fillQA(negChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + } + if (thegroupSelectedTracks.size() < confMinTrackNumber || thegroupselectedV0s.size() < confMinV0Number) { + return; + } + doSameEvent(thegroupSelectedTracks, thegroupselectedV0s, parts, col.magField(), col.multNtr(), col.multV0M()); + } + PROCESS_SWITCH(FemtoDreamTripletTaskTrackTrackV0PbPb, processSameEventMC, "Enable processing same event for Monte Carlo", false); + + /// process function for to call doSameEvent with Monte Carlo which has a mask for containing particles or not + /// \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 processSameEventMCMasked(const MaskedCollision& col, + const soa::Join& parts, + const o2::aod::FDMCParticles&) + { + fillCollision(col); + auto thegroupSelectedTracks = selectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (const auto& part : thegroupSelectedTracks) { + 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()); + } + auto thegroupselectedV0s = selectedV0sMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + for (const auto& V0 : thegroupselectedV0s) { + const auto& posChild = parts.iteratorAt(V0.index() - 2); + const auto& negChild = parts.iteratorAt(V0.index() - 1); + + if (((posChild.cut() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0 && + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0)) { + particleHistoALLselectedV0s.fillQA(V0, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + particleHistoALLPosChild.fillQA(posChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + particleHistoALLNegChild.fillQA(negChild, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + } + if (thegroupSelectedTracks.size() < confMinTrackNumber || thegroupselectedV0s.size() < confMinV0Number) { + return; + } + doSameEvent(thegroupSelectedTracks, thegroupselectedV0s, parts, col.magField(), col.multNtr(), col.multV0M()); + } + PROCESS_SWITCH(FemtoDreamTripletTaskTrackTrackV0PbPb, processSameEventMCMasked, "Enable processing same event for Monte Carlo", false); + + /// This function processes the mixed event + /// \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 groupPartsThree partition for the third particle passed by the process function + /// \param parts femtoDreamParticles table (in case of Monte Carlo joined with FemtoDreamMCLabels) + /// \param magFieldTesla magnetic field of the collision + /// \param multCol multiplicity of the collision + template + void doMixedEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, PartitionType groupPartsThree, PartType parts, float magFieldTesla, int multCol) + { + for (const auto& [T1, T2, V0] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo, groupPartsThree))) { + const auto& posChild = parts.iteratorAt(V0.globalIndex() - 2); + const auto& negChild = parts.iteratorAt(V0.globalIndex() - 1); + + if (!((posChild.cut() & confChildPosCutV0) == confChildPosCutV0 && + (posChild.pidcut() & confChildPosTPCBitV0) == confChildPosTPCBitV0 && + (negChild.cut() & confChildNegCutV0) == confChildNegCutV0 && + (negChild.pidcut() & confChildNegTPCBitV0) == confChildNegTPCBitV0)) { + continue; + } + + auto q3 = FemtoDreamMath::getQ3(T1, mMassOne, T2, mMassTwo, V0, mMassThree); + // Close pair rejection + if (confIsCPR.value) { + if (pairCloseRejectionTrackTrackME.isClosePair(T1, T2, parts, magFieldTesla, q3)) { + continue; + } + if (pairCloseRejectionTrackV0ME.isClosePair(T1, V0, parts, magFieldTesla, q3)) { + continue; + } + if (pairCloseRejectionTrackV0ME.isClosePair(T2, V0, parts, magFieldTesla, q3)) { + continue; + } + } + + // fill inv Mass as a function of Q3 for purity fits + threeBodyQARegistry.fill(HIST("TripletTaskQA/hMinvME_Lambda"), q3, V0.mLambda()); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hMinvME_AntiLambda"), q3, V0.mAntiLambda()); + threeBodyQARegistry.fill(HIST("TripletTaskQA/particle_pT_in_Triplet_ME"), T1.pt(), T2.pt(), V0.pt(), q3); + mixedEventCont.setTriplet(T1, T2, V0, multCol, q3); + } + } + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoDreamParticleTable + void processMixedEvent(const FilteredFDCollisions& cols, + const o2::aod::FDParticles& parts) + { + for (const auto& [collision1, collision2, collision3] : soa::selfCombinations(colBinning, confNEventsMix, -1, cols, cols, cols)) { + const int multiplicityCol = collision1.multNtr(); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision1.multV0M()); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision2.multV0M()); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision3.multV0M()); + + auto groupPartsOne = selectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = selectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsThree = selectedV0s->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision3.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + const auto& magFieldTesla3 = collision3.magField(); + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } + PROCESS_SWITCH(FemtoDreamTripletTaskTrackTrackV0PbPb, processMixedEvent, "Enable processing mixed events", true); + + /// process function for to call doMixedEvent with Data which has a mask for containing particles or not + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoDreamParticleTable + void processMixedEventMasked(const MaskedCollisions& cols, const o2::aod::FDParticles& parts) + { + if (confMixIfTripletPresent || confMixIfTVOPairPresent) { + Partition partitionMaskedCol1 = (confMixIfTripletPresent && (aod::femtodreamcollision::bitmaskTrackTwo & maskBit) == maskBit && (aod::femtodreamcollision::bitmaskTrackThree & maskBit) == maskBit) || + (confMixIfTVOPairPresent && (aod::femtodreamcollision::bitmaskTrackOne & maskBit) == maskBit && (aod::femtodreamcollision::bitmaskTrackThree & maskBit) == maskBit); + partitionMaskedCol1.bindTable(cols); + + for (const auto& [collision1, collision2, collision3] : soa::selfCombinations(colBinning, confNEventsMix, -1, *partitionMaskedCol1.mFiltered, *partitionMaskedCol1.mFiltered, *partitionMaskedCol1.mFiltered)) { + + const int multiplicityCol = collision1.multNtr(); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision1.multV0M()); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision2.multV0M()); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hCentralityME"), collision3.multV0M()); + + auto groupPartsOne = selectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = selectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsThree = selectedV0s->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision3.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + const auto& magFieldTesla3 = collision3.magField(); + + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } else if (confMixIfTOrVOPartsPresent) { + Partition partitionMaskedColT = ((aod::femtodreamcollision::bitmaskTrackOne & maskBit) == maskBit); + Partition partitionMaskedColV0 = ((aod::femtodreamcollision::bitmaskTrackThree & maskBit) == maskBit); + partitionMaskedColT.bindTable(cols); + partitionMaskedColV0.bindTable(cols); + + for (const auto& [ColWithTrack1, ColWithTrack2, ColWithV0] : soa::combinations(soa::CombinationsBlockFullIndexPolicy(colBinning, confNEventsMix, -1, *partitionMaskedColT.mFiltered, *partitionMaskedColT.mFiltered, *partitionMaskedColV0.mFiltered))) { + if (ColWithTrack1.globalIndex() == ColWithTrack2.globalIndex() || ColWithTrack1.globalIndex() == ColWithV0.globalIndex() || ColWithTrack2.globalIndex() == ColWithV0.globalIndex()) { + continue; + } + if (ColWithTrack1.globalIndex() > ColWithTrack2.globalIndex()) { + continue; + } + const int multiplicityCol = ColWithTrack1.multNtr(); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({ColWithTrack1.posZ(), multiplicityCol})); + + auto groupPartsOne = selectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, ColWithTrack1.globalIndex(), cache); + auto groupPartsTwo = selectedParts->sliceByCached(aod::femtodreamparticle::fdCollisionId, ColWithTrack2.globalIndex(), cache); + auto groupPartsThree = selectedV0s->sliceByCached(aod::femtodreamparticle::fdCollisionId, ColWithV0.globalIndex(), cache); + + const auto& magFieldTesla1 = ColWithTrack1.magField(); + const auto& magFieldTesla2 = ColWithTrack2.magField(); + const auto& magFieldTesla3 = ColWithV0.magField(); + + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } + } + PROCESS_SWITCH(FemtoDreamTripletTaskTrackTrackV0PbPb, processMixedEventMasked, "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 FemtoDreamParticles and FemtoDreamMCLables to access Monte Carlo truth + /// @param FemtoDreamMCParticles 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, collision3] : soa::selfCombinations(colBinning, confNEventsMix, -1, cols, cols, cols)) { + + const int multiplicityCol = collision1.multNtr(); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + + auto groupPartsOne = selectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = selectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsThree = selectedV0sMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision3.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + const auto& magFieldTesla3 = collision3.magField(); + + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + // CONSIDER testing different strategies to which events to use + + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } + PROCESS_SWITCH(FemtoDreamTripletTaskTrackTrackV0PbPb, processMixedEventMC, "Enable processing mixed events MC", false); + + /// brief process function for to call doMixedEvent with Monte Carlo which has a mask for containing particles or not + /// @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 processMixedEventMCMasked(const MaskedCollisions& cols, + const soa::Join& parts, + const o2::aod::FDMCParticles&) + { + if (confMixIfTripletPresent || confMixIfTVOPairPresent) { + Partition partitionMaskedCol1 = (confMixIfTripletPresent && (aod::femtodreamcollision::bitmaskTrackTwo & maskBit) == maskBit && (aod::femtodreamcollision::bitmaskTrackThree & maskBit) == maskBit) || + (confMixIfTVOPairPresent && (aod::femtodreamcollision::bitmaskTrackOne & maskBit) == maskBit && (aod::femtodreamcollision::bitmaskTrackThree & maskBit) == maskBit); + partitionMaskedCol1.bindTable(cols); + + for (const auto& [collision1, collision2, collision3] : soa::selfCombinations(colBinning, confNEventsMix, -1, *partitionMaskedCol1.mFiltered, *partitionMaskedCol1.mFiltered, *partitionMaskedCol1.mFiltered)) { + const int multiplicityCol = collision1.multNtr(); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + + auto groupPartsOne = selectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = selectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsThree = selectedV0sMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision3.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + const auto& magFieldTesla3 = collision3.magField(); + + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } else if (confMixIfTOrVOPartsPresent) { + Partition partitionMaskedColT = ((aod::femtodreamcollision::bitmaskTrackOne & maskBit) == maskBit); + Partition partitionMaskedColV0 = ((aod::femtodreamcollision::bitmaskTrackThree & maskBit) == maskBit); + partitionMaskedColT.bindTable(cols); + partitionMaskedColV0.bindTable(cols); + + for (const auto& [ColWithTrack1, ColWithTrack2, ColWithV0] : soa::combinations(soa::CombinationsBlockFullIndexPolicy(colBinning, confNEventsMix, -1, *partitionMaskedColT.mFiltered, *partitionMaskedColT.mFiltered, *partitionMaskedColV0.mFiltered))) { + if (ColWithTrack1.globalIndex() == ColWithTrack2.globalIndex() || ColWithTrack1.globalIndex() == ColWithV0.globalIndex() || ColWithTrack2.globalIndex() == ColWithV0.globalIndex()) { + continue; + } + if (ColWithTrack1.globalIndex() > ColWithTrack2.globalIndex()) { + continue; + } + const int multiplicityCol = ColWithTrack1.multNtr(); + threeBodyQARegistry.fill(HIST("TripletTaskQA/hMECollisionBins"), colBinning.getBin({ColWithTrack1.posZ(), multiplicityCol})); + + auto groupPartsOne = selectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, ColWithTrack1.globalIndex(), cache); + auto groupPartsTwo = selectedPartsMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, ColWithTrack2.globalIndex(), cache); + auto groupPartsThree = selectedV0sMC->sliceByCached(aod::femtodreamparticle::fdCollisionId, ColWithV0.globalIndex(), cache); + + const auto& magFieldTesla1 = ColWithTrack1.magField(); + const auto& magFieldTesla2 = ColWithTrack2.magField(); + const auto& magFieldTesla3 = ColWithV0.magField(); + + if ((magFieldTesla1 != magFieldTesla2) || (magFieldTesla2 != magFieldTesla3) || (magFieldTesla1 != magFieldTesla3)) { + continue; + } + doMixedEvent(groupPartsOne, groupPartsTwo, groupPartsThree, parts, magFieldTesla1, multiplicityCol); + } + } + } + PROCESS_SWITCH(FemtoDreamTripletTaskTrackTrackV0PbPb, processMixedEventMCMasked, "Enable processing mixed events MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoDream/Tasks/femtodreamPairCascadeCascade.cxx b/PWGCF/FemtoDream/Tasks/femtodreamPairCascadeCascade.cxx new file mode 100644 index 00000000000..fbf164378a1 --- /dev/null +++ b/PWGCF/FemtoDream/Tasks/femtodreamPairCascadeCascade.cxx @@ -0,0 +1,448 @@ +// 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 femtoDreamPairCascadeCascade.cxx +/// \brief Tasks that reads the track tables used for the pairing and builds pairs of two cascades +/// \author Andi Mathis, Anton Riedel, Georgios Mantzaridis, Oton Vazquez Doce. + +#include "PWGCF/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamContainer.h" +#include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" +#include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include + +#include +#include +#include +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 FemtoDreamPairCascadeCascade { + SliceCache cache; + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + + /// General options + struct : ConfigurableGroup { + std::string prefix = std::string("Option"); + Configurable sameSpecies{"sameSpecies", false, "Set to true if particle 1 and particle 2 are the same species"}; + 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; //??????????????????? + + /// Cascade 1 (Cascade) + struct : ConfigurableGroup { + std::string prefix = std::string("Cascade1"); + Configurable pdgCode{"pdgCode", 3334, "PDG code of Particle 1 (Cascade)"}; + Configurable cutBit{"cutBit", 5542474, "Particle 1 (Cascade) - Selection bit from cutCulator"}; + Configurable childPosCutBit{"childPosCutBit", 278, "Selection bit for positive child of Cascade"}; + Configurable childPosTPCBit{"childPosTPCBit", 1024, "PID TPC bit for positive child of Cascade"}; + Configurable childNegCutBit{"childNegCutBit", 277, "Selection bit for negative child of Cascade"}; + Configurable childNegTPCBit{"childNegTPCBit", 4096, "PID TPC bit for negative child of Cascade"}; + Configurable childBachCutBit{"childBachCutBit", 277, "Selection bit for bachelor child of Cascade"}; + Configurable childBachTPCBit{"childBachTPCBit", 64, "PID TPC bit for bachelor child of Cascade"}; + + Configurable invMassMin{"invMassMin", 1.6, "Minimum invariant mass of Partricle 1 (Cascade)"}; + Configurable invMassMax{"invMassMax", 1.8, "Maximum invariant mass of Partricle 1 (Cascade)"}; + Configurable invMassV0DaughMin{"invMassV0DaughMin", 0., "Minimum invariant mass of the V0 Daughter"}; + Configurable invMassV0DaughMax{"invMassV0DaughMax", 999., "Maximum invariant mass of the V0 Daughter"}; + Configurable ptMin{"ptMin", 0., "Minimum pT of Particle 2 (Cascade)"}; + Configurable ptMax{"ptMax", 999., "Maximum pT of Particle 2 (Cascade)"}; + Configurable etaMin{"etaMin", -10., "Minimum eta of Particle 2 (Cascade)"}; + Configurable etaMax{"etaMax", 10., "Maximum eta of Particle 2 (Cascade)"}; + 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)"}; + } Cascade1; + + /// Partition for particle 1 + Partition partitionCascade1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kCascade)) && + ((aod::femtodreamparticle::cut & Cascade1.cutBit) == Cascade1.cutBit) && + (aod::femtodreamparticle::pt > Cascade1.ptMin) && + (aod::femtodreamparticle::pt < Cascade1.ptMax) && + (aod::femtodreamparticle::eta > Cascade1.etaMin) && + (aod::femtodreamparticle::eta < Cascade1.etaMax) && + (aod::femtodreamparticle::mLambda > Cascade1.invMassMin) && + (aod::femtodreamparticle::mLambda < Cascade1.invMassMax) && + (aod::femtodreamparticle::mAntiLambda > Cascade1.invMassV0DaughMin) && + (aod::femtodreamparticle::mAntiLambda < Cascade1.invMassV0DaughMax); + /// Histogramming for particle 1 + FemtoDreamParticleHisto cascHistoPartOne; + FemtoDreamParticleHisto posChildHistosPartOne; + FemtoDreamParticleHisto negChildHistosPartOne; + FemtoDreamParticleHisto bachChildHistosPartOne; + + /// Particle 2 (Cascade) + struct : ConfigurableGroup { + std::string prefix = std::string("Cascade2"); + Configurable pdgCode{"pdgCode", 3334, "PDG code of particle 2 (Cascade)"}; + Configurable cutBit{"cutBit", 32221874, "Selection bit for particle 2 (Cascade)"}; + Configurable childPosCutBit{"childPosCutBit", 278, "Selection bit for positive child of Cascade"}; + Configurable childPosTPCBit{"childPosTPCBit", 1024, "PID TPC bit for positive child of Cascade"}; + Configurable childNegCutBit{"childNegCutBit", 277, "Selection bit for negative child of Cascade"}; + Configurable childNegTPCBit{"childNegTPCBit", 4096, "PID TPC bit for negative child of Cascade"}; + Configurable childBachCutBit{"childBachCutBit", 277, "Selection bit for negative child of Cascade"}; + Configurable childBachTPCBit{"childBachTPCBit", 64, "PID TPC bit for bachelor child of Cascade"}; + Configurable invMassMin{"invMassMin", 1.2, "Minimum invariant mass of Particle 2 (Cascade)"}; + Configurable invMassMax{"invMassMax", 1.4, "Maximum invariant mass of Particle 2 (Cascade)"}; + Configurable invMassV0DaughMin{"invMassV0DaughMin", 0., "Minimum invariant mass of the V0 Daughter"}; // (???????) + Configurable invMassV0DaughMax{"invMassV0DaughMax", 999., "Maximum invariant mass of the V0 Daughter"}; // (???????) + Configurable ptMin{"ptMin", 0., "Minimum pT of Particle 2 (Cascade)"}; + Configurable ptMax{"ptMax", 999., "Maximum pT of Particle 2 (Cascade)"}; + Configurable etaMin{"etaMin", -10., "Minimum eta of Particle 2 (Cascade)"}; + Configurable etaMax{"etaMax", 10., "Maximum eta of Particle 2 (Cascade)"}; + 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 cascHistoPartTwo; + FemtoDreamParticleHisto posChildHistosPartTwo; + FemtoDreamParticleHisto negChildHistosPartTwo; + FemtoDreamParticleHisto bachChildHistosPartTwo; + + /// Binning configurables + struct : ConfigurableGroup { + std::string prefix = std::string("Binning"); + 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 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 binPolicy{"binPolicy", 0, "Binning binPolicy 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 binPolicy for mixing + colBinningMult = {{Mixing.binVztx, Mixing.binMult}, true}; + colBinningMultPercentile = {{Mixing.binVztx, Mixing.binMultPercentile}, true}; + colBinningMultMultPercentile = {{Mixing.binVztx, Mixing.binMult, Mixing.binMultPercentile}, true}; + eventHisto.init(®istry, Option.isMC); + + cascHistoPartOne.init(®istry, Binning.multTempFit, Option.dummy, Binning.pTCascade, Option.dummy, Option.dummy, Binning.tempFitVarCascade, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.dummy, Option.isMC, Cascade1.pdgCode); + posChildHistosPartOne.init(®istry, 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); + negChildHistosPartOne.init(®istry, 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); + bachChildHistosPartOne.init(®istry, 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); + + if (!Option.sameSpecies) { + cascHistoPartTwo.init(®istry, 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); + posChildHistosPartTwo.init(®istry, 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); + negChildHistosPartTwo.init(®istry, 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); + bachChildHistosPartTwo.init(®istry, 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(®istry, + 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(Cascade1.pdgCode, Cascade2.pdgCode); + + mixedEventCont.init(®istry, + 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(Cascade1.pdgCode, Cascade2.pdgCode); + + pairCleaner.init(®istry); + if (Option.cprOn.value) { + pairCloseRejectionSE.init(®istry, ®istry, Option.cprDeltaPhiMax.value, Option.cprDeltaEtaMax.value, Option.cprPlotPerRadii.value, 1, Option.cprOld.value); + pairCloseRejectionME.init(®istry, ®istry, 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& sliceCascade1, PartitionType& sliceCascade2, TableTracks const& parts, Collision const& col) + { + /// Histogramming same event + for (auto const& casc : sliceCascade1) { + const auto& posChild1 = parts.iteratorAt(casc.index() - 3); + const auto& negChild1 = parts.iteratorAt(casc.index() - 2); + const auto& bachChild1 = parts.iteratorAt(casc.index() - 1); + + // check cuts on V0 children + if (Cascade1.useChildCuts) { + if (!(((posChild1.cut() & Cascade1.childPosCutBit) == Cascade1.childPosCutBit) && + ((negChild1.cut() & Cascade1.childNegCutBit) == Cascade1.childNegCutBit) && + ((bachChild1.cut() & Cascade1.childBachCutBit) == Cascade1.childBachCutBit))) { + continue; + } + } + if (Cascade1.useChildPIDCuts) { + if (!(((posChild1.pidcut() & Cascade1.childPosTPCBit) == Cascade1.childPosTPCBit) && + ((negChild1.pidcut() & Cascade1.childNegTPCBit) == Cascade1.childNegTPCBit) && + ((bachChild1.pidcut() & Cascade1.childBachTPCBit) == Cascade1.childBachTPCBit))) { + continue; + } + } + cascHistoPartOne.fillQA(casc, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + posChildHistosPartOne.fillQA(posChild1, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + negChildHistosPartOne.fillQA(negChild1, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + bachChildHistosPartOne.fillQA(bachChild1, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + if (!Option.sameSpecies) { + for (auto const& casc : sliceCascade2) { + const auto& posChild2 = parts.iteratorAt(casc.index() - 3); + const auto& negChild2 = parts.iteratorAt(casc.index() - 2); + const auto& bachChild2 = parts.iteratorAt(casc.index() - 1); + + // check cuts on V0 children + if (Cascade2.useChildCuts) { + if (!(((posChild2.cut() & Cascade2.childPosCutBit) == Cascade2.childPosCutBit) && + ((negChild2.cut() & Cascade2.childNegCutBit) == Cascade2.childNegCutBit) && + ((bachChild2.cut() & Cascade2.childBachCutBit) == Cascade2.childBachCutBit))) { + continue; + } + } + if (Cascade2.useChildPIDCuts) { + if (!(((posChild2.pidcut() & Cascade2.childPosTPCBit) == Cascade2.childPosTPCBit) && + ((negChild2.pidcut() & Cascade2.childNegTPCBit) == Cascade2.childNegTPCBit) && + ((bachChild2.pidcut() & Cascade2.childBachTPCBit) == Cascade2.childBachTPCBit))) { + continue; + } + } + cascHistoPartTwo.fillQA(casc, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + posChildHistosPartTwo.fillQA(posChild2, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + negChildHistosPartTwo.fillQA(negChild2, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + bachChildHistosPartTwo.fillQA(bachChild2, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + } + } + + /// Now build particle combinations + for (auto const& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(sliceCascade1, sliceCascade2))) { + const auto& posChild1 = parts.iteratorAt(p1.index() - 3); + const auto& negChild1 = parts.iteratorAt(p1.index() - 2); + const auto& bachChild1 = parts.iteratorAt(p1.index() - 1); + const auto& posChild2 = parts.iteratorAt(p2.index() - 3); + const auto& negChild2 = parts.iteratorAt(p2.index() - 2); + const auto& bachChild2 = parts.iteratorAt(p2.index() - 1); + + // cuts on Cascade children still need to be applied + if (Cascade1.useChildCuts) { + if (!(((posChild1.cut() & Cascade1.childPosCutBit) == Cascade1.childPosCutBit) && + ((negChild1.cut() & Cascade1.childNegCutBit) == Cascade1.childNegCutBit) && + ((bachChild1.cut() & Cascade1.childBachCutBit) == Cascade1.childBachCutBit))) { + continue; + } + } + if (Cascade1.useChildPIDCuts) { + if (!(((posChild1.pidcut() & Cascade1.childPosTPCBit) == Cascade1.childPosTPCBit) && + ((negChild1.pidcut() & Cascade1.childNegTPCBit) == Cascade1.childNegTPCBit) && + ((bachChild1.pidcut() & Cascade1.childBachTPCBit) == Cascade1.childBachTPCBit))) { + continue; + } + } + + if (Cascade2.useChildCuts) { + if (!(((posChild2.cut() & Cascade2.childPosCutBit) == Cascade2.childPosCutBit) && + ((negChild2.cut() & Cascade2.childNegCutBit) == Cascade2.childNegCutBit) && + ((bachChild2.cut() & Cascade2.childBachCutBit) == Cascade2.childBachCutBit))) { + continue; + } + } + if (Cascade2.useChildPIDCuts) { + if (!(((posChild2.pidcut() & Cascade2.childPosTPCBit) == Cascade2.childPosTPCBit) && + ((negChild2.pidcut() & Cascade2.childNegTPCBit) == Cascade2.childNegTPCBit) && + ((bachChild2.pidcut() & Cascade2.childBachTPCBit) == Cascade2.childBachTPCBit))) { + continue; + } + } + + // SE pair set: + sameEventCont.setPair(p1, p2, col.multNtr(), col.multV0M(), Option.use4D, Option.extendedPlots, Option.smearingByOrigin); + } + } + + // process Same Event + void processSameEvent(FilteredCollision const& col, FDParticles const& parts) + { + eventHisto.fillQA(col); + auto sliceCascade1 = partitionCascade1->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto sliceCascade2 = partitionCascade2->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + doSameEvent(sliceCascade1, sliceCascade2, parts, col); + } + PROCESS_SWITCH(FemtoDreamPairCascadeCascade, processSameEvent, "Enable processing same event", true); + + // Mixed events + template + void doMixedEvent(CollisionType const& cols, PartType const& parts, PartitionType& part1, PartitionType& part2, BinningType binPolicy) + { + for (auto const& [collision1, collision2] : soa::selfCombinations(binPolicy, Mixing.depth.value, -1, cols, cols)) { + // make sure that tracks in same events are not mixed + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + auto sliceCasc1 = part1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto sliceCasc2 = part2->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + for (auto const& [p1, p2] : combinations(CombinationsFullIndexPolicy(sliceCasc1, sliceCasc2))) { + const auto& posChild1 = parts.iteratorAt(p1.index() - 3); + const auto& negChild1 = parts.iteratorAt(p1.index() - 2); + const auto& bachChild1 = parts.iteratorAt(p1.index() - 1); + const auto& posChild2 = parts.iteratorAt(p2.index() - 3); + const auto& negChild2 = parts.iteratorAt(p2.index() - 2); + const auto& bachChild2 = parts.iteratorAt(p2.index() - 1); + // check cuts on Cascade children + if (Cascade1.useChildCuts) { + if (!(((posChild1.cut() & Cascade1.childPosCutBit) == Cascade1.childPosCutBit) && + ((negChild1.cut() & Cascade1.childNegCutBit) == Cascade1.childNegCutBit) && + ((bachChild1.cut() & Cascade1.childBachCutBit) == Cascade1.childBachCutBit))) { + continue; + } + } + if (Cascade1.useChildPIDCuts) { + if (!(((posChild1.pidcut() & Cascade1.childPosTPCBit) == Cascade1.childPosTPCBit) && + ((negChild1.pidcut() & Cascade1.childNegTPCBit) == Cascade1.childNegTPCBit) && + ((bachChild1.pidcut() & Cascade1.childBachTPCBit) == Cascade1.childBachTPCBit))) { + continue; + } + } + + if (Cascade2.useChildCuts) { + if (!(((posChild2.cut() & Cascade2.childPosCutBit) == Cascade2.childPosCutBit) && + ((negChild2.cut() & Cascade2.childNegCutBit) == Cascade2.childNegCutBit) && + ((bachChild2.cut() & Cascade2.childBachCutBit) == Cascade2.childBachCutBit))) { + continue; + } + } + if (Cascade2.useChildPIDCuts) { + if (!(((posChild2.pidcut() & Cascade2.childPosTPCBit) == Cascade2.childPosTPCBit) && + ((negChild2.pidcut() & Cascade2.childNegTPCBit) == Cascade2.childNegTPCBit) && + ((bachChild2.pidcut() & Cascade2.childBachTPCBit) == Cascade2.childBachTPCBit))) { + continue; + } + } + + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), Option.use4D, Option.extendedPlots, Option.smearingByOrigin); + } + } + } + + // process Mixed Event + void processMixedEvent(FilteredCollisions const& cols, FDParticles const& parts) + { + switch (Mixing.binPolicy.value) { + case femtodreamcollision::kMult: + doMixedEvent(cols, parts, partitionCascade1, partitionCascade2, colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + doMixedEvent(cols, parts, partitionCascade1, partitionCascade2, colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + doMixedEvent(cols, parts, partitionCascade1, partitionCascade2, colBinningMultMultPercentile); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + PROCESS_SWITCH(FemtoDreamPairCascadeCascade, processMixedEvent, "Enable processing mixed events", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoDream/Utils/CMakeLists.txt b/PWGCF/FemtoDream/Utils/CMakeLists.txt index 11e95315fba..a7e29b7839a 100644 --- a/PWGCF/FemtoDream/Utils/CMakeLists.txt +++ b/PWGCF/FemtoDream/Utils/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. # diff --git a/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.cxx b/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.cxx index 0096d6840e7..d6aa862851f 100644 --- a/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.cxx +++ b/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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..f54a9ff62a4 100644 --- a/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.h +++ b/PWGCF/FemtoDream/Utils/femtoDreamCutCulator.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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..77c8798a3b7 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverse3DContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverse3DContainer.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -17,22 +17,25 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSE3DCONTAINER_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSE3DCONTAINER_H_ -#include -#include -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" #include "Framework/HistogramRegistry.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include + #include "Math/Vector4D.h" -#include "TMath.h" #include "TDatabasePDG.h" +#include "TMath.h" + +#include +#include 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 +45,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 +53,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 +77,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 +108,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 +148,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 +170,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 +216,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 +230,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..4a1fb507b4a 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -20,23 +20,27 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEANGULARCONTAINER_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEANGULARCONTAINER_H_ -#include -#include -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" + +#include "Common/Core/RecoDecay.h" #include "Framework/HistogramRegistry.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include #include "Math/Vector4D.h" -#include "TMath.h" #include "TDatabasePDG.h" +#include "TMath.h" + +#include +#include 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 +50,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 +58,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 +75,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 +89,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 +110,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 +124,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 +156,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(); + + 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("/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 +180,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 +192,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, 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 == 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 +232,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..4bb024288e0 --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseCascadeSelection.h @@ -0,0 +1,593 @@ +// 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 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 "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" + +#include +#include + +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), fInvMassLowLimitXi(1.25), fInvMassUpLimitXi(1.4), fInvMassLowLimitOmega(1.6), fInvMassUpLimitOmega(1.8) /*, fRejectCompetingMass(false), fInvMassCompetingLowLimit(1.5), fInvMassCompetingUpLimit(2.0), 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 lowLimitXi, float lowLimitOmega, float upLimitXi, float upLimitOmega) + { + fInvMassLowLimitXi = lowLimitXi; + fInvMassUpLimitXi = upLimitXi; + fInvMassLowLimitOmega = lowLimitOmega; + fInvMassUpLimitOmega = upLimitOmega; + } + + /// 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 fInvMassLowLimitXi; + float fInvMassUpLimitXi; + + float fInvMassLowLimitOmega; + float fInvMassUpLimitOmega; + + /*float fRejectCompetingMass; + float fInvMassCompetingLowLimit; + float fInvMassCompetingUpLimit;*/ + + // 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 min + femto_universe_selection::kLowerLimit, // DCA neg to PV min + femto_universe_selection::kLowerLimit, // DCA bach to PV min + 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", + "Minimum DCA of positive track form primary vertex", + "Minimum DCA of negative track form primary vertex", + "Minimum DCA of bachelor track form primary vertex", + "Minimum 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) +{ + + 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/hInvMassXiCut", "Invariant mass with cut", kTH1F, {massAxisCascade}); + mHistogramRegistry->add("CascadeQA/hInvMassOmegaCut", "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); +} + +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 invMassXi = cascade.mXi(); + const float invMassOmega = cascade.mOmega(); + + if (invMassLambda < fV0InvMassLowLimit || invMassLambda > fV0InvMassUpLimit) { + return false; + } + // Accepts the cascade candidates as either Xi or Omega but not both + if ((invMassXi < fInvMassLowLimitXi || invMassXi > fInvMassUpLimitXi) == (invMassOmega < fInvMassLowLimitOmega || invMassOmega > fInvMassUpLimitOmega)) { + 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 invMassXi = cascade.mXi(); + const float invMassOmega = cascade.mOmega(); + + mHistogramRegistry->fill(HIST("CascadeQA/hInvMassV0Cut"), invMassLambda); + mHistogramRegistry->fill(HIST("CascadeQA/hInvMassXiCut"), invMassXi); + mHistogramRegistry->fill(HIST("CascadeQA/hInvMassOmegaCut"), invMassOmega); + 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..ab47405cb9c 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -18,15 +18,16 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECOLLISIONSELECTION_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECOLLISIONSELECTION_H_ -#include -#include #include "Common/CCDB/TriggerAliases.h" + #include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" +#include + using namespace o2::framework; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { /// \class FemtoUniverseCollisionSelection @@ -160,33 +161,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 +216,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..6f45d43f977 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -20,23 +20,27 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECONTAINER_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECONTAINER_H_ -#include -#include -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Common/Core/RecoDecay.h" #include "Framework/HistogramRegistry.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include #include "Math/Vector4D.h" -#include "TMath.h" #include "TDatabasePDG.h" +#include "TMath.h" + +#include +#include 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,15 +50,15 @@ 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 /// 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 eventType Type of the event (same or mixed) /// \tparam obs Observable to be computed (k*/Q_inv/...) -template +template class FemtoUniverseContainer { public: @@ -71,7 +75,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 +99,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 +110,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 +126,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 +139,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 +171,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 +205,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..58e278cdde7 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseCutculator.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseCutculator.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -18,21 +18,22 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECUTCULATOR_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSECUTCULATOR_H_ +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h" + +#include +#include + +#include #include #include +#include #include #include #include -#include -#include -#include -#include -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h" -#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 +46,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 +77,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 +96,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 +111,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 +133,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 +159,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 +175,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 +201,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 +253,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 +274,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 +295,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 +310,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 +334,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 +360,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 d7069e357a9..3c7d0f2369a 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -14,30 +14,28 @@ /// \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_ -#include -#include -#include -#include "TMath.h" -#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseAngularContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" -#include "Framework/HistogramRegistry.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.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 "TMath.h" + +#include +#include +#include namespace o2::analysis { -namespace femtoUniverse +namespace femto_universe { /// \class FemtoUniverseDetaDphiStar @@ -52,101 +50,175 @@ class FemtoUniverseDetaDphiStar /// Destructor virtual ~FemtoUniverseDetaDphiStar() = default; /// Initialization of the histograms and setting required values - void init(HistogramRegistry* registry, HistogramRegistry* registryQA, float ldeltaphistarcutmin, float ldeltaphistarcutmax, float ldeltaetacutmin, float ldeltaetacutmax, float lchosenradii, bool lplotForEveryRadii, float lPhiMassMin = 1.014, float lPhiMassMax = 1.026) + void init(HistogramRegistry* registry, HistogramRegistry* registryQA, float ldeltaphistarcutmin, float ldeltaphistarcutmax, float ldeltaetacutmin, float ldeltaetacutmax, float lchosenradii, bool lplotForEveryRadii, float lPhiMassMin = 1.014, float lPhiMassMax = 1.026, bool lisSameSignCPR = false) { - ChosenRadii = lchosenradii; - CutDeltaPhiStarMax = ldeltaphistarcutmax; - CutDeltaPhiStarMin = ldeltaphistarcutmin; - CutDeltaEtaMax = ldeltaetacutmax; - CutDeltaEtaMin = ldeltaetacutmin; + chosenRadii = lchosenradii; + cutDeltaPhiStarMax = ldeltaphistarcutmax; + cutDeltaPhiStarMin = ldeltaphistarcutmin; + cutDeltaEtaMax = ldeltaetacutmax; + cutDeltaEtaMin = ldeltaetacutmin; plotForEveryRadii = lplotForEveryRadii; mHistogramRegistry = registry; mHistogramRegistryQA = registryQA; - CutPhiInvMassLow = lPhiMassMin; - CutPhiInvMassHigh = lPhiMassMax; + cutPhiInvMassLow = lPhiMassMin; + cutPhiInvMassHigh = lPhiMassMax; + isSameSignCPR = lisSameSignCPR; + + 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 constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == 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}}); + histdetadpiqlcmssame = mHistogramRegistry->add((dirName + static_cast(HistNamesSame[1][7])).c_str(), "; #it{q}_{LCMS}; #Delta #eta; #Delta #phi", kTH3F, {{100, 0.0, 0.5}, {100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadpiqlcmsmixed = mHistogramRegistry->add((dirName + static_cast(HistNamesMixed[1][7])).c_str(), "; #it{q}_{LCMS}; #Delta #eta; #Delta #phi", kTH3F, {{100, 0.0, 0.5}, {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}}); + } + } + } + } + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kCascade && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// Cascade-Cascade 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::kCascade) { + /// Track-Cascade combination + for (int k = 0; k < 3; k++) { + std::string dirName = static_cast(DirNames[6]); + 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::kV0 && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// V0-Cascade combination + for (int k = 0; k < 3; k++) { + std::string dirName = static_cast(DirNames[7]); + 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 #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}}); + 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 #varphi*", 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}}); } } } } } + template + void init_kT(HistogramRegistry* registry, t1& ktbins, std::vector ldeltaphistarcutmin, std::vector ldeltaphistarcutmax, std::vector ldeltaetacutmin, std::vector ldeltaetacutmax) + { + mHistogramRegistry = registry; + ktBins = ktbins; + + cutDeltaPhiStarMaxVector = ldeltaphistarcutmax; + cutDeltaPhiStarMinVector = ldeltaphistarcutmin; + cutDeltaEtaMaxVector = ldeltaetacutmax; + cutDeltaEtaMinVector = ldeltaetacutmin; + + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { + std::string dirName = static_cast(DirNames[0]); + for (int j = 1; j < static_cast(ktBins.size() - 1); j++) { + 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 + "/"; + histdetadphisamebeforekT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiBeforeSame").c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadphimixedbeforekT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiBeforeMixed").c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadphisameafterkT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiAfterSame").c_str(), "; #Delta #eta; #Delta #phi", kTH2F, {{100, -0.15, 0.15}, {100, -0.15, 0.15}}); + histdetadphimixedafterkT[j] = mHistogramRegistry->add((dirName + histFolderkT + "detadphidetadphiAfterMixed").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 + 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) { @@ -154,21 +226,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."; @@ -176,7 +248,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) { @@ -186,25 +258,24 @@ class FemtoUniverseDetaDphiStar bool pass = false; for (int i = 0; i < 2; i++) { - auto indexOfDaughter = (ChosenEventType == femtoUniverseContainer::EventType::mixed ? part2.globalIndex() : part2.index()) - 2 + i; - // auto indexOfDaughter = part2.globalIndex() - 2 + i; + auto indexOfDaughter = (ChosenEventType == femto_universe_container::EventType::mixed ? part2.globalIndex() : part2.index()) - 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."; @@ -213,9 +284,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; @@ -223,28 +293,103 @@ class FemtoUniverseDetaDphiStar bool pass = false; for (int i = 0; i < 2; i++) { - auto indexOfDaughterpart1 = (ChosenEventType == femtoUniverseContainer::EventType::mixed ? part1.globalIndex() : part1.index()) - 2 + i; - auto indexOfDaughterpart2 = (ChosenEventType == femtoUniverseContainer::EventType::mixed ? part2.globalIndex() : part2.index()) - 2 + i; - // auto indexOfDaughterpart1 = part1.globalIndex() - 2 + i; - // auto indexOfDaughterpart2 = part2.globalIndex() - 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 (V0V0rect && (dphiAvg > cutDeltaPhiStarMin) && (dphiAvg < cutDeltaPhiStarMax) && (deta > cutDeltaEtaMin) && (deta < cutDeltaEtaMax)) { + pass = true; + } else if (!V0V0rect && std::pow(dphiAvg, 2) / std::pow(cutDeltaPhiStarMax, 2) + std::pow(deta, 2) / std::pow(cutDeltaEtaMax, 2) < 1.) { + 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) { + /// Cascade-Cascade 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 < 7; 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; + if (isSameSignCPR && (daughterpart1.mAntiLambda() != daughterpart2.mAntiLambda())) // mAntiLambda() is used here as sign getter + continue; 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 == 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)) { + 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::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// Track-Cascade combination + if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kTrack || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kCascade) { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar instantiation! Please provide kTrack,kCascade candidates."; + return false; + } + + bool pass = false; + for (int i = 0; i < 3; i++) { + auto indexOfDaughter = (ChosenEventType == femto_universe_container::EventType::mixed ? part2.globalIndex() : part2.index()) - 3 + i; + auto daughter = particles.begin() + indexOfDaughter; + if (isSameSignCPR && (part1.mAntiLambda() != daughter.mAntiLambda())) // mAntiLambda() is used here as sign getter + continue; + auto deta = part1.eta() - daughter.eta(); + 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 ((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."; @@ -252,8 +397,46 @@ class FemtoUniverseDetaDphiStar } } return pass; + } else if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kV0 && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// V0-Cascade combination + if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kV0 || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kCascade) { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar instantiation! Please provide kV0,kCascade candidates."; + return false; + } - } else if constexpr (mPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && mPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kD0) { + bool pass = false; + static constexpr int V0CascChildTable[][2] = {{-1, -1}, {-1, -2}, {-1, -3}, {-2, -1}, {-2, -2}, {-2, -3}}; + for (int i = 0; i < 3; i++) { + auto indexOfDaughterV0 = (ChosenEventType == femto_universe_container::EventType::mixed ? part1.globalIndex() : part1.index()) + V0CascChildTable[i][0]; + auto indexOfDaughterCasc = (ChosenEventType == femto_universe_container::EventType::mixed ? part2.globalIndex() : part2.index()) + V0CascChildTable[i][1]; + auto daughterV0 = particles.begin() + indexOfDaughterV0; + auto daughterCasc = particles.begin() + indexOfDaughterCasc; + if (isSameSignCPR && (daughterV0.mAntiLambda() != daughterCasc.mAntiLambda())) // mAntiLambda() is used here as sign getter + continue; + auto deta = daughterV0.eta() - daughterCasc.eta(); + auto dphiAvg = averagePhiStar(*daughterV0, *daughterCasc, 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 ((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::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) { @@ -264,30 +447,30 @@ 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); // 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 ((dphiAvg > CutDeltaPhiStarMin) && (dphiAvg < CutDeltaPhiStarMax) && (deta > CutDeltaEtaMin) && (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."; @@ -295,7 +478,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) { @@ -306,19 +489,19 @@ 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."; @@ -327,24 +510,24 @@ class FemtoUniverseDetaDphiStar // REMOVING THE "RING" -- CALCULATING THE INVARIANT MASS TLorentzVector part1Vec; TLorentzVector part2Vec; - float mMassOne = TDatabasePDG::Instance()->GetParticle(321)->Mass(); - float mMassTwo = TDatabasePDG::Instance()->GetParticle(321)->Mass(); + 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)) { + 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)) { + 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."; @@ -358,50 +541,261 @@ class FemtoUniverseDetaDphiStar } } + /// Check if pair is close or not + template + bool isClosePairAtITS(Part const& part1, Part const& part2, float lmagfield, uint8_t ChosenEventType) + { + magfield = lmagfield; + + 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) { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar instantiation! Please provide kTrack,kTrack candidates."; + return false; + } + auto deta = part1.eta() - part2.eta(); + auto dphiAvg = part1.phi() - part2.phi(); + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadpisame[0][0]->Fill(deta, dphiAvg); + } 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 (std::pow(dphiAvg, 2) / std::pow(cutDeltaPhiStarMax, 2) + std::pow(deta, 2) / std::pow(cutDeltaEtaMax, 2) < 1.) { + return true; + } else { + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadpisame[0][1]->Fill(deta, dphiAvg); + } 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."; + } + return false; + } + } else { + LOG(fatal) << "FemtoUniversePairCleaner: Combination of objects not defined - quitting!"; + return false; + } + } + + template + bool isClosePairFrac(Part const& part1, Part const& part2, float lmagfield, uint8_t ChosenEventType, bool IsDphiAvgOrDist, float DistMax, float FracMax, bool CircCut) + { + magfield = lmagfield; + + 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) { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar instantiation! Please provide kTrack,kTrack candidates."; + return false; + } + auto deta = part1.eta() - part2.eta(); + auto dphiAvg = averagePhiStar(part1, part2, 0); + auto distfrac = averagePhiStarFrac(part1, part2, DistMax); + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadpisame[0][0]->Fill(deta, dphiAvg); + } 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 (IsDphiAvgOrDist) { + if (CircCut && (std::pow(dphiAvg, 2) / std::pow(cutDeltaPhiStarMax, 2) + std::pow(deta, 2) / std::pow(cutDeltaEtaMax, 2) < 1.)) { + return true; + } else if (!CircCut && (dphiAvg > cutDeltaPhiStarMin) && (dphiAvg < cutDeltaPhiStarMax) && (deta > cutDeltaEtaMin) && (deta < cutDeltaEtaMax)) { + return true; + } else { + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadpisame[0][1]->Fill(deta, dphiAvg); + } 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."; + } + return false; + } + } else { + if (((deta > cutDeltaEtaMin) && (deta < cutDeltaEtaMax)) && (distfrac > FracMax)) { + return true; + } else { + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadpisame[0][1]->Fill(deta, dphiAvg); + } 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."; + } + return false; + } + } + + } else { + LOG(fatal) << "FemtoUniversePairCleaner: Combination of objects not defined - quitting!"; + return false; + } + } + + /// Check if pair is close or not + template + bool isClosePairkT(Part const& part1, Part const& part2, uint8_t ChosenEventType, float ktval, bool CircCut) + { + /// 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) { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar instantiation! Please provide kTrack,kTrack candidates."; + return false; + } + + int ktbinval = 1; + 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; + } + + auto deta = part1.eta() - part2.eta(); + auto dphiAvg = averagePhiStar(part1, part2, 0); + auto DeltaPhiStarMax = static_cast(cutDeltaPhiStarMaxVector[ktbinval]); + auto DeltaPhiStarMin = static_cast(cutDeltaPhiStarMinVector[ktbinval]); + auto DeltaEtaMax = static_cast(cutDeltaEtaMaxVector[ktbinval]); + auto DeltaEtaMin = static_cast(cutDeltaEtaMinVector[ktbinval]); + + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadphisamebeforekT[ktbinval]->Fill(deta, dphiAvg); + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { + histdetadphimixedbeforekT[ktbinval]->Fill(deta, dphiAvg); + } else { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; + } + + if (CircCut && (std::pow(dphiAvg, 2) / std::pow(DeltaPhiStarMax, 2) + std::pow(deta, 2) / std::pow(DeltaEtaMax, 2) < 1.)) { + return true; + } else if (!CircCut && (dphiAvg > DeltaPhiStarMin) && (dphiAvg < DeltaPhiStarMax) && (deta > DeltaEtaMin) && (deta < DeltaEtaMax)) { + return true; + } else { + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadphisameafterkT[ktbinval]->Fill(deta, dphiAvg); + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { + histdetadphimixedafterkT[ktbinval]->Fill(deta, dphiAvg); + } else { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; + } + return false; + } + } + + /// Check if pair is close or not + template + void ClosePairqLCMS(Part const& part1, Part const& part2, float lmagfield, uint8_t ChosenEventType, double qlcms) // add typename Parts and variable parts for adding MClabels + { + magfield = lmagfield; + if constexpr (kPartOneType == o2::aod::femtouniverseparticle::ParticleType::kTrack && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kTrack) { + auto deta = part1.eta() - part2.eta(); + auto dphiAvg = averagePhiStar(part1, part2, 0); + + if (ChosenEventType == femto_universe_container::EventType::same) { + histdetadpiqlcmssame->Fill(qlcms, deta, dphiAvg); + } else if (ChosenEventType == femto_universe_container::EventType::mixed) { + histdetadpiqlcmsmixed->Fill(qlcms, deta, dphiAvg); + } else { + LOG(fatal) << "FemtoUniverseDetaDphiStar: passed arguments don't agree with FemtoUniverseDetaDphiStar's type of events! Please provide same or mixed."; + } + } + } + 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[8] = {"kTrack_kTrack/", "kTrack_kV0/", "kV0_kV0/", "kTrack_kPhi/", "kTrack_kD0/", "kCascade_kCascade/", "kTrack_kCascade/", "kV0_kCascade/"}; + + static constexpr std::string_view HistNamesSame[2][8] = {{"detadphidetadphi0BeforeSame_0", "detadphidetadphi0BeforeSame_1", "detadphidetadphi0BeforeSame_2", + "detadphidetadphi0BeforeSame_3", "detadphidetadphi0BeforeSame_4", "detadphidetadphi0BeforeSame_5", + "detadphidetadphi0BeforeSame_6", "detadphidetadphi0BeforeSameqLCMS"}, + {"detadphidetadphi0AfterSame_0", "detadphidetadphi0AfterSame_1", "detadphidetadphi0AfterSame_2", + "detadphidetadphi0AfterSame_3", "detadphidetadphi0AfterSame_4", "detadphidetadphi0AfterSame_5", + "detadphidetadphi0AfterSame_6", "detadphidetadphi0AfterSameqLCMS"}}; + static constexpr std::string_view HistNamesMixed[2][8] = {{"detadphidetadphi0BeforeMixed_0", "detadphidetadphi0BeforeMixed_1", "detadphidetadphi0BeforeMixed_2", + "detadphidetadphi0BeforeMixed_3", "detadphidetadphi0BeforeMixed_4", "detadphidetadphi0BeforeMixed_5", + "detadphidetadphi0BeforeMixed_6", "detadphidetadphi0BeforeMixedqLCMS"}, + {"detadphidetadphi0AfterMixed_0", "detadphidetadphi0AfterMixed_1", "detadphidetadphi0AfterMixed_2", + "detadphidetadphi0AfterMixed_3", "detadphidetadphi0AfterMixed_4", "detadphidetadphi0AfterMixed_5", + "detadphidetadphi0AfterMixed_6", "detadphidetadphi0AfterMixedqLCMS"}}; + + 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; + + std::vector cutDeltaPhiStarMaxVector; + std::vector cutDeltaPhiStarMinVector; + std::vector cutDeltaEtaMaxVector; + std::vector cutDeltaEtaMinVector; + float magfield; bool plotForEveryRadii = false; - float CutPhiInvMassLow; - float CutPhiInvMassHigh; + float cutPhiInvMassLow; + float cutPhiInvMassHigh; + bool isSameSignCPR = false; + std::vector ktBins; + + std::array, 2>, 7> histdetadpisame{}; + std::array, 2>, 7> histdetadpimixed{}; + std::array, 4> histdetadphisamebeforekT{}; + std::array, 4> histdetadphimixedbeforekT{}; + std::array, 4> histdetadphisameafterkT{}; + std::array, 4> histdetadphimixedafterkT{}; + + std::array, 9>, 7> histdetadpiRadii{}; - std::array, 2>, 2> histdetadpisame{}; - std::array, 2>, 2> histdetadpimixed{}; - std::array, 9>, 2> histdetadpiRadii{}; + std::shared_ptr histdetadpiqlcmssame{}; + std::shared_ptr histdetadpiqlcmsmixed{}; - /// 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(); @@ -419,8 +813,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); @@ -430,12 +824,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; @@ -456,9 +850,39 @@ class FemtoUniverseDetaDphiStar return dPhiAvg / static_cast(entries); } + /// Calculate average phi + template + float averagePhiStarFrac(const T1& part1, const T2& part2, float maxdist) + { + std::vector tmpVec1; + std::vector tmpVec2; + phiAtRadiiTPC(part1, tmpVec1); + phiAtRadiiTPC(part2, tmpVec2); + int num = tmpVec1.size(); + float dphi = 0; + int entries = 0; + double distance = 0; + int badpoints = 0; + + for (int i = 0; i < num; i++) { + if (tmpVec1.at(i) != 999 && tmpVec2.at(i) != 999) { + dphi = tmpVec1.at(i) - tmpVec2.at(i); + entries++; + } else { + dphi = 0; + } + dphi = TVector2::Phi_mpi_pi(dphi); + distance = 2 * TMath::Sin(TMath::Abs(dphi) * 0.5) * TmpRadiiTPC[i]; + if (distance < maxdist) { + badpoints++; + } + } + return badpoints / entries; + } + // 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) { @@ -475,25 +899,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..7b66ac2fc45 --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCalculator.h @@ -0,0 +1,171 @@ +// 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 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 "FemtoUniverseParticleHisto.h" + +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/Configurable.h" + +#include + +#include +#include +#include +#include + +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(static_cast(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); + } + + auto clonedEffHist = static_cast(hEff->Clone()); + clonedEffHist->SetDirectory(nullptr); + + LOGF(info, notify("Successfully loaded %ld"), timestamp); + return clonedEffHist; + } + + EfficiencyConfigurableGroup* config{}; + + bool shouldApplyCorrections = false; + + o2::ccdb::BasicCCDBManager& ccdb{o2::ccdb::BasicCCDBManager::instance()}; + std::array hLoaded{nullptr, nullptr}; +}; + +} // 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..74e37d27a66 --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCorrection.h @@ -0,0 +1,294 @@ +// 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 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 "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace o2::analysis::femto_universe::efficiency_correction +{ +enum ParticleNo : size_t { + ONE = 1, + TWO, +}; + +template +concept IsOneOrTwo = T == ParticleNo::ONE || T == ParticleNo::TWO; + +struct EffCorConfigurableGroup : framework::ConfigurableGroup { + framework::Configurable confEffCorApply{"confEffCorApply", false, "[Efficiency Correction] Should apply efficiency corrections"}; + framework::Configurable confEffCorFillHist{"confEffCorFillHist", false, "[Efficiency Correction] Should fill histograms for 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)"}; + framework::Configurable confEffCorVariables{"confEffCorVariables", "pt", "[Efficiency Correction] Variables for efficiency correction histogram dimensions (available: 'pt'; 'pt,eta'; 'pt,mult'; 'pt,eta,mult')"}; + framework::Configurable confEffCorSetMultToConst{"confEffCorSetMultToConst", false, "[Efficiency Correction] Multiplicity for the histograms set to the constant value"}; +}; + +class EfficiencyCorrection +{ + public: + explicit EfficiencyCorrection(EffCorConfigurableGroup* config) : config(config) // o2-linter: disable=name/function-variable + { + } + + auto init(framework::HistogramRegistry* registry, std::vector axisSpecs) -> void + { + shouldFillHistograms = config->confEffCorFillHist; + shouldSetMultToConst = config->confEffCorSetMultToConst; + + histRegistry = registry; + if (shouldFillHistograms) { + for (const auto& suffix : histSuffix) { + auto path = std::format("{}/{}", histDirectory, suffix); + registry->add((path + "/hMCTruth").c_str(), "MCTruth; #it{p}_{T} (GeV/#it{c}); #it{#eta}; Mult", framework::kTH3F, axisSpecs); + registry->add((path + "/hPrimary").c_str(), "Primary; #it{p}_{T} (GeV/#it{c}); #it{#eta}; Mult", framework::kTH3F, axisSpecs); + registry->add((path + "/hSecondary").c_str(), "Secondary; #it{p}_{T} (GeV/#it{c}); #it{#eta}; Mult", framework::kTH3F, axisSpecs); + registry->add((path + "/hMaterial").c_str(), "Material; #it{p}_{T} (GeV/#it{c}); #it{#eta}; Mult", framework::kTH3F, axisSpecs); + registry->add((path + "/hFake").c_str(), "Fake; #it{p}_{T} (GeV/#it{c}); #it{#eta}; Mult", framework::kTH3F, axisSpecs); + registry->add((path + "/hOther").c_str(), "Other; #it{p}_{T} (GeV/#it{c}); #it{#eta}; Mult", framework::kTH3F, axisSpecs); + } + } + + 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; + } + + if (timestamp > 0) { + switch (getDimensionFromVariables()) { + case 1: + hLoaded[idx] = loadHistFromCCDB(timestamp); + break; + case 2: + hLoaded[idx] = loadHistFromCCDB(timestamp); + break; + case 3: + hLoaded[idx] = loadHistFromCCDB(timestamp); + break; + default: + LOGF(fatal, notify("Unknown configuration for efficiency variables")); + break; + } + } + } + } + } + + template + requires IsOneOrTwo + void fillTruthHist(auto particle) + { + if (!shouldFillHistograms) { + return; + } + + histRegistry->fill(HIST(histDirectory) + HIST("/") + HIST(histSuffix[N - 1]) + HIST("/hMCTruth"), + particle.pt(), + particle.eta(), + shouldSetMultToConst ? 100 : particle.template fdCollision_as().multV0M()); + } + + template + requires IsOneOrTwo + void fillRecoHist(auto particle, int particlePDG) + { + if (!shouldFillHistograms) { + return; + } + + if (!particle.has_fdMCParticle()) { + return; + } + + auto mcParticle = particle.fdMCParticle(); + + if (mcParticle.pdgMCTruth() == particlePDG) { + switch (mcParticle.partOriginMCTruth()) { + case (o2::aod::femtouniverse_mc_particle::kPrimary): + histRegistry->fill(HIST(histDirectory) + HIST("/") + HIST(histSuffix[N - 1]) + HIST("/hPrimary"), + mcParticle.pt(), + mcParticle.eta(), + particle.template fdCollision_as().multV0M()); + break; + + case (o2::aod::femtouniverse_mc_particle::kDaughter): + case (o2::aod::femtouniverse_mc_particle::kDaughterLambda): + case (o2::aod::femtouniverse_mc_particle::kDaughterSigmaplus): + histRegistry->fill(HIST(histDirectory) + HIST("/") + HIST(histSuffix[N - 1]) + HIST("/hSecondary"), + mcParticle.pt(), + mcParticle.eta(), + particle.template fdCollision_as().multV0M()); + break; + + case (o2::aod::femtouniverse_mc_particle::kMaterial): + histRegistry->fill(HIST(histDirectory) + HIST("/") + HIST(histSuffix[N - 1]) + HIST("/hMaterial"), + mcParticle.pt(), + mcParticle.eta(), + particle.template fdCollision_as().multV0M()); + break; + + case (o2::aod::femtouniverse_mc_particle::kFake): + histRegistry->fill(HIST(histDirectory) + HIST("/") + HIST(histSuffix[N - 1]) + HIST("/hFake"), + mcParticle.pt(), + mcParticle.eta(), + particle.template fdCollision_as().multV0M()); + break; + + default: + histRegistry->fill(HIST(histDirectory) + HIST("/") + HIST(histSuffix[N - 1]) + HIST("/hOther"), + mcParticle.pt(), + mcParticle.eta(), + particle.template fdCollision_as().multV0M()); + break; + } + } + } + + template + auto getWeight(ParticleNo partNo, auto particle) -> float + { + auto weight = 1.0f; + auto hWeights = hLoaded[partNo - 1]; + + if (shouldApplyCorrection && hWeights) { + auto dim = static_cast(hWeights->GetDimension()); + if (dim != getDimensionFromVariables()) { + LOGF(fatal, notify("Histogram \"%s\" has wrong dimension %d != %d"), config->confEffCorCCDBPath.value, dim, config->confEffCorVariables.value.size()); + return weight; + } + + auto bin = -1; + if (config->confEffCorVariables.value == "pt") { + bin = hWeights->FindBin(particle.pt()); + } else if (config->confEffCorVariables.value == "pt,eta") { + bin = hWeights->FindBin(particle.pt(), particle.eta()); + } else if (config->confEffCorVariables.value == "pt,mult") { + bin = hWeights->FindBin(particle.pt(), particle.template fdCollision_as().multV0M()); + } else if (config->confEffCorVariables.value == "pt,eta,mult") { + bin = hWeights->FindBin(particle.pt(), particle.eta(), particle.template fdCollision_as().multV0M()); + } else { + LOGF(fatal, notify("Unknown configuration for efficiency variables")); + return weight; + } + + 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(TH1* hist) -> bool + { + if (!hist) { + return true; + } + + const int nBinsX = hist->GetNbinsX() + 2; + const int nBinsY = hist->GetNbinsY() + 2; + const int nBinsZ = hist->GetNbinsZ() + 2; + + for (int x = 0; x < nBinsX; ++x) { + for (int y = 0; y < nBinsY; ++y) { + for (int z = 0; z < nBinsZ; ++z) { + if (hist->GetBinContent(x, y, z) != 0) { + return false; + } + } + } + } + + return true; + } + + template + auto loadHistFromCCDB(const int64_t timestamp) const -> H* + { + 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->confEffCorCCDBPath.value, timestamp); + } + + auto clonedHist = static_cast(hWeights->Clone()); + clonedHist->SetDirectory(nullptr); + + LOGF(info, notify("Successfully loaded %ld"), timestamp); + return clonedHist; + } + + auto getDimensionFromVariables() -> size_t + { + auto parts = std::views::split(config->confEffCorVariables.value, ','); + return std::ranges::distance(parts); + } + + EffCorConfigurableGroup* config{}; + + bool shouldApplyCorrection{false}; + bool shouldFillHistograms{false}; + bool shouldSetMultToConst{false}; + + o2::ccdb::BasicCCDBManager& ccdb{o2::ccdb::BasicCCDBManager::instance()}; + std::array hLoaded{nullptr, nullptr}; + + framework::HistogramRegistry* histRegistry{}; + static constexpr std::string_view histDirectory{"EfficiencyCorrection"}; + static constexpr std::string_view histSuffix[2]{"one", "two"}; +}; + +} // 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 57730fc677d..dfe2bd35d62 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -18,10 +18,11 @@ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEEVENTHISTO_H_ #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + #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,10 +36,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/MultNTrVSMultV0M", "; vMultNTr; MultV0M", kTH2F, {{200, 0, 200}, {16384, 0, 32768}}); + 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 @@ -52,12 +54,13 @@ class FemtoUniverseEventHisto 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..eb9f25dff14 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -20,23 +20,24 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEFEMTOCONTAINER_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEFEMTOCONTAINER_H_ -#include -#include -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" #include "Framework/HistogramRegistry.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include #include "Math/Vector4D.h" -#include "TMath.h" #include "TDatabasePDG.h" +#include "TMath.h" + +#include +#include 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 +47,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 +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 FemtoUniverseFemtoContainer { public: @@ -71,20 +72,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 +95,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 +118,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 +132,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 +147,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 +159,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 +183,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 +211,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..aee87f1a057 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -19,16 +19,15 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEMATH_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEMATH_H_ -#include -#include -#include - -#include "Math/Vector4D.h" #include "Math/Boost.h" +#include "Math/Vector4D.h" #include "TLorentzVector.h" #include "TMath.h" -namespace o2::analysis::femtoUniverse +#include +#include + +namespace o2::analysis::femto_universe { /// \class FemtoUniverseMath @@ -54,17 +53,45 @@ 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(); } + /// Boost particles from LAB Frame to Pair Rest Frame (for lambda daughters) + /// \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 ROOT::Math::PxPyPzMVector boostPRF(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); + + return partOneCMS; + } + /// Compute the qij of a pair of particles /// \tparam T type of tracks /// \param vecparti Particle i PxPyPzMVector @@ -98,21 +125,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 +176,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 +191,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)); + const double tE = trackSum.E(); - 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); - - 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 beta = tPz / tE; + const double gamma = tE / 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 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()); - 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 px1LCMS = fDKOut; + const double py1LCMS = fDKSide; + const double pz1LCMS = fDKLong; + const double pE1LCMS = fDE; - double fDKOutLCMS; - double fDKSideLCMS; - double fDKLongLCMS; + 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()); - double fDKOutPRF; - double fDKSidePRF; - double fDKLongPRF; - - 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..8487ef11bc0 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -17,21 +17,22 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEOBJECTSELECTION_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEOBJECTSELECTION_H_ +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/PID.h" + #include #include #include -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h" -#include "ReconstructionDataFormats/PID.h" -#include "Framework/HistogramRegistry.h" -#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" - using namespace o2; using namespace o2::framework; namespace o2::analysis { -namespace femtoUniverse +namespace femto_universe { /// \class FemtoUniverseObjectSelection @@ -67,7 +68,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 +84,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 +109,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 +127,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(); } @@ -181,7 +182,8 @@ class FemtoUniverseObjectSelection std::vector selVarVec; for (auto it : mSelections) { auto selVar = it.getSelectionVariable(); - if (std::none_of(selVarVec.begin(), selVarVec.end(), [selVar](selVariable a) { return a == selVar; })) { + if (std::none_of(selVarVec.begin(), selVarVec.end(), + [selVar](selVariable a) { return a == selVar; })) { selVarVec.push_back(selVar); } } @@ -193,7 +195,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..b63455ee3cf 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePairAngularWithCentMultKt.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePairAngularWithCentMultKt.h @@ -8,26 +8,26 @@ // In applying this license CERN does not 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; +#include +#include -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 +36,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 +86,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 +154,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 a99d569fd65..32da4810b85 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -14,16 +14,16 @@ /// \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_ #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -#include "Framework/HistogramRegistry.h" -using namespace o2::framework; +#include "Framework/HistogramRegistry.h" -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { /// \class FemtoUniversePairCleaner @@ -57,21 +57,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 +84,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 +100,56 @@ 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::kV0 && kPartTwoType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + /// V0-Cascade combination where part1 is a V0 and part2 is a cascade + if (part1.partType() != o2::aod::femtouniverseparticle::ParticleType::kV0 || part2.partType() != o2::aod::femtouniverseparticle::ParticleType::kCascade) { + LOG(fatal) << "FemtoUniversePairCleaner: passed arguments don't agree with FemtoUniversePairCleaner instantiation! Please provide first argument kV0 candidate and second argument kCascade candidate."; + return false; + } + // part1 v0 children + const auto& posChild1 = particles.iteratorAt(part1.index() - 2); + const auto& negChild1 = particles.iteratorAt(part1.index() - 1); + // part2 cascade children + 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() || posChild1.globalIndex() == bachelor2.globalIndex() || negChild1.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."; @@ -114,7 +163,7 @@ class FemtoUniversePairCleaner return true; } return false; - } 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 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."; @@ -137,9 +186,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 index 9d3c60bea79..377e7677c0b 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePairSHCentMultKt.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePairSHCentMultKt.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -16,16 +16,18 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRSHCENTMULTKT_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPAIRSHCENTMULTKT_H_ -#include -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSHContainer.h" + +#include "Framework/HistogramRegistry.h" + #include #include -#include "Framework/HistogramRegistry.h" +#include +#include -using namespace o2; -using namespace o2::framework; +// using namespace o2::constants::physics; -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { /// \class FemtoUniversePairSHCentMultKt @@ -34,8 +36,8 @@ namespace o2::analysis::femtoUniverse /// 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 +template class PairSHCentMultKt { public: @@ -51,21 +53,21 @@ class PairSHCentMultKt void init(HistogramRegistry* registry, t1& kstarbins, t1& centmultbins, t1& ktbins, int /*maxl*/) { - PairSHCentMultKtRegistry = registry; + pairSHCentMultKtRegistry = registry; AxisSpec kstarAxis = {kstarbins, "#it{k*} (GeV/#it{c})"}; - KStarBins = kstarbins; + kStarBins = kstarbins; - CentMultBins = centmultbins; - KtBins = ktbins; - KtBins.erase(KtBins.begin()); - CentMultBins.erase(CentMultBins.begin()); + centMultBins = centmultbins; + ktBins = ktbins; + ktBins.erase(ktBins.begin()); + centMultBins.erase(centMultBins.begin()); std::string femtoObs1D; - std::vector fels(fMaxJM); - std::vector fems(fMaxJM); - std::vector felsi(fMaxJM); - std::vector femsi(fMaxJM); + 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; @@ -83,128 +85,107 @@ class PairSHCentMultKt el++; em = -el; } - } while (el <= fMaxL); + } 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; + 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 < fMaxJM; ihist++) { + 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]); + suffix = "Ylm" + std::to_string(felsi[ihist]) + std::to_string(femsi[ihist]); } - if (mFolderSuffix[mEventType] == mFolderSuffix[0]) { - fnumsreal[i][j][ihist] = PairSHCentMultKtRegistry->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}); + // 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}); + 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 (mFolderSuffix[mEventType] == mFolderSuffix[0]) { + if (FolderSuffix[EventType] == FolderSuffix[0]) { std::string bufnameNum = "CovNum"; - fcovnum[i][j] = PairSHCentMultKtRegistry->add( - (HistFolderMult + "/" + HistFolderkT + "/" + bufnameNum).c_str(), - "; x; y; z", kTH3D, - {{kstarbins}, - {(fMaxJM * 2), -0.5, ((static_cast(fMaxJM) * 2.0 - 0.5))}, - {(fMaxJM * 2), -0.5, - ((static_cast(fMaxJM) * 2.0 - 0.5))}}); - } else if (mFolderSuffix[mEventType] == mFolderSuffix[1]) { + 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}, - {(fMaxJM * 2), -0.5, ((static_cast(fMaxJM) * 2.0 - 0.5))}, - {(fMaxJM * 2), -0.5, - ((static_cast(fMaxJM) * 2.0 - 0.5))}}); + 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 - /// fill_kT_NumDen \param part1 particle 1 \param part2 particle 2 \param + /// 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 fill_mult_NumDen(T const& part1, T const& part2, uint8_t ChosenEventType, - int maxl, int multval, float ktval) + 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])) { + if ((absmultval >= centMultBins[0]) && (absmultval < centMultBins[1])) { multbinval = 0; - } else if (absmultval <= CentMultBins[2]) { + } else if ((absmultval >= centMultBins[1]) && (absmultval < centMultBins[2])) { multbinval = 1; - } else if (absmultval <= CentMultBins[3]) { + } else if ((absmultval >= centMultBins[2]) && (absmultval < centMultBins[3])) { multbinval = 2; - } else if (ktval <= CentMultBins[4]) { + } else if ((absmultval >= centMultBins[3]) && (absmultval < centMultBins[4])) { multbinval = 3; } else { return; } // std::cout<<"multbinval "< - void fill_kT_NumDen(T const& part1, T const& part2, uint8_t ChosenEventType, - int maxl, int multval, float ktval) + 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])) { + if (ktval >= ktBins[0] && ktval < ktBins[1]) { ktbinval = 0; - } else if (ktval <= KtBins[2]) { + } else if (ktval >= ktBins[1] && ktval < ktBins[2]) { ktbinval = 1; - } else if (ktval <= KtBins[3]) { + } else if (ktval >= ktBins[2] && ktval < ktBins[3]) { ktbinval = 2; - } else if (ktval <= KtBins[4]) { + } 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); + 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 setPDGCodes(const int pdg1, const int pdg2) + void setPionPairMass() { - mMassOne = TDatabasePDG::Instance()->GetParticle(pdg1)->Mass(); - mMassTwo = TDatabasePDG::Instance()->GetParticle(pdg2)->Mass(); - mPDGOne = pdg1; - mPDGTwo = pdg2; + 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 @@ -247,9 +232,9 @@ class PairSHCentMultKt /// \param zeroimag /// \param ilmprim /// \param primimag - int GetBin(int qbin, int ilmzero, int zeroimag, int ilmprim, int primimag) + int getBin(int qbin, int ilmzero, int zeroimag, int ilmprim, int primimag) { - return qbin * fMaxJM * fMaxJM * 4 + (ilmprim * 2 + primimag) * fMaxJM * 2 + + return qbin * kMaxJM * kMaxJM * 4 + (ilmprim * 2 + primimag) * kMaxJM * 2 + ilmzero * 2 + zeroimag; } @@ -261,63 +246,64 @@ class PairSHCentMultKt /// \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) + 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(fMaxJM); + std::vector> fYlmBuffer(kMaxJM); std::vector f3d; - f3d = FemtoUniverseMath::getpairmom3d(part1, mMassOne, part2, mMassTwo, - true, true); + 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 = sqrt(qout * qout + qside * qside + qlong * qlong); - int nqbin = fbinctn[0][0]->GetXaxis()->FindFixBin(kv) - 1; + 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 Ylm; - Ylm.YlmUpToL(fMaxL, qout, qside, qlong, fYlmBuffer.data()); + FemtoUniverseSpherHarMath kYlm; + kYlm.doYlmUpToL(kMaxL, qout, qside, qlong, fYlmBuffer.data()); - if (ChosenEventType == femtoUniverseSHContainer::EventType::same) { - for (int ihist = 0; ihist < fMaxJM; ihist++) { + 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); } - if (nqbin < fbinctn[0][0]->GetNbinsX()) { - for (int ilmzero = 0; ilmzero < fMaxJM; ilmzero++) { - for (int ilmprim = 0; ilmprim < fMaxJM; ilmprim++) { - fcovmnum[fMultBin][fKtBin][GetBin(nqbin, ilmzero, 0, ilmprim, 0)] += - (real(fYlmBuffer[ilmzero]) * real(fYlmBuffer[ilmprim])); - fcovmnum[fMultBin][fKtBin][GetBin(nqbin, ilmzero, 0, ilmprim, 1)] += - (real(fYlmBuffer[ilmzero]) * -imag(fYlmBuffer[ilmprim])); - fcovmnum[fMultBin][fKtBin][GetBin(nqbin, ilmzero, 1, ilmprim, 0)] += - (-imag(fYlmBuffer[ilmzero]) * real(fYlmBuffer[ilmprim])); - fcovmnum[fMultBin][fKtBin][GetBin(nqbin, ilmzero, 1, ilmprim, 1)] += - (-imag(fYlmBuffer[ilmzero]) * -imag(fYlmBuffer[ilmprim])); + 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 == femtoUniverseSHContainer::EventType::mixed) { - for (int ihist = 0; ihist < fMaxJM; ihist++) { + } 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); } - if (nqbin < fbinctd[0][0]->GetNbinsX()) { - for (int ilmzero = 0; ilmzero < fMaxJM; ilmzero++) { - for (int ilmprim = 0; ilmprim < fMaxJM; ilmprim++) { - fcovmden[fMultBin][fKtBin][GetBin(nqbin, ilmzero, 0, ilmprim, 0)] += - (real(fYlmBuffer[ilmzero]) * real(fYlmBuffer[ilmprim])); - fcovmden[fMultBin][fKtBin][GetBin(nqbin, ilmzero, 0, ilmprim, 1)] += - (real(fYlmBuffer[ilmzero]) * -imag(fYlmBuffer[ilmprim])); - fcovmden[fMultBin][fKtBin][GetBin(nqbin, ilmzero, 1, ilmprim, 0)] += - (-imag(fYlmBuffer[ilmzero]) * real(fYlmBuffer[ilmprim])); - fcovmden[fMultBin][fKtBin][GetBin(nqbin, ilmzero, 1, ilmprim, 1)] += - (-imag(fYlmBuffer[ilmzero]) * -imag(fYlmBuffer[ilmprim])); + 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]))); } } } @@ -329,93 +315,81 @@ class PairSHCentMultKt /// \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) + void packCov(uint8_t ChosenEventType, int /*MaxJM*/, int multval, int ktval) { int fMultBin = multval; int fKtBin = ktval; - if (ChosenEventType == femtoUniverseSHContainer::EventType::same) { + if (ChosenEventType == femto_universe_sh_container::EventType::same) { for (int ibin = 1; ibin <= fcovnum[0][0]->GetNbinsX(); ibin++) { - for (int ilmz = 0; ilmz < fMaxJM * 2; ilmz++) { - for (int ilmp = 0; ilmp < fMaxJM * 2; ilmp++) { - auto bin = GetBin(ibin - 1, ilmz / 2, ilmz % 2, ilmp / 2, ilmp % 2); + 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); + fcovnum[fMultBin][fKtBin]->SetBinContent(ibin, ilmz + 1, ilmp + 1, value); } } } - } else if (ChosenEventType == femtoUniverseSHContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_sh_container::EventType::mixed) { for (int ibin = 1; ibin <= fcovden[0][0]->GetNbinsX(); ibin++) { - for (int ilmz = 0; ilmz < fMaxJM * 2; ilmz++) { - for (int ilmp = 0; ilmp < fMaxJM * 2; ilmp++) { - auto bin = GetBin(ibin - 1, ilmz / 2, ilmz % 2, ilmp / 2, ilmp % 2); + 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); + fcovden[fMultBin][fKtBin]->SetBinContent(ibin, ilmz + 1, ilmp + 1, value); } } } } } - /// Function to acces each multiplicity and kT directory and call PackCov + /// Function to acces each multiplicity and kT directory and call packCov /// \param ChosenEventType same or mixed event /// \param MaxJM Maximum value of J - void fill_mult_kT_Cov(uint8_t ChosenEventType, int MaxJM) + void fillMultkTCov(uint8_t ChosenEventType, int MaxJM) { for (int multbinvalcov = 0; - multbinvalcov < static_cast(CentMultBins.size() - 2); + multbinvalcov < static_cast(centMultBins.size() - 1); multbinvalcov++) { for (int ktbinvalcov = 0; - ktbinvalcov < static_cast(KtBins.size() - 1); ktbinvalcov++) { - PackCov(ChosenEventType, MaxJM, multbinvalcov, ktbinvalcov); + ktbinvalcov < static_cast(ktBins.size() - 1); ktbinvalcov++) { + packCov(ChosenEventType, MaxJM, multbinvalcov, ktbinvalcov); } } } private: - std::array, 15>, 10>, 10> - fnumsreal{}; - std::array, 15>, 10>, 10> - fnumsimag{}; - std::array, 15>, 10>, 10> - fdensreal{}; - std::array, 15>, 10>, 10> - fdensimag{}; + 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 fMaxL = 2; - static constexpr int fMaxJM = (fMaxL + 1) * (fMaxL + 1); + static constexpr int kMaxL = 2; + static constexpr int kMaxJM = (kMaxL + 1) * (kMaxL + 1); - std::array, 10>, 10> - fcovmnum{}; ///< Covariance matrix for the numerator - std::array, 10>, 10> - fcovmden{}; ///< Covariance matrix for the numerator + std::array, 7>, 4> fcovmnum{}; ///< Covariance matrix for the numerator + std::array, 7>, 4> fcovmden{}; ///< Covariance matrix for the numerator - std::array, 10>, 10> fcovnum{}; - std::array, 10>, 10> fcovden{}; + std::array, 7>, 4> fcovnum{}; + std::array, 7>, 4> fcovden{}; protected: - HistogramRegistry* PairSHCentMultKtRegistry = nullptr; - 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 - ///< 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; + 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::femtoUniverse +} // 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..f83f480347b 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h @@ -8,26 +8,26 @@ // In applying this license CERN does not 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; +#include +#include -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 +36,64 @@ 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]); + std::string histFolderMult = "mult_" + histSuffix1 + "_" + histSuffix2; + std::string histName = histFolderMult + "/kstar"; + pairWithCentMultKtRegistry->add(histName.c_str(), histTitle.c_str(), HistType::kTH1F, {kstarAxis}); + 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) { + std::string histName3D = histFolderMult + "/q3D"; + pairWithCentMultKtRegistry->add(histName3D.c_str(), histTitle.c_str(), HistType::kTH3F, {kOutAxis, kSideAxis, kLongAxis}); + 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 3f552861ea5..0fa792fb3be 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -20,14 +20,17 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPARTICLEHISTO_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSEPARTICLEHISTO_H_ -#include -#include #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "CommonConstants/MathConstants.h" #include "Framework/HistogramRegistry.h" -using namespace o2::framework; +#include +#include + +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 +52,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, T& tempFitVarpTAxis) // 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,26 +81,27 @@ 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}, {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}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{p}", kTH2F, {{100, 0, 10}, {100, 0, 5}}); - mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{d}", kTH2F, {{100, 0, 10}, {100, 0, 5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hTPCdEdX").c_str(), "; #it{p} (GeV/#it{c}); TPC Signal", kTH2F, {{tempFitVarpTAxis}, {1000, 0, 1000}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{e}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{p}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTPC_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TPC}^{d}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{e}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{p}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaTOF_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{TOF}^{d}", kTH2F, {{tempFitVarpTAxis}, {200, -4.975, 5.025}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_el").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{e}", kTH2F, {{tempFitVarpTAxis}, {100, 0, 5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_pi").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{#pi}", kTH2F, {{tempFitVarpTAxis}, {100, 0, 5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_K").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{K}", kTH2F, {{tempFitVarpTAxis}, {100, 0, 5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_p").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{p}", kTH2F, {{tempFitVarpTAxis}, {100, 0, 5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/nSigmaComb_d").c_str(), "; #it{p} (GeV/#it{c}); n#sigma_{comb}^{d}", kTH2F, {{tempFitVarpTAxis}, {100, 0, 5}}); } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0) { 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}}); @@ -105,8 +109,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 + "/hInvMassXi").c_str(), "; M_{Xi}; Entries", kTH1F, {{2000, 1.f, 1.8f}}); + mHistogramRegistry->add((folderName + folderSuffix + "/hInvMassOmega").c_str(), "; M_{Omega}; Entries", kTH1F, {{2000, 1.f, 1.8f}}); } } @@ -118,25 +132,53 @@ 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, bool isDebug) // 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 + "/hPDG").c_str(), "; PDG; Entries", kTH1I, {{6001, -3000, 3000}}); + 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}}); - 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 + "/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}); - mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_Fake").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); - mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_DaughterLambda").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); - 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}); + if (isDebug) { + mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_Primary").c_str(), "; PDG mother; Entries", kTH1I, {{6001, -3000.5, 3000.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_Daughter").c_str(), "; PDG mother; Entries", kTH1I, {{6001, -3000.5, 3000.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_Material").c_str(), "; PDG mother; Entries", kTH1I, {{6001, -3000.5, 3000.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_WrongCollision").c_str(), "; PDG mother; Entries", kTH1I, {{6001, -3000.5, 3000.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_Fake").c_str(), "; PDG mother; Entries", kTH1I, {{6001, -3000.5, 3000.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_Else").c_str(), "; PDG mother; Entries", kTH1I, {{6001, -3000.5, 3000.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_DaughterLambda").c_str(), "; PDG mother; Entries", kTH1I, {{12001, -6000.5, 6000.5}}); + mHistogramRegistry->add((folderName + folderSuffix + "/Debug/hPDGmother_DaughterSigmaplus").c_str(), "; PDG mother; Entries", kTH1I, {{12001, -6000.5, 6000.5}}); + + 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_Material").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_WrongCollision").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_Fake").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_Else").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_DaughterLambda").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + 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_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 { + 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_Material").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_WrongCollision").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_Fake").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_Else").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}); + + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_DaughterLambda").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + mHistogramRegistry->add((folderName + folderSuffix + "/hDCAxy_DaughterSigmaplus").c_str(), "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {tempFitVarpTAxis, tempFitVarAxis}); + } + } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0) { /// V0 histograms /// to be implemented @@ -145,6 +187,7 @@ class FemtoUniverseParticleHisto /// to be implemented } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kPhi) { // Phi histograms + } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kD0) { // D0/D0bar histograms } else { @@ -168,7 +211,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,13 +240,13 @@ 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, tempFitVarpTAxis); } if (isMC) { - init_base(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis); - init_MC(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis); + init_base(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis); + init_MC(folderName, tempFitVarAxisTitle, tempFitVarpTAxis, tempFitVarAxis, isDebug); } } } @@ -212,62 +255,75 @@ 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()); + } + if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kCascade) { + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassXi"), part.mLambda()); + mHistogramRegistry->fill(histFolder + HIST(o2::aod::femtouniverse_mc_particle::MCTypeName[mc]) + HIST("/hInvMassOmega"), part.mAntiLambda()); } } - 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()); } } @@ -278,46 +334,87 @@ class FemtoUniverseParticleHisto /// \param part Particle /// \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) + template + 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) { - /// Track histograms - switch (mctruthorigin) { - case (o2::aod::femtouniverseMCparticle::kPrimary): - mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Primary"), - part.pt(), part.tempFitVar()); - break; - case (o2::aod::femtouniverseMCparticle::kDaughter): - mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Daughter"), - part.pt(), part.tempFitVar()); - break; - case (o2::aod::femtouniverseMCparticle::kMaterial): - mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Material"), - part.pt(), part.tempFitVar()); - break; - case (o2::aod::femtouniverseMCparticle::kFake): - mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Fake"), - part.pt(), part.tempFitVar()); - break; - case (o2::aod::femtouniverseMCparticle::kDaughterLambda): - mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_DaughterLambda"), - part.pt(), part.tempFitVar()); - break; - case (o2::aod::femtouniverseMCparticle::kDaughterSigmaplus): - mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_DaughterSigmaplus"), - part.pt(), part.tempFitVar()); - break; - default: - LOG(fatal) << "femtouniverseparticleMC: not known value for ParticleOriginMCTruth - please check. Quitting!"; + 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) { + if constexpr (isDebug) { + switch (mctruthorigin) { + case (o2::aod::femtouniverse_mc_particle::kPrimary): + // mHistogramRegistry->fill(histFolder + HIST("_MC/Debug/hPDGmother_Primary"), part.fdMCParticle().motherPDG()); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Primary"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kDaughter): + // mHistogramRegistry->fill(histFolder + HIST("_MC/Debug/hPDGmother_Daughter"), part.fdMCParticle().motherPDG()); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Daughter"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kMaterial): + // mHistogramRegistry->fill(histFolder + HIST("_MC/Debug/hPDGmother_Material"), part.fdMCParticle().motherPDG()); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Material"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kWrongCollision): + // mHistogramRegistry->fill(histFolder + HIST("_MC/Debug/hPDGmother_WrongCollision"), part.fdMCParticle().motherPDG()); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_WrongCollision"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kFake): + // mHistogramRegistry->fill(histFolder + HIST("_MC/Debug/hPDGmother_Fake"), part.fdMCParticle().motherPDG()); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Fake"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kDaughterLambda): + // mHistogramRegistry->fill(histFolder + HIST("_MC/Debug/hPDGmother_DaughterLambda"), part.fdMCParticle().motherPDG()); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_DaughterLambda"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kDaughterSigmaplus): + // mHistogramRegistry->fill(histFolder + HIST("_MC/Debug/hPDGmother_DaughterSigmaplus"), part.fdMCParticle().motherPDG()); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_DaughterSigmaplus"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kElse): + // mHistogramRegistry->fill(histFolder + HIST("_MC/Debug/hPDGmother_Else"), part.fdMCParticle().motherPDG()); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Else"), part.pt(), part.tempFitVar()); + break; + default: + LOGF(info, "femtodreamparticleMC: not known value for ParticleOriginMCTruth --- %d - please check. Quitting!", mctruthorigin); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_NoMCTruthOrigin"), part.pt(), part.tempFitVar()); + } + } else { + switch (mctruthorigin) { + case (o2::aod::femtouniverse_mc_particle::kPrimary): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Primary"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kDaughter): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Daughter"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kMaterial): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Material"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kWrongCollision): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_WrongCollision"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kFake): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Fake"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kDaughterLambda): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_DaughterLambda"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kDaughterSigmaplus): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_DaughterSigmaplus"), part.pt(), part.tempFitVar()); + break; + case (o2::aod::femtouniverse_mc_particle::kElse): + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_Else"), part.pt(), part.tempFitVar()); + break; + + default: + LOGF(info, "femtodreamparticleMC: not known value for ParticleOriginMCTruth --- %d - please check. Quitting!", mctruthorigin); + mHistogramRegistry->fill(histFolder + HIST("_MC/hDCAxy_NoMCTruthOrigin"), part.pt(), part.tempFitVar()); + } } } else if constexpr (mParticleType == o2::aod::femtouniverseparticle::ParticleType::kV0) { /// V0 histograms @@ -333,6 +430,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 @@ -350,14 +480,14 @@ class FemtoUniverseParticleHisto { 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_MC(part, (part.fdMCParticle()).partOriginMCTruth(), (part.fdMCParticle()).pdgMCTruth(), histFolder); + fillQA_base(part.fdMCParticle(), histFolder); + fillQA_MC(part, (part.fdMCParticle()).partOriginMCTruth(), (part.fdMCParticle()).pdgMCTruth(), histFolder); } else { mHistogramRegistry->fill(histFolder + HIST("_MC/hNoMCtruthCounter"), 0); } @@ -365,13 +495,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..c43217ceb72 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -19,26 +19,23 @@ #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" #include "Common/Core/RecoDecay.h" + #include "Framework/HistogramRegistry.h" #include "ReconstructionDataFormats/PID.h" + #include "TLorentzVector.h" -using namespace o2::framework; +#include +#include -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 +59,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 +87,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 +98,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 +122,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 +140,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 +151,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 +160,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 +192,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 +222,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 +236,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 +271,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 +292,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 +305,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 +344,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 +414,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 +494,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 +521,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 +566,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 +605,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 +630,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 +653,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 index 0838ce5e5b3..b99cccb338a 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseSHContainer.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseSHContainer.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FemtoUniverseSHContainer..h +/// \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 @@ -17,25 +17,25 @@ #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 "Framework/HistogramRegistry.h" +#include + #include "Math/Vector4D.h" -#include "TMath.h" #include "TDatabasePDG.h" +#include "TMath.h" -using namespace o2::framework; +#include +#include +#include +#include -namespace o2::analysis::femtoUniverse +namespace o2::analysis::femto_universe { -namespace femtoUniverseSHContainer +namespace femto_universe_sh_container { /// Femtoscopic observable to be computed enum Observable { kstar ///< kstar @@ -45,15 +45,15 @@ enum Observable { kstar ///< kstar enum EventType { same, ///< Pair from same event mixed ///< Pair from mixed event }; -}; // namespace femtoUniverseSHContainer +}; // namespace femto_universe_sh_container -/// \class femtoUniverseSHContainer +/// \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 +template class FemtoUniverseSHContainer { public: @@ -69,13 +69,13 @@ class FemtoUniverseSHContainer template void init(HistogramRegistry* registry, T& kstarbins, int /*maxl*/) { - KStarBins = kstarbins; + kStarBins = kstarbins; std::string femtoObs1D; - std::vector fels(fMaxJM); - std::vector fems(fMaxJM); - std::vector felsi(fMaxJM); - std::vector femsi(fMaxJM); + 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; @@ -93,41 +93,41 @@ class FemtoUniverseSHContainer el++; em = -el; } - } while (el <= fMaxL); + } while (el <= kMaxL); - mHistogramRegistry = registry; + kHistogramRegistry = registry; femtoObs1D = "#it{q} (GeV/#it{c})"; framework::AxisSpec femtoObsAxis1D = {kstarbins, femtoObs1D.c_str()}; - 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]); std::string suffix; - for (int ihist = 0; ihist < fMaxJM; ihist++) { + 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 (mFolderSuffix[mEventType] == mFolderSuffix[0]) { - fnumsreal[ihist] = mHistogramRegistry->add(("NumRe" + suffix).c_str(), ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); - fnumsimag[ihist] = mHistogramRegistry->add(("NumIm" + suffix).c_str(), ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + 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] = mHistogramRegistry->add(("DenRe" + suffix).c_str(), ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); - fdensimag[ihist] = mHistogramRegistry->add(("DenIm" + suffix).c_str(), ("; " + femtoObs1D + "; Entries").c_str(), kTH1D, {femtoObsAxis1D}); + 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 (mFolderSuffix[mEventType] == mFolderSuffix[0]) { + if (kFolderSuffix[kEventType] == kFolderSuffix[0]) { std::string bufnameNum = "CovNum"; - fcovnum = mHistogramRegistry->add((bufnameNum).c_str(), "; x; y; z", kTH3D, {{kstarbins}, {(fMaxJM * 2), -0.5, ((static_cast(fMaxJM) * 2.0 - 0.5))}, {(fMaxJM * 2), -0.5, ((static_cast(fMaxJM) * 2.0 - 0.5))}}); - } else if (mFolderSuffix[mEventType] == mFolderSuffix[1]) { + 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 = mHistogramRegistry->add((bufnameDen).c_str(), "; x; y; z", kTH3D, {{kstarbins}, {(fMaxJM * 2), -0.5, ((static_cast(fMaxJM) * 2.0 - 0.5))}, {(fMaxJM * 2), -0.5, ((static_cast(fMaxJM) * 2.0 - 0.5))}}); + 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]); + 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 @@ -135,10 +135,10 @@ class FemtoUniverseSHContainer /// \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; } /// To compute the bin value for cavariance matrix @@ -147,9 +147,9 @@ class FemtoUniverseSHContainer /// \param zeroimag /// \param ilmprim /// \param primimag - int GetBin(int qbin, int ilmzero, int zeroimag, int ilmprim, int primimag) + int getBin(int qbin, int ilmzero, int zeroimag, int ilmprim, int primimag) { - return qbin * fMaxJM * fMaxJM * 4 + (ilmprim * 2 + primimag) * fMaxJM * 2 + ilmzero * 2 + zeroimag; + 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 @@ -159,54 +159,51 @@ class FemtoUniverseSHContainer /// \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*/) + void addEventPair(T const& part1, T const& part2, uint8_t ChosenEventType, int /*maxl*/, bool isiden) { - // int fMaxL = 2; - // int fMaxJM = (2+1)*(2+1); - std::vector> fYlmBuffer(fMaxJM); + std::vector> fYlmBuffer(kMaxJM); std::vector f3d; - f3d = FemtoUniverseMath::getpairmom3d(part1, mMassOne, part2, mMassTwo, true, true); + f3d = FemtoUniverseMath::newpairfunc(part1, kMassOne, part2, kMassTwo, isiden); - // const float qstar = f3d[0]; + const float kv = f3d[0]; const float qout = f3d[1]; const float qside = f3d[2]; const float qlong = f3d[3]; - double kv = sqrt(qout * qout + qside * qside + qlong * qlong); int nqbin = fbinctn->GetXaxis()->FindFixBin(kv) - 1; - FemtoUniverseSpherHarMath Ylm; - Ylm.YlmUpToL(fMaxL, qout, qside, qlong, fYlmBuffer.data()); + FemtoUniverseSpherHarMath kYlm; + kYlm.doYlmUpToL(kMaxL, qout, qside, qlong, fYlmBuffer.data()); - if (ChosenEventType == femtoUniverseSHContainer::EventType::same) { - for (int ihist = 0; ihist < fMaxJM; ihist++) { + 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 < fMaxJM; ilmzero++) { - for (int ilmprim = 0; ilmprim < fMaxJM; 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])); + 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 == femtoUniverseSHContainer::EventType::mixed) { - for (int ihist = 0; ihist < fMaxJM; ihist++) { + } 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 < fMaxJM; ilmzero++) { - for (int ilmprim = 0; ilmprim < fMaxJM; 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])); + 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])); } } } @@ -216,23 +213,23 @@ class FemtoUniverseSHContainer /// 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*/) + void packCov(uint8_t ChosenEventType, int /*MaxJM*/) { - if (ChosenEventType == femtoUniverseSHContainer::EventType::same) { + if (ChosenEventType == femto_universe_sh_container::EventType::same) { for (int ibin = 1; ibin <= fcovnum->GetNbinsX(); ibin++) { - for (int ilmz = 0; ilmz < fMaxJM * 2; ilmz++) { - for (int ilmp = 0; ilmp < fMaxJM * 2; ilmp++) { - auto bin = GetBin(ibin - 1, ilmz / 2, ilmz % 2, ilmp / 2, ilmp % 2); + 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 == femtoUniverseSHContainer::EventType::mixed) { + } else if (ChosenEventType == femto_universe_sh_container::EventType::mixed) { for (int ibin = 1; ibin <= fcovden->GetNbinsX(); ibin++) { - for (int ilmz = 0; ilmz < fMaxJM * 2; ilmz++) { - for (int ilmp = 0; ilmp < fMaxJM * 2; ilmp++) { - auto bin = GetBin(ibin - 1, ilmz / 2, ilmz % 2, ilmp / 2, ilmp % 2); + 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); } @@ -253,23 +250,23 @@ class FemtoUniverseSHContainer TH1D* fbinctn; TH1D* fbinctd; - static constexpr int fMaxL = 1; - static constexpr int fMaxJM = (fMaxL + 1) * (fMaxL + 1); + 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 + std::array fcovmnum{}; ///< Covariance matrix for the numerator + std::array fcovmden{}; ///< Covariance matrix for the numerator 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 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 KStarBins; + 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::femtoUniverse +} // 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..63d9646cdde 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseSelection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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..4a97c83865d --- /dev/null +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseSoftPionRemoval.h @@ -0,0 +1,121 @@ +// 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 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 "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/HistogramRegistry.h" + +#include + +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 index 07fe6f4e996..082ddd25663 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseSpherHarMath.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseSpherHarMath.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -16,16 +16,16 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESPHERHARMATH_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSESPHERHARMATH_H_ -#include -#include -#include - -#include "Math/Vector4D.h" #include "Math/Boost.h" +#include "Math/Vector4D.h" #include "TLorentzVector.h" #include "TMath.h" -namespace o2::analysis::femtoUniverse +#include +#include +#include + +namespace o2::analysis::femto_universe { /// \class FemtoUniverseMath @@ -34,39 +34,39 @@ class FemtoUniverseSpherHarMath { public: /// Values of various coefficients - void InitializeYlms() + void initializeYlms() { - double oneoversqrtpi = 1.0 / TMath::Sqrt(TMath::Pi()); + 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 * sqrt(3.0 / 2.0) * oneoversqrtpi; - fgPrefactors[2] = 0.5 * sqrt(3.0) * oneoversqrtpi; + 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 * sqrt(15.0 / 2.0) * oneoversqrtpi; - fgPrefactors[5] = 0.5 * sqrt(15.0 / 2.0) * oneoversqrtpi; - fgPrefactors[6] = 0.25 * sqrt(5.0) * oneoversqrtpi; + 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 * sqrt(35.0) * oneoversqrtpi; - fgPrefactors[10] = 0.25 * sqrt(105.0 / 2.0) * oneoversqrtpi; - fgPrefactors[11] = 0.125 * sqrt(21.0) * oneoversqrtpi; - fgPrefactors[12] = 0.25 * sqrt(7.0) * oneoversqrtpi; + 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 * sqrt(35.0 / 2.0) * oneoversqrtpi; - fgPrefactors[17] = 3.0 / 8.0 * sqrt(35.0) * oneoversqrtpi; - fgPrefactors[18] = 3.0 / 8.0 * sqrt(5.0 / 2.0) * oneoversqrtpi; - fgPrefactors[19] = 3.0 / 8.0 * sqrt(5.0) * oneoversqrtpi; + 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]; @@ -74,12 +74,12 @@ class FemtoUniverseSpherHarMath fgPrefactors[24] = fgPrefactors[16]; // l=5 prefactors - fgPrefactors[25] = 3.0 / 32.0 * sqrt(77.0) * oneoversqrtpi; - fgPrefactors[26] = 3.0 / 16.0 * sqrt(385.0 / 2.0) * oneoversqrtpi; - fgPrefactors[27] = 1.0 / 32.0 * sqrt(385.0) * oneoversqrtpi; - fgPrefactors[28] = 1.0 / 8.0 * sqrt(1155.0 / 2.0) * oneoversqrtpi; - fgPrefactors[29] = 1.0 / 16.0 * sqrt(165.0 / 2.0) * oneoversqrtpi; - fgPrefactors[30] = 1.0 / 16.0 * sqrt(11.0) * oneoversqrtpi; + 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]; @@ -105,7 +105,7 @@ class FemtoUniverseSpherHarMath /// \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) + void legendreUpToYlm(int lmax, double ctheta, double* lbuf) { // Calculate a set of legendre polynomials up to a given l // with spherical input @@ -113,7 +113,7 @@ class FemtoUniverseSpherHarMath double coss[6]; sins[0] = 0.0; coss[0] = 1.0; - sins[1] = sqrt(1 - ctheta * ctheta); + sins[1] = std::sqrt(1 - ctheta * ctheta); coss[1] = ctheta; for (int iter = 2; iter < 6; iter++) { sins[iter] = sins[iter - 1] * sins[1]; @@ -165,21 +165,21 @@ class FemtoUniverseSpherHarMath } /// Function to calculate a set of Ylms up to a given l with cartesian input - void YlmUpToL(int lmax, double x, double y, double z, std::complex* ylms) + void doYlmUpToL(int lmax, double x, double y, double z, std::complex* ylms) { double ctheta, phi; - double r = sqrt(x * x + y * y + z * z); - if (r < 1e-10 || fabs(z) < 1e-10) + 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 = atan2(y, x); - YlmUpToL(lmax, ctheta, phi, ylms); + 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 YlmUpToL(int lmax, double ctheta, double phi, std::complex* ylms) + void doYlmUpToL(int lmax, double ctheta, double phi, std::complex* ylms) { int lcur = 0; double lpol; @@ -188,12 +188,12 @@ class FemtoUniverseSpherHarMath double sins[6]; double lbuf[36]; - LegendreUpToYlm(lmax, ctheta, lbuf); - InitializeYlms(); + legendreUpToYlm(lmax, ctheta, lbuf); + initializeYlms(); for (int iter = 1; iter <= lmax; iter++) { - coss[iter - 1] = cos(iter * phi); - sins[iter - 1] = sin(iter * phi); + coss[iter - 1] = std::cos(iter * phi); + sins[iter - 1] = std::sin(iter * phi); } ylms[lcur++] = fgPrefactors[0] * lbuf[0] * std::complex(1, 0); @@ -212,13 +212,13 @@ class FemtoUniverseSpherHarMath } private: - static std::complex Ceiphi(double phi); + static std::complex fCeiphi(double phi); std::array fgPrefactors; std::array fgPrefshift; std::array fgPlmshift; }; -} // namespace o2::analysis::femtoUniverse +} // 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..51c711c8165 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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 @@ -18,40 +18,42 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSETRACKSELECTION_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUNIVERSETRACKSELECTION_H_ -#include -#include -#include -#include - +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -#include "Common/DataModel/TrackSelectionTables.h" + #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseObjectSelection.h" -#include "ReconstructionDataFormats/PID.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/PID.h" -using namespace o2::framework; +#include +#include +#include -namespace o2::analysis::femtoUniverse +// using namespace o2::framework; + +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 +61,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 +89,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 +112,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 +142,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 +161,10 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection(prefix); - outString += static_cast(mSelectionNames[iSel]); + outString += static_cast(kSelectionNames[iSel]); outString += suffix; return outString; } @@ -172,7 +175,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 +185,18 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection(prefix); - outString += static_cast(mSelectionHelper[iSel]); + outString += static_cast(kSelectionHelper[iSel]); return outString; } @@ -221,6 +224,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 +257,7 @@ class FemtoUniverseTrackSelection : public FemtoUniverseObjectSelection +template void FemtoUniverseTrackSelection::init(HistogramRegistry* registry) { if (registry) { @@ -298,20 +306,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 +344,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 +401,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 +409,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 +435,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 +472,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 +485,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 +501,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 +514,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 +576,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 +601,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..8b45f664f15 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h +++ b/PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -19,25 +19,21 @@ #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" #include "Common/Core/RecoDecay.h" + #include "Framework/HistogramRegistry.h" #include "ReconstructionDataFormats/PID.h" -using namespace o2::framework; +#include +#include -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 +59,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 +85,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 +96,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 +120,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 +138,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 +149,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 +158,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 +190,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 +220,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 +235,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 +270,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 +289,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 +302,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 +330,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 +370,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 +440,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 +520,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 +547,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 +590,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 +631,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 77% rename from PWGCF/FemtoUniverse/Core/FemtoUtils.h rename to PWGCF/FemtoUniverse/Core/femtoUtils.h index 54dbbe4e02b..ddc1833c335 100644 --- a/PWGCF/FemtoUniverse/Core/FemtoUtils.h +++ b/PWGCF/FemtoUniverse/Core/femtoUtils.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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 @@ -17,16 +17,18 @@ #ifndef PWGCF_FEMTOUNIVERSE_CORE_FEMTOUTILS_H_ #define PWGCF_FEMTOUNIVERSE_CORE_FEMTOUTILS_H_ -#include -#include -#include -#include "Framework/ASoAHelpers.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -namespace o2::analysis::femtoUniverse +#include "Framework/ASoAHelpers.h" + +#include +#include +#include + +namespace o2::analysis::femto_universe { -enum kDetector { kTPC, +enum KDetector { kTPC, kTPCTOF, kNdetectors }; @@ -51,19 +53,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 +78,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 +90,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 +103,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..4fe562d7fef 100644 --- a/PWGCF/FemtoUniverse/DataModel/FemtoDerived.h +++ b/PWGCF/FemtoUniverse/DataModel/FemtoDerived.h @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -9,39 +9,52 @@ // 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_ -#include -#include "Framework/ASoA.h" -#include "MathUtils/Utils.h" -#include "Framework/DataTypes.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/DataTypes.h" #include "Framework/Expressions.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" +#include "MathUtils/Utils.h" + +#include 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 @@ -53,6 +66,7 @@ enum ParticleType { kV0, //! V0 kV0Child, //! Child track of a V0 kCascade, //! Cascade + kCascadeV0Child, //! Child track of a V0 coming from a cascade kCascadeBachelor, //! Bachelor track of a cascade kPhi, //! Phi meson kPhiChild, //! Child track of a Phi meson @@ -61,27 +75,28 @@ enum ParticleType { kNParticleTypes //! Number of particle types }; -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 ParticleTypeName[kNParticleTypes] = {"Tracks", "MCTruthTracks", "V0", "V0Child", "Cascade", "CascadeV0Child", "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 +108,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 +124,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 +141,16 @@ 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 + 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, @@ -145,15 +162,33 @@ DECLARE_SOA_TABLE(FDParticles, "AOD", "FDPARTICLE", femtouniverseparticle::P); using FDParticle = FDParticles::iterator; +/// FemtoUniverseCascadeTrack +namespace femtouniversecascparticle +{ +DECLARE_SOA_INDEX_COLUMN(FDParticle, fdParticle); +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(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 +208,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 +221,29 @@ DECLARE_SOA_TABLE(FDExtParticles, "AOD", "FDEXTPARTICLE", pidtof_tiny::TOFNSigmaDe); using FDFullParticle = FDExtParticles::iterator; +DECLARE_SOA_TABLE(FDCascParticles, "AOD", "FDCASCPARTICLE", + o2::soa::Index<>, + femtouniverseparticle::FdCollisionId, + femtouniversecascparticle::FDParticleId, + 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 { @@ -195,10 +251,14 @@ enum ParticleOriginMCTruth { kDaughter, //! Particle from a decay kMaterial, //! Particle from a material kNotPrimary, //! Not primary particles (kept for compatibility reasons with the FullProducer task. will be removed, since we look at "non primaries" more differentially now) - kFake, //! particle, that has NOT the PDG code of the current analysed particle + 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 - kNOriginMCTruthTypes + kPrompt, //! Origin for D0/D0bar mesons + kNonPrompt, //! Origin for D0/D0bar mesons + kNOriginMCTruthTypes, + kElse, + kWrongCollision //! Origin for the wrong collision }; //! Naming of the different OriginMCTruth types @@ -209,7 +269,9 @@ static constexpr std::string_view ParticleOriginMCTruthName[kNOriginMCTruthTypes "_NotPrimary", "_Fake", "_DaughterLambda", - "DaughterSigmaPlus"}; + "DaughterSigmaPlus", + "_Prompt", + "_NonPrompt"}; /// Distinguished between reconstructed and truth enum MCType { @@ -221,39 +283,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/Macros/calculateEfficiencyCorrection.cxx b/PWGCF/FemtoUniverse/Macros/calculateEfficiencyCorrection.cxx new file mode 100644 index 00000000000..3880661d9f7 --- /dev/null +++ b/PWGCF/FemtoUniverse/Macros/calculateEfficiencyCorrection.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. + +/// \file calculateEfficiencyCorrection.cxx +/// \brief Macro for calculating efficiency corrections based on 3D histograms +/// \author Dawid Karpiński, WUT Warsaw, dawid.karpinski@cern.ch + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include // NOLINT +#include +#include +#include + +namespace fs = std::filesystem; + +auto* getHistogram(TFile* file, const std::string& name) +{ + return dynamic_cast(file->Get(name.c_str())); +} + +auto* projectHistogram(TH3* hist, const std::string& projection) +{ + return hist->Project3D(projection.c_str()); +} + +template +H* cloneHistogram(H* hist, const std::string& name) +{ + return dynamic_cast(hist->Clone(name.c_str())); +} + +auto forEachBin(TH1* hist, auto func) -> void +{ + if (hist->GetDimension() == 1) { + for (auto x{1}; x <= hist->GetNbinsX(); ++x) { + func(x, 0, 0); + } + } else if (hist->GetDimension() == 2) { + for (auto x{1}; x <= hist->GetNbinsX(); ++x) { + for (auto y{1}; y <= hist->GetNbinsY(); ++y) { + func(x, y, 0); + } + } + } else if (hist->GetDimension() == 3) { + for (auto x{1}; x <= hist->GetNbinsX(); ++x) { + for (auto y{1}; y <= hist->GetNbinsY(); ++y) { + for (auto z{1}; z <= hist->GetNbinsZ(); ++z) { + func(x, y, z); + } + } + } + } else { + assert(false && "should not happen"); + } +} + +auto setAxisTitles(TH1* hist, const std::string& projection) -> void +{ + auto* xAxis{hist->GetXaxis()}; + auto* yAxis{hist->GetYaxis()}; + auto* zAxis{hist->GetZaxis()}; + + xAxis->SetTitle("#it{p}_{T} (GeV/#it{c})"); + + if (hist->GetDimension() == 2) { + if (projection == "yx") { + yAxis->SetTitle("#it{#eta}"); + } else if (projection == "zx") { + yAxis->SetTitle("mult"); + } + } else if (hist->GetDimension() == 3) { + yAxis->SetTitle("#it{#eta}"); + zAxis->SetTitle("mult"); + } +} + +auto calculateEfficiencyCorrection(const fs::path& resultsPath, const fs::path& histPath, const std::string& projection) -> void +{ + assert(!resultsPath.empty() && !histPath.empty()); + if (projection != "" && projection != "x" && projection != "yx" && projection != "zx") { + std::cerr << "Error: projection must be one of: x, yx, zx\n"; + std::exit(1); + return; + } + + auto isAlien{false}; + if (resultsPath.string().starts_with("alien://")) { + TGrid::Connect("alien://"); + isAlien = true; + } + + auto* resultFile{TFile::Open(resultsPath.c_str())}; + assert(resultFile != nullptr && !resultFile->IsZombie()); + + using namespace std::chrono; + auto now{duration_cast(system_clock::now().time_since_epoch()).count()}; + auto outputPath{isAlien ? std::filesystem::current_path() : resultsPath.parent_path()}; + outputPath /= std::format("{}-effcor-{}.root", resultsPath.stem().string(), now); + + auto* outputFile{TFile::Open(outputPath.c_str(), "RECREATE")}; + assert(outputFile != nullptr && !outputFile->IsZombie()); + + auto* histTruthBase{getHistogram(resultFile, histPath / "hMCTruth")}; + auto* histPrimaryBase{getHistogram(resultFile, histPath / "hPrimary")}; + auto* histSecondaryBase{getHistogram(resultFile, histPath / "hSecondary")}; + + assert(histTruthBase); + assert(histPrimaryBase); + assert(histSecondaryBase); + + TH1* histTruth{histTruthBase}; + TH1* histPrimary{histPrimaryBase}; + TH1* histSecondary{histSecondaryBase}; + + if (projection != "") { + histPrimary = projectHistogram(histPrimaryBase, projection); + histSecondary = projectHistogram(histSecondaryBase, projection); + histTruth = projectHistogram(histTruthBase, projection); + } + + auto* histTotal{cloneHistogram(histPrimary, "hTotal")}; + histTotal->Add(histSecondary); + + auto* histEfficiency{cloneHistogram(histPrimary, "hEfficiency")}; + histEfficiency->Reset(); + setAxisTitles(histEfficiency, projection); + + auto* histWeights{cloneHistogram(histPrimary, "hWeights")}; + histWeights->Reset(); + setAxisTitles(histWeights, projection); + + auto* histCont{cloneHistogram(histPrimary, "hCont")}; + histCont->Reset(); + setAxisTitles(histCont, projection); + + forEachBin(histPrimary, [&](int x, int y, int z) { + auto primVal{histPrimary->GetBinContent(x, y, z)}; + auto primErr{histPrimary->GetBinError(x, y, z)}; + + auto secVal{histSecondary->GetBinContent(x, y, z)}; + auto secErr{histSecondary->GetBinError(x, y, z)}; + + auto truthVal{histTruth->GetBinContent(x, y, z)}; + auto truthErr{histTruth->GetBinError(x, y, z)}; + + auto effVal{0.}; + auto effErr{0.}; + if (truthVal > 0) { + effVal = primVal / truthVal; + effErr = std::sqrt(std::pow(primErr / truthVal, 2) + std::pow((primVal * truthErr / std::pow(truthVal, 2)), 2)); + } + + histEfficiency->SetBinContent(x, y, z, effVal); + histEfficiency->SetBinError(x, y, z, effErr); + + auto totalVal{primVal + secVal}; + auto totalErr{std::hypot(primErr, secErr)}; + + auto contVal{0.}; + auto contErr{0.}; + if (totalVal > 0) { + contVal = secVal / totalVal; + contErr = std::sqrt(std::pow(secErr / totalVal, 2) + std::pow((secVal * totalErr / std::pow(totalVal, 2)), 2)); + } + + histCont->SetBinContent(x, y, z, contVal); + histCont->SetBinError(x, y, z, contErr); + + auto weightVal{0.}; + auto weightErr{0.}; + if (effVal > 0) { + weightVal = (1 - contVal) / effVal; + weightErr = std::sqrt(std::pow(contErr / effVal, 2) + std::pow((1 - contVal) * effErr / std::pow(effVal, 2), 2)); + } + + histWeights->SetBinContent(x, y, z, weightVal); + histWeights->SetBinError(x, y, z, weightErr); + }); + + outputFile->WriteTObject(histEfficiency); + outputFile->WriteTObject(histCont); + outputFile->WriteTObject(histWeights); + + outputFile->Close(); + resultFile->Close(); +} + +auto printUsage(const char* name) -> void +{ + std::cerr << "Usage: " << name << "\n" + << " -f \n" + << " -d \n" + << " -p [optional, default: no projection, 3D histogram]\n" + << " Available projections:\n" + << " x - projection onto pT axis (1D histogram)\n" + << " yx - projection onto pT, eta (2D histogram)\n" + << " zx - projection onto pT, mult (2D histogram)\n"; +} + +int main(int argc, char** argv) +{ + std::string results{""}, hist{""}, proj{""}; + auto flag{0}; + + while ((flag = getopt(argc, argv, "f:d:p:")) != -1) { + switch (flag) { + case 'f': + results = optarg; + break; + case 'd': + hist = optarg; + break; + case 'p': + proj = optarg; + break; + default: + printUsage(argv[0]); + return 1; + } + } + + if (results.empty() || hist.empty()) { + printUsage(argv[0]); + return 1; + } + + calculateEfficiencyCorrection(results, hist, proj); + return 0; +} diff --git a/PWGCF/FemtoUniverse/Macros/femto_universe_efficiency_calculator.py b/PWGCF/FemtoUniverse/Macros/femto_universe_efficiency_calculator.py new file mode 100755 index 00000000000..2a0b822d215 --- /dev/null +++ b/PWGCF/FemtoUniverse/Macros/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/Macros/femto_universe_efficiency_phi_calculator.py b/PWGCF/FemtoUniverse/Macros/femto_universe_efficiency_phi_calculator.py new file mode 100644 index 00000000000..97f5bede27a --- /dev/null +++ b/PWGCF/FemtoUniverse/Macros/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..b2d03f48998 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerMCTruthTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerMCTruthTask.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -14,35 +14,36 @@ /// \author Malgorzata Janik, WUT Warsaw, majanik@cern.ch /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch -#include -#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 "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" #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 "Framework/ASoAHelpers.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" -#include "Math/Vector4D.h" -#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "ReconstructionDataFormats/Track.h" -#include "TMath.h" -#include "TLorentzVector.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include 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 { @@ -71,43 +72,43 @@ int getRowDaughters(int daughID, T const& vecID) return rowInPrimaryTrackTableDaugh; } -struct femtoUniverseProducerMCTruthTask { +struct FemtoUniverseProducerMCTruthTask { int mRunNumber; float mMagField; 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 - Configurable ConfIsRun3{"ConfIsRun3", false, "Running on Run3 or pilot"}; - Configurable ConfIsMC{"ConfIsMC", false, "Running on MC; implemented only for Run3"}; - 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 ConfIsActivateV0{"ConfIsActivateV0", true, "Activate filling of V0 into femtouniverse tables"}; - Configurable ConfIsActivatePhi{"ConfIsActivatePhi", true, "Activate filling of Phi into femtouniverse tables"}; - Configurable> ConfPDGCodes{"ConfPDGCodes", std::vector{211, -211, 2212, -2212, 333}, "PDG of particles to be stored"}; - Configurable ConfAnalysisWithPID{"ConfAnalysisWithPID", true, "1: take only particles with specified PDG, 0: all particles"}; + Configurable confIsRun3{"confIsRun3", false, "Running on Run3 or pilot"}; + Configurable confIsMC{"confIsMC", false, "Running on MC; implemented only for Run3"}; + 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> confPDGCodes{"confPDGCodes", std::vector{211, -211, 2212, -2212, 333}, "PDG of particles to be stored"}; + Configurable confAnalysisWithPID{"confAnalysisWithPID", true, "1: take only particles with specified PDG, 0: all particles"}; /// Event cuts - 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 ConfCentFT0Min{"ConfCentFT0Min", 0.f, "Min CentFT0 value for centrality selection"}; - Configurable ConfCentFT0Max{"ConfCentFT0Max", 200.f, "Max CentFT0 value for centrality selection"}; + 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 confCentFT0Min{"confCentFT0Min", 0.f, "Min CentFT0 value for centrality selection"}; + Configurable confCentFT0Max{"confCentFT0Max", 200.f, "Max CentFT0 value for centrality selection"}; + Configurable confDoSpher{"confDoSpher", false, "Calculate sphericity. If false sphericity will take value of 2."}; // Track cuts struct : o2::framework::ConfigurableGroup { - Configurable ConfPtLowFilterCut{"ConfPtLowFilterCut", 0.14, "Lower limit for Pt for the filtering tracks"}; // pT low - Configurable ConfPtHighFilterCut{"ConfPtHighFilterCut", 5.0, "Higher limit for Pt for the filtering tracks"}; // pT high - Configurable ConfEtaFilterCut{"ConfEtaFilterCut", 0.8, "Eta cut for the filtering tracks"}; + Configurable confPtLowFilterCut{"confPtLowFilterCut", 0.14, "Lower limit for Pt for the filtering tracks"}; // pT low + Configurable confPtHighFilterCut{"confPtHighFilterCut", 5.0, "Higher limit for Pt for the filtering tracks"}; // pT high + Configurable confEtaFilterCut{"confEtaFilterCut", 0.8, "Eta cut for the filtering tracks"}; } ConfFilteringTracks; + // D0/D0bar cuts + Configurable yD0CandGenMax{"yD0CandGenMax", 0.5, "Rapidity cut for the D0/D0bar mesons"}; + FemtoUniverseCollisionSelection colCuts; FemtoUniverseTrackSelection trackCuts; HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::QAObject}; @@ -118,10 +119,10 @@ struct femtoUniverseProducerMCTruthTask { LOGF(fatal, "Neither processFullData nor processFullMC enabled. 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.init(&qaRegistry); + trackCuts.init(&qaRegistry); mRunNumber = 0; mMagField = 0.0; @@ -135,16 +136,23 @@ struct femtoUniverseProducerMCTruthTask { } template - void fillCollisions(CollisionType const& col, TrackType const& /*tracks*/) + void fillCollisions(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; - int multNtr = 0; + float mult = confIsRun3 ? c.multFV0M() : 0.5 * (c.multFV0M()); + int multNtr = confIsRun3 ? c.multNTracksPV() : c.multTracklets(); + // Removing collisions with Zvtx > 10 cm + if (std::abs(vtxZ) > confEvtZvtx) { + continue; + } // 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 (confDoSpher) { + outputCollision(vtxZ, mult, multNtr, colCuts.computeSphericity(col, tracks), mMagField); + } else { + outputCollision(vtxZ, mult, multNtr, 2, mMagField); + } } } @@ -153,22 +161,24 @@ struct femtoUniverseProducerMCTruthTask { { std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children - 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() < -ConfFilteringTracks.ConfEtaFilterCut || particle.eta() > ConfFilteringTracks.ConfEtaFilterCut) - continue; - if (particle.pt() < ConfFilteringTracks.ConfPtLowFilterCut || particle.pt() > ConfFilteringTracks.ConfPtHighFilterCut) + if (particle.pt() < ConfFilteringTracks.confPtLowFilterCut || particle.pt() > ConfFilteringTracks.confPtHighFilterCut) continue; - uint32_t pdgCode = (uint32_t)particle.pdgCode(); + int pdgCode = particle.pdgCode(); - if (ConfAnalysisWithPID) { + if (confAnalysisWithPID) { bool pass = false; - std::vector tmpPDGCodes = ConfPDGCodes; // necessary due to some features of the Configurable - for (uint32_t pdg : tmpPDGCodes) { - if (pdgCode == 333) { + std::vector tmpPDGCodes = confPDGCodes; // necessary due to some features of the Configurable + for (auto const& pdg : tmpPDGCodes) { + if (pdgCode == Pdg::kPhi) { // phi meson + pass = true; + } else if (std::abs(pdgCode) == Pdg::kD0) { // D0(bar) meson + pass = true; + } else if (pdgCode == Pdg::kDPlus) { // D+ meson pass = true; } else if (static_cast(pdg) == static_cast(pdgCode)) { if (particle.isPhysicalPrimary()) @@ -179,6 +189,31 @@ struct femtoUniverseProducerMCTruthTask { continue; } + // check if D0/D0bar mesons pass the rapidity cut + // if pass then saving the orgin of D0/D0bar + // check if tracks (besides D0/D0bar) pass pseudorapidity cut + int8_t origin = -99; + if (std::abs(particle.pdgCode()) == Pdg::kD0) { + if (std::abs(particle.y()) > yD0CandGenMax) { + continue; + } else { + origin = RecoDecay::getCharmHadronOrigin(tracks, particle); + } + } else { + if (std::abs(particle.eta()) > ConfFilteringTracks.confEtaFilterCut) { + continue; + } else { + origin = -99; + } + } + + /// check if we end-up with the correct final state using MC info + int8_t sign = 0; + if (std::abs(pdgCode) == Pdg::kD0 && !RecoDecay::isMatchedMCGen(tracks, particle, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign)) { + /// check if we have D0(bar) → π± K∓ + continue; + } + // we cannot use isSelectedMinimal since it takes Ncls // if (!trackCuts.isSelectedMinimal(track)) { // continue; @@ -187,7 +222,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 @@ -200,8 +235,8 @@ struct femtoUniverseProducerMCTruthTask { pdgCode, pdgCode, childIDs, - 0, - 0); + origin, + -999.); } } @@ -216,11 +251,11 @@ struct femtoUniverseProducerMCTruthTask { fillCollisions(collisions, mcParticles); fillParticles(mcParticles); } - PROCESS_SWITCH(femtoUniverseProducerMCTruthTask, processTrackMC, "Provide MC data for track analysis", true); + PROCESS_SWITCH(FemtoUniverseProducerMCTruthTask, processTrackMC, "Provide MC data for track analysis", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerReducedTask.cxx b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerReducedTask.cxx index 9ab0fd70736..71101d143d4 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerReducedTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerReducedTask.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -16,30 +16,36 @@ /// \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 "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" +#include + #include "Math/Vector4D.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "TMath.h" + +#include 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 +69,9 @@ using FemtoFullTracks = soa::Join outputCollision; + Produces outputCollision; Produces outputParts; - Produces outputPartsMC; + Produces outputPartsMC; Produces outputDebugParts; Produces outputPartsMCLabels; Produces outputDebugPartsMC; @@ -92,19 +98,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 +128,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 +209,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 +275,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 +283,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 +297,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 4edca2f9566..fd01a746887 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -14,59 +14,77 @@ /// \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 "PWGCF/FemtoUniverse/Core/FemtoUniverseCascadeSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePhiSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" -#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 "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Core/HfHelper.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" -#include "Math/Vector4D.h" -#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" -#include "TMath.h" +#include + +#include "Math/Vector4D.h" #include "TLorentzVector.h" +#include "TMath.h" +#include + +#include +#include +#include +#include +#include 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 FemtoFullCollisionCentRun2 = - soa::Join::iterator; -using FemtoFullCollisionCentRun3 = - soa::Join::iterator; +using FemtoFullCollision = soa::Join::iterator; +using FemtoFullCollisionCentPP = soa::Join::iterator; +using FemtoFullCollisionCentRun2 = soa::Join::iterator; +using FemtoFullCollisionCentRun3 = soa::Join::iterator; using FemtoFullCollisionMC = soa::Join::iterator; - -using FemtoFullTracks = - soa::Join; +using FemtoFullCollisionCentRun3MCs = soa::Join; +using FemtoFullCollisionCentRun3MC = soa::Join::iterator; +using FemtoFullTracks = soa::Join; // using FilteredFullV0s = soa::Filtered; /// predefined Join // table for o2::aod::V0s = soa::Join @@ -93,255 +111,443 @@ int getRowDaughters(int daughID, T const& vecID) return rowInPrimaryTrackTableDaugh; } -struct femtoUniverseProducerTask { - Produces 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"}; + Configurable confIsUseCutculator{"confIsUseCutculator", true, "Enable cutculator for track cuts"}; // 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 filtering (used for v0-cascade analysis) + Configurable zorroMask{"zorroMask", "", "zorro trigger class to select on (empty: none)"}; /// 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); + struct : o2::framework::ConfigurableGroup { + 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 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 confIsGoodITSLayersAll{"confIsGoodITSLayersAll", true, "Require IsGoodITSLayersAll selection on Events."}; + Configurable confNoITSROFrameBorder{"confNoITSROFrameBorder", true, "Require NoITSROFrameBorder selection on Events."}; + Configurable confNoTimeFrameBorder{"confNoTimeFrameBorder", true, "Require kNoTimeFrameBorder selection on Events."}; + Configurable confNoCollInRofStandard{"confNoCollInRofStandard", true, "Require NoCollInRofStandard selection on Events."}; + Configurable confNoHighMultCollInPrevRof{"confNoHighMultCollInPrevRof", true, "Require NoHighMultCollInPrevRof selection on Events."}; + Configurable confNoCollInTimeRangeStandard{"confNoCollInTimeRangeStandard", true, "Require NoCollInTimeRangeStandard selection on Events."}; + Configurable confTPCOccupancyMin{"confTPCOccupancyMin", 0, "Minimum value for TPC Occupancy selection"}; + Configurable confTPCOccupancyMax{"confTPCOccupancyMax", 500, "Maximum value for TPC Occupancy selection"}; + Configurable confIsCent{"confIsCent", true, "Centrality or multiplicity selection"}; + } ConfGeneral; + Filter customCollCentFilter = (aod::cent::centFT0C > ConfGeneral.confCentFT0Min) && + (aod::cent::centFT0C < ConfGeneral.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"}; 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)"}; + Configurable confIsOnlyMCTrack{"confIsOnlyMCTrack", false, "Enable filling of only MC Tracks"}; + // 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> 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"}; + + Configurable> confV0PDGMCTruth{"confV0PDGMCTruth", std::vector{2212, -211, 3122}, "PDG codes of V0 daughters and mother, the order must be as follows -- positive daughter, negative daughter, mother"}; + } 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"}; - Configurable ConfLooseTPCNSigma{"ConfLooseTPCNSigma", false, "Use loose TPC N sigmas for Kaon PID."}; - Configurable ConfLooseTPCNSigmaValue{"ConfLooseTPCNSigmaValue", 10, "Value for the loose TPC N Sigma for Kaon 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"}; + Configurable confIsApplyTrkCutMCTruth{"confIsApplyTrkCutMCTruth", false, "Apply eta, pT selection cut on MCTruth tracks "}; + Configurable confIsOnlyPrimary{"confIsOnlyPrimary", false, "Select only primaries"}; + } 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> 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 confXiInvMassLowLimit{"confXiInvMassLowLimit", 1.25, "Lower limit of the Xi invariant mass"}; + Configurable confXiInvMassUpLimit{"confXiInvMassUpLimit", 1.40, "Upper limit of the Xi invariant mass"}; + Configurable confOmegaInvMassLowLimit{"confOmegaInvMassLowLimit", 1.60, "Lower limit of the Omega invariant mass"}; + Configurable confOmegaInvMassUpLimit{"confOmegaInvMassUpLimit", 1.80, "Upper limit of the Omega invariant mass"}; + } 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 confPhiEtaHighLimit{"confPhiEtaHighLimit", 0.8, "Maximum eta value of the Phi"}; + 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 confNSigmaTPCKaonLF{"confNSigmaTPCKaonLF", 3.0, "TPC Kaon Sigma as in LF"}; + Configurable confNSigmaCombKaonLF{"confNSigmaCombKaonLF", 3.0, "TPC and TOF Kaon Sigma (combined) as in LF"}; + Configurable confMomKaonLF{"confMomKaonLF", 0.5, "Momentum threshold for kaon identification as in LF"}; + Configurable confMomKaonRejected{"confMomKaonRejected", 0.5, "Momentum threshold for rejected kaon"}; + Configurable confMomKaon03{"confMomKaon03", 0.3, "Momentum threshold for kaon identification pT = 0.3 GeV/c"}; + Configurable confMomKaon045{"confMomKaon045", 0.45, "Momentum threshold for kaon identification pT = 0.45 GeV/c"}; + Configurable confMomKaon055{"confMomKaon055", 0.55, "Momentum threshold for kaon identification pT = 0.55 GeV/c"}; + Configurable confMomKaon15{"confMomKaon15", 1.5, "Momentum threshold for kaon identification pT = 1.5 GeV/c"}; + Configurable confPhiKaonNsigmaTPCfrom00to03{"confPhiKaonNsigmaTPCfrom00to03", 3.0, "Reject if Kaons in 0.0-0.3 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTPCfrom03to045{"confPhiKaonNsigmaTPCfrom03to045", 2.0, "Reject if Kaons in 0.3-0.45 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTPCfrom045to055{"confPhiKaonNsigmaTPCfrom045to055", 1.0, "Reject if Kaons in 0.45-0.55 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTPCfrom055to15{"confPhiKaonNsigmaTPCfrom055to15", 3.0, "Reject if Kaons in 0.55-1.5 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTOFfrom055to15{"confPhiKaonNsigmaTOFfrom055to15", 3.0, "Reject if Kaons in 0.55-1.5 are have TOF n sigma above this value."}; + Configurable confPhiKaonNsigmaTPCfrom15{"confPhiKaonNsigmaTPCfrom15", 3.0, "Reject if Kaons above 1.5 are have TPC n sigma above this value."}; + Configurable confPhiKaonNsigmaTOFfrom15{"confPhiKaonNsigmaTOFfrom15", 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 trackD0CandEtaMax{"trackD0CandEtaMax", 0.8, "max. track/D0 cand. pseudorapidity"}; + Configurable yD0CandGenMax{"yD0CandGenMax", 0.5, "max. gen. D0 cand. rapidity"}; + Configurable yD0CandMax{"yD0CandMax", 0.8, "max. D0 cand. rapidity"}; + Configurable trackD0pTGenMin{"trackD0pTGenMin", 0.0, "MC Truth, min. pT for tracks and D0/D0bar cand."}; + Configurable trackD0pTGenMax{"trackD0pTGenMax", 24.0, "MC Truth, max. pT for tracks and D0/D0bar cand."}; + Configurable useYCutD0Cand{"useYCutD0Cand", true, "True - apply cut on y of D0 cand./false - apply cut on eta"}; + 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; + // PID bitmask configurables + struct : o2::framework::ConfigurableGroup { + Configurable confMinMomTOF{"confMinMomTOF", 0.75, "momentum threshold for particle identification using TOF"}; + 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"}; + 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"}; + } ConfPIDBitmask; - bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + HfHelper hfHelper; + 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 - // ConfLooseTPCNSigma -> use loose nsigmas for Phi meson daughters (bool) - // ConfLooseTPCNSigmaValue -> value of the loose cut (float) - - if (mom < 0.3) { // 0.0-0.3 - if (ConfPhiChildSelection.ConfLooseTPCNSigma) { - if (TMath::Abs(nsigmaTPCK) < ConfPhiChildSelection.ConfLooseTPCNSigmaValue) { - return true; - } else { - return false; - } + if (mom < ConfPhiSelection.confMomKaon03) { // 0.0-0.3 + if (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom00to03) { + return true; } else { - if (TMath::Abs(nsigmaTPCK) < 3.0) { - return true; - } else { - return false; - } + return false; } - } else if (mom < 0.45) { // 0.30 - 0.45 - if (ConfPhiChildSelection.ConfLooseTPCNSigma) { - if (TMath::Abs(nsigmaTPCK) < ConfPhiChildSelection.ConfLooseTPCNSigmaValue) { - return true; - } else { - return false; - } + } else if (mom < ConfPhiSelection.confMomKaon045) { // 0.30 - 0.45 + if (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom03to045) { + return true; } else { - if (TMath::Abs(nsigmaTPCK) < 2.0) { - return true; - } else { - return false; - } + return false; } - } else if (mom < 0.55) { // 0.45-0.55 - if (ConfPhiChildSelection.ConfLooseTPCNSigma) { - if (TMath::Abs(nsigmaTPCK) < ConfPhiChildSelection.ConfLooseTPCNSigmaValue) { - return true; - } else { - return false; - } + } else if (mom < ConfPhiSelection.confMomKaon055) { // 0.45-0.55 + if (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom045to055) { + return true; } else { - if (TMath::Abs(nsigmaTPCK) < 1.0) { - return true; - } else { - return false; - } + return false; } - } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) - if (ConfPhiChildSelection.ConfLooseTPCNSigma) { - if ((TMath::Abs(nsigmaTOFK) < 3.0) && (TMath::Abs(nsigmaTPCK) < ConfPhiChildSelection.ConfLooseTPCNSigmaValue)) { + } else if (mom < ConfPhiSelection.confMomKaon15) { // 0.55-1.5 (now we use TPC and TOF) + if ((std::abs(nsigmaTOFK) < ConfPhiSelection.confPhiKaonNsigmaTOFfrom055to15) && (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom055to15)) { + { return true; - } else { - return false; } + } else { + return false; + } + } else if (mom > ConfPhiSelection.confMomKaon15) { // 1.5 - + if ((std::abs(nsigmaTOFK) < ConfPhiSelection.confPhiKaonNsigmaTOFfrom15) && (std::abs(nsigmaTPCK) < ConfPhiSelection.confPhiKaonNsigmaTPCfrom15)) { + return true; + } else { + return false; + } + } else { + return false; + } + } + bool isKaonNSigmaLF(float mom, float nsigmaTPCK, float nsigmaTOFK, bool hasTOF) + { + if (mom < ConfPhiSelection.confMomKaonLF) { + if (std::abs(nsigmaTPCK) < ConfPhiSelection.confNSigmaTPCKaonLF) { + return true; } else { - if ((TMath::Abs(nsigmaTOFK) < 3.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { - { - return true; - } - } else { - return false; - } + return false; } - } else if (mom > 1.5) { // 1.5 - - if (ConfPhiChildSelection.ConfLooseTPCNSigma) { - if ((TMath::Abs(nsigmaTOFK) < 2.0) && (TMath::Abs(nsigmaTPCK) < ConfPhiChildSelection.ConfLooseTPCNSigmaValue)) { + } else if (mom >= ConfPhiSelection.confMomKaonLF) { // 0.5-1.5 (now we use TPC and TOF) + if (!hasTOF) { + return false; + } else { + if (std::sqrt(nsigmaTPCK * nsigmaTPCK + nsigmaTOFK * nsigmaTOFK) < ConfPhiSelection.confNSigmaCombKaonLF) { return true; } else { return false; } + } + } else { + return false; + } + } + bool isKaonRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi) + { + if (mom < ConfPhiSelection.confMomKaonRejected) { + if (std::abs(nsigmaTPCPi) < ConfPhiSelection.confPhiKaonRejectPionNsigma.value) { + return true; + } else if (std::abs(nsigmaTPCPr) < ConfPhiSelection.confPhiKaonRejectProtonNsigma.value) { + return true; + } + } + if (mom > ConfPhiSelection.confMomKaonRejected) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPhiSelection.confPhiKaonRejectPionNsigma.value) { + return true; + } else if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPhiSelection.confPhiKaonRejectProtonNsigma.value) { + return true; } else { - if ((TMath::Abs(nsigmaTOFK) < 2.0) && (TMath::Abs(nsigmaTPCK) < 3.0)) { - return true; - } else { - return false; - } + return false; } } else { return false; } } + bool isNSigmaTPC(float nsigmaTPCParticle) + { + return (std::abs(nsigmaTPCParticle) < ConfPIDBitmask.confNsigmaTPCParticleChild); + } + + bool isNSigmaTOF(float mom, float nsigmaTOFParticle, bool hasTOF) + { + // Cut only on daughter and bachelor tracks, that have TOF signal + if (mom > ConfPIDBitmask.confMinMomTOF && hasTOF) { + return (std::abs(nsigmaTOFParticle) < ConfPIDBitmask.confNsigmaTOFParticleChild); + } else { + return true; + } + } + + bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle) + { + if (mom <= ConfPIDBitmask.confMinMomTOF) { + return (std::abs(nsigmaTPCParticle) < ConfPIDBitmask.confNsigmaTPCParticle); + } else { + return (std::hypot(nsigmaTOFParticle, nsigmaTPCParticle) < ConfPIDBitmask.confNsigmaCombinedParticle); + } + } + + template + aod::femtouniverseparticle::CutContainerType PIDBitmask(const TrackType& track) + { + static const o2::track::PID pids[] = {o2::track::PID::Proton, o2::track::PID::Pion, o2::track::PID::Kaon}; + aod::femtouniverseparticle::CutContainerType mask = 0u; + for (UInt_t i = 0; i < 3; ++i) { + if (isNSigmaTPC(trackCuts.getNsigmaTPC(track, pids[i]))) + mask |= (1u << i); + if (isNSigmaTOF(track.p(), trackCuts.getNsigmaTOF(track, pids[i]), track.hasTOF())) + mask |= (8u << i); + if (isNSigmaCombined(track.p(), trackCuts.getNsigmaTPC(track, pids[i]), trackCuts.getNsigmaTOF(track, pids[i]))) + mask |= (64u << i); + } + if (track.hasTOF()) + mask |= (512u); + return mask; + } + + template + using hasStrangeTOFinV0 = decltype(std::declval().tofNSigmaLaPr()); + + /// bitmask to save strangeness TOF for V0 analysis + template + aod::femtouniverseparticle::CutContainerType PIDStrangeTOFBitmaskV0(const V0Type& v0) + { + aod::femtouniverseparticle::CutContainerType mask = 0u; + if constexpr (std::experimental::is_detected::value) { + if (v0.tofNSigmaLaPr() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (1u); + if (v0.tofNSigmaLaPi() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (2u); + if (v0.tofNSigmaALaPr() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (4u); + if (v0.tofNSigmaALaPi() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (8u); + if (v0.tofNSigmaK0PiPlus() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (16u); + if (v0.tofNSigmaK0PiMinus() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (32u); + } + return mask; + } + + template + using hasStrangeTOFinCasc = decltype(std::declval().tofNSigmaXiLaPi()); + + /// bitmask to save strangeness TOF for cascade analysis + template + aod::femtouniverseparticle::CutContainerType PIDStrangeTOFBitmaskCasc(const CascType& casc) + { + aod::femtouniverseparticle::CutContainerType mask = 0u; + if constexpr (std::experimental::is_detected::value) { + if (casc.tofNSigmaXiLaPi() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (1u); + if (casc.tofNSigmaXiLaPr() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (2u); + if (casc.tofNSigmaXiPi() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (4u); + if (casc.tofNSigmaOmLaPi() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (8u); + if (casc.tofNSigmaOmLaPr() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (16u); + if (casc.tofNSigmaOmKa() < ConfPIDBitmask.confNsigmaTOFParticleChild) + mask |= (32u); + } + return mask; + } + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + int mRunNumberZorro = 0; + + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::QAObject}; + HistogramRegistry cascadeQaRegistry{"CascadeQAHistos", {}, OutputObjHandlingPolicy::QAObject}; + + void initZorro(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumberZorro == bc.runNumber()) + return; + + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), zorroMask.value); + zorro.populateHistRegistry(qaRegistry, bc.runNumber()); + mRunNumberZorro = bc.runNumber(); + } + /// \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) && @@ -349,82 +555,84 @@ struct femtoUniverseProducerTask { // (aod::v0data::v0radius > V0TranRadV0Min.value); to be added, not working // for now do not know why - HistogramRegistry qaRegistry{"QAHistos", {}, 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 || doprocessTrackV0CentRun3) == false && (doprocessFullMC || doprocessTrackMC || doprocessTrackMCTruth || doprocessTruthAndFullMC || doprocessFullMCCent) == false) { + if ((doprocessFullData || doprocessTrackPhiData || doprocessTrackData || doprocessTrackV0 || doprocessTrackCascadeData || doprocessTrackV0Cascade || 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 || doprocessTrackV0CentRun3) == true && (doprocessFullMC || doprocessTrackMC || doprocessTrackMCTruth || doprocessTruthAndFullMC || doprocessFullMCCent) == true) { + if ((doprocessFullData || doprocessTrackPhiData || doprocessTrackData || doprocessTrackV0 || doprocessTrackCascadeData || doprocessTrackV0Cascade || 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); + zorroSummary.setObject(zorro.getZorroSummary()); + + colCuts.setCuts(ConfGeneral.confEvtZvtx, ConfGeneral.confEvtTriggerCheck, ConfGeneral.confEvtTriggerSel, ConfGeneral.confEvtOfflineCheck, confIsRun3, ConfGeneral.confCentFT0Min, ConfGeneral.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 (ConfGeneral.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 @@ -433,9 +641,58 @@ struct femtoUniverseProducerTask { // } } - if (ConfIsActivatePhi) { + if (ConfGeneral.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); + // invmass cuts + cascadeCuts.setInvMassLimits(ConfCascadeSelection.confXiInvMassLowLimit, ConfCascadeSelection.confOmegaInvMassLowLimit, ConfCascadeSelection.confXiInvMassUpLimit, ConfCascadeSelection.confOmegaInvMassUpLimit); + } + + if (ConfGeneral.confIsActivatePhi) { // initializing for Phi meson - phiCuts.init(&qaRegistry); + phiCuts.init(&qaRegistry); } mRunNumber = 0; @@ -459,7 +716,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) { @@ -467,12 +724,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) { @@ -486,32 +742,63 @@ 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.itsNCls(), particle.itsNClsInnerBarrel(), - particle.dcaXY(), particle.dcaZ(), particle.tpcSignal(), - particle.tpcNSigmaStoreEl(), particle.tpcNSigmaStorePi(), - particle.tpcNSigmaStoreKa(), particle.tpcNSigmaStorePr(), - particle.tpcNSigmaStoreDe(), particle.tofNSigmaStoreEl(), - particle.tofNSigmaStorePi(), particle.tofNSigmaStoreKa(), - particle.tofNSigmaStorePr(), particle.tofNSigmaStoreDe(), - -999., -999., -999., -999., -999., -999.); + if constexpr (std::experimental::is_detected::value) { + outputDebugParts(particle.sign(), (uint8_t)particle.tpcNClsFound(), + particle.tpcNClsFindable(), + (uint8_t)particle.tpcNClsCrossedRows(), + particle.tpcNClsShared(), particle.tpcFractionSharedCls(), particle.tpcInnerParam(), + particle.itsNCls(), particle.itsNClsInnerBarrel(), + particle.dcaXY(), particle.dcaZ(), particle.tpcSignal(), + particle.tpcNSigmaStoreEl(), particle.tpcNSigmaStorePi(), + particle.tpcNSigmaStoreKa(), particle.tpcNSigmaStorePr(), + particle.tpcNSigmaStoreDe(), particle.tofNSigmaStoreEl(), + particle.tofNSigmaStorePi(), particle.tofNSigmaStoreKa(), + particle.tofNSigmaStorePr(), particle.tofNSigmaStoreDe(), + particle.tofNSigmaLaPr(), particle.tofNSigmaLaPi(), particle.tofNSigmaALaPr(), + particle.tofNSigmaALaPi(), particle.tofNSigmaK0PiPlus(), particle.tofNSigmaK0PiMinus()); + } else { + outputDebugParts(particle.sign(), (uint8_t)particle.tpcNClsFound(), + particle.tpcNClsFindable(), + (uint8_t)particle.tpcNClsCrossedRows(), + particle.tpcNClsShared(), particle.tpcFractionSharedCls(), particle.tpcInnerParam(), + particle.itsNCls(), particle.itsNClsInnerBarrel(), + particle.dcaXY(), particle.dcaZ(), particle.tpcSignal(), + particle.tpcNSigmaStoreEl(), particle.tpcNSigmaStorePi(), + particle.tpcNSigmaStoreKa(), particle.tpcNSigmaStorePr(), + particle.tpcNSigmaStoreDe(), particle.tofNSigmaStoreEl(), + particle.tofNSigmaStorePi(), particle.tofNSigmaStoreKa(), + 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 (isCasc) { + if constexpr (std::experimental::is_detected::value) { + outputDebugParts(-999., -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999., particle.tofNSigmaXiLaPi(), + particle.tofNSigmaXiLaPr(), particle.tofNSigmaXiPi(), particle.tofNSigmaOmLaPi(), + particle.tofNSigmaOmLaPr(), particle.tofNSigmaOmKa(), + particle.dcacascdaughters(), particle.cascradius(), + particle.x(), particle.y(), particle.z(), -999.); + } else { + 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(), -999.); + } } else { // LOGF(info, "isTrack0orV0: %d, isPhi: %d", isTrackOrV0, isPhiOrD0); - outputDebugParts(-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(), @@ -520,6 +807,95 @@ 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., + hfHelper.yD0(particle), // getter transRadius + 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., + hfHelper.yD0(particle), // getter transRadius + 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 + void fillDebugD0D0barMcMl(ParticleType const& particle) + { + int8_t originMcReco = 2; // 0 - prompt, 1 - non-prompt, 2 - default/else + if (particle.originMcRec() == RecoDecay::OriginType::Prompt) { + originMcReco = 0; + } else if (particle.originMcRec() == RecoDecay::OriginType::NonPrompt) { + originMcReco = 1; + } else { + originMcReco = 2; + } + if constexpr (isD0ML) { + outputDebugParts(particle.flagMcMatchRec(), // getter sign + originMcReco, -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., + -999., + hfHelper.yD0(particle), // getter transRadius + 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(particle.flagMcMatchRec(), -999., -999., -999., -999., -999., -999., -999., -999., + originMcReco, -999., -999., -999., -999., -999., -999., -999., + -999., -999., -999., -999., -999., + -999., + hfHelper.yD0(particle), // getter transRadius + 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) { @@ -530,21 +906,116 @@ struct femtoUniverseProducerTask { int particleOrigin = 99; auto motherparticlesMC = particleMC.template mothers_as(); - if (abs(pdgCode) == abs(ConfPhiChildOne.ConfPDGCodePartOne.value) || abs(pdgCode) == abs(ConfPhiChildTwo.ConfPDGCodePartTwo.value)) { + if (std::abs(pdgCode) == std::abs(confPDGCodePartOne.value) || std::abs(pdgCode) == std::abs(confPDGCodePartTwo.value)) { if (particleMC.isPhysicalPrimary()) { - particleOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kPrimary; + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary; } else if (!motherparticlesMC.empty()) { auto motherparticleMC = motherparticlesMC.front(); - if (motherparticleMC.producedByGenerator()) + if (motherparticleMC.producedByGenerator()) { particleOrigin = checkDaughterType(fdparttype, motherparticleMC.pdgCode()); - } else { - particleOrigin = aod::femtouniverseMCparticle::ParticleOriginMCTruth::kMaterial; + } else { + 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 fillMCTruthParticle(MCParticleType const& mcparticle, o2::aod::femtouniverseparticle::ParticleType fdparttype) + { + auto pdgCode = mcparticle.pdgCode(); + int particleOrigin = 99; + + // Determine particle origin + if (std::abs(pdgCode) == std::abs(confPDGCodePartOne.value) || std::abs(pdgCode) == std::abs(confPDGCodePartTwo.value)) { + if (mcparticle.isPhysicalPrimary()) { + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary; + } else { + auto mothers = mcparticle.template mothers_as(); + if (!mothers.empty()) { + auto mother = mothers.front(); + if (mother.producedByGenerator()) { + particleOrigin = checkDaughterType(fdparttype, mother.pdgCode()); + } else { + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kMaterial; + } + } + } + } else { + particleOrigin = aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kFake; + } + + // Fill MC companion tables + outputPartsMC(particleOrigin, pdgCode, mcparticle.pt(), mcparticle.eta(), mcparticle.phi()); + fillDebugParticleMC(mcparticle); + outputPartsMCLabels(outputPartsMC.lastIndex()); + + // Artificial fill of a debug table -- solves conflicts between FDParticles and FDExtParticles tables + outputDebugParts(-111., -111., -111., -111., -111., -111., -111., -111., -111., + -111., -111., -111., -111., -111., -111., -111., -111., + -111., -111., -111., -111., -111., + -111., -111., -111., -111., -111., -111.); + } + + 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() == Pdg::kPhi) { + 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); @@ -552,12 +1023,12 @@ struct femtoUniverseProducerTask { } 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 { @@ -565,7 +1036,7 @@ struct femtoUniverseProducerTask { /// FemtoUniverseRun2 is defined V0M/2 multNtr = col.multTracklets(); } - if (ConfEvtUseTPCmult) { + if (ConfGeneral.confEvtUseTPCmult) { multNtr = col.multTPC(); } @@ -575,53 +1046,45 @@ 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; } - colCuts.fillQA(col); - if (ConfDoSpher) { - outputCollision(vtxZ, mult, multNtr, colCuts.computeSphericity(col, tracks), mMagField); - } else { - outputCollision(vtxZ, mult, multNtr, 2, mMagField); + if (zorroMask.value != "") { + auto bc = col.template bc_as(); + initZorro(bc); + if (!zorro.isSelected(col.template bc_as().globalBC())) + return false; } - } - - template - void fillMCTruthCollisions(CollisionType const& col, TrackType const& tracks) - { - for (auto& c : col) { - const auto vtxZ = c.posZ(); - int mult = 0; - int multNtr = 0; - - if (std::abs(vtxZ) > ConfEvtZvtx) { - continue; - } - if (ConfDoSpher) { - outputCollision(vtxZ, mult, multNtr, colCuts.computeSphericity(col, tracks), mMagField); - } else { - outputCollision(vtxZ, mult, multNtr, 2, mMagField); - } + if (!ConfGeneral.confIsUsePileUp) { + outputCollision(vtxZ, mult, multNtr, confDoSpher ? colCuts.computeSphericity(col, tracks) : 2, mMagField); + colCuts.fillQA(col); + return true; + } else if ((!ConfGeneral.confEvNoSameBunchPileup || col.selection_bit(aod::evsel::kNoSameBunchPileup)) && (!ConfGeneral.confEvIsGoodZvtxFT0vsPV || col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && (!ConfGeneral.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 - void fillCollisionsCentRun2(CollisionType const& col, TrackType const& tracks) + bool fillCollisionsCentPP(CollisionType const& col, TrackType const& tracks) { const auto vtxZ = col.posZ(); - int cent = 0; + float mult = 0; int multNtr = 0; - if (!ConfIsRun3) { - cent = col.centRun2V0M(); + 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 (ConfGeneral.confEvtUseTPCmult) { + multNtr = col.multTPC(); } // check whether the basic event selection criteria are fulfilled @@ -630,75 +1093,129 @@ 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 false; + } + if (!ConfGeneral.confIsUsePileUp) { + outputCollision(vtxZ, mult, multNtr, confDoSpher ? colCuts.computeSphericity(col, tracks) : 2, mMagField); + colCuts.fillQA(col); + return true; + } else if ((!ConfGeneral.confEvNoSameBunchPileup || col.selection_bit(aod::evsel::kNoSameBunchPileup)) && (!ConfGeneral.confEvIsGoodZvtxFT0vsPV || col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && (!ConfGeneral.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; + } + } - return; + template + void fillMCTruthCollisions(CollisionType const& col, TrackType const& tracks) + { + for (const auto& c : col) { + const auto vtxZ = c.posZ(); + float mult = confIsRun3 ? c.multFV0M() : 0.5 * (c.multFV0M()); + int multNtr = confIsRun3 ? c.multNTracksPV() : c.multTracklets(); + + if (std::abs(vtxZ) > ConfGeneral.confEvtZvtx) { + continue; + } + + if (confDoSpher) { + outputCollision(vtxZ, mult, multNtr, colCuts.computeSphericity(col, tracks), mMagField); + } else { + outputCollision(vtxZ, mult, multNtr, 2, mMagField); + } } + } + + template + bool fillCollisionsCentRun2(CollisionType const& col) + { + const auto vtxZ = col.posZ(); + const auto cent = col.centRun2V0M(); + const auto multNtr = col.multNTracksPV(); - // 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); + // 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; } 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.multNTracksPV(); - 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 < ConfGeneral.confTPCOccupancyMin || occupancy > ConfGeneral.confTPCOccupancyMax)) { + return false; + } else { + if ((!ConfGeneral.confEvNoSameBunchPileup || col.selection_bit(aod::evsel::kNoSameBunchPileup)) && + (!ConfGeneral.confEvIsGoodZvtxFT0vsPV || col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && + (!ConfGeneral.confIsGoodITSLayersAll || col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) && + (!ConfGeneral.confNoCollInRofStandard || col.selection_bit(aod::evsel::kNoCollInRofStandard)) && + (!ConfGeneral.confNoHighMultCollInPrevRof || col.selection_bit(aod::evsel::kNoHighMultCollInPrevRof)) && + (!ConfGeneral.confEvIsVertexITSTPC || col.selection_bit(aod::evsel::kIsVertexITSTPC)) && + (!ConfGeneral.confNoCollInTimeRangeStandard || col.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) && + (!ConfGeneral.confNoITSROFrameBorder || col.selection_bit(aod::evsel::kNoITSROFrameBorder)) && + (!ConfGeneral.confNoTimeFrameBorder || col.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + 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) > ConfGeneral.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; } @@ -707,19 +1224,22 @@ 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); + femto_universe_track_selection::TrackContainerPosition::kCuts), + confIsUseCutculator ? cutContainer.at( + femto_universe_track_selection::TrackContainerPosition::kPID) + : PIDBitmask(track), + track.dcaXY(), childIDs, 0, + track.sign()); // sign getter is mAntiLambda() + tmpIDtrack.push_back(track.globalIndex()); - if (ConfIsDebug) { - fillDebugParticle(track); + if (confIsDebug) { + fillDebugParticle(track); } if constexpr (isMC) { @@ -733,7 +1253,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 @@ -756,7 +1276,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; @@ -766,12 +1286,12 @@ 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), + confIsUseCutculator ? cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosPID) : PIDBitmask(postrack), 0., childIDs, 0, - 0); + postrack.sign()); const int rowOfPosTrack = outputParts.lastIndex(); if constexpr (isMC) { fillMCParticle(postrack, o2::aod::femtouniverseparticle::ParticleType::kV0Child); @@ -786,12 +1306,12 @@ 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), + confIsUseCutculator ? cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegPID) : PIDBitmask(negtrack), 0., childIDs, 0, - 0); + negtrack.sign()); const int rowOfNegTrack = outputParts.lastIndex(); if constexpr (isMC) { fillMCParticle(negtrack, o2::aod::femtouniverseparticle::ParticleType::kV0Child); @@ -802,16 +1322,16 @@ struct femtoUniverseProducerTask { v0.eta(), v0.phi(), aod::femtouniverseparticle::ParticleType::kV0, - cutContainerV0.at(femtoUniverseV0Selection::V0ContainerPosition::kV0), - 0, + cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kV0), + PIDStrangeTOFBitmaskV0(v0), 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); @@ -819,26 +1339,252 @@ struct femtoUniverseProducerTask { } } + template + void fillV0MCTruth(MCParticlesType const& mcParticles) + { + for (const auto& mc : mcParticles) { // Loop over all MC Truth particles + if (mc.pdgCode() != ConfV0Selection.confV0PDGMCTruth.value[2]) + continue; // Artificially single out V0s + + auto daughters = mc.template daughters_as(); // Access daughters (no differentiation of signs, it needs to be checked separately) + + bool foundPos = false, foundNeg = false; + + std::vector childIDs = {0, 0}; + int rowPos = 0; + int rowNeg = 0; + + for (auto const& d : daughters) { // Loop over daughters + if (d.pdgCode() == ConfV0Selection.confV0PDGMCTruth.value[0]) { // Check for a positive child + foundPos = true; + + outputParts(outputCollision.lastIndex(), + d.pt(), + d.eta(), + d.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + 0, + d.pdgCode(), + childIDs, // {0, 0} + 0, + 0); + rowPos = outputParts.lastIndex(); + fillMCTruthParticle(d, aod::femtouniverseparticle::ParticleType::kMCTruthTrack); + } else if (d.pdgCode() == ConfV0Selection.confV0PDGMCTruth.value[1]) { // Check for a negative child + foundNeg = true; + + outputParts(outputCollision.lastIndex(), + d.pt(), + d.eta(), + d.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + 0, + d.pdgCode(), + childIDs, // {0, 0} + 0, + 0); + rowNeg = outputParts.lastIndex(); + fillMCTruthParticle(d, aod::femtouniverseparticle::ParticleType::kMCTruthTrack); + } + } + + if (!foundPos || !foundNeg) + continue; + + childIDs[0] = rowPos; + childIDs[1] = rowNeg; + outputParts(outputCollision.lastIndex(), + mc.pt(), + mc.eta(), + mc.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + 0, + mc.pdgCode(), + childIDs, + 0, + 0); + fillMCTruthParticle(mc, aod::femtouniverseparticle::ParticleType::kMCTruthTrack); + } + } + + template + void fillTracksMCTruth(MCParticlesType const& mcParticles) + { + for (const auto& mc : mcParticles) { // Loop over all MC Truth particles + if (ConfFilterCuts.confIsApplyTrkCutMCTruth) { + if (std::abs(mc.eta()) > ConfFilterCuts.confEtaFilterCut || mc.pt() < ConfFilterCuts.confPtLowFilterCut || mc.pt() > ConfFilterCuts.confPtHighFilterCut) { + continue; + } + } + + if (ConfFilterCuts.confIsOnlyPrimary) { + if (!mc.isPhysicalPrimary()) { + return; + } + } + + std::vector childIDs = {0, 0}; + outputParts(outputCollision.lastIndex(), + mc.pt(), + mc.eta(), + mc.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + 0, + mc.pdgCode(), + childIDs, + 0, + 0); + fillMCTruthParticle(mc, aod::femtouniverseparticle::ParticleType::kMCTruthTrack); + } + } + + 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; + outputParts(outputCollision.lastIndex(), + casc.positivept(), + casc.positiveeta(), + casc.positivephi(), + aod::femtouniverseparticle::ParticleType::kV0Child, + 0, + PIDBitmask(posTrackCasc), + hasTOF, + childIDs, + 0, + posTrackCasc.sign()); + const int rowOfPosTrack = outputParts.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; + outputParts(outputCollision.lastIndex(), + casc.negativept(), + casc.negativeeta(), + casc.negativephi(), + aod::femtouniverseparticle::ParticleType::kV0Child, + 0, + PIDBitmask(negTrackCasc), + hasTOF, + childIDs, + 0, + negTrackCasc.sign()); + const int rowOfNegTrack = outputParts.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; + outputParts(outputCollision.lastIndex(), + casc.bachelorpt(), + casc.bacheloreta(), + casc.bachelorphi(), + aod::femtouniverseparticle::ParticleType::kCascadeBachelor, + 0, + PIDBitmask(bachTrackCasc), + hasTOF, + childIDs, + 0, + bachTrackCasc.sign()); + const int rowOfBachTrack = outputParts.lastIndex(); + if constexpr (isMC) { + fillMCParticle(bachTrackCasc, o2::aod::femtouniverseparticle::ParticleType::kCascadeBachelor); + } + // cascade + std::vector indexCascChildID = {rowOfPosTrack, rowOfNegTrack, rowOfBachTrack}; + outputParts(outputCollision.lastIndex(), + casc.pt(), + casc.eta(), + casc.phi(), + aod::femtouniverseparticle::ParticleType::kCascade, + 0, + PIDStrangeTOFBitmaskCasc(casc), + 0, + indexCascChildID, + casc.mXi(), + casc.mOmega()); + outputCascParts(outputCollision.lastIndex(), + outputParts.lastIndex(), + 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) + void fillD0D0barData(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 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.useYCutD0Cand && std::abs(hfHelper.yD0(hfCand)) > ConfD0Selection.yD0CandMax) { continue; } - if (std::abs(hfCand.eta()) > ConfD0Selection.ConfD0D0barCandEtaCut) { + if (!(ConfD0Selection.useYCutD0Cand) && std::abs(hfCand.eta()) > ConfD0Selection.trackD0CandEtaMax) { continue; } @@ -855,14 +1601,22 @@ 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; @@ -875,16 +1629,16 @@ struct femtoUniverseProducerTask { 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; @@ -897,16 +1651,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(), @@ -914,17 +1668,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); @@ -933,28 +1687,321 @@ struct femtoUniverseProducerTask { } } + template + void fillD0D0barDataMl(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 + double invMassD0 = 0.0; + double invMassD0bar = 0.0; + bool isD0D0bar = false; + int8_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 (ConfD0Selection.useYCutD0Cand && std::abs(hfHelper.yD0(hfCand)) > ConfD0Selection.yD0CandMax) { + continue; + } + + if (!(ConfD0Selection.useYCutD0Cand) && std::abs(hfCand.eta()) > ConfD0Selection.trackD0CandEtaMax) { + continue; + } + + 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); + 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); + 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 + -999., // tempFitVar + 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) { + fillDebugD0D0barML(hfCand); // QA for D0/D0bar + } else if (hfCand.isSelD0bar() == 1) { + fillDebugD0D0barML(hfCand); + } else { + fillDebugD0D0barML(hfCand); + } + } + if constexpr (isMC) { + fillMCParticleD0(hfCand); + } + } + } + } + + template + void fillD0D0barMcMl(CollisionType const&, TrackType const&, HfCandidate const& hfCands, McPart const& mcParticles) + { + 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 + double invMassD0 = 0.0; + double invMassD0bar = 0.0; + bool isD0D0bar = false; + int indexMcRec = -1; + int8_t sign = 0; + int8_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 (ConfD0Selection.useYCutD0Cand && std::abs(hfHelper.yD0(hfCand)) > ConfD0Selection.yD0CandMax) { + continue; + } + + if (!(ConfD0Selection.useYCutD0Cand) && std::abs(hfCand.eta()) > ConfD0Selection.trackD0CandEtaMax) { + continue; + } + + // Check whether the D0 candidate has the corresponding MC particle + auto postrack = hfCand.template prong0_as(); + auto negtrack = hfCand.template prong1_as(); + auto arrayDaughters = std::array{postrack, negtrack}; + indexMcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign); + + if (!(indexMcRec > -1)) { + continue; + } + + if (std::abs(hfCand.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + int postrackID = hfCand.prong0Id(); // Index to first prong + int rowInPrimaryTrackTablePos = -1; + rowInPrimaryTrackTablePos = getRowDaughters(postrackID, tmpIDtrack); + childIDs[0] = rowInPrimaryTrackTablePos; + childIDs[1] = 0; + + if (hfCand.isSelD0() == 1 && hfCand.isSelD0bar() == 0) { + 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); + 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 + -999., // tempFitVar + 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) { + fillDebugD0D0barMcMl(hfCand); // QA for D0/D0bar + } else if (hfCand.isSelD0bar() == 1) { + fillDebugD0D0barMcMl(hfCand); + } else { + fillDebugD0D0barMcMl(hfCand); + } + } + if constexpr (isMC) { + auto particleMother = mcParticles.rawIteratorAt(indexMcRec); // gen. level pT + auto yGen = RecoDecay::y(particleMother.pVector(), o2::constants::physics::MassD0); // gen. level y + outputPartsMC(0, particleMother.pdgCode(), particleMother.pt(), yGen, particleMother.phi()); + outputPartsMCLabels(outputPartsMC.lastIndex()); + } + } + } + } + } + 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 (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)))) { + for (const auto& [p1, p2] : combinations(soa::CombinationsFullIndexPolicy(tracks, tracks))) { + if (!trackCuts.isSelectedMinimal(p1) || !trackCuts.isSelectedMinimal(p1)) { continue; } - if (!(IsKaonNSigma(p2.pt(), trackCuts.getNsigmaTPC(p2, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(p2, o2::track::PID::Kaon)))) { + 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; - } else if ((!(p1.sign() == 1)) || (!(p2.sign() == -1))) { + } + 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; - 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 + 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); @@ -963,28 +2010,22 @@ struct femtoUniverseProducerTask { sumVec += part2Vec; float phiEta = sumVec.Eta(); - if (TMath::Abs(phiEta) > 0.8) { + if (std::abs(phiEta) > ConfPhiSelection.confPhiEtaHighLimit.value) { 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? @@ -995,12 +2036,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); @@ -1015,12 +2056,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); @@ -1032,49 +2073,52 @@ 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 (ConfGeneral.confMCTruthAnalysisWithPID) { bool pass = false; - std::vector tmpPDGCodes = ConfMCTruthPDGCodes; // necessary due to some features of the Configurable - for (uint32_t pdg : tmpPDGCodes) { + std::vector tmpPDGCodes = ConfGeneral.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 == Pdg::kPhi) { // && (recoMcIds && recoMcIds->get().contains(particle.globalIndex()))) { // ATTENTION: all Phi mesons are NOT primary particles + pass = true; + } else if (pdgCode == Pdg::kD0) { pass = true; } else { - if (particle.isPhysicalPrimary()) + if (confStoreMCmothers || particle.isPhysicalPrimary() || (ConfGeneral.confActivateSecondaries && recoMcIds && recoMcIds->get().contains(particle.globalIndex()))) pass = true; } } @@ -1091,10 +2135,19 @@ 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 + if constexpr (resolveDaughs) { + tmpIDtrack.push_back(particle.globalIndex()); + continue; + } + + if (ConfGeneral.confIsActivateCascade) + childIDs.push_back(0); outputParts(outputCollision.lastIndex(), particle.pt(), particle.eta(), @@ -1102,18 +2155,145 @@ struct femtoUniverseProducerTask { aod::femtouniverseparticle::ParticleType::kMCTruthTrack, 0, pdgCode, - pdgCode, + variablePDG, childIDs, 0, 0); - if (ConfIsDebug) { - fillDebugParticle(particle); + + 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 (ConfGeneral.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(); + + outputParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + 0, + static_cast(particle.pdgCode()), + variablePDG, + 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); + } + } + } + } + + template + void fillMCTruthParticlesD0(TrackType const& mcParts) + { + std::vector childIDs = {0, 0}; // these IDs are necessary to keep track of the children + std::vector tmpIDtrack; + + for (const auto& particle : mcParts) { + + if (particle.pt() < ConfD0Selection.trackD0pTGenMin || particle.pt() > ConfD0Selection.trackD0pTGenMax) + continue; + + int pdgCode = particle.pdgCode(); + + if (ConfGeneral.confMCTruthAnalysisWithPID) { + bool pass = false; + std::vector tmpPDGCodes = ConfGeneral.confMCTruthPDGCodes; // necessary due to some features of the Configurable + for (auto const& pdg : tmpPDGCodes) { + if (static_cast(pdg) == static_cast(pdgCode)) { + if (pdgCode == Pdg::kPhi) { + pass = true; + } else if (std::abs(pdgCode) == Pdg::kD0) { + pass = true; + } else { + if (particle.isPhysicalPrimary()) + pass = true; + } + } + } + if (!pass) + continue; + } + + /// check if we end-up with the correct final state using MC info + int8_t sign = 0; + int8_t origin = -99; + int8_t mcGenFlag = -99; + if (std::abs(particle.pdgCode()) == Pdg::kD0 && !RecoDecay::isMatchedMCGen(mcParts, particle, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign)) { + /// check if we have D0(bar) → π± K∓ + continue; + } + + if (std::abs(particle.pdgCode()) == Pdg::kD0) { + if (std::abs(particle.y()) > ConfD0Selection.yD0CandGenMax) { + continue; + } else { + origin = RecoDecay::getCharmHadronOrigin(mcParts, particle); + mcGenFlag = particle.flagMcMatchGen(); + } + } else { + if (std::abs(particle.eta()) > ConfD0Selection.trackD0CandEtaMax) { + continue; + } + } + + outputParts(outputCollision.lastIndex(), + particle.pt(), + particle.eta(), + particle.phi(), + aod::femtouniverseparticle::ParticleType::kMCTruthTrack, + -999., + pdgCode, + pdgCode, // getter tempFitVar + childIDs, + mcGenFlag, + origin); // D0(bar) origin + + 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(-999); } } } @@ -1122,13 +2302,15 @@ 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 (ConfGeneral.confIsActivateV0) { + fillV0(col, fullV0s, tracks); + } + if (ConfGeneral.confIsActivatePhi) { + fillPhi(col, tracks); + } } } @@ -1142,7 +2324,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&, @@ -1154,9 +2336,45 @@ 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 processTrackV0Cascade(aod::FemtoFullCollision const& col, + aod::BCsWithTimestamps const&, + soa::Filtered const& tracks, + soa::Join const& fullV0s, + soa::Join const& fullCascades) + { + getMagneticFieldTesla(col.bc_as()); + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(tracks); + if (ConfGeneral.confIsActivateV0) { + fillV0(col, fullV0s, tracks); + } + if (ConfGeneral.confIsActivateCascade) { + fillCascade(col, fullCascades, tracks); + } + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackV0Cascade, "Provide experimental data for track, v0 and cascades", false); - void processTrackV0CentRun3(aod::FemtoFullCollisionCentRun3 const& col, + /*void processTrackV0CentRun3(aod::FemtoFullCollisionCentRun3 const& col, aod::BCsWithTimestamps const&, soa::Filtered const& tracks, o2::aod::V0Datas const& fullV0s) @@ -1164,11 +2382,11 @@ struct femtoUniverseProducerTask { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); // fill the tables - fillCollisionsCentRun3(col, tracks); + fillCollisionsCentRun3(col, tracks, fullV0s); fillTracks(tracks); fillV0(col, fullV0s, tracks); } - PROCESS_SWITCH(femtoUniverseProducerTask, processTrackV0CentRun3, "Provide experimental data for track v0", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackV0CentRun3, "Provide experimental data for track v0", false);*/ void processFullMC(aod::FemtoFullCollisionMC const& col, aod::BCsWithTimestamps const&, @@ -1182,7 +2400,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&, @@ -1193,10 +2411,12 @@ 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&, @@ -1207,11 +2427,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, processTrackPhiMC, "Provide MC data for track Phi analysis", false); + PROCESS_SWITCH(FemtoUniverseProducerTask, processTrackPhiMC, "Provide MC data for track Phi analysis", false); void processTrackData(aod::FemtoFullCollision const& col, aod::BCsWithTimestamps const&, @@ -1219,13 +2441,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&, @@ -1234,11 +2481,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, @@ -1249,13 +2498,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); + fillD0D0barData(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); + fillD0D0barDataMl(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, @@ -1266,81 +2534,396 @@ 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; - Preslice> perCollisionV0s = aod::track::collisionId; + + template + void processTruthAndFullMC( aod::McCollisions const& mccols, aod::McParticles const& mcParticles, soa::Join const& collisions, - soa::Join const& tracks, - soa::Join const& fullV0s, - aod::BCsWithTimestamps const&) + 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 (auto& mccol : mccols) { + 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); // fills mc particles + 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 + bool colcheck = false; + // fill the tables + + if (ConfGeneral.confIsCent) { + colcheck = fillCollisionsCentRun3(col); + } else { + colcheck = fillCollisions(col, groupedTracks); + } + + 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); + if (!ConfTrkSelection.confIsOnlyMCTrack) { + fillParticles(groupedMCParticles, recoMcIds); // fills mc particles + } else { + fillTracksMCTruth(groupedMCParticles); + } + } + } + } + } + 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); + + 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); + + void processTruthAndFullMCCentRun3Casc( + aod::McCollisions const& mccols, + aod::McParticles const& mcParticles, + aod::FemtoFullCollisionCentRun3MCs const& collisions, + soa::Filtered> const& tracks, + soa::Join const& fullCascades, + aod::BCsWithTimestamps const&) + { + // recos - for (auto& col : collisions) { + std::set recoMcIds; + for (const auto& col : collisions) { + auto groupedTracks = tracks.sliceBy(perCollisionTracks, col.globalIndex()); + auto groupedCascParts = fullCascades.sliceBy(perCollisionCascs, col.globalIndex()); + getMagneticFieldTesla(col.bc_as()); + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillTracks(groupedTracks); + fillCascade(col, groupedCascParts, 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, processTruthAndFullMCCentRun3Casc, "Provide both MC truth and reco for tracks and cascades with centrality", false); + + Preslice> mcPartPerMcColl = aod::mcparticle::mcCollisionId; + Preslice> perCollisionD0s = aod::track::collisionId; + void processTrackD0MC(aod::McCollisions const& mccols, + soa::Join const& collisions, + soa::Filtered> const& tracks, + soa::Join const& hfMcGenCands, + soa::Join const& hfMcRecoCands, + aod::BCsWithTimestamps const&, + aod::McParticles const& mcParts) + { + // MC Reco + for (const auto& col : collisions) { auto groupedTracks = tracks.sliceBy(perCollisionTracks, col.globalIndex()); - auto groupedV0s = fullV0s.sliceBy(perCollisionV0s, col.globalIndex()); + auto groupedD0s = hfMcRecoCands.sliceBy(perCollisionD0s, col.globalIndex()); + // get magnetic field for run getMagneticFieldTesla(col.bc_as()); - fillCollisionsAndTracksAndV0AndPhi(col, groupedTracks, groupedV0s); + // fill the tables + const auto colcheck = fillCollisions(col, tracks); + if (colcheck) { + fillTracks(groupedTracks); + fillD0D0barMcMl(col, groupedTracks, groupedD0s, mcParts); + } + } + // MC Truth + for (const auto& mccol : mccols) { + auto groupedMCParticles = hfMcGenCands.sliceBy(mcPartPerMcColl, mccol.globalIndex()); + auto groupedCollisions = collisions.sliceBy(recoCollsPerMCColl, mccol.globalIndex()); + fillMCTruthCollisions(groupedCollisions, groupedMCParticles); // fills the reco collisions for mc collision + fillMCTruthParticlesD0(groupedMCParticles); // fills mc particles } } - PROCESS_SWITCH(femtoUniverseProducerTask, processTruthAndFullMC, "Provide both MC truth and reco for tracks and V0s", false); + 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&, - soa::Join const& fullV0s) + aod::McParticles const&) { // get magnetic field for run - getMagneticFieldTesla(col.bc_as()); + 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 - fillCollisionsCentRun3(col, tracks); - fillTracks(tracks); - fillV0(col, fullV0s, tracks); + const auto colcheck = fillCollisionsCentRun3(col); + if (colcheck) { + fillCollisionsCentRun3ColExtra(col, ir); + fillTracks(tracks); + } } - PROCESS_SWITCH(femtoUniverseProducerTask, processFullMCCent, "Provide MC data with centrality bins", false); + 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 processTruthAndFullMCCentRun3V0( + aod::McCollisions const& mccols, + aod::McParticles const& mcParticles, + aod::FemtoFullCollisionCentRun3MCs const& collisions, + soa::Filtered> const& tracks, + soa::Join const& fullV0s, + aod::BCsWithTimestamps const&) + { + + // MCReco + std::set recoMcIds; + for (const auto& col : collisions) { // loop over collisions + auto groupedTracks = tracks.sliceBy(perCollisionTracks, col.globalIndex()); // slicing for tracks + auto groupedV0Parts = fullV0s.sliceBy(perCollisionV0s, col.globalIndex()); // slicing for V0 + 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()); + } + } + + // MCTruth + for (const auto& mccol : mccols) { + auto groupedCollisions = collisions.sliceBy(recoCollsPerMCCollCentPbPb, mccol.globalIndex()); // slicing for MC collisions + auto groupedMCParticles = mcParticles.sliceBy(perMCCollision, mccol.globalIndex()); // slicing for MC particles + for (const auto& col : groupedCollisions) { + const auto colcheck = fillMCTruthCollisionsCentRun3(col); + if (colcheck) { + outputCollExtra(1.0, 1.0); + fillV0MCTruth(groupedMCParticles); // fills MC V0s and its daughters + } + } + } + } + PROCESS_SWITCH(FemtoUniverseProducerTask, processTruthAndFullMCCentRun3V0, "Provide both MC truth and reco for tracks and V0s with centrality", 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..a7b66212480 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTaskV0Only.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTaskV0Only.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -13,30 +13,36 @@ /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + #include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseV0Selection.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 "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" +#include + +#include "Math/Vector4D.h" #include "TMath.h" +#include + 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 +83,7 @@ int getRowDaughters(int daughID, T const& vecID) struct femtoUniverseProducerTaskV0Only { - Produces outputCollision; + Produces outputCollision; Produces outputParts; Produces outputDebugParts; @@ -109,60 +115,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 +229,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 +425,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 +443,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 +457,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 +474,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 +488,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 +498,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 47dfc0fe681..346188d08fd 100644 --- a/PWGCF/FemtoUniverse/Tasks/CMakeLists.txt +++ b/PWGCF/FemtoUniverse/Tasks/CMakeLists.txt @@ -29,6 +29,16 @@ 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-v0-helicity + SOURCES femtoUniversePairTaskTrackV0Helicity.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 @@ -49,6 +59,16 @@ 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-v0-cascade-extended + SOURCES femtoUniversePairTaskV0CascadeExtended.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 diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseCutCulator.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseCutCulator.cxx index a13c35fa3e3..6e5af4e8d52 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseCutCulator.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseCutCulator.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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 94a0d58a646..984ab7d973e 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugTrack.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugTrack.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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; @@ -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..8f8f8664f52 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugV0.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseDebugV0.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -13,106 +13,193 @@ /// \brief Tasks that reads the particle tables and fills QA histograms for V0s /// \author Luca Barioglio, TU München, luca.barioglio@cern.ch /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch +/// \author Anna-Mariia Andrushko, WUT Warsaw, anna-mariia.andrushko@cern.ch -#include -#include -#include -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" -#include "DataFormatsParameters/GRPObject.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" -#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 + +#include +#include 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; -struct femtoUniverseDebugV0 { +struct FemtoUniverseDebugV0 { + + Service pdg; + SliceCache cache; - Configurable ConfPDGCodeV0{"ConfPDGCodePartOne", 3122, "V0 - PDG code"}; - Configurable ConfPDGCodeChildPos{"ConfPDGCodeChildPos", 2212, "Positive Child - PDG code"}; - Configurable ConfPDGCodeChildNeg{"ConfPDGCodeChildNeg", 211, "Negative Child- PDG code"}; - Configurable ConfCutV0{"ConfCutV0", 338, "V0 - Selection bit from cutCulator"}; - 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 ConfCutChildPos{"ConfCutChildPos", 150, "Positive Child of V0 - Selection bit from cutCulator"}; - Configurable ConfCutChildNeg{"ConfCutChildNeg", 149, "Negative Child of V0 - Selection bit from cutCulator"}; - Configurable ConfChildPosPidnSigmaMax{"ConfChildPosPidnSigmaMax", 3.f, "Positive Child of V0 - Selection bit from cutCulator"}; - Configurable ConfChildNegPidnSigmaMax{"ConfChildNegPidnSigmaMax", 3.f, "Negative Child of V0 - Selection bit from cutCulator"}; - Configurable ConfChildPosIndex{"ConfChildPosIndex", 1, "Positive Child of V0 - Index from cutCulator"}; - Configurable ConfChildNegIndex{"ConfChildNegIndex", 0, "Negative Child of V0 - Index from cutCulator"}; - Configurable> ConfChildPIDnSigmaMax{"ConfChildPIDnSigmaMax", std::vector{4.f, 3.f}, "V0 child sel: Max. PID nSigma TPC"}; - Configurable ConfChildnSpecies{"ConfChildnSpecies", 2, "Number of particle spieces (for V0 children) with PID info"}; - 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"}; + /// V0 configurables + struct : o2::framework::ConfigurableGroup { + Configurable confPDGCodeV0{"confPDGCodeV0", 3122, "V0 -- PDG code"}; + Configurable confPDGCodePositiveChild{"confPDGCodePositiveChild", 2212, "Positive Child -- PDG code"}; + Configurable confPDGCodeNegativeChild{"confPDGCodeNegativeChild", 211, "Negative Child -- PDG code"}; + Configurable confCutV0{"confCutV0", 338, "V0 -- Selection bit from cutCulator"}; + 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"}; + } V0configs; // o2-linter: disable=name/function-variable + + /// Children configurables + struct : o2::framework::ConfigurableGroup { + Configurable confCutPositiveChild{"confCutPositiveChild", 150, "Positive Child of V0 -- Selection bit from cutCulator"}; + Configurable confCutNegativeChild{"confCutNegativeChild", 149, "Negative Child of V0 -- Selection bit from cutCulator"}; + Configurable confPositiveChildPIDnSigmaMax{"confPositiveChildPIDnSigmaMax", 3.f, "Positive Child of V0 -- Selection bit from cutCulator"}; + Configurable confNegativeChildPIDnSigmaMax{"confNegativeChildPIDnSigmaMax", 3.f, "Negative Child of V0 -- Selection bit from cutCulator"}; + Configurable confPositiveChildIndex{"confPositiveChildIndex", 1, "Positive Child of V0 -- Index from cutCulator"}; + Configurable confNegativeChildIndex{"confNegativeChildIndex", 0, "Negative Child of V0 -- Index from cutCulator"}; + Configurable> confChildPIDnSigmaMax{"confChildPIDnSigmaMax", std::vector{4.f, 3.f}, "V0 child selection: max. PID nSigma TPC"}; + Configurable confChildnSpecies{"confChildnSpecies", 2, "Number of particle spieces (for V0 children) with PID info"}; + 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"}; + } childconfigs; + + Configurable confIsMC{"confIsMC", false, "Enable additional histograms in the case of a Monte Carlo run"}; + /// Partitioning using FemtoFullParticles = soa::Join; - Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && ((aod::femtouniverseparticle::cut & ConfCutV0) == ConfCutV0); + + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && ((aod::femtouniverseparticle::cut & V0configs.confCutV0) == V0configs.confCutV0); + + Partition> partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && ((aod::femtouniverseparticle::cut & V0configs.confCutV0) == V0configs.confCutV0); + Preslice perCol = aod::femtouniverseparticle::fdCollisionId; /// Histogramming FemtoUniverseEventHisto eventHisto; - FemtoUniverseParticleHisto posChildHistos; - FemtoUniverseParticleHisto negChildHistos; - FemtoUniverseParticleHisto V0Histos; + FemtoUniverseParticleHisto positiveChildHistos; + FemtoUniverseParticleHisto negativeChildHistos; + FemtoUniverseParticleHisto V0Histos; // o2-linter: disable=name/function-variable /// Histogram output - HistogramRegistry EventRegistry{"Event", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry V0Registry{"FullV0QA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry eventRegistry{"Event", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry V0Registry{"FullV0QA", {}, OutputObjHandlingPolicy::AnalysisObject}; // o2-linter: disable=name/function-variable + HistogramRegistry thetaRegistry{"ThetaQA", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { - eventHisto.init(&EventRegistry); - posChildHistos.init(&V0Registry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, ConfPDGCodeChildPos.value, true); - negChildHistos.init(&V0Registry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, ConfPDGCodeChildNeg, true); - V0Histos.init(&V0Registry, ConfV0TempFitVarpTBins, ConfV0TempFitVarBins, false, ConfPDGCodeV0.value, true); + eventHisto.init(&eventRegistry); + positiveChildHistos.init(&V0Registry, childconfigs.confChildTempFitVarpTBins, childconfigs.confChildTempFitVarBins, confIsMC, V0configs.confPDGCodePositiveChild.value, true); + negativeChildHistos.init(&V0Registry, childconfigs.confChildTempFitVarpTBins, childconfigs.confChildTempFitVarBins, confIsMC, V0configs.confPDGCodeNegativeChild.value, true); + V0Histos.init(&V0Registry, V0configs.confV0TempFitVarpTBins, V0configs.confV0TempFitVarBins, confIsMC, V0configs.confPDGCodeV0.value, true); + + thetaRegistry.add("Theta/hTheta", " ; p (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/PositiveChild/hThetaPt", " ; p_{T} (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/PositiveChild/hThetaEta", " ; #eta; cos(#theta)", kTH2F, {{100, -1, 1}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/PositiveChild/hThetaPhi", " ; #phi; cos(#theta)", kTH2F, {{100, -1, 7}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/NegativeChild/hThetaPt", " ; p_{T} (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/NegativeChild/hThetaEta", " ; #eta; cos(#theta)", kTH2F, {{100, -1, 1}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/NegativeChild/hThetaPhi", " ; #phi; cos(#theta)", kTH2F, {{100, -1, 7}, {110, -1.1, 1.1}}); } - /// Porduce QA plots for V0 selection in FemtoUniverse framework - void process(o2::aod::FDCollision const& col, FemtoFullParticles const& parts) + /// Produce QA plots for V0 and its children on real data + void processData(o2::aod::FdCollision const& col, FemtoFullParticles const& parts) { auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); eventHisto.fillQA(col); - for (auto& part : groupPartsOne) { + for (const auto& part : groupPartsOne) { if (!part.has_children()) { continue; } - const auto& posChild = parts.iteratorAt(part.index() - 2); - const auto& negChild = parts.iteratorAt(part.index() - 1); - if (posChild.globalIndex() != part.childrenIds()[0] || negChild.globalIndex() != part.childrenIds()[1]) { + const auto& positiveChild = parts.iteratorAt(part.index() - 2); + const auto& negativeChild = parts.iteratorAt(part.index() - 1); + if (positiveChild.globalIndex() != part.childrenIds()[0] || negativeChild.globalIndex() != part.childrenIds()[1]) { LOG(warn) << "Indices of V0 children do not match"; continue; } - // 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)) { + + // Check cuts on V0 children + if (positiveChild.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kV0Child) && + negativeChild.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kV0Child) && + isFullPIDSelected(positiveChild.pidCut(), positiveChild.p(), 999.f, childconfigs.confPositiveChildIndex.value, childconfigs.confChildnSpecies.value, childconfigs.confChildPIDnSigmaMax.value, childconfigs.confPositiveChildPIDnSigmaMax.value, 1.f) && + isFullPIDSelected(negativeChild.pidCut(), negativeChild.p(), 999.f, childconfigs.confNegativeChildIndex.value, childconfigs.confChildnSpecies.value, childconfigs.confChildPIDnSigmaMax.value, childconfigs.confNegativeChildPIDnSigmaMax.value, 1.f)) { + auto positiveChildMass = pdg->Mass(V0configs.confPDGCodePositiveChild); + auto negativeChildMass = pdg->Mass(V0configs.confPDGCodeNegativeChild); + auto positiveChildBoosted = FemtoUniverseMath::boostPRF(positiveChild, positiveChildMass, negativeChild, negativeChildMass); + auto cosineTheta = (positiveChildBoosted.Px() * part.px() + positiveChildBoosted.Py() * part.py() + positiveChildBoosted.Pz() * part.pz()) / (positiveChildBoosted.P() * part.p()); + V0Histos.fillQA(part); - posChildHistos.fillQA(posChild); - negChildHistos.fillQA(negChild); + positiveChildHistos.fillQA(positiveChild); + negativeChildHistos.fillQA(negativeChild); + + thetaRegistry.fill(HIST("Theta/hTheta"), part.p(), cosineTheta); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaPt"), positiveChild.pt(), cosineTheta); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaEta"), positiveChild.eta(), cosineTheta); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaPhi"), positiveChild.phi(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaPt"), negativeChild.pt(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaEta"), negativeChild.eta(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaPhi"), negativeChild.phi(), cosineTheta); + } + } + } + PROCESS_SWITCH(FemtoUniverseDebugV0, processData, "Enable processing on real data", true); + + /// Produce QA plots for V0 and its children on Monte Carlo + void processMC(o2::aod::FdCollision const& col, soa::Join const& parts, o2::aod::FdMCParticles const&) + { + auto groupPartsOne = partsOneMC->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + eventHisto.fillQA(col); + for (const auto& part : groupPartsOne) { + if (!part.has_children()) { + continue; + } + const auto& positiveChild = parts.iteratorAt(part.index() - 2); + const auto& negativeChild = parts.iteratorAt(part.index() - 1); + if (positiveChild.globalIndex() != part.childrenIds()[0] || negativeChild.globalIndex() != part.childrenIds()[1]) { + LOG(warn) << "Indices of V0 children do not match"; + continue; + } + + // Check cuts on V0 children + if (positiveChild.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kV0Child) && + negativeChild.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kV0Child) && + isFullPIDSelected(positiveChild.pidCut(), positiveChild.p(), 999.f, childconfigs.confPositiveChildIndex.value, childconfigs.confChildnSpecies.value, childconfigs.confChildPIDnSigmaMax.value, childconfigs.confPositiveChildPIDnSigmaMax.value, 1.f) && + isFullPIDSelected(negativeChild.pidCut(), negativeChild.p(), 999.f, childconfigs.confNegativeChildIndex.value, childconfigs.confChildnSpecies.value, childconfigs.confChildPIDnSigmaMax.value, childconfigs.confNegativeChildPIDnSigmaMax.value, 1.f)) { + auto positiveChildMass = pdg->Mass(V0configs.confPDGCodePositiveChild); + auto negativeChildMass = pdg->Mass(V0configs.confPDGCodeNegativeChild); + auto positiveChildBoosted = FemtoUniverseMath::boostPRF(positiveChild, positiveChildMass, negativeChild, negativeChildMass); + auto cosineTheta = (positiveChildBoosted.Px() * part.px() + positiveChildBoosted.Py() * part.py() + positiveChildBoosted.Pz() * part.pz()) / (positiveChildBoosted.P() * part.p()); + + V0Histos.fillQA(part); + positiveChildHistos.fillQA(positiveChild); + negativeChildHistos.fillQA(negativeChild); + + thetaRegistry.fill(HIST("Theta/hTheta"), part.p(), cosineTheta); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaPt"), positiveChild.pt(), cosineTheta); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaEta"), positiveChild.eta(), cosineTheta); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaPhi"), positiveChild.phi(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaPt"), negativeChild.pt(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaEta"), negativeChild.eta(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaPhi"), negativeChild.phi(), cosineTheta); } } } + PROCESS_SWITCH(FemtoUniverseDebugV0, processMC, "Enable processing on Monte Carlo", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; return workflow; } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyBase.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyBase.cxx index dbd4b368ea5..d974dd0f408 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyBase.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyBase.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -14,52 +14,113 @@ /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch /// \author Alicja Płachta, WUT Warsaw, alicja.plachta@cern.ch -#include -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.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 "TDatabasePDG.h" +#include "Framework/runDataProcessing.h" -#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include 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; -struct femtoUniverseEfficiencyBase { +struct FemtoUniverseEfficiencyBase { SliceCache cache; using FemtoFullParticles = soa::Join; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + Configurable confIsDebug{"confIsDebug", true, "Enable debug histograms"}; + Configurable confIsMCGen{"confIsMCGen", false, "Enable QA histograms for MC Gen"}; + Configurable confIsMCReco{"confIsMCReco", false, "Enable QA histograms for MC Reco"}; + + // 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 - 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"}; + 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{"confV0InvMassLowLimit", 1.10, "Lower limit of the V0 invariant mass"}; + Configurable confV0InvMassUpLimit{"confV0InvMassUpLimit", 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 + Configurable isKaonLF{"isKaonLF", false, "Enable kaon selection used in LF group"}; // select kaons according to the selection in LF group + struct : o2::framework::ConfigurableGroup { + // Momentum thresholds for Run2 and Run3 + Configurable confMomKaonRun2{"confMomKaonRun2", 0.4, "Momentum threshold for kaon identification using ToF (Run2)"}; + Configurable confMomKaonRun3{"confMomKaonRun3", 0.3, "Momentum threshold for kaon identification using ToF (Run3)"}; + Configurable confMomKaon045{"confMomKaon045", 0.45, "Momentum threshold for kaon identification pT = 0.45 GeV/c"}; + Configurable confMomKaon055{"confMomKaon055", 0.55, "Momentum threshold for kaon identification pT = 0.55 GeV/c"}; + Configurable confMomKaon08{"confMomKaon08", 0.8, "Momentum threshold for kaon identification pT = 0.8 GeV/c"}; + Configurable confMomKaon15{"confMomKaon15", 1.5, "Momentum threshold for kaon identification pT = 1.5 GeV/c"}; + // n sigma cuts for Run 2 + Configurable confKaonNsigmaTPCbelow04Run2{"confKaonNsigmaTPCbelow04Run2", 2.0, "Reject kaons with pT below 0.4 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTPCfrom04to045Run2{"confKaonNsigmaTPCfrom04to045Run2", 1.0, "Reject kaons within pT from 0.4 to 0.45 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTPCfrom045to08Run2{"confKaonNsigmaTPCfrom045to08Run2", 3.0, "Reject kaons within pT from 0.45 to 0.8 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTOFfrom045to08Run2{"confKaonNsigmaTOFfrom045to08Run2", 2.0, "Reject kaons within pT from 0.45 to 0.8 if ToF n sigma is above this value."}; + Configurable confKaonNsigmaTPCfrom08to15Run2{"confKaonNsigmaTPCfrom08to15Run2", 3.0, "Reject kaons within pT from 0.8 to 1.5 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTOFfrom08to15Run2{"confKaonNsigmaTOFfrom08to15Run2", 1.5, "Reject kaons within pT from 0.8 to 1.5 if ToF n sigma is above this value."}; + // n sigma cuts for Run 3 + Configurable confKaonNsigmaTPCfrom0to03{"confKaonNsigmaTPCfrom0to03", 3.0, "Reject kaons within pT from 0.0 to 0.3 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTPCfrom03to045{"confKaonNsigmaTPCfrom03to045", 2.0, "Reject kaons within pT from 0.3 to 0.45 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTPCfrom045to055{"confKaonNsigmaTPCfrom045to055", 1.0, "Reject kaons within pT from 0.45 to 0.55 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTPCfrom055to15{"confKaonNsigmaTPCfrom055to15", 3.0, "Reject kaons within pT from 0.55 to 1.5 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTOFfrom055to15{"confKaonNsigmaTOFfrom055to15", 3.0, "Reject kaons within pT from 0.55 to 1.5 if ToF n sigma is above this value."}; + Configurable confKaonNsigmaTPCfrom15{"confKaonNsigmaTPCfrom15", 3.0, "Reject kaons with pT above 1.5 if TPC n sigma is above this value."}; + Configurable confKaonNsigmaTOFfrom15{"confKaonNsigmaTOFfrom15", 2.0, "Reject kaons with pT above 1.5 if ToF n sigma is above this value.."}; + // n sigma cuts as in LF + Configurable confMomKaonLF{"confMomKaonLF", 0.5, "Momentum threshold for kaon identification using TOF (LF selection)"}; + Configurable confNSigmaTPCKaonLF{"confNSigmaTPCKaonLF", 3.0, "TPC Kaon Sigma as in LF"}; + Configurable confNSigmaCombKaonLF{"confNSigmaCombKaonLF", 3.0, "TPC and TOF Kaon Sigma (combined) as in LF"}; + } ConfKaonSelection; + + /// 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"}; - 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"}; - Configurable ConfChargePart1{"ConfChargePart1", 1, "Charge of the first particle"}; + 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) < ConfEtaMax; + 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) < ConfEtaMax; + Partition partsTrackOneMCReco = (aod::femtouniverseparticle::pt < confPtHighPart1) && (aod::femtouniverseparticle::pt > confPtLowPart1) && (nabs(aod::femtouniverseparticle::eta) < ConfBothTracks.confEtaMax); /// Histogramming for particle 1 FemtoUniverseParticleHisto trackHistoPartOneGen; @@ -69,17 +130,18 @@ struct femtoUniverseEfficiencyBase { 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"}; - 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"}; + 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) < ConfEtaMax; + Partition partsTwoMCGen = (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) < ConfEtaMax; + Partition partsTrackTwoMCReco = (aod::femtouniverseparticle::pt < confPtHighPart2) && (aod::femtouniverseparticle::pt > confPtLowPart2) && (nabs(aod::femtouniverseparticle::eta) < ConfBothTracks.confEtaMax); /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwoGen; @@ -87,29 +149,12 @@ struct femtoUniverseEfficiencyBase { FemtoUniverseParticleHisto trackHistoV0TwoRec; FemtoUniverseParticleHisto trackHistoV0TwoChildPosRec; FemtoUniverseParticleHisto trackHistoV0TwoChildNegRec; + /// Histogramming for Event FemtoUniverseEventHisto eventHisto; - /// The configurables need to be passed to an std::vector - int vPIDPartOne, vPIDPartTwo; - std::vector kNsigma; - - /// particle part - 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 TempFitVar in the pT vs. TempFitVar plot"}; - - 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"}; - } 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"}; - FemtoUniverseTrackSelection trackCuts; + /// Histogram output HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry registryPDG{"PDGHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; @@ -119,43 +164,45 @@ struct femtoUniverseEfficiencyBase { { eventHisto.init(&qaRegistry); - trackHistoPartOneGen.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, ConfPDGCodePartOne, false); - trackHistoPartOneRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, ConfPDGCodePartOne, false); - registryMCOrigin.add("part1/hPt", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH1F, {{240, 0, 6}}}); + trackHistoPartOneGen.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarPDGBins, confIsMCGen, confPDGCodePartOne, false); + trackHistoPartOneRec.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarDCABins, confIsMCReco, 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, ConfTempFitVarPDGBins, 0, ConfPDGCodePartOne, true); - trackHistoV0OneChildPosRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, 0, true, "posChildV0_1"); - trackHistoV0OneChildNegRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, 0, true, "negChildV0_1"); + registryPDG.add("part1/PDGvspTall", "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, ConfTempFitVarPDGBins, 0, ConfPDGCodePartTwo, false); - registryMCOrigin.add("part2/hPt", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH1F, {{240, 0, 6}}}); - if (ConfParticleTypePartTwo == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) { - trackHistoV0TwoRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, ConfPDGCodePartTwo, true); - trackHistoV0TwoChildPosRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, 0, true, "posChildV0_2"); - trackHistoV0TwoChildNegRec.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, 0, true, "negChildV0_2"); + registryPDG.add("part2/PDGvspTall", "PDG;#it{p}_{T} (GeV/c); PDG", {HistType::kTH2F, {{500, 0, 5}, {16001, -8000.5, 8000.5}}}); + if (!confIsSame) { + trackHistoPartTwoGen.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarPDGBins, confIsMCGen, confPDGCodePartTwo, false); + trackHistoPartTwoRec.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarDCABins, confIsMCReco, 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 + 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 < ConfMomProton) { - if (TMath::Abs(nsigmaTPCPr) < ConfBothTracks.ConfNsigmaTPCProton) { + if (mom < ConfBothTracks.confMomProton) { + if (std::abs(nsigmaTPCPr) < ConfBothTracks.confNsigmaTPCProton) { return true; } else { return false; } } else { - if (TMath::Hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfBothTracks.ConfNsigmaCombinedProton) { + if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfBothTracks.confNsigmaCombinedProton) { return true; } else { return false; @@ -164,36 +211,69 @@ struct femtoUniverseEfficiencyBase { 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) { - return true; + if (isKaonRun2 == true) { + if (mom < ConfKaonSelection.confMomKaonRun2) { // < 0.4 GeV/c + return std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCbelow04Run2; + } else if (mom > ConfKaonSelection.confMomKaonRun2 && mom < ConfKaonSelection.confMomKaon045) { // 0.4 - 0.45 + return std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCfrom04to045Run2; + } else if (mom > ConfKaonSelection.confMomKaon045 && mom < ConfKaonSelection.confMomKaon08) { // 0.45 - 0.8 + return (std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCfrom045to08Run2 && std::abs(nsigmaTOFK) < ConfKaonSelection.confKaonNsigmaTOFfrom045to08Run2); + } else if (mom > ConfKaonSelection.confMomKaon08 && mom < ConfKaonSelection.confMomKaon15) { // 0.8 - 1.5 + return (std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCfrom08to15Run2 && std::abs(nsigmaTOFK) < ConfKaonSelection.confKaonNsigmaTOFfrom08to15Run2); } else { return false; } - } else if (mom < 0.45) { // 0.30 - 0.45 - if (TMath::Abs(nsigmaTPCK) < 2.0) { - return true; + } else { + if (mom < ConfKaonSelection.confMomKaonRun3) { // 0.0-0.3 + if (std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCfrom0to03) { + return true; + } else { + return false; + } + } else if (mom < ConfKaonSelection.confMomKaon045) { // 0.30 - 0.45 + if (std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCfrom03to045) { + return true; + } else { + return false; + } + } else if (mom < ConfKaonSelection.confMomKaon055) { // 0.45-0.55 + if (std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCfrom045to055) { + return true; + } else { + return false; + } + } else if (mom < ConfKaonSelection.confMomKaon15) { // 0.55-1.5 (now we use TPC and TOF) + if ((std::abs(nsigmaTOFK) < ConfKaonSelection.confKaonNsigmaTOFfrom055to15) && (std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCfrom055to15)) { + { + return true; + } + } else { + return false; + } + } else if (mom > ConfKaonSelection.confMomKaon15) { // > 1.5 GeV/c + if ((std::abs(nsigmaTOFK) < ConfKaonSelection.confKaonNsigmaTOFfrom15) && (std::abs(nsigmaTPCK) < ConfKaonSelection.confKaonNsigmaTPCfrom15)) { + return true; + } else { + return false; + } } else { return false; } - } else if (mom < 0.55) { // 0.45-0.55 - if (TMath::Abs(nsigmaTPCK) < 1.0) { + } + } + + bool isKaonNSigmaLF(float mom, float nsigmaTPCK, float nsigmaTOFK) + { + if (mom < ConfKaonSelection.confMomKaonLF) { + if (std::abs(nsigmaTPCK) < ConfKaonSelection.confNSigmaTPCKaonLF) { 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)) { + } else if (mom >= ConfKaonSelection.confMomKaonLF) { + if (std::sqrt(nsigmaTPCK * nsigmaTPCK + nsigmaTOFK * nsigmaTOFK) < ConfKaonSelection.confNSigmaCombKaonLF) { return true; } else { return false; @@ -203,16 +283,16 @@ struct femtoUniverseEfficiencyBase { } } - bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + bool isPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) { - if (mom < 0.5) { - if (TMath::Abs(nsigmaTPCPi) < ConfBothTracks.ConfNsigmaTPCPion) { + if (mom < ConfBothTracks.confMomPion) { + if (std::abs(nsigmaTPCPi) < ConfBothTracks.confNsigmaTPCPion) { return true; } else { return false; } - } else if (mom > 0.5) { - if (TMath::Hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfBothTracks.ConfNsigmaCombinedPion) { + } else { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfBothTracks.confNsigmaCombinedPion) { return true; } else { return false; @@ -221,20 +301,41 @@ struct femtoUniverseEfficiencyBase { return false; } - bool IsParticleNSigma(int pdgCode, float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) + 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; + } + } + + 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); + 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); + if (isKaonLF) { + return isKaonNSigmaLF(mom, nsigmaTPCK, nsigmaTOFK); + } else { + return isKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + } + break; + case 1000010020: // Deuteron + case -1000010020: // Antideuteron + return isDeuteronNSigma(mom, nsigmaTPCDe, nsigmaTOFDe); break; default: return false; @@ -243,7 +344,7 @@ struct femtoUniverseEfficiencyBase { bool invMLambda(float invMassLambda, float invMassAntiLambda) { - if ((invMassLambda < ConfV0InvMassLowLimit || invMassLambda > ConfV0InvMassUpLimit) && (invMassAntiLambda < ConfV0InvMassLowLimit || invMassAntiLambda > ConfV0InvMassUpLimit)) { + if ((invMassLambda < confV0InvMassLowLimit || invMassLambda > confV0InvMassUpLimit) && (invMassAntiLambda < confV0InvMassLowLimit || invMassAntiLambda > confV0InvMassUpLimit)) { return false; } return true; @@ -256,29 +357,24 @@ struct femtoUniverseEfficiencyBase { } /// 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 grouppartsOneMCGen partition for the first particle passed by the process function - /// @param grouppartsTwoGen 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 grouppartsTwoMCGen partition for the second particle passed by the process function template - void doMCGen(PartitionType grouppartsOneMCGen, PartitionType grouppartsTwoGen) + void doMCGen(PartitionType grouppartsOneMCGen, PartitionType grouppartsTwoMCGen) { /// Histogramming same event - for (auto& part : grouppartsOneMCGen) { - if (!ConfNoPDGPartOne && part.pidcut() != ConfPDGCodePartOne) { + for (const auto& part : grouppartsOneMCGen) { + if (!confNoPDGPartOne && part.tempFitVar() != confPDGCodePartOne) { continue; } trackHistoPartOneGen.fillQA(part); } - if (!ConfIsSame) { - for (auto& part : grouppartsTwoGen) { - if (!ConfNoPDGPartOne && part.pidcut() != ConfPDGCodePartTwo) { + if (!confIsSame) { + for (const auto& part : grouppartsTwoMCGen) { + if (!confNoPDGPartTwo && part.tempFitVar() != confPDGCodePartTwo) { continue; } trackHistoPartTwoGen.fillQA(part); @@ -287,47 +383,62 @@ struct femtoUniverseEfficiencyBase { } /// 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 grouppartsOneMCGen partition for the first particle passed by the process function - /// @param grouppartsTwoGen 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 doMCRecTrackTrack(PartitionType grouppartsOneMCGen, PartitionType grouppartsTwoGen) + /// @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 : grouppartsOneMCGen) { - 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))) { + for (const 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/PDGvspTall"), part.pt(), mcParticle.pdgMCTruth()); + trackHistoPartOneRec.fillQA(part); + + if (!(mcParticle.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary)) { + continue; + } + + if (!(std::abs(mcParticle.pdgMCTruth()) == std::abs(confPDGCodePartOne))) { + continue; + } + registryPDG.fill(HIST("part1/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); registryMCOrigin.fill(HIST("part1/hPt"), mcParticle.pt()); } - if (!ConfIsSame) { - for (auto& part : grouppartsTwoGen) { - 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))) { + if (!confIsSame) { + for (const 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/PDGvspTall"), part.pt(), mcParticle.pdgMCTruth()); + trackHistoPartTwoRec.fillQA(part); + + if (!(mcParticle.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary)) { + continue; + } + + if (!(std::abs(mcParticle.pdgMCTruth()) == std::abs(confPDGCodePartTwo))) { + continue; + } + registryPDG.fill(HIST("part2/PDGvspT"), part.pt(), mcParticle.pdgMCTruth()); registryMCOrigin.fill(HIST("part2/hPt"), mcParticle.pt()); } @@ -335,25 +446,20 @@ struct femtoUniverseEfficiencyBase { } /// 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 grouppartsOneMCGen partition for the first particle passed by the process function - /// @param grouppartsTwoGen 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 doMCRecTrackPhi(PartitionType grouppartsOneMCGen, PartitionType grouppartsTwoGen) + /// @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 - /// Histogramming same event - for (auto& part : grouppartsOneMCGen) { - 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))) { + for (const 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); + trackHistoPartOneRec.fillQA(part); if (!part.has_fdMCParticle()) { continue; @@ -364,13 +470,13 @@ struct femtoUniverseEfficiencyBase { registryMCOrigin.fill(HIST("part1/hPt"), mcParticle.pt()); } - if (!ConfIsSame) { - for (auto& part : grouppartsTwoGen) { - if (part.partType() != ConfParticleTypePartTwo || part.sign() != ConfChargePart2) { + if (!confIsSame) { + for (const auto& part : grouppartsTwoMCRec) { + if (part.partType() != confParticleTypePartTwo || part.sign() != confChargePart2) { continue; } - trackHistoPartTwoRec.fillQA(part); + trackHistoPartTwoRec.fillQA(part); if (!part.has_fdMCParticle()) { continue; @@ -384,38 +490,36 @@ struct femtoUniverseEfficiencyBase { } /// 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 ParticlesType /// @tparam isMC: enables Monte Carlo truth specific histograms - /// @param grouppartsOneMCGen partition for the first particle passed by the process function - /// @param grouppartsTwoGen 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 doMCRecV0V0(PartitionType grouppartsOneMCGen, PartitionType grouppartsTwoGen, ParticlesType parts) + /// @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 : grouppartsOneMCGen) { + for (const auto& part : grouppartsOneMCRec) { - if (part.partType() != ConfParticleTypePartOne || !invMLambda(part.mLambda(), part.mAntiLambda())) { + 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 + 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 + 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")); + 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; @@ -430,26 +534,26 @@ struct femtoUniverseEfficiencyBase { registryMCOrigin.fill(HIST("part1/hPt"), mcParticle.pt()); } - if (!ConfIsSame) { - for (auto& part : grouppartsTwoGen) { + if (!confIsSame) { + for (const auto& part : grouppartsTwoMCRec) { - if (part.partType() != ConfParticleTypePartTwo || !invMLambda(part.mLambda(), part.mAntiLambda())) { + 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 + 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 + 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")); + 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; @@ -467,24 +571,24 @@ struct femtoUniverseEfficiencyBase { } /// 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 ParticlesType /// @tparam isMC: enables Monte Carlo truth specific histograms - /// @param grouppartsOneMCGen partition for the first particle passed by the process function - /// @param grouppartsTwoGen partition for the second particle passed by the process function - /// @param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) - template - void doMCRecTrackV0(PartitionType grouppartsOneMCGen, PartitionType grouppartsTwoGen, ParticlesType const& parts) + /// @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 : grouppartsOneMCGen) { - 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))) { + for (const 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); + trackHistoPartOneRec.fillQA(part); if (!part.has_fdMCParticle()) continue; @@ -493,25 +597,25 @@ struct femtoUniverseEfficiencyBase { registryMCOrigin.fill(HIST("part1/hPt"), mcParticle.pt()); } - if (!ConfIsSame) { - for (auto& part : grouppartsTwoGen) { + if (!confIsSame) { + for (const auto& part : grouppartsTwoMCRec) { - if (part.partType() != ConfParticleTypePartTwo || !invMLambda(part.mLambda(), part.mAntiLambda())) { + 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 + 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 + 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")); + 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; @@ -528,83 +632,106 @@ struct femtoUniverseEfficiencyBase { } } - /// process function for to call doMCPlots with Data + /// process function for to call doMCRecTrackTrack with Data /// \param col subscribe to the collision table (Data) - /// \param parts subscribe to the femtoUniverseParticleTable - void processTrackTrack(o2::aod::FDCollision& col, - FemtoFullParticles&, aod::FDMCParticles const&) + void processTrackTrack(FilteredFDCollision const& col, + FemtoFullParticles const&, aod::FdMCParticles const&) { fillCollision(col); // MCGen auto thegrouppartsOneMCGen = partsOneMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegrouppartsTwoGen = partsTwoGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoGen); + auto thegrouppartsTwoMCGen = partsTwoMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + if (confIsMCGen) { + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); + } else { + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); + } // MCRec auto thegroupPartsTrackOneRec = partsTrackOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsTrackTwoReco = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doMCRecTrackTrack(thegroupPartsTrackOneRec, thegroupPartsTrackTwoReco); + auto thegroupPartsTrackTwoRec = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + if (confIsDebug) { + if (confIsMCGen) { + doMCRecTrackTrack(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec); + } else { + doMCRecTrackTrack(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec); + } + } else { + doMCRecTrackTrack(thegroupPartsTrackOneRec, thegroupPartsTrackTwoRec); + } } - PROCESS_SWITCH(femtoUniverseEfficiencyBase, processTrackTrack, "Enable processing track-track efficiency task", true); + PROCESS_SWITCH(FemtoUniverseEfficiencyBase, processTrackTrack, "Enable processing track-track efficiency task", true); - /// process function for to call doMCPlots with Data + /// process function for to call doMCRecTrackPhi with Data /// \param col subscribe to the collision table (Data) - /// \param parts subscribe to the femtoUniverseParticleTable - void processTrackPhi(o2::aod::FDCollision& col, - FemtoFullParticles&, aod::FDMCParticles const&) + void processTrackPhi(FilteredFDCollision const& col, + FemtoFullParticles const&, aod::FdMCParticles const&) { fillCollision(col); // MCGen auto thegrouppartsOneMCGen = partsOneMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegrouppartsTwoGen = partsTwoGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoGen); + auto thegrouppartsTwoMCGen = partsTwoMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); // MCRec auto thegroupPartsTrackOneRec = partsTrackOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsTrackTwoReco = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doMCRecTrackPhi(thegroupPartsTrackOneRec, thegroupPartsTrackTwoReco); + 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_SWITCH(FemtoUniverseEfficiencyBase, processTrackPhi, "Enable processing track-phi efficiency task", false); - /// process function for to call doMCPlots with Data + /// process function for to call doMCRecV0V0 with Data /// \param col subscribe to the collision table (Data) /// \param parts subscribe to the femtoUniverseParticleTable - void processV0V0(o2::aod::FDCollision& col, - FemtoFullParticles& parts, aod::FDMCParticles const&) + void processV0V0(FilteredFDCollision const& col, + FemtoFullParticles const& parts, aod::FdMCParticles const&) { fillCollision(col); // MCGen auto thegrouppartsOneMCGen = partsOneMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegrouppartsTwoGen = partsTwoGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoGen); + auto thegrouppartsTwoMCGen = partsTwoMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); // MCRec auto thegroupPartsTrackOneRec = partsTrackOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsTrackTwoReco = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doMCRecV0V0(thegroupPartsTrackOneRec, thegroupPartsTrackTwoReco, parts); + 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_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(o2::aod::FDCollision& col, - FemtoFullParticles& parts, aod::FDMCParticles const&) + void processTrackV0(FilteredFDCollision const& col, + FemtoFullParticles const& parts, aod::FdMCParticles const&) { fillCollision(col); // MCGen auto thegrouppartsOneMCGen = partsOneMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegrouppartsTwoGen = partsTwoGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoGen); + auto thegrouppartsTwoMCGen = partsTwoMCGen->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCGen(thegrouppartsOneMCGen, thegrouppartsTwoMCGen); // MCRec auto thegroupPartsTrackOneRec = partsTrackOneMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - auto thegroupPartsTrackTwoReco = partsTrackTwoMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - doMCRecTrackV0(thegroupPartsTrackOneRec, thegroupPartsTrackTwoReco, parts); + 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); + PROCESS_SWITCH(FemtoUniverseEfficiencyBase, processTrackV0, "Enable processing track-V0 efficiency task", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; return workflow; } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyTask.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyTask.cxx index b1c4493470f..e9367ba944a 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyTask.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseEfficiencyTask.cxx @@ -17,25 +17,28 @@ /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch // O2 includes -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/EventSelection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseCollisionSelection.h" -#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" -#include "Framework/O2DatabasePDGPlugin.h" #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 +76,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"}; diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniverseHashTask.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniverseHashTask.cxx index 1fef7a97ac2..6f7a7d5db2b 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniverseHashTask.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniverseHashTask.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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..ffb5c8f56ea --- /dev/null +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackCascadeExtended.cxx @@ -0,0 +1,1167 @@ +// 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 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 "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include + +#include +#include +#include +#include + +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; + using FemtoRecoFullParticles = soa::Join; + using FemtoRecoBasicParticles = soa::Join; + + 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"}; + + // TODO: Add seperate selection for daughter particles + // Configurable confNSigmaTPCPion{"confNSigmaTPCPion", 4, "NSigmaTPCPion"}; + // Configurable confNSigmaTPCProton{"confNSigmaTPCProton", 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 confCascPDGCodePartTwo{"confCascPDGCodePartTwo", 3312, "Particle 2 (Cascade) - PDG code"}; + Configurable confCascType1{"confCascType1", 0, "select one of the Cascades (Omega = 0, Xi = 1, anti-Omega = 2, anti-Xi = 3) for track-cascade combination"}; + Configurable confCascType2{"confCascType2", 0, "select one of the Cascades (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 confIsSameSignCPR{"confIsSameSignCPR", false, "Close Pair Rejection for same sign children of cascades"}; + 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"}; + Configurable confUseStrangenessTOF{"confUseStrangenessTOF", true, "Use strangeness TOF for cascade PID"}; + + 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{"confTrkTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + Configurable confNEventsMix{"confNEventsMix", 5, "Number of events for mixing"}; + + // Efficiency + Configurable confLocalEfficiency{"confLocalEfficiency", "", "Local path to efficiency .root file"}; + + Filter collisionFilter = (nabs(aod::collision::posZ) < confZVertexCut); + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; + + /// Partition for particle 1 using extended table (track) + Partition partsOneFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::mAntiLambda == confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + + /// Partition for particle 1 without extended table (track) + Partition partsOneBasic = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::mAntiLambda == confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + Partition partsOneMCgenBasic = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + Partition partsOneMCrecoBasic = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::mAntiLambda == confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + + /// Partition for particle 2 using extended table (cascade) + Partition partsTwoFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kCascade)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + + /// Partition for particle 2 without extended table (cascade) + Partition partsTwoBasic = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kCascade)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + Partition partsTwoMCgenBasic = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + Partition partsTwoMCrecoBasic = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kCascade)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + + /// 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; + FemtoUniverseDetaDphiStar pairCloseRejectionCasc; + + 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}; + + std::set cascDuplicates; + + std::unique_ptr plocalEffFile; + std::unique_ptr plocalEffp1; + std::unique_ptr plocalEffp2; + + // 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 invMassXi, float invMassOmega, int cascType) + { + return (((cascType == 1 || cascType == 3) && (invMassXi > confCascInvMassLowLimit && invMassXi < confCascInvMassUpLimit)) || ((cascType == 0 || cascType == 2) && (invMassOmega > confCascInvMassLowLimit && invMassOmega < confCascInvMassUpLimit))); + } + + 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, float* partSigma = 0) + { + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; + if (partSigma) + *partSigma = tpcNSigmas[id]; + return isNSigmaTPC(tpcNSigmas[id]); + } + + template + bool isParticleTOF(const T& part, int id, float* partSigma = 0) + { + const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; + if (partSigma) + *partSigma = tofNSigmas[id]; + return isNSigmaTOF(part.p(), tofNSigmas[id], part.tempFitVar()); + } + + template + bool isParticleCombined(const T& part, int id) + { + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; + const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; + + return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id]); + } + + void init(InitContext const&) + { + std::vector multBinning = {0.0, 5.0, 10.0, 20.0, 30.0f, 40.0, 50.0, 60.0f, 70.0, 80.0, 100.0, 200.0, 99999.0}; + // 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)"}; + AxisSpec multAxis = {multBinning, "Multiplicity"}; + + // 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}}); + rXiQA.add("hInvMpTmult", "hInvMpTmult", kTH3F, {{ptAxis}, {aXiMassAxis}, {multAxis}}); + + eventHisto.init(&qaRegistry); + /// nSigma debug histograms for the selected particle species only i.e. not sigmas of all particles mixed together + 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}}); + qaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + + qaRegistry.add("V0Child_pos/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("V0Child_neg/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("hBachelor/nSigmaTPC", "; #it{p} (GeV/#it{c}); n#sigma_{TPC}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("V0Child_pos/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("V0Child_neg/nSigmaTOF", "; #it{p} (GeV/#it{c}); n#sigma_{TOF}", kTH2F, {{100, 0, 10}, {200, -4.975, 5.025}}); + qaRegistry.add("hBachelor/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); + sameEventCont.setPDGCodes(confTrkPDGCodePartOne, confCascPDGCodePartTwo); + mixedEventCont.setPDGCodes(confTrkPDGCodePartOne, confCascPDGCodePartTwo); + + pairCleaner.init(&qaRegistry); + pairCleanerCasc.init(&qaRegistry); + if (confIsCPR.value) { + if (doprocessSameEvent || doprocessSameEventBitmask || doprocessMixedEvent || doprocessMixedEventBitmask) + pairCloseRejection.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value, 0, 0, confIsSameSignCPR.value); + if (doprocessSameEventCasc || doprocessSameEventCascBitmask || doprocessMixedEventCasc || doprocessMixedEventCascBitmask) + pairCloseRejectionCasc.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value, 0, 0, confIsSameSignCPR.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 || doprocessSameEventBitmask || doprocessMixedEvent || doprocessMixedEventBitmask) { + 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 = (confCascType1 == 0 || confCascType1 == 1) ? std::unique_ptr(plocalEffFile.get()->Get("Cascade")) : std::unique_ptr(plocalEffFile.get()->Get("AntiCascade")); + LOGF(info, "Loaded efficiency histograms for track-Cascade."); + } else if (doprocessSameEventCasc || doprocessSameEventCascBitmask || doprocessMixedEventCasc || doprocessMixedEventCascBitmask) { + plocalEffp1 = (confCascType1 == 0 || confCascType1 == 1) ? std::unique_ptr(plocalEffFile.get()->Get("Cascade")) : std::unique_ptr(plocalEffFile.get()->Get("AntiCascade")); + plocalEffp2 = (confCascType2 == 0 || confCascType2 == 1) ? std::unique_ptr(plocalEffFile.get()->Get("Cascade")) : std::unique_ptr(plocalEffFile.get()->Get("AntiCascade")); + LOGF(info, "Loaded efficiency histograms for Cascade-Cascade."); + } + } + } + + void processCascadeQA([[maybe_unused]] const FilteredFDCollision& col, const FemtoFullParticles& parts, const aod::FDCascParticles& fdcascs) + { + for (const auto& casc : fdcascs) { + const auto& part = casc.fdParticle_as(); + rXiQA.fill(HIST("hMassXi"), part.mLambda()); + + const auto& posChild = parts.iteratorAt(part.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + + float posChildTPC, negChildTPC, bachelorTPC, posChildTOF, negChildTOF, bachelorTOF; + if (!isParticleTPC(posChild, CascChildTable[confCascType1][0], &posChildTPC) || !isParticleTPC(negChild, CascChildTable[confCascType1][1], &negChildTPC) || !isParticleTPC(bachelor, CascChildTable[confCascType1][2], &bachelorTPC)) + continue; + + if (!isParticleTOF(posChild, CascChildTable[confCascType1][0], &posChildTOF) || !isParticleTOF(negChild, CascChildTable[confCascType1][1], &negChildTOF) || !isParticleTOF(bachelor, CascChildTable[confCascType1][2], &bachelorTOF)) + continue; + + rXiQA.fill(HIST("hPtXi"), part.pt()); + rXiQA.fill(HIST("hEtaXi"), part.eta()); + rXiQA.fill(HIST("hPhiXi"), part.phi()); + rXiQA.fill(HIST("hMassXiSelected"), part.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"), part.pt(), part.mLambda()); + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processCascadeQA, "Enable processing cascades", false); + + template + using hasSigma = decltype(std::declval().tpcNSigmaStorePr()); + + /// track - cascade correlations + template + void doSameEvent(const FilteredFDCollision& col, const TableType& parts, PartitionType& partsOne, PartitionType& partsTwo) + { + 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); + + eventHisto.fillQA(col); + + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); + + for (const auto& part : groupPartsTwo) { + if (!invMCascade(part.mLambda(), part.mAntiLambda(), confCascType1)) /// mLambda stores Xi mass, mAntiLambda stores Omega mass + continue; + + const auto& posChild = parts.iteratorAt(part.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + /// Child particles must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + float posChildTPC, negChildTPC, bachelorTPC, posChildTOF, negChildTOF, bachelorTOF; + if (!isParticleTPC(posChild, CascChildTable[confCascType1][0], &posChildTPC) || !isParticleTPC(negChild, CascChildTable[confCascType1][1], &negChildTPC) || !isParticleTPC(bachelor, CascChildTable[confCascType1][2], &bachelorTPC)) + continue; + + if (!isParticleTOF(posChild, CascChildTable[confCascType1][0], &posChildTOF) || !isParticleTOF(negChild, CascChildTable[confCascType1][1], &negChildTOF) || !isParticleTOF(bachelor, CascChildTable[confCascType1][2], &bachelorTOF)) + continue; + + posChildHistos.fillQA(posChild); + negChildHistos.fillQA(negChild); + bachHistos.fillQABase(bachelor, HIST("hBachelor")); + + qaRegistry.fill(HIST("V0Child_pos/nSigmaTPC"), posChild.p(), posChildTPC); + qaRegistry.fill(HIST("V0Child_neg/nSigmaTPC"), negChild.p(), negChildTPC); + qaRegistry.fill(HIST("hBachelor/nSigmaTPC"), bachelor.p(), bachelorTPC); + qaRegistry.fill(HIST("V0Child_pos/nSigmaTOF"), posChild.p(), posChildTOF); + qaRegistry.fill(HIST("V0Child_neg/nSigmaTOF"), negChild.p(), negChildTOF); + qaRegistry.fill(HIST("hBachelor/nSigmaTOF"), bachelor.p(), bachelorTOF); + + cascQAHistos.fillQA(part); + + } else { + if ((posChild.pidCut() & (1u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (1u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType1][2])) == 0) + continue; + + if (confUseStrangenessTOF) { + if (((confCascType1 == 1 || confCascType1 == 3) && (part.pidCut() & 7) != 7) || ((confCascType1 == 0 || confCascType1 == 2) && (part.pidCut() & 56) != 56)) + continue; + } else { + if ((posChild.pidCut() & (8u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (8u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType1][2])) == 0) + continue; + } + + posChildHistos.fillQA(posChild); + negChildHistos.fillQA(negChild); + bachHistos.fillQABase(bachelor, HIST("hBachelor")); + cascQAHistos.fillQA(part); + } + rXiQA.fill(HIST("hInvMpTmult"), part.pt(), part.mLambda(), multCol); + } + + if constexpr (std::experimental::is_detected::value) { + for (const auto& part : groupPartsOne) { + /// PID plot for track particle + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; + const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; + + if (!isNSigmaCombined(part.p(), tpcNSigmas[confTrackChoicePartOne], tofNSigmas[confTrackChoicePartOne])) + continue; + + if (part.mAntiLambda() > 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.mAntiLambda() < 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 inv mass cut (mLambda stores Xi mass, mAntiLambda stores Omega mass) + if (!invMCascade(p2.mLambda(), p2.mAntiLambda(), confCascType1)) + continue; + // PID + if constexpr (std::experimental::is_detected::value) { + if (!isParticleCombined(p1, confTrackChoicePartOne)) + continue; + } else { + if ((p1.pidCut() & (64u << confTrackChoicePartOne)) == 0) + continue; + } + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + continue; + } + } + + const auto& posChild = parts.iteratorAt(p2.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); + /// Child particles must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + 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; + } else { + if ((posChild.pidCut() & (1u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (1u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType1][2])) == 0) + continue; + if (confUseStrangenessTOF) { + if (((confCascType1 == 1 || confCascType1 == 3) && (p2.pidCut() & 7) != 7) || ((confCascType1 == 0 || confCascType1 == 2) && (p2.pidCut() & 56) != 56)) + continue; + } else { + if ((posChild.pidCut() & (8u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (8u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType1][2])) == 0) + continue; + } + } + 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())); + sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); + } + } + + void processSameEvent(const FilteredFDCollision& col, const FemtoFullParticles& parts) + { + doSameEvent(col, parts, partsOneFull, partsTwoFull); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEvent, "Enable processing same event for track - cascade", false); + + void processSameEventBitmask(const FilteredFDCollision& col, const aod::FDParticles& parts) + { + doSameEvent(col, parts, partsOneBasic, partsTwoBasic); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEventBitmask, "Enable processing same event for track - cascade using bitmask for PID", false); + + /// cascade - cascade correlations + template + void doSameEventCasc(const FilteredFDCollision& col, const TableType& parts, PartitionType& partsTwo) + { + 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(), confCascType1)) /// mLambda stores Xi mass, mAntiLambda stores Omega mass + continue; + + if constexpr (std::experimental::is_detected::value) + cascQAHistos.fillQA(part); + else + cascQAHistos.fillQA(part); + + const auto& posChild = parts.iteratorAt(part.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + /// Check daughters of first cascade + if constexpr (std::experimental::is_detected::value) { + 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")); + } else { + if ((posChild.pidCut() & (1u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (1u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType1][2])) == 0) + continue; + if (confUseStrangenessTOF) { + if (((confCascType1 == 1 || confCascType1 == 3) && (part.pidCut() & 7) != 7) || ((confCascType1 == 0 || confCascType1 == 2) && (part.pidCut() & 56) != 56)) + continue; + } else { + if ((posChild.pidCut() & (8u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (8u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType1][2])) == 0) + continue; + } + + posChildHistos.fillQA(posChild); + negChildHistos.fillQA(negChild); + bachHistos.fillQABase(bachelor, HIST("hBachelor")); + } + } + + auto pairDuplicateCheckFunc = [&](auto& p1, auto& p2) -> void { + // Cascade inv mass cut for p1 (mLambda stores Xi mass, mAntiLambda stores Omega mass) + if (!invMCascade(p1.mLambda(), p1.mAntiLambda(), confCascType1)) + return; + // Cascade inv mass cut for p2 + if (!invMCascade(p2.mLambda(), p2.mAntiLambda(), confCascType2)) + return; + // track cleaning & checking for duplicate pairs + if (!pairCleanerCasc.isCleanPair(p1, p2, parts)) { + // mark for rejection the cascades that share a daughter with other cascades + cascDuplicates.insert(p1.globalIndex()); + cascDuplicates.insert(p2.globalIndex()); + } + }; + + auto pairProcessFunc = [&](auto& p1, auto& p2) -> void { + if (cascDuplicates.contains(p1.globalIndex()) || cascDuplicates.contains(p2.globalIndex())) + return; + if (!invMCascade(p1.mLambda(), p1.mAntiLambda(), confCascType1)) + return; + if (!invMCascade(p2.mLambda(), p2.mAntiLambda(), confCascType2)) + return; + if (confIsCPR.value) { + if (pairCloseRejectionCasc.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + return; + } + } + + const auto& posChild1 = parts.iteratorAt(p1.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild1 = parts.iteratorAt(p1.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor1 = parts.iteratorAt(p1.globalIndex() - 1 - parts.begin().globalIndex()); + /// Child particles must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild1, CascChildTable[confCascType1][0]) || !isParticleTPC(negChild1, CascChildTable[confCascType1][1]) || !isParticleTPC(bachelor1, CascChildTable[confCascType1][2])) + return; + if (!isParticleTOF(posChild1, CascChildTable[confCascType1][0]) || !isParticleTOF(negChild1, CascChildTable[confCascType1][1]) || !isParticleTOF(bachelor1, CascChildTable[confCascType1][2])) + return; + } else { + if ((posChild1.pidCut() & (1u << CascChildTable[confCascType1][0])) == 0 || (negChild1.pidCut() & (1u << CascChildTable[confCascType1][1])) == 0 || (bachelor1.pidCut() & (1u << CascChildTable[confCascType1][2])) == 0) + return; + if (confUseStrangenessTOF) { + if (((confCascType1 == 1 || confCascType1 == 3) && (p1.pidCut() & 7) != 7) || ((confCascType1 == 0 || confCascType1 == 2) && (p1.pidCut() & 56) != 56)) + return; + } else { + if ((posChild1.pidCut() & (8u << CascChildTable[confCascType1][0])) == 0 || (negChild1.pidCut() & (8u << CascChildTable[confCascType1][1])) == 0 || (bachelor1.pidCut() & (8u << CascChildTable[confCascType1][2])) == 0) + return; + } + } + + const auto& posChild2 = parts.iteratorAt(p2.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild2 = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor2 = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); + /// Child particles must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild2, CascChildTable[confCascType2][0]) || !isParticleTPC(negChild2, CascChildTable[confCascType2][1]) || !isParticleTPC(bachelor2, CascChildTable[confCascType2][2])) + return; + if (!isParticleTOF(posChild2, CascChildTable[confCascType2][0]) || !isParticleTOF(negChild2, CascChildTable[confCascType2][1]) || !isParticleTOF(bachelor2, CascChildTable[confCascType2][2])) + return; + } else { + if ((posChild2.pidCut() & (1u << CascChildTable[confCascType2][0])) == 0 || (negChild2.pidCut() & (1u << CascChildTable[confCascType2][1])) == 0 || (bachelor2.pidCut() & (1u << CascChildTable[confCascType2][2])) == 0) + return; + if (confUseStrangenessTOF) { + if (((confCascType2 == 1 || confCascType2 == 3) && (p2.pidCut() & 7) != 7) || ((confCascType2 == 0 || confCascType2 == 2) && (p2.pidCut() & 56) != 56)) + return; + } else { + if ((posChild2.pidCut() & (8u << CascChildTable[confCascType2][0])) == 0 || (negChild2.pidCut() & (8u << CascChildTable[confCascType2][1])) == 0 || (bachelor2.pidCut() & (8u << CascChildTable[confCascType2][2])) == 0) + return; + } + } + + 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())); + sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); + }; + cascDuplicates.clear(); + if (confCascType1 == confCascType2) { + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairDuplicateCheckFunc(p1, p2); + } + /// Now build the combinations for identical cascades + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairProcessFunc(p1, p2); + } + } else { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairDuplicateCheckFunc(p1, p2); + } + /// Now build the combinations for non-identical cascades + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsTwo, groupPartsTwo))) { + pairProcessFunc(p1, p2); + } + } + } + + void processSameEventCasc(const FilteredFDCollision& col, const FemtoFullParticles& parts) + { + doSameEventCasc(col, parts, partsTwoFull); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEventCasc, "Enable processing same event for cascade - cascade", false); + + void processSameEventCascBitmask(const FilteredFDCollision& col, const aod::FDParticles& parts) + { + doSameEventCasc(col, parts, partsTwoBasic); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEventCascBitmask, "Enable processing same event for cascade - cascade using bitmask for PID", false); + + /// track - cascade correlations + template + void doMixedEvent(const FilteredFDCollisions& cols, const TableType& parts, PartitionType& partsOne, PartitionType& partsTwo) + { + 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 = 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) { + return; + } + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // Cascade inv mass cut (mLambda stores Xi mass, mAntiLambda stores Omega mass) + if (!invMCascade(p2.mLambda(), p2.mAntiLambda(), confCascType1)) + continue; + // PID + if constexpr (std::experimental::is_detected::value) { + if (!isParticleCombined(p1, confTrackChoicePartOne)) + continue; + } else { + if ((p1.pidCut() & (64u << confTrackChoicePartOne)) == 0) + continue; + } + + const auto& posChild = parts.iteratorAt(p2.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); + /// Child particles must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + 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; + } else { + if ((posChild.pidCut() & (1u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (1u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType1][2])) == 0) + continue; + if (confUseStrangenessTOF) { + if (((confCascType1 == 1 || confCascType1 == 3) && (p2.pidCut() & 7) != 7) || ((confCascType1 == 0 || confCascType1 == 2) && (p2.pidCut() & 56) != 56)) + continue; + } else { + if ((posChild.pidCut() & (8u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (8u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType1][2])) == 0) + continue; + } + } + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } + } + + 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())); + mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); + } + }; + + if (confUseCent) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + qaRegistry.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); + qaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), collision1.multNtr()})); + } + } + } + + void processMixedEvent(const FilteredFDCollisions& cols, const FemtoFullParticles& parts) + { + doMixedEvent(cols, parts, partsOneFull, partsTwoFull); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEvent, "Enable processing mixed event for track - cascade", false); + + void processMixedEventBitmask(const FilteredFDCollisions& cols, const aod::FDParticles& parts) + { + doMixedEvent(cols, parts, partsOneBasic, partsTwoBasic); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEventBitmask, "Enable processing mixed event for track - cascade using bitmask for PID", false); + + /// cascade - cascade correlations + template + void doMixedEventCasc(const FilteredFDCollisions& cols, const TableType& parts, PartitionType& partsTwo) + { + 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 inv mass cut for p1 (mLambda stores Xi mass, mAntiLambda stores Omega mass) + if (!invMCascade(p1.mLambda(), p1.mAntiLambda(), confCascType1)) + continue; + // Cascade inv mass cut for p2 + if (!invMCascade(p2.mLambda(), p2.mAntiLambda(), confCascType2)) + continue; + + const auto& posChild1 = parts.iteratorAt(p1.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild1 = parts.iteratorAt(p1.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor1 = parts.iteratorAt(p1.globalIndex() - 1 - parts.begin().globalIndex()); + /// Child particles must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild1, CascChildTable[confCascType1][0]) || !isParticleTPC(negChild1, CascChildTable[confCascType1][1]) || !isParticleTPC(bachelor1, CascChildTable[confCascType1][2])) + continue; + if (!isParticleTOF(posChild1, CascChildTable[confCascType1][0]) || !isParticleTOF(negChild1, CascChildTable[confCascType1][1]) || !isParticleTOF(bachelor1, CascChildTable[confCascType1][2])) + continue; + } else { + if ((posChild1.pidCut() & (1u << CascChildTable[confCascType1][0])) == 0 || (negChild1.pidCut() & (1u << CascChildTable[confCascType1][1])) == 0 || (bachelor1.pidCut() & (1u << CascChildTable[confCascType1][2])) == 0) + continue; + if (confUseStrangenessTOF) { + if (((confCascType1 == 1 || confCascType1 == 3) && (p1.pidCut() & 7) != 7) || ((confCascType1 == 0 || confCascType1 == 2) && (p1.pidCut() & 56) != 56)) + continue; + } else { + if ((posChild1.pidCut() & (8u << CascChildTable[confCascType1][0])) == 0 || (negChild1.pidCut() & (8u << CascChildTable[confCascType1][1])) == 0 || (bachelor1.pidCut() & (8u << CascChildTable[confCascType1][2])) == 0) + continue; + } + } + + const auto& posChild2 = parts.iteratorAt(p2.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild2 = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor2 = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); + /// Child particles must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild2, CascChildTable[confCascType2][0]) || !isParticleTPC(negChild2, CascChildTable[confCascType2][1]) || !isParticleTPC(bachelor2, CascChildTable[confCascType2][2])) + continue; + if (!isParticleTOF(posChild2, CascChildTable[confCascType2][0]) || !isParticleTOF(negChild2, CascChildTable[confCascType2][1]) || !isParticleTOF(bachelor2, CascChildTable[confCascType2][2])) + continue; + } else { + if ((posChild2.pidCut() & (1u << CascChildTable[confCascType2][0])) == 0 || (negChild2.pidCut() & (1u << CascChildTable[confCascType2][1])) == 0 || (bachelor2.pidCut() & (1u << CascChildTable[confCascType2][2])) == 0) + continue; + if (confUseStrangenessTOF) { + if (((confCascType2 == 1 || confCascType2 == 3) && (p2.pidCut() & 7) != 7) || ((confCascType2 == 0 || confCascType2 == 2) && (p2.pidCut() & 56) != 56)) + continue; + } else { + if ((posChild2.pidCut() & (8u << CascChildTable[confCascType2][0])) == 0 || (negChild2.pidCut() & (8u << CascChildTable[confCascType2][1])) == 0 || (bachelor2.pidCut() & (8u << CascChildTable[confCascType2][2])) == 0) + continue; + } + } + // track cleaning + if (!pairCleanerCasc.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejectionCasc.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } + } + + 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())); + mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); + } + } + } + + void processMixedEventCasc(const FilteredFDCollisions& cols, const FemtoFullParticles& parts) + { + doMixedEventCasc(cols, parts, partsTwoFull); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEventCasc, "Enable processing mixed event for cascade - cascade", false); + + void processMixedEventCascBitmask(const FilteredFDCollisions& cols, const aod::FDParticles& parts) + { + doMixedEventCasc(cols, parts, partsTwoBasic); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEventCascBitmask, "Enable processing mixed event for cascade - cascade using bitmask for PID", false); + + // MC truth for track - cascade + void processSameEventMCgen(const FilteredFDCollision& col, [[maybe_unused]] const aod::FDParticles& parts) + { + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); + + auto groupPartsOne = partsOneMCgenBasic->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCgenBasic->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 != kOmegaMinus) || (confCascType1 == 2 && pdgCode != kOmegaPlusBar) || (confCascType1 == 1 && pdgCode != kXiMinus) || (confCascType1 == 3 && pdgCode != kXiPlusBar)) + 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 != kOmegaMinus) || (confCascType1 == 2 && pdgCodeCasc != kOmegaPlusBar) || (confCascType1 == 1 && pdgCodeCasc != kXiMinus) || (confCascType1 == 3 && pdgCodeCasc != kXiPlusBar)) + continue; + sameEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEventMCgen, "Enable processing same event MC truth for track - cascade", false); + + // MC truth for cascade - cascade + void processSameEventCascMCgen(const FilteredFDCollision& col, [[maybe_unused]] const aod::FDParticles& parts) + { + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); + + auto groupPartsTwo = partsTwoMCgenBasic->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 != kOmegaMinus) || (confCascType1 == 2 && pdgCode != kOmegaPlusBar) || (confCascType1 == 1 && pdgCode != kXiMinus) || (confCascType1 == 3 && pdgCode != kXiPlusBar)) + continue; + + cascQAHistos.fillQA(part); + + auto pairProcessFunc = [&](auto& p1, auto& p2) -> void { + int pdgCodeCasc1 = static_cast(p1.pidCut()); + if ((confCascType1 == 0 && pdgCodeCasc1 != kOmegaMinus) || (confCascType1 == 2 && pdgCodeCasc1 != kOmegaPlusBar) || (confCascType1 == 1 && pdgCodeCasc1 != kXiMinus) || (confCascType1 == 3 && pdgCodeCasc1 != kXiPlusBar)) + return; + int pdgCodeCasc2 = static_cast(p2.pidCut()); + if ((confCascType2 == 0 && pdgCodeCasc2 != kOmegaMinus) || (confCascType2 == 2 && pdgCodeCasc2 != kOmegaPlusBar) || (confCascType2 == 1 && pdgCodeCasc2 != kXiMinus) || (confCascType2 == 3 && pdgCodeCasc2 != kXiPlusBar)) + return; + sameEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + }; + + if (confCascType1 == confCascType2) { + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsTwo, groupPartsTwo))) + pairProcessFunc(p1, p2); + } else { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsTwo, groupPartsTwo))) + pairProcessFunc(p1, p2); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processSameEventCascMCgen, "Enable processing same event MC truth for cascade - cascade", false); + + // MC truth for track - cascade + void processMixedEventMCgen(const FilteredFDCollisions& cols, [[maybe_unused]] const aod::FDParticles& 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 = partsOneMCgenBasic->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCgenBasic->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 != kOmegaMinus) || (confCascType1 == 2 && pdgCodeCasc != kOmegaPlusBar) || (confCascType1 == 1 && pdgCodeCasc != kXiMinus) || (confCascType1 == 3 && pdgCodeCasc != kXiPlusBar)) + continue; + mixedEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEventMCgen, "Enable processing mixed event MC truth for track - cascade", false); + + // MC truth for cascade - cascade + void processMixedEventCascMCgen(const FilteredFDCollisions& cols, [[maybe_unused]] const aod::FDParticles& 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 = partsTwoMCgenBasic->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCgenBasic->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))) { + int pdgCodeCasc1 = static_cast(p1.pidCut()); + if ((confCascType1 == 0 && pdgCodeCasc1 != kOmegaMinus) || (confCascType1 == 2 && pdgCodeCasc1 != kOmegaPlusBar) || (confCascType1 == 1 && pdgCodeCasc1 != kXiMinus) || (confCascType1 == 3 && pdgCodeCasc1 != kXiPlusBar)) + continue; + int pdgCodeCasc2 = static_cast(p2.pidCut()); + if ((confCascType2 == 0 && pdgCodeCasc2 != kOmegaMinus) || (confCascType2 == 2 && pdgCodeCasc2 != kOmegaPlusBar) || (confCascType2 == 1 && pdgCodeCasc2 != kXiMinus) || (confCascType2 == 3 && pdgCodeCasc2 != kXiPlusBar)) + continue; + mixedEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMixedEventCascMCgen, "Enable processing mixed event MC truth for cascade - cascade", false); + + /// This function fills MC truth particles from derived MC table + void processMCgen(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 ((confCascType1 == 0 && pdgCode == kOmegaMinus) || (confCascType1 == 1 && pdgCode == kXiMinus)) { + registryMCgen.fill(HIST("plus/MCgenCasc"), part.pt(), part.eta()); + continue; + } else if ((confCascType1 == 0 && pdgCode == kOmegaPlusBar) || (confCascType1 == 1 && pdgCode == kXiPlusBar)) { + registryMCgen.fill(HIST("minus/MCgenCasc"), part.pt(), part.eta()); + continue; + } + + if (pdgParticle->Charge() > 0.0) { + registryMCgen.fill(HIST("plus/MCgenAllPt"), part.pt()); + } + if (pdgCode == kProton) { + 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 == kProtonBar) { + 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); + + template + void doMCReco(TableType 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 (!invMCascade(part.mLambda(), part.mAntiLambda(), confCascType1)) /// mLambda stores Xi mass, mAntiLambda stores Omega mass + continue; + if ((confCascType1 == 0 && mcpart.pdgMCTruth() == kOmegaMinus) || (confCascType1 == 1 && mcpart.pdgMCTruth() == kXiMinus)) { + const auto& posChild = parts.iteratorAt(part.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + /// Daughters that do not pass this condition are not selected + if constexpr (std::experimental::is_detected::value) { + 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; + } else { + if ((posChild.pidCut() & (1u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (1u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType1][2])) == 0) + continue; + if (confUseStrangenessTOF) { + if (((confCascType1 == 1) && (part.pidCut() & 7) != 7) || ((confCascType1 == 0) && (part.pidCut() & 56) != 56)) + continue; + } else { + if ((posChild.pidCut() & (8u << CascChildTable[confCascType1][0])) == 0 || (negChild.pidCut() & (8u << CascChildTable[confCascType1][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType1][2])) == 0) + continue; + } + } + registryMCreco.fill(HIST("plus/MCrecoCascade"), mcpart.pt(), mcpart.eta()); + + } else if ((confCascType1 == 0 && mcpart.pdgMCTruth() == kOmegaPlusBar) || (confCascType1 == 1 && mcpart.pdgMCTruth() == kXiPlusBar)) { + const auto& posChild = parts.iteratorAt(part.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, CascChildTable[confCascType1 + 2][0]) && !isParticleTPC(negChild, CascChildTable[confCascType1 + 2][1]) && !isParticleTPC(bachelor, CascChildTable[confCascType1 + 2][2])) + continue; + if (!isParticleTOF(posChild, CascChildTable[confCascType1 + 2][0]) || !isParticleTOF(negChild, CascChildTable[confCascType1 + 2][1]) || !isParticleTOF(bachelor, CascChildTable[confCascType1 + 2][2])) + continue; + } else { + if ((posChild.pidCut() & (1u << CascChildTable[confCascType1 + 2][0])) == 0 || (negChild.pidCut() & (1u << CascChildTable[confCascType1 + 2][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType1 + 2][2])) == 0) + continue; + if (confUseStrangenessTOF) { + if (((confCascType1 == 1) && (part.pidCut() & 7) != 7) || ((confCascType1 == 0) && (part.pidCut() & 56) != 56)) + continue; + } else { + if ((posChild.pidCut() & (8u << CascChildTable[confCascType1 + 2][0])) == 0 || (negChild.pidCut() & (8u << CascChildTable[confCascType1 + 2][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType1 + 2][2])) == 0) + continue; + } + } + registryMCreco.fill(HIST("minus/MCrecoCascade"), mcpart.pt(), mcpart.eta()); + } + + } else if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { + if (part.mAntiLambda() > 0) { + registryMCreco.fill(HIST("plus/MCrecoAllPt"), mcpart.pt()); + if (mcpart.pdgMCTruth() != kProton) + continue; + if constexpr (std::experimental::is_detected::value) { + if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) + continue; + } else { + if ((part.pidCut() & 64u) == 0) + continue; + } + registryMCreco.fill(HIST("plus/MCrecoPr"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("plus/MCrecoPrPt"), mcpart.pt()); + } else if (part.mAntiLambda() < 0) { + registryMCreco.fill(HIST("minus/MCrecoAllPt"), mcpart.pt()); + if (mcpart.pdgMCTruth() != kProtonBar) + continue; + if constexpr (std::experimental::is_detected::value) { + if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) + continue; + } else { + if ((part.pidCut() & 64u) == 0) + continue; + } + registryMCreco.fill(HIST("minus/MCrecoPr"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("minus/MCrecoPrPt"), mcpart.pt()); + } + } + } + } + + void processMCReco(FemtoRecoFullParticles const& parts, aod::FdMCParticles const& mcparts) + { + doMCReco(parts, mcparts); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMCReco, "Process MC reco data for cascades using nSigma for PID", false); + + void processMCRecoBitmask(FemtoRecoBasicParticles const& parts, aod::FdMCParticles const& mcparts) + { + doMCReco(parts, mcparts); + } + PROCESS_SWITCH(femtoUniversePairTaskTrackCascadeExtended, processMCRecoBitmask, "Process MC reco data for cascades using Bitmask for PID", 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 d9496c47212..140a02d957d 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -17,48 +17,48 @@ /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch /// \author Katarzyna Gwiździel, WUT Warsaw, katarzyna.gwizdziel@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 "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/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCalculator.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/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSoftPionRemoval.h" #include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" - +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" + +#include +#include + 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}}; +static const int8_t genPromptD0 = 1; +static const int8_t genNonPromptD0 = 2; } // namespace /// Returns deltaPhi value within the range [-pi/2, 3/2*pi] @@ -74,84 +74,123 @@ double wrapDeltaPhi0PI(double phiD, double phiDbar) { double deltaPhi = 0.0; deltaPhi = RecoDecay::constrainAngle(phiDbar - phiD, 0.0); - if (deltaPhi < 0.) { - deltaPhi = deltaPhi + o2::constants::math::TwoPI; - } if (deltaPhi > o2::constants::math::TwoPI) { deltaPhi = o2::constants::math::TwoPI - deltaPhi; } return deltaPhi; } -struct femtoUniversePairTaskTrackD0 { +struct FemtoUniversePairTaskTrackD0 { + + Service pdgMC; using FemtoFullParticles = soa::Join; SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + using FemtoMcRecoParticles = 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)"}; + Configurable confNsigmaTPCProton{"confNsigmaTPCProton", 3.0, "TPC Proton Sigma"}; + Configurable confNsigmaCombinedPion{"confNsigmaCombinedPion", 3.0, "TPC and TOF Pion Sigma (combined)"}; + Configurable confNsigmaTPCPion{"confNsigmaTPCPion", 3.0, "TPC Pion Sigma"}; + Configurable confNsigmaCombinedKaon{"confNsigmaCombinedKaon", 3.0, "TPC and TOF Kaon Sigma (combined)"}; + Configurable confNsigmaTPCKaon{"confNsigmaTPCKaon", 3.0, "TPC Kaon Sigma"}; + + 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 confTrackEtaMax{"confTrackEtaMax", 0.8, "max. pseudorapidity of the track"}; + Configurable minPtPidTpcTofProton{"minPtPidTpcTofProton", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; + Configurable minPtPidTpcTofPion{"minPtPidTpcTofPion", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; + Configurable minPtPidTpcTofKaonLF{"minPtPidTpcTofKaonLF", 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 ConfMinPtD0D0bar{"ConfMinPtD0D0bar", 3.0, "D0/D0bar sel. - min. pT"}; - Configurable ConfMaxPtD0D0bar{"ConfMaxPtD0D0bar", 5.0, "D0/D0bar sel. - max. pT"}; - 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 confD0OriginFlag{"confD0OriginFlag", 0, "D0/D0bar origin: 0 - prompt, 1 - non-prompt"}; + Configurable confMinPtD0D0barReco{"confMinPtD0D0barReco", 0.5, "MC Reco - D0/D0bar sel. - min. pT"}; + Configurable confMaxPtD0D0barReco{"confMaxPtD0D0barReco", 24.0, "MC Reco - 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 ConfUsePtCutForD0D0bar{"ConfUsePtCutForD0D0bar", false, "Include pT cut for D0/D0bar in same and mixed processes."}; - Configurable ConfUseMassCutForD0D0bar{"ConfUseMassCutForD0D0bar", false, "Switch to save D0/D0bar within declared inv. mass range"}; + Configurable confChooseD0trackCorr{"confChooseD0trackCorr", 0, "If 0 correlations with D0s, if 1 with D0bars"}; + + // Efficiency + Configurable doEfficiencyCorr{"doEfficiencyCorr", false, "Apply efficiency corrections"}; /// 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) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); + 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) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); + 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) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); /// 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 one and double mass hypothesis) + Partition partsAllDmesons = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > 0.0f) || (aod::femtouniverseparticle::mAntiLambda > 0.0f)) && (aod::femtouniverseparticle::decayVtxX < 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::decayVtxX < 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::decayVtxX < 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 MC Reco prompt D0/D0bar mesons + Partition partsPromptD0MCReco = (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) && (aod::femtouniverseparticle::decayVtxX < ConfMlOpt.confMaxProbMlClass1Bg) && (aod::femtouniverseparticle::decayVtxY > ConfMlOpt.confMinProbMlClass2Prompt) && (aod::femtouniverseparticle::tpcNClsFound == ConfDmesons.confD0OriginFlag); + Partition partsPromptD0barMCReco = (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) && (aod::femtouniverseparticle::decayVtxX < ConfMlOpt.confMaxProbMlClass1Bg) && (aod::femtouniverseparticle::decayVtxY > ConfMlOpt.confMinProbMlClass2Prompt) && (aod::femtouniverseparticle::tpcNClsFound == ConfDmesons.confD0OriginFlag); + /// Partition for MC Reco prompt D0/D0bar mesons (sideband candidates) + Partition partsPromptD0MCRecoSB = (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) && (aod::femtouniverseparticle::decayVtxX < ConfMlOpt.confMaxProbMlClass1Bg) && (aod::femtouniverseparticle::decayVtxY > ConfMlOpt.confMinProbMlClass2Prompt) && (aod::femtouniverseparticle::tpcNClsFound == ConfDmesons.confD0OriginFlag); + Partition partsPromptD0barMCRecoSB = (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) && (aod::femtouniverseparticle::decayVtxX < ConfMlOpt.confMaxProbMlClass1Bg) && (aod::femtouniverseparticle::decayVtxY > ConfMlOpt.confMinProbMlClass2Prompt) && (aod::femtouniverseparticle::tpcNClsFound == ConfDmesons.confD0OriginFlag); + // MC Truth D0/D0bar candidates + Partition partsD0MCTruth = (aod::femtouniverseparticle::partType == static_cast(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pidCut == static_cast(ConfDmesons.confPDGCodeD0)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar); + Partition partsD0barMCTruth = (aod::femtouniverseparticle::partType == static_cast(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (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); /// Histogramming for particle 1 - FemtoUniverseParticleHisto trackHistoPartTrack; + FemtoUniverseParticleHisto trackHistoPartTrack; /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartD0D0bar; @@ -164,88 +203,93 @@ 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"}; + ConfigurableAxis confTempFitVarDCABins{"confTempFitVarDCABins", {500, -1.0, 1.0}, "binning of the DCA histograms"}; /// 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"}; + + FemtoUniverseContainer sameEventAngularCont; + FemtoUniverseContainer 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{"McRecoHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry mcTruthRegistry{"McGenHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryDCA{"registryDCA", {}, 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}}}}, - {"hEtaDmesonCand", ";#eta ;counts", {HistType::kTH1F, {{200, -1., 1.}}}}, + {{"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}}}, + {"hPhiD0D0bar", ";#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}}}}, + {"hEtaD0D0bar", ";#eta ;counts", {HistType::kTH1F, {{200, -1., 1.}}}}, {"hEtaD0", ";#eta ;counts", {HistType::kTH1F, {{200, -1., 1.}}}}, {"hEtaD0bar", ";#eta ;counts", {HistType::kTH1F, {{200, -1., 1.}}}}, {"hDecayLengthD0", ";decay length (cm);counts", {HistType::kTH1F, {{800, 0., 4.}}}}, {"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.minPtPidTpcTofProton) { + 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.minPtPidTpcTofProton) { + if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfBothTracks.confNsigmaCombinedProton) { return true; } else { return false; @@ -254,36 +298,16 @@ struct femtoUniversePairTaskTrackD0 { return false; } - bool IsKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + bool isKaonNSigmaLF(float mom, float nsigmaTPCK, float nsigmaTOFK) { - 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) { + if (mom < ConfTrack.minPtPidTpcTofKaonLF) { + if (std::abs(nsigmaTPCK) < ConfBothTracks.confNsigmaTPCKaon) { 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)) { + } else if (mom >= ConfTrack.minPtPidTpcTofKaonLF) { + if (std::sqrt(nsigmaTPCK * nsigmaTPCK + nsigmaTOFK * nsigmaTOFK) < ConfBothTracks.confNsigmaCombinedKaon) { return true; } else { return false; @@ -293,24 +317,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 a given momentum + // confNsigmaCombinedPion -> TPC and TOF Pion Sigma (combined) for a given momentum if (true) { - if (mom < 0.5) { - if (TMath::Abs(nsigmaTPCPi) < ConfBothTracks.ConfNsigmaTPCPion) { + if (mom < ConfTrack.minPtPidTpcTofPion) { + 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.minPtPidTpcTofPion) { + if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfBothTracks.confNsigmaCombinedPion) { return true; } else { return false; @@ -320,20 +340,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 isKaonNSigmaLF(mom, nsigmaTPCK, nsigmaTOFK); break; default: return false; @@ -342,165 +362,428 @@ struct femtoUniversePairTaskTrackD0 { void init(InitContext&) { - eventHisto.init(&qaRegistry); - 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}}); + efficiencyCalculator.init(); - 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(ConfDmesons.ConfPDGCodeD0, ConfTrack.ConfPDGCodeTrack); - mixedEventFemtoCont.setPDGCodes(ConfDmesons.ConfPDGCodeD0, ConfTrack.ConfPDGCodeTrack); - sameEventAngularCont.setPDGCodes(ConfDmesons.ConfPDGCodeD0, ConfTrack.ConfPDGCodeTrack); - mixedEventAngularCont.setPDGCodes(ConfDmesons.ConfPDGCodeD0, ConfTrack.ConfPDGCodeTrack); + eventHisto.init(&qaRegistry); + 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}}); + // D0/D0bar histograms + auto vbins = (std::vector)binsPt; + if (doEfficiencyCorr) { + registry.add("D0D0bar_oneMassHypo/hMassVsPtEffCorr", "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/hMassVsPtD0EffCorr", "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/hMassVsPtD0barEffCorr", "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/hMassVsPtEffCorr", "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/hMassVsPtD0EffCorr", "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/hMassVsPtD0barEffCorr", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + } else { + 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/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_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})"}}}); + } + // MC Reco + mcRecoRegistry.add("hMcRecD0", "MC Reco all D0s;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecD0Pt", "MC Reco all D0s;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcRecoRegistry.add("hMcRecD0Prompt", "MC Reco prompt D0s;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecD0PromptPt", "MC Reco prompt D0s;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcRecoRegistry.add("hMcRecD0NonPrompt", "MC Reco non-prompt D0s;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecD0NonPromptPt", "MC Reco non-prompt D0s;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcRecoRegistry.add("hMcRecD0Phi", "MC Reco all D0s;#varphi (rad); counts", {HistType::kTH1F, {{80, 0., o2::constants::math::TwoPI}}}); + mcRecoRegistry.add("hMcRecD0PromptPhi", "MC Reco prompt D0s;#varphi (rad); counts", {HistType::kTH1F, {{80, 0., o2::constants::math::TwoPI}}}); + mcRecoRegistry.add("hMcRecD0NonPromptPhi", "MC Reco non-prompt D0s;#varphi (rad); counts", {HistType::kTH1F, {{80, 0., o2::constants::math::TwoPI}}}); + mcRecoRegistry.add("hMcRecD0bar", "MC Reco all D0bars;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecD0barPt", "MC Reco all D0bars;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcRecoRegistry.add("hMcRecD0barPrompt", "MC Reco prompt D0bars;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecD0barPromptPt", "MC Reco prompt D0bars;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcRecoRegistry.add("hMcRecD0barNonPrompt", "MC Reco non-prompt D0bars;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecD0barNonPromptPt", "MC Reco non-prompt D0bars;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcRecoRegistry.add("hMcRecD0barPhi", "MC Reco all D0bars;#varphi (rad); counts", {HistType::kTH1F, {{80, 0., o2::constants::math::TwoPI}}}); + // Inv. mass histograms + mcRecoRegistry.add("hMassVsPtD0Sig", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0Refl", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0Bkg", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0Prompt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0NonPrompt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0barSig", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0barRefl", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0barBkg", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0barPrompt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + mcRecoRegistry.add("hMassVsPtD0barNonPrompt", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + // Histograms for identified hadrons + mcRecoRegistry.add("hMcRecKpPt", "MC Reco K+;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcRecoRegistry.add("hMcRecKpPtGenEtaGen", "MC Reco K+;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecKmPt", "MC Reco K-;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcRecoRegistry.add("hMcRecKmPtGenEtaGen", "MC Reco K-;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecPipPt", "MC Reco #pi+;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcRecoRegistry.add("hMcRecPipPtGenEtaGen", "MC Reco #pi+;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecPimPt", "MC Reco #pi-;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcRecoRegistry.add("hMcRecPimPtGenEtaGen", "MC Reco #pi-;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecPrPt", "MC Reco proton;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcRecoRegistry.add("hMcRecPrPtGenEtaGen", "MC Reco proton;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcRecoRegistry.add("hMcRecAntiPrPt", "MC Reco antiproton;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcRecoRegistry.add("hMcRecAntiPrPtGenEtaGen", "MC Reco antiproton;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + + // MC truth + mcTruthRegistry.add("hMcGenD0", "MC Truth all D0s;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenD0Pt", "MC Truth all D0s;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcTruthRegistry.add("hMcGenD0Prompt", "MC Truth prompt D0s;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenD0PromptPt", "MC Truth prompt D0s;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcTruthRegistry.add("hMcGenD0NonPrompt", "MC Truth non-prompt D0s;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenD0NonPromptPt", "MC Truth non-prompt D0s;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcTruthRegistry.add("hMcGenD0bar", "MC Truth all D0bars;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenD0barPt", "MC Truth all D0bars;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcTruthRegistry.add("hMcGenD0barPrompt", "MC Truth prompt D0bars;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenD0barPromptPt", "MC Truth prompt D0s;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcTruthRegistry.add("hMcGenD0barNonPrompt", "MC Truth non-prompt D0bars;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenD0barNonPromptPt", "MC Truth non-prompt D0s;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {vbins}}); + mcTruthRegistry.add("hMcGenAllPositivePt", "MC Truth all positive;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{360, 0, 36}}}); + mcTruthRegistry.add("hMcGenAllNegativePt", "MC Truth all negative;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{360, 0, 36}}}); + mcTruthRegistry.add("hMcGenKpPtVsEta", "MC Truth K+;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenKmPtVsEta", "MC Truth K-;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenPipPtVsEta", "MC Truth #pi+;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenPimPtVsEta", "MC Truth #pi-;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenPrPtVsEta", "MC Truth proton;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenAntiPrPtVsEta", "MC Truth antiproton;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); + mcTruthRegistry.add("hMcGenKpPt", "MC Truth K+;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("hMcGenKmPt", "MC Truth K-;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("hMcGenPipPt", "MC Truth #pi+;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("hMcGenPimPt", "MC Truth #pi-;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("hMcGenPrPt", "MC Truth proton;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + mcTruthRegistry.add("hMcGenAntiPrPt", "MC Truth antiproton;#it{p}_{T} (GeV/c); counts", {HistType::kTH1F, {{500, 0, 5}}}); + + trackHistoPartTrack.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarBins, ConfBothTracks.confIsMC, ConfTrack.confPDGCodeTrack); + trackHistoPartD0D0bar.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarInvMassBins, ConfBothTracks.confIsMC, ConfDmesons.confPDGCodeD0); + + mixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + + 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.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; - - // 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, {{10, 0.0, o2::constants::math::PI}}}); - registry.add("hDeltaPhiD0BgD0barSig", "B(D0)x S(D0bar) correlation;#Delta#varphi (rad);counts", {HistType::kTH1F, {{10, 0.0, o2::constants::math::PI}}}); - registry.add("hDeltaPhiD0SigD0barBg", "S(D0)x B(D0bar) correlation;#Delta#varphi (rad);counts", {HistType::kTH1F, {{10, 0.0, o2::constants::math::PI}}}); - registry.add("hDeltaPhiBgBg", "BxB correlation;#Delta#varphi (rad);counts", {HistType::kTH1F, {{10, 0.0, 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.0, o2::constants::math::PI}}}); + vPIDTrack = ConfTrack.confPIDTrack.value; + kNsigma = ConfBothTracks.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); } - 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 groupPartsD0D0barChildren = partsDmesonsChildren->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - - // loop over all D mesons - for (auto const& dmeson : groupPartsAllDmesons) { - - if (dmeson.mLambda() > 0.0f) { - registry.fill(HIST("hMassVsPt"), dmeson.mLambda(), dmeson.pt()); - registry.fill(HIST("hMassVsPtFinerBinning"), dmeson.mLambda(), dmeson.pt()); + auto groupD0D0barCands = partsAllDmesons->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()); } - - if (dmeson.mAntiLambda() > 0.0f) { - registry.fill(HIST("hMassVsPt"), dmeson.mAntiLambda(), dmeson.pt()); - registry.fill(HIST("hMassVsPtFinerBinning"), dmeson.mAntiLambda(), dmeson.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()); } - - registry.fill(HIST("hPtDmesonCand"), dmeson.pt()); - registry.fill(HIST("hPhiDmesonCand"), dmeson.phi()); - registry.fill(HIST("hEtaDmesonCand"), dmeson.eta()); } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processD0MLOptBg, "Enable filling QA plots for ML Bg D0/D0bar selection optimization", false); - // loop over D0/D0bar mesons (ONLY) - for (auto const& d0d0bar : groupPartsOnlyD0D0bar) { - - registry.fill(HIST("hPtD0D0bar"), d0d0bar.pt()); - - 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()); + void processD0MLOptBgAndPrompt(o2::aod::FdCollision const& col, FemtoFullParticles const&) + { + auto groupD0D0barCands = partsAllDmesons->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()); } - 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()); + // 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()); } - registry.fill(HIST("hPtD0bar"), d0d0bar.pt()); - registry.fill(HIST("hPhiD0bar"), d0d0bar.phi()); - registry.fill(HIST("hEtaD0bar"), d0d0bar.eta()); } } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processD0MLOptBgAndPrompt, "Enable filling QA plots for ML Bg and Prompt D0/D0bar selection optimization", false); - // loop over D mesons childen - for (auto const& daughD0D0bar : groupPartsD0D0barChildren) { - registry.fill(HIST("hPtDaughters"), daughD0D0bar.pt()); + 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, processD0mesons, "Enable processing D0 mesons", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processQAD0D0barSel, "Enable filling QA plots for selected D0/D0bar cand.", true); - // D0-D0bar pair correlations (side-band methode) - void processSideBand(o2::aod::FDCollision& col, FemtoFullParticles&) + void processAllDmesons(o2::aod::FdCollision const& col, FemtoFullParticles const&) { - auto groupPartsOnlyD0D0bar = partsOnlyD0D0bar->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - - double deltaPhi = 0.0; - double deltaEta = 0.0; + auto groupPartsAllD0D0barCands = partsAllDmesons->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - // 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; - } + // loop over D0/D0bar mesons + for (auto const& d0d0bar : groupPartsAllD0D0barCands) { - 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()); - deltaPhi = wrapDeltaPhi0PI(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); + registry.fill(HIST("hPtD0D0bar"), d0d0bar.pt()); + registry.fill(HIST("hPhiD0D0bar"), d0d0bar.phi()); + registry.fill(HIST("hEtaD0D0bar"), 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); + + weight = 1.0f; + if (doEfficiencyCorr) { + weight = efficiencyCalculator.getWeight(ParticleNo::TWO, d0d0bar.pt()); + if (d0d0bar.mLambda() > 0.0f) { + registry.fill(HIST("D0D0bar_doubleMassHypo/hMassVsPtEffCorr"), d0d0bar.mLambda(), d0d0bar.pt(), weight); + registry.fill(HIST("D0D0bar_doubleMassHypo/hMassVsPtD0EffCorr"), d0d0bar.mLambda(), d0d0bar.pt(), weight); + if (d0d0bar.mAntiLambda() < 0.0f) { + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtEffCorr"), d0d0bar.mLambda(), d0d0bar.pt(), weight); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtD0EffCorr"), d0d0bar.mLambda(), d0d0bar.pt(), weight); + registry.fill(HIST("hPtD0"), d0d0bar.pt()); + registry.fill(HIST("hPhiD0"), d0d0bar.phi()); + registry.fill(HIST("hEtaD0"), d0d0bar.eta()); } - // 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 (d0d0bar.mAntiLambda() > 0.0f) { + registry.fill(HIST("D0D0bar_doubleMassHypo/hMassVsPtEffCorr"), d0d0bar.mLambda(), d0d0bar.pt(), weight); + registry.fill(HIST("D0D0bar_doubleMassHypo/hMassVsPtD0barEffCorr"), d0d0bar.mLambda(), d0d0bar.pt(), weight); + if (d0d0bar.mLambda() < 0.0f) { + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtEffCorr"), d0d0bar.mAntiLambda(), d0d0bar.pt(), weight); + registry.fill(HIST("D0D0bar_oneMassHypo/hMassVsPtD0barEffCorr"), d0d0bar.mAntiLambda(), d0d0bar.pt(), weight); + registry.fill(HIST("hPtD0bar"), d0d0bar.pt()); + registry.fill(HIST("hPhiD0bar"), d0d0bar.phi()); + registry.fill(HIST("hEtaD0bar"), d0d0bar.eta()); } } - 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); + } else { + 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()); } - // 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); + } + 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()); } } - } // It is the end of the for loop over D0bar mesons - } // It is the end of the for loop over all candidates + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processAllDmesons, "Enable processing over all D meson candidates", false); + + void processD0Children(o2::aod::FdCollision const& col, FemtoFullParticles const&) + { + auto groupPartsD0D0barChildren = partsDmesonsChildren->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + // 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, processSideBand, "Enable processing side-band methode", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processD0Children, "Enable processing over daughters of D0 meson candidates", false); /// 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, ... @@ -517,91 +800,219 @@ 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))) { - continue; - } - } - // // Set pT cut for D0/D0bar candidates - if (ConfUsePtCutForD0D0bar) { - if (d0candidate.pt() < ConfDmesons.ConfMinPtD0D0bar && d0candidate.pt() > ConfDmesons.ConfMaxPtD0D0bar) { + 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; } } - // // Set inv. mass cut for D0/D0bar candidates - if (ConfUseMassCutForD0D0bar) { - if ((d0candidate.mLambda() < ConfD0D0barSideBand.ConfSignalRegionMin && d0candidate.mLambda() > ConfD0D0barSideBand.ConfSignalRegionMax) || (d0candidate.mAntiLambda() < ConfD0D0barSideBand.ConfSignalRegionMin && d0candidate.mAntiLambda() > ConfD0D0barSideBand.ConfSignalRegionMax)) { + // 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 (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 theGroupPartsTrack = partsTrack->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, 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); + auto groupPartsD0barsFromSB = partsD0barsFromSB->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + switch (confChooseD0trackCorr) { + case 0: + doSameEvent(groupPartsTrack, groupPartsD0sFromSB, parts, col.magField(), col.multNtr()); + break; + case 1: + doSameEvent(groupPartsTrack, groupPartsD0barsFromSB, parts, col.magField(), col.multNtr()); + break; + default: + break; + } + } + 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) + /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table + void processSameEventMCRecoSignal(aod::FdCollision const& col, FemtoMcRecoParticles const& parts, aod::FdMCParticles const&) + { + fillCollision(col); + + auto theGroupPartsD0 = partsPromptD0MCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupPartsD0bar = partsPromptD0barMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupPartsTrack = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + switch (confChooseD0trackCorr) { + case 0: + doSameEvent(theGroupPartsTrack, theGroupPartsD0, parts, col.magField(), col.multNtr()); + break; + case 1: + doSameEvent(theGroupPartsTrack, theGroupPartsD0bar, parts, col.magField(), col.multNtr()); + break; + default: + break; } } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processSameEvent, "Enable processing same event", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processSameEventMCRecoSignal, "MC Reco - enable processing same event for D0/D0bar signal cand.", false); /// process function for to call doSameEvent with Monte Carlo - /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) + /// \param col subscribe to the collision table (Monte Carlo 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 processSameEventMCRecoSB(aod::FdCollision const& col, FemtoMcRecoParticles const& parts, 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 = partsPromptD0MCRecoSB->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupPartsD0bar = partsPromptD0barMCRecoSB->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupPartsTrack = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + switch (confChooseD0trackCorr) { + case 0: + doSameEvent(theGroupPartsTrack, theGroupPartsD0, parts, col.magField(), col.multNtr()); + break; + case 1: + doSameEvent(theGroupPartsTrack, theGroupPartsD0bar, parts, col.magField(), col.multNtr()); + break; + default: + break; + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processSameEventMCRecoSB, "MC Reco - enable processing same event for D0/D0bar side-band cand.", false); - doSameEvent(thegroupPartsTrack, thegroupPartsD0, parts, col.magField(), col.multNtr()); + /// process function for to call doSameEvent with Monte Carlo + /// \param col subscribe to the collision table + /// \param parts subscribe to the joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// \param FdMCParticles subscribe to the Monte Carlo truth table + void processSameEventMcTruth(aod::FdCollision const& col, FemtoMcRecoParticles const& parts, aod::FdMCParticles const&) + { + fillCollision(col); + /// !!! needs to be finished -> add possibility to change between D0 and D0bar + auto theGroupTruthD0s = partsD0MCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupTruthD0bars = partsD0barMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto theGroupTruthTracks = partsTrackMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + switch (confChooseD0trackCorr) { + case 0: + doSameEvent(theGroupTruthTracks, theGroupTruthD0s, parts, col.magField(), col.multNtr()); + break; + case 1: + doSameEvent(theGroupTruthTracks, theGroupTruthD0bars, parts, col.magField(), col.multNtr()); + break; + default: + break; + } } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processSameEventMC, "Enable processing same event for Monte Carlo", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processSameEventMcTruth, "MC Truth - enable processing same event", 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, ... @@ -617,50 +1028,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; } } - // // Set pT cut for D0/D0bar candidates - if (ConfUsePtCutForD0D0bar) { - if (d0candidate.pt() < ConfDmesons.ConfMinPtD0D0bar && d0candidate.pt() > ConfDmesons.ConfMaxPtD0D0bar) { - continue; - } - } - // // Set inv. mass cut for D0/D0bar candidates - if (ConfUseMassCutForD0D0bar) { - if ((d0candidate.mLambda() < ConfD0D0barSideBand.ConfSignalRegionMin && d0candidate.mLambda() > ConfD0D0barSideBand.ConfSignalRegionMax) || (d0candidate.mAntiLambda() < ConfD0D0barSideBand.ConfSignalRegionMin && d0candidate.mAntiLambda() > ConfD0D0barSideBand.ConfSignalRegionMax)) { + // // 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::mixed)) { + 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 (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(); @@ -669,32 +1083,184 @@ 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); + auto groupPartsD0barsFromSB = partsD0barsFromSB->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, groupPartsD0sFromSB, parts, magFieldTesla1, multiplicityCol); + break; + case 1: + doMixedEvent(groupPartsTrack, groupPartsD0barsFromSB, parts, magFieldTesla1, multiplicityCol); + break; + default: + break; } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processMixedEvent, "Enable processing mixed events", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMixedEventSB, "Enable processing mixed events for data", false); /// brief process function for to call doMixedEvent with Monte Carlo + /// @param cols subscribe to the collisions table (Monte Carlo 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 processMixedEventMCRecoSignal(aod::FdCollisions const& cols, FemtoMcRecoParticles const& parts, aod::FdMCParticles const&) + { + 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 = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsD0 = partsPromptD0MCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsD0bar = partsPromptD0barMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + + switch (confChooseD0trackCorr) { + case 0: + doMixedEvent(groupPartsTrack, groupPartsD0, parts, magFieldTesla1, multiplicityCol); + break; + case 1: + doMixedEvent(groupPartsTrack, groupPartsD0bar, parts, magFieldTesla1, multiplicityCol); + break; + default: + break; + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMixedEventMCRecoSignal, "MC Reco - enable processing mixed events for D0/D0bar signal cand.", false); + + /// brief process function for to call doMixedEvent with Monte Carlo Reco + /// @param cols subscribe to the collisions table (Monte Carlo 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 processMixedEventMCRecoSB(aod::FdCollisions const& cols, FemtoMcRecoParticles const& parts, aod::FdMCParticles const&) + { + 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 = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + auto groupPartsD0 = partsPromptD0MCRecoSB->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsD0bar = partsPromptD0barMCRecoSB->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + + switch (confChooseD0trackCorr) { + case 0: + doMixedEvent(groupPartsTrack, groupPartsD0, parts, magFieldTesla1, multiplicityCol); + break; + case 1: + doMixedEvent(groupPartsTrack, groupPartsD0bar, parts, magFieldTesla1, multiplicityCol); + break; + default: + break; + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMixedEventMCRecoSB, "MC Reco - enable processing mixed events for D0/D0bar side-band cand.", false); + + /// brief process function for to call doMixedEvent with Monte Carlo Reco /// @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 processMixedEventMCTruth(aod::FdCollisions const& cols, FemtoMcRecoParticles const& parts, 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 = partsD0MCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsD0bar = partsD0barMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); const auto& magFieldTesla1 = collision1.magField(); const auto& magFieldTesla2 = collision2.magField(); @@ -702,19 +1268,230 @@ struct femtoUniversePairTaskTrackD0 { if (magFieldTesla1 != magFieldTesla2) { 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; - doMixedEvent(groupPartsTrack, groupPartsD0, parts, magFieldTesla1, multiplicityCol); + switch (confChooseD0trackCorr) { + case 0: + doMixedEvent(groupPartsTrack, groupPartsD0, parts, magFieldTesla1, multiplicityCol); + break; + case 1: + doMixedEvent(groupPartsTrack, groupPartsD0bar, parts, magFieldTesla1, multiplicityCol); + break; + default: + break; + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMixedEventMCTruth, "MC Truth - enable processing mixed events for gen. D0/D0bar", false); + + void processMcReco(FemtoMcRecoParticles const& recoParts, aod::FdMCParticles const& mcParts) + { + for (auto const& part : recoParts) { + auto mcPartId = part.fdMCParticleId(); + if (mcPartId == -1) { + continue; // no MC particle + } + const auto& mcpart = mcParts.iteratorAt(mcPartId); + weight = 1.0f; + + // filling the histograms for identified hadrons + if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { + if (part.sign() > 0) { + if ((mcpart.pdgMCTruth() == PDG_t::kProton) && (part.pt() > ConfTrack.confTrackLowPtCut) && (part.pt() < ConfTrack.confTrackHighPtCut) && isParticleNSigma(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))) { + mcRecoRegistry.fill(HIST("hMcRecPrPt"), part.pt()); + if (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary) { + mcRecoRegistry.fill(HIST("hMcRecPrPtGenEtaGen"), mcpart.pt(), mcpart.eta()); + } + } + if ((mcpart.pdgMCTruth() == PDG_t::kPiPlus) && (part.pt() > ConfTrack.confTrackLowPtCut) && (part.pt() < ConfTrack.confTrackHighPtCut) && isParticleNSigma(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))) { + mcRecoRegistry.fill(HIST("hMcRecPipPt"), part.pt()); + if (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary) { + mcRecoRegistry.fill(HIST("hMcRecPipPtGenEtaGen"), mcpart.pt(), mcpart.eta()); + } + } + if ((mcpart.pdgMCTruth() == PDG_t::kKPlus) && (part.pt() > ConfTrack.confTrackLowPtCut) && (part.pt() < ConfTrack.confTrackHighPtCut) && isParticleNSigma(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))) { + mcRecoRegistry.fill(HIST("hMcRecKpPt"), part.pt()); + if (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary) { + mcRecoRegistry.fill(HIST("hMcRecKpPtGenEtaGen"), mcpart.pt(), mcpart.eta()); + } + } + } else if (part.sign() < 0) { + if ((mcpart.pdgMCTruth() == -PDG_t::kProton) && (part.pt() > ConfTrack.confTrackLowPtCut) && (part.pt() < ConfTrack.confTrackHighPtCut) && isParticleNSigma(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))) { + mcRecoRegistry.fill(HIST("hMcRecAntiPrPt"), part.pt()); + if (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary) { + mcRecoRegistry.fill(HIST("hMcRecAntiPrPtGenEtaGen"), mcpart.pt(), mcpart.eta()); + } + } + if ((mcpart.pdgMCTruth() == -PDG_t::kPiPlus) && (part.pt() > ConfTrack.confTrackLowPtCut) && (part.pt() < ConfTrack.confTrackHighPtCut) && isParticleNSigma(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))) { + mcRecoRegistry.fill(HIST("hMcRecPimPt"), part.pt()); + if (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary) { + mcRecoRegistry.fill(HIST("hMcRecPimPtGenEtaGen"), mcpart.pt(), mcpart.eta()); + } + } + if ((mcpart.pdgMCTruth() == -PDG_t::kKPlus) && (part.pt() > ConfTrack.confTrackLowPtCut) && (part.pt() < ConfTrack.confTrackHighPtCut) && isParticleNSigma(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))) { + mcRecoRegistry.fill(HIST("hMcRecKmPt"), part.pt()); + if (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary) { + mcRecoRegistry.fill(HIST("hMcRecKmPtGenEtaGen"), mcpart.pt(), mcpart.eta()); + } + } + } + } else if ((part.partType() == aod::femtouniverseparticle::ParticleType::kD0) && (part.pt() > ConfDmesons.confMinPtD0D0barReco) && (part.pt() < ConfDmesons.confMaxPtD0D0barReco)) { + if (mcpart.pdgMCTruth() == ConfDmesons.confPDGCodeD0) { + mcRecoRegistry.fill(HIST("hMcRecD0"), part.pt(), part.eta()); + mcRecoRegistry.fill(HIST("hMcRecD0Pt"), part.pt()); + mcRecoRegistry.fill(HIST("hMcRecD0Phi"), part.phi()); + if (part.tpcNClsFound() == 0) { // prompt candidates + mcRecoRegistry.fill(HIST("hMcRecD0Prompt"), part.pt(), part.eta()); + mcRecoRegistry.fill(HIST("hMcRecD0PromptPt"), part.pt()); + mcRecoRegistry.fill(HIST("hMcRecD0PromptPhi"), part.phi()); + } else if (part.tpcNClsFound() == 1) { // non-prompt candidates + mcRecoRegistry.fill(HIST("hMcRecD0NonPrompt"), part.pt(), part.eta()); + mcRecoRegistry.fill(HIST("hMcRecD0NonPromptPt"), part.pt()); + mcRecoRegistry.fill(HIST("hMcRecD0NonPromptPhi"), part.phi()); + } + } else if (mcpart.pdgMCTruth() == ConfDmesons.confPDGCodeD0bar) { + mcRecoRegistry.fill(HIST("hMcRecD0bar"), part.pt(), part.eta()); + mcRecoRegistry.fill(HIST("hMcRecD0barPt"), part.pt()); + mcRecoRegistry.fill(HIST("hMcRecD0barPhi"), part.phi()); + if (part.tpcNClsFound() == 0) { // prompt candidates + mcRecoRegistry.fill(HIST("hMcRecD0barPrompt"), part.pt(), part.eta()); + mcRecoRegistry.fill(HIST("hMcRecD0barPromptPt"), part.pt()); + } else if (part.tpcNClsFound() == 1) { // non-prompt candidates + mcRecoRegistry.fill(HIST("hMcRecD0barNonPrompt"), part.pt(), part.eta()); + mcRecoRegistry.fill(HIST("hMcRecD0barNonPromptPt"), part.pt()); + } + } + } + // if (isParticleNSigma(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); + //} This part required change + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMcReco, "Process MC reco data", false); + + void processMcRecoD0InvMass(FemtoMcRecoParticles const& recoParts) + { + for (auto const& part : recoParts) { + // filling the histograms for identified hadrons + if ((part.partType() == aod::femtouniverseparticle::ParticleType::kD0) && (part.pt() > ConfDmesons.confMinPtD0D0barReco) && (part.pt() < ConfDmesons.confMaxPtD0D0barReco)) { + // getting the efficiency value + if (doEfficiencyCorr) { + weight = efficiencyCalculator.getWeight(ParticleNo::TWO, part.pt()); + } else { + weight = 1.0f; + } + // filling the inv. mass histograms + if (part.mLambda() > 0) { + if (part.sign() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + mcRecoRegistry.fill(HIST("hMassVsPtD0Sig"), part.mLambda(), part.pt(), weight); + } else if (part.sign() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + mcRecoRegistry.fill(HIST("hMassVsPtD0Refl"), part.mLambda(), part.pt(), weight); + } else { + mcRecoRegistry.fill(HIST("hMassVsPtD0Bkg"), part.mLambda(), part.pt(), weight); + } + if (part.tpcNClsFound() == 0) { // prompt candidates + mcRecoRegistry.fill(HIST("hMassVsPtD0Prompt"), part.mLambda(), part.pt(), weight); + } else if (part.tpcNClsFound() == 1) { // non-prompt candidates + mcRecoRegistry.fill(HIST("hMassVsPtD0NonPrompt"), part.mLambda(), part.pt(), weight); + } + } else if (part.mAntiLambda() > 0) { + if (part.sign() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + mcRecoRegistry.fill(HIST("hMassVsPtD0barSig"), part.mAntiLambda(), part.pt(), weight); + } else if (part.sign() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + mcRecoRegistry.fill(HIST("hMassVsPtD0barRefl"), part.mAntiLambda(), part.pt(), weight); + } else { + mcRecoRegistry.fill(HIST("hMassVsPtD0barBkg"), part.mAntiLambda(), part.pt(), weight); + } + if (part.tpcNClsFound() == 0) { // prompt candidates + mcRecoRegistry.fill(HIST("hMassVsPtD0barPrompt"), part.mAntiLambda(), part.pt(), weight); + } else if (part.tpcNClsFound() == 1) { // non-prompt candidates + mcRecoRegistry.fill(HIST("hMassVsPtD0barNonPrompt"), part.mAntiLambda(), part.pt(), weight); + } + } + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMcRecoD0InvMass, "Process MC reco inv. mass histograms for D0", false); + + 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.tempFitVar()); + int8_t hfFlagMcGen = static_cast(part.mLambda()); + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) { + continue; + } + + if (pdgParticle->Charge() > 0.0) { + mcTruthRegistry.fill(HIST("hMcGenAllPositivePt"), part.pt()); + } + if (pdgCode == PDG_t::kPiPlus) { + mcTruthRegistry.fill(HIST("hMcGenPipPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenPipPt"), part.pt()); + } + if (pdgCode == PDG_t::kKPlus) { + mcTruthRegistry.fill(HIST("hMcGenKpPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenKpPt"), part.pt()); + } + if (pdgCode == o2::constants::physics::Pdg::kD0) { + if (std::abs(hfFlagMcGen) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + mcTruthRegistry.fill(HIST("hMcGenD0"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenD0Pt"), part.pt()); + if (static_cast(part.mAntiLambda()) == genPromptD0) { + mcTruthRegistry.fill(HIST("hMcGenD0Prompt"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenD0PromptPt"), part.pt()); + } else if (static_cast(part.mAntiLambda()) == genNonPromptD0) { + mcTruthRegistry.fill(HIST("hMcGenD0NonPrompt"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenD0NonPromptPt"), part.pt()); + } + } + } + if (pdgCode == PDG_t::kProton) { + mcTruthRegistry.fill(HIST("hMcGenPrPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenPrPt"), part.pt()); + } + + if (pdgParticle->Charge() < 0.0) { + mcTruthRegistry.fill(HIST("hMcGenAllNegativePt"), part.pt()); + } + if (pdgCode == PDG_t::kPiMinus) { + mcTruthRegistry.fill(HIST("hMcGenPimPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenPimPt"), part.pt()); + } + if (pdgCode == PDG_t::kKMinus) { + mcTruthRegistry.fill(HIST("hMcGenKmPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenKmPt"), part.pt()); + } + if (pdgCode == o2::constants::physics::Pdg::kD0Bar) { + if (std::abs(hfFlagMcGen) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + mcTruthRegistry.fill(HIST("hMcGenD0bar"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenD0barPt"), part.pt()); + if (static_cast(part.mAntiLambda()) == genPromptD0) { + mcTruthRegistry.fill(HIST("hMcGenD0barPrompt"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenD0barPromptPt"), part.pt()); + } else if (static_cast(part.mAntiLambda()) == genNonPromptD0) { + mcTruthRegistry.fill(HIST("hMcGenD0barNonPrompt"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenD0barNonPromptPt"), part.pt()); + } + } + } + if (pdgCode == -PDG_t::kProton) { + mcTruthRegistry.fill(HIST("hMcGenAntiPrPtVsEta"), part.pt(), part.eta()); + mcTruthRegistry.fill(HIST("hMcGenAntiPrPt"), part.pt()); + } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackD0, processMixedEventMC, "Enable processing mixed events MC", false); + 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..e133de72efe --- /dev/null +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackNucleus.cxx @@ -0,0 +1,846 @@ +// 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 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 "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" + +#include +#include +#include + +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 790c233773a..98a697434ac 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -10,58 +10,71 @@ // 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 "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCorrection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.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 "TDatabasePDG.h" +#include "Framework/runDataProcessing.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/FemtoUniverseDetaDphiStar.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUtils.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include +#include + +#include +#include 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{"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 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 ConfIsCPR{"ConfIsCPR", true, "Close Pair Rejection"}; + 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"}; @@ -72,102 +85,128 @@ struct femtoUniversePairTaskTrackPhi { 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}; + + HistogramRegistry effCorrRegistry{"EfficiencyCorrection", {}, OutputObjHandlingPolicy::AnalysisObject}; + + EffCorConfigurableGroup effCorConfGroup; + EfficiencyCorrection effCorrection{&effCorConfGroup}; + + 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; @@ -176,28 +215,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; } @@ -205,7 +262,7 @@ 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; @@ -215,17 +272,39 @@ struct femtoUniversePairTaskTrackPhi { } } - bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + 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; + } + } else { + return false; + } + } + + 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; @@ -235,199 +314,265 @@ 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) + { + 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 (ConfTrack.ConfPDGCodeTrack) { + 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; + } + } + + /// @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 (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}}); + } + + effCorrection.init( + &effCorrRegistry, + { + static_cast(ConfBinsTempFitVarpT), + {ConfBinsEta, -1, 1}, + ConfBinsMult, + }); + eventHisto.init(&qaRegistry); 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}, {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}}); - 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}}); - - 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, ConfCPRInvMassCutMin.value, ConfCPRInvMassCutMax.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); - } - - 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& 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); + if constexpr (isMC) { + // reco + effCorrection.fillRecoHist(phicandidate, 333); } } - float tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa; - 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; - // } - - 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); - - if (ConfTrack.ConfIsTrackIdentified) { - if (!IsParticleNSigma(track.p(), tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa)) { + + 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 (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); - 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); + if constexpr (isMC) { + effCorrection.fillRecoHist(track, ConfTrackPDGCode); } } + /// 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; } } @@ -436,107 +581,76 @@ struct femtoUniversePairTaskTrackPhi { if (!pairCleaner.isCleanPair(track, phicandidate, parts)) { continue; } - sameEventFemtoCont.setPair(track, phicandidate, multCol, ConfBothTracks.ConfUse3D); - sameEventAngularCont.setPair(track, phicandidate, multCol, ConfBothTracks.ConfUse3D); + weight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); + sameEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); } - } - /// 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); - - 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); - - 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 = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); + 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); + 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); @@ -547,29 +661,29 @@ 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); } } - 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) + { + eventHisto.fillQA(col); + // Reco + auto thegroupPartsTrack = partsTrackMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsPhi = partsPhiMCReco->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + 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(); @@ -577,19 +691,120 @@ 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, 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; + } + + if (pdgCode == ConfTrackPDGCode) { + effCorrection.fillTruthHist(part); + } + + // 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()); + effCorrection.fillTruthHist(part); + 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, processMixedEventMC, "Enable processing mixed events MC", false); + 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 = effCorrection.getWeight(ParticleNo::TWO, part); + 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 = effCorrection.getWeight(ParticleNo::ONE, part); + 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..f4eb45752dc 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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 ed5ff3c56f1..dcecf711c08 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack3DMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrack3DMultKtExtended.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -14,32 +14,34 @@ /// \remark This file is inherited from ~/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx on 10/01/2024 /// \author Pritam Chakraborty, WUT Warsaw, pritam.chakraborty@pw.edu.pl -#include -#include "TRandom2.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverse3DContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" +#include "Framework/runDataProcessing.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/FemtoUniverse3DContainer.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" +#include "TRandom2.h" + +#include +#include 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 +77,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"}; @@ -95,9 +99,9 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { } 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 == as(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 == as(trackonefilter.ConfChargePart1) && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; // /// Histogramming for particle 1 @@ -115,9 +119,9 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { } 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 == as(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 == as(tracktwofilter.ConfChargePart2)) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -132,9 +136,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 +158,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 +174,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 +183,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 +214,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 +229,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 +243,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; @@ -243,25 +261,25 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { 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; } @@ -269,7 +287,7 @@ struct femtoUniversePairTaskTrackTrack3DMultKtExtended { 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; @@ -290,13 +308,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; @@ -385,6 +403,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) { @@ -410,9 +432,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); } @@ -426,22 +452,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; } @@ -452,7 +479,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; @@ -463,7 +490,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; } } @@ -476,17 +503,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(0); 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; @@ -497,7 +523,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; } } @@ -515,17 +541,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::getpairmom3d(p1, mass1, p2, mass2, ConfIsIden, ConfIsLCMS); - sameEventMultContPP.fill_3D(k3d[1], k3d[2], k3d[3], multCol, kT); + 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 { + 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; @@ -538,17 +576,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; @@ -563,27 +613,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); @@ -591,28 +653,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); @@ -630,7 +703,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; @@ -641,43 +714,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; } @@ -687,13 +794,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(); @@ -718,21 +911,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(); @@ -746,21 +942,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..06665491396 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackExtended.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -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,38 +84,47 @@ 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; /// 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; @@ -128,64 +137,70 @@ 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}; + HistogramRegistry effCorrRegistry{"EfficiencyCorrection", {}, 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 +209,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 +236,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 +263,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 +313,75 @@ 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&) { 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, std::nullopt); // last true = isDebug + if (!confIsSame) { + trackHistoPartTwo.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarBins, twotracksconfigs.confIsMC, tracktwofilter.confPDGCodePartTwo, true, std::nullopt); // 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; + + effCorrection.init( + &effCorrRegistry, + { + static_cast(confTempFitVarpTBins), + {confEtaBins, -2, 2}, + confMultBins, + }); } 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(auto parts, int partPDG, int partCharge) -> void + { + for (const auto& particle : parts) { + auto pdgCode = static_cast(particle.pidCut()); + if (pdgCode != partPDG) { + continue; + } + + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) { + continue; + } + + if (sign(pdgParticle->Charge()) != sign(partCharge)) { + continue; + } + + effCorrection.fillTruthHist(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,90 +400,98 @@ 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; } } trackHistoPartOne.fillQA(part); + if constexpr (isMC) { + effCorrection.fillRecoHist(part, trackonefilter.confPDGCodePartOne); + } } - 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; } } trackHistoPartTwo.fillQA(part); + if constexpr (isMC) { + effCorrection.fillRecoHist(part, tracktwofilter.confPDGCodePartTwo); + } } /// 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 +501,58 @@ struct femtoUniversePairTaskTrackTrackExtended { continue; } + float weight = effCorrection.getWeight(ParticleNo::ONE, p1); + if (!confIsSame) { + weight *= effCorrection.getWeight(ParticleNo::TWO, p2); + } + 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 +561,18 @@ struct femtoUniversePairTaskTrackTrackExtended { if (!pairCleaner.isCleanPair(p1, p2, parts)) { continue; } - sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + + float weight = effCorrection.getWeight(ParticleNo::ONE, p1); + if (!confIsSame) { + weight *= effCorrection.getWeight(ParticleNo::TWO, p2); + } + + if (swpart) + sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.confUse3D, weight); + else + sameEventCont.setPair(p2, p1, multCol, twotracksconfigs.confUse3D, weight); + + swpart = !swpart; } } } @@ -504,8 +580,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 +590,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(groupMCTruth1, trackonefilter.confPDGCodePartOne, trackonefilter.confChargePart1); - doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr()); + if (!confIsSame) { + auto groupMCTruth2 = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + doMCTruth(groupMCTruth2, tracktwofilter.confPDGCodePartTwo, tracktwofilter.confChargePart2); + } + + 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 +635,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); + if (!confIsSame) { + weight *= effCorrection.getWeight(ParticleNo::TWO, p2); + } + 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 +692,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 +715,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 +745,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..5cff8c72cf9 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMC.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMC.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -17,31 +17,32 @@ /// \author Zuzanna Chochulska, WUT Warsaw, zuzanna.chochulska.stud@pw.edu.pl /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairAngularWithCentMultKt.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" +#include "Framework/runDataProcessing.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/FemtoUniverseContainer.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/FemtoUniversePairAngularWithCentMultKt.h" +#include "TDatabasePDG.h" + +#include 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 +168,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 +450,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 +482,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 +525,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 +550,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 +596,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 +642,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 +680,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 af8bccfc785..39e0e83e075 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMcTruth.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMcTruth.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -14,64 +14,65 @@ /// \author Malgorzata Janik, WUT, majanik@cern.ch /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch -#include -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" +#include "Framework/runDataProcessing.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/FemtoUtils.h" -#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include +#include using namespace o2; -using namespace o2::analysis::femtoUniverse; +using namespace o2::analysis::femto_universe; +using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -struct femtoUniversePairTaskTrackTrackMcTruth { +struct FemtoUniversePairTaskTrackTrackMcTruth { SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; /// Particle selection part /// Configurables for both particles - Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; - Configurable ConfEtaMax{"ConfEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; + Configurable confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable confEtaMax{"confEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; /// Particle 1 - 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"}; + 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", 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"}; + Configurable confIsSame{"confIsSame", false, "Pairs of the same particle"}; + 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; @@ -83,36 +84,40 @@ struct femtoUniversePairTaskTrackTrackMcTruth { int vPIDPartOne, vPIDPartTwo; std::vector kNsigma; + // D0/D0bar options + Configurable confActiveD0OriginCheck{"confActiveD0OriginCheck", false, "If true - calculate correlation for D0/D0bar mesons with a given origin"}; + Configurable confD0OriginFlag{"confD0OriginFlag", 1, "D0/D0bar origin: 0 - none, 1 - prompt, 2 - non-prompt"}; + /// particle part - ConfigurableAxis ConfTempFitVarpTBins{"ConfTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfTempFitVarPDGBins{"ConfDTempFitVarInvMassBins", {6000, -2300, 2300}, "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 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 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 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{"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 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; /// Histogram output HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry MixQaRegistry{"MixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry mixQaRegistry{"mixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; /// @brief Counter for particle swapping int fNeventsProcessed = 0; @@ -121,25 +126,25 @@ struct femtoUniversePairTaskTrackTrackMcTruth { { eventHisto.init(&qaRegistry); - trackHistoPartOne.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, ConfPDGCodePartOne, false); - if (!ConfIsSame) { - trackHistoPartTwo.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarPDGBins, 0, ConfPDGCodePartTwo, false); + trackHistoPartOne.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarPDGBins, 0, confPDGCodePartOne, false); + if (!confIsSame) { + trackHistoPartTwo.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarPDGBins, 0, 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}}); - sameEventCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, 0, ConfUse3D); - mixedEventCont.init(&resultRegistry, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, ConfEtaBins, ConfPhiBins, 0, ConfUse3D); - sameEventCont.setPDGCodes(ConfPDGCodePartOne, ConfPDGCodePartTwo); - mixedEventCont.setPDGCodes(ConfPDGCodePartOne, ConfPDGCodePartTwo); + sameEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, 0, confUse3D); + mixedEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, 0, confUse3D); + sameEventCont.setPDGCodes(confPDGCodePartOne, confPDGCodePartTwo); + mixedEventCont.setPDGCodes(confPDGCodePartOne, confPDGCodePartTwo); pairCleaner.init(&qaRegistry); } 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); } @@ -160,37 +165,71 @@ struct femtoUniversePairTaskTrackTrackMcTruth { fNeventsProcessed++; /// Histogramming same event - for (auto& part : groupPartsOne) { - + for (auto const& part : groupPartsOne) { + if (!confNoPDGPartOne && part.tempFitVar() != confPDGCodePartOne) { + continue; + } + if (static_cast(part.tempFitVar()) == static_cast(Pdg::kD0) && confActiveD0OriginCheck && part.mLambda() != confD0OriginFlag) { + continue; + } trackHistoPartOne.fillQA(part); } - if (!ConfIsSame) { - for (auto& part : groupPartsTwo) { - + if (!confIsSame) { + for (auto const& part : groupPartsTwo) { + if (!confNoPDGPartTwo && part.tempFitVar() != confPDGCodePartTwo) { + continue; + } + if (static_cast(part.tempFitVar()) == static_cast(Pdg::kD0) && confActiveD0OriginCheck && part.mLambda() != confD0OriginFlag) { + 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 const& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if ((!confNoPDGPartOne && static_cast(p1.tempFitVar()) != confPDGCodePartOne) || (!confNoPDGPartTwo && static_cast(p2.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 const& [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, - o2::aod::FDParticles& parts) + void processSameEvent(o2::aod::FdCollision const& col, + o2::aod::FDParticles const& parts) { fillCollision(col); @@ -199,7 +238,7 @@ struct femtoUniversePairTaskTrackTrackMcTruth { doSameEvent(thegroupPartsOne, thegroupPartsTwo, parts, col.magField(), col.multNtr()); } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackMcTruth, processSameEvent, "Enable processing same event", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackMcTruth, processSameEvent, "Enable processing same event", true); /// 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, ... @@ -217,11 +256,14 @@ struct femtoUniversePairTaskTrackTrackMcTruth { bool swpart = fNeventsProcessed % 2; fNeventsProcessed++; - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + for (auto const& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if ((!confNoPDGPartOne && static_cast(p1.tempFitVar()) != confPDGCodePartOne) || (!confNoPDGPartTwo && static_cast(p2.tempFitVar()) != confPDGCodePartTwo)) { + continue; + } if (swpart) - mixedEventCont.setPair(p1, p2, multCol, ConfUse3D); + mixedEventCont.setPair(p1, p2, multCol, confUse3D); else - mixedEventCont.setPair(p2, p1, multCol, ConfUse3D); + mixedEventCont.setPair(p2, p1, multCol, confUse3D); swpart = !swpart; } @@ -230,13 +272,13 @@ 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, - o2::aod::FDParticles& parts) + void processMixedEvent(o2::aod::FdCollisions const& cols, + o2::aod::FDParticles const& parts) { - 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})); + 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); @@ -253,13 +295,13 @@ struct femtoUniversePairTaskTrackTrackMcTruth { doMixedEvent(groupPartsOne, groupPartsTwo, parts, magFieldTesla1, multiplicityCol); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackMcTruth, processMixedEvent, "Enable processing mixed events", true); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackMcTruth, processMixedEvent, "Enable processing mixed events", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; return workflow; } diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx index 89d3a829dd6..5ff117461ca 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -17,80 +17,70 @@ /// \author Zuzanna Chochulska, WUT Warsaw & CTU Prague, zchochul@cern.ch /// \author Alicja Płachta, WUT Warsaw, alicja.plachta.stud@pw.edu.pl -#include +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseFemtoContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairWithCentMultKt.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" +#include "Framework/runDataProcessing.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" +#include "TDatabasePDG.h" + +#include +#include 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]{ - {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 { +struct FemtoUniversePairTaskTrackTrackMultKtExtended { Service pdg; /// Particle selection part - /// Table for both particles with separate configurables for De + /// Table for both particles struct : o2::framework::ConfigurableGroup { - Configurable ConfNsigmaCombined{"ConfNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > ConfTOFPtMin"}; - Configurable ConfNsigmaCombinedDe{"ConfNsigmaCombinedDe", 3.0f, "TPC and TOF Deuteron Sigma (combined) for momentum > ConfTOFPtMinDe"}; - Configurable ConfNsigmaTPC{"ConfNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < ConfTOFPtMin"}; - Configurable ConfNsigmaTPCDe{"ConfNsigmaTPCDe", 3.0f, "TPC Deuteron Sigma for momentum < ConfTOFPtMin"}; - Configurable ConfTOFPtMin{"ConfTOFPtMin", 0.5f, "Min. Pt for which TOF is required for PID."}; - Configurable ConfTOFPtMinDe{"ConfTOFPtMinDe", 0.5f, "Min. Pt for De 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 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"}; + 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; - /// 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 a{"a", -167.0f, "Parameter 'a' of a linear function 'y = a * x + b'"}; - Configurable b{"b", 300.0f, "Parameter 'b' of a linear function 'y = a * x + b'"}; - } lincut; - using FemtoFullParticles = soa::Join; // Filters for selecting particles (both p1 and p2) - 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 @@ -99,38 +89,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 ConfPtHighPart1{"ConfPtHighPart1", 1.5, "Higher limit for Pt for the first particle"}; - Configurable ConfChargePart1{"ConfChargePart1", 1, "Particle 1 sign"}; + 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 == as(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 == as(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 ConfPtHighPart2{"ConfPtHighPart2", 1.5, "Higher limit for Pt for the second particle"}; - Configurable ConfChargePart2{"ConfChargePart2", -1, "Particle 2 sign"}; + 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 == as(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 == as(tracktwofilter.confChargePart2)) && aod::femtouniverseparticle::pt < tracktwofilter.confPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.confpLowPart2; /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -143,70 +131,71 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { 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"}; + 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) < twotracksconfigs.ConfEtaMax); // example filtering on configurable + 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) < 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"}; + 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 or centrality"}; // \todo to be obtained from the hash task - ConfigurableAxis ConfMultKstarBins{"ConfMultKstarBins", {VARIABLE_WIDTH, 0.0f, 13.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, -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 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"}; - - FemtoUniverseFemtoContainer sameEventCont; - FemtoUniverseFemtoContainer mixedEventCont; - - FemtoUniverseFemtoContainer sameEventContPP; - FemtoUniverseFemtoContainer mixedEventContPP; - - FemtoUniverseFemtoContainer sameEventContMM; - FemtoUniverseFemtoContainer mixedEventContMM; + 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, 13.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, -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 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 sameEventContPP; + FemtoUniverseFemtoContainer mixedEventContPP; + + 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; @@ -217,195 +206,101 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { 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 mixQaRegistry{"mixQaRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry SameMultRegistryPM{"SameMultRegistryPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MixedMultRegistryPM{"MixedMultRegistryPM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + 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 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 sameMultRegistryMM{"sameMultRegistryMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mixedMultRegistryMM{"mixedMultRegistryMM", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; 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 std::abs(nsigmaTPC) < twotracksconfigs.confNsigmaTPC; } else { - if (TMath::Hypot(nsigmaTOFPr, nsigmaTPCPr) < twotracksconfigs.ConfNsigmaCombined) { - return true; - } else { - return false; - } - } - return false; - } - - 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 std::hypot(nsigmaTOF, nsigmaTPC) < twotracksconfigs.confNsigmaCombined; } - return false; } - bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + /// 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 - // 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 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 { - if (TMath::Hypot(nsigmaTOFPi, nsigmaTPCPi) < twotracksconfigs.ConfNsigmaCombined) { - return true; - } else { - return false; - } - } - } - return false; - } - - bool IsDeuteronNSigma(float mom, float nsigmaTPCDe, float nsigmaTOFDe) - { - //|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 - if (true) { - if (mom < twotracksconfigs.ConfTOFPtMinDe) { - if (TMath::Abs(nsigmaTPCDe) < twotracksconfigs.ConfNsigmaTPCDe) { - return true; - } else { - return false; - } - } else { - if (TMath::Hypot(nsigmaTOFDe, nsigmaTPCDe) < twotracksconfigs.ConfNsigmaCombinedDe) { - return true; - } else { - return false; - } - } - } - 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 > 0.8 && mom < 1.4) { - if (tpcSignal > lincut.a * mom + lincut.b) { - return IsDeuteronNSigma(mom, nsigmaTPCDe, nsigmaTOFDe); - } else { - return false; - } - } else { - return IsDeuteronNSigma(mom, nsigmaTPCDe, nsigmaTOFDe); + return false; } } else { - return IsDeuteronNSigma(mom, nsigmaTPCDe, nsigmaTOFDe); + return isNSigma(mom, nsigmaTPCK, nsigmaTOFK); } } - bool IsParticleNSigma(int8_t particle_number, float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK, float nsigmaTPCDe, float nsigmaTOFDe, float tpcSignal) + 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: // Proton- - return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); break; case 211: // Pion+ case -211: // Pion- case 111: // Pion 0 - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + return isNSigma(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; - case 1000010020: // Deuteron+ - case -1000010020: // Deuteron- - return IsDeuteronNSigmaLinearCut(mom, nsigmaTPCDe, nsigmaTOFDe, tpcSignal); + 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) { + switch (tracktwofilter.confPDGCodePartTwo) { case 2212: // Proton+ case -2212: // Proton- - return IsProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); break; case 211: // Pion+ case -211: // Pion- case 111: // Pion 0 - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + return isNSigma(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; - case 1000010020: // Deuteron+ - case -1000010020: // Deuteron- - return IsDeuteronNSigmaLinearCut(mom, nsigmaTPCDe, nsigmaTOFDe, tpcSignal); + case 130: // Kaon 0 LONG + case 310: // Kaon 0 SHORT + return isNSigma(mom, nsigmaTPCK, nsigmaTOFK); break; - default: return false; } return false; @@ -420,118 +315,120 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { eventHisto.init(&qaRegistry); sphericityRegistry.add("sphericity", ";Sphericity;Entries", kTH1F, {{150, 0.0, 3, "Sphericity"}}); - trackHistoPartOne.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, twotracksconfigs.ConfIsMC, trackonefilter.ConfPDGCodePartOne, true); + trackHistoPartOne.init(&qaRegistry, confTempFitVarpTBins, confTempFitVarBins, twotracksconfigs.confIsMC, trackonefilter.confPDGCodePartOne, true); - trackHistoPartTwo.init(&qaRegistry, ConfTempFitVarpTBins, ConfTempFitVarBins, twotracksconfigs.ConfIsMC, tracktwofilter.ConfPDGCodePartTwo, 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}}); + 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); + mass1 = pdg->Mass(trackonefilter.confPDGCodePartOne); + mass2 = pdg->Mass(tracktwofilter.confPDGCodePartTwo); if (cfgProcessPM) { - sameEventCont.init(&resultRegistryPM, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); - mixedEventCont.init(&resultRegistryPM, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); + sameEventCont.init(&resultRegistryPM, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, twotracksconfigs.confIsMC, twotracksconfigs.confUse3D); + mixedEventCont.init(&resultRegistryPM, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, twotracksconfigs.confIsMC, twotracksconfigs.confUse3D); - sameEventCont.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); - mixedEventCont.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + sameEventCont.setPDGCodes(trackonefilter.confPDGCodePartOne, tracktwofilter.confPDGCodePartTwo); + mixedEventCont.setPDGCodes(trackonefilter.confPDGCodePartOne, tracktwofilter.confPDGCodePartTwo); if (cfgProcessMultBins) { - sameEventMultCont.init(&SameMultRegistryPM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); - mixedEventMultCont.init(&MixedMultRegistryPM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + sameEventMultCont.init(&sameMultRegistryPM, confkstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + mixedEventMultCont.init(&mixedMultRegistryPM, confkstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); } } if (cfgProcessPP) { - sameEventContPP.init(&resultRegistryPP, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); - mixedEventContPP.init(&resultRegistryPP, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); - sameEventContPP.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); - mixedEventContPP.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + sameEventContPP.init(&resultRegistryPP, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, twotracksconfigs.confIsMC, twotracksconfigs.confUse3D); + mixedEventContPP.init(&resultRegistryPP, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, twotracksconfigs.confIsMC, twotracksconfigs.confUse3D); + sameEventContPP.setPDGCodes(trackonefilter.confPDGCodePartOne, tracktwofilter.confPDGCodePartTwo); + mixedEventContPP.setPDGCodes(trackonefilter.confPDGCodePartOne, tracktwofilter.confPDGCodePartTwo); if (cfgProcessMultBins) { - sameEventMultContPP.init(&SameMultRegistryPP, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); - mixedEventMultContPP.init(&MixedMultRegistryPP, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + 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, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); - mixedEventContMM.init(&resultRegistryMM, ConfkstarBins, ConfMultBins, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); - sameEventContMM.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); - mixedEventContMM.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); + sameEventContMM.init(&resultRegistryMM, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, twotracksconfigs.confIsMC, twotracksconfigs.confUse3D); + mixedEventContMM.init(&resultRegistryMM, confkstarBins, confMultBins, confkTBins, confmTBins, confmultBins3D, confmTBins3D, twotracksconfigs.confIsMC, twotracksconfigs.confUse3D); + sameEventContMM.setPDGCodes(trackonefilter.confPDGCodePartOne, tracktwofilter.confPDGCodePartTwo); + mixedEventContMM.setPDGCodes(trackonefilter.confPDGCodePartOne, tracktwofilter.confPDGCodePartTwo); if (cfgProcessMultBins) { - sameEventMultContMM.init(&SameMultRegistryMM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); - mixedEventMultContMM.init(&MixedMultRegistryMM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + sameEventMultContMM.init(&sameMultRegistryMM, confkstarBins, confMultKstarBins, confKtKstarBins, cfgProcessKtBins, cfgProcessKtMt3DCF); + mixedEventMultContMM.init(&mixedMultRegistryMM, 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); + 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.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) { - 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), trackCuts.getNsigmaTPC(part, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(part, o2::track::PID::Deuteron), part.tpcSignal())) { + if ((pairType == 1 || pairType == 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 (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), trackCuts.getNsigmaTPC(part, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(part, o2::track::PID::Deuteron), part.tpcSignal())) { + if ((pairType == 1 || pairType == 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) { + if (pairType == 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.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), trackCuts.getNsigmaTPC(p1, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p1, o2::track::PID::Deuteron), p1.tpcSignal())) { + 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), trackCuts.getNsigmaTPC(p2, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p2, o2::track::PID::Deuteron), p2.tpcSignal())) { + 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; } } @@ -544,24 +441,24 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { float kstar = FemtoUniverseMath::getkstar(p1, mass1, p2, mass2); float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); - sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D); + sameEventCont.setPair(p1, p2, multCol, twotracksconfigs.confUse3D); if (cfgProcessMultBins) sameEventMultCont.fill(kstar, multCol, kT); } } else { /// Now build the combinations for identical particles pairs - for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsOne))) { + for (const 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), trackCuts.getNsigmaTPC(p1, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p1, o2::track::PID::Deuteron), p1.tpcSignal())) { + 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), trackCuts.getNsigmaTPC(p2, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p2, o2::track::PID::Deuteron), p2.tpcSignal())) { + 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; } } @@ -571,24 +468,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: @@ -601,8 +518,8 @@ 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, - FilteredFemtoFullParticles& parts) + void processSameEvent(soa::Filtered::iterator const& col, + FilteredFemtoFullParticles const& parts) { fillCollision(col); sphericityRegistry.fill(HIST("sphericity"), col.sphericity()); @@ -613,23 +530,23 @@ 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); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackMultKtExtended, 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(o2::aod::FdCollision const& col, + soa::Join const& parts, + o2::aod::FdMCParticles const&) { fillCollision(col); @@ -638,15 +555,15 @@ 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); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackMultKtExtended, 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, ... @@ -658,50 +575,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))) { + for (const 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), trackCuts.getNsigmaTPC(p1, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p1, o2::track::PID::Deuteron), p1.tpcSignal())) { + 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), trackCuts.getNsigmaTPC(p2, o2::track::PID::Deuteron), trackCuts.getNsigmaTOF(p2, o2::track::PID::Deuteron), p2.tpcSignal())) { + 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; } } - 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); + + 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: @@ -711,15 +653,15 @@ 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, - FilteredFemtoFullParticles& parts) + /// \param cols subscribe to the collisions table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processMixedEvent(soa::Filtered const& cols, + FilteredFemtoFullParticles const& 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})); + 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(); @@ -745,20 +687,20 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackMultKtExtended, processMixedEvent, "Enable processing mixed events", true); + 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, - soa::Join& parts, - o2::aod::FDMCParticles&) + /// \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 const& cols, + soa::Join const& parts, + o2::aod::FdMCParticles const&) { - 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})); + 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(); @@ -786,13 +728,13 @@ struct femtoUniversePairTaskTrackTrackMultKtExtended { } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackMultKtExtended, processMixedEventMC, "Enable processing mixed events MC", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackTrackMultKtExtended, 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/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx index f2d9093976e..f0a5a1d925d 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -14,32 +14,33 @@ /// \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 "TRandom2.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairSHCentMultKt.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseSHContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseTrackSelection.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/StepTHn.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "TDatabasePDG.h" +#include "Framework/runDataProcessing.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" +#include "TRandom2.h" + +#include +#include 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; @@ -65,6 +66,9 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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 ConfIsElReject{"ConfIsElReject", false, "Is electron rejection activated"}; + Configurable ConfNsigmaTPCElRejectMin{"ConfNsigmaTPCElRejectMin", 2.0f, "TPC Electron SigmaMin for momentum < ConfTOFPtMin"}; + Configurable ConfNsigmaTPCElRejectMax{"ConfNsigmaTPCElRejectMax", 2.0f, "TPC Electron SigmaMax 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)"}; @@ -73,17 +77,39 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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 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., "Delta Phi min cut for Close Pair Rejection"}; + Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0., "Delta Eta max cut for Close Pair Rejection"}; + Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0., "Delta Eta min cut for Close Pair Rejection"}; + Configurable> ConfCPRdeltaPhiCutMaxVector{"ConfCPRdeltaPhiCutMaxVector", std::vector{0.0, 0.0, 0.0, 0.0}, "Delta Phi max cut for Close Pair Rejection"}; + Configurable> ConfCPRdeltaPhiCutMinVector{"ConfCPRdeltaPhiCutMinVector", std::vector{0.0, 0.0, 0.0, 0.0}, "Delta Phi min cut for Close Pair Rejection"}; + Configurable> ConfCPRdeltaEtaCutMaxVector{"ConfCPRdeltaEtaCutMaxVector", std::vector{0.0, 0.0, 0.0, 0.0}, "Delta Eta max cut for Close Pair Rejection"}; + Configurable> ConfCPRdeltaEtaCutMinVector{"ConfCPRdeltaEtaCutMinVector", std::vector{0.0, 0.0, 0.0, 0.0}, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confIsCPRkT{"confIsCPRkT", true, "kT dependent deltaEta-deltaPhi cut for Close Pair Rejection"}; + Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable confUseCCImCut{"confUseCCImCut", false, "Fill SH within specific quadrants of qout-qside"}; + Configurable confUse1stand3rd{"confUse1stand3rd", false, "Use first and third quadrants of qout-qside"}; + Configurable confUse2ndand4th{"confUse2ndand4th", false, "Use second and fourth quadrants of qout-qside"}; } 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 + // using FilteredFemtoFullParticles = FemtoFullParticles; //if no filtering is applied uncomment this optionconfIsCPRkT + using FemtoRecoParticles = soa::Join; + using FilteredFemtoRecoParticles = soa::Filtered; SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + using FemtoTruthParticles = soa::Join; + Preslice perColMCTruth = aod::femtouniverseparticle::fdCollisionId; + /// Particle 1 struct : o2::framework::ConfigurableGroup { Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 211, "Particle 1 - PDG code"}; @@ -95,9 +121,10 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { } 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 == as(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 == as(trackonefilter.ConfChargePart1) && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; + Partition partsOneMCTruth = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack); - 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 @@ -115,9 +142,9 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { } 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; + Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(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 == as(tracktwofilter.ConfChargePart2)) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + Partition partsTwoMCTruth = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack); /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -132,8 +159,17 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { /// Event part Configurable ConfV0MLow{"ConfV0MLow", 0.0, "Lower limit for V0M multiplicity"}; Configurable ConfV0MHigh{"ConfV0MHigh", 25000.0, "Upper limit for V0M multiplicity"}; - - Filter collV0Mfilter = ((o2::aod::femtouniversecollision::multV0M > ConfV0MLow) && (o2::aod::femtouniversecollision::multV0M < ConfV0MHigh)); + 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 @@ -141,7 +177,8 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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 ConfMultBinsCent{"ConfMultBinsCent", {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 - centrality"}; // \todo to be obtained from the hash task + ConfigurableAxis ConfMultBinsMult{"ConfMultBinsMult", {VARIABLE_WIDTH, 0.0f, 400.0f, 800.0f, 1200.0f, 1600.0f, 2000.0f, 2500.0f, 3000.0f, 3500.0f, 4000.0f, 4500.0f, 5000.0f, 6000.0f, 7000.0f, 8000.0f, 9000.0f, 10000.0f, 11000.0f, 12000.0f, 13000.0f, 14000.0f, 15000.0f, 16000.0f, 17000.0f, 18000.0f, 99999.f}, "Mixing bins - centrality"}; 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"}; @@ -149,7 +186,8 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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, ConfMultBinsCent}, true}; + ColumnBinningPolicy colBinningNtr{{ConfVtxBins, ConfMultBinsMult}, true}; ConfigurableAxis ConfkstarBins{"ConfkstarBins", {60, 0.0, 0.3}, "binning kstar"}; ConfigurableAxis ConfkTBins{"ConfkTBins", {150, 0., 9.}, "binning kT"}; @@ -158,41 +196,42 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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"}; + Configurable ConfIsFillAngqLCMS{"ConfIsFillAngqLCMS", true, "Fill qLCMS vs dEta vs dPhi"}; + Configurable confCPRDistMax{"confCPRDistMax", 0.0, "Max. radial seperation between two closed-pairs"}; + Configurable confCPRFracMax{"confCPRFracMax", 0.0, "Max. allowed fraction bad to all TPC points of radial seperation between two closed-pairs"}; + Configurable confCPRIsAtITS{"confCPRIsAtITS", false, "Close Pair Rejection at ITS or TPC"}; + Configurable confCPRDphiAvgOrDist{"confCPRDphiAvgOrDist", true, "Close Pair Rejection by radial or angular seperation"}; + Configurable confIsCircularCut{"confIsCircularCut", true, "Close Pair Rejection by circular cut"}; - FemtoUniverseSHContainer sameEventCont; - FemtoUniverseSHContainer mixedEventCont; + FemtoUniverseSHContainer sameEventCont; + FemtoUniverseSHContainer mixedEventCont; - FemtoUniverseSHContainer sameEventContPP; - FemtoUniverseSHContainer mixedEventContPP; + FemtoUniverseSHContainer sameEventContPP; + FemtoUniverseSHContainer mixedEventContPP; - FemtoUniverseSHContainer sameEventContMM; - FemtoUniverseSHContainer mixedEventContMM; + FemtoUniverseSHContainer sameEventContMM; + FemtoUniverseSHContainer mixedEventContMM; + + FemtoUniverseContainer sameEventCont1D; FemtoUniversePairCleaner pairCleaner; FemtoUniverseDetaDphiStar pairCloseRejection; FemtoUniverseTrackSelection trackCuts; - PairSHCentMultKt sameEventMultCont; - PairSHCentMultKt mixedEventMultCont; + PairSHCentMultKt sameEventMultCont; + PairSHCentMultKt mixedEventMultCont; - PairSHCentMultKt sameEventMultContPP; - PairSHCentMultKt mixedEventMultContPP; + PairSHCentMultKt sameEventMultContPP; + PairSHCentMultKt mixedEventMultContPP; - PairSHCentMultKt sameEventMultContMM; - PairSHCentMultKt mixedEventMultContMM; + PairSHCentMultKt sameEventMultContMM; + PairSHCentMultKt mixedEventMultContMM; float mass1 = -1; float mass2 = -1; @@ -200,6 +239,7 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { /// 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}; @@ -214,6 +254,8 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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 { @@ -226,13 +268,13 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { // 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; @@ -244,25 +286,25 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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; } @@ -270,7 +312,7 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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; @@ -280,7 +322,7 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { } } - bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) + bool IsPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCElReject) { //|nsigma_TPC| < 3 for p < 0.5 GeV/c //|nsigma_combined| < 3 for p > 0.5 @@ -291,13 +333,21 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { // 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; + if (twotracksconfigs.ConfIsElReject) { + if ((std::abs(nsigmaTPCPi) < twotracksconfigs.ConfNsigmaTPC) && (nsigmaTPCElReject < twotracksconfigs.ConfNsigmaTPCElRejectMin || nsigmaTPCElReject > twotracksconfigs.ConfNsigmaTPCElRejectMax)) { + return true; + } else { + return false; + } } else { - return false; + 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; @@ -307,7 +357,7 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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, float nsigmaTPCElReject) { if (particle_number == 1) { switch (trackonefilter.ConfPDGCodePartOne) { @@ -317,7 +367,7 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { break; case 211: // Pion+ case -211: // Pion- - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi, nsigmaTPCElReject); break; case 321: // Kaon+ case -321: // Kaon- @@ -335,7 +385,7 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { break; case 211: // Pion+ case -211: // Pion- - return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi); + return IsPionNSigma(mom, nsigmaTPCPi, nsigmaTOFPi, nsigmaTPCElReject); break; case 321: // Kaon+ case -321: // Kaon- @@ -386,6 +436,8 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { sameEventMultContPP.init(&SameMultRegistryPP, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); mixedEventMultContPP.init(&MixedMultRegistryPP, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); } + sameEventCont1D.init(&resultRegistry1D, ConfkstarBins, ConfMultBinsCent, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, twotracksconfigs.ConfEtaBins, twotracksconfigs.ConfPhiBins, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); + sameEventCont1D.setPDGCodes(trackonefilter.ConfPDGCodePartOne, tracktwofilter.ConfPDGCodePartTwo); } if (cfgProcessMM) { @@ -398,11 +450,14 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { sameEventMultContMM.init(&SameMultRegistryMM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); mixedEventMultContMM.init(&MixedMultRegistryMM, ConfkstarBins, ConfMultKstarBins, ConfKtKstarBins, ConfLMax); } + sameEventCont1D.init(&resultRegistry1D, ConfkstarBins, ConfMultBinsCent, ConfkTBins, ConfmTBins, ConfmultBins3D, ConfmTBins3D, twotracksconfigs.ConfEtaBins, twotracksconfigs.ConfPhiBins, twotracksconfigs.ConfIsMC, twotracksconfigs.ConfUse3D); + sameEventCont1D.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 (twotracksconfigs.ConfIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, twotracksconfigs.ConfCPRdeltaPhiCutMin.value, twotracksconfigs.ConfCPRdeltaPhiCutMax.value, twotracksconfigs.ConfCPRdeltaEtaCutMin.value, twotracksconfigs.ConfCPRdeltaEtaCutMax.value, twotracksconfigs.ConfCPRChosenRadii.value, twotracksconfigs.ConfCPRPlotPerRadii.value); + pairCloseRejection.init_kT(&resultRegistry, ConfKtKstarBins, twotracksconfigs.ConfCPRdeltaPhiCutMaxVector, twotracksconfigs.ConfCPRdeltaPhiCutMinVector, twotracksconfigs.ConfCPRdeltaEtaCutMaxVector, twotracksconfigs.ConfCPRdeltaEtaCutMinVector); } vPIDPartOne = trackonefilter.ConfPIDPartOne.value; @@ -411,9 +466,13 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { } 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); } @@ -433,17 +492,18 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { /// Histogramming same event if ((ContType == 1 || ContType == 2) && fillQA) { - for (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))) { + 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), trackCuts.getNsigmaTPC(part, o2::track::PID::Electron))) { continue; } trackHistoPartOne.fillQA(part); + trackHistoPartOne.fillQAMisIden(part, trackonefilter.ConfPDGCodePartOne); } } if ((ContType == 1 || ContType == 3) && fillQA) { - for (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))) { + 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), trackCuts.getNsigmaTPC(part, o2::track::PID::Electron))) { continue; } trackHistoPartTwo.fillQA(part); @@ -453,19 +513,38 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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))) { + 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::Electron))) { 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))) { + 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::Electron))) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { - continue; + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + float lastElement = ConfKtKstarBins.value.back(); + float firstRealElement = ConfKtKstarBins.value[1]; + + if (kT < firstRealElement || kT > lastElement) + continue; + + if (twotracksconfigs.ConfIsCPR.value) { + if (confCPRIsAtITS.value) { + if (pairCloseRejection.isClosePairAtITS(p1, p2, magFieldTesla, femto_universe_container::EventType::same)) { + continue; + } + } else { + if (twotracksconfigs.confIsCPRkT) { + if (pairCloseRejection.isClosePairkT(p1, p2, femto_universe_container::EventType::same, kT, confIsCircularCut)) { + continue; + } + } else { + if (pairCloseRejection.isClosePairFrac(p1, p2, magFieldTesla, femto_universe_container::EventType::same, confCPRDphiAvgOrDist, confCPRDistMax, confCPRFracMax, confIsCircularCut)) { + continue; + } + } } } @@ -473,23 +552,41 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { if (!pairCleaner.isCleanPair(p1, p2, parts)) { continue; } - float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); - sameEventMultCont.fill_mult_NumDen(p1, p2, femtoUniverseSHContainer::EventType::same, 2, multCol, kT); + sameEventMultCont.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); } } else { - 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))) { + 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), trackCuts.getNsigmaTPC(p1, o2::track::PID::Electron))) { 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))) { + 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::Electron))) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::same)) { - continue; + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + float lastElement = ConfKtKstarBins.value.back(); + float firstRealElement = ConfKtKstarBins.value[1]; + + if (kT < firstRealElement || kT > lastElement) + continue; + + if (twotracksconfigs.ConfIsCPR.value) { + if (confCPRIsAtITS.value) { + if (pairCloseRejection.isClosePairAtITS(p1, p2, magFieldTesla, femto_universe_container::EventType::same)) { + continue; + } + } else { + if (twotracksconfigs.confIsCPRkT) { + if (pairCloseRejection.isClosePairkT(p1, p2, femto_universe_container::EventType::same, kT, confIsCircularCut)) { + continue; + } + } else { + if (pairCloseRejection.isClosePairFrac(p1, p2, magFieldTesla, femto_universe_container::EventType::same, confCPRDphiAvgOrDist, confCPRDistMax, confCPRFracMax, confIsCircularCut)) { + continue; + } + } } } @@ -498,34 +595,110 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { continue; } - float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); - TRandom2* randgen = new TRandom2(0); double rand; + rand = randgen->Rndm(); + + std::vector f3d; + double kv; + float outsideref = 0.0; switch (ContType) { case 2: { - rand = randgen->Rndm(); if (rand > 0.5) { - sameEventMultContPP.fill_mult_NumDen(p1, p2, femtoUniverseSHContainer::EventType::same, 2, multCol, kT); + f3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + if (!twotracksconfigs.confUseCCImCut) { + sameEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } else { + if (twotracksconfigs.confUse1stand3rd) { + if ((f3d[1] >= outsideref && f3d[2] >= outsideref) || (f3d[1] < outsideref && f3d[2] < outsideref)) { + sameEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } else if (twotracksconfigs.confUse2ndand4th) { + if ((f3d[1] < outsideref && f3d[2] >= outsideref) || (f3d[1] >= outsideref && f3d[2] < outsideref)) { + sameEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } + } + if (twotracksconfigs.ConfIsMC) { + float weight = 1.0f; + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); + } } else if (rand <= 0.5) { - sameEventMultContPP.fill_mult_NumDen(p2, p1, femtoUniverseSHContainer::EventType::same, 2, multCol, kT); + f3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + if (!twotracksconfigs.confUseCCImCut) { + sameEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } else { + if (twotracksconfigs.confUse1stand3rd) { + if ((f3d[1] >= outsideref && f3d[2] >= outsideref) || (f3d[1] < outsideref && f3d[2] < outsideref)) { + sameEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } else if (twotracksconfigs.confUse2ndand4th) { + if ((f3d[1] < outsideref && f3d[2] >= outsideref) || (f3d[1] >= outsideref && f3d[2] < outsideref)) { + sameEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } + } + if (twotracksconfigs.ConfIsMC) { + float weight = 1.0f; + sameEventCont1D.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); + } + } + if (ConfIsFillAngqLCMS) { + kv = std::sqrt(f3d[1] * f3d[1] + f3d[2] * f3d[2] + f3d[3] * f3d[3]); + pairCloseRejection.ClosePairqLCMS(p1, p2, magFieldTesla, femto_universe_container::EventType::same, kv); } break; } case 3: { - rand = randgen->Rndm(); if (rand > 0.5) { - sameEventMultContMM.fill_mult_NumDen(p1, p2, femtoUniverseSHContainer::EventType::same, 2, multCol, kT); + f3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + if (!twotracksconfigs.confUseCCImCut) { + sameEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } else { + if (twotracksconfigs.confUse1stand3rd) { + if ((f3d[1] >= outsideref && f3d[2] >= outsideref) || (f3d[1] < outsideref && f3d[2] < outsideref)) { + sameEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } else if (twotracksconfigs.confUse2ndand4th) { + if ((f3d[1] < outsideref && f3d[2] >= outsideref) || (f3d[1] >= outsideref && f3d[2] < outsideref)) { + sameEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } + } + if (twotracksconfigs.ConfIsMC) { + float weight = 1.0f; + sameEventCont1D.setPair(p1, p2, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); + } } else if (rand <= 0.5) { - sameEventMultContMM.fill_mult_NumDen(p2, p1, femtoUniverseSHContainer::EventType::same, 2, multCol, kT); + f3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + if (!twotracksconfigs.confUseCCImCut) { + sameEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } else { + if (twotracksconfigs.confUse1stand3rd) { + if ((f3d[1] >= outsideref && f3d[2] >= outsideref) || (f3d[1] < outsideref && f3d[2] < outsideref)) { + sameEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } else if (twotracksconfigs.confUse2ndand4th) { + if ((f3d[1] < outsideref && f3d[2] >= outsideref) || (f3d[1] >= outsideref && f3d[2] < outsideref)) { + sameEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } + } + if (twotracksconfigs.ConfIsMC) { + float weight = 1.0f; + sameEventCont1D.setPair(p2, p1, multCol, twotracksconfigs.ConfUse3D, weight, ConfIsIden); + } + } + if (ConfIsFillAngqLCMS) { + kv = std::sqrt(f3d[1] * f3d[1] + f3d[2] * f3d[2] + f3d[3] * f3d[3]); + pairCloseRejection.ClosePairqLCMS(p1, p2, magFieldTesla, femto_universe_container::EventType::same, kv); } break; } default: break; } - delete randgen; } } } @@ -533,27 +706,39 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { /// 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(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processSameEvent, "Enable processing same event", true); @@ -561,17 +746,183 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { /// \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, + FilteredFemtoRecoParticles const& parts, + aod::FdMCParticles const&) { - 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 (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 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 doSameEventMCTruth(PartitionType groupPartsOne, PartitionType groupPartsTwo, int multCol, int ContType, bool fillQA) + { + + randgen = new TRandom2(0); + /// Histogramming same event + if ((cfgProcessPM || cfgProcessPP) && fillQA) { + for (const auto& part : groupPartsOne) { + if (part.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) { + int pdgCode = static_cast(part.tempFitVar()); + const auto& pdgParticle = pdg->GetParticle(pdgCode); + if (pdgParticle) { + trackHistoPartOne.fillQA(part); + } + } + } + } + + if ((cfgProcessPM || cfgProcessMM) && fillQA) { + for (const auto& part : groupPartsTwo) { + if (part.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) { + int pdgCode = static_cast(part.tempFitVar()); + const auto& pdgParticle = pdg->GetParticle(pdgCode); + if (pdgParticle) { + trackHistoPartTwo.fillQA(part); + } + } + } + } + + if (cfgProcessPM) { + + /// Now build the combinations for non-identical particle pairs + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + + int pdgCodePartOne = static_cast(p1.tempFitVar()); + const auto& pdgParticleOne = pdg->GetParticle(pdgCodePartOne); + int pdgCodePartTwo = static_cast(p2.tempFitVar()); + const auto& pdgParticleTwo = pdg->GetParticle(pdgCodePartTwo); + if (pdgParticleOne && pdgParticleTwo && (pdgCodePartOne == trackonefilter.ConfPDGCodePartOne) && (pdgCodePartTwo == tracktwofilter.ConfPDGCodePartTwo)) { + 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))) { + + int pdgCodePartOne = static_cast(p1.tempFitVar()); + const auto& pdgParticleOne = pdg->GetParticle(pdgCodePartOne); + int pdgCodePartTwo = static_cast(p2.tempFitVar()); + const auto& pdgParticleTwo = pdg->GetParticle(pdgCodePartTwo); + + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + double rand; + rand = randgen->Rndm(); + std::vector f3d; + if (pdgParticleOne && pdgParticleTwo && (pdgCodePartOne == trackonefilter.ConfPDGCodePartOne) && (pdgCodePartTwo == tracktwofilter.ConfPDGCodePartTwo)) { + + 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; + } + } + } + } + delete randgen; + } + + /// 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 processSameEventMCTruth(o2::aod::FdCollision const& col, + FemtoTruthParticles const&) + { + fillCollision(col, ConfIsCent); + + auto thegroupPartsOne = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTwo = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + bool fillQA = true; + + int pairType = 0; + if (cfgProcessPM) { + pairType = 1; + } else if (cfgProcessPP) { + pairType = 2; + } else if (cfgProcessMM) { + pairType = 3; + } + + if (ConfIsCent) { + if (cfgProcessPM) { + doSameEventMCTruth(thegroupPartsOne, thegroupPartsTwo, col.multV0M(), pairType, fillQA); + } + if (cfgProcessPP) { + doSameEventMCTruth(thegroupPartsOne, thegroupPartsOne, col.multV0M(), pairType, fillQA); + } + if (cfgProcessMM) { + doSameEventMCTruth(thegroupPartsTwo, thegroupPartsTwo, col.multV0M(), pairType, fillQA); + } + } else { + if (cfgProcessPM) { + doSameEventMCTruth(thegroupPartsOne, thegroupPartsTwo, col.multNtr(), pairType, fillQA); + } + if (cfgProcessPP) { + doSameEventMCTruth(thegroupPartsOne, thegroupPartsOne, col.multNtr(), pairType, fillQA); + } + if (cfgProcessMM) { + doSameEventMCTruth(thegroupPartsTwo, thegroupPartsTwo, col.multNtr(), pairType, fillQA); + } + } + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processSameEventMCTruth, "Enable processing same event for MC truth", 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 @@ -582,56 +933,198 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { /// \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) + template + void doMixedEvent(PartitionType groupPartsOne, PartitionType groupPartsTwo, 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))) { + 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), trackCuts.getNsigmaTPC(p1, o2::track::PID::Electron))) { 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))) { + 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::Electron))) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femtoUniverseContainer::EventType::mixed)) { - continue; + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + float lastElement = ConfKtKstarBins.value.back(); + float firstRealElement = ConfKtKstarBins.value[1]; + + if (kT < firstRealElement || kT > lastElement) + continue; + + if (twotracksconfigs.ConfIsCPR.value) { + if (confCPRIsAtITS.value) { + if (pairCloseRejection.isClosePairAtITS(p1, p2, magFieldTesla, femto_universe_container::EventType::mixed)) { + continue; + } + } else { + if (twotracksconfigs.confIsCPRkT) { + if (pairCloseRejection.isClosePairkT(p1, p2, femto_universe_container::EventType::mixed, kT, confIsCircularCut)) { + continue; + } + } else { + if (pairCloseRejection.isClosePairFrac(p1, p2, magFieldTesla, femto_universe_container::EventType::mixed, confCPRDphiAvgOrDist, confCPRDistMax, confCPRFracMax, confIsCircularCut)) { + continue; + } + } } } - float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + double rand; + rand = randgen->Rndm(); + + std::vector f3d; + double kv; + float outsideref = 0.0; + switch (ContType) { case 1: { - mixedEventMultCont.fill_mult_NumDen(p1, p2, femtoUniverseSHContainer::EventType::mixed, 2, multCol, kT); + 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: { - mixedEventMultContPP.fill_mult_NumDen(p1, p2, femtoUniverseSHContainer::EventType::mixed, 2, multCol, kT); + if (rand > 0.5) { + f3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + if (!twotracksconfigs.confUseCCImCut) { + mixedEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + if (twotracksconfigs.confUse1stand3rd) { + if ((f3d[1] >= outsideref && f3d[2] >= outsideref) || (f3d[1] < outsideref && f3d[2] < outsideref)) { + mixedEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + } else if (twotracksconfigs.confUse2ndand4th) { + if ((f3d[1] < outsideref && f3d[2] >= outsideref) || (f3d[1] >= outsideref && f3d[2] < outsideref)) { + mixedEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + } + } + } else { + f3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + if (!twotracksconfigs.confUseCCImCut) { + mixedEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + if (twotracksconfigs.confUse1stand3rd) { + if ((f3d[1] >= outsideref && f3d[2] >= outsideref) || (f3d[1] < outsideref && f3d[2] < outsideref)) { + mixedEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + } else if (twotracksconfigs.confUse2ndand4th) { + if ((f3d[1] < outsideref && f3d[2] >= outsideref) || (f3d[1] >= outsideref && f3d[2] < outsideref)) { + mixedEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + } + } + } + if (ConfIsFillAngqLCMS) { + kv = std::sqrt(f3d[1] * f3d[1] + f3d[2] * f3d[2] + f3d[3] * f3d[3]); + pairCloseRejection.ClosePairqLCMS(p1, p2, magFieldTesla, femto_universe_container::EventType::mixed, kv); + } break; } + case 3: { - mixedEventMultContMM.fill_mult_NumDen(p1, p2, femtoUniverseSHContainer::EventType::mixed, 2, multCol, kT); + if (rand > 0.5) { + f3d = FemtoUniverseMath::newpairfunc(p1, mass1, p2, mass2, ConfIsIden); + if (!twotracksconfigs.confUseCCImCut) { + mixedEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + if (twotracksconfigs.confUse1stand3rd) { + if ((f3d[1] >= outsideref && f3d[2] >= outsideref) || (f3d[1] < outsideref && f3d[2] < outsideref)) { + mixedEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + } else if (twotracksconfigs.confUse2ndand4th) { + if ((f3d[1] < outsideref && f3d[2] >= outsideref) || (f3d[1] >= outsideref && f3d[2] < outsideref)) { + mixedEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + } + } + } else { + f3d = FemtoUniverseMath::newpairfunc(p2, mass2, p1, mass1, ConfIsIden); + if (!twotracksconfigs.confUseCCImCut) { + mixedEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + if (twotracksconfigs.confUse1stand3rd) { + if ((f3d[1] >= outsideref && f3d[2] >= outsideref) || (f3d[1] < outsideref && f3d[2] < outsideref)) { + mixedEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + } else if (twotracksconfigs.confUse2ndand4th) { + if ((f3d[1] < outsideref && f3d[2] >= outsideref) || (f3d[1] >= outsideref && f3d[2] < outsideref)) { + mixedEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + } + } + } + if (ConfIsFillAngqLCMS) { + kv = std::sqrt(f3d[1] * f3d[1] + f3d[2] * f3d[2] + f3d[3] * f3d[3]); + pairCloseRejection.ClosePairqLCMS(p1, p2, magFieldTesla, femto_universe_container::EventType::mixed, kv); + } break; } + default: break; } } } + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param subscribe to the femtoUniverseParticleTable + void processMixedEventCent(FilteredFDCollisions const& cols, + FilteredFemtoFullParticles 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; + } + + 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, 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, 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, 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 processMixedEvent(soa::Filtered& cols, - FilteredFemtoFullParticles& parts) + void processMixedEventNtr(FilteredFDCollisions const& cols, + FilteredFemtoFullParticles const&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + 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(); @@ -643,55 +1136,81 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { 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); + doMixedEvent(groupPartsOne, groupPartsTwo, 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); + doMixedEvent(groupPartsOne, groupPartsTwo, 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); + doMixedEvent(groupPartsOne, groupPartsTwo, 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& /*col*/, - FilteredFemtoFullParticles& /*parts*/) + /// 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&, + o2::aod::FdMCParticles const&) { - int JMax = (ConfLMax + 1) * (ConfLMax + 1); - if (cfgProcessMM) { - sameEventMultContMM.fill_mult_kT_Cov(femtoUniverseSHContainer::EventType::same, JMax); - mixedEventMultContMM.fill_mult_kT_Cov(femtoUniverseSHContainer::EventType::mixed, JMax); - } else if (cfgProcessPP) { - sameEventMultContPP.fill_mult_kT_Cov(femtoUniverseSHContainer::EventType::same, JMax); - mixedEventMultContPP.fill_mult_kT_Cov(femtoUniverseSHContainer::EventType::mixed, JMax); - } else if (cfgProcessPM) { - sameEventMultCont.fill_mult_kT_Cov(femtoUniverseSHContainer::EventType::same, JMax); - mixedEventMultCont.fill_mult_kT_Cov(femtoUniverseSHContainer::EventType::mixed, JMax); + 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, 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, 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, magFieldTesla1, multiplicityCol, 3); + } } + delete randgen; } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processCov, "Enable processing same event covariance", true); - - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEvent, "Enable processing mixed events", true); + 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 processMixedEventMC(o2::aod::FDCollisions& cols, - soa::Join& /*parts*/, - o2::aod::FDMCParticles&) + void processMixedEventMCNtr(o2::aod::FdCollisions const& cols, + soa::Join const&, + o2::aod::FdMCParticles const&) { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + randgen = new TRandom2(0); - const int multiplicityCol = collision1.multNtr(); - MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision1.posZ(), multiplicityCol})); + 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(); @@ -701,9 +1220,126 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { } /// \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, 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, 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, magFieldTesla1, multiplicityCol, 3); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventMCNtr, "Enable processing mixed events MC", 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 doMixedEventMCTruth(PartitionType groupPartsOne, PartitionType groupPartsTwo, int multCol, int ContType) + { + randgen = new TRandom2(0); + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + + int pdgCodePartOne = static_cast(p1.tempFitVar()); + const auto& pdgParticleOne = pdg->GetParticle(pdgCodePartOne); + int pdgCodePartTwo = static_cast(p2.tempFitVar()); + const auto& pdgParticleTwo = pdg->GetParticle(pdgCodePartTwo); + + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + double rand; + rand = randgen->Rndm(); + if (pdgParticleOne && pdgParticleTwo && (pdgCodePartOne == trackonefilter.ConfPDGCodePartOne) && (pdgCodePartTwo == tracktwofilter.ConfPDGCodePartTwo)) { + + 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; + } + } + } + delete randgen; + } + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoUniverseParticleTable + void processMixedEventNtrMCTruth(o2::aod::FdCollisions const& cols, + FemtoTruthParticles const&) + { + int pairType = 0; + if (cfgProcessPM) { + pairType = 1; + } else if (cfgProcessPP) { + pairType = 2; + } else if (cfgProcessMM) { + pairType = 3; + } + + 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})); + + if (cfgProcessPM) { + auto groupPartsOne = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEventMCTruth(groupPartsOne, groupPartsTwo, multiplicityCol, pairType); + } + if (cfgProcessPP) { + auto groupPartsOne = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEventMCTruth(groupPartsOne, groupPartsTwo, multiplicityCol, pairType); + } + if (cfgProcessMM) { + auto groupPartsOne = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEventMCTruth(groupPartsOne, groupPartsTwo, multiplicityCol, pairType); + } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventMC, "Enable processing mixed events MC", false); + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventNtrMCTruth, "Enable processing MC Truth mixed events for multiplicity", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx index 0ee00ad8dd6..f158b23b726 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -9,36 +9,43 @@ // 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 "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 "PWGCF/FemtoUniverse/Core/FemtoUniverseEfficiencyCorrection.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" #include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +#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; +using namespace o2::analysis::femto_universe::efficiency_correction; -struct femtoUniversePairTaskTrackV0Extended { +struct FemtoUniversePairTaskTrackV0Extended { Service pdgMC; @@ -46,48 +53,58 @@ struct femtoUniversePairTaskTrackV0Extended { 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"}; + 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"}; - - Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZVertexCut); - using FilteredFDCollisions = soa::Filtered; + 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) && (nabs(aod::femtouniverseparticle::eta) < ConfEta) && (aod::femtouniverseparticle::pt < ConfHPtPart1) && (aod::femtouniverseparticle::pt > ConfLPtPart1); + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(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 == as(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"}; - Configurable ConfV0InvMassLowLimit{"ConfV0InvV0MassLowLimit", 1.10, "Lower limit of the V0 invariant mass"}; - Configurable ConfV0InvMassUpLimit{"ConfV0InvV0MassUpLimit", 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"}; + struct : o2::framework::ConfigurableGroup { + Configurable confV0PDGCodePartTwo{"confV0PDGCodePartTwo", 3122, "Particle 2 (V0) - PDG code"}; + 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"}; + } ConfV0Selection; + + 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 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; @@ -105,36 +122,39 @@ 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"}; - 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"}; - 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)"}; - - /// MC - - Configurable ConfHPtMC{"ConfHPtMC", 4.0f, "higher limit for pt"}; - Configurable ConfLPtMC{"ConfLPtMC", 0.3f, "lower limit for pt"}; - - 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 confRectV0V0CPR{"confRectV0V0CPR", true, "Enable rectangular CPR cut for V0-V0 pairs"}; + 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"}; + + EffCorConfigurableGroup effCorConfGroup; + EfficiencyCorrection effCorrection{&effCorConfGroup}; + + 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; @@ -145,34 +165,30 @@ struct femtoUniversePairTaskTrackV0Extended { HistogramRegistry registryMCtruth{"MCtruthHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; HistogramRegistry registryMCreco{"MCrecoHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - bool IsNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle) + std::unique_ptr plocalEffFile; + std::unique_ptr plocalEffp1; + std::unique_ptr plocalEffp2; + + 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)) { + 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; @@ -180,42 +196,48 @@ 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 tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::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())}; + const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::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())}; + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::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, true); - posChildHistos.init(&qaRegistry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, 0, true); - negChildHistos.init(&qaRegistry, ConfChildTempFitVarpTBins, ConfChildTempFitVarBins, false, 0, true); - - 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"); + 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, ConfV0Selection.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, ConfV0Selection.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, ConfV0Selection.confV0PDGCodePartTwo, true, "V0Type2"); + posChildV0Type2.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "posChildV0Type2"); + negChildV0Type2.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "negChildV0Type2"); + + qaRegistry.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}}}); @@ -235,6 +257,8 @@ struct femtoUniversePairTaskTrackV0Extended { 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("mothersTruth/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}}}); @@ -257,37 +281,55 @@ struct femtoUniversePairTaskTrackV0Extended { 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}}}); - 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); + registryMCreco.add("mothersReco/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, ConfV0Selection.confV0PDGCodePartTwo); + mixedEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventCont.setPDGCodes(confTrkPDGCodePartOne, ConfV0Selection.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 = (ConfV0Selection.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 = (ConfV0Selection.confV0Type1 == 0) ? std::unique_ptr(plocalEffFile.get()->Get("Lambda")) : std::unique_ptr(plocalEffFile.get()->Get("AntiLambda")); + plocalEffp2 = (ConfV0Selection.confV0Type2 == 0) ? std::unique_ptr(plocalEffFile.get()->Get("Lambda")) : std::unique_ptr(plocalEffFile.get()->Get("AntiLambda")); + LOGF(info, "Loaded efficiency histograms for V0-V0."); + } + } + + effCorrection.init(&qaRegistry, {static_cast(confV0TempFitVarpTBins), {confEtaBins, -2, 2}, confMultBins}); } /// This function processes the same event for track - V0 - void processSameEvent(FilteredFDCollision& 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 = ConfUseCent ? col.multV0M() : 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[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) continue; trackHistoPartTwo.fillQA(part); @@ -295,291 +337,786 @@ struct femtoUniversePairTaskTrackV0Extended { 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())}; + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; + const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::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[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.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(FilteredFDCollision& 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 = ConfUseCent ? col.multV0M() : 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])) { + if (isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) && isParticleTPC(negChild, V0ChildTable[ConfV0Selection.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()); + if constexpr (isMC) { + effCorrection.fillRecoHist(part, kLambda0); + } } /// Check daughters of second V0 particle - if (IsParticleTPC(posChild, V0ChildTable[ConfV0Type2][0]) && IsParticleTPC(negChild, V0ChildTable[ConfV0Type2][1])) { + if (isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type2][0]) && isParticleTPC(negChild, V0ChildTable[ConfV0Selection.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()); + if constexpr (isMC) { + effCorrection.fillRecoHist(part, kLambda0Bar); + } } } - /// Now build the combinations - for (auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsTwo, groupPartsTwo))) { + auto pairProcessFunc = [&](auto& p1, auto& p2) -> void { // Lambda invariant mass cut for p1 if (!invMLambda(p1.mLambda(), p1.mAntiLambda())) - continue; + return; // Lambda invariant mass cut for p2 if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) - continue; + 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 (confRectV0V0CPR && pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + return; + } else if (!confRectV0V0CPR && 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[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.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[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) + return; + + if constexpr (std::is_same::value) + sameEventCont.setPair(p1, p2, multCol, confUse3D); + else + sameEventCont.setPair(p1, p2, multCol, confUse3D); + }; + + if (ConfV0Selection.confV0Type1 == ConfV0Selection.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 ((ConfV0Selection.confV0Type1 == 0 && pdgCode != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode != kLambda0Bar)) continue; + trackHistoPartTwo.fillQA(part); + } - sameEventCont.setPair(p1, p2, multCol, ConfUse3D); + 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 ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.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); } } - PROCESS_SWITCH(femtoUniversePairTaskTrackV0Extended, processSameEventV0, "Enable processing same event for V0 - V0", false); + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMCSameEvent, "Enable processing same event for MC truth track - V0", false); - /// This function processes the mixed event for track - V0 - void processMixedEvent(FilteredFDCollisions& cols, FemtoFullParticles& parts) + /// This function processes MC same events for V0 - V0 + void processMCSameEventV0(FilteredFDCollision const& col, FemtoFullParticles const& parts) { - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; + 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 ((ConfV0Selection.confV0Type1 == 0 && pdgCode == kLambda0) || (ConfV0Selection.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()); + effCorrection.fillTruthHist(part); + } + if ((ConfV0Selection.confV0Type2 == 0 && pdgCode == kLambda0) || (ConfV0Selection.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()); + effCorrection.fillTruthHist(part); + } + } - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + auto pairProcessFunc = [&](auto& p1, auto& p2) -> void { + int pdgCode1 = static_cast(p1.pidCut()); + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + return; + int pdgCode2 = static_cast(p2.pidCut()); + if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + return; + sameEventCont.setPair(p1, p2, multCol, confUse3D); + }; + /// Now build the combinations + if (ConfV0Selection.confV0Type1 == ConfV0Selection.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, processMCSameEventV0, "Enable processing same event for MC truth V0 - V0", false); + + /// This function processes the mixed event for track - V0 + template + void doMixedEvent(FilteredFDCollisions const& cols, PartType const& parts, PartitionType& partitionOne, PartitionType& partitionTwo, [[maybe_unused]] MCParticles mcParts = nullptr) + { + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; - const int multCol = ConfUseCent ? collision1.multV0M() : collision1.multNtr(); + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + 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); + 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[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.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)) - 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; + 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); + } + }; - mixedEventCont.setPair(p1, p2, multCol, ConfUse3D); + if (confUseCent) { + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningCent, confNEventsMix, -1, cols, cols)) { + mixedCollProcessFunc(collision1, collision2); + qaRegistry.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); + qaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), collision1.multNtr()})); } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackV0Extended, processMixedEvent, "Enable processing mixed events for track - V0", false); - /// This function processes the mixed event for V0 - V0 - void processMixedEventV0(FilteredFDCollisions& cols, FemtoFullParticles& parts) + template + void doMixedEventV0(FilteredFDCollisions const& cols, PartType const& parts, PartitionType& partitionTwo, [[maybe_unused]] MCParticles mcParts = nullptr) { - ColumnBinningPolicy colBinning{{ConfVtxBins, ConfMultBins}, true}; - - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + ColumnBinningPolicy colBinningMult{{confVtxBins, confMultBins}, true}; + ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; - const int multCol = ConfUseCent ? collision1.multV0M() : 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 = 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) { - continue; + return; } - for (auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { // Lambda invariant mass cut for p1 - if (!invMLambda(p1.mLambda(), p1.mAntiLambda())) + if (!invMLambda(p1.mLambda(), p1.mAntiLambda())) { continue; + } // Lambda invariant mass cut for p2 - if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) - continue; - // track cleaning - if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { + if (!invMLambda(p2.mLambda(), p2.mAntiLambda())) { continue; } - if (ConfIsCPR.value) { - if (pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla1, femtoUniverseContainer::EventType::mixed)) { - 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[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) continue; 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[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) continue; - mixedEventCont.setPair(p1, p2, multCol, ConfUse3D); + // track cleaning + if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (confRectV0V0CPR && pairCloseRejectionV0.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } else if (!confRectV0V0CPR && 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); + qaRegistry.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); + qaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), collision1.multNtr()})); } } } - PROCESS_SWITCH(femtoUniversePairTaskTrackV0Extended, processMixedEventV0, "Enable processing mixed events for V0 - 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); + + 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); - ///--------------------------------------------MC-------------------------------------------------/// + void processMixedEventV0(FilteredFDCollisions const& cols, FemtoFullParticles const& parts) + { + doMixedEventV0(cols, parts, partsTwo); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Extended, processMixedEventV0, "Enable processing mixed events for V0 - V0", false); + + 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}; + + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + + 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 ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.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); + qaRegistry.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); + qaRegistry.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}; - using FemtoRecoParticles = soa::Join; + 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 ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.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); + qaRegistry.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); + qaRegistry.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 (auto& part : parts) { - if (!(part.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack))) - continue; - if (TMath::Abs(part.eta()) > ConfEta || part.pt() < ConfLPtMC || part.pt() > ConfHPtMC) + for (const auto& part : parts) { + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) continue; - int pdgCode = static_cast(part.pidcut()); + int pdgCode = static_cast(part.pidCut()); const auto& pdgParticle = pdgMC->GetParticle(pdgCode); if (!pdgParticle) { continue; } - if (pdgCode == 3122) { + if (pdgCode == kLambda0) { registryMCtruth.fill(HIST("plus/MCtruthLambda"), part.pt(), part.eta()); continue; - } else if (pdgCode == -3122) { + } else if (pdgCode == kLambda0Bar) { registryMCtruth.fill(HIST("minus/MCtruthLambda"), part.pt(), part.eta()); continue; } - if (pdgParticle->Charge() > 0) { + if (pdgParticle->Charge() > 0.0) { registryMCtruth.fill(HIST("plus/MCtruthAllPt"), part.pt()); } - if (pdgCode == 211) { + if (pdgCode == kPiPlus) { registryMCtruth.fill(HIST("plus/MCtruthPi"), part.pt(), part.eta()); registryMCtruth.fill(HIST("plus/MCtruthPiPt"), part.pt()); } - if (pdgCode == 2212) { + if (pdgCode == kProton) { registryMCtruth.fill(HIST("plus/MCtruthPr"), part.pt(), part.eta()); registryMCtruth.fill(HIST("plus/MCtruthPrPt"), part.pt()); } - if (pdgParticle->Charge() < 0) { + if (pdgParticle->Charge() < 0.0) { registryMCtruth.fill(HIST("minus/MCtruthAllPt"), part.pt()); } - if (pdgCode == -211) { + if (pdgCode == kPiMinus) { registryMCtruth.fill(HIST("minus/MCtruthPi"), part.pt(), part.eta()); registryMCtruth.fill(HIST("minus/MCtruthPiPt"), part.pt()); } - if (pdgCode == -2212) { + 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); + 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 (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[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + continue; + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } + } + registryMCreco.fill(HIST("mothersReco/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[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + continue; + + 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[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.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; + } + } + + registryMCreco.fill(HIST("mothersReco/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 processPairFractionsMCTruth(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 = partsOneMC->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()); + int pdgCode2 = static_cast(p2.pidCut()); + + if (pdgCode1 != confTrkPDGCodePartOne) + continue; + if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) + continue; + + registryMCtruth.fill(HIST("mothersTruth/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, processPairFractionsMCTruth, "Process MC data to obtain pair fractions for MC truth 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 ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + continue; + + registryMCtruth.fill(HIST("mothersTruth/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) + void processMCReco(FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) { - for (auto& part : parts) { + 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() == 3122) { + 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)) { + 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); @@ -590,11 +1127,11 @@ struct femtoUniversePairTaskTrackV0Extended { registryMCreco.fill(HIST("plus/MCrecoLambdaChildPi"), mcpartChild.pt(), mcpartChild.eta()); // lambda pion child } } - } else if (mcpart.pdgMCTruth() == -3122) { + } 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)) { + 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); @@ -609,10 +1146,10 @@ struct femtoUniversePairTaskTrackV0Extended { } else if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { if (part.sign() > 0) { registryMCreco.fill(HIST("plus/MCrecoAllPt"), mcpart.pt()); - if (mcpart.pdgMCTruth() == 211 && IsNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tofNSigmaStorePi()))) { + if (mcpart.pdgMCTruth() == kPiPlus && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()))) { registryMCreco.fill(HIST("plus/MCrecoPi"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("plus/MCrecoPiPt"), mcpart.pt()); - } else if (mcpart.pdgMCTruth() == 2212 && IsNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePr()))) { + } else if (mcpart.pdgMCTruth() == kProton && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) { registryMCreco.fill(HIST("plus/MCrecoPr"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("plus/MCrecoPrPt"), mcpart.pt()); } @@ -620,10 +1157,10 @@ struct femtoUniversePairTaskTrackV0Extended { if (part.sign() < 0) { registryMCreco.fill(HIST("minus/MCrecoAllPt"), mcpart.pt()); - if (mcpart.pdgMCTruth() == -211 && IsNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePi()), unPackInTable(part.tofNSigmaStorePi()))) { + if (mcpart.pdgMCTruth() == kPiMinus && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()))) { registryMCreco.fill(HIST("minus/MCrecoPi"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("minus/MCrecoPiPt"), mcpart.pt()); - } else if (mcpart.pdgMCTruth() == -2212 && IsNSigmaCombined(part.p(), unPackInTable(part.tpcNSigmaStorePr()), unPackInTable(part.tofNSigmaStorePr()))) { + } else if (mcpart.pdgMCTruth() == kProtonBar && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) { registryMCreco.fill(HIST("minus/MCrecoPr"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("minus/MCrecoPrPt"), mcpart.pt()); } @@ -632,13 +1169,13 @@ struct femtoUniversePairTaskTrackV0Extended { } } - PROCESS_SWITCH(femtoUniversePairTaskTrackV0Extended, processMCReco, "Process MC reco data", 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/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Helicity.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Helicity.cxx new file mode 100644 index 00000000000..afee000d7d6 --- /dev/null +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Helicity.cxx @@ -0,0 +1,1191 @@ +// 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 femtoUniversePairTaskTrackV0Helicity.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 +/// \author Anna-Mariia Andrushko, WUT Warsaw, anna-mariia.andrushko@cern.ch + +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseMath.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +#include +#include +#include + +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; +using namespace o2::track; + +struct FemtoUniversePairTaskTrackV0Helicity { + + Service pdg; + Service pdgMC; + + SliceCache cache; + + using FemtoFullParticles = soa::Join; + Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + + using FemtoRecoParticles = soa::Join; + Preslice perColMC = aod::femtouniverseparticle::fdCollisionId; + + using FemtoTruthParticles = soa::Join; + Preslice perColMCTruth = aod::femtouniverseparticle::fdCollisionId; + + /// To apply a narrow cut + Configurable confZVertexCut{"confZVertexCut", 10.f, "Event selection -- maximum z-vertex (cm)"}; + Configurable confEta{"confEta", 0.8, "Eta cut for the global track"}; + + /// Particle 1 (track) + struct : o2::framework::ConfigurableGroup { + 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}, "TempFitVar binning in the pT vs. TempFitVar plot"}; + ConfigurableAxis confTrkTempFitVarpTBins{"confTrkTempFitVarpTBins", {20, 0.5, 4.05}, "pT binning in the pT vs. TempFitVar plot"}; + Configurable confChargePart1{"confChargePart1", 0, "Particle 1 sign"}; + Configurable confHPtPart1{"confHPtPart1", 4.0f, "Particle 1 pT higher limit"}; + Configurable confLPtPart1{"confLPtPart1", 0.3f, "Particle 1 pT lower limit"}; + Configurable confTOFmom{"confTOFmom", 0.5, "Momentum threshold for particle identification using TOF"}; + Configurable confNsigmaTPCParticle{"confNsigmaTPCParticle", 3.0, "TPC nSigma for particle momentum < confTOFmom"}; + Configurable confNsigmaCombinedParticle{"confNsigmaCombinedParticle", 3.0, "TPC and TOF nSigma (combined) for particle momentum > confTOFmom"}; + } trackconfigs; + + Filter collisionFilter = (nabs(aod::collision::posZ) < confZVertexCut); + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; + + /// Partitioning for particle 1 + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == trackconfigs.confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < trackconfigs.confHPtPart1) && (aod::femtouniverseparticle::pt > trackconfigs.confLPtPart1); + Partition partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < trackconfigs.confHPtPart1) && (aod::femtouniverseparticle::pt > trackconfigs.confLPtPart1); + Partition partsOneMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == trackconfigs.confChargePart1) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < trackconfigs.confHPtPart1) && (aod::femtouniverseparticle::pt > trackconfigs.confLPtPart1); + + /// Histogramming for particle 1 + FemtoUniverseParticleHisto trackHistoPartOnePos; + FemtoUniverseParticleHisto trackHistoPartOneNeg; + + /// Particle 2 (V0) + struct : o2::framework::ConfigurableGroup { + Configurable confV0PDGCodePartTwo{"confV0PDGCodePartTwo", 3122, "Particle 2 (V0) -- PDG code"}; + ConfigurableAxis confV0TempFitVarBins{"confV0TempFitVarBins", {300, 0.95, 1.}, "V0: TempFitVar binning in the pT vs. TempFitVar plot"}; + ConfigurableAxis confV0TempFitVarpTBins{"confV0TempFitVarpTBins", {20, 0.5, 4.05}, "V0: pT binning in the pT vs. TempFitVar plot"}; + Configurable confV0Type1{"confV0Type1", 0, "Select V0 (Lambda = 0, Anti-lambda = 1, K0 = 2) for Track-V0 and V0-V0 combinations"}; + Configurable confV0Type2{"confV0Type2", 0, "Select V0 (Lambda = 0, Anti-lambda = 1, K0 = 2) for V0-V0 combinations"}; + Configurable confV0InvMassLowLimit{"confV0InvMassLowLimit", 1.10, "Invariant mass lower limit"}; + Configurable confV0InvMassUpLimit{"confV0InvMassUpLimit", 1.13, "Invariant mass upper limit"}; + ConfigurableAxis confChildTempFitVarBins{"confChildTempFitVarBins", {300, -0.15, 0.15}, "V0 child: TempFitVar binning in the pT vs. TempFitVar plot"}; + ConfigurableAxis confChildTempFitVarpTBins{"confChildTempFitVarpTBins", {20, 0.5, 4.05}, "V0 child: pT binning in the pT vs. TempFitVar plot"}; + Configurable confHPtPart2{"confHPtPart2", 4.0f, "Particle 2 pT higher limit"}; + Configurable confLPtPart2{"confLPtPart2", 0.3f, "Particle 2 pT higher limit"}; + Configurable confPDGCodeV0{"confPDGCodeV0", 3122, "V0 -- PDG code"}; + Configurable confPDGCodePosChild{"confPDGCodePosChild", 2212, "Positive Child -- PDG code"}; + Configurable confPDGCodeNegChild{"confPDGCodeNegChild", 211, "Negative Child -- PDG code"}; + } V0configs; + + /// Partitioning for particle 2 + Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < V0configs.confHPtPart2) && (aod::femtouniverseparticle::pt > V0configs.confLPtPart2); + Partition partsTwoMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pt < V0configs.confHPtPart2) && (aod::femtouniverseparticle::pt > V0configs.confLPtPart2); + Partition partsTwoMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < V0configs.confHPtPart2) && (aod::femtouniverseparticle::pt > V0configs.confLPtPart2); + Partition partsTwoMCTruth = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pt < V0configs.confHPtPart2) && (aod::femtouniverseparticle::pt > V0configs.confLPtPart2); + + /// Histogramming for particle 2 + /// Track-V0 + FemtoUniverseParticleHisto trackHistoPartTwo; + FemtoUniverseParticleHisto posChildHistos; + FemtoUniverseParticleHisto negChildHistos; + + /// V0-V0 + FemtoUniverseParticleHisto trackHistoV0Type1; + FemtoUniverseParticleHisto posChildV0Type1; + FemtoUniverseParticleHisto negChildV0Type1; + FemtoUniverseParticleHisto trackHistoV0Type2; + FemtoUniverseParticleHisto posChildV0Type2; + FemtoUniverseParticleHisto negChildV0Type2; + + /// Histogramming for event + FemtoUniverseEventHisto eventHisto; + + /// Correlation part + // Configurable confTrackChoicePartTwo{"confTrackChoicePartTwo", 1, "0: Proton, 1: Pion, 2: Kaon"}; // not used + Configurable confIsMC{"confIsMC", false, "Enable additional histograms in the case of Monte Carlo data"}; + 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.}, "k* binning"}; + ConfigurableAxis confkTBins{"confkTBins", {150, 0., 9.}, "kT binning"}; + ConfigurableAxis confmTBins{"confmTBins", {225, 0., 7.5}, "mT binning"}; + 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 CPR"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for CPR"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for CPR"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for CPR"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for CPR"}; + 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 3D 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 3D plot: k* vs multiplicity vs mT (set to true in order to use)"}; + + /// Helicity ranges (approximate) + Configurable cfgProcessHel{"cfgProcessHel", true, "Process particle pairs from all helicity ranges"}; + Configurable cfgProcessHel1{"cfgProcessHel1", false, "Process particle pairs from the helicity range 1"}; // 1.0 > cosineTheta >= 0.1 + Configurable cfgProcessHel2{"cfgProcessHel2", false, "Process particle pairs from the helicity range 2"}; // 0.1 > cosineTheta >= -0.1 + Configurable cfgProcessHel3{"cfgProcessHel3", false, "Process particle pairs from the helicity range 3"}; // -0.1 > cosineTheta >= -0.5 + Configurable cfgProcessHel4{"cfgProcessHel4", false, "Process particle pairs from the helicity range 4"}; // -0.5 > cosineTheta >= -1.0 + + /// 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 V0 children + + /// Containers + FemtoUniverseContainer sameEventCont; + FemtoUniverseContainer mixedEventCont; + + FemtoUniverseContainer sameEventContHel1; + FemtoUniverseContainer mixedEventContHel1; + + FemtoUniverseContainer sameEventContHel2; + FemtoUniverseContainer mixedEventContHel2; + + FemtoUniverseContainer sameEventContHel3; + FemtoUniverseContainer mixedEventContHel3; + + FemtoUniverseContainer sameEventContHel4; + FemtoUniverseContainer mixedEventContHel4; + + FemtoUniversePairCleaner pairCleaner; + FemtoUniversePairCleaner pairCleanerV0; + + FemtoUniverseDetaDphiStar pairCloseRejection; + FemtoUniverseDetaDphiStar pairCloseRejectionV0; + + /// Histogram output + HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry thetaRegistry{"ThetaQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryMCtruth{"MCtruthHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry registryMCreco{"MCrecoHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryHel1{"CorrelationsHel1", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryHel2{"CorrelationsHel2", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryHel3{"CorrelationsHel3", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry resultRegistryHel4{"CorrelationsHel4", {}, OutputObjHandlingPolicy::AnalysisObject, true, 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) + { + if (mom <= trackconfigs.confTOFmom) { + return (std::abs(nsigmaTPCParticle) < trackconfigs.confNsigmaTPCParticle); + } else { + return (std::hypot(nsigmaTOFParticle, nsigmaTPCParticle) < trackconfigs.confNsigmaCombinedParticle); + } + } + + bool invMLambda(float invMassLambda, float invMassAntiLambda) + { + if ((invMassLambda < V0configs.confV0InvMassLowLimit || invMassLambda > V0configs.confV0InvMassUpLimit) && (invMassAntiLambda < V0configs.confV0InvMassLowLimit || invMassAntiLambda > V0configs.confV0InvMassUpLimit)) { + return false; + } + return true; + } + + bool isNSigmaTPC(float nsigmaTPCParticle) + { + if (std::abs(nsigmaTPCParticle) < trackconfigs.confNsigmaTPCParticle) { + return true; + } else { + return false; + } + } + + template + bool isParticleCombined(const T& part, int id) + { + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; + // const float tofNSigmas[3] = {part.tofNSigmaPr(), part.tofNSigmaPi(), part.tofNSigmaKa()}; + const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; + + return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id]); + } + + template + bool isParticleTPC(const T& part, int id) + { + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; + + 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}, {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}}); + + /// Track-V0 + trackHistoPartOnePos.init(&qaRegistry, trackconfigs.confTrkTempFitVarpTBins, trackconfigs.confTrkTempFitVarBins, confIsMC, trackconfigs.confTrkPDGCodePartOne); + trackHistoPartOneNeg.init(&qaRegistry, trackconfigs.confTrkTempFitVarpTBins, trackconfigs.confTrkTempFitVarBins, confIsMC, trackconfigs.confTrkPDGCodePartOne); + trackHistoPartTwo.init(&qaRegistry, V0configs.confV0TempFitVarpTBins, V0configs.confV0TempFitVarBins, confIsMC, V0configs.confV0PDGCodePartTwo, true); + posChildHistos.init(&qaRegistry, V0configs.confChildTempFitVarpTBins, V0configs.confChildTempFitVarBins, false, 0, true); + negChildHistos.init(&qaRegistry, V0configs.confChildTempFitVarpTBins, V0configs.confChildTempFitVarBins, false, 0, true); + + /// V0-V0 + trackHistoV0Type1.init(&qaRegistry, V0configs.confV0TempFitVarpTBins, V0configs.confV0TempFitVarBins, confIsMC, V0configs.confV0PDGCodePartTwo, true, "V0Type1"); + posChildV0Type1.init(&qaRegistry, V0configs.confChildTempFitVarpTBins, V0configs.confChildTempFitVarBins, false, 0, true, "posChildV0Type1"); + negChildV0Type1.init(&qaRegistry, V0configs.confChildTempFitVarpTBins, V0configs.confChildTempFitVarBins, false, 0, true, "negChildV0Type1"); + trackHistoV0Type2.init(&qaRegistry, V0configs.confV0TempFitVarpTBins, V0configs.confV0TempFitVarBins, confIsMC, V0configs.confV0PDGCodePartTwo, true, "V0Type2"); + posChildV0Type2.init(&qaRegistry, V0configs.confChildTempFitVarpTBins, V0configs.confChildTempFitVarBins, false, 0, true, "posChildV0Type2"); + negChildV0Type2.init(&qaRegistry, V0configs.confChildTempFitVarpTBins, V0configs.confChildTempFitVarBins, false, 0, true, "negChildV0Type2"); + + /// Helicity angle + thetaRegistry.add("Theta/hTheta", " ; p (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/hTheta3D_PosChild", " ; p_{V0} (GeV/#it{c}); cos(#theta); p_{Positive Child} (GeV/#it{c})", kTH3F, {{100, 0, 10}, {110, -1.1, 1.1}, {100, 0, 10}}); + thetaRegistry.add("Theta/hTheta3D_NegChild", " ; p_{V0} (GeV/#it{c}); cos(#theta); p_{Negative Child} (GeV/#it{c})", kTH3F, {{100, 0, 10}, {110, -1.1, 1.1}, {100, 0, 10}}); + thetaRegistry.add("Theta/PositiveChild/hThetaPt", " ; p_{T} (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/PositiveChild/hThetaEta", " ; #eta; cos(#theta)", kTH2F, {{100, -1, 1}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/PositiveChild/hThetaPhi", " ; #phi; cos(#theta)", kTH2F, {{100, -1, 7}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/NegativeChild/hThetaPt", " ; p_{T} (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/NegativeChild/hThetaEta", " ; #eta; cos(#theta)", kTH2F, {{100, -1, 1}, {110, -1.1, 1.1}}); + thetaRegistry.add("Theta/NegativeChild/hThetaPhi", " ; #phi; cos(#theta)", kTH2F, {{100, -1, 7}, {110, -1.1, 1.1}}); + + /// 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("PosChildMCTruth/hPt", " ; p_{T} (GeV/#it{c}); ", {HistType::kTH1F, {{100, 0, 5}}}); + registryMCtruth.add("NegChildMCTruth/hPt", " ; p_{T} (GeV/#it{c}); ", {HistType::kTH1F, {{100, 0, 5}}}); + + registryMCtruth.add("ThetaMCTruth/hTheta", " ; p (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + registryMCtruth.add("ThetaMCTruth/hTheta3D_PosChild", " ; p_{V0} (GeV/#it{c}); cos(#theta); p_{Positive Child} (GeV/#it{c})", kTH3F, {{100, 0, 10}, {110, -1.1, 1.1}, {100, 0, 10}}); + registryMCtruth.add("ThetaMCTruth/hTheta3D_NegChild", " ; p_{V0} (GeV/#it{c}); cos(#theta); p_{Negative Child} (GeV/#it{c})", kTH3F, {{100, 0, 10}, {110, -1.1, 1.1}, {100, 0, 10}}); + registryMCtruth.add("ThetaMCTruth/PositiveChild/hThetaPt", " ; p_{T} (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + registryMCtruth.add("ThetaMCTruth/PositiveChild/hThetaEta", " ; #eta; cos(#theta)", kTH2F, {{100, -1, 1}, {110, -1.1, 1.1}}); + registryMCtruth.add("ThetaMCTruth/PositiveChild/hThetaPhi", " ; #phi; cos(#theta)", kTH2F, {{100, -1, 7}, {110, -1.1, 1.1}}); + registryMCtruth.add("ThetaMCTruth/NegativeChild/hThetaPt", " ; p_{T} (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + registryMCtruth.add("ThetaMCTruth/NegativeChild/hThetaEta", " ; #eta; cos(#theta)", kTH2F, {{100, -1, 1}, {110, -1.1, 1.1}}); + registryMCtruth.add("ThetaMCTruth/NegativeChild/hThetaPhi", " ; #phi; cos(#theta)", kTH2F, {{100, -1, 7}, {110, -1.1, 1.1}}); + + /// 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("ThetaMCReco/hTheta", " ; p (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + registryMCreco.add("ThetaMCReco/PositiveChild/hThetaPt", " ; p_{T} (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + registryMCreco.add("ThetaMCReco/PositiveChild/hThetaEta", " ; #eta; cos(#theta)", kTH2F, {{100, -1, 1}, {110, -1.1, 1.1}}); + registryMCreco.add("ThetaMCReco/PositiveChild/hThetaPhi", " ; #phi; cos(#theta)", kTH2F, {{100, -1, 7}, {110, -1.1, 1.1}}); + registryMCreco.add("ThetaMCReco/NegativeChild/hThetaPt", " ; p_{T} (GeV/#it{c}); cos(#theta)", kTH2F, {{100, 0, 10}, {110, -1.1, 1.1}}); + registryMCreco.add("ThetaMCReco/NegativeChild/hThetaEta", " ; #eta; cos(#theta)", kTH2F, {{100, -1, 1}, {110, -1.1, 1.1}}); + registryMCreco.add("ThetaMCReco/NegativeChild/hThetaPhi", " ; #phi; cos(#theta)", kTH2F, {{100, -1, 7}, {110, -1.1, 1.1}}); + + /// Correlations + if (cfgProcessHel) { + sameEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + sameEventCont.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + + mixedEventCont.init(&resultRegistry, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventCont.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + } + + if (cfgProcessHel1) { + sameEventContHel1.init(&resultRegistryHel1, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + sameEventContHel1.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + + mixedEventContHel1.init(&resultRegistryHel1, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventContHel1.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + } + + if (cfgProcessHel2) { + sameEventContHel2.init(&resultRegistryHel2, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + sameEventContHel2.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + + mixedEventContHel2.init(&resultRegistryHel2, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventContHel2.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + } + + if (cfgProcessHel3) { + sameEventContHel3.init(&resultRegistryHel3, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + sameEventContHel3.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + + mixedEventContHel3.init(&resultRegistryHel3, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventContHel3.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + } + + if (cfgProcessHel4) { + sameEventContHel4.init(&resultRegistryHel4, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + sameEventContHel4.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + + mixedEventContHel4.init(&resultRegistryHel4, confkstarBins, confMultBins, confkTBins, confmTBins, confMultBins3D, confmTBins3D, confEtaBins, confPhiBins, confIsMC, confUse3D); + mixedEventContHel4.setPDGCodes(trackconfigs.confTrkPDGCodePartOne, V0configs.confV0PDGCodePartTwo); + } + + mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); + + 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 (!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 = (trackconfigs.confChargePart1 > 0) ? std::unique_ptr(plocalEffFile.get()->Get("PrPlus")) : std::unique_ptr(plocalEffFile.get()->Get("PrMinus")); // note: works only for protons for now + plocalEffp2 = (V0configs.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 = (V0configs.confV0Type1 == 0) ? std::unique_ptr(plocalEffFile.get()->Get("Lambda")) : std::unique_ptr(plocalEffFile.get()->Get("AntiLambda")); + plocalEffp2 = (V0configs.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 + template + void doSameEvent(FilteredFDCollision const& col, PartType const& parts, PartitionType& groupPartsOne, PartitionType& groupPartsTwo, int helRange, [[maybe_unused]] MCParticles mcParts = nullptr) + { + const auto& magFieldTesla = col.magField(); + + const int multCol = confUseCent ? col.multV0M() : col.multNtr(); + + eventHisto.fillQA(col); + + /// Histogramming same event + 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[V0configs.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[V0configs.confV0Type1][1])) + continue; + + auto posChildMass = pdg->Mass(V0configs.confPDGCodePosChild); + auto negChildMass = pdg->Mass(V0configs.confPDGCodeNegChild); + auto posChildBoosted = FemtoUniverseMath::boostPRF(posChild, posChildMass, negChild, negChildMass); + auto cosineTheta = (posChildBoosted.Px() * part.px() + posChildBoosted.Py() * part.py() + posChildBoosted.Pz() * part.pz()) / (posChildBoosted.P() * part.p()); + + trackHistoPartTwo.fillQA(part); + posChildHistos.fillQA(posChild); + negChildHistos.fillQA(negChild); + + thetaRegistry.fill(HIST("Theta/hTheta"), part.p(), cosineTheta); + thetaRegistry.fill(HIST("Theta/hTheta3D_PosChild"), part.p(), cosineTheta, posChild.p()); + thetaRegistry.fill(HIST("Theta/hTheta3D_NegChild"), part.p(), cosineTheta, negChild.p()); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaPt"), posChild.pt(), cosineTheta); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaEta"), posChild.eta(), cosineTheta); + thetaRegistry.fill(HIST("Theta/PositiveChild/hThetaPhi"), posChild.phi(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaPt"), negChild.pt(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaEta"), negChild.eta(), cosineTheta); + thetaRegistry.fill(HIST("Theta/NegativeChild/hThetaPhi"), negChild.phi(), cosineTheta); + } + + for (const auto& part : groupPartsOne) { + /// PID plot for particle 1 + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; + const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; + + if (!isNSigmaCombined(part.p(), tpcNSigmas[trackconfigs.confTrackChoicePartOne], tofNSigmas[trackconfigs.confTrackChoicePartOne])) + continue; + if (part.sign() > 0) { + qaRegistry.fill(HIST("Tracks_pos/nSigmaTPC"), part.p(), tpcNSigmas[trackconfigs.confTrackChoicePartOne]); + qaRegistry.fill(HIST("Tracks_pos/nSigmaTOF"), part.p(), tofNSigmas[trackconfigs.confTrackChoicePartOne]); + trackHistoPartOnePos.fillQA(part); + } else if (part.sign() < 0) { + qaRegistry.fill(HIST("Tracks_neg/nSigmaTPC"), part.p(), tpcNSigmas[trackconfigs.confTrackChoicePartOne]); + qaRegistry.fill(HIST("Tracks_neg/nSigmaTOF"), part.p(), tofNSigmas[trackconfigs.confTrackChoicePartOne]); + trackHistoPartOneNeg.fillQA(part); + } + } + + /// Now build the combinations + 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, trackconfigs.confTrackChoicePartOne)) + continue; + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + 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[V0configs.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[V0configs.confV0Type1][1])) + continue; + + 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())); + + auto posChildMass = pdg->Mass(V0configs.confPDGCodePosChild); + auto negChildMass = pdg->Mass(V0configs.confPDGCodeNegChild); + auto posChildBoosted = FemtoUniverseMath::boostPRF(posChild, posChildMass, negChild, negChildMass); + auto cosineTheta = (posChildBoosted.Px() * p2.px() + posChildBoosted.Py() * p2.py() + posChildBoosted.Pz() * p2.pz()) / (posChildBoosted.P() * p2.p()); + + switch (helRange) { + case 0: { + if constexpr (std::is_same::value) + sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); + else + sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + case 1: { + if (cosineTheta < 1.0 && cosineTheta >= 0.1) + sameEventContHel1.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + case 2: { + if (cosineTheta < 0.1 && cosineTheta >= -0.1) + sameEventContHel2.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + case 3: { + if (cosineTheta < -0.1 && cosineTheta >= -0.5) + sameEventContHel3.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + case 4: { + if (cosineTheta < -0.5 && cosineTheta >= -1.0) + sameEventContHel4.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + default: + break; + } + } + } + + 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); + + if (cfgProcessHel) + doSameEvent(col, parts, groupPartsOne, groupPartsTwo, 0); + + if (cfgProcessHel1) + doSameEvent(col, parts, groupPartsOne, groupPartsTwo, 1); + + if (cfgProcessHel2) + doSameEvent(col, parts, groupPartsOne, groupPartsTwo, 2); + + if (cfgProcessHel3) + doSameEvent(col, parts, groupPartsOne, groupPartsTwo, 3); + + if (cfgProcessHel4) + doSameEvent(col, parts, groupPartsOne, groupPartsTwo, 4); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Helicity, 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, 0, mcparts); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Helicity, 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) + { + const auto& magFieldTesla = col.magField(); + + auto groupPartsTwo = partsTwo->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) { + 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[V0configs.confV0Type1][0]) && isParticleTPC(negChild, V0ChildTable[V0configs.confV0Type1][1])) { + trackHistoV0Type1.fillQABase(part, HIST("V0Type1")); + posChildV0Type1.fillQABase(posChild, HIST("posChildV0Type1")); + negChildV0Type1.fillQABase(negChild, HIST("negChildV0Type1")); + } + /// Check daughters of second V0 particle + if (isParticleTPC(posChild, V0ChildTable[V0configs.confV0Type2][0]) && isParticleTPC(negChild, V0ChildTable[V0configs.confV0Type2][1])) { + trackHistoV0Type2.fillQABase(part, HIST("V0Type2")); + posChildV0Type2.fillQABase(posChild, HIST("posChildV0Type2")); + negChildV0Type2.fillQABase(negChild, HIST("negChildV0Type2")); + } + } + + 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)) { + return; + } + 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[V0configs.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[V0configs.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[V0configs.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[V0configs.confV0Type2][1])) + return; + + sameEventCont.setPair(p1, p2, multCol, confUse3D); + }; + if (V0configs.confV0Type1 == V0configs.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(FemtoUniversePairTaskTrackV0Helicity, processSameEventV0, "Enable processing same event for V0 - V0", 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 ((V0configs.confV0Type1 == 0 && pdgCode != V0configs.confPDGCodeV0) || (V0configs.confV0Type1 == 1 && pdgCode != -V0configs.confPDGCodeV0)) + continue; + trackHistoPartTwo.fillQA(part); + } + + for (const auto& part : groupPartsOne) { + int pdgCode = static_cast(part.pidCut()); + if (pdgCode != trackconfigs.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()) != trackconfigs.confTrkPDGCodePartOne) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((V0configs.confV0Type1 == 0 && pdgCode2 != V0configs.confPDGCodeV0) || (V0configs.confV0Type1 == 1 && pdgCode2 != -V0configs.confPDGCodeV0)) + 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); + } + } + + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Helicity, 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) { + int pdgCode = static_cast(part.pidCut()); + if ((V0configs.confV0Type1 == 0 && pdgCode != V0configs.confPDGCodeV0) || (V0configs.confV0Type1 == 1 && pdgCode != -V0configs.confPDGCodeV0)) + continue; + trackHistoPartTwo.fillQA(part); + } + + auto pairProcessFunc = [&](auto& p1, auto& p2) -> void { + int pdgCode1 = static_cast(p1.pidCut()); + if ((V0configs.confV0Type1 == 0 && pdgCode1 != V0configs.confPDGCodeV0) || (V0configs.confV0Type1 == 1 && pdgCode1 != -V0configs.confPDGCodeV0)) + return; + int pdgCode2 = static_cast(p2.pidCut()); + if ((V0configs.confV0Type2 == 0 && pdgCode2 != V0configs.confPDGCodeV0) || (V0configs.confV0Type2 == 1 && pdgCode2 != -V0configs.confPDGCodeV0)) + return; + sameEventCont.setPair(p1, p2, multCol, confUse3D); + }; + /// Now build the combinations + if (V0configs.confV0Type1 == V0configs.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(FemtoUniversePairTaskTrackV0Helicity, processMCSameEventV0, "Enable processing same event for MC truth V0 - V0", false); + + /// This function processes the mixed event for track - V0 + template + void doMixedEvent(FilteredFDCollisions const& cols, PartType const& parts, PartitionType& partitionOne, PartitionType& partitionTwo, int helRange, [[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 = 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) { + return; + } + + 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, trackconfigs.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[V0configs.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[V0configs.confV0Type1][1])) + continue; + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { + continue; + } + } + + 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())); + + auto posChildMass = pdg->Mass(V0configs.confPDGCodePosChild); + auto negChildMass = pdg->Mass(V0configs.confPDGCodeNegChild); + auto posChildBoosted = FemtoUniverseMath::boostPRF(posChild, posChildMass, negChild, negChildMass); + auto cosineTheta = (posChildBoosted.Px() * p2.px() + posChildBoosted.Py() * p2.py() + posChildBoosted.Pz() * p2.pz()) / (posChildBoosted.P() * p2.p()); + + switch (helRange) { + case 0: { + if constexpr (std::is_same::value) + mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); + else + mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + case 1: { + if (cosineTheta < 1.0 && cosineTheta >= 0.1) + mixedEventContHel1.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + case 2: { + if (cosineTheta < 0.1 && cosineTheta >= -0.1) + mixedEventContHel2.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + case 3: { + if (cosineTheta < -0.1 && cosineTheta >= -0.5) + mixedEventContHel3.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + case 4: { + if (cosineTheta < -0.5 && cosineTheta >= -1.0) + mixedEventContHel4.setPair(p1, p2, multCol, confUse3D, weight); + + break; + } + + default: + break; + } + } + }; + + 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()})); + } + } + } + + void processMixedEvent(FilteredFDCollisions const& cols, FemtoFullParticles const& parts) + { + if (cfgProcessHel) + doMixedEvent(cols, parts, partsOne, partsTwo, 0); + + if (cfgProcessHel1) + doMixedEvent(cols, parts, partsOne, partsTwo, 1); + + if (cfgProcessHel2) + doMixedEvent(cols, parts, partsOne, partsTwo, 2); + + if (cfgProcessHel3) + doMixedEvent(cols, parts, partsOne, partsTwo, 3); + + if (cfgProcessHel4) + doMixedEvent(cols, parts, partsOne, partsTwo, 4); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Helicity, processMixedEvent, "Enable processing mixed event for track - V0", false); + + void processMixedEventMCReco(FilteredFDCollisions const& cols, FemtoRecoParticles const& parts, aod::FdMCParticles const& mcparts) + { + doMixedEvent(cols, parts, partsOneMCReco, partsTwoMCReco, 0, mcparts); + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Helicity, processMixedEventMCReco, "Enable processing mixed event for track - V0 for MC Reco", false); + + /// This function processes the mixed event for V0 - V0 + void processMixedEventV0(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 = 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) { + 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[V0configs.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[V0configs.confV0Type1][1])) + continue; + + 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[V0configs.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[V0configs.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); + } + }; + + 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(FemtoUniversePairTaskTrackV0Helicity, processMixedEventV0, "Enable processing mixed events for V0 - V0", 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}; + + auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { + const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + + 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()) != trackconfigs.confTrkPDGCodePartOne) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((V0configs.confV0Type1 == 0 && pdgCode2 != V0configs.confPDGCodeV0) || (V0configs.confV0Type1 == 1 && pdgCode2 != -V0configs.confPDGCodeV0)) + 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(FemtoUniversePairTaskTrackV0Helicity, 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 ((V0configs.confV0Type1 == 0 && pdgCode1 != V0configs.confPDGCodeV0) || (V0configs.confV0Type1 == 1 && pdgCode1 != -V0configs.confPDGCodeV0)) + continue; + int pdgCode2 = static_cast(p2.pidCut()); + if ((V0configs.confV0Type2 == 0 && pdgCode2 != V0configs.confPDGCodeV0) || (V0configs.confV0Type2 == 1 && pdgCode2 != -V0configs.confPDGCodeV0)) + 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(FemtoUniversePairTaskTrackV0Helicity, processMCMixedEventV0, "Enable processing mixed events for MC truth V0 - V0", false); + + /// --------------------------------------------------------------- MC --------------------------------------------------------------- /// + + /// This function fills MC Truth particles from derived MC table + void processMCTruth(o2::aod::FdCollision const& col, FemtoTruthParticles const& parts) + { + eventHisto.fillQA(col); + auto groupPartsTwo = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + for (const auto& part : groupPartsTwo) { + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) + continue; + + int pdgCode = static_cast(part.tempFitVar()); + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (!pdgParticle) + continue; + + if (pdgCode == 3122) { + registryMCtruth.fill(HIST("plus/MCtruthLambda"), part.pt(), part.eta()); + + // Helicity angle + const auto& posChild = parts.iteratorAt(part.index() - 2); + const auto& negChild = parts.iteratorAt(part.index() - 1); + + registryMCtruth.fill(HIST("PosChildMCTruth/hPt"), posChild.pt()); + registryMCtruth.fill(HIST("NegChildMCTruth/hPt"), negChild.pt()); + + auto posChildMass = pdg->Mass(V0configs.confPDGCodePosChild); + auto negChildMass = pdg->Mass(V0configs.confPDGCodeNegChild); + auto posChildBoosted = FemtoUniverseMath::boostPRF(posChild, posChildMass, negChild, negChildMass); + auto cosineTheta = (posChildBoosted.Px() * part.px() + posChildBoosted.Py() * part.py() + posChildBoosted.Pz() * part.pz()) / (posChildBoosted.P() * part.p()); + + registryMCtruth.fill(HIST("ThetaMCTruth/hTheta"), part.p(), cosineTheta); + registryMCtruth.fill(HIST("ThetaMCTruth/hTheta3D_PosChild"), part.p(), cosineTheta, posChild.pt()); + registryMCtruth.fill(HIST("ThetaMCTruth/hTheta3D_NegChild"), part.p(), cosineTheta, negChild.pt()); + registryMCtruth.fill(HIST("ThetaMCTruth/PositiveChild/hThetaPt"), posChild.pt(), cosineTheta); + registryMCtruth.fill(HIST("ThetaMCTruth/PositiveChild/hThetaEta"), posChild.eta(), cosineTheta); + registryMCtruth.fill(HIST("ThetaMCTruth/PositiveChild/hThetaPhi"), posChild.phi(), cosineTheta); + registryMCtruth.fill(HIST("ThetaMCTruth/NegativeChild/hThetaPt"), negChild.pt(), cosineTheta); + registryMCtruth.fill(HIST("ThetaMCTruth/NegativeChild/hThetaEta"), negChild.eta(), cosineTheta); + registryMCtruth.fill(HIST("ThetaMCTruth/NegativeChild/hThetaPhi"), negChild.phi(), cosineTheta); + + continue; + } else if (pdgCode == -3122) { + registryMCtruth.fill(HIST("minus/MCtruthLambda"), part.pt(), part.eta()); + continue; + } + + if (pdgParticle->Charge() > 0.0) { + registryMCtruth.fill(HIST("plus/MCtruthAllPt"), part.pt()); + } + if (pdgCode == 211) { + registryMCtruth.fill(HIST("plus/MCtruthPi"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("plus/MCtruthPiPt"), part.pt()); + } + if (pdgCode == 2212) { + 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 == -211) { + registryMCtruth.fill(HIST("minus/MCtruthPi"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("minus/MCtruthPiPt"), part.pt()); + } + if (pdgCode == -2212) { + registryMCtruth.fill(HIST("minus/MCtruthPr"), part.pt(), part.eta()); + registryMCtruth.fill(HIST("minus/MCtruthPrPt"), part.pt()); + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Helicity, processMCTruth, "Process MC truth data", 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() == 3122) { + 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() == -3122) { + 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() == 211 && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()))) { + registryMCreco.fill(HIST("plus/MCrecoPi"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("plus/MCrecoPiPt"), mcpart.pt()); + } else if (mcpart.pdgMCTruth() == 2212 && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::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() == -211 && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()))) { + registryMCreco.fill(HIST("minus/MCrecoPi"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("minus/MCrecoPiPt"), mcpart.pt()); + } else if (mcpart.pdgMCTruth() == -2212 && isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()))) { + registryMCreco.fill(HIST("minus/MCrecoPr"), mcpart.pt(), mcpart.eta()); + registryMCreco.fill(HIST("minus/MCrecoPrPt"), mcpart.pt()); + } + } + } // partType + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackV0Helicity, processMCReco, "Process MC reco data", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskV0CascadeExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskV0CascadeExtended.cxx new file mode 100644 index 00000000000..739128780ea --- /dev/null +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskV0CascadeExtended.cxx @@ -0,0 +1,458 @@ +// 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 femtoUniversePairTaskV0CascadeExtended.cxx +/// \brief Task for v0-cascade correlations and QA +/// \author Shirajum Monira, WUT Warsaw, shirajum.monira@cern.ch + +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseContainer.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseDetaDphiStar.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseEventHisto.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniversePairCleaner.h" +#include "PWGCF/FemtoUniverse/Core/FemtoUniverseParticleHisto.h" +#include "PWGCF/FemtoUniverse/Core/femtoUtils.h" +#include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +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 FemtoUniversePairTaskV0CascadeExtended { + + SliceCache cache; + using FemtoParticles = soa::Join; + + /// applying narrow cut + Configurable confZVertexCut{"confZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; + + Filter collisionFilter = (nabs(aod::collision::posZ) < confZVertexCut); + using FilteredFDCollisions = soa::Filtered; + using FilteredFDCollision = FilteredFDCollisions::iterator; + + /// particle 1 (v0) + 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 confV0Type{"confV0Type", 0, "select one of the V0s (lambda = 0, anti-lambda = 1, k0 = 2)"}; + Configurable confV0InvMassLowLimit{"confV0InvMassLowLimit", 1.10, "Lower limit of the V0 invariant mass"}; + Configurable confV0InvMassUpLimit{"confV0InvMassUpLimit", 1.13, "Upper limit of the V0 invariant mass"}; + Configurable confV0PDGCode{"confV0PDGCode", 3122, "Particle 1 (V0) - PDG code"}; + + /// particle 2 (cascade) + 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 confCascType{"confCascType", 0, "select one of the cascades (Omega = 0, Xi = 1, anti-Omega = 2, anti-Xi = 3)"}; + Configurable confCascInvMassLowLimit{"confCascInvMassLowLimit", 1.315, "Lower limit of the cascade invariant mass"}; + Configurable confCascInvMassUpLimit{"confCascInvMassUpLimit", 1.325, "Upper limit of the cascade invariant mass"}; + Configurable confCascPDGCode{"confCascPDGCode", 3312, "Particle 2 (Cascade) - PDG code"}; + + /// nSigma cuts + Configurable confmom{"confmom", 0.75, "momentum threshold for particle identification using TOF"}; + Configurable confNsigmaTPCParticleChild{"confNsigmaTPCParticleChild", 3.0, "TPC Sigma for cascade (daugh & bach) momentum < Confmom"}; + Configurable confNsigmaTOFParticleChild{"confNsigmaTOFParticleChild", 3.0, "TOF Sigma for cascade (daugh & bach) momentum > Confmom"}; + + /// CPR + Configurable confIsCPR{"confIsCPR", false, "Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for CPR"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for CPR"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for CPR"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for CPR"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.0, "Delta Eta cut for Close Pair Rejection"}; + Configurable confIsSameSignCPR{"confIsSameSignCPR", false, "Close Pair Rejection for same sign children of cascades"}; + + /// for correlation part + Configurable confIsMC{"confIsMC", false, "Enable additional Histograms in the case of a MonteCarlo Run"}; + 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 confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs 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{"confTrkTempFitVarBins", {300, -0.15, 0.15}, "binning of the TempFitVar in 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"}; + ConfigurableAxis confChildTempFitVarpTBins{"confChildTempFitVarpTBins", {20, 0.5, 4.05}, "V0 child: pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confV0TempFitVarpTBins{"confV0TempFitVarpTBins", {20, 0.5, 4.05}, "V0: pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confV0TempFitVarBins{"confV0TempFitVarBins", {300, 0.95, 1.}, "V0: binning of the TempFitVar in the pT vs. TempFitVar plot"}; + + /// Partition for particle 1 (V0) + Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < confHPtPart1) && (aod::femtouniverseparticle::pt > confLPtPart1); + + /// Partition for particle 1 (V0) without extended table + Partition partsOnebitmask = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (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 for particle 2 (Cascade) without extended table + Partition partsTwobitmask = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kCascade)) && (aod::femtouniverseparticle::pt < confHPtPart2) && (aod::femtouniverseparticle::pt > confLPtPart2); + + /// Histogramming for v0 + FemtoUniverseParticleHisto trackHistoV0; + FemtoUniverseParticleHisto posChildV0; + FemtoUniverseParticleHisto negChildV0; + + /// Histogramming for cascade + FemtoUniverseParticleHisto posChildHistosCasc; + FemtoUniverseParticleHisto negChildHistosCasc; + FemtoUniverseParticleHisto bachHistosCasc; + FemtoUniverseParticleHisto cascQAHistos; + + /// Histogramming for Event + FemtoUniverseEventHisto eventHisto; + + FemtoUniverseContainer sameEventCont; + FemtoUniverseContainer mixedEventCont; + FemtoUniversePairCleaner pairCleaner; + FemtoUniverseDetaDphiStar pairCloseRejection; + + HistogramRegistry qaRegistry{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry resultRegistry{"Correlations", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Table to select v0 daughters + static constexpr unsigned int V0ChildTable[][2] = {{0, 1}, {1, 0}, {1, 1}}; + + bool invMLambda(float invMassLambda, float invMassAntiLambda) + { + if ((invMassLambda < confV0InvMassLowLimit || invMassLambda > confV0InvMassUpLimit) && (invMassAntiLambda < confV0InvMassLowLimit || invMassAntiLambda > confV0InvMassUpLimit)) { + return false; + } + return 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 invMassXi, float invMassOmega, int cascType) + { + return (((cascType == 1 || cascType == 3) && (invMassXi > confCascInvMassLowLimit && invMassXi < confCascInvMassUpLimit)) || ((cascType == 0 || cascType == 2) && (invMassOmega > confCascInvMassLowLimit && invMassOmega < confCascInvMassUpLimit))); + } + + 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; + } + } + + template + bool isParticleTPC(const T& part, int id, float* partSigma = 0) + { + const float tpcNSigmas[3] = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; + if (partSigma) + *partSigma = tpcNSigmas[id]; + return isNSigmaTPC(tpcNSigmas[id]); + } + + template + bool isParticleTOF(const T& part, int id, float* partSigma = 0) + { + const float tofNSigmas[3] = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; + if (partSigma) + *partSigma = tofNSigmas[id]; + return isNSigmaTOF(part.p(), tofNSigmas[id], part.tempFitVar()); + } + + void init(InitContext const&) + { + trackHistoV0.init(&qaRegistry, confV0TempFitVarpTBins, confV0TempFitVarBins, confIsMC, confV0PDGCode, true, "trackHistoV0"); + posChildV0.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "posChildV0"); + negChildV0.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "negChildV0"); + + posChildHistosCasc.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "posChildCasc"); + negChildHistosCasc.init(&qaRegistry, confChildTempFitVarpTBins, confChildTempFitVarBins, false, 0, true, "negChildCasc"); + bachHistosCasc.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); + sameEventCont.setPDGCodes(confV0PDGCode, confCascPDGCode); + mixedEventCont.setPDGCodes(confV0PDGCode, confCascPDGCode); + + pairCleaner.init(&qaRegistry); + if (confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value, 0, 0, confIsSameSignCPR.value); + } + } + + template + using hasSigma = decltype(std::declval().tpcNSigmaStorePr()); + + /// v0-cascade correlations same event + template + void doSameEvent(const FilteredFDCollision& col, const TableType& parts, PartitionType& partsOne, PartitionType& partsTwo) + { + 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); + + eventHisto.fillQA(col); + + for (const auto& part : groupPartsTwo) { + /// inv Mass check for cascade + if (!invMCascade(part.mLambda(), part.mAntiLambda(), confCascType)) + continue; + + const auto& posChild = parts.iteratorAt(part.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + /// Children of cascade must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, CascChildTable[confCascType][0]) || !isParticleTPC(negChild, CascChildTable[confCascType][1]) || !isParticleTPC(bachelor, CascChildTable[confCascType][2])) + continue; + + if (!isParticleTOF(posChild, CascChildTable[confCascType][0]) || !isParticleTOF(negChild, CascChildTable[confCascType][1]) || !isParticleTOF(bachelor, CascChildTable[confCascType][2])) + continue; + + posChildHistosCasc.fillQABase(posChild, HIST("posChildCasc")); + negChildHistosCasc.fillQABase(negChild, HIST("negChildCasc")); + bachHistosCasc.fillQABase(bachelor, HIST("hBachelor")); + cascQAHistos.fillQA(part); + + } else { + if ((posChild.pidCut() & (1u << CascChildTable[confCascType][0])) == 0 || (negChild.pidCut() & (1u << CascChildTable[confCascType][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType][2])) == 0) + continue; + + if ((posChild.pidCut() & (8u << CascChildTable[confCascType][0])) == 0 || (negChild.pidCut() & (8u << CascChildTable[confCascType][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType][2])) == 0) + continue; + + posChildHistosCasc.fillQABase(posChild, HIST("posChildCasc")); + negChildHistosCasc.fillQABase(negChild, HIST("negChildCasc")); + bachHistosCasc.fillQABase(bachelor, HIST("hBachelor")); + cascQAHistos.fillQA(part); + } + } + + for (const auto& part : groupPartsOne) { + /// inv Mass check for V0s + if (!invMLambda(part.mLambda(), part.mAntiLambda())) + continue; + + const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); + /// Daughters of v0 must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, V0ChildTable[confV0Type][0]) || !isParticleTPC(negChild, V0ChildTable[confV0Type][1])) + continue; + + if (!isParticleTOF(posChild, V0ChildTable[confV0Type][0]) || !isParticleTOF(negChild, V0ChildTable[confV0Type][1])) + continue; + + trackHistoV0.fillQABase(part, HIST("trackHistoV0")); + posChildV0.fillQABase(posChild, HIST("posChildV0")); + negChildV0.fillQABase(negChild, HIST("negChildV0")); + + } else { + if ((posChild.pidCut() & (1u << V0ChildTable[confV0Type][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[confV0Type][1])) == 0) + continue; + + if ((posChild.pidCut() & (8u << V0ChildTable[confV0Type][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[confV0Type][1])) == 0) + continue; + + trackHistoV0.fillQABase(part, HIST("trackHistoV0")); + posChildV0.fillQABase(posChild, HIST("posChildV0")); + negChildV0.fillQABase(negChild, HIST("negChildV0")); + } + } + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if (!invMLambda(p1.mLambda(), p1.mAntiLambda())) + continue; + // Cascase inv Mass cut (mLambda stores Xi mass, mAntiLambda stored Omega mass) + if (!invMCascade(p2.mLambda(), p2.mAntiLambda(), confCascType)) + continue; + + // V0 + const auto& posChild1 = parts.iteratorAt(p1.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& negChild1 = parts.iteratorAt(p1.globalIndex() - 1 - parts.begin().globalIndex()); + /// Daughters of v0 must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild1, V0ChildTable[confV0Type][0]) || !isParticleTPC(negChild1, V0ChildTable[confV0Type][1])) + continue; + if (!isParticleTOF(posChild1, V0ChildTable[confV0Type][0]) || !isParticleTOF(negChild1, V0ChildTable[confV0Type][1])) + continue; + } else { + if ((posChild1.pidCut() & (1u << V0ChildTable[confV0Type][0])) == 0 || (negChild1.pidCut() & (1u << V0ChildTable[confV0Type][1])) == 0) + continue; + if ((posChild1.pidCut() & (8u << V0ChildTable[confV0Type][0])) == 0 || (negChild1.pidCut() & (8u << V0ChildTable[confV0Type][1])) == 0) + continue; + } + + // cascade + const auto& posChild2 = parts.iteratorAt(p2.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild2 = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); + /// Daughters of cascade must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild2, CascChildTable[confCascType][0]) || !isParticleTPC(negChild2, CascChildTable[confCascType][1]) || !isParticleTPC(bachelor, CascChildTable[confCascType][2])) + continue; + if (!isParticleTOF(posChild2, CascChildTable[confCascType][0]) || !isParticleTOF(negChild2, CascChildTable[confCascType][1]) || !isParticleTOF(bachelor, CascChildTable[confCascType][2])) + continue; + } else { + if ((posChild2.pidCut() & (1u << CascChildTable[confCascType][0])) == 0 || (negChild2.pidCut() & (1u << CascChildTable[confCascType][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType][2])) == 0) + continue; + if ((posChild2.pidCut() & (8u << CascChildTable[confCascType][0])) == 0 || (negChild2.pidCut() & (8u << CascChildTable[confCascType][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType][2])) == 0) + continue; + } + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { + return; + } + } + sameEventCont.setPair(p1, p2, col.multNtr(), confUse3D, 1.0f); + } + } + + void processSameEvent(const FilteredFDCollision& col, const FemtoParticles& parts) + { + doSameEvent(col, parts, partsOne, partsTwo); + } + PROCESS_SWITCH(FemtoUniversePairTaskV0CascadeExtended, processSameEvent, "Enable processing same event for v0 - cascade with debug table", false); + + void processSameEventBitmask(const FilteredFDCollision& col, const aod::FDParticles& parts) + { + doSameEvent(col, parts, partsOnebitmask, partsTwobitmask); + } + PROCESS_SWITCH(FemtoUniversePairTaskV0CascadeExtended, processSameEventBitmask, "Enable processing same event for v0 - cascade with bitmask", false); + + /// v0-cascade correlations mixed event + template + void doMixedEvent(const FilteredFDCollisions& cols, const TableType& parts, PartitionType& partsOne, PartitionType& partsTwo) + { + ColumnBinningPolicy colBinning{{confVtxBins, confMultBins}, true}; + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, cols, cols)) { + 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); + + const auto& magFieldTesla1 = collision1.magField(); + const auto& magFieldTesla2 = collision2.magField(); + + if (magFieldTesla1 != magFieldTesla2) { + continue; + } + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + if (!invMLambda(p1.mLambda(), p1.mAntiLambda())) + continue; + // Cascase inv Mass cut (mLambda stores Xi mass, mAntiLambda stored Omega mass) + if (!invMCascade(p2.mLambda(), p2.mAntiLambda(), confCascType)) + continue; + + // V0 + const auto& posChild1 = parts.iteratorAt(p1.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& negChild1 = parts.iteratorAt(p1.globalIndex() - 1 - parts.begin().globalIndex()); + /// Daughters of v0 must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild1, V0ChildTable[confV0Type][0]) || !isParticleTPC(negChild1, V0ChildTable[confV0Type][1])) + continue; + if (!isParticleTOF(posChild1, V0ChildTable[confV0Type][0]) || !isParticleTOF(negChild1, V0ChildTable[confV0Type][1])) + continue; + } else { + if ((posChild1.pidCut() & (1u << V0ChildTable[confV0Type][0])) == 0 || (negChild1.pidCut() & (1u << V0ChildTable[confV0Type][1])) == 0) + continue; + if ((posChild1.pidCut() & (8u << V0ChildTable[confV0Type][0])) == 0 || (negChild1.pidCut() & (8u << V0ChildTable[confV0Type][1])) == 0) + continue; + } + + // Cascade + const auto& posChild2 = parts.iteratorAt(p2.globalIndex() - 3 - parts.begin().globalIndex()); + const auto& negChild2 = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); + const auto& bachelor = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); + /// Daughters of cascade must pass this condition to be selected + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild2, CascChildTable[confCascType][0]) || !isParticleTPC(negChild2, CascChildTable[confCascType][1]) || !isParticleTPC(bachelor, CascChildTable[confCascType][2])) + continue; + if (!isParticleTOF(posChild2, CascChildTable[confCascType][0]) || !isParticleTOF(negChild2, CascChildTable[confCascType][1]) || !isParticleTOF(bachelor, CascChildTable[confCascType][2])) + continue; + } else { + if ((posChild2.pidCut() & (1u << CascChildTable[confCascType][0])) == 0 || (negChild2.pidCut() & (1u << CascChildTable[confCascType][1])) == 0 || (bachelor.pidCut() & (1u << CascChildTable[confCascType][2])) == 0) + continue; + if ((posChild2.pidCut() & (8u << CascChildTable[confCascType][0])) == 0 || (negChild2.pidCut() & (8u << CascChildTable[confCascType][1])) == 0 || (bachelor.pidCut() & (8u << CascChildTable[confCascType][2])) == 0) + continue; + } + + // track cleaning + if (!pairCleaner.isCleanPair(p1, p2, parts)) { + continue; + } + if (confIsCPR.value) { + if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::same)) { + return; + } + } + + mixedEventCont.setPair(p1, p2, multCol, confUse3D, 1.0f); + } + } + } + void processMixedEvent(const FilteredFDCollisions& cols, const FemtoParticles& parts) + { + doMixedEvent(cols, parts, partsOne, partsTwo); + } + PROCESS_SWITCH(FemtoUniversePairTaskV0CascadeExtended, processMixedEvent, "Enable processing mixed event for v0 - cascade with debug table", false); + + void processMixedEventBitmask(const FilteredFDCollisions& cols, const aod::FDParticles& parts) + { + doMixedEvent(cols, parts, partsOnebitmask, partsTwobitmask); + } + PROCESS_SWITCH(FemtoUniversePairTaskV0CascadeExtended, processMixedEventBitmask, "Enable processing mixed event for v0 - cascade with bitmask", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc), + }; + return workflow; +} diff --git a/PWGCF/FemtoWorld/Core/FemtoWorldMath.h b/PWGCF/FemtoWorld/Core/FemtoWorldMath.h index 6eff2f212b8..16df6773cd8 100644 --- a/PWGCF/FemtoWorld/Core/FemtoWorldMath.h +++ b/PWGCF/FemtoWorld/Core/FemtoWorldMath.h @@ -14,8 +14,8 @@ /// \author Valentina Mantovani Sarti, TU München, valentina.mantovani-sarti@tum.de, Laura Serksnyte, TU München, laura.serksnyte@cern.ch /// \author Zuzanna Chochulska, WUT Warsaw, zchochul@cern.ch -#ifndef FEMTOWORLDMATH_H_ -#define FEMTOWORLDMATH_H_ +#ifndef PWGCF_FEMTOWORLD_CORE_FEMTOWORLDMATH_H_ +#define PWGCF_FEMTOWORLD_CORE_FEMTOWORLDMATH_H_ #include "Math/Vector4D.h" #include "Math/Boost.h" @@ -39,10 +39,10 @@ class FemtoWorldMath /// \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) + static float getkstar(const T& part1, const float mass1, const T& part2, const float mass2, const float z1 = 1.f, const float z2 = 1.f) { - 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 vecpart1(part1.pt() * z1, part1.eta(), part1.phi(), mass1); + const ROOT::Math::PtEtaPhiMVector vecpart2(part2.pt() * z2, part2.eta(), part2.phi(), mass2); const ROOT::Math::PtEtaPhiMVector trackSum = vecpart1 + vecpart2; const float beta = trackSum.Beta(); @@ -140,4 +140,4 @@ class FemtoWorldMath } // namespace o2::analysis::femtoWorld -#endif /* FEMTOWORLDMATH_H_ */ +#endif // PWGCF_FEMTOWORLD_CORE_FEMTOWORLDMATH_H_ diff --git a/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerReducedTask.cxx b/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerReducedTask.cxx index 06bb8dff109..ffdeb15c7b2 100644 --- a/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerReducedTask.cxx +++ b/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerReducedTask.cxx @@ -16,23 +16,26 @@ #include "PWGCF/FemtoWorld/Core/FemtoWorldCollisionSelection.h" #include "PWGCF/FemtoWorld/Core/FemtoWorldTrackSelection.h" #include "PWGCF/FemtoWorld/DataModel/FemtoWorldDerived.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "DataFormatsParameters/GRPObject.h" +#include + #include "Math/Vector4D.h" #include "TMath.h" -#include using namespace o2; using namespace o2::analysis::femtoWorld; diff --git a/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTask.cxx b/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTask.cxx index ce5b415b275..ab3f7e66d96 100644 --- a/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTask.cxx +++ b/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTask.cxx @@ -14,38 +14,39 @@ /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de /// \author Zuzanna Chochulska, WUT Warsaw, zchochul@cern.ch -#include // FIXME - -#include "CCDB/BasicCCDBManager.h" #include "PWGCF/FemtoWorld/Core/FemtoWorldCollisionSelection.h" +#include "PWGCF/FemtoWorld/Core/FemtoWorldPairCleaner.h" +#include "PWGCF/FemtoWorld/Core/FemtoWorldPhiSelection.h" #include "PWGCF/FemtoWorld/Core/FemtoWorldTrackSelection.h" #include "PWGCF/FemtoWorld/Core/FemtoWorldV0Selection.h" -#include "PWGCF/FemtoWorld/Core/FemtoWorldPhiSelection.h" #include "PWGCF/FemtoWorld/DataModel/FemtoWorldDerived.h" -#include "PWGCF/FemtoWorld/Core/FemtoWorldPairCleaner.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "TLorentzVector.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + #include "Math/Vector4D.h" +#include "TLorentzVector.h" #include "TMath.h" +#include // FIXME using namespace o2; using namespace o2::analysis::femtoWorld; diff --git a/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTaskV0Only.cxx b/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTaskV0Only.cxx index b576f2c125b..b46aa32a312 100644 --- a/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTaskV0Only.cxx +++ b/PWGCF/FemtoWorld/TableProducer/femtoWorldProducerTaskV0Only.cxx @@ -17,23 +17,26 @@ #include "PWGCF/FemtoWorld/Core/FemtoWorldTrackSelection.h" #include "PWGCF/FemtoWorld/Core/FemtoWorldV0Selection.h" #include "PWGCF/FemtoWorld/DataModel/FemtoWorldDerived.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "Common/Core/trackUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "DataFormatsParameters/GRPObject.h" +#include + #include "Math/Vector4D.h" #include "TMath.h" -#include using namespace o2; using namespace o2::analysis::femtoWorld; diff --git a/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTask.cxx b/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTask.cxx index 9cad450302f..12bc5b3ad32 100644 --- a/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTask.cxx +++ b/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTask.cxx @@ -16,20 +16,23 @@ /// \author Barbara Chytla, WUT Warsaw, barbara.chytla@cern.ch // O2 includes -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/EventSelection.h" +#include "PWGCF/FemtoWorld/Core/FemtoWorldCollisionSelection.h" +#include "PWGCF/FemtoWorld/DataModel/FemtoWorldDerived.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "PWGCF/FemtoWorld/Core/FemtoWorldCollisionSelection.h" -#include "PWGCF/FemtoWorld/DataModel/FemtoWorldDerived.h" -#include "Framework/O2DatabasePDGPlugin.h" #include "TPDGCode.h" diff --git a/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTaskDe.cxx b/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTaskDe.cxx index b0108b37a2b..6c7a97c1f5b 100644 --- a/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTaskDe.cxx +++ b/PWGCF/FemtoWorld/Tasks/femtoWorldEfficiencyTaskDe.cxx @@ -16,19 +16,22 @@ /// \author Barbara Chytla, WUT Warsaw, barbara.chytla@cern.ch // O2 includes -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/EventSelection.h" +#include "PWGCF/FemtoWorld/Core/FemtoWorldCollisionSelection.h" +#include "PWGLF/DataModel/LFResonanceTables.h" + #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "PWGCF/FemtoWorld/Core/FemtoWorldCollisionSelection.h" -#include "Framework/O2DatabasePDGPlugin.h" #include "TPDGCode.h" 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..64ae1362838 --- /dev/null +++ b/PWGCF/Flow/TableProducer/zdcQVectors.cxx @@ -0,0 +1,1107 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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; +using namespace o2::aod::rctsel; +using namespace o2::constants::math; + +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] +std::vector qNoEq(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. +float centrality = 0; +int runnumber = 0; +int lastRunNumber = 0; +std::vector v(3, 0); // vx, vy, vz +bool isSelected = true; +std::vector cents; // centrality estimaters + +} // namespace o2::analysis::qvectortask + +using namespace o2::analysis::qvectortask; + +struct ZdcQVectors { + + Produces spTableZDC; + + struct : ConfigurableGroup { + Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", false, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label (CBT, CBT_hadronPID)"}; // all Labels can be found in Common/CCDB/RCTSelectionFlags.h + 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"}; + } rctFlags; + + RCTFlagsChecker rctChecker; + + struct : ConfigurableGroup { + // Additional event selections + O2_DEFINE_CONFIGURABLE(cfgMaxOccupancy, int, 10000, "Maximum occupancy of selected events"); + O2_DEFINE_CONFIGURABLE(cfgCentMin, float, 0, "Minimum cenrality for selected events"); + O2_DEFINE_CONFIGURABLE(cfgCentMax, float, 90, "Maximum cenrality for selected events"); + } EvSel; + + 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(cfgUseSecondCent, bool, false, "Use second centrality estimator"); + + O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10.0f, "Accepted z-vertex range") + 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_PbPb_pass5/Energy", "ccdb path for energy calibration histos") + O2_DEFINE_CONFIGURABLE(cfgMeanv, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5/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_pass5", "ccdb path for recentering histos"); + O2_DEFINE_CONFIGURABLE(cfgFillHistRegistry, bool, true, "Fill common registry with histograms"); + O2_DEFINE_CONFIGURABLE(cfgFillCutAnalysis, bool, true, "Fill cut analysis with histograms"); + O2_DEFINE_CONFIGURABLE(cfgFillNothing, bool, false, "Disable ALL Histograms -> ONLY use to reduce memory"); + + O2_DEFINE_CONFIGURABLE(cfgCCDBdir_Shift, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5/Shift", "CCDB directory for Shift ZDC"); + + // define my..... + // Filter collisionFilter = nabs(aod::collision::posZ) <; + using UsedCollisions = soa::Join; + using BCsRun3 = soa::Join; + + enum SelectionCriteria { + evSel_FilteredEvent, + evSel_BCHasZDC, + evSel_isSelectedZDC, + evSel_Zvtx, + evSel_sel8, + evSel_occupancy, + evSel_kNoSameBunchPileup, + evSel_kIsGoodZvtxFT0vsPV, + evSel_kNoCollInTimeRangeStandard, + evSel_kNoCollInTimeRangeNarrow, + evSel_kIsVertexITSTPC, + evSel_kIsGoodITSLayersAll, + evSel_kIsGoodITSLayer0123, + evSel_RCTFlagsZDC, + evSel_CentCuts, + 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; + + TProfile3D* shiftprofileC = nullptr; + TProfile3D* shiftprofileA = nullptr; + bool isShiftProfileFound = false; + + } 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); + + rctChecker.init(rctFlags.cfgEvtRCTFlagCheckerLabel, rctFlags.cfgEvtRCTFlagCheckerZDCCheck, rctFlags.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + std::vector sides = {"A", "C"}; + std::vector capCOORDS = {"X", "Y"}; + + AxisSpec axisPsiA = {100, -PI, PI, "#Psi_{1} ZNA"}; + AxisSpec axisPsiC = {100, -PI, PI, "#Psi_{1} ZNC"}; + + // This is the only histogram that is AL~WA~YS filled. + 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 events"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_BCHasZDC + 1, "BCHasZDC"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_RCTFlagsZDC + 1, "RCT Flags ZDC"); + 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_kNoCollInTimeRangeNarrow + 1, "kNoCollInTimeRangeNarrow"); + 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, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayer0123 + 1, "kIsGoodITSLayer0123"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_isSelectedZDC + 1, "isSelected"); + + 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); + } + + for (const auto& side : sides) { + for (const auto& coord : capCOORDS) { + 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 + } + + if (!cfgFillNothing) { + if (cfgFillHistRegistry) { + registry.add(Form("QA/before/hSPplaneA"), "hSPplaneA", kTH2D, {axisPsiA, axisCent10}); + registry.add(Form("QA/before/hSPplaneC"), "hSPplaneC", kTH2D, {axisPsiC, axisCent10}); + registry.add(Form("QA/before/hSPplaneFull"), "hSPplaneFull", kTH2D, {{100, -PI, PI}, 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}}); + registry.add(Form("QA/Q%s%s_vs_iteration", coord, side), Form("hQ%s%s_vs_iteration", coord, side), {HistType::kTH2D, {{25, 0, 25}, axisQ}}); + } // end of capCOORDS + } // end of sides + + registry.add("QA/centrality_before", "centrality_before", kTH1D, {{100, 0, 100}}); + registry.add("QA/centrality_after", "centrality_after", kTH1D, {{100, 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/psiZDCA", "psiZDCA", kTH2D, {axisPsiA, {100, 0, 100}}); + registry.add("QA/psiZDCA_shift", "psiZDCA_shift", kTH2D, {axisPsiA, {100, 0, 100}}); + registry.add("QA/psiZDCC", "psiZDCC", kTH2D, {axisPsiC, {100, 0, 100}}); + registry.add("QA/psiZDCC_shift", "psiZDCC_shift", kTH2D, {axisPsiC, {100, 0, 100}}); + registry.add("QA/psiZDCAC", "psiZDCAC", kTH2D, {axisPsiA, axisPsiC}); + registry.add("QA/psiZDCAC_shift", "psiZDCAC_shift", kTH2D, {axisPsiA, axisPsiC}); + + registry.add("QA/before/ZNA_pmC", "ZNA_pmC", kTProfile, {{1, 0, 1.}}); + 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_pmC", "ZNC_pmC", 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.add("QA/before/ZNA_Qx", "ZNA_Qx", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNA_Qy", "ZNA_Qy", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNC_Qx", "ZNC_Qx", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNC_Qy", "ZNC_Qy", kTProfile, {{1, 0, 1.}}); + + registry.add("QA/before/ZNA_Qx_vs_Centrality", "ZNA_Qx_vs_Centrality", kTH2D, {{100, 0, 100}, {200, -2, 2}}); + registry.add("QA/before/ZNA_Qy_vs_Centrality", "ZNA_Qy_vs_Centrality", kTH2D, {{100, 0, 100}, {200, -2, 2}}); + registry.add("QA/before/ZNC_Qx_vs_Centrality", "ZNC_Qx_vs_Centrality", kTH2D, {{100, 0, 100}, {200, -2, 2}}); + registry.add("QA/before/ZNC_Qy_vs_Centrality", "ZNC_Qy_vs_Centrality", kTH2D, {{100, 0, 100}, {200, -2, 2}}); + + registry.add("QA/before/ZNA_pmC_vs_Centrality", "ZNA_pmC_vs_Centrality", kTH2D, {{100, 0, 100}, {300, 0, 300}}); + registry.add("QA/before/ZNA_pmSUM_vs_Centrality", "ZNA_pmSUM_vs_Centrality", kTH2D, {{100, 0, 100}, {300, 0, 300}}); + registry.add("QA/before/ZNA_pm1_vs_Centrality", "ZNA_pm1_vs_Centrality", kTH2D, {{100, 0, 100}, {100, 0, 1}}); + registry.add("QA/before/ZNA_pm2_vs_Centrality", "ZNA_pm2_vs_Centrality", kTH2D, {{100, 0, 100}, {100, 0, 1}}); + registry.add("QA/before/ZNA_pm3_vs_Centrality", "ZNA_pm3_vs_Centrality", kTH2D, {{100, 0, 100}, {100, 0, 1}}); + registry.add("QA/before/ZNA_pm4_vs_Centrality", "ZNA_pm4_vs_Centrality", kTH2D, {{100, 0, 100}, {100, 0, 1}}); + + registry.add("QA/before/ZNC_pmC_vs_Centrality", "ZNC_pmC_vs_Centrality", kTH2D, {{100, 0, 100}, {300, 0, 300}}); + registry.add("QA/before/ZNC_pmSUM_vs_Centrality", "ZNC_pmSUM_vs_Centrality", kTH2D, {{100, 0, 100}, {300, 0, 300}}); + registry.add("QA/before/ZNC_pm1_vs_Centrality", "ZNC_pm1_vs_Centrality", kTH2D, {{100, 0, 100}, {100, 0, 1}}); + registry.add("QA/before/ZNC_pm2_vs_Centrality", "ZNC_pm2_vs_Centrality", kTH2D, {{100, 0, 100}, {100, 0, 1}}); + registry.add("QA/before/ZNC_pm3_vs_Centrality", "ZNC_pm3_vs_Centrality", kTH2D, {{100, 0, 100}, {100, 0, 1}}); + registry.add("QA/before/ZNC_pm4_vs_Centrality", "ZNC_pm4_vs_Centrality", kTH2D, {{100, 0, 100}, {100, 0, 1}}); + + registry.addClone("QA/before/", "QA/after/"); + + registry.add("QA/before/ZNA_Qx_noEq", "ZNA_Qx_noEq", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNA_Qy_noEq", "ZNA_Qy_noEq", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNC_Qx_noEq", "ZNC_Qx_noEq", kTProfile, {{1, 0, 1.}}); + registry.add("QA/before/ZNC_Qy_noEq", "ZNC_Qy_noEq", kTProfile, {{1, 0, 1.}}); + } + + // Tower mean energies vs. centrality used for tower gain equalisation + for (int tower = 0; tower < totalTowers; tower++) { + 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("shift/ShiftZDCC", "ShiftZDCC", kTProfile3D, {{100, 0, 100}, {2, 0, 2}, {10, 0, 10}}); + registry.add("shift/ShiftZDCA", "ShiftZDCA", kTProfile3D, {{100, 0, 100}, {2, 0, 2}, {10, 0, 10}}); + + if (cfgFillCutAnalysis) { + // Tower mean energies vs. centrality used for tower gain equalisation + int totalTowers = 10; + for (int tower = 0; tower < totalTowers; tower++) { + registry.add(Form("CutAnalysis/%s", namesEcal[tower].Data()), Form("%s", namesEcal[tower].Data()), kTProfile2D, {axisCent, {nEventSelections, 0, nEventSelections}}); + } + // recentered q-vectors (to check what steps are finished in the end) + registry.add("CutAnalysis/hvertex_vx", "hvertex_vx", kTProfile2D, {{1, 0., 1.}, {nEventSelections, 0, nEventSelections}}); + registry.add("CutAnalysis/hvertex_vy", "hvertex_vy", kTProfile2D, {{1, 0., 1.}, {nEventSelections, 0, nEventSelections}}); + registry.add("CutAnalysis/hvertex_vz", "hvertex_vz", kTProfile2D, {{1, 0., 1.}, {nEventSelections, 0, nEventSelections}}); + } + } + } + + template + inline void fillCutAnalysis(TCollision collision, TZdc zdcBC, int evSel) + { + registry.fill(HIST("hEventCount"), evSel); + // FT0C is the default centrality estimator + + if (!cfgFillCutAnalysis || cfgFillNothing) + return; + // Here we fill the Energy and mean vx, vy vz histograms with an extra dimension for all the event selections used. + registry.get(HIST("CutAnalysis/hvertex_vx"))->Fill(Form("%d", runnumber), evSel, collision.posX()); + registry.get(HIST("CutAnalysis/hvertex_vy"))->Fill(Form("%d", runnumber), evSel, collision.posY()); + registry.get(HIST("CutAnalysis/hvertex_vz"))->Fill(Form("%d", runnumber), evSel, collision.posZ()); + + registry.get(HIST("CutAnalysis/hZNA_mean_t0_cent"))->Fill(centrality, evSel, zdcBC.energyCommonZNA(), 1); + registry.get(HIST("CutAnalysis/hZNA_mean_t1_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNA()[0], 1); + registry.get(HIST("CutAnalysis/hZNA_mean_t2_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNA()[1], 1); + registry.get(HIST("CutAnalysis/hZNA_mean_t3_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNA()[2], 1); + registry.get(HIST("CutAnalysis/hZNA_mean_t4_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNA()[3], 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t0_cent"))->Fill(centrality, evSel, zdcBC.energyCommonZNC(), 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t1_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNC()[0], 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t2_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNC()[1], 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t3_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNC()[2], 1); + registry.get(HIST("CutAnalysis/hZNC_mean_t4_cent"))->Fill(centrality, evSel, zdcBC.energySectorZNC()[3], 1); + } + + template + uint16_t eventSelected(TCollision collision, TBunchCrossing bunchCrossing) + { + uint16_t selectionBits = 0; + bool selected; + + // Define selection criteria + // If event is selected (passed the cut), set the corresponding bit in the selectionBits variable + // bit 0 is for filterd events, so it will stay 0 + // uint16_t is 16 bits, so we have room for 15 selection criteria here + + selected = std::fabs(collision.posZ()) < cfgVtxZ; + if (selected) { + selectionBits |= static_cast(0x1u << evSel_Zvtx); + fillCutAnalysis(collision, bunchCrossing, evSel_Zvtx); + } + + selected = collision.sel8(); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_sel8); + fillCutAnalysis(collision, bunchCrossing, evSel_sel8); + } + + auto occupancy = collision.trackOccupancyInTimeRange(); + selected = occupancy <= EvSel.cfgMaxOccupancy; + if (selected) { + selectionBits |= static_cast(0x1u << evSel_occupancy); + fillCutAnalysis(collision, bunchCrossing, evSel_occupancy); + } + + selected = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_kNoSameBunchPileup); + fillCutAnalysis(collision, bunchCrossing, evSel_kNoSameBunchPileup); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_kIsGoodZvtxFT0vsPV); + fillCutAnalysis(collision, bunchCrossing, evSel_kIsGoodZvtxFT0vsPV); + } + + selected = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_kNoCollInTimeRangeStandard); + fillCutAnalysis(collision, bunchCrossing, evSel_kNoCollInTimeRangeStandard); + } + + selected = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_kNoCollInTimeRangeNarrow); + fillCutAnalysis(collision, bunchCrossing, evSel_kNoCollInTimeRangeNarrow); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_kIsVertexITSTPC); + fillCutAnalysis(collision, bunchCrossing, evSel_kIsVertexITSTPC); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_kIsGoodITSLayersAll); + fillCutAnalysis(collision, bunchCrossing, evSel_kIsGoodITSLayersAll); + } + + selected = collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_kIsGoodITSLayer0123); + fillCutAnalysis(collision, bunchCrossing, evSel_kIsGoodITSLayer0123); + } + + selected = rctChecker(collision); + if (selected) { + selectionBits |= static_cast(0x1u << evSel_RCTFlagsZDC); + fillCutAnalysis(collision, bunchCrossing, evSel_RCTFlagsZDC); + } + + return selectionBits; + } + + 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! + if (cfgFillNothing) + return; + 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); + + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/ZNA_Qx_vs_Centrality"), centrality, qxa); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/ZNA_Qy_vs_Centrality"), centrality, qya); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/ZNC_Qx_vs_Centrality"), centrality, qxc); + registry.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/ZNC_Qy_vs_Centrality"), centrality, 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()); + if (cm == kRec) { + cal.atStep = 5; + cal.atIteration = 5; + } + } + } + + 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))); + if (!list) { + LOGF(fatal, "No calibration list for iteration %i and step %i", iteration, step); + } + hist = reinterpret_cast(list->FindObject(Form("%s", objName))); + if (!hist) { + LOGF(fatal, "No calibration histo for iteration %i and step %i -> %s", iteration, step, 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.), sumZN_noEq(2, 0.); + std::vector xEnZN(2, 0.), xEnZN_noEq(2, 0.); + std::vector yEnZN(2, 0.), yEnZN_noEq(2, 0.); + + isSelected = true; + + std::vector centralities; + + auto cent = collision.centFT0C(); + centrality = cent; + + centralities.push_back(collision.centFT0C()); + + if (cfgFT0Cvariant1) { + centralities.push_back(collision.centFT0CVariant1()); + if (cfgUseSecondCent) + cent = collision.centFT0CVariant1(); + } + if (cfgFT0M) { + centralities.push_back(collision.centFT0M()); + if (cfgUseSecondCent) + cent = collision.centFT0M(); + } + if (cfgFV0A) { + centralities.push_back(collision.centFV0A()); + if (cfgUseSecondCent) + cent = collision.centFV0A(); + } + if (cfgNGlobal) { + centralities.push_back(collision.centNGlobal()); + if (cfgUseSecondCent) + cent = collision.centNGlobal(); + } + + v = {collision.posX(), collision.posY(), collision.posZ()}; + cents = centralities; + + const auto& foundBC = collision.foundBC_as(); + runnumber = foundBC.runNumber(); + + if (cfgFillHistRegistry && !cfgFillNothing) + registry.fill(HIST("QA/centrality_before"), cent); + + registry.fill(HIST("hEventCount"), evSel_FilteredEvent); + + if (!foundBC.has_zdc()) { + isSelected = false; + spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, isSelected, 0); + counter++; + lastRunNumber = runnumber; + return; + } + registry.fill(HIST("hEventCount"), evSel_BCHasZDC); + + 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]; + } + + 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; + + // if ZNA or ZNC not hit correctly.. do not use event in q-vector calculation + if (!isZNAhit || !isZNChit) { + counter++; + isSelected = false; + spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, isSelected, 0); + lastRunNumber = runnumber; + return; + } + registry.fill(HIST("hEventCount"), evSel_isSelectedZDC); + + uint16_t eventSelectionFlags = eventSelected(collision, foundBC.zdc()); + + // ALWAYS use these event selections + if (cent < EvSel.cfgCentMin || cent > EvSel.cfgCentMax || !collision.sel8() || std::abs(collision.posZ()) > cfgVtxZ) { + // event not selected + isSelected = false; + spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, isSelected, eventSelectionFlags); + counter++; + lastRunNumber = runnumber; + return; + } + registry.fill(HIST("hEventCount"), evSel_CentCuts); + + // load new calibrations for new runs only + if (runnumber != lastRunNumber) { + cal.calibfilesLoaded[0] = false; + cal.calibList[0] = nullptr; + + cal.calibfilesLoaded[1] = false; + cal.calibList[1] = nullptr; + + cal.calibfilesLoaded[2] = false; + cal.calibList[2] = nullptr; + + cal.isShiftProfileFound = false; + cal.shiftprofileC = nullptr; + cal.shiftprofileA = nullptr; + } + + // 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 (!cfgFillNothing) { + 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]); + + // 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); + } + } + + // Do not continue if Energy calibration is not loaded + if (!cal.calibfilesLoaded[0]) { + counter++; + isSelected = false; + spTableZDC(runnumber, cents, v, foundBC.timestamp(), 0, 0, 0, 0, isSelected, eventSelectionFlags); + lastRunNumber = runnumber; + 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++; + } + + if (cfgFillHistRegistry && !cfgFillNothing) { + 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_pmC"))->Fill(Form("%d", runnumber), meanEZN[0]); + 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_pmC"))->Fill(Form("%d", runnumber), meanEZN[5]); + 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]); + + double sumZNAbefore = eZN[0] + eZN[1] + eZN[2] + eZN[3]; + double sumZNAafter = e[0] + e[1] + e[2] + e[3]; + + double sumZNCbefore = eZN[4] + eZN[5] + eZN[6] + eZN[7]; + double sumZNCafter = e[4] + e[5] + e[6] + e[7]; + + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNA_pmC_vs_Centrality"), centrality, zdcCol.energyCommonZNA()); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNA_pmSUM_vs_Centrality"), centrality, sumZNAbefore); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNA_pm1_vs_Centrality"), centrality, eZN[0] / sumZNAbefore); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNA_pm2_vs_Centrality"), centrality, eZN[1] / sumZNAbefore); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNA_pm3_vs_Centrality"), centrality, eZN[2] / sumZNAbefore); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNA_pm4_vs_Centrality"), centrality, eZN[3] / sumZNAbefore); + + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNC_pmC_vs_Centrality"), centrality, zdcCol.energyCommonZNC()); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNC_pmSUM_vs_Centrality"), centrality, sumZNCbefore); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNC_pm1_vs_Centrality"), centrality, eZN[4] / sumZNCbefore); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNC_pm2_vs_Centrality"), centrality, eZN[5] / sumZNCbefore); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNC_pm3_vs_Centrality"), centrality, eZN[6] / sumZNCbefore); + registry.fill(HIST("QA/") + HIST("before") + HIST("/ZNC_pm4_vs_Centrality"), centrality, eZN[7] / sumZNCbefore); + + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNA_pmC_vs_Centrality"), centrality, zdcCol.energyCommonZNA()); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNA_pmSUM_vs_Centrality"), centrality, sumZNAafter); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNA_pm1_vs_Centrality"), centrality, e[0] / sumZNAafter); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNA_pm2_vs_Centrality"), centrality, e[1] / sumZNAafter); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNA_pm3_vs_Centrality"), centrality, e[2] / sumZNAafter); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNA_pm4_vs_Centrality"), centrality, e[3] / sumZNAafter); + + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNC_pmC_vs_Centrality"), centrality, zdcCol.energyCommonZNC()); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNC_pmSUM_vs_Centrality"), centrality, sumZNCafter); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNC_pm1_vs_Centrality"), centrality, e[4] / sumZNCafter); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNC_pm2_vs_Centrality"), centrality, e[5] / sumZNCafter); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNC_pm3_vs_Centrality"), centrality, e[6] / sumZNCafter); + registry.fill(HIST("QA/") + HIST("after") + HIST("/ZNC_pm4_vs_Centrality"), centrality, e[7] / sumZNCafter); + } + } + + // 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; + + // Also calculate the Q-vector for the non-equalized energy + double energyNoEq = std::pow(eZN[tower], alphaZDC); + sumZN_noEq[side] += energyNoEq; + xEnZN_noEq[side] += (side == 0) ? -1.0 * pxZDC[sector] * energyNoEq : pxZDC[sector] * energyNoEq; + yEnZN_noEq[side] += pyZDC[sector] * energyNoEq; + } + + // "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 (sumZN_noEq[i] > 0) { + qNoEq[i * 2] = xEnZN_noEq[i] / sumZN_noEq[i]; // for QXA[0] and QXC[2] + qNoEq[i * 2 + 1] = yEnZN_noEq[i] / sumZN_noEq[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 (cfgFillHistRegistry && !cfgFillNothing) { + registry.get(HIST("QA/before/ZNA_Qx"))->Fill(Form("%d", runnumber), q[0]); + registry.get(HIST("QA/before/ZNA_Qy"))->Fill(Form("%d", runnumber), q[1]); + registry.get(HIST("QA/before/ZNC_Qx"))->Fill(Form("%d", runnumber), q[2]); + registry.get(HIST("QA/before/ZNC_Qy"))->Fill(Form("%d", runnumber), q[3]); + + registry.get(HIST("QA/before/ZNA_Qx_noEq"))->Fill(Form("%d", runnumber), qNoEq[0]); + registry.get(HIST("QA/before/ZNA_Qy_noEq"))->Fill(Form("%d", runnumber), qNoEq[1]); + registry.get(HIST("QA/before/ZNC_Qx_noEq"))->Fill(Form("%d", runnumber), qNoEq[2]); + registry.get(HIST("QA/before/ZNC_Qy_noEq"))->Fill(Form("%d", runnumber), qNoEq[3]); + } + + if (cal.atIteration == 0) { + if (isSelected && cfgFillHistRegistry) + fillCommonRegistry(q[0], q[1], q[2], q[3], v, centrality); + + spTableZDC(runnumber, cents, v, foundBC.timestamp(), q[0], q[1], q[2], q[3], isSelected, eventSelectionFlags); + counter++; + lastRunNumber = runnumber; + return; + } else { + if (cfgFillHistRegistry) + 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 = 5; + int nSteps = 5; + + for (int it = 1; it <= nIterations; it++) { + corrQxA.push_back(getCorrection(names[0][0].Data(), it, 1)); + corrQyA.push_back(getCorrection(names[0][1].Data(), it, 1)); + corrQxC.push_back(getCorrection(names[0][2].Data(), it, 1)); + corrQyC.push_back(getCorrection(names[0][3].Data(), it, 1)); + pb++; + + for (int step = 2; step <= nSteps; step++) { + corrQxA.push_back(getCorrection(names[step - 1][0].Data(), it, step)); + corrQyA.push_back(getCorrection(names[step - 1][1].Data(), it, step)); + corrQxC.push_back(getCorrection(names[step - 1][2].Data(), it, step)); + corrQyC.push_back(getCorrection(names[step - 1][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 (cfgFillHistRegistry && !cfgFillNothing) { + registry.get(HIST("QA/QXA_vs_iteration"))->Fill(cor, qRec[0]); + registry.get(HIST("QA/QYA_vs_iteration"))->Fill(cor, qRec[1]); + registry.get(HIST("QA/QXC_vs_iteration"))->Fill(cor, qRec[2]); + registry.get(HIST("QA/QYC_vs_iteration"))->Fill(cor, qRec[3]); + } + } + + if (isSelected && cfgFillHistRegistry && !cfgFillNothing) { + fillCommonRegistry(qRec[0], qRec[1], qRec[2], qRec[3], v, centrality); + registry.fill(HIST("QA/centrality_after"), centrality); + registry.get(HIST("QA/after/ZNA_Qx"))->Fill(Form("%d", runnumber), qRec[0]); + registry.get(HIST("QA/after/ZNA_Qy"))->Fill(Form("%d", runnumber), qRec[1]); + registry.get(HIST("QA/after/ZNC_Qx"))->Fill(Form("%d", runnumber), qRec[2]); + registry.get(HIST("QA/after/ZNC_Qy"))->Fill(Form("%d", runnumber), qRec[3]); + } + + // do shift for psi. + double psiZDCA = 1.0 * std::atan2(qRec[1], qRec[0]); + double psiZDCC = 1.0 * std::atan2(qRec[3], qRec[2]); + + int nshift = 10; // no. of iterations + + double psiZDCAshift = psiZDCA; + double psiZDCCshift = psiZDCC; + + double deltaPsiZDCA = 0; + double deltaPsiZDCC = 0; + + if (!cfgCCDBdir_Shift.value.empty() && cal.isShiftProfileFound == false) { + LOGF(info, "Getting shift profile from CCDB for runnumber: %d", runnumber); + TList* hcorrList = ccdb->getForTimeStamp(cfgCCDBdir_Shift.value, foundBC.timestamp()); + cal.shiftprofileC = reinterpret_cast(hcorrList->FindObject("ShiftZDCC")); + cal.shiftprofileA = reinterpret_cast(hcorrList->FindObject("ShiftZDCA")); + if (!cal.shiftprofileC || !cal.shiftprofileA) { + LOGF(error, "Shift profile not found in CCDB for runnumber: %d", runnumber); + cal.isShiftProfileFound = false; + } else { + LOGF(info, "Shift profile found in CCDB for runnumber: %d", runnumber); + cal.isShiftProfileFound = true; + } + } + + for (int ishift = 1; ishift <= nshift; ishift++) { + if (!cfgFillNothing) { + registry.fill(HIST("shift/ShiftZDCC"), centrality, 0.5, ishift - 0.5, std::sin(ishift * 1.0 * psiZDCC)); + registry.fill(HIST("shift/ShiftZDCC"), centrality, 1.5, ishift - 0.5, std::cos(ishift * 1.0 * psiZDCC)); + registry.fill(HIST("shift/ShiftZDCA"), centrality, 0.5, ishift - 0.5, std::sin(ishift * 1.0 * psiZDCA)); + registry.fill(HIST("shift/ShiftZDCA"), centrality, 1.5, ishift - 0.5, std::cos(ishift * 1.0 * psiZDCA)); + } + } + + float coeffshiftxZDCC = 0.0; + float coeffshiftyZDCC = 0.0; + float coeffshiftxZDCA = 0.0; + float coeffshiftyZDCA = 0.0; + + if (cal.isShiftProfileFound) { + for (int ishift = 1; ishift <= nshift; ishift++) { + int binshiftxZDCC = cal.shiftprofileC->FindBin(centrality, 0.5, ishift - 0.5); // bin 0.5 + int binshiftyZDCC = cal.shiftprofileC->FindBin(centrality, 1.5, ishift - 0.5); + int binshiftxZDCA = cal.shiftprofileA->FindBin(centrality, 0.5, ishift - 0.5); + int binshiftyZDCA = cal.shiftprofileA->FindBin(centrality, 1.5, ishift - 0.5); + + if (binshiftxZDCC > 0) + coeffshiftxZDCC = cal.shiftprofileC->GetBinContent(binshiftxZDCC); + if (binshiftyZDCC > 0) + coeffshiftyZDCC = cal.shiftprofileC->GetBinContent(binshiftyZDCC); + if (binshiftxZDCA > 0) + coeffshiftxZDCA = cal.shiftprofileA->GetBinContent(binshiftxZDCA); + if (binshiftyZDCA > 0) + coeffshiftyZDCA = cal.shiftprofileA->GetBinContent(binshiftyZDCA); + + deltaPsiZDCC += ((2 / (1.0 * ishift)) * (-1.0 * coeffshiftxZDCC * std::cos(ishift * 1.0 * psiZDCC) + coeffshiftyZDCC * std::sin(ishift * 1.0 * psiZDCC))); + deltaPsiZDCA += ((2 / (1.0 * ishift)) * (-1.0 * coeffshiftxZDCA * std::cos(ishift * 1.0 * psiZDCA) + coeffshiftyZDCA * std::sin(ishift * 1.0 * psiZDCA))); + } + } + + psiZDCCshift += deltaPsiZDCC; + psiZDCAshift += deltaPsiZDCA; + + // Normalize angles to [-pi, pi] + psiZDCCshift = std::atan2(std::sin(psiZDCCshift), std::cos(psiZDCCshift)); + psiZDCAshift = std::atan2(std::sin(psiZDCAshift), std::cos(psiZDCAshift)); + + if (cfgFillHistRegistry && !cfgFillNothing) { + registry.fill(HIST("QA/psiZDCA"), psiZDCA, centrality); + registry.fill(HIST("QA/psiZDCC"), psiZDCC, centrality); + registry.fill(HIST("QA/psiZDCAC"), psiZDCA, psiZDCC); + registry.fill(HIST("QA/psiZDCA_shift"), psiZDCAshift, centrality); + registry.fill(HIST("QA/psiZDCC_shift"), psiZDCCshift, centrality); + registry.fill(HIST("QA/psiZDCAC_shift"), psiZDCAshift, psiZDCCshift); + } + + double qXaShift = std::hypot(qRec[1], qRec[0]) * std::cos(psiZDCAshift); + double qYaShift = std::hypot(qRec[1], qRec[0]) * std::sin(psiZDCAshift); + double qXcShift = std::hypot(qRec[2], qRec[3]) * std::cos(psiZDCCshift); + double qYcShift = std::hypot(qRec[2], qRec[3]) * std::sin(psiZDCCshift); + + spTableZDC(runnumber, cents, v, foundBC.timestamp(), qXaShift, qYaShift, qXcShift, qYcShift, isSelected, eventSelectionFlags); + qRec.clear(); + + counter++; + lastRunNumber = runnumber; + return; + } + LOGF(warning, "We return without saving table... -> THis is a problem"); + lastRunNumber = runnumber; + } // 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 bb658dc7398..b1300623c73 100644 --- a/PWGCF/Flow/Tasks/CMakeLists.txt +++ b/PWGCF/Flow/Tasks/CMakeLists.txt @@ -11,21 +11,36 @@ 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-pbpb-task - SOURCES FlowPbPbTask.cxx +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-pbpb - SOURCES FlowGFWPbPb.cxx +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 + SOURCES flowZdcTask.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) @@ -34,7 +49,57 @@ o2physics_add_dpl_workflow(flow-gf PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(flow-pbpb-pikp-task - SOURCES FlowPbPbpikp.cxx +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::AnalysisCCDB O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-pid-cme + SOURCES flowPidCme.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(resonances-gfw-flow + SOURCES resonancesGfwFlow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-efficiency-casc + SOURCES flowEfficiencyCasc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-ese-p-he3 + SOURCES flowEsePHe3.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-ese-task + SOURCES flowEseTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-gfw-ese + SOURCES flowGfwEse.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-event-plane + SOURCES flowEventPlane.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-flow-pt-corr + SOURCES pidFlowPtCorr.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::GFWCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/Flow/Tasks/FlowGFWPbPb.cxx b/PWGCF/Flow/Tasks/FlowGFWPbPb.cxx deleted file mode 100644 index 48868e86934..00000000000 --- a/PWGCF/Flow/Tasks/FlowGFWPbPb.cxx +++ /dev/null @@ -1,571 +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 -#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 FlowGFWPbPb { - - 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(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", {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 axisNchPV{"axisNchPV", {4000, 0, 4000}, "N_{ch} (PV)"}; - - using Colls = soa::Join; // collisions filter - using aodTracks = soa::Filtered>; // tracks filter - 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); - - // 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(); // 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-pt correlations that are not implemented in GFW - kc22, - kc24, - kc26, - kc28, - kc22etagap, - - // Count the total number of enum - kCount_ExtraProfile - }; - - // 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&) // Initialization - { - ccdb->setURL(url.value); - ccdb->setCaching(true); - ccdb->setCreatedNotAfter(nolaterthan.value); - - // Add some output objects to the histogram registry - registry.add("hEventCount", "Number of Events;; Count", {HistType::kTH1D, {{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, "after additional event cut"); - registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "after correction loads"); - registry.add("hPhi", "", {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, {{3000, 0.5, 3000.5}}}); - registry.add("hCent", "Centrality distribution", {HistType::kTH1D, {{90, 0, 90}}}); - registry.add("cent_vs_Nch", ";Centrality (%); M (|#eta| < 0.8);", {HistType::kTH2D, {axisCentrality, axisNch}}); - - // 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("multITSnoTPC_vs_MultITSTPC_Bef", " multiplicity ITS vs multiplicity ITS+TPC", kTH2F, {axisNch, axisNch}); - registry.add("multITSonly_vs_MultITSTPC_Bef", " multiplicity ITS vs multiplicity ITS+TPC", kTH2F, {axisNch, axisNch}); - registry.add("multNTracksITSonly_vs_MultNTracksITSTPC_Bef", " multiplicity ITS vs multiplicity ITS+TPC", kTH2F, {axisNch, axisNch}); - registry.add("multNTracksTPConly_vs_MultNtracksITSTPC_Bef", " multiplicity TPC only vs multiplicity ITS+TPC", kTH2F, {axisNch, axisNch}); - - // 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("multITSnoTPC_vs_MultITSTPC_Aft", " multiplicity ITS vs multiplicity ITS+TPC", kTH2F, {axisNch, axisNch}); - registry.add("multITSonly_vs_MultITSTPC_Aft", " multiplicity ITS vs multiplicity ITS+TPC", kTH2F, {axisNch, axisNch}); - registry.add("multNTracksITSonly_vs_MultNTracksITSTPC_Aft", " multiplicity ITS vs multiplicity ITS+TPC", kTH2F, {axisNch, axisNch}); - registry.add("multNTracksTPConly_vs_MultNtracksITSTPC_Aft", " multiplicity TPC only vs multiplicity ITS+TPC", kTH2F, {axisNch, 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}}}); - - // 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}}); - - // 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}}); - } - - 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(); - 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)); - 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); - } - - } // 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 (TMath::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 (TMath::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 (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(o2::aod::mult::MultNTracksPV, TCollision collision, const int multTrk, 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; - } - 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 (centrality >= 70. || centrality < 0) - return false; - if (abs(vtxz) > cfgCutVertex) - return false; - 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; - - // V0A T0A 5 sigma cut - if (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 = 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(Colls::iterator const& collision, aod::BCsWithTimestamps const&, aodTracks const& tracks) - { - registry.fill(HIST("hEventCount"), 0.5); - if (!collision.sel8()) - return; - - int Ntot = tracks.size(); - if (Ntot < 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); - - Int_t multITSnoTPC = 0, multITSonly = 0, multITSTPC = 0; - - for (auto& track : tracks) { - - if (track.hasITS() && !track.hasTPC()) - multITSnoTPC++; - - if (track.hasITS()) - multITSonly++; - - if (track.hasITS() && track.hasTPC()) - multITSTPC++; - } - - registry.fill(HIST("multITSnoTPC_vs_MultITSTPC_Bef"), multITSTPC, multITSnoTPC); - registry.fill(HIST("multITSonly_vs_MultITSTPC_Bef"), multITSTPC, multITSonly); - registry.fill(HIST("multNTracksITSonly_vs_MultNTracksITSTPC_Bef"), collision.multNTracksITSTPC(), collision.multNTracksITSOnly()); - registry.fill(HIST("multNTracksTPConly_vs_MultNtracksITSTPC_Bef"), collision.multNTracksITSTPC(), collision.multNTracksTPCOnly()); - - const auto cent = collision.centFT0C(); - - if (cfgUseAdditionalEventCut && !eventSelected(o2::aod::mult::MultNTracksPV(), collision, tracks.size(), cent)) - return; - - registry.fill(HIST("hEventCount"), 2.5); - - float vtxz = collision.posZ(); - float l_Random = fRndm->Rndm(); - registry.fill(HIST("hVtxZ"), vtxz); - registry.fill(HIST("hMult"), Ntot); - registry.fill(HIST("hCent"), collision.centFT0C()); - registry.fill(HIST("cent_vs_Nch"), cent, Ntot); - fGFW->Clear(); - - auto bc = collision.bc_as(); - loadCorrections(bc.timestamp()); - registry.fill(HIST("hEventCount"), 3.5); - - // fill event QA - 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("multITSnoTPC_vs_MultITSTPC_Aft"), multITSTPC, multITSnoTPC); - registry.fill(HIST("multITSonly_vs_MultITSTPC_Aft"), multITSTPC, multITSonly); - registry.fill(HIST("multNTracksITSonly_vs_MultNTracksITSTPC_Aft"), collision.multAllTracksITSTPC(), collision.multNTracksITSOnly()); - registry.fill(HIST("multNTracksTPConly_vs_MultNtracksITSTPC_Aft"), collision.multAllTracksITSTPC(), collision.multNTracksTPCOnly()); - - // track weights - float weff = 1, wacc = 1; - int Magnetfield = 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 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("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()); - } - - if (WithinPtRef) - fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); - - } // End of track loop - - // 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); - FillProfile(corrconfigs.at(4), HIST("c22etagap"), cent); - - // Filling Bootstrap Samples - int SampleIndex = static_cast(cfgNbootstrap * l_Random); - FillProfile(corrconfigs.at(0), BootstrapArray[SampleIndex][kc22], cent); - FillProfile(corrconfigs.at(1), BootstrapArray[SampleIndex][kc24], cent); - FillProfile(corrconfigs.at(2), BootstrapArray[SampleIndex][kc26], cent); - FillProfile(corrconfigs.at(3), BootstrapArray[SampleIndex][kc28], cent); - FillProfile(corrconfigs.at(4), BootstrapArray[SampleIndex][kc22etagap], cent); - - // Filling Flow Container - for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { - FillFC(corrconfigs.at(l_ind), cent, l_Random); - } - - } // End of process -}; // End of struct - -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 9a24b1c243c..00000000000 --- a/PWGCF/Flow/Tasks/FlowPbPbTask.cxx +++ /dev/null @@ -1,704 +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 "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 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(cfgUseInteractionRateCut, bool, false, "Use events with low interaction rate") - O2_DEFINE_CONFIGURABLE(cfgCutIR, float, 50.0, "maximum interaction rate (kHz)") - 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") - O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") - O2_DEFINE_CONFIGURABLE(cfgCutOccupancyLow, int, 0, "Low cut on TPC occupancy") - - 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 - }; - 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>; - - // 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; - } - if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { - // no collisions in specified time range - 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(); - auto occupancy = collision.trackOccupancyInTimeRange(); - - 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; - if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) - 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 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 (!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(); - 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 > cfgCutIR) // cut on hadronic rate - return; - gCurrentHadronicRate->Fill(seconds, hadronicRate); - 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/FlowPbPbpikp.cxx b/PWGCF/Flow/Tasks/FlowPbPbpikp.cxx deleted file mode 100644 index 9ad0696091a..00000000000 --- a/PWGCF/Flow/Tasks/FlowPbPbpikp.cxx +++ /dev/null @@ -1,501 +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 this is a code for the elliptic flow of identified hadrons -/// \author prottay das, preet -/// \since 29/05/2024 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.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/TrackSelectionTables.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StepTHn.h" -#include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "ReconstructionDataFormats/Track.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -struct v2ellip { - - // 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", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - - // Confugrable for QA histograms - Configurable onlyTOF{"onlyTOF", false, "only TOF tracks"}; - Configurable onlyTOFHIT{"onlyTOFHIT", false, "accept only TOF hit tracks at high pt"}; - bool onlyTPC = true; - - // 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 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 nsigmaCutTPCPr{"nsigmacutTPCPr", 3.0, "Value of the TPC Nsigma cut for protons"}; - 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 nsigmaCutTOFPr{"nsigmacutTOFPr", 3.0, "Value of the TOF Nsigma cut for protons"}; - Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, "Value of the Combined Nsigma cut"}; - Configurable ismanualDCAcut{"ismanualDCAcut", true, "ismanualDCAcut"}; - Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; - Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; - - // Event selection configurables - Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; - Configurable TVXEvsel{"TVXEvsel", false, "Triggger selection"}; - Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; - - // Configurable for histograms - Configurable nBins{"nBins", 100, "N bins in all histos"}; - ConfigurableAxis binsMultPlot{"binsCent", {201, -0.5f, 200.5f}, "Binning of the centrality axis for plots"}; - - void init(InitContext const&) - { - // Axes - AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm] for plots"}; - AxisSpec axisv2ref = {10, 0, 10, "v2_{ref}"}; - AxisSpec axisv2diff = {14, 0, 14, "v2_{def}"}; - AxisSpec axisphi = {700, 0, 7, "#phi"}; - - // Histograms - // Event selection - rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); - rEventSelection.add("hmult", "Centrality distribution", kTH1F, {{binsMultPlot}}); - - // v2 tprofiles for reference and differential flow - histos.add("profv2ref", "profv2ref", kTProfile, {axisv2ref}); - histos.add("profv2diff_pr_10_20", "profv2diff_pr_10_20", kTProfile, {axisv2diff}); - histos.add("profv2diff_pi_10_20", "profv2diff_pi_10_20", kTProfile, {axisv2diff}); - histos.add("profv2diff_k_10_20", "profv2diff_k_10_20", kTProfile, {axisv2diff}); - - histos.add("profv2diff_pr_20_30", "profv2diff_pr_20_30", kTProfile, {axisv2diff}); - histos.add("profv2diff_pi_20_30", "profv2diff_pi_20_30", kTProfile, {axisv2diff}); - histos.add("profv2diff_k_20_30", "profv2diff_k_20_30", kTProfile, {axisv2diff}); - - histos.add("profv2diff_pr_30_40", "profv2diff_pr_30_40", kTProfile, {axisv2diff}); - histos.add("profv2diff_pi_30_40", "profv2diff_pi_30_40", kTProfile, {axisv2diff}); - histos.add("profv2diff_k_30_40", "profv2diff_k_30_40", kTProfile, {axisv2diff}); - - histos.add("profv2diff_pr_40_50", "profv2diff_pr_40_50", kTProfile, {axisv2diff}); - histos.add("profv2diff_pi_40_50", "profv2diff_pi_40_50", kTProfile, {axisv2diff}); - histos.add("profv2diff_k_40_50", "profv2diff_k_40_50", kTProfile, {axisv2diff}); - - // histogram for phi distribution - histos.add("hphi", "hphi", kTH1F, {axisphi}); - } - - template - bool selectionTrack(const T& candidate) - { - if (ismanualDCAcut && !(candidate.isGlobalTrackWoDCA() && candidate.isPVContributor() && std::abs(candidate.dcaXY()) < cfgCutDCAxy && std::abs(candidate.dcaZ()) < cfgCutDCAz && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { - return false; - } - - return true; - } - - template - bool selectionPID(const T& candidate, int PID) - { - if (candidate.pt() > 0.4) { - onlyTPC = false; - } - - if (PID == 0) { - if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOFPi) { - return true; - } - } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOFPi) { - return true; - } - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { - return true; - } - } else if (onlyTPC) { - if (std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { - return true; - } - } else { - 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 (onlyTPC) { - if (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; - } - } - } else if (PID == 2) { - if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOFPr) { - return true; - } - } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOFPr) { - return true; - } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCPr) { - return true; - } - } else if (onlyTPC) { - if (std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCPr) { - return true; - } - } else { - if (candidate.hasTOF() && (candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < (nsigmaCutCombined * nsigmaCutCombined)) { - return true; - } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCPr) { - return true; - } - } - } - return false; - } - - // Defining filters for events (event selection) - // Processed events will be already fulfilling the event selection - // requirements - - 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); - - using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; - - // Defining partitions for subevents for eta-gap method - Partition Atracks = (aod::track::eta > 0.4f) && (aod::track::eta < 0.8f); // partition for subevent A - Partition Btracks = (aod::track::eta < -0.4f) && (aod::track::eta > -0.8f); // partition for subevent B - - array ptbins = {0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0, 3.5, 4.0, 4.5, 5.0}; - - void processSE(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) - - { - float sum_sinA = 0.0, sum_cosA = 0.0, sum_sinB = 0.0, sum_cosB = 0.0; - int multA = 0, multB = 0; - - // Q vector elements - array sum_sindsA = {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}; // sin component of Q vector for subevent A - array sum_cosdsA = {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}; // cos component of Q vector for subevent A - array sum_sindsB = {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}; // sin component of Q vector for subevent B - array sum_cosdsB = {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}; // cos component of Q vector for subevent B - - // p vector definitions for subevent A - array pn_sumsinA_pr = {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}; // to store ptwise pn vector components for proton - array pn_sumcosA_pr = {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}; // to store ptwise pn vector components for proton - - array pn_sumsinA_pi = {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}; // to store ptwise pn vector components for pion - array pn_sumcosA_pi = {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}; // to store ptwise pn vector components for pion - - array pn_sumsinA_k = {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}; // to store ptwise pn vector components for kaon - array pn_sumcosA_k = {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}; // to store ptwise pn vector components for kaon - - // p vector definitions for subevent B - array pn_sumsinB_pr = {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}; // to store ptwise pn vector components for proton - array pn_sumcosB_pr = {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}; // to store ptwise pn vector components for proton - - array pn_sumsinB_pi = {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}; // to store ptwise pn vector components for pion - array pn_sumcosB_pi = {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}; // to store ptwise pn vector components for pion - - array pn_sumsinB_k = {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}; // to store ptwise pn vector components for kaon - array pn_sumcosB_k = {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}; // to store ptwise pn vector components for kaon - - // POI multiplicities - array mpA_pr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // proton multiplicity for subevent A - array mpB_pr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // proton multiplicity for subevent B - - array mpA_pi = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // pion multiplicity for subevent A - array mpB_pi = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // pion multiplicity for subevent B - - array mpA_k = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // kaon multiplicity for subevent A - array mpB_k = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // kaon multiplicity for subevent B - - if (!collision.sel8()) { - return; - } - - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { - return; - } - - if (TVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { - return; - } - - float multiplicity = 0.0f; - multiplicity = collision.centFT0C(); - - // Fill the event counter - rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - rEventSelection.fill(HIST("hmult"), multiplicity); - - auto atrack = Atracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto btrack = Btracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - - for (auto track : tracks) { - if (!selectionTrack(track)) { - continue; - } - if (selectionPID(track, 0) || selectionPID(track, 1) || selectionPID(track, 2)) { // If track pion, kaon or proton - histos.fill(HIST("hphi"), track.phi()); - } else { - continue; - } - } // end of track loop - - for (auto track1 : atrack) { - if (!selectionTrack(track1)) { - continue; - } - - sum_sinA += TMath::Sin(2.0 * track1.phi()); // sum of sin components of Q vector - sum_cosA += TMath::Cos(2.0 * track1.phi()); // sum of cos components of Q vector - multA++; // charged particle multiplicity - - if (selectionPID(track1, 0) || selectionPID(track1, 1) || selectionPID(track1, 2)) { // If track pion, kaon or proton - // pt loop for component sums of p vector, POI multiplicities pt wise - for (auto pt = 0; pt < 14; pt++) { - sum_sindsA[pt] += TMath::Sin(2 * track1.phi()); - sum_cosdsA[pt] += TMath::Cos(2 * track1.phi()); - - if (track1.pt() > ptbins[pt] && track1.pt() <= ptbins[pt + 1] && selectionPID(track1, 0)) { // for pion - pn_sumsinA_pi[pt] += TMath::Sin(2 * track1.phi()); - pn_sumcosA_pi[pt] += TMath::Cos(2 * track1.phi()); - mpA_pi[pt]++; - } else if (track1.pt() > ptbins[pt] && track1.pt() <= ptbins[pt + 1] && selectionPID(track1, 1)) { // for kaon - pn_sumsinA_k[pt] += TMath::Sin(2 * track1.phi()); - pn_sumcosA_k[pt] += TMath::Cos(2 * track1.phi()); - mpA_k[pt]++; - } else if (track1.pt() > ptbins[pt] && track1.pt() <= ptbins[pt + 1] && selectionPID(track1, 2)) { // for proton - pn_sumsinA_pr[pt] += TMath::Sin(2 * track1.phi()); - pn_sumcosA_pr[pt] += TMath::Cos(2 * track1.phi()); - mpA_pr[pt]++; - } else { - continue; - } - } // end of pt loop - } else { - continue; - } - } // track loop ends - - for (auto track2 : btrack) { - if (!selectionTrack(track2)) { - continue; - } - - sum_sinB += TMath::Sin(2.0 * track2.phi()); // sum of sin components of Q vector - sum_cosB += TMath::Cos(2.0 * track2.phi()); // sum of cos components of Q vector - multB++; // charged particle multiplicity - - if (selectionPID(track2, 0) || selectionPID(track2, 1) || selectionPID(track2, 2)) { // If track pion, kaon or proton - // pt loop for component sums of p vector, POI multiplicities pt wise - for (auto pt = 0; pt < 14; pt++) { - sum_sindsB[pt] += TMath::Sin(2 * track2.phi()); - sum_cosdsB[pt] += TMath::Cos(2 * track2.phi()); - - if (track2.pt() > ptbins[pt] && track2.pt() <= ptbins[pt + 1] && selectionPID(track2, 0)) { // for pion - pn_sumsinB_pi[pt] += TMath::Sin(2 * track2.phi()); - pn_sumcosB_pi[pt] += TMath::Cos(2 * track2.phi()); - mpB_pi[pt]++; - } else if (track2.pt() > ptbins[pt] && track2.pt() <= ptbins[pt + 1] && selectionPID(track2, 1)) { // for kaon - pn_sumsinB_k[pt] += TMath::Sin(2 * track2.phi()); - pn_sumcosB_k[pt] += TMath::Cos(2 * track2.phi()); - mpB_k[pt]++; - } else if (track2.pt() > ptbins[pt] && track2.pt() <= ptbins[pt + 1] && selectionPID(track2, 2)) { // for proton - pn_sumsinB_pr[pt] += TMath::Sin(2 * track2.phi()); - pn_sumcosB_pr[pt] += TMath::Cos(2 * track2.phi()); - mpB_pr[pt]++; - } else { - continue; - } - } // end of pt loop - } else { - continue; - } - } // track loop ends - - if (10.0 < multiplicity && multiplicity <= 20.0) { - // reference flow - if ((multA * multB) != 0) { - histos.fill(HIST("profv2ref"), 1, ((sum_cosA * sum_cosB + sum_sinA * sum_sinB) / (multA * multB)), multA * multB); - } - - // pt wise differential flow - for (auto pt = 0; pt < 14; pt++) { - if ((mpA_pr[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_pr_10_20"), pt + 1, ((pn_sumcosA_pr[pt] * sum_cosB + pn_sumsinA_pr[pt] * sum_sinB) / (mpA_pr[pt] * multB)), mpA_pr[pt] * multB); - } // for proton - if ((mpA_pi[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_pi_10_20"), pt + 1, ((pn_sumcosA_pi[pt] * sum_cosB + pn_sumsinA_pi[pt] * sum_sinB) / (mpA_pi[pt] * multB)), mpA_pi[pt] * multB); - } // for pion - if ((mpA_k[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_k_10_20"), pt + 1, ((pn_sumcosA_k[pt] * sum_cosB + pn_sumsinA_k[pt] * sum_sinB) / (mpA_k[pt] * multB)), mpA_k[pt] * multB); - } // for kaon - } - } // 10 to 20 percent centrality - - if (20.0 < multiplicity && multiplicity <= 30.0) { - // reference flow - if ((multA * multB) != 0) { - histos.fill(HIST("profv2ref"), 2, ((sum_cosA * sum_cosB + sum_sinA * sum_sinB) / (multA * multB)), multA * multB); - } - - // pt wise differential flow - for (auto pt = 0; pt < 14; pt++) { - if ((mpA_pr[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_pr_20_30"), pt + 1, ((pn_sumcosA_pr[pt] * sum_cosB + pn_sumsinA_pr[pt] * sum_sinB) / (mpA_pr[pt] * multB)), mpA_pr[pt] * multB); - } // for proton - if ((mpA_pi[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_pi_20_30"), pt + 1, ((pn_sumcosA_pi[pt] * sum_cosB + pn_sumsinA_pi[pt] * sum_sinB) / (mpA_pi[pt] * multB)), mpA_pi[pt] * multB); - } // for pion - if ((mpA_k[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_k_20_30"), pt + 1, ((pn_sumcosA_k[pt] * sum_cosB + pn_sumsinA_k[pt] * sum_sinB) / (mpA_k[pt] * multB)), mpA_k[pt] * multB); - } // for kaon - } - } // 20 to 30 percent centrality - - if (30.0 < multiplicity && multiplicity <= 40.0) { - // reference flow - if ((multA * multB) != 0) { - histos.fill(HIST("profv2ref"), 3, ((sum_cosA * sum_cosB + sum_sinA * sum_sinB) / (multA * multB)), multA * multB); - } - - // pt wise differential flow - for (auto pt = 0; pt < 14; pt++) { - if ((mpA_pr[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_pr_30_40"), pt + 1, ((pn_sumcosA_pr[pt] * sum_cosB + pn_sumsinA_pr[pt] * sum_sinB) / (mpA_pr[pt] * multB)), mpA_pr[pt] * multB); - } // for proton - if ((mpA_pi[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_pi_30_40"), pt + 1, ((pn_sumcosA_pi[pt] * sum_cosB + pn_sumsinA_pi[pt] * sum_sinB) / (mpA_pi[pt] * multB)), mpA_pi[pt] * multB); - } // for pion - if ((mpA_k[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_k_30_40"), pt + 1, ((pn_sumcosA_k[pt] * sum_cosB + pn_sumsinA_k[pt] * sum_sinB) / (mpA_k[pt] * multB)), mpA_k[pt] * multB); - } // for kaon - } - } // 30 to 40 percent centrality - - if (40.0 < multiplicity && multiplicity <= 50.0) { - // reference flow - if ((multA * multB) != 0) { - histos.fill(HIST("profv2ref"), 4, ((sum_cosA * sum_cosB + sum_sinA * sum_sinB) / (multA * multB)), multA * multB); - } - - // pt wise differential flow - for (auto pt = 0; pt < 14; pt++) { - if ((mpA_pr[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_pr_40_50"), pt + 1, ((pn_sumcosA_pr[pt] * sum_cosB + pn_sumsinA_pr[pt] * sum_sinB) / (mpA_pr[pt] * multB)), mpA_pr[pt] * multB); - } // for proton - if ((mpA_pi[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_pi_40_50"), pt + 1, ((pn_sumcosA_pi[pt] * sum_cosB + pn_sumsinA_pi[pt] * sum_sinB) / (mpA_pi[pt] * multB)), mpA_pi[pt] * multB); - } // for pion - if ((mpA_k[pt] * multB) != 0) { - histos.fill(HIST("profv2diff_k_40_50"), pt + 1, ((pn_sumcosA_k[pt] * sum_cosB + pn_sumsinA_k[pt] * sum_sinB) / (mpA_k[pt] * multB)), mpA_k[pt] * multB); - } // for kaon - } - } // 40 to 50 percent centrality - - if (50.0 < multiplicity && multiplicity <= 60.0) { - // reference flow - if ((multA * multB) != 0) { - histos.fill(HIST("profv2ref"), 5, ((sum_cosA * sum_cosB + sum_sinA * sum_sinB) / (multA * multB)), multA * multB); - } - } // 50 to 60 percent centrality - - if (60.0 < multiplicity && multiplicity <= 70.0) { - // reference flow - if ((multA * multB) != 0) { - histos.fill(HIST("profv2ref"), 6, ((sum_cosA * sum_cosB + sum_sinA * sum_sinB) / (multA * multB)), multA * multB); - } - } // 60 to 70 percent centrality - - if (70.0 < multiplicity && multiplicity <= 80.0) { - // reference flow - if ((multA * multB) != 0) { - histos.fill(HIST("profv2ref"), 7, ((sum_cosA * sum_cosB + sum_sinA * sum_sinB) / (multA * multB)), multA * multB); - } - } // 70 to 80 percent centrality - - } // end of process - - PROCESS_SWITCH(v2ellip, processSE, "Process Same event", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/PWGCF/Flow/Tasks/FlowZDCtask.cxx b/PWGCF/Flow/Tasks/FlowZDCtask.cxx deleted file mode 100644 index 641ef3cb1e5..00000000000 --- a/PWGCF/Flow/Tasks/FlowZDCtask.cxx +++ /dev/null @@ -1,325 +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 "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 ColEvSels = soa::Join; -using aodCollisions = soa::Filtered>; -using aodTracks = soa::Filtered>; -using BCsRun3 = soa::Join; -using aodZDCs = soa::Join; - -#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, 3.0f, "Maximal pT for ref tracks") - O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.9f, "Eta range for tracks") // changed from .8 bc zdc is at eta 8.78 - 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") - - Configurable nBinsPt{"nBinsPt", 100, "N bins in pT histo"}; - Configurable eventSelection{"eventSelection", 1, "event selection"}; - Configurable MaxZP{"MaxZP", 3099.5, "Max ZP signal"}; - Configurable vtxCut{"vtxCut", 10.0, "Z vertex cut"}; - Configurable etaCut{"etaCut", 0.8, "Eta cut"}; - Configurable etaGap{"etaGap", 0.5, "Eta gap"}; - Configurable minPt{"minPt", 0.2, "Minimum pt"}; - Configurable maxPt{"maxPt", 20.0, "Maximum pt"}; - Configurable MaxZEM{"MaxZEM", 3099.5, "Max ZEM signal"}; - // for ZDC info and analysis - Configurable nBinsADC{"nBinsADC", 1000, "nbinsADC"}; - Configurable nBinsAmp{"nBinsAmp", 1025, "nbinsAmp"}; - Configurable MaxZN{"MaxZN", 4099.5, "Max ZN signal"}; - - 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"}; - - 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); - - Partition tracksIUWithTPC = (aod::track::tpcNClsFindable > (uint8_t)0); - - TComplex qTPC; // init q TPC - TComplex qZNA{0, 0}; // init qZNA - TComplex qZNC{0, 0}; // init qZNC - - // Begin Histogram Registry - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - OutputObj Q2_real_mean{TProfile("Q2_real_mean", "q2 real vs centrality", 10, 0, 100.)}; - OutputObj Q2_imag_mean{TProfile("Q2_imag_mean", "q2 imag vs centrality", 10, 0, 100.)}; - OutputObj Q2_after{TProfile("Q2_after", "q2 recentered vs centrality", 10, 0, 100.)}; - OutputObj Q2before{TProfile("Q2_imag_mean", "q2 re vs imag", 10, 0, 100.)}; - OutputObj Q2_ZNA_real{TProfile("Q2_ZNA_real", "q2_ZNA real vs centrality", 10, 0, 100.)}; - OutputObj Q2_ZNA_imag{TProfile("Q2_ZNA_imag", "q2_ZNA imag vs centrality", 10, 0, 100.)}; - OutputObj Q2_ZNC_real{TProfile("Q2_ZNC_real", "q2_ZNC real vs centrality", 10, 0, 100.)}; - OutputObj Q2_ZNC_imag{TProfile("Q2_ZNC_imag", "q2_ZNC imag vs centrality", 10, 0, 100.)}; - OutputObj avgQ2TPCRe{TProfile("avgQ2TPCRe", "Average Q2 Real part vs Centrality", 10, 0, 100)}; - OutputObj avgQ2TPCIm{TProfile("avgQ2TPCIm", "Average Q2 Imaginary part vs Centrality", 10, 0, 100)}; - OutputObj ZDC_ZEM_Energy{TProfile("ZDC_ZEM_Energy", "ZDC vs ZEM Energy", 10, 0, 1000)}; - 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)}; - - 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 axisEta{30, -1.5, +1.5, "#eta"}; - const AxisSpec axispt{100, 0, 2, "#pt"}; - - const AxisSpec axisPt{nBinsPt, 0, 10, "p_{T} (GeV/c)"}; - const AxisSpec axisCounter{1, 0, +1, ""}; - const AxisSpec axisPhi{100, 0, 2 * TMath::Pi(), "#phi"}; - const AxisSpec axisQ{100, -1, 1, "Q"}; - const AxisSpec axisZNA{100, 0, 200, "energy"}; - const AxisSpec axisQZNA{100, -1, 1, "Q"}; - const AxisSpec axisREQ{100, -1, 1, "real Q"}; - const AxisSpec axisIMQ{100, -1, 1, "imag Q"}; - const AxisSpec axisEnergy{100, 0, 50, "energy"}; - - AxisSpec axisVtxcounts{2, -0.5f, 1.5f, "Vtx info (0=no, 1=yes)"}; - AxisSpec axisZvert{120, -30.f, 30.f, "Vtx z (cm)"}; - AxisSpec axisCent{8, 0.f, 100.f, "centrality"}; - AxisSpec axisMult{1000, -0.5f, 1500.5f, "multiplicity"}; - AxisSpec axisMultTPC{1000, -0.5f, 1999.5f, "TPCmultiplicity"}; - AxisSpec axisCentBins{{0, 5., 10., 20., 30., 40., 50., 60., 70., 80.}, "centrality percentile"}; - AxisSpec axisPtBins{{0., 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.25, 2.5, 2.75, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 8.0, 10., 13., 16., 20.}, "p_{T} (GeV/c)"}; - - // 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, {axisMult}); - histos.add("multvsCent", "centrality vs multiplicity", kTH2F, {axisCent, axisMult}); - 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}); - // for q vector recentering - histos.add("revsimag", "revsimag", kTH2F, {axisREQ, axisIMQ}); - - 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, -TMath::Pi(), TMath::Pi()}}}); - histos.add("SPAngleZNC", "Spectator Plane Angle ZNC;Angle (radians);Entries", {HistType::kTH1F, {{100, -TMath::Pi(), TMath::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("CosPsiDifferencesAvg", "Differences in cos(psi);cos(psiZNC) - cos(psiZNA);Entries", {HistType::kTH2F, {{axisCent}, {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}}}}); - } - } - - void processQVector(aodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, aodTracks const& tracks, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, aod::ZDCMults const& /*zdcMults*/) - { - 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 Ntot = tracks.size(); - - // this is the q vector for the TPC data. it is a complex function - double qTPC_real = 0.0; // Initialize qTPC_real - double qTPC_im = 0.0; // init qTPC_imaginary - - Int_t multTrk = tracks.size(); // Tracks are already filtered with GlobalTrack || GlobalTrackSDD - - if (cent < 0.0 && cent > 70) - return; - TComplex qTPC(0, 0); // Starting with a q-vector of zero - - for (auto& track : tracks) { - double phi = track.phi(); - - histos.fill(HIST("etaHistogram"), track.eta()); - histos.fill(HIST("phiHistogram"), track.phi()); - histos.fill(HIST("ptHistogram"), track.pt()); - - qTPC += TComplex(TMath::Cos(2.0 * phi), TMath::Sin(2.0 * phi)); - - histos.fill(HIST("multvsCent"), cent, Ntot); - - } // end track loop - - qTPC_real = qTPC.Re() / Ntot; // normalize these vectors by the total number of particles - qTPC_im = qTPC.Im() / Ntot; - - histos.fill(HIST("REqHistogram"), qTPC_real); - histos.fill(HIST("IMqHistogram"), qTPC_im); - - histos.fill(HIST("multHistogram"), multTrk); - histos.fill(HIST("TPCmultiplicity"), multTPC); - - histos.fill(HIST("revsimag"), qTPC_real, qTPC_im); - } - void processZdcCollAssoc( - ColEvSels const& cols, - BCsRun3 const& /*bcs*/, - aod::Zdcs const& /*zdcs*/) - { - 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 - // collision-based event selection - for (auto& collision : cols) { - const auto& foundBC = collision.foundBC_as(); - if (foundBC.has_zdc()) { - const auto& zdcread = foundBC.zdc(); - const auto cent = collision.centFT0C(); - - 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()); - - 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(); - histos.get(HIST("ZDC_energy_vs_ZEM"))->Fill(sumZEM, sumZDC); - - const auto Ntot_ZNA = zdcread.amplitudeZNA(); - const auto Ntot_ZNC = zdcread.amplitudeZNC(); - double qZNA_real = 0.0; // Initialize qZNA_real - double qZNA_im = 0.0; // Initialize - double qZNC_real = 0.0; // Initialize qZNC_real - double qZNC_im = 0.0; // Initialize - const double phiRadians[4] = {45 * TMath::Pi() / 180, 135 * TMath::Pi() / 180, 225 * TMath::Pi() / 180, 315 * TMath::Pi() / 180}; - TComplex qZNA(0, 0), qZNC(0, 0); - - for (int sector = 0; sector < 4; ++sector) { - // energy for current sector for ZNA and ZNC - float energyZNA = zdcread.energySectorZNA()[sector]; - float energyZNC = zdcread.energySectorZNC()[sector]; - - // Calculate q-vector from current sector and add it to the total q-vector - qZNA += TComplex(TMath::Cos(2 * phiRadians[sector]) * energyZNA / sumZNA, TMath::Sin(2 * phiRadians[sector]) * energyZNA / sumZNA); - qZNC += TComplex(TMath::Cos(2 * phiRadians[sector]) * energyZNC / sumZNC, TMath::Sin(2 * phiRadians[sector]) * energyZNC / sumZNC); - } - - qZNA_real = qZNA.Re() / Ntot_ZNA; - qZNA_im = qZNA.Im() / Ntot_ZNA; - qZNC_real = qZNC.Re() / Ntot_ZNC; - qZNC_im = qZNC.Im() / Ntot_ZNC; - - histos.fill(HIST("Acorrelations"), qZNA.Re(), qZNA.Im()); - histos.fill(HIST("RealQHistogramZNA"), qZNA_real); - histos.fill(HIST("ImagQHistogramZNA"), qZNA_im); - histos.fill(HIST("RealQHistogramZNC"), qZNC_real); - histos.fill(HIST("ImagQHistogramZNC"), qZNC_im); - - // Calculate the spectator plane angles for ZNA and ZNC - double psiZNA = TMath::ATan2(qZNA.Im(), qZNA.Re()) / 2; - double psiZNC = TMath::ATan2(qZNC.Im(), qZNC.Re()) / 2; - - // Fill the histograms with the calculated angles - histos.fill(HIST("SPAngleZNA"), psiZNA); - histos.fill(HIST("SPAngleZNC"), psiZNC); - - double cosPsiDiff = TMath::Cos(psiZNA) - TMath::Cos(psiZNC); - double sinPsiDiff = TMath::Sin(psiZNA) - TMath::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); - } - } - } - PROCESS_SWITCH(FlowZDCtask, processZdcCollAssoc, "Processing ZDC w. collision association", true); - PROCESS_SWITCH(FlowZDCtask, processQVector, "Process before recentering", true); - -}; // end of struct function - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGCF/Flow/Tasks/flowAnalysisGF.cxx b/PWGCF/Flow/Tasks/flowAnalysisGF.cxx index 4648d8a49e6..08e223befb6 100644 --- a/PWGCF/Flow/Tasks/flowAnalysisGF.cxx +++ b/PWGCF/Flow/Tasks/flowAnalysisGF.cxx @@ -214,8 +214,8 @@ struct flowAnalysisGF { fPtAxis = new TAxis(ptbins, &ptbinning[0]); if (cfgFillWeights) { - fWeights->SetPtBins(ptbins, &ptbinning[0]); - fWeights->Init(true, false); + fWeights->setPtBins(ptbins, &ptbinning[0]); + fWeights->init(true, false); } if (doprocessMCGen) { @@ -286,7 +286,7 @@ struct flowAnalysisGF { fFC->Initialize(oba, multAxis, cfgNbootstrap); delete oba; - fFCpt->Initialise(multAxis, cfgMpar, configs, cfgNbootstrap); + fFCpt->initialise(multAxis, cfgMpar, configs, cfgNbootstrap); // Event selection - Alex if (cfgUseAdditionalEventCut) { @@ -388,7 +388,7 @@ struct flowAnalysisGF { return false; weight_nue = 1. / eff; if (cfg.mAcceptance) - weight_nua = cfg.mAcceptance->GetNUA(phi, eta, vtxz); + weight_nua = cfg.mAcceptance->getNUA(phi, eta, vtxz); else weight_nua = 1; return true; @@ -497,9 +497,9 @@ struct flowAnalysisGF { void FillOutputContainers(datatype dt, 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); 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) @@ -508,7 +508,7 @@ struct flowAnalysisGF { 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]); + fFCpt->fillVnPtProfiles(centmult, val, dnx, rndm, configs.GetpTCorrMasks()[l_ind]); } continue; } @@ -535,7 +535,7 @@ struct flowAnalysisGF { registry.fill(HIST("hEventCount"), 9.5); float vtxz = collision.posZ(); fGFW->Clear(); - fFCpt->ClearVector(); + fFCpt->clearVector(); float l_Random = fRndm->Rndm(); std::vector ITS_TPC_tracks(6, 0); @@ -582,7 +582,7 @@ struct flowAnalysisGF { return false; if (cfgFillWeights) - fWeights->Fill(particle.phi(), particle.eta(), vtxz, particle.pt(), centrality, 0); + fWeights->fill(particle.phi(), particle.eta(), vtxz, particle.pt(), centrality, 0); if (!setCurrentParticleWeights(weff, wacc, particle.phi(), particle.eta(), particle.pt(), vtxz)) return false; @@ -630,7 +630,7 @@ struct flowAnalysisGF { template inline void FillGFW(TrackObject track, float weff, float wacc) { - fFCpt->Fill(weff, track.pt()); + 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) diff --git a/PWGCF/Flow/Tasks/flowEfficiencyCasc.cxx b/PWGCF/Flow/Tasks/flowEfficiencyCasc.cxx new file mode 100644 index 00000000000..7a6c8a285a7 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowEfficiencyCasc.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 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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/cascqaanalysis.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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 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/flowEsePHe3.cxx b/PWGCF/Flow/Tasks/flowEsePHe3.cxx new file mode 100644 index 00000000000..e94d03f8fcb --- /dev/null +++ b/PWGCF/Flow/Tasks/flowEsePHe3.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. + +/// \author ZhengqingWang(zhengqing.wang@cern.ch) +/// \file flowEsePHe3.cxx +/// \brief task to calculate the P He3 flow correlation. +// C++/ROOT includes. +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// o2Physics includes. +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +namespace o2::aod +{ +namespace ese_var_table +{ +DECLARE_SOA_COLUMN(EseVtz, eseVtz, float); +DECLARE_SOA_COLUMN(EseCentFT0C, eseCentFT0C, float); +DECLARE_SOA_COLUMN(EsePsi2FT0C, esePsi2FT0C, float); +DECLARE_SOA_COLUMN(Eseq2Tar, eseq2Tar, float); +DECLARE_SOA_COLUMN(Eseq2Ref, eseq2Ref, float); +DECLARE_SOA_COLUMN(Eseq2FT0C, eseq2FT0C, float); +DECLARE_SOA_COLUMN(EseTarSign, eseTarSign, int8_t); +DECLARE_SOA_COLUMN(EseTarTPCInnerParam, eseTarTPCInnerParam, float); +DECLARE_SOA_COLUMN(EseTarTPCSignal, eseTarTPCSignal, float); +DECLARE_SOA_COLUMN(EseTarPt, eseTarPt, float); +DECLARE_SOA_COLUMN(EseTarEta, eseTarEta, float); +DECLARE_SOA_COLUMN(EseTarPhi, eseTarPhi, float); +DECLARE_SOA_COLUMN(EseTarDCAxy, eseTarDCAxy, float); +DECLARE_SOA_COLUMN(EseTarDCAz, eseTarDCAz, float); +DECLARE_SOA_COLUMN(EseTarTPCNcls, eseTarTPCNcls, uint8_t); +DECLARE_SOA_COLUMN(EseTarITSNcls, eseTarITSNcls, uint8_t); +DECLARE_SOA_COLUMN(EseTarTPCChi2NDF, eseTarTPCChi2NDF, float); +DECLARE_SOA_COLUMN(EseTarITSChi2NDF, eseTarITSChi2NDF, float); +DECLARE_SOA_COLUMN(EseTarTPCNSigma, eseTarTPCNSigma, float); +DECLARE_SOA_COLUMN(EseTarTOFNSigma, eseTarTOFNSigma, float); +DECLARE_SOA_COLUMN(EseTarITSNSigma, eseTarITSNSigma, float); +DECLARE_SOA_COLUMN(EseTarITSClusSize, eseTarITSClusSize, uint32_t); +} // namespace ese_var_table + +DECLARE_SOA_TABLE(ESETable, "AOD", "ESETable", + ese_var_table::EseVtz, + ese_var_table::EseCentFT0C, + ese_var_table::EsePsi2FT0C, + ese_var_table::Eseq2Tar, + ese_var_table::Eseq2Ref, + ese_var_table::Eseq2FT0C, + ese_var_table::EseTarSign, + ese_var_table::EseTarTPCInnerParam, + ese_var_table::EseTarTPCSignal, + ese_var_table::EseTarPt, + ese_var_table::EseTarEta, + ese_var_table::EseTarPhi, + ese_var_table::EseTarDCAxy, + ese_var_table::EseTarDCAz, + ese_var_table::EseTarTPCNcls, + ese_var_table::EseTarITSNcls, + ese_var_table::EseTarTPCChi2NDF, + ese_var_table::EseTarITSChi2NDF, + ese_var_table::EseTarTPCNSigma, + ese_var_table::EseTarTOFNSigma, + ese_var_table::EseTarITSNSigma, + ese_var_table::EseTarITSClusSize); +} // namespace o2::aod + +struct ESECandidate { + float vtz; + float centFT0C; + float psi2FT0C; + float q2Tar; + float q2Ref; + float q2FT0C; + int8_t signTar; + float tpcInnerParamTar; + float tpcSignalTar; + float ptTar; + float etaTar; + float phiTar; + float dcaXYTar; + float dcaZTar; + uint8_t tpcNclsTar; + uint8_t itsNclsTar; + float tpcChi2NDFTar; + float itsChi2NDFTar; + float tpcNSigmaTar; + float tofNSigmaTar; + float itsNSigmaTar; + uint32_t itsClusSizeTar; +}; + +struct ESEReference { + int8_t signRef; + float ptRef; + float v2Ref; +}; + +namespace ese_parameters +{ +constexpr uint8_t kProton = 0; +constexpr uint8_t kDeuteron = 1; +constexpr uint8_t kTriton = 2; +constexpr uint8_t kHe3 = 3; +constexpr uint8_t kAlpha = 4; +constexpr uint8_t kPion = 5; +constexpr uint8_t kKaon = 6; +constexpr uint8_t kHadron = 7; +constexpr int kFT0AV0ASigma = 5; +constexpr int kRMSMode = 0; +constexpr int kTPCMode = 1; +constexpr int kTOFOnlyMode = 2; +constexpr float Amplitudelow = 1e-8; +constexpr float Charges[8]{1.f, 1.f, 1.f, 2.f, 2.f, 1.f, 1.f, 1.f}; +constexpr float Masses[5]{MassProton, MassDeuteron, MassTriton, MassHelium3, MassAlpha}; +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 BbMomScalingDefault[5][2]{// 0:poscharged 1:negcharged + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}}; +constexpr int Open3DPIDPlots[3][1]{ + {0}, + {0}, + {0}}; +constexpr int OpenEvSel[10][1]{ + {1}, + {1}, + {1}, + {1}, + {1}, + {1}, + {1}, + {1}, + {0}, + {1}}; +constexpr int OpenTrackSel[7][1]{ + {1}, + {1}, + {1}, + {1}, + {1}, + {1}, + {1}}; +constexpr double TPCnSigmaCutDefault[7][2]{ + {-3., 3.}, + {-3., 3.}, + {-3., 3.}, + {-3., 3.}, + {-3., 3.}, + {-3., 3.}, + {-3., 3.}}; +constexpr double ITSnSigmaCutDefault[7][2]{ + {-3., 3.}, + {-3., 3.}, + {-3., 3.}, + {-3., 3.}, + {-3., 3.}, + {-3., 3.}, + {-3., 3.}}; +constexpr double POverZPreselection[7][2]{ + {0.15, 99.}, + {0.15, 99.}, + {0.15, 99.}, + {0.15, 99.}, + {0.15, 99.}, + {0.15, 99.}, + {0.15, 99.}}; +constexpr double EtaPreselection[7][2]{ + {0.9}, + {0.9}, + {0.9}, + {0.8}, + {0.9}, + {0.9}, + {0.9}}; +constexpr double TPCNclsPreselection[7][2]{ + {50, 160}, + {50, 160}, + {50, 160}, + {100, 160}, + {50, 160}, + {50, 160}, + {50, 160}}; +constexpr double ITSNclsPreselection[7][2]{ + {5, 7}, + {5, 7}, + {5, 7}, + {5, 7}, + {5, 7}, + {5, 7}, + {5, 7}}; +constexpr double TPCChi2Preselection[7][2]{ + {0, 10}, + {0, 10}, + {0, 10}, + {0.5, 4}, + {0, 10}, + {0, 10}, + {0, 10}}; +constexpr double ITSChi2Preselection[7][2]{ + {0, 36}, + {0, 36}, + {0, 36}, + {0, 36}, + {0, 36}, + {0, 36}, + {0, 36}}; +constexpr double DCAxyPreselection[7][2]{ + {1}, + {1}, + {1}, + {0.1}, + {1}, + {1}, + {1}, +}; +constexpr double DCAzPreselection[7][2]{ + {5}, + {5}, + {5}, + {1}, + {5}, + {5}, + {5}, +}; +static const std::vector names{"proton", "deuteron", "triton", "He3", "alpha"}; +static const std::vector namesFull{"proton", "deuteron", "triton", "He3", "alpha", "pion", "kaon"}; +static const std::vector chargeLabelNames{"Positive", "Negative"}; +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +static const std::vector plot3DPIDNames{"TOF vs ITS", "ITS vs TPC", "TOF vs TPC"}; +static const std::vector openEventSelNames{"EvSelkIsGoodZvtxFT0vsPV", "EvSelkNoSameBunchPileup", "EvSelkNoCollInTimeRangeStandard", "EvSelkIsGoodITSLayersAll", "EvSelkNoCollInRofStandard", "EvSelkNoHighMultCollInPrevRof", "EvSelOccupancy", "EvSelMultCorrelationPVTracks", "EvSelMultCorrelationGlobalTracks", "EvSelV0AT0ACut"}; +static const std::vector openTrackSelNames{"passedITSNCls", "passedITSChi2NDF", "passedITSHits", "passedTPCChi2NDF", "passedTPCCrossedRowsOverNCls", "passedDCAxy", "passedDCAz"}; +static const std::vector plot3DConfigNames{"Open related 3D nSigma plots"}; +static const std::vector openEventSelConfigNames{"Open related event selection options"}; +static const std::vector openTrackSelConfigNames{"Open track selection from TrackSelection table"}; +static const std::vector pidTPCnSigmaNames{"n#sigma_{TPC} Low", "n#sigma_{TPC} High"}; +static const std::vector pidITSnSigmaNames{"n#sigma_{ITS} Low", "n#sigma_{ITS} High"}; +static const std::vector pidPOverZNames{"p/z Low", "p/z High"}; +static const std::vector pidEtaNames{"Abs Eta Max"}; +static const std::vector pidTPCNclsNames{"TPCNcls Low", "TPCNcls High"}; +static const std::vector pidITSNclsNames{"ITSNcls Low", "ITSNcls High"}; +static const std::vector pidTPCChi2Names{"TPCChi2 Low", "TPCChi2 High"}; +static const std::vector pidITSChi2Names{"ITSChi2 Low", "ITSChi2 High"}; +static const std::vector pidDCAxyNames{"Abs DCAxy Max"}; +static const std::vector pidDCAzNames{"Abs DCAz Max"}; +std::vector eseCandidates; +std::vector eseReferences; +// Tar ptr +std::shared_ptr hPIDQATar1D[12]; +std::shared_ptr hPIDQATar2D[4]; +std::shared_ptr hPIDQATar3D[3]; +std::shared_ptr hv2Tar[2]; +std::shared_ptr hESEQATar1D[8]; +std::shared_ptr hESEQATar2D[2]; +std::shared_ptr hESETar; +// Ref ptr +std::shared_ptr hPIDQARef1D[12]; +std::shared_ptr hPIDQARef2D[4]; +std::shared_ptr hPIDQARef3D[3]; +std::shared_ptr hv2Ref[2]; +std::shared_ptr hESEQARef1D[8]; +std::shared_ptr hESEQARef2D[2]; +// FT0C general q2 QA +std::shared_ptr hESEQAFT0C1D[2]; +std::shared_ptr hESEQAFT0C2D[2]; +} // namespace ese_parameters + +using TracksPIDFull = soa::Join; + +struct FlowEsePHe3 { + + EventPlaneHelper helperEP; + o2::aod::ITSResponse itsResponse; + HistogramRegistry histsESE{"histsESE", {}, OutputObjHandlingPolicy::AnalysisObject}; + // process POI control + Configurable cfgTarName{"cfgTarName", "kHe3", "Name of the v2 particle: kProton, kDeuteron, kTriton, kHe3, kAlpha"}; + Configurable cfgRefName{"cfgRefName", "kProton", "Name of the q2 reference particle: kProton, kDeuteron, kTriton, kHe3, kAlpha"}; + // total control config + Configurable cfgOpenAllowCrossTrack{"cfgOpenAllowCrossTrack", true, "Allow one track to be identified as different kind of PID particles"}; + Configurable cfgOpenFullEventQA{"cfgOpenFullEventQA", true, "Open full QA plots for event QA"}; + Configurable cfgOpenPIDQA{"cfgOpenPIDQA", true, "Open PID QA plots"}; + Configurable cfgOpenv2Tar{"cfgOpenv2Tar", true, "Open v2(EP) for Tar patricle"}; + Configurable cfgOpenv2Ref{"cfgOpenv2Ref", true, "Open v2(EP) for Ref patricle"}; + Configurable cfgOpenESE{"cfgOpenESE", true, "Open ESE plots"}; + Configurable cfgOpenESEQA{"cfgOpenESEQA", true, "Open ESE QA plots"}; + Configurable> cfgOpen3DPIDPlots{"cfgOpen3DPIDPlots", {ese_parameters::Open3DPIDPlots[0], 3, 1, ese_parameters::plot3DPIDNames, ese_parameters::plot3DConfigNames}, "3D PID QA Plots switch configuration"}; + // Qvec configs + 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"}; + // pre event selection(filter) + Configurable cfgVtzCut{"cfgVtzCut", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCentMin{"cfgCentMin", 0.0f, "Centrality min"}; + Configurable cfgCentMax{"cfgCentMax", 100.0f, "Centrality max"}; + // event selection configs + Configurable cfgCutOccupancyLow{"cfgCutOccupancyLow", 0, "Low boundary cut on TPC occupancy"}; + Configurable cfgCutOccupancyHigh{"cfgCutOccupancyHigh", 3000, "High boundary cut on TPC occupancy"}; + Configurable> cfgOpenEvSel{"cfgOpenEvSel", {ese_parameters::OpenEvSel[0], 10, 1, ese_parameters::openEventSelNames, ese_parameters::openEventSelConfigNames}, "Event selection switch configuration"}; + // track selection configs + Configurable> cfgOpenTrackSel{"cfgOpenTrackSel", {ese_parameters::OpenTrackSel[0], 7, 1, ese_parameters::openTrackSelNames, ese_parameters::openTrackSelConfigNames}, "Track selection switch configuration"}; + 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.9, "Maximum track #eta for PID"}; + Configurable cfgMinTPCChi2NCl{"cfgMinTPCChi2NCl", 0, "Minimum chi2 per cluster TPC for PID if not use costom track cuts"}; + Configurable cfgMinChi2NClITS{"cfgMinChi2NClITS", 0, "Minimum chi2 per cluster ITS for PID if not use costom track cuts"}; + Configurable cfgMaxTPCChi2NCl{"cfgMaxTPCChi2NCl", 4, "Maximum chi2 per cluster TPC for PID if not use costom track cuts"}; + Configurable cfgMaxChi2NClITS{"cfgMaxChi2NClITS", 36, "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 cfgPtMaxforTPCOnlyPIDProton{"cfgPtMaxforTPCOnlyPIDProton", 0.4, "Maxmium track pt for TPC only PID, at RMS PID mode for proton"}; + Configurable cfgPtMaxforTPCOnlyPIDPion{"cfgPtMaxforTPCOnlyPIDPion", 0.4, "Maxmium track pt for TPC only PID, at RMS PID mode for pion"}; + Configurable cfgPtMaxforTPCOnlyPIDKaon{"cfgPtMaxforTPCOnlyPIDKaon", 0.4, "Maxmium track pt for TPC only PID, at RMS PID mode for kaon"}; + // PID configs + Configurable cfgOpenITSPreselection{"cfgOpenITSPreselection", false, "Use nSigma ITS preselection for light nuclei"}; + Configurable> cfgPOverZPreselection{"cfgPOverZPreselection", {ese_parameters::POverZPreselection[0], 7, 2, ese_parameters::namesFull, ese_parameters::pidPOverZNames}, "P/Z preselection for light nuclei"}; + Configurable> cfgEtaPreselection{"cfgEtaPreselection", {ese_parameters::EtaPreselection[0], 7, 1, ese_parameters::namesFull, ese_parameters::pidEtaNames}, "Eta preselection for light nuclei"}; + Configurable> cfgTPCNclsPreselection{"cfgTPCNclsPreselection", {ese_parameters::TPCNclsPreselection[0], 7, 2, ese_parameters::namesFull, ese_parameters::pidTPCNclsNames}, "TPCNcls preselection for light nuclei"}; + Configurable> cfgITSNclsPreselection{"cfgITSNclsPreselection", {ese_parameters::ITSNclsPreselection[0], 7, 2, ese_parameters::namesFull, ese_parameters::pidITSNclsNames}, "ITSNcls preselection for light nuclei"}; + Configurable> cfgTPCChi2Preselection{"cfgTPCChi2Preselection", {ese_parameters::TPCChi2Preselection[0], 7, 2, ese_parameters::namesFull, ese_parameters::pidTPCChi2Names}, "TPCChi2 preselection for light nuclei"}; + Configurable> cfgITSChi2Preselection{"cfgITSChi2Preselection", {ese_parameters::ITSChi2Preselection[0], 7, 2, ese_parameters::namesFull, ese_parameters::pidITSChi2Names}, "ITSChi2 preselection for light nuclei"}; + Configurable> cfgDCAxyPreselection{"cfgDCAxyPreselection", {ese_parameters::DCAxyPreselection[0], 7, 1, ese_parameters::namesFull, ese_parameters::pidDCAxyNames}, "DCAxy preselection for light nuclei"}; + Configurable> cfgDCAzPreselection{"cfgDCAzPreselection", {ese_parameters::DCAzPreselection[0], 7, 1, ese_parameters::namesFull, ese_parameters::pidDCAzNames}, "DCAz preselection for light nuclei"}; + Configurable> cfgnSigmaCutTOFProton{"cfgnSigmaCutTOFProton", {-1.5, 1.5}, "TOF nsigma cut limit for Proton"}; + Configurable> cfgnSigmaCutRMSProton{"cfgnSigmaCutRMSProton", {-3, 3}, "RMS nsigma cut limit for Proton"}; + Configurable> cfgnSigmaCutTOFPion{"cfgnSigmaCutTOFPion", {-1.5, 1.5}, "TOF nsigma cut limit for Pion"}; + Configurable> cfgnSigmaCutRMSPion{"cfgnSigmaCutRMSPion", {-3, 3}, "RMS nsigma cut limit for Pion"}; + Configurable> cfgnSigmaCutTOFKaon{"cfgnSigmaCutTOFKaon", {-1.5, 1.5}, "TOF nsigma cut limit for Kaon"}; + Configurable> cfgnSigmaCutRMSKaon{"cfgnSigmaCutRMSKaon", {-3, 3}, "RMS nsigma cut limit for Kaon"}; + Configurable cfgUseSelfnSigmaTPCProton{"cfgUseSelfnSigmaTPCProton", true, "Use self nSigma TPC for Proton PID"}; + Configurable cfgProtonPIDMode{"cfgProtonPIDMode", 2, "Proton PID mode: 0 for TPC + RMS(TPC,TOF), 1 for TPC only, 2 for TOF only"}; + Configurable cfgPionPIDMode{"cfgPionPIDMode", 2, "Pion PID mode: 0 for TPC + RMS(TPC,TOF), 1 for TPC only, 2 for TOF only"}; + Configurable cfgKaonPIDMode{"cfgKaonPIDMode", 2, "Kaon PID mode: 0 for TPC + RMS(TPC,TOF), 1 for TPC only, 2 for TOF only"}; + Configurable> cfgnSigmaTPC{"cfgnSigmaTPC", {ese_parameters::TPCnSigmaCutDefault[0], 7, 2, ese_parameters::namesFull, ese_parameters::pidTPCnSigmaNames}, "TPC nSigma selection for light nuclei"}; + Configurable> cfgnSigmaITS{"cfgnSigmaITS", {ese_parameters::ITSnSigmaCutDefault[0], 7, 2, ese_parameters::namesFull, ese_parameters::pidITSnSigmaNames}, "ITS nSigma selection for light nuclei"}; + // PID BBself paras config + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {ese_parameters::BetheBlochDefault[0], 5, 6, ese_parameters::names, ese_parameters::betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; + Configurable> cfgMomentumScalingBetheBloch{"cfgMomentumScalingBetheBloch", {ese_parameters::BbMomScalingDefault[0], 5, 2, ese_parameters::names, ese_parameters::chargeLabelNames}, "TPC Bethe-Bloch momentum scaling for light nuclei"}; + Configurable cfgCompensatePIDinTracking{"cfgCompensatePIDinTracking", true, "If true, divide tpcInnerParam by the electric charge"}; + // Axias configs + 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 cfgaxispt{"cfgaxispt", {100, 0, 10}, "Binning for P_{t}"}; + ConfigurableAxis cfgaxisDCAz{"cfgaxisDCAz", {200, -1, 1}, "Binning for DCAz"}; + ConfigurableAxis cfgaxisDCAxy{"cfgaxisDCAxy", {100, -0.5, 0.5}, "Binning for DCAxy"}; + ConfigurableAxis cfgaxisChi2Ncls{"cfgaxisChi2Ncls", {100, 0, 30}, "Binning for Chi2Ncls TPC/ITS"}; + ConfigurableAxis cfgaxisCent{"cfgaxisCent", {90, 0, 90}, ""}; + ConfigurableAxis cfgaxisq2Tar{"cfgaxisq2Tar", {100, 0, 2}, "Binning for q_{2} traget particle"}; + ConfigurableAxis cfgaxisq2Ref{"cfgaxisq2Ref", {120, 0, 12}, "Binning for q_{2} reference particle"}; + ConfigurableAxis cfgaxisq2FT0C{"cfgaxisq2FT0C", {900, 0, 900}, "Binning for q_{2} FT0C"}; + ConfigurableAxis cfgq2NumeratorTar{"cfgq2NumeratorTar", {20, 0, 2}, "q2 Numerator bin for tar particle"}; + ConfigurableAxis cfgq2NumeratorRef{"cfgq2NumeratorRef", {100, 0, 10}, "q2 Numerator bin for ref particle"}; + ConfigurableAxis cfgq2DenominatorTar{"cfgq2DenominatorTar", {20, 0, 2}, "q2 Denominator bin for tar particle"}; + ConfigurableAxis cfgq2DenominatorRef{"cfgq2DenominatorRef", {50, 0, 5}, "q2 Denominator bin for ref particle"}; + + uint8_t poiTar; + uint8_t poiRef; + int detId; + int refAId; + int refBId; + int detInd; + int refAInd; + int refBInd; + // Function for He3 purity cut refered from luca's slides + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + + Filter collisionFilter = (nabs(aod::collision::posZ) < cfgVtzCut) && (aod::cent::centFT0C > cfgCentMin) && (aod::cent::centFT0C < cfgCentMax); + + Produces eseTable; + + template + float getNSigmaTPCSelfBB(const TrackType track, uint8_t POI) + { + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + float correctedTpcInnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + const int iC{track.sign() < 0}; + switch (POI) { + case ese_parameters::kProton: { + const double bgScaling[2]{ese_parameters::Charges[0] * cfgMomentumScalingBetheBloch->get(0u, 0u) / ese_parameters::Masses[0], ese_parameters::Charges[0] * cfgMomentumScalingBetheBloch->get(0u, 1u) / ese_parameters::Masses[0]}; + double expBethe{tpc::BetheBlochAleph(static_cast(correctedTpcInnerParam * bgScaling[iC]), cfgBetheBlochParams->get(0u, 0u), cfgBetheBlochParams->get(0u, 1u), cfgBetheBlochParams->get(0u, 2u), cfgBetheBlochParams->get(0u, 3u), cfgBetheBlochParams->get(0u, 4u))}; + double expSigma{expBethe * cfgBetheBlochParams->get(0u, 5u)}; + double nSigmaTPC{static_cast((track.tpcSignal() - expBethe) / expSigma)}; + return nSigmaTPC; + } + case ese_parameters::kDeuteron: { + const double bgScaling[2]{ese_parameters::Charges[1] * cfgMomentumScalingBetheBloch->get(1u, 0u) / ese_parameters::Masses[1], ese_parameters::Charges[1] * cfgMomentumScalingBetheBloch->get(1u, 1u) / ese_parameters::Masses[1]}; + double expBethe{tpc::BetheBlochAleph(static_cast(correctedTpcInnerParam * bgScaling[iC]), cfgBetheBlochParams->get(1u, 0u), cfgBetheBlochParams->get(1u, 1u), cfgBetheBlochParams->get(1u, 2u), cfgBetheBlochParams->get(1u, 3u), cfgBetheBlochParams->get(1u, 4u))}; + double expSigma{expBethe * cfgBetheBlochParams->get(1u, 5u)}; + double nSigmaTPC{static_cast((track.tpcSignal() - expBethe) / expSigma)}; + return nSigmaTPC; + } + case ese_parameters::kTriton: { + const double bgScaling[2]{ese_parameters::Charges[2] * cfgMomentumScalingBetheBloch->get(2u, 0u) / ese_parameters::Masses[2], ese_parameters::Charges[2] * cfgMomentumScalingBetheBloch->get(2u, 1u) / ese_parameters::Masses[2]}; + double expBethe{tpc::BetheBlochAleph(static_cast(correctedTpcInnerParam * bgScaling[iC]), cfgBetheBlochParams->get(2u, 0u), cfgBetheBlochParams->get(2u, 1u), cfgBetheBlochParams->get(2u, 2u), cfgBetheBlochParams->get(2u, 3u), cfgBetheBlochParams->get(2u, 4u))}; + double expSigma{expBethe * cfgBetheBlochParams->get(2u, 5u)}; + double nSigmaTPC{static_cast((track.tpcSignal() - expBethe) / expSigma)}; + return nSigmaTPC; + } + case ese_parameters::kHe3: { + const double bgScaling[2]{ese_parameters::Charges[3] * cfgMomentumScalingBetheBloch->get(3u, 0u) / ese_parameters::Masses[3], ese_parameters::Charges[3] * cfgMomentumScalingBetheBloch->get(3u, 1u) / ese_parameters::Masses[3]}; + double expBethe{tpc::BetheBlochAleph(static_cast(correctedTpcInnerParam * bgScaling[iC]), cfgBetheBlochParams->get(3u, 0u), cfgBetheBlochParams->get(3u, 1u), cfgBetheBlochParams->get(3u, 2u), cfgBetheBlochParams->get(3u, 3u), cfgBetheBlochParams->get(3u, 4u))}; + double expSigma{expBethe * cfgBetheBlochParams->get(3u, 5u)}; + double nSigmaTPC{static_cast((track.tpcSignal() - expBethe) / expSigma)}; + return nSigmaTPC; + } + case ese_parameters::kAlpha: { + const double bgScaling[2]{ese_parameters::Charges[4] * cfgMomentumScalingBetheBloch->get(4u, 0u) / ese_parameters::Masses[4], ese_parameters::Charges[4] * cfgMomentumScalingBetheBloch->get(4u, 1u) / ese_parameters::Masses[4]}; + double expBethe{tpc::BetheBlochAleph(static_cast(correctedTpcInnerParam * bgScaling[iC]), cfgBetheBlochParams->get(4u, 0u), cfgBetheBlochParams->get(4u, 1u), cfgBetheBlochParams->get(4u, 2u), cfgBetheBlochParams->get(4u, 3u), cfgBetheBlochParams->get(4u, 4u))}; + double expSigma{expBethe * cfgBetheBlochParams->get(4u, 5u)}; + double nSigmaTPC{static_cast((track.tpcSignal() - expBethe) / expSigma)}; + return nSigmaTPC; + } + default: + return -99.f; + } + } + + template + float getNSigmaTPC(const TrackType track, uint8_t POI) + { + switch (POI) { + case ese_parameters::kProton: { + float nSigmaUse = (cfgUseSelfnSigmaTPCProton ? getNSigmaTPCSelfBB(track, ese_parameters::kProton) : track.tpcNSigmaPr()); + return nSigmaUse; + } + + case ese_parameters::kDeuteron: { + return getNSigmaTPCSelfBB(track, ese_parameters::kDeuteron); + } + + case ese_parameters::kTriton: { + return getNSigmaTPCSelfBB(track, ese_parameters::kTriton); + } + + case ese_parameters::kHe3: { + return getNSigmaTPCSelfBB(track, ese_parameters::kHe3); + } + + case ese_parameters::kAlpha: { + return getNSigmaTPCSelfBB(track, ese_parameters::kAlpha); + } + + case ese_parameters::kPion: { + return track.tpcNSigmaPi(); + } + + case ese_parameters::kKaon: { + return track.tpcNSigmaKa(); + } + + default: + LOGF(error, "Unknown POI: %d", POI); + return 0; + } + } + + template + float getNSigmaTOF(const TrackType track, uint8_t POI) + { + switch (POI) { + case ese_parameters::kProton: { + return track.tofNSigmaPr(); + } + case ese_parameters::kDeuteron: { + return track.tofNSigmaDe(); + } + case ese_parameters::kTriton: { + return track.tofNSigmaTr(); + } + case ese_parameters::kHe3: { + return track.tofNSigmaHe(); + } + case ese_parameters::kAlpha: { + return track.tofNSigmaAl(); + } + case ese_parameters::kPion: { + return track.tofNSigmaPi(); + } + case ese_parameters::kKaon: { + return track.tofNSigmaKa(); + } + default: + return -99.f; + } + } + + template + float getNSigmaITS(const TrackType track, uint8_t POI) + { + switch (POI) { + case ese_parameters::kProton: { + return itsResponse.nSigmaITS(track); + } + case ese_parameters::kDeuteron: { + return itsResponse.nSigmaITS(track); + } + case ese_parameters::kTriton: { + return itsResponse.nSigmaITS(track); + } + case ese_parameters::kHe3: { + return itsResponse.nSigmaITS(track); + } + case ese_parameters::kAlpha: { + return itsResponse.nSigmaITS(track); + } + case ese_parameters::kPion: { + return itsResponse.nSigmaITS(track); + } + case ese_parameters::kKaon: { + return itsResponse.nSigmaITS(track); + } + default: + return -99.f; + } + } + + 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; + } + } + + template + uint8_t getPOI(const T& POI) + { + if (POI.value == "kProton") { + return ese_parameters::kProton; + } else if (POI.value == "kDeuteron") { + return ese_parameters::kDeuteron; + } else if (POI.value == "kTriton") { + return ese_parameters::kTriton; + } else if (POI.value == "kHe3") { + return ese_parameters::kHe3; + } else if (POI.value == "kAlpha") { + return ese_parameters::kAlpha; + } else if (POI.value == "kPion") { + return ese_parameters::kPion; + } else if (POI.value == "kKaon") { + return ese_parameters::kKaon; + } else if (POI.value == "kHadron") { + return ese_parameters::kHadron; + } else { + LOGF(error, "Unknown POIstr: %s", POI.value.c_str()); + return 0; + } + } + + float calculateq2(const float qx, const float qy, const int multi) + { + if (multi <= 0) { + return 0.f; + } else { + return std::hypot(qx, qy) / std::sqrt(static_cast(multi)); + } + } + + template + bool eventSelBasic(const CollType& collision, const int64_t multTrk, const float centrality, bool fillQA) + { + if (!collision.sel8()) + return false; + if (fillQA) { + histsESE.fill(HIST("EventQA/histEventCount"), 0.5); + } + if (cfgOpenEvSel->get(0u) && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillQA && cfgOpenEvSel->get(0u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 1.5); + } + if (cfgOpenEvSel->get(1u) && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fillQA && cfgOpenEvSel->get(1u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 2.5); + } + if (cfgOpenEvSel->get(2u) && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillQA && cfgOpenEvSel->get(2u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 3.5); + } + if (cfgOpenEvSel->get(3u) && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + if (fillQA && cfgOpenEvSel->get(3u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 4.5); + } + if (cfgOpenEvSel->get(4u) && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (fillQA && cfgOpenEvSel->get(4u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 5.5); + } + if (cfgOpenEvSel->get(5u) && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + if (fillQA && cfgOpenEvSel->get(5u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 6.5); + } + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgOpenEvSel->get(6u) && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) { + return false; + } + if (fillQA && cfgOpenEvSel->get(6u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 7.5); + } + if (cfgOpenEvSel->get(7u)) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return false; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return false; + } + if (fillQA && cfgOpenEvSel->get(7u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 8.5); + } + if (cfgOpenEvSel->get(8u)) { + if (multTrk < fMultCutLow->Eval(centrality)) + return false; + if (multTrk > fMultCutHigh->Eval(centrality)) + return false; + } + if (fillQA && cfgOpenEvSel->get(8u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 9.5); + } + if (cfgOpenEvSel->get(9u) && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > ese_parameters::kFT0AV0ASigma * fT0AV0ASigma->Eval(collision.multFT0A()))) { + return false; + } + if (fillQA && cfgOpenEvSel->get(9u)) { + histsESE.fill(HIST("EventQA/histEventCount"), 10.5); + } + if (fillQA) { + histsESE.fill(HIST("EventQA/histVtz"), collision.posZ()); + histsESE.fill(HIST("EventQA/histCent"), centrality); + } + return true; + } + + template + bool trackSelBasic(const TrackType track) + { + if ((track.pt() < cfgMinPtPID) || (track.pt() > cfgMaxPtPID)) + return false; + if (std::abs(track.eta()) > cfgMaxEtaPID) + return false; + if (cfgOpenTrackSel->get(0u)) { + if (!track.passedITSNCls()) + return false; + } else { + if (track.itsNCls() < cfgMinITSCls || track.itsNCls() > cfgMaxITSCls) + return false; + } + if (cfgOpenTrackSel->get(1u)) { + if (!track.passedITSChi2NDF()) + return false; + } else { + if (track.itsChi2NCl() < cfgMinChi2NClITS || track.itsChi2NCl() > cfgMaxChi2NClITS) + return false; + } + if (cfgOpenTrackSel->get(2u)) { + if (!track.passedITSHits()) + return false; + } + if (cfgOpenTrackSel->get(3u)) { + if (!track.passedTPCChi2NDF()) + return false; + } else { + if (track.tpcChi2NCl() < cfgMinTPCChi2NCl || track.tpcChi2NCl() > cfgMaxTPCChi2NCl) + return false; + } + if (cfgOpenTrackSel->get(4u)) { + if (!track.passedTPCCrossedRowsOverNCls()) + return false; + } + if (cfgOpenTrackSel->get(5u)) { + if (!track.passedDCAxy()) + return false; + } else { + if (std::abs(track.dcaXY()) > cfgMaxDCAxy) + return false; + } + if (cfgOpenTrackSel->get(6u)) { + if (!track.passedDCAz()) + return false; + } else { + if (std::abs(track.dcaZ()) > cfgMaxDCAz) + return false; + } + if (track.tpcNClsFound() < cfgMinTPCCls || track.tpcNClsFound() > cfgMaxTPCCls) + return false; + return true; + } + + template + void fillEventQAhistBe(const CollType collision, const int multTrk, const float centrality) + { + histsESE.fill(HIST("EventQA/hist_globalTracks_centT0C_before"), centrality, multTrk); + histsESE.fill(HIST("EventQA/hist_PVTracks_centT0C_before"), centrality, collision.multNTracksPV()); + histsESE.fill(HIST("EventQA/hist_globalTracks_PVTracks_before"), collision.multNTracksPV(), multTrk); + histsESE.fill(HIST("EventQA/hist_globalTracks_multT0A_before"), collision.multFT0A(), multTrk); + histsESE.fill(HIST("EventQA/hist_globalTracks_multV0A_before"), collision.multFV0A(), multTrk); + histsESE.fill(HIST("EventQA/hist_multV0A_multT0A_before"), collision.multFT0A(), collision.multFV0A()); + histsESE.fill(HIST("EventQA/hist_multT0C_centT0C_before"), centrality, collision.multFT0C()); + } + + template + void fillEventQAhistAf(const CollType collision, const int multTrk, const float centrality) + { + histsESE.fill(HIST("EventQA/hist_globalTracks_centT0C_after"), centrality, multTrk); + histsESE.fill(HIST("EventQA/hist_PVTracks_centT0C_after"), centrality, collision.multNTracksPV()); + histsESE.fill(HIST("EventQA/hist_globalTracks_PVTracks_after"), collision.multNTracksPV(), multTrk); + histsESE.fill(HIST("EventQA/hist_globalTracks_multT0A_after"), collision.multFT0A(), multTrk); + histsESE.fill(HIST("EventQA/hist_globalTracks_multV0A_after"), collision.multFV0A(), multTrk); + histsESE.fill(HIST("EventQA/hist_multV0A_multT0A_after"), collision.multFT0A(), collision.multFV0A()); + histsESE.fill(HIST("EventQA/hist_multT0C_centT0C_after"), centrality, collision.multFT0C()); + } + + template + void fillTrackQAhist(const TrackType track) + { + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + float correctedTpcInnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + histsESE.fill(HIST("TrackQA/hist_dEdxTPC_All"), track.sign() * correctedTpcInnerParam, track.tpcSignal()); + histsESE.fill(HIST("TrackQA/hist_pt_All"), track.pt()); + histsESE.fill(HIST("TrackQA/hist_eta_All"), track.eta()); + histsESE.fill(HIST("TrackQA/hist_phi_All"), track.phi()); + histsESE.fill(HIST("TrackQA/hist_DCAxy_All"), track.dcaXY()); + histsESE.fill(HIST("TrackQA/hist_DCAz_All"), track.dcaZ()); + histsESE.fill(HIST("TrackQA/hist_ITSNcls_All"), track.itsNCls()); + histsESE.fill(HIST("TrackQA/hist_TPCNcls_All"), track.tpcNClsFound()); + histsESE.fill(HIST("TrackQA/hist_ITSChi2NDF_All"), track.itsChi2NCl()); + histsESE.fill(HIST("TrackQA/hist_TPCChi2NDF_All"), track.tpcChi2NCl()); + histsESE.fill(HIST("TrackQA/hist_MomRes_All"), track.p(), 1 - (correctedTpcInnerParam / track.p())); + if (heliumPID) { + histsESE.fill(HIST("TrackQA/hist_He3AlphaTrackcounts_All"), 1.5); + } else { + histsESE.fill(HIST("TrackQA/hist_He3AlphaTrackcounts_All"), 0.5); + } + } + + template + void fillHistosQvec(const CollType& collision) + { + if (collision.qvecAmp()[detId] > ese_parameters::Amplitudelow) { + histsESE.fill(HIST("PlanQA/histQvec_CorrL0_V2"), collision.qvecRe()[detInd], collision.qvecIm()[detInd], collision.centFT0C()); + histsESE.fill(HIST("PlanQA/histQvec_CorrL1_V2"), collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1], collision.centFT0C()); + histsESE.fill(HIST("PlanQA/histQvec_CorrL2_V2"), collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2], collision.centFT0C()); + histsESE.fill(HIST("PlanQA/histQvec_CorrL3_V2"), collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], collision.centFT0C()); + histsESE.fill(HIST("PlanQA/histEvtPl_CorrL0_V2"), helperEP.GetEventPlane(collision.qvecRe()[detInd], collision.qvecIm()[detInd], 2), collision.centFT0C()); + histsESE.fill(HIST("PlanQA/histEvtPl_CorrL1_V2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1], 2), collision.centFT0C()); + histsESE.fill(HIST("PlanQA/histEvtPl_CorrL2_V2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2], 2), collision.centFT0C()); + histsESE.fill(HIST("PlanQA/histEvtPl_CorrL3_V2"), helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], 2), collision.centFT0C()); + } + if (collision.qvecAmp()[detId] > ese_parameters::Amplitudelow && collision.qvecAmp()[refAId] > ese_parameters::Amplitudelow && collision.qvecAmp()[refBId] > ese_parameters::Amplitudelow) { + histsESE.fill(HIST("PlanQA/histQvecRes_SigRefAV2"), collision.centFT0C(), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], 2), helperEP.GetEventPlane(collision.qvecRe()[refAInd + 3], collision.qvecIm()[refAInd + 3], 2), 2)); + histsESE.fill(HIST("PlanQA/histQvecRes_SigRefBV2"), collision.centFT0C(), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], 2), helperEP.GetEventPlane(collision.qvecRe()[refBInd + 3], collision.qvecIm()[refBInd + 3], 2), 2)); + histsESE.fill(HIST("PlanQA/histQvecRes_RefARefBV2"), collision.centFT0C(), helperEP.GetResolution(helperEP.GetEventPlane(collision.qvecRe()[refAInd + 3], collision.qvecIm()[refAInd + 3], 2), helperEP.GetEventPlane(collision.qvecRe()[refBInd + 3], collision.qvecIm()[refBInd + 3], 2), 2)); + } + } + + template + bool pidSel(const TrackType& track, uint8_t POI) + { + // Hadron + if (POI == ese_parameters::kHadron) + return true; + // PID particles + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + float correctedTpcInnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + if (correctedTpcInnerParam < cfgPOverZPreselection->get(POI, 0u) || correctedTpcInnerParam > cfgPOverZPreselection->get(POI, 1u)) { + return false; + } + if (std::abs(track.eta()) > cfgEtaPreselection->get(POI)) { + return false; + } + if (track.tpcNClsFound() < cfgTPCNclsPreselection->get(POI, 0u) || track.tpcNClsFound() > cfgTPCNclsPreselection->get(POI, 1u)) { + return false; + } + if (track.itsNCls() < cfgITSNclsPreselection->get(POI, 0u) || track.itsNCls() > cfgITSNclsPreselection->get(POI, 1u)) { + return false; + } + if (track.tpcChi2NCl() < cfgTPCChi2Preselection->get(POI, 0u) || track.tpcChi2NCl() > cfgTPCChi2Preselection->get(POI, 1u)) { + return false; + } + if (track.itsChi2NCl() < cfgITSChi2Preselection->get(POI, 0u) || track.itsChi2NCl() > cfgITSChi2Preselection->get(POI, 1u)) { + return false; + } + if (std::abs(track.dcaXY()) > cfgDCAxyPreselection->get(POI)) { + return false; + } + if (std::abs(track.dcaZ()) > cfgDCAzPreselection->get(POI)) { + return false; + } + float nSigmaTPC{0.f}; + switch (POI) { + case ese_parameters::kProton: { + if (cfgProtonPIDMode == ese_parameters::kRMSMode) { // RMS mode + float nSigmaUse = (track.pt() > cfgPtMaxforTPCOnlyPIDProton) ? std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr()) : track.tpcNSigmaPr(); + if (nSigmaUse < cfgnSigmaCutRMSProton.value[0] || nSigmaUse > cfgnSigmaCutRMSProton.value[1]) { + return false; + } + } else if (cfgProtonPIDMode == ese_parameters::kTPCMode) { // TPC mode + nSigmaTPC = getNSigmaTPC(track, ese_parameters::kProton); + } else if (cfgProtonPIDMode == ese_parameters::kTOFOnlyMode) { // TOF only mode + if (!track.hasTOF()) + return false; + if (track.tofNSigmaPr() < cfgnSigmaCutTOFProton.value[0] || track.tofNSigmaPr() > cfgnSigmaCutTOFProton.value[1]) { + return false; + } + } + break; + } + + case ese_parameters::kDeuteron: { + nSigmaTPC = getNSigmaTPC(track, ese_parameters::kDeuteron); + break; + } + + case ese_parameters::kTriton: { + nSigmaTPC = getNSigmaTPC(track, ese_parameters::kTriton); + break; + } + + case ese_parameters::kHe3: { + nSigmaTPC = getNSigmaTPC(track, ese_parameters::kHe3); + break; + } + + case ese_parameters::kAlpha: { + nSigmaTPC = getNSigmaTPC(track, ese_parameters::kAlpha); + break; + } + + case ese_parameters::kPion: { + if (cfgPionPIDMode == ese_parameters::kRMSMode) { // RMS mode + float nSigmaUse = (track.pt() > cfgPtMaxforTPCOnlyPIDPion) ? std::hypot(track.tpcNSigmaPi(), track.tofNSigmaPi()) : track.tpcNSigmaPi(); + if (nSigmaUse < cfgnSigmaCutRMSPion.value[0] || nSigmaUse > cfgnSigmaCutRMSPion.value[1]) { + return false; + } + } else if (cfgPionPIDMode == ese_parameters::kTPCMode) { // TPC mode + nSigmaTPC = getNSigmaTPC(track, ese_parameters::kPion); + } else if (cfgPionPIDMode == ese_parameters::kTOFOnlyMode) { // TOF only mode + if (!track.hasTOF()) + return false; + if (track.tofNSigmaPi() < cfgnSigmaCutTOFPion.value[0] || track.tofNSigmaPi() > cfgnSigmaCutTOFPion.value[1]) { + return false; + } + } + break; + } + + case ese_parameters::kKaon: { + if (cfgKaonPIDMode == ese_parameters::kRMSMode) { // RMS mode + float nSigmaUse = (track.pt() > cfgPtMaxforTPCOnlyPIDKaon) ? std::hypot(track.tpcNSigmaKa(), track.tofNSigmaKa()) : track.tpcNSigmaKa(); + if (nSigmaUse < cfgnSigmaCutRMSKaon.value[0] || nSigmaUse > cfgnSigmaCutRMSKaon.value[1]) { + return false; + } + } else if (cfgKaonPIDMode == ese_parameters::kTPCMode) { // TPC mode + nSigmaTPC = getNSigmaTPC(track, ese_parameters::kKaon); + } else if (cfgKaonPIDMode == ese_parameters::kTOFOnlyMode) { // TOF only mode + if (!track.hasTOF()) + return false; + if (track.tofNSigmaKa() < cfgnSigmaCutTOFKaon.value[0] || track.tofNSigmaKa() > cfgnSigmaCutTOFKaon.value[1]) { + return false; + } + } + break; + } + + default: + LOGF(error, "Unknown POI: %d", POI); + return false; + } + if (nSigmaTPC < cfgnSigmaTPC->get(POI, 0u) || nSigmaTPC > cfgnSigmaTPC->get(POI, 1u)) { + return false; + } + if (cfgOpenITSPreselection) { + float nSigmaITS{getNSigmaITS(track, POI)}; + if (nSigmaITS < cfgnSigmaITS->get(POI, 0u) || nSigmaITS > cfgnSigmaITS->get(POI, 1u)) { + return false; + } + } + return true; + } + + template + void fillESECandidates(Tcoll const& collision, Ttrks const& tracks, float& q2Tarx, float& q2Tary, int& multiTar, float& q2Refx, float& q2Refy, int& multiRef) + { + float psi2 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], 2); + float q2Tarinit{0.f}; + float q2Refinit{0.f}; + float q2FT0Cinit{0.f}; + for (const auto& track : tracks) { // loop on tracks + if (!trackSelBasic(track)) { + continue; + } + // we fill the track info QA in the main process + fillTrackQAhist(track); + bool kIsTar{false}; + bool kIsRef{false}; + kIsTar = pidSel(track, poiTar); + kIsRef = pidSel(track, poiRef); + if (kIsTar && kIsRef && !cfgOpenAllowCrossTrack && poiRef != ese_parameters::kHadron) { + if (getNSigmaTPC(track, poiTar) < getNSigmaTPC(track, poiRef)) { + kIsRef = false; + } else { + kIsTar = false; + } + } + if (kIsTar) { + multiTar++; + q2Tarx += std::cos(2 * track.phi()); + q2Tary += std::sin(2 * track.phi()); + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + float correctedTpcInnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + float nSigmaTPCTar{getNSigmaTPC(track, poiTar)}; + float nSigmaTOFTar{getNSigmaTOF(track, poiTar)}; + float nSigmaITSTar{getNSigmaITS(track, poiTar)}; + if (cfgOpenPIDQA) { + ese_parameters::hPIDQATar1D[0]->Fill(ese_parameters::Charges[poiTar] * track.pt()); + ese_parameters::hPIDQATar1D[1]->Fill(track.eta()); + ese_parameters::hPIDQATar1D[2]->Fill(track.phi()); + ese_parameters::hPIDQATar1D[3]->Fill(track.itsNCls()); + ese_parameters::hPIDQATar1D[4]->Fill(track.tpcNClsFound()); + ese_parameters::hPIDQATar1D[5]->Fill(track.itsChi2NCl()); + ese_parameters::hPIDQATar1D[6]->Fill(track.tpcChi2NCl()); + ese_parameters::hPIDQATar1D[7]->Fill(track.dcaXY()); + ese_parameters::hPIDQATar1D[8]->Fill(track.dcaZ()); + ese_parameters::hPIDQATar1D[9]->Fill(nSigmaTPCTar); + ese_parameters::hPIDQATar1D[10]->Fill(nSigmaTOFTar); + ese_parameters::hPIDQATar1D[11]->Fill(nSigmaITSTar); + ese_parameters::hPIDQATar2D[0]->Fill(track.sign() * correctedTpcInnerParam, track.tpcSignal()); + ese_parameters::hPIDQATar2D[1]->Fill(ese_parameters::Charges[poiTar] * track.pt(), nSigmaTPCTar); + ese_parameters::hPIDQATar2D[2]->Fill(ese_parameters::Charges[poiTar] * track.pt(), nSigmaTOFTar); + ese_parameters::hPIDQATar2D[3]->Fill(ese_parameters::Charges[poiTar] * track.pt(), nSigmaITSTar); + if (cfgOpen3DPIDPlots->get(0u)) { + ese_parameters::hPIDQATar3D[0]->Fill(nSigmaTOFTar, nSigmaITSTar, ese_parameters::Charges[poiTar] * track.pt()); + } + if (cfgOpen3DPIDPlots->get(1u)) { + ese_parameters::hPIDQATar3D[1]->Fill(nSigmaITSTar, nSigmaTPCTar, ese_parameters::Charges[poiTar] * track.pt()); + } + if (cfgOpen3DPIDPlots->get(2u)) { + ese_parameters::hPIDQATar3D[2]->Fill(nSigmaTOFTar, nSigmaTPCTar, ese_parameters::Charges[poiTar] * track.pt()); + } + } + ese_parameters::eseCandidates.emplace_back(ESECandidate{ + collision.posZ(), collision.centFT0C(), psi2, q2Tarinit, q2Refinit, q2FT0Cinit, static_cast(track.sign()), correctedTpcInnerParam, track.tpcSignal(), ese_parameters::Charges[poiTar] * track.pt(), track.eta(), track.phi(), + track.dcaXY(), track.dcaZ(), static_cast(track.tpcNClsFound()), track.itsNCls(), track.tpcChi2NCl(), track.itsChi2NCl(), + nSigmaTPCTar, nSigmaTOFTar, nSigmaITSTar, track.itsClusterSizes()}); + } + if (kIsRef) { + multiRef++; + q2Refx += std::cos(2 * track.phi()); + q2Refy += std::sin(2 * track.phi()); + if (cfgOpenPIDQA && poiRef != ese_parameters::kHadron) { + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + float correctedTpcInnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + float nSigmaTPCRef{getNSigmaTPC(track, poiRef)}; + float nSigmaTOFRef{getNSigmaTOF(track, poiRef)}; + float nSigmaITSRef{getNSigmaITS(track, poiRef)}; + ese_parameters::hPIDQARef1D[0]->Fill(ese_parameters::Charges[poiRef] * track.pt()); + ese_parameters::hPIDQARef1D[1]->Fill(track.eta()); + ese_parameters::hPIDQARef1D[2]->Fill(track.phi()); + ese_parameters::hPIDQARef1D[3]->Fill(track.itsNCls()); + ese_parameters::hPIDQARef1D[4]->Fill(track.tpcNClsFound()); + ese_parameters::hPIDQARef1D[5]->Fill(track.itsChi2NCl()); + ese_parameters::hPIDQARef1D[6]->Fill(track.tpcChi2NCl()); + ese_parameters::hPIDQARef1D[7]->Fill(track.dcaXY()); + ese_parameters::hPIDQARef1D[8]->Fill(track.dcaZ()); + ese_parameters::hPIDQARef1D[9]->Fill(nSigmaTPCRef); + ese_parameters::hPIDQARef1D[10]->Fill(nSigmaTOFRef); + ese_parameters::hPIDQARef1D[11]->Fill(nSigmaITSRef); + ese_parameters::hPIDQARef2D[0]->Fill(track.sign() * correctedTpcInnerParam, track.tpcSignal()); + ese_parameters::hPIDQARef2D[1]->Fill(ese_parameters::Charges[poiRef] * track.pt(), nSigmaTPCRef); + ese_parameters::hPIDQARef2D[2]->Fill(ese_parameters::Charges[poiRef] * track.pt(), nSigmaTOFRef); + ese_parameters::hPIDQARef2D[3]->Fill(ese_parameters::Charges[poiRef] * track.pt(), nSigmaITSRef); + if (cfgOpen3DPIDPlots->get(0u)) { + ese_parameters::hPIDQARef3D[0]->Fill(nSigmaTOFRef, nSigmaITSRef, ese_parameters::Charges[poiRef] * track.pt()); + } + if (cfgOpen3DPIDPlots->get(1u)) { + ese_parameters::hPIDQARef3D[1]->Fill(nSigmaITSRef, nSigmaTPCRef, ese_parameters::Charges[poiRef] * track.pt()); + } + if (cfgOpen3DPIDPlots->get(2u)) { + ese_parameters::hPIDQARef3D[2]->Fill(nSigmaTOFRef, nSigmaTPCRef, ese_parameters::Charges[poiRef] * track.pt()); + } + } + if (cfgOpenv2Ref) { + ese_parameters::eseReferences.emplace_back(ESEReference{static_cast(track.sign()), ese_parameters::Charges[poiRef] * track.pt(), std::cos(2 * (track.phi() - psi2))}); + } + } + } + } + + void init(InitContext const&) + { + poiTar = getPOI(cfgTarName); + if (poiTar == ese_parameters::kHadron) { + LOGF(info, "This work flow is not designed to run over inclusive hadrons v2 ESE, you can only set the reference to be hadron, Reset Tar to He3"); + poiTar = ese_parameters::kHe3; + } + if (poiTar == poiRef) { + LOGF(error, "The POI and the reference cannot be the same, please change the configuration, Reset Tar to He3 Ref to Proton"); + poiTar = ese_parameters::kHe3; + poiRef = ese_parameters::kProton; + } + poiRef = getPOI(cfgRefName); + 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; + } + detInd = detId * 4 + cfgnTotalSystem * 4 * (2 - 2); + refAInd = refAId * 4 + cfgnTotalSystem * 4 * (2 - 2); + refBInd = refBId * 4 + cfgnTotalSystem * 4 * (2 - 2); + + 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 axisITSNcls = {10, -1.5, 8.5, "ITSNcls"}; + AxisSpec axisTPCNcls = {160, 0, 160, "TPCNcls"}; + AxisSpec axisEvtPl = {100, -1.0 * constants::math::PI, constants::math::PI}; + AxisSpec axisPhi = {200, -2.1 * constants::math::PI, 2.1 * constants::math::PI}; + AxisSpec axisCentForQA = {100, 0, 100}; + AxisSpec axisCharge = {4, -2, 2, "Charge"}; + AxisSpec axisRigidity = {200, -10, 10, "#it{p}^{TPC}/#it{z}"}; + AxisSpec axisdEdx = {1400, 0, 1400, "dE/dx [arb. units]"}; + AxisSpec axisEta = {200, -1.0, 1.0, "#eta"}; + AxisSpec axisQvecF = {300, -1, 1, "Qvec"}; + AxisSpec axisNch = {4000, 0, 4000, "N_{ch}"}; + AxisSpec axisT0C = {70, 0, 70000, "N_{ch} (T0C)"}; + AxisSpec axisT0A = {70, 0, 70000, "N_{ch} (T0A)"}; + AxisSpec axisNchPV = {4000, 0, 4000, "N_{ch} (PV)"}; + AxisSpec axisCos = {102, -1.02, 1.02, "Cos"}; + // hists for event level QA + histsESE.add("EventQA/histEventCount", ";Event Count;Counts", {HistType::kTH1F, {{11, 0, 11}}}); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(1, "after sel8"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(2, "kIsGoodZvtxFT0vsPV"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(3, "kNoSameBunchPileup"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(4, "kNoCollInTimeRangeStandard"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(5, "kIsGoodITSLayersAll"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(6, "kNoCollInRofStandard"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(7, "kNoHighMultCollInPrevRof"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(8, "occupancy"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(9, "MultCorrelationPVTracks"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(10, "MultCorrelationGlobalTracks"); + histsESE.get(HIST("EventQA/histEventCount"))->GetXaxis()->SetBinLabel(11, "cfgEvSelV0AT0ACut"); + histsESE.add("EventQA/histVtz", ";#it{Vtz} (cm);Counts", {HistType::kTH1F, {{200, -20., +20.}}}); + histsESE.add("EventQA/histCent", ";Centrality (%);Counts", {HistType::kTH1F, {{100, 0., 100.}}}); + if (cfgOpenFullEventQA) { + histsESE.add("EventQA/hist_globalTracks_centT0C_before", "before cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + histsESE.add("EventQA/hist_PVTracks_centT0C_before", "before cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNchPV}}); + histsESE.add("EventQA/hist_globalTracks_PVTracks_before", "before cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNchPV, axisNch}}); + histsESE.add("EventQA/hist_globalTracks_multT0A_before", "before cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + histsESE.add("EventQA/hist_globalTracks_multV0A_before", "before cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + histsESE.add("EventQA/hist_multV0A_multT0A_before", "before cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + histsESE.add("EventQA/hist_multT0C_centT0C_before", "before cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + histsESE.add("EventQA/hist_globalTracks_centT0C_after", "after cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + histsESE.add("EventQA/hist_PVTracks_centT0C_after", "after cut;Centrality T0C;mulplicity PV tracks", {HistType::kTH2D, {axisCentForQA, axisNchPV}}); + histsESE.add("EventQA/hist_globalTracks_PVTracks_after", "after cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNchPV, axisNch}}); + histsESE.add("EventQA/hist_globalTracks_multT0A_after", "after cut;mulplicity T0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + histsESE.add("EventQA/hist_globalTracks_multV0A_after", "after cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + histsESE.add("EventQA/hist_multV0A_multT0A_after", "after cut;mulplicity T0A;mulplicity V0A", {HistType::kTH2D, {axisT0A, axisT0A}}); + histsESE.add("EventQA/hist_multT0C_centT0C_after", "after cut;Centrality T0C;mulplicity T0C", {HistType::kTH2D, {axisCentForQA, axisT0C}}); + } + histsESE.add("PlanQA/histQvec_CorrL0_V2", ";#it{Q_{x}};#it{Q_{y}};Centrality", {HistType::kTH3F, {axisQvecF, axisQvecF, cfgaxisCent}}); + histsESE.add("PlanQA/histQvec_CorrL1_V2", ";#it{Q_{x}};#it{Q_{y}};Centrality", {HistType::kTH3F, {axisQvecF, axisQvecF, cfgaxisCent}}); + histsESE.add("PlanQA/histQvec_CorrL2_V2", ";#it{Q_{x}};#it{Q_{y}};Centrality", {HistType::kTH3F, {axisQvecF, axisQvecF, cfgaxisCent}}); + histsESE.add("PlanQA/histQvec_CorrL3_V2", ";#it{Q_{x}};#it{Q_{y}};Centrality", {HistType::kTH3F, {axisQvecF, axisQvecF, cfgaxisCent}}); + histsESE.add("PlanQA/histEvtPl_CorrL0_V2", ";EventPlane angle;Centrality", {HistType::kTH2F, {axisEvtPl, cfgaxisCent}}); + histsESE.add("PlanQA/histEvtPl_CorrL1_V2", ";EventPlane angle;Centrality", {HistType::kTH2F, {axisEvtPl, cfgaxisCent}}); + histsESE.add("PlanQA/histEvtPl_CorrL2_V2", ";EventPlane angle;Centrality", {HistType::kTH2F, {axisEvtPl, cfgaxisCent}}); + histsESE.add("PlanQA/histEvtPl_CorrL3_V2", ";EventPlane angle;Centrality", {HistType::kTH2F, {axisEvtPl, cfgaxisCent}}); + histsESE.add("PlanQA/histQvecRes_SigRefAV2", ";Centrality;Cos(Sig-RefA)", {HistType::kTProfile, {cfgaxisCent}}); + histsESE.add("PlanQA/histQvecRes_SigRefBV2", ";Centrality;Cos(Sig-RefB)", {HistType::kTProfile, {cfgaxisCent}}); + histsESE.add("PlanQA/histQvecRes_RefARefBV2", ";Centrality;Cos(RefA-RefB)", {HistType::kTProfile, {cfgaxisCent}}); + // hists for track level QA + histsESE.add("TrackQA/hist_dEdxTPC_All", ";#it{p}^{TPC}/#it{z} (GeV/c);d#it{E}/d#it{x} [arb. units]", {HistType::kTH2F, {axisRigidity, axisdEdx}}); + histsESE.add("TrackQA/hist_pt_All", ";#it{p}_{T};counts", {HistType::kTH1F, {cfgaxispt}}); + histsESE.add("TrackQA/hist_eta_All", ";#it{#eta};counts", {HistType::kTH1F, {axisEta}}); + histsESE.add("TrackQA/hist_phi_All", ";#it{#phi};counts", {HistType::kTH1F, {axisPhi}}); + histsESE.add("TrackQA/hist_ITSNcls_All", ";ITSNcls;counts", {HistType::kTH1F, {axisITSNcls}}); + histsESE.add("TrackQA/hist_TPCNcls_All", ";TPCNcls;counts", {HistType::kTH1F, {axisTPCNcls}}); + histsESE.add("TrackQA/hist_ITSChi2NDF_All", ";ITS#it{#chi^{2}}/NDF;counts", {HistType::kTH1F, {cfgaxisChi2Ncls}}); + histsESE.add("TrackQA/hist_TPCChi2NDF_All", ";TPC#it{#chi^{2}}/NDF;counts", {HistType::kTH1F, {cfgaxisChi2Ncls}}); + histsESE.add("TrackQA/hist_DCAxy_All", ";#it{DCA_{xy}};counts", {HistType::kTH1F, {cfgaxisDCAxy}}); + histsESE.add("TrackQA/hist_DCAz_All", ";#it{DCA_{xy}};counts", {HistType::kTH1F, {cfgaxisDCAz}}); + histsESE.add("TrackQA/hist_MomRes_All", ";#it{p};Res(1 - corrted_p/track_p)", {HistType::kTH2F, {{100, 0, 10}, {100, -1, 1}}}); + histsESE.add("TrackQA/hist_He3AlphaTrackcounts_All", ";Track counts;Counts", {HistType::kTH1F, {{2, 0, 2}}}); + histsESE.get(HIST("TrackQA/hist_He3AlphaTrackcounts_All"))->GetXaxis()->SetBinLabel(1, "All Tracks"); + histsESE.get(HIST("TrackQA/hist_He3AlphaTrackcounts_All"))->GetXaxis()->SetBinLabel(2, "He3+Alpha"); + // v2 and ESEPlots + /// QA plots + if (cfgOpenPIDQA) { + ese_parameters::hPIDQATar2D[0] = histsESE.add(Form("ESE/TrackQA/hist_dEdxTPC_%s", cfgTarName.value.c_str()), ";#it{p}^{TPC}/#it{z} (GeV/c);d#it{E}/d#it{x} [arb. units]", HistType::kTH2F, {axisRigidity, axisdEdx}); + ese_parameters::hPIDQATar1D[0] = histsESE.add(Form("ESE/TrackQA/hist_pt_%s", cfgTarName.value.c_str()), ";#it{p}_{T};counts", HistType::kTH1F, {cfgaxispt}); + ese_parameters::hPIDQATar1D[1] = histsESE.add(Form("ESE/TrackQA/hist_eta_%s", cfgTarName.value.c_str()), ";#it{#eta};counts", HistType::kTH1F, {axisEta}); + ese_parameters::hPIDQATar1D[2] = histsESE.add(Form("ESE/TrackQA/hist_phi_%s", cfgTarName.value.c_str()), ";#it{#phi};counts", HistType::kTH1F, {axisPhi}); + ese_parameters::hPIDQATar1D[3] = histsESE.add(Form("ESE/TrackQA/hist_ITSNcls_%s", cfgTarName.value.c_str()), ";ITSNcls;counts", HistType::kTH1F, {axisITSNcls}); + ese_parameters::hPIDQATar1D[4] = histsESE.add(Form("ESE/TrackQA/hist_TPCNcls_%s", cfgTarName.value.c_str()), ";TPCNcls;counts", HistType::kTH1F, {axisTPCNcls}); + ese_parameters::hPIDQATar1D[5] = histsESE.add(Form("ESE/TrackQA/hist_ITSChi2NDF_%s", cfgTarName.value.c_str()), ";ITS#it{#chi^{2}}/NDF;counts", HistType::kTH1F, {cfgaxisChi2Ncls}); + ese_parameters::hPIDQATar1D[6] = histsESE.add(Form("ESE/TrackQA/hist_TPCChi2NDF_%s", cfgTarName.value.c_str()), ";TPC#it{#chi^{2}}/NDF;counts", HistType::kTH1F, {cfgaxisChi2Ncls}); + ese_parameters::hPIDQATar1D[7] = histsESE.add(Form("ESE/TrackQA/hist_DCAxy_%s", cfgTarName.value.c_str()), ";#it{DCA_{xy}};counts", HistType::kTH1F, {cfgaxisDCAxy}); + ese_parameters::hPIDQATar1D[8] = histsESE.add(Form("ESE/TrackQA/hist_DCAz_%s", cfgTarName.value.c_str()), ";#it{DCA_{xy}};counts", HistType::kTH1F, {cfgaxisDCAz}); + ese_parameters::hPIDQATar1D[9] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTPC_%s", cfgTarName.value.c_str()), ";n#sigmaTPC;counts", HistType::kTH1F, {cfgnSigmaBinsTPC}); + ese_parameters::hPIDQATar2D[1] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTPC_pt_%s", cfgTarName.value.c_str()), ";#it{p}_{T};n#sigmaTPC", HistType::kTH2F, {cfgaxispt, cfgnSigmaBinsTPC}); + ese_parameters::hPIDQATar1D[10] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTOF_%s", cfgTarName.value.c_str()), ";n#sigmaTOF;counts", HistType::kTH1F, {cfgnSigmaBinsTOF}); + ese_parameters::hPIDQATar2D[2] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTOF_pt_%s", cfgTarName.value.c_str()), ";#it{p}_{T};n#sigmaTOF", HistType::kTH2F, {cfgaxispt, cfgnSigmaBinsTOF}); + ese_parameters::hPIDQATar1D[11] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaITS_%s", cfgTarName.value.c_str()), ";n#sigmaITS;counts", HistType::kTH1F, {cfgnSigmaBinsITS}); + ese_parameters::hPIDQATar2D[3] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaITS_pt_%s", cfgTarName.value.c_str()), ";#it{p}_{T};n#sigmaITS", HistType::kTH2F, {cfgaxispt, cfgnSigmaBinsITS}); + if (cfgRefName.value != "kHadron") { + ese_parameters::hPIDQARef2D[0] = histsESE.add(Form("ESE/TrackQA/hist_dEdxTPC_%s", cfgRefName.value.c_str()), ";#it{p}^{TPC}/#it{z} (GeV/c);d#it{E}/d#it{x} [arb. units]", HistType::kTH2F, {axisRigidity, axisdEdx}); + ese_parameters::hPIDQARef1D[0] = histsESE.add(Form("ESE/TrackQA/hist_pt_%s", cfgRefName.value.c_str()), ";#it{p}_{T};counts", HistType::kTH1F, {cfgaxispt}); + ese_parameters::hPIDQARef1D[1] = histsESE.add(Form("ESE/TrackQA/hist_eta_%s", cfgRefName.value.c_str()), ";#it{#eta};counts", HistType::kTH1F, {axisEta}); + ese_parameters::hPIDQARef1D[2] = histsESE.add(Form("ESE/TrackQA/hist_phi_%s", cfgRefName.value.c_str()), ";#it{#phi};counts", HistType::kTH1F, {axisPhi}); + ese_parameters::hPIDQARef1D[3] = histsESE.add(Form("ESE/TrackQA/hist_ITSNcls_%s", cfgRefName.value.c_str()), ";ITSNcls;counts", HistType::kTH1F, {axisITSNcls}); + ese_parameters::hPIDQARef1D[4] = histsESE.add(Form("ESE/TrackQA/hist_TPCNcls_%s", cfgRefName.value.c_str()), ";TPCNcls;counts", HistType::kTH1F, {axisTPCNcls}); + ese_parameters::hPIDQARef1D[5] = histsESE.add(Form("ESE/TrackQA/hist_ITSChi2NDF_%s", cfgRefName.value.c_str()), ";ITS#it{#chi^{2}}/NDF;counts", HistType::kTH1F, {cfgaxisChi2Ncls}); + ese_parameters::hPIDQARef1D[6] = histsESE.add(Form("ESE/TrackQA/hist_TPCChi2NDF_%s", cfgRefName.value.c_str()), ";TPC#it{#chi^{2}}/NDF;counts", HistType::kTH1F, {cfgaxisChi2Ncls}); + ese_parameters::hPIDQARef1D[7] = histsESE.add(Form("ESE/TrackQA/hist_DCAxy_%s", cfgRefName.value.c_str()), ";#it{DCA_{xy}};counts", HistType::kTH1F, {cfgaxisDCAxy}); + ese_parameters::hPIDQARef1D[8] = histsESE.add(Form("ESE/TrackQA/hist_DCAz_%s", cfgRefName.value.c_str()), ";#it{DCA_{xy}};counts", HistType::kTH1F, {cfgaxisDCAz}); + ese_parameters::hPIDQARef1D[9] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTPC_%s", cfgRefName.value.c_str()), ";n#sigmaTPC;counts", HistType::kTH1F, {cfgnSigmaBinsTPC}); + ese_parameters::hPIDQARef2D[1] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTPC_pt_%s", cfgRefName.value.c_str()), ";#it{p}_{T};n#sigmaTPC", HistType::kTH2F, {cfgaxispt, cfgnSigmaBinsTPC}); + ese_parameters::hPIDQARef1D[10] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTOF_%s", cfgRefName.value.c_str()), ";n#sigmaTOF;counts", HistType::kTH1F, {cfgnSigmaBinsTOF}); + ese_parameters::hPIDQARef2D[2] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTOF_pt_%s", cfgRefName.value.c_str()), ";#it{p}_{T};n#sigmaTOF", HistType::kTH2F, {cfgaxispt, cfgnSigmaBinsTOF}); + ese_parameters::hPIDQARef1D[11] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaITS_%s", cfgRefName.value.c_str()), ";n#sigmaITS;counts", HistType::kTH1F, {cfgnSigmaBinsITS}); + ese_parameters::hPIDQARef2D[3] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaITS_pt_%s", cfgRefName.value.c_str()), ";#it{p}_{T};n#sigmaITS", HistType::kTH2F, {cfgaxispt, cfgnSigmaBinsITS}); + } + if (cfgOpen3DPIDPlots->get(0u)) { + ese_parameters::hPIDQATar3D[0] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTOFITSPt_%s", cfgTarName.value.c_str()), ";n_{#sigma}TOF;n_{#sigma}ITS;#it{p}_{T}", HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxispt}); + if (cfgRefName.value != "kHadron") { + ese_parameters::hPIDQARef3D[0] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTOFITSPt_%s", cfgRefName.value.c_str()), ";n_{#sigma}TOF;n_{#sigma}ITS;#it{p}_{T}", HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsITS, cfgaxispt}); + } + } + if (cfgOpen3DPIDPlots->get(1u)) { + ese_parameters::hPIDQATar3D[1] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaITSTPCPt_%s", cfgTarName.value.c_str()), ";n_{#sigma}ITS;n_{#sigma}TPC;#it{p}_{T}", HistType::kTH3F, {cfgnSigmaBinsITS, cfgnSigmaBinsTPC, cfgaxispt}); + if (cfgRefName.value != "kHadron") { + ese_parameters::hPIDQARef3D[1] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaITSTPCPt_%s", cfgRefName.value.c_str()), ";n_{#sigma}ITS;n_{#sigma}TPC;#it{p}_{T}", HistType::kTH3F, {cfgnSigmaBinsITS, cfgnSigmaBinsTPC, cfgaxispt}); + } + } + if (cfgOpen3DPIDPlots->get(2u)) { + ese_parameters::hPIDQATar3D[2] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTOFTPCPt_%s", cfgTarName.value.c_str()), ";n_{#sigma}TOF;n_{#sigma}TPC;#it{p}_{T}", HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxispt}); + if (cfgRefName.value != "kHadron") { + ese_parameters::hPIDQARef3D[2] = histsESE.add(Form("ESE/TrackQA/hist_nSigmaTOFTPCPt_%s", cfgRefName.value.c_str()), ";n_{#sigma}TOF;n_{#sigma}TPC;#it{p}_{T}", HistType::kTH3F, {cfgnSigmaBinsTOF, cfgnSigmaBinsTPC, cfgaxispt}); + } + } + } + // v2 plots + if (cfgOpenv2Tar) { + ese_parameters::hv2Tar[0] = histsESE.add(Form("ESE/V2/hist_%sPosV2", cfgTarName.value.c_str()), ";#it{p}_{T};Centrality (%);#it{q}_{2}", {HistType::kTProfile3D, {cfgaxispt, cfgaxisCent, cfgaxisq2Tar}}); + ese_parameters::hv2Tar[1] = histsESE.add(Form("ESE/V2/hist_%sNegV2", cfgTarName.value.c_str()), ";#it{p}_{T};Centrality (%);#it{q}_{2}", {HistType::kTProfile3D, {cfgaxispt, cfgaxisCent, cfgaxisq2Tar}}); + } + if (cfgOpenv2Ref) { + ese_parameters::hv2Ref[0] = histsESE.add(Form("ESE/V2/hist_%sPosV2", cfgRefName.value.c_str()), ";#it{p}_{T};Centrality (%);#it{q}_{2}", {HistType::kTProfile3D, {cfgaxispt, cfgaxisCent, cfgaxisq2Ref}}); + ese_parameters::hv2Ref[1] = histsESE.add(Form("ESE/V2/hist_%sNegV2", cfgRefName.value.c_str()), ";#it{p}_{T};Centrality (%);#it{q}_{2}", {HistType::kTProfile3D, {cfgaxispt, cfgaxisCent, cfgaxisq2Ref}}); + } + // ESE plots + if (cfgOpenESEQA) { + ese_parameters::hESEQATar1D[0] = histsESE.add(Form("ESE/ESEQA/hist_%sNum", cfgTarName.value.c_str()), ";Num_{Proton}/Event;counts", HistType::kTH1F, {{100, 0, 100}}); + ese_parameters::hESEQATar1D[1] = histsESE.add(Form("ESE/ESEQA/hist_%sq2", cfgTarName.value.c_str()), ";#it{q}_{2};counts", HistType::kTH1F, {cfgaxisq2Tar}); + ese_parameters::hESEQATar1D[2] = histsESE.add(Form("ESE/ESEQA/hist_%sq2Numerator", cfgTarName.value.c_str()), ";#it{q}_{2} numerator;counts", HistType::kTH1F, {cfgq2NumeratorTar}); + ese_parameters::hESEQATar1D[3] = histsESE.add(Form("ESE/ESEQA/hist_%sq2Denominator", cfgTarName.value.c_str()), ";#it{q}_{2} denominator;counts", HistType::kTH1F, {cfgq2DenominatorTar}); + ese_parameters::hESEQATar1D[4] = histsESE.add(Form("ESE/ESEQA/hist_%sNum_Survived", cfgTarName.value.c_str()), ";Num_{Proton}/Event;counts", HistType::kTH1F, {{100, 0, 100}}); + ese_parameters::hESEQATar1D[5] = histsESE.add(Form("ESE/ESEQA/hist_%sq2_Survived", cfgTarName.value.c_str()), ";#it{q}_{2};counts", HistType::kTH1F, {cfgaxisq2Tar}); + ese_parameters::hESEQATar1D[6] = histsESE.add(Form("ESE/ESEQA/hist_%sq2Numerator_Survived", cfgTarName.value.c_str()), ";#it{q}_{2} numerator;counts", HistType::kTH1F, {cfgq2NumeratorTar}); + ese_parameters::hESEQATar1D[7] = histsESE.add(Form("ESE/ESEQA/hist_%sq2Denominator_Survived", cfgTarName.value.c_str()), ";#it{q}_{2} denominator;counts", HistType::kTH1F, {cfgq2DenominatorTar}); + ese_parameters::hESEQATar2D[0] = histsESE.add(Form("ESE/ESEQA/hist_%sq2_Cent", cfgTarName.value.c_str()), ";#it{q}_{2};Centrality (%)", HistType::kTH2F, {cfgaxisq2Tar, cfgaxisCent}); + ese_parameters::hESEQATar2D[1] = histsESE.add(Form("ESE/ESEQA/hist_%sq2_Cent_Survived", cfgTarName.value.c_str()), ";#it{q}_{2};Centrality (%)", HistType::kTH2F, {cfgaxisq2Tar, cfgaxisCent}); + ese_parameters::hESEQARef1D[0] = histsESE.add(Form("ESE/ESEQA/hist_%sNum", cfgRefName.value.c_str()), ";Num_{He3}/Event;counts", HistType::kTH1F, {{10, 0, 10}}); + ese_parameters::hESEQARef1D[1] = histsESE.add(Form("ESE/ESEQA/hist_%sq2", cfgRefName.value.c_str()), ";#it{q}_{2};counts", HistType::kTH1F, {cfgaxisq2Ref}); + ese_parameters::hESEQARef1D[2] = histsESE.add(Form("ESE/ESEQA/hist_%sq2Numerator", cfgRefName.value.c_str()), ";#it{q}_{2} numerator;counts", HistType::kTH1F, {cfgq2NumeratorRef}); + ese_parameters::hESEQARef1D[3] = histsESE.add(Form("ESE/ESEQA/hist_%sq2Denominator", cfgRefName.value.c_str()), ";#it{q}_{2} denominator;counts", HistType::kTH1F, {cfgq2DenominatorRef}); + ese_parameters::hESEQARef1D[4] = histsESE.add(Form("ESE/ESEQA/hist_%sNum_Survived", cfgRefName.value.c_str()), ";Num_{He3}/Event;counts", HistType::kTH1F, {{10, 0, 10}}); + ese_parameters::hESEQARef1D[5] = histsESE.add(Form("ESE/ESEQA/hist_%sq2_Survived", cfgRefName.value.c_str()), ";#it{q}_{2};counts", HistType::kTH1F, {cfgaxisq2Ref}); + ese_parameters::hESEQARef1D[6] = histsESE.add(Form("ESE/ESEQA/hist_%sq2Numerator_Survived", cfgRefName.value.c_str()), ";#it{q}_{2} numerator;counts", HistType::kTH1F, {cfgq2NumeratorRef}); + ese_parameters::hESEQARef1D[7] = histsESE.add(Form("ESE/ESEQA/hist_%sq2Denominator_Survived", cfgRefName.value.c_str()), ";#it{q}_{2} denominator;counts", HistType::kTH1F, {cfgq2DenominatorRef}); + ese_parameters::hESEQARef2D[0] = histsESE.add(Form("ESE/ESEQA/hist_%sq2_Cent", cfgRefName.value.c_str()), ";#it{q}_{2};Centrality (%)", HistType::kTH2F, {cfgaxisq2Ref, cfgaxisCent}); + ese_parameters::hESEQARef2D[1] = histsESE.add(Form("ESE/ESEQA/hist_%sq2_Cent_Survived", cfgRefName.value.c_str()), ";#it{q}_{2};Centrality (%)", HistType::kTH2F, {cfgaxisq2Ref, cfgaxisCent}); + ese_parameters::hESEQAFT0C1D[0] = histsESE.add("ESE/ESEQA/hist_q2FT0C", ";#it{q}_{2} (FT0C)", HistType::kTH1F, {cfgaxisq2FT0C}); + ese_parameters::hESEQAFT0C1D[1] = histsESE.add("ESE/ESEQA/hist_q2FT0C_Survived", ";#it{q}_{2} (FT0C)", HistType::kTH1F, {cfgaxisq2FT0C}); + ese_parameters::hESEQAFT0C2D[0] = histsESE.add("ESE/ESEQA/hist_q2FT0C_Cent", ";#it{q}_{2} (FT0C);Centrality (%)", HistType::kTH2F, {cfgaxisq2FT0C, cfgaxisCent}); + ese_parameters::hESEQAFT0C2D[1] = histsESE.add("ESE/ESEQA/hist_q2FT0C_Cent_Survived", ";#it{q}_{2} (FT0C);Centrality (%)", HistType::kTH2F, {cfgaxisq2FT0C, cfgaxisCent}); + } + if (cfgOpenESE) { + ese_parameters::hESETar = histsESE.add(Form("ESE/ESE/histESE_%s", cfgTarName.value.c_str()), ";#it{p}_{T};Centrality (%);#it{q}_{2};cos(#phi-#Psi_{2});Charge", HistType::kTHnSparseF, {cfgaxispt, cfgaxisCent, cfgaxisq2Ref, axisCos, axisCharge}); + } + } + + void process(soa::Filtered>::iterator const& collision, TracksPIDFull const& tracks) + { + ese_parameters::eseCandidates.clear(); + ese_parameters::eseReferences.clear(); + const float centrality{collision.centFT0C()}; + const int64_t multTrk{tracks.size()}; + if (cfgOpenFullEventQA) + fillEventQAhistBe(collision, multTrk, centrality); + if (!eventSelBasic(collision, multTrk, centrality, true)) + return; + if (cfgOpenFullEventQA) + fillEventQAhistAf(collision, multTrk, centrality); + float q2FT0C{std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C())}; + float q2Tarx{0.}; + float q2Tary{0.}; + float q2Refx{0.}; + float q2Refy{0.}; + int multiTar{0}; + int multiRef{0}; + fillHistosQvec(collision); + fillESECandidates(collision, tracks, q2Tarx, q2Tary, multiTar, q2Refx, q2Refy, multiRef); + float q2Tar{calculateq2(q2Tarx, q2Tary, multiTar)}; + float q2Ref{calculateq2(q2Refx, q2Refy, multiRef)}; + if (cfgOpenESEQA) { + ese_parameters::hESEQATar1D[0]->Fill(multiTar); + ese_parameters::hESEQATar1D[1]->Fill(q2Tar); + ese_parameters::hESEQATar1D[2]->Fill(std::hypot(q2Tarx, q2Tary)); + ese_parameters::hESEQATar1D[3]->Fill(std::sqrt(static_cast(multiTar))); + ese_parameters::hESEQATar2D[0]->Fill(q2Tar, centrality); + ese_parameters::hESEQARef1D[0]->Fill(multiRef); + ese_parameters::hESEQARef1D[1]->Fill(q2Ref); + ese_parameters::hESEQARef1D[2]->Fill(std::hypot(q2Refx, q2Refy)); + ese_parameters::hESEQARef1D[3]->Fill(std::sqrt(static_cast(multiRef))); + ese_parameters::hESEQARef2D[0]->Fill(q2Ref, centrality); + ese_parameters::hESEQAFT0C1D[0]->Fill(q2FT0C); + ese_parameters::hESEQAFT0C2D[0]->Fill(q2FT0C, centrality); + } + if (cfgOpenv2Ref) { + for (const auto& c : ese_parameters::eseReferences) { + if (c.signRef > 0) { + ese_parameters::hv2Ref[0]->Fill(c.ptRef, centrality, q2Ref, c.v2Ref); + } else { + ese_parameters::hv2Ref[1]->Fill(c.ptRef, centrality, q2Ref, c.v2Ref); + } + } + } + if (multiTar == 0) + return; + if (cfgOpenESEQA) { + ese_parameters::hESEQATar1D[4]->Fill(multiTar); + ese_parameters::hESEQATar1D[5]->Fill(q2Tar); + ese_parameters::hESEQATar1D[6]->Fill(std::hypot(q2Tarx, q2Tary)); + ese_parameters::hESEQATar1D[7]->Fill(std::sqrt(static_cast(multiTar))); + ese_parameters::hESEQATar2D[1]->Fill(q2Tar, centrality); + ese_parameters::hESEQARef1D[4]->Fill(multiRef); + ese_parameters::hESEQARef1D[5]->Fill(q2Ref); + ese_parameters::hESEQARef1D[6]->Fill(std::hypot(q2Refx, q2Refy)); + ese_parameters::hESEQARef1D[7]->Fill(std::sqrt(static_cast(multiRef))); + ese_parameters::hESEQARef2D[1]->Fill(q2Ref, centrality); + ese_parameters::hESEQAFT0C1D[1]->Fill(q2FT0C); + ese_parameters::hESEQAFT0C2D[1]->Fill(q2FT0C, centrality); + } + for (const auto& c : ese_parameters::eseCandidates) { + eseTable(c.vtz, c.centFT0C, c.psi2FT0C, q2Tar, q2Ref, q2FT0C, c.signTar, c.tpcInnerParamTar, c.tpcSignalTar, c.ptTar, c.etaTar, c.phiTar, c.dcaXYTar, c.dcaZTar, c.tpcNclsTar, c.itsNclsTar, c.tpcChi2NDFTar, c.itsChi2NDFTar, c.tpcNSigmaTar, c.tofNSigmaTar, c.itsNSigmaTar, c.itsClusSizeTar); + if (cfgOpenESE) { + ese_parameters::hESETar->Fill(c.ptTar, c.centFT0C, q2Ref, std::cos(2 * (c.phiTar - c.psi2FT0C)), c.signTar); + } + if (cfgOpenv2Tar) { + if (c.signTar > 0) { + ese_parameters::hv2Tar[0]->Fill(c.ptTar, c.centFT0C, q2Tar, std::cos(2 * (c.phiTar - c.psi2FT0C))); + } else { + ese_parameters::hv2Tar[1]->Fill(c.ptTar, c.centFT0C, q2Tar, std::cos(2 * (c.phiTar - c.psi2FT0C))); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/Flow/Tasks/flowEseTask.cxx b/PWGCF/Flow/Tasks/flowEseTask.cxx new file mode 100644 index 00000000000..3db602eb36a --- /dev/null +++ b/PWGCF/Flow/Tasks/flowEseTask.cxx @@ -0,0 +1,1150 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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) +/// \file flowEseTask.cxx +/// \brief Task for flow and event shape engineering correlation with other observation. +/// \since 2023-05-15 +/// \version 1.0 + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#include "Common/Core/EventPlaneHelper.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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include "TVector2.h" +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct FlowEseTask { + // 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 ccdbNoLaterThan{"ccdbNoLaterThan", 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 cfgMinPt{"cfgMinPt", 0.15, "Minimum transverse momentum for track"}; + Configurable cfgMaxEta{"cfgMaxEta", 0.8, "Maximum pseudorapidiy for charged track"}; + + 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 ptFullAxis{"ptFullAxis", {VARIABLE_WIDTH, -5.0, -4.0, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, -0.2, 0, 0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.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"}; + ConfigurableAxis lowerQAxis{"lowerQAxis", {800, 0, 800}, "result of q2"}; + ConfigurableAxis multNumAxis{"multNumAxis", {300, 0, 2700}, "mult num"}; + ConfigurableAxis qvecAxis{"qvecAxis", {300, -1, 1}, "range of Qvector component"}; + ConfigurableAxis qvec2Axis{"qvec2Axis", {600, 0, 600}, "range of Qvector Module"}; + + static constexpr float kMinAmplitudeThreshold = 1e-5f; + static constexpr int kShiftLevel = 10; + static constexpr int kLambdaId = 3122; + static constexpr std::array kCorrLevel = {2, 3, 4, 1}; + static constexpr std::array kCentBoundaries = {0.0f, 3.49f, 4.93f, 6.98f, 8.55f, 9.87f, 11.0f, 12.1f, 13.1f, 14.0f}; + static constexpr std::array kCentValues = {2.5f, 7.5f, 15.0f, 25.0f, 35.0f, 45.0f, 55.0f, 65.0f, 75.0f}; + static constexpr std::array, 8> kLowQvec = {{{121, 196}, {110, 172}, {93, 143}, {74, 117}, {58, 92}, {43, 70}, {31, 50}, {21, 34}}}; + static constexpr float kEtaAcceptance = 0.8f; + static constexpr float kCentUpperLimit = 80.0f; + + EventPlaneHelper helperEP; + + 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; + + 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, o2::constants::math::TwoPI}; + AxisSpec epQaAxis = {100, -1.0 * o2::constants::math::PI, o2::constants::math::PI}; + + AxisSpec pidAxis = {100, -10, 10}; + AxisSpec vertexAxis = {100, -20, 20}; + + AxisSpec shiftAxis = {10, 0, 10, "shift"}; + AxisSpec basisAxis = {20, 0, 20, "basis"}; + + histos.add(Form("histQvecV2"), "", {HistType::kTH3F, {qvecAxis, qvecAxis, centAxis}}); + histos.add(Form("histMult_Cent"), "", {HistType::kTH2F, {multNumAxis, centAxis}}); + histos.add(Form("histQvecCent"), "", {HistType::kTH2F, {lowerQAxis, centAxis}}); + histos.add(Form("histPrPtCent"), "", {HistType::kTHnSparseF, {ptFullAxis, ptFullAxis, ptFullAxis, centAxis}}); + histos.add(Form("histPiPtCent"), "", {HistType::kTHnSparseF, {ptFullAxis, ptFullAxis, ptFullAxis, centAxis}}); + histos.add(Form("histPrBoostedPtCent"), "", {HistType::kTHnSparseF, {ptFullAxis, ptFullAxis, ptFullAxis, centAxis}}); + histos.add(Form("histVertex"), "", {HistType::kTHnSparseF, {vertexAxis, vertexAxis, vertexAxis, centAxis}}); + histos.add(Form("histV2"), "", {HistType::kTHnSparseF, {centAxis, ptAxis, cosAxis, qvec2Axis}}); + histos.add(Form("histV2_lambda"), "", {HistType::kTHnSparseF, {centAxis, ptAxis, cosAxis, qvec2Axis, massAxis}}); + histos.add(Form("histV2_alambda"), "", {HistType::kTHnSparseF, {centAxis, ptAxis, cosAxis, qvec2Axis, massAxis}}); + 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}}); + histos.add(Form("psi%d/h_lambda_cos2_q2", i), "", {HistType::kTH3F, {centAxis, qvec2Axis, cosAxis}}); + histos.add(Form("psi%d/h_alambda_cos2_q2", i), "", {HistType::kTH3F, {centAxis, qvec2Axis, cosAxis}}); + + 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}}); + + histos.add(Form("psi%d/h_lambda_cossin_q2", i), "", {HistType::kTH3F, {centAxis, qvec2Axis, cosAxis}}); + histos.add(Form("psi%d/h_alambda_cossin_q2", i), "", {HistType::kTH3F, {centAxis, qvec2Axis, cosAxis}}); + histos.add(Form("psi%d/h_lambda_cossin_cov", i), "", {HistType::kTHnSparseF, {ptAxis, cosAxis, centAxis}}); + histos.add(Form("psi%d/h_alambda_cossin_cov", i), "", {HistType::kTHnSparseF, {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}}); + + histos.add(Form("psi%d/QA/EPRes_RefARefB_cov", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi%d/QA/EPRes_RefARefBRefC_cov", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + } + } + + if (doprocessMcItsTpc) { + histos.add("hImpactParameter", "Impact parameter", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hEventPlaneAngle", "hEventPlaneAngle", kTH1F, {{200, -1.0 * o2::constants::math::TwoPI, 1.0 * o2::constants::math::TwoPI}}); + histos.add("hEventPlaneAngleRec", "hEventPlaneAngleRec", kTH1F, {{200, -1.0 * o2::constants::math::TwoPI, 1.0 * o2::constants::math::TwoPI}}); + 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, o2::constants::math::PI}, {50, 0.0f, 1}, ptAxis, {8, -0.8, 0.8}}); + histos.add("hSparseMCRecWeight", "hSparseMCRecWeight", HistType::kTHnSparseF, {centAxis, {36, 0.0f, o2::constants::math::PI}, {50, 0.0f, 1}, ptAxis, {8, -0.8, 0.8}}); + histos.add("hSparseMCRecAllTrackWeight", "hSparseMCRecAllTrackWeight", HistType::kTHnSparseF, {centAxis, {36, 0.0, o2::constants::math::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; + } + + double safeATan2(double y, double x) + { + if (x != 0) + return std::atan2(y, x); + if (y == 0) + return 0; + if (y > 0) + return o2::constants::math::PIHalf; + else + return -o2::constants::math::PIHalf; + } + + template + bool selectionTrack(TrackType const& 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 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 <= kShiftLevel; ishift++) { + if (nmode == kCorrLevel[0]) { + histos.fill(HIST("psi2/ShiftFIT"), centrality, 0.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode))); + histos.fill(HIST("psi2/ShiftFIT"), centrality, 1.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode))); + + histos.fill(HIST("psi2/ShiftFIT"), centrality, 2.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode))); + histos.fill(HIST("psi2/ShiftFIT"), centrality, 3.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode))); + + histos.fill(HIST("psi2/ShiftFIT"), centrality, 4.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]) / static_cast(nmode))); + histos.fill(HIST("psi2/ShiftFIT"), centrality, 5.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]) / static_cast(nmode))); + } else if (nmode == kCorrLevel[1]) { + histos.fill(HIST("psi3/ShiftFIT"), centrality, 0.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode))); + histos.fill(HIST("psi3/ShiftFIT"), centrality, 1.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode))); + + histos.fill(HIST("psi3/ShiftFIT"), centrality, 2.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode))); + histos.fill(HIST("psi3/ShiftFIT"), centrality, 3.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode))); + + histos.fill(HIST("psi3/ShiftFIT"), centrality, 4.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]) / static_cast(nmode))); + histos.fill(HIST("psi3/ShiftFIT"), centrality, 5.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]) / static_cast(nmode))); + } else if (nmode == kCorrLevel[2]) { + histos.fill(HIST("psi4/ShiftFIT"), centrality, 0.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode))); + histos.fill(HIST("psi4/ShiftFIT"), centrality, 1.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode))); + + histos.fill(HIST("psi4/ShiftFIT"), centrality, 2.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode))); + histos.fill(HIST("psi4/ShiftFIT"), centrality, 3.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode))); + + histos.fill(HIST("psi4/ShiftFIT"), centrality, 4.5, ishift - 0.5, std::sin(ishift * static_cast(nmode) * std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]) / static_cast(nmode))); + histos.fill(HIST("psi4/ShiftFIT"), centrality, 5.5, ishift - 0.5, std::cos(ishift * static_cast(nmode) * std::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] < kMinAmplitudeThreshold || collision.qvecAmp()[refAId] < kMinAmplitudeThreshold || collision.qvecAmp()[refBId] < kMinAmplitudeThreshold) + return; + + if (nmode == kCorrLevel[0]) { + histos.fill(HIST("psi2/QA/EP_Det"), centrality, std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode)); + histos.fill(HIST("psi2/QA/EP_RefA"), centrality, std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode)); + histos.fill(HIST("psi2/QA/EP_RefB"), centrality, std::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, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]))); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); + } else if (nmode == kCorrLevel[1]) { + histos.fill(HIST("psi3/QA/EP_Det"), centrality, std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode)); + histos.fill(HIST("psi3/QA/EP_RefA"), centrality, std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode)); + histos.fill(HIST("psi3/QA/EP_RefB"), centrality, std::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, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]))); + histos.fill(HIST("psi3/QA/EPRes_Det_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); + histos.fill(HIST("psi3/QA/EPRes_RefA_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); + } else if (nmode == kCorrLevel[2]) { + histos.fill(HIST("psi4/QA/EP_Det"), centrality, std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode)); + histos.fill(HIST("psi4/QA/EP_RefA"), centrality, std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode)); + histos.fill(HIST("psi4/QA/EP_RefB"), centrality, std::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, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]))); + histos.fill(HIST("psi4/QA/EPRes_Det_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); + histos.fill(HIST("psi4/QA/EPRes_RefA_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); + } + + if (cfgShiftCorr) { + auto deltapsiFT0C = 0.0; + auto deltapsiFT0A = 0.0; + auto deltapsiFV0A = 0.0; + + auto psidefFT0C = std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode); + auto psidefFT0A = std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode); + auto psidefFV0A = std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]) / static_cast(nmode); + for (int ishift = 1; ishift <= kShiftLevel; 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 * std::cos(ishift * static_cast(nmode) * psidefFT0C) + coeffshiftyFT0C * std::sin(ishift * static_cast(nmode) * psidefFT0C))); + deltapsiFT0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0A * std::cos(ishift * static_cast(nmode) * psidefFT0A) + coeffshiftyFT0A * std::sin(ishift * static_cast(nmode) * psidefFT0A))); + deltapsiFV0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFV0A * std::cos(ishift * static_cast(nmode) * psidefFV0A) + coeffshiftyFV0A * std::sin(ishift * static_cast(nmode) * psidefFV0A))); + } + if (nmode == kCorrLevel[0]) { + 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, std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFT0A - deltapsiFT0A))); + histos.fill(HIST("psi2/QA/EPRes_FT0C_FV0A_shifted"), centrality, std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFV0A - deltapsiFV0A))); + histos.fill(HIST("psi2/QA/EPRes_FT0A_FV0A_shifted"), centrality, std::cos(static_cast(nmode) * (psidefFT0A + deltapsiFT0A - psidefFV0A - deltapsiFV0A))); + + histos.fill(HIST("psi2/QA/EPRes_RefARefB_cov"), centrality, std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFT0A - deltapsiFT0A)) * std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFV0A - deltapsiFV0A))); + histos.fill(HIST("psi2/QA/EPRes_RefARefBRefC_cov"), centrality, std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFT0A - deltapsiFT0A)) * std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFV0A - deltapsiFV0A)) * std::cos(static_cast(nmode) * (psidefFT0A + deltapsiFT0A - psidefFV0A - deltapsiFV0A))); + } else if (nmode == kCorrLevel[1]) { + 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, std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFT0A - deltapsiFT0A))); + histos.fill(HIST("psi3/QA/EPRes_FT0C_FV0A_shifted"), centrality, std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFV0A - deltapsiFV0A))); + histos.fill(HIST("psi3/QA/EPRes_FT0A_FV0A_shifted"), centrality, std::cos(static_cast(nmode) * (psidefFT0A + deltapsiFT0A - psidefFV0A - deltapsiFV0A))); + } else if (nmode == kCorrLevel[2]) { + 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, std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFT0A - deltapsiFT0A))); + histos.fill(HIST("psi4/QA/EPRes_FT0C_FV0A_shifted"), centrality, std::cos(static_cast(nmode) * (psidefFT0C + deltapsiFT0C - psidefFV0A - deltapsiFV0A))); + histos.fill(HIST("psi4/QA/EPRes_FT0A_FV0A_shifted"), centrality, std::cos(static_cast(nmode) * (psidefFT0A + deltapsiFT0A - psidefFV0A - deltapsiFV0A))); + } + } + } + + template + void fillHistograms(TCollision const& collision, V0 const& V0s, TrackType const& track, 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 (const auto& trk : track) { + if (!selectionTrack(trk)) { + continue; + } + if (nmode == kCorrLevel[0]) { + histos.fill(HIST("histV2"), collision.centFT0C(), trk.pt(), + std::cos(static_cast(nmode) * (trk.phi() - helperEP.GetEventPlane(collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], nmode))), + std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C())); + } + } + + histos.fill(HIST("histQvecCent"), std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C()), centrality); + histos.fill(HIST("histQvecV2"), collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], collision.centFT0C()); + histos.fill(HIST("histMult_Cent"), collision.sumAmplFT0C(), collision.centFT0C()); + histos.fill(HIST("histVertex"), collision.posX(), collision.posY(), collision.posZ(), collision.centFT0C()); + + for (const 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 == kCorrLevel[0]) { + 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); + histos.fill(HIST("histV2_lambda"), collision.centFT0C(), v0.pt(), + std::cos(static_cast(nmode) * (v0.phi() - helperEP.GetEventPlane(collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], nmode))), + std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C()), + v0.mLambda()); + } + if (aLambdaTag) { + protonVec = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPr); + pionVec = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPi); + histos.fill(HIST("histV2_alambda"), collision.centFT0C(), v0.pt(), + std::cos(static_cast(nmode) * (v0.phi() - helperEP.GetEventPlane(collision.qvecFT0CReVec()[0], collision.qvecFT0CImVec()[0], nmode))), + std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C()), + v0.mAntiLambda()); + } + LambdaVec = protonVec + pionVec; + LambdaVec.SetM(massLambda); + + ROOT::Math::Boost boost{LambdaVec.BoostToCM()}; + protonBoostedVec = boost(protonVec); + + angle = protonBoostedVec.Pz() / protonBoostedVec.P(); + psi = safeATan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode); + relphi = TVector2::Phi_0_2pi(static_cast(nmode) * (LambdaVec.Phi() - psi)); + + histos.fill(HIST("histPrPtCent"), protonVec.Px(), protonVec.Py(), protonVec.Pz(), collision.centFT0C()); + histos.fill(HIST("histPiPtCent"), pionVec.Px(), pionVec.Py(), pionVec.Pz(), collision.centFT0C()); + histos.fill(HIST("histPrBoostedPtCent"), protonBoostedVec.Px(), protonBoostedVec.Py(), protonBoostedVec.Pz(), collision.centFT0C()); + + if (cfgShiftCorr) { + auto deltapsiFT0C = 0.0; + auto deltapsiFT0A = 0.0; + auto deltapsiFV0A = 0.0; + + auto psidefFT0C = std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode); + auto psidefFT0A = std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode); + auto psidefFV0A = std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]) / static_cast(nmode); + for (int ishift = 1; ishift <= kShiftLevel; 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 * std::cos(ishift * static_cast(nmode) * psidefFT0C) + coeffshiftyFT0C * std::sin(ishift * static_cast(nmode) * psidefFT0C))); + deltapsiFT0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0A * std::cos(ishift * static_cast(nmode) * psidefFT0A) + coeffshiftyFT0A * std::sin(ishift * static_cast(nmode) * psidefFT0A))); + deltapsiFV0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFV0A * std::cos(ishift * static_cast(nmode) * psidefFV0A) + coeffshiftyFV0A * std::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(std::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 *= std::sqrt(std::pow(collision.qvecIm()[3 + (nmode - 2) * 28], 2) + std::pow(collision.qvecRe()[3 + (nmode - 2) * 28], 2)); + + if (nmode == kCorrLevel[0]) { //////////// + double q2 = std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C()); + 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 * std::sin(relphi) * weight, centrality); + histos.fill(HIST("psi2/h_lambda_vncos"), v0.mLambda(), v0.pt(), qvecMag * std::cos(relphi) * weight, centrality); + histos.fill(HIST("psi2/h_lambda_vnsin"), v0.mLambda(), v0.pt(), std::sin(relphi), centrality); + + histos.fill(HIST("psi2/h_lambda_cos2_q2"), centrality, q2, angle * angle); + histos.fill(HIST("psi2/h_lambda_cossin_q2"), centrality, q2, angle * std::sin(relphi) * weight); + + histos.fill(HIST("psi2/h_lambda_cossin_cov"), v0.pt(), angle * angle * angle * std::sin(relphi) * weight, 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 * std::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(), std::cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosPhi_l"), v0.mLambda(), v0.pt(), std::cos(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPsi_l"), v0.mLambda(), v0.pt(), std::sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_l"), v0.mLambda(), v0.pt(), std::sin(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosTheta_cosPhi_l"), v0.mLambda(), v0.pt(), angle * std::cos(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPsi_l"), v0.mLambda(), v0.pt(), angle * std::cos(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosTheta_sinPhi_l"), v0.mLambda(), v0.pt(), angle * std::sin(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPsi_l"), v0.mLambda(), v0.pt(), angle * std::sin(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosPhi_sinPsi_l"), v0.mLambda(), v0.pt(), std::cos(v0.phi() * 2.0) * std::sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_cosPsi_l"), v0.mLambda(), v0.pt(), std::sin(v0.phi() * 2.0) * std::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(), std::cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosPhi_l"), v0.mLambda(), v0.pt(), std::cos(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosPhi_cosPsi_l"), v0.mLambda(), v0.pt(), std::cos(v0.phi() * 2.0) * std::cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPhi_l"), v0.mLambda(), v0.pt(), angle * std::cos(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPsi_l"), v0.mLambda(), v0.pt(), angle * std::cos(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPhi_sinPsi_l"), v0.mLambda(), v0.pt(), std::sin(v0.phi() * 2.0) * std::sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPhi_l"), v0.mLambda(), v0.pt(), angle * std::sin(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPsi_l"), v0.mLambda(), v0.pt(), angle * std::sin(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPsi_l"), v0.mLambda(), v0.pt(), std::sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_l"), v0.mLambda(), v0.pt(), std::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 * std::sin(relphi) * weight, centrality); + histos.fill(HIST("psi2/h_alambda_vncos"), v0.mAntiLambda(), v0.pt(), qvecMag * std::cos(relphi) * weight, centrality); + histos.fill(HIST("psi2/h_alambda_vnsin"), v0.mAntiLambda(), v0.pt(), std::sin(relphi), centrality); + + histos.fill(HIST("psi2/h_alambda_cos2_q2"), centrality, q2, angle * angle); + histos.fill(HIST("psi2/h_alambda_cossin_q2"), centrality, q2, angle * std::sin(relphi) * weight); + + histos.fill(HIST("psi2/h_alambda_cossin_cov"), v0.pt(), angle * angle * angle * std::sin(relphi) * weight, 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 * std::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(), std::cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosPhi_al"), v0.mAntiLambda(), v0.pt(), std::cos(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPsi_al"), v0.mAntiLambda(), v0.pt(), std::sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_al"), v0.mAntiLambda(), v0.pt(), std::sin(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosTheta_cosPhi_al"), v0.mAntiLambda(), v0.pt(), angle * std::cos(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPsi_al"), v0.mAntiLambda(), v0.pt(), angle * std::cos(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosTheta_sinPhi_al"), v0.mAntiLambda(), v0.pt(), angle * std::sin(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPsi_al"), v0.mAntiLambda(), v0.pt(), angle * std::sin(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosPhi_sinPsi_al"), v0.mAntiLambda(), v0.pt(), std::cos(v0.phi() * 2.0) * std::sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_cosPsi_al"), v0.mAntiLambda(), v0.pt(), std::sin(v0.phi() * 2.0) * std::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(), std::cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosPhi_al"), v0.mAntiLambda(), v0.pt(), std::cos(v0.phi() * 2.0), centrality); + + histos.fill(HIST("psi2/QA/cosPhi_cosPsi_al"), v0.mAntiLambda(), v0.pt(), std::cos(v0.phi() * 2.0) * std::cos(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPhi_al"), v0.mAntiLambda(), v0.pt(), angle * std::cos(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_cosPsi_al"), v0.mAntiLambda(), v0.pt(), angle * std::cos(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPhi_sinPsi_al"), v0.mAntiLambda(), v0.pt(), std::sin(v0.phi() * 2.0) * std::sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPhi_al"), v0.mAntiLambda(), v0.pt(), angle * std::sin(v0.phi() * 2.0), centrality); + histos.fill(HIST("psi2/QA/cosTheta_sinPsi_al"), v0.mAntiLambda(), v0.pt(), angle * std::sin(psi * 2.0), centrality); + + histos.fill(HIST("psi2/QA/sinPsi_al"), v0.mAntiLambda(), v0.pt(), std::sin(psi * 2.0), centrality); + histos.fill(HIST("psi2/QA/sinPhi_al"), v0.mAntiLambda(), v0.pt(), std::sin(v0.phi() * 2.0), centrality); + } + } + } else if (nmode == kCorrLevel[1]) { + 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 * std::sin(relphi) * weight, centrality); + histos.fill(HIST("psi3/h_lambda_vncos"), v0.mLambda(), v0.pt(), qvecMag * std::cos(relphi) * weight, centrality); + histos.fill(HIST("psi3/h_lambda_vnsin"), v0.mLambda(), v0.pt(), std::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 * std::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 * std::sin(relphi) * weight, centrality); + histos.fill(HIST("psi3/h_alambda_vncos"), v0.mAntiLambda(), v0.pt(), qvecMag * std::cos(relphi) * weight, centrality); + histos.fill(HIST("psi3/h_alambda_vnsin"), v0.mAntiLambda(), v0.pt(), std::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 * std::cos(relphi), centrality, weight); + } + } + } else if (nmode == kCorrLevel[2]) { + 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 * std::sin(relphi) * weight, centrality); + histos.fill(HIST("psi4/h_lambda_vncos"), v0.mLambda(), v0.pt(), qvecMag * std::cos(relphi) * weight, centrality); + histos.fill(HIST("psi4/h_lambda_vnsin"), v0.mLambda(), v0.pt(), std::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 * std::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 * std::sin(relphi) * weight, centrality); + histos.fill(HIST("psi4/h_alambda_vncos"), v0.mAntiLambda(), v0.pt(), qvecMag * std::cos(relphi) * weight, centrality); + histos.fill(HIST("psi4/h_alambda_vnsin"), v0.mAntiLambda(), v0.pt(), std::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 * std::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 == kCorrLevel[3]) { + centrality = collision.centFT0C(); + } else if (cfgCentEst == kCorrLevel[0]) { + centrality = collision.centFT0M(); + } + if (!eventSelected(collision)) { + return; + } + + 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, tracks, i); + } // FIXME: need to fill different histograms for different harmonic + } + PROCESS_SWITCH(FlowEseTask, processData, "Process Event for data", true); + + using RecoTracks = soa::Join; + void processMcItsTpc(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 >= kCentBoundaries[0] && imp < kCentBoundaries[1]) { + centclass = kCentValues[0]; + } + if (imp >= kCentBoundaries[1] && imp < kCentBoundaries[2]) { + centclass = kCentValues[1]; + } + if (imp >= kCentBoundaries[2] && imp < kCentBoundaries[3]) { + centclass = kCentValues[2]; + } + if (imp >= kCentBoundaries[3] && imp < kCentBoundaries[4]) { + centclass = kCentValues[3]; + } + if (imp >= kCentBoundaries[4] && imp < kCentBoundaries[5]) { + centclass = kCentValues[4]; + } + if (imp >= kCentBoundaries[5] && imp < kCentBoundaries[6]) { + centclass = kCentValues[5]; + } + if (imp >= kCentBoundaries[6] && imp < kCentBoundaries[7]) { + centclass = kCentValues[6]; + } + if (imp >= kCentBoundaries[7] && imp < kCentBoundaries[8]) { + centclass = kCentValues[7]; + } + if (imp >= kCentBoundaries[8] && imp < kCentBoundaries[9]) { + centclass = kCentValues[8]; + } + + int nCh = 0; + + if (centclass > 0 && centclass < kCentUpperLimit) { + // 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 = std::abs(mcParticle.pdgCode()); + if (pdgCode != kLambdaId) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + if (std::abs(mcParticle.eta()) > kEtaAcceptance) // main acceptance + continue; + histos.fill(HIST("hSparseMCGenWeight"), centclass, RecoDecay::constrainAngle(deltaPhi, 0, 2), std::pow(std::cos(2.0 * RecoDecay::constrainAngle(deltaPhi, 0, 2)), 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, RecoDecay::constrainAngle(deltaPhi, 0, 2), std::pow(std::cos(2.0 * RecoDecay::constrainAngle(deltaPhi, 0, 2)), 2.0), mcParticle.pt(), mcParticle.eta()); + } + if (validAny) { + histos.fill(HIST("hSparseMCRecAllTrackWeight"), centclass, RecoDecay::constrainAngle(deltaPhi, 0, 2), std::pow(std::cos(2.0 * RecoDecay::constrainAngle(deltaPhi, 0, 2)), 2.0), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST("hEventPlaneAngleRec"), RecoDecay::constrainAngle(deltaPhi, 0, 2)); + } + // if any track present, fill + } + } + histos.fill(HIST("hNchVsImpactParameter"), imp, nCh); + } + PROCESS_SWITCH(FlowEseTask, processMcItsTpc, "Process MC for ITSTPC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowEventPlane.cxx b/PWGCF/Flow/Tasks/flowEventPlane.cxx new file mode 100644 index 00000000000..e172f90e13b --- /dev/null +++ b/PWGCF/Flow/Tasks/flowEventPlane.cxx @@ -0,0 +1,849 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file flowEventPlane.cxx +/// \brief Flow calculation using event plane. +/// \author Yash Patley + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::constants::math; + +enum GainClibCorr { + kGainCalibA = 0, + kGainCalibC, + kNGainCalib +}; + +enum CorrectionType { + kFineCorr = 0, + kCoarseCorr, + kNCorr +}; + +enum CollisionParameterType { + kCent = 0, + kVx, + kVy, + kVz +}; + +enum ZDCXYType { + kXa = 0, + kYa, + kXc, + kYc, + kXYAC +}; + +enum ParticleType { + kPi = 0, + kKa, + kPr, + kNPart +}; + +struct FlowEventPlane { + // Configurables + // Collisions + Configurable cMinZVtx{"cMinZVtx", -10.0, "Min VtxZ cut"}; + Configurable cMaxZVtx{"cMaxZVtx", 10.0, "Max VtxZ cut"}; + Configurable cMinCent{"cMinCent", 0., "Minumum Centrality"}; + Configurable cMaxCent{"cMaxCent", 100.0, "Maximum Centrality"}; + Configurable cSel8Trig{"cSel8Trig", true, "Sel8 (T0A + T0C) Selection Run3"}; + 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", true, "Pileup rejection"}; + Configurable cZVtxTimeDiff{"cZVtxTimeDiff", false, "z-vtx time diff selection"}; + Configurable cIsGoodITSLayers{"cIsGoodITSLayers", true, "Good ITS Layers All"}; + Configurable cMinOccupancy{"cMinOccupancy", 0, "Minimum FT0C Occupancy"}; + Configurable cMaxOccupancy{"cMaxOccupancy", 1e6, "Maximum FT0C Occupancy"}; + + // Tracks + Configurable cTrackMinPt{"cTrackMinPt", 0.1, "p_{T} minimum"}; + Configurable cTrackMaxPt{"cTrackMaxPt", 10.0, "p_{T} maximum"}; + Configurable cNEtaBins{"cNEtaBins", 7, "# of eta bins"}; + Configurable cTrackEtaCut{"cTrackEtaCut", 0.8, "Pseudorapidity cut"}; + Configurable cTrackGlobal{"cTrackGlobal", true, "Global Track"}; + Configurable cTrackDcaXYCut{"cTrackDcaXYCut", 0.1, "DcaXY Cut"}; + Configurable cTrackDcaZCut{"cTrackDcaZCut", 1., "DcaXY Cut"}; + Configurable cNRapBins{"cNRapBins", 5, "# of y bins"}; + Configurable cNInvMassBins{"cNInvMassBins", 500, "# of m bins"}; + + // Track PID + Configurable cTpcNSigmaCut{"cTpcNSigmaCut", 2, "TPC NSigma Cut"}; + Configurable cTpcRejCut{"cTpcRejCut", 3, "TPC Rej Cut"}; + Configurable cTofNSigmaCut{"cTofNSigmaCut", 2, "TOF NSigma Cut"}; + Configurable cTofRejCut{"cTofRejCut", 3, "TOF Rej Cut"}; + Configurable cPionPtCut{"cPionPtCut", 0.6, "Pion TPC pT cutoff"}; + Configurable cKaonPtCut{"cKaonPtCut", 0.6, "Kaon TPC pT cutoff"}; + Configurable cProtonPtCut{"cProtonPtCut", 1.1, "Proton TPC pT cutoff"}; + + // Resonance + Configurable cResRapCut{"cResRapCut", 0.5, "Resonance rapidity cut"}; + + // Gain calibration + Configurable cDoGainCalib{"cDoGainCalib", false, "Gain Calib Flag"}; + Configurable cUseAlphaZDC{"cUseAlphaZDC", true, "Use Alpha ZDC"}; + + // Coarse binning factor + Configurable cAxisCBF{"cAxisCBF", 5, "Coarse Bin Factor"}; + + // Cent Vx Vy Vz Bins + Configurable cAxisCentBins{"cAxisCentBins", 20, "NBins Centrality"}; + Configurable cAxisVxyBins{"cAxisVxyBins", 20, "NBins Vx Vy"}; + Configurable cAxisVzBins{"cAxisVzBins", 20, "NBins Vz"}; + Configurable cAxisVxMin{"cAxisVxMin", -0.06, "Vx Min"}; + Configurable cAxisVxMax{"cAxisVxMax", -0.02, "Vx Max"}; + Configurable cAxisVyMin{"cAxisVyMin", -0.01, "Vy Min"}; + Configurable cAxisVyMax{"cAxisVyMax", 0.006, "Vy Max"}; + + // Corrections + Configurable cApplyRecentCorr{"cApplyRecentCorr", false, "Apply recentering"}; + Configurable> cCorrFlagVector{"cCorrFlagVector", {0, 0, 0, 0, 0, 0}, "Correction Flag"}; + + // CCDB + Configurable cCcdbUrl{"cCcdbUrl", "http://ccdb-test.cern.ch:8080", "url of ccdb"}; + Configurable cCcdbPath{"cCcdbPath", "Users/y/ypatley/DFOO", "Path for ccdb-object"}; + + // Initialize CCDB Service + Service ccdbService; + + // Histogram registry: an object to hold your histograms + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Global objects + const float zdcDenThrs = 1e-4; + float cent = 0., mult = 0.; + float posX = 0., posY = 0., posZ = 0.; + std::vector> vCoarseCorrHistNames = { + {"hXZNAVsCentVxVyVz"}, + {"hYZNAVsCentVxVyVz"}, + {"hXZNCVsCentVxVyVz"}, + {"hYZNCVsCentVxVyVz"}}; + std::vector> vFineCorrHistNames = { + {"hXZNAVsCent", "hXZNAVsVx", "hXZNAVsVy", "hXZNAVsVz"}, + {"hYZNAVsCent", "hYZNAVsVx", "hYZNAVsVy", "hYZNAVsVz"}, + {"hXZNCVsCent", "hXZNCVsVx", "hXZNCVsVy", "hXZNCVsVz"}, + {"hYZNCVsCent", "hYZNCVsVx", "hYZNCVsVy", "hYZNCVsVz"}}; + std::map>> corrTypeHistNameMap = {{kFineCorr, vFineCorrHistNames}, {kCoarseCorr, vCoarseCorrHistNames}}; + + // Container for histograms + struct CorrectionHistContainer { + std::array hGainCalib; + std::array, 4>, 6> vCoarseCorrHist; + std::array, 4>, 6> vFineCorrHist; + } CorrectionHistContainer; + + // Run number + int cRunNum = 0, lRunNum = 0; + + void init(InitContext const&) + { + // Set CCDB url + ccdbService->setURL(cCcdbUrl.value); + ccdbService->setCaching(true); + + // Define axes + const AxisSpec axisZDCEnergy{500, 0, 500, "ZD[AC] Signal"}; + + const AxisSpec axisCent{100, 0., 100, "FT0C%"}; + const AxisSpec axisVx{cAxisVxyBins, cAxisVxMin, cAxisVxMax, "V_{X}(cm)"}; + const AxisSpec axisVy{cAxisVxyBins, cAxisVyMin, cAxisVyMax, "V_{Y}(cm)"}; + const AxisSpec axisVz{cAxisVzBins, cMinZVtx, cMaxZVtx, "V_{Z}(cm)"}; + + const AxisSpec axisCoarseCent{cAxisCentBins / cAxisCBF, cMinCent, cMaxCent, "FT0C%"}; + const AxisSpec axisCoarseVx{cAxisVxyBins / cAxisCBF, cAxisVxMin, cAxisVxMax, "V_{x}"}; + const AxisSpec axisCoarseVy{cAxisVxyBins / cAxisCBF, cAxisVyMin, cAxisVyMax, "V_{y}"}; + const AxisSpec axisCoarseVz{cAxisVzBins / cAxisCBF, cMinZVtx, cMaxZVtx, "V_{z}"}; + + const AxisSpec axisFineCent{cAxisCentBins, cMinCent, cMaxCent, "FT0C%"}; + const AxisSpec axisFineVx{cAxisVxyBins, cAxisVxMin, cAxisVxMax, "V_{x}"}; + const AxisSpec axisFineVy{cAxisVxyBins, cAxisVyMin, cAxisVyMax, "V_{x}"}; + const AxisSpec axisFineVz{cAxisVzBins, cMinZVtx, cMaxZVtx, "V_{z}"}; + + const AxisSpec axisXa{40, -1, 1, "X^{ZNA}_{1}"}; + const AxisSpec axisYa{40, -1, 1, "Y^{ZNA}_{1}"}; + const AxisSpec axisXc{40, -1, 1, "X^{ZNC}_{1}"}; + const AxisSpec axisYc{40, -1, 1, "Y^{ZNC}_{1}"}; + + const AxisSpec axisPsi{18, -PIHalf, PIHalf, "#Psi_{SP}"}; + + const AxisSpec axisXYac{600, -6, 6, "Q^{t}Q^{p}"}; + const AxisSpec axisV1{400, -4, 4, "v_{1}"}; + + const AxisSpec axisTrackPt{100, 0., 10., "p_{T} (GeV/#it{c})"}; + const AxisSpec axisTrackEta{cNEtaBins, -0.8, 0.8, "#eta"}; + const AxisSpec axisTrackRap{cNRapBins, -0.5, 0.5, "y"}; + const AxisSpec axisInvMass{cNInvMassBins, 0.87, 1.12, "M_{KK} (GeV/#it{c}^{2}"}; + + const AxisSpec axisTrackDcaXY{60, -0.15, 0.15, "DCA_{XY}"}; + const AxisSpec axisTrackDcaZ{230, -1.15, 1.15, "DCA_{XY}"}; + const AxisSpec axisTrackdEdx{360, 20, 200, "#frac{dE}{dx}"}; + const AxisSpec axisTrackNSigma{161, -4.025, 4.025, {"n#sigma"}}; + + // Create histograms + // Event + histos.add("Event/hCent", "FT0C%", kTH1F, {axisCent}); + histos.add("Event/hVx", "V_{x}", kTH1F, {axisVx}); + histos.add("Event/hVy", "V_{y}", kTH1F, {axisVy}); + histos.add("Event/hVz", "V_{z}", kTH1F, {axisVz}); + + // Gain calib + histos.add("QA/GainCalib/hZNASignal", "ZNA Signal", kTH2F, {{4, 0, 4}, {axisZDCEnergy}}); + histos.add("QA/GainCalib/hZNCSignal", "ZNC Signal", kTH2F, {{4, 0, 4}, {axisZDCEnergy}}); + histos.add("QA/hZNASignal", "ZNA Signal", kTProfile2D, {{4, 0, 4}, {axisVz}}); + histos.add("QA/hZNCSignal", "ZNC Signal", kTProfile2D, {{4, 0, 4}, {axisVz}}); + histos.add("QA/hZNAEnergyCommon", "ZNA Energy Common", kTProfile, {axisVz}); + histos.add("QA/hZNCEnergyCommon", "ZNC Energy Common", kTProfile, {axisVz}); + + // Corrections + histos.add("CorrHist/hWtXZNA", "X^{ZNA}_{1}", kTHnSparseF, {axisCoarseCent, axisCoarseVx, axisCoarseVy, axisCoarseVz}); + histos.add("CorrHist/hWtYZNA", "Y^{ZNA}_{1}", kTHnSparseF, {axisCoarseCent, axisCoarseVx, axisCoarseVy, axisCoarseVz}); + histos.add("CorrHist/hWtXZNC", "X^{ZNC}_{1}", kTHnSparseF, {axisCoarseCent, axisCoarseVx, axisCoarseVy, axisCoarseVz}); + histos.add("CorrHist/hWtYZNC", "Y^{ZNC}_{1}", kTHnSparseF, {axisCoarseCent, axisCoarseVx, axisCoarseVy, axisCoarseVz}); + histos.add("CorrHist/hUWtXZNA", "X^{ZNA}_{1}", kTHnSparseF, {axisCoarseCent, axisCoarseVx, axisCoarseVy, axisCoarseVz}); + histos.add("CorrHist/hUWtYZNA", "Y^{ZNA}_{1}", kTHnSparseF, {axisCoarseCent, axisCoarseVx, axisCoarseVy, axisCoarseVz}); + histos.add("CorrHist/hUWtXZNC", "X^{ZNC}_{1}", kTHnSparseF, {axisCoarseCent, axisCoarseVx, axisCoarseVy, axisCoarseVz}); + histos.add("CorrHist/hUWtYZNC", "Y^{ZNC}_{1}", kTHnSparseF, {axisCoarseCent, axisCoarseVx, axisCoarseVy, axisCoarseVz}); + histos.add("CorrHist/hXZNAVsCent", "X^{ZNA}_{1} Vs Cent", kTProfile, {axisFineCent}); + histos.add("CorrHist/hXZNAVsVx", "X^{ZNA}_{1} Vs V_{x}", kTProfile, {axisFineVx}); + histos.add("CorrHist/hXZNAVsVy", "X^{ZNA}_{1} Vs V_{y}", kTProfile, {axisFineVy}); + histos.add("CorrHist/hXZNAVsVz", "X^{ZNA}_{1} Vs V_{z}", kTProfile, {axisFineVz}); + histos.add("CorrHist/hYZNAVsCent", "Y^{ZNA}_{1} Vs Cent", kTProfile, {axisFineCent}); + histos.add("CorrHist/hYZNAVsVx", "Y^{ZNA}_{1} Vs V_{x}", kTProfile, {axisFineVx}); + histos.add("CorrHist/hYZNAVsVy", "Y^{ZNA}_{1} Vs V_{y}", kTProfile, {axisFineVy}); + histos.add("CorrHist/hYZNAVsVz", "Y^{ZNA}_{1} Vs V_{z}", kTProfile, {axisFineVz}); + histos.add("CorrHist/hXZNCVsCent", "X^{ZNC}_{1} Vs Cent", kTProfile, {axisFineCent}); + histos.add("CorrHist/hXZNCVsVx", "X^{ZNC}_{1} Vs V_{x}", kTProfile, {axisFineVx}); + histos.add("CorrHist/hXZNCVsVy", "X^{ZNC}_{1} Vs V_{y}", kTProfile, {axisFineVy}); + histos.add("CorrHist/hXZNCVsVz", "X^{ZNC}_{1} Vs V_{z}", kTProfile, {axisFineVz}); + histos.add("CorrHist/hYZNCVsCent", "Y^{ZNC}_{1} Vs Cent", kTProfile, {axisFineCent}); + histos.add("CorrHist/hYZNCVsVx", "Y^{ZNC}_{1} Vs V_{x}", kTProfile, {axisFineVx}); + histos.add("CorrHist/hYZNCVsVy", "Y^{ZNC}_{1} Vs V_{y}", kTProfile, {axisFineVy}); + histos.add("CorrHist/hYZNCVsVz", "Y^{ZNC}_{1} Vs V_{z}", kTProfile, {axisFineVz}); + + // Checks + histos.add("Checks/hPsiSPA", "#Psi_{SP}^{A} distribution", kTH2F, {axisCent, axisPsi}); + histos.add("Checks/hPsiSPC", "#Psi_{SP}^{C} distribution", kTH2F, {axisCent, axisPsi}); + histos.add("Checks/hCosPsiSPAC", "Cos(#Psi_{SP}^{A} #minus #Psi_{SP}^{C}) distribution", kTProfile, {axisCent}); + histos.add("Checks/hSinPsiSPAC", "Sin(#Psi_{SP}^{A} #minus #Psi_{SP}^{C}) distribution", kTProfile, {axisCent}); + histos.add("Checks/hXaXc", "X^{A}_{1}X^{C}_{1}", kTProfile, {axisCent}); + histos.add("Checks/hYaYc", "Y^{A}_{1}Y^{C}_{1}", kTProfile, {axisCent}); + histos.add("Checks/hXaYc", "X^{A}_{1}Y^{C}_{1}", kTProfile, {axisCent}); + histos.add("Checks/hYaXc", "Y^{A}_{1}X^{C}_{1}", kTProfile, {axisCent}); + + // Track QA + histos.add("TrackQA/hPtDcaXY", "DCA_{XY} vs p_{T}", kTH2F, {axisTrackPt, axisTrackDcaXY}); + histos.add("TrackQA/hPtDcaZ", "DCA_{Z} vs p_{T}", kTH2F, {axisTrackPt, axisTrackDcaZ}); + histos.add("TrackQA/hTrackTPCdEdX", "hTrackTPCdEdX", kTH2F, {axisTrackPt, axisTrackdEdx}); + + // Charged particle directed flow + histos.add("DF/hQaQc", "X^{A}_{1}X^{C}_{1} + Y^{A}_{1}Y^{C}_{1}", kTProfile, {axisCent}); + histos.add("DF/hAQu", "u_{x}X^{A}_{1} + u_{y}Y^{A}_{1}", kTProfile2D, {axisCent, axisTrackEta}); + histos.add("DF/hCQu", "u_{x}X^{C}_{1} + u_{y}Y^{C}_{1}", kTProfile2D, {axisCent, axisTrackEta}); + histos.add("DF/hAQuPos", "u_{x}X^{A}_{1} + u_{y}Y^{A}_{1}", kTProfile2D, {axisCent, axisTrackEta}); + histos.add("DF/hCQuPos", "u_{x}X^{C}_{1} + u_{y}Y^{C}_{1}", kTProfile2D, {axisCent, axisTrackEta}); + histos.add("DF/hAQuNeg", "u_{x}X^{A}_{1} + u_{y}Y^{A}_{1}", kTProfile2D, {axisCent, axisTrackEta}); + histos.add("DF/hCQuNeg", "u_{x}X^{C}_{1} + u_{y}Y^{C}_{1}", kTProfile2D, {axisCent, axisTrackEta}); + + // Identified particle + histos.add("PartId/Pion/hdEdX", "PartId/Pion/hdEdX", kTH2F, {axisTrackPt, axisTrackdEdx}); + histos.add("PartId/Pion/hTPCNSigma", "PartId/Pion/hTPCNSigma", kTH2F, {axisTrackPt, axisTrackNSigma}); + histos.add("PartId/Pion/hTOFNSigma", "PartId/Pion/hTOFNSigma", kTH2F, {axisTrackPt, axisTrackNSigma}); + histos.add("PartId/Pion/hAQuPos", "PartId/Pion/hAQuPos", kTProfile2D, {axisCent, axisTrackEta}); + histos.add("PartId/Pion/hAQuNeg", "PartId/Pion/hAQuNeg", kTProfile2D, {axisCent, axisTrackEta}); + histos.add("PartId/Pion/hCQuPos", "PartId/Pion/hCQuPos", kTProfile2D, {axisCent, axisTrackEta}); + histos.add("PartId/Pion/hCQuNeg", "PartId/Pion/hCQuNeg", kTProfile2D, {axisCent, axisTrackEta}); + histos.addClone("PartId/Pion/", "PartId/Kaon/"); + histos.addClone("PartId/Pion/", "PartId/Proton/"); + + // Resonance + histos.add("Reso/Phi/hSigCentPtInvMass", "hUSCentPtInvMass", kTH3F, {axisCent, axisTrackPt, axisInvMass}); + histos.add("Reso/Phi/hBkgCentPtInvMass", "hLSCentPtInvMass", kTH3F, {axisCent, axisTrackPt, axisInvMass}); + histos.add("Reso/Phi/Sig/hPhiQuA", "hPhiQuA", kTProfile3D, {axisCent, axisTrackRap, axisInvMass}); + histos.add("Reso/Phi/Sig/hPhiQuC", "hPhiQuC", kTProfile3D, {axisCent, axisTrackRap, axisInvMass}); + histos.add("Reso/Phi/Bkg/hPhiQuA", "hPhiQuA", kTProfile3D, {axisCent, axisTrackRap, axisInvMass}); + histos.add("Reso/Phi/Bkg/hPhiQuC", "hPhiQuC", kTProfile3D, {axisCent, axisTrackRap, axisInvMass}); + } + + template + bool selCollision(C const& col) + { + if (col.posZ() <= cMinZVtx || col.posZ() >= cMaxZVtx) { // VtxZ selection + return false; + } + + if (cSel8Trig && !col.sel8()) { // Sel8 selection + return false; + } + + cent = col.centFT0C(); + if (cent <= cMinCent || cent >= cMaxCent) { // Centrality selection + return false; + } + + if (col.ft0cOccupancyInTimeRange() < cMinOccupancy || col.ft0cOccupancyInTimeRange() > cMaxOccupancy) { // Occupancy cut + return false; + } + + if (cTriggerTvxSel && !col.selection_bit(aod::evsel::kIsTriggerTVX)) { // Time and Vertex trigger + return false; + } + + if (cTFBorder && !col.selection_bit(aod::evsel::kNoTimeFrameBorder)) { // Time frame border + return false; + } + + if (cNoItsROBorder && !col.selection_bit(aod::evsel::kNoITSROFrameBorder)) { // ITS Readout frame border + return false; + } + + if (cItsTpcVtx && !col.selection_bit(aod::evsel::kIsVertexITSTPC)) { // ITS+TPC Vertex + return false; + } + + if (cPileupReject && !col.selection_bit(aod::evsel::kNoSameBunchPileup)) { // Pile-up rejection + return false; + } + + if (cZVtxTimeDiff && !col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { // ZvtxFT0 vs PV + return false; + } + + if (cIsGoodITSLayers && !col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { // All ITS layer active + return false; + } + + // Set Multiplicity + mult = col.multNTracksHasTPC(); + + return true; + } + + // Track Selection + template + bool selectTrack(T const& track) + { + if (track.pt() <= cTrackMinPt || track.pt() >= cTrackMaxPt || std::abs(track.eta()) >= cTrackEtaCut) { + return false; + } + + if (cTrackGlobal && !track.isGlobalTrackWoDCA()) { + return false; + } + + if (std::abs(track.dcaXY()) > cTrackDcaXYCut || std::abs(track.dcaZ()) > cTrackDcaZCut) { + return false; + } + + return true; + } + + template + bool checkTrackPid(float const& ptCut, float const& trackPt, std::vector const& vTpcNsig, std::vector const& vTofNsig, bool const& tofFlag) + { + bool retFlag = false; + if (tofFlag) { + if (vTofNsig[part1] < cTofNSigmaCut && vTofNsig[part2] > cTofRejCut && vTofNsig[part3] > cTofRejCut && vTpcNsig[part1] < cTpcNSigmaCut) { + retFlag = true; + } + } else { + if (trackPt < ptCut && vTpcNsig[part1] < cTpcNSigmaCut && vTpcNsig[part2] > cTpcRejCut && vTpcNsig[part3] > cTpcRejCut) { + retFlag = true; + } + } + return retFlag; + } + + template + bool identifyTrack(T const& track) + { + std::vector vPtCut = {cPionPtCut, cKaonPtCut, cProtonPtCut}; + std::vector vTpcNsig = {std::abs(track.tpcNSigmaPi()), std::abs(track.tpcNSigmaKa()), std::abs(track.tpcNSigmaPr())}; + std::vector vTofNsig = {std::abs(track.tofNSigmaPi()), std::abs(track.tofNSigmaKa()), std::abs(track.tofNSigmaPr())}; + bool retFlag = false; + + if (partType == kPi && checkTrackPid(vPtCut[kPi], track.pt(), vTpcNsig, vTofNsig, track.hasTOF())) { + retFlag = true; + } else if (partType == kKa && checkTrackPid(vPtCut[kKa], track.pt(), vTpcNsig, vTofNsig, track.hasTOF())) { + retFlag = true; + } else if (partType == kPr && checkTrackPid(vPtCut[kPr], track.pt(), vTpcNsig, vTofNsig, track.hasTOF())) { + retFlag = true; + } else { + return false; + } + + return retFlag; + } + + void gainCalib(bool const& loadGainCalib, float const& vz, std::array& eA, std::array& eC) + { + // Store gain calibration histograms per run number + if (loadGainCalib) { + std::string ccdbPath = static_cast(cCcdbPath) + "/GainCalib" + "/Run" + std::to_string(cRunNum); + auto ccdbObj = ccdbService->getForTimeStamp(ccdbPath, -1); + CorrectionHistContainer.hGainCalib[0] = reinterpret_cast(ccdbObj->FindObject("hZNASignal")); + CorrectionHistContainer.hGainCalib[1] = reinterpret_cast(ccdbObj->FindObject("hZNCSignal")); + } + + // Apply gain calibration + float vA = 0., vC = 0.; + for (int i = 0; i < static_cast(eA.size()); ++i) { + vA = CorrectionHistContainer.hGainCalib[0]->GetBinContent(CorrectionHistContainer.hGainCalib[0]->FindBin(i + 0.5, vz + 0.00001)); + vC = CorrectionHistContainer.hGainCalib[1]->GetBinContent(CorrectionHistContainer.hGainCalib[1]->FindBin(i + 0.5, vz + 0.00001)); + eA[i] *= vA; + eC[i] *= vC; + } + } + + std::vector getAvgCorrFactors(int const& itr, CorrectionType const& corrType, std::array const& vCollParam) + { + std::vector vAvgOutput = {0., 0., 0., 0.}; + int binarray[4]; + if (corrType == kCoarseCorr) { + int cntrx = 0; + for (auto const& v : CorrectionHistContainer.vCoarseCorrHist[itr]) { + for (auto const& h : v) { + binarray[kCent] = h->GetAxis(kCent)->FindBin(vCollParam[kCent] + 0.0001); + binarray[kVx] = h->GetAxis(kVx)->FindBin(vCollParam[kVx] + 0.0001); + binarray[kVy] = h->GetAxis(kVy)->FindBin(vCollParam[kVy] + 0.0001); + binarray[kVz] = h->GetAxis(kVz)->FindBin(vCollParam[kVz] + 0.0001); + vAvgOutput[cntrx] += h->GetBinContent(h->GetBin(binarray)); + } + ++cntrx; + } + } else { + int cntrx = 0; + for (auto const& v : CorrectionHistContainer.vFineCorrHist[itr]) { + int cntry = 0; + for (auto const& h : v) { + vAvgOutput[cntrx] += h->GetBinContent(h->GetXaxis()->FindBin(vCollParam[cntry] + 0.0001)); + ++cntry; + } + ++cntrx; + } + } + + return vAvgOutput; + } + + void applyCorrection(bool const& loadShiftCorr, std::array const& inputParam, std::array& outputParam) + { + std::vector vCorrFlags = static_cast>(cCorrFlagVector); + int nitr = vCorrFlags.size(); + CorrectionType corrType = kFineCorr; + std::string ccdbPath; + + // Correction iterations + for (int i = 0; i < nitr; ++i) { + // Don't correct if corrFlag != 1 + if (vCorrFlags[i] != 1) { + continue; + } + + // Set correction type + if (i % kNCorr == 0) { + corrType = kCoarseCorr; + } else { + corrType = kFineCorr; + } + + // Check current and last run number, fetch ccdb object and store corrections in container + if (loadShiftCorr) { + // Set ccdb path + ccdbPath = static_cast(cCcdbPath) + "/CorrItr_" + std::to_string(i + 1) + "/Run" + std::to_string(cRunNum); + + // Get object from CCDB + auto ccdbObject = ccdbService->getForTimeStamp(ccdbPath, -1); + + // Check CCDB Object + if (!ccdbObject) { + LOGF(warning, "CCDB OBJECT NOT FOUND"); + return; + } + + // Store histograms in Hist Container + std::vector> vHistNames = corrTypeHistNameMap.at(corrType); + int cntrx = 0; + for (auto const& x : vHistNames) { + int cntry = 0; + for (auto const& y : x) { + if (corrType == kFineCorr) { + CorrectionHistContainer.vFineCorrHist[i][cntrx][cntry] = reinterpret_cast(ccdbObject->FindObject(y.c_str())); + } else { + CorrectionHistContainer.vCoarseCorrHist[i][cntrx][cntry] = reinterpret_cast(ccdbObject->FindObject(y.c_str())); + } + ++cntry; + } + ++cntrx; + } + } + + // Get averages + std::vector vAvg = getAvgCorrFactors(i, corrType, inputParam); + + // Apply correction + outputParam[kXa] -= vAvg[kXa]; + outputParam[kYa] -= vAvg[kYa]; + outputParam[kXc] -= vAvg[kXc]; + outputParam[kYc] -= vAvg[kYc]; + } + } + + template + void getResoFlow(T const& tracks, std::array const& vSP) + { + float ux = 0., uy = 0., v1a = 0., v1c = 0.; + for (auto const& [track1, track2] : soa::combinations(soa::CombinationsFullIndexPolicy(tracks, tracks))) { + // Discard same track + if (track1.index() == track2.index()) { + continue; + } + + // Discard same charge track + if (track1.sign() == track2.sign()) { + continue; + } + + // Select track + if (!selectTrack(track1) || !selectTrack(track2)) { + continue; + } + + // Identify track + if (!identifyTrack(track1) || !identifyTrack(track2)) { + continue; + } + + // Apply rapidity acceptance + std::array v = {track1.px() + track2.px(), track1.py() + track2.py(), track1.pz() + track2.pz()}; + if (RecoDecay::y(v, MassPhi) >= cResRapCut) { + continue; + } + + // Reconstruct invariant mass + float p = RecoDecay::p((track1.px() + track2.px()), (track1.py() + track2.py()), (track1.pz() + track2.pz())); + float e = RecoDecay::e(track1.px(), track1.py(), track1.pz(), MassKaonCharged) + RecoDecay::e(track2.px(), track2.py(), track2.pz(), MassKaonCharged); + float m = std::sqrt(RecoDecay::m2(p, e)); + + // Get directed flow + ux = std::cos(RecoDecay::phi(v)); + uy = std::sin(RecoDecay::phi(v)); + v1a = ux * vSP[kXa] + uy * vSP[kYa]; + v1c = ux * vSP[kXc] + uy * vSP[kYc]; + + // Fill signal histogram + histos.fill(HIST("Reso/Phi/hSigCentPtInvMass"), cent, RecoDecay::pt(v), m); + histos.fill(HIST("Reso/Phi/Sig/hPhiQuA"), cent, RecoDecay::y(v, MassPhi), m, v1a); + histos.fill(HIST("Reso/Phi/Sig/hPhiQuC"), cent, RecoDecay::y(v, MassPhi), m, v1c); + + // Get background + p = RecoDecay::p((track1.px() - track2.px()), (track1.py() - track2.py()), (track1.pz() - track2.pz())); + m = std::sqrt(RecoDecay::m2(p, e)); + v[0] = track1.px() - track2.px(); + v[1] = track1.py() - track2.py(); + v[2] = track1.pz() - track2.pz(); + ux = std::cos(RecoDecay::phi(v)); + uy = std::sin(RecoDecay::phi(v)); + v1a = ux * vSP[kXa] + uy * vSP[kYa]; + v1c = ux * vSP[kXc] + uy * vSP[kYc]; + + // Fill bkg histogram + histos.fill(HIST("Reso/Phi/hBkgCentPtInvMass"), cent, RecoDecay::pt(v), m); + histos.fill(HIST("Reso/Phi/Bkg/hPhiQuA"), cent, RecoDecay::y(v, MassPhi), m, v1a); + histos.fill(HIST("Reso/Phi/Bkg/hPhiQuC"), cent, RecoDecay::y(v, MassPhi), m, v1c); + } + } + + template + void getIdHadronFlow(float const& cent, T const& track, float const& v1a, float const& v1c) + { + static constexpr std::string_view SubDir[] = {"Pion/", "Kaon/", "Proton/"}; + float tpcNsigma = 0., tofNsigma = 0.; + if (part == kPi) { + tpcNsigma = track.tpcNSigmaPi(); + tofNsigma = track.tofNSigmaPi(); + } else if (part == kKa) { + tpcNsigma = track.tpcNSigmaKa(); + tofNsigma = track.tofNSigmaKa(); + } else if (part == kPr) { + tpcNsigma = track.tpcNSigmaPr(); + tofNsigma = track.tofNSigmaPr(); + } else { + return; + } + histos.fill(HIST("PartId/") + HIST(SubDir[part]) + HIST("hdEdX"), track.pt(), track.tpcSignal()); + histos.fill(HIST("PartId/") + HIST(SubDir[part]) + HIST("hTPCNSigma"), track.pt(), tpcNsigma); + if (track.hasTOF()) { + histos.fill(HIST("PartId/") + HIST(SubDir[part]) + HIST("hTOFNSigma"), track.pt(), tofNsigma); + } + if (track.sign() > 0) { + histos.fill(HIST("PartId/") + HIST(SubDir[part]) + HIST("hAQuPos"), cent, track.eta(), v1a); + histos.fill(HIST("PartId/") + HIST(SubDir[part]) + HIST("hCQuPos"), cent, track.eta(), v1c); + } else { + histos.fill(HIST("PartId/") + HIST(SubDir[part]) + HIST("hAQuNeg"), cent, track.eta(), v1a); + histos.fill(HIST("PartId/") + HIST(SubDir[part]) + HIST("hCQuNeg"), cent, track.eta(), v1c); + } + } + + void fillCorrHist(std::array const& vCollParam, std::array const& vSP) + { + histos.fill(HIST("CorrHist/hWtXZNA"), vCollParam[kCent], vCollParam[kVx], vCollParam[kVy], vCollParam[kVz], vSP[kXa]); + histos.fill(HIST("CorrHist/hWtYZNA"), vCollParam[kCent], vCollParam[kVx], vCollParam[kVy], vCollParam[kVz], vSP[kYa]); + histos.fill(HIST("CorrHist/hWtXZNC"), vCollParam[kCent], vCollParam[kVx], vCollParam[kVy], vCollParam[kVz], vSP[kXc]); + histos.fill(HIST("CorrHist/hWtYZNC"), vCollParam[kCent], vCollParam[kVx], vCollParam[kVy], vCollParam[kVz], vSP[kYc]); + histos.fill(HIST("CorrHist/hUWtXZNA"), vCollParam[kCent], vCollParam[kVx], vCollParam[kVy], vCollParam[kVz]); + histos.fill(HIST("CorrHist/hUWtYZNA"), vCollParam[kCent], vCollParam[kVx], vCollParam[kVy], vCollParam[kVz]); + histos.fill(HIST("CorrHist/hUWtXZNC"), vCollParam[kCent], vCollParam[kVx], vCollParam[kVy], vCollParam[kVz]); + histos.fill(HIST("CorrHist/hUWtYZNC"), vCollParam[kCent], vCollParam[kVx], vCollParam[kVy], vCollParam[kVz]); + histos.fill(HIST("CorrHist/hXZNAVsCent"), vCollParam[kCent], vSP[kXa]); + histos.fill(HIST("CorrHist/hXZNAVsVx"), vCollParam[kVx], vSP[kXa]); + histos.fill(HIST("CorrHist/hXZNAVsVy"), vCollParam[kVy], vSP[kXa]); + histos.fill(HIST("CorrHist/hXZNAVsVz"), vCollParam[kVz], vSP[kXa]); + histos.fill(HIST("CorrHist/hYZNAVsCent"), vCollParam[kCent], vSP[kYa]); + histos.fill(HIST("CorrHist/hYZNAVsVx"), vCollParam[kVx], vSP[kYa]); + histos.fill(HIST("CorrHist/hYZNAVsVy"), vCollParam[kVy], vSP[kYa]); + histos.fill(HIST("CorrHist/hYZNAVsVz"), vCollParam[kVz], vSP[kYa]); + histos.fill(HIST("CorrHist/hXZNCVsCent"), vCollParam[kCent], vSP[kXc]); + histos.fill(HIST("CorrHist/hXZNCVsVx"), vCollParam[kVx], vSP[kXc]); + histos.fill(HIST("CorrHist/hXZNCVsVy"), vCollParam[kVy], vSP[kXc]); + histos.fill(HIST("CorrHist/hXZNCVsVz"), vCollParam[kVz], vSP[kXc]); + histos.fill(HIST("CorrHist/hYZNCVsCent"), vCollParam[kCent], vSP[kYc]); + histos.fill(HIST("CorrHist/hYZNCVsVx"), vCollParam[kVx], vSP[kYc]); + histos.fill(HIST("CorrHist/hYZNCVsVy"), vCollParam[kVy], vSP[kYc]); + histos.fill(HIST("CorrHist/hYZNCVsVz"), vCollParam[kVz], vSP[kYc]); + } + + template + void fillTrackHist(T const& track) + { + histos.fill(HIST("TrackQA/hPtDcaZ"), track.pt(), track.dcaZ()); + histos.fill(HIST("TrackQA/hPtDcaXY"), track.pt(), track.dcaXY()); + } + + template + bool analyzeCollision(C const& collision, std::array& vSP) + { + // Event selection + if (!selCollision(collision)) { + return false; + } + posX = collision.posX(); + posY = collision.posY(); + posZ = collision.posZ(); + std::array vCollParam = {cent, posX, posY, posZ}; + + // Fill event QA + histos.fill(HIST("Event/hCent"), cent); + histos.fill(HIST("Event/hVx"), posX); + histos.fill(HIST("Event/hVy"), posY); + histos.fill(HIST("Event/hVz"), posZ); + + // Get bunch crossing + auto bc = collision.template foundBC_as(); + cRunNum = collision.template foundBC_as().runNumber(); + + // Load calibration flags + bool loadGainCalib = false, loadShiftCorr = false; + if (cRunNum != lRunNum) { + loadGainCalib = true; + loadShiftCorr = true; + } + + // check zdc + if (!bc.has_zdc()) { + lRunNum = cRunNum; + return false; + } + + auto zdc = bc.zdc(); + auto znaEnergy = zdc.energySectorZNA(); + auto zncEnergy = zdc.energySectorZNC(); + auto znaEnergyCommon = zdc.energyCommonZNA(); + auto zncEnergyCommon = zdc.energyCommonZNC(); + + // check energy deposits + if (znaEnergyCommon <= 0 || zncEnergyCommon <= 0 || znaEnergy[0] <= 0 || znaEnergy[1] <= 0 || znaEnergy[2] <= 0 || znaEnergy[3] <= 0 || zncEnergy[0] <= 0 || zncEnergy[1] <= 0 || zncEnergy[2] <= 0 || zncEnergy[3] <= 0) { + lRunNum = cRunNum; + return false; + } + + // Fill gain calib histograms + for (int iCh = 0; iCh < kXYAC; ++iCh) { + histos.fill(HIST("QA/hZNASignal"), iCh + 0.5, vCollParam[kVz], znaEnergy[iCh]); + histos.fill(HIST("QA/hZNCSignal"), iCh + 0.5, vCollParam[kVz], zncEnergy[iCh]); + histos.fill(HIST("QA/hZNAEnergyCommon"), vCollParam[kVz], znaEnergyCommon); + histos.fill(HIST("QA/hZNCEnergyCommon"), vCollParam[kVz], zncEnergyCommon); + } + + // Do gain calibration + if (cDoGainCalib) { + gainCalib(loadGainCalib, vCollParam[kVz], znaEnergy, zncEnergy); + } + + // Fill zdc signal + for (int iCh = 0; iCh < kXYAC; ++iCh) { + histos.fill(HIST("QA/GainCalib/hZNASignal"), iCh + 0.5, znaEnergy[iCh]); + histos.fill(HIST("QA/GainCalib/hZNCSignal"), iCh + 0.5, zncEnergy[iCh]); + } + + auto alphaZDC = 0.395; + const double x[4] = {-1.75, 1.75, -1.75, 1.75}; + const double y[4] = {-1.75, -1.75, 1.75, 1.75}; + + // Calculate X and Y + float znaXNum = 0., znaYNum = 0., zncXNum = 0., zncYNum = 0.; + float znaDen = 0., zncDen = 0.; + float znaWt = 0., zncWt = 0.; + + // Loop over zdc sectors + for (int i = 0; i < kXYAC; ++i) { + if (cUseAlphaZDC) { + znaWt = std::pow(znaEnergy[i], alphaZDC); + zncWt = std::pow(zncEnergy[i], alphaZDC); + } else { + znaWt = znaEnergy[i]; + zncWt = zncEnergy[i]; + } + znaXNum -= znaWt * x[i]; + znaYNum += znaWt * y[i]; + zncXNum += zncWt * x[i]; + zncYNum += zncWt * y[i]; + znaDen += znaWt; + zncDen += zncWt; + } + + if (znaDen < zdcDenThrs || zncDen < zdcDenThrs) { + lRunNum = cRunNum; + return false; + } + + // Get X and Y for A and C side ZNA + vSP[kXa] = znaXNum / znaDen; + vSP[kYa] = znaYNum / znaDen; + vSP[kXc] = zncXNum / zncDen; + vSP[kYc] = zncYNum / zncDen; + + // Do corrections + if (cApplyRecentCorr) { + applyCorrection(loadShiftCorr, vCollParam, vSP); + } + + // Fill X and Y histograms for corrections after each iteration + fillCorrHist(vCollParam, vSP); + return true; + } + + using BCsRun3 = soa::Join; + using CollisionsRun3 = soa::Join; + using Tracks = soa::Join; + + void process(CollisionsRun3::iterator const& collision, BCsRun3 const& /* bcs*/, aod::Zdcs const&, Tracks const& tracks) + { + // Analyze collison and get SP vector + std::array vSP = {0., 0., 0., 0.}; + if (!analyzeCollision(collision, vSP)) { + lRunNum = cRunNum; + return; + } + + // Evaluate spectator plane angle and [X,Y] correlations + float psiA = std::atan2(vSP[kYa], vSP[kXa]); + float psiC = std::atan2(vSP[kYc], vSP[kXc]); + histos.fill(HIST("Checks/hPsiSPA"), cent, psiA); + histos.fill(HIST("Checks/hPsiSPC"), cent, psiC); + histos.fill(HIST("Checks/hCosPsiSPAC"), cent, std::cos(psiA - psiC)); + histos.fill(HIST("Checks/hSinPsiSPAC"), cent, std::sin(psiA - psiC)); + histos.fill(HIST("Checks/hXaXc"), cent, (vSP[kXa] * vSP[kXc])); + histos.fill(HIST("Checks/hYaYc"), cent, (vSP[kYa] * vSP[kYc])); + histos.fill(HIST("Checks/hXaYc"), cent, (vSP[kXa] * vSP[kYc])); + histos.fill(HIST("Checks/hYaXc"), cent, (vSP[kYa] * vSP[kXc])); + + // Directed flow + float qac = (vSP[kXa] * vSP[kXc]) + (vSP[kYa] * vSP[kYc]); + histos.fill(HIST("DF/hQaQc"), cent, qac); + + // Loop over tracks + float ux = 0., uy = 0., v1a = 0., v1c = 0.; + for (auto const& track : tracks) { + // Select track + if (!selectTrack(track)) { + continue; + } + + // Fill track QA + fillTrackHist(track); + + // Get directed flow + ux = std::cos(track.phi()); + uy = std::sin(track.phi()); + v1a = ux * vSP[kXa] + uy * vSP[kYa]; + v1c = ux * vSP[kXc] + uy * vSP[kYc]; + + // Charged particle directed flow + histos.fill(HIST("DF/hAQu"), cent, track.eta(), v1a); + histos.fill(HIST("DF/hCQu"), cent, track.eta(), v1c); + if (track.sign() > 0) { + histos.fill(HIST("DF/hAQuPos"), cent, track.eta(), v1a); + histos.fill(HIST("DF/hCQuPos"), cent, track.eta(), v1c); + } else { + histos.fill(HIST("DF/hAQuNeg"), cent, track.eta(), v1a); + histos.fill(HIST("DF/hCQuNeg"), cent, track.eta(), v1c); + } + + // Identified directed flow + if (identifyTrack(track)) { + getIdHadronFlow(cent, track, v1a, v1c); + } else if (identifyTrack(track)) { + getIdHadronFlow(cent, track, v1a, v1c); + } else if (identifyTrack(track)) { + getIdHadronFlow(cent, track, v1a, v1c); + } + } + + // Get resonance flow + getResoFlow(tracks, vSP); + + // Update runnumber + lRunNum = cRunNum; + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowGfwEse.cxx b/PWGCF/Flow/Tasks/flowGfwEse.cxx new file mode 100644 index 00000000000..633fb6ff332 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowGfwEse.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. + +/// \file flowGfwEse.cxx +/// \brief Dedicated GFW task to analyse angular correlations using ESE primarily in light ions +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch, Joachim C. K. B. Hansen, Lund University, joachim.hansen@cern.ch + +#include "FlowContainer.h" +#include "FlowPtContainer.h" +#include "GFW.h" +#include "GFWConfig.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.h" +#include "GFWWeightsList.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EseTable.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +namespace o2::analysis::gfwflowese +{ +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 = 40; +float vtxZlow = -10.0, vtxZup = 10.0; +int phibins = 72; +float philow = 0.0; +float phiup = o2::constants::math::TwoPI; +int nchbins = 300; +float nchlow = 0; +float nchup = 3000; +std::vector centbinning(90); +int nBootstrap = 10; +GFWRegions regions; +GFWCorrConfigs configs; +std::vector multGlobalCorrCutPars; +std::vector multPVCorrCutPars; +std::vector multGlobalPVCorrCutPars; +std::vector multGlobalV0ACutPars; +std::vector multGlobalT0ACutPars; +std::vector firstRunsOfFill; +} // namespace o2::analysis::gfwflowese + +struct FlowGfwEse { + + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgMpar, int, 4, "Highest order of pt-pt correlations") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FV0A, 4:NTPV, 5:NGlobals, 6:MFT") + 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(cfgFillFlowRunByRun, bool, false, "Fill flow profile run-by-run (only for v22)") + O2_DEFINE_CONFIGURABLE(cfgTimeDependent, bool, false, "Fill output as function of time (for contamination studies)") + O2_DEFINE_CONFIGURABLE(cfgFirstRunsOfFill, std::vector, {}, "First runs of a fill for time dependent analysis") + 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(cfgUseCentralMoments, bool, true, "Use central moments 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(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); + O2_DEFINE_CONFIGURABLE(cfgDCAxy, std::string, "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"); + O2_DEFINE_CONFIGURABLE(cfgDCAz, float, 2, "Cut on DCA in the longitudinal direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgNTPCCls, float, 50, "Cut on number of TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgNTPCXrows, float, 70, "Cut on number of TPC crossed rows"); + O2_DEFINE_CONFIGURABLE(cfgMinNITSCls, float, 5, "Cut on minimum number of ITS clusters found"); + O2_DEFINE_CONFIGURABLE(cfgChi2PrITSCls, float, 36, "Cut on chi^2 per ITS clusters found"); + O2_DEFINE_CONFIGURABLE(cfgChi2PrTPCCls, float, 2.5, "Cut on chi^2 per 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(cfgEtaPtPt, float, 0.4, "eta cut for pt-pt correlations"); + O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10, "vertex cut (cm)"); + O2_DEFINE_CONFIGURABLE(cfgOccupancySelection, int, 2000, "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(cfgFixedMultMin, int, 1, "Minimum for fixed nch range"); + O2_DEFINE_CONFIGURABLE(cfgFixedMultMax, int, 3000, "Maximum for fixed nch range"); + O2_DEFINE_CONFIGURABLE(cfgUseMultiplicityFlowWeights, bool, true, "Enable or disable the use of multiplicity-based event weighting"); + O2_DEFINE_CONFIGURABLE(cfgConsistentEventFlag, int, 0, "Flag to select consistent events - 0: off, 1: v2{2} gap calculable, 2: v2{4} full calculable, 4: v2{4} gap calculable, 8: v2{4} 3sub calculable"); + O2_DEFINE_CONFIGURABLE(cfgUseDensityDependentCorrection, bool, false, "Use density dependent efficiency correction based on Run 2 measurements"); + 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"}; + Configurable> cfgMultGlobalCutPars{"cfgMultGlobalCutPars", std::vector{2272.16, -76.6932, 1.01204, -0.00631545, 1.59868e-05, 136.336, -4.97006, 0.121199, -0.0015921, 7.66197e-06}, "Global vs FT0C multiplicity cut parameter values"}; + Configurable> cfgMultPVCutPars{"cfgMultPVCutPars", std::vector{3074.43, -106.192, 1.46176, -0.00968364, 2.61923e-05, 182.128, -7.43492, 0.193901, -0.00256715, 1.22594e-05}, "PV vs FT0C multiplicity cut parameter values"}; + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", std::vector{-0.223013, 0.715849, 0.664242, 0.0829653, -0.000503733, 1.21185e-06}, "Global vs PV multiplicity cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultCorrHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCorrLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCorrCutFunction, std::string, "[0] + [1]*x + 3*([2] + [3]*x + [4]*x*x + [5]*x*x*x)", "Functional for global vs pv multiplicity correlation cut"); + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgMultGlobalASideCorrCutFunction, std::string, "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + [10]*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", "Functional for global vs V0A multiplicity low correlation cut"); + Configurable> cfgMultGlobalV0ACutPars{"cfgMultGlobalV0ACutPars", std::vector{567.785, 172.715, 0.77888, -0.00693466, 1.40564e-05, 679.853, 66.8068, -0.444332, 0.00115002, -4.92064e-07}, "Global vs FV0A multiplicity cut parameter values"}; + Configurable> cfgMultGlobalT0ACutPars{"cfgMultGlobalT0ACutPars", std::vector{241.618, 61.8402, 0.348049, -0.00306078, 6.20357e-06, 315.235, 29.1491, -0.188639, 0.00044528, -9.08912e-08}, "Global vs FT0A multiplicity cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgGlobalV0ALowSigma, float, -3, "Number of sigma deviations below expected value in global vs V0A correlation"); + O2_DEFINE_CONFIGURABLE(cfgGlobalV0AHighSigma, float, 4, "Number of sigma deviations above expected value in global vs V0A correlation"); + O2_DEFINE_CONFIGURABLE(cfgGlobalT0ALowSigma, float, -3., "Number of sigma deviations below expected value in global vs T0A correlation"); + O2_DEFINE_CONFIGURABLE(cfgGlobalT0AHighSigma, float, 4, "Number of sigma deviations above expected value in global vs T0A correlation"); + } cfgGlobalAsideCorrCuts; + 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, 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}}, "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"}; + Configurable cfgCorrConfig{"cfgCorrConfig", {{"refP {2} refN {-2}", "refP {3} refN {-3}", "refP {4} refN {-4}", "refFull {2 -2}", "refFull {2 2 -2 -2}"}, {"ChGap22", "ChGap32", "ChGap42", "ChFull22", "ChFull24"}, {1, 0, 0, 0, 0}, {15, 1, 1, 0, 0}}, "Configurations for each correlation to calculate"}; + // Configurable cfgESEbinning{"cfgESEbinning", 100, "Number of ESE bins"}; + + // Connect to ccdb + Service ccdb; + + struct Config { + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance; + bool correctionsLoaded = false; + } cfg; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + OutputObj fFCpt{FlowPtContainer("FlowPtContainer")}; + OutputObj fFCgen{FlowContainer("FlowContainer_gen")}; + OutputObj fFCptgen{FlowPtContainer("FlowPtContainer_gen")}; + HistogramRegistry registry{"registry"}; + + // QA outputs + std::map>> th1sList; + std::map>> tpfsList; + std::map>> th3sList; + enum OutputTH1Names { + hPhi = 0, + hEta, + hVtxZ, + hMult, + hCent, + hEventSel, + kCount_TH1Names + }; + enum OutputTProfileNames { + pfCorr22 = 0, + kCount_TProfileNames + }; + // NUA outputs + enum OutputTH3Names { + hNUAref = 0, + kCount_TH3Names + }; + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + kCentNTPV, + kCentNGlobal, + kCentMFT + }; + enum EventSelFlags { + kFilteredEvent = 1, + kSel8, + kOccupancy, + kTVXTRD, + kNoSamebunchPU, + kZVtxFT0PV, + kNoCollTRStd, + kVtxITSTPC, + kGoodITSLayers, + kMultCuts, + kTrackCent + }; + + // Define global variables + // Generic Framework + GFW* fGFW = new GFW(); + std::vector corrconfigs; + + TRandom3* fRndm = new TRandom3(0); + TAxis* fSecondAxis; + int lastRun = -1; + std::vector::iterator firstRunOfCurrentFill; + std::vector runNumbers; + + // Density dependent eff correction + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + struct DensityCorr { + double psi2Est; + double psi3Est; + double psi4Est; + double v2; + double v3; + double v4; + int density; + DensityCorr() : psi2Est(0.), psi3Est(0.), psi4Est(0.), v2(0.), v3(0.), v4(0.), density(0) {} + }; + + O2_DEFINE_CONFIGURABLE(cfgAnalysisType, bool, true, "true for ese, false for mean-pT"); + const std::string shapesel = cfgAnalysisType ? "ese" : "mpt"; + static constexpr int EseBins = 100; + + // region indices for consistency flag + int posRegionIndex = -1; + int negRegionIndex = -1; + int fullRegionIndex = -1; + int midRegionIndex = -1; + + // Event selection cuts - Alex + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultPVGlobalCutHigh = nullptr; + TF1* fMultGlobalV0ACutLow = nullptr; + TF1* fMultGlobalV0ACutHigh = nullptr; + TF1* fMultGlobalT0ACutLow = nullptr; + TF1* fMultGlobalT0ACutHigh = nullptr; + + TF1* fPtDepDCAxy = nullptr; + + o2::framework::expressions::Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; + o2::framework::expressions::Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == static_cast(true))) && (aod::track::itsChi2NCl < cfgChi2PrITSCls) && (aod::track::tpcChi2NCl < cfgChi2PrTPCCls) && nabs(aod::track::dcaZ) < cfgDCAz; + + Preslice perCollision = aod::track::collisionId; + o2::framework::expressions::Filter mcCollFilter = nabs(aod::mccollision::posZ) < cfgVtxZ; + o2::framework::expressions::Filter mcParticlesFilter = (aod::mcparticle::eta > o2::analysis::gfwflowese::etalow && aod::mcparticle::eta < o2::analysis::gfwflowese::etaup && aod::mcparticle::pt > o2::analysis::gfwflowese::ptlow && aod::mcparticle::pt < o2::analysis::gfwflowese::ptup); + + using GFWTracks = soa::Filtered>; + + void init(InitContext const&) + { + LOGF(info, "FlowGfwEse::init()"); + o2::analysis::gfwflowese::regions.SetNames(cfgRegions->GetNames()); + o2::analysis::gfwflowese::regions.SetEtaMin(cfgRegions->GetEtaMin()); + o2::analysis::gfwflowese::regions.SetEtaMax(cfgRegions->GetEtaMax()); + o2::analysis::gfwflowese::regions.SetpTDifs(cfgRegions->GetpTDifs()); + o2::analysis::gfwflowese::regions.SetBitmasks(cfgRegions->GetBitmasks()); + o2::analysis::gfwflowese::configs.SetCorrs(cfgCorrConfig->GetCorrs()); + o2::analysis::gfwflowese::configs.SetHeads(cfgCorrConfig->GetHeads()); + o2::analysis::gfwflowese::configs.SetpTDifs(cfgCorrConfig->GetpTDifs()); + o2::analysis::gfwflowese::configs.SetpTCorrMasks(cfgCorrConfig->GetpTCorrMasks()); + o2::analysis::gfwflowese::regions.Print(); + o2::analysis::gfwflowese::configs.Print(); + o2::analysis::gfwflowese::ptbinning = cfgGFWBinning->GetPtBinning(); + o2::analysis::gfwflowese::ptpoilow = cfgGFWBinning->GetPtPOImin(); + o2::analysis::gfwflowese::ptpoiup = cfgGFWBinning->GetPtPOImax(); + o2::analysis::gfwflowese::ptreflow = cfgGFWBinning->GetPtRefMin(); + o2::analysis::gfwflowese::ptrefup = cfgGFWBinning->GetPtRefMax(); + o2::analysis::gfwflowese::ptlow = cfgPtmin; + o2::analysis::gfwflowese::ptup = cfgPtmax; + o2::analysis::gfwflowese::etabins = cfgGFWBinning->GetEtaBins(); + o2::analysis::gfwflowese::vtxZbins = cfgGFWBinning->GetVtxZbins(); + o2::analysis::gfwflowese::phibins = cfgGFWBinning->GetPhiBins(); + o2::analysis::gfwflowese::philow = 0.0f; + o2::analysis::gfwflowese::phiup = o2::constants::math::TwoPI; + o2::analysis::gfwflowese::nchbins = cfgGFWBinning->GetNchBins(); + o2::analysis::gfwflowese::nchlow = cfgGFWBinning->GetNchMin(); + o2::analysis::gfwflowese::nchup = cfgGFWBinning->GetNchMax(); + o2::analysis::gfwflowese::centbinning = cfgGFWBinning->GetCentBinning(); + cfgGFWBinning->Print(); + o2::analysis::gfwflowese::multGlobalCorrCutPars = cfgMultGlobalCutPars; + o2::analysis::gfwflowese::multPVCorrCutPars = cfgMultPVCutPars; + o2::analysis::gfwflowese::multGlobalPVCorrCutPars = cfgMultGlobalPVCutPars; + o2::analysis::gfwflowese::multGlobalV0ACutPars = cfgGlobalAsideCorrCuts.cfgMultGlobalV0ACutPars; + o2::analysis::gfwflowese::multGlobalT0ACutPars = cfgGlobalAsideCorrCuts.cfgMultGlobalT0ACutPars; + o2::analysis::gfwflowese::firstRunsOfFill = cfgFirstRunsOfFill; + if (cfgTimeDependent && !std::is_sorted(o2::analysis::gfwflowese::firstRunsOfFill.begin(), o2::analysis::gfwflowese::firstRunsOfFill.end())) { + std::sort(o2::analysis::gfwflowese::firstRunsOfFill.begin(), o2::analysis::gfwflowese::firstRunsOfFill.end()); + } + firstRunOfCurrentFill = o2::analysis::gfwflowese::firstRunsOfFill.begin(); + + AxisSpec phiAxis = {o2::analysis::gfwflowese::phibins, o2::analysis::gfwflowese::philow, o2::analysis::gfwflowese::phiup, "#phi"}; + AxisSpec etaAxis = {o2::analysis::gfwflowese::etabins, -cfgEta, cfgEta, "#eta"}; + AxisSpec vtxAxis = {o2::analysis::gfwflowese::vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; + AxisSpec ptAxis = {o2::analysis::gfwflowese::ptbinning, "#it{p}_{T} GeV/#it{c}"}; + std::string sCentralityEstimator; + std::map centEstimatorMap = { + {kCentFT0C, "FT0C"}, + {kCentFT0CVariant1, "FT0C variant 1"}, + {kCentFT0M, "FT0M"}, + {kCentFV0A, "FV0A"}, + {kCentNTPV, "NTPV"}, + {kCentNGlobal, "NGlobals"}, + {kCentMFT, "MFT"}}; + + sCentralityEstimator = centEstimatorMap.at(cfgCentEstimator); + sCentralityEstimator += " centrality (%)"; + AxisSpec centAxis = {o2::analysis::gfwflowese::centbinning, sCentralityEstimator.c_str()}; + std::vector nchbinning; + int nchskip = (o2::analysis::gfwflowese::nchup - o2::analysis::gfwflowese::nchlow) / o2::analysis::gfwflowese::nchbins; + for (int i = 0; i <= o2::analysis::gfwflowese::nchbins; ++i) { + nchbinning.push_back(nchskip * i + o2::analysis::gfwflowese::nchlow + 0.5); + } + AxisSpec nchAxis = {nchbinning, "N_{ch}"}; + std::vector bbinning(201); + std::generate(bbinning.begin(), bbinning.end(), [n = -0.1, step = 0.1]() mutable { + n += step; + return n; + }); + AxisSpec bAxis = {bbinning, "#it{b}"}; + AxisSpec t0cAxis = {1000, 0, 10000, "N_{ch} (T0C)"}; + AxisSpec t0aAxis = {300, 0, 30000, "N_{ch} (T0A)"}; + AxisSpec v0aAxis = {800, 0, 80000, "N_{ch} (V0A)"}; + AxisSpec multpvAxis = {600, 0, 600, "N_{ch} (PV)"}; + AxisSpec dcaZAXis = {200, -2, 2, "DCA_{z} (cm)"}; + AxisSpec dcaXYAXis = {200, -0.5, 0.5, "DCA_{xy} (cm)"}; + std::vector timebinning(289); + std::generate(timebinning.begin(), timebinning.end(), [n = -24 / 288., step = 24 / 288.]() mutable { + n += step; + return n; + }); + AxisSpec timeAxis = {timebinning, "time (hrs)"}; + + AxisSpec multAxis = (cfgTimeDependent) ? timeAxis : (cfgUseNch) ? nchAxis + : centAxis; + + 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 = o2::analysis::gfwflowese::ptbinning.size() - 1; + fSecondAxis = (cfgTimeDependent) ? new TAxis(timeAxis.binEdges.size() - 1, &(timeAxis.binEdges[0])) : new TAxis(ptbins, &o2::analysis::gfwflowese::ptbinning[0]); + + if (doprocessMptq2) { + registry.add("mptcorr/eventcounter", "", HistType::kTH1F, {{3, 0, 3}}); + registry.add("mptcorr/h3_cent_q2_meanptperc", ";Centrality;#it{q}_{2};mean-#it{p}_{T}", HistType::kTH3D, {{100, 0, 100}, {100, 0, 100}, {100, 0, 100}}); + registry.add("mptcorr/h3_cent_q2_mptvalue", ";Centrality;#it{q}_{2};mean-#it{p}_{T}", HistType::kTH3D, {{100, 0, 100}, {100, 0, 100}, {200, -1, 1}}); + } + + if (doprocessData) { + 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.add("trackQA/before/nch_pt", "#it{p}_{T} vs multiplicity; N_{ch}; #it{p}_{T}", {HistType::kTH2D, {nchAxis, ptAxis}}); + registry.add("trackQA/before/chi2prTPCcls", "#chi^{2}/cluster for the TPC track segment; #chi^{2}/TPC cluster", {HistType::kTH1D, {{100, 0., 5.}}}); + registry.add("trackQA/before/chi2prITScls", "#chi^{2}/cluster for the ITS track; #chi^{2}/ITS cluster", {HistType::kTH1D, {{100, 0., 50.}}}); + registry.add("trackQA/before/nTPCClusters", "Number of found TPC clusters; TPC N_{cls}; Counts", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("trackQA/before/nITSClusters", "Number of found ITS clusters; ITS N_{cls}; Counts", {HistType::kTH1D, {{100, 0, 20}}}); + registry.add("trackQA/before/nTPCCrossedRows", "Number of crossed TPC Rows; TPC X-rows; Counts", {HistType::kTH1D, {{100, 40, 180}}}); + + registry.addClone("trackQA/before/", "trackQA/after/"); + registry.add("trackQA/after/pt_ref", "", {HistType::kTH1D, {{100, o2::analysis::gfwflowese::ptreflow, o2::analysis::gfwflowese::ptrefup}}}); + registry.add("trackQA/after/pt_poi", "", {HistType::kTH1D, {{100, o2::analysis::gfwflowese::ptpoilow, o2::analysis::gfwflowese::ptpoiup}}}); + + registry.add("eventQA/before/multiplicity", "", {HistType::kTH1D, {nchAxis}}); + if (cfgTimeDependent) { + registry.add("eventQA/before/multiplicity_time", "Multiplicity vs time; time (hrs); N_{ch}", {HistType::kTH2D, {timeAxis, nchAxis}}); + registry.add("eventQA/before/multT0C_time", "T0C Multiplicity vs time; time (hrs); N_{ch} (T0C)", {HistType::kTH2D, {timeAxis, t0cAxis}}); + registry.add("eventQA/before/multT0A_time", "T0A Multiplicity vs time; time (hrs); N_{ch} (T0A)", {HistType::kTH2D, {timeAxis, t0aAxis}}); + registry.add("eventQA/before/multV0A_time", "V0A Multiplicity vs time; time (hrs); N_{ch} (V0A)", {HistType::kTH2D, {timeAxis, v0aAxis}}); + registry.add("eventQA/before/multPV_time", "PV Multiplicity vs time; time (hrs); N_{ch} (PV)", {HistType::kTH2D, {timeAxis, 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, {v0aAxis, nchAxis}}); + registry.add("eventQA/before/multV0A_multT0A", "", {HistType::kTH2D, {t0aAxis, v0aAxis}}); + + if (doprocessData) { + registry.add("eventQA/before/centrality", "", {HistType::kTH1D, {centAxis}}); + registry.add("eventQA/before/globalTracks_centT0C", "", {HistType::kTH2D, {centAxis, nchAxis}}); + registry.add("eventQA/before/PVTracks_centT0C", "", {HistType::kTH2D, {centAxis, multpvAxis}}); + registry.add("eventQA/before/multT0C_centT0C", "", {HistType::kTH2D, {centAxis, t0cAxis}}); + + registry.add("eventQA/before/centT0M_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + registry.add("eventQA/before/centV0A_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + registry.add("eventQA/before/centGlobal_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + registry.add("eventQA/before/centNTPV_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + registry.add("eventQA/before/centMFT_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + } + + registry.addClone("eventQA/before/", "eventQA/after/"); + registry.add("eventQA/eventSel", "Number of Events;; Counts", {HistType::kTH1D, {{11, 0.5, 11.5}}}); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kFilteredEvent, "Filtered event"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kSel8, "sel8"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kOccupancy, "occupancy"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kTVXTRD, "kTVXinTRD"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kNoSamebunchPU, "kNoSameBunchPileup"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kZVtxFT0PV, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kNoCollTRStd, "kNoCollInTimeRangeStandard"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kVtxITSTPC, "kIsVertexITSTPC"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kGoodITSLayers, "kIsGoodITSLayersAll"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kMultCuts, "after Mult cuts"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kTrackCent, "has track + within cent"); + if (!cfgRunByRun && cfgFillWeights) { + registry.add("phi_eta_vtxz_ref", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + } + } + + if (o2::analysis::gfwflowese::regions.GetSize() < 0) + LOGF(error, "Configuration contains vectors of different size - check the GFWRegions configurable"); + for (auto i(0); i < o2::analysis::gfwflowese::regions.GetSize(); ++i) { + fGFW->AddRegion(o2::analysis::gfwflowese::regions.GetNames()[i], o2::analysis::gfwflowese::regions.GetEtaMin()[i], o2::analysis::gfwflowese::regions.GetEtaMax()[i], (o2::analysis::gfwflowese::regions.GetpTDifs()[i]) ? ptbins + 1 : 1, o2::analysis::gfwflowese::regions.GetBitmasks()[i]); + } + for (auto i = 0; i < o2::analysis::gfwflowese::configs.GetSize(); ++i) { + corrconfigs.push_back(fGFW->GetCorrelatorConfig(o2::analysis::gfwflowese::configs.GetCorrs()[i], o2::analysis::gfwflowese::configs.GetHeads()[i], o2::analysis::gfwflowese::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); + if (doprocessData) { + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fSecondAxis); + fFC->Initialize(oba, multAxis, cfgNbootstrap); + } + delete oba; + fFCpt->setUseCentralMoments(cfgUseCentralMoments); + fFCpt->setUseGapMethod(true); + fFCpt->initialise(multAxis, cfgMpar, o2::analysis::gfwflowese::configs, cfgNbootstrap); + fFCptgen->setUseCentralMoments(cfgUseCentralMoments); + fFCptgen->setUseGapMethod(true); + fFCptgen->initialise(multAxis, cfgMpar, o2::analysis::gfwflowese::configs, cfgNbootstrap); + + fPtDepDCAxy = new TF1("ptDepDCAxy", Form("[0]*%s", cfgDCAxy->c_str()), 0.001, 100); + fPtDepDCAxy->SetParameter(0, cfgDCAxyNSigma); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", cfgDCAxy->c_str())); + if (cfgUseAdditionalEventCut) { + fMultPVCutLow = new TF1("fMultPVCutLow", cfgMultCorrLowCutFunction->c_str(), 0, 100); + fMultPVCutLow->SetParameters(&(o2::analysis::gfwflowese::multPVCorrCutPars[0])); + fMultPVCutHigh = new TF1("fMultPVCutHigh", cfgMultCorrHighCutFunction->c_str(), 0, 100); + fMultPVCutHigh->SetParameters(&(o2::analysis::gfwflowese::multPVCorrCutPars[0])); + fMultCutLow = new TF1("fMultCutLow", cfgMultCorrLowCutFunction->c_str(), 0, 100); + fMultCutLow->SetParameters(&(o2::analysis::gfwflowese::multGlobalCorrCutPars[0])); + fMultCutHigh = new TF1("fMultCutHigh", cfgMultCorrHighCutFunction->c_str(), 0, 100); + fMultCutHigh->SetParameters(&(o2::analysis::gfwflowese::multGlobalCorrCutPars[0])); + fMultPVGlobalCutHigh = new TF1("fMultPVGlobalCutHigh", cfgMultGlobalPVCorrCutFunction->c_str(), 0, nchbinning.back()); + fMultPVGlobalCutHigh->SetParameters(&(o2::analysis::gfwflowese::multGlobalPVCorrCutPars[0])); + + LOGF(info, "Global V0A function: %s in range 0-%g", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), v0aAxis.binEdges.back()); + fMultGlobalV0ACutLow = new TF1("fMultGlobalV0ACutLow", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), 0, v0aAxis.binEdges.back()); + for (std::size_t i = 0; i < o2::analysis::gfwflowese::multGlobalV0ACutPars.size(); ++i) + fMultGlobalV0ACutLow->SetParameter(i, o2::analysis::gfwflowese::multGlobalV0ACutPars[i]); + fMultGlobalV0ACutLow->SetParameter(o2::analysis::gfwflowese::multGlobalV0ACutPars.size(), cfgGlobalAsideCorrCuts.cfgGlobalV0ALowSigma); + for (int i = 0; i < fMultGlobalV0ACutLow->GetNpar(); ++i) + LOGF(info, "fMultGlobalV0ACutLow par %d = %g", i, fMultGlobalV0ACutLow->GetParameter(i)); + + fMultGlobalV0ACutHigh = new TF1("fMultGlobalV0ACutHigh", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), 0, v0aAxis.binEdges.back()); + for (std::size_t i = 0; i < o2::analysis::gfwflowese::multGlobalV0ACutPars.size(); ++i) + fMultGlobalV0ACutHigh->SetParameter(i, o2::analysis::gfwflowese::multGlobalV0ACutPars[i]); + fMultGlobalV0ACutHigh->SetParameter(o2::analysis::gfwflowese::multGlobalV0ACutPars.size(), cfgGlobalAsideCorrCuts.cfgGlobalV0AHighSigma); + for (int i = 0; i < fMultGlobalV0ACutHigh->GetNpar(); ++i) + LOGF(info, "fMultGlobalV0ACutHigh par %d = %g", i, fMultGlobalV0ACutHigh->GetParameter(i)); + + LOGF(info, "Global T0A function: %s", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str()); + fMultGlobalT0ACutLow = new TF1("fMultGlobalT0ACutLow", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), 0, t0aAxis.binEdges.back()); + for (std::size_t i = 0; i < o2::analysis::gfwflowese::multGlobalT0ACutPars.size(); ++i) + fMultGlobalT0ACutLow->SetParameter(i, o2::analysis::gfwflowese::multGlobalT0ACutPars[i]); + fMultGlobalT0ACutLow->SetParameter(o2::analysis::gfwflowese::multGlobalT0ACutPars.size(), cfgGlobalAsideCorrCuts.cfgGlobalT0ALowSigma); + for (int i = 0; i < fMultGlobalT0ACutLow->GetNpar(); ++i) + LOGF(info, "fMultGlobalT0ACutLow par %d = %g", i, fMultGlobalT0ACutLow->GetParameter(i)); + + fMultGlobalT0ACutHigh = new TF1("fMultGlobalT0ACutHigh", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), 0, t0aAxis.binEdges.back()); + for (std::size_t i = 0; i < o2::analysis::gfwflowese::multGlobalT0ACutPars.size(); ++i) + fMultGlobalT0ACutHigh->SetParameter(i, o2::analysis::gfwflowese::multGlobalT0ACutPars[i]); + fMultGlobalT0ACutHigh->SetParameter(o2::analysis::gfwflowese::multGlobalT0ACutPars.size(), cfgGlobalAsideCorrCuts.cfgGlobalT0AHighSigma); + for (int i = 0; i < fMultGlobalT0ACutHigh->GetNpar(); ++i) + LOGF(info, "fMultGlobalT0ACutHigh par %d = %g", i, fMultGlobalT0ACutHigh->GetParameter(i)); + } + if (cfgUseDensityDependentCorrection) { + 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); + } + if (cfgConsistentEventFlag) { + auto findRegionIndex = [&](const std::string& name) { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, name); + return (it != end) ? std::distance(begin, it) : -1; + }; + posRegionIndex = findRegionIndex("refP"); + negRegionIndex = findRegionIndex("refN"); + fullRegionIndex = findRegionIndex("refFull"); + midRegionIndex = findRegionIndex("refMid"); + } + } + + 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) { + for (int jese = 0; jese < EseBins; ++jese) { + if (it->pTDif) { + for (int i = 0; i < fSecondAxis->GetNbins(); ++i) { + std::string name = Form("%s_%d_%s_pt_%d", shapesel.c_str(), jese, it->Head.c_str(), i + 1); + std::string title = it->Head + std::string("_ptDiff"); + oba->Add(new TNamed(name.c_str(), title.c_str())); + } + } else { + std::string name = Form("%s_%d_%s", shapesel.c_str(), jese, it->Head.c_str()); + std::string title = it->Head + std::string("_ese"); + oba->Add(new TNamed(name.c_str(), title.c_str())); + } + } + } + } + + int getMagneticField(uint64_t timestamp) + { + 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(); + } + + void loadCorrections(aod::BCsWithTimestamps::iterator const& bc) + { + uint64_t timestamp = bc.timestamp(); + if (!cfgRunByRun && cfg.correctionsLoaded) + return; + if (!cfgAcceptance.value.empty()) { + std::string runstr = (cfgRunByRun) ? "RunByRun/" : ""; + cfg.mAcceptance = ccdb->getForTimeStamp(cfgAcceptance.value + runstr, timestamp); + } + if (!cfgEfficiency.value.empty()) { + cfg.mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (cfg.mEfficiency == nullptr) { + 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; + } + + template + double getAcceptance(TTrack track, const double& vtxz) + { + double wacc = 1; + if (cfg.mAcceptance) + wacc = cfg.mAcceptance->getNUA(track.phi(), track.eta(), vtxz); + return wacc; + } + + template + double getEfficiency(TTrack track) + { + double eff = 1.; + if (cfg.mEfficiency) + eff = cfg.mEfficiency->GetBinContent(cfg.mEfficiency->FindBin(track.pt())); + if (eff == 0) + return -1.; + else + return 1. / eff; + } + + template + bool eventSelected(TCollision collision, const int& multTrk, const float& centrality, const int& run) + { + if (cfgTVXinTRD) { + if (collision.alias_bit(kTVXinTRD)) { + // TRD triggered + // "CMTVX-B-NOPF-TRD,minbias_TVX" + return 0; + } + registry.fill(HIST("eventQA/eventSel"), kTVXTRD); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kTVXTRD); + } + 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"), kNoSamebunchPU); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kNoSamebunchPU); + } + 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"), kZVtxFT0PV); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kZVtxFT0PV); + } + 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"), kNoCollTRStd); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kNoCollTRStd); + } + + 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"), kVtxITSTPC); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kVtxITSTPC); + } + + if (cfgIsGoodITSLayersAll) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return 0; + } + registry.fill(HIST("eventQA/eventSel"), kGoodITSLayers); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kGoodITSLayers); + } + + float vtxz = -999; + if (collision.numContrib() > 1) { + vtxz = collision.posZ(); + float zRes = std::sqrt(collision.covZZ()); + float minZRes = 0.25; + int minNContrib = 20; + if (zRes > minZRes && collision.numContrib() < minNContrib) + vtxz = -999; + } + auto multNTracksPV = collision.multNTracksPV(); + + if (vtxz > o2::analysis::gfwflowese::vtxZup || vtxz < o2::analysis::gfwflowese::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; + if (multTrk > fMultPVGlobalCutHigh->Eval(collision.multNTracksPV())) + return 0; + + if (!(cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->empty()) && static_cast(collision.multFV0A()) < fMultGlobalV0ACutLow->Eval(multTrk)) + return 0; + if (!(cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->empty()) && static_cast(collision.multFV0A()) > fMultGlobalV0ACutHigh->Eval(multTrk)) + return 0; + if (!(cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->empty()) && static_cast(collision.multFT0A()) < fMultGlobalT0ACutLow->Eval(multTrk)) + return 0; + if (!(cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->empty()) && static_cast(collision.multFT0A()) > fMultGlobalT0ACutHigh->Eval(multTrk)) + return 0; + registry.fill(HIST("eventQA/eventSel"), kMultCuts); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kMultCuts); + } + return 1; + } + + template + bool trackSelected(TTrack track) + { + if (cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > fPtDepDCAxy->Eval(track.pt()))) + return false; + return ((track.tpcNClsCrossedRows() >= cfgNTPCXrows) && (track.tpcNClsFound() >= cfgNTPCCls) && (track.itsNCls() >= cfgMinNITSCls)); + } + + enum DataType { + kReco, + kGen + }; + + template + void fillWeights(const TTrack track, const double vtxz, const int& run) + { + 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; + } + + void createRunByRunHistograms(const int& run) + { + AxisSpec phiAxis = {o2::analysis::gfwflowese::phibins, o2::analysis::gfwflowese::philow, o2::analysis::gfwflowese::phiup, "#phi"}; + AxisSpec etaAxis = {o2::analysis::gfwflowese::etabins, -cfgEta, cfgEta, "#eta"}; + AxisSpec vtxAxis = {o2::analysis::gfwflowese::vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; + AxisSpec nchAxis = {o2::analysis::gfwflowese::nchbins, o2::analysis::gfwflowese::nchlow, o2::analysis::gfwflowese::nchup, "N_{ch}"}; + AxisSpec centAxis = {o2::analysis::gfwflowese::centbinning, "Centrality (%)"}; + 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, {nchAxis}}); + histos[hCent] = registry.add(Form("%d/cent", run), "", {HistType::kTH1D, {centAxis}}); + if (cfgFillFlowRunByRun) { + std::vector> profiles(kCount_TProfileNames); + profiles[pfCorr22] = registry.add(Form("%d/corr22", run), "", {HistType::kTProfile, {(cfgUseNch) ? nchAxis : centAxis}}); + tpfsList.insert(std::make_pair(run, profiles)); + } + histos[hEventSel] = registry.add(Form("%d/eventSel", run), "Number of Events;; Counts", {HistType::kTH1D, {{11, 0.5, 11.5}}}); + histos[hEventSel]->GetXaxis()->SetBinLabel(kFilteredEvent, "Filtered event"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kSel8, "sel8"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kOccupancy, "occupancy"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kTVXTRD, "kTVXinTRD"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kNoSamebunchPU, "kNoSameBunchPileup"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kZVtxFT0PV, "kIsGoodZvtxFT0vsPV"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kNoCollTRStd, "kNoCollInTimeRangeStandard"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kVtxITSTPC, "kIsVertexITSTPC"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kGoodITSLayers, "kIsGoodITSLayersAll"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kMultCuts, "after Mult cuts"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kTrackCent, "has track + within cent"); + th1sList.insert(std::make_pair(run, histos)); + std::vector> histos3d(kCount_TH3Names); + 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, const int& run = 0, const float& fPerc = -1.0f) + { + (dt == kGen) ? fFCptgen->calculateCorrelations() : fFCpt->calculateCorrelations(); + (dt == kGen) ? fFCptgen->fillPtProfiles(centmult, rndm) : fFCpt->fillPtProfiles(centmult, rndm); + (dt == kGen) ? fFCptgen->fillCMProfiles(centmult, rndm) : fFCpt->fillCMProfiles(centmult, rndm); + int qPtmp = static_cast(fPerc); + for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { + 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 (std::abs(val) < 1) { + (dt == kGen) ? fFCgen->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm) : fFC->FillProfile(Form("%s_%i_%s", shapesel.c_str(), qPtmp, corrconfigs.at(l_ind).Head.c_str()), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm); + (dt == kGen) ? fFCptgen->fillVnPtProfiles(centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm, o2::analysis::gfwflowese::configs.GetpTCorrMasks()[l_ind]) : fFCpt->fillVnPtProfiles(centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm, o2::analysis::gfwflowese::configs.GetpTCorrMasks()[l_ind]); + if (cfgRunByRun && cfgFillFlowRunByRun && dt != kGen && l_ind == 0) { + tpfsList[run][pfCorr22]->Fill(centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0); + } + } + continue; + } + for (int i = 1; i <= fSecondAxis->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 (std::abs(val) < 1) + (dt == kGen) ? fFCgen->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm) : fFC->FillProfile(Form("%s_%i_%s_pt_%i", shapesel.c_str(), qPtmp, corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm); + // (dt == kGen) ? fFCgen->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm) : fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm); + } + } + return; + } + + struct XAxis { + float centrality; + int64_t multiplicity; + double time; + }; + + struct AcceptedTracks { + int nPos; + int nNeg; + int nFull; + int nMid; + }; + + template + void processCollision(TCollision collision, TTracks tracks, const XAxis& xaxis, const int& run) + { + if (tracks.size() < 1) + return; + if (dt != kGen && xaxis.centrality >= 0 && (xaxis.centrality < o2::analysis::gfwflowese::centbinning.front() || xaxis.centrality > o2::analysis::gfwflowese::centbinning.back())) + return; + if (xaxis.multiplicity < cfgFixedMultMin || xaxis.multiplicity > cfgFixedMultMax) + return; + if (dt != kGen) { + registry.fill(HIST("eventQA/eventSel"), kTrackCent); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kTrackCent); + } + if (xaxis.centrality >= 0) + registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); + registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); + float vtxz = collision.posZ(); + if (dt != kGen && cfgRunByRun) { + th1sList[run][hVtxZ]->Fill(vtxz); + th1sList[run][hMult]->Fill(xaxis.multiplicity); + th1sList[run][hCent]->Fill(xaxis.centrality); + } + fGFW->Clear(); + (dt == kGen) ? fFCptgen->clearVector() : fFCpt->clearVector(); + + float lRandom = fRndm->Rndm(); + + // be cautious, this only works for Pb-Pb + // esimate the Event plane and vn for this event + DensityCorr densitycorrections; + if (cfgUseDensityDependentCorrection) { + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + double v2 = 0, v3 = 0, v4 = 0; + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (const auto& track : tracks) { + bool withinPtRef = (o2::analysis::gfwflowese::ptreflow < track.pt()) && (track.pt() < o2::analysis::gfwflowese::ptrefup); // 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(xaxis.centrality); + v3 = funcV3->Eval(xaxis.centrality); + v4 = funcV4->Eval(xaxis.centrality); + densitycorrections.psi2Est = psi2Est; + densitycorrections.psi3Est = psi3Est; + densitycorrections.psi4Est = psi4Est; + densitycorrections.v2 = v2; + densitycorrections.v3 = v3; + densitycorrections.v4 = v4; + densitycorrections.density = tracks.size(); + } + AcceptedTracks acceptedTracks{0, 0, 0, 0}; + for (const auto& track : tracks) { + processTrack(track, vtxz, xaxis.multiplicity, run, densitycorrections, acceptedTracks); + if (cfgConsistentEventFlag & 1) + if (!acceptedTracks.nPos || !acceptedTracks.nNeg) + return; + if (cfgConsistentEventFlag & 2) + if (acceptedTracks.nFull < 4) // o2-linter: disable=magic-number (at least four tracks in full acceptance) + return; + if (cfgConsistentEventFlag & 4) + if (acceptedTracks.nPos < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in each subevent) + return; + if (cfgConsistentEventFlag & 8) + if (acceptedTracks.nPos < 2 || acceptedTracks.nMid < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in all three subevents) + return; + } + const auto fPerc = cfgAnalysisType ? collision.qPERCFT0C() : collision.fMEANPTSHAPE(); + if (!cfgFillWeights) + fillOutputContainers
((cfgTimeDependent) ? xaxis.time : (cfgUseNch) ? xaxis.multiplicity + : xaxis.centrality, + lRandom, run, fPerc[0]); + } + + bool isStable(int pdg) + { + if (std::abs(pdg) == PDG_t::kPiPlus) + return true; + if (std::abs(pdg) == PDG_t::kKPlus) + return true; + if (std::abs(pdg) == PDG_t::kProton) + return true; + if (std::abs(pdg) == PDG_t::kElectron) + return true; + if (std::abs(pdg) == PDG_t::kMuonMinus) + return true; + return false; + } + + template + void fillAcceptedTracks(TTrack track, AcceptedTracks& acceptedTracks) + { + if (posRegionIndex >= 0 && track.eta() > o2::analysis::gfwflowese::regions.GetEtaMin()[posRegionIndex] && track.eta() < o2::analysis::gfwflowese::regions.GetEtaMax()[posRegionIndex]) + ++acceptedTracks.nPos; + if (negRegionIndex >= 0 && track.eta() > o2::analysis::gfwflowese::regions.GetEtaMin()[negRegionIndex] && track.eta() < o2::analysis::gfwflowese::regions.GetEtaMax()[negRegionIndex]) + ++acceptedTracks.nNeg; + if (fullRegionIndex >= 0 && track.eta() > o2::analysis::gfwflowese::regions.GetEtaMin()[fullRegionIndex] && track.eta() < o2::analysis::gfwflowese::regions.GetEtaMax()[fullRegionIndex]) + ++acceptedTracks.nFull; + if (midRegionIndex >= 0 && track.eta() > o2::analysis::gfwflowese::regions.GetEtaMin()[midRegionIndex] && track.eta() < o2::analysis::gfwflowese::regions.GetEtaMax()[midRegionIndex]) + ++acceptedTracks.nMid; + } + + template + inline void processTrack(TTrack const& track, const float& vtxz, const int& multiplicity, const int& run, DensityCorr densitycorrections, AcceptedTracks& acceptedTracks) + { + if constexpr (framework::has_type_v) { + if (track.mcParticleId() < 0 || !(track.has_mcParticle())) + return; + + auto mcParticle = track.mcParticle(); + if (!mcParticle.isPhysicalPrimary()) + return; + if (!isStable(mcParticle.pdgCode())) + return; + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/before/nch_pt"), multiplicity, track.pt()); + } + if (!trackSelected(track)) + return; + + if (cfgFillWeights) { + fillWeights(track, vtxz, run); + } else { + fillPtSums(track); + fillGFW(track, vtxz, densitycorrections); + fillAcceptedTracks(track, acceptedTracks); + } + + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/after/nch_pt"), multiplicity, track.pt()); + if (cfgRunByRun) { + th1sList[run][hPhi]->Fill(track.phi()); + th1sList[run][hEta]->Fill(track.eta()); + } + } + + } else if constexpr (framework::has_type_v) { + if (!track.isPhysicalPrimary() || !isStable(track.pdgCode())) + return; + + fillPtSums(track); + fillGFW(track, vtxz, densitycorrections); + fillAcceptedTracks(track, acceptedTracks); + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("MCGen/trackQA/nch_pt"), multiplicity, track.pt()); + } + } else { + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/before/nch_pt"), multiplicity, track.pt()); + } + if (!trackSelected(track)) + return; + + if (cfgFillWeights) { + fillWeights(track, vtxz, run); + } else { + fillPtSums(track); + fillGFW(track, vtxz, densitycorrections); + fillAcceptedTracks(track, acceptedTracks); + } + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/after/nch_pt"), multiplicity, track.pt()); + if (cfgRunByRun) { + th1sList[run][hPhi]->Fill(track.phi()); + th1sList[run][hEta]->Fill(track.eta()); + th3sList[run][hNUAref]->Fill(track.phi(), track.eta(), vtxz, getAcceptance(track, vtxz)); + } + } + } + return; + } + + template + inline void fillGFW(TTrack track, const double& vtxz, DensityCorr densitycorrections) + { + bool withinPtRef = (track.pt() > o2::analysis::gfwflowese::ptreflow && track.pt() < o2::analysis::gfwflowese::ptrefup); + bool withinPtPOI = (track.pt() > o2::analysis::gfwflowese::ptpoilow && track.pt() < o2::analysis::gfwflowese::ptpoiup); + if (!withinPtPOI && !withinPtRef) + return; + double weff = (dt == kGen) ? 1. : getEfficiency(track); + if (weff < 0) + return; + if (cfgUseDensityDependentCorrection && withinPtRef && dt != kGen) { + double fphi = densitycorrections.v2 * std::cos(2 * (track.phi() - densitycorrections.psi2Est)) + densitycorrections.v3 * std::cos(3 * (track.phi() - densitycorrections.psi3Est)) + densitycorrections.v4 * std::cos(4 * (track.phi() - densitycorrections.psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(track.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + float wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * densitycorrections.density); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + } + } + } + double wacc = (dt == kGen) ? 1. : getAcceptance(track, vtxz); + if (withinPtRef) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 1); + if (withinPtPOI) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 2); + if (withinPtRef && withinPtPOI) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 4); + return; + } + + template + inline void fillPtSums(TTrack track) + { + double weff = (dt == kGen) ? 1. : getEfficiency(track); + if (weff < 0) + return; + if (std::abs(track.eta()) < cfgEtaPtPt && track.pt() > o2::analysis::gfwflowese::ptreflow && track.pt() < o2::analysis::gfwflowese::ptrefup) { + (dt == kGen) ? fFCptgen->fill(1., track.pt()) : fFCpt->fill(weff, track.pt()); + } + } + + template + inline void fillTrackQA(TTrack track, const float vtxz) + { + if constexpr (dt == kGen) { + registry.fill(HIST("MCGen/trackQA/phi_eta_vtxZ"), track.phi(), track.eta(), vtxz); + registry.fill(HIST("MCGen/trackQA/pt_ref"), track.pt()); + registry.fill(HIST("MCGen/trackQA/pt_poi"), track.pt()); + } else { + double wacc = getAcceptance(track, vtxz); + 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()); + + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("chi2prTPCcls"), track.tpcChi2NCl()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("chi2prITScls"), track.itsChi2NCl()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nTPCClusters"), track.tpcNClsFound()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nITSClusters"), track.itsNCls()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nTPCCrossedRows"), track.tpcNClsCrossedRows()); + + 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 + float getCentrality(TCollision collision) + { + switch (cfgCentEstimator) { + case kCentFT0C: + return collision.centFT0C(); + case kCentFT0CVariant1: + return collision.centFT0CVariant1(); + case kCentFT0M: + return collision.centFT0M(); + case kCentFV0A: + return collision.centFV0A(); + case kCentNTPV: + return collision.centNTPV(); + case kCentNGlobal: + return collision.centNGlobal(); + case kCentMFT: + return collision.centMFT(); + default: + return collision.centFT0C(); + } + } + + template + inline void fillEventQA(TCollision collision, XAxis xaxis) + { + if constexpr (framework::has_type_v) { + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_centT0C"), collision.centFT0C(), xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centT0M_centT0C"), collision.centFT0C(), collision.centFT0M()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centV0A_centT0C"), collision.centFT0C(), collision.centFV0A()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centGlobal_centT0C"), collision.centFT0C(), collision.centNGlobal()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centNTPV_centT0C"), collision.centFT0C(), collision.centNTPV()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centMFT_centT0C"), collision.centFT0C(), collision.centMFT()); + } + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_PVTracks"), collision.multNTracksPV(), xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_multT0A"), collision.multFT0A(), xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_multV0A"), collision.multFV0A(), xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + if (cfgTimeDependent) { + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multiplicity_time"), xaxis.time, xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multT0C_time"), xaxis.time, collision.multFT0C()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multT0A_time"), xaxis.time, collision.multFT0A()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multV0A_time"), xaxis.time, collision.multFV0A()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multPV_time"), xaxis.time, collision.multNTracksPV()); + } + return; + } + + double getTimeSinceStartOfFill(uint64_t timestamp, int firstRun) + { + auto runDuration = ccdb->getRunDuration(firstRun); + uint64_t tsSOF = runDuration.first; + uint64_t diff = timestamp - tsSOF; + return static_cast(diff) / 3600000.0; + } + + 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"), kFilteredEvent); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kFilteredEvent); + if (!collision.sel8()) + return; + registry.fill(HIST("eventQA/eventSel"), kSel8); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kSel8); + if (cfgDoOccupancySel) { + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy < 0 || occupancy > cfgOccupancySelection) + return; + } + const auto fPerc = cfgAnalysisType ? collision.qPERCFT0C() : collision.fMEANPTSHAPE(); + if (fPerc[0] < 0) + return; + registry.fill(HIST("eventQA/eventSel"), kOccupancy); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kOccupancy); + + const XAxis xaxis{getCentrality(collision), tracks.size(), (cfgTimeDependent) ? getTimeSinceStartOfFill(bc.timestamp(), *firstRunOfCurrentFill) : -1.0}; + if (cfgTimeDependent && run == *firstRunOfCurrentFill && firstRunOfCurrentFill != o2::analysis::gfwflowese::firstRunsOfFill.end() - 1) + ++firstRunOfCurrentFill; + + if (cfgFillQA) + fillEventQA(collision, xaxis); + registry.fill(HIST("eventQA/before/centrality"), xaxis.centrality); + registry.fill(HIST("eventQA/before/multiplicity"), xaxis.multiplicity); + if (cfgUseAdditionalEventCut && !eventSelected(collision, xaxis.multiplicity, xaxis.centrality, run)) + return; + if (cfgFillQA) + fillEventQA(collision, xaxis); + processCollision(collision, tracks, xaxis, run); + } + PROCESS_SWITCH(FlowGfwEse, processData, "Process analysis for non-derived data", true); + + // void processMptq2(soa::Filtered::iterator const& collision, aod::BCsWithTimestamps const&, GFWTracks const& tracks) + + void processMptq2(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const& /*, GFWTracks const& tracks*/) + { + float count{0.5}; + registry.fill(HIST("mptcorr/eventcounter"), count++); + const auto centr = collision.centFT0C(); + const auto qPerc = collision.qPERCFT0C(); + const auto mPt = collision.fMEANPTSHAPE(); + const auto mPtv = collision.fMEANPT(); + if (qPerc[0] < 0 || mPt[0] < 0) + return; + registry.fill(HIST("mptcorr/eventcounter"), count++); + registry.fill(HIST("mptcorr/h3_cent_q2_meanptperc"), centr, qPerc[0], mPt[0]); + registry.fill(HIST("mptcorr/h3_cent_q2_mptvalue"), centr, qPerc[0], mPtv[0]); + } + PROCESS_SWITCH(FlowGfwEse, processMptq2, "Process analysis for mpt-q2 correlation", false); +}; + +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..f9e0de18755 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowGfwOmegaXi.cxx @@ -0,0 +1,2054 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "GFW.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.h" + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/EventPlaneHelper.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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include "TList.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +namespace +{ +std::shared_ptr refc22[10]; +std::shared_ptr refc24[10]; +std::shared_ptr refc22Full[10]; +std::shared_ptr refc32[10]; +std::shared_ptr k0sc22[10]; +std::shared_ptr k0sc24[10]; +std::shared_ptr k0sc22Full[10]; +std::shared_ptr k0sc32[10]; +std::shared_ptr lambdac22[10]; +std::shared_ptr lambdac24[10]; +std::shared_ptr lambdac22Full[10]; +std::shared_ptr lambdac32[10]; +std::shared_ptr xic22[10]; +std::shared_ptr xic24[10]; +std::shared_ptr xic22Full[10]; +std::shared_ptr xic32[10]; +std::shared_ptr omegac22[10]; +std::shared_ptr omegac24[10]; +std::shared_ptr omegac22Full[10]; +std::shared_ptr omegac32[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(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + 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") + + struct : ConfigurableGroup { + std::string prefix = "v0BuilderOpts"; + // 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") + O2_DEFINE_CONFIGURABLE(cfgv0_compmassrejLambda, float, 0.01f, "competing mass rejection of lambda") + O2_DEFINE_CONFIGURABLE(cfgv0_compmassrejK0s, float, 0.005f, "competing mass rejection of K0s") + } v0BuilderOpts; + + struct : ConfigurableGroup { + std::string prefix = "cascBuilderOpts"; + // 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") + O2_DEFINE_CONFIGURABLE(cfgcasc_compmassrej, float, 0.008f, "competing mass rejection of cascades") + } cascBuilderOpts; + + struct : ConfigurableGroup { + std::string prefix = "trkQualityOpts"; + // track selections + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for 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(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtDauMin, float, 0.2f, "Minimal pT for daughter tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtDauMax, float, 10.0f, "Maximal pT for daughter tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtK0sMin, float, 0.2f, "Minimal pT for K0s") + O2_DEFINE_CONFIGURABLE(cfgCutPtK0sMax, float, 10.0f, "Maximal pT for K0s") + O2_DEFINE_CONFIGURABLE(cfgCutPtLambdaMin, float, 0.2f, "Minimal pT for Lambda") + O2_DEFINE_CONFIGURABLE(cfgCutPtLambdaMax, float, 10.0f, "Maximal pT for Lambda") + O2_DEFINE_CONFIGURABLE(cfgCutPtXiMin, float, 0.2f, "Minimal pT for Xi") + O2_DEFINE_CONFIGURABLE(cfgCutPtXiMax, float, 10.0f, "Maximal pT for Xi") + O2_DEFINE_CONFIGURABLE(cfgCutPtOmegaMin, float, 0.2f, "Minimal pT for Omega") + O2_DEFINE_CONFIGURABLE(cfgCutPtOmegaMax, float, 10.0f, "Maximal pT for Omega") + O2_DEFINE_CONFIGURABLE(cfgCutPtPIDDauMin, float, 0.15f, "Minimal pT for daughter PID") + O2_DEFINE_CONFIGURABLE(cfgCutPtPIDbachMin, float, 0.15f, "Minimal pT for daughter PID") + O2_DEFINE_CONFIGURABLE(cfgCutPtPIDdauLaPrMin, float, 0.15f, "Minimal pT for daughter PID") + O2_DEFINE_CONFIGURABLE(cfgCutPtPIDdauLaPiMin, float, 0.15f, "Minimal pT for daughter PID") + // track quality selections for daughter track + O2_DEFINE_CONFIGURABLE(cfgCheckITSNCls, bool, false, "check minimum number of ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCheckITSHits, bool, false, "check minimum number of ITS hits") + O2_DEFINE_CONFIGURABLE(cfgCheckITSChi2NDF, bool, false, "check ITS Chi2NDF") + O2_DEFINE_CONFIGURABLE(cfgCheckGlobalTrack, bool, false, "check global track") + } trkQualityOpts; + + struct : ConfigurableGroup { + std::string prefix = "evtSelOpts"; + O2_DEFINE_CONFIGURABLE(cfgDoTVXinTRD, bool, true, "check kTVXinTRD") + O2_DEFINE_CONFIGURABLE(cfgDoNoTimeFrameBorder, bool, true, "check kNoTimeFrameBorder") + O2_DEFINE_CONFIGURABLE(cfgDoNoITSROFrameBorder, bool, true, "check kNoITSROFrameBorder") + O2_DEFINE_CONFIGURABLE(cfgDoNoSameBunchPileup, bool, true, "check kNoITSROFrameBorder") + O2_DEFINE_CONFIGURABLE(cfgDoIsGoodZvtxFT0vsPV, bool, true, "check kIsGoodZvtxFT0vsPV") + O2_DEFINE_CONFIGURABLE(cfgDoNoCollInTimeRangeStandard, bool, true, "check kNoCollInTimeRangeStandard") + O2_DEFINE_CONFIGURABLE(cfgDoIsGoodITSLayersAll, bool, true, "check kIsGoodITSLayersAll") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 500, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgDoMultPVCut, bool, true, "do multNTracksPV vs cent cut") + O2_DEFINE_CONFIGURABLE(cfgMultPVCut, std::vector, (std::vector{3074.43, -106.192, 1.46176, -0.00968364, 2.61923e-05, 182.128, -7.43492, 0.193901, -0.00256715, 1.22594e-05}), "Used MultPVCut function parameter") + O2_DEFINE_CONFIGURABLE(cfgDoV0AT0Acut, bool, true, "do V0A-T0A cut") + O2_DEFINE_CONFIGURABLE(cfgCutminIR, float, -1, "cut min IR") + O2_DEFINE_CONFIGURABLE(cfgCutmaxIR, float, -1, "cut max IR") + } evtSeleOpts; + + O2_DEFINE_CONFIGURABLE(cfgCasc_rapidity, float, 0.5, "rapidity") + O2_DEFINE_CONFIGURABLE(cfgNSigmapid, std::vector, (std::vector{9, 9, 9, 3, 3, 3, 3, 3, 3}), "tpc, tof and its 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)") + O2_DEFINE_CONFIGURABLE(cfgRunNumbers, std::vector, (std::vector{544095, 544098, 544116, 544121, 544122, 544123, 544124}), "Preconfigured run numbers") + // switch + 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(cfgOutputV0, bool, true, "Fill and output V0s flow") + O2_DEFINE_CONFIGURABLE(cfgOutputCasc, bool, true, "Fill and output cascades flow") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgOutputrunbyrun, bool, false, "Fill and output NUA weights run by run") + O2_DEFINE_CONFIGURABLE(cfgOutputLocDenWeights, bool, false, "Fill and output local density weights") + O2_DEFINE_CONFIGURABLE(cfgOutputQA, bool, false, "do QA") + + 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 cfgaxisPtK0s{"cfgaxisPtK0s", {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 cfgaxisPtLambda{"cfgaxisPtLambda", {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) < trkQualityOpts.cfgCutEta.value) && (aod::track::pt > trkQualityOpts.cfgCutPtPOIMin.value) && (aod::track::pt < trkQualityOpts.cfgCutPtPOIMax.value) && ((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; + ctpRateFetcher rateFetcher; + 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; + std::vector cfgEfficiency; + std::vector cfgNSigma; + std::vector cfgMultPVCutPara; + std::vector cfgmassbins; + std::vector runNumbers; + std::map>> th1sList; + std::map>> th3sList; + enum OutputTH1Names { + // here are TProfiles for vn-pt correlations that are not implemented in GFW + hPhi = 0, + hPhicorr, + hPhiK0s, + hPhiLambda, + hPhiXi, + hPhiOmega, + hPhiK0scorr, + hPhiLambdacorr, + hPhiXicorr, + hPhiOmegacorr, + kCount_TH1Names + }; + + enum OutputTH3Names { + hPhiEtaVtxz = 0, + hPhiEtaVtxzK0s, + hPhiEtaVtxzLambda, + hPhiEtaVtxzXi, + hPhiEtaVtxzOmega, + kCount_TH3Names + }; + + 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 nOmegaPtBins = 0; + TAxis* fOmegaPtAxis = nullptr; + + int nK0sPtBins = 0; + TAxis* fK0sPtAxis = nullptr; + + int nLambdaPtBins = 0; + TAxis* fLambdaPtAxis = 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); + + cfgAcceptance = cfgAcceptancePath; + cfgEfficiency = cfgEfficiencyPath; + cfgNSigma = cfgNSigmapid; + cfgmassbins = cfgMassBins; + cfgMultPVCutPara = evtSeleOpts.cfgMultPVCut; + + // 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 axisOmegaPt = cfgaxisPtOmega; + nOmegaPtBins = axisOmegaPt.binEdges.size() - 1; + fOmegaPtAxis = new TAxis(nOmegaPtBins, &(axisOmegaPt.binEdges)[0]); + + o2::framework::AxisSpec axisK0sPt = cfgaxisPtK0s; + nK0sPtBins = axisK0sPt.binEdges.size() - 1; + fK0sPtAxis = new TAxis(nK0sPtBins, &(axisK0sPt.binEdges)[0]); + + o2::framework::AxisSpec axisLambdaPt = cfgaxisPtLambda; + nLambdaPtBins = axisLambdaPt.binEdges.size() - 1; + fLambdaPtAxis = new TAxis(nLambdaPtBins, &(axisLambdaPt.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.29, 1.36); + + 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("hPhiK0s", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiLambda", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiXi", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiOmega", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiK0scorr", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiLambdacorr", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiXicorr", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiOmegacorr", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hEta", "", {HistType::kTH1D, {cfgaxisEta}}); + registry.add("hVtxZ", "", {HistType::kTH1D, {cfgaxisVertex}}); + registry.add("hMult", "", {HistType::kTH1D, {cfgaxisNch}}); + registry.add("hMultTPC", "", {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("hCentvsMultTPC", "", {HistType::kTH2D, {{18, 0, 90}, cfgaxisNch}}); + registry.add("MC/hCentvsMultTPCMC", "", {HistType::kTH2D, {{18, 0, 90}, cfgaxisNch}}); + registry.add("hNTracksPVvsCentrality", "", {HistType::kTH2D, {{5000, 0, 5000}, axisMultiplicity}}); + registry.add("hPt", "", {HistType::kTH1D, {cfgaxisPt}}); + + if (cfgOutputrunbyrun) { + runNumbers = cfgRunNumbers; + for (const auto& runNumber : runNumbers) { + if (cfgOutputQA) { + std::vector> histosPhi(kCount_TH1Names); + histosPhi[hPhi] = registry.add(Form("%d/hPhi", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhicorr] = registry.add(Form("%d/hPhicorr", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhiK0s] = registry.add(Form("%d/hPhiK0s", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhiLambda] = registry.add(Form("%d/hPhiLambda", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhiXi] = registry.add(Form("%d/hPhiXi", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhiOmega] = registry.add(Form("%d/hPhiOmega", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhiK0scorr] = registry.add(Form("%d/hPhiK0scorr", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhiLambdacorr] = registry.add(Form("%d/hPhiLambdacorr", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhiXicorr] = registry.add(Form("%d/hPhiXicorr", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhiOmegacorr] = registry.add(Form("%d/hPhiOmegacorr", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + th1sList.insert(std::make_pair(runNumber, histosPhi)); + } + + std::vector> nuaTH3(kCount_TH3Names); + nuaTH3[hPhiEtaVtxz] = registry.add(Form("%d/hPhiEtaVtxz", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {cfgaxisPhi, {64, -1.6, 1.6}, cfgaxisVertex}}); + nuaTH3[hPhiEtaVtxzK0s] = registry.add(Form("%d/hPhiEtaVtxzK0s", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {cfgaxisPhi, {64, -1.6, 1.6}, cfgaxisVertex}}); + nuaTH3[hPhiEtaVtxzLambda] = registry.add(Form("%d/hPhiEtaVtxzLambda", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {cfgaxisPhi, {64, -1.6, 1.6}, cfgaxisVertex}}); + nuaTH3[hPhiEtaVtxzXi] = registry.add(Form("%d/hPhiEtaVtxzXi", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {cfgaxisPhi, {64, -1.6, 1.6}, cfgaxisVertex}}); + nuaTH3[hPhiEtaVtxzOmega] = registry.add(Form("%d/hPhiEtaVtxzOmega", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {cfgaxisPhi, {64, -1.6, 1.6}, cfgaxisVertex}}); + th3sList.insert(std::make_pair(runNumber, nuaTH3)); + } + } + + registry.add("hEventCount", "", {HistType::kTH1D, {{14, 0, 14}}}); + 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 kTVXinTRD"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "after kNoTimeFrameBorder"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(5, "after kNoITSROFrameBorder"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(6, "after kDoNoSameBunchPileup"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(7, "after kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(8, "after kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(9, "after kIsGoodITSLayersAll"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(10, "after MultPVCut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(11, "after TPC occupancy cut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(12, "after V0AT0Acut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(13, "after IRmincut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(14, "after IRmaxcut"); + registry.add("hInteractionRate", "", {HistType::kTH1D, {{1000, 0, 1000}}}); + + // QA + if (cfgOutputQA) { + // 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/Xi/hqaCascRadiusbefore", "", {HistType::kTH1D, {{200, -10, 10}}}); + registry.add("QAhisto/Xi/hqaCascRadiusafter", "", {HistType::kTH1D, {{200, -10, 10}}}); + registry.add("QAhisto/Xi/hqaCasccosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Xi/hqaCasccosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Xi/hqaCascV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Xi/hqaCascV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Xi/hqadcaCascV0toPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Xi/hqadcaCascV0toPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Xi/hqadcaCascBachtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Xi/hqadcaCascBachtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Xi/hqadcaCascdaubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Xi/hqadcaCascdauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Xi/hqadcaCascV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Xi/hqadcaCascV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + + registry.add("QAhisto/Omega/hqaCascRadiusbefore", "", {HistType::kTH1D, {{200, -10, 10}}}); + registry.add("QAhisto/Omega/hqaCascRadiusafter", "", {HistType::kTH1D, {{200, -10, 10}}}); + registry.add("QAhisto/Omega/hqaCasccosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Omega/hqaCasccosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Omega/hqaCascV0cosPAbefore", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Omega/hqaCascV0cosPAafter", "", {HistType::kTH1D, {{1000, 0.95, 1}}}); + registry.add("QAhisto/Omega/hqadcaCascV0toPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Omega/hqadcaCascV0toPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Omega/hqadcaCascBachtoPVbefore", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Omega/hqadcaCascBachtoPVafter", "", {HistType::kTH1D, {{1000, -10, 10}}}); + registry.add("QAhisto/Omega/hqadcaCascdaubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Omega/hqadcaCascdauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Omega/hqadcaCascV0daubefore", "", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("QAhisto/Omega/hqadcaCascV0dauafter", "", {HistType::kTH1D, {{100, 0, 1}}}); + } + + // cumulant of flow + registry.add("c22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c32", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c24", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c22Full", ";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}}); + registry.add("c22Fulldpt", ";Centrality (%) ; C_{2}{2}", {HistType::kTProfile2D, {cfgaxisPt, axisMultiplicity}}); + // pt-diff cumulant of flow + if (cfgOutputCasc) { + // v2 + registry.add("Xic22dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + registry.add("Omegac22dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + registry.add("Xic24dpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + registry.add("Omegac24dpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + registry.add("Xic22Fulldpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + registry.add("Omegac22Fulldpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + registry.add("Xic24_gapdpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + registry.add("Omegac24_gapdpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + // v3 + registry.add("Xic32dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + registry.add("Omegac32dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + } + if (cfgOutputV0) { + // v2 + registry.add("K0sc22dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisK0sMassforflow, axisMultiplicity}}); + registry.add("Lambdac22dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtLambda, cfgaxisLambdaMassforflow, axisMultiplicity}}); + registry.add("K0sc24dpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisK0sMassforflow, axisMultiplicity}}); + registry.add("Lambdac24dpt", ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisLambdaMassforflow, axisMultiplicity}}); + registry.add("K0sc22Fulldpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisK0sMassforflow, axisMultiplicity}}); + registry.add("Lambdac22Fulldpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtLambda, cfgaxisLambdaMassforflow, axisMultiplicity}}); + // v3 + registry.add("K0sc32dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisK0sMassforflow, axisMultiplicity}}); + registry.add("Lambdac32dpt", ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtLambda, 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}}); + refc22Full[i - 1] = registry.add(Form("Jackknife/REF/c22Full_%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, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + k0sc22[i - 1] = registry.add(Form("Jackknife/K0s/K0sc22dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisK0sMassforflow, axisMultiplicity}}); + lambdac22[i - 1] = registry.add(Form("Jackknife/Lambda/Lambdac22dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtLambda, 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, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + k0sc24[i - 1] = registry.add(Form("Jackknife/K0s/K0sc24dpt_%d", i), ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisK0sMassforflow, axisMultiplicity}}); + lambdac24[i - 1] = registry.add(Form("Jackknife/Lambda/Lambdac24dpt_%d", i), ";pt ; C_{2}{4} ", {HistType::kTProfile3D, {cfgaxisPtLambda, cfgaxisLambdaMassforflow, axisMultiplicity}}); + refc32[i - 1] = registry.add(Form("Jackknife/REF/c32_%d", i), ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + xic22Full[i - 1] = registry.add(Form("Jackknife/Xi/Xic22Fulldpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + omegac22Full[i - 1] = registry.add(Form("Jackknife/Omega/Omegac22Fulldpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + k0sc22Full[i - 1] = registry.add(Form("Jackknife/K0s/K0sc22Fulldpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisK0sMassforflow, axisMultiplicity}}); + lambdac22Full[i - 1] = registry.add(Form("Jackknife/Lambda/Lambdac22Fulldpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtLambda, cfgaxisLambdaMassforflow, axisMultiplicity}}); + xic32[i - 1] = registry.add(Form("Jackknife/Xi/Xic32dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtXi, cfgaxisXiMassforflow, axisMultiplicity}}); + omegac32[i - 1] = registry.add(Form("Jackknife/Omega/Omegac32dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtOmega, cfgaxisOmegaMassforflow, axisMultiplicity}}); + k0sc32[i - 1] = registry.add(Form("Jackknife/K0s/K0sc32dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtK0s, cfgaxisK0sMassforflow, axisMultiplicity}}); + lambdac32[i - 1] = registry.add(Form("Jackknife/Lambda/Lambdac32dpt_%d", i), ";pt ; C_{2}{2} ", {HistType::kTProfile3D, {cfgaxisPtLambda, cfgaxisLambdaMassforflow, axisMultiplicity}}); + } + } + // MC True flow + registry.add("MC/c22MC", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + if (cfgOutputCasc) { + registry.add("MC/Xic22dptMC", ";pt ; C_{2}{2} ", {HistType::kTProfile2D, {cfgaxisPtXi, axisMultiplicity}}); + registry.add("MC/Omegac22dptMC", ";pt ; C_{2}{2} ", {HistType::kTProfile2D, {cfgaxisPtOmega, axisMultiplicity}}); + } + if (cfgOutputV0) { + registry.add("MC/K0sc22dptMC", ";pt ; C_{2}{2} ", {HistType::kTProfile2D, {cfgaxisPtK0s, axisMultiplicity}}); + registry.add("MC/Lambdac22dptMC", ";pt ; C_{2}{2} ", {HistType::kTProfile2D, {cfgaxisPtLambda, axisMultiplicity}}); + } + // InvMass(GeV) of casc and v0 + AxisSpec axisOmegaMass = {80, 1.63f, 1.71f, "Inv. Mass (GeV)"}; + AxisSpec axisXiMass = {80, 1.29f, 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)"}; + if (cfgOutputCasc) { + registry.add("InvMassXi_all", "", {HistType::kTHnSparseF, {cfgaxisPtXi, axisXiMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassOmega_all", "", {HistType::kTHnSparseF, {cfgaxisPtOmega, axisOmegaMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassXi", "", {HistType::kTHnSparseF, {cfgaxisPtXi, axisXiMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassOmega", "", {HistType::kTHnSparseF, {cfgaxisPtOmega, axisOmegaMass, cfgaxisEta, axisMultiplicity}}); + } + if (cfgOutputV0) { + registry.add("InvMassK0s_all", "", {HistType::kTHnSparseF, {cfgaxisPtK0s, axisK0sMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassLambda_all", "", {HistType::kTHnSparseF, {cfgaxisPtLambda, axisLambdaMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassK0s", "", {HistType::kTHnSparseF, {cfgaxisPtK0s, axisK0sMass, cfgaxisEta, axisMultiplicity}}); + registry.add("InvMassLambda", "", {HistType::kTHnSparseF, {cfgaxisPtLambda, axisLambdaMass, cfgaxisEta, axisMultiplicity}}); + } + // for local density correction + if (cfgOutputLocDenWeights) { + registry.add("MC/densityMCGenK0s", "", {HistType::kTH3D, {cfgaxisPtK0s, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenLambda", "", {HistType::kTH3D, {cfgaxisPtLambda, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenXi", "", {HistType::kTH3D, {cfgaxisPtXi, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenOmega", "", {HistType::kTH3D, {cfgaxisPtOmega, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCRecK0s", "", {HistType::kTHnSparseF, {cfgaxisPtK0s, cfgaxisNch, cfgaxisLocalDensity, axisK0sMass}}); + registry.add("MC/densityMCRecLambda", "", {HistType::kTHnSparseF, {cfgaxisPtLambda, cfgaxisNch, cfgaxisLocalDensity, axisLambdaMass}}); + registry.add("MC/densityMCRecXi", "", {HistType::kTHnSparseF, {cfgaxisPtXi, cfgaxisNch, cfgaxisLocalDensity, axisXiMass}}); + registry.add("MC/densityMCRecOmega", "", {HistType::kTHnSparseF, {cfgaxisPtOmega, cfgaxisNch, cfgaxisLocalDensity, axisOmegaMass}}); + + registry.add("MC/densityMCGenK0sMultTPC", "", {HistType::kTH3D, {cfgaxisPtK0s, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenLambdaMultTPC", "", {HistType::kTH3D, {cfgaxisPtLambda, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenXiMultTPC", "", {HistType::kTH3D, {cfgaxisPtXi, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCGenOmegaMultTPC", "", {HistType::kTH3D, {cfgaxisPtOmega, cfgaxisNch, cfgaxisLocalDensity}}); + registry.add("MC/densityMCRecK0sMultTPC", "", {HistType::kTHnSparseF, {cfgaxisPtK0s, cfgaxisNch, cfgaxisLocalDensity, axisK0sMass}}); + registry.add("MC/densityMCRecLambdaMultTPC", "", {HistType::kTHnSparseF, {cfgaxisPtLambda, cfgaxisNch, cfgaxisLocalDensity, axisLambdaMass}}); + registry.add("MC/densityMCRecXiMultTPC", "", {HistType::kTHnSparseF, {cfgaxisPtXi, cfgaxisNch, cfgaxisLocalDensity, axisXiMass}}); + registry.add("MC/densityMCRecOmegaMultTPC", "", {HistType::kTHnSparseF, {cfgaxisPtOmega, 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); + 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); + int nK0sptMassBins = nK0sPtBins * 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); + int nLambdaptMassBins = nLambdaPtBins * 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); + // 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 + // v2 + 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("poifulldpt reffull | poioldpt {2 -2}", "PoiFull22dpt", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiPdpt {2} refN10 {-2}", "Xi10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiNdpt {2} refP10 {-2}", "Xi10Gap22b", kTRUE)); // 5 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXifulldpt reffull {2 2 -2 -2}", "Xi10Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXifulldpt {2} reffull {-2}", "XiFull22", kTRUE)); + 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}", "Omega10Gap24", kTRUE)); // 10 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegafulldpt {2} reffull {-2}", "OmegaFull22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sPdpt {2} refN10 {-2}", "K0short10Gap22a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sNdpt {2} refP10 {-2}", "K0short10Gap22b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sfulldpt reffull {2 2 -2 -2}", "K0short10Gap24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sfulldpt {2} reffull {-2}", "K0shortFull22", kTRUE)); // 15 + 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}", "LambdaFull24", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiLambdafulldpt {2} reffull {-2}", "LambdaFull22", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP10 {2} refN10 {-2}", "Ref10Gap22a", kFALSE)); // 20 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("reffull reffull {2 2 -2 -2}", "Ref10Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("reffull reffull {2 -2}", "RefFull22", kFALSE)); + // v3 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiPdpt {3} refN10 {-3}", "Xi10Gap32a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiNdpt {3} refP10 {-3}", "Xi10Gap32b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegaPdpt {3} refN10 {-3}", "Omega10Gap32a", kTRUE)); // 25 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegaNdpt {3} refP10 {-3}", "Omega10Gap32b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sPdpt {3} refN10 {-3}", "K0short10Gap32a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiK0sNdpt {3} refP10 {-3}", "K0short10Gap32b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiLambdaPdpt {3} refN10 {-3}", "Lambda10Gap32a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiLambdaNdpt {3} refP10 {-3}", "Lambda10Gap32b", kTRUE)); // 30 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP10 {3} refN10 {-3}", "Ref10Gap32a", kFALSE)); + // MC + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiPdptMC {2} refN10MC {-2}", "MCXi10Gap22a", kTRUE)); + 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)); // 35 + 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)); // 40 + + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiPdpt refP10 {2, 2} refN10 {-2 -2}", "Xi10Gap24a", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiXiNdpt refN10 {2, 2} refP10 {-2 -2}", "Xi10Gap24b", kTRUE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegaPdpt refP10 {2, 2} refN10 {-2 -2}", "Omega10Gap24a", kTRUE)); // 45 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiOmegaNdpt refN10 {2, 2} refP10 {-2 -2}", "Omega10Gap24b", kTRUE)); + 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]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", 0, 100); + fMultPVCutLow->SetParameters(cfgMultPVCutPara[0], cfgMultPVCutPara[1], cfgMultPVCutPara[2], cfgMultPVCutPara[3], cfgMultPVCutPara[4], cfgMultPVCutPara[5], cfgMultPVCutPara[6], cfgMultPVCutPara[7], cfgMultPVCutPara[8], cfgMultPVCutPara[9]); + 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(cfgMultPVCutPara[0], cfgMultPVCutPara[1], cfgMultPVCutPara[2], cfgMultPVCutPara[3], cfgMultPVCutPara[4], cfgMultPVCutPara[5], cfgMultPVCutPara[6], cfgMultPVCutPara[7], cfgMultPVCutPara[8], cfgMultPVCutPara[9]); + + 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 = fOmegaPtAxis; + } else if (PDGCode == kK0Short) { + fpt = fK0sPtAxis; + } else if (PDGCode == kLambda0) { + fpt = fLambdaPtAxis; + } 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 = nOmegaPtBins; + fpt = fOmegaPtAxis; + fMass = fOmegaMass; + } else if (PDGCode == kK0Short) { + nMassBins = cfgmassbins[0]; + nptbins = nK0sPtBins; + fpt = fK0sPtAxis; + fMass = fK0sMass; + } else if (PDGCode == kLambda0) { + nMassBins = cfgmassbins[1]; + nptbins = nLambdaPtBins; + fpt = fLambdaPtAxis; + 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 = nOmegaPtBins; + fpt = fOmegaPtAxis; + fMass = fOmegaMass; + } else if (PDGCode == kK0Short) { + nMassBins = cfgmassbins[0]; + nptbins = nK0sPtBins; + fpt = fK0sPtAxis; + fMass = fK0sMass; + } else if (PDGCode == kLambda0) { + nMassBins = cfgmassbins[1]; + nptbins = nLambdaPtBins; + fpt = fLambdaPtAxis; + 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() == 1) + mEfficiency.push_back(ccdb->getForTimeStamp(cfgEfficiency[0], timestamp)); + + correctionsLoaded = true; + } + + template + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, TrackObject track, float vtxz, int ispecies) + { + float eff = 1.; + int nspecies = 5; + if (ispecies == 0 && cfgEfficiency.size() == 1) + eff = mEfficiency[ispecies]->GetBinContent(mEfficiency[ispecies]->FindBin(track.pt())); + 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, float interactionRate = -1) + { + if (evtSeleOpts.cfgDoTVXinTRD.value && collision.alias_bit(kTVXinTRD)) { + // TRD triggered + return false; + } + registry.fill(HIST("hEventCount"), 2.5); + if (evtSeleOpts.cfgDoNoTimeFrameBorder.value && !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"), 3.5); + if (evtSeleOpts.cfgDoNoITSROFrameBorder.value && !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"), 4.5); + if (evtSeleOpts.cfgDoNoSameBunchPileup.value && !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"), 5.5); + if (evtSeleOpts.cfgDoIsGoodZvtxFT0vsPV.value && !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"), 6.5); + if (evtSeleOpts.cfgDoNoCollInTimeRangeStandard.value && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + registry.fill(HIST("hEventCount"), 7.5); + if (evtSeleOpts.cfgDoIsGoodITSLayersAll.value && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // cut time intervals with dead ITS staves + return 0; + } + registry.fill(HIST("hEventCount"), 8.5); + 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; + + registry.fill(HIST("hNTracksPVvsCentrality"), multNTracksPV, centrality); + if (evtSeleOpts.cfgDoMultPVCut.value) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return false; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return false; + } + + registry.fill(HIST("hEventCount"), 9.5); + + if (occupancy > evtSeleOpts.cfgCutOccupancyHigh.value) + return 0; + registry.fill(HIST("hEventCount"), 10.5); + + // V0A T0A 5 sigma cut + if (evtSeleOpts.cfgDoV0AT0Acut.value) { + int nsigma = 5; + if (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > nsigma * fT0AV0ASigma->Eval(collision.multFT0A())) + return 0; + } + registry.fill(HIST("hEventCount"), 11.5); + + registry.fill(HIST("hInteractionRate"), interactionRate); + if (interactionRate > 0 && interactionRate < evtSeleOpts.cfgCutminIR.value) + return false; + registry.fill(HIST("hEventCount"), 12.5); + if (interactionRate > evtSeleOpts.cfgCutmaxIR.value) + return false; + registry.fill(HIST("hEventCount"), 13.5); + + return true; + } + + void processData(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks, soa::Join const& Cascades, aod::V0Datas const& V0s, DaughterTracks const&) + { + o2::aod::ITSResponse itsResponse; + int nTot = tracks.size(); + float nMultTPC = collision.multTPC(); + auto bc = collision.bc_as(); + int runNumber = bc.runNumber(); + double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + + registry.fill(HIST("hEventCount"), 0.5); + if (nTot < 1) + return; + fGFW->Clear(); + const auto cent = collision.centFT0C(); + if (!collision.sel8()) + return; + registry.fill(HIST("hEventCount"), 1.5); + + if (!eventSelected(collision, cent, interactionRate)) + return; + TH1D* hLocalDensity = new TH1D("hphi", "hphi", 400, -constants::math::TwoPI, constants::math::TwoPI); + loadCorrections(bc.timestamp()); + float vtxz = collision.posZ(); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), nTot); + registry.fill(HIST("hMultTPC"), nMultTPC); + registry.fill(HIST("hCent"), cent); + + 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("hPt"), track.pt()); + int ptbin = fPtAxis->FindBin(track.pt()) - 1; + if ((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value)) { + fGFW->Fill(track.eta(), ptbin, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) + } + if ((track.pt() > trkQualityOpts.cfgCutPtPOIMin.value) && (track.pt() < trkQualityOpts.cfgCutPtPOIMax.value)) { + 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 (cfgOutputrunbyrun) { + if (cfgOutputQA) { + th1sList[runNumber][hPhi]->Fill(track.phi()); + th1sList[runNumber][hPhicorr]->Fill(track.phi(), wacc); + } + th3sList[runNumber][hPhiEtaVtxz]->Fill(track.phi(), track.eta(), vtxz); + } + } + if (cfgDoLocDenCorr) { + registry.fill(HIST("hCentvsNch"), cent, nch); + registry.fill(HIST("hCentvsMultTPC"), cent, nMultTPC); + } + // fill GFW of V0 flow + double lowpt = trkQualityOpts.cfgCutPtPIDDauMin.value; + double bachPtcut = trkQualityOpts.cfgCutPtPIDbachMin.value; + double dauLaPrPtcut = trkQualityOpts.cfgCutPtPIDdauLaPrMin.value; + double dauLaPiPtcut = trkQualityOpts.cfgCutPtPIDdauLaPiMin.value; + + if (cfgOutputV0) { + for (const auto& v0 : V0s) { + auto v0posdau = v0.posTrack_as(); + auto v0negdau = v0.negTrack_as(); + // check tpc + bool isK0s = false; + bool isLambda = false; + if (v0posdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || v0posdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + if (v0negdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || v0negdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + + // fill QA + if (cfgOutputQA) { + registry.fill(HIST("QAhisto/V0/hqaarm_podobefore"), v0.alpha(), v0.qtarm()); + } + // check daughter TPC and TOF + // K0short + if (v0.pt() > trkQualityOpts.cfgCutPtK0sMin.value && v0.pt() < trkQualityOpts.cfgCutPtK0sMax.value) { + if (v0.qtarm() / std::fabs(v0.alpha()) > v0BuilderOpts.cfgv0_ArmPodocut.value && + std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0BuilderOpts.cfgv0_mk0swindow.value && + (std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0]) && + ((std::fabs(v0posdau.tofNSigmaPi()) < cfgNSigma[3] || v0posdau.pt() < lowpt) && (std::fabs(v0negdau.tofNSigmaPi()) < cfgNSigma[3] || v0negdau.pt() < lowpt)) && + ((std::fabs(itsResponse.nSigmaITS(v0posdau)) < cfgNSigma[6]) || v0posdau.pt() < lowpt) && ((std::fabs(itsResponse.nSigmaITS(v0negdau)) < cfgNSigma[6]) || v0negdau.pt() < lowpt)) { + registry.fill(HIST("InvMassK0s_all"), v0.pt(), v0.mK0Short(), v0.eta(), cent); + isK0s = true; + if (cfgOutputQA) { + registry.fill(HIST("QAhisto/V0/hqaarm_podoafter"), v0.alpha(), v0.qtarm()); + } + } + } + // Lambda and antiLambda + if (v0.pt() > trkQualityOpts.cfgCutPtLambdaMin.value && v0.pt() < trkQualityOpts.cfgCutPtLambdaMax.value) { + if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < v0BuilderOpts.cfgv0_mlambdawindow.value && + (std::fabs(v0posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0negdau.tpcNSigmaPi()) < cfgNSigma[0]) && + ((std::fabs(v0posdau.tofNSigmaPr()) < cfgNSigma[4] || v0posdau.pt() < lowpt) && (std::fabs(v0negdau.tofNSigmaPi()) < cfgNSigma[3] || v0negdau.pt() < lowpt)) && + ((std::fabs(itsResponse.nSigmaITS(v0posdau)) < cfgNSigma[7]) || v0posdau.pt() < lowpt) && ((std::fabs(itsResponse.nSigmaITS(v0negdau)) < cfgNSigma[6]) || v0negdau.pt() < lowpt)) { + registry.fill(HIST("InvMassLambda_all"), v0.pt(), v0.mLambda(), v0.eta(), cent); + isLambda = true; + } else if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < v0BuilderOpts.cfgv0_mlambdawindow.value && + (std::fabs(v0negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(v0posdau.tpcNSigmaPi()) < cfgNSigma[0]) && + ((std::fabs(v0negdau.tofNSigmaPr()) < cfgNSigma[4] || v0negdau.pt() < lowpt) && (std::fabs(v0posdau.tofNSigmaPi()) < cfgNSigma[3] || v0posdau.pt() < lowpt)) && + ((std::fabs(itsResponse.nSigmaITS(v0posdau)) < cfgNSigma[7]) || v0posdau.pt() < lowpt) && ((std::fabs(itsResponse.nSigmaITS(v0negdau)) < cfgNSigma[6]) || v0negdau.pt() < lowpt)) { + registry.fill(HIST("InvMassLambda_all"), v0.pt(), v0.mLambda(), v0.eta(), cent); + isLambda = true; + } + } + // fill QA before cut + if (cfgOutputQA) { + 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.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!v0negdau.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!v0posdau.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!v0negdau.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!v0posdau.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (!v0negdau.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (trkQualityOpts.cfgCheckGlobalTrack.value) { + if (!v0posdau.hasTPC() || !v0posdau.hasITS()) + continue; + if (!v0negdau.hasTPC() || !v0negdau.hasITS()) + continue; + } + // // topological cut + if (v0.v0radius() < v0BuilderOpts.cfgv0_radius.value) + continue; + if (v0.v0cosPA() < v0BuilderOpts.cfgv0_v0cospa.value) + continue; + if (v0.dcaV0daughters() > v0BuilderOpts.cfgv0_dcav0dau.value) + continue; + if (std::fabs(v0.dcapostopv()) < v0BuilderOpts.cfgv0_dcadautopv.value) + continue; + if (std::fabs(v0.dcanegtopv()) < v0BuilderOpts.cfgv0_dcadautopv.value) + continue; + if (isK0s && std::fabs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0BuilderOpts.cfgv0_compmassrejLambda.value) + isK0s = false; + if (isLambda && std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0BuilderOpts.cfgv0_compmassrejK0s.value) + isLambda = false; + + // fill QA after cut + if (cfgOutputQA) { + 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()); + registry.fill(HIST("MC/densityMCRecK0sMultTPC"), v0.pt(), nMultTPC, density, v0.mK0Short()); + } + } + registry.fill(HIST("InvMassK0s"), v0.pt(), v0.mK0Short(), v0.eta(), cent); + registry.fill(HIST("hPhiK0s"), v0.phi()); + registry.fill(HIST("hPhiK0scorr"), v0.phi(), wacc); + fGFW->Fill(v0.eta(), fK0sPtAxis->FindBin(v0.pt()) - 1 + ((fK0sMass->FindBin(v0.mK0Short()) - 1) * nK0sPtBins), v0.phi(), wacc * weff * wloc, 8); + if (cfgOutputNUAWeights) + fWeightsK0s->fill(v0.phi(), v0.eta(), vtxz, v0.pt(), cent, 0); + if (cfgOutputrunbyrun) { + if (cfgOutputQA) { + th1sList[runNumber][hPhiK0s]->Fill(v0.phi()); + th1sList[runNumber][hPhiK0scorr]->Fill(v0.phi(), wacc); + } + th3sList[runNumber][hPhiEtaVtxzK0s]->Fill(v0.phi(), v0.eta(), vtxz); + } + } + 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()); + registry.fill(HIST("MC/densityMCRecLambdaMultTPC"), v0.pt(), nMultTPC, density, v0.mLambda()); + } + } + registry.fill(HIST("InvMassLambda"), v0.pt(), v0.mLambda(), v0.eta(), cent); + registry.fill(HIST("hPhiLambda"), v0.phi()); + registry.fill(HIST("hPhiLambdacorr"), v0.phi(), wacc); + fGFW->Fill(v0.eta(), fK0sPtAxis->FindBin(v0.pt()) - 1 + ((fLambdaMass->FindBin(v0.mLambda()) - 1) * nK0sPtBins), v0.phi(), wacc * weff * wloc, 16); + if (cfgOutputNUAWeights) + fWeightsLambda->fill(v0.phi(), v0.eta(), vtxz, v0.pt(), cent, 0); + if (cfgOutputrunbyrun) { + if (cfgOutputQA) { + th1sList[runNumber][hPhiLambda]->Fill(v0.phi()); + th1sList[runNumber][hPhiLambdacorr]->Fill(v0.phi(), wacc); + } + th3sList[runNumber][hPhiEtaVtxzLambda]->Fill(v0.phi(), v0.eta(), vtxz); + } + } + } + } + + // fill GFW of casc flow + if (cfgOutputCasc) { + for (const auto& casc : Cascades) { + auto bachelor = casc.bachelor_as(); + auto posdau = casc.posTrack_as(); + auto negdau = casc.negTrack_as(); + // check TPC + bool isOmega = false; + bool isXi = false; + + if (bachelor.pt() < trkQualityOpts.cfgCutPtDauMin.value || bachelor.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + if (posdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || posdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + if (negdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || negdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + + // Omega and antiOmega + if (casc.pt() > trkQualityOpts.cfgCutPtOmegaMin.value && casc.pt() < trkQualityOpts.cfgCutPtOmegaMax.value) { + if (casc.sign() < 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0]) && + ((std::fabs(casc.tofNSigmaOmKa()) < cfgNSigma[5] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaOmLaPr()) < cfgNSigma[4] || posdau.pt() < dauLaPrPtcut) && (std::fabs(casc.tofNSigmaOmLaPi()) < cfgNSigma[3] || negdau.pt() < dauLaPiPtcut)) && + ((std::fabs(itsResponse.nSigmaITS(bachelor)) < cfgNSigma[8]) || bachelor.pt() < bachPtcut) && ((std::fabs(itsResponse.nSigmaITS(posdau)) < cfgNSigma[7]) || posdau.pt() < dauLaPrPtcut) && ((std::fabs(itsResponse.nSigmaITS(negdau)) < cfgNSigma[6]) || negdau.pt() < dauLaPiPtcut)) { + registry.fill(HIST("InvMassOmega_all"), casc.pt(), casc.mOmega(), casc.eta(), cent); + isOmega = true; + } else if (casc.sign() > 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (std::fabs(bachelor.tpcNSigmaKa()) < cfgNSigma[2] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0]) && + ((std::fabs(casc.tofNSigmaOmKa()) < cfgNSigma[5] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaOmLaPr()) < cfgNSigma[4] || negdau.pt() < dauLaPrPtcut) && (std::fabs(casc.tofNSigmaOmLaPi()) < cfgNSigma[3] || posdau.pt() < dauLaPiPtcut)) && + ((std::fabs(itsResponse.nSigmaITS(bachelor)) < cfgNSigma[8]) || bachelor.pt() < bachPtcut) && ((std::fabs(itsResponse.nSigmaITS(negdau)) < cfgNSigma[7]) || negdau.pt() < dauLaPrPtcut) && ((std::fabs(itsResponse.nSigmaITS(posdau)) < cfgNSigma[6]) || posdau.pt() < dauLaPiPtcut)) { + registry.fill(HIST("InvMassOmega_all"), casc.pt(), casc.mOmega(), casc.eta(), cent); + isOmega = true; + } + } + // Xi and antiXi + if (casc.pt() > trkQualityOpts.cfgCutPtXiMin.value && casc.pt() < trkQualityOpts.cfgCutPtXiMax.value) { + if (casc.sign() < 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(posdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(negdau.tpcNSigmaPi()) < cfgNSigma[0]) && + ((std::fabs(casc.tofNSigmaXiPi()) < cfgNSigma[3] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaXiLaPr()) < cfgNSigma[4] || posdau.pt() < dauLaPrPtcut) && (std::fabs(casc.tofNSigmaXiLaPi()) < cfgNSigma[3] || negdau.pt() < dauLaPiPtcut)) && + ((std::fabs(itsResponse.nSigmaITS(bachelor)) < cfgNSigma[6]) || bachelor.pt() < bachPtcut) && ((std::fabs(itsResponse.nSigmaITS(posdau)) < cfgNSigma[7]) || posdau.pt() < dauLaPrPtcut) && ((std::fabs(itsResponse.nSigmaITS(negdau)) < cfgNSigma[6]) || negdau.pt() < dauLaPiPtcut)) { + registry.fill(HIST("InvMassXi_all"), casc.pt(), casc.mXi(), casc.eta(), cent); + isXi = true; + } else if (casc.sign() > 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (std::fabs(bachelor.tpcNSigmaPi()) < cfgNSigma[0] && std::fabs(negdau.tpcNSigmaPr()) < cfgNSigma[1] && std::fabs(posdau.tpcNSigmaPi()) < cfgNSigma[0]) && + ((std::fabs(casc.tofNSigmaXiPi()) < cfgNSigma[3] || bachelor.pt() < bachPtcut) && (std::fabs(casc.tofNSigmaXiLaPr()) < cfgNSigma[4] || negdau.pt() < dauLaPrPtcut) && (std::fabs(casc.tofNSigmaXiLaPi()) < cfgNSigma[3] || posdau.pt() < dauLaPiPtcut)) && + ((std::fabs(itsResponse.nSigmaITS(bachelor)) < cfgNSigma[6]) || bachelor.pt() < bachPtcut) && ((std::fabs(itsResponse.nSigmaITS(negdau)) < cfgNSigma[7]) || negdau.pt() < dauLaPrPtcut) && ((std::fabs(itsResponse.nSigmaITS(posdau)) < cfgNSigma[6]) || posdau.pt() < dauLaPiPtcut)) { + registry.fill(HIST("InvMassXi_all"), casc.pt(), casc.mXi(), casc.eta(), cent); + isXi = true; + } + } + // fill QA + if (cfgOutputQA) { + if (isXi) { + registry.fill(HIST("QAhisto/Xi/hqaCascRadiusbefore"), casc.cascradius()); + registry.fill(HIST("QAhisto/Xi/hqaCasccosPAbefore"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqaCascV0cosPAbefore"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0toPVbefore"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascdaubefore"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + } + if (isOmega) { + registry.fill(HIST("QAhisto/Omega/hqaCascRadiusbefore"), casc.cascradius()); + registry.fill(HIST("QAhisto/Omega/hqaCasccosPAbefore"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqaCascV0cosPAbefore"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0toPVbefore"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascdaubefore"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + } + } + + if (!isXi && !isOmega) + continue; + // // topological cut + if (casc.cascradius() < cascBuilderOpts.cfgcasc_radius.value) + continue; + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascBuilderOpts.cfgcasc_casccospa.value) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascBuilderOpts.cfgcasc_v0cospa.value) + continue; + if (std::fabs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascBuilderOpts.cfgcasc_dcav0topv.value) + continue; + if (std::fabs(casc.dcabachtopv()) < cascBuilderOpts.cfgcasc_dcabachtopv.value) + continue; + if (casc.dcacascdaughters() > cascBuilderOpts.cfgcasc_dcacascdau.value) + continue; + if (casc.dcaV0daughters() > cascBuilderOpts.cfgcasc_dcav0dau.value) + continue; + if (std::fabs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascBuilderOpts.cfgcasc_mlambdawindow.value) + continue; + // // track quality check + if (!bachelor.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!posdau.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!negdau.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!bachelor.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!posdau.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!negdau.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!bachelor.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (!posdau.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (!negdau.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (trkQualityOpts.cfgCheckGlobalTrack.value) { + if (!bachelor.hasTPC() || !bachelor.hasITS()) + continue; + if (!posdau.hasTPC() || !posdau.hasITS()) + continue; + if (!negdau.hasTPC() || !negdau.hasITS()) + continue; + } + if (isXi && std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < cascBuilderOpts.cfgcasc_compmassrej.value) { + isXi = false; + } + if (isOmega && std::fabs(casc.mXi() - o2::constants::physics::MassXiMinus) < cascBuilderOpts.cfgcasc_compmassrej.value) { + isOmega = false; + } + // fill QA + if (cfgOutputQA) { + if (isXi) { + registry.fill(HIST("QAhisto/Xi/hqaCascRadiusafter"), casc.cascradius()); + registry.fill(HIST("QAhisto/Xi/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + } + if (isOmega) { + registry.fill(HIST("QAhisto/Omega/hqaCascRadiusafter"), casc.cascradius()); + registry.fill(HIST("QAhisto/Omega/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Omega/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()); + registry.fill(HIST("MC/densityMCRecOmegaMultTPC"), casc.pt(), nMultTPC, density, casc.mOmega()); + } + } + registry.fill(HIST("hPhiOmega"), casc.phi()); + registry.fill(HIST("hPhiOmegacorr"), casc.phi(), wacc); + registry.fill(HIST("InvMassOmega"), casc.pt(), casc.mOmega(), casc.eta(), cent); + fGFW->Fill(casc.eta(), fOmegaPtAxis->FindBin(casc.pt()) - 1 + ((fOmegaMass->FindBin(casc.mOmega()) - 1) * nOmegaPtBins), casc.phi(), wacc * weff * wloc, 4); + + if (cfgOutputNUAWeights) + fWeightsOmega->fill(casc.phi(), casc.eta(), vtxz, casc.pt(), cent, 0); + if (cfgOutputrunbyrun) { + if (cfgOutputQA) { + th1sList[runNumber][hPhiOmega]->Fill(casc.phi()); + th1sList[runNumber][hPhiOmegacorr]->Fill(casc.phi(), wacc); + } + th3sList[runNumber][hPhiEtaVtxzOmega]->Fill(casc.phi(), casc.eta(), vtxz); + } + } + 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()); + registry.fill(HIST("MC/densityMCRecXiMultTPC"), casc.pt(), nMultTPC, density, casc.mXi()); + } + } + registry.fill(HIST("hPhiXi"), casc.phi()); + registry.fill(HIST("hPhiXicorr"), casc.phi(), 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); + if (cfgOutputrunbyrun) { + if (cfgOutputQA) { + th1sList[runNumber][hPhiXi]->Fill(casc.phi()); + th1sList[runNumber][hPhiXicorr]->Fill(casc.phi(), wacc); + } + th3sList[runNumber][hPhiEtaVtxzXi]->Fill(casc.phi(), casc.eta(), vtxz); + } + } + } + } + delete hLocalDensity; + // Filling cumulant with ROOT TProfile and loop for all ptBins + fillProfile(corrconfigs.at(20), HIST("c22"), cent); + fillProfile(corrconfigs.at(21), HIST("c24"), cent); + fillProfile(corrconfigs.at(22), HIST("c22Full"), cent); + fillProfile(corrconfigs.at(31), HIST("c32"), 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); + fillProfilepT(corrconfigs.at(3), HIST("c22Fulldpt"), i, cent); + } + if (cfgOutputV0) { + for (int i = 1; i <= nK0sPtBins; i++) { + fillProfilepTMass(corrconfigs.at(12), HIST("K0sc22dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(13), HIST("K0sc22dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(14), HIST("K0sc24dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(15), HIST("K0sc22Fulldpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(27), HIST("K0sc32dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(28), HIST("K0sc32dpt"), i, kK0Short, cent); + } + for (int i = 1; i <= nLambdaPtBins; i++) { + fillProfilepTMass(corrconfigs.at(16), HIST("Lambdac22dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(17), HIST("Lambdac22dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(18), HIST("Lambdac24dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(19), HIST("Lambdac22Fulldpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(29), HIST("Lambdac32dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(30), HIST("Lambdac32dpt"), i, kLambda0, cent); + } + } + if (cfgOutputCasc) { + for (int i = 1; i <= nXiPtBins; i++) { + fillProfilepTMass(corrconfigs.at(4), HIST("Xic22dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(5), HIST("Xic22dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(6), HIST("Xic24dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(7), HIST("Xic22Fulldpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(23), HIST("Xic32dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(24), HIST("Xic32dpt"), i, kXiMinus, cent); + + fillProfilepTMass(corrconfigs.at(41), HIST("Xic24_gapdpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(42), HIST("Xic24_gapdpt"), i, kXiMinus, cent); + } + for (int i = 1; i <= nOmegaPtBins; i++) { + fillProfilepTMass(corrconfigs.at(8), HIST("Omegac22dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(9), HIST("Omegac22dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(10), HIST("Omegac24dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(11), HIST("Omegac22Fulldpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(25), HIST("Omegac32dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(26), HIST("Omegac32dpt"), i, kOmegaMinus, cent); + + fillProfilepTMass(corrconfigs.at(43), HIST("Omegac24_gapdpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(44), HIST("Omegac24_gapdpt"), 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(20), refc22[j - 1], cent); + fillProfile(corrconfigs.at(21), refc24[j - 1], cent); + fillProfile(corrconfigs.at(22), refc22Full[j - 1], cent); + fillProfile(corrconfigs.at(31), refc32[j - 1], cent); + if (cfgOutputV0) { + for (int i = 1; i <= nK0sPtBins; i++) { + fillProfilepTMass(corrconfigs.at(12), k0sc22[j - 1], i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(13), k0sc22[j - 1], i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(14), k0sc24[j - 1], i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(15), k0sc22Full[j - 1], i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(27), k0sc32[j - 1], i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(28), k0sc32[j - 1], i, kK0Short, cent); + } + for (int i = 1; i <= nLambdaPtBins; i++) { + fillProfilepTMass(corrconfigs.at(16), lambdac22[j - 1], i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(17), lambdac22[j - 1], i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(18), lambdac24[j - 1], i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(19), lambdac22Full[j - 1], i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(29), lambdac32[j - 1], i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(30), lambdac32[j - 1], i, kLambda0, cent); + } + } + if (cfgOutputCasc) { + for (int i = 1; i <= nXiPtBins; i++) { + fillProfilepTMass(corrconfigs.at(4), xic22[j - 1], i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(5), xic22[j - 1], i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(6), xic24[j - 1], i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(7), xic22Full[j - 1], i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(23), xic32[j - 1], i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(24), xic32[j - 1], i, kXiMinus, cent); + } + for (int i = 1; i <= nOmegaPtBins; i++) { + fillProfilepTMass(corrconfigs.at(8), omegac22[j - 1], i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(9), omegac22[j - 1], i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(10), omegac24[j - 1], i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(11), omegac22Full[j - 1], i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(25), omegac32[j - 1], i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(26), omegac32[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; + float nMultTPC = 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(); + nMultTPC = collision.multTPC(); + registry.fill(HIST("MC/hCentvsMultTPCMC"), cent, nMultTPC); + } + 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 (std::fabs(track.eta()) > trkQualityOpts.cfgCutEta.value) { + continue; + } + if (!(track.isGlobalTrack())) { + continue; + } + if (track.tpcChi2NCl() > cfgCutChi2prTPCcls) { + continue; + } + int ptbin = fPtAxis->FindBin(mcParticle.pt()) - 1; + if ((mcParticle.pt() > trkQualityOpts.cfgCutPtMin.value) && (mcParticle.pt() < trkQualityOpts.cfgCutPtMax.value)) { + fGFW->Fill(mcParticle.eta(), ptbin, mcParticle.phi(), 1, 64); //(eta, ptbin, phi, wacc*weff, bitmask) + } + if ((mcParticle.pt() > trkQualityOpts.cfgCutPtPOIMin.value) && (mcParticle.pt() < trkQualityOpts.cfgCutPtPOIMax.value)) { + 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()) > trkQualityOpts.cfgCutEta.value) + 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); + registry.fill(HIST("MC/densityMCGenXiMultTPC"), straGen.pt(), nMultTPC, 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); + registry.fill(HIST("MC/densityMCGenOmegaMultTPC"), straGen.pt(), nMultTPC, density); + } + fGFW->Fill(straGen.eta(), fOmegaPtAxis->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); + registry.fill(HIST("MC/densityMCGenK0sMultTPC"), straGen.pt(), nMultTPC, density); + } + fGFW->Fill(straGen.eta(), fK0sPtAxis->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); + registry.fill(HIST("MC/densityMCGenLambdaMultTPC"), straGen.pt(), nMultTPC, density); + } + fGFW->Fill(straGen.eta(), fLambdaPtAxis->FindBin(straGen.pt()) - 1, straGen.phi(), 1, 1024); + } + } + fillProfile(corrconfigs.at(40), HIST("MC/c22MC"), cent); + for (int i = 1; i <= nK0sPtBins; i++) { + fillProfilepTMC(corrconfigs.at(36), HIST("MC/K0sc22dptMC"), i, kK0Short, cent); + fillProfilepTMC(corrconfigs.at(37), HIST("MC/K0sc22dptMC"), i, kK0Short, cent); + } + for (int i = 1; i <= nLambdaPtBins; i++) { + fillProfilepTMC(corrconfigs.at(38), HIST("MC/Lambdac22dptMC"), i, kLambda0, cent); + fillProfilepTMC(corrconfigs.at(39), HIST("MC/Lambdac22dptMC"), i, kLambda0, cent); + } + for (int i = 1; i <= nXiPtBins; i++) { + fillProfilepTMC(corrconfigs.at(32), HIST("MC/Xic22dptMC"), i, kXiMinus, cent); + fillProfilepTMC(corrconfigs.at(33), HIST("MC/Xic22dptMC"), i, kXiMinus, cent); + } + for (int i = 1; i <= nOmegaPtBins; i++) { + fillProfilepTMC(corrconfigs.at(34), HIST("MC/Omegac22dptMC"), i, kOmegaMinus, cent); + fillProfilepTMC(corrconfigs.at(35), 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.pt() < trkQualityOpts.cfgCutPtPOIMin.value || track.pt() > trkQualityOpts.cfgCutPtPOIMax.value) + continue; + if (std::fabs(track.eta()) > trkQualityOpts.cfgCutEta.value) + continue; + if (!(track.isGlobalTrack())) + continue; + if (track.tpcChi2NCl() > cfgCutChi2prTPCcls) + continue; + if (cfgDoAccEffCorr) { + if (!setCurrentParticleWeights(weff, wacc, track, vtxz, 0)) + continue; + } + nch += wacc * weff; + if (!track.has_mcParticle()) + continue; + auto mcParticle = track.mcParticle_as(); + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhicorr"), track.phi(), wacc); + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hPt"), track.pt()); + int ptbin = fPtAxis->FindBin(track.pt()) - 1; + if ((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value)) { + fGFW->Fill(track.eta(), ptbin, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) + } + if ((track.pt() > trkQualityOpts.cfgCutPtPOIMin.value) && (track.pt() < trkQualityOpts.cfgCutPtPOIMax.value)) { + 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); + } + } + } + + 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(); + int pdgCode{cascMC.pdgCode()}; + if (bachelor.pt() < trkQualityOpts.cfgCutPtDauMin.value || bachelor.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + if (posdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || posdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + if (negdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || negdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + // fill QA + if (cfgOutputQA) { + if (std::abs(pdgCode) == kXiMinus) { + registry.fill(HIST("QAhisto/Xi/hqaCascRadiusbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Xi/hqaCasccosPAbefore"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqaCascV0cosPAbefore"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0toPVbefore"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascdaubefore"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + } + if (std::abs(pdgCode) == kOmegaMinus) { + registry.fill(HIST("QAhisto/Omega/hqaCascRadiusbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Omega/hqaCasccosPAbefore"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqaCascV0cosPAbefore"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0toPVbefore"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascBachtoPVbefore"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascdaubefore"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0daubefore"), casc.dcaV0daughters()); + } + } + // track quality check + if (!bachelor.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!posdau.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!negdau.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!bachelor.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!posdau.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!negdau.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!bachelor.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (!posdau.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (!negdau.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (trkQualityOpts.cfgCheckGlobalTrack.value) { + if (!bachelor.hasTPC() || !bachelor.hasITS()) + continue; + if (!posdau.hasTPC() || !posdau.hasITS()) + continue; + if (!negdau.hasTPC() || !negdau.hasITS()) + continue; + } + // // topological cut + if (casc.cascradius() < cascBuilderOpts.cfgcasc_radius.value) + continue; + if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascBuilderOpts.cfgcasc_casccospa.value) + continue; + if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascBuilderOpts.cfgcasc_v0cospa.value) + continue; + if (std::fabs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascBuilderOpts.cfgcasc_dcav0topv.value) + continue; + if (std::fabs(casc.dcabachtopv()) < cascBuilderOpts.cfgcasc_dcabachtopv.value) + continue; + if (casc.dcacascdaughters() > cascBuilderOpts.cfgcasc_dcacascdau.value) + continue; + if (casc.dcaV0daughters() > cascBuilderOpts.cfgcasc_dcav0dau.value) + continue; + if (std::fabs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascBuilderOpts.cfgcasc_mlambdawindow.value) + continue; + // Omega and antiOmega + 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 && + (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()); + } + // fill QA + if (cfgOutputQA) { + registry.fill(HIST("QAhisto/Omega/hqaCascRadiusafter"), casc.cascradius()); + registry.fill(HIST("QAhisto/Omega/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + } + fGFW->Fill(cascEta, fOmegaPtAxis->FindBin(cascPt) - 1, cascPhi, wacc * weff * wloc, 4); + } else if (casc.sign() > 0 && std::fabs(casc.yOmega()) < cfgCasc_rapidity && + (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()); + } + // fill QA + if (cfgOutputQA) { + registry.fill(HIST("QAhisto/Omega/hqaCascRadiusafter"), casc.cascradius()); + registry.fill(HIST("QAhisto/Omega/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Omega/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Omega/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + } + fGFW->Fill(cascEta, fOmegaPtAxis->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 && + (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()); + } + // fill QA + if (cfgOutputQA) { + registry.fill(HIST("QAhisto/Xi/hqaCascRadiusafter"), casc.cascradius()); + registry.fill(HIST("QAhisto/Xi/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + } + fGFW->Fill(cascEta, fXiPtAxis->FindBin(cascPt) - 1, cascPhi, wacc * weff * wloc, 2); + } else if (casc.sign() > 0 && std::fabs(casc.yXi()) < cfgCasc_rapidity && + (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()); + } + if (cfgOutputQA) { + registry.fill(HIST("QAhisto/Xi/hqaCascRadiusafter"), casc.cascradius()); + registry.fill(HIST("QAhisto/Xi/hqaCasccosPAafter"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqaCascV0cosPAafter"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0toPVafter"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("QAhisto/Xi/hqadcaCascBachtoPVafter"), casc.dcabachtopv()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascdauafter"), casc.dcacascdaughters()); + registry.fill(HIST("QAhisto/Xi/hqadcaCascV0dauafter"), casc.dcaV0daughters()); + } + 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(); + + if (v0posdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || v0posdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + if (v0negdau.pt() < trkQualityOpts.cfgCutPtDauMin.value || v0negdau.pt() > trkQualityOpts.cfgCutPtDauMax.value) + continue; + + // fill QA before cut + if (cfgOutputQA) { + 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.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!v0negdau.passedITSNCls() && trkQualityOpts.cfgCheckITSNCls.value) + continue; + if (!v0posdau.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!v0negdau.passedITSHits() && trkQualityOpts.cfgCheckITSHits.value) + continue; + if (!v0posdau.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (!v0negdau.passedITSChi2NDF() && trkQualityOpts.cfgCheckITSChi2NDF.value) + continue; + if (trkQualityOpts.cfgCheckGlobalTrack.value) { + if (!v0posdau.hasTPC() || !v0posdau.hasITS()) + continue; + if (!v0negdau.hasTPC() || !v0negdau.hasITS()) + continue; + } + // topological cut + if (v0.v0radius() < v0BuilderOpts.cfgv0_radius.value) + continue; + if (v0.v0cosPA() < v0BuilderOpts.cfgv0_v0cospa.value) + continue; + if (v0.dcaV0daughters() > v0BuilderOpts.cfgv0_dcav0dau.value) + continue; + if (std::fabs(v0.dcapostopv()) < v0BuilderOpts.cfgv0_dcadautopv.value) + continue; + if (std::fabs(v0.dcanegtopv()) < v0BuilderOpts.cfgv0_dcadautopv.value) + continue; + // fill QA after cut + if (cfgOutputQA) { + 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()) > v0BuilderOpts.cfgv0_ArmPodocut.value && + std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0BuilderOpts.cfgv0_mk0swindow.value && + (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, fK0sPtAxis->FindBin(v0Pt) - 1, v0Phi, wacc * weff * wloc, 8); + } + } + // Lambda and antiLambda + if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < v0BuilderOpts.cfgv0_mlambdawindow.value && + (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, fLambdaPtAxis->FindBin(v0Pt) - 1, v0Phi, wacc * weff * wloc, 16); + } + } else if (std::fabs(v0.mLambda() - o2::constants::physics::MassLambda) < v0BuilderOpts.cfgv0_mlambdawindow.value && + (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, fLambdaPtAxis->FindBin(v0Pt) - 1, v0Phi, wacc * weff * wloc, 16); + } + } + } + delete hLocalDensity; + fillProfile(corrconfigs.at(20), HIST("c22"), cent); + fillProfile(corrconfigs.at(31), HIST("c32"), cent); + for (int i = 1; i <= nK0sPtBins; i++) { + fillProfilepTMass(corrconfigs.at(12), HIST("K0sc22dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(13), HIST("K0sc22dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(27), HIST("K0sc32dpt"), i, kK0Short, cent); + fillProfilepTMass(corrconfigs.at(28), HIST("K0sc32dpt"), i, kK0Short, cent); + } + for (int i = 1; i <= nLambdaPtBins; i++) { + fillProfilepTMass(corrconfigs.at(16), HIST("Lambdac22dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(17), HIST("Lambdac22dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(29), HIST("Lambdac32dpt"), i, kLambda0, cent); + fillProfilepTMass(corrconfigs.at(30), HIST("Lambdac32dpt"), i, kLambda0, cent); + } + for (int i = 1; i <= nXiPtBins; i++) { + fillProfilepTMass(corrconfigs.at(4), HIST("Xic22dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(5), HIST("Xic22dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(23), HIST("Xic32dpt"), i, kXiMinus, cent); + fillProfilepTMass(corrconfigs.at(24), HIST("Xic32dpt"), i, kXiMinus, cent); + } + for (int i = 1; i <= nOmegaPtBins; i++) { + fillProfilepTMass(corrconfigs.at(8), HIST("Omegac22dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(9), HIST("Omegac22dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(25), HIST("Omegac32dpt"), i, kOmegaMinus, cent); + fillProfilepTMass(corrconfigs.at(26), HIST("Omegac32dpt"), 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..4190e2d1740 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowGfwTask.cxx @@ -0,0 +1,1361 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "FlowContainer.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +#include "TList.h" +#include "TPDGCode.h" +#include +#include +#include + +#include +#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, 50.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCCrossedRows, float, 70.0f, "minimum TPC crossed rows") + 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(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.0f, "Custom DCA Z cut") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + 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(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgEfficiencyPt, 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(cfgDCAzPt, bool, false, "switch for DCAz pt dependent") + O2_DEFINE_CONFIGURABLE(cfgTrackSelRun3ITSMatch, bool, false, "Track selection for ITS matches") + 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(cfgOccupancy, bool, false, "Bool for event selection on detector occupancy"); + 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(cfgMultCut, bool, false, "Use additional event cut on mult correlations"); + O2_DEFINE_CONFIGURABLE(cfgV0AT0ANSigma, bool, false, "V0A T0A n sigma cut") + O2_DEFINE_CONFIGURABLE(cfgNSigma, float, 5.0f, "N sigma cut") + O2_DEFINE_CONFIGURABLE(cfgGlobalTracks, bool, false, "Global tracks") + 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") + + 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, + kc34etagap, + kc22Nch, + kc24Nch, + kc26Nch, + kc28Nch, + kc22Nchetagap, + kc32Nch, + kc32Nchetagap, + kc34Nch, + kc34Nchetagap, + kc22Nch05, + kc24Nch05, + kc26Nch05, + kc28Nch05, + kc22Nch05etagap, + kc32Nch05, + kc32Nch05etagap, + kc34Nch05, + kc34Nch05etagap, + kc22ft0c, + kc22etagapft0c, + kc32ft0c, + kc32etagapft0c, + kc34ft0c, + kc34etagapft0c, + + // 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("GlobalTracks", "Global Tracks;Centrality FT0C;Nch", {HistType::kTH2D, {axisCentrality, axisNch}}); + 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("c34etagap", ";Centrality (%) ; C_{3}{4} (|#eta| < 0.8) ", {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("c34Nchetagap", ";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}}); + registry.add("c34Nch05etagap", ";N_{ch 0-5%}(|#eta| < 0.8) ; C_{3}{4} ", {HistType::kTProfile, {axisNch}}); + + registry.add("c22ft0c", ";FT0C Amplitude ; C_{2}{2} ", {HistType::kTProfile, {axisFT0CAmp}}); + registry.add("c22etagapft0c", ";FT0C Amplitude ; C_{2}{2} (|#eta| < 0.8) ", {HistType::kTProfile, {axisFT0CAmp}}); + registry.add("c32ft0c", ";FT0C Amplitude ; C_{2}{2} ", {HistType::kTProfile, {axisFT0CAmp}}); + registry.add("c32etagapft0c", ";FT0C Amplitude ; C_{3}{2} (|#eta| < 0.8) ", {HistType::kTProfile, {axisFT0CAmp}}); + registry.add("c34ft0c", ";FT0C Amplitude ; C_{3}{4} ", {HistType::kTProfile, {axisFT0CAmp}}); + registry.add("c34etagapft0c", ";FT0C Amplitude ; C_{3}{4} (|#eta| < 0.8) ", {HistType::kTProfile, {axisFT0CAmp}}); + } // 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][kc34etagap] = registry.add(Form("BootstrapContainer_%d/c34etagap", i), ";Centrality (%) ; C_{3}{4} (|#eta| < 0.8)", {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][kc34Nchetagap] = registry.add(Form("BootstrapContainer_%d/c34Nchetagap", i), ";N_ch(|#eta| < 0.8) ; C_{3}{4} (|#eta| < 0.8)", {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}}); + bootstrapArray[i][kc34Nch05etagap] = registry.add(Form("BootstrapContainer_%d/c34Nch05etagap", i), ";N_ch05(|#eta| < 0.8) ; C_{3}{4} (|#eta| < 0.8)", {HistType::kTProfile, {axisNch}}); + + bootstrapArray[i][kc22ft0c] = registry.add(Form("BootstrapContainer_%d/c22ftoc", i), ";FT0C Amplitude ; C_{2}{2}", {HistType::kTProfile, {axisFT0CAmp}}); + bootstrapArray[i][kc22etagapft0c] = registry.add(Form("BootstrapContainer_%d/c22etagapftoc", i), ";FT0C Amplitude ; C_{2}{2} (|#eta| < 0.8)", {HistType::kTProfile, {axisFT0CAmp}}); + bootstrapArray[i][kc32ft0c] = registry.add(Form("BootstrapContainer_%d/c32ftoc", i), ";FT0C Amplitude ; C_{3}{2}", {HistType::kTProfile, {axisFT0CAmp}}); + bootstrapArray[i][kc32etagapft0c] = registry.add(Form("BootstrapContainer_%d/c32etagapftoc", i), ";FT0C Amplitude ; C_{3}{2} (|#eta| < 0.8)", {HistType::kTProfile, {axisFT0CAmp}}); + bootstrapArray[i][kc34ft0c] = registry.add(Form("BootstrapContainer_%d/c34ftoc", i), ";FT0C Amplitude ; C_{3}{4}", {HistType::kTProfile, {axisFT0CAmp}}); + bootstrapArray[i][kc34etagapft0c] = registry.add(Form("BootstrapContainer_%d/c34ftocetagap", i), ";FT0C Amplitude ; C_{3}{4} (|#eta| < 0.8)", {HistType::kTProfile, {axisFT0CAmp}}); + } + + 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)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN10 {3 3} refP10 {-3 -3}", "Ch10Gap34", 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 (cfgEfficiencyPt.value.empty() == false) { + mEfficiency = ccdb->getForTimeStamp(cfgEfficiencyPt, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load Pt efficiency histogram for trigger particles from %s", cfgEfficiencyPt.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiencyPt.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, zResmin = 0.25, maxContrib = 20; + if (collision.numContrib() > 1) { + vtxz = collision.posZ(); + float zRes = std::sqrt(collision.covZZ()); + if (zRes > zResmin && collision.numContrib() < maxContrib) + 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 N sigma cut + if (cfgV0AT0ANSigma) { + if (std::abs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > cfgNSigma * 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 if (cfgGlobalTracks) { + return ((track.tpcNClsFound() >= cfgCutTPCclu) && (track.tpcNClsCrossedRows() >= cfgCutTPCCrossedRows) && (track.itsNCls() >= cfgCutITSclu)); + } else { + return false; + } + } + + // Apply process filters GlobalTracks + 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); + + // Draft notation for centrality limits + float zero = 0, five = 5, ten = 10, twenty = 20, thirty = 30; + if (centrality >= zero && centrality <= five) { + registry.fill(HIST("ZNvsZEMcoll05"), aZEM1 + aZEM2, aZNA + aZNC); + } else if (centrality > five && centrality <= ten) { + registry.fill(HIST("ZNvsZEMcoll510"), aZEM1 + aZEM2, aZNA + aZNC); + } else if (centrality > ten && centrality <= twenty) { + registry.fill(HIST("ZNvsZEMcoll1020"), aZEM1 + aZEM2, aZNA + aZNC); + } else if (centrality > twenty && centrality <= thirty) { + registry.fill(HIST("ZNvsZEMcoll2030"), aZEM1 + aZEM2, aZNA + aZNC); + } else { + registry.fill(HIST("ZNvsZEMcollrest"), aZEM1 + aZEM2, aZNA + aZNC); + } + } // End of ZDC + + // Use for c22 vs ft0 amplitude + double ft0cAmp = 0; + if (foundBC.has_ft0()) { + for (const auto& amplitude : foundBC.ft0().amplitudeC()) { + ft0cAmp += amplitude; + } + } + + 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 (cfgGlobalTracks) { + if (withinPtRef) { + registry.fill(HIST("GlobalTracks"), centrality, nch); + fGFW->Fill(track.eta(), fPtAxis->FindBin(track.pt()) - 1, track.phi(), wacc * weff, 1); + } + } + + 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); + } + } + } + + } // 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 Cumulants 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(8), HIST("c34etagap"), 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); + fillProfile(corrconfigs.at(8), HIST("c34Nchetagap"), nch); + + // 0-5% centrality Nch + float zero = 0, five = 5; + if (centrality >= zero && centrality <= five) { + 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); + fillProfile(corrconfigs.at(8), HIST("c34Nch05etagap"), nch); + } + + // C22, C32 and C34 vs FT0C amplitude + fillProfile(corrconfigs.at(0), HIST("c22ft0c"), ft0cAmp); + fillProfile(corrconfigs.at(4), HIST("c22etagapft0c"), ft0cAmp); + fillProfile(corrconfigs.at(5), HIST("c32ft0c"), ft0cAmp); + fillProfile(corrconfigs.at(6), HIST("c32etagapft0c"), ft0cAmp); + fillProfile(corrconfigs.at(7), HIST("c34ft0c"), ft0cAmp); + fillProfile(corrconfigs.at(8), HIST("c34etagapft0c"), ft0cAmp); + + // 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(8), bootstrapArray[sampleIndex][kc34etagap], 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); + fillProfile(corrconfigs.at(8), bootstrapArray[sampleIndex][kc34Nchetagap], nch); + + if (centrality >= zero && centrality <= five) { + 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); + fillProfile(corrconfigs.at(8), bootstrapArray[sampleIndex][kc34Nch05etagap], nch); + + registry.fill(HIST("Nch05"), nch); + } + + registry.fill(HIST("Nch"), nch); + + // Filling Bootstrap Samples for FT0C Amplitudes + fillProfile(corrconfigs.at(0), bootstrapArray[sampleIndex][kc22ft0c], ft0cAmp); + fillProfile(corrconfigs.at(4), bootstrapArray[sampleIndex][kc22etagapft0c], ft0cAmp); + fillProfile(corrconfigs.at(5), bootstrapArray[sampleIndex][kc32ft0c], ft0cAmp); + fillProfile(corrconfigs.at(6), bootstrapArray[sampleIndex][kc32etagapft0c], ft0cAmp); + fillProfile(corrconfigs.at(7), bootstrapArray[sampleIndex][kc34ft0c], ft0cAmp); + fillProfile(corrconfigs.at(8), bootstrapArray[sampleIndex][kc34etagapft0c], ft0cAmp); + + // 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()); + + float zero = 0, five = 5; + if (centrality >= zero && centrality <= five) { + 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); + + float zero = 0, five = 5; + if (centrality >= zero && centrality <= five) { + 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()); + float zero = 0, five = 5; + if (centrality >= zero && centrality <= five) { + 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..ea3223dc153 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowMc.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 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(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal 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(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, 50.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, float, 5.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC 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(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); + O2_DEFINE_CONFIGURABLE(cfgDCAxyFunction, std::string, "(0.0015+0.005/(x^1.1))", "Functional form of pt-dependent DCAxy cut"); + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "DCAz cut for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutDCAzPtDepEnabled, bool, false, "switch of DCAz pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgEnableITSCuts, bool, true, "switch of enabling ITS based track selection cuts") + O2_DEFINE_CONFIGURABLE(cfgTrkSelRun3ITSMatch, bool, false, "GlobalTrackRun3ITSMatching::Run3ITSall7Layers selection") + 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") + O2_DEFINE_CONFIGURABLE(cfgRecoEvRejectMC, bool, false, "reject both MC and Reco events when reco do not pass") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSel8, bool, false, "require sel8 for reconstruction events") + O2_DEFINE_CONFIGURABLE(cfgRecoEvkIsGoodITSLayersAll, bool, false, "require kIsGoodITSLayersAll for reconstruction events") + O2_DEFINE_CONFIGURABLE(cfgRecoEvkNoSameBunchPileup, bool, false, "require kNoSameBunchPileup for reconstruction events") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkIsGoodZvtxFT0vsPV, 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(cfgRecoEvSelkNoITSROFrameBorder, bool, false, "reject events at ITS ROF border") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoTimeFrameBorder, bool, false, "reject events at TF border") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoCollInTimeRangeStandard, bool, false, "no collisions in specified time range") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoCollInRofStandard, bool, false, "no other collisions in this Readout Frame with per-collision multiplicity above threshold") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoHighMultCollInPrevRof, bool, false, "veto an event if FT0C amplitude in previous ITS ROF is above threshold") + + 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"}; + + // Filter for MCcollisions + Filter mccollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; + using FilteredMcCollisions = soa::Filtered; + // Filter for MCParticle + Filter particleFilter = (nabs(aod::mcparticle::eta) < cfgCutEta) && (aod::mcparticle::pt > cfgCutPtMin) && (aod::mcparticle::pt < cfgCutPtMax); + using FilteredMcParticles = soa::Filtered>; + // Filter for reco tracks + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); + using FilteredTracks = soa::Filtered>; + + // using FilteredTracks = soa::Join; + + // Additional filters for tracks + TrackSelection myTrackSel; + TF1* fPtDepDCAxy = nullptr; + + // 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 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); + double epsilon = 1e-6; + + void init(InitContext&) + { + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + const AxisSpec axisVertex{20, -10, 10, "Vtxz (cm)"}; + const AxisSpec axisEta{20, -1., 1., "#eta"}; + const AxisSpec axisCounter{1, 0, +1, ""}; + // QA histograms + histos.add("mcEventCounter", "Monte Carlo Truth EventCounter", HistType::kTH1F, {axisCounter}); + histos.add("numberOfRecoCollisions", "numberOfRecoCollisions", HistType::kTH1F, {{10, -0.5f, 9.5f}}); + histos.add("RecoEventCounter", "Reconstruction EventCounter", HistType::kTH1F, {axisCounter}); + 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("hEtaPtVtxzMCGen", "Monte Carlo Truth; #eta; p_{T} (GeV/c); V_{z} (cm);", {HistType::kTH3D, {axisEta, axisPt, axisVertex}}); + histos.add("hPtMCGlobal", "Monte Carlo Global; pT (GeV/c);", {HistType::kTH1D, {axisPt}}); + histos.add("hEtaPtVtxzMCGlobal", "Monte Carlo Global; #eta; p_{T} (GeV/c); V_{z} (cm);", {HistType::kTH3D, {axisEta, axisPt, axisVertex}}); + 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 (cfgEnableITSCuts) { + if (cfgTrkSelRun3ITSMatch) { + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + } else { + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + } + } + if (cfgCutDCAxy != 0.0) { + myTrackSel.SetMaxDcaXY(cfgCutDCAxy); + } else { + fPtDepDCAxy = new TF1("ptDepDCAxy", Form("[0]*%s", cfgDCAxyFunction->c_str()), 0.001, 100); + fPtDepDCAxy->SetParameter(0, cfgDCAxyNSigma); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", cfgDCAxyFunction->c_str())); + myTrackSel.SetMaxDcaXYPtDep([fPtDepDCAxy = this->fPtDepDCAxy](float pt) { return fPtDepDCAxy->Eval(pt); }); + } + myTrackSel.SetMinNClustersTPC(cfgCutTPCclu); + myTrackSel.SetMinNCrossedRowsTPC(cfgCutTPCcrossedrows); + if (cfgEnableITSCuts) + myTrackSel.SetMinNClustersITS(cfgCutITSclu); + if (!cfgCutDCAzPtDepEnabled) + myTrackSel.SetMaxDcaZ(cfgCutDCAz); + + 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"); + } + } + + template + bool eventSelected(TCollision collision) + { + if (std::fabs(collision.posZ()) > cfgCutVertex) { + return 0; + } + if (cfgRecoEvSel8 && !collision.sel8()) { + return 0; + } + if (cfgRecoEvkNoSameBunchPileup && !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 (cfgRecoEvkIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // from Jan 9 2025 AOT meeting + // cut time intervals with dead ITS staves + return 0; + } + if (cfgRecoEvSelkIsGoodZvtxFT0vsPV && !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 (cfgRecoEvSelkNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return 0; + } + if (cfgRecoEvSelkNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return 0; + } + if (cfgRecoEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (cfgRecoEvSelkNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + // no other collisions in this Readout Frame with per-collision multiplicity above threshold + return 0; + } + if (cfgRecoEvSelkNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + // veto an event if FT0C amplitude in previous ITS ROF is above threshold + return 0; + } + return 1; + } + + template + bool trackSelected(TTrack track) + { + if (cfgCutDCAzPtDepEnabled && (track.dcaZ() > (0.004f + 0.013f / track.pt()))) { + return false; + } + return myTrackSel.IsSelected(track); + } + + void process(FilteredMcCollisions::iterator const& mcCollision, aod::BCsWithTimestamps const&, soa::SmallGroups> const& collisions, FilteredMcParticles const& mcParticles, FilteredTracks 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 (collisions.size() > -1) { + histos.fill(HIST("mcEventCounter"), 0.5); + histos.fill(HIST("numberOfRecoCollisions"), collisions.size()); // number of times coll was reco-ed + if (cfgRecoEvRejectMC) { + if (collisions.size() != 1) { // only pass those have one reconstruction event + return; + } + for (auto const& collision : collisions) { + if (!eventSelected(collision)) + return; + } + } + histos.fill(HIST("RecoEventCounter"), 0.5); + } + + 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 (!trackSelected(track)) { + 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()); + histos.fill(HIST("hEtaPtVtxzMCGen"), mcParticle.eta(), mcParticle.pt(), vtxz); + 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 (!trackSelected(track)) { + 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() > -1. * epsilon) { + validITSTrack = true; + } + if (track.hasITS() && track.itsChi2NCl() < -1. * epsilon) { + 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()); + histos.fill(HIST("hEtaPtVtxzMCGlobal"), mcParticle.eta(), mcParticle.pt(), vtxz); + 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..12809169eb8 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowPbpbPikp.cxx @@ -0,0 +1,1029 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGCF/GenericFramework/Core/FlowContainer.h" +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWConfig.h" +#include "PWGCF/GenericFramework/Core/GFWCumulant.h" +#include "PWGCF/GenericFramework/Core/GFWPowerArray.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" +#include "PWGCF/GenericFramework/Core/GFWWeightsList.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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include "Math/Vector4D.h" +#include +#include +#include + +#include +#include +#include +#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}; + +namespace o2::analysis::genericframework +{ +GFWRegions regions; +GFWCorrConfigs configs; +} // namespace o2::analysis::genericframework + +using namespace o2::analysis::genericframework; + +struct FlowPbpbPikp { + o2::aod::ITSResponse itsResponse; + 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(cfgTpcCrossRows, int, 70, "Number of TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + 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(cfgTpcCut, 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(cfgCutOccupancyMin, int, 0, "Minimum occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyMax, int, 2000, "Maximum occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgUseGlobalTrack, bool, true, "use Global track") + O2_DEFINE_CONFIGURABLE(cfgITScluster, int, 5, "Number of ITS cluster") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrUse, bool, false, "Use track density efficiency correction") + + O2_DEFINE_CONFIGURABLE(cfgUseWeightPhiEtaVtxz, bool, false, "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, true, "Use Phi, Eta, Pt dependent NUA weights") + O2_DEFINE_CONFIGURABLE(cfgUseStrictPID, bool, true, "Use strict PID cuts for TPC") + O2_DEFINE_CONFIGURABLE(cfgV0AT0Acut, int, 5, "V0AT0A cut") + O2_DEFINE_CONFIGURABLE(cfgUseAsymmetricPID, bool, false, "Use asymmetric PID cuts") + O2_DEFINE_CONFIGURABLE(cfgUseItsPID, bool, true, "Use ITS PID for particle identification") + O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, true, "Use Nch for multiplicity selection instead of centrality") + + 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"}; + Configurable> cfgTofNsigmaCut{"cfgTofNsigmaCut", std::vector{1.5, 1.5, 1.5, -1.5, -1.5, -1.5}, "TOF n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable> cfgItsNsigmaCut{"cfgItsNsigmaCut", std::vector{3, 3, 3, -3, -3, -3}, "ITS n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable> cfgTpcNsigmaCut{"cfgTpcNsigmaCut", std::vector{10, 10, 10, -10, -10, -10}, "TOF n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable> cfgUseEventCuts{"cfgUseEventCuts", std::vector{1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, "Switch for various event cuts [Filtered Events, Sel8, kNoTimeFrameBorder, kNoITSROFrameBorder, kNoSameBunchPileup, kIsGoodZvtxFT0vsPV, kNoCollInTimeRangeStandard, kIsGoodITSLayersAll, kNoCollInRofStandard, kNoHighMultCollInPrevRof, Occupancy, Multiplicity correlation, T0AV0A 3 sigma cut, kIsVertexITSTPC, kTVXinTRD]"}; + + Configurable cfgRegions{"cfgRegions", {{"refN08", "refP08", "full", "poiN", "olN", "poiP", "olP", "poi", "ol", "poiNpi", "olNpi", "poiPpi", "olPpi", "poifullpi", "olfullpi", "poiNka", "olNka", "poiPka", "olPka", "poifullka", "olfullka", "poiNpr", "olNpr", "poiPpr", "olPpr", "poifullpr", "olfullpr"}, {-0.8, 0.4, -0.8, -0.8, -0.8, 0.4, 0.4, -0.8, -0.8, -0.8, -0.8, 0.4, 0.4, -0.8, -0.8, -0.8, -0.8, 0.4, 0.4, -0.8, -0.8, -0.8, -0.8, 0.4, 0.4, -0.8, -0.8}, {-0.4, 0.8, 0.8, -0.4, -0.4, 0.8, 0.8, 0.8, 0.8, -0.4, -0.4, 0.8, 0.8, 0.8, 0.8, -0.4, -0.4, 0.8, 0.8, 0.8, 0.8, -0.4, -0.4, 0.8, 0.8, 0.8, 0.8}, {0, 0, 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}, {1, 1, 1, 128, 256, 128, 256, 128, 256, 2, 16, 2, 16, 2, 16, 4, 32, 4, 32, 4, 32, 8, 64, 8, 64, 8, 64}}, "Configurations for GFW regions"}; + Configurable cfgCorrConfig{"cfgCorrConfig", {{"full {2 -2}", "full {2 -2}", "full {2 -2}", "full {2 -2}", "refN08 {2} refP08 {-2}", "refN08 {2} refP08 {-2}", "refN08 {2} refP08 {-2}", "refN08 {2} refP08 {-2}", "refP08 {-2} refN08 {2}", "refP08 {-2} refN08 {2}", "refP08 {-2} refN08 {2}", "refP08 {-2} refN08 {2}", "full {2 2 -2 -2}", "full {2 2 -2 -2}", "full {2 2 -2 -2}", "full {2 2 -2 -2}", "poi full | ol {2 -2}", "poifullpi full | olfullpi {2 -2}", "poifullka full | olfullka {2 -2}", "poifullpr full | olfullpr {2 -2}", "poiN refN08 | olN {2} refP08 {-2}", "poiNpi refN08 | olNpi {2} refP08 {-2}", "poiNka refN08 | olNka {2} refP08 {-2}", "poiNpr refN08 | olNpr {2} refP08 {-2}", "poiP refP08 | olP {2} refN08 {-2}", "poiPpi refP08 | olPpi {2} refN08 {-2}", "poiPka refP08 | olPka {2} refN08 {-2}", "poiPpr refP08 | olPpr {2} refN08 {-2}", "poi full | ol {2 2 -2 -2}", "poifullpi full | olfullpi {2 2 -2 -2}", "poifullka full | olfullka {2 2 -2 -2}", "poifullpr full | olfullpr {2 2 -2 -2}", "refN08 {2 2} refP08 {-2 -2}", "refP08 {-2 -2} refN08 {2 2}", "poiNka refN08 | olNka {2 2} refP08 {-2 -2}", "poiPka refP08 | olPka {2 2} refN08 {-2 -2}"}, {"ChFull22", "PiFull22", "KaFull22", "PrFull22", "Ch08FGap22", "Pi08FGap22", "Ka08FGap22", "Pr08FGap22", "Ch08BGap22", "Pi08BGap22", "Ka08BGap22", "Pr08BGap22", "ChFull24", "PiFull24", "KaFull24", "PrFull24", "ChFull22", "PiFull22", "KaFull22", "PrFull22", "Ch08FGap22", "Pi08FGap22", "Ka08FGap22", "Pr08FGap22", "Ch08BGap22", "Pi08BGap22", "Ka08BGap22", "Pr08BGap22", "ChFull24", "PiFull24", "KaFull24", "PrFull24", "Ka08FGap24", "Ka08BGap24", "Ka08FGap24", "Ka08BGap24"}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 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}}, "Configurations for each correlation to calculate"}; + + 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", {16, -0.8, 0.8}, "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 axisNsigmaITS{"axisNsigmaITS", {80, -5, 5}, "nsigmaITS axis"}; + ConfigurableAxis axisParticles{"axisParticles", {3, 0, 3}, "axis for different hadrons"}; + ConfigurableAxis axisTPCsignal{"axisTPCsignal", {10000, 0, 1000}, "axis for TPC signal"}; + ConfigurableAxis axisTOFbeta{"axisTOFbeta", {200, 0, 2}, "axis for TOF beta"}; + ConfigurableAxis axisNch{"axisNch", {200, 2000, 4000}, "N_{ch}"}; + + std::vector tofNsigmaCut; + std::vector itsNsigmaCut; + std::vector tpcNsigmaCut; + std::vector eventCuts; + + 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 + }; + + enum EventCutTypes { + kFilteredEvents = 0, + kAfterSel8, + kUseNoTimeFrameBorder, + kUseNoITSROFrameBorder, + kUseNoSameBunchPileup, + kUseGoodZvtxFT0vsPV, + kUseNoCollInTimeRangeStandard, + kUseGoodITSLayersAll, + kUseNoCollInRofStandard, + kUseNoHighMultCollInPrevRof, + kUseOccupancy, + kUseMultCorrCut, + kUseT0AV0ACut, + kUseVertexITSTPC, + kUseTVXinTRD + }; + + enum TrackCutTypes { + kFilteredTracks = 0, + kUseGlobalTracks, + kUsePvContributor, + kItsClustersCut, + kHasTpcSignal, + kTpcClustersCut, + kTpcCrossedRowsCut, + kNumPions, + kNumKaons, + kNumProtons + }; + + int lastRunNumer = -1; + std::vector runNumbers; + std::vector mAcceptance; + bool correctionsLoaded = false; + + // Local track density correction - Copy from flowTask.cxx + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + + // 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&) + { + eventCuts = cfgUseEventCuts; + + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(noLaterThan.value); + + LOGF(info, "flowGenericFramework::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(); + + const AxisSpec axisCentForQA{100, 0, 100, "centrality (%)"}; + + 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_full_ch", "", {HistType::kTProfile, {axisMultiplicity}}); + histos.add("c22_full_ch_Nch", "", {HistType::kTProfile, {axisNch}}); + + histos.add("TpcdEdx", "", {HistType::kTH2D, {axisPt, axisTPCsignal}}); + histos.add("TofBeta", "", {HistType::kTH2D, {axisPt, axisTOFbeta}}); + + histos.add("globalTracks_centT0C", "after cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + + histos.add("TofTpcNsigma_before", "", {HistType::kTHnSparseD, {{axisParticles, axisNsigmaTPC, axisNsigmaTOF, axisPt}}}); + if (!cfgUseItsPID) + histos.add("TofTpcNsigma_after", "", {HistType::kTHnSparseD, {{axisParticles, axisNsigmaTPC, axisNsigmaTOF, axisPt}}}); + + histos.add("TofItsNsigma_before", "", {HistType::kTHnSparseD, {{axisParticles, axisNsigmaITS, axisNsigmaTOF, axisPt}}}); + if (cfgUseItsPID) + histos.add("TofItsNsigma_after", "", {HistType::kTHnSparseD, {{axisParticles, axisNsigmaITS, axisNsigmaTOF, axisPt}}}); + + histos.add("partCount", "", {HistType::kTHnSparseD, {{axisParticles, axisMultiplicity, axisPt}}}); + + histos.add("hEventCount", "Number of Events;; Count", {HistType::kTH1D, {{15, -0.5, 14.5}}}); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kFilteredEvents + 1, "Filtered event"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kAfterSel8 + 1, "After sel8"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoTimeFrameBorder + 1, "kNoTimeFrameBorder"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoITSROFrameBorder + 1, "kNoITSROFrameBorder"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoSameBunchPileup + 1, "kNoSameBunchPileup"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoCollInRofStandard + 1, "kNoCollInTimeRangeStandard"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseGoodITSLayersAll + 1, "kIsGoodITSLayersAll"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoCollInRofStandard + 1, "kNoCollInRofStandard"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoHighMultCollInPrevRof + 1, "kNoHighMultCollInPrevRof"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseOccupancy + 1, "Occupancy Cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseMultCorrCut + 1, "Multiplicity correlation Cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseT0AV0ACut + 1, "T0AV0A cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseVertexITSTPC + 1, "kIsVertexITSTPC"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseTVXinTRD + 1, "kTVXinTRD"); + + histos.add("hTrackCount", "Number of Tracks;; Count", {HistType::kTH1D, {{10, -0.5, 9.5}}}); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kFilteredTracks + 1, "Filtered track"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kUseGlobalTracks + 1, "Global tracks"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kUsePvContributor + 1, "PV contributor"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kItsClustersCut + 1, "ITS clusters"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kHasTpcSignal + 1, "TPC signal"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kTpcClustersCut + 1, "TPC clusters"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kTpcCrossedRowsCut + 1, "TPC crossed rows"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kNumPions + 1, "Pions"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kNumKaons + 1, "Kaons"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kNumProtons + 1, "Protons"); + + if (cfgOutputNUAWeights && !cfgOutputRunByRun) { + histos.add("NUA/hPhiEtaVtxz_ref", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + histos.add("NUA/hPhiEtaVtxz_ch", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + histos.add("NUA/hPhiEtaVtxz_pi", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + histos.add("NUA/hPhiEtaVtxz_ka", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + histos.add("NUA/hPhiEtaVtxz_pr", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + + histos.add("NUA/hPhiPtCent_ref", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, axisMultiplicity}}); + histos.add("NUA/hPhiPtCent_ch", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, axisMultiplicity}}); + histos.add("NUA/hPhiPtCent_pi", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, axisMultiplicity}}); + histos.add("NUA/hPhiPtCent_ka", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, axisMultiplicity}}); + histos.add("NUA/hPhiPtCent_pr", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, axisMultiplicity}}); + + histos.add("NUA/hPhiEtaPt_ref", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, axisEta, axisPt}}); + histos.add("NUA/hPhiEtaPt_ch", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, axisEta, axisPt}}); + histos.add("NUA/hPhiEtaPt_pi", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, axisEta, axisPt}}); + histos.add("NUA/hPhiEtaPt_ka", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, axisEta, axisPt}}); + histos.add("NUA/hPhiEtaPt_pr", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, axisEta, axisPt}}); + } + + if (!cfgAcceptance.value.empty()) { + if (cfgUseWeightPhiEtaVtxz) { + histos.add("PhiCorrected/hPhiEtaVtxz_pi_corrd", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + histos.add("PhiCorrected/hPhiEtaVtxz_ka_corrd", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + histos.add("PhiCorrected/hPhiEtaVtxz_pr_corrd", ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + } + if (cfgUseWeightPhiPtCent) { + histos.add("PhiCorrected/hPhiPtCent_pi_corrd", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, axisMultiplicity}}); + histos.add("PhiCorrected/hPhiPtCent_ka_corrd", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, axisMultiplicity}}); + histos.add("PhiCorrected/hPhiPtCent_pr_corrd", ";#varphi;p_{T};Cent", {HistType::kTH3D, {axisPhi, axisPt, axisMultiplicity}}); + } + if (cfgUseWeightPhiEtaPt) { + histos.add("PhiCorrected/hPhiEtaPt_pi_corrd", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, axisEta, axisPt}}); + histos.add("PhiCorrected/hPhiEtaPt_ka_corrd", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, axisEta, axisPt}}); + histos.add("PhiCorrected/hPhiEtaPt_pr_corrd", ";#varphi;#eta;p_{T}", {HistType::kTH3D, {axisPhi, axisEta, axisPt}}); + } + } + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + // Defining the regions + for (auto i(0); i < regions.GetSize(); ++i) { + fGFW->AddRegion(regions.GetNames()[i], regions.GetEtaMin()[i], regions.GetEtaMax()[i], (regions.GetpTDifs()[i]) ? nPtBins + 1 : 1, regions.GetBitmasks()[i]); + } + + // Defining the correlators + 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(); + + // Defining the flow container + TObjArray* oba = new TObjArray(); + addConfigObjectsToObjArray(oba, corrconfigs); + + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fPtAxis); + + if (!cfgUseNch) { + fFC->Initialize(oba, axisMultiplicity, cfgNbootstrap); + } else { + fFC->Initialize(oba, axisNch, cfgNbootstrap); + } + + delete oba; + + if (eventCuts[kUseMultCorrCut]) { + 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); + } + if (eventCuts[kUseT0AV0ACut]) { + 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); + } + + tofNsigmaCut = cfgTofNsigmaCut; + itsNsigmaCut = cfgItsNsigmaCut; + tpcNsigmaCut = cfgTpcNsigmaCut; + } // End of init() + + enum Particles { + PIONS, + KAONS, + PROTONS + }; + + 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())); + } + } + } + + template + bool selectionTrack(const TTrack& track) + { + histos.fill(HIST("hTrackCount"), kFilteredTracks); // Filtered tracks + if (cfgUseGlobalTrack && !(track.isGlobalTrack())) { + return 0; + } + if (cfgUseGlobalTrack) + histos.fill(HIST("hTrackCount"), kUseGlobalTracks); // After global track selection + + if (!(track.isPVContributor())) { + return 0; + } + histos.fill(HIST("hTrackCount"), kUsePvContributor); // After PV contributor selection + + if (!(track.itsNCls() > cfgITScluster)) { + return 0; + } + histos.fill(HIST("hTrackCount"), kItsClustersCut); // After ITS cluster selection + + if (!(track.hasTPC())) { + return 0; + } + histos.fill(HIST("hTrackCount"), kHasTpcSignal); // If track has TPC signal + + if (!(track.tpcNClsFound() > cfgTpcCluster)) { + return 0; + } + histos.fill(HIST("hTrackCount"), kTpcClustersCut); // After TPC cluster selection + + if (!(track.tpcNClsCrossedRows() > cfgTpcCrossRows)) { + return 0; + } + histos.fill(HIST("hTrackCount"), kTpcCrossedRowsCut); // After TPC crossed rows selection + return 1; + } + + template + void fillQA(const TCollision collision, const TTrack track, int pidIndex, double wacc) + { + histos.fill(HIST("partCount"), pidIndex - 1, collision.centFT0C(), track.pt()); + switch (pidIndex) { + case 1: + if (!cfgUseItsPID) + histos.fill(HIST("TofTpcNsigma_after"), pidIndex - 1, track.tpcNSigmaPi(), track.tofNSigmaPi(), track.pt()); + if (cfgUseItsPID) + histos.fill(HIST("TofItsNsigma_after"), pidIndex - 1, itsResponse.nSigmaITS(track), track.tofNSigmaPi(), track.pt()); + histos.fill(HIST("hTrackCount"), kNumPions); // Pion count + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiEtaVtxz) + histos.fill(HIST("PhiCorrected/hPhiEtaVtxz_pi_corrd"), track.phi(), track.eta(), collision.posZ(), wacc); // pion weights + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiPtCent) + histos.fill(HIST("PhiCorrected/hPhiPtCent_pi_corrd"), track.phi(), track.pt(), collision.centFT0C(), wacc); + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiEtaPt) + histos.fill(HIST("PhiCorrected/hPhiEtaPt_pi_corrd"), track.phi(), track.eta(), track.pt(), wacc); + break; + case 2: + if (!cfgUseItsPID) + histos.fill(HIST("TofTpcNsigma_after"), pidIndex - 1, track.tpcNSigmaKa(), track.tofNSigmaKa(), track.pt()); + if (cfgUseItsPID) + histos.fill(HIST("TofItsNsigma_after"), pidIndex - 1, itsResponse.nSigmaITS(track), track.tofNSigmaKa(), track.pt()); + histos.fill(HIST("hTrackCount"), kNumKaons); // Kaon count + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiEtaVtxz) + histos.fill(HIST("PhiCorrected/hPhiEtaVtxz_ka_corrd"), track.phi(), track.eta(), collision.posZ(), wacc); // kaon weights + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiPtCent) + histos.fill(HIST("PhiCorrected/hPhiPtCent_ka_corrd"), track.phi(), track.pt(), collision.centFT0C(), wacc); + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiEtaPt) + histos.fill(HIST("PhiCorrected/hPhiEtaPt_ka_corrd"), track.phi(), track.eta(), track.pt(), wacc); + break; + case 3: + if (!cfgUseItsPID) + histos.fill(HIST("TofTpcNsigma_after"), pidIndex - 1, track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); + if (cfgUseItsPID) + histos.fill(HIST("TofItsNsigma_after"), pidIndex - 1, itsResponse.nSigmaITS(track), track.tofNSigmaPr(), track.pt()); + histos.fill(HIST("hTrackCount"), kNumProtons); // Proton count + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiEtaVtxz) + histos.fill(HIST("PhiCorrected/hPhiEtaVtxz_pr_corrd"), track.phi(), track.eta(), collision.posZ(), wacc); // proton weights + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiPtCent) + histos.fill(HIST("PhiCorrected/hPhiPtCent_pr_corrd"), track.phi(), track.pt(), collision.centFT0C(), wacc); + if (!cfgAcceptance.value.empty() && cfgUseWeightPhiEtaPt) + histos.fill(HIST("PhiCorrected/hPhiEtaPt_pr_corrd"), track.phi(), track.eta(), track.pt(), wacc); + break; + } // end of switch + } // end of fillQA + + template + int getNsigmaPIDTpcTof(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 = cfgTpcCut; + + // Choose which nSigma to use + std::array nSigmaToUse = (track.pt() > cfgTofPtCut && track.hasTOF()) ? nSigmaCombined : nSigmaTPC; + if (track.pt() > cfgTofPtCut && !track.hasTOF()) + return 0; + + const int numSpecies = 3; + int pidCount = 0; + // Select particle with the lowest nsigma + for (int i = 0; i < numSpecies; ++i) { + if (std::abs(nSigmaToUse[i]) < nsigma) { + if (pidCount > 0 && cfgUseStrictPID) + return 0; // more than one particle with low nsigma + + pidCount++; + pid = i; + if (!cfgUseStrictPID) + nsigma = std::abs(nSigmaToUse[i]); + } + } + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + + template + int getNsigmaPIDAssymmetric(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaTOF = {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + std::array nSigmaITS = {itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track)}; + int pid = -1; + + std::array nSigmaToUse = cfgUseItsPID ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS + std::vector detectorNsigmaCut = cfgUseItsPID ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS + + bool isPion, isKaon, isProton; + bool isDetectedPion = nSigmaToUse[0] < detectorNsigmaCut[0] && nSigmaToUse[0] > detectorNsigmaCut[0 + 3]; + bool isDetectedKaon = nSigmaToUse[1] < detectorNsigmaCut[1] && nSigmaToUse[1] > detectorNsigmaCut[1 + 3]; + bool isDetectedProton = nSigmaToUse[2] < detectorNsigmaCut[2] && nSigmaToUse[2] > detectorNsigmaCut[2 + 3]; + + bool isTofPion = nSigmaTOF[0] < tofNsigmaCut[0] && nSigmaTOF[0] > tofNsigmaCut[0 + 3]; + bool isTofKaon = nSigmaTOF[1] < tofNsigmaCut[1] && nSigmaTOF[1] > tofNsigmaCut[1 + 3]; + bool isTofProton = nSigmaTOF[2] < tofNsigmaCut[2] && nSigmaTOF[2] > tofNsigmaCut[2 + 3]; + + if (track.pt() > cfgTofPtCut && !track.hasTOF()) { + return 0; + } else if (track.pt() > cfgTofPtCut && track.hasTOF()) { + isPion = isTofPion && isDetectedPion; + isKaon = isTofKaon && isDetectedKaon; + isProton = isTofProton && isDetectedProton; + } else { + isPion = isDetectedPion; + isKaon = isDetectedKaon; + isProton = isDetectedProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + return 0; // more than one particle satisfy the criteria + } + + if (isPion) { + pid = PIONS; + } else if (isKaon) { + pid = KAONS; + } else if (isProton) { + pid = PROTONS; + } else { + return 0; // no particle satisfies the criteria + } + + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + + 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, axisEta, axisVertex}}); + tH3s[hCharge] = histos.add(Form("NUA/%d/hPhiEtaVtxz_ch", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + tH3s[hPion] = histos.add(Form("NUA/%d/hPhiEtaVtxz_pi", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + tH3s[hKaon] = histos.add(Form("NUA/%d/hPhiEtaVtxz_ka", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + tH3s[hProton] = histos.add(Form("NUA/%d/hPhiEtaVtxz_pr", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, axisEta, axisVertex}}); + 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 TCollision collision, int index) + { // 0 = ref, 1 = ch, 2 = pi, 3 = ka, 4 = pr + if (index < 0 || index >= 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[index]) { + LOGF(fatal, "Acceptance weights not loaded for index %d", index); + return 1; + } + if (cfgUseWeightPhiEtaVtxz) + wacc = mAcceptance[index]->getNUA(track.phi(), track.eta(), vtxz); + if (cfgUseWeightPhiPtCent) + wacc = mAcceptance[index]->getNUA(track.phi(), track.pt(), cent); + if (cfgUseWeightPhiEtaPt) + wacc = mAcceptance[index]->getNUA(track.phi(), track.eta(), track.pt()); + } + return wacc; + } + + template + void fillWeights(const TTrack track, const TCollision collision, const int& pid_index, const int& run) + { + 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 (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 + 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) { + case 0: + histos.fill(HIST("NUA/hPhiEtaVtxz_ch"), track.phi(), track.eta(), vtxz); // charged particle weights + histos.fill(HIST("NUA/hPhiPtCent_ch"), track.phi(), track.pt(), cent); + histos.fill(HIST("NUA/hPhiEtaPt_ch"), track.phi(), track.eta(), track.pt()); + break; + case 1: + histos.fill(HIST("NUA/hPhiEtaVtxz_pi"), track.phi(), track.eta(), vtxz); // pion weights + histos.fill(HIST("NUA/hPhiPtCent_pi"), track.phi(), track.pt(), cent); + histos.fill(HIST("NUA/hPhiEtaPt_pi"), track.phi(), track.eta(), track.pt()); + break; + case 2: + histos.fill(HIST("NUA/hPhiEtaVtxz_ka"), track.phi(), track.eta(), vtxz); // kaon weights + histos.fill(HIST("NUA/hPhiPtCent_ka"), track.phi(), track.pt(), cent); + histos.fill(HIST("NUA/hPhiEtaPt_ka"), track.phi(), track.eta(), track.pt()); + break; + case 3: + histos.fill(HIST("NUA/hPhiEtaVtxz_pr"), track.phi(), track.eta(), vtxz); // proton weights + histos.fill(HIST("NUA/hPhiPtCent_pr"), track.phi(), track.pt(), cent); + histos.fill(HIST("NUA/hPhiEtaPt_pr"), track.phi(), track.eta(), track.pt()); + break; + } + } + } + } + + template + bool selectionEvent(TCollision collision, const int mult, const float cent) + { + histos.fill(HIST("hEventCount"), kFilteredEvents); + if (!collision.sel8()) { + return 0; + } + histos.fill(HIST("hEventCount"), kAfterSel8); + + if (eventCuts[kUseNoTimeFrameBorder] && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return 0; + } + if (eventCuts[kUseNoTimeFrameBorder]) + histos.fill(HIST("hEventCount"), kUseNoTimeFrameBorder); + + if (eventCuts[kUseNoITSROFrameBorder] && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return 0; + } + if (eventCuts[kUseNoITSROFrameBorder]) + histos.fill(HIST("hEventCount"), kUseNoITSROFrameBorder); + + if (eventCuts[kUseNoSameBunchPileup] && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return 0; + } + if (eventCuts[kUseNoSameBunchPileup]) + histos.fill(HIST("hEventCount"), kUseNoSameBunchPileup); + + if (eventCuts[kUseGoodZvtxFT0vsPV] && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return 0; + } + if (eventCuts[kUseGoodZvtxFT0vsPV]) + histos.fill(HIST("hEventCount"), kUseGoodZvtxFT0vsPV); + + if (eventCuts[kUseNoCollInTimeRangeStandard] && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + if (eventCuts[kUseNoCollInTimeRangeStandard]) + histos.fill(HIST("hEventCount"), kUseNoCollInTimeRangeStandard); + + if (eventCuts[kUseGoodITSLayersAll] && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return 0; + } + if (eventCuts[kUseGoodITSLayersAll]) + histos.fill(HIST("hEventCount"), kUseGoodITSLayersAll); + + if (eventCuts[kUseNoCollInRofStandard] && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return 0; + } + if (eventCuts[kUseNoCollInRofStandard]) + histos.fill(HIST("hEventCount"), kUseNoCollInRofStandard); + + if (eventCuts[kUseNoHighMultCollInPrevRof] && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return 0; + } + if (eventCuts[kUseNoHighMultCollInPrevRof]) + histos.fill(HIST("hEventCount"), kUseNoHighMultCollInPrevRof); + + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + + if (eventCuts[kUseOccupancy] && (occupancy < cfgCutOccupancyMin || occupancy > cfgCutOccupancyMax)) { + return 0; + } + if (eventCuts[kUseOccupancy]) + histos.fill(HIST("hEventCount"), kUseOccupancy); + + if (eventCuts[kUseMultCorrCut]) { + if (multNTracksPV < fMultPVCutLow->Eval(cent)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(cent)) + return 0; + if (mult < fMultCutLow->Eval(cent)) + return 0; + if (mult > fMultCutHigh->Eval(cent)) + return 0; + } + if (eventCuts[kUseMultCorrCut]) + histos.fill(HIST("hEventCount"), kUseMultCorrCut); + + // V0A T0A 5 sigma cut + if (eventCuts[kUseT0AV0ACut] && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > cfgV0AT0Acut * fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + if (eventCuts[kUseT0AV0ACut]) + histos.fill(HIST("hEventCount"), kUseT0AV0ACut); + + if (eventCuts[kUseVertexITSTPC] && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return 0; + if (eventCuts[kUseVertexITSTPC]) + histos.fill(HIST("hEventCount"), kUseVertexITSTPC); + + if (eventCuts[kUseTVXinTRD] && collision.alias_bit(kTVXinTRD)) { + return 0; + } + if (eventCuts[kUseTVXinTRD]) + histos.fill(HIST("hEventCount"), kUseTVXinTRD); + + return 1; + } + + void process(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracksWithoutBayes const& tracks) + { + int nTot = tracks.size(); + if (nTot < 1) + return; + + float lRandom = fRndm->Rndm(); + float vtxz = collision.posZ(); + const auto cent = collision.centFT0C(); + + if (!selectionEvent(collision, nTot, cent)) + return; + + 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); + histos.fill(HIST("globalTracks_centT0C"), cent, nTot); + 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("TpcdEdx"), pt, track.tpcSignal()); + histos.fill(HIST("TofBeta"), pt, track.beta()); + + histos.fill(HIST("TofTpcNsigma_before"), PIONS, track.tpcNSigmaPi(), track.tofNSigmaPi(), pt); + histos.fill(HIST("TofTpcNsigma_before"), KAONS, track.tpcNSigmaKa(), track.tofNSigmaKa(), pt); + histos.fill(HIST("TofTpcNsigma_before"), PROTONS, track.tpcNSigmaPr(), track.tofNSigmaPr(), pt); + + histos.fill(HIST("TofItsNsigma_before"), PIONS, itsResponse.nSigmaITS(track), track.tofNSigmaPi(), pt); + histos.fill(HIST("TofItsNsigma_before"), KAONS, itsResponse.nSigmaITS(track), track.tofNSigmaKa(), pt); + histos.fill(HIST("TofItsNsigma_before"), PROTONS, itsResponse.nSigmaITS(track), track.tofNSigmaPr(), pt); + + bool withinPtPOI = (cfgCutPtPOIMin < pt) && (pt < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtMin < pt) && (pt < cfgCutPtMax); // within RF pT range + + pidIndex = cfgUseAsymmetricPID ? getNsigmaPIDAssymmetric(track) : getNsigmaPIDTpcTof(track); + + weff = 1; // Initializing weff for each track + // NUA weights + if (cfgOutputNUAWeights) + fillWeights(track, collision, pidIndex, runNumber); + + if (!withinPtPOI && !withinPtRef) + return; + double waccRef = getAcceptance(track, collision, 0); + double waccPOI = withinPtPOI ? getAcceptance(track, collision, pidIndex + 1) : getAcceptance(track, collision, 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); + } + if (withinPtPOI) { + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccPOI * weff, 128); + } + if (withinPtPOI && withinPtRef) { + fGFW->Fill(track.eta(), fPtAxis->FindBin(pt) - 1, track.phi(), waccPOI * weff, 256); + } + + if (pidIndex) { + fillQA(collision, track, pidIndex, waccPOI); + 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(0), HIST("c22_full_ch"), cent); + fillProfile(corrconfigs.at(0), HIST("c22_full_ch_Nch"), nTot); + + if (!cfgUseNch) { + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), cent, lRandom); + } + } else { + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), nTot, lRandom); + } + } + + } // end of process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/flowPidCme.cxx b/PWGCF/Flow/Tasks/flowPidCme.cxx new file mode 100644 index 00000000000..6b457daa168 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowPidCme.cxx @@ -0,0 +1,3492 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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), KegangXiong(kxiong@cern.ch) +/// \file flowPidCme.cxx +/// \brief task to calculate the pikp cme signal and bacground. +// C++/ROOT includes. +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// o2Physics includes. +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.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 + +namespace pid_flags +{ +constexpr int8_t kUnqualified = -1; +constexpr int8_t kUnPOIHadron = 0; +constexpr int8_t kPion = 1; +constexpr int8_t kKaon = 2; +constexpr int8_t kProton = 3; +constexpr int8_t kPionITSleft = 4; +constexpr int8_t kKaonITSleft = 5; +constexpr int8_t kProtonITSleft = 6; +constexpr int8_t kPionKaon = 7; +constexpr int8_t kPionProton = 8; +constexpr int8_t kKaonProton = 9; +constexpr int8_t kPionKaonProton = 10; +constexpr int8_t kPionKaonITSleft = 11; +constexpr int8_t kPionProtonITSleft = 12; +constexpr int8_t kKaonProtonITSleft = 13; +constexpr int8_t kPionKaonProtonITSleft = 14; +} // namespace pid_flags + +namespace event_selection +{ +constexpr int kFT0AV0ASigma = 5; +} + +namespace fourier_mode +{ +// constexpr int kMode1 = 1; +constexpr int kMode2 = 2; +// constexpr int kMode3 = 3; +} // namespace fourier_mode + +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 cfgUseStrictPID{"cfgUseStrictPID", true, "More strict pid strategy"}; + 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); + const int nlayerITS = 7; + + for (int layer = 0; layer < nlayerITS; 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 { + if (candidate.pt() > cfgPtMaxforTPCOnlyPID && candidate.hasTOF()) { + nSigmaToUse = nSigmaCombined; + pidVectorUpper = cfgnSigmaCutRMSUpper.value; + pidVectorLower = cfgnSigmaCutRMSLower.value; + } else if (candidate.pt() > cfgPtMaxforTPCOnlyPID && !candidate.hasTOF() && cfgUseStrictPID) { + return 0; + } else { + nSigmaToUse = nSigmaTPC; + pidVectorUpper = cfgnSigmaCutTPCUpper.value; + pidVectorLower = cfgnSigmaCutTPCLower.value; + } + } + float nsigma = 9999.99; + const int nPOI = 3; + const int piCase = 0; + const int kaCase = 1; + const int prCase = 2; + // Fill cross pid QA + for (int i = 0; i < nPOI; ++i) { + if (nSigmaToUse[i] > pidVectorLower[i] && nSigmaToUse[i] < pidVectorUpper[i]) { + if (i == piCase) { + 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 == kaCase) { + 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 == prCase) { + 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 (cfgUseStrictPID) { + // Only use the track which was recognized as an unique PID particle + int index = (kIsPr << 2) | (kIsKa << 1) | kIsPi; + const int map[] = {0, 1, 2, 0, 3, 0, 0, 0}; + return map[index]; + } else { + 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 < nPOI; ++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 == pid_flags::kUnqualified || pidFlag == pid_flags::kUnPOIHadron)) { + // First fill ITS uncut plots + if ((pidFlag == pid_flags::kPion) || (pidFlag == pid_flags::kPionKaon) || (pidFlag == pid_flags::kPionProton) || (pidFlag == pid_flags::kPionKaonProton)) { + 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 == pid_flags::kUnPOIHadron)) { + 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 == pid_flags::kKaon) || (pidFlag == pid_flags::kPionKaon) || (pidFlag == pid_flags::kKaonProton) || (pidFlag == pid_flags::kPionKaonProton)) { + 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 || pid_flags::kUnPOIHadron)) { + 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 == pid_flags::kProton) || (pidFlag == pid_flags::kPionProton) || (pidFlag == pid_flags::kKaonProton) || (pidFlag == pid_flags::kPionKaonProton)) { + 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 == pid_flags::kUnPOIHadron)) { + 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 == pid_flags::kPion) || (pidFlag == pid_flags::kPionKaon) || (pidFlag == pid_flags::kPionProton) || (pidFlag == pid_flags::kPionKaonProton)) { + 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 == pid_flags::kKaon) || (pidFlag == pid_flags::kPionKaon) || (pidFlag == pid_flags::kKaonProton) || (pidFlag == pid_flags::kPionKaonProton)) { + 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 == pid_flags::kProton) || (pidFlag == pid_flags::kPionProton) || (pidFlag == pid_flags::kKaonProton) || (pidFlag == pid_flags::kPionKaonProton)) { + 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 == pid_flags::kPion) || (pidFlag == pid_flags::kPionITSleft) || (pidFlag == pid_flags::kPionKaon) || (pidFlag == pid_flags::kPionProton) || (pidFlag == pid_flags::kPionKaonProton) || (pidFlag == pid_flags::kPionKaonITSleft) || (pidFlag == pid_flags::kPionProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft)) { + if (trk.sign() > 0) { + if (!((pidFlag == pid_flags::kPionITSleft) || (pidFlag == pid_flags::kPionKaonITSleft) || (pidFlag == pid_flags::kPionProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft))) { + 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 == pid_flags::kPionITSleft) || (pidFlag == pid_flags::kPionKaonITSleft) || (pidFlag == pid_flags::kPionProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft))) { + 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 == pid_flags::kKaon) || (pidFlag == pid_flags::kKaonITSleft) || (pidFlag == pid_flags::kPionKaon) || (pidFlag == pid_flags::kKaonProton) || (pidFlag == pid_flags::kPionKaonProton) || (pidFlag == pid_flags::kPionKaonITSleft) || (pidFlag == pid_flags::kKaonProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft)) { + if (trk.sign() > 0) { + if (!((pidFlag == pid_flags::kKaonITSleft) || (pidFlag == pid_flags::kPionKaonITSleft) || (pidFlag == pid_flags::kKaonProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft))) { + 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 == pid_flags::kKaonITSleft) || (pidFlag == pid_flags::kPionKaonITSleft) || (pidFlag == pid_flags::kKaonProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft))) { + 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 == pid_flags::kProton) || (pidFlag == pid_flags::kProtonITSleft) || (pidFlag == pid_flags::kPionProton) || (pidFlag == pid_flags::kKaonProton) || (pidFlag == pid_flags::kPionKaonProton) || (pidFlag == pid_flags::kPionProtonITSleft) || (pidFlag == pid_flags::kKaonProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft)) { + if (trk.sign() > 0) { + if (!((pidFlag == pid_flags::kProtonITSleft) || (pidFlag == pid_flags::kPionProtonITSleft) || (pidFlag == pid_flags::kKaonProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft))) { + 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 == pid_flags::kProtonITSleft) || (pidFlag == pid_flags::kPionProtonITSleft) || (pidFlag == pid_flags::kKaonProtonITSleft) || (pidFlag == pid_flags::kPionKaonProtonITSleft))) { + 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 FlowPidCme { + 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 == pid_flags::kPion) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kPionKaon) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kPionProton) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kPionKaonProton)); + Partition>> tracksSet2 = ((aod::cme_track_pid_columns::nPidFlag == pid_flags::kKaon) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kPionKaon) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kKaonProton) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kPionKaonProton)); + Partition>> tracksSet3 = ((aod::cme_track_pid_columns::nPidFlag == pid_flags::kProton) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kPionProton) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kKaonProton) || (aod::cme_track_pid_columns::nPidFlag == pid_flags::kPionKaonProton)); + 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())) > event_selection::kFT0AV0ASigma * 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() == pid_flags::kProton) || (track.nPidFlag() == pid_flags::kPionProton) || (track.nPidFlag() == pid_flags::kKaonProton) || (track.nPidFlag() == pid_flags::kPionKaonProton)) { + 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); + double nonzero = 1e-8; + if (nmode == fourier_mode::kMode2) { + if (collision.qvecAmp()[detId] > nonzero) { + 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] > nonzero && collision.qvecAmp()[refAId] > nonzero && collision.qvecAmp()[refBId] > nonzero) { + 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) + { + double nonzero2 = 1e-8; + if (collision.qvecAmp()[detId] < nonzero2) { + 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 == fourier_mode::kMode2) { + 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 == fourier_mode::kMode2) { + 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 == fourier_mode::kMode2) { + 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 == fourier_mode::kMode2) { + 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 == fourier_mode::kMode2) { + 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 == fourier_mode::kMode2) { + 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 == fourier_mode::kMode2) { + 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 == fourier_mode::kMode2) { + 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 == fourier_mode::kMode2) { + 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; + const float cenPlotMin = 20; + const float cenPlotMax = 30; + 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 >= cenPlotMin && cent < cenPlotMax) { + if ((trk.nPidFlag() == pid_flags::kProton) || (trk.nPidFlag() == pid_flags::kPionProton) || (trk.nPidFlag() == pid_flags::kKaonProton) || (trk.nPidFlag() == pid_flags::kPionKaonProton)) { + 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) == fourier_mode::kMode2) { + 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/flowPtEfficiency.cxx b/PWGCF/Flow/Tasks/flowPtEfficiency.cxx index 43a6eff399d..27657e0f435 100644 --- a/PWGCF/Flow/Tasks/flowPtEfficiency.cxx +++ b/PWGCF/Flow/Tasks/flowPtEfficiency.cxx @@ -8,17 +8,38 @@ // In applying this license CERN does 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 -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" +/// \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 "FlowContainer.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.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 "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include + +#include +#include +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; @@ -26,85 +47,494 @@ 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(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); + O2_DEFINE_CONFIGURABLE(cfgDCAxyFunction, std::string, "(0.0015+0.005/(x^1.1))", "Functional form of pt-dependent DCAxy cut"); + 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(cfgEnableITSCuts, bool, true, "switch of enabling ITS based track selection cuts") + 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); + TF1* fPtDepDCAxy = nullptr; 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; } void init(InitContext const&) { + const AxisSpec axisVertex{20, -10, 10, "Vtxz (cm)"}; + const AxisSpec axisEta{20, -1., 1., "#eta"}; const AxisSpec axisCounter{1, 0, +1, ""}; // 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("hEtaPtVzRec", "hEtaPtVz Reconstructed", HistType::kTH3D, {axisEta, axisPt, axisVertex}); 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}); + registry.add("hEtaPtVzTrue", "hEtaPtVz True", HistType::kTH3D, {axisEta, axisPt, axisVertex}); + + 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 (cfgEnableITSCuts) { + 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 { + if (cfgCutDCAxy != 0.0) { + myTrackSel.SetMaxDcaXY(cfgCutDCAxy); + } else { + fPtDepDCAxy = new TF1("ptDepDCAxy", Form("[0]*%s", cfgDCAxyFunction->c_str()), 0.001, 100); + fPtDepDCAxy->SetParameter(0, cfgDCAxyNSigma); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", cfgDCAxyFunction->c_str())); + myTrackSel.SetMaxDcaXYPtDep([fPtDepDCAxy = this->fPtDepDCAxy](float pt) { return fPtDepDCAxy->Eval(pt); }); + } + } + myTrackSel.SetMinNClustersTPC(cfgCutTPCclu); + myTrackSel.SetMinNCrossedRowsTPC(cfgCutTPCcrossedrows); + if (cfgEnableITSCuts) + myTrackSel.SetMinNClustersITS(cfgCutITSclu); + 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 processReco(o2::aod::Collision const&, myTracks const& tracks, aod::McParticles const&) + 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 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()); + registry.fill(HIST("hEtaPtVzRec"), track.eta(), track.pt(), vtxz); + + 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; + float vtxz = mcCollision.posZ(); + 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]); + } + registry.fill(HIST("hEtaPtVzTrue"), mcParticle.eta(), mcParticle.pt(), vtxz); + + 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..9259eb8be9e --- /dev/null +++ b/PWGCF/Flow/Tasks/flowRunbyRun.cxx @@ -0,0 +1,590 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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(cfgOutputCorrelationQA, bool, false, "Fill correlation QA histograms") + 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"}; + ConfigurableAxis axisNch{"axisNch", {4000, 0, 4000}, "N_{ch}"}; + ConfigurableAxis axisCentForQA{"axisCentForQA", {100, 0, 100}, "centrality (%)"}; + ConfigurableAxis axisT0C{"axisT0C", {70, 0, 70000}, "N_{ch} (T0C)"}; + ConfigurableAxis axisT0A{"axisT0A", {200, 0, 200000}, "N_{ch} (T0A)"}; + + 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 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>> th2sList; // map of TH2 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 OutputTH2Names { + // here are TH2 histograms + hglobalTracks_centT0C = 0, + hglobalTracks_PVTracks, + hglobalTracks_multV0A, + hcentFV0A_centFT0C, + kCount_TH2Names + }; + 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); + auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + // 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)); + + if (cfgOutputCorrelationQA) { + std::vector> th2s(kCount_TH2Names); + th2s[hglobalTracks_centT0C] = registry.add(Form("%d/globalTracks_centT0C", runNumber), "after cut;Centrality T0C;mulplicity global tracks", {HistType::kTH2D, {axisCentForQA, axisNch}}); + th2s[hglobalTracks_PVTracks] = registry.add(Form("%d/globalTracks_PVTracks", runNumber), "after cut;mulplicity PV tracks;mulplicity global tracks", {HistType::kTH2D, {axisNch, axisNch}}); + th2s[hglobalTracks_multV0A] = registry.add(Form("%d/globalTracks_multV0A", runNumber), "after cut;mulplicity V0A;mulplicity global tracks", {HistType::kTH2D, {axisT0A, axisNch}}); + th2s[hcentFV0A_centFT0C] = registry.add(Form("%d/centFV0A_centFT0C", runNumber), "after cut;Centrality T0C;Centrality V0A", {HistType::kTH2D, {axisCentForQA, axisCentForQA}}); + th2sList.insert(std::make_pair(runNumber, th2s)); + } + + 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 + float nSigma = 5.; // 5 sigma cut + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > nSigma * 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()); + if (cfgOutputCorrelationQA) { + th2sList[runNumber][hglobalTracks_centT0C]->Fill(collision.centFT0C(), tracks.size()); + th2sList[runNumber][hglobalTracks_PVTracks]->Fill(collision.multNTracksPV(), tracks.size()); + th2sList[runNumber][hglobalTracks_multV0A]->Fill(collision.multFV0A(), tracks.size()); + th2sList[runNumber][hcentFV0A_centFT0C]->Fill(collision.centFT0C(), collision.centFV0A()); + } + + 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..4ea5937776d --- /dev/null +++ b/PWGCF/Flow/Tasks/flowSP.cxx @@ -0,0 +1,1653 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "GFWWeights.h" + +#include "PWGCF/DataModel/SPTableZDC.h" + +#include "Common/Core/EventPlaneHelper.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include "TF1.h" +#include "TPDGCode.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; +// using namespace o2::analysis; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct FlowSP { + RCTFlagsChecker rctChecker; + + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgEvtUseRCTFlagChecker, bool, false, "Evt sel: use RCT flag checker"); + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerLabel, std::string, "CBT_hadronPID", "Evt sel: RCT flag checker label (CBT, CBT_hadronPID)"); // all Labels can be found in Common/CCDB/RCTSelectionFlags.h + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerZDCCheck, bool, false, "Evt sel: RCT flag checker ZDC check"); + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerLimitAcceptAsBad, bool, false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"); + } rctFlags; + + // struct : ConfigurableGroup { // <-- change all to evsels.Selection + // event selection configurable group + O2_DEFINE_CONFIGURABLE(cfgEvSelsUseAdditionalEventCut, bool, true, "Bool to enable Additional Event Cut"); + 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(cfgEvSelsNoCollInTimeRangeNarrow, bool, true, "kNoCollInTimeRangeNarrow"); + 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(cfgEvSelsIsGoodITSLayer0123, bool, true, "Cut time intervals with dead ITS staves"); + // } evSels; + + // QA Plots + O2_DEFINE_CONFIGURABLE(cfgFillEventQA, bool, false, "Fill histograms for event QA"); + O2_DEFINE_CONFIGURABLE(cfgFillTrackQA, bool, false, "Fill histograms for track QA"); + O2_DEFINE_CONFIGURABLE(cfgFillPIDQA, bool, false, "Fill histograms for PID QA"); + O2_DEFINE_CONFIGURABLE(cfgFillEventPlaneQA, bool, false, "Fill histograms for Event Plane QA"); + O2_DEFINE_CONFIGURABLE(cfgFillQABefore, bool, false, "Fill QA histograms before cuts, only for processData"); + // Flags to make and fill histograms + O2_DEFINE_CONFIGURABLE(cfgFillGeneralV1Histos, bool, true, "Fill histograms for vn analysis"); + O2_DEFINE_CONFIGURABLE(cfgFillMixedHarmonics, bool, true, "Flag to make and fill histos for mixed harmonics"); + O2_DEFINE_CONFIGURABLE(cfgFillEventPlane, bool, false, "Flag to make and fill histos with Event Plane"); + O2_DEFINE_CONFIGURABLE(cfgFillXandYterms, bool, false, "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"); + O2_DEFINE_CONFIGURABLE(cfgFillChargeDependenceQA, bool, true, "Flag to make and fill QA histos for charge dependent flow"); + O2_DEFINE_CONFIGURABLE(cfgFillPID, bool, false, "Flag to make and fill histos for PID 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(cfgTrackSelsDCAxy, float, 0.2, "Cut on DCA in the transverse direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsDCAz, float, 2, "Cut on DCA in the longitudinal direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsNcls, float, 70, "Cut on number of TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsFshcls, float, 0.4, "Cut on fraction of shared TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsPtmin, float, 0.2, "minimum pt (GeV/c)"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsPtmax, float, 10, "maximum pt (GeV/c)"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsEta, float, 0.8, "eta cut"); + O2_DEFINE_CONFIGURABLE(cfgEvSelsVtxZ, 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"); + O2_DEFINE_CONFIGURABLE(cfgFilterLeptons, bool, true, "Filter out leptons from MCGenerated by requiring |pdgCode| > 100"); + // NUA and NUE weights + O2_DEFINE_CONFIGURABLE(cfgFillWeights, bool, true, "Fill NUA weights"); + O2_DEFINE_CONFIGURABLE(cfgFillWeightsPOS, bool, true, "Fill NUA weights only for positive charges"); + O2_DEFINE_CONFIGURABLE(cfgFillWeightsNEG, bool, true, "Fill NUA weights only for negative charges"); + O2_DEFINE_CONFIGURABLE(cfguseNUA1D, bool, false, "Use 1D NUA weights (only phi)"); + O2_DEFINE_CONFIGURABLE(cfguseNUA2D, bool, true, "Use 2D NUA weights (phi and eta)"); + O2_DEFINE_CONFIGURABLE(cfguseNUE2D, bool, true, "Use 2D NUE weights (pt and eta)"); + // Additional track Selections + O2_DEFINE_CONFIGURABLE(cfgTrackSelsUseAdditionalTrackCut, bool, false, "Bool to enable Additional Track Cut"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsDoDCApt, bool, false, "Apply Pt dependent DCAz cut"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsDCApt1, float, 0.1, "DcaZ < a * b / pt^1.1 -> this sets a"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsDCApt2, float, 0.035, "DcaZ < a * b / pt^1.1 -> this sets b"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelsPIDNsigma, float, 2.0, "nSigma cut for PID"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelDoTrackQAvsCent, bool, true, "Do track selection QA plots as function of centrality"); + // 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(cfgCCDBdir_QQ, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5/meanQQ/Default", "ccdb dir for average QQ values in 1% centrality bins"); + O2_DEFINE_CONFIGURABLE(cfgCCDBdir_SP, std::string, "", "ccdb dir for average event plane resolution in 1% centrality bins"); + O2_DEFINE_CONFIGURABLE(cfgCCDB_NUA, std::string, "Users/c/ckoster/flowSP/LHC23_PbPb_pass5/Default", "ccdb dir for NUA corrections"); + O2_DEFINE_CONFIGURABLE(cfgCCDB_NUE, std::string, "Users/c/ckoster/flowSP/LHC23_PbPb_pass5/NUE/Default", "ccdb dir for NUE corrections (pt)"); + O2_DEFINE_CONFIGURABLE(cfgCCDB_NUE2D, std::string, "Users/c/ckoster/flowSP/LHC23_PbPb_pass5/NUE/2D", "ccdb dir for NUE 2D corrections (eta, pt)"); + O2_DEFINE_CONFIGURABLE(cfgCCDBdir_centrality, std::string, "", "ccdb dir for Centrality corrections"); + // Confogirable axis + ConfigurableAxis axisCentrality{"axisCentrality", {20, 0, 100}, "Centrality bins for vn "}; + ConfigurableAxis axisNch = {"axisNch", {400, 0, 4000}, "Global N_{ch}"}; + ConfigurableAxis axisMultpv = {"axisMultpv", {400, 0, 4000}, "N_{ch} (PV)"}; + // Configurables containing vector + Configurable> cfgEvSelsMultPv{"cfgEvSelsMultPv", std::vector{2228.05, -75.5988, 0.976695, -0.00585275, 1.40738e-05, 3795.65, -136.988, 2.12393, -0.017028, 5.78679e-05}, "Multiplicity cuts (PV) first 5 parameters cutLOW last 5 cutHIGH (Default is +-2sigma pass5) "}; + Configurable> cfgEvSelsMult{"cfgEvSelsMult", std::vector{1308.86, -41.9314, 0.488423, -0.00248178, 4.71554e-06, 2973.55, -103.092, 1.47673, -0.0106685, 3.29348e-05}, "Multiplicity cuts (Global) first 5 parameters cutLOW last 5 cutHIGH (Default is +-2sigma pass5) "}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgEvSelsVtxZ; + Filter trackFilter = nabs(aod::track::eta) < cfgTrackSelsEta && aod::track::pt > cfgTrackSelsPtmin&& aod::track::pt < cfgTrackSelsPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && nabs(aod::track::dcaXY) < cfgTrackSelsDCAxy&& nabs(aod::track::dcaZ) < cfgTrackSelsDCAz; + Filter trackFilterMC = nabs(aod::mcparticle::eta) < cfgTrackSelsEta && aod::mcparticle::pt > cfgTrackSelsPtmin&& aod::mcparticle::pt < cfgTrackSelsPtmax; + using GeneralCollisions = soa::Join; + using UnfilteredTracks = soa::Join; + + using UsedTracks = soa::Filtered; + using ZDCCollisions = 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 mEfficiency2D = {}; + std::vector mAcceptance = {}; + std::vector mAcceptance2D = {}; + bool correctionsLoaded = false; + int lastRunNumber = 0; + + TProfile* hcorrQQ = nullptr; + TProfile* hcorrQQx = nullptr; + TProfile* hcorrQQy = nullptr; + TProfile* hEvPlaneRes = nullptr; + TH1D* hCentrality = nullptr; + + bool clQQ = false; + bool clEvPlaneRes = false; + bool clCentrality = false; + + } cfg; + + struct SPMvars { + std::vector> wacc = {{{0, 1.0}, {1, 1.0}, {2, 1.0}, {3, 1.0}}, {{0, 1.0}, {1, 1.0}, {2, 1.0}, {3, 1.0}}, {{0, 1.0}, {1, 1.0}, {2, 1.0}, {3, 1.0}}}; // int for part species, float for weight vector for kIncl, kPos, kNeg + std::vector> weff = {{{0, 1.0}, {1, 1.0}, {2, 1.0}, {3, 1.0}}, {{0, 1.0}, {1, 1.0}, {2, 1.0}, {3, 1.0}}, {{0, 1.0}, {1, 1.0}, {2, 1.0}, {3, 1.0}}}; // int for part species, float for weight vector for kIncl, kPos, kNeg + double centWeight = 1.0; + double ux = 0; + double uy = 0; + double uxMH = 0; + double uyMH = 0; + double qxA = 0; + double qyA = 0; + double qxC = 0; + double qyC = 0; + double corrQQx = 1; + double corrQQy = 1; + double corrQQ = 1; + double vnA = 0; + double vnC = 0; + double vnFull = 0; + float centrality = 0; + float vtxz = 0; + double vx = 0; + double vy = 0; + double vz = 0; + int charge = 0; + } spm; + + OutputObj fWeights{GFWWeights("weights")}; + OutputObj fWeightsPOS{GFWWeights("weights_positive")}; + OutputObj fWeightsNEG{GFWWeights("weights_negative")}; + + HistogramRegistry registry{"registry"}; + HistogramRegistry histos{"QAhistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + // Event selection cuts + 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_RCTFlagsZDC, + evSel_occupancy, + evSel_kNoSameBunchPileup, + evSel_kIsGoodZvtxFT0vsPV, + evSel_kNoCollInTimeRangeStandard, + evSel_kNoCollInTimeRangeNarrow, + evSel_kIsVertexITSTPC, + evSel_kIsGoodITSLayersAll, + evSel_kIsGoodITSLayer0123, + evSel_MultCuts, + evSel_isSelectedZDC, + evSel_CentCuts, + nEventSelections + }; + + enum TrackSelections { + trackSel_ZeroCharge, + trackSel_Eta, + trackSel_Pt, + trackSel_DCAxy, + trackSel_DCAz, + trackSel_GlobalTracks, + trackSel_NCls, + trackSel_FshCls, + trackSel_TPCBoundary, + trackSel_ParticleWeights, + nTrackSelections + }; + + enum ChargeType { + kInclusive, + kPositive, + kNegative, + nChargeTypes + }; + + enum FillType { + kBefore, + kAfter, + nFillTypes + }; + + enum ModeType { + kGen, + kReco, + nModeTypes + }; + + enum ParticleType { + kUnidentified, + kPions, + kKaons, + kProtons, + nParticleTypes + }; + + static constexpr std::string_view Charge[] = {"incl/", "pos/", "neg/"}; + static constexpr std::string_view Species[] = {"", "pion/", "kaon/", "proton/"}; + 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.6, 1.6, "#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 axisT0c = {70, 0, 100000, "N_{ch} (T0C)"}; + AxisSpec axisT0a = {70, 0, 200000, "N_{ch} (T0A)"}; + AxisSpec axisV0a = {70, 0, 200000, "N_{ch} (V0A)"}; + AxisSpec axisShCl = {40, 0, 1, "Fraction shared cl. TPC"}; + AxisSpec axisCl = {80, 0, 160, "Number of cl. TPC"}; + AxisSpec axisNsigma = {100, -10, 10, "Nsigma for TPC and TOF"}; + AxisSpec axisdEdx = {300, 0, 300, "dEdx for PID"}; + AxisSpec axisBeta = {150, 0, 1.5, "Beta for PID"}; + + 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; + + rctChecker.init(rctFlags.cfgEvtRCTFlagCheckerLabel, rctFlags.cfgEvtRCTFlagCheckerZDCCheck, rctFlags.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + histos.add("hEventCount", "Number of Event; Cut; #Events Passed Cut", {HistType::kTH1D, {{nEventSelections, 0, nEventSelections}}}); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_FilteredEvent + 1, "Filtered events"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_RCTFlagsZDC + 1, "RCT Flags ZDC"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_sel8 + 1, "Sel8"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_occupancy + 1, "kOccupancy"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoSameBunchPileup + 1, "kNoSameBunchPileup"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoCollInTimeRangeStandard + 1, "kNoCollInTimeRangeStandard"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kNoCollInTimeRangeNarrow + 1, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsVertexITSTPC + 1, "kIsVertexITSTPC"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_CentCuts + 1, "Cenrality range"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayersAll + 1, "kkIsGoodITSLayersAll"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_kIsGoodITSLayer0123 + 1, "kkIsGoodITSLayer0123"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_MultCuts + 1, "Multiplicity Cuts Pilup"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(evSel_isSelectedZDC + 1, "isSelected"); + + histos.add("hTrackCount", "Number of Tracks; Cut; #Tracks Passed Cut", {HistType::kTH1D, {{nTrackSelections, 0, nTrackSelections}}}); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_Eta + 1, "Eta"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_Pt + 1, "Pt"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_DCAxy + 1, "DCAxy"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_DCAz + 1, "DCAz"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_GlobalTracks + 1, "GlobalTracks"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_NCls + 1, "nClusters TPC"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_FshCls + 1, "Frac. sh. Cls TPC"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_TPCBoundary + 1, "TPC Boundary"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_ZeroCharge + 1, "Only charged"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(trackSel_ParticleWeights + 1, "Apply weights"); + + if (cfgFillWeights) { + registry.add("weights2D/hPhi_Eta_vz", "", kTH3D, {axisPhi, axisEta, axisVz}); + registry.add("weights2D/hPhi_Eta_vz_positive", "", kTH3D, {axisPhi, axisEta, axisVz}); + registry.add("weights2D/hPhi_Eta_vz_negative", "", kTH3D, {axisPhi, axisEta, axisVz}); + + // define output objects + 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 (cfgFillEventQA) { + histos.add("QA/after/hCentFT0C", " ; Cent FT0C (%); ", {HistType::kTH1D, {axisCent}}); + histos.add("QA/after/hCentFT0M", "; Cent FT0M (%); ", {HistType::kTH1D, {axisCent}}); + histos.add("QA/after/hCentFV0A", "; Cent FV0A (%); ", {HistType::kTH1D, {axisCent}}); + histos.add("QA/after/hCentNGlobal", "; Cent NGlobal (%); ", {HistType::kTH1D, {axisCent}}); + histos.add("QA/after/globalTracks_centT0C", "", {HistType::kTH2D, {axisCent, axisNch}}); + histos.add("QA/after/PVTracks_centT0C", "", {HistType::kTH2D, {axisCent, axisMultpv}}); + histos.add("QA/after/globalTracks_PVTracks", "", {HistType::kTH2D, {axisMultpv, axisNch}}); + histos.add("QA/after/globalTracks_multT0A", "", {HistType::kTH2D, {axisT0a, axisNch}}); + histos.add("QA/after/globalTracks_multV0A", "", {HistType::kTH2D, {axisV0a, axisNch}}); + histos.add("QA/after/multV0A_multT0A", "", {HistType::kTH2D, {axisT0a, axisV0a}}); + histos.add("QA/after/multT0C_centT0C", "", {HistType::kTH2D, {axisCent, axisT0c}}); + histos.add("QA/after/CentFT0C_vs_CentFT0Cvariant1", " ; Cent FT0C (%); Cent FT0Cvariant1 (%) ", {HistType::kTH2D, {axisCent, axisCent}}); + histos.add("QA/after/CentFT0C_vs_CentFT0M", " ; Cent FT0C (%); Cent FT0M (%) ", {HistType::kTH2D, {axisCent, axisCent}}); + histos.add("QA/after/CentFT0C_vs_CentFV0A", " ; Cent FT0C (%); Cent FV0A (%) ", {HistType::kTH2D, {axisCent, axisCent}}); + histos.add("QA/after/CentFT0C_vs_CentNGlobal", " ; Cent FT0C (%); Cent NGlobal (%) ", {HistType::kTH2D, {axisCent, axisCent}}); + + if (cfgFillEventPlaneQA && doprocessData) { + histos.add("QA/after/PsiA_vs_Cent", "", {HistType::kTH2D, {axisPhiPlane, axisCent}}); + histos.add("QA/after/PsiC_vs_Cent", "", {HistType::kTH2D, {axisPhiPlane, axisCent}}); + histos.add("QA/after/PsiFull_vs_Cent", "", {HistType::kTH2D, {axisPhiPlane, axisCent}}); + histos.add("QA/after/PsiA_vs_Vx", "", {HistType::kTH2D, {axisPhiPlane, axisVx}}); + histos.add("QA/after/PsiC_vs_Vx", "", {HistType::kTH2D, {axisPhiPlane, axisVx}}); + histos.add("QA/after/PsiFull_vs_Vx", "", {HistType::kTH2D, {axisPhiPlane, axisVx}}); + histos.add("QA/after/PsiA_vs_Vy", "", {HistType::kTH2D, {axisPhiPlane, axisVy}}); + histos.add("QA/after/PsiC_vs_Vy", "", {HistType::kTH2D, {axisPhiPlane, axisVy}}); + histos.add("QA/after/PsiFull_vs_Vy", "", {HistType::kTH2D, {axisPhiPlane, axisVy}}); + histos.add("QA/after/PsiA_vs_Vz", "", {HistType::kTH2D, {axisPhiPlane, axisVz}}); + histos.add("QA/after/PsiC_vs_Vz", "", {HistType::kTH2D, {axisPhiPlane, axisVz}}); + histos.add("QA/after/PsiFull_vs_Vz", "", {HistType::kTH2D, {axisPhiPlane, axisVz}}); + } + + if (cfgFillQABefore) { + histos.addClone("QA/after/", "QA/before/"); + } + } + + if (doprocessData || doprocessMCReco) { + + if (cfgFillTrackQA) { + histos.add("incl/QA/after/pt_phi", "", {HistType::kTH2D, {axisPt, axisPhiMod}}); + histos.add("incl/QA/after/hPhi_Eta_vz", "", kTH3D, {axisPhi, axisEta, axisVz}); + histos.add("incl/QA/after/hPhi_Eta_vz_corrected", "", kTH3D, {axisPhi, axisEta, axisVz}); + histos.add("incl/QA/after/hDCAxy_pt", "", kTH2D, {axisPt, axisDCAxy}); + histos.add("incl/QA/after/hDCAz_pt", "", kTH2D, {axisPt, axisDCAz}); + histos.add("incl/QA/after/hSharedClusters_pt", "", {HistType::kTH2D, {axisPt, axisShCl}}); + histos.add("incl/QA/after/hCrossedRows_pt", "", {HistType::kTH2D, {axisPt, axisCl}}); + histos.add("incl/QA/after/hCrossedRows_vs_SharedClusters", "", {HistType::kTH2D, {axisCl, axisShCl}}); + + if (cfgTrackSelDoTrackQAvsCent) { + histos.add("incl/QA/after/hPt_Eta", "", kTH3D, {axisPt, axisEta, axisCent}); + histos.add("incl/QA/after/hPt_Eta_uncorrected", "", kTH3D, {axisPt, axisEta, axisCent}); + histos.add("incl/QA/after/hPhi_Eta", "", kTH3D, {axisPhi, axisEta, axisCent}); + histos.add("incl/QA/after/hPhi_Eta_uncorrected", "", kTH3D, {axisPhi, axisEta, axisCent}); + } else { + histos.add("incl/QA/after/hPhi_Eta_Pt", "", kTH3D, {axisPhi, axisEta, axisPt}); + histos.add("incl/QA/after/hPhi_Eta_Pt_corrected", "", kTH3D, {axisPhi, axisEta, axisPt}); + } + + if (cfgFillQABefore) + histos.addClone("incl/QA/after/", "incl/QA/before/"); + } + + if (cfgFillPIDQA) { + histos.add("hPIDcounts", "", kTH2D, {{{4, 0, 4}, axisPt}}); + histos.get(HIST("hPIDcounts"))->GetXaxis()->SetBinLabel(1, "UFO"); + histos.get(HIST("hPIDcounts"))->GetXaxis()->SetBinLabel(2, "Pion"); + histos.get(HIST("hPIDcounts"))->GetXaxis()->SetBinLabel(3, "Kaon"); + histos.get(HIST("hPIDcounts"))->GetXaxis()->SetBinLabel(4, "Proton"); + + histos.add("incl/QA/after/hdEdxTPC_pt", "", {HistType::kTH2D, {axisPt, axisdEdx}}); + histos.add("incl/QA/after/hBetaTOF_pt", "", {HistType::kTH2D, {axisPt, axisBeta}}); + histos.add("incl/QA/before/hdEdxTPC_pt", "", {HistType::kTH2D, {axisPt, axisdEdx}}); + histos.add("incl/QA/before/hBetaTOF_pt", "", {HistType::kTH2D, {axisPt, axisBeta}}); + + histos.add("incl/pion/QA/after/hNsigmaTPC_pt", "", {HistType::kTH2D, {axisPt, axisNsigma}}); + histos.add("incl/pion/QA/after/hNsigmaTOF_pt", "", {HistType::kTH2D, {axisPt, axisNsigma}}); + + if (cfgTrackSelDoTrackQAvsCent) { + histos.add("incl/pion/QA/after/hPt_Eta", "", kTH3D, {axisPt, axisEta, axisCent}); + histos.add("incl/pion/QA/after/hPt_Eta_uncorrected", "", kTH3D, {axisPt, axisEta, axisCent}); + histos.add("incl/pion/QA/after/hPhi_Eta", "", kTH3D, {axisPhi, axisEta, axisCent}); + histos.add("incl/pion/QA/after/hPhi_Eta_uncorrected", "", kTH3D, {axisPhi, axisEta, axisCent}); + } else { + histos.add("incl/pion/QA/after/hPhi_Eta_Pt", "", kTH3D, {axisPhi, axisEta, axisPt}); + histos.add("incl/pion/QA/after/hPhi_Eta_Pt_corrected", "", kTH3D, {axisPhi, axisEta, axisPt}); + } + histos.add("incl/pion/QA/after/hPhi_Eta_vz", "", kTH3D, {axisPhi, axisEta, axisVz}); + histos.add("incl/pion/QA/after/hPhi_Eta_vz_corrected", "", kTH3D, {axisPhi, axisEta, axisVz}); + histos.add("incl/pion/QA/after/hDCAxy_pt", "", kTH2D, {axisPt, axisDCAxy}); + histos.add("incl/pion/QA/after/hDCAz_pt", "", kTH2D, {axisPt, axisDCAz}); + histos.add("incl/pion/QA/after/hSharedClusters_pt", "", {HistType::kTH2D, {axisPt, axisShCl}}); + histos.add("incl/pion/QA/after/hCrossedRows_pt", "", {HistType::kTH2D, {axisPt, axisCl}}); + histos.add("incl/pion/QA/after/hCrossedRows_vs_SharedClusters", "", {HistType::kTH2D, {axisCl, axisShCl}}); + + if (cfgFillQABefore) { + histos.addClone("incl/pion/QA/after/", "incl/pion/QA/before/"); + } + + histos.addClone("incl/pion/", "incl/kaon/"); + histos.addClone("incl/pion/", "incl/proton/"); + } + + if (doprocessMCReco) { + registry.add("trackMCReco/after/hIsPhysicalPrimary", "", {HistType::kTH2D, {{2, 0, 2}, axisCentrality}}); + registry.add("trackMCReco/hTrackSize_unFiltered", "", {HistType::kTH2D, {{100, 0, 200000}, axisCentrality}}); + registry.add("trackMCReco/hTrackSize_Filtered", "", {HistType::kTH2D, {{100, 0, 20000}, axisCentrality}}); + 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::kTH3D, {axisPt, axisEta, axisCentrality}}); + registry.add("trackMCReco/after/incl/hPt_proton", "", {HistType::kTH3D, {axisPt, axisEta, axisCentrality}}); + registry.add("trackMCReco/after/incl/hPt_pion", "", {HistType::kTH3D, {axisPt, axisEta, axisCentrality}}); + registry.add("trackMCReco/after/incl/hPt_kaon", "", {HistType::kTH3D, {axisPt, axisEta, axisCentrality}}); + // Clone into particles and before/after + registry.addClone("trackMCReco/after/incl/", "trackMCReco/after/pos/"); + registry.addClone("trackMCReco/after/incl/", "trackMCReco/after/neg/"); + registry.addClone("trackMCReco/after/", "trackMCReco/before/"); + } + if (doprocessData) { + registry.add("QQCorrelations/qAqCX", "", kTProfile, {axisCent}); + registry.add("QQCorrelations/qAqCY", "", kTProfile, {axisCent}); + registry.add("QQCorrelations/qAqCXY", "", kTProfile, {axisCent}); + registry.add("QQCorrelations/qAXqCY", "", kTProfile, {axisCent}); + registry.add("QQCorrelations/qAYqCX", "", kTProfile, {axisCent}); + registry.add("QQCorrelations/qAXYqCXY", "", kTProfile, {axisCent}); + + if (cfgFillGeneralV1Histos) { + // track properties per centrality and per eta, pt bin + registry.add("incl/vnC", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/vnA", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + } + if (cfgFillPID) { + registry.add("incl/pion/vnC", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/vnA", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + + if (cfgFillEventPlane) { + registry.add("incl/pion/vnA_EP", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/vnC_EP", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/vnFull_EP", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + } + } + if (cfgFillXandYterms) { + registry.add("incl/vnAx", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/vnAy", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/vnCx", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/vnCy", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + if (cfgFillPID) { + registry.add("incl/pion/vnAx", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/vnAy", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/vnCx", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/vnCy", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + } + } + if (cfgFillMixedHarmonics) { + registry.add("incl/MH/vnAxCxUx_MH", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/MH/vnAyCyUx_MH", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/MH/vnAxCyUy_MH", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/MH/vnAyCxUy_MH", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + if (cfgFillPID) { + registry.add("incl/pion/MH/vnAxCxUx_MH", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/MH/vnAyCyUx_MH", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/MH/vnAxCyUy_MH", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/pion/MH/vnAyCxUy_MH", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + } + } + if (cfgFillEventPlane) { + registry.add("incl/vnA_EP", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/vnC_EP", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + registry.add("incl/vnFull_EP", "", kTProfile3D, {axisPt, axisEtaVn, axisCentrality}); + } + if (cfgFillEventPlaneQA) { + histos.add("QA/hSPplaneA", "hSPplaneA", kTH1D, {axisPhiPlane}); + histos.add("QA/hSPplaneC", "hSPplaneC", kTH1D, {axisPhiPlane}); + histos.add("QA/hSPplaneFull", "hSPplaneFull", kTH1D, {axisPhiPlane}); + histos.add("QA/hCosPhiACosPhiC", "hCosPhiACosPhiC; Centrality(%); #LT Cos(#Psi^{A})Cos(#Psi^{C})#GT", kTProfile, {axisCent}); + histos.add("QA/hSinPhiASinPhiC", "hSinPhiASinPhiC; Centrality(%); #LT Sin(#Psi^{A})Sin(#Psi^{C})#GT", kTProfile, {axisCent}); + histos.add("QA/hSinPhiACosPhiC", "hSinPhiACosPhiC; Centrality(%); #LT Sin(#Psi^{A})Cos(#Psi^{C})#GT", kTProfile, {axisCent}); + histos.add("QA/hCosPhiASinsPhiC", "hCosPhiASinsPhiC; Centrality(%); #LT Cos(#Psi^{A})Sin(#Psi^{C})#GT", kTProfile, {axisCent}); + histos.add("QA/hFullEvPlaneRes", "hFullEvPlaneRes; Centrality(%); -#LT Cos(#Psi^{A} - #Psi^{C})#GT ", kTProfile, {axisCent}); + } + if (cfgFillEventQA) { + histos.add("QA/hCentFull", " ; Centrality (%); ", {HistType::kTH1D, {axisCent}}); + } + } // end of doprocessData + if (cfgFillChargeDependence || cfgFillPID) { + registry.addClone("incl/pion/", "incl/proton/"); + registry.addClone("incl/pion/", "incl/kaon/"); + registry.addClone("incl/", "pos/"); + registry.addClone("incl/", "neg/"); + } + if (cfgFillPIDQA || cfgFillChargeDependenceQA) { + histos.addClone("incl/", "pos/"); + histos.addClone("incl/", "neg/"); + } + + } else if (doprocessMCGen) { + registry.add("trackMCGen/nCollReconstructedPerMcCollision", "", {HistType::kTH1D, {{10, -5, 5}}}); + registry.add("trackMCGen/after/incl/hPt_hadron", "", {HistType::kTH3D, {axisPt, axisEta, axisCentrality}}); + registry.add("trackMCGen/after/incl/hPt_proton", "", {HistType::kTH3D, {axisPt, axisEta, axisCentrality}}); + registry.add("trackMCGen/after/incl/hPt_pion", "", {HistType::kTH3D, {axisPt, axisEta, axisCentrality}}); + registry.add("trackMCGen/after/incl/hPt_kaon", "", {HistType::kTH3D, {axisPt, axisEta, axisCentrality}}); + registry.add("trackMCGen/after/incl/phi_eta_vtxZ_gen", "", {HistType::kTH3D, {axisPhi, axisEta, axisVz}}); + registry.addClone("trackMCGen/after/incl/", "trackMCGen/after/pos/"); + registry.addClone("trackMCGen/after/incl/", "trackMCGen/after/neg/"); + registry.addClone("trackMCGen/after/", "trackMCGen/before/"); + } + + if (cfgEvSelsUseAdditionalEventCut) { + fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + + std::vector paramsMultPVCut = cfgEvSelsMultPv; + std::vector paramsMultCut = cfgEvSelsMult; + + // number of parameters required in cfgEvSelsMultPv and cfgEvSelsMult. (5 Low + 5 High) + uint64_t nParams = 10; + + if (paramsMultPVCut.size() < nParams) { + LOGF(fatal, "cfgEvSelsMultPv not set properly.. size = %d (should be 10) --> Check your config files!", paramsMultPVCut.size()); + } else if (paramsMultCut.size() < nParams) { + LOGF(fatal, "cfgEvSelsMult not set properly.. size = %d (should be 10) --> Check your config files!", paramsMultCut.size()); + } else { + fMultPVCutLow->SetParameters(paramsMultPVCut[0], paramsMultPVCut[1], paramsMultPVCut[2], paramsMultPVCut[3], paramsMultPVCut[4]); + fMultPVCutHigh->SetParameters(paramsMultPVCut[5], paramsMultPVCut[6], paramsMultPVCut[7], paramsMultPVCut[8], paramsMultPVCut[9]); + fMultCutLow->SetParameters(paramsMultCut[0], paramsMultCut[1], paramsMultCut[2], paramsMultCut[3], paramsMultCut[4]); + fMultCutHigh->SetParameters(paramsMultCut[5], paramsMultCut[6], paramsMultCut[7], paramsMultCut[8], paramsMultCut[9]); + } + } + + if (cfgTrackSelsUseAdditionalTrackCut) { + 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); + } + } // end of init + + float getNUA2D(TH3D* hNUA, float eta, float phi, float vtxz) + { + int xind = hNUA->GetXaxis()->FindBin(phi); + int etaind = hNUA->GetYaxis()->FindBin(eta); + int vzind = hNUA->GetZaxis()->FindBin(vtxz); + float weight = hNUA->GetBinContent(xind, etaind, vzind); + if (weight != 0) + return 1. / weight; + return 1; + } + + template + ParticleType getTrackPID(TrackObject track) + { + + float usedNSigmaPi = -1; + float usedNSigmaKa = -1; + float usedNSigmaPr = -1; + + if (track.hasTOF() && track.hasTPC()) { + usedNSigmaPi = std::hypot(track.tofNSigmaPi(), track.tpcNSigmaPi()); + usedNSigmaKa = std::hypot(track.tofNSigmaKa(), track.tpcNSigmaKa()); + usedNSigmaPr = std::hypot(track.tofNSigmaPr(), track.tpcNSigmaPr()); + } else if (track.hasTOF()) { + usedNSigmaPi = track.tofNSigmaPi(); + usedNSigmaKa = track.tofNSigmaKa(); + usedNSigmaPr = track.tofNSigmaPr(); + } else if (track.hasTPC()) { + usedNSigmaPi = track.tpcNSigmaPi(); + usedNSigmaKa = track.tpcNSigmaKa(); + usedNSigmaPr = track.tpcNSigmaPr(); + } else { + return kUnidentified; // No PID information available + } + + std::unordered_map usedNSigma = {{usedNSigmaPi, kPions}, {usedNSigmaKa, kKaons}, {usedNSigmaPr, kProtons}}; + + int nIdentified = 0; + ParticleType valPID = kUnidentified; + + for (const auto& nsigma : usedNSigma) { + if (std::abs(nsigma.first) < cfgTrackSelsPIDNsigma) { + valPID = nsigma.second; + nIdentified++; + } + } + + if (nIdentified == 0) { + return kUnidentified; // No PID match found + } else if (nIdentified == 1) { + return valPID; + } else { + return kUnidentified; // Multiple PID matches found + } + } + + int getMagneticField(uint64_t timestamp) + { + // TODO done only once (and not per run). Will be replaced by CCDBConfigurable + 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(); + } + + std::pair getCrossingAngleCCDB(uint64_t timestamp) + { + // TODO done only once (and not per run). Will be replaced by CCDBConfigurable + auto grpo = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object for Crossing Angle not found for timestamp %llu", timestamp); + return {0, 0}; + } + float crossingAngle = grpo->getCrossingAngle(); + uint16_t crossingAngleTime = grpo->getCrossingAngleTime(); + return {crossingAngle, crossingAngleTime}; + } + + // 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 (cfguseNUA1D) { + if (cfgCCDB_NUA.value.empty() == false) { + TList* listCorrections = ccdb->getForTimeStamp(cfgCCDB_NUA, 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(fatal, "Could not load acceptance weights from %s", cfgCCDB_NUA.value.c_str()); + else + LOGF(info, "Loaded acceptance weights from %s", cfgCCDB_NUA.value.c_str()); + } else { + LOGF(info, "cfgCCDB_NUA empty! No corrections loaded"); + } + } else if (cfguseNUA2D) { + if (cfgCCDB_NUA.value.empty() == false) { + TH3D* hNUA2D = ccdb->getForTimeStamp(cfgCCDB_NUA, timestamp); + if (!hNUA2D) { + LOGF(fatal, "Could not load acceptance weights from %s", cfgCCDB_NUA.value.c_str()); + } else { + LOGF(info, "Loaded acceptance weights from %s", cfgCCDB_NUA.value.c_str()); + cfg.mAcceptance2D.push_back(hNUA2D); + } + } else { + LOGF(info, "cfgCCDB_NUA empty! No corrections loaded"); + } + } + // Get Efficiency correction + if (cfgCCDB_NUE.value.empty() == false) { + TList* listCorrections = ccdb->getForTimeStamp(cfgCCDB_NUE, 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", cfgCCDB_NUE.value.c_str()); + else + LOGF(info, "Loaded efficiency histogram from %s", cfgCCDB_NUE.value.c_str()); + } else { + LOGF(info, "cfgCCDB_NUE empty! No corrections loaded"); + } + // Get Efficiency correction + if (cfgCCDB_NUE2D.value.empty() == false) { + TList* listCorrections = ccdb->getForTimeStamp(cfgCCDB_NUE2D, timestamp); + cfg.mEfficiency2D.push_back(reinterpret_cast(listCorrections->FindObject("Efficiency2D"))); + cfg.mEfficiency2D.push_back(reinterpret_cast(listCorrections->FindObject("Efficiency2D_pos"))); + cfg.mEfficiency2D.push_back(reinterpret_cast(listCorrections->FindObject("Efficiency2D_neg"))); + int sizeEff = cfg.mEfficiency2D.size(); + if (sizeEff < nWeights) + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgCCDB_NUE.value.c_str()); + else + LOGF(info, "Loaded efficiency histogram from %s", cfgCCDB_NUE.value.c_str()); + } else { + LOGF(info, "cfgCCDB_NUE2 empty! No corrections loaded"); + } + cfg.correctionsLoaded = true; + } + + // From Generic Framework + bool setCurrentParticleWeights(int pID, int spec, const float& phi, const float& eta, const float& pt, const float& vtxz) + { + float eff = 1.; + int sizeEff = cfg.mEfficiency.size(); + if (sizeEff > pID) { + if (cfguseNUE2D) { + int binx = cfg.mEfficiency2D[pID]->GetXaxis()->FindBin(eta); + int biny = cfg.mEfficiency2D[pID]->GetYaxis()->FindBin(pt); + eff = cfg.mEfficiency2D[pID]->GetBinContent(binx, biny); + } else { + eff = cfg.mEfficiency[pID]->GetBinContent(cfg.mEfficiency[pID]->FindBin(pt)); + } + } else { + eff = 1.0; + } + if (eff == 0) + return false; + + spm.weff[pID][spec] = 1. / eff; + + if (cfguseNUA1D) { + int sizeAcc = cfg.mAcceptance.size(); + if (sizeAcc > pID) { + spm.wacc[pID][spec] = cfg.mAcceptance[pID]->getNUA(phi, eta, vtxz); + } else { + spm.wacc[pID][spec] = 1; + } + } else if (cfguseNUA2D) { + if (cfg.mAcceptance2D.size() > 0) { + spm.wacc[pID][spec] = getNUA2D(cfg.mAcceptance2D[0], eta, phi, vtxz); + } else { + spm.wacc[pID][spec] = 1; + } + } + return true; + } + + template + bool eventSelected(TCollision collision, const int& multTrk) + { + if (!collision.sel8()) + return 0; + histos.fill(HIST("hEventCount"), evSel_sel8); + + if (rctFlags.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return 0; + histos.fill(HIST("hEventCount"), evSel_RCTFlagsZDC); + + // Occupancy + if (cfgEvSelsDoOccupancySel) { + auto occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgEvSelsMaxOccupancy) { + return 0; + } + histos.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; + } + histos.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; + } + histos.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; + } + histos.fill(HIST("hEventCount"), evSel_kNoCollInTimeRangeStandard); + } + if (cfgEvSelsNoCollInTimeRangeNarrow) { + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + // Rejection of the collisions which have other events nearby + return 0; + } + histos.fill(HIST("hEventCount"), evSel_kNoCollInTimeRangeNarrow); + } + 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; + } + histos.fill(HIST("hEventCount"), evSel_kIsVertexITSTPC); + } + + 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; + } + histos.fill(HIST("hEventCount"), evSel_kIsGoodITSLayersAll); + } + if (cfgEvSelsIsGoodITSLayer0123) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + return 0; + } + histos.fill(HIST("hEventCount"), evSel_kIsGoodITSLayer0123); + } + + if (cfgEvSelsUseAdditionalEventCut) { + 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 > cfgEvSelsVtxZ || vtxz < -cfgEvSelsVtxZ) + 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; + + histos.fill(HIST("hEventCount"), evSel_MultCuts); + } + + return 1; + } + + template + bool trackSelected(TrackObject track, const int& field) + { + if (std::fabs(track.eta()) > cfgTrackSelsEta) + return false; + histos.fill(HIST("hTrackCount"), trackSel_Eta); + + if (track.pt() < cfgTrackSelsPtmin || track.pt() > cfgTrackSelsPtmax) + return false; + + histos.fill(HIST("hTrackCount"), trackSel_Pt); + + if (track.dcaXY() > cfgTrackSelsDCAxy) + return false; + + histos.fill(HIST("hTrackCount"), trackSel_DCAxy); + + if (track.dcaZ() > cfgTrackSelsDCAz) + return false; + + if (cfgTrackSelsDoDCApt && std::fabs(track.dcaZ()) > (cfgTrackSelsDCApt1 * cfgTrackSelsDCApt2) / (std::pow(track.pt(), 1.1))) + return false; + + histos.fill(HIST("hTrackCount"), trackSel_DCAz); + + if (track.tpcNClsFound() < cfgTrackSelsNcls) + return false; + histos.fill(HIST("hTrackCount"), trackSel_NCls); + + if (track.tpcFractionSharedCls() > cfgTrackSelsFshcls) + return false; + histos.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 (cfgFillTrackQA && cfgFillQABefore) + histos.fill(HIST("incl/QA/before/pt_phi"), track.pt(), phimodn); + + if (cfgTrackSelsUseAdditionalTrackCut) { + if (phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt())) + return false; // reject track + } + if (cfgFillTrackQA) + histos.fill(HIST("incl/QA/after/pt_phi"), track.pt(), phimodn); + histos.fill(HIST("hTrackCount"), trackSel_TPCBoundary); + return true; + } + + template + inline void fillEventQA(CollisionObject collision, TracksObject tracks) + { + if (!cfgFillEventQA) + return; + + static constexpr std::string_view Time[] = {"before", "after"}; + + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFT0C"), collision.centFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentNGlobal"), collision.centNGlobal(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFT0M"), collision.centFT0M(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/hCentFV0A"), collision.centFV0A(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_centT0C"), collision.centFT0C(), tracks.size(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_multT0A"), collision.multFT0A(), tracks.size(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/globalTracks_multV0A"), collision.multFV0A(), tracks.size(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/multV0A_multT0A"), collision.multFT0A(), collision.multFV0A(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/multT0C_centT0C"), collision.centFT0C(), collision.multFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFT0Cvariant1"), collision.centFT0C(), collision.centFT0CVariant1(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFT0M"), collision.centFT0C(), collision.centFT0M(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentFV0A"), collision.centFT0C(), collision.centFV0A(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/CentFT0C_vs_CentNGlobal"), collision.centFT0C(), collision.centNGlobal(), spm.centWeight); + + if (cfgFillEventPlaneQA) { + if constexpr (o2::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()); + + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Cent"), psiA, collision.centFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Cent"), psiC, collision.centFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Cent"), psiFull, collision.centFT0C(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vx"), psiA, collision.vertex()[0], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vx"), psiC, collision.vertex()[0], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vx"), psiFull, collision.vertex()[0], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vy"), psiA, collision.vertex()[1], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vy"), psiC, collision.vertex()[1], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vy"), psiFull, collision.vertex()[1], spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiA_vs_Vz"), psiA, collision.posZ(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiC_vs_Vz"), psiC, collision.posZ(), spm.centWeight); + histos.fill(HIST("QA/") + HIST(Time[ft]) + HIST("/PsiFull_vs_Vz"), psiFull, collision.posZ(), spm.centWeight); + } + } + return; + } + + template + inline void fillHistograms(TrackObject track) + { + double weight = spm.wacc[ct][pt] * spm.weff[ct][pt] * spm.centWeight; + + if (cfgFillGeneralV1Histos) { + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnA"), track.pt(), track.eta(), spm.centrality, (spm.uy * spm.qyA + spm.ux * spm.qxA) / std::sqrt(std::fabs(spm.corrQQ)), weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnC"), track.pt(), track.eta(), spm.centrality, (spm.uy * spm.qyC + spm.ux * spm.qxC) / std::sqrt(std::fabs(spm.corrQQ)), weight); + } + + if (cfgFillMixedHarmonics) { + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("MH/vnAxCxUx_MH"), track.pt(), track.eta(), spm.centrality, (spm.uxMH * spm.qxA * spm.qxC) / spm.corrQQx, weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("MH/vnAyCyUx_MH"), track.pt(), track.eta(), spm.centrality, (spm.uxMH * spm.qyA * spm.qyC) / spm.corrQQy, weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("MH/vnAxCyUy_MH"), track.pt(), track.eta(), spm.centrality, (spm.uyMH * spm.qxA * spm.qyC) / spm.corrQQx, weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("MH/vnAyCxUy_MH"), track.pt(), track.eta(), spm.centrality, (spm.uyMH * spm.qyA * spm.qxC) / spm.corrQQy, weight); + } + + if (cfgFillXandYterms) { + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnAx"), track.pt(), track.eta(), spm.centrality, (spm.ux * spm.qxA) / std::sqrt(std::fabs(spm.corrQQx)), weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnAy"), track.pt(), track.eta(), spm.centrality, (spm.uy * spm.qyA) / std::sqrt(std::fabs(spm.corrQQy)), weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnCx"), track.pt(), track.eta(), spm.centrality, (spm.ux * spm.qxC) / std::sqrt(std::fabs(spm.corrQQx)), weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnCy"), track.pt(), track.eta(), spm.centrality, (spm.uy * spm.qyC) / std::sqrt(std::fabs(spm.corrQQy)), weight); + } + + if (cfgFillEventPlane) { // only fill for inclusive! + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnA_EP"), track.pt(), track.eta(), spm.centrality, spm.vnA, weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnC_EP"), track.pt(), track.eta(), spm.centrality, spm.vnC, weight); + registry.fill(HIST(Charge[ct]) + HIST(Species[pt]) + HIST("vnFull_EP"), track.pt(), track.eta(), spm.centrality, spm.vnFull, weight); + } + } + + template + inline void fillTrackQA(TrackObject track) + { + if (!cfgFillTrackQA) + return; + + static constexpr std::string_view Time[] = {"before/", "after/"}; + // NOTE: species[kUnidentified] = "" (when nocfgTrackSelDo) { + if (cfgTrackSelDoTrackQAvsCent) { + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPt_Eta"), track.pt(), track.eta(), spm.centrality, spm.wacc[ct][par] * spm.weff[ct][par]); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPt_Eta_uncorrected"), track.pt(), track.eta(), spm.centrality); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPhi_Eta"), track.phi(), track.eta(), spm.centrality, spm.wacc[ct][par] * spm.weff[ct][par]); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPhi_Eta_uncorrected"), track.phi(), track.eta(), spm.centrality); + } else { + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPhi_Eta_Pt"), track.phi(), track.eta(), track.pt()); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPhi_Eta_Pt_corrected"), track.phi(), track.eta(), track.pt(), spm.wacc[ct][par] * spm.weff[ct][par]); + } + + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPhi_Eta_vz"), track.phi(), track.eta(), spm.vz); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hPhi_Eta_vz_corrected"), track.phi(), track.eta(), spm.vz, spm.wacc[ct][par]); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hDCAxy_pt"), track.pt(), track.dcaXY(), spm.wacc[ct][par] * spm.weff[ct][par]); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hDCAz_pt"), track.pt(), track.dcaZ(), spm.wacc[ct][par] * spm.weff[ct][par]); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hSharedClusters_pt"), track.pt(), track.tpcFractionSharedCls(), spm.wacc[ct][par] * spm.weff[ct][par]); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hCrossedRows_pt"), track.pt(), track.tpcNClsFound(), spm.wacc[ct][par] * spm.weff[ct][par]); + histos.fill(HIST(Charge[ct]) + HIST(Species[par]) + HIST("QA/") + HIST(Time[ft]) + HIST("hCrossedRows_vs_SharedClusters"), track.tpcNClsFound(), track.tpcFractionSharedCls(), spm.wacc[ct][par] * spm.weff[ct][par]); + } + + template + inline void fillPIDQA(TrackObject track) + { + if (!cfgFillPIDQA || !cfgFillTrackQA) + return; + + histos.fill(HIST(Charge[ct]) + HIST("pion/") + HIST("QA/") + HIST(Time[ft]) + HIST("hNsigmaTOF_pt"), track.pt(), track.tofNSigmaPi()); + histos.fill(HIST(Charge[ct]) + HIST("pion/") + HIST("QA/") + HIST(Time[ft]) + HIST("hNsigmaTPC_pt"), track.pt(), track.tpcNSigmaPi()); + histos.fill(HIST(Charge[ct]) + HIST("kaon/") + HIST("QA/") + HIST(Time[ft]) + HIST("hNsigmaTOF_pt"), track.pt(), track.tofNSigmaKa()); + histos.fill(HIST(Charge[ct]) + HIST("kaon/") + HIST("QA/") + HIST(Time[ft]) + HIST("hNsigmaTPC_pt"), track.pt(), track.tpcNSigmaKa()); + histos.fill(HIST(Charge[ct]) + HIST("proton/") + HIST("QA/") + HIST(Time[ft]) + HIST("hNsigmaTOF_pt"), track.pt(), track.tofNSigmaPr()); + histos.fill(HIST(Charge[ct]) + HIST("proton/") + HIST("QA/") + HIST(Time[ft]) + HIST("hNsigmaTPC_pt"), track.pt(), track.tpcNSigmaPr()); + histos.fill(HIST(Charge[ct]) + HIST("QA/") + HIST(Time[ft]) + HIST("hdEdxTPC_pt"), track.pt(), track.tpcSignal()); + histos.fill(HIST(Charge[ct]) + HIST("QA/") + HIST(Time[ft]) + HIST("hBetaTOF_pt"), track.pt(), track.beta()); + } + + 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(), track.eta(), spm.centrality); + if (pdgCode > 0) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("pos/hPt_hadron"), track.pt(), track.eta(), spm.centrality); + } else { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("neg/hPt_hadron"), track.pt(), track.eta(), spm.centrality); + } + + if (pdgCode == kPiPlus || pdgCode == kPiMinus) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("incl/hPt_pion"), track.pt(), track.eta(), spm.centrality); + if (pdgCode == kPiPlus) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("pos/hPt_pion"), track.pt(), track.eta(), spm.centrality); + } else { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("neg/hPt_pion"), track.pt(), track.eta(), spm.centrality); + } + } else if (pdgCode == kKPlus || pdgCode == kKMinus) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("incl/hPt_kaon"), track.pt(), track.eta(), spm.centrality); + if (pdgCode == kKPlus) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("pos/hPt_kaon"), track.pt(), track.eta(), spm.centrality); + } else { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("neg/hPt_kaon"), track.pt(), track.eta(), spm.centrality); + } + } else if (pdgCode == kProton || pdgCode == kProtonBar) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("incl/hPt_proton"), track.pt(), track.eta(), spm.centrality); + if (pdgCode == kProton) { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("pos/hPt_proton"), track.pt(), track.eta(), spm.centrality); + } else { + registry.fill(HIST("trackMC") + HIST(Mode[md]) + HIST(Time[ft]) + HIST("neg/hPt_proton"), track.pt(), track.eta(), spm.centrality); + } + } + } + + template + inline void fillPrimaryHistos(McParticleObject mcparticle) + { + static constexpr std::string_view Time[] = {"/before", "/after"}; + + if (!mcparticle.isPhysicalPrimary()) { + registry.fill(HIST("trackMCReco") + HIST(Time[ft]) + HIST("/hIsPhysicalPrimary"), 0, spm.centrality); + } else { + registry.fill(HIST("trackMCReco") + HIST(Time[ft]) + HIST("/hIsPhysicalPrimary"), 1, spm.centrality); + } + } + + template + void fillAllQA(TrackObject track) + { + fillTrackQA(track); + fillPIDQA(track); + + if (cfgFillChargeDependenceQA) { + switch (spm.charge) { + case kPositive: { + fillTrackQA(track); + fillPIDQA(track); + break; + } + case kNegative: { + fillTrackQA(track); + fillPIDQA(track); + break; + } + } + } + } + + void processData(ZDCCollisions::iterator const& collision, aod::BCsWithTimestamps const&, UsedTracks const& tracks) + { + + histos.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) { + cfg.correctionsLoaded = false; + cfg.clCentrality = false; + cfg.lastRunNumber = bc.runNumber(); + cfg.mAcceptance.clear(); + LOGF(info, "Size of mAcceptance: %i (should be 0)", (int)cfg.mAcceptance.size()); + } + + if (cfgFillQABefore) + fillEventQA(collision, tracks); + + loadCorrections(bc.timestamp()); + + spm.centrality = collision.centFT0C(); + + if (cfgCentFT0Cvariant1) + spm.centrality = collision.centFT0CVariant1(); + if (cfgCentFT0M) + spm.centrality = collision.centFT0M(); + if (cfgCentFV0A) + spm.centrality = collision.centFV0A(); + if (cfgCentNGlobal) + spm.centrality = collision.centNGlobal(); + + if (!eventSelected(collision, tracks.size())) + return; + + if (!collision.isSelected()) // selected by ZDCQVectors task (checks signal in ZDC) --> only possible in data not MC + return; + histos.fill(HIST("hEventCount"), evSel_isSelectedZDC); + + spm.qxA = collision.qxA(); + spm.qyA = collision.qyA(); + spm.qxC = collision.qxC(); + spm.qyC = collision.qyC(); + + spm.vz = collision.posZ(); + float vtxz = collision.posZ(); + + double psiA = 1.0 * std::atan2(spm.qyA, spm.qxA); + double psiC = 1.0 * std::atan2(spm.qyC, spm.qxC); + + // https://twiki.cern.ch/twiki/pub/ALICE/DirectedFlowAnalysisNote/vn_ZDC_ALICE_INT_NOTE_version02.pdf + double psiFull = 1.0 * std::atan2(spm.qyA + spm.qyC, spm.qxA + spm.qxC); + + // always fill these histograms! + registry.fill(HIST("QQCorrelations/qAqCXY"), spm.centrality, spm.qxA * spm.qxC + spm.qyA * spm.qyC); + registry.fill(HIST("QQCorrelations/qAXqCY"), spm.centrality, spm.qxA * spm.qyC); + registry.fill(HIST("QQCorrelations/qAYqCX"), spm.centrality, spm.qyA * spm.qxC); + registry.fill(HIST("QQCorrelations/qAXYqCXY"), spm.centrality, spm.qyA * spm.qxC + spm.qxA * spm.qyC); + registry.fill(HIST("QQCorrelations/qAqCX"), spm.centrality, spm.qxA * spm.qxC); + registry.fill(HIST("QQCorrelations/qAqCY"), spm.centrality, spm.qyA * spm.qyC); + + if (cfgFillEventQA) { + histos.fill(HIST("QA/hCentFull"), spm.centrality, 1); + } + if (cfgFillEventPlaneQA) { + histos.fill(HIST("QA/hSPplaneA"), psiA, 1); + histos.fill(HIST("QA/hSPplaneC"), psiC, 1); + histos.fill(HIST("QA/hSPplaneFull"), psiFull, 1); + histos.fill(HIST("QA/hCosPhiACosPhiC"), spm.centrality, std::cos(psiA) * std::cos(psiC)); + histos.fill(HIST("QA/hSinPhiASinPhiC"), spm.centrality, std::sin(psiA) * std::sin(psiC)); + histos.fill(HIST("QA/hSinPhiACosPhiC"), spm.centrality, std::sin(psiA) * std::cos(psiC)); + histos.fill(HIST("QA/hCosPhiASinsPhiC"), spm.centrality, std::cos(psiA) * std::sin(psiC)); + histos.fill(HIST("QA/hFullEvPlaneRes"), spm.centrality, -1 * std::cos(psiA - psiC)); + } + + if (spm.centrality > cfgCentMax || spm.centrality < cfgCentMin) + return; + + histos.fill(HIST("hEventCount"), evSel_CentCuts); + + // Load correlations and SP resolution needed for Scalar Product and event plane methods. + // Only load once! + // If not loaded set to 1 + + if (cfgCCDBdir_QQ.value.empty() == false) { + if (!cfg.clQQ) { + TList* hcorrList = ccdb->getForTimeStamp(cfgCCDBdir_QQ.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; + } + spm.corrQQ = cfg.hcorrQQ->GetBinContent(cfg.hcorrQQ->FindBin(spm.centrality)); + spm.corrQQx = cfg.hcorrQQx->GetBinContent(cfg.hcorrQQx->FindBin(spm.centrality)); + spm.corrQQy = cfg.hcorrQQy->GetBinContent(cfg.hcorrQQy->FindBin(spm.centrality)); + } + + double evPlaneRes = 1.; + if (cfgCCDBdir_SP.value.empty() == false) { + if (!cfg.clEvPlaneRes) { + cfg.hEvPlaneRes = ccdb->getForTimeStamp(cfgCCDBdir_SP.value, bc.timestamp()); + cfg.clEvPlaneRes = true; + } + evPlaneRes = cfg.hEvPlaneRes->GetBinContent(cfg.hEvPlaneRes->FindBin(spm.centrality)); + if (evPlaneRes < 0) + LOGF(fatal, " > 0 for centrality %.2f! Cannot determine resolution.. Change centrality ranges!!!", spm.centrality); + evPlaneRes = std::sqrt(evPlaneRes); + } + + if (cfgCCDBdir_centrality.value.empty() == false) { + if (!cfg.clCentrality) { + cfg.hCentrality = ccdb->getForTimeStamp(cfgCCDBdir_centrality.value, bc.timestamp()); + cfg.clCentrality = true; + } + spm.centWeight = cfg.hCentrality->GetBinContent(cfg.hCentrality->FindBin(spm.centrality)); + if (spm.centWeight < 0) + LOGF(fatal, "Centrality weight cannot be negative.. abort for (%.2f)", spm.centrality); + } + + fillEventQA(collision, tracks); + + for (const auto& track : tracks) { + + ParticleType trackPID = (cfgFillPID || cfgFillPIDQA) ? getTrackPID(track) : kUnidentified; + + if (cfgFillPIDQA) + histos.fill(HIST("hPIDcounts"), trackPID, track.pt()); + + if (track.sign() == 0) + continue; + + histos.fill(HIST("hTrackCount"), trackSel_ZeroCharge); + + spm.charge = ((track.sign() > 0)) ? kPositive : kNegative; + + if (cfgFillQABefore) { + fillAllQA(track); + if (cfgFillPIDQA) { + switch (trackPID) { + case kPions: + fillAllQA(track); + break; + case kKaons: + fillAllQA(track); + break; + case kProtons: + fillAllQA(track); + break; + default: /* do nothing */ + break; + } + } + } + + if (!trackSelected(track, field)) + continue; + + // constrain angle to 0 -> [0,0+2pi] + auto phi = RecoDecay::constrainAngle(track.phi(), 0); + + // Fill NUA weights (last 0 is for Data see GFWWeights class (not a weight)) + // ToDo: Add pi, ka, proton here! + if (cfgFillWeights) { + fWeights->fill(phi, track.eta(), spm.vz, track.pt(), spm.centrality, 0); + registry.fill(HIST("weights2D/hPhi_Eta_vz"), phi, track.eta(), spm.vz, 1); + } + if (cfgFillWeightsPOS && spm.charge == kPositive) { + fWeightsPOS->fill(phi, track.eta(), spm.vz, track.pt(), spm.centrality, 0); + registry.fill(HIST("weights2D/hPhi_Eta_vz_positive"), phi, track.eta(), spm.vz, 1); + } + if (cfgFillWeightsNEG && spm.charge == kNegative) { + fWeightsNEG->fill(phi, track.eta(), spm.vz, track.pt(), spm.centrality, 0); + registry.fill(HIST("weights2D/hPhi_Eta_vz_negative"), phi, track.eta(), spm.vz, 1); + } + + // Set weff and wacc for inclusive, negative and positive hadrons + if (!setCurrentParticleWeights(kInclusive, kUnidentified, phi, track.eta(), track.pt(), vtxz)) + continue; + if (!setCurrentParticleWeights(spm.charge, kUnidentified, phi, track.eta(), track.pt(), vtxz)) + continue; + + histos.fill(HIST("hTrackCount"), trackSel_ParticleWeights); + + fillAllQA(track); + if (cfgFillPIDQA) { + switch (trackPID) { + case kPions: + fillAllQA(track); + break; + case kKaons: + fillAllQA(track); + break; + case kProtons: + fillAllQA(track); + break; + default: /* do nothing */ + break; + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + spm.ux = std::cos(cfgHarm * phi); + spm.uy = std::sin(cfgHarm * phi); + + spm.uxMH = std::cos(cfgHarmMixed * phi); + spm.uyMH = std::sin(cfgHarmMixed * phi); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + spm.vnA = std::cos(cfgHarm * (phi - psiA)) / evPlaneRes; + spm.vnC = std::cos(cfgHarm * (phi - psiC)) / evPlaneRes; + spm.vnFull = std::cos(cfgHarm * (phi - psiFull)) / evPlaneRes; + + fillHistograms(track); + + if (cfgFillChargeDependence) { + switch (spm.charge) { + case kPositive: + fillHistograms(track); + break; + case kNegative: + fillHistograms(track); + break; + } + } + + if (cfgFillPID) { + switch (trackPID) { + case kPions: + fillHistograms(track); + break; + case kKaons: + fillHistograms(track); + break; + case kProtons: + fillHistograms(track); + break; + default: /* do nothing */ + break; + } + if (cfgFillChargeDependence) { + switch (spm.charge) { + case kPositive: { + switch (trackPID) { + case kPions: + fillHistograms(track); + break; + case kKaons: + fillHistograms(track); + break; + case kProtons: + fillHistograms(track); + break; + default: /* do nothing */ + break; + } + break; + } + case kNegative: { + switch (trackPID) { + case kPions: + fillHistograms(track); + break; + case kKaons: + fillHistograms(track); + break; + case kProtons: + fillHistograms(track); + break; + default: /* do nothing */ + break; + } + break; + } + } + } + } // end of fillPID + + } // end of track 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; + + spm.vz = collision.posZ(); + spm.centrality = collision.centFT0C(); + if (cfgCentFT0Cvariant1) + spm.centrality = collision.centFT0CVariant1(); + if (cfgCentFT0M) + spm.centrality = collision.centFT0M(); + if (cfgCentFV0A) + spm.centrality = collision.centFV0A(); + if (cfgCentNGlobal) + spm.centrality = collision.centNGlobal(); + + if (cfgFillQABefore) + fillEventQA(collision, filteredTracks); + + if (!eventSelected(collision, filteredTracks.size())) + return; + + if (spm.centrality > cfgCentMax || spm.centrality < cfgCentMin) + return; + + histos.fill(HIST("hEventCount"), evSel_CentCuts); + + if (!collision.has_mcCollision()) { + LOGF(info, "No mccollision found for this collision"); + return; + } + + fillEventQA(collision, filteredTracks); + + registry.fill(HIST("trackMCReco/hTrackSize_unFiltered"), tracks.size(), spm.centrality); + registry.fill(HIST("trackMCReco/hTrackSize_Filtered"), filteredTracks.size(), spm.centrality); + + for (const auto& track : filteredTracks) { + auto mcParticle = track.mcParticle(); + if (track.sign() == 0.0) + continue; + histos.fill(HIST("hTrackCount"), trackSel_ZeroCharge); + + fillMCPtHistos(track, mcParticle.pdgCode()); + fillPrimaryHistos(mcParticle); + + if (!mcParticle.isPhysicalPrimary()) + continue; + + spm.charge = (track.sign() > 0) ? kPositive : kNegative; + + int minVal = 100; + if (cfgFilterLeptons && std::abs(mcParticle.pdgCode()) < minVal) { + continue; + } + + // This neglects PID (for now) later use getPID like in data. + if (cfgFillQABefore) { + fillAllQA(track); + if (cfgFillPIDQA) { + switch (std::abs(mcParticle.pdgCode())) { + case kPiPlus: + fillAllQA(track); + break; + case kKPlus: + fillAllQA(track); + break; + case kProton: + fillAllQA(track); + break; + } + } + } + + if (!trackSelected(track, field)) + continue; + + fillMCPtHistos(track, mcParticle.pdgCode()); + + fillAllQA(track); + + if (cfgFillPIDQA) { + switch (std::abs(mcParticle.pdgCode())) { + case kPions: + fillAllQA(track); + break; + case kKaons: + fillAllQA(track); + break; + case kProtons: + fillAllQA(track); + break; + } + } + + fillPrimaryHistos(mcParticle); + + } // end of track loop + } + PROCESS_SWITCH(FlowSP, processMCReco, "Process analysis for MC reconstructed events", false); + + void processMCGen(aod::McCollisions const& mcCollisions, CCs const& collisions, TCs const& tracks, FilteredTCs const& filteredTracks, MCs const& McParts) + { + + for (const auto& mcCollision : mcCollisions) { + spm.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()); + + spm.centrality = col.centFT0C(); + if (cfgCentFT0Cvariant1) + spm.centrality = col.centFT0CVariant1(); + if (cfgCentFT0M) + spm.centrality = col.centFT0M(); + if (cfgCentFV0A) + spm.centrality = col.centFV0A(); + if (cfgCentNGlobal) + spm.centrality = col.centNGlobal(); + + if (cfgFillQABefore) + fillEventQA(col, filteredTrackSlice); + + if (trackSlice.size() < 1) { + colSelected = false; + continue; + } + if (!eventSelected(col, filteredTrackSlice.size())) { + colSelected = false; + continue; + } + + if (spm.centrality > cfgCentMax || spm.centrality < cfgCentMin) { + colSelected = false; + continue; + } + histos.fill(HIST("hEventCount"), evSel_CentCuts); + + fillEventQA(col, filteredTrackSlice); + + } // leave reconstructed collision loop + + if (!colSelected) + continue; + + float vtxz = mcCollision.posZ(); + + for (const auto& particle : partSlice) { + if (!particle.isPhysicalPrimary()) + continue; + + auto pdgCode = particle.pdgCode(); + auto pdgInfo = pdg->GetParticle(pdgCode); + + if (std::abs(pdgInfo->Charge()) < 1) + continue; + + spm.charge = (pdgInfo->Charge() > 0) ? kPositive : kNegative; + + int minVal = 100; + if (cfgFilterLeptons && std::abs(pdgCode) < minVal) { + continue; + } + + fillMCPtHistos(particle, pdgCode); + + registry.fill(HIST("trackMCGen/before/incl/phi_eta_vtxZ_gen"), particle.phi(), particle.eta(), vtxz); + + if (spm.charge == kPositive) { + 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() < -cfgTrackSelsEta || particle.eta() > cfgTrackSelsEta || particle.pt() < cfgTrackSelsPtmin || particle.pt() > cfgTrackSelsPtmax) + continue; + + fillMCPtHistos(particle, pdgCode); + + registry.fill(HIST("trackMCGen/after/incl/phi_eta_vtxZ_gen"), particle.phi(), particle.eta(), vtxz); + + if (spm.charge == kPositive) { + 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..0bf14f15405 --- /dev/null +++ b/PWGCF/Flow/Tasks/flowTask.cxx @@ -0,0 +1,1284 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "FlowContainer.h" +#include "FlowPtContainer.h" +#include "GFW.h" +#include "GFWConfig.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include +#include + +#include "TList.h" +#include +#include +#include +#include + +#include +#include +#include +#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 { + + // Basic event&track selections + 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(cfgEtaPtPt, float, 0.4, "eta range for pt-pt correlations") + O2_DEFINE_CONFIGURABLE(cfgEtaSubPtPt, float, 0.8, "eta range for subevent pt-pt correlations") + O2_DEFINE_CONFIGURABLE(cfgEtaGapPtPt, float, 0.2, "eta gap for pt-pt correlations, cfgEtaGapPtPt<|eta|> 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 cfgUserPtVnCorrConfig{"cfgUserPtVnCorrConfig", {{"refP {2} refN {-2}", "refP {3} refN {-3}"}, {"ChGap22", "ChGap32"}, {0, 0}, {3, 3}}, "Configurations for vn-pt correlations"}; + Configurable> cfgRunRemoveList{"cfgRunRemoveList", std::vector{-1}, "excluded run numbers"}; + struct : ConfigurableGroup { + 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"}; + O2_DEFINE_CONFIGURABLE(cfgMultCentHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 10.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCentLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultT0CCutEnabled, bool, false, "Enable Global multiplicity vs T0C centrality cut") + Configurable> cfgMultT0CCutPars{"cfgMultT0CCutPars", std::vector{143.04, -4.58368, 0.0766055, -0.000727796, 2.86153e-06, 23.3108, -0.36304, 0.00437706, -4.717e-05, 1.98332e-07}, "Global multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultPVT0CCutEnabled, bool, false, "Enable PV multiplicity vs T0C centrality cut") + Configurable> cfgMultPVT0CCutPars{"cfgMultPVT0CCutPars", std::vector{195.357, -6.15194, 0.101313, -0.000955828, 3.74793e-06, 30.0326, -0.43322, 0.00476265, -5.11206e-05, 2.13613e-07}, "PV multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultMultPVHighCutFunction, std::string, "[0]+[1]*x + 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultPVLowCutFunction, std::string, "[0]+[1]*x - 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCutEnabled, bool, false, "Enable global multiplicity vs PV multiplicity cut") + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", std::vector{-0.140809, 0.734344, 2.77495, 0.0165935}, "PV multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultMultV0AHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 4.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ALowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ACutEnabled, bool, false, "Enable global multiplicity vs V0A multiplicity cut") + Configurable> cfgMultMultV0ACutPars{"cfgMultMultV0ACutPars", std::vector{534.893, 184.344, 0.423539, -0.00331436, 5.34622e-06, 871.239, 53.3735, -0.203528, 0.000122758, 5.41027e-07}, "Global multiplicity vs V0A multiplicity cut parameter values"}; + std::vector multT0CCutPars; + std::vector multPVT0CCutPars; + std::vector multGlobalPVCutPars; + std::vector multMultV0ACutPars; + TF1* fMultPVT0CCutLow = nullptr; + TF1* fMultPVT0CCutHigh = nullptr; + TF1* fMultT0CCutLow = nullptr; + TF1* fMultT0CCutHigh = nullptr; + TF1* fMultGlobalPVCutLow = nullptr; + TF1* fMultGlobalPVCutHigh = nullptr; + TF1* fMultMultV0ACutLow = nullptr; + TF1* fMultMultV0ACutHigh = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + // for TPC sector boundary + O2_DEFINE_CONFIGURABLE(cfgShowTPCsectorOverlap, bool, true, "Draw TPC sector overlap") + O2_DEFINE_CONFIGURABLE(cfgRejectionTPCsectorOverlap, bool, false, "rejection for TPC sector overlap") + O2_DEFINE_CONFIGURABLE(cfgMagnetField, std::string, "GLO/Config/GRPMagField", "CCDB path to Magnet field object") + ConfigurableAxis axisPhiMod{"axisPhiMod", {100, 0, constants::math::PI / 9}, "fmod(#varphi,#pi/9)"}; + O2_DEFINE_CONFIGURABLE(cfgTPCPhiCutLowCutFunction, std::string, "0.1/x-0.005", "Function for TPC mod phi-pt cut"); + O2_DEFINE_CONFIGURABLE(cfgTPCPhiCutHighCutFunction, std::string, "0.1/x+0.01", "Function for TPC mod phi-pt cut"); + O2_DEFINE_CONFIGURABLE(cfgTPCPhiCutPtMin, float, 2.0f, "start point of phi-pt cut") + TF1* fPhiCutLow = nullptr; + TF1* fPhiCutHigh = nullptr; + // for deltaPt/ vs centrality + O2_DEFINE_CONFIGURABLE(cfgDptDisEnable, bool, false, "Produce deltaPt/meanPt vs centrality") + O2_DEFINE_CONFIGURABLE(cfgDptDisSelectionSwitch, int, 0, "0: disable, 1: use low cut, 2:use high cut") + TH1D* hEvAvgMeanPt = nullptr; + TH1D* fDptDisCutLow = nullptr; + TH1D* fDptDisCutHigh = nullptr; + O2_DEFINE_CONFIGURABLE(cfgDptDishEvAvgMeanPt, std::string, "", "CCDB path to hMeanPt object") + O2_DEFINE_CONFIGURABLE(cfgDptDisCutLow, std::string, "", "CCDB path to dpt lower boundary") + O2_DEFINE_CONFIGURABLE(cfgDptDisCutHigh, std::string, "", "CCDB path to dpt higher boundary") + ConfigurableAxis cfgDptDisAxisNormal{"cfgDptDisAxisNormal", {200, -1., 1.}, "normalized axis"}; + // Functional form of pt-dependent DCAxy cut + TF1* fPtDepDCAxy = nullptr; + O2_DEFINE_CONFIGURABLE(cfgDCAxyNSigma, float, 0, "0: disable; Cut on number of sigma deviations from expected DCA in the transverse direction, nsigma=7 is the same with global track"); + O2_DEFINE_CONFIGURABLE(cfgDCAxy, std::string, "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"); + } cfgFuncParas; + + 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); + using FilteredCollisions = soa::Filtered>; + using FilteredTracks = soa::Filtered>; + // Filter for MCcollisions + Filter mccollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; + using FilteredMcCollisions = soa::Filtered; + // Filter for MCParticle + Filter particleFilter = (nabs(aod::mcparticle::eta) < cfgCutEta) && (aod::mcparticle::pt > cfgCutPtMin) && (aod::mcparticle::pt < cfgCutPtMax); + using FilteredMcParticles = soa::Filtered; + + using FilteredSmallGroupMcCollisions = soa::SmallGroups>; + + // Corrections + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + bool correctionsLoaded = false; + + // Connect to ccdb + Service ccdb; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + OutputObj fFCgen{FlowContainer("FlowContainer_gen")}; + OutputObj fFCpt{FlowPtContainer("FlowPtContainer")}; + OutputObj fFCptgen{FlowPtContainer("FlowPtContainer_gen")}; + OutputObj fWeights{GFWWeights("weights")}; + HistogramRegistry registry{"registry"}; + + // define global variables + GFW* fGFW = new GFW(); + std::vector corrconfigs; + GFWCorrConfigs gfwConfigs; + std::vector corrconfigsPtVn; + TAxis* fPtAxis; + TRandom3* fRndm = new TRandom3(0); + std::vector>> bootstrapArray; + int lastRunNumber = -1; + std::vector runNumbers; + std::map> th3sPerRun; // map of TH3 histograms for all runs + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + // Count the total number of enum + kCount_CentEstimators + }; + enum DataType { + kReco, + kGen + }; + enum DptCut { + kNoDptCut = 0, + kLowDptCut = 1, + kHighDptCut = 2 + }; + enum BootstrapHist { + kMeanPtWithinGap08 = 0, + kCount_BootstrapHist + }; + 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; + + 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); + auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + // 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, {{12, 0, 12}}}); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(3, "kNoITSROFrameBorder"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(4, "kNoTimeFrameBorder"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(5, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(6, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(7, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(8, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(9, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(10, "occupancy"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(11, "MultCorrelation"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(12, "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, {{100, 0, 100}}}); + if (doprocessMCGen) { + registry.add("MCGen/MChVtxZ", "Vexter Z distribution", {HistType::kTH1D, {axisVertex}}); + registry.add("MCGen/MChMult", "Multiplicity distribution", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + registry.add("MCGen/MChCent", hCentTitle.c_str(), {HistType::kTH1D, {{100, 0, 100}}}); + } + 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("pt_phi_bef", "before cut;p_{T};#phi_{modn}", {HistType::kTH2D, {axisPt, cfgFuncParas.axisPhiMod}}); + registry.add("pt_phi_aft", "after cut;p_{T};#phi_{modn}", {HistType::kTH2D, {axisPt, cfgFuncParas.axisPhiMod}}); + 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}}); + registry.add("hMeanPt", "", {HistType::kTProfile, {axisIndependent}}); + registry.add("hMeanPtWithinGap08", "", {HistType::kTProfile, {axisIndependent}}); + // initial array + bootstrapArray.resize(cfgNbootstrap); + for (int i = 0; i < cfgNbootstrap; i++) { + bootstrapArray[i].resize(kCount_BootstrapHist); + } + for (auto i = 0; i < cfgNbootstrap; i++) { + bootstrapArray[i][kMeanPtWithinGap08] = registry.add(Form("BootstrapContainer_%d/hMeanPtWithinGap08", i), "", {HistType::kTProfile, {axisIndependent}}); + } + registry.add("c22_gap08_Weff", "", {HistType::kTProfile, {axisIndependent}}); + registry.add("c22_gap08_trackMeanPt", "", {HistType::kTProfile, {axisIndependent}}); + registry.add("PtVariance_partA_WithinGap08", "", {HistType::kTProfile, {axisIndependent}}); + registry.add("PtVariance_partB_WithinGap08", "", {HistType::kTProfile, {axisIndependent}}); + if (cfgFuncParas.cfgDptDisEnable) { + registry.add("hNormDeltaPt_X", "; #delta p_{T}/[p_{T}]; X", {HistType::kTH2D, {cfgFuncParas.cfgDptDisAxisNormal, axisIndependent}}); + } + if (doprocessMCGen) { + registry.add("MCGen/MChPhi", "#phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("MCGen/MChEta", "#eta distribution", {HistType::kTH1D, {axisEta}}); + registry.add("MCGen/MChPtRef", "p_{T} distribution after cut", {HistType::kTH1D, {axisPtHist}}); + } + + 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); + if (doprocessMCGen) { + fFCgen->SetName("FlowContainer_gen"); + fFCgen->SetXAxis(fPtAxis); + fFCgen->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("poiN00", -0.8, 0., 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN02", -0.8, -0.1, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN04", -0.8, -0.2, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN06", -0.8, -0.3, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN08", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN12", -0.8, -0.6, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN14", -0.8, -0.7, 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("olN00", -0.8, 0., 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN02", -0.8, -0.1, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN04", -0.8, -0.2, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN06", -0.8, -0.3, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN08", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN12", -0.8, -0.6, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN14", -0.8, -0.7, 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; + } + if (userDefineGFWCorr.at(i).find("poi") != std::string::npos) { + LOGF(info, "%d: enable pt-Diff for %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(), kTRUE)); + } else { + 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)); + } + } + } + + gfwConfigs.SetCorrs(cfgUserPtVnCorrConfig->GetCorrs()); + gfwConfigs.SetHeads(cfgUserPtVnCorrConfig->GetHeads()); + gfwConfigs.SetpTDifs(cfgUserPtVnCorrConfig->GetpTDifs()); + // Mask 1: vn-[pT], 3: vn-[pT^2], 7: vn-[pT^3], 15: vn-[pT^4] + gfwConfigs.SetpTCorrMasks(cfgUserPtVnCorrConfig->GetpTCorrMasks()); + gfwConfigs.Print(); + fFCpt->setUseCentralMoments(cfgUseCentralMoments); + fFCpt->setUseGapMethod(true); + fFCpt->initialise(axisIndependent, cfgMpar, gfwConfigs, cfgNbootstrap); + if (cfgEtaGapPtPtEnabled) + fFCpt->initialiseSubevent(axisIndependent, cfgMpar, cfgNbootstrap); + for (auto i = 0; i < gfwConfigs.GetSize(); ++i) { + corrconfigsPtVn.push_back(fGFW->GetCorrelatorConfig(gfwConfigs.GetCorrs()[i], gfwConfigs.GetHeads()[i], gfwConfigs.GetpTDifs()[i])); + } + if (doprocessMCGen) { + fFCptgen->setUseCentralMoments(cfgUseCentralMoments); + fFCptgen->setUseGapMethod(true); + fFCptgen->initialise(axisIndependent, cfgMpar, gfwConfigs, cfgNbootstrap); + if (cfgEtaGapPtPtEnabled) + fFCptgen->initialiseSubevent(axisIndependent, cfgMpar, cfgNbootstrap); + } + fGFW->CreateRegions(); + + if (cfgEvSelMultCorrelation) { + cfgFuncParas.multT0CCutPars = cfgFuncParas.cfgMultT0CCutPars; + cfgFuncParas.multPVT0CCutPars = cfgFuncParas.cfgMultPVT0CCutPars; + cfgFuncParas.multGlobalPVCutPars = cfgFuncParas.cfgMultGlobalPVCutPars; + cfgFuncParas.multMultV0ACutPars = cfgFuncParas.cfgMultMultV0ACutPars; + cfgFuncParas.fMultPVT0CCutLow = new TF1("fMultPVT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutLow->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultPVT0CCutHigh = new TF1("fMultPVT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutHigh->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + + cfgFuncParas.fMultT0CCutLow = new TF1("fMultT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutLow->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultT0CCutHigh = new TF1("fMultT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutHigh->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + + cfgFuncParas.fMultGlobalPVCutLow = new TF1("fMultGlobalPVCutLow", cfgFuncParas.cfgMultMultPVLowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutLow->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultGlobalPVCutHigh = new TF1("fMultGlobalPVCutHigh", cfgFuncParas.cfgMultMultPVHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutHigh->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + + cfgFuncParas.fMultMultV0ACutLow = new TF1("fMultMultV0ACutLow", cfgFuncParas.cfgMultMultV0ALowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutLow->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fMultMultV0ACutHigh = new TF1("fMultMultV0ACutHigh", cfgFuncParas.cfgMultMultV0AHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutHigh->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + + cfgFuncParas.fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + cfgFuncParas.fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + cfgFuncParas.fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + cfgFuncParas.fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + if (cfgFuncParas.cfgShowTPCsectorOverlap) { + cfgFuncParas.fPhiCutLow = new TF1("fPhiCutLow", cfgFuncParas.cfgTPCPhiCutLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fPhiCutHigh = new TF1("fPhiCutHigh", cfgFuncParas.cfgTPCPhiCutHighCutFunction->c_str(), 0, 100); + } + + 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 = cfgFuncParas.cfgTrackDensityP0; + std::vector f1p1 = cfgFuncParas.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); + } + + if (cfgFuncParas.cfgDCAxyNSigma) { + cfgFuncParas.fPtDepDCAxy = new TF1("ptDepDCAxy", Form("[0]*%s", cfgFuncParas.cfgDCAxy->c_str()), 0.001, 1000); + cfgFuncParas.fPtDepDCAxy->SetParameter(0, cfgFuncParas.cfgDCAxyNSigma); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", cfgFuncParas.cfgDCAxy->c_str())); + } + } + + void createOutputObjectsForRun(int runNumber) + { + const AxisSpec axisPhi{60, 0.0, constants::math::TwoPI, "#varphi"}; + std::shared_ptr histPhiEtaVtxz = registry.add(Form("%d/hPhiEtaVtxz", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {axisPhi, {64, -1.6, 1.6}, {40, -10, 10}}}); + th3sPerRun.insert(std::make_pair(runNumber, histPhiEtaVtxz)); + } + + 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; + } + + 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 (std::fabs(val) < 1) { + registry.fill(vnWeff, cent, val, dnx * WeffEvent); + registry.fill(vnpT, cent, val * meanPt, dnx * WeffEvent); + } + return; + } + return; + } + + template + 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) { + (dt == kGen) ? fFCgen->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm) : 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) { + (dt == kGen) ? fFCgen->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm) : fFC->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + } + return; + } + + template + inline void fillPtSums(TTrack track, float weff) + { + if (std::abs(track.eta()) < cfgEtaPtPt) { + (dt == kGen) ? fFCptgen->fill(1., track.pt()) : fFCpt->fill(weff, track.pt()); + } + if (std::abs(track.eta()) < cfgEtaSubPtPt) { + if (cfgEtaGapPtPtEnabled) { + if (track.eta() < -1. * cfgEtaGapPtPt) { + (dt == kGen) ? fFCptgen->fillSub1(1., track.pt()) : fFCpt->fillSub1(weff, track.pt()); + } + if (track.eta() > cfgEtaGapPtPt) { + (dt == kGen) ? fFCptgen->fillSub2(1., track.pt()) : fFCpt->fillSub2(weff, track.pt()); + } + } + } + } + + template + void fillPtContainers(const float& centmult, const double& rndm) + { + (dt == kGen) ? fFCptgen->calculateCorrelations() : fFCpt->calculateCorrelations(); + (dt == kGen) ? fFCptgen->fillPtProfiles(centmult, rndm) : fFCpt->fillPtProfiles(centmult, rndm); + (dt == kGen) ? fFCptgen->fillCMProfiles(centmult, rndm) : fFCpt->fillCMProfiles(centmult, rndm); + if (cfgEtaGapPtPtEnabled) { + (dt == kGen) ? fFCptgen->calculateSubeventCorrelations() : fFCpt->calculateSubeventCorrelations(); + (dt == kGen) ? fFCptgen->fillSubeventPtProfiles(centmult, rndm) : fFCpt->fillSubeventPtProfiles(centmult, rndm); + (dt == kGen) ? fFCptgen->fillCMSubeventProfiles(centmult, rndm) : fFCpt->fillCMSubeventProfiles(centmult, rndm); + } + for (uint l_ind = 0; l_ind < corrconfigsPtVn.size(); ++l_ind) { + if (!corrconfigsPtVn.at(l_ind).pTDif) { + auto dnx = fGFW->Calculate(corrconfigsPtVn.at(l_ind), 0, kTRUE).real(); + if (dnx == 0) + continue; + auto val = fGFW->Calculate(corrconfigsPtVn.at(l_ind), 0, kFALSE).real() / dnx; + if (std::abs(val) < 1) { + (dt == kGen) ? fFCptgen->fillVnPtProfiles(l_ind, centmult, val, dnx, rndm, gfwConfigs.GetpTCorrMasks()[l_ind]) : fFCpt->fillVnPtProfiles(l_ind, centmult, val, dnx, rndm, gfwConfigs.GetpTCorrMasks()[l_ind]); + } + continue; + } + } + 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 (cfgFuncParas.cfgDptDisEnable && cfgFuncParas.cfgDptDishEvAvgMeanPt.value.empty() == false) { + cfgFuncParas.hEvAvgMeanPt = ccdb->getForTimeStamp(cfgFuncParas.cfgDptDishEvAvgMeanPt, timestamp); + if (cfgFuncParas.hEvAvgMeanPt == nullptr) { + LOGF(fatal, "Could not load mean pT histogram from %s", cfgFuncParas.cfgDptDishEvAvgMeanPt.value.c_str()); + } + LOGF(info, "Loaded mean pT histogram from %s (%p)", cfgFuncParas.cfgDptDishEvAvgMeanPt.value.c_str(), (void*)cfgFuncParas.hEvAvgMeanPt); + } + if (cfgFuncParas.cfgDptDisEnable && cfgFuncParas.cfgDptDisSelectionSwitch > kNoDptCut) { + if (cfgFuncParas.cfgDptDisCutLow.value.empty() == false) { + cfgFuncParas.fDptDisCutLow = ccdb->getForTimeStamp(cfgFuncParas.cfgDptDisCutLow, timestamp); + if (cfgFuncParas.fDptDisCutLow == nullptr) { + LOGF(fatal, "Could not load dptDis low cut histogram from %s", cfgFuncParas.cfgDptDisCutLow.value.c_str()); + } + LOGF(info, "Loaded dptDis low cut histogram from %s (%p)", cfgFuncParas.cfgDptDisCutLow.value.c_str(), (void*)cfgFuncParas.fDptDisCutLow); + } + if (cfgFuncParas.cfgDptDisCutHigh.value.empty() == false) { + cfgFuncParas.fDptDisCutHigh = ccdb->getForTimeStamp(cfgFuncParas.cfgDptDisCutHigh, timestamp); + if (cfgFuncParas.fDptDisCutHigh == nullptr) { + LOGF(fatal, "Could not load dptDis high cut histogram from %s", cfgFuncParas.cfgDptDisCutHigh.value.c_str()); + } + LOGF(info, "Loaded dptDis high cut histogram from %s (%p)", cfgFuncParas.cfgDptDisCutHigh.value.c_str(), (void*)cfgFuncParas.fDptDisCutHigh); + } + } + 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 (cfgEvSelkNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return 0; + } + if (cfgEvSelkNoITSROFrameBorder) + registry.fill(HIST("hEventCountSpecific"), 2.5); + if (cfgEvSelkNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return 0; + } + if (cfgEvSelkNoTimeFrameBorder) + registry.fill(HIST("hEventCountSpecific"), 3.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"), 4.5); + if (cfgEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (cfgEvSelkNoCollInTimeRangeStandard) + registry.fill(HIST("hEventCountSpecific"), 5.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"), 6.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"), 7.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"), 8.5); + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) + return 0; + if (cfgEvSelOccupancy) + registry.fill(HIST("hEventCountSpecific"), 9.5); + + if (cfgEvSelMultCorrelation) { + if (cfgFuncParas.cfgMultPVT0CCutEnabled) { + if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(centrality)) + return 0; + } + if (cfgFuncParas.cfgMultT0CCutEnabled) { + if (multTrk < cfgFuncParas.fMultT0CCutLow->Eval(centrality)) + return 0; + if (multTrk > cfgFuncParas.fMultT0CCutHigh->Eval(centrality)) + return 0; + } + if (cfgFuncParas.cfgMultGlobalPVCutEnabled) { + if (multTrk < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) + return 0; + if (multTrk > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) + return 0; + } + if (cfgFuncParas.cfgMultMultV0ACutEnabled) { + if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(multTrk)) + return 0; + if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(multTrk)) + return 0; + } + } + if (cfgEvSelMultCorrelation) + registry.fill(HIST("hEventCountSpecific"), 10.5); + + // V0A T0A 5 sigma cut + float sigma = 5.0; + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > sigma * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + if (cfgEvSelV0AT0ACut) + registry.fill(HIST("hEventCountSpecific"), 11.5); + + return 1; + } + + int getMagneticField(uint64_t timestamp) + { + static o2::parameters::GRPMagField* grpo = nullptr; + if (grpo == nullptr) { + grpo = ccdb->getForTimeStamp(cfgFuncParas.cfgMagnetField, timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRP object not found in %s for timestamp %llu", cfgFuncParas.cfgMagnetField.value.c_str(), timestamp); + return 0; + } + LOGF(info, "Retrieved GRP from %s for timestamp %llu with magnetic field of %d kG", cfgFuncParas.cfgMagnetField.value.c_str(), timestamp, grpo->getNominalL3Field()); + } + return grpo->getNominalL3Field(); + } + + template + bool trackSelected(TTrack track) + { + if (cfgFuncParas.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > cfgFuncParas.fPtDepDCAxy->Eval(track.pt()))) + return false; + return ((track.tpcNClsFound() >= cfgCutTPCclu) && (track.tpcNClsCrossedRows() >= cfgCutTPCCrossedRows) && (track.itsNCls() >= cfgCutITSclu)); + } + + template + bool rejectionTPCoverlap(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); + + float middle = o2::constants::math::TwoPI / 18.0; + phimodn += middle; // to center gap in the middle + phimodn = fmod(phimodn, o2::constants::math::TwoPI / 9.0); + registry.fill(HIST("pt_phi_bef"), track.pt(), phimodn); + if (cfgFuncParas.cfgRejectionTPCsectorOverlap) { + if (track.pt() >= cfgFuncParas.cfgTPCPhiCutPtMin && phimodn < cfgFuncParas.fPhiCutHigh->Eval(track.pt()) && phimodn > cfgFuncParas.fPhiCutLow->Eval(track.pt())) + return false; // reject track + } + registry.fill(HIST("pt_phi_aft"), track.pt(), phimodn); + 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]; + } + + template + float getCentrality(TCollision const& collision) + { + 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(); + } + return cent; + } + + void processData(FilteredCollisions::iterator const& collision, aod::BCsWithTimestamps const&, FilteredTracks 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; + } + } + if (cfgOutputNUAWeightsRunbyRun && currentRunNumber != lastRunNumber) { + lastRunNumber = currentRunNumber; + if (std::find(runNumbers.begin(), runNumbers.end(), currentRunNumber) == runNumbers.end()) { + // if run number is not in the preconfigured list, create new output histograms for this run + createOutputObjectsForRun(currentRunNumber); + runNumbers.push_back(currentRunNumber); + } + + if (th3sPerRun.find(currentRunNumber) == th3sPerRun.end()) { + LOGF(fatal, "RunNumber %d not found in th3sPerRun", currentRunNumber); + 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 = getCentrality(collision); + + 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(); + fFCpt->clearVector(); + 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()); + 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 weffEvent = 0; + double ptSum = 0., ptSum_Gap08 = 0.; + double weffEventWithinGap08 = 0., weffEventSquareWithinGap08 = 0.; + double sumPtsquareWsquareWithinGap08 = 0., sumPtWsquareWithinGap08 = 0.; + double nTracksCorrected = 0; + int magnetfield = 0; + float independent = cent; + if (cfgUseNch) + independent = static_cast(tracks.size()); + if (cfgFuncParas.cfgShowTPCsectorOverlap) { + // magnet field dependence cut + magnetfield = getMagneticField(bc.timestamp()); + } + + 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; + if (cfgFuncParas.cfgShowTPCsectorOverlap && !rejectionTPCoverlap(track, magnetfield)) + 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 + bool withinEtaGap08 = (std::abs(track.eta()) < cfgEtaPtPt); + if (cfgOutputNUAWeights) { + if (cfgOutputNUAWeightsRefPt) { + if (withinPtRef) { + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + if (cfgOutputNUAWeightsRunbyRun) + th3sPerRun[currentRunNumber]->Fill(track.phi(), track.eta(), collision.posZ()); + } + } else { + fWeights->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + if (cfgOutputNUAWeightsRunbyRun) + th3sPerRun[currentRunNumber]->Fill(track.phi(), track.eta(), collision.posZ()); + } + } + 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()); + weffEvent += weff; + ptSum += weff * track.pt(); + nTracksCorrected += weff; + if (withinEtaGap08) { + ptSum_Gap08 += weff * track.pt(); + sumPtWsquareWithinGap08 += weff * weff * track.pt(); + sumPtsquareWsquareWithinGap08 += weff * weff * track.pt() * track.pt(); + weffEventWithinGap08 += weff; + weffEventSquareWithinGap08 += 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); + if (cfgUsePtRef && withinPtRef) + fillPtSums(track, weff); + if (!cfgUsePtRef && withinPtPOI) + fillPtSums(track, weff); + } + registry.fill(HIST("hTrackCorrection2d"), tracks.size(), nTracksCorrected); + + if (cfgFuncParas.cfgDptDisEnable) { + double meanPt = ptSum / weffEvent; + double deltaPt = meanPt - cfgFuncParas.hEvAvgMeanPt->GetBinContent(cfgFuncParas.hEvAvgMeanPt->FindBin(independent)); + double normDeltaPt = deltaPt / meanPt; + registry.fill(HIST("hNormDeltaPt_X"), normDeltaPt, independent, weffEvent); + if (cfgFuncParas.cfgDptDisSelectionSwitch == kLowDptCut && normDeltaPt > cfgFuncParas.fDptDisCutLow->GetBinContent(cfgFuncParas.fDptDisCutLow->FindBin(independent))) { + // only keep low 10% dpt event + return; + } else if (cfgFuncParas.cfgDptDisSelectionSwitch == kHighDptCut && normDeltaPt < cfgFuncParas.fDptDisCutHigh->GetBinContent(cfgFuncParas.fDptDisCutHigh->FindBin(independent))) { + // only keep high 10% dpt event + return; + } + } + + double weffEventDiffWithGap08 = weffEventWithinGap08 * weffEventWithinGap08 - weffEventSquareWithinGap08; + // MeanPt + if (weffEvent) { + registry.fill(HIST("hMeanPt"), independent, ptSum / weffEvent, weffEvent); + } + if (weffEventWithinGap08) + registry.fill(HIST("hMeanPtWithinGap08"), independent, ptSum_Gap08 / weffEventWithinGap08, 1.0); + int sampleIndex = static_cast(cfgNbootstrap * lRandom); + if (weffEventWithinGap08) + bootstrapArray[sampleIndex][kMeanPtWithinGap08]->Fill(independent, ptSum_Gap08 / weffEventWithinGap08, 1.0); + // c22_gap8 * pt_withGap8 + if (weffEventWithinGap08) + fillpTvnProfile(corrconfigs.at(7), ptSum_Gap08, weffEventWithinGap08, HIST("c22_gap08_Weff"), HIST("c22_gap08_trackMeanPt"), independent); + // PtVariance + if (weffEventDiffWithGap08) { + registry.fill(HIST("PtVariance_partA_WithinGap08"), independent, + (ptSum_Gap08 * ptSum_Gap08 - sumPtsquareWsquareWithinGap08) / weffEventDiffWithGap08, + weffEventDiffWithGap08); + registry.fill(HIST("PtVariance_partB_WithinGap08"), independent, + (weffEventWithinGap08 * ptSum_Gap08 - sumPtWsquareWithinGap08) / weffEventDiffWithGap08, + weffEventDiffWithGap08); + } + + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), independent, lRandom); + } + // Filling pt Container + fillPtContainers(independent, lRandom); + } + PROCESS_SWITCH(FlowTask, processData, "Process analysis for non-derived data", true); + + void processMCGen(FilteredMcCollisions::iterator const& mcCollision, FilteredSmallGroupMcCollisions const& collisions, FilteredMcParticles const& mcParticles) + { + if (collisions.size() != 1) + return; + + float cent = -1.; + for (const auto& collision : collisions) { + cent = getCentrality(collision); + } + + float lRandom = fRndm->Rndm(); + float vtxz = mcCollision.posZ(); + registry.fill(HIST("MCGen/MChVtxZ"), vtxz); + registry.fill(HIST("MCGen/MChMult"), mcParticles.size()); + registry.fill(HIST("MCGen/MChCent"), cent); + float independent = cent; + if (cfgUseNch) + independent = static_cast(mcParticles.size()); + + fGFW->Clear(); + fFCptgen->clearVector(); + + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary()) + continue; + bool withinPtPOI = (cfgCutPtPOIMin < mcParticle.pt()) && (mcParticle.pt() < cfgCutPtPOIMax); // within POI pT range + bool withinPtRef = (cfgCutPtRefMin < mcParticle.pt()) && (mcParticle.pt() < cfgCutPtRefMax); // within RF pT range + + if (withinPtRef) { + registry.fill(HIST("MCGen/MChPhi"), mcParticle.phi()); + registry.fill(HIST("MCGen/MChEta"), mcParticle.eta()); + registry.fill(HIST("MCGen/MChPtRef"), mcParticle.pt()); + } + if (withinPtRef) + fGFW->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), 1., 1); + if (withinPtPOI) + fGFW->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), 1., 2); + if (withinPtPOI && withinPtRef) + fGFW->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), 1., 4); + if (cfgUsePtRef && withinPtRef) + fillPtSums(mcParticle, 1.); + if (!cfgUsePtRef && withinPtPOI) + fillPtSums(mcParticle, 1.); + } + + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + fillFC(corrconfigs.at(l_ind), independent, lRandom); + } + // Filling pt Container + fillPtContainers(independent, lRandom); + } + PROCESS_SWITCH(FlowTask, processMCGen, "Process analysis for MC generated events", false); +}; + +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..148d1430e5d --- /dev/null +++ b/PWGCF/Flow/Tasks/flowZdcTask.cxx @@ -0,0 +1,939 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Common/CCDB/EventSelectionParams.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 "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include + +#include "TList.h" +#include +#include +#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::constants::math; +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") + Configurable eventSelection{"eventSelection", 1, "event selection"}; + Configurable maxZp{"maxZp", 125.5, "Max ZP signal"}; + Configurable maxZem{"maxZem", 3099.5, "Max ZEM signal"}; + // for ZDC info and analysis + Configurable nBinsAmp{"nBinsAmp", 1025, "nbinsAmp"}; + Configurable nBinsADC{"nBinsADC", 1000, "nbinsADC"}; + Configurable nBinsCent{"nBinsCent", 90, "nBinsCent"}; + Configurable maxZn{"maxZn", 125.5, "Max ZN signal"}; + // configs for process QA + Configurable nBinsNch{"nBinsNch", 2501, "N bins Nch (|eta|<0.8)"}; + Configurable nBinsAmpFT0{"nBinsAmpFT0", 100, "N bins FT0 amp"}; + Configurable maxAmpFT0{"maxAmpFT0", 2500, "Max FT0 amp"}; + Configurable maxAmpFT0M{"maxAmpFT0M", 2500, "Max FT0M amp"}; + Configurable nBinsAmpFV0{"nBinsAmpFV0", 100, "N bins FV0 amp"}; + Configurable maxAmpFV0{"maxAmpFV0", 2000, "Max FV0 amp"}; + Configurable nBinsZDC{"nBinsZDC", 400, "nBinsZDC"}; + Configurable minNch{"minNch", 0, "Min Nch (|eta|<0.8)"}; + Configurable maxNch{"maxNch", 2500, "Max Nch (|eta|<0.8)"}; + Configurable nBinsTDC{"nBinsTDC", 150, "nbinsTDC"}; + Configurable minTdcZn{"minTdcZn", -4.0, "minimum TDC for ZN"}; + Configurable maxTdcZn{"maxTdcZn", -4.0, "maximum TDC for ZN"}; + Configurable minTdcZp{"minTdcZp", -4.0, "minimum TDC for ZP"}; + Configurable maxTdcZp{"maxTdcZp", -4.0, "maximum TDC for ZP"}; + Configurable cfgCollisionEnergy{"cfgCollisionEnergy", 2.68, "cfgCollisionEnergy"}; + Configurable applyZdcCorrection{"applyZdcCorrection", false, "Apply ZP correction?"}; + Configurable zdcCoeff{"zdcCoeff", 0.021f, "Coefficient b in zdc correction"}; + // 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 useMidRapNchSel{"useMidRapNchSel", false, "Use mid-rapidity Nch selection"}; + Configurable applyEff{"applyEff", true, "Apply track-by-track efficiency correction"}; + Configurable correctNch{"correctNch", true, "Correct also Nch"}; + + Configurable nSigmaNchCut{"nSigmaNchCut", 1., "nSigma Nch selection"}; + Configurable minNchSel{"minNchSel", 5., "min Nch Selection"}; + Configurable tdcCut{"tdcCut", 1., "TDC cut"}; + Configurable minOccCut{"minOccCut", 0, "min Occu cut"}; + Configurable maxOccCut{"maxOccCut", 500, "max Occu cut"}; + Configurable minPt{"minPt", 0.1, "minimum pt of the tracks"}; + Configurable maxPt{"maxPt", 3., "maximum pt of the tracks"}; + Configurable maxPtSpectra{"maxPtSpectra", 50., "maximum pt of the tracks"}; + Configurable zemCut{"zemCut", 100., "ZEM cut"}; + // axis configs + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {3500, 0, 3500}, "centrality axis for histograms"}; + ConfigurableAxis axisZN{"axisZN", {5000, 0, 500}, "axisZN"}; + ConfigurableAxis axisZP{"axisZP", {5000, 0, 500}, "axisZP"}; + ConfigurableAxis axisCent{"axisCent", {10, 0, 100}, "axisCent"}; + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12}, "pT binning"}; + Configurable posZcut{"posZcut", +10.0, "z-vertex position cut"}; + Configurable minEta{"minEta", -0.8, "minimum eta"}; + Configurable maxEta{"maxEta", +0.8, "maximum eta"}; + Configurable minT0CcentCut{"minT0CcentCut", 0.0, "Min T0C Cent. cut"}; + Configurable maxT0CcentCut{"maxT0CcentCut", 90.0, "Max T0C Cent. cut"}; + + using ColEvents = soa::Join; + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = ((aod::track::eta > minEta) && (aod::track::eta < maxEta)); + 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 TracksSel = soa::Join; + using CollisionDataTable = soa::Join; + using TrackDataTable = soa::Join; + using FilTrackDataTable = soa::Filtered; + using TheFilteredTracks = soa::Filtered; + + // CCDB paths + Configurable paTH{"paTH", "Users/s/sahernan/test", "base path to the ccdb object"}; + Configurable paTHmeanNch{"paTHmeanNch", "Users/s/shernan/test", "base path to the ccdb object"}; + Configurable paTHsigmaNch{"paTHsigmaNch", "Users/s/shernan/testSigma", "base path to the ccdb object"}; + Configurable paTHEff{"paTHEff", "Users/s/shernan/TrackingEff", "base path to the ccdb object"}; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + + enum EvCutLabel { + All = 1, + SelEigth, + NoSameBunchPileup, + IsGoodZvtxFT0vsPV, + NoCollInTimeRangeStrict, + NoCollInTimeRangeStandard, + NoCollInRofStrict, + NoCollInRofStandard, + NoHighMultCollInPrevRof, + NoCollInTimeRangeNarrow, + OccuCut, + Centrality, + VtxZ, + Zdc, + TZero, + Tdc, + Zem + }; + // Begin Histogram Registry + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Service ccdb; + + void init(InitContext const&) + { + // define axes + const AxisSpec axisEvent{18, 0.5, 18.5, ""}; + const AxisSpec axisZpos{48, -12., 12., "Vtx_{z} (cm)"}; + const AxisSpec axisEta{40, -1., +1., "#eta"}; + const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisVtxZ{40, -20, 20, "Vertex Z", "VzAxis"}; + + // create histograms + histos.add("hEventCounter", "Event counter", kTH1F, {axisEvent}); + histos.add("zPos", ";;Entries;", kTH1F, {axisZpos}); + 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("T0Ccent", ";;Entries", kTH1F, {axisCent}); + histos.add("NchUncorrected", ";#it{N}_{ch} (|#eta| < 0.8);Entries;", kTH1F, {{300, 0., 3000.}}); + histos.add("ZNamp", ";ZNA+ZNC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ExcludedEvtVsFT0M", ";T0A+T0C (#times 1/100, -3.3 < #eta < -2.1 and 3.5 < #eta < 4.9);Entries;", kTH1F, {{nBinsAmpFT0, 0., maxAmpFT0}}); + histos.add("ExcludedEvtVsNch", ";#it{N}_{ch} (|#eta|<0.8);Entries;", kTH1F, {{300, 0, 3000}}); + histos.add("Nch", ";#it{N}_{ch} (|#eta| < 0.8, Corrected);", kTH1F, {{nBinsNch, minNch, maxNch}}); + histos.add("EtaVsPhi", ";#eta;#varphi", kTH2F, {{{axisEta}, {100, -0.1 * PI, +2.1 * PI}}}); + histos.add("ZposVsEta", "", kTProfile, {axisZpos}); + histos.add("dcaXYvspT", ";DCA_{xy} (cm);;", kTH2F, {{{50, -1., 1.}, {axisPt}}}); + + // 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, "SelEigth"); + xAxis->SetBinLabel(3, "NoSameBunchPileup"); // reject collisions in case of pileup with another collision in the same foundBC + xAxis->SetBinLabel(4, "GoodZvtxFT0vsPV"); // small difference between z-vertex from PV and from FT0 + xAxis->SetBinLabel(5, "NoCollInTimeRangeStrict"); + xAxis->SetBinLabel(6, "NoCollInTimeRangeStandard"); + xAxis->SetBinLabel(7, "NoCollInRofStrict"); + xAxis->SetBinLabel(8, "NoCollInRofStandard"); + xAxis->SetBinLabel(9, "NoHighMultCollInPrevRof"); + xAxis->SetBinLabel(10, "NoCollInTimeRangeNarrow"); + xAxis->SetBinLabel(11, "Occupancy Cut"); + xAxis->SetBinLabel(12, "Cent. Sel."); + xAxis->SetBinLabel(13, "VtxZ cut"); + xAxis->SetBinLabel(14, "has ZDC?"); + xAxis->SetBinLabel(15, "has T0?"); + xAxis->SetBinLabel(16, "Within TDC cut?"); + + 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("ZPCcoll", "ZPCcoll; ZPC amplitude; Entries", {HistType::kTH1F, {{nBinsAmp, -0.5, maxZn}}}); + histos.add("ZPAcoll", "ZPAcoll; ZPA 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("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", "common sum ZN energy side c", kTH1F, {axisZN}); + histos.add("ZNAenergy", "common sum ZN energy side a", kTH1F, {axisZN}); + histos.add("ZPCenergy", "common sum ZP energy side c", kTH1F, {axisZP}); + histos.add("ZPAenergy", "common sum ZP energy side a", kTH1F, {axisZP}); + histos.add("ZNenergy", "common sum zn (a + c sides) energy", kTH1F, {axisZN}); + histos.add("ZPenergy", "common sum zp energy (a + c sides)", kTH1F, {axisZP}); + histos.add("hZNvsFT0CAmp", "ZN Energy vs FT0C Amplitude", kTH2F, {{nBinsAmpFT0, 0., maxAmpFT0}, axisZN}); + histos.add("hZPvsFT0CAmp", "ZP Energy vs FT0C Amplitude", kTH2F, {{nBinsAmpFT0, 0., maxAmpFT0}, axisZP}); + histos.add("hZNvsMult", "ZN Energy vs Multiplicity", kTH2F, {axisMultiplicity, axisZN}); + histos.add("hZPvsMult", "ZP Energy vs Multiplicity", kTH2F, {axisMultiplicity, axisZP}); + } + + if (doprocessQA) { + histos.add("ZNVsFT0A", ";T0A (#times 1/100);ZNA+ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNVsFT0C", ";T0C (#times 1/100);ZNA+ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNVsFT0M", ";T0A+T0C (#times 1/100);ZNA+ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZPVsFT0A", ";T0A (#times 1/100);ZPA+ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPVsFT0C", ";T0C (#times 1/100);ZPA+ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPVsFT0M", ";T0A+T0C (#times 1/100);ZPA+ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZNAVsFT0A", ";T0A (#times 1/100);ZNA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNAVsFT0C", ";T0C (#times 1/100);ZNA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNAVsFT0M", ";T0A+T0C (#times 1/100);ZNA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNCVsFT0A", ";T0A (#times 1/100);ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNCVsFT0C", ";T0C (#times 1/100);ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNCVsFT0M", ";T0A+T0C (#times 1/100);ZNC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZPAVsFT0A", ";T0A (#times 1/100);ZPA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPAVsFT0C", ";T0C (#times 1/100);ZPA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPAVsFT0M", ";T0A+T0C (#times 1/100);ZPA Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPCVsFT0A", ";T0A (#times 1/100);ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPCVsFT0C", ";T0C (#times 1/100);ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPCVsFT0M", ";T0A+T0C (#times 1/100);ZPC Amplitude;", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0M}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZN", ";ZNA+ZNC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ZNA", ";ZNA Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ZPA", ";ZPA Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); + histos.add("ZNC", ";ZNC Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ZPC", ";ZPC Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); + histos.add("ZNACommon", ";ZNA Common Energy;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ZPACommon", ";ZPA Common Energy;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); + histos.add("ZNCCommon", ";ZNC Common Energy;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ZPCCommon", ";ZPC Common Energy;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); + histos.add("ZNAVsZNC", ";ZNC;ZNA", kTH2F, {{{nBinsZDC, -0.5, maxZn}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZPAVsZPC", ";ZPC;ZPA;", kTH2F, {{{nBinsZDC, -0.5, maxZp}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZNAVsZPA", ";ZPA;ZNA;", kTH2F, {{{nBinsZDC, -0.5, maxZp}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNCVsZPC", ";ZPC;ZNC;", kTH2F, {{{nBinsZDC, -0.5, maxZp}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNASector", ";ZNA;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ZPASector", ";ZPA;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); + histos.add("ZNCSector", ";ZNC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ZPCSector", ";ZPC;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); + histos.add("ZNCcvsZNCsum", ";ZNC common;ZNC sum towers;", kTH2F, {{{30, -0.5, maxZn}, {30, -0.5, maxZn}}}); + histos.add("ZNAcvsZNAsum", ";ZNA common;ZNA sum towers;", kTH2F, {{{30, -0.5, maxZn}, {30, -0.5, maxZn}}}); + histos.add("ZPCcvsZPCsum", ";ZPC common;ZPC sum towers;", kTH2F, {{{30, -0.5, maxZp}, {30, -0.5, maxZp}}}); + histos.add("ZPAcvsZPAsum", ";ZPA common;ZPA sum towers;", kTH2F, {{{30, -0.5, maxZp}, {30, -0.5, maxZp}}}); + histos.add("ZNVsZEM", ";ZEM;ZNA+ZNC;", kTH2F, {{{60, -0.5, maxZem}, {60, -0.5, maxZn}}}); + histos.add("ZNCVstdccoll", ";t_{ZNC};ZNC;", kTH2F, {{{nBinsTDC, -13.5, 11.45}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZNAVstdccoll", ";t_{ZNA};ZNA;", kTH2F, {{{nBinsTDC, -13.5, 11.45}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZPCVstdccoll", ";t_{ZPC};ZPC;", kTH2F, {{{nBinsTDC, -13.5, 11.45}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPAVstdccoll", ";t_{ZPA};ZPA;", kTH2F, {{{nBinsTDC, -13.5, 11.45}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZEM1", ";ZEM1 Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZem}}); + histos.add("ZEM2", ";ZEM2 Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZem}}); + histos.add("ZEM1Vstdc", ";t_{ZEM1};ZEM1;", kTH2F, {{{480, -13.5, 11.45}, {30, -0.5, 2000.5}}}); + histos.add("ZEM2Vstdc", ";t_{ZEM2};ZEM2;", kTH2F, {{{480, -13.5, 11.45}, {30, -0.5, 2000.5}}}); + histos.add("debunch", ";t_{ZDC}-t_{ZDA};t_{ZDC}+t_{ZDA}", kTH2F, {{{nBinsTDC, minTdcZn, maxTdcZn}, {nBinsTDC, minTdcZp, maxTdcZp}}}); + histos.add("GlbTracks", "Nch", kTH1F, {{nBinsNch, minNch, maxNch}}); + histos.add("ampFT0C", ";T0C (#times 1/100);", kTH1F, {{nBinsAmpFT0, 0., maxAmpFT0}}); + histos.add("ampFT0A", ";T0A (#times 1/100);", kTH1F, {{nBinsAmpFT0, 0., maxAmpFT0}}); + histos.add("ampFT0M", ";T0A+T0C (#times 1/100);", kTH1F, {{nBinsAmpFT0, 0., maxAmpFT0M}}); + histos.add("ampFV0A", ";V0A (#times 1/100);", kTH1F, {{nBinsAmpFV0, 0., maxAmpFV0}}); + histos.add("NchVsFT0C", ";T0C (#times 1/100, -3.3 < #eta < -2.1);#it{N}_{ch} (|#eta|<0.8);", kTH2F, {{{nBinsAmpFT0, 0., 950.}, {nBinsNch, minNch, maxNch}}}); + histos.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., maxAmpFT0M}, {nBinsNch, minNch, maxNch}}}); + histos.add("NchVsFT0A", ";T0A (#times 1/100, 3.5 < #eta < 4.9);#it{N}_{ch} (|#eta|<0.8);", kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsNch, minNch, maxNch}}}); + histos.add("NchVsFV0A", ";V0A (#times 1/100, 2.2 < #eta < 5);#it{N}_{ch} (|#eta|<0.8);", kTH2F, {{{nBinsAmpFV0, 0., maxAmpFV0}, {nBinsNch, minNch, maxNch}}}); + histos.add("NchVsEt", ";#it{E}_{T} (|#eta|<0.8);#LTITS+TPC tracks#GT (|#eta|<0.8);", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsNch, minNch, maxNch}}}); + histos.add("NchVsMeanPt", ";#it{N}_{ch} (|#eta|<0.8);#LT[#it{p}_{T}]#GT (|#eta|<0.8);", kTProfile, {{nBinsNch, minNch, maxNch}}); + histos.add("NchVsNPV", ";#it{N}_{PV} (|#eta|<1);ITS+TPC tracks (|#eta|<0.8);", kTH2F, {{{300, -0.5, 5999.5}, {nBinsNch, minNch, maxNch}}}); + histos.add("NchVsITStracks", ";ITS tracks nCls >= 5;TITS+TPC tracks (|#eta|<0.8);", kTH2F, {{{300, -0.5, 5999.5}, {nBinsNch, minNch, maxNch}}}); + histos.add("ZNCVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); + histos.add("ZNAVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); + histos.add("ZNVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA+ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); + histos.add("ZNDifVsNch", ";#it{N}_{ch} (|#eta|<0.8);ZNA-ZNC;", kTH2F, {{{nBinsNch, minNch, maxNch}, {100, -50., 50.}}}); + histos.add("ZPAvsCent", ";centFT0C;ZPA", kTH2F, {{{axisCent}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZPCvsCent", ";centFT0C;ZPC", kTH2F, {{{axisCent}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("hZPASectorvsGlbTrack", ";Global Tracks (ITS + TPC);ZPA Sector Energy", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZp}}}); + histos.add("hZPCSectorvsGlbTrack", ";Global Tracks (ITS + TPC);ZPC Sector Energy", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZp}}}); + histos.add("hZNASectorvsGlbTrack", ";Global Tracks (ITS + TPC);ZNA Sector Energy", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); + histos.add("hZNCSectorvsGlbTrack", ";Global Tracks (ITS + TPC);ZNC Sector Energy", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); + histos.add("hZPSectorvsGlbTrack", ";Global Tracks (ITS + TPC);(ZPA + ZPC) Sector Energy", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZp}}}); + histos.add("hZNSectorvsGlbTrack", ";Global Tracks (ITS + TPC);(ZNA + ZNC) Sector Energy", kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZDC, minNch, maxZn}}}); + } + if (doprocessZdc) { + histos.add("ampZna", ";ZNA Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ampZpa", ";ZPA Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); + histos.add("ampZnc", ";ZNC Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZn}}); + histos.add("ampZpc", ";ZPC Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZp}}); + histos.add("ampZEM1", ";ZEM1 Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZem}}); + histos.add("ampZEM2", ";ZEM2 Amplitude;Entries;", kTH1F, {{nBinsZDC, -0.5, maxZem}}); + histos.add("ZnVsZem", "ZnVsZEM; ZEM; ZNA + ZNC", kTH2F, {{{nBinsZDC, -0.5, maxZem}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZnaVsZnc", "ZNAvsZNC; ZNC; ZNA;", kTH2F, {{{nBinsZDC, -0.5, maxZn}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZpaVsZpc", "ZPAvsZPC; ZPC; ZPA;", kTH2F, {{{nBinsZDC, -0.5, maxZp}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZnaVsZpa", "ZNAvsZPA; ZNA; ZPA;", kTH2F, {{{nBinsZDC, -0.5, maxZn}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZncVsZpc", "ZNCvsZPC; ZNC; ZPC;", kTH2F, {{{nBinsZDC, -0.5, maxZn}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZnccVsZncSum", "ZNCcVsZNCsum; ZNCC ADC; ZNCsum", kTH2F, {{{nBinsADC, -0.5, 3. * maxZn}, {nBinsADC, -0.5, 3. * maxZn}}}); + histos.add("ZnacVsZnaSum", "ZNAcVsZNAsum; ZNAC ADC; ZNAsum", kTH2F, {{{nBinsADC, -0.5, 3. * maxZn}, {nBinsADC, -0.5, 3. * maxZn}}}); + histos.add("ZpacVsZpaSum", "ZPAcVsZPAsum; ZPAC ADC; ZPAsum", kTH2F, {{{nBinsADC, -0.5, 3. * maxZp}, {nBinsADC, -0.5, 3. * maxZp}}}); + histos.add("ZpccVsZpcSum", "ZPCcVsZPCsum; ZPCC ADC; ZPCsum", kTH2F, {{{nBinsADC, -0.5, 3. * maxZp}, {nBinsADC, -0.5, 3. * maxZp}}}); + histos.add("ZncVsTdc", "ZNCvsTDC; ZNC Amp; ZNC TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZnaVsTdc", "ZNAvsTDC; ZNA Amp; ZNA TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZn}}}); + histos.add("ZpcVsTdc", "ZPCvsTDC; ZPC Amp; ZPC TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("ZpaVsTdc", "ZPAvsTDC; ZPA Amp; ZPA TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZp}}}); + histos.add("Zem1VsTdc", "ZEM1vsTDC; ZEM1 Amp; ZEM1 TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZem}}}); + histos.add("Zem2VsTdc", "ZEM2vsTDC; ZEM2 Amp; ZEM2 TDC", kTH2F, {{{480, -13.5, 11.45}, {nBinsZDC, -0.5, maxZem}}}); + } + + ccdb->setURL("http://alice-ccdb.cern.ch"); + // Enabling object caching, otherwise each call goes to the CCDB server + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + // 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); + } + template + bool isEventSelected(EventCuts const& col) + { + histos.fill(HIST("hEventCounter"), EvCutLabel::All); + if (!col.sel8()) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::SelEigth); + + if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::NoSameBunchPileup); + + if (!col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::IsGoodZvtxFT0vsPV); + + if (isNoCollInTimeRangeStrict) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::NoCollInTimeRangeStrict); + } + + if (isNoCollInTimeRangeStandard) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::NoCollInTimeRangeStandard); + } + + if (isNoCollInRofStrict) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::NoCollInRofStrict); + } + + if (isNoCollInRofStandard) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::NoCollInRofStandard); + } + + if (isNoHighMultCollInPrevRof) { + if (!col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + histos.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; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::NoCollInTimeRangeNarrow); + } + + if (isOccupancyCut) { + auto occuValue{isApplyFT0CbasedOccupancy ? col.ft0cOccupancyInTimeRange() : col.trackOccupancyInTimeRange()}; + if (occuValue < minOccCut || occuValue > maxOccCut) { + return false; + } + } + histos.fill(HIST("hEventCounter"), EvCutLabel::OccuCut); + + if (col.centFT0C() < minT0CcentCut || col.centFT0C() > maxT0CcentCut) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::Centrality); + + // Z-vertex position cut + if (std::fabs(col.posZ()) > posZcut) { + return false; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::VtxZ); + + return true; + } + + void processQA(ColEvSels::iterator const& collision, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, aod::FV0As const& /*fv0as*/, aod::FT0s const& /*ft0s*/, TheFilteredTracks const& tracks) + { + const auto& foundBC = collision.foundBC_as(); + const auto cent = collision.centFT0C(); + if (!isEventSelected(collision)) { + return; + } + if (!foundBC.has_zdc()) { + return; + } + histos.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; + } + } + histos.fill(HIST("hEventCounter"), EvCutLabel::TZero); + if (foundBC.has_fv0a()) { + for (const auto& amplitude : foundBC.fv0a().amplitude()) { + aV0A += amplitude; + } + } + float tZNA{zdc.timeZNA()}; + float tZNC{zdc.timeZNC()}; + float tZPA{zdc.timeZPA()}; + float tZPC{zdc.timeZPC()}; + const double normT0M{(aT0A + aT0C) / 100.}; + float znA = zdc.amplitudeZNA() / cfgCollisionEnergy; + float znC = zdc.amplitudeZNC() / cfgCollisionEnergy; + float zpA = zdc.amplitudeZPA() / cfgCollisionEnergy; + float zpC = zdc.amplitudeZPC() / cfgCollisionEnergy; + if (applyZdcCorrection) { + const float b = zdcCoeff; + zpA = zpA - b * znA; + zpC = zpC - b * znC; + } + float commonSumZnc = zdc.energyCommonZNC() / cfgCollisionEnergy; + float commonSumZna = zdc.energyCommonZNA() / cfgCollisionEnergy; + float commonSumZpc = zdc.energyCommonZPC() / cfgCollisionEnergy; + float commonSumZpa = zdc.energyCommonZPA() / cfgCollisionEnergy; + float aZEM1{zdc.amplitudeZEM1()}; + float aZEM2{zdc.amplitudeZEM2()}; + float sumZEMs{aZEM1 + aZEM2}; + 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]) / cfgCollisionEnergy; + float sumZNA = ((zdc.energySectorZNA())[0] + (zdc.energySectorZNA())[1] + (zdc.energySectorZNA())[2] + (zdc.energySectorZNA())[3]) / cfgCollisionEnergy; + float sumZPC = ((zdc.energySectorZPC())[0] + (zdc.energySectorZPC())[1] + (zdc.energySectorZPC())[2] + (zdc.energySectorZPC())[3]) / cfgCollisionEnergy; + float sumZPA = ((zdc.energySectorZPA())[0] + (zdc.energySectorZPA())[1] + (zdc.energySectorZPA())[2] + (zdc.energySectorZPA())[3]) / cfgCollisionEnergy; + float sumSectZN = (sumZNC + sumZNA); + float sumSectZP = (sumZPC + sumZPA); + + if (sumZEMs > zemCut) { + if (isTDCcut) { + if ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) { + histos.fill(HIST("ZNA"), znA); + histos.fill(HIST("ZNACommon"), commonSumZna); + histos.fill(HIST("ZNASector"), sumZNA); + } + if ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) { + histos.fill(HIST("ZNC"), znC); + histos.fill(HIST("ZNCCommon"), commonSumZnc); + histos.fill(HIST("ZNCSector"), sumZNC); + } + if ((tZPA >= minTdcZp) && (tZPA <= maxTdcZp)) { + histos.fill(HIST("ZPA"), zpA); + histos.fill(HIST("ZPACommon"), commonSumZpa); + histos.fill(HIST("ZPASector"), sumZPA); + } + if ((tZPC >= minTdcZp) && (tZPC <= maxTdcZp)) { + histos.fill(HIST("ZPC"), zpC); + histos.fill(HIST("ZPCCommon"), commonSumZpc); + histos.fill(HIST("ZPCSector"), sumZPC); + } + if (((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) && ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn))) + histos.fill(HIST("ZNVsZEM"), sumZEMs, sumZNs); + if (((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) && ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn))) { + histos.fill(HIST("ZNAVsZNC"), znC, znA); + histos.fill(HIST("ZN"), znA + znC); + } + if ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) + histos.fill(HIST("ZNAVsZPA"), zpA, znA); + if ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) + histos.fill(HIST("ZNCVsZPC"), zpC, znC); + if (((tZPA >= minTdcZp) && (tZPA <= maxTdcZp)) && ((tZPC >= minTdcZp) && (tZPC <= maxTdcZp))) + histos.fill(HIST("ZPAVsZPC"), zpC, zpA); + } else { + histos.fill(HIST("ZNA"), znA); + histos.fill(HIST("ZNC"), znC); + histos.fill(HIST("ZPA"), zpA); + histos.fill(HIST("ZPC"), zpC); + histos.fill(HIST("ZNVsZEM"), sumZEMs, sumZNs); + histos.fill(HIST("ZNAVsZNC"), znC, znA); + histos.fill(HIST("ZNAVsZPA"), zpA, znA); + histos.fill(HIST("ZNCVsZPC"), zpC, znC); + histos.fill(HIST("ZPAVsZPC"), zpC, zpA); + histos.fill(HIST("ZNACommon"), commonSumZna); + histos.fill(HIST("ZNASector"), sumZNA); + histos.fill(HIST("ZNCCommon"), commonSumZnc); + histos.fill(HIST("ZNCSector"), sumZNC); + histos.fill(HIST("ZPACommon"), commonSumZpa); + histos.fill(HIST("ZPASector"), sumZPA); + histos.fill(HIST("ZPCCommon"), commonSumZpc); + histos.fill(HIST("ZPCSector"), sumZPC); + histos.fill(HIST("ZN"), znA + znC); + } + histos.fill(HIST("ZEM1"), aZEM1); + histos.fill(HIST("ZEM2"), aZEM2); + histos.fill(HIST("ZNCVstdccoll"), tZNC, znC); + histos.fill(HIST("ZNAVstdccoll"), tZNA, znA); + histos.fill(HIST("ZPCVstdccoll"), tZPC, zpC); + histos.fill(HIST("ZPAVstdccoll"), tZPA, zpA); + histos.fill(HIST("ZEM1Vstdc"), tZEM1, aZEM1); + histos.fill(HIST("ZEM2Vstdc"), tZEM2, aZEM2); + histos.fill(HIST("debunch"), tZNA - tZNC, tZNA + tZNC); + } + float et = 0., meanpt = 0.; + int itsTracks = 0, glbTracks = 0; + for (const auto& track : tracks) { + if (track.hasITS() && ((track.eta() > minEta) && (track.eta() < maxEta))) { + itsTracks++; + } + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + glbTracks++; + } + bool skipEvent{false}; + if (useMidRapNchSel) { + auto hMeanNch = ccdb->getForTimeStamp(paTHmeanNch.value, foundBC.timestamp()); + auto hSigmaNch = ccdb->getForTimeStamp(paTHsigmaNch.value, foundBC.timestamp()); + if (!hMeanNch) { + LOGF(info, "hMeanNch NOT LOADED!"); + return; + } + if (!hSigmaNch) { + LOGF(info, "hSigmaNch NOT LOADED!"); + return; + } + + const int binT0M{hMeanNch->FindBin(normT0M)}; + const double meanNch{hMeanNch->GetBinContent(binT0M)}; + const double sigmaNch{hSigmaNch->GetBinContent(binT0M)}; + const double nSigmaSelection{nSigmaNchCut * sigmaNch}; + const double diffMeanNch{meanNch - glbTracks}; + + if (!(std::abs(diffMeanNch) < nSigmaSelection)) { + histos.fill(HIST("ExcludedEvtVsNch"), glbTracks); + } else { + skipEvent = true; + } + } else { + skipEvent = true; + } + if (!skipEvent) { + return; + } + + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + histos.fill(HIST("ZposVsEta"), collision.posZ(), track.eta()); + histos.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); + histos.fill(HIST("dcaXYvspT"), track.dcaXY(), track.pt()); + et += std::sqrt(std::pow(track.pt(), 2.) + std::pow(o2::constants::physics::MassPionCharged, 2.)); + meanpt += track.pt(); + } + histos.fill(HIST("zPos"), collision.posZ()); + histos.fill(HIST("T0Ccent"), collision.centFT0C()); + histos.fill(HIST("GlbTracks"), glbTracks); + + if (sumZEMs > zemCut) { + histos.fill(HIST("ZNVsFT0C"), aT0C / 100., znA + znC); + histos.fill(HIST("ZNVsFT0M"), (aT0A + aT0C) / 100., znA + znC); + histos.fill(HIST("ZPVsFT0A"), aT0A / 100., zpA + zpC); + histos.fill(HIST("ZPVsFT0C"), aT0C / 100., zpA + zpC); + histos.fill(HIST("ZPVsFT0M"), (aT0A + aT0C) / 100., zpA + zpC); + histos.fill(HIST("ZPAVsFT0A"), aT0A / 100., zpA); + histos.fill(HIST("ZPAVsFT0C"), aT0C / 100., zpA); + histos.fill(HIST("ZPAVsFT0M"), (aT0A + aT0C) / 100., zpA); + histos.fill(HIST("ZPCVsFT0A"), aT0A / 100., zpC); + histos.fill(HIST("ZPCVsFT0C"), aT0C / 100., zpC); + histos.fill(HIST("ZPCVsFT0M"), (aT0A + aT0C) / 100., zpC); + histos.fill(HIST("ZNCVsFT0A"), aT0A / 100., znC); + histos.fill(HIST("ZNCVsFT0C"), aT0C / 100., znC); + histos.fill(HIST("ZNCVsFT0M"), (aT0A + aT0C) / 100., znC); + histos.fill(HIST("ZNAVsFT0A"), aT0A / 100., znA); + histos.fill(HIST("ZNAVsFT0C"), aT0C / 100., znA); + histos.fill(HIST("ZNAVsFT0M"), (aT0A + aT0C) / 100., znA); + histos.fill(HIST("ZPAvsCent"), cent, zpA); + histos.fill(HIST("ZPCvsCent"), cent, zpC); + if (std::isfinite(zpA) && !std::isnan(zpA) && cent >= minT0CcentCut && cent < maxT0CcentCut && glbTracks >= minNch && glbTracks < maxNch) { + histos.fill(HIST("hZPASectorvsGlbTrack"), glbTracks, sumZPA); + } + if (std::isfinite(zpC) && !std::isnan(zpC) && cent >= minT0CcentCut && cent < maxT0CcentCut && glbTracks >= minNch && glbTracks < maxNch) { + histos.fill(HIST("hZPCSectorvsGlbTrack"), glbTracks, sumZPC); + } + histos.fill(HIST("hZNASectorvsGlbTrack"), glbTracks, sumZNA); + histos.fill(HIST("hZNCSectorvsGlbTrack"), glbTracks, sumZNC); + histos.fill(HIST("hZPSectorvsGlbTrack"), glbTracks, sumSectZP); + histos.fill(HIST("hZNSectorvsGlbTrack"), glbTracks, sumSectZN); + // ZDC Correlations + histos.fill(HIST("ZNAVsNch"), glbTracks, znA); + histos.fill(HIST("ZNCVsNch"), glbTracks, znC); + histos.fill(HIST("ZNVsNch"), glbTracks, sumZNs); + histos.fill(HIST("ZNDifVsNch"), glbTracks, znA - znC); + histos.fill(HIST("ZNCcvsZNCsum"), sumZNC, zdc.energyCommonZNC()); + histos.fill(HIST("ZNAcvsZNAsum"), sumZNA, zdc.energyCommonZNA()); + histos.fill(HIST("ZPCcvsZPCsum"), sumZPC, zdc.energyCommonZPC()); + histos.fill(HIST("ZPAcvsZPAsum"), sumZPA, zdc.energyCommonZPA()); + } + + histos.fill(HIST("ampFT0C"), aT0C / 100.); + histos.fill(HIST("ampFT0A"), aT0A / 100.); + histos.fill(HIST("ampFT0M"), (aT0A + aT0C) / 100.); + histos.fill(HIST("ampFV0A"), aV0A / 100.); + // charged particle correlations + histos.fill(HIST("NchVsFV0A"), aV0A / 100., glbTracks); + histos.fill(HIST("NchVsFT0A"), aT0A / 100., glbTracks); + histos.fill(HIST("NchVsFT0C"), aT0C / 100., glbTracks); + histos.fill(HIST("NchVsFT0M"), (aT0A + aT0C) / 100., glbTracks); + histos.fill(HIST("hNchvsNPV"), collision.multNTracksPVeta1(), tracks.size()); + histos.fill(HIST("NchVsEt"), et, glbTracks); + histos.fill(HIST("NchVsITStracks"), itsTracks, glbTracks); + if (glbTracks >= minNchSel) { + histos.fill(HIST("NchVsMeanPt"), glbTracks, meanpt / glbTracks); + } + } + + void processZdcCollAssoc( + AodCollisions::iterator const& collision, + AodTracks const& tracks, + BCsRun3 const& /*bcs*/, + aod::Zdcs const& /*zdcs*/, + aod::FT0s const& /*ft0s*/) + { + if (!isEventSelected(collision)) { + return; + } + const auto& foundBC = collision.foundBC_as(); + if (!foundBC.has_zdc()) { + return; + } + int nTot = tracks.size(); + double ft0aAmp = 0; + double ft0cAmp = 0; + if (collision.has_foundFT0()) { + auto ft0 = collision.foundFT0(); + for (const auto& amplitude : ft0.amplitudeA()) { + ft0aAmp += amplitude; + } + for (const auto& amplitude : ft0.amplitudeC()) { + ft0cAmp += amplitude; + } + } + const double normT0M{(ft0aAmp + ft0aAmp) / 100.}; + + const auto& zdcread = foundBC.zdc(); + const auto cent = collision.centFT0C(); + + // ZDC data and histogram filling + float znA = zdcread.amplitudeZNA() / cfgCollisionEnergy; + float znC = zdcread.amplitudeZNC() / cfgCollisionEnergy; + float zpA = zdcread.amplitudeZPA() / cfgCollisionEnergy; + float zpC = zdcread.amplitudeZPC() / cfgCollisionEnergy; + float tZNA{zdcread.timeZNA()}; + float tZNC{zdcread.timeZNC()}; + float tZPA{zdcread.timeZPA()}; + float tZPC{zdcread.timeZPC()}; + float tZDCdif{tZNC + tZPC - tZNA - tZPA}; + float tZDCsum{tZNC + tZPC + tZNA + tZPA}; + float sumZNC = ((zdcread.energySectorZNC())[0] + (zdcread.energySectorZNC())[1] + (zdcread.energySectorZNC())[2] + (zdcread.energySectorZNC())[3]) / cfgCollisionEnergy; + float sumZNA = ((zdcread.energySectorZNA())[0] + (zdcread.energySectorZNA())[1] + (zdcread.energySectorZNA())[2] + (zdcread.energySectorZNA())[3]) / cfgCollisionEnergy; + float sumZPC = ((zdcread.energySectorZPC())[0] + (zdcread.energySectorZPC())[1] + (zdcread.energySectorZPC())[2] + (zdcread.energySectorZPC())[3]) / cfgCollisionEnergy; + float sumZPA = ((zdcread.energySectorZPA())[0] + (zdcread.energySectorZPA())[1] + (zdcread.energySectorZPA())[2] + (zdcread.energySectorZPA())[3]) / cfgCollisionEnergy; + float sumZDC = sumZPA + sumZPC + sumZNA + sumZNC; + float sumZEM = zdcread.amplitudeZEM1() + zdcread.amplitudeZEM2(); + float sumZNs{znA + znC}; + float sumZPs{zpA + zpC}; + // TDC cut + if (isTDCcut) { + if (std::sqrt(std::pow(tZDCdif, 2.) + std::pow(tZDCsum, 2.)) > tdcCut) { + return; + } + histos.fill(HIST("hEventCounter"), EvCutLabel::Tdc); + } + // common energies + float commonSumZnc = zdcread.energyCommonZNC() / cfgCollisionEnergy; + float commonSumZna = zdcread.energyCommonZNA() / cfgCollisionEnergy; + float commonSumZpc = zdcread.energyCommonZPC() / cfgCollisionEnergy; + float commonSumZpa = zdcread.energyCommonZPA() / cfgCollisionEnergy; + float sumZN = (sumZNC) + (sumZNA); + float sumZP = (sumZPC) + (sumZPA); + + int itsTracks = 0, glbTracks = 0; + for (const auto& track : tracks) { + // Track Selection + if (track.hasITS()) { + itsTracks++; + } + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + histos.fill(HIST("ZposVsEta"), collision.posZ(), track.eta()); + histos.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); + histos.fill(HIST("dcaXYvspT"), track.dcaXY(), track.pt()); + glbTracks++; + } + bool skipEvent{false}; + if (useMidRapNchSel) { + auto hMeanNch = ccdb->getForTimeStamp(paTHmeanNch.value, foundBC.timestamp()); + auto hSigmaNch = ccdb->getForTimeStamp(paTHsigmaNch.value, foundBC.timestamp()); + if (!hMeanNch) { + LOGF(info, "hMeanNch NOT LOADED!"); + return; + } + if (!hSigmaNch) { + LOGF(info, "hSigmaNch NOT LOADED!"); + return; + } + const int binT0M{hMeanNch->FindBin(normT0M)}; + const double meanNch{hMeanNch->GetBinContent(binT0M)}; + const double sigmaNch{hSigmaNch->GetBinContent(binT0M)}; + const double nSigmaSelection{nSigmaNchCut * sigmaNch}; + const double diffMeanNch{meanNch - glbTracks}; + if (!(std::abs(diffMeanNch) < nSigmaSelection)) { + histos.fill(HIST("ExcludedEvtVsFT0M"), normT0M); + histos.fill(HIST("ExcludedEvtVsNch"), glbTracks); + } else { + skipEvent = true; + } + } + // Skip event based on number of Nch sigmas + if (!skipEvent) { + return; + } + std::vector vecOneOverEff; + auto efficiency = ccdb->getForTimeStamp(paTHEff.value, foundBC.timestamp()); + if (!efficiency) { + return; + } + // Calculates the Nch multiplicity + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + + float pt{track.pt()}; + float effValue{1.0}; + if (applyEff) { + effValue = efficiency->GetBinContent(efficiency->FindBin(pt)); + } + if (effValue > 0.) { + vecOneOverEff.emplace_back(1. / effValue); + } + } + + double nchMult{0.}; + nchMult = std::accumulate(vecOneOverEff.begin(), vecOneOverEff.end(), 0); + if (!applyEff) + nchMult = static_cast(glbTracks); + if (applyEff && !correctNch) + nchMult = static_cast(glbTracks); + if (nchMult < minNchSel) { + return; + } + 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()); + 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("Nch"), nchMult); + histos.fill(HIST("ZNamp"), sumZNs); + histos.fill(HIST("NchVsZN"), nchMult, sumZNs); + histos.fill(HIST("NchVsZP"), nchMult, sumZPs); + histos.fill(HIST("NITSTacksVsZN"), itsTracks, sumZNs); + histos.fill(HIST("NITSTacksVsZP"), itsTracks, sumZPs); + histos.fill(HIST("T0MVsZN"), normT0M, sumZNs); + histos.fill(HIST("T0MVsZP"), normT0M, sumZPs); + histos.fill(HIST("NchUncorrected"), glbTracks); + histos.get(HIST("ZDC_energy_vs_ZEM"))->Fill(sumZEM, sumZDC); + } + + void processZdc( + ColEvents const& cols, + BCsRun3 const& /*bcs*/, + aod::Zdcs const& /*zdcs*/) + { + for (const auto& collision : cols) { + const auto& foundBC = collision.foundBC_as(); + if (foundBC.has_zdc()) { + const auto& zdc = foundBC.zdc(); + auto znA = zdc.amplitudeZNA() / cfgCollisionEnergy; + auto znC = zdc.amplitudeZNC() / cfgCollisionEnergy; + auto zpA = zdc.amplitudeZPA() / cfgCollisionEnergy; + auto zpC = zdc.amplitudeZPC() / cfgCollisionEnergy; + float sumZNC = ((zdc.energySectorZNC())[0] + (zdc.energySectorZNC())[1] + (zdc.energySectorZNC())[2] + (zdc.energySectorZNC())[3]) / cfgCollisionEnergy; + float sumZNA = ((zdc.energySectorZNA())[0] + (zdc.energySectorZNA())[1] + (zdc.energySectorZNA())[2] + (zdc.energySectorZNA())[3]) / cfgCollisionEnergy; + float sumZPC = ((zdc.energySectorZPC())[0] + (zdc.energySectorZPC())[1] + (zdc.energySectorZPC())[2] + (zdc.energySectorZPC())[3]) / cfgCollisionEnergy; + float sumZPA = ((zdc.energySectorZPA())[0] + (zdc.energySectorZPA())[1] + (zdc.energySectorZPA())[2] + (zdc.energySectorZPA())[3]) / cfgCollisionEnergy; + float commonSumZnc = zdc.energyCommonZNC() / cfgCollisionEnergy; + float commonSumZna = zdc.energyCommonZNA() / cfgCollisionEnergy; + float commonSumZpc = zdc.energyCommonZPC() / cfgCollisionEnergy; + float commonSumZpa = zdc.energyCommonZPA() / cfgCollisionEnergy; + float aZEM1 = zdc.amplitudeZEM1(); + float aZEM2 = zdc.amplitudeZEM2(); + float sumZEMs = aZEM1 + aZEM2; + auto tZNA = zdc.timeZNA(); + auto tZNC = zdc.timeZNC(); + auto tZPA = zdc.timeZPA(); + auto tZPC = zdc.timeZPC(); + if (isTDCcut) { + if ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) + histos.fill(HIST("ampZna"), znA); + if ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) + histos.fill(HIST("ampZnc"), znC); + if ((tZPA >= minTdcZp) && (tZPA <= maxTdcZp)) + histos.fill(HIST("ampZpa"), zpA); + if ((tZPC >= minTdcZp) && (tZPC <= maxTdcZp)) + histos.fill(HIST("ampZpc"), zpC); + if (((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) && ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn))) + histos.fill(HIST("ZnVsZem"), sumZEMs, znC + znA); + if (((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) && ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn))) + histos.fill(HIST("ZnaVsZnc"), znA, znC); + if (((tZPC >= minTdcZp) && (tZPC <= maxTdcZp)) && ((tZPA >= minTdcZp) && (tZPA <= maxTdcZp))) + histos.fill(HIST("ZpaVsZpc"), zpA, zpC); + if ((tZNA >= minTdcZn) && (tZNA <= maxTdcZn)) + histos.fill(HIST("ZnaVsZpa"), znA, zpA); + if ((tZNC >= minTdcZn) && (tZNC <= maxTdcZn)) + histos.fill(HIST("ZncVsZpc"), znC, zpC); + } else { + histos.fill(HIST("ampZna"), znA); + histos.fill(HIST("ampZnc"), znC); + histos.fill(HIST("ampZpa"), zpA); + histos.fill(HIST("ampZpc"), zpC); + histos.fill(HIST("ZnVsZem"), sumZEMs, znC + znA); + histos.fill(HIST("ZnaVsZnc"), znA, znC); + histos.fill(HIST("ZpaVsZpc"), zpA, zpC); + histos.fill(HIST("ZnaVsZpa"), znA, zpA); + histos.fill(HIST("ZncVsZpc"), znC, zpC); + } + histos.fill(HIST("ampZEM1"), aZEM1); + histos.fill(HIST("ampZEM2"), aZEM2); + histos.fill(HIST("ZnccVsZncSum"), sumZNC, commonSumZnc); + histos.fill(HIST("ZnacVsZnaSum"), sumZNA, commonSumZna); + histos.fill(HIST("ZpccVsZpcSum"), sumZPC, commonSumZpc); + histos.fill(HIST("ZpacVsZpaSum"), sumZPA, commonSumZpa); + histos.fill(HIST("ZncVsTdc"), zdc.timeZNC(), znC); + histos.fill(HIST("ZnaVsTdc"), zdc.timeZNA(), znA); + histos.fill(HIST("ZpcVsTdc"), zdc.timeZPC(), zpC); + histos.fill(HIST("ZpaVsTdc"), zdc.timeZPA(), zpA); + histos.fill(HIST("Zem1VsTdc"), zdc.timeZEM1(), aZEM1); + histos.fill(HIST("Zem2VsTdc"), zdc.timeZEM2(), aZEM2); + } + } + } + + PROCESS_SWITCH(FlowZdcTask, processQA, "Process QA", true); + PROCESS_SWITCH(FlowZdcTask, processZdcCollAssoc, "Processing ZDC w. collision association", false); + PROCESS_SWITCH(FlowZdcTask, processZdc, "Process ZDC without corrections or associations", true); + +}; // end of struct function + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx new file mode 100644 index 00000000000..86b50a2a822 --- /dev/null +++ b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx @@ -0,0 +1,720 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file pidFlowPtCorr.cxx +/// \author Fuchun Cui(fcui@cern.ch) +/// \since Nov/24/2025 +/// \brief This task is to caculate vn-[pt] correlation of PID particles + +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.h" + +#include "PWGMM/Mult/DataModel/Index.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/EventPlaneHelper.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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include "TList.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct PidFlowPtCorr { + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgDeltaPhiLocDen, int, 3, "Number of delta phi for local density, 200 bins in 2 pi") + + struct : ConfigurableGroup { + std::string prefix = "trkQualityOpts"; + // track selections + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgRangeEta, float, 0.4f, "Eta range for mean Pt") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "Maximal pT for ref tracks") + // track quality selections for daughter track + O2_DEFINE_CONFIGURABLE(cfgITSNCls, int, 5, "check minimum number of ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgTPCNCls, int, 50, "check minimum number of TPC hits") + O2_DEFINE_CONFIGURABLE(cfgITSChi2NDF, double, 2.5, "check ITS Chi2NDF") + O2_DEFINE_CONFIGURABLE(cfgCheckGlobalTrack, bool, false, "check global track") + } trkQualityOpts; + + struct : ConfigurableGroup { + std::string prefix = "evtSelOpts"; + O2_DEFINE_CONFIGURABLE(cfgDoTVXinTRD, bool, false, "check kTVXinTRD") + O2_DEFINE_CONFIGURABLE(cfgDoNoTimeFrameBorder, bool, true, "check kNoTimeFrameBorder") + O2_DEFINE_CONFIGURABLE(cfgDoNoITSROFrameBorder, bool, true, "check kNoITSROFrameBorder") + O2_DEFINE_CONFIGURABLE(cfgDoNoSameBunchPileup, bool, true, "check kNoITSROFrameBorder") + O2_DEFINE_CONFIGURABLE(cfgDoIsGoodZvtxFT0vsPV, bool, true, "check kIsGoodZvtxFT0vsPV") + O2_DEFINE_CONFIGURABLE(cfgDoNoCollInTimeRangeStandard, bool, true, "check kNoCollInTimeRangeStandard") + O2_DEFINE_CONFIGURABLE(cfgDoIsGoodITSLayersAll, bool, true, "check kIsGoodITSLayersAll") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyHigh, int, 3000, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgMultPVCut, int, 5, "Use apassX MultPVCut function or not (-1)") + O2_DEFINE_CONFIGURABLE(cfgDoV0AT0Acut, bool, true, "do V0A-T0A cut") + O2_DEFINE_CONFIGURABLE(cfgCutminIR, float, -1, "cut min IR") + O2_DEFINE_CONFIGURABLE(cfgCutmaxIR, float, 3000, "cut max IR") + } evtSeleOpts; + + O2_DEFINE_CONFIGURABLE(cfgCasc_rapidity, float, 0.5, "rapidity") + O2_DEFINE_CONFIGURABLE(cfgNSigmapid, std::vector, (std::vector{3, 3, 3, 9, 9, 9, 9, 9, 9}), "tpc, tof and its NSigma for Pion Proton Kaon") + O2_DEFINE_CONFIGURABLE(cfgMeanPtcent, std::vector, (std::vector{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}), "mean Pt in different cent bin") + 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(cfgRunNumbers, std::vector, (std::vector{544095, 544098, 544116, 544121, 544122, 544123, 544124}), "Preconfigured run numbers") + // switch + O2_DEFINE_CONFIGURABLE(cfgDoAccEffCorr, bool, false, "do acc and eff corr") + O2_DEFINE_CONFIGURABLE(cfgDoLocDenCorr, bool, false, "do local density corr") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgOutputrunbyrun, bool, false, "Fill and output NUA weights run by run") + O2_DEFINE_CONFIGURABLE(cfgOutputLocDenWeights, bool, false, "Fill and output local density weights") + O2_DEFINE_CONFIGURABLE(cfgOutputQA, bool, false, "do QA") + + 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 cfgaxisMeanPt{"cfgaxisMeanPt", {300, 0, 3}, "pt (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) < trkQualityOpts.cfgCutEta.value) && ((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 + + // Connect to ccdb + Service ccdb; + ctpRateFetcher rateFetcher; + 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")}; + + // define global variables + GFW* fGFW = new GFW(); // GFW class used from main src + std::vector corrconfigs; + std::vector cfgAcceptance; + std::vector cfgEfficiency; + std::vector cfgNSigma; + std::vector cfgMeanPt; + std::vector runNumbers; + std::map>> th1sList; + std::map>> th3sList; + enum OutputTH1Names { + // here are TProfiles for vn-pt correlations that are not implemented in GFW + hPhi = 0, + hPhicorr, + kCount_TH1Names + }; + + enum OutputTH3Names { + hPhiEtaVtxz = 0, + kCount_TH3Names + }; + + 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; + + TAxis* fMultAxis = nullptr; + + void init(InitContext const&) // Initialization + { + ccdb->setURL(cfgurl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(cfgnolaterthan.value); + + cfgAcceptance = cfgAcceptancePath; + cfgEfficiency = cfgEfficiencyPath; + cfgNSigma = cfgNSigmapid; + cfgMeanPt = cfgMeanPtcent; + + // 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 axisMult = axisMultiplicity; + int nMultBins = axisMult.binEdges.size() - 1; + fMultAxis = new TAxis(nMultBins, &(axisMult.binEdges)[0]); + + // 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("hMultTPC", "", {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("hCentvsMultTPC", "", {HistType::kTH2D, {{18, 0, 90}, cfgaxisNch}}); + registry.add("MC/hCentvsMultTPCMC", "", {HistType::kTH2D, {{18, 0, 90}, cfgaxisNch}}); + registry.add("hPt", "", {HistType::kTH1D, {cfgaxisPt}}); + registry.add("hEtaPhiVtxzREF", "", {HistType::kTH3D, {cfgaxisPhi, cfgaxisEta, {20, -10, 10}}}); + registry.add("hNTracksPVvsCentrality", "", {HistType::kTH2D, {{500, 0, 500}, axisMultiplicity}}); + + if (cfgOutputrunbyrun) { + runNumbers = cfgRunNumbers; + for (const auto& runNumber : runNumbers) { + std::vector> histosPhi(kCount_TH1Names); + histosPhi[hPhi] = registry.add(Form("%d/hPhi", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + histosPhi[hPhicorr] = registry.add(Form("%d/hPhicorr", runNumber), "", {HistType::kTH1D, {cfgaxisPhi}}); + th1sList.insert(std::make_pair(runNumber, histosPhi)); + + std::vector> nuaTH3(kCount_TH3Names); + nuaTH3[hPhiEtaVtxz] = registry.add(Form("%d/hPhiEtaVtxz", runNumber), ";#varphi;#eta;v_{z}", {HistType::kTH3D, {cfgaxisPhi, {64, -1.6, 1.6}, cfgaxisVertex}}); + th3sList.insert(std::make_pair(runNumber, nuaTH3)); + } + } + + registry.add("hEventCount", "", {HistType::kTH1D, {{14, 0, 14}}}); + 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 kTVXinTRD"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(4, "after kNoTimeFrameBorder"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(5, "after kNoITSROFrameBorder"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(6, "after kDoNoSameBunchPileup"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(7, "after kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(8, "after kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(9, "after kIsGoodITSLayersAll"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(10, "after MultPVCut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(11, "after TPC occupancy cut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(12, "after V0AT0Acut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(13, "after IRmincut"); + registry.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(14, "after IRmaxcut"); + registry.add("hInteractionRate", "", {HistType::kTH1D, {{1000, 0, 1000}}}); + + // cumulant of flow + registry.add("c22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c32", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c24", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c34", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("c22Full", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + + registry.add("pi/c22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ka/c22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pr/c22", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pi/c24", ";Centrality (%) ; C_{2}{4} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ka/c24", ";Centrality (%) ; C_{2}{4} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pr/c24", ";Centrality (%) ; C_{2}{4} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pi/c32", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ka/c32", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pr/c32", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pi/c34", ";Centrality (%) ; C_{2}{4} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ka/c34", ";Centrality (%) ; C_{2}{4} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pr/c34", ";Centrality (%) ; C_{2}{4} ", {HistType::kTProfile, {axisMultiplicity}}); + + // vn-pt corr + registry.add("covV2Pt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pi/covV2Pt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ka/covV2Pt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pr/covV2Pt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("covV3Pt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pi/covV3Pt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ka/covV3Pt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pr/covV3Pt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + + registry.add("covV2Pt_diffpt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pi/covV2Pt_diffpt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ka/covV2Pt_diffpt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pr/covV2Pt_diffpt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("covV3Pt_diffpt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pi/covV3Pt_diffpt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ka/covV3Pt_diffpt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("pr/covV3Pt_diffpt", ";Centrality (%) ; cov(v_{2}^{2}{2}, P_{T}) ", {HistType::kTProfile, {axisMultiplicity}}); + + registry.add("hMeanPt", ";Centrality (%) ; [P_{T}]} ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ptSquareAve", ";Centrality (%) ; [P_{T}^{2}] ", {HistType::kTProfile, {axisMultiplicity}}); + registry.add("ptAve", ";Centrality (%) ; [P_{T}] ", {HistType::kTProfile, {axisMultiplicity}}); + + registry.add("c22dmeanpt", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile2D, {axisMultiplicity, cfgaxisMeanPt}}); + registry.add("pi/c22dmeanpt", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile2D, {axisMultiplicity, cfgaxisMeanPt}}); + registry.add("ka/c22dmeanpt", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile2D, {axisMultiplicity, cfgaxisMeanPt}}); + registry.add("pr/c22dmeanpt", ";Centrality (%) ; C_{2}{2} ", {HistType::kTProfile2D, {axisMultiplicity, cfgaxisMeanPt}}); + + // Data + fGFW->AddRegion("reffull", -0.8, 0.8, 1, 1); // ("name", etamin, etamax, ptbinnum, bitmask)eta region -0.8 to 0.8 + fGFW->AddRegion("refN08", -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP08", 0.4, 0.8, 1, 1); + fGFW->AddRegion("refN", -0.8, 0, 1, 1); + fGFW->AddRegion("refP", 0, 0.8, 1, 1); + + fGFW->AddRegion("poiPiN08", -0.8, -0.4, 1, 2); + fGFW->AddRegion("poiPiP08", 0.4, 0.8, 1, 2); + fGFW->AddRegion("poiPiN", -0.8, 0, 1, 2); + fGFW->AddRegion("poiPiP", 0, 0.8, 1, 2); + fGFW->AddRegion("olPiN", -0.8, 0, 1, 16); + fGFW->AddRegion("olPiP", 0, 0.8, 1, 16); + + fGFW->AddRegion("poiKaN08", -0.8, -0.4, 1, 4); + fGFW->AddRegion("poiKaP08", 0.4, 0.8, 1, 4); + fGFW->AddRegion("poiKaN", -0.8, 0, 1, 4); + fGFW->AddRegion("poiKaP", 0, 0.8, 1, 4); + fGFW->AddRegion("olKaN", -0.8, 0, 1, 32); + fGFW->AddRegion("olKaP", 0, 0.8, 1, 32); + + fGFW->AddRegion("poiPrN08", -0.8, -0.4, 1, 8); + fGFW->AddRegion("poiPrP08", 0.4, 0.8, 1, 8); + fGFW->AddRegion("poiPrN", -0.8, 0, 1, 8); + fGFW->AddRegion("poiPrP", 0, 0.8, 1, 8); + fGFW->AddRegion("olPrN", -0.8, 0, 1, 64); + fGFW->AddRegion("olPrP", 0, 0.8, 1, 64); + + // pushback + // Data + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP08 {2} refN08 {-2}", "Ref08Gap22", kFALSE)); // 0 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN {2 2} refP {-2 -2}", "Ref0Gap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refN {2} refP {-2}", "Ref0Gap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP08 {3} refN08 {-3}", "Ref08Gap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP08 {3 3} refN08 {-3 -3}", "Ref08Gap34", kFALSE)); + + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiN08 {2} refP08 {-2}", "Pion08gap22a", kFALSE)); // 5 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiP08 {2} refN08 {-2}", "Pion08gap22b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN08 {2} refP08 {-2}", "Kaon08gap22a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaP08 {2} refN08 {-2}", "Kaon08gap22b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN08 {2} refP08 {-2}", "Prot08gap22a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP08 {2} refN08 {-2}", "Prot08gap22b", kFALSE)); // 10 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiN refN | olPiN {2 2} refP {-2 -2}", "Pion0gap24a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiP refP | olPiP {2 2} refN {-2 -2}", "Pion0gap24b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN refN | olKaN {2 2} refP {-2 -2}", "Kaon0gap24a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaP refP | olKaP {2 2} refN {-2 -2}", "Kaon0gap24b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN refN | olPrN {2 2} refP {-2 -2}", "Prot0gap24a", kFALSE)); // 15 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP refP | olPaP {2 2} refN {-2 -2}", "Prot0gap24b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiN08 {3} refP08 {-3}", "Pion08gap32a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiP08 {3} refN08 {-3}", "Pion08gap32b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN08 {3} refP08 {-3}", "Kaon08gap32a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaP08 {3} refN08 {-3}", "Kaon08gap32b", kFALSE)); // 20 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN08 {3} refP08 {-3}", "Prot08gap32a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP08 {3} refN08 {-3}", "Prot08gap32b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiN refN | olPiN {3 3} refP {-3 -3}", "Pion0gap34a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiP refP | olPiP {3 3} refN {-3 -3}", "Pion0gap34b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN refN | olKaN {3 3} refP {-3 -3}", "Kaon0gap34a", kFALSE)); // 25 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaP refP | olKaP {3 3} refN {-3 -3}", "Kaon0gap34b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN refN | olPrN {3 3} refP {-3 -3}", "Prot0gap34a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP refP | olPaP {3 3} refN {-3 -3}", "Prot0gap34b", kFALSE)); + + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiN08 {2} poiPiP08 {-2}", "Pion08gap22a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPiP08 {2} poiPiN08 {-2}", "Pion08gap22b", kFALSE)); // 30 + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaN08 {2} poiKaP08 {-2}", "Kaon08gap22a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiKaP08 {2} poiKaN08 {-2}", "Kaon08gap22b", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrN08 {2} poiPrP08 {-2}", "Prot08gap22a", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("poiPrP08 {2} poiPrN08 {-2}", "Prot08gap22b", kFALSE)); + + fGFW->CreateRegions(); // finalize the initialization + + // used for event selection + int caseapass4 = 4; + int caseapass5 = 5; + if (evtSeleOpts.cfgMultPVCut.value == caseapass4) { + 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); + } + if (evtSeleOpts.cfgMultPVCut.value == caseapass5) { + 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(3074.43, -106.192, 1.46176, -0.00968364, 2.61923e-05, 182.128, -7.43492, 0.193901, -0.00256715, 1.22594e-05); + 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(3074.43, -106.192, 1.46176, -0.00968364, 2.61923e-05, 182.128, -7.43492, 0.193901, -0.00256715, 1.22594e-05); + } + + 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); + } + } + + // 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; + } + + template + void fillProfilevnpt(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent, const double& ptSum, const double& nch, const double& meanPt = 0) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) + registry.fill(tarName, cent, val * (ptSum / nch - meanPt), dnx * nch); + return; + } + + template + void fillProfilePOIvnpt(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent, const double& ptSum, const double& nch) + { + double dnx, val; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) + return; + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + + if (std::fabs(val) < 1) + registry.fill(tarName, cent, ptSum / nch, 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; + } + + // event selection + template + bool eventSelected(TCollision collision, const float centrality, float interactionRate = -1) + { + if (evtSeleOpts.cfgDoTVXinTRD.value && collision.alias_bit(kTVXinTRD)) { + // TRD triggered + return false; + } + registry.fill(HIST("hEventCount"), 2.5); + if (evtSeleOpts.cfgDoNoTimeFrameBorder.value && !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"), 3.5); + if (evtSeleOpts.cfgDoNoITSROFrameBorder.value && !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"), 4.5); + if (evtSeleOpts.cfgDoNoSameBunchPileup.value && !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"), 5.5); + if (evtSeleOpts.cfgDoIsGoodZvtxFT0vsPV.value && !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"), 6.5); + if (evtSeleOpts.cfgDoNoCollInTimeRangeStandard.value && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + registry.fill(HIST("hEventCount"), 7.5); + if (evtSeleOpts.cfgDoIsGoodITSLayersAll.value && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // cut time intervals with dead ITS staves + return 0; + } + registry.fill(HIST("hEventCount"), 8.5); + 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; + int caseapass4 = 4; + int caseapass5 = 5; + registry.fill(HIST("hNTracksPVvsCentrality"), multNTracksPV, centrality); + if (evtSeleOpts.cfgMultPVCut.value == caseapass4 || evtSeleOpts.cfgMultPVCut.value == caseapass5) { + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + return false; + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + return false; + } + registry.fill(HIST("hEventCount"), 9.5); + + if (occupancy > evtSeleOpts.cfgCutOccupancyHigh.value) + return 0; + registry.fill(HIST("hEventCount"), 10.5); + + // V0A T0A 5 sigma cut + if (evtSeleOpts.cfgDoV0AT0Acut.value) { + int nsigma = 5; + if (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > nsigma * fT0AV0ASigma->Eval(collision.multFT0A())) + return 0; + } + registry.fill(HIST("hEventCount"), 11.5); + + registry.fill(HIST("hInteractionRate"), interactionRate); + if (interactionRate > 0 && interactionRate < evtSeleOpts.cfgCutminIR.value) + return false; + registry.fill(HIST("hEventCount"), 12.5); + if (interactionRate > evtSeleOpts.cfgCutmaxIR.value) + return false; + registry.fill(HIST("hEventCount"), 13.5); + + return true; + } + + void processData(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracks const& tracks) + { + // o2::aod::ITSResponse itsResponse; + int nTot = tracks.size(); + float nMultTPC = collision.multTPC(); + auto bc = collision.bc_as(); + int runNumber = bc.runNumber(); + double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + + registry.fill(HIST("hEventCount"), 0.5); + if (nTot < 1) + return; + fGFW->Clear(); + const auto cent = collision.centFT0C(); + if (!collision.sel8()) + return; + registry.fill(HIST("hEventCount"), 1.5); + if (!eventSelected(collision, cent, interactionRate)) + return; + loadCorrections(bc.timestamp()); + float vtxz = collision.posZ(); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), nTot); + registry.fill(HIST("hMultTPC"), nMultTPC); + registry.fill(HIST("hCent"), cent); + + float weff = 1; + float wacc = 1; + double ptSum = 0; + double ptSumw2 = 0; + double nch = 0; + double nchSquare = 0; + double ptSquareSum = 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()); + if (!((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value))) + continue; + fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) + if (track.tpcNSigmaPi() < cfgNSigma[0]) + fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 18); + if (track.tpcNSigmaKa() < cfgNSigma[1]) + fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 36); + if (track.tpcNSigmaPr() < cfgNSigma[2]) + fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 72); + + if (cfgOutputNUAWeights) + fWeightsREF->fill(track.phi(), track.eta(), vtxz, track.pt(), cent, 0); + + if (cfgOutputrunbyrun) { + th1sList[runNumber][hPhi]->Fill(track.phi()); + th1sList[runNumber][hPhicorr]->Fill(track.phi(), wacc); + th3sList[runNumber][hPhiEtaVtxz]->Fill(track.phi(), track.eta(), vtxz); + } + + if (std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { + nch += weff; + nchSquare += weff * weff; + ptSum += weff * track.pt(); + ptSumw2 += weff * weff * track.pt(); + ptSquareSum += weff * weff * track.pt() * track.pt(); + } + } + + if (nch > 0) { + int centbin = 0; + centbin = fMultAxis->FindBin(cent); + + fillProfile(corrconfigs.at(0), HIST("c22"), cent); + fillProfile(corrconfigs.at(1), HIST("c24"), cent); + fillProfile(corrconfigs.at(2), HIST("c22Full"), cent); + fillProfile(corrconfigs.at(3), HIST("c32"), cent); + fillProfile(corrconfigs.at(4), HIST("c34"), cent); + + fillProfile(corrconfigs.at(5), HIST("pi/c22"), cent); + fillProfile(corrconfigs.at(6), HIST("pi/c22"), cent); + fillProfile(corrconfigs.at(7), HIST("ka/c22"), cent); + fillProfile(corrconfigs.at(8), HIST("ka/c22"), cent); + fillProfile(corrconfigs.at(9), HIST("pr/c22"), cent); + fillProfile(corrconfigs.at(10), HIST("pr/c22"), cent); + + fillProfile(corrconfigs.at(11), HIST("pi/c24"), cent); + fillProfile(corrconfigs.at(12), HIST("pi/c24"), cent); + fillProfile(corrconfigs.at(13), HIST("ka/c24"), cent); + fillProfile(corrconfigs.at(14), HIST("ka/c24"), cent); + fillProfile(corrconfigs.at(15), HIST("pr/c24"), cent); + fillProfile(corrconfigs.at(16), HIST("pr/c24"), cent); + + fillProfile(corrconfigs.at(17), HIST("pi/c32"), cent); + fillProfile(corrconfigs.at(18), HIST("pi/c32"), cent); + fillProfile(corrconfigs.at(19), HIST("ka/c32"), cent); + fillProfile(corrconfigs.at(20), HIST("ka/c32"), cent); + fillProfile(corrconfigs.at(21), HIST("pr/c32"), cent); + fillProfile(corrconfigs.at(22), HIST("pr/c32"), cent); + + fillProfile(corrconfigs.at(23), HIST("pi/c34"), cent); + fillProfile(corrconfigs.at(24), HIST("pi/c34"), cent); + fillProfile(corrconfigs.at(25), HIST("ka/c34"), cent); + fillProfile(corrconfigs.at(26), HIST("ka/c34"), cent); + fillProfile(corrconfigs.at(27), HIST("pr/c34"), cent); + fillProfile(corrconfigs.at(28), HIST("pr/c34"), cent); + + fillProfilevnpt(corrconfigs.at(0), HIST("covV2Pt"), cent, ptSum, nch, 0); + fillProfilevnpt(corrconfigs.at(0), HIST("covV2Pt_diffpt"), cent, ptSum, nch, cfgMeanPt[centbin]); + fillProfilevnpt(corrconfigs.at(29), HIST("pi/covV2Pt"), cent, ptSum, nch, 0); + fillProfilevnpt(corrconfigs.at(29), HIST("pi/covV2Pt_diffpt"), cent, ptSum, nch, cfgMeanPt[centbin]); + fillProfilevnpt(corrconfigs.at(30), HIST("ka/covV2Pt"), cent, ptSum, nch, 0); + fillProfilevnpt(corrconfigs.at(30), HIST("ka/covV2Pt_diffpt"), cent, ptSum, nch, cfgMeanPt[centbin]); + fillProfilevnpt(corrconfigs.at(31), HIST("pr/covV2Pt"), cent, ptSum, nch, 0); + fillProfilevnpt(corrconfigs.at(31), HIST("pr/covV2Pt_diffpt"), cent, ptSum, nch, cfgMeanPt[centbin]); + + fillProfilePOIvnpt(corrconfigs.at(0), HIST("c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(5), HIST("pi/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(6), HIST("pi/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(7), HIST("ka/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(8), HIST("ka/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(9), HIST("pr/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(10), HIST("pr/c22dmeanpt"), cent, ptSum, nch); + registry.fill(HIST("hMeanPt"), cent, (ptSum / nch), nch); + + double nchDiff = nch * nch - nchSquare; + if (nchDiff) { + registry.fill(HIST("ptSquareAve"), cent, + (ptSum * ptSum - ptSquareSum) / nchDiff, + nchDiff); + registry.fill(HIST("ptAve"), cent, + (nch * ptSum - ptSumw2) / nchDiff, + nchDiff); + } + } + } + PROCESS_SWITCH(PidFlowPtCorr, processData, "", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/Flow/Tasks/resonancesGfwFlow.cxx b/PWGCF/Flow/Tasks/resonancesGfwFlow.cxx new file mode 100644 index 00000000000..45f4284391c --- /dev/null +++ b/PWGCF/Flow/Tasks/resonancesGfwFlow.cxx @@ -0,0 +1,1440 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGCF/GenericFramework/Core/FlowContainer.h" +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWConfig.h" +#include "PWGCF/GenericFramework/Core/GFWCumulant.h" +#include "PWGCF/GenericFramework/Core/GFWPowerArray.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" +#include "PWGCF/GenericFramework/Core/GFWWeightsList.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include "Math/Vector4D.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; + +namespace +{ +std::vector> refV2; +std::vector> phiV2; +std::vector> k0V2; +std::vector> lambdaV2; + +std::vector>> refBoot; +std::vector>> phiBoot; +std::vector>> k0Boot; +std::vector>> lambdaBoot; +} // namespace + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +namespace o2::analysis::genericframework +{ +GFWRegions regions; +GFWCorrConfigs configs; +} // namespace o2::analysis::genericframework + +template +auto projectMatrix(Array2D const& mat, std::array& array1, std::array& array2, std::array& array3) +{ + for (auto j = 0; j < static_cast(mat.cols); ++j) { + array1[j] = mat(0, j); + array2[j] = mat(1, j); + array3[j] = mat(2, j); + } + return; +} +template +auto readMatrix(Array2D const& mat, P& array) +{ + for (auto i = 0; i < static_cast(mat.rows); ++i) { + for (auto j = 0; j < static_cast(mat.cols); ++j) { + array[i][j] = mat(i, j); + } + } + + return; +} + +using namespace o2::analysis::genericframework; + +static constexpr float LongArrayFloat[3][20] = {{1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {2.1, 2.2, 2.3, -2.1, -2.2, -2.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {3.1, 3.2, 3.3, -3.1, -3.2, -3.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}}; +static constexpr int LongArrayInt[3][20] = {{1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1}, {2, 2, 2, -2, -2, -2, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1}, {3, 3, 3, -3, -3, -3, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1}}; + +struct ResonancesGfwFlow { + o2::aod::ITSResponse itsResponse; + Service ccdb; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + enum OutputSpecies { + K0 = 0, + LAMBDA = 1, + PHI = 2, + ANLAMBDA = 3, + REF = 4, + kCount_OutputSpecies + }; + enum Particles { + PIONS, + KAONS, + PROTONS + }; + enum ParticleCuts { + kCosPA = 0, + kMassMin, + kMassMax, + kPosTrackPt, + kNegTrackPt, + kDCAPosToPVMin, + kDCANegToPVMin, + kLifeTime, + kRadiusMin, + kRadiusMax, + kRapidity + }; + enum ParticleSwitches { + kUseParticle = 0, + kUseCosPA, + kMassBins, + kDCABetDaug, + kUseProperLifetime, + kUseV0Radius + }; + enum EventCutTypes { + kFilteredEvents = 0, + kAfterSel8, + kUseNoTimeFrameBorder, + kUseNoITSROFrameBorder, + kUseNoSameBunchPileup, + kUseGoodZvtxFT0vsPV, + kUseNoCollInTimeRangeStandard, + kUseGoodITSLayersAll, + kUseNoCollInRofStandard, + kUseNoHighMultCollInPrevRof, + kUseOccupancy, + kUseMultCorrCut, + kUseT0AV0ACut, + kUseVertexITSTPC, + kUseTVXinTRD + }; + enum TrackCutTypes { + kFilteredTracks = 0, + kUseGlobalTracks, + kUsePvContributor, + kItsClustersCut, + kHasTpcSignal, + kTpcClustersCut, + kTpcCrossedRowsCut + }; + + 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, 50, "Number of TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgTpcCrossRows, int, 70, "Number of TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgTpcCut, float, 3.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(cfgITScluster, int, 5, "Number of ITS cluster") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyMin, int, 0, "Minimum occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyMax, int, 2000, "Maximum 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(cfgCutDCAxy, float, 2.0f, "DCAxy range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "DCAz range for tracks") + 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(cfgV0AT0Acut, int, 5, "V0AT0A cut") + O2_DEFINE_CONFIGURABLE(cfgUseLsPhi, bool, true, "Use LikeSign for Phi v2") + O2_DEFINE_CONFIGURABLE(cfgUseOnlyTPC, bool, true, "Use only TPC PID for daughter selection") + O2_DEFINE_CONFIGURABLE(cfgUseStrictPID, bool, true, "Use strict PID cuts for TPC") + O2_DEFINE_CONFIGURABLE(cfgUseAsymmetricPID, bool, false, "Use asymmetric PID cuts") + O2_DEFINE_CONFIGURABLE(cfgUseItsPID, bool, true, "Use ITS PID for particle identification") + + 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"}; + Configurable> cfgUseEventCuts{"cfgUseEventCuts", std::vector{1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, "Switch for various event cuts [Filtered Events, Sel8, kNoTimeFrameBorder, kNoITSROFrameBorder, kNoSameBunchPileup, kIsGoodZvtxFT0vsPV, kNoCollInTimeRangeStandard, kIsGoodITSLayersAll, kNoCollInRofStandard, kNoHighMultCollInPrevRof, Occupancy, Multiplicity correlation, T0AV0A 3 sigma cut, kIsVertexITSTPC, kTVXinTRD]"}; + Configurable> nSigmas{"nSigmas", {LongArrayFloat[0], 3, 6, {"TPC", "TOF", "ITS"}, {"pos_pi", "pos_ka", "pos_pr", "neg_pi", "neg_ka", "neg_pr"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; + Configurable> resonanceCuts{"resonanceCuts", {LongArrayFloat[0], 3, 11, {"K0", "Lambda", "Phi"}, {"cos_PAs", "massMin", "massMax", "PosTrackPt", "NegTrackPt", "DCAPosToPVMin", "DCANegToPVMin", "Lifetime", "RadiusMin", "RadiusMax", "Rapidity"}}, "Labeled array (float) for various cuts on resonances"}; + Configurable> resonanceSwitches{"resonanceSwitches", {LongArrayInt[0], 3, 6, {"K0", "Lambda", "Phi"}, {"UseParticle", "UseCosPA", "NMassBins", "DCABetDaug", "UseProperLifetime", "UseV0Radius"}}, "Labeled array (int) for various cuts on resonances"}; + + Configurable cfgRegions{"cfgRegions", {{"refN08", "refP08", "refFull", "poiNphi", "poiPphi", "poifullphi", "olNphi", "olPphi", "olfullphi", "poiNk0", "poiPk0", "poifullk0", "olNk0", "olPk0", "olfullk0", "poiNlam", "poiPlam", "poifulllam", "olNlam", "olPlam", "olfulllam", "poiNantilam", "poiPantilam", "poifullantilam", "olNantilam", "olPantilam", "olfullantilam"}, {-0.8, 0.4, -0.8, -0.8, 0.4, -0.8, -0.8, 0.4, -0.8, -0.8, 0.4, -0.8, -0.8, 0.4, -0.8, -0.8, 0.4, -0.8, -0.8, 0.4, -0.8, -0.8, 0.4, -0.8, -0.8, 0.4, -0.8}, {-0.4, 0.8, 0.8, -0.4, 0.8, 0.8, -0.4, 0.8, 0.8, -0.4, 0.8, 0.8, -0.4, 0.8, 0.8, -0.4, 0.8, 0.8, -0.4, 0.8, 0.8, -0.4, 0.8, 0.8, -0.4, 0.8, 0.8}, {0, 0, 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}, {1, 1, 1, 2, 2, 2, 32, 32, 32, 4, 4, 4, 64, 64, 64, 8, 8, 8, 128, 128, 128, 16, 16, 16, 256, 256, 256}}, "Configurations for GFW regions"}; + Configurable cfgCorrConfig{"cfgCorrConfig", {{"refN08 {2} refP08 {-2}", "refN08 {2 2} refP08 {-2 -2}", "poiNphi refN08 | olNphi {2} refP08 {-2}", "poiNphi refN08 | olNphi {2 2} refP08 {-2 -2}", "poiPphi refP08 | olPphi {2} refN08 {-2}", "poiPphi refP08 | olPphi {2 2} refN08 {-2 -2}", "poiNk0 refN08 | olNk0 {2} refP08 {-2}", "poiNk0 refN08 | olNk0 {2 2} refP08 {-2 -2}", "poiPk0 refP08 | olPk0 {2} refN08 {-2}", "poiPk0 refP08 | olPk0 {2 2} refN08 {-2 -2}", "poiNlam refN08 | olNlam {2} refP08 {-2}", "poiNlam refN08 | olNlam {2 2} refP08 {-2 -2}", "poiPlam refP08 | olPlam {2} refN08 {-2}", "poiPlam refP08 | olPlam {2 2} refN08 {-2 -2}", "poiNantilam refN08 | olNantilam {2} refP08 {-2}", "poiNantilam refN08 | olNantilam {2 2} refP08 {-2 -2}", "poiPantilam refP08 | olPantilam {2} refN08 {-2}", "poiPantilam refP08 | olPantilam {2 2} refN08 {-2 -2}"}, {"Ref08Gap22", "Ref08Gap24", "PhiF08Gap22", "PhiF08Gap24", "PhiB08Gap22", "PhiB08Gap24", "K0F08Gap22", "K0F08Gap24", "K0B08Gap22", "K0B08Gap24", "LamF08Gap22", "LamF08Gap24", "LamB08Gap22", "LamB08Gap24", "AnLamF08Gap22", "AnLamF08Gap24", "AnLamB08Gap22", "AnLamB08Gap24"}, {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, "Configurations for each correlation to calculate"}; + + // 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"}; + + 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}; + + std::array, 3> resoCutVals; + std::array, 3> resoSwitchVals; + std::array tofNsigmaCut; + std::array itsNsigmaCut; + std::array tpcNsigmaCut; + std::vector eventCuts; + + 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; + + // 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&) + { + int64_t noLaterThan = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + + // Initilizing ccdb + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(noLaterThan); + + LOGF(info, "flowGenericFramework::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(); + + projectMatrix(nSigmas->getData(), tpcNsigmaCut, tofNsigmaCut, itsNsigmaCut); + readMatrix(resonanceCuts->getData(), resoCutVals); + readMatrix(resonanceSwitches->getData(), resoSwitchVals); + eventCuts = cfgUseEventCuts; + + AxisSpec singleCount = {1, 0, 1}; + AxisSpec axisK0Mass = {resoSwitchVals[K0][kMassBins], resoCutVals[K0][kMassMin], resoCutVals[K0][kMassMax]}; + AxisSpec axisLambdaMass = {resoSwitchVals[LAMBDA][kMassBins], resoCutVals[LAMBDA][kMassMin], resoCutVals[LAMBDA][kMassMax]}; + AxisSpec axisPhiMass = {resoSwitchVals[PHI][kMassBins], resoCutVals[PHI][kMassMin], resoCutVals[PHI][kMassMax]}; + + histos.add("hVtxZ", "", {HistType::kTH1D, {axisVertex}}); + histos.add("hMult", "", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + histos.add("hCent", "", {HistType::kTH1D, {{90, 0, 90}}}); + + refBoot.resize(cfgNbootstrap); + phiBoot.resize(cfgNbootstrap); + k0Boot.resize(cfgNbootstrap); + lambdaBoot.resize(cfgNbootstrap); + + // Defining histograms to store correlations + for (auto i = 0; i < configs.GetSize(); ++i) { + if (resoSwitchVals[PHI][kUseParticle] && configs.GetHeads()[i].starts_with("Phi")) { + phiV2.push_back(histos.add(Form("h%spt", configs.GetHeads()[i].c_str()), "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}})); + if (cfgUseBootStrap) { + for (int j = 0; j < cfgNbootstrap; ++j) { + phiBoot[j].push_back(histos.add(Form("BootStrap/h%spt_boot_%d", configs.GetHeads()[i].c_str(), j), "", {HistType::kTProfile3D, {axisPt, axisPhiMass, axisMultiplicity}})); + } + } // end of bootstrap condition + } // end of phi loop + + if (resoSwitchVals[K0][kUseParticle] && configs.GetHeads()[i].starts_with("K0")) { + k0V2.push_back(histos.add(Form("h%spt", configs.GetHeads()[i].c_str()), "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}})); + if (cfgUseBootStrap) { + for (int j = 0; j < cfgNbootstrap; ++j) { + k0Boot[j].push_back(histos.add(Form("BootStrap/h%spt_boot_%d", configs.GetHeads()[i].c_str(), j), "", {HistType::kTProfile3D, {axisPt, axisK0Mass, axisMultiplicity}})); + } + } // end of bootstrap condition + } // end of K0 loop + + if (resoSwitchVals[LAMBDA][kUseParticle] && (configs.GetHeads()[i].starts_with("Lam") || configs.GetHeads()[i].starts_with("AnLam"))) { + lambdaV2.push_back(histos.add(Form("h%spt", configs.GetHeads()[i].c_str()), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}})); + if (cfgUseBootStrap) { + for (int j = 0; j < cfgNbootstrap; ++j) { + lambdaBoot[j].push_back(histos.add(Form("BootStrap/h%spt_boot_%d", configs.GetHeads()[i].c_str(), j), "", {HistType::kTProfile3D, {axisPt, axisLambdaMass, axisMultiplicity}})); + } + } // end of bootstrap condition + } // end of lambda loop + + if (configs.GetHeads()[i].starts_with("Ref")) { + refV2.push_back(histos.add(Form("h%s", configs.GetHeads()[i].c_str()), "", {HistType::kTProfile, {axisMultiplicity}})); + if (cfgUseBootStrap) { + for (int j = 0; j < cfgNbootstrap; ++j) { + refBoot[j].push_back(histos.add(Form("BootStrap/h%s_boot_%d", configs.GetHeads()[i].c_str(), j), "", {HistType::kTProfile, {axisMultiplicity}})); + } + } // end of bootstrap condition + } // end of ref loop + + } // end of configs loop + + if (cfgUseLsPhi) { + histos.add("hLsPhiMass_sparse", "", {HistType::kTHnSparseD, {{axisPhiMass, axisPt, axisMultiplicity}}}); + } + + if (resoSwitchVals[PHI][kUseParticle]) { + histos.add("KaPlusTPC", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("KaMinusTPC", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("KaPlusTOF", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("KaMinusTOF", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("hPhiPhi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hPhiEta", "", {HistType::kTH1D, {axisEta}}); + histos.add("hPhiMass_sparse", "", {HistType::kTHnSparseD, {{axisPhiMass, axisPt, axisMultiplicity}}}); + + histos.add("hPhiCount", "Number of Phi;; Count", {HistType::kTH1D, {{5, 0, 5}}}); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(1, "Phi candidates"); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(2, "Daughter track selection"); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(3, "Fake Kaon"); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(4, "CosPA"); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(5, "Rapidity cut"); + } + if (resoSwitchVals[K0][kUseParticle]) { + histos.add("PiPlusTPC_K0", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PiMinusTPC_K0", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PiPlusTOF_K0", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("PiMinusTOF_K0", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + 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("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 (resoSwitchVals[LAMBDA][kUseParticle]) { + histos.add("PrPlusTPC_L", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PiMinusTPC_L", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PrPlusTOF_L", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("PiMinusTOF_L", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("hLambdaPhi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hLambdaEta", "", {HistType::kTH1D, {axisEta}}); + histos.add("hLambdaMass_sparse", "", {HistType::kTHnSparseF, {{axisLambdaMass, axisPt, axisMultiplicity}}}); + histos.add("PiPlusTPC_AL", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PrMinusTPC_AL", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PiPlusTOF_AL", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("PrMinusTOF_AL", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + 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("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 Events;; Count", {HistType::kTH1D, {{15, -0.5, 14.5}}}); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kFilteredEvents + 1, "Filtered event"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kAfterSel8 + 1, "After sel8"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoTimeFrameBorder + 1, "kNoTimeFrameBorder"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoITSROFrameBorder + 1, "kNoITSROFrameBorder"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoSameBunchPileup + 1, "kNoSameBunchPileup"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoCollInRofStandard + 1, "kNoCollInTimeRangeStandard"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseGoodITSLayersAll + 1, "kIsGoodITSLayersAll"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoCollInRofStandard + 1, "kNoCollInRofStandard"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoHighMultCollInPrevRof + 1, "kNoHighMultCollInPrevRof"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseOccupancy + 1, "Occupancy Cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseMultCorrCut + 1, "Multiplicity correlation Cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseT0AV0ACut + 1, "T0AV0A cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseVertexITSTPC + 1, "kIsVertexITSTPC"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseTVXinTRD + 1, "kTVXinTRD"); + + histos.add("hTrackCount", "Number of Tracks;; Count", {HistType::kTH1D, {{7, -0.5, 6.5}}}); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kFilteredTracks + 1, "Filtered track"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kUseGlobalTracks + 1, "Global tracks"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kUsePvContributor + 1, "PV contributor"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kItsClustersCut + 1, "ITS clusters"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kHasTpcSignal + 1, "TPC signal"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kTpcClustersCut + 1, "TPC clusters"); + histos.get(HIST("hTrackCount"))->GetXaxis()->SetBinLabel(kTpcCrossedRowsCut + 1, "TPC crossed rows"); + + 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}}); + } + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = &(axis.binEdges)[0]; + fPtAxis = new TAxis(nPtBins, ptBins); + + fPhiMassAxis = new TAxis(resoSwitchVals[PHI][kMassBins], resoCutVals[PHI][kMassMin], resoCutVals[PHI][kMassMax]); + fK0MassAxis = new TAxis(resoSwitchVals[K0][kMassBins], resoCutVals[K0][kMassMin], resoCutVals[K0][kMassMax]); + fLambdaMassAxis = new TAxis(resoSwitchVals[LAMBDA][kMassBins], resoCutVals[LAMBDA][kMassMin], resoCutVals[LAMBDA][kMassMax]); + + int nPhisPtMassBins = nPtBins * resoSwitchVals[PHI][kMassBins]; + int nK0sPtMassBins = nPtBins * resoSwitchVals[K0][kMassBins]; + int nLambdasPtMassBins = nPtBins * resoSwitchVals[LAMBDA][kMassBins]; + int nPtMassBins; + + //********** Defining the regions ********** + for (auto i(0); i < regions.GetSize(); ++i) { + if (regions.GetNames()[i].ends_with("phi")) { + nPtMassBins = nPhisPtMassBins; + } else if (regions.GetNames()[i].ends_with("k0")) { + nPtMassBins = nK0sPtMassBins; + } else if (regions.GetNames()[i].ends_with("lam") || regions.GetNames()[i].ends_with("antilam")) { + nPtMassBins = nLambdasPtMassBins; + } else { + nPtMassBins = nPtBins; + } + fGFW->AddRegion(regions.GetNames()[i], regions.GetEtaMin()[i], regions.GetEtaMax()[i], (regions.GetpTDifs()[i]) ? nPtMassBins + 1 : 1, regions.GetBitmasks()[i]); + } + + //********** Defining the correlations ************ + 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(); + + // Multiplicity correlation cuts + if (eventCuts[kUseMultCorrCut]) { + 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); + } + if (eventCuts[kUseT0AV0ACut]) { + 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); + } + + // Track density correction + 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 + int findComponent(std::vector>& ptr, const std::string& name) + { + int nIndex = -1; + for (int i = 0; i < static_cast(ptr.size()); i++) { + if (ptr[i]->GetName() == name) { + nIndex = i; + } + } + + return nIndex; + } + + 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 + double cosinePointingAngle(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)); + + return angle; + } + + 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 isGoodTrack(const TTrack& track) + { + histos.fill(HIST("hTrackCount"), kFilteredTracks); // Filtered tracks + + if (cfgUseGlobalTrack && !(track.isGlobalTrack())) { + return 0; + } + histos.fill(HIST("hTrackCount"), kUseGlobalTracks); // After global track selection + + if (!(track.isPVContributor())) { + return 0; + } + histos.fill(HIST("hTrackCount"), kUsePvContributor); // After PV contributor selection + + if (!(track.itsNCls() > cfgITScluster)) { + return 0; + } + histos.fill(HIST("hTrackCount"), kItsClustersCut); // After ITS cluster selection + + if (!(track.hasTPC())) { + return 0; + } + histos.fill(HIST("hTrackCount"), kHasTpcSignal); // If track has TPC signal + + if (!(track.tpcNClsFound() > cfgTpcCluster)) { + return 0; + } + histos.fill(HIST("hTrackCount"), kTpcClustersCut); // After TPC cluster selection + + if (!(track.tpcNClsCrossedRows() > cfgTpcCrossRows)) { + return 0; + } + histos.fill(HIST("hTrackCount"), kTpcCrossedRowsCut); // After TPC crossed rows selection + + return 1; + } + + template + int getNsigmaPIDTpcTof(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 = cfgTpcCut; + + // Choose which nSigma to use + std::array nSigmaToUse = (track.pt() > cfgTofPtCut && track.hasTOF()) ? nSigmaCombined : nSigmaTPC; + if (track.pt() > cfgTofPtCut && !track.hasTOF()) + return 0; + + const int numSpecies = 3; + int pidCount = 0; + // Select particle with the lowest nsigma + for (int i = 0; i < numSpecies; ++i) { + if (std::abs(nSigmaToUse[i]) < nsigma) { + if (pidCount > 0 && cfgUseStrictPID) + return 0; // more than one particle with low nsigma + + pidCount++; + pid = i; + if (!cfgUseStrictPID) + nsigma = std::abs(nSigmaToUse[i]); + } + } + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + + template + int getNsigmaPIDAssymmetric(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaTOF = {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + std::array nSigmaITS = {itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track)}; + int pid = -1; + + std::array nSigmaToUse = cfgUseItsPID ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS + std::array detectorNsigmaCut = cfgUseItsPID ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS + + bool isPion, isKaon, isProton; + bool isDetectedPion = nSigmaToUse[0] < detectorNsigmaCut[0] && nSigmaToUse[0] > detectorNsigmaCut[0 + 3]; + bool isDetectedKaon = nSigmaToUse[1] < detectorNsigmaCut[1] && nSigmaToUse[1] > detectorNsigmaCut[1 + 3]; + bool isDetectedProton = nSigmaToUse[2] < detectorNsigmaCut[2] && nSigmaToUse[2] > detectorNsigmaCut[2 + 3]; + + bool isTofPion = nSigmaTOF[0] < tofNsigmaCut[0] && nSigmaTOF[0] > tofNsigmaCut[0 + 3]; + bool isTofKaon = nSigmaTOF[1] < tofNsigmaCut[1] && nSigmaTOF[1] > tofNsigmaCut[1 + 3]; + bool isTofProton = nSigmaTOF[2] < tofNsigmaCut[2] && nSigmaTOF[2] > tofNsigmaCut[2 + 3]; + + if (track.pt() > cfgTofPtCut && !track.hasTOF()) { + return 0; + } else if (track.pt() > cfgTofPtCut && track.hasTOF()) { + isPion = isTofPion && isDetectedPion; + isKaon = isTofKaon && isDetectedKaon; + isProton = isTofProton && isDetectedProton; + } else { + isPion = isDetectedPion; + isKaon = isDetectedKaon; + isProton = isDetectedProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + return 0; // more than one particle satisfy the criteria + } + + if (isPion) { + pid = PIONS; + } else if (isKaon) { + pid = KAONS; + } else if (isProton) { + pid = PROTONS; + } else { + return 0; // no particle satisfies the criteria + } + + 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[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[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]); + + 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[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]); + } + + correctionsLoaded = true; + } + + template + double getAcceptance(TTrack track, const TCollision collision, int pid_index_reso) + { // 0 = k0, 1 = lambda, 2 = phi, 3 = anti-lambda, 4 = ref + 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 = k0, 1 = lambda, 2 = phi, 3 = anti-lambda, 4 = ref + 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 == REF) { + 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 + bool selectionV0Daughter(TTrack const& track, int pid) + { + if (!(track.itsNCls() > cfgITScluster)) + return 0; + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < cfgTpcCluster) + return false; + if (!(track.tpcNClsCrossedRows() > cfgTpcCrossRows)) + return 0; + + if (cfgUseOnlyTPC) { + if (pid == PIONS && std::abs(track.tpcNSigmaPi()) > cfgTpcCut) + return false; + if (pid == KAONS && std::abs(track.tpcNSigmaKa()) > cfgTpcCut) + return false; + if (pid == PROTONS && std::abs(track.tpcNSigmaPr()) > cfgTpcCut) + return false; + } else { + int partIndex = cfgUseAsymmetricPID ? getNsigmaPIDAssymmetric(track) : getNsigmaPIDTpcTof(track); + int pidIndex = partIndex - 1; // 0 = pion, 1 = kaon, 2 = proton + if (pidIndex != pid) + return false; + } + + return true; + } + + template + void resurrectPhi(TTrack trackplus, TTrack trackminus, const TCollision collision, vector plusdaug, vector minusdaug, vector mom, double plusmass, const ConstStr& hist) + { + for (auto const& [partplus, partminus] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(trackplus, trackminus))) { + histos.fill(HIST("hPhiCount"), 0.5); + if (!selectionV0Daughter(partplus, KAONS) || !selectionV0Daughter(partminus, KAONS)) // 0 = pion, 1 = kaon, 2 = proton + continue; + histos.fill(HIST("hPhiCount"), 1.5); + + if (isFakeKaon(partplus) || isFakeKaon(partminus)) + continue; + histos.fill(HIST("hPhiCount"), 2.5); + + if (resoSwitchVals[PHI][kUseCosPA] && cosinePointingAngle(partplus, partminus) < resoCutVals[PHI][kCosPA]) + continue; + histos.fill(HIST("hPhiCount"), 3.5); + + 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()); + + // 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()) < resoCutVals[PHI][kRapidity]) { + histos.fill(HIST("hPhiCount"), 4.5); + + histos.fill(hist, invMass, pt, collision.centFT0C()); + histos.fill(HIST("hPhiPhi"), phi); + histos.fill(HIST("hPhiEta"), mom.Eta()); + + // 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); + } + } // end of combinations loop + return; + } + + template + void likeSignPhi(TTrack track, const TCollision collision, double plusmass, const ConstStr& hist) + { + ROOT::Math::PxPyPzMVector daug1, daug2, mom; + for (auto const& [part1, part2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(track, track))) { + + if (!selectionV0Daughter(part1, KAONS) || !selectionV0Daughter(part2, KAONS)) // 0 = pion, 1 = kaon, 2 = proton + continue; + if (isFakeKaon(part1) || isFakeKaon(part2)) + continue; + + // Calculation using ROOT vectors + daug1 = ROOT::Math::PxPyPzMVector(part1.px(), part1.py(), part1.pz(), plusmass); + daug2 = ROOT::Math::PxPyPzMVector(part2.px(), part2.py(), part2.pz(), plusmass); + mom = daug1 + daug2; + + double pt = mom.Pt(); + double invMass = mom.M(); + double phi = mom.Phi(); + + phi = RecoDecay::constrainAngle(phi, 0.0, 1); // constrain azimuthal angle to [0,2pi] + + if (std::abs(mom.Rapidity()) < resoCutVals[PHI][kRapidity]) { + histos.fill(hist, invMass, pt, collision.centFT0C()); + } + } // end of positive combinations loop + return; + } + + 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() < resoCutVals[LAMBDA][kPosTrackPt] || negtrack.pt() < resoCutVals[LAMBDA][kNegTrackPt]) + return false; + + histos.fill(HIST("hLambdaCount"), 1.5); + if (mlambda > resoCutVals[LAMBDA][kMassMin] && mlambda < resoCutVals[LAMBDA][kMassMax]) + isL = true; + if (mantilambda > resoCutVals[LAMBDA][kMassMin] && mantilambda < resoCutVals[LAMBDA][kMassMax]) + isAL = true; + + if (!isL && !isAL) { + return false; + } + histos.fill(HIST("hLambdaCount"), 2.5); + + // Rapidity correction + if (candidate.yLambda() > resoCutVals[LAMBDA][kRapidity]) + return false; + histos.fill(HIST("hLambdaCount"), 3.5); + // DCA cuts for lambda and antilambda + if (isL) { + if (std::abs(candidate.dcapostopv()) < resoCutVals[LAMBDA][kDCAPosToPVMin] || std::abs(candidate.dcanegtopv()) < resoCutVals[LAMBDA][kDCANegToPVMin]) + return false; + } + if (isAL) { + if (std::abs(candidate.dcapostopv()) < resoCutVals[LAMBDA][kDCANegToPVMin] || std::abs(candidate.dcanegtopv()) < resoCutVals[LAMBDA][kDCAPosToPVMin]) + return false; + } + histos.fill(HIST("hLambdaCount"), 4.5); + if (std::abs(candidate.dcaV0daughters()) > resoSwitchVals[LAMBDA][kDCABetDaug]) + return false; + histos.fill(HIST("hLambdaCount"), 5.5); + // v0 radius cuts + if (resoSwitchVals[LAMBDA][kUseV0Radius] && (candidate.v0radius() < resoCutVals[LAMBDA][kRadiusMin] || candidate.v0radius() > resoCutVals[LAMBDA][kRadiusMax])) + return false; + histos.fill(HIST("hLambdaCount"), 6.5); + // cosine pointing angle cuts + if (candidate.v0cosPA() < resoCutVals[LAMBDA][kCosPA]) + return false; + histos.fill(HIST("hLambdaCount"), 7.5); + // Proper lifetime + if (resoSwitchVals[LAMBDA][kUseProperLifetime] && candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda > resoCutVals[LAMBDA][kLifeTime]) + return false; + histos.fill(HIST("hLambdaCount"), 8.5); + if (isL) { + if (!selectionV0Daughter(postrack, PROTONS) || !selectionV0Daughter(negtrack, PIONS)) + return false; + } + if (isAL) { + if (!selectionV0Daughter(postrack, PIONS) || !selectionV0Daughter(negtrack, PROTONS)) + 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("PrPlusTPC_L"), postrack.pt(), postrack.tpcNSigmaKa()); + histos.fill(HIST("PrPlusTOF_L"), postrack.pt(), postrack.tofNSigmaKa()); + histos.fill(HIST("PiMinusTPC_L"), negtrack.pt(), negtrack.tpcNSigmaKa()); + histos.fill(HIST("PiMinusTOF_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("PiPlusTPC_AL"), postrack.pt(), postrack.tpcNSigmaKa()); + histos.fill(HIST("PiPlusTOF_AL"), postrack.pt(), postrack.tofNSigmaKa()); + histos.fill(HIST("PrMinusTPC_AL"), negtrack.pt(), negtrack.tpcNSigmaKa()); + histos.fill(HIST("PrMinusTOF_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() < resoCutVals[K0][kPosTrackPt] || negtrack.pt() < resoCutVals[K0][kNegTrackPt]) + return false; + histos.fill(HIST("hK0Count"), 1.5); + if (mk0 < resoCutVals[K0][kMassMin] && mk0 > resoCutVals[K0][kMassMax]) + return false; + histos.fill(HIST("hK0Count"), 2.5); + // Rapidity correction + if (candidate.yK0Short() > resoCutVals[K0][kRapidity]) + return false; + histos.fill(HIST("hK0Count"), 3.5); + // DCA cuts for K0short + if (std::abs(candidate.dcapostopv()) < resoCutVals[K0][kDCAPosToPVMin] || std::abs(candidate.dcanegtopv()) < resoCutVals[K0][kDCANegToPVMin]) + return false; + histos.fill(HIST("hK0Count"), 4.5); + if (std::abs(candidate.dcaV0daughters()) > resoSwitchVals[K0][kDCABetDaug]) + return false; + histos.fill(HIST("hK0Count"), 5.5); + // v0 radius cuts + if (resoSwitchVals[K0][kUseV0Radius] && (candidate.v0radius() < resoCutVals[K0][kRadiusMin] || candidate.v0radius() > resoCutVals[K0][kRadiusMax])) + return false; + histos.fill(HIST("hK0Count"), 6.5); + // cosine pointing angle cuts + if (candidate.v0cosPA() < resoCutVals[K0][kCosPA]) + return false; + histos.fill(HIST("hK0Count"), 7.5); + // Proper lifetime + if (resoSwitchVals[K0][kUseProperLifetime] && candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massK0Short > resoCutVals[K0][kLifeTime]) + return false; + histos.fill(HIST("hK0Count"), 8.5); + if (!selectionV0Daughter(postrack, PIONS) || !selectionV0Daughter(negtrack, PIONS)) + 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("PiPlusTPC_K0"), postrack.pt(), postrack.tpcNSigmaKa()); + histos.fill(HIST("PiPlusTOF_K0"), postrack.pt(), postrack.tofNSigmaKa()); + histos.fill(HIST("PiMinusTPC_K0"), negtrack.pt(), negtrack.tpcNSigmaKa()); + histos.fill(HIST("PiMinusTOF_K0"), negtrack.pt(), negtrack.tofNSigmaKa()); + + return true; + } + + template + bool selectionEvent(TCollision collision, const int mult, const float cent) + { + histos.fill(HIST("hEventCount"), kFilteredEvents); + if (!collision.sel8()) { + return 0; + } + histos.fill(HIST("hEventCount"), kAfterSel8); + + if (eventCuts[kUseNoTimeFrameBorder] && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return 0; + } + if (eventCuts[kUseNoTimeFrameBorder]) + histos.fill(HIST("hEventCount"), kUseNoTimeFrameBorder); + + if (eventCuts[kUseNoITSROFrameBorder] && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return 0; + } + if (eventCuts[kUseNoITSROFrameBorder]) + histos.fill(HIST("hEventCount"), kUseNoITSROFrameBorder); + + if (eventCuts[kUseNoSameBunchPileup] && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return 0; + } + if (eventCuts[kUseNoSameBunchPileup]) + histos.fill(HIST("hEventCount"), kUseNoSameBunchPileup); + + if (eventCuts[kUseGoodZvtxFT0vsPV] && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return 0; + } + if (eventCuts[kUseGoodZvtxFT0vsPV]) + histos.fill(HIST("hEventCount"), kUseGoodZvtxFT0vsPV); + + if (eventCuts[kUseNoCollInTimeRangeStandard] && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + if (eventCuts[kUseNoCollInTimeRangeStandard]) + histos.fill(HIST("hEventCount"), kUseNoCollInTimeRangeStandard); + + if (eventCuts[kUseGoodITSLayersAll] && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return 0; + } + if (eventCuts[kUseGoodITSLayersAll]) + histos.fill(HIST("hEventCount"), kUseGoodITSLayersAll); + + if (eventCuts[kUseNoCollInRofStandard] && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return 0; + } + if (eventCuts[kUseNoCollInRofStandard]) + histos.fill(HIST("hEventCount"), kUseNoCollInRofStandard); + + if (eventCuts[kUseNoHighMultCollInPrevRof] && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return 0; + } + if (eventCuts[kUseNoHighMultCollInPrevRof]) + histos.fill(HIST("hEventCount"), kUseNoHighMultCollInPrevRof); + + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + + if (eventCuts[kUseOccupancy] && (occupancy < cfgCutOccupancyMin || occupancy > cfgCutOccupancyMax)) { + return 0; + } + if (eventCuts[kUseOccupancy]) + histos.fill(HIST("hEventCount"), kUseOccupancy); + + if (eventCuts[kUseMultCorrCut]) { + if (multNTracksPV < fMultPVCutLow->Eval(cent)) + return 0; + if (multNTracksPV > fMultPVCutHigh->Eval(cent)) + return 0; + if (mult < fMultCutLow->Eval(cent)) + return 0; + if (mult > fMultCutHigh->Eval(cent)) + return 0; + } + if (eventCuts[kUseMultCorrCut]) + histos.fill(HIST("hEventCount"), kUseMultCorrCut); + + // V0A T0A 5 sigma cut + if (eventCuts[kUseT0AV0ACut] && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > cfgV0AT0Acut * fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + if (eventCuts[kUseT0AV0ACut]) + histos.fill(HIST("hEventCount"), kUseT0AV0ACut); + + if (eventCuts[kUseVertexITSTPC] && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return 0; + if (eventCuts[kUseVertexITSTPC]) + histos.fill(HIST("hEventCount"), kUseVertexITSTPC); + + if (eventCuts[kUseTVXinTRD] && collision.alias_bit(kTVXinTRD)) { + return 0; + } + if (eventCuts[kUseTVXinTRD]) + histos.fill(HIST("hEventCount"), kUseTVXinTRD); + + return 1; + } + + // 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) + { + int nTot = tracks.size(); + if (nTot < 1) + return; + + float vtxz = collision.posZ(); + const auto cent = collision.centFT0C(); + + if (!selectionEvent(collision, nTot, cent)) + return; + + 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 (!isGoodTrack(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, REF); + + 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 (resoSwitchVals[PHI][kUseParticle]) { + resurrectPhi(posSlicedTracks, negSlicedTracks, collision, kaonPlus, kaonMinus, phiMom, massKaPlus, HIST("hPhiMass_sparse")); + } + + if (cfgUseLsPhi) { + likeSignPhi(posSlicedTracks, collision, massKaPlus, HIST("hLsPhiMass_sparse")); + likeSignPhi(negSlicedTracks, collision, massKaPlus, HIST("hLsPhiMass_sparse")); + } + + // ---------------------- Analyzing the V0s + for (auto const& v0s : V0s) { + if (resoSwitchVals[K0][kUseParticle]) { + if (selectionK0(collision, v0s) == true) + histos.fill(HIST("hK0s"), 1); + } + if (resoSwitchVals[LAMBDA][kUseParticle]) { + if (selectionLambda(collision, v0s) == true) + histos.fill(HIST("hLambdas"), 1); + } + } // End of v0 loop + + // Filling cumulant profiles + double r = fRndm->Rndm(); + int bootId = static_cast(r * 10); + + for (auto i = 0; i < static_cast(corrconfigs.size()); ++i) { + if (resoSwitchVals[PHI][kUseParticle] && corrconfigs.at(i).Head.starts_with("Phi")) { + int pIndex = findComponent(phiV2, Form("h%spt", corrconfigs.at(i).Head.c_str())); + fillProfileBoot3D(corrconfigs.at(i), phiV2[pIndex], cent, fPhiMassAxis); + + if (cfgUseBootStrap) { + fillProfileBoot3D(corrconfigs.at(i), phiBoot[bootId][pIndex], cent, fPhiMassAxis); + } + } // end of phi condition + + if (resoSwitchVals[K0][kUseParticle] && corrconfigs.at(i).Head.starts_with("K0")) { + int pIndex = findComponent(k0V2, Form("h%spt", corrconfigs.at(i).Head.c_str())); + fillProfileBoot3D(corrconfigs.at(i), k0V2[pIndex], cent, fK0MassAxis); + + if (cfgUseBootStrap) { + fillProfileBoot3D(corrconfigs.at(i), k0Boot[bootId][pIndex], cent, fK0MassAxis); + } + } // end of K0 condition + + if (resoSwitchVals[LAMBDA][kUseParticle] && (corrconfigs.at(i).Head.starts_with("Lam") || corrconfigs.at(i).Head.starts_with("AnLam"))) { + int pIndex = findComponent(lambdaV2, Form("h%spt", corrconfigs.at(i).Head.c_str())); + fillProfileBoot3D(corrconfigs.at(i), lambdaV2[pIndex], cent, fLambdaMassAxis); + + if (cfgUseBootStrap) { + fillProfileBoot3D(corrconfigs.at(i), lambdaBoot[bootId][pIndex], cent, fLambdaMassAxis); + } + } // end of lambda condition + + if (configs.GetHeads()[i].starts_with("Ref")) { + int pIndex = findComponent(refV2, Form("h%s", corrconfigs.at(i).Head.c_str())); + fillProfileBoot(corrconfigs.at(i), refV2[pIndex], cent); + + if (cfgUseBootStrap) { + fillProfileBoot(corrconfigs.at(i), refBoot[bootId][pIndex], cent); + } + } // end of ref condition + } // end of loop over correlation configurations + } // end of processReso +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/GenericFramework/Core/BootstrapProfile.h b/PWGCF/GenericFramework/Core/BootstrapProfile.h index a0dfde08509..829c58cc11a 100644 --- a/PWGCF/GenericFramework/Core/BootstrapProfile.h +++ b/PWGCF/GenericFramework/Core/BootstrapProfile.h @@ -9,6 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file BootstrapProfile.h/.cxx +/// \brief Derived class from TProfile that stores extra TProfiles for bootstrap samples +/// \author Emil Gorm Nielsen (ack. V. Vislavicius), NBI, emil.gorm.nielsen@cern.ch + #ifndef PWGCF_GENERICFRAMEWORK_CORE_BOOTSTRAPPROFILE_H_ #define PWGCF_GENERICFRAMEWORK_CORE_BOOTSTRAPPROFILE_H_ 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/FlowContainer.cxx b/PWGCF/GenericFramework/Core/FlowContainer.cxx index 8a906ba2321..d938e0d81b9 100644 --- a/PWGCF/GenericFramework/Core/FlowContainer.cxx +++ b/PWGCF/GenericFramework/Core/FlowContainer.cxx @@ -11,6 +11,9 @@ #include "FlowContainer.h" +#include +#include + ClassImp(FlowContainer); FlowContainer::FlowContainer() : TNamed("", ""), @@ -462,9 +465,11 @@ TH1D* FlowContainer::GetHistCorrXXVsPt(const char* order, double lminmulti, doub TProfile* tpf = GetCorrXXVsPt(order, lminmulti, lmaxmulti); TH1D* rethist = ProfToHist(tpf); TProfile* refflow = GetRefFlowProfile(order, lminmulti, lmaxmulti); - refflow->RebinX(refflow->GetNbinsX()); - rethist->SetBinContent(0, refflow->GetBinContent(1)); - rethist->SetBinError(0, refflow->GetBinError(1)); + if (refflow) { + refflow->RebinX(refflow->GetNbinsX()); + rethist->SetBinContent(0, refflow->GetBinContent(1)); + rethist->SetBinError(0, refflow->GetBinError(1)); + } delete refflow; delete tpf; return rethist; @@ -916,7 +921,12 @@ TProfile* FlowContainer::GetRefFlowProfile(const char* order, double m1, double delete tempprof; } delete rhSubset; - retpf->RebinX(nBins); + if (!retpf) { + LOGF(error, "Reference flow profile is null"); + return nullptr; + } else { + retpf->RebinX(nBins); + } return retpf; }; diff --git a/PWGCF/GenericFramework/Core/FlowContainer.h b/PWGCF/GenericFramework/Core/FlowContainer.h index 40a379e01a8..bb330c049b6 100644 --- a/PWGCF/GenericFramework/Core/FlowContainer.h +++ b/PWGCF/GenericFramework/Core/FlowContainer.h @@ -9,6 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file GFW.h/.cxx +/// \brief Container to store correlations and compute common cumulants +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch + #ifndef PWGCF_GENERICFRAMEWORK_CORE_FLOWCONTAINER_H_ #define PWGCF_GENERICFRAMEWORK_CORE_FLOWCONTAINER_H_ #include diff --git a/PWGCF/GenericFramework/Core/FlowPtContainer.cxx b/PWGCF/GenericFramework/Core/FlowPtContainer.cxx index d7b6b8dd114..ad5f5880d53 100644 --- a/PWGCF/GenericFramework/Core/FlowPtContainer.cxx +++ b/PWGCF/GenericFramework/Core/FlowPtContainer.cxx @@ -9,65 +9,118 @@ // 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), + fSubList(0), + fSubCMList(0), fCumulantList(0), fCentralMomentList(0), mpar(0), fillCounter(0), - fEventWeight(kEventWeight::kUnity), + fEventWeight(EventWeight::UnityWeight), + fUseCentralMoments(true), + fUseGap(false), + sumP(), + insub1(), + insub2(), corrNum(), - corrDen() {} + corrNum1(), + corrNum2(), + corrDen(), + corrDen1(), + corrDen2(), + cmVal(), + cmVal1(), + cmVal2(), + cmDen(), + cmDen1(), + cmDen2(), + arr(), + warr() {} FlowPtContainer::~FlowPtContainer() { delete fCMTermList; delete fCorrList; + delete fCovList; + delete fSubList; + delete fSubCMList; + delete fCumulantList; + delete fCentralMomentList; }; FlowPtContainer::FlowPtContainer(const char* name) : TNamed(name, name), fCMTermList(0), fCorrList(0), fCovList(0), + fSubList(0), + fSubCMList(0), fCumulantList(0), fCentralMomentList(0), mpar(0), fillCounter(0), - fEventWeight(kEventWeight::kUnity), + fEventWeight(EventWeight::UnityWeight), + fUseCentralMoments(true), + fUseGap(false), + sumP(), + insub1(), + insub2(), 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) + corrNum1(), + corrNum2(), + corrDen(), + corrDen1(), + corrDen2(), + cmVal(), + cmVal1(), + cmVal2(), + cmDen(), + cmDen1(), + cmDen2(), + arr(), + warr() {} +FlowPtContainer::FlowPtContainer(const char* name, const char* title) : TNamed(name, title), + fCMTermList(0), + fCorrList(0), + fCovList(0), + fSubList(0), + fSubCMList(0), + fCumulantList(0), + fCentralMomentList(0), + mpar(0), + fillCounter(0), + fEventWeight(EventWeight::UnityWeight), + fUseCentralMoments(true), + fUseGap(false), + sumP(), + insub1(), + insub2(), + corrNum(), + corrNum1(), + corrNum2(), + corrDen(), + corrDen1(), + corrDen2(), + cmVal(), + cmVal1(), + cmVal2(), + cmDen(), + cmDen1(), + cmDen2(), + 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 +128,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 +143,67 @@ 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) { + int obsIndex = 0; + fCovFirstIndex.resize(configs.GetSize(), 0); + for (int i = 0; i < configs.GetSize(); ++i) { + fCovFirstIndex[i] = obsIndex; + 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])); + obsIndex++; + } + } 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])); + obsIndex++; + } + } + } + } 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])); + + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt0", "ChFull22pt3_Mpt0", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt1", "ChFull22pt3_Mpt1", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt2", "ChFull22pt3_Mpt2", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt3", "ChFull22pt3_Mpt3", nMultiBins, &multiBins[0])); + + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt0", "ChFull22pt4_Mpt0", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt1", "ChFull22pt4_Mpt1", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt2", "ChFull22pt4_Mpt2", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt3", "ChFull22pt4_Mpt3", nMultiBins, &multiBins[0])); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt4", "ChFull22pt4_Mpt4", 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 +212,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 * 5 * 5); + warr.resize(3 * 3 * 5 * 5); if (!mpar) mpar = m; if (fCMTermList) @@ -126,17 +229,68 @@ 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) { + int obsIndex = 0; + fCovFirstIndex.resize(configs.GetSize(), 0); + for (int i = 0; i < configs.GetSize(); ++i) { + fCovFirstIndex[i] = obsIndex; + 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)); + obsIndex++; + } + } 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)); + obsIndex++; + } + } + } + } 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)); + + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt0", "ChFull22pt3_Mpt0", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt1", "ChFull22pt3_Mpt1", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt2", "ChFull22pt3_Mpt2", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt3", "ChFull22pt3_Mpt3", nbinsx, xbins)); + + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt0", "ChFull22pt4_Mpt0", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt1", "ChFull22pt4_Mpt1", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt2", "ChFull22pt4_Mpt2", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt3", "ChFull22pt4_Mpt3", nbinsx, xbins)); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt4", "ChFull22pt4_Mpt4", 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 +301,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 * 5 * 5); + warr.resize(3 * 3 * 5 * 5); if (!mpar) mpar = m; if (fCMTermList) @@ -161,17 +317,68 @@ 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) { + int obsIndex = 0; + fCovFirstIndex.resize(configs.GetSize(), 0); + for (int i = 0; i < configs.GetSize(); ++i) { + fCovFirstIndex[i] = obsIndex; + 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)); + obsIndex++; + } + } 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)); + obsIndex++; + } + } + } + } 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)); + + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt0", "ChFull22pt3_Mpt0", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt1", "ChFull22pt3_Mpt1", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt2", "ChFull22pt3_Mpt2", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt3_Mpt3", "ChFull22pt3_Mpt3", nbinsx, xlow, xhigh)); + + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt0", "ChFull22pt4_Mpt0", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt1", "ChFull22pt4_Mpt1", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt2", "ChFull22pt4_Mpt2", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt3", "ChFull22pt4_Mpt3", nbinsx, xlow, xhigh)); + fCovList->Add(new BootstrapProfile("ChFull22pt4_Mpt4", "ChFull22pt4_Mpt4", 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 +389,198 @@ 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::initialiseSubevent(const o2::framework::AxisSpec axis, const int& m, const int& nsub) { - for (auto i = 0; i < sumP.size(); ++i) { - sumP[i] += pow(w, i % (mpar + 1)) * pow(pt, i / (mpar + 1)); + if (!mpar) + mpar = m; + std::vector multiBins = axis.binEdges; + int nMultiBins = axis.nBins.value_or(0); + if (nMultiBins <= 0) + nMultiBins = multiBins.size() - 1; + if (nMultiBins <= 0) { + LOGF(warning, "Multiplicity axis does not exist"); + return; + } + + if (fSubList) + delete fSubList; + fSubList = new TList(); + fSubList->SetOwner(kTRUE); + for (int subEv = 0; subEv < 2; ++subEv) { + for (int m = 0; m < mpar; ++m) { + fSubList->Add(new BootstrapProfile(Form("mpt_sub%i_%ipar", subEv + 1, m + 1), this->GetTitle(), nMultiBins, &multiBins[0])); + } + } + for (int m = 2; m <= mpar; ++m) { + for (int k = 0; k < m - 1; ++k) { + fSubList->Add(new BootstrapProfile(Form("mpt_%isub1_%isub2_%ipar", m - k - 1, k + 1, m), this->GetTitle(), nMultiBins, &multiBins[0])); + } + } + + if (fSubCMList) + delete fSubCMList; + fSubCMList = new TList(); + fSubCMList->SetOwner(kTRUE); + for (int subEv = 0; subEv < 2; ++subEv) { + for (int m = 0; m < 4; ++m) { + for (int i = 0; i <= m; ++i) { + fSubCMList->Add(new BootstrapProfile(Form("cm%i_sub%i_Mpt%i", m + 1, subEv + 1, i), this->GetTitle(), nMultiBins, &multiBins[0])); + } + } + } + for (int m = 2; m <= 4; ++m) { + for (int first = 1; first < m; ++first) { + for (int second = first; second < m; ++second) { + if (first > second) + continue; + int fourth = m - second; + for (int third = 1; third < m; ++third) { + if (third > fourth) + continue; + fSubCMList->Add(new BootstrapProfile(Form("cm%i_%i%isub1_%i%isub2", m, first, second, third, fourth), this->GetTitle(), nMultiBins, &multiBins[0])); + } + } + } + } + + if (nsub) { + for (int i = 0; i < fSubList->GetEntries(); ++i) + dynamic_cast(fSubList->At(i))->InitializeSubsamples(nsub); + for (int i = 0; i < fSubCMList->GetEntries(); ++i) + dynamic_cast(fSubCMList->At(i))->InitializeSubsamples(nsub); + } + LOGF(info, "Container %s initialized Subevents and %i subsamples", this->GetName(), nsub); +} +void FlowPtContainer::initialiseSubevent(int nbinsx, double* xbins, const int& m, const int& nsub) +{ + if (!mpar) + mpar = m; + + if (fSubList) + delete fSubList; + fSubList = new TList(); + fSubList->SetOwner(kTRUE); + for (int subEv = 0; subEv < 2; ++subEv) { + for (int m = 0; m < mpar; ++m) { + fSubList->Add(new BootstrapProfile(Form("mpt_sub%i_%ipar", subEv + 1, m + 1), this->GetTitle(), nbinsx, xbins)); + } + } + for (int m = 2; m <= mpar; ++m) { + for (int k = 0; k < m - 1; ++k) { + fSubList->Add(new BootstrapProfile(Form("mpt_%isub1_%isub2_%ipar", m - k - 1, k + 1, m), this->GetTitle(), nbinsx, xbins)); + } + } + + if (fSubCMList) + delete fSubCMList; + fSubCMList = new TList(); + fSubCMList->SetOwner(kTRUE); + for (int subEv = 0; subEv < 2; ++subEv) { + for (int m = 0; m < 4; ++m) { + for (int i = 0; i <= m; ++i) { + fSubCMList->Add(new BootstrapProfile(Form("cm%i_sub%i_Mpt%i", m + 1, subEv + 1, i), this->GetTitle(), nbinsx, xbins)); + } + } + } + for (int m = 2; m <= 4; ++m) { + for (int first = 1; first < m; ++first) { + for (int second = first; second < m; ++second) { + if (first > second) + continue; + int fourth = m - second; + for (int third = 1; third < m; ++third) { + if (third > fourth) + continue; + fSubCMList->Add(new BootstrapProfile(Form("cm%i_%i%isub1_%i%isub2", m, first, second, third, fourth), this->GetTitle(), nbinsx, xbins)); + } + } + } + } + + if (nsub) { + for (int i = 0; i < fSubList->GetEntries(); ++i) + dynamic_cast(fSubList->At(i))->InitializeSubsamples(nsub); + for (int i = 0; i < fSubCMList->GetEntries(); ++i) + dynamic_cast(fSubCMList->At(i))->InitializeSubsamples(nsub); + } + LOGF(info, "Container %s initialized Subevents and %i subsamples", this->GetName(), nsub); +} +void FlowPtContainer::initialiseSubevent(int nbinsx, double xlow, double xhigh, const int& m, const int& nsub) +{ + if (!mpar) + mpar = m; + if (fSubList) + delete fSubList; + fSubList = new TList(); + fSubList->SetOwner(kTRUE); + for (int subEv = 0; subEv < 2; ++subEv) { + for (int m = 0; m < mpar; ++m) { + fSubList->Add(new BootstrapProfile(Form("mpt_sub%i_%ipar", subEv + 1, m + 1), this->GetTitle(), nbinsx, xlow, xhigh)); + } + } + for (int m = 2; m <= mpar; ++m) { + for (int k = 0; k < m - 1; ++k) { + fSubList->Add(new BootstrapProfile(Form("mpt_%isub1_%isub2_%ipar", m - k - 1, k + 1, m), this->GetTitle(), nbinsx, xlow, xhigh)); + } + } + + if (fSubCMList) + delete fSubCMList; + fSubCMList = new TList(); + fSubCMList->SetOwner(kTRUE); + for (int subEv = 0; subEv < 2; ++subEv) { + for (int m = 0; m < 4; ++m) { + for (int i = 0; i <= m; ++i) { + fSubCMList->Add(new BootstrapProfile(Form("cm%i_sub%i_Mpt%i", m + 1, subEv + 1, i), this->GetTitle(), nbinsx, xlow, xhigh)); + } + } + } + for (int m = 2; m <= 4; ++m) { + for (int first = 1; first < m; ++first) { + for (int second = first; second < m; ++second) { + if (first > second) + continue; + int fourth = m - second; + for (int third = 1; third < m; ++third) { + if (third > fourth) + continue; + fSubCMList->Add(new BootstrapProfile(Form("cm%i_%i%isub1_%i%isub2", m, first, second, third, fourth), this->GetTitle(), nbinsx, xlow, xhigh)); + } + } + } + } + if (nsub) { + for (int i = 0; i < fSubList->GetEntries(); ++i) + dynamic_cast(fSubList->At(i))->InitializeSubsamples(nsub); + for (int i = 0; i < fSubCMList->GetEntries(); ++i) + dynamic_cast(fSubCMList->At(i))->InitializeSubsamples(nsub); + } + LOGF(info, "Container %s initialized Subevents and %i subsamples", this->GetName(), nsub); +} +void FlowPtContainer::fill(const double& w, const double& pt) +{ + 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::fillSub1(const double& w, const double& pt) +{ + for (size_t i = 0; i < insub1.size(); ++i) { + insub1[i] += std::pow(w, i % (mpar + 1)) * std::pow(pt, i / (mpar + 1)); + } + return; +} +void FlowPtContainer::fillSub2(const double& w, const double& pt) +{ + for (size_t i = 0; i < insub2.size(); ++i) { + insub2[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 +594,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 +607,1085 @@ void FlowPtContainer::CalculateCorrelations() } return; } -void FlowPtContainer::FillPtProfiles(const double& centmult, const double& rn) +void FlowPtContainer::calculateSubeventCorrelations() +{ + corrNum1.clear(); + corrNum1.resize(mpar + 1, 0); + corrNum1[0] = 1.0; + corrDen1.clear(); + corrDen1.resize(mpar + 1, 0); + corrDen1[0] = 1.0; + corrNum2.clear(); + corrNum2.resize(mpar + 1, 0); + corrNum2[0] = 1.0; + corrDen2.clear(); + corrDen2.resize(mpar + 1, 0); + corrDen2[0] = 1.0; + + double sumNum1 = 0; + double sumDenum1 = 0; + std::vector valNum1; + std::vector valDenum1; + double sumNum2 = 0; + double sumDenum2 = 0; + std::vector valNum2; + std::vector valDenum2; + + for (int m(1); m <= mpar; ++m) { + for (int k(1); k <= m; ++k) { + // correlations in subevent 1 + valNum1.push_back(SignArray[k - 1] * corrNum1[m - k] * (FactorialArray[m - 1] / FactorialArray[m - k]) * insub1[getVectorIndex(k, k)]); + valDenum1.push_back(SignArray[k - 1] * corrDen1[m - k] * (FactorialArray[m - 1] / FactorialArray[m - k]) * insub1[getVectorIndex(k, 0)]); + // correlations in subevent 2 + valNum2.push_back(SignArray[k - 1] * corrNum2[m - k] * (FactorialArray[m - 1] / FactorialArray[m - k]) * insub2[getVectorIndex(k, k)]); + valDenum2.push_back(SignArray[k - 1] * corrDen2[m - k] * (FactorialArray[m - 1] / FactorialArray[m - k]) * insub2[getVectorIndex(k, 0)]); + } + sumNum1 = orderedAddition(valNum1); + sumDenum1 = orderedAddition(valDenum1); + sumNum2 = orderedAddition(valNum2); + sumDenum2 = orderedAddition(valDenum2); + valNum1.clear(); + valDenum1.clear(); + valNum2.clear(); + valDenum2.clear(); + corrNum1[m] = sumNum1; + corrDen1[m] = sumDenum1; + corrNum2[m] = sumNum2; + corrDen2[m] = sumDenum2; + } + return; +} +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::fillSubeventPtProfiles(const double& centmult, const double& rn) { - if (!mask) + // Fill the correlations within subevents, requires that the CalculateSubeventCorrelations have been called with the correct input vectors right before + for (int m = 1; m <= mpar; ++m) { + if (corrDen1[m] != 0) + dynamic_cast(fSubList->At(m - 1))->FillProfile(centmult, corrNum1[m] / corrDen1[m], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : corrDen1[m], rn); + // subevent 2 profiles offset by mpar positions + if (corrDen2[m] != 0) + dynamic_cast(fSubList->At(mpar + m - 1))->FillProfile(centmult, corrNum2[m] / corrDen2[m], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : corrDen2[m], rn); + } + + // Fill the cross-subevent correlations + for (int m = 2; m <= mpar; ++m) { + for (int k = 0; k < m - 1; ++k) { + if (corrDen1[m - k - 1] != 0 && corrDen2[k + 1] != 0) + dynamic_cast(fSubList->FindObject(Form("mpt_%isub1_%isub2_%ipar", m - k - 1, k + 1, m)))->FillProfile(centmult, corrNum1[m - k - 1] / corrDen1[m - k - 1] * corrNum2[k + 1] / corrDen2[k + 1], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : corrDen1[m - k - 1] * corrDen2[k + 1], rn); + } + } + return; +} +void FlowPtContainer::fillVnPtCorrProfiles(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)))) + 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::fillVnPtCorrProfiles(const int configIndex, const double& centmult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask) +{ + if (!mask) { + return; + } + int startIndex = fCovFirstIndex[configIndex]; + for (auto m(1); m <= mpar; ++m) { + if (!(mask & (1 << (m - 1)))) { + continue; + } + if (corrDen[m] != 0) { + dynamic_cast(fCovList->At(startIndex))->FillProfile(centmult, flowval * corrNum[m] / corrDen[m], (fEventWeight == UnityWeight) ? 1.0 : flowtuples * corrDen[m], rn); + } + ++startIndex; + } + return; +} +void FlowPtContainer::fillVnDeltaPtProfiles(const int configIndex, const double& centmult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask) +{ + if (!mask) { + return; + } + int startIndex = fCovFirstIndex[configIndex]; + 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(startIndex))->FillProfile(centmult, flowval * ((i == m) ? cmVal[0] : cmVal[m * (m - 1) / 2 + i + 1]), (fEventWeight == UnityWeight) ? 1.0 : flowtuples * cmDen[m], rn); + } + ++startIndex; + } + } + 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); + double wABCCCC = getStdABCCCC(warr); + if (wABCCCC != 0.) + dynamic_cast(fCovList->At(14))->FillProfile(centmult, getStdABCCCC(arr) / wABCCCC, (fEventWeight == UnityWeight) ? 1. : wABCCCC, rn); + double wABCCCD = getStdABCCCD(warr); + if (wABCCCD != 0.) + dynamic_cast(fCovList->At(15))->FillProfile(centmult, getStdABCCCD(arr) / wABCCCD, (fEventWeight == UnityWeight) ? 1. : wABCCCD, rn); + double wABCCDD = getStdABCCDD(warr); + if (wABCCDD != 0.) + dynamic_cast(fCovList->At(16))->FillProfile(centmult, getStdABCCDD(arr) / wABCCDD, (fEventWeight == UnityWeight) ? 1. : wABCCDD, rn); + double wABCDDD = getStdABCDDD(warr); + if (wABCDDD != 0.) + dynamic_cast(fCovList->At(17))->FillProfile(centmult, getStdABCDDD(arr) / wABCDDD, (fEventWeight == UnityWeight) ? 1. : wABCDDD, rn); + double wABDDDD = getStdABDDDD(warr); + if (wABDDDD != 0.) + dynamic_cast(fCovList->At(18))->FillProfile(centmult, getStdABDDDD(arr) / wABDDDD, (fEventWeight == UnityWeight) ? 1. : wABDDDD, rn); + double wABCCC = getStdABCCC(warr); + if (wABCCC != 0.) + dynamic_cast(fCovList->At(10))->FillProfile(centmult, getStdABCCC(arr) / wABCCC, (fEventWeight == UnityWeight) ? 1. : wABCCC, rn); + double wABCCD = getStdABCCD(warr); + if (wABCCD != 0.) + dynamic_cast(fCovList->At(11))->FillProfile(centmult, getStdABCCD(arr) / wABCCD, (fEventWeight == UnityWeight) ? 1. : wABCCD, rn); + double wABCDD = getStdABCDD(warr); + if (wABCDD != 0.) + dynamic_cast(fCovList->At(12))->FillProfile(centmult, getStdABCDD(arr) / wABCDD, (fEventWeight == UnityWeight) ? 1. : wABCDD, rn); + double wABDDD = getStdABDDD(warr); + if (wABDDD != 0.) + dynamic_cast(fCovList->At(13))->FillProfile(centmult, getStdABDDD(arr) / wABDDD, (fEventWeight == UnityWeight) ? 1. : wABDDD, rn); + return; +} +void FlowPtContainer::fillCMProfiles(const double& centmult, const double& rn) +{ + if (sumP[getVectorIndex(0, 0)] == 0) + return; + // 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; - 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) + 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(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(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(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[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; + 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)] + 2 * sumP[getVectorIndex(3, 3)] * sumP[getVectorIndex(1, 0)] + 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::fillCMSubeventProfiles(const double& centmult, const double& rn) +{ + // do I need to add an extra return statement here to match fillCMProfiles? + if (mpar < 1) + return; + + int indOffset = 0; + for (int im = 1; im <= mpar; im++) { + indOffset += im; + } + // 0th order correlation + cmDen1.push_back(1.); + cmVal1.push_back(1.); + cmDen2.push_back(1.); + cmVal2.push_back(1.); + + cmDen1.push_back(insub1[getVectorIndex(1, 0)]); + cmDen1.push_back(insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] - insub1[getVectorIndex(2, 0)]); + cmDen1.push_back(insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] - 3 * insub1[getVectorIndex(2, 0)] * insub1[getVectorIndex(1, 0)] + 2 * insub1[getVectorIndex(3, 0)]); + cmDen1.push_back(insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] - 6 * insub1[getVectorIndex(2, 0)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] + 8 * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(3, 0)] + 3 * insub1[getVectorIndex(2, 0)] * insub1[getVectorIndex(2, 0)] - 6 * insub1[getVectorIndex(4, 0)]); + + cmDen2.push_back(insub2[getVectorIndex(1, 0)]); + cmDen2.push_back(insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] - insub2[getVectorIndex(2, 0)]); + cmDen2.push_back(insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] - 3 * insub2[getVectorIndex(2, 0)] * insub2[getVectorIndex(1, 0)] + 2 * insub2[getVectorIndex(3, 0)]); + cmDen2.push_back(insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] - 6 * insub2[getVectorIndex(2, 0)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] + 8 * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(3, 0)] + 3 * insub2[getVectorIndex(2, 0)] * insub2[getVectorIndex(2, 0)] - 6 * insub2[getVectorIndex(4, 0)]); + + if (cmDen1[1] != 0) { + cmVal1.push_back(insub1[getVectorIndex(1, 1)] / cmDen1[1]); + dynamic_cast(fSubCMList->At(0))->FillProfile(centmult, cmVal1[1], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[1], rn); + } + if (cmDen2[1] != 0) { + cmVal2.push_back(insub2[getVectorIndex(1, 1)] / cmDen2[1]); + dynamic_cast(fSubCMList->At(indOffset + 0))->FillProfile(centmult, cmVal2[1], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[1], rn); + } + + if (mpar < 2) + return; + if (insub1[getVectorIndex(2, 0)] != 0 && cmDen1[2] != 0) { + cmVal1.push_back(1 / cmDen1[2] * (insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] - insub1[getVectorIndex(2, 2)])); + dynamic_cast(fSubCMList->At(1))->FillProfile(centmult, cmVal1[2], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[2], rn); + cmVal1.push_back(1 / cmDen1[2] * (insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 1)] - insub1[getVectorIndex(2, 1)])); + dynamic_cast(fSubCMList->At(2))->FillProfile(centmult, cmVal1[3], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[2], rn); + } + if (insub2[getVectorIndex(2, 0)] != 0 && cmDen2[2] != 0) { + cmVal2.push_back(1 / cmDen2[2] * (insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] - insub2[getVectorIndex(2, 2)])); + dynamic_cast(fSubCMList->At(indOffset + 1))->FillProfile(centmult, cmVal2[2], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[2], rn); + cmVal2.push_back(1 / cmDen2[2] * (insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 1)] - insub2[getVectorIndex(2, 1)])); + dynamic_cast(fSubCMList->At(indOffset + 2))->FillProfile(centmult, cmVal2[3], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[2], rn); + } + + if (mpar < 3) 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) + if (insub1[getVectorIndex(3, 0)] != 0 && cmDen1[3] != 0) { + cmVal1.push_back(1 / cmDen1[3] * (insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] - 3 * insub1[getVectorIndex(2, 2)] * insub1[getVectorIndex(1, 1)] + 2 * insub1[getVectorIndex(3, 3)])); + dynamic_cast(fSubCMList->At(3))->FillProfile(centmult, cmVal1[4], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[3], rn); + cmVal1.push_back(1 / cmDen1[3] * (insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 0)] - 2 * insub1[getVectorIndex(2, 1)] * insub1[getVectorIndex(1, 1)] + 2 * insub1[getVectorIndex(3, 2)] - insub1[getVectorIndex(2, 2)] * insub1[getVectorIndex(1, 0)])); + dynamic_cast(fSubCMList->At(4))->FillProfile(centmult, cmVal1[5], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[3], rn); + cmVal1.push_back(1 / cmDen1[3] * (insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] - 2 * insub1[getVectorIndex(2, 1)] * insub1[getVectorIndex(1, 0)] + 2 * insub1[getVectorIndex(3, 1)] - insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(2, 0)])); + dynamic_cast(fSubCMList->At(5))->FillProfile(centmult, cmVal1[6], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[3], rn); + } + if (insub2[getVectorIndex(3, 0)] != 0 && cmDen2[3] != 0) { + cmVal2.push_back(1 / cmDen2[3] * (insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] - 3 * insub2[getVectorIndex(2, 2)] * insub2[getVectorIndex(1, 1)] + 2 * insub2[getVectorIndex(3, 3)])); + dynamic_cast(fSubCMList->At(indOffset + 3))->FillProfile(centmult, cmVal2[4], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[3], rn); + cmVal2.push_back(1 / cmDen2[3] * (insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 0)] - 2 * insub2[getVectorIndex(2, 1)] * insub2[getVectorIndex(1, 1)] + 2 * insub2[getVectorIndex(3, 2)] - insub2[getVectorIndex(2, 2)] * insub2[getVectorIndex(1, 0)])); + dynamic_cast(fSubCMList->At(indOffset + 4))->FillProfile(centmult, cmVal2[5], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[3], rn); + cmVal2.push_back(1 / cmDen2[3] * (insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] - 2 * insub2[getVectorIndex(2, 1)] * insub2[getVectorIndex(1, 0)] + 2 * insub2[getVectorIndex(3, 1)] - insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(2, 0)])); + dynamic_cast(fSubCMList->At(indOffset + 5))->FillProfile(centmult, cmVal2[6], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[3], rn); + } + + if (mpar < 4) 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); + if (insub1[getVectorIndex(4, 0)] != 0 && cmDen1[4] != 0) { + cmVal1.push_back(1 / cmDen1[4] * (insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] - 6 * insub1[getVectorIndex(2, 2)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] + 3 * insub1[getVectorIndex(2, 2)] * insub1[getVectorIndex(2, 2)] + 8 * insub1[getVectorIndex(3, 3)] * insub1[getVectorIndex(1, 1)] - 6 * insub1[getVectorIndex(4, 4)])); + dynamic_cast(fSubCMList->At(6))->FillProfile(centmult, cmVal1[7], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[4], rn); + cmVal1.push_back(1 / cmDen1[4] * (insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 0)] - 3 * insub1[getVectorIndex(2, 2)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 0)] - 3 * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(2, 1)] + 3 * insub1[getVectorIndex(2, 2)] * insub1[getVectorIndex(2, 1)] + 6 * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(3, 2)] - 6 * insub1[getVectorIndex(4, 3)])); + dynamic_cast(fSubCMList->At(7))->FillProfile(centmult, cmVal1[8], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[4], rn); + cmVal1.push_back(1 / cmDen1[4] * (insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] - insub1[getVectorIndex(2, 2)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] - insub1[getVectorIndex(2, 0)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 1)] + insub1[getVectorIndex(2, 0)] * insub1[getVectorIndex(2, 2)] - 4 * insub1[getVectorIndex(2, 1)] * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 0)] + 4 * insub1[getVectorIndex(3, 2)] * insub1[getVectorIndex(1, 0)] + 4 * insub1[getVectorIndex(3, 1)] * insub1[getVectorIndex(1, 1)] + 2 * insub1[getVectorIndex(2, 1)] * insub1[getVectorIndex(2, 1)] - 6 * insub1[getVectorIndex(4, 2)])); + dynamic_cast(fSubCMList->At(8))->FillProfile(centmult, cmVal1[9], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[4], rn); + cmVal1.push_back(1 / cmDen1[4] * (insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] - 3 * insub1[getVectorIndex(2, 1)] * insub1[getVectorIndex(1, 0)] * insub1[getVectorIndex(1, 0)] - 3 * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(2, 0)] * insub1[getVectorIndex(1, 0)] + 3 * insub1[getVectorIndex(2, 1)] * insub1[getVectorIndex(2, 0)] + 2 * insub1[getVectorIndex(1, 1)] * insub1[getVectorIndex(3, 0)] + 6 * insub1[getVectorIndex(3, 1)] * insub1[getVectorIndex(1, 0)] - 6 * insub1[getVectorIndex(4, 1)])); + dynamic_cast(fSubCMList->At(9))->FillProfile(centmult, cmVal1[10], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[4], rn); + } + if (insub2[getVectorIndex(4, 0)] != 0 && cmDen2[4] != 0) { + cmVal2.push_back(1 / cmDen2[4] * (insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] - 6 * insub2[getVectorIndex(2, 2)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] + 3 * insub2[getVectorIndex(2, 2)] * insub2[getVectorIndex(2, 2)] + 8 * insub2[getVectorIndex(3, 3)] * insub2[getVectorIndex(1, 1)] - 6 * insub2[getVectorIndex(4, 4)])); + dynamic_cast(fSubCMList->At(indOffset + 6))->FillProfile(centmult, cmVal2[7], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[4], rn); + cmVal2.push_back(1 / cmDen2[4] * (insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 0)] - 3 * insub2[getVectorIndex(2, 2)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 0)] - 3 * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(2, 1)] + 3 * insub2[getVectorIndex(2, 2)] * insub2[getVectorIndex(2, 1)] + 6 * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(3, 2)] - 6 * insub2[getVectorIndex(4, 3)])); + dynamic_cast(fSubCMList->At(indOffset + 7))->FillProfile(centmult, cmVal2[8], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[4], rn); + cmVal2.push_back(1 / cmDen2[4] * (insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] - insub2[getVectorIndex(2, 2)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] - insub2[getVectorIndex(2, 0)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 1)] + insub2[getVectorIndex(2, 0)] * insub2[getVectorIndex(2, 2)] - 4 * insub2[getVectorIndex(2, 1)] * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 0)] + 4 * insub2[getVectorIndex(3, 2)] * insub2[getVectorIndex(1, 0)] + 4 * insub2[getVectorIndex(3, 1)] * insub2[getVectorIndex(1, 1)] + 2 * insub2[getVectorIndex(2, 1)] * insub2[getVectorIndex(2, 1)] - 6 * insub2[getVectorIndex(4, 2)])); + dynamic_cast(fSubCMList->At(indOffset + 8))->FillProfile(centmult, cmVal2[9], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[4], rn); + cmVal2.push_back(1 / cmDen2[4] * (insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] - 3 * insub2[getVectorIndex(2, 1)] * insub2[getVectorIndex(1, 0)] * insub2[getVectorIndex(1, 0)] - 3 * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(2, 0)] * insub2[getVectorIndex(1, 0)] + 3 * insub2[getVectorIndex(2, 1)] * insub2[getVectorIndex(2, 0)] + 2 * insub2[getVectorIndex(1, 1)] * insub2[getVectorIndex(3, 0)] + 6 * insub2[getVectorIndex(3, 1)] * insub2[getVectorIndex(1, 0)] - 6 * insub2[getVectorIndex(4, 1)])); + dynamic_cast(fSubCMList->At(indOffset + 9))->FillProfile(centmult, cmVal2[10], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen2[4], rn); + } + + // Fill cross terms + for (int m = 2; m <= 4; ++m) { + for (int first = 1; first < m; ++first) { + for (int second = first; second < m; ++second) { + if (first > second) + continue; + int fourth = m - second; + for (int third = 1; third < m; ++third) { + if (third > fourth) + continue; + if (insub1[getVectorIndex(m, 0)] != 0 && insub2[getVectorIndex(m, 0)] != 0 && cmDen1[m] * cmDen2[m] != 0) + dynamic_cast(fSubCMList->FindObject(Form("cm%i_%i%isub1_%i%isub2", m, first, second, third, fourth)))->FillProfile(centmult, cmVal1[second * (second - 1) / 2 + second - first + 1] * cmVal2[fourth * (fourth - 1) / 2 + fourth - third + 1], (fEventWeight == EventWeight::UnityWeight) ? 1.0 : cmDen1[m] * cmDen2[m], rn); + } + } + } + } + return; +} +void FlowPtContainer::fillArray(FillType a, FillType b, double c, double d) +{ + for (int idx = 0; idx < 225; ++idx) { + int i = idx % 3; + int j = ((idx - i) / 3) % 3; + int k = ((idx - j * 3 - i) / 9) % 5; + int l = ((idx - k * 9 - j * 3 - i) / 45) % 5; + 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, 0, 1)]; + 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, 0, 1)]; + std::complex bb = inarr[getVectorIndex(0, 2, 0, 0)]; + 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 abd = inarr[getVectorIndex(1, 1, 0, 1)]; + std::complex bbd = inarr[getVectorIndex(0, 2, 0, 1)]; + std::complex aabb = inarr[getVectorIndex(2, 2, 0, 0)]; + std::complex aabd = inarr[getVectorIndex(2, 1, 0, 1)]; + std::complex abbd = inarr[getVectorIndex(1, 2, 0, 1)]; + std::complex aabbd = inarr[getVectorIndex(2, 2, 0, 1)]; + 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(); +} +template +double FlowPtContainer::getStdABCCCC(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 ccc = inarr[getVectorIndex(0, 0, 3, 0)]; + std::complex abcc = inarr[getVectorIndex(1, 1, 2, 0)]; + std::complex accc = inarr[getVectorIndex(1, 0, 3, 0)]; + std::complex bccc = inarr[getVectorIndex(0, 1, 3, 0)]; + std::complex cccc = inarr[getVectorIndex(0, 0, 4, 0)]; + std::complex abccc = inarr[getVectorIndex(1, 1, 3, 0)]; + std::complex acccc = inarr[getVectorIndex(1, 0, 4, 0)]; + std::complex bcccc = inarr[getVectorIndex(0, 1, 4, 0)]; + std::complex abcccc = inarr[getVectorIndex(1, 1, 4, 0)]; + return (-120. * abcccc + 24. * acccc * b + 24. * accc * bc + 24. * acc * bcc + + 24. * ac * bccc + 24. * a * bcccc + 96. * abccc * c - 24. * accc * b * c - 24. * acc * bc * c - + 24. * ac * bcc * c - 24. * a * bccc * c - 36. * abcc * c * c + 12. * acc * b * c * c + + 12. * ac * bc * c * c + 12. * a * bcc * c * c + 8. * abc * c * c * c - 4. * ac * b * c * c * c - 4. * a * bc * c * c * c - + ab * c * c * c * c + a * b * c * c * c * c + 36. * abcc * cc - 12. * acc * b * cc - 12. * ac * bc * cc - 12. * a * bcc * cc - 24. * abc * c * cc + 12. * ac * b * c * cc + 12. * a * bc * c * cc + 6. * ab * c * c * cc - 6. * a * b * c * c * cc - 3. * ab * cc * cc + 3. * a * b * cc * cc + 16. * abc * ccc - 8. * ac * b * ccc - 8. * a * bc * ccc - 8. * ab * c * ccc + 8. * a * b * c * ccc + 6. * ab * cccc - 6. * a * b * cccc) + .real(); +} +template +double FlowPtContainer::getStdABCCCD(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 cc = inarr[getVectorIndex(0, 0, 2, 0)]; + 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 acc = inarr[getVectorIndex(1, 0, 2, 0)]; + std::complex acd = inarr[getVectorIndex(1, 0, 1, 1)]; + std::complex bcc = inarr[getVectorIndex(0, 1, 2, 0)]; + std::complex bcd = inarr[getVectorIndex(0, 1, 1, 1)]; + std::complex ccc = inarr[getVectorIndex(0, 0, 3, 0)]; + std::complex ccd = inarr[getVectorIndex(0, 0, 2, 1)]; + std::complex abcc = inarr[getVectorIndex(1, 1, 2, 0)]; + std::complex abcd = inarr[getVectorIndex(1, 1, 1, 1)]; + std::complex accc = inarr[getVectorIndex(1, 0, 3, 0)]; + std::complex accd = inarr[getVectorIndex(1, 0, 2, 1)]; + std::complex bccc = inarr[getVectorIndex(0, 1, 3, 0)]; + std::complex bccd = inarr[getVectorIndex(0, 1, 2, 1)]; + std::complex cccd = inarr[getVectorIndex(0, 0, 3, 1)]; + std::complex abccc = inarr[getVectorIndex(1, 1, 3, 0)]; + std::complex abccd = inarr[getVectorIndex(1, 1, 2, 1)]; + std::complex acccd = inarr[getVectorIndex(1, 0, 3, 1)]; + std::complex bcccd = inarr[getVectorIndex(0, 1, 3, 1)]; + std::complex abcccd = inarr[getVectorIndex(1, 1, 3, 1)]; + return (-120. * abcccd + 24. * acccd * b + 18. * accd * bc + 12. * acd * bcc + 6. * ad * bccc + + 24. * a * bcccd + 18. * ac * bccd + 12. * acc * bcd + 6. * accc * bd + 72. * abccd * c - + 18. * accd * b * c - 12. * acd * bc * c - 6. * ad * bcc * c - 18. * a * bccd * c - 12. * ac * bcd * c - + 6. * acc * bd * c - 18. * abcd * c * c + 6. * acd * b * c * c + 3. * ad * bc * c * c + 6. * a * bcd * c * c + + 3. * ac * bd * c * c + 2. * abd * c * c * c - ad * b * c * c * c - a * bd * c * c * c + 18. * abcd * cc - + 6. * acd * b * cc - 3. * ad * bc * cc - 6. * a * bcd * cc - 3. * ac * bd * cc - 6. * abd * c * cc + + 3. * ad * b * c * cc + 3. * a * bd * c * cc + 4. * abd * ccc - 2. * ad * b * ccc - 2. * a * bd * ccc + + 6. * ab * cccd - 6. * a * b * cccd + 12. * abc * ccd - 6. * ac * b * ccd - 6. * a * bc * ccd - + 6. * ab * c * ccd + 6. * a * b * c * ccd + 18. * abcc * cd - 6. * acc * b * cd - 6. * ac * bc * cd - + 6. * a * bcc * cd - 12. * abc * c * cd + 6. * ac * b * c * cd + 6. * a * bc * c * cd + 3. * ab * c * c * cd - + 3. * a * b * c * c * cd - 3. * ab * cc * cd + 3. * a * b * cc * cd + 24. * abccc * d - 6. * accc * b * d - + 6. * acc * bc * d - 6. * ac * bcc * d - 6. * a * bccc * d - 18. * abcc * c * d + 6. * acc * b * c * d + + 6. * ac * bc * c * d + 6. * a * bcc * c * d + 6. * abc * c * c * d - 3. * ac * b * c * c * d - + 3. * a * bc * c * c * d - ab * c * c * c * d + a * b * c * c * c * d - 6. * abc * cc * d + 3. * ac * b * cc * d + + 3. * a * bc * cc * d + 3. * ab * c * cc * d - 3. * a * b * c * cc * d - 2. * ab * ccc * d + 2. * a * b * ccc * d) + .real(); +} +template +double FlowPtContainer::getStdABCCDD(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 cc = inarr[getVectorIndex(0, 0, 2, 0)]; + std::complex cd = inarr[getVectorIndex(0, 0, 1, 1)]; + std::complex dd = inarr[getVectorIndex(0, 0, 0, 2)]; + std::complex abc = inarr[getVectorIndex(1, 1, 1, 0)]; + std::complex abd = inarr[getVectorIndex(1, 1, 0, 1)]; + std::complex acc = inarr[getVectorIndex(1, 0, 2, 0)]; + std::complex acd = inarr[getVectorIndex(1, 0, 1, 1)]; + std::complex add = inarr[getVectorIndex(1, 0, 0, 2)]; + std::complex bcc = inarr[getVectorIndex(0, 1, 2, 0)]; + std::complex bcd = inarr[getVectorIndex(0, 1, 1, 1)]; + std::complex bdd = inarr[getVectorIndex(0, 1, 0, 2)]; + std::complex ccd = inarr[getVectorIndex(0, 0, 2, 1)]; + std::complex cdd = inarr[getVectorIndex(0, 0, 1, 2)]; + std::complex abcc = inarr[getVectorIndex(1, 1, 2, 0)]; + std::complex abcd = inarr[getVectorIndex(1, 1, 1, 1)]; + std::complex abdd = inarr[getVectorIndex(1, 1, 0, 2)]; + std::complex accd = inarr[getVectorIndex(1, 0, 2, 1)]; + std::complex acdd = inarr[getVectorIndex(1, 0, 1, 2)]; + std::complex bccd = inarr[getVectorIndex(0, 1, 2, 1)]; + std::complex bcdd = inarr[getVectorIndex(0, 1, 1, 2)]; + std::complex ccdd = inarr[getVectorIndex(0, 0, 2, 2)]; + std::complex abccd = inarr[getVectorIndex(1, 1, 2, 1)]; + std::complex abcdd = inarr[getVectorIndex(1, 1, 1, 2)]; + std::complex accdd = inarr[getVectorIndex(1, 0, 2, 2)]; + std::complex bccdd = inarr[getVectorIndex(0, 1, 2, 2)]; + std::complex abccdd = inarr[getVectorIndex(1, 1, 2, 2)]; + return (-120. * abccdd + 24. * accdd * b + 12. * acdd * bc + 4. * add * bcc + 12. * ad * bccd + + 24. * a * bccdd + 16. * acd * bcd + 12. * ac * bcdd + 12. * accd * bd + 4. * acc * bdd + + 48. * abcdd * c - 12. * acdd * b * c - 4. * add * bc * c - 8. * ad * bcd * c - 12. * a * bcdd * c - + 8. * acd * bd * c - 4. * ac * bdd * c - 6. * abdd * c * c + 2. * add * b * c * c + 2. * ad * bd * c * c + + 2. * a * bdd * c * c + 6. * abdd * cc - 2. * add * b * cc - 2. * ad * bd * cc - 2. * a * bdd * cc + + 8. * abd * ccd - 4. * ad * b * ccd - 4. * a * bd * ccd + 6. * ab * ccdd - 6. * a * b * ccdd + + 24. * abcd * cd - 8. * acd * b * cd - 4. * ad * bc * cd - 8. * a * bcd * cd - 4. * ac * bd * cd - + 8. * abd * c * cd + 4. * ad * b * c * cd + 4. * a * bd * c * cd - 2. * ab * cd * d + 2. * a * b * cd * d + + 8. * abc * cdd - 4. * ac * b * cdd - 4. * a * bc * cdd - 4. * ab * c * cdd + 4. * a * b * c * cdd + + 48. * abccd * d - 12. * accd * b * d - 8. * acd * bc * d - 4. * ad * bcc * d - 12. * a * bccd * d - + 8. * ac * bcd * d - 4. * acc * bd * d - 24. * abcd * c * d + 8. * acd * b * c * d + 4. * ad * bc * c * d + + 8. * a * bcd * c * d + 4. * ac * bd * c * d + 4. * abd * c * c * d - 2. * ad * b * c * c * d - + 2. * a * bd * c * c * d - 4. * abd * cc * d + 2. * ad * b * cc * d + 2. * a * bd * cc * d - 4. * ab * ccd * d + + 4. * a * b * ccd * d - 8. * abc * cd * d + 4. * ac * b * cd * d + 4. * a * bc * cd * d + 4. * ab * c * cd * d - + 4. * a * b * c * cd * d - 6. * abcc * d * d + 2. * acc * b * d * d + 2. * ac * bc * d * d + + 2. * a * bcc * d * d + 4. * abc * c * d * d - 2. * ac * b * c * d * d - 2. * a * bc * c * d * d - + ab * c * c * d * d + a * b * c * c * d * d + ab * cc * d * d - a * b * cc * d * d + 6. * abcc * dd - + 2. * acc * b * dd - 2. * ac * bc * dd - 2. * a * bcc * dd - 4. * abc * c * dd + 2. * ac * b * c * dd + + 2. * a * bc * c * dd + ab * c * c * dd - a * b * c * c * dd - ab * cc * dd + a * b * cc * dd) + .real(); +} +template +double FlowPtContainer::getStdABCDDD(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 dd = inarr[getVectorIndex(0, 0, 0, 2)]; + 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 add = inarr[getVectorIndex(1, 0, 0, 2)]; + std::complex bcd = inarr[getVectorIndex(0, 1, 1, 1)]; + std::complex bdd = inarr[getVectorIndex(0, 1, 0, 2)]; + std::complex cdd = inarr[getVectorIndex(0, 0, 1, 2)]; + std::complex ddd = inarr[getVectorIndex(0, 0, 0, 3)]; + std::complex abcd = inarr[getVectorIndex(1, 1, 1, 1)]; + std::complex abdd = inarr[getVectorIndex(1, 1, 0, 2)]; + std::complex acdd = inarr[getVectorIndex(1, 0, 1, 2)]; + std::complex addd = inarr[getVectorIndex(1, 0, 0, 3)]; + std::complex bcdd = inarr[getVectorIndex(0, 1, 1, 2)]; + std::complex bddd = inarr[getVectorIndex(0, 1, 0, 3)]; + std::complex cddd = inarr[getVectorIndex(0, 0, 1, 3)]; + std::complex abcdd = inarr[getVectorIndex(1, 1, 1, 2)]; + std::complex abddd = inarr[getVectorIndex(1, 1, 0, 3)]; + std::complex acddd = inarr[getVectorIndex(1, 0, 1, 3)]; + std::complex bcddd = inarr[getVectorIndex(0, 1, 1, 3)]; + std::complex abcddd = inarr[getVectorIndex(1, 1, 1, 3)]; + return (-120. * abcddd + 24. * acddd * b + 6. * addd * bc + 12. * add * bcd + 18. * ad * bcdd + + 24. * a * bcddd + 18. * acdd * bd + 12. * acd * bdd + 6. * ac * bddd + 24. * abddd * c - + 6. * addd * b * c - 6. * add * bd * c - 6. * ad * bdd * c - 6. * a * bddd * c + 18. * abdd * cd - + 6. * add * b * cd - 6. * ad * bd * cd - 6. * a * bdd * cd + 12. * abd * cdd - 6. * ad * b * cdd - + 6. * a * bd * cdd + 6. * ab * cddd - 6. * a * b * cddd + 72. * abcdd * d - 18. * acdd * b * d - + 6. * add * bc * d - 12. * ad * bcd * d - 18. * a * bcdd * d - 12. * acd * bd * d - 6. * ac * bdd * d - + 18. * abdd * c * d + 6. * add * b * c * d + 6. * ad * bd * c * d + 6. * a * bdd * c * d - + 12. * abd * cd * d + 6. * ad * b * cd * d + 6. * a * bd * cd * d - 6. * ab * cdd * d + 6. * a * b * cdd * d - + 18. * abcd * d * d + 6. * acd * b * d * d + 3. * ad * bc * d * d + 6. * a * bcd * d * d + + 3. * ac * bd * d * d + 6. * abd * c * d * d - 3. * ad * b * c * d * d - 3. * a * bd * c * d * d + + 3. * ab * cd * d * d - 3. * a * b * cd * d * d + 2. * abc * d * d * d - ac * b * d * d * d - a * bc * d * d * d - + ab * c * d * d * d + a * b * c * d * d * d + 18. * abcd * dd - 6. * acd * b * dd - 3. * ad * bc * dd - + 6. * a * bcd * dd - 3. * ac * bd * dd - 6. * abd * c * dd + 3. * ad * b * c * dd + 3. * a * bd * c * dd - + 3. * ab * cd * dd + 3. * a * b * cd * dd - 6. * abc * d * dd + 3. * ac * b * d * dd + 3. * a * bc * d * dd + + 3. * ab * c * d * dd - 3. * a * b * c * d * dd + 4. * abc * ddd - 2. * ac * b * ddd - 2. * a * bc * ddd - + 2. * ab * c * ddd + 2. * a * b * c * ddd) + .real(); +} +template +double FlowPtContainer::getStdABDDDD(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 ddd = inarr[getVectorIndex(0, 0, 0, 3)]; + std::complex abdd = inarr[getVectorIndex(1, 1, 0, 2)]; + std::complex addd = inarr[getVectorIndex(1, 0, 0, 3)]; + std::complex bddd = inarr[getVectorIndex(0, 1, 0, 3)]; + std::complex dddd = inarr[getVectorIndex(0, 0, 0, 4)]; + std::complex abddd = inarr[getVectorIndex(1, 1, 0, 3)]; + std::complex adddd = inarr[getVectorIndex(1, 0, 0, 4)]; + std::complex bdddd = inarr[getVectorIndex(0, 1, 0, 4)]; + std::complex abdddd = inarr[getVectorIndex(1, 1, 0, 4)]; + return (-120. * abdddd + 24. * adddd * b + 24. * addd * bd + 24. * add * bdd + 24. * ad * bddd + + 24. * a * bdddd + 96. * abddd * d - 24. * addd * b * d - 24. * add * bd * d - 24. * ad * bdd * d - + 24. * a * bddd * d - 36. * abdd * d * d + 12. * add * b * d * d + 12. * ad * bd * d * d + + 12. * a * bdd * d * d + 8. * abd * d * d * d - 4. * ad * b * d * d * d - 4. * a * bd * d * d * d - ab * d * d * d * d + + a * b * d * d * d * d + 36. * abdd * dd - 12. * add * b * dd - 12. * ad * bd * dd - 12. * a * bdd * dd - + 24. * abd * d * dd + 12. * ad * b * d * dd + 12. * a * bd * d * dd + 6. * ab * d * d * dd - + 6. * a * b * d * d * dd - 3. * ab * dd * d + 3. * a * b * dd * d + 16. * abd * ddd - 8. * ad * b * ddd - + 8. * a * bd * ddd - 8. * ab * d * ddd + 8. * a * b * d * ddd + 6. * ab * dddd - 6. * a * b * dddd) + .real(); +} +template +double FlowPtContainer::getStdABCCC(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 ccc = inarr[getVectorIndex(0, 0, 3, 0)]; + std::complex abcc = inarr[getVectorIndex(1, 1, 2, 0)]; + std::complex accc = inarr[getVectorIndex(1, 0, 3, 0)]; + std::complex bccc = inarr[getVectorIndex(0, 1, 3, 0)]; + std::complex abccc = inarr[getVectorIndex(1, 1, 3, 0)]; + return (24. * abccc - 6. * accc * b - 6. * acc * bc - 6. * ac * bcc - 6. * a * bccc - 18. * abcc * c + + 6. * acc * b * c + 6. * ac * bc * c + 6. * a * bcc * c + 6. * abc * c * c - 3. * ac * b * c * c - + 3. * a * bc * c * c - ab * c * c * c + a * b * c * c * c - 6. * abc * cc + 3. * ac * b * cc + 3. * a * bc * cc + + 3. * ab * c * cc - 3. * a * b * c * cc - 2. * ab * ccc + 2. * a * b * ccc) + .real(); +} +template +double FlowPtContainer::getStdABCCD(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 cc = inarr[getVectorIndex(0, 0, 2, 0)]; + 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 acc = inarr[getVectorIndex(1, 0, 2, 0)]; + std::complex bcc = inarr[getVectorIndex(0, 1, 2, 0)]; + std::complex ccd = inarr[getVectorIndex(0, 0, 2, 1)]; + std::complex acd = inarr[getVectorIndex(1, 0, 1, 1)]; + std::complex bcd = inarr[getVectorIndex(0, 1, 1, 1)]; + std::complex abcc = inarr[getVectorIndex(1, 1, 2, 0)]; + std::complex abcd = inarr[getVectorIndex(1, 1, 1, 1)]; + std::complex accd = inarr[getVectorIndex(1, 0, 2, 1)]; + std::complex bccd = inarr[getVectorIndex(0, 1, 2, 1)]; + std::complex abccd = inarr[getVectorIndex(1, 1, 2, 1)]; + return (24. * abccd - 6. * accd * b - 4. * acd * bc - 2. * ad * bcc - 6. * a * bccd - 4. * ac * bcd - + 2. * acc * bd - 12. * abcd * c + 4. * acd * b * c + 2. * ad * bc * c + 4. * a * bcd * c + + 2. * ac * bd * c + 2. * abd * c * c - ad * b * c * c - a * bd * c * c - 2. * abd * cc + ad * b * cc + + a * bd * cc - 2. * ab * ccd + 2. * a * b * ccd - 4. * abc * cd + 2. * ac * b * cd + 2. * a * bc * cd + + 2. * ab * c * cd - 2. * a * b * c * cd - 6. * abcc * d + 2. * acc * b * d + 2. * ac * bc * d + + 2. * a * bcc * d + 4. * abc * c * d - 2. * ac * b * c * d - 2. * a * bc * c * d - ab * c * c * d + + a * b * c * c * d + ab * cc * d - a * b * cc * d) + .real(); +} +template +double FlowPtContainer::getStdABCDD(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 dd = inarr[getVectorIndex(0, 0, 0, 2)]; + std::complex abc = inarr[getVectorIndex(1, 1, 1, 0)]; + 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 cdd = inarr[getVectorIndex(0, 0, 1, 2)]; + std::complex acd = inarr[getVectorIndex(1, 0, 1, 1)]; + std::complex bcd = inarr[getVectorIndex(0, 1, 1, 1)]; + std::complex abdd = inarr[getVectorIndex(1, 1, 0, 2)]; + std::complex abcd = inarr[getVectorIndex(1, 1, 1, 1)]; + std::complex acdd = inarr[getVectorIndex(1, 0, 1, 2)]; + std::complex bcdd = inarr[getVectorIndex(0, 1, 1, 2)]; + std::complex abcdd = inarr[getVectorIndex(1, 1, 1, 2)]; + return (24. * abcdd - 6. * acdd * b - 2. * add * bc - 4. * ad * bcd - 6. * a * bcdd - 4. * acd * bd - + 2. * ac * bdd - 6. * abdd * c + 2. * add * b * c + 2. * ad * bd * c + 2. * a * bdd * c - 4. * abd * cd + + 2. * ad * b * cd + 2. * a * bd * cd - 2. * ab * cdd + 2. * a * b * cdd - 12. * abcd * d + + 4. * acd * b * d + 2. * ad * bc * d + 4. * a * bcd * d + 2. * ac * bd * d + 4. * abd * c * d - + 2. * ad * b * c * d - 2. * a * bd * c * d + 2. * ab * cd * d - 2. * a * b * cd * d + 2. * abc * d * d - + ac * b * d * d - a * bc * d * d - ab * c * d * d + a * b * c * d * d - 2. * abc * dd + ac * b * dd + + a * bc * dd + ab * c * dd - a * b * c * dd) + .real(); +} +template +double FlowPtContainer::getStdABDDD(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 ddd = inarr[getVectorIndex(0, 0, 0, 3)]; + std::complex abdd = inarr[getVectorIndex(1, 1, 0, 2)]; + std::complex addd = inarr[getVectorIndex(1, 0, 0, 3)]; + std::complex bddd = inarr[getVectorIndex(0, 1, 0, 3)]; + std::complex abddd = inarr[getVectorIndex(1, 1, 0, 3)]; + return (24. * abddd - 6. * addd * b - 6. * add * bd - 6. * ad * bdd - 6. * a * bddd - 18. * abdd * d + + 6. * add * b * d + 6. * ad * bd * d + 6. * a * bdd * d + 6. * abd * d * d - 3. * ad * b * d * d - + 3. * a * bd * d * d - ab * d * d * d + a * b * d * d * d - 6. * abd * dd + 3. * ad * b * dd + 3. * a * bd * dd + + 3. * ab * d * dd - 3. * a * b * d * dd - 2. * ab * ddd + 2. * a * b * ddd) + .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); } + if (fSubList) { + for (int i = 0; i < fSubList->GetEntries(); i++) + dynamic_cast(fSubList->At(i))->RebinMulti(nbins); + } + if (fSubCMList) { + for (int i = 0; i < fSubCMList->GetEntries(); i++) + dynamic_cast(fSubCMList->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); } + if (fSubList) { + for (int i = 0; i < fSubList->GetEntries(); i++) + dynamic_cast(fSubList->At(i))->RebinMulti(nbins, binedges); + } + if (fSubCMList) { + for (int i = 0; i < fSubCMList->GetEntries(); i++) + dynamic_cast(fSubCMList->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 +1699,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 +1720,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 +1737,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 +1769,72 @@ 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* tSub = lPTC->fSubList; + TList* tSubCM = lPTC->fSubCMList; + 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, tCM); + } + if (tSub) { + if (!fSubList) + fSubList = dynamic_cast(tSub->Clone()); + else + mergeBSLists(fSubList, tSub); + } + if (tSubCM) { + if (!fSubCMList) + fSubCMList = dynamic_cast(tSubCM->Clone()); else - MergeBSLists(fCentralMomentList, t_CM); + mergeBSLists(fSubCMList, tSubCM); } } 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 +1843,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..86bd676d7d8 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,190 @@ 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); + // initial pt-pt correlations with two subevents + void initialiseSubevent(const o2::framework::AxisSpec axis, const int& m, const int& nsub = 10); + void initialiseSubevent(int nbinsx, double* xbins, const int& m, const int& nsub = 10); + void initialiseSubevent(int nbinsx, double xlow, double xhigh, const int& m, const int& nsub = 10); + void fill(const double& w, const double& pt); + void fillSub1(const double& w, const double& pt); + void fillSub2(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 * 5; } // index for 4d array for std vnpt correlation - size 3x3x3x3 + void calculateCorrelations(); + void calculateSubeventCorrelations(); + void calculateCMTerms(); + void fillPtProfiles(const double& lMult, const double& rn); + void fillSubeventPtProfiles(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 fillVnPtCorrProfiles(const int configIndex, const double& lMult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask); + void fillVnDeltaPtProfiles(const int configIndex, 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 fillVnPtProfiles(const int configIndex, const double& centmult, const double& flowval, const double& flowtuples, const double& rn, uint8_t mask) + { + if (fUseCentralMoments) + fillVnDeltaPtProfiles(configIndex, centmult, flowval, flowtuples, rn, mask); + else + fillVnPtCorrProfiles(configIndex, centmult, flowval, flowtuples, rn, mask); + } + void skipVnPtProfiles(uint8_t mask) + { + for (auto m(1); m <= mpar; ++m) { + if (!(mask & (1 << (m - 1)))) { + continue; + } + if (fUseCentralMoments) { + for (auto i = 0; i <= m; ++i) { + ++fillCounter; + } + } else { + ++fillCounter; + } + } + return; + } + 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); + void fillCMSubeventProfiles(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)); + insub1.clear(); + insub1.resize((mpar + 1) * (mpar + 1)); + insub2.clear(); + insub2.resize((mpar + 1) * (mpar + 1)); + cmVal.clear(); + cmVal1.clear(); + cmVal2.clear(); + cmDen.clear(); + cmDen1.clear(); + cmDen2.clear(); fillCounter = 0; + arr.clear(); + arr.resize(3 * 3 * 5 * 5, {0.0, 0.0}); + warr.clear(); + warr.resize(3 * 3 * 5 * 5, 0.0); }; - private: TList* fCMTermList; TList* fCorrList; TList* fCovList; + TList* fSubList; + TList* fSubCMList; TList* fCumulantList; TList* fCentralMomentList; + int mpar; - int fillCounter; - unsigned int fEventWeight; - void MergeBSLists(TList* source, TList* target); + 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 insub1; //! + std::vector insub2; //! + std::vector corrNum; //! + std::vector corrNum1; //! + std::vector corrNum2; //! + std::vector corrDen; //! + std::vector corrDen1; //! + std::vector corrDen2; //! + std::vector cmVal; //! + std::vector cmVal1; //! + std::vector cmVal2; //! + std::vector cmDen; //! + std::vector cmDen1; //! + std::vector cmDen2; //! + std::vector> arr; //! + std::vector warr; //! + std::vector fCovFirstIndex; //! + 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); + template + double getStdABCCCC(T& inarr); + template + double getStdABCCCD(T& inarr); + template + double getStdABCCDD(T& inarr); + template + double getStdABCDDD(T& inarr); + template + double getStdABDDDD(T& inarr); + template + double getStdABCCC(T& inarr); + template + double getStdABCCD(T& inarr); + template + double getStdABCDD(T& inarr); + template + double getStdABDDD(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/GFW.cxx b/PWGCF/GenericFramework/Core/GFW.cxx index 1541aaf8993..350fe752156 100644 --- a/PWGCF/GenericFramework/Core/GFW.cxx +++ b/PWGCF/GenericFramework/Core/GFW.cxx @@ -9,16 +9,13 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/* -Author: Vytautas Vislavicius -Extention of Generic Flow (https://arxiv.org/abs/1312.3572 by A. Bilandzic et al.) -Class steers the initialization and calculation of n-particle correlations. Uses recursive function, all terms are calculated only once. -Latest version includes the calculation of any number of gaps and any combination of harmonics (including eg symmetric cumulants, etc.) -If used, modified, or distributed, please aknowledge the author of this code. -*/ - #include "GFW.h" +#include +#include +#include +#include + using std::complex; using std::pair; using std::string; diff --git a/PWGCF/GenericFramework/Core/GFW.h b/PWGCF/GenericFramework/Core/GFW.h index 629731bea85..8ec2b78d095 100644 --- a/PWGCF/GenericFramework/Core/GFW.h +++ b/PWGCF/GenericFramework/Core/GFW.h @@ -9,23 +9,22 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/* -Author: Vytautas Vislavicius -Extention of Generic Flow (https://arxiv.org/abs/1312.3572 by A. Bilandzic et al.) -Class steers the initialization and calculation of n-particle correlations. Uses recursive function, all terms are calculated only once. -Latest version includes the calculation of any number of gaps and any combination of harmonics (including eg symmetric cumulants, etc.) -If used, modified, or distributed, please aknowledge the author of this code. -*/ +/// \file GFW.h/.cxx +/// \brief Class steers the initialization and calculation of n-particle correlations. Uses recursive function, all terms are calculated only once. +/// \author Emil Gorm Nielsen (ack. V. Vislavicius), NBI, emil.gorm.nielsen@cern.ch + #ifndef PWGCF_GENERICFRAMEWORK_CORE_GFW_H_ #define PWGCF_GENERICFRAMEWORK_CORE_GFW_H_ #include "GFWCumulant.h" #include "GFWPowerArray.h" -#include -#include -#include + #include #include +#include +#include +#include +#include class GFW { 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/GFWCumulant.cxx b/PWGCF/GenericFramework/Core/GFWCumulant.cxx index a82e3bcd08b..f27da24bd27 100644 --- a/PWGCF/GenericFramework/Core/GFWCumulant.cxx +++ b/PWGCF/GenericFramework/Core/GFWCumulant.cxx @@ -9,16 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/* -Author: Vytautas Vislavicius -Extention of Generic Flow (https://arxiv.org/abs/1312.3572 by A. Bilandzic et al.) -A part of -A container to store Q vectors for one subevent with an extra layer to recursively calculate particle correlations. -If used, modified, or distributed, please aknowledge the author of this code. -*/ - #include "GFWCumulant.h" +#include + using std::complex; using std::vector; diff --git a/PWGCF/GenericFramework/Core/GFWCumulant.h b/PWGCF/GenericFramework/Core/GFWCumulant.h index f8cf6624542..2567a2e9c4a 100644 --- a/PWGCF/GenericFramework/Core/GFWCumulant.h +++ b/PWGCF/GenericFramework/Core/GFWCumulant.h @@ -9,13 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/* -Author: Vytautas Vislavicius -Extention of Generic Flow (https://arxiv.org/abs/1312.3572 by A. Bilandzic et al.) -A part of -A container to store Q vectors for one subevent with an extra layer to recursively calculate particle correlations. -If used, modified, or distributed, please aknowledge the author of this code. -*/ +/// \file GFWCumulant.h/.cxx +/// \brief A container to store Q vectors for one subevent with an extra layer to recursively calculate particle correlations. +/// \author Emil Gorm Nielsen (ack. V. Vislavicius), NBI, emil.gorm.nielsen@cern.ch + #ifndef PWGCF_GENERICFRAMEWORK_CORE_GFWCUMULANT_H_ #define PWGCF_GENERICFRAMEWORK_CORE_GFWCUMULANT_H_ 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/GFWPowerArray.h b/PWGCF/GenericFramework/Core/GFWPowerArray.h index 82314374e00..ba38f2fcc54 100644 --- a/PWGCF/GenericFramework/Core/GFWPowerArray.h +++ b/PWGCF/GenericFramework/Core/GFWPowerArray.h @@ -9,6 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file GFWPowerArray.h/.cxx +/// \brief Class to compute necessary powers of Q-vectors based on input correlations +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch + #ifndef PWGCF_GENERICFRAMEWORK_CORE_GFWPOWERARRAY_H_ #define PWGCF_GENERICFRAMEWORK_CORE_GFWPOWERARRAY_H_ 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/Core/ProfileSubset.h b/PWGCF/GenericFramework/Core/ProfileSubset.h index 3d749e06b0e..fc920b898c4 100644 --- a/PWGCF/GenericFramework/Core/ProfileSubset.h +++ b/PWGCF/GenericFramework/Core/ProfileSubset.h @@ -9,9 +9,13 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file ProfileSubset.h/.cxx +/// \brief // Helper class to select a subrange of a TProfile +/// \author Emil Gorm Nielsen (ack. V. Vislavicius), NBI, emil.gorm.nielsen@cern.ch + #ifndef PWGCF_GENERICFRAMEWORK_CORE_PROFILESUBSET_H_ #define PWGCF_GENERICFRAMEWORK_CORE_PROFILESUBSET_H_ -// Helper function to select a subrange of a TProfile + #include "TProfile.h" #include "TProfile2D.h" #include "TError.h" diff --git a/PWGCF/GenericFramework/Tasks/CMakeLists.txt b/PWGCF/GenericFramework/Tasks/CMakeLists.txt index ee71394c4cb..338f173aa73 100644 --- a/PWGCF/GenericFramework/Tasks/CMakeLists.txt +++ b/PWGCF/GenericFramework/Tasks/CMakeLists.txt @@ -13,3 +13,8 @@ o2physics_add_dpl_workflow(flow-generic-framework SOURCES flowGenericFramework.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(flow-gfw-light-ions + SOURCES flowGfwLightIons.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx index d18d08309bf..f0242a8a1b6 100644 --- a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx @@ -9,50 +9,57 @@ // 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" +/// \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 "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 "GFW.h" #include "GFWConfig.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" #include "GFWWeights.h" +#include "GFWWeightsList.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#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; -using namespace o2::analysis; #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; -namespace o2::analysis::genericframework +namespace o2::analysis::gfw { -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 +69,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 = o2::constants::math::TwoPI; int nchbins = 300; float nchlow = 0; float nchup = 3000; @@ -70,31 +77,57 @@ std::vector centbinning(90); int nBootstrap = 10; GFWRegions regions; GFWCorrConfigs configs; -} // namespace o2::analysis::genericframework - -using namespace o2::analysis::genericframework; +std::vector multGlobalCorrCutPars; +std::vector multPVCorrCutPars; +} // namespace o2::analysis::gfw -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(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") 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)"); + O2_DEFINE_CONFIGURABLE(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); 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(cfgNTPCCls, float, 70, "Cut on number of TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgNTPCXrows, float, 70, "Cut on number of TPC crossed rows"); + O2_DEFINE_CONFIGURABLE(cfgMinNITSCls, float, 5, "Cut on minimum number of ITS clusters found"); + O2_DEFINE_CONFIGURABLE(cfgChi2PrITSCls, float, 36, "Cut on chi^2 per ITS clusters found"); + O2_DEFINE_CONFIGURABLE(cfgChi2PrTPCCls, float, 2.5, "Cut on chi^2 per 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(cfgEtaPtPt, float, 0.4, "eta cut for pt-pt correlations"); O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10, "vertex cut (cm)"); + O2_DEFINE_CONFIGURABLE(cfgOccupancySelection, int, 2000, "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"); + O2_DEFINE_CONFIGURABLE(cfgUseDensityDependentCorrection, bool, false, "Use density dependent efficiency correction based on Run 2 measurements"); + 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"}; + Configurable> cfgMultGlobalCutPars{"cfgMultGlobalCutPars", std::vector{2272.16, -76.6932, 1.01204, -0.00631545, 1.59868e-05, 136.336, -4.97006, 0.121199, -0.0015921, 7.66197e-06}, "Global multiplicity cut parameter values"}; + Configurable> cfgMultPVCutPars{"cfgMultPVCutPars", std::vector{3074.43, -106.192, 1.46176, -0.00968364, 2.61923e-05, 182.128, -7.43492, 0.193901, -0.00256715, 1.22594e-05}, "PV multiplicity cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultCorrHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCorrLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); - 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 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, 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}}, "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"}; Configurable cfgCorrConfig{"cfgCorrConfig", {{"refP {2} refN {-2}", "refP {3} refN {-3}", "refP {4} refN {-4}", "refFull {2 -2}", "refFull {2 2 -2 -2}"}, {"ChGap22", "ChGap32", "ChGap42", "ChFull22", "ChFull24"}, {0, 0, 0, 0, 0}, {15, 1, 1, 0, 0}}, "Configurations for each correlation to calculate"}; @@ -105,22 +138,71 @@ 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"}; - // define global variables + // QA outputs + std::map>> th1sList; + std::map>> th3sList; + enum OutputTH1Names { + hPhi = 0, + hEta, + hVtxZ, + hMult, + hCent, + hEventSel, + kCount_TH1Names + }; + // NUA outputs + enum OutputTH3Names { + hNUAref = 0, + hNUAch, + hNUApi, + hNUAka, + hNUApr, + kCount_TH3Names + }; + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + kCentNTPV + }; + + // Define global variables + // Generic Framework GFW* fGFW = new GFW(); std::vector corrconfigs; + TRandom3* fRndm = new TRandom3(0); TAxis* fPtAxis; + int lastRun = -1; + std::vector runNumbers; + + // Density dependent eff correction + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + struct DensityCorr { + double psi2Est; + double psi3Est; + double psi4Est; + double v2; + double v3; + double v4; + int density; + DensityCorr() : psi2Est(0.), psi3Est(0.), psi4Est(0.), v2(0.), v3(0.), v4(0.), density(0) {} + }; // Event selection cuts - Alex TF1* fPhiCutLow = nullptr; @@ -134,51 +216,75 @@ struct GenericFramework { void init(InitContext const&) { LOGF(info, "flowGenericFramework::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(); + o2::analysis::gfw::regions.SetNames(cfgRegions->GetNames()); + o2::analysis::gfw::regions.SetEtaMin(cfgRegions->GetEtaMin()); + o2::analysis::gfw::regions.SetEtaMax(cfgRegions->GetEtaMax()); + o2::analysis::gfw::regions.SetpTDifs(cfgRegions->GetpTDifs()); + o2::analysis::gfw::regions.SetBitmasks(cfgRegions->GetBitmasks()); + o2::analysis::gfw::configs.SetCorrs(cfgCorrConfig->GetCorrs()); + o2::analysis::gfw::configs.SetHeads(cfgCorrConfig->GetHeads()); + o2::analysis::gfw::configs.SetpTDifs(cfgCorrConfig->GetpTDifs()); + o2::analysis::gfw::configs.SetpTCorrMasks(cfgCorrConfig->GetpTCorrMasks()); + o2::analysis::gfw::regions.Print(); + o2::analysis::gfw::configs.Print(); + o2::analysis::gfw::ptbinning = cfgGFWBinning->GetPtBinning(); + o2::analysis::gfw::ptpoilow = cfgGFWBinning->GetPtPOImin(); + o2::analysis::gfw::ptpoiup = cfgGFWBinning->GetPtPOImax(); + o2::analysis::gfw::ptreflow = cfgGFWBinning->GetPtRefMin(); + o2::analysis::gfw::ptrefup = cfgGFWBinning->GetPtRefMax(); + o2::analysis::gfw::ptlow = cfgPtmin; + o2::analysis::gfw::ptup = cfgPtmax; + o2::analysis::gfw::etabins = cfgGFWBinning->GetEtaBins(); + o2::analysis::gfw::vtxZbins = cfgGFWBinning->GetVtxZbins(); + o2::analysis::gfw::phibins = cfgGFWBinning->GetPhiBins(); + o2::analysis::gfw::philow = 0.0f; + o2::analysis::gfw::phiup = o2::constants::math::TwoPI; + o2::analysis::gfw::nchbins = cfgGFWBinning->GetNchBins(); + o2::analysis::gfw::nchlow = cfgGFWBinning->GetNchMin(); + o2::analysis::gfw::nchup = cfgGFWBinning->GetNchMax(); + o2::analysis::gfw::centbinning = cfgGFWBinning->GetCentBinning(); cfgGFWBinning->Print(); + o2::analysis::gfw::multGlobalCorrCutPars = cfgMultGlobalCutPars; + o2::analysis::gfw::multPVCorrCutPars = cfgMultPVCutPars; - 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 (%)"}; + AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; + AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgEta, cfgEta, "#eta"}; + AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; + AxisSpec ptAxis = {o2::analysis::gfw::ptbinning, "#it{p}_{T} GeV/#it{c}"}; + std::string sCentralityEstimator; + switch (cfgCentEstimator) { + case kCentFT0C: + sCentralityEstimator = "FT0C"; + break; + case kCentFT0CVariant1: + sCentralityEstimator = "FT0C variant 1"; + break; + case kCentFT0M: + sCentralityEstimator = "FT0M"; + break; + case kCentFV0A: + sCentralityEstimator = "FV0A"; + break; + case kCentNTPV: + sCentralityEstimator = "NTPV"; + break; + default: + sCentralityEstimator = "FT0C"; + } + sCentralityEstimator += " centrality (%)"; + AxisSpec centAxis = {o2::analysis::gfw::centbinning, sCentralityEstimator.c_str()}; std::vector nchbinning; - int nchskip = (nchup - nchlow) / nchbins; - for (int i = 0; i <= nchbins; ++i) { - nchbinning.push_back(nchskip * i + nchlow + 0.5); + int nchskip = (o2::analysis::gfw::nchup - o2::analysis::gfw::nchlow) / o2::analysis::gfw::nchbins; + for (int i = 0; i <= o2::analysis::gfw::nchbins; ++i) { + nchbinning.push_back(nchskip * i + o2::analysis::gfw::nchlow + 0.5); } AxisSpec nchAxis = {nchbinning, "N_{ch}"}; + AxisSpec bAxis = {200, 0, 20, "#it{b}"}; 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 multAxis = (doprocessOnTheFly && !cfgUseNch) ? bAxis : (cfgUseNch) ? nchAxis + : centAxis; AxisSpec dcaZAXis = {200, -2, 2, "DCA_{z} (cm)"}; AxisSpec dcaXYAXis = {200, -1, 1, "DCA_{xy} (cm)"}; ccdb->setURL("http://alice-ccdb.cern.ch"); @@ -188,92 +294,131 @@ struct GenericFramework { 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]); + int ptbins = o2::analysis::gfw::ptbinning.size() - 1; + fPtAxis = new TAxis(ptbins, &o2::analysis::gfw::ptbinning[0]); - if (cfgFillWeights) { - fWeights->SetPtBins(ptbins, &ptbinning[0]); - fWeights->Init(true, false); + if (doprocessMCGen || doprocessOnTheFly) { + 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 (doprocessOnTheFly) + registry.add("MCGen/impactParameter", "", {HistType::kTH2D, {{bAxis, nchAxis}}}); } + if (doprocessMCReco || doprocessData || doprocessRun2) { + 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.add("trackQA/before/chi2prTPCcls", "#chi^{2}/cluster for the TPC track segment", {HistType::kTH1D, {{100, 0., 5.}}}); + registry.add("trackQA/before/chi2prITScls", "#chi^{2}/cluster for the ITS track", {HistType::kTH1D, {{100, 0., 50.}}}); + registry.add("trackQA/before/nTPCClusters", "Number of found TPC clusters", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("trackQA/before/nITSClusters", "Number of found ITS clusters", {HistType::kTH1D, {{100, 0, 20}}}); + registry.add("trackQA/before/nTPCCrossedRows", "Number of crossed TPC Rows", {HistType::kTH1D, {{100, 40, 180}}}); + + registry.addClone("trackQA/before/", "trackQA/after/"); + registry.add("trackQA/after/pt_ref", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptreflow, o2::analysis::gfw::ptrefup}}}); + registry.add("trackQA/after/pt_poi", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoiup}}}); - if (doprocessMCGen) { - registry.add("pt_gen", "", {HistType::kTH1D, {ptAxis}}); - registry.add("phi_eta_vtxZ_gen", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("eventQA/before/centrality", "", {HistType::kTH1D, {centAxis}}); + registry.add("eventQA/before/multiplicity", "", {HistType::kTH1D, {nchAxis}}); + 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 (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}}); - } - - if (regions.GetSize() < 0) + + if (o2::analysis::gfw::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 < o2::analysis::gfw::regions.GetSize(); ++i) { + fGFW->AddRegion(o2::analysis::gfw::regions.GetNames()[i], o2::analysis::gfw::regions.GetEtaMin()[i], o2::analysis::gfw::regions.GetEtaMax()[i], (o2::analysis::gfw::regions.GetpTDifs()[i]) ? ptbins + 1 : 1, o2::analysis::gfw::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])); + for (auto i = 0; i < o2::analysis::gfw::configs.GetSize(); ++i) { + corrconfigs.push_back(fGFW->GetCorrelatorConfig(o2::analysis::gfw::configs.GetCorrs()[i], o2::analysis::gfw::configs.GetHeads()[i], o2::analysis::gfw::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); + 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); + if (doprocessMCGen || doprocessOnTheFly) { + 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, o2::analysis::gfw::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); - 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); - } - - 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); + fMultPVCutLow = new TF1("fMultPVCutLow", cfgMultCorrLowCutFunction->c_str(), 0, 100); + fMultPVCutLow->SetParameters(&(o2::analysis::gfw::multPVCorrCutPars[0])); + fMultPVCutHigh = new TF1("fMultPVCutHigh", cfgMultCorrHighCutFunction->c_str(), 0, 100); + fMultPVCutHigh->SetParameters(&(o2::analysis::gfw::multPVCorrCutPars[0])); + fMultCutLow = new TF1("fMultCutLow", cfgMultCorrLowCutFunction->c_str(), 0, 100); + fMultCutLow->SetParameters(&(o2::analysis::gfw::multGlobalCorrCutPars[0])); + fMultCutHigh = new TF1("fMultCutHigh", cfgMultCorrHighCutFunction->c_str(), 0, 100); + fMultCutHigh->SetParameters(&(o2::analysis::gfw::multGlobalCorrCutPars[0])); + } + if (cfgUseDensityDependentCorrection) { + 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); } } - 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,56 +450,149 @@ 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 + const int nspecies = 3; + for (int i = 0; i < nspecies; ++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()); - if (zRes > 0.25 && collision.numContrib() < 20) + float zRes = std::sqrt(collision.covZZ()); + float minZRes = 0.25; + int minNContrib = 20; + if (zRes > minZRes && collision.numContrib() < minNContrib) vtxz = -999; } // auto multV0A = collision.multFV0A(); @@ -362,264 +600,569 @@ struct GenericFramework { // auto multT0C = collision.multFT0C(); auto multNTracksPV = collision.multNTracksPV(); - 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)) + if (vtxz > o2::analysis::gfw::vtxZup || vtxz < o2::analysis::gfw::vtxZlow) 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; } template - bool trackSelected(TTrack track, const int& field) + bool trackSelected(TTrack track) { - 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 (cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > cfgDCAxyNSigma / 7. * (0.0105f + 0.0035f / track.pt()))) + return false; + return ((track.tpcNClsCrossedRows() >= cfgNTPCXrows) && (track.tpcNClsFound() >= cfgNTPCCls) && (track.itsNCls() >= cfgMinNITSCls)); } - - enum datatype { + enum DataType { kReco, kGen }; - template - void FillOutputContainers(const float& centmult, const double& rndm) + template + void fillWeights(const TTrack track, const double vtxz, const int& pid_index, const int& run) { - fFCpt->CalculateCorrelations(); - fFCpt->FillPtProfiles(centmult, rndm); - fFCpt->FillCMProfiles(centmult, rndm); + if (cfgUsePID) { + double ptpidmins[] = {o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoilow, 0.3, 0.5}; // min pt for ch, pi, ka, pr + double ptpidmaxs[] = {o2::analysis::gfw::ptpoiup, o2::analysis::gfw::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 = (o2::analysis::gfw::ptreflow < track.pt()) && (track.pt() < o2::analysis::gfw::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; + } + + void createRunByRunHistograms(const int& run) + { + AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; + AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgEta, cfgEta, "#eta"}; + AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; + AxisSpec nchAxis = {o2::analysis::gfw::nchbins, o2::analysis::gfw::nchlow, o2::analysis::gfw::nchup, "N_{ch}"}; + AxisSpec centAxis = {o2::analysis::gfw::centbinning, "Centrality (%)"}; + 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, {nchAxis}}); + histos[hCent] = registry.add(Form("%d/cent", run), "", {HistType::kTH1D, {centAxis}}); + 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) + { + 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, o2::analysis::gfw::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()) + if (dt != kGen && (centrality < o2::analysis::gfw::centbinning.front() || centrality > o2::analysis::gfw::centbinning.back())) return; + if (dt != kGen) { + 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(); + + // be cautious, this only works for Pb-Pb + // esimate the Event plane and vn for this event + DensityCorr densitycorrections; + if (cfgUseDensityDependentCorrection) { + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + double v2 = 0, v3 = 0, v4 = 0; + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (const auto& track : tracks) { + bool withinPtRef = (o2::analysis::gfw::ptreflow < track.pt()) && (track.pt() < o2::analysis::gfw::ptrefup); // 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(centrality); + v3 = funcV3->Eval(centrality); + v4 = funcV4->Eval(centrality); + densitycorrections.psi2Est = psi2Est; + densitycorrections.psi3Est = psi3Est; + densitycorrections.psi4Est = psi4Est; + densitycorrections.v2 = v2; + densitycorrections.v3 = v3; + densitycorrections.v4 = v4; + densitycorrections.density = tracks.size(); + } + + for (const auto& track : tracks) { + processTrack(track, vtxz, run, densitycorrections); } - 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, DensityCorr densitycorrections) { - 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() < o2::analysis::gfw::etalow || mcParticle.eta() > o2::analysis::gfw::etaup || mcParticle.pt() < o2::analysis::gfw::ptlow || mcParticle.pt() > o2::analysis::gfw::ptup) return; - if (cfgFillWeights) - fWeights->Fill(mcParticle.phi(), mcParticle.eta(), vtxz, mcParticle.pt(), centrality, 0); - - if (!setCurrentParticleWeights(weff, wacc, mcParticle.phi(), mcParticle.eta(), mcParticle.pt(), vtxz)) + if (!trackSelected(track)) return; - registry.fill(HIST("phi_eta_vtxZ_corrected"), mcParticle.phi(), mcParticle.eta(), vtxz, wacc); - if (cfgFillQA) - FillTrackQA(track, vtxz); + 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; + } - 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) - return; + if (cfgFillWeights) { + fillWeights(mcParticle, vtxz, 0, run); + } else { + fillPtSums(track, vtxz); + fillGFW(mcParticle, vtxz, pidIndex, densitycorrections); + } - 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(track, 1., 1.); - } else { - if (track.tpcNClsFound() < cfgNcls) + } else if constexpr (framework::has_type_v) { + if (!track.isPhysicalPrimary()) return; + if (cfgFillQA) + fillTrackQA(track, vtxz); - if (cfgUseAdditionalTrackCut && !trackSelected(track, field)) + if (track.eta() < o2::analysis::gfw::etalow || track.eta() > o2::analysis::gfw::etaup || track.pt() < o2::analysis::gfw::ptlow || track.pt() > o2::analysis::gfw::ptup) return; - if (cfgFillWeights) - fWeights->Fill(track.phi(), track.eta(), vtxz, track.pt(), centrality, 0); + 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 (!setCurrentParticleWeights(weff, wacc, track.phi(), track.eta(), track.pt(), vtxz)) - return; + fillPtSums(track, vtxz); + fillGFW(track, vtxz, pidIndex, densitycorrections); - registry.fill(HIST("phi_eta_vtxZ_corrected"), track.phi(), track.eta(), vtxz, wacc); if (cfgFillQA) - FillTrackQA(track, vtxz); + fillTrackQA(track, vtxz); + } else { + if (cfgFillQA) + fillTrackQA(track, vtxz); + + if (!trackSelected(track)) + return; + + 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, densitycorrections); + } + 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, DensityCorr densitycorrections) { - 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[] = {o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoilow, 0.3, 0.5}; + double ptmaxs[] = {o2::analysis::gfw::ptpoiup, o2::analysis::gfw::ptpoiup, 6.0, 6.0}; + bool withinPtRef = (track.pt() > o2::analysis::gfw::ptreflow && track.pt() < o2::analysis::gfw::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() > o2::analysis::gfw::ptreflow && track.pt() < o2::analysis::gfw::ptrefup); + bool withinPtPOI = (track.pt() > o2::analysis::gfw::ptpoilow && track.pt() < o2::analysis::gfw::ptpoiup); + if (!withinPtPOI && !withinPtRef) + return; + double weff = (dt == kGen) ? 1. : getEfficiency(track); + if (weff < 0) + return; + if (cfgUseDensityDependentCorrection && withinPtRef && dt != kGen) { + double fphi = densitycorrections.v2 * std::cos(2 * (track.phi() - densitycorrections.psi2Est)) + densitycorrections.v3 * std::cos(3 * (track.phi() - densitycorrections.psi3Est)) + densitycorrections.v4 * std::cos(4 * (track.phi() - densitycorrections.psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(track.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + float wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * densitycorrections.density); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + } + } + } + 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()); + + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("chi2prTPCcls"), track.tpcChi2NCl()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("chi2prITScls"), track.itsChi2NCl()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nTPCClusters"), track.tpcNClsFound()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nITSClusters"), track.itsNCls()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nTPCCrossedRows"), track.tpcNClsCrossedRows()); + + 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>; + o2::framework::expressions::Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; + o2::framework::expressions::Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::itsChi2NCl < cfgChi2PrITSCls) && (aod::track::tpcChi2NCl < cfgChi2PrTPCCls) && nabs(aod::track::dcaZ) < cfgDCAz; - void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, myTracks const& tracks) + using GFWTracks = soa::Filtered>; + + 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; - const auto centrality = collision.centFT0C(); - auto bc = collision.bc_as(); - if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), centrality)) + registry.fill(HIST("eventQA/eventSel"), 1.5); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(1.5); + if (cfgDoOccupancySel) { + 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); + float centrality; + switch (cfgCentEstimator) { + case kCentFT0C: + centrality = collision.centFT0C(); + break; + case kCentFT0CVariant1: + centrality = collision.centFT0CVariant1(); + break; + case kCentFT0M: + centrality = collision.centFT0M(); + break; + case kCentFV0A: + centrality = collision.centFV0A(); + break; + case kCentNTPV: + centrality = collision.centNTPV(); + break; + default: + centrality = collision.centFT0C(); + } + if (cfgFillQA) + fillEventQA(collision, tracks); + registry.fill(HIST("eventQA/before/centrality"), centrality); + registry.fill(HIST("eventQA/before/multiplicity"), tracks.size()); + 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); + registry.fill(HIST("eventQA/after/centrality"), centrality); + registry.fill(HIST("eventQA/after/multiplicity"), tracks.size()); + 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&) + 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; + o2::framework::expressions::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) { + for (const auto& collision : collisions) { centrality = collision.centFT0C(); } - processCollision(mcCollision, particles, centrality, -999); + int run = 0; + processCollision(mcCollision, particles, centrality, run); } - 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 processOnTheFly(soa::Filtered::iterator const& mcCollision, aod::McParticles const& mcParticles) { + int run = 0; + registry.fill(HIST("MCGen/impactParameter"), mcCollision.impactParameter(), mcParticles.size()); + processCollision(mcCollision, mcParticles, mcCollision.impactParameter(), run); + } + PROCESS_SWITCH(FlowGenericFramework, processOnTheFly, "Process analysis for MC on-the-fly generated events", false); + + 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/GenericFramework/Tasks/flowGfwLightIons.cxx b/PWGCF/GenericFramework/Tasks/flowGfwLightIons.cxx new file mode 100644 index 00000000000..4c8ffcfaa55 --- /dev/null +++ b/PWGCF/GenericFramework/Tasks/flowGfwLightIons.cxx @@ -0,0 +1,1336 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file flowGfwLightIons.cxx +/// \brief Dedicated GFW task to analyse angular correlations in light-ion collision systems +/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch + +#include "FlowContainer.h" +#include "FlowPtContainer.h" +#include "GFW.h" +#include "GFWConfig.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.h" +#include "GFWWeightsList.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 "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +namespace o2::analysis::gfw +{ +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 = 40; +float vtxZlow = -10.0, vtxZup = 10.0; +int phibins = 72; +float philow = 0.0; +float phiup = o2::constants::math::TwoPI; +int nchbins = 300; +float nchlow = 0; +float nchup = 3000; +std::vector centbinning(90); +int nBootstrap = 10; +GFWRegions regions; +GFWCorrConfigs configs; +std::vector multGlobalCorrCutPars; +std::vector multPVCorrCutPars; +std::vector multGlobalPVCorrCutPars; +std::vector multGlobalV0ACutPars; +std::vector multGlobalT0ACutPars; +std::vector firstRunsOfFill; +} // namespace o2::analysis::gfw + +struct FlowGfwLightIons { + + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgMpar, int, 4, "Highest order of pt-pt correlations") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") + 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(cfgFillFlowRunByRun, bool, false, "Fill flow profile run-by-run (only for v22)") + O2_DEFINE_CONFIGURABLE(cfgTimeDependent, bool, false, "Fill output as function of time (for contamination studies)") + O2_DEFINE_CONFIGURABLE(cfgFirstRunsOfFill, std::vector, {}, "First runs of a fill for time dependent analysis") + 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(cfgUseCentralMoments, bool, true, "Use central moments 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(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); + O2_DEFINE_CONFIGURABLE(cfgDCAxy, std::string, "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"); + O2_DEFINE_CONFIGURABLE(cfgDCAz, float, 2, "Cut on DCA in the longitudinal direction (cm)"); + O2_DEFINE_CONFIGURABLE(cfgNTPCCls, float, 50, "Cut on number of TPC clusters found"); + O2_DEFINE_CONFIGURABLE(cfgNTPCXrows, float, 70, "Cut on number of TPC crossed rows"); + O2_DEFINE_CONFIGURABLE(cfgMinNITSCls, float, 5, "Cut on minimum number of ITS clusters found"); + O2_DEFINE_CONFIGURABLE(cfgChi2PrITSCls, float, 36, "Cut on chi^2 per ITS clusters found"); + O2_DEFINE_CONFIGURABLE(cfgChi2PrTPCCls, float, 2.5, "Cut on chi^2 per 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(cfgEtaPtPt, float, 0.4, "eta cut for pt-pt correlations used in subevent vn-pt"); + O2_DEFINE_CONFIGURABLE(cfgEtaPtPtGap, float, 0.4, "eta gap for subevent pt-pt correlations"); + O2_DEFINE_CONFIGURABLE(cfgEtaPtPtFull, float, 0.8, "eta cut for pure pt-pt correlations"); + O2_DEFINE_CONFIGURABLE(cfgVtxZ, float, 10, "vertex cut (cm)"); + O2_DEFINE_CONFIGURABLE(cfgOccupancySelection, int, 2000, "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(cfgFixedMultMin, int, 1, "Minimum for fixed nch range"); + O2_DEFINE_CONFIGURABLE(cfgFixedMultMax, int, 3000, "Maximum for fixed nch range"); + O2_DEFINE_CONFIGURABLE(cfgUseMultiplicityFlowWeights, bool, true, "Enable or disable the use of multiplicity-based event weighting"); + O2_DEFINE_CONFIGURABLE(cfgConsistentEventFlag, int, 0, "Flag to select consistent events - 0: off, 1: v2{2} gap calculable, 2: v2{4} full calculable, 4: v2{4} gap calculable, 8: v2{4} 3sub calculable"); + O2_DEFINE_CONFIGURABLE(cfgUseDensityDependentCorrection, bool, false, "Use density dependent efficiency correction based on Run 2 measurements"); + 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"}; + struct : ConfigurableGroup { + Configurable> cfgMultGlobalCutPars{"cfgMultGlobalCutPars", std::vector{2272.16, -76.6932, 1.01204, -0.00631545, 1.59868e-05, 136.336, -4.97006, 0.121199, -0.0015921, 7.66197e-06}, "Global vs FT0C multiplicity cut parameter values"}; + Configurable> cfgMultPVCutPars{"cfgMultPVCutPars", std::vector{3074.43, -106.192, 1.46176, -0.00968364, 2.61923e-05, 182.128, -7.43492, 0.193901, -0.00256715, 1.22594e-05}, "PV vs FT0C multiplicity cut parameter values"}; + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", std::vector{-0.223013, 0.715849, 0.664242, 0.0829653, -0.000503733, 1.21185e-06}, "Global vs PV multiplicity cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultCorrHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCorrLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCorrCutFunction, std::string, "[0] + [1]*x + 3*([2] + [3]*x + [4]*x*x + [5]*x*x*x)", "Functional for global vs pv multiplicity correlation cut"); + } cfgMultCorrCuts; + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgMultGlobalASideCorrCutFunction, std::string, "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x + [10]*([5]+[6]*x+[7]*x*x+[8]*x*x*x+[9]*x*x*x*x)", "Functional for global vs V0A multiplicity low correlation cut"); + Configurable> cfgMultGlobalV0ACutPars{"cfgMultGlobalV0ACutPars", std::vector{567.785, 172.715, 0.77888, -0.00693466, 1.40564e-05, 679.853, 66.8068, -0.444332, 0.00115002, -4.92064e-07}, "Global vs FV0A multiplicity cut parameter values"}; + Configurable> cfgMultGlobalT0ACutPars{"cfgMultGlobalT0ACutPars", std::vector{241.618, 61.8402, 0.348049, -0.00306078, 6.20357e-06, 315.235, 29.1491, -0.188639, 0.00044528, -9.08912e-08}, "Global vs FT0A multiplicity cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgGlobalV0ALowSigma, float, -3, "Number of sigma deviations below expected value in global vs V0A correlation"); + O2_DEFINE_CONFIGURABLE(cfgGlobalV0AHighSigma, float, 4, "Number of sigma deviations above expected value in global vs V0A correlation"); + O2_DEFINE_CONFIGURABLE(cfgGlobalT0ALowSigma, float, -3., "Number of sigma deviations below expected value in global vs T0A correlation"); + O2_DEFINE_CONFIGURABLE(cfgGlobalT0AHighSigma, float, 4, "Number of sigma deviations above expected value in global vs T0A correlation"); + } cfgGlobalAsideCorrCuts; + + 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, 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}}, "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"}; + + Configurable cfgCorrConfig{"cfgCorrConfig", {{"refP {2} refN {-2}", "refP {3} refN {-3}", "refP {4} refN {-4}", "refFull {2 -2}", "refFull {2 2 -2 -2}"}, {"ChGap22", "ChGap32", "ChGap42", "ChFull22", "ChFull24"}, {0, 0, 0, 0, 0}, {15, 1, 1, 0, 0}}, "Configurations for each correlation to calculate"}; + + // Connect to ccdb + Service ccdb; + + struct Config { + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance; + bool correctionsLoaded = false; + } cfg; + + // Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + OutputObj fFCpt{FlowPtContainer("FlowPtContainer")}; + OutputObj fFCptFull{FlowPtContainer("FlowPtContainerFull")}; + OutputObj fFCgen{FlowContainer("FlowContainer_gen")}; + OutputObj fFCptgen{FlowPtContainer("FlowPtContainer_gen")}; + OutputObj fFCptgenFull{FlowPtContainer("FlowPtContainer_gen")}; + HistogramRegistry registry{"registry"}; + + // QA outputs + std::map>> th1sList; + std::map>> tpfsList; + std::map>> th3sList; + enum OutputTH1Names { + hPhi = 0, + hEta, + hVtxZ, + hMult, + hCent, + hEventSel, + kCount_TH1Names + }; + enum OutputTProfileNames { + pfCorr22 = 0, + kCount_TProfileNames + }; + // NUA outputs + enum OutputTH3Names { + hNUAref = 0, + kCount_TH3Names + }; + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + kCentNTPV, + kCentNGlobal, + kCentMFT + }; + std::map centNamesMap = {{kCentFT0C, "FT0C"}, {kCentFT0CVariant1, "FT0C variant1"}, {kCentFT0M, "FT0M"}, {kCentFV0A, "FV0A"}, {kCentNTPV, "NTPV"}, {kCentNGlobal, "NGlobal"}, {kCentMFT, "MFT"}}; + + enum EventSelFlags { + kFilteredEvent = 1, + kSel8, + kOccupancy, + kTVXTRD, + kNoSamebunchPU, + kZVtxFT0PV, + kNoCollTRStd, + kVtxITSTPC, + kGoodITSLayers, + kMultCuts, + kTrackCent + }; + + // Define global variables + // Generic Framework + GFW* fGFW = new GFW(); + std::vector corrconfigs; + + TRandom3* fRndm = new TRandom3(0); + TAxis* fSecondAxis; + int lastRun = -1; + std::vector::iterator firstRunOfCurrentFill; + std::vector runNumbers; + + // Density dependent eff correction + std::vector funcEff; + TH1D* hFindPtBin; + TF1* funcV2; + TF1* funcV3; + TF1* funcV4; + struct DensityCorr { + double psi2Est; + double psi3Est; + double psi4Est; + double v2; + double v3; + double v4; + int density; + DensityCorr() : psi2Est(0.), psi3Est(0.), psi4Est(0.), v2(0.), v3(0.), v4(0.), density(0) {} + }; + + // region indices for consistency flag + int posRegionIndex = -1; + int negRegionIndex = -1; + int fullRegionIndex = -1; + int midRegionIndex = -1; + + // Event selection cuts - Alex + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + TF1* fMultCutLow = nullptr; + TF1* fMultCutHigh = nullptr; + TF1* fMultPVGlobalCutHigh = nullptr; + TF1* fMultGlobalV0ACutLow = nullptr; + TF1* fMultGlobalV0ACutHigh = nullptr; + TF1* fMultGlobalT0ACutLow = nullptr; + TF1* fMultGlobalT0ACutHigh = nullptr; + + TF1* fPtDepDCAxy = nullptr; + + o2::framework::expressions::Filter collisionFilter = nabs(aod::collision::posZ) < cfgVtxZ; + o2::framework::expressions::Filter trackFilter = nabs(aod::track::eta) < cfgEta && aod::track::pt > cfgPtmin&& aod::track::pt < cfgPtmax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && (aod::track::itsChi2NCl < cfgChi2PrITSCls) && (aod::track::tpcChi2NCl < cfgChi2PrTPCCls) && nabs(aod::track::dcaZ) < cfgDCAz; + + Preslice perCollision = aod::track::collisionId; + o2::framework::expressions::Filter mcCollFilter = nabs(aod::mccollision::posZ) < cfgVtxZ; + o2::framework::expressions::Filter mcParticlesFilter = (aod::mcparticle::eta > o2::analysis::gfw::etalow && aod::mcparticle::eta < o2::analysis::gfw::etaup && aod::mcparticle::pt > o2::analysis::gfw::ptlow && aod::mcparticle::pt < o2::analysis::gfw::ptup); + + using GFWTracks = soa::Filtered>; + + void init(InitContext const&) + { + LOGF(info, "flowGfwLightIons::init()"); + o2::analysis::gfw::regions.SetNames(cfgRegions->GetNames()); + o2::analysis::gfw::regions.SetEtaMin(cfgRegions->GetEtaMin()); + o2::analysis::gfw::regions.SetEtaMax(cfgRegions->GetEtaMax()); + o2::analysis::gfw::regions.SetpTDifs(cfgRegions->GetpTDifs()); + o2::analysis::gfw::regions.SetBitmasks(cfgRegions->GetBitmasks()); + o2::analysis::gfw::configs.SetCorrs(cfgCorrConfig->GetCorrs()); + o2::analysis::gfw::configs.SetHeads(cfgCorrConfig->GetHeads()); + o2::analysis::gfw::configs.SetpTDifs(cfgCorrConfig->GetpTDifs()); + o2::analysis::gfw::configs.SetpTCorrMasks(cfgCorrConfig->GetpTCorrMasks()); + o2::analysis::gfw::regions.Print(); + o2::analysis::gfw::configs.Print(); + o2::analysis::gfw::ptbinning = cfgGFWBinning->GetPtBinning(); + o2::analysis::gfw::ptpoilow = cfgGFWBinning->GetPtPOImin(); + o2::analysis::gfw::ptpoiup = cfgGFWBinning->GetPtPOImax(); + o2::analysis::gfw::ptreflow = cfgGFWBinning->GetPtRefMin(); + o2::analysis::gfw::ptrefup = cfgGFWBinning->GetPtRefMax(); + o2::analysis::gfw::ptlow = cfgPtmin; + o2::analysis::gfw::ptup = cfgPtmax; + o2::analysis::gfw::etabins = cfgGFWBinning->GetEtaBins(); + o2::analysis::gfw::vtxZbins = cfgGFWBinning->GetVtxZbins(); + o2::analysis::gfw::phibins = cfgGFWBinning->GetPhiBins(); + o2::analysis::gfw::philow = 0.0f; + o2::analysis::gfw::phiup = o2::constants::math::TwoPI; + o2::analysis::gfw::nchbins = cfgGFWBinning->GetNchBins(); + o2::analysis::gfw::nchlow = cfgGFWBinning->GetNchMin(); + o2::analysis::gfw::nchup = cfgGFWBinning->GetNchMax(); + o2::analysis::gfw::centbinning = cfgGFWBinning->GetCentBinning(); + cfgGFWBinning->Print(); + o2::analysis::gfw::multGlobalCorrCutPars = cfgMultCorrCuts.cfgMultGlobalCutPars; + o2::analysis::gfw::multPVCorrCutPars = cfgMultCorrCuts.cfgMultPVCutPars; + o2::analysis::gfw::multGlobalPVCorrCutPars = cfgMultCorrCuts.cfgMultGlobalPVCutPars; + o2::analysis::gfw::multGlobalV0ACutPars = cfgGlobalAsideCorrCuts.cfgMultGlobalV0ACutPars; + o2::analysis::gfw::multGlobalT0ACutPars = cfgGlobalAsideCorrCuts.cfgMultGlobalT0ACutPars; + o2::analysis::gfw::firstRunsOfFill = cfgFirstRunsOfFill; + if (cfgTimeDependent && !std::is_sorted(o2::analysis::gfw::firstRunsOfFill.begin(), o2::analysis::gfw::firstRunsOfFill.end())) { + std::sort(o2::analysis::gfw::firstRunsOfFill.begin(), o2::analysis::gfw::firstRunsOfFill.end()); + } + firstRunOfCurrentFill = o2::analysis::gfw::firstRunsOfFill.begin(); + + AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; + AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgEta, cfgEta, "#eta"}; + AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; + AxisSpec ptAxis = {o2::analysis::gfw::ptbinning, "#it{p}_{T} GeV/#it{c}"}; + std::string sCentralityEstimator = centNamesMap[cfgCentEstimator] + " centrality (%)"; + AxisSpec centAxis = {o2::analysis::gfw::centbinning, sCentralityEstimator.c_str()}; + std::vector nchbinning; + int nchskip = (o2::analysis::gfw::nchup - o2::analysis::gfw::nchlow) / o2::analysis::gfw::nchbins; + for (int i = 0; i <= o2::analysis::gfw::nchbins; ++i) { + nchbinning.push_back(nchskip * i + o2::analysis::gfw::nchlow + 0.5); + } + AxisSpec nchAxis = {nchbinning, "N_{ch}"}; + std::vector bbinning(201); + std::generate(bbinning.begin(), bbinning.end(), [n = -0.1, step = 0.1]() mutable { + n += step; + return n; + }); + AxisSpec bAxis = {bbinning, "#it{b}"}; + AxisSpec t0cAxis = {1000, 0, 10000, "N_{ch} (T0C)"}; + AxisSpec t0aAxis = {300, 0, 30000, "N_{ch} (T0A)"}; + AxisSpec v0aAxis = {800, 0, 80000, "N_{ch} (V0A)"}; + AxisSpec multpvAxis = {600, 0, 600, "N_{ch} (PV)"}; + AxisSpec dcaZAXis = {200, -2, 2, "DCA_{z} (cm)"}; + AxisSpec dcaXYAXis = {200, -0.5, 0.5, "DCA_{xy} (cm)"}; + std::vector timebinning(289); + std::generate(timebinning.begin(), timebinning.end(), [n = -24 / 288., step = 24 / 288.]() mutable { + n += step; + return n; + }); + AxisSpec timeAxis = {timebinning, "time (hrs)"}; + + AxisSpec multAxis = (cfgTimeDependent) ? timeAxis : (doprocessOnTheFly && !cfgUseNch) ? bAxis + : (cfgUseNch) ? nchAxis + : centAxis; + 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 = o2::analysis::gfw::ptbinning.size() - 1; + fSecondAxis = (cfgTimeDependent) ? new TAxis(timeAxis.binEdges.size() - 1, &(timeAxis.binEdges[0])) : new TAxis(ptbins, &o2::analysis::gfw::ptbinning[0]); + + if (doprocessMCGen || doprocessOnTheFly) { + registry.add("MCGen/trackQA/nch_pt", "#it{p}_{T} vs multiplicity; N_{ch}; #it{p}_{T}", {HistType::kTH2D, {nchAxis, ptAxis}}); + registry.add("MCGen/trackQA/phi_eta_vtxZ", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + registry.add("MCGen/trackQA/pt_ref", "Reference #it{p}_{T}; #it{p}_{T}; Counts", {HistType::kTH1D, {{100, o2::analysis::gfw::ptreflow, o2::analysis::gfw::ptrefup}}}); + registry.add("MCGen/trackQA/pt_poi", "POI #it{p}_{T}; #it{p}_{T}; Counts", {HistType::kTH1D, {{100, o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoiup}}}); + if (doprocessOnTheFly) + registry.add("MCGen/impactParameter", "", {HistType::kTH2D, {{bAxis, nchAxis}}}); + + registry.add("MCGen/eventQA/multiplicity", "", {HistType::kTH1D, {nchAxis}}); + if (doprocessMCGen) + registry.add("MCGen/eventQA/centrality", "", {HistType::kTH1D, {centAxis}}); + } + if (doprocessMCReco || doprocessData) { + 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.add("trackQA/before/nch_pt", "#it{p}_{T} vs multiplicity; N_{ch}; #it{p}_{T}", {HistType::kTH2D, {nchAxis, ptAxis}}); + registry.add("trackQA/before/chi2prTPCcls", "#chi^{2}/cluster for the TPC track segment; #chi^{2}/TPC cluster", {HistType::kTH1D, {{100, 0., 5.}}}); + registry.add("trackQA/before/chi2prITScls", "#chi^{2}/cluster for the ITS track; #chi^{2}/ITS cluster", {HistType::kTH1D, {{100, 0., 50.}}}); + registry.add("trackQA/before/nTPCClusters", "Number of found TPC clusters; TPC N_{cls}; Counts", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("trackQA/before/nITSClusters", "Number of found ITS clusters; ITS N_{cls}; Counts", {HistType::kTH1D, {{100, 0, 20}}}); + registry.add("trackQA/before/nTPCCrossedRows", "Number of crossed TPC Rows; TPC X-rows; Counts", {HistType::kTH1D, {{100, 40, 180}}}); + + registry.addClone("trackQA/before/", "trackQA/after/"); + registry.add("trackQA/after/pt_ref", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptreflow, o2::analysis::gfw::ptrefup}}}); + registry.add("trackQA/after/pt_poi", "", {HistType::kTH1D, {{100, o2::analysis::gfw::ptpoilow, o2::analysis::gfw::ptpoiup}}}); + + registry.add("eventQA/before/multiplicity", "", {HistType::kTH1D, {nchAxis}}); + if (cfgTimeDependent) { + registry.add("eventQA/before/multiplicity_time", "Multiplicity vs time; time (hrs); N_{ch}", {HistType::kTH2D, {timeAxis, nchAxis}}); + registry.add("eventQA/before/multT0C_time", "T0C Multiplicity vs time; time (hrs); N_{ch} (T0C)", {HistType::kTH2D, {timeAxis, t0cAxis}}); + registry.add("eventQA/before/multT0A_time", "T0A Multiplicity vs time; time (hrs); N_{ch} (T0A)", {HistType::kTH2D, {timeAxis, t0aAxis}}); + registry.add("eventQA/before/multV0A_time", "V0A Multiplicity vs time; time (hrs); N_{ch} (V0A)", {HistType::kTH2D, {timeAxis, v0aAxis}}); + registry.add("eventQA/before/multPV_time", "PV Multiplicity vs time; time (hrs); N_{ch} (PV)", {HistType::kTH2D, {timeAxis, 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, {v0aAxis, nchAxis}}); + registry.add("eventQA/before/multV0A_multT0A", "", {HistType::kTH2D, {t0aAxis, v0aAxis}}); + + if (doprocessData || doprocessMCReco) { + registry.add("eventQA/before/centrality", "", {HistType::kTH1D, {centAxis}}); + registry.add("eventQA/before/globalTracks_centT0C", "", {HistType::kTH2D, {centAxis, nchAxis}}); + registry.add("eventQA/before/PVTracks_centT0C", "", {HistType::kTH2D, {centAxis, multpvAxis}}); + registry.add("eventQA/before/multT0C_centT0C", "", {HistType::kTH2D, {centAxis, t0cAxis}}); + + registry.add("eventQA/before/centT0M_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + registry.add("eventQA/before/centV0A_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + registry.add("eventQA/before/centGlobal_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + registry.add("eventQA/before/centNTPV_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + registry.add("eventQA/before/centMFT_centT0C", "", {HistType::kTH2D, {centAxis, centAxis}}); + } + + registry.addClone("eventQA/before/", "eventQA/after/"); + registry.add("eventQA/eventSel", "Number of Events;; Counts", {HistType::kTH1D, {{11, 0.5, 11.5}}}); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kFilteredEvent, "Filtered event"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kSel8, "sel8"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kOccupancy, "occupancy"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kTVXTRD, "kTVXinTRD"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kNoSamebunchPU, "kNoSameBunchPileup"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kZVtxFT0PV, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kNoCollTRStd, "kNoCollInTimeRangeStandard"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kVtxITSTPC, "kIsVertexITSTPC"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kGoodITSLayers, "kIsGoodITSLayersAll"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kMultCuts, "after Mult cuts"); + registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kTrackCent, "has track + within cent"); + if (!cfgRunByRun && cfgFillWeights) { + registry.add("phi_eta_vtxz_ref", "", {HistType::kTH3D, {phiAxis, etaAxis, vtxAxis}}); + } + } + + if (o2::analysis::gfw::regions.GetSize() < 0) + LOGF(error, "Configuration contains vectors of different size - check the GFWRegions configurable"); + for (auto i(0); i < o2::analysis::gfw::regions.GetSize(); ++i) { + fGFW->AddRegion(o2::analysis::gfw::regions.GetNames()[i], o2::analysis::gfw::regions.GetEtaMin()[i], o2::analysis::gfw::regions.GetEtaMax()[i], (o2::analysis::gfw::regions.GetpTDifs()[i]) ? ptbins + 1 : 1, o2::analysis::gfw::regions.GetBitmasks()[i]); + } + for (auto i = 0; i < o2::analysis::gfw::configs.GetSize(); ++i) { + corrconfigs.push_back(fGFW->GetCorrelatorConfig(o2::analysis::gfw::configs.GetCorrs()[i], o2::analysis::gfw::configs.GetHeads()[i], o2::analysis::gfw::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); + if (doprocessData || doprocessMCReco) { + fFC->SetName("FlowContainer"); + fFC->SetXAxis(fSecondAxis); + fFC->Initialize(oba, multAxis, cfgNbootstrap); + } + if (doprocessMCGen || doprocessOnTheFly) { + fFCgen->SetName("FlowContainer_gen"); + fFCgen->SetXAxis(fSecondAxis); + fFCgen->Initialize(oba, multAxis, cfgNbootstrap); + } + delete oba; + fFCpt->setUseCentralMoments(cfgUseCentralMoments); + fFCpt->setUseGapMethod(true); + fFCpt->initialise(multAxis, cfgMpar, o2::analysis::gfw::configs, cfgNbootstrap); + fFCptFull->setUseCentralMoments(cfgUseCentralMoments); + fFCptFull->setUseGapMethod(true); + fFCptFull->initialise(multAxis, cfgMpar, o2::analysis::gfw::configs, cfgNbootstrap); + fFCptFull->initialiseSubevent(multAxis, cfgMpar, cfgNbootstrap); + fFCptgen->setUseCentralMoments(cfgUseCentralMoments); + fFCptgen->setUseGapMethod(true); + fFCptgen->initialise(multAxis, cfgMpar, o2::analysis::gfw::configs, cfgNbootstrap); + fFCptgenFull->setUseCentralMoments(cfgUseCentralMoments); + fFCptgenFull->setUseGapMethod(true); + fFCptgenFull->initialise(multAxis, cfgMpar, o2::analysis::gfw::configs, cfgNbootstrap); + fFCptgenFull->initialiseSubevent(multAxis, cfgMpar, cfgNbootstrap); + + fPtDepDCAxy = new TF1("ptDepDCAxy", Form("[0]*%s", cfgDCAxy->c_str()), 0.001, 100); + fPtDepDCAxy->SetParameter(0, cfgDCAxyNSigma); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", cfgDCAxy->c_str())); + if (cfgUseAdditionalEventCut) { + fMultPVCutLow = new TF1("fMultPVCutLow", cfgMultCorrCuts.cfgMultCorrLowCutFunction->c_str(), 0, 100); + fMultPVCutLow->SetParameters(&(o2::analysis::gfw::multPVCorrCutPars[0])); + fMultPVCutHigh = new TF1("fMultPVCutHigh", cfgMultCorrCuts.cfgMultCorrHighCutFunction->c_str(), 0, 100); + fMultPVCutHigh->SetParameters(&(o2::analysis::gfw::multPVCorrCutPars[0])); + fMultCutLow = new TF1("fMultCutLow", cfgMultCorrCuts.cfgMultCorrLowCutFunction->c_str(), 0, 100); + fMultCutLow->SetParameters(&(o2::analysis::gfw::multGlobalCorrCutPars[0])); + fMultCutHigh = new TF1("fMultCutHigh", cfgMultCorrCuts.cfgMultCorrHighCutFunction->c_str(), 0, 100); + fMultCutHigh->SetParameters(&(o2::analysis::gfw::multGlobalCorrCutPars[0])); + fMultPVGlobalCutHigh = new TF1("fMultPVGlobalCutHigh", cfgMultCorrCuts.cfgMultGlobalPVCorrCutFunction->c_str(), 0, nchbinning.back()); + fMultPVGlobalCutHigh->SetParameters(&(o2::analysis::gfw::multGlobalPVCorrCutPars[0])); + + LOGF(info, "Global V0A function: %s in range 0-%g", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), v0aAxis.binEdges.back()); + fMultGlobalV0ACutLow = new TF1("fMultGlobalV0ACutLow", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), 0, v0aAxis.binEdges.back()); + for (std::size_t i = 0; i < o2::analysis::gfw::multGlobalV0ACutPars.size(); ++i) + fMultGlobalV0ACutLow->SetParameter(i, o2::analysis::gfw::multGlobalV0ACutPars[i]); + fMultGlobalV0ACutLow->SetParameter(o2::analysis::gfw::multGlobalV0ACutPars.size(), cfgGlobalAsideCorrCuts.cfgGlobalV0ALowSigma); + for (int i = 0; i < fMultGlobalV0ACutLow->GetNpar(); ++i) + LOGF(info, "fMultGlobalV0ACutLow par %d = %g", i, fMultGlobalV0ACutLow->GetParameter(i)); + + fMultGlobalV0ACutHigh = new TF1("fMultGlobalV0ACutHigh", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), 0, v0aAxis.binEdges.back()); + for (std::size_t i = 0; i < o2::analysis::gfw::multGlobalV0ACutPars.size(); ++i) + fMultGlobalV0ACutHigh->SetParameter(i, o2::analysis::gfw::multGlobalV0ACutPars[i]); + fMultGlobalV0ACutHigh->SetParameter(o2::analysis::gfw::multGlobalV0ACutPars.size(), cfgGlobalAsideCorrCuts.cfgGlobalV0AHighSigma); + for (int i = 0; i < fMultGlobalV0ACutHigh->GetNpar(); ++i) + LOGF(info, "fMultGlobalV0ACutHigh par %d = %g", i, fMultGlobalV0ACutHigh->GetParameter(i)); + + LOGF(info, "Global T0A function: %s", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str()); + fMultGlobalT0ACutLow = new TF1("fMultGlobalT0ACutLow", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), 0, t0aAxis.binEdges.back()); + for (std::size_t i = 0; i < o2::analysis::gfw::multGlobalT0ACutPars.size(); ++i) + fMultGlobalT0ACutLow->SetParameter(i, o2::analysis::gfw::multGlobalT0ACutPars[i]); + fMultGlobalT0ACutLow->SetParameter(o2::analysis::gfw::multGlobalT0ACutPars.size(), cfgGlobalAsideCorrCuts.cfgGlobalT0ALowSigma); + for (int i = 0; i < fMultGlobalT0ACutLow->GetNpar(); ++i) + LOGF(info, "fMultGlobalT0ACutLow par %d = %g", i, fMultGlobalT0ACutLow->GetParameter(i)); + + fMultGlobalT0ACutHigh = new TF1("fMultGlobalT0ACutHigh", cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->c_str(), 0, t0aAxis.binEdges.back()); + for (std::size_t i = 0; i < o2::analysis::gfw::multGlobalT0ACutPars.size(); ++i) + fMultGlobalT0ACutHigh->SetParameter(i, o2::analysis::gfw::multGlobalT0ACutPars[i]); + fMultGlobalT0ACutHigh->SetParameter(o2::analysis::gfw::multGlobalT0ACutPars.size(), cfgGlobalAsideCorrCuts.cfgGlobalT0AHighSigma); + for (int i = 0; i < fMultGlobalT0ACutHigh->GetNpar(); ++i) + LOGF(info, "fMultGlobalT0ACutHigh par %d = %g", i, fMultGlobalT0ACutHigh->GetParameter(i)); + } + if (cfgUseDensityDependentCorrection) { + 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); + } + if (cfgConsistentEventFlag) { + posRegionIndex = [&]() { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, "refP"); + return (it != end) ? std::distance(begin, it) : -1; + }(); + negRegionIndex = [&]() { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, "refN"); + return (it != end) ? std::distance(begin, it) : -1; + }(); + fullRegionIndex = [&]() { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, "refFull"); + return (it != end) ? std::distance(begin, it) : -1; + }(); + midRegionIndex = [&]() { + auto begin = cfgRegions->GetNames().begin(); + auto end = cfgRegions->GetNames().end(); + auto it = std::find(begin, end, "refMid"); + return (it != end) ? std::distance(begin, it) : -1; + }(); + } + } + + 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) { + std::string suffix = "_ptDiff"; + for (auto i = 0; i < fSecondAxis->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) + { + 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(); + } + + void loadCorrections(aod::BCsWithTimestamps::iterator const& bc) + { + uint64_t timestamp = bc.timestamp(); + if (!cfgRunByRun && cfg.correctionsLoaded) + return; + if (!cfgAcceptance.value.empty()) { + std::string runstr = (cfgRunByRun) ? "RunByRun/" : ""; + cfg.mAcceptance = ccdb->getForTimeStamp(cfgAcceptance.value + runstr, timestamp); + } + if (!cfgEfficiency.value.empty()) { + cfg.mEfficiency = ccdb->getForTimeStamp(cfgEfficiency, timestamp); + if (cfg.mEfficiency == nullptr) { + 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; + } + + template + double getAcceptance(TTrack track, const double& vtxz) + { + double wacc = 1; + if (cfg.mAcceptance) + wacc = cfg.mAcceptance->getNUA(track.phi(), track.eta(), vtxz); + return wacc; + } + + template + double getEfficiency(TTrack track) + { + double eff = 1.; + if (cfg.mEfficiency) + eff = cfg.mEfficiency->GetBinContent(cfg.mEfficiency->FindBin(track.pt())); + if (eff == 0) + return -1.; + else + return 1. / eff; + } + + template + bool eventSelected(TCollision collision, const int& multTrk, const float& centrality, const int& run) + { + if (cfgTVXinTRD) { + if (collision.alias_bit(kTVXinTRD)) { + // TRD triggered + // "CMTVX-B-NOPF-TRD,minbias_TVX" + return 0; + } + registry.fill(HIST("eventQA/eventSel"), kTVXTRD); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kTVXTRD); + } + 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"), kNoSamebunchPU); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kNoSamebunchPU); + } + 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"), kZVtxFT0PV); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kZVtxFT0PV); + } + 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"), kNoCollTRStd); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kNoCollTRStd); + } + + 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"), kVtxITSTPC); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kVtxITSTPC); + } + + if (cfgIsGoodITSLayersAll) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return 0; + } + registry.fill(HIST("eventQA/eventSel"), kGoodITSLayers); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kGoodITSLayers); + } + + float vtxz = -999; + if (collision.numContrib() > 1) { + vtxz = collision.posZ(); + float zRes = std::sqrt(collision.covZZ()); + float minZRes = 0.25; + int minNContrib = 20; + if (zRes > minZRes && collision.numContrib() < minNContrib) + vtxz = -999; + } + auto multNTracksPV = collision.multNTracksPV(); + + if (vtxz > o2::analysis::gfw::vtxZup || vtxz < o2::analysis::gfw::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; + if (multTrk > fMultPVGlobalCutHigh->Eval(collision.multNTracksPV())) + return 0; + + if (!(cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->empty()) && static_cast(collision.multFV0A()) < fMultGlobalV0ACutLow->Eval(multTrk)) + return 0; + if (!(cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->empty()) && static_cast(collision.multFV0A()) > fMultGlobalV0ACutHigh->Eval(multTrk)) + return 0; + if (!(cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->empty()) && static_cast(collision.multFT0A()) < fMultGlobalT0ACutLow->Eval(multTrk)) + return 0; + if (!(cfgGlobalAsideCorrCuts.cfgMultGlobalASideCorrCutFunction->empty()) && static_cast(collision.multFT0A()) > fMultGlobalT0ACutHigh->Eval(multTrk)) + return 0; + registry.fill(HIST("eventQA/eventSel"), kMultCuts); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kMultCuts); + } + return 1; + } + + template + bool trackSelected(TTrack track) + { + if (cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > fPtDepDCAxy->Eval(track.pt()))) + return false; + return ((track.tpcNClsCrossedRows() >= cfgNTPCXrows) && (track.tpcNClsFound() >= cfgNTPCCls) && (track.itsNCls() >= cfgMinNITSCls)); + } + + enum DataType { + kReco, + kGen + }; + + template + void fillWeights(const TTrack track, const double vtxz, const int& run) + { + 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; + } + + void createRunByRunHistograms(const int& run) + { + AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; + AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgEta, cfgEta, "#eta"}; + AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgVtxZ, cfgVtxZ, "Vtx_{z} (cm)"}; + AxisSpec nchAxis = {o2::analysis::gfw::nchbins, o2::analysis::gfw::nchlow, o2::analysis::gfw::nchup, "N_{ch}"}; + AxisSpec centAxis = {o2::analysis::gfw::centbinning, "Centrality (%)"}; + 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, {nchAxis}}); + histos[hCent] = registry.add(Form("%d/cent", run), "", {HistType::kTH1D, {centAxis}}); + if (cfgFillFlowRunByRun) { + std::vector> profiles(kCount_TProfileNames); + profiles[pfCorr22] = registry.add(Form("%d/corr22", run), "", {HistType::kTProfile, {(cfgUseNch) ? nchAxis : centAxis}}); + tpfsList.insert(std::make_pair(run, profiles)); + } + histos[hEventSel] = registry.add(Form("%d/eventSel", run), "Number of Events;; Counts", {HistType::kTH1D, {{11, 0.5, 11.5}}}); + histos[hEventSel]->GetXaxis()->SetBinLabel(kFilteredEvent, "Filtered event"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kSel8, "sel8"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kOccupancy, "occupancy"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kTVXTRD, "kTVXinTRD"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kNoSamebunchPU, "kNoSameBunchPileup"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kZVtxFT0PV, "kIsGoodZvtxFT0vsPV"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kNoCollTRStd, "kNoCollInTimeRangeStandard"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kVtxITSTPC, "kIsVertexITSTPC"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kGoodITSLayers, "kIsGoodITSLayersAll"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kMultCuts, "after Mult cuts"); + histos[hEventSel]->GetXaxis()->SetBinLabel(kTrackCent, "has track + within cent"); + th1sList.insert(std::make_pair(run, histos)); + std::vector> histos3d(kCount_TH3Names); + 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, const int& run = 0) + { + if (dt == kGen) { + fFCptgen->calculateCorrelations(); + fFCptgenFull->calculateCorrelations(); + fFCptgenFull->calculateSubeventCorrelations(); + } else { + fFCpt->calculateCorrelations(); + fFCptFull->calculateCorrelations(); + fFCptFull->calculateSubeventCorrelations(); + } + if (dt == kGen) { + fFCptgen->fillPtProfiles(centmult, rndm); + fFCptgen->fillCMProfiles(centmult, rndm); + fFCptgenFull->fillPtProfiles(centmult, rndm); + fFCptgenFull->fillCMProfiles(centmult, rndm); + fFCptgenFull->fillSubeventPtProfiles(centmult, rndm); + fFCptgenFull->fillCMSubeventProfiles(centmult, rndm); + } else { + fFCpt->fillPtProfiles(centmult, rndm); + fFCpt->fillCMProfiles(centmult, rndm); + fFCptFull->fillPtProfiles(centmult, rndm); + fFCptFull->fillSubeventPtProfiles(centmult, rndm); + fFCptFull->fillCMProfiles(centmult, rndm); + fFCptFull->fillCMSubeventProfiles(centmult, rndm); + } + for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { + if (!corrconfigs.at(l_ind).pTDif) { + uint8_t vnptmask = o2::analysis::gfw::configs.GetpTCorrMasks()[l_ind]; + auto dnx = fGFW->Calculate(corrconfigs.at(l_ind), 0, kTRUE).real(); + if (dnx == 0) { + (dt == kGen) ? fFCptgen->skipVnPtProfiles(vnptmask) : fFCpt->skipVnPtProfiles(vnptmask); + continue; + } + auto val = fGFW->Calculate(corrconfigs.at(l_ind), 0, kFALSE).real() / dnx; + if (std::abs(val) < 1) { + (dt == kGen) ? fFCgen->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm) : fFC->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm); + (dt == kGen) ? fFCptgen->fillVnPtProfiles(centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm, vnptmask) : fFCpt->fillVnPtProfiles(centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm, vnptmask); + if (cfgRunByRun && cfgFillFlowRunByRun && dt != kGen && l_ind == 0) { + tpfsList[run][pfCorr22]->Fill(centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0); + } + } else { + (dt == kGen) ? fFCptgen->skipVnPtProfiles(vnptmask) : fFCpt->skipVnPtProfiles(vnptmask); + } + continue; + } + for (int i = 1; i <= fSecondAxis->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 (std::abs(val) < 1) + (dt == kGen) ? fFCgen->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm) : fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm); + } + } + return; + } + + struct XAxis { + float centrality; + int64_t multiplicity; + double time; + }; + + struct AcceptedTracks { + int nPos; + int nNeg; + int nFull; + int nMid; + }; + + template + void processCollision(TCollision collision, TTracks tracks, const XAxis& xaxis, const int& run) + { + if (tracks.size() < 1) + return; + if (dt != kGen && xaxis.centrality >= 0 && (xaxis.centrality < o2::analysis::gfw::centbinning.front() || xaxis.centrality > o2::analysis::gfw::centbinning.back())) + return; + if (xaxis.multiplicity < cfgFixedMultMin || xaxis.multiplicity > cfgFixedMultMax) + return; + if (dt != kGen) { + registry.fill(HIST("eventQA/eventSel"), kTrackCent); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kTrackCent); + } + if (xaxis.centrality >= 0) + registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); + registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); + float vtxz = collision.posZ(); + if (dt != kGen && cfgRunByRun) { + th1sList[run][hVtxZ]->Fill(vtxz); + th1sList[run][hMult]->Fill(xaxis.multiplicity); + th1sList[run][hCent]->Fill(xaxis.centrality); + } + fGFW->Clear(); + if (dt == kGen) { + fFCptgen->clearVector(); + fFCptgenFull->clearVector(); + } else { + fFCpt->clearVector(); + fFCptFull->clearVector(); + } + + float lRandom = fRndm->Rndm(); + + // be cautious, this only works for Pb-Pb + // esimate the Event plane and vn for this event + DensityCorr densitycorrections; + if (cfgUseDensityDependentCorrection) { + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + double v2 = 0, v3 = 0, v4 = 0; + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (const auto& track : tracks) { + bool withinPtRef = (o2::analysis::gfw::ptreflow < track.pt()) && (track.pt() < o2::analysis::gfw::ptrefup); // 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(xaxis.centrality); + v3 = funcV3->Eval(xaxis.centrality); + v4 = funcV4->Eval(xaxis.centrality); + densitycorrections.psi2Est = psi2Est; + densitycorrections.psi3Est = psi3Est; + densitycorrections.psi4Est = psi4Est; + densitycorrections.v2 = v2; + densitycorrections.v3 = v3; + densitycorrections.v4 = v4; + densitycorrections.density = tracks.size(); + } + AcceptedTracks acceptedTracks{0, 0, 0, 0}; + for (const auto& track : tracks) { + processTrack(track, vtxz, xaxis.multiplicity, run, densitycorrections, acceptedTracks); + if (cfgConsistentEventFlag & 1) + if (!acceptedTracks.nPos || !acceptedTracks.nNeg) + return; + if (cfgConsistentEventFlag & 2) + if (acceptedTracks.nFull < 4) // o2-linter: disable=magic-number (at least four tracks in full acceptance) + return; + if (cfgConsistentEventFlag & 4) + if (acceptedTracks.nPos < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in each subevent) + return; + if (cfgConsistentEventFlag & 8) + if (acceptedTracks.nPos < 2 || acceptedTracks.nMid < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in all three subevents) + return; + } + if (!cfgFillWeights) + fillOutputContainers
((cfgTimeDependent) ? xaxis.time : (cfgUseNch) ? xaxis.multiplicity + : xaxis.centrality, + lRandom, run); + } + + bool isStable(int pdg) + { + if (std::abs(pdg) == PDG_t::kPiPlus) + return true; + if (std::abs(pdg) == PDG_t::kKPlus) + return true; + if (std::abs(pdg) == PDG_t::kProton) + return true; + if (std::abs(pdg) == PDG_t::kElectron) + return true; + if (std::abs(pdg) == PDG_t::kMuonMinus) + return true; + return false; + } + + template + void fillAcceptedTracks(TTrack track, AcceptedTracks& acceptedTracks) + { + if (posRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[posRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[posRegionIndex]) + ++acceptedTracks.nPos; + if (negRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[negRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[negRegionIndex]) + ++acceptedTracks.nNeg; + if (fullRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[fullRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[fullRegionIndex]) + ++acceptedTracks.nFull; + if (midRegionIndex >= 0 && track.eta() > o2::analysis::gfw::regions.GetEtaMin()[midRegionIndex] && track.eta() < o2::analysis::gfw::regions.GetEtaMax()[midRegionIndex]) + ++acceptedTracks.nMid; + } + + template + inline void processTrack(TTrack const& track, const float& vtxz, const int& multiplicity, const int& run, DensityCorr densitycorrections, AcceptedTracks& acceptedTracks) + { + if constexpr (framework::has_type_v) { + if (track.mcParticleId() < 0 || !(track.has_mcParticle())) + return; + + auto mcParticle = track.mcParticle(); + if (!mcParticle.isPhysicalPrimary()) + return; + if (!isStable(mcParticle.pdgCode())) + return; + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/before/nch_pt"), multiplicity, track.pt()); + } + if (!trackSelected(track)) + return; + + if (cfgFillWeights) { + fillWeights(track, vtxz, run); + } else { + fillPtSums(track); + fillGFW(track, vtxz, densitycorrections); + fillAcceptedTracks(track, acceptedTracks); + } + + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/after/nch_pt"), multiplicity, track.pt()); + if (cfgRunByRun) { + th1sList[run][hPhi]->Fill(track.phi()); + th1sList[run][hEta]->Fill(track.eta()); + } + } + + } else if constexpr (framework::has_type_v) { + if (!track.isPhysicalPrimary() || !isStable(track.pdgCode())) + return; + + fillPtSums(track); + fillGFW(track, vtxz, densitycorrections); + fillAcceptedTracks(track, acceptedTracks); + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("MCGen/trackQA/nch_pt"), multiplicity, track.pt()); + } + } else { + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/before/nch_pt"), multiplicity, track.pt()); + } + if (!trackSelected(track)) + return; + + if (cfgFillWeights) { + fillWeights(track, vtxz, run); + } else { + fillPtSums(track); + fillGFW(track, vtxz, densitycorrections); + fillAcceptedTracks(track, acceptedTracks); + } + if (cfgFillQA) { + fillTrackQA(track, vtxz); + registry.fill(HIST("trackQA/after/nch_pt"), multiplicity, track.pt()); + if (cfgRunByRun) { + th1sList[run][hPhi]->Fill(track.phi()); + th1sList[run][hEta]->Fill(track.eta()); + th3sList[run][hNUAref]->Fill(track.phi(), track.eta(), vtxz, getAcceptance(track, vtxz)); + } + } + } + return; + } + + template + inline void fillGFW(TTrack track, const double& vtxz, DensityCorr densitycorrections) + { + bool withinPtRef = (track.pt() > o2::analysis::gfw::ptreflow && track.pt() < o2::analysis::gfw::ptrefup); + bool withinPtPOI = (track.pt() > o2::analysis::gfw::ptpoilow && track.pt() < o2::analysis::gfw::ptpoiup); + if (!withinPtPOI && !withinPtRef) + return; + double weff = (dt == kGen) ? 1. : getEfficiency(track); + if (weff < 0) + return; + if (cfgUseDensityDependentCorrection && withinPtRef && dt != kGen) { + double fphi = densitycorrections.v2 * std::cos(2 * (track.phi() - densitycorrections.psi2Est)) + densitycorrections.v3 * std::cos(3 * (track.phi() - densitycorrections.psi3Est)) + densitycorrections.v4 * std::cos(4 * (track.phi() - densitycorrections.psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(track.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + float wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * densitycorrections.density); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + } + } + } + double wacc = (dt == kGen) ? 1. : getAcceptance(track, vtxz); + if (withinPtRef) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 1); + if (withinPtPOI) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 2); + if (withinPtRef && withinPtPOI) + fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 4); + return; + } + + template + inline void fillPtSums(TTrack track) + { + if (track.pt() < o2::analysis::gfw::ptreflow || track.pt() > o2::analysis::gfw::ptrefup) + return; + + double weff = (dt == kGen) ? 1. : getEfficiency(track); + if (weff < 0) + return; + + // Fill pt-pt correlations used in vn-pt correlations (gapped) + if (std::abs(track.eta()) < cfgEtaPtPt) { + if (dt == kGen) { + fFCptgen->fill(1., track.pt()); + } else { + fFCpt->fill(weff, track.pt()); + } + } + + // Fill pt-pt correlations for entire eta range + if (std::abs(track.eta()) < cfgEtaPtPtFull) + (dt == kGen) ? fFCptgenFull->fill(1., track.pt()) : fFCptFull->fill(weff, track.pt()); + + // Fill pt-pt correlations in subevents + if (track.eta() < -cfgEtaPtPtGap && track.eta() > -cfgEtaPtPtFull) + (dt == kGen) ? fFCptgenFull->fillSub1(weff, track.pt()) : fFCptFull->fillSub1(weff, track.pt()); + if (track.eta() > cfgEtaPtPtGap && track.eta() < cfgEtaPtPtFull) + (dt == kGen) ? fFCptgenFull->fillSub2(weff, track.pt()) : fFCptFull->fillSub2(weff, track.pt()); + return; + } + + template + inline void fillTrackQA(TTrack track, const float vtxz) + { + if constexpr (dt == kGen) { + registry.fill(HIST("MCGen/trackQA/phi_eta_vtxZ"), track.phi(), track.eta(), vtxz); + registry.fill(HIST("MCGen/trackQA/pt_ref"), track.pt()); + registry.fill(HIST("MCGen/trackQA/pt_poi"), track.pt()); + } else { + double wacc = getAcceptance(track, vtxz); + 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()); + + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("chi2prTPCcls"), track.tpcChi2NCl()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("chi2prITScls"), track.itsChi2NCl()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nTPCClusters"), track.tpcNClsFound()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nITSClusters"), track.itsNCls()); + registry.fill(HIST("trackQA/") + HIST(FillTimeName[ft]) + HIST("nTPCCrossedRows"), track.tpcNClsCrossedRows()); + + 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 + float getCentrality(TCollision collision) + { + switch (cfgCentEstimator) { + case kCentFT0C: + return collision.centFT0C(); + case kCentFT0CVariant1: + return collision.centFT0CVariant1(); + case kCentFT0M: + return collision.centFT0M(); + case kCentFV0A: + return collision.centFV0A(); + case kCentNTPV: + return collision.centNTPV(); + case kCentNGlobal: + return collision.centNGlobal(); + case kCentMFT: + return collision.centMFT(); + default: + return collision.centFT0C(); + } + } + + template + inline void fillEventQA(TCollision collision, XAxis xaxis) + { + if constexpr (framework::has_type_v) { + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_centT0C"), collision.centFT0C(), xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("PVTracks_centT0C"), collision.centFT0C(), collision.multNTracksPV()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multT0C_centT0C"), collision.centFT0C(), collision.multFT0C()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centT0M_centT0C"), collision.centFT0C(), collision.centFT0M()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centV0A_centT0C"), collision.centFT0C(), collision.centFV0A()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centGlobal_centT0C"), collision.centFT0C(), collision.centNGlobal()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centNTPV_centT0C"), collision.centFT0C(), collision.centNTPV()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("centMFT_centT0C"), collision.centFT0C(), collision.centMFT()); + } + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_PVTracks"), collision.multNTracksPV(), xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_multT0A"), collision.multFT0A(), xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("globalTracks_multV0A"), collision.multFV0A(), xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multV0A_multT0A"), collision.multFT0A(), collision.multFV0A()); + if (cfgTimeDependent) { + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multiplicity_time"), xaxis.time, xaxis.multiplicity); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multT0C_time"), xaxis.time, collision.multFT0C()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multT0A_time"), xaxis.time, collision.multFT0A()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multV0A_time"), xaxis.time, collision.multFV0A()); + registry.fill(HIST("eventQA/") + HIST(FillTimeName[ft]) + HIST("multPV_time"), xaxis.time, collision.multNTracksPV()); + } + return; + } + + double getTimeSinceStartOfFill(uint64_t timestamp, int firstRun) + { + auto runDuration = ccdb->getRunDuration(firstRun); + uint64_t tsSOF = runDuration.first; + uint64_t diff = timestamp - tsSOF; + return static_cast(diff) / 3600000.0; + } + + 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"), kFilteredEvent); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kFilteredEvent); + if (!collision.sel8()) + return; + registry.fill(HIST("eventQA/eventSel"), kSel8); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kSel8); + if (cfgDoOccupancySel) { + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy < 0 || occupancy > cfgOccupancySelection) + return; + } + registry.fill(HIST("eventQA/eventSel"), kOccupancy); + if (cfgRunByRun) + th1sList[run][hEventSel]->Fill(kOccupancy); + + const XAxis xaxis{getCentrality(collision), tracks.size(), (cfgTimeDependent) ? getTimeSinceStartOfFill(bc.timestamp(), *firstRunOfCurrentFill) : -1.0}; + if (cfgTimeDependent && run == *firstRunOfCurrentFill && firstRunOfCurrentFill != o2::analysis::gfw::firstRunsOfFill.end() - 1) + ++firstRunOfCurrentFill; + + if (cfgFillQA) + fillEventQA(collision, xaxis); + registry.fill(HIST("eventQA/before/centrality"), xaxis.centrality); + registry.fill(HIST("eventQA/before/multiplicity"), xaxis.multiplicity); + if (cfgUseAdditionalEventCut && !eventSelected(collision, xaxis.multiplicity, xaxis.centrality, run)) + return; + if (cfgFillQA) + fillEventQA(collision, xaxis); + processCollision(collision, tracks, xaxis, run); + } + PROCESS_SWITCH(FlowGfwLightIons, 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 XAxis xaxis{getCentrality(collision), tracks.size(), (cfgTimeDependent) ? getTimeSinceStartOfFill(bc.timestamp(), *firstRunOfCurrentFill) : -1.0}; + if (cfgTimeDependent && run == *firstRunOfCurrentFill && firstRunOfCurrentFill != o2::analysis::gfw::firstRunsOfFill.end() - 1) + ++firstRunOfCurrentFill; + + if (cfgFillQA) + fillEventQA(collision, xaxis); + registry.fill(HIST("eventQA/before/centrality"), xaxis.centrality); + registry.fill(HIST("eventQA/before/multiplicity"), xaxis.multiplicity); + if (cfgUseAdditionalEventCut && !eventSelected(collision, xaxis.multiplicity, xaxis.centrality, run)) + return; + if (cfgFillQA) + fillEventQA(collision, xaxis); + if (!cfgFillWeights) + loadCorrections(bc); + processCollision(collision, tracks, xaxis, run); + } + PROCESS_SWITCH(FlowGfwLightIons, processMCReco, "Process analysis for MC reconstructed events", false); + + void processMCGen(soa::Filtered::iterator const& mcCollision, soa::SmallGroups> const& collisions, aod::McParticles const& particles, GFWTracks const& tracks) + { + if (collisions.size() != 1) + return; + float centrality = -1; + for (const auto& collision : collisions) { + centrality = getCentrality(collision); + } + + std::vector numberOfTracks; + for (auto const& collision : collisions) { + auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + numberOfTracks.emplace_back(groupedTracks.size()); + } + + const XAxis xaxis{centrality, numberOfTracks[0], -1.0}; + int run = 0; + processCollision(mcCollision, particles, xaxis, run); + } + PROCESS_SWITCH(FlowGfwLightIons, processMCGen, "Process analysis for MC generated events", false); + + void processOnTheFly(soa::Filtered::iterator const& mcCollision, aod::McParticles const& mcParticles) + { + int run = 0; + registry.fill(HIST("MCGen/impactParameter"), mcCollision.impactParameter(), mcParticles.size()); + const XAxis xaxis{mcCollision.impactParameter(), mcParticles.size(), -1.0}; + processCollision(mcCollision, mcParticles, xaxis, run); + } + PROCESS_SWITCH(FlowGfwLightIons, processOnTheFly, "Process analysis for MC on-the-fly generated events", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/JCorran/Core/CMakeLists.txt b/PWGCF/JCorran/Core/CMakeLists.txt index 9f6f99e9e74..6c4e10529bb 100644 --- a/PWGCF/JCorran/Core/CMakeLists.txt +++ b/PWGCF/JCorran/Core/CMakeLists.txt @@ -14,6 +14,7 @@ o2physics_add_library(JCorran JFFlucAnalysisO2Hist.cxx FlowJSPCAnalysis.cxx FlowJHistManager.cxx + JEPFlowAnalysis.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore) o2physics_target_root_dictionary(JCorran @@ -22,4 +23,5 @@ o2physics_target_root_dictionary(JCorran 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 index c78dbc4af3b..880ec409dbd 100644 --- a/PWGCF/JCorran/Core/FlowJHistManager.cxx +++ b/PWGCF/JCorran/Core/FlowJHistManager.cxx @@ -10,18 +10,20 @@ // 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() +void FlowJHistManager::createHistQA() { // Security checks for proper use of the method. if (!mHistRegistryQA) { @@ -60,7 +62,7 @@ void FlowJHistManager::CreateHistQA() mHistRegistryQA->add("Centrality_00-01/After/histEta", "Pseudorapidity", HistType::kTH1F, {axisEta}, true); - const AxisSpec axisPhi = {100, 0., 2. * M_PI, "#varphi"}; + 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); @@ -145,7 +147,7 @@ void FlowJHistManager::CreateHistQA() // Clone the first centrality class into the other classes. for (int iBin = 1; iBin < mNcentBins; iBin++) { - mHistRegistryQA->addClone("Centrality_00-01/", mCentClasses[iBin].data()); + mHistRegistryQA->addClone("Centrality_00-01/", MCentClasses[iBin].data()); } LOGF(info, "QA histograms created."); @@ -154,9 +156,9 @@ void FlowJHistManager::CreateHistQA() /// \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) +int FlowJHistManager::getCentBin(float cValue) { - const float centClasses[] = {0., 1., 2., 5., 10., 20., 30., 40., 50., 60., 70.}; + 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]) { diff --git a/PWGCF/JCorran/Core/FlowJHistManager.h b/PWGCF/JCorran/Core/FlowJHistManager.h index cbb212ff917..e067a9f00b5 100644 --- a/PWGCF/JCorran/Core/FlowJHistManager.h +++ b/PWGCF/JCorran/Core/FlowJHistManager.h @@ -16,7 +16,6 @@ #define PWGCF_JCORRAN_CORE_FLOWJHISTMANAGER_H_ /* Header files. */ -#include #include #include #include @@ -33,8 +32,6 @@ // O2 Physics headers. /* Namespaces. */ -using namespace o2; -using namespace o2::framework; // ---------------------------------------------------------------------------- // Histogram manager to fill the general QA common to all flow tasks. @@ -45,52 +42,52 @@ class FlowJHistManager FlowJHistManager() = default; // Setters and getters, in the same order as the data members. - void SetHistRegistryQA(HistogramRegistry* myRegistry) + void setHistRegistryQA(o2::framework::HistogramRegistry* myRegistry) { mHistRegistryQA = myRegistry; LOGF(info, "QA histogram registry successfully set."); } - HistogramRegistry* GetHistRegistryQA() const { return mHistRegistryQA; } + o2::framework::HistogramRegistry* getHistRegistryQA() const { return mHistRegistryQA; } - void SetDebugLog(bool debug) + void setDebugLog(bool debug) { mDebugLog = debug; LOGF(info, "Debug level: %d", mDebugLog); } - bool GetDebugLog() const { return mDebugLog; } + bool getDebugLog() const { return mDebugLog; } - void SetObtainNUA(bool nua) + void setObtainNUA(bool nua) { mObtainNUA = nua; LOGF(info, "Obtain 3D Zvtx-eta-phi distribution: %d", mObtainNUA); } - bool GetObtainNUA() const { return mObtainNUA; } + bool getObtainNUA() const { return mObtainNUA; } - void SetSaveAllQA(bool saveQA) + void setSaveAllQA(bool saveQA) { mSaveAllQA = saveQA; LOGF(info, "Save the additional QA : %d.", mSaveAllQA); } - bool GetSaveAllQA() const { return mSaveAllQA; } + bool getSaveAllQA() const { return mSaveAllQA; } - void SetSaveQABefore(bool saveQA) + void setSaveQABefore(bool saveQA) { mSaveQABefore = saveQA; LOGF(info, "Save the QA before the selection : %d.", mSaveQABefore); } - bool GetSaveQABefore() const { return mSaveQABefore; } + bool getSaveQABefore() const { return mSaveQABefore; } - void SetUseVariablePtBins(bool myAxis) + void setUseVariablePtBins(bool myAxis) { mUseVariablePtBins = myAxis; LOGF(info, "Use variable pT binning: %d.", mUseVariablePtBins); } - bool GetUseVariablePtBins() const { return 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); + void createHistQA(); + int getCentBin(float cValue); /// \brief Fill the event QA histograms. /// \tparam T Type of collision. @@ -100,71 +97,72 @@ class FlowJHistManager /// \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) + 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/"}; + 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()); + 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()); + 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()); + 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()); + 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()); + 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()); + 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()); + 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()); + 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()); + 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()); + 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; } - LOGF(info, "The EventQA has been filled."); + if (mDebugLog) + LOGF(info, "The EventQA has been filled."); } - /// \brief Hardcode the cBin for FillThisTrackQA if not constant. + /// \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. @@ -172,7 +170,7 @@ class FlowJHistManager /// \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, + void fillTrackQA(T const& track, int cBin, float weightNUE = 1., float weightNUA = 1., float zVtx = 0.) { if (!mHistRegistryQA) { @@ -182,34 +180,34 @@ class FlowJHistManager switch (cBin) { case 0: - FillThisTrackQA<0, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<0, mode>(track, zVtx, weightNUE, weightNUA); break; case 1: - FillThisTrackQA<1, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<1, mode>(track, zVtx, weightNUE, weightNUA); break; case 2: - FillThisTrackQA<2, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<2, mode>(track, zVtx, weightNUE, weightNUA); break; case 3: - FillThisTrackQA<3, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<3, mode>(track, zVtx, weightNUE, weightNUA); break; case 4: - FillThisTrackQA<4, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<4, mode>(track, zVtx, weightNUE, weightNUA); break; case 5: - FillThisTrackQA<5, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<5, mode>(track, zVtx, weightNUE, weightNUA); break; case 6: - FillThisTrackQA<6, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<6, mode>(track, zVtx, weightNUE, weightNUA); break; case 7: - FillThisTrackQA<7, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<7, mode>(track, zVtx, weightNUE, weightNUA); break; case 8: - FillThisTrackQA<8, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<8, mode>(track, zVtx, weightNUE, weightNUA); break; case 9: - FillThisTrackQA<9, mode>(track, zVtx, weightNUE, weightNUA); + fillThisTrackQA<9, mode>(track, zVtx, weightNUE, weightNUA); break; } @@ -229,61 +227,61 @@ class FlowJHistManager /// \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., + void fillThisTrackQA(T const& track, float zVtx = 0., float weightNUE = 1., float weightNUA = 1.) { - static constexpr std::string_view subDir[] = {"Before/", "After/"}; + 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()); + 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"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST("After/histPtCorrected"), track.pt(), 1. / weightNUE); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST("After/histPhiCorrected"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST("After/histPhiCorrected"), track.phi(), 1. / weightNUA); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST("After/histNUEWeights"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST("After/histNUEWeights"), track.pt(), weightNUE); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST("After/histNUAWeights"), + 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"), + 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"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCNClsFound"), track.tpcNClsFound()); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histTPCNClsCrossedRows"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCNClsCrossedRows"), track.tpcNClsCrossedRows()); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histTPCCrossedRowsOverFindableCls"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCCrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histTPCFoundOverFindableCls"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCFoundOverFindableCls"), track.tpcFoundOverFindableCls()); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histTPCFractionSharedCls"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCFractionSharedCls"), track.tpcFractionSharedCls()); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histTPCChi2NCl"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histTPCChi2NCl"), track.tpcChi2NCl()); // ITS information. - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histITSNCls"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histITSNCls"), track.itsNCls()); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histITSNClsInnerBarrel"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histITSNClsInnerBarrel"), track.itsNClsInnerBarrel()); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histITSChi2NCl"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histITSChi2NCl"), track.itsChi2NCl()); // DCA information. - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histDCAxy"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histDCAxy"), track.pt(), track.dcaXY()); - mHistRegistryQA->fill(HIST(mCentClasses[cBin]) + HIST(subDir[mode]) + HIST("histDCAz"), + mHistRegistryQA->fill(HIST(MCentClasses[cBin]) + HIST(SubDir[mode]) + HIST("histDCAz"), track.dcaZ()); } @@ -293,7 +291,7 @@ class FlowJHistManager } private: - HistogramRegistry* mHistRegistryQA = nullptr; ///< For the QA output. + 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. @@ -302,7 +300,7 @@ class FlowJHistManager 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. + 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/", diff --git a/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx b/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx index b1221432aa4..40585b3abec 100644 --- a/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Core/FlowJSPCAnalysis.cxx @@ -21,7 +21,7 @@ using namespace o2; using namespace o2::framework; using namespace std; -TComplex FlowJSPCAnalysis::Q(const Int_t harmN, const Int_t p) +TComplex FlowJSPCAnalysis::q(const int harmN, const int p) { if (harmN >= 0) return qvecs->QvectorQC[harmN][p]; @@ -34,24 +34,24 @@ TComplex FlowJSPCAnalysis::Q(const Int_t harmN, const Int_t p) /// \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) +TComplex FlowJSPCAnalysis::recursion(int n, int* harmonic, int mult = 1, int skip = 0) { - Int_t nm1 = n - 1; - TComplex c(Q(harmonic[nm1], mult)); + int nm1 = n - 1; + TComplex c(q(harmonic[nm1], mult)); if (nm1 == 0) return c; - c *= Recursion(nm1, harmonic); + c *= recursion(nm1, harmonic); if (nm1 == skip) return c; - Int_t multp1 = mult + 1; - Int_t nm2 = n - 2; - Int_t counter1 = 0; - Int_t hhold = harmonic[counter1]; + 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_t counter2 = n - 3; + TComplex c2(recursion(nm1, harmonic, multp1, nm2)); + int counter2 = n - 3; while (counter2 >= skip) { harmonic[nm2] = harmonic[counter1]; @@ -60,7 +60,7 @@ TComplex FlowJSPCAnalysis::Recursion(int n, int* harmonic, int mult = 1, int ski hhold = harmonic[counter1]; harmonic[counter1] = harmonic[nm2]; harmonic[nm2] = hhold + harmonic[nm1]; - c2 += Recursion(nm1, harmonic, multp1, counter2); + c2 += recursion(nm1, harmonic, multp1, counter2); --counter2; } harmonic[nm2] = harmonic[counter1]; @@ -68,298 +68,356 @@ TComplex FlowJSPCAnalysis::Recursion(int n, int* harmonic, int mult = 1, int ski if (mult == 1) return c - c2; - return c - Double_t(mult) * c2; + return c - static_cast(mult) * c2; } // End of recursion -void FlowJSPCAnalysis::CalculateCorrelators(const Int_t fCentBin) +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_t* dataCorrelation = new Double_t[3]; // cosine, weight, sine. - Double_t correlationNum; - Double_t weightCorrelationNum; - Double_t correlationDenom; - Double_t weightCorrelationDenom; + double* dataCorrelation = new double[3]; // cosine, weight, sine. + double correlationNum; + double weightCorrelationNum; + double correlationDenom; + double weightCorrelationDenom; - for (Int_t j = 0; j < 12; j++) { + 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_t hArrayNum[7] = {0}; + int hArrayNum[7] = {0}; for (int iH = 0; iH < 7; iH++) { hArrayNum[iH] = fHarmosArray[j][iH + 1]; } - Correlation(fHarmosArray[j][0], 7, hArrayNum, dataCorrelation); + correlation(fHarmosArray[j][0], 7, hArrayNum, dataCorrelation); correlationNum = dataCorrelation[0]; weightCorrelationNum = dataCorrelation[1]; // Calculate the denominator. - Int_t nPartDen = 2 * fHarmosArray[j][0]; - Int_t hArrayDen[14] = {0}; + 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); + 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); - FillHistograms(fCentBin, j, correlationNum, correlationDenom, weightCorrelationNum, weightCorrelationDenom); + correlationNum = 0.; + weightCorrelationNum = 0.; + correlationDenom = 0.; + weightCorrelationDenom = 0.; + } +} - 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::FillHistograms(const Int_t fCentBin, Int_t ind, Double_t cNum, Double_t cDenom, Double_t wNum, Double_t wDenom) +void FlowJSPCAnalysis::fillQAHistograms(const int fCentBin, double phi, double phiWeight) { switch (fCentBin) { case 0: { - mHistRegistry->fill(HIST(mCentClasses[0]) + HIST("fResults"), 2. * (Float_t)(ind) + 0.5, cNum, wNum); - mHistRegistry->fill(HIST(mCentClasses[0]) + HIST("fResults"), 2. * (Float_t)(ind) + 1.5, cDenom, wDenom); - mHistRegistry->fill(HIST(mCentClasses[0]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 0.5, cNum * cDenom, wNum * wDenom); - mHistRegistry->fill(HIST(mCentClasses[0]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 1.5, wNum * wDenom, 1.); - mHistRegistry->fill(HIST(mCentClasses[0]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 2.5, wNum, 1.); - mHistRegistry->fill(HIST(mCentClasses[0]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 3.5, wDenom, 1.); + 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("fResults"), 2. * (Float_t)(ind) + 0.5, cNum, wNum); - mHistRegistry->fill(HIST(mCentClasses[1]) + HIST("fResults"), 2. * (Float_t)(ind) + 1.5, cDenom, wDenom); - mHistRegistry->fill(HIST(mCentClasses[1]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 0.5, cNum * cDenom, wNum * wDenom); - mHistRegistry->fill(HIST(mCentClasses[1]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 1.5, wNum * wDenom, 1.); - mHistRegistry->fill(HIST(mCentClasses[1]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 2.5, wNum, 1.); - mHistRegistry->fill(HIST(mCentClasses[1]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 3.5, wDenom, 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("fResults"), 2. * (Float_t)(ind) + 0.5, cNum, wNum); - mHistRegistry->fill(HIST(mCentClasses[2]) + HIST("fResults"), 2. * (Float_t)(ind) + 1.5, cDenom, wDenom); - mHistRegistry->fill(HIST(mCentClasses[2]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 0.5, cNum * cDenom, wNum * wDenom); - mHistRegistry->fill(HIST(mCentClasses[2]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 1.5, wNum * wDenom, 1.); - mHistRegistry->fill(HIST(mCentClasses[2]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 2.5, wNum, 1.); - mHistRegistry->fill(HIST(mCentClasses[2]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 3.5, wDenom, 1.); + 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("fResults"), 2. * (Float_t)(ind) + 0.5, cNum, wNum); - mHistRegistry->fill(HIST(mCentClasses[3]) + HIST("fResults"), 2. * (Float_t)(ind) + 1.5, cDenom, wDenom); - mHistRegistry->fill(HIST(mCentClasses[3]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 0.5, cNum * cDenom, wNum * wDenom); - mHistRegistry->fill(HIST(mCentClasses[3]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 1.5, wNum * wDenom, 1.); - mHistRegistry->fill(HIST(mCentClasses[3]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 2.5, wNum, 1.); - mHistRegistry->fill(HIST(mCentClasses[3]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 3.5, wDenom, 1.); + 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("fResults"), 2. * (Float_t)(ind) + 0.5, cNum, wNum); - mHistRegistry->fill(HIST(mCentClasses[4]) + HIST("fResults"), 2. * (Float_t)(ind) + 1.5, cDenom, wDenom); - mHistRegistry->fill(HIST(mCentClasses[4]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 0.5, cNum * cDenom, wNum * wDenom); - mHistRegistry->fill(HIST(mCentClasses[4]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 1.5, wNum * wDenom, 1.); - mHistRegistry->fill(HIST(mCentClasses[4]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 2.5, wNum, 1.); - mHistRegistry->fill(HIST(mCentClasses[4]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 3.5, wDenom, 1.); + 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("fResults"), 2. * (Float_t)(ind) + 0.5, cNum, wNum); - mHistRegistry->fill(HIST(mCentClasses[5]) + HIST("fResults"), 2. * (Float_t)(ind) + 1.5, cDenom, wDenom); - mHistRegistry->fill(HIST(mCentClasses[5]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 0.5, cNum * cDenom, wNum * wDenom); - mHistRegistry->fill(HIST(mCentClasses[5]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 1.5, wNum * wDenom, 1.); - mHistRegistry->fill(HIST(mCentClasses[5]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 2.5, wNum, 1.); - mHistRegistry->fill(HIST(mCentClasses[5]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 3.5, wDenom, 1.); + 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("fResults"), 2. * (Float_t)(ind) + 0.5, cNum, wNum); - mHistRegistry->fill(HIST(mCentClasses[6]) + HIST("fResults"), 2. * (Float_t)(ind) + 1.5, cDenom, wDenom); - mHistRegistry->fill(HIST(mCentClasses[6]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 0.5, cNum * cDenom, wNum * wDenom); - mHistRegistry->fill(HIST(mCentClasses[6]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 1.5, wNum * wDenom, 1.); - mHistRegistry->fill(HIST(mCentClasses[6]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 2.5, wNum, 1.); - mHistRegistry->fill(HIST(mCentClasses[6]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 3.5, wDenom, 1.); + 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("fResults"), 2. * (Float_t)(ind) + 0.5, cNum, wNum); - mHistRegistry->fill(HIST(mCentClasses[7]) + HIST("fResults"), 2. * (Float_t)(ind) + 1.5, cDenom, wDenom); - mHistRegistry->fill(HIST(mCentClasses[7]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 0.5, cNum * cDenom, wNum * wDenom); - mHistRegistry->fill(HIST(mCentClasses[7]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 1.5, wNum * wDenom, 1.); - mHistRegistry->fill(HIST(mCentClasses[7]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 2.5, wNum, 1.); - mHistRegistry->fill(HIST(mCentClasses[7]) + HIST("fCovResults"), 2. * (Float_t)(ind) + 3.5, wDenom, 1.); + 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_t c_nPart, Int_t c_nHarmo, Int_t* harmo, Double_t* correlData) +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_t sumHarmo = 0; - for (Int_t i = 0; i < c_nHarmo; i++) { + int sumHarmo = 0; + for (int i = 0; i < c_nHarmo; i++) { sumHarmo += harmo[i]; } if (sumHarmo != 0) { - printf("\nOups, this correlator is not isotropic(sum = %d). Bye\n", sumHarmo); + LOGF(error, "\nOups, this correlator is not isotropic(sum = %d). Bye\n", sumHarmo); return; } switch (c_nPart) { case 2: { - Int_t harmonicsTwoNum[2] = {harmo[0], harmo[1]}; - Int_t harmonicsTwoDen[2] = {0, 0}; + int harmonicsTwoNum[2] = {harmo[0], harmo[1]}; + int harmonicsTwoDen[2] = {0, 0}; if (!fCorrelDenoms[1]) { - fCorrelDenoms[1] = Recursion(2, harmonicsTwoDen).Re(); + fCorrelDenoms[1] = recursion(2, harmonicsTwoDen).Re(); } - TComplex twoRecursion = Recursion(2, harmonicsTwoNum) / fCorrelDenoms[1]; + TComplex twoRecursion = recursion(2, harmonicsTwoNum) / fCorrelDenoms[1]; correlData[0] = twoRecursion.Re(); // correlData[1] = fCorrelDenoms[1]; // weight correlData[2] = twoRecursion.Im(); // } break; case 3: { - Int_t harmonicsThreeNum[3] = {harmo[0], harmo[1], harmo[2]}; - Int_t harmonicsThreeDen[3] = {0, 0, 0}; + int harmonicsThreeNum[3] = {harmo[0], harmo[1], harmo[2]}; + int harmonicsThreeDen[3] = {0, 0, 0}; if (!fCorrelDenoms[2]) { - fCorrelDenoms[2] = Recursion(3, harmonicsThreeDen).Re(); + fCorrelDenoms[2] = recursion(3, harmonicsThreeDen).Re(); } - TComplex threeRecursion = Recursion(3, harmonicsThreeNum) / fCorrelDenoms[2]; + TComplex threeRecursion = recursion(3, harmonicsThreeNum) / fCorrelDenoms[2]; correlData[0] = threeRecursion.Re(); // correlData[1] = fCorrelDenoms[2]; // weight correlData[2] = threeRecursion.Im(); // } break; case 4: { - Int_t harmonicsFourNum[4] = {harmo[0], harmo[1], harmo[2], harmo[3]}; - Int_t harmonicsFourDen[4] = {0, 0, 0, 0}; + 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(); + fCorrelDenoms[3] = recursion(4, harmonicsFourDen).Re(); } - TComplex fourRecursion = Recursion(4, harmonicsFourNum) / fCorrelDenoms[3]; + TComplex fourRecursion = recursion(4, harmonicsFourNum) / fCorrelDenoms[3]; correlData[0] = fourRecursion.Re(); // correlData[1] = fCorrelDenoms[3]; // weight correlData[2] = fourRecursion.Im(); // } break; case 5: { - Int_t harmonicsFiveNum[5] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4]}; - Int_t harmonicsFiveDen[5] = {0, 0, 0, 0, 0}; + 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(); + fCorrelDenoms[4] = recursion(5, harmonicsFiveDen).Re(); } - TComplex fiveRecursion = Recursion(5, harmonicsFiveNum) / fCorrelDenoms[4]; + TComplex fiveRecursion = recursion(5, harmonicsFiveNum) / fCorrelDenoms[4]; correlData[0] = fiveRecursion.Re(); // correlData[1] = fCorrelDenoms[4]; // weight correlData[2] = fiveRecursion.Im(); // } break; case 6: { - Int_t harmonicsSixNum[6] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], harmo[5]}; - Int_t harmonicsSixDen[6] = {0, 0, 0, 0, 0, 0}; + 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(); + fCorrelDenoms[5] = recursion(6, harmonicsSixDen).Re(); } - TComplex sixRecursion = Recursion(6, harmonicsSixNum) / fCorrelDenoms[5]; + TComplex sixRecursion = recursion(6, harmonicsSixNum) / fCorrelDenoms[5]; correlData[0] = sixRecursion.Re(); // correlData[1] = fCorrelDenoms[5]; // weight correlData[2] = sixRecursion.Im(); // } break; case 7: { - Int_t harmonicsSevenNum[7] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], harmo[5], harmo[6]}; - Int_t harmonicsSevenDen[7] = {0, 0, 0, 0, 0, 0, 0}; + 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(); + fCorrelDenoms[6] = recursion(7, harmonicsSevenDen).Re(); } - TComplex sevenRecursion = Recursion(7, harmonicsSevenNum) / fCorrelDenoms[6]; + TComplex sevenRecursion = recursion(7, harmonicsSevenNum) / fCorrelDenoms[6]; correlData[0] = sevenRecursion.Re(); // correlData[1] = fCorrelDenoms[6]; // weight correlData[2] = sevenRecursion.Im(); // } break; case 8: { - Int_t harmonicsEightNum[8] = {harmo[0], harmo[1], harmo[2], harmo[3], - harmo[4], harmo[5], harmo[6], harmo[7]}; - Int_t harmonicsEightDen[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + 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(); + fCorrelDenoms[7] = recursion(8, harmonicsEightDen).Re(); } - TComplex eightRecursion = Recursion(8, harmonicsEightNum) / fCorrelDenoms[7]; + TComplex eightRecursion = recursion(8, harmonicsEightNum) / fCorrelDenoms[7]; correlData[0] = eightRecursion.Re(); // correlData[1] = fCorrelDenoms[7]; // weight correlData[2] = eightRecursion.Im(); // } break; case 9: { - Int_t harmonicsNineNum[9] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], - harmo[5], harmo[6], harmo[7], harmo[8]}; - Int_t harmonicsNineDen[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + 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(); + fCorrelDenoms[8] = recursion(9, harmonicsNineDen).Re(); } - TComplex nineRecursion = Recursion(9, harmonicsNineNum) / fCorrelDenoms[8]; + TComplex nineRecursion = recursion(9, harmonicsNineNum) / fCorrelDenoms[8]; correlData[0] = nineRecursion.Re(); correlData[1] = fCorrelDenoms[8]; correlData[2] = nineRecursion.Im(); } break; case 10: { - Int_t harmonicsTenNum[10] = {harmo[0], harmo[1], harmo[2], harmo[3], harmo[4], - harmo[5], harmo[6], harmo[7], harmo[8], harmo[9]}; - Int_t harmonicsTenDen[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + 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(); + fCorrelDenoms[9] = recursion(10, harmonicsTenDen).Re(); } - TComplex tenRecursion = Recursion(10, harmonicsTenNum) / fCorrelDenoms[9]; + TComplex tenRecursion = recursion(10, harmonicsTenNum) / fCorrelDenoms[9]; correlData[0] = tenRecursion.Re(); correlData[1] = fCorrelDenoms[9]; correlData[2] = tenRecursion.Im(); } break; case 12: { - Int_t 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_t harmonicsTwelveDen[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + 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(); + fCorrelDenoms[11] = recursion(12, harmonicsTwelveDen).Re(); } - TComplex twelveRecursion = Recursion(12, harmonicsTwelveNum) / fCorrelDenoms[11]; + TComplex twelveRecursion = recursion(12, harmonicsTwelveNum) / fCorrelDenoms[11]; correlData[0] = twelveRecursion.Re(); correlData[1] = fCorrelDenoms[11]; correlData[2] = twelveRecursion.Im(); } break; case 14: { - Int_t 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_t harmonicsFourteenDen[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + 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(); + fCorrelDenoms[13] = recursion(14, harmonicsFourteenDen).Re(); } - TComplex fourteenRecursion = Recursion(14, harmonicsFourteenNum) / fCorrelDenoms[13]; + TComplex fourteenRecursion = recursion(14, harmonicsFourteenNum) / fCorrelDenoms[13]; correlData[0] = fourteenRecursion.Re(); correlData[1] = fCorrelDenoms[13]; @@ -367,7 +425,7 @@ void FlowJSPCAnalysis::Correlation(Int_t c_nPart, Int_t c_nHarmo, Int_t* harmo, } break; } } -int FlowJSPCAnalysis::GetCentBin(float cValue) +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++) { diff --git a/PWGCF/JCorran/Core/FlowJSPCAnalysis.h b/PWGCF/JCorran/Core/FlowJSPCAnalysis.h index 656e54c8453..ba584d1e1eb 100644 --- a/PWGCF/JCorran/Core/FlowJSPCAnalysis.h +++ b/PWGCF/JCorran/Core/FlowJSPCAnalysis.h @@ -16,7 +16,6 @@ #define PWGCF_JCORRAN_CORE_FLOWJSPCANALYSIS_H_ /* Header files. */ -#include #include #include #include @@ -25,64 +24,54 @@ // O2 headers. // #include "Framework/HistogramRegistry.h" #include "PWGCF/JCorran/Core/JQVectors.h" - -using namespace o2; -using namespace o2::framework; -using namespace std; +#include "CommonConstants/MathConstants.h" class FlowJSPCAnalysis { public: FlowJSPCAnalysis() = default; - void SetHistRegistry(HistogramRegistry* histReg) { mHistRegistry = histReg; } - Int_t GetCentBin(float cValue); + 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_t c_nPart, Int_t c_nHarmo, Int_t* harmo, Double_t* correlData); - void CalculateCorrelators(const Int_t fCentBin); - void FillHistograms(const Int_t fCentBin, Int_t ind, Double_t cNum, Double_t cDenom, Double_t wNum, Double_t wDenom); - TComplex Recursion(int n, int* harmonic, int mult, int skip); - TComplex Q(const Int_t harmN, const Int_t p); - - void CreateHistos() + 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", HistType::kTH1D, {{100, 0., 100.}}, true); - mHistRegistry->add("Centrality_0/fResults", "Numerators and denominators", {HistType::kTProfile, {{24, 0., 24.}}}, true); - mHistRegistry->add("Centrality_0/fCovResults", "Covariance N*D", {HistType::kTProfile, {{48, 0., 48.}}}, true); + 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_t i = 1; i < 8; i++) { + for (uint i = 1; i < 9; i++) { mHistRegistry->addClone("Centrality_0/", Form("Centrality_%u/", i)); } } - void SetCorrSet(Int_t obsInd, Int_t harmo[8]) + void setCorrSet(int obsInd, int harmo[8]) { for (int i = 0; i < 8; i++) { fHarmosArray[obsInd][i] = harmo[i]; } } - void SetFullCorrSet(Int_t harmo[12][8]) + void setFullCorrSet(int harmo[12][8]) { - memcpy(fHarmosArray, harmo, sizeof(Int_t) * 12 * 8); + memcpy(fHarmosArray, harmo, sizeof(int) * 12 * 8); } - private: - const Int_t mNqHarmos = 113; ///< Highest harmo for Q(n,p): (v8*14part)+1. - const Int_t mNqPowers = 15; ///< Max power for Q(n,p): 14part+1. - const JQVectorsT* qvecs; - - HistogramRegistry* mHistRegistry = nullptr; - - Int_t fHarmosArray[12][8]; - - Double_t fCorrelDenoms[14]; - static constexpr std::string_view mCentClasses[] = { + static constexpr std::string_view MCentClasses[] = { "Centrality_0/", "Centrality_1/", "Centrality_2/", @@ -91,8 +80,18 @@ class FlowJSPCAnalysis "Centrality_5/", "Centrality_6/", "Centrality_7/", - "Centrality_8/", - "Centrality_9/"}; + "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); }; diff --git a/PWGCF/JCorran/Core/FlowJSPCObservables.h b/PWGCF/JCorran/Core/FlowJSPCObservables.h index 5bf46f8aec2..bc504fe31fe 100644 --- a/PWGCF/JCorran/Core/FlowJSPCObservables.h +++ b/PWGCF/JCorran/Core/FlowJSPCObservables.h @@ -18,27 +18,23 @@ // O2 headers. // #include "Framework/HistogramRegistry.h" -using namespace o2; -using namespace o2::framework; -using namespace std; - const int maxNrComb = 12; class FlowJSPCObservables { public: FlowJSPCObservables() = default; - Int_t harmonicArray[maxNrComb][8] = {{0}}; + int harmonicArray[maxNrComb][8] = {{0}}; - void SetSPCObservables(Int_t index) + void setSPCObservables(int index) { - // Int_t *harmonicArray = (Int_t*)malloc(sizeof(Int_t)*maxNrComb*8); + // 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_t harmonicArray01[maxNrComb][8] = { + 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}, @@ -52,11 +48,11 @@ class FlowJSPCObservables {0, 2, -3, -3, 4, 0, 0, 0}, {0, 3, 3, -2, -2, -2, 0, 0}}; - memcpy(harmonicArray, harmonicArray01, sizeof(Int_t) * maxNrComb * 8); + memcpy(harmonicArray, harmonicArray01, sizeof(int) * maxNrComb * 8); } break; case 1: { LOGF(info, "Computing four harmonic SPC"); - Int_t harmonicArray02[maxNrComb][8] = { + 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}, @@ -69,11 +65,11 @@ class FlowJSPCObservables {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_t) * maxNrComb * 8); + memcpy(harmonicArray, harmonicArray02, sizeof(int) * maxNrComb * 8); } break; case 3: { LOGF(info, "Computing five and six harmonic SPC"); - Int_t harmonicArray03[maxNrComb][8] = { + 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}, @@ -86,11 +82,10 @@ class FlowJSPCObservables {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_t) * maxNrComb * 8); + memcpy(harmonicArray, harmonicArray03, sizeof(int) * maxNrComb * 8); } break; default: - std::cout << "ERROR: Invalid configuration index. Skipping this element." - << std::endl; + LOGF(error, "ERROR: Invalid configuration index. Skipping this element."); } } diff --git a/PWGCF/JCorran/Core/JCORRANLinkDef.h b/PWGCF/JCorran/Core/JCORRANLinkDef.h index 7cadfacca79..d0e9bef308d 100755 --- a/PWGCF/JCorran/Core/JCORRANLinkDef.h +++ b/PWGCF/JCorran/Core/JCORRANLinkDef.h @@ -21,5 +21,6 @@ #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 c3ca3595718..4c3b01adeca 100644 --- a/PWGCF/JCorran/Core/JFFlucAnalysis.cxx +++ b/PWGCF/JCorran/Core/JFFlucAnalysis.cxx @@ -12,13 +12,16 @@ /// \author Jasper Parkkila (jparkkil@cern.ch) /// \since Sep 2022 -#include +#include "JFFlucAnalysis.h" + #include +#include + #include -#include "JFFlucAnalysis.h" JFFlucAnalysis::JFFlucAnalysis() : TNamed(), fVertex(0), + fAvgInvariantMass(0.0f), fCent(0), fImpactParameter(-1), subeventMask(kSubEvent_A | kSubEvent_B), @@ -32,6 +35,7 @@ JFFlucAnalysis::JFFlucAnalysis() : TNamed(), //________________________________________________________________________ JFFlucAnalysis::JFFlucAnalysis(const char* /*name*/) : TNamed(), fVertex(0), + fAvgInvariantMass(0.0f), fCent(0), fImpactParameter(-1), subeventMask(kSubEvent_A | kSubEvent_B), @@ -45,6 +49,7 @@ JFFlucAnalysis::JFFlucAnalysis(const char* /*name*/) : TNamed(), //________________________________________________________________________ JFFlucAnalysis::JFFlucAnalysis(const JFFlucAnalysis& a) : TNamed(a), fVertex(a.fVertex), + fAvgInvariantMass(a.fAvgInvariantMass), fCent(a.fCent), fImpactParameter(a.fImpactParameter), subeventMask(a.subeventMask), @@ -113,6 +118,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 @@ -121,9 +133,26 @@ 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); } + +TComplex JFFlucAnalysis::TwoDiff(int n1, int n2) +{ +#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); +} + +#undef dp +#undef dQ +#undef dq #undef C //________________________________________________________________________ @@ -136,7 +165,7 @@ void JFFlucAnalysis::UserExec(Option_t* /*popt*/) // NOLINT(readability/casting) for (UInt_t i = 0; i < 2; ++i) { if ((subeventMask & (1 << i)) == 0) continue; - decltype(pqvecs->QvectorQCgap[i])& Qa = pqvecs->QvectorQCgap[i]; + 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(); @@ -203,11 +232,11 @@ void JFFlucAnalysis::UserExec(Option_t* /*popt*/) // NOLINT(readability/casting) // 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, ih, ik, 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++) { Double_t vn2_vn2 = ncorr2[ih][ik][ihh][ikk] / ref_2Np[ik + ikk - 1]; - phs[HIST_THN_SPARSE_VN_VN]->Fill(fCent, ih, ik, ihh, ikk, vn2_vn2, ebe_2Np_weight[ik + ikk - 1]); + phs[HIST_THN_SPARSE_VN_VN]->Fill(fCent, fAvgInvariantMass, ih, ik, ihh, ikk, vn2_vn2, ebe_2Np_weight[ik + ikk - 1]); } } } @@ -246,41 +275,41 @@ void JFFlucAnalysis::UserExec(Option_t* /*popt*/) // NOLINT(readability/casting) 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, V4V2starv2_2.Re()); - pht[HIST_THN_V4V2starv2_4]->Fill(fCent, V4V2starv2_4.Re()); - pht[HIST_THN_V4V2star_2]->Fill(fCent, V4V2star_2.Re(), ebe_3p_weight); // added 2015.3.18 - pht[HIST_THN_V5V2starV3starv2_2]->Fill(fCent, V5V2starV3starv2_2.Re()); - pht[HIST_THN_V5V2starV3star]->Fill(fCent, V5V2starV3star.Re(), ebe_3p_weight); - pht[HIST_THN_V5V2starV3startv3_2]->Fill(fCent, V5V2starV3startv3_2.Re()); - pht[HIST_THN_V6V2star_3]->Fill(fCent, V6V2star_3.Re(), ebe_4p_weightB); - pht[HIST_THN_V6V3star_2]->Fill(fCent, V6V3star_2.Re(), ebe_3p_weight); - pht[HIST_THN_V7V2star_2V3star]->Fill(fCent, V7V2star_2V3star.Re(), ebe_4p_weightB); + 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, nV4V2star_2.Re(), ebe_3p_weight); // added 2015.6.10 - pht[HIST_THN_V5V2starV3star]->Fill(fCent, nV5V2starV3star.Re(), ebe_3p_weight); - pht[HIST_THN_V6V3star_2]->Fill(fCent, nV6V3star_2.Re(), ebe_3p_weight); + 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.. - pht[HIST_THN_nV4V4V2V2]->Fill(fCent, nV4V4V2V2.Re(), ebe_2Np_weight[1]); - pht[HIST_THN_nV3V3V2V2]->Fill(fCent, 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]); - pht[HIST_THN_nV5V5V2V2]->Fill(fCent, nV5V5V2V2.Re(), ebe_2Np_weight[1]); - pht[HIST_THN_nV5V5V3V3]->Fill(fCent, nV5V5V3V3.Re(), ebe_2Np_weight[1]); - pht[HIST_THN_nV4V4V3V3]->Fill(fCent, 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 - pht[HIST_THN_V8V2starV3star_2]->Fill(fCent, V8V2starV3star_2.Re(), ebe_4p_weightB); - pht[HIST_THN_V8V2star_4]->Fill(fCent, V8V2star_4.Re()); // 5p weight - pht[HIST_THN_V6V2star_3]->Fill(fCent, nV6V2star_3.Re(), ebe_4p_weightB); - pht[HIST_THN_V7V2star_2V3star]->Fill(fCent, nV7V2star_2V3star.Re(), ebe_4p_weightB); - pht[HIST_THN_V8V2starV3star_2]->Fill(fCent, nV8V2starV3star_2.Re(), ebe_4p_weightB); - - pht[HIST_THN_V6V2starV4star]->Fill(fCent, V6V2starV4star.Re(), ebe_3p_weight); - pht[HIST_THN_V7V2starV5star]->Fill(fCent, V7V2starV5star.Re(), ebe_3p_weight); - pht[HIST_THN_V7V3starV4star]->Fill(fCent, V7V3starV4star.Re(), ebe_3p_weight); - pht[HIST_THN_V6V2starV4star]->Fill(fCent, nV6V2starV4star.Re(), ebe_3p_weight); - pht[HIST_THN_V7V2starV5star]->Fill(fCent, nV7V2starV5star.Re(), ebe_3p_weight); - pht[HIST_THN_V7V3starV4star]->Fill(fCent, 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) { @@ -289,24 +318,26 @@ void JFFlucAnalysis::UserExec(Option_t* /*popt*/) // NOLINT(readability/casting) 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, ih, sctwoGap.Re(), event_weight_two_gap); + 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; if (flags & kFlucEbEWeighting) { - event_weight_four = Four(0, 0, 0, 0).Re(); - event_weight_two = Two(0, 0).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 : 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, ih, ihh, scfour.Re(), event_weight_four); + 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(); - pht[HIST_THN_SC_with_QC_2corr]->Fill(fCent, ih, sctwo.Re(), event_weight_two); + 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); } } diff --git a/PWGCF/JCorran/Core/JFFlucAnalysis.h b/PWGCF/JCorran/Core/JFFlucAnalysis.h index cd5fdf5e515..b728c809173 100644 --- a/PWGCF/JCorran/Core/JFFlucAnalysis.h +++ b/PWGCF/JCorran/Core/JFFlucAnalysis.h @@ -15,13 +15,16 @@ #ifndef PWGCF_JCORRAN_CORE_JFFLUCANALYSIS_H_ #define PWGCF_JCORRAN_CORE_JFFLUCANALYSIS_H_ -#include #include "JQVectors.h" + #include -#include #include #include #include +#include + +#include +#include class JFFlucAnalysis : public TNamed { @@ -37,6 +40,8 @@ class JFFlucAnalysis : public TNamed 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*); @@ -44,6 +49,7 @@ class JFFlucAnalysis : public TNamed inline float GetEventCentrality() const { return fCent; } inline void SetEventImpactParameter(float ip) { fImpactParameter = ip; } inline void SetEventVertex(float zvertex) { fVertex = zvertex; } + inline void SetAverageInvariantMass(float mass) { fAvgInvariantMass = mass; } enum SubEvent { kSubEvent_A = 0x1, kSubEvent_B = 0x2 @@ -58,7 +64,6 @@ class JFFlucAnalysis : public TNamed 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, @@ -95,6 +100,7 @@ class JFFlucAnalysis : public TNamed enum HIST_THN_SPARSE { HIST_THN_SPARSE_VN, HIST_THN_SPARSE_VN_VN, + HIST_THN_SPARSE_MULTCORR, HIST_THN_SPARSE_COUNT }; enum { @@ -123,6 +129,7 @@ class JFFlucAnalysis : public TNamed kK4, nKL }; // order using JQVectorsT = JQVectors; + TComplex Q(const JQVectorsT& qvecs, int n, int p); inline void SetJQVectors(const JQVectorsT* _pqvecs) { pqvecs = _pqvecs; @@ -139,44 +146,59 @@ class JFFlucAnalysis : public TNamed template using hasWeightEff = decltype(std::declval().weightEff()); template - using hasType = decltype(std::declval().particleType()); + using hasSign = decltype(std::declval().sign()); + template + using hasMultSet = decltype(std::declval().multiplicities()); template - inline void FillQA(JInputClass& inputInst, UInt_t type = 0) + inline void FillQA(JInputClass& inputInst, UInt_t type = 0u) { - ph1[HIST_TH1_CENTRALITY]->Fill(fCent); - ph1[HIST_TH1_IMPACTPARAM]->Fill(fImpactParameter); + if (type == 0u) { + ph1[HIST_TH1_CENTRALITY]->Fill(fCent); + ph1[HIST_TH1_ZVERTEX]->Fill(fVertex); + ph1[HIST_TH1_IMPACTPARAM]->Fill(fImpactParameter); + } for (auto& track : inputInst) { Double_t corrInv = 1.0; using JInputClassIter = typename JInputClass::iterator; if constexpr (std::experimental::is_detected::value) - corrInv /= track.weightEff(); - pht[HIST_THN_PTETA]->Fill(fCent, track.pt(), track.eta(), corrInv); + corrInv *= track.weightEff(); + 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(); - pht[HIST_THN_PHIETA]->Fill(fCent, track.phi(), track.eta(), corrInv); - if constexpr (std::experimental::is_detected::value) - type = track.particleType(); pht[HIST_THN_PHIETAZ]->Fill(fCent, static_cast(type), track.phi(), track.eta(), fVertex, corrInv); } + } - ph1[HIST_TH1_ZVERTEX]->Fill(fVertex); + template + inline void FillMultSet(JEventClass& event) + { + // + if constexpr (std::experimental::is_detected::value) { + // need to convert to vec of doubles since THnSparse has no way to fill vec of floats directly + std::vector v(event.multiplicities().begin(), event.multiplicities().end()); + phs[HIST_THN_SPARSE_MULTCORR]->Fill(v.data()); + } } -#define kcNH kH6 // max second dimension + 1 +#define kcNH kH4 // max second dimension + 1 protected: - Float_t fVertex; //! - Float_t fCent; //! - Float_t fImpactParameter; //! - UInt_t subeventMask; //! - UInt_t flags; //! + Float_t fVertex; //! + Float_t fAvgInvariantMass; //! + Float_t fCent; //! + Float_t fImpactParameter; //! + UInt_t subeventMask; //! + UInt_t flags; //! const JQVectorsT* pqvecs; //! const JQVectorsT* pqvecsRef; //! TH1* ph1[HIST_TH1_COUNT]; //! - THn* pht[HIST_THN_COUNT]; //! + THnSparse* pht[HIST_THN_COUNT]; //! THnSparse* phs[HIST_THN_SPARSE_COUNT]; //! ClassDef(JFFlucAnalysis, 1) diff --git a/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.cxx b/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.cxx index 181dbe6a05f..0439b5e2931 100644 --- a/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.cxx +++ b/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.cxx @@ -12,41 +12,58 @@ /// \since Sep 2024 #include "JFFlucAnalysisO2Hist.h" -#include -#include + +#include "PWGCF/DataModel/CorrelationsDerived.h" + #include "CommonConstants/MathConstants.h" +#include +#include + using namespace o2; +using namespace o2::framework; -JFFlucAnalysisO2Hist::JFFlucAnalysisO2Hist(HistogramRegistry& registry, AxisSpec& axisMultiplicity, AxisSpec& phiAxis, AxisSpec& etaAxis, AxisSpec& zvtAxis, const TString& folder) : JFFlucAnalysis() +JFFlucAnalysisO2Hist::JFFlucAnalysisO2Hist(HistogramRegistry& registry, AxisSpec& axisMultiplicity, AxisSpec& phiAxis, AxisSpec& etaAxis, AxisSpec& zvtAxis, AxisSpec& ptAxis, AxisSpec& massAxis, AxisSpec& vnAxis, AxisSpec& fourAxisSC, AxisSpec& mixedAxis, AxisSpec& twoAxisSC, uint16_t multCorrMask, 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(); - // - // TODO: these shall be configurable - std::vector ptBinning = {0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 10.0}; - AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/c)"}; + + if (multCorrMask != 0) { + std::vector multAxes; + if (multCorrMask & aod::cfmultset::CentFT0C) + multAxes.emplace_back(100, 0, 100, "FT0C centrality"); + if (multCorrMask & aod::cfmultset::MultFV0A) + multAxes.emplace_back(100, 0, 100000, "V0A multiplicity"); + if (multCorrMask & aod::cfmultset::MultNTracksPV) + multAxes.emplace_back(100, 0, 1000, "Nch PV"); + if (multCorrMask & aod::cfmultset::MultNTracksGlobal) + multAxes.emplace_back(100, 0, 1000, "Nch Global"); + phs[HIST_THN_SPARSE_MULTCORR] = std::get>(registry.add(Form("%s/multCorrelations", folder.Data()), "multiplicity/centrality correlations", {HistType::kTHnSparseF, multAxes})).get(); + } else { + phs[HIST_THN_SPARSE_MULTCORR] = 0; + } + + 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::kTHnF, {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", {HistType::kTHnF, {axisMultiplicity, ptAxis, etaAxis}})).get(); - pht[HIST_THN_PHIETA] = std::get>(registry.add(Form("%s/h_phieta", folder.Data()), "(corrected) multiplicity/centrality, phi, eta", {HistType::kTHnF, {axisMultiplicity, phiAxis, etaAxis}})).get(); + pht[HIST_THN_PHIETAZ] = std::get>(registry.add(Form("%s/h_phietaz", folder.Data()), "(corrected) 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(); 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::kTHnF, {axisMultiplicity, 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::kTHnF, {axisMultiplicity, 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::kTHnF, {axisMultiplicity, hAxis, {2048, -0.1, 0.1, "correlation"}}})).get(); + 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, fourAxisSC}})).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, twoAxisSC}})).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, twoAxisSC}})).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::kTHnF, {axisMultiplicity, {2048, -3.0, 3.0, "correlation"}}})).get(); + pht[i] = std::get>(registry.add(Form("%s/h_corrC%02u", folder.Data(), i - HIST_THN_V4V2star_2), "correlator", {HistType::kTHnSparseF, {axisMultiplicity, massAxis, mixedAxis}})).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, 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, hAxis, kAxis, hAxis, kAxis, vnAxis}})).get(); + 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(); + if (phs[i]) + phs[i]->Sumw2(); } JFFlucAnalysisO2Hist::~JFFlucAnalysisO2Hist() diff --git a/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.h b/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.h index 2e6a593a062..3bc0a1a225e 100644 --- a/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.h +++ b/PWGCF/JCorran/Core/JFFlucAnalysisO2Hist.h @@ -15,15 +15,13 @@ #define PWGCF_JCORRAN_CORE_JFFLUCANALYSISO2HIST_H_ #include "JFFlucAnalysis.h" -#include "Framework/HistogramRegistry.h" -using namespace o2; -using namespace o2::framework; +#include "Framework/HistogramRegistry.h" class JFFlucAnalysisO2Hist : public JFFlucAnalysis { public: - JFFlucAnalysisO2Hist(HistogramRegistry&, AxisSpec&, AxisSpec&, AxisSpec&, AxisSpec&, const TString&); + JFFlucAnalysisO2Hist(o2::framework::HistogramRegistry&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, o2::framework::AxisSpec&, uint16_t, const TString&); ~JFFlucAnalysisO2Hist(); }; diff --git a/PWGCF/JCorran/Core/JQVectors.h b/PWGCF/JCorran/Core/JQVectors.h index 884840010bf..01693ae6073 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,11 +81,10 @@ 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) - tf /= track.weightEff(); + tf *= track.weightEff(); } } } diff --git a/PWGCF/JCorran/Tasks/CMakeLists.txt b/PWGCF/JCorran/Tasks/CMakeLists.txt index bb123a2d5a6..465083509d0 100644 --- a/PWGCF/JCorran/Tasks/CMakeLists.txt +++ b/PWGCF/JCorran/Tasks/CMakeLists.txt @@ -28,3 +28,18 @@ 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 index 914dc37b4ab..31edc2a7c3d 100644 --- a/PWGCF/JCorran/Tasks/flowJNUACreation.cxx +++ b/PWGCF/JCorran/Tasks/flowJNUACreation.cxx @@ -93,10 +93,10 @@ struct flowJNUACreation { void init(InitContext const&) { // Add histomanager here - histManager.SetHistRegistryQA(&qaHistRegistry); - histManager.SetDebugLog(false); - histManager.SetObtainNUA(true); - histManager.CreateHistQA(); + histManager.setHistRegistryQA(&qaHistRegistry); + histManager.setDebugLog(false); + histManager.setObtainNUA(true); + histManager.createHistQA(); // Add CCDB access here ccdb->setURL(cfgCCDB.cfgURL); @@ -131,13 +131,13 @@ struct flowJNUACreation { if (cent < 0. || cent > 70.) { return; } - Int_t cBin = histManager.GetCentBin(cent); + Int_t cBin = histManager.getCentBin(cent); int nTracks = tracks.size(); for (auto& track : tracks) { - histManager.FillTrackQA<1>(track, cBin, 1., 1., coll.posZ()); + histManager.fillTrackQA<1>(track, cBin, 1., 1., coll.posZ()); } - histManager.FillEventQA<1>(coll, cBin, cent, nTracks); + histManager.fillEventQA<1>(coll, cBin, cent, nTracks); LOGF(info, "Collision analysed. Next..."); } diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index 3a533674f14..2ce4568348f 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -25,7 +25,6 @@ #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -#include "CCDB/BasicCCDBManager.h" #include "Framework/HistogramRegistry.h" // O2 Physics headers. // @@ -36,6 +35,8 @@ #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" @@ -50,24 +51,24 @@ using MyCollisions = soa::Join; -using MyTracks = soa::Join; +using MyTracks = soa::Join; struct flowJSPCAnalysis { - HistogramRegistry SPCHistograms{"SPCResults", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + 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; + FlowJSPCObservables spcObservables; // Set Configurables here - Configurable cfgUseNUA{"cfgUseNUA", false, "Use NUA correction"}; - Configurable cfgUseNUE{"cfgUseNUE", false, "Use NUE correction"}; Configurable cfgFillQA{"cfgFillQA", true, "Fill QA plots"}; - Configurable cfgWhichSPC{"cfgWhichSPC", 0, "Which SPC observables to compute."}; + Configurable cfgWhichSPC{"cfgWhichSPC", 0, "Which SPC observables to compute."}; struct : ConfigurableGroup { Configurable cfgPtMin{"cfgPtMin", 0.2f, "Minimum pT used for track selection."}; @@ -75,107 +76,89 @@ struct flowJSPCAnalysis { Configurable cfgEtaMax{"cfgEtaMax", 0.8f, "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", 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; - // Set the access to the CCDB for the NUA/NUE weights. - struct : ConfigurableGroup { - Configurable cfgUseCCDB{"cfgUseCCDB", true, "Use CCDB for NUA/NUE corrections."}; - 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); + 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); + spcAnalysis.setHistRegistry(&spcHistograms); + spcAnalysis.createHistos(); - histManager.SetHistRegistryQA(&qaHistRegistry); - histManager.SetDebugLog(false); - histManager.CreateHistQA(); + spcObservables.setSPCObservables(cfgWhichSPC); + spcAnalysis.setFullCorrSet(spcObservables.harmonicArray); - ///////////////////// - - ccdb->setURL(cfgCCDB.cfgURL); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setCreatedNotAfter(cfgCCDB.cfgTime.value); + histManager.setHistRegistryQA(&qaHistRegistry); + histManager.setDebugLog(false); + histManager.createHistQA(); } - void process(soa::Filtered::iterator const& coll, soa::Filtered const& tracks) + 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 = -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.) { + float cent = collision.multiplicity(); + if (cent < 0. || cent > 100.) { return; } - Int_t cBin = histManager.GetCentBin(cent); - SPCHistograms.fill(HIST("FullCentrality"), cent); + int cBin = histManager.getCentBin(cent); + spcHistograms.fill(HIST("FullCentrality"), cent); int nTracks = tracks.size(); - - for (auto& track : tracks) { - if (cfgFillQA) - histManager.FillTrackQA<1>(track, cBin, coll.posZ()); - - if (cfgUseNUE) { - ; - } - if (cfgUseNUA) { - ; + 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>(coll, cBin, cent, nTracks); + histManager.fillEventQA<1>(collision, cBin, cent, nTracks); jqvecs.Calculate(tracks, 0.0, cfgTrackCuts.cfgEtaMax); - spcAnalysis.SetQvectors(&jqvecs); - spcAnalysis.CalculateCorrelators(cBin); + spcAnalysis.setQvectors(&jqvecs); + spcAnalysis.calculateCorrelators(cBin); + } - LOGF(info, "Collision analysed. Next..."); + 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) 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..452ddd72abb --- /dev/null +++ b/PWGCF/JCorran/Tasks/jEPFlowAnalysis.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. + +/// \author Maxim Virta (maxim.virta@cern.ch) +/// \brief flow measurement with q-vectors +/// \file jEPFlowAnalysis.cxx +/// \since Jul 2024 + +#include "FlowJHistManager.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace std; + +using MyCollisions = soa::Join; +using MyCollisionsWithSC = soa::Join; +using MyTracks = aod::Tracks; + +struct jEPFlowAnalysis { + + HistogramRegistry epFlowHistograms{"EPFlow", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + EventPlaneHelper helperEP; + FlowJHistManager histManager; + bool debug = kFALSE; + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + // Set Configurables here + struct : ConfigurableGroup { + Configurable cfgPtMin{"cfgPtMin", 0.2f, "Minimum pT used for track selection."}; + Configurable cfgEtaMax{"cfgEtaMax", 1.f, "Maximum eta used for track selection."}; + } cfgTrackCuts; + + Configurable cfgAddEvtSel{"cfgAddEvtSel", true, "event selection"}; + Configurable cfgEvtSel{"cfgEvtSel", 0, "Event selection flags\n0: Sel8\n1: Sel8+kIsGoodZvtxFT0vsPV+kNoSameBunchPileup\n2: Sel8+kIsGoodZvtxFT0vsPV+kNoSameBunchPileup+kNoCollInTimeRangeStandard\n3: Sel8+kNoSameBunchPileup"}; + 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 cfgnTotalSystem{"cfgnTotalSystem", 7, "Total number of detectors in qVectorsTable"}; + Configurable cfgnMode{"cfgnMode", 1, "the number of modulations"}; + + Configurable cfgShiftCorr{"cfgShiftCorr", false, "additional shift correction"}; + Configurable cfgShiftPath{"cfgShiftPath", "Users/j/junlee/Qvector/QvecCalib/Shift", "Path for Shift"}; + Configurable cfgVertexZ{"cfgVertexZ", 10.0, "Maximum vertex Z 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 cfgAxisCent{"cfgAxisCent", {100, 0, 100}, ""}; + ConfigurableAxis cfgAxisPt{"cfgAxisPt", {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.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 10.0, 12.0, 15.0, 30.0, 50.0, 70.0, 100.0}, ""}; + ConfigurableAxis cfgAxisCos{"cfgAxisCos", {102, -1.02, 1.02}, ""}; + ConfigurableAxis cfgAxisQvec{"cfgAxisQvec", {200, -5.0, 5.0}, ""}; + + Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax); + + int detId; + int refAId; + int refBId; + int harmInd; + + int currentRunNumber = -999; + int lastRunNumber = -999; + + std::vector shiftprofile{}; + std::string fullCCDBShiftCorrPath; + + 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); + + AxisSpec axisMod{cfgnMode, 2., cfgnMode + 2.}; + AxisSpec axisEvtPl{360, -constants::math::PI * 1.1, constants::math::PI * 1.1}; + AxisSpec axisVertex{150, -12.5, 12.5}; + + AxisSpec axisCent{cfgAxisCent, "cent"}; + AxisSpec axisPt{cfgAxisPt, "pT"}; + AxisSpec axisCos{cfgAxisCos, "cos"}; + AxisSpec axisQvec{cfgAxisQvec, "Qvec"}; + + epFlowHistograms.add("EpDet", "", {HistType::kTH3F, {axisMod, axisCent, axisEvtPl}}); + epFlowHistograms.add("EpRefA", "", {HistType::kTH3F, {axisMod, axisCent, axisEvtPl}}); + epFlowHistograms.add("EpRefB", "", {HistType::kTH3F, {axisMod, axisCent, axisEvtPl}}); + + epFlowHistograms.add("EpResDetRefA", "", {HistType::kTH3F, {axisMod, axisCent, axisEvtPl}}); + epFlowHistograms.add("EpResDetRefB", "", {HistType::kTH3F, {axisMod, axisCent, axisEvtPl}}); + epFlowHistograms.add("EpResRefARefB", "", {HistType::kTH3F, {axisMod, axisCent, axisEvtPl}}); + + epFlowHistograms.add("vncos", "", {HistType::kTHnSparseF, {axisMod, axisCent, axisPt, axisCos}}); + epFlowHistograms.add("vnsin", "", {HistType::kTHnSparseF, {axisMod, axisCent, axisPt, axisCos}}); + + epFlowHistograms.add("EpResQvecDetRefAxx", "", {HistType::kTH3F, {axisMod, axisCent, axisQvec}}); + epFlowHistograms.add("EpResQvecDetRefAxy", "", {HistType::kTH3F, {axisMod, axisCent, axisQvec}}); + epFlowHistograms.add("EpResQvecDetRefBxx", "", {HistType::kTH3F, {axisMod, axisCent, axisQvec}}); + epFlowHistograms.add("EpResQvecDetRefBxy", "", {HistType::kTH3F, {axisMod, axisCent, axisQvec}}); + epFlowHistograms.add("EpResQvecRefARefBxx", "", {HistType::kTH3F, {axisMod, axisCent, axisQvec}}); + epFlowHistograms.add("EpResQvecRefARefBxy", "", {HistType::kTH3F, {axisMod, axisCent, axisQvec}}); + + epFlowHistograms.add("SPvnxx", "", {HistType::kTHnSparseF, {axisMod, axisCent, axisPt, axisQvec}}); + epFlowHistograms.add("SPvnxy", "", {HistType::kTHnSparseF, {axisMod, axisCent, axisPt, axisQvec}}); + + epFlowHistograms.add("hCentrality", "", {HistType::kTH1F, {axisCent}}); + epFlowHistograms.add("hVertex", "", {HistType::kTH1F, {axisVertex}}); + } + + void processWithSC(MyCollisionsWithSC::iterator const& coll, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + { + if (cfgAddEvtSel) { + if (std::abs(coll.posZ()) > cfgVertexZ) + return; + switch (cfgEvtSel) { + case 0: // Sel8 + if (!coll.sel8()) + return; + break; + case 1: // PbPb standard + if (!coll.sel8() || !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + case 2: // PbPb with pileup + if (!coll.sel8() || !coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) || + !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + case 3: // Small systems (OO, NeNe, pp) + if (!coll.sel8() || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + default: + LOGF(warning, "Event selection flag was not found, continuing without basic event selections!\n"); + } + // Check occupancy + if (coll.trackOccupancyInTimeRange() > cfgMaxOccupancy || coll.trackOccupancyInTimeRange() < cfgMinOccupancy) + return; + } + + float cent = coll.cent(); + epFlowHistograms.fill(HIST("hCentrality"), cent); + epFlowHistograms.fill(HIST("hVertex"), coll.posZ()); + float eps[3] = {0.}; + + if (coll.qvecAmp()[detId] < 1e-5 || coll.qvecAmp()[refAId] < 1e-5 || coll.qvecAmp()[refBId] < 1e-5) + return; + + for (int i = 0; i < cfgnMode; i++) { // loop over different harmonic orders + harmInd = cfgnTotalSystem * i; // harmonic index to access corresponding Q-vector as all Q-vectors are in same vector + eps[0] = helperEP.GetEventPlane(coll.qvecShiftedRe()[detId + harmInd], coll.qvecShiftedIm()[detId + harmInd], i + 2); + eps[1] = helperEP.GetEventPlane(coll.qvecShiftedRe()[refAId + harmInd], coll.qvecShiftedIm()[refAId + harmInd], i + 2); + eps[2] = helperEP.GetEventPlane(coll.qvecShiftedRe()[refBId + harmInd], coll.qvecShiftedIm()[refBId + harmInd], i + 2); + + float resNumA = helperEP.GetResolution(eps[0], eps[1], i + 2); + float resNumB = helperEP.GetResolution(eps[0], eps[2], i + 2); + float resDenom = helperEP.GetResolution(eps[1], eps[2], i + 2); + + epFlowHistograms.fill(HIST("EpDet"), i + 2, cent, eps[0]); + epFlowHistograms.fill(HIST("EpRefA"), i + 2, cent, eps[1]); + epFlowHistograms.fill(HIST("EpRefB"), i + 2, cent, eps[2]); + + epFlowHistograms.fill(HIST("EpResDetRefA"), i + 2, cent, resNumA); + epFlowHistograms.fill(HIST("EpResDetRefB"), i + 2, cent, resNumB); + epFlowHistograms.fill(HIST("EpResRefARefB"), i + 2, cent, resDenom); + + epFlowHistograms.fill(HIST("EpResQvecDetRefAxx"), i + 2, cent, coll.qvecShiftedRe()[detId + harmInd] * coll.qvecShiftedRe()[refAId + harmInd] + coll.qvecShiftedIm()[detId + harmInd] * coll.qvecShiftedIm()[refAId + harmInd]); + epFlowHistograms.fill(HIST("EpResQvecDetRefAxy"), i + 2, cent, coll.qvecShiftedRe()[refAId + harmInd] * coll.qvecShiftedIm()[detId + harmInd] - coll.qvecShiftedRe()[detId + harmInd] * coll.qvecShiftedIm()[refAId + harmInd]); + epFlowHistograms.fill(HIST("EpResQvecDetRefBxx"), i + 2, cent, coll.qvecShiftedRe()[detId + harmInd] * coll.qvecShiftedRe()[refBId + harmInd] + coll.qvecShiftedIm()[detId + harmInd] * coll.qvecShiftedIm()[refBId + harmInd]); + epFlowHistograms.fill(HIST("EpResQvecDetRefBxy"), i + 2, cent, coll.qvecShiftedRe()[refBId + harmInd] * coll.qvecShiftedIm()[detId + harmInd] - coll.qvecShiftedRe()[detId + harmInd] * coll.qvecShiftedIm()[refBId + harmInd]); + epFlowHistograms.fill(HIST("EpResQvecRefARefBxx"), i + 2, cent, coll.qvecShiftedRe()[refAId + harmInd] * coll.qvecShiftedRe()[refBId + harmInd] + coll.qvecShiftedIm()[refAId + harmInd] * coll.qvecShiftedIm()[refBId + harmInd]); + epFlowHistograms.fill(HIST("EpResQvecRefARefBxy"), i + 2, cent, coll.qvecShiftedRe()[refBId + harmInd] * coll.qvecShiftedIm()[refAId + harmInd] - coll.qvecShiftedRe()[refAId + harmInd] * coll.qvecShiftedIm()[refBId + harmInd]); + + float weight = 1.0; + + for (const auto& track : tracks) { + float vn = std::cos((i + 2) * (track.phi() - eps[0])); + float vnSin = std::sin((i + 2) * (track.phi() - eps[0])); + + epFlowHistograms.fill(HIST("vncos"), i + 2, cent, track.pt(), vn * weight); + epFlowHistograms.fill(HIST("vnsin"), i + 2, cent, track.pt(), vnSin * weight); + + epFlowHistograms.fill(HIST("SPvnxx"), i + 2, cent, track.pt(), (std::cos(track.phi() * static_cast(i + 2)) * coll.qvecShiftedRe()[detId + harmInd] + std::sin(track.phi() * static_cast(i + 2)) * coll.qvecShiftedIm()[detId + harmInd]) * weight); + epFlowHistograms.fill(HIST("SPvnxy"), i + 2, cent, track.pt(), (std::sin(track.phi() * static_cast(i + 2)) * coll.qvecShiftedRe()[detId + harmInd] - std::cos(track.phi() * static_cast(i + 2)) * coll.qvecShiftedIm()[detId + harmInd]) * weight); + } + } + } + PROCESS_SWITCH(jEPFlowAnalysis, processWithSC, "process with shift-corrected qvectors", false); + + void processDefault(MyCollisions::iterator const& coll, soa::Filtered const& tracks, aod::BCsWithTimestamps const&) + { + if (cfgAddEvtSel) { + if (std::abs(coll.posZ()) > cfgVertexZ) + return; + switch (cfgEvtSel) { + case 0: // Sel8 + if (!coll.sel8()) + return; + break; + case 1: // PbPb standard + if (!coll.sel8() || !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + case 2: // PbPb with pileup + if (!coll.sel8() || !coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) || + !coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + case 3: // Small systems (OO, NeNe, pp) + if (!coll.sel8() || !coll.selection_bit(aod::evsel::kNoSameBunchPileup)) + return; + break; + default: + LOGF(warning, "Event selection flag was not found, continuing without basic event selections!\n"); + } + // Check occupancy + if (coll.trackOccupancyInTimeRange() > cfgMaxOccupancy || coll.trackOccupancyInTimeRange() < cfgMinOccupancy) + return; + } + + float cent = coll.cent(); + epFlowHistograms.fill(HIST("hCentrality"), cent); + epFlowHistograms.fill(HIST("hVertex"), coll.posZ()); + float eps[3] = {0.}; + float qx_shifted[3] = {0.}; + float qy_shifted[3] = {0.}; + + if (cfgShiftCorr) { + auto bc = coll.bc_as(); + currentRunNumber = bc.runNumber(); + if (currentRunNumber != lastRunNumber) { + shiftprofile.clear(); + for (int i = 0; i < cfgnMode; i++) { + fullCCDBShiftCorrPath = cfgShiftPath; + fullCCDBShiftCorrPath += "/v"; + fullCCDBShiftCorrPath += std::to_string(i + 2); + auto objshift = ccdb->getForTimeStamp(fullCCDBShiftCorrPath, bc.timestamp()); + shiftprofile.push_back(objshift); + } + lastRunNumber = currentRunNumber; + } + } + + if (coll.qvecAmp()[detId] < 1e-5 || coll.qvecAmp()[refAId] < 1e-5 || coll.qvecAmp()[refBId] < 1e-5) + return; + + for (int i = 0; i < cfgnMode; i++) { // loop over different harmonic orders + harmInd = cfgnTotalSystem * 4 * (i) + 3; // harmonic index to access corresponding Q-vector as all Q-vectors are in same vector + eps[0] = helperEP.GetEventPlane(coll.qvecRe()[4 * detId + harmInd], coll.qvecIm()[4 * detId + harmInd], i + 2); + eps[1] = helperEP.GetEventPlane(coll.qvecRe()[4 * refAId + harmInd], coll.qvecIm()[4 * refAId + harmInd], i + 2); + eps[2] = helperEP.GetEventPlane(coll.qvecRe()[4 * refBId + harmInd], coll.qvecIm()[4 * refBId + harmInd], i + 2); + + auto deltapsiDet = 0.0; + auto deltapsiRefA = 0.0; + auto deltapsiRefB = 0.0; + + float weight = 1.0; + + if (cfgShiftCorr) { + constexpr int kShiftBins = 10; + for (int ishift = 1; ishift <= kShiftBins; ishift++) { + auto coeffshiftxDet = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * detId + 0.5, ishift - 0.5)); + auto coeffshiftyDet = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * detId + 1.5, ishift - 0.5)); + auto coeffshiftxRefA = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refAId + 0.5, ishift - 0.5)); + auto coeffshiftyRefA = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refAId + 1.5, ishift - 0.5)); + auto coeffshiftxRefB = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refBId + 0.5, ishift - 0.5)); + auto coeffshiftyRefB = shiftprofile.at(i)->GetBinContent(shiftprofile.at(i)->FindBin(cent, 2.0 * refBId + 1.5, ishift - 0.5)); + + deltapsiDet += ((2. / (1.0 * ishift)) * (-coeffshiftxDet * std::cos(ishift * static_cast(i + 2) * eps[0]) + coeffshiftyDet * std::sin(ishift * static_cast(i + 2) * eps[0]))) / static_cast(i + 2); + deltapsiRefA += ((2. / (1.0 * ishift)) * (-coeffshiftxRefA * std::cos(ishift * static_cast(i + 2) * eps[1]) + coeffshiftyRefA * std::sin(ishift * static_cast(i + 2) * eps[1]))) / static_cast(i + 2); + deltapsiRefB += ((2. / (1.0 * ishift)) * (-coeffshiftxRefB * std::cos(ishift * static_cast(i + 2) * eps[2]) + coeffshiftyRefB * std::sin(ishift * static_cast(i + 2) * eps[2]))) / static_cast(i + 2); + } + + eps[0] += deltapsiDet; + eps[1] += deltapsiRefA; + eps[2] += deltapsiRefB; + + qx_shifted[0] = coll.qvecRe()[4 * detId + harmInd] * std::cos(deltapsiDet) - coll.qvecIm()[4 * detId + harmInd] * std::sin(deltapsiDet); + qy_shifted[0] = coll.qvecRe()[4 * detId + harmInd] * std::sin(deltapsiDet) + coll.qvecIm()[4 * detId + harmInd] * std::cos(deltapsiDet); + qx_shifted[1] = coll.qvecRe()[4 * refAId + harmInd] * std::cos(deltapsiRefA) - coll.qvecIm()[4 * refAId + harmInd] * std::sin(deltapsiRefA); + qy_shifted[1] = coll.qvecRe()[4 * refAId + harmInd] * std::sin(deltapsiRefA) + coll.qvecIm()[4 * refAId + harmInd] * std::cos(deltapsiRefA); + qx_shifted[2] = coll.qvecRe()[4 * refBId + harmInd] * std::cos(deltapsiRefB) - coll.qvecIm()[4 * refBId + harmInd] * std::sin(deltapsiRefB); + qy_shifted[2] = coll.qvecRe()[4 * refBId + harmInd] * std::sin(deltapsiRefB) + coll.qvecIm()[4 * refBId + harmInd] * std::cos(deltapsiRefB); + } + + float resNumA = helperEP.GetResolution(eps[0], eps[1], i + 2); + float resNumB = helperEP.GetResolution(eps[0], eps[2], i + 2); + float resDenom = helperEP.GetResolution(eps[1], eps[2], i + 2); + + epFlowHistograms.fill(HIST("EpDet"), i + 2, cent, eps[0]); + epFlowHistograms.fill(HIST("EpRefA"), i + 2, cent, eps[1]); + epFlowHistograms.fill(HIST("EpRefB"), i + 2, cent, eps[2]); + + epFlowHistograms.fill(HIST("EpResDetRefA"), i + 2, cent, resNumA); + epFlowHistograms.fill(HIST("EpResDetRefB"), i + 2, cent, resNumB); + epFlowHistograms.fill(HIST("EpResRefARefB"), i + 2, cent, resDenom); + + epFlowHistograms.fill(HIST("EpResQvecDetRefAxx"), i + 2, cent, qx_shifted[0] * qx_shifted[1] + qy_shifted[0] * qy_shifted[1]); + epFlowHistograms.fill(HIST("EpResQvecDetRefAxy"), i + 2, cent, qx_shifted[1] * qy_shifted[0] - qx_shifted[0] * qy_shifted[1]); + epFlowHistograms.fill(HIST("EpResQvecDetRefBxx"), i + 2, cent, qx_shifted[0] * qx_shifted[2] + qy_shifted[0] * qy_shifted[2]); + epFlowHistograms.fill(HIST("EpResQvecDetRefBxy"), i + 2, cent, qx_shifted[2] * qy_shifted[0] - qx_shifted[0] * qy_shifted[2]); + epFlowHistograms.fill(HIST("EpResQvecRefARefBxx"), i + 2, cent, qx_shifted[1] * qx_shifted[2] + qy_shifted[1] * qy_shifted[2]); + epFlowHistograms.fill(HIST("EpResQvecRefARefBxy"), i + 2, cent, qx_shifted[2] * qy_shifted[1] - qx_shifted[1] * qy_shifted[2]); + + for (const auto& track : tracks) { + float vn = std::cos((i + 2) * (track.phi() - eps[0])); + float vnSin = std::sin((i + 2) * (track.phi() - eps[0])); + + epFlowHistograms.fill(HIST("vncos"), i + 2, cent, track.pt(), vn * weight); + epFlowHistograms.fill(HIST("vnsin"), i + 2, cent, track.pt(), vnSin * weight); + + epFlowHistograms.fill(HIST("SPvnxx"), i + 2, cent, track.pt(), (std::cos(track.phi() * static_cast(i + 2)) * qx_shifted[0] + std::sin(track.phi() * static_cast(i + 2)) * qy_shifted[0]) * weight); + epFlowHistograms.fill(HIST("SPvnxy"), i + 2, cent, track.pt(), (std::sin(track.phi() * static_cast(i + 2)) * qx_shifted[0] - std::cos(track.phi() * static_cast(i + 2)) * qy_shifted[0]) * weight); + } + } + } + PROCESS_SWITCH(jEPFlowAnalysis, processDefault, "default process", true); +}; + +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..70f9b1a8390 --- /dev/null +++ b/PWGCF/JCorran/Tasks/jFlucEfficiencyTask.cxx @@ -0,0 +1,961 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGLF/Utils/collisionCuts.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::rctsel; +using namespace o2::constants::physics; + +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}; + + static constexpr double kChargeThreshold = 3.0; // PDG charge units: 3 = |e| + + // 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"}; + // PID + Configurable cfgPIDnSigmaCut{"cfgPIDnSigmaCut", 3.0, "PID nSigma cut"}; + } TrackCuts; + + Configurable applyMCStudy{"applyMCStudy", false, "Apply MC study"}; + + // 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 TrackCandidatesPID = soa::Join; + using MCCollisionCandidates = soa::Join; + using MCRun2CollisionCandidates = soa::Join; + using MCTrackCandidates = soa::Join; + using MCTrackCandidatesPID = 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); + + // Helper function to add histograms with consistent naming + auto addHistograms = [this](const std::string& prefix, bool isMC = false) { + if (isMC) { + // Generated (MC) histograms - pT has all variations + registry.add(Form("hPtGen%s", prefix.c_str()), + Form("Generated p_{T} %s;p_{T} (GeV/c);Centrality (%%);Counts", prefix.c_str()), + {HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + } + + // Reconstructed histograms - pT has all variations + registry.add(Form("hPtRec%s", prefix.c_str()), + Form("Reconstructed p_{T} %s;p_{T} (GeV/c);Centrality (%%);Counts", prefix.c_str()), + {HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + }; + + // Add MC histograms if MC processing is enabled + if (doprocessDerivedMC || doprocessMC || doprocessMCRun2 || doprocessMCPID) { + addHistograms("", true); // hPtGen, hPtRec + addHistograms("Pos", true); // hPtGenPos, hPtRecPos + addHistograms("Neg", true); // hPtGenNeg, hPtRecNeg + addHistograms("_Pos", true); // hPtGen_Pos, hPtRec_Pos + addHistograms("_Neg", true); // hPtGen_Neg, hPtRec_Neg + addHistograms("Pos_Pos", true); // hPtGenPos_Pos, hPtRecPos_Pos + addHistograms("Pos_Neg", true); // hPtGenPos_Neg, hPtRecPos_Neg + addHistograms("Neg_Pos", true); // hPtGenNeg_Pos, hPtRecNeg_Pos + addHistograms("Neg_Neg", true); // hPtGenNeg_Neg, hPtRecNeg_Neg + } else { + // Add reconstructed histograms + addHistograms(""); // hPtRec + addHistograms("_Pos"); // hPtRec_Pos + addHistograms("_Neg"); // hPtRec_Neg + addHistograms("Pos"); // hPtRecPos + addHistograms("Neg"); // hPtRecNeg + addHistograms("Pos_Pos"); // hPtRecPos_Pos + addHistograms("Pos_Neg"); // hPtRecPos_Neg + addHistograms("Neg_Pos"); // hPtRecNeg_Pos + addHistograms("Neg_Neg"); // hPtRecNeg_Neg + } + // Add basic eta histograms separately + if (doprocessDerivedMC || doprocessMC || doprocessMCRun2 || doprocessMCPID) { + registry.add("hEtaGen", "Generated #eta (all);#eta;Centrality (%);Counts", + {HistType::kTH2F, {AxisSpec(100, -1, 1), AxisSpec(axisMultiplicity)}}); + } + registry.add("hEtaRec", "Reconstructed #eta (all);#eta;Centrality (%);Counts", + {HistType::kTH2F, {AxisSpec(100, -1, 1), AxisSpec(axisMultiplicity)}}); + + // Add pT uncertainty histograms + registry.add("hPtUncertainty", "Track p_{T} uncertainty;p_{T} (GeV/c);Centrality (%);p_{T} uncertainty (GeV/c)", + {HistType::kTH3F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity), AxisSpec(100, 0, 10)}}); + registry.add("hPtUncertaintyPos", "Track p_{T} uncertainty (positive);p_{T} (GeV/c);Centrality (%);p_{T} uncertainty (GeV/c)", + {HistType::kTH3F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity), AxisSpec(100, 0, 10)}}); + registry.add("hPtUncertaintyNeg", "Track p_{T} uncertainty (negative);p_{T} (GeV/c);Centrality (%);p_{T} uncertainty (GeV/c)", + {HistType::kTH3F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity), AxisSpec(100, 0, 10)}}); + + // Add MC study histograms if enabled + if (applyMCStudy && (doprocessDerivedMC || doprocessMC || doprocessMCRun2 || doprocessMCPID)) { + registry.add("hChargeSignMismatch", "Charge-Sign mismatch cases", {HistType::kTH2D, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + registry.add("hChargeSignMismatchPos", "MC charge + but track sign -", {HistType::kTH2D, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + registry.add("hChargeSignMismatchNeg", "MC charge - but track sign +", {HistType::kTH2D, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + registry.add("hChargeSignMatch", "Charge-Sign match cases", {HistType::kTH2D, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + registry.add("hChargeSignMatchPos", "MC charge + and track sign +", {HistType::kTH2D, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + registry.add("hChargeSignMatchNeg", "MC charge - and track sign -", {HistType::kTH2D, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + } + + // Add efficiency histograms if enabled + 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", + {HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + registry.add("hEtaRecData", "Reconstructed #eta (all);#eta;Centrality (%);Counts", + {HistType::kTH2F, {AxisSpec(100, -1, 1), AxisSpec(axisMultiplicity)}}); + registry.add("hPtRecDataPos", "Reconstructed p_{T} (positive);p_{T} (GeV/c);Centrality (%);Counts", + {HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + registry.add("hPtRecDataNeg", "Reconstructed p_{T} (negative);p_{T} (GeV/c);Centrality (%);Counts", + {HistType::kTH2F, {AxisSpec(axisPt), AxisSpec(axisMultiplicity)}}); + } + + // 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) >= kChargeThreshold; + } + // 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; + // Common histogram filling function for tracks + template + void fillTrackHistograms(const TrackType& track, float centrality) + { + // Basic pT and eta histograms + registry.fill(HIST("hPtRec"), track.pt(), centrality); + registry.fill(HIST("hEtaRec"), track.eta(), centrality); + + // pT histograms by eta direction + if (track.eta() > 0) { + registry.fill(HIST("hPtRec_Pos"), track.pt(), centrality); + } else if (track.eta() < 0) { + registry.fill(HIST("hPtRec_Neg"), track.pt(), centrality); + } + + // Charge sign specific histograms + if (track.sign() > 0) { // Positive tracks + registry.fill(HIST("hPtRecPos"), track.pt(), centrality); + if (track.eta() > 0) { + registry.fill(HIST("hPtRecPos_Pos"), track.pt(), centrality); + } else if (track.eta() < 0) { + registry.fill(HIST("hPtRecPos_Neg"), track.pt(), centrality); + } + } else if (track.sign() < 0) { // Negative tracks + registry.fill(HIST("hPtRecNeg"), track.pt(), centrality); + if (track.eta() > 0) { + registry.fill(HIST("hPtRecNeg_Pos"), track.pt(), centrality); + } else if (track.eta() < 0) { + registry.fill(HIST("hPtRecNeg_Neg"), track.pt(), centrality); + } + } + + // pT uncertainty histograms + auto ptUncertaintySigma = track.c1Pt21Pt2() * track.pt() * track.pt(); // Variance of pT + auto ptUncertainty = std::sqrt(ptUncertaintySigma); // Standard deviation of pT + registry.fill(HIST("hPtUncertainty"), track.pt(), centrality, ptUncertainty); + + if (track.sign() > 0) { + registry.fill(HIST("hPtUncertaintyPos"), track.pt(), centrality, ptUncertainty); + } else if (track.sign() < 0) { + registry.fill(HIST("hPtUncertaintyNeg"), track.pt(), centrality, ptUncertainty); + } + } + + // Common histogram filling function for MC particles + template + void fillMCParticleHistograms(const ParticleType& particle, float centrality) + { + registry.fill(HIST("hPtGen"), particle.pt(), centrality); + registry.fill(HIST("hEtaGen"), particle.eta(), centrality); + + // pT histograms by eta direction + if (particle.eta() > 0) { + registry.fill(HIST("hPtGen_Pos"), particle.pt(), centrality); + } else if (particle.eta() < 0) { + registry.fill(HIST("hPtGen_Neg"), particle.pt(), centrality); + } + + // Charge sign specific histograms + auto charge = getCharge(particle); + if (charge > 0) { // Positive particles + registry.fill(HIST("hPtGenPos"), particle.pt(), centrality); + if (particle.eta() > 0) { + registry.fill(HIST("hPtGenPos_Pos"), particle.pt(), centrality); + } else if (particle.eta() < 0) { + registry.fill(HIST("hPtGenPos_Neg"), particle.pt(), centrality); + } + } else if (charge < 0) { // Negative particles + registry.fill(HIST("hPtGenNeg"), particle.pt(), centrality); + if (particle.eta() > 0) { + registry.fill(HIST("hPtGenNeg_Pos"), particle.pt(), centrality); + } else if (particle.eta() < 0) { + registry.fill(HIST("hPtGenNeg_Neg"), particle.pt(), centrality); + } + } + } + + // Common event selection function + template + bool selectEvent(const CollisionType& collision, float& centrality) + { + if (!colCuts.isSelected(collision)) { + return false; + } + + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + return false; + } + + colCuts.fillQA(collision); + centrality = collision.centFT0C(); + + if (centrality < EventCuts.cfgCentMin || centrality > EventCuts.cfgCentMax) { + return false; + } + + return true; + } + + // Common event selection function for Run2 data + template + bool selectEventRun2(const CollisionType& collision, float& centrality) + { + if (!colCuts.isSelected(collision)) { + return false; + } + + colCuts.fillQARun2(collision); + centrality = collision.centRun2V0M(); + + if (centrality < EventCuts.cfgCentMin || centrality > EventCuts.cfgCentMax) { + return false; + } + + return true; + } + + 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) { // Anyway 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; + } + + // Fill MC particle histograms + for (const auto& particle : mcParticles) { + 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; + } + fillMCParticleHistograms(particle, centrality); + } + + // Process reconstructed tracks + 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; + } + + if (applyMCStudy) { + // Check charge-sign consistency + auto mcCharge = getCharge(mcPart); + auto trackSign = track.sign(); + + if (mcCharge > 0 && trackSign > 0) { + // MC charge + and track sign + + registry.fill(HIST("hChargeSignMatchPos"), track.pt(), centrality); + registry.fill(HIST("hChargeSignMatch"), track.pt(), centrality); + } else if (mcCharge < 0 && trackSign < 0) { + // MC charge - and track sign - + registry.fill(HIST("hChargeSignMatchNeg"), track.pt(), centrality); + registry.fill(HIST("hChargeSignMatch"), track.pt(), centrality); + } else if (mcCharge > 0 && trackSign < 0) { + // MC charge + but track sign - + registry.fill(HIST("hChargeSignMismatchPos"), track.pt(), centrality); + registry.fill(HIST("hChargeSignMismatch"), track.pt(), centrality); + } else if (mcCharge < 0 && trackSign > 0) { + // MC charge - but track sign + + registry.fill(HIST("hChargeSignMismatchNeg"), track.pt(), centrality); + registry.fill(HIST("hChargeSignMismatch"), track.pt(), centrality); + } + } + + fillTrackHistograms(track, centrality); + } + } + } + + Preslice perCollisionPID = aod::track::collisionId; + void processMCPID(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) { // Anyway 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; + } + + // Fill MC particle histograms + for (const auto& particle : mcParticles) { + if (!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; + } + // Check if the particle is a pion + if (std::abs(particle.pdgCode()) != std::abs(kPiPlus)) { + continue; + } + fillMCParticleHistograms(particle, centrality); + } + + // Process reconstructed tracks + for (const auto& collision : collisions) { + registry.fill(HIST("hZVertexReco"), collision.posZ(), centrality); + registry.fill(HIST("hZVertexCorrelation"), mcCollision.posZ(), collision.posZ()); + + auto tracks = mcTracks.sliceBy(perCollisionPID, collision.globalIndex()); + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + if (std::abs(track.tpcNSigmaPi()) > TrackCuts.cfgPIDnSigmaCut) { + continue; + } + if (!trackCut(track)) { + continue; + } + auto mcPart = track.mcParticle(); + if (!isChargedParticle(mcPart.pdgCode())) { + continue; + } + if (std::abs(mcPart.pdgCode()) != kPiPlus) { + continue; + } + + if (applyMCStudy) { + // Check charge-sign consistency + auto mcCharge = getCharge(mcPart); + auto trackSign = track.sign(); + + if (mcCharge > 0 && trackSign > 0) { + // MC charge + and track sign + + registry.fill(HIST("hChargeSignMatchPos"), track.pt(), centrality); + registry.fill(HIST("hChargeSignMatch"), track.pt(), centrality); + } else if (mcCharge < 0 && trackSign < 0) { + // MC charge - and track sign - + registry.fill(HIST("hChargeSignMatchNeg"), track.pt(), centrality); + registry.fill(HIST("hChargeSignMatch"), track.pt(), centrality); + } else if (mcCharge > 0 && trackSign < 0) { + // MC charge + but track sign - + registry.fill(HIST("hChargeSignMismatchPos"), track.pt(), centrality); + registry.fill(HIST("hChargeSignMismatch"), track.pt(), centrality); + } else if (mcCharge < 0 && trackSign > 0) { + // MC charge - but track sign + + registry.fill(HIST("hChargeSignMismatchNeg"), track.pt(), centrality); + registry.fill(HIST("hChargeSignMismatch"), track.pt(), centrality); + } + } + + fillTrackHistograms(track, 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) { // Anyway 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; + } + + // Fill MC particle histograms + for (const auto& particle : mcParticles) { + 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; + } + fillMCParticleHistograms(particle, centrality); + } + + // Process reconstructed tracks + 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; + } + if (!trackCut(track)) { + continue; + } + + fillTrackHistograms(track, centrality); + } + } + } + + void processData(CollisionCandidates::iterator const& collision, soa::Filtered const& tracks) + { + float centrality; + if (!selectEvent(collision, centrality)) { + return; + } + + registry.fill(HIST("hZVertexReco"), collision.posZ(), centrality); + + for (const auto& track : tracks) { + if (!trackCut(track)) { + continue; + } + fillTrackHistograms(track, centrality); + } + } + + void processDataPID(CollisionCandidates::iterator const& collision, soa::Filtered const& tracks) + { + float centrality; + if (!selectEvent(collision, centrality)) { + return; + } + + registry.fill(HIST("hZVertexReco"), collision.posZ(), centrality); + + for (const auto& track : tracks) { + if (!trackCut(track)) { + continue; + } + if (std::abs(track.tpcNSigmaPi()) > TrackCuts.cfgPIDnSigmaCut) { + continue; + } + fillTrackHistograms(track, centrality); + } + } + + void processDataRun2(CollisionRun2Candidates::iterator const& collision, soa::Filtered const& tracks, BCsWithRun2Info const&) + { + float centrality; + if (!selectEventRun2(collision, centrality)) { + return; + } + + registry.fill(HIST("hZVertexReco"), collision.posZ(), centrality); + + for (const auto& track : tracks) { + if (!trackCut(track)) { + continue; + } + fillTrackHistograms(track, 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, processMCPID, "Process MC with PID only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processMCRun2, "Process Run2 MC only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processData, "Process data only", false); + PROCESS_SWITCH(JFlucEfficiencyTask, processDataPID, "Process data with PID 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 16ff1b6c25b..c6a213163d5 100644 --- a/PWGCF/JCorran/Tasks/jflucAnalysisTask.cxx +++ b/PWGCF/JCorran/Tasks/jflucAnalysisTask.cxx @@ -12,25 +12,32 @@ /// \author Dong Jo Kim (djkim@jyu.fi) /// \since Sep 2022 -#include +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" -#include "Framework/RunningWorkflowInfo.h" +#include "Framework/AnalysisTask.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 "Framework/RunningWorkflowInfo.h" #include "ReconstructionDataFormats/V0.h" +#include + +#include +#include +#include +#include + // #include "CCDB/BasicCCDBManager.h" -#include "PWGCF/JCorran/DataModel/JCatalyst.h" -#include "PWGCF/DataModel/CorrelationsDerived.h" #include "JFFlucAnalysis.h" #include "JFFlucAnalysisO2Hist.h" + +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/JCorran/DataModel/JCatalyst.h" + #include "Framework/runDataProcessing.h" using namespace o2; @@ -51,42 +58,86 @@ struct jflucAnalysisTask { 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, 0.5, "Maximum pt for tracks"); + O2_DEFINE_CONFIGURABLE(ptmax, float, 5.0, "Maximum pt for tracks"); + O2_DEFINE_CONFIGURABLE(cfgCentBinsForMC, int, 0, "0 = OFF and 1 = ON for data like multiplicity/centrality bins for MC process"); + O2_DEFINE_CONFIGURABLE(cfgMultCorrelationsMask, uint16_t, 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask.") + O2_DEFINE_CONFIGURABLE(cfgMultCutFormula, std::string, "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity") 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"}; + + ConfigurableAxis vnCorrAxis{"vnCorrAxis", {2048, -0.1, 0.1}, "vn correlation axis"}; + ConfigurableAxis fourCorrSCAxis{"4pCorrAxisSC", {2048, -0.001, 0.001}, "4-particle correlation axis for SC"}; + ConfigurableAxis twoCorrSCAxis{"2pCorrAxisSC", {2048, -0.1, 0.1}, "2-particle correlation axis for SC"}; + ConfigurableAxis mixedCorrAxis{"mixedCorrAxis", {2048, -3.0, 3.0}, "N-particle correlation axis"}; - 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 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 cfmcparticleFilter = (aod::cfmcparticle::pt > ptmin) && (aod::cfmcparticle::pt < ptmax) && (aod::cfmcparticle::sign != 0); // eta cuts done by jfluc Filter cf2pFilter = (aod::cf2prongtrack::pt > ptmin) && (aod::cf2prongtrack::pt < ptmax); HistogramRegistry registry{"registry"}; + std::unique_ptr multCutFormula; + std::array multCutFormulaParamIndex; + void init(InitContext const&) { auto axisSpecMult = AxisSpec(axisMultiplicity); auto axisSpecPhi = AxisSpec(phiAxis); auto axisSpecEta = AxisSpec(etaAxis); auto axisSpecZvt = AxisSpec(zvtAxis); - if (doprocessJDerived || doprocessJDerivedCorrected || doprocessCFDerived || doprocessCFDerivedCorrected) { - pcf = new JFFlucAnalysisO2Hist(registry, axisSpecMult, axisSpecPhi, axisSpecEta, axisSpecZvt, "jfluc"); + auto axisSpecPt = AxisSpec(ptAxis); + auto axisSpecMass = AxisSpec(massAxis); + auto axisSpecVn = AxisSpec(vnCorrAxis); + auto axisSpec4pSC = AxisSpec(fourCorrSCAxis); + auto axisSpec2pSC = AxisSpec(twoCorrSCAxis); + auto axisSpecMixed = AxisSpec(mixedCorrAxis); + if (doprocessJDerived || doprocessJDerivedCorrected || doprocessCFDerived || doprocessCFDerivedCorrected || doprocessCFDerivedMultSet || doprocessCFDerivedMultSetCorrected || doprocessMCCFDerived) { + pcf = new JFFlucAnalysisO2Hist(registry, axisSpecMult, axisSpecPhi, axisSpecEta, axisSpecZvt, axisSpecPt, axisSpecMass, axisSpecVn, axisSpec4pSC, axisSpec2pSC, axisSpecMixed, cfgMultCorrelationsMask, "jfluc"); pcf->AddFlags(JFFlucAnalysis::kFlucEbEWeighting); pcf->UserCreateOutputObjects(); } else { pcf = 0; } if (doprocessCF2ProngDerived || doprocessCF2ProngDerivedCorrected) { - pcf2Prong = new JFFlucAnalysisO2Hist(registry, axisSpecMult, axisSpecPhi, axisSpecEta, axisSpecZvt, "jfluc2prong"); + pcf2Prong = new JFFlucAnalysisO2Hist(registry, axisSpecMult, axisSpecPhi, axisSpecEta, axisSpecZvt, axisSpecPt, axisSpecMass, axisSpecVn, axisSpec4pSC, axisSpec2pSC, axisSpecMixed, cfgMultCorrelationsMask, "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::kTH2F, {axisInvMassHistogram, axisMultiplicity}}); + registry.add("invMass", "2-prong invariant mass (GeV/c^2)", {HistType::kTH3F, {axisInvMassHistogram, {8, 0.0, 8.0, "p_{T}"}, axisMultiplicity}}); } else { pcf2Prong = 0; } + if ((doprocessCFDerivedMultSet || doprocessCFDerivedMultSetCorrected) && cfgMultCorrelationsMask == 0) + LOGF(fatal, "cfgMultCorrelationsMask can not be 0 when MultSet process functions are in use."); + + if (!cfgMultCutFormula.value.empty()) { + if (cfgMultCorrelationsMask == 0) + LOGF(fatal, "cfgMultCorrelationsMask can not be 0 when outlier cuts are enabled."); + multCutFormula = std::make_unique("multCutFormula", cfgMultCutFormula.value.c_str()); + std::fill_n(multCutFormulaParamIndex.begin(), std::size(multCutFormulaParamIndex), ~0u); + std::array pars = {"cFT0C", "mFV0A", "mPV", "mGlob"}; // must correspond the order of MultiplicityEstimators + for (uint i = 0, n = multCutFormula->GetNpar(); i < n; ++i) { + auto m = std::find(pars.begin(), pars.end(), multCutFormula->GetParName(i)); + if (m == pars.end()) { + + LOGF(warning, "Unknown parameter in cfgMultCutFormula: %s", multCutFormula->GetParName(i)); + continue; + } + if ((cfgMultCorrelationsMask.value & (1u << i)) == 0) { + LOGF(warning, "The centrality/multiplicity estimator %s is not available to be used in cfgMultCutFormula. Ensure cfgMultCorrelationsMask is correct and matches the CFMultSets in derived data."); + } else { + multCutFormulaParamIndex[std::distance(pars.begin(), m)] = i; + LOGF(info, "Multiplicity cut parameter %s in use.", m->c_str()); + } + } + } } template @@ -99,6 +150,7 @@ struct jflucAnalysisTask { pcf->SetEventCentrality(collision.multiplicity()); pcf->SetEventVertex(collision.posZ()); pcf->FillQA(tracks); + pcf->FillMultSet(collision); qvecs.Calculate(tracks, etamin, etamax); pcf->SetJQVectors(&qvecs); pcf->UserExec(""); @@ -109,16 +161,35 @@ struct jflucAnalysisTask { { if constexpr (std::experimental::is_detected::value) { for (auto& track : poiTracks) - registry.fill(HIST("invMass"), track.invMass(), collision.multiplicity()); + 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 - qvecs.Calculate(poiTracks, etamin, etamax); qvecsRef.Calculate(refTracks, etamin, etamax); pcf2Prong->SetJQVectors(&qvecs, &qvecsRef); - pcf2Prong->UserExec(""); + 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 + } + } + + template + bool passOutlier(CollType const& collision) + { + if (cfgMultCutFormula.value.empty()) + return true; + for (uint i = 0; i < 4; ++i) { + if ((cfgMultCorrelationsMask.value & (1u << i)) == 0 || multCutFormulaParamIndex[i] == ~0u) + continue; + auto estIndex = std::popcount(cfgMultCorrelationsMask.value & ((1u << i) - 1)); + multCutFormula->SetParameter(multCutFormulaParamIndex[i], collision.multiplicities()[estIndex]); + } + return multCutFormula->Eval() > 0.0f; } void processJDerived(aod::JCollision const& collision, soa::Filtered const& tracks) @@ -137,13 +208,33 @@ struct jflucAnalysisTask { { analyze(collision, tracks); } - PROCESS_SWITCH(jflucAnalysisTask, processCFDerived, "Process CF derived data", true); + PROCESS_SWITCH(jflucAnalysisTask, processCFDerived, "Process CF derived data", false); void processCFDerivedCorrected(aod::CFCollision const& collision, soa::Filtered> const& tracks) { 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 processCFDerivedMultSet(soa::Join::iterator const& collision, soa::Filtered const& tracks) + { + if (std::popcount(cfgMultCorrelationsMask.value) != static_cast(collision.multiplicities().size())) + LOGF(fatal, "Multiplicity selections (cfgMultCorrelationsMask = 0x%x) do not match the size of the table column (%ld). The histogram filling relies on the preservation of order.", cfgMultCorrelationsMask.value, collision.multiplicities().size()); + if (!passOutlier(collision)) + return; + analyze(collision, tracks); + } + PROCESS_SWITCH(jflucAnalysisTask, processCFDerivedMultSet, "Process CF derived data with multiplicity sets", false); + + void processCFDerivedMultSetCorrected(soa::Join::iterator const& collision, soa::Filtered> const& tracks) + { + if (std::popcount(cfgMultCorrelationsMask.value) != static_cast(collision.multiplicities().size())) + LOGF(fatal, "Multiplicity selections (cfgMultCorrelationsMask = 0x%x) do not match the size of the table column (%ld). The histogram filling relies on the preservation of order.", cfgMultCorrelationsMask.value, collision.multiplicities().size()); + if (!passOutlier(collision)) + return; + analyze(collision, tracks); + } + PROCESS_SWITCH(jflucAnalysisTask, processCFDerivedMultSetCorrected, "Process CF derived data with corrections and multiplicity sets", false); void processCF2ProngDerived(aod::CFCollision const& collision, soa::Filtered const& tracks, soa::Filtered const& p2tracks) { @@ -157,6 +248,27 @@ struct jflucAnalysisTask { } PROCESS_SWITCH(jflucAnalysisTask, processCF2ProngDerivedCorrected, "Process CF derived data with 2-prongs as POI and charged particles as REF with corrections.", false); + void processMCCFDerived(aod::CFMcCollision const& mcCollision, soa::Filtered const& particles, soa::SmallGroups const& collisions) + { + auto multiplicity = mcCollision.multiplicity(); + if (cfgCentBinsForMC > 0) { + if (collisions.size() == 0) { + return; + } + for (const auto& collision : collisions) { + multiplicity = collision.multiplicity(); + } + } + pcf->Init(); + pcf->SetEventCentrality(multiplicity); + pcf->SetEventVertex(mcCollision.posZ()); + pcf->FillQA(particles); + qvecs.Calculate(particles, etamin, etamax); + pcf->SetJQVectors(&qvecs); + pcf->UserExec(""); + } + PROCESS_SWITCH(jflucAnalysisTask, processMCCFDerived, "Process CF derived MC data", false); + JFFlucAnalysis::JQVectorsT qvecs; JFFlucAnalysis::JQVectorsT qvecsRef; JFFlucAnalysisO2Hist* pcf; diff --git a/PWGCF/JCorran/Tasks/jflucWeightsLoader.cxx b/PWGCF/JCorran/Tasks/jflucWeightsLoader.cxx index a7717b6c2f5..4b14c8ba049 100644 --- a/PWGCF/JCorran/Tasks/jflucWeightsLoader.cxx +++ b/PWGCF/JCorran/Tasks/jflucWeightsLoader.cxx @@ -8,29 +8,34 @@ // In applying this license CERN does 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) +/// +/// \file jflucWeightsLoader.cxx +/// \brief Task to load the NUA and NUE weights from local files or CCDB. +/// \author Jasper Parkkila (jparkkil@cern.ch), Maxim Virta (maxim.virta@cern.ch) /// \since May 2024 +/// The weights are loaded from the local files or CCDB and stored in the JWeights table. -#include -#include -#include - -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/HistogramRegistry.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/JCorran/DataModel/JCatalyst.h" -#include "Common/DataModel/EventSelection.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/V0.h" -// #include "CCDB/BasicCCDBManager.h" +#include +#include -#include "PWGCF/JCorran/DataModel/JCatalyst.h" -#include "PWGCF/DataModel/CorrelationsDerived.h" -#include "Framework/runDataProcessing.h" +#include +#include using namespace o2; using namespace o2::framework; @@ -40,14 +45,25 @@ using namespace o2::framework::expressions; // 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"); +struct JflucWeightsLoader { + O2_DEFINE_CONFIGURABLE(cfgPathPhiWeights, std::string, "Users/m/mavirta/corrections/NUA/LHC23zzh", "Local (local://) or CCDB path for the phi acceptance correction histogram"); + O2_DEFINE_CONFIGURABLE(cfgPathEffWeights, std::string, "Users/m/mavirta/corrections/NUE/LHC23zzh", "Local (local://) or CCDB path for the efficiency correction histogram"); + O2_DEFINE_CONFIGURABLE(cfgForRunNumber, bool, false, "Get CCDB object by run"); THnF* ph = 0; TFile* pf = 0; + THnF* pheff = 0; + TFile* pfeff = 0; int runNumber = 0; + int timestamp = 0; + bool useNUAFromCCDB = false; + bool useEffFromCCDB = false; + Service ccdb; + std::string ccdbURL = "http://alice-ccdb.cern.ch"; + enum { kNUA, + kEFF }; - ~jflucWeightsLoader() + ~JflucWeightsLoader() { if (ph) delete ph; @@ -55,46 +71,138 @@ struct jflucWeightsLoader { pf->Close(); delete pf; } + if (pheff) + delete pheff; + if (pfeff) { + pfeff->Close(); + delete pfeff; + } + } + + void initCCDB(int runNum, int ts, int NUAorEFF = kNUA) + { + if (cfgForRunNumber) { + if (NUAorEFF == kNUA) { + ph = ccdb->getForRun(cfgPathPhiWeights, runNum); + } else { + pheff = ccdb->getForRun(cfgPathEffWeights, runNum); + } + } else { + if (NUAorEFF == kNUA) { + ph = ccdb->getForTimeStamp(cfgPathPhiWeights, ts); + } else { + pheff = ccdb->getForTimeStamp(cfgPathEffWeights, ts); + } + } } void init(InitContext const&) { - if (!doprocessLoadWeights && !doprocessLoadWeightsCF) + if (!doprocessLoadWeights && !doprocessLoadWeightsCF) { return; + } + if (doprocessLoadWeights && doprocessLoadWeightsCF) LOGF(fatal, "Only one of JTracks or CFTracks processing can be enabled at a time."); - if (pathPhiWeights.value.substr(0, 8) == "local://") { - pf = new TFile(pathPhiWeights.value.substr(8).c_str(), "read"); + + // NUA corrections from local file or CCDB + if (cfgPathPhiWeights.value.substr(0, 8) == "local://") { + LOGF(info, "Using NUA corrections locally 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", pathPhiWeights.value.substr(8).c_str()); + LOGF(fatal, "NUA correction weights file not found: %s", cfgPathPhiWeights.value.substr(8).c_str()); + } + useNUAFromCCDB = false; + } else if (cfgPathPhiWeights.value == "") { + LOGF(info, "No NUA corrections provided."); + useNUAFromCCDB = false; + } else { + LOGF(info, "Assuming NUA corrections from CCDB."); + useNUAFromCCDB = true; + ccdb->setURL(ccdbURL.data()); // default CCDB URL + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + } + + // Efficiency corrections from local file or CCDB + if (cfgPathEffWeights.value.substr(0, 8) == "local://") { + LOGF(info, "Using efficiency corrections locally 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()); + } else { + LOGF(info, "Loaded efficiency correction histogram locally."); + } + useEffFromCCDB = false; + } else if (cfgPathEffWeights.value == "") { + LOGF(info, "No efficiency corrections provided."); + useEffFromCCDB = false; + } else { + LOGF(info, "Assuming efficiency corrections from CCDB."); + useEffFromCCDB = true; + // If NUA corrections are from CCDB, use the same CCDB URL for efficiency corrections + if (!useNUAFromCCDB) { + ccdb->setURL(ccdbURL.data()); // default CCDB URL + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); } } } template - using hasDecay = decltype(std::declval().decay()); + using HasDecay = decltype(std::declval().decay()); template void loadWeights(Produces& outputT, CollisionT const& collision, TrackT const& tracks) { - if (!pf) - LOGF(fatal, "NUA correction weights file has not been opened."); - if (collision.runNumber() != runNumber) { - if (ph) - delete ph; - if (!(ph = static_cast(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 for run %d.", collision.runNumber()); - runNumber = collision.runNumber(); + if (pf || useNUAFromCCDB) { + if (collision.runNumber() != runNumber) { + if (ph) + delete ph; + if (!useNUAFromCCDB) { + // 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, kNUA); + LOGF(info, "Loaded NUA correction histogram from CCDB for run %d.", collision.runNumber()); + } + } + } + if (pfeff || useEffFromCCDB) { + if (collision.runNumber() != runNumber) { + if (pheff) + delete pheff; + if (!useEffFromCCDB) { + if (!(pheff = pfeff->Get("ccdb_object"))) { + LOGF(warning, "Efficiency correction histogram not found."); + } else { + LOGF(info, "Loaded NUE correction histogram locally for run %d.", collision.runNumber()); + } + } else { + initCCDB(collision.runNumber(), timestamp, kEFF); + LOGF(info, "Loaded efficiency correction histogram from CCDB for run %d.", collision.runNumber()); + } + } } - for (auto& track : tracks) { + + // Set run number after reading corrections + runNumber = collision.runNumber(); + + for (const auto& track : tracks) { float phiWeight, effWeight; if (ph) { - UInt_t partType = 0; // partType 0 = all charged hadrons - if constexpr (std::experimental::is_detected::value) { + 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: @@ -103,14 +211,22 @@ struct jflucWeightsLoader { default: break; } - } - const Double_t coords[] = {collision.multiplicity(), static_cast(partType), track.phi(), track.eta(), collision.posZ()}; - phiWeight = ph->GetBinContent(ph->GetBin(coords)); + }*/ + // NUA corrections are a function of multiplicity, partType, phi, eta, and z-vertex + const double nuaCoords[] = {collision.multiplicity(), static_cast(partType), track.phi(), track.eta(), collision.posZ()}; + phiWeight = ph->GetBinContent(ph->GetBin(nuaCoords)); } else { phiWeight = 1.0f; } - effWeight = 1.0f; //<--- todo + if (pheff) { + // Efficiency corrections are a function of eta, pT, multiplicity, and z-vertex + const double nueCoords[] = {track.eta(), track.pt(), collision.multiplicity(), collision.posZ()}; + + effWeight = pheff->GetBinContent(pheff->GetBin(nueCoords)); + } else { + effWeight = 1.0f; + } outputT(phiWeight, effWeight); } @@ -121,23 +237,23 @@ struct jflucWeightsLoader { { loadWeights(output, collision, tracks); } - PROCESS_SWITCH(jflucWeightsLoader, processLoadWeights, "Load weights histograms for derived data table", false); + 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); + 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); + 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)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h b/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h index 770ed87472f..c1274b6788c 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h @@ -9,137 +9,219 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file MuPa-Configurables.h +/// \brief ... TBI 20250425 +/// \author Ante.Bilandzic@cern.ch + #ifndef PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_CONFIGURABLES_H_ #define PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_CONFIGURABLES_H_ // ... -#include #include +#include // *) 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 cfTaskName{"cfTaskName", "Default task name", "set task name - use eventually to determine weights for this task"}; + 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 function calls per particle)"}; + 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 cfUseCCDB{"cfUseCCDB", true, "if requested, access personal files from CCDB (true) or from home dir in AliEn (false)"}; 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 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\""}; + Configurable cfUseSetBinLabel{"cfUseSetBinLabel", false, "until hist->SetBinLabel(...) large memory consumption is resolved, for each histogram dump all that info in the y-axis title. See also local executable PostprocessLabels.C, where I do the final bin labeling offline"}; + Configurable cfUseClone{"cfUseClone", false, "until hist->Clone(...) large memory consumption is resolved, do not use cloning. See ROOT Forum thread."}; + Configurable cfUseFormula{"cfUseFormula", false, "until TFormula large memory consumption is resolved, do not use this class. See ROOT Forum thread."}; + Configurable cfUseDatabasePDG{"cfUseDatabasePDG", false, "When enabled, there is a standard memory blow-up."}; } 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", {"MultTPC_vs_NContributors-1", "Vertex_z_vs_MultTPC-1", "Vertex_z_vs_NContributors-1", "CentFT0M_vs_CentNTPV-1", "CentRun2V0M_vs_CentRun2SPDTracklets-1", "CentRun2V0M_vs_NContributors-1"}, "book (1) or do not book (0) this QA 2D event histogram"}; + 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", "1-Centrality_vs_CentralitySim"}, "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", {"dcaXY_vs_Pt-1"}, "book (1) or do not book (0) this QA 2D particle histogram"}; + 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", {"NumberOfEvents-1", "TotalMultiplicity-1", "SelectedTracks-1", "MultFV0M-1", "MultFT0M-1", "MultTPC-1", "MultNTracksPV-1", "MultTracklets-1", "Centrality-1", "Vertex_x-1", "Vertex_y-1", "Vertex_z-1", "NContributors-1", "ImpactParameter-1"}, "Book (1) or do not book (0) event histogram"}; + 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", {"NumberOfEvents-1", "TotalMultiplicity-1", "SelectedTracks-1", "MultFV0M-1", "MultFT0M-1", "MultTPC-1", "MultNTracksPV-1", "MultTracklets-1", "Centrality-1", "Vertex_x-1", "Vertex_y-1", "Vertex_z-1", "NContributors-1", "ImpactParameter-1", "Trigger-1", "Sel7-1", "Sel8-1", "CentralityEstimator-1", "SelectedEvents-1", "NoSameBunchPileup-1", "IsGoodZvtxFT0vsPV-1", "IsVertexITSTPC-1", "IsVertexTOFmatched-1", "IsVertexTRDmatched-1"}, "use (1) or do not use (0) event cuts"}; + 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", "0-FT0Bad", "0-ITSBad", "0-ITSLimAccMCRepr", "0-TPCBadTracking", "0-TPCLimAccMCRepr", "0-TPCBadPID", "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> cfSelectedTracks{"cfSelectedTracks", {-1, 1000000000}, "selected tracks range: {min, max}, with convention: min <= M < max"}; - Configurable> cfMultFV0M{"cfMultFV0M", {-1, 1000000000}, "MultFV0M range {min, max}, with convention: min <= M < max"}; - Configurable> cfMultFT0M{"cfMultFT0M", {-1, 1000000000}, "MultFT0M range {min, max}, with convention: min <= M < max"}; - Configurable> cfMultTPC{"cfMultTPC", {-1, 1000000000}, "MultTPC range {min, max}, with convention: min <= M < max"}; - Configurable> cfMultNTracksPV{"cfMultNTracksPV", {-1, 1000000000}, "MultNTracksPV range {min, max}, with convention: min <= M < max"}; - Configurable> cfMultTracklets{"cfMultTracklets", {-1, 1000000000}, "MultTracklets range {min, max}, with convention: min <= M < max"}; - Configurable> cfCentrality{"cfCentrality", {-10., 110.}, "centrality range: {min, max}, with convention: min <= cent < max"}; - Configurable> cfVertex_x{"cfVertex_x", {-10., 10.}, "vertex x position range: {min, max}[cm], with convention: min <= Vx < max"}; - Configurable> cfVertex_y{"cfVertex_y", {-10., 10.}, "vertex y position range: {min, max}[cm], with convention: min <= Vy < max"}; - Configurable> cfVertex_z{"cfVertex_z", {-10., 10.}, "vertex z position range: {min, max}[cm], with convention: min <= Vz < max"}; - Configurable> cfNContributors{"cfNContributors", {-1, 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 cfTrigger{"cfTrigger", "some supported trigger", "set here some supported trigger (kINT7, ...) "}; + 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> 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 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 cfCentralityEstimator{"cfCentralityEstimator", "some supported centrality estimator", "set here some supported centrality estimator (CentFT0M, CentFV0A, CentNTPV, ... for Run 3, and CentRun2V0M, CentRun2SPDTracklets, ..., for Run 2 and 1) "}; + 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 formula in the mandatory format \"p0 + p1*x\" for the upper boundary cut in RefMult_vs_NContr correlation"}; + Configurable cfRefMultVsNContrLow{"cfRefMultVsNContrLow", "-650. + 0.08*x", "set here some in the mandatory format \"p0 + p1*x\" 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\""}; + Configurable cfUseFT0Bad{"cfUseFT0Bad", false, "TBI 20250516 explanation (or see enum)"}; + Configurable cfUseITSBad{"cfUseITSBad", false, "TBI 20250516 explanation (or see enum)"}; + Configurable cfUseITSLimAccMCRepr{"cfUseITSLimAccMCRepr", false, "TBI 20250516 explanation (or see enum)"}; + Configurable cfUseTPCBadTracking{"cfUseTPCBadTracking", false, "TBI 20250516 explanation (or see enum)"}; + Configurable cfUseTPCLimAccMCRepr{"cfUseTPCLimAccMCRepr", false, "TBI 20250516 explanation (or see enum)"}; + Configurable cfUseTPCBadPID{"cfUseTPCBadPID", false, "TBI 20250516 explanation (or see enum)"}; } 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", {"Phi-1", "Pt-1", "Eta-1", "Charge-1", "tpcNClsFindable-1", "tpcNClsShared-1", "tpcNClsFound-1", "tpcNClsCrossedRows-1", "itsNCls-1", "itsNClsInnerBarrel-1", "tpcCrossedRowsOverFindableCls-1", "tpcFoundOverFindableCls-1", "tpcFractionSharedCls-1", "dcaXY-1", "dcaZ-1", "PDG-1"}, "Book (1) or do not book (0) particle histogram"}; - Configurable cfFillParticleHistograms2D{"cfFillParticleHistograms2D", true, "if false, all 2D particle histograms are not filled. if kTRUE, the ones for which fBookParticleHistograms2D[...] is kTRUE, are filled"}; - Configurable> cfBookParticleHistograms2D{"cfBookParticleHistograms2D", {"Phi_vs_Pt-1", "Phi_vs_Eta-1"}, "Book (1) or do not book (0) this 2D particle histogram"}; + 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", {"Phi-1", "Pt-1", "Eta-1", "Charge-1", "tpcNClsFindable-1", "tpcNClsShared-1", "tpcNClsFound-1", "tpcNClsCrossedRows-1", "itsNCls-1", "itsNClsInnerBarrel-1", "tpcCrossedRowsOverFindableCls-1", "tpcFoundOverFindableCls-1", "tpcFractionSharedCls-1", "dcaXY-1", "dcaZ-1", "PDG-1", "trackCutFlagFb1-0", "trackCutFlagFb2-0", "isQualityTrack-0", "isPrimaryTrack-0", "isInAcceptanceTrack-0", "isGlobalTrack-0", "PtDependentDCAxyParameterization-0"}, "Use (1) or do not use (0) particle cuts"}; + 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, TMath::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 <= eta < max"}; - Configurable> cftpcNClsShared{"cftpcNClsShared", {-1000., 1000.}, "tpcNClsShared range: {min, max}, with convention: min <= eta < max"}; - Configurable> cftpcNClsFound{"cftpcNClsFound", {-1000., 1000.}, "tpcNClsFound range: {min, max}, with convention: min <= eta < max"}; - Configurable> cftpcNClsCrossedRows{"cftpcNClsCrossedRows", {-1000., 1000.}, "tpcNClsCrossedRows range: {min, max}, with convention: min <= eta < max"}; - Configurable> cfitsNCls{"cfitsNCls", {-1000., 1000.}, "itsNCls range: {min, max}, with convention: min <= eta < max"}; - Configurable> cfitsNClsInnerBarrel{"cfitsNClsInnerBarrel", {-1000., 1000.}, "itsNClsInnerBarrel range: {min, max}, with convention: min <= eta < max"}; - Configurable> cftpcCrossedRowsOverFindableCls{"cftpcCrossedRowsOverFindableCls", {-1000., 1000.}, "tpcCrossedRowsOverFindableCls range: {min, max}, with convention: min <= eta < max"}; - Configurable> cftpcFoundOverFindableCls{"cftpcFoundOverFindableCls", {-1000., 1000.}, "tpcFoundOverFindableCls range: {min, max}, with convention: min <= eta < max"}; - Configurable> cftpcFractionSharedCls{"cftpcFractionSharedCls", {-1000., 1000.}, "tpcFractionSharedCls range: {min, max}, with convention: min <= eta < max"}; - Configurable> cfdcaXY{"cfdcaXY", {-1000., 1000.}, "dcaXY range: {min, max}, with convention: min <= eta < max"}; - Configurable> cfdcaZ{"cfdcaZ", {-1000., 1000.}, "dcaZ range: {min, max}, with convention: min <= eta < max"}; - Configurable> cfPDG{"cfPDG", {-5000., 5000.}, "PDG code"}; - Configurable cftrackCutFlagFb1{"cftrackCutFlagFb1", false, "TBI 20240510 add description"}; - Configurable cftrackCutFlagFb2{"cftrackCutFlagFb2", false, "TBI 20240510 add description"}; + 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", false, "TBI 20240510 add description"}; - Configurable cfisInAcceptanceTrack{"cfisInAcceptanceTrack", 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 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"}; + 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", false, "calculate or not Q-vectors (all, also diff. ones). If I want only to fill control histograms, then set here false"}; + 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> cfCalculateCorrelationsAsFunctionOf{"cfCalculateCorrelationsAsFunctionOf", {"1-Integrated", "1-Multiplicity", "1-Centrality", "0-Pt", "0-Eta", "1-Occupancy", "1-InteractionRate", "1-CurrentRunDuration", "1-Vz", "0-Charge"}, "calculate or not correlations as a function of specified variable"}; } cf_mupa; // *) Test0: struct : ConfigurableGroup { + + // 1D: 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 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> cfCalculateTest0AsFunctionOf{"cfCalculateTest0AsFunctionOf", {"1-Integrated", "1-Multiplicity", "1-Centrality", "1-Pt", "1-Eta", "1-Occupancy", "1-InteractionRate", "1-CurrentRunDuration", "1-Vz", "1-Charge"}, "calculate or not correlations as a function of specified variable"}; + + // 2D: + Configurable cfCalculate2DTest0{"cfCalculate2DTest0", false, "calculate or not 2D Test0 using TProfile2D"}; + Configurable> cfCalculate2DTest0AsFunctionOf{"cfCalculate2DTest0AsFunctionOf", {"1-Centrality_Pt", "1-Centrality_Eta", "1-Centrality_Charge", "1-Centrality_Vz", "1-Pt_Eta", "1-Pt_Charge", "1-Eta_Charge"}, "calculate or not correlations in 2D as a function of two specified variables."}; + + // 3D: + Configurable cfCalculate3DTest0{"cfCalculate3DTest0", false, "calculate or not 3D Test0 using TProfile3D"}; + Configurable> cfCalculate3DTest0AsFunctionOf{"cfCalculate3DTest0AsFunctionOf", {"1-Centrality_Pt_Eta", "1-Centrality_Pt_Charge", "1-Centrality_Pt_Vz", "1-Centrality_Eta_Vz", "1-Centrality_Eta_Charge", "1-Centrality_Vz_Charge", "1-Pt_Eta_Charge"}, "calculate or not correlations in 3D as a function of three specified variables."}; + + 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> cfCalculateEtaSeparationsAsFunctionOf{"cfCalculateEtaSeparationsAsFunctionOf", {"1-Integrated", "1-Multiplicity", "1-Centrality", "1-Pt", "0-Eta", "1-Occupancy", "1-InteractionRate", "1-CurrentRunDuration", "1-Vz", "1-Charge"}, "calculate or not correlations as a function of specified variable"}; + 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"}; @@ -147,9 +229,18 @@ struct : ConfigurableGroup { 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" + 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", {"0-wPt", "0-wCharge", "0-wCentrality"}, "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", {"0-wEta", "0-wCharge", "0-wCentrality"}, "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"}; @@ -160,10 +251,10 @@ struct : ConfigurableGroup { // *) 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" + 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: @@ -171,30 +262,46 @@ 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, set whether flow amplitudes are \"constant\" or \"correlared\""}; + 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}, "{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}, "{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"}; + Configurable cfRandomizeReactionPlane{"cfRandomizeReactionPlane", true, "set to false only when validating against theoretical value the non-isotropic correlators"}; + 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: +// *) 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"}; - Configurable> cfFixedLength_cent_bins{"cfFixedLength_cent_bins", {110, 0., 110.}, "nCentBins, centMin, centMax"}; - Configurable> cfFixedLength_pt_bins{"cfFixedLength_pt_bins", {1000, 0., 100.}, "nPtBins, ptMin, ptMax"}; - Configurable> cfFixedLength_eta_bins{"cfFixedLength_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 cfUseVariableLength_mult_bins{"cfUseVariableLength_mult_bins", false, "use or not variable-length multiplicity bins"}; - Configurable cfVariableLength_mult_bins{"cfVariableLength_mult_bins", "0.,100.,250.,1000.", "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", false, "use or not variable-length pt bins"}; - Configurable cfVariableLength_pt_bins{"cfVariableLength_pt_bins", "1.0,2.0,5.0", "variable-length pt bins"}; - Configurable cfUseVariableLength_eta_bins{"cfUseVariableLength_eta_bins", false, "use or not variable-length eta bins"}; - Configurable cfVariableLength_eta_bins{"cfVariableLength_eta_bins", "-0.8,-0.4,0.0,0.4,0.8", "variable-length eta bins"}; + Configurable> cfFixedLengthMultBins{"cfFixedLengthMultBins", {2000, 0., 20000.}, "nMultBins, multMin, multMax (only for results histograms)"}; + Configurable> cfFixedLengthCentBins{"cfFixedLengthCentBins", {110, 0., 110.}, "nCentBins, centMin, centMax (only for results histograms)"}; + Configurable> cfFixedLengthPtBins{"cfFixedLengthPtBins", {1000, 0., 10.}, "nPtBins, ptMin, ptMax (only for results histograms)"}; + Configurable> cfFixedLengthEtaBins{"cfFixedLengthEtaBins", {80, -2., 2.}, "nEtaBins, etaMin, etaMax (only for results histograms)"}; + Configurable> cfFixedLengthOccuBins{"cfFixedLengthOccuBins", {200, 0., 60000.}, "nOccuBins, occuMin, occuMax (only for results histograms)"}; + Configurable> cfFixedLengthIRBins{"cfFixedLengthIRBins", {1000, 0., 100.}, "nirBins, irMin, irMax (only for results histograms)"}; + Configurable> cfFixedLengthCRDBins{"cfFixedLengthCRDBins", {100000, 0., 100000.}, "ncrdBins, crdMin, crdMax (only for results histograms)"}; + Configurable> cfFixedLengthVzBins{"cfFixedLengthVzBins", {400, -20., 20.}, "nvzBins, vzMin, vzMax (only for results histograms)"}; + + // Variable-length binning (per request): + Configurable cfUseVariableLengthMultBins{"cfUseVariableLengthMultBins", false, "use or not variable-length multiplicity bins"}; + Configurable> cfVariableLengthMultBins{"cfVariableLengthMultBins", {0., 5., 6., 7., 8., 9., 100., 200., 500., 1000., 10000.}, "variable-length multiplicity bins"}; + Configurable cfUseVariableLengthCentBins{"cfUseVariableLengthCentBins", false, "use or not variable-length centrality bins"}; + Configurable> cfVariableLengthCentBins{"cfVariableLengthCentBins", {0., 10., 50., 100.}, "variable-length centrality bins"}; + Configurable cfUseVariableLengthPtBins{"cfUseVariableLengthPtBins", true, "use or not variable-length pt bins"}; + Configurable> cfVariableLengthPtBins{"cfVariableLengthPtBins", {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 cfUseVariableLengthEtaBins{"cfUseVariableLengthEtaBins", true, "use or not variable-length eta bins"}; + Configurable> cfVariableLengthEtaBins{"cfVariableLengthEtaBins", {-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 cfUseVariableLengthOccuBins{"cfUseVariableLengthOccuBins", false, "use or not variable-length occupancy bins"}; + Configurable> cfVariableLengthOccuBins{"cfVariableLengthOccuBins", {0., 5., 6., 7., 8., 9., 100., 200., 500., 1000., 10000.}, "variable-length occupancy bins"}; + Configurable cfUseVariableLengthIRBins{"cfUseVariableLengthIRBins", false, "use or not variable-length interaction rate bins"}; + Configurable> cfVariableLengthIRBins{"cfVariableLengthIRBins", {0., 5., 10., 50., 100., 200.}, "variable-length ineraction rate bins"}; + Configurable cfUseVariableLengthCRDBins{"cfUseVariableLengthCRDBins", false, "use or not variable-length current run duration bins"}; + Configurable> cfVariableLengthCRDBins{"cfVariableLengthCRDBins", {0., 5., 10., 50., 100., 500.}, "variable-length current run duration bins"}; + Configurable cfUseVariableLengthVzBins{"cfUseVariableLengthVzBins", false, "use or not variable-length vertex z bins"}; + Configurable> cfVariableLengthVzBins{"cfVariableLengthVzBins", {-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 2d4d7536cc6..fff7cd5fdee 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h @@ -9,9 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file MuPa-DataMembers.h +/// \brief ... TBI 20250425 +/// \author Ante.Bilandzic@cern.ch + #ifndef PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_DATAMEMBERS_H_ #define PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_DATAMEMBERS_H_ +#include + // General remarks: // 0. Starting with C++11, it's possible to initialize data members at declaration, so I do it here // 1. Use //! fBaseList{sBaseListName.Data(), OutputObjHandlingPolicy::AnalysisObject, OutputObjSourceType::OutputObjSource}; -TProfile* fBasePro = NULL; //! 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 + unsigned int 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 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 + TDatabasePDG* fDatabasePDG = NULL; // booked only when MC info is available. There is a standard memory blow-up when booked, therefore I need to request also fUseDatabasePDG = true + // TBI 20250625 replace eventually with the service O2DatabasePDG, when memory consumption problem is resolved + bool fUseSetBinLabel = false; // until SetBinLabel(...) large memory consumption is resolved, do not use hist->SetBinLabel(...), see ROOT Forum + // See also local executable PostprocessLabels.C + bool fUseClone = false; // until Clone(...) large memory consumption is resolved, do not use hist->Clone(...), see ROOT Forum + bool fUseFormula = false; // until TFormula large memory consumption is resolved, do not use, see ROOT Forum + bool fUseDatabasePDG = false; // I use it at the moment only to retreive charge for MC particle from its PDG code, because there is no direct getter mcParticle.sign() + // But most likely I will use it to retrieve other particle proprties from PDG table. There is a standard memory blow-up when used. +} 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. Value of the default centrality estimator, set via configurable cfCentralityEstimator -} 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, in reconstructed data. Value of the default centrality estimator, set via configurable cfCentralityEstimator + float fCentralitySim = 0.; // event-by-event centrality, in simulated data. Calculated directly from IP at the moment, eventually I will access it from o2::aod::hepmcheavyion::Centrality + 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 + float fImpactParameter = 0.; // calculated only for simulated/generated data +} ebye; // "ebye" is a common label for objects in this struct // *) QA: -// Remark: 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 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; //!>>>> fqvector; // dynamically allocated differential q-vector => it has to be done this way, to optimize memory usage + // dimensions: [eqvectorKine_N][gMaxNoBinsKine][gMaxHarmonic * gMaxCorrelator + 1][gMaxCorrelator + 1] + std::vector fNumberOfKineBins = {0}; // for each kine vector which was requested in this analysis, here I calculate and store the corresponding number of kine bins + std::vector> fqvectorEntries; // dynamically allocated number of entries for differential q-vector => it has to be done this way, to optimize memory usage + + // q-vectors for eta separations: + TComplex fQabVector[2][gMaxHarmonic][gMaxNumberEtaSeparations] = {{{TComplex(0., 0.)}}}; //! integrated [-eta or +eta][harmonic][eta separation] + float fMab[2][gMaxNumberEtaSeparations] = {{0.}}; //! multiplicities in 2 eta separated intervals + TH1F* fMabDist[2][2][2][gMaxNumberEtaSeparations] = {{{{NULL}}}}; // multiplicity distributions in A and B, for each eta separation [ A or B ] [rec or sim] [ before or after cuts ] [ eta separation value ] + std::vector>>>>> fqabVector; // dynamically allocated differential q-vector. + // dimensions: [-eta or +eta][eqvectorKine_N][global binNo][harmonic][eta separation] + // Remark: Unlike fqvector above, here I support only 2-p correlations, + // therefore no need for "[gMaxHarmonic * gMaxCorrelator + 1][gMaxCorrelator + 1]", etc. + std::vector>>> fmab; //! multiplicities vs kine in 2 eta separated intervals + // [-eta or +eta][eqvectorKine_N][global binNo][eta separation] +} qv; // "qv" is a common label for objects in this struct // *) Multiparticle correlations (standard, isotropic, same harmonic): struct MultiparticleCorrelations { TList* fCorrelationsList = NULL; // list to hold all correlations objects TProfile* fCorrelationsFlagsPro = NULL; // profile to hold all flags for correlations - Bool_t fCalculateCorrelations = kTRUE; // calculate and store integrated correlations + bool fCalculateCorrelations = false; // calculate and store integrated correlations TProfile* fCorrelationsPro[4][gMaxHarmonic][eAsFunctionOf_N] = {{{NULL}}}; //! multiparticle correlations - //! [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] + // [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,5=vs. occupancy, ...] + bool fCalculateCorrelationsAsFunctionOf[eAsFunctionOf_N] = {false}; //! [0=integrated,1=vs. multiplicity,2=vs. centrality,3=pT,4=eta,5=vs. occupancy, ...] + // As of 20241111, 3=pT and 4=eta are not implemented, see void CalculateKineCorrelations(...) } mupa; // "mupa" is a common label for objects in this struct // *) Particle weights: struct ParticleWeights { TList* fWeightsList = 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 = kFALSE; // calculate and store correlations with nested loops, as a cross-check - Bool_t fCalculateCustomNestedLoops = kFALSE; // validate e-b-e all correlations with custom nested loop - Bool_t fCalculateKineCustomNestedLoops = kFALSE; // validate e-b-e all differential (vs pt, eta, etc.) correlations with custom nested loop - Int_t fMaxNestedLoop = -1; // if set to e.g. 4, all nested loops beyond that, e.g. 6-p and 8-p, are NOT calculated + 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] + TArrayD* ftaNestedLoopsKine[eqvectorKine_N][gMaxNoBinsKine][2] = {{{NULL}}}; //! e-b-e container for nested loops // [0=pT,1=eta,2=...][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'): +// *) 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_t fApplyNUAPDF[eNUAPDF_N] = {kFALSE}; // apply NUA to particular kine variable (see the corresponding enum eNUAPDF) - Bool_t fUseDefaultNUAPDF[eNUAPDF_N] = {kTRUE}; // by default, use simple hardcoded expressions for NUA acceptance profile - TF1* fDefaultNUAPDF[eNUAPDF_N] = {NULL}; // default distributions used as pdfs to simulate events 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 + 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 + float 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_t fUseInternalValidation = kFALSE; // use internal validation - Bool_t fInternalValidationForceBailout = kFALSE; // force bailout after fnEventsInternalValidation is reached. In HL, for each real event, I do fnEventsInternalValidation events - UInt_t fnEventsInternalValidation = 0; // how many events will be sampled on-the-fly for internal validation - TString* fHarmonicsOptionInternalValidation = NULL; // see .cxx for full documentation - Bool_t fRescaleWithTheoreticalInput = kFALSE; // if kTRUE, all measured correlators are rescaled with theoretical input, so that in profiles everything is at 1 + 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. + unsigned int 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 + bool fRandomizeReactionPlane = true; // if true, RP is randomized e-by-e. I need false basically only when validating against theoretical input non-isotropic correlators TArrayD* fInternalValidationVnPsin[2] = {NULL}; // 0 = { v1, v2, ... }, 1 = { Psi1, Psi2, ... } - Int_t fMultRangeInternalValidation[2] = {0, 0}; // min and max values for uniform multiplicity distribution in on-the-fly analysis (convention: min <= M < max) + 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] + bool fCalculate2DTest0 = false; // calculate or not 2D Test0 + TProfile2D* fTest0Pro2D[gMaxCorrelator][gMaxIndex][eAsFunctionOf2D_N] = {{{NULL}}}; //! [order][index][0=cent vs pt, ..., see enum eAsFunctionOf2D] + bool fCalculate3DTest0 = false; // calculate or not 2D Test0 + TProfile3D* fTest0Pro3D[gMaxCorrelator][gMaxIndex][eAsFunctionOf3D_N] = {{{NULL}}}; //! [order][index][0=cent vs pt vs eta, ..., see enum eAsFunctionOf3D] + 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, ...] + bool fCalculate2DTest0AsFunctionOf[eAsFunctionOf2D_N] = {false}; //! [0=integrated,1=vs. multiplicity,2=vs. centrality,3=pT,4=eta,5=vs. occupancy, ...] + bool fCalculate3DTest0AsFunctionOf[eAsFunctionOf3D_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 +} 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 srsLong[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 sbaLong[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 sccLong[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; //!Clone() + eUseFormula, // Use or not class TFormula + eUseDatabasePDG, // Use or not class TDatabasePDG eConfiguration_N }; @@ -40,8 +56,10 @@ enum eProcess { eProcessRecSim_Run1, // Run 1, both reconstructed and simulated eProcessSim_Run1, // Run 1, only simulated eProcessTest, // minimum subscription to the tables, for testing purposes + eProcessQA, // maximum subscription to the tables, for QA purposes. Basically: eProcessRec + otherwise unnecessary tables + eProcessHepMChi, // special subscription when I extract info from the table HepMCHeavyIons TBI 20250429 merge this case eventualyl with RecSim cases // Generic flags, calculated and set from individual flags above in DefaultConfiguration(), AFTER process switch was taken into account: - eGenericRec, // generic "Rec" case, eTest is treated for the time being as "Rec" + eGenericRec, // generic "Rec" case, eTest is treated for the time being as "Rec". eQA is also in this category eGenericRecSim, // generic "RecSim" case eGenericSim, // generic "Sim" case eProcess_N @@ -56,7 +74,8 @@ enum eRecSim { eRec = 0, eRec_Run1, // converted Run 1 data eSim_Run1, eRecAndSim_Run1, - eTest }; + eTest, // remember that as of 20250315 I can use "cfWhichSpecificCuts": "Test" in JSON, to configure quickly all cuts for this case + eQA }; enum eBeforeAfter { eBefore = 0, // use this one for cuts eAfter = 1 }; @@ -74,72 +93,163 @@ enum eDefaultColors { eColor = kBlack, enum eWeights { wPHI = 0, wPT = 1, wETA = 2, + wCHARGE = 3, eWeights_N }; -enum eDiffWeights { +enum eDiffWeights { // TBI 20250215 this is now obsolete, superseeded with more general implementation, see enums eDiffWeightCategory, eDiffPhiWeights, etc. wPHIPT = 0, wPHIETA, + wPHICHARGE, eDiffWeights_N }; +enum eDiffWeightCategory { + eDWPhi = 0, // corresponds to eDiffPhiWeights structure, here the fundamental 0-th axis never to be projected out is "phi" + eDWPt, // corresponds to eDiffPtWeights structure, here the fundamental 0-th axis never to be projected out is "pt" + eDWEta, // corresponds to eDiffEtaWeights structure, here the fundamental 0-th axis never to be projected out is "eta" + // ... + eDiffWeightCategory_N +}; + +enum eDiffPhiWeights { + wPhiPhiAxis = 0, // this is the main axis in this category, the only axis which shall never be projected out. If I project out all remaining axes, I shall recover the standard integrated phi weights + wPhiPtAxis, + wPhiEtaAxis, + wPhiChargeAxis, + wPhiCentralityAxis, + wPhiVertexZAxis, + eDiffPhiWeights_N +}; + +enum eDiffPtWeights { + wPtPtAxis = 0, + wPtChargeAxis, + wPtCentralityAxis, + eDiffPtWeights_N +}; + +enum eDiffEtaWeights { + wEtaEtaAxis = 0, + wEtaChargeAxis, + wEtaCentralityAxis, + eDiffEtaWeights_N +}; + enum eVnPsin { eVn = 0, ePsin = 1 }; enum eEventHistograms { - eNumberOfEvents = 0, // Total events = eNumberOfEvents + eBefore, Selected events = eNumberOfEvents + eAfter - eTotalMultiplicity, - eSelectedTracks, - eMultFV0M, // ref. mult from helper task o2-analysis-multiplicity-table - eMultFT0M, // ref. mult from helper task o2-analysis-multiplicity-table - eMultTPC, // ref. mult from helper task o2-analysis-multiplicity-table - eMultNTracksPV, // ref. mult from helper task o2-analysis-multiplicity-table - eMultTracklets, // ref. mult from helper task o2-analysis-multiplicity-table, use only for Run 2 - eCentrality, // default centrality estimator - eVertex_x, - eVertex_y, - eVertex_z, + eNumberOfEvents = 0, // Total events = eNumberOfEvents + eBefore, Selected events = eNumberOfEvents + eAfter + eTotalMultiplicity, // TBI 20241123 I define it as tracks.size(), but most likely this I do not need this + eMultiplicity, // see documentation for ebye.fMultiplicity + eReferenceMultiplicity, // see documentation for ebye.fReferenceMultiplicity + eCentrality, // default centrality estimator + eVertexX, + eVertexY, + eVertexZ, eNContributors, // number of tracks used for the vertex eImpactParameter, + eEventPlaneAngle, + eOccupancy, // from helper task o2-analysis-event-selection, see also IA's presentation in https://indico.cern.ch/event/1464946, slide 38. Use specific occupancy estimator via eOccupancyEstimator + eInteractionRate, // from utility ctpRateFetcher . + eCurrentRunDuration, // calculated with utility ctpRateFetcher + eMultMCNParticlesEta08, // from helper task table o2::aod::MultMCExtras eEventHistograms_N }; enum eEventCuts { - // a) For available event selection bits, check https://github.com/ekryshen/O2Physics/blob/ede841e3d9037919680f34acc1d555dfc6d5df55/Common/CCDB/EventSelectionParams.cxx - // b) Some settings are configurable, check: https://github.com/ekryshen/O2Physics/blob/master/Common/TableProducer/eventSelection.cxx#L44 - eTrigger = eEventHistograms_N, // Do NOT use eTrigger for Run 3. Validated only for Run 2, and it has to be "kINT7" . TBI 20240522 investigate for Run 1 - eSel7, // Event selection decision based on V0A & V0C => use only in Run 2 and Run 1. TBI 20240522 I stil need to validate this one over MC - eSel8, // 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 def. of sel8 in Ref. a) - // See also email from EK from 20240410 - eCentralityEstimator, // the default centrality estimator, set via configurable. All supported centrality estimatos, 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) - 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 + // a) For available event selection bits, check https://github.com/AliceO2Group/O2Physics/blob/master/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + // b) Some settings are configurable, check: https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/eventSelection.cxx + eTrigger = eEventHistograms_N, // Implemented and validated so far: + // a) Run 3: "kTVXinTRD" (use optionally for systematics, and only in real data) + // b) Run 2: "kINT7" (at the moment there is a warning if not used in real data.). Not validated in Monte Carlo. + // c) Run 1: TBI 20241209 check if I can use kINT7 also for Run 1 + eSel7, // See def. of sel7 in Ref. b) above. Event selection decision based on V0A & V0C => 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 + + // RCT flags, see https://indico.cern.ch/event/1545907/ + up-to-date code in Common/CCDB/RCTSelectionFlags.h + // Remark 1: For the time being, I support here differentially 6 flags used to define the combined "CBT" flag, see if (label == "CBT") in Common/CCDB/RCTSelectionFlags.h + // Remark 2: If I want to use directly the combined "CBT" flag, see how it can be done using RCTFlagsChecker in + // https://github.com/AliceO2Group/O2Physics/blob/master/DPG/Tasks/AOTEvent/timeDependentQa.cxx#L115 + // But check before the memory status after RCTFlagsChecker is used. + eFT0Bad, + eITSBad, + eITSLimAccMCRepr, + eTPCBadTracking, + eTPCLimAccMCRepr, + eTPCBadPID, + // ... + 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 collision vertex) + // from o2::aod::Tracks (Track parameters at their point closest to the collision vertex) ePhi = 0, ePt, eEta, eCharge, // Charge: positive: 1, negative: -1 - // from o2::aod::TracksExtra_001 + // 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, + 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, @@ -159,29 +269,92 @@ enum eParticleHistograms2D { // All 2D histograms are first implemented in eQAPa enum eParticleCuts { - // from o2::aod::TrackSelection - etrackCutFlagFb1 = eParticleHistograms_N, // do not use in Run 2 and 1 - etrackCutFlagFb2, // do not use in Run 2 and 1 - eisQualityTrack, // not validated in Run 3, but it can be used in Run 2 and Run 1 (for the latter, it yields to large NUA) - eisPrimaryTrack, - eisInAcceptanceTrack, // TBI 20240516 check and document how acceptance window is defined - eisGlobalTrack, // not validated in Run 3, but it can be used in Run 2 and Run 1 (for the latter, it yields to real holes in NUA) - + // 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 { +enum eAsFunctionOf { // this is a specific enum only for 1D dependence + // 1D: 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" + AFO_CHARGE, // vs. "particle charge" + // ... eAsFunctionOf_N }; // prefix is needed, to avoid conflict with enum eKinematics +enum eAsFunctionOf2D { // this is a specific enum only for 2D dependence + // 2D: + AFO_CENTRALITY_PT = 0, + AFO_CENTRALITY_ETA, + AFO_CENTRALITY_CHARGE, + AFO_CENTRALITY_VZ, + AFO_PT_ETA, + AFO_PT_CHARGE, + AFO_ETA_CHARGE, + // ... + eAsFunctionOf2D_N +}; + +enum eAsFunctionOf3D { // this is a specific enum only for 3D dependence + // 3D: + AFO_CENTRALITY_PT_ETA = 0, + AFO_CENTRALITY_PT_CHARGE, + AFO_CENTRALITY_PT_VZ, + AFO_CENTRALITY_ETA_VZ, + AFO_CENTRALITY_ETA_CHARGE, + AFO_CENTRALITY_VZ_CHARGE, + AFO_PT_ETA_CHARGE, + // ... + eAsFunctionOf3D_N +}; + enum eNUAPDF { ePhiNUAPDF = 0, ePtNUAPDF, @@ -190,8 +363,21 @@ enum eNUAPDF { }; enum eqvectorKine { // Here "kine" originally meant "kinematic", i.e. vs. pt or vs. eta, now it's general. + // 1D: PTq = 0, ETAq, + CHARGEq, + // ... + + // 2D: // Yes, I linearize 2D case, in an analogy with "global bin" structure for multidimensional histograms. + PT_ETAq, + PT_CHARGEq, + ETA_CHARGEq, + // ... + + // 3D: // Yes, I linearize 3D case, in an analogy with "global bin" structure for multidimensional histograms. + PT_ETA_CHARGEq, + // ... eqvectorKine_N }; @@ -201,7 +387,7 @@ enum eTimer { eTimer_N }; -enum eEventCounter { +enum eEventCounterForDryRun { eFill = 0, ePrint }; @@ -220,32 +406,213 @@ enum eCutCounter { }; enum eQAEventHistograms2D { - // Common: - eMultTPC_vs_NContributors = 0, - eVertex_z_vs_MultTPC, - eVertex_z_vs_NContributors, - // Run 3: - eCentFT0M_vs_CentNTPV, - // Run 2 (do not use in Run 1 converted, because there is no centrality information): - eCentRun2V0M_vs_CentRun2SPDTracklets, - eCentRun2V0M_vs_NContributors, + // 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, + eCentrality_vs_CentralitySim, // correlation between centrality determined from reconstructed data, and centrality determined at generated level (from IP). I save it as [eSim], not as [eRec] + // ... eQAEventHistograms2D_N }; enum eQAParticleHistograms2D { - edcaXY_vs_Pt, + 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: - eCentFT0M = 0, + 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..adacaf76282 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-GlobalConstants.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-GlobalConstants.h @@ -9,13 +9,19 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file MuPa-GlobalConstants.h +/// \brief ... TBI 20250425 +/// \author Ante.Bilandzic@cern.ch + #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 50eec12c14c..bd4bca81735 100644 --- a/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h +++ b/PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h @@ -9,84 +9,234 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file MuPa-MemberFunctions.h +/// \brief ... TBI 20250425 +/// \author Ante.Bilandzic@cern.ch + #ifndef PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_MEMBERFUNCTIONS_H_ #define PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_MEMBERFUNCTIONS_H_ // ... -#include #include +#include //============================================================ -void BookBaseList() +void bookBaseList() { - // ... + // Book base TList and store task configuration. + + // a) Book base TList; + // b) Book base profile fBasePro to hold task configuration; + // c) Define bin labels directly via SetBinLabel(...); + // d) Define bin labels indirectly by storing them in y-axis title + local executable PostprocessLabels.C. + // Algorithm: y-axis title is formatted with respect to 2 IFS, ":" and ";" as follows "1:first-bin-label; 2:second-bin-label; ..." + // Then, I tokenize with respect to ";" to get bin number and corresponding bin label. + // In the final step, I tokenize with respect to ":" to disentangle bin number and its bin label; + // e) Add configured base TProfile to the list. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __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.5, 0.5 + static_cast(eConfiguration_N)); - fBasePro->SetStats(kFALSE); + // b) Book base profile to hold 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 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(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 DetermineAndPropagateRunNumber(T const& collision) + if (tc.fUseSetBinLabel) { + + // c) Define bin labels directly via SetBinLabel(...): + fBasePro->GetXaxis()->SetBinLabel(eTaskIsConfiguredFromJson, TString::Format("fTaskIsConfiguredFromJson = %s", tc.fTaskIsConfiguredFromJson.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, static_cast(tc.fDryRun)); + + fBasePro->GetXaxis()->SetBinLabel(eVerbose, "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, 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, static_cast(tc.fDoAdditionalInsanityChecks)); + + 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(eRandomSeed, "fRandomSeed"); + fBasePro->Fill(eRandomSeed, static_cast(tc.fRandomSeed)); + + fBasePro->GetXaxis()->SetBinLabel(eUseFisherYates, "fUseFisherYates"); + fBasePro->Fill(eUseFisherYates, static_cast(tc.fUseFisherYates)); + + fBasePro->GetXaxis()->SetBinLabel(eFixedNumberOfRandomlySelectedTracks, "fFixedNumberOfRandomlySelectedTracks"); + fBasePro->Fill(eFixedNumberOfRandomlySelectedTracks, static_cast(tc.fFixedNumberOfRandomlySelectedTracks)); + + fBasePro->GetXaxis()->SetBinLabel(eUseStopwatch, "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())); + + fBasePro->GetXaxis()->SetBinLabel(eUseSetBinLabel, "fUseSetBinLabel"); + fBasePro->Fill(eUseSetBinLabel, static_cast(tc.fUseSetBinLabel)); + + fBasePro->GetXaxis()->SetBinLabel(eUseClone, "fUseClone"); + fBasePro->Fill(eUseClone, static_cast(tc.fUseClone)); + + fBasePro->GetXaxis()->SetBinLabel(eUseFormula, "fUseFormula"); + fBasePro->Fill(eUseFormula, static_cast(tc.fUseFormula)); + + fBasePro->GetXaxis()->SetBinLabel(eUseDatabasePDG, "fUseDatabasePDG"); + fBasePro->Fill(eUseDatabasePDG, static_cast(tc.fUseDatabasePDG)); + + } else { + + // d) Define bin labels indirectly by storing them in y-axis title + local executable PostprocessLabels.C. + // Algorithm is documented in the function preamble above. + + TString yAxisTitle = ""; + yAxisTitle += TString::Format("%d:fTaskIsConfiguredFromJson = %s; ", static_cast(eTaskIsConfiguredFromJson), tc.fTaskIsConfiguredFromJson.Data()); + + yAxisTitle += TString::Format("%d:fTaskName = %s; ", static_cast(eTaskName), tc.fTaskName.Data()); + + yAxisTitle += TString::Format("%d:fRunNumber = %s; ", static_cast(eRunNumber), "__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(...) + + yAxisTitle += TString::Format("%d:fDryRun; ", static_cast(eDryRun)); + fBasePro->Fill(eDryRun, static_cast(tc.fDryRun)); + + yAxisTitle += TString::Format("%d:fVerbose; ", static_cast(eVerbose)); + fBasePro->Fill(eVerbose, static_cast(tc.fVerbose)); + + yAxisTitle += TString::Format("%d:fVerboseUtility; ", static_cast(eVerboseUtility)); + fBasePro->Fill(eVerboseUtility, static_cast(tc.fVerboseUtility)); + + yAxisTitle += TString::Format("%d:fVerboseForEachParticle; ", static_cast(eVerboseForEachParticle)); + fBasePro->Fill(eVerboseForEachParticle, static_cast(tc.fVerboseForEachParticle)); + + yAxisTitle += TString::Format("%d:fVerboseEventCounter; ", static_cast(eVerboseEventCounter)); + fBasePro->Fill(eVerboseEventCounter, static_cast(tc.fVerboseEventCounter)); + + yAxisTitle += TString::Format("%d:fPlainPrintout; ", static_cast(ePlainPrintout)); + fBasePro->Fill(ePlainPrintout, static_cast(tc.fPlainPrintout)); + + yAxisTitle += TString::Format("%d:fDoAdditionalInsanityChecks; ", static_cast(eDoAdditionalInsanityChecks)); + fBasePro->Fill(eDoAdditionalInsanityChecks, static_cast(tc.fDoAdditionalInsanityChecks)); + + yAxisTitle += TString::Format("%d:fInsanityCheckForEachParticle; ", static_cast(eInsanityCheckForEachParticle)); + fBasePro->Fill(eInsanityCheckForEachParticle, static_cast(tc.fInsanityCheckForEachParticle)); + + yAxisTitle += TString::Format("%d:fWhichProcess = %s; ", static_cast(eWhichProcess), tc.fWhichProcess.Data()); + + yAxisTitle += TString::Format("%d:fRandomSeed; ", static_cast(eRandomSeed)); + fBasePro->Fill(eRandomSeed, static_cast(tc.fRandomSeed)); + + yAxisTitle += TString::Format("%d:fUseFisherYates; ", static_cast(eUseFisherYates)); + fBasePro->Fill(eUseFisherYates, static_cast(tc.fUseFisherYates)); - fBasePro->GetXaxis()->SetBinLabel(eDryRun, "fDryRun"); - fBasePro->Fill(eDryRun, static_cast(tc.fDryRun)); + yAxisTitle += TString::Format("%d:fFixedNumberOfRandomlySelectedTracks; ", static_cast(eFixedNumberOfRandomlySelectedTracks)); + fBasePro->Fill(eFixedNumberOfRandomlySelectedTracks, static_cast(tc.fFixedNumberOfRandomlySelectedTracks)); - fBasePro->GetXaxis()->SetBinLabel(eVerbose, "fVerbose"); - fBasePro->Fill(eVerbose, static_cast(tc.fVerbose)); + yAxisTitle += TString::Format("%d:fUseStopwatch; ", static_cast(eUseStopwatch)); + fBasePro->Fill(eUseStopwatch, static_cast(tc.fUseStopwatch)); - fBasePro->GetXaxis()->SetBinLabel(eVerboseForEachParticle, "fVerboseForEachParticle"); - fBasePro->Fill(eVerboseForEachParticle, static_cast(tc.fVerboseForEachParticle)); + yAxisTitle += TString::Format("%d:fFloatingPointPrecision; ", static_cast(eFloatingPointPrecision)); + fBasePro->Fill(eFloatingPointPrecision, static_cast(tc.fFloatingPointPrecision)); - fBasePro->GetXaxis()->SetBinLabel(eDoAdditionalInsanityChecks, "fDoAdditionalInsanityChecks"); - fBasePro->Fill(eDoAdditionalInsanityChecks, static_cast(tc.fDoAdditionalInsanityChecks)); + yAxisTitle += TString::Format("%d:fSequentialBailout; ", static_cast(eSequentialBailout)); + fBasePro->Fill(eSequentialBailout, static_cast(tc.fSequentialBailout)); - fBasePro->GetXaxis()->SetBinLabel(eInsanityCheckForEachParticle, "fInsanityCheckForEachParticle"); - fBasePro->Fill(eInsanityCheckForEachParticle, static_cast(tc.fInsanityCheckForEachParticle)); + yAxisTitle += TString::Format("%d:fUseSpecificCuts; ", static_cast(eUseSpecificCuts)); + fBasePro->Fill(eUseSpecificCuts, static_cast(tc.fUseSpecificCuts)); - fBasePro->GetXaxis()->SetBinLabel(eUseCCDB, "fUseCCDB"); - fBasePro->Fill(eUseCCDB, static_cast(tc.fUseCCDB)); + yAxisTitle += TString::Format("%d:fWhichSpecificCuts = %s; ", static_cast(eWhichSpecificCuts), tc.fWhichSpecificCuts.Data()); - fBasePro->GetXaxis()->SetBinLabel(eWhichProcess, Form("WhichProcess = %s", tc.fWhichProcess.Data())); + yAxisTitle += TString::Format("%d:fSkipTheseRuns = %s; ", static_cast(eSkipTheseRuns), tc.fSkipTheseRuns.Data()); - fBasePro->GetXaxis()->SetBinLabel(eRandomSeed, "fRandomSeed"); - fBasePro->Fill(eRandomSeed, static_cast(tc.fRandomSeed)); + yAxisTitle += TString::Format("%d:fUseSetBinLabel; ", static_cast(eUseSetBinLabel)); + fBasePro->Fill(eUseSetBinLabel, static_cast(tc.fUseSetBinLabel)); - fBasePro->GetXaxis()->SetBinLabel(eUseFisherYates, "fUseFisherYates"); - fBasePro->Fill(eUseFisherYates, static_cast(tc.fUseFisherYates)); + yAxisTitle += TString::Format("%d:fUseClone; ", static_cast(eUseClone)); + fBasePro->Fill(eUseClone, static_cast(tc.fUseClone)); - fBasePro->GetXaxis()->SetBinLabel(eFixedNumberOfRandomlySelectedTracks, "fFixedNumberOfRandomlySelectedTracks"); - fBasePro->Fill(eFixedNumberOfRandomlySelectedTracks, static_cast(tc.fFixedNumberOfRandomlySelectedTracks)); + yAxisTitle += TString::Format("%d:fUseFormula; ", static_cast(eUseFormula)); + fBasePro->Fill(eUseFormula, static_cast(tc.fUseFormula)); - fBasePro->GetXaxis()->SetBinLabel(eUseStopwatch, "fUseStopwatch"); - fBasePro->Fill(eUseStopwatch, static_cast(tc.fUseStopwatch)); + yAxisTitle += TString::Format("%d:fUseDatabasePDG; ", static_cast(eUseDatabasePDG)); + fBasePro->Fill(eUseDatabasePDG, static_cast(tc.fUseDatabasePDG)); + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() != static_cast(eConfiguration_N)) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() = %d != eConfiguration_N = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), static_cast(eConfiguration_N)); + } + delete oa; + + // *) Okay, set the title: + fBasePro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + + // e) Add configured base TProfile to the list: fBaseList->Add(fBasePro); -} // void BookBaseList() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void bookBaseList() //============================================================ -void DefaultConfiguration() +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. @@ -113,15 +263,20 @@ void DefaultConfiguration() // *) 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", __FUNCTION__); // yes, here + 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; - tc.fUseCCDB = cf_tc.cfUseCCDB; // Set automatically what to process, from an implicit variable "doprocessSomeProcessName" within a PROCESS_SWITCH clause: tc.fProcess[eProcessRec] = doprocessRec; tc.fProcess[eProcessRecSim] = doprocessRecSim; @@ -133,6 +288,8 @@ void DefaultConfiguration() tc.fProcess[eProcessRecSim_Run1] = doprocessRecSim_Run1; tc.fProcess[eProcessSim_Run1] = doprocessSim_Run1; tc.fProcess[eProcessTest] = doprocessTest; + tc.fProcess[eProcessQA] = doprocessQA; + tc.fProcess[eProcessHepMChi] = doprocessHepMChi; // Temporarary bailout protection against cases which are not implemented/validated yet: if (tc.fProcess[eProcessSim]) { @@ -156,7 +313,7 @@ void DefaultConfiguration() } // Set automatically generic flags, from above individual flags: - tc.fProcess[eGenericRec] = tc.fProcess[eProcessRec] || tc.fProcess[eProcessRec_Run2] || tc.fProcess[eProcessRec_Run1] || tc.fProcess[eProcessTest]; + 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]; @@ -181,29 +338,44 @@ void DefaultConfiguration() tc.fWhichProcess = "ProcessSim_Run1"; } else if (tc.fProcess[eProcessTest]) { tc.fWhichProcess = "ProcessTest"; + } else if (tc.fProcess[eProcessQA]) { + tc.fWhichProcess = "ProcessQA"; + } else if (tc.fProcess[eProcessHepMChi]) { + tc.fWhichProcess = "ProcessHepMChi"; } tc.fRandomSeed = cf_tc.cfRandomSeed; tc.fUseFisherYates = cf_tc.cfUseFisherYates; tc.fFixedNumberOfRandomlySelectedTracks = cf_tc.cfFixedNumberOfRandomlySelectedTracks; tc.fUseStopwatch = cf_tc.cfUseStopwatch; - - // *) Event histograms: + 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; + tc.fUseSetBinLabel = cf_tc.cfUseSetBinLabel; + tc.fUseClone = cf_tc.cfUseClone; + tc.fUseFormula = cf_tc.cfUseFormula; + tc.fUseDatabasePDG = cf_tc.cfUseDatabasePDG; + + // *) Event histograms (for QA see below): eh.fEventHistogramsName[eNumberOfEvents] = "NumberOfEvents"; eh.fEventHistogramsName[eTotalMultiplicity] = "TotalMultiplicity"; - eh.fEventHistogramsName[eSelectedTracks] = "SelectedTracks"; - eh.fEventHistogramsName[eMultFV0M] = "MultFV0M"; - eh.fEventHistogramsName[eMultFT0M] = "MultFT0M"; - eh.fEventHistogramsName[eMultTPC] = "MultTPC"; - eh.fEventHistogramsName[eMultNTracksPV] = "MultNTracksPV"; - eh.fEventHistogramsName[eMultTracklets] = "MultTracklets"; + eh.fEventHistogramsName[eMultiplicity] = "Multiplicity"; + eh.fEventHistogramsName[eReferenceMultiplicity] = "ReferenceMultiplicity"; eh.fEventHistogramsName[eCentrality] = "Centrality"; - eh.fEventHistogramsName[eVertex_x] = "Vertex_x"; - eh.fEventHistogramsName[eVertex_y] = "Vertex_y"; - eh.fEventHistogramsName[eVertex_z] = "Vertex_z"; + eh.fEventHistogramsName[eVertexX] = "VertexX"; + eh.fEventHistogramsName[eVertexY] = "VertexY"; + eh.fEventHistogramsName[eVertexZ] = "VertexZ"; eh.fEventHistogramsName[eNContributors] = "NContributors"; eh.fEventHistogramsName[eImpactParameter] = "ImpactParameter"; - for (Int_t t = 0; t < eEventHistograms_N; t++) { + 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)); } @@ -217,41 +389,68 @@ void DefaultConfiguration() // Set names of all event cuts: ec.fEventCutName[eNumberOfEvents] = "NumberOfEvents"; ec.fEventCutName[eTotalMultiplicity] = "TotalMultiplicity"; - ec.fEventCutName[eSelectedTracks] = "SelectedTracks"; - ec.fEventCutName[eMultFV0M] = "MultFV0M"; - ec.fEventCutName[eMultFT0M] = "MultFT0M"; - ec.fEventCutName[eMultTPC] = "MultTPC"; - ec.fEventCutName[eMultNTracksPV] = "MultNTracksPV"; - ec.fEventCutName[eMultTracklets] = "MultTracklets"; + ec.fEventCutName[eMultiplicity] = "Multiplicity"; + ec.fEventCutName[eReferenceMultiplicity] = "ReferenceMultiplicity"; ec.fEventCutName[eCentrality] = "Centrality"; - ec.fEventCutName[eVertex_x] = "Vertex_x"; - ec.fEventCutName[eVertex_y] = "Vertex_y"; - ec.fEventCutName[eVertex_z] = "Vertex_z"; + 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"; - for (Int_t t = 0; t < eEventCuts_N; t++) { + 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[eFT0Bad] = "FT0Bad"; + ec.fEventCutName[eITSBad] = "ITSBad"; + ec.fEventCutName[eITSLimAccMCRepr] = "ITSLimAccMCRepr"; + ec.fEventCutName[eTPCBadTracking] = "TPCBadTracking"; + ec.fEventCutName[eTPCLimAccMCRepr] = "TPCLimAccMCRepr"; + ec.fEventCutName[eTPCBadPID] = "TPCBadPID"; + 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: + // *) 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"; @@ -259,19 +458,20 @@ void DefaultConfiguration() 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 t = 0; t < eParticleHistograms_N; t++) { + 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: + // *) 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 t = 0; t < eParticleHistograms2D_N; t++) { + 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); } @@ -288,6 +488,7 @@ void DefaultConfiguration() 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"; @@ -295,17 +496,20 @@ void DefaultConfiguration() 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 t = 0; t < eParticleCuts_N; t++) { + 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); } @@ -317,31 +521,187 @@ void DefaultConfiguration() // *) Multiparticle correlations: mupa.fCalculateCorrelations = cf_mupa.cfCalculateCorrelations; + // *) Use configurable array cfCalculateCorrelationsAsFunctionOf, to specify vs which observable correlations will be calculated (flags 1 or 0). + // Supported format: "0-someName" and "1-someName", where "-" is a field separator. + // Ordering of the flags in that array is interpreted through ordering of enums in enum eAsFunctionOf. + auto lCalculateCorrelationsAsFunctionOf = cf_mupa.cfCalculateCorrelationsAsFunctionOf.value; // this is now the local version of that string array from configurable. + if (lCalculateCorrelationsAsFunctionOf.size() != eAsFunctionOf_N) { + LOGF(info, "\033[1;31m lCalculateCorrelationsAsFunctionOf.size() = %d\033[0m", lCalculateCorrelationsAsFunctionOf.size()); + LOGF(info, "\033[1;31m eAsFunctionOf_N) = %d\033[0m", static_cast(eAsFunctionOf_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfCalculateCorrelationsAsFunctionOf, and number of entries in enum eAsFunctionOf_N \n \033[0m", __FUNCTION__, __LINE__); + } + + // I append "&& mupa.fCalculateCorrelations" below, to switch off calculation of all correlations with one common flag: + mupa.fCalculateCorrelationsAsFunctionOf[AFO_INTEGRATED] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_INTEGRATED]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_MULTIPLICITY] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_MULTIPLICITY]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_CENTRALITY] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_CENTRALITY]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_PT] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_PT]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_ETA]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_OCCUPANCY] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_OCCUPANCY]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_INTERACTIONRATE] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_INTERACTIONRATE]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_CURRENTRUNDURATION] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_CURRENTRUNDURATION]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_VZ] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_VZ]) && mupa.fCalculateCorrelations; + mupa.fCalculateCorrelationsAsFunctionOf[AFO_CHARGE] = Alright(lCalculateCorrelationsAsFunctionOf[AFO_CHARGE]) && mupa.fCalculateCorrelations; + // ... + // *) Test0: - // TBI 20250506 Implemented this way, I miss possibility to switch off all Test0 flags in one go. Re-think if i really need that. - t0.fCalculateTest0 = cf_t0.cfCalculateTest0; // + see below, how it's automatically set via other Test0 flags - t0.fCalculateTest0AsFunctionOf[AFO_INTEGRATED] = cf_t0.cfCalculateTest0AsFunctionOfIntegrated; - t0.fCalculateTest0AsFunctionOf[AFO_MULTIPLICITY] = cf_t0.cfCalculateTest0AsFunctionOfMultiplicity; - t0.fCalculateTest0AsFunctionOf[AFO_CENTRALITY] = cf_t0.cfCalculateTest0AsFunctionOfCentrality; - t0.fCalculateTest0AsFunctionOf[AFO_PT] = cf_t0.cfCalculateTest0AsFunctionOfPt; - t0.fCalculateTest0AsFunctionOf[AFO_ETA] = cf_t0.cfCalculateTest0AsFunctionOfEta; - // Use above Test0 flags to automatically set the main Test0 flag: TBI 20240521 do I really want to do it this way? - 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 - } - } - t0.fFileWithLabels = TString(cf_t0.cfFileWithLabels); + // 1D: + t0.fCalculateTest0 = cf_t0.cfCalculateTest0; + + // *) Use configurable array cfCalculateTest0AsFunctionOf, to specify vs which observable Test0 will be calculated (flags 1 or 0). + // Supported format: "0-someName" and "1-someName", where "-" is a field separator. + // Ordering of the flags in that array is interpreted through ordering of enums in enum eAsFunctionOf. + auto lCalculateTest0AsFunctionOf = cf_t0.cfCalculateTest0AsFunctionOf.value; // this is now the local version of that string array from configurable. + if (lCalculateTest0AsFunctionOf.size() != eAsFunctionOf_N) { + LOGF(info, "\033[1;31m lCalculateTest0AsFunctionOf.size() = %d\033[0m", lCalculateTest0AsFunctionOf.size()); + LOGF(info, "\033[1;31m eAsFunctionOf_N) = %d\033[0m", static_cast(eAsFunctionOf_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfCalculateTest0AsFunctionOf, and number of entries in enum eAsFunctionOf_N \n \033[0m", __FUNCTION__, __LINE__); + } + + // I append "&& t0.fCalculateTest0" below, to switch off calculation of all Test0 with one common flag: + t0.fCalculateTest0AsFunctionOf[AFO_INTEGRATED] = Alright(lCalculateTest0AsFunctionOf[AFO_INTEGRATED]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_MULTIPLICITY] = Alright(lCalculateTest0AsFunctionOf[AFO_MULTIPLICITY]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_CENTRALITY] = Alright(lCalculateTest0AsFunctionOf[AFO_CENTRALITY]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_PT] = Alright(lCalculateTest0AsFunctionOf[AFO_PT]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_ETA] = Alright(lCalculateTest0AsFunctionOf[AFO_ETA]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_OCCUPANCY] = Alright(lCalculateTest0AsFunctionOf[AFO_OCCUPANCY]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_INTERACTIONRATE] = Alright(lCalculateTest0AsFunctionOf[AFO_INTERACTIONRATE]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_CURRENTRUNDURATION] = Alright(lCalculateTest0AsFunctionOf[AFO_CURRENTRUNDURATION]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_VZ] = Alright(lCalculateTest0AsFunctionOf[AFO_VZ]) && t0.fCalculateTest0; + t0.fCalculateTest0AsFunctionOf[AFO_CHARGE] = Alright(lCalculateTest0AsFunctionOf[AFO_CHARGE]) && t0.fCalculateTest0; + // ... + + // 2D: + t0.fCalculate2DTest0 = cf_t0.cfCalculate2DTest0; + + // *) Use configurable array cfCalculate2DTest0AsFunctionOf, to specify vs which two observables Test0 will be calculated (flags 1 or 0). + // Supported format: "0-someName1_someName_2" and "1-someName1_someName_2", where both "-" and "_" are IFS, but with different meaning. + // Ordering of the flags in that array is interpreted through ordering of enums in enum eAsFunctionOf2D_N. + auto lCalculate2DTest0AsFunctionOf = cf_t0.cfCalculate2DTest0AsFunctionOf.value; // this is now the local version of that string array from configurable. + if (lCalculate2DTest0AsFunctionOf.size() != eAsFunctionOf2D_N) { + LOGF(info, "\033[1;31m lCalculate2DTest0AsFunctionOf.size() = %d\033[0m", lCalculate2DTest0AsFunctionOf.size()); + LOGF(info, "\033[1;31m eAsFunctionOf2D_N) = %d\033[0m", static_cast(eAsFunctionOf2D_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfCalculate2DTest0AsFunctionOf, and number of entries in enum eAsFunctionOf2D_N \n \033[0m", __FUNCTION__, __LINE__); + } + + // I append "&& t0.fCalculate2DTest0" below, to switch off calculation of all Test0 with one common flag: + t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_PT] = Alright(lCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_PT]) && t0.fCalculate2DTest0; + t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_ETA] = Alright(lCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_ETA]) && t0.fCalculate2DTest0; + t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_CHARGE] = Alright(lCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_CHARGE]) && t0.fCalculate2DTest0; + t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_VZ] = Alright(lCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_VZ]) && t0.fCalculate2DTest0; + t0.fCalculate2DTest0AsFunctionOf[AFO_PT_ETA] = Alright(lCalculate2DTest0AsFunctionOf[AFO_PT_ETA]) && t0.fCalculate2DTest0; + t0.fCalculate2DTest0AsFunctionOf[AFO_PT_CHARGE] = Alright(lCalculate2DTest0AsFunctionOf[AFO_PT_CHARGE]) && t0.fCalculate2DTest0; + t0.fCalculate2DTest0AsFunctionOf[AFO_ETA_CHARGE] = Alright(lCalculate2DTest0AsFunctionOf[AFO_ETA_CHARGE]) && t0.fCalculate2DTest0; + + // ... + + // 3D: + t0.fCalculate3DTest0 = cf_t0.cfCalculate3DTest0; + + // *) Use configurable array cfCalculate3DTest0AsFunctionOf, to specify vs which two observables Test0 will be calculated (flags 1 or 0). + // Supported format: "0-someName1_someName_2" and "1-someName1_someName_2", where both "-" and "_" are IFS, but with different meaning. + // Ordering of the flags in that array is interpreted through ordering of enums in enum eAsFunctionOf3D_N. + auto lCalculate3DTest0AsFunctionOf = cf_t0.cfCalculate3DTest0AsFunctionOf.value; // this is now the local version of that string array from configurable. + if (lCalculate3DTest0AsFunctionOf.size() != eAsFunctionOf3D_N) { + LOGF(info, "\033[1;31m lCalculate3DTest0AsFunctionOf.size() = %d\033[0m", lCalculate3DTest0AsFunctionOf.size()); + LOGF(info, "\033[1;31m eAsFunctionOf3D_N) = %d\033[0m", static_cast(eAsFunctionOf3D_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfCalculate3DTest0AsFunctionOf, and number of entries in enum eAsFunctionOf3D_N \n \033[0m", __FUNCTION__, __LINE__); + } + + // I append "&& t0.fCalculate3DTest0" below, to switch off calculation of all Test0 with one common flag: + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_ETA] = Alright(lCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_ETA]) && t0.fCalculate3DTest0; + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_CHARGE] = Alright(lCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_CHARGE]) && t0.fCalculate3DTest0; + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_VZ] = Alright(lCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_VZ]) && t0.fCalculate3DTest0; + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_VZ] = Alright(lCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_VZ]) && t0.fCalculate3DTest0; + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_CHARGE] = Alright(lCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_CHARGE]) && t0.fCalculate3DTest0; + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_VZ_CHARGE] = Alright(lCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_VZ_CHARGE]) && t0.fCalculate3DTest0; + t0.fCalculate3DTest0AsFunctionOf[AFO_PT_ETA_CHARGE] = Alright(lCalculate3DTest0AsFunctionOf[AFO_PT_ETA_CHARGE]) && t0.fCalculate3DTest0; + + // ... + + if (t0.fCalculateTest0 || t0.fCalculate2DTest0 || t0.fCalculate3DTest0) { + t0.fFileWithLabels = TString(cf_t0.cfFileWithLabels); + t0.fUseDefaultLabels = cf_t0.cfUseDefaultLabels; + t0.fWhichDefaultLabels = TString(cf_t0.cfWhichDefaultLabels); + } // *) 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; - pw.fUseDiffWeights[wPHIETA] = cf_pw.cfUseDiffPhiEtaWeights; + 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 if (TString(lWhichDiffPtWeights[dpw]).Contains("wCharge")) { + pw.fUseDiffPtWeights[wPtChargeAxis] = Alright(lWhichDiffPtWeights[dpw]) && pw.fUseDiffPtWeights[wPtPtAxis]; + } else if (TString(lWhichDiffPtWeights[dpw]).Contains("wCentrality")) { + pw.fUseDiffPtWeights[wPtCentralityAxis] = Alright(lWhichDiffPtWeights[dpw]) && pw.fUseDiffPtWeights[wPtPtAxis]; + } else { + 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 if (TString(lWhichDiffEtaWeights[dpw]).Contains("wCharge")) { + pw.fUseDiffEtaWeights[wEtaChargeAxis] = Alright(lWhichDiffEtaWeights[dpw]) && pw.fUseDiffEtaWeights[wEtaEtaAxis]; + } else if (TString(lWhichDiffEtaWeights[dpw]).Contains("wCentrality")) { + pw.fUseDiffEtaWeights[wEtaCentralityAxis] = Alright(lWhichDiffEtaWeights[dpw]) && pw.fUseDiffEtaWeights[wEtaEtaAxis]; + } else { + 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; + // *) Centrality weights: + cw.fUseCentralityWeights = cf_cw.cfUseCentralityWeights; + cw.fFileWithCentralityWeights = cf_cw.cfFileWithCentralityWeights; + // ... // *) Nested loops: @@ -353,7 +713,7 @@ void DefaultConfiguration() // ... // *) Toy NUA: - auto lApplyNUAPDF = (vector)cf_nua.cfApplyNUAPDF; + 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)); @@ -366,7 +726,7 @@ void DefaultConfiguration() // **) 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 = (vector)cf_nua.cfUseDefaultNUAPDF; + 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)); @@ -387,7 +747,8 @@ void DefaultConfiguration() nua.fFileWithCustomNUA = TString(cf_nua.cfFileWithCustomNUA); // *) histogram names with custom NUA distributions in that file + get those histograms immediately here: - auto lCustomNUAPDFHistNames = (vector)cf_nua.cfCustomNUAPDFHistNames; + 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)); @@ -425,89 +786,378 @@ void DefaultConfiguration() iv.fInternalValidationForceBailout = cf_iv.cfInternalValidationForceBailout; iv.fnEventsInternalValidation = cf_iv.cfnEventsInternalValidation; iv.fRescaleWithTheoreticalInput = cf_iv.cfRescaleWithTheoreticalInput; + iv.fRandomizeReactionPlane = cf_iv.cfRandomizeReactionPlane; + iv.fHarmonicsOptionInternalValidation = new TString(cf_iv.cfHarmonicsOptionInternalValidation); // *) Results histograms: + // **) Fixed-length or variable-length binning: + // Remark: keep ordering in sync with enum eAsFunctionOf: + cf_res.cfUseVariableLengthMultBins ? res.fUseResultsProVariableLengthBins[AFO_MULTIPLICITY] = true : res.fUseResultsProVariableLengthBins[AFO_MULTIPLICITY] = false; + cf_res.cfUseVariableLengthCentBins ? res.fUseResultsProVariableLengthBins[AFO_CENTRALITY] = true : res.fUseResultsProVariableLengthBins[AFO_CENTRALITY] = false; + cf_res.cfUseVariableLengthPtBins ? res.fUseResultsProVariableLengthBins[AFO_PT] = true : res.fUseResultsProVariableLengthBins[AFO_PT] = false; + cf_res.cfUseVariableLengthEtaBins ? res.fUseResultsProVariableLengthBins[AFO_ETA] = true : res.fUseResultsProVariableLengthBins[AFO_ETA] = false; + cf_res.cfUseVariableLengthOccuBins ? res.fUseResultsProVariableLengthBins[AFO_OCCUPANCY] = true : res.fUseResultsProVariableLengthBins[AFO_OCCUPANCY] = false; + cf_res.cfUseVariableLengthCRDBins ? res.fUseResultsProVariableLengthBins[AFO_CURRENTRUNDURATION] = true : res.fUseResultsProVariableLengthBins[AFO_CURRENTRUNDURATION] = false; + cf_res.cfUseVariableLengthVzBins ? res.fUseResultsProVariableLengthBins[AFO_VZ] = true : res.fUseResultsProVariableLengthBins[AFO_VZ] = false; + + // **) Define axis titles: + // Remark: keep ordering in sync with enum eAsFunctionOf + // 1D: + 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.fResultsProXaxisTitle[AFO_CHARGE] = "particle charge"; + res.fResultsProRawName[AFO_CHARGE] = "charge"; + // ... + + // 2D: + // Remark: I re-use the above definitions for 1D. + + // 3D: + // Remark: I re-use the above definitions for 1D. + 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"; - // **) Names of 2D event histograms: - qa.fEventHistogramsName2D[eMultTPC_vs_NContributors] = Form("%s_vs_%s", eh.fEventHistogramsName[eMultTPC].Data(), eh.fEventHistogramsName[eNContributors].Data()); - qa.fEventHistogramsName2D[eVertex_z_vs_MultTPC] = Form("%s_vs_%s", eh.fEventHistogramsName[eVertex_z].Data(), eh.fEventHistogramsName[eMultTPC].Data()); - qa.fEventHistogramsName2D[eVertex_z_vs_NContributors] = Form("%s_vs_%s", eh.fEventHistogramsName[eVertex_z].Data(), eh.fEventHistogramsName[eNContributors].Data()); + // **) 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[eCentrality_vs_CentralitySim] = Form("%s_vs_%s", eh.fEventHistogramsName[eCentrality].Data(), "CentralitySim"); // 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[eCentRun2V0M_vs_NContributors] = Form("%s_vs_%s", qa.fCentralityEstimatorName[eCentRun2V0M].Data(), eh.fEventHistogramsName[eNContributors].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 t = 0; t < eQAEventHistograms2D_N; t++) { + 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); } } - // **) Names of 2D particle histograms: - qa.fParticleHistogramsName2D[edcaXY_vs_Pt] = Form("%s_vs_%s", ph.fParticleHistogramsName[edcaXY].Data(), ph.fParticleHistogramsName[ePt].Data()); + // **) Names of QA 2D particle histograms: + qa.fParticleHistogramsName2D[ePt_vs_dcaXY] = Form("%s_vs_%s", ph.fParticleHistogramsName[ePt].Data(), ph.fParticleHistogramsName[edcaXY].Data()); // ***) Quick insanity check that all names are set: - for (Int_t t = 0; t < eQAParticleHistograms2D_N; t++) { + 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); } } -} // void DefaultConfiguration() + // **) 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); + } + } + + // **) 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(); + + // ... + + // ***) 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); + } + } + + // **) 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(); + + // ... + + // ***) 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); + } + } + + // **) Names and titles of all categories of sparse histograms: + ph.fParticleSparseHistogramsName[eDWPhi] = "fParticleSparseHistograms_DWPhi"; + ph.fParticleSparseHistogramsTitle[eDWPhi] = "sparse histogram for differential #phi weights,"; + + 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; + + // *) Use configurable array cfCalculateEtaSeparationsAsFunctionOf, to specify vs which observable EtaSeparations will be calculated (flags 1 or 0). + // Supported format: "0-someName" and "1-someName", where "-" is a field separator. + // Ordering of the flags in that array is interpreted through ordering of enums in enum eAsFunctionOf. + auto lCalculateEtaSeparationsAsFunctionOf = cf_es.cfCalculateEtaSeparationsAsFunctionOf.value; // this is now the local version of that string array from configurable. + if (lCalculateEtaSeparationsAsFunctionOf.size() != eAsFunctionOf_N) { + LOGF(info, "\033[1;31m lCalculateEtaSeparationsAsFunctionOf.size() = %d\033[0m", lCalculateEtaSeparationsAsFunctionOf.size()); + LOGF(info, "\033[1;31m eAsFunctionOf_N) = %d\033[0m", static_cast(eAsFunctionOf_N)); + LOGF(fatal, "\033[1;31m%s at line %d : Mismatch in the number of flags in configurable cfCalculateEtaSeparationsAsFunctionOf, and number of entries in enum eAsFunctionOf_N \n \033[0m", __FUNCTION__, __LINE__); + } + + // I append "&& es.fCalculateEtaSeparations" below, to switch off calculation of all correlations with one common flag: + es.fCalculateEtaSeparationsAsFunctionOf[AFO_INTEGRATED] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_INTEGRATED]) && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_MULTIPLICITY] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_MULTIPLICITY]) && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_CENTRALITY] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_CENTRALITY]) && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_PT]) && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_ETA] = false; // yes, in this context this one doesn't make sense + es.fCalculateEtaSeparationsAsFunctionOf[AFO_OCCUPANCY] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_OCCUPANCY]) && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_INTERACTIONRATE] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_INTERACTIONRATE]) && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_CURRENTRUNDURATION] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_CURRENTRUNDURATION]) && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_VZ] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_VZ]) && es.fCalculateEtaSeparations; + es.fCalculateEtaSeparationsAsFunctionOf[AFO_CHARGE] = Alright(lCalculateEtaSeparationsAsFunctionOf[AFO_CHARGE]) && 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) { + + // Set the flags qv.fCalculateqvectorsKineAny, fCalculateqvectorsKine[eqvectorKine_N] and fCalculateqvectorsKineEtaSeparations[eqvectorKine_N]: + // TBI 20250601 I have to do it without loop, until I provide support for 2D and 3D to Correlations and EtaSeparations + + // Test0 and Correlations: + if (mupa.fCalculateCorrelationsAsFunctionOf[AfoKineMap1D(PTq)] || t0.fCalculateTest0AsFunctionOf[AfoKineMap1D(PTq)]) { + qv.fCalculateqvectorsKine[PTq] = true; + } + if (mupa.fCalculateCorrelationsAsFunctionOf[AfoKineMap1D(ETAq)] || t0.fCalculateTest0AsFunctionOf[AfoKineMap1D(ETAq)]) { + qv.fCalculateqvectorsKine[ETAq] = true; + } + if (mupa.fCalculateCorrelationsAsFunctionOf[AfoKineMap1D(CHARGEq)] || t0.fCalculateTest0AsFunctionOf[AfoKineMap1D(CHARGEq)]) { + qv.fCalculateqvectorsKine[CHARGEq] = true; + } + if (t0.fCalculate2DTest0AsFunctionOf[AfoKineMap2D(PT_ETAq)]) { + qv.fCalculateqvectorsKine[PT_ETAq] = true; + } + if (t0.fCalculate2DTest0AsFunctionOf[AfoKineMap2D(PT_CHARGEq)]) { + qv.fCalculateqvectorsKine[PT_CHARGEq] = true; + } + if (t0.fCalculate2DTest0AsFunctionOf[AfoKineMap2D(ETA_CHARGEq)]) { + qv.fCalculateqvectorsKine[ETA_CHARGEq] = true; + } + if (t0.fCalculate3DTest0AsFunctionOf[AfoKineMap3D(PT_ETA_CHARGEq)]) { + qv.fCalculateqvectorsKine[PT_ETA_CHARGEq] = true; + } + + // Eta separations: + if (es.fCalculateEtaSeparationsAsFunctionOf[AfoKineMap1D(PTq)]) { + qv.fCalculateqvectorsKineEtaSeparations[PTq] = true; + } + qv.fCalculateqvectorsKineEtaSeparations[ETAq] = false; // yes, this one is alwas set explicitly to false + if (es.fCalculateEtaSeparationsAsFunctionOf[AfoKineMap1D(CHARGEq)]) { + qv.fCalculateqvectorsKineEtaSeparations[CHARGEq] = true; + } + qv.fCalculateqvectorsKineEtaSeparations[PT_ETAq] = false; // yes, this one is alwas set explicitly to false + + // TBI 20250617 comment in this branch, when i implement support for 2D eta separations. + // if (es.fCalculate2DEtaSeparationsAsFunctionOf[AfoKineMap2D(PT_CHARGEq)]) { + // qv.fCalculateqvectorsKineEtaSeparations[PT_CHARGEq] = true; + // } + + qv.fCalculateqvectorsKineEtaSeparations[ETA_CHARGEq] = false; // yes, this one is alwas set explicitly to false + qv.fCalculateqvectorsKineEtaSeparations[PT_ETA_CHARGEq] = false; // yes, this one is alwas set explicitly to false + + for (int qKine = 0; qKine < eqvectorKine_N; qKine++) { + if (qv.fCalculateqvectorsKine[qKine] || qv.fCalculateqvectorsKineEtaSeparations[qKine]) { + qv.fCalculateqvectorsKineAny = true; + break; // yes, I need at least one kine calculus, to set this flag to true + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void defaultConfiguration() //============================================================ -Bool_t Alright(TString s) +bool Alright(TString s) { - // Simple utility function, which for a string formatted "someName-0" returns false, and for "someName-1" returns true. + // 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.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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_t nEntries = oa->GetEntries(); + 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()); + 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()); } // b) Do the thing: - // Algorithm: I split "someName-0" with respect to "-" as a field separator, and check what is in the 2nd field. - if (TString(oa->At(1)->GetName()).EqualTo("0")) { + // 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; - return kFALSE; - } else if (TString(oa->At(1)->GetName()).EqualTo("1")) { + returnValue = false; + } else if (TString(oa->At(0)->GetName()).EqualTo("1")) { delete oa; - return kTRUE; + returnValue = true; } else { - 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()); + 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 kFALSE; // obsolete, but suppresses the warning -} // Bool_t Alright(const char* name) + return returnValue; + +} // bool Alright(const char* name) //============================================================ -void DefaultBooking() +void defaultBooking() { // Set here which histograms are booked by default. @@ -515,21 +1165,22 @@ void DefaultBooking() // b) Event histograms 2D; // c) Particle histograms 1D; // d) Particle histograms 2D; - // e) QA; + // e) Particle sparse histograms; + // f) QA. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Event histograms 1D: - // By default all event histograms are booked. Set this flag to kFALSE to switch off booking of all event histograms: + // 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. + // Supported format: "0-someName" and "1-someName", where "-" is a field separator. // Ordering of the flags in that array is interpreted through ordering of enums in enum eEventHistograms. - auto lBookEventHistograms = (vector)cf_eh.cfBookEventHistograms; // this is now the local version of that int array from configurable. + auto lBookEventHistograms = cf_eh.cfBookEventHistograms.value; // this is now the local version of that string array from configurable. if (lBookEventHistograms.size() != eEventHistograms_N) { 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)); @@ -538,39 +1189,41 @@ void DefaultBooking() // *) 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_t name = 0; name < eEventHistograms_N; name++) { - // TBI 20240518 I could implement even a strickter EqualTo instead of BeginsWith, but then I need to tokenize, etc., etc. This shall be safe enough. - if (!TString(lBookEventHistograms[name]).BeginsWith(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\" \033[0m", __FUNCTION__, __LINE__, name, name, TString(lBookEventHistograms[name]).Data(), name, eh.fEventHistogramsName[name].Data()); + 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[eSelectedTracks] = Alright(lBookEventHistograms[eSelectedTracks]) && eh.fFillEventHistograms; - eh.fBookEventHistograms[eMultFV0M] = Alright(lBookEventHistograms[eMultFV0M]) && eh.fFillEventHistograms; - eh.fBookEventHistograms[eMultFT0M] = Alright(lBookEventHistograms[eMultFT0M]) && eh.fFillEventHistograms; - eh.fBookEventHistograms[eMultTPC] = Alright(lBookEventHistograms[eMultTPC]) && eh.fFillEventHistograms; - eh.fBookEventHistograms[eMultNTracksPV] = Alright(lBookEventHistograms[eMultNTracksPV]) && eh.fFillEventHistograms; - eh.fBookEventHistograms[eMultTracklets] = Alright(lBookEventHistograms[eMultTracklets]) && 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[eVertex_x] = Alright(lBookEventHistograms[eVertex_x]) && eh.fFillEventHistograms; - eh.fBookEventHistograms[eVertex_y] = Alright(lBookEventHistograms[eVertex_y]) && eh.fFillEventHistograms; - eh.fBookEventHistograms[eVertex_z] = Alright(lBookEventHistograms[eVertex_z]) && 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 kFALSE to switch off booking of all 1D particle histograms: + // 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)cf_ph.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(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)); @@ -579,10 +1232,10 @@ void DefaultBooking() // *) 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_t name = 0; name < eParticleHistograms_N; name++) { - // TBI 20240518 I could implement even a strickter EqualTo instead of BeginsWith, but then I need to tokenize, etc., etc. This shall be safe enough. - if (!TString(lBookParticleHistograms[name]).BeginsWith(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\" \033[0m", __FUNCTION__, __LINE__, name, TString(lBookParticleHistograms[name]).Data(), ph.fParticleHistogramsName[name].Data()); + 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()); } } @@ -593,6 +1246,7 @@ void DefaultBooking() 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; @@ -600,6 +1254,7 @@ void DefaultBooking() 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; @@ -607,59 +1262,127 @@ void DefaultBooking() // 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 kFALSE to switch off booking of all 2D particle histograms: + // 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. // TBI 20240124 is this safe enough? - auto lBookParticleHistograms2D = (vector)cf_ph.cfBookParticleHistograms2D; // this is now the local version of that int array from configurable. TBI 20240124 why is this casting mandatory? + // *) 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) QA: + // 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 = (vector)cf_qa.cfBookQAEventHistograms2D; // this is now the local version of that int array from configurable + 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 eEventHistograms2D \n \033[0m", __FUNCTION__, __LINE__); + 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_t name = 0; name < eQAEventHistograms2D_N; name++) { - // TBI 20240518 I could implement even a strickter EqualTo instead of BeginsWith, but then I need to tokenize, etc., etc. This shall be safe enough. - if (!TString(lBookQAEventHistograms2D[name]).BeginsWith(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\" \033[0m", __FUNCTION__, __LINE__, name, TString(lBookQAEventHistograms2D[name]).Data(), qa.fEventHistogramsName2D[name].Data()); + 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[eMultTPC_vs_NContributors] = Alright(lBookQAEventHistograms2D[eMultTPC_vs_NContributors]) && qa.fFillQAEventHistograms2D; - qa.fBookQAEventHistograms2D[eVertex_z_vs_MultTPC] = Alright(lBookQAEventHistograms2D[eVertex_z_vs_MultTPC]) && qa.fFillQAEventHistograms2D; - qa.fBookQAEventHistograms2D[eVertex_z_vs_NContributors] = Alright(lBookQAEventHistograms2D[eVertex_z_vs_NContributors]) && qa.fFillQAEventHistograms2D; + 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[eCentrality_vs_CentralitySim] = Alright(lBookQAEventHistograms2D[eCentrality_vs_CentralitySim]) && 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[eCentRun2V0M_vs_NContributors] = Alright(lBookQAEventHistograms2D[eCentRun2V0M_vs_NContributors]) && 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 = (vector)cf_qa.cfBookQAParticleHistograms2D; // this is now the local version of that int array from configurable + 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)); @@ -668,37 +1391,174 @@ void DefaultBooking() // *) 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_t name = 0; name < eQAParticleHistograms2D_N; name++) { - // TBI 20240518 I could implement even a strickter EqualTo instead of BeginsWith, but then I need to tokenize, etc., etc. This shall be safe enough. - if (!TString(lBookQAParticleHistograms2D[name]).BeginsWith(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\" \033[0m", __FUNCTION__, __LINE__, name, TString(lBookQAParticleHistograms2D[name]).Data(), qa.fParticleHistogramsName2D[name].Data()); + 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[edcaXY_vs_Pt] = Alright(lBookQAParticleHistograms2D[edcaXY_vs_Pt]) && qa.fFillQAParticleHistograms2D; + 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()); + } + } + + // 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]); + } // ... -} // void DefaultBooking() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void defaultBooking() //============================================================ -void DefaultBinning() +void defaultBinning() { // Default binning for all histograms. // 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(). + // 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 1D; // c) Default binning for particle histograms 2D; // d) Default binning for results histograms; - // e) Variable-length binning set via MuPa-Configurables.h. + // e) Variable-length binning for results histograms set via MuPa-Configurables.h. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Default binning for event histograms: @@ -706,62 +1566,62 @@ void DefaultBinning() eh.fEventHistogramsBins[eNumberOfEvents][1] = 0.; eh.fEventHistogramsBins[eNumberOfEvents][2] = 1.; - eh.fEventHistogramsBins[eTotalMultiplicity][0] = 20000; - eh.fEventHistogramsBins[eTotalMultiplicity][1] = -1.e5; - eh.fEventHistogramsBins[eTotalMultiplicity][2] = 1.e5; + eh.fEventHistogramsBins[eTotalMultiplicity][0] = 10000.; + eh.fEventHistogramsBins[eTotalMultiplicity][1] = 0.; + eh.fEventHistogramsBins[eTotalMultiplicity][2] = 100000.; - eh.fEventHistogramsBins[eSelectedTracks][0] = 20000; - eh.fEventHistogramsBins[eSelectedTracks][1] = -1.e5; - eh.fEventHistogramsBins[eSelectedTracks][2] = 1.e5; + eh.fEventHistogramsBins[eMultiplicity][0] = 500.; + eh.fEventHistogramsBins[eMultiplicity][1] = 0.; + eh.fEventHistogramsBins[eMultiplicity][2] = 5000.; - eh.fEventHistogramsBins[eMultFV0M][0] = 20000; - eh.fEventHistogramsBins[eMultFV0M][1] = -1.e5; - eh.fEventHistogramsBins[eMultFV0M][2] = 1.e5; + eh.fEventHistogramsBins[eReferenceMultiplicity][0] = 700.; // bin width is 100 + eh.fEventHistogramsBins[eReferenceMultiplicity][1] = 0.; + eh.fEventHistogramsBins[eReferenceMultiplicity][2] = 70000.; - eh.fEventHistogramsBins[eMultFT0M][0] = 20000; - eh.fEventHistogramsBins[eMultFT0M][1] = -1.e5; - eh.fEventHistogramsBins[eMultFT0M][2] = 1.e5; + 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.; - eh.fEventHistogramsBins[eMultTPC][0] = 20000; - eh.fEventHistogramsBins[eMultTPC][1] = -1.e5; - eh.fEventHistogramsBins[eMultTPC][2] = 1.e5; + eh.fEventHistogramsBins[eVertexX][0] = 1600; + eh.fEventHistogramsBins[eVertexX][1] = -0.8; + eh.fEventHistogramsBins[eVertexX][2] = 0.8; - eh.fEventHistogramsBins[eMultNTracksPV][0] = 20000; - eh.fEventHistogramsBins[eMultNTracksPV][1] = -1.e5; - eh.fEventHistogramsBins[eMultNTracksPV][2] = 1.e5; + eh.fEventHistogramsBins[eVertexY][0] = 1600; + eh.fEventHistogramsBins[eVertexY][1] = -0.8; + eh.fEventHistogramsBins[eVertexY][2] = 0.8; - eh.fEventHistogramsBins[eMultTracklets][0] = 20000; - eh.fEventHistogramsBins[eMultTracklets][1] = -1.e5; - eh.fEventHistogramsBins[eMultTracklets][2] = 1.e5; + eh.fEventHistogramsBins[eVertexZ][0] = 800; + eh.fEventHistogramsBins[eVertexZ][1] = -40.; + eh.fEventHistogramsBins[eVertexZ][2] = 40.; - eh.fEventHistogramsBins[eCentrality][0] = 120; // intentionally, because if centrality is not determined, it's set to 105.0 at the moment - eh.fEventHistogramsBins[eCentrality][1] = -10.; - eh.fEventHistogramsBins[eCentrality][2] = 110.; + eh.fEventHistogramsBins[eNContributors][0] = 600.; // bin width is 20 + eh.fEventHistogramsBins[eNContributors][1] = 0.; + eh.fEventHistogramsBins[eNContributors][2] = 12000.; - eh.fEventHistogramsBins[eVertex_x][0] = 800; - eh.fEventHistogramsBins[eVertex_x][1] = -0.4; - eh.fEventHistogramsBins[eVertex_x][2] = 0.4; + eh.fEventHistogramsBins[eImpactParameter][0] = 1000; + eh.fEventHistogramsBins[eImpactParameter][1] = 0.; + eh.fEventHistogramsBins[eImpactParameter][2] = 100.; - eh.fEventHistogramsBins[eVertex_y][0] = 800; - eh.fEventHistogramsBins[eVertex_y][1] = -0.4; - eh.fEventHistogramsBins[eVertex_y][2] = 0.4; + 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; - eh.fEventHistogramsBins[eVertex_z][0] = 800; - eh.fEventHistogramsBins[eVertex_z][1] = -40.; - eh.fEventHistogramsBins[eVertex_z][2] = 40.; + eh.fEventHistogramsBins[eOccupancy][0] = 1000; + eh.fEventHistogramsBins[eOccupancy][1] = 0.; + eh.fEventHistogramsBins[eOccupancy][2] = 100000.; - eh.fEventHistogramsBins[eNContributors][0] = 1000; - eh.fEventHistogramsBins[eNContributors][1] = 0.; - eh.fEventHistogramsBins[eNContributors][2] = 10000.; + eh.fEventHistogramsBins[eInteractionRate][0] = 1000; + eh.fEventHistogramsBins[eInteractionRate][1] = 0.; + eh.fEventHistogramsBins[eInteractionRate][2] = 100.; - eh.fEventHistogramsBins[eImpactParameter][0] = 2000; - eh.fEventHistogramsBins[eImpactParameter][1] = -1000.; - eh.fEventHistogramsBins[eImpactParameter][2] = 1000.; // It's set to -999 is not meaningful + 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(); + ph.fParticleHistogramsBins[ePhi][2] = o2::constants::math::TwoPI; ph.fParticleHistogramsBins[ePt][0] = 2000; ph.fParticleHistogramsBins[ePt][1] = 0.; @@ -772,7 +1632,7 @@ void DefaultBinning() 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][1] = -3.5; // anticipating I might be storing charge of Delta++, etc. ph.fParticleHistogramsBins[eCharge][2] = 3.5; ph.fParticleHistogramsBins[etpcNClsFindable][0] = 300; @@ -783,6 +1643,10 @@ void DefaultBinning() ph.fParticleHistogramsBins[etpcNClsShared][1] = 0.; ph.fParticleHistogramsBins[etpcNClsShared][2] = 200.; + 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.; @@ -799,25 +1663,29 @@ void DefaultBinning() ph.fParticleHistogramsBins[eitsNClsInnerBarrel][1] = 0.; ph.fParticleHistogramsBins[eitsNClsInnerBarrel][2] = 10.; - ph.fParticleHistogramsBins[etpcCrossedRowsOverFindableCls][0] = 250; + ph.fParticleHistogramsBins[etpcCrossedRowsOverFindableCls][0] = 1000; ph.fParticleHistogramsBins[etpcCrossedRowsOverFindableCls][1] = 0.; - ph.fParticleHistogramsBins[etpcCrossedRowsOverFindableCls][2] = 5000; + ph.fParticleHistogramsBins[etpcCrossedRowsOverFindableCls][2] = 10; - ph.fParticleHistogramsBins[etpcFoundOverFindableCls][0] = 250; + ph.fParticleHistogramsBins[etpcFoundOverFindableCls][0] = 1000; ph.fParticleHistogramsBins[etpcFoundOverFindableCls][1] = 0.; - ph.fParticleHistogramsBins[etpcFoundOverFindableCls][2] = 5000.; + ph.fParticleHistogramsBins[etpcFoundOverFindableCls][2] = 10.; - ph.fParticleHistogramsBins[etpcFractionSharedCls][0] = 600; + 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] = 1000.; + 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] = -1000.; - ph.fParticleHistogramsBins[edcaXY][2] = 1000.; + ph.fParticleHistogramsBins[edcaXY][1] = -10.; + ph.fParticleHistogramsBins[edcaXY][2] = 10.; ph.fParticleHistogramsBins[edcaZ][0] = 2000; - ph.fParticleHistogramsBins[edcaZ][1] = -1000.; - ph.fParticleHistogramsBins[edcaZ][2] = 1000.; + ph.fParticleHistogramsBins[edcaZ][1] = -10.; + ph.fParticleHistogramsBins[edcaZ][2] = 10.; ph.fParticleHistogramsBins[ePDG][0] = 2000; ph.fParticleHistogramsBins[ePDG][1] = -1000.; @@ -841,133 +1709,281 @@ void DefaultBinning() 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.; + // Remark: These bins apply to following categories fCorrelationsPro, fNestedLoopsPro, fTest0Pro, fResultsPro, and all 2D and 3D variants. + // 1D: + // *) For integrated results, binning is always the same nBins = 1 in (0.,1.): + res.fResultsProBinEdges[AFO_INTEGRATED] = new TArrayD(2); + res.fResultsProBinEdges[AFO_INTEGRATED]->AddAt(0., 0); + res.fResultsProBinEdges[AFO_INTEGRATED]->AddAt(1., 1); + + // *) Binning vs. multiplicity: + if (res.fUseResultsProVariableLengthBins[AFO_MULTIPLICITY]) { + this->InitializeVariableLengthBins(AFO_MULTIPLICITY); + } else { + this->InitializeFixedLengthBins(AFO_MULTIPLICITY); + } - // *) Fixed-length binning vs. multiplicity: - auto lFixedLength_mult_bins = (vector)cf_res.cfFixedLength_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 cfFixedLength_mult_bins must have 3 entries: {nBins, min, max} \n \033[0m", __FUNCTION__, __LINE__); + // *) Binning vs. centrality: + if (res.fUseResultsProVariableLengthBins[AFO_CENTRALITY]) { + this->InitializeVariableLengthBins(AFO_CENTRALITY); + } else { + this->InitializeFixedLengthBins(AFO_CENTRALITY); } - 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]; - // *) Fixed-length binning vs. centrality: - auto lFixedLength_cent_bins = (vector)cf_res.cfFixedLength_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 cfFixedLength_cent_bins must have 3 entries: {nBins, min, max} \n \033[0m", __FUNCTION__, __LINE__); + // *) Binning vs. pt: + if (res.fUseResultsProVariableLengthBins[AFO_PT]) { + this->InitializeVariableLengthBins(AFO_PT); + } else { + this->InitializeFixedLengthBins(AFO_PT); } - 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]; - // *) Fixed-length binning vs. pt: - auto lFixedLength_pt_bins = (vector)cf_res.cfFixedLength_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 cfFixedLength_pt_bins must have 3 entries: {nBins, min, max} \n \033[0m", __FUNCTION__, __LINE__); + // *) Binning vs. eta: + if (res.fUseResultsProVariableLengthBins[AFO_ETA]) { + this->InitializeVariableLengthBins(AFO_ETA); + } else { + this->InitializeFixedLengthBins(AFO_ETA); } - 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]; - // *) Fixed-length binning vs. eta: - auto lFixedLength_eta_bins = (vector)cf_res.cfFixedLength_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 cfFixedLength_eta_bins must have 3 entries: {nBins, min, max} \n \033[0m", __FUNCTION__, __LINE__); + // *) Binning vs. occupancy: + if (res.fUseResultsProVariableLengthBins[AFO_OCCUPANCY]) { + this->InitializeVariableLengthBins(AFO_OCCUPANCY); + } else { + this->InitializeFixedLengthBins(AFO_OCCUPANCY); } - 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]; - // e) Variable-length binning set via MuPa-Configurables.h: - // *) Variable-length binning vs. multiplicity: - if (cf_res.cfUseVariableLength_mult_bins) { - res.fUseResultsProVariableLengthBins[AFO_MULTIPLICITY] = kTRUE; - res.fResultsProVariableLengthBinsString[AFO_MULTIPLICITY] = cf_res.cfVariableLength_mult_bins; - this->CastStringIntoArray(AFO_MULTIPLICITY); + // *) Binning vs. interaction rate: + if (res.fUseResultsProVariableLengthBins[AFO_INTERACTIONRATE]) { + this->InitializeVariableLengthBins(AFO_INTERACTIONRATE); + } else { + this->InitializeFixedLengthBins(AFO_INTERACTIONRATE); } - // *) Variable-length binning vs. centrality: - if (cf_res.cfUseVariableLength_cent_bins) { - res.fUseResultsProVariableLengthBins[AFO_CENTRALITY] = kTRUE; - res.fResultsProVariableLengthBinsString[AFO_CENTRALITY] = cf_res.cfVariableLength_cent_bins; - this->CastStringIntoArray(AFO_CENTRALITY); + + // *) Binning vs. current run duration: + if (res.fUseResultsProVariableLengthBins[AFO_CURRENTRUNDURATION]) { + this->InitializeVariableLengthBins(AFO_CURRENTRUNDURATION); + } else { + this->InitializeFixedLengthBins(AFO_CURRENTRUNDURATION); } - // *) Variable-length binning vs. pt: - if (cf_res.cfUseVariableLength_pt_bins) { - res.fUseResultsProVariableLengthBins[AFO_PT] = kTRUE; - res.fResultsProVariableLengthBinsString[AFO_PT] = cf_res.cfVariableLength_pt_bins; - this->CastStringIntoArray(AFO_PT); + + // *) Binning vs. vertex z position: + if (res.fUseResultsProVariableLengthBins[AFO_VZ]) { + this->InitializeVariableLengthBins(AFO_VZ); + } else { + this->InitializeFixedLengthBins(AFO_VZ); } - // *) Variable-length binning vs. eta: - if (cf_res.cfUseVariableLength_eta_bins) { - res.fUseResultsProVariableLengthBins[AFO_ETA] = kTRUE; - res.fResultsProVariableLengthBinsString[AFO_ETA] = cf_res.cfVariableLength_eta_bins; - this->CastStringIntoArray(AFO_ETA); + + // *) Binning vs. particle charge => binning is always the same nBins = 2 in (-2.,2), so that the center of bins is at +/- 1: + // Therefore, I shall never initialize or set for ill-defined cases the charge to 0., because when filling, that one will go to bin for +1 charge ("lower boundary included"). + res.fResultsProBinEdges[AFO_CHARGE] = new TArrayD(3); + res.fResultsProBinEdges[AFO_CHARGE]->AddAt(-2., 0); + res.fResultsProBinEdges[AFO_CHARGE]->AddAt(0., 1); + res.fResultsProBinEdges[AFO_CHARGE]->AddAt(2., 2); + + // ... + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } -} // void DefaultBinning() +} // 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", __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. + // I do not have here AFO_INTEGRATED and AFO_CHARGE, because for them binning is always the same, i.e. no need for configurable. 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", __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.cfFixedLengthMultBins.value; + break; + } + case AFO_CENTRALITY: { + lFixedLength_bins = cf_res.cfFixedLengthCentBins.value; + break; + } + case AFO_PT: { + lFixedLength_bins = cf_res.cfFixedLengthPtBins.value; + break; + } + case AFO_ETA: { + lFixedLength_bins = cf_res.cfFixedLengthEtaBins.value; + break; + } + case AFO_OCCUPANCY: { + lFixedLength_bins = cf_res.cfFixedLengthOccuBins.value; + break; + } + case AFO_INTERACTIONRATE: { + lFixedLength_bins = cf_res.cfFixedLengthIRBins.value; + break; + } + case AFO_CURRENTRUNDURATION: { + lFixedLength_bins = cf_res.cfFixedLengthCRDBins.value; + break; + } + case AFO_VZ: { + lFixedLength_bins = cf_res.cfFixedLengthVzBins.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.fResultsProBinEdges[AFO] = ArrayWithBinEdges(lFixedLength_bins[0], lFixedLength_bins[1], lFixedLength_bins[2]); + if (tc.fVerbose) { - LOGF(info, "\033[1;32m Done! \033[0m"); + 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. + // 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) { + StartFunction(__FUNCTION__); + } + + // Common local vector for all variable-length bins: + std::vector lVariableLength_bins; + + switch (AFO) { + case AFO_MULTIPLICITY: { + lVariableLength_bins = cf_res.cfVariableLengthMultBins.value; + break; + } + case AFO_CENTRALITY: { + lVariableLength_bins = cf_res.cfVariableLengthCentBins.value; + break; + } + case AFO_PT: { + lVariableLength_bins = cf_res.cfVariableLengthPtBins.value; + break; + } + case AFO_ETA: { + lVariableLength_bins = cf_res.cfVariableLengthEtaBins.value; + break; + } + case AFO_OCCUPANCY: { + lVariableLength_bins = cf_res.cfVariableLengthOccuBins.value; + break; + } + case AFO_INTERACTIONRATE: { + lVariableLength_bins = cf_res.cfVariableLengthIRBins.value; + break; + } + case AFO_CURRENTRUNDURATION: { + lVariableLength_bins = cf_res.cfVariableLengthCRDBins.value; + break; + } + case AFO_VZ: { + lVariableLength_bins = cf_res.cfVariableLengthVzBins.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 (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.fResultsProBinEdges[AFO] = new TArrayD(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.fResultsProBinEdges[AFO]->GetSize(); i++) { + LOGF(info, "\033[1;32m [%d] : %f \033[0m", i, res.fResultsProBinEdges[AFO]->GetAt(i)); + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // 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. + + // TBI 20241019 This function is not needed any longer, remove eventually. + + if (tc.fVerbose) { + LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + } + + if (tc.fVerbose) { + LOGF(info, "\033[1;32m Casting a string %s into TArrayD .... \033[0m", res.fResultsProVariableLengthBinsString[AFO].Data()); + } + + 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 (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 (tc.fVerbose) { + LOGF(info, "\033[1;32m Done! \033[0m"); + } + +} // 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Default event cuts: // *) Use or do not use a cut enumerated in eEventHistograms + eEventCuts. // Default cuts are set in configurable cfUseEventCuts - auto lUseEventCuts = (vector)cf_ec.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)); @@ -976,9 +1992,9 @@ void DefaultCuts() // *) 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_t name = 0; name < eEventCuts_N; name++) { - // TBI 20240518 I could implement even a strickter EqualTo instead of BeginsWith, but then I need to tokenize, etc., etc. This shall be safe enough. - if (!TString(lUseEventCuts[name]).BeginsWith(ec.fEventCutName[name].Data())) { + 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()); } } @@ -986,29 +2002,56 @@ void DefaultCuts() // *) from enum eEventHistograms: ec.fUseEventCuts[eNumberOfEvents] = Alright(lUseEventCuts[eNumberOfEvents]); // total number of events (before event cuts) ec.fUseEventCuts[eTotalMultiplicity] = Alright(lUseEventCuts[eTotalMultiplicity]); - ec.fUseEventCuts[eSelectedTracks] = Alright(lUseEventCuts[eSelectedTracks]); - ec.fUseEventCuts[eMultFV0M] = Alright(lUseEventCuts[eMultFV0M]); - ec.fUseEventCuts[eMultFT0M] = Alright(lUseEventCuts[eMultFT0M]); - ec.fUseEventCuts[eMultTPC] = Alright(lUseEventCuts[eMultTPC]); - ec.fUseEventCuts[eMultNTracksPV] = Alright(lUseEventCuts[eMultNTracksPV]); - ec.fUseEventCuts[eMultTracklets] = Alright(lUseEventCuts[eMultTracklets]); + ec.fUseEventCuts[eMultiplicity] = Alright(lUseEventCuts[eMultiplicity]); + ec.fUseEventCuts[eReferenceMultiplicity] = Alright(lUseEventCuts[eReferenceMultiplicity]); ec.fUseEventCuts[eCentrality] = Alright(lUseEventCuts[eCentrality]); - ec.fUseEventCuts[eVertex_x] = Alright(lUseEventCuts[eVertex_x]); - ec.fUseEventCuts[eVertex_y] = Alright(lUseEventCuts[eVertex_y]); - ec.fUseEventCuts[eVertex_z] = Alright(lUseEventCuts[eVertex_z]); + 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[eFT0Bad] = Alright(lUseEventCuts[eFT0Bad]); + ec.fUseEventCuts[eITSBad] = Alright(lUseEventCuts[eITSBad]); + ec.fUseEventCuts[eITSLimAccMCRepr] = Alright(lUseEventCuts[eITSLimAccMCRepr]); + ec.fUseEventCuts[eTPCBadTracking] = Alright(lUseEventCuts[eTPCBadTracking]); + ec.fUseEventCuts[eTPCLimAccMCRepr] = Alright(lUseEventCuts[eTPCLimAccMCRepr]); + ec.fUseEventCuts[eTPCBadPID] = Alright(lUseEventCuts[eTPCBadPID]); + ec.fUseEventCuts[eCentralityWeights] = Alright(lUseEventCuts[eCentralityWeights]); // **) event cuts defined via booleans: ec.fUseEventCuts[eSel7] = ec.fUseEventCuts[eSel7] && cf_ec.cfUseSel7; @@ -1018,71 +2061,112 @@ void DefaultCuts() 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[eFT0Bad] = ec.fUseEventCuts[eFT0Bad] && cf_ec.cfUseFT0Bad; + ec.fUseEventCuts[eITSBad] = ec.fUseEventCuts[eITSBad] && cf_ec.cfUseITSBad; + ec.fUseEventCuts[eITSLimAccMCRepr] = ec.fUseEventCuts[eITSLimAccMCRepr] && cf_ec.cfUseITSLimAccMCRepr; + ec.fUseEventCuts[eTPCBadTracking] = ec.fUseEventCuts[eTPCBadTracking] && cf_ec.cfUseTPCBadTracking; + ec.fUseEventCuts[eTPCLimAccMCRepr] = ec.fUseEventCuts[eTPCLimAccMCRepr] && cf_ec.cfUseTPCLimAccMCRepr; + ec.fUseEventCuts[eTPCBadPID] = ec.fUseEventCuts[eTPCBadPID] && cf_ec.cfUseTPCBadPID; + ec.fUseEventCuts[eCentralityWeights] = ec.fUseEventCuts[eCentralityWeights] && cf_cw.cfUseCentralityWeights; // **) event cuts defined via [min, max): - auto lNumberOfEvents = (vector)cf_ec.cfNumberOfEvents; + // 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 = (vector)cf_ec.cfTotalMultiplicity; + auto lTotalMultiplicity = (std::vector)cf_ec.cfTotalMultiplicity; ec.fdEventCuts[eTotalMultiplicity][eMin] = lTotalMultiplicity[eMin]; ec.fdEventCuts[eTotalMultiplicity][eMax] = lTotalMultiplicity[eMax]; - auto lSelectedTracks = (vector)cf_ec.cfSelectedTracks; - ec.fdEventCuts[eSelectedTracks][eMin] = lSelectedTracks[eMin]; - ec.fdEventCuts[eSelectedTracks][eMax] = lSelectedTracks[eMax]; - - auto lMultFV0M = (vector)cf_ec.cfMultFV0M; - ec.fdEventCuts[eMultFV0M][eMin] = lMultFV0M[eMin]; - ec.fdEventCuts[eMultFV0M][eMax] = lMultFV0M[eMax]; - - auto lMultFT0M = (vector)cf_ec.cfMultFT0M; - ec.fdEventCuts[eMultFT0M][eMin] = lMultFT0M[eMin]; - ec.fdEventCuts[eMultFT0M][eMax] = lMultFT0M[eMax]; - - auto lMultTPC = (vector)cf_ec.cfMultTPC; - ec.fdEventCuts[eMultTPC][eMin] = lMultTPC[eMin]; - ec.fdEventCuts[eMultTPC][eMax] = lMultTPC[eMax]; - - auto lMultNTracksPV = (vector)cf_ec.cfMultNTracksPV; - ec.fdEventCuts[eMultNTracksPV][eMin] = lMultNTracksPV[eMin]; - ec.fdEventCuts[eMultNTracksPV][eMax] = lMultNTracksPV[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 lMultTracklets = (vector)cf_ec.cfMultTracklets; - ec.fdEventCuts[eMultTracklets][eMin] = lMultTracklets[eMin]; - ec.fdEventCuts[eMultTracklets][eMax] = lMultTracklets[eMax]; + auto lReferenceMultiplicity = (std::vector)cf_ec.cfReferenceMultiplicity; + ec.fdEventCuts[eReferenceMultiplicity][eMin] = lReferenceMultiplicity[eMin]; + ec.fdEventCuts[eReferenceMultiplicity][eMax] = lReferenceMultiplicity[eMax]; - auto lCentrality = (vector)cf_ec.cfCentrality; + auto lCentrality = (std::vector)cf_ec.cfCentrality; ec.fdEventCuts[eCentrality][eMin] = lCentrality[eMin]; ec.fdEventCuts[eCentrality][eMax] = lCentrality[eMax]; - auto lVertex_x = (vector)cf_ec.cfVertex_x; - ec.fdEventCuts[eVertex_x][eMin] = lVertex_x[eMin]; - ec.fdEventCuts[eVertex_x][eMax] = lVertex_x[eMax]; + auto lVertexX = (std::vector)cf_ec.cfVertexX; + ec.fdEventCuts[eVertexX][eMin] = lVertexX[eMin]; + ec.fdEventCuts[eVertexX][eMax] = lVertexX[eMax]; - auto lVertex_y = (vector)cf_ec.cfVertex_y; - ec.fdEventCuts[eVertex_y][eMin] = lVertex_y[eMin]; - ec.fdEventCuts[eVertex_y][eMax] = lVertex_y[eMax]; + auto lVertexY = (std::vector)cf_ec.cfVertexY; + ec.fdEventCuts[eVertexY][eMin] = lVertexY[eMin]; + ec.fdEventCuts[eVertexY][eMax] = lVertexY[eMax]; - auto lVertex_z = (vector)cf_ec.cfVertex_z; - ec.fdEventCuts[eVertex_z][eMin] = lVertex_z[eMin]; - ec.fdEventCuts[eVertex_z][eMax] = lVertex_z[eMax]; + auto lVertexZ = (std::vector)cf_ec.cfVertexZ; + ec.fdEventCuts[eVertexZ][eMin] = lVertexZ[eMin]; + ec.fdEventCuts[eVertexZ][eMax] = lVertexZ[eMax]; - auto lNContributors = (vector)cf_ec.cfNContributors; + auto lNContributors = (std::vector)cf_ec.cfNContributors; ec.fdEventCuts[eNContributors][eMin] = lNContributors[eMin]; ec.fdEventCuts[eNContributors][eMax] = lNContributors[eMax]; - auto lImpactParameter = (vector)cf_ec.cfImpactParameter; + auto lImpactParameter = (std::vector)cf_ec.cfImpactParameter; ec.fdEventCuts[eImpactParameter][eMin] = lImpactParameter[eMin]; ec.fdEventCuts[eImpactParameter][eMax] = lImpactParameter[eMax]; - auto lSelectedEvents = (vector)cf_ec.cfSelectedEvents; + 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; // ---------------------------------------------------------------------- @@ -1090,7 +2174,7 @@ void DefaultCuts() // *) Use or do not use a cut enumerated in eParticleHistograms + eParticleCuts. // Default cuts are set in configurable cfUseParticleCuts - auto lUseParticleCuts = (vector)cf_pc.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)); @@ -1099,9 +2183,9 @@ void DefaultCuts() // *) 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_t name = 0; name < eParticleCuts_N; name++) { - // TBI 20240518 I could implement even a strickter EqualTo instead of BeginsWith, but then I need to tokenize, etc., etc. This shall be safe enough. - if (!TString(lUseParticleCuts[name]).BeginsWith(pc.fParticleCutName[name].Data())) { + 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()); } } @@ -1113,6 +2197,7 @@ void DefaultCuts() 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]); @@ -1120,1156 +2205,3953 @@ void DefaultCuts() 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 = (vector)cf_pc.cfPhi; + auto lPhi = (std::vector)cf_pc.cfPhi; pc.fdParticleCuts[ePhi][eMin] = lPhi[eMin]; pc.fdParticleCuts[ePhi][eMax] = lPhi[eMax]; - auto lPt = (vector)cf_pc.cfPt; + auto lPt = (std::vector)cf_pc.cfPt; pc.fdParticleCuts[ePt][eMin] = lPt[eMin]; pc.fdParticleCuts[ePt][eMax] = lPt[eMax]; - auto lEta = (vector)cf_pc.cfEta; + auto lEta = (std::vector)cf_pc.cfEta; pc.fdParticleCuts[eEta][eMin] = lEta[eMin]; pc.fdParticleCuts[eEta][eMax] = lEta[eMax]; - auto lCharge = (vector)cf_pc.cfCharge; + auto lCharge = (std::vector)cf_pc.cfCharge; pc.fdParticleCuts[eCharge][eMin] = lCharge[eMin]; pc.fdParticleCuts[eCharge][eMax] = lCharge[eMax]; - auto ltpcNClsFindable = (vector)cf_pc.cftpcNClsFindable; + auto ltpcNClsFindable = (std::vector)cf_pc.cftpcNClsFindable; pc.fdParticleCuts[etpcNClsFindable][eMin] = ltpcNClsFindable[eMin]; pc.fdParticleCuts[etpcNClsFindable][eMax] = ltpcNClsFindable[eMax]; - auto ltpcNClsShared = (vector)cf_pc.cftpcNClsShared; + auto ltpcNClsShared = (std::vector)cf_pc.cftpcNClsShared; pc.fdParticleCuts[etpcNClsShared][eMin] = ltpcNClsShared[eMin]; pc.fdParticleCuts[etpcNClsShared][eMax] = ltpcNClsShared[eMax]; - auto ltpcNClsFound = (vector)cf_pc.cftpcNClsFound; + 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 = (vector)cf_pc.cftpcNClsCrossedRows; + auto ltpcNClsCrossedRows = (std::vector)cf_pc.cftpcNClsCrossedRows; pc.fdParticleCuts[etpcNClsCrossedRows][eMin] = ltpcNClsCrossedRows[eMin]; pc.fdParticleCuts[etpcNClsCrossedRows][eMax] = ltpcNClsCrossedRows[eMax]; - auto litsNCls = (vector)cf_pc.cfitsNCls; + auto litsNCls = (std::vector)cf_pc.cfitsNCls; pc.fdParticleCuts[eitsNCls][eMin] = litsNCls[eMin]; pc.fdParticleCuts[eitsNCls][eMax] = litsNCls[eMax]; - auto litsNClsInnerBarrel = (vector)cf_pc.cfitsNClsInnerBarrel; + auto litsNClsInnerBarrel = (std::vector)cf_pc.cfitsNClsInnerBarrel; pc.fdParticleCuts[eitsNClsInnerBarrel][eMin] = litsNClsInnerBarrel[eMin]; pc.fdParticleCuts[eitsNClsInnerBarrel][eMax] = litsNClsInnerBarrel[eMax]; - auto ltpcCrossedRowsOverFindableCls = (vector)cf_pc.cftpcCrossedRowsOverFindableCls; + auto ltpcCrossedRowsOverFindableCls = (std::vector)cf_pc.cftpcCrossedRowsOverFindableCls; pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMin] = ltpcCrossedRowsOverFindableCls[eMin]; pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax] = ltpcCrossedRowsOverFindableCls[eMax]; - auto ltpcFoundOverFindableCls = (vector)cf_pc.cftpcFoundOverFindableCls; + auto ltpcFoundOverFindableCls = (std::vector)cf_pc.cftpcFoundOverFindableCls; pc.fdParticleCuts[etpcFoundOverFindableCls][eMin] = ltpcFoundOverFindableCls[eMin]; pc.fdParticleCuts[etpcFoundOverFindableCls][eMax] = ltpcFoundOverFindableCls[eMax]; - auto ltpcFractionSharedCls = (vector)cf_pc.cftpcFractionSharedCls; + auto ltpcFractionSharedCls = (std::vector)cf_pc.cftpcFractionSharedCls; pc.fdParticleCuts[etpcFractionSharedCls][eMin] = ltpcFractionSharedCls[eMin]; pc.fdParticleCuts[etpcFractionSharedCls][eMax] = ltpcFractionSharedCls[eMax]; - auto ldcaXY = (vector)cf_pc.cfdcaXY; + 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 = (vector)cf_pc.cfdcaZ; + auto ldcaZ = (std::vector)cf_pc.cfdcaZ; pc.fdParticleCuts[edcaZ][eMin] = ldcaZ[eMin]; pc.fdParticleCuts[edcaZ][eMax] = ldcaZ[eMax]; - auto lPDG = (vector)cf_pc.cfPDG; + 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; -} // void DefaultCuts() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void defaultCuts() //============================================================ -void InsanityChecks() +void specificCuts(TString whichSpecificCuts) { - // Do insanity checks on configuration, booking, binning and cuts. + // 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) 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; - // f) Insanity checks on Toy NUA; - // g) Insanity checks on internal validation. + // a) Mapping; + // b) Implementation of analysis-specific cuts. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __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] = false; // I set it to false by default, to prevent having the standard memory blow-up by default + 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 + } - // a) Insanity checks on configuration: - // Remark: Here I also classify all cases which couple 2 or more categories: + ec.fUseEventCuts[eCentralityCorrelationsCut] = true; + ec.fsEventCuts[eCentralityCorrelationsCut] = "CentFT0C_CentFT0M"; + ec.fCentralityCorrelationsCutTreshold = 10.0; + ec.fCentralityCorrelationsCutVersion = "Absolute"; - // *) 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 filled \033[0m", __FUNCTION__, __LINE__); - } + // Particle cuts: + pc.fUseParticleCuts[eitsNCls] = true; + pc.fdParticleCuts[eitsNCls][eMin] = 5.; + pc.fdParticleCuts[eitsNCls][eMax] = 1000.; - // *) 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__); - } + pc.fUseParticleCuts[etpcNClsFound] = true; + pc.fdParticleCuts[etpcNClsFound][eMin] = 70.; + pc.fdParticleCuts[etpcNClsFound][eMax] = 1000.; - // *) 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 (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 kTRUE: 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__); - } + pc.fUseParticleCuts[etpcNClsCrossedRows] = true; + pc.fdParticleCuts[etpcNClsCrossedRows][eMin] = 70.; + pc.fdParticleCuts[etpcNClsCrossedRows][eMax] = 1000.; - // *) Insanity checks on event cuts: - if (ec.fUseEventCuts[eTrigger] && !(tc.fProcess[eProcessRec_Run2])) { - LOGF(fatal, "\033[1;31m%s at line %d : trigger \"%s\" => From documentation: Bypass this check if you analyse MC or continuous Run3 data. By now, it's validated only for \"Rec_Run2\", for other cases, simply switch off this event cut eTrigger. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eTrigger].Data()); - } + pc.fUseParticleCuts[etpcCrossedRowsOverFindableCls] = true; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMin] = 0.8; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax] = 1000.; - if (tc.fProcess[eProcessRec_Run2]) { - // TBI 20240517 for the time being, here I am enforcing that "kINT7" is mandatory for Run 2 and Run 1 converted real data - if (!(ec.fUseEventCuts[eTrigger] && ec.fsEventCuts[eTrigger].EqualTo("kINT7"))) { // TBI 20240223 expand this list with other supported triggers eventually in this category (see if(...) above) - 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 programmattic access to "event-selection-task" flags "isMC and "isRunMC" . Then I can directly bail out. - } - } + pc.fUseParticleCuts[etpcFoundOverFindableCls] = true; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMin] = 0.8; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMax] = 1000.; - if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim]) { // From documentation: Bypass this check if you analyse MC or continuous Run3 data. - if (ec.fUseEventCuts[eTrigger]) { - LOGF(fatal, "\033[1;31m%s at line %d : offline trigger eTrigger (e.g. kINT7) cannot be used in Run 3\033[0m", __FUNCTION__, __LINE__); - } - } + pc.fUseParticleCuts[etpcFractionSharedCls] = true; + pc.fdParticleCuts[etpcFractionSharedCls][eMin] = -1000.; + pc.fdParticleCuts[etpcFractionSharedCls][eMax] = 0.4; - if (ec.fUseEventCuts[eSel7]) { // from doc: for Run 2 data and MC - 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__); - } - } + pc.fUseParticleCuts[etpcChi2NCl] = true; + pc.fdParticleCuts[etpcChi2NCl][eMin] = -1000.; + pc.fdParticleCuts[etpcChi2NCl][eMax] = 4.0; - if (ec.fUseEventCuts[eSel8]) { // from doc: for Run 3 data and MC - if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim])) { - LOGF(fatal, "\033[1;31m%s at line %d : use eSel8 only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); - } - } + pc.fUseParticleCuts[edcaXY] = true; + pc.fdParticleCuts[edcaXY][eMin] = -2.4; // TBI 20250401 check further + pc.fdParticleCuts[edcaXY][eMax] = 2.4; // TBI 20250401 check further - if (ec.fUseEventCuts[eNoSameBunchPileup]) { - if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim])) { - LOGF(fatal, "\033[1;31m%s at line %d : use eNoSameBunchPileup only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); - } - } + pc.fUseParticleCuts[edcaZ] = true; + pc.fdParticleCuts[edcaZ][eMin] = -3.2; // TBI 20250401 check further + pc.fdParticleCuts[edcaZ][eMax] = 3.2; // TBI 20250401 check further - if (ec.fUseEventCuts[eIsGoodZvtxFT0vsPV]) { - if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim])) { - LOGF(fatal, "\033[1;31m%s at line %d : use eIsGoodZvtxFT0vsPV only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); - } - } + pc.fUseParticleCuts[eisInAcceptanceTrack] = false; // see enum + pc.fUseParticleCuts[eisGlobalTrack] = false; // only for Run 2 + pc.fUseParticleCuts[eisPVContributor] = true; - if (ec.fUseEventCuts[eIsVertexITSTPC]) { - if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim])) { - LOGF(fatal, "\033[1;31m%s at line %d : use eIsVertexITSTPC only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + break; } - } - if (ec.fUseEventCuts[eIsVertexTOFmatched]) { - if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim])) { - LOGF(fatal, "\033[1;31m%s at line %d : use eIsVertexTOFmatched only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); - } - } + 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] = false; // I set it to false by default, to prevent having the standard memory blow-up by default + 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 + } - if (ec.fUseEventCuts[eIsVertexTRDmatched]) { - if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim])) { - LOGF(fatal, "\033[1;31m%s at line %d : use eIsVertexTRDmatched only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); - } - } + 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"; - if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && !tc.fUseFisherYates) { - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } + // Particle cuts: + pc.fUseParticleCuts[eitsNCls] = true; + pc.fdParticleCuts[eitsNCls][eMin] = 5.; + pc.fdParticleCuts[eitsNCls][eMax] = 1000.; - if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim]) { - // Supported centrality estimators for Run 3 are enlisted here: - if (!(ec.fsEventCuts[eCentralityEstimator].EqualTo("centFT0M", TString::kIgnoreCase) || - ec.fsEventCuts[eCentralityEstimator].EqualTo("centFV0A", TString::kIgnoreCase) || - ec.fsEventCuts[eCentralityEstimator].EqualTo("centNTPV", TString::kIgnoreCase))) { - LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %s is not supported yet for Run 3 analysis. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); - } - } + pc.fUseParticleCuts[etpcNClsFound] = true; + pc.fdParticleCuts[etpcNClsFound][eMin] = 70.; + pc.fdParticleCuts[etpcNClsFound][eMax] = 1000.; - 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]) { - // Supported centrality estimators for Run 3 are enlisted here: - 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 yet for converted Run 2 and Run 1 analysis. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); - } - } + pc.fUseParticleCuts[etpcNClsCrossedRows] = true; + pc.fdParticleCuts[etpcNClsCrossedRows][eMin] = 70.; + pc.fdParticleCuts[etpcNClsCrossedRows][eMax] = 1000.; - // *) Insanity checks on particle cuts: - // **) Protection against particle cuts which are available, but not yet validated, or are meaningless, in Run 3: - if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim]) { - if (pc.fUseParticleCuts[eisQualityTrack]) { - LOGF(fatal, "\033[1;31m%s at line %d : particle cut isQualityTrack is not validated in Run 3 as of 20240516 => 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 is not validated in Run 3 as of 20240516 => it kills all reconstructed tracks \033[0m", __FUNCTION__, __LINE__); - } - } + pc.fUseParticleCuts[etpcCrossedRowsOverFindableCls] = true; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMin] = 0.8; + pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax] = 1000.; - // **) 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[etrackCutFlagFb1]) { - LOGF(fatal, "\033[1;31m%s at line %d : particle cut etrackCutFlagFb1 is not validated, as of 20240511 it kills all reconstructed tracks \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 20240511 it kills all reconstructed tracks \033[0m", __FUNCTION__, __LINE__); - } - } + pc.fUseParticleCuts[etpcFoundOverFindableCls] = true; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMin] = 0.8; + pc.fdParticleCuts[etpcFoundOverFindableCls][eMax] = 1000.; - // **) 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__); - } + pc.fUseParticleCuts[etpcFractionSharedCls] = true; + pc.fdParticleCuts[etpcFractionSharedCls][eMin] = -1000.; + pc.fdParticleCuts[etpcFractionSharedCls][eMax] = 0.4; - // *) Insanity checks on booking: - // ... + pc.fUseParticleCuts[etpcChi2NCl] = true; + pc.fdParticleCuts[etpcChi2NCl][eMin] = -1000.; + pc.fdParticleCuts[etpcChi2NCl][eMax] = 4.0; - // *) Insanity checks on binning: - // ... + pc.fUseParticleCuts[edcaXY] = true; + pc.fdParticleCuts[edcaXY][eMin] = -2.4; // TBI 20250401 check further + pc.fdParticleCuts[edcaXY][eMax] = 2.4; // TBI 20250401 check further - // *) Insanity checks on cuts: - // ... + pc.fUseParticleCuts[edcaZ] = true; + pc.fdParticleCuts[edcaZ][eMin] = -3.2; // TBI 20250401 check further + pc.fdParticleCuts[edcaZ][eMax] = 3.2; // TBI 20250401 check further - // *) 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() - 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__); + pc.fUseParticleCuts[eisInAcceptanceTrack] = false; // see enum + pc.fUseParticleCuts[eisGlobalTrack] = false; // only for Run 2 + pc.fUseParticleCuts[eisPVContributor] = true; + + break; } - if (pw.fUseWeights[wPHI] || pw.fUseWeights[wPT] || pw.fUseWeights[wETA]) { - LOGF(fatal, "\033[1;31m%s at line %d : integrated weights are not supported (yet) for internal validation. \033[0m", __FUNCTION__, __LINE__); + 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[eFT0Bad] = false; + ec.fUseEventCuts[eITSBad] = false; + ec.fUseEventCuts[eITSLimAccMCRepr] = false; + ec.fUseEventCuts[eTPCBadTracking] = false; + ec.fUseEventCuts[eTPCLimAccMCRepr] = false; + ec.fUseEventCuts[eTPCBadPID] = 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 + } + + ec.fUseEventCuts[eCentralityCorrelationsCut] = false; + ec.fsEventCuts[eCentralityCorrelationsCut] = "CentRun2V0M_CentRun2SPDTracklets"; + ec.fCentralityCorrelationsCutTreshold = 10.0; + ec.fCentralityCorrelationsCutVersion = "Absolute"; + + // ... + + // 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 + + // 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; + + eh.fBookEventHistograms[eOccupancy] = false; + eh.fBookEventHistograms[eInteractionRate] = false; + eh.fBookEventHistograms[eCurrentRunDuration] = false; + + qa.fBookQAEventHistograms2D[eMultiplicity_vs_Occupancy] = false; + qa.fBookQAEventHistograms2D[eMultiplicity_vs_InteractionRate] = false; + qa.fBookQAEventHistograms2D[eReferenceMultiplicity_vs_Occupancy] = false; + qa.fBookQAEventHistograms2D[eReferenceMultiplicity_vs_InteractionRate] = false; + qa.fBookQAEventHistograms2D[eNContributors_vs_Occupancy] = false; + qa.fBookQAEventHistograms2D[eNContributors_vs_InteractionRate] = false; + qa.fBookQAEventHistograms2D[eCentrality_vs_Occupancy] = false; + qa.fBookQAEventHistograms2D[eCentrality_vs_InteractionRate] = false; + qa.fBookQAEventHistograms2D[eVertexZ_vs_Occupancy] = false; + qa.fBookQAEventHistograms2D[eVertexZ_vs_InteractionRate] = false; + qa.fBookQAEventHistograms2D[eMultiplicity_vs_FT0CAmplitudeOnFoundBC] = false; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_FT0CAmplitudeOnFoundBC] = false; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentFT0CVariant1] = false; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentFT0M] = false; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentFV0A] = false; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentNTPV] = false; + qa.fBookQAEventHistograms2D[eCentFT0C_vs_CentNGlobal] = false; + qa.fBookQAEventHistograms2D[eCentFT0M_vs_CentNTPV] = false; + qa.fBookQAEventHistograms2D[eTrackOccupancyInTimeRange_vs_FT0COccupancyInTimeRange] = false; + + // ... + + break; } - if (pw.fUseDiffWeights[wPHIPT] || pw.fUseDiffWeights[wPHIETA]) { - LOGF(fatal, "\033[1;31m%s at line %d : differential weights are not supported (yet) for internal validation. \033[0m", __FUNCTION__, __LINE__); + // ... + + case eTestCuts: { + + // In this branch I implement default cuts and settings for minimal subscription, "processTest": "true in JSON + + // Event cuts: + // 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[eFT0Bad] = false; + ec.fUseEventCuts[eITSBad] = false; + ec.fUseEventCuts[eITSLimAccMCRepr] = false; + ec.fUseEventCuts[eTPCBadTracking] = false; + ec.fUseEventCuts[eTPCLimAccMCRepr] = false; + ec.fUseEventCuts[eTPCBadPID] = false; + + // 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 + + // ... + + // 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 + + // ... + + // 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; } - 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__); + 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 (iv.fUseInternalValidation) { + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } -} // void InsanityChecks() +} // void specificCuts(const char* specificCutsName) //============================================================ -void BookAndNestAllLists() +void insanityChecksOnDefinitionsOfConfigurables() { - // *) QA; - // *) Control event histograms; - // *) Control particle histograms; - // *) Correlations; - // *) Q-vectors; - // *) Particle weights; - // *) Nested loops; - // *) Toy NUA; - // *) Internal validation; - // *) Test0; - // *) Results. + // 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", __FUNCTION__); + StartFunction(__FUNCTION__); } - // *) QA: - qa.fQAList = new TList(); - qa.fQAList->SetName("QA"); - qa.fQAList->SetOwner(kTRUE); - fBaseList->Add(qa.fQAList); + // 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()); + } - // *) Event cuts: - ec.fEventCutsList = new TList(); - ec.fEventCutsList->SetName("EventCuts"); - ec.fEventCutsList->SetOwner(kTRUE); - fBaseList->Add(ec.fEventCutsList); + if (cf_tc.cfUseSpecificCuts) { + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! cfUseSpecificCuts = true, all settings in the current config are ignored !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + } - // *) Control event histograms: - eh.fEventHistogramsList = new TList(); - eh.fEventHistogramsList->SetName("EventHistograms"); - eh.fEventHistogramsList->SetOwner(kTRUE); - fBaseList->Add(eh.fEventHistogramsList); + // b) QA: + // ... - // *) Particle cuts: - pc.fParticleCutsList = new TList(); - pc.fParticleCutsList->SetName("ParticleCuts"); - pc.fParticleCutsList->SetOwner(kTRUE); - fBaseList->Add(pc.fParticleCutsList); + // c) Event histograms: + // ... - // *) Control particle histograms: - ph.fParticleHistogramsList = new TList(); - ph.fParticleHistogramsList->SetName("ParticleHistograms"); - ph.fParticleHistogramsList->SetOwner(kTRUE); - fBaseList->Add(ph.fParticleHistogramsList); + // d) Event cuts: + // ... - // *) Q-vectors: - qv.fQvectorList = new TList(); - qv.fQvectorList->SetName("Q-vectors"); - qv.fQvectorList->SetOwner(kTRUE); - fBaseList->Add(qv.fQvectorList); + // e) Particle histograms: + // ... - // *) Correlations: - mupa.fCorrelationsList = new TList(); - mupa.fCorrelationsList->SetName("Correlations"); - mupa.fCorrelationsList->SetOwner(kTRUE); - fBaseList->Add(mupa.fCorrelationsList); + // f) Particle cuts: + // ... - // *) Particle weights: - pw.fWeightsList = new TList(); - pw.fWeightsList->SetName("Weights"); - pw.fWeightsList->SetOwner(kTRUE); - fBaseList->Add(pw.fWeightsList); + // g) Q-vectors: + // ... - // *) Nested loops: - nl.fNestedLoopsList = new TList(); - nl.fNestedLoopsList->SetName("NestedLoops"); - nl.fNestedLoopsList->SetOwner(kTRUE); - fBaseList->Add(nl.fNestedLoopsList); - - // *) Toy NUA: - nua.fNUAList = new TList(); - nua.fNUAList->SetName("ToyNUA"); - nua.fNUAList->SetOwner(kTRUE); - fBaseList->Add(nua.fNUAList); - - // *) Internal validation: - iv.fInternalValidationList = new TList(); - iv.fInternalValidationList->SetName("InternalValidation"); - iv.fInternalValidationList->SetOwner(kTRUE); - fBaseList->Add(iv.fInternalValidationList); + // h) Multiparticle correlations: + // ... - // *) Test0: - t0.fTest0List = new TList(); - t0.fTest0List->SetName("Test0"); - t0.fTest0List->SetOwner(kTRUE); - fBaseList->Add(t0.fTest0List); + // i) Test0: + // ... - // *) Results: - res.fResultsList = new TList(); - res.fResultsList->SetName("Results"); - res.fResultsList->SetOwner(kTRUE); - fBaseList->Add(res.fResultsList); + // j) Particle weights: + // ... -} // void BookAndNestAllLists() + // k) Centrality weights: + // ... -//============================================================ + // l) Nested loops: + // ... -void BookQAHistograms() -{ - // Book all QA histograms and other related objects. + // m) Toy NUA: + // ... - // 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 + // n) Internal validation: + // ... - // a) Book the profile holding flags; - // b) Common local variables; - // c) Book specific QA 2D event histograms; - // d) Book specific QA 2D particle histograms. + // o) Results histograms: + // ... if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + ExitFunction(__FUNCTION__); } - // a) Book the profile holding flags: - qa.fQAHistogramsPro = new TProfile("fQAHistogramsPro", "flags for QA histograms", 2, 0., 2.); // TBI 20240515 re-think how to organize the binning here - qa.fQAHistogramsPro->SetStats(kFALSE); - 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.fQAList->Add(qa.fQAHistogramsPro); +} // insanityChecksOnDefinitionsOfConfigurables() - // b) Common local variables: - TString srs[2] = {"rec", "sim"}; - TString srs_long[2] = {"reconstructed", "simulated"}; - TString sba[2] = {"before", "after"}; - TString sba_long[2] = {"before cuts", "after cuts"}; +//============================================================ - // c) Book specific QA 2D event histograms: - // Binning of 2D event histos: TBI 20240503 see if you can automate all this - Int_t nBins_x_Event[eQAEventHistograms2D_N] = {0}; - Double_t min_x_Event[eQAEventHistograms2D_N] = {0.}; - Double_t max_x_Event[eQAEventHistograms2D_N] = {0.}; - TString title_x_Event[eQAEventHistograms2D_N] = {""}; - Int_t nBins_y_Event[eQAEventHistograms2D_N] = {0}; - Double_t min_y_Event[eQAEventHistograms2D_N] = {0.}; - Double_t max_y_Event[eQAEventHistograms2D_N] = {0.}; - TString title_y_Event[eQAEventHistograms2D_N] = {""}; +void insanityChecksBeforeBooking() +{ + // 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(). - // *) "MultTPC_vs_NContributors": - nBins_x_Event[eMultTPC_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eMultTPC][0]) / 10; // TBI 20240504 hardcoded number - min_x_Event[eMultTPC_vs_NContributors] = eh.fEventHistogramsBins[eMultTPC][1]; - max_x_Event[eMultTPC_vs_NContributors] = eh.fEventHistogramsBins[eMultTPC][2]; - title_x_Event[eMultTPC_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eMultTPC].Data()); - nBins_y_Event[eMultTPC_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eNContributors][0]) / 10; // TBI 20240504 hardcoded number - min_y_Event[eMultTPC_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][1]; - max_y_Event[eMultTPC_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][2]; - title_y_Event[eMultTPC_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); - - // *) "Vertex_z_vs_MultTPC": - nBins_x_Event[eVertex_z_vs_MultTPC] = static_cast(eh.fEventHistogramsBins[eVertex_z][0]) / 10; // TBI 20240504 hardcoded number - min_x_Event[eVertex_z_vs_MultTPC] = eh.fEventHistogramsBins[eVertex_z][1]; - max_x_Event[eVertex_z_vs_MultTPC] = eh.fEventHistogramsBins[eVertex_z][2]; - title_x_Event[eVertex_z_vs_MultTPC] = FancyFormatting(eh.fEventHistogramsName[eVertex_z].Data()); - nBins_y_Event[eVertex_z_vs_MultTPC] = static_cast(eh.fEventHistogramsBins[eMultTPC][0]) / 100; // TBI 20240504 hardcoded number - min_y_Event[eVertex_z_vs_MultTPC] = eh.fEventHistogramsBins[eMultTPC][1]; - max_y_Event[eVertex_z_vs_MultTPC] = eh.fEventHistogramsBins[eMultTPC][2]; - title_y_Event[eVertex_z_vs_MultTPC] = FancyFormatting(eh.fEventHistogramsName[eMultTPC].Data()); - - // *) "Vertex_z_vs_NContributors": - nBins_x_Event[eVertex_z_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eVertex_z][0]) / 10; // TBI 20240504 hardcoded number - min_x_Event[eVertex_z_vs_NContributors] = eh.fEventHistogramsBins[eVertex_z][1]; - max_x_Event[eVertex_z_vs_NContributors] = eh.fEventHistogramsBins[eVertex_z][2]; - title_x_Event[eVertex_z_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eVertex_z].Data()); - nBins_y_Event[eVertex_z_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eNContributors][0]) / 10; // TBI 20240504 hardcoded number - min_y_Event[eVertex_z_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][1]; - max_y_Event[eVertex_z_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][2]; - title_y_Event[eVertex_z_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); - - // *) "eCentFT0M_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()); + // 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. - // *) "eCentRun2V0M_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()); + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } - // *) "eCentRun2V0M_vs_NContributors": - nBins_x_Event[eCentRun2V0M_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eCentrality][0]); - min_x_Event[eCentRun2V0M_vs_NContributors] = eh.fEventHistogramsBins[eCentrality][1]; - max_x_Event[eCentRun2V0M_vs_NContributors] = eh.fEventHistogramsBins[eCentrality][2]; - title_x_Event[eCentRun2V0M_vs_NContributors] = FancyFormatting(qa.fCentralityEstimatorName[eCentRun2V0M].Data()); - nBins_y_Event[eCentRun2V0M_vs_NContributors] = static_cast(eh.fEventHistogramsBins[eNContributors][0]); - min_y_Event[eCentRun2V0M_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][1]; - max_y_Event[eCentRun2V0M_vs_NContributors] = eh.fEventHistogramsBins[eNContributors][2]; - title_y_Event[eCentRun2V0M_vs_NContributors] = FancyFormatting(eh.fEventHistogramsName[eNContributors].Data()); + // a) Insanity checks on configuration: - // ... + // **) 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__); + } - // *) Quick insanity check on title_x_Event and title_y_Event: - for (Int_t t = 0; t < eQAEventHistograms2D_N; t++) { - 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); - } - 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); - } + // **) 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__); } - // Okay, let's book 'em all: - for (Int_t t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eQAEventHistograms2D - { - if (!qa.fBookQAEventHistograms2D[t]) { - continue; + // **) 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); } - 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.fProcess[eProcessTest] is treated as tc.fProcess[eProcessRec], for the time being - if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && rs == eRec)) { - continue; - } + } - // If I am doing internal validation, I need only sim: - if (iv.fUseInternalValidation && rs == eRec) { - continue; - } + // **) 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__); + } - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - { - qa.fQAEventHistograms2D[t][rs][ba] = new TH2D( - Form("fQAEventHistograms2D[%s][%s][%s]", qa.fEventHistogramsName2D[t].Data(), srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", "__RUN_NUMBER__", srs_long[rs].Data(), sba_long[ba].Data()), // __RUN_NUMBER__ is handled in DetermineAndPropagateRunNumber(T const& collision) - nBins_x_Event[t], min_x_Event[t], max_x_Event[t], nBins_y_Event[t], min_y_Event[t], max_y_Event[t]); + // **) 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); + } + } - 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.fQAList->Add(qa.fQAEventHistograms2D[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;t 0 && !tc.fUseFisherYates) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m : Did you forget to enable Fisher-Yates algorithm?", __FUNCTION__, __LINE__); + } - // ... + // **) 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__); + } - // c) Book specific QA 2D particle histograms: - // Binning of 2D particle histos: TBI 20240503 see if you can automate all this - Int_t nBins_x_Particle[eQAParticleHistograms2D_N] = {0}; - Double_t min_x_Particle[eQAParticleHistograms2D_N] = {0.}; - Double_t max_x_Particle[eQAParticleHistograms2D_N] = {0.}; - TString title_x_Particle[eQAParticleHistograms2D_N] = {""}; - Int_t nBins_y_Particle[eQAParticleHistograms2D_N] = {0}; - Double_t min_y_Particle[eQAParticleHistograms2D_N] = {0.}; - Double_t max_y_Particle[eQAParticleHistograms2D_N] = {0.}; - TString title_y_Particle[eQAParticleHistograms2D_N] = {""}; + // **) 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__); + } - // *) "dcaXY_vs_Pt": - nBins_x_Particle[edcaXY_vs_Pt] = static_cast(ph.fParticleHistogramsBins[edcaXY][0]) / 10; // TBI 20240504 hardcoded number - min_x_Particle[edcaXY_vs_Pt] = ph.fParticleHistogramsBins[edcaXY][1]; - max_x_Particle[edcaXY_vs_Pt] = ph.fParticleHistogramsBins[edcaXY][2]; - title_x_Particle[edcaXY_vs_Pt] = FancyFormatting(ph.fParticleHistogramsName[edcaXY].Data()); - nBins_y_Particle[edcaXY_vs_Pt] = static_cast(ph.fParticleHistogramsBins[ePt][0]) / 10; // TBI 20240504 hardcoded number - min_y_Particle[edcaXY_vs_Pt] = ph.fParticleHistogramsBins[ePt][1]; - max_y_Particle[edcaXY_vs_Pt] = ph.fParticleHistogramsBins[ePt][2]; - title_y_Particle[edcaXY_vs_Pt] = FancyFormatting(ph.fParticleHistogramsName[ePt].Data()); + // **) 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__); + } - // ... + // **) Insanity checks on event cuts: - // *) Quick insanity check on title_x_Particle and title_y_Particle: - for (Int_t 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); + // **) 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__); } } - // Okay, let's book 'em all: - for (Int_t t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eQAParticleHistograms2D - { - if (!qa.fBookQAParticleHistograms2D[t]) { - continue; - } - 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.fProcess[eProcessTest] is treated as tc.fProcess[eProcessRec], for the time being - if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && rs == eRec)) { - continue; + // **) Check if the trigger makes sense or was validated for this dataset: + if (ec.fUseEventCuts[eTrigger]) { + + // 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()); } + } - // If I am doing internal validation, I need only sim: - if (iv.fUseInternalValidation && rs == eRec) { - continue; + // 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()); } + } - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - { - qa.fQAParticleHistograms2D[t][rs][ba] = new TH2D( - Form("fQAParticleHistograms2D[%s][%s][%s]", qa.fParticleHistogramsName2D[t].Data(), srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", "__RUN_NUMBER__", srs_long[rs].Data(), sba_long[ba].Data()), // __RUN_NUMBER__ is handled in DetermineAndPropagateRunNumber(T const& collision) - nBins_x_Particle[t], min_x_Particle[t], max_x_Particle[t], nBins_y_Particle[t], min_y_Particle[t], max_y_Particle[t]); + // Validated and supported Run 1 triggers: + // ... - 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.fQAList->Add(qa.fQAParticleHistograms2D[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;t 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]); + } + } -//============================================================ + // **) 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 -void BookEventHistograms() -{ - // Book all event histograms. + // 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. + // } + // } - // a) Book the profile holding flags; - // b) Book specific event histograms 1D; - // c) Book specific event histograms 2D. + // **) 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); + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + // **) 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); } - // 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); + // **) 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); + } - // b) Book specific control event histograms 1D: - TString srs[2] = {"rec", "sim"}; - TString srs_long[2] = {"reconstructed", "simulated"}; - TString sba[2] = {"before", "after"}; - TString sba_long[2] = {"before cuts", "after cuts"}; + // ** For simulated data when fDatabasePDG is NOT used, I have to disable cut on charge, since that info is not available: + if ((tc.fProcess[eGenericRecSim] || tc.fProcess[eGenericSim]) && pc.fUseParticleCuts[eCharge] && !tc.fUseDatabasePDG) { + LOGF(fatal, "\033[1;31m%s at line %d : For simulated data when fDatabasePDG is NOT used, I have to disable cut on charge, since that info is not available.\033[0m", __FUNCTION__, __LINE__); + } + // ** Make sure I am using fDatabasePDG only over Monte Carlo data: + if (tc.fUseDatabasePDG && !(tc.fProcess[eGenericRecSim] || tc.fProcess[eGenericSim])) { + LOGF(fatal, "\033[1;31m%s at line %d : Use fDatabasePDG only over Monte Carlo datasets.\033[0m", __FUNCTION__, __LINE__); + } - for (Int_t t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms - { - if (!eh.fBookEventHistograms[t]) { - continue; + // 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__); } - 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.fProcess[eProcessTest] is treated as tc.fProcess[eProcessRec], for the time being - if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && rs == eRec)) { - continue; - } + } - // If I am doing internal validation, I need only sim: - if (iv.fUseInternalValidation && rs == eRec) { - continue; - } + // **) 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__); + } - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - { + // **) 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()); + } + } - // Special treatment for eSelectedTracks => I will never fill this one before the cuts, obviously: - if (ba == eBefore && eh.fEventHistogramsName[t].EqualTo("SelectedTracks")) { - continue; - } + // **) 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__); + } + } - eh.fEventHistograms[t][rs][ba] = new TH1D( - Form("fEventHistograms[%s][%s][%s]", eh.fEventHistogramsName[t].Data(), srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", "__RUN_NUMBER__", srs_long[rs].Data(), sba_long[ba].Data()), // __RUN_NUMBER__ is handled in DetermineAndPropagateRunNumber(T const& collision) - static_cast(eh.fEventHistogramsBins[t][0]), - eh.fEventHistogramsBins[t][1], eh.fEventHistogramsBins[t][2]); + // **) 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__); + } + } - 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_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for(Int_t t=0;t(eEventCuts_N) - 0.5); - ec.fEventCutsPro->SetStats(kFALSE); - ec.fEventCutsPro->SetLineColor(eColor); - ec.fEventCutsPro->SetFillColor(eFillColor); - for (Int_t 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])); + 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__); + } } - ec.fEventCutsList->Add(ec.fEventCutsPro); - // b) Book event cut counter maps: - for (Int_t 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; + 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__); } - ec.fEventCutCounterMap[rs] = new TExMap(); - ec.fEventCutCounterMapInverse[rs] = new TExMap(); } - // c) Book event cut counter histograms: - TString srs[2] = {"rec", "sim"}; - TString srs_long[2] = {"reconstructed", "simulated"}; - TString scc[eCutCounter_N] = {"abs", "seq"}; - TString scc_long[eCutCounter_N] = {"absolute", "sequential"}; - 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. - if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && rs == eRec)) { - continue; + 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 I am doing internal validation, I need only sim: - if (iv.fUseInternalValidation && rs == eRec) { - continue; + 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__); } + } - for (Int_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter - { + 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.fUseEventCutCounterAbsolute && cc == eAbsolute) || (!ec.fUseEventCutCounterSequential && cc == eSequential)) { - continue; - } + 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__); + } + } - ec.fEventCutCounterHist[rs][cc] = new TH1D(Form("fEventCutCounterHist[%s][%s]", srs[rs].Data(), scc[cc].Data()), Form("%s, %s, event cut counter (%s)", "__RUN_NUMBER__", srs_long[rs].Data(), scc_long[cc].Data()), eEventCuts_N, 0.5, static_cast(eEventCuts_N) + 0.5); - ec.fEventCutCounterHist[rs][cc]->SetStats(kFALSE); - ec.fEventCutCounterHist[rs][cc]->SetLineColor(eColor); - ec.fEventCutCounterHist[rs][cc]->SetFillColor(eFillColor); - // 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]); + 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__); + } + } - } // for (Int_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + 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__); + } + } - } // for (Int_t rs = 0; rs < 2; rs++) // reco/sim + 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__); + } + } -} // void BookEventCutsHistograms() + 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 (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__); + } + } -void BookParticleHistograms() -{ - // Book all particle histograms. + 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__); + } + } - // a) Book the profile holding flags; - // b) Book specific particle histograms 1D; - // c) Book specific particle histograms 2D. + 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__); + } + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + if (ec.fUseEventCuts[eFT0Bad] || ec.fUseEventCuts[eITSBad] || ec.fUseEventCuts[eITSLimAccMCRepr] || ec.fUseEventCuts[eTPCBadTracking] || ec.fUseEventCuts[eTPCLimAccMCRepr] || ec.fUseEventCuts[eTPCBadPID]) { + if (!(tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA])) { + LOGF(fatal, "\033[1;31m%s at line %d : use eFT0Bad, eITSBad, eITSLimAccMCRepr, eTPCBadTracking, eTPCLimAccMCRepr, eTPCBadPID only for Run 3 data and MC\033[0m", __FUNCTION__, __LINE__); + } } - // a) Book the profile holding flags: - ph.fParticleHistogramsPro = new TProfile( - "fParticleHistogramsPro", "flags for particle histograms", 1, 0., 1.); - ph.fParticleHistogramsPro->SetStats(kFALSE); - ph.fParticleHistogramsPro->SetLineColor(eColor); - ph.fParticleHistogramsPro->SetFillColor(eFillColor); - // ... TBI 20240418 I shall fill something in this config profile... - ph.fParticleHistogramsList->Add(ph.fParticleHistogramsPro); + // **) 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__); + } - // b) Book specific particle histograms 1D: - TString srs[2] = {"rec", "sim"}; - TString srs_long[2] = {"reconstructed", "simulated"}; - TString sba[2] = {"before", "after"}; - TString sba_long[2] = {"before cuts", "after cuts"}; + // **) 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__); + } - for (Int_t t = 0; t < eParticleHistograms_N; t++) // type, see enum eParticleHistograms - { - if (!ph.fBookParticleHistograms[t]) { - continue; + // **) 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()); } - 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. - if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && rs == eRec)) { - continue; - } + // **) Protection against particle cuts which are available, but not yet validated, or are meaningless, in Run 3: + if (tc.fProcess[eProcessRec] || tc.fProcess[eProcessRecSim] || tc.fProcess[eProcessSim] || tc.fProcess[eProcessQA]) { + if (pc.fUseParticleCuts[etrackCutFlag]) { + LOGF(fatal, "\033[1;31m%s at line %d : particle cut trackCutFlag is not validated in Run 3 as of 20250113 => 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__); + } + } - // **) PDG makes sense only for Sim: - if ((tc.fProcess[eGenericRec] || tc.fProcess[eGenericRecSim]) && rs == eRec) { - if (t == ePDG) { - continue; - } - } + // **) 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 I am doing internal validation, I need only sim: - if (iv.fUseInternalValidation && rs == eRec) { - continue; - } + // 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__); + } + } - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - { - ph.fParticleHistograms[t][rs][ba] = new TH1D(Form("fParticleHistograms[%s][%s][%s]", ph.fParticleHistogramsName[t].Data(), srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", "__RUN_NUMBER__", srs_long[rs].Data(), 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_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for(Int_t t=0;t(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__); + // d) Insanity checks on binning: + // ... + + // 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__); } + // ... - for (Int_t t = 0; t < eParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D - { - if (!ph.fBookParticleHistograms2D[t]) { - continue; + // f) Insanity checks on Toy NUA: + // ... + + // 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__); } - for (Int_t rs = 0; rs < 2; rs++) // reco/sim - { - if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && 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 - { - // optional variable-length binning for y-axis (for supported observables): - if (ph.fParticleHistogramsName2D[t].EqualTo("PhiPt") && res.fUseResultsProVariableLengthBins[AFO_PT]) { + 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()); + } - // Remark: placeholder __RUN_NUMBER__ is handled in DetermineAndPropagateRunNumber(T const& collision) + 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__); + } - // *) variable-length binning for phi vs pt, but only in pt axis: - ph.fParticleHistograms2D[t][rs][ba] = new TH2D(Form("fParticleHistograms2D[%s][%s][%s]", ph.fParticleHistogramsName2D[t].Data(), srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", "__RUN_NUMBER__", srs_long[rs].Data(), sba_long[ba].Data()), - static_cast(ph.fParticleHistogramsBins2D[t][eX][0]), ph.fParticleHistogramsBins2D[t][eX][1], ph.fParticleHistogramsBins2D[t][eX][2], // TBI 20240418 this is not safe, eX doesn't have to be phi axis in general, but it's ok for the time being => re-thing and fix later - 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("PhiEta") && res.fUseResultsProVariableLengthBins[AFO_ETA]) { + 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__); + } - // *) variable-length binning for phi vs eta, but only in eta axis: - ph.fParticleHistograms2D[t][rs][ba] = new TH2D(Form("fParticleHistograms2D[%s][%s][%s]", ph.fParticleHistogramsName2D[t].Data(), srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", "__RUN_NUMBER__", srs_long[rs].Data(), sba_long[ba].Data()), - static_cast(ph.fParticleHistogramsBins2D[t][eX][0]), ph.fParticleHistogramsBins2D[t][eX][1], ph.fParticleHistogramsBins2D[t][eX][2], // TBI 20240418 this is not safe, eX doesn't have to be phi axis in general, but it's ok for the time being => re-thing and fix later - 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-langth binnging: - ph.fParticleHistograms2D[t][rs][ba] = new TH2D(Form("fParticleHistograms2D[%s][%s][%s]", ph.fParticleHistogramsName2D[t].Data(), srs[rs].Data(), sba[ba].Data()), - Form("%s, %s, %s", "__RUN_NUMBER__", srs_long[rs].Data(), 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_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for(Int_t t=0;t(eParticleCuts_N) - 0.5); - pc.fParticleCutsPro->SetStats(kFALSE); - pc.fParticleCutsPro->SetLineColor(eColor); - pc.fParticleCutsPro->SetFillColor(eFillColor); - for (Int_t 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); + // a) Insanity checks on booking: - // b) Book particle cut counter maps: - for (Int_t 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(); + // **) Check that the last bin is not empty in fBasePro, and that there is no underflow or overflow bins: + if (std::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 (std::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__); } - // c) Book the particle cut counter (absolute): - TString srs[2] = {"rec", "sim"}; - TString srs_long[2] = {"reconstructed", "simulated"}; - TString scc[eCutCounter_N] = {"abs", "seq"}; - TString scc_long[eCutCounter_N] = {"absolute", "sequential"}; + // ... - for (Int_t rs = 0; rs < 2; rs++) // reco/sim - { + // b) Insanity checks on internal validation: + if (iv.fUseInternalValidation) { - // If I am analyzing only reconstructed data, do not book histos for simulated, and vice versa. - if ((tc.fProcess[eGenericRec] && rs == eSim) || (tc.fProcess[eGenericSim] && rs == eRec)) { - continue; + // **) 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 I am doing internal validation, I need only sim: - if (iv.fUseInternalValidation && rs == eRec) { - continue; + 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__); } - for (Int_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter - { - - if ((!pc.fUseParticleCutCounterAbsolute && cc == eAbsolute) || (!pc.fUseParticleCutCounterSequential && cc == eSequential)) { - continue; - } - - pc.fParticleCutCounterHist[rs][cc] = new TH1D(Form("fParticleCutCounterHist[%s][%s]", srs[rs].Data(), scc[cc].Data()), Form("%s, %s, particle cut counter (%s)", "__RUN_NUMBER__", srs_long[rs].Data(), scc_long[cc].Data()), eParticleCuts_N, 0.5, static_cast(eParticleCuts_N) + 0.5); - pc.fParticleCutCounterHist[rs][cc]->SetStats(kFALSE); - pc.fParticleCutCounterHist[rs][cc]->SetLineColor(eColor); - pc.fParticleCutCounterHist[rs][cc]->SetFillColor(eFillColor); - // 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]); + // **) 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__); + } - } // for (Int_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + } // end of if (iv.fUseInternalValidation) { - } // for (Int_t 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 insanityChecksAfterBooking() //============================================================ -void BookQvectorHistograms() +void purgeAfterBooking() { - // Book all Q-vector histograms. + // I can purge a few objects used for common consistent booking across different group of histograms. - // a) Book the profile holding flags; - // b) ... + // TBI 20250518 I now automatically purge only 2D and 3D objects, I can refine further an purge also the lighte objects, if necessary + + // a) Purge results histograms and related objects; + // ... if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __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); + return; // TBI 20250625 the code below is not ready yet, because I still use these 2D and 3D histos in in FillqvectorNdim(...) - // b) ... + // a) Purge results histograms and related objects: + if (!res.fSaveResultsHistograms) { + for (int v = 0; v < eAsFunctionOf2D_N; v++) { + if (res.fResultsPro2D[v]) { + delete res.fResultsPro2D[v]; + res.fResultsPro2D[v] = NULL; + } + } + + for (int v = 0; v < eAsFunctionOf3D_N; v++) { + if (res.fResultsPro3D[v]) { + delete res.fResultsPro3D[v]; + res.fResultsPro3D[v] = NULL; + } + } + } // if(!res.fSaveResultsHistograms) -} // void BookQvectorHistograms() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void purgeAfterBooking() //============================================================ -void BookCorrelationsHistograms() +bool Skip(int recOrSim) { - // Book all correlations histograms. + // Decide here whether a certain histogram, etc., will be booked and used both for eRec and eSim. + // Same for cuts. - // a) Book the profile holding flags; - // b) Common local labels; - // c) Histograms; - // d) Few quick insanity checks on booking. + if (tc.fVerboseUtility) { + StartFunction(__FUNCTION__); + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + // *) Insanity check: + if (!(recOrSim == eRec || recOrSim == eSim)) { + LOGF(fatal, "\033[1;31m%s at line %d : recOrSim = %d \033[0m", __FUNCTION__, __LINE__, recOrSim); } - // 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); + // *) 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 + } + } - if (!mupa.fCalculateCorrelations) { - return; + // *) 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 } - // 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}"}; + return false; // by default, I do not skip anything - // 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, "\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(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] +} // bool Skip(int recOrSim) - // 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")) { +//============================================================ + +void bookAndNestAllLists() +{ + // *) 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.fVerbose) { + StartFunction(__FUNCTION__); + } + + // *) 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 + } + + // **) 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 + } + + // **) 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 + } + + // **) 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 + } + + // **) 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 + } + + // *) Event cuts: + ec.fEventCutsList = new TList(); + ec.fEventCutsList->SetName("EventCuts"); + ec.fEventCutsList->SetOwner(true); + fBaseList->Add(ec.fEventCutsList); + + // *) Control event histograms: + eh.fEventHistogramsList = new TList(); + eh.fEventHistogramsList->SetName("EventHistograms"); + eh.fEventHistogramsList->SetOwner(true); + fBaseList->Add(eh.fEventHistogramsList); + + // *) Particle cuts: + pc.fParticleCutsList = new TList(); + pc.fParticleCutsList->SetName("ParticleCuts"); + pc.fParticleCutsList->SetOwner(true); + fBaseList->Add(pc.fParticleCutsList); + + // *) Control particle histograms: + ph.fParticleHistogramsList = new TList(); + ph.fParticleHistogramsList->SetName("ParticleHistograms"); + ph.fParticleHistogramsList->SetOwner(true); + fBaseList->Add(ph.fParticleHistogramsList); + + // *) Q-vectors: + qv.fQvectorList = new TList(); + qv.fQvectorList->SetName("Q-vectors"); + qv.fQvectorList->SetOwner(true); + fBaseList->Add(qv.fQvectorList); + + // *) 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); + + // *) Centrality weights: + cw.fCentralityWeightsList = new TList(); + cw.fCentralityWeightsList->SetName("CentralityWeights"); + cw.fCentralityWeightsList->SetOwner(true); + fBaseList->Add(cw.fCentralityWeightsList); + + // *) 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() + +//========================================================== + +void bookQAHistograms() +{ + // 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 + + // 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) { + StartFunction(__FUNCTION__); + } + + // *) 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__); + } + + // 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); + + if (tc.fUseSetBinLabel) { + 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)); + + // ... + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fCheckUnderflowAndOverflow; ", 1); + qa.fQAHistogramsPro->Fill(0.5, static_cast(qa.fCheckUnderflowAndOverflow)); + + yAxisTitle += TString::Format("%d:fFillQAEventHistograms2D; ", 2); + qa.fQAHistogramsPro->Fill(1.5, static_cast(qa.fFillQAEventHistograms2D)); + + yAxisTitle += TString::Format("%d:fFillQAParticleHistograms2D; ", 3); + qa.fQAHistogramsPro->Fill(2.5, static_cast(qa.fFillQAParticleHistograms2D)); + + yAxisTitle += TString::Format("%d:fFillQAParticleEventHistograms2D; ", 4); + qa.fQAHistogramsPro->Fill(3.5, static_cast(qa.fFillQAParticleEventHistograms2D)); + + yAxisTitle += TString::Format("%d:fFillQACorrelationsVsHistograms2D; ", 5); + qa.fQAHistogramsPro->Fill(4.5, static_cast(qa.fFillQACorrelationsVsHistograms2D)); + + yAxisTitle += TString::Format("%d:fFillQACorrelationsVsInteractionRateVsProfiles2D; ", 6); + qa.fQAHistogramsPro->Fill(5.5, static_cast(qa.fFillQACorrelationsVsInteractionRateVsProfiles2D)); + + yAxisTitle += TString::Format("%d:fRebin; ", 7); + qa.fQAHistogramsPro->Fill(6.5, static_cast(qa.fRebin)); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != qa.fQAHistogramsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != qa.fQAHistogramsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), qa.fQAHistogramsPro->GetNbinsX()); + } + delete oa; + + // *) Okay, set the title: + qa.fQAHistogramsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + + 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 + + // *) "Centrality_vs_CentralitySim": + nBins_x_Event[eCentrality_vs_CentralitySim] = eh.fEventHistogramsBins[eCentrality][0]; + min_x_Event[eCentrality_vs_CentralitySim] = eh.fEventHistogramsBins[eCentrality][1]; + max_x_Event[eCentrality_vs_CentralitySim] = eh.fEventHistogramsBins[eCentrality][2]; + title_x_Event[eCentrality_vs_CentralitySim] = FancyFormatting(eh.fEventHistogramsName[eCentrality].Data()); + nBins_y_Event[eCentrality_vs_CentralitySim] = eh.fEventHistogramsBins[eCentrality][0]; + min_y_Event[eCentrality_vs_CentralitySim] = eh.fEventHistogramsBins[eCentrality][1]; + max_y_Event[eCentrality_vs_CentralitySim] = eh.fEventHistogramsBins[eCentrality][2]; + title_y_Event[eCentrality_vs_CentralitySim] = "simulated centrality (calculated from IP)"; // 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()); + } + 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); + } + + // **) title_y_Event: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m title_y_Event[%d] = %s \033[0m", t, title_y_Event[t].Data()); + } + 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); + } + + } // 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; + } + for (int rs = 0; rs < 2; rs++) // reco/sim + { + + if (Skip(rs)) { + continue; + } + + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + + // 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; + } + + // 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.srsLong[rs].Data(), gc.sbaLong[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(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); + } + } + + // 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 + { + + if (Skip(rs)) { + continue; + } + + 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.srsLong[rs].Data(), gc.sbaLong[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 (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); + } + } + + // 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 + { + + if (Skip(rs)) { + continue; + } + + for (int ba = 0; ba < 2; ba++) // before/after cuts + { + + if (ba == eBefore) { // TBI 20241214 re-think if I need these additional QA particle event histos before cuts + continue; + } + + // 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.srsLong[rs].Data(), gc.sbaLong[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;t(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); + } + } + + // Okay, let's book 'em all: + for (int t = 0; t < eQACorrelationsVsHistograms2D_N; t++) // type, see enum eQACorrelationsVsHistograms2D + { + if (!qa.fBookQACorrelationsVsHistograms2D[t]) { + continue; + } + + for (int h = 0; h < gMaxHarmonic; h++) { + + if (h + 1 < qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMin] || h + 1 >= qa.fQACorrelationsVsHistogramsMinMaxHarmonic[eMax]) { + continue; + } + + for (int rs = 0; rs < 2; rs++) // reco/sim + { + + if (Skip(rs)) { + continue; + } + + // 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.srsLong[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); + } + } + + // 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; + } + + for (int rs = 0; rs < 2; rs++) // reco/sim + { + + if (Skip(rs)) { + continue; + } + + // 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.srsLong[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]); + + 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 + + } // for (int h = 0; h < gMaxHarmonic; h++) { + + } // for(int t=0;tSetStats(false); + eh.fEventHistogramsPro->SetLineColor(eColor); + eh.fEventHistogramsPro->SetFillColor(eFillColor); + + if (tc.fUseSetBinLabel) { + eh.fEventHistogramsPro->GetXaxis()->SetBinLabel(1, "fFillEventHistograms"); + eh.fEventHistogramsPro->Fill(0.5, static_cast(eh.fFillEventHistograms)); + + // ... + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fFillEventHistograms; ", 1); // TBI 20250411 hardwired 1 + eh.fEventHistogramsPro->Fill(0.5, static_cast(eh.fFillEventHistograms)); // TBI 20250411 hardwired 0.5 + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != eh.fEventHistogramsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != eh.fEventHistogramsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), eh.fEventHistogramsPro->GetNbinsX()); + } + delete oa; + + // *) Okay, set the title: + eh.fEventHistogramsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + + eh.fEventHistogramsList->Add(eh.fEventHistogramsPro); + + // b) Book specific control event histograms 1D: + // ... + + for (int t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms + { + if (!eh.fBookEventHistograms[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 + { + + // 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.srsLong[rs].Data(), gc.sbaLong[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(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); + + TString yAxisTitle = ""; // TBI 20250413 when I fall back on using SetBinLabel(...), this variable is declared but will be unused + for (int cut = 0; cut < eEventCuts_N; cut++) { + + if (tc.fUseSetBinLabel) { + ec.fEventCutsPro->GetXaxis()->SetBinLabel(1 + cut, ec.fEventCutName[cut].Data()); // Remark: check always if bin labels here correspond to ordering in enum eEventCuts + } else { + // Workaround for SetBinLabel() large memory consumption: + yAxisTitle += TString::Format("%d:%s; ", 1 + cut, ec.fEventCutName[cut].Data()); + } + + ec.fEventCutsPro->Fill(cut, static_cast(ec.fUseEventCuts[cut])); + + } // for (int cut = 0; cut < eEventCuts_N; cut++) { + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + if (!tc.fUseSetBinLabel) { + + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != ec.fEventCutsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() = %d != ec.fEventCutsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), ec.fEventCutsPro->GetNbinsX()); + } + delete oa; + + // *) Okay, set the title: + ec.fEventCutsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + } // if(!tc.fUseSetBinLabel) + + ec.fEventCutsList->Add(ec.fEventCutsPro); + + // 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(); + } + + // c) Book event cut counter histograms: + // ... + for (int rs = 0; rs < 2; rs++) // reco/sim + { + + if (Skip(rs)) { + continue; + } + + for (int cc = 0; cc < eCutCounter_N; cc++) // cut counter + { + + if ((!ec.fUseEventCutCounterAbsolute && cc == eAbsolute) || (!ec.fUseEventCutCounterSequential && cc == eSequential)) { + continue; + } + + 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.srsLong[rs].Data(), gc.sccLong[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); + + // 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]); + + } // for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + + } // for (int rs = 0; rs < 2; rs++) // reco/sim + + // d) Book the formulas for all event cuts defined via mathematical expressions: + + // **) eRefMultVsNContrUp: + if (ec.fUseEventCuts[eRefMultVsNContrUp]) { + if (tc.fUseFormula) { + ec.fEventCutsFormulas[eRefMultVsNContrUp_Formula] = new TFormula("RefMultVsNContrUp_Formula", ec.fsEventCuts[eRefMultVsNContrUp].Data()); + + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! There is a large memory blow-up when using TFormula() !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + + // 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__); + } + } else { + // This is a workaround to evaluate upper boundary of HMO cut, until large-memory consumption with TFormula is resolved. + + // Algorithm: 1. ec.fsEventCuts[eRefMultVsNContrUp].Data() is linear expression in the mandatory format "p0 + p1*x". + // 2. Then I extract p0 and p1, and store them in float fdEventCutsFormulas[eEventCutsFormulas_N][2] = {{0.}} + // 3. Those values are then used in temporary function float RefMultVsNContr(const float &refMult, ...) + + this->GetP0P1(ec.fsEventCuts[eRefMultVsNContrUp].ReplaceAll(" ", ""), eRefMultVsNContrUp_Formula); + + } // else + + } // if (ec.fUseEventCuts[eRefMultVsNContrUp]) + + // **) eRefMultVsNContrLow: + if (ec.fUseEventCuts[eRefMultVsNContrLow]) { + if (tc.fUseFormula) { + ec.fEventCutsFormulas[eRefMultVsNContrLow_Formula] = new TFormula("RefMultVsNContrLow_Formula", ec.fsEventCuts[eRefMultVsNContrLow].Data()); + + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! There is a large memory blow-up when using TFormula() !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + + // 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__); + } + } else { + // This is a workaround to evaluate upper boundary of HMO cut, until large-memory consumption with TFormula is resolved. + + // Algorithm: See above for eRefMultVsNContrUp + this->GetP0P1(ec.fsEventCuts[eRefMultVsNContrLow].ReplaceAll(" ", ""), eRefMultVsNContrLow_Formula); + } + + } // if (ec.fUseEventCuts[eRefMultVsNContrLow]) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void bookEventCutsHistograms() + +//============================================================ + +void GetP0P1(const char* formula, eEventCutsFormulas whichCutFormula) +{ + // This is a sort of temporary parser, which extracts from linear expression p0 + p1*x coefficients p0 and p1, and stores them into float fdEventCutsFormulas[eEventCutsFormulas_N][2] = {{0.}} + // Remark #0: I need all this gym until large memory consumption with TFormula is resolved; + // Remark #1: Remove all blanks in 'formula' before calling this function; + // Remark #2: If I need to go beyond p1, use recursion instead. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + TString signP0 = ""; + TString signP1 = ""; + TString P0 = ""; + TString P1 = ""; + + // P0 signature parser: + int offset = 0; + if (TString(formula[0]).EqualTo("-")) { + signP0 = "-"; + offset = 1; + } + + // P0 parser + P1 signature parser: + int c1 = 0; + for (int c = 0 + offset; c < static_cast(strlen(formula)); c++) { + if (!(TString(formula[c]).EqualTo("-") || TString(formula[c]).EqualTo("+") || TString(formula[c]).EqualTo("*"))) { + P0 += formula[c]; + continue; + } else { + signP1 = formula[c]; + c1 = c; + break; + } + } + // P1 parser: + for (int c = c1 + 1; c < static_cast(strlen(formula)); c++) { + if (TString(formula[c]).EqualTo("-") || TString(formula[c]).EqualTo("+") || TString(formula[c]).EqualTo("*")) { + break; + } + P1 += formula[c]; + } + + // Okay, finally merge signature and value, cast into floats and store: + signP0 += P0; + ec.fdEventCutsFormulas[whichCutFormula][0] = signP0.Atof(); + + signP1 += P1; + ec.fdEventCutsFormulas[whichCutFormula][1] = signP1.Atof(); + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void GetP0P1(const char *formula, eEventCutsFormulas whichCutFormula) + +//============================================================ + +float RefMultVsNContr(const float& refMult, eEventCutsFormulas whichCutFormula) +{ + // Temporary workaround for p0 + p1 * x formula until large memory consumption with TFormula is resolved. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Evaluate p0 + p1 * x: + return ec.fdEventCutsFormulas[whichCutFormula][0] + (ec.fdEventCutsFormulas[whichCutFormula][1]) * refMult; + +} // float RefMultVsNContr(const float &refMult, eEventCutsFormulas whichCutFormula) + +//============================================================ + +void bookParticleHistograms() +{ + // Book all particle histograms. + + // 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.fVerbose) { + StartFunction(__FUNCTION__); + } + + // 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); + + if (tc.fUseSetBinLabel) { + ph.fParticleHistogramsPro->GetXaxis()->SetBinLabel(1, "fFillParticleHistograms"); + ph.fParticleHistogramsPro->Fill(0.5, static_cast(ph.fFillParticleHistograms)); + + // ... + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fFillParticleHistograms; ", 1); // TBI 20250411 hardwired 1 + ph.fParticleHistogramsPro->Fill(0.5, static_cast(ph.fFillParticleHistograms)); // TBI 20250411 hardwired 0.5 + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != ph.fParticleHistogramsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != ph.fParticleHistogramsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), ph.fParticleHistogramsPro->GetNbinsX()); + } + + // *) Okay, set the title: + ph.fParticleHistogramsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + + ph.fParticleHistogramsList->Add(ph.fParticleHistogramsPro); + + // 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; + } + + // **) PDG makes sense only for Sim: + if ((tc.fProcess[eGenericRec] || tc.fProcess[eGenericRecSim]) && rs == eRec) { + if (t == ePDG) { + continue; + } + } + + 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.srsLong[rs].Data(), gc.sbaLong[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;t(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.srsLong[rs].Data(), gc.sbaLong[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.srsLong[rs].Data(), gc.sbaLong[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.srsLong[rs].Data(), gc.sbaLong[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: + if (!res.fResultsPro[AFO_PT]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_PT] is NULL \033[0m", __FUNCTION__, __LINE__); + } + 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: + if (!res.fResultsPro[AFO_ETA]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_ETA] is NULL \033[0m", __FUNCTION__, __LINE__); + } + 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 re-use binning from results histograms: + if (!res.fResultsPro[AFO_CHARGE]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CHARGE] is NULL \033[0m", __FUNCTION__, __LINE__); + } + ph.fParticleSparseHistogramsNBins[eDWPhi][wPhiChargeAxis] = res.fResultsPro[AFO_CHARGE]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_CHARGE]->GetXaxis(); + 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: + if (!res.fResultsPro[AFO_CENTRALITY]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CENTRALITY] is NULL \033[0m", __FUNCTION__, __LINE__); + } + 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: + if (!res.fResultsPro[AFO_VZ]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_VZ] is NULL \033[0m", __FUNCTION__, __LINE__); + } + 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: + if (!res.fResultsPro[AFO_PT]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_PT] is NULL \033[0m", __FUNCTION__, __LINE__); + } + 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"); + + // ***) charge-axis for diff pt weights - I re-use binning from results histograms: + if (!res.fResultsPro[AFO_CHARGE]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CHARGE] is NULL \033[0m", __FUNCTION__, __LINE__); + } + ph.fParticleSparseHistogramsNBins[eDWPt][wPtChargeAxis] = res.fResultsPro[AFO_CHARGE]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_CHARGE]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtChargeAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPt][wPtChargeAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtChargeAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtChargeAxis]->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][wPtChargeAxis] = FancyFormatting("Charge"); + + // ***) centrality-axis for diff pt weights - I re-use binning from results histograms: + if (!res.fResultsPro[AFO_CENTRALITY]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CENTRALITY] is NULL \033[0m", __FUNCTION__, __LINE__); + } + ph.fParticleSparseHistogramsNBins[eDWPt][wPtCentralityAxis] = res.fResultsPro[AFO_CENTRALITY]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_CENTRALITY]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtCentralityAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWPt][wPtCentralityAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtCentralityAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWPt][wPtCentralityAxis]->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][wPtCentralityAxis] = "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. + + // ... + + // **) eDiffWeightCategory = eDWEta: + + // ***) eta-axis for diff eta weights - I re-use binning from results histograms: + if (!res.fResultsPro[AFO_ETA]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_ETA] is NULL \033[0m", __FUNCTION__, __LINE__); + } + 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"); + + // ***) charge-axis for diff eta weights - I re-use binning from results histograms: + if (!res.fResultsPro[AFO_CHARGE]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CHARGE] is NULL \033[0m", __FUNCTION__, __LINE__); + } + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaChargeAxis] = res.fResultsPro[AFO_CHARGE]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_CHARGE]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaChargeAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaChargeAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaChargeAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaChargeAxis]->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][wEtaChargeAxis] = FancyFormatting("Charge"); + + // ***) centrality-axis for diff eta weights - I re-use binning from results histograms: + if (!res.fResultsPro[AFO_CENTRALITY]) { + LOGF(fatal, "\033[1;31m%s at line %d : res.fResultsPro[AFO_CENTRALITY] is NULL \033[0m", __FUNCTION__, __LINE__); + } + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaCentralityAxis] = res.fResultsPro[AFO_CENTRALITY]->GetNbinsX(); + lAxis = res.fResultsPro[AFO_CENTRALITY]->GetXaxis(); + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaCentralityAxis] = new TArrayD(1 + ph.fParticleSparseHistogramsNBins[eDWEta][wEtaCentralityAxis]); + for (int bin = 1; bin <= lAxis->GetNbins(); bin++) { + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaCentralityAxis]->AddAt(lAxis->GetBinLowEdge(bin), bin - 1); + } + ph.fParticleSparseHistogramsBinEdges[eDWEta][wEtaCentralityAxis]->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][wEtaCentralityAxis] = "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. + + // ... + + // 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.srsLong[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); + + TString yAxisTitle = ""; // TBI 20250413 when I fall back on using SetBinLabel(...), this variable is declared but will be unused + for (int cut = 0; cut < eParticleCuts_N; cut++) { + if (tc.fUseSetBinLabel) { + pc.fParticleCutsPro->GetXaxis()->SetBinLabel(1 + cut, pc.fParticleCutName[cut].Data()); // Remark: check always if bin labels here correspond to ordering in enum eParticleCuts + } else { + // Workaround for SetBinLabel() large memory consumption: + yAxisTitle += TString::Format("%d:%s; ", 1 + cut, pc.fParticleCutName[cut].Data()); + } + + pc.fParticleCutsPro->Fill(cut, static_cast(pc.fUseParticleCuts[cut])); + + } // for (int cut = 0; cut < eParticleCuts_N; cut++)s + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + if (!tc.fUseSetBinLabel) { + + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != pc.fParticleCutsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() = %d != pc.fParticleCutsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), pc.fParticleCutsPro->GetNbinsX()); + } + delete oa; + + // *) Okay, set the title: + pc.fParticleCutsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + } // if(!tc.fUseSetBinLabel) + + 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 TH1F(TString::Format("fParticleCutCounterHist[%s][%s]", gc.srs[rs].Data(), gc.scc[cc].Data()), TString::Format("%s, %s, particle cut counter (%s)", "__RUN_NUMBER__", gc.srsLong[rs].Data(), gc.sccLong[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()); + + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! There is a large memory blow-up when using TFormula() !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + + // 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) Differential q-vectors booked dynamically: + // c) Book multiplicity distributions in A and B, for each eta separation; + // d) ... + + 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); + + if (tc.fUseSetBinLabel) { + + 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); + + // ... + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fCalculateQvectors; ", 1); + qv.fQvectorFlagsPro->Fill(0.5, static_cast(qv.fCalculateQvectors)); + + yAxisTitle += TString::Format("%d:gMaxHarmonic; ", 2); + qv.fQvectorFlagsPro->Fill(1.5, static_cast(gMaxHarmonic)); + + yAxisTitle += TString::Format("%d:gMaxCorrelator; ", 3); + qv.fQvectorFlagsPro->Fill(2.5, static_cast(gMaxCorrelator)); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != qv.fQvectorFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != qv.fQvectorFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), qv.fQvectorFlagsPro->GetNbinsX()); + } + + // *) Okay, set the title: + qv.fQvectorFlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + + qv.fQvectorList->Add(qv.fQvectorFlagsPro); + + // b) Differential q-vectors booked dynamically: + // Remark: Here I am slighthly generalizing the great example provided at https://cplusplus.com/forum/articles/7459/ + + // b1) book qv.fqvector and qv.fqvectorEntries : + // dimensions: [eqvectorKine_N][gMaxNoBinsKine][gMaxHarmonic * gMaxCorrelator + 1][gMaxCorrelator + 1] => keep in sync with the documentation in the header + // here I am calculating for each dimensions how many entries I need in a given analysis + if (qv.fCalculateqvectorsKineAny) { + qv.fNumberOfKineBins.resize(eqvectorKine_N); // this is the light object, so I can hardwire here eqvectorKine_N + // then, in NumberOfKineVectors() i will store bins ONLY for qvectorKine which were requested. + // Therefore, final ordering in will correspond to the ordering in enum eqvectorKine ONLY if all kine vectors were requested. + // Otherwise, I fill here bins only for kine vectors which were requested, in consequtive order, starting from 0. + + int dim1 = eqvectorKine_N; + // int dim2 = number of kine bins => I calculate this one dynamically for each qVectorKine, see the loop below + NumberOfKineBins(); // here I calculate and fill qv.fNumberOfKineBins[ ... ] + int dim3 = gMaxHarmonic * gMaxCorrelator + 1; // TBI 20250601 I could dinamically allocate this one as well, but this will trigger another major re-design, and it's not rally a big deal + int dim4 = gMaxCorrelator + 1; // TBI 20250601 I could dinamically allocate this one as well, but this will trigger another major re-design, and it's not really a big deal + + qv.fqvector.resize(dim1); + qv.fqvectorEntries.resize(dim1); + + for (int i = 0; i < dim1; ++i) { // here I am looping over entries in enum eqvectorKine + if (qv.fCalculateqvectorsKine[i]) { + qv.fqvector[i].resize(qv.fNumberOfKineBins[i]); // yes, qv.fNumberOfKineBins[i] => for each qvectorkine I calculate and dynamically allocate only necessary bins + qv.fqvectorEntries[i].resize(qv.fNumberOfKineBins[i]); + } else { + // calculus for this kine variable is not needed, I am ironing out this dimension + qv.fqvector[i].resize(0); + qv.fqvectorEntries[i].resize(0); + } + + for (int j = 0; j < qv.fNumberOfKineBins[i]; ++j) { + if (qv.fCalculateqvectorsKine[i]) { + qv.fqvector[i][j].resize(dim3); + } else { + // calculus for this kine variable is not needed, I am ironing out this dimension + qv.fqvector[i][j].resize(0); + } + + for (int k = 0; k < dim3; ++k) { + if (qv.fCalculateqvectorsKine[i]) { + qv.fqvector[i][j][k].resize(dim4); + } else { + // calculus for this kine variable is not needed, I am ironing out this dimension + qv.fqvector[i][j][k].resize(0); + } + } + } + } // for (int i = 0; i < dim1; ++i) + + // b2) book qv.fqabVector and qv.fmab (differential q-vectors with eta separations): + // dimensions: [-eta or +eta][eqvectorKine_N][global binNo][harmonic][eta separation] => keep in sync with the documentation in the header + // here I am calculating for each dimensions how many entries I need in a given analysis + + if (es.fCalculateEtaSeparations) { + int dim1 = 2; // -eta or eta + int dim2 = eqvectorKine_N; + // int dim3 = number of kine bins => I calculated this one dynamically for each qVectorKine, see the loop below + // NumberOfKineBins(); // here I calculate and fill qv.fNumberOfKineBins[ ... ] => I did it already above for qv.fqvector + int dim4 = gMaxHarmonic; + int dim5 = gMaxNumberEtaSeparations; + qv.fqabVector.resize(dim1); + qv.fmab.resize(dim1); + + for (int i = 0; i < dim1; ++i) { // here I am looping over -eta or eta + qv.fqabVector[i].resize(dim2); + qv.fmab[i].resize(dim2); + + for (int j = 0; j < dim2; ++j) { // here I am looping over entries in enum eqvectorKine + + if (qv.fCalculateqvectorsKineEtaSeparations[j]) { + qv.fqabVector[i][j].resize(qv.fNumberOfKineBins[j]); // yes, qv.fNumberOfKineBins[j] => for each qvectorkine I calculate and dynamically allocate only necessary bins + qv.fmab[i][j].resize(qv.fNumberOfKineBins[j]); + } else { + // calculus for this kine variable is not needed, I am ironing out this dimension + qv.fqabVector[i][j].resize(0); + qv.fmab[i][j].resize(0); + } + + for (int k = 0; k < qv.fNumberOfKineBins[j]; ++k) { + if (qv.fCalculateqvectorsKineEtaSeparations[j]) { + qv.fqabVector[i][j][k].resize(dim4); + qv.fmab[i][j][k].resize(dim5); // yes, directly dim5, because this one doesn't depend on harmonics + } else { + // calculus for this kine variable is not needed, I am ironing out this dimension + // I have already in the previous loop ironed out for qv.fCalculateqvectorsKineEtaSeparations[j] = false, so no need to do it here again + // TBI 20250620 validate what happens here + } + + for (int l = 0; l < dim4; ++l) { // loop over harmonics + if (qv.fCalculateqvectorsKineEtaSeparations[j] && !es.fEtaSeparationsSkipHarmonics[l]) { + qv.fqabVector[i][j][k][l].resize(dim5); + // no need to resize qv.fmab here, because this one doesn't depend on harmonics + } else { + // calculus for this kine variable is not needed, I am ironing out this dimension + // I have already in the previous loop ironed out for qv.fCalculateqvectorsKineEtaSeparations[j] = false, so no need to do it here again + // TBI 20250620 validate what happens here + } + } // for (int l = 0; l < dim4; ++l) + } // for (int k = 0; k < qv.fNumberOfKineBins[j]; ++k) + } // for (int j = 0; j < dim2; ++j) + } // for (int i = 0; i < dim1; ++i) + } // if(es.fCalculateEtaSeparations) + } // if(qv.fCalculateqvectorsKineAny) + + // c) Book multiplicity distributions in A and B, for each eta separation: + if (es.fCalculateEtaSeparations) { + TString sEtaSep[2] = {"A", "B"}; // A <=> -eta , B <=> + eta + TString sEtaSepLong[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", sEtaSepLong[ab].Data(), es.fEtaSeparationsValues[e] / 2.) : Form("%.2f %s", es.fEtaSeparationsValues[e] / 2., sEtaSepLong[ab].Data()), gc.srsLong[rs].Data(), gc.sbaLong[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 NumberOfKineBins() +{ + // Helper function called only in void bookQvectorHistograms(), if kine analysis was requested. + // I calculate for each requested kine vector the number of kine bins => this is stored in dynamically allocated array qv.fNumberOfKineBins. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // 1D kine: + if (qv.fCalculateqvectorsKine[PTq]) { + qv.fNumberOfKineBins[PTq] = res.fResultsPro[AFO_PT]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + if (qv.fCalculateqvectorsKine[ETAq]) { + qv.fNumberOfKineBins[ETAq] = res.fResultsPro[AFO_ETA]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + if (qv.fCalculateqvectorsKine[CHARGEq]) { + qv.fNumberOfKineBins[CHARGEq] = res.fResultsPro[AFO_CHARGE]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + // ... + + // 2D kine: + if (qv.fCalculateqvectorsKine[PT_ETAq]) { + qv.fNumberOfKineBins[PT_ETAq] = (res.fResultsPro2D[AfoKineMap2D(PT_ETAq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(PT_ETAq)]->GetNbinsY() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + if (qv.fCalculateqvectorsKine[PT_CHARGEq]) { + qv.fNumberOfKineBins[PT_CHARGEq] = (res.fResultsPro2D[AfoKineMap2D(PT_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(PT_CHARGEq)]->GetNbinsY() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + if (qv.fCalculateqvectorsKine[ETA_CHARGEq]) { + qv.fNumberOfKineBins[ETA_CHARGEq] = (res.fResultsPro2D[AfoKineMap2D(ETA_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(ETA_CHARGEq)]->GetNbinsY() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + // ... + + // 3D kine: + if (qv.fCalculateqvectorsKine[PT_ETA_CHARGEq]) { + qv.fNumberOfKineBins[PT_ETA_CHARGEq] = (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsY() + 2) * (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsZ() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + // ... + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void NumberOfKineBins() + +//============================================================ + +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); + + if (tc.fUseSetBinLabel) { + mupa.fCorrelationsFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateCorrelations"); + mupa.fCorrelationsFlagsPro->Fill(0.5, mupa.fCalculateCorrelations); + + // ... + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fCalculateCorrelations; ", 1); + mupa.fCorrelationsFlagsPro->Fill(0.5, static_cast(mupa.fCalculateCorrelations)); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != mupa.fCorrelationsFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != mupa.fCorrelationsFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), mupa.fCorrelationsFlagsPro->GetNbinsX()); + } + + // *) Okay, set the title: + mupa.fCorrelationsFlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + + 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 (!mupa.fCalculateCorrelationsAsFunctionOf[v]) { + continue; + } + + if (!res.fResultsPro[v]) { + LOGF(fatal, "\033[1;31m%s at line %d : fResultsPro[%d] is NULL, this shall never happen, but apparently it happened... \033[0m", __FUNCTION__, __LINE__, v); + } + + if (tc.fUseClone) { + mupa.fCorrelationsPro[k][n][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fCorrelationsPro[%d][%d][%s]", k, n, res.fResultsProRawName[v].Data()))); // yes + } else { + mupa.fCorrelationsPro[k][n][v] = new TProfile(Form("fCorrelationsPro[%d][%d][%s]", k, n, res.fResultsProRawName[v].Data()), "", res.fResultsPro[v]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[v]->GetXaxis()->GetXbins()->GetArray()); + } + + 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] } -} // BookCorrelationsHistograms() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // bookCorrelationsHistograms() //============================================================ -void BookWeightsHistograms() +void bookWeightsHistograms() { // Book all objects for particle weights. // a) Book the profile holding flags; - // b) Histograms; - // c) Histograms for differential weights. + // b) Histograms for integrated weights; + // c) Histograms for differential weights; + // d) Sparse histograms for differential phi weights. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Book the profile holding flags: - pw.fWeightsFlagsPro = - new TProfile("fWeightsFlagsPro", "flags for particle weights", 5, 0., 5.); - pw.fWeightsFlagsPro->SetStats(kFALSE); + 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.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)"); - - for (Int_t w = 0; w < eWeights_N; w++) // use weights [phi,pt,eta] + pw.fWeightsFlagsPro->GetXaxis()->SetLabelSize(0.035); + + if (tc.fUseSetBinLabel) { + + 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)}"); + + } else { + + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:w_{#varphi}; ", 1); + yAxisTitle += TString::Format("%d:w_{p_{t}}; ", 2); + yAxisTitle += TString::Format("%d:w_{#eta}; ", 3); + yAxisTitle += TString::Format("%d:(w_{#varphi})_{| p_{T}}; ", 4); + yAxisTitle += TString::Format("%d:(w_{#varphi})_{| #eta}; ", 5); + + // **) differential phi weights using sparse: + yAxisTitle += TString::Format("%d:(w_{#varphi})_{phi axis (sparse)}; ", 6); + yAxisTitle += TString::Format("%d:(w_{#varphi})_{p_{T} axis (sparse)}; ", 7); + yAxisTitle += TString::Format("%d:(w_{#varphi})_{#eta axis (sparse)}; ", 8); + yAxisTitle += TString::Format("%d:(w_{#varphi})_{charge axis (sparse)}; ", 9); + yAxisTitle += TString::Format("%d:(w_{#varphi})_{centrality axis (sparse)}; ", 10); + yAxisTitle += TString::Format("%d:(w_{#varphi})_{VertexZ axis (sparse)}; ", 11); + + // **) differential pt weights using sparse: + yAxisTitle += TString::Format("%d:(w_{p_{T}})_{pt axis (sparse)}; ", 12); + + // **) differential eta weights using sparse: + yAxisTitle += TString::Format("%d:(w_{#eta})_{eta axis (sparse)}; ", 13); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != pw.fWeightsFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != pw.fWeightsFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), pw.fWeightsFlagsPro->GetNbinsX()); + } + + // *) Okay, set the title: + pw.fWeightsFlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + + for (int 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... - } + + // **) 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.); + } + if (pw.fUseDiffPhiWeights[wPtChargeAxis]) { + pw.fWeightsFlagsPro->Fill(12.5, 1.); + } + if (pw.fUseDiffPhiWeights[wPtCentralityAxis]) { + pw.fWeightsFlagsPro->Fill(13.5, 1.); + } + + // **) differential eta weights using sparse: + if (pw.fUseDiffEtaWeights[wEtaEtaAxis]) { + pw.fWeightsFlagsPro->Fill(14.5, 1.); } + if (pw.fUseDiffPhiWeights[wEtaChargeAxis]) { + pw.fWeightsFlagsPro->Fill(15.5, 1.); + } + if (pw.fUseDiffPhiWeights[wEtaCentralityAxis]) { + pw.fWeightsFlagsPro->Fill(16.5, 1.); + } + pw.fWeightsList->Add(pw.fWeightsFlagsPro); - // b) Histograms: + // 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 c) => add histograms to the list, only after they are cloned from external files. + // 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); + + if (tc.fUseSetBinLabel) { + cw.fCentralityWeightsFlagsPro->GetXaxis()->SetBinLabel(1, TString::Format("Use centrality weights for estimator %s", ec.fsEventCuts[eCentralityEstimator].Data())); + + // ... + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:Use centrality weights for estimator %s; ", 1, ec.fsEventCuts[eCentralityEstimator].Data()); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != cw.fCentralityWeightsFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != cw.fCentralityWeightsFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), cw.fCentralityWeightsFlagsPro->GetNbinsX()); + } + + // *) Okay, set the title: + cw.fCentralityWeightsFlagsPro->GetYaxis()->SetTitle(yAxisTitle.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 BookWeightsHistograms() +} // void bookCentralityWeightsHistograms() //============================================================ -void BookNestedLoopsHistograms() +void bookNestedLoopsHistograms() { // Book all nested loops histograms. // a) Book the profile holding flags; - // b) Common local labels (keep 'em in sync with BookCorrelationsHistograms()); + // 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Book the profile holding flags: nl.fNestedLoopsFlagsPro = new TProfile("fNestedLoopsFlagsPro", "flags for nested loops", 4, 0., 4.); - nl.fNestedLoopsFlagsPro->SetStats(kFALSE); + 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); + + if (tc.fUseSetBinLabel) { + 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); + + // ... + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fCalculateNestedLoops; ", 1); + nl.fNestedLoopsFlagsPro->Fill(0.5, nl.fCalculateNestedLoops); + + yAxisTitle += TString::Format("%d:fCalculateCustomNestedLoops; ", 2); + nl.fNestedLoopsFlagsPro->Fill(1.5, nl.fCalculateCustomNestedLoops); + + yAxisTitle += TString::Format("%d:fCalculateKineCustomNestedLoops; ", 3); + nl.fNestedLoopsFlagsPro->Fill(2.5, nl.fCalculateKineCustomNestedLoops); + + yAxisTitle += TString::Format("%d:fMaxNestedLoop; ", 4); + nl.fNestedLoopsFlagsPro->Fill(3.5, nl.fMaxNestedLoop); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != nl.fNestedLoopsFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != nl.fNestedLoopsFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), nl.fNestedLoopsFlagsPro->GetNbinsX()); + } + + // *) Okay, set the title: + nl.fNestedLoopsFlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + nl.fNestedLoopsList->Add(nl.fNestedLoopsFlagsPro); if (!(nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops || nl.fCalculateKineCustomNestedLoops)) { @@ -2279,25 +6161,94 @@ void BookNestedLoopsHistograms() // *) Book containers for integrated nested loops: if (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) { - const Int_t iMaxSize = 2e4; + 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_t iMaxSize = 2e4; - for (Int_t b = 0; b < res.fResultsPro[AFO_PT]->GetNbinsX(); b++) { + + const int iMaxSize = 2e4; // this is roughly number of particles per bin, it shouldn't exceed this threshold + int nBins = -1; + + // 1D kine: + // **) vs. pt: + nBins = res.fResultsPro[AFO_PT]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip later + for (int b = 0; b < nBins; b++) { nl.ftaNestedLoopsKine[PTq][b][0] = new TArrayD(iMaxSize); nl.ftaNestedLoopsKine[PTq][b][1] = new TArrayD(iMaxSize); } - for (Int_t b = 0; b < res.fResultsPro[AFO_ETA]->GetNbinsX(); b++) { + + // **) vs. eta: + nBins = res.fResultsPro[AFO_ETA]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it later + for (int b = 0; b < nBins; 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()) + // **) vs. charge: + nBins = res.fResultsPro[AFO_CHARGE]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it later + for (int b = 0; b < nBins; b++) { + nl.ftaNestedLoopsKine[CHARGEq][b][0] = new TArrayD(iMaxSize); + nl.ftaNestedLoopsKine[CHARGEq][b][1] = new TArrayD(iMaxSize); + } + + // ... + + // 2D kine: + // **) vs. (pt,eta): + if (res.fResultsPro2D[AfoKineMap2D(PT_ETAq)]) { + // this is safe, because this one shall be booked if any of Correlations, Test0, EtaSeparations, etc., was requested + nBins = (res.fResultsPro2D[AfoKineMap2D(PT_ETAq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(PT_ETAq)]->GetNbinsY() + 2); + // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { // loop over lineralized global bins + nl.ftaNestedLoopsKine[PT_ETAq][b][0] = new TArrayD(iMaxSize); + nl.ftaNestedLoopsKine[PT_ETAq][b][1] = new TArrayD(iMaxSize); + } + } + + // **) vs. (pt,charge): + if (res.fResultsPro2D[AfoKineMap2D(PT_CHARGEq)]) { + // this is safe, because this one shall be booked if any of Correlations, Test0, EtaSeparations, etc., was requested + nBins = (res.fResultsPro2D[AfoKineMap2D(PT_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(PT_CHARGEq)]->GetNbinsY() + 2); + // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { // loop over lineralized global bins + nl.ftaNestedLoopsKine[PT_CHARGEq][b][0] = new TArrayD(iMaxSize); + nl.ftaNestedLoopsKine[PT_CHARGEq][b][1] = new TArrayD(iMaxSize); + } + } + + // **) vs. (eta,charge): + if (res.fResultsPro2D[AfoKineMap2D(ETA_CHARGEq)]) { + // this is safe, because this one shall be booked if any of Correlations, Test0, EtaSeparations, etc., was requested + nBins = (res.fResultsPro2D[AfoKineMap2D(ETA_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(ETA_CHARGEq)]->GetNbinsY() + 2); + // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { // loop over lineralized global bins + nl.ftaNestedLoopsKine[ETA_CHARGEq][b][0] = new TArrayD(iMaxSize); + nl.ftaNestedLoopsKine[ETA_CHARGEq][b][1] = new TArrayD(iMaxSize); + } + } + + // ... + + // 3D kine: + // **) vs. (pt,eta,charge): + if (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]) { + // this is safe, because this one shall be booked if any of Correlations, Test0, EtaSeparations, etc., was requested + nBins = (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsY() + 2) * (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsZ() + 2); + // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { // loop over lineralized global bins + nl.ftaNestedLoopsKine[PT_ETA_CHARGEq][b][0] = new TArrayD(iMaxSize); + nl.ftaNestedLoopsKine[PT_ETA_CHARGEq][b][1] = new TArrayD(iMaxSize); + } + } + + // ... + + } // if (nl.fCalculateKineCustomNestedLoops) + + // 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}", @@ -2309,58 +6260,58 @@ void BookNestedLoopsHistograms() 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_t k = 0; k < 4; k++) // order [2p=0,4p=1,6p=2,8p=3] + 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_t n = 0; n < gMaxHarmonic; n++) // harmonic + for (int 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(PTKINE == v && !fCalculatePtCorrelations){continue;} - // if(ETAKINE == v && !fCalculateEtaCorrelations){continue;} + 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 + + if (tc.fUseClone) { + nl.fNestedLoopsPro[k][n][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fNestedLoopsPro[%d][%d][%d]", k, n, v))); // yes + } else { + nl.fNestedLoopsPro[k][n][v] = new TProfile(Form("fNestedLoopsPro[%d][%d][%s]", k, n, res.fResultsProRawName[v].Data()), "", res.fResultsPro[v]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[v]->GetXaxis()->GetXbins()->GetArray()); + } + 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]->SetStats(false); nl.fNestedLoopsPro[k][n][v]->Sumw2(); - nl.fNestedLoopsPro[k][n][v]->GetXaxis()->SetTitle( - res.fResultsProXaxisTitle[v].Data()); + 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"); + if (tc.fFixedNumberOfRandomlySelectedTracks > 0 && AFO_MULTIPLICITY == v) { // just a warning for the meaning of multiplicity in this special case + nl.fNestedLoopsPro[k][n][v]->GetXaxis()->SetTitle("WARNING: for each multiplicity, fFixedNumberOfRandomlySelectedTracks is selected randomly in Q-vector"); } - */ nl.fNestedLoopsList->Add(nl.fNestedLoopsPro[k][n][v]); - } // for(Int_t v=0;v<5;v++) // variable [0=integrated,1=vs. + } // for(int 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] + } // 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("p_{T}")) { + 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] } -} // void BookNestedLoopsHistograms() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void bookNestedLoopsHistograms() //============================================================ -void BookNUAHistograms() +void bookNUAHistograms() { // Book all objects for Toy NUA. @@ -2369,19 +6320,55 @@ void BookNUAHistograms() // c) Histograms. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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(kFALSE); + 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 (tc.fUseSetBinLabel) { + 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]"); + 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]"); + + // ... + + } else { + + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fApplyNUAPDF[phi]; ", static_cast(1 + ePhiNUAPDF)); + yAxisTitle += TString::Format("%d:fApplyNUAPDF[pt]; ", static_cast(1 + ePtNUAPDF)); + yAxisTitle += TString::Format("%d:fApplyNUAPDF[eta]; ", static_cast(1 + eEtaNUAPDF)); + yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[phi]; ", static_cast(4 + ePhiNUAPDF)); + yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[pt]; ", static_cast(4 + ePtNUAPDF)); + yAxisTitle += TString::Format("%d:fUseDefaultNUAPDF[eta]; ", static_cast(4 + eEtaNUAPDF)); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != nua.fNUAFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != nua.fNUAFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), nua.fNUAFlagsPro->GetNbinsX()); + } + + // *) Okay, set the title: + nua.fNUAFlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + if (nua.fApplyNUAPDF[ePhiNUAPDF]) { nua.fNUAFlagsPro->Fill(static_cast(1 + ePhiNUAPDF), 1.); } @@ -2391,9 +6378,6 @@ void BookNUAHistograms() 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.); } @@ -2413,7 +6397,7 @@ void BookNUAHistograms() TString sVariable[eNUAPDF_N] = {"#varphi", "p_{t}", "#eta"}; // has to be in sync with the ordering of enum eNUAPDF // c) Histograms: - for (Int_t pdf = 0; pdf < eNUAPDF_N; pdf++) // use pdfs for NUA in (phi, pt, eta, ...) + 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); { @@ -2425,10 +6409,10 @@ void BookNUAHistograms() continue; } // Define default detector acceptance in azimuthal angle: Two sectors, with different probabilities. - Double_t dFirstSector[2] = {-(3. / 4.) * TMath::Pi(), -(1. / 4.) * TMath::Pi()}; // first sector is defined as [-3Pi/4,Pi/4] - Double_t dSecondSector[2] = {(1. / 3.) * TMath::Pi(), (2. / 3.) * TMath::Pi()}; // second sector is defined as [Pi/3,2Pi/3] - Double_t dProbability[2] = {0.3, 0.5}; // probabilities - nua.fDefaultNUAPDF[ePhiNUAPDF] = new TF1(Form("fDefaultNUAPDF[%d]", ePhiNUAPDF), "1.-(x>=[0])*(1.-[4]) + (x>=[1])*(1.-[4]) - (x>=[2])*(1.-[5]) + (x>=[3])*(1.-[5]) ", + 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]); @@ -2445,9 +6429,9 @@ void BookNUAHistograms() continue; } // Define default detector acceptance in transverse momentum: One sectors, with probability < 1. - Double_t dSector[2] = {0.4, 0.8}; // sector is defined as 0.8 < pT < 1.2 - Double_t dProbability = 0.3; // probability, so after being set this way, only 30% of particles in that sector are reconstructed - nua.fDefaultNUAPDF[ePtNUAPDF] = new TF1(Form("fDefaultNUAPDF[%d]", ePtNUAPDF), "1.-(x>=[0])*(1.-[2]) + (x>=[1])*(1.-[2])", + 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]); @@ -2461,9 +6445,9 @@ void BookNUAHistograms() continue; } // Define default detector acceptance in pseudorapidity: One sectors, with probability < 1. - Double_t dSector[2] = {2.0, 2.5}; // sector is defined as 0.5 < eta < 1.0 - Double_t dProbability = 0.5; // probability, so after being set this way, only 50% of particles in that sector are reconstructed - nua.fDefaultNUAPDF[eEtaNUAPDF] = new TF1(Form("fDefaultNUAPDF[%d]", eEtaNUAPDF), "1.-(x>=[0])*(1.-[2]) + (x>=[1])*(1.-[2])", + 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]); @@ -2475,8 +6459,8 @@ void BookNUAHistograms() } else { // if(!nua.fCustomNUAPDF[pdf]) // generic cosmetics for custom user-supplied pdfs via histograms: - nua.fCustomNUAPDF[pdf]->SetTitle(Form("Custom user-provided NUA for %s", sVariable[pdf].Data())); - nua.fCustomNUAPDF[pdf]->SetStats(kFALSE); + 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); @@ -2492,13 +6476,17 @@ void BookNUAHistograms() nua.fMaxValuePDF[pdf] = nua.fDefaultNUAPDF[pdf]->GetMaximum(ph.fParticleHistogramsBins[pdf][1], ph.fParticleHistogramsBins[pdf][2]); } - } // for(Int_t pdf=0;pdfSetStats(kFALSE); + iv.fInternalValidationFlagsPro = new TProfile("fInternalValidationFlagsPro", "flags for internal validation", 5, 0., 5.); + iv.fInternalValidationFlagsPro->SetStats(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); - - /* TBI 20240423 I have to re-think where to fill the remaining bins of this profile. It feels now I have to fill it on the bottom, after all objects for internal validation are booked. - The problem here is that I do not book all objects below, unless I really do internal validation. - iv.fInternalValidationFlagsPro->GetXaxis()->SetBinLabel(4, Form("fHarmonicsOptionInternalValidation = %s", iv.fHarmonicsOptionInternalValidation->Data())); - iv.fInternalValidationFlagsPro->Fill(3.5, 1); - */ + if (tc.fUseSetBinLabel) { + 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, "fRandomizeReactionPlane"); + iv.fInternalValidationFlagsPro->Fill(3.5, iv.fRandomizeReactionPlane); + iv.fInternalValidationFlagsPro->GetXaxis()->SetBinLabel(5, TString::Format("option = %s", iv.fHarmonicsOptionInternalValidation->Data())); + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fUseInternalValidation; ", 1); + iv.fInternalValidationFlagsPro->Fill(0.5, static_cast(iv.fUseInternalValidation)); + + yAxisTitle += TString::Format("%d:fnEventsInternalValidation; ", 2); + iv.fInternalValidationFlagsPro->Fill(1.5, static_cast(iv.fnEventsInternalValidation)); + + yAxisTitle += TString::Format("%d:fRescaleWithTheoreticalInput; ", 3); + iv.fInternalValidationFlagsPro->Fill(2.5, static_cast(iv.fRescaleWithTheoreticalInput)); + + yAxisTitle += TString::Format("%d:fRandomizeReactionPlane; ", 4); + iv.fInternalValidationFlagsPro->Fill(3.5, static_cast(iv.fRandomizeReactionPlane)); + + yAxisTitle += TString::Format("%d:option = %s; ", 5, iv.fHarmonicsOptionInternalValidation->Data()); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != iv.fInternalValidationFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != iv.fInternalValidationFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), iv.fInternalValidationFlagsPro->GetNbinsX()); + } + + // *) Okay, set the title: + iv.fInternalValidationFlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else // *) Book object beyond this line only if internal validation was requested: if (!iv.fUseInternalValidation) { return; } - // *) TBI - iv.fHarmonicsOptionInternalValidation = new TString(cf_iv.cfHarmonicsOptionInternalValidation); - if (!(iv.fHarmonicsOptionInternalValidation->EqualTo("constant", TString::kIgnoreCase) || - iv.fHarmonicsOptionInternalValidation->EqualTo("correlated", TString::kIgnoreCase))) { - LOGF(fatal, "\033[1;31m%s at line %d : fHarmonicsOptionInternalValidation = %s is not supported. \033[0m", __FUNCTION__, __LINE__, iv.fHarmonicsOptionInternalValidation->Data()); - } - // b) Book and fill container vn amplitudes: iv.fInternalValidationVnPsin[eVn] = new TArrayD(gMaxHarmonic); - auto lInternalValidationAmplitudes = (vector)cf_iv.cfInternalValidationAmplitudes; // this is now the local version of that array from configurable + 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_t i = 0; i < static_cast(lInternalValidationAmplitudes.size()); i++) { + 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 = (vector)cf_iv.cfInternalValidationPlanes; + 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__); } @@ -2569,19 +6582,23 @@ void BookInternalValidationHistograms() 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_t i = 0; i < static_cast(lInternalValidationPlanes.size()); i++) { + 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 = (vector)cf_iv.cfMultRangeInternalValidation; + 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__); } -} // BookInternalValidationHistograms() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // bookInternalValidationHistograms() //============================================================ @@ -2595,7 +6612,7 @@ TComplex TheoreticalValue(TArrayI* harmonics, TArrayD* amplitudes, TArrayD* plan // c) Return value. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Insanity checks: @@ -2613,13 +6630,16 @@ TComplex TheoreticalValue(TArrayI* harmonics, TArrayD* amplitudes, TArrayD* plan } // b) Main calculus: - TComplex value = TComplex(1., 0., kTRUE); // yes, polar representation - for (Int_t h = 0; h < harmonics->GetSize(); h++) { - // Using polar form of TComplex (Double_t re, Double_t im=0, Bool_t polar=kFALSE): - value *= TComplex(amplitudes->GetAt(TMath::Abs(harmonics->GetAt(h)) - 1), 1. * harmonics->GetAt(h) * planes->GetAt(TMath::Abs(harmonics->GetAt(h)) - 1), kTRUE); - } // for(Int_t h=0;hGetSize();h++) + 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(std::abs(harmonics->GetAt(h)) - 1), 1. * harmonics->GetAt(h) * planes->GetAt(std::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) @@ -2630,23 +6650,66 @@ void InternalValidation() { // Internal validation against theoretical values in on-the-fly study for all implemented correlators. + // Last update: 20250121 + // To do: - // 20231114 Do I need to add support for diff. weights also here? + // 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 ebe quantities; + // 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; + // b2) Fill event histograms before cuts; // b3) Loop over particles; - // b4) Calculate correlations; - // b5) Optionally, cross-check with nested loops; + // b4) Fill event histograms after cuts; + // b5) Calculate everything for selected events and particles; // c) Delete persistent objects. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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; + } + + // differential pt weights: + if (pw.fUseDiffPhiWeights[wPtPtAxis]) { // Yes, I check only the first flag. This way, I can switch off all differential pt weights by setting 0-wPt in config. + // On the other hand, it doesn't make sense to calculate differential pt weights without having pt axis. + // At any point I shall be able to fall back to integrated pt weights, that corresponds to the case wheh "1-wPt" and all others are "0-w..." + GetParticleWeights(); + pw.fParticleWeightsAreFetched = true; + } + + // differential eta weights: + if (pw.fUseDiffPhiWeights[wEtaEtaAxis]) { // Yes, I check only the first flag. This way, I can switch off all differential eta weights by setting 0-wEta in config. + // On the other hand, it doesn't make sense to calculate differential eta weights without having eta axis. + // At any point I shall be able to fall back to integrated eta weights, that corresponds to the case wheh "1-wEta" 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; @@ -2654,11 +6717,11 @@ void InternalValidation() 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_t 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., TMath::TwoPi()); - for (Int_t h = 0; h < gMaxHarmonic; h++) { - fPhiPDF->SetParName(2 * h, Form("v_{%d}", h + 1)); // set name v_n - fPhiPDF->SetParName(2 * h + 1, Form("Psi_{%d}", h + 1)); // set name psi_n + // Keep also in sync with const int gMaxHarmonic = 9; in *GlobalConstants.h + fPhiPDF = new TF1("fPhiPDF", "1 + 2.*[0]*std::cos(x-[1]-[18]) + 2.*[2]*std::cos(2.*(x-[3]-[18])) + 2.*[4]*std::cos(3.*(x-[5]-[18])) + 2.*[6]*std::cos(4.*(x-[7]-[18])) + 2.*[8]*std::cos(5.*(x-[9]-[18])) + 2.*[10]*std::cos(6.*(x-[11]-[18])) + 2.*[12]*std::cos(7.*(x-[13]-[18])) + 2.*[14]*std::cos(8.*(x-[15]-[18])) + 2.*[16]*std::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)); @@ -2671,109 +6734,195 @@ void InternalValidation() } else { fPhiPDF->SetParameter(2 * h + 1, 0.); } - } // for(Int_t h=0;h This is initial configuration for p.d.f. used in internal validation:"); - for (Int_t h = 0; h < 2 * gMaxHarmonic; h++) { + 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) { + 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_t gMaxHarmonic = 9; in *GlobalConstants.h - 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., TMath::TwoPi()); + // 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]*std::cos(x-[3]) + 2.*[1]*std::cos(2.*(x-[3])) + 2.*[2]*std::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]*std::cos(x-[3]) + 2.*[1]*std::cos(2.*(x-[4])) + 2.*[2]*std::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 - fvnPDF->SetParName(0, "v_{1}"); - fvnPDF->SetParName(1, "v_{2}"); - fvnPDF->SetParName(2, "v_{3}"); - fvnPDF->SetParName(3, "RP"); - // Both amplitudes v1-v3 and RP are sampled e-b-e, and then set in fPhiPDF below - } // else if(fHarmonicsOptionInternalValidation->EqualTo("correlated")) + // 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_t step = 10.; // in percentage. Used only for the printout of progress - // TStopwatch watch; - // watch.Start(); - Double_t v1 = 0., v2 = 0., v3 = 0.; - for (Int_t e = 0; e < static_cast(iv.fnEventsInternalValidation); e++) { + double v1 = 0., v2 = 0., v3 = 0.; + for (int e = 0; e < static_cast(iv.fnEventsInternalValidation); e++) { - // b0) Reset ebe quantities: + // 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_t nMult = gRandom->Uniform(iv.fMultRangeInternalValidation[eMin], iv.fMultRangeInternalValidation[eMax]); + int nMult = static_cast(gRandom->Uniform(iv.fMultRangeInternalValidation[eMin], iv.fMultRangeInternalValidation[eMax])); - Double_t fReactionPlane = gRandom->Uniform(0., TMath::TwoPi()); + double fReactionPlane = 0.; + if (iv.fRandomizeReactionPlane) { + fReactionPlane = gRandom->Uniform(0., o2::constants::math::TwoPI); // no cast is needed, since Uniform(...) returns double + } else { + LOGF(info, "\033[1;33m%s at line %d : Reaction plane was not randomized for this collision.\033[0m", __FUNCTION__, __LINE__); + } 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 = gRandom->Uniform(0., 100.); // this is perfectly fine for this exercise + 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., 1000.)); // 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 + ebye.fImpactParameter = static_cast(gRandom->Uniform(0., 20.)); // this is perfectly fine for this exercise - // b2) Fill event histograms: + // b2) Fill event histograms before cuts: if (eh.fFillEventHistograms) { - !eh.fEventHistograms[eNumberOfEvents][eSim][eAfter] ? true : eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]->Fill(0.5); - !eh.fEventHistograms[eTotalMultiplicity][eSim][eAfter] ? true : eh.fEventHistograms[eTotalMultiplicity][eSim][eAfter]->Fill(nMult); - !eh.fEventHistograms[eSelectedTracks][eSim][eAfter] ? true : eh.fEventHistograms[eSelectedTracks][eSim][eAfter]->Fill(ebye.fSelectedTracks); - !eh.fEventHistograms[eCentrality][eSim][eAfter] ? true : eh.fEventHistograms[eCentrality][eSim][eAfter]->Fill(ebye.fCentrality); + !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); } - // configure p.d.f. for azimuthal angles if harmonics are not constant e-by-e: + // ... 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); - // cout<SetParameter(0, v1); fPhiPDF->SetParameter(1, v2); fPhiPDF->SetParameter(2, v3); - // reaction plane is set above + // reaction plane is set above already } // if(fHarmonicsOptionInternalValidation->EqualTo("correlated")) - // b2) Loop over particles: - Double_t dPhi = 0.; - Double_t dPt = 0.; - Double_t dEta = 0.; + // 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::PIQuarter + 2. * Psi2 + Psi1); // see arXiv:1901.06968, Sec. II D. + // o2::constants::math::PIQuarter = 0.25f * PI + fPhiPDF->SetParameter(3, Psi1); + fPhiPDF->SetParameter(4, Psi2); + fPhiPDF->SetParameter(5, Psi3); + + // Remark: reaction plane is not needed for case "persistent" - // ..) Define min and max ranges for sampling: - Double_t dPt_min = res.fResultsPro[AFO_PT]->GetXaxis()->GetBinLowEdge(1); // yes, low edge of first bin is pt min - Double_t dPt_max = res.fResultsPro[AFO_PT]->GetXaxis()->GetBinLowEdge(1 + res.fResultsPro[AFO_PT]->GetNbinsX()); // yes, low edge of overflow bin is max pt - Double_t dEta_min = res.fResultsPro[AFO_ETA]->GetXaxis()->GetBinLowEdge(1); // yes, low edge of first bin is eta min - Double_t dEta_max = res.fResultsPro[AFO_ETA]->GetXaxis()->GetBinLowEdge(1 + res.fResultsPro[AFO_ETA]->GetNbinsX()); // yes, low edge of overflow bin is max eta + } // if(fHarmonicsOptionInternalValidation->EqualTo("persistent")) - for (Int_t p = 0; p < nMult; p++) { + // b3) Loop over particles: + double dPhi = 0.; + double dPt = 0.; + double dEta = 0.; + double dCharge = -44.; // it has to be double, because below I use e.g. double kineArr[2] = {dPt, dCharge}; + + // *) 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.fCalculateCorrelations || t0.fCalculateTest0AsFunctionOf[AFO_PT]) { // TBI 20240423 The first switch I need to replace with differentual switch, like I have it for Test0 now + // *) To increase performance, sample pt, eta or charge only if requested: + if (mupa.fCalculateCorrelationsAsFunctionOf[AFO_PT] || t0.fCalculateTest0AsFunctionOf[AFO_PT] || es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT] || + t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_PT] || t0.fCalculate2DTest0AsFunctionOf[AFO_PT_ETA] || t0.fCalculate2DTest0AsFunctionOf[AFO_PT_CHARGE] || + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_ETA] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_VZ] || + t0.fCalculate3DTest0AsFunctionOf[AFO_PT_ETA_CHARGE]) { dPt = gRandom->Uniform(dPt_min, dPt_max); } - if (mupa.fCalculateCorrelations || t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { // TBI 20240423 The first switch I need to replace with differentual switch, like I have it for Test0 now + if (mupa.fCalculateCorrelationsAsFunctionOf[AFO_ETA] || t0.fCalculateTest0AsFunctionOf[AFO_ETA] || es.fCalculateEtaSeparations || + t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_ETA] || t0.fCalculate2DTest0AsFunctionOf[AFO_PT_ETA] || t0.fCalculate2DTest0AsFunctionOf[AFO_ETA_CHARGE] || + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_ETA] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_VZ] || + t0.fCalculate3DTest0AsFunctionOf[AFO_PT_ETA_CHARGE]) { + // 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 here: + if (mupa.fCalculateCorrelationsAsFunctionOf[AFO_CHARGE] || t0.fCalculateTest0AsFunctionOf[AFO_CHARGE] || es.fCalculateEtaSeparationsAsFunctionOf[AFO_CHARGE] || + t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_CHARGE] || t0.fCalculate2DTest0AsFunctionOf[AFO_PT_CHARGE] || t0.fCalculate2DTest0AsFunctionOf[AFO_ETA_CHARGE] || + t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_VZ_CHARGE] || + t0.fCalculate3DTest0AsFunctionOf[AFO_PT_ETA_CHARGE]) { + dCharge = (1 == gRandom->Integer(2) ? 1 : -1); // gRandom->Integer(2) samples either 0 or 1, then I cast 0 into -1 + if (tc.fInsanityCheckForEachParticle && std::abs(dCharge) != 1) { + LOGF(fatal, "\033[1;31m%s at line %d : dCharge = %d\033[0m", __FUNCTION__, __LINE__, dCharge); + } + } + + // *) 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); + !ph.fParticleHistograms[eCharge][eSim][eBefore] ? true : ph.fParticleHistograms[eCharge][eSim][eBefore]->Fill(dCharge); // 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); @@ -2798,22 +6947,86 @@ void InternalValidation() !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); + !ph.fParticleHistograms[eCharge][eSim][eAfter] ? true : ph.fParticleHistograms[eCharge][eSim][eAfter]->Fill(dCharge); // 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) { + if (qv.fCalculateQvectors || es.fCalculateEtaSeparations) { this->FillQvector(dPhi, dPt, dEta); // all 3 arguments are passed by reference } - // *) Differential q-vectors: - if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_PT]) { // TBI 20240423 I need to extend this condition to mupa.fCalculateCorrelations or some differential version of it - this->Fillqvector(dPhi, dPt, PTq); // first 2 arguments are passed by reference, 3rd argument is enum + // *) Differential q-vectors (keep in sync with the code in MainLoopOverParticles(...)): + + // ** 1D: + // ***) 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: + double kineArr[1] = {dPt}; + this->FillqvectorNdim(dPhi, kineArr, 1, PTq); + } else if (es.fCalculateEtaSeparations && es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { + // In this branch I do need eta separation, so the heavier call must be executed: + double kineArr[1] = {dPt}; + this->FillqvectorNdim(dPhi, kineArr, 1, PTq, dEta); + } + + // ***) 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. + double kineArr[1] = {dEta}; + this->FillqvectorNdim(dPhi, kineArr, 1, ETAq); + } + + // ***) charge dependence: + if (qv.fCalculateQvectors && (mupa.fCalculateCorrelationsAsFunctionOf[AFO_CHARGE] || t0.fCalculateTest0AsFunctionOf[AFO_CHARGE]) && !es.fCalculateEtaSeparations) { + // In this branch I do not need eta separation, so the lighter call can be executed: + double kineArr[1] = {dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 1, CHARGEq); + } else if (es.fCalculateEtaSeparations && es.fCalculateEtaSeparationsAsFunctionOf[AFO_CHARGE]) { + // In this branch I do need eta separation, so the heavier call must be executed: + double kineArr[1] = {dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 1, CHARGEq, dEta); + } + + // ... + + // ** 2D: + // ***) pt-eta dependence: + if (qv.fCalculateQvectors && (t0.fCalculate2DTest0AsFunctionOf[AFO_PT_ETA] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_ETA])) { + // Remark: For eta dependence I do not consider es.fCalculateEtaSeparations, because in this context that calculation is meaningless. + double kineArr[2] = {dPt, dEta}; + this->FillqvectorNdim(dPhi, kineArr, 2, PT_ETAq); + } + + // ***) pt-charge dependence: + if (qv.fCalculateQvectors && (t0.fCalculate2DTest0AsFunctionOf[AFO_PT_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_CHARGE]) && !es.fCalculateEtaSeparations) { + // In this branch I do not need eta separation, so the lighter call can be executed: + double kineArr[2] = {dPt, dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 2, PT_CHARGEq); + } else if (es.fCalculateEtaSeparations && false) { // && TBI 20250623 finalize, replace "false" with 2D flag for (pt,charge) with eta separation case + // In this branch I do need eta separation, so the heavier call must be executed: + double kineArr[2] = {dPt, dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 2, PT_CHARGEq, dEta); + } + + // ***) eta-charge dependence: + if (qv.fCalculateQvectors && (t0.fCalculate2DTest0AsFunctionOf[AFO_ETA_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_CHARGE])) { + // Remark: For eta dependence I do not consider es.fCalculateEtaSeparations, because in this context that calculation is meaningless. + double kineArr[2] = {dEta, dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 2, ETA_CHARGEq); } - if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { // TBI 20240423 I need to extend this condition to mupa.fCalculateCorrelations or some differential version of it - this->Fillqvector(dPhi, dEta, ETAq); // first 2 arguments are passed by reference, 3rd argument is enum + + // ... + + // ** 3D: + // ***) pt-eta-charge dependence: + if (qv.fCalculateQvectors && (t0.fCalculate3DTest0AsFunctionOf[AFO_PT_ETA_CHARGE])) { + // Remark: For eta dependence I do not consider es.fCalculateEtaSeparations, because in this context that calculation is meaningless. + double kineArr[3] = {dPt, dEta, dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 3, PT_ETA_CHARGEq); } // *) Fill nested loops containers: @@ -2822,34 +7035,66 @@ void InternalValidation() } // *) 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[eSelectedTracks][eMax]) { + if (ebye.fSelectedTracks >= ec.fdEventCuts[eMultiplicity][eMax]) { break; } - } // for(Int_t 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 after cuts: - if (tc.fVerbose) { - if (eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]) { - LOGF(info, "\033[1;32m%s : event number %d/%d\033[0m", __FUNCTION__, static_cast(eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->GetBinContent(1)), static_cast(iv.fnEventsInternalValidation)); - } + // *) Print info on the current event number (within current real event): + LOGF(info, " Event # %d/%d (within current real event, running internal validation) ....", 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(); + BailOut(true); } } - } // for(Int_t e=0;e(iv.fnEventsInternalValidation);e++) + } // 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) { @@ -2859,11 +7104,15 @@ void InternalValidation() delete fvnPDF; } + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + } // void InternalValidation() //============================================================ -Bool_t Accept(const Double_t& value, Int_t var) +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. @@ -2884,10 +7133,10 @@ Bool_t Accept(const Double_t& value, Int_t var) LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - Bool_t bAccept = kTRUE; // return value + bool bAccept = true; // return value - Double_t acceptanceProbability = 1.; - Double_t correspondingAcceptance = -44.; + double acceptanceProbability = 1.; + double correspondingAcceptance = -44.; if (!nua.fUseDefaultNUAPDF[var]) { correspondingAcceptance = nua.fCustomNUAPDF[var]->GetBinContent(nua.fCustomNUAPDF[var]->FindBin(value)); } else { @@ -2897,161 +7146,649 @@ Bool_t Accept(const Double_t& value, Int_t var) // Probability to accept: acceptanceProbability = 1. - (nua.fMaxValuePDF[var] - correspondingAcceptance) / nua.fMaxValuePDF[var]; - // Accept or not: - (gRandom->Uniform(0, 1) < acceptanceProbability) ? bAccept = kTRUE : bAccept = kFALSE; + // 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) Book what needs to be booked for 1D; + // d) Book what needs to be booked for 2D; + // e) Book what needs to be booked for 3D; + // f) Few quick insanity checks on booking (cherry-picking). + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Book the profile holding flags: + t0.fTest0FlagsPro = new TProfile("fTest0FlagsPro", "flags for Test0", 3, 0., 3.); + t0.fTest0FlagsPro->SetStats(false); + t0.fTest0FlagsPro->GetXaxis()->SetLabelSize(0.04); + + if (tc.fUseSetBinLabel) { + t0.fTest0FlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateTest0"); + t0.fTest0FlagsPro->GetXaxis()->SetBinLabel(2, "fCalculate2DTest0"); + t0.fTest0FlagsPro->GetXaxis()->SetBinLabel(3, "fCalculate3DTest0"); + + // ... + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fCalculateTest0; ", 1); + yAxisTitle += TString::Format("%d:fCalculate2DTest0; ", 2); + yAxisTitle += TString::Format("%d:fCalculate3DTest0; ", 3); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != t0.fTest0FlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != t0.fTest0FlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), t0.fTest0FlagsPro->GetNbinsX()); + } + + // *) Okay, set the title: + t0.fTest0FlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + + // ... + + } // else + + t0.fTest0FlagsPro->Fill(0.5, static_cast(t0.fCalculateTest0)); + t0.fTest0FlagsPro->Fill(1.5, static_cast(t0.fCalculate2DTest0)); + t0.fTest0FlagsPro->Fill(2.5, static_cast(t0.fCalculate3DTest0)); + // ... + t0.fTest0List->Add(t0.fTest0FlagsPro); + + if (!(t0.fCalculateTest0 || t0.fCalculate2DTest0 || t0.fCalculate3DTest0)) { + return; + } + + // b) Book placeholder and make sure all labels are stored in the placeholder: + this->StoreLabelsInPlaceholder(); + + // c) Book what needs to be booked for 1D: + if (t0.fCalculateTest0) { + 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 fTest0Pro[k][n][v] is used as a boolean, in the standard way: + if (!t0.fCalculateTest0AsFunctionOf[v]) { + continue; + } + + if (!res.fResultsPro[v]) { + LOGF(fatal, "\033[1;31m%s at line %d : fResultsPro[%d] is NULL, this shall never happen, but apparently it happened... \033[0m", __FUNCTION__, __LINE__, v); + } + + if (tc.fUseClone) { + t0.fTest0Pro[mo][mi][v] = reinterpret_cast(res.fResultsPro[v]->Clone(Form("fTest0Pro[%d][%d][%s]", mo, mi, res.fResultsProRawName[v].Data()))); // yes + } else { + t0.fTest0Pro[mo][mi][v] = new TProfile(Form("fTest0Pro[%d][%d][%s]", mo, mi, res.fResultsProRawName[v].Data()), "", res.fResultsPro[v]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[v]->GetXaxis()->GetXbins()->GetArray()); + } + + 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())); + t0.fTest0List->Add(t0.fTest0Pro[mo][mi][v]); // yes, this has to be here + + } // for(int v=0;vGetName(); + TObjArray* oa = rawName.Tokenize("[]"); + if (oa->GetEntries() != 2) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() = %d \033[0m", __FUNCTION__, __LINE__, oa->GetEntries()); + } + rawName = oa->At(1)->GetName(); // basically: fResultsPro2D[cent_pt] => cent_pt + delete oa; + if (rawName.EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : rawName is empty string \033[0m", __FUNCTION__, __LINE__); + } + + if (tc.fUseClone) { + t0.fTest0Pro2D[mo][mi][v] = reinterpret_cast(res.fResultsPro2D[v]->Clone(Form("fTest0Pro2D[%d][%d][%s]", mo, mi, rawName.Data()))); + } else { + // TBI 20250412 this branch is temporary workaround until hist->Clone(...) large memory consumption is resolved + t0.fTest0Pro2D[mo][mi][v] = new TProfile2D(Form("fTest0Pro2D[%d][%d][%s]", mo, mi, rawName.Data()), "", + res.fResultsPro2D[v]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro2D[v]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro2D[v]->GetYaxis()->GetXbins()->GetSize() - 1, res.fResultsPro2D[v]->GetYaxis()->GetXbins()->GetArray()); // yes, GetYaxis()->GetXbins() + } // else + + t0.fTest0Pro2D[mo][mi][v]->SetStats(false); + t0.fTest0Pro2D[mo][mi][v]->Sumw2(); + t0.fTest0Pro2D[mo][mi][v]->SetTitle(t0.fTest0Labels[mo][mi]->Data()); + t0.fTest0Pro2D[mo][mi][v]->GetXaxis()->SetTitle(FancyFormatting(res.fResultsPro2D[v]->GetXaxis()->GetTitle())); + t0.fTest0Pro2D[mo][mi][v]->GetYaxis()->SetTitle(FancyFormatting(res.fResultsPro2D[v]->GetYaxis()->GetTitle())); + t0.fTest0List->Add(t0.fTest0Pro2D[mo][mi][v]); // yes, this has to be here + + } // for(int v=0;vGetName(); + TObjArray* oa = rawName.Tokenize("[]"); + if (oa->GetEntries() != 2) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() = %d \033[0m", __FUNCTION__, __LINE__, oa->GetEntries()); + } + rawName = oa->At(1)->GetName(); // basically: fResultsPro2D[cent_pt_eta] => cent_pt_eta + delete oa; + if (rawName.EqualTo("")) { + LOGF(fatal, "\033[1;31m%s at line %d : rawName is empty string \033[0m", __FUNCTION__, __LINE__); + } + + if (tc.fUseClone) { + t0.fTest0Pro3D[mo][mi][v] = reinterpret_cast(res.fResultsPro3D[v]->Clone(Form("fTest0Pro3D[%d][%d][%s]", mo, mi, rawName.Data()))); + } else { + // TBI 20250412 this branch is temporary workaround until hist->Clone(...) large memory consumption is resolved + t0.fTest0Pro3D[mo][mi][v] = new TProfile3D(Form("fTest0Pro3D[%d][%d][%s]", mo, mi, rawName.Data()), "", + res.fResultsPro3D[v]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro3D[v]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro3D[v]->GetYaxis()->GetXbins()->GetSize() - 1, res.fResultsPro3D[v]->GetYaxis()->GetXbins()->GetArray(), // yes, GetYaxis()->GetXbins() + res.fResultsPro3D[v]->GetZaxis()->GetXbins()->GetSize() - 1, res.fResultsPro3D[v]->GetZaxis()->GetXbins()->GetArray()); // yes, GetZaxis()->GetXbins() + } // else + + t0.fTest0Pro3D[mo][mi][v]->SetStats(false); + t0.fTest0Pro3D[mo][mi][v]->Sumw2(); + t0.fTest0Pro3D[mo][mi][v]->SetTitle(t0.fTest0Labels[mo][mi]->Data()); + t0.fTest0Pro3D[mo][mi][v]->GetXaxis()->SetTitle(FancyFormatting(res.fResultsPro3D[v]->GetXaxis()->GetTitle())); + t0.fTest0Pro3D[mo][mi][v]->GetYaxis()->SetTitle(FancyFormatting(res.fResultsPro3D[v]->GetYaxis()->GetTitle())); + t0.fTest0Pro3D[mo][mi][v]->GetZaxis()->SetTitle(FancyFormatting(res.fResultsPro3D[v]->GetZaxis()->GetTitle())); + t0.fTest0List->Add(t0.fTest0Pro3D[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 : x-axis title = %s\033[0m", __FUNCTION__, __LINE__, t0.fTest0Pro[0][0][AFO_PT]->GetXaxis()->GetTitle()); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + + // 2D: + if (t0.fTest0Pro2D[0][0][AFO_CENTRALITY_PT] && !(TString(t0.fTest0Pro2D[0][0][AFO_CENTRALITY_PT]->GetXaxis()->GetTitle()).Contains("centrality", TString::kIgnoreCase) && TString(t0.fTest0Pro2D[0][0][AFO_CENTRALITY_PT]->GetYaxis()->GetTitle()).EqualTo("p_{T}"))) { + LOGF(fatal, "\033[1;31m%s at line %d : x-axis title = %s, y-axis title = %s\033[0m", __FUNCTION__, __LINE__, t0.fTest0Pro2D[0][0][AFO_CENTRALITY_PT]->GetXaxis()->GetTitle(), t0.fTest0Pro2D[0][0][AFO_CENTRALITY_PT]->GetYaxis()->GetTitle()); // ordering in enum eAsFunctionOf is not the same as in TString fResultsProXaxisTitle[eAsFunctionOf_N] + } + + // 3D: + if (t0.fTest0Pro3D[0][0][AFO_CENTRALITY_PT_ETA] && !(TString(t0.fTest0Pro3D[0][0][AFO_CENTRALITY_PT_ETA]->GetXaxis()->GetTitle()).Contains("centrality", TString::kIgnoreCase) && TString(t0.fTest0Pro3D[0][0][AFO_CENTRALITY_PT_ETA]->GetYaxis()->GetTitle()).EqualTo("p_{T}") && TString(t0.fTest0Pro3D[0][0][AFO_CENTRALITY_PT_ETA]->GetZaxis()->GetTitle()).EqualTo("#eta"))) { + LOGF(fatal, "\033[1;31m%s at line %d : x-axis title = %s, y-axis title = %s, z-axis title = %s\033[0m", __FUNCTION__, __LINE__, t0.fTest0Pro3D[0][0][AFO_CENTRALITY_PT_ETA]->GetXaxis()->GetTitle(), t0.fTest0Pro3D[0][0][AFO_CENTRALITY_PT_ETA]->GetYaxis()->GetTitle(), t0.fTest0Pro3D[0][0][AFO_CENTRALITY_PT_ETA]->GetZaxis()->GetTitle()); // 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); + + if (tc.fUseSetBinLabel) { + es.fEtaSeparationsFlagsPro->GetXaxis()->SetBinLabel(1, "fCalculateEtaSeparations"); + + // ... + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; - return bAccept; + yAxisTitle += TString::Format("%d:fCalculateEtaSeparations; ", 1); + es.fEtaSeparationsFlagsPro->Fill(0.5, static_cast(es.fCalculateEtaSeparations)); -} // Bool_t Accept(const Double_t &value, Int_t var) + // ... -//============================================================ + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != es.fEtaSeparationsFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() - 1 = %d != es.fEtaSeparationsFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), es.fEtaSeparationsFlagsPro->GetNbinsX()); + } -void BookTest0Histograms() -{ - // Book all Test0 histograms. + // *) Okay, set the title: + es.fEtaSeparationsFlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); - // 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); - } + } // else - // 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); + es.fEtaSeparationsFlagsPro->Fill(0.5, es.fCalculateEtaSeparations); + es.fEtaSeparationsList->Add(es.fEtaSeparationsFlagsPro); - if (!t0.fCalculateTest0) { + if (!es.fCalculateEtaSeparations) { 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__); - } + // 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++) { - // 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; - } + // decide what is booked, then later valid pointer to es.fEtaSeparationsPro[h][e][v] is used as a boolean, in the standard way: + if (!es.fCalculateEtaSeparationsAsFunctionOf[v]) { + continue; + } - if (!res.fResultsPro[v]) { - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } + if (!res.fResultsPro[v]) { + LOGF(fatal, "\033[1;31m%s at line %d : fResultsPro[%d] is NULL, this shall never happen, but apparently it happened... \033[0m", __FUNCTION__, __LINE__, v); + } - 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(res.fResultsPro[v]->Clone(Form("fEtaSeparationsPro[%d][%d][%s]", h, e, res.fResultsProRawName[v].Data()))); // yes + } else { + es.fEtaSeparationsPro[h][e][v] = new TProfile(Form("fEtaSeparationsPro[%d][%d][%s]", h, e, res.fResultsProRawName[v].Data()), "", res.fResultsPro[v]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[v]->GetXaxis()->GetXbins()->GetArray()); + } - // 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")) { + 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 (t0.fTest0Pro[0][0][AFO_PT] && !TString(t0.fTest0Pro[0][0][AFO_PT]->GetXaxis()->GetTitle()).EqualTo("p_{T}")) { + 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] } -} // void BookTest0Histograms() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void bookEtaSeparationsHistograms() //============================================================ -void BookResultsHistograms() +void bookResultsHistograms() { // Book all results histograms. + // These results histograms in addition act as a sort of "abstract" interface, which defines common binning, etc., for other groups of 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. + // b) Book (and optionaly save) results histograms 1D; + // c) Book (and optionaly save) results histograms 2D; + // d) Book (and optionaly save) results histograms 3D. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Book the profile holding flags: - res.fResultsFlagsPro = new TProfile("fResultsFlagsPro", - "flags for results histograms", 1, 0., 1.); - res.fResultsFlagsPro->SetStats(kFALSE); + 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_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()), "...", static_cast(res.fResultsProFixedLengthBins[v][0]), res.fResultsProFixedLengthBins[v][1], res.fResultsProFixedLengthBins[v][2]); + if (tc.fUseSetBinLabel) { + res.fResultsFlagsPro->GetXaxis()->SetBinLabel(1, "fSaveResultsHistograms"); + res.fResultsFlagsPro->Fill(0.5, res.fSaveResultsHistograms); + + // ... + + } else { + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + + yAxisTitle += TString::Format("%d:fSaveResultsHistograms; ", 1); + res.fResultsFlagsPro->Fill(0.5, static_cast(res.fSaveResultsHistograms)); + + // ... + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != res.fResultsFlagsPro->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() = %d != res.fResultsFlagsPro->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), res.fResultsFlagsPro->GetNbinsX()); } + delete oa; + + // *) Okay, set the title: + res.fResultsFlagsPro->GetYaxis()->SetTitle(yAxisTitle.Data()); + } + res.fResultsList->Add(res.fResultsFlagsPro); + + // b) Book (and optionaly save) results histograms 1D: + for (int v = 0; v < eAsFunctionOf_N; v++) { + + // TBI 20250518 I book 1D case always for the time being, because I also use their binning to book particle sparse histograms. + // There should not be any big memory penalty for 1D case + // if (!(t0.fCalculateTest0AsFunctionOf[v] || mupa.fCalculateCorrelationsAsFunctionOf[v] || es.fCalculateEtaSeparationsAsFunctionOf[v])) { + // // TBI 20250518 do I need here also some check for the nested loops? + // continue; + // } + + res.fResultsPro[v] = new TProfile(Form("fResultsPro[%s]", res.fResultsProRawName[v].Data()), "...", res.fResultsProBinEdges[v]->GetSize() - 1, res.fResultsProBinEdges[v]->GetArray()); + res.fResultsPro[v]->GetXaxis()->SetTitle(res.fResultsProXaxisTitle[v].Data()); + res.fResultsPro[v]->SetStats(false); - // Optionally, save these histograms. Or just use them as an "abstract" interface for the booking of other group of histograms: + delete res.fResultsProBinEdges[v]; // yes, it served the purpose. Now this info is carried permanently with res.fResultsPro[v], and I can always retrieve it later with e.g. + // res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins() (which gives pointer to TArrayD, yes I need double, because TProfile ctor takes double) + + // Optionally, save these histograms - I need this mostly to check/validate the binning. if (res.fSaveResultsHistograms) { res.fResultsList->Add(res.fResultsPro[v]); } - } // for (Int_t v = 0; v < eAsFunctionOf_N; v++) { + } // for (int v = 0; v < eAsFunctionOf_N; v++) + + // c) Book (and optionaly save) results histograms 2D: + // Remark 1: Here I cannot loop, because for each axis I re-use binning from 1D cases. + // Remark 2: I have deleted above res.fResultsProBinEdges[...], that info is now only in the axis of res.fResultsPro[...] + if (t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_PT]) { + TString rawName = TString::Format("%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_PT].Data()); // raw name is e.g. "[cent_pt]" in the file + res.fResultsPro2D[AFO_CENTRALITY_PT] = new TProfile2D(Form("fResultsPro2D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro2D[AFO_CENTRALITY_PT]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_CENTRALITY_PT]->GetYaxis()->SetTitle(res.fResultsPro[AFO_PT]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_CENTRALITY_PT]->SetStats(false); + } + + if (t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_ETA]) { + TString rawName = TString::Format("%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_ETA].Data()); + res.fResultsPro2D[AFO_CENTRALITY_ETA] = new TProfile2D(Form("fResultsPro2D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro2D[AFO_CENTRALITY_ETA]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_CENTRALITY_ETA]->GetYaxis()->SetTitle(res.fResultsPro[AFO_ETA]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_CENTRALITY_ETA]->SetStats(false); + } + + if (t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_CHARGE]) { + TString rawName = TString::Format("%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_CHARGE].Data()); + res.fResultsPro2D[AFO_CENTRALITY_CHARGE] = new TProfile2D(Form("fResultsPro2D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetArray()); + + res.fResultsPro2D[AFO_CENTRALITY_CHARGE]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_CENTRALITY_CHARGE]->GetYaxis()->SetTitle(res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_CENTRALITY_CHARGE]->SetStats(false); + } + + if (t0.fCalculate2DTest0AsFunctionOf[AFO_CENTRALITY_VZ]) { + TString rawName = TString::Format("%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_VZ].Data()); + res.fResultsPro2D[AFO_CENTRALITY_VZ] = new TProfile2D(Form("fResultsPro2D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_VZ]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_VZ]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro2D[AFO_CENTRALITY_VZ]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_CENTRALITY_VZ]->GetYaxis()->SetTitle(res.fResultsPro[AFO_VZ]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_CENTRALITY_VZ]->SetStats(false); + } + + if (t0.fCalculate2DTest0AsFunctionOf[AFO_PT_ETA]) { + TString rawName = TString::Format("%s_%s", res.fResultsProRawName[AFO_PT].Data(), res.fResultsProRawName[AFO_ETA].Data()); + res.fResultsPro2D[AFO_PT_ETA] = new TProfile2D(Form("fResultsPro2D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro2D[AFO_PT_ETA]->GetXaxis()->SetTitle(res.fResultsPro[AFO_PT]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_PT_ETA]->GetYaxis()->SetTitle(res.fResultsPro[AFO_ETA]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_PT_ETA]->SetStats(false); + } + + if (t0.fCalculate2DTest0AsFunctionOf[AFO_PT_CHARGE]) { + TString rawName = TString::Format("%s_%s", res.fResultsProRawName[AFO_PT].Data(), res.fResultsProRawName[AFO_CHARGE].Data()); + res.fResultsPro2D[AFO_PT_CHARGE] = new TProfile2D(Form("fResultsPro2D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro2D[AFO_PT_CHARGE]->GetXaxis()->SetTitle(res.fResultsPro[AFO_PT]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_PT_CHARGE]->GetYaxis()->SetTitle(res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_PT_CHARGE]->SetStats(false); + } + + if (t0.fCalculate2DTest0AsFunctionOf[AFO_ETA_CHARGE]) { + TString rawName = TString::Format("%s_%s", res.fResultsProRawName[AFO_ETA].Data(), res.fResultsProRawName[AFO_CHARGE].Data()); + res.fResultsPro2D[AFO_ETA_CHARGE] = new TProfile2D(Form("fResultsPro2D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro2D[AFO_ETA_CHARGE]->GetXaxis()->SetTitle(res.fResultsPro[AFO_ETA]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_ETA_CHARGE]->GetYaxis()->SetTitle(res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetTitle()); + res.fResultsPro2D[AFO_ETA_CHARGE]->SetStats(false); + } + + // ... + + // Optionally, save 2D results histograms - I need this mostly to check/validate the binning: + for (int v = 0; v < eAsFunctionOf2D_N; v++) { + if (res.fSaveResultsHistograms && res.fResultsPro2D[v]) { + res.fResultsList->Add(res.fResultsPro2D[v]); + } + } + + // d) Book (and optionaly save) results histograms 3D: + // Remark 1: Here I cannot loop, because for each axis I re-use binning from 1D cases. + // Remark 2: I have deleted above res.fResultsProBinEdges[...], that info is now only in the axis of res.fResultsPro[...] + if (t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_ETA]) { + TString rawName = TString::Format("%s_%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_PT].Data(), res.fResultsProRawName[AFO_ETA].Data()); + res.fResultsPro3D[AFO_CENTRALITY_PT_ETA] = new TProfile3D(Form("fResultsPro3D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro3D[AFO_CENTRALITY_PT_ETA]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_ETA]->GetYaxis()->SetTitle(res.fResultsPro[AFO_PT]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_ETA]->GetZaxis()->SetTitle(res.fResultsPro[AFO_ETA]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_ETA]->SetStats(false); + } + + if (t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_CHARGE]) { + TString rawName = TString::Format("%s_%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_PT].Data(), res.fResultsProRawName[AFO_CHARGE].Data()); + res.fResultsPro3D[AFO_CENTRALITY_PT_CHARGE] = new TProfile3D(Form("fResultsPro3D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro3D[AFO_CENTRALITY_PT_CHARGE]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_CHARGE]->GetYaxis()->SetTitle(res.fResultsPro[AFO_PT]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_CHARGE]->GetZaxis()->SetTitle(res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_CHARGE]->SetStats(false); + } + + if (t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_VZ]) { + TString rawName = TString::Format("%s_%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_PT].Data(), res.fResultsProRawName[AFO_VZ].Data()); + res.fResultsPro3D[AFO_CENTRALITY_PT_VZ] = new TProfile3D(Form("fResultsPro3D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_VZ]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_VZ]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro3D[AFO_CENTRALITY_PT_VZ]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_VZ]->GetYaxis()->SetTitle(res.fResultsPro[AFO_PT]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_VZ]->GetZaxis()->SetTitle(res.fResultsPro[AFO_VZ]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_PT_VZ]->SetStats(false); + } + + if (t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_VZ]) { + TString rawName = TString::Format("%s_%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_ETA].Data(), res.fResultsProRawName[AFO_VZ].Data()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_VZ] = new TProfile3D(Form("fResultsPro3D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_VZ]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_VZ]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_VZ]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_VZ]->GetYaxis()->SetTitle(res.fResultsPro[AFO_ETA]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_VZ]->GetZaxis()->SetTitle(res.fResultsPro[AFO_VZ]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_VZ]->SetStats(false); + } + + if (t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_CHARGE]) { + TString rawName = TString::Format("%s_%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_ETA].Data(), res.fResultsProRawName[AFO_CHARGE].Data()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_CHARGE] = new TProfile3D(Form("fResultsPro3D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_CHARGE]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_CHARGE]->GetYaxis()->SetTitle(res.fResultsPro[AFO_ETA]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_CHARGE]->GetZaxis()->SetTitle(res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_ETA_CHARGE]->SetStats(false); + } + + if (t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_VZ_CHARGE]) { + TString rawName = TString::Format("%s_%s_%s", res.fResultsProRawName[AFO_CENTRALITY].Data(), res.fResultsProRawName[AFO_VZ].Data(), res.fResultsProRawName[AFO_CHARGE].Data()); + res.fResultsPro3D[AFO_CENTRALITY_VZ_CHARGE] = new TProfile3D(Form("fResultsPro3D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_VZ]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_VZ]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro3D[AFO_CENTRALITY_VZ_CHARGE]->GetXaxis()->SetTitle(res.fResultsPro[AFO_CENTRALITY]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_VZ_CHARGE]->GetYaxis()->SetTitle(res.fResultsPro[AFO_VZ]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_VZ_CHARGE]->GetZaxis()->SetTitle(res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_CENTRALITY_VZ_CHARGE]->SetStats(false); + } + + if (t0.fCalculate3DTest0AsFunctionOf[AFO_PT_ETA_CHARGE]) { + TString rawName = TString::Format("%s_%s_%s", res.fResultsProRawName[AFO_PT].Data(), res.fResultsProRawName[AFO_ETA].Data(), res.fResultsProRawName[AFO_CHARGE].Data()); + res.fResultsPro3D[AFO_PT_ETA_CHARGE] = new TProfile3D(Form("fResultsPro3D[%s]", rawName.Data()), "...", + res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_PT]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_ETA]->GetXaxis()->GetXbins()->GetArray(), + res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetSize() - 1, res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetXbins()->GetArray()); + res.fResultsPro3D[AFO_PT_ETA_CHARGE]->GetXaxis()->SetTitle(res.fResultsPro[AFO_PT]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_PT_ETA_CHARGE]->GetYaxis()->SetTitle(res.fResultsPro[AFO_ETA]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_PT_ETA_CHARGE]->GetZaxis()->SetTitle(res.fResultsPro[AFO_CHARGE]->GetXaxis()->GetTitle()); + res.fResultsPro3D[AFO_PT_ETA_CHARGE]->SetStats(false); + } + + // Optionally, save 3D results histograms - I need this mostly to check/validate the binning: + for (int v = 0; v < eAsFunctionOf3D_N; v++) { + + if (res.fSaveResultsHistograms && res.fResultsPro3D[v]) { + res.fResultsList->Add(res.fResultsPro3D[v]); + } + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void bookResultsHistograms() + +//============================================================ + +TArrayD* ArrayWithBinEdges(int nBins, float min, float max) +{ + // Helper function to determine concrete bin edges, when the fixed-size binning was specified with nBins in (min, max). + + // a) Insanity checks on arguments; + // b) Okay, do the thing. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) Insanity check on arguments: + if (nBins <= 0 || max < min || std::abs(max - min) < tc.fFloatingPointPrecision) { + LOGF(fatal, "\033[1;31m%s at line %d : Insane arguments for fixed-length binning: nBins = %d , min = %f, max = %f \033[0m", __FUNCTION__, __LINE__, nBins, min, max); + } + + // b) Okay, do the thing: + float binWidth = (max - min) / (1. * nBins); -} // void BookResultsHistograms() + TArrayD* binEdges = new TArrayD(nBins + 1); + for (int b = 1; b <= nBins + 1; b++) { + binEdges->AddAt(min + (b - 1) * binWidth, b - 1); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + return binEdges; + +} // TArrayD *ArrayWithBinEdges(int nBins, float min, float max) //============================================================ -void BookTheRest() +void bookTheRest() { // Here I book everything not sorted (yes) in specific functions above. // a) Book the timer; + // b) Book TDatabasePDG; // *) ... if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Book the timer: @@ -3061,82 +7798,194 @@ void BookTheRest() tc.fTimer[eLocal] = new TStopwatch(); } -} // void BookTheRest() + // b) Book TDatabasePDG: + if (tc.fUseDatabasePDG) { + tc.fDatabasePDG = new TDatabasePDG(); // there is a standard memory blow-up here + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void bookTheRest() //============================================================ -template -void Preprocess(T const& collision) +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) { - // LOGF(info, "\033[1;32m%s\033[0m", __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__); + } + + // *) 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(); + BailOut(true); } // *) Determine and propagate run number info to already booked objects: if (!tc.fRunNumberIsDetermined) { - DetermineAndPropagateRunNumber(collision); + DetermineRunNumber(collision, bcs); + PropagateRunNumber(); } + if (tc.fDoAdditionalInsanityChecks && tc.fRunNumberIsDetermined) { - CheckCurrentRunNumber(collision); + 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]) { GetParticleWeights(); - pw.fParticleWeightsAreFetched = kTRUE; + 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; } } -} // template void Preprocess(T const& collision) + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // template void Preprocess(T1 const& collision, T2 const& bcs) //============================================================ -template -void DetermineAndPropagateRunNumber(T const& collision) +template +void DetermineRunNumber(T1 const& collision, T2 const&) { - // Determine and propagate run number info to already booked objects, wherever it's relevant. + // 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(...) via collision->bc().runNumber(), but not in init(...) + // 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; - // b) Propagate run number to all booked objects, wherever that info is relevant. + // 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) { - // LOGF(info, "\033[1;32m%s\033[0m", __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__); } - // 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 + // Do some local insanity checks: if (tc.fRunNumber.EqualTo("")) { - LOGF(error, "\033[1;33m%s fRunNumber is empty, collision->bc().runNumber() failed...\033[0m", __FUNCTION__); - LOGF(fatal, "collision->bc().runNumber() = %d", collision.bc().runNumber()); + LOGF(fatal, "\033[1;31m%s at line %d : tc.fRunNumber is empty \033[0m", __FUNCTION__, __LINE__); } - tc.fRunNumberIsDetermined = kTRUE; - // b) Propagate run number to all booked objects, wherever that info is relevant: // *) base: - fBasePro->GetXaxis()->SetBinLabel(eRunNumber, Form("tc.fRunNumber = %s", tc.fRunNumber.Data())); + if (tc.fUseSetBinLabel) { + fBasePro->GetXaxis()->SetBinLabel(eRunNumber, Form("fRunNumber = %s", tc.fRunNumber.Data())); + } else { + // Workaround for SetBinLabel() large memory consumption: + TString tmp = fBasePro->GetYaxis()->GetTitle(); + fBasePro->GetYaxis()->SetTitle(tmp.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data())); + } // else // *) common title var: TString histTitle = ""; // *) event cuts: - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter { if (!ec.fEventCutCounterHist[rs][cc]) { continue; @@ -3150,11 +7999,11 @@ void DetermineAndPropagateRunNumber(T const& collision) } // *) event histograms 1D: - for (Int_t t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms + for (int t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms { - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts + for (int ba = 0; ba < 2; ba++) // before/after cuts { if (!eh.fEventHistograms[t][rs][ba]) { continue; @@ -3164,16 +8013,16 @@ void DetermineAndPropagateRunNumber(T const& collision) histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place eh.fEventHistograms[t][rs][ba]->SetTitle(histTitle.Data()); } - } // for(Int_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for(Int_t t=0;tSetTitle(histTitle.Data()); } - } // for(Int_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for (Int_t t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eEventHistograms2D + } // 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 t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + for (int t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D { - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts + for (int ba = 0; ba < 2; ba++) // before/after cuts { if (!qa.fQAParticleHistograms2D[t][rs][ba]) { continue; @@ -3202,16 +8051,86 @@ void DetermineAndPropagateRunNumber(T const& collision) histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place qa.fQAParticleHistograms2D[t][rs][ba]->SetTitle(histTitle.Data()); } - } // for(Int_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for (Int_t t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + } // 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 cuts: - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + // *) 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_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + 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; } @@ -3224,11 +8143,11 @@ void DetermineAndPropagateRunNumber(T const& collision) } // *) particle histograms 1D: - for (Int_t t = 0; t < eParticleHistograms_N; t++) // type, see enum eParticleHistograms + for (int t = 0; t < eParticleHistograms_N; t++) // type, see enum eParticleHistograms { - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts + for (int ba = 0; ba < 2; ba++) // before/after cuts { if (!ph.fParticleHistograms[t][rs][ba]) { continue; @@ -3238,16 +8157,16 @@ void DetermineAndPropagateRunNumber(T const& collision) histTitle.ReplaceAll("__RUN_NUMBER__", tc.fRunNumber.Data()); // it replaces in-place ph.fParticleHistograms[t][rs][ba]->SetTitle(histTitle.Data()); } - } // for(Int_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for(Int_t t=0;tSetTitle(histTitle.Data()); } - } // for(Int_t ba=0;ba<2;ba++) - } // for(Int_t rs=0;rs<2;rs++) // reco/sim - } // for(Int_t 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__); + } -} // template void DetermineAndPropagateRunNumber(T const& collision) +} // PropagateRunNumber() //============================================================ -template -void CheckCurrentRunNumber(T const& collision) +template +void CheckCurrentRunNumber(T1 const& collision, T2 const&) { - // Insanity check for the current run number. + // 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.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()); + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } -} // template void CheckCurrentRunNumber(T const& collision) +} // template void CheckCurrentRunNumber(T1 const& collision, T2 const&) //============================================================ @@ -3286,39 +8283,106 @@ void ResetEventByEventQuantities() // a) Event-by-event quantities; // b) Q-vectors; // c) Reset ebe containers for nested loops; - // d) Fisher-Yates algorithm. + // d) Fisher-Yates algorithm; + // e) QA. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Event-by-event quantities: ebye.fSelectedTracks = 0; - ebye.fCentrality = 0; + ebye.fMultiplicity = 0.; + ebye.fReferenceMultiplicity = 0.; + ebye.fCentrality = 0.; + // ebye.fCentralitySim = 0.; // TBI 20250429 special treatment, because I access this one before Steer(...) is called in .cxx . Re-think how to handle this one + // But if I do not access it in .cxx, in any case I skip that collision, so I think it is just fine not to reset it here + ebye.fOccupancy = 0.; + ebye.fInteractionRate = 0.; + ebye.fCurrentRunDuration = 0.; + ebye.fVz = 0.; + ebye.fFT0CAmplitudeOnFoundBC = 0.; + ebye.fImpactParameter = 0.; // I can reset it here to 0., as long as I am calculating it from collision.mcCollision().impactParameter() . If I calculate it from hep.impactParameter(), i need to re-think // 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 + 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_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) + } // if (qv.fCalculateQvectors) + + if (qv.fCalculateqvectorsKineAny) { + ResetQ(); // TBI 20250601 do I really need this one here. It doesn't hurt, though... + // Remark: It's important to validate this reset with nested loops e-by-e and for all events. + for (int i = 0; i < static_cast(qv.fqvector.size()); ++i) { + for (int j = 0; j < static_cast(qv.fqvector[i].size()); ++j) { + qv.fqvectorEntries[i][j] = 0; + for (int k = 0; k < static_cast(qv.fqvector[i][j].size()); ++k) { + for (int l = 0; l < static_cast(qv.fqvector[i][j][k].size()); ++l) { + qv.fqvector[i][j][k][l] = {0., 0.}; // yes, this is the right notation for complex numbers + } + } + } + } + + } // if (qv.fCalculateqvectorsKineAny) + + // 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 needed for calculations with eta separations: + if (es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { // _444 check this conditions + // [-eta or +eta][eqvectorKine_N][global binNo][harmonic][eta separation] + for (int i = 0; i < static_cast(qv.fqabVector.size()); ++i) { + for (int j = 0; j < static_cast(qv.fqabVector[i].size()); ++j) { + for (int k = 0; k < static_cast(qv.fqabVector[i][j].size()); ++k) { + for (int l = 0; l < static_cast(qv.fqabVector[i][j][k].size()); ++l) { // yes, this dimension is for harmonics at the moment + if (es.fEtaSeparationsSkipHarmonics[l]) { + continue; + } + for (int m = 0; m < static_cast(qv.fqabVector[i][j][k][l].size()); ++m) { + qv.fqabVector[i][j][k][l][m] = {0., 0.}; // yes, this is the right notation for complex numbers + } + } + } + } + } + + // [-eta or +eta][eqvectorKine_N][global binNo][eta separation] + for (int i = 0; i < static_cast(qv.fmab.size()); ++i) { + for (int j = 0; j < static_cast(qv.fmab[i].size()); ++j) { + for (int k = 0; k < static_cast(qv.fmab[i][j].size()); ++k) { + for (int l = 0; l < static_cast(qv.fmab[i][j][k].size()); ++l) { + qv.fmab[i][j][k][l] = 0.; + } + } + } + } + + } // if (es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) // c) Reset ebe containers for nested loops: if (nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) { @@ -3332,14 +8396,74 @@ void ResetEventByEventQuantities() } // if(nl.fCalculateNestedLoops || nl.fCalculateCustomNestedLoops) if (nl.fCalculateKineCustomNestedLoops) { - for (Int_t b = 0; b < res.fResultsPro[AFO_PT]->GetNbinsX(); b++) { + int nBins = -1; + + // 1D kine: + // **) vs. pt: + nBins = res.fResultsPro[AFO_PT]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { nl.ftaNestedLoopsKine[PTq][b][0]->Reset(); nl.ftaNestedLoopsKine[PTq][b][1]->Reset(); } - for (Int_t b = 0; b < res.fResultsPro[AFO_ETA]->GetNbinsX(); b++) { + + // **) vs. eta: + nBins = res.fResultsPro[AFO_ETA]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { nl.ftaNestedLoopsKine[ETAq][b][0]->Reset(); nl.ftaNestedLoopsKine[ETAq][b][1]->Reset(); } + + // **) vs. charge: + nBins = res.fResultsPro[AFO_CHARGE]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { + nl.ftaNestedLoopsKine[CHARGEq][b][0]->Reset(); + nl.ftaNestedLoopsKine[CHARGEq][b][1]->Reset(); + } + + // ... + + // 2D kine: + // **) vs. (pt,eta): + if (res.fResultsPro2D[AfoKineMap2D(PT_ETAq)]) { // this is safe, because this one shall be booked if any of Correlations, Test0, EtaSeparations, etc., was requested + nBins = (res.fResultsPro2D[AfoKineMap2D(PT_ETAq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(PT_ETAq)]->GetNbinsY() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { // loop over lineralized global bins + nl.ftaNestedLoopsKine[PT_ETAq][b][0]->Reset(); + nl.ftaNestedLoopsKine[PT_ETAq][b][1]->Reset(); + } + } + + // **) vs. (pt,charge): + if (res.fResultsPro2D[AfoKineMap2D(PT_CHARGEq)]) { // this is safe, because this one shall be booked if any of Correlations, Test0, EtaSeparations, etc., was requested + nBins = (res.fResultsPro2D[AfoKineMap2D(PT_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(PT_CHARGEq)]->GetNbinsY() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { // loop over lineralized global bins + nl.ftaNestedLoopsKine[PT_CHARGEq][b][0]->Reset(); + nl.ftaNestedLoopsKine[PT_CHARGEq][b][1]->Reset(); + } + } + + // **) vs. (eta,charge): + if (res.fResultsPro2D[AfoKineMap2D(ETA_CHARGEq)]) { // this is safe, because this one shall be booked if any of Correlations, Test0, EtaSeparations, etc., was requested + nBins = (res.fResultsPro2D[AfoKineMap2D(ETA_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro2D[AfoKineMap2D(ETA_CHARGEq)]->GetNbinsY() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { // loop over lineralized global bins + nl.ftaNestedLoopsKine[ETA_CHARGEq][b][0]->Reset(); + nl.ftaNestedLoopsKine[ETA_CHARGEq][b][1]->Reset(); + } + } + + // ... + + // 3D kine: + // **) vs. (pt,eta,charge): + if (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]) { // this is safe, because this one shall be booked if any of Correlations, Test0, EtaSeparations, etc., was requested + nBins = (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsX() + 2) * (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsY() + 2) * (res.fResultsPro3D[AfoKineMap3D(PT_ETA_CHARGEq)]->GetNbinsZ() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + for (int b = 0; b < nBins; b++) { // loop over lineralized global bins + nl.ftaNestedLoopsKine[PT_ETA_CHARGEq][b][0]->Reset(); + nl.ftaNestedLoopsKine[PT_ETA_CHARGEq][b][1]->Reset(); + } + } + + // ... + } // if(nl.fCalculateKineCustomNestedLoops) { // d) Fisher-Yates algorithm: @@ -3348,7 +8472,20 @@ void ResetEventByEventQuantities() tc.fRandomIndices = NULL; } - // ... TBI 20240117 port the rest ... + // 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() @@ -3360,7 +8497,7 @@ 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); // just a bare function name + StartFunction(__FUNCTION__); } // *) Establish ordering of binning in event cut counters histograms, which resembles ordering of event cuts implementation: @@ -3369,45 +8506,78 @@ void EventCutsCounters(T1 const& collision, T2 const& tracks) 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 eSelectedTracks: - // Algorithm: I simply add eSelectedTracks at the end of what was esatablished by now in the above call EventCuts(collision, tracks, eCutCounterBinning) + // **) 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], eSelectedTracks); - ec.fEventCutCounterMapInverse[eRec]->Add(eSelectedTracks, ec.fEventCutCounterBinNumber[eRec]); + 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], eSelectedTracks); - ec.fEventCutCounterMapInverse[eSim]->Add(eSelectedTracks, ec.fEventCutCounterBinNumber[eSim]); + 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_t 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 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_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter { if (!ec.fEventCutCounterHist[rec_sim][cc]) { continue; } - for (Int_t 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_t bin = ec.fEventCutCounterBinNumber[rec_sim]; bin <= eEventCuts_N; bin++) // implemented, but unused cuts in this analysis - { - ec.fEventCutCounterHist[rec_sim][cc]->GetXaxis()->SetBinLabel(bin, "TBI"); - } - // All cuts which were implemeted, not used, and tagged temporarily with "TBI", simply do not show: - // TBI 20240522 re-think if this is really what I want here. + + if (tc.fUseSetBinLabel) { + 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, TString::Format("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... + } + } else { + + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + for (int bin = 1; bin < ec.fEventCutCounterBinNumber[rec_sim]; bin++) // implemented and used cuts in this analysis + { + yAxisTitle += TString::Format("%d:%s; ", 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 + { + yAxisTitle += TString::Format("%d:%s; ", bin, TString::Format("binNo = %d (unused cut)", bin).Data()); + } + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != ec.fEventCutCounterHist[rec_sim][cc]->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() = %d != ec.fEventCutCounterHist[rec_sim][cc]->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), ec.fEventCutCounterHist[rec_sim][cc]->GetNbinsX()); + } + delete oa; + + // *) Okay, set the title: + ec.fEventCutCounterHist[rec_sim][cc]->GetYaxis()->SetTitle(yAxisTitle.Data()); + + } // else + + // 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 = kTRUE; // this flag ensures that this specific binning is performed only once, for the first processed event + 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]; @@ -3420,340 +8590,619 @@ void EventCutsCounters(T1 const& collision, T2 const& tracks) ec.fEventCutCounterBinNumber[eSim] = 1; EventCuts(collision, tracks, eCutCounterAbsolute); - // **) Special treatments: - // a) eSelectedTracks: It doesn't make sense to treat this one in 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. std::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] || std::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] || std::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] || std::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] || std::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] || std::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] || std::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 (std::sqrt(std::pow(collision.posX(), 2.) + std::pow(collision.posY(), 2.) + std::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] || std::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() > (tc.fUseFormula ? ec.fEventCutsFormulas[eRefMultVsNContrUp_Formula]->Eval(ebye.fReferenceMultiplicity) : RefMultVsNContr(ebye.fReferenceMultiplicity, eRefMultVsNContrUp_Formula))) { + if (!EventCut(eRec, eRefMultVsNContrUp, cutModus)) { + return false; + } + } + } + + // *) RefMultVsNContrLow: + if (ec.fUseEventCuts[eRefMultVsNContrLow]) { + if (cutModus == eCutCounterBinning) { + EventCut(eRec, eRefMultVsNContrLow, eCutCounterBinning); + } else if (collision.numContrib() < (tc.fUseFormula ? ec.fEventCutsFormulas[eRefMultVsNContrLow_Formula]->Eval(ebye.fReferenceMultiplicity) : RefMultVsNContr(ebye.fReferenceMultiplicity, eRefMultVsNContrLow_Formula))) { + 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, "\033[1;31m%s at line %d : No MC collision for this collision, skip... \033[0m", __FUNCTION__, __LINE__); // 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] || std::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] || std::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 centrality is calculated directly from impact parameter, i.e. this is centrality at simulated level, see DetermineCentrality(...) what I do for thre "eSim*" cases. + if (ec.fUseEventCuts[eCentrality]) { + if (cutModus == eCutCounterBinning) { + EventCut(eSim, eCentrality, eCutCounterBinning); + } else if (ebye.fCentrality < ec.fdEventCuts[eCentrality][eMin] || ebye.fCentrality > ec.fdEventCuts[eCentrality][eMax] || std::abs(ebye.fCentrality - ec.fdEventCuts[eCentrality][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eSim, eCentrality, cutModus)) { + return false; + } + } + } + + // *) 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] || std::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] || std::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] || std::abs(collision.posZ() - ec.fdEventCuts[eVertexZ][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eSim, eVertexZ, cutModus)) { + return false; + } + } + } - // *) Event cut counter (sequential): - if (ec.fUseEventCutCounterSequential) { - ec.fEventCutCounterBinNumber[eRec] = 1; - ec.fEventCutCounterBinNumber[eSim] = 1; - EventCuts(collision, tracks, eCutCounterSequential); + // *) 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 (std::sqrt(std::pow(collision.posX(), 2.) + std::pow(collision.posY(), 2.) + std::pow(collision.posZ(), 2.)) < ec.fdEventCuts[eMinVertexDistanceFromIP][eMin]) { + if (!EventCut(eRec, eMinVertexDistanceFromIP, cutModus)) { + return false; + } + } + } - // **) Special treatments: - // a) eSelectedTracks: Since cut on eSelectedTracks is implenented outside of EventCuts - // I call EventCut(rs, eSelectedTracks, eCutCounterSequential) directly where its implemented. - // Add same treatment for other special cases, but do not forget above to expand **) Special treatment for event cuts ... - } + // *) Sel8: TBI 20240509 -} // template void EventCutsCounters(T1 const& collision, T2 const& tracks, eCutModus cutModus) + // *) SelectedEvents: => this event cut is implemented directly in Steer(...) -//============================================================ + // ... -template -Bool_t 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. + } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { - // 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 on Test case. + // ------------------------------------------------------------------------- - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); // just a bare function name - } + // 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) { - // 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) { + // 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 - // *) NumberOfEvents: => this event cut is implemented directly in Steer(...) + // *) 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] || std::abs(ebye.fOccupancy - ec.fdEventCuts[eOccupancy][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eOccupancy, cutModus)) { + return false; + } + } + } - // *) Sel8: // see definition in Common/TableProducer/eventSelection.cxx - if (ec.fUseEventCuts[eSel8]) { + // *) InteractionRate: + if (ec.fUseEventCuts[eInteractionRate]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eSel8, eCutCounterBinning); - } else if (!collision.sel8()) { - if (!EventCut(eRec, eSel8, cutModus)) { - return kFALSE; + EventCut(eRec, eInteractionRate, eCutCounterBinning); + } else if (ebye.fInteractionRate < ec.fdEventCuts[eInteractionRate][eMin] || ebye.fInteractionRate > ec.fdEventCuts[eInteractionRate][eMax] || std::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] || std::abs(ebye.fCurrentRunDuration - ec.fdEventCuts[eCurrentRunDuration][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eCurrentRunDuration, cutModus)) { + return false; } } } - // *) NoSameBunchPileup: // see O2Physics/Common/CCDB/EventSelectionParams.cxx + // *) 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 kFALSE; + return false; } } } - // *) IsGoodZvtxFT0vsPV: // see O2Physics/Common/CCDB/EventSelectionParams.cxx + // *) 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 kFALSE; + return false; } } } - // *) IsVertexITSTPC: // see O2Physics/Common/CCDB/EventSelectionParams.cxx + // *) 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 kFALSE; + return false; } } } - // *) IsVertexTOFmatched: // see O2Physics/Common/CCDB/EventSelectionParams.cxx + // *) 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 kFALSE; + return false; } } } - // *) IsVertexTRDmatched: // see O2Physics/Common/CCDB/EventSelectionParams.cxx + // *) 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 kFALSE; + return false; } } } - // *) TotalMultiplicity: - if (ec.fUseEventCuts[eTotalMultiplicity]) { + // *) NoCollInTimeRangeStrict: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoCollInTimeRangeStrict]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eTotalMultiplicity, eCutCounterBinning); - } else if (tracks.size() < ec.fdEventCuts[eTotalMultiplicity][eMin] || tracks.size() > ec.fdEventCuts[eTotalMultiplicity][eMax]) { - if (!EventCut(eRec, eTotalMultiplicity, cutModus)) { - return kFALSE; + EventCut(eRec, eNoCollInTimeRangeStrict, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + if (!EventCut(eRec, eNoCollInTimeRangeStrict, cutModus)) { + return false; } } } - // *) SelectedTracks: - // Remark: This cut is implemented directly in void process( ... ) TBI 20240508 check how to implement this one with the current re-write - - // *) 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]) { + // *) NoCollInTimeRangeStandard: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoCollInTimeRangeStandard]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eCentrality, eCutCounterBinning); - } else if (ebye.fCentrality < ec.fdEventCuts[eCentrality][eMin] || ebye.fCentrality > ec.fdEventCuts[eCentrality][eMax]) { - if (!EventCut(eRec, eCentrality, cutModus)) { - return kFALSE; + EventCut(eRec, eNoCollInTimeRangeStandard, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + if (!EventCut(eRec, eNoCollInTimeRangeStandard, cutModus)) { + return false; } } } - // *) Vertex_x: - if (ec.fUseEventCuts[eVertex_x]) { + // *) NoCollInRofStrict: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoCollInRofStrict]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eVertex_x, eCutCounterBinning); - } else if (collision.posX() < ec.fdEventCuts[eVertex_x][eMin] || collision.posX() > ec.fdEventCuts[eVertex_x][eMax]) { - if (!EventCut(eRec, eVertex_x, cutModus)) { - return kFALSE; + EventCut(eRec, eNoCollInRofStrict, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + if (!EventCut(eRec, eNoCollInRofStrict, cutModus)) { + return false; } } } - // *) Vertex_y: - if (ec.fUseEventCuts[eVertex_y]) { + // *) NoCollInRofStandard: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoCollInRofStandard]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eVertex_y, eCutCounterBinning); - } else if (collision.posY() < ec.fdEventCuts[eVertex_y][eMin] || collision.posY() > ec.fdEventCuts[eVertex_y][eMax]) { - if (!EventCut(eRec, eVertex_y, cutModus)) { - return kFALSE; + EventCut(eRec, eNoCollInRofStandard, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + if (!EventCut(eRec, eNoCollInRofStandard, cutModus)) { + return false; } } } - // *) Vertex_z: - if (ec.fUseEventCuts[eVertex_z]) { + // *) NoHighMultCollInPrevRof: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoHighMultCollInPrevRof]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eVertex_z, eCutCounterBinning); - } else if (collision.posZ() < ec.fdEventCuts[eVertex_z][eMin] || collision.posZ() > ec.fdEventCuts[eVertex_z][eMax]) { - if (!EventCut(eRec, eVertex_z, cutModus)) { - return kFALSE; + EventCut(eRec, eNoHighMultCollInPrevRof, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + if (!EventCut(eRec, eNoHighMultCollInPrevRof, cutModus)) { + return false; } } } - // *) NContributors: - if (ec.fUseEventCuts[eNContributors]) { + // *) IsGoodITSLayer3: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsGoodITSLayer3]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eNContributors, eCutCounterBinning); - } else if (collision.numContrib() < ec.fdEventCuts[eNContributors][eMin] || collision.numContrib() > ec.fdEventCuts[eNContributors][eMax]) { - if (!EventCut(eRec, eNContributors, cutModus)) { - return kFALSE; + EventCut(eRec, eIsGoodITSLayer3, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + if (!EventCut(eRec, eIsGoodITSLayer3, cutModus)) { + return false; } } } - // *) SelectedEvents: => this event cut is implemented directly in Steer(...) - - // ... - - // ... 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 kFALSE; + // *) 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; + } } + } - // 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]) { + // *) IsGoodITSLayersAll: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eIsGoodITSLayersAll]) { if (cutModus == eCutCounterBinning) { - EventCut(eSim, eImpactParameter, eCutCounterBinning); - } else if (collision.impactParameter() < ec.fdEventCuts[eImpactParameter][eMin] || collision.impactParameter() > ec.fdEventCuts[eImpactParameter][eMax]) { - if (!EventCut(eSim, eImpactParameter, cutModus)) { - return kFALSE; + EventCut(eRec, eIsGoodITSLayersAll, eCutCounterBinning); + } else if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + if (!EventCut(eRec, eIsGoodITSLayersAll, cutModus)) { + return false; } } } - // *) TotalMultiplicity: - // TBI 20240509 check what is the Monte Carlo analogy for tracks.size() - - // *) SelectedTracks: - // Remark: This cut is implemented directly in void process( ... ) 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? - - // *) Vertex_x: - if (ec.fUseEventCuts[eVertex_x]) { + // *) FT0Bad: // see O2Physics/Common/CCDB/RCTSelectionFlags.h + if (ec.fUseEventCuts[eFT0Bad]) { if (cutModus == eCutCounterBinning) { - EventCut(eSim, eVertex_x, eCutCounterBinning); - } else if (collision.posX() < ec.fdEventCuts[eVertex_x][eMin] || collision.posX() > ec.fdEventCuts[eVertex_x][eMax]) { - if (!EventCut(eSim, eVertex_x, cutModus)) { - return kFALSE; + EventCut(eRec, eFT0Bad, eCutCounterBinning); + } else if (collision.rct_bit(o2::aod::rctsel::kFT0Bad)) { + if (!EventCut(eRec, eFT0Bad, cutModus)) { + return false; } } } - // *) Vertex_y: - if (ec.fUseEventCuts[eVertex_y]) { + // *) ITSBad: // see O2Physics/Common/CCDB/RCTSelectionFlags.h + if (ec.fUseEventCuts[eITSBad]) { if (cutModus == eCutCounterBinning) { - EventCut(eSim, eVertex_y, eCutCounterBinning); - } else if (collision.posY() < ec.fdEventCuts[eVertex_y][eMin] || collision.posY() > ec.fdEventCuts[eVertex_y][eMax]) { - if (!EventCut(eSim, eVertex_y, cutModus)) { - return kFALSE; + EventCut(eRec, eITSBad, eCutCounterBinning); + } else if (collision.rct_bit(o2::aod::rctsel::kITSBad)) { + if (!EventCut(eRec, eITSBad, cutModus)) { + return false; } } } - // *) Vertex_z: - if (ec.fUseEventCuts[eVertex_z]) { + // *) ITSLimAccMCRepr: // see O2Physics/Common/CCDB/RCTSelectionFlags.h + if (ec.fUseEventCuts[eITSLimAccMCRepr]) { if (cutModus == eCutCounterBinning) { - EventCut(eSim, eVertex_z, eCutCounterBinning); - } else if (collision.posZ() < ec.fdEventCuts[eVertex_z][eMin] || collision.posZ() > ec.fdEventCuts[eVertex_z][eMax]) { - if (!EventCut(eSim, eVertex_z, cutModus)) { - return kFALSE; + EventCut(eRec, eITSLimAccMCRepr, eCutCounterBinning); + } else if (collision.rct_bit(o2::aod::rctsel::kITSLimAccMCRepr)) { + if (!EventCut(eRec, eITSLimAccMCRepr, 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) { - - // 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 - - // *) MultFV0M: - if (ec.fUseEventCuts[eMultFV0M]) { + // *) TPCBadTracking: // see O2Physics/Common/CCDB/RCTSelectionFlags.h + if (ec.fUseEventCuts[eTPCBadTracking]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eMultFV0M, eCutCounterBinning); - } else if (collision.multFV0M() < ec.fdEventCuts[eMultFV0M][eMin] || collision.multFV0M() > ec.fdEventCuts[eMultFV0M][eMax]) { - if (!EventCut(eRec, eVertex_z, cutModus)) { - return kFALSE; + EventCut(eRec, eTPCBadTracking, eCutCounterBinning); + } else if (collision.rct_bit(o2::aod::rctsel::kTPCBadTracking)) { + if (!EventCut(eRec, eTPCBadTracking, cutModus)) { + return false; } } } - // *) MultFT0M: - if (ec.fUseEventCuts[eMultFT0M]) { + // *) TPCLimAccMCRepr: // see O2Physics/Common/CCDB/RCTSelectionFlags.h + if (ec.fUseEventCuts[eTPCLimAccMCRepr]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eMultFT0M, eCutCounterBinning); - } else if (collision.multFT0M() < ec.fdEventCuts[eMultFT0M][eMin] || collision.multFT0M() > ec.fdEventCuts[eMultFT0M][eMax]) { - if (!EventCut(eRec, eVertex_z, cutModus)) { - return kFALSE; + EventCut(eRec, eTPCLimAccMCRepr, eCutCounterBinning); + } else if (collision.rct_bit(o2::aod::rctsel::kTPCLimAccMCRepr)) { + if (!EventCut(eRec, eTPCLimAccMCRepr, cutModus)) { + return false; } } } - // *) MultTPC: - if (ec.fUseEventCuts[eMultTPC]) { + // *) TPCBadPID: // see O2Physics/Common/CCDB/RCTSelectionFlags.h + if (ec.fUseEventCuts[eTPCBadPID]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eMultTPC, eCutCounterBinning); - } else if (collision.multTPC() < ec.fdEventCuts[eMultTPC][eMin] || collision.multTPC() > ec.fdEventCuts[eMultTPC][eMax]) { - if (!EventCut(eRec, eVertex_z, cutModus)) { - return kFALSE; + EventCut(eRec, eTPCBadPID, eCutCounterBinning); + } else if (collision.rct_bit(o2::aod::rctsel::kTPCBadPID)) { + if (!EventCut(eRec, eTPCBadPID, cutModus)) { + return false; } } } - // *) MultNTracksPV: - if (ec.fUseEventCuts[eMultNTracksPV]) { + // ... + + // *) 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, eMultNTracksPV, eCutCounterBinning); - } else if (collision.multNTracksPV() < ec.fdEventCuts[eMultNTracksPV][eMin] || collision.multNTracksPV() > ec.fdEventCuts[eMultNTracksPV][eMax]) { - if (!EventCut(eRec, eMultNTracksPV, cutModus)) { - return kFALSE; + 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 kFALSE; + LOGF(warning, "\033[1;31m%s at line %d : No MC collision for this collision, skip... \033[0m", __FUNCTION__, __LINE__); // 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. @@ -3784,54 +9233,75 @@ Bool_t EventCuts(T1 const& collision, T2 const& tracks, eCutModus cutModus) // 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) { - // *) 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)) { - if (!EventCut(eRec, eTrigger, cutModus)) { - return kFALSE; - } - } - } - // *) Sel7: if (ec.fUseEventCuts[eSel7]) { if (cutModus == eCutCounterBinning) { EventCut(eRec, eSel7, eCutCounterBinning); } else if (!collision.sel7()) { if (!EventCut(eRec, eSel7, cutModus)) { - return kFALSE; + 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; } } } - // *) MultTracklets: - if (ec.fUseEventCuts[eMultTracklets]) { + // *) NoSPDOnVsOfPileup: // see O2Physics/Common/CCDB/EventSelectionParams.cxx (and .h for better documentation) + if (ec.fUseEventCuts[eNoSPDOnVsOfPileup]) { if (cutModus == eCutCounterBinning) { - EventCut(eRec, eMultTracklets, eCutCounterBinning); - } else if (collision.multTracklets() < ec.fdEventCuts[eMultTracklets][eMin] || collision.multTracklets() > ec.fdEventCuts[eMultTracklets][eMax]) { - if (!EventCut(eRec, eMultTracklets, cutModus)) { - return kFALSE; + 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 kFALSE; + LOGF(warning, "\033[1;31m%s at line %d : No MC collision for this collision, skip... \033[0m", __FUNCTION__, __LINE__); // 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. @@ -3867,20 +9337,20 @@ Bool_t EventCuts(T1 const& collision, T2 const& tracks, eCutModus cutModus) 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]) { + } else if (tracks.size() < ec.fdEventCuts[eTotalMultiplicity][eMin] || tracks.size() > ec.fdEventCuts[eTotalMultiplicity][eMax] || std::abs(tracks.size() - ec.fdEventCuts[eTotalMultiplicity][eMax]) < tc.fFloatingPointPrecision) { if (!EventCut(eRec, eTotalMultiplicity, cutModus)) { - return kFALSE; + return false; } } } - // *) Vertex_z: - if (ec.fUseEventCuts[eVertex_z]) { + // *) VertexZ: + if (ec.fUseEventCuts[eVertexZ]) { if (cutModus == eCutCounterBinning) { - EventCut(eSim, eVertex_z, eCutCounterBinning); - } else if (collision.posZ() < ec.fdEventCuts[eVertex_z][eMin] || collision.posZ() > ec.fdEventCuts[eVertex_z][eMax]) { - if (!EventCut(eSim, eVertex_z, cutModus)) { - return kFALSE; + EventCut(eRec, eVertexZ, eCutCounterBinning); + } else if (collision.posZ() < ec.fdEventCuts[eVertexZ][eMin] || collision.posZ() > ec.fdEventCuts[eVertexZ][eMax] || std::abs(collision.posZ() - ec.fdEventCuts[eVertexZ][eMax]) < tc.fFloatingPointPrecision) { + if (!EventCut(eRec, eVertexZ, cutModus)) { + return false; } } } @@ -3889,9 +9359,9 @@ Bool_t EventCuts(T1 const& collision, T2 const& tracks, eCutModus cutModus) 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]) { + } else if (ebye.fCentrality < ec.fdEventCuts[eCentrality][eMin] || ebye.fCentrality > ec.fdEventCuts[eCentrality][eMax] || std::abs(ebye.fCentrality - ec.fdEventCuts[eCentrality][eMax]) < tc.fFloatingPointPrecision) { if (!EventCut(eRec, eCentrality, cutModus)) { - return kFALSE; + return false; } } } @@ -3900,16 +9370,18 @@ Bool_t EventCuts(T1 const& collision, T2 const& tracks, eCutModus cutModus) } // if constexpr (rs == eTest) { - return kTRUE; + return true; -} // template Bool_t EventCuts(T1 const& collision, T2 const& tracks) +} // template bool EventCuts(T1 const& collision, T2 const& tracks) //============================================================ -Bool_t EventCut(Int_t rs, Int_t eventCut, eCutModus cutModus) +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 eSelectedTracks, but use with care. + // 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 . @@ -3923,41 +9395,130 @@ Bool_t EventCut(Int_t rs, Int_t eventCut, eCutModus cutModus) // *) Do the thing: switch (cutModus) { - case eCut: - if (tc.fVerbose) { - LOGF(info, "\033[1;31mEvent didn't pass the cut: %s\033[0m", ec.fEventCutName[eventCut].Data()); + case eCut: { + if (tc.fVerboseEventCut) { + LOGF(info, "\033[1;31mEvent didn't survive the cut: %s\033[0m", ec.fEventCutName[eventCut].Data()); } - return kFALSE; + return false; break; - case eCutCounterBinning: + } + case eCutCounterBinning: { ec.fEventCutCounterMap[rs]->Add(ec.fEventCutCounterBinNumber[rs], eventCut); ec.fEventCutCounterMapInverse[rs]->Add(eventCut, ec.fEventCutCounterBinNumber[rs]); ec.fEventCutCounterBinNumber[rs]++; // yes - return kTRUE; + return true; break; - case eCutCounterAbsolute: + } + case eCutCounterAbsolute: { ec.fEventCutCounterHist[rs][eAbsolute]->Fill(ec.fEventCutCounterMapInverse[rs]->GetValue(eventCut)); - return kTRUE; // yes, so that I can proceed with another cut in EventCuts + return true; // yes, so that I can proceed with another cut in EventCuts break; - case eCutCounterSequential: + } + case eCutCounterSequential: { ec.fEventCutCounterHist[rs][eSequential]->Fill(ec.fEventCutCounterMapInverse[rs]->GetValue(eventCut)); - return kFALSE; // yes, so that I bail out from EventCuts + return false; // yes, so that I bail out from EventCuts break; - default: + } + 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 kFALSE; // obsolete, but it suppresses the warning... + 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] || std::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__); + } -} // Bool_t EventCut(Int_t rs, Int_t eventCut, eCutModus cutModus) +} // void FillSubeventMultiplicities() //============================================================ template void FillEventHistograms(T1 const& collision, T2 const& tracks, eBeforeAfter ba) { - // Fill all event histograms for reconstructed or simulated data. + // 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); @@ -3967,112 +9528,302 @@ void FillEventHistograms(T1 const& collision, T2 const& tracks, eBeforeAfter ba) // 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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) { - // 1D: - !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[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); + 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[eMultTPC_vs_NContributors][eRec][ba] ? true : qa.fQAEventHistograms2D[eMultTPC_vs_NContributors][eRec][ba]->Fill(collision.multTPC(), collision.numContrib()); - !qa.fQAEventHistograms2D[eVertex_z_vs_MultTPC][eRec][ba] ? true : qa.fQAEventHistograms2D[eVertex_z_vs_MultTPC][eRec][ba]->Fill(collision.posZ(), collision.multTPC()); - !qa.fQAEventHistograms2D[eVertex_z_vs_NContributors][eRec][ba] ? true : qa.fQAEventHistograms2D[eVertex_z_vs_NContributors][eRec][ba]->Fill(collision.posZ(), collision.numContrib()); - !qa.fQAEventHistograms2D[eCentFT0M_vs_CentNTPV][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentFT0M_vs_CentNTPV][eRec][ba]->Fill(qa.fCentrality[eCentFT0M], qa.fCentrality[eCentNTPV]); - } + !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..."); + LOGF(warning, "\033[1;31m%s at line %d : No MC collision for this collision, skip... \033[0m", __FUNCTION__, __LINE__); return; } - !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[eImpactParameter][eSim][ba] ? true : eh.fEventHistograms[eImpactParameter][eSim][ba]->Fill(collision.mcCollision().impactParameter()); - // 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) { + 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] ? true : eh.fEventHistograms[eCentrality][eSim][ba]->Fill(ebye.fCentralitySim); + } + + // 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()); + !qa.fQAEventHistograms2D[eCentrality_vs_CentralitySim][eSim][ba] ? true : qa.fQAEventHistograms2D[eCentrality_vs_CentralitySim][eSim][ba]->Fill(ebye.fCentrality, ebye.fCentralitySim); + // ... + } + } // 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] ? true : eh.fEventHistograms[eCentrality][eSim][ba]->Fill(ebye.fCentrality); // ebye.fCentrality = ebye.fCentralitySim in any case in this branch + // 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); + } - // b) Fill only simulated (common to Run 3, Run 2 and Run 1): - if constexpr (rs == eSim || 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[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.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(); - // 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()); + } // 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..."); + LOGF(warning, "\033[1;31m%s at line %d : No MC collision for this collision, skip... \033[0m", __FUNCTION__, __LINE__); 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) { + } // if constexpr (rs == eRec || rs == eRecAndSim) { // ----------------------------------------------------------------------------- - // d) Fill only simulated(Run 3 specific): + // 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) { - !eh.fEventHistograms[eMultTracklets][eRec][ba] ? true : eh.fEventHistograms[eMultTracklets][eRec][ba]->Fill(collision.multTracklets()); + 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]); - !qa.fQAEventHistograms2D[eCentRun2V0M_vs_NContributors][eRec][ba] ? true : qa.fQAEventHistograms2D[eCentRun2V0M_vs_NContributors][eRec][ba]->Fill(qa.fCentrality[eCentRun2V0M], collision.numContrib()); } // ... 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..."); + LOGF(warning, "\033[1;31m%s at line %d : No MC collision for this collision, skip... \033[0m", __FUNCTION__, __LINE__); 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) { + } // 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) { // ----------------------------------------------------------------------------- @@ -4081,11 +9832,18 @@ void FillEventHistograms(T1 const& collision, T2 const& tracks, eBeforeAfter ba) 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: - !eh.fEventHistograms[eVertex_z][eRec][ba] ? true : eh.fEventHistograms[eVertex_z][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 (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(...) //============================================================ @@ -4094,23 +9852,28 @@ void CheckUnderflowAndOverflow() { // Check and bail out if in event and particle histograms there are entries which went to underflow or overflow bins. + // TBI 20250527 I have reinvented the wheel here, there are already member functions TH1::IsBinUnderflow() and TH1::IsBinOverflow(), + // which I have use also for 2D and 3D cases with "global bin". + // Reimplemented this function using those member functions eventually. + // 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. + // f) QA Particle histograms 2D; + // g) QA Particle event histograms 2D. if (tc.fVerboseForEachParticle) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Event histograms 1D: - for (Int_t t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms + for (int t = 0; t < eEventHistograms_N; t++) // type, see enum eEventHistograms { - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts + for (int ba = 0; ba < 2; ba++) // before/after cuts { if (!eh.fEventHistograms[t][rs][ba]) { continue; @@ -4127,11 +9890,11 @@ void CheckUnderflowAndOverflow() // ... // c) Particle histograms 1D: - for (Int_t t = 0; t < eParticleHistograms_N; t++) // type, see enum eParticleHistograms + for (int t = 0; t < eParticleHistograms_N; t++) // type, see enum eParticleHistograms { - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts + for (int ba = 0; ba < 2; ba++) // before/after cuts { if (!ph.fParticleHistograms[t][rs][ba]) { continue; @@ -4145,28 +9908,28 @@ void CheckUnderflowAndOverflow() } // d) Particle histograms 2D: - for (Int_t t = 0; t < eParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + for (int t = 0; t < eParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D { - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts + for (int ba = 0; ba < 2; ba++) // before/after cuts { if (!ph.fParticleHistograms2D[t][rs][ba]) { continue; } // Underflow and overflow in x: - for (Int_t binY = 0; binY <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + 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_t binY = 0; binY <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + } // for (int binY = 0; binY <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { // Underflow and overflow in y: - for (Int_t binX = 0; binX <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + 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); } @@ -4174,34 +9937,34 @@ void CheckUnderflowAndOverflow() 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_t binX = 0; binX <= ph.fParticleHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { - } // for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - } // for (Int_t rs = 0; rs < 2; rs++) // reco/sim - } // for (Int_t t = 0; t < eParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + } // 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 t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eQAEventHistograms2D + for (int t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eQAEventHistograms2D { - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts + for (int ba = 0; ba < 2; ba++) // before/after cuts { if (!qa.fQAEventHistograms2D[t][rs][ba]) { continue; } // Underflow and overflow in x: - for (Int_t binY = 0; binY <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + 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_t binY = 0; binY <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + } // for (int binY = 0; binY <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { // Underflow and overflow in y: - for (Int_t binX = 0; binX <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + 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); } @@ -4209,34 +9972,34 @@ void CheckUnderflowAndOverflow() 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_t binX = 0; binX <= qa.fQAEventHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { - } // for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - } // for (Int_t rs = 0; rs < 2; rs++) // reco/sim - } // for (Int_t t = 0; t < eQAEventHistograms2D_N; t++) // type, see enum eQAEventHistograms2D + } // 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 t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eQAParticleHistograms2D + for (int t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eQAParticleHistograms2D { - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t ba = 0; ba < 2; ba++) // before/after cuts + for (int ba = 0; ba < 2; ba++) // before/after cuts { if (!qa.fQAParticleHistograms2D[t][rs][ba]) { continue; } // Underflow and overflow in x: - for (Int_t binY = 0; binY <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + 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_t binY = 0; binY <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { + } // for (int binY = 0; binY <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsY(); binY++) { // Underflow and overflow in y: - for (Int_t binX = 0; binX <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { + 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); } @@ -4244,10 +10007,50 @@ void CheckUnderflowAndOverflow() 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_t binX = 0; binX <= qa.fQAParticleHistograms2D[t][rs][ba]->GetNbinsX(); binX++) { - } // for (Int_t ba = 0; ba < 2; ba++) // before/after cuts - } // for (Int_t rs = 0; rs < 2; rs++) // reco/sim - } // for (Int_t t = 0; t < eQAParticleHistograms2D_N; t++) // type, see enum eParticleHistograms2D + } // 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() @@ -4256,17 +10059,17 @@ void CheckUnderflowAndOverflow() template bool ValidTrack(T const& track) { - // Before I start applying any particle tracks, check if this is a valid 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. + // 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); LOGF(info, " track.phi() = %f", track.phi()); LOGF(info, " track.pt() = %f", track.pt()); LOGF(info, " track.eta() = %f", track.eta()); @@ -4275,12 +10078,12 @@ bool ValidTrack(T const& track) // 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 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 kFALSE; + return false; } } @@ -4291,7 +10094,7 @@ bool ValidTrack(T const& track) if (tc.fVerboseForEachParticle) { LOGF(info, "\033[1;31m%s track.trackType() == o2::aod::track::TrackTypeEnum::Run2Track\033[0m", __FUNCTION__); } - return kFALSE; + return false; } } @@ -4309,7 +10112,7 @@ bool ValidTrack(T const& track) 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 kFALSE; + return false; } // *) ... @@ -4318,19 +10121,133 @@ bool ValidTrack(T const& track) } // if(tc.fInsanityCheckForEachParticle) { // *) All checks above survived, then it's a valid track: - return kTRUE; + 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__); + LOGF(info, "\033[1;33m%s at line %d : ec.fsEventCuts[eCentralityCorrelationsCut] = %s \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityCorrelationsCut].Data()); + } + + 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: + if (!ec.fsEventCuts[eCentralityCorrelationsCut].Contains("_")) { + LOGF(fatal, "\033[1;31m%s at line %d : ec.fsEventCuts[eCentralityCorrelationsCut] = %s \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityCorrelationsCut].Data()); + } + + TObjArray* oa = ec.fsEventCuts[eCentralityCorrelationsCut].Tokenize("_"); // TBI 20250331 let's see for how long I can use "_" safely as IFS ... + if (!oa || 2 != oa->GetEntries()) { + 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()); + } + + if (tc.fVerbose) { + LOGF(info, "\033[1;33m%s at line %d : oa->At(0)->GetName() = %s \033[0m", __FUNCTION__, __LINE__, oa->At(0)->GetName()); + LOGF(info, "\033[1;33m%s at line %d : oa->At(1)->GetName() = %s \033[0m", __FUNCTION__, __LINE__, oa->At(1)->GetName()); + } + + 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 (std::abs((ec.fCentralityValues[0] - ec.fCentralityValues[1]) / (ec.fCentralityValues[0] + ec.fCentralityValues[1])) > ec.fCentralityCorrelationsCutTreshold) { + alright = false; + } + } else if (ec.fCentralityCorrelationsCutVersion.EqualTo("Absolute")) { + if (std::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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // *) Establish ordering of binning in particle cut counters histograms, which resembles ordering of particle cuts implementation: @@ -4340,28 +10257,60 @@ void ParticleCutsCounters(T const& track) 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_t 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 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_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + for (int cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter { if (!pc.fParticleCutCounterHist[rec_sim][cc]) { continue; } - for (Int_t 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_t 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, "TBI"); + + if (tc.fUseSetBinLabel) { + + 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... + } + + } else { + + // Workaround for SetBinLabel() large memory consumption: + TString yAxisTitle = ""; + for (int bin = 1; bin < pc.fParticleCutCounterBinNumber[rec_sim]; bin++) // implemented and used cuts in this analysis + { + yAxisTitle += TString::Format("%d:%s; ", 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 cuts in this analysis + { + yAxisTitle += TString::Format("%d:%s; ", bin, TString::Format("binNo = %d (unused cut)", bin).Data()); + } + + // *) Insanity check on the number of fields in this specially crafted y-axis title: + TObjArray* oa = yAxisTitle.Tokenize(";"); + if (!oa) { + LOGF(fatal, "\033[1;31m%s at line %d : oa is NULL\033[0m", __FUNCTION__, __LINE__); + } + if (oa->GetEntries() - 1 != pc.fParticleCutCounterHist[rec_sim][cc]->GetNbinsX()) { + LOGF(fatal, "\033[1;31m%s at line %d : oa->GetEntries() = %d != pc.fParticleCutCounterHist[rec_sim][cc]->GetNbinsX() = %d\033[0m", __FUNCTION__, __LINE__, oa->GetEntries(), pc.fParticleCutCounterHist[rec_sim][cc]->GetNbinsX()); + } + delete oa; + + // *) Okay, set the title: + pc.fParticleCutCounterHist[rec_sim][cc]->GetYaxis()->SetTitle(yAxisTitle.Data()); } - // All cuts which were implemeted, not used, and tagged temporarily with "TBI", simply do not show: - // TBI 20240522 re-think if this is really what I want here. + // 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 = kTRUE; // this flag ensures that this specific binning is performed only once, for the first processed particle + 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]; @@ -4387,10 +10336,12 @@ void ParticleCutsCounters(T const& track) //============================================================ template -Bool_t ParticleCuts(T const& track, eCutModus cutModus) +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. std::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); @@ -4401,20 +10352,22 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) // *) Particle cuts on Test case; // *) Toy NUA. + // 44:ParticleCuts + if (tc.fVerboseForEachParticle) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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) { + 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]) { + } else if (track.phi() < pc.fdParticleCuts[ePhi][eMin] || track.phi() > pc.fdParticleCuts[ePhi][eMax] || std::abs(track.phi() - pc.fdParticleCuts[ePhi][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, ePhi, cutModus)) { - return kFALSE; + return false; } } } @@ -4423,9 +10376,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.pt() < pc.fdParticleCuts[ePt][eMin] || track.pt() > pc.fdParticleCuts[ePt][eMax] || std::abs(track.pt() - pc.fdParticleCuts[ePt][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, ePt, cutModus)) { - return kFALSE; + return false; } } } @@ -4434,9 +10387,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.eta() < pc.fdParticleCuts[eEta][eMin] || track.eta() > pc.fdParticleCuts[eEta][eMax] || std::abs(track.eta() - pc.fdParticleCuts[eEta][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, eEta, cutModus)) { - return kFALSE; + return false; } } } @@ -4446,9 +10399,10 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) if (cutModus == eCutCounterBinning) { ParticleCut(eRec, 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 + // 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 kFALSE; + return false; } } } @@ -4459,7 +10413,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, etpcNClsFindable, eCutCounterBinning); } else if (track.tpcNClsFindable() < pc.fdParticleCuts[etpcNClsFindable][eMin] || track.tpcNClsFindable() > pc.fdParticleCuts[etpcNClsFindable][eMax]) { if (!ParticleCut(eRec, etpcNClsFindable, cutModus)) { - return kFALSE; + return false; } } } @@ -4470,7 +10424,18 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, etpcNClsShared, eCutCounterBinning); } else if (track.tpcNClsShared() < pc.fdParticleCuts[etpcNClsShared][eMin] || track.tpcNClsShared() > pc.fdParticleCuts[etpcNClsShared][eMax]) { if (!ParticleCut(eRec, etpcNClsShared, cutModus)) { - return kFALSE; + 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; } } } @@ -4481,7 +10446,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, etpcNClsFound, eCutCounterBinning); } else if (track.tpcNClsFound() < pc.fdParticleCuts[etpcNClsFound][eMin] || track.tpcNClsFound() > pc.fdParticleCuts[etpcNClsFound][eMax]) { if (!ParticleCut(eRec, etpcNClsFound, cutModus)) { - return kFALSE; + return false; } } } @@ -4492,7 +10457,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, etpcNClsCrossedRows, eCutCounterBinning); } else if (track.tpcNClsCrossedRows() < pc.fdParticleCuts[etpcNClsCrossedRows][eMin] || track.tpcNClsCrossedRows() > pc.fdParticleCuts[etpcNClsCrossedRows][eMax]) { if (!ParticleCut(eRec, etpcNClsCrossedRows, cutModus)) { - return kFALSE; + return false; } } } @@ -4503,7 +10468,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, eitsNCls, eCutCounterBinning); } else if (track.itsNCls() < pc.fdParticleCuts[eitsNCls][eMin] || track.itsNCls() > pc.fdParticleCuts[eitsNCls][eMax]) { if (!ParticleCut(eRec, eitsNCls, cutModus)) { - return kFALSE; + return false; } } } @@ -4514,7 +10479,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, eitsNClsInnerBarrel, eCutCounterBinning); } else if (track.itsNClsInnerBarrel() < pc.fdParticleCuts[eitsNClsInnerBarrel][eMin] || track.itsNClsInnerBarrel() > pc.fdParticleCuts[eitsNClsInnerBarrel][eMax]) { if (!ParticleCut(eRec, eitsNClsInnerBarrel, cutModus)) { - return kFALSE; + return false; } } } @@ -4523,9 +10488,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.tpcCrossedRowsOverFindableCls() < pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMin] || track.tpcCrossedRowsOverFindableCls() > pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax] || std::abs(track.tpcCrossedRowsOverFindableCls() - pc.fdParticleCuts[etpcCrossedRowsOverFindableCls][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, etpcCrossedRowsOverFindableCls, cutModus)) { - return kFALSE; + return false; } } } @@ -4534,9 +10499,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.tpcFoundOverFindableCls() < pc.fdParticleCuts[etpcFoundOverFindableCls][eMin] || track.tpcFoundOverFindableCls() > pc.fdParticleCuts[etpcFoundOverFindableCls][eMax] || std::abs(track.tpcFoundOverFindableCls() - pc.fdParticleCuts[etpcFoundOverFindableCls][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, etpcFoundOverFindableCls, cutModus)) { - return kFALSE; + return false; } } } @@ -4545,9 +10510,20 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.tpcFractionSharedCls() < pc.fdParticleCuts[etpcFractionSharedCls][eMin] || track.tpcFractionSharedCls() > pc.fdParticleCuts[etpcFractionSharedCls][eMax] || std::abs(track.tpcFractionSharedCls() - pc.fdParticleCuts[etpcFractionSharedCls][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, etpcFractionSharedCls, cutModus)) { - return kFALSE; + 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] || std::abs(track.tpcChi2NCl() - pc.fdParticleCuts[etpcChi2NCl][eMax]) < tc.fFloatingPointPrecision) { + if (!ParticleCut(eRec, etpcChi2NCl, cutModus)) { + return false; } } } @@ -4556,9 +10532,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.dcaXY() < pc.fdParticleCuts[edcaXY][eMin] || track.dcaXY() > pc.fdParticleCuts[edcaXY][eMax] || std::abs(track.dcaXY() - pc.fdParticleCuts[edcaXY][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, edcaXY, cutModus)) { - return kFALSE; + return false; } } } @@ -4567,9 +10543,20 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.dcaZ() < pc.fdParticleCuts[edcaZ][eMin] || track.dcaZ() > pc.fdParticleCuts[edcaZ][eMax] || std::abs(track.dcaZ() - pc.fdParticleCuts[edcaZ][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, edcaZ, cutModus)) { - return kFALSE; + 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; } } } @@ -4580,7 +10567,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, etrackCutFlagFb1, eCutCounterBinning); } else if (!track.trackCutFlagFb1()) { if (!ParticleCut(eRec, etrackCutFlagFb1, cutModus)) { - return kFALSE; + return false; } } } @@ -4591,7 +10578,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, etrackCutFlagFb2, eCutCounterBinning); } else if (!track.trackCutFlagFb2()) { if (!ParticleCut(eRec, etrackCutFlagFb2, cutModus)) { - return kFALSE; + return false; } } } @@ -4602,7 +10589,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, eisQualityTrack, eCutCounterBinning); } else if (!track.isQualityTrack()) { if (!ParticleCut(eRec, eisQualityTrack, cutModus)) { - return kFALSE; + return false; } } } @@ -4613,7 +10600,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, eisPrimaryTrack, eCutCounterBinning); } else if (!track.isPrimaryTrack()) { if (!ParticleCut(eRec, eisPrimaryTrack, cutModus)) { - return kFALSE; + return false; } } } @@ -4624,7 +10611,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, eisInAcceptanceTrack, eCutCounterBinning); } else if (!track.isInAcceptanceTrack()) { if (!ParticleCut(eRec, eisInAcceptanceTrack, cutModus)) { - return kFALSE; + return false; } } } @@ -4635,7 +10622,18 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) ParticleCut(eRec, eisGlobalTrack, eCutCounterBinning); } else if (!track.isGlobalTrack()) { if (!ParticleCut(eRec, eisGlobalTrack, cutModus)) { - return kFALSE; + 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; } } } @@ -4644,9 +10642,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) if (pc.fUseParticleCuts[ePtDependentDCAxyParameterization]) { if (cutModus == eCutCounterBinning) { ParticleCut(eRec, ePtDependentDCAxyParameterization, eCutCounterBinning); - } else if (TMath::Abs(track.dcaXY()) > pc.fPtDependentDCAxyFormula->Eval(track.pt())) { + } else if (std::abs(track.dcaXY()) > pc.fPtDependentDCAxyFormula->Eval(track.pt())) { if (!ParticleCut(eRec, ePtDependentDCAxyParameterization, cutModus)) { - return kFALSE; + return false; } } } @@ -4660,38 +10658,37 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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 track + 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 + // 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 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 kFALSE; - } - } - } - */ - // *) 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 kFALSE; - } - } - } - */ + // // *) 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, get charge from tc.fDatabasePDG instead using PDG code , as I did it below + + // 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 // ... @@ -4711,9 +10708,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.phi() < pc.fdParticleCuts[ePhi][eMin] || track.phi() > pc.fdParticleCuts[ePhi][eMax] || std::abs(track.phi() - pc.fdParticleCuts[ePhi][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eSim, ePhi, cutModus)) { - return kFALSE; + return false; } } } @@ -4722,9 +10719,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.pt() < pc.fdParticleCuts[ePt][eMin] || track.pt() > pc.fdParticleCuts[ePt][eMax] || std::abs(track.pt() - pc.fdParticleCuts[ePt][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eSim, ePt, cutModus)) { - return kFALSE; + return false; } } } @@ -4733,9 +10730,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.eta() < pc.fdParticleCuts[eEta][eMin] || track.eta() > pc.fdParticleCuts[eEta][eMax] || std::abs(track.eta() - pc.fdParticleCuts[eEta][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eSim, eEta, cutModus)) { - return kFALSE; + return false; } } } @@ -4743,17 +10740,39 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) /* // *) Charge: if (pc.fUseParticleCuts[eCharge]) { + double charge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(track.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + charge = tc.fDatabasePDG->GetParticle(track.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + if (tc.fVerboseForEachParticle) { + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! There is a large memory blow-up when using TDatabasePDG !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + } + } 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 + } else if (0 == static_cast(charge) || charge < pc.fdParticleCuts[eCharge][eMin] || charge > pc.fdParticleCuts[eCharge][eMax]) { + // TBI 20250611 with first condition, I always throw away neutral particles when O2DatabasePDG is used. + // However due to initialization charge = 0. that way I throw all particles when O2DatabasePDG is NOT used. + // Therefore, when O2DatabasePDG is NOT used, I have to disable cut on charge, since that info is not available. if (!ParticleCut(eSim, eCharge, cutModus)) { - return kFALSE; + return false; } } } + */ - // TBI 20240511 add cut on PDG + + // *) PDG code: + if (pc.fUseParticleCuts[ePDG]) { + if (cutModus == eCutCounterBinning) { + ParticleCut(eSim, ePDG, eCutCounterBinning); + } else if (track.pdgCode() < pc.fdParticleCuts[ePDG][eMin] || track.pdgCode() > pc.fdParticleCuts[ePDG][eMax]) { + // TBI 20250611 I need to generalize this, e.g. add support to process more that one PDG code (e.g. 2212 and -2212, etc.) + if (!ParticleCut(eSim, ePDG, cutModus)) { + return false; + } + } + } // ... @@ -4763,7 +10782,7 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) // 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) { + if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) { // ... @@ -4772,9 +10791,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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 track + 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 + // auto mcParticle = track.mcParticle(); // corresponding MC truth simulated particle // ... @@ -4809,9 +10828,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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 track + 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 + // auto mcParticle = track.mcParticle(); // corresponding MC truth simulated particle // ... @@ -4842,9 +10861,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.phi() < pc.fdParticleCuts[ePhi][eMin] || track.phi() > pc.fdParticleCuts[ePhi][eMax] || std::abs(track.phi() - pc.fdParticleCuts[ePhi][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, ePhi, cutModus)) { - return kFALSE; + return false; } } } @@ -4853,9 +10872,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.pt() < pc.fdParticleCuts[ePt][eMin] || track.pt() > pc.fdParticleCuts[ePt][eMax] || std::abs(track.pt() - pc.fdParticleCuts[ePt][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, ePt, cutModus)) { - return kFALSE; + return false; } } } @@ -4864,9 +10883,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) 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]) { + } else if (track.eta() < pc.fdParticleCuts[eEta][eMin] || track.eta() > pc.fdParticleCuts[eEta][eMax] || std::abs(track.eta() - pc.fdParticleCuts[eEta][eMax]) < tc.fFloatingPointPrecision) { if (!ParticleCut(eRec, eEta, cutModus)) { - return kFALSE; + return false; } } } @@ -4883,9 +10902,9 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) // 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_t dPhi = 0.; - Double_t dPt = 0.; - Double_t dEta = 0.; + 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) { @@ -4895,39 +10914,39 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) // Apply NUA on these kine variables: if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { - return kFALSE; + return false; } if (nua.fApplyNUAPDF[ePtNUAPDF] && !Accept(dPt, ePtNUAPDF)) { - return kFALSE; + return false; } if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { - return kFALSE; + 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 kFALSE; // TBI 20231107 re-think. I shouldn't probably get to this point, if MC truth info doesn't exist for this particle + 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(); + 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 kFALSE; + return false; } if (nua.fApplyNUAPDF[ePtNUAPDF] && !Accept(dPt, ePtNUAPDF)) { - return kFALSE; + return false; } if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { - return kFALSE; + 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) { + } // 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) { @@ -4938,64 +10957,69 @@ Bool_t ParticleCuts(T const& track, eCutModus cutModus) // Apply NUA on these kine variables: if (nua.fApplyNUAPDF[ePhiNUAPDF] && !Accept(dPhi, ePhiNUAPDF)) { - return kFALSE; + return false; } if (nua.fApplyNUAPDF[ePtNUAPDF] && !Accept(dPt, ePtNUAPDF)) { - return kFALSE; + return false; } if (nua.fApplyNUAPDF[eEtaNUAPDF] && !Accept(dEta, eEtaNUAPDF)) { - return kFALSE; + return false; } } // if constexpr (rs == eSim || rs == eSim_Run2 || rs == eSim_Run1) { } // if(nua.fApplyNUAPDF[ePhiNUAPDF] || nua.fApplyNUAPDF[ePtNUAPDF] || nua.fApplyNUAPDF[eEtaNUAPDF]) { - return kTRUE; + return true; -} // template Bool_t ParticleCuts(T const& track, eCutModus cutModus) +} // template bool ParticleCuts(T const& track, eCutModus cutModus) //============================================================ -Bool_t ParticleCut(Int_t rs, Int_t particleCut, 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: + case eCut: { if (tc.fVerboseForEachParticle) { LOGF(info, "\033[1;31mParticle didn't pass the cut: %s\033[0m", pc.fParticleCutName[particleCut].Data()); } - return kFALSE; + return false; break; - case eCutCounterBinning: + } + case eCutCounterBinning: { pc.fParticleCutCounterMap[rs]->Add(pc.fParticleCutCounterBinNumber[rs], particleCut); pc.fParticleCutCounterMapInverse[rs]->Add(particleCut, pc.fParticleCutCounterBinNumber[rs]); pc.fParticleCutCounterBinNumber[rs]++; // yes - return kTRUE; + return true; break; - case eCutCounterAbsolute: + } + case eCutCounterAbsolute: { pc.fParticleCutCounterHist[rs][eAbsolute]->Fill(pc.fParticleCutCounterMapInverse[rs]->GetValue(particleCut)); - return kTRUE; // yes, so that I can proceed with another cut in ParticleCuts + return true; // yes, so that I can proceed with another cut in ParticleCuts break; - case eCutCounterSequential: + } + case eCutCounterSequential: { pc.fParticleCutCounterHist[rs][eSequential]->Fill(pc.fParticleCutCounterMapInverse[rs]->GetValue(particleCut)); - return kFALSE; // yes, so that I bail out from ParticleCuts + return false; // yes, so that I bail out from ParticleCuts break; - default: + } + 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 kFALSE; // obsolete, but it suppresses the warning... + return false; // obsolete, but it suppresses the warning... -} // Bool_t ParticleCut(Int_t rs, Int_t particleCut, eCutModus cutModus) +} // bool ParticleCut(int rs, int particleCut, eCutModus cutModus) //============================================================ template -void FillParticleHistograms(T const& track, eBeforeAfter ba, Int_t weight = 1) +void FillParticleHistograms(T const& track, eBeforeAfter ba, int weight = 1) { // Fill all particle histograms for reconstructed and simulated data. @@ -5013,55 +11037,167 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, Int_t weight = 1) // 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 enties, I rarely need even GetMean(), and basically never GetMeanError(), + // 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } if (tc.fInsanityCheckForEachParticle) { - if (1 != TMath::Abs(weight)) { + if (1 != std::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) { + 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: - // From o2::aod::Tracks - !ph.fParticleHistograms[ePhi][eRec][ba] ? true : ph.fParticleHistograms[ePhi][eRec][ba]->Fill(track.phi(), weight); // 3 2 - !ph.fParticleHistograms[ePt][eRec][ba] ? true : ph.fParticleHistograms[ePt][eRec][ba]->Fill(track.pt(), weight); // 3 2 - !ph.fParticleHistograms[eEta][eRec][ba] ? true : ph.fParticleHistograms[eEta][eRec][ba]->Fill(track.eta(), weight); // 3 2 - !ph.fParticleHistograms[eCharge][eRec][ba] ? true : ph.fParticleHistograms[eCharge][eRec][ba]->Fill(track.sign(), weight); // 3 2 - - // From o2::aod::TracksExtra_001 - !ph.fParticleHistograms[etpcNClsFindable][eRec][ba] ? true : ph.fParticleHistograms[etpcNClsFindable][eRec][ba]->Fill(track.tpcNClsFindable(), weight); // 3 2 - !ph.fParticleHistograms[etpcNClsShared][eRec][ba] ? true : ph.fParticleHistograms[etpcNClsShared][eRec][ba]->Fill(track.tpcNClsShared(), weight); // 3 2 - !ph.fParticleHistograms[etpcNClsFound][eRec][ba] ? true : ph.fParticleHistograms[etpcNClsFound][eRec][ba]->Fill(track.tpcNClsFound(), weight); // 3 2 - !ph.fParticleHistograms[etpcNClsCrossedRows][eRec][ba] ? true : ph.fParticleHistograms[etpcNClsCrossedRows][eRec][ba]->Fill(track.tpcNClsCrossedRows(), weight); // 3 2 - !ph.fParticleHistograms[eitsNCls][eRec][ba] ? true : ph.fParticleHistograms[eitsNCls][eRec][ba]->Fill(track.itsNCls(), weight); // 3 2 - !ph.fParticleHistograms[eitsNClsInnerBarrel][eRec][ba] ? true : ph.fParticleHistograms[eitsNClsInnerBarrel][eRec][ba]->Fill(track.itsNClsInnerBarrel(), weight); // 3 2 - !ph.fParticleHistograms[etpcCrossedRowsOverFindableCls][eRec][ba] ? true : ph.fParticleHistograms[etpcCrossedRowsOverFindableCls][eRec][ba]->Fill(track.tpcCrossedRowsOverFindableCls(), weight); // 3 2 - !ph.fParticleHistograms[etpcFoundOverFindableCls][eRec][ba] ? true : ph.fParticleHistograms[etpcFoundOverFindableCls][eRec][ba]->Fill(track.tpcFoundOverFindableCls(), weight); // 3 2 - !ph.fParticleHistograms[etpcFractionSharedCls][eRec][ba] ? true : ph.fParticleHistograms[etpcFractionSharedCls][eRec][ba]->Fill(track.tpcFractionSharedCls(), weight); // 3 2 - - // 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); // 3 2 - !ph.fParticleHistograms[edcaZ][eRec][ba] ? true : ph.fParticleHistograms[edcaZ][eRec][ba]->Fill(track.dcaZ(), weight); // 3 2 + 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: - !ph.fParticleHistograms2D[ePhiPt][eRec][ba] ? true : ph.fParticleHistograms2D[ePhiPt][eRec][ba]->Fill(track.phi(), track.pt(), weight); // 3 2 - !ph.fParticleHistograms2D[ePhiEta][eRec][ba] ? true : ph.fParticleHistograms2D[ePhiEta][eRec][ba]->Fill(track.phi(), track.eta(), weight); + 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(), static_cast(track.sign()), ebye.fCentrality}; + 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(), static_cast(track.sign()), ebye.fCentrality}; + ph.fParticleSparseHistograms[eDWEta][eRec]->Fill(vector, weight); + } + } // if (ba == eAfter) { + // QA: if (qa.fFillQAParticleHistograms2D) { - !qa.fQAParticleHistograms2D[edcaXY_vs_Pt][eRec][ba] ? true : qa.fQAParticleHistograms2D[edcaXY_vs_Pt][eRec][ba]->Fill(track.dcaXY(), track.pt()); + !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 @@ -5072,19 +11208,76 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, Int_t weight = 1) LOGF(warning, " No MC particle for this track, skip..."); return; } - auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + auto mcParticle = track.mcParticle(); // corresponding MC truth simulated particle + // 1D: - !ph.fParticleHistograms[ePhi][eSim][ba] ? true : ph.fParticleHistograms[ePhi][eSim][ba]->Fill(mcparticle.phi(), weight); // 3 - !ph.fParticleHistograms[ePt][eSim][ba] ? true : ph.fParticleHistograms[ePt][eSim][ba]->Fill(mcparticle.pt(), weight); // 3 - !ph.fParticleHistograms[eEta][eSim][ba] ? true : ph.fParticleHistograms[eEta][eSim][ba]->Fill(mcparticle.eta(), weight); // 3 - // !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 + 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); + + // special treatment for charge, because there is no getter mcParticle.sign() + double charge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + charge = tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + } + !ph.fParticleHistograms[eCharge][eSim][ba] ? true : ph.fParticleHistograms[eCharge][eSim][ba]->Fill(charge); + !ph.fParticleHistograms[ePDG][eSim][ba] ? true : ph.fParticleHistograms[ePDG][eSim][ba]->Fill(mcParticle.pdgCode(), weight); + } + // 2D: - !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) { + !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 + + // special treatment for charge, because there is no getter mcParticle.sign() + double charge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + charge = tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + } + double vector[eDiffPhiWeights_N] = {mcParticle.phi(), mcParticle.pt(), mcParticle.eta(), charge, ebye.fCentralitySim, 0.}; + // TBI 20250611 I do nothing 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 + + // special treatment for charge, because there is no getter mcParticle.sign() + double charge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + charge = tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + } + double vector[eDiffPtWeights_N] = {mcParticle.pt(), charge, ebye.fCentralitySim}; + 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 + + // special treatment for charge, because there is no getter mcParticle.sign() + double charge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + charge = tc.fDatabasePDG->GetParticle(mcParticle.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + } + double vector[eDiffEtaWeights_N] = {mcParticle.eta(), charge, ebye.fCentralitySim}; + 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) { + } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { // ----------------------------------------------------------------------------- @@ -5093,20 +11286,32 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, Int_t weight = 1) // 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: - !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) { + !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); + + // special treatment for charge, because there is no getter mcParticle.sign() + double charge = -44.; // yes, never initialize charge to 0. + if (tc.fDatabasePDG && tc.fDatabasePDG->GetParticle(track.pdgCode())) { + // Yes, I have to check the 2nd condition, because e.g. for PDG code 1000010020 (deuteron), GetParticle(...) returns NULL + charge = tc.fDatabasePDG->GetParticle(track.pdgCode())->Charge() / 3.; // yes, divided by 3. Fundamental unit of charge is associated with quarks + } + !ph.fParticleHistograms[eCharge][eSim][ba] ? true : ph.fParticleHistograms[eCharge][eSim][ba]->Fill(charge); + !ph.fParticleHistograms[ePDG][eSim][ba] ? true : ph.fParticleHistograms[ePDG][eSim][ba]->Fill(track.pdgCode(), weight); + } // if(ph.fFillParticleHistograms) { + // 2D: - !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) { + !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) { + 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? @@ -5120,12 +11325,12 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, Int_t weight = 1) return; } - // auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + // auto mcParticle = track.mcParticle(); // corresponding MC truth simulated particle // ... } // if constexpr (rs == eRecAndSim) { - } // if constexpr (rs == eRec || rs == eRecAndSim) { + } // if constexpr (rs == eRec || rs == eRecAndSim) { // ----------------------------------------------------------------------------- @@ -5155,12 +11360,12 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, Int_t weight = 1) return; } - // auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + // 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) { + } // if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2 || rs == eRec_Run1 || rs == eRecAndSim_Run1) { // ----------------------------------------------------------------------------- @@ -5181,12 +11386,16 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, Int_t weight = 1) // 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: - !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); + 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: - !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) { + !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(...) @@ -5196,28 +11405,27 @@ void FillParticleHistograms(T const& track, eBeforeAfter ba, Int_t weight = 1) void CalculateCorrelations() { // Calculate analytically multiparticle correlations from Q-vectors. - // In this method, only isotropic correlations for which all harmonics are the - // same are evaluated. + // In this method, only isotropic correlations for which all harmonics are the same are evaluated. // a) Flush 'n' fill the generic Q-vectors; // b) Calculate correlations; // c) Flush the generic Q-vectors. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __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) { @@ -5227,10 +11435,10 @@ void CalculateCorrelations() 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 { @@ -5242,19 +11450,19 @@ void CalculateCorrelations() TArrayI* harmonics = new TArrayI(2); harmonics->SetAt(h, 0); harmonics->SetAt(-h, 1); - Double_t nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(twoC - nestedLoopValue) > 1.e-5) { + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (std::abs(nestedLoopValue) > 0. && std::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 CustomNestedLoops 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.fCalculateCustomNestedLoops) // 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.); + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && std::abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1)) > 0.) { + twoC /= std::pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1), 2.); } // integrated: @@ -5269,6 +11477,22 @@ 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) { @@ -5278,9 +11502,9 @@ void CalculateCorrelations() 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 { @@ -5295,19 +11519,19 @@ void CalculateCorrelations() harmonics->SetAt(h, 1); harmonics->SetAt(-h, 2); harmonics->SetAt(-h, 3); - Double_t nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(fourC - nestedLoopValue) > 1.e-5) { + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (std::abs(nestedLoopValue) > 0. && std::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 CustomNestedLoops 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.fCalculateCustomNestedLoops) // 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.); + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && std::abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1)) > 0.) { + fourC /= std::pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1), 4.); } // integrated: @@ -5322,6 +11546,22 @@ 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) { @@ -5331,9 +11571,9 @@ void CalculateCorrelations() 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 { @@ -5350,19 +11590,19 @@ void CalculateCorrelations() harmonics->SetAt(-h, 3); harmonics->SetAt(-h, 4); harmonics->SetAt(-h, 5); - Double_t nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(sixC - nestedLoopValue) > 1.e-5) { + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (std::abs(nestedLoopValue) > 0. && std::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 CustomNestedLoops 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.fCalculateCustomNestedLoops) // 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.); + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && std::abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1)) > 0.) { + sixC /= std::pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1), 6.); } // integrated: @@ -5377,6 +11617,22 @@ 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) { @@ -5386,9 +11642,9 @@ void CalculateCorrelations() 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 { @@ -5407,39 +11663,112 @@ void CalculateCorrelations() harmonics->SetAt(-h, 5); harmonics->SetAt(-h, 6); harmonics->SetAt(-h, 7); - Double_t nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); - if (TMath::Abs(nestedLoopValue) > 0. && TMath::Abs(eightC - nestedLoopValue) > 1.e-5) { + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (std::abs(nestedLoopValue) > 0. && std::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 CustomNestedLoops 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.fCalculateCustomNestedLoops) - // 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.); - } + // for on-the-fly and internal validation, rescale results with theoretical value: + if (iv.fUseInternalValidation && iv.fRescaleWithTheoreticalInput && iv.fInternalValidationVnPsin[eVn] && std::abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1)) > 0.) { + eightC /= std::pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h - 1), 8.); + } + + // integrated: + if (mupa.fCorrelationsPro[3][h - 1][AFO_INTEGRATED]) { + mupa.fCorrelationsPro[3][h - 1][AFO_INTEGRATED]->Fill(0.5, eightC, wEight); + } + // vs. multiplicity: + if (mupa.fCorrelationsPro[3][h - 1][AFO_MULTIPLICITY]) { + mupa.fCorrelationsPro[3][h - 1][AFO_MULTIPLICITY]->Fill(ebye.fSelectedTracks + 0.5, eightC, wEight); + } + // vs. centrality: + if (mupa.fCorrelationsPro[3][h - 1][AFO_CENTRALITY]) { + mupa.fCorrelationsPro[3][h - 1][AFO_CENTRALITY]->Fill(ebye.fCentrality, eightC, wEight); + } + // 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__); + } - // integrated: - if (mupa.fCorrelationsPro[3][h - 1][AFO_INTEGRATED]) { - mupa.fCorrelationsPro[3][h - 1][AFO_INTEGRATED]->Fill(0.5, eightC, wEight); + // *) ... + 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; } - // vs. multiplicity: - if (mupa.fCorrelationsPro[3][h - 1][AFO_MULTIPLICITY]) { - mupa.fCorrelationsPro[3][h - 1][AFO_MULTIPLICITY]->Fill(ebye.fSelectedTracks + 0.5, eightC, wEight); + case AFO_ETA: { + qvKine = ETAq; + // nBins = res.fResultsPro[AFO_ETA]->GetNbinsX(); // TBI 20241111 temporarily commented out just to suppress warnings + break; } - // vs. centrality: - if (mupa.fCorrelationsPro[3][h - 1][AFO_CENTRALITY]) { - mupa.fCorrelationsPro[3][h - 1][AFO_CENTRALITY]->Fill(ebye.fCentrality, eightC, wEight); + case AFO_CHARGE: { + qvKine = CHARGEq; + // 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; } - } // for(Int_t h=1;h<=gMaxHarmonic;h++) // harmonic + } // switch(AFO_variable) - // c) Flush the generic Q-vectors: - ResetQ(); + // *) 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__); + } -} // void CalculateCorrelations() + // ... + + 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) //============================================================ @@ -5452,31 +11781,31 @@ void CalculateTest0() // c) Flush the generic Q-vectors. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __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 @@ -5486,7 +11815,7 @@ 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, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); @@ -5605,16 +11934,16 @@ void CalculateTest0() // e-b-e sanity check: 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->CalculateCustomNestedLoops(harmonics); - if (!(TMath::Abs(nestedLoopValue) > 0.)) { - LOGF(info, " e-b-e check 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) > 1.e-5) { + double nestedLoopValue = this->CalculateCustomNestedLoops(harmonics); + if (!(std::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 (std::abs(nestedLoopValue) > 0. && std::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 CustomNestedLoops 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; @@ -5623,11 +11952,11 @@ void CalculateTest0() // 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_t i = 0; i < mo + 1; i++) { + 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.) { + if (std::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... @@ -5636,100 +11965,434 @@ void CalculateTest0() } // if(fUseInternalValidation && fRescaleWithTheoreticalInput) // Finally, fill: + + // 1D: // integrated: if (t0.fTest0Pro[mo][mi][AFO_INTEGRATED]) { t0.fTest0Pro[mo][mi][AFO_INTEGRATED]->Fill(0.5, correlation / weight, weight); } // 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); + } + + // ... + + // 2D: + // vs. centrality vs. vertex z position: + if (t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_VZ]) { + t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_VZ]->Fill(ebye.fCentrality, ebye.fVz, correlation / weight, weight); + } + + // ... + + // 3D: + + // ... + } // if(t0.fTest0Labels[mo][mi]) - } // for(Int_t mi=0;miGetNbinsX(); + break; + } + case AFO_ETA: { + qvKine = ETAq; + nBins = res.fResultsPro[AFO_ETA]->GetNbinsX(); + break; + } + case AFO_CHARGE: { + qvKine = CHARGEq; + nBins = res.fResultsPro[AFO_CHARGE]->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 bins for all kine variables: + 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] || std::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 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]; TBI 20250616 I cannot use this any longer, after I added one more dimension to qv.fqvector + } + } + + // *) Okay, let's do the differential calculus: + double correlation = 0.; + double weight = 0.; + int n[gMaxCorrelator] = {0}; // array holding harmonics + + 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 h = 0; h <= mo; h++) { + // cout<At(h)->GetName()).Atoi(); + delete oa; // yes, otherwise it's a memory leak + } + + if (qv.fqvectorEntries[qvKine][b] < mo + 1) { + continue; + } + + switch (mo + 1) // which order? yes, mo+1 + { + case 1: + correlation = One(n[0]).Re(); + weight = One(0).Re(); + break; + + case 2: + correlation = Two(n[0], n[1]).Re(); + weight = Two(0, 0).Re(); + break; + + case 3: + correlation = Three(n[0], n[1], n[2]).Re(); + weight = Three(0, 0, 0).Re(); + break; + + case 4: + correlation = Four(n[0], n[1], n[2], n[3]).Re(); + weight = Four(0, 0, 0, 0).Re(); + break; + + case 5: + correlation = Five(n[0], n[1], n[2], n[3], n[4]).Re(); + weight = Five(0, 0, 0, 0, 0).Re(); + break; + + case 6: + correlation = Six(n[0], n[1], n[2], n[3], n[4], n[5]).Re(); + weight = Six(0, 0, 0, 0, 0, 0).Re(); + break; + + case 7: + correlation = Seven(n[0], n[1], n[2], n[3], n[4], n[5], n[6]).Re(); + weight = Seven(0, 0, 0, 0, 0, 0, 0).Re(); + break; + + case 8: + correlation = Eight(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]).Re(); + weight = Eight(0, 0, 0, 0, 0, 0, 0, 0).Re(); + break; + + case 9: + correlation = Nine(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], n[8]).Re(); + weight = Nine(0, 0, 0, 0, 0, 0, 0, 0, 0).Re(); + break; + + case 10: + correlation = Ten(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], n[8], n[9]).Re(); + weight = Ten(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).Re(); + break; + + case 11: + correlation = Eleven(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], n[8], n[9], n[10]).Re(); + weight = Eleven(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).Re(); + break; + + case 12: + correlation = Twelve(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], n[8], n[9], n[10], n[11]).Re(); + weight = Twelve(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).Re(); + break; + + default: + 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 (nl.fCalculateKineCustomNestedLoops) { + TArrayI* harmonics = new TArrayI(mo + 1); + for (int i = 0; i < mo + 1; i++) { + harmonics->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 (!(std::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 (std::abs(nestedLoopValue) > 0. && std::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 (std::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: + + // 1D: + 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 + + // 2D: + if (t0.fCalculate2DTest0) { + + // vs. centrality vs. pt: + if (t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_PT] && AFO_variable == AFO_PT) { + t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_PT]->Fill(ebye.fCentrality, t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_PT]->GetYaxis()->GetBinCenter(b + 1), correlation / weight, weight); + } + + // vs. centrality vs. eta: + if (t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_ETA] && AFO_variable == AFO_ETA) { + t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_ETA]->Fill(ebye.fCentrality, t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_ETA]->GetYaxis()->GetBinCenter(b + 1), correlation / weight, weight); + } + + // vs. centrality vs. charge: + if (t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_CHARGE] && AFO_variable == AFO_CHARGE) { + t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_CHARGE]->Fill(ebye.fCentrality, t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_CHARGE]->GetYaxis()->GetBinCenter(b + 1), correlation / weight, weight); + } + + // ... + + } // if(t0.fCalculate2DTest0) + + } // if(fTest0Labels[mo][mi]) + } // for(int mi=0;mi(kineVarChoice), StringKineMap(kineVarChoice).Data(), Ndim); } - // *) ... - eqvectorKine qvKine = eqvectorKine_N; // which eqvectorKine enum - Int_t nBins = -1; + int nBins = -1; + + switch (Ndim) { + + case 1: { + eAsFunctionOf AFO_var = AfoKineMap1D(kineVarChoice); + if (res.fResultsPro[AFO_var]) { + nBins = res.fResultsPro[AFO_var]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it in the loop below. + if (tc.fVerbose) { + LOGF(info, "\033[1;31m%s nBins = %d, kineVarChoice = %d (%s), Ndim = %d \033[0m", __FUNCTION__, nBins, static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), Ndim); + } + } + + break; + } + + case 2: { + eAsFunctionOf2D AFO_var = AfoKineMap2D(kineVarChoice); + if (res.fResultsPro2D[AFO_var]) { + nBins = (res.fResultsPro2D[AFO_var]->GetNbinsX() + 2) * (res.fResultsPro2D[AFO_var]->GetNbinsY() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + if (tc.fVerbose) { + LOGF(info, "\033[1;31m%s nBins = %d, kineVarChoice = %d (%s), Ndim = %d \033[0m", __FUNCTION__, nBins, static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), Ndim); + } + } - 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(); + } + + case 3: { + eAsFunctionOf3D AFO_var = AfoKineMap3D(kineVarChoice); + if (res.fResultsPro3D[AFO_var]) { + nBins = (res.fResultsPro3D[AFO_var]->GetNbinsX() + 2) * (res.fResultsPro3D[AFO_var]->GetNbinsY() + 2) * (res.fResultsPro3D[AFO_var]->GetNbinsZ() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + if (tc.fVerbose) { + LOGF(info, "\033[1;31m%s nBins = %d, kineVarChoice = %d (%s), Ndim = %d \033[0m", __FUNCTION__, nBins, static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), Ndim); + } + } 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)); + } + + // ... + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : Ndim = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, Ndim); 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 stamenent \033[0m", __FUNCTION__, __LINE__); - } + } // switch (Ndim) + + // *) Uniform loop over linearized global bins for all kine variables: + for (int b = 0; b < nBins; b++) { // yes, "< nBins", not "<= nBins", because b runs over all regular bins + 2 (therefore, including underflow and overflow already) - // *) Uniform loop over bin for all kine variables: - for (Int_t b = 0; b < nBins; b++) { + if (tc.fVerbose) { // TBI 20250701 temporary check, remove eventually + LOGF(info, "\033[1;31m%s b = %d \033[0m", __FUNCTION__, b); + Trace(__FUNCTION__, __LINE__); + } + + // *) Check if this bin is overflow or underflow: + // Well, I already checked that when filling fqvector, if this global bin is overflow or underflow, qvector and number of entries shall be empty for that bin, so I am checking for that: + if (0 == qv.fqvectorEntries[kineVarChoice][b]) { + if (tc.fVerbose) { + LOGF(info, "\033[1;31m%s no entries in bin = %d, for kineVarChoice = %d (%s). Just skipping this bin (this is most likely underflow or overflow global bin)\033[0m", __FUNCTION__, b, static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data()); + } + continue; + } // *) 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[eSelectedTracks][eMin]) || (qv.fqVectorEntries[qvKine][b] > ec.fdEventCuts[eSelectedTracks][eMax])) { + /* TBI 20250603 not sure any longer if I can use this code: + // 1. if i do not use it, I allow possibility that correlations are calculated even when that makes no sense (two few particles for that correlators) + // 2. if I use it, I will not be able to get exactly the same result after rebinning (or ironing out some dimensions) as in integrated analysis + // => re-think + if ((qv.fqvectorEntries[kineVarChoice][b] < ec.fdEventCuts[eMultiplicity][eMin]) || (qv.fqvectorEntries[kineVarChoice][b] > ec.fdEventCuts[eMultiplicity][eMax] || std::abs(qv.fqvectorEntries[kineVarChoice][b] - ec.fdEventCuts[eMultiplicity][eMax]) < tc.fFloatingPointPrecision)) { if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eSelectedTracks cut in bin = %d, for qvKine = %d\033[0m", __FUNCTION__, b, static_cast(qvKine)); + LOGF(info, "\033[1;31m%s eMultiplicity cut in global bin = %d, for kineVarChoice = %d (%s), there are only %d selected particles in this bin\033[0m", __FUNCTION__, b, static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), qv.fqvectorEntries[kineVarChoice][b]); } } + */ // *) 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][b][h][wp]; + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { + qv.fQ[h][wp] = TComplex(qv.fqvector[kineVarChoice][b][h][wp].real(), qv.fqvector[kineVarChoice][b][h][wp].imag()); // TBI 20250601 check if there is a simpler way to initialize ROOT TComplex with C++ type 'complex' } } - // *) Okay, let's do the differential calculus: - Double_t correlation = 0.; - Double_t weight = 0.; - Int_t n[gMaxCorrelator] = {0}; // array holding harmonics + if (tc.fVerbose) { // TBI 20250701 temporary check, remove eventually + Trace(__FUNCTION__, __LINE__); + } + + // *) Okay, let's do transparently the differential calculus, whether it's 1D, 2D, 3D, ...: + 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][b] < mo + 1) { + if (qv.fqvectorEntries[kineVarChoice][b] < mo + 1) { continue; } @@ -5802,32 +12465,37 @@ void CalculateKineTest0(eAsFunctionOf AFO_variable) // *) e-b-e sanity check: if (nl.fCalculateKineCustomNestedLoops) { 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); } 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_t 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) > 1.e-5) { + double nestedLoopValue = this->CalculateKineCustomNestedLoops(harmonics, kineVarChoice, b); + PrintBinEdgesKine(kineVarChoice, b); + if (!(std::abs(nestedLoopValue) > 0.)) { + LOGF(info, " e-b-e check with CalculateKineCustomNestedLoops was NOT calculated for %d-p Test0 corr. %s, kineVarChoice (eqvectorKine) = %d (%s), bin = %d", mo + 1, t0.fTest0Labels[mo][mi]->Data(), static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), b); + } else if (std::abs(nestedLoopValue) > 0. && std::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, " e-b-e check with CalculateKineCustomNestedLoops is OK for %d-p Test0 corr. %s, bin = %d", mo + 1, t0.fTest0Labels[mo][mi]->Data(), b + 1); + LOGF(info, "\033[1;32m ebye check (differential) with CalculateKineCustomNestedLoops is OK for %d-p Test0 corr. %s, kineVarChoice (eqvectorKine) = %d (%s), bin = %d, nParticles in this bin = %d\033[0m", mo + 1, t0.fTest0Labels[mo][mi]->Data(), static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), b, qv.fqvectorEntries[kineVarChoice][b]); } delete harmonics; harmonics = NULL; } // if(nl.fCalculateKineCustomNestedLoops) + if (tc.fVerbose) { // TBI 20250701 temporary check, remove eventually + Trace(__FUNCTION__, __LINE__); + } + // 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_t i = 0; i < mo + 1; i++) { + 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.) { + if (std::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... @@ -5835,50 +12503,540 @@ void CalculateKineTest0(eAsFunctionOf AFO_variable) 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__); - } + if (tc.fVerbose) { // TBI 20250701 temporary check, remove eventually + Trace(__FUNCTION__, __LINE__); + } + + // 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 kineVarChoice = %d \033[0m\n", static_cast(kineVarChoice)); + 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); + + switch (Ndim) { + + case 1: { + eAsFunctionOf AFO_var = AfoKineMap1D(kineVarChoice); + LOGF(info, "\n\033[1;33m t0.fTest0Pro[mo][mi][AFO_variable]->GetTitle() = %s \033[0m\n", t0.fTest0Pro[mo][mi][AFO_var]->GetTitle()); + LOGF(info, "\n\033[1;33m [mo][mi][AFO_variable] = [%d][%d][%d] \033[0m\n", mo, mi, static_cast(AFO_var)); + break; + } + + case 2: { + eAsFunctionOf2D AFO_var = AfoKineMap2D(kineVarChoice); + LOGF(info, "\n\033[1;33m t0.fTest0Pro2D[mo][mi][AFO_variable]->GetTitle() = %s \033[0m\n", t0.fTest0Pro2D[mo][mi][AFO_var]->GetTitle()); + LOGF(info, "\n\033[1;33m [mo][mi][AFO_variable] = [%d][%d][%d] \033[0m\n", mo, mi, static_cast(AFO_var)); + break; + } + + case 3: { + eAsFunctionOf3D AFO_var = AfoKineMap3D(kineVarChoice); + LOGF(info, "\n\033[1;33m t0.fTest0Pro3D[mo][mi][AFO_variable]->GetTitle() = %s \033[0m\n", t0.fTest0Pro3D[mo][mi][AFO_var]->GetTitle()); + LOGF(info, "\n\033[1;33m [mo][mi][AFO_variable] = [%d][%d][%d] \033[0m\n", mo, mi, static_cast(AFO_var)); + break; + } + + // ... + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : Ndim = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, Ndim); + break; + } + + } // switch (Ndim) + + LOGF(info, "\n\033[1;33m ebye.fSelectedTracks = %d \033[0m\n", ebye.fSelectedTracks); + LOGF(info, "\n\033[1;33m qv.fqvectorEntries[kineVarChoice][b] = %d \033[0m\n", qv.fqvectorEntries[kineVarChoice][b]); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Finally, fill: + switch (Ndim) { + + case 1: { + + // *) cases for which 1D vs. pt calculus is needed: + if (kineVarChoice == PTq) { + // **) vs. pt: + if (t0.fTest0Pro[mo][mi][AFO_PT]) { + t0.fTest0Pro[mo][mi][AFO_PT]->Fill(t0.fTest0Pro[mo][mi][AFO_PT]->GetXaxis()->GetBinCenter(b), correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + // **) vs. centrality vs. pt: + if (t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_PT]) { + t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_PT]->Fill(ebye.fCentrality, t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_PT]->GetYaxis()->GetBinCenter(b), correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + // **) vs. centrality vs. pt vs. vz: + if (t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_VZ]) { + t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_VZ]->Fill(ebye.fCentrality, t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_VZ]->GetYaxis()->GetBinCenter(b), ebye.fVz, correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + + // ... + + } // if (kineVarChoice == PTq) { + + // *) cases for which 1D vs. eta calculus is needed: + if (kineVarChoice == ETAq) { + // **) vs. eta: + if (t0.fTest0Pro[mo][mi][AFO_ETA]) { + t0.fTest0Pro[mo][mi][AFO_ETA]->Fill(t0.fTest0Pro[mo][mi][AFO_ETA]->GetXaxis()->GetBinCenter(b), correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + // **) vs. centrality vs. eta: + if (t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_ETA]) { + t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_ETA]->Fill(ebye.fCentrality, t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_ETA]->GetYaxis()->GetBinCenter(b), correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + // **) vs. centrality vs. eta vs. vz: + if (t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_ETA_VZ]) { + t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_ETA_VZ]->Fill(ebye.fCentrality, t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_ETA_VZ]->GetYaxis()->GetBinCenter(b), ebye.fVz, correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + + // ... + + } // if (kineVarChoice == ETAq) { + + // *) cases for which 1D vs. charge calculus is needed: + if (kineVarChoice == CHARGEq) { + // **) vs. charge: + if (t0.fTest0Pro[mo][mi][AFO_CHARGE]) { + t0.fTest0Pro[mo][mi][AFO_CHARGE]->Fill(t0.fTest0Pro[mo][mi][AFO_CHARGE]->GetXaxis()->GetBinCenter(b), correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + // **) vs. centrality vs. charge: + if (t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_CHARGE]) { + t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_CHARGE]->Fill(ebye.fCentrality, t0.fTest0Pro2D[mo][mi][AFO_CENTRALITY_CHARGE]->GetYaxis()->GetBinCenter(b), correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + + // **) vs. centrality vs. vz vs. charge: + if (t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_VZ_CHARGE]) { + t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_VZ_CHARGE]->Fill(ebye.fCentrality, ebye.fVz, t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_VZ_CHARGE]->GetZaxis()->GetBinCenter(b), correlation / weight, weight); // only for 1D kine case, I can use direcly b, because "linearized global bin" is the same as ordinary bin + } + + // ... + + } // if (kineVarChoice == CHARGEq) { + + // ... + + break; + } + + case 2: { + + // *) cases for which 2D vs. (pt,eta) calculus is needed: + if (kineVarChoice == PT_ETAq) { + + // transfer global bin b into (binX, binY, binZ): + int binX = -1; + int binY = -1; + int binZ = -1; // dummy for 2D case + t0.fTest0Pro2D[mo][mi][AFO_PT_ETA]->GetBinXYZ(b, binX, binY, binZ); + + // **) vs. pt vs. eta: + if (t0.fTest0Pro2D[mo][mi][AFO_PT_ETA]) { + t0.fTest0Pro2D[mo][mi][AFO_PT_ETA]->Fill(t0.fTest0Pro2D[mo][mi][AFO_PT_ETA]->GetXaxis()->GetBinCenter(binX), t0.fTest0Pro2D[mo][mi][AFO_PT_ETA]->GetYaxis()->GetBinCenter(binY), correlation / weight, weight); + } + + // **) vs. centrality vs. pt vs. eta: + if (t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_ETA]) { + // Remark: I have to re-use binX, binY, binZ obtained from t0.fTest0Pro2D[mo][mi][AFO_PT_ETA] above, because I am looping for "case 2:" here over global bin number of + // t0.fTest0Pro2D[mo][mi][AFO_PT_ETA], not of t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_ETA] + t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_ETA]->Fill(ebye.fCentrality, t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_ETA]->GetYaxis()->GetBinCenter(binX), t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_ETA]->GetZaxis()->GetBinCenter(binY), correlation / weight, weight); // yes, y-axis of this histogram is x-axis of t0.fTest0Pro2D[mo][mi][AFO_PT_ETA], and similarly z-axis here is y-axis of t0.fTest0Pro2D[mo][mi][AFO_PT_ETA] + } + + // ... + + } // if (kineVarChoice == PT_ETAq) + + // *) cases for which 2D vs. (pt,charge) calculus is needed: + if (kineVarChoice == PT_CHARGEq) { + + // transfer global bin b into (binX, binY, binZ): + int binX = -1; + int binY = -1; + int binZ = -1; // dummy for 2D case + t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE]->GetBinXYZ(b, binX, binY, binZ); + + // **) vs. pt vs. charge: + if (t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE]) { + t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE]->Fill(t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE]->GetXaxis()->GetBinCenter(binX), t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE]->GetYaxis()->GetBinCenter(binY), correlation / weight, weight); + } + // **) vs. centrality vs. pt vs. charge: + if (t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_CHARGE]) { + // Remark: I have to re-use binX, binY, binZ obtained from t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE] above, because I am looping for "case 2:" here over global bin number of + // t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE], not of t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_CHARGE] + t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_CHARGE]->Fill(ebye.fCentrality, t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_CHARGE]->GetYaxis()->GetBinCenter(binX), t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_PT_CHARGE]->GetZaxis()->GetBinCenter(binY), correlation / weight, weight); // yes, y-axis of this histogram is x-axis of t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE], and similarly z-axis here is y-axis of t0.fTest0Pro2D[mo][mi][AFO_PT_CHARGE] + } + + // ... + + } // if (kineVarChoice == PT_CHARGEq) + + // *) cases for which 2D vs. (eta,charge) calculus is needed: + if (kineVarChoice == ETA_CHARGEq) { + + // transfer global bin b into (binX, binY, binZ): + int binX = -1; + int binY = -1; + int binZ = -1; // dummy for 2D case + t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE]->GetBinXYZ(b, binX, binY, binZ); + + // **) vs. eta vs. charge: + if (t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE]) { + t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE]->Fill(t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE]->GetXaxis()->GetBinCenter(binX), t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE]->GetYaxis()->GetBinCenter(binY), correlation / weight, weight); + } + // **) vs. centrality vs. eta vs. charge: + if (t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_ETA_CHARGE]) { + // Remark: I have to re-use binX, binY, binZ obtained from t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE] above, because I am looping for "case 2:" here over global bin number of + // t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE], not of t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_ETA_CHARGE] + t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_ETA_CHARGE]->Fill(ebye.fCentrality, t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_ETA_CHARGE]->GetYaxis()->GetBinCenter(binX), t0.fTest0Pro3D[mo][mi][AFO_CENTRALITY_ETA_CHARGE]->GetZaxis()->GetBinCenter(binY), correlation / weight, weight); // yes, y-axis of this histogram is x-axis of t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE], and similarly z-axis here is y-axis of t0.fTest0Pro2D[mo][mi][AFO_ETA_CHARGE] + } + + // ... + + } // if (kineVarChoice == ETA_CHARGEq) + + // ... + + break; + } + + case 3: { + + // *) cases for which 3D vs. (pt,eta,charge) calculus is needed: + if (kineVarChoice == PT_ETA_CHARGEq) { + + // transfer global bin b into (binX, binY, binZ): + int binX = -1; + int binY = -1; + int binZ = -1; + t0.fTest0Pro3D[mo][mi][AFO_PT_ETA_CHARGE]->GetBinXYZ(b, binX, binY, binZ); + + // **) vs. pt vs. eta vs. charge: + if (t0.fTest0Pro3D[mo][mi][AFO_PT_ETA_CHARGE]) { + t0.fTest0Pro3D[mo][mi][AFO_PT_ETA_CHARGE]->Fill(t0.fTest0Pro3D[mo][mi][AFO_PT_ETA_CHARGE]->GetXaxis()->GetBinCenter(binX), + t0.fTest0Pro3D[mo][mi][AFO_PT_ETA_CHARGE]->GetYaxis()->GetBinCenter(binY), + t0.fTest0Pro3D[mo][mi][AFO_PT_ETA_CHARGE]->GetZaxis()->GetBinCenter(binZ), + correlation / weight, weight); + } + } + + // ... + + break; + } + + // ... + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : Ndim = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, Ndim); + break; + } + + } // switch (Ndim) + + } // if(fTest0Labels[mo][mi]) + } // for(int mi=0;mi kineVarChoice (eqvectorKine) = %d, global (ordinary) bin %d <=> (%f, %f)", static_cast(kineVarChoice), bin, res.fResultsPro[AfoKineMap1D(kineVarChoice)]->GetBinLowEdge(bin), res.fResultsPro[AfoKineMap1D(kineVarChoice)]->GetBinLowEdge(bin + 1)); + + break; + } + + // 2D: + case PT_ETAq: + case PT_CHARGEq: + case ETA_CHARGEq: { + + // transfer global bin b into (binX, binY, binZ): + int binX = -1; + int binY = -1; + int binZ = -1; // dummy for 2D case + res.fResultsPro2D[AfoKineMap2D(kineVarChoice)]->GetBinXYZ(bin, binX, binY, binZ); + + LOGF(info, " => kineVarChoice (eqvectorKine) = %d, global bin %d = (%d, %d) <=> (%f, %f) x (%f, %f)", static_cast(kineVarChoice), bin, binX, binY, res.fResultsPro2D[AfoKineMap2D(kineVarChoice)]->GetXaxis()->GetBinLowEdge(binX), res.fResultsPro2D[AfoKineMap2D(kineVarChoice)]->GetXaxis()->GetBinLowEdge(binX + 1), res.fResultsPro2D[AfoKineMap2D(kineVarChoice)]->GetYaxis()->GetBinLowEdge(binY), res.fResultsPro2D[AfoKineMap2D(kineVarChoice)]->GetYaxis()->GetBinLowEdge(binY + 1)); + + break; + } + + // 3D: + case PT_ETA_CHARGEq: { + + // transfer global bin b into (binX, binY, binZ): + int binX = -1; + int binY = -1; + int binZ = -1; + res.fResultsPro3D[AfoKineMap3D(kineVarChoice)]->GetBinXYZ(bin, binX, binY, binZ); + + LOGF(info, " => kineVarChoice (eqvectorKine) = %d, global bin %d = (%d, %d, %d) <=> (%f, %f) x (%f, %f) x (%f, %f)", static_cast(kineVarChoice), bin, binX, binY, binZ, res.fResultsPro3D[AfoKineMap3D(kineVarChoice)]->GetXaxis()->GetBinLowEdge(binX), res.fResultsPro3D[AfoKineMap3D(kineVarChoice)]->GetXaxis()->GetBinLowEdge(binX + 1), res.fResultsPro3D[AfoKineMap3D(kineVarChoice)]->GetYaxis()->GetBinLowEdge(binY), res.fResultsPro3D[AfoKineMap3D(kineVarChoice)]->GetYaxis()->GetBinLowEdge(binY + 1), res.fResultsPro3D[AfoKineMap3D(kineVarChoice)]->GetZaxis()->GetBinLowEdge(binZ), res.fResultsPro3D[AfoKineMap3D(kineVarChoice)]->GetZaxis()->GetBinLowEdge(binZ + 1)); + + break; + } + + 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(AFO_variable) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void PrintBinEdgesKine() + +//============================================================ + +void CalculateEtaSeparations() +{ + // Calculate correlations with pseudorapidity separations. + + // Remark: this is a port and generalization of void AliFlowAnalysisWithMultiparticleCorrelations::CalculateEtaGaps(AliFlowEventSimple *anEvent) + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // Calculate 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][h][e].Rho() > 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] && std::abs(iv.fInternalValidationVnPsin[eVn]->GetAt(h)) > 0.) { + correlation /= std::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 CalculateKineEtaSeparationsNdim(eqvectorKine kineVarChoice, int Ndim) +{ + // Calculate analytically N-dimensional kine eta separations from differential q-vectors. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // This is a replacement for the legacy function CalculateKineEtaSeparations(...), which is as of 20250620 deemed obsolete. + // Remember that here I changed design, and pass enum eqvectorKine as an argument, not any longer enum eAsFunctionOf. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + int nBins = -1; + + switch (Ndim) { + + case 1: { + eAsFunctionOf AFO_var = AfoKineMap1D(kineVarChoice); + if (res.fResultsPro[AFO_var]) { + nBins = res.fResultsPro[AFO_var]->GetNbinsX() + 2; // + 2 means that I take into account overflow and underflow, then skip it in the loop below. + } + + break; + } + + case 2: { + eAsFunctionOf2D AFO_var = AfoKineMap2D(kineVarChoice); + if (res.fResultsPro2D[AFO_var]) { + nBins = (res.fResultsPro2D[AFO_var]->GetNbinsX() + 2) * (res.fResultsPro2D[AFO_var]->GetNbinsY() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + + break; + } + + case 3: { + eAsFunctionOf3D AFO_var = AfoKineMap3D(kineVarChoice); + if (res.fResultsPro3D[AFO_var]) { + nBins = (res.fResultsPro3D[AFO_var]->GetNbinsX() + 2) * (res.fResultsPro3D[AFO_var]->GetNbinsY() + 2) * (res.fResultsPro3D[AFO_var]->GetNbinsZ() + 2); // + 2 means that I take into account overflow and underflow, then skip it in the loop below + } + break; + } + + // ... + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : Ndim = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, Ndim); + break; + } + + } // switch (Ndim) + + // *) Uniform loop over linearized global bins for all kine variables: + for (int b = 0; b < nBins; b++) { // yes, "< nBins", not "<= nBins", because b runs over all regular bins + 2 (therefore, including underflow and overflow already) + + // 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] || std::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 (!(std::abs(qv.fqabVector[0][kineVarChoice][b][h][e]) > 0. && std::abs(qv.fqabVector[1][kineVarChoice][b][h][e]) > 0.)) { + continue; + } + if (!(qv.fmab[0][kineVarChoice][b][e] > 0. && qv.fmab[1][kineVarChoice][b][e] > 0.)) { + continue; + } - // Finally, fill: - 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 + // calculate correlation and weights with particular eta separation: + correlation = (qv.fqabVector[0][kineVarChoice][b][h][e] * std::conj(qv.fqabVector[1][kineVarChoice][b][h][e])).real(); + // Remark: this was the legacy code, just in case I would still need it: + // correlation = TComplex(qv.fqabVector[0][kineVarChoice][b][h][e] * TComplex::Conjugate(qv.fqabVector[1][kineVarChoice][b][h][e])).Re(); + weight = qv.fmab[0][kineVarChoice][b][e] * qv.fmab[1][kineVarChoice][b][e]; - } // if(fTest0Labels[mo][mi]) - } // for(Int_t mi=0;miGetAt(h)) > 0.) { + correlation /= std::pow(iv.fInternalValidationVnPsin[eVn]->GetAt(h), 2.); + } + + // finally, fill 1D case: + if (es.fEtaSeparationsPro[h][e][AfoKineMap1D(kineVarChoice)]) { + es.fEtaSeparationsPro[h][e][AfoKineMap1D(kineVarChoice)]->Fill(es.fEtaSeparationsPro[h][e][AfoKineMap1D(kineVarChoice)]->GetXaxis()->GetBinCenter(b), correlation / weight, weight); + } + + // TBI 20250620 I need to add support eventually also for 2D and 3D cases. + } + } + } // for (int b = 0; b < nBins; b++) + + // *) Quick insanity check: I shall never have any entry in underflow (bin = 0) or overflow (bin = nBins -1) in es.fEtaSeparationsPro, otherwise some cuts were bypassed: + if (tc.fDoAdditionalInsanityChecks) { + for (int h = 0; h < gMaxHarmonic; h++) { + for (int e = 0; e < gMaxNumberEtaSeparations; e++) { + if (es.fEtaSeparationsPro[h][e][AfoKineMap1D(kineVarChoice)] && std::abs(es.fEtaSeparationsPro[h][e][AfoKineMap1D(kineVarChoice)]->GetBinContent(0)) > 0.) { + LOGF(fatal, "\033[1;31m%s at line %d : underflow is not empty \033[0m", __FUNCTION__, __LINE__); + } + if (es.fEtaSeparationsPro[h][e][AfoKineMap1D(kineVarChoice)] && std::abs(es.fEtaSeparationsPro[h][e][AfoKineMap1D(kineVarChoice)]->GetBinContent(nBins - 1)) > 0.) { + LOGF(fatal, "\033[1;31m%s at line %d : overflow is not empty \033[0m", __FUNCTION__, __LINE__); + } + } + } + } // if (tc.fDoAdditionalInsanityChecks) - } // for(Int_t b=0;bGetAt(particleIndex - 1)) > 0.)) { + if (!(std::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 @@ -5895,9 +13053,9 @@ void FillNestedLoopsContainers(const Int_t& particleIndex, const Double_t& dPhi, // 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_t wPhi = 1.; - Double_t wPt = 1.; - Double_t wEta = 1.; + double wPhi = 1.; + double wPt = 1.; + double wEta = 1.; if (pw.fUseWeights[wPHI]) { wPhi = Weight(dPhi, wPHI); } @@ -5910,7 +13068,11 @@ void FillNestedLoopsContainers(const Int_t& particleIndex, const Double_t& dPhi, nl.ftaNestedLoops[1]->AddAt(wPhi * wPt * wEta, particleIndex); // remember that the 2nd argument here must start from 0 } -} // void FillNestedLoopsContainers(const Int_t& particleIndex, const Double_t& dPhi, const Double_t& dPt, const Double_t& dEta) + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void FillNestedLoopsContainers(const int& particleIndex, const double& dPhi, const double& dPt, const double& dEta) //============================================================ @@ -5924,24 +13086,11 @@ void CalculateNestedLoops() // d) 8-particle nested loops. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } LOGF(info, " ebye.fSelectedTracks = %d", ebye.fSelectedTracks); - Int_t nParticles = ebye.fSelectedTracks; - - /* TBI 20220823 enable the lines below eventually - if(fUseFixedNumberOfRandomlySelectedTracks) - { - nParticles = 0; - for(Int_t i=0;iGetSize();i++) - { - if(TMath::Abs(ftaNestedLoops[0]->GetAt(i)) > 0. && - TMath::Abs(ftaNestedLoops[1]->GetAt(i)) > 0.){nParticles++;} - } - } - cout<<"nParticles = "<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]) { nl.fNestedLoopsPro[0][h][AFO_INTEGRATED]->Fill( - 0.5, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); + 0.5, std::cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); } // 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, std::cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); } // fill cos, 2p, vs. centrality: if (nl.fNestedLoopsPro[0][h][AFO_CENTRALITY]) { nl.fNestedLoopsPro[0][h][AFO_CENTRALITY]->Fill( - ebye.fCentrality, TMath::Cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); + ebye.fCentrality, std::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, std::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, std::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, std::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, std::cos((h + 1.) * (dPhi1 - dPhi2)), dW1 * dW2); + } + } // for(int h=1; h<=6; h++) - } // for(int i2=0; i2GetAt(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]) { - nl.fNestedLoopsPro[1][h][AFO_INTEGRATED]->Fill(0.5, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); + nl.fNestedLoopsPro[1][h][AFO_INTEGRATED]->Fill(0.5, std::cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); } // 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, std::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); + nl.fNestedLoopsPro[1][h][AFO_CENTRALITY]->Fill(ebye.fCentrality, std::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, std::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, std::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, std::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, std::cos((h + 1.) * (dPhi1 + dPhi2 - dPhi3 - dPhi4)), dW1 * dW2 * dW3 * dW4); } } // for(int h=0; hGetAt(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]) { - nl.fNestedLoopsPro[2][h][AFO_INTEGRATED]->Fill(0.5, TMath::Cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); + nl.fNestedLoopsPro[2][h][AFO_INTEGRATED]->Fill(0.5, std::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_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, std::cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); } - // fill cos, 6p, all harmonics, vs. M: + // 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); + nl.fNestedLoopsPro[2][h][AFO_CENTRALITY]->Fill(ebye.fCentrality, std::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, std::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, std::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, std::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, std::cos((h + 1.) * (dPhi1 + dPhi2 + dPhi3 - dPhi4 - dPhi5 - dPhi6)), dW1 * dW2 * dW3 * dW4 * dW5 * dW6); } } // for(int h=0; hGetAt(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]) { - nl.fNestedLoopsPro[3][h][AFO_INTEGRATED]->Fill(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_INTEGRATED]->Fill(0.5, std::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: 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, std::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); + nl.fNestedLoopsPro[3][h][AFO_CENTRALITY]->Fill(ebye.fCentrality, std::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, std::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, std::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, std::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, std::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, "\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 o = 0; o < 4; o++) { + LOGF(info, "\033[1;32m ==== <<%d>>-particle correlations ====\033[0m", 2 * (o + 1)); + 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); + } + if (nl.fNestedLoopsPro[o][h][v]) { + valueNL = nl.fNestedLoopsPro[o][h][v]->GetBinContent(b); + } + if (std::abs(valueQV) > 0. && std::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 (std::abs(valueQV - valueNL) > tc.fFloatingPointPrecision) { + LOGF(info, "\n\033[1;33m[%d][%d][%d] \033[0m\n", o, h, v); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } // if(std::abs(valueQV)>0. && std::abs(valueNL)>0.) + } // for(int b=1;b<=nBinsQV;b++) + } // for (int h = 0; h < gMaxHarmonic; h++) { + LOGF(info, ""); // new line + } // for(int o=0;o<4;o++) + } // for (int v = 0; v < 3; v++) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void ComparisonNestedLoopsVsCorrelations() + +//============================================================ + +TComplex Q(int n, int wp) +{ + // Using the fact that Q{-n,p} = Q{n,p}^*. + + if (n >= 0) { + return qv.fQ[n][wp]; + } + return TComplex::Conjugate(qv.fQ[-n][wp]); + +} // TComplex FlowWithMultiparticleCorrelationsTask::Q(int n, int wp) + +//============================================================ + +TComplex One(int n1) +{ + // Generic expression . + + TComplex one = Q(n1, 1); + + return one; + +} // TComplex FlowWithMultiparticleCorrelationsTask::One(int n1) + +//============================================================ + +TComplex Two(int n1, int n2) +{ + // Generic two-particle correlation . + + TComplex two = Q(n1, 1) * Q(n2, 1) - Q(n1 + n2, 2); + + return two; + +} // TComplex FlowWithMultiparticleCorrelationsTask::Two(int n1, int n2) + +//============================================================ + +TComplex Three(int n1, int n2, int n3) +{ + // Generic three-particle correlation . + + TComplex three = Q(n1, 1) * Q(n2, 1) * Q(n3, 1) - Q(n1 + n2, 2) * Q(n3, 1) - + Q(n2, 1) * Q(n1 + n3, 2) - Q(n1, 1) * Q(n2 + n3, 2) + + 2. * Q(n1 + n2 + n3, 3); + + return three; + +} // TComplex Three(int n1, int n2, int n3) + +//============================================================ + +TComplex Four(int n1, int n2, int n3, int n4) +{ + // Generic four-particle correlation + // . + + TComplex four = + 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); + + return four; + +} // TComplex Four(int n1, int n2, int n3, int n4) + +//============================================================ + +TComplex Five(int n1, int n2, int n3, int n4, int n5) +{ + // Generic five-particle correlation . + + TComplex five = Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) - Q(n1 + n2, 2) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) - Q(n2, 1) * Q(n1 + n3, 2) * Q(n4, 1) * Q(n5, 1) - Q(n1, 1) * Q(n2 + n3, 2) * Q(n4, 1) * Q(n5, 1) + 2. * Q(n1 + n2 + n3, 3) * Q(n4, 1) * Q(n5, 1) - Q(n2, 1) * Q(n3, 1) * Q(n1 + n4, 2) * Q(n5, 1) + Q(n2 + n3, 2) * Q(n1 + n4, 2) * Q(n5, 1) - Q(n1, 1) * Q(n3, 1) * Q(n2 + n4, 2) * Q(n5, 1) + Q(n1 + n3, 2) * Q(n2 + n4, 2) * Q(n5, 1) + 2. * Q(n3, 1) * Q(n1 + n2 + n4, 3) * Q(n5, 1) - Q(n1, 1) * Q(n2, 1) * Q(n3 + n4, 2) * Q(n5, 1) + Q(n1 + n2, 2) * Q(n3 + n4, 2) * Q(n5, 1) + 2. * Q(n2, 1) * Q(n1 + n3 + n4, 3) * Q(n5, 1) + 2. * Q(n1, 1) * Q(n2 + n3 + n4, 3) * Q(n5, 1) - 6. * Q(n1 + n2 + n3 + n4, 4) * Q(n5, 1) - Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n1 + n5, 2) + Q(n2 + n3, 2) * Q(n4, 1) * Q(n1 + n5, 2) + Q(n3, 1) * Q(n2 + n4, 2) * Q(n1 + n5, 2) + Q(n2, 1) * Q(n3 + n4, 2) * Q(n1 + n5, 2) - 2. * Q(n2 + n3 + n4, 3) * Q(n1 + n5, 2) - Q(n1, 1) * Q(n3, 1) * Q(n4, 1) * Q(n2 + n5, 2) + Q(n1 + n3, 2) * Q(n4, 1) * Q(n2 + n5, 2) + Q(n3, 1) * Q(n1 + n4, 2) * Q(n2 + n5, 2) + Q(n1, 1) * Q(n3 + n4, 2) * Q(n2 + n5, 2) - 2. * Q(n1 + n3 + n4, 3) * Q(n2 + n5, 2) + 2. * Q(n3, 1) * Q(n4, 1) * Q(n1 + n2 + n5, 3) - 2. * Q(n3 + n4, 2) * Q(n1 + n2 + n5, 3) - Q(n1, 1) * Q(n2, 1) * Q(n4, 1) * Q(n3 + n5, 2) + Q(n1 + n2, 2) * Q(n4, 1) * Q(n3 + n5, 2) + Q(n2, 1) * Q(n1 + n4, 2) * Q(n3 + n5, 2) + Q(n1, 1) * Q(n2 + n4, 2) * Q(n3 + n5, 2) - 2. * Q(n1 + n2 + n4, 3) * Q(n3 + n5, 2) + 2. * Q(n2, 1) * Q(n4, 1) * Q(n1 + n3 + n5, 3) - 2. * Q(n2 + n4, 2) * Q(n1 + n3 + n5, 3) + 2. * Q(n1, 1) * Q(n4, 1) * Q(n2 + n3 + n5, 3) - 2. * Q(n1 + n4, 2) * Q(n2 + n3 + n5, 3) - 6. * Q(n4, 1) * Q(n1 + n2 + n3 + n5, 4) - Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4 + n5, 2) + Q(n1 + n2, 2) * Q(n3, 1) * Q(n4 + n5, 2) + Q(n2, 1) * Q(n1 + n3, 2) * Q(n4 + n5, 2) + Q(n1, 1) * Q(n2 + n3, 2) * Q(n4 + n5, 2) - 2. * Q(n1 + n2 + n3, 3) * Q(n4 + n5, 2) + 2. * Q(n2, 1) * Q(n3, 1) * Q(n1 + n4 + n5, 3) - 2. * Q(n2 + n3, 2) * Q(n1 + n4 + n5, 3) + 2. * Q(n1, 1) * Q(n3, 1) * Q(n2 + n4 + n5, 3) - 2. * Q(n1 + n3, 2) * Q(n2 + n4 + n5, 3) - 6. * Q(n3, 1) * Q(n1 + n2 + n4 + n5, 4) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n3 + n4 + n5, 3) - 2. * Q(n1 + n2, 2) * Q(n3 + n4 + n5, 3) - 6. * Q(n2, 1) * Q(n1 + n3 + n4 + n5, 4) - 6. * Q(n1, 1) * Q(n2 + n3 + n4 + n5, 4) + 24. * Q(n1 + n2 + n3 + n4 + n5, 5); + + return five; + +} // TComplex Five(int n1, int n2, int n3, int n4, int n5) + +//============================================================ + +TComplex Six(int n1, int n2, int n3, int n4, int n5, int n6) +{ + // Generic six-particle correlation . + + TComplex six = Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) - Q(n1 + n2, 2) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) - Q(n2, 1) * Q(n1 + n3, 2) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) - Q(n1, 1) * Q(n2 + n3, 2) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) + 2. * Q(n1 + n2 + n3, 3) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) - Q(n2, 1) * Q(n3, 1) * Q(n1 + n4, 2) * Q(n5, 1) * Q(n6, 1) + Q(n2 + n3, 2) * Q(n1 + n4, 2) * Q(n5, 1) * Q(n6, 1) - Q(n1, 1) * Q(n3, 1) * Q(n2 + n4, 2) * Q(n5, 1) * Q(n6, 1) + Q(n1 + n3, 2) * Q(n2 + n4, 2) * Q(n5, 1) * Q(n6, 1) + 2. * Q(n3, 1) * Q(n1 + n2 + n4, 3) * Q(n5, 1) * Q(n6, 1) - Q(n1, 1) * Q(n2, 1) * Q(n3 + n4, 2) * Q(n5, 1) * Q(n6, 1) + Q(n1 + n2, 2) * Q(n3 + n4, 2) * Q(n5, 1) * Q(n6, 1) + 2. * Q(n2, 1) * Q(n1 + n3 + n4, 3) * Q(n5, 1) * Q(n6, 1) + 2. * Q(n1, 1) * Q(n2 + n3 + n4, 3) * Q(n5, 1) * Q(n6, 1) - 6. * Q(n1 + n2 + n3 + n4, 4) * Q(n5, 1) * Q(n6, 1) - Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n1 + n5, 2) * Q(n6, 1) + Q(n2 + n3, 2) * Q(n4, 1) * Q(n1 + n5, 2) * Q(n6, 1) + Q(n3, 1) * Q(n2 + n4, 2) * Q(n1 + n5, 2) * Q(n6, 1) + Q(n2, 1) * Q(n3 + n4, 2) * Q(n1 + n5, 2) * Q(n6, 1) - 2. * Q(n2 + n3 + n4, 3) * Q(n1 + n5, 2) * Q(n6, 1) - Q(n1, 1) * Q(n3, 1) * Q(n4, 1) * Q(n2 + n5, 2) * Q(n6, 1) + Q(n1 + n3, 2) * Q(n4, 1) * Q(n2 + n5, 2) * Q(n6, 1) + Q(n3, 1) * Q(n1 + n4, 2) * Q(n2 + n5, 2) * Q(n6, 1) + Q(n1, 1) * Q(n3 + n4, 2) * Q(n2 + n5, 2) * Q(n6, 1) - 2. * Q(n1 + n3 + n4, 3) * Q(n2 + n5, 2) * Q(n6, 1) + 2. * Q(n3, 1) * Q(n4, 1) * Q(n1 + n2 + n5, 3) * Q(n6, 1) - 2. * Q(n3 + n4, 2) * Q(n1 + n2 + n5, 3) * Q(n6, 1) - Q(n1, 1) * Q(n2, 1) * Q(n4, 1) * Q(n3 + n5, 2) * Q(n6, 1) + Q(n1 + n2, 2) * Q(n4, 1) * Q(n3 + n5, 2) * Q(n6, 1) + Q(n2, 1) * Q(n1 + n4, 2) * Q(n3 + n5, 2) * Q(n6, 1) + Q(n1, 1) * Q(n2 + n4, 2) * Q(n3 + n5, 2) * Q(n6, 1) - 2. * Q(n1 + n2 + n4, 3) * Q(n3 + n5, 2) * Q(n6, 1) + 2. * Q(n2, 1) * Q(n4, 1) * Q(n1 + n3 + n5, 3) * Q(n6, 1) - 2. * Q(n2 + n4, 2) * Q(n1 + n3 + n5, 3) * Q(n6, 1) + 2. * Q(n1, 1) * Q(n4, 1) * Q(n2 + n3 + n5, 3) * Q(n6, 1) - 2. * Q(n1 + n4, 2) * Q(n2 + n3 + n5, 3) * Q(n6, 1) - 6. * Q(n4, 1) * Q(n1 + n2 + n3 + n5, 4) * Q(n6, 1) - Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4 + n5, 2) * Q(n6, 1) + Q(n1 + n2, 2) * Q(n3, 1) * Q(n4 + n5, 2) * Q(n6, 1) + Q(n2, 1) * Q(n1 + n3, 2) * Q(n4 + n5, 2) * Q(n6, 1) + Q(n1, 1) * Q(n2 + n3, 2) * Q(n4 + n5, 2) * Q(n6, 1) - 2. * Q(n1 + n2 + n3, 3) * Q(n4 + n5, 2) * Q(n6, 1) + 2. * Q(n2, 1) * Q(n3, 1) * Q(n1 + n4 + n5, 3) * Q(n6, 1) - 2. * Q(n2 + n3, 2) * Q(n1 + n4 + n5, 3) * Q(n6, 1) + 2. * Q(n1, 1) * Q(n3, 1) * Q(n2 + n4 + n5, 3) * Q(n6, 1) - 2. * Q(n1 + n3, 2) * Q(n2 + n4 + n5, 3) * Q(n6, 1) - 6. * Q(n3, 1) * Q(n1 + n2 + n4 + n5, 4) * Q(n6, 1) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n3 + n4 + n5, 3) * Q(n6, 1) - 2. * Q(n1 + n2, 2) * Q(n3 + n4 + n5, 3) * Q(n6, 1) - 6. * Q(n2, 1) * Q(n1 + n3 + n4 + n5, 4) * Q(n6, 1) - 6. * Q(n1, 1) * Q(n2 + n3 + n4 + n5, 4) * Q(n6, 1) + 24. * Q(n1 + n2 + n3 + n4 + n5, 5) * Q(n6, 1) - Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n1 + n6, 2) + Q(n2 + n3, 2) * Q(n4, 1) * Q(n5, 1) * Q(n1 + n6, 2) + Q(n3, 1) * Q(n2 + n4, 2) * Q(n5, 1) * Q(n1 + n6, 2) + Q(n2, 1) * Q(n3 + n4, 2) * Q(n5, 1) * Q(n1 + n6, 2) - 2. * Q(n2 + n3 + n4, 3) * Q(n5, 1) * Q(n1 + n6, 2) + Q(n3, 1) * Q(n4, 1) * Q(n2 + n5, 2) * Q(n1 + n6, 2) - Q(n3 + n4, 2) * Q(n2 + n5, 2) * Q(n1 + n6, 2) + Q(n2, 1) * Q(n4, 1) * Q(n3 + n5, 2) * Q(n1 + n6, 2) - Q(n2 + n4, 2) * Q(n3 + n5, 2) * Q(n1 + n6, 2) - 2. * Q(n4, 1) * Q(n2 + n3 + n5, 3) * Q(n1 + n6, 2) + Q(n2, 1) * Q(n3, 1) * Q(n4 + n5, 2) * Q(n1 + n6, 2) - Q(n2 + n3, 2) * Q(n4 + n5, 2) * Q(n1 + n6, 2) - 2. * Q(n3, 1) * Q(n2 + n4 + n5, 3) * Q(n1 + n6, 2) - 2. * Q(n2, 1) * Q(n3 + n4 + n5, 3) * Q(n1 + n6, 2) + 6. * Q(n2 + n3 + n4 + n5, 4) * Q(n1 + n6, 2) - Q(n1, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n2 + n6, 2) + Q(n1 + n3, 2) * Q(n4, 1) * Q(n5, 1) * Q(n2 + n6, 2) + Q(n3, 1) * Q(n1 + n4, 2) * Q(n5, 1) * Q(n2 + n6, 2) + Q(n1, 1) * Q(n3 + n4, 2) * Q(n5, 1) * Q(n2 + n6, 2) - 2. * Q(n1 + n3 + n4, 3) * Q(n5, 1) * Q(n2 + n6, 2) + Q(n3, 1) * Q(n4, 1) * Q(n1 + n5, 2) * Q(n2 + n6, 2) - Q(n3 + n4, 2) * Q(n1 + n5, 2) * Q(n2 + n6, 2) + Q(n1, 1) * Q(n4, 1) * Q(n3 + n5, 2) * Q(n2 + n6, 2) - Q(n1 + n4, 2) * Q(n3 + n5, 2) * Q(n2 + n6, 2) - 2. * Q(n4, 1) * Q(n1 + n3 + n5, 3) * Q(n2 + n6, 2) + Q(n1, 1) * Q(n3, 1) * Q(n4 + n5, 2) * Q(n2 + n6, 2) - Q(n1 + n3, 2) * Q(n4 + n5, 2) * Q(n2 + n6, 2) - 2. * Q(n3, 1) * Q(n1 + n4 + n5, 3) * Q(n2 + n6, 2) - 2. * Q(n1, 1) * Q(n3 + n4 + n5, 3) * Q(n2 + n6, 2) + 6. * Q(n1 + n3 + n4 + n5, 4) * Q(n2 + n6, 2) + 2. * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n1 + n2 + n6, 3) - 2. * Q(n3 + n4, 2) * Q(n5, 1) * Q(n1 + n2 + n6, 3) - 2. * Q(n4, 1) * Q(n3 + n5, 2) * Q(n1 + n2 + n6, 3) - 2. * Q(n3, 1) * Q(n4 + n5, 2) * Q(n1 + n2 + n6, 3) + 4. * Q(n3 + n4 + n5, 3) * Q(n1 + n2 + n6, 3) - Q(n1, 1) * Q(n2, 1) * Q(n4, 1) * Q(n5, 1) * Q(n3 + n6, 2) + Q(n1 + n2, 2) * Q(n4, 1) * Q(n5, 1) * Q(n3 + n6, 2) + Q(n2, 1) * Q(n1 + n4, 2) * Q(n5, 1) * Q(n3 + n6, 2) + Q(n1, 1) * Q(n2 + n4, 2) * Q(n5, 1) * Q(n3 + n6, 2) - 2. * Q(n1 + n2 + n4, 3) * Q(n5, 1) * Q(n3 + n6, 2) + Q(n2, 1) * Q(n4, 1) * Q(n1 + n5, 2) * Q(n3 + n6, 2) - Q(n2 + n4, 2) * Q(n1 + n5, 2) * Q(n3 + n6, 2) + Q(n1, 1) * Q(n4, 1) * Q(n2 + n5, 2) * Q(n3 + n6, 2) - Q(n1 + n4, 2) * Q(n2 + n5, 2) * Q(n3 + n6, 2) - 2. * Q(n4, 1) * Q(n1 + n2 + n5, 3) * Q(n3 + n6, 2) + Q(n1, 1) * Q(n2, 1) * Q(n4 + n5, 2) * Q(n3 + n6, 2) - Q(n1 + n2, 2) * Q(n4 + n5, 2) * Q(n3 + n6, 2) - 2. * Q(n2, 1) * Q(n1 + n4 + n5, 3) * Q(n3 + n6, 2) - 2. * Q(n1, 1) * Q(n2 + n4 + n5, 3) * Q(n3 + n6, 2) + 6. * Q(n1 + n2 + n4 + n5, 4) * Q(n3 + n6, 2) + 2. * Q(n2, 1) * Q(n4, 1) * Q(n5, 1) * Q(n1 + n3 + n6, 3) - 2. * Q(n2 + n4, 2) * Q(n5, 1) * Q(n1 + n3 + n6, 3) - 2. * Q(n4, 1) * Q(n2 + n5, 2) * Q(n1 + n3 + n6, 3) - 2. * Q(n2, 1) * Q(n4 + n5, 2) * Q(n1 + n3 + n6, 3) + 4. * Q(n2 + n4 + n5, 3) * Q(n1 + n3 + n6, 3) + 2. * Q(n1, 1) * Q(n4, 1) * Q(n5, 1) * Q(n2 + n3 + n6, 3) - 2. * Q(n1 + n4, 2) * Q(n5, 1) * Q(n2 + n3 + n6, 3) - 2. * Q(n4, 1) * Q(n1 + n5, 2) * Q(n2 + n3 + n6, 3) - 2. * Q(n1, 1) * Q(n4 + n5, 2) * Q(n2 + n3 + n6, 3) + 4. * Q(n1 + n4 + n5, 3) * Q(n2 + n3 + n6, 3) - 6. * Q(n4, 1) * Q(n5, 1) * Q(n1 + n2 + n3 + n6, 4) + 6. * Q(n4 + n5, 2) * Q(n1 + n2 + n3 + n6, 4) - Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n5, 1) * Q(n4 + n6, 2) + Q(n1 + n2, 2) * Q(n3, 1) * Q(n5, 1) * Q(n4 + n6, 2) + Q(n2, 1) * Q(n1 + n3, 2) * Q(n5, 1) * Q(n4 + n6, 2) + Q(n1, 1) * Q(n2 + n3, 2) * Q(n5, 1) * Q(n4 + n6, 2) - 2. * Q(n1 + n2 + n3, 3) * Q(n5, 1) * Q(n4 + n6, 2) + Q(n2, 1) * Q(n3, 1) * Q(n1 + n5, 2) * Q(n4 + n6, 2) - Q(n2 + n3, 2) * Q(n1 + n5, 2) * Q(n4 + n6, 2) + Q(n1, 1) * Q(n3, 1) * Q(n2 + n5, 2) * Q(n4 + n6, 2) - Q(n1 + n3, 2) * Q(n2 + n5, 2) * Q(n4 + n6, 2) - 2. * Q(n3, 1) * Q(n1 + n2 + n5, 3) * Q(n4 + n6, 2) + Q(n1, 1) * Q(n2, 1) * Q(n3 + n5, 2) * Q(n4 + n6, 2) - Q(n1 + n2, 2) * Q(n3 + n5, 2) * Q(n4 + n6, 2) - 2. * Q(n2, 1) * Q(n1 + n3 + n5, 3) * Q(n4 + n6, 2) - 2. * Q(n1, 1) * Q(n2 + n3 + n5, 3) * Q(n4 + n6, 2) + 6. * Q(n1 + n2 + n3 + n5, 4) * Q(n4 + n6, 2) + 2. * Q(n2, 1) * Q(n3, 1) * Q(n5, 1) * Q(n1 + n4 + n6, 3) - 2. * Q(n2 + n3, 2) * Q(n5, 1) * Q(n1 + n4 + n6, 3) - 2. * Q(n3, 1) * Q(n2 + n5, 2) * Q(n1 + n4 + n6, 3) - 2. * Q(n2, 1) * Q(n3 + n5, 2) * Q(n1 + n4 + n6, 3) + 4. * Q(n2 + n3 + n5, 3) * Q(n1 + n4 + n6, 3) + 2. * Q(n1, 1) * Q(n3, 1) * Q(n5, 1) * Q(n2 + n4 + n6, 3) - 2. * Q(n1 + n3, 2) * Q(n5, 1) * Q(n2 + n4 + n6, 3) - 2. * Q(n3, 1) * Q(n1 + n5, 2) * Q(n2 + n4 + n6, 3) - 2. * Q(n1, 1) * Q(n3 + n5, 2) * Q(n2 + n4 + n6, 3) + 4. * Q(n1 + n3 + n5, 3) * Q(n2 + n4 + n6, 3) - 6. * Q(n3, 1) * Q(n5, 1) * Q(n1 + n2 + n4 + n6, 4) + 6. * Q(n3 + n5, 2) * Q(n1 + n2 + n4 + n6, 4) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n5, 1) * Q(n3 + n4 + n6, 3) - 2. * Q(n1 + n2, 2) * Q(n5, 1) * Q(n3 + n4 + n6, 3) - 2. * Q(n2, 1) * Q(n1 + n5, 2) * Q(n3 + n4 + n6, 3) - 2. * Q(n1, 1) * Q(n2 + n5, 2) * Q(n3 + n4 + n6, 3) + 4. * Q(n1 + n2 + n5, 3) * Q(n3 + n4 + n6, 3) - 6. * Q(n2, 1) * Q(n5, 1) * Q(n1 + n3 + n4 + n6, 4) + 6. * Q(n2 + n5, 2) * Q(n1 + n3 + n4 + n6, 4) - 6. * Q(n1, 1) * Q(n5, 1) * Q(n2 + n3 + n4 + n6, 4) + 6. * Q(n1 + n5, 2) * Q(n2 + n3 + n4 + n6, 4) + 24. * Q(n5, 1) * Q(n1 + n2 + n3 + n4 + n6, 5) - Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5 + n6, 2) + Q(n1 + n2, 2) * Q(n3, 1) * Q(n4, 1) * Q(n5 + n6, 2) + Q(n2, 1) * Q(n1 + n3, 2) * Q(n4, 1) * Q(n5 + n6, 2) + Q(n1, 1) * Q(n2 + n3, 2) * Q(n4, 1) * Q(n5 + n6, 2) - 2. * Q(n1 + n2 + n3, 3) * Q(n4, 1) * Q(n5 + n6, 2) + Q(n2, 1) * Q(n3, 1) * Q(n1 + n4, 2) * Q(n5 + n6, 2) - Q(n2 + n3, 2) * Q(n1 + n4, 2) * Q(n5 + n6, 2) + Q(n1, 1) * Q(n3, 1) * Q(n2 + n4, 2) * Q(n5 + n6, 2) - Q(n1 + n3, 2) * Q(n2 + n4, 2) * Q(n5 + n6, 2) - 2. * Q(n3, 1) * Q(n1 + n2 + n4, 3) * Q(n5 + n6, 2) + Q(n1, 1) * Q(n2, 1) * Q(n3 + n4, 2) * Q(n5 + n6, 2) - Q(n1 + n2, 2) * Q(n3 + n4, 2) * Q(n5 + n6, 2) - 2. * Q(n2, 1) * Q(n1 + n3 + n4, 3) * Q(n5 + n6, 2) - 2. * Q(n1, 1) * Q(n2 + n3 + n4, 3) * Q(n5 + n6, 2) + 6. * Q(n1 + n2 + n3 + n4, 4) * Q(n5 + n6, 2) + 2. * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n1 + n5 + n6, 3) - 2. * Q(n2 + n3, 2) * Q(n4, 1) * Q(n1 + n5 + n6, 3) - 2. * Q(n3, 1) * Q(n2 + n4, 2) * Q(n1 + n5 + n6, 3) - 2. * Q(n2, 1) * Q(n3 + n4, 2) * Q(n1 + n5 + n6, 3) + 4. * Q(n2 + n3 + n4, 3) * Q(n1 + n5 + n6, 3) + 2. * Q(n1, 1) * Q(n3, 1) * Q(n4, 1) * Q(n2 + n5 + n6, 3) - 2. * Q(n1 + n3, 2) * Q(n4, 1) * Q(n2 + n5 + n6, 3) - 2. * Q(n3, 1) * Q(n1 + n4, 2) * Q(n2 + n5 + n6, 3) - 2. * Q(n1, 1) * Q(n3 + n4, 2) * Q(n2 + n5 + n6, 3) + 4. * Q(n1 + n3 + n4, 3) * Q(n2 + n5 + n6, 3) - 6. * Q(n3, 1) * Q(n4, 1) * Q(n1 + n2 + n5 + n6, 4) + 6. * Q(n3 + n4, 2) * Q(n1 + n2 + n5 + n6, 4) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n4, 1) * Q(n3 + n5 + n6, 3) - 2. * Q(n1 + n2, 2) * Q(n4, 1) * Q(n3 + n5 + n6, 3) - 2. * Q(n2, 1) * Q(n1 + n4, 2) * Q(n3 + n5 + n6, 3) - 2. * Q(n1, 1) * Q(n2 + n4, 2) * Q(n3 + n5 + n6, 3) + 4. * Q(n1 + n2 + n4, 3) * Q(n3 + n5 + n6, 3) - 6. * Q(n2, 1) * Q(n4, 1) * Q(n1 + n3 + n5 + n6, 4) + 6. * Q(n2 + n4, 2) * Q(n1 + n3 + n5 + n6, 4) - 6. * Q(n1, 1) * Q(n4, 1) * Q(n2 + n3 + n5 + n6, 4) + 6. * Q(n1 + n4, 2) * Q(n2 + n3 + n5 + n6, 4) + 24. * Q(n4, 1) * Q(n1 + n2 + n3 + n5 + n6, 5) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4 + n5 + n6, 3) - 2. * Q(n1 + n2, 2) * Q(n3, 1) * Q(n4 + n5 + n6, 3) - 2. * Q(n2, 1) * Q(n1 + n3, 2) * Q(n4 + n5 + n6, 3) - 2. * Q(n1, 1) * Q(n2 + n3, 2) * Q(n4 + n5 + n6, 3) + 4. * Q(n1 + n2 + n3, 3) * Q(n4 + n5 + n6, 3) - 6. * Q(n2, 1) * Q(n3, 1) * Q(n1 + n4 + n5 + n6, 4) + 6. * Q(n2 + n3, 2) * Q(n1 + n4 + n5 + n6, 4) - 6. * Q(n1, 1) * Q(n3, 1) * Q(n2 + n4 + n5 + n6, 4) + 6. * Q(n1 + n3, 2) * Q(n2 + n4 + n5 + n6, 4) + 24. * Q(n3, 1) * Q(n1 + n2 + n4 + n5 + n6, 5) - 6. * Q(n1, 1) * Q(n2, 1) * Q(n3 + n4 + n5 + n6, 4) + 6. * Q(n1 + n2, 2) * Q(n3 + n4 + n5 + n6, 4) + 24. * Q(n2, 1) * Q(n1 + n3 + n4 + n5 + n6, 5) + 24. * Q(n1, 1) * Q(n2 + n3 + n4 + n5 + n6, 5) - 120. * Q(n1 + n2 + n3 + n4 + n5 + n6, 6); + + return six; + +} // 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); -} // void CalculateNestedLoops() + 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) //============================================================ -void ComparisonNestedLoopsVsCorrelations() +TComplex Recursion(int n, int* harmonic, int mult = 1, int skip = 0) { - // Compare analytic results from Q-vectors and brute force results from nested loops. - // Use only for small multiplicities, when nested loops are still feasible. - // Results have to be exactly the same in each case. + // Calculate multi-particle correlators by using recursion (an improved faster version) originally developed by + // Kristjan Gulbrandsen (gulbrand@nbi.dk). - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); - } + 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_t nBinsQV = -44; - Int_t nBinsNL = -44; - Double_t valueQV = 0.; - Double_t valueNL = 0.; + 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; - for (Int_t v = 0; v < 3; v++) { // TBI 20240116 this corresponds to the ordering of variables in enum eAsFunctionOf . Here (for the time being) I compare only int, mult. and cent. - // a) Integrated comparison: - nBinsQV = mupa.fCorrelationsPro[0][0][v]->GetNbinsX(); - nBinsNL = nl.fNestedLoopsPro[0][0][v]->GetNbinsX(); - if (nBinsQV != nBinsNL) { - 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++) { - 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++) { - if (mupa.fCorrelationsPro[o][h][v]) { - valueQV = mupa.fCorrelationsPro[o][h][v]->GetBinContent(b); - } - if (nl.fNestedLoopsPro[o][h][v]) { - valueNL = nl.fNestedLoopsPro[o][h][v]->GetBinContent(b); - } - 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) { - LOGF(info, "\n\033[1;33m[%d][%d][%d] \033[0m\n", o, h, v); - 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++) - LOGF(info, ""); // new line - } // for(Int_t o=0;o<4;o++) - } // for (Int_t v = 0; v < 3; v++) + if (mult == 1) + return c - c2; + return c - static_cast(mult) * c2; -} // void ComparisonNestedLoopsVsCorrelations() +} // TComplex Recursion(int n, int* harmonic, int mult = 1, int skip = 0) //============================================================ -TComplex Q(Int_t n, Int_t wp) +void ResetQ() { - // Using the fact that Q{-n,p} = Q{n,p}^*. + // Reset the components of generic Q-vectors. Use it whenever you call the + // standard functions for correlations, for some custom Q-vectors. - if (n >= 0) { - return qv.fQ[n][wp]; + 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.); + } } - return TComplex::Conjugate(qv.fQ[-n][wp]); -} // TComplex FlowWithMultiparticleCorrelationsTask::Q(Int_t n, Int_t wp) + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void ResetQ() //============================================================ -TComplex One(Int_t n1) +void SetWeightsHist(TH1D* const hist, eWeights whichWeight) { - // Generic expression . + // Copy histogram holding weights from an external file to the corresponding data member. - TComplex one = Q(n1, 1); + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } - return one; + // 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__); + } -} // TComplex FlowWithMultiparticleCorrelationsTask::One(Int_t n1) +} // void SetWeightsHist(TH1D* const hist, eWeights whichWeight) //============================================================ -TComplex Two(Int_t n1, Int_t n2) +void SetDiffWeightsHist(TH1D* const hist, eDiffWeights whichDiffWeight, int bin) { - // Generic two-particle correlation . + // Copy histogram holding differential weights from an external file to the corresponding data member. - TComplex two = Q(n1, 1) * Q(n2, 1) - Q(n1 + n2, 2); + // 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. - return two; + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } -} // TComplex FlowWithMultiparticleCorrelationsTask::Two(Int_t n1, Int_t n2) + // 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__); + } -TComplex Three(Int_t n1, Int_t n2, Int_t n3) -{ - // Generic three-particle correlation . + // 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. - TComplex three = Q(n1, 1) * Q(n2, 1) * Q(n3, 1) - Q(n1 + n2, 2) * Q(n3, 1) - - Q(n2, 1) * Q(n1 + n3, 2) - Q(n1, 1) * Q(n2 + n3, 2) + - 2. * Q(n1 + n2 + n3, 3); + // Flag: + if (!pw.fUseDiffWeights[whichDiffWeight]) // yes, set it only once to true, for all bins + { + pw.fUseDiffWeights[whichDiffWeight] = true; + } - return three; + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } -} // TComplex Three(Int_t n1, Int_t n2, Int_t n3) +} // SetDiffWeightsHist(TH1D* const hist, const char *variable, int bin) //============================================================ -TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) +void SetDiffWeightsSparse(THnSparseF* const sparse, eDiffWeightCategory dwc) { - // Generic four-particle correlation - // . + // Copy sparse histogram holding differential phi, pt, eta, etc., weights from an external file to the corresponding data member. - TComplex four = - 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); + // 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. - return four; + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } -} // TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) + // 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__); + } -TComplex Five(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5) -{ - // Generic five-particle correlation . + // 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(); - TComplex five = Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) - Q(n1 + n2, 2) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) - Q(n2, 1) * Q(n1 + n3, 2) * Q(n4, 1) * Q(n5, 1) - Q(n1, 1) * Q(n2 + n3, 2) * Q(n4, 1) * Q(n5, 1) + 2. * Q(n1 + n2 + n3, 3) * Q(n4, 1) * Q(n5, 1) - Q(n2, 1) * Q(n3, 1) * Q(n1 + n4, 2) * Q(n5, 1) + Q(n2 + n3, 2) * Q(n1 + n4, 2) * Q(n5, 1) - Q(n1, 1) * Q(n3, 1) * Q(n2 + n4, 2) * Q(n5, 1) + Q(n1 + n3, 2) * Q(n2 + n4, 2) * Q(n5, 1) + 2. * Q(n3, 1) * Q(n1 + n2 + n4, 3) * Q(n5, 1) - Q(n1, 1) * Q(n2, 1) * Q(n3 + n4, 2) * Q(n5, 1) + Q(n1 + n2, 2) * Q(n3 + n4, 2) * Q(n5, 1) + 2. * Q(n2, 1) * Q(n1 + n3 + n4, 3) * Q(n5, 1) + 2. * Q(n1, 1) * Q(n2 + n3 + n4, 3) * Q(n5, 1) - 6. * Q(n1 + n2 + n3 + n4, 4) * Q(n5, 1) - Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n1 + n5, 2) + Q(n2 + n3, 2) * Q(n4, 1) * Q(n1 + n5, 2) + Q(n3, 1) * Q(n2 + n4, 2) * Q(n1 + n5, 2) + Q(n2, 1) * Q(n3 + n4, 2) * Q(n1 + n5, 2) - 2. * Q(n2 + n3 + n4, 3) * Q(n1 + n5, 2) - Q(n1, 1) * Q(n3, 1) * Q(n4, 1) * Q(n2 + n5, 2) + Q(n1 + n3, 2) * Q(n4, 1) * Q(n2 + n5, 2) + Q(n3, 1) * Q(n1 + n4, 2) * Q(n2 + n5, 2) + Q(n1, 1) * Q(n3 + n4, 2) * Q(n2 + n5, 2) - 2. * Q(n1 + n3 + n4, 3) * Q(n2 + n5, 2) + 2. * Q(n3, 1) * Q(n4, 1) * Q(n1 + n2 + n5, 3) - 2. * Q(n3 + n4, 2) * Q(n1 + n2 + n5, 3) - Q(n1, 1) * Q(n2, 1) * Q(n4, 1) * Q(n3 + n5, 2) + Q(n1 + n2, 2) * Q(n4, 1) * Q(n3 + n5, 2) + Q(n2, 1) * Q(n1 + n4, 2) * Q(n3 + n5, 2) + Q(n1, 1) * Q(n2 + n4, 2) * Q(n3 + n5, 2) - 2. * Q(n1 + n2 + n4, 3) * Q(n3 + n5, 2) + 2. * Q(n2, 1) * Q(n4, 1) * Q(n1 + n3 + n5, 3) - 2. * Q(n2 + n4, 2) * Q(n1 + n3 + n5, 3) + 2. * Q(n1, 1) * Q(n4, 1) * Q(n2 + n3 + n5, 3) - 2. * Q(n1 + n4, 2) * Q(n2 + n3 + n5, 3) - 6. * Q(n4, 1) * Q(n1 + n2 + n3 + n5, 4) - Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4 + n5, 2) + Q(n1 + n2, 2) * Q(n3, 1) * Q(n4 + n5, 2) + Q(n2, 1) * Q(n1 + n3, 2) * Q(n4 + n5, 2) + Q(n1, 1) * Q(n2 + n3, 2) * Q(n4 + n5, 2) - 2. * Q(n1 + n2 + n3, 3) * Q(n4 + n5, 2) + 2. * Q(n2, 1) * Q(n3, 1) * Q(n1 + n4 + n5, 3) - 2. * Q(n2 + n3, 2) * Q(n1 + n4 + n5, 3) + 2. * Q(n1, 1) * Q(n3, 1) * Q(n2 + n4 + n5, 3) - 2. * Q(n1 + n3, 2) * Q(n2 + n4 + n5, 3) - 6. * Q(n3, 1) * Q(n1 + n2 + n4 + n5, 4) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n3 + n4 + n5, 3) - 2. * Q(n1 + n2, 2) * Q(n3 + n4 + n5, 3) - 6. * Q(n2, 1) * Q(n1 + n3 + n4 + n5, 4) - 6. * Q(n1, 1) * Q(n2 + n3 + n4 + n5, 4) + 24. * Q(n1 + n2 + n3 + n4 + n5, 5); + // I book here immediately vectors needed to fetch the weight from the right bin of THnSparse: + pw.fFindBinVector[dwc] = new TArrayD(pw.fDWdimension[dwc]); - return five; + // Finally, add to corresponding TList: + pw.fWeightsList->Add(pw.fDiffWeightsSparse[dwc]); -} // TComplex Five(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5) + // TBI 20250530 check this code snippet - do I need it? + // // 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) //============================================================ -TComplex Six(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6) +void SetCentralityWeightsHist(TH1D* const hist) { - // Generic six-particle correlation . + // Copy histogram holding weights from an external file to the corresponding data member. - TComplex six = Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) - Q(n1 + n2, 2) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) - Q(n2, 1) * Q(n1 + n3, 2) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) - Q(n1, 1) * Q(n2 + n3, 2) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) + 2. * Q(n1 + n2 + n3, 3) * Q(n4, 1) * Q(n5, 1) * Q(n6, 1) - Q(n2, 1) * Q(n3, 1) * Q(n1 + n4, 2) * Q(n5, 1) * Q(n6, 1) + Q(n2 + n3, 2) * Q(n1 + n4, 2) * Q(n5, 1) * Q(n6, 1) - Q(n1, 1) * Q(n3, 1) * Q(n2 + n4, 2) * Q(n5, 1) * Q(n6, 1) + Q(n1 + n3, 2) * Q(n2 + n4, 2) * Q(n5, 1) * Q(n6, 1) + 2. * Q(n3, 1) * Q(n1 + n2 + n4, 3) * Q(n5, 1) * Q(n6, 1) - Q(n1, 1) * Q(n2, 1) * Q(n3 + n4, 2) * Q(n5, 1) * Q(n6, 1) + Q(n1 + n2, 2) * Q(n3 + n4, 2) * Q(n5, 1) * Q(n6, 1) + 2. * Q(n2, 1) * Q(n1 + n3 + n4, 3) * Q(n5, 1) * Q(n6, 1) + 2. * Q(n1, 1) * Q(n2 + n3 + n4, 3) * Q(n5, 1) * Q(n6, 1) - 6. * Q(n1 + n2 + n3 + n4, 4) * Q(n5, 1) * Q(n6, 1) - Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n1 + n5, 2) * Q(n6, 1) + Q(n2 + n3, 2) * Q(n4, 1) * Q(n1 + n5, 2) * Q(n6, 1) + Q(n3, 1) * Q(n2 + n4, 2) * Q(n1 + n5, 2) * Q(n6, 1) + Q(n2, 1) * Q(n3 + n4, 2) * Q(n1 + n5, 2) * Q(n6, 1) - 2. * Q(n2 + n3 + n4, 3) * Q(n1 + n5, 2) * Q(n6, 1) - Q(n1, 1) * Q(n3, 1) * Q(n4, 1) * Q(n2 + n5, 2) * Q(n6, 1) + Q(n1 + n3, 2) * Q(n4, 1) * Q(n2 + n5, 2) * Q(n6, 1) + Q(n3, 1) * Q(n1 + n4, 2) * Q(n2 + n5, 2) * Q(n6, 1) + Q(n1, 1) * Q(n3 + n4, 2) * Q(n2 + n5, 2) * Q(n6, 1) - 2. * Q(n1 + n3 + n4, 3) * Q(n2 + n5, 2) * Q(n6, 1) + 2. * Q(n3, 1) * Q(n4, 1) * Q(n1 + n2 + n5, 3) * Q(n6, 1) - 2. * Q(n3 + n4, 2) * Q(n1 + n2 + n5, 3) * Q(n6, 1) - Q(n1, 1) * Q(n2, 1) * Q(n4, 1) * Q(n3 + n5, 2) * Q(n6, 1) + Q(n1 + n2, 2) * Q(n4, 1) * Q(n3 + n5, 2) * Q(n6, 1) + Q(n2, 1) * Q(n1 + n4, 2) * Q(n3 + n5, 2) * Q(n6, 1) + Q(n1, 1) * Q(n2 + n4, 2) * Q(n3 + n5, 2) * Q(n6, 1) - 2. * Q(n1 + n2 + n4, 3) * Q(n3 + n5, 2) * Q(n6, 1) + 2. * Q(n2, 1) * Q(n4, 1) * Q(n1 + n3 + n5, 3) * Q(n6, 1) - 2. * Q(n2 + n4, 2) * Q(n1 + n3 + n5, 3) * Q(n6, 1) + 2. * Q(n1, 1) * Q(n4, 1) * Q(n2 + n3 + n5, 3) * Q(n6, 1) - 2. * Q(n1 + n4, 2) * Q(n2 + n3 + n5, 3) * Q(n6, 1) - 6. * Q(n4, 1) * Q(n1 + n2 + n3 + n5, 4) * Q(n6, 1) - Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4 + n5, 2) * Q(n6, 1) + Q(n1 + n2, 2) * Q(n3, 1) * Q(n4 + n5, 2) * Q(n6, 1) + Q(n2, 1) * Q(n1 + n3, 2) * Q(n4 + n5, 2) * Q(n6, 1) + Q(n1, 1) * Q(n2 + n3, 2) * Q(n4 + n5, 2) * Q(n6, 1) - 2. * Q(n1 + n2 + n3, 3) * Q(n4 + n5, 2) * Q(n6, 1) + 2. * Q(n2, 1) * Q(n3, 1) * Q(n1 + n4 + n5, 3) * Q(n6, 1) - 2. * Q(n2 + n3, 2) * Q(n1 + n4 + n5, 3) * Q(n6, 1) + 2. * Q(n1, 1) * Q(n3, 1) * Q(n2 + n4 + n5, 3) * Q(n6, 1) - 2. * Q(n1 + n3, 2) * Q(n2 + n4 + n5, 3) * Q(n6, 1) - 6. * Q(n3, 1) * Q(n1 + n2 + n4 + n5, 4) * Q(n6, 1) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n3 + n4 + n5, 3) * Q(n6, 1) - 2. * Q(n1 + n2, 2) * Q(n3 + n4 + n5, 3) * Q(n6, 1) - 6. * Q(n2, 1) * Q(n1 + n3 + n4 + n5, 4) * Q(n6, 1) - 6. * Q(n1, 1) * Q(n2 + n3 + n4 + n5, 4) * Q(n6, 1) + 24. * Q(n1 + n2 + n3 + n4 + n5, 5) * Q(n6, 1) - Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n1 + n6, 2) + Q(n2 + n3, 2) * Q(n4, 1) * Q(n5, 1) * Q(n1 + n6, 2) + Q(n3, 1) * Q(n2 + n4, 2) * Q(n5, 1) * Q(n1 + n6, 2) + Q(n2, 1) * Q(n3 + n4, 2) * Q(n5, 1) * Q(n1 + n6, 2) - 2. * Q(n2 + n3 + n4, 3) * Q(n5, 1) * Q(n1 + n6, 2) + Q(n3, 1) * Q(n4, 1) * Q(n2 + n5, 2) * Q(n1 + n6, 2) - Q(n3 + n4, 2) * Q(n2 + n5, 2) * Q(n1 + n6, 2) + Q(n2, 1) * Q(n4, 1) * Q(n3 + n5, 2) * Q(n1 + n6, 2) - Q(n2 + n4, 2) * Q(n3 + n5, 2) * Q(n1 + n6, 2) - 2. * Q(n4, 1) * Q(n2 + n3 + n5, 3) * Q(n1 + n6, 2) + Q(n2, 1) * Q(n3, 1) * Q(n4 + n5, 2) * Q(n1 + n6, 2) - Q(n2 + n3, 2) * Q(n4 + n5, 2) * Q(n1 + n6, 2) - 2. * Q(n3, 1) * Q(n2 + n4 + n5, 3) * Q(n1 + n6, 2) - 2. * Q(n2, 1) * Q(n3 + n4 + n5, 3) * Q(n1 + n6, 2) + 6. * Q(n2 + n3 + n4 + n5, 4) * Q(n1 + n6, 2) - Q(n1, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n2 + n6, 2) + Q(n1 + n3, 2) * Q(n4, 1) * Q(n5, 1) * Q(n2 + n6, 2) + Q(n3, 1) * Q(n1 + n4, 2) * Q(n5, 1) * Q(n2 + n6, 2) + Q(n1, 1) * Q(n3 + n4, 2) * Q(n5, 1) * Q(n2 + n6, 2) - 2. * Q(n1 + n3 + n4, 3) * Q(n5, 1) * Q(n2 + n6, 2) + Q(n3, 1) * Q(n4, 1) * Q(n1 + n5, 2) * Q(n2 + n6, 2) - Q(n3 + n4, 2) * Q(n1 + n5, 2) * Q(n2 + n6, 2) + Q(n1, 1) * Q(n4, 1) * Q(n3 + n5, 2) * Q(n2 + n6, 2) - Q(n1 + n4, 2) * Q(n3 + n5, 2) * Q(n2 + n6, 2) - 2. * Q(n4, 1) * Q(n1 + n3 + n5, 3) * Q(n2 + n6, 2) + Q(n1, 1) * Q(n3, 1) * Q(n4 + n5, 2) * Q(n2 + n6, 2) - Q(n1 + n3, 2) * Q(n4 + n5, 2) * Q(n2 + n6, 2) - 2. * Q(n3, 1) * Q(n1 + n4 + n5, 3) * Q(n2 + n6, 2) - 2. * Q(n1, 1) * Q(n3 + n4 + n5, 3) * Q(n2 + n6, 2) + 6. * Q(n1 + n3 + n4 + n5, 4) * Q(n2 + n6, 2) + 2. * Q(n3, 1) * Q(n4, 1) * Q(n5, 1) * Q(n1 + n2 + n6, 3) - 2. * Q(n3 + n4, 2) * Q(n5, 1) * Q(n1 + n2 + n6, 3) - 2. * Q(n4, 1) * Q(n3 + n5, 2) * Q(n1 + n2 + n6, 3) - 2. * Q(n3, 1) * Q(n4 + n5, 2) * Q(n1 + n2 + n6, 3) + 4. * Q(n3 + n4 + n5, 3) * Q(n1 + n2 + n6, 3) - Q(n1, 1) * Q(n2, 1) * Q(n4, 1) * Q(n5, 1) * Q(n3 + n6, 2) + Q(n1 + n2, 2) * Q(n4, 1) * Q(n5, 1) * Q(n3 + n6, 2) + Q(n2, 1) * Q(n1 + n4, 2) * Q(n5, 1) * Q(n3 + n6, 2) + Q(n1, 1) * Q(n2 + n4, 2) * Q(n5, 1) * Q(n3 + n6, 2) - 2. * Q(n1 + n2 + n4, 3) * Q(n5, 1) * Q(n3 + n6, 2) + Q(n2, 1) * Q(n4, 1) * Q(n1 + n5, 2) * Q(n3 + n6, 2) - Q(n2 + n4, 2) * Q(n1 + n5, 2) * Q(n3 + n6, 2) + Q(n1, 1) * Q(n4, 1) * Q(n2 + n5, 2) * Q(n3 + n6, 2) - Q(n1 + n4, 2) * Q(n2 + n5, 2) * Q(n3 + n6, 2) - 2. * Q(n4, 1) * Q(n1 + n2 + n5, 3) * Q(n3 + n6, 2) + Q(n1, 1) * Q(n2, 1) * Q(n4 + n5, 2) * Q(n3 + n6, 2) - Q(n1 + n2, 2) * Q(n4 + n5, 2) * Q(n3 + n6, 2) - 2. * Q(n2, 1) * Q(n1 + n4 + n5, 3) * Q(n3 + n6, 2) - 2. * Q(n1, 1) * Q(n2 + n4 + n5, 3) * Q(n3 + n6, 2) + 6. * Q(n1 + n2 + n4 + n5, 4) * Q(n3 + n6, 2) + 2. * Q(n2, 1) * Q(n4, 1) * Q(n5, 1) * Q(n1 + n3 + n6, 3) - 2. * Q(n2 + n4, 2) * Q(n5, 1) * Q(n1 + n3 + n6, 3) - 2. * Q(n4, 1) * Q(n2 + n5, 2) * Q(n1 + n3 + n6, 3) - 2. * Q(n2, 1) * Q(n4 + n5, 2) * Q(n1 + n3 + n6, 3) + 4. * Q(n2 + n4 + n5, 3) * Q(n1 + n3 + n6, 3) + 2. * Q(n1, 1) * Q(n4, 1) * Q(n5, 1) * Q(n2 + n3 + n6, 3) - 2. * Q(n1 + n4, 2) * Q(n5, 1) * Q(n2 + n3 + n6, 3) - 2. * Q(n4, 1) * Q(n1 + n5, 2) * Q(n2 + n3 + n6, 3) - 2. * Q(n1, 1) * Q(n4 + n5, 2) * Q(n2 + n3 + n6, 3) + 4. * Q(n1 + n4 + n5, 3) * Q(n2 + n3 + n6, 3) - 6. * Q(n4, 1) * Q(n5, 1) * Q(n1 + n2 + n3 + n6, 4) + 6. * Q(n4 + n5, 2) * Q(n1 + n2 + n3 + n6, 4) - Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n5, 1) * Q(n4 + n6, 2) + Q(n1 + n2, 2) * Q(n3, 1) * Q(n5, 1) * Q(n4 + n6, 2) + Q(n2, 1) * Q(n1 + n3, 2) * Q(n5, 1) * Q(n4 + n6, 2) + Q(n1, 1) * Q(n2 + n3, 2) * Q(n5, 1) * Q(n4 + n6, 2) - 2. * Q(n1 + n2 + n3, 3) * Q(n5, 1) * Q(n4 + n6, 2) + Q(n2, 1) * Q(n3, 1) * Q(n1 + n5, 2) * Q(n4 + n6, 2) - Q(n2 + n3, 2) * Q(n1 + n5, 2) * Q(n4 + n6, 2) + Q(n1, 1) * Q(n3, 1) * Q(n2 + n5, 2) * Q(n4 + n6, 2) - Q(n1 + n3, 2) * Q(n2 + n5, 2) * Q(n4 + n6, 2) - 2. * Q(n3, 1) * Q(n1 + n2 + n5, 3) * Q(n4 + n6, 2) + Q(n1, 1) * Q(n2, 1) * Q(n3 + n5, 2) * Q(n4 + n6, 2) - Q(n1 + n2, 2) * Q(n3 + n5, 2) * Q(n4 + n6, 2) - 2. * Q(n2, 1) * Q(n1 + n3 + n5, 3) * Q(n4 + n6, 2) - 2. * Q(n1, 1) * Q(n2 + n3 + n5, 3) * Q(n4 + n6, 2) + 6. * Q(n1 + n2 + n3 + n5, 4) * Q(n4 + n6, 2) + 2. * Q(n2, 1) * Q(n3, 1) * Q(n5, 1) * Q(n1 + n4 + n6, 3) - 2. * Q(n2 + n3, 2) * Q(n5, 1) * Q(n1 + n4 + n6, 3) - 2. * Q(n3, 1) * Q(n2 + n5, 2) * Q(n1 + n4 + n6, 3) - 2. * Q(n2, 1) * Q(n3 + n5, 2) * Q(n1 + n4 + n6, 3) + 4. * Q(n2 + n3 + n5, 3) * Q(n1 + n4 + n6, 3) + 2. * Q(n1, 1) * Q(n3, 1) * Q(n5, 1) * Q(n2 + n4 + n6, 3) - 2. * Q(n1 + n3, 2) * Q(n5, 1) * Q(n2 + n4 + n6, 3) - 2. * Q(n3, 1) * Q(n1 + n5, 2) * Q(n2 + n4 + n6, 3) - 2. * Q(n1, 1) * Q(n3 + n5, 2) * Q(n2 + n4 + n6, 3) + 4. * Q(n1 + n3 + n5, 3) * Q(n2 + n4 + n6, 3) - 6. * Q(n3, 1) * Q(n5, 1) * Q(n1 + n2 + n4 + n6, 4) + 6. * Q(n3 + n5, 2) * Q(n1 + n2 + n4 + n6, 4) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n5, 1) * Q(n3 + n4 + n6, 3) - 2. * Q(n1 + n2, 2) * Q(n5, 1) * Q(n3 + n4 + n6, 3) - 2. * Q(n2, 1) * Q(n1 + n5, 2) * Q(n3 + n4 + n6, 3) - 2. * Q(n1, 1) * Q(n2 + n5, 2) * Q(n3 + n4 + n6, 3) + 4. * Q(n1 + n2 + n5, 3) * Q(n3 + n4 + n6, 3) - 6. * Q(n2, 1) * Q(n5, 1) * Q(n1 + n3 + n4 + n6, 4) + 6. * Q(n2 + n5, 2) * Q(n1 + n3 + n4 + n6, 4) - 6. * Q(n1, 1) * Q(n5, 1) * Q(n2 + n3 + n4 + n6, 4) + 6. * Q(n1 + n5, 2) * Q(n2 + n3 + n4 + n6, 4) + 24. * Q(n5, 1) * Q(n1 + n2 + n3 + n4 + n6, 5) - Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n5 + n6, 2) + Q(n1 + n2, 2) * Q(n3, 1) * Q(n4, 1) * Q(n5 + n6, 2) + Q(n2, 1) * Q(n1 + n3, 2) * Q(n4, 1) * Q(n5 + n6, 2) + Q(n1, 1) * Q(n2 + n3, 2) * Q(n4, 1) * Q(n5 + n6, 2) - 2. * Q(n1 + n2 + n3, 3) * Q(n4, 1) * Q(n5 + n6, 2) + Q(n2, 1) * Q(n3, 1) * Q(n1 + n4, 2) * Q(n5 + n6, 2) - Q(n2 + n3, 2) * Q(n1 + n4, 2) * Q(n5 + n6, 2) + Q(n1, 1) * Q(n3, 1) * Q(n2 + n4, 2) * Q(n5 + n6, 2) - Q(n1 + n3, 2) * Q(n2 + n4, 2) * Q(n5 + n6, 2) - 2. * Q(n3, 1) * Q(n1 + n2 + n4, 3) * Q(n5 + n6, 2) + Q(n1, 1) * Q(n2, 1) * Q(n3 + n4, 2) * Q(n5 + n6, 2) - Q(n1 + n2, 2) * Q(n3 + n4, 2) * Q(n5 + n6, 2) - 2. * Q(n2, 1) * Q(n1 + n3 + n4, 3) * Q(n5 + n6, 2) - 2. * Q(n1, 1) * Q(n2 + n3 + n4, 3) * Q(n5 + n6, 2) + 6. * Q(n1 + n2 + n3 + n4, 4) * Q(n5 + n6, 2) + 2. * Q(n2, 1) * Q(n3, 1) * Q(n4, 1) * Q(n1 + n5 + n6, 3) - 2. * Q(n2 + n3, 2) * Q(n4, 1) * Q(n1 + n5 + n6, 3) - 2. * Q(n3, 1) * Q(n2 + n4, 2) * Q(n1 + n5 + n6, 3) - 2. * Q(n2, 1) * Q(n3 + n4, 2) * Q(n1 + n5 + n6, 3) + 4. * Q(n2 + n3 + n4, 3) * Q(n1 + n5 + n6, 3) + 2. * Q(n1, 1) * Q(n3, 1) * Q(n4, 1) * Q(n2 + n5 + n6, 3) - 2. * Q(n1 + n3, 2) * Q(n4, 1) * Q(n2 + n5 + n6, 3) - 2. * Q(n3, 1) * Q(n1 + n4, 2) * Q(n2 + n5 + n6, 3) - 2. * Q(n1, 1) * Q(n3 + n4, 2) * Q(n2 + n5 + n6, 3) + 4. * Q(n1 + n3 + n4, 3) * Q(n2 + n5 + n6, 3) - 6. * Q(n3, 1) * Q(n4, 1) * Q(n1 + n2 + n5 + n6, 4) + 6. * Q(n3 + n4, 2) * Q(n1 + n2 + n5 + n6, 4) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n4, 1) * Q(n3 + n5 + n6, 3) - 2. * Q(n1 + n2, 2) * Q(n4, 1) * Q(n3 + n5 + n6, 3) - 2. * Q(n2, 1) * Q(n1 + n4, 2) * Q(n3 + n5 + n6, 3) - 2. * Q(n1, 1) * Q(n2 + n4, 2) * Q(n3 + n5 + n6, 3) + 4. * Q(n1 + n2 + n4, 3) * Q(n3 + n5 + n6, 3) - 6. * Q(n2, 1) * Q(n4, 1) * Q(n1 + n3 + n5 + n6, 4) + 6. * Q(n2 + n4, 2) * Q(n1 + n3 + n5 + n6, 4) - 6. * Q(n1, 1) * Q(n4, 1) * Q(n2 + n3 + n5 + n6, 4) + 6. * Q(n1 + n4, 2) * Q(n2 + n3 + n5 + n6, 4) + 24. * Q(n4, 1) * Q(n1 + n2 + n3 + n5 + n6, 5) + 2. * Q(n1, 1) * Q(n2, 1) * Q(n3, 1) * Q(n4 + n5 + n6, 3) - 2. * Q(n1 + n2, 2) * Q(n3, 1) * Q(n4 + n5 + n6, 3) - 2. * Q(n2, 1) * Q(n1 + n3, 2) * Q(n4 + n5 + n6, 3) - 2. * Q(n1, 1) * Q(n2 + n3, 2) * Q(n4 + n5 + n6, 3) + 4. * Q(n1 + n2 + n3, 3) * Q(n4 + n5 + n6, 3) - 6. * Q(n2, 1) * Q(n3, 1) * Q(n1 + n4 + n5 + n6, 4) + 6. * Q(n2 + n3, 2) * Q(n1 + n4 + n5 + n6, 4) - 6. * Q(n1, 1) * Q(n3, 1) * Q(n2 + n4 + n5 + n6, 4) + 6. * Q(n1 + n3, 2) * Q(n2 + n4 + n5 + n6, 4) + 24. * Q(n3, 1) * Q(n1 + n2 + n4 + n5 + n6, 5) - 6. * Q(n1, 1) * Q(n2, 1) * Q(n3 + n4 + n5 + n6, 4) + 6. * Q(n1 + n2, 2) * Q(n3 + n4 + n5 + n6, 4) + 24. * Q(n2, 1) * Q(n1 + n3 + n4 + n5 + n6, 5) + 24. * Q(n1, 1) * Q(n2 + n3 + n4 + n5 + n6, 5) - 120. * Q(n1 + n2 + n3 + n4 + n5 + n6, 6); + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } - return six; + // 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. -} // TComplex Six(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6) + // Flag: + cw.fUseCentralityWeights = true; + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void SetCentralityWeightsHist(TH1D* const hist) //============================================================ -TComplex Seven(Int_t n1, Int_t n2, Int_t n3, Int_t n4, Int_t n5, Int_t n6, Int_t n7) +TH1D* GetWeightsHist(eWeights whichWeight) { - // Generic seven-particle correlation . + // The standard getter. - Int_t harmonic[7] = {n1, n2, n3, n4, n5, n6, n7}; + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } - TComplex seven = Recursion(7, harmonic); + // ... - return seven; + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + + // Finally: + return pw.fWeightsHist[whichWeight]; -} // 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) +} // TH1D* GetWeightsHist(eWeights whichWeigh) //============================================================ -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) +TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const char* variable, int bin = -1) { - // Generic eight-particle correlation . + // 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. + + // 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). + + 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()); + } + + // 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 + + // 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__); + } + + // 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__); + } + + 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 (!(std::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 (!(std::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", __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 -} // void ResetQ() + // 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); + } -//============================================================ + // 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/")) { -void SetWeightsHist(TH1D* const hist, eWeights whichWeight) -{ - // Copy histogram holding weights from an external file to the corresponding data member. + 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__); + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); - } + 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__); + } - // Finally: - hist->SetDirectory(0); - pw.fWeightsHist[whichWeight] = reinterpret_cast(hist->Clone()); + 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__); + } + } - if (!pw.fWeightsHist[whichWeight]) { - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } + } else if (bFileIsInCCDB) { - // 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(kFALSE); - 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); - pw.fWeightsList->Add(pw.fWeightsHist[whichWeight]); + // 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 - // Flag: - pw.fUseWeights[whichWeight] = kTRUE; + 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()); + } -} // void SetWeightsHist(TH1D* const hist, , eWeights whichWeight) + 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__); + } -void SetDiffWeightsHist(TH1D* const hist, eDiffWeights whichDiffWeight, Int_t bin) -{ - // Copy histogram holding differential weights from an external file to the corresponding data member. + 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__); + } + } - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); - } + } else { - // Finally: - hist->SetDirectory(0); - pw.fDiffWeightsHist[whichDiffWeight][bin] = reinterpret_cast(hist->Clone()); + // 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. - if (!pw.fDiffWeightsHist[whichDiffWeight][bin]) { - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } + // 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__); + } - // 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[whichDiffWeight][bin]->SetStats(kFALSE); - 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]); + TFile* weightsFile = TFile::Open(filePath, "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - // Flag: - if (!pw.fUseDiffWeights[whichDiffWeight]) // yes, set it only once to kTRUE, for all bins - { - pw.fUseDiffWeights[whichDiffWeight] = kTRUE; - } + 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__); + } -} // SetDiffWeightsHist(TH1D* const hist, const char *variable, Int_t bin) + 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()); + } + } -//============================================================ + } // else { -TH1D* GetWeightsHist(eWeights whichWeight) -{ - // The standard getter. + // 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 (!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()); + } + + sparseHist->SetTitle(Form("%s, %s", filePath, runNumber)); // I have to do it here, because only here I have "filePath" available + + // hist->SetTitle(Form("%s, %.2f < %s < %.2f", filePath, min, lVariableName, max)); + + // TBI 20250530 check this code snippet - do I need it? + // // *) 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)); + // } + // + // // 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()); + // } + // + // // Compare with min and max value stored in external weights.root file using MakeWeights.C: + // if (!(std::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 (!(std::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); + + // 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)); + + // 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 if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + ExitFunction(__FUNCTION__); } - // Finally: - return pw.fWeightsHist[whichWeight]; + return sparseHistClone; -} // TH1D* GetWeightsHist(eWeights whichWeigh) +} // 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 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 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; @@ -6573,14 +14481,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", __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 (if bin = -1, integrated weights are searched for)\033[0m", bin); LOGF(info, "\033[1;33m fTaskName = %s\033[0m", tc.fTaskName.Data()); } @@ -6590,27 +14497,22 @@ 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, "\033[1;31m%s at line %d\033[0m", __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: @@ -6618,23 +14520,27 @@ TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const 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) { + 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(); + // 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, "\033[1;31m%s at line %d\033[0m", __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) { @@ -6653,23 +14559,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, "\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, "\033[1;31m%s at line %d\033[0m", __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 { @@ -6677,8 +14583,7 @@ 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)) { @@ -6686,104 +14591,396 @@ TH1D* GetHistogramWithWeights(const char* filePath, const char* runNumber, const LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - TFile* weightsFile = TFile::Open(filePath, "READ"); - if (!weightsFile) { + 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 + 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(); + // 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, "\033[1;31m%s at line %d\033[0m", __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, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } + // g) The final touch on histogram with centrality weights: + TString histName = ""; - // fetch histogram directly from this list: - hist = reinterpret_cast(listWithRuns->FindObject(Form("%s_%s", variable, tc.fTaskName.Data()))); - // if the previous search failed, descend recursively also into the nested lists: - if (!hist) { - 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) { - listWithRuns->ls(); - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } - hist->SetDirectory(0); - hist->SetTitle(Form("%s, %s", filePath, runNumber)); + // 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, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } - // fetch histogram directly from this list: - hist = reinterpret_cast(listWithRuns->FindObject(Form("%s[%d]_%s", variable, bin, tc.fTaskName.Data()))); - // if the previous search failed, descend recursively also into the nested lists: - if (!hist) { - 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]' - } - if (!hist) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); - listWithRuns->ls(); - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } - hist->SetDirectory(0); + LOGF(fatal, "\033[1;31m%s at line %d : the case tmp = %s is not supported yet\033[0m", __FUNCTION__, __LINE__, tmp.Data()); + } - 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))); - } - 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))); + 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); + } + } else if (TString(whichDefaultLabels).EqualTo("mixedEventsStudy")) { + const int nLabels = 3; + TString labels[nLabels] = {"2", "-2", "2 -2"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); + } + } 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); + } + } else if (TString(whichDefaultLabels).EqualTo("projections")) { // use this set to test projections when calculating multi-dimensional weights + const int nLabels = 10; + TString labels[nLabels] = {"1", "2", "3", "1 -1", "2 -2", "3 -3", "3 -1 -2", "1 1 -1 -1", "2 2 -2 -2", "3 3 -3 -3"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); + } + } 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); + } + } 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); + } + } 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 if (TString(whichDefaultLabels).EqualTo("Set_0")) { + // From ~/scratch/O2/master/Labels/Set_0/labels_Set_0.root + const int nLabels = 57; // yes, because I do not care about 1-p + TString labels[nLabels] = { + "1 -1 ", + "2 -2 ", + "3 -3 ", + "4 -4 ", + "5 -5 ", + "6 -6 ", + "2 1 -1 -2 ", + "3 1 -1 -3 ", + "3 2 -2 -3 ", + "4 1 -1 -4 ", + "4 2 -2 -4 ", + "4 3 -3 -4 ", + "5 1 -1 -5 ", + "5 2 -2 -5 ", + "5 3 -3 -5 ", + "5 4 -4 -5 ", + "6 1 -1 -6 ", + "6 2 -2 -6 ", + "6 3 -3 -6 ", + "6 4 -4 -6 ", + "6 5 -5 -6 ", + "3 2 1 -1 -2 -3 ", + "4 2 1 -1 -2 -4 ", + "4 3 1 -1 -3 -4 ", + "4 3 2 -2 -3 -4 ", + "5 2 1 -1 -2 -5 ", + "5 3 1 -1 -3 -5 ", + "5 3 2 -2 -3 -5 ", + "5 4 1 -1 -4 -5 ", + "5 4 2 -2 -4 -5 ", + "5 4 3 -3 -4 -5 ", + "6 2 1 -1 -2 -6 ", + "6 3 1 -1 -3 -6 ", + "6 3 2 -2 -3 -6 ", + "6 4 1 -1 -4 -6 ", + "6 4 2 -2 -4 -6 ", + "6 4 3 -3 -4 -6 ", + "6 5 1 -1 -5 -6 ", + "6 5 2 -2 -5 -6 ", + "6 5 3 -3 -5 -6 ", + "6 5 4 -4 -5 -6 ", + "2 2 -2 -2", + "3 3 -3 -3", + "4 4 -4 -4", + "2 2 2 -2 -2 -2", + "3 3 2 -2 -3 -3", + "3 2 2 -2 -2 -3 ", + "3 3 3 -3 -3 -3", + "4 4 2 -2 -4 -4", + "4 2 2 -2 -2 -4", + "4 4 3 -3 -4 -4", + "4 3 3 -3 -3 -4", + "4 4 3 2 -2 -3 -4 -4", + "4 3 3 2 -2 -3 -3 -4", + "4 3 2 2 -2 -2 -3 -4", + "3 3 3 2 -2 -3 -3 -3", + "3 2 2 2 -2 -2 -2 -3"}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); + } + } else if (TString(whichDefaultLabels).EqualTo("Set_1")) { + // From ~/scratch/O2/master/Labels/Set_1/labels_Set_1.root + const int nLabels = 56; // yes, because I do not care about 1-p + TString labels[nLabels] = { + "1 -1 ", + "2 -2 ", + "3 -3 ", + "4 -4 ", + "5 -5 ", + "6 -6 ", + "2 1 -1 -2 ", + "3 1 -1 -3 ", + "3 2 -2 -3 ", + "4 1 -1 -4 ", + "4 2 -2 -4 ", + "4 3 -3 -4 ", + "5 1 -1 -5 ", + "5 2 -2 -5 ", + "5 3 -3 -5 ", + "5 4 -4 -5 ", + "6 1 -1 -6 ", + "6 2 -2 -6 ", + "6 3 -3 -6 ", + "6 4 -4 -6 ", + "6 5 -5 -6 ", + "3 2 1 -1 -2 -3 ", + "4 2 1 -1 -2 -4 ", + "4 3 1 -1 -3 -4 ", + "4 3 2 -2 -3 -4 ", + "5 2 1 -1 -2 -5 ", + "5 3 1 -1 -3 -5 ", + "5 3 2 -2 -3 -5 ", + "5 4 1 -1 -4 -5 ", + "5 4 2 -2 -4 -5 ", + "5 4 3 -3 -4 -5 ", + "6 2 1 -1 -2 -6 ", + "6 3 1 -1 -3 -6 ", + "6 3 2 -2 -3 -6 ", + "6 4 1 -1 -4 -6 ", + "6 4 2 -2 -4 -6 ", + "6 4 3 -3 -4 -6 ", + "6 5 1 -1 -5 -6 ", + "6 5 2 -2 -5 -6 ", + "6 5 3 -3 -5 -6 ", + "6 5 4 -4 -5 -6 ", + "4 3 2 1 -1 -2 -3 -4 ", + "5 3 2 1 -1 -2 -3 -5 ", + "5 4 2 1 -1 -2 -4 -5 ", + "5 4 3 1 -1 -3 -4 -5 ", + "5 4 3 2 -2 -3 -4 -5 ", + "6 3 2 1 -1 -2 -3 -6 ", + "6 4 2 1 -1 -2 -4 -6 ", + "6 4 3 1 -1 -3 -4 -6 ", + "6 4 3 2 -2 -3 -4 -6 ", + "6 5 2 1 -1 -2 -5 -6 ", + "6 5 3 1 -1 -3 -5 -6 ", + "6 5 3 2 -2 -3 -5 -6 ", + "6 5 4 1 -1 -4 -5 -6 ", + "6 5 4 2 -2 -4 -5 -6 ", + "6 5 4 3 -3 -4 -5 -6 "}; + for (int l = 0; l < nLabels; l++) { + TObjString* objstr = new TObjString(labels[l].Data()); + arr->Add(objstr); + } + } else if (TString(whichDefaultLabels).EqualTo("Set_2")) { + // From ~/scratch/O2/master/Labels/Set_2/labels_Set_2.root + const int nLabels = 62; // yes, because I do not care about 1-p + TString labels[nLabels] = { + "1 -1 ", + "2 -2 ", + "3 -3 ", + "4 -4 ", + "5 -5 ", + "6 -6 ", + "2 1 -1 -2 ", + "3 1 -1 -3 ", + "3 2 -2 -3 ", + "4 1 -1 -4 ", + "4 2 -2 -4 ", + "4 3 -3 -4 ", + "5 1 -1 -5 ", + "5 2 -2 -5 ", + "5 3 -3 -5 ", + "5 4 -4 -5 ", + "6 1 -1 -6 ", + "6 2 -2 -6 ", + "6 3 -3 -6 ", + "6 4 -4 -6 ", + "6 5 -5 -6 ", + "3 2 1 -1 -2 -3 ", + "4 2 1 -1 -2 -4 ", + "4 3 1 -1 -3 -4 ", + "4 3 2 -2 -3 -4 ", + "5 2 1 -1 -2 -5 ", + "5 3 1 -1 -3 -5 ", + "5 3 2 -2 -3 -5 ", + "5 4 1 -1 -4 -5 ", + "5 4 2 -2 -4 -5 ", + "5 4 3 -3 -4 -5 ", + "6 2 1 -1 -2 -6 ", + "6 3 1 -1 -3 -6 ", + "6 3 2 -2 -3 -6 ", + "6 4 1 -1 -4 -6 ", + "6 4 2 -2 -4 -6 ", + "6 4 3 -3 -4 -6 ", + "6 5 1 -1 -5 -6 ", + "6 5 2 -2 -5 -6 ", + "6 5 3 -3 -5 -6 ", + "6 5 4 -4 -5 -6 ", + "4 3 2 1 -1 -2 -3 -4 ", + "5 3 2 1 -1 -2 -3 -5 ", + "5 4 2 1 -1 -2 -4 -5 ", + "5 4 3 1 -1 -3 -4 -5 ", + "5 4 3 2 -2 -3 -4 -5 ", + "6 3 2 1 -1 -2 -3 -6 ", + "6 4 2 1 -1 -2 -4 -6 ", + "6 4 3 1 -1 -3 -4 -6 ", + "6 4 3 2 -2 -3 -4 -6 ", + "6 5 2 1 -1 -2 -5 -6 ", + "6 5 3 1 -1 -3 -5 -6 ", + "6 5 3 2 -2 -3 -5 -6 ", + "6 5 4 1 -1 -4 -5 -6 ", + "6 5 4 2 -2 -4 -5 -6 ", + "6 5 4 3 -3 -4 -5 -6 ", + "5 4 3 2 1 -1 -2 -3 -4 -5 ", + "6 4 3 2 1 -1 -2 -3 -4 -6 ", + "6 5 3 2 1 -1 -2 -3 -5 -6 ", + "6 5 4 2 1 -1 -2 -4 -5 -6 ", + "6 5 4 3 1 -1 -3 -4 -5 -6 ", + "6 5 4 3 2 -2 -3 -4 -5 -6 "}; + 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; // c) Handle the AliEn case; // d) Handle the CCDB case; - // e) Handle the local case. + // e) Handle the local case; + // f) Clean up. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Return value: @@ -6797,15 +14994,15 @@ 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) { @@ -6824,7 +15021,7 @@ TObjArray* GetObjArrayWithLabels(const char* filePath) if (!lok) { 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, @@ -6833,7 +15030,7 @@ 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, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); @@ -6853,11 +15050,7 @@ 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())); // TBI 20250414 memory blow-up if (!oa) { LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } @@ -6879,7 +15072,7 @@ TObjArray* GetObjArrayWithLabels(const char* filePath) if (!lok) { 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, @@ -6888,7 +15081,7 @@ 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, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } @@ -6897,9 +15090,17 @@ TObjArray* GetObjArrayWithLabels(const char* filePath) 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; + // f) Clean up: + if (oaFile) { + oaFile->Close(); + delete oaFile; + oaFile = nullptr; + } + + return oa; // "292535" (local) + 294291 (ccdb) } // TObjArray* GetObjArrayWithLabels(const char *filePath) @@ -6923,10 +15124,11 @@ void GetHistogramWithCustomNUA(const char* filePath, eNUAPDF variable) // d) Handle the AliEn case; // e) Handle the CCDB case; // f) Handle the local case; - // g) The final touch. + // g) The final touch; + // h) Clone histogram and delete baseList (realising back the memory). if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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()); @@ -6952,15 +15154,15 @@ void GetHistogramWithCustomNUA(const char* filePath, eNUAPDF variable) // *) 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_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: @@ -7033,56 +15235,91 @@ void GetHistogramWithCustomNUA(const char* filePath, eNUAPDF 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__); } + + // 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; // TBI 20240501 if additional cosmetics is needed, it can be implemented here + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + } // void GetHistogramWithCustomNUA(const char* filePath, eNUAPDF variable) //============================================================ void StoreLabelsInPlaceholder() { - // Storal all Test0 labels in the temporary placeholder. + // Storal all Test0 labels in the placeholder. // a) Initialize all counters; - // 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. + // b) Fetch TObjArray with labels from an external file or from local hardwired values; + // c) Insanity check on labels; + // d) Finally, store the labels from external source into the placeholder. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __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()); + // b) Fetch TObjArray with labels from an external file or from local hardwired values: + TObjArray* oa = NULL; + if (t0.fUseDefaultLabels) { + oa = GetDefaultObjArrayWithLabels(t0.fWhichDefaultLabels.Data()); + } else { + + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! There is a large memory blow-up when calling function GetObjArrayWithLabels(...) !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + + oa = GetObjArrayWithLabels(t0.fFileWithLabels.Data()); + // TBI 20250412 There is a large memory penalty in this call, confirmed for "local" and "ccdb" cases (most likely also for "alien", but I didn't test it yet) + // a) For the "local" case, it's related to the following minimal reproducer: + // TFile *f = new TFile("tmp.root", "read"); // memory blows up by > 50 MB + // f->Close(); delete f; f = nullptr; // memory stays > 50 MB + // b) Not clear why there is a blow-up for "ccdb" case, but it can be reproduced with this line: + // Service ccdb; + // ccdb->get("somePath"); + // c) TBI 20250412 document eventually also the "alien" case here + // ... + } if (!oa) { LOGF(info, "\033[1;33m fFileWithLabels = %s \033[0m", t0.fFileWithLabels.Data()); 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(); - t0.fTest0LabelsPlaceholder = - new TH1I("fTest0LabelsPlaceholder", - Form("placeholder for all labels, %d in total", nLabels), - nLabels, 0, nLabels); - t0.fTest0LabelsPlaceholder->SetStats(kFALSE); + // c) Insanity check on labels: + int nLabels = oa->GetEntries(); + // c1) Insanity check on number of labels: + if (nLabels <= 0) { + LOGF(fatal, "\033[1;31m%s at line %d : nLabels = %d \033[0m", __FUNCTION__, __LINE__, nLabels); + } + // c2) Here I am merely checking that harmonic larger than gMaxHarmonic was not requested: + for (int e = 0; e < nLabels; e++) { + TObjArray* temp = TString(oa->At(e)->GetName()).Tokenize(" "); + for (int h = 0; h < temp->GetEntries(); h++) { + if (std::abs(TString(temp->At(h)->GetName()).Atoi()) > gMaxHarmonic) { + LOGF(info, "\033[1;31m e = %d, label = %s, gMaxHarmonic = %d\033[0m", e, temp->At(h)->GetName(), 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 e = 0; e < nLabels; e++) { + // ... - // 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++) { + // d) Finally, store the labels from external source into the placeholder: + int order = -44; + for (int e = 0; e < nLabels; e++) { TObjArray* temp = TString(oa->At(e)->GetName()).Tokenize(" "); if (!temp) { LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); @@ -7093,78 +15330,20 @@ void StoreLabelsInPlaceholder() 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(oa->At(e)->GetName()); // okay... - t0.fTest0LabelsPlaceholder->GetXaxis()->SetBinLabel( - bin++, t0.fTest0Labels[order - 1][counter[order - 1]]->Data()); - // cout<<__LINE__<<": - // "<Data()<At(e)->GetName()); // okay... counter[order - 1]++; - // cout<GetEntries()<GetXaxis()->GetNbins(); b++) { - TObjArray* temp = TString(t0.fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b)).Tokenize(" "); - for (Int_t 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), 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_t 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++) { - -} // void StoreLabelsInPlaceholder() - -//============================================================ - -Bool_t RetrieveCorrelationsLabels() -{ - // Generate the labels of all correlations of interest, i.e. retrieve them - // from TH1I *t0.fTest0LabelsPlaceholder + } // for(int e=0; eGetXaxis()->GetNbins(); - - Int_t order = -44; - for (Int_t b = 1; b <= nBins; b++) { - TObjArray* oa = TString(t0.fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b)) - .Tokenize(" "); - if (!oa) { - 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 - if (0 == order) { - 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()<(whichWeight)); } @@ -7234,8 +15421,8 @@ Double_t Weight(const Double_t& value, eWeights whichWeight) // value, integrate LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - Int_t bin = pw.fWeightsHist[whichWeight]->FindBin(value); - Double_t weight = 0.; + 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? @@ -7243,16 +15430,132 @@ Double_t Weight(const Double_t& value, eWeights whichWeight) // value, integrate 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 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? + // If I decide to implement this, remember e.g. for 2D case that all bins of type (0,1), (0,2) ... are underflow of first variable, + // and all bins of type (1,0), (2,0), ... are underflow of second variable. Analogously for overflow. + // Each of these cases, however, have different global bin! + // Total number of linearized global bins for N-dimensional sparse = (N_1 + 2) * (N_2 + 2) * ... (N_N + 2), + // where N_1 is number of bins in first dimension, etc. The offset + 2 in each case counts underflow and overflow. + // Mapping between 2D bins and linearized global bins goes as follows (for an example 2 x 3 histogram): + // 0,0 => 0 + // 1,0 => 1 + // 2,0 => 2 + // 3,0 => 3 + // 0,1 => 4 + // 1,1 => 5 + // ... + // 2,4 => 18 + // 3,4 => 19 + // So, for 2 x 3 histogram, there are (2+2) * (3+2) = 20 linearized global bins. + // Remember that I need to loop first over y dimensions, then nest inside the loop over x dimension, to achieve loop over global bins in consequtive order. + + double weight = pw.fDiffWeightsSparse[dwc]->GetBinContent(bin); + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + return weight; -} // Weight(const Double_t &value, eWeights whichWeight) // value, integrated [phi,pt,eta] weight +} // double WeightFromSparse(...) //============================================================ -Double_t DiffWeight(const Double_t& valueY, const Double_t& valueX, eqvectorKine 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. + // TBI 20250520 This function is now obsolete, use WeightFromSparse(...) instead. + + 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 @@ -7269,15 +15572,15 @@ Double_t DiffWeight(const Double_t& valueY, const Double_t& valueX, eqvectorKine // *) 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 stamenent \033[0m", __FUNCTION__, __LINE__); + 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 stamenent \033[0m", __FUNCTION__, __LINE__); + 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__); } // *) 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_t binX = res.fResultsPro[AFO_var]->FindBin(valueX); + int binX = res.fResultsPro[AFO_var]->FindBin(valueX); if (tc.fInsanityCheckForEachParticle) // enable only during debugging, as this check is computationally heavy. { if (binX < 1) { @@ -7300,8 +15603,8 @@ Double_t DiffWeight(const Double_t& valueY, const Double_t& valueX, eqvectorKine LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - Int_t 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. + 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__); @@ -7313,7 +15616,7 @@ Double_t DiffWeight(const Double_t& valueY, const Double_t& valueX, eqvectorKine } } // if(tc.fInsanityCheckForEachParticle) - Double_t diffWeight = pw.fDiffWeightsHist[AFO_diffWeight][binX - 1]->GetBinContent(bin); + 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 @@ -7321,9 +15624,13 @@ Double_t DiffWeight(const Double_t& valueY, const Double_t& valueX, eqvectorKine } } + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + return diffWeight; -} // DiffWeight(const Double_t &valueY, const Double_t &valueX, eqvectorKine variableX) +} // DiffWeight(const double &valueY, const double &valueX, eqvectorKine variableX) //============================================================ @@ -7337,10 +15644,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", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Integrated weights: @@ -7375,12 +15685,28 @@ void GetParticleWeights() // 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, "\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()); } + + // *) okay, just use this histogram with weights: SetDiffWeightsHist(phiptWeights, wPHIPT, b); } } // if (pw.fUseDiffWeights[wPHIPT]) { @@ -7388,42 +15714,211 @@ void GetParticleWeights() // 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++) { + 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, "\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_t 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // *) Return value: - Bool_t reachedMaxNumberOfEvents = kFALSE; + bool reachedMaxNumberOfEvents = false; // *) Internal validation case (special treatment): if (iv.fUseInternalValidation) { - if (eh.fEventHistograms[eNumberOfEvents][eSim][eBefore] && eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->GetBinContent(1) == static_cast(iv.fnEventsInternalValidation)) { - return kTRUE; + 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 kFALSE; + return false; } } // *) Determine from which histogram the relevant info will be taken: - Int_t rs = -44; // reconstructed or simulated + 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]) { @@ -7434,22 +15929,28 @@ Bool_t MaxNumberOfEvents(eBeforeAfter ba) // *) Okay, do the thing: switch (ba) { - case eBefore: + case eBefore: { if (eh.fEventHistograms[eNumberOfEvents][rs][eBefore] && eh.fEventHistograms[eNumberOfEvents][rs][eBefore]->GetBinContent(1) == ec.fdEventCuts[eNumberOfEvents][eMax]) { - reachedMaxNumberOfEvents = kTRUE; + reachedMaxNumberOfEvents = true; } break; - case eAfter: + } + case eAfter: { if (eh.fEventHistograms[eNumberOfEvents][rs][eAfter] && eh.fEventHistograms[eNumberOfEvents][rs][eAfter]->GetBinContent(1) == ec.fdEventCuts[eSelectedEvents][eMax]) { - reachedMaxNumberOfEvents = kTRUE; + reachedMaxNumberOfEvents = true; } break; - default: + } + 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) @@ -7459,73 +15960,86 @@ Bool_t 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // *) Print or die: switch (ba) { - case eBefore: - if (eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]) { - LOGF(info, "\033[1;32m%s : processing event %d\033[0m", __FUNCTION__, static_cast(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__, static_cast(eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->GetBinContent(1))); + 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.fVerbose) { - if (eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]) { - LOGF(info, "\033[1;32m%s : this event passed all cuts %d/%d\033[0m", __FUNCTION__, static_cast(eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1)), static_cast(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__, static_cast(eh.fEventHistograms[eNumberOfEvents][eSim][eAfter]->GetBinContent(1)), static_cast(eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->GetBinContent(1))); - } + } + 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]); } break; - default: + } + 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) + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } } // void PrintEventCounter(eBeforeAfter ba) //============================================================ -void EventCounter(eEventCounter eVar) +void EventCounterForDryRun(eEventCounterForDryRun eVar) { // Simple utility function which either fills histogram with event count, or prints its current content. - // Remark: Use only in combination with tc.fDryRun = kTRUE, otherwise I might be filling the same histogram in different member functions, there is a protection below. + // 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", __FUNCTION__); + StartFunction(__FUNCTION__); } if (!tc.fDryRun) { - LOGF(fatal, "\033[1;31m%s at line %d : for the time being, function EventCounter(...) can be safely used only for tc.fDryRun = kTRUE \033[0m", __FUNCTION__, __LINE__); + 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__); } switch (eVar) { - case eFill: + 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: + } + case ePrint: { // Print current status of event counter: - // Remark: if I am processign RecSim, the counter is corresponding to Rec. + // 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][eRec][eBefore] && eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]) { + } 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: + } + 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) -} // void EventCounter() + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + +} // void EventCounterForDryRun(eEventCounterForDryRun eVar) //============================================================ @@ -7538,46 +16052,277 @@ const char* FancyFormatting(const char* name) // 2. add additional information to defalt name (e.g. "Centrality" => "Centrality (V0M)" // 3. ... - if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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")) { + if (TString(name).EqualTo("Phi", TString::kIgnoreCase)) { fancyFormatting = "#varphi"; - } else if (TString(name).EqualTo("Pt")) { + } else if (TString(name).EqualTo("Pt", TString::kIgnoreCase)) { fancyFormatting = "p_{T}"; - } else if (TString(name).EqualTo("Eta")) { + } else if (TString(name).EqualTo("Eta", TString::kIgnoreCase)) { fancyFormatting = "#eta"; - } else if (TString(name).EqualTo("Vertex_x")) { + } else if (TString(name).EqualTo("VertexX")) { fancyFormatting = "V_{x}"; - } else if (TString(name).EqualTo("Vertex_y")) { + } else if (TString(name).EqualTo("VertexY")) { fancyFormatting = "V_{y}"; - } else if (TString(name).EqualTo("Vertex_z")) { + } else if (TString(name).EqualTo("VertexZ")) { fancyFormatting = "V_{z}"; - } else if (TString(name).EqualTo("Centrality")) { + } 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()); + fancyFormatting = Form("Centrality (%s)", tmp.ReplaceAll("CentRun2", "").Data()); // "CentRun2V0M" => "Centrality (V0M)" } else if (tmp.BeginsWith("Cent")) { - fancyFormatting = Form("Centrality (%s)", tmp.ReplaceAll("Cent", "").Data()); + 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)"; + } + + if (tc.fVerboseUtility) { + ExitFunction(__FUNCTION__); + } + + return fancyFormatting; + +} // const char* FancyFormatting(const char *name) + +//============================================================ + +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. + + // 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__); + } + + int nParticles = ebye.fSelectedTracks; + + // a) Determine the order of correlator; + 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... } - return fancyFormatting; + // 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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 -} // const char* FancyFormatting(const char *name) + } // for(int i12=0; i12GetBinContent(1); + delete profile; + profile = NULL; + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } + return finalValue; + +} // double CalculateCustomNestedLoops(TArrayI *harmonics) //============================================================ -Double_t CalculateCustomNestedLoops(TArrayI* harmonics) +double CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_variable, int bin) { - // For the specified harmonics, get the correlation from nested loops. + // !!! OBSOLETE FUNCTION !!! + + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! As of 20250529, this is an obsolete function, use double CalculateKineCustomNestedLoops(TArrayI* harmonics, eqvectorKine kineVarChoice, int bin) instead !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + + // 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; @@ -7585,30 +16330,72 @@ Double_t CalculateCustomNestedLoops(TArrayI* harmonics) // c) Return value. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } if (!harmonics) { LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); } - Int_t nParticles = ebye.fSelectedTracks; - /* TBI 20231108 enable eventually - if(fUseFixedNumberOfRandomlySelectedParticles) - { - nParticles = 0; - for(Int_t i=0;iGetSize();i++) - { - if(TMath::Abs(nl.ftaNestedLoops[0]->GetAt(i)) > 0. && TMath::Abs(nl.ftaNestedLoops[1]->GetAt(i)) > 0.){nParticles++;} - } + // *) ... + 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; + } + case AFO_CHARGE: { + qvKine = CHARGEq; + kineVarName = "charge"; + 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 (std::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_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 (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... @@ -7617,13 +16404,13 @@ Double_t CalculateCustomNestedLoops(TArrayI* harmonics) // 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); + value = std::cos(harmonics->GetAt(0) * dPhi1); weight = dW1; profile->Fill(0.5, value, weight); continue; @@ -7632,10 +16419,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2); weight = dW1 * dW2; profile->Fill(0.5, value, weight); continue; @@ -7644,10 +16431,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3); weight = dW1 * dW2 * dW3; profile->Fill(0.5, value, weight); continue; @@ -7656,10 +16443,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7668,10 +16455,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7680,10 +16467,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7692,10 +16479,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7704,10 +16491,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7716,10 +16503,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7728,10 +16515,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7740,10 +16527,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7752,10 +16539,10 @@ Double_t CalculateCustomNestedLoops(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); + value = std::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; @@ -7764,29 +16551,32 @@ Double_t CalculateCustomNestedLoops(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 CalculateCustomNestedLoops(TArrayI *harmonics) +} // double CalculateKineCustomNestedLoops(TArrayI *harmonics, eAsFunctionOf AFO_variable, int bin) //============================================================ -Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_variable, Int_t bin) +double CalculateKineCustomNestedLoops(TArrayI* harmonics, eqvectorKine kineVarChoice, 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. @@ -7796,55 +16586,35 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va // c) Return value. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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 - switch (AFO_variable) { - case AFO_PT: - qvKine = PTq; - break; - case AFO_ETA: - qvKine = ETAq; - 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 stamenent \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); - } + // TBI 20250529 add protection for b in underflow or overflow // Get the number of particles in this kine bin: - Int_t nParticles = 0; - for (Int_t i = 0; i < nl.ftaNestedLoopsKine[qvKine][bin][0]->GetSize(); i++) { - if (TMath::Abs(nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i)) > 0.) { + int nParticles = 0; + for (int i = 0; i < nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetSize(); i++) { + if (std::abs(nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i)) > 0.) { nParticles++; } } - // 'qvKine' is enum eqvectorKine: - LOGF(info, " %s: nParticles = %d, bin range = [%f,%f)", static_cast(qvKine), nParticles, res.fResultsPro[AFO_variable]->GetBinLowEdge(bin + 1), res.fResultsPro[AFO_variable]->GetBinLowEdge(bin + 2)); + // It doesn't hurt to do here insanity check on the number of particles, in case I have already calculated it independently when calculating diff. q-vectors: + if (qv.fCalculateqvectorsKineAny && qv.fqvectorEntries[kineVarChoice][bin] > 0) { // TBI 20250602 I think this chained condition is ok, but re-think nevertheless + if (!(nParticles == qv.fqvectorEntries[kineVarChoice][bin])) { + LOGF(fatal, "\033[1;31m%s at line %d : nParticles = %d, qv.fqvectorEntries[kineVarChoice][bin] = %d, kineVarChoices = %d (%s), bin = %d\033[0m", __FUNCTION__, __LINE__, nParticles, qv.fqvectorEntries[kineVarChoice][bin], static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), bin); + } + } // a) Determine the order of correlator; - Int_t order = harmonics->GetSize(); + int order = harmonics->GetSize(); if (0 == order || order > gMaxCorrelator) { - cout << __LINE__ << endl; - exit(1); + 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... @@ -7857,13 +16627,13 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va // 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.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i1); - Double_t dW1 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i1); + double dPhi1 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i1); + double dW1 = nl.ftaNestedLoopsKine[kineVarChoice][bin][1]->GetAt(i1); if (1 == order) { - value = TMath::Cos(harmonics->GetAt(0) * dPhi1); + value = std::cos(harmonics->GetAt(0) * dPhi1); weight = dW1; profile->Fill(0.5, value, weight); continue; @@ -7872,10 +16642,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i2 == i1) { continue; } - Double_t dPhi2 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i2); - Double_t dW2 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i2); + double dPhi2 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i2); + double dW2 = nl.ftaNestedLoopsKine[kineVarChoice][bin][1]->GetAt(i2); if (2 == order) { - value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2); + value = std::cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2); weight = dW1 * dW2; profile->Fill(0.5, value, weight); continue; @@ -7884,10 +16654,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i3 == i1 || i3 == i2) { continue; } - Double_t dPhi3 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i3); - Double_t dW3 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i3); + double dPhi3 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i3); + double dW3 = nl.ftaNestedLoopsKine[kineVarChoice][bin][1]->GetAt(i3); if (3 == order) { - value = TMath::Cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3); + value = std::cos(harmonics->GetAt(0) * dPhi1 + harmonics->GetAt(1) * dPhi2 + harmonics->GetAt(2) * dPhi3); weight = dW1 * dW2 * dW3; profile->Fill(0.5, value, weight); continue; @@ -7896,10 +16666,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i4 == i1 || i4 == i2 || i4 == i3) { continue; } - Double_t dPhi4 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i4); - Double_t dW4 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i4); + double dPhi4 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i4); + double dW4 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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; @@ -7908,10 +16678,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i5 == i1 || i5 == i2 || i5 == i3 || i5 == i4) { continue; } - Double_t dPhi5 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i5); - Double_t dW5 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i5); + double dPhi5 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i5); + double dW5 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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; @@ -7920,10 +16690,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i6 == i1 || i6 == i2 || i6 == i3 || i6 == i4 || i6 == i5) { continue; } - Double_t dPhi6 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i6); - Double_t dW6 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i6); + double dPhi6 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i6); + double dW6 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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; @@ -7932,10 +16702,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i7 == i1 || i7 == i2 || i7 == i3 || i7 == i4 || i7 == i5 || i7 == i6) { continue; } - Double_t dPhi7 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i7); - Double_t dW7 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i7); + double dPhi7 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i7); + double dW7 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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; @@ -7944,10 +16714,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i8 == i1 || i8 == i2 || i8 == i3 || i8 == i4 || i8 == i5 || i8 == i6 || i8 == i7) { continue; } - Double_t dPhi8 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i8); - Double_t dW8 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i8); + double dPhi8 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i8); + double dW8 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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; @@ -7956,10 +16726,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i9 == i1 || i9 == i2 || i9 == i3 || i9 == i4 || i9 == i5 || i9 == i6 || i9 == i7 || i9 == i8) { continue; } - Double_t dPhi9 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i9); - Double_t dW9 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i9); + double dPhi9 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i9); + double dW9 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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; @@ -7968,10 +16738,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va if (i10 == i1 || i10 == i2 || i10 == i3 || i10 == i4 || i10 == i5 || i10 == i6 || i10 == i7 || i10 == i8 || i10 == i9) { continue; } - Double_t dPhi10 = nl.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i10); - Double_t dW10 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i10); + double dPhi10 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i10); + double dW10 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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; @@ -7980,10 +16750,10 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va 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.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i11); - Double_t dW11 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i11); + double dPhi11 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i11); + double dW11 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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; @@ -7992,144 +16762,611 @@ Double_t CalculateKineCustomNestedLoops(TArrayI* harmonics, eAsFunctionOf AFO_va 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.ftaNestedLoopsKine[qvKine][bin][0]->GetAt(i12); - Double_t dW12 = nl.ftaNestedLoopsKine[qvKine][bin][1]->GetAt(i12); + double dPhi12 = nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->GetAt(i12); + double dW12 = nl.ftaNestedLoopsKine[kineVarChoice][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); + value = std::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 + // ... 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 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) + +//============================================================ + +template +void DetermineCentrality(T const& collision) +{ + // Determine collision centrality. + // For simulated data, I determine ebye.ImpactParameter here as well. + + // TBI 20250429 there it a bit of code bloat here in this function + + // a) For real data, determine centrality from default centrality estimator; + // b) For simulated data, determine centrality directly from impact parameter + store impact parameter; + // c) Same as a), just for converted Run 2 data; + // 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; + // h) Print centrality for the audience... + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + // a) For real data, determine centrality from default centrality estimator: + 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.fsEventCuts[eCentralityEstimator].EqualTo("centFV0A", TString::kIgnoreCase)) { + ebye.fCentrality = collision.centFV0A(); + } 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, "\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 + } + + // ... + + // ... and corresponding MC truth simulated: + if constexpr (rs == eRecAndSim) { + + // *) Impact parameter: + ebye.fImpactParameter = collision.mcCollision().impactParameter(); // has to be called before DetermineSimulatedCentrality(); + + // *) Centrality for simulated data in Run 3: + ebye.fCentralitySim = DetermineSimulatedCentrality(); + + // ... + + } // if constexpr (rs == eRecAndSim) + + } // if constexpr (rs == eRec || rs == eRecAndSim || rs == eQA) + + // b) For simulated data, determine centrality directly from impact parameter + store impact parameter: + if constexpr (rs == eSim) { + ebye.fImpactParameter = collision.mcCollision().impactParameter(); // has to be called before DetermineSimulatedCentrality(); + ebye.fCentrality = DetermineSimulatedCentrality(); // yes, I use here ebye.fCentrality, not ebye.fCentralitySim + } + + // c) Same as a), just for converted Run 2 data: + if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2) { + if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2V0M", TString::kIgnoreCase)) { + ebye.fCentrality = collision.centRun2V0M(); + } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2SPDTracklets", TString::kIgnoreCase)) { + ebye.fCentrality = collision.centRun2SPDTracklets(); + } else { + 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(); + } + + // ... + + // ... and corresponding MC truth simulated: + + if constexpr (rs == eRecAndSim_Run2) { + + // *) Impact parameter: + ebye.fImpactParameter = collision.mcCollision().impactParameter(); // has to be called before DetermineSimulatedCentrality(); + + // *) Centrality for simulated data in Run 3: + ebye.fCentralitySim = DetermineSimulatedCentrality(); + + // ... + + } // if constexpr (rs == eRecAndSim_Run2) + } + + // d) Same as b), just for converted Run 2 data: + if constexpr (rs == eSim_Run2) { + ebye.fImpactParameter = collision.mcCollision().impactParameter(); // has to be called before DetermineSimulatedCentrality(); + ebye.fCentrality = DetermineSimulatedCentrality(); // yes, I use here ebye.fCentrality, not ebye.fCentralitySim + } + + // e) Same as a), just for converted Run 1 data: + if constexpr (rs == eRec_Run1 || rs == eRecAndSim_Run1) { + 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.fsEventCuts[eCentralityEstimator].EqualTo("CentRun2SPDTracklets", TString::kIgnoreCase)) { + // ebye.fCentrality = collision.centRun2SPDTracklets(); // TBI 20240224 enable when I add support for RecAndSim_Run1 + } else { + LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); + } + + // ... and corresponding MC truth simulated: + + if constexpr (rs == eRecAndSim_Run1) { + + // *) Impact parameter: + ebye.fImpactParameter = collision.mcCollision().impactParameter(); // has to be called before DetermineSimulatedCentrality(); + + // *) Centrality for simulated data in Run 3: + ebye.fCentralitySim = DetermineSimulatedCentrality(); + + // ... + + } // if constexpr (rs == eRecAndSim_Run1) + } + + // f) Same as b), just for converted Run 1 data: + if constexpr (rs == eSim_Run1) { + ebye.fImpactParameter = collision.mcCollision().impactParameter(); // has to be called before DetermineSimulatedCentrality(); + ebye.fCentrality = DetermineSimulatedCentrality(); // yes, I use here ebye.fCentrality, not ebye.fCentralitySim + } + + // g) Test case: + if constexpr (rs == eTest) { + ebye.fCentrality = static_cast(gRandom->Uniform(0., 100.)); + } + + // h) Print centrality for the audience...: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m ebye.fCentrality = %f\033[0m", ebye.fCentrality); + LOGF(info, "\033[1;32m ebye.fCentralitySim = %f\033[0m", ebye.fCentralitySim); + ExitFunction(__FUNCTION__); + } + +} // template void DetermineCentrality(T const& collision) - } // for(int i12=0; i12GetBinContent(1); - delete profile; - profile = NULL; - return finalValue; +float DetermineSimulatedCentrality() +{ + // Determine centrality at generated/simulated level, just using impact parameter. + // This is a helper function for DetermineCentrality(), to reduce the code bloat there. I do not anticipate calling this function anywhere alse at the moment. + + // Algorithm: + // 1. Ideally, I simply fetch this centrality from the table HepMCHeavyIons via getter .centrality(); + // 2. If that info is not available, I calculate the simulated centrality here temporarily manually from impact parameter + sigma_inel; + // 3. From process switches I can see whether I am processing Run 3, Run 2 or Run 1 data, for collision system I support at the moment only Pb+Pb. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + + float lSimulatedCentrality = -1.; + float lSigmaInel = -1.; + + if (tc.fProcess[eProcessHepMChi]) { + // I have extracted already by this point simulated centrality from HepMCHeavyIons and stored it in ebye.fCentralitySim: + + // TBI 20250429 when I merge eProcessHepMChi with other RecSim process switches, I will have to refurbish the code here + + lSimulatedCentrality = ebye.fCentralitySim; + + } else if (tc.fProcess[eGenericRecSim] || tc.fProcess[eGenericSim]) { + + LOGF(warning, "\033[1;33m%s at line %d : Simulated centrality is calculated manually for the time being from impact parameter. Results make sense only for Pb+Pb at Run 3, Run 2 and Run 1 energies, other cases are not supported here (yet)\033[0m\n", __FUNCTION__, __LINE__); + + // Algorithm: Temporarily, I calculate centrality manually for simulated data directly from impact parameter as follows: + + // centrality(b) = Pi * b^2 / sigma_inel , where e.g. I take sigma_inel = 7.67 for Pb+Pb at 5.02 TeV, and analogously for other collision systems and energies + + if (tc.fProcess[eProcessRecSim] || tc.fProcess[eSim]) { + // Pb+Pb in Run 3: + lSigmaInel = 7.71; // interpolation, see Slide 3 in DDC presentation https://indico.cern.ch/event/1326916/ + } else if (tc.fProcess[eProcessRecSim_Run2] || tc.fProcess[eSim_Run2]) { + // Pb+Pb in Run 2: + lSigmaInel = 7.67; // for 5.02 TeV, see Slide 3 in DDC presentation https://indico.cern.ch/event/1326916/ + Run 2 paper https://arxiv.org/abs/2204.10148 + } else if (tc.fProcess[eProcessRecSim_Run1] || tc.fProcess[eSim_Run1]) { + // Pb+Pb in Run 1: + lSigmaInel = 7.55; // see Slide 3 in DDC presentation https://indico.cern.ch/event/1326916/ + Run 1 multiplicity paper https://arxiv.org/abs/1301.4361 + } else { + LOGF(fatal, "\033[1;31m%s at line %d : this branch is not supported/validated yet\033[0m", __FUNCTION__, __LINE__); + } + + // okay, I have SigmaInel for this collision system and energy, calculate centrality: + float b = ebye.fImpactParameter; + if (b < 0.) { + LOGF(warning, "\033[1;31m%s at line %d : b < 0. => did you forget to calculate ebye.fImpactParameter before calling DetermineSimulatedCentrality() ? Or you are processing Monte Carlo dataset where IP was not stored, i.e. it's set to -999 (e.g. in LHC21i6a) ? Setting lSimulatedCentrality = -1. and simply continuing... \033[0m", __FUNCTION__, __LINE__); + lSimulatedCentrality = -1.; + } else { + lSimulatedCentrality = o2::constants::math::PI * std::pow(b, 2.) / lSigmaInel; // finally, calculate true simulated centrality directly from impact parameter + } + } else { + LOGF(fatal, "\033[1;31m%s at line %d : this branch is not supported/validated yet\033[0m", __FUNCTION__, __LINE__); + } + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } -} // Double_t CalculateKineCustomNestedLoops(TArrayI *harmonics, eAsFunctionOf AFO_variable, Int_t bin) + return lSimulatedCentrality; + +} // float DetermineSimulatedCentrality() //============================================================ template -void DetermineCentrality(T const& collision) +void DetermineOccupancy(T const& collision) { - // Determine collision centrality. + // Determine collision occupancy. - // a) For real data, determine centrality from default centrality estimator; - // b) For simulated data, determine centrality directly from impact parameter; - // c) Same as a), just for converted Run 2 data; - // 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. + // 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) { - 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.fsEventCuts[eCentralityEstimator].EqualTo("centFT0M", TString::kIgnoreCase)) { - ebye.fCentrality = collision.centFT0M(); - } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("CentFV0A", TString::kIgnoreCase)) { - ebye.fCentrality = collision.centFV0A(); - } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("CentNTPV", TString::kIgnoreCase)) { - ebye.fCentrality = collision.centNTPV(); + // 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 : centrality estimator = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); + 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.fCentrality[eCentFT0M] = collision.centFT0M(); - qa.fCentrality[eCentFV0A] = collision.centFV0A(); - qa.fCentrality[eCentNTPV] = collision.centNTPV(); + 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.; + } } + } - // TBI 20240120 I could also here access also corresponding simulated centrality from impact parameter, if available through collision.has_mcCollision() + // c) Print occupancy for the audience...: + if (tc.fVerbose) { + LOGF(info, "\033[1;32m ebye.fOccupancy = %f\033[0m", ebye.fOccupancy); + ExitFunction(__FUNCTION__); } - // b) For simulated data, determine centrality directly from impact parameter: - if constexpr (rs == eSim) { - ebye.fCentrality = -44.; // TBI 20240120 add support eventualy +} // 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__); } - // c) Same as a), just for converted Run 2 data: - if constexpr (rs == eRec_Run2 || rs == eRecAndSim_Run2) { - // Local convention for name of centrality estimator: use the same name as the getter, case insensitive. - if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2V0M", TString::kIgnoreCase)) { - ebye.fCentrality = collision.centRun2V0M(); - } else if (ec.fsEventCuts[eCentralityEstimator].EqualTo("centRun2SPDTracklets", TString::kIgnoreCase)) { - ebye.fCentrality = collision.centRun2SPDTracklets(); - } else { - LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); + 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. + + // a1) Determine interaction rate only for eRec: + if (ec.fUseEventCuts[eInteractionRate] || qa.fFillQAEventHistograms2D || qa.fFillQACorrelationsVsInteractionRateVsProfiles2D || (mupa.fCalculateCorrelations && mupa.fCalculateCorrelationsAsFunctionOf[AFO_INTERACTIONRATE]) || (t0.fCalculateTest0 && t0.fCalculateTest0AsFunctionOf[AFO_INTERACTIONRATE]) || (es.fCalculateEtaSeparations && es.fCalculateEtaSeparationsAsFunctionOf[AFO_INTERACTIONRATE])) { + + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! There is a large memory blow-up of ~130 MB when calling mRateFetcher.fetch(...) !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + + double hadronicRate = mRateFetcher.fetch(ccdb.service, static_cast(bc.timestamp()), static_cast(bc.runNumber()), "ZNC hadronic") * 1.e-3; // TBI 20250414 memory blow-up + 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. + } + } // if(...) + + // a2) Determine the current run duration: + // TBI 20250107 I could move this to a separate function? + // TBI 20250415 I do not see any memory penalty here, so I keep it + 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])); } - // QA: - if (qa.fFillQAEventHistograms2D) { // TBI 20240515 this flag is too general here, I need to make it more specific - qa.fCentrality[eCentRun2V0M] = collision.centRun2V0M(); - qa.fCentrality[eCentRun2SPDTracklets] = collision.centRun2SPDTracklets(); + + } 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() - // TBI 20240120 I could also here access also corresponding simulated centrality from impact parameter, if available through collision.has_mcCollision() + if (tc.fVerbose) { + StartFunction(__FUNCTION__); } - // d) Same as b), just for converted Run 2 data: - if constexpr (rs == eSim_Run2) { - ebye.fCentrality = -44.; // TBI 20240120 add support eventualy + ebye.fVz = collision.posZ(); + + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } - // e) Same as a), just for converted Run 1 data: - if constexpr (rs == eRec_Run1 || rs == eRecAndSim_Run1) { - 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.fsEventCuts[eCentralityEstimator].EqualTo("CentRun2SPDTracklets", TString::kIgnoreCase)) { - // ebye.fCentrality = collision.centRun2SPDTracklets(); // TBI 20240224 enable when I add support for RecAndSim_Run1 - } else { - LOGF(fatal, "\033[1;31m%s at line %d : centrality estimator = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, ec.fsEventCuts[eCentralityEstimator].Data()); +} // 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 } - // TBI 20240120 I could also here access also corresponding simulated centrality from impact parameter, if available through collision.has_mcCollision() + + // ... + + // *) 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.; } - // f) Same as b), just for converted Run 1 data: - if constexpr (rs == eSim_Run1) { - 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. + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); + } // if (tc.fVerbose) { + +} // template void DetermineQAThingies(T1 const& collision, T2 const&) + +//============================================================ + +void ProcessHepMCHeavyIons(aod::HepMCHeavyIon const& hep) +{ + // Process extra MC info from HepMCHeavyIons only in this function. + // See documentation at https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + + LOGF(info, "\033[1;32m hep.mcCollisionId() = %d\033[0m", hep.mcCollisionId()); + LOGF(info, "\033[1;32m hep.centrality() = %f\033[0m", hep.centrality()); // TBI 20250428 set to -1 in LHC24g3 + LOGF(info, "\033[1;32m hep.eccentricity() = %f\033[0m", hep.eccentricity()); // TBI 20250428 set to 0 in LHC24g3 + LOGF(info, "\033[1;32m hep.sigmaInelNN() = %f\033[0m", hep.sigmaInelNN()); // TBI 20250428 set to 0 in LHC24g3 + LOGF(info, "\033[1;32m hep.eventPlaneAngle() = %f\033[0m", hep.eventPlaneAngle()); // TBI 20250428 set to 0 in LHC24g3, but stored correctly in McCollisions + LOGF(info, "\033[1;32m hep.impactParameter() = %f\033[0m\n", hep.impactParameter()); // stored correctly both in HepMCHeavyIons and McCollisions + + // *) Centrality at generated level: + ebye.fCentralitySim = hep.centrality(); + if (ebye.fCentralitySim < 0. || ebye.fCentralitySim > 100.) { + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! ebye.fCentralitySim = %f, this info is still not stored in the table HepMCHeavyIons !!!! WARNING !!!! \033[0m\n", __FUNCTION__, __LINE__, ebye.fCentralitySim); } - // g) Test case: - if constexpr (rs == eTest) { - ebye.fCentrality = gRandom->Uniform(0., 100.); + // ... TBI 20240429 as soon as HepMCHeavyIons data is stored filled in Monte Carlo datasets, ctd. here + +} // void ProcessHepMCHeavyIons(aod::HepMCHeavyIon const& hep) + +//============================================================ + +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)); } - // *) 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 DetermineEventCounters() //============================================================ -void RandomIndices(Int_t nTracks) +void RandomIndices(int nTracks) { // Randomize indices using Fisher-Yates algorithm. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } if (nTracks < 1) { @@ -8139,24 +17376,28 @@ 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_t nTracks) +} // void RandomIndices(int nTracks) //============================================================ template void BanishmentLoopOverParticles(T const& tracks) { - // This is the quick banishment loop over particles, as a support for eSelectedTracks cut. + // 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. @@ -8168,7 +17409,7 @@ void BanishmentLoopOverParticles(T const& tracks) // at the end with central data member ebye.fSelectedTracks if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // *) If random access of tracks from collection is requested, use Fisher-Yates algorithm to generate random indices: @@ -8180,7 +17421,7 @@ void BanishmentLoopOverParticles(T const& tracks) } // *) Counter of selected tracks in the current event: - Int_t lSelectedTracks = 0; // I could reset and reuse here ebye.fSelectedTracks, but it's safer to use separate local variable, as I can did additional insanity checks here + 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 @@ -8191,7 +17432,7 @@ void BanishmentLoopOverParticles(T const& tracks) 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.): @@ -8208,21 +17449,24 @@ void BanishmentLoopOverParticles(T const& tracks) // } // *) Particle cuts: - if (!ParticleCuts(track, eCut)) { // Main call for event cuts. + if (!ParticleCuts(track, eCut)) { // Main call for particle cuts. continue; // not return!! } - // *) Increase the local selected particle counter: - lSelectedTracks++; - // *) Banish particle histograms after particle cuts: - if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D) { + if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D || qa.fFillQAParticleHistograms2D) { FillParticleHistograms(track, eAfter, -1); // with negative weight -1, I effectively remove the previous fill for this track } - // *) Break the loop if fixed number of particles is taken randomly from each event (use always in combination with tc.fUseFisherYates = kTRUE): + // *) 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); + LOGF(info, "%s : Breaking the loop over particles, since requested fixed number of %d particles was reached", __FUNCTION__, tc.fFixedNumberOfRandomlySelectedTracks); break; } @@ -8230,7 +17474,11 @@ void BanishmentLoopOverParticles(T const& 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 \033[0m", __FUNCTION__, __LINE__, 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) { @@ -8245,7 +17493,7 @@ void PrintCutCounterContent() // b) Print or die. if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // a) Insanity checks: @@ -8254,50 +17502,103 @@ void PrintCutCounterContent() } // b) Print or die: - for (Int_t rs = 0; rs < 2; rs++) // reco/sim + for (int rs = 0; rs < 2; rs++) // reco/sim { - for (Int_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter + 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_t bin = 1; bin <= ec.fEventCutCounterHist[rs][cc]->GetNbinsX(); bin++) { + 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_t cc = 0; cc < eCutCounter_N; cc++) // enum eCutCounter - } // for (Int_t rs = 0; rs < 2; rs++) // reco/sim + } // 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_t lineNumber) +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_t 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 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", __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", static_cast(eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1)), sBailOutFile.Data()); @@ -8306,11 +17607,11 @@ void BailOut() // *) 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(). + // 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); @@ -8321,27 +17622,41 @@ void BailOut() 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->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: - 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", __FUNCTION__, __LINE__, sBailOutFile.Data()); + 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() +} // void BailOut(bool finalBailout = false) //============================================================ -void FillQvector(const Double_t& dPhi, const Double_t& dPt, const Double_t& dEta) +void FillQvector(const double& dPhi, const double& dPt, const double& dEta) { // Fill integrated Q-vector. // Example usage: this->FillQvector(dPhi, dPt, dEta); @@ -8350,17 +17665,17 @@ void FillQvector(const Double_t& dPhi, const Double_t& dPt, const Double_t& dEta // 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) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + 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_t wPhi = 1.; // integrated phi weight - Double_t wPt = 1.; // integrated pt weight - Double_t wEta = 1.; // integrated eta weight - Double_t wToPowerP = 1.; // weight raised to power p + 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); @@ -8368,48 +17683,225 @@ void FillQvector(const Double_t& dPhi, const Double_t& dPt, const Double_t& dEta 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[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 = std::pow(wPhi * wPt * wEta, wp); + qv.fQvector[h][wp] += TComplex(wToPowerP * std::cos(h * dPhi), wToPowerP * std::sin(h * dPhi)); // Q-vector with weights + } else { + qv.fQvector[h][wp] += TComplex(std::cos(h * dPhi), std::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 * std::cos((h + 1) * dPhi), wPhi * wPt * wEta * std::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 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]) - if (pw.fUseWeights[wPT]) { - wPt = Weight(dPt, wPT); // corresponding pt weight + // *) 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(fatal, "dPt = %f\nwPt = %f", dPt, wPt); + 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.fUseWeights[wPT]) + } // if(pw.fUseDiffPtWeights[wPtPtAxis]) - if (pw.fUseWeights[wETA]) { - wEta = Weight(dEta, wETA); // corresponding eta weight + // *) 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(fatal, "dEta = %f\nwEta = %f", dEta, wEta); + 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.fUseWeights[wETA]) + } // if(pw.fUseDiffEtaWeights[wEtaEtaAxis]) 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)); // Q-vector with weights + 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 = std::pow(wPhi * wPt * wEta, wp); + qv.fQvector[h][wp] += TComplex(wToPowerP * std::cos(h * dPhi), wToPowerP * std::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 + qv.fQvector[h][wp] += TComplex(std::cos(h * dPhi), std::sin(h * dPhi)); // bare Q-vector without weights } - } // for(Int_t 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 * std::cos((h + 1) * dPhi), wPhi * wPt * wEta * std::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 FillQvector(const Double_t& dPhi, const Double_t& dPt, const Double_t& dEta) +} // 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.) { + // !!! OBSOLETE FUNCTION (as of 20250527) !!! + + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! As of 20250527, this is an obsolete function, use FillqvectorNdim(...) and FillqvectorNdimFromSparse(...) instead !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + // 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) + + // Remark: As of 20250527, this function is obsolete, and it's superseeded by more general functions: + // a) void FillqvectorNdim(...) (without particle weights) + // b) void FillqvectorNdimFromSparse(...) (with particle weights) if (tc.fVerboseForEachParticle) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); + StartFunction(__FUNCTION__); } // *) Mapping between enum's "eqvectorKine" on one side, and "eAsFunctionOf", "eWeights" and "eDiffWeights" on the other: @@ -8418,34 +17910,43 @@ void Fillqvector(const Double_t& dPhi, const Double_t& kineVarValue, eqvectorKin 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_diffWeight = wPHIPT; // TBI 20250215 this is now obsolete, see the comment in enum break; - case ETAq: + } + case ETAq: { AFO_var = AFO_ETA; AFO_weight = wETA; - AFO_diffWeight = wPHIETA; + AFO_diffWeight = wPHIETA; // TBI 20250215 this is now obsolete, see the comment in enum + break; + } + case CHARGEq: { + AFO_var = AFO_CHARGE; + AFO_weight = wCHARGE; + AFO_diffWeight = wPHICHARGE; // TBI 20250215 this is now obsolete, see the comment in enum break; - default: + } + 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 stamenent \033[0m", __FUNCTION__, __LINE__); + 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 stamenent \033[0m", __FUNCTION__, __LINE__); + 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 stamenent \033[0m", __FUNCTION__, __LINE__); + 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); // 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 @@ -8454,8 +17955,8 @@ void Fillqvector(const Double_t& dPhi, const Double_t& kineVarValue, eqvectorKin } // *) 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_weight); // corresponding e.g. pt or eta weight if (!(kineVarWeight > 0.)) { @@ -8466,7 +17967,7 @@ void Fillqvector(const Double_t& dPhi, const Double_t& kineVarValue, eqvectorKin // *) 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, kineVarChoice); // corresponding differential phi weight as a function of e.g. pt or eta if (!(diffPhiWeightsForThisKineVar > 0.)) { @@ -8476,194 +17977,625 @@ void Fillqvector(const Double_t& dPhi, const Double_t& kineVarValue, eqvectorKin } // 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]) { // 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 + wToPowerP = std::pow(diffPhiWeightsForThisKineVar * kineVarWeight, wp); + qv.fqvector[kineVarChoice][bin - 1][h][wp] += TComplex(wToPowerP * std::cos(h * dPhi), wToPowerP * std::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(std::cos(h * dPhi), std::sin(h * dPhi)); // bare q-vector without weights + } + } // for(int wp=0;wpAddAt(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 + + // *) 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 + // TBI 20250616 I cannot use this any longer, after i added one more dimension + for (int h = 0; h < gMaxHarmonic; h++) { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + // qv.fqabVector[0][bin - 1][h][e] += TComplex(diffPhiWeightsForThisKineVar * kineVarWeight * std::cos((h + 1) * dPhi), diffPhiWeightsForThisKineVar * kineVarWeight * std::sin((h + 1) * dPhi)); // TBI 20250616 I cannot use this any longer, after I added one more dimension to qv.fqabVector + } + } // 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 + // TBI 20250616 I cannot use this any longer, after i added one more dimension + for (int h = 0; h < gMaxHarmonic; h++) { + { + if (es.fEtaSeparationsSkipHarmonics[h]) { + continue; + } + // qv.fqabVector[1][bin - 1][h][e] += TComplex(diffPhiWeightsForThisKineVar * kineVarWeight * std::cos((h + 1) * dPhi), diffPhiWeightsForThisKineVar * kineVarWeight * std::sin((h + 1) * dPhi)); // Remark: I can hardwire linear weight like this only for 2-p correlation // TBI 20250616 I cannot use this any longer, after I added one more dimension to qv.fqabVector + } + } // 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) + +//============================================================ + +eAsFunctionOf AfoKineMap1D(eqvectorKine kineVarChoice) +{ + // Simple utility function to map for the 1-dimensional case eqvectorKine into eAsFunctionOf. + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + } + + eAsFunctionOf AFO_var = eAsFunctionOf_N; + + switch (kineVarChoice) { + + case PTq: { + AFO_var = AFO_PT; + break; + } + + case ETAq: { + AFO_var = AFO_ETA; + break; + } + + case CHARGEq: { + AFO_var = AFO_CHARGE; + break; + } + + // ... + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : this kineVarChoice = %d is not supported yet for 1D case. \033[0m", __FUNCTION__, __LINE__, static_cast(kineVarChoice)); + break; + } + + } // switch(kineVarChoice) + + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } + + return AFO_var; + +} // eAsFunctionOf AfoKineMap1D(eqvectorKine kineVarChoice) + +//============================================================ + +eAsFunctionOf2D AfoKineMap2D(eqvectorKine kineVarChoice) +{ + // Simple utility function to map for the 2-dimensional case eqvectorKine into eAsFunctionOf2D. + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + } + + eAsFunctionOf2D AFO_var = eAsFunctionOf2D_N; + + switch (kineVarChoice) { + + case PT_ETAq: { + AFO_var = AFO_PT_ETA; + break; + } + + case PT_CHARGEq: { + AFO_var = AFO_PT_CHARGE; + break; + } + + case ETA_CHARGEq: { + AFO_var = AFO_ETA_CHARGE; + break; + } + + // ... + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : this kineVarChoice = %d is not supported yet for 2D case. \033[0m", __FUNCTION__, __LINE__, static_cast(kineVarChoice)); + break; + } + + } // switch(kineVarChoice) + + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } + + return AFO_var; + +} // eAsFunctionOf2D AfoKineMap2D(eqvectorKine kineVarChoice) + +//============================================================ + +eAsFunctionOf3D AfoKineMap3D(eqvectorKine kineVarChoice) +{ + // Simple utility function to map for the 3-dimensional case eqvectorKine into eAsFunctionOf3D. + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + } + + eAsFunctionOf3D AFO_var = eAsFunctionOf3D_N; + + switch (kineVarChoice) { + + case PT_ETA_CHARGEq: { + AFO_var = AFO_PT_ETA_CHARGE; + break; + } + + // ... + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : this kineVarChoice = %d is not supported yet for 3D case. \033[0m", __FUNCTION__, __LINE__, static_cast(kineVarChoice)); + break; + } + + } // switch(kineVarChoice) + + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } + + return AFO_var; + +} // eAsFunctionOf3D AfoKineMap3D(eqvectorKine kineVarChoice) + +//============================================================ + +TString StringKineMap(eqvectorKine kineVarChoice) +{ + // Simple utility function to map eqvectorKine into string. + + // Example: StringKineMap(PTq).Data() => prints "vs. pt" + + if (tc.fVerboseForEachParticle) { + StartFunction(__FUNCTION__); + } + + TString s = ""; + + switch (kineVarChoice) { + + case PTq: { + s = "vs. pt"; + break; + } + + case ETAq: { + s = "vs. eta"; + break; + } + + case CHARGEq: { + s = "vs. charge"; + break; + } + + case PT_ETAq: { + s = "vs. pt vs. eta"; + break; + } + + case PT_CHARGEq: { + s = "vs. pt vs. charge"; + break; + } + + case ETA_CHARGEq: { + s = "vs. eta vs. charge"; + break; + } + + case PT_ETA_CHARGEq: { + s = "vs. pt vs. eta vs. charge"; + break; + } + + // ... + + 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) + + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } + + return s; + +} // TString StringKineMap(eqvectorKine kineVarChoice) + +//============================================================ + +void FillqvectorNdim(const double& dPhi, double* kineVarValues, int Ndim, eqvectorKine kineVarChoice, const double& dEta = 0.) +{ + // Fill differential q-vector in N dimensions, calculated vs. N generic kinematic variables, + // and using only the unit particle weights (for non-unit weights, there is FillqvectorNdimFromSparse(...)). + // Here "kine" originally meant vs. pt or vs. eta, now it's general. + // For more than 1 dimension, e.g. vs. (pt, eta), "kineVarChoice" corresponds to linearized 2D case, in an analogy with "global bin" structure for multidimensional histograms. + + // Remark 0: "kineVarValues" is now an array, e.g. for qvector vs. (pt, eta), it holds pt and eta of a particle. Ndim is dimensionality of that array. + // Remark 1: The last argument "dEta" is meant to be used only for fqabVector (I need dEta of particle to decide whether particle is added to qa or qb) + // Remark 2: "bin" is always mean to be "linearized global bin", therefore I changed indexing here from "bin-1" to "bin" + + // Example - the standard 1D case: + // double kineArr[1] = {dPt}; + // this->FillqvectorNdim(dPhi, kineArr, 1, PTq); // differential q-vector vs. pt + + // Example - the 2D case: + // double kineArr[2] = {dPt, dEta}; + // this->FillqvectorNdim(dPhi, kineArr, 2, PT_ETAq); // differential q-vector vs. (pt, eta) + + // Example - the 3D case: + // double kineArr[3] = {dPt, dEta, dCharge}; + // this->FillqvectorNdim(dPhi, kineArr, 3, PT_ETA_CHARGEq); // differential q-vector vs. (pt, eta, charge) + + // Example - the 1D case, pt dependence with eta separations: + // double kineArr[1] = {dPt}; + // this->FillqvectorNdim(dPhi, kineArr, 1, 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) { + StartFunction(__FUNCTION__); + } + + // This is the linearized global bin, the 2nd index of fqvector[...][gMaxNoBinsKine][...][...], it shall work transparently for 1D, 2D, 3D, etc... + // Yes, it is also the 3rd index of fqabVector[...][...][gMaxNoBinsKine][...][...] + int bin = -1; + + switch (Ndim) { + + case 1: { + eAsFunctionOf AFO_var = AfoKineMap1D(kineVarChoice); + if (res.fResultsPro[AFO_var]) { + bin = res.fResultsPro[AFO_var]->FindBin(kineVarValues[0]); // this is linearized 'global bin', for 1D it's the same as ordinary bin + + // TBI 20250528 check if the check below is computationally heavy. If so, add the flag tc.fInsanityCheckForEachParticle here. + if (res.fResultsPro[AFO_var]->IsBinUnderflow(bin) || res.fResultsPro[AFO_var]->IsBinOverflow(bin)) { + LOGF(fatal, "\033[1;31m%s at line %d : kineVarChoice = %d (%s), kineVarValues[0] = %f is in bin = %d, which is either underflow or overflow.\033[0m", __FUNCTION__, __LINE__, static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), kineVarValues[0], bin); + } + } + break; + } + + case 2: { + eAsFunctionOf2D AFO_var = AfoKineMap2D(kineVarChoice); + if (res.fResultsPro2D[AFO_var]) { + bin = res.fResultsPro2D[AFO_var]->FindBin(kineVarValues[0], kineVarValues[1]); // this is linearized 'global bin' + + // TBI 20250528 check if the check below is computationally heavy. If so, add the flag tc.fInsanityCheckForEachParticle here. + if (res.fResultsPro2D[AFO_var]->IsBinUnderflow(bin) || res.fResultsPro2D[AFO_var]->IsBinOverflow(bin)) { + LOGF(fatal, "\033[1;31m%s at line %d : kineVarChoice = %d (%s), kineVarValues[0] = %f, kineVarValues[1] = %f is in global bin = %d, which is either underflow or overflow.\033[0m", __FUNCTION__, __LINE__, static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), kineVarValues[0], kineVarValues[1], bin); + } + } + break; + } + + case 3: { + eAsFunctionOf3D AFO_var = AfoKineMap3D(kineVarChoice); + if (res.fResultsPro3D[AFO_var]) { + bin = res.fResultsPro3D[AFO_var]->FindBin(kineVarValues[0], kineVarValues[1], kineVarValues[2]); // this is linearized 'global bin' + + // TBI 20250528 check if the check below is computationally heavy. If so, add the flag tc.fInsanityCheckForEachParticle here. + if (res.fResultsPro3D[AFO_var]->IsBinUnderflow(bin) || res.fResultsPro3D[AFO_var]->IsBinOverflow(bin)) { + LOGF(fatal, "\033[1;31m%s at line %d : kineVarChoice = %d (%s), kineVarValues[0] = %f, kineVarValues[1] = %f, kineVarValues[2] = %f is in global bin = %d, which is either underflow or overflow.\033[0m", __FUNCTION__, __LINE__, static_cast(kineVarChoice), StringKineMap(kineVarChoice).Data(), kineVarValues[0], kineVarValues[1], kineVarValues[2], bin); + } + } + break; + } + + // ... + + default: { + LOGF(fatal, "\033[1;31m%s at line %d : Ndim = %d is not supported yet. \033[0m", __FUNCTION__, __LINE__, Ndim); + break; + } + + } // switch (Ndim) + + // zzzzzzzzzzzzzzzzzzzzzz + + /* + + // *) 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? + 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: { + AFO_var = AFO_PT; + AFO_weight = wPT; + AFO_diffWeight = wPHIPT; // TBI 20250215 this is now obsolete, see the comment in enum + break; + } + case ETAq: { + AFO_var = AFO_ETA; + AFO_weight = wETA; + AFO_diffWeight = wPHIETA; // TBI 20250215 this is now obsolete, see the comment in enum + break; } - } // for(Int_t wp=0;wp(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 bin = -1; + if (res.fResultsPro[AFO_var]) { + 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, "\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 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_weight); // corresponding e.g. pt or eta weight + if (!(kineVarWeight > 0.)) { + 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 diffPhiWeightsForThisKineVar = 1.; + if (pw.fUseDiffWeights[AFO_diffWeight]) { + diffPhiWeightsForThisKineVar = DiffWeight(dPhi, kineVarValue, kineVarChoice); // corresponding differential phi weight as a function of e.g. pt or eta + if (!(diffPhiWeightsForThisKineVar > 0.)) { + 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 linearized "global bin": + for (int h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) { + for (int wp = 0; wp < gMaxCorrelator + 1; wp++) { // weight power + qv.fqvector[kineVarChoice][bin][h][wp] += std::complex(std::cos(h * dPhi), std::sin(h * dPhi)); // bare q-vector without weights + } // for(int wp=0;wpAddAt(dPhi, qv.fqVectorEntries[kineVarChoice][bin - 1]); - nl.ftaNestedLoopsKine[kineVarChoice][bin - 1][1]->AddAt(diffPhiWeightsForThisKineVar * kineVarWeight, qv.fqVectorEntries[kineVarChoice][bin - 1]); + nl.ftaNestedLoopsKine[kineVarChoice][bin][0]->AddAt(dPhi, qv.fqvectorEntries[kineVarChoice][bin]); + nl.ftaNestedLoopsKine[kineVarChoice][bin][1]->AddAt(1, qv.fqvectorEntries[kineVarChoice][bin]); // TBI 20250529 bare, without weights. Otherwise, adapt and use the line below + // nl.ftaNestedLoopsKine[kineVarChoice][bin][1]->AddAt(diffPhiWeightsForThisKineVar * kineVarWeight, qv.fqvectorEntries[kineVarChoice][bin]); // TBI 20250527 temporarily commented out } // *) Multiplicity counter in this bin: - qv.fqVectorEntries[kineVarChoice][bin - 1]++; // count number of particles in this pt bin in this event + qv.fqvectorEntries[kineVarChoice][bin]++; // count number of particles in this differential bin in this event + + // *) Usage of eta separations in differential correlations: + if (es.fCalculateEtaSeparations && qv.fCalculateqvectorsKineEtaSeparations[kineVarChoice]) { // yes, I have decoupled this one from if (qv.fCalculateQvectors) + + if (kineVarChoice == ETAq || kineVarChoice == PT_ETAq || kineVarChoice == ETA_CHARGEq || kineVarChoice == PT_ETA_CHARGEq) { + LOGF(fatal, "\033[1;31m%s at line %d : kineVarChoice == %s . This doesn't make any sense in this context => eta separations cannot be used for differential vectors vs. eta (either 1D or 2D or 3D case). \033[0m", __FUNCTION__, __LINE__, StringKineMap(kineVarChoice).Data()); // _22 + } + + 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][kineVarChoice][bin][e] += 1.; // 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][kineVarChoice][bin][h][e] += std::complex(std::cos((h + 1) * dPhi), std::sin((h + 1) * dPhi)); // bare q_ab-vector without weights + } + } // 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][kineVarChoice][bin][e] += 1.; // 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][kineVarChoice][bin][h][e] += std::complex(std::cos((h + 1) * dPhi), std::sin((h + 1) * dPhi)); // bare q_ab-vector without weights + } + } // for (int h = 0; h < gMaxHarmonic; h++) { + } // for (int e = 0; e < gMaxNumberEtaSeparations; e++) { // eta separation + } + } + } // if(es.fCalculateEtaSeparations) -} // void Fillqvector(const Double_t &dPhi, const Double_t &kineVarValue, eqvectorKine kineVarChoice) + if (tc.fVerboseForEachParticle) { + ExitFunction(__FUNCTION__); + } + +} // void FillqvectorNdim(const double& dPhi, double* kineVarValues, int Ndim, eqvectorKine kineVarChoice, const double& dEta = 0.) //============================================================ void CalculateEverything() { // Calculate everything for selected events and particles. - // Remark: Data members for Q-vectors, containers for nested loops, etc., must all be filled when this function is called. + // Remark: Data members for Q-vectors (both integrated and differential), 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", __FUNCTION__); + StartFunction(__FUNCTION__); } - // *) Progress info: - if (iv.fUseInternalValidation && eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]) { - // this branch is relevant e.g. for internal validation: - LOGF(info, " Processing event %d .... ", static_cast(eh.fEventHistograms[eNumberOfEvents][eSim][eBefore]->GetBinContent(1))); - } else if (eh.fEventHistograms[eNumberOfEvents][eRec][eBefore] && eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]) { - LOGF(info, " Processing event %d/%d (selected/total) .... ", static_cast(eh.fEventHistograms[eNumberOfEvents][eRec][eAfter]->GetBinContent(1)), static_cast(eh.fEventHistograms[eNumberOfEvents][eRec][eBefore]->GetBinContent(1))); - } - // TBI 20240423 I need to re-organize here if-else statements + add support for the case when I process only sim, etc. - // *) Calculate multiparticle correlations (standard, isotropic, same harmonic): 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 (qv.fCalculateQvectors && t0.fCalculateTest0) { this->CalculateTest0(); } - // *) Calculate kine Test0: TBI 20240110 name convention - // Remark: vs. pt, vs. eta, etc., are all calculated here - if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_PT]) { - this->CalculateKineTest0(AFO_PT); - } - if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { - this->CalculateKineTest0(AFO_ETA); - } + // *) Calculate kine Test0: - // *) Calculate nested loops: - if (nl.fCalculateNestedLoops) { - this->CalculateNestedLoops(); - if (mupa.fCalculateCorrelations) { - this->ComparisonNestedLoopsVsCorrelations(); // I call it here, so comparison is performed cumulatively after each event. The final printout corresponds to all events. - } + // **) 1D kine: + // ***) cases for which 1D vs. pt calculus is needed: + if (qv.fCalculateQvectors && qv.fCalculateqvectorsKine[PTq]) { // TBI 20250601 do I really need here qv.fCalculateQvectors + this->CalculateKineTest0Ndim(PTq, 1); } -} // 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.fVerbose) { - LOGF(info, "\033[1;32m%s starting ...\033[0m", __FUNCTION__); // just a bare function name + // ***) cases for which 1D vs. eta calculus is needed: + if (qv.fCalculateQvectors && qv.fCalculateqvectorsKine[ETAq]) { // TBI 20250601 do I really need here qv.fCalculateQvectors + this->CalculateKineTest0Ndim(ETAq, 1); } - - // *) Dry run: - if (tc.fDryRun) { - EventCounter(eFill); - EventCounter(ePrint); - return; + // ***) cases for which 1D vs. charge calculus is needed: + if (qv.fCalculateQvectors && qv.fCalculateqvectorsKine[CHARGEq]) { // TBI 20250601 do I really need here qv.fCalculateQvectors + this->CalculateKineTest0Ndim(CHARGEq, 1); } + // ... - // *) 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; + // **) 2D kine: + // ***) cases for which 2D vs. (pt,eta) calculus is needed: + if (qv.fCalculateQvectors && qv.fCalculateqvectorsKine[PT_ETAq]) { // TBI 20250601 do I really need here qv.fCalculateQvectors + this->CalculateKineTest0Ndim(PT_ETAq, 2); } - - // *) Global timestamp: - if (tc.fUseStopwatch) { - LOGF(info, "\033[1;32m\n\n=> Global timer: Steer begins ... %.6f\n\033[0m", tc.fTimer[eGlobal]->RealTime()); - tc.fTimer[eGlobal]->Continue(); // yes + // ***) cases for which 2D vs. (pt,charge) calculus is needed: + if (qv.fCalculateQvectors && qv.fCalculateqvectorsKine[PT_CHARGEq]) { // TBI 20250601 do I really need here qv.fCalculateQvectors + this->CalculateKineTest0Ndim(PT_CHARGEq, 2); } - - // *) Do all thingies before starting to process data from this collision (e.g. cut on number of events (bot total and selected), fetch the run number, etc.): - Preprocess(collision); - - // *) Determine collision centrality: - DetermineCentrality(collision); - - // *) Fill event histograms before event cuts: - if (eh.fFillEventHistograms) { - FillEventHistograms(collision, tracks, eBefore); + // ***) cases for which 2D vs. (eta,charge) calculus is needed: + if (qv.fCalculateQvectors && qv.fCalculateqvectorsKine[ETA_CHARGEq]) { // TBI 20250601 do I really need here qv.fCalculateQvectors + this->CalculateKineTest0Ndim(ETA_CHARGEq, 2); } + // ... - // *) Print info on the current event number (total, before cuts): - PrintEventCounter(eBefore); - - // *) Event cuts counters (use only during QA, as this is computationally heavy): - if (ec.fUseEventCutCounterAbsolute || ec.fUseEventCutCounterSequential) { - EventCutsCounters(collision, tracks); + // **) 3D kine: + // ***) cases for which 3D vs. (pt,eta,charge) calculus is needed: + if (qv.fCalculateQvectors && qv.fCalculateqvectorsKine[PT_ETA_CHARGEq]) { // TBI 20250601 do I really need here qv.fCalculateQvectors + this->CalculateKineTest0Ndim(PT_ETA_CHARGEq, 3); } + // ... - // *) Event cuts: - if (!EventCuts(collision, tracks, eCut)) { // Main call for event cuts - return; + // *) Calculate nested loops: + if (nl.fCalculateNestedLoops) { + this->CalculateNestedLoops(); + 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. + } } - // *) Main loop over particles: - MainLoopOverParticles(tracks); - - // *) Remaining event cuts which can be applied only after the loop over particles is performed: - if ((ebye.fSelectedTracks < ec.fdEventCuts[eSelectedTracks][eMin]) || (ebye.fSelectedTracks > ec.fdEventCuts[eSelectedTracks][eMax])) { - if (tc.fVerbose) { - LOGF(info, "\033[1;31m%s eSelectedTracks \033[0m", __FUNCTION__); - } - // **) Special treatment for event cut counter: - // TBI 20240514 not sure if everything is done here correctly. Do some additional validation checks, and them move all this to some dedicated member function, e.g. RemainingEventCuts() - if (tc.fProcess[eGenericRec] || tc.fProcess[eGenericRecSim]) { - EventCut(eRec, eSelectedTracks, eCutCounterSequential); + // *) Calculate correlations with eta separations: + if (es.fCalculateEtaSeparations) { + this->CalculateEtaSeparations(); + if (es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { + this->CalculateKineEtaSeparationsNdim(PTq, 1); } - if (tc.fProcess[eGenericSim] || tc.fProcess[eGenericRecSim]) { - EventCut(eSim, eSelectedTracks, eCutCounterSequential); + if (es.fCalculateEtaSeparationsAsFunctionOf[AFO_CHARGE]) { + this->CalculateKineEtaSeparationsNdim(CHARGEq, 1); } - - // TBI 20240514 Do I need to do here also something about particle cut counters? Most likely yes, but it's not that important, really - - BanishmentLoopOverParticles(tracks); // yes, I need to remove particles from ParticleHistograms, which were filled in the MainLoopOverParticles also for events < eSelectedTracks - ResetEventByEventQuantities(); - return; } - // *) 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 - if (eh.fFillEventHistograms) { - FillEventHistograms(collision, tracks, eAfter); + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } - // *) Calculate everything for selected events and particles: - CalculateEverything(); +} // void 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(); +void SkipThisRun() +{ + // Skip or not the current run from furher processing. + + // a) Insanity checks; + // b) Do the check. + + if (tc.fVerbose) { + StartFunction(__FUNCTION__); + } + // 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__); } - // *) Print info on the current event number after cuts: - PrintEventCounter(eAfter); + // 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... - // *) Per request, print content of event cut counters: - if (ec.fPrintCutCounterContent) { - PrintCutCounterContent(); + // 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; } - // *) 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 + if (tc.fVerbose) { + ExitFunction(__FUNCTION__); } -} // template void Steer(T1 const* collision, T2 const* tracks) +} // void SkipThisRun() //============================================================ @@ -8683,14 +18615,21 @@ 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 + + // Remark #5: + // *) Switch ProcessHepMChi(...) amounts at the moment to calling one dedicated function + calling Steer for "RecSim", so no special care is needed here for that switch. + if (tc.fVerbose) { - LOGF(info, "\033[1;32m%s\033[0m", __FUNCTION__); // just a bare function name + StartFunction(__FUNCTION__); } // *) Declare local kinematic variables: - Double_t dPhi = 0.; // azimuthal angle - Double_t dPt = 0.; // transverse momentum - Double_t dEta = 0.; // pseudorapidity + double dPhi = 0.; // azimuthal angle + double dPt = 0.; // transverse momentum + double dEta = 0.; // pseudorapidity + double dCharge = -44.; // particle charge. Yes, never initialize charge to 0. // *) If random access of tracks from collection is requested, use Fisher-Yates algorithm to generate random indices: if (tc.fUseFisherYates) { @@ -8704,7 +18643,7 @@ void MainLoopOverParticles(T const& tracks) } // *) Local timestamp: - if (tc.fUseStopwatch) { + if (tc.fUseStopwatch && tc.fVerboseUtility) { LOGF(info, " Local timer starts at line %d", __LINE__); tc.fTimer[eLocal]->Reset(); tc.fTimer[eLocal]->Start(); @@ -8719,7 +18658,7 @@ void MainLoopOverParticles(T const& tracks) 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.): @@ -8728,10 +18667,9 @@ void MainLoopOverParticles(T const& tracks) } // *) Fill particle histograms before particle cuts: - if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D) { + 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); @@ -8743,7 +18681,7 @@ void MainLoopOverParticles(T const& tracks) } // *) Fill particle histograms after particle cuts: - if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D) { + if (ph.fFillParticleHistograms || ph.fFillParticleHistograms2D || qa.fFillQAParticleHistograms2D) { FillParticleHistograms(track, eAfter); } @@ -8752,41 +18690,117 @@ void MainLoopOverParticles(T const& tracks) dPhi = track.phi(); dPt = track.pt(); dEta = track.eta(); + dCharge = track.sign(); + // Remark: Keep in sync all calls and flags below with the ones in InternalValidation(). // *) Integrated Q-vectors: - if (qv.fCalculateQvectors) { - this->FillQvector(dPhi, dPt, dEta); // all 3 arguments are passed by reference + 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, dCharge); // 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, ...) + } + } + + // *) Differential q-vectors (keep in sync with the code in InternalValidation()): + + // ** 1D: + // ***) 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: + double kineArr[1] = {dPt}; + this->FillqvectorNdim(dPhi, kineArr, 1, PTq); + } else if (es.fCalculateEtaSeparations && es.fCalculateEtaSeparationsAsFunctionOf[AFO_PT]) { + // In this branch I do need eta separation, so the heavier call must be executed: + double kineArr[1] = {dPt}; + this->FillqvectorNdim(dPhi, kineArr, 1, PTq, dEta); + } + + // ***) 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. + double kineArr[1] = {dEta}; + this->FillqvectorNdim(dPhi, kineArr, 1, ETAq); + } + + // ***) charge dependence: + if (qv.fCalculateQvectors && (mupa.fCalculateCorrelationsAsFunctionOf[AFO_CHARGE] || t0.fCalculateTest0AsFunctionOf[AFO_CHARGE]) && !es.fCalculateEtaSeparations) { + // In this branch I do not need eta separation, so the lighter call can be executed: + double kineArr[1] = {dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 1, CHARGEq); + } else if (es.fCalculateEtaSeparations && es.fCalculateEtaSeparationsAsFunctionOf[AFO_CHARGE]) { + // In this branch I do need eta separation, so the heavier call must be executed: + double kineArr[1] = {dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 1, CHARGEq, dEta); + } + + // ... + + // ** 2D: + // ***) pt-eta dependence: + if (qv.fCalculateQvectors && (t0.fCalculate2DTest0AsFunctionOf[AFO_PT_ETA] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_ETA])) { + // Remark: For eta dependence I do not consider es.fCalculateEtaSeparations, because in this context that calculation is meaningless. + double kineArr[2] = {dPt, dEta}; + this->FillqvectorNdim(dPhi, kineArr, 2, PT_ETAq); + } + + // ***) pt-charge dependence: + if (qv.fCalculateQvectors && (t0.fCalculate2DTest0AsFunctionOf[AFO_PT_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_PT_CHARGE]) && !es.fCalculateEtaSeparations) { + // In this branch I do not need eta separation, so the lighter call can be executed: + double kineArr[2] = {dPt, dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 2, PT_CHARGEq); + } else if (es.fCalculateEtaSeparations) { // && TBI 20250527 finalize by checking if 2D pt_charge with eta separations was requested + // In this branch I do need eta separation, so the heavier call must be executed: + // double kineArr[2] = {dPt, dCharge}; + // this->FillqvectorNdim(dPhi, kineArr, 2, PT_CHARGEq, dEta); // TBI 20250620 enable when I finalize else if above + + if (tc.fVerboseForEachParticle) { // TBI 20250627 temporary here I use this switch, otherwise logs in HL are too heavy + LOGF(info, "\033[1;33m%s at line %d: !!!! WARNING !!!! This branch is not finalized yet, i need to implement 2D objects also for eta separations, but it's unlikely I will ever need that in pracice. If I ever add it, just finalize the if statement above, and comment in two lines above !!!! WARNING !!!! \033[0m", __FUNCTION__, __LINE__); + } } - // *) Differential q-vectors: - if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_PT]) { // TBI 20240423 I need to extend this condition to mupa.fCalculateCorrelations or some differential version of it - this->Fillqvector(dPhi, dPt, PTq); // first 2 arguments are passed by reference, 3rd argument is enum + // ***) eta-charge dependence: + if (qv.fCalculateQvectors && (t0.fCalculate2DTest0AsFunctionOf[AFO_ETA_CHARGE] || t0.fCalculate3DTest0AsFunctionOf[AFO_CENTRALITY_ETA_CHARGE])) { + // Remark: For eta dependence I do not consider es.fCalculateEtaSeparations, because in this context that calculation is meaningless. + double kineArr[2] = {dEta, dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 2, ETA_CHARGEq); } - if (qv.fCalculateQvectors && t0.fCalculateTest0AsFunctionOf[AFO_ETA]) { // TBI 20240423 I need to extend this condition to mupa.fCalculateCorrelations or some differential version of it - this->Fillqvector(dPhi, dEta, ETAq); // first 2 arguments are passed by reference, 3rd argument is enum + + // ... + + // ** 3D: + // ***) pt-eta-charge dependence: + if (qv.fCalculateQvectors && (t0.fCalculate3DTest0AsFunctionOf[AFO_PT_ETA_CHARGE])) { + // Remark: For eta dependence I do not consider es.fCalculateEtaSeparations, because in this context that calculation is meaningless. + double kineArr[3] = {dPt, dEta, dCharge}; + this->FillqvectorNdim(dPhi, kineArr, 3, PT_ETA_CHARGEq); } - // *) Fill nested loops containers: + // *) Fill nested loops containers (integrated => I fill kine containers for nested loops in FillqvectorNdim(...)): 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 >= ec.fdEventCuts[eSelectedTracks][eMax]) { + 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, " Breaking the loop over particles, since requested fixed number of %d particles was reached", 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) { + 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(); } @@ -8796,6 +18810,177 @@ 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__); + } + + // memStatus: ~50K (without differential q-vectors and eta separations) + + // *) 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; + } + + // memStatus: ~50K (without differential q-vectors and eta separations) + + // *) 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: + // Remark: I determine also IP here. + DetermineCentrality(collision); + + // *) Determine collision occupancy: + DetermineOccupancy(collision); + + // *) Determine collision interaction rate and current run duration: + DetermineInteractionRateAndCurrentRunDuration(collision, bcs); // TBI 20250414 temporary commented out, because of memory blow-up + + // *) Determine vertex z position: + DetermineVertexZ(collision); + + // memStatus: ~50K (without differential q-vectors and eta separations) + + // *) 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 subscription 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; + } + + // memStatus: ~50K (without differential q-vectors and eta separations) + + // *) Main loop over particles: + MainLoopOverParticles(tracks); // memStatus: so here I invest ~20K, as of 20250530 + + // memStatus: ~70K (without differential q-vectors and eta separations) + + // *) 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(); + + // memStatus: ~72K (without differential q-vectors and eta separations) + + // *) 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__); + } + + // memStatus (summary): Last update: 20250602 + // Remark: disable sequential bailout before doing this test (yes!) + all of UseSetBinLabel, ... UseDatabasetPDG + // ~46K (skeleton - literally) + // ~50K (dry run with 1D objects booked) + // ~70K (all object declaration besides kine objects (diff. q-vectors and eta separations) + all calculus and 1D histograms filled, trivial labels) + // ~70K (all object declaration + 1D kine objects (diff. q-vectors in coarse kine bins) + all calculus and 1D histograms filled, standard labels) + // ~80K (all object declaration + 1D + 2D kine objects (diff. q-vectors in fine kine bins) + all calculus and 1D histograms filled, standard labels) + // ~110K (all object declaration + 1D + 2D + 3D kine objects (diff. q-vectors in fine kine bins) + all calculus and 1D histograms filled, standard labels) + // ~125K (all object declaration + 1D + 2D + 3D kine objects (diff. q-vectors in fine kine bins) + all calculus and 1D histograms filled, Set_0 labels) + +} // 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 4240aaf37e0..05bb4edb850 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt @@ -11,7 +11,7 @@ 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 @@ -19,7 +19,7 @@ o2physics_add_dpl_workflow(multiparticle-correlations-ar PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(threeparticle-correlations - SOURCES ThreeParticleCorrelations.cxx +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/ThreeParticleCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/ThreeParticleCorrelations.cxx deleted file mode 100644 index c45730fd9f5..00000000000 --- a/PWGCF/MultiparticleCorrelations/Tasks/ThreeParticleCorrelations.cxx +++ /dev/null @@ -1,320 +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 "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct ThreePartCorr { - - // Histogram registry - HistogramRegistry MECorrRegistry{"MECorrRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - HistogramRegistry SECorrRegistry{"SECorrRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - HistogramRegistry QARegistry{"QARegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - - // Collision filters - Filter CollCent = aod::cent::centFT0C > 0.0f && aod::cent::centFT0C < 90.0f; - Filter CollZvtx = nabs(aod::collision::posZ) < 7.0f; - - // V0 filters - Filter V0Pt = aod::v0data::pt > 0.6f && aod::v0data::pt < 12.0f; - Filter V0Eta = nabs(aod::v0data::eta) < 0.72f; - - // Track filters - Filter TrackPt = aod::track::pt > 0.2f && aod::track::pt < 3.0f; - Filter TrackEta = nabs(aod::track::eta) < 0.8f; - - // Table aliases - using MyFilteredCollisions = soa::Filtered>; - using MyFilteredCollision = MyFilteredCollisions::iterator; - using MyFilteredV0s = soa::Filtered; - using MyFilteredTracks = soa::Filtered>; - - // Mixed-events binning policy - SliceCache cache; - 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; - - BinningType CollBinning{{ConfCentBins, ConfZvtxBins}, true}; - Pair pair{CollBinning, 5, -1, &cache}; - - // Particle masses - Double_t massLambda = 1.115683; - - // Correlation variables - Int_t T_Sign; - Double_t CandMass; - Double_t* A_PID; - - Double_t DeltaPhi, DeltaEta; - - //================================================================================================================================================================================================================ - - void init(InitContext const&) - { - - const AxisSpec CentralityAxis{ConfCentBins}; - const AxisSpec ZvtxAxis{ConfZvtxBins}; - const AxisSpec PhiAxis{36, (-1. / 2) * M_PI, (3. / 2) * M_PI}; - const AxisSpec EtaAxis{32, -1.52, 1.52}; - const AxisSpec PtAxis{120, 0, 12}; - const AxisSpec LambdaInvMassAxis{100, 1.08, 1.16}; - - QARegistry.add("hTrackPt", "hTrackPt", {HistType::kTH1D, {{100, 0, 4}}}); - QARegistry.add("hTrackEta", "hTrackEta", {HistType::kTH1D, {{100, -1, 1}}}); - QARegistry.add("hTrackPhi", "hTrackPhi", {HistType::kTH1D, {{100, (-1. / 2) * M_PI, (5. / 2) * M_PI}}}); - QARegistry.add("hEventCentrality", "hEventCentrality", {HistType::kTH1D, {{CentralityAxis}}}); - QARegistry.add("hEventZvtx", "hEventZvtx", {HistType::kTH1D, {{ZvtxAxis}}}); - - QARegistry.add("hNSigmaPion", "hNSigmaPion", {HistType::kTH2D, {{28, 0.2, 3.0}, {161, -4.025, 4.025}}}); - QARegistry.add("hNSigmaKaon", "hNSigmaKaon", {HistType::kTH2D, {{28, 0.2, 3.0}, {161, -4.025, 4.025}}}); - QARegistry.add("hNSigmaProton", "hNSigmaProton", {HistType::kTH2D, {{28, 0.2, 3.0}, {161, -4.025, 4.025}}}); - - QARegistry.add("hInvMassLambda", "hInvMassLambda", {HistType::kTH3D, {{LambdaInvMassAxis}, {PtAxis}, {CentralityAxis}}}); - QARegistry.add("hInvMassAntiLambda", "hInvMassAntiLambda", {HistType::kTH3D, {{LambdaInvMassAxis}, {PtAxis}, {CentralityAxis}}}); - - SECorrRegistry.add("hSameLambdaPion_SGNL", "Same-event #Lambda - #pi correlator (SGNL region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - SECorrRegistry.add("hSameLambdaPion_SB", "Same-event #Lambda - #pi correlator (SB region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - SECorrRegistry.add("hSameLambdaKaon_SGNL", "Same-event #Lambda - K correlator (SGNL region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - SECorrRegistry.add("hSameLambdaKaon_SB", "Same-event #Lambda - K correlator (SB region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - SECorrRegistry.add("hSameLambdaProton_SGNL", "Same-event #Lambda - p correlator (SGNL region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - SECorrRegistry.add("hSameLambdaProton_SB", "Same-event #Lambda - p correlator (SB region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - - MECorrRegistry.add("hMixLambdaPion_SGNL", "Mixed-event #Lambda - #pi correlator (SGNL region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - MECorrRegistry.add("hMixLambdaPion_SB", "Mixed-event #Lambda - #pi correlator (SB region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - MECorrRegistry.add("hMixLambdaKaon_SGNL", "Mixed-event #Lambda - K correlator (SGNL region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - MECorrRegistry.add("hMixLambdaKaon_SB", "Mixed-event #Lambda - K correlator (SB region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - MECorrRegistry.add("hMixLambdaProton_SGNL", "Mixed-event #Lambda - p correlator (SGNL region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - MECorrRegistry.add("hMixLambdaProton_SB", "Mixed-event #Lambda - p correlator (SB region)", {HistType::kTHnSparseD, {{PhiAxis}, {EtaAxis}, {CentralityAxis}, {ZvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); - } - - //================================================================================================================================================================================================================ - - void processSame(MyFilteredCollision const& collision, MyFilteredV0s const& v0s, MyFilteredTracks const& tracks) - { - - QARegistry.fill(HIST("hEventCentrality"), collision.centFT0C()); - QARegistry.fill(HIST("hEventZvtx"), collision.posZ()); - - // Start of the Track QA - for (const auto& track : tracks) { - A_PID = TrackPID(track); - if (A_PID[1] < 4.0) { - QARegistry.fill(HIST("hTrackPt"), track.pt()); - QARegistry.fill(HIST("hTrackEta"), track.eta()); - QARegistry.fill(HIST("hTrackPhi"), track.phi()); - if (A_PID[0] == 0.0) { // Pions - QARegistry.fill(HIST("hNSigmaPion"), track.pt(), track.tpcNSigmaPi()); - } else if (A_PID[0] == 1.0) { // Kaons - QARegistry.fill(HIST("hNSigmaKaon"), track.pt(), track.tpcNSigmaKa()); - } else if (A_PID[0] == 2.0) { // Protons - QARegistry.fill(HIST("hNSigmaProton"), track.pt(), track.tpcNSigmaPr()); - } - } - } - // End of the Track QA - - // Start of the V0-Track Correlations - for (const auto& trigger : v0s) { - if (V0Filters(trigger)) { - - T_Sign = V0Sign(trigger); - if (T_Sign == 1) { - CandMass = trigger.mLambda(); - QARegistry.fill(HIST("hInvMassLambda"), trigger.mLambda(), trigger.pt(), collision.centFT0C()); - } else if (T_Sign == -1) { - CandMass = trigger.mAntiLambda(); - QARegistry.fill(HIST("hInvMassAntiLambda"), trigger.mAntiLambda(), trigger.pt(), collision.centFT0C()); - } - - for (const auto& associate : tracks) { - if (TrackFilters(trigger, associate)) { - - A_PID = TrackPID(associate); - DeltaPhi = DeltaPhiShift(trigger.phi(), associate.phi()); - DeltaEta = trigger.eta() - associate.eta(); - - if (CandMass >= 1.10 && CandMass <= 1.13) { - if (A_PID[0] == 0) { // Pions - SECorrRegistry.fill(HIST("hSameLambdaPion_SGNL"), DeltaPhi, DeltaEta, collision.centFT0C(), collision.posZ(), T_Sign, associate.sign()); - } else if (A_PID[0] == 1) { // Kaons - SECorrRegistry.fill(HIST("hSameLambdaKaon_SGNL"), DeltaPhi, DeltaEta, collision.centFT0C(), collision.posZ(), T_Sign, associate.sign()); - } else if (A_PID[0] == 2) { // Protons - SECorrRegistry.fill(HIST("hSameLambdaProton_SGNL"), DeltaPhi, DeltaEta, collision.centFT0C(), collision.posZ(), T_Sign, associate.sign()); - } - } else { - if (A_PID[0] == 0) { // Pions - SECorrRegistry.fill(HIST("hSameLambdaPion_SB"), DeltaPhi, DeltaEta, collision.centFT0C(), collision.posZ(), T_Sign, associate.sign()); - } else if (A_PID[0] == 1) { // Kaons - SECorrRegistry.fill(HIST("hSameLambdaKaon_SB"), DeltaPhi, DeltaEta, collision.centFT0C(), collision.posZ(), T_Sign, associate.sign()); - } else if (A_PID[0] == 2) { // Protons - SECorrRegistry.fill(HIST("hSameLambdaProton_SB"), DeltaPhi, DeltaEta, collision.centFT0C(), collision.posZ(), T_Sign, associate.sign()); - } - } - } - } - } - } - // End of the V0-Track Correlations - } - PROCESS_SWITCH(ThreePartCorr, processSame, "Process same-event correlations", true); - - void processMixed(MyFilteredCollisions const& collisions, MyFilteredV0s const& v0s, MyFilteredTracks const& tracks) - { - - LOGF(info, "Input data Collisions %d, V0s %d, Tracks %d ", collisions.size(), v0s.size(), tracks.size()); - - // Start of the Mixed-events Correlations - for (const auto& [coll_1, v0_1, coll_2, track_2] : pair) { - for (const auto& [trigger, associate] : soa::combinations(soa::CombinationsFullIndexPolicy(v0_1, track_2))) { - if (V0Filters(trigger) && TrackFilters(trigger, associate)) { - - T_Sign = V0Sign(trigger); - if (T_Sign == 1) { - CandMass = trigger.mLambda(); - } else if (T_Sign == -1) { - CandMass = trigger.mAntiLambda(); - } - - A_PID = TrackPID(associate); - DeltaPhi = DeltaPhiShift(trigger.phi(), associate.phi()); - DeltaEta = trigger.eta() - associate.eta(); - - if (CandMass >= 1.10 && CandMass <= 1.13) { - if (A_PID[0] == 0) { // Pions - MECorrRegistry.fill(HIST("hMixLambdaPion_SGNL"), DeltaPhi, DeltaEta, coll_1.centFT0C(), coll_1.posZ(), T_Sign, associate.sign()); - } else if (A_PID[0] == 1) { // Kaons - MECorrRegistry.fill(HIST("hMixLambdaKaon_SGNL"), DeltaPhi, DeltaEta, coll_1.centFT0C(), coll_1.posZ(), T_Sign, associate.sign()); - } else if (A_PID[0] == 2) { // Protons - MECorrRegistry.fill(HIST("hMixLambdaProton_SGNL"), DeltaPhi, DeltaEta, coll_1.centFT0C(), coll_1.posZ(), T_Sign, associate.sign()); - } - } else { - if (A_PID[0] == 0) { // Pions - MECorrRegistry.fill(HIST("hMixLambdaPion_SB"), DeltaPhi, DeltaEta, coll_1.centFT0C(), coll_1.posZ(), T_Sign, associate.sign()); - } else if (A_PID[0] == 1) { // Kaons - MECorrRegistry.fill(HIST("hMixLambdaKaon_SB"), DeltaPhi, DeltaEta, coll_1.centFT0C(), coll_1.posZ(), T_Sign, associate.sign()); - } else if (A_PID[0] == 2) { // Protons - MECorrRegistry.fill(HIST("hMixLambdaProton_SB"), DeltaPhi, DeltaEta, coll_1.centFT0C(), coll_1.posZ(), T_Sign, associate.sign()); - } - } - } - } - } - // End of the Mixed-events Correlations - } - PROCESS_SWITCH(ThreePartCorr, processMixed, "Process mixed-event correlations", true); - - //================================================================================================================================================================================================================ - - Double_t DeltaPhiShift(Double_t TriggerPhi, Double_t AssociatePhi) - { - - Double_t dPhi = TriggerPhi - AssociatePhi; - - if (dPhi < (-1. / 2) * M_PI) { - dPhi = dPhi + 2 * M_PI; - } else if (dPhi > (3. / 2) * M_PI) { - dPhi = dPhi - 2 * M_PI; - } - - return dPhi; - } - - template - Double_t* TrackPID(const TrackCand& Track) - { - - static Double_t ID[2]; // {PID, NSigma} - - Double_t NSigma[3]; - NSigma[0] = TMath::Abs(Track.tpcNSigmaPi()); - NSigma[1] = TMath::Abs(Track.tpcNSigmaKa()); - NSigma[2] = TMath::Abs(Track.tpcNSigmaPr()); - - if (NSigma[0] < std::min(NSigma[1], NSigma[2])) { // Pions - ID[0] = 0.0; - ID[1] = NSigma[0]; - } else if (NSigma[1] < std::min(NSigma[0], NSigma[2])) { // Kaons - ID[0] = 1.0; - ID[1] = NSigma[1]; - } else if (NSigma[2] < std::min(NSigma[0], NSigma[1])) { // Protons - ID[0] = 2.0; - ID[1] = NSigma[2]; - } - - return ID; - } - - template - Int_t V0Sign(const V0Cand& V0) - { - - if (TMath::Abs(V0.mLambda() - massLambda) <= TMath::Abs(V0.mAntiLambda() - massLambda)) { - return 1; - } else if (TMath::Abs(V0.mLambda() - massLambda) > TMath::Abs(V0.mAntiLambda() - massLambda)) { - return -1; - } - - return 0; - } - - template - Bool_t V0Filters(const V0Cand& V0) - { - - if (V0Sign(V0) == 1) { - const auto& posDaughter = V0.template posTrack_as(); - if (TMath::Abs(posDaughter.tpcNSigmaPr()) > 4.0) { - return kFALSE; - } - // if(V0.mLambda() < 1.10 || V0.mLambda() > 1.13) { return kFALSE; } - } else if (V0Sign(V0) == -1) { - const auto& negDaughter = V0.template negTrack_as(); - if (TMath::Abs(negDaughter.tpcNSigmaPr()) > 4.0) { - return kFALSE; - } - // if(V0.mAntiLambda() < 1.10 || V0.mAntiLambda() > 1.13) { return kFALSE; } - } - - return kTRUE; - } - - template - Bool_t TrackFilters(const V0Cand& V0, const TrackCand& Track) - { - - if (Track.globalIndex() == V0.posTrackId() || Track.globalIndex() == V0.negTrackId()) { - return kFALSE; - } - if (TrackPID(Track)[1] > 4.0) { - return kFALSE; - } - - return kTRUE; - } -}; - -//================================================================================================================================================================================================================== - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; - return workflow; -} - -//================================================================================================================================================================================================================== diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiparticle-correlations-ab.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiparticle-correlations-ab.cxx index aac8b255ef4..3f7953f5f11 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiparticle-correlations-ab.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiparticle-correlations-ab.cxx @@ -9,27 +9,43 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file multiparticle-correlations-ab.cxx +/// \brief ... TBI 20250425 +/// \author Ante.Bilandzic@cern.ch + // O2: -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/DataTypes.h" -#include "Common/DataModel/TrackSelectionTables.h" // needed for aod::TracksDCA table +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" // needed for aod::TracksDCA table + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include using namespace o2; using namespace o2::framework; // *) Run 3: -using EventSelection = soa::Join; +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 CollisionRecSim = soa::Join::iterator; // TBI 20241210 validating "MultsExtraMC" for multMCNParticlesEta08 using CollisionSim = aod::McCollision; using TracksRec = soa::Join; -using TrackRec = soa::Join::iterator; +// using TrackRec = soa::Join::iterator; using TracksRecSim = soa::Join; // + use in json "isMC" : "true" using TrackRecSim = soa::Join::iterator; using TracksSim = aod::McParticles; @@ -49,19 +65,37 @@ using CollisionRec_Run1 = soa::Join::itera 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 -#include -#include -#include -#include -#include -#include #include -#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include using namespace std; // *) Enums: @@ -76,6 +110,13 @@ 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 + + // *) O2DatabsePDG service shared service between different tasks (do not use TDatabasePDG directly, because it's not shared) + // See also Tutorials/src/usingPDGCervice.cxx + // TBI 20250625 enable the line below and switch to O2DatabsePDG when memory consumption with O2DatabsePDG is resolved, and then replace in all functions + // tc.fDatabasePDG->GetParticle(track.pdgCode()) with pdg->GetParticle(track.pdgCode()) + same for mcParticle + remove TDatabasePDG.h + // Service pdg; // *) Configurables (cuts): #include "PWGCF/MultiparticleCorrelations/Core/MuPa-Configurables.h" @@ -93,52 +134,66 @@ 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(); // here I decide only which histograms are booked, not details like binning, etc. That's done later in Book* member functions. - 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; gRandom = new TRandom3(tc.fRandomSeed); // if uiSeed is 0, the seed is determined uniquely in space and time via TUUID // *) Book base list: - BookBaseList(); + bookBaseList(); // *) 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(); - BookParticleCutsHistograms(); - BookQvectorHistograms(); - BookCorrelationsHistograms(); - BookWeightsHistograms(); - BookNestedLoopsHistograms(); - BookNUAHistograms(); - BookInternalValidationHistograms(); - BookTest0Histograms(); - BookTheRest(); // here I book everything that was not sorted (yet) in the specific functions above + bookAndNestAllLists(); + bookResultsHistograms(); // yes, this one has to be booked first, because it defines the common binning for other groups of histograms, w/ or w/o clonning + bookQAHistograms(); + bookEventHistograms(); + bookEventCutsHistograms(); + bookParticleHistograms(); + bookParticleCutsHistograms(); // memStatus: 50913 + bookQvectorHistograms(); // memStatus: 50913 (without differential q-vectors and eta separations) + bookCorrelationsHistograms(); + bookWeightsHistograms(); + bookCentralityWeightsHistograms(); + bookNestedLoopsHistograms(); + bookNUAHistograms(); + bookInternalValidationHistograms(); + bookTest0Histograms(); + bookEtaSeparationsHistograms(); + bookTheRest(); // I book everything that was not sorted (yet) in the specific functions above + // memStatus: 50913 (without differential q-vectors and eta separations) + + // *) I can purge a few objects used for common consistent booking across different groups of histograms: + purgeAfterBooking(); + + // *) 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); @@ -168,48 +223,48 @@ 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); // 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... + // 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&, TracksRec 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 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); @@ -225,18 +280,18 @@ struct MultiparticleCorrelationsAB // this name is used in lower-case format to // ------------------------------------------- // G) Process only converted reconstructed Run 1 data: - void processRec_Run1(CollisionRec_Run1 const& collision, aod::BCs const&, TracksRec 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(CollisionRecSim_Run1 const& /*collision*/, aod::BCs const&, TracksRecSim const& /*tracks*/, aod::McParticles const&, aod::McCollisions const&) + void processRecSim_Run1(CollisionRecSim_Run1 const& /*collision*/, aod::BCs const& /*bcs*/, TracksRecSim const& /*tracks*/, aod::McParticles const&, aod::McCollisions const&) { - // Steer(collision, tracks); // TBI 20240517 not ready yet, but for benchmarking in any case I need only "Rec" + // 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); @@ -252,12 +307,74 @@ struct MultiparticleCorrelationsAB // this name is used in lower-case format to // ------------------------------------------- // 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); + + // ------------------------------------------- + + // L) Process extra Monte Carlo info the from table HepMCHeavyIons: + // Remark 1: Under testing, merge eventually this process switch with processRecSim, processRecSim_Run2, and processRecSim_Run1 above; + // This switch does everything the same as processRecSim (so it works only for Run 3 at the moment), except extra info is processed from table HepMCHeavyIons with dedicated function call + // ProcessHepMCHeavyIons(hepMChi). I use this dedicated function, in order not to modify call to Steer(...) by adding the fourth argument. + // TBI 20250429 see if I can circumvent this with templates (i can NOT join HepMCHeavyIons and McParticles), in order to keep call to Steer(...) as simple as it is now + // Remark 2: In MC LHC24g3 and LHC24e2c, for HepMCHeavyIons only impact parameter is filled; + // As soon as HepMCHeavyIons is correctly filled in MC productions, merge this switch with processRecSim, processRecSim_Run2, and processRecSim_Run1 above. + // Most notably, I will need hep.centrality() (centrality at generated level), and hep.sigmaInelNN() + void processHepMChi(CollisionRecSim const& collision, aod::BCs const& bcs, TracksRecSim const& tracks, aod::HepMCHeavyIons const& hepMChi, aod::McParticles const&, aod::McCollisions const&) + { + // Comment the weather here... + + // *) Check if this collision has the corresponding MC collision: + if (!collision.has_mcCollision()) { + LOGF(warning, "\033[1;31m%s at line %d : No MC collision for this collision, skip... \033[0m", __FUNCTION__, __LINE__); + return; + } + + // *) For this collision, get the corresponding mcCollision, and then profit from the fact that HepMCHeavyIons have index to mcCollision by default (no need to join with McCollisionLabels): + auto hep = hepMChi.iteratorAt(collision.mcCollision().globalIndex()); + + // *) Quick insanity check that HepMCHeavyIons and McCollisions refer to the same MC collision: + // Since both of them provide getter impactParameter(), i simply check if it gives the same value in both cases: + if (std::abs(hep.impactParameter() - collision.mcCollision().impactParameter()) > tc.fFloatingPointPrecision) { + LOGF(fatal, "\033[1;31m%s at line %d : impactParameter accessed from HepMCHeavyIons and McCollisions is not the same, they do not correspond to the same MC event \033[0m", __FUNCTION__, __LINE__); + } + + // *) Okay, extract all extra info from HepMCHeavyIons: + ProcessHepMCHeavyIons(hep); + + // *) Call the Steer(...) + // TBI 20250429 For the time being, only Run 3 call for Steer(...) is supported. When generalizing to Run 2 and Run 1 process switches, perhaps the better strategy is + // just to inject ProcessHepMCHeavyIons(hep); , and keep call to Steer(...) as it is now? + Steer(collision, bcs, tracks); // TBI 20250429 remember that I have hardwired here eRecAndSim, so this now works only for Run 3 + + } // void processHepMChi( ... ) + + PROCESS_SWITCH(MultiparticleCorrelationsAB, processHepMChi, "HepMCHeavyIons processing", false); + + // ------------------------------------------- + + // ... ctd. here with further process switches ... + + // ------------------------------------------- + }; // struct MultiparticleCorrelationsAB // ------------------------------------------- diff --git a/PWGCF/MultiparticleCorrelations/Tasks/threeParticleCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/threeParticleCorrelations.cxx new file mode 100644 index 00000000000..df1c3f1fe27 --- /dev/null +++ b/PWGCF/MultiparticleCorrelations/Tasks/threeParticleCorrelations.cxx @@ -0,0 +1,1313 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "RecoDecay.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "TPDGCode.h" + +#include +#include +#include + +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 v0PtMin = 0.6, v0PtMax = 12.0; + float v0EtaMax = 0.72; + float trackPtMin = 0.2, trackPtMax = 3.0; + float trackEtaMax = 0.8; + + // Track PID parameters + double pionID = 0.0, kaonID = 1.0, protonID = 2.0; + float nSigma0 = 0.0, nSigma1 = 1.0, nSigma2 = 2.0, nSigma4 = 4.0, nSigma5 = 5.0; + + // Event selection parameters + struct : ConfigurableGroup { + std::string prefix = "EventSelection"; + Configurable zvtxMax{"zvtxMax", 10.0, "Maximum collision Z-vertex position (cm)"}; + Configurable occupMin{"occupMin", 0, "Minimum collision occupancy"}; + Configurable occupMax{"occupMax", 15000, "Maximum collision occupancy"}; + Configurable useOccupCut{"useOccupCut", true, "Use the kNoCollInTimeRangeStandard cut"}; + } evSelGroup; + + // V0 filter parameters + struct : ConfigurableGroup { + std::string prefix = "V0Selection"; + Configurable tpcNCrossedRows{"tpcNCrossedRows", 70.0, "Minimum number of TPC crossed rows"}; + Configurable decayR{"decayR", 1.2, "Minimum V0 decay radius (cm)"}; + Configurable ctau{"ctau", 30.0, "Maximum V0 proper lifetime (cm)"}; + Configurable cosPA{"cosPA", 0.995, "Minimum V0 cosine of pointing angle"}; + Configurable dcaProton{"dcaProton", 0.05, "Minimum DCA of proton daughter (cm)"}; + Configurable dcaPion{"dcaPion", 0.2, "Minimum DCA of pion daughter (cm)"}; + Configurable dcaV0Dau{"dcaV0Dau", 1.0, "Maximum DCA between V0 daughters"}; + } v0SelGroup; + + // Track filter parameters + float pionPtMin = 0.3, pionPtMax = 2.3, kaonPtMin = 0.5, kaonPtMax = 2.3, protonPtMin = 0.6; + float pionPtMid1 = 1.6, pionPtMid2 = 2.0, kaonPtMid1 = 1.5, kaonPtMid2 = 2.0, protonPtMid = 2.3; + + // RD filter parameters + float dEtaMax = 0.05, dEtaMin = 0.023; + float dPhiStarMinOS = 0.09, dPhiStarMinSS = 0.095; + float rMin = 0.8, rMax = 2.5; + + // Lambda invariant mass fit + Configurable invMassNSigma{"invMassNSigma", 4.0, "Number of standard deviations from the mean of the Lambda invariant mass peak"}; + double dGaussSigma = 0.002; + + // 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) < evSelGroup.zvtxMax; + Filter mcCollZvtx = nabs(aod::mccollision::posZ) < evSelGroup.zvtxMax; + Filter evSel8 = aod::evsel::sel8 == true; + Filter evSelOccup = o2::aod::evsel::trackOccupancyInTimeRange >= evSelGroup.occupMin && o2::aod::evsel::trackOccupancyInTimeRange < evSelGroup.occupMax; + + // 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 MyFilteredTracks = soa::Filtered>; + + // Table aliases - MC Gen + using MyFilteredMCGenCollisions = soa::Filtered>; + using MyFilteredMCGenCollision = MyFilteredMCGenCollisions::iterator; + using MyFilteredMCParticles = soa::Filtered; + + // Table aliases - MC Rec + using MCRecCollisions = soa::Join; + using MyFilteredMCRecCollisions = soa::Filtered; + using MyMCV0s = soa::Join; + using MyFilteredMCTracks = soa::Filtered>; + + // Partitions + Partition mcTracks = aod::mcparticle::pt > trackPtMin&& aod::mcparticle::pt < trackPtMax; + Partition mcV0s = aod::mcparticle::pt > v0PtMin&& aod::mcparticle::pt < v0PtMax&& nabs(aod::mcparticle::eta) < v0EtaMax; + 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; + PresliceUnsorted perMCCol = aod::mccollisionlabel::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, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.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 + struct : ConfigurableGroup { + std::string prefix = "processSwitchBoard"; + Configurable confBfieldSwitch{"confBfieldSwitch", 0, "Switch for the detector magnetic field (1 if Pos, -1 if Neg, 0 if both)"}; + Configurable confRatioCorrectionSwitch{"confRatioCorrectionSwitch", false, "Switch for correcting the negative spectra back to the positive spectra"}; + Configurable confFakeV0Switch{"confFakeV0Switch", false, "Switch for the fakeV0Filter function"}; + Configurable confRDSwitch{"confRDSwitch", true, "Switch for the radialDistanceFilter function"}; + } switchGroup; + + // Efficiency histograms + TH3D** hEffPions = new TH3D*[2]; + TH3D** hEffKaons = new TH3D*[2]; + TH3D** hEffProtons = new TH3D*[2]; + TH3D** hEffLambdas = new TH3D*[2]; + + // Spectra correction histograms + TH2D** hCorrectionPions = new TH2D*[2]; + TH2D** hCorrectionKaons = new TH2D*[2]; + TH2D** hCorrectionProtons = new TH2D*[2]; + + // Correlation variables + int triggSign, assocSign; + double v0Efficiency; + double candMass; + double* assocPID; + + double deltaPhi, deltaEta; + + //========================================================================================================================================================================================================================================================================== + + void init(InitContext const&) + { + + // Bins of variable width + std::vector fineCentBins = {0.0, 2.0, 4.0, 7.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 60.0, 70.0, 80.0, 90.0}; + + // Histograms axes + const AxisSpec centralityAxis{confCentBins}; + const AxisSpec fineCentralityAxis{fineCentBins}; + const AxisSpec zvtxAxis{confZvtxBins}; + const AxisSpec occupancyAxis{200, 0, 20000}; + const AxisSpec dPhiAxis{36, (-1. / 2) * constants::math::PI, (3. / 2) * constants::math::PI}; + const AxisSpec dEtaAxis{32, -1.52, 1.52}; + const AxisSpec v0PtAxis{114, 0.6, 12}; + const AxisSpec v0EtaAxis{36, -0.72, 0.72}; + 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("hNEvents", "hNEvents", {HistType::kTH1D, {{5, 0, 5}}}); + rQARegistry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "All"); + rQARegistry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "kIsGoodZvtxFT0vsPV"); + rQARegistry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "kNoSameBunchPileup"); + rQARegistry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, Form("[%i < Occupancy < %i)", static_cast(evSelGroup.occupMin), static_cast(evSelGroup.occupMax))); + rQARegistry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(5, "kNoCollInTimeRangeStandard"); + + rQARegistry.add("hEventCentrality", "hEventCentrality", {HistType::kTH1D, {{fineCentralityAxis}}}); + rQARegistry.add("hEventCentrality_MC", "hEventCentrality_MC", {HistType::kTH1D, {{fineCentralityAxis}}}); + rQARegistry.add("hEventZvtx", "hEventZvtx", {HistType::kTH1D, {{zvtxAxis}}}); + rQARegistry.add("hEventOccupancy", "hEventOccupancy", {HistType::kTH1D, {{occupancyAxis}}}); + rQARegistry.add("hEventBfield", "hEventBfield", {HistType::kTH1D, {{2, -1, 1}}}); + 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("hTrackNSharedClusters", "hTrackNSharedClusters", {HistType::kTH1D, {{200, 0, 200}}}); + + rQARegistry.add("hPtPion_Uncorrected", "hPtPion_Uncorrected", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtKaon_Uncorrected", "hPtKaon_Uncorrected", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtProton_Uncorrected", "hPtProton_Uncorrected", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtV0_Uncorrected", "hPtV0_Uncorrected", {HistType::kTH3D, {{v0PtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtPion_Corrected", "hPtPion_Corrected", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtKaon_Corrected", "hPtKaon_Corrected", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtProton_Corrected", "hPtProton_Corrected", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtV0_Corrected", "hPtV0_Corrected", {HistType::kTH3D, {{v0PtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtPion_Looped", "hPtPion_Looped", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtKaon_Looped", "hPtKaon_Looped", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtProton_Looped", "hPtProton_Looped", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtPion_MC", "hPtPion_MC", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtKaon_MC", "hPtKaon_MC", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtProton_MC", "hPtProton_MC", {HistType::kTH3D, {{trackPtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + rQARegistry.add("hPtV0_MC", "hPtV0_MC", {HistType::kTH3D, {{v0PtAxis}, {fineCentralityAxis}, {2, -2, 2}}}); + + rQARegistry.add("hdEdx", "hdEdx", {HistType::kTH2D, {{120, -3.0, 3.0}, {180, 20, 200}}}); + rQARegistry.add("hdEdxPion", "hdEdxPion", {HistType::kTH2D, {{120, -3.0, 3.0}, {180, 20, 200}}}); + rQARegistry.add("hdEdxKaon", "hdEdxKaon", {HistType::kTH2D, {{120, -3.0, 3.0}, {180, 20, 200}}}); + rQARegistry.add("hdEdxProton", "hdEdxProton", {HistType::kTH2D, {{120, -3.0, 3.0}, {180, 20, 200}}}); + rQARegistry.add("hBeta", "hBeta", {HistType::kTH2D, {{120, -3.0, 3.0}, {70, 0.4, 1.1}}}); + rQARegistry.add("hBetaPion", "hBetaPion", {HistType::kTH2D, {{120, -3.0, 3.0}, {70, 0.4, 1.1}}}); + rQARegistry.add("hBetaKaon", "hBetaKaon", {HistType::kTH2D, {{120, -3.0, 3.0}, {70, 0.4, 1.1}}}); + rQARegistry.add("hBetaProton", "hBetaProton", {HistType::kTH2D, {{120, -3.0, 3.0}, {70, 0.4, 1.1}}}); + + rQARegistry.add("hTPCPion", "hTPCPion", {HistType::kTH3D, {{trackPtAxis}, {1001, -50.05, 50.05}, {2, -2, 2}}}); + rQARegistry.add("hTPCKaon", "hTPCKaon", {HistType::kTH3D, {{trackPtAxis}, {1001, -50.05, 50.05}, {2, -2, 2}}}); + rQARegistry.add("hTPCProton", "hTPCProton", {HistType::kTH3D, {{trackPtAxis}, {1001, -50.05, 50.05}, {2, -2, 2}}}); + rQARegistry.add("hTOFPion", "hTOFPion", {HistType::kTH3D, {{trackPtAxis}, {1001, -50.05, 50.05}, {2, -2, 2}}}); + rQARegistry.add("hTOFKaon", "hTOFKaon", {HistType::kTH3D, {{trackPtAxis}, {1001, -50.05, 50.05}, {2, -2, 2}}}); + rQARegistry.add("hTOFProton", "hTOFProton", {HistType::kTH3D, {{trackPtAxis}, {1001, -50.05, 50.05}, {2, -2, 2}}}); + + 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}}}); + rQARegistry.add("hInvMassLambda_MC", "hInvMassLambda_MC", {HistType::kTH3D, {{lambdaInvMassAxis}, {v0PtAxis}, {centralityAxis}}}); + rQARegistry.add("hInvMassAntiLambda_MC", "hInvMassAntiLambda_MC", {HistType::kTH3D, {{lambdaInvMassAxis}, {v0PtAxis}, {centralityAxis}}}); + + // PhiStar + rPhiStarRegistry.add("hSEPhiStarIR_OS", "hSEPhiStarIR_OS", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hSEPhiStarIR_SS", "hSEPhiStarIR_SS", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hSEPhiStarIR_SSP", "hSEPhiStarIR_SSP", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hSEPhiStarIR_SSN", "hSEPhiStarIR_SSN", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hSEPhiStarMean_OS", "hSEPhiStarMean_OS", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hSEPhiStarMean_SS", "hSEPhiStarMean_SS", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hSEPhiStarMean_SSP", "hSEPhiStarMean_SSP", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hSEPhiStarMean_SSN", "hSEPhiStarMean_SSN", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + + rPhiStarRegistry.add("hMEPhiStarIR_OS", "hMEPhiStarIR_OS", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hMEPhiStarIR_SS", "hMEPhiStarIR_SS", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hMEPhiStarIR_SSP", "hMEPhiStarIR_SSP", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hMEPhiStarIR_SSN", "hMEPhiStarIR_SSN", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hMEPhiStarMean_OS", "hMEPhiStarMean_OS", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hMEPhiStarMean_SS", "hMEPhiStarMean_SS", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hMEPhiStarMean_SSP", "hMEPhiStarMean_SSP", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + rPhiStarRegistry.add("hMEPhiStarMean_SSN", "hMEPhiStarMean_SSN", {HistType::kTH2D, {{121, -0.3025, 0.3025}, {101, -0.0505, 0.0505}}}); + + // Efficiency + rMCRegistry.add("hGenerated", "hGenerated", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hGenPionP", "hGenPionP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hGenPionN", "hGenPionN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hGenKaonP", "hGenKaonP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hGenKaonN", "hGenKaonN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hGenProtonP", "hGenProtonP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hGenProtonN", "hGenProtonN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hGenLambdaP", "hGenLambdaP", {HistType::kTH3D, {{v0PtAxis}, {v0EtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hGenLambdaN", "hGenLambdaN", {HistType::kTH3D, {{v0PtAxis}, {v0EtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hReconstructed", "hReconstructed", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hRecPionP", "hRecPionP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hRecPionN", "hRecPionN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hRecKaonP", "hRecKaonP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hRecKaonN", "hRecKaonN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hRecProtonP", "hRecProtonP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hRecProtonN", "hRecProtonN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hRecLambdaP", "hRecLambdaP", {HistType::kTH3D, {{v0PtAxis}, {v0EtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hRecLambdaN", "hRecLambdaN", {HistType::kTH3D, {{v0PtAxis}, {v0EtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hIdentified", "hIdentified", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hPIDPionP", "hPIDPionP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hPIDPionN", "hPIDPionN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hPIDKaonP", "hPIDKaonP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hPIDKaonN", "hPIDKaonN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hPIDProtonP", "hPIDProtonP", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + rMCRegistry.add("hPIDProtonN", "hPIDProtonN", {HistType::kTH3D, {{trackPtAxis}, {trackEtaAxis}, {centralityAxis}}}); + + // 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, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaPion_SB", "Same-event #Lambda - #pi correlator (SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaKaon_SGNL", "Same-event #Lambda - K correlator (SGNL region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaKaon_SB", "Same-event #Lambda - K correlator (SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaProton_SGNL", "Same-event #Lambda - p correlator (SGNL region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaProton_SB", "Same-event #Lambda - p correlator (SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaPion_MC", "Same-event #Lambda - #pi correlator (MC)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaKaon_MC", "Same-event #Lambda - K correlator (MC)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaProton_MC", "Same-event #Lambda - p correlator (MC)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + + rSECorrRegistry.add("hSameLambdaPion_leftSB", "Same-event #Lambda - #pi correlator (Left SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaPion_rightSB", "Same-event #Lambda - #pi correlator (Right SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaKaon_leftSB", "Same-event #Lambda - K correlator (Left SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaKaon_rightSB", "Same-event #Lambda - K correlator (Right SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaProton_leftSB", "Same-event #Lambda - p correlator (Left SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rSECorrRegistry.add("hSameLambdaProton_rightSB", "Same-event #Lambda - p correlator (Right SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + + rMECorrRegistry.add("hMixLambdaPion_SGNL", "Mixed-event #Lambda - #pi correlator (SGNL region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaPion_SB", "Mixed-event #Lambda - #pi correlator (SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaKaon_SGNL", "Mixed-event #Lambda - K correlator (SGNL region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaKaon_SB", "Mixed-event #Lambda - K correlator (SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaProton_SGNL", "Mixed-event #Lambda - p correlator (SGNL region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaProton_SB", "Mixed-event #Lambda - p correlator (SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaPion_MC", "Mixed-event #Lambda - #pi correlator (MC)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaKaon_MC", "Mixed-event #Lambda - K correlator (MC)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaProton_MC", "Mixed-event #Lambda - p correlator (MC)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + + rMECorrRegistry.add("hMixLambdaPion_leftSB", "Mixed-event #Lambda - #pi correlator (Left SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaPion_rightSB", "Mixed-event #Lambda - #pi correlator (Right SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaKaon_leftSB", "Mixed-event #Lambda - K correlator (Left SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaKaon_rightSB", "Mixed-event #Lambda - K correlator (Right SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaProton_leftSB", "Mixed-event #Lambda - p correlator (Left SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + rMECorrRegistry.add("hMixLambdaProton_rightSB", "Mixed-event #Lambda - p correlator (Right SB region)", {HistType::kTHnSparseF, {{dPhiAxis}, {dEtaAxis}, {centralityAxis}, {zvtxAxis}, {2, -2, 2}, {2, -2, 2}}}); + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + TList* effListChargedParticles = ccdb->getForTimeStamp("Users/j/jstaa/Efficiency/ChargedParticles", 1); + TList* effListLambdas = ccdb->getForTimeStamp("Users/j/jstaa/Efficiency/Lambdas", 1); + hEffPions[0] = static_cast(effListChargedParticles->FindObject("hEfficiencyPionP")); + hEffPions[1] = static_cast(effListChargedParticles->FindObject("hEfficiencyPionN")); + hEffKaons[0] = static_cast(effListChargedParticles->FindObject("hEfficiencyKaonP")); + hEffKaons[1] = static_cast(effListChargedParticles->FindObject("hEfficiencyKaonN")); + hEffProtons[0] = static_cast(effListChargedParticles->FindObject("hEfficiencyProtonP")); + hEffProtons[1] = static_cast(effListChargedParticles->FindObject("hEfficiencyProtonN")); + hEffLambdas[0] = static_cast(effListLambdas->FindObject("hEfficiencyLambdaP")); + hEffLambdas[1] = static_cast(effListLambdas->FindObject("hEfficiencyLambdaN")); + + TList* correctionListChargedParticles = ccdb->getForTimeStamp("Users/j/jstaa/SpectraRatios/ChargedParticles", 1); + hCorrectionPions[0] = static_cast(correctionListChargedParticles->FindObject("h2DRatioPionP")); + hCorrectionPions[1] = static_cast(correctionListChargedParticles->FindObject("h2DRatioPionN")); + hCorrectionKaons[0] = static_cast(correctionListChargedParticles->FindObject("h2DRatioKaonP")); + hCorrectionKaons[1] = static_cast(correctionListChargedParticles->FindObject("h2DRatioKaonN")); + hCorrectionProtons[0] = static_cast(correctionListChargedParticles->FindObject("h2DRatioProtonP")); + hCorrectionProtons[1] = static_cast(correctionListChargedParticles->FindObject("h2DRatioProtonN")); + } + + //========================================================================================================================================================================================================================================================================== + + void processSame(MyFilteredCollision const& collision, aod::V0Datas const& v0s, MyFilteredTracks const& tracks, aod::BCsWithTimestamps const&) + { + + if (!acceptEvent(collision, true)) { + return; + } + + auto bc = collision.bc_as(); + auto bField = getMagneticField(bc.timestamp()); + if (switchGroup.confBfieldSwitch != 0) { + if (std::signbit(static_cast(switchGroup.confBfieldSwitch)) != std::signbit(bField)) { + return; + } + } + + rQARegistry.fill(HIST("hEventCentrality"), collision.centFT0C()); + rQARegistry.fill(HIST("hEventZvtx"), collision.posZ()); + rQARegistry.fill(HIST("hEventOccupancy"), collision.trackOccupancyInTimeRange()); + rQARegistry.fill(HIST("hEventBfield"), bField); + + // Start of the Track QA + for (const auto& track : tracks) { + rQARegistry.fill(HIST("hTPCPion"), track.pt(), track.tpcNSigmaPi(), track.sign()); + rQARegistry.fill(HIST("hTPCKaon"), track.pt(), track.tpcNSigmaKa(), track.sign()); + rQARegistry.fill(HIST("hTPCProton"), track.pt(), track.tpcNSigmaPr(), track.sign()); + if (track.hasTOF()) { + rQARegistry.fill(HIST("hTOFPion"), track.pt(), track.tofNSigmaPi(), track.sign()); + rQARegistry.fill(HIST("hTOFKaon"), track.pt(), track.tofNSigmaKa(), track.sign()); + rQARegistry.fill(HIST("hTOFProton"), track.pt(), track.tofNSigmaPr(), track.sign()); + } + + 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("hTrackNSharedClusters"), track.tpcNClsShared()); + rQARegistry.fill(HIST("hdEdx"), track.sign() * track.pt(), track.tpcSignal()); + rQARegistry.fill(HIST("hBeta"), track.sign() * track.pt(), track.beta()); + if (assocPID[0] == pionID) { // Pions + rQARegistry.fill(HIST("hPtPion_Uncorrected"), track.pt(), collision.centFT0C(), track.sign()); + rQARegistry.fill(HIST("hPtPion_Corrected"), track.pt(), collision.centFT0C(), track.sign(), ratioCorrection(hCorrectionPions, track, collision.centFT0C()) / trackEff(hEffPions, track, collision.centFT0C())); + rQARegistry.fill(HIST("hdEdxPion"), track.sign() * track.pt(), track.tpcSignal()); + rQARegistry.fill(HIST("hBetaPion"), track.sign() * track.pt(), track.beta()); + } else if (assocPID[0] == kaonID) { // Kaons + rQARegistry.fill(HIST("hPtKaon_Uncorrected"), track.pt(), collision.centFT0C(), track.sign()); + rQARegistry.fill(HIST("hPtKaon_Corrected"), track.pt(), collision.centFT0C(), track.sign(), ratioCorrection(hCorrectionKaons, track, collision.centFT0C()) / trackEff(hEffKaons, track, collision.centFT0C())); + rQARegistry.fill(HIST("hdEdxKaon"), track.sign() * track.pt(), track.tpcSignal()); + rQARegistry.fill(HIST("hBetaKaon"), track.sign() * track.pt(), track.beta()); + } else if (assocPID[0] == protonID) { // Protons + rQARegistry.fill(HIST("hPtProton_Uncorrected"), track.pt(), collision.centFT0C(), track.sign()); + rQARegistry.fill(HIST("hPtProton_Corrected"), track.pt(), collision.centFT0C(), track.sign(), ratioCorrection(hCorrectionProtons, track, collision.centFT0C()) / trackEff(hEffProtons, track, collision.centFT0C())); + rQARegistry.fill(HIST("hdEdxProton"), track.sign() * track.pt(), track.tpcSignal()); + rQARegistry.fill(HIST("hBetaProton"), track.sign() * track.pt(), track.beta()); + } + } + } + // End of the Track QA + + // Start of the Same-Event correlations + for (const auto& trigger : v0s) { + if (v0Filters(collision, trigger, tracks)) { + + triggSign = v0Sign(trigger); + v0Efficiency = v0Eff(hEffLambdas, trigger, collision.centFT0C()); + + rQARegistry.fill(HIST("hPtV0_Uncorrected"), trigger.pt(), collision.centFT0C(), triggSign); + rQARegistry.fill(HIST("hPtV0_Corrected"), trigger.pt(), collision.centFT0C(), triggSign, 1. / v0Efficiency); + if (triggSign == 1) { + candMass = trigger.mLambda(); + rQARegistry.fill(HIST("hInvMassLambda"), trigger.mLambda(), trigger.pt(), collision.centFT0C(), 1. / v0Efficiency); + } else if (triggSign == -1) { + candMass = trigger.mAntiLambda(); + rQARegistry.fill(HIST("hInvMassAntiLambda"), trigger.mAntiLambda(), trigger.pt(), collision.centFT0C(), 1. / v0Efficiency); + } + + 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 (assocPID[0] == pionID) { // Pions + rQARegistry.fill(HIST("hPtPion_Looped"), associate.pt(), collision.centFT0C(), associate.sign(), ratioCorrection(hCorrectionPions, associate, collision.centFT0C()) / trackEff(hEffPions, associate, collision.centFT0C())); + } else if (assocPID[0] == kaonID) { // Kaons + rQARegistry.fill(HIST("hPtKaon_Looped"), associate.pt(), collision.centFT0C(), associate.sign(), ratioCorrection(hCorrectionKaons, associate, collision.centFT0C()) / trackEff(hEffKaons, associate, collision.centFT0C())); + } else if (assocPID[0] == protonID) { // Protons + rQARegistry.fill(HIST("hPtProton_Looped"), associate.pt(), collision.centFT0C(), associate.sign(), ratioCorrection(hCorrectionProtons, associate, collision.centFT0C()) / trackEff(hEffProtons, associate, collision.centFT0C())); + } + + if (candMass >= MassLambda0 - invMassNSigma * dGaussSigma && candMass <= MassLambda0 + invMassNSigma * dGaussSigma) { + if (assocPID[0] == pionID) { // Pions + rSECorrRegistry.fill(HIST("hSameLambdaPion_SGNL"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionPions, associate, collision.centFT0C()) / (trackEff(hEffPions, associate, collision.centFT0C()) * v0Efficiency)); + } else if (assocPID[0] == kaonID) { // Kaons + rSECorrRegistry.fill(HIST("hSameLambdaKaon_SGNL"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionKaons, associate, collision.centFT0C()) / (trackEff(hEffKaons, associate, collision.centFT0C()) * v0Efficiency)); + } else if (assocPID[0] == protonID) { // Protons + rSECorrRegistry.fill(HIST("hSameLambdaProton_SGNL"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionProtons, associate, collision.centFT0C()) / (trackEff(hEffProtons, associate, collision.centFT0C()) * v0Efficiency)); + } + + } else if (candMass >= MassLambda0 - 2 * invMassNSigma * dGaussSigma && candMass <= MassLambda0 + 2 * invMassNSigma * dGaussSigma) { + if (assocPID[0] == pionID) { // Pions + rSECorrRegistry.fill(HIST("hSameLambdaPion_SB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionPions, associate, collision.centFT0C()) / (trackEff(hEffPions, associate, collision.centFT0C()) * v0Efficiency)); + if (candMass >= MassLambda0 - 2 * invMassNSigma * dGaussSigma && candMass < MassLambda0 - invMassNSigma * dGaussSigma) { + rSECorrRegistry.fill(HIST("hSameLambdaPion_leftSB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionPions, associate, collision.centFT0C()) / (trackEff(hEffPions, associate, collision.centFT0C()) * v0Efficiency)); + } else if (candMass > MassLambda0 + invMassNSigma * dGaussSigma && candMass <= MassLambda0 + 2 * invMassNSigma * dGaussSigma) { + rSECorrRegistry.fill(HIST("hSameLambdaPion_rightSB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionPions, associate, collision.centFT0C()) / (trackEff(hEffPions, associate, collision.centFT0C()) * v0Efficiency)); + } + + } else if (assocPID[0] == kaonID) { // Kaons + rSECorrRegistry.fill(HIST("hSameLambdaKaon_SB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionKaons, associate, collision.centFT0C()) / (trackEff(hEffKaons, associate, collision.centFT0C()) * v0Efficiency)); + if (candMass >= MassLambda0 - 2 * invMassNSigma * dGaussSigma && candMass < MassLambda0 - invMassNSigma * dGaussSigma) { + rSECorrRegistry.fill(HIST("hSameLambdaKaon_leftSB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionKaons, associate, collision.centFT0C()) / (trackEff(hEffKaons, associate, collision.centFT0C()) * v0Efficiency)); + } else if (candMass > MassLambda0 + invMassNSigma * dGaussSigma && candMass <= MassLambda0 + 2 * invMassNSigma * dGaussSigma) { + rSECorrRegistry.fill(HIST("hSameLambdaKaon_rightSB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionKaons, associate, collision.centFT0C()) / (trackEff(hEffKaons, associate, collision.centFT0C()) * v0Efficiency)); + } + + } else if (assocPID[0] == protonID) { // Protons + rSECorrRegistry.fill(HIST("hSameLambdaProton_SB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionProtons, associate, collision.centFT0C()) / (trackEff(hEffProtons, associate, collision.centFT0C()) * v0Efficiency)); + if (candMass >= MassLambda0 - 2 * invMassNSigma * dGaussSigma && candMass < MassLambda0 - invMassNSigma * dGaussSigma) { + rSECorrRegistry.fill(HIST("hSameLambdaProton_leftSB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionProtons, associate, collision.centFT0C()) / (trackEff(hEffProtons, associate, collision.centFT0C()) * v0Efficiency)); + } else if (candMass > MassLambda0 + invMassNSigma * dGaussSigma && candMass <= MassLambda0 + 2 * invMassNSigma * dGaussSigma) { + rSECorrRegistry.fill(HIST("hSameLambdaProton_rightSB"), deltaPhi, deltaEta, collision.centFT0C(), collision.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionProtons, associate, collision.centFT0C()) / (trackEff(hEffProtons, associate, collision.centFT0C()) * v0Efficiency)); + } + } + } + } + } + } + } + } + // End of the Same-Event correlations + } + + void processMixed(MyFilteredCollisions const&, aod::V0Datas const&, MyFilteredTracks const& tracks, aod::BCsWithTimestamps const&) + { + + // Start of the Mixed-Event correlations + for (const auto& [coll_1, v0_1, coll_2, track_2] : pairData) { + if (!acceptEvent(coll_1, false)) { + continue; + } + if (!acceptEvent(coll_2, false)) { + continue; + } + + auto bc = coll_1.bc_as(); + auto bField = getMagneticField(bc.timestamp()); + if (switchGroup.confBfieldSwitch != 0) { + if (std::signbit(static_cast(switchGroup.confBfieldSwitch)) != std::signbit(bField)) { + continue; + } + } + + for (const auto& [trigger, associate] : soa::combinations(soa::CombinationsFullIndexPolicy(v0_1, track_2))) { + if (v0Filters(coll_1, trigger, tracks) && trackFilters(associate)) { + if (radialDistanceFilter(trigger, associate, bField, true) && fakeV0Filter(trigger, associate)) { + + triggSign = v0Sign(trigger); + v0Efficiency = v0Eff(hEffLambdas, trigger, coll_1.centFT0C()); + + 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 - invMassNSigma * dGaussSigma && candMass <= MassLambda0 + invMassNSigma * dGaussSigma) { + if (assocPID[0] == pionID) { // Pions + rMECorrRegistry.fill(HIST("hMixLambdaPion_SGNL"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionPions, associate, coll_1.centFT0C()) / (trackEff(hEffPions, associate, coll_1.centFT0C()) * v0Efficiency)); + } else if (assocPID[0] == kaonID) { // Kaons + rMECorrRegistry.fill(HIST("hMixLambdaKaon_SGNL"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionKaons, associate, coll_1.centFT0C()) / (trackEff(hEffKaons, associate, coll_1.centFT0C()) * v0Efficiency)); + } else if (assocPID[0] == protonID) { // Protons + rMECorrRegistry.fill(HIST("hMixLambdaProton_SGNL"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionProtons, associate, coll_1.centFT0C()) / (trackEff(hEffProtons, associate, coll_1.centFT0C()) * v0Efficiency)); + } + + } else if (candMass >= MassLambda0 - 2 * invMassNSigma * dGaussSigma && candMass <= MassLambda0 + 2 * invMassNSigma * dGaussSigma) { + if (assocPID[0] == pionID) { // Pions + rMECorrRegistry.fill(HIST("hMixLambdaPion_SB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionPions, associate, coll_1.centFT0C()) / (trackEff(hEffPions, associate, coll_1.centFT0C()) * v0Efficiency)); + if (candMass >= MassLambda0 - 2 * invMassNSigma * dGaussSigma && candMass < MassLambda0 - invMassNSigma * dGaussSigma) { + rMECorrRegistry.fill(HIST("hMixLambdaPion_leftSB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionPions, associate, coll_1.centFT0C()) / (trackEff(hEffPions, associate, coll_1.centFT0C()) * v0Efficiency)); + } else if (candMass > MassLambda0 + invMassNSigma * dGaussSigma && candMass <= MassLambda0 + 2 * invMassNSigma * dGaussSigma) { + rMECorrRegistry.fill(HIST("hMixLambdaPion_rightSB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionPions, associate, coll_1.centFT0C()) / (trackEff(hEffPions, associate, coll_1.centFT0C()) * v0Efficiency)); + } + + } else if (assocPID[0] == kaonID) { // Kaons + rMECorrRegistry.fill(HIST("hMixLambdaKaon_SB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionKaons, associate, coll_1.centFT0C()) / (trackEff(hEffKaons, associate, coll_1.centFT0C()) * v0Efficiency)); + if (candMass >= MassLambda0 - 2 * invMassNSigma * dGaussSigma && candMass < MassLambda0 - invMassNSigma * dGaussSigma) { + rMECorrRegistry.fill(HIST("hMixLambdaKaon_leftSB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionKaons, associate, coll_1.centFT0C()) / (trackEff(hEffKaons, associate, coll_1.centFT0C()) * v0Efficiency)); + } else if (candMass > MassLambda0 + invMassNSigma * dGaussSigma && candMass <= MassLambda0 + 2 * invMassNSigma * dGaussSigma) { + rMECorrRegistry.fill(HIST("hMixLambdaKaon_rightSB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionKaons, associate, coll_1.centFT0C()) / (trackEff(hEffKaons, associate, coll_1.centFT0C()) * v0Efficiency)); + } + + } else if (assocPID[0] == protonID) { // Protons + rMECorrRegistry.fill(HIST("hMixLambdaProton_SB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionProtons, associate, coll_1.centFT0C()) / (trackEff(hEffProtons, associate, coll_1.centFT0C()) * v0Efficiency)); + if (candMass >= MassLambda0 - 2 * invMassNSigma * dGaussSigma && candMass < MassLambda0 - invMassNSigma * dGaussSigma) { + rMECorrRegistry.fill(HIST("hMixLambdaProton_leftSB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionProtons, associate, coll_1.centFT0C()) / (trackEff(hEffProtons, associate, coll_1.centFT0C()) * v0Efficiency)); + } else if (candMass > MassLambda0 + invMassNSigma * dGaussSigma && candMass <= MassLambda0 + 2 * invMassNSigma * dGaussSigma) { + rMECorrRegistry.fill(HIST("hMixLambdaProton_rightSB"), deltaPhi, deltaEta, coll_1.centFT0C(), coll_1.posZ(), triggSign, associate.sign(), ratioCorrection(hCorrectionProtons, associate, coll_1.centFT0C()) / (trackEff(hEffProtons, associate, coll_1.centFT0C()) * v0Efficiency)); + } + } + } + } + } + } + } + // End of the Mixed-Event Correlations + } + + void processMCSame(MyFilteredMCGenCollision const& collision, MyFilteredMCParticles const&, soa::SmallGroups const& recCollisions) + { + + if (recCollisions.size() == 1 && acceptEvent(recCollisions.begin(), false)) { + + 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 Track QA + for (const auto& track : groupMCAssociates) { + if (track.isPhysicalPrimary()) { + + if (track.pdgCode() > 0) { + assocSign = 1; + } else if (track.pdgCode() < 0) { + assocSign = -1; + } + + if (std::abs(track.pdgCode()) == kPiPlus) { // Pions + rQARegistry.fill(HIST("hPtPion_MC"), track.pt(), collision.bestCollisionCentFT0C(), assocSign); + } else if (std::abs(track.pdgCode()) == kKPlus) { // Kaons + rQARegistry.fill(HIST("hPtKaon_MC"), track.pt(), collision.bestCollisionCentFT0C(), assocSign); + } else if (std::abs(track.pdgCode()) == kProton) { // Protons + rQARegistry.fill(HIST("hPtProton_MC"), track.pt(), collision.bestCollisionCentFT0C(), assocSign); + } + } + } + // End of the MC Track QA + + // 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("hPtV0_MC"), trigger.pt(), collision.bestCollisionCentFT0C(), triggSign); + 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&, MyFilteredMCRecCollisions const& recCollisions) + { + + // Start of the MC Mixed-events Correlations + for (const auto& [coll_1, v0_1, coll_2, particle_2] : pairMC) { + auto recCollsA1 = recCollisions.sliceBy(perMCCol, coll_1.globalIndex()); + auto recCollsA2 = recCollisions.sliceBy(perMCCol, coll_2.globalIndex()); + if (recCollsA1.size() == 1 && recCollsA2.size() == 1 && acceptEvent(recCollsA1.begin(), false) && acceptEvent(recCollsA2.begin(), false)) { + + LOGF(info, "Size_1 = %i, Size_2 = %i", recCollsA1.size(), recCollsA1.size()); + 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&, soa::SmallGroups const& recCollisions) + { + + if (recCollisions.size() == 1 && acceptEvent(recCollisions.begin(), false)) { + + auto groupMCTracks = mcTracks->sliceByCached(aod::mcparticle::mcCollisionId, collision.globalIndex(), cache); + auto groupMCV0s = mcV0s->sliceByCached(aod::mcparticle::mcCollisionId, collision.globalIndex(), cache); + + // Start of the Monte-Carlo generated QA + for (const auto& particle : groupMCTracks) { + if (particle.isPhysicalPrimary()) { + + // Track efficiency - Generated + rMCRegistry.fill(HIST("hGenerated"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + if (particle.pdgCode() == kPiPlus) { // Pos pions + rMCRegistry.fill(HIST("hGenPionP"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + } else if (particle.pdgCode() == kPiMinus) { // Neg pions + rMCRegistry.fill(HIST("hGenPionN"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + } else if (particle.pdgCode() == kKPlus) { // Pos kaons + rMCRegistry.fill(HIST("hGenKaonP"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + } else if (particle.pdgCode() == kKMinus) { // Neg kaons + rMCRegistry.fill(HIST("hGenKaonN"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + } else if (particle.pdgCode() == kProton) { // Pos protons + rMCRegistry.fill(HIST("hGenProtonP"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + } else if (particle.pdgCode() == kProtonBar) { // Neg protons + rMCRegistry.fill(HIST("hGenProtonN"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + } + } + } + + for (const auto& particle : groupMCV0s) { + if (particle.isPhysicalPrimary()) { + + // V0 efficiency - Generated + if (particle.pdgCode() == kLambda0) { // Lambdas + rMCRegistry.fill(HIST("hGenLambdaP"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + } else if (particle.pdgCode() == kLambda0Bar) { // AntiLambdas + rMCRegistry.fill(HIST("hGenLambdaN"), particle.pt(), particle.eta(), collision.bestCollisionCentFT0C()); + } + } + } + // End of the Monte-Carlo generated QA + } + } + + void processMCRec(MyFilteredMCRecCollisions::iterator const& collision, MyMCV0s const& v0s, MyFilteredMCTracks const& tracks, aod::McCollisions const&, aod::McParticles const&) + { + + if (!acceptEvent(collision, false) || !collision.has_mcCollision()) { + return; + } + + // Start of the Monte-Carlo reconstructed QA + for (const auto& track : tracks) { + + if (!track.has_mcParticle()) { + continue; + } + auto particle = track.mcParticle(); + + // Track efficiency - Reconstructed + rMCRegistry.fill(HIST("hReconstructed"), track.pt(), track.eta(), collision.centFT0C()); + if (particle.pdgCode() == kPiPlus) { // Pos pions + rMCRegistry.fill(HIST("hRecPionP"), track.pt(), track.eta(), collision.centFT0C()); + } else if (particle.pdgCode() == kPiMinus) { // Neg pions + rMCRegistry.fill(HIST("hRecPionN"), track.pt(), track.eta(), collision.centFT0C()); + } else if (particle.pdgCode() == kKPlus) { // Pos kaons + rMCRegistry.fill(HIST("hRecKaonP"), track.pt(), track.eta(), collision.centFT0C()); + } else if (particle.pdgCode() == kKMinus) { // Neg kaons + rMCRegistry.fill(HIST("hRecKaonN"), track.pt(), track.eta(), collision.centFT0C()); + } else if (particle.pdgCode() == kProton) { // Pos protons + rMCRegistry.fill(HIST("hRecProtonP"), track.pt(), track.eta(), collision.centFT0C()); + } else if (particle.pdgCode() == kProtonBar) { // Neg protons + rMCRegistry.fill(HIST("hRecProtonN"), track.pt(), track.eta(), collision.centFT0C()); + } + + if (trackFilters(track)) { + + // Track efficiency - Reconstructed & PID filters applied + assocPID = trackPID(track); + rMCRegistry.fill(HIST("hIdentified"), track.pt(), track.eta(), collision.centFT0C()); + if (assocPID[0] == pionID && track.sign() > 0) { // Pos pions + rMCRegistry.fill(HIST("hPIDPionP"), track.pt(), track.eta(), collision.centFT0C()); + } else if (assocPID[0] == pionID && track.sign() < 0) { // Neg pions + rMCRegistry.fill(HIST("hPIDPionN"), track.pt(), track.eta(), collision.centFT0C()); + } else if (assocPID[0] == kaonID && track.sign() > 0) { // Pos kaons + rMCRegistry.fill(HIST("hPIDKaonP"), track.pt(), track.eta(), collision.centFT0C()); + } else if (assocPID[0] == kaonID && track.sign() < 0) { // Neg kaons + rMCRegistry.fill(HIST("hPIDKaonN"), track.pt(), track.eta(), collision.centFT0C()); + } else if (assocPID[0] == protonID && track.sign() > 0) { // Pos protons + rMCRegistry.fill(HIST("hPIDProtonP"), track.pt(), track.eta(), collision.centFT0C()); + } else if (assocPID[0] == protonID && track.sign() < 0) { // Neg protons + rMCRegistry.fill(HIST("hPIDProtonN"), track.pt(), track.eta(), collision.centFT0C()); + } + + // Purity (PID) + 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()); + } + } + } + } + } + + for (const auto& v0 : v0s) { + + if (!v0.has_mcParticle()) { + continue; + } + + if (v0Filters(collision, v0, tracks)) { + + v0Efficiency = v0Eff(hEffLambdas, v0, collision.centFT0C()); + + // V0 efficiency - Reconstructed + if (v0Sign(v0) == 1) { // Lambdas + candMass = v0.mLambda(); + rQARegistry.fill(HIST("hInvMassLambda_MC"), v0.mLambda(), v0.pt(), collision.centFT0C(), 1. / v0Efficiency); + rMCRegistry.fill(HIST("hRecLambdaP"), v0.pt(), v0.eta(), collision.centFT0C()); + } else if (v0Sign(v0) == -1) { // AntiLambdas + candMass = v0.mAntiLambda(); + rQARegistry.fill(HIST("hInvMassAntiLambda_MC"), v0.mAntiLambda(), v0.pt(), collision.centFT0C(), 1. / v0Efficiency); + rMCRegistry.fill(HIST("hRecLambdaN"), v0.pt(), v0.eta(), collision.centFT0C()); + } + } + } + // 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 v0Eff(TH3D** efficiencies, const V0Cand& v0, double centrality) + { + + int index = -999; + if (v0Sign(v0) > 0) { + index = 0; + } else if (v0Sign(v0) < 0) { + index = 1; + } + + double efficiency = efficiencies[index]->GetBinContent(efficiencies[index]->FindBin(v0.pt(), v0.eta(), centrality)); + if (efficiency > 0) { + return efficiency; + } else { + return 1.0; + } + } + + template + double trackEff(TH3D** efficiencies, const TrackCand& track, double centrality) + { + + 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(), centrality)); + if (efficiency > 0) { + return efficiency; + } else { + return 1.0; + } + } + + template + double ratioCorrection(TH2D** ratios, const TrackCand& track, double centrality) + { + + double ratioCorrection = 1.0; + if (switchGroup.confRatioCorrectionSwitch) { + + int index = -999; + if (track.sign() > 0) { + index = 0; + } else if (track.sign() < 0) { + index = 1; + } + + ratioCorrection = ratios[index]->GetBinContent(ratios[index]->FindBin(track.pt(), centrality)); + } + + return ratioCorrection; + } + + 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 acceptEvent(const Col& col, bool FillHist) // Event filter + { + + if (FillHist) { + rQARegistry.fill(HIST("hNEvents"), 0.5); + } + + if (!col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { // kIsGoodZvtxFT0vsPV + return false; + } + if (FillHist) { + rQARegistry.fill(HIST("hNEvents"), 1.5); + } + + if (!col.selection_bit(aod::evsel::kNoSameBunchPileup)) { // kNoSameBunchPileup + return false; + } + if (FillHist) { + rQARegistry.fill(HIST("hNEvents"), 2.5); + } + + if (evSelGroup.useOccupCut) { + if (!col.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) { // kNoCollInTimeRangeStandard + return false; + } + if (FillHist) { + rQARegistry.fill(HIST("hNEvents"), 4.5); + } + } + + return true; + } + + template + bool v0Filters(const Col& col, const V0Cand& v0, T const&) // V0 filter + { + + // Kinematic cuts + if (v0.pt() <= v0PtMin || v0.pt() >= v0PtMax || std::abs(v0.eta()) >= v0EtaMax) { + return false; + } + + // Daughter cuts + auto posDaughter = v0.template posTrack_as(); + auto negDaughter = v0.template negTrack_as(); + if (std::abs(posDaughter.eta()) >= trackEtaMax || std::abs(negDaughter.eta()) >= trackEtaMax) { + return false; + } + if (posDaughter.tpcNClsCrossedRows() <= v0SelGroup.tpcNCrossedRows || negDaughter.tpcNClsCrossedRows() <= v0SelGroup.tpcNCrossedRows) { + return false; + } + if (v0Sign(v0) == 1) { + if (std::abs(posDaughter.tpcNSigmaPr()) >= nSigma5 || std::abs(negDaughter.tpcNSigmaPi()) >= nSigma5) { + return false; + } + if (std::abs(v0.dcapostopv()) <= v0SelGroup.dcaProton || std::abs(v0.dcanegtopv()) <= v0SelGroup.dcaPion) { + return false; + } + } else if (v0Sign(v0) == -1) { + if (std::abs(posDaughter.tpcNSigmaPi()) >= nSigma5 || std::abs(negDaughter.tpcNSigmaPr()) >= nSigma5) { + return false; + } + if (std::abs(v0.dcapostopv()) <= v0SelGroup.dcaPion || std::abs(v0.dcanegtopv()) <= v0SelGroup.dcaProton) { + return false; + } + } + + // Topological cuts + float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * MassLambda0; + if (v0.v0radius() <= v0SelGroup.decayR) { + return false; + } + if (ctau >= v0SelGroup.ctau) { + return false; + } + if (v0.v0cosPA() <= v0SelGroup.cosPA) { + return false; + } + if (v0.dcaV0daughters() >= v0SelGroup.dcaV0Dau) { + return false; + } + + return true; + } + + template + bool trackFilters(const TrackCand& track) // Track filter + { + + if (!track.hasTOF()) { + return false; + } + + if (trackPID(track)[0] == pionID) { // Pions + if (std::abs(track.tpcNSigmaPi()) >= nSigma4) { + return false; + } + if (track.pt() < pionPtMin) { + return false; + } else if (track.pt() > pionPtMin && track.pt() < pionPtMid1) { + if (std::abs(track.tofNSigmaPi()) >= nSigma4) { + return false; + } + } else if (track.pt() > pionPtMid1 && track.pt() < pionPtMid2) { + if (track.tofNSigmaPi() <= -nSigma4 || track.tofNSigmaPi() >= nSigma2) { + return false; + } + } else if (track.pt() > pionPtMid2 && track.pt() < pionPtMax) { + if (track.tofNSigmaPi() <= -nSigma4 || track.tofNSigmaPi() >= nSigma0) { + return false; + } + } else if (track.pt() > pionPtMax) { + return false; + } + + } else if (trackPID(track)[0] == kaonID) { // Kaons + if (std::abs(track.tpcNSigmaKa()) >= nSigma4) { + return false; + } + if (track.pt() < kaonPtMin) { + return false; + } else if (track.pt() > kaonPtMin && track.pt() < kaonPtMid1) { + if (std::abs(track.tofNSigmaKa()) >= nSigma4) { + return false; + } + } else if (track.pt() > kaonPtMid1 && track.pt() < kaonPtMid2) { + if (track.tofNSigmaKa() <= -nSigma1 || track.tofNSigmaKa() >= nSigma4) { + return false; + } + } else if (track.pt() > kaonPtMid2 && track.pt() < kaonPtMax) { + if (track.tofNSigmaKa() <= nSigma0 || track.tofNSigmaKa() >= nSigma4) { + return false; + } + } else if (track.pt() > kaonPtMax) { + return false; + } + + } else if (trackPID(track)[0] == protonID) { // Protons + if (std::abs(track.tpcNSigmaPr()) >= nSigma4) { + return false; + } + if (track.pt() < protonPtMin) { + return false; + } else if (track.pt() > protonPtMin && track.pt() < protonPtMid) { + if (std::abs(track.tofNSigmaPr()) >= nSigma4) { + return false; + } + } else if (track.pt() > protonPtMid) { + if (track.tofNSigmaPr() <= -nSigma2 || track.tofNSigmaPr() >= nSigma4) { + return false; + } + } + } + + return true; + } + + template + bool correlationFilters(const V0Cand& v0, const TrackCand& track) // Correlation filter + { + + if (track.globalIndex() == v0.posTrackId() || track.globalIndex() == v0.negTrackId()) { + return false; + } + + return true; + } + + template + bool fakeV0Filter(const V0Cand& v0, const TrackCand& track) + { + + if (switchGroup.confFakeV0Switch) { + + if (trackPID(track)[0] == kaonID) { // Kaons + return true; + } + + 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 - invMassNSigma * dGaussSigma && invMass <= MassLambda0 + invMassNSigma * dGaussSigma) { + return false; + } + } + + return true; + } + + template + bool radialDistanceFilter(const V0Cand& v0, const TrackCand& track, double B, bool Mix) + { + + bool pass = true; + if (switchGroup.confRDSwitch) { + + 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) > dEtaMax) { + return pass; + } + + 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()); + + double dPhiStarMean = 0; + + // Start of the TPC radius loop + 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) { // Same-event + if (proton.sign() * track.sign() == -1) { // OS (Electric charge) + rPhiStarRegistry.fill(HIST("hSEPhiStarIR_OS"), dPhiStar, dEta); + } else if (proton.sign() * track.sign() == 1) { // SS (Electric charge) + rPhiStarRegistry.fill(HIST("hSEPhiStarIR_SS"), dPhiStar, dEta); + if (proton.sign() == 1) { // Positive + rPhiStarRegistry.fill(HIST("hSEPhiStarIR_SSP"), dPhiStar, dEta); + } else if (proton.sign() == -1) { // Negative + rPhiStarRegistry.fill(HIST("hSEPhiStarIR_SSN"), dPhiStar, dEta); + } + } + + } else { // Mixed-event + if (proton.sign() * track.sign() == -1) { // OS (Electric charge) + rPhiStarRegistry.fill(HIST("hMEPhiStarIR_OS"), dPhiStar, dEta); + } else if (proton.sign() * track.sign() == 1) { // SS (Electric charge) + rPhiStarRegistry.fill(HIST("hMEPhiStarIR_SS"), dPhiStar, dEta); + if (proton.sign() == 1) { // Positive + rPhiStarRegistry.fill(HIST("hMEPhiStarIR_SSP"), dPhiStar, dEta); + } else if (proton.sign() == -1) { // Negative + rPhiStarRegistry.fill(HIST("hMEPhiStarIR_SSN"), dPhiStar, dEta); + } + } + } + + if (proton.sign() * track.sign() == -1) { // OS (Electric charge) + if (std::abs(dEta) < dEtaMin && std::abs(dPhiStar) < dPhiStarMinOS) { + pass = false; + } + } + } + + dPhiStarMean += (dPhiStar / 170); + } + // End of the TPC radius loop + + if (!Mix) { // Same-event + if (proton.sign() * track.sign() == -1) { // OS (Electric charge) + rPhiStarRegistry.fill(HIST("hSEPhiStarMean_OS"), dPhiStarMean, dEta); + } else if (proton.sign() * track.sign() == 1) { // SS (Electric charge) + rPhiStarRegistry.fill(HIST("hSEPhiStarMean_SS"), dPhiStarMean, dEta); + if (proton.sign() == 1) { // Positive + rPhiStarRegistry.fill(HIST("hSEPhiStarMean_SSP"), dPhiStarMean, dEta); + } else if (proton.sign() == -1) { // Negative + rPhiStarRegistry.fill(HIST("hSEPhiStarMean_SSN"), dPhiStarMean, dEta); + } + } + + } else { // Mixed-event + if (proton.sign() * track.sign() == -1) { // OS (Electric charge) + rPhiStarRegistry.fill(HIST("hMEPhiStarMean_OS"), dPhiStarMean, dEta); + } else if (proton.sign() * track.sign() == 1) { // SS (Electric charge) + rPhiStarRegistry.fill(HIST("hMEPhiStarMean_SS"), dPhiStarMean, dEta); + if (proton.sign() == 1) { // Positive + rPhiStarRegistry.fill(HIST("hMEPhiStarMean_SSP"), dPhiStarMean, dEta); + } else if (proton.sign() == -1) { // Negative + rPhiStarRegistry.fill(HIST("hMEPhiStarMean_SSN"), dPhiStarMean, dEta); + } + } + } + + if (proton.sign() * track.sign() == 1) { // SS (Electric charge) + if (std::abs(dEta) < dEtaMin && std::abs(dPhiStarMean) < dPhiStarMinSS) { + pass = false; + } + } + } + + return pass; + } +}; + +//============================================================================================================================================================================================================================================================================ + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} + +//============================================================================================================================================================================================================================================================================ diff --git a/PWGCF/TableProducer/CMakeLists.txt b/PWGCF/TableProducer/CMakeLists.txt index 1bfef915ff3..6438d45a5fe 100644 --- a/PWGCF/TableProducer/CMakeLists.txt +++ b/PWGCF/TableProducer/CMakeLists.txt @@ -19,7 +19,7 @@ o2physics_add_dpl_workflow(filter-correlations-2prong PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(dptdpt-filter - SOURCES dptdptfilter.cxx +o2physics_add_dpl_workflow(dpt-dpt-filter + SOURCES dptDptFilter.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) diff --git a/PWGCF/TableProducer/dptdptfilter.cxx b/PWGCF/TableProducer/dptDptFilter.cxx similarity index 50% rename from PWGCF/TableProducer/dptdptfilter.cxx rename to PWGCF/TableProducer/dptDptFilter.cxx index ff5930aa9cc..0378692eb71 100644 --- a/PWGCF/TableProducer/dptdptfilter.cxx +++ b/PWGCF/TableProducer/dptDptFilter.cxx @@ -9,36 +9,49 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include +/// \file dptDptFilter.cxx +/// \brief Filters collisions and tracks according to selection criteria +/// \author victor.gonzalez.sebastian@gmail.com + +#include "PWGCF/TableProducer/dptDptFilter.h" + +#include "PWGCF/Core/AnalysisConfigurableCuts.h" +#include "PWGCF/DataModel/DptDptFiltered.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" #include "Common/Core/TableHelper.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include "PWGCF/DataModel/DptDptFiltered.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" -#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RunningWorkflowInfo.h" -#include -#include -#include -#include +#include "Framework/runDataProcessing.h" + #include #include #include #include #include +#include +#include +#include #include +#include -#include "PWGCF/TableProducer/dptdptfilter.h" +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -67,6 +80,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,16 +99,99 @@ const char* speciesName[kDptDptNoOfSpecies] = {"h", "e", "mu", "pi", "ka", "p"}; const char* speciesTitle[kDptDptNoOfSpecies] = {"", "e", "#mu", "#pi", "K", "p"}; +/// \enum BeforeAfter +/// \brief when filling the histograms +enum BeforeAfter { + BeforeAfterBEFORE = 0, ///< filling the histograms before selections + BeforeAfterBEFOREMULTCORR, ///< filling the histograms before outliers exclusion + BeforeAfterAFTER, ///< filling the histograms after selections + BeforeAfterNOOFTIMES ///< how many times fill the histograms +}; + +static const std::vector beforeAfterName = {"before", "before outliers exclusion", ""}; +static const std::vector beforeAfterSuffix = {"B", "BO", "A"}; + +/* helpers for the multiplicity axes definition */ +static constexpr float MultiplicityUpperLimitBase[11][8] = { + /* T0A, T0C, T0M, V0A, V0C, V0M, tracks, PV contr. tracks */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 100e3f, 10e3f, 400.0f}, /* no system */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 50e3f, 5e3f, 400.0f}, /* pp Run2 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 100e3f, 10e3f, 400.0f}, /* pPb Run2 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 100e3f, 10e3f, 400.0f}, /* Pbp Run2 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 100e3f, 10e3f, 400.0f}, /* PbPb Run2 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 100e3f, 10e3f, 400.0f}, /* XeXe Run2 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 50e3f, 5e3f, 400.0f}, /* pp Run3 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 100e3f, 10e3f, 400.0f}, /* PbPb Run3 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 50e3f, 5e3f, 400.0f}, /* NeNe Run3 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 50e3f, 5e3f, 400.0f}, /* OO Run3 */ + {30e3f, 10e3f, 40e3f, 50e3f, 70e3f, 50e3f, 5e3f, 400.0f} /* pO Run3 */ +}; + +/* helpers for the multiplicity/centrality correlations exclusion formulae */ +static const std::string multiplicityCentralityCorrelationsFormulaBase[11][1] = { + /* no system */ {""}, + /* pp Run2 */ {""}, + /* pPb Run2 */ {""}, + /* Pbp Run2 */ {""}, + /* PbPb Run2 */ {""}, + /* XeXe Run2 */ {""}, + /* pp Run3 */ {""}, + /* PbPb Run3 */ {""}, + /* NeNe Run3 */ {"((221.987-0.706581*[CT0C]+0.00906828*[CT0C]*[CT0C]-23.5275*sqrt([CT0C])-2.5*(38.5823+2.00054*[CT0C]+0.0125088*[CT0C]*[CT0C]-8.47825*sqrt([CT0C])-0.273493*[CT0C]*sqrt([CT0C])))<=[MNGLTRK])&&((-0.0729502+0.79403*[MNPVC]+5.0*(0.032005+0.00372503*[MNPVC]-7.18977e-06*[MNPVC]*[MNPVC]+0.412714*sqrt([MNPVC])))>[MNGLTRK])&&((-0.0729502+0.79403*[MNPVC]-5.0*(0.032005+0.00372503*[MNPVC]-7.18977e-06*[MNPVC]*[MNPVC]+0.412714*sqrt([MNPVC])))<=[MNGLTRK])"}, + /* OO Run3 */ {"((180.584-0.211625*[CT0C]+0.00568101*[CT0C]*[CT0C]-20.9838*sqrt([CT0C])-2.5*(32.665+1.67341*[CT0C]+0.0113878*[CT0C]*[CT0C]-6.83271*sqrt([CT0C])-0.239428*[CT0C]*sqrt([CT0C])))<=[MNGLTRK])&&((-0.0533229+0.79235*[MNPVC]+5.0*(0.031512+0.0045874*[MNPVC]-1.06374e-05*[MNPVC]*[MNPVC]+0.407526*sqrt([MNPVC])))>[MNGLTRK])&&((-0.0533229+0.79235*[MNPVC]-5.0*(0.031512+0.0045874*[MNPVC]-1.06374e-05*[MNPVC]*[MNPVC]+0.407526*sqrt([MNPVC])))<=[MNGLTRK])"}, + /* pO Run3 */ {""}}; + +/* helpers for the system type assignment */ +static const std::string periodsOnSystemType[11][1] = { + /* no system */ {""}, + /* pp Run2 */ {""}, + /* pPb Run2 */ {""}, + /* Pbp Run2 */ {""}, + /* PbPb Run2 */ {"LHC18q,LHC18r"}, + /* XeXe Run2 */ {""}, + /* pp Run3 */ {"LHC22o"}, + /* PbPb Run3 */ {"LHC23zzh"}, + /* NeNe Run3 */ {"LHC25af"}, + /* OO Run3 */ {"LHC25ae"}, + /* pO Run3 */ {"LHC25ad"}}; + //============================================================================================ // The DptDptFilter histogram objects // TODO: consider registering in the histogram registry //============================================================================================ +/* event/collision histograms */ +TH1D* fhEventSelection = nullptr; +TH1D* fhTriggerSelection = nullptr; +TH2D* fhTriggerSelectionCorrelations = nullptr; TH1F* fhCentMultB = nullptr; TH1F* fhCentMultA = nullptr; TH1F* fhVertexZB = nullptr; TH1F* fhVertexZA = nullptr; TH1F* fhMultB = nullptr; TH1F* fhMultA = nullptr; + +/* multiplicty correlation histograms */ +/* B: before, A: after collision selection */ +/* credits: A. Dobrin team! */ +TH2F* fhMultiplicityVsCentrality[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhMultiplicityVsT0cMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhMultiplicityVsT0aMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhMultiplicityVsV0aMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhMultiplicityVsPvMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhPvMultiplicityVsCentrality[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhPvMultiplicityVsT0cMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhPvMultiplicityVsT0aMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhPvMultiplicityVsV0aMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhV0aMultiplicityVsCentrality[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhV0aMultiplicityVsT0cMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhV0aMultiplicityVsT0aMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhT0cMultiplicityVsCentrality[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhT0cMultiplicityVsT0aMultiplicity[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhT0CentralityVsCentrality[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhV0aCentralityVsCentrality[BeforeAfterNOOFTIMES] = {nullptr}; +TH2F* fhNtpvCentralityVsCentrality[BeforeAfterNOOFTIMES] = {nullptr}; + +/* track histograms */ TH1F* fhPB = nullptr; std::vector fhPA; TH1F* fhPtB = nullptr; @@ -124,11 +221,14 @@ TH2F* fhAmbiguousTrackPt = nullptr; TH2F* fhAmbiguityDegree = nullptr; TH2F* fhCompatibleCollisionsZVtxRms = nullptr; +/* MC generator level event/collision histograms */ TH1F* fhTrueCentMultB = nullptr; TH1F* fhTrueCentMultA = nullptr; TH1F* fhTrueVertexZB = nullptr; TH1F* fhTrueVertexZA = nullptr; TH1F* fhTrueVertexZAA = nullptr; + +/* MC generator level particle histograms */ TH1F* fhTruePB = nullptr; std::vector fhTruePA; TH1F* fhTruePtB = nullptr; @@ -163,24 +263,325 @@ std::vector partMultNeg; // multiplicity of negative particles using namespace dptdptfilter; +/* we need this for the time being from TableHelper.h */ +/// Function to check for a specific configurable from another task in the current workflow and fetch its value. Useful for tasks that need to know the value of a configurable in another task. +/// @param initContext initContext of the init function +/// @param taskName name of the task to check for +/// @param optName name of the option to check for +/// @param value value of the option to set +/// @param verbose if true, print debug messages +template <> +bool o2::common::core::getTaskOptionValue(o2::framework::InitContext& initContext, const std::string& taskName, const std::string& optName, o2::framework::LabeledArray& value, const bool verbose) +{ + if (verbose) { + LOG(info) << "Checking for option '" << optName << "' in task '" << taskName << "'"; + } + const auto& workflows = initContext.services().get(); + int deviceCounter = 0; + bool found = false; + for (auto const& device : workflows.devices) { + if (verbose) { + LOG(info) << " Device " << deviceCounter++ << " " << device.name; + } + if (device.name == taskName) { // Found the mother task + int optionCounter = 0; + for (o2::framework::ConfigParamSpec const& option : device.options) { + if (verbose) { + LOG(info) << " Option " << optionCounter++ << " " << option.name << " of type " << static_cast(option.type) << " = '" << option.defaultValue.asString() << "'"; + } + if (option.name == optName) { + value = option.defaultValue.get>(); + return true; + } + } + return found; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// 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; + + static constexpr float kForMultiplicityPtLowLimit = 0.001f; + static constexpr float kForMultiplicityPtHighLimit = 50.0f; + 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 (kForMultiplicityPtLowLimit < p.pt() && p.pt() < kForMultiplicityPtHighLimit) { + if (p.eta() < 1.0f && -1.0f < p.eta()) { + inelgth0 = true; + } + addTo(p, v0am, 2.8f, 5.1f); + addTo(p, v0cm, -3.7f, -1.7f); + addTo(p, cl1m, -1.4f, 1.4f); + addTo(p, cl1EtaGapM, -1.4f, -0.8f); + addTo(p, cl1EtaGapM, 0.8f, 1.4f); + addTo(p, dNchdEta, -0.5f, 0.5f); + 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); + } + } +}; + +////////////////////////////////////////////////////////////////////////////////// +/// Centrality/multiplicity correlations exclusion +/// TODO: adaptation to Run 1/Run 2 +////////////////////////////////////////////////////////////////////////////////// +template +inline void storeMultiplicitiesAndCentralities(CollisionObject const& collision, TrackListObject const& tracks) +{ + int nGlobalTracks = 0; + for (auto const& track : tracks) { + if (track.isGlobalTrack()) { + nGlobalTracks++; + } + } + for (CentMultCorrelationsParams ipar = CentMultCorrelationsMT0A; ipar < CentMultCorrelationsNOOFPARAMS; ++ipar) { + switch (ipar) { + case CentMultCorrelationsMT0A: + collisionMultiplicityCentralityObservables[ipar] = collision.multFT0A(); + break; + case CentMultCorrelationsMT0C: + collisionMultiplicityCentralityObservables[ipar] = collision.multFT0C(); + break; + case CentMultCorrelationsMT0M: + collisionMultiplicityCentralityObservables[ipar] = collision.multFT0M(); + break; + case CentMultCorrelationsMV0A: + collisionMultiplicityCentralityObservables[ipar] = collision.multFV0A(); + break; + case CentMultCorrelationsMV0C: + collisionMultiplicityCentralityObservables[ipar] = collision.multFV0C(); + break; + case CentMultCorrelationsMV0M: + collisionMultiplicityCentralityObservables[ipar] = collision.multFV0M(); + break; + case CentMultCorrelationsMNGLTRK: + collisionMultiplicityCentralityObservables[ipar] = nGlobalTracks; + break; + case CentMultCorrelationsMNPVC: + collisionMultiplicityCentralityObservables[ipar] = collision.multNTracksPV(); + break; + case CentMultCorrelationsCT0A: + if constexpr (framework::has_type_v) { + collisionMultiplicityCentralityObservables[ipar] = collision.centFT0A(); + } + break; + case CentMultCorrelationsCT0C: + if constexpr (framework::has_type_v) { + collisionMultiplicityCentralityObservables[ipar] = collision.centFT0C(); + } + break; + case CentMultCorrelationsCT0M: + if constexpr (framework::has_type_v) { + collisionMultiplicityCentralityObservables[ipar] = collision.centFT0M(); + } + break; + case CentMultCorrelationsCV0A: + if constexpr (framework::has_type_v) { + collisionMultiplicityCentralityObservables[ipar] = collision.centFV0A(); + } + break; + case CentMultCorrelationsCNTPV: + if constexpr (framework::has_type_v) { + collisionMultiplicityCentralityObservables[ipar] = collision.centNTPV(); + } + break; + default: + break; + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// The filter class +////////////////////////////////////////////////////////////////////////////// + struct DptDptFilter { 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 cfgCCDBPeriod{"input_ccdbperiod", "LHC22o", "The CCDB dataset period for the input file"}; + std::string prefix = "cfgCCDB"; + Configurable url{"url", "http://ccdb-test.cern.ch:8080", "The CCDB url for the input file"}; + Configurable pathNameCorrections{"pathNameCorrections", "", "The CCDB path for the corrections file. Default \"\", i.e. don't load from CCDB"}; + Configurable pathNamePID{"pathNamePID", "", "The CCDB path for the PID adjusts file. Default \"\", i.e. don't load from CCDB"}; + Configurable dateCorrections{"dateCorrections", "20220307", "The CCDB date for the corrections input file"}; + Configurable datePID{"datePID", "20220307", "The CCDB date for the PID adjustments input file"}; + Configurable suffix{"suffix", "", "Dataset period suffix for metadata discrimination"}; } 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"}; - 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"}; - 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"}; + + struct : ConfigurableGroup { + std::string prefix = "cfgEventSelection"; + Configurable fillQc{"fillQc", false, "Fill the quality control histograms. Default: false"}; + Configurable minOrbit{"minOrbit", -1, "Lowest orbit to track"}; + Configurable maxOrbit{"maxOrbit", INT64_MAX, "Highest orbit to track"}; + Configurable rctSource{"rctSource", "None", "RCT selection source: None,CBT,CBT_hadronPID,CBT_electronPID,CBT_calo,CBT_muon,CBT_muon_glo. Default: None"}; +#define SYSTEMNAME(sysid) systemExternalNamesMap.at(sysid).data() +#define MULTSRCNAME(msrcid) multiplicitySourceConfigNamesMap.at(msrcid).data() + Configurable> multiplicityUpperLimit{"multiplicityUpperLimit", {MultiplicityUpperLimitBase[0], 11, 8, {SYSTEMNAME(0), SYSTEMNAME(1), SYSTEMNAME(2), SYSTEMNAME(3), SYSTEMNAME(4), SYSTEMNAME(5), SYSTEMNAME(6), SYSTEMNAME(7), SYSTEMNAME(8), SYSTEMNAME(9), SYSTEMNAME(10)}, {MULTSRCNAME(0), MULTSRCNAME(1), MULTSRCNAME(2), MULTSRCNAME(3), MULTSRCNAME(4), MULTSRCNAME(5), MULTSRCNAME(6), MULTSRCNAME(7)}}, "Upper limits for the multiplicity observables"}; + Configurable> multiplicitiesExclusionFormula{"multiplicitiesExclusionFormula", {multiplicityCentralityCorrelationsFormulaBase[0], 11, 1, {SYSTEMNAME(0), SYSTEMNAME(1), SYSTEMNAME(2), SYSTEMNAME(3), SYSTEMNAME(4), SYSTEMNAME(5), SYSTEMNAME(6), SYSTEMNAME(7), SYSTEMNAME(8), SYSTEMNAME(9), SYSTEMNAME(10)}, {"Exclusion formula"}}, "Formula for excluding outliers of the multiplicities correlations. Use any parameter from centMultCorrelationsParamsMap"}; + Configurable triggSel{"triggSel", "mb+nocollintrstd+nocollinrofstd+nosamebunchpup+isvtxitstpc+gooditslayerall", "Trigger selection: check \'triggerSelectionBitsMap\' for options. Default: mb+nocollintrstd+nocollinrofstd+nosamebunchpup+isvtxitstpc+gooditslayerall"}; + struct : ConfigurableGroup { + std::string prefix = "cfgEventSelection.occupancySelection"; + Configurable occupancyEstimation{"occupancyEstimation", "None", "Occupancy estimation: None, Tracks, FT0C. Default None"}; + Configurable minOccupancy{"minOccupancy", 0.0f, "Minimum allowed occupancy. Depends on the occupancy estimation"}; + Configurable maxOccupancy{"maxOccupancy", 1e6f, "Maximum allowed occupancy. Depends on the occupancy estimation"}; + } occupancySelection; + } cfgEventSelection; + Configurable> cfgSystemForPeriod{"cfgSystemForPeriod", {periodsOnSystemType[0], 11, 1, {SYSTEMNAME(0), SYSTEMNAME(1), SYSTEMNAME(2), SYSTEMNAME(3), SYSTEMNAME(4), SYSTEMNAME(5), SYSTEMNAME(6), SYSTEMNAME(7), SYSTEMNAME(8), SYSTEMNAME(9), SYSTEMNAME(10)}, {"Periods separated by commas"}}, "List of periods associated to each system type"}; + Configurable cfgDataType{"cfgDataType", "data", "Data type: data, datanoevsel, MC, FastMC, OnTheFlyMC. Default data"}; + Configurable cfgCentSpec{"cfgCentSpec", "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{"cfgOverallMinP", 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{"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{"DptDptFilterCollisionsInfo", OutputObjHandlingPolicy::AnalysisObject}; @@ -189,6 +590,9 @@ struct DptDptFilter { Produces acceptedtrueevents; Produces gencollisionsinfo; + Multiplicity multiplicity; + Preslice perCollision = aod::track::collisionId; + void init(InitContext const&) { using namespace dptdptfilter; @@ -211,18 +615,38 @@ struct DptDptFilter { /* the track types and combinations */ /* the centrality/multiplicity estimation */ if (doprocessWithoutCent || doprocessWithoutCentDetectorLevel || doprocessWithoutCentGeneratorLevel) { - fCentMultEstimator = kNOCM; + fCentMultEstimator = CentMultNOCM; + } else if (doprocessOnTheFlyGeneratorLevel) { + fCentMultEstimator = CentMultFV0A; } else { - fCentMultEstimator = getCentMultEstimator(cfgCentMultEstimator); + fCentMultEstimator = getCentMultEstimator(cfgCentMultEstimator.value.c_str()); } + /* RCT information usage */ + if (cfgEventSelection.rctSource.value == "None") { + useRctInformation = false; + } else { + /* for the time being we don't require ZDC and treat limited acceptance as faulty */ + rctChecker.init(cfgEventSelection.rctSource.value, false, true); + useRctInformation = true; + } + + /* the occupancy selection */ + fOccupancyEstimation = getOccupancyEstimator(cfgEventSelection.occupancySelection.occupancyEstimation.value.c_str()); + fMinOccupancy = cfgEventSelection.occupancySelection.minOccupancy; + fMaxOccupancy = cfgEventSelection.occupancySelection.maxOccupancy; + /* the trigger selection */ - fTriggerSelection = getTriggerSelection(cfgTriggSel); + triggerSelectionFlags = getTriggerSelection(cfgEventSelection.triggSel.value.c_str()); traceCollId0 = cfgTraceCollId0; - /* if the system type is not known at this time, we have to put the initialization somewhere else */ - fSystem = getSystemType(cfgSystem); + /* get the system type */ + fSystem = getSystemType(cfgSystemForPeriod.value); + fLhcRun = multRunForSystemMap.at(fSystem); fDataType = getDataType(cfgDataType); + /* the multiplicities outliers exclusion */ + multiplicityCentralityCorrelationsExclusion = getExclusionFormula(cfgEventSelection.multiplicitiesExclusionFormula->getData()[fSystem][0].c_str()); + /* create the output list which will own the task histograms */ TList* fOutputList = new TList(); fOutputList->SetOwner(true); @@ -230,107 +654,176 @@ struct DptDptFilter { if ((fDataType == kData) || (fDataType == kDataNoEvtSel) || (fDataType == kMC)) { /* create the reconstructed data histograms */ - /* TODO: proper axes and axes titles according to the system; still incomplete */ - std::string multestimator = getCentMultEstimatorName(fCentMultEstimator); - if (fSystem > kPbp) { - fhCentMultB = new TH1F("CentralityB", "Centrality before cut; centrality (%)", 100, 0, 100); - fhCentMultA = new TH1F("CentralityA", "Centrality; centrality (%)", 100, 0, 100); - fhMultB = new TH1F("MultB", TString::Format("%s Multiplicity before cut;%s Multiplicity;Collisions", multestimator.c_str(), multestimator.c_str()), 4001, -0.5, 4000.5); - fhMultA = new TH1F("MultA", TString::Format("%s Multiplicity;%s Multiplicity;Collisions", multestimator.c_str(), multestimator.c_str()), 4001, -0.5, 4000.5); - } else { - /* for pp, pPb and Pbp systems use multiplicity instead */ - fhCentMultB = new TH1F("MultiplicityB", "Multiplicity before cut; multiplicity (%)", 100, 0, 100); - fhCentMultA = new TH1F("MultiplicityA", "Multiplicity; multiplicity (%)", 100, 0, 100); - fhMultB = new TH1F("MultB", TString::Format("%s Multiplicity before cut;%s Multiplicity;Collisions", multestimator.c_str(), multestimator.c_str()), 601, -0.5, 600.5); - fhMultA = new TH1F("MultA", TString::Format("%s Multiplicity;%s Multiplicity;Collisions", multestimator.c_str(), multestimator.c_str()), 601, -0.5, 600.5); + fhEventSelection = new TH1D("EventSelection", ";;counts", CollSelNOOFFLAGS, -0.5f, static_cast(CollSelNOOFFLAGS) - 0.5f); + for (int ix = 0; ix < CollSelNOOFFLAGS; ++ix) { + fhEventSelection->GetXaxis()->SetBinLabel(ix + 1, collisionSelectionExternalNamesMap.at(ix).data()); + } + fhTriggerSelection = new TH1D("TriggerSelection", ";;counts", TriggSelNOOFTRIGGERS, -0.5f, static_cast(TriggSelNOOFTRIGGERS) - 0.5f); + for (int ix = 0; ix < TriggSelNOOFTRIGGERS; ++ix) { + fhTriggerSelection->GetXaxis()->SetBinLabel(ix + 1, TString::Format("#color[%d]{%s}", triggerSelectionFlags.test(ix) ? 2 : 1, triggerSelectionExternalNamesMap.at(ix).data()).Data()); + } + fhTriggerSelectionCorrelations = new TH2D("TriggerSelectionCorrelations", ";;;counts", + TriggSelNOOFTRIGGERS, -0.5f, static_cast(TriggSelNOOFTRIGGERS) - 0.5f, + TriggSelNOOFTRIGGERS, -0.5f, static_cast(TriggSelNOOFTRIGGERS) - 0.5f); + for (int ixy = 0; ixy < TriggSelNOOFTRIGGERS; ++ixy) { + fhTriggerSelectionCorrelations->GetXaxis()->SetBinLabel(ixy + 1, TString::Format("#color[%d]{%s}", triggerSelectionFlags.test(ixy) ? 2 : 1, triggerSelectionExternalNamesMap.at(ixy).data()).Data()); + fhTriggerSelectionCorrelations->GetYaxis()->SetBinLabel(ixy + 1, TString::Format("#color[%d]{%s}", triggerSelectionFlags.test(ixy) ? 2 : 1, triggerSelectionExternalNamesMap.at(ixy).data()).Data()); } fhVertexZB = new TH1F("VertexZB", "Vertex Z; z_{vtx}", 60, -15, 15); fhVertexZA = new TH1F("VertexZA", "Vertex Z; z_{vtx}", zvtxbins, zvtxlow, zvtxup); +/* helpers for the multiplicity/centrality axes definition */ +#define DPTDPTCENTRALITYAXIS 105, -0.5f, 104.5f +#define DPTDPTFWMULTIPLICITYAXIS(est) 1000, 0.0f, cfgEventSelection.multiplicityUpperLimit->getData()[fSystem][est] +#define DPTDPTMULTIPLICITYAXIS(est) cfgEventSelection.multiplicityUpperLimit->getData()[fSystem][est] + 1, -0.5f, cfgEventSelection.multiplicityUpperLimit->getData()[fSystem][est] + 0.5f + + std::string_view multestimator = getCentMultEstimatorName(fCentMultEstimator); + fhCentMultB = new TH1F("CentralityB", "Centrality before cut; centrality (%)", DPTDPTCENTRALITYAXIS); + fhCentMultA = new TH1F("CentralityA", "Centrality; centrality (%)", DPTDPTCENTRALITYAXIS); + fhMultB = new TH1F("MultB", TString::Format("%s Multiplicity before cut;%s Multiplicity;Collisions", multestimator.data(), multestimator.data()), DPTDPTFWMULTIPLICITYAXIS(estimatorMultiplicitySourceMap.at(fCentMultEstimator))); + fhMultA = new TH1F("MultA", TString::Format("%s Multiplicity;%s Multiplicity;Collisions", multestimator.data(), multestimator.data()), DPTDPTFWMULTIPLICITYAXIS(estimatorMultiplicitySourceMap.at(fCentMultEstimator))); + + if (cfgEventSelection.fillQc) { + /* the quality control histograms */ + for (int i = 0; i < BeforeAfterNOOFTIMES; ++i) { + fhMultiplicityVsCentrality[i] = new TH2F(TString::Format("MultiplicityVsCentrality%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;%s centrality (%%);Global tracks", beforeAfterName[i].c_str(), multestimator.data()).Data(), DPTDPTCENTRALITYAXIS, DPTDPTMULTIPLICITYAXIS(MultSourceNtracks)); + fhMultiplicityVsT0cMultiplicity[i] = new TH2F(TString::Format("MultiplicityVsT0cMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;T0C Multiplicity;Global tracks", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceT0C), DPTDPTMULTIPLICITYAXIS(MultSourceNtracks)); + fhMultiplicityVsT0aMultiplicity[i] = new TH2F(TString::Format("MultiplicityVsT0aMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;T0A Multiplicity;Global tracks", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceT0A), DPTDPTMULTIPLICITYAXIS(MultSourceNtracks)); + fhMultiplicityVsV0aMultiplicity[i] = new TH2F(TString::Format("MultiplicityVsV0aMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;V0A Multiplicity;Global tracks", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceV0A), DPTDPTMULTIPLICITYAXIS(MultSourceNtracks)); + fhMultiplicityVsPvMultiplicity[i] = new TH2F(TString::Format("MultiplicityVsPvMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;PV contributors;Global tracks", beforeAfterName[i].c_str()).Data(), DPTDPTMULTIPLICITYAXIS(MultSourcePvContributors), DPTDPTMULTIPLICITYAXIS(MultSourceNtracks)); + fhPvMultiplicityVsCentrality[i] = new TH2F(TString::Format("PvMultiplicityVsCentrality%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;%s centrality (%%);PV contributors", beforeAfterName[i].c_str(), multestimator.data()).Data(), DPTDPTCENTRALITYAXIS, DPTDPTMULTIPLICITYAXIS(MultSourcePvContributors)); + fhPvMultiplicityVsT0cMultiplicity[i] = new TH2F(TString::Format("PvMultiplicityVsT0cMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;T0C multiplicity;PV contributors", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceT0C), DPTDPTMULTIPLICITYAXIS(MultSourcePvContributors)); + fhPvMultiplicityVsT0aMultiplicity[i] = new TH2F(TString::Format("PvMultiplicityVsT0aMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;T0A multiplicity;PV contributors", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceT0A), DPTDPTMULTIPLICITYAXIS(MultSourcePvContributors)); + fhPvMultiplicityVsV0aMultiplicity[i] = new TH2F(TString::Format("PvMultiplicityVsV0aMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;V0A multiplicity;PV contributors", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceV0A), DPTDPTMULTIPLICITYAXIS(MultSourcePvContributors)); + fhV0aMultiplicityVsCentrality[i] = new TH2F(TString::Format("V0aMultiplicityVsCentrality%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;%s centrality (%%);V0A multiplicity", beforeAfterName[i].c_str(), multestimator.data()).Data(), DPTDPTCENTRALITYAXIS, DPTDPTFWMULTIPLICITYAXIS(MultSourceV0A)); + fhV0aMultiplicityVsT0cMultiplicity[i] = new TH2F(TString::Format("V0aMultiplicityVsT0cMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;T0C multiplicity;V0A multiplicity", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceT0C), DPTDPTFWMULTIPLICITYAXIS(MultSourceV0A)); + fhV0aMultiplicityVsT0aMultiplicity[i] = new TH2F(TString::Format("V0aMultiplicityVsT0aMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;T0A multiplicity;V0A multiplicity", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceT0A), DPTDPTFWMULTIPLICITYAXIS(MultSourceV0A)); + fhT0cMultiplicityVsCentrality[i] = new TH2F(TString::Format("T0cMultiplicityVsCentrality%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;%s centrality (%%);T0C multiplicity", beforeAfterName[i].c_str(), multestimator.data()).Data(), DPTDPTCENTRALITYAXIS, DPTDPTFWMULTIPLICITYAXIS(MultSourceT0C)); + fhT0cMultiplicityVsT0aMultiplicity[i] = new TH2F(TString::Format("T0cMultiplicityVsT0aMultiplicity%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;T0A multiplicity;T0C multiplicity", beforeAfterName[i].c_str()).Data(), DPTDPTFWMULTIPLICITYAXIS(MultSourceT0A), DPTDPTFWMULTIPLICITYAXIS(MultSourceT0C)); + fhT0CentralityVsCentrality[i] = new TH2F(TString::Format("T0CentralityVsCentrality%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;%s centrality (%%);T0 centrality(%%)", beforeAfterName[i].c_str(), multestimator.data()).Data(), DPTDPTCENTRALITYAXIS, DPTDPTCENTRALITYAXIS); + fhV0aCentralityVsCentrality[i] = new TH2F(TString::Format("V0aCentralityVsCentrality%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;%s centrality (%%);V0A centrality (%%)", beforeAfterName[i].c_str(), multestimator.data()).Data(), DPTDPTCENTRALITYAXIS, DPTDPTCENTRALITYAXIS); + fhNtpvCentralityVsCentrality[i] = new TH2F(TString::Format("NtpvCentralityVsCentrality%s", beforeAfterSuffix[i].c_str()).Data(), TString::Format("%s;%s centrality (%%);NTPV centrality (%%)", beforeAfterName[i].c_str(), multestimator.data()).Data(), DPTDPTCENTRALITYAXIS, DPTDPTCENTRALITYAXIS); + } + } + /* add the hstograms to the output list */ + fOutputList->Add(fhEventSelection); + fOutputList->Add(fhTriggerSelection); + fOutputList->Add(fhTriggerSelectionCorrelations); fOutputList->Add(fhCentMultB); fOutputList->Add(fhCentMultA); fOutputList->Add(fhMultB); fOutputList->Add(fhMultA); fOutputList->Add(fhVertexZB); fOutputList->Add(fhVertexZA); + if (cfgEventSelection.fillQc) { + for (int i = 0; i < BeforeAfterNOOFTIMES; ++i) { + /* the quality control histograms */ + fOutputList->Add(fhMultiplicityVsCentrality[i]); + fOutputList->Add(fhMultiplicityVsT0cMultiplicity[i]); + fOutputList->Add(fhMultiplicityVsT0aMultiplicity[i]); + fOutputList->Add(fhMultiplicityVsV0aMultiplicity[i]); + fOutputList->Add(fhMultiplicityVsPvMultiplicity[i]); + fOutputList->Add(fhPvMultiplicityVsCentrality[i]); + fOutputList->Add(fhPvMultiplicityVsT0cMultiplicity[i]); + fOutputList->Add(fhPvMultiplicityVsT0aMultiplicity[i]); + fOutputList->Add(fhPvMultiplicityVsV0aMultiplicity[i]); + fOutputList->Add(fhV0aMultiplicityVsCentrality[i]); + fOutputList->Add(fhV0aMultiplicityVsT0cMultiplicity[i]); + fOutputList->Add(fhV0aMultiplicityVsT0aMultiplicity[i]); + fOutputList->Add(fhT0cMultiplicityVsCentrality[i]); + fOutputList->Add(fhT0cMultiplicityVsT0aMultiplicity[i]); + fOutputList->Add(fhT0CentralityVsCentrality[i]); + fOutputList->Add(fhV0aCentralityVsCentrality[i]); + fOutputList->Add(fhNtpvCentralityVsCentrality[i]); + } + } } if ((fDataType != kData) && (fDataType != kDataNoEvtSel)) { /* create the true data histograms */ - /* TODO: proper axes and axes titles according to the system; still incomplete */ - if (fSystem > kPbp) { - fhTrueCentMultB = new TH1F("TrueCentralityB", "Centrality before (truth); centrality (%)", 100, 0, 100); - fhTrueCentMultA = new TH1F("TrueCentralityA", "Centrality (truth); centrality (%)", 100, 0, 100); - } else { - /* for pp, pPb and Pbp systems use multiplicity instead */ - fhTrueCentMultB = new TH1F("TrueMultiplicityB", "Multiplicity before (truth); multiplicity (%)", 100, 0, 100); - fhTrueCentMultA = new TH1F("TrueMultiplicityA", "Multiplicity (truth); multiplicity (%)", 100, 0, 100); - } - + fhTrueCentMultB = new TH1F("TrueCentralityB", "Centrality before (truth); centrality (%)", 100, 0, 100); + fhTrueCentMultA = new TH1F("TrueCentralityA", "Centrality (truth); centrality (%)", 100, 0, 100); 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); + void processWithoutCentWithoutEvSelDetectorLevel(soa::Join::iterator const& collision, DptDptFullTracksDetLevel const& ftracks, aod::McParticles const&, const aod::BCsWithTimestamps&); + PROCESS_SWITCH(DptDptFilter, processWithoutCentWithoutEvSelDetectorLevel, "Process MC detector level without centrality nor event selections", false); + template - void processGenerated(CollisionObject const& mccollision, ParticlesList const& mcparticles, float centormult); + bool processGenerated(CollisionObject const& mccollision, ParticlesList const& mcparticles, float centormult); - template + template void processGeneratorLevel(aod::McCollision const& mccollision, CollisionsGroup const& collisions, aod::McParticles const& mcparticles, AllCollisions const& allcollisions, + AllTracks const& alltracks, float defaultcent); void processWithCentGeneratorLevel(aod::McCollision const& mccollision, soa::SmallGroups> const& collisions, aod::McParticles const& mcparticles, - aod::CollisionsEvSelCent const& allcollisions); + aod::CollisionsEvSelCent const& allcollisions, + DptDptFullTracksDetLevel const& alltracks); PROCESS_SWITCH(DptDptFilter, processWithCentGeneratorLevel, "Process generated with centrality", false); void processWithRun2CentGeneratorLevel(aod::McCollision const& mccollision, soa::SmallGroups> const& collisions, aod::McParticles const& mcparticles, - aod::CollisionsEvSelRun2Cent const& allcollisions); + aod::CollisionsEvSelRun2Cent const& allcollisions, + DptDptFullTracksDetLevel const& alltracks); PROCESS_SWITCH(DptDptFilter, processWithRun2CentGeneratorLevel, "Process generated with centrality", false); void processWithoutCentGeneratorLevel(aod::McCollision const& mccollision, soa::SmallGroups> const& collisions, aod::McParticles const& mcparticles, - aod::CollisionsEvSel const& allcollisions); + aod::CollisionsEvSel const& allcollisions, + DptDptFullTracksDetLevel const& alltracks); 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 +836,17 @@ 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); + storeMultiplicitiesAndCentralities(collision, ftracks); + if (withinOrbitOfInterest && isEventSelected(collision, centormult)) { acceptedevent = true; fhCentMultA->Fill(centormult); fhMultA->Fill(mult); @@ -365,45 +862,114 @@ void DptDptFilter::processReconstructed(CollisionObject const& collision, Tracks collisionsinfo(uint8_t(false), 105.0); } } + /* report the trigger and event selection */ + for (int iflag = 0; iflag < TriggSelNOOFTRIGGERS; ++iflag) { + if (triggerFlags.test(iflag)) { + fhTriggerSelection->Fill(iflag); + for (int jflag = 0; jflag < TriggSelNOOFTRIGGERS; ++jflag) { + if (triggerFlags.test(jflag)) { + fhTriggerSelectionCorrelations->Fill(iflag, jflag); + } + } + } + } + for (int iflag = 0; iflag < CollSelNOOFFLAGS; ++iflag) { + if (collisionFlags.test(iflag)) { + fhEventSelection->Fill(iflag); + } else { + if (iflag >= CollSelTRIGGSELBIT) { + /* don't report not accepted events */ + break; + } + } + } + /* report QC information if required */ + if (cfgEventSelection.fillQc) { + auto fillHistograms = [&](int step) { + fhMultiplicityVsCentrality[step]->Fill(centormult, collisionMultiplicityCentralityObservables[CentMultCorrelationsMNGLTRK]); + fhMultiplicityVsT0cMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0C], collisionMultiplicityCentralityObservables[CentMultCorrelationsMNGLTRK]); + fhMultiplicityVsT0aMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0A], collisionMultiplicityCentralityObservables[CentMultCorrelationsMNGLTRK]); + fhMultiplicityVsV0aMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMV0A], collisionMultiplicityCentralityObservables[CentMultCorrelationsMNGLTRK]); + fhMultiplicityVsPvMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMNPVC], collisionMultiplicityCentralityObservables[CentMultCorrelationsMNGLTRK]); + fhPvMultiplicityVsCentrality[step]->Fill(centormult, collisionMultiplicityCentralityObservables[CentMultCorrelationsMNPVC]); + fhPvMultiplicityVsT0cMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0C], collisionMultiplicityCentralityObservables[CentMultCorrelationsMNPVC]); + fhPvMultiplicityVsT0aMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0A], collisionMultiplicityCentralityObservables[CentMultCorrelationsMNPVC]); + fhPvMultiplicityVsV0aMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMV0A], collisionMultiplicityCentralityObservables[CentMultCorrelationsMNPVC]); + fhV0aMultiplicityVsCentrality[step]->Fill(centormult, collisionMultiplicityCentralityObservables[CentMultCorrelationsMV0A]); + fhV0aMultiplicityVsT0cMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0C], collisionMultiplicityCentralityObservables[CentMultCorrelationsMV0A]); + fhV0aMultiplicityVsT0aMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0A], collisionMultiplicityCentralityObservables[CentMultCorrelationsMV0A]); + fhT0cMultiplicityVsCentrality[step]->Fill(centormult, collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0C]); + fhT0cMultiplicityVsT0aMultiplicity[step]->Fill(collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0A], collisionMultiplicityCentralityObservables[CentMultCorrelationsMT0C]); + if constexpr (framework::has_type_v) { + fhT0CentralityVsCentrality[step]->Fill(centormult, collisionMultiplicityCentralityObservables[CentMultCorrelationsCT0M]); + fhV0aCentralityVsCentrality[step]->Fill(centormult, collisionMultiplicityCentralityObservables[CentMultCorrelationsCV0A]); + fhNtpvCentralityVsCentrality[step]->Fill(centormult, collisionMultiplicityCentralityObservables[CentMultCorrelationsCNTPV]); + } + }; + for (int i = 0; i < BeforeAfterNOOFTIMES; ++i) { + switch (static_cast(i)) { + case BeforeAfterBEFORE: + fillHistograms(i); + break; + case BeforeAfterBEFOREMULTCORR: + if ((collisionFlags & CollSelPREMULTACCEPTEDRUN3) == CollSelPREMULTACCEPTEDRUN3) { + fillHistograms(i); + } + break; + case BeforeAfterAFTER: + if (acceptedevent) { + fillHistograms(i); + } + break; + default: + break; + } + } + } } -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); +} + +void DptDptFilter::processWithoutCentWithoutEvSelDetectorLevel(soa::Join::iterator 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,13 +977,15 @@ void DptDptFilter::processGenerated(CollisionObject const& mccollision, Particle } else { gencollisionsinfo(acceptedevent, centormult); } + return static_cast(acceptedevent); } -template +template void DptDptFilter::processGeneratorLevel(aod::McCollision const& mccollision, CollisionsGroup const& collisions, aod::McParticles const& mcparticles, AllCollisions const& allcollisions, + AllTracks const& alltracks, float defaultcent) { using namespace dptdptfilter; @@ -429,13 +997,16 @@ 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); + auto collisionTracks = alltracks.sliceBy(perCollision, collision.globalIndex()); + storeMultiplicitiesAndCentralities(collision, collisionTracks); + if (isEventSelected(collision, defaultcent)) { + if (processGenerated(mccollision, mcparticles, defaultcent)) { + fhTrueVertexZAA->Fill((mccollision.posZ())); + } processed = true; break; /* TODO: only processing the first reconstructed accepted collision */ } @@ -450,25 +1021,48 @@ void DptDptFilter::processGeneratorLevel(aod::McCollision const& mccollision, void DptDptFilter::processWithCentGeneratorLevel(aod::McCollision const& mccollision, soa::SmallGroups> const& collisions, aod::McParticles const& mcparticles, - aod::CollisionsEvSelCent const& allcollisions) + aod::CollisionsEvSelCent const& allcollisions, + DptDptFullTracksDetLevel const& alltracks) { - processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, 50.0); + processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, alltracks, 50.0); } void DptDptFilter::processWithRun2CentGeneratorLevel(aod::McCollision const& mccollision, soa::SmallGroups> const& collisions, aod::McParticles const& mcparticles, - aod::CollisionsEvSelRun2Cent const& allcollisions) + aod::CollisionsEvSelRun2Cent const& allcollisions, + DptDptFullTracksDetLevel const& alltracks) { - processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, 50.0); + processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, alltracks, 50.0); } void DptDptFilter::processWithoutCentGeneratorLevel(aod::McCollision const& mccollision, soa::SmallGroups> const& collisions, aod::McParticles const& mcparticles, - aod::CollisionsEvSel const& allcollisions) + aod::CollisionsEvSel const& allcollisions, + DptDptFullTracksDetLevel const& alltracks) +{ + processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, alltracks, 50.0); +} + +void DptDptFilter::processOnTheFlyGeneratorLevel(aod::McCollision const& mccollision, + aod::McParticles const& mcparticles) { - processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, 50.0); + 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) @@ -477,7 +1071,7 @@ void DptDptFilter::processVertexGenerated(aod::McCollisions const& 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,14 +1087,13 @@ 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 { - Produces scannedtracks; Produces tracksinfo; Produces scannedgentracks; @@ -510,37 +1103,40 @@ struct DptDptFilterTracks { bool storedccdbinfo = false; std::string cfgCCDBUrl{"http://ccdb-test.cern.ch:8080"}; - std::string cfgCCDBPathName{""}; - 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 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 cfgPionPIDSelection{"pipidsel", + std::string cfgCCDBPathNamePID{""}; + std::string cfgCCDBDatePID{"20220307"}; + + Configurable cfgOutDebugInfo{"cfgOutDebugInfo", false, "Out detailed debug information per track into a text file. Default false"}; + Configurable cfgFullDerivedData{"cfgFullDerivedData", false, "Produce the full derived data for external storage. Default false"}; + Configurable cfgTrackType{"cfgTrackType", 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{"cfgOnlyInOneSide", false, "select tracks that don't cross the TPC central membrane. Default false"}; + 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, 3 mcparticle only primaries, 4 mcparticle only sec, 5 mcparicle only sec from decays, 6 mcparticle only sec from material. Default 0"}; + Configurable cfgTuneTrackSelection{"cfgTuneTrackSelection", {}, "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{"cfgPionPIDSelection", {}, "PID criteria for pions"}; - Configurable cfgKaonPIDSelection{"kapidsel", + Configurable cfgKaonPIDSelection{"cfgKaonPIDSelection", {}, "PID criteria for kaons"}; - Configurable cfgProtonPIDSelection{"prpidsel", + Configurable cfgProtonPIDSelection{"cfgProtonPIDSelection", {}, "PID criteria for protons"}; - Configurable cfgElectronPIDSelection{"elpidsel", + Configurable cfgElectronPIDSelection{"cfgElectronPIDSelection", {}, "PID criteria for electrons"}; - Configurable cfgMuonPIDSelection{"mupidsel", + Configurable cfgMuonPIDSelection{"cfgMuonPIDSelection", {}, "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()"); @@ -549,41 +1145,72 @@ struct DptDptFilterTracks { /* update with the configurable values */ /* self configure 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", "cfgOverallMinP", overallminp, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxbins", zvtxbins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxmin", zvtxlow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxmax", zvtxup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTbins", ptbins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTmin", ptlow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTmax", ptup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtabins", etabins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtamin", etalow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtamax", etaup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPhibins", phibins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.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); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgCCDB.url", cfgCCDBUrl, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgCCDB.pathNamePID", cfgCCDBPathNamePID, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgCCDB.datePID", cfgCCDBDatePID, 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 */ + o2::framework::LabeledArray tmpLabeledArray = {}; + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgSystemForPeriod", tmpLabeledArray, false); + fSystem = getSystemType(tmpLabeledArray); std::string tmpstr; - getTaskOptionValue(initContext, "dpt-dpt-filter", "syst", tmpstr, false); - fSystem = getSystemType(tmpstr); - getTaskOptionValue(initContext, "dpt-dpt-filter", "datatype", tmpstr, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgDataType", 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; } @@ -591,10 +1218,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()); } } @@ -605,16 +1232,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); @@ -825,9 +1442,9 @@ struct DptDptFilterTracks { using namespace analysis::dptdptfilter; /* let's get a potential PID adjustment */ - if (cfgCCDBPathName.length() > 0 && !storedccdbinfo) { - LOGF(info, "Getting information for PID adjustment from %s, at %s, for %s", cfgCCDBPathName.c_str(), cfgCCDBDate.c_str(), cfgCCDBPeriod.c_str()); - TList* pidinfo = getCCDBInput(ccdb, cfgCCDBPathName.c_str(), cfgCCDBDate.c_str(), cfgCCDBPeriod.c_str()); + if ((cfgCCDBDatePID.length() > 0) && (cfgCCDBPathNamePID.length() > 0) && !storedccdbinfo) { + LOGF(info, "Getting information for PID adjustment from %s, at %s", cfgCCDBPathNamePID.c_str(), cfgCCDBDatePID.c_str()); + TList* pidinfo = getCCDBInput(ccdb, cfgCCDBPathNamePID.c_str(), cfgCCDBDatePID.c_str()); if (pidinfo != nullptr) { pidselector.storePIDAdjustments(pidinfo); } @@ -837,7 +1454,7 @@ struct DptDptFilterTracks { template int8_t trackIdentification(TrackObject const& track); - template + template int8_t selectTrack(TrackObject const& track); template int8_t selectTrackAmbiguousCheck(CollisionObjects const& collisions, TrackObject const& track); @@ -881,12 +1498,12 @@ 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); @@ -920,6 +1537,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) @@ -932,16 +1569,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>(); @@ -968,6 +1606,59 @@ 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) { @@ -1057,6 +1748,26 @@ 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 @@ -1101,7 +1812,7 @@ int8_t DptDptFilterTracks::trackIdentification(TrackObject const& track) return sp; } -template +template int8_t DptDptFilterTracks::selectTrack(TrackObject const& track) { using namespace dptdptfilter; @@ -1111,7 +1822,7 @@ 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); @@ -1136,8 +1847,14 @@ int8_t DptDptFilterTracks::selectTrack(TrackObject const& track) template int8_t DptDptFilterTracks::selectTrackAmbiguousCheck(CollisionObjects const& collisions, TrackObject const& track) { + enum AmbiguityTypes { + kNoAmbiguous = 0, /* no ambiguous track */ + kOnePossibilitySame = 1, /* the track is present in the collision association table but has the same associated collision so the track is not ambiguous */ + kOnePossibilityDifferent = 2, /* the track is present in the collision association table and has a diffetent collision associeted so the track is ambiguous */ + kMoreThanOnePossibility = 3 /* the track is associated to more than one collision in the collision association table so the track is ambiguous */ + }; bool ambiguoustrack = false; - int ambtracktype = 0; /* no ambiguous */ + AmbiguityTypes ambtracktype = kNoAmbiguous; std::vector zvertexes{}; /* ambiguous tracks checks if required */ if constexpr (has_type_v) { @@ -1147,17 +1864,17 @@ int8_t DptDptFilterTracks::selectTrackAmbiguousCheck(CollisionObjects const& col /* ambiguous track! */ ambiguoustrack = true; /* in principle we should not be here because the track is associated to two collisions at least */ - ambtracktype = 2; + ambtracktype = kOnePossibilityDifferent; zvertexes.push_back(collisions.iteratorAt(track.collisionId()).posZ()); zvertexes.push_back(collisions.iteratorAt(track.compatibleCollIds()[0]).posZ()); } else { /* we consider the track as no ambiguous */ - ambtracktype = 1; + ambtracktype = kOnePossibilitySame; } } else { /* ambiguous track! */ ambiguoustrack = true; - ambtracktype = 3; + ambtracktype = kMoreThanOnePossibility; /* the track is associated to more than one collision */ for (const auto& collIdx : track.compatibleCollIds()) { zvertexes.push_back(collisions.iteratorAt(collIdx).posZ()); @@ -1166,24 +1883,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); - if (ambtracktype == 2) { - fhCompatibleCollisionsZVtxRms->Fill(-computeRMS(zvertexes), multiplicityclass); + fhAmbiguousTrackType->Fill(ambtracktype, multiplicityClass); + fhAmbiguousTrackPt->Fill(track.pt(), multiplicityClass); + fhAmbiguityDegree->Fill(zvertexes.size(), multiplicityClass); + if (ambtracktype == kOnePossibilityDifferent) { + 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); } } @@ -1263,14 +1980,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 */ @@ -1307,14 +2025,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())); } @@ -1323,16 +2041,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()); @@ -1345,10 +2063,8 @@ void DptDptFilterTracks::fillParticleHistosAfterSelection(ParticleObject const& WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow{adaptAnalysisTask(cfgc, - SetDefaultProcesses{ - {{"processWithoutCent", true}, - {"processWithoutCentMC", true}}}), + metadataInfo.initMetadata(cfgc); + WorkflowSpec workflow{adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGCF/TableProducer/dptDptFilter.h b/PWGCF/TableProducer/dptDptFilter.h new file mode 100644 index 00000000000..1d431bbde3f --- /dev/null +++ b/PWGCF/TableProducer/dptDptFilter.h @@ -0,0 +1,2071 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGCF/Core/AnalysisConfigurableCuts.h" + +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/MetadataHelper.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/PID.h" +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace o2 +{ +namespace aod +{ +using CollisionsEvSelCent = soa::Join; +using CollisionEvSelCent = 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; +} // namespace aod +namespace analysis +{ +namespace dptdptfilter +{ +/// \enum SystemType +/// \brief The type of the system under analysis +enum SystemType { + SystemNoSystem = 0, ///< no system defined + SystemPp, ///< **p-p** system + SystemPPb, ///< **p-Pb** system + SystemPbp, ///< **Pb-p** system + SystemPbPb, ///< **Pb-Pb** system + SystemXeXe, ///< **Xe-Xe** system + SystemPpRun3, ///< **p-p Run 3** system + SystemPbPbRun3, ///< **Pb-Pb Run 3** system + SystemNeNeRun3, ///< **Ne-Ne Run 3** system + SystemOORun3, ///< **O-O Run 3** system + SystemPORun3, ///< **p-O Run 3** system + SystemNoOfSystems ///< number of handled systems +}; + +/// @brief SystemType prefix increment operator +/// @param ipar value +/// @return the incremented value +inline SystemType& operator++(SystemType& ipar) +{ + return ipar = static_cast(static_cast(ipar) + 1); +} + +/// @brief SystemType postfix increment operator +/// @param ipar the value +/// @param empty +/// @return the same value +inline SystemType operator++(SystemType& ipar, int) +{ + SystemType iparTmp(ipar); + ++ipar; + return iparTmp; +} + +/// \std::map systemInternalCodesMap +/// \brief maps system names to internal system codes +static const std::map systemInternalCodesMap{ + {"", SystemNoSystem}, + {"pp", SystemPp}, + {"pPb", SystemPPb}, + {"Pbp", SystemPbp}, + {"PbPb", SystemPbPb}, + {"XeXe", SystemXeXe}, + {"ppRun3", SystemPpRun3}, + {"PbPbRun3", SystemPbPbRun3}, + {"NeNeRun3", SystemNeNeRun3}, + {"OORun3", SystemOORun3}, + {"pORun3", SystemPORun3}}; + +/// \std::map systemExternalNamesMap +/// \brief maps system internal codes to system external names +static const std::map systemExternalNamesMap{ + {SystemNoSystem, ""}, + {SystemPp, "pp"}, + {SystemPPb, "pPb"}, + {SystemPbp, "Pbp"}, + {SystemPbPb, "PbPb"}, + {SystemXeXe, "XeXe"}, + {SystemPpRun3, "ppRun3"}, + {SystemPbPbRun3, "PbPbRun3"}, + {SystemNeNeRun3, "NeNeRun3"}, + {SystemOORun3, "OORun3"}, + {SystemPORun3, "pORun3"}}; + +/// \enum DataType +/// \brief Which kind of data is the task addressing +enum DataType { + kData = 0, ///< actual data, not generated + kMC, ///< Generator level and detector level + kFastMC, ///< Gererator level but stored dataset + kOnTheFly, ///< On the fly generator level data + kDataNoEvtSel, ///< actual data but not event selection available yet + knGenData ///< number of different generator data types +}; + +/// \enum CentMultEstimatorType +/// \brief The detector used to estimate centrality/multiplicity +enum CentMultEstimatorType { + CentMultNOCM = 0, ///< do not use centrality/multiplicity estimator + CentMultV0M, ///< V0M centrality/multiplicity estimator Run 1/2 + CentMultCL0, ///< CL0 centrality/multiplicity estimator Run 1/2 + CentMultCL1, ///< CL1 centrality/multiplicity estimator Run 1/2 + CentMultFV0A, ///< FV0A centrality/multiplicity estimator Run 3 + CentMultFT0M, ///< FT0M centrality/multiplicity estimator Run 3 + CentMultFT0A, ///< FT0A centrality/multiplicity estimator Run 3 + CentMultFT0C, ///< FT0C centrality/multiplicity estimator Run 3 + CentMultNTPV, ///< NTPV centrality/multiplicity estimator Run 3 + CentMultNOOFESTIMATORS ///< number of centrality/mutiplicity estimator +}; + +/// \std::map estimatorInternalCodesMap +/// \brief maps centrality/multiplicity estimator names to internal estimator codes +static const std::map estimatorInternalCodesMap{ + {"NOCM", CentMultNOCM}, + {"V0M", CentMultV0M}, + {"CL0", CentMultCL0}, + {"CL1", CentMultCL1}, + {"FV0A", CentMultFV0A}, + {"FT0M", CentMultFT0M}, + {"FT0A", CentMultFT0A}, + {"FT0C", CentMultFT0C}, + {"NTPV", CentMultNTPV}}; + +/// \std::map estimatorExternalNamesMap +/// \brief maps internal estimator codes to centrality/multiplicity estimator external names +static const std::map estimatorExternalNamesMap{ + {CentMultNOCM, "NOCM"}, + {CentMultV0M, "V0M"}, + {CentMultCL0, "CL0"}, + {CentMultCL1, "CL1"}, + {CentMultFV0A, "FV0A"}, + {CentMultFT0M, "FT0M"}, + {CentMultFT0A, "FT0A"}, + {CentMultFT0C, "FT0C"}, + {CentMultNTPV, "NTPV"}}; + +/// \enum MultSourceType +/// \brief The multiplicity source +enum MultSourceType { + MultSourceT0A = 0, ///< T0A multiplicity + MultSourceT0C, ///< T0C multiplicity + MultSourceT0M, ///< T0M multiplicity + MultSourceV0A, ///< V0A multiplicity + MultSourceV0C, ///< V0C multiplicity + MultSourceV0M, ///< V0M multiplicity + MultSourceNtracks, ///< number of tracks multiplicity + MultSourcePvContributors, ///< number of primary vertex contributors + MultSourceNOOFSOURCES ///< number multiplicity sources +}; + +/// \enum MultRunType +/// \brief The multiplicity LHC run +enum MultRunType { + MultRunRUN1RUN2 = 0, ///< LHC Run 1 or Run 2 + MultRunRUN3, ///< LHC Run 3 + MultRunNOOFRUNS ///< number of runs for multiplicity +}; + +/// \std::map multRunForSystemMap +/// \brief maps the system to the lhc Run for multiplicity +static const std::map multRunForSystemMap{ + {SystemNoSystem, MultRunRUN1RUN2}, + {SystemPp, MultRunRUN1RUN2}, + {SystemPPb, MultRunRUN1RUN2}, + {SystemPbp, MultRunRUN1RUN2}, + {SystemPbPb, MultRunRUN1RUN2}, + {SystemXeXe, MultRunRUN1RUN2}, + {SystemPpRun3, MultRunRUN3}, + {SystemPbPbRun3, MultRunRUN3}, + {SystemNeNeRun3, MultRunRUN3}, + {SystemOORun3, MultRunRUN3}, + {SystemPORun3, MultRunRUN3}}; + +/// \std::map estimatorMultiplicitySourceMap +/// \brief maps internal estimator codes internal multiplicity sources +static const std::map estimatorMultiplicitySourceMap{ + {CentMultNOCM, MultSourceT0C}, + {CentMultV0M, MultSourceV0M}, + {CentMultCL0, MultSourceT0C}, /* TODO: for Run1,2 */ + {CentMultCL1, MultSourceT0C}, /* TODO: for Run1,2 */ + {CentMultFV0A, MultSourceV0A}, + {CentMultFT0M, MultSourceT0M}, + {CentMultFT0A, MultSourceT0A}, + {CentMultFT0C, MultSourceT0C}, + {CentMultNTPV, MultSourcePvContributors}}; + +/// \std::vector multiplicitySourceExternalNamesMap +/// \brief maps internal multiplicity source to external names for the LHC runs +static const std::vector> multiplicitySourceExternalNamesMap{ + /* Run 1 and Run 2 */ + { + {MultSourceT0A, "T0A multiplicity"}, + {MultSourceT0C, "T0C multiplicity"}, + {MultSourceT0M, "T0M multiplicity"}, + {MultSourceV0A, "V0A multiplicity"}, + {MultSourceV0C, "V0C multiplicity"}, + {MultSourceV0M, "V0M multiplicity"}, + {MultSourceNtracks, "Global tracks"}, + {MultSourcePvContributors, "PV contributors"}}, + /* Run 3 */ + { + {MultSourceT0A, "FT0A multiplicity"}, + {MultSourceT0C, "FT0C multiplicity"}, + {MultSourceT0M, "FT0M multiplicity"}, + {MultSourceV0A, "FV0A multiplicity"}, + {MultSourceV0C, "WRONG SOURCE"}, + {MultSourceV0M, "FV0M multiplicity"}, + {MultSourceNtracks, "Global tracks"}, + {MultSourcePvContributors, "PV contributors"}}}; + +/// \std::map multiplicitySourceConfigNamesMap +/// \brief maps internal multiplicity source to external configuration names +/// At configuration time neither the system nor the lhc run is known +static const std::map multiplicitySourceConfigNamesMap{ + {MultSourceT0A, "FT0A (T0A)"}, + {MultSourceT0C, "FT0C (T0C)"}, + {MultSourceT0M, "FT0M (T0M)"}, + {MultSourceV0A, "FV0A (V0A)"}, + {MultSourceV0C, "WRONG (V0C)"}, + {MultSourceV0M, "FV0M (V0M)"}, + {MultSourceNtracks, "Global tracks"}, + {MultSourcePvContributors, "PV contributors"}}; + +/// \enum CentMultCorrelationsParams +/// \brief internal codes for the supported parameters for centrality/multiplicity correlations exclusion cuts +enum CentMultCorrelationsParams { + CentMultCorrelationsMT0A = 0, ///< multiplicity from T0A + CentMultCorrelationsMT0C, ///< multiplicity from T0C + CentMultCorrelationsMT0M, ///< multiplicity from T0M + CentMultCorrelationsMV0A, ///< multiplicity from V0A + CentMultCorrelationsMV0C, ///< multiplicity from V0C (only Run 1 & Run 2) + CentMultCorrelationsMV0M, ///< multiplicity from V0M + CentMultCorrelationsMNGLTRK, ///< multiplicity from number of global tracks + CentMultCorrelationsMNPVC, ///< multiplicity from number of PV contributors + CentMultCorrelationsCT0A, ///< centrality from T0A + CentMultCorrelationsCT0C, ///< centrality from T0C + CentMultCorrelationsCT0M, ///< centrality from T0M + CentMultCorrelationsCV0A, ///< centrality from V0A + CentMultCorrelationsCNTPV, ///< centrality from number of PV contributors + CentMultCorrelationsNOOFPARAMS ///< the number of parameters supported +}; + +/// @brief prefix increment operator +/// @param ipar value +/// @return the incremented value +inline CentMultCorrelationsParams& operator++(CentMultCorrelationsParams& ipar) +{ + return ipar = static_cast(static_cast(ipar) + 1); +} + +/// @brief postfix increment operator +/// @param ipar the value +/// @param empty +/// @return the same value +inline CentMultCorrelationsParams operator++(CentMultCorrelationsParams& ipar, int) +{ + CentMultCorrelationsParams iparTmp(ipar); + ++ipar; + return iparTmp; +} + +/// \std::map centMultCorrelationsParamsMap +/// \brief maps centrality/multiplicity correlations parameters names to internal codes +static const std::map centMultCorrelationsParamsMap{ + {"MT0A", CentMultCorrelationsMT0A}, + {"MT0C", CentMultCorrelationsMT0C}, + {"MT0M", CentMultCorrelationsMT0M}, + {"MV0A", CentMultCorrelationsMV0A}, + {"MV0C", CentMultCorrelationsMV0C}, + {"MV0M", CentMultCorrelationsMV0M}, + {"MNGLTRK", CentMultCorrelationsMNGLTRK}, + {"MNPVC", CentMultCorrelationsMNPVC}, + {"CT0A", CentMultCorrelationsCT0A}, + {"CT0C", CentMultCorrelationsCT0C}, + {"CT0M", CentMultCorrelationsCT0M}, + {"CV0A", CentMultCorrelationsCV0A}, + {"CNTPV", CentMultCorrelationsCNTPV}}; + +/// \std::map centMultCorrelationsParamsNamesMap +/// \brief maps centrality/multiplicity correlations parameters internal codes to their external names +static const std::map centMultCorrelationsParamsNamesMap{ + {CentMultCorrelationsMT0A, "MT0A"}, + {CentMultCorrelationsMT0C, "MT0C"}, + {CentMultCorrelationsMT0M, "MT0M"}, + {CentMultCorrelationsMV0A, "MV0A"}, + {CentMultCorrelationsMV0C, "MV0C"}, + {CentMultCorrelationsMV0M, "MV0M"}, + {CentMultCorrelationsMNGLTRK, "MNGLTRK"}, + {CentMultCorrelationsMNPVC, "MNPVC"}, + {CentMultCorrelationsCT0A, "CT0A"}, + {CentMultCorrelationsCT0C, "CT0C"}, + {CentMultCorrelationsCT0M, "CT0M"}, + {CentMultCorrelationsCV0A, "CV0A"}, + {CentMultCorrelationsCNTPV, "CNTPV"}}; + +/// \enum TriggerSelectionTags +/// \brief The potential trigger tags to apply for event selection +enum TriggerSelectionTags { + TriggSelNONE = 0, ///< do not use trigger selection + TriggSelMB, ///< Minimum bias trigger + TriggSelNOSAMEBUNCHPUP, ///< No same bunch pile up + TriggSelNUMPVCONTRIBUTORS, ///< Number of primary vertex contributors + TriggSelVTXTOFMATCHED, ///< at least one primary vertex contributor is matched to TOF + TriggSelVTXTRDMATCHED, ///< at least one primary vertex contributor is matched to TRD + TriggSelNOCOLLINTRSTD, ///< no other collision in standard time range gap + TriggSelNOCOLLINROFSTD, ///< no other collision in standard readout frame gap + TriggSelISVERTEXITSTPC, ///< primary vertex contributors are matched tracks ITS+TPC + TriggSelISGOODZVTXFT0VSPV, ///< vertex extracted from FT0 is compatible with the one from primary vertex contributors + TriggSelGOODITSLAYER3, ///< good the 3 ITS layer + TriggSelGOODITSLAYER0123, ///< check good the 0,1,2,and 3 ITS layers + TriggSelGOODITSLAYERALL, ///< check good all ITS layers + TriggSelNOGOODITSLAYER3, ///< check no good the 3 ITS layer + TriggSelNOGOODITSLAYER0123, ///< check no good the 0,1,2,and 3 ITS layers + TriggSelNOGOODITSLAYERALL, ///< check no good all ITS layers + TriggSelNOOFTRIGGERS ///< number of triggers for event selection +}; + +/// \std::map triggerSelectionBitsMap +/// \brief maps trigger selection tags to internal trigger selection bits +static const std::map triggerSelectionBitsMap{ + {"none", TriggSelNONE}, + {"mb", TriggSelMB}, + {"nosamebunchpup", TriggSelNOSAMEBUNCHPUP}, + {"numpvcontr", TriggSelNUMPVCONTRIBUTORS}, + {"vtxtofmatched", TriggSelVTXTOFMATCHED}, + {"vtxtrdmatched", TriggSelVTXTRDMATCHED}, + {"nocollintrstd", TriggSelNOCOLLINTRSTD}, + {"nocollinrofstd", TriggSelNOCOLLINROFSTD}, + {"isvtxitstpc", TriggSelISVERTEXITSTPC}, + {"isgoodvtxft0vspv", TriggSelISGOODZVTXFT0VSPV}, + {"gooditslayer3", TriggSelGOODITSLAYER3}, + {"gooditslayer0123", TriggSelGOODITSLAYER0123}, + {"gooditslayerall", TriggSelGOODITSLAYERALL}, + {"nogooditslayer3", TriggSelNOGOODITSLAYER3}, + {"nogooditslayer0123", TriggSelNOGOODITSLAYER0123}, + {"nogooditslayerall", TriggSelNOGOODITSLAYERALL}}; + +/// \std::map triggerSelectionExternalNamesMap +/// \brief maps trigger selection bits to external names +static const std::map triggerSelectionExternalNamesMap{ + {TriggSelNONE, "none"}, + {TriggSelMB, "Sel8"}, ///< Sel8 includes kIsTriggerTVX, kNoTimeFrameBorder, and kNoITSROFrameBorder + {TriggSelNOSAMEBUNCHPUP, "No same bunch pileup"}, + {TriggSelNUMPVCONTRIBUTORS, "Number PV contributors"}, + {TriggSelVTXTOFMATCHED, "PV contributor TOF matched"}, + {TriggSelVTXTRDMATCHED, "PV contributor TRD matched"}, + {TriggSelNOCOLLINTRSTD, "No coll in TR standard"}, + {TriggSelNOCOLLINROFSTD, "No coll in ROF standard"}, + {TriggSelISVERTEXITSTPC, "Vertex from ITS and TPC"}, + {TriggSelISGOODZVTXFT0VSPV, "Good vtx FT0 vs PV"}, + {TriggSelGOODITSLAYER3, "Good ITS layer 3"}, + {TriggSelGOODITSLAYER0123, "Good ITS layers 0,1,2,3"}, + {TriggSelGOODITSLAYERALL, "Good ITS layer all"}, + {TriggSelNOGOODITSLAYER3, "No good ITS layer 3"}, + {TriggSelNOGOODITSLAYER0123, "No good ITS layer 0,1,2,3"}, + {TriggSelNOGOODITSLAYERALL, "No good ITS layer all"}}; + +/// \enum OccupancyEstimationType +/// \brief The type of occupancy estimation +enum OccupancyEstimationType { + OccupancyNOOCC = 0, ///< do not use occupancy estimation + OccupancyTRACKSOCC, ///< occupancy estimated using tracks + OccupancyFT0COCC, ///< occupancy estimated using the FT0C + OccupancyNOOFESTIMATORS ///< the number of occupancy estimators +}; + +/// \enum CollisionSelectionFlags +/// \brief The different criteria for selecting/rejecting collisions +enum CollisionSelectionFlags { + CollSelIN = 0, ///< new unhandled, yet, event + CollSelMBBIT, ///< minimum bias + CollSelINT7BIT, ///< INT7 Run 1/2 + CollSelSEL7BIT, ///< Sel7 Run 1/2 + CollSelTRIGGSELBIT, ///< Accepted by trigger selection + CollSelRCTBIT, ///< Accetped by the RCT information + CollSelOCCUPANCYBIT, ///< occupancy within limits + CollSelCENTRALITYBIT, ///< centrality cut passed + CollSelZVERTEXBIT, ///< zvtx cut passed + CollSelMULTCORRELATIONS, ///< multiplicities correlations passed + CollSelSELECTED, ///< the event has passed all selections + CollSelNOOFFLAGS ///< number of flags +}; + +constexpr std::bitset<32> CollSelACCEPTEDRUN3 = BIT(CollSelTRIGGSELBIT) | BIT(CollSelRCTBIT) | BIT(CollSelOCCUPANCYBIT) | BIT(CollSelCENTRALITYBIT) | BIT(CollSelZVERTEXBIT) | BIT(CollSelMULTCORRELATIONS); +constexpr std::bitset<32> CollSelPREMULTACCEPTEDRUN3 = BIT(CollSelTRIGGSELBIT) | BIT(CollSelRCTBIT) | BIT(CollSelOCCUPANCYBIT) | BIT(CollSelCENTRALITYBIT) | BIT(CollSelZVERTEXBIT); + +/// \std::mag collisionSelectionExternalNamesMap +/// \brief maps collision selection bits to external names +static const std::map collisionSelectionExternalNamesMap{ + {CollSelIN, "In"}, + {CollSelMBBIT, "MB"}, + {CollSelINT7BIT, "INT7"}, + {CollSelSEL7BIT, "Sel7"}, + {CollSelTRIGGSELBIT, "Trigger selection"}, + {CollSelRCTBIT, "RCT accepted"}, + {CollSelOCCUPANCYBIT, "Occupancy"}, + {CollSelCENTRALITYBIT, "Centrality"}, + {CollSelZVERTEXBIT, "z vertex"}, + {CollSelMULTCORRELATIONS, "Multiplicities correlations"}, + {CollSelSELECTED, "Selected"}}; + +/// \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 +}; + +//============================================================================================ +// The debug output stream +//============================================================================================ +std::ofstream debugstream; + +//============================================================================================ +// The overall minimum momentum +//============================================================================================ +float overallminp = 0.0f; + +//============================================================================================ +// The collision selection and trigger selection flags and configuration objects +//============================================================================================ +std::bitset<32> collisionFlags; +std::bitset<32> collisionSelectionFlags; +std::bitset<32> triggerFlags; +std::bitset<32> triggerSelectionFlags; + +//============================================================================================ +// The collision exclusion using correlations between multiplicity/centrality observables +//============================================================================================ +bool useCentralityMultiplicityCorrelationsExclusion = false; +std::vector collisionMultiplicityCentralityObservables = {}; +std::vector observableIndexForCentralityMultiplicityParameter = {}; +TFormula* multiplicityCentralityCorrelationsExclusion = nullptr; + +//============================================================================================ +// The input data metadata access helper +//============================================================================================ +o2::common::core::MetadataHelper metadataInfo; + +//============================================================================================ +// The RCT information access +//============================================================================================ +bool useRctInformation = false; +o2::aod::rctsel::RCTFlagsChecker rctChecker; + +//============================================================================================ +// The DptDptFilter configuration objects +//============================================================================================ +int ptbins = 18; +float ptlow = 0.2, ptup = 2.0; +int etabins = 16; +float etalow = -0.8, etaup = 0.8; +int zvtxbins = 40; +float zvtxlow = -10.0, zvtxup = 10.0; +int phibins = 72; +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 */ +static constexpr int TrackTypePWGMM = 4; +// default quality criteria for tracks with ITS contribution +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 = + 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 = + o2::aod::track::TrackSelectionFlags::kDCAz | o2::aod::track::TrackSelectionFlags::kDCAxy; + +struct DptDptTrackSelection; // forward struct declaration +int tracktype = 1; +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.mUseITSclusters) { + filter->stdTrackSelection->ResetITSRequirements(); + filter->stdTrackSelection->SetRequireHitsInITSLayers(1, {0, 1, 2}); + filter->stdTrackSelection->SetMinNClustersITS(tune.mITSclusters); + } + 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); + } + } + } + } + + 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, bool periodInPath = false, const std::string& suffix = "") +{ + 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; + + auto cleanPeriod = [](const auto& str) { + std::string tmpStr = str; + size_t pos = tmpStr.find('_'); + if (pos != std::string::npos) { + tmpStr.erase(pos); + } + return tmpStr; + }; + + std::string actualPeriod = cleanPeriod(metadataInfo.get("LPMProductionTag")); + std::string actualPath = ccdbpath; + if (periodInPath) { + actualPath = actualPath + "/" + actualPeriod; + } + if (suffix.length() > 0) { + actualPeriod = actualPeriod + "_" + suffix; + } + + TList* lst = nullptr; + std::map metadata{{"Period", actualPeriod}}; + lst = ccdb->template getSpecific(actualPath, timestamp, metadata); + if (lst != nullptr) { + LOGF(info, "Correctly loaded CCDB input object"); + } else { + LOGF(error, "CCDB input object could not be loaded"); + } + return lst; +} + +SystemType fSystem = SystemNoSystem; +MultRunType fLhcRun = MultRunRUN1RUN2; +DataType fDataType = kData; +CentMultEstimatorType fCentMultEstimator = CentMultV0M; +OccupancyEstimationType fOccupancyEstimation = OccupancyNOOCC; /* the occupancy estimator 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; +bool traceOutOfSpeciesParticles = false; +int recoIdMethod = 0; +float particleMaxDCAxy = 999.9f; +float particleMaxDCAZ = 999.9f; +bool traceCollId0 = false; + +inline std::bitset<32> getTriggerSelection(std::string_view const& triggstr) +{ + std::bitset<32> flags; + + auto split = [](const auto s) { + std::vector tokens; + std::string_view token; + + size_t posStart = 0; + size_t posEnd; + while ((posEnd = s.find("+", posStart)) != std::string_view::npos) { + token = s.substr(posStart, posEnd - posStart); + posStart = posEnd + 1; + tokens.push_back(token); + } + tokens.push_back(s.substr(posStart)); + return tokens; + }; + + std::vector tags = split(triggstr); + + for (const auto& tag : tags) { + if (triggerSelectionBitsMap.contains(tag)) { + flags.set(triggerSelectionBitsMap.at(tag), true); + } else { + LOGF(fatal, "Wrong trigger selection tag: %s", tag.data()); + } + } + return flags; +} + +inline SystemType getSystemType(auto const& periodsForSysType) +{ + auto period = metadataInfo.get("LPMProductionTag"); + auto anchoredPeriod = metadataInfo.get("AnchorProduction"); + bool checkAnchor = anchoredPeriod.length() > 0; + + for (SystemType sT = SystemNoSystem; sT < SystemNoOfSystems; ++sT) { + const std::string& periods = periodsForSysType[static_cast(sT)][0]; + auto contains = [periods](auto const& period) { + if (periods.find(period) != std::string::npos) { + return true; + } + return false; + }; + if (periods.length() > 0) { + if (contains(period) || (checkAnchor && contains(anchoredPeriod))) { + LOGF(info, "DptDptCorrelations::getSystemType(). Assigned system type %s for period %s", systemExternalNamesMap.at(static_cast(sT)).data(), period.c_str()); + return sT; + } + } + } + LOGF(fatal, "DptDptCorrelations::getSystemType(). No system type for period: %s", period.c_str()); + return SystemPbPb; +} + +/// \brief Type of data according to the configuration string +/// \param datastr The data type configuration string +/// \return Internal code for the passed kind of data string +inline DataType getDataType(std::string const& datastr) +{ + /* we have to figure out how extract the type of data*/ + if (datastr.empty() || (datastr == "data")) { + return kData; + } else if (datastr == "datanoevsel") { + return kDataNoEvtSel; + } else if (datastr == "MC") { + return kMC; + } else if (datastr == "FastMC") { + return kFastMC; + } else if (datastr == "OnTheFlyMC") { + return kOnTheFly; + } else { + LOGF(fatal, "DptDptCorrelations::getDataType(). Wrong type of dat: %d", datastr.c_str()); + } + return kData; +} + +inline CentMultEstimatorType getCentMultEstimator(std::string_view const& datastr) +{ + if (estimatorInternalCodesMap.contains(datastr)) { + return static_cast(estimatorInternalCodesMap.at(datastr)); + } else { + LOGF(fatal, "Centrality/Multiplicity estimator %s not supported yet", datastr.data()); + } + return CentMultNOCM; +} + +inline std::string_view getCentMultEstimatorName(CentMultEstimatorType est) +{ + if (estimatorExternalNamesMap.contains(est)) { + return estimatorExternalNamesMap.at(est); + } else { + LOGF(fatal, "Centrality/Multiplicity estimator %d not supported yet", static_cast(est)); + } + return "WRONG"; +} + +inline OccupancyEstimationType getOccupancyEstimator(const std::string_view& estimator) +{ + if (estimator == "None") { + return OccupancyNOOCC; + } else if (estimator == "Tracks") { + return OccupancyTRACKSOCC; + } else if (estimator == "FT0C") { + return OccupancyFT0COCC; + } else { + LOGF(fatal, "Occupancy estimator %s not supported yet", estimator.data()); + return OccupancyNOOCC; + } +} + +/// @brief gets the exclusion formula from the corresponding expression and initializes the exclusion machinery +/// @param std::string_view with the formula expression +/// @return the expression TFormula +inline TFormula* getExclusionFormula(std::string_view formula) +{ + collisionMultiplicityCentralityObservables.resize(CentMultCorrelationsNOOFPARAMS); + if (formula.length() != 0) { + useCentralityMultiplicityCorrelationsExclusion = true; + TFormula* f = new TFormula("Exclussion expression", formula.data()); + int nParameters = f->GetNpar(); + observableIndexForCentralityMultiplicityParameter.resize(nParameters); + LOGF(info, "Configuring outliers exclusion with the formula %s which has %d parameters", formula.data(), nParameters); + for (int iPar = 0; iPar < nParameters; ++iPar) { + if (centMultCorrelationsParamsMap.contains(std::string(f->GetParName(iPar)))) { + observableIndexForCentralityMultiplicityParameter[iPar] = centMultCorrelationsParamsMap.at(std::string(f->GetParName(iPar))); + LOGF(info, "\tAssigned observable %s with index %d to the parameter %s with parameter index %d", centMultCorrelationsParamsNamesMap.at(centMultCorrelationsParamsMap.at(std::string(f->GetParName(iPar)))).data(), static_cast(centMultCorrelationsParamsMap.at(std::string(f->GetParName(iPar)))), f->GetParName(iPar), iPar); + } else { + LOGF(fatal, "Exclusion expression contains parameter %s which is still not supported. Please, fix it!", f->GetParName(iPar)); + } + } + return f; + } else { + useCentralityMultiplicityCorrelationsExclusion = false; + return nullptr; + } +} + +////////////////////////////////////////////////////////////////////////////////// +/// Trigger selection +////////////////////////////////////////////////////////////////////////////////// + +/// \brief Trigger selection for reconstructed and detector level collision tables +template +inline bool triggerSelectionReco(CollisionObject const& collision) +{ + bool trigsel = false; + switch (fSystem) { + case SystemPp: + case SystemPPb: + case SystemPbp: + case SystemPbPb: + case SystemXeXe: + if (triggerSelectionFlags.test(TriggSelMB)) { + switch (fDataType) { + case kData: + if (collision.alias_bit(kINT7)) { + collisionFlags.set(CollSelINT7BIT); + if (collision.sel7()) { + trigsel = true; + collisionFlags.set(CollSelSEL7BIT); + } + } + break; + case kMC: + if (collision.sel7()) { + trigsel = true; + collisionFlags.set(CollSelSEL7BIT); + } + break; + default: + collisionFlags.set(CollSelMBBIT); + trigsel = true; + break; + } + } else if (triggerSelectionFlags.test(TriggSelNONE)) { + trigsel = true; + } + break; + case SystemPpRun3: + case SystemPbPbRun3: + case SystemNeNeRun3: + case SystemPORun3: + case SystemOORun3: { + auto setTriggerFlags = [](auto& flags, auto const& coll) { + flags.set(TriggSelMB, coll.sel8() != 0); + flags.set(TriggSelNOSAMEBUNCHPUP, coll.selection_bit(aod::evsel::kNoSameBunchPileup)); + flags.set(TriggSelNUMPVCONTRIBUTORS, coll.numContrib() > 1); /* TODO: make it configurable */ + flags.set(TriggSelVTXTOFMATCHED, coll.selection_bit(aod::evsel::kIsVertexTOFmatched)); + flags.set(TriggSelVTXTRDMATCHED, coll.selection_bit(aod::evsel::kIsVertexTRDmatched)); + flags.set(TriggSelNOCOLLINTRSTD, coll.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)); + flags.set(TriggSelNOCOLLINROFSTD, coll.selection_bit(aod::evsel::kNoCollInRofStandard)); + flags.set(TriggSelISVERTEXITSTPC, coll.selection_bit(aod::evsel::kIsVertexITSTPC)); + flags.set(TriggSelISGOODZVTXFT0VSPV, coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)); + flags.set(TriggSelGOODITSLAYER3, coll.selection_bit(aod::evsel::kIsGoodITSLayer3)); + flags.set(TriggSelGOODITSLAYER0123, coll.selection_bit(aod::evsel::kIsGoodITSLayer0123)); + flags.set(TriggSelGOODITSLAYERALL, coll.selection_bit(aod::evsel::kIsGoodITSLayersAll)); + flags.set(TriggSelNOGOODITSLAYER3, !coll.selection_bit(aod::evsel::kIsGoodITSLayer3)); + flags.set(TriggSelNOGOODITSLAYER0123, !coll.selection_bit(aod::evsel::kIsGoodITSLayer0123)); + flags.set(TriggSelNOGOODITSLAYERALL, !coll.selection_bit(aod::evsel::kIsGoodITSLayersAll)); + }; + setTriggerFlags(triggerFlags, collision); + + /* special treatment for no trigger selection */ + if (triggerSelectionFlags.test(TriggSelNONE)) { + trigsel = true; + } else { + trigsel = ((triggerSelectionFlags & triggerFlags) == triggerSelectionFlags); + } + } break; + default: + break; + } + collisionFlags.set(CollSelTRIGGSELBIT, trigsel); + return trigsel; +} + +/// \brief Trigger selection by default: unknow subscribed collision table +template +inline bool triggerSelection(CollisionObject const&) +{ + LOGF(fatal, "Trigger selection not implemented for this kind of collisions"); + return false; +} + +/// \brief Trigger selection for reconstructed collision tables without centrality/multiplicity +template <> +inline bool triggerSelection(aod::CollisionEvSel const& collision) +{ + return triggerSelectionReco(collision); +} + +/// \brief Trigger selection for reconstructed collision tables with Run 2 centrality/multiplicity +template <> +inline bool triggerSelection(aod::CollisionEvSelRun2Cent const& collision) +{ + return triggerSelectionReco(collision); +} + +/// \brief Trigger selection for reconstructed collision tables with centrality/multiplicity +template <> +inline bool triggerSelection(aod::CollisionEvSelCent const& collision) +{ + return triggerSelectionReco(collision); +} + +/// \brief Trigger selection for detector level collision tables without centrality/multiplicity +template <> +inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) +{ + return triggerSelectionReco(collision); +} + +/// \brief Trigger selection for detector level collision tables with Run 2 centrality/multiplicity +template <> +inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) +{ + return triggerSelectionReco(collision); +} + +/// \brief Trigger selection for detector level collision tables with centrality/multiplicity +template <> +inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) +{ + return triggerSelectionReco(collision); +} + +/// \brief Trigger selection for generator level collison table +template <> +inline bool triggerSelection(aod::McCollision const&) +{ + return true; +} + +////////////////////////////////////////////////////////////////////////////////// +/// Multiplicity extraction +////////////////////////////////////////////////////////////////////////////////// +static constexpr float ValidPercentileLowLimit = 0.0f; +static constexpr float ValidPercentileUpLimit = 100.0f; + +/// \brief Extract the collision multiplicity from the event selection information +template +inline float extractMultiplicity(CollisionObject const& collision, CentMultEstimatorType est) +{ + switch (est) { + case CentMultV0M: + return collision.multFV0M(); + break; + case CentMultCL0: + return collision.multTracklets(); + break; + case CentMultCL1: + return collision.multTracklets(); + break; + case CentMultFV0A: + return collision.multFV0A(); + break; + case CentMultFT0M: + return collision.multFT0M(); + break; + case CentMultFT0A: + return collision.multFT0A(); + break; + case CentMultFT0C: + return collision.multFT0C(); + break; + case CentMultNTPV: + return collision.multNTracksPV(); + break; + case CentMultNOCM: + return collision.multFT0M(); + break; + default: + LOGF(fatal, "Centrality/Multiplicity estimator %d not supported yet", (int)est); + return collision.multFT0M(); + break; + } +} + +////////////////////////////////////////////////////////////////////////////////// +/// Centrality selection +////////////////////////////////////////////////////////////////////////////////// + +/// \brief Centrality/multiplicity percentile +template + requires(o2::aod::HasRun2Centrality) +float getCentMultPercentile(CollisionObject collision) +{ + switch (fCentMultEstimator) { + case CentMultV0M: + return collision.centRun2V0M(); + case CentMultCL0: + return collision.centRun2CL0(); + case CentMultCL1: + return collision.centRun2CL1(); + default: + return 105.0; + } +} + +template + requires(o2::aod::HasCentrality) +float getCentMultPercentile(CollisionObject collision) +{ + switch (fCentMultEstimator) { + case CentMultFV0A: + return collision.centFV0A(); + case CentMultFT0M: + return collision.centFT0M(); + case CentMultFT0A: + return collision.centFT0A(); + case CentMultFT0C: + return collision.centFT0C(); + case CentMultNTPV: + return collision.centNTPV(); + default: + return 105.0; + } +} + +/// \brief Centrality selection when there is centrality/multiplicity information +template +inline bool centralitySelectionMult(CollisionObject collision, float& centmult) +{ + float mult = getCentMultPercentile(collision); + if (mult < ValidPercentileUpLimit && ValidPercentileLowLimit < mult) { + centmult = mult; + collisionFlags.set(CollSelCENTRALITYBIT); + return true; + } + return false; +} + +/// \brief Centrality selection when there is not centrality/multiplicity information +template +inline bool centralitySelectionNoMult(CollisionObject const&, float& centmult) +{ + bool centmultsel = false; + switch (fCentMultEstimator) { + case CentMultNOCM: + centmult = 50.0; + centmultsel = true; + collisionFlags.set(CollSelCENTRALITYBIT); + break; + default: + break; + } + return centmultsel; +} + +/// \brief Centrality selection by default: unknown subscribed collision table +template +inline bool centralitySelection(CollisionObject const&, float&) +{ + LOGF(fatal, "Centrality selection not implemented for this kind of collisions"); + return false; +} + +/// \brief Centrality selection for reconstructed and detector level collision tables with centrality/multiplicity information +template <> +inline bool centralitySelection(aod::CollisionEvSelCent const& collision, float& centmult) +{ + return centralitySelectionMult(collision, centmult); +} + +/// \brief Centrality selection for reconstructed and detector level collision tables with Run 2 centrality/multiplicity information +template <> +inline bool centralitySelection(aod::CollisionEvSelRun2Cent const& collision, float& centmult) +{ + return centralitySelectionMult(collision, centmult); +} + +/// \brief Centrality selection for reconstructed and detector level collision tables without centrality/multiplicity information +template <> +inline bool centralitySelection(aod::CollisionEvSel const& collision, float& centmult) +{ + return centralitySelectionNoMult(collision, centmult); +} + +/// \brief Centrality selection for detector level collision tables without centrality/multiplicity +template <> +inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) +{ + return centralitySelectionNoMult(collision, centmult); +} + +/// \brief Centrality selection for detector level collision tables with centrality/multiplicity +template <> +inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) +{ + return centralitySelectionMult(collision, centmult); +} + +/// \brief Centrality selection for detector level collision tables with Run 2 centrality/multiplicity +template <> +inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) +{ + return centralitySelectionMult(collision, centmult); +} + +/// \brief Centrality selection for generator level collision table +template <> +inline bool centralitySelection(aod::McCollision const&, float& centmult) +{ + if (centmult < ValidPercentileUpLimit && ValidPercentileLowLimit < centmult) { + return true; + } else { + return false; + } +} + +/// @brief evalues the exclusion formula for the current multiplicity / centrality parameters +/// @return true if the collision is not excluded according to the formula false otherwise +/// WARNING: it has always to be called after filling the multiplicity / centrality observables +/// NOTE: for MC generator level does nothing, as expected +template +inline bool isCollisionNotExcluded() +{ + bool notExcluded = true; + if constexpr (!framework::has_type_v) { + if (useCentralityMultiplicityCorrelationsExclusion) { + [&]() { + /* set the formula parameter values */ + for (size_t iPar = 0; iPar < observableIndexForCentralityMultiplicityParameter.size(); ++iPar) { + multiplicityCentralityCorrelationsExclusion->SetParameter(iPar, collisionMultiplicityCentralityObservables[observableIndexForCentralityMultiplicityParameter[iPar]]); + } + }(); + notExcluded = multiplicityCentralityCorrelationsExclusion->Eval() != 0; + } + } + collisionFlags.set(CollSelMULTCORRELATIONS, notExcluded); + return notExcluded; +} + +////////////////////////////////////////////////////////////////////////////////// +/// 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 OccupancyNOOCC: + collisionFlags.set(CollSelOCCUPANCYBIT); + return true; + case OccupancyTRACKSOCC: + if ((fMinOccupancy <= collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < fMaxOccupancy)) { + collisionFlags.set(CollSelOCCUPANCYBIT); + return true; + } else { + return false; + } + case OccupancyFT0COCC: + if ((fMinOccupancy <= collision.ft0cOccupancyInTimeRange()) && (collision.ft0cOccupancyInTimeRange() < fMaxOccupancy)) { + collisionFlags.set(CollSelOCCUPANCYBIT); + 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; +} + +////////////////////////////////////////////////////////////////////////////////// +/// Event selection +////////////////////////////////////////////////////////////////////////////////// + +template +inline bool isEventSelected(CollisionObject const& collision, float& centormult) +{ + triggerFlags.reset(); + collisionFlags.reset(); + collisionFlags.set(CollSelIN); + + bool trigsel = triggerSelection(collision); + + /* run condition table information */ + bool rctsel = true; + if (useRctInformation) { + if constexpr (framework::has_type_v) { + /* RCT condition not considered for generator level */ + } else { + if constexpr (framework::has_type_v) { + if (!rctChecker.checkTable(collision)) { + rctsel = false; + } + } else { + LOGF(fatal, "RCT check required but the dataset does not have RCT information associated. Please, fix it"); + } + } + } + collisionFlags.set(CollSelRCTBIT, rctsel); + + bool occupancysel = occupancySelection(collision); + + bool zvtxsel = false; + /* TODO: vertex quality checks */ + if (zvtxlow < collision.posZ() && collision.posZ() < zvtxup) { + if (onlyInOneSide) { + if (collision.posZ() != 0.0) { + /* if only one side, we accept collisions which have zvtx different than zero */ + zvtxsel = true; + collisionFlags.set(CollSelZVERTEXBIT); + } + } else { + zvtxsel = true; + collisionFlags.set(CollSelZVERTEXBIT); + } + } + + bool centmultsel = centralitySelection(collision, centormult); + + bool centmultexclusion = isCollisionNotExcluded(); + + bool accepted = trigsel && rctsel && occupancysel && zvtxsel && centmultsel && centmultexclusion; + + if (accepted) { + collisionFlags.set(CollSelSELECTED); + } + + return accepted; +} + +////////////////////////////////////////////////////////////////////////////////// +/// Track selection +////////////////////////////////////////////////////////////////////////////////// + +struct TpcExcludeTrack { + TpcExcludeTrack() + { + method = kNOEXCLUSION; + } + explicit TpcExcludeTrack(TpcExclusionMethod m) + { + static constexpr float DefaultPhiBinShift = 0.5f; + static constexpr int DefaultNoOfPhiBins = 72; + switch (m) { + case kNOEXCLUSION: + method = m; + break; + case kSTATIC: + if (phibinshift == DefaultPhiBinShift && phibins == DefaultNoOfPhiBins) { + 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 NoOfTpcSectors = 18; + constexpr float TpcPhiSectorWidth = (constants::math::TwoPI) / NoOfTpcSectors; + + 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(), TpcPhiSectorWidth); + 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) +{ + using namespace o2::aod::track; + + if (tracktype == TrackTypePWGMM) { + // under tests MM track selection + // see: https://indico.cern.ch/event/1383788/contributions/5816953/attachments/2805905/4896281/TrackSel_GlobalTracks_vs_MMTrackSel.pdf + // it should be equivalent to this + // (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); + } else { + for (auto const& filter : trackFilters) { + if (filter->isSelected(track)) { + return true; + } + } + return false; + } +} + +/// \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) +{ + /* 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; + } + + if constexpr (framework::has_type_v) { + if (track.mcParticleId() < 0) { + return false; + } + } + + /* 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 !tpcExcluder.exclude(track); + } + return false; +} + +/// \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) +{ + if (inTheAcceptance(track)) { + if (matchTrackType(track)) { + return true; + } + } + return false; +} + +template +void exploreMothers(ParticleObject& particle, MCCollisionObject& collision) +{ + 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()); + LOGF(info, " index: %d, pdg code: %d", m.globalIndex(), m.pdgCode()); + LOGF(info, " Passed isPhysicalPrimary(): %s", m.isPhysicalPrimary() ? "YES" : "NO"); + + exploreMothers(m, collision); + } +} + +inline float getCharge(float pdgCharge) +{ + static constexpr int NoOfBasicChargesPerUnitCharge = 3; + float charge = (pdgCharge / NoOfBasicChargesPerUnitCharge >= 1) ? 1.0 : ((pdgCharge / NoOfBasicChargesPerUnitCharge <= -1) ? -1.0 : 0); + return charge; +} + +/// \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 bool acceptParticle(ParticleObject& particle, MCCollisionObject const&) +{ + /* overall momentum cut */ + if (!(overallminp < particle.p())) { + return false; + } + + 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 true; + } + } else { + if ((particle.mcCollisionId() == 0) && traceCollId0) { + LOGF(info, "Particle %d NOT passed isPhysicalPrimary", particle.globalIndex()); + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////// +/// PID +////////////////////////////////////////////////////////////////////////////////// + +struct PIDSpeciesSelection { + const std::vector pdgcodes = {kElectron, kMuonMinus, kPiPlus, kKPlus, kProton}; + const std::vector spnames = {"e", "mu", "pi", "ka", "p"}; + 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"; + const char* hadfname = "Ha"; + uint getNSpecies() { return config.size(); } + 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; } + bool isSpeciesBeingSelected(uint8_t sp) { return std::find(species.begin(), species.end(), sp) != species.end(); } + bool isGlobalSpecies(uint8_t isp, o2::track::PID::ID glsp) { return species[isp] == glsp; } + void storePIDAdjustments(TList* lst) + { + auto storedetectorwithcharge = [&](auto& detectorstore, auto detectorname, auto charge) { + for (uint isp = 0; isp < spadjnames.size(); ++isp) { + TString fullhname = TString::Format("%s%s%s_Difference", detectorname, spadjnames[isp].data(), charge); + detectorstore[isp] = static_cast(lst->FindObject(fullhname.Data())); + } + }; + auto reportadjdetectorwithcharge = [&](auto& detectorstore, auto detectorname, auto charge) { + for (uint isp = 0; isp < spadjnames.size(); ++isp) { + if (detectorstore[isp] != nullptr) { + LOGF(info, "Stored nsigmas adjust for detector %s and species %s%s in histogram %s", detectorname, spadjnames[isp].data(), charge, detectorstore[isp]->GetName()); + } + } + }; + storedetectorwithcharge(tpcnsigmasshiftpos, "TPC", "P"); + storedetectorwithcharge(tofnsigmasshiftpos, "TOF", "P"); + storedetectorwithcharge(tpcnsigmasshiftneg, "TPC", "M"); + storedetectorwithcharge(tofnsigmasshiftneg, "TOF", "M"); + + reportadjdetectorwithcharge(tpcnsigmasshiftpos, "TPC", "P"); + reportadjdetectorwithcharge(tofnsigmasshiftpos, "TOF", "P"); + reportadjdetectorwithcharge(tpcnsigmasshiftneg, "TPC", "M"); + reportadjdetectorwithcharge(tofnsigmasshiftneg, "TOF", "M"); + } + void addSpecies(uint8_t sp, o2::analysis::TrackSelectionPIDCfg* incfg) + { + o2::analysis::TrackSelectionPIDCfg* cfg = new o2::analysis::TrackSelectionPIDCfg(*incfg); + config.push_back(cfg); + species.push_back(sp); + + auto last = config[config.size() - 1]; + uint8_t lastsp = species[config.size() - 1]; + LOGF(info, "Inserted species %d with", lastsp); + LOGF(info, " minTPC nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMinNSigmasTPC[0], last->mMinNSigmasTPC[1], last->mMinNSigmasTPC[2], last->mMinNSigmasTPC[3], last->mMinNSigmasTPC[4]); + 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 addExcludedSpecies(uint8_t sp, const o2::analysis::TrackSelectionPIDCfg* incfg) + { + o2::analysis::TrackSelectionPIDCfg* cfg = new o2::analysis::TrackSelectionPIDCfg(*incfg); + configexclude.push_back(cfg); + speciesexclude.push_back(sp); + auto last = configexclude[configexclude.size() - 1]; + uint8_t lastsp = speciesexclude[configexclude.size() - 1]; + + LOGF(info, "Inserted species %d for exclusion with", lastsp); + LOGF(info, " minTPC nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMinNSigmasTPC[0], last->mMinNSigmasTPC[1], last->mMinNSigmasTPC[2], last->mMinNSigmasTPC[3], last->mMinNSigmasTPC[4]); + 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 + 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; + } else { + return false; + } + }; + auto awayFrom = [&](auto& values, auto& mindet, auto& maxdet, uint8_t sp) { + for (size_t ix = 0; ix < pdgcodes.size(); ix++) { + if (ix != sp) { + if (mindet[ix] <= values[ix] && values[ix] < maxdet[ix]) { + return false; + } + } else { + continue; + } + } + return true; + }; + auto closeToTPC = [&](auto& config, uint8_t sp) { + return closeTo(tpcnsigmas, config->mMinNSigmasTPC, config->mMaxNSigmasTPC, sp); + }; + auto awayFromTPC = [&](auto& config, uint8_t sp) { + return awayFrom(tpcnsigmas, config->mMinNSigmasTPC, config->mMaxNSigmasTPC, sp); + }; + auto closeToTOF = [&](auto& config, uint8_t sp) { + return closeTo(tofnsigmas, config->mMinNSigmasTOF, config->mMaxNSigmasTOF, sp); + }; + auto closeToTPCTOF = [&](auto& config, uint8_t sp) { + if (config->m2Dcut) { + float a = (config->mMaxNSigmasTPC[sp] - config->mMinNSigmasTPC[sp]) / 2.0; + float b = (config->mMaxNSigmasTOF[sp] - config->mMinNSigmasTOF[sp]) / 2.0; + float oa = (config->mMaxNSigmasTPC[sp] + config->mMinNSigmasTPC[sp]) / 2.0; + float ob = (config->mMaxNSigmasTOF[sp] + config->mMinNSigmasTOF[sp]) / 2.0; + float vtpc = tpcnsigmas[sp] - oa; + float vtof = tofnsigmas[sp] - ob; + return ((vtpc * vtpc / a / a + vtof * vtof / b / b) < 1); + } else { + return closeToTPC(config, sp) && closeToTOF(config, sp); + } + }; + auto awayFromTPCTOF = [&](auto& config, uint8_t sp) { + for (uint8_t ix = 0; ix < pdgcodes.size(); ++ix) { + if (ix != sp) { + if (closeToTPCTOF(config, ix)) { + return false; + } + } else { + continue; + } + } + return true; + }; + auto aboveThreshold = [&](auto& config) { + return ((config->mPThreshold > 0.0) && (config->mPThreshold < track.p())); + }; + auto isA = [&](auto& config, uint8_t sp) { + if (track.hasTOF()) { + return closeToTPCTOF(config, sp) && awayFromTPCTOF(config, sp); + } else { + if (aboveThreshold(config)) { + if (config->mRequireTOF) { + return false; + } + } + } + /* we are here */ + /* - below the threshold */ + /* - above the threshold without TOF and without requiring it */ + /* so we check only the TPC information */ + return closeToTPC(config, sp) && awayFromTPC(config, sp); + }; + + auto adjustnsigmas = [&]() { + if (track.sign() > 0) { + for (uint isp = 0; isp < spnames.size(); ++isp) { + if (tpcnsigmasshiftpos[isp] != nullptr) { + TH1* h = tpcnsigmasshiftpos[isp]; + tpcnsigmas[isp] -= h->GetBinContent(h->GetXaxis()->FindFixBin(track.p())); + } + if (tofnsigmasshiftpos[isp] != nullptr) { + TH1* h = tofnsigmasshiftpos[isp]; + tofnsigmas[isp] -= h->GetBinContent(h->GetXaxis()->FindFixBin(track.p())); + } + } + } else { + for (uint isp = 0; isp < spnames.size(); ++isp) { + if (tpcnsigmasshiftneg[isp] != nullptr) { + TH1* h = tpcnsigmasshiftneg[isp]; + tpcnsigmas[isp] -= h->GetBinContent(h->GetXaxis()->FindFixBin(track.p())); + } + if (tofnsigmasshiftneg[isp] != nullptr) { + TH1* h = tofnsigmasshiftneg[isp]; + tofnsigmas[isp] -= h->GetBinContent(h->GetXaxis()->FindFixBin(track.p())); + } + } + } + }; + + 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); + } + } + /* we don't exclude it so check which species if any required */ + if (config.size() > 0) { + int8_t id = -127; + for (uint8_t ix = 0; ix < config.size(); ++ix) { + if (isA(config[ix], species[ix])) { + 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; + } + } + template + int8_t whichTruthSpecies(ParticleObject part) + { + int pdgcode = std::abs(part.pdgCode()); + /* let's first check the exclusion from the analysis */ + for (uint8_t ix = 0; ix < configexclude.size(); ++ix) { + if (pdgcode == pdgcodes[speciesexclude[ix]]) { + return -(ix + 1); + } + } + /* we don't exclude it so check which species if any required */ + 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; + } + } + return -127; + } else { + return 0; + } + } + + template + int8_t whichTruthPrimarySpecies(ParticleObject part) + { + if (part.isPhysicalPrimary()) { + return whichTruthSpecies(part); + } else { + return -127; + } + } + + template + int8_t whichTruthSecondarySpecies(ParticleObject part) + { + if (!(part.isPhysicalPrimary())) { + return whichTruthSpecies(part); + } else { + return -127; + } + } + + template + int8_t whichTruthSecFromDecaySpecies(ParticleObject part) + { + if (!(part.isPhysicalPrimary()) && (part.getProcess() == TMCProcess::kPDecay)) { + return whichTruthSpecies(part); + } else { + return -127; + } + } + + template + int8_t whichTruthSecFromMaterialSpecies(ParticleObject part) + { + if (!(part.isPhysicalPrimary()) && (part.getProcess() != TMCProcess::kPDecay)) { + return whichTruthSpecies(part); + } else { + return -127; + } + } + + std::vector config; ///< the PID selection configuration of the species to include in the analysis + std::vector species; ///< the species index of the species to include in the analysis + std::vector configexclude; ///< the PID selection configuration of the species to exclude from the analysis + std::vector speciesexclude; ///< the species index of teh species to exclude from the analysis + std::vector tpcnsigmasshiftpos{spnames.size(), nullptr}; + std::vector tpcnsigmasshiftneg{spnames.size(), nullptr}; + std::vector tofnsigmasshiftpos{spnames.size(), nullptr}; + std::vector tofnsigmasshiftneg{spnames.size(), nullptr}; +}; + +} // namespace dptdptfilter +} // namespace analysis +} // namespace o2 + +#endif // PWGCF_TABLEPRODUCER_DPTDPTFILTER_H_ diff --git a/PWGCF/TableProducer/dptdptfilter.h b/PWGCF/TableProducer/dptdptfilter.h deleted file mode 100644 index bae7b9934d0..00000000000 --- a/PWGCF/TableProducer/dptdptfilter.h +++ /dev/null @@ -1,1289 +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. -#ifndef PWGCF_TABLEPRODUCER_DPTDPTFILTER_H_ -#define PWGCF_TABLEPRODUCER_DPTDPTFILTER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ReconstructionDataFormats/PID.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include - -namespace o2 -{ -namespace aod -{ -using CollisionsEvSelCent = soa::Join; -using CollisionEvSelCent = 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; -} // namespace aod -namespace analysis -{ -namespace dptdptfilter -{ -/// \enum SystemType -/// \brief The type of the system under analysis -enum SystemType { - kNoSystem = 0, ///< no system defined - kpp, ///< **p-p** system - kpPb, ///< **p-Pb** system - kPbp, ///< **Pb-p** system - kPbPb, ///< **Pb-Pb** system - kXeXe, ///< **Xe-Xe** system - kppRun3, ///< **p-p Run 3** system - kPbPbRun3, ///< **Pb-Pb Run 3** system - knSystems ///< number of handled systems -}; - -/// \enum DataType -/// \brief Which kind of data is the task addressing -enum DataType { - kData = 0, ///< actual data, not generated - kMC, ///< Generator level and detector level - kFastMC, ///< Gererator level but stored dataset - kOnTheFly, ///< On the fly generator level data - kDataNoEvtSel, ///< actual data but not event selection available yet - knGenData ///< number of different generator data types -}; - -/// \enum CentMultEstimatorType -/// \brief The detector used to estimate centrality/multiplicity -enum CentMultEstimatorType { - kNOCM = 0, ///< do not use centrality/multiplicity estimator - kV0M, ///< V0M centrality/multiplicity estimator Run 1/2 - kCL0, ///< CL0 centrality/multiplicity estimator Run 1/2 - kCL1, ///< CL1 centrality/multiplicity estimator Run 1/2 - kFV0A, ///< FV0A centrality/multiplicity estimator Run 3 - kFT0M, ///< FT0M centrality/multiplicity estimator Run 3 - kFT0A, ///< FT0A centrality/multiplicity estimator Run 3 - kFT0C, ///< FT0C centrality/multiplicity estimator Run 3 - kNTPV, ///< NTPV centrality/multiplicity estimator Run 3 - knCentMultEstimators ///< number of centrality/mutiplicity estimator -}; - -/// \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 -}; - -/// \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 -}; - -//============================================================================================ -// The debug output stream -//============================================================================================ -std::ofstream debugstream; - -//============================================================================================ -// The overall minimum momentum -//============================================================================================ -float overallminp = 0.0f; - -//============================================================================================ -// The DptDptFilter configuration objects -//============================================================================================ -int ptbins = 18; -float ptlow = 0.2, ptup = 2.0; -int etabins = 16; -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 phiup = constants::math::TwoPI; - -/* selection criteria from PWGMM */ -// default quality criteria for tracks with ITS contribution -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 = - 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 = - o2::aod::track::TrackSelectionFlags::kDCAz | o2::aod::track::TrackSelectionFlags::kDCAxy; - -int tracktype = 1; -std::function maxDcaZPtDep{}; // max dca in z axis as function of pT - -std::vector trackFilters = {}; -bool dca2Dcut = false; -float maxDCAz = 1e6f; -float maxDCAxy = 1e6f; - -inline TList* getCCDBInput(auto& ccdb, const char* ccdbpath, const char* ccdbdate, const char* period = "") -{ - 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 = nullptr; - if (std::strlen(period) != 0) { - std::map metadata{{"Period", period}}; - lst = ccdb->template getSpecific(ccdbpath, timestamp, metadata); - } else { - lst = ccdb->template 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; -} - -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; - -/* adaptations for the pp nightly checks */ -analysis::CheckRangeCfg traceDCAOutliers; -bool traceOutOfSpeciesParticles = false; -int recoIdMethod = 0; -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 == "VTXTOFMATCHED") { - return kVTXTOFMATCHED; - } else if (triggstr == "VTXTRDMATCHED") { - return kVTXTRDMATCHED; - } else if (triggstr == "VTXTRDTOFMATCHED") { - return kVTXTRDTOFMATCHED; - } else if (triggstr == "None") { - return kNONE; - } else { - LOGF(fatal, "Wrong trigger selection: %s", triggstr.c_str()); - return kNONE; - } -} - -inline SystemType getSystemType(std::string const& sysstr) -{ - /* we have to figure out how extract the system type */ - if (sysstr.empty() || (sysstr == "PbPb")) { - return kPbPb; - } else if (sysstr == "pp") { - return kpp; - } else if (sysstr == "pPb") { - return kpPb; - } else if (sysstr == "Pbp") { - return kPbp; - } else if (sysstr == "pPb") { - return kpPb; - } else if (sysstr == "XeXe") { - return kXeXe; - } else if (sysstr == "ppRun3") { - return kppRun3; - } else if (sysstr == "PbPbRun3") { - return kPbPbRun3; - } else { - LOGF(fatal, "DptDptCorrelations::getSystemType(). Wrong system type: %s", sysstr.c_str()); - } - return kPbPb; -} - -/// \brief Type of data according to the configuration string -/// \param datastr The data type configuration string -/// \return Internal code for the passed kind of data string -inline DataType getDataType(std::string const& datastr) -{ - /* we have to figure out how extract the type of data*/ - if (datastr.empty() || (datastr == "data")) { - return kData; - } else if (datastr == "datanoevsel") { - return kDataNoEvtSel; - } else if (datastr == "MC") { - return kMC; - } else if (datastr == "FastMC") { - return kFastMC; - } else if (datastr == "OnTheFlyMC") { - return kOnTheFly; - } else { - LOGF(fatal, "DptDptCorrelations::getDataType(). Wrong type of dat: %d", datastr.c_str()); - } - return kData; -} - -inline CentMultEstimatorType getCentMultEstimator(std::string const& datastr) -{ - if (datastr == "V0M") { - return kV0M; - } else if (datastr == "CL0") { - return kCL0; - } else if (datastr == "CL1") { - return kCL1; - } else if (datastr == "FV0A") { - return kFV0A; - } else if (datastr == "FT0M") { - return kFT0M; - } else if (datastr == "FT0A") { - return kFT0A; - } else if (datastr == "FT0C") { - return kFT0C; - } else if (datastr == "NTPV") { - return kNTPV; - } else if (datastr == "NOCM") { - return kNOCM; - } else { - LOGF(fatal, "Centrality/Multiplicity estimator %s not supported yet", datastr.c_str()); - } - return kNOCM; -} - -inline std::string getCentMultEstimatorName(CentMultEstimatorType est) -{ - switch (est) { - case kV0M: - return "V0M"; - break; - case kCL0: - return "CL0"; - break; - case kCL1: - return "CL1"; - break; - case kFV0A: - return "FV0A"; - break; - case kFT0M: - return "FT0M"; - break; - case kFT0A: - return "FT0A"; - break; - case kFT0C: - return "FT0C"; - break; - case kNTPV: - return "NTPV"; - break; - case kNOCM: - return "NOCM"; - break; - default: - LOGF(fatal, "Centrality/Multiplicity estimator %d not supported yet", (int)est); - return "WRONG"; - break; - } -} - -////////////////////////////////////////////////////////////////////////////////// -/// Trigger selection -////////////////////////////////////////////////////////////////////////////////// - -/// \brief Trigger selection for reconstructed and detector level collision tables -template -inline bool triggerSelectionReco(CollisionObject const& collision) -{ - bool trigsel = false; - switch (fSystem) { - case kpp: - case kpPb: - case kPbp: - case kPbPb: - case kXeXe: - switch (fTriggerSelection) { - case kMB: - switch (fDataType) { - case kData: - if (collision.alias_bit(kINT7)) { - if (collision.sel7()) { - trigsel = true; - } - } - break; - case kMC: - if (collision.sel7()) { - trigsel = true; - } - break; - default: - trigsel = true; - break; - } - break; - case kNONE: - trigsel = true; - break; - default: - break; - } - break; - case kppRun3: - 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::kNoSameBunchPileup) && - coll.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && - coll.selection_bit(aod::evsel::kIsVertexITSTPC); - }; - switch (fTriggerSelection) { - case kMB: - if (run3Accepted(collision)) { - trigsel = true; - } - break; - case kVTXTOFMATCHED: - if (run3Accepted(collision) && collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { - trigsel = true; - } - break; - case kVTXTRDMATCHED: - if (run3Accepted(collision) && collision.selection_bit(aod::evsel::kIsVertexTRDmatched)) { - trigsel = true; - } - break; - case kVTXTRDTOFMATCHED: - if (run3Accepted(collision) && collision.selection_bit(aod::evsel::kIsVertexTRDmatched) && collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { - trigsel = true; - } - break; - case kNONE: - trigsel = true; - break; - default: - break; - } - } break; - default: - break; - } - return trigsel; -} - -/// \brief Trigger selection by default: unknow subscribed collision table -template -inline bool triggerSelection(CollisionObject const&) -{ - LOGF(fatal, "Trigger selection not implemented for this kind of collisions"); - return false; -} - -/// \brief Trigger selection for reconstructed collision tables without centrality/multiplicity -template <> -inline bool triggerSelection(aod::CollisionEvSel const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for reconstructed collision tables with Run 2 centrality/multiplicity -template <> -inline bool triggerSelection(aod::CollisionEvSelRun2Cent const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for reconstructed collision tables with centrality/multiplicity -template <> -inline bool triggerSelection(aod::CollisionEvSelCent const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for detector level collision tables without centrality/multiplicity -template <> -inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for detector level collision tables with Run 2 centrality/multiplicity -template <> -inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for detector level collision tables with centrality/multiplicity -template <> -inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for generator level collison table -template <> -inline bool triggerSelection(aod::McCollision const&) -{ - return true; -} - -////////////////////////////////////////////////////////////////////////////////// -/// Multiplicity extraction -////////////////////////////////////////////////////////////////////////////////// - -/// \brief Extract the collision multiplicity from the event selection information -template -inline float extractMultiplicity(CollisionObject const& collision, CentMultEstimatorType est) -{ - switch (est) { - case kV0M: - return collision.multFV0M(); - break; - case kCL0: - return collision.multTracklets(); - break; - case kCL1: - return collision.multTracklets(); - break; - case kFV0A: - return collision.multFV0A(); - break; - case kFT0M: - return collision.multFT0M(); - break; - case kFT0A: - return collision.multFT0A(); - break; - case kFT0C: - return collision.multFT0M(); - break; - case kNTPV: - return collision.multNTracksPV(); - break; - case kNOCM: - return collision.multFT0M(); - break; - default: - LOGF(fatal, "Centrality/Multiplicity estimator %d not supported yet", (int)est); - return collision.multFT0M(); - break; - } -} - -////////////////////////////////////////////////////////////////////////////////// -/// Centrality selection -////////////////////////////////////////////////////////////////////////////////// - -/// \brief Centrality/multiplicity percentile -template -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; - } - } - 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; - } - } -} - -/// \brief Centrality selection when there is centrality/multiplicity information -template -inline bool centralitySelectionMult(CollisionObject collision, float& centmult) -{ - float mult = getCentMultPercentile(collision); - if (mult < 100 && 0 < mult) { - centmult = mult; - return true; - } - return false; -} - -/// \brief Centrality selection when there is not centrality/multiplicity information -template -inline bool centralitySelectionNoMult(CollisionObject const&, float& centmult) -{ - bool centmultsel = false; - switch (fCentMultEstimator) { - case kNOCM: - centmult = 50.0; - centmultsel = true; - break; - default: - break; - } - return centmultsel; -} - -/// \brief Centrality selection by default: unknown subscribed collision table -template -inline bool centralitySelection(CollisionObject const&, float&) -{ - LOGF(fatal, "Centrality selection not implemented for this kind of collisions"); - return false; -} - -/// \brief Centrality selection for reconstructed and detector level collision tables with centrality/multiplicity information -template <> -inline bool centralitySelection(aod::CollisionEvSelCent const& collision, float& centmult) -{ - return centralitySelectionMult(collision, centmult); -} - -/// \brief Centrality selection for reconstructed and detector level collision tables with Run 2 centrality/multiplicity information -template <> -inline bool centralitySelection(aod::CollisionEvSelRun2Cent const& collision, float& centmult) -{ - return centralitySelectionMult(collision, centmult); -} - -/// \brief Centrality selection for reconstructed and detector level collision tables without centrality/multiplicity information -template <> -inline bool centralitySelection(aod::CollisionEvSel const& collision, float& centmult) -{ - return centralitySelectionNoMult(collision, centmult); -} - -/// \brief Centrality selection for detector level collision tables without centrality/multiplicity -template <> -inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) -{ - return centralitySelectionNoMult(collision, centmult); -} - -/// \brief Centrality selection for detector level collision tables with centrality/multiplicity -template <> -inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) -{ - return centralitySelectionMult(collision, centmult); -} - -/// \brief Centrality selection for detector level collision tables with Run 2 centrality/multiplicity -template <> -inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) -{ - return centralitySelectionMult(collision, centmult); -} - -/// \brief Centrality selection for generator level collision table -template <> -inline bool centralitySelection(aod::McCollision const&, float& centmult) -{ - if (centmult < 100 && 0 < centmult) { - return true; - } else { - return false; - } -} - -////////////////////////////////////////////////////////////////////////////////// -/// Event selection -////////////////////////////////////////////////////////////////////////////////// - -template -inline bool IsEvtSelected(CollisionObject const& collision, float& centormult) -{ - bool trigsel = triggerSelection(collision); - - bool zvtxsel = false; - /* TODO: vertex quality checks */ - if (zvtxlow < collision.posZ() && collision.posZ() < zvtxup) { - zvtxsel = true; - } - - bool centmultsel = centralitySelection(collision, centormult); - - return trigsel && zvtxsel && centmultsel; -} - -////////////////////////////////////////////////////////////////////////////////// -/// Track selection -////////////////////////////////////////////////////////////////////////////////// - -template -inline bool matchTrackType(TrackObject const& track) -{ - using namespace o2::aod::track; - - if (tracktype == 4) { - // under tests MM track selection - // see: https://indico.cern.ch/event/1383788/contributions/5816953/attachments/2805905/4896281/TrackSel_GlobalTracks_vs_MMTrackSel.pdf - // it should be equivalent to this - // (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); - } 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; - } - return true; - } - } - return false; - } -} - -/// \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) -{ - /* overall minimum momentum cut for the analysis */ - if (!(overallminp < track.p())) { - return false; - } - - if constexpr (framework::has_type_v) { - if (track.mcParticleId() < 0) { - return false; - } - } - - if (ptlow < track.pt() && track.pt() < ptup && etalow < track.eta() && track.eta() < etaup) { - return true; - } - return false; -} - -/// \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) -{ - if (InTheAcceptance(track)) { - if (matchTrackType(track)) { - return true; - } - } - return false; -} - -template -void exploreMothers(ParticleObject& particle, MCCollisionObject& collision) -{ - for (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()); - LOGF(info, " index: %d, pdg code: %d", m.globalIndex(), m.pdgCode()); - LOGF(info, " Passed isPhysicalPrimary(): %s", m.isPhysicalPrimary() ? "YES" : "NO"); - - exploreMothers(m, collision); - } -} - -template -inline float getCharge(ParticleObject& particle) -{ - 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); - } - return charge; -} - -/// \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 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; - } - } else { - if ((particle.mcCollisionId() == 0) && traceCollId0) { - LOGF(info, "Particle %d NOT passed isPhysicalPrimary", particle.globalIndex()); - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////////////// -/// PID -////////////////////////////////////////////////////////////////////////////////// - -struct PIDSpeciesSelection { - const std::vector pdgcodes = {11, 13, 211, 321, 2212}; - const std::vector spnames = {"e", "mu", "pi", "ka", "p"}; - 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 chadjnames = {"P", "M"}; - const char* hadname = "h"; - const char* hadtitle = "h"; - const char* hadfname = "Ha"; - uint getNSpecies() { return config.size(); } - 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(); } - const char* getHadName() { return hadname; } - const char* getHadTitle() { return hadtitle; } - const char* getHadFName() { return hadfname; } - bool isSpeciesBeingSelected(uint8_t sp) { return std::find(species.begin(), species.end(), sp) != species.end(); } - bool isGlobalSpecies(uint8_t isp, o2::track::PID::ID glsp) { return species[isp] == glsp; } - void storePIDAdjustments(TList* lst) - { - auto storedetectorwithcharge = [&](auto& detectorstore, auto detectorname, auto charge) { - for (uint isp = 0; isp < spadjnames.size(); ++isp) { - TString fullhname = TString::Format("%s%s%s_Difference", detectorname, spadjnames[isp].data(), charge); - detectorstore[isp] = static_cast(lst->FindObject(fullhname.Data())); - } - }; - auto reportadjdetectorwithcharge = [&](auto& detectorstore, auto detectorname, auto charge) { - for (uint isp = 0; isp < spadjnames.size(); ++isp) { - if (detectorstore[isp] != nullptr) { - LOGF(info, "Stored nsigmas adjust for detector %s and species %s%s in histogram %s", detectorname, spadjnames[isp].data(), charge, detectorstore[isp]->GetName()); - } - } - }; - storedetectorwithcharge(tpcnsigmasshiftpos, "TPC", "P"); - storedetectorwithcharge(tofnsigmasshiftpos, "TOF", "P"); - storedetectorwithcharge(tpcnsigmasshiftneg, "TPC", "M"); - storedetectorwithcharge(tofnsigmasshiftneg, "TOF", "M"); - - reportadjdetectorwithcharge(tpcnsigmasshiftpos, "TPC", "P"); - reportadjdetectorwithcharge(tofnsigmasshiftpos, "TOF", "P"); - reportadjdetectorwithcharge(tpcnsigmasshiftneg, "TPC", "M"); - reportadjdetectorwithcharge(tofnsigmasshiftneg, "TOF", "M"); - } - void Add(uint8_t sp, o2::analysis::TrackSelectionPIDCfg* incfg) - { - o2::analysis::TrackSelectionPIDCfg* cfg = new o2::analysis::TrackSelectionPIDCfg(*incfg); - config.push_back(cfg); - species.push_back(sp); - - auto last = config[config.size() - 1]; - uint8_t lastsp = species[config.size() - 1]; - LOGF(info, "Inserted species %d with", lastsp); - LOGF(info, " minTPC nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMinNSigmasTPC[0], last->mMinNSigmasTPC[1], last->mMinNSigmasTPC[2], last->mMinNSigmasTPC[3], last->mMinNSigmasTPC[4]); - 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) - { - o2::analysis::TrackSelectionPIDCfg* cfg = new o2::analysis::TrackSelectionPIDCfg(*incfg); - configexclude.push_back(cfg); - speciesexclude.push_back(sp); - auto last = configexclude[configexclude.size() - 1]; - uint8_t lastsp = speciesexclude[configexclude.size() - 1]; - - LOGF(info, "Inserted species %d for exclusion with", lastsp); - LOGF(info, " minTPC nsigmas: el: %.2f, mu: %.2f, pi: %.2f, ka: %.2f, pr: %.2f", last->mMinNSigmasTPC[0], last->mMinNSigmasTPC[1], last->mMinNSigmasTPC[2], last->mMinNSigmasTPC[3], last->mMinNSigmasTPC[4]); - 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 - 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 tpcn : tpcnsigmas) { - debuginfo += TString::Format("%.4f,", tpcn); - } - for (auto 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; - } else { - return false; - } - }; - auto awayFrom = [](auto& values, auto& mindet, auto& maxdet, uint8_t sp) { - for (int ix = 0; ix < 5; ix++) { - if (ix != sp) { - if (mindet[ix] <= values[ix] && values[ix] < maxdet[ix]) { - return false; - } - } else { - continue; - } - } - return true; - }; - auto closeToTPC = [&](auto& config, uint8_t sp) { - return closeTo(tpcnsigmas, config->mMinNSigmasTPC, config->mMaxNSigmasTPC, sp); - }; - auto awayFromTPC = [&](auto& config, uint8_t sp) { - return awayFrom(tpcnsigmas, config->mMinNSigmasTPC, config->mMaxNSigmasTPC, sp); - }; - auto closeToTOF = [&](auto& config, uint8_t sp) { - return closeTo(tofnsigmas, config->mMinNSigmasTOF, config->mMaxNSigmasTOF, sp); - }; - auto closeToTPCTOF = [&](auto& config, uint8_t sp) { - if (config->m2Dcut) { - float a = (config->mMaxNSigmasTPC[sp] - config->mMinNSigmasTPC[sp]) / 2.0; - float b = (config->mMaxNSigmasTOF[sp] - config->mMinNSigmasTOF[sp]) / 2.0; - float oa = (config->mMaxNSigmasTPC[sp] + config->mMinNSigmasTPC[sp]) / 2.0; - float ob = (config->mMaxNSigmasTOF[sp] + config->mMinNSigmasTOF[sp]) / 2.0; - float vtpc = tpcnsigmas[sp] - oa; - float vtof = tofnsigmas[sp] - ob; - return ((vtpc * vtpc / a / a + vtof * vtof / b / b) < 1); - } else { - return closeToTPC(config, sp) && closeToTOF(config, sp); - } - }; - auto awayFromTPCTOF = [&](auto& config, uint8_t sp) { - for (uint8_t ix = 0; ix < 5; ++ix) { - if (ix != sp) { - if (closeToTPCTOF(config, ix)) { - return false; - } - } else { - continue; - } - } - return true; - }; - auto aboveThreshold = [&](auto& config) { - return ((config->mPThreshold > 0.0) && (config->mPThreshold < track.p())); - }; - auto isA = [&](auto& config, uint8_t sp) { - if (track.hasTOF()) { - return closeToTPCTOF(config, sp) && awayFromTPCTOF(config, sp); - } else { - if (aboveThreshold(config)) { - if (config->mRequireTOF) { - return false; - } - } - } - /* we are here */ - /* - below the threshold */ - /* - above the threshold without TOF and without requiring it */ - /* so we check only the TPC information */ - return closeToTPC(config, sp) && awayFromTPC(config, sp); - }; - - auto adjustnsigmas = [&]() { - if (track.sign() > 0) { - for (uint isp = 0; isp < spnames.size(); ++isp) { - if (tpcnsigmasshiftpos[isp] != nullptr) { - TH1* h = tpcnsigmasshiftpos[isp]; - tpcnsigmas[isp] -= h->GetBinContent(h->GetXaxis()->FindFixBin(track.p())); - } - if (tofnsigmasshiftpos[isp] != nullptr) { - TH1* h = tofnsigmasshiftpos[isp]; - tofnsigmas[isp] -= h->GetBinContent(h->GetXaxis()->FindFixBin(track.p())); - } - } - } else { - for (uint isp = 0; isp < spnames.size(); ++isp) { - if (tpcnsigmasshiftneg[isp] != nullptr) { - TH1* h = tpcnsigmasshiftneg[isp]; - tpcnsigmas[isp] -= h->GetBinContent(h->GetXaxis()->FindFixBin(track.p())); - } - if (tofnsigmasshiftneg[isp] != nullptr) { - TH1* h = tofnsigmasshiftneg[isp]; - tofnsigmas[isp] -= h->GetBinContent(h->GetXaxis()->FindFixBin(track.p())); - } - } - } - }; - - 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); - } - } - /* we don't exclude it so check which species if any required */ - if (config.size() > 0) { - int8_t id = -127; - for (uint8_t ix = 0; ix < config.size(); ++ix) { - if (isA(config[ix], species[ix])) { - 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; - } - } - template - int8_t whichTruthSpecies(ParticleObject part) - { - int pdgcode = std::abs(part.pdgCode()); - /* let's first check the exclusion from the analysis */ - for (uint8_t ix = 0; ix < configexclude.size(); ++ix) { - if (pdgcode == pdgcodes[speciesexclude[ix]]) { - return -(ix + 1); - } - } - /* we don't exclude it so check which species if any required */ - 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; - } - } - return -127; - } else { - return 0; - } - } - - template - int8_t whichTruthPrimarySpecies(ParticleObject part) - { - if (part.isPhysicalPrimary()) { - return whichTruthSpecies(part); - } else { - return -127; - } - } - - template - int8_t whichTruthSecondarySpecies(ParticleObject part) - { - if (!(part.isPhysicalPrimary())) { - return whichTruthSpecies(part); - } else { - return -127; - } - } - - template - int8_t whichTruthSecFromDecaySpecies(ParticleObject part) - { - if (!(part.isPhysicalPrimary()) && (part.getProcess() == 4)) { - return whichTruthSpecies(part); - } else { - return -127; - } - } - - template - int8_t whichTruthSecFromMaterialSpecies(ParticleObject part) - { - if (!(part.isPhysicalPrimary()) && (part.getProcess() != 4)) { - return whichTruthSpecies(part); - } else { - return -127; - } - } - - std::vector config; ///< the PID selection configuration of the species to include in the analysis - std::vector species; ///< the species index of the species to include in the analysis - std::vector configexclude; ///< the PID selection configuration of the species to exclude from the analysis - std::vector speciesexclude; ///< the species index of teh species to exclude from the analysis - std::vector tpcnsigmasshiftpos{spnames.size(), nullptr}; - std::vector tpcnsigmasshiftneg{spnames.size(), nullptr}; - std::vector tofnsigmasshiftpos{spnames.size(), nullptr}; - std::vector tofnsigmasshiftneg{spnames.size(), nullptr}; -}; - -} // namespace dptdptfilter -} // namespace analysis -} // namespace o2 - -#endif // PWGCF_TABLEPRODUCER_DPTDPTFILTER_H_ diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index d4353ca9150..0197160a5e1 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -8,50 +8,203 @@ // In applying this license CERN does 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/ASoAHelpers.h" -#include "MathUtils/detail/TypeTruncation.h" +/// \author Jasper Parkkila #include "PWGCF/DataModel/CorrelationsDerived.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/DataModel/PIDResponseITS.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/detail/TypeTruncation.h" + +#include + +#include +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::math_utils::detail; +enum LambdaPid { kLambda = 0, + kAntiLambda +}; + // #define FLOAT_PRECISION 0xFFFFFFF0 #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; 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, int, o2::track::PID::Kaon, "PID of daughter particle 1 (O2 PID ID)") + O2_DEFINE_CONFIGURABLE(cfgImPart2PID, int, o2::track::PID::Kaon, "PID of daughter particle 2 (O2 PID ID)") + O2_DEFINE_CONFIGURABLE(cfgMomDepPID, bool, 1, "Use mommentum dependent PID for Phi meson") + O2_DEFINE_CONFIGURABLE(cfgImCutPt, float, 0.2f, "Minimal pT for candidates") + O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.95f, "Minimum invariant mass for generic 2 prong") + O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass for generic 2 prong") + O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(([p] < 0.5 || [hasTOF] <= 0.0) && abs([sTPC]) < 3.0) || ([p] >= 0.5 && abs([sTPC]) < 2.5 && abs([sTOF]) < 3.0)", "pT dependent daughter track sigma pass condition. Parameters: [p] momentum, [sTPC] sigma TPC, [sTOF] sigma TOF, [hasTOF] has TOF.") + + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(storeLooseTight, bool, false, "Store also loose and tight V0 candidates for systematics"); + O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC"); + O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity"); + O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.15, "Minimum transverse momentum"); + O2_DEFINE_CONFIGURABLE(minV0DCAPr, std::vector, + (std::vector{0.06f, 0.07f, 0.08f}), + "Maximum DCAxy for daughter tracks (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(minV0DCAPiLambda, std::vector, + (std::vector{0.1f, 0.2f, 0.3f}), + "Min V0 pion DCA for lambda (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(minV0DCAPiK0s, std::vector, + (std::vector{0.05f, 0.1f, 0.2f}), + "Min V0 pion DCA for K0s (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(daughPIDCuts, std::vector, + (std::vector{3.0f, 4.0f, 5.0f}), + "PID nsigma for V0s (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(massK0Min, std::vector, + (std::vector{0.4f, 0.4f, 0.4f}), + "Minimum mass for K0 (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(massK0Max, std::vector, + (std::vector{0.6f, 0.6f, 0.6f}), + "Maximum mass for K0 (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(massLambdaMin, std::vector, + (std::vector{1.07f, 1.07f, 1.07f}), + "Minimum mass for lambda (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(massLambdaMax, std::vector, + (std::vector{1.17f, 1.17f, 1.17f}), + "Maximum mass for lambda (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(radiusMaxLambda, std::vector, + (std::vector{20.f, 30.f, 40.f}), + "Maximum decay radius (cm) for lambda (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(radiusMinLambda, std::vector, + (std::vector{1.0f, 1.2f, 1.4f}), + "Minimum decay radius (cm) for lambda (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(radiusMaxK0s, std::vector, + (std::vector{1.0f, 1.2f, 1.4f}), + "Maximum decay radius (cm) for K0s (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(radiusMinK0s, std::vector, + (std::vector{0.0f, 0.0f, 0.1f}), + "Minimum decay radius (cm) for K0s (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(cosPaMinLambda, std::vector, + (std::vector{0.990f, 0.993f, 0.995f}), + "Minimum cosine of pointing angle for lambda (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(cosPaMinK0s, std::vector, + (std::vector{0.990f, 0.993f, 0.995f}), + "Minimum cosine of pointing angle for K0s (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMaxLambda, std::vector, + (std::vector{0.7f, 0.8f, 0.9f}), + "Maximum DCA among the V0 daughters (cm) for lambda (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMaxK0s, std::vector, + (std::vector{0.7f, 0.8f, 0.9f}), + "Maximum DCA among the V0 daughters (cm) for K0s (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0s, std::vector, + (std::vector{0.2f, 0.2f, 0.2f}), + "Minimum Armenteros' qt for K0s (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(maxLambdaLifeTime, std::vector, + (std::vector{40.f, 30.f, 25.f}), + "Maximum lambda lifetime (in cm) (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(maxK0sLifeTime, std::vector, + (std::vector{40.f, 30.f, 25.f}), + "Maximum K0s lifetime (in cm) (Loose, Default, Tight)"); + + } grpV0; + + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(storeLooseTightforphi, bool, true, "Store also loose and tight phi candidates for systematics"); + O2_DEFINE_CONFIGURABLE(ImMinInvMassPhiMeson, float, 0.98f, "Minimum invariant mass Phi meson (GeV)"); + O2_DEFINE_CONFIGURABLE(ImMaxInvMassPhiMeson, float, 1.07f, "Maximum invariant mass Phi meson (GeV)"); + O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS"); + O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)"); + O2_DEFINE_CONFIGURABLE(lowITSPIDNsigma, float, 3.0, "lower cut on PID nsigma for ITS"); + O2_DEFINE_CONFIGURABLE(highITSPIDNsigma, float, 3.0, "higher cut on PID nsigma for ITS"); + O2_DEFINE_CONFIGURABLE(ITSclusterPhiMeson, int, 5, "Minimum number of ITS cluster for phi meson track"); + O2_DEFINE_CONFIGURABLE(TPCCrossedRowsPhiMeson, std::vector, (std::vector{70, 80, 90}), "Minimum number of TPC Crossed Rows for phi meson track (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(cutDCAxyPhiMeson, std::vector, (std::vector{0.12, 0.1, 0.08}), "Maximum DCAxy for phi meson tracks (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(cutDCAzPhiMeson, std::vector, (std::vector{0.12, 0.1, 0.08}), "Maximum DCAz for phi meson tracks (Loose, Default, Tight)"); + O2_DEFINE_CONFIGURABLE(cutEtaPhiMeson, float, 0.8, "Maximum eta for phi meson track"); + O2_DEFINE_CONFIGURABLE(cutPTPhiMeson, float, 0.15, "Maximum pt for phi meson track"); + O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "Flag for applying deep angle"); + O2_DEFINE_CONFIGURABLE(deepAngle, float, 0.04, "Deep angle cut"); + O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 2.5, "nsigma tpc"); + O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 2.5, "nsigma tof"); + O2_DEFINE_CONFIGURABLE(cutTOFBeta, float, 0.5, "TOF beta"); + O2_DEFINE_CONFIGURABLE(confFakeKaonCut, float, 0.15, "Cut based on track from momentum difference"); + O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "Flag to remove fake kaon"); + O2_DEFINE_CONFIGURABLE(applyTOF, bool, false, "Flag for applying TOF"); + } grpPhi; 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; + using HFCandidatesMCRecoML = soa::Join; + + template + using HasMLProb = decltype(std::declval().mlProbD0()); + template + using HasFlagMcMatchRec = decltype(std::declval().flagMcMatchRec()); + + using PIDTrack = soa::Join; + using ResoV0s = aod::V0Datas; + + std::unique_ptr sigmaFormula; + std::array sigmaFormulaParamIndex; + + void init(InitContext&) + { + if (doprocessDataInvMass) { + sigmaFormula = std::make_unique("sigmaFormula", cfgImSigmaFormula.value.c_str()); + if (static_cast(sigmaFormula->GetNpar()) > std::size(sigmaFormulaParamIndex)) + LOGF(fatal, "Number of parameters in cfgImSigmaFormula can not be larger than %d.", std::size(sigmaFormulaParamIndex)); + // could do SetParameter(name,value) directly, but pre-lookup of the names will result in faster process + std::array pars = {"p", "sTPC", "sTOF", "hasTOF"}; + std::fill_n(sigmaFormulaParamIndex.begin(), std::size(sigmaFormulaParamIndex), ~0u); + for (uint i = 0, n = sigmaFormula->GetNpar(); i < n; ++i) { + auto m = std::find(pars.begin(), pars.end(), sigmaFormula->GetParName(i)); + if (m != pars.end()) + sigmaFormulaParamIndex[std::distance(pars.begin(), m)] = i; + else + LOGF(warning, "Unrecognized cfgImSigmaFormula parameter %s.", sigmaFormula->GetParName(i)); + } + } + } + + 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 if (cfgVerbosity > 0 && candidates.size() > 0) LOGF(info, "Candidates for collision: %lu, cfcollisions: %lu, CFTracks: %lu", candidates.size(), cfcollisions.size(), cftracks.size()); - for (auto& c : candidates) { + for (const auto& c : candidates) { int prongCFId[2] = {-1, -1}; - for (auto& cftrack : cftracks) { + for (const auto& cftrack : cftracks) { if (c.prong0Id() == cftrack.trackId()) { prongCFId[0] = cftrack.globalIndex(); break; } } - for (auto& cftrack : cftracks) { + for (const auto& cftrack : cftracks) { if (c.prong1Id() == cftrack.trackId()) { prongCFId[1] = cftrack.globalIndex(); break; @@ -62,15 +215,667 @@ struct Filter2Prong { continue; if (cfgYMax >= 0.0f && std::abs(hfHelper.yD0(c)) > cfgYMax) continue; - if (c.isSelD0() > 0) + if constexpr (std::experimental::is_detected::value) { + if (std::abs(c.flagMcMatchRec()) != o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) + continue; + } + + 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 (const float val : c.mlProbD0()) + mlvecd.push_back(val); + mlvecdbar.clear(); + for (const 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 (const float val : c.mlProbD0()) + mlvecd.push_back(val); + mlvecdbar.clear(); + for (const 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 processMCRecoML(aod::Collisions::iterator const& col, aod::BCsWithTimestamps const& bcs, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, HFCandidatesMCRecoML const& candidates) + { + processDataT(col, bcs, cfcollisions, cftracks, candidates); + } + PROCESS_SWITCH(Filter2Prong, processMCRecoML, "Process data D0 candidates together with reco information and ML", false); + + using HFMCTrack = soa::Join; + void processMC(aod::McCollisions::iterator const&, aod::CFMcParticleRefs const& cfmcparticles, [[maybe_unused]] HFMCTrack 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 (const auto& r : cfmcparticles) { + const auto& mcParticle = r.mcParticle_as(); + if ((std::abs(mcParticle.flagMcMatchGen()) != o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || mcParticle.daughtersIds().size() != 2) { + output2ProngMcParts(-1, -1, aod::cf2prongtrack::Generic2Prong); + continue; + } + int prongCFId[2] = {-1, -1}; + for (uint i = 0; i < 2; ++i) { + for (const auto& cfmcpart : cfmcparticles) { + if (mcParticle.daughtersIds()[i] == cfmcpart.mcParticleId()) { + prongCFId[i] = cfmcpart.globalIndex(); + break; + } + } + } + output2ProngMcParts(prongCFId[0], prongCFId[1], + (mcParticle.pdgCode() >= 0 ? aod::cf2prongtrack::D0ToPiK : aod::cf2prongtrack::D0barToKPi) | ((mcParticle.originMcGen() == RecoDecay::OriginType::Prompt) ? aod::cf2prongmcpart::Prompt : 0)); + } + } + PROCESS_SWITCH(Filter2Prong, processMC, "Process MC 2-prong daughters", false); + + void processMCGeneric(aod::McCollisions::iterator const&, aod::CFMcParticleRefs const& cfmcparticles, [[maybe_unused]] 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 (const auto& r : cfmcparticles) { + const auto& mcParticle = r.mcParticle(); + if (mcParticle.daughtersIds().size() != 2) { + output2ProngMcParts(-1, -1, aod::cf2prongtrack::Generic2Prong); // not a 2-prong + continue; + } + int prongCFId[2] = {-1, -1}; + for (uint i = 0; i < 2; ++i) { + for (const auto& cfmcpart : cfmcparticles) { + if (mcParticle.daughtersIds()[i] == cfmcpart.mcParticleId()) { + prongCFId[i] = cfmcpart.globalIndex(); + break; + } + } + } + output2ProngMcParts(prongCFId[0], prongCFId[1], aod::cf2prongtrack::Generic2Prong); // the 2-prong Phi, for example, can be checked through its daughters + } + } + PROCESS_SWITCH(Filter2Prong, processMCGeneric, "Process generic MC 2-prong daughters", false); + + template + bool selectionTrack(const T& candidate) + { + if (candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() >= grpPhi.ITSclusterPhiMeson && std::abs(candidate.eta()) <= grpPhi.cutEtaPhiMeson && candidate.pt() >= grpPhi.cutPTPhiMeson) { + return true; + } + return false; + } + + template + bool selectionSys(const T& candidate, bool isLoose, bool isTight) + { + const int indexCut = isLoose ? 0 : (isTight ? 2 : 1); + + if (std::abs(candidate.dcaXY()) <= grpPhi.cutDCAxyPhiMeson.value[indexCut] && std::abs(candidate.dcaZ()) <= grpPhi.cutDCAzPhiMeson.value[indexCut] && candidate.tpcNClsCrossedRows() > grpPhi.TPCCrossedRowsPhiMeson.value[indexCut]) { + return true; + } + return false; + } + + 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 (grpPhi.isDeepAngle && angle < grpPhi.deepAngle) { + return false; + } + return true; + } + + template + bool isFakeTrack(T const& track) + { + const auto pglobal = track.p(); + const auto ptpc = track.tpcInnerParam(); + if (TMath::Abs(pglobal - ptpc) > grpPhi.confFakeKaonCut) { + return true; + } + return false; + } + + template + bool isSelectedV0AsK0s(Collision const& collision, const V0Cand& v0, bool isLoose, bool isTight) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + const int indexCut = isLoose ? 0 : (isTight ? 2 : 1); + + float CtauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0; + + if (v0.mK0Short() < grpV0.massK0Min.value[indexCut] || v0.mK0Short() > grpV0.massK0Max.value[indexCut]) { + return false; + } + if ((v0.qtarm() / std::abs(v0.alpha())) < grpV0.qtArmenterosMinForK0s.value[indexCut]) { + return false; + } + if (v0.v0radius() > grpV0.radiusMaxK0s.value[indexCut] || v0.v0radius() < grpV0.radiusMinK0s.value[indexCut]) { + return false; + } + if (v0.v0cosPA() < grpV0.cosPaMinK0s.value[indexCut]) { + return false; + } + if (v0.dcaV0daughters() > grpV0.dcaV0DaughtersMaxK0s.value[indexCut]) { + return false; + } + if (std::abs(CtauK0s) > grpV0.maxK0sLifeTime.value[indexCut]) { + return false; + } + if (((std::abs(posTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts.value[indexCut]) || (std::abs(negTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts.value[indexCut]))) { + return false; + } + if ((TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPiK0s.value[indexCut]) || (TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPiK0s.value[indexCut])) { + return false; + } + return true; + } + + template + bool isSelectedV0AsLambda(Collision const& collision, const V0Cand& v0, bool isLoose, bool isTight) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + const int indexCut = isLoose ? 0 : (isTight ? 2 : 1); + + float CtauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda; + + if ((v0.mLambda() < grpV0.massLambdaMin.value[indexCut] || v0.mLambda() > grpV0.massLambdaMax.value[indexCut]) && + (v0.mAntiLambda() < grpV0.massLambdaMin.value[indexCut] || v0.mAntiLambda() > grpV0.massLambdaMax.value[indexCut])) { + return false; + } + if (v0.v0radius() > grpV0.radiusMaxLambda.value[indexCut] || v0.v0radius() < grpV0.radiusMinLambda.value[indexCut]) { + return false; + } + if (v0.v0cosPA() < grpV0.cosPaMinLambda.value[indexCut]) { + return false; + } + if (v0.dcaV0daughters() > grpV0.dcaV0DaughtersMaxLambda.value[indexCut]) { + return false; + } + if (pid == LambdaPid::kLambda && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPr.value[indexCut] || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPiLambda.value[indexCut])) { + return false; + } + if (pid == LambdaPid::kAntiLambda && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPiLambda.value[indexCut] || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPr.value[indexCut])) { + return false; + } + if (pid == LambdaPid::kLambda && ((std::abs(posTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts.value[indexCut]) || (std::abs(negTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts.value[indexCut]))) { + return false; + } + if (pid == LambdaPid::kAntiLambda && ((std::abs(posTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts.value[indexCut]) || (std::abs(negTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts.value[indexCut]))) { + return false; + } + if (std::abs(CtauLambda) > grpV0.maxLambdaLifeTime.value[indexCut]) { + return false; + } + return true; + } + + template + bool isV0TrackSelected(const T1& v0) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + if (!posTrack.hasTPC() || !negTrack.hasTPC()) { + return false; + } + if (posTrack.tpcNClsCrossedRows() < grpV0.tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < grpV0.tpcNClsCrossedRowsTrackMin) { + return false; + } + if (posTrack.tpcCrossedRowsOverFindableCls() < 0.8 || negTrack.tpcCrossedRowsOverFindableCls() < 0.8) { + return false; + } + if (std::abs(v0.positiveeta()) > grpV0.etaTrackMax || std::abs(v0.negativeeta()) > grpV0.etaTrackMax) { + return false; + } + if (v0.positivept() < grpV0.ptTrackMin || v0.negativept() < grpV0.ptTrackMin) { + return false; + } + return true; + } + + template + bool selectionPID(const T& candidate) + { + if (cfgMomDepPID) { + if (candidate.p() < 0.5) { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpPhi.nsigmaCutTPC) { + return true; + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpPhi.nsigmaCutTOF && candidate.beta() > grpPhi.cutTOFBeta) { + return true; + } + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpPhi.nsigmaCutTOF && candidate.beta() > grpPhi.cutTOFBeta) { + return true; + } + } else { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpPhi.nsigmaCutTPC) { + return true; + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpPhi.nsigmaCutTOF && candidate.beta() > grpPhi.cutTOFBeta) { + return true; + } + } + return false; + } + + template + bool selectionPID2(const T& candidate) + { + double nsigmaTPC = candidate.tpcNSigmaKa(); + double nsigmaTOF = candidate.tofNSigmaKa(); + + if (grpPhi.applyTOF) { + if (!candidate.hasTOF() && TMath::Abs(nsigmaTPC) < grpPhi.nsigmaCutTPC) { + return true; + } + if (candidate.p() > 0.5 && candidate.hasTOF() && TMath::Abs(nsigmaTPC) < grpPhi.nsigmaCutTPC) { + if (candidate.p() > 0.5 && candidate.p() < 1.6 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -5.0 && nsigmaTOF < 10.0) { + return true; + } + if (candidate.p() >= 1.6 && candidate.p() < 2.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 10.0) { + return true; + } + if (candidate.p() >= 2.0 && candidate.p() < 2.5 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 6.0) { + return true; + } + if (candidate.p() >= 2.5 && candidate.p() < 4.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -2.5 && nsigmaTOF < 4.0) { + return true; + } + if (candidate.p() >= 4.0 && candidate.p() < 5.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -4.0 && nsigmaTOF < 3.0) { + return true; + } + if (candidate.p() >= 5.0 && candidate.p() < 6.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -4.0 && nsigmaTOF < 2.5) { + return true; + } + if (candidate.p() >= 6.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 3.0) { + return true; + } + } + } else if (TMath::Abs(nsigmaTPC) < grpPhi.nsigmaCutTPC) { + return true; + } + return false; + } + + template + bool selectionPID3(const T& candidate) + { + double nsigmaTPC = candidate.tpcNSigmaKa(); + double nsigmaTOF = candidate.tofNSigmaKa(); + if (candidate.p() < 0.7 && TMath::Abs(nsigmaTPC) < grpPhi.nsigmaCutTPC) { + return true; + } + if (candidate.p() > 0.7 && candidate.hasTOF() && TMath::Abs(nsigmaTPC) < grpPhi.nsigmaCutTPC) { + if (candidate.p() > 0.7 && candidate.p() < 1.6 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -5.0 && nsigmaTOF < 10.0) { + return true; + } + if (candidate.p() >= 1.6 && candidate.p() < 2.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 10.0) { + return true; + } + if (candidate.p() >= 2.0 && candidate.p() < 2.5 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 6.0) { + return true; + } + if (candidate.p() >= 2.5 && candidate.p() < 4.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -2.5 && nsigmaTOF < 4.0) { + return true; + } + if (candidate.p() >= 4.0 && candidate.p() < 5.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -4.0 && nsigmaTOF < 3.0) { + return true; + } + if (candidate.p() >= 5.0 && candidate.p() < 6.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -4.0 && nsigmaTOF < 2.5) { + return true; + } + if (candidate.p() >= 6.0 && candidate.beta() > grpPhi.cutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 3.0) { + return true; + } + } + return false; + } + + // Generic 2-prong invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + void processDataInvMass(aod::Collisions::iterator const&, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks) + { + if (cfcollisions.size() <= 0 || cftracks.size() <= 0) + return; // rejected collision + for (const auto& cftrack1 : cftracks) { + const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); + if (p1.sign() != 1) + continue; + sigmaFormula->SetParameter(sigmaFormulaParamIndex[0], p1.p()); + sigmaFormula->SetParameter(sigmaFormulaParamIndex[1], o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p1)); + sigmaFormula->SetParameter(sigmaFormulaParamIndex[2], o2::aod::pidutils::tofNSigma(cfgImPart1PID, p1)); + sigmaFormula->SetParameter(sigmaFormulaParamIndex[3], static_cast(p1.hasTOF())); + if (sigmaFormula->Eval() <= 0.0f) + continue; + for (const auto& cftrack2 : cftracks) { + if (cftrack2.globalIndex() == cftrack1.globalIndex()) + continue; + const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); + if (p2.sign() != -1) + continue; + sigmaFormula->SetParameter(sigmaFormulaParamIndex[0], p2.p()); + sigmaFormula->SetParameter(sigmaFormulaParamIndex[1], o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p2)); + sigmaFormula->SetParameter(sigmaFormulaParamIndex[2], o2::aod::pidutils::tofNSigma(cfgImPart1PID, p2)); + sigmaFormula->SetParameter(sigmaFormulaParamIndex[3], static_cast(p2.hasTOF())); + if (sigmaFormula->Eval() <= 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); + + // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + void processDataPhiV0(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks, aod::V0Datas const& V0s) + { + if (cfcollisions.size() <= 0) + return; // rejected collision + + // V0 + for (const auto& v0 : V0s) { // Loop over V0 candidates + if (!isV0TrackSelected(v0)) { // Quality selection for V0 prongs + continue; + } + + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + double massV0 = 0.0; + + // K0s + if (isSelectedV0AsK0s(collision, v0, false, false)) { // candidate is K0s + output2ProngTracks(cfcollisions.begin().globalIndex(), + posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::cf2prongtrack::K0stoPiPi); + } + if (grpV0.storeLooseTight) // store also loose and tight K0s + { + if (isSelectedV0AsK0s(collision, v0, true, false)) { // candidate is loose K0s + output2ProngTracks(cfcollisions.begin().globalIndex(), + posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::cf2prongtrack::K0stoPiPiLoose); + } + if (isSelectedV0AsK0s(collision, v0, false, true)) { // candidate is tight K0s + output2ProngTracks(cfcollisions.begin().globalIndex(), + posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::cf2prongtrack::K0stoPiPiTight); + } + } + + // Lambda and Anti-Lambda + bool LambdaTag = isSelectedV0AsLambda(collision, v0, false, false); + bool aLambdaTag = isSelectedV0AsLambda(collision, v0, false, false); + + // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) + if (LambdaTag) { // candidate is Lambda + massV0 = v0.mLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::LambdatoPPi); + } + if (aLambdaTag) { // candidate is Anti-lambda + massV0 = v0.mAntiLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::AntiLambdatoPiP); + } + if (grpV0.storeLooseTight) { // store also loose and tight Lambdas + bool LambdaLooseTag = isSelectedV0AsLambda(collision, v0, true, false); + bool aLambdaLooseTag = isSelectedV0AsLambda(collision, v0, true, false); + bool LambdaTightTag = isSelectedV0AsLambda(collision, v0, false, true); + bool aLambdaTightTag = isSelectedV0AsLambda(collision, v0, false, true); + + if (LambdaLooseTag) { // candidate is loose Lambda + massV0 = v0.mLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::LambdaToPPiLoose); + } + if (LambdaTightTag) { // candidate is tight Lambda + massV0 = v0.mLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::LambdaToPPiTight); + } + if (aLambdaLooseTag) { // candidate is loose Anti-lambda + massV0 = v0.mAntiLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::AntiLambdaToPiPLoose); + } + if (aLambdaTightTag) { // candidate is tight Anti-lambda + massV0 = v0.mAntiLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::AntiLambdaToPiPTight); + } + } // end of Lambda and Anti-Lambda processing + } // end of loop over V0 candidates + + // Phi + if (cftracks.size() <= 0) + return; // rejected collision + + o2::aod::ITSResponse itsResponse; + + for (const auto& cftrack1 : cftracks) { // Loop over first track + const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); + if (p1.sign() != 1) { + continue; + } + if (!selectionTrack(p1)) { + continue; + } + if (grpPhi.ITSPIDSelection && p1.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition + continue; + } + /*if (!selectionPID(p1)) { + continue; + }*/ + if (grpPhi.removefaketrack && isFakeTrack(p1)) { // Check if the track is a fake kaon + continue; + } + + for (const auto& cftrack2 : cftracks) { // Loop over second track + if (cftrack2.globalIndex() == cftrack1.globalIndex()) // Skip if it's the same track as the first one + continue; + + const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); + if (p2.sign() != -1) { + continue; + } + if (!selectionTrack(p2)) { + continue; + } + /*if (!selectionPID(p2)) { + continue; + }*/ + if (grpPhi.ITSPIDSelection && p2.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition + continue; + } + if (grpPhi.removefaketrack && isFakeTrack(p2)) { // Check if the track is a fake kaon + continue; + } + if (!selectionPair(p1, p2)) { + 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.M() < grpPhi.ImMinInvMassPhiMeson || s.M() > grpPhi.ImMaxInvMassPhiMeson) { + continue; + } + float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); + if (selectionPID(p1) && selectionPID(p2)) { + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKKPID1); + } + if (selectionPID2(p1) && selectionPID2(p2)) { + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKKPID2); + } + if (selectionPID3(p1) && selectionPID3(p2)) { + if (selectionSys(p1, false, false) && selectionSys(p2, false, false)) // default + { + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKKPID3); + } + if (grpPhi.storeLooseTightforphi) // store also loose and tight K0s + { + if (selectionSys(p1, true, false) && selectionSys(p2, true, false)) // loose + { + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKKPID3Loose); + } + if (selectionSys(p1, false, true) && selectionSys(p2, false, true)) // tight + { + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKKPID3Tight); + } + } + } + } // end of loop over second track + } // end of loop over first track + } + PROCESS_SWITCH(Filter2Prong, processDataPhiV0, "Process data Phi and V0 candidates with invariant mass method", false); + + // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + void processDataV0(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const&, aod::V0Datas const& V0s) + { + if (cfcollisions.size() <= 0 || cftracks.size() <= 0) + return; // rejected collision + + for (const auto& v0 : V0s) { // Loop over V0 candidates + if (!isV0TrackSelected(v0)) { // Quality selection for V0 prongs + continue; + } + + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + double massV0 = 0.0; + + // K0s + if (isSelectedV0AsK0s(collision, v0, false, false)) { // candidate is K0s + output2ProngTracks(cfcollisions.begin().globalIndex(), + posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::cf2prongtrack::K0stoPiPi); + } + + // Lambda and Anti-Lambda + bool LambdaTag = isSelectedV0AsLambda(collision, v0, false, false); + bool aLambdaTag = isSelectedV0AsLambda(collision, v0, false, false); + + // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) + if (LambdaTag) { // candidate is Lambda + massV0 = v0.mLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::LambdatoPPi); + } + if (aLambdaTag) { // candidate is Anti-lambda + massV0 = v0.mAntiLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::AntiLambdatoPiP); + } // end of Lambda and Anti-Lambda processing + } // end of loop over V0 candidates + } + PROCESS_SWITCH(Filter2Prong, processDataV0, "Process data V0 candidates with invariant mass method", false); + + // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + void processDataPhi(aod::Collisions::iterator const&, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks) + { + if (cfcollisions.size() <= 0 || cftracks.size() <= 0) + return; // rejected collision + + o2::aod::ITSResponse itsResponse; + + for (const auto& cftrack1 : cftracks) { // Loop over first track + const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); + if (p1.sign() != 1) { + continue; + } + if (!selectionTrack(p1)) { + continue; + } + if (grpPhi.ITSPIDSelection && p1.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition + continue; + } + if (!selectionPID(p1)) { + continue; + } + if (grpPhi.removefaketrack && isFakeTrack(p1)) { // Check if the track is a fake kaon + continue; + } + + for (const auto& cftrack2 : cftracks) { // Loop over second track + if (cftrack2.globalIndex() == cftrack1.globalIndex()) // Skip if it's the same track as the first one + continue; + + const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); + if (p2.sign() != -1) { + continue; + } + if (!selectionTrack(p2)) { + continue; + } + if (!selectionPID(p2)) { + continue; + } + if (grpPhi.ITSPIDSelection && p2.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition + continue; + } + if (grpPhi.removefaketrack && isFakeTrack(p2)) { // Check if the track is a fake kaon + continue; + } + if (!selectionPair(p1, p2)) { + 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.M() < grpPhi.ImMinInvMassPhiMeson || s.M() > grpPhi.ImMaxInvMassPhiMeson) { + 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::PhiToKKPID1); + } // end of loop over second track + } // end of loop over first track + } + PROCESS_SWITCH(Filter2Prong, processDataPhi, "Process data Phi 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 9cbde25a20c..0c44d086a3f 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -8,21 +8,26 @@ // In applying this license CERN does 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/ASoAHelpers.h" -#include "Framework/O2DatabasePDGPlugin.h" - -#include "MathUtils/detail/TypeTruncation.h" - #include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Centrality.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/detail/TypeTruncation.h" #include -#include + +#include // required for is_detected +#include using namespace o2; using namespace o2::framework; @@ -46,10 +51,17 @@ using CFMultiplicity = CFMultiplicities::iterator; struct FilterCF { Service pdg; - enum TrackSelectionCuts : uint8_t { + enum TrackSelectionCuts1 : uint8_t { kTrackSelected = BIT(0), kITS5Clusters = BIT(1), - kTPC90CrossedRows = BIT(2) + kTPCCrossedRows = BIT(2), + kTPCClusters = BIT(3), + kchi2perTPC = BIT(4), + kchi2perITS = BIT(5), + }; + + enum TrackSelectionCuts2 : uint8_t { + kPIDProton = BIT(1) }; // Configuration @@ -59,10 +71,26 @@ 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, 9 = sel8 + kNoSameBunchPileup + kIsGoodZvtxFT0vsPV, 10 = sel8 before April, 2024, 11 = sel8 for MC, 12 = sel8 with low occupancy cut)") + 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, 13 = sel8 + kNoSameBunchPileup + kIsGoodITSLayersAll -- for OO/NeNe) ") + 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(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics)") + 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 | 2 = Run 3 with proton pid selection)") + 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 + O2_DEFINE_CONFIGURABLE(nsigmaCutTPCProton, float, 3, "proton nsigma TPC") + O2_DEFINE_CONFIGURABLE(nsigmaCutTOFProton, float, 3, "proton nsigma TOF") + O2_DEFINE_CONFIGURABLE(ITSProtonselection, bool, false, "flag for ITS proton nsigma selection") + O2_DEFINE_CONFIGURABLE(nsigmaCutITSProton, float, 3, "proton nsigma ITS") + O2_DEFINE_CONFIGURABLE(dcaxymax, float, 999.f, "maximum dcaxy of tracks") + O2_DEFINE_CONFIGURABLE(dcazmax, float, 999.f, "maximum dcaz of tracks") + O2_DEFINE_CONFIGURABLE(itsnclusters, int, 5, "minimum number of ITS clusters for tracks") + O2_DEFINE_CONFIGURABLE(tpcncrossedrows, int, 80, "minimum number of TPC crossed rows for tracks") + O2_DEFINE_CONFIGURABLE(tpcnclusters, int, 50, "minimum number of TPC clusters found") + O2_DEFINE_CONFIGURABLE(chi2pertpccluster, float, 2.5, "maximum Chi2 / cluster for the TPC track segment") + O2_DEFINE_CONFIGURABLE(chi2peritscluster, float, 36, "maximum Chi2 / cluster for the ITS track segment") + O2_DEFINE_CONFIGURABLE(cfgEstimatorBitMask, uint16_t, 0, "BitMask for multiplicity estimators to be included in the CFMultSet tables."); // Filters and input definitions Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; @@ -88,34 +116,89 @@ struct FilterCF { Produces outputCollRefs; Produces outputTrackRefs; + Produces outputMcParticleRefs; + + Produces outputMultSets; + std::vector multiplicities{}; + + // 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 collision.sel8() && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV); + 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 collision.selection_bit(aod::evsel::kIsTriggerTVX); + return isMultSelected && collision.selection_bit(aod::evsel::kIsTriggerTVX); } else if (cfgTrigger == 11) { // sel8 selection for MC - return collision.selection_bit(aod::evsel::kIsTriggerTVX) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + 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 >= 0 && occupancy < 500) - return collision.sel8() && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kNoCollInTimeRangeStandard); + 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; + } else if (cfgTrigger == 13) { // relevant for OO/NeNe + return isMultSelected && collision.sel8() && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodITSLayersAll); } return false; } - template - uint8_t getTrackType(TTrack& track) + using TrackType = soa::Filtered>; + + template + bool selectionPIDProton(const T& candidate) + { + o2::aod::ITSResponse itsResponse; + + if (ITSProtonselection && candidate.pt() <= 0.6 && !(itsResponse.nSigmaITS(candidate) > nsigmaCutITSProton)) { + return false; + } + if (ITSProtonselection && candidate.pt() > 0.6 && candidate.pt() <= 0.8 && !(itsResponse.nSigmaITS(candidate) > nsigmaCutITSProton)) { + return false; + } + + if (candidate.hasTOF()) { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton) { + return true; + } + if (candidate.p() >= 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOFProton) { + return true; + } + } else { + if (std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton) { + return true; + } + } + return false; + } + + template + struct HasProtonPID : std::false_type { + }; + + template + struct HasProtonPID().tpcNSigmaPr()), + decltype(std::declval().tofNSigmaPr()), + decltype(std::declval().hasTOF())>> + : std::true_type { + }; + + template + uint8_t getTrackType(const TTrack& track) { if (cfgTrackSelection == 0) { if (track.isGlobalTrack()) { @@ -128,20 +211,45 @@ struct FilterCF { uint8_t trackType = 0; if (track.isGlobalTrack()) { trackType |= kTrackSelected; - if (track.itsNCls() >= 5) { + if (track.itsNCls() >= itsnclusters) { trackType |= kITS5Clusters; } - if (track.tpcNClsCrossedRows() >= 90) { - trackType |= kTPC90CrossedRows; + if (track.tpcNClsCrossedRows() >= tpcncrossedrows) { + trackType |= kTPCCrossedRows; + } + if (track.tpcNClsFound() >= tpcnclusters) { + trackType |= kTPCClusters; + } + if (track.tpcChi2NCl() <= chi2pertpccluster) { + trackType |= kchi2perTPC; + } + if (track.itsChi2NCl() <= chi2peritscluster) { + trackType |= kchi2perITS; + } + } + return trackType; + } else if (cfgTrackSelection == 2) { + uint8_t trackType = 0; + if constexpr (HasProtonPID::value) { + if (track.isGlobalTrack() && (track.itsNCls() >= itsnclusters) && (track.tpcNClsCrossedRows() >= tpcncrossedrows) && selectionPIDProton(track)) { + trackType |= kPIDProton; } } 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) + template + using HasMultTables = decltype(std::declval().multNTracksPV()); + + /// \brief Templetized process data for a given collision and its associated tracks + /// \param collision The collision object containing information about the collision + /// \param tracks The collection of tracks associated with the collision + template + void processDataT(const C1& collision, const T1& 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()); @@ -151,13 +259,29 @@ struct FilterCF { return; } - auto bc = collision.bc_as(); + auto bc = collision.template bc_as(); outputCollisions(bc.runNumber(), collision.posZ(), collision.multiplicity(), bc.timestamp()); + if constexpr (std::experimental::is_detected::value) { + multiplicities.clear(); + if (cfgEstimatorBitMask & aod::cfmultset::CentFT0C) + multiplicities.push_back(collision.centFT0C()); + if (cfgEstimatorBitMask & aod::cfmultset::MultFV0A) + multiplicities.push_back(collision.multFV0A()); + if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksPV) + multiplicities.push_back(collision.multNTracksPV()); + if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksGlobal) + multiplicities.push_back(collision.multNTracksGlobal()); + outputMultSets(multiplicities); + } + if (cfgTransientTables) outputCollRefs(collision.globalIndex()); - for (auto& track : tracks) { + if ((std::abs(track.dcaXY()) > dcaxymax) || (std::abs(track.dcaZ()) > dcazmax)) { + continue; + } + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track)); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); @@ -166,21 +290,45 @@ struct FilterCF { etaphi->Fill(collision.multiplicity(), track.eta(), track.phi()); } } + + void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + { + processDataT(collision, tracks); + } PROCESS_SWITCH(FilterCF, processData, "Process data", true); - // NOTE not filtering collisions here because in that case there can be tracks referring to MC particles which are not part of the selected MC collisions - Preslice perMcCollision = aod::mcparticle::mcCollisionId; - Preslice perCollision = aod::track::collisionId; - void processMC(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, - soa::Join const& allCollisions, - soa::Filtered> const& tracks, - aod::BCsWithTimestamps const&) + void processDataPid(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + { + processDataT(collision, tracks); + } + PROCESS_SWITCH(FilterCF, processDataPid, "Process data with PID", false); + + void processDataMults(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + { + processDataT(collision, tracks); + } + PROCESS_SWITCH(FilterCF, processDataMults, "Process data with multiplicity sets", false); + + /// \brief Process MC data for a given set of MC collisions and associated particles and tracks + /// \param mcCollisions The collection of MC collisions + /// \param allParticles The collection of all MC particles + /// \param allCollisions The collection of all collisions, joined with MC collision labels and + /// event selections + /// \param tracks The collection of tracks, filtered by selection criteria + /// \param bcs The collection of bunch crossings with timestamps + template + void processMCT(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, + C1 const& allCollisions, + T1 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 @@ -196,7 +344,7 @@ struct FilterCF { for (auto& track : groupedTracks) { if (track.has_mcParticle()) { - reconstructed[track.mcParticleId()] = true; + mcReconstructedCache[track.mcParticleId()] = true; } } } @@ -216,25 +364,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); @@ -251,33 +403,78 @@ struct FilterCF { continue; } - auto bc = collision.bc_as(); + auto bc = collision.template bc_as(); // 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 constexpr (std::experimental::is_detected::value) { + multiplicities.clear(); + if (cfgEstimatorBitMask & aod::cfmultset::CentFT0C) + multiplicities.push_back(collision.centFT0C()); + if (cfgEstimatorBitMask & aod::cfmultset::MultFV0A) + multiplicities.push_back(collision.multFV0A()); + if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksPV) + multiplicities.push_back(collision.multNTracksPV()); + if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksGlobal) + multiplicities.push_back(collision.multNTracksGlobal()); + outputMultSets(multiplicities); + } + + if (cfgTransientTables) + outputCollRefs(collision.globalIndex()); + for (auto& track : groupedTracks) { 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(), getTrackType(track)); + outputTracks(outputCollisions.lastIndex(), 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; + // NOTE not filtering collisions here because in that case there can be tracks referring to MC particles which are not part of the selected MC collisions + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + Preslice perCollision = aod::track::collisionId; + void processMC(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, + soa::Join const& allCollisions, + soa::Filtered> const& tracks, + aod::BCsWithTimestamps const& bcs) + { + processMCT(mcCollisions, allParticles, allCollisions, tracks, bcs); } PROCESS_SWITCH(FilterCF, processMC, "Process MC", false); + // NOTE not filtering collisions here because in that case there can be tracks referring to MC particles which are not part of the selected MC collisions + void processMCPid(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, + soa::Join const& allCollisions, + soa::Filtered> const& tracks, + aod::BCsWithTimestamps const& bcs) + { + processMCT(mcCollisions, allParticles, allCollisions, tracks, bcs); + } + PROCESS_SWITCH(FilterCF, processMCPid, "Process MC with PID", false); + + void processMCMults(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, + soa::Join const& allCollisions, + soa::Filtered> const& tracks, + aod::BCsWithTimestamps const& bcs) + { + processMCT(mcCollisions, allParticles, allCollisions, tracks, bcs); + } + + PROCESS_SWITCH(FilterCF, processMCMults, "Process MC with multiplicity sets", false); + void processMCGen(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& particles) { float multiplicity = 0.0f; @@ -322,9 +519,15 @@ struct MultiplicitySelector { if (doprocessFT0C) { enabledFunctions++; } + if (doprocessFT0CVariant1) { + enabledFunctions++; + } if (doprocessFT0A) { enabledFunctions++; } + if (doprocessCentNGlobal) { + enabledFunctions++; + } if (doprocessMCGen) { enabledFunctions++; } @@ -356,6 +559,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) { @@ -364,6 +575,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) { diff --git a/PWGCF/Tasks/CMakeLists.txt b/PWGCF/Tasks/CMakeLists.txt index fdc35cf2ef6..22e2b0f9f21 100644 --- a/PWGCF/Tasks/CMakeLists.txt +++ b/PWGCF/Tasks/CMakeLists.txt @@ -9,18 +9,18 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -o2physics_add_dpl_workflow(dptdptcorrelations - SOURCES dptdptcorrelations.cxx +o2physics_add_dpl_workflow(dpt-dpt-correlations + SOURCES dptDptCorrelations.cxx 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 a83558740e2..a94fd8c1bab 100644 --- a/PWGCF/Tasks/correlations.cxx +++ b/PWGCF/Tasks/correlations.cxx @@ -8,32 +8,46 @@ // In applying this license CERN does 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 +/// \file correlations.cxx +/// \brief task for the correlation calculations with CF-filtered tracks for O2 analysis +/// \author Jan Fiete Grosse-Oetringhaus , Jasper Parkkila -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "CCDB/BasicCCDBManager.h" -#include "Framework/StepTHn.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/RunningWorkflowInfo.h" -#include "CommonConstants/MathConstants.h" +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Centrality.h" -#include "PWGCF/DataModel/CorrelationsDerived.h" -#include "PWGCF/Core/CorrelationContainer.h" -#include "PWGCF/Core/PairCuts.h" -#include "DataFormatsParameters/GRPObject.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" #include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -53,7 +67,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; @@ -65,16 +79,20 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgPtOrder, int, 1, "Only consider pairs for which pT,1 < pT,2 (0 = OFF, 1 = ON)"); 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(cfgAssociatedCharge, int, 0, "Select on charge of associated particle: 0 = all charged; 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"); + O2_DEFINE_CONFIGURABLE(cfgTrackBitMask, uint16_t, 0, "BitMask for track selection systematics; refer to the enum TrackSelectionCuts in filtering task"); + O2_DEFINE_CONFIGURABLE(cfgMultCorrelationsMask, uint16_t, 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask.") + O2_DEFINE_CONFIGURABLE(cfgMultCutFormula, std::string, "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity") + // 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") @@ -84,7 +102,12 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgVerbosity, int, 1, "Verbosity level (0 = major, 1 = per collision)") O2_DEFINE_CONFIGURABLE(cfgDecayParticleMask, int, 0, "Selection bitmask for the decay particles: 0 = no selection") + O2_DEFINE_CONFIGURABLE(cfgV0RapidityMax, float, 0.8, "Maximum rapidity 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"}; @@ -97,13 +120,12 @@ struct CorrelationTask { 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"}; - ConfigurableAxis axisInvMass{"axisInvMass", {VARIABLE_WIDTH, 0, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2.0, 5.0}, "invariant mass axis for histograms"}; - ConfigurableAxis axisInvMassHistogram{"axisInvMassHistogram", {1000, 1.0, 3.0}, "invariant mass histogram binning"}; + ConfigurableAxis axisInvMass{"axisInvMass", {VARIABLE_WIDTH, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2.0, 5.0}, "invariant mass axis for histograms"}; // 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)); @@ -111,7 +133,7 @@ struct CorrelationTask { // MC filters Filter cfMCCollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; - Filter cfMCParticleFilter = (nabs(aod::cfmcparticle::eta) < cfgCutEta) && (aod::cfmcparticle::pt > cfgCutPt) && (aod::cfmcparticle::sign != 0); + Filter cfMCParticleFilter = (nabs(aod::cfmcparticle::eta) < cfgCutEta) && (aod::cfmcparticle::pt > cfgCutPt); // && (aod::cfmcparticle::sign != 0); //check the sign manually, some specials may be neutral // HF filters Filter track2pFilter = (nabs(aod::cf2prongtrack::eta) < cfgCutEta) && (aod::cf2prongtrack::pt > cfgCutPt); @@ -120,7 +142,12 @@ struct CorrelationTask { OutputObj same{"sameEvent"}; OutputObj mixed{"mixedEvent"}; + // persistent caches std::vector efficiencyAssociatedCache; + std::vector p2indexCache; + + std::unique_ptr multCutFormula; + std::array multCutFormulaParamIndex; struct Config { bool mPairCuts = false; @@ -134,25 +161,53 @@ 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&) { + if ((doprocessSame2ProngDerivedML || doprocessSame2Prong2ProngML || doprocessMixed2ProngDerivedML || doprocessMixed2Prong2ProngML) && (cfgPtDepMLbkg->empty() || cfgPtCentDepMLbkgSel->empty())) + LOGF(fatal, "cfgPtDepMLbkg or cfgPtCentDepMLbkgSel can not be empty when ML 2-prong selections are used."); 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 || doprocessMCSameDerived2Prong) { 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("invMass", "2-prong invariant mass (GeV/c^2)", {HistType::kTH3F, {axisInvMassHistogram, axisPtTrigger, axisMultiplicity}}); + 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"}}}); + const AxisSpec& a = AxisSpec(axisInvMass); + AxisSpec axisSpecMass = {1000, a.binEdges[0], a.binEdges[a.getNbins()]}; + registry.add("invMass", "2-prong invariant mass (GeV/c^2)", {HistType::kTH3F, {axisSpecMass, axisPtTrigger, axisMultiplicity}}); + if (doprocessSame2Prong2Prong || doprocessSame2Prong2ProngML) { + registry.add("invMassTwoPart", "2D 2-prong invariant mass (GeV/c^2)", {HistType::kTHnSparseF, {axisSpecMass, axisSpecMass, axisPtTrigger, axisPtAssoc, axisMultiplicity}}); + registry.add("invMassTwoPartDPhi", "2D 2-prong invariant mass (GeV/c^2)", {HistType::kTHnSparseF, {axisSpecMass, axisSpecMass, axisPtTrigger, axisPtAssoc, axisDeltaPhi}}); + registry.add("invMassTwoPartDEta", "2D 2-prong invariant mass (GeV/c^2)", {HistType::kTHnSparseF, {axisSpecMass, axisSpecMass, axisPtTrigger, axisPtAssoc, axisDeltaEta}}); + } + } + if (doprocessSameDerivedMultSet) { + if (cfgMultCorrelationsMask == 0) + LOGF(fatal, "cfgMultCorrelationsMask can not be 0 when MultSet process functions are in use."); + std::vector multAxes; + if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0C) + multAxes.emplace_back(100, 0, 100, "FT0C centrality"); + if (cfgMultCorrelationsMask & aod::cfmultset::MultFV0A) + multAxes.emplace_back(1000, 0, 100000, "V0A multiplicity"); + if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksPV) + multAxes.emplace_back(100, 0, 1000, "Nch PV"); + if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksGlobal) + multAxes.emplace_back(100, 0, 1000, "Nch Global"); + registry.add("multCorrelations", "Multiplicity correlations", {HistType::kTHnSparseF, multAxes}); } + registry.add("multiplicity", "event multiplicity", {HistType::kTH1F, {{1000, 0, 100, "/multiplicity/centrality"}}}); + registry.add("yvspt", "y vs pT", {HistType::kTH2F, {{100, -1, 1, "y"}, {100, 0, 20, "p_{T}"}}}); // y vs pT for all tracks (control histogram) const int maxMixBin = AxisSpec(axisMultiplicity).getNbins() * AxisSpec(axisVertex).getNbins(); + // The bin numbers for the control histograms (eventcount_*) come from getBin(...) and are the following: #mult_bin * #number_of_z_bins + #zbin registry.add("eventcount_same", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); registry.add("eventcount_mixed", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); + registry.add("trackcount_same", "bin", {HistType::kTH2F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}, {10, -0.5, 9.5}}}); + registry.add("trackcount_mixed", "bin", {HistType::kTH3F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}, {10, -0.5, 9.5}, {10, -0.5, 9.5}}}); mPairCuts.SetHistogramRegistry(®istry); @@ -171,6 +226,26 @@ struct CorrelationTask { // --- OBJECT INIT --- + if (!cfgMultCutFormula.value.empty()) { + multCutFormula = std::make_unique("multCutFormula", cfgMultCutFormula.value.c_str()); + std::fill_n(multCutFormulaParamIndex.begin(), std::size(multCutFormulaParamIndex), ~0u); + std::array pars = {"cFT0C", "mFV0A", "mPV", "mGlob"}; // must correspond the order of MultiplicityEstimators + for (uint i = 0, n = multCutFormula->GetNpar(); i < n; ++i) { + auto m = std::find(pars.begin(), pars.end(), multCutFormula->GetParName(i)); + if (m == pars.end()) { + + LOGF(warning, "Unknown parameter in cfgMultCutFormula: %s", multCutFormula->GetParName(i)); + continue; + } + if ((cfgMultCorrelationsMask.value & (1u << i)) == 0) { + LOGF(warning, "The centrality/multiplicity estimator %s is not available to be used in cfgMultCutFormula. Ensure cfgMultCorrelationsMask is correct and matches the CFMultSets in derived data."); + } else { + multCutFormulaParamIndex[std::distance(pars.begin(), m)] = i; + LOGF(info, "Multiplicity cut parameter %s in use.", m->c_str()); + } + } + } + std::vector corrAxis = {{axisDeltaEta, "#Delta#eta"}, {axisPtAssoc, "p_{T} (GeV/c)"}, {axisPtTrigger, "p_{T} (GeV/c)"}, @@ -181,15 +256,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 || doprocessMCEfficiency2ProngML) { + 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 @@ -218,28 +308,103 @@ 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 + using HasMultSet = decltype(std::declval().multiplicities()); + template - void fillQA(const TCollision& /*collision*/, float multiplicity, const TTracks& tracks) + void fillQA(const TCollision& collision, float multiplicity, const TTracks& tracks) { - for (auto& track1 : tracks) { + registry.fill(HIST("multiplicity"), multiplicity); + if constexpr (std::experimental::is_detected::value) { + if (std::popcount(cfgMultCorrelationsMask.value) != static_cast(collision.multiplicities().size())) + LOGF(fatal, "Multiplicity selections (cfgMultCorrelationsMask = 0x%x) do not match the size of the table column (%ld). The histogram filling relies on the preservation of order.", cfgMultCorrelationsMask.value, collision.multiplicities().size()); + // need to convert to vec of doubles since THnSparse has no way to fill vec of floats directly + std::vector v(collision.multiplicities().begin(), collision.multiplicities().end()); + registry.get(HIST("multCorrelations")).get()->Fill(v.data()); + } + 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 (std::abs(track1.phi() - track2.phi()) < constants::math::PI * 0.5) { + registry.fill(HIST("invMassTwoPartDEta"), track1.invMass(), track2.invMass(), track1.pt(), track2.pt(), track1.eta() - track2.eta()); + } + } + } + } + } + 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()); @@ -276,13 +441,71 @@ struct CorrelationTask { } template - using hasSign = decltype(std::declval().sign()); + using HasSign = decltype(std::declval().sign()); + template + using HasDecay = decltype(std::declval().decay()); + template + using HasMcDecay = decltype(std::declval().mcDecay()); + template + using HasProng0Id = decltype(std::declval().cfTrackProng0Id()); + template + using HasProng1Id = decltype(std::declval().cfTrackProng1Id()); template - using hasDecay = decltype(std::declval().decay()); + using HasMlProbD0 = decltype(std::declval().mlProbD0()); template - using hasProng0Id = decltype(std::declval().cfTrackProng0Id()); + using HasPartDaugh0Id = decltype(std::declval().cfParticleDaugh0Id()); template - using hasProng1Id = decltype(std::declval().cfTrackProng1Id()); + using HasPartDaugh1Id = decltype(std::declval().cfParticleDaugh1Id()); + + /* + OO outlier cut (requires mask 15): +(567.785+172.715*[mGlob]+0.77888*[mGlob]*[mGlob]+-0.00693466*[mGlob]*[mGlob]*[mGlob]+1.40564e-05*[mGlob]*[mGlob]*[mGlob]*[mGlob] + 3.5*(679.853+66.8068*[mGlob]+-0.444332*[mGlob]*[mGlob]+0.00115002*[mGlob]*[mGlob]*[mGlob]+-4.92064e-07*[mGlob]*[mGlob]*[mGlob]*[mGlob])) > [mFV0A] && (567.785+172.715*[mGlob]+0.77888*[mGlob]*[mGlob]+-0.00693466*[mGlob]*[mGlob]*[mGlob]+1.40564e-05*[mGlob]*[mGlob]*[mGlob]*[mGlob] - 3.0*(679.853+66.8068*[mGlob]+-0.444332*[mGlob]*[mGlob]+0.00115002*[mGlob]*[mGlob]*[mGlob]+-4.92064e-07*[mGlob]*[mGlob]*[mGlob]*[mGlob])) < [mFV0A] && (172.406 + -4.50219*[cFT0C] + 0.0543038*[cFT0C]*[cFT0C] + -0.000373213*[cFT0C]*[cFT0C]*[cFT0C] + 1.15322e-06*[cFT0C]*[cFT0C]*[cFT0C]*[cFT0C] + 4.0*(49.7503 + -1.29008*[cFT0C] + 0.0160059*[cFT0C]*[cFT0C] + -7.86846e-05*[cFT0C]*[cFT0C]*[cFT0C])) > [mPV] && (172.406 + -4.50219*[cFT0C] + 0.0543038*[cFT0C]*[cFT0C] + -0.000373213*[cFT0C]*[cFT0C]*[cFT0C] + 1.15322e-06*[cFT0C]*[cFT0C]*[cFT0C]*[cFT0C] - 2.5*(49.7503 + -1.29008*[cFT0C] + 0.0160059*[cFT0C]*[cFT0C] + -7.86846e-05*[cFT0C]*[cFT0C]*[cFT0C])) < [mPV] && (125.02 + -3.30255*[cFT0C] + 0.0398663*[cFT0C]*[cFT0C] + -0.000271942*[cFT0C]*[cFT0C]*[cFT0C] + 8.34098e-07*[cFT0C]*[cFT0C]*[cFT0C]*[cFT0C] + 4.0*(37.0244 + -0.949883*[cFT0C] + 0.0116622*[cFT0C]*[cFT0C] + -5.71117e-05*[cFT0C]*[cFT0C]*[cFT0C])) > [mGlob] && (125.02 + -3.30255*[cFT0C] + 0.0398663*[cFT0C]*[cFT0C] + -0.000271942*[cFT0C]*[cFT0C]*[cFT0C] + 8.34098e-07*[cFT0C]*[cFT0C]*[cFT0C]*[cFT0C] - 2.5*(37.0244 + -0.949883*[cFT0C] + 0.0116622*[cFT0C]*[cFT0C] + -5.71117e-05*[cFT0C]*[cFT0C]*[cFT0C])) < [mGlob] && (-0.223013 + 0.715849*[mPV] + 3*(0.664242 + 0.0829653*[mPV] + -0.000503733*[mPV]*[mPV] + 1.21185e-06*[mPV]*[mPV]*[mPV])) > [mGlob] +*/ + template + bool passOutlier(CollType const& collision) + { + if (cfgMultCutFormula.value.empty()) + return true; + for (uint i = 0; i < 4; ++i) { + if ((cfgMultCorrelationsMask.value & (1u << i)) == 0 || multCutFormulaParamIndex[i] == ~0u) + continue; + auto estIndex = std::popcount(cfgMultCorrelationsMask.value & ((1u << i) - 1)); + multCutFormula->SetParameter(multCutFormulaParamIndex[i], collision.multiplicities()[estIndex]); + } + return multCutFormula->Eval() > 0.0f; + } + + template + std::tuple getV0Rapidity(const T& track) + { + if constexpr (!std::experimental::is_detected::value) + return {false, 0.0f}; // no decay type, return dummy rapidity + const auto decayType = track.decay(); + float mass = 0.f; + + if (decayType == aod::cf2prongtrack::K0stoPiPi) { + mass = o2::constants::physics::MassK0Short; + } else if (decayType == aod::cf2prongtrack::LambdatoPPi || decayType == aod::cf2prongtrack::AntiLambdatoPiP) { + mass = o2::constants::physics::MassLambda; + } else if (decayType == aod::cf2prongtrack::PhiToKKPID1 || decayType == aod::cf2prongtrack::PhiToKKPID2 || decayType == aod::cf2prongtrack::PhiToKKPID3) { + mass = o2::constants::physics::MassPhi; + } else { + return {false, 0.0f}; // unsupported decay type, return dummy rapidity + } + + const float pt = track.pt(); + const float eta = track.eta(); + const float phi = track.phi(); + + const float px = pt * std::cos(phi); + const float py = pt * std::sin(phi); + const float pz = pt * std::sinh(eta); + + const float p2 = px * px + py * py + pz * pz; + + const float E = std::sqrt(p2 + mass * mass); + return {true, 0.5f * std::log((E + pz) / (E - pz))}; + } template void fillCorrelations(TTarget target, TTracks1& tracks1, TTracks2& tracks2, float multiplicity, float posZ, int magField, float eventWeight) @@ -292,32 +515,66 @@ 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) { + if constexpr (step <= CorrelationContainer::kCFStepTracked && !std::experimental::is_detected::value) { if (!checkObject(track1)) { continue; } } - if constexpr (std::experimental::is_detected::value) { - if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << (uint32_t)track1.decay())) == 0u) + // sign check and PDG code special cases + if constexpr (std::experimental::is_detected::value) { + // If the MC trigger particle is on the trigger PDG code list, we will accept them regardless of their charge. + if (!cfgMcTriggerPDGs->empty()) { + if (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track1.pdgCode()) == cfgMcTriggerPDGs->end()) + continue; + } else { // otherwise check the sign against the configuration + if (cfgTriggerCharge != 0) { + if (cfgTriggerCharge * track1.sign() < 0) + continue; + } else if (track1.sign() == 0) { + continue; // reject neutral MC particles + } + } + } else if constexpr (std::experimental::is_detected::value) { + // Check reco objects that have the sign attribute. There are no neutrals to deal with. + if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.sign() < 0) continue; } - if constexpr (std::experimental::is_detected::value) { - if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.sign() < 0) { + if constexpr (std::experimental::is_detected::value) { + if (((track1.mcDecay() != aod::cf2prongtrack::D0ToPiK) && (track1.mcDecay() != aod::cf2prongtrack::D0barToKPi)) || (track1.decay() & aod::cf2prongmcpart::Prompt) == 0) continue; + } else if constexpr (std::experimental::is_detected::value) { + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) { + continue; // skip particles that do not match the decay mask + } + if (cfgV0RapidityMax > 0) { + auto [t, y] = getV0Rapidity(track1); + if (t && std::abs(y) > cfgV0RapidityMax) + continue; // V0s are not allowed to be outside the rapidity range + registry.fill(HIST("yvspt"), y, track1.pt()); } } + if constexpr (std::experimental::is_detected::value) { + if (track1.cfParticleDaugh0Id() < 0 && track1.cfParticleDaugh1Id() < 0) + continue; // these we could not match + } + + if constexpr (std::experimental::is_detected::value) { + if (!passMLScore(track1)) + continue; + } // ML selection + float triggerWeight = eventWeight; if constexpr (step == CorrelationContainer::kCFStepCorrected) { if (cfg.mEfficiencyTrigger) { @@ -326,45 +583,122 @@ struct CorrelationTask { } if (cfgMassAxis) { - if constexpr (std::experimental::is_detected::value) + if constexpr (std::experimental::is_detected::value) target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, track1.invMass(), triggerWeight); - else + else if constexpr (std::experimental::is_detected::value) { + // TParticlePDG *p = pdg->GetParticle(track1.pdgCode()); + // target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, p->Mass(), triggerWeight); + target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, 1.8, 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) { // skip those that are specifically chosen to be triggers + if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track2.pdgCode()) != cfgMcTriggerPDGs->end()) + continue; // TODO: fix cases like MC D0-D0 + } + + // Daughter track and particle checks + 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; } + if constexpr (std::experimental::is_detected::value) { + if (track2.globalIndex() == track1.cfParticleDaugh0Id()) // do not correlate daughter particles of the same event + continue; + } + if constexpr (std::experimental::is_detected::value) { + if (track2.globalIndex() == track1.cfParticleDaugh1Id()) // do not correlate daughter particles of the same event + continue; + } - if constexpr (step <= CorrelationContainer::kCFStepTracked) { + if constexpr (step <= CorrelationContainer::kCFStepTracked && !std::experimental::is_detected::value) { if (!checkObject(track2)) { continue; } } + // If decay attributes are found for the second track/particle, we assume 2p-2p correlation + if constexpr (std::experimental::is_detected::value) { + if ((((track2.mcDecay()) != aod::cf2prongtrack::D0ToPiK) && ((track2.mcDecay()) != aod::cf2prongtrack::D0barToKPi)) || (track2.decay() & aod::cf2prongmcpart::Prompt) == 0) + continue; + } else if constexpr (std::experimental::is_detected::value) { + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track2.decay()))) == 0u) { + continue; // skip particles that do not match the decay mask + } + + // track2 here is charged hadron so we don't need rapidity cut for this track...this rapidity is only needed for V0 + /* + if (cfgV0RapidityMax > 0) { + auto [t, y] = getV0Rapidity(track2); + if (t && std::abs(y) > cfgV0RapidityMax) + 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 + // TODO MC daughters check ^^ + if (cfgPtOrder != 0 && track2.pt() >= track1.pt()) { continue; } - if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.sign() < 0) { - continue; + if constexpr (std::experimental::is_detected::value) { + // TODO: support for MC D0-D0 case + if (cfgAssociatedCharge != 0) { + if (cfgAssociatedCharge * track2.sign() < 0) + continue; + } else if (track2.sign() == 0) { // mc particles come in neutrals, need to check explicitly + 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; } @@ -372,12 +706,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; + } } } } @@ -389,20 +724,28 @@ 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 (!passMLScore(track2)) + continue; + } // ML selection // last param is the weight - 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); + 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 if constexpr (std::experimental::is_detected::value) { + // TParticlePDG *p = pdg->GetParticle(track1.pdgCode()); //TODO: get the mass for the PDG properly + target->getPairHist()->Fill(step, track1.eta() - track2.eta(), track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, 1.8, associatedWeight); // p->Mass() + } else { LOGF(fatal, "Can not fill mass axis without invMass column. Disable cfgMassAxis."); + } } else { target->getPairHist()->Fill(step, track1.eta() - track2.eta(), track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, associatedWeight); } @@ -453,7 +796,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 @@ -476,11 +819,13 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processSameAOD, "Process same event on AOD", true); - void processSameDerived(derivedCollisions::iterator const& collision, soa::Filtered const& tracks) + template + void processSameDerivedT(CollType const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) { + using BinningTypeDerived = ColumnBinningPolicy; 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()); + LOGF(info, "processSameDerivedT: Tracks for collision: %d/%d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks1.size(), tracks2.size(), collision.posZ(), collision.multiplicity()); } loadEfficiency(collision.timestamp()); @@ -492,51 +837,68 @@ struct CorrelationTask { int bin = configurableBinningDerived.getBin({collision.posZ(), collision.multiplicity()}); registry.fill(HIST("eventcount_same"), bin); - fillQA(collision, multiplicity, tracks); + registry.fill(HIST("trackcount_same"), bin, tracks1.size()); + if constexpr (std::experimental::is_detected::value) + fillQA(collision, multiplicity, tracks1, tracks2); + else + fillQA(collision, multiplicity, tracks1); same->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), field, 1.0f); + fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f); if (cfg.mEfficiencyAssociated || cfg.mEfficiencyTrigger) { same->fillEvent(multiplicity, CorrelationContainer::kCFStepCorrected); - fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), field, 1.0f); + fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f); } } + + void processSameDerived(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks) + { + processSameDerivedT(collision, tracks, tracks); + } 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) + void processSameDerivedMultSet(soa::Filtered>::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, "processSame2ProngDerived: Tracks for collision: %d | 2-prong candidates: %d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks.size(), p2tracks.size(), collision.posZ(), collision.multiplicity()); - } - loadEfficiency(collision.timestamp()); + if (!passOutlier(collision)) + return; + processSameDerivedT(collision, tracks, tracks); + } + PROCESS_SWITCH(CorrelationTask, processSameDerivedMultSet, "Process same event on derived data with multiplicity sets", false); - const auto multiplicity = collision.multiplicity(); + void processSame2ProngDerived(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks, soa::Filtered const& p2tracks) + { + processSameDerivedT(collision, p2tracks, tracks); + } + PROCESS_SWITCH(CorrelationTask, processSame2ProngDerived, "Process same event on derived data", false); - int bin = configurableBinningDerived.getBin({collision.posZ(), collision.multiplicity()}); - registry.fill(HIST("eventcount_same"), bin); - fillQA(collision, multiplicity, p2tracks, tracks); + void processSame2ProngDerivedML(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks, soa::Filtered> const& p2tracks) + { + processSameDerivedT(collision, p2tracks, tracks); + } + PROCESS_SWITCH(CorrelationTask, processSame2ProngDerivedML, "Process same event on derived data with ML scores", false); - same->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(same, p2tracks, tracks, multiplicity, collision.posZ(), 0, 1.0f); + void processSame2Prong2Prong(DerivedCollisions::iterator const& collision, soa::Filtered const& p2tracks) + { + processSameDerivedT(collision, p2tracks, p2tracks); + } + PROCESS_SWITCH(CorrelationTask, processSame2Prong2Prong, "Process same event on derived data", false); - if (cfg.mEfficiencyAssociated || cfg.mEfficiencyTrigger) { - same->fillEvent(multiplicity, CorrelationContainer::kCFStepCorrected); - fillCorrelations(same, p2tracks, tracks, multiplicity, collision.posZ(), 0, 1.0f); - } + void processSame2Prong2ProngML(DerivedCollisions::iterator const& collision, soa::Filtered> const& p2tracks) + { + processSameDerivedT(collision, p2tracks, p2tracks); } - PROCESS_SWITCH(CorrelationTask, processSame2ProngDerived, "Process same event on derived data", false); + 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++) { @@ -571,17 +933,32 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processMixedAOD, "Process mixed events on AOD", false); - using BinningTypeDerived = ColumnBinningPolicy; - void processMixedDerived(derivedCollisions& collisions, derivedTracks const& tracks) + template + void processMixedDerivedT(CollType const& collisions, TrackTypes&&... 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 + auto getMultiplicity = + [this](auto& col) { + if constexpr (std::experimental::is_detected::value) { + if (!passOutlier(col)) + return -1.0f; + } else { + (void)this; // fix compile error on unused 'this' capture + } + return col.multiplicity(); + }; + + using BinningTypeDerived = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getMultiplicity)>; + BinningTypeDerived configurableBinningDerived{{getMultiplicity}, {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(std::forward(tracks)...); + using TA = std::tuple_element<0, decltype(tracksTuple)>::type; + using TB = std::tuple_element - 1, decltype(tracksTuple)>::type; + 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; - int bin = configurableBinningDerived.getBin({collision1.posZ(), collision1.multiplicity()}); + float multiplicity = getMultiplicity(collision1); + int bin = configurableBinningDerived.getBin(std::tuple(collision1.posZ(), multiplicity)); float eventWeight = 1.0f / it.currentWindowNeighbours(); int field = 0; if (cfgTwoTrackCut > 0) { @@ -601,6 +978,7 @@ struct CorrelationTask { // LOGF(info, "Tracks: %d and %d entries", tracks1.size(), tracks2.size()); registry.fill(HIST("eventcount_mixed"), bin); + registry.fill(HIST("trackcount_mixed"), bin, tracks1.size(), tracks2.size()); fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), field, eventWeight); if (cfg.mEfficiencyAssociated || cfg.mEfficiencyTrigger) { @@ -611,46 +989,42 @@ struct CorrelationTask { } } } - PROCESS_SWITCH(CorrelationTask, processMixedDerived, "Process mixed events on derived data", false); - void processMixed2ProngDerived(derivedCollisions& collisions, derivedTracks const& tracks, soa::Filtered const& p2tracks) + 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(p2tracks, tracks); - Pair, derivedTracks, BinningTypeDerived> 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()); - } + processMixedDerivedT(collisions, tracks); + } + PROCESS_SWITCH(CorrelationTask, processMixedDerived, "Process mixed events on derived data", false); - if (cfgVerbosity > 0) { - LOGF(info, "processMixed2ProngDerived: 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()); - } + void processMixedDerivedMultSet(soa::Filtered> const& collisions, DerivedTracks const& tracks) + { + processMixedDerivedT(collisions, tracks); + } + PROCESS_SWITCH(CorrelationTask, processMixedDerivedMultSet, "Process mixed events on derived data with multiplicity sets", false); - if (it.isNewWindow()) { - loadEfficiency(collision1.timestamp()); + void processMixed2ProngDerived(DerivedCollisions const& collisions, DerivedTracks const& tracks, soa::Filtered const& p2tracks) + { + processMixedDerivedT(collisions, p2tracks, tracks); + } + PROCESS_SWITCH(CorrelationTask, processMixed2ProngDerived, "Process mixed events on derived data", false); - mixed->fillEvent(collision1.multiplicity(), CorrelationContainer::kCFStepReconstructed); - } + void processMixed2ProngDerivedML(DerivedCollisions const& collisions, DerivedTracks const& tracks, soa::Filtered> const& p2tracks) + { + processMixedDerivedT(collisions, p2tracks, tracks); + } + PROCESS_SWITCH(CorrelationTask, processMixed2ProngDerivedML, "Process mixed events on derived data with ML scores", false); - registry.fill(HIST("eventcount_mixed"), bin); - fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), field, eventWeight); + void processMixed2Prong2Prong(DerivedCollisions const& collisions, soa::Filtered const& p2tracks) + { + processMixedDerivedT(collisions, p2tracks); + } + PROCESS_SWITCH(CorrelationTask, processMixed2Prong2Prong, "Process mixed events on derived data", false); - 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 processMixed2Prong2ProngML(DerivedCollisions const& collisions, soa::Filtered> const& p2tracks) + { + processMixedDerivedT(collisions, p2tracks); } - PROCESS_SWITCH(CorrelationTask, processMixed2ProngDerived, "Process mixed events on derived data", false); + 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) @@ -674,7 +1048,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) { @@ -695,14 +1069,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); @@ -710,7 +1077,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 @@ -722,9 +1089,11 @@ struct CorrelationTask { case 2212: // proton case -2212: return 2; - default: - return 3; } + if (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), pdgCode) != cfgMcTriggerPDGs->end()) + return 4; // NOTE - if changed, the number in processMCEfficiency2Prong needs to be changed too since we skip the getSpecies call + else // The efficiency histogram is hardcoded to contain 5 species. Anything special will have the 4th slot. + return 3; } // NOTE SmallGroups includes soa::Filtered always @@ -740,30 +1109,32 @@ struct CorrelationTask { if (collisions.size() == 0) { return; } - for (auto& collision : collisions) { + for (const auto& collision : collisions) { multiplicity = collision.multiplicity(); } } // Primaries - for (auto& mcParticle : mcParticles) { - if (mcParticle.isPhysicalPrimary() && mcParticle.sign() != 0) { - same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), GetSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); + for (const auto& mcParticle : mcParticles) { + if (mcParticle.isPhysicalPrimary() && mcParticle.sign() != 0 && !((doprocessMCEfficiency2Prong || doprocessMCEfficiency2ProngML) && 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()); } } - 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 ((doprocessMCEfficiency2Prong || doprocessMCEfficiency2ProngML) && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end()) + continue; // properly booked by the 2Prong efficiency function, ignore here 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 @@ -774,11 +1145,95 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processMCEfficiency, "MC: Extract efficiencies", false); - // NOTE SmallGroups includes soa::Filtered always - void processMCSameDerived(soa::Filtered::iterator const& mcCollision, soa::Filtered const& mcParticles, soa::SmallGroups const& collisions) + template + void processMCEfficiency2ProngT(soa::Filtered::iterator const& mcCollision, soa::Join const& mcParticles, soa::SmallGroups const& collisions, aod::CFTracksWithLabel const&, p2type const& p2tracks, Preslice& perCollision2Prong) + { + 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 (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end()) { + if (((mcParticle.mcDecay() != aod::cf2prongtrack::D0ToPiK) && (mcParticle.mcDecay() != aod::cf2prongtrack::D0barToKPi)) || (mcParticle.decay() & aod::cf2prongmcpart::Prompt) == 0) + continue; // wrong decay channel + if (mcParticle.cfParticleDaugh0Id() < 0 && mcParticle.cfParticleDaugh1Id() < 0) + continue; // daughters not found + same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), 4, multiplicity, mcCollision.posZ()); + p2indexCache.push_back(mcParticle.globalIndex()); + } + } + for (const auto& collision : collisions) { + auto grouped2ProngTracks = p2tracks.sliceBy(perCollision2Prong, collision.globalIndex()); + + for (const auto& p2track : grouped2ProngTracks) { + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(p2track.decay()))) == 0u) + continue; + // Check if the mc particles of the prongs are found. + if constexpr (std::experimental::is_detected::value) { + if (!passMLScore(p2track)) + continue; + } + auto fillMC2p = [&](const aod::CFTracksWithLabel::iterator& p) -> bool { + if (!p.has_cfMCParticle()) + return false; + auto m = std::find_if(p2indexCache.begin(), p2indexCache.end(), [&](const auto& t) -> bool { + const auto& mcParticle = mcParticles.iteratorAt(t - mcParticles.begin().globalIndex()); + return (p.cfMCParticleId() == mcParticle.cfParticleDaugh0Id() || p.cfMCParticleId() == mcParticle.cfParticleDaugh1Id()); + }); + if (m == p2indexCache.end()) + return false; + const auto& mcParticle = mcParticles.iteratorAt(*m - mcParticles.begin().globalIndex()); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, mcParticle.eta(), mcParticle.pt(), 4, multiplicity, mcCollision.posZ()); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoAll, mcParticle.eta(), mcParticle.pt(), 4, multiplicity, mcCollision.posZ()); + return true; + }; + if (p2track.has_cfTrackProng0()) { + // + if (const auto& p0 = p2track.template cfTrackProng0_as(); fillMC2p(p0)) + continue; + } + if (p2track.has_cfTrackProng1()) { + if (const auto& p1 = p2track.template cfTrackProng1_as(); fillMC2p(p1)) + continue; + } + + // alternatively, book the reco pTs directly + // same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, p2track.eta(), p2track.pt(), 4, multiplicity, mcCollision.posZ()); + // same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoAll, p2track.eta(), p2track.pt(), 4, multiplicity, mcCollision.posZ()); + // continue; + + // fake track + same->getTrackHistEfficiency()->Fill(CorrelationContainer::Fake, p2track.eta(), p2track.pt(), 4, multiplicity, mcCollision.posZ()); + } + } + } + + Preslice perCollision2Prong = aod::cftrack::cfCollisionId; + void processMCEfficiency2Prong(soa::Filtered::iterator const& mcCollision, soa::Join const& mcParticles, soa::SmallGroups const& collisions, aod::CFTracksWithLabel const& tracks, aod::CF2ProngTracks const& p2tracks) + { + processMCEfficiency2ProngT(mcCollision, mcParticles, collisions, tracks, p2tracks, perCollision2Prong); + } + PROCESS_SWITCH(CorrelationTask, processMCEfficiency2Prong, "MC: Extract efficiencies for 2-prong particles", false); + + Preslice> perCollision2ProngML = aod::cftrack::cfCollisionId; + void processMCEfficiency2ProngML(soa::Filtered::iterator const& mcCollision, soa::Join const& mcParticles, soa::SmallGroups const& collisions, aod::CFTracksWithLabel const& tracks, soa::Join const& p2tracks) + { + processMCEfficiency2ProngT(mcCollision, mcParticles, collisions, tracks, p2tracks, perCollision2ProngML); + } + PROCESS_SWITCH(CorrelationTask, processMCEfficiency2ProngML, "MC: Extract efficiencies for 2-prong particles with ML scores", false); + + template + void processMCSameDerivedT(soa::Filtered::iterator const& mcCollision, Particles1 const& mcParticles1, Particles2 const& mcParticles2, soa::SmallGroups const& collisions) { if (cfgVerbosity > 0) { - LOGF(info, "processMCSameDerived. MC collision: %d, particles: %d, collisions: %d", mcCollision.globalIndex(), mcParticles.size(), collisions.size()); + LOGF(info, "processMCSameDerivedT. MC collision: %d, particles1: %d, particles2: %d, collisions: %d", mcCollision.globalIndex(), mcParticles1.size(), mcParticles2.size(), collisions.size()); } auto multiplicity = mcCollision.multiplicity(); @@ -786,37 +1241,58 @@ struct CorrelationTask { if (collisions.size() == 0) { return; } - for (auto& collision : collisions) { + for (const auto& collision : collisions) { multiplicity = collision.multiplicity(); } - if (cfgVerbosity > 0) { - LOGF(info, " Data multiplicity: %f", multiplicity); - } + } + + if (!(doprocessSameDerived || doprocessSameDerivedMultSet || doprocessSame2ProngDerived || doprocessSame2ProngDerivedML || doprocessSame2Prong2Prong || doprocessSame2Prong2ProngML)) { + if constexpr (std::experimental::is_detected::value) + fillQA(mcCollision, multiplicity, mcParticles1, mcParticles2); + else + fillQA(mcCollision, multiplicity, mcParticles1); } same->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); - fillCorrelations(same, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), 0, 1.0f); + fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f); if (collisions.size() == 0) { return; } same->fillEvent(multiplicity, CorrelationContainer::kCFStepVertex); - fillCorrelations(same, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), 0, 1.0f); + fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f); same->fillEvent(multiplicity, CorrelationContainer::kCFStepTrackedOnlyPrim); - fillCorrelations(same, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), 0, 1.0f); + fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f); same->fillEvent(multiplicity, CorrelationContainer::kCFStepTracked); - fillCorrelations(same, mcParticles, mcParticles, multiplicity, mcCollision.posZ(), 0, 1.0f); + fillCorrelations(same, mcParticles1, mcParticles2, 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 } + + // NOTE SmallGroups includes soa::Filtered always + void processMCSameDerived(soa::Filtered::iterator const& mcCollision, soa::Filtered const& mcParticles, soa::SmallGroups const& collisions) // TODO. For mixed no need to check the daughters since the events are different + { + processMCSameDerivedT(mcCollision, mcParticles, mcParticles, collisions); + } PROCESS_SWITCH(CorrelationTask, processMCSameDerived, "Process MC same event on derived data", false); + void processMCSameDerived2Prong(soa::Filtered::iterator const& mcCollision, soa::Filtered> const& mcParticles2Prong, soa::Filtered const& mcParticles, soa::SmallGroups const& collisions) + { + // Subscribe to the MC particles table twice, once joined with the 2prongs and another time without. + // This is to avoid triggering any 2p-2p specific cases in the templated fillCorrelations(). + processMCSameDerivedT(mcCollision, mcParticles2Prong, mcParticles, collisions); + } + PROCESS_SWITCH(CorrelationTask, processMCSameDerived2Prong, "Process MC same event on derived data", false); + + // TODO: add MC 2Prong2Prong functions when needed + PresliceUnsorted collisionPerMCCollision = aod::cfcollision::cfMcCollisionId; - void processMCMixedDerived(soa::Filtered& mcCollisions, soa::Filtered const& mcParticles, soa::Filtered const& collisions) + template + void processMCMixedDerivedT(soa::Filtered const& mcCollisions, soa::Filtered const& collisions, ParticleTypes&&... particles) { bool useMCMultiplicity = (cfgCentBinsForMC == 0); auto getMultiplicity = @@ -833,8 +1309,10 @@ struct CorrelationTask { BinningTypeMCDerived configurableBinning{{getMultiplicity}, {axisVertex, axisMultiplicity}, true}; // Strictly upper categorised collisions, for cfgNoMixedEvents combinations per bin, skipping those in entry -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 + auto tuple = std::make_tuple(std::forward(particles)...); + using TA = std::tuple_element<0, decltype(tuple)>::type; + using TB = std::tuple_element - 1, decltype(tuple)>::type; + Pair, TA, TB, BinningTypeMCDerived> pairs{configurableBinning, cfgNoMixedEvents, -1, mcCollisions, tuple, &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; @@ -874,7 +1352,20 @@ struct CorrelationTask { // This also means that if a MC collision had several reconstructed vertices (collisions), all of them are filled } } + + void processMCMixedDerived(soa::Filtered const& mcCollisions, soa::Filtered const& mcParticles, soa::Filtered const& collisions) + { + processMCMixedDerivedT(mcCollisions, collisions, mcParticles); + } PROCESS_SWITCH(CorrelationTask, processMCMixedDerived, "Process MC mixed events on derived data", false); + + void processMCMixedDerived2Prong(soa::Filtered const& mcCollisions, soa::Filtered> const& mcParticles2Prong, soa::Filtered const& mcParticles, soa::Filtered const& collisions) + { + // Subscribe to the MC particles table twice, once joined with the 2prongs and another time without. + // This is to avoid triggering any 2p-2p specific cases in the templated fillCorrelations(). + processMCMixedDerivedT(mcCollisions, collisions, mcParticles2Prong, mcParticles); + } + PROCESS_SWITCH(CorrelationTask, processMCMixedDerived2Prong, "Process MC mixed events on derived data", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/Tasks/dptdptcorrelations.cxx b/PWGCF/Tasks/dptDptCorrelations.cxx similarity index 52% rename from PWGCF/Tasks/dptdptcorrelations.cxx rename to PWGCF/Tasks/dptDptCorrelations.cxx index 8ccdc1f93a0..e6ee088eca0 100644 --- a/PWGCF/Tasks/dptdptcorrelations.cxx +++ b/PWGCF/Tasks/dptDptCorrelations.cxx @@ -9,8 +9,30 @@ // 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 "PWGCF/Core/AnalysisConfigurableCuts.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptDptFilter.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TableHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" #include -#include + #include #include #include @@ -21,24 +43,12 @@ #include #include #include + #include +#include #include - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TableHelper.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "DataFormatsParameters/GRPObject.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include "PWGCF/Core/PairCuts.h" -#include "PWGCF/DataModel/DptDptFiltered.h" -#include "PWGCF/TableProducer/dptdptfilter.h" +#include +#include using namespace o2; using namespace o2::framework; @@ -51,7 +61,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 +71,19 @@ 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; +enum HistoDimensions { + kNONE = 0, + k1D, + k2D, + k3D, + k4D +}; +HistoDimensions nNoOfDimensions = k1D; // 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,11 +91,12 @@ 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 // Task for building correlations -struct DptDptCorrelationsTask { +struct DptDptCorrelations { /* the data collecting engine */ template @@ -87,32 +107,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,15 +147,11 @@ 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; - if (!(phi < phiup)) { - return phi - constants::math::TwoPI; - } else { - return phi; - } + return RecoDecay::constrainAngle(phi, philow); } /// \brief Returns the zero based bin index of the eta phi passed track @@ -148,19 +167,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 RecoDecay::constrainAngle(value, deltaphilow - constants::math::PI); + } + + /// \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 +246,102 @@ 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()*/ + + constexpr float kLARGETANTHETA = 1e10; + constexpr float kVERYSMALLETA = 1e-10; + float tantheta1 = kLARGETANTHETA; + + if (track1.eta() < -kVERYSMALLETA || track1.eta() > kVERYSMALLETA) { + float expTmp = std::exp(-track1.eta()); + tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); + } + + float tantheta2 = kLARGETANTHETA; + if (track2.eta() < -kVERYSMALLETA || track2.eta() > kVERYSMALLETA) { + 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, static_cast(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, static_cast(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 == k1D) { + nbins++; + avg += fhNuaNue[i]->GetBinContent(ix + 1); + } else { + for (int iy = 0; iy < fhNuaNue[i]->GetNbinsY(); ++iy) { + if (nNoOfDimensions == k2D) { + nbins++; + avg += fhNuaNue[i]->GetBinContent(ix + 1, iy + 1); + } else if (nNoOfDimensions == k3D || nNoOfDimensions == k4D) { + 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 +352,56 @@ 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) { + using namespace correlationstask; + 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 == k1D) { + (*corr)[index] = fhNuaNue[t.trackacceptedid()]->GetBinContent(fhNuaNue[t.trackacceptedid()]->FindFixBin(t.pt())); + } else if constexpr (nDim == k2D) { + (*corr)[index] = fhNuaNue[t.trackacceptedid()]->GetBinContent(fhNuaNue[t.trackacceptedid()]->FindFixBin(t.eta(), t.pt())); + } else if constexpr (nDim == k3D) { + (*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 == k1D) { + return getTrackCorrections(tracks, zvtx); + } else if (nNoOfDimensions == k2D) { + return getTrackCorrections(tracks, zvtx); + } else if (nNoOfDimensions == k3D) { + return getTrackCorrections(tracks, zvtx); + } + return getTrackCorrections(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 +415,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 +445,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 +470,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,12 +484,14 @@ 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 */ @@ -349,26 +506,25 @@ struct DptDptCorrelationsTask { } } /* 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) { - deltaphi -= constants::math::TwoPI; - } - while (deltaphi < deltaphilow) { - deltaphi += constants::math::TwoPI; - } + deltaphi = RecoDecay::constrainAngle(deltaphi, deltaphilow); 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 */ @@ -379,30 +535,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]); + } } } } @@ -442,15 +610,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); + } + } } } @@ -465,13 +658,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) { @@ -479,23 +675,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(), @@ -511,7 +710,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)", @@ -535,58 +734,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) { @@ -596,58 +802,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]); } } } @@ -665,28 +901,31 @@ struct DptDptCorrelationsTask { /* the data collecting engine instances */ DataCollectingEngine** dataCE; - DataCollectingEngine** dataCE_small; + DataCollectingEngine** dataCEsmall; DataCollectingEngine** dataCEME; /* the input file structure from CCDB */ TList* ccdblst = nullptr; bool loadfromccdb = false; std::string cfgCCDBUrl{"http://ccdb-test.cern.ch:8080"}; - std::string cfgCCDBPathName{""}; - std::string cfgCCDBDate{"20220307"}; - std::string cfgCCDBPeriod{"LHC22o"}; + std::string cfgCCDBPathNameCorrections{""}; + std::string cfgCCDBDateCorrections{"20220307"}; + std::string cfgCCDBSuffix{""}; /* 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{"cfgPairCut", {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 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 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{"cfgSmallDCE", true, "Use small data collecting engine for singles processing, true = yes. Default = true"}; + Configurable cfgDoInvMass{"cfgDoInvMass", false, "Do the invariant mass analyis, true = yes. Default = false"}; + Configurable cfgDoCorrelations{"cfgDoCorrelations", true, "Do the correlations analysis, 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 cfgPtOrder{"cfgPtOrder", 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) @@ -711,35 +950,38 @@ struct DptDptCorrelationsTask { } /* self configure the binning */ - 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); - getTaskOptionValue(initContext, "dpt-dpt-filter", "binning.mPhibinshift", phibinshift, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxbins", zvtxbins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxmin", zvtxlow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxmax", zvtxup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTbins", ptbins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTmin", ptlow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTmax", ptup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtabins", etabins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtamin", etalow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtamax", etaup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPhibins", phibins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPhibinshift", phibinshift, false); philow = 0.0f; phiup = constants::math::TwoPI; processpairs = cfgProcessPairs.value; processmixedevents = cfgProcessME.value; ptorder = cfgPtOrder.value; + invmass = cfgDoInvMass.value; + corrana = cfgDoCorrelations.value; + nNoOfDimensions = static_cast(cfgNoOfDimensions.value); /* 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); - loadfromccdb = cfgCCDBPathName.length() > 0; + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgCCDB.url", cfgCCDBUrl, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgCCDB.pathNameCorrections", cfgCCDBPathNameCorrections, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgCCDB.dateCorrections", cfgCCDBDateCorrections, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgCCDB.suffix", cfgCCDBSuffix, false); + loadfromccdb = (cfgCCDBDateCorrections.length() > 0) && (cfgCCDBPathNameCorrections.length() > 0); /* update the potential binning change */ etabinwidth = (etaup - etalow) / static_cast(etabins); phibinwidth = (phiup - philow) / static_cast(phibins); - /* the differential bining */ + /* the differential binning */ deltaetabins = etabins * 2 - 1; deltaetalow = etalow - etaup, deltaetaup = etaup - etalow; deltaetabinwidth = (deltaetaup - deltaetalow) / static_cast(deltaetabins); @@ -773,7 +1015,7 @@ struct DptDptCorrelationsTask { { /* self configure the desired species */ o2::analysis::dptdptfilter::PIDSpeciesSelection pidselector; - std::vector cfgnames = {"elpidsel", "mupidsel", "pipidsel", "kapidsel", "prpidsel"}; + std::vector cfgnames = {"cfgElectronPIDSelection", "cfgMuonPIDSelection", "cfgPionPIDSelection", "cfgKaonPIDSelection", "cfgProtonPIDSelection"}; std::vector spids = {0, 1, 2, 3, 4}; for (uint i = 0; i < cfgnames.size(); ++i) { auto includeIt = [&pidselector, &initContext](int spid, auto name) { @@ -785,7 +1027,7 @@ struct DptDptCorrelationsTask { auto cfg = new o2::analysis::TrackSelectionPIDCfg(); cfg->mUseIt = true; cfg->mExclude = false; - pidselector.Add(spid, cfg); + pidselector.addSpecies(spid, cfg); } } }; @@ -803,7 +1045,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(); @@ -817,7 +1060,7 @@ struct DptDptCorrelationsTask { /* self configure the centrality/multiplicity ranges */ std::string centspec; - if (getTaskOptionValue(initContext, "dpt-dpt-filter", "centralities", centspec, false)) { + if (getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgCentSpec", centspec, false)) { LOGF(info, "Got the centralities specification: %s", centspec.c_str()); auto tokens = TString(centspec.c_str()).Tokenize(","); ncmranges = tokens->GetEntries(); @@ -839,9 +1082,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]; } @@ -850,23 +1092,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])); @@ -874,16 +1129,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) { @@ -946,6 +1215,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) { @@ -953,7 +1230,7 @@ struct DptDptCorrelationsTask { if (ccdblst == nullptr) { if (loadfromccdb) { - ccdblst = getCCDBInput(ccdb, cfgCCDBPathName.c_str(), cfgCCDBDate.c_str()); + ccdblst = getCCDBInput(ccdb, cfgCCDBPathNameCorrections.c_str(), cfgCCDBDateCorrections.c_str(), true, cfgCCDBSuffix); } } @@ -962,21 +1239,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); } @@ -994,14 +1271,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}; @@ -1034,7 +1312,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); } @@ -1048,7 +1326,7 @@ struct DptDptCorrelationsTask { if (ccdblst == nullptr) { if (loadfromccdb) { - ccdblst = getCCDBInput(ccdb, cfgCCDBPathName.c_str(), cfgCCDBDate.c_str()); + ccdblst = getCCDBInput(ccdb, cfgCCDBPathNameCorrections.c_str(), cfgCCDBDateCorrections.c_str(), true, cfgCCDBSuffix); } } @@ -1068,14 +1346,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}; @@ -1116,20 +1395,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); + PROCESS_SWITCH(DptDptCorrelations, 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,16 +1426,16 @@ struct DptDptCorrelationsTask { LOGF(info, " First not assigned track index %d", firstNotAssignedIndex); LOGF(info, " Last not assigned track index %d", lastNotAssignedIndex); } - PROCESS_SWITCH(DptDptCorrelationsTask, processRecLevelCheck, "Process reco level checks", true); + PROCESS_SWITCH(DptDptCorrelations, 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 { @@ -1174,38 +1453,32 @@ struct DptDptCorrelationsTask { LOGF(info, " First not assigned track index %d", firstNotAssignedIndex); LOGF(info, " Last not assigned track index %d", lastNotAssignedIndex); } - PROCESS_SWITCH(DptDptCorrelationsTask, processGenLevelCheck, "Process generator level checks", true); + PROCESS_SWITCH(DptDptCorrelations, 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(DptDptCorrelationsTask, - processRecLevelNotStored, - "Process reco level correlations for not stored derived data", - true); + PROCESS_SWITCH(DptDptCorrelations, 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); } - PROCESS_SWITCH(DptDptCorrelationsTask, processGenLevel, "Process generator level correlations", false); + PROCESS_SWITCH(DptDptCorrelations, 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(DptDptCorrelationsTask, - processGenLevelNotStored, - "Process generator level correlations for not stored derived data", - false); + PROCESS_SWITCH(DptDptCorrelations, 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}; @@ -1213,16 +1486,17 @@ struct DptDptCorrelationsTask { SliceCache cache; using BinningZVtxMultRec = ColumnBinningPolicy; BinningZVtxMultRec bindingOnVtxAndMultRec{{vtxBinsEdges, multBinsEdges}, true}; // true is for 'ignore overflows' (true by default) + static constexpr int kNoOfLoggingCombinations = 10; - 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) { - if (logcomb < 10) { + for (auto const& [collision1, tracks1, collision2, tracks2] : pairreco) { + if (logcomb < kNoOfLoggingCombinations) { LOGF(DPTDPTLOGCOLLISIONS, "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"); @@ -1236,12 +1510,12 @@ struct DptDptCorrelationsTask { processMixed(collision1, tracks1, tracks2, collision1.bc_as().timestamp()); } } - PROCESS_SWITCH(DptDptCorrelationsTask, processRecLevelMixed, "Process reco level mixed events correlations", false); + PROCESS_SWITCH(DptDptCorrelations, 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>, @@ -1256,8 +1530,8 @@ struct DptDptCorrelationsTask { LOGF(DPTDPTLOGCOLLISIONS, "Received %d collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairreco) { - if (logcomb < 10) { + for (auto const& [collision1, tracks1, collision2, tracks2] : pairreco) { + if (logcomb < kNoOfLoggingCombinations) { LOGF(DPTDPTLOGCOLLISIONS, "Received collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", collision1.globalIndex(), @@ -1288,23 +1562,20 @@ struct DptDptCorrelationsTask { collision1.bc_as().timestamp()); } } - PROCESS_SWITCH(DptDptCorrelationsTask, - processRecLevelMixedNotStored, - "Process reco level mixed events correlations for not stored derived data", - false); + PROCESS_SWITCH(DptDptCorrelations, 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) { - if (logcomb < 10) { + for (auto const& [collision1, tracks1, collision2, tracks2] : pairgen) { + if (logcomb < kNoOfLoggingCombinations) { 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", collision2.globalIndex(), collision2.posZ(), collision2.centmult(), collision2.collisionaccepted() ? "accepted" : "not accepted"); @@ -1317,11 +1588,9 @@ struct DptDptCorrelationsTask { processMixed(collision1, tracks1, tracks2); } } - PROCESS_SWITCH(DptDptCorrelationsTask, processGenLevelMixed, "Process generator level mixed events correlations", false); + PROCESS_SWITCH(DptDptCorrelations, 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>, @@ -1336,8 +1605,8 @@ struct DptDptCorrelationsTask { LOGF(DPTDPTLOGCOLLISIONS, "Received %d generated collisions", collisions.size()); int logcomb = 0; - for (auto& [collision1, tracks1, collision2, tracks2] : pairgen) { - if (logcomb < 10) { + for (auto const& [collision1, tracks1, collision2, tracks2] : pairgen) { + if (logcomb < kNoOfLoggingCombinations) { LOGF(DPTDPTLOGCOLLISIONS, "Received generated collision pair: %ld (%f, %f): %s, %ld (%f, %f): %s", collision1.globalIndex(), @@ -1364,10 +1633,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(DptDptCorrelations, 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) @@ -1375,13 +1641,14 @@ struct DptDptCorrelationsTask { LOGF(DPTDPTLOGCOLLISIONS, "Got %d new collisions", colls.size()); fOutput->Clear(); } - PROCESS_SWITCH(DptDptCorrelationsTask, processCleaner, "Cleaner process for not used output", false); + PROCESS_SWITCH(DptDptCorrelations, processCleaner, "Cleaner process for not used output", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + o2::analysis::dptdptfilter::metadataInfo.initMetadata(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{"DptDptCorrelationsRec"}, SetDefaultProcesses{{{"processRecLevel", true}, {"processRecLevelMixed", false}, {"processCleaner", false}}}), // o2-linter: disable=name/o2-task (It is adapted multiple times) + adaptAnalysisTask(cfgc, TaskName{"DptDptCorrelationsGen"}, SetDefaultProcesses{{{"processGenLevel", false}, {"processGenLevelMixed", false}, {"processCleaner", true}}})}; // o2-linter: disable=name/o2-task (It is adapted multiple times) return workflow; } diff --git a/PWGCF/Tasks/dptdptfilterqa.cxx b/PWGCF/Tasks/dptDptFilterQa.cxx similarity index 67% rename from PWGCF/Tasks/dptdptfilterqa.cxx rename to PWGCF/Tasks/dptDptFilterQa.cxx index a8479d20d1a..876fd8ccb5e 100644 --- a/PWGCF/Tasks/dptdptfilterqa.cxx +++ b/PWGCF/Tasks/dptDptFilterQa.cxx @@ -9,14 +9,20 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include +/// \file dptDptFilterQa.cxx +/// \brief basic checks for the behavior of the filter task +/// \author victor.gonzalez.sebastian@gmail.com + +#include "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptDptFilter.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGCF/DataModel/DptDptFiltered.h" -#include "PWGCF/TableProducer/dptdptfilter.h" + +#include +#include using namespace o2; using namespace o2::framework; @@ -30,12 +36,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 +51,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&) @@ -86,42 +92,43 @@ struct DptDptFilterQA { FilteredTracks const& tracks) { using namespace o2::analysis::dptdptfilterqa; + static constexpr int kNoOfIclusiveParticles = 2; /* number of inclusive charged particles, aka positive and negative */ 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) { - if (!(track.trackacceptedid() < 0) && !(track.trackacceptedid() < 2)) { + int nTracksOne = 0; + int nTracksTwo = 0; + int nTracksOneAndTwo = 0; + int nTracksNone = 0; + for (auto const& track : tracks) { + if (!(track.trackacceptedid() < 0) && !(track.trackacceptedid() < kNoOfIclusiveParticles)) { 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 +141,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 +149,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/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..8f1b57ce348 100644 --- a/PWGCF/Tasks/match-reco-gen.cxx +++ b/PWGCF/Tasks/matchRecoGen.cxx @@ -9,22 +9,27 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include +/// \file matchRecoGen.cxx +/// \brief basic check for the matching between generator level and detector level +/// \author victor.gonzalez.sebastian@gmail.com +#include "PWGCF/Core/AnalysisConfigurableCuts.h" +#include "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptDptFilter.h" + +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.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/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 @@ -35,6 +40,10 @@ #include #include +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::soa; @@ -50,29 +59,20 @@ 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, - kNEGATIVE } colllabelsign; + kNEGATIVE, + kNOOFCOLLSIGNS } colllabelsign; enum { kMATCH = 0, kDONTMATCH }; @@ -82,44 +82,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 +122,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 +143,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 +173,7 @@ struct CheckGeneratorLevelVsDetectorLevel { auto track2 = tracks.iteratorAt(mclabelpos[collsign][ixpart][j]); if (track1.collisionId() != track2.collisionId()) { - nrec_poslabel_crosscoll++; + nRecPosLabelCrossColl++; crosscollfound = true; } } @@ -236,8 +212,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 +223,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 +273,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); } } @@ -325,7 +295,7 @@ struct CheckGeneratorLevelVsDetectorLevel { using namespace o2::analysis::recogenmap; using namespace o2::analysis::dptdptfilter; - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < kNOOFCOLLSIGNS; ++i) { mclabelpos[i].clear(); mclabelneg[i].clear(); mclabelpos[i].resize(mcParticles.size()); @@ -335,10 +305,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 +319,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(); @@ -379,7 +349,7 @@ struct CheckGeneratorLevelVsDetectorLevel { using namespace o2::analysis::recogenmap; using namespace o2::analysis::dptdptfilter; - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < kNOOFCOLLSIGNS; ++i) { mclabelpos[i].clear(); mclabelneg[i].clear(); mclabelpos[i].resize(mcParticles.size()); @@ -389,10 +359,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 +370,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 +393,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/Tutorial/CFTutorialTask1.cxx b/PWGCF/Tutorial/CFTutorialTask1.cxx index f79eb1871c2..d4f0360bdf0 100644 --- a/PWGCF/Tutorial/CFTutorialTask1.cxx +++ b/PWGCF/Tutorial/CFTutorialTask1.cxx @@ -12,11 +12,12 @@ /// \author Luca Barioglio // O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; diff --git a/PWGCF/Tutorial/CFTutorialTask2.cxx b/PWGCF/Tutorial/CFTutorialTask2.cxx index bf40ce17353..6402ed2d504 100644 --- a/PWGCF/Tutorial/CFTutorialTask2.cxx +++ b/PWGCF/Tutorial/CFTutorialTask2.cxx @@ -12,11 +12,12 @@ /// \author Luca Barioglio // O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; diff --git a/PWGCF/Tutorial/CFTutorialTask3.cxx b/PWGCF/Tutorial/CFTutorialTask3.cxx index 42b76f9f0db..7ddbe231b30 100644 --- a/PWGCF/Tutorial/CFTutorialTask3.cxx +++ b/PWGCF/Tutorial/CFTutorialTask3.cxx @@ -12,11 +12,12 @@ /// \author Luca Barioglio // O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; diff --git a/PWGCF/Tutorial/CFTutorialTask4.cxx b/PWGCF/Tutorial/CFTutorialTask4.cxx index a21f1ff7949..fdd79d9e9f4 100644 --- a/PWGCF/Tutorial/CFTutorialTask4.cxx +++ b/PWGCF/Tutorial/CFTutorialTask4.cxx @@ -12,12 +12,13 @@ /// \author Luca Barioglio // O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTPC.h" + #include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" #include "TLorentzVector.h" diff --git a/PWGCF/Tutorial/CFTutorialTask5.cxx b/PWGCF/Tutorial/CFTutorialTask5.cxx index 5357950aab1..bb99f0a36cc 100644 --- a/PWGCF/Tutorial/CFTutorialTask5.cxx +++ b/PWGCF/Tutorial/CFTutorialTask5.cxx @@ -12,12 +12,13 @@ /// \author Luca Barioglio // O2 includes -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTPC.h" + #include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" #include "TLorentzVector.h" diff --git a/PWGCF/TwoParticleCorrelations/Core/PIDSelectionFilterAndAnalysis.cxx b/PWGCF/TwoParticleCorrelations/Core/PIDSelectionFilterAndAnalysis.cxx index bfe06121f9e..d5b15a8db3f 100644 --- a/PWGCF/TwoParticleCorrelations/Core/PIDSelectionFilterAndAnalysis.cxx +++ b/PWGCF/TwoParticleCorrelations/Core/PIDSelectionFilterAndAnalysis.cxx @@ -9,14 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include +#include "PIDSelectionFilterAndAnalysis.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -#include "Common/DataModel/PIDResponse.h" -#include "PIDSelectionFilterAndAnalysis.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" + +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/PWGCF/TwoParticleCorrelations/DataModel/IdentifiedBfFiltered.h b/PWGCF/TwoParticleCorrelations/DataModel/IdentifiedBfFiltered.h deleted file mode 100644 index 96a5721d35c..00000000000 --- a/PWGCF/TwoParticleCorrelations/DataModel/IdentifiedBfFiltered.h +++ /dev/null @@ -1,115 +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. -#ifndef PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_IDENTIFIEDBFFILTERED_H_ -#define PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_IDENTIFIEDBFFILTERED_H_ - -#include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" - -namespace o2 -{ -namespace aod -{ -/* we have to change from int to bool when bool columns work properly */ -namespace identifiedbffilter -{ -DECLARE_SOA_COLUMN(IdentifiedBfCFCollisionAccepted, collisionaccepted, uint8_t); //! If the collision/event has been accepted or not -DECLARE_SOA_COLUMN(IdentifiedBfCFCollisionCentMult, centmult, float); //! The centrality/multiplicity pecentile -DECLARE_SOA_DYNAMIC_COLUMN(IsCollisionAccepted, //! Is the collision/event accepted - iscollisionaccepted, - [](uint8_t _collisionaccepted) -> uint8_t { return _collisionaccepted; }); -DECLARE_SOA_DYNAMIC_COLUMN(IsGenCollisionAccepted, //! Is the generated collision/event accepted - isgencollisionaccepted, - [](uint8_t _collisionaccepted) -> uint8_t { return _collisionaccepted; }); -} // namespace identifiedbffilter -DECLARE_SOA_TABLE(IdentifiedBfCFAcceptedCollisions, - "AOD", - "IBFCFACCCOLL", //! Accepted reconstructed collisions/events filtered table - o2::soa::Index<>, - collision::BCId, - collision::PosZ, - identifiedbffilter::IdentifiedBfCFCollisionAccepted, - identifiedbffilter::IdentifiedBfCFCollisionCentMult, - identifiedbffilter::IsCollisionAccepted); -using IdentifiedBfCFAcceptedCollision = IdentifiedBfCFAcceptedCollisions::iterator; -DECLARE_SOA_TABLE(IdentifiedBfCFAcceptedTrueCollisions, - "AOD", - "IBFCFACCGENCOLL", //! Accepted generated collisions/events filtered table - o2::soa::Index<>, - collision::BCId, - mccollision::PosZ, - identifiedbffilter::IdentifiedBfCFCollisionAccepted, - identifiedbffilter::IdentifiedBfCFCollisionCentMult, - identifiedbffilter::IsGenCollisionAccepted); -using IdentifiedBfCFAcceptedTrueCollision = IdentifiedBfCFAcceptedTrueCollisions::iterator; -DECLARE_SOA_TABLE( - IdentifiedBfCFCollisionsInfo, - "AOD", - "IBFCFCOLLINF", //! Accepted reconstructed collisions/events Collisions joinable table - identifiedbffilter::IdentifiedBfCFCollisionAccepted, - identifiedbffilter::IdentifiedBfCFCollisionCentMult, - identifiedbffilter::IsCollisionAccepted); -DECLARE_SOA_TABLE( - IdentifiedBfCFGenCollisionsInfo, - "AOD", - "IBFGENCFCOLLINF", //! Accepted generated collisions/events mcCollisions joinable table - identifiedbffilter::IdentifiedBfCFCollisionAccepted, - identifiedbffilter::IdentifiedBfCFCollisionCentMult, - identifiedbffilter::IsGenCollisionAccepted); -namespace identifiedbffilter -{ -DECLARE_SOA_INDEX_COLUMN(IdentifiedBfCFAcceptedCollision, event); //! Reconstructed collision/event -DECLARE_SOA_INDEX_COLUMN(IdentifiedBfCFAcceptedTrueCollision, mcevent); //! Generated collision/event -DECLARE_SOA_COLUMN(TrackacceptedId, - trackacceptedid, - int8_t); //! Id of accepted track, criteria: even (+) odd (-) -DECLARE_SOA_COLUMN(Pt, pt, float); //! The track transverse momentum -DECLARE_SOA_COLUMN(Eta, eta, float); //! The track pseudorapidity -DECLARE_SOA_COLUMN(Phi, phi, float); //! The track azimuthal angle -DECLARE_SOA_DYNAMIC_COLUMN(Sign, - sign, //! Charge: positive: 1, negative: -1 - [](int8_t trackacceptedid) -> int8_t { - return (trackacceptedid % 2 == 0 - ? 1 - : (trackacceptedid % 2 == 1 ? -1 : 0)); - }); -DECLARE_SOA_DYNAMIC_COLUMN(TrkID, - trkid, //! The track id - [](int8_t trackacceptedid) -> int8_t { return trackacceptedid; }); -DECLARE_SOA_DYNAMIC_COLUMN(PartID, - partid, //! The generated particle id - [](int8_t trackacceptedid) -> int8_t { return trackacceptedid; }); -} // namespace identifiedbffilter -DECLARE_SOA_TABLE(ScannedTracks, "AOD", "SCANNEDTRACKS", //! The reconstructed tracks filtered table - identifiedbffilter::IdentifiedBfCFAcceptedCollisionId, - identifiedbffilter::TrackacceptedId, - identifiedbffilter::Pt, - identifiedbffilter::Eta, - identifiedbffilter::Phi, - identifiedbffilter::Sign); -DECLARE_SOA_TABLE(ScannedTrueTracks, "AOD", "SCANTRUETRACKS", //! The generated particles filtered table - identifiedbffilter::IdentifiedBfCFAcceptedTrueCollisionId, - identifiedbffilter::TrackacceptedId, - identifiedbffilter::Pt, - identifiedbffilter::Eta, - identifiedbffilter::Phi, - identifiedbffilter::Sign); -DECLARE_SOA_TABLE(IdentifiedBfCFTracksInfo, "AOD", "SCANDTRCKINF", //! The additional information Tracks joinable table - identifiedbffilter::TrackacceptedId, - identifiedbffilter::TrkID); -DECLARE_SOA_TABLE(IdentifiedBfCFGenTracksInfo, "AOD", "SCANDGENTRCKINF", //! The additional information mcParticle joinable table - identifiedbffilter::TrackacceptedId, - identifiedbffilter::Sign, - identifiedbffilter::PartID); -} // namespace aod -} // namespace o2 - -#endif // PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_IDENTIFIEDBFFILTERED_H_ diff --git a/PWGCF/TwoParticleCorrelations/DataModel/LongRangeDerived.h b/PWGCF/TwoParticleCorrelations/DataModel/LongRangeDerived.h new file mode 100644 index 00000000000..f9b79242ac0 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/DataModel/LongRangeDerived.h @@ -0,0 +1,214 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file LongRangeDerived.h +/// +/// \brief task derived table definition for long range correlation +/// \author Abhi Modak (abhi.modak@cern.ch) +/// \since October 28, 2025 + +#ifndef PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_LONGRANGEDERIVED_H_ +#define PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_LONGRANGEDERIVED_H_ + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace lrcorrcolltable +{ +DECLARE_SOA_COLUMN(Zvtx, zvtx, float); +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); +DECLARE_SOA_COLUMN(Centrality, centrality, float); +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); //! sum of amplitudes on A side of FT0 +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); //! sum of amplitudes on C side of FT0 +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); //! sum of amplitudes on A side of FDD +DECLARE_SOA_COLUMN(GapSide, gapSide, uint8_t); // 0 for side A, 1 for side C, 2 for both sides +} // namespace lrcorrcolltable + +DECLARE_SOA_TABLE(CollLRTables, "AOD", "COLLLRTABLE", + o2::soa::Index<>, + bc::RunNumber, + lrcorrcolltable::Zvtx, + lrcorrcolltable::Multiplicity, + lrcorrcolltable::Centrality, + timestamp::Timestamp); +using CollLRTable = CollLRTables::iterator; + +DECLARE_SOA_TABLE(UpcCollLRTables, "AOD", "UPCCOLLLRTABLE", + o2::soa::Index<>, + bc::GlobalBC, + bc::RunNumber, + lrcorrcolltable::Zvtx, + lrcorrcolltable::Multiplicity, + lrcorrcolltable::TotalFT0AmplitudeA, + lrcorrcolltable::TotalFT0AmplitudeC, + lrcorrcolltable::TotalFV0AmplitudeA); +using UpcCollLRTable = UpcCollLRTables::iterator; + +DECLARE_SOA_TABLE(UpcSgCollLRTables, "AOD", "UPCSGCOLLLRTABLE", + lrcorrcolltable::GapSide); +using UpcSgCollLRTable = UpcSgCollLRTables::iterator; + +namespace lrcorrzdctable +{ +DECLARE_SOA_INDEX_COLUMN(UpcCollLRTable, upcCollLRTable); +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +} // namespace lrcorrzdctable + +DECLARE_SOA_TABLE(ZdcLRTables, "AOD", "ZDCLRTABLE", + o2::soa::Index<>, + lrcorrzdctable::UpcCollLRTableId, + lrcorrzdctable::EnergyCommonZNA, + lrcorrzdctable::EnergyCommonZNC); +using ZdcLRTable = ZdcLRTables::iterator; + +namespace lrcorrtrktable +{ +DECLARE_SOA_INDEX_COLUMN(CollLRTable, collLRTable); +DECLARE_SOA_INDEX_COLUMN(UpcCollLRTable, upcCollLRTable); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(ChannelID, channelID, int); +DECLARE_SOA_COLUMN(Amplitude, amplitude, float); +DECLARE_SOA_COLUMN(InvMass, invMass, float); +DECLARE_SOA_COLUMN(IdPos, idPos, int64_t); +DECLARE_SOA_COLUMN(IdNeg, idNeg, int64_t); +DECLARE_SOA_COLUMN(TrackType, trackType, uint8_t); +DECLARE_SOA_COLUMN(V0Type, v0Type, uint8_t); +enum TrackPid { + kSpCharge, + kSpPion, + kSpKaon, + kSpProton +}; +enum V0TrackPid { + kSpK0short, + kSpLambda, + kSpALambda +}; +} // namespace lrcorrtrktable + +DECLARE_SOA_TABLE(TrkLRTables, "AOD", "TRKLRTABLE", + o2::soa::Index<>, + lrcorrtrktable::CollLRTableId, + lrcorrtrktable::Pt, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi, + lrcorrtrktable::TrackType); +using TrkLRTable = TrkLRTables::iterator; + +DECLARE_SOA_TABLE(Ft0aLRTables, "AOD", "FT0ALRTABLE", + o2::soa::Index<>, + lrcorrtrktable::CollLRTableId, + lrcorrtrktable::ChannelID, + lrcorrtrktable::Amplitude, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi); +using Ft0aLRTable = Ft0aLRTables::iterator; + +DECLARE_SOA_TABLE(Ft0cLRTables, "AOD", "FT0CLRTABLE", + o2::soa::Index<>, + lrcorrtrktable::CollLRTableId, + lrcorrtrktable::ChannelID, + lrcorrtrktable::Amplitude, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi); +using Ft0cLRTable = Ft0cLRTables::iterator; + +DECLARE_SOA_TABLE(V0TrkLRTables, "AOD", "V0TRKLRTABLE", + o2::soa::Index<>, + lrcorrtrktable::CollLRTableId, + lrcorrtrktable::IdPos, + lrcorrtrktable::IdNeg, + lrcorrtrktable::Pt, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi, + lrcorrtrktable::InvMass, + lrcorrtrktable::V0Type); +using V0TrkLRTable = V0TrkLRTables::iterator; + +DECLARE_SOA_TABLE(MftTrkLRTables, "AOD", "MFTTRKLRTABLE", + o2::soa::Index<>, + lrcorrtrktable::CollLRTableId, + lrcorrtrktable::Pt, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi); +using MftTrkLRTable = MftTrkLRTables::iterator; + +DECLARE_SOA_TABLE(MftBestTrkLRTables, "AOD", "MFTBESTTRKLRTABLE", + o2::soa::Index<>, + lrcorrtrktable::CollLRTableId, + lrcorrtrktable::Pt, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi); +using MftBestTrkLRTable = MftBestTrkLRTables::iterator; + +DECLARE_SOA_TABLE(TrkLRUpcTables, "AOD", "TRKLRUPCTABLE", + o2::soa::Index<>, + lrcorrtrktable::UpcCollLRTableId, + lrcorrtrktable::Pt, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi, + lrcorrtrktable::TrackType); +using TrkLRUpcTable = TrkLRUpcTables::iterator; + +DECLARE_SOA_TABLE(Ft0aLRUpcTables, "AOD", "FT0ALRUpcTABLE", + o2::soa::Index<>, + lrcorrtrktable::UpcCollLRTableId, + lrcorrtrktable::ChannelID, + lrcorrtrktable::Amplitude, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi); +using Ft0aLRUpcTable = Ft0aLRUpcTables::iterator; + +DECLARE_SOA_TABLE(Ft0cLRUpcTables, "AOD", "FT0CLRUpcTABLE", + o2::soa::Index<>, + lrcorrtrktable::UpcCollLRTableId, + lrcorrtrktable::ChannelID, + lrcorrtrktable::Amplitude, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi); +using Ft0cLRUpcTable = Ft0cLRUpcTables::iterator; + +DECLARE_SOA_TABLE(V0TrkLRUpcTables, "AOD", "V0TRKLRUPCTABLE", + o2::soa::Index<>, + lrcorrtrktable::UpcCollLRTableId, + lrcorrtrktable::IdPos, + lrcorrtrktable::IdNeg, + lrcorrtrktable::Pt, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi, + lrcorrtrktable::InvMass, + lrcorrtrktable::V0Type); +using V0TrkLRUpcTable = V0TrkLRUpcTables::iterator; + +DECLARE_SOA_TABLE(MftTrkLRUpcTables, "AOD", "MFTTRKLRUPCTABLE", + o2::soa::Index<>, + lrcorrtrktable::UpcCollLRTableId, + lrcorrtrktable::Pt, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi); +using MftTrkLRUpcTable = MftTrkLRUpcTables::iterator; + +DECLARE_SOA_TABLE(MftBestTrkLRUpcTables, "AOD", "MFTBESTTRKLRUPCTABLE", + o2::soa::Index<>, + lrcorrtrktable::UpcCollLRTableId, + lrcorrtrktable::Pt, + lrcorrtrktable::Eta, + lrcorrtrktable::Phi); +using MftBestTrkLRUpcTable = MftBestTrkLRUpcTables::iterator; + +} // namespace o2::aod + +#endif // PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_LONGRANGEDERIVED_H_ diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt b/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt index 4bc1d428324..0669a351d1e 100644 --- a/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt +++ b/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt @@ -9,27 +9,27 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -o2physics_add_dpl_workflow(twopartcorr-register-skim +o2physics_add_dpl_workflow(two-particle-correlations-register-skimming SOURCES twoParticleCorrelationsRegisterSkimming.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::TwoPartCorrCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(twopartcorr-skim +o2physics_add_dpl_workflow(two-particle-correlations-full-skimming SOURCES twoParticleCorrelationsFullSkimming.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::TwoPartCorrCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(twopartcorr-notstored-skim +o2physics_add_dpl_workflow(two-particle-correlations-not-stored-skimming SOURCES twoParticleCorrelationsNotStoredSkimming.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::TwoPartCorrCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(twopartcorr-filter +o2physics_add_dpl_workflow(two-particle-correlations-filtering SOURCES twoParticleCorrelationsFiltering.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::TwoPartCorrCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(identifiedbf-filter - SOURCES identifiedBfFilter.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore +o2physics_add_dpl_workflow(longrange-maker + SOURCES longrangeMaker.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::TwoPartCorrCore O2Physics::SGCutParHolder COMPONENT_NAME Analysis) diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.cxx b/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.cxx deleted file mode 100644 index e5f2aa908ca..00000000000 --- a/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.cxx +++ /dev/null @@ -1,1507 +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 "PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h" - -#include -#include - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include "PWGCF/TwoParticleCorrelations/DataModel/IdentifiedBfFiltered.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "Framework/runDataProcessing.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace o2; -using namespace o2::framework; -using namespace o2::soa; -using namespace o2::framework::expressions; -using namespace o2::analysis; - -#define IDENTIFIEDBFFILTERLOGCOLLISIONS debug -#define IDENTIFIEDBFFILTERLOGTRACKS debug - -namespace o2::analysis::identifiedbffilter -{ -using IdBfFullTracks = soa::Join; -using IdBfFullTracksAmbiguous = 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 */ - -//============================================================================================ -// The IdentifiedBfFilter histogram objects -// TODO: consider registering in the histogram registry -//============================================================================================ -TH1F* fhCentMultB = nullptr; -TH1F* fhCentMultA = nullptr; -TH1F* fhVertexZB = nullptr; -TH1F* fhVertexZA = nullptr; -TH1F* fhMultB = nullptr; -TH1F* fhMultA = nullptr; -TH1F* fhPB = nullptr; -TH1F* fhPA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhPtB = nullptr; -TH1F* fhPtA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhPtPosB = nullptr; -TH1F* fhPtPosA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhPtNegB = nullptr; -TH1F* fhPtNegA[kIdBfNoOfSpecies] = {nullptr}; -TH2F* fhNPosNegA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhDeltaNA[kIdBfNoOfSpecies] = {nullptr}; - -TH2F* fhNSigmaTPC[kIdBfNoOfSpecies] = {nullptr}; -TH2F* fhNSigmaTOF[kIdBfNoOfSpecies] = {nullptr}; -TH2F* fhNSigmaCombo[kIdBfNoOfSpecies] = {nullptr}; -TH2F* fhNSigmaTPC_IdTrks[kIdBfNoOfSpecies] = {nullptr}; - -TH1F* fhEtaB = nullptr; -TH1F* fhEtaA = nullptr; - -TH1F* fhPhiB = nullptr; -TH1F* fhPhiA = nullptr; - -TH2F* fhdEdxB = nullptr; -TH2F* fhdEdxIPTPCB = nullptr; -TH2F* fhdEdxA[kIdBfNoOfSpecies + 1] = {nullptr}; -TH2F* fhdEdxIPTPCA[kIdBfNoOfSpecies + 1] = {nullptr}; - -TH2S* fhDoublePID = nullptr; - -TH1F* fhDCAxyB = nullptr; -TH1F* fhDCAxyA = nullptr; -TH1F* fhFineDCAxyA = nullptr; -TH1F* fhDCAzB = nullptr; -TH1F* fhDCAzA = nullptr; -TH1F* fhFineDCAzA = nullptr; - -TH1F* fhWrongTrackID = nullptr; - -TH2D* fhAmbiguousTrackType = nullptr; -TH2F* fhAmbiguousTrackPt = nullptr; -TH2F* fhAmbiguityDegree = nullptr; -TH2F* fhCompatibleCollisionsZVtxRms = nullptr; - -TH1F* fhTrueCentMultB = nullptr; -TH1F* fhTrueCentMultA = nullptr; -TH1F* fhTrueVertexZB = nullptr; -TH1F* fhTrueVertexZA = nullptr; -TH1F* fhTrueVertexZAA = nullptr; -TH1F* fhTruePB = nullptr; -TH1F* fhTruePA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhTruePtB = nullptr; -TH1F* fhTruePtA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhTruePtPosB = nullptr; -TH1F* fhTruePtPosA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhTruePtNegB = nullptr; -TH1F* fhTruePtNegA[kIdBfNoOfSpecies] = {nullptr}; -TH2F* fhTrueNPosNegA[kIdBfNoOfSpecies] = {nullptr}; -TH1F* fhTrueDeltaNA[kIdBfNoOfSpecies] = {nullptr}; - -TH1F* fhTrueEtaB = nullptr; -TH1F* fhTrueEtaA = nullptr; - -TH1F* fhTruePhiB = nullptr; -TH1F* fhTruePhiA = nullptr; - -TH1F* fhTrueDCAxyB = nullptr; -TH1F* fhTrueDCAxyA = nullptr; -TH1F* fhTrueDCAzB = nullptr; -TH1F* fhTrueDCAxyBid = nullptr; -TH1F* fhTrueDCAzA = nullptr; - -//============================================================================================ -// The IdentifiedBfFilter multiplicity counters -//============================================================================================ -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", - {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"}; - - OutputObj fOutput{"IdentifiedBfFilterCollisionsInfo", OutputObjHandlingPolicy::AnalysisObject}; - - Produces acceptedcollisions; - Produces collisionsinfo; - Produces acceptedtrueevents; - Produces gencollisionsinfo; - - void init(InitContext const&) - { - using namespace identifiedbffilter; - - LOGF(info, "IdentifiedBfFilterTask::init()"); - - fullDerivedData = cfgFullDerivedData; - - /* update with the configurable values */ - /* 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 */ - /* the centrality/multiplicity estimation */ - fCentMultEstimator = getCentMultEstimator(cfgCentMultEstimator); - /* the trigger selection */ - fTriggerSelection = getTriggerSelection(cfgTriggSel); - 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); - - /* create the output list which will own the task histograms */ - TList* fOutputList = new TList(); - fOutputList->SetOwner(true); - fOutput.setObject(fOutputList); - - if ((fDataType == kData) || (fDataType == kDataNoEvtSel) || (fDataType == kMC)) { - /* create the reconstructed data histograms */ - /* TODO: proper axes and axes titles according to the system; still incomplete */ - std::string multestimator = getCentMultEstimatorName(fCentMultEstimator); - if (fSystem > kPbp) { - fhCentMultB = new TH1F("CentralityB", "Centrality before cut; centrality (%)", 100, 0, 100); - fhCentMultA = new TH1F("CentralityA", "Centrality; centrality (%)", 100, 0, 100); - fhMultB = new TH1F("MultB", TString::Format("%s Multiplicity before cut;%s Multiplicity;Collisions", multestimator.c_str(), multestimator.c_str()), 4001, -0.5, 4000.5); - fhMultA = new TH1F("MultA", TString::Format("%s Multiplicity;%s Multiplicity;Collisions", multestimator.c_str(), multestimator.c_str()), 4001, -0.5, 4000.5); - } else { - /* for pp, pPb and Pbp systems use multiplicity instead */ - fhCentMultB = new TH1F("MultiplicityB", "Multiplicity before cut; multiplicity (%)", 100, 0, 100); - fhCentMultA = new TH1F("MultiplicityA", "Multiplicity; multiplicity (%)", 100, 0, 100); - fhMultB = new TH1F("MultB", TString::Format("%s Multiplicity before cut;%s Multiplicity;Collisions", multestimator.c_str(), multestimator.c_str()), 601, -0.5, 600.5); - fhMultA = new TH1F("MultA", TString::Format("%s Multiplicity;%s Multiplicity;Collisions", multestimator.c_str(), multestimator.c_str()), 601, -0.5, 600.5); - } - - fhVertexZB = new TH1F("VertexZB", "Vertex Z; z_{vtx}", 60, -15, 15); - fhVertexZA = new TH1F("VertexZA", "Vertex Z; z_{vtx}", zvtxbins, zvtxlow, zvtxup); - - /* add the hstograms to the output list */ - fOutputList->Add(fhCentMultB); - fOutputList->Add(fhCentMultA); - fOutputList->Add(fhMultB); - fOutputList->Add(fhMultA); - fOutputList->Add(fhVertexZB); - fOutputList->Add(fhVertexZA); - } - - if ((fDataType != kData) && (fDataType != kDataNoEvtSel)) { - /* create the true data histograms */ - /* TODO: proper axes and axes titles according to the system; still incomplete */ - if (fSystem > kPbp) { - fhTrueCentMultB = new TH1F("TrueCentralityB", "Centrality before (truth); centrality (%)", 100, 0, 100); - fhTrueCentMultA = new TH1F("TrueCentralityA", "Centrality (truth); centrality (%)", 100, 0, 100); - } else { - /* for pp, pPb and Pbp systems use multiplicity instead */ - fhTrueCentMultB = new TH1F("TrueMultiplicityB", "Multiplicity before (truth); multiplicity (%)", 100, 0, 100); - fhTrueCentMultA = new TH1F("TrueMultiplicityA", "Multiplicity (truth); multiplicity (%)", 100, 0, 100); - } - - 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); - - /* add the hstograms to the output list */ - fOutputList->Add(fhTrueCentMultB); - fOutputList->Add(fhTrueCentMultA); - fOutputList->Add(fhTrueVertexZB); - fOutputList->Add(fhTrueVertexZA); - fOutputList->Add(fhTrueVertexZAA); - } - } - - template - void processReconstructed(CollisionObject const& collision, TracksObject const& ftracks, float centormult); - - void processWithCent(aod::CollisionEvSelCent const& collision, IdBfFullTracks const& ftracks); - PROCESS_SWITCH(IdentifiedBfFilter, processWithCent, "Process reco with centrality", false); - - void processWithRun2Cent(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracks const& ftracks); - PROCESS_SWITCH(IdentifiedBfFilter, processWithRun2Cent, "Process reco with Run !/2 centrality", false); - - void processWithoutCent(aod::CollisionEvSel const& collision, IdBfFullTracks const& ftracks); - PROCESS_SWITCH(IdentifiedBfFilter, processWithoutCent, "Process reco without centrality", false); - - void processWithCentPID(aod::CollisionEvSelCent const& collision, IdBfFullTracksPID const& ftracks); - PROCESS_SWITCH(IdentifiedBfFilter, processWithCentPID, "Process PID reco with centrality", false); - - void processWithRun2CentPID(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksPID const& ftracks); - PROCESS_SWITCH(IdentifiedBfFilter, processWithRun2CentPID, "Process PID reco with centrality", false); - - 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); - - void processWithRun2CentDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksDetLevel const& ftracks, aod::McParticles const&); - PROCESS_SWITCH(IdentifiedBfFilter, processWithRun2CentDetectorLevel, "Process MC detector level with centrality", false); - - void processWithoutCentDetectorLevel(aod::CollisionEvSel const& collision, IdBfFullTracksDetLevel const& ftracks, aod::McParticles const&); - PROCESS_SWITCH(IdentifiedBfFilter, processWithoutCentDetectorLevel, "Process MC detector level without centrality", false); - - void processWithCentPIDDetectorLevel(aod::CollisionEvSelCent const& collision, IdBfFullTracksPIDDetLevel const& ftracks, aod::McParticles const&); - PROCESS_SWITCH(IdentifiedBfFilter, processWithCentPIDDetectorLevel, "Process PID MC detector level with centrality", false); - - void processWithRun2CentPIDDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksPIDDetLevel const& ftracks, aod::McParticles const&); - PROCESS_SWITCH(IdentifiedBfFilter, processWithRun2CentPIDDetectorLevel, "Process PID MC detector level with centrality", false); - - 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); - - template - void processGeneratorLevel(aod::McCollision const& mccollision, - CollisionsGroup const& collisions, - aod::McParticles const& mcparticles, - AllCollisions const& allcollisions, - float defaultcent); - - void processWithCentGeneratorLevel(aod::McCollision const& mccollision, - soa::SmallGroups> const& collisions, - aod::McParticles const& mcparticles, - aod::CollisionsEvSelCent const& allcollisions); - PROCESS_SWITCH(IdentifiedBfFilter, processWithCentGeneratorLevel, "Process generated with centrality", false); - - void processWithRun2CentGeneratorLevel(aod::McCollision const& mccollision, - soa::SmallGroups> const& collisions, - aod::McParticles const& mcparticles, - aod::CollisionsEvSelRun2Cent const& allcollisions); - PROCESS_SWITCH(IdentifiedBfFilter, processWithRun2CentGeneratorLevel, "Process generated with centrality", false); - - void processWithoutCentGeneratorLevel(aod::McCollision const& mccollision, - soa::SmallGroups> const& collisions, - aod::McParticles const& mcparticles, - aod::CollisionsEvSel const& allcollisions); - PROCESS_SWITCH(IdentifiedBfFilter, processWithoutCentGeneratorLevel, "Process generated without centrality", false); - - void processVertexGenerated(aod::McCollisions const&); - PROCESS_SWITCH(IdentifiedBfFilter, processVertexGenerated, "Process vertex generator level", false); -}; - -template -void IdentifiedBfFilter::processReconstructed(CollisionObject const& collision, TracksObject const& ftracks, float tentativecentmult) -{ - using namespace identifiedbffilter; - - LOGF(IDENTIFIEDBFFILTERLOGCOLLISIONS, "IdentifiedBfFilterTask::processReconstructed(). New collision with %d tracks", ftracks.size()); - - float mult = extractMultiplicity(collision, fCentMultEstimator); - - fhCentMultB->Fill(tentativecentmult); - fhMultB->Fill(mult); - fhVertexZB->Fill(collision.posZ()); - uint8_t acceptedevent = uint8_t(false); - float centormult = tentativecentmult; - if (IsEvtSelected(collision, centormult)) { - acceptedevent = true; - fhCentMultA->Fill(centormult); - fhMultA->Fill(mult); - fhVertexZA->Fill(collision.posZ()); - if (fullDerivedData) { - acceptedcollisions(collision.bcId(), collision.posZ(), acceptedevent, centormult); - } else { - collisionsinfo(acceptedevent, centormult); - } - } else { - if (!fullDerivedData) { - /* the tracks are done at a different level */ - collisionsinfo(uint8_t(false), 105.0); - } - } -} - -void IdentifiedBfFilter::processWithCent(aod::CollisionEvSelCent const& collision, IdBfFullTracks const& ftracks) -{ - processReconstructed(collision, ftracks, getCentMultPercentile(collision)); -} - -void IdentifiedBfFilter::processWithRun2Cent(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracks const& ftracks) -{ - processReconstructed(collision, ftracks, getCentMultPercentile(collision)); -} - -void IdentifiedBfFilter::processWithoutCent(aod::CollisionEvSel const& collision, IdBfFullTracks const& ftracks) -{ - processReconstructed(collision, ftracks, 50.0); -} - -void IdentifiedBfFilter::processWithCentPID(aod::CollisionEvSelCent const& collision, IdBfFullTracksPID const& ftracks) -{ - processReconstructed(collision, ftracks, getCentMultPercentile(collision)); -} - -void IdentifiedBfFilter::processWithRun2CentPID(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksPID const& ftracks) -{ - processReconstructed(collision, ftracks, getCentMultPercentile(collision)); -} - -void IdentifiedBfFilter::processWithoutCentPID(aod::CollisionEvSel const& collision, IdBfFullTracksPID const& ftracks) -{ - 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)); -} - -void IdentifiedBfFilter::processWithRun2CentDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksDetLevel const& ftracks, aod::McParticles const&) -{ - processReconstructed(collision, ftracks, getCentMultPercentile(collision)); -} - -void IdentifiedBfFilter::processWithoutCentDetectorLevel(aod::CollisionEvSel const& collision, IdBfFullTracksDetLevel const& ftracks, aod::McParticles const&) -{ - processReconstructed(collision, ftracks, 50.0); -} - -void IdentifiedBfFilter::processWithCentPIDDetectorLevel(aod::CollisionEvSelCent const& collision, IdBfFullTracksPIDDetLevel const& ftracks, aod::McParticles const&) -{ - processReconstructed(collision, ftracks, getCentMultPercentile(collision)); -} - -void IdentifiedBfFilter::processWithRun2CentPIDDetectorLevel(aod::CollisionEvSelRun2Cent const& collision, IdBfFullTracksPIDDetLevel const& ftracks, aod::McParticles const&) -{ - processReconstructed(collision, ftracks, getCentMultPercentile(collision)); -} - -void IdentifiedBfFilter::processWithoutCentPIDDetectorLevel(aod::CollisionEvSel const& collision, IdBfFullTracksPIDDetLevel const& ftracks, aod::McParticles const&) -{ - 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)) { - acceptedevent = uint8_t(true); - } - if (fullDerivedData) { - acceptedtrueevents(mccollision.bcId(), mccollision.posZ(), acceptedevent, centormult); - } else { - gencollisionsinfo(acceptedevent, centormult); - } -} - -template -void IdentifiedBfFilter::processGeneratorLevel(aod::McCollision const& mccollision, - CollisionsGroup const& collisions, - aod::McParticles const& mcparticles, - AllCollisions const& allcollisions, - float defaultcent) -{ - using namespace identifiedbffilter; - - LOGF(IDENTIFIEDBFFILTERLOGCOLLISIONS, "IdentifiedBfFilterTask::processGeneratorLevel(). New generated collision with %d reconstructed collisions and %d particles", collisions.size(), mcparticles.size()); - - if (collisions.size() > 1) { - LOGF(IDENTIFIEDBFFILTERLOGCOLLISIONS, "IdentifiedBfFilterTask::processGeneratorLevel(). Generated collision with more than one reconstructed collisions. Processing only the first accepted for centrality/multiplicity classes extraction"); - } - - bool processed = false; - for (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())); - processGenerated(mccollision, mcparticles, defaultcent); - processed = true; - break; /* TODO: only processing the first reconstructed accepted collision */ - } - } - } - } - if (!processed && !fullDerivedData) { - gencollisionsinfo(uint8_t(false), 105.0); - } -} - -void IdentifiedBfFilter::processWithCentGeneratorLevel(aod::McCollision const& mccollision, - soa::SmallGroups> const& collisions, - aod::McParticles const& mcparticles, - aod::CollisionsEvSelCent const& allcollisions) -{ - processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, 50.0); -} - -void IdentifiedBfFilter::processWithRun2CentGeneratorLevel(aod::McCollision const& mccollision, - soa::SmallGroups> const& collisions, - aod::McParticles const& mcparticles, - aod::CollisionsEvSelRun2Cent const& allcollisions) -{ - processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, 50.0); -} - -void IdentifiedBfFilter::processWithoutCentGeneratorLevel(aod::McCollision const& mccollision, - soa::SmallGroups> const& collisions, - aod::McParticles const& mcparticles, - aod::CollisionsEvSel const& allcollisions) -{ - processGeneratorLevel(mccollision, collisions, mcparticles, allcollisions, 50.0); -} - -void IdentifiedBfFilter::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)) { - fhTrueVertexZA->Fill((mccollision.posZ())); - } - } -} - -/// RMS calculation. Taken from PWGHF/Tasks/taskMcValidation.cxx -/// \param vec vector of values to compute RMS -template -T computeRMS(std::vector& vec) -{ - T sum = std::accumulate(vec.begin(), vec.end(), 0.0); - T mean = sum / vec.size(); - - 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()); - - return stdev; -} - -struct IdentifiedBfFilterTracks { - 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", - {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 reqTOF{"requireTOF", 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"}; - - OutputObj fOutput{"IdentifiedBfFilterTracksInfo", OutputObjHandlingPolicy::AnalysisObject}; - bool checkAmbiguousTracks = false; - - void init(InitContext&) - { - LOGF(info, "IdentifiedBfFilterTracks::init()"); - - fullDerivedData = cfgFullDerivedData; - - /* update with the configurable values */ - /* 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(); - traceDCAOutliers = cfgTraceDCAOutliers; - traceOutOfSpeciesParticles = cfgTraceOutOfSpeciesParticles; - recoIdMethod = cfgRecoIdMethod; - if (cfgTrackSelection->mUseIt) { - useOwnTrackSelection = true; - if (cfgTrackSelection->mOnGen) { - useOwnParticleSelection = true; - particleMaxDCAxy = cfgTrackSelection->mDCAxy; - particleMaxDCAZ = cfgTrackSelection->mDCAz; - } - ownTrackSelection.ResetITSRequirements(); - ownTrackSelection.SetMinNClustersTPC(cfgTrackSelection->mTPCclusters); - ownTrackSelection.SetMinNCrossedRowsTPC(cfgTrackSelection->mTPCxRows); - ownTrackSelection.SetMaxDcaXYPtDep([&](float) { return cfgTrackSelection->mDCAxy; }); - ownTrackSelection.SetMaxDcaXY(cfgTrackSelection->mDCAxy); - ownTrackSelection.SetMaxDcaZ(cfgTrackSelection->mDCAz); - o2::aod::track::TrackTypeEnum ttype; - switch (tracktype) { - case 1: - ttype = o2::aod::track::Run2Track; - break; - case 3: - ttype = o2::aod::track::Track; - break; - default: - ttype = o2::aod::track::Track; - break; - } - ownTrackSelection.SetTrackType(ttype); - } else { - useOwnTrackSelection = false; - } - - /* 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) { - checkAmbiguousTracks = true; - } - - /* 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); - 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); - fhPtNegB = new TH1F("fHistPtNegB", "P_{T} distribution for reconstructed (#minus) before;P_{T} (GeV/c);dN/dP_{T} (c/GeV)", 100, 0.0, 15.0); - 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; 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); - 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); - - 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); - fhAmbiguousTrackPt = new TH2F("fHistAmbiguousTracksPt", "Ambiguous tracks #it{p}_{T} vs. multiplicity class;#it{p}_{T} (GeV/#it{c});Multiplicity (%);counts", 100, 0.0, 15.0, 101, -0.5, 100.5); - fhAmbiguityDegree = new TH2F("fHistAmbiguityDegree", "Ambiguity degree vs. multiplicity class;Ambiguity degree;Multiplicity (%);counts", 31, -0.5, 30.5, 101, -0.5, 100.5); - fhCompatibleCollisionsZVtxRms = new TH2F("fHistCompatibleCollisionsZVtxRms", "Compatible collisions #it{z}_{vtx} RMS;#sigma_{#it{z}_{vtx}};Multiplicity (%);counts", 100, -10.0, 10.0, 101, -0.5, 100.5); - } - - for (int sp = 0; sp < kIdBfNoOfSpecies; ++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); - fhPtA[sp] = new TH1F(TString::Format("fHistPtA_%s", speciesName[sp]), - TString::Format("p_{T} distribution for reconstructed %s;p_{T} (GeV/c);dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), - ptbins, ptlow, ptup); - fhPtPosA[sp] = new TH1F(TString::Format("fHistPtPosA_%s", speciesName[sp]), - TString::Format("P_{T} distribution for reconstructed %s^{#plus};P_{T} (GeV/c);dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), - ptbins, ptlow, ptup); - 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); - 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); - fhDeltaNA[sp] = new TH1F(TString::Format("fhDeltaNA_%s", speciesName[sp]).Data(), - 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); - 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); - fhNSigmaTPC_IdTrks[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); - fhdEdxA[sp] = new TH2F(TString::Format("fhdEdxA_%s", speciesName[sp]).Data(), - 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); - } - fhdEdxA[kIdBfNoOfSpecies] = 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] = 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); - /* add the hstograms to the output list */ - fOutputList->Add(fhPB); - fOutputList->Add(fhPtB); - fOutputList->Add(fhPtPosB); - fOutputList->Add(fhPtNegB); - fOutputList->Add(fhEtaB); - fOutputList->Add(fhEtaA); - fOutputList->Add(fhPhiB); - fOutputList->Add(fhPhiA); - fOutputList->Add(fhdEdxB); - fOutputList->Add(fhdEdxIPTPCB); - fOutputList->Add(fhDCAxyB); - fOutputList->Add(fhDCAxyA); - 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); - fOutputList->Add(fhAmbiguityDegree); - fOutputList->Add(fhCompatibleCollisionsZVtxRms); - } - - for (int sp = 0; sp < kIdBfNoOfSpecies; ++sp) { - fOutputList->Add(fhPA[sp]); - fOutputList->Add(fhPtA[sp]); - fOutputList->Add(fhPtPosA[sp]); - fOutputList->Add(fhPtNegA[sp]); - fOutputList->Add(fhNPosNegA[sp]); - fOutputList->Add(fhDeltaNA[sp]); - fOutputList->Add(fhNSigmaTPC[sp]); - fOutputList->Add(fhNSigmaTOF[sp]); - fOutputList->Add(fhNSigmaCombo[sp]); - fOutputList->Add(fhNSigmaTPC_IdTrks[sp]); - fOutputList->Add(fhdEdxA[sp]); - fOutputList->Add(fhdEdxIPTPCA[sp]); - } - fOutputList->Add(fhdEdxA[kIdBfNoOfSpecies]); - fOutputList->Add(fhdEdxIPTPCA[kIdBfNoOfSpecies]); - } - - if ((fDataType != kData) && (fDataType != kDataNoEvtSel)) { - /* create the true data histograms */ - fhTruePB = new TH1F("fTrueHistPB", "p distribution before (truth);p (GeV/c);dN/dp (c/GeV)", 100, 0.0, 15.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); - fhTrueEtaB = new TH1F("fTrueHistEtaB", "#eta distribution before (truth);#eta;counts", 40, -2.0, 2.0); - fhTrueEtaA = new TH1F("fTrueHistEtaA", "#eta distribution (truth);#eta;counts", etabins, etalow, etaup); - fhTruePhiB = new TH1F("fTrueHistPhiB", "#phi distribution before (truth);#phi;counts", 360, 0.0, constants::math::TwoPI); - fhTruePhiA = new TH1F("fTrueHistPhiA", "#phi distribution (truth);#phi;counts", 360, 0.0, constants::math::TwoPI); - fhTrueDCAxyB = new TH1F("TrueDCAxyB", "DCA_{xy} distribution for generated before;DCA_{xy} (cm);counts", 1000, -4.0, 4.0); - if (traceDCAOutliers.mDoIt) { - fhTrueDCAxyBid = new TH1F("PDGCodeDCAxyB", - TString::Format("PDG code within %.2f<|DCA_{#it{xy}}|<%.2f; PDG code", traceDCAOutliers.mLowValue, traceDCAOutliers.mUpValue).Data(), - 100, 0.5, 100.5); - } - 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); - - for (int sp = 0; sp < kIdBfNoOfSpecies; ++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); - fhTruePtA[sp] = new TH1F(TString::Format("fTrueHistPtA_%s", speciesName[sp]), - TString::Format("p_{T} distribution %s (truth);p_{T} (GeV/c);dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), - ptbins, ptlow, ptup); - fhTruePtPosA[sp] = new TH1F(TString::Format("fTrueHistPtPosA_%s", speciesName[sp]), - TString::Format("P_{T} distribution %s^{#plus} (truth);P_{T} (GeV/c);dN/dP_{T} (c/GeV)", speciesTitle[sp]).Data(), - ptbins, ptlow, ptup); - 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); - 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); - fhTrueDeltaNA[sp] = new TH1F(TString::Format("fhTrueDeltaNA_%s", speciesName[sp]).Data(), - 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); - } - - /* add the hstograms to the output list */ - fOutputList->Add(fhTruePB); - fOutputList->Add(fhTruePtB); - fOutputList->Add(fhTruePtPosB); - fOutputList->Add(fhTruePtNegB); - fOutputList->Add(fhTrueEtaB); - fOutputList->Add(fhTrueEtaA); - fOutputList->Add(fhTruePhiB); - fOutputList->Add(fhTruePhiA); - fOutputList->Add(fhTrueDCAxyB); - if (traceDCAOutliers.mDoIt) { - fOutputList->Add(fhTrueDCAxyBid); - } - fOutputList->Add(fhTrueDCAxyA); - fOutputList->Add(fhTrueDCAzB); - fOutputList->Add(fhTrueDCAzA); - - for (int sp = 0; sp < kIdBfNoOfSpecies; ++sp) { - fOutputList->Add(fhTruePA[sp]); - fOutputList->Add(fhTruePtA[sp]); - fOutputList->Add(fhTruePtPosA[sp]); - fOutputList->Add(fhTruePtNegA[sp]); - fOutputList->Add(fhTrueNPosNegA[sp]); - fOutputList->Add(fhTrueDeltaNA[sp]); - } - } - } - - template - inline MatchRecoGenSpecies IdentifyTrack(TrackObject const& track); - template - MatchRecoGenSpecies trackIdentification(TrackObject const& track); - template - int8_t AcceptTrack(TrackObject const& track); - template - int8_t selectTrackAmbiguousCheck(CollisionObjects const& collisions, TrackObject const& track); - template - inline MatchRecoGenSpecies IdentifyParticle(ParticleObject const& particle); - template - void fillTrackHistosBeforeSelection(TrackObject const& track); - template - void fillTrackHistosAfterSelection(TrackObject const& track, MatchRecoGenSpecies sp); - template - void fillParticleHistosBeforeSelection(ParticleObject const& particle, - MCCollisionObject const& collision, - float charge); - template - void fillParticleHistosAfterSelection(ParticleObject const& particle, - MCCollisionObject const& collision, - float charge, - MatchRecoGenSpecies sp); - - /* 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 - void filterTracks(soa::Join const& collisions, - passedtracks const& tracks) - { - int naccepted = 0; - int ncollaccepted = 0; - if (!fullDerivedData) { - tracksinfo.reserve(tracks.size()); - } - for (auto collision : collisions) { - if (collision.collisionaccepted()) { - ncollaccepted++; - } - } - for (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 % 2 == 0) { - trkMultPos[kIdBfCharged]++; - } - if (pid % 2 == 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()); - } else { - tracksinfo(pid); - } - } else { - if (!fullDerivedData) { - /* track not accepted */ - tracksinfo(pid); - } - } - } else { - if (!fullDerivedData) { - /* track collision not accepted */ - tracksinfo(pid); - } - } - } - LOGF(IDENTIFIEDBFFILTERLOGCOLLISIONS, - "Processed %d accepted collisions out of a total of %d with %d accepted tracks out of a " - "total of %d", - ncollaccepted, - collisions.size(), - naccepted, - tracks.size()); - } - - /* 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) - { - using namespace identifiedbffilter; - - int acceptedparticles = 0; - int acceptedcollisions = 0; - if (!fullDerivedData) { - gentracksinfo.reserve(particles.size()); - } - - for (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); - } - - 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]++; - } - acceptedparticles++; - } else { - pid = -1; - } - } - } - } else { - if ((particle.mcCollisionId() == 0) && traceCollId0) { - LOGF(IDENTIFIEDBFFILTERLOGTRACKS, "Particle %d with fractional charge or equal to zero", particle.globalIndex()); - } - } - if (!fullDerivedData) { - gentracksinfo(pid); - } - } - LOGF(IDENTIFIEDBFFILTERLOGCOLLISIONS, - "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()); - } - - void filterRecoWithPID(soa::Join& collisions, IdBfFullTracksPID const& tracks) - { - filterTracks(collisions, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterRecoWithPID, "Not stored derived data track filtering", false) - - void filterRecoWithPIDAmbiguous(soa::Join& collisions, IdBfFullTracksPIDAmbiguous const& tracks) - { - filterTracks(collisions, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterRecoWithPIDAmbiguous, "Not stored derived data track filtering with ambiguous tracks check", false) - - void filterDetectorLevelWithPID(soa::Join& collisions, IdBfFullTracksPIDDetLevel const& tracks) - { - filterTracks(collisions, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithPID, "Not stored derived data detector level track filtering", false) - - void filterDetectorLevelWithPIDAmbiguous(soa::Join& collisions, IdBfFullTracksPIDDetLevelAmbiguous const& tracks) - { - 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) - { - 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) - { - filterTracks(collisions, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithFullPID, "Not stored derived data detector level track filtering", false) - - void filterDetectorLevelWithFullPIDAmbiguous(soa::Join& collisions, IdBfFullTracksFullPIDDetLevelAmbiguous const& tracks) - { - 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); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterRecoWithoutPID, "Track filtering without PID information", true) - - void filterRecoWithoutPIDAmbiguous(soa::Join const& collisions, IdBfFullTracksAmbiguous const& tracks) - { - filterTracks(collisions, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterRecoWithoutPIDAmbiguous, "Track filtering without PID information with ambiguous tracks check", false) - - void filterDetectorLevelWithoutPID(soa::Join const& collisions, IdBfFullTracksDetLevel const& tracks) - { - filterTracks(collisions, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithoutPID, "Detector level track filtering without PID information", false) - - void filterDetectorLevelWithoutPIDAmbiguous(soa::Join const& collisions, IdBfFullTracksDetLevelAmbiguous const& tracks) - { - filterTracks(collisions, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterDetectorLevelWithoutPIDAmbiguous, "Detector level track filtering without PID information with ambiguous tracks check", false) - - void filterGenerated(soa::Join const& gencollisions, aod::McParticles const& particles) - { - filterParticles(gencollisions, particles); - } - PROCESS_SWITCH(IdentifiedBfFilterTracks, filterGenerated, "Generated particles filering", true) -}; - -template -inline MatchRecoGenSpecies IdentifiedBfFilterTracks::IdentifyParticle(ParticleObject const& particle) -{ - using namespace identifiedbffilter; - - constexpr int pdgcodeEl = 11; - constexpr int pdgcodePi = 211; - constexpr int pdgcodeKa = 321; - constexpr int pdgcodePr = 2212; - - int pdgcode = abs(particle.pdgCode()); - - switch (pdgcode) { - case pdgcodeEl: - return kIdBfElectron; - break; - - case pdgcodePi: - return kIdBfPion; - break; - case pdgcodeKa: - return kIdBfKaon; - break; - case pdgcodePr: - return kIdBfProton; - break; - - default: - if (traceOutOfSpeciesParticles) { - LOGF(info, "Wrong particle passed selection cuts. PDG code: %d", pdgcode); - } - return kWrongSpecies; - break; - } -} - -template -void fillNSigmaHistos(TrackObject const& track) -{ - - fhNSigmaTPC[kIdBfElectron]->Fill(track.tpcNSigmaEl(), track.tpcInnerParam()); - fhNSigmaTPC[kIdBfPion]->Fill(track.tpcNSigmaPi(), track.tpcInnerParam()); - fhNSigmaTPC[kIdBfKaon]->Fill(track.tpcNSigmaKa(), track.tpcInnerParam()); - fhNSigmaTPC[kIdBfProton]->Fill(track.tpcNSigmaPr(), track.tpcInnerParam()); - - fhNSigmaTOF[kIdBfElectron]->Fill(track.tofNSigmaEl(), track.tpcInnerParam()); - fhNSigmaTOF[kIdBfPion]->Fill(track.tofNSigmaPi(), track.tpcInnerParam()); - fhNSigmaTOF[kIdBfKaon]->Fill(track.tofNSigmaKa(), track.tpcInnerParam()); - fhNSigmaTOF[kIdBfProton]->Fill(track.tofNSigmaPr(), track.tpcInnerParam()); - - fhNSigmaCombo[kIdBfElectron]->Fill(sqrtf(track.tofNSigmaEl() * track.tofNSigmaEl() + track.tpcNSigmaEl() * track.tpcNSigmaEl()), track.tpcInnerParam()); - fhNSigmaCombo[kIdBfPion]->Fill(sqrtf(track.tofNSigmaPi() * track.tofNSigmaPi() + track.tpcNSigmaPi() * track.tpcNSigmaPi()), track.tpcInnerParam()); - fhNSigmaCombo[kIdBfKaon]->Fill(sqrtf(track.tofNSigmaKa() * track.tofNSigmaKa() + track.tpcNSigmaKa() * track.tpcNSigmaKa()), track.tpcInnerParam()); - fhNSigmaCombo[kIdBfProton]->Fill(sqrtf(track.tofNSigmaPr() * track.tofNSigmaPr() + track.tpcNSigmaPr() * track.tpcNSigmaPr()), track.tpcInnerParam()); -} - -template -inline MatchRecoGenSpecies IdentifiedBfFilterTracks::IdentifyTrack(TrackObject const& track) -{ - using namespace o2::analysis::identifiedbffilter; - - fillNSigmaHistos(track); - - float nsigmas[kIdBfNoOfSpecies]; - if (track.p() < 0.8 && !reqTOF && !onlyTOF) { - nsigmas[kIdBfElectron] = track.tpcNSigmaEl(); - nsigmas[kIdBfPion] = track.tpcNSigmaPi(); - nsigmas[kIdBfKaon] = track.tpcNSigmaKa(); - nsigmas[kIdBfProton] = track.tpcNSigmaPr(); - - } else { - /* introduce require TOF flag */ - if (track.hasTOF() && !onlyTOF) { - nsigmas[kIdBfElectron] = sqrtf(track.tpcNSigmaEl() * track.tpcNSigmaEl() + track.tofNSigmaEl() * track.tofNSigmaEl()); - 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()); - - } else if (!reqTOF || !onlyTOF) { - nsigmas[kIdBfElectron] = track.tpcNSigmaEl(); - nsigmas[kIdBfPion] = track.tpcNSigmaPi(); - nsigmas[kIdBfKaon] = track.tpcNSigmaKa(); - nsigmas[kIdBfProton] = track.tpcNSigmaPr(); - - } else if (track.hasTOF() && onlyTOF) { - nsigmas[kIdBfElectron] = track.tofNSigmaEl(); - nsigmas[kIdBfPion] = track.tofNSigmaPi(); - nsigmas[kIdBfKaon] = track.tofNSigmaKa(); - nsigmas[kIdBfProton] = track.tofNSigmaPr(); - } else { - return 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 min_nsigma = 999.0f; - MatchRecoGenSpecies sp_min_nsigma = kWrongSpecies; - for (int sp = 0; sp < kIdBfNoOfSpecies; ++sp) { - if (abs(nsigmas[sp]) < abs(min_nsigma)) { // Check if species nsigma is less than current nsigma - min_nsigma = nsigmas[sp]; // If yes, set species nsigma to current nsigma - sp_min_nsigma = MatchRecoGenSpecies(sp); // set current species sp number to current sp - } - } - bool doublematch = false; - MatchRecoGenSpecies spDouble = kWrongSpecies; - if (min_nsigma < maxPIDSigma && min_nsigma > 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 != sp_min_nsigma) { // for species not current minimum nsigma species - if (nsigmas[sp] < maxRejectSigma && min_nsigma > minRejectSigma) { // If secondary species is in rejection range - doublematch = true; // Set double match true - spDouble = MatchRecoGenSpecies(sp); - } - } - } - if (doublematch) { // if double match true - fhWrongTrackID->Fill(track.p()); - fhdEdxA[kIdBfNoOfSpecies]->Fill(track.p(), track.tpcSignal()); - fhdEdxIPTPCA[kIdBfNoOfSpecies]->Fill(track.tpcInnerParam(), track.tpcSignal()); - fhDoublePID->Fill(sp_min_nsigma, spDouble); - return kWrongSpecies; // Return wrong species value - } else { - if (track.hasTOF() && (reqTOF || onlyTOF)) { - if (sp_min_nsigma == 0) { - fhNSigmaTPC_IdTrks[sp_min_nsigma]->Fill(track.tpcNSigmaEl(), track.tpcInnerParam()); - } - if (sp_min_nsigma == 1) { - fhNSigmaTPC_IdTrks[sp_min_nsigma]->Fill(track.tpcNSigmaPi(), track.tpcInnerParam()); - } - if (sp_min_nsigma == 2) { - fhNSigmaTPC_IdTrks[sp_min_nsigma]->Fill(track.tpcNSigmaKa(), track.tpcInnerParam()); - } - if (sp_min_nsigma == 3) { - fhNSigmaTPC_IdTrks[sp_min_nsigma]->Fill(track.tpcNSigmaPr(), track.tpcInnerParam()); - } - } - return sp_min_nsigma; - } - } 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 || 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; -} - -/// \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 -template -inline int8_t IdentifiedBfFilterTracks::AcceptTrack(TrackObject const& track) -{ - fillTrackHistosBeforeSelection(track); // ) { - if (track.mcParticleId() < 0) { - return -1; - } - } - - if (matchTrackType(track)) { - if (ptlow < track.pt() && track.pt() < ptup && etalow < track.eta() && track.eta() < etaup) { - fillTrackHistosAfterSelection(track, kIdBfCharged); - MatchRecoGenSpecies sp = trackIdentification(track); - if (sp == kWrongSpecies) { - return -1; - } - if (!(sp < 0)) { - fillTrackHistosAfterSelection(track, sp); // 0) { - trkMultPos[sp]++; //<< Update Particle Multiplicity - return speciesChargeValue1[sp]; - } - if (track.sign() < 0) { - trkMultNeg[sp]++; //<< Update Particle Multiplicity - return speciesChargeValue1[sp] + 1; - } - } - } - } - return -1; -} - -template -int8_t IdentifiedBfFilterTracks::selectTrackAmbiguousCheck(CollisionObjects const& collisions, TrackObject const& track) -{ - bool ambiguoustrack = false; - int tracktype = 0; /* no ambiguous */ - std::vector zvertexes{}; - /* ambiguous tracks checks if required */ - if constexpr (has_type_v) { - if (track.compatibleCollIds().size() > 0) { - if (track.compatibleCollIds().size() == 1) { - if (track.collisionId() != track.compatibleCollIds()[0]) { - /* ambiguous track! */ - ambiguoustrack = true; - /* in principle we should not be here because the track is associated to two collisions at least */ - tracktype = 2; - zvertexes.push_back(collisions.iteratorAt(track.collisionId()).posZ()); - zvertexes.push_back(collisions.iteratorAt(track.compatibleCollIds()[0]).posZ()); - } else { - /* we consider the track as no ambiguous */ - tracktype = 1; - } - } else { - /* ambiguous track! */ - ambiguoustrack = true; - tracktype = 3; - /* the track is associated to more than one collision */ - for (const auto& collIdx : track.compatibleCollIds()) { - zvertexes.push_back(collisions.iteratorAt(collIdx).posZ()); - } - } - } - } - - float multiplicityclass = (track.template collision_as>()).centmult(); - if (ambiguoustrack) { - /* keep track of ambiguous tracks */ - fhAmbiguousTrackType->Fill(tracktype, multiplicityclass); - fhAmbiguousTrackPt->Fill(track.pt(), multiplicityclass); - fhAmbiguityDegree->Fill(zvertexes.size(), multiplicityclass); - if (tracktype == 2) { - fhCompatibleCollisionsZVtxRms->Fill(-computeRMS(zvertexes), multiplicityclass); - } else { - fhCompatibleCollisionsZVtxRms->Fill(computeRMS(zvertexes), multiplicityclass); - } - return -1; - } else { - if (checkAmbiguousTracks) { - /* feedback of no ambiguous tracks only if checks required */ - fhAmbiguousTrackType->Fill(tracktype, multiplicityclass); - } - return AcceptTrack(track); - } -} - -template -void IdentifiedBfFilterTracks::fillTrackHistosBeforeSelection(TrackObject const& track) -{ - fhPB->Fill(track.p()); - fhPtB->Fill(track.pt()); - fhEtaB->Fill(track.eta()); - fhPhiB->Fill(track.phi()); - fhdEdxB->Fill(track.p(), track.tpcSignal()); - fhdEdxIPTPCB->Fill(track.tpcInnerParam(), track.tpcSignal()); - if (track.sign() > 0) { - fhPtPosB->Fill(track.pt()); - } else { - fhPtNegB->Fill(track.pt()); - } - fhDCAxyB->Fill(track.dcaXY()); - fhDCAzB->Fill(track.dcaZ()); -} - -template -void IdentifiedBfFilterTracks::fillTrackHistosAfterSelection(TrackObject const& track, MatchRecoGenSpecies sp) -{ - /* the charged species should have been called first so avoid double counting */ - if (sp == kIdBfCharged) { - fhEtaA->Fill(track.eta()); - fhPhiA->Fill(track.phi()); - fhDCAxyA->Fill(track.dcaXY()); - fhDCAzA->Fill(track.dcaZ()); - - if (track.dcaXY() < 1.0) { - fhFineDCAxyA->Fill(track.dcaXY()); - } - if (track.dcaZ() < 1.0) { - fhFineDCAzA->Fill(track.dcaZ()); - } - } else { - fhPA[sp]->Fill(track.p()); - fhPtA[sp]->Fill(track.pt()); - fhdEdxA[sp]->Fill(track.p(), track.tpcSignal()); - fhdEdxIPTPCA[sp]->Fill(track.tpcInnerParam(), track.tpcSignal()); - if (track.sign() > 0) { - fhPtPosA[sp]->Fill(track.pt()); - } else { - fhPtNegA[sp]->Fill(track.pt()); - } - } -} - -template -void IdentifiedBfFilterTracks::fillParticleHistosBeforeSelection(ParticleObject const& particle, MCCollisionObject const& collision, float charge) -{ - fhTruePB->Fill(particle.p()); - fhTruePtB->Fill(particle.pt()); - fhTrueEtaB->Fill(particle.eta()); - fhTruePhiB->Fill(particle.phi()); - if (charge > 0) { - fhTruePtPosB->Fill(particle.pt()); - } else if (charge < 0) { - fhTruePtNegB->Fill(particle.pt()); - } - - float dcaxy = TMath::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()))); - fhTrueDCAzB->Fill((particle.vz() - collision.posZ())); -} - -template -void IdentifiedBfFilterTracks::fillParticleHistosAfterSelection(ParticleObject const& particle, MCCollisionObject const& collision, float charge, MatchRecoGenSpecies sp) -{ - /* the charged species should have been called first so avoid double counting */ - if (sp == kIdBfCharged) { - 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())); - 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()))); - fhTrueDCAzA->Fill((particle.vz() - collision.posZ())); - } else { - fhTruePA[sp]->Fill(particle.p()); - fhTruePtA[sp]->Fill(particle.pt()); - if (charge > 0) { - fhTruePtPosA[sp]->Fill(particle.pt()); - } else { - fhTruePtNegA[sp]->Fill(particle.pt()); - } - } -} - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask(cfgc, - SetDefaultProcesses{ - {{"processWithoutCent", true}, - {"processWithoutCentMC", true}}}), - adaptAnalysisTask(cfgc)}; - return workflow; -} diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h b/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h deleted file mode 100644 index 55036a6ae38..00000000000 --- a/PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h +++ /dev/null @@ -1,785 +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. - -#ifndef PWGCF_TWOPARTICLECORRELATIONS_TABLEPRODUCER_IDENTIFIEDBFFILTER_H_ -#define PWGCF_TWOPARTICLECORRELATIONS_TABLEPRODUCER_IDENTIFIEDBFFILTER_H_ - -#include -#include - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include - -namespace o2 -{ -namespace aod -{ -using CollisionsEvSelCent = soa::Join; -using CollisionEvSelCent = 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; -} // namespace aod -namespace analysis -{ -namespace identifiedbffilter -{ - -/// \enum MatchRecoGenSpecies -/// \brief The species considered by the matching test -enum MatchRecoGenSpecies { - kIdBfElectron = 0, ///< electron - kIdBfPion, ///< pion - kIdBfKaon, ///< kaon - kIdBfProton, ///< proton - kIdBfNoOfSpecies, ///< the number of considered species - kIdBfCharged = 4, - kWrongSpecies = -1 -}; - -/// \enum SpeciesPairMatch -/// \brief The species pair considered by the matching test -enum SpeciesPairMatch { - kIdBfElectronElectron, ///< Electron-Electron,Electron-Positron - kIdBfElectronMuon, ///< Electron-Muon - kIdBfElectronPion, ///< Electron-Pion - kIdBfElectronKaon, ///< Electron-Kaon - kIdBfElectronProton, ///< Electron-Proton - kIdBfMuonMuon, ///< Muon-Muon - kIdBfMuonPion, ///< Muon-Pion - kIdBfMuonKaon, ///< Muon-Kaon - kIdBfMuonProton, ///< Muon-Proton - kIdBfPionPion, ///< Pion-Pion - kIdBfPionKaon, ///< Pion-Kaon - kIdBfPionProton, ///< Pion-Proton - kIdBfKaonKaon, ///< Kaon-Kaon - kIdBfKaonProton, ///< Kaon-Proton - kIdBfProtonProton ///< Proton-Proton -}; - -const char* speciesName[kIdBfNoOfSpecies] = {"e", "pi", "ka", "p"}; - -const char* speciesTitle[kIdBfNoOfSpecies] = {"e", "#pi", "K", "p"}; - -const int speciesChargeValue1[kIdBfNoOfSpecies] = { - 0, //< electron - 2, //< pion - 4, //< Kaon - 6 //< proton -}; - -/// \enum SystemType -/// \brief The type of the system under analysis -enum SystemType { - kNoSystem = 0, ///< no system defined - kpp, ///< **p-p** system - kpPb, ///< **p-Pb** system - kPbp, ///< **Pb-p** system - kPbPb, ///< **Pb-Pb** system - kXeXe, ///< **Xe-Xe** system - kppRun3, ///< **p-p Run 3** system - kPbPbRun3, ///< **Pb-Pb Run 3** system - knSystems ///< number of handled systems -}; - -/// \enum DataType -/// \brief Which kind of data is the task addressing -enum DataType { - kData = 0, ///< actual data, not generated - kMC, ///< Generator level and detector level - kFastMC, ///< Gererator level but stored dataset - kOnTheFly, ///< On the fly generator level data - kDataNoEvtSel, ///< actual data but not event selection available yet - knGenData ///< number of different generator data types -}; - -/// \enum CentMultEstimatorType -/// \brief The detector used to estimate centrality/multiplicity -enum CentMultEstimatorType { - kNOCM = 0, ///< do not use centrality/multiplicity estimator - kV0M, ///< V0M centrality/multiplicity estimator Run 1/2 - kCL0, ///< CL0 centrality/multiplicity estimator Run 1/2 - kCL1, ///< CL1 centrality/multiplicity estimator Run 1/2 - kFV0A, ///< FV0A centrality/multiplicity estimator Run 3 - kFT0M, ///< FT0M centrality/multiplicity estimator Run 3 - kFT0A, ///< FT0A centrality/multiplicity estimator Run 3 - kFT0C, ///< FT0C centrality/multiplicity estimator Run 3 - kNTPV, ///< NTPV centrality/multiplicity estimator Run 3 - knCentMultEstimators ///< number of centrality/mutiplicity estimator -}; - -/// \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 - knEventSelection ///< number of triggers for event selection -}; - -//============================================================================================ -// The IdentifiedBfFilter configuration objects -//============================================================================================ -int ptbins = 18; -float ptlow = 0.2, ptup = 2.0; -int etabins = 16; -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 phiup = constants::math::TwoPI; - -int tracktype = 1; - -std::vector trackFilters = {}; -bool dca2Dcut = false; -float maxDCAz = 1e6f; -float maxDCAxy = 1e6f; - -inline void initializeTrackSelection() -{ - 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; - default: - break; - } -} - -SystemType fSystem = kNoSystem; -DataType fDataType = kData; -CentMultEstimatorType fCentMultEstimator = kV0M; -TriggerSelectionType fTriggerSelection = kMB; - -/* adaptations for the pp nightly checks */ -analysis::CheckRangeCfg traceDCAOutliers; -bool traceOutOfSpeciesParticles = false; -int recoIdMethod = 0; -bool useOwnTrackSelection = false; -TrackSelection ownTrackSelection = getGlobalTrackSelection(); -bool useOwnParticleSelection = false; -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 == "None") { - return kNONE; - } else { - LOGF(fatal, "Wrong trigger selection: %s", triggstr.c_str()); - return kNONE; - } -} - -inline SystemType getSystemType(std::string const& sysstr) -{ - /* we have to figure out how extract the system type */ - if (sysstr.empty() || (sysstr == "PbPb")) { - return kPbPb; - } else if (sysstr == "pp") { - return kpp; - } else if (sysstr == "pPb") { - return kpPb; - } else if (sysstr == "Pbp") { - return kPbp; - } else if (sysstr == "pPb") { - return kpPb; - } else if (sysstr == "XeXe") { - return kXeXe; - } else if (sysstr == "ppRun3") { - return kppRun3; - } else if (sysstr == "PbPbRun3") { - return kPbPbRun3; - } else { - LOGF(fatal, "IdentifiedBfCorrelations::getSystemType(). Wrong system type: %s", sysstr.c_str()); - } - return kPbPb; -} - -/// \brief Type of data according to the configuration string -/// \param datastr The data type configuration string -/// \return Internal code for the passed kind of data string -inline DataType getDataType(std::string const& datastr) -{ - /* we have to figure out how extract the type of data*/ - if (datastr.empty() || (datastr == "data")) { - return kData; - } else if (datastr == "datanoevsel") { - return kDataNoEvtSel; - } else if (datastr == "MC") { - return kMC; - } else if (datastr == "FastMC") { - return kFastMC; - } else if (datastr == "OnTheFlyMC") { - return kOnTheFly; - } else { - LOGF(fatal, "IdentifiedBfCorrelations::getDataType(). Wrong type of dat: %d", datastr.c_str()); - } - return kData; -} - -inline CentMultEstimatorType getCentMultEstimator(std::string const& datastr) -{ - if (datastr == "V0M") { - return kV0M; - } else if (datastr == "CL0") { - return kCL0; - } else if (datastr == "CL1") { - return kCL1; - } else if (datastr == "FV0A") { - return kFV0A; - } else if (datastr == "FT0M") { - return kFT0M; - } else if (datastr == "FT0A") { - return kFT0A; - } else if (datastr == "FT0C") { - return kFT0C; - } else if (datastr == "NTPV") { - return kNTPV; - } else if (datastr == "NOCM") { - return kNOCM; - } else { - LOGF(fatal, "Centrality/Multiplicity estimator %s not supported yet", datastr.c_str()); - } - return kNOCM; -} - -inline std::string getCentMultEstimatorName(CentMultEstimatorType est) -{ - switch (est) { - case kV0M: - return "V0M"; - break; - case kCL0: - return "CL0"; - break; - case kCL1: - return "CL1"; - break; - case kFV0A: - return "FV0A"; - break; - case kFT0M: - return "FT0M"; - break; - case kFT0A: - return "FT0A"; - break; - case kFT0C: - return "FT0C"; - break; - case kNTPV: - return "NTPV"; - break; - case kNOCM: - return "NOCM"; - break; - default: - LOGF(fatal, "Centrality/Multiplicity estimator %d not supported yet", (int)est); - return "WRONG"; - break; - } -} - -////////////////////////////////////////////////////////////////////////////////// -/// Trigger selection -////////////////////////////////////////////////////////////////////////////////// - -/// \brief Trigger selection for reconstructed and detector level collision tables -template -inline bool triggerSelectionReco(CollisionObject const& collision) -{ - bool trigsel = false; - switch (fSystem) { - case kpp: - case kpPb: - case kPbp: - case kPbPb: - case kXeXe: - switch (fTriggerSelection) { - case kMB: - switch (fDataType) { - case kData: - if (collision.alias_bit(kINT7)) { - if (collision.sel7()) { - trigsel = true; - } - } - break; - case kMC: - if (collision.sel7()) { - trigsel = true; - } - break; - default: - trigsel = true; - break; - } - break; - case kNONE: - trigsel = true; - break; - default: - break; - } - break; - case kppRun3: - case kPbPbRun3: - switch (fTriggerSelection) { - case kMB: - if (collision.sel8()) { - trigsel = true; - } - break; - case kNONE: - trigsel = true; - break; - default: - break; - } - break; - default: - break; - } - return trigsel; -} - -/// \brief Trigger selection by default: unknow subscribed collision table -template -inline bool triggerSelection(CollisionObject const&) -{ - LOGF(fatal, "Trigger selection not implemented for this kind of collisions"); - return false; -} - -/// \brief Trigger selection for reconstructed collision tables without centrality/multiplicity -template <> -inline bool triggerSelection(aod::CollisionEvSel const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for reconstructed collision tables with Run 2 centrality/multiplicity -template <> -inline bool triggerSelection(aod::CollisionEvSelRun2Cent const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for reconstructed collision tables with centrality/multiplicity -template <> -inline bool triggerSelection(aod::CollisionEvSelCent const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for detector level collision tables without centrality/multiplicity -template <> -inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for detector level collision tables with Run 2 centrality/multiplicity -template <> -inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for detector level collision tables with centrality/multiplicity -template <> -inline bool triggerSelection::iterator>(soa::Join::iterator const& collision) -{ - return triggerSelectionReco(collision); -} - -/// \brief Trigger selection for generator level collison table -template <> -inline bool triggerSelection(aod::McCollision const&) -{ - return true; -} - -////////////////////////////////////////////////////////////////////////////////// -/// Multiplicity extraction -////////////////////////////////////////////////////////////////////////////////// - -/// \brief Extract the collision multiplicity from the event selection information -template -inline float extractMultiplicity(CollisionObject const& collision, CentMultEstimatorType est) -{ - switch (est) { - case kV0M: - return collision.multFV0M(); - break; - case kCL0: - return collision.multTracklets(); - break; - case kCL1: - return collision.multTracklets(); - break; - case kFV0A: - return collision.multFV0A(); - break; - case kFT0M: - return collision.multFT0M(); - break; - case kFT0A: - return collision.multFT0A(); - break; - case kFT0C: - return collision.multFT0M(); - break; - case kNTPV: - return collision.multNTracksPV(); - break; - case kNOCM: - return collision.multFT0M(); - break; - default: - LOGF(fatal, "Centrality/Multiplicity estimator %d not supported yet", (int)est); - return collision.multFT0M(); - break; - } -} - -////////////////////////////////////////////////////////////////////////////////// -/// Centrality selection -////////////////////////////////////////////////////////////////////////////////// - -/// \brief Centrality/multiplicity percentile -template -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; - } - } - 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; - } - } -} - -/// \brief Centrality selection when there is centrality/multiplicity information -template -inline bool centralitySelectionMult(CollisionObject collision, float& centmult) -{ - float mult = getCentMultPercentile(collision); - if (mult < 100 && 0 < mult) { - centmult = mult; - return true; - } - return false; -} - -/// \brief Centrality selection when there is not centrality/multiplicity information -template -inline bool centralitySelectionNoMult(CollisionObject const&, float& centmult) -{ - bool centmultsel = false; - switch (fCentMultEstimator) { - case kNOCM: - centmult = 50.0; - centmultsel = true; - break; - default: - break; - } - return centmultsel; -} - -/// \brief Centrality selection by default: unknown subscribed collision table -template -inline bool centralitySelection(CollisionObject const&, float&) -{ - LOGF(fatal, "Centrality selection not implemented for this kind of collisions"); - return false; -} - -/// \brief Centrality selection for reconstructed and detector level collision tables with centrality/multiplicity information -template <> -inline bool centralitySelection(aod::CollisionEvSelCent const& collision, float& centmult) -{ - - return centralitySelectionMult(collision, centmult); -} - -/// \brief Centrality selection for reconstructed and detector level collision tables with Run 2 centrality/multiplicity information -template <> -inline bool centralitySelection(aod::CollisionEvSelRun2Cent const& collision, float& centmult) -{ - - return centralitySelectionMult(collision, centmult); -} - -/// \brief Centrality selection for reconstructed and detector level collision tables without centrality/multiplicity information -template <> -inline bool centralitySelection(aod::CollisionEvSel const& collision, float& centmult) -{ - - return centralitySelectionNoMult(collision, centmult); -} - -/// \brief Centrality selection for detector level collision tables without centrality/multiplicity -template <> -inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) -{ - - return centralitySelectionNoMult(collision, centmult); -} - -/// \brief Centrality selection for detector level collision tables with centrality/multiplicity -template <> -inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) -{ - - return centralitySelectionMult(collision, centmult); -} - -/// \brief Centrality selection for detector level collision tables with Run 2 centrality/multiplicity -template <> -inline bool centralitySelection::iterator>(soa::Join::iterator const& collision, float& centmult) -{ - return centralitySelectionMult(collision, centmult); -} - -/// \brief Centrality selection for generator level collision table -template <> -inline bool centralitySelection(aod::McCollision const&, float& centmult) -{ - if (centmult < 100 && 0 < centmult) { - return true; - } else { - return false; - } -} - -////////////////////////////////////////////////////////////////////////////////// -/// Event selection -////////////////////////////////////////////////////////////////////////////////// - -template -inline bool IsEvtSelected(CollisionObject const& collision, float& centormult) -{ - bool trigsel = triggerSelection(collision); - - bool zvtxsel = false; - /* TODO: vertex quality checks */ - if (zvtxlow < collision.posZ() && collision.posZ() < zvtxup) { - zvtxsel = true; - } - - bool centmultsel = centralitySelection(collision, centormult); - return trigsel && zvtxsel && centmultsel; -} - -////////////////////////////////////////////////////////////////////////////////// -/// Track selection -////////////////////////////////////////////////////////////////////////////////// - -template -inline bool matchTrackType(TrackObject const& track) -{ - if (useOwnTrackSelection) { - return ownTrackSelection.IsSelected(track); - } else { - for (auto filter : trackFilters) { - if (filter->IsSelected(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; - } - } - } - return false; - } -} - -/// \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 -void exploreMothers(ParticleObject& particle, MCCollisionObject& collision) -{ - for (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()); - LOGF(info, " index: %d, pdg code: %d", m.globalIndex(), m.pdgCode()); - LOGF(info, " Passed isPhysicalPrimary(): %s", m.isPhysicalPrimary() ? "YES" : "NO"); - - exploreMothers(m, 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) -{ - 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; -} - -} // namespace identifiedbffilter -} // namespace analysis -} // namespace o2 - -#endif // PWGCF_TWOPARTICLECORRELATIONS_TABLEPRODUCER_IDENTIFIEDBFFILTER_H_ diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/longrangeMaker.cxx b/PWGCF/TwoParticleCorrelations/TableProducer/longrangeMaker.cxx new file mode 100644 index 00000000000..a7d90746265 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/TableProducer/longrangeMaker.cxx @@ -0,0 +1,774 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file longrangeMaker.cxx +/// +/// \brief task derived table definition for long range correlation +/// \author Abhi Modak (abhi.modak@cern.ch) +/// \since October 28, 2025 + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/TwoParticleCorrelations/DataModel/LongRangeDerived.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UPCHelpers.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "FT0Base/Geometry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +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::aod::evsel; +using namespace o2::constants::math; + +auto static constexpr KminFt0cCell = 96; +auto static constexpr PionTrackN = 1; +auto static constexpr KaonTrackN = 2; +auto static constexpr ProtonTrackN = 3; +AxisSpec axisEvent{15, 0.5, 15.5, "#Event", "EventAxis"}; + +enum KindOfParticles { + PIONS, + KAONS, + PROTONS +}; + +enum KindOfV0 { + kLambda = 0, + kAntiLambda +}; + +struct LongrangeMaker { + + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable noLaterThan{"noLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + } cfgCcdbParam; + + struct : ConfigurableGroup { + Configurable isApplyTrigTvx{"isApplyTrigTvx", false, "Enable Ft0a and Ft0c coincidence"}; + Configurable isApplyTfborder{"isApplyTfborder", false, "Enable TF border cut"}; + Configurable isApplyItsRofborder{"isApplyItsRofborder", false, "Enable ITS ROF border cut"}; + Configurable isApplySameBunchPileup{"isApplySameBunchPileup", false, "Enable SameBunchPileup cut"}; + Configurable isApplyGoodZvtxFT0vsPV{"isApplyGoodZvtxFT0vsPV", false, "Enable GoodZvtxFT0vsPV cut"}; + Configurable isApplyGoodITSLayersAll{"isApplyGoodITSLayersAll", false, "Enable GoodITSLayersAll cut"}; + Configurable isApplyExtraCorrCut{"isApplyExtraCorrCut", false, "Enable extra NPVtracks vs FTOC correlation cut"}; + Configurable npvTracksCut{"npvTracksCut", 1.0f, "Apply extra NPVtracks cut"}; + Configurable ft0cCut{"ft0cCut", 1.0f, "Apply extra FT0C cut"}; + Configurable isApplyNoCollInTimeRangeStandard{"isApplyNoCollInTimeRangeStandard", false, "Enable NoCollInTimeRangeStandard cut"}; + Configurable isApplyNoCollInRofStandard{"isApplyNoCollInRofStandard", false, "Enable NoCollInRofStandard cut"}; + Configurable isApplyNoHighMultCollInPrevRof{"isApplyNoHighMultCollInPrevRof", false, "Enable NoHighMultCollInPrevRof cut"}; + Configurable isApplyCentFT0C{"isApplyCentFT0C", false, "Centrality based on FT0C"}; + Configurable isApplyCentFV0A{"isApplyCentFV0A", false, "Centrality based on FV0A"}; + Configurable isApplyCentFT0M{"isApplyCentFT0M", false, "Centrality based on FT0A + FT0C"}; + Configurable isApplyOccuSelection{"isApplyOccuSelection", false, "Enable occupancy selection"}; + Configurable cfgOccuCut{"cfgOccuCut", 1000, "Occupancy selection"}; + } cfgevtsel; + + struct : ConfigurableGroup { + Configurable cfgEtaCut{"cfgEtaCut", 0.8f, "Eta range to consider"}; + Configurable cfgPtCutMin{"cfgPtCutMin", 0.2f, "minimum accepted track pT"}; + Configurable cfgPtCutMax{"cfgPtCutMax", 10.0f, "maximum accepted track pT"}; + Configurable cfgPtCutMult{"cfgPtCutMult", 3.0f, "maximum track pT for multiplicity classification"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70.f, "cut on minimum number of TPC crossed rows"}; + Configurable minTPCNClsFound{"minTPCNClsFound", 50.f, "cut on minimum value of TPC found clusters"}; + Configurable maxDcaZ{"maxDcaZ", 2.f, "cut on maximum abs value of DCA z"}; + Configurable maxChi2PerClusterTPC{"maxChi2PerClusterTPC", 4.f, "cut on maximum value of TPC chi2 per cluster"}; + } cfgtrksel; + + struct : ConfigurableGroup { + Configurable cfigMftEtaMax{"cfigMftEtaMax", -2.5f, "Maximum MFT eta cut"}; + Configurable cfigMftEtaMin{"cfigMftEtaMin", -3.6f, "Minimum MFT eta cut"}; + Configurable cfigMftDcaxy{"cfigMftDcaxy", 2.0f, "cut on DCA xy for MFT tracks"}; + Configurable cfigMftCluster{"cfigMftCluster", 5, "cut on MFT Cluster"}; + Configurable useMftPtCut{"useMftPtCut", true, "Choose to apply MFT track pT cut"}; + Configurable cfgMftPtCutMin{"cfgMftPtCutMin", 0.f, "minimum accepted MFT track pT"}; + Configurable cfgMftPtCutMax{"cfgMftPtCutMax", 10.f, "maximum accepted MFT track pT"}; + } cfgmfttrksel; + + struct : ConfigurableGroup { + Configurable minTPCcrossedrows{"minTPCcrossedrows", 70.f, "cut on minimum number of crossed rows in TPC"}; + Configurable minTPCcrossedrowsoverfindcls{"minTPCcrossedrowsoverfindcls", 0.8f, "cut on minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + Configurable v0etaCut{"v0etaCut", 0.8f, "maximum v0 track pseudorapidity"}; + Configurable v0ptCut{"v0ptCut", 0.15f, "minimum v0 track pT"}; + Configurable minK0sMass{"minK0sMass", 0.4f, "minimum mass for K0s"}; + Configurable maxK0sMass{"maxK0sMass", 0.6f, "maximum mass for K0s"}; + Configurable maxK0sRadius{"maxK0sRadius", 30.0f, "Maximum decay radius (cm) for K0s"}; + Configurable minK0sRadius{"minK0sRadius", 1.2f, "Minimum decay radius (cm) for K0s"}; + Configurable minK0sCosPa{"minK0sCosPa", 0.993f, "Minimum cosine of pointing angle for K0s"}; + Configurable maxDcaV0DauK0s{"maxDcaV0DauK0s", 0.8f, "Maximum DCA among the V0 daughters (cm) for K0s"}; + Configurable minqtArmenterosForK0s{"minqtArmenterosForK0s", 0.2f, "Minimum Armenteros' qt for K0s"}; + Configurable maxK0sLifeTime{"maxK0sLifeTime", 20.0f, "Maximum K0s lifetime (in cm)"}; + Configurable daughPIDCuts{"daughPIDCuts", 4.0f, "PID nsigma for V0s"}; + Configurable minV0DcaPiK0s{"minV0DcaPiK0s", 0.1f, "Min V0 pion DCA for K0s"}; + + Configurable minLambdaMass{"minLambdaMass", 1.07f, "minimum mass for Lambda"}; + Configurable maxLambdaMass{"maxLambdaMass", 1.17f, "maximum mass for Lambda"}; + Configurable maxLambdaRadius{"maxLambdaRadius", 30.0f, "Maximum decay radius (cm) for Lambda"}; + Configurable minLambdaRadius{"minLambdaRadius", 1.2f, "Minimum decay radius (cm) for Lambda"}; + Configurable minLambdaCosPa{"minLambdaCosPa", 0.993f, "Minimum cosine of pointing angle for Lambda"}; + Configurable maxDcaV0DauLambda{"maxDcaV0DauLambda", 0.8f, "Maximum DCA among the V0 daughters (cm) for K0s"}; + Configurable minV0DcaPiLambda{"minV0DcaPiLambda", 0.2f, "Min V0 pion DCA for Lambda"}; + Configurable minV0DcaPr{"minV0DcaPr", 0.07f, "Min V0 proton DCA for Lambda"}; + Configurable maxLambdaLifeTime{"maxLambdaLifeTime", 30.0f, "Maximum Lambda lifetime (in cm)"}; + } cfgv0trksel; + + Configurable> itsNsigmaPidCut{"itsNsigmaPidCut", std::vector{3, 2.5, 2, -3, -2.5, -2}, "ITS n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable> tpcNsigmaPidCut{"tpcNsigmaPidCut", std::vector{1.5, 1.5, 1.5, -1.5, -1.5, -1.5}, "TPC n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable> tofNsigmaPidCut{"tofNsigmaPidCut", std::vector{1.5, 1.5, 1.5, -1.5, -1.5, -1.5}, "TOF n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable cfgTofPidPtCut{"cfgTofPidPtCut", 0.3f, "Minimum pt to use TOF N-sigma"}; + Configurable isUseItsPid{"isUseItsPid", false, "Use ITS PID for particle identification"}; + + Service ccdb; + Service pdg; + o2::ccdb::CcdbApi ccdbApi; + o2::ft0::Geometry ft0Det; + std::vector* offsetFT0; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + TrackSelection myTrackFilter; + + std::vector tofNsigmaCut; + std::vector itsNsigmaCut; + std::vector tpcNsigmaCut; + o2::aod::ITSResponse itsResponse; + + // Create instance of the selector class which runs the gap selection algorithm + SGSelector sgSelector; + // Create instance of cut holder class to contain the user defined cuts + SGCutParHolder cfgSgCuts = SGCutParHolder(); + Configurable sgCuts{"sgCuts", {}, "SG event cuts"}; + Configurable cfgGapSide{"cfgGapSide", 2, "cut on UPC events"}; + + void init(InitContext&) + { + 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()); + LOGF(info, "Getting alignment offsets from the CCDB..."); + offsetFT0 = ccdb->getForTimeStamp>("FT0/Calib/Align", cfgCcdbParam.noLaterThan.value); + LOGF(info, "Offset for FT0A: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[0].getX(), (*offsetFT0)[0].getY(), (*offsetFT0)[0].getZ()); + LOGF(info, "Offset for FT0C: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[1].getX(), (*offsetFT0)[1].getY(), (*offsetFT0)[1].getZ()); + + histos.add("EventHist", "EventHist", kTH1D, {axisEvent}, false); + auto hstat = histos.get(HIST("EventHist")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All events"); + x->SetBinLabel(2, "Apply TriggerTVX"); + x->SetBinLabel(3, "Apply TF Border"); + x->SetBinLabel(4, "Apply ITS ROF Border"); + x->SetBinLabel(5, "ApplySameBunchPileup"); + x->SetBinLabel(6, "ApplyGoodZvtxFT0vsPV"); + x->SetBinLabel(7, "ApplyGoodITSLayersAll"); + x->SetBinLabel(8, "ApplyExtraCorrCut"); + x->SetBinLabel(9, "ApplyNoCollInTimeRangeStandard"); + x->SetBinLabel(10, "ApplyNoCollInRofStandard"); + x->SetBinLabel(11, "ApplyNoHighMultCollInPrevRof"); + x->SetBinLabel(12, "ApplyOccupancySelection"); + histos.add("hSelectionResult", "hSelectionResult", kTH1I, {{5, -0.5, 4.5}}); + + myTrackFilter = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + myTrackFilter.SetPtRange(cfgtrksel.cfgPtCutMin, cfgtrksel.cfgPtCutMax); + myTrackFilter.SetEtaRange(-cfgtrksel.cfgEtaCut, cfgtrksel.cfgEtaCut); + myTrackFilter.SetMinNCrossedRowsTPC(cfgtrksel.minNCrossedRowsTPC); + myTrackFilter.SetMinNClustersTPC(cfgtrksel.minTPCNClsFound); + myTrackFilter.SetMaxDcaZ(cfgtrksel.maxDcaZ); + myTrackFilter.SetMaxChi2PerClusterTPC(cfgtrksel.maxChi2PerClusterTPC); + myTrackFilter.print(); + + tofNsigmaCut = tofNsigmaPidCut; + itsNsigmaCut = itsNsigmaPidCut; + tpcNsigmaCut = tpcNsigmaPidCut; + + cfgSgCuts = (SGCutParHolder)sgCuts; + } + + Produces collisionLRTable; + Produces tracksLRTable; + Produces ft0aLRTable; + Produces ft0cLRTable; + Produces mftLRTable; + Produces mftbestLRTable; + Produces v0LRTable; + + Produces outupccol; + Produces outsgupccol; + Produces outzdctable; + + Produces tracksLRUpcTable; + Produces ft0aLRUpcTable; + Produces ft0cLRUpcTable; + Produces mftLRUpcTable; + Produces mftbestLRUpcTable; + Produces v0LRUpcTable; + + Filter fTracksEta = nabs(aod::track::eta) < cfgtrksel.cfgEtaCut; + Filter fTracksPt = (aod::track::pt > cfgtrksel.cfgPtCutMin) && (aod::track::pt < cfgtrksel.cfgPtCutMax); + + using CollTable = soa::Join; + using TrksTable = soa::Filtered>; + using MftTrkTable = aod::MFTTracks; + using BCs = soa::Join; + + void processData(CollTable::iterator const& col, TrksTable const& tracks, + aod::FT0s const&, MftTrkTable const& mfttracks, + soa::SmallGroups const& retracks, + aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) + { + if (!isEventSelected(col)) { + return; + } + + auto multiplicity = countNTracks(tracks); + auto centrality = selColCent(col); + auto bc = col.bc_as(); + + collisionLRTable(bc.runNumber(), col.posZ(), multiplicity, centrality, bc.timestamp()); + + // track loop + for (const auto& track : tracks) { + if (!track.isGlobalTrack()) + continue; + if (!myTrackFilter.IsSelected(track)) + continue; + tracksLRTable(collisionLRTable.lastIndex(), track.pt(), track.eta(), track.phi(), aod::lrcorrtrktable::kSpCharge); + if (getTrackPID(track) == PionTrackN) + tracksLRTable(collisionLRTable.lastIndex(), track.pt(), track.eta(), track.phi(), aod::lrcorrtrktable::kSpPion); + if (getTrackPID(track) == KaonTrackN) + tracksLRTable(collisionLRTable.lastIndex(), track.pt(), track.eta(), track.phi(), aod::lrcorrtrktable::kSpKaon); + if (getTrackPID(track) == ProtonTrackN) + tracksLRTable(collisionLRTable.lastIndex(), track.pt(), track.eta(), track.phi(), aod::lrcorrtrktable::kSpProton); + } + + // ft0 loop + if (col.has_foundFT0()) { + const auto& ft0 = col.foundFT0(); + for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { + auto chanelid = ft0.channelA()[iCh]; + float ampl = ft0.amplitudeA()[iCh]; + auto phi = getPhiFT0(chanelid, 0); + auto eta = getEtaFT0(chanelid, 0); + ft0aLRTable(collisionLRTable.lastIndex(), chanelid, ampl, eta, phi); + } + for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { + auto chanelid = ft0.channelC()[iCh]; + float ampl = ft0.amplitudeC()[iCh]; + auto phi = getPhiFT0(chanelid, 1); + auto eta = getEtaFT0(chanelid, 1); + ft0cLRTable(collisionLRTable.lastIndex(), chanelid, ampl, eta, phi); + } + } + + // mft loop + for (const auto& track : mfttracks) { + if (!isMftTrackSelected(track)) + continue; + auto phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + mftLRTable(collisionLRTable.lastIndex(), track.pt(), track.eta(), phi); + } + + if (retracks.size() > 0) { + for (const auto& retrack : retracks) { + if (std::abs(retrack.bestDCAXY()) > cfgmfttrksel.cfigMftDcaxy) { + continue; // does not point to PV properly + } + auto track = retrack.mfttrack(); + if (!isMftTrackSelected(track)) { + continue; + } + auto phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + mftbestLRTable(collisionLRTable.lastIndex(), track.pt(), track.eta(), phi); + } + } + + // v0 loop + for (const auto& v0 : V0s) { + if (!isSelectV0Track(v0)) { // Quality selection for V0 prongs + continue; + } + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + double massV0 = 0.0; + + // K0short + if (isSelectK0s(col, v0)) { // candidate is K0s + v0LRTable(collisionLRTable.lastIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::lrcorrtrktable::kSpK0short); + } + + // Lambda and Anti-Lambda + bool lambdaTag = isSelectLambda(col, v0); + bool antilambdaTag = isSelectLambda(col, v0); + + // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) + if (lambdaTag) { // candidate is Lambda + massV0 = v0.mLambda(); + v0LRTable(collisionLRTable.lastIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::lrcorrtrktable::kSpLambda); + } + if (antilambdaTag) { // candidate is Anti-lambda + massV0 = v0.mAntiLambda(); + v0LRTable(collisionLRTable.lastIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::lrcorrtrktable::kSpALambda); + } // end of Lambda and Anti-Lambda processing + } + } // process function + + void processUpc(CollTable::iterator const& col, BCs const& bcs, + TrksTable const& tracks, aod::Zdcs const&, + aod::FV0As const& fv0as, aod::FT0s const& ft0s, + aod::FDDs const& fdds, MftTrkTable const& mfttracks, + soa::SmallGroups const& retracks, + aod::V0Datas const& V0s) + { + if (!isEventSelected(col)) { + return; + } + + if (!col.has_foundBC()) { + return; + } + + auto bc = col.template foundBC_as(); + auto newbc = bc; + // obtain slice of compatible BCs + auto bcRange = udhelpers::compatibleBCs(col, cfgSgCuts.NDtcoll(), bcs, cfgSgCuts.minNBCs()); + auto isSGEvent = sgSelector.IsSelected(cfgSgCuts, col, bcRange, bc); + int issgevent = isSGEvent.value; + histos.fill(HIST("hSelectionResult"), isSGEvent.value); + + if (issgevent <= cfgGapSide) { + if (cfgSgCuts.minRgtrwTOF()) { + if (udhelpers::rPVtrwTOF(tracks, col.numContrib()) < cfgSgCuts.minRgtrwTOF()) + return; + } + + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, newbc, bcs, ft0s, fv0as, fdds); + auto multiplicity = countNTracks(tracks); + outupccol(bc.globalBC(), bc.runNumber(), col.posZ(), multiplicity, fitInfo.ampFT0A, fitInfo.ampFT0C, fitInfo.timeFV0A); + outsgupccol(issgevent); + if (newbc.has_zdc()) { + auto zdc = newbc.zdc(); + outzdctable(outupccol.lastIndex(), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + } else { + outzdctable(outupccol.lastIndex(), -999, -999); + } + + // track loop + for (const auto& track : tracks) { + if (!track.isGlobalTrack()) + continue; + if (!myTrackFilter.IsSelected(track)) + continue; + tracksLRUpcTable(outupccol.lastIndex(), track.pt(), track.eta(), track.phi(), aod::lrcorrtrktable::kSpCharge); + if (getTrackPID(track) == PionTrackN) + tracksLRUpcTable(outupccol.lastIndex(), track.pt(), track.eta(), track.phi(), aod::lrcorrtrktable::kSpPion); + if (getTrackPID(track) == KaonTrackN) + tracksLRUpcTable(outupccol.lastIndex(), track.pt(), track.eta(), track.phi(), aod::lrcorrtrktable::kSpKaon); + if (getTrackPID(track) == ProtonTrackN) + tracksLRUpcTable(outupccol.lastIndex(), track.pt(), track.eta(), track.phi(), aod::lrcorrtrktable::kSpProton); + } + + // ft0 loop + if (col.has_foundFT0()) { + const auto& ft0 = col.foundFT0(); + for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { + auto chanelid = ft0.channelA()[iCh]; + float ampl = ft0.amplitudeA()[iCh]; + auto phi = getPhiFT0(chanelid, 0); + auto eta = getEtaFT0(chanelid, 0); + ft0aLRUpcTable(outupccol.lastIndex(), chanelid, ampl, eta, phi); + } + for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { + auto chanelid = ft0.channelC()[iCh]; + float ampl = ft0.amplitudeC()[iCh]; + auto phi = getPhiFT0(chanelid, 1); + auto eta = getEtaFT0(chanelid, 1); + ft0cLRUpcTable(outupccol.lastIndex(), chanelid, ampl, eta, phi); + } + } + + // mft loop + for (const auto& track : mfttracks) { + if (!isMftTrackSelected(track)) + continue; + auto phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + mftLRUpcTable(outupccol.lastIndex(), track.pt(), track.eta(), phi); + } + + if (retracks.size() > 0) { + for (const auto& retrack : retracks) { + if (std::abs(retrack.bestDCAXY()) > cfgmfttrksel.cfigMftDcaxy) { + continue; // does not point to PV properly + } + auto track = retrack.mfttrack(); + if (!isMftTrackSelected(track)) { + continue; + } + auto phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + mftbestLRUpcTable(outupccol.lastIndex(), track.pt(), track.eta(), phi); + } + } + + // v0 loop + for (const auto& v0 : V0s) { + if (!isSelectV0Track(v0)) { // Quality selection for V0 prongs + continue; + } + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + double massV0 = 0.0; + + // K0short + if (isSelectK0s(col, v0)) { // candidate is K0s + v0LRUpcTable(outupccol.lastIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::lrcorrtrktable::kSpK0short); + } + + // Lambda and Anti-Lambda + bool lambdaTag = isSelectLambda(col, v0); + bool antilambdaTag = isSelectLambda(col, v0); + + // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) + if (lambdaTag) { // candidate is Lambda + massV0 = v0.mLambda(); + v0LRUpcTable(outupccol.lastIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::lrcorrtrktable::kSpLambda); + } + if (antilambdaTag) { // candidate is Anti-lambda + massV0 = v0.mAntiLambda(); + v0LRUpcTable(outupccol.lastIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::lrcorrtrktable::kSpALambda); + } // end of Lambda and Anti-Lambda processing + } + } // SG events + } + + template + bool isEventSelected(CheckCol const& col) + { + histos.fill(HIST("EventHist"), 1); + if (cfgevtsel.isApplyTrigTvx && !col.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + histos.fill(HIST("EventHist"), 2); + if (cfgevtsel.isApplyTfborder && !col.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + histos.fill(HIST("EventHist"), 3); + if (cfgevtsel.isApplyItsRofborder && !col.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + histos.fill(HIST("EventHist"), 4); + if (cfgevtsel.isApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("EventHist"), 5); + if (cfgevtsel.isApplyGoodZvtxFT0vsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + histos.fill(HIST("EventHist"), 6); + if (cfgevtsel.isApplyGoodITSLayersAll && !col.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + histos.fill(HIST("EventHist"), 7); + if (cfgevtsel.isApplyExtraCorrCut && col.multNTracksPV() > cfgevtsel.npvTracksCut && col.multFT0C() < (10 * col.multNTracksPV() - cfgevtsel.ft0cCut)) { + return false; + } + histos.fill(HIST("EventHist"), 8); + if (cfgevtsel.isApplyNoCollInTimeRangeStandard && !col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 9); + if (cfgevtsel.isApplyNoCollInRofStandard && !col.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 10); + if (cfgevtsel.isApplyNoHighMultCollInPrevRof && !col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + histos.fill(HIST("EventHist"), 11); + if (cfgevtsel.isApplyOccuSelection && (col.trackOccupancyInTimeRange() > cfgevtsel.cfgOccuCut)) { + return false; + } + histos.fill(HIST("EventHist"), 12); + return true; + } + + template + int countNTracks(countTrk const& tracks) + { + auto nTrk = 0; + for (const auto& track : tracks) { + if (!track.isGlobalTrack()) + continue; + if (!myTrackFilter.IsSelected(track)) + continue; + if (track.pt() < cfgtrksel.cfgPtCutMin || track.pt() > cfgtrksel.cfgPtCutMult) { + continue; + } + nTrk++; + } + return nTrk; + } + + template + float selColCent(CheckColCent const& col) + { + auto cent = -1; + if (cfgevtsel.isApplyCentFT0C) { + cent = col.centFT0C(); + } + if (cfgevtsel.isApplyCentFV0A) { + cent = col.centFV0A(); + } + if (cfgevtsel.isApplyCentFT0M) { + cent = col.centFT0M(); + } + return cent; + } + + template + int getTrackPID(TTrack const& track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaTOF = {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + std::array nSigmaITS = {itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track)}; + std::array nSigmaToUse = isUseItsPid ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS + std::vector detectorNsigmaCut = isUseItsPid ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS + int pid = -1; + bool isPion, isKaon, isProton; + bool isDetectedPion = nSigmaToUse[0] < detectorNsigmaCut[0] && nSigmaToUse[0] > detectorNsigmaCut[0 + 3]; + bool isDetectedKaon = nSigmaToUse[1] < detectorNsigmaCut[1] && nSigmaToUse[1] > detectorNsigmaCut[1 + 3]; + bool isDetectedProton = nSigmaToUse[2] < detectorNsigmaCut[2] && nSigmaToUse[2] > detectorNsigmaCut[2 + 3]; + + bool isTofPion = nSigmaTOF[0] < tofNsigmaCut[0] && nSigmaTOF[0] > tofNsigmaCut[0 + 3]; + bool isTofKaon = nSigmaTOF[1] < tofNsigmaCut[1] && nSigmaTOF[1] > tofNsigmaCut[1 + 3]; + bool isTofProton = nSigmaTOF[2] < tofNsigmaCut[2] && nSigmaTOF[2] > tofNsigmaCut[2 + 3]; + + if (track.pt() > cfgTofPidPtCut && !track.hasTOF()) { + return 0; + } else if (track.pt() > cfgTofPidPtCut && track.hasTOF()) { + isPion = isTofPion && isDetectedPion; + isKaon = isTofKaon && isDetectedKaon; + isProton = isTofProton && isDetectedProton; + } else { + isPion = isDetectedPion; + isKaon = isDetectedKaon; + isProton = isDetectedProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + return 0; // more than one particle satisfy the criteria + } + + if (isPion) { + pid = PIONS; + } else if (isKaon) { + pid = KAONS; + } else if (isProton) { + pid = PROTONS; + } else { + return 0; // no particle satisfies the criteria + } + + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + + double getPhiFT0(uint chno, int i) + { + ft0Det.calculateChannelCenter(); + auto chPos = ft0Det.getChannelCenter(chno); + return RecoDecay::phi(chPos.X() + (*offsetFT0)[i].getX(), chPos.Y() + (*offsetFT0)[i].getY()); + } + + double getEtaFT0(uint chno, int i) + { + ft0Det.calculateChannelCenter(); + auto chPos = ft0Det.getChannelCenter(chno); + auto x = chPos.X() + (*offsetFT0)[i].getX(); + auto y = chPos.Y() + (*offsetFT0)[i].getY(); + auto z = chPos.Z() + (*offsetFT0)[i].getZ(); + if (chno >= KminFt0cCell) + z = -z; + auto r = std::sqrt(x * x + y * y); + auto theta = std::atan2(r, z); + return -std::log(std::tan(0.5 * theta)); + } + + template + bool isMftTrackSelected(CheckMftTrack const& track) + { + if (track.nClusters() < cfgmfttrksel.cfigMftCluster) { + return false; + } + if (track.eta() > cfgmfttrksel.cfigMftEtaMax || track.eta() < cfgmfttrksel.cfigMftEtaMin) { + return false; + } + if (cfgmfttrksel.useMftPtCut && (track.pt() < cfgmfttrksel.cfgMftPtCutMin || track.pt() > cfgmfttrksel.cfgMftPtCutMax)) { + return false; + } + return true; + } + + template + bool isSelectV0Track(const T1& v0) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + if (!posTrack.hasTPC() || !negTrack.hasTPC()) { + return false; + } + if (posTrack.tpcNClsCrossedRows() < cfgv0trksel.minTPCcrossedrows || negTrack.tpcNClsCrossedRows() < cfgv0trksel.minTPCcrossedrows) { + return false; + } + if (posTrack.tpcCrossedRowsOverFindableCls() < cfgv0trksel.minTPCcrossedrowsoverfindcls || negTrack.tpcCrossedRowsOverFindableCls() < cfgv0trksel.minTPCcrossedrowsoverfindcls) { + return false; + } + if (std::abs(v0.positiveeta()) > cfgv0trksel.v0etaCut || std::abs(v0.negativeeta()) > cfgv0trksel.v0etaCut) { + return false; + } + if (v0.positivept() < cfgv0trksel.v0ptCut || v0.negativept() < cfgv0trksel.v0ptCut) { + return false; + } + return true; + } + + template + bool isSelectK0s(Collision const& col, const V0candidate& v0) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + float ctauK0s = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * o2::constants::physics::MassK0; + + if (v0.mK0Short() < cfgv0trksel.minK0sMass || v0.mK0Short() > cfgv0trksel.maxK0sMass) { + return false; + } + if ((v0.qtarm() / std::abs(v0.alpha())) < cfgv0trksel.minqtArmenterosForK0s) { + return false; + } + if (v0.v0radius() > cfgv0trksel.maxK0sRadius || v0.v0radius() < cfgv0trksel.minK0sRadius) { + return false; + } + if (v0.v0cosPA() < cfgv0trksel.minK0sCosPa) { + return false; + } + if (v0.dcaV0daughters() > cfgv0trksel.maxDcaV0DauK0s) { + return false; + } + if (std::abs(ctauK0s) > cfgv0trksel.maxK0sLifeTime) { + return false; + } + if (((std::abs(posTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts))) { + return false; + } + if ((std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPiK0s || std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPiK0s)) { + return false; + } + return true; + } + + template + bool isSelectLambda(Collision const& col, const V0candidate& v0) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + float ctauLambda = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * o2::constants::physics::MassLambda; + if ((v0.mLambda() < cfgv0trksel.minLambdaMass || v0.mLambda() > cfgv0trksel.maxLambdaMass) && + (v0.mAntiLambda() < cfgv0trksel.minLambdaMass || v0.mAntiLambda() > cfgv0trksel.maxLambdaMass)) { + return false; + } + if (v0.v0radius() > cfgv0trksel.maxLambdaRadius || v0.v0radius() < cfgv0trksel.minLambdaRadius) { + return false; + } + if (v0.v0cosPA() < cfgv0trksel.minLambdaCosPa) { + return false; + } + if (v0.dcaV0daughters() > cfgv0trksel.maxDcaV0DauLambda) { + return false; + } + if (pid == KindOfV0::kLambda && (std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPr || std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPiLambda)) { + return false; + } + if (pid == KindOfV0::kAntiLambda && (std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPiLambda || std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPr)) { + return false; + } + if (pid == KindOfV0::kLambda && ((std::abs(posTrack.tpcNSigmaPr()) > cfgv0trksel.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts))) { + return false; + } + if (pid == KindOfV0::kAntiLambda && ((std::abs(posTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > cfgv0trksel.daughPIDCuts))) { + return false; + } + if (std::abs(ctauLambda) > cfgv0trksel.maxLambdaLifeTime) { + return false; + } + return true; + } + + PROCESS_SWITCH(LongrangeMaker, processData, "process All collisions", false); + PROCESS_SWITCH(LongrangeMaker, processUpc, "process UPC collisions", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/twoParticleCorrelationsFullSkimming.cxx b/PWGCF/TwoParticleCorrelations/TableProducer/twoParticleCorrelationsFullSkimming.cxx index 2dec74acf61..907a885f2b9 100644 --- a/PWGCF/TwoParticleCorrelations/TableProducer/twoParticleCorrelationsFullSkimming.cxx +++ b/PWGCF/TwoParticleCorrelations/TableProducer/twoParticleCorrelationsFullSkimming.cxx @@ -9,18 +9,21 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGCF/TwoParticleCorrelations/Core/FilterAndAnalysisFramework.h" +#include "PWGCF/TwoParticleCorrelations/DataModel/TwoParticleCorrelationsSkimmed.h" + #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGCF/TwoParticleCorrelations/DataModel/TwoParticleCorrelationsSkimmed.h" -#include "PWGCF/TwoParticleCorrelations/Core/FilterAndAnalysisFramework.h" -#include "Framework/runDataProcessing.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include using namespace o2; using namespace o2::framework; diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/twoParticleCorrelationsNotStoredSkimming.cxx b/PWGCF/TwoParticleCorrelations/TableProducer/twoParticleCorrelationsNotStoredSkimming.cxx index 3964b745b91..274207c246c 100644 --- a/PWGCF/TwoParticleCorrelations/TableProducer/twoParticleCorrelationsNotStoredSkimming.cxx +++ b/PWGCF/TwoParticleCorrelations/TableProducer/twoParticleCorrelationsNotStoredSkimming.cxx @@ -9,18 +9,21 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGCF/TwoParticleCorrelations/Core/FilterAndAnalysisFramework.h" +#include "PWGCF/TwoParticleCorrelations/DataModel/TwoParticleCorrelationsSkimmed.h" + #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGCF/TwoParticleCorrelations/DataModel/TwoParticleCorrelationsSkimmed.h" -#include "PWGCF/TwoParticleCorrelations/Core/FilterAndAnalysisFramework.h" -#include "Framework/runDataProcessing.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include using namespace o2; using namespace o2::framework; diff --git a/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt index f6742441246..9d19b73cbbb 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt @@ -9,7 +9,7 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -o2physics_add_dpl_workflow(twopartcorr +o2physics_add_dpl_workflow(two-particle-correlations SOURCES twoParticleCorrelations.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::TwoPartCorrCore COMPONENT_NAME Analysis) @@ -23,27 +23,57 @@ o2physics_add_dpl_workflow(lambdacorr PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(identifiedbf - SOURCES identifiedbf.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(identifiedbf-filter-qa - SOURCES identifiedbfqa.cxx +o2physics_add_dpl_workflow(dpt-dpt-per-run-qc + SOURCES dptDptPerRunQc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB O2::DataFormatsITSMFT + 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(twopartcorr-efficiency-qc - SOURCES efficiencyAndQc.cxx +o2physics_add_dpl_workflow(neutron-proton-corr-zdc + SOURCES neutronProtonCorrZdc.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(di-hadron-cor + SOURCES diHadronCor.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pid-di-hadron + SOURCES pidDiHadron.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB O2Physics::GFWCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(longrange-correlation + SOURCES longrangeCorrelation.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(twopartcorr-per-run-qc - SOURCES perRunQc.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB +o2physics_add_dpl_workflow(longrangecorr-derived + SOURCES longrangecorrDerived.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(twopartcorr-per-run-extraqc - SOURCES perRunExtraQc.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB +o2physics_add_dpl_workflow(long-range-dihadron-cor + SOURCES longRangeDihadronCor.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::AnalysisCCDB O2Physics::GFWCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(two-particle-correlation-pp + SOURCES twoParticleCorrelationPp.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx b/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx new file mode 100644 index 00000000000..489c99bdbff --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/corrSparse.cxx @@ -0,0 +1,387 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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) + +#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/Multiplicity.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 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.02, "Merging cut on track merge") + O2_DEFINE_CONFIGURABLE(cfgApplyTwoTrackEfficiency, bool, true, "Apply two track efficiency for tpc tpc") + 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, -3.6, "Minimum eta for MFT track") + O2_DEFINE_CONFIGURABLE(etaMftTrackMax, float, -2.5, "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"}; + + SliceCache cache; + SliceCache cacheNch; + + 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::evsel::sel8) == true; + Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (cfgPtCutMin < aod::track::pt) && (cfgPtCutMax > aod::track::pt) && ((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("Nch_used", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); // histogram to see how many events are in the same and mixed event + registry.add("zVtx", "zVtx", {HistType::kTH1D, {axisVertex}}); + + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + + registry.add("eventcount", "bin", {HistType::kTH1F, {{4, 0, 4, "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() < etaMftTrackMin || mftTrack.eta() > etaMftTrackMax) { + 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) { + + if (processMFT) { + if constexpr (std::is_same_v) { + if (!isAcceptedMftTrack(track1)) { + continue; + } + } + } + + registry.fill(HIST("Phi"), RecoDecay::constrainAngle(track1.phi(), 0.0)); + 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, 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("Nch_used"), tracks1.size()); + registry.fill(HIST("Trig_hist"), fSampleIndex, posZ, track1.pt()); + } + + for (auto const& track2 : tracks2) { + + if (processMFT) { + if constexpr (std::is_same_v) { + if (!isAcceptedMftTrack(track2)) { + continue; + } + } + } else { + if (track1.pt() <= track2.pt()) + continue; // skip if the trigger pt is less than the associate pt + } + + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -PIHalf); + float deltaEta = track1.eta() - track2.eta(); + + if (cfgApplyTwoTrackEfficiency && 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 = false; + + 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 = true; + 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 + + if (processMFT) { + fillYield(collision, mfts); + + if (tracks.size() < cfgMinMult || tracks.size() >= cfgMaxMult) { + return; + } + + fillCorrelations(tracks, mfts, collision.posZ(), SameEvent, getMagneticField(bc.timestamp())); + + } else { + fillYield(collision, tracks); + + if (tracks.size() < cfgMinMult || tracks.size() >= cfgMaxMult) { + return; + } + + fillCorrelations(tracks, tracks, collision.posZ(), SameEvent, getMagneticField(bc.timestamp())); + } + } + PROCESS_SWITCH(CorrSparse, processSame, "Process same event", true); + + // the process for filling the mixed events + void processMixed(AodCollisions const& collisions, AodTracks const& tracks, aod::MFTTracks const& MFTtracks, aod::BCsWithTimestamps const&) + { + + auto getTracksSize = [&tracks, this](AodCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {vtxMix, multMix}, true}; + + if (processMFT) { + + auto tracksTuple = std::make_tuple(tracks, MFTtracks); + Pair pair{binningOnVtxAndMult, cfgMinMixEventNum, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + for (auto const& [collision1, tracks1, collision2, tracks2] : pair) { + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + + if ((tracks1.size() < cfgMinMult || tracks1.size() >= cfgMaxMult)) + continue; + + fillCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, getMagneticField(bc.timestamp())); + } + } else { + auto tracksTuple = std::make_tuple(tracks, tracks); + Pair pair{binningOnVtxAndMult, cfgMinMixEventNum, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + for (auto const& [collision1, tracks1, collision2, tracks2] : pair) { + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + + if ((tracks1.size() < cfgMinMult || tracks1.size() >= cfgMaxMult)) + continue; + + if ((tracks2.size() < cfgMinMult || tracks2.size() >= cfgMaxMult)) + continue; + + fillCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, getMagneticField(bc.timestamp())); + } + } + } + + PROCESS_SWITCH(CorrSparse, processMixed, "Process mixed events", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/diHadronCor.cxx b/PWGCF/TwoParticleCorrelations/Tasks/diHadronCor.cxx new file mode 100644 index 00000000000..b76a0d454cb --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/diHadronCor.cxx @@ -0,0 +1,1203 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file diHadronCor.cxx +/// \brief di-hadron correlation for O-O, Pb-Pb collisions +/// \author Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since May/03/2025 + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWCumulant.h" +#include "PWGCF/GenericFramework/Core/GFWPowerArray.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" + +#include "Common/Core/RecoDecay.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 "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include + +#include "TF1.h" +#include "TRandom3.h" +#include + +#include +#include + +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 DiHadronCor { + Service ccdb; + + O2_DEFINE_CONFIGURABLE(cfgCutVtxZ, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "minimum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "maximum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta cut") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 50.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCCrossedRows, float, 70.0f, "minimum TPC crossed rows") + 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(cfgCutMerging, float, 0.0, "Merging cut on track merge") + O2_DEFINE_CONFIGURABLE(cfgSelCollByNch, bool, true, "Select collisions by Nch or centrality") + O2_DEFINE_CONFIGURABLE(cfgCutMultMin, int, 0, "Minimum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgCutMultMax, int, 10, "Maximum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgCutCentMin, float, 60.0f, "Minimum centrality for collision") + O2_DEFINE_CONFIGURABLE(cfgCutCentMax, float, 80.0f, "Maximum centrality for collision") + O2_DEFINE_CONFIGURABLE(cfgMixEventNumMin, int, 5, "Minimum number of events to mix") + 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(cfgSampleSize, double, 10, "Sample size for mixed event") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") + O2_DEFINE_CONFIGURABLE(cfgCentTableUnavailable, bool, false, "if a dataset does not provide centrality information") + 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(cfgEvSelkNoITSROFrameBorder, bool, false, "reject events at ITS ROF border") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoTimeFrameBorder, bool, false, "reject events at TF border") + 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, 2000, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyLow, int, 0, "Low cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgCentralityWeight, std::string, "", "CCDB path to centrality weight object") + O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, bool, false, "Use local efficiency object") + O2_DEFINE_CONFIGURABLE(cfgVerbosity, bool, false, "Verbose output") + O2_DEFINE_CONFIGURABLE(cfgUseEventWeights, bool, false, "Use event weights for mixed event") + O2_DEFINE_CONFIGURABLE(cfgUsePtOrder, bool, true, "enable trigger pT < associated pT cut") + O2_DEFINE_CONFIGURABLE(cfgUsePtOrderInMixEvent, bool, true, "enable trigger pT < associated pT cut in mixed event") + O2_DEFINE_CONFIGURABLE(cfgSoloPtTrack, bool, false, "Skip trigger tracks that are alone in their pT bin for same process") + O2_DEFINE_CONFIGURABLE(cfgSingleSoloPtTrack, bool, false, "Skip associated tracks that are alone in their pT bin for same process, works only if cfgSoloPtTrack is enabled") + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgMultCentHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 10.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCentLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultT0CCutEnabled, bool, false, "Enable Global multiplicity vs T0C centrality cut") + Configurable> cfgMultT0CCutPars{"cfgMultT0CCutPars", std::vector{143.04, -4.58368, 0.0766055, -0.000727796, 2.86153e-06, 23.3108, -0.36304, 0.00437706, -4.717e-05, 1.98332e-07}, "Global multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultPVT0CCutEnabled, bool, false, "Enable PV multiplicity vs T0C centrality cut") + Configurable> cfgMultPVT0CCutPars{"cfgMultPVT0CCutPars", std::vector{195.357, -6.15194, 0.101313, -0.000955828, 3.74793e-06, 30.0326, -0.43322, 0.00476265, -5.11206e-05, 2.13613e-07}, "PV multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultMultPVHighCutFunction, std::string, "[0]+[1]*x + 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultPVLowCutFunction, std::string, "[0]+[1]*x - 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCutEnabled, bool, false, "Enable global multiplicity vs PV multiplicity cut") + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", std::vector{-0.140809, 0.734344, 2.77495, 0.0165935}, "PV multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultMultV0AHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 4.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ALowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ACutEnabled, bool, false, "Enable global multiplicity vs V0A multiplicity cut") + Configurable> cfgMultMultV0ACutPars{"cfgMultMultV0ACutPars", std::vector{534.893, 184.344, 0.423539, -0.00331436, 5.34622e-06, 871.239, 53.3735, -0.203528, 0.000122758, 5.41027e-07}, "Global multiplicity vs V0A multiplicity cut parameter values"}; + std::vector multT0CCutPars; + std::vector multPVT0CCutPars; + std::vector multGlobalPVCutPars; + std::vector multMultV0ACutPars; + TF1* fMultPVT0CCutLow = nullptr; + TF1* fMultPVT0CCutHigh = nullptr; + TF1* fMultT0CCutLow = nullptr; + TF1* fMultT0CCutHigh = nullptr; + TF1* fMultGlobalPVCutLow = nullptr; + TF1* fMultGlobalPVCutHigh = nullptr; + TF1* fMultMultV0ACutLow = nullptr; + TF1* fMultMultV0ACutHigh = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + } cfgFuncParas; + + SliceCache cache; + + ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 10, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260}, "multiplicity 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 axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "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.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt trigger axis for histograms"}; + ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt associated axis for histograms"}; + ConfigurableAxis axisVtxMix{"axisVtxMix", {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 axisMultMix{"axisMultMix", {VARIABLE_WIDTH, 0, 10, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260}, "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.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt axis for efficiency histograms"}; + + // make the filters and cuts. + Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVtxZ); + 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); + using FilteredCollisions = soa::Filtered>; + using FilteredTracks = soa::Filtered>; + using FilteredTracksWithMCLabels = soa::Filtered>; + + // Filter for MCParticle + Filter particleFilter = (nabs(aod::mcparticle::eta) < cfgCutEta) && (aod::mcparticle::pt > cfgCutPtMin) && (aod::mcparticle::pt < cfgCutPtMax); + using FilteredMcParticles = soa::Filtered; + + // Filter for MCcollisions + Filter mccollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVtxZ; + using FilteredMcCollisions = soa::Filtered; + + using SmallGroupMcCollisions = soa::SmallGroups>; + + Preslice perCollision = aod::track::collisionId; + PresliceUnsorted collisionPerMCCollision = aod::mccollisionlabel::mcCollisionId; + + // Corrections + TH3D* mEfficiency = nullptr; + TH1D* mCentralityWeight = nullptr; + bool correctionsLoaded = false; + + // Define the outputs + OutputObj same{"sameEvent"}; + OutputObj mixed{"mixedEvent"}; + HistogramRegistry registry{"registry"}; + + // define global variables + TRandom3* gRandom = new TRandom3(); + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + // Count the total number of enum + kCount_CentEstimators + }; + enum EventType { + SameEvent = 1, + MixedEvent = 3 + }; + + // persistent caches + std::vector efficiencyAssociatedCache; + + void init(InitContext&) + { + if (cfgCentTableUnavailable && !cfgSelCollByNch) { + LOGF(fatal, "Centrality table is unavailable, cannot select collisions by centrality"); + } + const AxisSpec axisPhi{72, 0.0, constants::math::TwoPI, "#varphi"}; + const AxisSpec axisEta{40, -1., 1., "#eta"}; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + LOGF(info, "Starting init"); + + // Event Counter + if (doprocessSame && cfgUseAdditionalEventCut) { + registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{12, 0, 12}}}); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(3, "kNoITSROFrameBorder"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(4, "kNoTimeFrameBorder"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(5, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(6, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(7, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(8, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(9, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(10, "occupancy"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(11, "MultCorrelation"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(12, "cfgEvSelV0AT0ACut"); + } + + if (cfgEvSelMultCorrelation) { + cfgFuncParas.multT0CCutPars = cfgFuncParas.cfgMultT0CCutPars; + cfgFuncParas.multPVT0CCutPars = cfgFuncParas.cfgMultPVT0CCutPars; + cfgFuncParas.multGlobalPVCutPars = cfgFuncParas.cfgMultGlobalPVCutPars; + cfgFuncParas.multMultV0ACutPars = cfgFuncParas.cfgMultMultV0ACutPars; + cfgFuncParas.fMultPVT0CCutLow = new TF1("fMultPVT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutLow->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultPVT0CCutHigh = new TF1("fMultPVT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutHigh->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + + cfgFuncParas.fMultT0CCutLow = new TF1("fMultT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutLow->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultT0CCutHigh = new TF1("fMultT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutHigh->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + + cfgFuncParas.fMultGlobalPVCutLow = new TF1("fMultGlobalPVCutLow", cfgFuncParas.cfgMultMultPVLowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutLow->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultGlobalPVCutHigh = new TF1("fMultGlobalPVCutHigh", cfgFuncParas.cfgMultMultPVHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutHigh->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + + cfgFuncParas.fMultMultV0ACutLow = new TF1("fMultMultV0ACutLow", cfgFuncParas.cfgMultMultV0ALowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutLow->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fMultMultV0ACutHigh = new TF1("fMultMultV0ACutHigh", cfgFuncParas.cfgMultMultV0AHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutHigh->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + + cfgFuncParas.fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + cfgFuncParas.fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + cfgFuncParas.fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + cfgFuncParas.fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + std::string hCentTitle = "Centrality distribution, Estimator " + std::to_string(cfgCentEstimator); + // Make histograms to check the distributions after cuts + if (doprocessSame) { + 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("EtaCorrected", "EtaCorrected", {HistType::kTH1D, {axisEta}}); + registry.add("pT", "pT", {HistType::kTH1D, {axisPtTrigger}}); + registry.add("pTCorrected", "pTCorrected", {HistType::kTH1D, {axisPtTrigger}}); + registry.add("Nch", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); + registry.add("Nch_used", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); // histogram to see how many events are in the same and mixed event + registry.add("Centrality", hCentTitle.c_str(), {HistType::kTH1D, {{100, 0, 100}}}); + registry.add("CentralityWeighted", hCentTitle.c_str(), {HistType::kTH1D, {{100, 0, 100}}}); + registry.add("Centrality_used", hCentTitle.c_str(), {HistType::kTH1D, {{100, 0, 100}}}); // histogram to see how many events are in the same and mixed event + registry.add("zVtx", "zVtx", {HistType::kTH1D, {axisVertex}}); + registry.add("zVtx_used", "zVtx_used", {HistType::kTH1D, {axisVertex}}); + registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + } + if (cfgSoloPtTrack && doprocessSame) { + registry.add("Nch_final_pt", "pT", {HistType::kTH1D, {axisPtTrigger}}); + registry.add("Solo_tracks_trigger", "pT", {HistType::kTH1D, {axisPtTrigger}}); + if (!cfgSingleSoloPtTrack) { + registry.add("Solo_tracks_assoc", "pT", {HistType::kTH1D, {axisPtAssoc}}); + } + } + + registry.add("eventcount", "bin", {HistType::kTH1F, {{4, 0, 4, "bin"}}}); // histogram to see how many events are in the same and mixed event + if (doprocessMCSame && doprocessOntheflySame) { + LOGF(fatal, "Full simulation and on-the-fly processing of same event not supported"); + } + if (doprocessMCMixed && doprocessOntheflyMixed) { + LOGF(fatal, "Full simulation and on-the-fly processing of mixed event not supported"); + } + if (doprocessMCSame || doprocessOntheflySame) { + registry.add("MCTrue/MCeventcount", "MCeventcount", {HistType::kTH1F, {{5, 0, 5, "bin"}}}); // histogram to see how many events are in the same and mixed event + registry.get(HIST("MCTrue/MCeventcount"))->GetXaxis()->SetBinLabel(2, "same all"); + registry.get(HIST("MCTrue/MCeventcount"))->GetXaxis()->SetBinLabel(3, "same reco"); + registry.get(HIST("MCTrue/MCeventcount"))->GetXaxis()->SetBinLabel(4, "mixed all"); + registry.get(HIST("MCTrue/MCeventcount"))->GetXaxis()->SetBinLabel(5, "mixed reco"); + registry.add("MCTrue/MCCentrality", hCentTitle.c_str(), {HistType::kTH1D, {axisCentrality}}); + registry.add("MCTrue/MCNch", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); + registry.add("MCTrue/MCzVtx", "MCzVtx", {HistType::kTH1D, {axisVertex}}); + registry.add("MCTrue/MCPhi", "MCPhi", {HistType::kTH1D, {axisPhi}}); + registry.add("MCTrue/MCEta", "MCEta", {HistType::kTH1D, {axisEta}}); + registry.add("MCTrue/MCpT", "MCpT", {HistType::kTH1D, {axisPtTrigger}}); + registry.add("MCTrue/MCTrig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + registry.add("MCTrue/MCdeltaEta_deltaPhi_same", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // check to see the delta eta and delta phi distribution + registry.add("MCTrue/MCdeltaEta_deltaPhi_mixed", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); + } + if (doprocessMCEfficiency) { + registry.add("MCEffeventcount", "bin", {HistType::kTH1F, {{5, 0, 5, "bin"}}}); + registry.get(HIST("MCEffeventcount"))->GetXaxis()->SetBinLabel(1, "All"); + registry.get(HIST("MCEffeventcount"))->GetXaxis()->SetBinLabel(2, "MC"); + registry.get(HIST("MCEffeventcount"))->GetXaxis()->SetBinLabel(3, "Reco Primary"); + registry.get(HIST("MCEffeventcount"))->GetXaxis()->SetBinLabel(4, "Reco All"); + registry.get(HIST("MCEffeventcount"))->GetXaxis()->SetBinLabel(5, "Fake"); + } + + LOGF(info, "Initializing correlation container"); + 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 = { + {axisEtaEfficiency, "#eta"}, + {axisPtEfficiency, "p_{T} (GeV/c)"}, + {axisVertexEfficiency, "z-vtx (cm)"}, + }; + std::vector userAxis; + + same.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + + LOGF(info, "End of init"); + } + + 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(); + } + + template + float getCentrality(TCollision const& collision) + { + 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(); + } + return cent; + } + + template + bool trackSelected(TTrack track) + { + return ((track.tpcNClsFound() >= cfgCutTPCclu) && (track.tpcNClsCrossedRows() >= cfgCutTPCCrossedRows) && (track.itsNCls() >= cfgCutITSclu)); + } + + template + bool genTrackSelected(TTrack track) + { + if (!track.isPhysicalPrimary()) { + return false; + } + if (!track.producedByGenerator()) { + return false; + } + if (std::abs(track.eta()) > cfgCutEta) { + return false; + } + if (std::abs(track.pt()) < cfgCutPtMin || std::abs(track.pt()) > cfgCutPtMax) { + return false; + } + return true; + } + + void loadCorrection(uint64_t timestamp) + { + if (correctionsLoaded) { + return; + } + if (cfgEfficiency.value.empty() == false) { + if (cfgLocalEfficiency > 0) { + TFile* fEfficiencyTrigger = TFile::Open(cfgEfficiency.value.c_str(), "READ"); + mEfficiency = reinterpret_cast(fEfficiencyTrigger->Get("ccdb_object")); + } else { + 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 (cfgCentralityWeight.value.empty() == false) { + mCentralityWeight = ccdb->getForTimeStamp(cfgCentralityWeight, timestamp); + if (mCentralityWeight == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgCentralityWeight.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgCentralityWeight.value.c_str(), (void*)mCentralityWeight); + } + correctionsLoaded = true; + } + + bool getEfficiencyCorrection(float& weight_nue, float eta, float pt, float posZ) + { + float eff = 1.; + if (mEfficiency) { + int etaBin = mEfficiency->GetXaxis()->FindBin(eta); + int ptBin = mEfficiency->GetYaxis()->FindBin(pt); + int zBin = mEfficiency->GetZaxis()->FindBin(posZ); + eff = mEfficiency->GetBinContent(etaBin, ptBin, zBin); + } else { + eff = 1.0; + } + if (eff == 0) + return false; + weight_nue = 1. / eff; + return true; + } + + bool getCentralityWeight(float& weightCent, const float centrality) + { + float weight = 1.; + if (mCentralityWeight) + weight = mCentralityWeight->GetBinContent(mCentralityWeight->FindBin(centrality)); + else + weight = 1.0; + if (weight == 0) + return false; + weightCent = weight; + return true; + } + + // fill multiple histograms + template + void fillYield(TCollision collision, TTracks tracks) // function to fill the yield and etaphi histograms. + { + float weff1 = 1; + float vtxz = collision.posZ(); + for (auto const& track1 : tracks) { + if (!trackSelected(track1)) + continue; + if (!getEfficiencyCorrection(weff1, track1.eta(), track1.pt(), vtxz)) + continue; + registry.fill(HIST("Phi"), RecoDecay::constrainAngle(track1.phi(), 0.0)); + registry.fill(HIST("Eta"), track1.eta()); + registry.fill(HIST("EtaCorrected"), track1.eta(), weff1); + registry.fill(HIST("pT"), track1.pt()); + registry.fill(HIST("pTCorrected"), track1.pt(), weff1); + } + } + + 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, int magneticField, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + // Cache efficiency for particles (too many FindBin lookups) + if (mEfficiency) { + efficiencyAssociatedCache.clear(); + efficiencyAssociatedCache.reserve(tracks2.size()); + for (const auto& track2 : tracks2) { + float weff = 1.; + getEfficiencyCorrection(weff, track2.eta(), track2.pt(), posZ); + efficiencyAssociatedCache.push_back(weff); + } + } + + if (system == SameEvent) { + if (!cfgCentTableUnavailable) + registry.fill(HIST("Centrality_used"), cent); + registry.fill(HIST("Nch_used"), tracks1.size()); + } + + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + float triggerWeight = 1.0f; + float associatedWeight = 1.0f; + // loop over all tracks + for (auto const& track1 : tracks1) { + + if (!trackSelected(track1)) + continue; + if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) + continue; + if (system == SameEvent) { + registry.fill(HIST("Trig_hist"), fSampleIndex, posZ, track1.pt(), eventWeight * triggerWeight); + } + + for (auto const& track2 : tracks2) { + + if (!trackSelected(track2)) + continue; + if (mEfficiency) { + associatedWeight = efficiencyAssociatedCache[track2.filteredIndex()]; + } + + if (!cfgUsePtOrder && track1.globalIndex() == track2.globalIndex()) + continue; // For pt-differential correlations, skip if the trigger and associate are the same track + if (cfgUsePtOrder && system == SameEvent && track1.pt() <= track2.pt()) + continue; // Without pt-differential correlations, skip if the trigger pt is less than the associate pt + if (cfgUsePtOrder && system == MixedEvent && cfgUsePtOrderInMixEvent && track1.pt() <= track2.pt()) + continue; // For pt-differential correlations in mixed events, skip if the trigger pt is less than the associate pt + + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -PIHalf); + float deltaEta = track1.eta() - track2.eta(); + + if (std::abs(deltaEta) < cfgCutMerging) { + + double dPhiStarHigh = getDPhiStar(track1, track2, cfgRadiusHigh, magneticField); + double dPhiStarLow = getDPhiStar(track1, track2, cfgRadiusLow, magneticField); + + const double kLimit = 3.0 * cfgCutMerging; + + bool bIsBelow = false; + + 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 = true; + 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, eventWeight * triggerWeight * associatedWeight); + registry.fill(HIST("deltaEta_deltaPhi_same"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } else if (system == MixedEvent) { + + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + registry.fill(HIST("deltaEta_deltaPhi_mixed"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } + } + } + } + + template + void fillCorrelationsExcludeSoloTracks(TTracks tracks1, TTracksAssoc tracks2, float posZ, int magneticField, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + std::vector tracksSkipIndices; + std::vector tracks2SkipIndices; + + findBiasedTracks(tracks1, tracksSkipIndices, posZ); + if (!cfgSingleSoloPtTrack) { // only look for the solo pt tracks if we want to skip both + findBiasedTracks(tracks2, tracks2SkipIndices, posZ); + } + + // Cache efficiency for particles (too many FindBin lookups) + if (mEfficiency) { + efficiencyAssociatedCache.clear(); + efficiencyAssociatedCache.reserve(tracks2.size()); + for (const auto& track2 : tracks2) { + float weff = 1.; + getEfficiencyCorrection(weff, track2.eta(), track2.pt(), posZ); + efficiencyAssociatedCache.push_back(weff); + } + } + + if (!cfgCentTableUnavailable) + registry.fill(HIST("Centrality_used"), cent); + registry.fill(HIST("Nch_used"), tracks1.size()); + + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + float triggerWeight = 1.0f; + float associatedWeight = 1.0f; + // loop over all tracks + for (auto const& track1 : tracks1) { + + if (!trackSelected(track1)) + continue; + if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) + continue; + + registry.fill(HIST("Nch_final_pt"), track1.pt()); + + if (std::find(tracksSkipIndices.begin(), tracksSkipIndices.end(), track1.globalIndex()) != tracksSkipIndices.end()) { + registry.fill(HIST("Solo_tracks_trigger"), track1.pt()); + continue; // Skip the track1 if it is alone in pt bin + } + registry.fill(HIST("Trig_hist"), fSampleIndex, posZ, track1.pt(), eventWeight * triggerWeight); + + for (auto const& track2 : tracks2) { + + if (!trackSelected(track2)) + continue; + if (mEfficiency) { + associatedWeight = efficiencyAssociatedCache[track2.filteredIndex()]; + } + if (!cfgUsePtOrder && track1.globalIndex() == track2.globalIndex()) + continue; // For pt-differential correlations, skip if the trigger and associate are the same track + if (cfgUsePtOrder && track1.pt() <= track2.pt()) + continue; // Without pt-differential correlations, skip if the trigger pt is less than the associate pt + if (!cfgSingleSoloPtTrack) { // avoid skipping the second track if we only want one + if (std::find(tracks2SkipIndices.begin(), tracks2SkipIndices.end(), track2.globalIndex()) != tracks2SkipIndices.end()) { + registry.fill(HIST("Solo_tracks_assoc"), track2.pt()); + continue; // Skip the track2 if it is alone in pt bin + } + } + + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -PIHalf); + float deltaEta = track1.eta() - track2.eta(); + + if (std::abs(deltaEta) < cfgCutMerging) { + + double dPhiStarHigh = getDPhiStar(track1, track2, cfgRadiusHigh, magneticField); + double dPhiStarLow = getDPhiStar(track1, track2, cfgRadiusLow, magneticField); + + const double kLimit = 3.0 * cfgCutMerging; + + bool bIsBelow = false; + + 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 = true; + break; + } + } + if (bIsBelow) + continue; + } + } + + // fill the right sparse and histograms + same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + registry.fill(HIST("deltaEta_deltaPhi_same"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } + } + } + + template + void fillMCCorrelations(TTracks tracks1, TTracksAssoc tracks2, float posZ, int system, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + float triggerWeight = 1.0f; + float associatedWeight = 1.0f; + // loop over all tracks + for (auto const& track1 : tracks1) { + if (step >= CorrelationContainer::kCFStepTrackedOnlyPrim && !track1.isPhysicalPrimary()) + continue; + if (doprocessOntheflySame && !genTrackSelected(track1)) + continue; + + if (system == SameEvent && (doprocessMCSame || doprocessOntheflySame)) + registry.fill(HIST("MCTrue/MCTrig_hist"), fSampleIndex, posZ, track1.pt(), eventWeight * triggerWeight); + + for (auto const& track2 : tracks2) { + + if (step >= CorrelationContainer::kCFStepTrackedOnlyPrim && !track2.isPhysicalPrimary()) + continue; + if (doprocessOntheflyMixed && !genTrackSelected(track2)) + continue; + + if (!cfgUsePtOrder && track1.globalIndex() == track2.globalIndex()) + continue; // For pt-differential correlations, skip if the trigger and associate are the same track + if (cfgUsePtOrder && system == SameEvent && track1.pt() <= track2.pt()) + continue; // Without pt-differential correlations, skip if the trigger pt is less than the associate pt + if (cfgUsePtOrder && system == MixedEvent && cfgUsePtOrderInMixEvent && track1.pt() <= track2.pt()) + continue; // For pt-differential correlations in mixed events, skip if the trigger pt is less than the associate pt + + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -PIHalf); + float deltaEta = track1.eta() - track2.eta(); + + // fill the right sparse and histograms + if (system == SameEvent) { + same->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + if (doprocessMCSame || doprocessOntheflySame) + registry.fill(HIST("MCTrue/MCdeltaEta_deltaPhi_same"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } else if (system == MixedEvent) { + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + if (doprocessMCMixed || doprocessOntheflyMixed) + registry.fill(HIST("MCTrue/MCdeltaEta_deltaPhi_mixed"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } + } + } + } + + template + bool eventSelected(TCollision collision, const int multTrk, const float centrality, const bool fillCounter) + { + 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 (fillCounter && cfgEvSelkNoSameBunchPileup) + registry.fill(HIST("hEventCountSpecific"), 1.5); + if (cfgEvSelkNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return 0; + } + if (fillCounter && cfgEvSelkNoITSROFrameBorder) + registry.fill(HIST("hEventCountSpecific"), 2.5); + if (cfgEvSelkNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return 0; + } + if (fillCounter && cfgEvSelkNoTimeFrameBorder) + registry.fill(HIST("hEventCountSpecific"), 3.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 (fillCounter && cfgEvSelkIsGoodZvtxFT0vsPV) + registry.fill(HIST("hEventCountSpecific"), 4.5); + if (cfgEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (fillCounter && cfgEvSelkNoCollInTimeRangeStandard) + registry.fill(HIST("hEventCountSpecific"), 5.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 (fillCounter && cfgEvSelkIsGoodITSLayersAll) + registry.fill(HIST("hEventCountSpecific"), 6.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 (fillCounter && cfgEvSelkNoCollInRofStandard) + registry.fill(HIST("hEventCountSpecific"), 7.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 (fillCounter && cfgEvSelkNoHighMultCollInPrevRof) + registry.fill(HIST("hEventCountSpecific"), 8.5); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) + return 0; + if (fillCounter && cfgEvSelOccupancy) + registry.fill(HIST("hEventCountSpecific"), 9.5); + + auto multNTracksPV = collision.multNTracksPV(); + if (cfgEvSelMultCorrelation) { + if (cfgFuncParas.cfgMultPVT0CCutEnabled && !cfgCentTableUnavailable) { + if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(centrality)) + return 0; + } + if (cfgFuncParas.cfgMultT0CCutEnabled && !cfgCentTableUnavailable) { + if (multTrk < cfgFuncParas.fMultT0CCutLow->Eval(centrality)) + return 0; + if (multTrk > cfgFuncParas.fMultT0CCutHigh->Eval(centrality)) + return 0; + } + if (cfgFuncParas.cfgMultGlobalPVCutEnabled) { + if (multTrk < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) + return 0; + if (multTrk > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) + return 0; + } + if (cfgFuncParas.cfgMultMultV0ACutEnabled) { + if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(multTrk)) + return 0; + if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(multTrk)) + return 0; + } + } + if (fillCounter && cfgEvSelMultCorrelation) + registry.fill(HIST("hEventCountSpecific"), 10.5); + + // V0A T0A 5 sigma cut + float sigma = 5.0; + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > sigma * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + if (fillCounter && cfgEvSelV0AT0ACut) + registry.fill(HIST("hEventCountSpecific"), 11.5); + + return 1; + } + + void findBiasedTracks(FilteredTracks const& tracks, std::vector& tracksSkipIndices, float posZ) + { + // Find the tracks that are alone in their pT bin + tracksSkipIndices.clear(); + static const std::vector& ptBins = axisPtTrigger.value; + static const size_t nPtBins = ptBins.size() - 1; + + std::vector numberOfTracksInBin(nPtBins, 0); + std::vector firstTrackIndex(nPtBins, -1); + + float triggerWeight = 1.0f; + + // Count tracks per bin and remember the first track id in each bin + for (const auto& track : tracks) { + if (!trackSelected(track)) + continue; + if (!getEfficiencyCorrection(triggerWeight, track.eta(), track.pt(), posZ)) + continue; + double pt = track.pt(); + auto binEdgeIt = std::upper_bound(ptBins.begin(), ptBins.end(), pt); + if (binEdgeIt == ptBins.begin() || binEdgeIt == ptBins.end()) + continue; // skip pt bins out of range + + size_t binIndex = static_cast(std::distance(ptBins.begin(), binEdgeIt) - 1); + + if (numberOfTracksInBin[binIndex] == 0) { + firstTrackIndex[binIndex] = track.globalIndex(); + } + ++numberOfTracksInBin[binIndex]; + } + + // Collect track ids for bins that have exactly one track + for (size_t i = 0; i < nPtBins; ++i) { + if (numberOfTracksInBin[i] == 1) { + tracksSkipIndices.push_back(firstTrackIndex[i]); + } + } + } + + void processSame(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks, aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) + return; + auto bc = collision.bc_as(); + float cent = -1.; + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) { + cent = getCentrality(collision); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent, true)) + return; + loadCorrection(bc.timestamp()); + if (!cfgCentTableUnavailable) { + getCentralityWeight(weightCent, cent); + registry.fill(HIST("Centrality"), cent); + registry.fill(HIST("CentralityWeighted"), cent, weightCent); + } + registry.fill(HIST("Nch"), tracks.size()); + registry.fill(HIST("zVtx"), collision.posZ()); + + if (cfgSelCollByNch && (tracks.size() < cfgCutMultMin || tracks.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + fillYield(collision, tracks); + + same->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + if (!cfgSoloPtTrack) { + fillCorrelations(tracks, tracks, collision.posZ(), SameEvent, getMagneticField(bc.timestamp()), cent, weightCent); + } else { + fillCorrelationsExcludeSoloTracks(tracks, tracks, collision.posZ(), getMagneticField(bc.timestamp()), cent, weightCent); + } + } + PROCESS_SWITCH(DiHadronCor, processSame, "Process same event", true); + + // the process for filling the mixed events + void processMixed(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::BCsWithTimestamps const&) + { + + auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(tracks, tracks); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -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; + if (!collision1.sel8() || !collision2.sel8()) + continue; + + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + float cent1 = -1; + float cent2 = -1; + if (!cfgCentTableUnavailable) { + cent1 = getCentrality(collision1); + cent2 = getCentrality(collision2); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), cent1, false)) + continue; + if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), cent2, false)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent1 < cfgCutCentMin || cent1 >= cfgCutCentMax)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent2 < cfgCutCentMin || cent2 >= cfgCutCentMax)) + continue; + + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + loadCorrection(bc.timestamp()); + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + getCentralityWeight(weightCent, cent1); + + fillCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, getMagneticField(bc.timestamp()), cent1, eventWeight * weightCent); + } + } + + PROCESS_SWITCH(DiHadronCor, processMixed, "Process mixed events", true); + + int getSpecies(int pdgCode) + { + switch (std::abs(pdgCode)) { + case PDG_t::kPiPlus: // pion + return 0; + case PDG_t::kKPlus: // Kaon + return 1; + case PDG_t::kProton: // proton + return 2; + default: // NOTE. The efficiency histogram is hardcoded to contain 4 species. Anything special will have the last slot. + return 3; + } + } + + void processMCEfficiency(FilteredMcCollisions::iterator const& mcCollision, soa::SmallGroups> const& collisions, FilteredMcParticles const& mcParticles, FilteredTracksWithMCLabels const& tracks) + { + registry.fill(HIST("MCEffeventcount"), 0.5); + if (cfgSelCollByNch && (mcParticles.size() < cfgCutMultMin || mcParticles.size() >= cfgCutMultMax)) { + return; + } + // Primaries + for (const auto& mcParticle : mcParticles) { + if (mcParticle.isPhysicalPrimary()) { + registry.fill(HIST("MCEffeventcount"), 1.5); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), 0., mcCollision.posZ()); + } + } + for (const auto& collision : collisions) { + auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + if (cfgVerbosity) { + LOGF(info, " Reconstructed collision at vtx-z = %f", collision.posZ()); + LOGF(info, " which has %d tracks", groupedTracks.size()); + } + + for (const auto& track : groupedTracks) { + if (track.has_mcParticle()) { + auto mcParticle = track.mcParticle(); + if (mcParticle.isPhysicalPrimary()) { + registry.fill(HIST("MCEffeventcount"), 2.5); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), 0., mcCollision.posZ()); + } + registry.fill(HIST("MCEffeventcount"), 3.5); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoAll, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), 0., mcCollision.posZ()); + } else { + // fake track + registry.fill(HIST("MCEffeventcount"), 4.5); + same->getTrackHistEfficiency()->Fill(CorrelationContainer::Fake, track.eta(), track.pt(), 0, 0., mcCollision.posZ()); + } + } + } + } + PROCESS_SWITCH(DiHadronCor, processMCEfficiency, "MC: Extract efficiencies", false); + + void processMCSame(FilteredMcCollisions::iterator const& mcCollision, FilteredMcParticles const& mcParticles, SmallGroupMcCollisions const& collisions) + { + if (cfgVerbosity) { + LOGF(info, "processMCSame. MC collision: %d, particles: %d, collisions: %d", mcCollision.globalIndex(), mcParticles.size(), collisions.size()); + } + + float cent = -1; + if (!cfgCentTableUnavailable) { + for (const auto& collision : collisions) { + cent = getCentrality(collision); + } + } + + if (cfgSelCollByNch && (mcParticles.size() < cfgCutMultMin || mcParticles.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + + registry.fill(HIST("MCTrue/MCeventcount"), SameEvent); // because its same event i put it in the 1 bin + if (!cfgCentTableUnavailable) + registry.fill(HIST("MCTrue/MCCentrality"), cent); + registry.fill(HIST("MCTrue/MCNch"), mcParticles.size()); + registry.fill(HIST("MCTrue/MCzVtx"), mcCollision.posZ()); + for (const auto& mcParticle : mcParticles) { + if (mcParticle.isPhysicalPrimary()) { + registry.fill(HIST("MCTrue/MCPhi"), mcParticle.phi()); + registry.fill(HIST("MCTrue/MCEta"), mcParticle.eta()); + registry.fill(HIST("MCTrue/MCpT"), mcParticle.pt()); + } + } + + same->fillEvent(mcParticles.size(), CorrelationContainer::kCFStepAll); + fillMCCorrelations(mcParticles, mcParticles, mcCollision.posZ(), SameEvent, 1.0f); + + if (collisions.size() == 0) { + return; + } + + registry.fill(HIST("MCTrue/MCeventcount"), 2.5); + same->fillEvent(mcParticles.size(), CorrelationContainer::kCFStepTrackedOnlyPrim); + fillMCCorrelations(mcParticles, mcParticles, mcCollision.posZ(), SameEvent, 1.0f); + } + PROCESS_SWITCH(DiHadronCor, processMCSame, "Process MC same event", false); + + void processMCMixed(FilteredMcCollisions const& mcCollisions, FilteredMcParticles const& mcParticles, SmallGroupMcCollisions const& collisions) + { + auto getTracksSize = [&mcParticles, this](FilteredMcCollisions::iterator const& mcCollision) { + auto associatedTracks = mcParticles.sliceByCached(o2::aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, o2::aod::mccollision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(mcParticles, mcParticles); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -1, mcCollisions, 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; + + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + auto groupedCollisions = collisions.sliceBy(collisionPerMCCollision, collision1.globalIndex()); + if (cfgVerbosity > 0) { + LOGF(info, "Found %d related collisions", groupedCollisions.size()); + } + float cent = -1; + if (!cfgCentTableUnavailable) { + for (const auto& collision : groupedCollisions) { + cent = getCentrality(collision); + } + } + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && groupedCollisions.size() != 0 && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) + continue; + + registry.fill(HIST("MCTrue/MCeventcount"), MixedEvent); // fill the mixed event in the 3 bin + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + + fillMCCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, eventWeight); + + if (groupedCollisions.size() == 0) { + continue; + } + + registry.fill(HIST("MCTrue/MCeventcount"), 4.5); + fillMCCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, eventWeight); + } + } + PROCESS_SWITCH(DiHadronCor, processMCMixed, "Process MC mixed events", false); + + void processOntheflySame(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles) + { + if (cfgVerbosity) { + LOGF(info, "processOntheflySame. MC collision: %d, particles: %d", mcCollision.globalIndex(), mcParticles.size()); + } + + if (cfgSelCollByNch && (mcParticles.size() < cfgCutMultMin || mcParticles.size() >= cfgCutMultMax)) { + return; + } + + registry.fill(HIST("MCTrue/MCeventcount"), SameEvent); // because its same event i put it in the 1 bin + registry.fill(HIST("MCTrue/MCNch"), mcParticles.size()); + registry.fill(HIST("MCTrue/MCzVtx"), mcCollision.posZ()); + for (const auto& mcParticle : mcParticles) { + if (mcParticle.isPhysicalPrimary()) { + registry.fill(HIST("MCTrue/MCPhi"), mcParticle.phi()); + registry.fill(HIST("MCTrue/MCEta"), mcParticle.eta()); + registry.fill(HIST("MCTrue/MCpT"), mcParticle.pt()); + } + } + + same->fillEvent(mcParticles.size(), CorrelationContainer::kCFStepAll); + fillMCCorrelations(mcParticles, mcParticles, mcCollision.posZ(), SameEvent, 1.0f); + + same->fillEvent(mcParticles.size(), CorrelationContainer::kCFStepTrackedOnlyPrim); + fillMCCorrelations(mcParticles, mcParticles, mcCollision.posZ(), SameEvent, 1.0f); + } + PROCESS_SWITCH(DiHadronCor, processOntheflySame, "Process on-the-fly same event", false); + + void processOntheflyMixed(aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + auto getTracksSize = [&mcParticles, this](aod::McCollisions::iterator const& mcCollision) { + auto associatedTracks = mcParticles.sliceByCached(o2::aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, o2::aod::mccollision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(mcParticles, mcParticles); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -1, mcCollisions, 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; + + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + registry.fill(HIST("MCTrue/MCeventcount"), MixedEvent); // fill the mixed event in the 3 bin + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + + fillMCCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, eventWeight); + + fillMCCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, eventWeight); + } + } + PROCESS_SWITCH(DiHadronCor, processOntheflyMixed, "Process on-the-fly mixed events", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/dptDptEfficiencyAndQc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/dptDptEfficiencyAndQc.cxx new file mode 100644 index 00000000000..37aabda0f26 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/dptDptEfficiencyAndQc.cxx @@ -0,0 +1,1487 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGCF/Core/AnalysisConfigurableCuts.h" +#include "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptDptFilter.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TableHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Expressions.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include + +#include "Math/MatrixFunctions.h" +#include "Math/SMatrix.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 kWhenPrefix[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", kWhenPrefix[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", kWhenPrefix[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", kWhenPrefix[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", kWhenPrefix[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", kWhenPrefix[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", kWhenPrefix[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", kWhenPrefix[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", kWhenPrefix[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", "cfgOverallMinP", overallminp, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxbins", zvtxbins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxmin", zvtxlow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mZVtxmax", zvtxup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTbins", ptbins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTmin", ptlow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPTmax", ptup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtabins", etabins, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtamin", etalow, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mEtamax", etaup, false); + getTaskOptionValue(initContext, "dpt-dpt-filter", "cfgBinning.mPhibins", phibins, false); + + /* configuring the involved species */ + std::vector cfgnames = {"cfgElectronPIDSelection", "cfgMuonPIDSelection", "cfgPionPIDSelection", "cfgKaonPIDSelection", "cfgProtonPIDSelection"}; + 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", "cfgCentSpec", 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/perRunExtraQc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunExtraQc.cxx similarity index 76% rename from PWGCF/TwoParticleCorrelations/Tasks/perRunExtraQc.cxx rename to PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunExtraQc.cxx index ce09b4fed46..c9304ec1ef9 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/perRunExtraQc.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunExtraQc.cxx @@ -8,21 +8,23 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// -// Minimal example to run this task: -// o2-analysis-centrality-table -b --configuration json://configuration.json | o2-analysis-timestamp -b --configuration json://configuration.json | o2-analysis-event-selection -b --configuration json://configuration.json | o2-analysis-multiplicity-table -b --configuration json://configuration.json | o2-analysis-lf-zdcsp -b --configuration json://configuration.json --aod-file @input_data.txt --aod-writer-json OutputDirector.json -#include -#include +/// \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 "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptDptFilter.h" +#include "Framework/ASoAHelpers.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" +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -31,21 +33,21 @@ using namespace o2::constants::physics; using BCsWithTimestamps = soa::Join; -namespace perrunextraqa +namespace perrunextraqc { std::unordered_map gRunMapPvsTpcIwP; TProfile3D* gCurrentRunPvsPtcIwP; -} // namespace perrunextraqa +} // namespace perrunextraqc -struct DptDptPerRunExtraQa { +struct DptDptPerRunExtraQc { int mRunNumber{-1}; AxisSpec qaPAxis{150, 0.1, 5.0}; - HistogramRegistry mHistos{"PerRunExtraQaHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry mHistos{"PerRunExtraQcHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; void initRunNumber(aod::BCsWithTimestamps::iterator const& bc) { - using namespace perrunextraqa; + using namespace perrunextraqc; if (mRunNumber == bc.runNumber()) { return; @@ -60,7 +62,7 @@ struct DptDptPerRunExtraQa { void init(InitContext&) { - using namespace perrunextraqa; + using namespace perrunextraqc; qaPAxis.makeLogarithmic(); } @@ -68,9 +70,9 @@ struct DptDptPerRunExtraQa { template void processTracks(PassedTracks const& tracks) { - using namespace perrunextraqa; + using namespace perrunextraqc; - for (auto& track : tracks) { + for (const auto& track : tracks) { gCurrentRunPvsPtcIwP->Fill(track.trackacceptedid(), track.p(), track.tpcInnerParam(), track.pt()); } } @@ -95,5 +97,5 @@ struct DptDptPerRunExtraQa { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunQc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunQc.cxx new file mode 100644 index 00000000000..286641391ea --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/dptDptPerRunQc.cxx @@ -0,0 +1,141 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGCF/DataModel/DptDptFiltered.h" +#include "PWGCF/TableProducer/dptDptFilter.h" + +#include "Common/CCDB/ctpRateFetcher.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsITSMFT/NoiseMap.h" // missing include in TimeDeadMap.h +#include "DataFormatsITSMFT/TimeDeadMap.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" + +#include +#include +#include +#include +#include +#include + +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 5b76d50d1a2..00000000000 --- a/PWGCF/TwoParticleCorrelations/Tasks/efficiencyAndQc.cxx +++ /dev/null @@ -1,946 +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 - //=================================================== - /* 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> 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; - - AxisSpec pidPAxis{150, 0.1, 5.0, "#it{p} (GeV/#it{c})"}; - 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"}; - 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 */ - fhPvsInnerP = ADDHISTOGRAM(TH2, DIRECTORYSTRING("%s/%s/%s", dirname, "Efficiency", "Reco"), "pVsInnerP", "#it{p} versus TPC inner wall #it{p}", kTH2F, {pidPAxis, pidPAxis}); - 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"}; - 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 */ - 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); - 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 */ - fhPvsInnerP->Fill(track.tpcInnerParam(), track.p()); - 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); - 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 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}", 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, {120, -6.0, 6.0, FORMATSTRING("n#sigma_{TOF}^{%s}", mainsptitles[isp].c_str())}}); - } - } - } - } - } - - template - void fillAllSpeciesPID(uint ix, TrackObject const& track, float mom) - { - if (track.sign() < 0) { - ix = 2 * ix + 1; - } else { - ix = 2 * ix; - } - for (uint when = 0; when < 2; ++when) { - fhTPCnSigmasVsP[when][ix]->Fill(mom, o2::aod::pidutils::tpcNSigma(track)); - fhTOFnSigmasVsP[when][ix]->Fill(mom, o2::aod::pidutils::tofNSigma(track)); - if (track.trackacceptedid() < 0) { - /* track not accepted */ - return; - } - } - fhIdTPCnSigmasVsP[track.trackacceptedid()][ix]->Fill(mom, o2::aod::pidutils::tpcNSigma(track)); - fhIdTOFnSigmasVsP[track.trackacceptedid()][ix]->Fill(mom, 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(mom, track.tpcSignal(), o2::aod::pidutils::tpcNSigma(track)); - fpIdTOFSignalVsPSigmas[track.trackacceptedid()]->Fill(mom, track.beta(), o2::aod::pidutils::tofNSigma(track)); - } - } - - template - void fillSpeciesPID(uint ix, TrackObject const& track, float mom) - { - if (track.sign() < 0) { - ix = 2 * ix + 1; - } else { - ix = 2 * ix; - } - for (uint when = 0; when < 2; ++when) { - fhTPCdEdxSignalDiffVsP[when][ix]->Fill(mom, o2::aod::pidutils::tpcExpSignalDiff(track)); - fhTOFSignalDiffVsP[when][ix]->Fill(mom, o2::aod::pidutils::tofExpSignalDiff(track)); - fhTPCTOFSigmaVsP[when][ix]->Fill(mom, 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 mom) - { - for (uint when = 0; when < 2; ++when) { - fhTPCdEdxSignalVsP[when]->Fill(mom, track.tpcSignal()); - fhTOFSignalVsP[when]->Fill(mom, track.beta()); - fhPvsTOFSqMass[when]->Fill(track.mass() * track.mass(), mom); - if (track.trackacceptedid() < 0) { - /* track not accepted */ - return; - } - } - fhIdTPCdEdxSignalVsP[track.trackacceptedid()]->Fill(mom, track.tpcSignal()); - fhIdTOFSignalVsP[track.trackacceptedid()]->Fill(mom, track.beta()); - } - - template - void processTrack(TrackObject const& track, float mom) - { - using namespace efficiencyandqatask; - - if constexpr (kind == kReco) { - fillPID(track, mom); - fillSpeciesPID(0, track, mom); - fillSpeciesPID(1, track, mom); - fillSpeciesPID(2, track, mom); - fillAllSpeciesPID(0, track, mom); - fillAllSpeciesPID(1, track, mom); - fillAllSpeciesPID(2, track, mom); - fillAllSpeciesPID(3, track, mom); - fillAllSpeciesPID(4, track, mom); - } - } -}; - -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"}; - Configurable useTPCInnerWallMomentum{"useinnerwallmomm", false, "Use the TPC inner wall momentum. Default: 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) { - float mom = track.p(); - if (useTPCInnerWallMomentum.value) { - if constexpr (!framework::has_type_v) { - mom = track.tpcInnerParam(); - } - } - qaDataCE[ixDCE]->processTrack(collision.posZ(), track); - if constexpr (dopid) { - pidDataCE[ixDCE]->processTrack(track, mom); - } - } - } - } - - 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 deleted file mode 100644 index 83bd0629020..00000000000 --- a/PWGCF/TwoParticleCorrelations/Tasks/identifiedbf.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. - -#include -#include -#include -#include -#include -#include -#include -#include -#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 "DataFormatsParameters/GRPObject.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "PWGCF/Core/AnalysisConfigurableCuts.h" -#include "PWGCF/Core/PairCuts.h" -#include "PWGCF/TwoParticleCorrelations/DataModel/IdentifiedBfFiltered.h" -#include "PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::soa; -using namespace o2::framework::expressions; - -#define IDENTIFIEDBFLOGCOLLISIONS debug -#define IDENTIFIEDBFLOGTRACKS debug - -namespace correlationstask -{ -using namespace o2::analysis::identifiedbffilter; -float phibinshift = 0.5; -float etabinwidth = (etaup - etalow) / static_cast(etabins); -float phibinwidth = (phiup - philow) / static_cast(phibins); -int deltaetabins = etabins * 2 - 1; -float deltaetalow = etalow - etaup, deltaetaup = etaup - etalow; -float deltaetabinwidth = (deltaetaup - deltaetalow) / static_cast(deltaetabins); -int deltaphibins = phibins; -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; - -PairCuts fPairCuts; // pair suppression engine -bool fUseConversionCuts = false; // suppress resonances and conversions -bool fUseTwoTrackCut = false; // suppress too close tracks - -std::vector tname = {"e+", "e-", "pi+", "pi-", "K+", "K-", "p+", "p-"}; ///< the track names -} // namespace correlationstask - -// Task for building correlations -struct IdentifiedBfCorrelationsTask { - - /* the data collecting engine */ - template - struct DataCollectingEngine { - int nspecies = static_cast(analysis::identifiedbffilter::kIdBfNoOfSpecies); /* Doing All Species */ - size_t nch = nspecies * 2; - - //============================================================================================ - // The IdentifiedBfCorrelationsAnalysisTask 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}}; //! 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> chargePairsNames = {{"OO", "OT"}, {"TO", "TT"}}; - 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() - { - return ccdbstored; - } - - /// \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) - { - using namespace correlationstask; - using namespace o2::analysis::identifiedbffilter; - if (!(phi < phiup)) { - return phi - constants::math::TwoPI; - } else { - return phi; - } - } - - /// \brief Returns the zero based bin index of the eta phi passed track - /// \param t the intended track - /// \return the zero based bin index - /// - /// According to the bining structure, to the track eta will correspond - /// a zero based bin index and similarly for the track phi - /// The returned index is the composition of both considering eta as - /// the first index component - /// WARNING: for performance reasons no checks are done about the consistency - /// of track's eta and phin with the corresponding ranges so, it is suppossed - /// 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) - { - 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()); - int phiix = static_cast((phi - philow) / phibinwidth); - return etaix * phibins + phiix; - } - - /// \brief Returns the TH2 global index 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 - /// - /// 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 - 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); - /* 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); - /* consider a potential phi origin shift */ - phi = GetShiftedPhi(t2.phi()); - int phiix_2 = 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; - } - - return fhN2_vsDEtaDPhi[0][0]->GetBin(deltaeta_ix + 1, deltaphi_ix + 1); - } - - void storeTrackCorrections(std::vector corrs) - { - 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) { - 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); - } - } - } - LOGF(info, "Average NUA&NUE correction for track id %d: %f", i, avg / nbins); - } - } - ccdbstored = true; - } - - void storePtAverages(std::vector ptavgs) - { - 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]; - } - ccdbstored = true; - } - - 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())); - } - index++; - } - return corr; - } - - 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())); - index++; - } - } - return ptavg; - } - - /// \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 - template - void processSingles(TrackListObject const& passedtracks, std::vector* corrs, float zvtx) - { - int index = 0; - for (auto& track : passedtracks) { - float corr = (*corrs)[index]; - fhN1_vsPt[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); - } 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); - } - index++; - } - } - - /// \brief fills the singles histograms in pair 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 - /// \param cmul centrality - multiplicity for the collision being analyzed - template - void processTracks(TrackListObject const& passedtracks, std::vector* corrs, float cmul) - { - LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Processing %d tracks in a collision with cent/mult %f ", passedtracks.size(), cmul); - - /* process magnitudes */ - std::vector n1(nch, 0.0); ///< weighted number of single tracks for current collision - std::vector sum1Pt(nch, 0.0); ///< accumulated sum of weighted single track \f$p_T\f$ for current collision - 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) { - 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); - 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]); - } - } - - /// \brief fills the pair histograms in pair execution mode - /// \param trks1 filtered table with the tracks associated to the first track in the pair - /// \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 - 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; - - /* process pair magnitudes */ - std::vector> n2(nch, std::vector(nch, 0.0)); ///< weighted number of track 1 track 2 pairs for current collision - std::vector> n2sup(nch, std::vector(nch, 0.0)); ///< weighted number of track 1 track 2 suppressed pairs for current collision - std::vector> sum2PtPt(nch, std::vector(nch, 0.0)); ///< accumulated sum of weighted track 1 track 2 \f${p_T}_1 {p_T}_2\f$ for current collision - std::vector> sum2DptDpt(nch, std::vector(nch, 0.0)); ///< accumulated sum of weighted number of track 1 tracks times weighted track 2 \f$p_T\f$ for current collision - std::vector> n2nw(nch, std::vector(nch, 0.0)); ///< not weighted number of track1 track 2 pairs for current collision - 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; - - for (auto& track1 : trks1) { - double ptavg_1 = (*ptavgs1)[index1]; - double corr1 = (*corrs1)[index1]; - int index2 = 0; - for (auto& track2 : trks2) { - /* checking the same track id condition */ - if (track1 == track2) { - /* exclude autocorrelations */ - continue; - } - - if constexpr (doptorder) { - if (track2.pt() >= track1.pt()) { - continue; - } - } - /* process pair magnitudes */ - double ptavg_2 = (*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); - - /* get the global bin for filling the differential histograms */ - 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; - } - 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); - n2sup[track1.trackacceptedid()][track2.trackacceptedid()] += corr; - } else { - /* count the pair */ - n2[track1.trackacceptedid()][track2.trackacceptedid()] += corr; - sum2PtPt[track1.trackacceptedid()][track2.trackacceptedid()] += track1.pt() * track2.pt() * corr; - sum2DptDpt[track1.trackacceptedid()][track2.trackacceptedid()] += dptdptw; - n2nw[track1.trackacceptedid()][track2.trackacceptedid()] += 1; - 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); - } - 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]); - /* 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]); - } - } - } - - template - void processCollision(TrackOneListObject const& Tracks1, TrackTwoListObject const& Tracks2, float zvtx, float centmult, int bfield) - { - using namespace correlationstask; - std::vector* corrs1; - std::vector* corrs2; - corrs1 = getTrackCorrections(Tracks1, zvtx); - if constexpr (mixed) { - corrs2 = getTrackCorrections(Tracks2, zvtx); - } - - if (!processpairs) { - /* process single tracks */ - fhVertexZA->Fill(zvtx); - processSingles(Tracks1, corrs1, zvtx); - if constexpr (mixed) { - processSingles(Tracks2, corrs2, zvtx); - } - } else { - /* process track magnitudes */ - std::vector* ptavgs1; - std::vector* ptavgs2; - ptavgs1 = getPtAvg(Tracks1); - if constexpr (mixed) { - ptavgs2 = getPtAvg(Tracks2); - } - - /* TODO: the centrality should be chosen non detector dependent */ - processTracks(Tracks1, corrs1, centmult); - if constexpr (mixed) { - processTracks(Tracks2, corrs2, centmult); - } - /* process pair magnitudes */ - if constexpr (mixed) { - if (ptorder) { - processTrackPairs(Tracks1, Tracks2, corrs1, corrs2, ptavgs1, ptavgs2, centmult, bfield); - } else { - processTrackPairs(Tracks1, Tracks2, corrs1, corrs2, ptavgs1, ptavgs2, centmult, bfield); - } - } else { - if (ptorder) { - processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); - } else { - processTrackPairs(Tracks1, Tracks1, corrs1, corrs1, ptavgs1, ptavgs1, centmult, bfield); - } - } - - delete ptavgs1; - if constexpr (mixed) { - delete ptavgs2; - } - } - delete corrs1; - if constexpr (mixed) { - delete corrs2; - } - } - - void init(TList* fOutputList) - { - using namespace correlationstask; - using namespace o2::analysis::identifiedbffilter; - - /* create the histograms */ - Bool_t oldstatus = TH1::AddDirectoryStatus(); - TH1::AddDirectory(kFALSE); - - if (!processpairs) { - fhVertexZA = new TH1F("VertexZA", "Vertex Z; z_{vtx}", zvtxbins, zvtxlow, zvtxup); - 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); - /* 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); - } else { - TH1::SetDefaultSumw2(false); - fhN1_vsZEtaPhiPt[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(), - tname[i].c_str(), - tname[i].c_str()) - .Data(), - zvtxbins, - zvtxlow, - zvtxup, - etabins * phibins, - 0.0, - static_cast(etabins * phibins), - ptbins, - ptlow, - ptup); - fhSum1Pt_vsZEtaPhiPt[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)", - tname[i].c_str(), - 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); - } - /* we return it back to previuos state */ - TH1::SetDefaultSumw2(defSumw2); - - /* 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); - } else { - fhN1_vsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); - fhN1_vsZEtaPhiPt[i]->Sumw2(false); - fhSum1Pt_vsZEtaPhiPt[i]->SetBit(TH1::kIsNotW); - fhSum1Pt_vsZEtaPhiPt[i]->Sumw2(false); - } - fhNuaNue_vsZEtaPhiPt[i] = nullptr; - fhPtAvg_vsEtaPhi[i] = nullptr; - - fOutputList->Add(fhN1_vsPt[i]); - if constexpr (smallsingles) { - fOutputList->Add(fhN1_vsEtaPhi[i]); - fOutputList->Add(fhSum1Pt_vsEtaPhi[i]); - } else { - fOutputList->Add(fhN1_vsZEtaPhiPt[i]); - fOutputList->Add(fhSum1Pt_vsZEtaPhiPt[i]); - } - } - } 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]); - } - for (uint i = 0; i < nch; ++i) { - for (uint j = 0; j < nch; ++j) { - /* histograms for each track pair combination */ - /* we don't want the Sumw2 structure being created here */ - bool defSumw2 = TH1::GetDefaultSumw2(); - 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), - 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), - 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); - - 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); - - /* 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]); - } - } - } - TH1::AddDirectory(oldstatus); - } - }; // DataCollectingEngine - - Service ccdb; - - /* the data memebers for this task */ - /* the centrality / multiplicity limits for collecting data in this task instance */ - int ncmranges = 0; - float* fCentMultMin = nullptr; - float* fCentMultMax = nullptr; - - /* the data collecting engine instances */ - DataCollectingEngine** dataCE; - DataCollectingEngine** dataCE_small; - DataCollectingEngine** dataCEME; - - /* the input file structure from CCDB */ - TList* ccdblst = nullptr; - 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"}; - /* 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 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 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 cfgPtOrder{"ptorder", 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"}; - } cfginputfile; - - OutputObj fOutput{"IdentifiedBfCorrelationsData", OutputObjHandlingPolicy::AnalysisObject, OutputObjSourceType::OutputObjSource}; - - void init(InitContext const&) - { - using namespace correlationstask; - using namespace o2::analysis::identifiedbffilter; - - /* update with the configurable values */ - 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; - phibins = cfgBinning->mPhibins; - philow = 0.0f; - phiup = constants::math::TwoPI; - phibinshift = cfgBinning->mPhibinshift; - processpairs = cfgProcessPairs.value; - processmixedevents = cfgProcessME.value; - ptorder = cfgPtOrder.value; - loadfromccdb = cfginputfile.cfgCCDBPathName->length() > 0; - /* update the potential binning change */ - etabinwidth = (etaup - etalow) / static_cast(etabins); - phibinwidth = (phiup - philow) / static_cast(phibins); - - /* the differential bining */ - deltaetabins = etabins * 2 - 1; - deltaetalow = etalow - etaup, deltaetaup = etaup - etalow; - deltaetabinwidth = (deltaetaup - deltaetalow) / static_cast(deltaetabins); - deltaphibins = phibins; - deltaphibinwidth = constants::math::TwoPI / deltaphibins; - deltaphilow = 0.0 - deltaphibinwidth / 2.0; - deltaphiup = constants::math::TwoPI - deltaphibinwidth / 2.0; - - /* create the output directory which will own the task output */ - TList* fGlobalOutputList = new TList(); - fGlobalOutputList->SetOwner(true); - fOutput.setObject(fGlobalOutputList); - - /* incorporate configuration parameters to the output */ - fGlobalOutputList->Add(new TParameter("NoBinsPt", ptbins, 'f')); - fGlobalOutputList->Add(new TParameter("NoBinsEta", etabins, 'f')); - fGlobalOutputList->Add(new TParameter("NoBinsPhi", phibins, 'f')); - fGlobalOutputList->Add(new TParameter("NoBinsVertexZ", zvtxbins, 'f')); - fGlobalOutputList->Add(new TParameter("MinVertexZ", zvtxlow, 'f')); - fGlobalOutputList->Add(new TParameter("MaxVertexZ", zvtxup, 'f')); - fGlobalOutputList->Add(new TParameter("MinPt", ptlow, 'f')); - fGlobalOutputList->Add(new TParameter("MaxPt", ptup, 'f')); - fGlobalOutputList->Add(new TParameter("MinEta", etalow, 'f')); - fGlobalOutputList->Add(new TParameter("MaxEta", etaup, 'f')); - fGlobalOutputList->Add(new TParameter("MinPhi", philow, 'f')); - fGlobalOutputList->Add(new TParameter("MaxPhi", phiup, 'f')); - fGlobalOutputList->Add(new TParameter("PhiBinShift", phibinshift, 'f')); - fGlobalOutputList->Add(new TParameter("DifferentialOutput", true, 'f')); - fGlobalOutputList->Add(new TParameter("SmallDCE", cfgSmallDCE.value, 'f')); - - /* after the parameters dump the proper phi limits are set according to the phi shift */ - phiup = phiup - phibinwidth * phibinshift; - philow = philow - phibinwidth * phibinshift; - - /* create the data collecting engine instances according to the configured centrality/multiplicity ranges */ - { - TObjArray* tokens = TString(cfgCentSpec.value.c_str()).Tokenize(","); - ncmranges = tokens->GetEntries(); - fCentMultMin = new float[ncmranges]; - fCentMultMax = new float[ncmranges]; - dataCE = new DataCollectingEngine*[ncmranges]; - if (cfgSmallDCE) { - dataCE_small = new DataCollectingEngine*[ncmranges]; - } else { - dataCE = new DataCollectingEngine*[ncmranges]; - } - if (processmixedevents) { - dataCEME = new DataCollectingEngine*[ncmranges]; - } - - for (int i = 0; i < ncmranges; ++i) { - auto initializeCEInstance = [&fGlobalOutputList](auto dce, auto name) { - /* 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); - fGlobalOutputList->Add(fOutputList); - }; - auto builSmallDCEInstance = [&initializeCEInstance](auto rg, bool me = false) { - DataCollectingEngine* dce = new DataCollectingEngine(); - initializeCEInstance(dce, TString::Format("IdentifiedBfCorrelationsData%s-%s", me ? "ME" : "", rg)); - return dce; - }; - auto buildCEInstance = [&initializeCEInstance](auto rg, bool me = false) { - DataCollectingEngine* dce = new DataCollectingEngine(); - initializeCEInstance(dce, TString::Format("IdentifiedBfCorrelationsData%s-%s", me ? "ME" : "", rg)); - return dce; - }; - float cmmin = 0.0f; - float cmmax = 0.0f; - sscanf(tokens->At(i)->GetName(), "%f-%f", &cmmin, &cmmax); - fCentMultMin[i] = cmmin; - fCentMultMax[i] = cmmax; - if (cfgSmallDCE.value) { - if (processpairs) { - LOGF(fatal, "Processing pairs cannot be used with the small DCE, please configure properly!!"); - } - dataCE_small[i] = builSmallDCEInstance(tokens->At(i)->GetName()); - } else { - dataCE[i] = buildCEInstance(tokens->At(i)->GetName()); - } - if (processmixedevents) { - /* consistency check */ - if (cfgSmallDCE.value) { - LOGF(fatal, "Mixed events cannot be used with the small DCE, please configure properly!!"); - } - dataCEME[i] = buildCEInstance(tokens->At(i)->GetName(), true); - } - } - delete tokens; - for (int i = 0; i < ncmranges; ++i) { - LOGF(info, " centrality/multipliicty range: %d, low limit: %f, up limit: %f", i, fCentMultMin[i], fCentMultMax[i]); - } - } - /* two-track cut and conversion suppression */ - fPairCuts.SetHistogramRegistry(nullptr); // not histogram registry for the time being, incompatible with TList when it is empty - if (processpairs && ((cfgPairCut->get("Photon") > 0) || (cfgPairCut->get("K0") > 0) || (cfgPairCut->get("Lambda") > 0) || (cfgPairCut->get("Phi") > 0) || (cfgPairCut->get("Rho") > 0))) { - fPairCuts.SetPairCut(PairCuts::Photon, cfgPairCut->get("Photon")); - fPairCuts.SetPairCut(PairCuts::K0, cfgPairCut->get("K0")); - fPairCuts.SetPairCut(PairCuts::Lambda, cfgPairCut->get("Lambda")); - fPairCuts.SetPairCut(PairCuts::Phi, cfgPairCut->get("Phi")); - fPairCuts.SetPairCut(PairCuts::Rho, cfgPairCut->get("Rho")); - fUseConversionCuts = true; - } - if (processpairs && (cfgTwoTrackCut > 0)) { - fPairCuts.SetTwoTrackCuts(cfgTwoTrackCut, cfgTwoTrackCutMinRadius); - fUseTwoTrackCut = true; - } - - /* initialize access to the CCDB */ - ccdb->setURL(cfginputfile.cfgCCDBUrl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - } - - /// \brief Get the data collecting engine index corresponding to the passed collision - template - int getDCEindex(FilteredCollision collision) - { - int ixDCE = -1; - float cm = collision.centmult(); - for (int i = 0; i < ncmranges; ++i) { - if (cm < fCentMultMax[i]) { - ixDCE = i; - break; - } - } - if (!(ixDCE < 0)) { - if (cm < fCentMultMin[ixDCE]) { - ixDCE = -1; - } - } - return ixDCE; - } - - 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; - } - - int getMagneticField(uint64_t timestamp) - { - // TODO done only once (and not per run). Will be replaced by CCDBConfigurable - static o2::parameters::GRPObject* grpo = nullptr; - if (grpo == nullptr) { - grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", 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(); - } - - template - void processSame(FilterdCollision const& collision, FilteredTracks const& tracks, uint64_t timestamp = 0) - { - using namespace correlationstask; - if (ccdblst == nullptr) { - if (loadfromccdb) { - ccdblst = getCCDBInput(cfginputfile.cfgCCDBPathName->c_str(), cfginputfile.cfgCCDBDate->c_str()); - } - } - - /* locate the data collecting engine for the collision centrality/multiplicity */ - int ixDCE = getDCEindex(collision); - if (!(ixDCE < 0)) { - if (ccdblst != nullptr && !(dataCE[ixDCE]->isCCDBstored())) { - if constexpr (gen) { - std::vector ptavgs{tname.size(), nullptr}; - for (uint isp = 0; isp < tname.size(); ++isp) { - ptavgs[isp] = reinterpret_cast(ccdblst->FindObject( - TString::Format("trueptavgetaphi_%02d-%02d_%s", - static_cast(fCentMultMin[ixDCE]), - static_cast(fCentMultMax[ixDCE]), - tname[isp].c_str()) - .Data())); - } - if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->storePtAverages(ptavgs); - } else { - dataCE[ixDCE]->storePtAverages(ptavgs); - } - } else { - std::vector corrs{tname.size(), nullptr}; - for (uint isp = 0; isp < tname.size(); ++isp) { - corrs[isp] = reinterpret_cast(ccdblst->FindObject( - TString::Format("correction_%02d-%02d_%s", - static_cast(fCentMultMin[ixDCE]), - static_cast(fCentMultMax[ixDCE]), - tname[isp].c_str()) - .Data())); - } - if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->storeTrackCorrections(corrs); - } else { - dataCE[ixDCE]->storeTrackCorrections(corrs); - } - - std::vector ptavgs{tname.size(), nullptr}; - for (uint isp = 0; isp < tname.size(); ++isp) { - ptavgs[isp] = reinterpret_cast(ccdblst->FindObject( - TString::Format("ptavgetaphi_%02d-%02d_%s", - static_cast(fCentMultMin[ixDCE]), - static_cast(fCentMultMax[ixDCE]), - tname[isp].c_str()) - .Data())); - } - if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->storePtAverages(ptavgs); - } else { - dataCE[ixDCE]->storePtAverages(ptavgs); - } - } - } - - std::string generated = ""; - if constexpr (gen) { - generated = "generated "; - } - - LOGF(IDENTIFIEDBFLOGCOLLISIONS, - "Accepted BC id %d %scollision with cent/mult %f and %d total tracks. Assigned DCE: %d", - collision.bcId(), - generated.c_str(), - collision.centmult(), - tracks.size(), - ixDCE); - int bfield = 0; - if constexpr (!gen) { - bfield = (fUseConversionCuts || fUseTwoTrackCut) ? getMagneticField(timestamp) : 0; - } - if (cfgSmallDCE.value) { - dataCE_small[ixDCE]->processCollision(tracks, tracks, collision.posZ(), collision.centmult(), bfield); - } else { - dataCE[ixDCE]->processCollision(tracks, tracks, collision.posZ(), collision.centmult(), bfield); - } - } - } - - template - void processMixed(FilterdCollision const& collision, FilteredTracks1 const& tracks1, FilteredTracks2 const& tracks2, uint64_t timestamp = 0) - { - using namespace correlationstask; - - if (ccdblst == nullptr) { - if (loadfromccdb) { - ccdblst = getCCDBInput(cfginputfile.cfgCCDBPathName->c_str(), cfginputfile.cfgCCDBDate->c_str()); - } - } - - /* locate the data collecting engine for the collision centrality/multiplicity */ - int ixDCE = getDCEindex(collision); - if (!(ixDCE < 0)) { - if (ccdblst != nullptr && !(dataCEME[ixDCE]->isCCDBstored())) { - if constexpr (gen) { - std::vector ptavgs{tname.size(), nullptr}; - for (uint isp = 0; isp < tname.size(); ++isp) { - ptavgs[isp] = reinterpret_cast(ccdblst->FindObject( - TString::Format("trueptavgetaphi_%02d-%02d_%s", - static_cast(fCentMultMin[ixDCE]), - static_cast(fCentMultMax[ixDCE]), - tname[isp].c_str()) - .Data())); - } - dataCEME[ixDCE]->storePtAverages(ptavgs); - } else { - std::vector corrs{tname.size(), nullptr}; - for (uint isp = 0; isp < tname.size(); ++isp) { - corrs[isp] = reinterpret_cast(ccdblst->FindObject( - TString::Format("correction_%02d-%02d_%s", - static_cast(fCentMultMin[ixDCE]), - static_cast(fCentMultMax[ixDCE]), - tname[isp].c_str()) - .Data())); - } - dataCEME[ixDCE]->storeTrackCorrections(corrs); - - std::vector ptavgs{tname.size(), nullptr}; - for (uint isp = 0; isp < tname.size(); ++isp) { - ptavgs[isp] = reinterpret_cast(ccdblst->FindObject( - TString::Format("ptavgetaphi_%02d-%02d_%s", - static_cast(fCentMultMin[ixDCE]), - static_cast(fCentMultMax[ixDCE]), - tname[isp].c_str()) - .Data())); - } - dataCEME[ixDCE]->storePtAverages(ptavgs); - } - } - - std::string generated = ""; - if constexpr (gen) { - generated = "generated "; - } - - LOGF(IDENTIFIEDBFLOGCOLLISIONS, - "Accepted BC id %d mixed %scollision with cent/mult %f and %d-%d total mixed tracks. " - "Assigned DCE: %d", - collision.bcId(), - generated.c_str(), - collision.centmult(), - tracks1.size(), - tracks2.size(), - ixDCE); - int bfield = 0; - if constexpr (!gen) { - bfield = (fUseConversionCuts || fUseTwoTrackCut) ? getMagneticField(timestamp) : 0; - } - dataCEME[ixDCE]->processCollision(tracks1, tracks2, collision.posZ(), collision.centmult(), bfield); - } - } - - 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) - { - processSame(collision, tracks, collision.bc_as().timestamp()); - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processRecLevel, "Process reco level correlations", false); - - void processRecLevelCheck(aod::Collisions const& collisions, aod::Tracks& tracks) - { - int nAssignedTracks = 0; - int nNotAssignedTracks = 0; - int64_t firstNotAssignedIndex = -1; - int64_t lastNotAssignedIndex = -1; - - for (auto track : tracks) { - if (track.has_collision()) { - nAssignedTracks++; - } else { - nNotAssignedTracks++; - if (firstNotAssignedIndex < 0) { - firstNotAssignedIndex = track.globalIndex(); - } else { - lastNotAssignedIndex = track.globalIndex(); - } - } - } - LOGF(info, "Received %d collisions and %d tracks.", collisions.size(), tracks.size()); - LOGF(info, " Assigned tracks %d", nAssignedTracks); - LOGF(info, " Not assigned tracks %d", nNotAssignedTracks); - 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); - - void processGenLevelCheck(aod::McCollisions const& mccollisions, aod::McParticles& particles) - { - int nAssignedParticles = 0; - int nNotAssignedParticles = 0; - int64_t firstNotAssignedIndex = -1; - int64_t lastNotAssignedIndex = -1; - - for (auto particle : particles) { - if (particle.has_mcCollision()) { - nAssignedParticles++; - } else { - nNotAssignedParticles++; - if (firstNotAssignedIndex < 0) { - firstNotAssignedIndex = particle.globalIndex(); - } else { - lastNotAssignedIndex = particle.globalIndex(); - } - } - } - LOGF(info, "Received %d generated collisions and %d particles.", mccollisions.size(), particles.size()); - LOGF(info, " Assigned tracks %d", nAssignedParticles); - LOGF(info, " Not assigned tracks %d", nNotAssignedParticles); - 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); - - void processRecLevelNotStored( - soa::Filtered>::iterator const& collision, - aod::BCsWithTimestamps const&, - soa::Filtered>& tracks) - { - processSame(collision, tracks, collision.bc_as().timestamp()); - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, - processRecLevelNotStored, - "Process reco level correlations for not stored derived data", - true); - - void processGenLevel( - soa::Filtered::iterator const& collision, - soa::Filtered>& tracks) - { - processSame(collision, tracks); - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processGenLevel, "Process generator level correlations", false); - - void processGenLevelNotStored( - soa::Filtered>::iterator const& collision, - soa::Filtered>& particles) - { - processSame(collision, particles); - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, - 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}; - std::vector multBinsEdges{VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0, 100.1f}; - SliceCache cache; - 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) - { - 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) { - 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"); - logcomb++; - } - if (!collision1.collisionaccepted() || !collision2.collisionaccepted()) { - LOGF(error, "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"); - } - processMixed(collision1, tracks1, tracks2, collision1.bc_as().timestamp()); - } - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processRecLevelMixed, "Process reco level mixed events correlations", false); - - void processRecLevelMixedNotStored( - soa::Filtered>& collisions, - aod::BCsWithTimestamps const&, - soa::Filtered>& 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) { - 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"); - logcomb++; - } - if (!collision1.collisionaccepted() || !collision2.collisionaccepted()) { - LOGF(error, - "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"); - } - processMixed(collision1, - tracks1, - tracks2, - collision1.bc_as().timestamp()); - } - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, - 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) - { - 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) { - 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"); - } - if (!collision1.collisionaccepted() || !collision2.collisionaccepted()) { - LOGF(error, "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"); - } - processMixed(collision1, tracks1, tracks2); - } - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, processGenLevelMixed, "Process generator level mixed events correlations", false); - - void processGenLevelMixedNotStored( - soa::Filtered>& collisions, - soa::Filtered>& 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) { - 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"); - } - if (!collision1.collisionaccepted() || !collision2.collisionaccepted()) { - LOGF(error, - "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"); - } - processMixed(collision1, tracks1, tracks2); - } - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, - 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) - { - LOGF(IDENTIFIEDBFLOGCOLLISIONS, "Got %d new collisions", colls.size()); - fOutput->Clear(); - } - PROCESS_SWITCH(IdentifiedBfCorrelationsTask, 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}}})}; - return workflow; -} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/identifiedbfqa.cxx b/PWGCF/TwoParticleCorrelations/Tasks/identifiedbfqa.cxx deleted file mode 100644 index a52ff377832..00000000000 --- a/PWGCF/TwoParticleCorrelations/Tasks/identifiedbfqa.cxx +++ /dev/null @@ -1,152 +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 "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "PWGCF/TwoParticleCorrelations/DataModel/IdentifiedBfFiltered.h" -#include "PWGCF/TwoParticleCorrelations/TableProducer/identifiedBfFilter.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::soa; -using namespace o2::framework::expressions; - -#define IDENTIFIEDBFFILTERLOGCOLLISIONS debug -// #define IDENTIFIEDBFFILTERLOGTRACKS debug - -namespace o2::analysis::identifiedbffilterqa -{ -typedef enum { kRECO = 0, - kGEN } innerdatatype; -static constexpr std::string_view dirname[] = {"reconstructed/", "generated/"}; -} // namespace o2::analysis::identifiedbffilterqa - -// Checking the filtered tables -struct IdentifiedBfFilterQA { - Configurable cfgDataType{"datatype", "data", "Data type: data, MC, FastMC, OnTheFlyMC. Default data"}; - HistogramRegistry histos{"IdentifiedBfFilterQA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - o2::analysis::identifiedbffilter::DataType datatype; - - template - void createHistograms() - { - - using namespace o2::analysis::identifiedbffilterqa; - - 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&) - { - using namespace o2::analysis::identifiedbffilter; - using namespace o2::analysis::identifiedbffilterqa; - - switch (getDataType(cfgDataType)) { - case kData: - createHistograms(); - break; - case kMC: - createHistograms(); - createHistograms(); - break; - case kFastMC: - case kOnTheFly: - createHistograms(); - break; - default: - LOGF(fatal, "Data type %s not supported", (std::string)cfgDataType); - break; - } - } - - template - void processQATask(FilteredCollision const& collision, - FilteredTracks const& tracks) - { - using namespace o2::analysis::identifiedbffilterqa; - - if (collision.collisionaccepted() != uint8_t(true)) { - histos.fill(HIST(dirname[dir]) + HIST("SelectedEvents"), 0.5); - } else { - 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) { - if (!(track.trackacceptedid() < 0) && !(track.trackacceptedid() < 2)) { - LOGF(fatal, "Task not prepared for identified particles"); - } - if (track.trackacceptedid() != 0 && track.trackacceptedid() != 1) { - ntracks_none++; - } - if (track.trackacceptedid() == 0) { - ntracks_one++; - } - if (track.trackacceptedid() == 1) { - ntracks_two++; - } - } - 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); - } 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); - } - } - - Filter onlyacceptedcollisions = (aod::identifiedbffilter::collisionaccepted == uint8_t(true)); - Filter onlyacceptedtracks = (int8_t(0) <= aod::identifiedbffilter::trackacceptedid); - - void processGeneratorLevel(soa::Filtered::iterator const& collision, soa::Filtered const& tracks) - { - using namespace o2::analysis::identifiedbffilterqa; - LOGF(IDENTIFIEDBFFILTERLOGCOLLISIONS, "New filtered generated collision with BC id %d and with %d accepted tracks", collision.bcId(), tracks.size()); - processQATask(collision, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterQA, processGeneratorLevel, "Process generator level filter task QA", true); - - void processDetectorLevel(soa::Filtered::iterator const& collision, soa::Filtered const& tracks) - { - using namespace o2::analysis::identifiedbffilterqa; - LOGF(IDENTIFIEDBFFILTERLOGCOLLISIONS, "New filtered collision with BC id %d and with %d accepted tracks", collision.bcId(), tracks.size()); - processQATask(collision, tracks); - } - PROCESS_SWITCH(IdentifiedBfFilterQA, processDetectorLevel, "Process detector level filter task QA", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; - return workflow; -} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx index e0d331ba140..0d0d75c58bb 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx @@ -9,70 +9,189 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file lambdaCorrelationAnalysis.cxx +/// \file lambdaR2Correlation.cxx /// \brief R2 correlation of Lambda baryons. /// \author Yash Patley -#include -#include +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisTask.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.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 +#include +#include 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_COLUMN(Mult, mult, float); +} // namespace lambdacollision DECLARE_SOA_TABLE(LambdaCollisions, "AOD", "LAMBDACOLS", o2::soa::Index<>, lambdacollision::Cent, + lambdacollision::Mult, 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, + lambdacollision::Mult, + 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(Rap, rap, 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(MassWindow, masswindow, int8_t); +DECLARE_SOA_COLUMN(PrPx, prPx, float); +DECLARE_SOA_COLUMN(PrPy, prPy, float); +DECLARE_SOA_COLUMN(PrPz, prPz, float); +DECLARE_SOA_COLUMN(PosTrackId, posTrackId, int64_t); +DECLARE_SOA_COLUMN(NegTrackId, negTrackId, int64_t); +DECLARE_SOA_COLUMN(CosPA, cosPA, float); +DECLARE_SOA_COLUMN(DcaDau, dcaDau, float); +DECLARE_SOA_COLUMN(V0Type, v0Type, int8_t); +DECLARE_SOA_COLUMN(V0PrmScd, v0PrmScd, int8_t); +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::Rap, + lambdatrack::Eta, lambdatrack::Phi, + lambdatrack::Rap, lambdatrack::Mass, + lambdatrack::PrPx, + lambdatrack::PrPy, + lambdatrack::PrPz, lambdatrack::PosTrackId, lambdatrack::NegTrackId, + lambdatrack::CosPA, + lambdatrack::DcaDau, lambdatrack::V0Type, - lambdatrack::MassWindow); + lambdatrack::V0PrmScd, + 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::PrPx, + lambdatrack::PrPy, + lambdatrack::PrPz, + lambdatrack::PosTrackId, + lambdatrack::NegTrackId, + lambdatrack::V0Type, + lambdatrack::CosPA, + lambdatrack::DcaDau, + lambdatrack::V0PrmScd, + lambdatrack::CorrFact); +using LambdaMcGenTrack = LambdaMcGenTracks::iterator; + } // namespace o2::aod -enum PidType { - kPion = 0, - kProton +enum CollisionLabels { + kTotColBeforeHasMcCollision = 1, + kTotCol, + kPassSelCol +}; + +enum TrackLabels { + kTracksBeforeHasMcParticle = 1, + kAllV0Tracks, + kV0KShortMassRej, + kNotLambdaNotAntiLambda, + kV0IsBothLambdaAntiLambda, + kNotLambdaAfterSel, + kV0IsLambdaOrAntiLambda, + kPassV0DauTrackSel, + kPassV0KinCuts, + kPassV0TopoSel, + kAllSelPassed, + kPrimaryLambda, + kSecondaryLambda, + kLambdaDauNotMcParticle, + kLambdaNotPrPiMinus, + kAntiLambdaNotAntiPrPiPlus, + kPassTrueLambdaSel, + kEffCorrPtCent, + kEffCorrPtRapCent, + kNoEffCorr, + kPFCorrPtCent, + kPFCorrPtRapCent, + kNoPFCorr, + kGenTotAccLambda, + kGenLambdaNoDau, + kGenLambdaToPrPi +}; + +enum CentEstType { + kCentFT0M = 0, + kCentFT0C +}; + +enum RunType { + kRun3 = 0, + kRun2 }; enum ParticleType { @@ -86,404 +205,1459 @@ enum ParticlePairType { kAntiLambdaAntiLambda }; -enum MassWindowType { - kCentralWindow = 0, - kLeftWindow, - kRightWindow +enum ShareDauLambda { + kUniqueLambda = 0, + kLambdaShareDau }; -struct lambdaCorrTableProducer { +enum RecGenType { + kRec = 0, + kGen +}; + +enum DMCType { + kData = 0, + kMC +}; + +enum CorrHistDim { + OneDimCorr = 1, + TwoDimCorr, + ThreeDimCorr +}; + +enum PrmScdType { + kPrimary = 0, + kSecondary +}; + +enum PrmScdPairType { + kPP = 0, + kPS, + kSP, + kSS +}; + +struct LambdaTableProducer { Produces lambdaCollisionTable; Produces lambdaTrackTable; + Produces lambdaMCGenCollisionTable; + Produces lambdaMCGenTrackTable; // Collisions - Configurable cfg_z_vtx{"cfg_z_vtx", 10.0, "z vertex cut"}; - Configurable cfg_trigger_tvx_sel{"cfg_trigger_tvx_sel", false, "Trigger Time and Vertex Selection"}; - Configurable cfg_tf_border{"cfg_tf_border", false, "Timeframe Border Selection"}; - Configurable cfg_noitsro_border{"cfg_noitsro_border", false, "No ITSRO Border Cut"}; - Configurable cfg_sel8_sel{"cfg_sel8_sel", true, "Sel8 (T0A + T0C) Selection"}; - Configurable cfg_itstpc_vtx{"cfg_itstpc_vtx", false, "ITS+TPC Vertex Selection"}; - Configurable cfg_pileup_reject{"cfg_pileup_reject", false, "Pileup rejection"}; - Configurable cfg_zvtx_time_diff{"cfg_zvtx_time_diff", false, "z-vtx time diff selection"}; + Configurable cCentEstimator{"cCentEstimator", 0, "Centrality Estimator : 0-FT0M, 1-FT0C"}; + 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 cfg_eta_cut{"cfg_eta_cut", 0.8, "Pseudorapidity cut"}; - Configurable cfg_min_crossed_rows{"cfg_min_crossed_rows", 70, "min crossed rows"}; - Configurable cfg_tpc_nsigma{"cfg_tpc_nsigma", 3.0, "TPC NSigma Selection Cut"}; - Configurable cfg_tof_nsigma{"cfg_tof_nsigma", 3.0, "TOF NSigma Selection Cut"}; + Configurable cTrackMinPt{"cTrackMinPt", 0.15, "p_{T} minimum"}; + Configurable cTrackMaxPt{"cTrackMaxPt", 999.0, "p_{T} maximum"}; + Configurable cTrackEtaCut{"cTrackEtaCut", 0.8, "Pseudorapidity cut"}; + Configurable cMinTpcCrossedRows{"cMinTpcCrossedRows", 70, "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", 3.0, "TPC NSigma Selection Cut"}; + Configurable cRemoveAmbiguousTracks{"cRemoveAmbiguousTracks", false, "Remove Ambiguous Tracks"}; // V0s - Configurable cfg_min_dca_V0_daughters{"cfg_min_dca_V0_daughters", 1.0, "min DCA between V0 daughters"}; - Configurable cfg_min_dca_pos_to_PV{"cfg_min_dca_pos_to_PV", 0.1, "Minimum V0 Positive Track DCAr cut to PV"}; - Configurable cfg_min_dca_neg_to_PV{"cfg_min_dca_neg_to_PV", 0.1, "Minimum V0 Negative Track DCAr cut to PV"}; - Configurable cfg_min_dca_V0_to_PV{"cfg_min_dca_V0_to_PV", 0.6, "Minimum DCA V0 to PV"}; - Configurable cfg_min_V0_radius{"cfg_min_V0_radius", 0.0, "Minimum V0 radius from PV"}; - Configurable cfg_max_V0_radius{"cfg_max_V0_radius", 50.0, "Maximum V0 radius from PV"}; - Configurable cfg_min_ctau{"cfg_min_ctau", 0.0, "Minimum ctau"}; - Configurable cfg_max_ctau{"cfg_max_ctau", 50.0, "Maximum ctau"}; - Configurable cfg_min_V0_cosPA{"cfg_min_V0_cosPA", 0.995, "Minimum V0 CosPA to PV"}; - Configurable cfg_lambda_mass_window{"cfg_lambda_mass_window", 0.01, "Mass Window to select Lambda"}; - Configurable cfg_kshort_rej{"cfg_kshort_rej", 0.005, "Reject K0Short Candidates"}; + 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"}; // V0s kinmatic acceptance - Configurable cfg_v0_pt_min{"cfg_v0_pt_min", 0.5, "Minimum V0 pT"}; - Configurable cfg_v0_pt_max{"cfg_v0_pt_max", 2.5, "Minimum V0 pT"}; - Configurable cfg_v0_rap_max{"cfg_v0_rap_max", 0.8, "|rap| cut"}; + 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"}; + Configurable cV0TypeSelFlag{"cV0TypeSelFlag", false, "V0 Type Selection Flag"}; + Configurable cV0TypeSelection{"cV0TypeSelection", 1, "V0 Type Selection"}; + + // V0s MC + Configurable cHasMcFlag{"cHasMcFlag", true, "Has Mc Tag"}; + Configurable cSelectTrueLambda{"cSelectTrueLambda", true, "Select True Lambda"}; + Configurable cSelMCPSV0{"cSelMCPSV0", true, "Select Primary/Secondary V0"}; + 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"}; + Configurable cRecoMomResoFlag{"cRecoMomResoFlag", false, "Check effect of momentum space smearing on balance function"}; + + // Efficiency Correction + Configurable cCorrectionFlag{"cCorrectionFlag", false, "Correction Flag"}; + Configurable cGetEffFact{"cGetEffFact", false, "Get Efficiency Factor Flag"}; + Configurable cGetPrimFrac{"cGetPrimFrac", false, "Get Primary Fraction Flag"}; + Configurable cCorrFactHist{"cCorrFactHist", 0, "Efficiency Factor Histogram"}; + Configurable cPrimFracHist{"cPrimFracHist", 0, "Primary Fraction Histogram"}; + + // 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; - // bool eta/rapidity - Configurable cfg_do_eta_analysis{"cfg_do_eta_analysis", false, "Eta Analysis"}; + // Histogram Registry. + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - // lambda mass windows - Configurable cfg_lambda_mass_min{"cfg_lambda_mass_min", 1.11, "Minimum Central Window"}; - Configurable cfg_lambda_mass_max{"cfg_lambda_mass_max", 1.12, "Maximum Central Window"}; - Configurable cfg_lambda_left_min{"cfg_lambda_left_min", 1.08, "Minimum Left Window"}; - Configurable cfg_lambda_left_max{"cfg_lambda_left_max", 1.10, "Maximum Left Window"}; - Configurable cfg_lambda_right_min{"cfg_lambda_right_min", 1.13, "Minimum Right Window"}; - Configurable cfg_lambda_right_max{"cfg_lambda_right_max", 1.15, "Maximum Right Window"}; + // initialize corr_factor objects + std::vector> vCorrFactStrings = {{"hEffVsPtCentLambda", "hEffVsPtCentAntiLambda"}, + {"hEffVsPtYCentLambda", "hEffVsPtYCentAntiLambda"}, + {"hEffVsPtEtaCentLambda", "hEffVsPtEtaCentAntiLambda"}}; - // global variable declaration - std::map mass_map_min; - std::map mass_map_max; + // initialize corr_factor objects + std::vector> vPrimFracStrings = {{"hPrimFracVsPtCentLambda", "hPrimFracVsPtCentAntiLambda"}, + {"hPrimFracVsPtYCentLambda", "hPrimFracVsPtYCentAntiLambda"}, + {"hPrimFracVsPtEtaCentLambda", "hPrimFracVsPtEtaCentAntiLambda"}}; - // Histogram Registry. - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // Initialize Global Variables + float cent = 0., mult = 0.; + float pt = 0., eta = 0., rap = 0., phi = 0.; void init(InitContext const&) { - // global variable - mass_map_min = {{kCentralWindow, cfg_lambda_mass_min}, {kLeftWindow, cfg_lambda_left_min}, {kRightWindow, cfg_lambda_right_min}}; - mass_map_max = {{kCentralWindow, cfg_lambda_mass_max}, {kLeftWindow, cfg_lambda_left_max}, {kRightWindow, cfg_lambda_right_max}}; - - const AxisSpec axisCent(105, 0, 105, "FT0M (%)"); + // Set CCDB url + ccdb->setURL(cUrlCCDB.value); + ccdb->setCaching(true); + + // initialize axis specifications + const AxisSpec axisCols(5, 0.5, 5.5, ""); + const AxisSpec axisTrks(30, 0.5, 30.5, ""); + const AxisSpec axisCent(100, 0, 100, "FT0M (%)"); const AxisSpec axisMult(10, 0, 10, "N_{#Lambda}"); - - const AxisSpec axisV0Mass(100, 1.06, 1.16, "Inv Mass (GeV/#it{c}^{2})"); - const AxisSpec axisV0Pt(200, 0., 5., "p_{T} (GeV/#it{c})"); - const AxisSpec axisV0Rap(16, -1., 1., "rap"); - const AxisSpec axisV0Phi(36, 0., 2. * TMath::Pi(), "#phi (rad)"); - - const AxisSpec axisRadius(500, 0, 100, "r(cm)"); - const AxisSpec axisCosPA(120, 0.97, 1.0, "cos(#theta_{PA})"); - const AxisSpec axisDcaV0PV(200, 0, 2., "dca (cm)"); - const AxisSpec axisDcaProngPV(200, 0, 20., "dca (cm)"); - const AxisSpec axisDcaDau(75, 0., 1.5, "Daug DCA (cm^{2})"); - const AxisSpec axisCTau(500, 0, 100, "c#tau (cm/#it{c})"); - + 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(300, 0.97, 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("QA_Checks/h1d_lambda_mass", "M_{#Lambda}", kTH1F, {axisV0Mass}); + 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_Sel_Lambda/h1d_V0_inv_mass", "V_{0} mass", kTH1F, {axisV0Mass}); - histos.add("QA_Sel_Lambda/h1d_V0_pt", "V_{0} p_{T}", kTH1F, {axisV0Pt}); - histos.add("QA_Sel_Lambda/h1d_V0_eta", "#eta-distribution", kTH1F, {axisV0Rap}); - histos.add("QA_Sel_Lambda/h1d_V0_rap", "y-distribution", kTH1F, {axisV0Rap}); - histos.add("QA_Sel_Lambda/h1d_V0_phi", "#phi-distribution", kTH1F, {axisV0Phi}); - - histos.add("QA_Sel_Lambda/h1d_dca_V0_daughters", "DCA between V0 daughters", kTH1F, {axisDcaDau}); - histos.add("QA_Sel_Lambda/h1d_dca_pos_to_PV", "DCA positive prong to PV", kTH1F, {axisDcaProngPV}); - histos.add("QA_Sel_Lambda/h1d_dca_neg_to_PV", "DCA negative prong to PV", kTH1F, {axisDcaProngPV}); - histos.add("QA_Sel_Lambda/h1d_dca_V0_to_PV", "DCA V0 to PV", kTH1F, {axisDcaV0PV}); - histos.add("QA_Sel_Lambda/h1d_V0_cospa", "cos(#theta_{PA})", kTH1F, {axisCosPA}); - histos.add("QA_Sel_Lambda/h1d_V0_radius", "V_{0} Decay Radius in XY plane", kTH1F, {axisRadius}); - histos.add("QA_Sel_Lambda/h1d_V0_ctau", "V_{0} c#tau", kTH1F, {axisCTau}); - - histos.add("QA_Sel_Lambda/h2d_pr_dEdx_vs_p", "TPC Signal Proton", kTH2F, {axisMomPID, axisdEdx}); - histos.add("QA_Sel_Lambda/h2d_pi_dEdx_vs_p", "TPC Signal Pion", kTH2F, {axisMomPID, axisdEdx}); - histos.add("QA_Sel_Lambda/h2d_pr_nsigma_tpc", "TPC Proton", kTH2F, {axisMomPID, axisNsigma}); - histos.add("QA_Sel_Lambda/h2d_pi_nsigma_tpc", "TPC Pion", kTH2F, {axisMomPID, axisNsigma}); - histos.add("QA_Sel_Lambda/h2d_pr_nsigma_tof", "TOF Proton", kTH2F, {axisMomPID, axisNsigma}); - histos.add("QA_Sel_Lambda/h2d_pi_nsigma_tof", "TOF Pion", kTH2F, {axisMomPID, axisNsigma}); + 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/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_Sel_Lambda/", "QA_Sel_AntiLambda/"); + histos.addClone("QA/Lambda/", "QA/AntiLambda/"); + histos.addClone("McRec/Lambda/", "McRec/AntiLambda/"); + + // MC Generated Histograms + if (doprocessMCRun3 || doprocessMCRun2 || doprocessMCRecoRun3 || doprocessMCRecoRun2) { + // 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_mothers_pdg", "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::kPrimaryLambda, "kPrimaryLambda"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kSecondaryLambda, "kSecondaryLambda"); + 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::kEffCorrPtCent, "kEffCorrPtCent"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kEffCorrPtRapCent, "kEffCorrPtRapCent"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kNoEffCorr, "kNoEffCorr"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kPFCorrPtCent, "kPFCorrPtCent"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kPFCorrPtRapCent, "kPFCorrPtRapCent"); + histos.get(HIST("Tracks/h1f_tracks_info"))->GetXaxis()->SetBinLabel(TrackLabels::kNoPFCorr, "kNoPFCorr"); } - template - bool selCol(C const& col) + template + bool selCollision(C const& col) { + // VtxZ Selection + if (col.posZ() <= cMinZVtx || col.posZ() >= cMaxZVtx) { + return false; + } - if (fabs(col.posZ()) > cfg_z_vtx) { + if constexpr (run == kRun3) { // Run3 Min-Bias Trigger + // select centrality estimator + if (cCentEstimator == kCentFT0M) { + cent = col.centFT0M(); + } else if (cCentEstimator == kCentFT0C) { + cent = col.centFT0C(); + } + 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 percentile class return false; } - if (!col.selection_bit(aod::evsel::kIsTriggerTVX) && cfg_trigger_tvx_sel) { + if (cTriggerTvxSel && !col.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; } - if (!col.selection_bit(aod::evsel::kNoTimeFrameBorder) && cfg_tf_border) { + if (cTFBorder && !col.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return false; } - if (!col.selection_bit(aod::evsel::kNoITSROFrameBorder) && cfg_noitsro_border) { + if (cNoItsROBorder && !col.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return false; } - if (!col.sel8() && cfg_sel8_sel) { + if (cItsTpcVtx && !col.selection_bit(aod::evsel::kIsVertexITSTPC)) { return false; } - if (!col.selection_bit(aod::evsel::kIsVertexITSTPC) && cfg_itstpc_vtx) { + if (cPileupReject && !col.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; } - if (!col.selection_bit(aod::evsel::kNoSameBunchPileup) && cfg_pileup_reject) { + if (cZVtxTimeDiff && !col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; } - if (!col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && cfg_zvtx_time_diff) { + if (cIsGoodITSLayers && !col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { return false; } + // Set Multiplicity + mult = col.multNTracksPV(); + return true; } - template - bool topologicalCutsV0(V const& v0, T const&) + // 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; + } - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); + return true; + } + + // Track Selection + template + bool selTrack(T const& track) + { + if (!kinCutSelection(track.pt(), std::abs(track.eta()), cTrackMinPt, cTrackMaxPt, cTrackEtaCut)) { + return false; + } - if (fabs(postrack.eta()) > cfg_eta_cut) { + if (track.tpcNClsCrossedRows() <= cMinTpcCrossedRows) { return false; } - if (fabs(negtrack.eta()) > cfg_eta_cut) { + if (track.tpcCrossedRowsOverFindableCls() < cMinTpcCROverCls) { return false; } - if (postrack.tpcNClsCrossedRows() < cfg_min_crossed_rows) { + if (track.tpcNClsShared() > cMaxTpcSharedClusters) { return false; } - if (negtrack.tpcNClsCrossedRows() < cfg_min_crossed_rows) { + if (track.tpcChi2NCl() > cMaxChi2Tpc) { return false; } - if (v0.dcaV0daughters() > cfg_min_dca_V0_daughters) { + 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; } - if (fabs(v0.dcapostopv()) < cfg_min_dca_pos_to_PV) { + // 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; } - if (fabs(v0.dcanegtopv()) < cfg_min_dca_neg_to_PV) { + 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.dcav0topv() > cfg_min_dca_V0_to_PV) { + if (v0.v0radius() <= cMinV0TransRadius || v0.v0radius() >= cMaxV0TransRadius) { return false; } - if ((v0.v0radius() > cfg_max_V0_radius) || (v0.v0radius() < cfg_min_V0_radius)) { + // ctau + float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * MassLambda0; + if (ctau <= cMinV0CTau || ctau >= cMaxV0CTau) { return false; } - if (v0.v0cosPA() < cfg_min_V0_cosPA) { + // cosine of pointing angle + if (v0.v0cosPA() <= cMinV0CosPA) { return false; } + // all selection criterion passed (Return True) return true; } - template - bool selPIDTrack(T const& track) + 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; - bool selTPCv0type = false, selTOFv0type = false; - float tpcNSigma = 0., tofNSigma = 0.; + // negtrack = Proton, postrack = Pion + case kAntiLambda: + tpcNSigmaPr = negtrack.tpcNSigmaPr(); + tpcNSigmaPi = postrack.tpcNSigmaPi(); + break; + } - switch (pid) { + if (std::abs(tpcNSigmaPr) < cTpcNsigmaCut && std::abs(tpcNSigmaPi) < cTpcNsigmaCut) { + returnFlag = true; + } - case kPion: - tpcNSigma = track.tpcNSigmaPi(); - tofNSigma = track.tofNSigmaPi(); - break; + return returnFlag; + } - case kProton: - tpcNSigma = track.tpcNSigmaPr(); - tofNSigma = track.tofNSigmaPr(); - break; + 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; } - if (track.hasTOF()) { - if (fabs(tofNSigma) < cfg_tof_nsigma) { - selTOFv0type = true; - } - if (fabs(tpcNSigma) < cfg_tpc_nsigma) { - selTPCv0type = true; - } + // 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 { - selTOFv0type = true; - if (fabs(tpcNSigma) < cfg_tpc_nsigma) { - selTPCv0type = true; - } + 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 hasAmbiguousDaughters(V const& v0, T const&) + { + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + + auto posTrackCompCols = posTrack.compatibleCollIds(); + auto negTrackCompCols = negTrack.compatibleCollIds(); + + // Check if daughter tracks belongs to more than one collision (Ambiguous Tracks) + if (posTrackCompCols.size() > 1 || negTrackCompCols.size() > 1) { + return true; } - if (selTPCv0type && selTOFv0type) { + // Check if compatible collision index matches the track collision index + if (((posTrackCompCols.size() != 0) && (posTrackCompCols[0] != posTrack.collisionId())) || + ((negTrackCompCols.size() != 0) && (negTrackCompCols[0] != negTrack.collisionId()))) { return true; } + // Pass as not ambiguous return false; } - template - void fillQALambda(C const& col, V const& v0, T const&) + template + PrmScdType isPrimaryV0(V const& v0) { + auto mcpart = v0.template mcParticle_as(); - static constexpr std::string_view sub_dir[] = {"QA_Sel_Lambda/", "QA_Sel_AntiLambda/"}; + // check for secondary lambda + if (!mcpart.isPhysicalPrimary()) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kSecondaryLambda); + return kSecondary; + } - // ctau - float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * MassLambda0; + histos.fill(HIST("Tracks/h1f_tracks_info"), kPrimaryLambda); + return kPrimary; + } + + 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; + } + } + } + + return true; + } + + template + float getCorrectionFactors(V const& v0) + { + // Check for efficiency correction flag + 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.; + } + + // initialize efficiency factor and primary fraction values + float effCorrFact = 1., primFrac = 1.; + float rap = (cDoEtaAnalysis) ? v0.eta() : v0.yLambda(); + + // Get Efficiency Factor + if (cGetEffFact) { + TObject* objEff = reinterpret_cast(ccdbObj->FindObject(Form("%s", vCorrFactStrings[cCorrFactHist][part].c_str()))); + TH1F* histEff = reinterpret_cast(objEff->Clone()); + if (histEff->GetDimension() == TwoDimCorr) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kEffCorrPtCent); + effCorrFact = histEff->GetBinContent(histEff->FindBin(cent, v0.pt())); + } else if (histEff->GetDimension() == ThreeDimCorr) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kEffCorrPtRapCent); + effCorrFact = histEff->GetBinContent(histEff->FindBin(cent, v0.pt(), rap)); + } else { + histos.fill(HIST("Tracks/h1f_tracks_info"), kNoEffCorr); + LOGF(warning, "CCDB OBJECT IS NOT A HISTOGRAM !!!"); + effCorrFact = 1.; + } + delete histEff; + } + + // Get Primary Fraction + // (The dimension of this could be different than efficiency because of large errors !!!) + if (cGetPrimFrac) { + TObject* objPrm = reinterpret_cast(ccdbObj->FindObject(Form("%s", vPrimFracStrings[cPrimFracHist][part].c_str()))); + TH1F* histPrm = reinterpret_cast(objPrm->Clone()); + if (histPrm->GetDimension() == TwoDimCorr) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kPFCorrPtCent); + primFrac = histPrm->GetBinContent(histPrm->FindBin(cent, v0.pt())); + } else if (histPrm->GetDimension() == ThreeDimCorr) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kPFCorrPtRapCent); + primFrac = histPrm->GetBinContent(histPrm->FindBin(cent, v0.pt(), rap)); + } else { + histos.fill(HIST("Tracks/h1f_tracks_info"), kNoPFCorr); + LOGF(warning, "CCDB OBJECT IS NOT A HISTOGRAM !!!"); + primFrac = 1.; + } + delete histPrm; + } + + return primFrac * effCorrFact; + } + + template + void fillLambdaMothers(V const& v0, T const&) + { + auto mcpart = v0.template mcParticle_as(); + auto lambdaMothers = mcpart.template mothers_as(); + histos.fill(HIST("Tracks/h2f_lambda_mothers_pdg"), lambdaMothers[0].pdgCode(), v0.pt()); + } + + 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.; - histos.fill(HIST(sub_dir[part]) + HIST("h1d_dca_V0_daughters"), v0.dcaV0daughters()); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_dca_pos_to_PV"), fabs(v0.dcapostopv())); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_dca_neg_to_PV"), fabs(v0.dcanegtopv())); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_dca_V0_to_PV"), fabs(v0.dcav0topv())); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_cospa"), v0.v0cosPA()); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_radius"), v0.v0radius()); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_ctau"), ctau); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_pt"), v0.pt()); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_eta"), v0.eta()); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_rap"), v0.yLambda()); - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_phi"), v0.phi()); if constexpr (part == kLambda) { - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_inv_mass"), v0.mLambda()); - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pr_dEdx_vs_p"), postrack.tpcInnerParam(), postrack.tpcSignal()); - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pi_dEdx_vs_p"), negtrack.tpcInnerParam(), negtrack.tpcSignal()); - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pr_nsigma_tpc"), postrack.tpcInnerParam(), postrack.tpcNSigmaPr()); - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pi_nsigma_tpc"), negtrack.tpcInnerParam(), negtrack.tpcNSigmaPi()); - if (postrack.hasTOF()) { - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pr_nsigma_tof"), postrack.tofExpMom(), postrack.tofNSigmaPr()); + 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; } - if (negtrack.hasTOF()) { - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pi_nsigma_tof"), negtrack.tofExpMom(), negtrack.tofNSigmaPi()); + } + + histos.fill(HIST("Events/h1f_collisions_info"), kPassSelCol); + histos.fill(HIST("Events/h1f_collision_posZ"), collision.posZ()); + + // Fill Collision Table + lambdaCollisionTable(cent, mult, collision.posX(), collision.posY(), collision.posZ()); + + // initialize v0track objects + ParticleType v0Type = kLambda; + PrmScdType v0PrmScdType = kPrimary; + float mass = 0., corr_fact = 1.; + float prPx = 0., prPy = 0., prPz = 0.; + + 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()) { + continue; + } } - } else { - histos.fill(HIST(sub_dir[part]) + HIST("h1d_V0_inv_mass"), v0.mAntiLambda()); - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pi_dEdx_vs_p"), postrack.tpcInnerParam(), postrack.tpcSignal()); - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pr_dEdx_vs_p"), negtrack.tpcInnerParam(), negtrack.tpcSignal()); - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pi_nsigma_tpc"), postrack.tpcInnerParam(), postrack.tpcNSigmaPi()); - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pr_nsigma_tpc"), negtrack.tpcInnerParam(), negtrack.tpcNSigmaPr()); - if (postrack.hasTOF()) { - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pi_nsigma_tof"), postrack.tofExpMom(), postrack.tofNSigmaPi()); + + 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; + } + + // Select V0 Type Selection + if (cV0TypeSelFlag && v0.v0Type() != cV0TypeSelection) { + continue; + } + + // we have v0 as lambda + histos.fill(HIST("Tracks/h1f_tracks_info"), kAllSelPassed); + + // Remove lambda with ambiguous daughters (Only for run3) + if constexpr (run == kRun3) { + if (cRemoveAmbiguousTracks && hasAmbiguousDaughters(v0, tracks)) { + continue; + } } - if (negtrack.hasTOF()) { - histos.fill(HIST(sub_dir[part]) + HIST("h2d_pr_nsigma_tof"), negtrack.tofExpMom(), negtrack.tofNSigmaPr()); + + // Get Lambda mass and kinematic variables + mass = (v0Type == kLambda) ? v0.mLambda() : v0.mAntiLambda(); + pt = v0.pt(); + eta = v0.eta(); + rap = v0.yLambda(); + phi = v0.phi(); + + // do MC analysis + if constexpr (dmc == kMC) { + histos.fill(HIST("Tracks/h2f_tracks_pid_before_sel"), v0.mcParticle().pdgCode(), v0.pt()); + + // Get Primary/Secondary Lambda + if (cSelMCPSV0) { + v0PrmScdType = isPrimaryV0(v0); + } + + // check for true Lambda/Anti-Lambda + if (cSelectTrueLambda && !selTrueMcRecLambda(v0, tracks)) { + continue; + } + + // get mothers information + if (v0PrmScdType == kSecondary) { + fillLambdaMothers(v0, tracks); + } + + histos.fill(HIST("Tracks/h1f_tracks_info"), kPassTrueLambdaSel); + histos.fill(HIST("Tracks/h2f_tracks_pid_after_sel"), v0.mcParticle().pdgCode(), v0.pt()); + + if (cRecoMomResoFlag) { + auto mc = v0.template mcParticle_as(); + pt = mc.pt(); + eta = mc.eta(); + rap = mc.y(); + phi = mc.phi(); + float y = (cDoEtaAnalysis) ? eta : rap; + // apply kinematic selection (On Truth) + if (!kinCutSelection(pt, std::abs(y), cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) { + continue; + } + } + } + + histos.fill(HIST("Tracks/h2f_armpod_after_sel"), v0.alpha(), v0.qtarm()); + + // get correction factors + corr_fact = (v0Type == kLambda) ? getCorrectionFactors(v0) : getCorrectionFactors(v0); + + // fill lambda qa + if (v0Type == kLambda) { + // Assign proton Eta Phi + prPx = v0.template posTrack_as().px(); + prPy = v0.template posTrack_as().py(); + prPz = v0.template posTrack_as().pz(); + 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 { + // Assign proton Eta Phi + prPx = v0.template negTrack_as().px(); + prPy = v0.template negTrack_as().py(); + prPz = v0.template negTrack_as().pz(); + 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(), + pt, eta, phi, rap, mass, prPx, prPy, prPz, + v0.template posTrack_as().index(), v0.template negTrack_as().index(), + v0.v0cosPA(), v0.dcaV0daughters(), (int8_t)v0Type, v0PrmScdType, corr_fact); } } - template - void selV0Particle(C const& collision, V const& v0track, T const& tracks) + // MC Generater Level Tables + template + void fillLambdaMcGenTables(C const& mcCollision, M const& mcParticles) { + // Fill McGen Collision Table + lambdaMCGenCollisionTable(cent, mult, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); + + // initialize track objects + ParticleType v0Type = kLambda; + PrmScdType v0PrmScdType = kPrimary; + float rap = 0.; + float prPx = 0., prPy = 0., prPz = 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; + } - // initialize variables - auto postrack = v0track.template posTrack_as(); - auto negtrack = v0track.template negTrack_as(); - float mass = 0., rap = 0.; + // check for Primary Lambda/AntiLambda + if (mcpart.isPhysicalPrimary()) { + v0PrmScdType = kPrimary; + } else { + v0PrmScdType = kSecondary; + } - if (v0part == kLambda) { - mass = v0track.mLambda(); - } - if (v0part == kAntiLambda) { - mass = v0track.mAntiLambda(); - } + // Decide Eta/Rap + if (!cDoEtaAnalysis) { + rap = mcpart.y(); + } else { + rap = mcpart.eta(); + } - if (cfg_do_eta_analysis) { - rap = v0track.eta(); - } else { - rap = v0track.yLambda(); + // 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; + std::vector vDauPx, vDauPy, vDauPz; + 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()); + vDauPx.push_back(dautrack.px()); + vDauPy.push_back(dautrack.py()); + vDauPz.push_back(dautrack.pz()); + } + 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) { + // Assign proton p-vec + prPx = vDauPx[0]; + prPy = vDauPy[0]; + prPz = vDauPz[0]; + 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 { + // Assign anti-proton p-vec + prPx = vDauPx[1]; + prPy = vDauPy[1]; + prPz = vDauPz[1]; + 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()), prPx, prPy, prPz, + daughterIDs[0], daughterIDs[1], (int8_t)v0Type, -999., -999., v0PrmScdType, 1.); } + } - // apply mass window selection [global] - if ((fabs(mass - MassLambda0) >= cfg_lambda_mass_window) || (fabs(v0track.mK0Short() - MassK0Short) <= cfg_kshort_rej)) { + 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; } - - // apply daughter particle id - if (!selPIDTrack(postrack) || !selPIDTrack(negtrack)) { + 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; } + histos.fill(HIST("McGen/h1f_collisions_info"), kPassSelCol); + histos.fill(HIST("McGen/h2f_collision_posZ"), mcCollision.posZ(), collisions.begin().posZ()); + auto v0Tracks = V0s.sliceBy(perCollision, collisions.begin().globalIndex()); + fillLambdaRecoTables(collisions.begin(), v0Tracks, tracks); + fillLambdaMcGenTables(mcCollision, mcParticles); + } + + SliceCache cache; + Preslice> perCollision = aod::v0data::collisionId; + + using CollisionsRun3 = soa::Join; + using CollisionsRun2 = soa::Join; + using Tracks = soa::Join; + using TracksRun2 = soa::Join; + using TracksMC = soa::Join; + using TracksMCRun2 = soa::Join; + using McV0Tracks = 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, TracksRun2 const& tracks) + { + fillLambdaRecoTables(collision, V0s, tracks); + } - // apply kinematic acceptance - if (v0track.pt() <= cfg_v0_pt_min || v0track.pt() >= cfg_v0_pt_max) { + PROCESS_SWITCH(LambdaTableProducer, processDataRun2, "Process for Run2 DATA", false); + + void processMCRecoRun3(soa::Join::iterator const& collision, aod::McCollisions const&, + McV0Tracks const& V0s, TracksMC const& tracks, aod::McParticles const&) + { + // check collision + if (!selCollision(collision)) { return; } + fillLambdaRecoTables(collision, V0s, tracks); + } - if (cfg_do_eta_analysis && (fabs(v0track.eta()) >= cfg_v0_rap_max)) { - return; - } else if (fabs(v0track.yLambda()) >= cfg_v0_rap_max) { + PROCESS_SWITCH(LambdaTableProducer, processMCRecoRun3, "Process for Run3 McReco DATA", false); + + void processMCRecoRun2(soa::Join::iterator const& collision, aod::McCollisions const&, + McV0Tracks const& V0s, TracksMCRun2 const& tracks, aod::McParticles const&) + { + // check collision + if (!selCollision(collision)) { return; } + fillLambdaRecoTables(collision, V0s, tracks); + } - if (v0part == kLambda) { - histos.fill(HIST("QA_Checks/h1d_lambda_mass"), v0track.mLambda()); - } + PROCESS_SWITCH(LambdaTableProducer, processMCRecoRun2, "Process for Run2 McReco DATA", false); + + void processMCRun3(aod::McCollisions::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(aod::McCollisions::iterator const& mcCollision, + soa::SmallGroups> const& collisions, + McV0Tracks const& V0s, TracksMCRun2 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}; - if (v0part == kAntiLambda) { - histos.fill(HIST("QA_Checks/h1d_lambda_mass"), v0track.mAntiLambda()); + 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)"); + const AxisSpec axisDEta(320, -1.6, 1.6, "#Delta#eta"); + const AxisSpec axisDPhi(640, -PIHalf, 3. * PIHalf, "#Delta#varphi"); + + // 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}); + histos.add("h2d_n2_etaphi_LaP_LaM", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); + histos.add("h2d_n2_etaphi_LaP_LaP", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); + histos.add("h2d_n2_etaphi_LaM_LaM", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); + + // 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 if lambda shares daughters with any other track + if (lambda.posTrackId() == track.posTrackId() || lambda.negTrackId() == track.negTrackId()) { + vSharedDauLambdaIndex.push_back(track.index()); + lambdaSharingDauFlag = true; + + // Fill DEta-DPhi Histogram + if ((lambda.v0Type() == kLambda && track.v0Type() == kAntiLambda) || (lambda.v0Type() == kAntiLambda && track.v0Type() == kLambda)) { + histos.fill(HIST("h2d_n2_etaphi_LaP_LaM"), lambda.eta() - track.eta(), RecoDecay::constrainAngle((lambda.phi() - track.phi()), -PIHalf)); + } else if (lambda.v0Type() == kLambda && track.v0Type() == kLambda) { + histos.fill(HIST("h2d_n2_etaphi_LaP_LaP"), lambda.eta() - track.eta(), RecoDecay::constrainAngle((lambda.phi() - track.phi()), -PIHalf)); + } else if (lambda.v0Type() == kAntiLambda && track.v0Type() == kAntiLambda) { + histos.fill(HIST("h2d_n2_etaphi_LaM_LaM"), lambda.eta() - track.eta(), RecoDecay::constrainAngle((lambda.phi() - track.phi()), -PIHalf)); + } + + // 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; + } - // apply further mass window selection [central, left, right] - if (mass > mass_map_min[masswin] && mass < mass_map_max[masswin]) { - if (masswin == kCentralWindow) { - fillQALambda(collision, v0track, tracks); + // Multiplicity of selected lambda + if (trueLambdaFlag) { + if (lambda.v0Type() == kLambda) { + ++nSelLambda; + } else if (lambda.v0Type() == kAntiLambda) { + ++nSelAntiLambda; + } } - lambdaTrackTable(lambdaCollisionTable.lastIndex(), v0track.pt(), rap, v0track.phi(), mass, postrack.index(), negtrack.index(), v0part, masswin); + + // 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); } } +}; - using Collisions = soa::Join; - using Tracks = soa::Join; +struct LambdaSpinCorrelation { + // Global Configurables + Configurable cNPtBins{"cNPtBins", 30, "N pT Bins"}; + Configurable cMinPt{"cMinPt", 0.5, "pT Min"}; + Configurable cMaxPt{"cMaxPt", 3.5, "pT Max"}; + Configurable cNRapBins{"cNRapBins", 10, "N Rapidity Bins"}; + Configurable cMinRap{"cMinRap", -0.5, "Minimum Rapidity"}; + Configurable cMaxRap{"cMaxRap", 0.5, "Maximum Rapidity"}; + Configurable cNPhiBins{"cNPhiBins", 36, "N Phi Bins"}; + Configurable cNBinsCosTS{"cNBinsCosTS", 10, "N CosTS Bins"}; + Configurable cInvBoostFlag{"cInvBoostFlag", true, "Inverse Boost Flag"}; + + // Centrality Axis + ConfigurableAxis cMultBins{"cMultBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 30.0f, 50.f, 80.0f, 100.f}, "Variable Mult-Bins"}; - void process(Collisions::iterator const& collision, aod::V0Datas const& V0s, Tracks const& tracks) + // Histogram Registry. + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Global variables + float cent = 0.; + + void init(InitContext const&) { + const AxisSpec axisCheck(1, 0, 1, ""); + const AxisSpec axisPosZ(220, -11, 11, "V_{z} (cm)"); + const AxisSpec axisCent(cMultBins, "FT0M (%)"); + const AxisSpec axisChMult(200, 0, 200, "N_{ch}"); + const AxisSpec axisMult(10, 0, 10, "N_{#Lambda}"); + const AxisSpec axisMass(100, 1.06, 1.16, "M_{#Lambda} (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 axisDRap(2 * cNRapBins, cMinRap - cMaxRap, cMaxRap - cMinRap, "#Deltay"); + const AxisSpec axisDPhi(cNPhiBins, -PI, PI, "#Delta#varphi"); + const AxisSpec axisCosTS(cNBinsCosTS, -1, 1, "cos(#theta*)"); + const AxisSpec axisDR(10, 0, 2, "#DeltaR"); + + // Single and Two Particle Densities + // 1D Histograms + histos.add("Reco/h2f_n2_mass_LaPLaM", "m_{inv}^{#Lambda} vs m_{inv}^{#bar{#Lambda}}", kTHnSparseF, {axisMass, axisMass, axisPt, axisPt}); + histos.add("Reco/h2f_n2_mass_LaPLaP", "m_{inv}^{#Lambda} vs m_{inv}^{#Lambda}", kTHnSparseF, {axisMass, axisMass, axisPt, axisPt}); + histos.add("Reco/h2f_n2_mass_LaMLaM", "m_{inv}^{#bar{#Lambda}} vs m_{inv}^{#bar{#Lambda}}", kTHnSparseF, {axisMass, axisMass, axisPt, axisPt}); + + // rho2 for C2 + histos.add("RecoCorr/h2f_n2_dlta_LaPLaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisDR}); + histos.add("RecoCorr/h2f_n2_dlta_LaPLaP", "#rho_{2}^{#Lambda#Lambda}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisDR}); + histos.add("RecoCorr/h2f_n2_dlta_LaMLaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisCosTS}); + histos.add("RecoCorr/h2f_n2_cphi_LaPLaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisCosTS}); + histos.add("RecoCorr/h2f_n2_cphi_LaPLaP", "#rho_{2}^{#Lambda#Lambda}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisCosTS}); + histos.add("RecoCorr/h2f_n2_cphi_LaMLaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisCosTS}); + histos.add("RecoCorr/h2f_n2_dphi_LaPLaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisDPhi}); + histos.add("RecoCorr/h2f_n2_dphi_LaPLaP", "#rho_{2}^{#Lambda#Lambda}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisDPhi}); + histos.add("RecoCorr/h2f_n2_dphi_LaMLaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTHnSparseF, {axisCent, axisDRap, axisDPhi, axisDPhi}); + } - // select collision - if (!selCol(collision)) { - return; + void getBoostVector(std::array const& p, std::array& v, bool inverseBoostFlag = true) + { + int n = p.size(); + for (int i = 0; i < n - 1; ++i) { + if (inverseBoostFlag) { + v[i] = -p[i] / RecoDecay::e(p[0], p[1], p[2], p[3]); + } else { + v[i] = p[i] / RecoDecay::e(p[0], p[1], p[2], p[3]); + } } + } - lambdaCollisionTable(collision.centFT0M(), collision.posX(), collision.posY(), collision.posZ()); + void boost(std::array& p, std::array const& b) + { + float e = RecoDecay::e(p[0], p[1], p[2], p[3]); + float b2 = b[0] * b[0] + b[1] * b[1] + b[2] * b[2]; + float gamma = 1. / std::sqrt(1 - b2); + float bp = b[0] * p[0] + b[1] * p[1] + b[2] * p[2]; + float gamma2 = b2 > 0 ? (gamma - 1.) / b2 : 0.; + + p[0] = p[0] + gamma2 * bp * b[0] + gamma * b[0] * e; + p[1] = p[1] + gamma2 * bp * b[1] + gamma * b[1] * e; + p[2] = p[2] + gamma2 * bp * b[2] + gamma * b[2] * e; + } - for (auto const& v0 : V0s) { + template + void fillPairHistos(U& p1, U& p2) + { + static constexpr std::string_view SubDirHist[] = {"LaPLaM", "LaPLaP", "LaMLaM"}; + + // Fill lambda pair mass + histos.fill(HIST("Reco/h2f_n2_mass_") + HIST(SubDirHist[part_pair]), p1.mass(), p2.mass(), p1.pt(), p2.pt()); + float drap = p1.rap() - p2.rap(); + float dphi = RecoDecay::constrainAngle(p1.phi() - p2.phi(), -PI); + + // Get Lambda-Proton four-momentum + std::array l1 = {p1.px(), p1.py(), p1.pz(), MassLambda0}; + std::array l2 = {p2.px(), p2.py(), p2.pz(), MassLambda0}; + std::array pr1 = {p1.prPx(), p1.prPy(), p1.prPz(), MassProton}; + std::array pr2 = {p2.prPx(), p2.prPy(), p2.prPz(), MassProton}; + std::array v1, v2; + getBoostVector(l1, v1, cInvBoostFlag); + getBoostVector(l2, v2, cInvBoostFlag); + boost(pr1, v1); + boost(pr2, v2); + + std::array pr1tv = {pr1[0], pr1[1], pr1[2]}; + std::array pr2tv = {pr2[0], pr2[1], pr2[2]}; + float cphi = RecoDecay::dotProd(pr1tv, pr2tv) / (RecoDecay::sqrtSumOfSquares(pr1tv[0], pr1tv[1], pr1tv[2]) * RecoDecay::sqrtSumOfSquares(pr2tv[0], pr2tv[1], pr2tv[2])); + float prdphi = RecoDecay::constrainAngle(RecoDecay::phi(pr1) - RecoDecay::phi(pr2), -PI); + float prdrap = RecoDecay::eta(pr1tv) - RecoDecay::eta(pr2tv); + float dr = std::sqrt(prdrap * prdrap + prdphi * prdphi); + + // Fill pair density + histos.fill(HIST("RecoCorr/h2f_n2_dphi_") + HIST(SubDirHist[part_pair]), cent, drap, dphi, RecoDecay::constrainAngle(RecoDecay::phi(pr1) - RecoDecay::phi(pr2), -PI)); + histos.fill(HIST("RecoCorr/h2f_n2_cphi_") + HIST(SubDirHist[part_pair]), cent, drap, dphi, cphi); + histos.fill(HIST("RecoCorr/h2f_n2_dlta_") + HIST(SubDirHist[part_pair]), cent, drap, dphi, dr); + } - // apply topological cuts on v0 candidates - if (!topologicalCutsV0(v0, tracks)) { - continue; + 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); } - - selV0Particle(collision, v0, tracks); - selV0Particle(collision, v0, tracks); - selV0Particle(collision, v0, tracks); - selV0Particle(collision, v0, tracks); - selV0Particle(collision, v0, tracks); - selV0Particle(collision, v0, tracks); } } -}; -struct lambdaCorrelationAnalysis { + // Initialize tables + using LambdaCollisions = aod::LambdaCollisions; + using LambdaTracks = soa::Join; + + SliceCache cache; + Partition partLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kLambda) && (aod::lambdatrackext::trueLambdaFlag == true) && (aod::lambdatrack::v0PrmScd == (int8_t)kPrimary); + Partition partAntiLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kAntiLambda) && (aod::lambdatrackext::trueLambdaFlag == true) && (aod::lambdatrack::v0PrmScd == (int8_t)kPrimary); + + void processDummy(LambdaCollisions::iterator const&) {} + + PROCESS_SWITCH(LambdaSpinCorrelation, processDummy, "Dummy process", true); + + void processDataReco(LambdaCollisions::iterator const& collision, LambdaTracks const&) + { + // assign centrality + cent = collision.cent(); + + auto lambdaTracks = partLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + auto antiLambdaTracks = partAntiLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + analyzePairs(lambdaTracks, antiLambdaTracks); + analyzePairs(lambdaTracks, lambdaTracks); + analyzePairs(antiLambdaTracks, antiLambdaTracks); + } + + PROCESS_SWITCH(LambdaSpinCorrelation, processDataReco, "Process for Data and MCReco", false); +}; +struct LambdaR2Correlation { // Global Configurables - Configurable cfg_nRapBins{"cfg_nRapBins", 16, "N Rapidity Bins"}; - Configurable cfg_Rap_Min{"cfg_Rap_Min", -0.8, "Minimum Rapidity"}; - Configurable cfg_Rap_Max{"cfg_Rap_Max", 0.8, "Maximum Rapidity"}; - Configurable cfg_nPhiBins{"cfg_nPhiBins", 64, "N Phi Bins"}; - Configurable cfg_Phi_Min{"cfg_Phi_Min", 0, "Minimum Phi"}; - Configurable cfg_Phi_Max{"cfg_Phi_Max", 2 * TMath::Pi(), "Maximum Phi"}; + Configurable cNPtBins{"cNPtBins", 34, "N pT Bins"}; + Configurable cMinPt{"cMinPt", 0.8, "pT Min"}; + Configurable cMaxPt{"cMaxPt", 4.2, "pT Max"}; + Configurable cNRapBins{"cNRapBins", 20, "N Rapidity Bins"}; + Configurable cMinRap{"cMinRap", -0.5, "Minimum Rapidity"}; + Configurable cMaxRap{"cMaxRap", 0.5, "Maximum Rapidity"}; + Configurable cNPhiBins{"cNPhiBins", 36, "N Phi Bins"}; + Configurable cAnaSecondaries{"cAnaSecondaries", false, "Analysze Secondaries"}; + Configurable cAnaPairs{"cAnaPairs", false, "Analyze Pairs Flag"}; + Configurable cAnaSecondaryPairs{"cAnaSecondaryPairs", false, "Analyze Secondary Pairs Flag"}; + + // Eta/Rap Analysis + Configurable cDoEtaAnalysis{"cDoEtaAnalysis", false, "Eta/Rap Analysis Flag"}; + + // Centrality Axis + ConfigurableAxis cMultBins{"cMultBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 30.0f, 50.f, 80.0f, 100.f}, "Variable Mult-Bins"}; // Histogram Registry. HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -494,163 +1668,322 @@ struct lambdaCorrelationAnalysis { float kmaxrap = 0.; float nphibins = 0.; float kminphi = 0.; - float kmaxphi = 0.; + float kmaxphi = TwoPI; float rapbinwidth = 0.; float phibinwidth = 0.; + float q = 0., e = 0., qinv = 0.; + float cent = 0.; void init(InitContext const&) { - nrapbins = static_cast(cfg_nRapBins); - kminrap = static_cast(cfg_Rap_Min); - kmaxrap = static_cast(cfg_Rap_Max); - nphibins = static_cast(cfg_nPhiBins); - kminphi = static_cast(cfg_Phi_Min); - kmaxphi = static_cast(cfg_Phi_Max); + // 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(cfg_nRapBins) * static_cast(cfg_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 axisCent(cMultBins, "FT0M (%)"); + const AxisSpec axisChMult(200, 0, 200, "N_{ch}"); const AxisSpec axisMult(10, 0, 10, "N_{#Lambda}"); - const AxisSpec axisMass(100, 1.06, 1.16, "Inv Mass (GeV/#it{c}^{2})"); - const AxisSpec axisRap(cfg_nRapBins, cfg_Rap_Min, cfg_Rap_Max, "rap"); - const AxisSpec axisPhi(cfg_nPhiBins, cfg_Phi_Min, cfg_Phi_Max, "#phi (rad)"); - const AxisSpec axisRapPhi(knrapphibins, kminrapphi, kmaxrapphi, "rap #phi"); + const AxisSpec axisMass(100, 1.06, 1.16, "M_{#Lambda} (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})"); // Create Histograms. // Event - histos.add("Event/h1d_posz", "V_{Z} Distribution", kTH1F, {axisPosZ}); - histos.add("Event/h1d_ft0m_mult_percentile", "FT0M (%)", kTH1F, {axisCent}); - histos.add("Event/h1d_lambda_tot_mult", "#Lambda/#bar{#Lambda} - Multiplicity", kTH1I, {axisMult}); - histos.add("Event/h1d_lambda_multiplicity", "#Lambda - Multiplicity", kTH1I, {axisMult}); - histos.add("Event/h1d_antilambda_multiplicity", "#bar{#Lambda} - Multiplicity", kTH1I, {axisMult}); - - // Lambda - histos.add("Lambda/h1d_inv_mass", "M_{p#pi}", kTH1F, {axisMass}); - - // Anti-Lambda - histos.addClone("Lambda/", "AntiLambda/"); + 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/h2f_Mult_vs_Centrality", "N_{ch} vs FT0M(%)", kTH2F, {axisCent, axisChMult}); + histos.add("Event/Reco/h2f_lambda_mult", "#Lambda - Multiplicity", kTH2F, {axisCent, axisMult}); + histos.add("Event/Reco/h2f_antilambda_mult", "#bar{#Lambda} - Multiplicity", kTH2F, {axisCent, axisMult}); + + // Efficiency Histograms + // Single Particle Efficiencies + histos.add("Reco/Primary/Efficiency/h2f_n1_centpt_LaP", "#rho_{1}^{#Lambda}", kTH2F, {axisCent, axisPt}); + histos.add("Reco/Primary/Efficiency/h2f_n1_centpt_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2F, {axisCent, axisPt}); + histos.add("Reco/Primary/Efficiency/h3f_n1_centpteta_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisPt, axisEta}); + histos.add("Reco/Primary/Efficiency/h3f_n1_centpteta_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPt, axisEta}); + histos.add("Reco/Primary/Efficiency/h3f_n1_centptrap_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisPt, axisRap}); + histos.add("Reco/Primary/Efficiency/h3f_n1_centptrap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPt, axisRap}); + + // Single and Two Particle Densities + // 1D Histograms + histos.add("Reco/Primary/h3f_n1_centmasspt_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisMass, axisPt}); + histos.add("Reco/Primary/h3f_n1_centmasspt_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisMass, axisPt}); + histos.add("Reco/Primary/h2f_n1_pt_LaP", "#rho_{1}^{#Lambda}", kTH2F, {axisCent, axisPt}); + histos.add("Reco/Primary/h2f_n1_pt_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2F, {axisCent, axisPt}); + histos.add("Reco/Primary/h2f_n1_eta_LaP", "#rho_{1}^{#Lambda}", kTH2F, {axisCent, axisEta}); + histos.add("Reco/Primary/h2f_n1_eta_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2F, {axisCent, axisEta}); + histos.add("Reco/Primary/h2f_n1_rap_LaP", "#rho_{1}^{#Lambda}", kTH2F, {axisCent, axisRap}); + histos.add("Reco/Primary/h2f_n1_rap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2F, {axisCent, axisRap}); + histos.add("Reco/Primary/h2f_n1_phi_LaP", "#rho_{1}^{#Lambda}", kTH2F, {axisCent, axisPhi}); + histos.add("Reco/Primary/h2f_n1_phi_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2F, {axisCent, axisPhi}); + + // rho1 for R2 RapPhi + histos.add("Reco/Primary/h3f_n1_rapphi_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisRap, axisPhi}); + histos.add("Reco/Primary/h3f_n1_rapphi_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisRap, axisPhi}); + + // rho1 for Q_{inv} + histos.add("Reco/Primary/h3f_n1_pteta_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisPt, axisEta}); + histos.add("Reco/Primary/h3f_n1_pteta_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPt, axisEta}); + + // Clone Singles Primary/Secondary Histogram + if (cAnaSecondaries) { + histos.addClone("Reco/Primary/", "Reco/Secondary/"); + } - // single and two particle densities - histos.add("Lambda_Mass/h2d_n1_LaP", "#rho_{1}^{#Lambda}", kTH2D, {axisRap, axisPhi}); - histos.add("Lambda_Mass/h2d_n1_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2D, {axisRap, axisPhi}); - histos.add("Lambda_Mass/h2d_n2_LaP_LaM", "#rho_{2}^{#Lambda - #bar{#Lambda}}", kTH2D, {axisRapPhi, axisRapPhi}); - histos.add("Lambda_Mass/h2d_n2_LaP_LaP", "#rho_{2}^{#Lambda - #Lambda}", kTH2D, {axisRapPhi, axisRapPhi}); - histos.add("Lambda_Mass/h2d_n2_LaM_LaM", "#rho_{2}^{#bar{#Lambda} - #bar{#Lambda}}", kTH2D, {axisRapPhi, axisRapPhi}); + if (cAnaPairs) { + // rho2 for numerator of R2 + histos.add("Reco/PP/h3f_n2_raprap_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH3F, {axisCent, axisRap, axisRap}); + histos.add("Reco/PP/h3f_n2_raprap_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH3F, {axisCent, axisRap, axisRap}); + histos.add("Reco/PP/h3f_n2_raprap_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH3F, {axisCent, axisRap, axisRap}); + histos.add("Reco/PP/h3f_n2_phiphi_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH3F, {axisCent, axisPhi, axisPhi}); + histos.add("Reco/PP/h3f_n2_phiphi_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH3F, {axisCent, axisPhi, axisPhi}); + histos.add("Reco/PP/h3f_n2_phiphi_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH3F, {axisCent, axisPhi, axisPhi}); + + // rho2 for R2 Rap1Phi1Rap2Phi2 + histos.add("Reco/PP/h3f_n2_rapphi_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); + histos.add("Reco/PP/h3f_n2_rapphi_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); + histos.add("Reco/PP/h3f_n2_rapphi_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); + + // rho2 for R2 Qinv + histos.add("Reco/PP/h2f_n2_qinv_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH2F, {axisCent, axisQinv}); + histos.add("Reco/PP/h2f_n2_qinv_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH2F, {axisCent, axisQinv}); + histos.add("Reco/PP/h2f_n2_qinv_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH2F, {axisCent, axisQinv}); + + // Clone Pairs Histograms + if (cAnaSecondaryPairs) { + histos.addClone("Reco/PP/", "Reco/PS/"); + histos.addClone("Reco/PP/", "Reco/SP/"); + histos.addClone("Reco/PP/", "Reco/SS/"); + } + } - histos.addClone("Lambda_Mass/", "Lambda_Right/"); - histos.addClone("Lambda_Mass/", "Lambda_Left/"); + // MCGen + if (doprocessMCGen) { + histos.addClone("Event/Reco/", "Event/McGen/"); + histos.addClone("Reco/", "McGen/"); + } } - template + template void fillPairHistos(U& p1, U& p2) { + static constexpr std::string_view SubDirRecGen[] = {"Reco/", "McGen/"}; + static constexpr std::string_view SubDirPrmScd[] = {"PP/", "PS/", "SP/", "SS/"}; + static constexpr std::string_view SubDirHist[] = {"LaP_LaM", "LaP_LaP", "LaM_LaM"}; - static constexpr std::string_view sub_dir_type[] = {"Lambda_Mass/", "Lambda_Left/", "Lambda_Right/"}; - static constexpr std::string_view sub_dir_hist[] = {"h2d_n2_LaP_LaM", "h2d_n2_LaP_LaP", "h2d_n2_LaM_LaM"}; + float rap1 = (cDoEtaAnalysis) ? p1.eta() : p1.rap(); + float rap2 = (cDoEtaAnalysis) ? p2.eta() : p2.rap(); - int rapbin1 = static_cast((p1.rap() - kminrap) / rapbinwidth); - int rapbin2 = static_cast((p2.rap() - kminrap) / rapbinwidth); + 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(SubDirPrmScd[psp]) + HIST("h3f_n2_raprap_") + HIST(SubDirHist[part_pair]), cent, rap1, rap2, corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[psp]) + HIST("h3f_n2_phiphi_") + HIST(SubDirHist[part_pair]), cent, 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(sub_dir_type[mass_win]) + HIST(sub_dir_hist[part_pair]), rapphix + 0.5, rapphiy + 0.5); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[psp]) + HIST("h3f_n2_rapphi_") + HIST(SubDirHist[part_pair]), cent, 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(SubDirPrmScd[psp]) + HIST("h2f_n2_qinv_") + HIST(SubDirHist[part_pair]), cent, qinv, corfac); } - template + template void analyzeSingles(T const& tracks) { + static constexpr std::string_view SubDirRecGen[] = {"Reco/", "McGen/"}; + static constexpr std::string_view SubDirPrmScd[] = {"Primary/", "Secondary/"}; + static constexpr std::string_view SubDirHist[] = {"LaP", "LaM"}; - static constexpr std::string_view sub_dir_part[] = {"Lambda/", "AntiLambda/"}; - static constexpr std::string_view sub_dir_mass_win[] = {"Lambda_Mass/", "Lambda_Left/", "Lambda_Right/"}; - static constexpr std::string_view sub_dir_hist[] = {"h2d_n1_LaP", "h2d_n1_LaM"}; + int ntrk = 0; for (auto const& track : tracks) { - histos.fill(HIST(sub_dir_part[part]) + HIST("h1d_inv_mass"), track.mass()); - histos.fill(HIST(sub_dir_mass_win[masswin]) + HIST(sub_dir_hist[part]), track.rap(), track.phi()); + // count tracks + ++ntrk; + + // Efficiency Plots + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("Efficiency/h2f_n1_centpt_") + HIST(SubDirHist[part]), cent, track.pt()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("Efficiency/h3f_n1_centpteta_") + HIST(SubDirHist[part]), cent, track.pt(), track.eta()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("Efficiency/h3f_n1_centptrap_") + HIST(SubDirHist[part]), cent, track.pt(), track.rap()); + + // QA Plots + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("h3f_n1_centmasspt_") + HIST(SubDirHist[part]), cent, track.mass(), track.pt()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("h2f_n1_pt_") + HIST(SubDirHist[part]), cent, track.pt(), track.corrFact()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("h2f_n1_eta_") + HIST(SubDirHist[part]), cent, track.eta(), track.corrFact()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("h2f_n1_phi_") + HIST(SubDirHist[part]), cent, track.phi(), track.corrFact()); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("h2f_n1_rap_") + HIST(SubDirHist[part]), cent, track.rap(), track.corrFact()); + + // Rho1 for N1RapPhi + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("h3f_n1_rapphi_") + HIST(SubDirHist[part]), cent, track.rap(), track.phi(), track.corrFact()); + + // Rho1 for Q_{inv} Bkg Estimation + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST(SubDirPrmScd[pst]) + HIST("h3f_n1_pteta_") + HIST(SubDirHist[part]), cent, track.pt(), track.eta(), track.corrFact()); + } + + // fill multiplicity histograms + if (ntrk != 0) { + if (part == kLambda) { + histos.fill(HIST("Event/") + HIST(SubDirRecGen[rec_gen]) + HIST("h2f_lambda_mult"), cent, ntrk); + } else { + histos.fill(HIST("Event/") + HIST(SubDirRecGen[rec_gen]) + HIST("h2f_antilambda_mult"), cent, ntrk); + } } } - template + 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) { - if (samelambda && (trk_1.index() == trk_2.index()) && (trk_1.postrackid() == trk_2.postrackid()) && (trk_1.negtrackid() == trk_2.negtrackid())) { + // check for same index for Lambda-Lambda / AntiLambda-AntiLambda + if (samelambda && ((trk_1.index() == trk_2.index()))) { continue; } - fillPairHistos(trk_1, trk_2); + fillPairHistos(trk_1, trk_2); } } } - using Lambda_Collisions = aod::LambdaCollisions; - using Lambda_Tracks = aod::LambdaTracks; + using LambdaCollisions = aod::LambdaCollisions; + using LambdaTracks = soa::Join; SliceCache cache; + Partition partPrimLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kLambda) && (aod::lambdatrackext::trueLambdaFlag == true) && (aod::lambdatrack::v0PrmScd == (int8_t)kPrimary); + Partition partPrimAntiLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kAntiLambda) && (aod::lambdatrackext::trueLambdaFlag == true) && (aod::lambdatrack::v0PrmScd == (int8_t)kPrimary); + Partition partSecdLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kLambda) && (aod::lambdatrackext::trueLambdaFlag == true) && (aod::lambdatrack::v0PrmScd == (int8_t)kSecondary); + Partition partSecdAntiLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kAntiLambda) && (aod::lambdatrackext::trueLambdaFlag == true) && (aod::lambdatrack::v0PrmScd == (int8_t)kSecondary); - Partition part_lambda_tracks = (aod::lambdatrack::v0type == (int8_t)kLambda && aod::lambdatrack::masswindow == (int8_t)kCentralWindow); - Partition part_anti_lambda_tracks = (aod::lambdatrack::v0type == (int8_t)kAntiLambda && aod::lambdatrack::masswindow == (int8_t)kCentralWindow); + 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()); + histos.fill(HIST("Event/Reco/h2f_Mult_vs_Centrality"), collision.cent(), collision.mult()); - Partition part_lambda_tracks_left_masswin = (aod::lambdatrack::v0type == (int8_t)kLambda && aod::lambdatrack::masswindow == (int8_t)kLeftWindow); - Partition part_anti_lambda_tracks_left_masswin = (aod::lambdatrack::v0type == (int8_t)kAntiLambda && aod::lambdatrack::masswindow == (int8_t)kLeftWindow); + cent = collision.cent(); - Partition part_lambda_tracks_right_masswin = (aod::lambdatrack::v0type == (int8_t)kLambda && aod::lambdatrack::masswindow == (int8_t)kRightWindow); - Partition part_anti_lambda_tracks_right_masswin = (aod::lambdatrack::v0type == (int8_t)kAntiLambda && aod::lambdatrack::masswindow == (int8_t)kRightWindow); + auto lambdaPrimTracks = partPrimLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + auto antiLambdaPrimTracks = partPrimAntiLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + auto lambdaSecdTracks = partSecdLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + auto antiLambdaSecdTracks = partSecdAntiLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); - void process(Lambda_Collisions::iterator const& collision, Lambda_Tracks const&) - { + analyzeSingles(lambdaPrimTracks); + analyzeSingles(antiLambdaPrimTracks); + + if (cAnaSecondaries) { + analyzeSingles(lambdaSecdTracks); + analyzeSingles(antiLambdaSecdTracks); + } + + if (cAnaPairs) { + // Primary Pairs Only + analyzePairs(lambdaPrimTracks, antiLambdaPrimTracks); + analyzePairs(lambdaPrimTracks, lambdaPrimTracks); + analyzePairs(antiLambdaPrimTracks, antiLambdaPrimTracks); + + // Secondary Pairs + if (cAnaSecondaryPairs) { + analyzePairs(lambdaPrimTracks, antiLambdaSecdTracks); + analyzePairs(lambdaPrimTracks, lambdaSecdTracks); + analyzePairs(antiLambdaPrimTracks, antiLambdaSecdTracks); + analyzePairs(lambdaSecdTracks, antiLambdaPrimTracks); + analyzePairs(lambdaSecdTracks, lambdaPrimTracks); + analyzePairs(antiLambdaSecdTracks, antiLambdaPrimTracks); + analyzePairs(lambdaSecdTracks, antiLambdaSecdTracks); + analyzePairs(lambdaSecdTracks, lambdaSecdTracks); + analyzePairs(antiLambdaSecdTracks, antiLambdaSecdTracks); + } + } + } - histos.fill(HIST("Event/h1d_posz"), collision.posZ()); - histos.fill(HIST("Event/h1d_ft0m_mult_percentile"), collision.cent()); + PROCESS_SWITCH(LambdaR2Correlation, processDataReco, "Process for Data and MCReco", true); - auto lambda_tracks = part_lambda_tracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); - auto anti_lambda_tracks = part_anti_lambda_tracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + using LambdaMcGenCollisions = aod::LambdaMcGenCollisions; + using LambdaMcGenTracks = aod::LambdaMcGenTracks; - auto lambda_tracks_left = part_lambda_tracks_left_masswin->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); - auto anti_lambda_tracks_left = part_anti_lambda_tracks_left_masswin->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + SliceCache cachemc; + Partition partMcPrimLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kLambda) && (aod::lambdatrack::v0PrmScd == (int8_t)kPrimary); + Partition partMcPrimAntiLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kAntiLambda) && (aod::lambdatrack::v0PrmScd == (int8_t)kPrimary); + Partition partMcSecdLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kLambda) && (aod::lambdatrack::v0PrmScd == (int8_t)kSecondary); + Partition partMcSecdAntiLambdaTracks = (aod::lambdatrack::v0Type == (int8_t)kAntiLambda) && (aod::lambdatrack::v0PrmScd == (int8_t)kSecondary); - auto lambda_tracks_right = part_lambda_tracks_right_masswin->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); - auto anti_lambda_tracks_right = part_anti_lambda_tracks_right_masswin->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); + 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()); + histos.fill(HIST("Event/McGen/h2f_Mult_vs_Centrality"), mcgencol.cent(), mcgencol.mult()); - analyzeSingles(lambda_tracks); - analyzeSingles(lambda_tracks_left); - analyzeSingles(lambda_tracks_right); + cent = mcgencol.cent(); - analyzeSingles(anti_lambda_tracks); - analyzeSingles(anti_lambda_tracks_left); - analyzeSingles(anti_lambda_tracks_right); + auto lambdaPrimTracks = partMcPrimLambdaTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cachemc); + auto antiLambdaPrimTracks = partMcPrimAntiLambdaTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cachemc); + auto lambdaSecdTracks = partMcSecdLambdaTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cachemc); + auto antiLambdaSecdTracks = partMcSecdAntiLambdaTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cachemc); - analyzePairs(lambda_tracks, anti_lambda_tracks); - analyzePairs(lambda_tracks_left, anti_lambda_tracks_left); - analyzePairs(lambda_tracks_right, anti_lambda_tracks_right); + analyzeSingles(lambdaPrimTracks); + analyzeSingles(antiLambdaPrimTracks); - analyzePairs(lambda_tracks, lambda_tracks); - analyzePairs(lambda_tracks_left, lambda_tracks_left); - analyzePairs(lambda_tracks_right, lambda_tracks_right); + if (cAnaSecondaries) { + analyzeSingles(lambdaSecdTracks); + analyzeSingles(antiLambdaSecdTracks); + } - analyzePairs(anti_lambda_tracks, anti_lambda_tracks); - analyzePairs(anti_lambda_tracks_left, anti_lambda_tracks_left); - analyzePairs(anti_lambda_tracks_right, anti_lambda_tracks_right); + if (cAnaPairs) { + // Primary Pairs Only + analyzePairs(lambdaPrimTracks, antiLambdaPrimTracks); + analyzePairs(lambdaPrimTracks, lambdaPrimTracks); + analyzePairs(antiLambdaPrimTracks, antiLambdaPrimTracks); + + // Secondary Pairs + if (cAnaSecondaryPairs) { + analyzePairs(lambdaPrimTracks, antiLambdaSecdTracks); + analyzePairs(lambdaPrimTracks, lambdaSecdTracks); + analyzePairs(antiLambdaPrimTracks, antiLambdaSecdTracks); + analyzePairs(lambdaSecdTracks, antiLambdaPrimTracks); + analyzePairs(lambdaSecdTracks, lambdaPrimTracks); + analyzePairs(antiLambdaSecdTracks, antiLambdaPrimTracks); + analyzePairs(lambdaSecdTracks, antiLambdaSecdTracks); + analyzePairs(lambdaSecdTracks, lambdaSecdTracks); + analyzePairs(antiLambdaSecdTracks, antiLambdaSecdTracks); + } + } } + + PROCESS_SWITCH(LambdaR2Correlation, processMCGen, "Process for MC Generated", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/longRangeDihadronCor.cxx b/PWGCF/TwoParticleCorrelations/Tasks/longRangeDihadronCor.cxx new file mode 100644 index 00000000000..625317caa0b --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/longRangeDihadronCor.cxx @@ -0,0 +1,1182 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file longRangeDihadronCor.cxx +/// \brief long range di-hadron correlation for O-O, Pb-Pb collisions +/// \author Zhiyong Lu (zhiyong.lu@cern.ch), Joachim Hansen (joachim.hansen@cern.ch) +/// \since Sep/10/2025 + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWCumulant.h" +#include "PWGCF/GenericFramework/Core/GFWPowerArray.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/MathConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "FT0Base/Geometry.h" +#include "FV0Base/Geometry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include "TF1.h" +#include "TRandom3.h" +#include + +#include +#include + +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}; +// template for labelled array +static constexpr float LongArrayFloat[3][20] = {{1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {2.1, 2.2, 2.3, -2.1, -2.2, -2.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {3.1, 3.2, 3.3, -3.1, -3.2, -3.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}}; + +struct LongRangeDihadronCor { + Service ccdb; + o2::aod::ITSResponse itsResponse; + + O2_DEFINE_CONFIGURABLE(cfgCutVtxZ, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "minimum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 10.0f, "maximum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta cut") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, float, 50.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCCrossedRows, float, 70.0f, "minimum TPC crossed rows") + 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(cfgSelCollByNch, bool, true, "Select collisions by Nch or centrality") + O2_DEFINE_CONFIGURABLE(cfgCutMultMin, int, 0, "Minimum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgCutMultMax, int, 10, "Maximum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgCutCentMin, float, 60.0f, "Minimum centrality for collision") + O2_DEFINE_CONFIGURABLE(cfgCutCentMax, float, 80.0f, "Maximum centrality for collision") + O2_DEFINE_CONFIGURABLE(cfgMixEventNumMin, int, 5, "Minimum number of events to mix") + O2_DEFINE_CONFIGURABLE(cfgSampleSize, double, 10, "Sample size for mixed event") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") + O2_DEFINE_CONFIGURABLE(cfgCentTableUnavailable, bool, false, "if a dataset does not provide centrality information") + 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(cfgEvSelkNoITSROFrameBorder, bool, false, "reject events at ITS ROF border") + O2_DEFINE_CONFIGURABLE(cfgEvSelkNoTimeFrameBorder, bool, false, "reject events at TF border") + 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, 2000, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyLow, int, 0, "Low cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgCentralityWeight, std::string, "", "CCDB path to centrality weight object") + O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, bool, false, "Use local efficiency object") + O2_DEFINE_CONFIGURABLE(cfgUseEventWeights, bool, false, "Use event weights for mixed event") + O2_DEFINE_CONFIGURABLE(cfgDrawEtaPhiDis, bool, false, "draw eta-phi distribution for detectors in used") + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgMultCentHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 10.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCentLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultT0CCutEnabled, bool, false, "Enable Global multiplicity vs T0C centrality cut") + Configurable> cfgMultT0CCutPars{"cfgMultT0CCutPars", std::vector{143.04, -4.58368, 0.0766055, -0.000727796, 2.86153e-06, 23.3108, -0.36304, 0.00437706, -4.717e-05, 1.98332e-07}, "Global multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultPVT0CCutEnabled, bool, false, "Enable PV multiplicity vs T0C centrality cut") + Configurable> cfgMultPVT0CCutPars{"cfgMultPVT0CCutPars", std::vector{195.357, -6.15194, 0.101313, -0.000955828, 3.74793e-06, 30.0326, -0.43322, 0.00476265, -5.11206e-05, 2.13613e-07}, "PV multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultMultPVHighCutFunction, std::string, "[0]+[1]*x + 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultPVLowCutFunction, std::string, "[0]+[1]*x - 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCutEnabled, bool, false, "Enable global multiplicity vs PV multiplicity cut") + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", std::vector{-0.140809, 0.734344, 2.77495, 0.0165935}, "PV multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultMultV0AHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 4.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ALowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ACutEnabled, bool, false, "Enable global multiplicity vs V0A multiplicity cut") + Configurable> cfgMultMultV0ACutPars{"cfgMultMultV0ACutPars", std::vector{534.893, 184.344, 0.423539, -0.00331436, 5.34622e-06, 871.239, 53.3735, -0.203528, 0.000122758, 5.41027e-07}, "Global multiplicity vs V0A multiplicity cut parameter values"}; + std::vector multT0CCutPars; + std::vector multPVT0CCutPars; + std::vector multGlobalPVCutPars; + std::vector multMultV0ACutPars; + TF1* fMultPVT0CCutLow = nullptr; + TF1* fMultPVT0CCutHigh = nullptr; + TF1* fMultT0CCutLow = nullptr; + TF1* fMultT0CCutHigh = nullptr; + TF1* fMultGlobalPVCutLow = nullptr; + TF1* fMultGlobalPVCutHigh = nullptr; + TF1* fMultMultV0ACutLow = nullptr; + TF1* fMultMultV0ACutHigh = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + } cfgFuncParas; + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgUseItsPID, bool, true, "Use ITS PID for particle identification") + O2_DEFINE_CONFIGURABLE(cfgPIDParticle, int, 0, "1 = pion, 2 = kaon, 3 = proton, 4 = kshort, 5 = lambda, 6 = phi, 0 for no PID") + O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5f, "Minimum pt to use TOF N-sigma") + Configurable> nSigmas{"nSigmas", {LongArrayFloat[0], 3, 6, {"TPC", "TOF", "ITS"}, {"pos_pi", "pos_ka", "pos_pr", "neg_pi", "neg_ka", "neg_pr"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; + } cfgPIDConfig; + + SliceCache cache; + + ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 10, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260}, "multiplicity axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt axis for histograms"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; + ConfigurableAxis axisDeltaEtaTpcFt0a{"axisDeltaEtaTpcFt0a", {32, -5.8, -2.6}, "delta eta axis, -5.8~-2.6 for TPC-FT0A,"}; + ConfigurableAxis axisDeltaEtaTpcFt0c{"axisDeltaEtaTpcFt0c", {32, 1.2, 4.2}, "delta eta axis, 1.2~4.2 for TPC-FT0C"}; + ConfigurableAxis axisDeltaEtaFt0aFt0c{"axisDeltaEtaFt0aFt0c", {32, -1.5, 3.0}, "delta eta axis"}; + ConfigurableAxis axisPtTrigger{"axisPtTrigger", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt trigger axis for histograms"}; + ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt associated axis for histograms"}; + ConfigurableAxis axisVtxMix{"axisVtxMix", {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 axisMultMix{"axisMultMix", {VARIABLE_WIDTH, 0, 10, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260}, "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.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt axis for efficiency histograms"}; + ConfigurableAxis axisAmplitudeFt0a{"axisAmplitudeFt0a", {5000, 0, 1000}, "FT0A amplitude"}; + ConfigurableAxis axisChannelFt0aAxis{"axisChannelFt0aAxis", {96, 0.0, 96.0}, "FT0A channel"}; + + Configurable cfgGainEqPath{"cfgGainEqPath", "Analysis/EventPlane/GainEq", "CCDB path for gain equalization constants"}; + Configurable cfgCorrLevel{"cfgCorrLevel", 1, "calibration step: 0 = no corr, 1 = gain corr"}; + ConfigurableAxis cfgaxisFITamp{"cfgaxisFITamp", {1000, 0, 5000}, ""}; + AxisSpec axisFit{cfgaxisFITamp, "fit amplitude"}; + AxisSpec axisChID = {220, 0, 220}; + // make the filters and cuts. + Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVtxZ); + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == static_cast(true))) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + using FilteredCollisions = soa::Filtered>; + using FilteredTracks = soa::Filtered>; + + // FT0 geometry + o2::ft0::Geometry ft0Det; + static constexpr uint64_t Ft0IndexA = 96; + std::vector* offsetFT0; + std::vector cstFT0RelGain{}; + + // Corrections + TH3D* mEfficiency = nullptr; + TH1D* mCentralityWeight = nullptr; + bool correctionsLoaded = false; + + // Define the outputs + OutputObj sameTpcFt0a{"sameEvent_TPC_FT0A"}; + OutputObj mixedTpcFt0a{"mixedEvent_TPC_FT0A"}; + OutputObj sameTpcFt0c{"sameEvent_TPC_FT0C"}; + OutputObj mixedTpcFt0c{"mixedEvent_TPC_FT0C"}; + OutputObj sameFt0aFt0c{"sameEvent_FT0A_FT0C"}; + OutputObj mixedFt0aFt0c{"mixedEvent_FT0A_FT0C"}; + HistogramRegistry registry{"registry"}; + + // define global variables + TRandom3* gRandom = new TRandom3(); + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + // Count the total number of enum + kCount_CentEstimators + }; + enum EventType { + SameEvent = 1, + MixedEvent = 3 + }; + enum FITIndex { + kFT0A = 0, + kFT0C = 1 + }; + enum ParticleNsigma { + kPionUp = 0, + kKaonUp, + kProtonUp, + kPionLow, + kKaonLow, + kProtonLow + }; + enum PIDIndex { + kCharged = 0, + kPions, + kKaons, + kProtons, + kK0, + kLambda, + kPhi + }; + enum DetectorType { + kTPC = 0, + kTOF, + kITS + }; + std::array tofNsigmaCut; + std::array itsNsigmaCut; + std::array tpcNsigmaCut; + + void init(InitContext&) + { + if (cfgCentTableUnavailable && !cfgSelCollByNch) { + LOGF(fatal, "Centrality table is unavailable, cannot select collisions by centrality"); + } + const AxisSpec axisPhi{72, 0.0, constants::math::TwoPI, "#varphi"}; + const AxisSpec axisEta{40, -1., 1., "#eta"}; + const AxisSpec axisEtaFull{90, -4., 5., "#eta"}; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + LOGF(info, "Starting init"); + + // filling tpc nSigmas array + tpcNsigmaCut[kPionUp] = cfgPIDConfig.nSigmas->getData()[kTPC][kPionUp]; + tpcNsigmaCut[kKaonUp] = cfgPIDConfig.nSigmas->getData()[kTPC][kKaonUp]; + tpcNsigmaCut[kProtonUp] = cfgPIDConfig.nSigmas->getData()[kTPC][kProtonUp]; + tpcNsigmaCut[kPionLow] = cfgPIDConfig.nSigmas->getData()[kTPC][kPionLow]; + tpcNsigmaCut[kKaonLow] = cfgPIDConfig.nSigmas->getData()[kTPC][kKaonLow]; + tpcNsigmaCut[kProtonLow] = cfgPIDConfig.nSigmas->getData()[kTPC][kProtonLow]; + // filling tof nSigmas array + tofNsigmaCut[kPionUp] = cfgPIDConfig.nSigmas->getData()[kTOF][kPionUp]; + tofNsigmaCut[kKaonUp] = cfgPIDConfig.nSigmas->getData()[kTOF][kKaonUp]; + tofNsigmaCut[kProtonUp] = cfgPIDConfig.nSigmas->getData()[kTOF][kProtonUp]; + tofNsigmaCut[kPionLow] = cfgPIDConfig.nSigmas->getData()[kTOF][kPionLow]; + tofNsigmaCut[kKaonLow] = cfgPIDConfig.nSigmas->getData()[kTOF][kKaonLow]; + tofNsigmaCut[kProtonLow] = cfgPIDConfig.nSigmas->getData()[kTOF][kProtonLow]; + // filling its nSigmas array + itsNsigmaCut[kPionUp] = cfgPIDConfig.nSigmas->getData()[kITS][kPionUp]; + itsNsigmaCut[kKaonUp] = cfgPIDConfig.nSigmas->getData()[kITS][kKaonUp]; + itsNsigmaCut[kProtonUp] = cfgPIDConfig.nSigmas->getData()[kITS][kProtonUp]; + itsNsigmaCut[kPionLow] = cfgPIDConfig.nSigmas->getData()[kITS][kPionLow]; + itsNsigmaCut[kKaonLow] = cfgPIDConfig.nSigmas->getData()[kITS][kKaonLow]; + itsNsigmaCut[kProtonLow] = cfgPIDConfig.nSigmas->getData()[kITS][kProtonLow]; + + // Event Counter + if ((doprocessSameTpcFt0a || doprocessSameTpcFt0c || doprocessSameFt0aFt0c) && cfgUseAdditionalEventCut) { + registry.add("hEventCountSpecific", "Number of Event;; Count", {HistType::kTH1D, {{12, 0, 12}}}); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(1, "after sel8"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(2, "kNoSameBunchPileup"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(3, "kNoITSROFrameBorder"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(4, "kNoTimeFrameBorder"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(5, "kIsGoodZvtxFT0vsPV"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(6, "kNoCollInTimeRangeStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(7, "kIsGoodITSLayersAll"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(8, "kNoCollInRofStandard"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(9, "kNoHighMultCollInPrevRof"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(10, "occupancy"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(11, "MultCorrelation"); + registry.get(HIST("hEventCountSpecific"))->GetXaxis()->SetBinLabel(12, "cfgEvSelV0AT0ACut"); + } + + if (cfgEvSelMultCorrelation) { + cfgFuncParas.multT0CCutPars = cfgFuncParas.cfgMultT0CCutPars; + cfgFuncParas.multPVT0CCutPars = cfgFuncParas.cfgMultPVT0CCutPars; + cfgFuncParas.multGlobalPVCutPars = cfgFuncParas.cfgMultGlobalPVCutPars; + cfgFuncParas.multMultV0ACutPars = cfgFuncParas.cfgMultMultV0ACutPars; + cfgFuncParas.fMultPVT0CCutLow = new TF1("fMultPVT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutLow->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultPVT0CCutHigh = new TF1("fMultPVT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutHigh->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + + cfgFuncParas.fMultT0CCutLow = new TF1("fMultT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutLow->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultT0CCutHigh = new TF1("fMultT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutHigh->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + + cfgFuncParas.fMultGlobalPVCutLow = new TF1("fMultGlobalPVCutLow", cfgFuncParas.cfgMultMultPVLowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutLow->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultGlobalPVCutHigh = new TF1("fMultGlobalPVCutHigh", cfgFuncParas.cfgMultMultPVHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutHigh->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + + cfgFuncParas.fMultMultV0ACutLow = new TF1("fMultMultV0ACutLow", cfgFuncParas.cfgMultMultV0ALowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutLow->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fMultMultV0ACutHigh = new TF1("fMultMultV0ACutHigh", cfgFuncParas.cfgMultMultV0AHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutHigh->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + + cfgFuncParas.fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + cfgFuncParas.fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + cfgFuncParas.fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + cfgFuncParas.fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + std::string hCentTitle = "Centrality distribution, Estimator " + std::to_string(cfgCentEstimator); + // Make histograms to check the distributions after cuts + if (doprocessSameTpcFt0a || doprocessSameTpcFt0c || doprocessSameFt0aFt0c) { + registry.add("Phi", "Phi", {HistType::kTH1D, {axisPhi}}); + registry.add("Eta", "Eta", {HistType::kTH1D, {axisEta}}); + registry.add("EtaCorrected", "EtaCorrected", {HistType::kTH1D, {axisEta}}); + registry.add("pT", "pT", {HistType::kTH1D, {axisPtTrigger}}); + registry.add("pTCorrected", "pTCorrected", {HistType::kTH1D, {axisPtTrigger}}); + registry.add("Nch", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); + registry.add("Nch_used", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); // histogram to see how many events are in the same and mixed event + registry.add("Centrality", hCentTitle.c_str(), {HistType::kTH1D, {{100, 0, 100}}}); + registry.add("CentralityWeighted", hCentTitle.c_str(), {HistType::kTH1D, {{100, 0, 100}}}); + registry.add("Centrality_used", hCentTitle.c_str(), {HistType::kTH1D, {{100, 0, 100}}}); // histogram to see how many events are in the same and mixed event + registry.add("zVtx", "zVtx", {HistType::kTH1D, {axisVertex}}); + registry.add("zVtx_used", "zVtx_used", {HistType::kTH1D, {axisVertex}}); + registry.add("FT0Amp", "", {HistType::kTH2F, {axisChID, axisFit}}); + registry.add("FT0AmpCorrect", "", {HistType::kTH2F, {axisChID, axisFit}}); + if (cfgDrawEtaPhiDis) { + registry.add("EtaPhi", "", {HistType::kTH2F, {axisEtaFull, axisPhi}}); + } + } + if (doprocessSameTpcFt0a) { + registry.add("deltaEta_deltaPhi_same_TPC_FT0A", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFt0a}}); // check to see the delta eta and delta phi distribution + registry.add("deltaEta_deltaPhi_mixed_TPC_FT0A", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFt0a}}); + registry.add("Assoc_amp_same_TPC_FT0A", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Assoc_amp_mixed_TPC_FT0A", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Trig_hist_TPC_FT0A", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + } + if (doprocessSameTpcFt0c) { + registry.add("deltaEta_deltaPhi_same_TPC_FT0C", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFt0c}}); // check to see the delta eta and delta phi distribution + registry.add("deltaEta_deltaPhi_mixed_TPC_FT0C", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaTpcFt0c}}); + registry.add("Assoc_amp_same_TPC_FT0C", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Assoc_amp_mixed_TPC_FT0C", "", {HistType::kTH2D, {axisChannelFt0aAxis, axisAmplitudeFt0a}}); + registry.add("Trig_hist_TPC_FT0C", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + } + if (doprocessSameFt0aFt0c) { + registry.add("deltaEta_deltaPhi_same_FT0A_FT0C", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaFt0aFt0c}}); // check to see the delta eta and delta phi distribution + registry.add("deltaEta_deltaPhi_mixed_FT0A_FT0C", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEtaFt0aFt0c}}); + registry.add("Trig_hist_FT0A_FT0C", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + } + + registry.add("eventcount", "bin", {HistType::kTH1F, {{4, 0, 4, "bin"}}}); // histogram to see how many events are in the same and mixed event + + LOGF(info, "Initializing correlation container"); + std::vector corrAxisTpcFt0a = {{axisSample, "Sample"}, + {axisVertex, "z-vtx (cm)"}, + {axisPtTrigger, "p_{T} (GeV/c)"}, + {axisPtAssoc, "p_{T} (GeV/c)"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEtaTpcFt0a, "#Delta#eta"}}; + std::vector effAxis = { + {axisEtaEfficiency, "#eta"}, + {axisPtEfficiency, "p_{T} (GeV/c)"}, + {axisVertexEfficiency, "z-vtx (cm)"}, + }; + std::vector userAxis; + std::vector corrAxisTpcFt0c = {{axisSample, "Sample"}, + {axisVertex, "z-vtx (cm)"}, + {axisPtTrigger, "p_{T} (GeV/c)"}, + {axisPtAssoc, "p_{T} (GeV/c)"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEtaTpcFt0c, "#Delta#eta"}}; + std::vector corrAxisFt0aFt0c = {{axisSample, "Sample"}, + {axisVertex, "z-vtx (cm)"}, + {axisPtTrigger, "p_{T} (GeV/c)"}, + {axisPtAssoc, "p_{T} (GeV/c)"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEtaFt0aFt0c, "#Delta#eta"}}; + + if (doprocessSameTpcFt0a) { + sameTpcFt0a.setObject(new CorrelationContainer("sameEvent_TPC_FT0A", "sameEvent_TPC_FT0A", corrAxisTpcFt0a, effAxis, userAxis)); + mixedTpcFt0a.setObject(new CorrelationContainer("mixedEvent_TPC_FT0A", "mixedEvent_TPC_FT0A", corrAxisTpcFt0a, effAxis, userAxis)); + } + if (doprocessSameTpcFt0c) { + sameTpcFt0c.setObject(new CorrelationContainer("sameEvent_TPC_FT0C", "sameEvent_TPC_FT0C", corrAxisTpcFt0c, effAxis, userAxis)); + mixedTpcFt0c.setObject(new CorrelationContainer("mixedEvent_TPC_FT0C", "mixedEvent_TPC_FT0C", corrAxisTpcFt0c, effAxis, userAxis)); + } + if (doprocessSameFt0aFt0c) { + sameFt0aFt0c.setObject(new CorrelationContainer("sameEvent_FT0A_FT0C", "sameEvent_FT0A_FT0C", corrAxisFt0aFt0c, effAxis, userAxis)); + mixedFt0aFt0c.setObject(new CorrelationContainer("mixedEvent_FT0A_FT0C", "mixedEvent_FT0A_FT0C", corrAxisFt0aFt0c, effAxis, userAxis)); + } + + LOGF(info, "End of init"); + } + + double getPhiFT0(uint64_t chno, int i) + { + // offsetFT0[0]: FT0A, offsetFT0[1]: FT0C + if (i > 1 || i < 0) { + LOGF(fatal, "kFIT Index %d out of range", i); + } + ft0Det.calculateChannelCenter(); + auto chPos = ft0Det.getChannelCenter(chno); + return RecoDecay::phi(chPos.X() + (*offsetFT0)[i].getX(), chPos.Y() + (*offsetFT0)[i].getY()); + } + + double getEtaFT0(uint64_t chno, int i) + { + // offsetFT0[0]: FT0A, offsetFT0[1]: FT0C + if (i > 1 || i < 0) { + LOGF(fatal, "kFIT Index %d out of range", i); + } + ft0Det.calculateChannelCenter(); + auto chPos = ft0Det.getChannelCenter(chno); + auto x = chPos.X() + (*offsetFT0)[i].getX(); + auto y = chPos.Y() + (*offsetFT0)[i].getY(); + auto z = chPos.Z() + (*offsetFT0)[i].getZ(); + if (chno >= Ft0IndexA) { + z = -z; + } + auto r = std::sqrt(x * x + y * y); + auto theta = std::atan2(r, z); + return -std::log(std::tan(0.5 * theta)); + } + + template + float getCentrality(TCollision const& collision) + { + 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(); + } + return cent; + } + + template + bool trackSelected(TTrack track) + { + return ((track.tpcNClsFound() >= cfgCutTPCclu) && (track.tpcNClsCrossedRows() >= cfgCutTPCCrossedRows) && (track.itsNCls() >= cfgCutITSclu)); + } + + template + int getNsigmaPID(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaTOF = {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + std::array nSigmaITS = {itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track)}; + int pid = -1; // -1 = not identified, 1 = pion, 2 = kaon, 3 = proton + + std::array nSigmaToUse = cfgPIDConfig.cfgUseItsPID ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS + std::array detectorNsigmaCut = cfgPIDConfig.cfgUseItsPID ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS + + bool isPion = false; + bool isKaon = false; + bool isProton = false; + bool isDetectedPion = nSigmaToUse[kPionUp] < detectorNsigmaCut[kPionUp] && nSigmaToUse[kPionUp] > detectorNsigmaCut[kPionLow]; + bool isDetectedKaon = nSigmaToUse[kKaonUp] < detectorNsigmaCut[kKaonUp] && nSigmaToUse[kKaonUp] > detectorNsigmaCut[kKaonLow]; + bool isDetectedProton = nSigmaToUse[kProtonUp] < detectorNsigmaCut[kProtonUp] && nSigmaToUse[kProtonUp] > detectorNsigmaCut[kProtonLow]; + + bool isTofPion = nSigmaTOF[kPionUp] < tofNsigmaCut[kPionUp] && nSigmaTOF[kPionUp] > tofNsigmaCut[kPionLow]; + bool isTofKaon = nSigmaTOF[kKaonUp] < tofNsigmaCut[kKaonUp] && nSigmaTOF[kKaonUp] > tofNsigmaCut[kKaonLow]; + bool isTofProton = nSigmaTOF[kProtonUp] < tofNsigmaCut[kProtonUp] && nSigmaTOF[kProtonUp] > tofNsigmaCut[kProtonLow]; + + if (track.pt() > cfgPIDConfig.cfgTofPtCut && !track.hasTOF()) { + return -1; + } else if (track.pt() > cfgPIDConfig.cfgTofPtCut && track.hasTOF()) { + isPion = isTofPion && isDetectedPion; + isKaon = isTofKaon && isDetectedKaon; + isProton = isTofProton && isDetectedProton; + } else { + isPion = isDetectedPion; + isKaon = isDetectedKaon; + isProton = isDetectedProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + return -1; // more than one particle satisfy the criteria + } + + if (isPion) { + pid = kPions; + } else if (isKaon) { + pid = kKaons; + } else if (isProton) { + pid = kProtons; + } else { + return -1; // no particle satisfies the criteria + } + + return pid; // -1 = not identified, 1 = pion, 2 = kaon, 3 = proton + } + + void loadAlignParam(uint64_t timestamp) + { + offsetFT0 = ccdb->getForTimeStamp>("FT0/Calib/Align", timestamp); + if (offsetFT0 == nullptr) { + LOGF(fatal, "Could not load FT0/Calib/Align for timestamp %d", timestamp); + } + } + + void loadGain(aod::BCsWithTimestamps::iterator const& bc) + { + cstFT0RelGain.clear(); + cstFT0RelGain = {}; + std::string fullPath; + + auto timestamp = bc.timestamp(); + constexpr int ChannelsFT0 = 208; + if (cfgCorrLevel == 0) { + for (auto i{0u}; i < ChannelsFT0; i++) { + cstFT0RelGain.push_back(1.); + } + } else { + fullPath = cfgGainEqPath; + fullPath += "/FT0"; + const auto objft0Gain = ccdb->getForTimeStamp>(fullPath, timestamp); + if (!objft0Gain) { + for (auto i{0u}; i < ChannelsFT0; i++) { + cstFT0RelGain.push_back(1.); + } + } else { + cstFT0RelGain = *(objft0Gain); + } + } + } + + void loadCorrection(uint64_t timestamp) + { + if (correctionsLoaded) { + return; + } + if (cfgEfficiency.value.empty() == false) { + if (cfgLocalEfficiency > 0) { + TFile* fEfficiencyTrigger = TFile::Open(cfgEfficiency.value.c_str(), "READ"); + mEfficiency = reinterpret_cast(fEfficiencyTrigger->Get("ccdb_object")); + } else { + 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 (cfgCentralityWeight.value.empty() == false) { + mCentralityWeight = ccdb->getForTimeStamp(cfgCentralityWeight, timestamp); + if (mCentralityWeight == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgCentralityWeight.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgCentralityWeight.value.c_str(), (void*)mCentralityWeight); + } + correctionsLoaded = true; + } + + bool getEfficiencyCorrection(float& weight_nue, float eta, float pt, float posZ) + { + float eff = 1.; + if (mEfficiency) { + int etaBin = mEfficiency->GetXaxis()->FindBin(eta); + int ptBin = mEfficiency->GetYaxis()->FindBin(pt); + int zBin = mEfficiency->GetZaxis()->FindBin(posZ); + eff = mEfficiency->GetBinContent(etaBin, ptBin, zBin); + } else { + eff = 1.0; + } + if (eff == 0) + return false; + weight_nue = 1. / eff; + return true; + } + + bool getCentralityWeight(float& weightCent, const float centrality) + { + float weight = 1.; + if (mCentralityWeight) + weight = mCentralityWeight->GetBinContent(mCentralityWeight->FindBin(centrality)); + else + weight = 1.0; + if (weight == 0) + return false; + weightCent = weight; + return true; + } + + // fill multiple histograms + template + void fillYield(TCollision collision, TTracks tracks) // function to fill the yield and etaphi histograms. + { + float weff1 = 1; + float vtxz = collision.posZ(); + for (auto const& track1 : tracks) { + if (!trackSelected(track1)) + continue; + if (!getEfficiencyCorrection(weff1, track1.eta(), track1.pt(), vtxz)) + continue; + registry.fill(HIST("Phi"), RecoDecay::constrainAngle(track1.phi(), 0.0)); + registry.fill(HIST("Eta"), track1.eta()); + registry.fill(HIST("EtaCorrected"), track1.eta(), weff1); + registry.fill(HIST("pT"), track1.pt()); + registry.fill(HIST("pTCorrected"), track1.pt(), weff1); + } + } + + template + void getChannel(TFT0s const& ft0, std::size_t const& iCh, int& id, float& ampl, int fitType) + { + if (fitType == kFT0C) { + id = ft0.channelC()[iCh]; + id = id + Ft0IndexA; + ampl = ft0.amplitudeC()[iCh]; + registry.fill(HIST("FT0Amp"), id, ampl); + ampl = ampl / cstFT0RelGain[iCh]; + registry.fill(HIST("FT0AmpCorrect"), id, ampl); + } else if (fitType == kFT0A) { + id = ft0.channelA()[iCh]; + ampl = ft0.amplitudeA()[iCh]; + registry.fill(HIST("FT0Amp"), id, ampl); + ampl = ampl / cstFT0RelGain[iCh]; + registry.fill(HIST("FT0AmpCorrect"), id, ampl); + } else { + LOGF(fatal, "Cor Index %d out of range", fitType); + } + } + + template + void fillCorrelationsTPCFT0(TTracks tracks1, TFT0s const& ft0, float posZ, int system, int corType, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + if (system == SameEvent) { + if (!cfgCentTableUnavailable) + registry.fill(HIST("Centrality_used"), cent); + registry.fill(HIST("Nch_used"), tracks1.size()); + } + + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + float triggerWeight = 1.0f; + // loop over all tracks + for (auto const& track1 : tracks1) { + + if (!trackSelected(track1)) + continue; + if (cfgPIDConfig.cfgPIDParticle && getNsigmaPID(track1) != cfgPIDConfig.cfgPIDParticle) + continue; // if PID is selected, check if the track has the right PID + if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) + continue; + if (system == SameEvent) { + if (corType == kFT0C) { + registry.fill(HIST("Trig_hist_TPC_FT0C"), fSampleIndex, posZ, track1.pt(), eventWeight * triggerWeight); + } else if (corType == kFT0A) { + registry.fill(HIST("Trig_hist_TPC_FT0A"), fSampleIndex, posZ, track1.pt(), eventWeight * triggerWeight); + } + if (cfgDrawEtaPhiDis && corType == kFT0A) { + registry.fill(HIST("EtaPhi"), track1.eta(), track1.phi(), eventWeight * triggerWeight); + } + } + + std::size_t channelSize = 0; + if (corType == kFT0C) { + channelSize = ft0.channelC().size(); + } else if (corType == kFT0A) { + channelSize = ft0.channelA().size(); + } else { + LOGF(fatal, "Cor Index %d out of range", corType); + } + for (std::size_t iCh = 0; iCh < channelSize; iCh++) { + int chanelid = 0; + float ampl = 0.; + getChannel(ft0, iCh, chanelid, ampl, corType); + auto phi = getPhiFT0(chanelid, corType); + auto eta = getEtaFT0(chanelid, corType); + if (cfgDrawEtaPhiDis && system == SameEvent) { + registry.fill(HIST("EtaPhi"), eta, phi, ampl * eventWeight); + } + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - phi, -PIHalf); + float deltaEta = track1.eta() - eta; + // fill the right sparse and histograms + if (system == SameEvent) { + if (corType == kFT0A) { + registry.fill(HIST("Assoc_amp_same_TPC_FT0A"), chanelid, ampl); + sameTpcFt0a->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_same_TPC_FT0A"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + } else if (corType == kFT0C) { + registry.fill(HIST("Assoc_amp_same_TPC_FT0C"), chanelid, ampl); + sameTpcFt0c->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_same_TPC_FT0C"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + } + } else if (system == MixedEvent) { + if (corType == kFT0A) { + registry.fill(HIST("Assoc_amp_mixed_TPC_FT0A"), chanelid, ampl); + mixedTpcFt0a->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_FT0A"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + } else if (corType == kFT0C) { + registry.fill(HIST("Assoc_amp_mixed_TPC_FT0C"), chanelid, ampl); + mixedTpcFt0c->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track1.pt(), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_mixed_TPC_FT0C"), deltaPhi, deltaEta, ampl * eventWeight * triggerWeight); + } + } + } + } + } + + template + void fillCorrelationsFT0AFT0C(TFT0s const& ft0Col1, TFT0s const& ft0Col2, float posZ, int system, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + float triggerWeight = 1.0f; + std::size_t channelASize = ft0Col1.channelA().size(); + std::size_t channelCSize = ft0Col2.channelC().size(); + // loop over all tracks + for (std::size_t iChA = 0; iChA < channelASize; iChA++) { + + int chanelAid = 0; + float amplA = 0.; + getChannel(ft0Col1, iChA, chanelAid, amplA, kFT0A); + auto phiA = getPhiFT0(chanelAid, kFT0A); + auto etaA = getEtaFT0(chanelAid, kFT0A); + + if (system == SameEvent) { + registry.fill(HIST("Trig_hist_FT0A_FT0C"), fSampleIndex, posZ, 0.5, eventWeight * amplA); + } + + for (std::size_t iChC = 0; iChC < channelCSize; iChC++) { + int chanelCid = 0; + float amplC = 0.; + getChannel(ft0Col2, iChC, chanelCid, amplC, kFT0C); + auto phiC = getPhiFT0(chanelCid, kFT0C); + auto etaC = getEtaFT0(chanelCid, kFT0C); + float deltaPhi = RecoDecay::constrainAngle(phiA - phiC, -PIHalf); + float deltaEta = etaA - etaC; + // fill the right sparse and histograms + if (system == SameEvent) { + sameFt0aFt0c->getPairHist()->Fill(step, fSampleIndex, posZ, 0.5, 0.5, deltaPhi, deltaEta, amplA * amplC * eventWeight * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_same_FT0A_FT0C"), deltaPhi, deltaEta, amplA * amplC * eventWeight * triggerWeight); + } else if (system == MixedEvent) { + mixedFt0aFt0c->getPairHist()->Fill(step, fSampleIndex, posZ, 0.5, 0.5, deltaPhi, deltaEta, amplA * amplC * eventWeight * triggerWeight); + registry.fill(HIST("deltaEta_deltaPhi_mixed_FT0A_FT0C"), deltaPhi, deltaEta, amplA * amplC * eventWeight * triggerWeight); + } + } + } + } + + template + bool eventSelected(TCollision collision, const int multTrk, const float centrality, const bool fillCounter) + { + 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 (fillCounter && cfgEvSelkNoSameBunchPileup) + registry.fill(HIST("hEventCountSpecific"), 1.5); + if (cfgEvSelkNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return 0; + } + if (fillCounter && cfgEvSelkNoITSROFrameBorder) + registry.fill(HIST("hEventCountSpecific"), 2.5); + if (cfgEvSelkNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return 0; + } + if (fillCounter && cfgEvSelkNoTimeFrameBorder) + registry.fill(HIST("hEventCountSpecific"), 3.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 (fillCounter && cfgEvSelkIsGoodZvtxFT0vsPV) + registry.fill(HIST("hEventCountSpecific"), 4.5); + if (cfgEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (fillCounter && cfgEvSelkNoCollInTimeRangeStandard) + registry.fill(HIST("hEventCountSpecific"), 5.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 (fillCounter && cfgEvSelkIsGoodITSLayersAll) + registry.fill(HIST("hEventCountSpecific"), 6.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 (fillCounter && cfgEvSelkNoCollInRofStandard) + registry.fill(HIST("hEventCountSpecific"), 7.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 (fillCounter && cfgEvSelkNoHighMultCollInPrevRof) + registry.fill(HIST("hEventCountSpecific"), 8.5); + auto occupancy = collision.trackOccupancyInTimeRange(); + if (cfgEvSelOccupancy && (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh)) + return 0; + if (fillCounter && cfgEvSelOccupancy) + registry.fill(HIST("hEventCountSpecific"), 9.5); + + auto multNTracksPV = collision.multNTracksPV(); + if (cfgEvSelMultCorrelation) { + if (cfgFuncParas.cfgMultPVT0CCutEnabled && !cfgCentTableUnavailable) { + if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(centrality)) + return 0; + if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(centrality)) + return 0; + } + if (cfgFuncParas.cfgMultT0CCutEnabled && !cfgCentTableUnavailable) { + if (multTrk < cfgFuncParas.fMultT0CCutLow->Eval(centrality)) + return 0; + if (multTrk > cfgFuncParas.fMultT0CCutHigh->Eval(centrality)) + return 0; + } + if (cfgFuncParas.cfgMultGlobalPVCutEnabled) { + if (multTrk < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) + return 0; + if (multTrk > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) + return 0; + } + if (cfgFuncParas.cfgMultMultV0ACutEnabled) { + if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(multTrk)) + return 0; + if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(multTrk)) + return 0; + } + } + if (fillCounter && cfgEvSelMultCorrelation) + registry.fill(HIST("hEventCountSpecific"), 10.5); + + // V0A T0A 5 sigma cut + float sigma = 5.0; + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > sigma * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + if (fillCounter && cfgEvSelV0AT0ACut) + registry.fill(HIST("hEventCountSpecific"), 11.5); + + return 1; + } + + void processSameTpcFt0a(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) + return; + auto bc = collision.bc_as(); + float cent = -1.; + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) { + cent = getCentrality(collision); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent, true)) + return; + if (!collision.has_foundFT0()) + return; + loadAlignParam(bc.timestamp()); + loadGain(bc); + loadCorrection(bc.timestamp()); + if (!cfgCentTableUnavailable) { + getCentralityWeight(weightCent, cent); + registry.fill(HIST("Centrality"), cent); + registry.fill(HIST("CentralityWeighted"), cent, weightCent); + } + registry.fill(HIST("Nch"), tracks.size()); + registry.fill(HIST("zVtx"), collision.posZ()); + + if (cfgSelCollByNch && (tracks.size() < cfgCutMultMin || tracks.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + fillYield(collision, tracks); + + sameTpcFt0a->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + const auto& ft0 = collision.foundFT0(); + fillCorrelationsTPCFT0(tracks, ft0, collision.posZ(), SameEvent, kFT0A, cent, weightCent); + } + PROCESS_SWITCH(LongRangeDihadronCor, processSameTpcFt0a, "Process same event for TPC-FT0 correlation", true); + + // the process for filling the mixed events + void processMixedTpcFt0a(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&) + { + + auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(tracks, tracks); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -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; + if (!collision1.sel8() || !collision2.sel8()) + continue; + + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + float cent1 = -1; + float cent2 = -1; + if (!cfgCentTableUnavailable) { + cent1 = getCentrality(collision1); + cent2 = getCentrality(collision2); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), cent1, false)) + continue; + if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), cent2, false)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent1 < cfgCutCentMin || cent1 >= cfgCutCentMax)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent2 < cfgCutCentMin || cent2 >= cfgCutCentMax)) + continue; + + if (!(collision1.has_foundFT0() && collision2.has_foundFT0())) + continue; + + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + loadAlignParam(bc.timestamp()); + loadCorrection(bc.timestamp()); + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + getCentralityWeight(weightCent, cent1); + const auto& ft0 = collision2.foundFT0(); + fillCorrelationsTPCFT0(tracks1, ft0, collision1.posZ(), MixedEvent, kFT0A, cent1, eventWeight * weightCent); + } + } + PROCESS_SWITCH(LongRangeDihadronCor, processMixedTpcFt0a, "Process mixed events for TPC-FT0A correlation", true); + + void processSameTpcFt0c(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) + return; + auto bc = collision.bc_as(); + float cent = -1.; + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) { + cent = getCentrality(collision); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent, true)) + return; + if (!collision.has_foundFT0()) + return; + loadAlignParam(bc.timestamp()); + loadGain(bc); + loadCorrection(bc.timestamp()); + if (!cfgCentTableUnavailable) { + getCentralityWeight(weightCent, cent); + registry.fill(HIST("Centrality"), cent); + registry.fill(HIST("CentralityWeighted"), cent, weightCent); + } + registry.fill(HIST("Nch"), tracks.size()); + registry.fill(HIST("zVtx"), collision.posZ()); + + if (cfgSelCollByNch && (tracks.size() < cfgCutMultMin || tracks.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + + registry.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + fillYield(collision, tracks); + + sameTpcFt0c->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + const auto& ft0 = collision.foundFT0(); + fillCorrelationsTPCFT0(tracks, ft0, collision.posZ(), SameEvent, kFT0C, cent, weightCent); + } + PROCESS_SWITCH(LongRangeDihadronCor, processSameTpcFt0c, "Process same event for TPC-FT0C correlation", false); + + // the process for filling the mixed events + void processMixedTpcFt0c(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&) + { + + auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(tracks, tracks); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -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; + if (!collision1.sel8() || !collision2.sel8()) + continue; + + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + float cent1 = -1; + float cent2 = -1; + if (!cfgCentTableUnavailable) { + cent1 = getCentrality(collision1); + cent2 = getCentrality(collision2); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), cent1, false)) + continue; + if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), cent2, false)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent1 < cfgCutCentMin || cent1 >= cfgCutCentMax)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent2 < cfgCutCentMin || cent2 >= cfgCutCentMax)) + continue; + + if (!(collision1.has_foundFT0() && collision2.has_foundFT0())) + continue; + + registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + loadAlignParam(bc.timestamp()); + loadCorrection(bc.timestamp()); + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + getCentralityWeight(weightCent, cent1); + const auto& ft0 = collision2.foundFT0(); + fillCorrelationsTPCFT0(tracks1, ft0, collision1.posZ(), MixedEvent, kFT0C, cent1, eventWeight * weightCent); + } + } + PROCESS_SWITCH(LongRangeDihadronCor, processMixedTpcFt0c, "Process mixed events for TPC-FT0C correlation", false); + + void processSameFt0aFt0c(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&) + { + if (!collision.sel8()) + return; + auto bc = collision.bc_as(); + float cent = -1.; + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) { + cent = getCentrality(collision); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), cent, true)) + return; + if (!collision.has_foundFT0()) + return; + loadAlignParam(bc.timestamp()); + loadGain(bc); + loadCorrection(bc.timestamp()); + + // should have the same event to TPC-FT0A/C correlations + if (cfgSelCollByNch && (tracks.size() < cfgCutMultMin || tracks.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + + sameFt0aFt0c->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + const auto& ft0 = collision.foundFT0(); + fillCorrelationsFT0AFT0C(ft0, ft0, collision.posZ(), SameEvent, weightCent); + } + PROCESS_SWITCH(LongRangeDihadronCor, processSameFt0aFt0c, "Process same event for FT0A-FT0C correlation", false); + + // the process for filling the mixed events + void processMixedFt0aFt0c(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&) + { + + auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(tracks, tracks); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -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; + + // should have the same event to TPC-FT0A/C correlations + if (!collision1.sel8() || !collision2.sel8()) + continue; + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + float cent1 = -1; + float cent2 = -1; + if (!cfgCentTableUnavailable) { + cent1 = getCentrality(collision1); + cent2 = getCentrality(collision2); + } + if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), cent1, false)) + continue; + if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), cent2, false)) + continue; + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent1 < cfgCutCentMin || cent1 >= cfgCutCentMax)) + continue; + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent2 < cfgCutCentMin || cent2 >= cfgCutCentMax)) + continue; + + if (!(collision1.has_foundFT0() && collision2.has_foundFT0())) + continue; + + auto bc = collision1.bc_as(); + loadAlignParam(bc.timestamp()); + loadCorrection(bc.timestamp()); + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + getCentralityWeight(weightCent, cent1); + const auto& ft0Col1 = collision1.foundFT0(); + const auto& ft0Col2 = collision2.foundFT0(); + fillCorrelationsFT0AFT0C(ft0Col1, ft0Col2, collision1.posZ(), MixedEvent, eventWeight * weightCent); + } + } + PROCESS_SWITCH(LongRangeDihadronCor, processMixedFt0aFt0c, "Process mixed events for FT0A-FT0C correlation", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/longrangeCorrelation.cxx b/PWGCF/TwoParticleCorrelations/Tasks/longrangeCorrelation.cxx new file mode 100644 index 00000000000..2986c545c90 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/longrangeCorrelation.cxx @@ -0,0 +1,1119 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file longrangeCorrelation.cxx +/// +/// \brief task for long range correlation analysis +/// \author Abhi Modak (abhi.modak@cern.ch) and Debojit Sarkar (debojit.sarkar@cern.ch) +/// \since April 22, 2025 + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "FT0Base/Geometry.h" +#include "FV0Base/Geometry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +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::aod::evsel; +using namespace o2::constants::math; + +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; + +enum KindOfEvntType { + kSE, + kME +}; + +enum KindOfCorrType { + kFT0AGLOBAL, + kFT0CGLOBAL, + kMFTGLOBAL, + kFT0AMFT, + kFT0AFT0C +}; + +enum KindOfParticles { + PIONS, + KAONS, + PROTONS +}; + +static constexpr std::string_view kCorrType[] = { + "Ft0aGlobal/", + "Ft0cGlobal/", + "MftGlobal/", + "Ft0aMft/", + "Ft0aFt0c/"}; +static constexpr std::string_view kEvntType[] = {"SE/", "ME/"}; +auto static constexpr kMinFt0cCell = 96; +auto static constexpr kMinCharge = 3.f; +AxisSpec axisEvent{10, 0.5, 9.5, "#Event", "EventAxis"}; + +struct LongrangeCorrelation { + + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable noLaterThan{"noLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + } cfgCcdbParam; + + SliceCache cache; + Service ccdb; + Service pdg; + o2::ccdb::CcdbApi ccdbApi; + o2::ft0::Geometry ft0Det; + std::vector* offsetFT0; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable cfgVtxCut{"cfgVtxCut", 10.0f, "Vertex Z range to consider"}; + Configurable cfgEtaCut{"cfgEtaCut", 1.0f, "Eta range to consider"}; + Configurable dcaZ{"dcaZ", 0.2f, "Custom DCA Z cut (ignored if negative)"}; + Configurable cfgPtCutMin{"cfgPtCutMin", 0.2f, "minimum accepted track pT"}; + Configurable cfgPtCutMax{"cfgPtCutMax", 10.0f, "maximum accepted track pT"}; + Configurable mixingParameter{"mixingParameter", 5, "how many events are mixed"}; + Configurable cfigMftEtaMax{"cfigMftEtaMax", -2.5f, "Maximum MFT eta cut"}; + Configurable cfigMftEtaMin{"cfigMftEtaMin", -3.6f, "Minimum MFT eta cut"}; + Configurable cfigMftDcaxy{"cfigMftDcaxy", 2.0f, "cut on DCA xy for MFT tracks"}; + Configurable cfigMftCluster{"cfigMftCluster", 5, "cut on MFT Cluster"}; + Configurable cfgSampleSize{"cfgSampleSize", 10, "Sample size for mixed event"}; + Configurable isApplySameBunchPileup{"isApplySameBunchPileup", false, "Enable SameBunchPileup cut"}; + Configurable isApplyGoodZvtxFT0vsPV{"isApplyGoodZvtxFT0vsPV", false, "Enable GoodZvtxFT0vsPV cut"}; + Configurable isReadoutCenter{"isReadoutCenter", false, "Enable Readout Center"}; + Configurable isUseEffCorr{"isUseEffCorr", false, "Enable efficiency correction"}; + Configurable cfgLowEffCut{"cfgLowEffCut", 0.001f, "Low efficiency cut"}; + Configurable isUseItsPid{"isUseItsPid", false, "Use ITS PID for particle identification"}; + Configurable cfgTofPidPtCut{"cfgTofPidPtCut", 0.3f, "Minimum pt to use TOF N-sigma"}; + Configurable cfgTrackPid{"cfgTrackPid", 0, "1 = pion, 2 = kaon, 3 = proton, 0 for no PID"}; + Configurable> itsNsigmaPidCut{"itsNsigmaPidCut", std::vector{3, 2.5, 2, -3, -2.5, -2}, "ITS n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable> tpcNsigmaPidCut{"tpcNsigmaPidCut", std::vector{1.5, 1.5, 1.5, -1.5, -1.5, -1.5}, "TPC n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable> tofNsigmaPidCut{"tofNsigmaPidCut", std::vector{1.5, 1.5, 1.5, -1.5, -1.5, -1.5}, "TOF n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; + Configurable cfgEffccdbPath{"cfgEffccdbPath", "/alice/data/CCDB/Users/a/abmodak/OO/Efficiency", "Browse track eff object from CCDB"}; + Configurable cfgMultccdbPath{"cfgMultccdbPath", "/alice/data/CCDB/Users/a/abmodak/OO/Multiplicity", "Browse mult efficiency object from CCDB"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {40, -6, -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 axisMultME{"axisMultME", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 1000}, "Mixing bins - multiplicity"}; + ConfigurableAxis axisVtxZME{"axisVtxZME", {VARIABLE_WIDTH, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10}, "Mixing bins - z-vertex"}; + 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"}; + ConfigurableAxis axisVtxZ{"axisVtxZ", {40, -20, 20}, "vertex axis"}; + ConfigurableAxis axisPhi{"axisPhi", {96, 0, TwoPI}, "#phi axis"}; + ConfigurableAxis axisEtaTrig{"axisEtaTrig", {40, -1., 1.}, "#eta trig axis"}; + ConfigurableAxis axisEtaAssoc{"axisEtaAssoc", {96, 3.5, 4.9}, "#eta assoc axis"}; + ConfigurableAxis axisSample{"axisSample", {cfgSampleSize, 0, cfgSampleSize}, "sample axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 10, 15, 25, 50, 60, 1000}, "multiplicity / centrality axis for histograms"}; + ConfigurableAxis amplitudeFt0a{"amplitudeFt0a", {5000, 0, 10000}, "FT0A amplitude"}; + ConfigurableAxis channelFt0aAxis{"channelFt0aAxis", {96, 0.0, 96.0}, "FT0A channel"}; + + Configurable isApplyCentFT0C{"isApplyCentFT0C", true, "Centrality based on FT0C"}; + Configurable isApplyCentFV0A{"isApplyCentFV0A", false, "Centrality based on FV0A"}; + Configurable isApplyCentFT0M{"isApplyCentFT0M", false, "Centrality based on FT0A + FT0C"}; + Configurable isUseCentEst{"isUseCentEst", false, "Centrality based classification"}; + Configurable cfgPtCutMult{"cfgPtCutMult", 3.0f, "maximum track pT for multiplicity classification"}; + + using CollTable = soa::Join; + using TrksTable = soa::Filtered>; + using MftTrkTable = soa::Filtered; + using CollTableMC = soa::SmallGroups>; + using TrksTableMC = soa::Filtered>; + Preslice perColGlobal = aod::track::collisionId; + Preslice perColMC = aod::track::collisionId; + Preslice perColMft = aod::fwdtrack::collisionId; + + OutputObj sameFt0aGlobal{"sameEventFt0aGlobal"}; + OutputObj mixedFt0aGlobal{"mixedEventFt0aGlobal"}; + OutputObj sameFt0cGlobal{"sameEventFt0cGlobal"}; + OutputObj mixedFt0cGlobal{"mixedEventFt0cGlobal"}; + OutputObj sameMftGlobal{"sameEventMftGlobal"}; + OutputObj mixedMftGlobal{"mixedEventMftGlobal"}; + OutputObj sameFt0aMft{"sameEventFt0aMft"}; + OutputObj mixedFt0aMft{"mixedEventFt0aMft"}; + OutputObj sameFt0aFt0c{"sameEventFt0aFt0c"}; + OutputObj mixedFt0aFt0c{"mixedEventFt0aFt0c"}; + + // corrections + TH3D* hTrkEff = nullptr; + TH1D* hMultEff = nullptr; + bool fLoadTrkEffCorr = false; + bool fLoadMultEffCorr = false; + + std::vector tofNsigmaCut; + std::vector itsNsigmaCut; + std::vector tpcNsigmaCut; + o2::aod::ITSResponse itsResponse; + + template + void addhistosQA() + { + histos.add(Form("%s%shMult", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH1D, {axisMultiplicity}); + histos.add(Form("%s%sTrig_etavsphi", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH2D, {axisPhi, axisEtaTrig}); + histos.add(Form("%s%sTrig_eta", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH1D, {axisEtaTrig}); + histos.add(Form("%s%sTrig_phi", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH1D, {axisPhi}); + histos.add(Form("%s%sTrig_pt", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH1D, {axisPtTrigger}); + histos.add(Form("%s%sTrig_hist", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTHnSparseF, {axisSample, axisVtxZ, axisPtTrigger, axisMultiplicity}); + histos.add(Form("%s%sAssoc_amp", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH2D, {channelFt0aAxis, amplitudeFt0a}); + histos.add(Form("%s%sAssoc_eta", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH1D, {axisEtaAssoc}); + histos.add(Form("%s%sAssoc_phi", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH1D, {axisPhi}); + histos.add(Form("%s%sAssoc_etavsphi", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH2D, {axisPhi, axisEtaAssoc}); + histos.add(Form("%s%sdeltaEta_deltaPhi", kCorrType[corrType].data(), kEvntType[evntType].data()), "", kTH2D, {axisDeltaPhi, axisDeltaEta}); + } + + void init(InitContext const&) + { + 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()); + LOGF(info, "Getting alignment offsets from the CCDB..."); + offsetFT0 = ccdb->getForTimeStamp>("FT0/Calib/Align", cfgCcdbParam.noLaterThan.value); + LOGF(info, "Offset for FT0A: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[0].getX(), (*offsetFT0)[0].getY(), (*offsetFT0)[0].getZ()); + LOGF(info, "Offset for FT0C: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[1].getX(), (*offsetFT0)[1].getY(), (*offsetFT0)[1].getZ()); + + std::vector corrAxis = {{axisSample, "Sample"}, + {axisVtxZ, "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; + userAxis.emplace_back(axisMultiplicity, "multiplicity"); + + tofNsigmaCut = tofNsigmaPidCut; + itsNsigmaCut = itsNsigmaPidCut; + tpcNsigmaCut = tpcNsigmaPidCut; + + if (doprocessEventStat) { + histos.add("QA/EventHist", "events", kTH1F, {axisEvent}, false); + histos.add("QA/VtxZHist", "v_{z} (cm)", kTH1F, {axisVtxZ}, false); + + auto hstat = histos.get(HIST("QA/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, "|vz|<10"); + } + + if (doprocessFt0aGlobalSE || doprocessFt0aGlobalME) { + addhistosQA(); + histos.add("Ft0aGlobal/ME/deltaEta_deltaPhi", "", kTH2D, {axisDeltaPhi, axisDeltaEta}); + sameFt0aGlobal.setObject(new CorrelationContainer("sameEventFt0aGlobal", "sameEventFt0aGlobal", corrAxis, effAxis, userAxis)); + mixedFt0aGlobal.setObject(new CorrelationContainer("mixedEventFt0aGlobal", "mixedEventFt0aGlobal", corrAxis, effAxis, userAxis)); + } + + if (doprocessFt0cGlobalSE || doprocessFt0cGlobalME) { + addhistosQA(); + histos.add("Ft0cGlobal/ME/deltaEta_deltaPhi", "", kTH2D, {axisDeltaPhi, axisDeltaEta}); + sameFt0cGlobal.setObject(new CorrelationContainer("sameEventFt0cGlobal", "sameEventFt0cGlobal", corrAxis, effAxis, userAxis)); + mixedFt0cGlobal.setObject(new CorrelationContainer("mixedEventFt0cGlobal", "mixedEventFt0cGlobal", corrAxis, effAxis, userAxis)); + } + + if (doprocessMftGlobalSE || doprocessMftGlobalME) { + addhistosQA(); + histos.add("MftGlobal/ME/deltaEta_deltaPhi", "", kTH2D, {axisDeltaPhi, axisDeltaEta}); + sameMftGlobal.setObject(new CorrelationContainer("sameEventMftGlobal", "sameEventMftGlobal", corrAxis, effAxis, userAxis)); + mixedMftGlobal.setObject(new CorrelationContainer("mixedEventMftGlobal", "mixedEventMftGlobal", corrAxis, effAxis, userAxis)); + } + + if (doprocessFt0aMftSE || doprocessFt0aMftME) { + addhistosQA(); + histos.add("Ft0aMft/ME/deltaEta_deltaPhi", "", kTH2D, {axisDeltaPhi, axisDeltaEta}); + sameFt0aMft.setObject(new CorrelationContainer("sameEventFt0aMft", "sameEventFt0aMft", corrAxis, effAxis, userAxis)); + mixedFt0aMft.setObject(new CorrelationContainer("mixedEventFt0aMft", "mixedEventFt0aMft", corrAxis, effAxis, userAxis)); + } + + if (doprocessFt0aFt0cSE || doprocessFt0aFt0cME) { + addhistosQA(); + histos.add("Ft0aFt0c/ME/deltaEta_deltaPhi", "", kTH2D, {axisDeltaPhi, axisDeltaEta}); + sameFt0aFt0c.setObject(new CorrelationContainer("sameEventFt0aFt0c", "sameEventFt0aFt0c", corrAxis, effAxis, userAxis)); + mixedFt0aFt0c.setObject(new CorrelationContainer("mixedEventFt0aFt0c", "mixedEventFt0aFt0c", corrAxis, effAxis, userAxis)); + } + + if (doprocessEff) { + histos.add("hmcgendndptPrimary", "hmcgendndptPrimary", kTHnSparseD, {axisEtaTrig, axisPtTrigger, axisMultiplicity, axisVtxZ}, false); + histos.add("hmcrecdndptRecoPrimary", "hmcrecdndptRecoPrimary", kTHnSparseD, {axisEtaTrig, axisPtTrigger, axisMultiplicity, axisVtxZ}, false); + histos.add("hmcrecdndptRecoAll", "hmcrecdndptRecoAll", kTHnSparseD, {axisEtaTrig, axisPtTrigger, axisMultiplicity, axisVtxZ}, false); + histos.add("hmcrecdndptFake", "hmcrecdndptFake", kTHnSparseD, {axisEtaTrig, axisPtTrigger, axisMultiplicity, axisVtxZ}, false); + } + } + + 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 = ifnode(dcaZ.node() > 0.f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly), + ncheckbit(aod::track::trackCutFlag, TrackSelectionDca)); + Filter fTracksEta = nabs(aod::track::eta) < cfgEtaCut; + Filter fTracksPt = (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax); + + Filter fMftTrackEta = (aod::fwdtrack::eta < cfigMftEtaMax) && (aod::fwdtrack::eta > cfigMftEtaMin); + Filter fMftTrackColID = (aod::fwdtrack::bestCollisionId >= 0); + Filter fMftTrackDca = (nabs(aod::fwdtrack::bestDCAXY) < cfigMftDcaxy); + + double getPhiFT0(uint chno, int i) + { + ft0Det.calculateChannelCenter(); + auto chPos = ft0Det.getChannelCenter(chno); + return RecoDecay::phi(chPos.X() + (*offsetFT0)[i].getX(), chPos.Y() + (*offsetFT0)[i].getY()); + } + + double getEtaFT0(uint chno, int i) + { + ft0Det.calculateChannelCenter(); + auto chPos = ft0Det.getChannelCenter(chno); + auto x = chPos.X() + (*offsetFT0)[i].getX(); + auto y = chPos.Y() + (*offsetFT0)[i].getY(); + auto z = chPos.Z() + (*offsetFT0)[i].getZ(); + if (chno >= kMinFt0cCell) + z = -z; + auto r = std::sqrt(x * x + y * y); + auto theta = std::atan2(r, z); + return -std::log(std::tan(0.5 * theta)); + } + + template + bool isEventSelected(CheckCol const& col) + { + if (!col.sel8()) { + return false; + } + if (isApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (isApplyGoodZvtxFT0vsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (std::abs(col.posZ()) >= cfgVtxCut) { + return false; + } + return true; + } + + template + bool isMftTrackSelected(CheckMftTrack const& track) + { + if (track.nClusters() < cfigMftCluster) { + return false; + } + return true; + } + + template + void fillTrackQA(TTrack const& track) + { + histos.fill(HIST(kCorrType[corrType]) + HIST(kEvntType[evntType]) + HIST("Trig_etavsphi"), track.phi(), track.eta()); + histos.fill(HIST(kCorrType[corrType]) + HIST(kEvntType[evntType]) + HIST("Trig_eta"), track.eta()); + histos.fill(HIST(kCorrType[corrType]) + HIST(kEvntType[evntType]) + HIST("Trig_phi"), track.phi()); + histos.fill(HIST(kCorrType[corrType]) + HIST(kEvntType[evntType]) + HIST("Trig_pt"), track.pt()); + } + + template + int countNTracks(countTrk const& tracks) + { + auto nTrk = 0; + for (const auto& track : tracks) { + if (track.pt() < cfgPtCutMin || track.pt() > cfgPtCutMult) { + continue; + } + nTrk++; + } + return nTrk; + } + + template + float selColCent(CheckColCent const& col) + { + auto cent = -1; + if (isApplyCentFT0C) { + cent = col.centFT0C(); + } + if (isApplyCentFV0A) { + cent = col.centFV0A(); + } + if (isApplyCentFT0M) { + cent = col.centFT0M(); + } + return cent; + } + + void loadEffCorrection(uint64_t timestamp) + { + if (fLoadTrkEffCorr) { + return; + } + if (cfgEffccdbPath.value.empty() == false) { + hTrkEff = ccdb->getForTimeStamp(cfgEffccdbPath, timestamp); + if (hTrkEff == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEffccdbPath.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEffccdbPath.value.c_str(), (void*)hTrkEff); + } + fLoadTrkEffCorr = true; + } + + void loadMultCorrection(uint64_t timestamp) + { + if (fLoadMultEffCorr) { + return; + } + if (cfgMultccdbPath.value.empty() == false) { + hMultEff = ccdb->getForTimeStamp(cfgMultccdbPath, timestamp); + if (hMultEff == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for multiplicity from %s", cfgMultccdbPath.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgMultccdbPath.value.c_str(), (void*)hMultEff); + } + fLoadMultEffCorr = true; + } + + float getTrkEffCorr(float eta, float pt, float posZ) + { + float eff = 1.; + if (hTrkEff) { + int etaBin = hTrkEff->GetXaxis()->FindBin(eta); + int ptBin = hTrkEff->GetYaxis()->FindBin(pt); + int zBin = hTrkEff->GetZaxis()->FindBin(posZ); + eff = hTrkEff->GetBinContent(etaBin, ptBin, zBin); + } else { + eff = 1.0; + } + if (eff < cfgLowEffCut) + eff = 1.0; + + return eff; + } + + float getMultEffCorr(float mult) + { + float eff = 1.; + if (hMultEff) { + int multBin = hMultEff->GetXaxis()->FindBin(mult); + eff = hMultEff->GetBinContent(multBin); + } else { + eff = 1.0; + } + if (eff < cfgLowEffCut) + eff = 1.0; + + return eff; + } + + template + int getTrackPID(TTrack track) + { + // Computing Nsigma arrays for pion, kaon, and protons + std::array nSigmaTPC = {track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + std::array nSigmaTOF = {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + std::array nSigmaITS = {itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track)}; + int pid = -1; + + std::array nSigmaToUse = isUseItsPid ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS + std::vector detectorNsigmaCut = isUseItsPid ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS + + bool isPion, isKaon, isProton; + bool isDetectedPion = nSigmaToUse[0] < detectorNsigmaCut[0] && nSigmaToUse[0] > detectorNsigmaCut[0 + 3]; + bool isDetectedKaon = nSigmaToUse[1] < detectorNsigmaCut[1] && nSigmaToUse[1] > detectorNsigmaCut[1 + 3]; + bool isDetectedProton = nSigmaToUse[2] < detectorNsigmaCut[2] && nSigmaToUse[2] > detectorNsigmaCut[2 + 3]; + + bool isTofPion = nSigmaTOF[0] < tofNsigmaCut[0] && nSigmaTOF[0] > tofNsigmaCut[0 + 3]; + bool isTofKaon = nSigmaTOF[1] < tofNsigmaCut[1] && nSigmaTOF[1] > tofNsigmaCut[1 + 3]; + bool isTofProton = nSigmaTOF[2] < tofNsigmaCut[2] && nSigmaTOF[2] > tofNsigmaCut[2 + 3]; + + if (track.pt() > cfgTofPidPtCut && !track.hasTOF()) { + return 0; + } else if (track.pt() > cfgTofPidPtCut && track.hasTOF()) { + isPion = isTofPion && isDetectedPion; + isKaon = isTofKaon && isDetectedKaon; + isProton = isTofProton && isDetectedProton; + } else { + isPion = isDetectedPion; + isKaon = isDetectedKaon; + isProton = isDetectedProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + return 0; // more than one particle satisfy the criteria + } + + if (isPion) { + pid = PIONS; + } else if (isKaon) { + pid = KAONS; + } else if (isProton) { + pid = PROTONS; + } else { + return 0; // no particle satisfies the criteria + } + + return pid + 1; // shift the pid by 1, 1 = pion, 2 = kaon, 3 = proton + } + + template + void fillCorrFt0aGlobal(TTarget target, TTriggers const& triggers, TFT0s const& ft0, bool mixing, float vz, float multiplicity) + { + histos.fill(HIST("Ft0aGlobal/SE/hMult"), multiplicity); + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + for (auto const& triggerTrack : triggers) { + if (cfgTrackPid && getTrackPID(triggerTrack) != cfgTrackPid) + continue; // if PID is selected, check if the track has the right PID + + float trkeffw = 1.0f; + if (isUseEffCorr) + trkeffw = getTrkEffCorr(triggerTrack.eta(), triggerTrack.pt(), vz); + + if (!mixing) { + fillTrackQA(triggerTrack); + histos.fill(HIST("Ft0aGlobal/SE/Trig_hist"), fSampleIndex, vz, triggerTrack.pt(), multiplicity, trkeffw); + } + + for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { + auto chanelid = ft0.channelA()[iCh]; + float ampl = ft0.amplitudeA()[iCh]; + + auto phi = getPhiFT0(chanelid, 0); + auto eta = getEtaFT0(chanelid, 0); + + if (!mixing) { + histos.fill(HIST("Ft0aGlobal/SE/Assoc_amp"), chanelid, ampl); + histos.fill(HIST("Ft0aGlobal/SE/Assoc_eta"), eta); + histos.fill(HIST("Ft0aGlobal/SE/Assoc_phi"), phi); + histos.fill(HIST("Ft0aGlobal/SE/Assoc_etavsphi"), phi, eta); + } + float deltaPhi = RecoDecay::constrainAngle(triggerTrack.phi() - phi, -PIHalf); + float deltaEta = triggerTrack.eta() - eta; + if (mixing) + histos.fill(HIST("Ft0aGlobal/ME/deltaEta_deltaPhi"), deltaPhi, deltaEta, trkeffw); + else + histos.fill(HIST("Ft0aGlobal/SE/deltaEta_deltaPhi"), deltaPhi, deltaEta, trkeffw); + target->getPairHist()->Fill(step, fSampleIndex, vz, triggerTrack.pt(), triggerTrack.pt(), deltaPhi, deltaEta, multiplicity, trkeffw); + } // associated ft0 tracks + } // trigger tracks + } // fillCorrFt0aGlobal + + template + void fillCorrFt0cGlobal(TTarget target, TTriggers const& triggers, TFT0s const& ft0, bool mixing, float vz, float multiplicity) + { + histos.fill(HIST("Ft0cGlobal/SE/hMult"), multiplicity); + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + for (auto const& triggerTrack : triggers) { + if (cfgTrackPid && getTrackPID(triggerTrack) != cfgTrackPid) + continue; // if PID is selected, check if the track has the right PID + + float trkeffw = 1.0f; + if (isUseEffCorr) + trkeffw = getTrkEffCorr(triggerTrack.eta(), triggerTrack.pt(), vz); + + if (!mixing) { + fillTrackQA(triggerTrack); + histos.fill(HIST("Ft0cGlobal/SE/Trig_hist"), fSampleIndex, vz, triggerTrack.pt(), multiplicity, trkeffw); + } + + for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { + auto chanelid = ft0.channelC()[iCh] + 96; + float ampl = ft0.amplitudeC()[iCh]; + + auto phi = getPhiFT0(chanelid, 1); + auto eta = getEtaFT0(chanelid, 1); + + if (!mixing) { + histos.fill(HIST("Ft0cGlobal/SE/Assoc_amp"), chanelid, ampl); + histos.fill(HIST("Ft0cGlobal/SE/Assoc_eta"), eta); + histos.fill(HIST("Ft0cGlobal/SE/Assoc_phi"), phi); + histos.fill(HIST("Ft0cGlobal/SE/Assoc_etavsphi"), phi, eta); + } + + float deltaPhi = RecoDecay::constrainAngle(triggerTrack.phi() - phi, -PIHalf); + float deltaEta = triggerTrack.eta() - eta; + if (mixing) + histos.fill(HIST("Ft0cGlobal/ME/deltaEta_deltaPhi"), deltaPhi, deltaEta, trkeffw); + else + histos.fill(HIST("Ft0cGlobal/SE/deltaEta_deltaPhi"), deltaPhi, deltaEta, trkeffw); + target->getPairHist()->Fill(step, fSampleIndex, vz, triggerTrack.pt(), triggerTrack.pt(), deltaPhi, deltaEta, multiplicity, trkeffw); + } // associated ft0 tracks + } // trigger tracks + } // fillCorrFt0cGlobal + + template + void fillCorrMftGlobal(TTarget target, TTriggers const& triggers, TMFTs const& mft, bool mixing, float vz, float multiplicity) + { + histos.fill(HIST("MftGlobal/SE/hMult"), multiplicity); + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + for (auto const& triggerTrack : triggers) { + if (cfgTrackPid && getTrackPID(triggerTrack) != cfgTrackPid) + continue; // if PID is selected, check if the track has the right PID + + float trkeffw = 1.0f; + if (isUseEffCorr) + trkeffw = getTrkEffCorr(triggerTrack.eta(), triggerTrack.pt(), vz); + + if (!mixing) { + fillTrackQA(triggerTrack); + histos.fill(HIST("MftGlobal/SE/Trig_hist"), fSampleIndex, vz, triggerTrack.pt(), multiplicity, trkeffw); + } + + for (auto const& assoTrack : mft) { + if (!isMftTrackSelected(assoTrack)) { + continue; + } + auto phi = assoTrack.phi(); + o2::math_utils::bringTo02Pi(phi); + + if (!mixing) { + histos.fill(HIST("MftGlobal/SE/Assoc_eta"), assoTrack.eta()); + histos.fill(HIST("MftGlobal/SE/Assoc_phi"), phi); + histos.fill(HIST("MftGlobal/SE/Assoc_etavsphi"), phi, assoTrack.eta()); + } + + float deltaPhi = RecoDecay::constrainAngle(triggerTrack.phi() - phi, -PIHalf); + float deltaEta = triggerTrack.eta() - assoTrack.eta(); + if (mixing) + histos.fill(HIST("MftGlobal/ME/deltaEta_deltaPhi"), deltaPhi, deltaEta, trkeffw); + else + histos.fill(HIST("MftGlobal/SE/deltaEta_deltaPhi"), deltaPhi, deltaEta, trkeffw); + target->getPairHist()->Fill(step, fSampleIndex, vz, triggerTrack.pt(), assoTrack.pt(), deltaPhi, deltaEta, multiplicity, trkeffw); + } // associated mft tracks + } // trigger tracks + } // fillCorrMftGlobal + + template + void fillCorrFt0aMft(TTarget target, TTriggers const& triggers, TFT0s const& ft0, bool mixing, float vz, float multiplicity) + { + histos.fill(HIST("Ft0aMft/SE/hMult"), multiplicity); + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + for (auto const& triggerTrack : triggers) { + if (!isMftTrackSelected(triggerTrack)) { + continue; + } + + auto trigphi = triggerTrack.phi(); + o2::math_utils::bringTo02Pi(trigphi); + + if (!mixing) { + fillTrackQA(triggerTrack); + histos.fill(HIST("Ft0aMft/SE/Trig_hist"), fSampleIndex, vz, triggerTrack.pt(), multiplicity); + } + + for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { + auto chanelid = ft0.channelA()[iCh]; + float ampl = ft0.amplitudeA()[iCh]; + + auto phi = getPhiFT0(chanelid, 0); + auto eta = getEtaFT0(chanelid, 0); + + if (!mixing) { + histos.fill(HIST("Ft0aMft/SE/Assoc_amp"), chanelid, ampl); + histos.fill(HIST("Ft0aMft/SE/Assoc_eta"), eta); + histos.fill(HIST("Ft0aMft/SE/Assoc_phi"), phi); + histos.fill(HIST("Ft0aMft/SE/Assoc_etavsphi"), phi, eta); + } + + float deltaPhi = RecoDecay::constrainAngle(trigphi - phi, -PIHalf); + float deltaEta = triggerTrack.eta() - eta; + if (mixing) + histos.fill(HIST("Ft0aMft/ME/deltaEta_deltaPhi"), deltaPhi, deltaEta); + else + histos.fill(HIST("Ft0aMft/SE/deltaEta_deltaPhi"), deltaPhi, deltaEta); + target->getPairHist()->Fill(step, fSampleIndex, vz, triggerTrack.pt(), triggerTrack.pt(), deltaPhi, deltaEta, multiplicity); + } // associated ft0 tracks + } // trigger tracks + } // fillCorrFt0aMft + + template + void fillCorrFt0aFt0c(TTarget target, TFT0As const& ft0a, TFT0Cs const& ft0c, bool mixing, float vz, float multiplicity) + { + histos.fill(HIST("Ft0aFt0c/SE/hMult"), multiplicity); + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + for (std::size_t iChA = 0; iChA < ft0a.channelA().size(); iChA++) { + + auto chanelidA = ft0a.channelA()[iChA]; + auto phiA = getPhiFT0(chanelidA, 0); + auto etaA = getEtaFT0(chanelidA, 0); + + if (!mixing) { + histos.fill(HIST("Ft0aFt0c/SE/Trig_eta"), etaA); + histos.fill(HIST("Ft0aFt0c/SE/Trig_phi"), phiA); + histos.fill(HIST("Ft0aFt0c/SE/Trig_etavsphi"), phiA, etaA); + histos.fill(HIST("Ft0aFt0c/SE/Trig_hist"), fSampleIndex, vz, 1.0, multiplicity); + } + + for (std::size_t iChC = 0; iChC < ft0c.channelC().size(); iChC++) { + + auto chanelidC = ft0c.channelC()[iChC] + 96; + float ampl = ft0c.amplitudeC()[iChC]; + auto phiC = getPhiFT0(chanelidC, 1); + auto etaC = getEtaFT0(chanelidC, 1); + + if (mixing) { + histos.fill(HIST("Ft0aFt0c/SE/Assoc_amp"), chanelidC, ampl); + histos.fill(HIST("Ft0aFt0c/SE/Assoc_eta"), etaC); + histos.fill(HIST("Ft0aFt0c/SE/Assoc_phi"), phiC); + histos.fill(HIST("Ft0aFt0c/SE/Assoc_etavsphi"), phiC, etaC); + } + + float deltaPhi = RecoDecay::constrainAngle(phiA - phiC, -PIHalf); + float deltaEta = etaA - etaC; + if (mixing) + histos.fill(HIST("Ft0aFt0c/ME/deltaEta_deltaPhi"), deltaPhi, deltaEta); + else + histos.fill(HIST("Ft0aFt0c/SE/deltaEta_deltaPhi"), deltaPhi, deltaEta); + target->getPairHist()->Fill(step, fSampleIndex, vz, 1.0, 1.0, deltaPhi, deltaEta, multiplicity); + } // associated ft0 tracks + } // trigger tracks + } // fillCorrFt0aFt0c + + void processEventStat(CollTable::iterator const& col) + { + histos.fill(HIST("QA/EventHist"), 1); + if (!col.sel8()) { + return; + } + histos.fill(HIST("QA/EventHist"), 2); + if (isApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } + histos.fill(HIST("QA/EventHist"), 3); + if (isApplyGoodZvtxFT0vsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + histos.fill(HIST("QA/EventHist"), 4); + if (std::abs(col.posZ()) >= cfgVtxCut) { + return; + } + histos.fill(HIST("QA/EventHist"), 5); + histos.fill(HIST("QA/VtxZHist"), col.posZ()); + } + + void processFt0aGlobalSE(CollTable::iterator const& col, aod::FT0s const&, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + if (!isEventSelected(col)) { + return; + } + if (col.has_foundFT0()) { + auto bc = col.bc_as(); + loadEffCorrection(bc.timestamp()); + loadMultCorrection(bc.timestamp()); + const auto& ft0 = col.foundFT0(); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col); + else + multiplicity = countNTracks(tracks); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrFt0aGlobal(sameFt0aGlobal, tracks, ft0, false, col.posZ(), multiplicity); + } + } // same event + + void processFt0cGlobalSE(CollTable::iterator const& col, aod::FT0s const&, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + if (!isEventSelected(col)) { + return; + } + if (col.has_foundFT0()) { + auto bc = col.bc_as(); + loadEffCorrection(bc.timestamp()); + loadMultCorrection(bc.timestamp()); + const auto& ft0 = col.foundFT0(); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col); + else + multiplicity = countNTracks(tracks); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrFt0cGlobal(sameFt0cGlobal, tracks, ft0, false, col.posZ(), multiplicity); + } + } // same event + + void processMftGlobalSE(CollTable::iterator const& col, MftTrkTable const& mfttracks, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + if (!isEventSelected(col)) { + return; + } + auto bc = col.bc_as(); + loadEffCorrection(bc.timestamp()); + loadMultCorrection(bc.timestamp()); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col); + else + multiplicity = countNTracks(tracks); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrMftGlobal(sameMftGlobal, tracks, mfttracks, false, col.posZ(), multiplicity); + } // same event + + void processFt0aMftSE(CollTable::iterator const& col, aod::FT0s const&, MftTrkTable const& mfttracks, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + if (!isEventSelected(col)) { + return; + } + if (col.has_foundFT0()) { + auto bc = col.bc_as(); + loadMultCorrection(bc.timestamp()); + const auto& ft0 = col.foundFT0(); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col); + else + multiplicity = countNTracks(tracks); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrFt0aMft(sameFt0aMft, mfttracks, ft0, false, col.posZ(), multiplicity); + } + } // same event + + void processFt0aFt0cSE(CollTable::iterator const& col, aod::FT0s const&, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + if (!isEventSelected(col)) { + return; + } + if (col.has_foundFT0()) { + auto bc = col.bc_as(); + const auto& ft0 = col.foundFT0(); + loadMultCorrection(bc.timestamp()); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col); + else + multiplicity = countNTracks(tracks); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrFt0aFt0c(sameFt0aFt0c, ft0, ft0, false, col.posZ(), multiplicity); + } + } // same event + + void processFt0aGlobalME(CollTable const& col, aod::FT0s const&, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + auto getTracksSize = [&tracks, this](CollTable::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + return associatedTracks.size(); + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxZME, axisMultME}, true}; + for (auto const& [col1, col2] : soa::selfCombinations(binningOnVtxAndMult, mixingParameter, -1, col, col)) { + if (!isEventSelected(col1) || !isEventSelected(col2)) { + continue; + } + if (col1.globalIndex() == col2.globalIndex()) { + continue; + } + if (col1.has_foundFT0() && col2.has_foundFT0()) { + auto bc = col1.bc_as(); + loadEffCorrection(bc.timestamp()); + loadMultCorrection(bc.timestamp()); + auto slicedTriggerTracks = tracks.sliceBy(perColGlobal, col1.globalIndex()); + const auto& ft0 = col2.foundFT0(); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col1); + else + multiplicity = countNTracks(slicedTriggerTracks); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrFt0aGlobal(mixedFt0aGlobal, slicedTriggerTracks, ft0, true, col1.posZ(), multiplicity); + } + } + } // mixed event + + void processFt0cGlobalME(CollTable const& col, aod::FT0s const&, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + auto getTracksSize = [&tracks, this](CollTable::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + return associatedTracks.size(); + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxZME, axisMultME}, true}; + for (auto const& [col1, col2] : soa::selfCombinations(binningOnVtxAndMult, mixingParameter, -1, col, col)) { + if (!isEventSelected(col1) || !isEventSelected(col2)) { + continue; + } + if (col1.globalIndex() == col2.globalIndex()) { + continue; + } + if (col1.has_foundFT0() && col2.has_foundFT0()) { + auto bc = col1.bc_as(); + loadEffCorrection(bc.timestamp()); + loadMultCorrection(bc.timestamp()); + auto slicedTriggerTracks = tracks.sliceBy(perColGlobal, col1.globalIndex()); + const auto& ft0 = col2.foundFT0(); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col1); + else + multiplicity = countNTracks(slicedTriggerTracks); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrFt0cGlobal(mixedFt0cGlobal, slicedTriggerTracks, ft0, true, col1.posZ(), multiplicity); + } + } + } // mixed event + + void processMftGlobalME(CollTable const& col, MftTrkTable const& mfttracks, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + auto getTracksSize = [&tracks, this](CollTable::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + return associatedTracks.size(); + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxZME, axisMultME}, true}; + auto tracksTuple = std::make_tuple(tracks, mfttracks); + Pair pairs{binningOnVtxAndMult, mixingParameter, -1, col, tracksTuple, &cache}; + for (auto const& [col1, tracks1, col2, tracks2] : pairs) { + if (!isEventSelected(col1) || !isEventSelected(col2)) { + continue; + } + auto bc = col1.bc_as(); + loadEffCorrection(bc.timestamp()); + loadMultCorrection(bc.timestamp()); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col1); + else + multiplicity = countNTracks(tracks1); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrMftGlobal(mixedMftGlobal, tracks1, tracks2, true, col1.posZ(), multiplicity); + } + } // mixed event + + void processFt0aMftME(CollTable const& col, aod::FT0s const&, TrksTable const& tracks, MftTrkTable const& mfttracks, aod::BCsWithTimestamps const&) + { + auto getTracksSize = [&tracks, this](CollTable::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + return associatedTracks.size(); + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxZME, axisMultME}, true}; + for (auto const& [col1, col2] : soa::selfCombinations(binningOnVtxAndMult, mixingParameter, -1, col, col)) { + if (!isEventSelected(col1) || !isEventSelected(col2)) { + continue; + } + if (col1.globalIndex() == col2.globalIndex()) { + continue; + } + if (col1.has_foundFT0() && col2.has_foundFT0()) { + auto bc = col1.bc_as(); + loadMultCorrection(bc.timestamp()); + auto slicedTriggerMftTracks = mfttracks.sliceBy(perColMft, col1.globalIndex()); + auto slicedTriggerTracks = tracks.sliceBy(perColGlobal, col1.globalIndex()); + const auto& ft0 = col2.foundFT0(); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col1); + else + multiplicity = countNTracks(slicedTriggerTracks); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrFt0aMft(mixedFt0aMft, slicedTriggerMftTracks, ft0, true, col1.posZ(), multiplicity); + } + } + } // mixed event + + void processFt0aFt0cME(CollTable const& col, aod::FT0s const&, TrksTable const& tracks, aod::BCsWithTimestamps const&) + { + auto getTracksSize = [&tracks, this](CollTable::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + return associatedTracks.size(); + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxZME, axisMultME}, true}; + for (auto const& [col1, col2] : soa::selfCombinations(binningOnVtxAndMult, mixingParameter, -1, col, col)) { + if (!isEventSelected(col1) || !isEventSelected(col2)) { + continue; + } + if (col1.globalIndex() == col2.globalIndex()) { + continue; + } + if (col1.has_foundFT0() && col2.has_foundFT0()) { + auto bc = col1.bc_as(); + loadMultCorrection(bc.timestamp()); + auto slicedTriggerTracks = tracks.sliceBy(perColGlobal, col1.globalIndex()); + auto multiplicity = 1.0f; + if (isUseCentEst) + multiplicity = selColCent(col1); + else + multiplicity = countNTracks(slicedTriggerTracks); + const auto& ft0a = col1.foundFT0(); + const auto& ft0c = col2.foundFT0(); + float multw = getMultEffCorr(multiplicity); + if (isUseEffCorr) + multiplicity = multiplicity * multw; + fillCorrFt0aFt0c(mixedFt0aFt0c, ft0a, ft0c, true, col1.posZ(), multiplicity); + } + } + } // mixed event + + 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()) >= cfgEtaCut) { + return false; + } + return true; + } + + void processEff(aod::McCollisions::iterator const& mcCollision, CollTableMC const& RecCols, aod::McParticles const& GenParticles, TrksTableMC const& RecTracks) + { + if (std::abs(mcCollision.posZ()) >= cfgVtxCut) { + return; + } + + auto multiplicity = -999.; + auto numcontributors = -999; + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (RecCol.numContrib() <= numcontributors) { + continue; + } else { + numcontributors = RecCol.numContrib(); + } + if (isUseCentEst) { + multiplicity = selColCent(RecCol); + } else { + auto recTracksPart = RecTracks.sliceBy(perColMC, RecCol.globalIndex()); + multiplicity = countNTracks(recTracksPart); + } + } + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgendndptPrimary"), particle.eta(), particle.pt(), multiplicity, mcCollision.posZ()); + } // track (mcgen) loop + + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + auto recTracksPart = RecTracks.sliceBy(perColMC, RecCol.globalIndex()); + for (const auto& Rectrack : recTracksPart) { + if (Rectrack.has_mcParticle()) { + auto mcpart = Rectrack.mcParticle(); + histos.fill(HIST("hmcrecdndptRecoAll"), mcpart.eta(), mcpart.pt(), multiplicity, mcCollision.posZ()); + if (mcpart.isPhysicalPrimary()) { + histos.fill(HIST("hmcrecdndptRecoPrimary"), mcpart.eta(), mcpart.pt(), multiplicity, mcCollision.posZ()); + } + } else { + histos.fill(HIST("hmcrecdndptFake"), Rectrack.eta(), Rectrack.pt(), multiplicity, mcCollision.posZ()); + } + } // track (mcrec) loop + } // rec collision + } + + PROCESS_SWITCH(LongrangeCorrelation, processEventStat, "event stat", false); + PROCESS_SWITCH(LongrangeCorrelation, processFt0aGlobalSE, "same event FT0a vs global", false); + PROCESS_SWITCH(LongrangeCorrelation, processFt0aGlobalME, "mixed event FT0a vs global", false); + PROCESS_SWITCH(LongrangeCorrelation, processFt0cGlobalSE, "same event FT0c vs global", false); + PROCESS_SWITCH(LongrangeCorrelation, processFt0cGlobalME, "mixed event FT0c vs global", false); + PROCESS_SWITCH(LongrangeCorrelation, processMftGlobalSE, "same event MFT vs global", false); + PROCESS_SWITCH(LongrangeCorrelation, processMftGlobalME, "mixed event MFT vs global", false); + PROCESS_SWITCH(LongrangeCorrelation, processFt0aMftSE, "same event FT0a vs MFT", false); + PROCESS_SWITCH(LongrangeCorrelation, processFt0aMftME, "mixed event FT0a vs MFT", false); + PROCESS_SWITCH(LongrangeCorrelation, processFt0aFt0cSE, "same event FT0a vs FT0c", false); + PROCESS_SWITCH(LongrangeCorrelation, processFt0aFt0cME, "mixed event FT0a vs FT0c", false); + PROCESS_SWITCH(LongrangeCorrelation, processEff, "Estimate efficiency", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/longrangecorrDerived.cxx b/PWGCF/TwoParticleCorrelations/Tasks/longrangecorrDerived.cxx new file mode 100644 index 00000000000..751a5cedec5 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/longrangecorrDerived.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 longrangecorrDerived.cxx +/// +/// \brief task for long range correlation analysis based on derived table +/// \author Abhi Modak (abhi.modak@cern.ch) +/// \since November 05, 2025 + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/TwoParticleCorrelations/DataModel/LongRangeDerived.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "FT0Base/Geometry.h" +#include "FV0Base/Geometry.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::track; +using namespace o2::aod::fwdtrack; +using namespace o2::aod::evsel; +using namespace o2::constants::math; + +struct LongrangecorrDerived { + + SliceCache cache; + SGSelector sgSelector; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable cfgNmixedevent{"cfgNmixedevent", 5, "how many events are mixed"}; + Configurable cfgPidMask{"cfgPidMask", 0, "Selection bitmask for the TPC particle"}; + Configurable cfgV0Mask{"cfgV0Mask", 0, "Selection bitmask for the V0 particle"}; + Configurable cfgVtxCut{"cfgVtxCut", 10.0f, "Vertex Z range to consider"}; + + Configurable cfgFv0Cut{"cfgFv0Cut", 50.0f, "FV0A threshold"}; + Configurable cfgFt0aCut{"cfgFt0aCut", 100.0f, "FT0A threshold"}; + Configurable cfgFt0cCut{"cfgFt0cCut", 50.0f, "FT0C threshold"}; + Configurable cfgZdcCut{"cfgZdcCut", 0.1f, "ZDC threshold"}; + Configurable cfgGapSideCut{"cfgGapSideCut", 0, "Gap-side A=0, C=1, AC = 2, No Gap = -1, All events = 3"}; + + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 10, 15, 25, 50, 60, 1000}, "multiplicity axis"}; + ConfigurableAxis axisPhi{"axisPhi", {96, 0, TwoPI}, "#phi axis"}; + ConfigurableAxis axisEtaTrig{"axisEtaTrig", {40, -1., 1.}, "#eta trig axis"}; + 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 assoc axis for histograms"}; + ConfigurableAxis axisVtxZ{"axisVtxZ", {40, -20, 20}, "vertex axis"}; + ConfigurableAxis axisEtaAssoc{"axisEtaAssoc", {96, 3.5, 4.9}, "#eta assoc axis"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {40, -6, -2}, "delta eta axis for histograms"}; + ConfigurableAxis axisInvMass{"axisInvMass", {VARIABLE_WIDTH, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2.0}, "invariant mass axis"}; + ConfigurableAxis axisMultME{"axisMultME", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 1000}, "Mixing bins - multiplicity"}; + ConfigurableAxis axisVtxZME{"axisVtxZME", {VARIABLE_WIDTH, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10}, "Mixing bins - z-vertex"}; + + 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"}; + + OutputObj same{"sameEvent"}; + OutputObj mixed{"mixedEvent"}; + + using CollsTable = aod::CollLRTables; + using TrksTable = aod::TrkLRTables; + using MftTrksTable = aod::MftTrkLRTables; + using Ft0aTrksTable = aod::Ft0aLRTables; + using Ft0cTrksTable = aod::Ft0cLRTables; + using MftbestTrksTable = aod::MftBestTrkLRTables; + using V0TrksTable = aod::V0TrkLRTables; + + using UpcCollsTable = soa::Join; + using TrksUpcTable = aod::TrkLRUpcTables; + using MftTrksUpcTable = aod::MftTrkLRUpcTables; + using Ft0aTrksUpcTable = aod::Ft0aLRUpcTables; + using Ft0cTrksUpcTable = aod::Ft0cLRUpcTables; + using MftbestTrksUpcTable = aod::MftBestTrkLRUpcTables; + using V0TrksUpcTable = aod::V0TrkLRUpcTables; + + Preslice perColTpc = aod::lrcorrtrktable::collLRTableId; + Preslice perColMft = aod::lrcorrtrktable::collLRTableId; + Preslice perColMftbest = aod::lrcorrtrktable::collLRTableId; + Preslice perColFt0a = aod::lrcorrtrktable::collLRTableId; + Preslice perColFt0c = aod::lrcorrtrktable::collLRTableId; + Preslice perColV0 = aod::lrcorrtrktable::collLRTableId; + + Preslice perUpcColTpc = aod::lrcorrtrktable::upcCollLRTableId; + Preslice perUpcColMft = aod::lrcorrtrktable::upcCollLRTableId; + Preslice perUpcColMftbest = aod::lrcorrtrktable::upcCollLRTableId; + Preslice perUpcColFt0a = aod::lrcorrtrktable::upcCollLRTableId; + Preslice perUpcColFt0c = aod::lrcorrtrktable::upcCollLRTableId; + Preslice perUpcColV0 = aod::lrcorrtrktable::upcCollLRTableId; + + void init(InitContext const&) + { + std::vector corrAxis = {{axisVtxZ, "z-vtx (cm)"}, + {axisMultiplicity, "multiplicity"}, + {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 = {{axisInvMass, "m (GeV/c^2)"}}; + + same.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + + histos.add("hMultiplicity", "hMultiplicity", kTH1D, {axisMultiplicity}); + histos.add("hVertexZ", "hVertexZ", kTH1D, {axisVtxZ}); + + histos.add("hGapSide", "hGapSide", kTH1I, {{5, -0.5, 4.5}}); + histos.add("hTrueGapSide", "hTrueGapSide", kTH1I, {{6, -1.5, 4.5}}); + histos.add("hTrueGapSide_AfterSel", "hTrueGapSide_AfterSel", kTH1I, {{6, -1.5, 4.5}}); + + histos.add("Trig_eta", "Trig_eta", kTH1D, {axisEtaTrig}); + histos.add("Trig_phi", "Trig_phi", kTH1D, {axisPhi}); + histos.add("Trig_etavsphi", "Trig_etavsphi", kTH2D, {axisPhi, axisEtaTrig}); + histos.add("Trig_pt", "Trig_pt", kTH1D, {axisPtTrigger}); + histos.add("Trig_hist", "Trig_hist", kTHnSparseF, {axisVtxZ, axisMultiplicity, axisPtTrigger, axisInvMass}); + + histos.add("Assoc_eta", "Assoc_eta", kTH1D, {axisEtaAssoc}); + histos.add("Assoc_phi", "Assoc_phi", kTH1D, {axisPhi}); + histos.add("Assoc_etavsphi", "Assoc_etavsphi", kTH2D, {axisPhi, axisEtaAssoc}); + histos.add("Assoc_pt", "Assoc_pt", kTH1D, {axisPtAssoc}); + + histos.add("deltaEta_deltaPhi_same", "", kTH2D, {axisDeltaPhi, axisDeltaEta}); + histos.add("deltaEta_deltaPhi_mixed", "", kTH2D, {axisDeltaPhi, axisDeltaEta}); + } + + template + void fillCollQA(TCollision const& col) + { + histos.fill(HIST("hMultiplicity"), col.multiplicity()); + histos.fill(HIST("hVertexZ"), col.zvtx()); + } + + template + void fillTrigTrackQA(TTrack const& track) + { + histos.fill(HIST("Trig_etavsphi"), track.phi(), track.eta()); + histos.fill(HIST("Trig_eta"), track.eta()); + histos.fill(HIST("Trig_phi"), track.phi()); + histos.fill(HIST("Trig_pt"), track.pt()); + } + + template + void fillAssocTrackQA(TTrack const& track) + { + histos.fill(HIST("Assoc_etavsphi"), track.phi(), track.eta()); + histos.fill(HIST("Assoc_eta"), track.eta()); + histos.fill(HIST("Assoc_phi"), track.phi()); + } + + template + bool isUpcEventSelected(CheckCol const& col) + { + if constexpr (fillHist) { + histos.fill(HIST("hGapSide"), col.gapSide()); + } + int truegapSide = sgSelector.trueGap(col, cfgFv0Cut, cfgFt0aCut, cfgFt0cCut, cfgZdcCut); + if constexpr (fillHist) { + histos.fill(HIST("hTrueGapSide"), truegapSide); + } + if (truegapSide != cfgGapSideCut) + return false; + if constexpr (fillHist) { + histos.fill(HIST("hTrueGapSide_AfterSel"), truegapSide); + } + return true; + } + + template + using HasTpcTrack = decltype(std::declval().trackType()); + template + using HasV0Track = decltype(std::declval().v0Type()); + template + using HasInvMass = decltype(std::declval().invMass()); + template + using HasUpc = decltype(std::declval().gapSide()); + + template + void fillCorrHist(TTarget target, TTriggers const& triggers, TAssocs const& assocs, bool mixing, float vz, float multiplicity, float eventWeight) + { + for (auto const& triggerTrack : triggers) { + if constexpr (std::experimental::is_detected::value) { + if (cfgPidMask != 0 && (cfgPidMask & (1u << static_cast(triggerTrack.trackType()))) == 0u) + continue; + } else if constexpr (std::experimental::is_detected::value) { + if (cfgV0Mask != 0 && (cfgV0Mask & (1u << static_cast(triggerTrack.v0Type()))) == 0u) + continue; + } + if (!mixing) { + fillTrigTrackQA(triggerTrack); + if constexpr (std::experimental::is_detected::value) { + histos.fill(HIST("Trig_hist"), vz, multiplicity, triggerTrack.pt(), triggerTrack.invMass(), eventWeight); + } else { + histos.fill(HIST("Trig_hist"), vz, multiplicity, triggerTrack.pt(), 1.0, eventWeight); + } + } + for (auto const& assoTrack : assocs) { + float deltaPhi = RecoDecay::constrainAngle(triggerTrack.phi() - assoTrack.phi(), -PIHalf); + float deltaEta = triggerTrack.eta() - assoTrack.eta(); + if (!mixing) { + fillAssocTrackQA(assoTrack); + histos.fill(HIST("deltaEta_deltaPhi_same"), deltaPhi, deltaEta); + } else { + histos.fill(HIST("deltaEta_deltaPhi_mixed"), deltaPhi, deltaEta); + } + if constexpr (std::experimental::is_detected::value) { + target->getPairHist()->Fill(step, vz, multiplicity, triggerTrack.pt(), triggerTrack.pt(), deltaPhi, deltaEta, triggerTrack.invMass(), eventWeight); + } else { + target->getPairHist()->Fill(step, vz, multiplicity, triggerTrack.pt(), triggerTrack.pt(), deltaPhi, deltaEta, 1.0, eventWeight); + } + } // associated tracks + } // trigger tracks + } // fill correlation + + template + void processSame(TCollision const& col, TTriggers const& triggers, TAssocs const& assocs) + { + if (std::abs(col.zvtx()) >= cfgVtxCut) { + return; + } + fillCollQA(col); + fillCorrHist(same, triggers, assocs, false, col.zvtx(), col.multiplicity(), 1.0); + } // process same + + template + void processMixed(TCollision const& cols, TrackTypes&&... tracks) + { + auto getMultiplicity = [this](auto& col) { + if constexpr (std::experimental::is_detected::value) { + if (!isUpcEventSelected(col)) { + return -1.0f; + } + } else { + (void)this; + } + return col.multiplicity(); + }; + using MixedBinning = FlexibleBinningPolicy, aod::lrcorrcolltable::Zvtx, decltype(getMultiplicity)>; + MixedBinning binningOnVtxAndMult{{getMultiplicity}, {axisVtxZME, axisMultME}, true}; + auto tracksTuple = std::make_tuple(std::forward(tracks)...); + using TupleAtrack = std::tuple_element<0, decltype(tracksTuple)>::type; + using TupleBtrack = std::tuple_element - 1, decltype(tracksTuple)>::type; + Pair pairs{binningOnVtxAndMult, cfgNmixedevent, -1, cols, tracksTuple, &cache}; + for (auto it = pairs.begin(); it != pairs.end(); it++) { + auto& [col1, tracks1, col2, tracks2] = *it; + if constexpr (std::experimental::is_detected::value) { + if (!isUpcEventSelected(col1) || !isUpcEventSelected(col2)) { + continue; + } + } + float eventweight = 1.0f / it.currentWindowNeighbours(); + fillCorrHist(mixed, tracks1, tracks2, true, col1.zvtx(), col1.multiplicity(), eventweight); + } // pair loop + } // process mixed + + void processTpcft0aSE(CollsTable::iterator const& col, TrksTable const& tracks, Ft0aTrksTable const& ft0as) + { + processSame(col, tracks, ft0as); + } + + void processTpcft0cSE(CollsTable::iterator const& col, TrksTable const& tracks, Ft0cTrksTable const& ft0cs) + { + processSame(col, tracks, ft0cs); + } + + void processTpcmftSE(CollsTable::iterator const& col, TrksTable const& tracks, MftTrksTable const& mfts) + { + processSame(col, tracks, mfts); + } + + void processMftft0aSE(CollsTable::iterator const& col, MftTrksTable const& mfts, Ft0aTrksTable const& ft0as) + { + processSame(col, mfts, ft0as); + } + + void processV0ft0aSE(CollsTable::iterator const& col, V0TrksTable const& tracks, Ft0aTrksTable const& ft0as) + { + processSame(col, tracks, ft0as); + } + + void processV0mftSE(CollsTable::iterator const& col, V0TrksTable const& tracks, MftTrksTable const& mfts) + { + processSame(col, tracks, mfts); + } + + void processTpcmftbestSE(CollsTable::iterator const& col, TrksTable const& tracks, MftbestTrksTable const& mfts) + { + processSame(col, tracks, mfts); + } + + void processMftbestft0aSE(CollsTable::iterator const& col, MftbestTrksTable const& mfts, Ft0aTrksTable const& ft0as) + { + processSame(col, mfts, ft0as); + } + + void processV0mftbestSE(CollsTable::iterator const& col, V0TrksTable const& tracks, MftbestTrksTable const& mfts) + { + processSame(col, tracks, mfts); + } + + void processTpcft0aME(CollsTable const& cols, TrksTable const& tracks, Ft0aTrksTable const& ft0as) + { + processMixed(cols, tracks, ft0as); + } + + void processTpcft0cME(CollsTable const& cols, TrksTable const& tracks, Ft0cTrksTable const& ft0cs) + { + processMixed(cols, tracks, ft0cs); + } + + void processTpcmftME(CollsTable const& cols, TrksTable const& tracks, MftTrksTable const& mfts) + { + processMixed(cols, tracks, mfts); + } + + void processMftft0aME(CollsTable const& cols, MftTrksTable const& mfts, Ft0aTrksTable const& ft0as) + { + processMixed(cols, mfts, ft0as); + } + + void processV0ft0aME(CollsTable const& cols, V0TrksTable const& tracks, Ft0aTrksTable const& ft0as) + { + processMixed(cols, tracks, ft0as); + } + + void processV0mftME(CollsTable const& cols, V0TrksTable const& tracks, MftTrksTable const& mfts) + { + processMixed(cols, tracks, mfts); + } + + void processTpcmftbestME(CollsTable const& cols, TrksTable const& tracks, MftbestTrksTable const& mfts) + { + processMixed(cols, tracks, mfts); + } + + void processMftbestft0aME(CollsTable const& cols, MftbestTrksTable const& mfts, Ft0aTrksTable const& ft0as) + { + processMixed(cols, mfts, ft0as); + } + + void processV0mftbestME(CollsTable const& cols, V0TrksTable const& tracks, MftbestTrksTable const& mfts) + { + processMixed(cols, tracks, mfts); + } + + void processUpcTpcft0aSE(UpcCollsTable::iterator const& col, TrksUpcTable const& tracks, Ft0aTrksUpcTable const& ft0as) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, tracks, ft0as); + } + + void processUpcTpcft0cSE(UpcCollsTable::iterator const& col, TrksUpcTable const& tracks, Ft0cTrksUpcTable const& ft0cs) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, tracks, ft0cs); + } + + void processUpcTpcmftSE(UpcCollsTable::iterator const& col, TrksUpcTable const& tracks, MftTrksUpcTable const& mfts) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, tracks, mfts); + } + + void processUpcMftft0aSE(UpcCollsTable::iterator const& col, MftTrksUpcTable const& mfts, Ft0aTrksUpcTable const& ft0as) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, mfts, ft0as); + } + + void processUpcV0ft0aSE(UpcCollsTable::iterator const& col, V0TrksUpcTable const& tracks, Ft0aTrksUpcTable const& ft0as) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, tracks, ft0as); + } + + void processUpcV0mftSE(UpcCollsTable::iterator const& col, V0TrksUpcTable const& tracks, MftTrksUpcTable const& mfts) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, tracks, mfts); + } + + void processUpcTpcmftbestSE(UpcCollsTable::iterator const& col, TrksUpcTable const& tracks, MftbestTrksUpcTable const& mfts) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, tracks, mfts); + } + + void processUpcMftbestft0aSE(UpcCollsTable::iterator const& col, MftbestTrksUpcTable const& mfts, Ft0aTrksUpcTable const& ft0as) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, mfts, ft0as); + } + + void processUpcV0mftbestSE(UpcCollsTable::iterator const& col, V0TrksUpcTable const& tracks, MftbestTrksUpcTable const& mfts) + { + if (!isUpcEventSelected(col)) { + return; + } + processSame(col, tracks, mfts); + } + + void processUpcTpcft0aME(UpcCollsTable const& cols, TrksUpcTable const& tracks, Ft0aTrksUpcTable const& ft0as) + { + processMixed(cols, tracks, ft0as); + } + + void processUpcTpcft0cME(UpcCollsTable const& cols, TrksUpcTable const& tracks, Ft0cTrksUpcTable const& ft0cs) + { + processMixed(cols, tracks, ft0cs); + } + + void processUpcTpcmftME(UpcCollsTable const& cols, TrksUpcTable const& tracks, MftTrksUpcTable const& mfts) + { + processMixed(cols, tracks, mfts); + } + + void processUpcMftft0aME(UpcCollsTable const& cols, MftTrksUpcTable const& mfts, Ft0aTrksUpcTable const& ft0as) + { + processMixed(cols, mfts, ft0as); + } + + void processUpcV0ft0aME(UpcCollsTable const& cols, V0TrksUpcTable const& tracks, Ft0aTrksUpcTable const& ft0as) + { + processMixed(cols, tracks, ft0as); + } + + void processUpcV0mftME(UpcCollsTable const& cols, V0TrksUpcTable const& tracks, MftTrksUpcTable const& mfts) + { + processMixed(cols, tracks, mfts); + } + + void processUpcTpcmftbestME(UpcCollsTable const& cols, TrksUpcTable const& tracks, MftbestTrksUpcTable const& mfts) + { + processMixed(cols, tracks, mfts); + } + + void processUpcMftbestft0aME(UpcCollsTable const& cols, MftbestTrksUpcTable const& mfts, Ft0aTrksUpcTable const& ft0as) + { + processMixed(cols, mfts, ft0as); + } + + void processUpcV0mftbestME(UpcCollsTable const& cols, V0TrksUpcTable const& tracks, MftbestTrksUpcTable const& mfts) + { + processMixed(cols, tracks, mfts); + } + + PROCESS_SWITCH(LongrangecorrDerived, processTpcft0aSE, "same event TPC vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processTpcft0aME, "mixed event TPC vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processTpcft0cSE, "same event TPC vs FT0C", false); + PROCESS_SWITCH(LongrangecorrDerived, processTpcft0cME, "mixed event TPC vs FT0C", false); + PROCESS_SWITCH(LongrangecorrDerived, processTpcmftSE, "same event TPC vs MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processTpcmftME, "mixed event TPC vs MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processMftft0aSE, "same event MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processMftft0aME, "mixed event MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0ft0aSE, "same event V0 vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0ft0aME, "mixed event V0 vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0mftSE, "same event V0 vs MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0mftME, "mixed event V0 vs MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processTpcmftbestSE, "same event TPC vs best MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processTpcmftbestME, "mixed event TPC vs best MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processMftbestft0aSE, "same event best MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processMftbestft0aME, "mixed event best MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0mftbestSE, "same event V0 vs best MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0mftbestME, "mixed event V0 vs best MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcTpcft0aSE, "same UPC event TPC vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcTpcft0aME, "mixed UPC event TPC vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcTpcft0cSE, "same UPC event TPC vs FT0C", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcTpcft0cME, "mixed UPC event TPC vs FT0C", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcTpcmftSE, "same UPC event TPC vs MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcTpcmftME, "mixed UPC event TPC vs MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcMftft0aSE, "same UPC event MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcMftft0aME, "mixed UPC event MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcV0ft0aSE, "same UPC event V0 vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcV0ft0aME, "mixed UPC event V0 vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcV0mftSE, "same UPC event V0 vs MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcV0mftME, "mixed UPC event V0 vs MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcTpcmftbestSE, "same UPC event TPC vs best MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcTpcmftbestME, "mixed UPC event TPC vs best MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcMftbestft0aSE, "same UPC event best MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcMftbestft0aME, "mixed UPC event best MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcV0mftbestSE, "same UPC event V0 vs best MFT", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcV0mftbestME, "mixed UPC event V0 vs best MFT", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/neutronProtonCorrZdc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/neutronProtonCorrZdc.cxx new file mode 100644 index 00000000000..772d7c9d288 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/neutronProtonCorrZdc.cxx @@ -0,0 +1,451 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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, + kSel8 = 1, + kNoSameBunchPileUp = 2, + kIsGoodZvtxFT0vsPV = 3, + kNoCollInTimeRangeStandard = 4, + kMaxCentralitySelection = 5, + kZDCSelection = 6, + kTimeDifferenceZDC = 7 }; + +struct NeutronProtonCorrZdc { + // Histogram registry: an object to hold your histograms + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgZVertexCut{"cfgZVertexCut", 10., "Cut on Z vertex position"}; + Configurable cfgNoSameBunchPileupCut{"cfgNoSameBunchPileupCut", true, "kNoSameBunchPileUp Cut"}; + Configurable cfgIsGoodZvtxFT0vsPV{"cfgIsGoodZvtxFT0vsPV", true, "kIsGoodZvtxFT0vsPV Cut"}; + Configurable cfgNoCollInTimeRangeStandard{"cfgNoCollInTimeRangeStandard", true, "kNoCollInTimeRangeStandard Cut"}; + Configurable cfgMaxCentrality{"cfgMaxCentrality", 80, "Maximum collision centrality"}; + Configurable cfgZDCTimingInformationCut{"cfgZDCTimingInformationCut", true, "Use timing information in ZDC event selection"}; + Configurable cfgTimingBins{"cfgTimingBins", 200, "N bins for timing histograms"}; + Configurable cfgTDCZNmincut{"cfgTDCZNmincut", -3.0, "Min ZN TDC cut"}; + Configurable cfgTDCZNmaxcut{"cfgTDCZNmaxcut", 3.0, "Max ZN TDC cut"}; + Configurable cfgTDCZPmincut{"cfgTDCZPmincut", -3.0, "Min ZP TDC cut"}; + Configurable cfgTDCZPmaxcut{"cfgTDCZPmaxcut", 3.0, "Max ZP TDC cut"}; + 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", 150, "Maximum value for ZP signal"}; + Configurable cfgAmplMin{"cfgAmplMin", -50, "Minimum value for sector amplitude"}; + Configurable cfgAmplMax{"cfgAmplMax", 300, "Maximum value for sector amplitude"}; + Configurable cfgNBinsAmpl{"cfgNBinsAmpl", 100, "Number of bins for sector amplitude histograms"}; + 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 cfgCentralityEstimator{"cfgCentralityEstimator", 0, "Choice of centrality estimator"}; + Configurable cfgFillMultiplicityQAHistograms{"cfgFillMultiplicityQAHistograms", true, "Fill multiplicity QA plots"}; + Configurable cfgNBinsMultiplicity{"cfgNBinsMultiplicity", 500, "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) < cfgZVertexCut; + + 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{8, -0.5, 7.5, ""}; + const AxisSpec axisZDCTiming{cfgTimingBins, -10, 10}; + 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 axisZNAmplitude{cfgNBinsAmpl, cfgAmplMin, cfgAmplMax, "Ampl (a.u.)"}; + const AxisSpec axisZPAmplitude{cfgNBinsAmpl, cfgAmplMin * 0.3, cfgAmplMax * 0.3, "Ampl (a.u.)"}; + const AxisSpec axisTotalAmplitude{cfgNBinsAmpl, 4.0 * cfgAmplMin, 4.0 * cfgAmplMax, "Ampl (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 defaultTimingHistogram({HistType::kTH2F, {cfgAxisCent, axisZDCTiming}}); + HistogramConfigSpec defaultZNSectorHist({HistType::kTH2F, {cfgAxisCent, axisZNSectorSignal}}); + HistogramConfigSpec defaultZPSectorHist({HistType::kTH2F, {cfgAxisCent, axisZPSectorSignal}}); + HistogramConfigSpec defaultZNAmplSectorHist({HistType::kTH2F, {cfgAxisCent, axisZNAmplitude}}); + HistogramConfigSpec defaultZPAmplSectorHist({HistType::kTH2F, {cfgAxisCent, axisZPAmplitude}}); + HistogramConfigSpec defaultEnergyZNAmplSectorHist({HistType::kTH2F, {axisZNSignal, axisZNAmplitude}}); + HistogramConfigSpec defaultEnergyZPAmplSectorHist({HistType::kTH2F, {axisZPSignal, axisZPAmplitude}}); + HistogramConfigSpec defaultZDCDiffHist({HistType::kTH2F, {cfgAxisCent, axisZDiffSignal}}); + + // create histograms + histos.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); + histos.get(HIST("eventCounter"))->GetXaxis()->SetBinLabel(EventCounter::kSel8 + 1, "Sel8"); + histos.get(HIST("eventCounter"))->GetXaxis()->SetBinLabel(EventCounter::kNoSameBunchPileUp + 1, "kNoSameBunchPileup"); + histos.get(HIST("eventCounter"))->GetXaxis()->SetBinLabel(EventCounter::kIsGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("eventCounter"))->GetXaxis()->SetBinLabel(EventCounter::kNoCollInTimeRangeStandard + 1, "kNoCollInTimeRangeStandard"); + histos.get(HIST("eventCounter"))->GetXaxis()->SetBinLabel(EventCounter::kMaxCentralitySelection + 1, "Cenrality range"); + histos.get(HIST("eventCounter"))->GetXaxis()->SetBinLabel(EventCounter::kZDCSelection + 1, "isSelectedZDC"); + histos.get(HIST("eventCounter"))->GetXaxis()->SetBinLabel(EventCounter::kTimeDifferenceZDC + 1, "ZDC time difference"); + + histos.add("CentralityPercentile", "CentralityPercentile", kTH1F, {cfgAxisCent}); + histos.add("TimingZNAvsCent", "TimingZNAvsCent", defaultTimingHistogram); + histos.add("TimingZNCvsCent", "TimingZNCvsCent", defaultTimingHistogram); + histos.add("TimingZPAvsCent", "TimingZPAvsCent", defaultTimingHistogram); + histos.add("TimingZPCvsCent", "TimingZPCvsCent", defaultTimingHistogram); + + 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); + + histos.add("ASide/CentvsZNAmplitude", "CentvsZNAmplitude", defaultZNAmplSectorHist); + histos.add("ASide/CentvsZPAmplitude", "CentvsZPAmplitude", defaultZPAmplSectorHist); + histos.add("ASide/ZNSignalvsZNAmplitudeSum", "ZNSignalvsZNAmplitudeSum", defaultEnergyZNAmplSectorHist); + histos.add("ASide/ZNSignalvsZNAmplitudeCommon", "ZNSignalvsZNAmplitudeCommon", defaultEnergyZNAmplSectorHist); + histos.add("ASide/ZPSignalvsZPAmplitudeSum", "ZPSignalvsZPAmplitudeSum", defaultEnergyZPAmplSectorHist); + histos.add("ASide/ZPSignalvsZPAmplitudeCommon", "ZPSignalvsZPAmplitudeCommon", defaultEnergyZPAmplSectorHist); + + // 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("CentvsAlphaZNAmplitude", "CentvsAlphaZNAmplitude", kTH2F, {cfgAxisCent, axisAlphaZ}); + histos.add("CentvsAlphaZPAmplitude", "CentvsAlphaZPAmplitude", 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}); + + if (cfgFillMultiplicityQAHistograms) { + 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 + bool eventSelected(TCollision coll, const float centrality) + { + if (!coll.sel8()) + return 0; + histos.fill(HIST("eventCounter"), kSel8); + + if (cfgNoSameBunchPileupCut) { + if (!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 0; + } + histos.fill(HIST("eventCounter"), EventCounter::kNoSameBunchPileUp); + } + + if (cfgIsGoodZvtxFT0vsPV) { + if (!coll.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; + } + histos.fill(HIST("eventCounter"), EventCounter::kIsGoodZvtxFT0vsPV); + } + + if (cfgNoCollInTimeRangeStandard) { + if (!coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // Rejection of the collisions which have other events nearby + return 0; + } + histos.fill(HIST("eventCounter"), EventCounter::kNoCollInTimeRangeStandard); + } + + if (centrality > cfgMaxCentrality) { + return 0; + } + histos.fill(HIST("eventCounter"), EventCounter::kMaxCentralitySelection); + + return 1; + } + + 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()}; + std::array znAmplitudeResponse = {zdc.amplitudeZNA(), zdc.amplitudeZNC()}; + std::array zpAmplitudeResponse = {zdc.amplitudeZPA(), zdc.amplitudeZPC()}; + + 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]); + histos.fill(HIST(SubDir[side]) + HIST("CentvsZNAmplitude"), centr, znAmplitudeResponse[side]); + histos.fill(HIST(SubDir[side]) + HIST("CentvsZPAmplitude"), centr, zpAmplitudeResponse[side]); + + histos.fill(HIST(SubDir[side]) + HIST("ZNSignalvsZNAmplitudeSum"), sumZN, znAmplitudeResponse[side]); + histos.fill(HIST(SubDir[side]) + HIST("ZNSignalvsZNAmplitudeCommon"), znEnergyResponseCommon[side], znAmplitudeResponse[side]); + histos.fill(HIST(SubDir[side]) + HIST("ZPSignalvsZPAmplitudeSum"), sumZP, zpAmplitudeResponse[side]); + histos.fill(HIST(SubDir[side]) + HIST("ZPSignalvsZPAmplitudeCommon"), zpEnergyResponseCommon[side], zpAmplitudeResponse[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); + + const float centArray[] = {collision.centFT0C(), collision.centFT0CVariant1(), collision.centFT0M(), collision.centFV0A(), collision.centNGlobal()}; + const auto cent = centArray[cfgCentralityEstimator]; + + if (!eventSelected(collision, cent)) + return; + + const auto& foundBC = collision.foundBC_as(); + if (foundBC.has_zdc()) { + const auto& zdcread = foundBC.zdc(); + histos.fill(HIST("eventCounter"), EventCounter::kZDCSelection); + + auto tZNA = zdcread.timeZNA(); + auto tZNC = zdcread.timeZNC(); + auto tZPA = zdcread.timeZPA(); + auto tZPC = zdcread.timeZPC(); + + histos.fill(HIST("TimingZNAvsCent"), cent, tZNA); + histos.fill(HIST("TimingZNCvsCent"), cent, tZNC); + histos.fill(HIST("TimingZPAvsCent"), cent, tZPA); + histos.fill(HIST("TimingZPCvsCent"), cent, tZPC); + + // Selection on timing for the ZDC + if (cfgZDCTimingInformationCut) { + if (tZNA <= cfgTDCZNmincut || tZNA >= cfgTDCZNmaxcut) { + return; + } + if (tZNC <= cfgTDCZNmincut || tZNC >= cfgTDCZNmaxcut) { + return; + } + if (tZPA <= cfgTDCZPmincut || tZPA >= cfgTDCZPmaxcut) { + return; + } + if (tZPC <= cfgTDCZPmincut || tZPC >= cfgTDCZPmaxcut) { + return; + } + } + histos.fill(HIST("eventCounter"), EventCounter::kTimeDifferenceZDC); + histos.fill(HIST("CentralityPercentile"), cent); + + if (cfgFillMultiplicityQAHistograms) { + static_for<0, 6>([&](auto i) { + fillMultHistosRun3(collision); // Fill multiplicity histograms + }); + + static_for<0, 4>([&](auto i) { + fillCentHistosRun3(collision); // Fill centrality vs multiplicity 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); + + float alphaZNAmplitude = (zdcread.amplitudeZNA() - zdcread.amplitudeZNC()) / (zdcread.amplitudeZNA() + zdcread.amplitudeZNC()); + float alphaZPAmplitude = (zdcread.amplitudeZPA() - zdcread.amplitudeZPC()) / (zdcread.amplitudeZPA() + zdcread.amplitudeZPC()); + + 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("CentvsAlphaZNAmplitude"), cent, alphaZNAmplitude); + histos.fill(HIST("CentvsAlphaZPAmplitude"), cent, alphaZPAmplitude); + + 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::kSel8); + 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/perRunQc.cxx b/PWGCF/TwoParticleCorrelations/Tasks/perRunQc.cxx deleted file mode 100644 index 0faa24ab951..00000000000 --- a/PWGCF/TwoParticleCorrelations/Tasks/perRunQc.cxx +++ /dev/null @@ -1,102 +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. -// -// Minimal example to run this task: -// o2-analysis-centrality-table -b --configuration json://configuration.json | o2-analysis-timestamp -b --configuration json://configuration.json | o2-analysis-event-selection -b --configuration json://configuration.json | o2-analysis-multiplicity-table -b --configuration json://configuration.json | o2-analysis-lf-zdcsp -b --configuration json://configuration.json --aod-file @input_data.txt --aod-writer-json OutputDirector.json - -#include -#include - -#include "CCDB/BasicCCDBManager.h" -#include "Common/CCDB/ctpRateFetcher.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 perrunqatask -{ -std::unordered_map gHadronicRate; - -TH2* gCurrentHadronicRate; -} // namespace perrunqatask - -struct DptDptPerRunQa { - - Service ccdb; - - int mRunNumber{-1}; - uint64_t mSOR{0}; - double mMinSeconds{-1.}; - - ctpRateFetcher mRateFetcher; - HistogramRegistry mHistos{"PerRunQaHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - using namespace perrunqatask; - using namespace analysis::dptdptfilter; - - 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), 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(); - } - 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 perrunqatask; - using namespace analysis::dptdptfilter; - - if (!collision.collisionaccepted()) { - return; - } - - auto bc = collision.bc_as(); - initCCDB(bc); - double hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "T0VTX") * 1.e-3; // - double seconds = bc.timestamp() * 1.e-3 - mMinSeconds; - gCurrentHadronicRate->Fill(seconds, hadronicRate); - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/pidDiHadron.cxx b/PWGCF/TwoParticleCorrelations/Tasks/pidDiHadron.cxx new file mode 100644 index 00000000000..cf356975198 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/pidDiHadron.cxx @@ -0,0 +1,1467 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file pidDiHadron.cxx +/// \brief di-hadron correlation of PID for O-O, Pb-Pb collisions +/// \author Preet Bhanjan Pati (preet.bhanjan.pati@cern.ch), Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since July/29/2025 + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/MathConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include "TF1.h" +#include "TRandom3.h" +#include + +#include +#include + +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}; + +template +auto readMatrix(Array2D const& mat, P& array, int rowStart, int rowEnd, int colStart, int colEnd) +{ + for (auto i = rowStart; i < rowEnd; ++i) { + for (auto j = colStart; j < colEnd; ++j) { + array[i][j] = mat(i, j); + } + } + + return; +} + +static constexpr float LongArrayFloat[3][20] = {{1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {2.1, 2.2, 2.3, -2.1, -2.2, -2.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}, {3.1, 3.2, 3.3, -3.1, -3.2, -3.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2, 1.3, -1.1, -1.2, -1.3, 1.1, 1.2}}; +static constexpr int LongArrayInt[3][20] = {{1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1}, {2, 2, 2, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1}, {3, 3, 3, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1}}; + +struct PidDiHadron { + o2::aod::ITSResponse itsResponse; + Service ccdb; + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "minimum accepted track pT") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "maximum accepted track pT") + 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 cut") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgTpcCluster, float, 50.0f, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgTpcCrossRows, float, 70.0f, "minimum TPC crossed rows") + O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5f, "Minimum pt to use TOF N-sigma") + O2_DEFINE_CONFIGURABLE(cfgTpcCut, float, 3.0f, "TPC N-sigma cut for pions, kaons, protons") + O2_DEFINE_CONFIGURABLE(cfgITScluster, float, 5.0f, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyMax, int, 2000, "Minimum occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgCutOccupancyMin, int, 0, "Maximum occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgFakeKaonCut, float, 0.1f, "Maximum difference in measured momentum and TPC inner ring momentum of particle") + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "max DCA to vertex z") + O2_DEFINE_CONFIGURABLE(cfgCutMerging, float, 0.0, "Merging cut on track merge") + O2_DEFINE_CONFIGURABLE(cfgSelCollByNch, bool, true, "Select collisions by Nch or centrality") + O2_DEFINE_CONFIGURABLE(cfgCutMultMin, int, 0, "Minimum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgCutMultMax, int, 10, "Maximum multiplicity for collision") + O2_DEFINE_CONFIGURABLE(cfgCutCentMin, float, 60.0f, "Minimum centrality for collision") + O2_DEFINE_CONFIGURABLE(cfgCutCentMax, float, 80.0f, "Maximum centrality for collision") + O2_DEFINE_CONFIGURABLE(cfgMixEventNumMin, int, 5, "Minimum number of events to mix") + 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(cfgSampleSize, double, 10, "Sample size for mixed event") + O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") + O2_DEFINE_CONFIGURABLE(cfgCentTableUnavailable, bool, false, "if a dataset does not provide centrality information") + O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, false, "Use additional event cut on mult correlations") + O2_DEFINE_CONFIGURABLE(cfgV0AT0Acut, int, 5, "V0AT0A cut") + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgCentralityWeight, std::string, "", "CCDB path to centrality weight object") + O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, bool, false, "Use local efficiency object") + O2_DEFINE_CONFIGURABLE(cfgVerbosity, bool, false, "Verbose output") + O2_DEFINE_CONFIGURABLE(cfgUseEventWeights, bool, false, "Use event weights for mixed event") + O2_DEFINE_CONFIGURABLE(cfgUsePtOrder, bool, false, "enable trigger pT < associated pT cut") + O2_DEFINE_CONFIGURABLE(cfgUsePtOrderInMixEvent, bool, false, "enable trigger pT < associated pT cut in mixed event") + O2_DEFINE_CONFIGURABLE(cfgUseItsPID, bool, true, "Use ITS PID for particle identification") + O2_DEFINE_CONFIGURABLE(cfgUseOnlyTPC, bool, true, "Use only TPC PID for daughter selection") + O2_DEFINE_CONFIGURABLE(cfgPIDParticle, int, 0, "1 = pion, 2 = kaon, 3 = proton, 4 = kshort, 5 = lambda, 6 = phi, 0 for no PID") + O2_DEFINE_CONFIGURABLE(cfgGetNsigmaQA, bool, true, "Get QA histograms for selection of pions, kaons, and protons") + O2_DEFINE_CONFIGURABLE(cfgUseAntiLambda, bool, true, "Use AntiLambda candidates for analysis") + + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgMultCentHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 10.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultCentLowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultT0CCutEnabled, bool, false, "Enable Global multiplicity vs T0C centrality cut") + Configurable> cfgMultT0CCutPars{"cfgMultT0CCutPars", std::vector{143.04, -4.58368, 0.0766055, -0.000727796, 2.86153e-06, 23.3108, -0.36304, 0.00437706, -4.717e-05, 1.98332e-07}, "Global multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultPVT0CCutEnabled, bool, false, "Enable PV multiplicity vs T0C centrality cut") + Configurable> cfgMultPVT0CCutPars{"cfgMultPVT0CCutPars", std::vector{195.357, -6.15194, 0.101313, -0.000955828, 3.74793e-06, 30.0326, -0.43322, 0.00476265, -5.11206e-05, 2.13613e-07}, "PV multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultMultPVHighCutFunction, std::string, "[0]+[1]*x + 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultPVLowCutFunction, std::string, "[0]+[1]*x - 5.*([2]+[3]*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultGlobalPVCutEnabled, bool, false, "Enable global multiplicity vs PV multiplicity cut") + Configurable> cfgMultGlobalPVCutPars{"cfgMultGlobalPVCutPars", std::vector{-0.140809, 0.734344, 2.77495, 0.0165935}, "PV multiplicity vs T0C centrality cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgMultMultV0AHighCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 4.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ALowCutFunction, std::string, "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)", "Functional for multiplicity correlation cut"); + O2_DEFINE_CONFIGURABLE(cfgMultMultV0ACutEnabled, bool, false, "Enable global multiplicity vs V0A multiplicity cut") + Configurable> cfgMultMultV0ACutPars{"cfgMultMultV0ACutPars", std::vector{534.893, 184.344, 0.423539, -0.00331436, 5.34622e-06, 871.239, 53.3735, -0.203528, 0.000122758, 5.41027e-07}, "Global multiplicity vs V0A multiplicity cut parameter values"}; + O2_DEFINE_CONFIGURABLE(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); + O2_DEFINE_CONFIGURABLE(cfgDCAxy, std::string, "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"); + std::vector multT0CCutPars; + std::vector multPVT0CCutPars; + std::vector multGlobalPVCutPars; + std::vector multMultV0ACutPars; + TF1* fMultPVT0CCutLow = nullptr; + TF1* fMultPVT0CCutHigh = nullptr; + TF1* fMultT0CCutLow = nullptr; + TF1* fMultT0CCutHigh = nullptr; + TF1* fMultGlobalPVCutLow = nullptr; + TF1* fMultGlobalPVCutHigh = nullptr; + TF1* fMultMultV0ACutLow = nullptr; + TF1* fMultMultV0ACutHigh = nullptr; + TF1* fT0AV0AMean = nullptr; + TF1* fT0AV0ASigma = nullptr; + TF1* fPtDepDCAxy = nullptr; + } cfgFuncParas; + + SliceCache cache; + + ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 10, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260}, "multiplicity 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 axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "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.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt trigger axis for histograms"}; + ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt associated axis for histograms"}; + ConfigurableAxis axisVtxMix{"axisVtxMix", {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 axisMultMix{"axisMultMix", {VARIABLE_WIDTH, 0, 10, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260}, "multiplicity / centrality axis for mixed event histograms"}; + ConfigurableAxis axisSample{"axisSample", {cfgSampleSize, 0, cfgSampleSize}, "sample axis for histograms"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {80, -5, 5}, "nsigmaTPC axis"}; + ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {80, -5, 5}, "nsigmaTOF axis"}; + ConfigurableAxis axisNsigmaITS{"axisNsigmaITS", {80, -5, 5}, "nsigmaITS axis"}; + + Configurable> cfgUseEventCuts{"cfgUseEventCuts", {LongArrayInt[0], 15, 1, {"Filtered Events", "Sel8", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "kNoCollInTimeRangeStandard", "kIsGoodITSLayersAll", "kNoCollInRofStandard", "kNoHighMultCollInPrevRof", "Occupancy", "Multcorrelation", "T0AV0ACut", "kIsVertexITSTPC", "kTVXinTRD"}, {"EvCuts"}}, "Labeled array (int) for various cuts on resonances"}; + Configurable> nSigmas{"nSigmas", {LongArrayFloat[0], 6, 3, {"UpCut_pi", "UpCut_ka", "UpCut_pr", "LowCut_pi", "LowCut_ka", "LowCut_pr"}, {"TPC", "TOF", "ITS"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; + Configurable> resonanceCuts{"resonanceCuts", {LongArrayFloat[0], 12, 3, {"cos_PAs", "massMin", "massMax", "PosTrackPt", "NegTrackPt", "DCAPosToPVMin", "DCANegToPVMin", "Lifetime", "RadiusMin", "RadiusMax", "Rapidity", "ArmPodMinVal"}, {"K0", "Lambda", "Phi"}}, "Labeled array (float) for various cuts on resonances"}; + Configurable> resonanceSwitches{"resonanceSwitches", {LongArrayInt[0], 6, 3, {"UseCosPA", "NMassBins", "DCABetDaug", "UseProperLifetime", "UseV0Radius", "UseArmPodCut"}, {"K0", "Lambda", "Phi"}}, "Labeled array (int) for various cuts on resonances"}; + + ConfigurableAxis axisVertexEfficiency{"axisVertexEfficiency", {1, 0, 1}, "vertex axis for efficiency histograms"}; + ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {1, 0, 1}, "eta axis for efficiency histograms"}; + ConfigurableAxis axisPtEfficiency{"axisPtEfficiency", {1, 0, 1}, "pt axis for efficiency histograms"}; + + // make the filters and cuts. + 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) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + using FilteredCollisions = soa::Filtered>; + using FilteredTracks = soa::Filtered>; + using V0TrackCandidate = aod::V0Datas; + + Preslice perCollision = aod::track::collisionId; + Preslice perCollisionV0 = aod::v0::collisionId; + + // Corrections + TH3D* mEfficiency = nullptr; + TH1D* mCentralityWeight = nullptr; + bool correctionsLoaded = false; + + // Define the outputs + OutputObj same{"sameEvent"}; + OutputObj mixed{"mixedEvent"}; + OutputObj sameReso{"sameEventReso"}; + OutputObj mixedReso{"mixedEventReso"}; + HistogramRegistry histos{"histos"}; + + // define global variables + TRandom3* gRandom = new TRandom3(); + enum PIDIndex { + kCharged = 0, + kPions, + kKaons, + kProtons, + kK0, + kLambda, + kPhi + }; + enum PiKpArrayIndex { + iPionUp = 0, + iKaonUp, + iProtonUp, + iPionLow, + iKaonLow, + iProtonLow + }; + enum ResoArrayIndex { + iK0 = 0, + iLambda = 1, + iPhi = 2, + NResoParticles = 3 + }; + enum ResoParticleCuts { + kCosPA = 0, + kMassMin, + kMassMax, + kPosTrackPt, + kNegTrackPt, + kDCAPosToPVMin, + kDCANegToPVMin, + kLifeTime, + kRadiusMin, + kRadiusMax, + kRapidity, + kArmPodMinVal, + kNParticleCuts + }; + enum ResoParticleSwitches { + kUseCosPA = 0, + kMassBins, + kDCABetDaug, + kUseProperLifetime, + kUseV0Radius, + kUseArmPodCut, + kNParticleSwitches + }; + enum EventCutTypes { + kFilteredEvents = 0, + kAfterSel8, + kUseNoTimeFrameBorder, + kUseNoITSROFrameBorder, + kUseNoSameBunchPileup, + kUseGoodZvtxFT0vsPV, + kUseNoCollInTimeRangeStandard, + kUseGoodITSLayersAll, + kUseNoCollInRofStandard, + kUseNoHighMultCollInPrevRof, + kUseOccupancy, + kUseMultCorrCut, + kUseT0AV0ACut, + kUseVertexITSTPC, + kUseTVXinTRD, + kNEventCuts + }; + enum CentEstimators { + kCentFT0C = 0, + kCentFT0CVariant1, + kCentFT0M, + kCentFV0A, + // Count the total number of enum + kCount_CentEstimators + }; + enum EventType { + SameEvent = 1, + MixedEvent = 3 + }; + enum DetectorType { + kTPC = 0, + kTOF, + kITS + }; + enum EventCutType { + kEvCut1 = 0, + kNEvCutTypes = 1 + }; + + std::array, 15> eventCuts; + std::array, 12> resoCutVals; + std::array, 7> resoSwitchVals; + std::array tofNsigmaCut; + std::array itsNsigmaCut; + std::array tpcNsigmaCut; + + // persistent caches + std::vector efficiencyAssociatedCache; + + void init(InitContext&) + { + readMatrix(resonanceCuts->getData(), resoCutVals, kCosPA, kNParticleCuts, iK0, NResoParticles); + readMatrix(resonanceSwitches->getData(), resoSwitchVals, kUseCosPA, kNParticleSwitches, iK0, NResoParticles); + readMatrix(cfgUseEventCuts->getData(), eventCuts, kFilteredEvents, kNEventCuts, kEvCut1, kNEvCutTypes); + + tpcNsigmaCut[iPionUp] = nSigmas->getData()[iPionUp][kTPC]; + tpcNsigmaCut[iKaonUp] = nSigmas->getData()[iKaonUp][kTPC]; + tpcNsigmaCut[iProtonUp] = nSigmas->getData()[iProtonUp][kTPC]; + tpcNsigmaCut[iPionLow] = nSigmas->getData()[iPionLow][kTPC]; + tpcNsigmaCut[iKaonLow] = nSigmas->getData()[iKaonLow][kTPC]; + tpcNsigmaCut[iProtonLow] = nSigmas->getData()[iProtonLow][kTPC]; + + tofNsigmaCut[iPionUp] = nSigmas->getData()[iPionUp][kTOF]; + tofNsigmaCut[iKaonUp] = nSigmas->getData()[iKaonUp][kTOF]; + tofNsigmaCut[iProtonUp] = nSigmas->getData()[iProtonUp][kTOF]; + tofNsigmaCut[iPionLow] = nSigmas->getData()[iPionLow][kTOF]; + tofNsigmaCut[iKaonLow] = nSigmas->getData()[iKaonLow][kTOF]; + tofNsigmaCut[iProtonLow] = nSigmas->getData()[iProtonLow][kTOF]; + + itsNsigmaCut[iPionUp] = nSigmas->getData()[iPionUp][kITS]; + itsNsigmaCut[iKaonUp] = nSigmas->getData()[iKaonUp][kITS]; + itsNsigmaCut[iProtonUp] = nSigmas->getData()[iProtonUp][kITS]; + itsNsigmaCut[iPionLow] = nSigmas->getData()[iPionLow][kITS]; + itsNsigmaCut[iKaonLow] = nSigmas->getData()[iKaonLow][kITS]; + itsNsigmaCut[iProtonLow] = nSigmas->getData()[iProtonLow][kITS]; + + AxisSpec axisK0Mass = {resoSwitchVals[kMassBins][iK0], resoCutVals[kMassMin][iK0], resoCutVals[kMassMax][iK0]}; + AxisSpec axisLambdaMass = {resoSwitchVals[kMassBins][iLambda], resoCutVals[kMassMin][iLambda], resoCutVals[kMassMax][iLambda]}; + AxisSpec axisPhiMass = {resoSwitchVals[kMassBins][iPhi], resoCutVals[kMassMin][iPhi], resoCutVals[kMassMax][iPhi]}; + + if (cfgCentTableUnavailable && !cfgSelCollByNch) { + LOGF(fatal, "Centrality table is unavailable, cannot select collisions by centrality"); + } + const AxisSpec axisPhi{72, 0.0, constants::math::TwoPI, "#varphi"}; + const AxisSpec axisEta{40, -1., 1., "#eta"}; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + ccdb->setCreatedNotAfter(now); + + LOGF(info, "Starting init"); + + // Creating mass axis depending on particle - 4 = kshort, 5 = lambda, 6 = phi + AxisSpec massAxisReso = {10, 0, 1, "mass"}; + if (cfgPIDParticle == kK0) + massAxisReso = {resoSwitchVals[kMassBins][iK0], resoCutVals[kMassMin][iK0], resoCutVals[kMassMax][iK0], "M_{#pi^{+}#pi^{-}} (GeV/c^{2})"}; + if (cfgPIDParticle == kLambda) + massAxisReso = {resoSwitchVals[kMassBins][iLambda], resoCutVals[kMassMin][iLambda], resoCutVals[kMassMax][iLambda], "M_{p#pi^{-}} (GeV/c^{2})"}; + if (cfgPIDParticle == kPhi) + massAxisReso = {resoSwitchVals[kMassBins][iPhi], resoCutVals[kMassMin][iPhi], resoCutVals[kMassMax][iPhi], "M_{K^{+}K^{-}} (GeV/c^{2})"}; + + // Event Counter + if ((doprocessSame || doprocessSameReso) && cfgUseAdditionalEventCut) { + histos.add("hEventCount", "Number of Events;; Count", {HistType::kTH1D, {{15, -0.5, 14.5}}}); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kFilteredEvents + 1, "Filtered event"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kAfterSel8 + 1, "After sel8"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoTimeFrameBorder + 1, "kNoTimeFrameBorder"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoITSROFrameBorder + 1, "kNoITSROFrameBorder"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoSameBunchPileup + 1, "kNoSameBunchPileup"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseGoodZvtxFT0vsPV + 1, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoCollInTimeRangeStandard + 1, "kNoCollInTimeRangeStandard"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseGoodITSLayersAll + 1, "kIsGoodITSLayersAll"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoCollInRofStandard + 1, "kNoCollInRofStandard"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseNoHighMultCollInPrevRof + 1, "kNoHighMultCollInPrevRof"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseOccupancy + 1, "Occupancy Cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseMultCorrCut + 1, "MultCorrelation Cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseT0AV0ACut + 1, "T0AV0A cut"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseVertexITSTPC + 1, "kIsVertexITSTPC"); + histos.get(HIST("hEventCount"))->GetXaxis()->SetBinLabel(kUseTVXinTRD + 1, "kTVXinTRD"); + } + + if (cfgPIDParticle == kK0) { // For K0 + histos.add("PiPlusTPC_K0", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PiMinusTPC_K0", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PiPlusTOF_K0", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("PiMinusTOF_K0", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("hK0Phi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hK0Eta", "", {HistType::kTH1D, {axisEta}}); + + histos.add("hK0Count", "Number of K0;; Count", {HistType::kTH1D, {{11, 0, 11}}}); + 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, "ArmenterosPod"); + histos.get(HIST("hK0Count"))->GetXaxis()->SetBinLabel(11, "Daughter track selection"); + } + if (cfgPIDParticle == kLambda) { // For Lambda + histos.add("PrPlusTPC_L", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PiMinusTPC_L", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("PrPlusTOF_L", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("PiMinusTOF_L", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("hLambdaPhi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hLambdaEta", "", {HistType::kTH1D, {axisEta}}); + + 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"); + } + if (cfgPIDParticle == kPhi) { // For Phi + histos.add("KaPlusTPC", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("KaMinusTPC", "", {HistType::kTH2D, {{axisPt, axisNsigmaTPC}}}); + histos.add("KaPlusTOF", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("KaMinusTOF", "", {HistType::kTH2D, {{axisPt, axisNsigmaTOF}}}); + histos.add("hPhiPhi", "", {HistType::kTH1D, {axisPhi}}); + histos.add("hPhiEta", "", {HistType::kTH1D, {axisEta}}); + histos.add("hPhiMass_sparse", "", {HistType::kTHnSparseD, {{axisPhiMass, axisPt, axisMultiplicity}}}); + + histos.add("hPhiCount", "Number of Phi;; Count", {HistType::kTH1D, {{5, 0, 5}}}); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(1, "Phi candidates"); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(2, "Daughter track selection"); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(3, "Fake Kaon"); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(4, "CosPA"); + histos.get(HIST("hPhiCount"))->GetXaxis()->SetBinLabel(5, "Rapidity cut"); + } + + // Multiplicity correlation cuts + if (eventCuts[kUseMultCorrCut][kEvCut1]) { + cfgFuncParas.multT0CCutPars = cfgFuncParas.cfgMultT0CCutPars; + cfgFuncParas.multPVT0CCutPars = cfgFuncParas.cfgMultPVT0CCutPars; + cfgFuncParas.multGlobalPVCutPars = cfgFuncParas.cfgMultGlobalPVCutPars; + cfgFuncParas.multMultV0ACutPars = cfgFuncParas.cfgMultMultV0ACutPars; + cfgFuncParas.fMultPVT0CCutLow = new TF1("fMultPVT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutLow->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultPVT0CCutHigh = new TF1("fMultPVT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultPVT0CCutHigh->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + + cfgFuncParas.fMultT0CCutLow = new TF1("fMultT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutLow->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultT0CCutHigh = new TF1("fMultT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); + cfgFuncParas.fMultT0CCutHigh->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + + cfgFuncParas.fMultGlobalPVCutLow = new TF1("fMultGlobalPVCutLow", cfgFuncParas.cfgMultMultPVLowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutLow->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultGlobalPVCutHigh = new TF1("fMultGlobalPVCutHigh", cfgFuncParas.cfgMultMultPVHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultGlobalPVCutHigh->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + + cfgFuncParas.fMultMultV0ACutLow = new TF1("fMultMultV0ACutLow", cfgFuncParas.cfgMultMultV0ALowCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutLow->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fMultMultV0ACutHigh = new TF1("fMultMultV0ACutHigh", cfgFuncParas.cfgMultMultV0AHighCutFunction->c_str(), 0, 4000); + cfgFuncParas.fMultMultV0ACutHigh->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + } + if (eventCuts[kUseT0AV0ACut][kEvCut1]) { + cfgFuncParas.fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); + cfgFuncParas.fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); + cfgFuncParas.fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); + cfgFuncParas.fT0AV0ASigma->SetParameters(463.4144, 6.796509e-02, -9.097136e-07, 7.971088e-12, -2.600581e-17); + } + + cfgFuncParas.fPtDepDCAxy = new TF1("ptDepDCAxy", Form("[0]*%s", cfgFuncParas.cfgDCAxy->c_str()), 0.001, 100); + cfgFuncParas.fPtDepDCAxy->SetParameter(0, cfgFuncParas.cfgDCAxyNSigma); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", cfgFuncParas.cfgDCAxy->c_str())); + + std::string hCentTitle = "Centrality distribution, Estimator " + std::to_string(cfgCentEstimator); + // Make histograms to check the distributions after cuts + if (doprocessSame || doprocessSameReso) { + histos.add("deltaEta_deltaPhi_same", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // check to see the delta eta and delta phi distribution + histos.add("Nch", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); + histos.add("Nch_used", "N_{ch}", {HistType::kTH1D, {axisMultiplicity}}); // histogram to see how many events are in the same and mixed event + histos.add("Centrality", hCentTitle.c_str(), {HistType::kTH1D, {axisCentrality}}); + histos.add("CentralityWeighted", hCentTitle.c_str(), {HistType::kTH1D, {{100, 0, 100}}}); + histos.add("Centrality_used", hCentTitle.c_str(), {HistType::kTH1D, {axisCentrality}}); // histogram to see how many events are in the same and mixed event + histos.add("zVtx", "zVtx", {HistType::kTH1D, {axisVertex}}); + histos.add("zVtx_used", "zVtx_used", {HistType::kTH1D, {axisVertex}}); + + if (cfgPIDParticle == kCharged || cfgPIDParticle == kPions || cfgPIDParticle == kKaons || cfgPIDParticle == kProtons) { + histos.add("Phi", "Phi", {HistType::kTH1D, {axisPhi}}); + histos.add("Eta", "Eta", {HistType::kTH1D, {axisEta}}); + histos.add("EtaCorrected", "EtaCorrected", {HistType::kTH1D, {axisEta}}); + histos.add("pT", "pT", {HistType::kTH1D, {axisPtTrigger}}); + histos.add("pTCorrected", "pTCorrected", {HistType::kTH1D, {axisPtTrigger}}); + histos.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger}}}); + + if (cfgGetNsigmaQA) { + if (!cfgUseItsPID) { + histos.add("TofTpcNsigma_before", "", {HistType::kTHnSparseD, {{axisNsigmaTPC, axisNsigmaTOF, axisPt}}}); + histos.add("TofTpcNsigma_after", "", {HistType::kTHnSparseD, {{axisNsigmaTPC, axisNsigmaTOF, axisPt}}}); + } + if (cfgUseItsPID) { + histos.add("TofItsNsigma_before", "", {HistType::kTHnSparseD, {{axisNsigmaITS, axisNsigmaTOF, axisPt}}}); + histos.add("TofItsNsigma_after", "", {HistType::kTHnSparseD, {{axisNsigmaITS, axisNsigmaTOF, axisPt}}}); + } + } + } + + if (cfgPIDParticle == kK0 || cfgPIDParticle == kLambda || cfgPIDParticle == kPhi) { + histos.add("Trig_histReso", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisPtTrigger, massAxisReso}}}); + } + } + if (doprocessMixed || doprocessMixedReso) { + histos.add("deltaEta_deltaPhi_mixed", "", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); + } + + histos.add("eventcount", "bin", {HistType::kTH1F, {{4, 0, 4, "bin"}}}); // histogram to see how many events are in the same and mixed event + + LOGF(info, "Initializing correlation container"); + 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 corrAxisReso = {{axisSample, "Sample"}, + {axisVertex, "z-vtx (cm)"}, + {axisPtTrigger, "p_{T} (GeV/c)"}, + {massAxisReso}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisDeltaEta, "#Delta#eta"}}; + std::vector effAxis = { + {axisEtaEfficiency, "#eta"}, + {axisPtEfficiency, "p_{T} (GeV/c)"}, + {axisVertexEfficiency, "z-vtx (cm)"}, + }; + std::vector userAxis; + + if (cfgPIDParticle == kCharged || cfgPIDParticle == kPions || cfgPIDParticle == kKaons || cfgPIDParticle == kProtons) { + same.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); + mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userAxis)); + } + + if (cfgPIDParticle == kK0 || cfgPIDParticle == kLambda || cfgPIDParticle == kPhi) { + sameReso.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxisReso, effAxis, userAxis)); + mixedReso.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxisReso, effAxis, userAxis)); + } + LOGF(info, "End of init"); + } + + 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(); + } + + template + float getCentrality(TCollision const& collision) + { + 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(); + } + return cent; + } + + template + bool trackSelected(TTrack track) + { + if (cfgFuncParas.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > cfgFuncParas.fPtDepDCAxy->Eval(track.pt()))) + return false; + return ((track.tpcNClsFound() >= cfgTpcCluster) && (track.tpcNClsCrossedRows() >= cfgTpcCrossRows) && (track.itsNCls() >= cfgITScluster)); + } + + template + bool selectionV0Daughter(TTrack const& track, int pid) + { + if (!(track.itsNCls() > cfgITScluster)) + return 0; + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < cfgTpcCluster) + return false; + if (!(track.tpcNClsCrossedRows() > cfgTpcCrossRows)) + return 0; + + if (cfgUseOnlyTPC) { + if (pid == kPions && std::abs(track.tpcNSigmaPi()) > cfgTpcCut) + return false; + if (pid == kKaons && std::abs(track.tpcNSigmaKa()) > cfgTpcCut) + return false; + if (pid == kProtons && std::abs(track.tpcNSigmaPr()) > cfgTpcCut) + return false; + } else { + int partIndex = getNsigmaPID(track); + int pidIndex = partIndex; // 1 = pion, 2 = kaon, 3 = proton + if (pidIndex != pid) + 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 nSigmaTOF = {track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + std::array nSigmaITS = {itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track), itsResponse.nSigmaITS(track)}; + int pid = -1; // -1 = not identified, 1 = pion, 2 = kaon, 3 = proton + + std::array nSigmaToUse = cfgUseItsPID ? nSigmaITS : nSigmaTPC; // Choose which nSigma to use: TPC or ITS + std::array detectorNsigmaCut = cfgUseItsPID ? itsNsigmaCut : tpcNsigmaCut; // Choose which nSigma to use: TPC or ITS + + bool isPion, isKaon, isProton; + bool isDetectedPion = nSigmaToUse[iPionUp] < detectorNsigmaCut[iPionUp] && nSigmaToUse[iPionUp] > detectorNsigmaCut[iPionLow]; + bool isDetectedKaon = nSigmaToUse[iKaonUp] < detectorNsigmaCut[iKaonUp] && nSigmaToUse[iKaonUp] > detectorNsigmaCut[iKaonLow]; + bool isDetectedProton = nSigmaToUse[iProtonUp] < detectorNsigmaCut[iProtonUp] && nSigmaToUse[iProtonUp] > detectorNsigmaCut[iProtonLow]; + + bool isTofPion = nSigmaTOF[iPionUp] < tofNsigmaCut[iPionUp] && nSigmaTOF[iPionUp] > tofNsigmaCut[iPionLow]; + bool isTofKaon = nSigmaTOF[iKaonUp] < tofNsigmaCut[iKaonUp] && nSigmaTOF[iKaonUp] > tofNsigmaCut[iKaonLow]; + bool isTofProton = nSigmaTOF[iProtonUp] < tofNsigmaCut[iProtonUp] && nSigmaTOF[iProtonUp] > tofNsigmaCut[iProtonLow]; + + if (track.pt() > cfgTofPtCut && !track.hasTOF()) { + return -1; + } else if (track.pt() > cfgTofPtCut && track.hasTOF()) { + isPion = isTofPion && isDetectedPion; + isKaon = isTofKaon && isDetectedKaon; + isProton = isTofProton && isDetectedProton; + } else { + isPion = isDetectedPion; + isKaon = isDetectedKaon; + isProton = isDetectedProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + return -1; // more than one particle satisfy the criteria + } + + if (isPion) { + pid = kPions; + } else if (isKaon) { + pid = kKaons; + } else if (isProton) { + pid = kProtons; + } else { + return -1; // no particle satisfies the criteria + } + + return pid; // -1 = not identified, 1 = pion, 2 = kaon, 3 = proton + } + + void loadCorrection(uint64_t timestamp) + { + if (correctionsLoaded) { + return; + } + if (cfgEfficiency.value.empty() == false) { + if (cfgLocalEfficiency > 0) { + TFile* fEfficiencyTrigger = TFile::Open(cfgEfficiency.value.c_str(), "READ"); + mEfficiency = reinterpret_cast(fEfficiencyTrigger->Get("ccdb_object")); + } else { + 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 (cfgCentralityWeight.value.empty() == false) { + mCentralityWeight = ccdb->getForTimeStamp(cfgCentralityWeight, timestamp); + if (mCentralityWeight == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgCentralityWeight.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgCentralityWeight.value.c_str(), (void*)mCentralityWeight); + } + correctionsLoaded = true; + } + + bool getEfficiencyCorrection(float& weight_nue, float eta, float pt, float posZ) + { + float eff = 1.; + if (mEfficiency) { + int etaBin = mEfficiency->GetXaxis()->FindBin(eta); + int ptBin = mEfficiency->GetYaxis()->FindBin(pt); + int zBin = mEfficiency->GetZaxis()->FindBin(posZ); + eff = mEfficiency->GetBinContent(etaBin, ptBin, zBin); + } else { + eff = 1.0; + } + if (eff == 0) + return false; + weight_nue = 1. / eff; + return true; + } + + bool getCentralityWeight(float& weightCent, const float centrality) + { + float weight = 1.; + if (mCentralityWeight) + weight = mCentralityWeight->GetBinContent(mCentralityWeight->FindBin(centrality)); + else + weight = 1.0; + if (weight == 0) + return false; + weightCent = weight; + return true; + } + + // fill multiple histograms + template + void fillYield(TCollision collision, TTracks tracks) // function to fill the yield and etaphi histograms. + { + float weff1 = 1; + float vtxz = collision.posZ(); + for (auto const& track1 : tracks) { + if (!trackSelected(track1)) + continue; + if (cfgPIDParticle && getNsigmaPID(track1) != cfgPIDParticle) + continue; // if PID is selected, check if the track has the right PID + if (!getEfficiencyCorrection(weff1, track1.eta(), track1.pt(), vtxz)) + continue; + histos.fill(HIST("Phi"), RecoDecay::constrainAngle(track1.phi(), 0.0)); + histos.fill(HIST("Eta"), track1.eta()); + histos.fill(HIST("EtaCorrected"), track1.eta(), weff1); + histos.fill(HIST("pT"), track1.pt()); + histos.fill(HIST("pTCorrected"), track1.pt(), weff1); + } + } + + template + void fillNsigmaAfterCut(TTrack track1, Int_t pid) // function to fill the QA after Nsigma selection + { + switch (pid) { + case 1: // For Pions + if (!cfgUseItsPID) + histos.fill(HIST("TofTpcNsigma_after"), track1.tpcNSigmaPi(), track1.tofNSigmaPi(), track1.pt()); + if (cfgUseItsPID) + histos.fill(HIST("TofItsNsigma_after"), itsResponse.nSigmaITS(track1), track1.tofNSigmaPi(), track1.pt()); + break; + case 2: // For Kaons + if (!cfgUseItsPID) + histos.fill(HIST("TofTpcNsigma_after"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); + if (cfgUseItsPID) + histos.fill(HIST("TofItsNsigma_after"), itsResponse.nSigmaITS(track1), track1.tofNSigmaKa(), track1.pt()); + break; + case 3: // For Protons + if (!cfgUseItsPID) + histos.fill(HIST("TofTpcNsigma_after"), track1.tpcNSigmaPr(), track1.tofNSigmaPr(), track1.pt()); + if (cfgUseItsPID) + histos.fill(HIST("TofItsNsigma_after"), itsResponse.nSigmaITS(track1), track1.tofNSigmaPr(), track1.pt()); + break; + } // end of switch + } + + float getDPhiStar(float charge1, float charge2, float phi1, float phi2, float pt1, float pt2, float radius, int magField) + { + 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, int magneticField, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + // Cache efficiency for particles (too many FindBin lookups) + if (mEfficiency) { + efficiencyAssociatedCache.clear(); + efficiencyAssociatedCache.reserve(tracks2.size()); + for (const auto& track2 : tracks2) { + float weff = 1.; + getEfficiencyCorrection(weff, track2.eta(), track2.pt(), posZ); + efficiencyAssociatedCache.push_back(weff); + } + } + + if (system == SameEvent) { + if (!cfgCentTableUnavailable) + histos.fill(HIST("Centrality_used"), cent); + histos.fill(HIST("Nch_used"), tracks1.size()); + } + + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + float triggerWeight = 1.0f; + float associatedWeight = 1.0f; + // loop over all tracks + for (auto const& track1 : tracks1) { + + if (!trackSelected(track1)) + continue; + + // Fill Nsigma QA + if (cfgGetNsigmaQA && !cfgUseItsPID) { + if (cfgPIDParticle == kPions) + histos.fill(HIST("TofTpcNsigma_before"), track1.tpcNSigmaPi(), track1.tofNSigmaPi(), track1.pt()); + if (cfgPIDParticle == kKaons) + histos.fill(HIST("TofTpcNsigma_before"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); + if (cfgPIDParticle == kProtons) + histos.fill(HIST("TofTpcNsigma_before"), track1.tpcNSigmaPr(), track1.tofNSigmaPr(), track1.pt()); + } + if (cfgGetNsigmaQA && cfgUseItsPID) { + if (cfgPIDParticle == kPions) + histos.fill(HIST("TofItsNsigma_before"), itsResponse.nSigmaITS(track1), track1.tofNSigmaPi(), track1.pt()); + if (cfgPIDParticle == kKaons) + histos.fill(HIST("TofItsNsigma_before"), itsResponse.nSigmaITS(track1), track1.tofNSigmaKa(), track1.pt()); + if (cfgPIDParticle == kProtons) + histos.fill(HIST("TofItsNsigma_before"), itsResponse.nSigmaITS(track1), track1.tofNSigmaPr(), track1.pt()); + } + + if (cfgPIDParticle && getNsigmaPID(track1) != cfgPIDParticle) + continue; // if PID is selected, check if the track has the right PID + + if (cfgGetNsigmaQA) + fillNsigmaAfterCut(track1, cfgPIDParticle); + + if (!getEfficiencyCorrection(triggerWeight, track1.eta(), track1.pt(), posZ)) + continue; + if (system == SameEvent) { + histos.fill(HIST("Trig_hist"), fSampleIndex, posZ, track1.pt(), eventWeight * triggerWeight); + } + + for (auto const& track2 : tracks2) { + + if (!trackSelected(track2)) + continue; + if (mEfficiency) { + associatedWeight = efficiencyAssociatedCache[track2.filteredIndex()]; + } + + if (!cfgUsePtOrder && track1.globalIndex() == track2.globalIndex()) + continue; // For pt-differential correlations, skip if the trigger and associate are the same track + if (cfgUsePtOrder && system == SameEvent && track1.pt() <= track2.pt()) + continue; // Without pt-differential correlations, skip if the trigger pt is less than the associate pt + if (cfgUsePtOrder && system == MixedEvent && cfgUsePtOrderInMixEvent && track1.pt() <= track2.pt()) + continue; // For pt-differential correlations in mixed events, skip if the trigger pt is less than the associate pt + + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -PIHalf); + float deltaEta = track1.eta() - track2.eta(); + + if (std::abs(deltaEta) < cfgCutMerging) { + + double dPhiStarHigh = getDPhiStar(track1.sign(), track2.sign(), track1.phi(), track2.phi(), track1.pt(), track2.pt(), cfgRadiusHigh, magneticField); + double dPhiStarLow = getDPhiStar(track1.sign(), track2.sign(), track1.phi(), track2.phi(), track1.pt(), track2.pt(), cfgRadiusLow, magneticField); + + const double kLimit = 3.0 * cfgCutMerging; + + bool bIsBelow = false; + + 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.sign(), track2.sign(), track1.phi(), track2.phi(), track1.pt(), track2.pt(), rad, magneticField); + if (std::abs(dPhiStar) < kLimit) { + bIsBelow = true; + 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, eventWeight * triggerWeight * associatedWeight); + histos.fill(HIST("deltaEta_deltaPhi_same"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } else if (system == MixedEvent) { + + mixed->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), track2.pt(), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + histos.fill(HIST("deltaEta_deltaPhi_mixed"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } + } + } + } + + template + void fillCorrelationsReso(TV0Tracks tracks1, TTracksAssoc tracks2, float posZ, float posY, float posX, int system, int magneticField, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + { + // Cache efficiency for particles (too many FindBin lookups) + if (mEfficiency) { + efficiencyAssociatedCache.clear(); + efficiencyAssociatedCache.reserve(tracks2.size()); + for (const auto& track2 : tracks2) { + float weff = 1.; + getEfficiencyCorrection(weff, track2.eta(), track2.pt(), posZ); + efficiencyAssociatedCache.push_back(weff); + } + } + + if (system == SameEvent) { + if (!cfgCentTableUnavailable) + histos.fill(HIST("Centrality_used"), cent); + histos.fill(HIST("Nch_used"), tracks2.size()); // Taking Nch from tracks2 since tracks1 are V0s + } + + int fSampleIndex = gRandom->Uniform(0, cfgSampleSize); + + float triggerWeight = 1.0f; + float associatedWeight = 1.0f; + // loop over all tracks + for (auto const& track1 : tracks1) { + + double resoMass = -1; + + // 4 = kshort, 5 = lambda, 6 = phi + if (cfgPIDParticle == kK0) { + if (!isSelectedK0(track1, posZ, posY, posX)) + continue; // Reject if called for K0 but V0 is not K0 + + resoMass = track1.mK0Short(); + } + + if (cfgPIDParticle == kLambda) { + if (!isSelectedLambda(track1, posZ, posY, posX)) + continue; // Reject if called for Lambda but V0 is not lambda + + resoMass = track1.mLambda(); + } + + if (system == SameEvent) { + histos.fill(HIST("Trig_histReso"), fSampleIndex, posZ, track1.pt(), resoMass, eventWeight * triggerWeight); + } + + for (auto const& track2 : tracks2) { + + if (!trackSelected(track2)) + continue; + if (track2.pt() < cfgCutPtMin || track2.pt() > cfgCutPtMax) // Select associated particles in the pt range 0.2 - 3.0 GeV/c + continue; + if (mEfficiency) { + associatedWeight = efficiencyAssociatedCache[track2.filteredIndex()]; + } + + if (cfgUsePtOrder && system == SameEvent && track1.pt() <= track2.pt()) + continue; // Without pt-differential correlations, skip if the trigger pt is less than the associate pt + if (cfgUsePtOrder && system == MixedEvent && cfgUsePtOrderInMixEvent && track1.pt() <= track2.pt()) + continue; // For pt-differential correlations in mixed events, skip if the trigger pt is less than the associate pt + + float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -PIHalf); + float deltaEta = track1.eta() - track2.eta(); + + if (std::abs(deltaEta) < cfgCutMerging) { + + double dPhiStarHigh = getDPhiStar(0, track2.sign(), track1.phi(), track2.phi(), track1.pt(), track2.pt(), cfgRadiusHigh, magneticField); + double dPhiStarLow = getDPhiStar(0, track2.sign(), track1.phi(), track2.phi(), track1.pt(), track2.pt(), cfgRadiusLow, magneticField); + + const double kLimit = 3.0 * cfgCutMerging; + + bool bIsBelow = false; + + if (std::abs(dPhiStarLow) < kLimit || std::abs(dPhiStarHigh) < kLimit || dPhiStarLow * dPhiStarHigh < 0) { + for (double rad(cfgRadiusLow); rad < cfgRadiusHigh; rad += 0.01) { + double dPhiStar = getDPhiStar(0, track2.sign(), track1.phi(), track2.phi(), track1.pt(), track2.pt(), rad, magneticField); + if (std::abs(dPhiStar) < kLimit) { + bIsBelow = true; + break; + } + } + if (bIsBelow) + continue; + } + } + + // fill the right sparse and histograms + if (system == SameEvent) { + sameReso->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), resoMass, deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + histos.fill(HIST("deltaEta_deltaPhi_same"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } else if (system == MixedEvent) { + mixedReso->getPairHist()->Fill(step, fSampleIndex, posZ, track1.pt(), resoMass, deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + histos.fill(HIST("deltaEta_deltaPhi_mixed"), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight); + } + } + } + } + + template + bool selectionEvent(TCollision collision, const int mult, const float cent, const bool fillCounter) + { + if (fillCounter) + histos.fill(HIST("hEventCount"), kFilteredEvents); + if (!collision.sel8()) { + return 0; + } + if (fillCounter) + histos.fill(HIST("hEventCount"), kAfterSel8); + + if (eventCuts[kUseNoTimeFrameBorder][kEvCut1] && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return 0; + } + if (fillCounter && eventCuts[kUseNoTimeFrameBorder][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseNoTimeFrameBorder); + + if (eventCuts[kUseNoITSROFrameBorder][kEvCut1] && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return 0; + } + if (fillCounter && eventCuts[kUseNoITSROFrameBorder][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseNoITSROFrameBorder); + + if (eventCuts[kUseNoSameBunchPileup][kEvCut1] && !collision.selection_bit(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 (fillCounter && eventCuts[kUseNoSameBunchPileup][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseNoSameBunchPileup); + + if (eventCuts[kUseGoodZvtxFT0vsPV][kEvCut1] && !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 (fillCounter && eventCuts[kUseGoodZvtxFT0vsPV][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseGoodZvtxFT0vsPV); + + if (eventCuts[kUseNoCollInTimeRangeStandard][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (fillCounter && eventCuts[kUseNoCollInTimeRangeStandard][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseNoCollInTimeRangeStandard); + + if (eventCuts[kUseGoodITSLayersAll][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // from Jan 9 2025 AOT meeting + // cut time intervals with dead ITS staves + return 0; + } + if (fillCounter && eventCuts[kUseGoodITSLayersAll][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseGoodITSLayersAll); + + if (eventCuts[kUseNoCollInRofStandard][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + // no other collisions in this Readout Frame with per-collision multiplicity above threshold + return 0; + } + if (fillCounter && eventCuts[kUseNoCollInRofStandard][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseNoCollInRofStandard); + + if (eventCuts[kUseNoHighMultCollInPrevRof][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + // veto an event if FT0C amplitude in previous ITS ROF is above threshold + return 0; + } + if (fillCounter && eventCuts[kUseNoHighMultCollInPrevRof][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseNoHighMultCollInPrevRof); + + auto multNTracksPV = collision.multNTracksPV(); + auto occupancy = collision.trackOccupancyInTimeRange(); + + if (eventCuts[kUseOccupancy][kEvCut1] && (occupancy < cfgCutOccupancyMin || occupancy > cfgCutOccupancyMax)) { + return 0; + } + if (fillCounter && eventCuts[kUseOccupancy][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseOccupancy); + + if (eventCuts[kUseMultCorrCut][kEvCut1]) { + if (cfgFuncParas.cfgMultPVT0CCutEnabled && !cfgCentTableUnavailable) { + if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(cent)) + return 0; + if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(cent)) + return 0; + } + if (cfgFuncParas.cfgMultT0CCutEnabled && !cfgCentTableUnavailable) { + if (mult < cfgFuncParas.fMultT0CCutLow->Eval(cent)) + return 0; + if (mult > cfgFuncParas.fMultT0CCutHigh->Eval(cent)) + return 0; + } + if (cfgFuncParas.cfgMultGlobalPVCutEnabled) { + if (mult < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) + return 0; + if (mult > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) + return 0; + } + if (cfgFuncParas.cfgMultMultV0ACutEnabled) { + if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(mult)) + return 0; + if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(mult)) + return 0; + } + } + + if (fillCounter && eventCuts[kUseMultCorrCut][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseMultCorrCut); + + // V0A T0A 5 sigma cut + if (eventCuts[kUseT0AV0ACut][kEvCut1] && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > cfgV0AT0Acut * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) + return 0; + if (fillCounter && eventCuts[kUseT0AV0ACut][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseT0AV0ACut); + + if (eventCuts[kUseVertexITSTPC][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return 0; + if (fillCounter && eventCuts[kUseVertexITSTPC][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseVertexITSTPC); + + if (eventCuts[kUseTVXinTRD][kEvCut1] && collision.alias_bit(kTVXinTRD)) { + return 0; + } + if (fillCounter && eventCuts[kUseTVXinTRD][kEvCut1]) + histos.fill(HIST("hEventCount"), kUseTVXinTRD); + + return 1; + } + + void processSame(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks, aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); + float cent = -1.; + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + cent = getCentrality(collision); + if (cfgUseAdditionalEventCut && !selectionEvent(collision, tracks.size(), cent, true)) + return; + + loadCorrection(bc.timestamp()); + if (!cfgCentTableUnavailable) { + getCentralityWeight(weightCent, cent); + histos.fill(HIST("Centrality"), cent); + histos.fill(HIST("CentralityWeighted"), cent, weightCent); + } + histos.fill(HIST("Nch"), tracks.size()); + histos.fill(HIST("zVtx"), collision.posZ()); + + if (cfgSelCollByNch && (tracks.size() < cfgCutMultMin || tracks.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + histos.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + fillYield(collision, tracks); + + same->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + fillCorrelations(tracks, tracks, collision.posZ(), SameEvent, getMagneticField(bc.timestamp()), cent, weightCent); + } + PROCESS_SWITCH(PidDiHadron, processSame, "Process same event", true); + + // the process for filling the mixed events + void processMixed(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::BCsWithTimestamps const&) + { + + auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(tracks, tracks); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -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; + if (!collision1.sel8() || !collision2.sel8()) + continue; + + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + float cent1 = -1; + float cent2 = -1; + if (!cfgCentTableUnavailable) { + cent1 = getCentrality(collision1); + cent2 = getCentrality(collision2); + } + if (cfgUseAdditionalEventCut && !selectionEvent(collision1, tracks1.size(), cent1, false)) + continue; + if (cfgUseAdditionalEventCut && !selectionEvent(collision2, tracks2.size(), cent2, false)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent1 < cfgCutCentMin || cent1 >= cfgCutCentMax)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent2 < cfgCutCentMin || cent2 >= cfgCutCentMax)) + continue; + + histos.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + loadCorrection(bc.timestamp()); + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + getCentralityWeight(weightCent, cent1); + + fillCorrelations(tracks1, tracks2, collision1.posZ(), MixedEvent, getMagneticField(bc.timestamp()), cent1, eventWeight * weightCent); + } + } + PROCESS_SWITCH(PidDiHadron, processMixed, "Process mixed events", true); + + template + bool isSelectedK0(V0 const& candidate, float posZ, float posY, float posX) + { + 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() < resoCutVals[kPosTrackPt][iK0] || negtrack.pt() < resoCutVals[kNegTrackPt][iK0]) + return false; + histos.fill(HIST("hK0Count"), 1.5); + if (mk0 < resoCutVals[kMassMin][iK0] && mk0 > resoCutVals[kMassMax][iK0]) + return false; + histos.fill(HIST("hK0Count"), 2.5); + // Rapidity correction + if (candidate.yK0Short() > resoCutVals[kRapidity][iK0]) + return false; + histos.fill(HIST("hK0Count"), 3.5); + // DCA cuts for K0short + if (std::abs(candidate.dcapostopv()) < resoCutVals[kDCAPosToPVMin][iK0] || std::abs(candidate.dcanegtopv()) < resoCutVals[kDCANegToPVMin][iK0]) + return false; + histos.fill(HIST("hK0Count"), 4.5); + if (std::abs(candidate.dcaV0daughters()) > resoSwitchVals[kDCABetDaug][iK0]) + return false; + histos.fill(HIST("hK0Count"), 5.5); + // v0 radius cuts + if (resoSwitchVals[kUseV0Radius][iK0] && (candidate.v0radius() < resoCutVals[kRadiusMin][iK0] || candidate.v0radius() > resoCutVals[kRadiusMax][iK0])) + return false; + histos.fill(HIST("hK0Count"), 6.5); + // cosine pointing angle cuts + if (candidate.v0cosPA() < resoCutVals[kCosPA][iK0]) + return false; + histos.fill(HIST("hK0Count"), 7.5); + // Proper lifetime + float cTauK0 = candidate.distovertotmom(posX, posY, posZ) * massK0Short; + if (resoSwitchVals[kUseProperLifetime][iK0] && std::abs(cTauK0) > resoCutVals[kLifeTime][iK0]) + return false; + histos.fill(HIST("hK0Count"), 8.5); + // ArmenterosPodolanskiCut + if (resoSwitchVals[kUseArmPodCut][iK0] && (candidate.qtarm() / std::abs(candidate.alpha())) < resoCutVals[kArmPodMinVal][iK0]) + return false; + histos.fill(HIST("hK0Count"), 9.5); + // Selection on V0 daughters + if (!selectionV0Daughter(postrack, kPions) || !selectionV0Daughter(negtrack, kPions)) + return false; + histos.fill(HIST("hK0Count"), 10.5); + + histos.fill(HIST("hK0Phi"), candidate.phi()); + histos.fill(HIST("hK0Eta"), candidate.eta()); + histos.fill(HIST("PiPlusTPC_K0"), postrack.pt(), postrack.tpcNSigmaPi()); + histos.fill(HIST("PiPlusTOF_K0"), postrack.pt(), postrack.tofNSigmaPi()); + histos.fill(HIST("PiMinusTPC_K0"), negtrack.pt(), negtrack.tpcNSigmaPi()); + histos.fill(HIST("PiMinusTOF_K0"), negtrack.pt(), negtrack.tofNSigmaPi()); + + return true; + } + + template + bool isSelectedLambda(V0 const& candidate, float posZ, float posY, float posX) + { + 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() < resoCutVals[kPosTrackPt][iLambda] || negtrack.pt() < resoCutVals[kNegTrackPt][iLambda]) + return false; + + histos.fill(HIST("hLambdaCount"), 1.5); + if (mlambda > resoCutVals[kMassMin][iLambda] && mlambda < resoCutVals[kMassMax][iLambda]) + isL = true; + if (mantilambda > resoCutVals[kMassMin][iLambda] && mantilambda < resoCutVals[kMassMax][iLambda]) + isAL = true; + + if (!isL && !isAL) { + return false; + } + histos.fill(HIST("hLambdaCount"), 2.5); + + // Rapidity correction + if (candidate.yLambda() > resoCutVals[kRapidity][iLambda]) + return false; + histos.fill(HIST("hLambdaCount"), 3.5); + // DCA cuts for lambda and antilambda + if (isL) { + if (std::abs(candidate.dcapostopv()) < resoCutVals[kDCAPosToPVMin][iLambda] || std::abs(candidate.dcanegtopv()) < resoCutVals[kDCANegToPVMin][iLambda]) + return false; + } + if (isAL) { + if (std::abs(candidate.dcapostopv()) < resoCutVals[kDCANegToPVMin][iLambda] || std::abs(candidate.dcanegtopv()) < resoCutVals[kDCAPosToPVMin][iLambda]) + return false; + } + histos.fill(HIST("hLambdaCount"), 4.5); + if (std::abs(candidate.dcaV0daughters()) > resoSwitchVals[kDCABetDaug][iLambda]) + return false; + histos.fill(HIST("hLambdaCount"), 5.5); + // v0 radius cuts + if (resoSwitchVals[kUseV0Radius][iLambda] && (candidate.v0radius() < resoCutVals[kRadiusMin][iLambda] || candidate.v0radius() > resoCutVals[kRadiusMax][iLambda])) + return false; + histos.fill(HIST("hLambdaCount"), 6.5); + // cosine pointing angle cuts + if (candidate.v0cosPA() < resoCutVals[kCosPA][iLambda]) + return false; + histos.fill(HIST("hLambdaCount"), 7.5); + // Proper lifetime + float cTauLambda = candidate.distovertotmom(posX, posY, posZ) * massLambda; + if (resoSwitchVals[kUseProperLifetime][iLambda] && cTauLambda > resoCutVals[kLifeTime][iLambda]) + return false; + histos.fill(HIST("hLambdaCount"), 8.5); + if (isL) { + if (!selectionV0Daughter(postrack, kProtons) || !selectionV0Daughter(negtrack, kPions)) + return false; + } + if (isAL) { + if (!selectionV0Daughter(postrack, kPions) || !selectionV0Daughter(negtrack, kProtons)) + return false; + } + histos.fill(HIST("hLambdaCount"), 9.5); + + if (!cfgUseAntiLambda && isAL) { // Reject the track if it is antilambda + return false; + } + + histos.fill(HIST("hLambdaPhi"), candidate.phi()); + histos.fill(HIST("hLambdaEta"), candidate.eta()); + histos.fill(HIST("PrPlusTPC_L"), postrack.pt(), postrack.tpcNSigmaPr()); + histos.fill(HIST("PrPlusTOF_L"), postrack.pt(), postrack.tofNSigmaPr()); + histos.fill(HIST("PiMinusTPC_L"), negtrack.pt(), negtrack.tpcNSigmaPi()); + histos.fill(HIST("PiMinusTOF_L"), negtrack.pt(), negtrack.tofNSigmaPi()); + + return true; + } + + double massKaPlus = o2::constants::physics::MassKPlus; // same as MassKMinus + double massLambda = o2::constants::physics::MassLambda; // same as MassLambda0 and MassLambda0Bar + double massK0Short = o2::constants::physics::MassK0Short; // same as o2::constants::physics::MassK0 and o2::constants::physics::MassK0Bar + + void processSameReso(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks, aod::BCsWithTimestamps const&, aod::V0Datas const& V0s) + { + auto bc = collision.bc_as(); + float cent = -1.; + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + cent = getCentrality(collision); + if (cfgUseAdditionalEventCut && !selectionEvent(collision, tracks.size(), cent, true)) + return; + + loadCorrection(bc.timestamp()); + if (!cfgCentTableUnavailable) { + getCentralityWeight(weightCent, cent); + histos.fill(HIST("Centrality"), cent); + histos.fill(HIST("CentralityWeighted"), cent, weightCent); + } + histos.fill(HIST("Nch"), tracks.size()); + histos.fill(HIST("zVtx"), collision.posZ()); + + if (cfgSelCollByNch && (tracks.size() < cfgCutMultMin || tracks.size() >= cfgCutMultMax)) { + return; + } + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent < cfgCutCentMin || cent >= cfgCutCentMax)) { + return; + } + + histos.fill(HIST("eventcount"), SameEvent); // because its same event i put it in the 1 bin + + sameReso->fillEvent(tracks.size(), CorrelationContainer::kCFStepReconstructed); + fillCorrelationsReso(V0s, tracks, collision.posZ(), collision.posY(), collision.posX(), SameEvent, getMagneticField(bc.timestamp()), cent, weightCent); + } + PROCESS_SWITCH(PidDiHadron, processSameReso, "Process same event for resonances", true); + + void processMixedReso(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::BCsWithTimestamps const&, aod::V0Datas const& V0s) + { + auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { + auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); + auto mult = associatedTracks.size(); + return mult; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getTracksSize)>; + + MixedBinning binningOnVtxAndMult{{getTracksSize}, {axisVtxMix, axisMultMix}, true}; + + auto tracksTuple = std::make_tuple(V0s, tracks); + Pair pairs{binningOnVtxAndMult, cfgMixEventNumMin, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + for (auto it = pairs.begin(); it != pairs.end(); it++) { + auto& [collision1, v0s1, collision2, tracks2] = *it; + if (!collision1.sel8() || !collision2.sel8()) + continue; + + auto tracks1 = tracks.sliceByCached(o2::aod::track::collisionId, collision1.globalIndex(), this->cache); + if (cfgSelCollByNch && (tracks1.size() < cfgCutMultMin || tracks1.size() >= cfgCutMultMax)) + continue; + + if (cfgSelCollByNch && (tracks2.size() < cfgCutMultMin || tracks2.size() >= cfgCutMultMax)) + continue; + + float cent1 = -1; + float cent2 = -1; + if (!cfgCentTableUnavailable) { + cent1 = getCentrality(collision1); + cent2 = getCentrality(collision2); + } + if (cfgUseAdditionalEventCut && !selectionEvent(collision1, tracks1.size(), cent1, false)) + continue; + if (cfgUseAdditionalEventCut && !selectionEvent(collision2, tracks2.size(), cent2, false)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent1 < cfgCutCentMin || cent1 >= cfgCutCentMax)) + continue; + + if (!cfgSelCollByNch && !cfgCentTableUnavailable && (cent2 < cfgCutCentMin || cent2 >= cfgCutCentMax)) + continue; + + histos.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin + auto bc = collision1.bc_as(); + loadCorrection(bc.timestamp()); + float eventWeight = 1.0f; + if (cfgUseEventWeights) { + eventWeight = 1.0f / it.currentWindowNeighbours(); + } + float weightCent = 1.0f; + if (!cfgCentTableUnavailable) + getCentralityWeight(weightCent, cent1); + + fillCorrelationsReso(v0s1, tracks2, collision1.posZ(), collision1.posY(), collision1.posX(), MixedEvent, getMagneticField(bc.timestamp()), cent1, eventWeight * weightCent); + } + } + PROCESS_SWITCH(PidDiHadron, processMixedReso, "Process mixed events", true); +}; + +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..b12ee5481a1 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/r2p2-4-id.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/r2p2-4-id.cxx @@ -9,12 +9,16 @@ // 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 "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" + #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include using namespace o2; using namespace o2::framework; @@ -49,12 +53,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 +262,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/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationPp.cxx b/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationPp.cxx new file mode 100644 index 00000000000..24cfc066838 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationPp.cxx @@ -0,0 +1,574 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file twoParticleCorrelationPp.cxx +/// \brief Task for two particle correlation in pp in order to calculate a baseline in a template fit for the flow coefficients +/// \author Josué Martínez García + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" + +#include "Common/Core/RecoDecay.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/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +static constexpr float cfgPairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; +constexpr float kThreeHalfPi = 1.5f * PI; + +struct TwoParticleCorrelationPp { + + // Declare configurables on events/collisions + Configurable minMultiplicity{"minMultiplicity", 2, {"Range on multiplicity"}}; + Configurable range1Max{"range1Max", 10, {"Range on multiplicity"}}; + Configurable range2Min{"range2Min", 11, {"Range on multiplicity"}}; + Configurable range2Max{"range2Max", 20, {"Range on multiplicity"}}; + Configurable range3Min{"range3Min", 21, {"Range on multiplicity"}}; + Configurable range3Max{"range3Max", 30, {"Range on multiplicity"}}; + Configurable range4Min{"range4Min", 31, {"Range on multiplicity"}}; + Configurable range4Max{"range4Max", 40, {"Range on multiplicity"}}; + Configurable range5Min{"range5Min", 41, {"Range on multiplicity"}}; + Configurable range5Max{"range5Max", 50, {"Range on multiplicity"}}; + Configurable nEventsMixed{"nEventsMixed", 5, {"Events to be Mixed"}}; + Configurable evSel8{"evSel8", true, {"rejects collisions using sel8()"}}; + Configurable cfgZVtxCut = {"cfgZVtxCut", 10.0, "Vertex z cut. Default 10 cm"}; + Configurable evSelkNoSameBunchPileup{"evSelkNoSameBunchPileup", true, {"rejects collisions which are associated with the same found-by-T0 bunch crossing"}}; + Configurable evSelkNoITSROFrameBorder{"evSelkNoITSROFrameBorder", true, {"reject events at ITS ROF border"}}; + Configurable evSelkNoTimeFrameBorder{"evSelkNoTimeFrameBorder", true, {"reject events at TF border"}}; + Configurable evSelkIsGoodZvtxFT0vsPV{"evSelkIsGoodZvtxFT0vsPV", 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 evSelkNoCollInTimeRangeStandard{"evSelkNoCollInTimeRangeStandard", true, {"no collisions in specified time range"}}; + // Declare configurables on tracks + Configurable cutMyptMin{"cutMyptMin", 0.2, {"My Track cut"}}; + Configurable cutMyptMax{"cutMyptMax", 3., {"My Track cut"}}; + Configurable cutMyetaMin{"cutMyetaMin", -0.8, {"My Track cut"}}; + Configurable cutMyetaMax{"cutMyetaMax", 0.8, {"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"}}; + // Declare configurables for correlations + + Configurable> cfgPairCut{"cfgPairCut", + {cfgPairCutDefaults[0], + 5, + {"Photon", "K0", "Lambda", "Phi", "Rho"}}, + "Pair cuts on various particles"}; + // Configurable cfgTwoTrackCut{"cfgTwoTrackCut", -1, {"Two track cut"}}; + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {32, -PIHalf, kThreeHalfPi}, "delta phi axis for histograms"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {32, -1.6, 1.6}, "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}, "pt associated axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110.1}, "multiplicity / multiplicity 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"}; + + // Output definitions + OutputObj same{"sameEvent"}; + OutputObj mixed{"mixedEvent"}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + PairCuts mPairCuts; + bool doPairCuts = false; + + void init(InitContext&) + { + LOGF(info, "Starting init"); + + const AxisSpec axisCountTracks{17, -0.5, 16.5}; + const AxisSpec axisCountEvents{8, -0.5, 7.5}; + + histos.add("yields", "multiplicity vs pT vs eta", {HistType::kTH3F, {{100, 0, 100, "multiplicity"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); + histos.add("etaphi", "multiplicity vs eta vs phi", {HistType::kTH3F, {{100, 0, 100, "multiplicity"}, {100, -2, 2, "#eta"}, {64, 0., TwoPI, "#varphi"}}}); + histos.add("sameEvent2D", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_2_10", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_11_20", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_21_30", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_31_40", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_41_50", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent2D", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_2_10", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_11_20", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_21_30", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_31_40", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_41_50", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("Tracks/hTracksAfterCuts", " ; ; counts", kTH1F, {axisCountTracks}); + histos.add("Events/hEventsAfterCuts", " ; ; counts", kTH1F, {axisCountEvents}); + + const int maxMixBin = axisMultiplicity->size() * axisVertex->size(); + histos.add("eventcount", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); + mPairCuts.SetHistogramRegistry(&histos); + if (cfgPairCut->get("Photon") > 0 || cfgPairCut->get("K0") > 0 || cfgPairCut->get("Lambda") > 0 || + cfgPairCut->get("Phi") > 0 || cfgPairCut->get("Rho") > 0) { + mPairCuts.SetPairCut(PairCuts::Photon, cfgPairCut->get("Photon")); + mPairCuts.SetPairCut(PairCuts::K0, cfgPairCut->get("K0")); + mPairCuts.SetPairCut(PairCuts::Lambda, cfgPairCut->get("Lambda")); + mPairCuts.SetPairCut(PairCuts::Phi, cfgPairCut->get("Phi")); + mPairCuts.SetPairCut(PairCuts::Rho, cfgPairCut->get("Rho")); + doPairCuts = true; + } + + std::vector corrAxis = {{axisDeltaEta, "#Delta#eta"}, + {axisPtAssoc, "p_{T} (GeV/c)"}, + {axisPtTrigger, "p_{T} (GeV/c)"}, + {axisMultiplicity, "multiplicity / centrality"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisVertex, "z-vtx (cm)"}}; + std::vector effAxis = {{axisEtaEfficiency, "#eta"}, + {axisEtaEfficiency, "#eta"}, + {axisPtEfficiency, "p_{T} (GeV/c)"}, + {axisVertexEfficiency, "z-vtx (cm)"}}; + same.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + + LOGF(info, "Finishing init"); + } + + // Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgZVtxCut; + // Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgPtCutMin) && (aod::track::pt < cfgPtCutMax) && (requireGlobalTrackInFilter() || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + + using FullCollisions = soa::Join; + using FullTracks = soa::Join; + + enum EventType { + SameEvent = 1, + MixedEvent = 2 + }; + + SliceCache cache; + std::vector vtxBinsEdges{VARIABLE_WIDTH, -10.0f, -7.0f, -5.0f, -2.5f, 0.0f, 2.5f, 5.0f, 7.0f, 10.0f}; + using BinningType = ColumnBinningPolicy; + + template + bool isEventSelected(TCollision collision) + { + if (evSel8 && !collision.sel8()) { + return false; + } + if (collision.posZ() < -cfgZVtxCut || cfgZVtxCut < collision.posZ()) { + return false; + } + if (evSelkNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (evSelkNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (evSelkNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (evSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (evSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + return true; + } + + template + bool isTrackCut(T const& track) + { + if (track.sign() != 1 && track.sign() != -1) { + return false; + } + if (track.pt() < cutMyptMin || track.pt() > cutMyptMax) { + return false; + } + if (track.eta() < cutMyetaMin || track.eta() > 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; + } + } + if (track.isPVContributor() == false) { + 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; + } + + template + void fillQA(TTracks tracks, float multiplicity) + { + for (const auto& track : tracks) { + histos.fill(HIST("yields"), multiplicity, track.pt(), track.eta()); + histos.fill(HIST("etaphi"), multiplicity, track.eta(), track.phi()); + } + } + + template + bool fillCollision(TTarget target, float multiplicity) + { + target->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); + target->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + return true; + } + + template + void fillCorrelations(TTarget target, TTracks tracks1, TTracks tracks2, float multiplicity, float posZ, int system) + { + for (const auto& track1 : tracks1) { + if (isTrackCut(track1) == false) { + return; + } + float phi1 = track1.phi(); + phi1 = RecoDecay::constrainAngle(phi1, 0.f); + float eta1 = track1.eta(); + target->getTriggerHist()->Fill(CorrelationContainer::kCFStepReconstructed, track1.pt(), multiplicity, posZ, 1.0); + for (const auto& track2 : tracks2) { + if (track1 == track2) { + continue; + } + if (isTrackCut(track2) == false) { + return; + } + float phi2 = track2.phi(); + phi2 = RecoDecay::constrainAngle(phi2, 0.f); + float eta2 = track2.eta(); + /*if (doPairCuts && mPairCuts.conversionCuts(track1, track2)) { + continue; + }*/ + float deltaPhi = phi1 - phi2; + float deltaEta = eta1 - eta2; + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); + target->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, + deltaEta, + track2.pt(), track1.pt(), + multiplicity, + deltaPhi, + posZ); + + if (system == SameEvent) { + if (minMultiplicity <= multiplicity) { + histos.fill(HIST("sameEvent2D"), deltaEta, deltaPhi); + } + if (minMultiplicity <= multiplicity && multiplicity <= range1Max) { + histos.fill(HIST("sameEvent_2_10"), deltaEta, deltaPhi); + } else if (range2Min <= multiplicity && multiplicity <= range2Max) { + histos.fill(HIST("sameEvent_11_20"), deltaEta, deltaPhi); + } else if (range3Min <= multiplicity && multiplicity <= range3Max) { + histos.fill(HIST("sameEvent_21_30"), deltaEta, deltaPhi); + } else if (range4Min <= multiplicity && multiplicity <= range4Max) { + histos.fill(HIST("sameEvent_31_40"), deltaEta, deltaPhi); + } else if (range5Min <= multiplicity && multiplicity <= range5Max) { + histos.fill(HIST("sameEvent_41_50"), deltaEta, deltaPhi); + } else { + continue; + } + } else if (system == MixedEvent) { + if (minMultiplicity <= multiplicity) { + histos.fill(HIST("mixedEvent2D"), deltaEta, deltaPhi); + } + if (minMultiplicity <= multiplicity && multiplicity <= range1Max) { + histos.fill(HIST("mixedEvent_2_10"), deltaEta, deltaPhi); + } else if (range2Min <= multiplicity && multiplicity <= range2Max) { + histos.fill(HIST("mixedEvent_11_20"), deltaEta, deltaPhi); + } else if (range3Min <= multiplicity && multiplicity <= range3Max) { + histos.fill(HIST("mixedEvent_21_30"), deltaEta, deltaPhi); + } else if (range4Min <= multiplicity && multiplicity <= range4Max) { + histos.fill(HIST("mixedEvent_31_40"), deltaEta, deltaPhi); + } else if (range5Min <= multiplicity && multiplicity <= range5Max) { + histos.fill(HIST("mixedEvent_41_50"), deltaEta, deltaPhi); + } else { + continue; + } + } + } + } + } + + void processMixed(FullCollisions const& collisions, FullTracks const& tracks) + { + BinningType bindingOnVtx{{vtxBinsEdges}, true}; + auto tracksTuple = std::make_tuple(tracks); + SameKindPair + pairs{bindingOnVtx, nEventsMixed, -1, collisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (collision1.size() == 0 || collision2.size() == 0) { + continue; + } + + if (isEventSelected(collision1) == false || isEventSelected(collision2) == false) { + continue; + } + + float multiplicity = 0; + for (const auto& track : tracks1) { + if (isTrackCut(track) == false) { + continue; + } + ++multiplicity; + } + if (fillCollision(mixed, multiplicity) == false) { + return; + } + // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ()})); + fillCorrelations(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), MixedEvent); + } + } + + PROCESS_SWITCH(TwoParticleCorrelationPp, processMixed, "Process mixed events", true); + + void processSame(FullCollisions::iterator const& collision, FullTracks const& tracks) + { + float multiplicity = 0; + + if (isEventSelected(collision) == false) { + return; + } + + for (const auto& track : tracks) { + if (isTrackCut(track) == false) { + continue; + } + ++multiplicity; + } + // LOGF(debug, "Filling same events"); + if (fillCollision(same, multiplicity) == false) { + return; + } + histos.fill(HIST("eventcount"), -2); + if (minMultiplicity <= multiplicity && multiplicity <= range1Max) { + histos.fill(HIST("eventcount"), 1); + } else if (range2Min <= multiplicity && multiplicity <= range2Max) { + histos.fill(HIST("eventcount"), 2); + } else if (range3Min <= multiplicity && multiplicity <= range3Max) { + histos.fill(HIST("eventcount"), 3); + } else if (range4Min <= multiplicity && multiplicity <= range4Max) { + histos.fill(HIST("eventcount"), 4); + } else if (range5Min <= multiplicity && multiplicity <= range5Max) { + histos.fill(HIST("eventcount"), 5); + } + fillQA(tracks, multiplicity); + fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), SameEvent); + } + + PROCESS_SWITCH(TwoParticleCorrelationPp, processSame, "Process same events", true); + + void process(FullCollisions::iterator const& collision, FullTracks const& tracks) + { + // Configure events flow histogram labels + auto hFlowEvents = histos.get(HIST("Events/hEventsAfterCuts")); + hFlowEvents->GetXaxis()->SetBinLabel(1, "All tracks"); + hFlowEvents->GetXaxis()->SetBinLabel(2, "sel8"); + hFlowEvents->GetXaxis()->SetBinLabel(3, "Z vertex"); + hFlowEvents->GetXaxis()->SetBinLabel(4, "kNoSameBunchPileup"); + hFlowEvents->GetXaxis()->SetBinLabel(5, "kNoITSROFrameBorder"); + hFlowEvents->GetXaxis()->SetBinLabel(6, "kNoTimeFrameBorder"); + hFlowEvents->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + hFlowEvents->GetXaxis()->SetBinLabel(8, "kNoCollInTimeRangeStandard"); + + histos.fill(HIST("Events/hEventsAfterCuts"), 0); + if (evSel8 && !collision.sel8()) { + return; + } + histos.fill(HIST("Events/hEventsAfterCuts"), 1); + if (collision.posZ() < -cfgZVtxCut || cfgZVtxCut < collision.posZ()) { + return; + } + histos.fill(HIST("Events/hEventsAfterCuts"), 2); + if (evSelkNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } + histos.fill(HIST("Events/hEventsAfterCuts"), 3); + if (evSelkNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return; + } + histos.fill(HIST("Events/hEventsAfterCuts"), 4); + if (evSelkNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return; + } + histos.fill(HIST("Events/hEventsAfterCuts"), 5); + if (evSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + histos.fill(HIST("Events/hEventsAfterCuts"), 6); + if (evSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + histos.fill(HIST("Events/hEventsAfterCuts"), 7); + + // Configure track flow histogram labels + auto hFlowTracks = histos.get(HIST("Tracks/hTracksAfterCuts")); + hFlowTracks->GetXaxis()->SetBinLabel(1, "All tracks"); + hFlowTracks->GetXaxis()->SetBinLabel(2, "Track sign"); + hFlowTracks->GetXaxis()->SetBinLabel(3, "p_{T} range"); + hFlowTracks->GetXaxis()->SetBinLabel(4, "#eta range"); + hFlowTracks->GetXaxis()->SetBinLabel(5, "dcaZ"); + hFlowTracks->GetXaxis()->SetBinLabel(6, "dcaXY"); + hFlowTracks->GetXaxis()->SetBinLabel(7, "PV contrib cut"); + hFlowTracks->GetXaxis()->SetBinLabel(8, "has ITS cut"); + hFlowTracks->GetXaxis()->SetBinLabel(9, "N clusters ITS cut"); + hFlowTracks->GetXaxis()->SetBinLabel(10, "#chi^{2} N cluster ITS cut"); + hFlowTracks->GetXaxis()->SetBinLabel(11, "has TPC cut"); + hFlowTracks->GetXaxis()->SetBinLabel(12, "N clusters crossed row TPC cut"); + hFlowTracks->GetXaxis()->SetBinLabel(13, "(N cluster findable - N cluster minus findable) TPC cut"); + hFlowTracks->GetXaxis()->SetBinLabel(14, "N cluster findable TPC cut"); + hFlowTracks->GetXaxis()->SetBinLabel(15, "(N cluster crossed row / N cluster findable) TPC cut"); + hFlowTracks->GetXaxis()->SetBinLabel(16, "(N cluster findable - N cluster minus findable) / N cluster findable cut"); + hFlowTracks->GetXaxis()->SetBinLabel(17, "#chi^{2} N cluster TPC cut"); + + for (const auto& track : tracks) { + histos.fill(HIST("Tracks/hTracksAfterCuts"), 0); + if (track.sign() != 1 && track.sign() != -1) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 1); + if (track.pt() < cutMyptMin || track.pt() > cutMyptMax) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 2); + if (track.eta() < cutMyetaMin || track.eta() > cutMyetaMax) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 3); + if (std::abs(track.dcaZ()) > cutMydcaZmax) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 4); + if (cutMydcaXYusePt) { + float maxDCA = 0.0105f + 0.0350f / std::pow(track.pt(), 1.1f); + if (std::abs(track.dcaXY()) > maxDCA) { + continue; + } + } else { + if (std::abs(track.dcaXY()) > cutMydcaXYmax) { + continue; + } + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 5); + if (track.isPVContributor() == false) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 6); + // Quality Track + // ITS + if (cutMyHasITS && !track.hasITS()) { + continue; // ITS refit + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 7); + if (track.itsNCls() < cutMyITSNClsMin) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 8); + if (track.itsChi2NCl() > cutMyITSChi2NClMax) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 9); + // TPC + if (cutMyHasTPC && !track.hasTPC()) { + continue; // TPC refit + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 10); + if (track.tpcNClsCrossedRows() < cutMyTPCNClsCrossedRowsMin) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 11); + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < cutMyTPCNClsMin) { + continue; // tpcNClsFound() + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 12); + if (track.tpcNClsFindable() < cutMyTPCNClsFindableMin) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 13); + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < cutMyTPCNClsCrossedRowsOverNClsFindableMin) { + continue; // + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 14); + if ((static_cast(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) / static_cast(track.tpcNClsFindable())) < cutMyTPCNClsCrossedRowsOverNClsFindableMin) { + continue; // + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 15); + if (track.tpcChi2NCl() > cutMyTPCChi2NclMax) { + continue; // TPC chi2 + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 16); + } + } + + PROCESS_SWITCH(TwoParticleCorrelationPp, process, "Process mixed events", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} 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..41ceb661bf9 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::MLCore) o2physics_target_root_dictionary(PWGDQCore HEADERS AnalysisCut.h diff --git a/PWGDQ/Core/CutsLibrary.cxx b/PWGDQ/Core/CutsLibrary.cxx index 7833a78333e..ac4af0432b8 100644 --- a/PWGDQ/Core/CutsLibrary.cxx +++ b/PWGDQ/Core/CutsLibrary.cxx @@ -12,11 +12,22 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // #include "PWGDQ/Core/CutsLibrary.h" -#include -#include + #include "AnalysisCompositeCut.h" #include "VarManager.h" +#include + +#include + +#include +#include +#include +#include + +using std::cout; +using std::endl; + AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) { // @@ -31,6 +42,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")); @@ -39,36 +52,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, 4.0); + qualityCuts->AddCut(VarManager::kTPCncls, 70, 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, 4.0); + qualityCuts->AddCut(VarManager::kTPCncls, 70, 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, 4.0); + qualityCuts->AddCut(VarManager::kTPCncls, 70, 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, 4.0); + qualityCuts->AddCut(VarManager::kTPCncls, 70, 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, 4.0); + qualityCuts->AddCut(VarManager::kTPCncls, 70, 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")) { @@ -76,12 +187,30 @@ 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")); + cut->AddCut(GetAnalysisCut("MCHMID")); + return cut; + } // /////////////////////////////////////////////// // End of Cuts for CEFP // // /////////////////////////////////////////////// @@ -144,6 +273,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")); @@ -369,6 +513,43 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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 @@ -399,6 +580,29 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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")); @@ -436,6 +640,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; @@ -538,6 +748,23 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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")); @@ -589,6 +816,14 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + 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("kaonPID4")) { cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); return cut; @@ -599,11 +834,18 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("kaonPID6")) { + cut->AddCut(GetAnalysisCut("kaonPIDnsigma700")); + return cut; + } + 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); @@ -613,22 +855,32 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare("kaonPosPID4")) { - cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); - cut->AddCut(GetAnalysisCut("posTrack")); + 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("kaonPosPID4DCAz")) { + if (!nameStr.compare("kaonPosPID4")) { cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); return cut; } - if (!nameStr.compare("kaonPosPID5")) { - cut->AddCut(GetAnalysisCut("kaonPIDnsigma")); + if (!nameStr.compare("kaonPosPID4Pt05")) { + cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } @@ -638,22 +890,10 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare("kaonNegPID4DCAz")) { + if (!nameStr.compare("kaonNegPID4Pt05")) { cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); - return cut; - } - - if (!nameStr.compare("kaonNegPID5")) { - cut->AddCut(GetAnalysisCut("kaonPIDnsigma")); - cut->AddCut(GetAnalysisCut("negTrack")); - return cut; - } - - if (!nameStr.compare("kaonPID4_PVC")) { - cut->AddCut(GetAnalysisCut("kaonPID_TPCnTOF")); - cut->AddCut(GetAnalysisCut("primaryVertexContributor")); + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } @@ -687,13 +927,6 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare("pionPosPIDDCAz")) { - cut->AddCut(GetAnalysisCut("pionPID_TPCnTOF")); - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); - return cut; - } - if (!nameStr.compare("pionPosPID2")) { cut->AddCut(GetAnalysisCut("pionPIDnsigma")); cut->AddCut(GetAnalysisCut("posTrack")); @@ -706,55 +939,46 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare("pionNegPIDDCAz")) { - cut->AddCut(GetAnalysisCut("pionPID_TPCnTOF")); - cut->AddCut(GetAnalysisCut("negTrack")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); - return cut; - } - if (!nameStr.compare("pionNegPID2")) { cut->AddCut(GetAnalysisCut("pionPIDnsigma")); cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - if (!nameStr.compare("pionPID_PVC")) { - cut->AddCut(GetAnalysisCut("pionPID_TPCnTOF")); - cut->AddCut(GetAnalysisCut("primaryVertexContributor")); + if (!nameStr.compare("protonPosPID")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); + cut->AddCut(GetAnalysisCut("posTrack")); return cut; } - if (!nameStr.compare("pionPosPID2_PVC")) { - cut->AddCut(GetAnalysisCut("pionPIDnsigma")); - cut->AddCut(GetAnalysisCut("primaryVertexContributor")); + if (!nameStr.compare("protonPosPIDPt05")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } - if (!nameStr.compare("pionNegPID2_PVC")) { - cut->AddCut(GetAnalysisCut("pionPIDnsigma")); - cut->AddCut(GetAnalysisCut("primaryVertexContributor")); + if (!nameStr.compare("protonNegPID")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); cut->AddCut(GetAnalysisCut("negTrack")); return cut; } - if (!nameStr.compare("protonPosPID")) { + if (!nameStr.compare("protonNegPIDPt05")) { cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); - cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("muonLowPt")); return cut; } - if (!nameStr.compare("protonPosPIDDCAz")) { - cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); - cut->AddCut(GetAnalysisCut("posTrack")); - cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); + if (!nameStr.compare("protonPIDPV")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF2")); + cut->AddCut(GetAnalysisCut("protonPVcut")); return cut; } - if (!nameStr.compare("protonNegPID")) { - cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF")); - cut->AddCut(GetAnalysisCut("negTrack")); + if (!nameStr.compare("protonPIDPV2")) { + cut->AddCut(GetAnalysisCut("protonPID_TPCnTOF2")); return cut; } @@ -763,13 +987,25 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare("pionPosPrimaryNoPID")) { + if (!nameStr.compare("posPrimaryTrack_DCAz")) { + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); + cut->AddCut(GetAnalysisCut("posTrack")); + return cut; + } + + if (!nameStr.compare("negPrimaryTrack_DCAz")) { + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); + cut->AddCut(GetAnalysisCut("negTrack")); + return cut; + } + + if (!nameStr.compare("posStandardPrimaryTrackDCA")) { cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCA")); cut->AddCut(GetAnalysisCut("posTrack")); return cut; } - if (!nameStr.compare("pionNegPrimaryNoPID")) { + if (!nameStr.compare("negStandardPrimaryTrackDCA")) { cut->AddCut(GetAnalysisCut("standardPrimaryTrackDCA")); cut->AddCut(GetAnalysisCut("negTrack")); return cut; @@ -785,6 +1021,56 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("posTrackKaonRej")) { + cut->AddCut(GetAnalysisCut("posTrack")); + cut->AddCut(GetAnalysisCut("kaonRejNsigma")); + return cut; + } + + if (!nameStr.compare("negTrackKaonRej")) { + cut->AddCut(GetAnalysisCut("negTrack")); + cut->AddCut(GetAnalysisCut("kaonRejNsigma")); + return cut; + } + + if (!nameStr.compare("pTLow05")) { + cut->AddCut(GetAnalysisCut("muonLowPt")); + return cut; + } + + if (!nameStr.compare("pTLow04")) { + cut->AddCut(GetAnalysisCut("pTLow04")); + return cut; + } + + if (!nameStr.compare("pTLow03")) { + cut->AddCut(GetAnalysisCut("pTLow03")); + return cut; + } + + if (!nameStr.compare("pTLow02")) { + cut->AddCut(GetAnalysisCut("pTLow02")); + return cut; + } + + if (!nameStr.compare("pTLow05DCAzHigh03")) { + cut->AddCut(GetAnalysisCut("muonLowPt")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); + return cut; + } + + if (!nameStr.compare("pTLow04DCAzHigh03")) { + cut->AddCut(GetAnalysisCut("pTLow04")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); + return cut; + } + + if (!nameStr.compare("pTLow03DCAzHigh03")) { + cut->AddCut(GetAnalysisCut("pTLow03")); + cut->AddCut(GetAnalysisCut("PrimaryTrack_DCAz")); + 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")); @@ -830,11 +1116,24 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) } if (!nameStr.compare("Jpsi_TPCPost_calib_debug8")) { - cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug3")); + 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("Jpsi_TPCPost_calib_debug10")) { + cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); + cut->AddCut(GetAnalysisCut("jpsi_trackCut_debug6")); + cut->AddCut(GetAnalysisCut("jpsi_TPCPID_debug10")); + return cut; + } + if (!nameStr.compare("LMee_TPCPost_calib_debug1")) { cut->AddCut(GetAnalysisCut("lmee_trackCut_debug")); cut->AddCut(GetAnalysisCut("lmee_TPCPID_debug1")); @@ -870,6 +1169,171 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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 // @@ -1012,34 +1476,6 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) } } - //--------------------------------------------------------------------------------------- - // 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")); @@ -1286,6 +1722,13 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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")); @@ -1500,6 +1943,26 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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()))) { @@ -1582,6 +2045,24 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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()))); @@ -1590,16 +2071,16 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare(Form("lmee%s_lowB_eNSigmaRun3%s_strongNSigE", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeLowBKine")); + 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("standardPrimaryTrackDCAz")); // to reject looper using DCAz + 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", 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", 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); @@ -1608,16 +2089,16 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare(Form("lmee%s_lowB_eNSigmaRun3%s_strongNSigE_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeLowBKine")); + 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")); // to reject looper using DCAz + 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_rejBadTOF", vecPIDcase.at(icase).Data()))); + cut_tpc_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TPCnsigma%s_tightNSigEPbPb_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()))); + cut_tof_nSigma->AddCut(GetAnalysisCut(Form("electronPID_TOFnsigma%s_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); AnalysisCompositeCut* cut_pid_OR = new AnalysisCompositeCut("e_NSigma", "e_NSigma", kFALSE); cut_pid_OR->AddCut(cut_tpc_nSigma); @@ -1626,16 +2107,16 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongNSigE_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), 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("PrimaryTrack_looseDCA")); + 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_rejBadTOF", vecPIDcase.at(icase).Data()))); + 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_strongNSigE_rejBadTOF", vecPIDcase.at(icase).Data()))); + 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); @@ -1644,8 +2125,8 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_tightNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + 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")); @@ -1662,8 +2143,8 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongNSigEPbPb_rejBadTOF", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine")); + 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")); @@ -1680,16 +2161,16 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_tightNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); + 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")); + 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_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + 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_tightNSigEPbPb_rejBadTOF", vecPIDcase.at(icase).Data()))); + 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); @@ -1698,16 +2179,16 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (!nameStr.compare(Form("lmee%s_eNSigmaRun3%s_strongNSigEPbPb_rejBadTOF_pt04", vecTypetrackWithPID.at(jcase).Data(), vecPIDcase.at(icase).Data()))) { - cut->AddCut(GetAnalysisCut("lmeeStandardKine_pt04")); + 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")); + 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()))); + 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()))); + 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); @@ -2418,6 +2899,22 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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("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; + } + // ------------------------------------------------------------------------------------------------- // lmee pair cuts @@ -2445,6 +2942,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; @@ -2455,6 +2957,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")); @@ -2476,6 +3001,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")); @@ -2641,6 +3173,17 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("muonQualityCutsMUONStandalone")) { + cut->AddCut(GetAnalysisCut("matchedMchMid")); + cut->AddCut(GetAnalysisCut("muonQualityCuts")); + return cut; + } + + if (!nameStr.compare("muonQualityCutsGlobal")) { + cut->AddCut(GetAnalysisCut("matchedGlobal")); + cut->AddCut(GetAnalysisCut("muonQualityCuts")); + return cut; + } // ----------------------------------------------------------- // Pair cuts if (!nameStr.compare("pairNoCut")) { @@ -2918,6 +3461,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; @@ -2933,11 +3481,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; @@ -2993,6 +3556,27 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) 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 @@ -3066,6 +3650,13 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (!nameStr.compare("emu_electron_test")) { + cut->AddCut(GetAnalysisCut("jpsiStandardKine")); + cut->AddCut(GetAnalysisCut("electronTrackQuality_Maolin")); + cut->AddCut(GetAnalysisCut("electronPIDnsigmaEMu")); + return cut; + } + if (!nameStr.compare("muonLooseTriggerTestCuts")) { cut->AddCut(GetAnalysisCut("muonLooseTriggerTestCuts")); return cut; @@ -3113,7 +3704,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; } @@ -3126,6 +3717,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; @@ -3147,7 +3742,11 @@ 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; @@ -3155,18 +3754,19 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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")) { + 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")) { + 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); @@ -3182,6 +3782,19 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("eventSel8NoSameBunch")) { + cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); + cut->AddCut(VarManager::kIsNoSameBunch, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventSel8NoSameBunchGoodZvtx")) { + 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("eventStandardSel8PbPbQuality")) { cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); @@ -3192,6 +3805,17 @@ 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); @@ -3201,6 +3825,18 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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; } @@ -3218,6 +3854,34 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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., @@ -3233,7 +3897,22 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 50000.}; for (size_t icase = 0; icase < vecOccupancies.size() - 1; icase++) { - if (!nameStr.compare(Form("eventStandardSel8PbPbQualityTrackOccupancySlice%lu", 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); @@ -3241,7 +3920,7 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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]); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, 0, vecOccupancies[icase]); return cut; } @@ -3259,6 +3938,55 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("eventStandardSel8ppQualityNoVtxZ")) { + 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::kIsVertexITSTPC, 0.5, 1.5); + cut->AddCut(VarManager::kIsVertexTOFmatched, 0.5, 1.5); + return cut; + } + + if (!nameStr.compare("eventStandardSel8multAnalysis")) { + 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::kIsVertexITSTPC, 0.5, 1.5); + 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; @@ -3342,6 +4070,26 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cutAorC; } + 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); @@ -3460,6 +4208,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); @@ -3526,9 +4286,40 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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 + // --------------------------------------------------- + // MC generated particle acceptance cuts + + if (!nameStr.compare("rapidity08")) { + cut->AddCut(VarManager::kMCY, -0.8, 0.8); + return cut; + } + + if (!nameStr.compare("rapidity09")) { + cut->AddCut(VarManager::kMCY, -0.9, 0.9); + return cut; + } + + // --------------------------------------------------- + // MC generated particle acceptance cuts + // Run 2 only if (!nameStr.compare("highPtHadron")) { @@ -3615,6 +4406,34 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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("jpsi_trackCut_debug6")) { + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCncls, 120., 159); + cut->AddCut(VarManager::kTPCnclsCR, 140., 159); + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kIsSPDfirst, 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); @@ -3632,6 +4451,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); @@ -3765,6 +4595,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); @@ -3840,12 +4694,50 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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("electronTrackQuality_Maolin")) { + cut->AddCut(VarManager::kIsITSibAny, 0.5, 1.5); + cut->AddCut(VarManager::kITSchi2, 0.0, 15.0); + cut->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut->AddCut(VarManager::kTPCncls, 70, 161.); + cut->AddCut(VarManager::kTPCnclsCR, 70, 161); + cut->AddCut(VarManager::kTrackDCAxy, -2.0, 2.0); + cut->AddCut(VarManager::kTrackDCAz, -2.0, 2.0); + 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; } @@ -3861,12 +4753,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); @@ -3907,6 +4926,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 @@ -4002,6 +5026,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); @@ -4017,10 +5049,25 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) } if (!nameStr.compare("jpsi_TPCPID_debug8")) { - cut->AddCut(VarManager::kTOFbeta, 0.975, 1.025, false, VarManager::kPin, 0.0, 3.0); - cut->AddCut(VarManager::kTPCnSigmaEl, -3.0, 4.0); - cut->AddCut(VarManager::kTPCnSigmaPi, 2.0, 999, false, VarManager::kPin, 3.0, 999.0); - cut->AddCut(VarManager::kTPCnSigmaPr, 2.0, 999, false, VarManager::kPin, 3.0, 999.0); + 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("jpsi_TPCPID_debug10")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -1.5, 2.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 4.0, 999); + cut->AddCut(VarManager::kTPCnSigmaPr, 3.5, 999); return cut; } @@ -4090,13 +5137,6 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } - if (!nameStr.compare("electronPID1randomized")) { - cutLow1->SetParameters(130., -40.0); - cut->AddCut(VarManager::kTPCsignalRandomized, 70., 100.); - cut->AddCut(VarManager::kTPCsignalRandomized, cutLow1, 100.0, false, VarManager::kPin, 0.5, 3.0); - return cut; - } - if (!nameStr.compare("electronPID2")) { cutLow1->SetParameters(130., -40.0); cut->AddCut(VarManager::kTPCsignal, 73., 100.); @@ -4111,13 +5151,6 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } - if (!nameStr.compare("electronPID2randomized")) { - cutLow1->SetParameters(130., -40.0); - cut->AddCut(VarManager::kTPCsignalRandomized, 73., 100.); - cut->AddCut(VarManager::kTPCsignalRandomized, cutLow1, 100.0, false, VarManager::kPin, 0.5, 3.0); - return cut; - } - if (!nameStr.compare("electronPIDnsigma")) { cut->AddCut(VarManager::kTPCnSigmaEl, -3.0, 3.0); cut->AddCut(VarManager::kTPCnSigmaPr, 3.0, 3000.0); @@ -4125,6 +5158,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 @@ -4335,6 +5383,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); @@ -4449,14 +5529,20 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) cut->AddCut(VarManager::kTPCnSigmaPi, 2.5, 3000.0); return cut; } - - if (!nameStr.compare("electronPIDnsigmaMedium")) { + + if (!nameStr.compare("electronPIDnsigmaMedium")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -3.0, 3.0); + cut->AddCut(VarManager::kTPCnSigmaPr, 2.7, 3000.0); + 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); @@ -4464,6 +5550,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); @@ -4498,11 +5591,24 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (!nameStr.compare("electronPIDnsigmaEMu")) { + cut->AddCut(VarManager::kTPCnSigmaEl, -1.0, 3.0); + cut->AddCut(VarManager::kTPCnSigmaPr, 3.5, 3000.0); + cut->AddCut(VarManager::kTPCnSigmaPi, 3.5, 3000.0); + cut->AddCut(VarManager::kTPCnSigmaKa, 3.5, 3000.0); + return cut; + } + if (!nameStr.compare("kaonPIDnsigma")) { cut->AddCut(VarManager::kTPCnSigmaKa, -3.0, 3.0); 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; @@ -4514,16 +5620,15 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } - if (!nameStr.compare("AssocKine")) { - cut->AddCut(VarManager::kPt, 1.0, 1000.0); - cut->AddCut(VarManager::kEta, -0.9, 0.9); + 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("electronPIDnsigmaRandomized")) { - cut->AddCut(VarManager::kTPCnSigmaElRandomized, -3.0, 3.0); - cut->AddCut(VarManager::kTPCnSigmaPrRandomized, 3.0, 3000.0); - cut->AddCut(VarManager::kTPCnSigmaPiRandomized, 3.0, 3000.0); + if (!nameStr.compare("AssocKine")) { + cut->AddCut(VarManager::kPt, 1.0, 1000.0); + cut->AddCut(VarManager::kEta, -0.9, 0.9); return cut; } @@ -4558,6 +5663,11 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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); @@ -4623,6 +5733,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; @@ -4682,6 +5797,29 @@ 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); @@ -4883,6 +6021,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); @@ -4893,6 +6039,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); @@ -4914,6 +6070,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); @@ -5224,6 +6391,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; @@ -5324,6 +6496,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; @@ -5335,7 +6512,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; } @@ -5426,6 +6619,21 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) 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 @@ -5495,6 +6703,623 @@ 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; +} + +//________________________________________________________________________________________________ +o2::aod::dqmlcuts::BdtScoreConfig o2::aod::dqmlcuts::GetBdtScoreCutsAndConfigFromJSON(const char* json) +{ + LOG(info) << "========================================== interpreting JSON for ML analysis cuts"; + if (!json) { + LOG(fatal) << "JSON config string is null!"; + return {}; + } + LOG(info) << "JSON string: " << json; + + 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 {}; + } + + for (auto it = document.MemberBegin(); it != document.MemberEnd(); ++it) { + const auto& obj = it->value; + + // Classification type + if (!obj.HasMember("type")) { + LOG(fatal) << "Missing type (Binary/MultiClass)"; + return {}; + } + TString typeStr = obj["type"].GetString(); + if (typeStr != "Binary" && typeStr != "MultiClass") { + LOG(fatal) << "Unsupported classification type: " << typeStr; + return {}; + } + + // Input features + if (!obj.HasMember("inputFeatures") || !obj["inputFeatures"].IsArray()) { + LOG(fatal) << "Missing inputFeatures member or array"; + return {}; + } + std::vector namesInputFeatures; + for (const auto& feature : obj["inputFeatures"].GetArray()) { + namesInputFeatures.emplace_back(feature.GetString()); + LOG(debug) << "Input features: " << feature.GetString(); + } + + // Model files + if (!obj.HasMember("modelFiles") || !obj["modelFiles"].IsArray()) { + LOG(fatal) << "Missing modelFiles member or array"; + return {}; + } + std::vector onnxFileNames; + for (const auto& model : obj["modelFiles"].GetArray()) { + onnxFileNames.emplace_back(model.GetString()); + LOG(debug) << "Model Files: " << model.GetString() << " "; + } + + // Centrality estimation type + if (!obj.HasMember("cent") || !obj["cent"].IsString()) { + LOG(fatal) << "Missing cent member"; + return {}; + } + std::string cent = obj["cent"].GetString(); + LOG(debug) << "Centrality type: " << cent; + if (cent != "kCentFT0C" && cent != "kCentFT0A" && cent != "kCentFT0M") { + LOG(fatal) << "Unsupported centrality type: " << cent; + return {}; + } + + // Cut storage + std::vector> centBins; + std::vector> ptBins; + std::vector> cutsMl; + std::vector cutDirs; + std::vector labelsFlatBin; + bool cutDirsFilled = false; + + for (auto centMember = obj.MemberBegin(); centMember != obj.MemberEnd(); ++centMember) { + TString centKey = centMember->name.GetString(); + if (!centKey.Contains("AddCentCut")) + continue; + + const auto& centCut = centMember->value; + + // Centrality info + if (!centCut.HasMember("centMin") || !centCut.HasMember("centMax")) { + LOG(fatal) << "Missing centMin/centMax in " << centKey; + return {}; + } + double centMin = centCut["centMin"].GetDouble(); + double centMax = centCut["centMax"].GetDouble(); + + for (auto ptMember = centCut.MemberBegin(); ptMember != centCut.MemberEnd(); ++ptMember) { + TString ptKey = ptMember->name.GetString(); + if (!ptKey.Contains("AddPtCut")) + continue; + + const auto& ptCut = ptMember->value; + + // Pt info + if (!ptCut.HasMember("pTMin") || !ptCut.HasMember("pTMax")) { + LOG(fatal) << "Missing pTMin/pTMax in " << ptKey; + return {}; + } + + double ptMin = ptCut["pTMin"].GetDouble(); + double ptMax = ptCut["pTMax"].GetDouble(); + + std::vector binCuts; + bool exclude = false; + + for (auto mlMember = ptCut.MemberBegin(); mlMember != ptCut.MemberEnd(); ++mlMember) { + TString mlKey = mlMember->name.GetString(); + if (!mlKey.Contains("AddMLCut")) + continue; + + const auto& mlcut = mlMember->value; + + if (!mlcut.HasMember("cut")) { + LOG(fatal) << "Missing cut (score) in " << mlKey; + return {}; + } + + double cutVal = mlcut["cut"].GetDouble(); + exclude = mlcut.HasMember("exclude") ? mlcut["exclude"].GetBool() : false; + + binCuts.push_back(cutVal); + + if (!cutDirsFilled) { + cutDirs.push_back(exclude ? 0 : 1); + } + } + + if (!cutDirsFilled) { + cutDirsFilled = true; + } + + centBins.emplace_back(centMin, centMax); + ptBins.emplace_back(ptMin, ptMax); + cutsMl.push_back(binCuts); + labelsFlatBin.push_back(Form("%s_cent%.0f_%.0f_pt%.1f_%.1f", cent.c_str(), centMin, centMax, ptMin, ptMax)); + LOG(info) << "Added cut for " << Form("%s_cent%.0f_%.0f_pt%.1f_%.1f", cent.c_str(), centMin, centMax, ptMin, ptMax) << " with cuts: ["; + for (size_t i = 0; i < binCuts.size(); ++i) { + std::cout << binCuts[i]; + if (i != binCuts.size() - 1) + std::cout << ", "; + } + std::cout << "] and direction: " << (exclude ? "CutGreater" : "CutSmaller") << std::endl; + } + } + + if (cutDirs.size() != cutsMl[0].size()) { + LOG(fatal) << "Mismatch the cut size and direction size: cutsMl[0].size() = " << cutsMl[0].size() + << ", cutsMl[0].size() = " << cutDirs.size(); + return {}; + } + + std::vector labelsClass; + for (size_t j = 0; j < cutsMl[0].size(); ++j) { + labelsClass.push_back(Form("score class %d", static_cast(j))); + } + + size_t nFlatBins = cutsMl.size(); + std::vector binsMl(nFlatBins + 1); + std::iota(binsMl.begin(), binsMl.end(), 0); + + // Binary + if (typeStr == "Binary") { + dqmlcuts::BinaryBdtScoreConfig binaryCfg; + binaryCfg.inputFeatures = namesInputFeatures; + binaryCfg.onnxFiles = onnxFileNames; + binaryCfg.binsCent = centBins; + binaryCfg.binsPt = ptBins; + binaryCfg.binsMl = binsMl; + binaryCfg.cutDirs = cutDirs; + binaryCfg.centType = cent; + binaryCfg.cutsMl = makeLabeledCutsMl(cutsMl, labelsFlatBin, labelsClass); + + return binaryCfg; + + // MultiClass + } else if (typeStr == "MultiClass") { + dqmlcuts::MultiClassBdtScoreConfig multiCfg; + multiCfg.inputFeatures = namesInputFeatures; + multiCfg.onnxFiles = onnxFileNames; + multiCfg.binsCent = centBins; + multiCfg.binsPt = ptBins; + multiCfg.binsMl = binsMl; + multiCfg.cutDirs = cutDirs; + multiCfg.centType = cent; + multiCfg.cutsMl = makeLabeledCutsMl(cutsMl, labelsFlatBin, labelsClass); + + return multiCfg; + } + } + + return {}; +} + +o2::framework::LabeledArray o2::aod::dqmlcuts::makeLabeledCutsMl(const std::vector>& cuts, + const std::vector& labelsflatBin, + const std::vector& labelsClass) +{ + const size_t nRows = cuts.size(); + const size_t nCols = cuts.empty() ? 0 : cuts[0].size(); + std::vector flat; + + for (const auto& row : cuts) { + flat.insert(flat.end(), row.begin(), row.end()); + } + + o2::framework::Array2D arr(flat.data(), nRows, nCols); + return o2::framework::LabeledArray(arr, labelsflatBin, labelsClass); +} + +int o2::aod::dqmlcuts::getMlBinIndex(double cent, double pt, + const std::vector>& binsCent, + const std::vector>& binsPt) +{ + LOG(debug) << "Searching for Ml bin index for cent: " << cent << ", pt: " << pt; + for (size_t i = 0; i < binsCent.size(); ++i) { + if (cent >= binsCent[i].first && cent < binsCent[i].second && pt >= binsPt[i].first && pt < binsPt[i].second) { + LOG(debug) << " - Found at index: " << i; + return static_cast(i); + } + } + return -1; // not found +} diff --git a/PWGDQ/Core/CutsLibrary.h b/PWGDQ/Core/CutsLibrary.h index 59079166b29..b38577f3c2b 100644 --- a/PWGDQ/Core/CutsLibrary.h +++ b/PWGDQ/Core/CutsLibrary.h @@ -15,19 +15,146 @@ #ifndef PWGDQ_CORE_CUTSLIBRARY_H_ #define PWGDQ_CORE_CUTSLIBRARY_H_ -#include -#include -#include "PWGDQ/Core/AnalysisCut.h" #include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/AnalysisCut.h" #include "PWGDQ/Core/VarManager.h" +#include +#include + +// /////////////////////////////////////////////// +// 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 dqmlcuts +{ +struct BinaryBdtScoreConfig { + std::vector inputFeatures; + std::vector onnxFiles; + std::vector> binsCent; // bins for centrality + std::vector> binsPt; // bins for pT + std::vector binsMl; // bins for flattened binning + std::string centType; + o2::framework::LabeledArray cutsMl; // BDT score cuts for each bin + std::vector cutDirs; // direction of the cuts on the BDT score +}; + +struct MultiClassBdtScoreConfig { + std::vector inputFeatures; + std::vector onnxFiles; + std::vector> binsCent; + std::vector> binsPt; + std::vector binsMl; + std::string centType; + o2::framework::LabeledArray cutsMl; + std::vector cutDirs; +}; + +using BdtScoreConfig = std::variant; + +BdtScoreConfig GetBdtScoreCutsAndConfigFromJSON(const char* json); + +o2::framework::LabeledArray makeLabeledCutsMl(const std::vector>& cuts, + const std::vector& labelsPt, + const std::vector& labelsClass); +int getMlBinIndex(double cent, double pt, + const std::vector>& binsCent, + const std::vector>& binsPt); +} // namespace dqmlcuts } // namespace o2::aod AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName); diff --git a/PWGDQ/Core/DQMlResponse.h b/PWGDQ/Core/DQMlResponse.h new file mode 100644 index 00000000000..64bfe233cc7 --- /dev/null +++ b/PWGDQ/Core/DQMlResponse.h @@ -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. +// +// Contact: jseo@cern.ch +// +// Class to compute the ML response for DQ-analysis selections +// + +#ifndef PWGDQ_CORE_DQMLRESPONSE_H_ +#define PWGDQ_CORE_DQMLRESPONSE_H_ + +#include "Tools/ML/MlResponse.h" + +#include +#include +#include +#include + +namespace o2::analysis +{ + +enum class InputFeatures : uint8_t { // refer to DielectronsAll, TODO: add more features if needed + kMass = 0, + kPt, + kEta, + kPhi, + kPt1, + kITSChi2NCl1, + kTPCNClsCR1, + kTPCNClsFound1, + kTPCChi2NCl1, + kDcaXY1, + kDcaZ1, + kTPCNSigmaEl1, + kTPCNSigmaPi1, + kTPCNSigmaPr1, + kTOFNSigmaEl1, + kTOFNSigmaPi1, + kTOFNSigmaPr1, + kPt2, + kITSChi2NCl2, + kTPCNClsCR2, + kTPCNClsFound2, + kTPCChi2NCl2, + kDcaXY2, + kDcaZ2, + kTPCNSigmaEl2, + kTPCNSigmaPi2, + kTPCNSigmaPr2, + kTOFNSigmaEl2, + kTOFNSigmaPi2, + kTOFNSigmaPr2 +}; + +static const std::map gFeatureNameMap = { + {InputFeatures::kMass, "kMass"}, + {InputFeatures::kPt, "kPt"}, + {InputFeatures::kEta, "kEta"}, + {InputFeatures::kPhi, "kPhi"}, + {InputFeatures::kPt1, "kPt1"}, + {InputFeatures::kITSChi2NCl1, "kITSChi2NCl1"}, + {InputFeatures::kTPCNClsCR1, "kTPCNClsCR1"}, + {InputFeatures::kTPCNClsFound1, "kTPCNClsFound1"}, + {InputFeatures::kTPCChi2NCl1, "kTPCChi2NCl1"}, + {InputFeatures::kDcaXY1, "kDcaXY1"}, + {InputFeatures::kDcaZ1, "kDcaZ1"}, + {InputFeatures::kTPCNSigmaEl1, "kTPCNSigmaEl1"}, + {InputFeatures::kTPCNSigmaPi1, "kTPCNSigmaPi1"}, + {InputFeatures::kTPCNSigmaPr1, "kTPCNSigmaPr1"}, + {InputFeatures::kTOFNSigmaEl1, "kTOFNSigmaEl1"}, + {InputFeatures::kTOFNSigmaPi1, "kTOFNSigmaPi1"}, + {InputFeatures::kTOFNSigmaPr1, "kTOFNSigmaPr1"}, + {InputFeatures::kPt2, "kPt2"}, + {InputFeatures::kITSChi2NCl2, "kITSChi2NCl2"}, + {InputFeatures::kTPCNClsCR2, "kTPCNClsCR2"}, + {InputFeatures::kTPCNClsFound2, "kTPCNClsFound2"}, + {InputFeatures::kTPCChi2NCl2, "kTPCChi2NCl2"}, + {InputFeatures::kDcaXY2, "kDcaXY2"}, + {InputFeatures::kDcaZ2, "kDcaZ2"}, + {InputFeatures::kTPCNSigmaEl2, "kTPCNSigmaEl2"}, + {InputFeatures::kTPCNSigmaPi2, "kTPCNSigmaPi2"}, + {InputFeatures::kTPCNSigmaPr2, "kTPCNSigmaPr2"}, + {InputFeatures::kTOFNSigmaEl2, "kTOFNSigmaEl2"}, + {InputFeatures::kTOFNSigmaPi2, "kTOFNSigmaPi2"}, + {InputFeatures::kTOFNSigmaPr2, "kTOFNSigmaPr2"}}; + +template +class DQMlResponse : public MlResponse +{ + public: + DQMlResponse() = default; + virtual ~DQMlResponse() = default; + + void setBinsCent(const std::vector>& bins) { binsCent = bins; } + void setBinsPt(const std::vector>& bins) { binsPt = bins; } + void setCentType(std::string& type) { centType = type; } + + const std::vector>& getBinsCent() const { return binsCent; } + const std::vector>& getBinsPt() const { return binsPt; } + const std::string& getCentType() const { return centType; } + + /// Method to get the input features vector needed for ML inference + /// \return inputFeatures vector + template + std::vector getInputFeatures(const T1& t1, + const T2& t2, + const TValues& fg) const + { + std::vector dqInputFeatures; + dqInputFeatures.reserve(MlResponse::mCachedIndices.size()); + + for (auto idx : MlResponse::mCachedIndices) { + auto enumIdx = static_cast(idx); + auto mapIdx = gFeatureNameMap.find(enumIdx); + if (mapIdx == gFeatureNameMap.end()) { + LOG(fatal) << "Unknown InputFeatures index: " << static_cast(enumIdx); + } + + const auto& name = mapIdx->second; + if (name == "kMass") { + dqInputFeatures.push_back(fg[VarManager::fgVarNamesMap["kMass"]]); + } else if (name == "kPt") { + dqInputFeatures.push_back(fg[VarManager::fgVarNamesMap["kPt"]]); + } else if (name == "kEta") { + dqInputFeatures.push_back(fg[VarManager::fgVarNamesMap["kEta"]]); + } else if (name == "kPhi") { + dqInputFeatures.push_back(fg[VarManager::fgVarNamesMap["kPhi"]]); + } else if (name == "kPt1") { + dqInputFeatures.push_back(t1.pt()); + } else if (name == "kITSChi2NCl1") { + dqInputFeatures.push_back(t1.itsChi2NCl()); + } else if (name == "kTPCNClsCR1") { + dqInputFeatures.push_back(t1.tpcNClsCrossedRows()); + } else if (name == "kTPCNClsFound1") { + dqInputFeatures.push_back(t1.tpcNClsFound()); + } else if (name == "kTPCChi2NCl1") { + dqInputFeatures.push_back(t1.tpcChi2NCl()); + } else if (name == "kDcaXY1") { + dqInputFeatures.push_back(t1.dcaXY()); + } else if (name == "kDcaZ1") { + dqInputFeatures.push_back(t1.dcaZ()); + } else if (name == "kTPCNSigmaEl1") { + dqInputFeatures.push_back(t1.tpcNSigmaEl()); + } else if (name == "kTPCNSigmaPi1") { + dqInputFeatures.push_back(t1.tpcNSigmaPi()); + } else if (name == "kTPCNSigmaPr1") { + dqInputFeatures.push_back(t1.tpcNSigmaPr()); + } else if (name == "kTOFNSigmaEl1") { + dqInputFeatures.push_back(t1.tofNSigmaEl()); + } else if (name == "kTOFNSigmaPi1") { + dqInputFeatures.push_back(t1.tofNSigmaPi()); + } else if (name == "kTOFNSigmaPr1") { + dqInputFeatures.push_back(t1.tofNSigmaPr()); + } else if (name == "kPt2") { + dqInputFeatures.push_back(t2.pt()); + } else if (name == "kITSChi2NCl2") { + dqInputFeatures.push_back(t2.itsChi2NCl()); + } else if (name == "kTPCNClsCR2") { + dqInputFeatures.push_back(t2.tpcNClsCrossedRows()); + } else if (name == "kTPCNClsFound2") { + dqInputFeatures.push_back(t2.tpcNClsFound()); + } else if (name == "kTPCChi2NCl2") { + dqInputFeatures.push_back(t2.tpcChi2NCl()); + } else if (name == "kDcaXY2") { + dqInputFeatures.push_back(t2.dcaXY()); + } else if (name == "kDcaZ2") { + dqInputFeatures.push_back(t2.dcaZ()); + } else if (name == "kTPCNSigmaEl2") { + dqInputFeatures.push_back(t2.tpcNSigmaEl()); + } else if (name == "kTPCNSigmaPi2") { + dqInputFeatures.push_back(t2.tpcNSigmaPi()); + } else if (name == "kTPCNSigmaPr2") { + dqInputFeatures.push_back(t2.tpcNSigmaPr()); + } else if (name == "kTOFNSigmaEl2") { + dqInputFeatures.push_back(t2.tofNSigmaEl()); + } else if (name == "kTOFNSigmaPi2") { + dqInputFeatures.push_back(t2.tofNSigmaPi()); + } else if (name == "kTOFNSigmaPr2") { + dqInputFeatures.push_back(t2.tofNSigmaPr()); + } else { + LOG(fatal) << "Missing accessor for feature: " << name; + } + } + LOG(debug) << "Total features collected: " << dqInputFeatures.size(); + return dqInputFeatures; + } + + protected: + std::vector> binsCent; + std::vector> binsPt; + std::string centType; + + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + {"kMass", static_cast(InputFeatures::kMass)}, + {"kPt", static_cast(InputFeatures::kPt)}, + {"kEta", static_cast(InputFeatures::kEta)}, + {"kPhi", static_cast(InputFeatures::kPhi)}, + {"kPt1", static_cast(InputFeatures::kPt1)}, + {"kITSChi2NCl1", static_cast(InputFeatures::kITSChi2NCl1)}, + {"kTPCNClsCR1", static_cast(InputFeatures::kTPCNClsCR1)}, + {"kTPCNClsFound1", static_cast(InputFeatures::kTPCNClsFound1)}, + {"kTPCChi2NCl1", static_cast(InputFeatures::kTPCChi2NCl1)}, + {"kDcaXY1", static_cast(InputFeatures::kDcaXY1)}, + {"kDcaZ1", static_cast(InputFeatures::kDcaZ1)}, + {"kTPCNSigmaEl1", static_cast(InputFeatures::kTPCNSigmaEl1)}, + {"kTPCNSigmaPi1", static_cast(InputFeatures::kTPCNSigmaPi1)}, + {"kTPCNSigmaPr1", static_cast(InputFeatures::kTPCNSigmaPr1)}, + {"kTOFNSigmaEl1", static_cast(InputFeatures::kTOFNSigmaEl1)}, + {"kTOFNSigmaPi1", static_cast(InputFeatures::kTOFNSigmaPi1)}, + {"kTOFNSigmaPr1", static_cast(InputFeatures::kTOFNSigmaPr1)}, + {"kPt2", static_cast(InputFeatures::kPt2)}, + {"kITSChi2NCl2", static_cast(InputFeatures::kITSChi2NCl2)}, + {"kTPCNClsCR2", static_cast(InputFeatures::kTPCNClsCR2)}, + {"kTPCNClsFound2", static_cast(InputFeatures::kTPCNClsFound2)}, + {"kTPCChi2NCl2", static_cast(InputFeatures::kTPCChi2NCl2)}, + {"kDcaXY2", static_cast(InputFeatures::kDcaXY2)}, + {"kDcaZ2", static_cast(InputFeatures::kDcaZ2)}, + {"kTPCNSigmaEl2", static_cast(InputFeatures::kTPCNSigmaEl2)}, + {"kTPCNSigmaPi2", static_cast(InputFeatures::kTPCNSigmaPi2)}, + {"kTPCNSigmaPr2", static_cast(InputFeatures::kTPCNSigmaPr2)}, + {"kTOFNSigmaEl2", static_cast(InputFeatures::kTOFNSigmaEl2)}, + {"kTOFNSigmaPi2", static_cast(InputFeatures::kTOFNSigmaPi2)}, + {"kTOFNSigmaPr2", static_cast(InputFeatures::kTOFNSigmaPr2)}}; + } +}; + +} // namespace o2::analysis + +#endif // PWGDQ_CORE_DQMLRESPONSE_H_ diff --git a/PWGDQ/Core/HistogramManager.cxx b/PWGDQ/Core/HistogramManager.cxx index 146baeb939a..4882b7d84f5 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, bool isdouble) + 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; @@ -330,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, bool isdouble) + int varT, int varW, bool isdouble, bool isFillLabelx) { // // add a histogram @@ -388,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; @@ -559,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 @@ -745,7 +757,7 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) } // get the corresponding std::list containng identifiers to the needed variables to be filled - list varList = fVariablesMap[className]; + auto const& varList = fVariablesMap[className]; TIter next(hList); @@ -754,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}; @@ -764,25 +777,26 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) for (auto varIter = varList.begin(); varIter != varList.end(); varIter++) { h = next(); // get the histogram // decode information from the vector of indices - isProfile = (varIter->at(0) == 1 ? true : false); - isTHn = (varIter->at(1) > 0 ? true : false); + isProfile = ((*varIter)[0] == 1 ? true : false); + isTHn = ((*varIter)[1] > 0 ? true : false); if (isTHn) { - dimension = varIter->at(1); + dimension = (*varIter)[1]; } else { dimension = (reinterpret_cast(h))->GetDimension(); } // get the various variable indices - varW = varIter->at(2); + varW = (*varIter)[2]; if (isTHn) { for (int i = 0; i < dimension; i++) { - fillValues[i] = values[varIter->at(3 + i)]; + fillValues[i] = values[(*varIter)[3 + i]]; } } else { - varX = varIter->at(3); - varY = varIter->at(4); - varZ = varIter->at(5); - varT = varIter->at(6); + varX = (*varIter)[3]; + varY = (*varIter)[4]; + varZ = (*varIter)[5]; + varT = (*varIter)[6]; + isFillLabelx = ((*varIter)[7] == 1 ? true : false); } if (!isTHn) { @@ -790,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; @@ -811,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; @@ -852,7 +890,7 @@ void HistogramManager::FillHistClass(const char* className, Float_t* values) } } } // end else - } // end loop over histograms + } // end loop over histograms } //____________________________________________________________________________________ diff --git a/PWGDQ/Core/HistogramManager.h b/PWGDQ/Core/HistogramManager.h index 273cbfd0bd6..4b1393b2eb7 100644 --- a/PWGDQ/Core/HistogramManager.h +++ b/PWGDQ/Core/HistogramManager.h @@ -67,14 +67,14 @@ 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, bool isdouble = false); + 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, bool isdouble = false); + 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, diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index d98c05a0bb2..dd05a26d359 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -12,8 +12,14 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // #include "PWGDQ/Core/HistogramsLibrary.h" + #include "VarManager.h" +#include "CommonConstants/MathConstants.h" + +#include +#include + void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* histClass, const char* groupName, const char* subGroupName) { // @@ -30,7 +36,7 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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, 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()); + 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")) { @@ -54,16 +60,17 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } 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, 100.0, VarManager::kCollisionTimeRes); + 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, 500., VarManager::kMultTPC, 100, 0.0, 100.0, VarManager::kCollisionTimeRes); - hm->AddHistogram(histClass, "CollTimeRes_MultPV", "Coll. time resolution ", false, 50, 0.0, 500., VarManager::kVtxNcontribReal, 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); @@ -72,44 +79,112 @@ 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")) { if (subGroupStr.Contains("pp")) { - hm->AddHistogram(histClass, "MultTPC", "MultTPC", false, 300, 0.0, 500.0, VarManager::kMultTPC); - hm->AddHistogram(histClass, "MultFV0A", "MultFV0A", false, 300, 0.0, 500.0, VarManager::kMultFV0A); - hm->AddHistogram(histClass, "MultFT0A", "MultFT0A", false, 300, 0.0, 200.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, 300, 0.0, 50.0, VarManager::kMultFDDC); - hm->AddHistogram(histClass, "MultTracklets", "MultTracklets", false, 100, 0.0, 250.0, VarManager::kMultTracklets); - hm->AddHistogram(histClass, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 100.0, VarManager::kVtxNcontribReal); + hm->AddHistogram(histClass, "MultTPC", "MultTPC", false, 250, 0.0, 500.0, VarManager::kMultTPC); + hm->AddHistogram(histClass, "MultFV0A", "MultFV0A", false, 1000, 0.0, 25000.0, VarManager::kMultFV0A); + hm->AddHistogram(histClass, "MultFT0A", "MultFT0A", false, 1000, 0.0, 25000.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "MultFT0C", "MultFT0C", false, 1000, 0.0, 25000.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "MultFDDA", "MultFDDA", false, 1000, 0.0, 25000.0, VarManager::kMultFDDA); + hm->AddHistogram(histClass, "MultFDDC", "MultFDDC", false, 1000, 0.0, 25000.0, VarManager::kMultFDDC); + hm->AddHistogram(histClass, "MultTracklets", "MultTracklets", false, 250, 0.0, 250.0, VarManager::kMultTracklets); + hm->AddHistogram(histClass, "VtxNContribReal", "Vtx n contributors", false, 150, 0.0, 150.0, VarManager::kVtxNcontribReal); hm->AddHistogram(histClass, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 100.0, VarManager::kVtxNcontrib); + hm->AddHistogram(histClass, "MultNTracksPVeta1", "MultNTracksPVeta1", false, 150, 0, 150.0, VarManager::kMultNTracksPVeta1); + hm->AddHistogram(histClass, "MultNTracksPVetaHalf", "MultNTracksPVetaHalf", false, 150, 0, 150.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, 100, -10.0, 10.0, VarManager::kVtxZ, 150, 0, 150.0, VarManager::kVtxNcontribReal); + hm->AddHistogram(histClass, "VtxZ_MultNTracksPVeta1", "VtxZ vs MultNTracksPVeta1", false, 100, -10.0, 10.0, VarManager::kVtxZ, 150, 0, 150.0, VarManager::kMultNTracksPVeta1); + hm->AddHistogram(histClass, "VtxZ_MultNTracksPVetaHalf", "VtxZ vs MultNTracksPVetaHalf", false, 100, -10.0, 10.0, VarManager::kVtxZ, 150, 0, 150.0, VarManager::kMultNTracksPVetaHalf); + hm->AddHistogram(histClass, "VtxZ_MultFV0A", "VtxZ vs MultFV0A", false, 20, -10.0, 10.0, VarManager::kVtxZ, 200, 0, 25000.0, VarManager::kMultFV0A); + hm->AddHistogram(histClass, "VtxZ_MultFT0A", "VtxZ vs MultFT0A", false, 20, -10.0, 10.0, VarManager::kVtxZ, 200, 0, 25000.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "VtxZ_MultFT0C", "VtxZ vs MultFT0C", false, 20, -10.0, 10.0, VarManager::kVtxZ, 200, 0, 25000.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "VtxZ_MultFDDA", "VtxZ vs MultFDDA", false, 20, -10.0, 10.0, VarManager::kVtxZ, 200, 0, 25000.0, VarManager::kMultFDDA); + hm->AddHistogram(histClass, "VtxZ_MultFDDC", "VtxZ vs MultFDDC", false, 20, -10.0, 10.0, VarManager::kVtxZ, 200, 0, 25000.0, VarManager::kMultFDDC); + hm->AddHistogram(histClass, "MultNTracksPVetaHalf_MultMCNParticlesEta05", "MultNTracksPVetaHalf vs MultMCNParticlesEta05", false, 150, 0, 150.0, VarManager::kMultNTracksPVetaHalf, 150, 0, 150.0, VarManager::kMultMCNParticlesEta05); + hm->AddHistogram(histClass, "VtxNcontribReal_MultMCNParticlesEta08", "VtxNcontribReal vs MultMCNParticlesEta08", false, 150, 0, 150.0, VarManager::kVtxNcontribReal, 150, 0, 150.0, VarManager::kMultMCNParticlesEta08); + hm->AddHistogram(histClass, "MultNTracksPVeta1_MultMCNParticlesEta10", "MultNTracksPVeta1 vs MultMCNParticlesEta10", false, 150, 0, 150.0, VarManager::kMultNTracksPVeta1, 150, 0, 150.0, VarManager::kMultMCNParticlesEta10); + } else { - hm->AddHistogram(histClass, "MultTPC", "MultTPC", false, 100, 0.0, 25000.0, VarManager::kMultTPC); - hm->AddHistogram(histClass, "MultFV0A", "MultFV0A", false, 100, 0.0, 25000.0, VarManager::kMultFV0A); - hm->AddHistogram(histClass, "MultFT0A", "MultFT0A", false, 100, 0.0, 25000.0, VarManager::kMultFT0A); - hm->AddHistogram(histClass, "MultFT0C", "MultFT0C", false, 100, 0.0, 25000.0, VarManager::kMultFT0C); - hm->AddHistogram(histClass, "MultFDDA", "MultFDDA", false, 100, 0.0, 25000.0, VarManager::kMultFDDA); - hm->AddHistogram(histClass, "MultFDDC", "MultFDDC", false, 100, 0.0, 25000.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, "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, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 10000.0, VarManager::kVtxNcontribReal); - hm->AddHistogram(histClass, "VtxNContrib", "Vtx n contributors", false, 100, 0.0, 10000.0, VarManager::kVtxNcontrib); - hm->AddHistogram(histClass, "MultTPC_MultFV0A", "MultTPC vs MultFV0A", false, 100, 0, 25000.0, VarManager::kMultTPC, 100, 0, 25000.0, VarManager::kMultFV0A); - hm->AddHistogram(histClass, "MultTPC_MultFT0A", "MultTPC vs MultFT0A", false, 100, 0, 25000.0, VarManager::kMultTPC, 100, 0, 25000.0, VarManager::kMultFT0A); - hm->AddHistogram(histClass, "MultTPC_MultFT0C", "MultTPC vs MultFT0C", false, 100, 0, 25000.0, VarManager::kMultTPC, 100, 0, 25000.0, VarManager::kMultFT0C); - hm->AddHistogram(histClass, "MultFT0A_MultFT0C", "MultFT0A vs MultFT0C", false, 100, 0, 25000.0, VarManager::kMultFT0A, 100, 0, 25000.0, VarManager::kMultFT0C); + 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")) { @@ -123,7 +198,20 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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, 300, 0.0, 30000.0, VarManager::kTrackOccupancyInTimeRange); + 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("qvector")) { + hm->AddHistogram(histClass, "Psi2A_ITStrackOccupancy", "", false, 200, 0.0, 20000.0, VarManager::kTrackOccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2A); + hm->AddHistogram(histClass, "Psi2B_ITStrackOccupancy", "", true, 200, 0.0, 20000.0, VarManager::kTrackOccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2B); + hm->AddHistogram(histClass, "Psi2C_ITStrackOccupancy", "", true, 200, 0.0, 20000.0, VarManager::kTrackOccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2C); + hm->AddHistogram(histClass, "Psi2APOS_ITStrackOccupancy", "", true, 200, 0.0, 20000.0, VarManager::kTrackOccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2APOS); + hm->AddHistogram(histClass, "Psi2ANEG_ITStrackOccupancy", "", true, 200, 0.0, 20000.0, VarManager::kTrackOccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2ANEG); + hm->AddHistogram(histClass, "Psi2A_Ft0cOccupancy", "", false, 200, 0.0, 20000.0, VarManager::kFT0COccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2A); + hm->AddHistogram(histClass, "Psi2B_Ft0cOccupancy", "", true, 200, 0.0, 20000.0, VarManager::kFT0COccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2B); + hm->AddHistogram(histClass, "Psi2C_Ft0cOccupancy", "", true, 200, 0.0, 20000.0, VarManager::kFT0COccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2C); + hm->AddHistogram(histClass, "Psi2APOS_Ft0cOccupancy", "", true, 200, 0.0, 20000.0, VarManager::kFT0COccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2APOS); + hm->AddHistogram(histClass, "Psi2ANEG_Ft0cOccupancy", "", true, 200, 0.0, 20000.0, VarManager::kFT0COccupancyInTimeRange, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kPsi2ANEG); + } } 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); @@ -140,6 +228,13 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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); + hm->AddHistogram(histClass, "MCCentrFT0C", "MC Centrality FT0C", false, 100, 0.0, 100.0, VarManager::kMCEventCentrFT0C); + hm->AddHistogram(histClass, "MultMCNParticlesEta05", "MultMCNParticlesEta05", false, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta05); + hm->AddHistogram(histClass, "MultMCNParticlesEta08", "MultMCNParticlesEta08", false, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta08); + hm->AddHistogram(histClass, "MultMCNParticlesEta10", "MultMCNParticlesEta10", false, 150, 0.0, 150.0, VarManager::kMultMCNParticlesEta10); + } + if (subGroupStr.Contains("subgen")) { + hm->AddHistogram(histClass, "SubGenID", "SubGenerator ID", false, 11, -0.5, 10.5, VarManager::kMCEventSubGeneratorId); } if (subGroupStr.Contains("qvector")) { int varZNA[3] = {VarManager::kQ1ZNAX, VarManager::kQ1ZNAY, VarManager::kCentFT0C}; @@ -169,6 +264,10 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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, "Q2X0APOS", "", false, 500, -10.0, 10.0, VarManager::kQ2X0APOS); + hm->AddHistogram(histClass, "Q2Y0APOS", "", false, 500, -10.0, 10.0, VarManager::kQ2Y0APOS); + hm->AddHistogram(histClass, "Q2X0ANEG", "", false, 500, -10.0, 10.0, VarManager::kQ2X0ANEG); + hm->AddHistogram(histClass, "Q2Y0ANEG", "", false, 500, -10.0, 10.0, VarManager::kQ2Y0ANEG); 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); @@ -185,6 +284,9 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Q2Y0B_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kQ2Y0B); hm->AddHistogram(histClass, "Q2X0C_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kQ2X0C); hm->AddHistogram(histClass, "Q2Y0C_Cent", "", true, 18, 0.0, 90.0, VarManager::kCentVZERO, 500, -10.0, 10.0, VarManager::kQ2Y0C); + hm->AddHistogram(histClass, "Q2X0A_Q2Y0A_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kQ2X0A, 500, -10.0, 10.0, VarManager::kQ2Y0A); + hm->AddHistogram(histClass, "Q2X0B_Q2Y0B_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kQ2X0B, 500, -10.0, 10.0, VarManager::kQ2Y0B); + hm->AddHistogram(histClass, "Q2X0C_Q2Y0C_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kQ2X0C, 500, -10.0, 10.0, VarManager::kQ2Y0C); hm->AddHistogram(histClass, "Q3X0A", "", false, 500, -10.0, 10.0, VarManager::kQ3X0A); hm->AddHistogram(histClass, "Q3Y0A", "", false, 500, -10.0, 10.0, VarManager::kQ3Y0A); hm->AddHistogram(histClass, "Q3X0B", "", false, 500, -10.0, 10.0, VarManager::kQ3X0B); @@ -212,11 +314,25 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Q3X0A_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kQ3X0A); hm->AddHistogram(histClass, "Q3Y0A_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kQ3Y0A); hm->AddHistogram(histClass, "Psi2A", "", false, 100, -2.0, 2.0, VarManager::kPsi2A); + hm->AddHistogram(histClass, "Psi2APOS", "", false, 100, -2.0, 2.0, VarManager::kPsi2APOS); + hm->AddHistogram(histClass, "Psi2ANEG", "", false, 100, -2.0, 2.0, VarManager::kPsi2ANEG); 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); @@ -264,27 +380,43 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_AB); - hm->AddHistogram(histClass, "R2SP_TPCFT0C_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_AC); - hm->AddHistogram(histClass, "R2SP_FT0AFT0C_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2SP_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_TPCFT0A_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_AB); - hm->AddHistogram(histClass, "R2EP_TPCFT0C_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_AC); - hm->AddHistogram(histClass, "R2EP_FT0CFT0A_CentFT0C", "", false, 18, 0.0, 90.0, VarManager::kCentFT0C, 500, -10.0, 10.0, VarManager::kR2EP_BC); + 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); @@ -306,8 +438,8 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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")) { @@ -319,10 +451,10 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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); @@ -349,6 +481,7 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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, "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); @@ -379,10 +512,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); @@ -430,24 +562,54 @@ 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); + } + if (subGroupStr.Contains("tpcpidvspt")) { + hm->AddHistogram(histClass, "TPCnSigEl_Pt", "TPC n-#sigma(e). vs Pt", false, 200, 0.0, 20.0, VarManager::kPt, 100, -5.0, 5.0, VarManager::kTPCnSigmaEl); + hm->AddHistogram(histClass, "TPCnSigPi_Pt", "TPC n-#sigma(#pi). vs Pt", false, 200, 0.0, 20.0, VarManager::kPt, 100, -5.0, 5.0, VarManager::kTPCnSigmaPi); + hm->AddHistogram(histClass, "TPCnSigKa_Pt", "TPC n-#sigma(K). vs Pt", false, 200, 0.0, 20.0, VarManager::kPt, 100, -5.0, 5.0, VarManager::kTPCnSigmaKa); + hm->AddHistogram(histClass, "TPCnSigPr_Pt", "TPC n-#sigma(p). vs Pt", false, 200, 0.0, 20.0, VarManager::kPt, 100, -5.0, 5.0, VarManager::kTPCnSigmaPr); + } } - 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; @@ -456,8 +618,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}; @@ -616,34 +778,21 @@ 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, "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); @@ -690,13 +839,18 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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_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); } } @@ -705,8 +859,6 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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); @@ -717,7 +869,7 @@ 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")) { @@ -731,73 +883,205 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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.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, "Eta_Pt", "", false, 100, -2.0, 2.0, VarManager::kPairEta, 200, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 30.0, VarManager::kPt1); + hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 30.0, VarManager::kPt2); + hm->AddHistogram(histClass, "Eta_Pt_Assoc", "", false, 100, -2.0, 2.0, VarManager::kEta, 200, 0.0, 30.0, VarManager::kPt); + 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); - hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 2000, 0.0, 20.0, VarManager::kPairPtDau); - hm->AddHistogram(histClass, "Pt_Photon", "", false, 500, 0.0, 5.0, VarManager::kPt); - hm->AddHistogram(histClass, "Mass_DileptonPhoton", "", false, 4500, 0.0, 4.5, VarManager::kPairMass); - hm->AddHistogram(histClass, "Pt_DileptonPhoton", "", false, 2000, 0.0, 20.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "Mass_Pt_DileptonPhoton", "", false, 500, 0.0, 5.0, VarManager::kPairMass, 200, 0.0, 20.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "DeltaMass", "", false, 1500, 0.0, 1.5, VarManager::kDeltaMass); - hm->AddHistogram(histClass, "DeltaMass_ptdileptonphoton", "", false, 1000, 0.0, 1.0, VarManager::kDeltaMass, 3000, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Mass_Assoc", "", false, 500, 0.0, 1.0, VarManager::kMassDau); + hm->AddHistogram(histClass, "Mass_Dilepton_Mass_Assoc", "", false, 500, 0.0, 5.0, VarManager::kPairMassDau, 500, 0.0, 5.0, VarManager::kMassDau); + hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 2000, 0.0, 30.0, VarManager::kPairPtDau); + hm->AddHistogram(histClass, "Pt_Assoc", "", false, 500, 0.0, 10.0, VarManager::kPt); + hm->AddHistogram(histClass, "Mass_DileptonAssoc", "", false, 4500, 0.0, 30.0, VarManager::kPairMass); + hm->AddHistogram(histClass, "Pt_DileptonAssoc", "", false, 2000, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Mass_Pt_DileptonAssoc", "", false, 500, 0.0, 30.0, VarManager::kPairMass, 200, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Pt_Rap_DileptonAssoc", "", false, 5120, 0.0, 30.0, VarManager::kPairPt, 1000, -5.0, 5.0, VarManager::kRap); + hm->AddHistogram(histClass, "DeltaMass", "", false, 1500, 0.0, 5.5, VarManager::kDeltaMass); + hm->AddHistogram(histClass, "DeltaMass_ptdileptonassoc", "", false, 1000, 0.0, 1.0, VarManager::kDeltaMass, 3000, 0.0, 30.0, VarManager::kPairPt); 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); + hm->AddHistogram(histClass, "Rapidity", "", false, 400, -5.0, 5.0, VarManager::kRap); } 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, "Mass_Pt", "", false, 500, 0.0, 15.0, VarManager::kMCMass, 40, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "Pt", "", false, 200, 0.0, 20.0, VarManager::kMCPt); 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, "Mass", "", false, 500, 0.0, 15.0, VarManager::kMCMass); + hm->AddHistogram(histClass, "Rapidity", "", false, 100, -5.0, 5.0, VarManager::kMCY); + hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kMCEta, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kMCEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kMCPhi); + if (subGroupStr.Contains("polarization")) { + int varspTHE[4] = {VarManager::kMCPt, VarManager::kMCCosThetaHE, VarManager::kMCPhiHE, VarManager::kMCPhiTildeHE}; + int varspTCS[4] = {VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCPhiCS, VarManager::kMCPhiTildeCS}; + int bins[4] = {20, 20, 20, 20}; + double xmin[4] = {0., -1., 0., 0.}; + double xmax[4] = {20., 1., 2. * o2::constants::math::PI, 2. * o2::constants::math::PI}; + hm->AddHistogram(histClass, "Pt_cosThetaHE_phiHE_phiTildeHE", "", 4, varspTHE, bins, xmin, xmax, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Pt_cosThetaCS_phiCS_phiTildeCS", "", 4, varspTCS, bins, xmin, xmax, 0, -1, kFALSE); + } + } + 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, "PhiMC", "MC #phi", false, 50, -6.3, 6.3, VarManager::kMCPhi); - hm->AddHistogram(histClass, "MCY", "MC y", false, 50, -5.0, 5.0, VarManager::kMCY); + 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::kMCEventCentrFT0C); + 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, "Weight", "", false, 50, 0.0, 5.0, VarManager::kMCParticleWeight); + hm->AddHistogram(histClass, "MCImpPar_CentFT0CMC", "MC impact param vs MC Cent. FT0C", false, 20, 0.0, 20.0, VarManager::kMCEventImpParam, 100, 0.0, 100.0, VarManager::kMCEventCentrFT0C); } + if (!groupStr.CompareTo("energy-correlator-gen")) { + hm->AddHistogram(histClass, "MCCostheta", "Cos#theta", false, 40, -1.0, 1.0, VarManager::kMCCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + hm->AddHistogram(histClass, "MCHadronPdgCode", "MCHadronPdgCode", false, 6000, -3000, 3000, VarManager::kMCHadronPdgCode); + hm->AddHistogram(histClass, "MCMotherPdgCode", "MCMotherPdgCode", false, 6000, -3000, 3000, VarManager::kMCMotherPdgCode); + hm->AddHistogram(histClass, "MCPdgCode", "MCPdgCode", false, 1000, -1000, 1000, VarManager::kMCPdgCode); + hm->AddHistogram(histClass, "Coschi", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight); + hm->AddHistogram(histClass, "Pt_Hadron", "", false, 120, 0.0, 30.0, VarManager::kMCHadronPt); + hm->AddHistogram(histClass, "Eta_Hadron", "", false, 120, -2.0, 2.0, VarManager::kMCHadronEta); + hm->AddHistogram(histClass, "Phi_Hadron", "", false, 120, -2.0, 2.0, VarManager::kMCHadronPhi); + hm->AddHistogram(histClass, "DeltaEta", "", false, 20, -2.0, 2.0, VarManager::kMCdeltaeta); + hm->AddHistogram(histClass, "DeltaPhi", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi); + hm->AddHistogram(histClass, "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kMCdeltaeta, 50, -8.0, 8.0, VarManager::kMCdeltaphi); + // for bkg + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_trans", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_trans); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_toward", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_toward); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_away", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_away); + + hm->AddHistogram(histClass, "Coschi_randomPhi_trans", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_trans, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_trans); + hm->AddHistogram(histClass, "Coschi_randomPhi_toward", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_toward, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_toward); + hm->AddHistogram(histClass, "Coschi_randomPhi_away", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_away, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_away); + } 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, 150, 0, 150.0, VarManager::kVtxNcontribReal); + hm->AddHistogram(histClass, "Mass_MultNTracksPVetaHalf", "Mass vs MultNTracksPVetaHalf", false, 200, 2.0, 5.0, VarManager::kMass, 150, 0, 150.0, VarManager::kMultNTracksPVetaHalf); + hm->AddHistogram(histClass, "Mass_MultNTracksPVeta1", "Mass vs MultNTracksPVeta1", false, 200, 2.0, 5.0, VarManager::kMass, 150, 0, 150.0, VarManager::kMultNTracksPVeta1); + } + if (subGroupStr.Contains("dimuon_fwdmult")) { + hm->AddHistogram(histClass, "Mass_MultFV0A", "Mass vs MultFV0A", false, 200, 2.0, 5.0, VarManager::kMass, 1000, 0, 25000.0, VarManager::kMultFV0A); + hm->AddHistogram(histClass, "Mass_MultFT0A", "Mass vs MultFT0A", false, 200, 2.0, 5.0, VarManager::kMass, 1000, 0, 25000.0, VarManager::kMultFT0A); + hm->AddHistogram(histClass, "Mass_MultFT0C", "Mass vs MultFT0C", false, 200, 2.0, 5.0, VarManager::kMass, 1000, 0, 25000.0, VarManager::kMultFT0C); + hm->AddHistogram(histClass, "Mass_MultFDDA", "Mass vs MultFDDA", false, 200, 2.0, 5.0, VarManager::kMass, 1000, 0, 25000.0, VarManager::kMultFDDA); + hm->AddHistogram(histClass, "Mass_MultFDDC", "Mass vs MultFDDC", false, 200, 2.0, 5.0, VarManager::kMass, 1000, 0, 25000.0, VarManager::kMultFDDC); + } 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); + hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 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("energy-correlator")) { + hm->AddHistogram(histClass, "Mass_Y_Pt", "", false, 125, 0.0, 5.0, VarManager::kMass, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); + } 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("dielectron-polarization-he-pbpb")) { + int varsHEpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaHE, VarManager::kPhiHE}; + int binspT[5] = {100, 30, 10, 10, 10}; + double xminpT[5] = {2., 0., 0, -1., 0.0}; + double xmaxpT[5] = {4.5, 3., 100, 1., 6.28}; + hm->AddHistogram(histClass, "Dielectron_Mass_Pt_Cent_cosThetaHE", "", 5, varsHEpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + + if (subGroupStr.Contains("dielectron-polarization-cs-pbpb")) { + int varsCSpbpb[5] = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaCS, VarManager::kPhiCS}; + int binspT[5] = {100, 30, 10, 10, 10}; + double xminpT[5] = {2.0, 0., 0, -1., 0.0}; + double xmaxpT[5] = {4.5, 3., 100, 1., 6.28}; + hm->AddHistogram(histClass, "Dielectron_Mass_Pt_Cent_cosThetaCS", "", 5, varsCSpbpb, binspT, xminpT, xmaxpT, 0, -1, kFALSE); } 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, "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); + if (subGroupStr.Contains("helicity")) { + hm->AddHistogram(histClass, "Mass_Pt_CosThetaHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaHE); + hm->AddHistogram(histClass, "Mass_Pt_PhiHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiHE); + hm->AddHistogram(histClass, "Mass_Pt_PhiTildeHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildeHE); + } + if (subGroupStr.Contains("collins-soper")) { + hm->AddHistogram(histClass, "Mass_Pt_CosThetaCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaCS); + hm->AddHistogram(histClass, "Mass_Pt_PhiCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiCS); + hm->AddHistogram(histClass, "Mass_Pt_PhiTildeCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildeCS); + } + if (subGroupStr.Contains("production")) { + hm->AddHistogram(histClass, "Mass_Pt_CosThetaPP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaPP); + hm->AddHistogram(histClass, "Mass_Pt_PhiPP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiPP); + hm->AddHistogram(histClass, "Mass_Pt_PhiTildePP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildePP); + } + if (subGroupStr.Contains("random")) { + hm->AddHistogram(histClass, "Mass_Pt_CosThetaRM", "", false, 200, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaRM); + } + } + if (subGroupStr.Contains("globalpolarization")) { + hm->AddHistogram(histClass, "CosThetaStarTPC", "", false, 100, -1.0, 1.0, VarManager::kCosThetaStarTPC); + hm->AddHistogram(histClass, "CosThetaStarFT0A", "", false, 100, -1.0, 1.0, VarManager::kCosThetaStarFT0A); + hm->AddHistogram(histClass, "CosThetaStarFT0C", "", false, 100, -1.0, 1.0, VarManager::kCosThetaStarFT0C); } if (subGroupStr.Contains("upsilon")) { hm->AddHistogram(histClass, "MassUpsilon_Pt", "", false, 500, 7.0, 12.0, VarManager::kMass, 400, 0.0, 40.0, VarManager::kPt); @@ -821,10 +1105,39 @@ 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); + hm->AddHistogram(histClass, "VtxingChi2PCA", "", false, 100, 0.0, 10.0, VarManager::kVertexingChi2PCA); + } + if (subGroupStr.Contains("tauxy-midy-pol-he")) { + int varspTHE[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaHE, VarManager::kVertexingTauxyProjectedPoleJPsiMass}; + int binspT[4] = {50, 10, 20, 1000}; + double xminpT[4] = {2., 0., -1., -0.5}; + double xmaxpT[4] = {4., 20., 1., 0.5}; + hm->AddHistogram(histClass, "Tauxy_Mass_Pt_CosthetaHE", "", 4, varspTHE, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + + if (subGroupStr.Contains("tauxy-midy-pol-rand")) { + int varspTRand[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaRM, VarManager::kVertexingTauxyProjectedPoleJPsiMass}; + + int binspT[4] = {50, 10, 20, 1000}; + double xminpT[4] = {2., 0., -1., -0.5}; + double xmaxpT[4] = {4., 20., 1., 0.5}; + hm->AddHistogram(histClass, "Tauxy_Mass_Pt_CosthetaRand", "", 4, varspTRand, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + + if (subGroupStr.Contains("tauxy-midy-pol-cs")) { + int varspTCS[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaCS, VarManager::kVertexingTauxyProjectedPoleJPsiMass}; + + int binspT[4] = {50, 10, 20, 1000}; + double xminpT[4] = {2., 0., -1., -0.5}; + double xmaxpT[4] = {4., 20., 1., 0.5}; + hm->AddHistogram(histClass, "Tauxy_Mass_Pt_CosthetaCS", "", 4, varspTCS, binspT, xminpT, xmaxpT, 0, -1, kFALSE); } if (subGroupStr.Contains("kalman-filter")) { @@ -908,6 +1221,11 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } else if (subGroupStr.Contains("dimuon")) { 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, 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-tag-and-probe")) { + hm->AddHistogram(histClass, "Mass_PtProbe", "mass vs probe pT", false, 750, 0.0, 15.0, VarManager::kMass, 120, 0.0, 30.0, VarManager::kPt2); // Warning: in the tag-and-probe task t2 is always the probe + hm->AddHistogram(histClass, "Mass_EtaProbe", "mass vs probe eta", false, 750, 0.0, 15.0, VarManager::kMass, 120, 0.0, 30.0, VarManager::kEta2); // Warning: in the tag-and-probe task t2 is always the probe + } if (subGroupStr.Contains("dimuon-multi-diff")) { int varsKine[3] = {VarManager::kMass, VarManager::kPt, VarManager::kRap}; int binsKine[3] = {250, 120, 60}; @@ -915,6 +1233,13 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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); } @@ -933,35 +1258,147 @@ 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("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 varsFT0CCentHE[4] = {VarManager::kMass, VarManager::kCentFT0C, VarManager::kCosThetaHE, VarManager::kPhiHE}; - int binspT[4] = {100, 20, 20, 20}; - int binsCent[4] = {100, 20, 20, 20}; + int binspT[4] = {100, 40, 20, 20}; double xminpT[4] = {1., 0., -1., -3.14}; double xmaxpT[4] = {5., 20., 1., +3.14}; - double xminCent[4] = {1., 0., -1., -3.14}; - double xmaxCent[4] = {5., 100., 1., +3.14}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaHE_phiHE", "", 4, varspTHE, binspT, xminpT, xmaxpT, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_CentFT0C_cosThetaHE_phiHE", "", 4, varsFT0CCentHE, binsCent, xminCent, xmaxCent, 0, -1, kFALSE); } if (subGroupStr.Contains("dimuon-polarization-cs")) { int varspTCS[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaCS, VarManager::kPhiCS}; - int varsFT0CCentCS[4] = {VarManager::kMass, VarManager::kCentFT0C, VarManager::kCosThetaCS, VarManager::kPhiCS}; - int binspT[4] = {100, 20, 20, 20}; - int binsCent[4] = {100, 20, 20, 20}; + int binspT[4] = {100, 40, 20, 20}; double xminpT[4] = {1., 0., -1., -3.14}; double xmaxpT[4] = {5., 20., 1., +3.14}; - double xminCent[4] = {1., 0., -1., -3.14}; - double xmaxCent[4] = {5., 100., 1., +3.14}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaCS_phiCS", "", 4, varspTCS, binspT, xminpT, xmaxpT, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_CentFT0C_cosThetaCS_phiCS", "", 4, varsFT0CCentCS, binsCent, xminCent, xmaxCent, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-pp")) { + int varspTPP[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaPP, VarManager::kPhiPP}; + int binspT[4] = {100, 40, 20, 20}; + double xminpT[4] = {1., 0., -1., -3.14}; + double xmaxpT[4] = {5., 20., 1., +3.14}; + hm->AddHistogram(histClass, "Mass_Pt_cosThetaPP_phiPP", "", 4, varspTPP, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + } + if (subGroupStr.Contains("dimuon-polarization-lowmass-pp")) { + int varspTPP[4] = {VarManager::kMass, VarManager::kPt, VarManager::kCosThetaPP, VarManager::kPhiPP}; + int varsrapPP[4] = {VarManager::kMass, VarManager::kRap, VarManager::kCosThetaPP, VarManager::kPhiPP}; + int binspT[4] = {100, 20, 20, 20}; + int binsy[4] = {100, 10, 20, 20}; + double xminpT[4] = {0.2, 0., -1., -3.14}; + double xmaxpT[4] = {1.5, 20., 1., +3.14}; + double xminy[4] = {0.2, 2.5, -1., -3.14}; + double xmaxy[4] = {1.5, 4.0, 1., +3.14}; + hm->AddHistogram(histClass, "Mass_Pt_cosThetaPP_phiPP", "", 4, varspTPP, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass_y_cosThetaPP_phiPP", "", 4, varsrapPP, 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] = {150, 200, 10, 8}; - double xminpT[4] = {2., 0., 0, 2.0}; - double xmaxpT[4] = {5., 20., 100, 4.5}; + 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")) { @@ -971,6 +1408,13 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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}; @@ -978,23 +1422,76 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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("multiplicity-fvoa")) { + 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 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., 5000., 1., +3.14}; - hm->AddHistogram(histClass, "Mass_MultFV0A_cosThetaHE_phiHE", "", 4, varsFV0AMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_MultFV0A_cosThetaCS_phiCS", "", 4, varsFV0AMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + 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("multiplicity-tpc")) { - int varsTPCMulHE[4] = {VarManager::kMass, VarManager::kMultTPC, VarManager::kCosThetaHE, VarManager::kPhiHE}; - int varsTPCMulCS[4] = {VarManager::kMass, VarManager::kMultTPC, VarManager::kCosThetaCS, VarManager::kPhiCS}; + 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., 2000., 1., +3.14}; - hm->AddHistogram(histClass, "Mass_MultTPC_cosThetaCS_phiCS", "", 4, varsTPCMulCS, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Mass_MultTPC_cosThetaHE_phiHE", "", 4, varsTPCMulHE, binsMul, xminMul, xmaxMul, 0, -1, kFALSE); + 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); @@ -1021,38 +1518,149 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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, 500, 0.0, 1, VarManager::kQuadDCAabsXY); + 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[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}; + // 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); + // 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.; + } + } + + 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::kCORR2REF, 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::kCORR4REF, 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::kCORR2POIMp, 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::kCORR4POIMp, VarManager::kM0111POIoverMp); + 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[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}; + // int varV3[6] = {VarManager::kMass, VarManager::kPt, VarManager::kRap, VarManager::kCentFT0C, VarManager::kR3SP, VarManager::kR3EP}; // removed temporarily 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); + // 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); @@ -1061,6 +1669,12 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "MassMult", "", false, 750, 0.0, 15.0, VarManager::kMass, 301, -0.5, 300.5, VarManager::kVtxNcontrib); hm->AddHistogram(histClass, "MassVtxZMult", "", false, 300, 0.0, 6.0, VarManager::kMass, 60, -15.0, 15.0, VarManager::kVtxZ, 100, 0.0, 100.0, VarManager::kVtxNcontrib); } + if (subGroupStr.Contains("dimuon-drellyan")) { + hm->AddHistogram(histClass, "DY_mass", "", false, 5000, 0.0, 50.0, VarManager::kMass); // 10 MeV mass res + hm->AddHistogram(histClass, "DY_pT", "", false, 2000, 0.0, 100.0, VarManager::kPt); // 50 MeV pT res + hm->AddHistogram(histClass, "DY_y", "", false, 20, 2.0, 4.0, VarManager::kRap); + hm->AddHistogram(histClass, "DY_phi", "", false, 180, constants::math::PI, 2 * constants::math::PI, VarManager::kPhi); + } } else if (subGroupStr.Contains("electronmuon")) { hm->AddHistogram(histClass, "Mass", "", false, 750, 0.0, 30.0, VarManager::kMass); hm->AddHistogram(histClass, "Pt", "", false, 120, 0.0, 30.0, VarManager::kPt); @@ -1068,20 +1682,22 @@ 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", "", false, 600, -0.5 * TMath::Pi(), 1.5 * TMath::Pi(), VarManager::kDeltaPhiPair2); + 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, TMath::Pi(), VarManager::kPairPhiv, "", "", "", -1, -1, true); + 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: @@ -1108,7 +1724,7 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h // steps of size pi/100 double phiv_bins[101]; for (int i = 0; i <= 100; i++) - phiv_bins[i] = TMath::Pi() / 100. * i; + phiv_bins[i] = o2::constants::math::PI / 100. * i; int nbins_phiv = sizeof(phiv_bins) / sizeof(*phiv_bins) - 1; // 3D histo @@ -1173,26 +1789,23 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } if (subGroupStr.Contains("opencharm")) { if (subGroupStr.Contains("dmeson")) { - double mD0_bins[51]; - for (int i = 0; i <= 50; i++) { - mD0_bins[i] = 1.7 + i * 0.006; - } - int nbins_mD0 = sizeof(mD0_bins) / sizeof(*mD0_bins) - 1; - - double ptD0_bins[31]; - for (int i = 0; i <= 16; i++) - ptD0_bins[i] = 0.125 * i; - for (int i = 1; i <= 8; i++) - ptD0_bins[16 + i] = 2 + 0.25 * i; - for (int i = 1; i <= 4; i++) - ptD0_bins[24 + i] = 4 + 1 * i; - ptD0_bins[29] = 8; - ptD0_bins[30] = 20; - int nbins_ptD0 = sizeof(ptD0_bins) / sizeof(*ptD0_bins) - 1; - hm->AddHistogram(histClass, "MassD0region", "", false, nbins_mD0, mD0_bins, VarManager::kMass); - hm->AddHistogram(histClass, "MassD0region_Pt", "", false, nbins_mD0, mD0_bins, VarManager::kMass, nbins_ptD0, ptD0_bins, VarManager::kPt); - hm->AddHistogram(histClass, "MassD0region_eta", "", false, 50, 1.7, 2.0, VarManager::kMass, 40, -2., 2., VarManager::kEta); - hm->AddHistogram(histClass, "MassD0region_TauxyzProj", "", false, 50, 1.7, 2.0, VarManager::kMass, 1000, -0.03, 0.03, VarManager::kVertexingTauxyzProjected); + 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); + hm->AddHistogram(histClass, "Mass_Pt_Ft0cOccupancy", "", false, 150, 0.0, 5.0, VarManager::kMass, 10, 0., 10., VarManager::kPt, 20, 0., 20000., VarManager::kFT0COccupancyInTimeRange); + hm->AddHistogram(histClass, "Mass_Pt_ITStrackOccupancy", "", false, 150, 0.0, 5.0, VarManager::kMass, 10, 0., 10., VarManager::kPt, 20, 0., 20000., VarManager::kTrackOccupancyInTimeRange); } if (subGroupStr.Contains("lambdac")) { hm->AddHistogram(histClass, "MassLambdacRegion", "", false, 50, 2.15, 2.4, VarManager::kMass); @@ -1218,7 +1831,8 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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, "Rap", "", false, 100, -10.0, 10.0, VarManager::kPairRap); + 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); } @@ -1241,12 +1855,40 @@ 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 (!groupStr.Contains("dilepton-hadron-array-correlation")) { + if (subGroupStr.Contains("dilepton-hadron-array-correlation")) { const int kInvMassBins = 500; double InvMassBinLims[kInvMassBins + 1]; for (int i = 0; i <= kInvMassBins; i++) @@ -1257,11 +1899,11 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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 kDelPhiBins = 26; + double DelPhiBinLims[] = {-1.69647, -1.44513, -1.19381, -0.94248, -0.69115, -0.43982, -0.18850, 0.06283, 0.31416, 0.56549, 0.81681, 1.06814, 1.31947, 1.57080, 1.82212, 2.07345, 2.32478, 2.57611, 2.82743, 3.07876, 3.33009, 3.58142, 3.83274, 4.08407, 4.33540, 4.58673, 4.83806}; - 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}; + const int kPtBins = 12; + double PtBinLims[kPtBins + 1] = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 7.5, 10, 20}; TArrayD nJPsiHadCorr[4]; nJPsiHadCorr[0] = TArrayD(kInvMassBins + 1, InvMassBinLims); @@ -1273,9 +1915,31 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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("dilepton-hadron-femto")) { + hm->AddHistogram(histClass, "DileptonHadronKstar_DileptonMass", "", false, 150, 0.0, 3.0, VarManager::kDileptonHadronKstar, 100, 1.5, 4.5, VarManager::kPairMassDau); + } if (subGroupStr.Contains("opencharm")) { hm->AddHistogram(histClass, "Delta_Mass_DstarD0region", "", false, 50, 0.14, 0.16, VarManager::kDeltaMass); } + if (subGroupStr.Contains("energy-correlator")) { + hm->AddHistogram(histClass, "Coschi", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kECWeight); + hm->AddHistogram(histClass, "CosTheta_woweight", "", false, 40, -1.0, 1.0, VarManager::kCosTheta); + hm->AddHistogram(histClass, "CosTheta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kEWeight_before); + hm->AddHistogram(histClass, "Pt_Hadron", ";P_{T}", false, 120, 0.0, 30.0, VarManager::kPtDau); + hm->AddHistogram(histClass, "Eta_Hadron", ";#eta", false, 120, -2.0, 2.0, VarManager::kEtaDau); + hm->AddHistogram(histClass, "Phi_Hadron", ";#phi", false, 120, -8, 8, VarManager::kPhiDau); + hm->AddHistogram(histClass, "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhi); + hm->AddHistogram(histClass, "DeltaEta", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta); + hm->AddHistogram(histClass, "DeltaPhi", "", false, 50, -8.0, 8.0, VarManager::kDeltaPhi); + // for bkg + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_trans", "", false, 50, -8.0, 8.0, VarManager::kdeltaphi_randomPhi_trans); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_toward", "", false, 50, -8.0, 8.0, VarManager::kdeltaphi_randomPhi_toward); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_away", "", false, 50, -8.0, 8.0, VarManager::kdeltaphi_randomPhi_away); + + hm->AddHistogram(histClass, "Coschi_randomPhi_trans", "", false, 40, -1.0, 1.0, VarManager::kCosChi_randomPhi_trans, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kWeight_randomPhi_trans); + hm->AddHistogram(histClass, "Coschi_randomPhi_toward", "", false, 40, -1.0, 1.0, VarManager::kCosChi_randomPhi_toward, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kWeight_randomPhi_toward); + hm->AddHistogram(histClass, "Coschi_randomPhi_away", "", false, 40, -1.0, 1.0, VarManager::kCosChi_randomPhi_away, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kWeight_randomPhi_away); + } } if (!groupStr.CompareTo("dilepton-charmhadron")) { @@ -1308,7 +1972,7 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } } if (!groupStr.CompareTo("dilepton-dihadron")) { - if (subGroupStr.EqualTo("xtojpsipipi")) { + if (subGroupStr.Contains("xtojpsipipi") || subGroupStr.Contains("psi2stojpsipipi")) { hm->AddHistogram(histClass, "hMass_X3872", "", false, 1000, 3.0, 5.0, VarManager::kQuadMass); 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); @@ -1317,11 +1981,12 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "hCostheta_Jpsi_Dihadron", "", false, 100, -1.0, 1.0, VarManager::kCosthetaDileptonDitrack); 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, "hQ_X3872", "", false, 300, -3.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, "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, "hDeltaR_X3872", "", false, 100, 0.0, 10.0, VarManager::kDeltaR); + hm->AddHistogram(histClass, "hMass_Q_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadMass, 300, -3.0, 3.0, VarManager::kQ); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_Q_X3872", "", false, 100, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 300, -3.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); @@ -1341,6 +2006,60 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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 (subGroupStr.Contains("vertexing")) { + hm->AddHistogram(histClass, "UsedKF", "", false, 2, -0.5, 1.5, VarManager::kUsedKF); + hm->AddHistogram(histClass, "KFMass", "", false, 750, 0.0, 30.0, VarManager::kKFMass); + hm->AddHistogram(histClass, "Lz", "", false, 1000, -0.2, 0.2, VarManager::kVertexingLz); + hm->AddHistogram(histClass, "Lxy", "", false, 1000, -0.2, 0.2, VarManager::kVertexingLxy); + hm->AddHistogram(histClass, "Lxyz", "", false, 1000, -0.2, 0.2, VarManager::kVertexingLxyz); + hm->AddHistogram(histClass, "Tauz", "", false, 4000, -0.01, 0.01, VarManager::kVertexingTauz); + hm->AddHistogram(histClass, "Tauxy", "", false, 4000, -0.01, 0.01, VarManager::kVertexingTauxy); + hm->AddHistogram(histClass, "LxyzErr", "", false, 100, 0.0, 0.2, VarManager::kVertexingLxyzErr); + hm->AddHistogram(histClass, "LzErr", "", false, 100, 0.0, 0.2, VarManager::kVertexingLzErr); + hm->AddHistogram(histClass, "TauzErr", "", false, 100, 0.0, 0.2, VarManager::kVertexingTauzErr); + hm->AddHistogram(histClass, "VtxingProcCode", "", false, 10, 0.0, 10.0, VarManager::kVertexingProcCode); + hm->AddHistogram(histClass, "VtxingChi2PCA", "", false, 100, 0.0, 10.0, VarManager::kVertexingChi2PCA); + hm->AddHistogram(histClass, "LzProj", "", false, 1000, -0.2, 0.2, VarManager::kVertexingLzProjected); + hm->AddHistogram(histClass, "LxyProj", "", false, 1000, -0.2, 0.2, VarManager::kVertexingLxyProjected); + hm->AddHistogram(histClass, "LxyzProj", "", false, 1000, -0.2, 0.2, VarManager::kVertexingLxyzProjected); + 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); + hm->AddHistogram(histClass, "KFChi2OverNDFGeo", "", false, 150, -5, 10, VarManager::kKFChi2OverNDFGeo); + hm->AddHistogram(histClass, "hMass_Chi2OverNDFGeo", "", false, 1000, 3.0, 5.0, VarManager::kQuadMass, 150, -5, 10., VarManager::kKFChi2OverNDFGeo); + hm->AddHistogram(histClass, "hMass_defaultDileptonMass_Chi2OverNDFGeo", "", false, 1000, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass, 150, -5, 10., VarManager::kKFChi2OverNDFGeo); + } + } + if (subGroupStr.Contains("mctruth")) { + 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, "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, "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, "LzMC", "", false, 1000, 0.0, 2.0, VarManager::kMCVertexingLz); + hm->AddHistogram(histClass, "LxyMC", "", false, 1000, 0.0, 2.0, VarManager::kMCVertexingLxy); + hm->AddHistogram(histClass, "LxyzMC", "", false, 1000, 0.0, 2.0, VarManager::kMCVertexingLxyz); + hm->AddHistogram(histClass, "LxyMCExpected", "", false, 1000, 0.0, 2.0, VarManager::kMCLxyExpected); + hm->AddHistogram(histClass, "LxyzMCExpected", "", false, 1000, 0.0, 2.0, VarManager::kMCLxyzExpected); + hm->AddHistogram(histClass, "LxyMC_LxyMCExpected", "", false, 500, 0.0, 2.0, VarManager::kMCVertexingLxy, 500, 0.0, 2.0, VarManager::kMCLxyExpected); + hm->AddHistogram(histClass, "LxyzMC_LxyzMCExpected", "", false, 500, 0.0, 2.0, VarManager::kMCVertexingLxyz, 500, 0.0, 2.0, VarManager::kMCLxyzExpected); + hm->AddHistogram(histClass, "TauzMC", "", false, 4000, -0.01, 0.01, VarManager::kMCVertexingTauz); + hm->AddHistogram(histClass, "TauxyMC", "", false, 4000, -0.01, 0.01, VarManager::kMCVertexingTauxy); + hm->AddHistogram(histClass, "TauzMC_PtMC", "", false, 500, -0.01, 0.01, VarManager::kMCVertexingTauz, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "TauxyMC_PtMC", "", false, 500, -0.01, 0.01, VarManager::kMCVertexingTauxy, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "TauzProjectedMC", "", false, 4000, -0.5, 0.5, VarManager::kMCVertexingTauzProjected); + hm->AddHistogram(histClass, "TauxyProjectedMC", "", false, 4000, -0.5, 0.5, VarManager::kMCVertexingTauxyProjected); + hm->AddHistogram(histClass, "TauzProjectedMC_PtMC", "", false, 500, -0.5, 0.5, VarManager::kMCVertexingTauzProjected, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "TauxyProjectedMC_PtMC", "", false, 500, -0.5, 0.5, VarManager::kMCVertexingTauxyProjected, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "LzMC_Lz", "", false, 500, 0.0, 2.0, VarManager::kMCVertexingLz, 500, 0.0, 2.0, VarManager::kVertexingLz); + hm->AddHistogram(histClass, "LxyMC_Lxy", "", false, 500, 0.0, 2.0, VarManager::kMCVertexingLxy, 500, 0.0, 2.0, VarManager::kVertexingLxy); + hm->AddHistogram(histClass, "TauzMC_Tauz", "", false, 500, -0.01, 0.01, VarManager::kMCVertexingTauz, 500, -0.01, 0.01, VarManager::kVertexingTauz); + hm->AddHistogram(histClass, "TauxyMC_Tauxy", "", false, 500, -0.01, 0.01, VarManager::kMCVertexingTauxy, 500, -0.01, 0.01, VarManager::kVertexingTauxy); + hm->AddHistogram(histClass, "CosPointingAngleMC", "", false, 100, 0.0, 1.0, VarManager::kMCCosPointingAngle); } if (!groupStr.CompareTo("dilepton-photon-mass")) { hm->AddHistogram(histClass, "Mass_Dilepton", "", false, 500, 0.0, 5.0, VarManager::kPairMassDau); @@ -1366,9 +2085,463 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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; + } + + // check that the histClass field is an array of strings + if (!hist->FindMember("histClass")->value.IsArray()) { + LOG(fatal) << "histClass field should be an array of strings, e.g. [class1, class2]"; + return false; + } + for (auto& v : hist->FindMember("histClass")->value.GetArray()) { + if (!v.IsString()) { + LOG(fatal) << "histClass field should be an array of strings, e.g. [class1, class2]"; + 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; + } + + // create an array of strings to store the different histogram classes + std::vector histClasses; + for (auto& v : hist.FindMember("histClass")->value.GetArray()) { + histClasses.push_back(v.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) { + for (auto histClass : histClasses) { + hm->AddHistogram(histClass, histName, title, nDimensions, vars, nBins, xmin, xmax, axLabels, varW, useSparse, isDouble); + } + } else { + for (auto histClass : histClasses) { + 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) { + for (auto histClass : histClasses) { + 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); + } + for (auto histClass : histClasses) { + 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 b157ff0897b..6c7b88492c9 100644 --- a/PWGDQ/Core/MCSignalLibrary.cxx +++ b/PWGDQ/Core/MCSignalLibrary.cxx @@ -11,11 +11,20 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // -#include -#include "CommonConstants/PhysicsConstants.h" +#include +#include +// #include + #include "PWGDQ/Core/MCSignalLibrary.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/Logger.h" + +#include + using namespace o2::constants::physics; +// using std::cout; +// using std::endl; MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) { @@ -80,12 +89,43 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Primary Kaons", {prong}, {-1}); // define the signal using the full constructor return signal; } + if (!nameStr.compare("Lambda0Baryon")) { + MCProng prong(1, {3122}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "Lambda0 Baryon", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("SigmaPlusBaryon")) { + MCProng prong(1, {3222}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "SigmaPlus Baryon", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("proton")) { + MCProng prong(1, {2212}, {true}, {false}, {0}, {0}, {false}); + signal = new MCSignal(name, "proton", {prong}, {-1}); + return signal; + } if (!nameStr.compare("protonPrimary")) { MCProng prong(1, {2212}, {true}, {false}, {0}, {0}, {false}); // define 1-generation prong using the full constructor prong.SetSourceBit(0, MCProng::kPhysicalPrimary); // set source to be ALICE primary particles signal = new MCSignal(name, "Primary Proton", {prong}, {-1}); // define the signal using the full constructor return signal; } + if (!nameStr.compare("protonFromTransport")) { + MCProng prong(1, {2212}, {true}, {false}, {0}, {0}, {false}); + prong.SetSourceBit(0, MCProng::kProducedInTransport); + signal = new MCSignal(name, "ProtonFromTransport", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("protonFromLambda0")) { + MCProng prong(2, {2212, 3122}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Proton from Lambda0 decays", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("protonFromSigmaPlus")) { + MCProng prong(2, {2212, 3222}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Proton from Sigma+ decays", {prong}, {-1}); + return signal; + } if (!nameStr.compare("phiMeson")) { MCProng prong(1, {333}, {true}, {false}, {0}, {0}, {false}); // define 1-generation prong using the full constructor signal = new MCSignal(name, "phi meson", {prong}, {-1}); // define the signal using the full constructor @@ -114,14 +154,32 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Electrons from prompt jpsi decays", {prong}, {-1}); return signal; } + if (!nameStr.compare("ePrimaryFromNonpromptJpsi")) { + MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from non-prompt jpsi decays with beauty in decay chain", {prong}, {-1}); + return signal; + } if (!nameStr.compare("Jpsi")) { MCProng prong(1, {443}, {true}, {false}, {0}, {0}, {false}); signal = new MCSignal(name, "Inclusive jpsi", {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}); + 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("promptJpsi")) { @@ -129,13 +187,44 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Prompt jpsi (not from beauty)", {prong}, {-1}); return signal; } + if (!nameStr.compare("nonPromptJpsi")) { + MCProng prong(1, {443}, {true}, {false}, {0}, {0}, {false}, false, {503}, {false}); + signal = new MCSignal(name, "Non-prompt jpsi (from beauty)", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("nonPromptJpsiFromBeauty")) { + MCProng prong(2, {443, 503}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Non-prompt jpsi directly from beauty", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("nonPromptJpsiNotDirectlyFromBeauty")) { + MCProng prong(2, {443, 503}, {true, true}, {false, true}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + signal = new MCSignal(name, "Non-prompt jpsi from other but with beauty in decay chain", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("AnythingDecayToJpsi")) { + MCProng prong(2, {MCProng::kPDGCodeNotAssigned, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSignalInTime(true); + signal = new MCSignal(name, "Decay of anything into J/psi", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("eeFromNonpromptPsi2S")) { + MCProng prong(2, {11, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + signal = new MCSignal(name, "ee pairs from non-prompt psi2s decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } + if (!nameStr.compare("eeFromPromptPsi2S")) { + MCProng prong(2, {11, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + signal = new MCSignal(name, "ee pairs from prompt psi2s decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } if (!nameStr.compare("eFromNonpromptPsi2S")) { - MCProng prong(3, {11, 100443, 503}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prong(2, {11, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); signal = new MCSignal(name, "Electrons from beauty psi2s decays", {prong}, {-1}); return signal; } if (!nameStr.compare("eFromPromptPsi2S")) { - MCProng prong(3, {11, 100443, 503}, {true, true, true}, {false, false, true}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + MCProng prong(2, {11, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); signal = new MCSignal(name, "Electrons from prompt psi2s decays", {prong}, {-1}); return signal; } @@ -145,12 +234,12 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) return signal; } if (!nameStr.compare("nonPromptPsi2S")) { - MCProng prong(2, {100443, 503}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prong(1, {100443}, {true}, {false}, {0}, {0}, {false}, false, {503}, {false}); signal = new MCSignal(name, "Non-prompt psi2s", {prong}, {-1}); return signal; } if (!nameStr.compare("promptPsi2S")) { - MCProng prong(2, {100443, 503}, {true, true}, {false, true}, {0, 0}, {0, 0}, {false, false}); + MCProng prong(1, {100443}, {true}, {false}, {0}, {0}, {false}, false, {503}, {true}); signal = new MCSignal(name, "Prompt psi2s (not from beauty)", {prong}, {-1}); return signal; } @@ -174,16 +263,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}); @@ -210,11 +326,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}); @@ -298,6 +426,12 @@ 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")) { @@ -331,6 +465,12 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) 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 @@ -385,9 +525,13 @@ 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); + MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); signal = new MCSignal(name, "Electrons from jpsi decays", {prong}, {-1}); return signal; } @@ -456,6 +600,24 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) 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); @@ -510,6 +672,36 @@ 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}); + 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}); + 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}); + 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")) { @@ -522,6 +714,57 @@ 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}); + 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}); + 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}); + signal = new MCSignal(name, "muons from b->c->mu", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("secondaryMuon")) { + MCProng prong(1, {13}, {true}, {false}, {0}, {0}, {false}); + 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}); + 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}); + 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}); + 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")) { @@ -663,6 +906,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); @@ -675,11 +932,29 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "ee pairs from non-prompt j/psi decays", {prong, prong}, {1, 1}); // signal at pair level return signal; } + if (!nameStr.compare("mumuFromPhi")) { + MCProng prong(2, {13, 333}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "mumu pairs from phi decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } if (!nameStr.compare("mumuFromJpsi")) { MCProng prong(2, {13, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); signal = new MCSignal(name, "mumu pairs from j/psi decays", {prong, prong}, {1, 1}); // signal at pair level return signal; } + if (!nameStr.compare("mumuFromPromptJpsi")) { + MCProng prong(2, {13, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "mumu pairs from prompt j/psi decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } + if (!nameStr.compare("mumuFromNonPromptJpsi")) { + MCProng prong(2, {13, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "mumu pairs from non-prompt j/psi decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } if (!nameStr.compare("eeFromPsi2S")) { MCProng prong(2, {11, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -691,6 +966,33 @@ 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("mumuFromPromptPsi2S")) { + MCProng prong(2, {13, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "mumu pairs from prompt psi2s decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } + if (!nameStr.compare("mumuFromNonPromptPsi2S")) { + MCProng prong(2, {13, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "mumu pairs from non-prompt 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); @@ -886,33 +1188,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}); @@ -967,6 +1344,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}); @@ -979,6 +1383,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}); @@ -992,12 +1408,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}); @@ -1020,6 +1548,143 @@ 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("nonPromptD0")) { + MCProng prong(2, {Pdg::kD0, 503}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Non-prompt D0", {prong}, {-1}); + return signal; + } + if (!nameStr.compare("D0FS")) { + MCProng prong(1, {Pdg::kD0}, {true}, {false}, {0}, {0}, {false}); + prong.SetSourceBit(0, MCProng::kHEPMCFinalState); + 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("KPiFromD0Reflected")) { + MCProng prongFalseKaon(2, {211, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + MCProng prongFalsePion(2, {321, Pdg::kD0}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + signal = new MCSignal(name, "Kaon and pion pair from D0 with reflected mass assumption", {prongFalseKaon, prongFalsePion}, {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")) { @@ -1160,5 +1825,593 @@ 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("JpsiFromPromptPsi2S")) { + MCProng prong(2, {443, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + signal = new MCSignal(name, "Jpsi from prompt Psi2S", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("JpsiFromNonpromptPsi2S")) { + MCProng prong(2, {443, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + signal = new MCSignal(name, "Jpsi from non-prompt Psi2S", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("eFromJpsiFromPsi2S")) { + 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("eFromJpsiFromPromptPsi2S")) { + MCProng prong(3, {11, 443, 100443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {503}, {true}); + signal = new MCSignal(name, "Electron from Jpsi from prompt Psi2S", {prong}, {1}); + return signal; + } + + if (!nameStr.compare("eFromJpsiFromNonpromptPsi2S")) { + MCProng prong(3, {11, 443, 100443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {503}, {false}); + signal = new MCSignal(name, "Electron from Jpsi from non-prompt 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("PionFromPromptPsi2S")) { + MCProng prong(2, {211, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + signal = new MCSignal(name, "Pion from prompt Psi2S", {prong}, {-1}); + return signal; + } + + if (!nameStr.compare("PionFromNonpromptPsi2S")) { + MCProng prong(2, {211, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + signal = new MCSignal(name, "Pion from non-prompt 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("eeFromJpsiFromPromptPsi2S")) { + MCProng prong(3, {11, 443, 100443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {503}, {true}); + signal = new MCSignal(name, "Electron pair from Jpsi from prompt Psi2S", {prong, prong}, {1, 1}); + return signal; + } + + if (!nameStr.compare("eeFromJpsiFromNonpromptPsi2S")) { + MCProng prong(3, {11, 443, 100443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {503}, {false}); + signal = new MCSignal(name, "Electron pair from Jpsi from non-prompt 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; + } + + if (!nameStr.compare("eePiPiFromPromptPsi2S")) { + MCProng pronge(3, {11, 443, 100443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {503}, {true}); + MCProng prongPi(2, {211, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + signal = new MCSignal(name, "Electron pair and pion pair from prompt Psi2S", {pronge, pronge, prongPi, prongPi}, {2, 2, 1, 1}); + return signal; + } + + if (!nameStr.compare("eePiPiFromNonpromptPsi2S")) { + MCProng pronge(3, {11, 443, 100443}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}, false, {503}, {false}); + MCProng prongPi(2, {211, 100443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + signal = new MCSignal(name, "Electron pair and pion pair from non-prompt Psi2S", {pronge, pronge, prongPi, prongPi}, {2, 2, 1, 1}); + return signal; + } + + if (!nameStr.compare("eeFromPromptJpsiAnyPrimary")) { + MCProng pronge(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongPrimary(1); + prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "anyprimary and electron pair from prompt jpsi", {pronge, pronge, prongPrimary}, {1, 1, -1}); + return signal; + } + + if (!nameStr.compare("eeFromJpsiAnyPrimary")) { + MCProng pronge(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongPrimary(1); + prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "anyprimary and electron pair from prompt jpsi", {pronge, pronge, prongPrimary}, {1, 1, -1}); + return signal; + } + + if (!nameStr.compare("eeFromNonPromptJpsiAnyPrimary")) { + MCProng pronge(3, {11, 443, 503}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongPrimary(1); + prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "anyprimary and electron pair from non-prompt jpsi", {pronge, pronge, prongPrimary}, {1, 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 0682a224ad3..9cb2eb9029d 100644 --- a/PWGDQ/Core/MixingLibrary.cxx +++ b/PWGDQ/Core/MixingLibrary.cxx @@ -64,6 +64,18 @@ void o2::aod::dqmixing::SetUpMixing(MixingHandler* mh, const char* mixingVarible std::vector fCentFT0CLimsHashing = {0.0f, 2.5f, 5.0f, 7.5f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f}; mh->AddMixingVariable(VarManager::kCentFT0C, fCentFT0CLimsHashing.size(), fCentFT0CLimsHashing); } + if (!nameStr.compare("Mult1")) { + std::vector fMultLimsHashing = {0.0f, 10.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 120.0f, 160.0f, 350.0f}; + mh->AddMixingVariable(VarManager::kVtxNcontrib, fMultLimsHashing.size(), fMultLimsHashing); + } + if (!nameStr.compare("Mult2")) { + std::vector fMultLimsHashing = {0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 120.0f, 140.0f, 180.0f, 350.0f}; + mh->AddMixingVariable(VarManager::kVtxNcontrib, fMultLimsHashing.size(), fMultLimsHashing); + } + if (!nameStr.compare("Mult3")) { + std::vector fMultLimsHashing = {0.0f, 5.0f, 10.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 45.0f, 50.0f, 55.0f, 60.0f, 65.0f, 70.0f, 75.0f, 80.0f, 85.0f, 90.0f, 100.0f, 120.0f, 140.0f, 165.0f, 200.0f, 350.0f}; + mh->AddMixingVariable(VarManager::kVtxNcontrib, fMultLimsHashing.size(), fMultLimsHashing); + } if (!nameStr.compare("Vtx1")) { std::vector fZLimsHashing = {-10.0f, 0.0f, 10.0f}; mh->AddMixingVariable(VarManager::kVtxZ, fZLimsHashing.size(), fZLimsHashing); @@ -156,4 +168,32 @@ void o2::aod::dqmixing::SetUpMixing(MixingHandler* mh, const char* mixingVarible 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); } + if (!nameStr.compare("MedianTimeA1")) { + std::vector fMTLimsHashing = {-100.0f, -40.0f, -20.0f, 20.0f, 40.0f, 100.0f}; + mh->AddMixingVariable(VarManager::kNTPCmedianTimeLongA, fMTLimsHashing.size(), fMTLimsHashing); + } + if (!nameStr.compare("MedianTimeA2")) { + std::vector fMTLimsHashing = {-100.0f, -80.0f, -60.0f, -40.0f, -20.0f, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f}; + mh->AddMixingVariable(VarManager::kNTPCmedianTimeLongA, fMTLimsHashing.size(), fMTLimsHashing); + } + if (!nameStr.compare("MedianTimeA3")) { + std::vector fMTLimsHashing = {-100.0f, -80.0f, -60.0f, -40.0f, -30.0f, -20.0f, -10.0f, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 60.0f, 80.0f, 100.0f}; + mh->AddMixingVariable(VarManager::kNTPCmedianTimeLongA, fMTLimsHashing.size(), fMTLimsHashing); + } + if (!nameStr.compare("PileUpA1")) { + std::vector fPileUpLimsHashing = {0.0f, 1000.0f, 2000.0f, 6000.0f, 10000.0f, 20000.0f}; + mh->AddMixingVariable(VarManager::kNTPCcontribLongA, fPileUpLimsHashing.size(), fPileUpLimsHashing); + } + if (!nameStr.compare("PileUpA2")) { + std::vector fPileUpLimsHashing = {0.0f, 1000.0f, 2000.0f, 4000.0f, 6000.0f, 8000.0f, 10000.0f, 20000.0f}; + mh->AddMixingVariable(VarManager::kNTPCcontribLongA, fPileUpLimsHashing.size(), fPileUpLimsHashing); + } + if (!nameStr.compare("PileUpA3")) { + std::vector fPileUpLimsHashing = {0.0f, 1000.0f, 2000.0f, 3000.0f, 4000.0f, 5000.0f, 6000.0f, 8000.0f, 10000.0f, 20000.0f}; + mh->AddMixingVariable(VarManager::kNTPCcontribLongA, fPileUpLimsHashing.size(), fPileUpLimsHashing); + } + if (!nameStr.compare("PileUpA4")) { + std::vector fPileUpLimsHashing = {0.0f, 500.0f, 1000.0f, 1500.0f, 2000.0f, 2500.0f, 3000.0f, 3500.0f, 4000.0f, 4500.0f, 5000.0f, 5500.0f, 6000.0f, 8000.0f, 10000.0f, 20000.0f}; + mh->AddMixingVariable(VarManager::kNTPCcontribLongA, fPileUpLimsHashing.size(), fPileUpLimsHashing); + } } diff --git a/PWGDQ/Core/MuonMatchingMlResponse.h b/PWGDQ/Core/MuonMatchingMlResponse.h new file mode 100644 index 00000000000..236a4f48329 --- /dev/null +++ b/PWGDQ/Core/MuonMatchingMlResponse.h @@ -0,0 +1,428 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MuonMatchingMlResponse.h +/// \brief Class to compute the ML response for MFT-Muon matching +/// \author Maurice Coquet + +#ifndef PWGDQ_CORE_MUONMATCHINGMLRESPONSE_H_ +#define PWGDQ_CORE_MUONMATCHINGMLRESPONSE_H_ + +#include "Tools/ML/MlResponse.h" + +#include +#include +#include + +// 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_MFTMUON_MATCH(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesMFTMuonMatch::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_MUON_TRACK(FEATURE, GETTER) \ + case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ + inputFeature = muon.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 GETTER=FEATURE from track +#define CHECK_AND_FILL_MUONGLOB_TRACK(FEATURE, GETTER) \ + case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ + inputFeature = muonglob.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 GETTER=FEATURE from track +#define CHECK_AND_FILL_MFT_TRACK(FEATURE, GETTER) \ + case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ + inputFeature = mft.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 GETTER=FEATURE from track +#define CHECK_AND_FILL_MUON_COV(FEATURE, GETTER) \ + case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ + inputFeature = muoncov.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 GETTER=FEATURE from track +#define CHECK_AND_FILL_MFT_COV(FEATURE, GETTER) \ + case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ + inputFeature = mftcov.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 and GETTER2 from track. +#define CHECK_AND_FILL_MFTMUON_DIFF(FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesMFTMuonMatch::FEATURE): { \ + inputFeature = (mft.GETTER2() - muon.GETTER1()); \ + 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_MFTMUON_COLLISION(GETTER) \ + case static_cast(InputFeaturesMFTMuonMatch::GETTER): { \ + inputFeature = collision.GETTER(); \ + break; \ + } + +namespace o2::analysis +{ +// possible input features for ML +enum class InputFeaturesMFTMuonMatch : uint8_t { + zMatching, + xMFT, + yMFT, + qOverptMFT, + tglMFT, + phiMFT, + dcaXY, + dcaZ, + chi2MFT, + nClustersMFT, + xMCH, + yMCH, + qOverptMCH, + tglMCH, + phiMCH, + nClustersMCH, + chi2MCH, + pdca, + Rabs, + cXXMFT, + cXYMFT, + cYYMFT, + cPhiYMFT, + cPhiXMFT, + cPhiPhiMFT, + cTglYMFT, + cTglXMFT, + cTglPhiMFT, + cTglTglMFT, + c1PtYMFT, + c1PtXMFT, + c1PtPhiMFT, + c1PtTglMFT, + c1Pt21Pt2MFT, + cXXMCH, + cXYMCH, + cYYMCH, + cPhiYMCH, + cPhiXMCH, + cPhiPhiMCH, + cTglYMCH, + cTglXMCH, + cTglPhiMCH, + cTglTglMCH, + c1PtYMCH, + c1PtXMCH, + c1PtPhiMCH, + c1PtTglMCH, + c1Pt21Pt2MCH, + deltaX, + deltaY, + deltaPhi, + deltaEta, + deltaPt, + posX, + posY, + posZ, + numContrib, + trackOccupancyInTimeRange, + ft0cOccupancyInTimeRange, + multFT0A, + multFT0C, + multNTracksPV, + multNTracksPVeta1, + multNTracksPVetaHalf, + isInelGt0, + isInelGt1, + multFT0M, + centFT0M, + centFT0A, + centFT0C, + chi2MCHMFT, + chi2GlobMUON +}; + +template +class MlResponseMFTMuonMatch : public MlResponse +{ + public: + /// Default constructor + MlResponseMFTMuonMatch() = default; + /// Default destructor + virtual ~MlResponseMFTMuonMatch() = default; + + template + float returnFeature(uint8_t idx, T1 const& muon, T2 const& mft, C1 const& muoncov, C2 const& mftcov, U const& collision) + { + float inputFeature = 0.; + switch (idx) { + CHECK_AND_FILL_MFT_TRACK(zMatching, z); + CHECK_AND_FILL_MFT_TRACK(xMFT, x); + CHECK_AND_FILL_MFT_TRACK(yMFT, y); + CHECK_AND_FILL_MFT_TRACK(qOverptMFT, signed1Pt); + CHECK_AND_FILL_MFT_TRACK(tglMFT, tgl); + CHECK_AND_FILL_MFT_TRACK(phiMFT, phi); + CHECK_AND_FILL_MFT_TRACK(chi2MFT, chi2); + CHECK_AND_FILL_MFT_TRACK(nClustersMFT, nClusters); + CHECK_AND_FILL_MUON_TRACK(dcaXY, fwddcaXY); + CHECK_AND_FILL_MUON_TRACK(dcaZ, fwddcaz); + CHECK_AND_FILL_MUON_TRACK(xMCH, x); + CHECK_AND_FILL_MUON_TRACK(yMCH, y); + CHECK_AND_FILL_MUON_TRACK(qOverptMCH, signed1Pt); + CHECK_AND_FILL_MUON_TRACK(tglMCH, tgl); + CHECK_AND_FILL_MUON_TRACK(phiMCH, phi); + CHECK_AND_FILL_MUON_TRACK(nClustersMCH, nClusters); + CHECK_AND_FILL_MUON_TRACK(chi2MCH, chi2); + CHECK_AND_FILL_MUON_TRACK(pdca, pDca); + CHECK_AND_FILL_MFT_COV(cXXMFT, cXX); + CHECK_AND_FILL_MFT_COV(cXYMFT, cXY); + CHECK_AND_FILL_MFT_COV(cYYMFT, cYY); + CHECK_AND_FILL_MFT_COV(cPhiYMFT, cPhiY); + CHECK_AND_FILL_MFT_COV(cPhiXMFT, cPhiX); + CHECK_AND_FILL_MFT_COV(cPhiPhiMFT, cPhiPhi); + CHECK_AND_FILL_MFT_COV(cTglYMFT, cTglY); + CHECK_AND_FILL_MFT_COV(cTglXMFT, cTglX); + CHECK_AND_FILL_MFT_COV(cTglPhiMFT, cTglPhi); + CHECK_AND_FILL_MFT_COV(cTglTglMFT, cTglTgl); + CHECK_AND_FILL_MFT_COV(c1PtYMFT, c1PtY); + CHECK_AND_FILL_MFT_COV(c1PtXMFT, c1PtX); + CHECK_AND_FILL_MFT_COV(c1PtPhiMFT, c1PtPhi); + CHECK_AND_FILL_MFT_COV(c1PtTglMFT, c1PtTgl); + CHECK_AND_FILL_MFT_COV(c1Pt21Pt2MFT, c1Pt21Pt2); + CHECK_AND_FILL_MUON_COV(cXXMCH, cXX); + CHECK_AND_FILL_MUON_COV(cXYMCH, cXY); + CHECK_AND_FILL_MUON_COV(cYYMCH, cYY); + CHECK_AND_FILL_MUON_COV(cPhiYMCH, cPhiY); + CHECK_AND_FILL_MUON_COV(cPhiXMCH, cPhiX); + CHECK_AND_FILL_MUON_COV(cPhiPhiMCH, cPhiPhi); + CHECK_AND_FILL_MUON_COV(cTglYMCH, cTglY); + CHECK_AND_FILL_MUON_COV(cTglXMCH, cTglX); + CHECK_AND_FILL_MUON_COV(cTglPhiMCH, cTglPhi); + CHECK_AND_FILL_MUON_COV(cTglTglMCH, cTglTgl); + CHECK_AND_FILL_MUON_COV(c1PtYMCH, c1PtY); + CHECK_AND_FILL_MUON_COV(c1PtXMCH, c1PtX); + CHECK_AND_FILL_MUON_COV(c1PtPhiMCH, c1PtPhi); + CHECK_AND_FILL_MUON_COV(c1PtTglMCH, c1PtTgl); + CHECK_AND_FILL_MUON_COV(c1Pt21Pt2MCH, c1Pt21Pt2); + CHECK_AND_FILL_MFTMUON_COLLISION(posX); + CHECK_AND_FILL_MFTMUON_COLLISION(posY); + CHECK_AND_FILL_MFTMUON_COLLISION(posZ); + CHECK_AND_FILL_MFTMUON_COLLISION(numContrib); + CHECK_AND_FILL_MFTMUON_COLLISION(trackOccupancyInTimeRange); + CHECK_AND_FILL_MFTMUON_COLLISION(ft0cOccupancyInTimeRange); + CHECK_AND_FILL_MFTMUON_COLLISION(multFT0A); + CHECK_AND_FILL_MFTMUON_COLLISION(multFT0C); + CHECK_AND_FILL_MFTMUON_COLLISION(multNTracksPV); + CHECK_AND_FILL_MFTMUON_COLLISION(multNTracksPVeta1); + CHECK_AND_FILL_MFTMUON_COLLISION(multNTracksPVetaHalf); + CHECK_AND_FILL_MFTMUON_COLLISION(isInelGt0); + CHECK_AND_FILL_MFTMUON_COLLISION(isInelGt1); + CHECK_AND_FILL_MFTMUON_COLLISION(multFT0M); + CHECK_AND_FILL_MFTMUON_COLLISION(centFT0M); + CHECK_AND_FILL_MFTMUON_COLLISION(centFT0A); + CHECK_AND_FILL_MFTMUON_COLLISION(centFT0C); + CHECK_AND_FILL_MUON_TRACK(chi2MCHMFT, chi2MatchMCHMFT); + } + return inputFeature; + } + + template + float returnFeatureGlob(uint8_t idx, T1 const& muonglob, T2 const& muon, T3 const& mft, U const& collision) + { + float inputFeature = 0.; + switch (idx) { + CHECK_AND_FILL_MFT_TRACK(xMFT, getX); + CHECK_AND_FILL_MFT_TRACK(yMFT, getY); + CHECK_AND_FILL_MFT_TRACK(qOverptMFT, getInvQPt); + CHECK_AND_FILL_MFT_TRACK(tglMFT, getTanl); + CHECK_AND_FILL_MFT_TRACK(phiMFT, getPhi); + CHECK_AND_FILL_MFT_TRACK(chi2MFT, getTrackChi2); + CHECK_AND_FILL_MUON_TRACK(xMCH, getX); + CHECK_AND_FILL_MUON_TRACK(yMCH, getY); + CHECK_AND_FILL_MUON_TRACK(qOverptMCH, getInvQPt); + CHECK_AND_FILL_MUON_TRACK(tglMCH, getTanl); + CHECK_AND_FILL_MUON_TRACK(phiMCH, getPhi); + CHECK_AND_FILL_MUON_TRACK(chi2MCH, getTrackChi2); + CHECK_AND_FILL_MUONGLOB_TRACK(chi2MCHMFT, chi2MatchMCHMFT); + CHECK_AND_FILL_MUONGLOB_TRACK(chi2GlobMUON, chi2); + CHECK_AND_FILL_MUONGLOB_TRACK(Rabs, rAtAbsorberEnd); + // Below are dummy files to remove warning of unused parameters + CHECK_AND_FILL_MFTMUON_COLLISION(posZ); + } + return inputFeature; + } + + template + float returnFeatureTest(uint8_t idx, T1 const& muon) + { + float inputFeature = 0.; + switch (idx) { + CHECK_AND_FILL_MUON_TRACK(chi2MCHMFT, chi2MatchMCHMFT); + } + return inputFeature; + } + + /// Method to get the input features vector needed for ML inference + /// \param track is the single track, \param collision is the collision + /// \return inputFeatures vector + template + std::vector getInputFeatures(T1 const& muon, T2 const& mft, C1 const& muoncov, C2 const& mftcov, U const& collision) + { + std::vector inputFeatures; + for (const auto& idx : MlResponse::mCachedIndices) { + float inputFeature = returnFeature(idx, muon, mft, muoncov, mftcov, collision); + inputFeatures.emplace_back(inputFeature); + } + return inputFeatures; + } + + template + std::vector getInputFeaturesTest(T1 const& muon) + { + std::vector inputFeatures; + for (const auto& idx : MlResponse::mCachedIndices) { + float inputFeature = returnFeatureTest(idx, muon); + inputFeatures.emplace_back(inputFeature); + } + return inputFeatures; + } + + template + std::vector getInputFeaturesGlob(T1 const& muonglob, T2 const& muon, T3 const& mft, U const& collision) + { + std::vector inputFeatures; + for (const auto& idx : MlResponse::mCachedIndices) { + float inputFeature = returnFeatureGlob(idx, muonglob, muon, mft, 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(T1 const& muon, T2 const& mft, C1 const& muoncov, C2 const& mftcov, U const& collision) + { + return returnFeature(mCachedIndexBinning, muon, mft, muoncov, mftcov, 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() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_MFTMUON_MATCH(zMatching), + FILL_MAP_MFTMUON_MATCH(xMFT), + FILL_MAP_MFTMUON_MATCH(yMFT), + FILL_MAP_MFTMUON_MATCH(qOverptMFT), + FILL_MAP_MFTMUON_MATCH(tglMFT), + FILL_MAP_MFTMUON_MATCH(phiMFT), + FILL_MAP_MFTMUON_MATCH(dcaXY), + FILL_MAP_MFTMUON_MATCH(dcaZ), + FILL_MAP_MFTMUON_MATCH(chi2MFT), + FILL_MAP_MFTMUON_MATCH(nClustersMFT), + FILL_MAP_MFTMUON_MATCH(xMCH), + FILL_MAP_MFTMUON_MATCH(yMCH), + FILL_MAP_MFTMUON_MATCH(qOverptMCH), + FILL_MAP_MFTMUON_MATCH(tglMCH), + FILL_MAP_MFTMUON_MATCH(phiMCH), + FILL_MAP_MFTMUON_MATCH(nClustersMCH), + FILL_MAP_MFTMUON_MATCH(chi2MCH), + FILL_MAP_MFTMUON_MATCH(pdca), + FILL_MAP_MFTMUON_MATCH(Rabs), + FILL_MAP_MFTMUON_MATCH(cXXMFT), + FILL_MAP_MFTMUON_MATCH(cXYMFT), + FILL_MAP_MFTMUON_MATCH(cYYMFT), + FILL_MAP_MFTMUON_MATCH(cPhiYMFT), + FILL_MAP_MFTMUON_MATCH(cPhiXMFT), + FILL_MAP_MFTMUON_MATCH(cPhiPhiMFT), + FILL_MAP_MFTMUON_MATCH(cTglYMFT), + FILL_MAP_MFTMUON_MATCH(cTglXMFT), + FILL_MAP_MFTMUON_MATCH(cTglPhiMFT), + FILL_MAP_MFTMUON_MATCH(cTglTglMFT), + FILL_MAP_MFTMUON_MATCH(c1PtYMFT), + FILL_MAP_MFTMUON_MATCH(c1PtXMFT), + FILL_MAP_MFTMUON_MATCH(c1PtPhiMFT), + FILL_MAP_MFTMUON_MATCH(c1PtTglMFT), + FILL_MAP_MFTMUON_MATCH(c1Pt21Pt2MFT), + FILL_MAP_MFTMUON_MATCH(cXXMCH), + FILL_MAP_MFTMUON_MATCH(cXYMCH), + FILL_MAP_MFTMUON_MATCH(cYYMCH), + FILL_MAP_MFTMUON_MATCH(cPhiYMCH), + FILL_MAP_MFTMUON_MATCH(cPhiXMCH), + FILL_MAP_MFTMUON_MATCH(cPhiPhiMCH), + FILL_MAP_MFTMUON_MATCH(cTglYMCH), + FILL_MAP_MFTMUON_MATCH(cTglXMCH), + FILL_MAP_MFTMUON_MATCH(cTglPhiMCH), + FILL_MAP_MFTMUON_MATCH(cTglTglMCH), + FILL_MAP_MFTMUON_MATCH(c1PtYMCH), + FILL_MAP_MFTMUON_MATCH(c1PtXMCH), + FILL_MAP_MFTMUON_MATCH(c1PtPhiMCH), + FILL_MAP_MFTMUON_MATCH(c1PtTglMCH), + FILL_MAP_MFTMUON_MATCH(c1Pt21Pt2MCH), + FILL_MAP_MFTMUON_MATCH(chi2MCHMFT), + FILL_MAP_MFTMUON_MATCH(chi2GlobMUON)}; + } + + uint8_t mCachedIndexBinning; // index correspondance between configurable and available input features +}; + +} // namespace o2::analysis + +#undef FILL_MAP_MFTMUON_MAP +#undef CHECK_AND_FILL_MUON_TRACK +#undef CHECK_AND_FILL_MFT_TRACK +#undef CHECK_AND_FILL_MUON_COV +#undef CHECK_AND_FILL_MFT_COV +#undef CHECK_AND_FILL_MFTMUON_DIFF +#undef CHECK_AND_FILL_MFTMUON_COLLISION + +#endif // PWGDQ_CORE_MUONMATCHINGMLRESPONSE_H_ diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index 6c76c2747d8..e7f84bda876 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -8,10 +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. -#include #include "PWGDQ/Core/VarManager.h" + #include "Tools/KFparticle/KFUtilities.h" +#include +#include +#include +#include + using std::cout; using std::endl; using namespace o2::constants::physics; @@ -20,27 +25,31 @@ 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; +float VarManager::fgzMatching = -77.5; float VarManager::fgValues[VarManager::kNVars] = {0.0f}; -std::map VarManager::fgRunMap; -TString VarManager::fgRunStr = ""; -std::vector VarManager::fgRunList = {0}; -float VarManager::fgCenterOfMassEnergy = 13600; // GeV -float VarManager::fgMassofCollidingParticle = 9.382720; // GeV -float VarManager::fgTPCInterSectorBoundary = 1.0; // cm +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; +ROOT::Math::PxPyPzEVector VarManager::fgBeamA(0, 0, 6799.99, 6800); // GeV, beam from A-side 4-momentum vector +ROOT::Math::PxPyPzEVector VarManager::fgBeamC(0, 0, -6799.99, 6800); // GeV, beam from C-side 4-momentum vector o2::vertexing::DCAFitterN<2> VarManager::fgFitterTwoProngBarrel; o2::vertexing::DCAFitterN<3> VarManager::fgFitterThreeProngBarrel; +o2::vertexing::DCAFitterN<4> VarManager::fgFitterFourProngBarrel; o2::vertexing::FwdDCAFitterN<2> VarManager::fgFitterTwoProngFwd; o2::vertexing::FwdDCAFitterN<3> VarManager::fgFitterThreeProngFwd; o2::globaltracking::MatchGlobalFwd VarManager::mMatching; std::map VarManager::fgCalibs; bool VarManager::fgRunTPCPostCalibration[4] = {false, false, false, false}; +int VarManager::fgCalibrationType = 0; // 0 - no calibration, 1 - calibration vs (TPCncls,pIN,eta) typically for pp, 2 - calibration vs (eta,nPV,nLong,tLong) typically for PbPb +bool VarManager::fgUseInterpolatedCalibration = true; // use interpolated calibration histograms (default: true) //__________________________________________________________________ VarManager::VarManager() : TObject() @@ -104,97 +113,91 @@ void VarManager::ResetValues(int startValue, int endValue, float* values) } } -//__________________________________________________________________ -void VarManager::SetRunNumbers(int n, int* runs) -{ - // - // maps the list of runs such that one can plot the list of runs nicely in a histogram axis - // - for (int i = 0; i < n; ++i) { - fgRunMap[runs[i]] = i + 1; - fgRunStr += Form("%d;", runs[i]); - } -} - -//__________________________________________________________________ -void VarManager::SetRunNumbers(std::vector runs) -{ - // - // maps the list of runs such that one can plot the list of runs nicely in a histogram axis - // - int i = 0; - for (auto run = runs.begin(); run != runs.end(); run++, i++) { - fgRunMap[*run] = i + 1; - fgRunStr += Form("%d;", *run); - } - fgRunList = runs; -} - -//__________________________________________________________________ -void VarManager::SetDummyRunlist(int InitRunnumber) -{ - // - // runlist for the different periods - fgRunList.clear(); - fgRunList.push_back(InitRunnumber); - fgRunList.push_back(InitRunnumber + 100); -} - -//__________________________________________________________________ -int VarManager::GetDummyFirst() -{ - // - // Get the fist index of the vector of run numbers - // - return fgRunList[0]; -} -//__________________________________________________________________ -int VarManager::GetDummyLast() -{ - // - // Get the last index of the vector of run numbers - // - return fgRunList[fgRunList.size() - 1]; -} -//_________________________________________________________________ -float VarManager::GetRunIndex(double Runnumber) -{ - // - // Get the index of RunNumber in it's runlist - // - int runNumber = static_cast(Runnumber); - auto runIndex = std::find(fgRunList.begin(), fgRunList.end(), runNumber); - float index = std::distance(fgRunList.begin(), runIndex); - return index; -} //__________________________________________________________________ void VarManager::SetCollisionSystem(TString system, float energy) { // // Set the collision system and the center of mass energy // - fgCenterOfMassEnergy = energy; - - if (system.Contains("PbPb")) { - fgMassofCollidingParticle = MassProton * 208; - } - if (system.Contains("pp")) { - fgMassofCollidingParticle = MassProton; + int NumberOfNucleonsA = 1; // default value for pp collisions + int NumberOfNucleonsC = 1; // default value for pp collisions + int NumberOfProtonsA = 1; // default value for pp collisions + int NumberOfProtonsC = 1; // default value for pp collisions + if (system.EqualTo("PbPb")) { + NumberOfNucleonsA = 208; + NumberOfNucleonsC = 208; + NumberOfProtonsA = 82; // Pb has 82 protons + NumberOfProtonsC = 82; // Pb has 82 protons + } else if (system.EqualTo("pp")) { + NumberOfNucleonsA = 1; + NumberOfNucleonsC = 1; + NumberOfProtonsA = 1; // proton has 1 proton + NumberOfProtonsC = 1; // proton has 1 proton + } else if (system.EqualTo("XeXe")) { + NumberOfNucleonsA = 129; + NumberOfNucleonsC = 129; + NumberOfProtonsA = 54; // Xe has 54 protons + NumberOfProtonsC = 54; // Xe has 54 protons + } else if (system.EqualTo("pPb")) { + NumberOfNucleonsA = 1; + NumberOfNucleonsC = 208; + NumberOfProtonsA = 1; // proton has 1 proton + NumberOfProtonsC = 82; // Pb has 82 protons + } else if (system.EqualTo("Pbp")) { + NumberOfNucleonsA = 208; + NumberOfNucleonsC = 1; + NumberOfProtonsA = 82; // Pb has 82 protons + NumberOfProtonsC = 1; // proton has 1 proton + } else if (system.EqualTo("OO")) { + NumberOfNucleonsA = 16; + NumberOfNucleonsC = 16; + NumberOfProtonsA = 8; // O has 8 protons + NumberOfProtonsC = 8; // O has 8 protons + } else if (system.EqualTo("pO")) { + NumberOfNucleonsA = 1; + NumberOfNucleonsC = 16; + NumberOfProtonsA = 1; // proton has 1 proton + NumberOfProtonsC = 8; // O has 8 protons + } else if (system.EqualTo("NeNe")) { + NumberOfNucleonsA = 20; + NumberOfNucleonsC = 20; + NumberOfProtonsA = 10; // Ne has 5 protons + NumberOfProtonsC = 10; // Ne has 5 protons } // TO Do: add more systems + + // set the beam 4-momentum vectors + float beamAEnergy = energy / 2.0 * sqrt(NumberOfProtonsA * NumberOfProtonsC / NumberOfProtonsC / NumberOfProtonsA); // GeV + float beamCEnergy = energy / 2.0 * sqrt(NumberOfProtonsC * NumberOfProtonsA / NumberOfProtonsA / NumberOfProtonsC); // GeV + float beamAMomentum = std::sqrt(beamAEnergy * beamAEnergy - NumberOfNucleonsA * NumberOfNucleonsA * MassProton * MassProton); + float beamCMomentum = std::sqrt(beamCEnergy * beamCEnergy - NumberOfNucleonsC * NumberOfNucleonsC * MassProton * MassProton); + fgBeamA.SetPxPyPzE(0, 0, beamAMomentum, beamAEnergy); + fgBeamC.SetPxPyPzE(0, 0, -beamCMomentum, beamCEnergy); } //__________________________________________________________________ -void VarManager::FillEventDerived(float* values) +void VarManager::SetCollisionSystem(o2::parameters::GRPLHCIFData* grplhcif) { // - // Fill event-wise derived quantities (these are all quantities which can be computed just based on the values already filled in the FillEvent() function) - // - if (fgUsedVars[kRunId]) { - values[kRunId] = (fgRunMap.size() > 0 ? fgRunMap[static_cast(values[kRunNo])] : 0); - } + // Set the collision system and the center of mass energy from the GRP information + double beamAEnergy = grplhcif->getBeamEnergyPerNucleonInGeV(o2::constants::lhc::BeamDirection::BeamA); + double beamCEnergy = grplhcif->getBeamEnergyPerNucleonInGeV(o2::constants::lhc::BeamDirection::BeamC); + double beamANucleons = grplhcif->getBeamA(o2::constants::lhc::BeamDirection::BeamA); + double beamCNucleons = grplhcif->getBeamA(o2::constants::lhc::BeamDirection::BeamC); + double beamAMomentum = std::sqrt(beamAEnergy * beamAEnergy - beamANucleons * beamANucleons * MassProton * MassProton); + double beamCMomentum = std::sqrt(beamCEnergy * beamCEnergy - beamCNucleons * beamCNucleons * MassProton * MassProton); + fgBeamA.SetPxPyPzE(0, 0, beamAMomentum, beamAEnergy); + fgBeamC.SetPxPyPzE(0, 0, -beamCMomentum, beamCEnergy); } +//__________________________________________________________________ +// void VarManager::FillEventDerived(float* values) +// { +// // +// // Fill event-wise derived quantities (these are all quantities which can be computed just based on the values already filled in the FillEvent() function) +// // +// } + //__________________________________________________________________ void VarManager::FillTrackDerived(float* values) { @@ -211,6 +214,148 @@ float VarManager::calculateCosPA(KFParticle kfp, KFParticle PV) { return cpaFromKF(kfp, PV); } + +//__________________________________________________________________ +double VarManager::ComputePIDcalibration(int species, double nSigmaValue) +{ + // species: 0 - electron, 1 - pion, 2 - kaon, 3 - proton + // Depending on the PID calibration type, we use different types of calibration histograms + + if (fgCalibrationType == 1) { + // get the calibration histograms + CalibObjects calibMean, calibSigma; + switch (species) { + case 0: + calibMean = kTPCElectronMean; + calibSigma = kTPCElectronSigma; + break; + case 1: + calibMean = kTPCPionMean; + calibSigma = kTPCPionSigma; + break; + case 2: + calibMean = kTPCKaonMean; + calibSigma = kTPCKaonSigma; + break; + case 3: + calibMean = kTPCProtonMean; + calibSigma = kTPCProtonSigma; + break; + default: + LOG(fatal) << "Invalid species for PID calibration: " << species; + return -999.0; // Return zero if species is invalid + } + + TH3F* calibMeanHist = reinterpret_cast(fgCalibs[calibMean]); + TH3F* calibSigmaHist = reinterpret_cast(fgCalibs[calibSigma]); + if (!calibMeanHist || !calibSigmaHist) { + LOG(fatal) << "Calibration histograms not found for species: " << species; + return -999.0; // Return zero if histograms are not found + } + + // Get the bin indices for the calibration histograms + int binTPCncls = calibMeanHist->GetXaxis()->FindBin(fgValues[kTPCncls]); + binTPCncls = (binTPCncls == 0 ? 1 : binTPCncls); + binTPCncls = (binTPCncls > calibMeanHist->GetXaxis()->GetNbins() ? calibMeanHist->GetXaxis()->GetNbins() : binTPCncls); + int binPin = calibMeanHist->GetYaxis()->FindBin(fgValues[kPin]); + binPin = (binPin == 0 ? 1 : binPin); + binPin = (binPin > calibMeanHist->GetYaxis()->GetNbins() ? calibMeanHist->GetYaxis()->GetNbins() : binPin); + int binEta = calibMeanHist->GetZaxis()->FindBin(fgValues[kEta]); + binEta = (binEta == 0 ? 1 : binEta); + binEta = (binEta > calibMeanHist->GetZaxis()->GetNbins() ? calibMeanHist->GetZaxis()->GetNbins() : binEta); + + double mean = calibMeanHist->GetBinContent(binTPCncls, binPin, binEta); + double sigma = calibSigmaHist->GetBinContent(binTPCncls, binPin, binEta); + return (nSigmaValue - mean) / sigma; // Return the calibrated nSigma value + } else if (fgCalibrationType == 2) { + // get the calibration histograms + CalibObjects calibMean, calibSigma, calibStatus; + switch (species) { + case 0: + calibMean = kTPCElectronMean; + calibSigma = kTPCElectronSigma; + calibStatus = kTPCElectronStatus; + break; + case 1: + calibMean = kTPCPionMean; + calibSigma = kTPCPionSigma; + calibStatus = kTPCPionStatus; + break; + case 2: + calibMean = kTPCKaonMean; + calibSigma = kTPCKaonSigma; + calibStatus = kTPCKaonStatus; + break; + case 3: + calibMean = kTPCProtonMean; + calibSigma = kTPCProtonSigma; + calibStatus = kTPCProtonStatus; + break; + default: + LOG(fatal) << "Invalid species for PID calibration: " << species; + return -999.0; // Return zero if species is invalid + } + + THnF* calibMeanHist = reinterpret_cast(fgCalibs[calibMean]); + THnF* calibSigmaHist = reinterpret_cast(fgCalibs[calibSigma]); + THnF* calibStatusHist = reinterpret_cast(fgCalibs[calibStatus]); + if (!calibMeanHist || !calibSigmaHist || !calibStatusHist) { + LOG(fatal) << "Calibration histograms not found for species: " << species; + return -999.0; // Return zero if histograms are not found + } + + // Get the bin indices for the calibration histograms + int binEta = calibMeanHist->GetAxis(0)->FindBin(fgValues[kEta]); + binEta = (binEta == 0 ? 1 : binEta); + binEta = (binEta > calibMeanHist->GetAxis(0)->GetNbins() ? calibMeanHist->GetAxis(0)->GetNbins() : binEta); + int binNpv = calibMeanHist->GetAxis(1)->FindBin(fgValues[kVtxNcontribReal]); + binNpv = (binNpv == 0 ? 1 : binNpv); + binNpv = (binNpv > calibMeanHist->GetAxis(1)->GetNbins() ? calibMeanHist->GetAxis(1)->GetNbins() : binNpv); + int binNlong = calibMeanHist->GetAxis(2)->FindBin(fgValues[kNTPCcontribLongA]); + binNlong = (binNlong == 0 ? 1 : binNlong); + binNlong = (binNlong > calibMeanHist->GetAxis(2)->GetNbins() ? calibMeanHist->GetAxis(2)->GetNbins() : binNlong); + int binTlong = calibMeanHist->GetAxis(3)->FindBin(fgValues[kNTPCmedianTimeLongA]); + binTlong = (binTlong == 0 ? 1 : binTlong); + binTlong = (binTlong > calibMeanHist->GetAxis(3)->GetNbins() ? calibMeanHist->GetAxis(3)->GetNbins() : binTlong); + + int bin[4] = {binEta, binNpv, binNlong, binTlong}; + int status = static_cast(calibStatusHist->GetBinContent(bin)); + double mean = calibMeanHist->GetBinContent(bin); + double sigma = calibSigmaHist->GetBinContent(bin); + switch (status) { + case 0: + // good calibration, return the calibrated nSigma value + return (nSigmaValue - mean) / sigma; + break; + case 1: + // calibration not valid, return the original nSigma value + return nSigmaValue; + break; + case 2: // calibration constant has poor stat uncertainty, consider the user option for what to do + case 3: + // calibration constants have been interpolated + if (fgUseInterpolatedCalibration) { + return (nSigmaValue - mean) / sigma; + } else { + // return the original nSigma value + return nSigmaValue; + } + break; + case 4: + // calibration constants interpolation failed, return the original nSigma value + return nSigmaValue; + break; + default: + return nSigmaValue; // unknown status, return the original nSigma value + break; + } + } else { + // unknown calibration type, return the original nSigma value + LOG(fatal) << "Unknown calibration type: " << fgCalibrationType; + return nSigmaValue; // Return the original nSigma value + } +} + //__________________________________________________________________ void VarManager::SetDefaultVarNames() { @@ -224,10 +369,12 @@ void VarManager::SetDefaultVarNames() fgVariableNames[kRunNo] = "Run number"; fgVariableUnits[kRunNo] = ""; - fgVariableNames[kRunId] = "Run number"; - 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 "; @@ -236,6 +383,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."; @@ -258,6 +409,10 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kCentVZERO] = "%"; fgVariableNames[kCentFT0C] = "Centrality FT0C"; fgVariableUnits[kCentFT0C] = "%"; + fgVariableNames[kCentFT0A] = "Centrality FT0A"; + fgVariableUnits[kCentFT0A] = "%"; + fgVariableNames[kCentFT0M] = "Centrality FT0M"; + fgVariableUnits[kCentFT0M] = "%"; fgVariableNames[kMultTPC] = "Multiplicity TPC"; fgVariableUnits[kMultTPC] = ""; fgVariableNames[kMultFV0A] = "Multiplicity FV0A"; @@ -280,22 +435,34 @@ 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"; fgVariableNames[kMCEventTime] = "MC event time"; fgVariableNames[kMCEventWeight] = "MC event weight"; fgVariableNames[kMCEventImpParam] = "MC impact parameter"; + fgVariableNames[kMCEventCentrFT0C] = "MC Centrality FT0C"; + fgVariableNames[kMultMCNParticlesEta05] = "MC Multiplicity Central Barrel for |eta| < 0.5"; + fgVariableNames[kMultMCNParticlesEta08] = "MC Multiplicity Central Barrel for |eta| < 0.8"; + fgVariableNames[kMultMCNParticlesEta10] = "MC Multiplicity Central Barrel for |eta| < 1.0"; fgVariableUnits[kMCEventGeneratorId] = ""; + fgVariableUnits[kMCEventSubGeneratorId] = ""; fgVariableUnits[kMCVtxX] = "cm"; fgVariableUnits[kMCVtxY] = "cm"; fgVariableUnits[kMCVtxZ] = "cm"; fgVariableUnits[kMCEventTime] = ""; // TODO: add proper unit fgVariableUnits[kMCEventWeight] = ""; fgVariableUnits[kMCEventImpParam] = "b"; + fgVariableUnits[kMCEventCentrFT0C] = "%"; + fgVariableUnits[kMultMCNParticlesEta05] = "Multiplicity_eta05"; + fgVariableUnits[kMultMCNParticlesEta08] = "Multiplicity_eta08"; + fgVariableUnits[kMultMCNParticlesEta10] = "Multiplicity_eta10"; fgVariableNames[kTwoEvPosZ1] = "vtx-z_{1}"; fgVariableUnits[kTwoEvPosZ1] = "cm"; fgVariableNames[kTwoEvPosZ2] = "vtx-z_{2}"; @@ -346,8 +513,16 @@ void VarManager::SetDefaultVarNames() 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"; @@ -364,8 +539,36 @@ void VarManager::SetDefaultVarNames() 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"; @@ -388,8 +591,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"; @@ -423,6 +632,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"; @@ -453,6 +664,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}"; @@ -523,6 +736,22 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kMuonTimeRes] = "ns"; fgVariableNames[kMCPdgCode] = "MC PDG code"; fgVariableUnits[kMCPdgCode] = ""; + fgVariableNames[kMCCosTheta] = "Cos#theta"; + fgVariableUnits[kMCCosTheta] = ""; + fgVariableNames[kMCHadronPdgCode] = "HadronPdgCode"; + fgVariableUnits[kMCHadronPdgCode] = ""; + fgVariableNames[kMCCosChi] = "Cos#chi"; + fgVariableUnits[kMCCosChi] = ""; + fgVariableNames[kMCJpsiPt] = "Jpsi p_{T}"; + fgVariableUnits[kMCJpsiPt] = "GeV/c"; + fgVariableNames[kMCHadronPt] = "Hadron p_{T}"; + fgVariableUnits[kMCHadronPt] = "GeV/c"; + fgVariableNames[kMCHadronEta] = "Hadron #eta"; + fgVariableUnits[kMCHadronEta] = ""; + fgVariableNames[kMCdeltaphi] = "#Delta#phi"; + fgVariableUnits[kMCdeltaphi] = ""; + fgVariableNames[kMCdeltaeta] = "#Delta#eta"; + fgVariableUnits[kMCdeltaeta] = ""; fgVariableNames[kMCParticleWeight] = "MC particle weight"; fgVariableUnits[kMCParticleWeight] = ""; fgVariableNames[kMCPx] = "MC px"; @@ -531,7 +760,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"; @@ -541,22 +770,54 @@ 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"; fgVariableUnits[kMCVy] = "cm"; // TODO: check the unit fgVariableNames[kMCVz] = "MC vz"; fgVariableUnits[kMCVz] = "cm"; // TODO: check the unit + fgVariableNames[kMCCosThetaHE] = "MC cos(#theta_{HE})"; + fgVariableUnits[kMCCosThetaHE] = ""; + fgVariableNames[kMCPhiHE] = "MC #varphi_{HE}"; + fgVariableUnits[kMCPhiHE] = "rad"; + fgVariableNames[kMCPhiTildeHE] = "MC #tilde{#varphi}_{HE}"; + fgVariableUnits[kMCPhiTildeHE] = "rad"; + fgVariableNames[kMCCosThetaCS] = "MC cos(#theta_{CS})"; + fgVariableUnits[kMCCosThetaCS] = ""; + fgVariableNames[kMCPhiCS] = "MC #varphi_{CS}"; + fgVariableUnits[kMCPhiCS] = "rad"; + fgVariableNames[kMCPhiTildeCS] = "MC #tilde{#varphi}_{CS}"; + fgVariableUnits[kMCPhiTildeCS] = "rad"; + fgVariableNames[kMCCosThetaPP] = "MC cos(#theta_{PP})"; + fgVariableUnits[kMCCosThetaPP] = ""; + fgVariableNames[kMCPhiPP] = "MC #varphi_{PP}"; + fgVariableUnits[kMCPhiPP] = "rad"; + fgVariableNames[kMCPhiTildePP] = "MC #tilde{#varphi}_{PP}"; + fgVariableUnits[kMCPhiTildePP] = "rad"; + fgVariableNames[kMCCosThetaRM] = "MC cos(#theta_{RM})"; + fgVariableUnits[kMCCosThetaRM] = ""; fgVariableNames[kCandidateId] = ""; fgVariableUnits[kCandidateId] = ""; fgVariableNames[kPairType] = "Pair type"; fgVariableUnits[kPairType] = ""; fgVariableNames[kVertexingLxy] = "Pair Lxy"; fgVariableUnits[kVertexingLxy] = "cm"; + fgVariableNames[kMCVertexingLxy] = "MC Lxy"; + fgVariableUnits[kMCVertexingLxy] = "cm"; fgVariableNames[kVertexingLz] = "Pair Lz"; fgVariableUnits[kVertexingLz] = "cm"; + fgVariableNames[kMCVertexingLz] = "MC Lz"; + fgVariableUnits[kMCVertexingLz] = "cm"; fgVariableNames[kVertexingLxyz] = "Pair Lxyz"; fgVariableUnits[kVertexingLxyz] = "cm"; + fgVariableNames[kMCVertexingLxyz] = "MC Lxyz"; + fgVariableUnits[kMCVertexingLxyz] = "cm"; + fgVariableNames[kMCLxyExpected] = "MC Expected Lxy"; + fgVariableUnits[kMCLxyExpected] = "cm"; + fgVariableNames[kMCLxyzExpected] = "MC Expected Lxyz"; + fgVariableUnits[kMCLxyzExpected] = "cm"; fgVariableNames[kVertexingLxyErr] = "Pair Lxy err."; fgVariableUnits[kVertexingLxyErr] = "cm"; fgVariableNames[kVertexingLzErr] = "Pair Lz err."; @@ -567,6 +828,10 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kVertexingTauz] = "ns"; fgVariableNames[kVertexingTauxy] = "Pair pseudo-proper Tauxy"; fgVariableUnits[kVertexingTauxy] = "ns"; + fgVariableNames[kMCVertexingTauz] = "MC pseudo-proper Tauz"; + fgVariableUnits[kMCVertexingTauz] = "ns"; + fgVariableNames[kMCVertexingTauxy] = "MC pseudo-proper Tauxy"; + fgVariableUnits[kMCVertexingTauxy] = "ns"; fgVariableNames[kVertexingTauzErr] = "Pair pseudo-proper Tauz err."; fgVariableUnits[kVertexingTauzErr] = "ns"; fgVariableNames[kVertexingLxyProjected] = "Pair Lxy"; @@ -579,8 +844,26 @@ 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[kMCVertexingLxyProjected] = "MC Lxy_{proj}"; + fgVariableUnits[kMCVertexingLxyProjected] = "cm"; + fgVariableNames[kMCVertexingLzProjected] = "MC Lz_{proj}"; + fgVariableUnits[kMCVertexingLzProjected] = "cm"; + fgVariableNames[kMCVertexingLxyzProjected] = "MC Lxyz_{proj}"; + fgVariableUnits[kMCVertexingLxyzProjected] = "cm"; + fgVariableNames[kMCVertexingTauzProjected] = "MC Tauz_{proj}"; + fgVariableUnits[kMCVertexingTauzProjected] = "ns"; + fgVariableNames[kMCVertexingTauxyProjected] = "MC Tauxy_{proj}"; + fgVariableUnits[kMCVertexingTauxyProjected] = "ns"; + fgVariableNames[kMCVertexingTauxyzProjected] = "MC Tauxyz_{proj}"; + fgVariableUnits[kMCVertexingTauxyzProjected] = "ns"; + fgVariableNames[kCosPointingAngle] = "cos(#theta_{pointing})"; + fgVariableUnits[kCosPointingAngle] = ""; + fgVariableNames[kMCCosPointingAngle] = "MC cos(#theta_{pointing})"; + fgVariableUnits[kMCCosPointingAngle] = ""; fgVariableNames[kVertexingPz] = "Pz Pair"; fgVariableUnits[kVertexingPz] = "GeV/c"; fgVariableNames[kVertexingSV] = "Secondary Vertexing z"; @@ -739,18 +1022,46 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kS31A] = ""; fgVariableNames[kM11REF] = "M_{11}^{REF} "; fgVariableUnits[kM11REF] = ""; + fgVariableNames[kM11REFetagap] = "M_{11}^{REF}-etagap "; + fgVariableUnits[kM11REFetagap] = ""; fgVariableNames[kM01POI] = "M^{'}_{01}^{POI} "; fgVariableUnits[kM01POI] = ""; fgVariableNames[kM1111REF] = "M_{1111}^{REF} "; fgVariableUnits[kM1111REF] = ""; + 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[kCORR2REFbydimuons] = "<2> only for events with dimuons"; + fgVariableUnits[kCORR2REFbydimuons] = ""; + fgVariableNames[kCORR2REFetagap] = "<2-etagap> "; + fgVariableUnits[kCORR2REFetagap] = ""; fgVariableNames[kCORR2POI] = "<2'> "; fgVariableUnits[kCORR2POI] = ""; fgVariableNames[kCORR4REF] = "<4> "; fgVariableUnits[kCORR4REF] = ""; + fgVariableNames[kCORR4REFbydimuons] = "<4> only for events with dimuons"; + fgVariableUnits[kCORR4REFbydimuons] = ""; fgVariableNames[kCORR4POI] = "<4'> "; fgVariableUnits[kCORR4POI] = ""; fgVariableNames[kM11REFoverMp] = "M_{11}^{REF}/M_{p} "; @@ -765,6 +1076,68 @@ void VarManager::SetDefaultVarNames() 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}) "; @@ -819,26 +1192,64 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kPairPt] = "GeV/c"; fgVariableNames[kPairEta] = "#eta"; fgVariableUnits[kPairEta] = ""; + fgVariableNames[kPairRap] = "#rap"; + fgVariableUnits[kPairRap] = ""; fgVariableNames[kPairPhi] = "#varphi"; fgVariableUnits[kPairPhi] = "rad."; fgVariableNames[kPairPhiv] = "#varphi_{V}"; fgVariableUnits[kPairPhiv] = "rad."; + fgVariableNames[kDileptonHadronKstar] = "Dilepton-hadron k^{*}"; + fgVariableUnits[kDileptonHadronKstar] = "GeV/c^{2}"; fgVariableNames[kDeltaEta] = "#Delta#eta"; fgVariableUnits[kDeltaEta] = ""; fgVariableNames[kDeltaPhi] = "#Delta#phi"; fgVariableUnits[kDeltaPhi] = "rad."; fgVariableNames[kDeltaPhiSym] = "#Delta#phi"; fgVariableUnits[kDeltaPhiSym] = "rad."; + fgVariableNames[kCosChi] = "Cos#chi"; + fgVariableUnits[kCosChi] = ""; + fgVariableNames[kCosTheta] = "Cos#theta"; + fgVariableUnits[kCosTheta] = ""; + fgVariableNames[kPtDau] = "hadron P_{T}"; + fgVariableUnits[kPtDau] = "GeV/c"; + fgVariableNames[kEtaDau] = "hadron #eta"; + fgVariableUnits[kEtaDau] = ""; + fgVariableNames[kPhiDau] = "hadron #phi"; + fgVariableUnits[kPhiDau] = ""; fgVariableNames[kCosThetaHE] = "cos#it{#theta}"; fgVariableUnits[kCosThetaHE] = ""; fgVariableNames[kPhiHE] = "#varphi_{HE}"; fgVariableUnits[kPhiHE] = "rad."; + fgVariableNames[kPhiTildeHE] = "#tilde{#varphi}_{HE}"; + fgVariableUnits[kPhiTildeHE] = "rad."; fgVariableNames[kCosThetaCS] = "cos#it{#theta}_{CS}"; fgVariableUnits[kCosThetaCS] = ""; fgVariableNames[kPhiCS] = "#varphi_{CS}"; fgVariableUnits[kPhiCS] = "rad."; + fgVariableNames[kPhiTildeCS] = "#tilde{#varphi}_{CS}"; + fgVariableUnits[kPhiTildeCS] = "rad."; + fgVariableNames[kCosThetaPP] = "cos#it{#theta}_{PP}"; + fgVariableUnits[kCosThetaPP] = ""; + fgVariableNames[kPhiPP] = "#varphi_{PP}"; + fgVariableUnits[kPhiPP] = "rad."; + fgVariableNames[kPhiTildePP] = "#tilde{#varphi}_{PP}"; + fgVariableUnits[kPhiTildePP] = "rad."; + fgVariableNames[kCosThetaRM] = "cos#it{#theta}_{RM}"; + fgVariableUnits[kCosThetaRM] = ""; + fgVariableNames[kCosThetaStarTPC] = "cos#it{#theta}^{*}_{TPC}"; + fgVariableUnits[kCosThetaStarTPC] = ""; + fgVariableNames[kCosThetaStarFT0A] = "cos#it{#theta}^{*}_{FT0A}"; + fgVariableUnits[kCosThetaStarFT0A] = ""; + fgVariableNames[kCosThetaStarFT0C] = "cos#it{#theta}^{*}_{FT0C}"; + fgVariableUnits[kCosThetaStarFT0C] = ""; + 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"; @@ -883,6 +1294,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}"; @@ -903,4 +1318,740 @@ void VarManager::SetDefaultVarNames() 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] = ""; + fgVariableNames[kS12] = "m_{12}^{2}"; + fgVariableUnits[kS12] = "GeV^{2}/c^{4}"; + fgVariableNames[kS13] = "m_{13}^{2}"; + fgVariableUnits[kS13] = "GeV^{2}/c^{4}"; + fgVariableNames[kS23] = "m_{23}^{2}"; + fgVariableUnits[kS23] = "GeV^{2}/c^{4}"; + fgVariableNames[kBdtBackground] = "kBdtBackground"; + fgVariableUnits[kBdtBackground] = " "; + fgVariableNames[kBdtPrompt] = "kBdtPrompt"; + fgVariableUnits[kBdtPrompt] = " "; + fgVariableNames[kBdtNonprompt] = "kBdtNonprompt"; + fgVariableUnits[kBdtNonprompt] = " "; + + // Set the variables short names map. This is needed for dynamic configuration via JSON files + fgVarNamesMap["kNothing"] = kNothing; + fgVarNamesMap["kRunNo"] = kRunNo; + 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["kCentFT0A"] = kCentFT0A; + fgVarNamesMap["kCentFT0M"] = kCentFT0M; + 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["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["kTPCnSigmaMu"] = kTPCnSigmaMu; + fgVarNamesMap["kTPCnSigmaPi"] = kTPCnSigmaPi; + 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["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["kMCCosTheta"] = kMCCosTheta; + fgVarNamesMap["kMCHadronPdgCode"] = kMCHadronPdgCode; + fgVarNamesMap["kMCCosChi"] = kMCCosChi; + fgVarNamesMap["kMCHadronPt"] = kMCHadronPt; + fgVarNamesMap["kMCWeight_before"] = kMCWeight_before; + 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["kMCCosThetaHE"] = kMCCosThetaHE; + fgVarNamesMap["kMCPhiHE"] = kMCPhiHE; + fgVarNamesMap["kMCPhiTildeHE"] = kMCPhiTildeHE; + fgVarNamesMap["kMCCosThetaCS"] = kMCCosThetaCS; + fgVarNamesMap["kMCPhiCS"] = kMCPhiCS; + fgVarNamesMap["kMCPhiTildeCS"] = kMCPhiTildeCS; + fgVarNamesMap["kMCCosThetaPP"] = kMCCosThetaPP; + fgVarNamesMap["kMCPhiPP"] = kMCPhiPP; + fgVarNamesMap["kMCPhiTildePP"] = kMCPhiTildePP; + fgVarNamesMap["kMCCosThetaRM"] = kMCCosThetaRM; + fgVarNamesMap["kMCParticleGeneratorId"] = kMCParticleGeneratorId; + fgVarNamesMap["kNMCParticleVariables"] = kNMCParticleVariables; + fgVarNamesMap["kMCMotherPdgCode"] = kMCMotherPdgCode; + fgVarNamesMap["kCandidateId"] = kCandidateId; + fgVarNamesMap["kPairType"] = kPairType; + fgVarNamesMap["kVertexingLxy"] = kVertexingLxy; + fgVarNamesMap["kVertexingLxyErr"] = kVertexingLxyErr; + fgVarNamesMap["kMCVertexingLxy"] = kMCVertexingLxy; + fgVarNamesMap["kVertexingPseudoCTau"] = kVertexingPseudoCTau; + fgVarNamesMap["kVertexingLxyz"] = kVertexingLxyz; + fgVarNamesMap["kVertexingLxyzErr"] = kVertexingLxyzErr; + fgVarNamesMap["kMCVertexingLxyz"] = kMCVertexingLxyz; + fgVarNamesMap["kVertexingLz"] = kVertexingLz; + fgVarNamesMap["kVertexingLzErr"] = kVertexingLzErr; + fgVarNamesMap["kMCVertexingLz"] = kMCVertexingLz; + fgVarNamesMap["kVertexingTauxy"] = kVertexingTauxy; + fgVarNamesMap["kVertexingTauxyErr"] = kVertexingTauxyErr; + fgVarNamesMap["kMCVertexingTauxy"] = kMCVertexingTauxy; + 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["kMCVertexingTauzProjected"] = kVertexingTauzProjected; + fgVarNamesMap["kMCVertexingTauxyProjected"] = kVertexingTauxyProjected; + fgVarNamesMap["kMCVertexingTauxyzProjected"] = kVertexingTauxyzProjected; + fgVarNamesMap["kVertexingTauz"] = kVertexingTauz; + fgVarNamesMap["kVertexingTauzErr"] = kVertexingTauzErr; + fgVarNamesMap["kMCVertexingTauz"] = kMCVertexingTauz; + fgVarNamesMap["kVertexingPz"] = kVertexingPz; + fgVarNamesMap["kVertexingSV"] = kVertexingSV; + fgVarNamesMap["kVertexingProcCode"] = kVertexingProcCode; + fgVarNamesMap["kVertexingChi2PCA"] = kVertexingChi2PCA; + fgVarNamesMap["kCosThetaHE"] = kCosThetaHE; + fgVarNamesMap["kPhiHE"] = kPhiHE; + fgVarNamesMap["kPhiTildeHE"] = kPhiTildeHE; + fgVarNamesMap["kCosThetaCS"] = kCosThetaCS; + fgVarNamesMap["kPhiCS"] = kPhiCS; + fgVarNamesMap["kPhiTildeCS"] = kPhiTildeCS; + fgVarNamesMap["kCosThetaPP"] = kCosThetaPP; + fgVarNamesMap["kPhiPP"] = kPhiPP; + fgVarNamesMap["kPhiTildePP"] = kPhiTildePP; + fgVarNamesMap["kCosThetaRM"] = kCosThetaRM; + fgVarNamesMap["kCosThetaStarTPC"] = kCosThetaStarTPC; + fgVarNamesMap["kCosThetaStarFT0A"] = kCosThetaStarFT0A; + fgVarNamesMap["kCosThetaStarFT0C"] = kCosThetaStarFT0C; + 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["kMCCosPointingAngle"] = kMCCosPointingAngle; + 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["kS12"] = kS12, + fgVarNamesMap["kS13"] = kS13, + fgVarNamesMap["kS23"] = kS23, + fgVarNamesMap["kNPairVariables"] = kNPairVariables; + fgVarNamesMap["kPairMass"] = kPairMass; + fgVarNamesMap["kPairMassDau"] = kPairMassDau; + fgVarNamesMap["kMassDau"] = kMassDau; + fgVarNamesMap["kPairPt"] = kPairPt; + fgVarNamesMap["kPairPtDau"] = kPairPtDau; + fgVarNamesMap["kPairEta"] = kPairEta; + fgVarNamesMap["kPairRap"] = kPairRap; + fgVarNamesMap["kPairPhi"] = kPairPhi; + fgVarNamesMap["kPairPhiv"] = kPairPhiv; + fgVarNamesMap["kDileptonHadronKstar"] = kDileptonHadronKstar; + fgVarNamesMap["kDeltaEta"] = kDeltaEta; + fgVarNamesMap["kDeltaPhi"] = kDeltaPhi; + fgVarNamesMap["kDeltaPhiSym"] = kDeltaPhiSym; + fgVarNamesMap["kCosTheta"] = kCosTheta; + fgVarNamesMap["kCosChi"] = kCosChi; + fgVarNamesMap["kECWeight"] = kECWeight; + fgVarNamesMap["kEWeight_before"] = kEWeight_before; + fgVarNamesMap["kPtDau"] = kPtDau; + fgVarNamesMap["kEtaDau"] = kEtaDau; + fgVarNamesMap["kPhiDau"] = kPhiDau; + 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; + fgVarNamesMap["kBdtBackground"] = kBdtBackground; + fgVarNamesMap["kBdtPrompt"] = kBdtPrompt; + fgVarNamesMap["kBdtNonprompt"] = kBdtNonprompt; + fgVariableNames[kAmplitudeFT0A] = "FT0A amplitude"; + fgVariableUnits[kAmplitudeFT0A] = "a.u."; + fgVariableNames[kAmplitudeFT0C] = "FT0C amplitude"; + fgVariableUnits[kAmplitudeFT0C] = "a.u."; + fgVariableNames[kTimeFT0A] = "FT0A time"; + fgVariableUnits[kTimeFT0A] = "ns"; + fgVariableNames[kTimeFT0C] = "FT0C time"; + fgVariableUnits[kTimeFT0C] = "ns"; + fgVariableNames[kTriggerMaskFT0] = "FT0 trigger mask"; + fgVariableUnits[kTriggerMaskFT0] = ""; + fgVariableNames[kNFiredChannelsFT0A] = "FT0A fired channels"; + fgVariableUnits[kNFiredChannelsFT0A] = ""; + fgVariableNames[kNFiredChannelsFT0C] = "FT0C fired channels"; + fgVariableUnits[kNFiredChannelsFT0C] = ""; + fgVariableNames[kAmplitudeFDDA] = "FDDA amplitude"; + fgVariableUnits[kAmplitudeFDDA] = "a.u."; + fgVariableNames[kAmplitudeFDDC] = "FDDC amplitude"; + fgVariableUnits[kAmplitudeFDDC] = "a.u."; + fgVariableNames[kTimeFDDA] = "FDDA time"; + fgVariableUnits[kTimeFDDA] = "ns"; + fgVariableNames[kTimeFDDC] = "FDDC time"; + fgVariableUnits[kTimeFDDC] = "ns"; + fgVariableNames[kTriggerMaskFDD] = "FDD trigger mask"; + fgVariableUnits[kTriggerMaskFDD] = ""; + fgVariableNames[kAmplitudeFV0A] = "FV0A amplitude"; + fgVariableUnits[kAmplitudeFV0A] = "a.u."; + fgVariableNames[kTimeFV0A] = "FV0A time"; + fgVariableUnits[kTimeFV0A] = "ns"; + fgVariableNames[kTriggerMaskFV0A] = "FV0A trigger mask"; + fgVariableUnits[kTriggerMaskFV0A] = ""; + fgVariableNames[kNFiredChannelsFV0A] = "FV0A fired channels"; + fgVariableUnits[kNFiredChannelsFV0A] = ""; + fgVariableNames[kBBFT0Apf] = "FT0A BB pileup flag"; + fgVariableUnits[kBBFT0Apf] = ""; + fgVariableNames[kBGFT0Apf] = "FT0A BG pileup flag"; + fgVariableUnits[kBGFT0Apf] = ""; + fgVariableNames[kBBFT0Cpf] = "FT0C BB pileup flag"; + fgVariableUnits[kBBFT0Cpf] = ""; + fgVariableNames[kBGFT0Cpf] = "FT0C BG pileup flag"; + fgVariableUnits[kBGFT0Cpf] = ""; + fgVariableNames[kBBFV0Apf] = "FV0A BB pileup flag"; + fgVariableUnits[kBBFV0Apf] = ""; + fgVariableNames[kBGFV0Apf] = "FV0A BG pileup flag"; + fgVariableUnits[kBGFV0Apf] = ""; + fgVariableNames[kBBFDDApf] = "FDDA BB pileup flag"; + fgVariableUnits[kBBFDDApf] = ""; + fgVariableNames[kBGFDDApf] = "FDDA BG pileup flag"; + fgVariableUnits[kBGFDDApf] = ""; + fgVariableNames[kBBFDDCpf] = "FDDC BB pileup flag"; + fgVariableUnits[kBBFDDCpf] = ""; + fgVariableNames[kBGFDDCpf] = "FDDC BG pileup flag"; + fgVariableUnits[kBGFDDCpf] = ""; } diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index b0b9fc89dbc..822575019af 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -17,53 +17,60 @@ #ifndef PWGDQ_CORE_VARMANAGER_H_ #define PWGDQ_CORE_VARMANAGER_H_ -#include -#include #ifndef HomogeneousField #define HomogeneousField #endif -#include -#include -#include -#include -#include -#include +#include "PWGUD/Core/UDHelpers.h" -#include -#include -#include "TRandom.h" -#include "TH3F.h" -#include "Math/Vector4D.h" -#include "Math/Vector3D.h" -#include "Math/GenVector/Boost.h" - -#include "Framework/DataTypes.h" -#include "TGeoGlobalMagField.h" -#include "Field/MagneticField.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/Vertex.h" -#include "DCAFitter/DCAFitterN.h" #include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/TriggerAliases.h" -#include "ReconstructionDataFormats/DCA.h" -#include "DetectorsBase/Propagator.h" +#include "Common/Core/CollisionTypeHelper.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/fwdtrackUtilities.h" #include "Common/Core/trackUtilities.h" -#include "Math/SMatrix.h" -#include "ReconstructionDataFormats/TrackFwd.h" -#include "DCAFitter/FwdDCAFitterN.h" -#include "GlobalTracking/MatchGlobalFwd.h" -#include "CommonConstants/PhysicsConstants.h" -#include "CommonConstants/LHCConstants.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "KFParticle.h" -#include "KFPTrack.h" -#include "KFPVertex.h" -#include "KFParticleBase.h" -#include "KFVertex.h" +#include +#include +#include +#include +#include -#include "Common/Core/EventPlaneHelper.h" +#include +#include +#include +#include +#include +#include +#include +#include using std::complex; using std::cout; @@ -101,6 +108,9 @@ class VarManager : public TObject ReducedZdc = BIT(17), CollisionMultExtra = BIT(18), ReducedEventMultExtra = BIT(19), + CollisionQvectCentr = BIT(20), + RapidityGapFilter = BIT(21), + ReducedFit = BIT(22), Track = BIT(0), TrackCov = BIT(1), TrackExtra = BIT(2), @@ -126,7 +136,10 @@ 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), + MFTCov = BIT(28) }; enum PairCandidateType { @@ -137,13 +150,17 @@ class VarManager : public TObject kElectronMuon, // e.g. Electron - muon correlations kBcToThreeMuons, // e.g. Bc -> mu+ mu- mu+ kBtoJpsiEEK, // e.g. B+ -> e+ e- K+ + kJpsiEEProton, // e.g. Jpsi-proton correlation, Jpsi to e+e- kXtoJpsiPiPi, // e.g. X(3872) -> J/psi pi+ pi- + kPsi2StoJpsiPiPi, // e.g. Psi(2S) -> 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+ + kJpsiHadronMass, // using the real hadron mass + kJpsiPionMass, // treat the hadron as pion kNMaxCandidateTypes }; @@ -168,12 +185,11 @@ class VarManager : public TObject kNothing = -1, // Run wise variables kRunNo = 0, - kRunId, - kRunIndex, kNRunWiseVariables, // Event wise variables kTimestamp, + kTimeFromSOR, // Time since Start of Run (SOR) in minutes kCollisionTime, kCollisionTimeRes, kBC, @@ -186,7 +202,10 @@ class VarManager : public TObject 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 + 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, @@ -212,6 +231,8 @@ class VarManager : public TObject kVtxChi2, kCentVZERO, kCentFT0C, + kCentFT0A, + kCentFT0M, kMultTPC, kMultFV0A, kMultFV0C, @@ -223,6 +244,9 @@ class VarManager : public TObject kMultZNC, kMultTracklets, kMultDimuons, + kMultAntiMuons, + kMultMuons, + kMultSingleMuons, kMultNTracksHasITS, kMultNTracksHasTPC, kMultNTracksHasTOF, @@ -230,7 +254,11 @@ class VarManager : public TObject kMultNTracksITSOnly, kMultNTracksTPCOnly, kMultNTracksITSTPC, + kMultNTracksPVeta1, + kMultNTracksPVetaHalf, kTrackOccupancyInTimeRange, + kFT0COccupancyInTimeRange, + kNoCollInTimeRangeStandard, kMultAllTracksTPCOnly, kMultAllTracksITSTPC, kNTPCpileupContribA, @@ -239,13 +267,30 @@ class VarManager : public TObject kNTPCpileupZC, kNTPCtracksInPast, kNTPCtracksInFuture, + kNTPCcontribLongA, + kNTPCcontribLongC, + kNTPCmeanTimeLongA, + kNTPCmeanTimeLongC, + kNTPCmedianTimeLongA, + kNTPCmedianTimeLongC, + kNTPCcontribShortA, + kNTPCcontribShortC, + kNTPCmeanTimeShortA, + kNTPCmeanTimeShortC, + kNTPCmedianTimeShortA, + kNTPCmedianTimeShortC, kMCEventGeneratorId, + kMCEventSubGeneratorId, kMCVtxX, kMCVtxY, kMCVtxZ, kMCEventTime, kMCEventWeight, kMCEventImpParam, + kMCEventCentrFT0C, + kMultMCNParticlesEta10, + kMultMCNParticlesEta08, + kMultMCNParticlesEta05, kQ1ZNAX, kQ1ZNAY, kQ1ZNCX, @@ -304,6 +349,15 @@ class VarManager : public TObject 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, @@ -316,6 +370,15 @@ class VarManager : public TObject 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, @@ -329,10 +392,13 @@ 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 @@ -355,17 +421,37 @@ class VarManager : public TObject kTimeZNC, kTimeZPA, kTimeZPC, - kNEventWiseVariables, 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, @@ -393,6 +479,8 @@ class VarManager : public TObject kEta1, kPhi1, kCharge1, + kPin_leg1, + kTPCnSigmaKa_leg1, kPt2, kEta2, kPhi2, @@ -427,10 +515,9 @@ class VarManager : public TObject kTPCncls, kITSClusterMap, kTPCnclsCR, + kTPCnCRoverFindCls, kTPCchi2, kTPCsignal, - kTPCsignalRandomized, - kTPCsignalRandomizedDelta, kPhiTPCOuter, kTrackIsInsideTPCModule, kTRDsignal, @@ -438,7 +525,11 @@ class VarManager : public TObject kTOFbeta, kTrackLength, kTrackDCAxy, + kTrackDCAxyProng1, + kTrackDCAxyProng2, kTrackDCAz, + kTrackDCAzProng1, + kTrackDCAzProng2, kTrackDCAsigXY, kTrackDCAsigZ, kTrackDCAresXY, @@ -450,20 +541,14 @@ class VarManager : public TObject kTrackCTglTgl, kTrackC1Pt21Pt2, kTPCnSigmaEl, - kTPCnSigmaElRandomized, - kTPCnSigmaElRandomizedDelta, kTPCnSigmaMu, kTPCnSigmaPi, - kTPCnSigmaPiRandomized, - kTPCnSigmaPiRandomizedDelta, kTPCnSigmaKa, kTPCnSigmaPr, kTPCnSigmaEl_Corr, kTPCnSigmaPi_Corr, kTPCnSigmaKa_Corr, kTPCnSigmaPr_Corr, - kTPCnSigmaPrRandomized, - kTPCnSigmaPrRandomizedDelta, kTOFnSigmaEl, kTOFnSigmaMu, kTOFnSigmaPi, @@ -526,6 +611,7 @@ class VarManager : public TObject kMCPx, kMCPy, kMCPz, + kMCMass, kMCE, kMCVx, kMCVy, @@ -536,10 +622,42 @@ class VarManager : public TObject kMCY, kMCParticleGeneratorId, kNMCParticleVariables, + kMCHadronPdgCode, + kMCCosTheta, + kMCJpsiPt, + kMCCosChi, + kMCdeltaphi, + kMCdeltaeta, + kMCHadronPt, + kMCHadronEta, + kMCHadronPhi, + kMCWeight, + kMCCosChi_randomPhi_toward, + kMCWeight_randomPhi_toward, + kMCCosChi_randomPhi_away, + kMCWeight_randomPhi_away, + kMCCosChi_randomPhi_trans, + kMCWeight_randomPhi_trans, + kMCdeltaphi_randomPhi_toward, + kMCdeltaphi_randomPhi_away, + kMCdeltaphi_randomPhi_trans, + kMCWeight_before, // MC mother particle variables kMCMotherPdgCode, + // MC pair variables + kMCCosThetaHE, + kMCPhiHE, + kMCPhiTildeHE, + kMCCosThetaCS, + kMCPhiCS, + kMCPhiTildeCS, + kMCCosThetaPP, + kMCPhiPP, + kMCPhiTildePP, + kMCCosThetaRM, + // Pair variables kCandidateId, kPairType, @@ -548,28 +666,56 @@ class VarManager : public TObject kVertexingPseudoCTau, kVertexingLxyz, kVertexingLxyzErr, + kMCVertexingLxy, + kMCVertexingLxyz, + kMCLxyExpected, + kMCLxyzExpected, kVertexingLz, kVertexingLzErr, + kMCVertexingLz, kVertexingTauxy, kVertexingTauxyErr, + kMCVertexingTauxy, kVertexingLzProjected, kVertexingLxyProjected, kVertexingLxyzProjected, + kMCVertexingLzProjected, + kMCVertexingLxyProjected, + kMCVertexingLxyzProjected, kVertexingTauzProjected, kVertexingTauxyProjected, + kVertexingTauxyProjectedPoleJPsiMass, kVertexingTauxyProjectedNs, kVertexingTauxyzProjected, + kMCVertexingTauzProjected, + kMCVertexingTauxyProjected, + kMCVertexingTauxyProjectedNs, + kMCVertexingTauxyzProjected, + kMCCosPointingAngle, kVertexingTauz, + kMCVertexingTauz, kVertexingTauzErr, kVertexingPz, kVertexingSV, kVertexingProcCode, kVertexingChi2PCA, kCosThetaHE, - kCosThetaCS, kPhiHE, + kPhiTildeHE, + kCosThetaCS, kPhiCS, + kPhiTildeCS, + kCosThetaPP, + kPhiPP, + kPhiTildePP, + kCosThetaRM, + kCosThetaStarTPC, + kCosThetaStarFT0A, + kCosThetaStarFT0C, + kCosPhiVP, + kPhiVP, kDeltaPhiPair2, + kDeltaEtaPair2, kPsiPair, kDeltaPhiPair, kOpeningAngle, @@ -584,6 +730,10 @@ class VarManager : public TObject kImpParXYK, kDCATrackProd, kDCATrackVtxProd, + kV2SP, + kV2EP, + kWV2SP, + kWV2EP, kU2Q2, kU3Q3, kQ42XA, @@ -595,12 +745,28 @@ class VarManager : public TObject kS13A, kS31A, kM11REF, + kM11REFetagap, kM01POI, kM1111REF, + kM11M1111REF, + kM11M1111REFoverMp, + kM01M0111POIoverMp, kM0111POI, kCORR2REF, + kCORR2REFbydimuons, + kCORR2REFbysinglemu, + kCORR2REFetagap, kCORR2POI, + kCORR2POICORR4POI, + kCORR2REFCORR4POI, + kCORR2REFCORR2POI, + kM01M0111overMp, + kM11M0111overMp, + kM11M01overMp, + kCORR2CORR4REF, kCORR4REF, + kCORR4REFbydimuons, + kCORR4REFbysinglemu, kCORR4POI, kM11REFoverMp, kM01POIoverMp, @@ -608,6 +774,44 @@ class VarManager : public TObject 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, @@ -641,6 +845,9 @@ class VarManager : public TObject kKFJpsiDCAxy, kKFPairDeviationFromPV, kKFPairDeviationxyFromPV, + kS12, + kS13, + kS23, kNPairVariables, // Candidate-track correlation variables @@ -650,12 +857,30 @@ class VarManager : public TObject kPairPt, kPairPtDau, kPairEta, + kPairRap, kPairPhi, kPairPhiv, kDeltaEta, kDeltaPhi, kDeltaPhiSym, kNCorrelationVariables, + kDileptonHadronKstar, + kCosChi, + kEtaDau, + kPhiDau, + kECWeight, + kPtDau, + kCosTheta, + kEWeight_before, + kCosChi_randomPhi_trans, + kCosChi_randomPhi_toward, + kCosChi_randomPhi_away, + kWeight_randomPhi_trans, + kWeight_randomPhi_toward, + kWeight_randomPhi_away, + kdeltaphi_randomPhi_trans, + kdeltaphi_randomPhi_toward, + kdeltaphi_randomPhi_away, // Dilepton-track-track variables kQuadMass, @@ -669,6 +894,7 @@ class VarManager : public TObject kQ, kDeltaR1, kDeltaR2, + kDeltaR, // DQ-HF correlation variables kMassCharmHadron, @@ -685,18 +911,55 @@ class VarManager : public TObject // deltaMass_jpsi = kPairMass - kPairMassDau +3.096900 kDeltaMass_jpsi, + // BDT score + kBdtBackground, + kBdtPrompt, + kBdtNonprompt, + + // FIT detector variables + kAmplitudeFT0A, + kAmplitudeFT0C, + kTimeFT0A, + kTimeFT0C, + kTriggerMaskFT0, + kAmplitudeFDDA, + kAmplitudeFDDC, + kTimeFDDA, + kTimeFDDC, + kTriggerMaskFDD, + kAmplitudeFV0A, + kTimeFV0A, + kTriggerMaskFV0A, + kBBFT0Apf, + kBGFT0Apf, + kBBFT0Cpf, + kBGFT0Cpf, + kBBFV0Apf, + kBGFV0Apf, + kBBFDDApf, + kBGFDDApf, + kBBFDDCpf, + kBGFDDCpf, + kNFiredChannelsFT0A, + kNFiredChannelsFT0C, + kNFiredChannelsFV0A, + kNVars }; // end of Variables enumeration enum CalibObjects { kTPCElectronMean = 0, kTPCElectronSigma, + kTPCElectronStatus, kTPCPionMean, kTPCPionSigma, + kTPCPionStatus, kTPCKaonMean, kTPCKaonSigma, + kTPCKaonStatus, kTPCProtonMean, kTPCProtonSigma, + kTPCProtonStatus, kNCalibObjects }; @@ -709,18 +972,21 @@ class VarManager : public TObject enum EventFilters { kDoubleGap = 0, kSingleGapA, - kSingleGapC + kSingleGapC, + kITSUPCMode }; enum MuonExtrapolation { // Index used to set different options for Muon propagation kToVertex = 0, // propagtion to vertex by default kToDCA, - kToRabs + kToRabs, + kToMatching }; - static TString fgVariableNames[kNVars]; // variable names - static TString fgVariableUnits[kNVars]; // variable units + 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) @@ -753,37 +1019,26 @@ class VarManager : public TObject return false; } - static void SetRunNumbers(int n, int* runs); - static void SetRunNumbers(std::vector runs); - static float GetRunIndex(double); - static void SetDummyRunlist(int InitRunnumber); - static int GetDummyFirst(); - static int GetDummyLast(); - static int GetDummyNRuns() - { - if (fgRunMap.size() == 0) { - return 101; - } else { - return fgRunMap.size(); - } - } - static int GetNRuns() - { - return fgRunMap.size(); - } - static TString GetRunStr() - { - return fgRunStr; - } - // Setup the collision system static void SetCollisionSystem(TString system, float energy); + static void SetCollisionSystem(o2::parameters::GRPLHCIFData* grplhcif); static void SetMagneticField(float magField) { fgMagField = magField; } + // Setup plane position for MFT-MCH matching + static void SetMatchingPlane(float z) + { + fgzMatching = z; + } + + static float GetMatchingPlane() + { + return fgzMatching; + } + // Setup the 2 prong KFParticle static void SetupTwoProngKFParticle(float magField) { @@ -852,7 +1107,25 @@ class VarManager : public TObject fgFitterThreeProngBarrel.setMinParamChange(minParamChange); fgFitterThreeProngBarrel.setMinRelChi2Change(minRelChi2Change); fgFitterThreeProngBarrel.setUseAbsDCA(useAbsDCA); - cout << "!!! fgFitterThreeProngBarrel bz = " << fgFitterThreeProngBarrel.getBz() << endl; + fgUsedKF = false; + } + + // Setup the 4 prong KFParticle + static void SetupFourProngKFParticle(float magField) + { + KFParticle::SetField(magField); + fgUsedKF = true; + } + + // Setup the 4 prong DCAFitterN + static void SetupFourProngDCAFitter(float magField, bool propagateToPCA, float maxR, float /*maxDZIni*/, float minParamChange, float minRelChi2Change, bool useAbsDCA) + { + fgFitterFourProngBarrel.setBz(magField); + fgFitterFourProngBarrel.setPropagateToPCA(propagateToPCA); + fgFitterFourProngBarrel.setMaxR(maxR); + fgFitterFourProngBarrel.setMinParamChange(minParamChange); + fgFitterFourProngBarrel.setMinRelChi2Change(minRelChi2Change); + fgFitterFourProngBarrel.setUseAbsDCA(useAbsDCA); fgUsedKF = false; } @@ -875,8 +1148,12 @@ class VarManager : public TObject return deltaPsi; } + template + static o2::track::TrackParCovFwd FwdToTrackPar(const T& track, const C& cov); template static o2::dataformats::GlobalFwdTrack PropagateMuon(const T& muon, const C& collision, int endPoint = kToVertex); + template + static o2::track::TrackParCovFwd PropagateFwd(const T& track, const C& cov, float z); template static void FillMuonPDca(const T& muon, const C& collision, float* values = nullptr); template @@ -885,34 +1162,54 @@ class VarManager : public TObject 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 static void FillPhoton(T const& photon, float* values = nullptr); template static void FillTrackCollision(T const& track, C const& collision, float* values = nullptr); + template + static void FillTrackCollisionMC(T1 const& track, T2 const& MotherTrack, C const& collision, float* values = nullptr); template static void FillTrackCollisionMatCorr(T const& track, C const& collision, M const& materialCorr, P const& propagator, float* values = nullptr); template static void FillTrackMC(const U& mcStack, T const& track, float* values = nullptr); + template + static void FillEnergyCorrelatorsMC(T const& track, T1 const& t1, 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 FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, const C& collision, C2 const& mftcov, 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 FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr, PairCandidateType pairType = kTripleCandidateToEEPhoton); + 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); + template + static void FillQuadMC(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 @@ -934,13 +1231,21 @@ class VarManager : public TObject 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 FillDileptonTrackTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track1, T1 const& track2, float* values); template static void FillZDC(const T& zdc, float* values = nullptr); + template + static void FillBdtScore(const T& bdtScore, float* values = nullptr); + template + static void FillFIT(const T1& bc, const T2& bcs, const T3& ft0s, const T4& fv0as, const T5& fdds, float* values = nullptr); static void SetCalibrationObject(CalibObjects calib, TObject* obj) { @@ -948,17 +1253,32 @@ class VarManager : public TObject // Check whether all the needed objects for TPC postcalibration are available if (fgCalibs.find(kTPCElectronMean) != fgCalibs.end() && fgCalibs.find(kTPCElectronSigma) != fgCalibs.end()) { fgRunTPCPostCalibration[0] = true; + fgUsedVars[kTPCnSigmaEl_Corr] = true; } if (fgCalibs.find(kTPCPionMean) != fgCalibs.end() && fgCalibs.find(kTPCPionSigma) != fgCalibs.end()) { fgRunTPCPostCalibration[1] = true; + fgUsedVars[kTPCnSigmaPi_Corr] = true; } if (fgCalibs.find(kTPCKaonMean) != fgCalibs.end() && fgCalibs.find(kTPCKaonSigma) != fgCalibs.end()) { fgRunTPCPostCalibration[2] = true; + fgUsedVars[kTPCnSigmaKa_Corr] = true; } if (fgCalibs.find(kTPCProtonMean) != fgCalibs.end() && fgCalibs.find(kTPCProtonSigma) != fgCalibs.end()) { fgRunTPCPostCalibration[3] = true; + fgUsedVars[kTPCnSigmaPr_Corr] = true; + } + } + + static void SetCalibrationType(int type, bool useInterpolation = true) + { + if (type < 0 || type > 2) { + LOG(fatal) << "Invalid calibration type. Must be 0, 1, or 2."; } + fgCalibrationType = type; + fgUseInterpolatedCalibration = useInterpolation; } + static double ComputePIDcalibration(int species, double nSigmaValue); + static TObject* GetCalibrationObject(CalibObjects calib) { auto obj = fgCalibs.find(calib); @@ -980,6 +1300,12 @@ class VarManager : public TObject fgITSROFBorderMarginHigh = marginHigh; } + static void SetSORandEOR(uint64_t sor, uint64_t eor) + { + fgSOR = sor; + fgEOR = eor; + } + public: VarManager(); ~VarManager() override; @@ -993,18 +1319,20 @@ class VarManager : public TObject static void SetVariableDependencies(); // toggle those variables on which other used variables might depend static float fgMagField; - static std::map fgRunMap; // map of runs to be used in histogram axes - static TString fgRunStr; // semi-colon separated list of runs, to be used for histogram axis labels - static std::vector fgRunList; // vector of runs, to be used for histogram axis - 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 void FillEventDerived(float* values = nullptr); + static float fgzMatching; + 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 ROOT::Math::PxPyPzEVector fgBeamA; // beam from A-side 4-momentum vector + static ROOT::Math::PxPyPzEVector fgBeamC; // beam from C-side 4-momentum vector + + // static void FillEventDerived(float* values = nullptr); static void FillTrackDerived(float* values = nullptr); template static auto getRotatedCovMatrixXX(const T& matrix, U phi, V theta); @@ -1017,22 +1345,40 @@ class VarManager : public TObject static float calculateCosPA(KFParticle kfp, KFParticle PV); template static float calculatePhiV(const T1& t1, const T2& t2); + template + static float LorentzTransformJpsihadroncosChi(TString Option, const T1& v1, const T2& v2); static o2::vertexing::DCAFitterN<2> fgFitterTwoProngBarrel; static o2::vertexing::DCAFitterN<3> fgFitterThreeProngBarrel; + static o2::vertexing::DCAFitterN<4> fgFitterFourProngBarrel; static o2::vertexing::FwdDCAFitterN<2> fgFitterTwoProngFwd; static o2::vertexing::FwdDCAFitterN<3> fgFitterThreeProngFwd; static o2::globaltracking::MatchGlobalFwd mMatching; static std::map fgCalibs; // map of calibration histograms static bool fgRunTPCPostCalibration[4]; // 0-electron, 1-pion, 2-kaon, 3-proton + static int fgCalibrationType; // 0 - no calibration, 1 - calibration vs (TPCncls,pIN,eta) typically for pp, 2 - calibration vs (eta,nPV,nLong,tLong) typically for PbPb + static bool fgUseInterpolatedCalibration; // use interpolated calibration histograms (default: true) VarManager& operator=(const VarManager& c); VarManager(const VarManager& c); - ClassDef(VarManager, 3); + ClassDef(VarManager, 4); }; +template +o2::track::TrackParCovFwd VarManager::FwdToTrackPar(const T& track, const C& cov) +{ + double chi2 = track.chi2(); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), + cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), + cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; + return trackparCov; +} + template auto VarManager::getRotatedCovMatrixXX(const T& matrix, U phi, V theta) { @@ -1081,13 +1427,7 @@ KFPTrack VarManager::createKFPTrackFromTrack(const T& track) template KFPTrack VarManager::createKFPFwdTrackFromFwdTrack(const T& muon) { - 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 trackparCov{muon.z(), tpars, tcovs, chi2}; + o2::track::TrackParCovFwd trackparCov = FwdToTrackPar(muon, muon); std::array trk_cov; trackparCov.getCovXYZPxPyPzGlo(trk_cov); @@ -1102,7 +1442,7 @@ KFPTrack VarManager::createKFPFwdTrackFromFwdTrack(const T& muon) kfpTrack.SetCovarianceMatrix(trkcov_KF); kfpTrack.SetCharge(muon.sign()); kfpTrack.SetNDF(muon.nClusters() - 5); - kfpTrack.SetChi2(chi2); + kfpTrack.SetChi2(muon.chi2()); return kfpTrack; } @@ -1121,19 +1461,13 @@ KFPVertex VarManager::createKFPVertexFromCollision(const T& collision) template o2::dataformats::GlobalFwdTrack VarManager::PropagateMuon(const T& muon, const C& collision, const int 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::track::TrackParCovFwd fwdtrack = FwdToTrackPar(muon, muon); o2::dataformats::GlobalFwdTrack propmuon; if (static_cast(muon.trackType()) > 2) { o2::dataformats::GlobalFwdTrack track; - track.setParameters(tpars); + track.setParameters(fwdtrack.getParameters()); track.setZ(fwdtrack.getZ()); - track.setCovariances(tcovs); + track.setCovariances(fwdtrack.getCovariances()); auto mchTrack = mMatching.FwdtoMCH(track); if (endPoint == kToVertex) { @@ -1145,6 +1479,9 @@ o2::dataformats::GlobalFwdTrack VarManager::PropagateMuon(const T& muon, const C if (endPoint == kToRabs) { o2::mch::TrackExtrap::extrapToZ(mchTrack, -505.); } + if (endPoint == kToMatching) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, fgzMatching); + } auto proptrack = mMatching.MCHtoFwd(mchTrack); propmuon.setParameters(proptrack.getParameters()); @@ -1165,6 +1502,14 @@ o2::dataformats::GlobalFwdTrack VarManager::PropagateMuon(const T& muon, const C return propmuon; } +template +o2::track::TrackParCovFwd VarManager::PropagateFwd(const T& track, const C& cov, float z) +{ + o2::track::TrackParCovFwd fwdtrack = FwdToTrackPar(track, cov); + fwdtrack.propagateToZhelix(z, fgMagField); + return fwdtrack; +} + template void VarManager::FillMuonPDca(const T& muon, const C& collision, float* values) { @@ -1197,7 +1542,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(); @@ -1263,17 +1608,41 @@ void VarManager::FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, co } } +template +void VarManager::FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, const C& collision, C2 const& mftcov, float* values) +{ + if (!values) { + values = fgValues; + } + if constexpr ((MuonfillMap & MuonCov) > 0) { + if constexpr ((MFTfillMap & MFTCov) > 0) { + o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); + o2::track::TrackParCovFwd mft = FwdToTrackPar(mfttrack, mftcov); + + o2::dataformats::GlobalFwdTrack globalRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuon, mft); + values[kX] = globalRefit.getX(); + values[kY] = globalRefit.getY(); + values[kZ] = globalRefit.getZ(); + values[kTgl] = globalRefit.getTgl(); + values[kPt] = globalRefit.getPt(); + values[kPz] = globalRefit.getPz(); + values[kEta] = globalRefit.getEta(); + values[kPhi] = globalRefit.getPhi(); + } + } +} + template void VarManager::FillBC(T const& bc, float* values) { if (!values) { values = fgValues; } - values[VarManager::kRunNo] = bc.runNumber(); - values[VarManager::kBC] = bc.globalBC(); + values[kRunNo] = bc.runNumber(); + values[kBC] = bc.globalBC(); values[kBCOrbit] = bc.globalBC() % o2::constants::lhc::LHCMaxBunches; - values[VarManager::kTimestamp] = bc.timestamp(); - values[VarManager::kRunIndex] = GetRunIndex(bc.runNumber()); + values[kTimestamp] = bc.timestamp(); + values[kTimeFromSOR] = (fgSOR > 0 ? (bc.timestamp() - fgSOR) / 60000. : -1.0); } template @@ -1294,6 +1663,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); } @@ -1310,7 +1688,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); @@ -1365,17 +1752,21 @@ void VarManager::FillEvent(T const& event, float* values) } if constexpr ((fillMap & CollisionCent) > 0 || (fillMap & ReducedEventExtended) > 0) { - values[kCentFT0C] = event.centFT0C(); + if constexpr ((fillMap & CollisionMC) == 0) { + values[kCentFT0C] = event.centFT0C(); + values[kCentFT0A] = event.centFT0A(); + values[kCentFT0M] = event.centFT0M(); + } } if constexpr ((fillMap & CollisionMult) > 0 || (fillMap & ReducedEventExtended) > 0) { - 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[kMultTPC] = event.multTPC(); + values[kMultFV0C] = event.multFV0C(); values[kMultZNA] = event.multZNA(); values[kMultZNC] = event.multZNC(); values[kMultTracklets] = event.multTracklets(); @@ -1390,33 +1781,70 @@ void VarManager::FillEvent(T const& event, float* values) values[kMultNTracksITSOnly] = event.multNTracksITSOnly(); values[kMultNTracksTPCOnly] = event.multNTracksTPCOnly(); values[kMultNTracksITSTPC] = event.multNTracksITSTPC(); - values[kTrackOccupancyInTimeRange] = event.trackOccupancyInTimeRange(); + 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[kNTPCpileupContribA] = event.nTPCpileupContribA(); - values[kNTPCpileupContribC] = event.nTPCpileupContribC(); - values[kNTPCpileupZA] = event.nTPCpileupZA(); - values[kNTPCpileupZC] = event.nTPCpileupZC(); - values[kNTPCtracksInPast] = event.nTPCtracksInPast(); - values[kNTPCtracksInFuture] = event.nTPCtracksInFuture(); + 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) { values[kRunNo] = event.runNumber(); - values[kRunIndex] = GetRunIndex(event.runNumber()); values[kVtxX] = event.posX(); 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); } @@ -1430,29 +1858,16 @@ 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); } - 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[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[kIsGoodITSLayersAll]) { + values[kIsGoodITSLayersAll] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); } if (fgUsedVars[kIsINT7]) { values[kIsINT7] = (event.alias_bit(kINT7) > 0); @@ -1549,11 +1964,15 @@ void VarManager::FillEvent(T const& event, float* values) } if constexpr ((fillMap & ReducedEventRefFlow) > 0) { - values[kM1111REF] = event.m1111ref(); - values[kM11REF] = event.m11ref(); - values[kCORR4REF] = event.corr4ref(); - values[kCORR2REF] = event.corr2ref(); 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; } } @@ -1604,40 +2023,225 @@ void VarManager::FillEvent(T const& event, float* values) 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(); values[kMCEventTime] = event.t(); values[kMCEventWeight] = event.weight(); values[kMCEventImpParam] = event.impactParameter(); + if constexpr ((fillMap & CollisionCent) > 0) { + // WARNING: temporary solution, ongoing work to provide proper MC gen. centrality + values[kMCEventCentrFT0C] = event.bestCollisionCentFT0C(); + values[kMultMCNParticlesEta05] = event.multMCNParticlesEta05(); + values[kMultMCNParticlesEta08] = event.multMCNParticlesEta08(); + values[kMultMCNParticlesEta10] = event.multMCNParticlesEta10(); + } } 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(); values[kMCEventTime] = event.t(); values[kMCEventWeight] = event.weight(); values[kMCEventImpParam] = event.impactParameter(); + values[kMCEventCentrFT0C] = event.centFT0C(); } - 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); + // 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 @@ -1686,29 +2290,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 (std::isnan(VarManager::fgValues[VarManager::kTwoR2SP1]) == true || std::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()); } } @@ -1739,7 +2337,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]) { @@ -1798,6 +2396,30 @@ void VarManager::FillTrack(T const& track, float* values) values[kIsDalitzLeg + i] = track.filteringFlags_bit(VarManager::kDalitzBits + i); } } + + 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 @@ -1866,6 +2488,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 } @@ -1960,7 +2585,7 @@ void VarManager::FillTrack(T const& track, float* values) } // Quantities based on the barrel PID tables - if constexpr ((fillMap & TrackPID) > 0 || (fillMap & ReducedTrackBarrelPID) > 0) { + if constexpr ((fillMap & TrackPID) > 0 || (fillMap & TrackTPCPID) > 0 || (fillMap & ReducedTrackBarrelPID) > 0) { values[kTPCnSigmaEl] = track.tpcNSigmaEl(); values[kTPCnSigmaPi] = track.tpcNSigmaPi(); values[kTPCnSigmaKa] = track.tpcNSigmaKa(); @@ -1974,114 +2599,47 @@ void VarManager::FillTrack(T const& track, float* values) } // compute TPC postcalibrated electron nsigma based on calibration histograms from CCDB if (fgUsedVars[kTPCnSigmaEl_Corr] && fgRunTPCPostCalibration[0]) { - TH3F* calibMean = reinterpret_cast(fgCalibs[kTPCElectronMean]); - TH3F* calibSigma = reinterpret_cast(fgCalibs[kTPCElectronSigma]); - - int binTPCncls = calibMean->GetXaxis()->FindBin(values[kTPCncls]); - binTPCncls = (binTPCncls == 0 ? 1 : binTPCncls); - binTPCncls = (binTPCncls > calibMean->GetXaxis()->GetNbins() ? calibMean->GetXaxis()->GetNbins() : binTPCncls); - int binPin = calibMean->GetYaxis()->FindBin(values[kPin]); - binPin = (binPin == 0 ? 1 : binPin); - binPin = (binPin > calibMean->GetYaxis()->GetNbins() ? calibMean->GetYaxis()->GetNbins() : binPin); - int binEta = calibMean->GetZaxis()->FindBin(values[kEta]); - binEta = (binEta == 0 ? 1 : binEta); - binEta = (binEta > calibMean->GetZaxis()->GetNbins() ? calibMean->GetZaxis()->GetNbins() : binEta); - - double mean = calibMean->GetBinContent(binTPCncls, binPin, binEta); - double width = calibSigma->GetBinContent(binTPCncls, binPin, binEta); if (!isTPCCalibrated) { - values[kTPCnSigmaEl_Corr] = (values[kTPCnSigmaEl] - mean) / width; + values[kTPCnSigmaEl_Corr] = ComputePIDcalibration(0, values[kTPCnSigmaEl]); } else { + LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; values[kTPCnSigmaEl_Corr] = track.tpcNSigmaEl(); } } + // compute TPC postcalibrated pion nsigma if required if (fgUsedVars[kTPCnSigmaPi_Corr] && fgRunTPCPostCalibration[1]) { - TH3F* calibMean = reinterpret_cast(fgCalibs[kTPCPionMean]); - TH3F* calibSigma = reinterpret_cast(fgCalibs[kTPCPionSigma]); - - int binTPCncls = calibMean->GetXaxis()->FindBin(values[kTPCncls]); - binTPCncls = (binTPCncls == 0 ? 1 : binTPCncls); - binTPCncls = (binTPCncls > calibMean->GetXaxis()->GetNbins() ? calibMean->GetXaxis()->GetNbins() : binTPCncls); - int binPin = calibMean->GetYaxis()->FindBin(values[kPin]); - binPin = (binPin == 0 ? 1 : binPin); - binPin = (binPin > calibMean->GetYaxis()->GetNbins() ? calibMean->GetYaxis()->GetNbins() : binPin); - int binEta = calibMean->GetZaxis()->FindBin(values[kEta]); - binEta = (binEta == 0 ? 1 : binEta); - binEta = (binEta > calibMean->GetZaxis()->GetNbins() ? calibMean->GetZaxis()->GetNbins() : binEta); - - double mean = calibMean->GetBinContent(binTPCncls, binPin, binEta); - double width = calibSigma->GetBinContent(binTPCncls, binPin, binEta); if (!isTPCCalibrated) { - values[kTPCnSigmaPi_Corr] = (values[kTPCnSigmaPi] - mean) / width; + values[kTPCnSigmaPi_Corr] = ComputePIDcalibration(1, values[kTPCnSigmaPi]); } else { + LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; values[kTPCnSigmaPi_Corr] = track.tpcNSigmaPi(); } } if (fgUsedVars[kTPCnSigmaKa_Corr] && fgRunTPCPostCalibration[2]) { - TH3F* calibMean = reinterpret_cast(fgCalibs[kTPCKaonMean]); - TH3F* calibSigma = reinterpret_cast(fgCalibs[kTPCKaonSigma]); - - int binTPCncls = calibMean->GetXaxis()->FindBin(values[kTPCncls]); - binTPCncls = (binTPCncls == 0 ? 1 : binTPCncls); - binTPCncls = (binTPCncls > calibMean->GetXaxis()->GetNbins() ? calibMean->GetXaxis()->GetNbins() : binTPCncls); - int binPin = calibMean->GetYaxis()->FindBin(values[kPin]); - binPin = (binPin == 0 ? 1 : binPin); - binPin = (binPin > calibMean->GetYaxis()->GetNbins() ? calibMean->GetYaxis()->GetNbins() : binPin); - int binEta = calibMean->GetZaxis()->FindBin(values[kEta]); - binEta = (binEta == 0 ? 1 : binEta); - binEta = (binEta > calibMean->GetZaxis()->GetNbins() ? calibMean->GetZaxis()->GetNbins() : binEta); - - double mean = calibMean->GetBinContent(binTPCncls, binPin, binEta); - double width = calibSigma->GetBinContent(binTPCncls, binPin, binEta); + // compute TPC postcalibrated kaon nsigma if required if (!isTPCCalibrated) { - values[kTPCnSigmaKa_Corr] = (values[kTPCnSigmaKa] - mean) / width; + values[kTPCnSigmaKa_Corr] = ComputePIDcalibration(2, values[kTPCnSigmaKa]); } else { + LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; values[kTPCnSigmaKa_Corr] = track.tpcNSigmaKa(); } } // compute TPC postcalibrated proton nsigma if required if (fgUsedVars[kTPCnSigmaPr_Corr] && fgRunTPCPostCalibration[3]) { - TH3F* calibMean = reinterpret_cast(fgCalibs[kTPCProtonMean]); - TH3F* calibSigma = reinterpret_cast(fgCalibs[kTPCProtonSigma]); - - int binTPCncls = calibMean->GetXaxis()->FindBin(values[kTPCncls]); - binTPCncls = (binTPCncls == 0 ? 1 : binTPCncls); - binTPCncls = (binTPCncls > calibMean->GetXaxis()->GetNbins() ? calibMean->GetXaxis()->GetNbins() : binTPCncls); - int binPin = calibMean->GetYaxis()->FindBin(values[kPin]); - binPin = (binPin == 0 ? 1 : binPin); - binPin = (binPin > calibMean->GetYaxis()->GetNbins() ? calibMean->GetYaxis()->GetNbins() : binPin); - int binEta = calibMean->GetZaxis()->FindBin(values[kEta]); - binEta = (binEta == 0 ? 1 : binEta); - binEta = (binEta > calibMean->GetZaxis()->GetNbins() ? calibMean->GetZaxis()->GetNbins() : binEta); - - double mean = calibMean->GetBinContent(binTPCncls, binPin, binEta); - double width = calibSigma->GetBinContent(binTPCncls, binPin, binEta); if (!isTPCCalibrated) { - values[kTPCnSigmaPr_Corr] = (values[kTPCnSigmaPr] - mean) / width; + values[kTPCnSigmaPr_Corr] = ComputePIDcalibration(3, values[kTPCnSigmaPr]); } else { + LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; values[kTPCnSigmaPr_Corr] = track.tpcNSigmaPr(); } } - values[kTOFnSigmaEl] = track.tofNSigmaEl(); - values[kTOFnSigmaPi] = track.tofNSigmaPi(); - values[kTOFnSigmaKa] = track.tofNSigmaKa(); - values[kTOFnSigmaPr] = track.tofNSigmaPr(); - - if (fgUsedVars[kTPCsignalRandomized] || fgUsedVars[kTPCnSigmaElRandomized] || fgUsedVars[kTPCnSigmaPiRandomized] || fgUsedVars[kTPCnSigmaPrRandomized]) { - // NOTE: this is needed temporarily for the study of the impact of TPC pid degradation on the quarkonium triggers in high lumi pp - // This study involves a degradation from a dE/dx resolution of 5% to one of 6% (20% worsening) - // For this we smear the dE/dx and n-sigmas using a gaus distribution with a width of 3.3% - // which is approx the needed amount to get dE/dx to a resolution of 6% - double randomX = gRandom->Gaus(0.0, 0.033); - values[kTPCsignalRandomized] = values[kTPCsignal] * (1.0 + randomX); - values[kTPCsignalRandomizedDelta] = values[kTPCsignal] * randomX; - values[kTPCnSigmaElRandomized] = values[kTPCnSigmaEl] * (1.0 + randomX); - values[kTPCnSigmaElRandomizedDelta] = values[kTPCnSigmaEl] * randomX; - values[kTPCnSigmaPiRandomized] = values[kTPCnSigmaPi] * (1.0 + randomX); - values[kTPCnSigmaPiRandomizedDelta] = values[kTPCnSigmaPi] * randomX; - values[kTPCnSigmaPrRandomized] = values[kTPCnSigmaPr] * (1.0 + randomX); - values[kTPCnSigmaPrRandomizedDelta] = values[kTPCnSigmaPr] * randomX; + + if constexpr ((fillMap & TrackPID) > 0 || (fillMap & ReducedTrackBarrelPID) > 0) { + values[kTOFnSigmaEl] = track.tofNSigmaEl(); + values[kTOFnSigmaPi] = track.tofNSigmaPi(); + values[kTOFnSigmaKa] = track.tofNSigmaKa(); + values[kTOFnSigmaPr] = track.tofNSigmaPr(); } if constexpr ((fillMap & ReducedTrackBarrelPID) > 0) { @@ -2105,7 +2663,7 @@ void VarManager::FillTrack(T const& track, float* values) } // Quantities based on the muon extra table - if constexpr ((fillMap & ReducedMuonExtra) > 0 || (fillMap & Muon) > 0) { + if constexpr ((fillMap & ReducedMuonExtra) > 0 || (fillMap & Muon) > 0 || (fillMap & MuonRealign) > 0) { values[kMuonNClusters] = track.nClusters(); values[kMuonPDca] = track.pDca(); values[kMCHBitMap] = track.mchBitMap(); @@ -2121,7 +2679,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(); @@ -2178,7 +2736,7 @@ void VarManager::FillTrackCollision(T const& track, C const& collision, float* v } } } - if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { + if constexpr ((fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0 || (fillMap & ReducedMuonCov) > 0) { o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(track, collision, kToDCA); @@ -2282,6 +2840,116 @@ void VarManager::FillTrackMC(const U& mcStack, T const& track, float* values) FillTrackDerived(values); } +template +void VarManager::FillTrackCollisionMC(T1 const& track, T2 const& MotherTrack, C const& collision, float* values) +{ + + if (!values) { + values = fgValues; + } + + float m = 0.0; + float pdgLifetime = 0.0; + if (std::abs(MotherTrack.pdgCode()) == 521) { + m = o2::constants::physics::MassBPlus; + pdgLifetime = 1.638e-12; // s + } + if (std::abs(MotherTrack.pdgCode()) == 511) { + m = o2::constants::physics::MassB0; + pdgLifetime = 1.517e-12; // s + } + + // displaced vertex is compued with decay product (track) and momentum of mother particle (MotherTrack) + values[kMCVertexingLxy] = (collision.mcPosX() - track.vx()) * (collision.mcPosX() - track.vx()) + + (collision.mcPosY() - track.vy()) * (collision.mcPosY() - track.vy()); + values[kMCVertexingLz] = (collision.mcPosZ() - track.vz()) * (collision.mcPosZ() - track.vz()); + values[kMCVertexingLxyz] = values[kMCVertexingLxy] + values[kMCVertexingLz]; + values[kMCVertexingLxy] = std::sqrt(values[kMCVertexingLxy]); + values[kMCVertexingLz] = std::sqrt(values[kMCVertexingLz]); + values[kMCVertexingLxyz] = std::sqrt(values[kMCVertexingLxyz]); + values[kMCVertexingTauz] = (collision.mcPosZ() - track.vz()) * m / (TMath::Abs(MotherTrack.pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kMCVertexingTauxy] = values[kMCVertexingLxy] * m / (MotherTrack.pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kMCCosPointingAngle] = ((collision.mcPosX() - track.vx()) * MotherTrack.px() + + (collision.mcPosY() - track.vy()) * MotherTrack.py() + + (collision.mcPosZ() - track.vz()) * MotherTrack.pz()) / + (MotherTrack.p() * values[VarManager::kMCVertexingLxyz]); + + values[kMCLxyExpected] = (MotherTrack.pt() / m) * (pdgLifetime * o2::constants::physics::LightSpeedCm2S); + values[kMCLxyzExpected] = (MotherTrack.p() / m) * (pdgLifetime * o2::constants::physics::LightSpeedCm2S); + + values[kMCVertexingLzProjected] = ((track.vz() - collision.mcPosZ()) * MotherTrack.pz()) / TMath::Abs(MotherTrack.pz()); + values[kMCVertexingLxyProjected] = (((track.vx() - collision.mcPosX()) * MotherTrack.px()) + ((track.vy() - collision.mcPosY()) * MotherTrack.py())) / TMath::Abs(MotherTrack.pt()); + values[kMCVertexingLxyzProjected] = (((track.vx() - collision.mcPosX()) * MotherTrack.px()) + ((track.vy() - collision.mcPosY()) * MotherTrack.py()) + ((track.vz() - collision.mcPosZ()) * MotherTrack.pz())) / MotherTrack.p(); + values[kMCVertexingTauxyProjected] = values[kMCVertexingLxyProjected] * m / (MotherTrack.pt()); + values[kMCVertexingTauzProjected] = values[kMCVertexingLzProjected] * m / TMath::Abs(MotherTrack.pz()); + values[kMCVertexingTauxyzProjected] = values[kMCVertexingLxyzProjected] * m / (MotherTrack.p()); +} + +template +void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* values) +{ + // energy correlators + float MassHadron; + if constexpr (pairType == kJpsiHadronMass) { + MassHadron = TMath::Sqrt(t1.e() * t1.e() - t1.p() * t1.p()); + } + if constexpr (pairType == kJpsiPionMass) { + MassHadron = o2::constants::physics::MassPionCharged; + } + ROOT::Math::PtEtaPhiMVector v1(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); + float deltaphi = RecoDecay::constrainAngle(track.phi() - t1.phi(), -o2::constants::math::PIHalf); + float deltaeta = t1.eta() - track.eta(); + ROOT::Math::PtEtaPhiMVector v2(t1.pt(), t1.eta(), t1.phi(), MassHadron); + float E_boost = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2); + float CosChi = LorentzTransformJpsihadroncosChi("coschi", v1, v2); + float CosTheta = LorentzTransformJpsihadroncosChi("costheta", v1, v2); + values[kMCCosChi] = CosChi; + values[kMCWeight_before] = t1.pt() / o2::constants::physics::MassJPsi; + values[kMCCosTheta] = CosTheta; + values[kMCdeltaphi] = deltaphi; + values[kMCdeltaeta] = deltaeta; + values[kMCHadronPt] = t1.pt(); + values[kMCHadronEta] = t1.eta(); + values[kMCHadronPhi] = RecoDecay::constrainAngle(t1.phi(), -o2::constants::math::PIHalf); + values[kMCHadronPdgCode] = t1.pdgCode(); + values[kMCWeight] = E_boost / o2::constants::physics::MassJPsi; + + values[kMCCosChi_randomPhi_trans] = -999.9f; + values[kMCCosChi_randomPhi_toward] = -999.9f; + values[kMCCosChi_randomPhi_away] = -999.9f; + + values[kMCdeltaphi_randomPhi_trans] = -999.9f; + values[kMCdeltaphi_randomPhi_toward] = -999.9f; + values[kMCdeltaphi_randomPhi_away] = -999.9f; + + float randomPhi_trans = -o2::constants::math::PIHalf; + float randomPhi_toward = -o2::constants::math::PIHalf; + float randomPhi_away = -o2::constants::math::PIHalf; + + if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { + randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); + values[kMCWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); + values[kMCWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); + values[kMCWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); + + values[kMCdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); + } +} + template void VarManager::FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values) { @@ -2329,12 +2997,18 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) 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; @@ -2348,6 +3022,13 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) double Ptot2 = TMath::Sqrt(v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz()); values[kDeltaPtotTracks] = Ptot1 - Ptot2; + values[kPt1] = t1.pt(); + values[kEta1] = t1.eta(); + values[kPhi1] = t1.phi(); + values[kPt2] = t2.pt(); + values[kEta2] = t2.eta(); + values[kPhi2] = t2.phi(); + if (fgUsedVars[kDeltaPhiPair2]) { double phipair2 = v1.Phi() - v2.Phi(); if (phipair2 > 3 * TMath::Pi() / 2) { @@ -2359,6 +3040,10 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) } } + 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()); @@ -2380,42 +3065,123 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) } } - // TO DO: get the correct values from CCDB - double BeamMomentum = TMath::Sqrt(fgCenterOfMassEnergy * fgCenterOfMassEnergy / 4 - fgMassofCollidingParticle * fgMassofCollidingParticle); // GeV - ROOT::Math::PxPyPzEVector Beam1(0., 0., -BeamMomentum, fgCenterOfMassEnergy / 2); - ROOT::Math::PxPyPzEVector Beam2(0., 0., BeamMomentum, fgCenterOfMassEnergy / 2); - - // Boost to center of mass frame - 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()}; - - // Helicity frame - ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; - ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; - ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; + // polarization parameters + bool useHE = fgUsedVars[kCosThetaHE] || fgUsedVars[kPhiHE]; // helicity frame + bool useCS = fgUsedVars[kCosThetaCS] || fgUsedVars[kPhiCS]; // Collins-Soper frame + bool usePP = fgUsedVars[kCosThetaPP]; // production plane frame + bool useRM = fgUsedVars[kCosThetaRM]; // Random frame + + if (useHE || useCS || usePP || useRM) { + 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(fgBeamA).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; + + // using positive sign convention for the first track + ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); + + if (useHE) { + ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; + ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; + if (fgUsedVars[kCosThetaHE]) + values[kCosThetaHE] = zaxis_HE.Dot(v_CM); + if (fgUsedVars[kPhiHE]) { + values[kPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); + if (values[kPhiHE] < 0) { + values[kPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildeHE]) { + if (fgUsedVars[kCosThetaHE] && fgUsedVars[kPhiHE]) { + if (values[kCosThetaHE] > 0) { + values[kPhiTildeHE] = values[kPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildeHE] < 0) { + values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildeHE] = values[kPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildeHE] < 0) { + values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildeHE] = -999; // not computable + } + } + } - // 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()}; - - if (fgUsedVars[kCosThetaHE]) { - values[kCosThetaHE] = (t1.sign() > 0 ? zaxis_HE.Dot(v1_CM) : zaxis_HE.Dot(v2_CM)); - } - - if (fgUsedVars[kPhiHE]) { - values[kPhiHE] = (t1.sign() > 0 ? TMath::ATan2(yaxis_HE.Dot(v1_CM), xaxis_HE.Dot(v1_CM)) : TMath::ATan2(yaxis_HE.Dot(v2_CM), xaxis_HE.Dot(v2_CM))); - } + if (useCS) { + ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; + ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; + if (fgUsedVars[kCosThetaCS]) + values[kCosThetaCS] = zaxis_CS.Dot(v_CM); + if (fgUsedVars[kPhiCS]) { + values[kPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); + if (values[kPhiCS] < 0) { + values[kPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildeCS]) { + if (fgUsedVars[kCosThetaCS] && fgUsedVars[kPhiCS]) { + if (values[kCosThetaCS] > 0) { + values[kPhiTildeCS] = values[kPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildeCS] < 0) { + values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildeCS] = values[kPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildeCS] < 0) { + values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildeCS] = -999; // not computable + } + } + } - if (fgUsedVars[kCosThetaCS]) { - values[kCosThetaCS] = (t1.sign() > 0 ? zaxis_CS.Dot(v1_CM) : zaxis_CS.Dot(v2_CM)); - } + if (usePP) { + ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); + ROOT::Math::XYZVector yaxis_PP{(v12.Vect()).Unit()}; + ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; + if (fgUsedVars[kCosThetaPP]) { + values[kCosThetaPP] = zaxis_PP.Dot(v_CM) / std::sqrt(zaxis_PP.Mag2()); + } + if (fgUsedVars[kPhiPP]) { + values[kPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); + if (values[kPhiPP] < 0) { + values[kPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildePP]) { + if (fgUsedVars[kCosThetaPP] && fgUsedVars[kPhiPP]) { + if (values[kCosThetaPP] > 0) { + values[kPhiTildePP] = values[kPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildePP] < 0) { + values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildePP] = values[kPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildePP] < 0) { + values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildePP] = -999; // not computable + } + } + } - if (fgUsedVars[kPhiCS]) { - values[kPhiCS] = (t1.sign() > 0 ? TMath::ATan2(yaxis_CS.Dot(v1_CM), xaxis_CS.Dot(v1_CM)) : TMath::ATan2(yaxis_CS.Dot(v2_CM), xaxis_CS.Dot(v2_CM))); + if (useRM) { + double randomCostheta = gRandom->Uniform(-1., 1.); + double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); + ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); + if (fgUsedVars[kCosThetaRM]) + values[kCosThetaRM] = zaxis_RM.Dot(v_CM); + } } if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { @@ -2468,6 +3234,116 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) } } +template +void VarManager::FillPairCollision(const C& collision, T1 const& t1, T2 const& t2, float* values) +{ + if (!values) { + values = fgValues; + } + + 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); + + 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::FillPairCollisionMatCorr(C const& collision, T1 const& t1, T2 const& t2, M const& materialCorr, P const& propagator, float* values) +{ + if (!values) { + values = fgValues; + } + + 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) { @@ -2517,6 +3393,10 @@ void VarManager::FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* val values[kEta] = v123.Eta(); values[kPhi] = v123.Phi(); values[kRap] = -v123.Rapidity(); + values[kCharge] = t1.sign() + t2.sign() + t3.sign(); + values[kS12] = (v1 + v2).M2(); + values[kS13] = (v1 + v3).M2(); + values[kS23] = (v2 + v3).M2(); } if (pairType == kTripleCandidateToPKPi) { @@ -2536,7 +3416,7 @@ void VarManager::FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* val } } -template +template void VarManager::FillPairME(T1 const& t1, T2 const& t2, float* values) { // @@ -2572,13 +3452,194 @@ void VarManager::FillPairME(T1 const& t1, T2 const& t2, float* values) 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(); + } + + // polarization parameters + bool useHE = fgUsedVars[kCosThetaHE] || fgUsedVars[kPhiHE]; // helicity frame + bool useCS = fgUsedVars[kCosThetaCS] || fgUsedVars[kPhiCS]; // Collins-Soper frame + bool usePP = fgUsedVars[kCosThetaPP]; // production plane frame + bool useRM = fgUsedVars[kCosThetaRM]; // Random frame + if (useHE || useCS || usePP || useRM) { + 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(fgBeamA).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; + + // using positive sign convention for the first track + ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); + + if (useHE) { + ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; + ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; + if (fgUsedVars[kCosThetaHE]) + values[kCosThetaHE] = zaxis_HE.Dot(v_CM); + if (fgUsedVars[kPhiHE]) { + values[kPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); + if (values[kPhiHE] < 0) { + values[kPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildeHE]) { + if (fgUsedVars[kCosThetaHE] && fgUsedVars[kPhiHE]) { + if (values[kCosThetaHE] > 0) { + values[kPhiTildeHE] = values[kPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildeHE] < 0) { + values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildeHE] = values[kPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildeHE] < 0) { + values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildeHE] = -999; // not computable + } + } + } + + if (useCS) { + ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; + ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; + if (fgUsedVars[kCosThetaCS]) + values[kCosThetaCS] = zaxis_CS.Dot(v_CM); + if (fgUsedVars[kPhiCS]) { + values[kPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); + if (values[kPhiCS] < 0) { + values[kPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildeCS]) { + if (fgUsedVars[kCosThetaCS] && fgUsedVars[kPhiCS]) { + if (values[kCosThetaCS] > 0) { + values[kPhiTildeCS] = values[kPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildeCS] < 0) { + values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildeCS] = values[kPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildeCS] < 0) { + values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildeCS] = -999; // not computable + } + } + } + + if (usePP) { + ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); + ROOT::Math::XYZVector yaxis_PP{(v12.Vect()).Unit()}; + ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; + if (fgUsedVars[kCosThetaPP]) { + values[kCosThetaPP] = zaxis_PP.Dot(v_CM) / std::sqrt(zaxis_PP.Mag2()); + } + if (fgUsedVars[kPhiPP]) { + values[kPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); + if (values[kPhiPP] < 0) { + values[kPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildePP]) { + if (fgUsedVars[kCosThetaPP] && fgUsedVars[kPhiPP]) { + if (values[kCosThetaPP] > 0) { + values[kPhiTildePP] = values[kPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildePP] < 0) { + values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildePP] = values[kPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildePP] < 0) { + values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildePP] = -999; // not computable + } + } + } + + if (useRM) { + double randomCostheta = gRandom->Uniform(-1., 1.); + double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); + ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); + if (fgUsedVars[kCosThetaRM]) + values[kCosThetaRM] = zaxis_RM.Dot(v_CM); + } + } + + 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(); @@ -2595,8 +3656,8 @@ void VarManager::FillPairME(T1 const& t1, T2 const& t2, float* values) } } -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; @@ -2614,6 +3675,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; } @@ -2622,21 +3688,140 @@ 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(); + + // polarization parameters + bool useHE = fgUsedVars[kMCCosThetaHE] || fgUsedVars[kMCPhiHE]; // helicity frame + bool useCS = fgUsedVars[kMCCosThetaCS] || fgUsedVars[kMCPhiCS]; // Collins-Soper frame + bool usePP = fgUsedVars[kMCCosThetaPP]; // production plane frame + bool useRM = fgUsedVars[kMCCosThetaRM]; // Random frame + + if (useHE || useCS || usePP || useRM) { + 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(fgBeamA).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; + + // using positive sign convention for the first track + ROOT::Math::XYZVectorF v_CM = (t1.pdgCode() > 0 ? v1_CM : v2_CM); + + if (useHE) { + ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; + ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; + if (fgUsedVars[kMCCosThetaHE]) + values[kMCCosThetaHE] = zaxis_HE.Dot(v_CM); + if (fgUsedVars[kMCPhiHE]) { + values[kMCPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); + if (values[kMCPhiHE] < 0) { + values[kMCPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kMCPhiTildeHE]) { + if (fgUsedVars[kMCCosThetaHE] && fgUsedVars[kMCPhiHE]) { + if (values[kMCCosThetaHE] > 0) { + values[kMCPhiTildeHE] = values[kMCPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kMCPhiTildeHE] < 0) { + values[kMCPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kMCPhiTildeHE] = values[kMCPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kMCPhiTildeHE] < 0) { + values[kMCPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kMCPhiTildeHE] = -999; // not computable + } + } + } + + if (useCS) { + ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; + ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; + if (fgUsedVars[kMCCosThetaCS]) + values[kMCCosThetaCS] = zaxis_CS.Dot(v_CM); + if (fgUsedVars[kMCPhiCS]) { + values[kMCPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); + if (values[kMCPhiCS] < 0) { + values[kMCPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kMCPhiTildeCS]) { + if (fgUsedVars[kMCCosThetaCS] && fgUsedVars[kMCPhiCS]) { + if (values[kMCCosThetaCS] > 0) { + values[kMCPhiTildeCS] = values[kMCPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kMCPhiTildeCS] < 0) { + values[kMCPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kMCPhiTildeCS] = values[kMCPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kMCPhiTildeCS] < 0) { + values[kMCPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kMCPhiTildeCS] = -999; // not computable + } + } + } + + if (usePP) { + ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); + ROOT::Math::XYZVector yaxis_PP{v12.Vect().Unit()}; + ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; + if (fgUsedVars[kMCCosThetaPP]) { + values[kMCCosThetaPP] = zaxis_PP.Dot(v_CM); + } + if (fgUsedVars[kMCPhiPP]) { + values[kMCPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); + if (values[kMCPhiPP] < 0) { + values[kMCPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kMCPhiTildePP]) { + if (fgUsedVars[kMCCosThetaPP] && fgUsedVars[kMCPhiPP]) { + if (values[kMCCosThetaPP] > 0) { + values[kMCPhiTildePP] = values[kMCPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kMCPhiTildePP] < 0) { + values[kMCPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kMCPhiTildePP] = values[kMCPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kMCPhiTildePP] < 0) { + values[kMCPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kMCPhiTildePP] = -999; // not computable + } + } + } + + if (useRM) { + double randomCostheta = gRandom->Uniform(-1., 1.); + double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); + ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); + if (fgUsedVars[kMCCosThetaRM]) + values[kMCCosThetaRM] = zaxis_RM.Dot(v_CM); + } + } } -template -void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values, PairCandidateType pairType) +template +void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values) { if (!values) { values = fgValues; } - if (pairType == kTripleCandidateToEEPhoton) { + if constexpr (candidateType == kTripleCandidateToEEPhoton) { float m1 = o2::constants::physics::MassElectron; float m2 = o2::constants::physics::MassElectron; float m3 = o2::constants::physics::MassPhoton; @@ -2664,6 +3849,54 @@ void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* v values[kPt1] = t1.pt(); values[kPt2] = t2.pt(); } + + if constexpr (candidateType == 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(); + values[kS12] = (v1 + v2).M2(); + values[kS13] = (v1 + v3).M2(); + values[kS23] = (v2 + v3).M2(); + } + if constexpr (candidateType == kBtoJpsiEEK) { + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + float m3 = o2::constants::physics::MassKaonCharged; + 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(), m2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v123 = v12 + v3; + values[kPairMass] = v123.M(); + values[kPairPt] = v123.Pt(); + values[kPairEta] = v123.Eta(); + values[kPhi] = v123.Phi(); + values[kMCY] = -v123.Rapidity(); + values[kPairMassDau] = v12.M(); + values[kPairPtDau] = v12.Pt(); + values[kRap] = -v123.Rapidity(); + values[kMassDau] = m3; + values[VarManager::kDeltaMass] = v123.M() - v12.M(); + values[VarManager::kDeltaMass_jpsi] = v123.M() - v12.M() + m4; + values[kPt] = t3.pt(); + values[kEta] = t3.eta(); + values[kEta1] = t1.eta(); + values[kEta2] = t2.eta(); + values[kDeltaEta] = v12.Eta(); + values[kPt1] = t1.pt(); + values[kPt2] = t2.pt(); + } } template @@ -2713,20 +3946,8 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, procCode = fgFitterTwoProngBarrel.process(pars1, pars2); } else if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { // Initialize track parameters for forward - double chi21 = t1.chi2(); - double chi22 = t2.chi2(); - 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 pars1{t1.z(), t1pars, t1covs, chi21}; - 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 pars2{t2.z(), t2pars, t2covs, chi22}; + o2::track::TrackParCovFwd pars1 = FwdToTrackPar(t1, t1); + o2::track::TrackParCovFwd pars2 = FwdToTrackPar(t2, t2); procCode = fgFitterTwoProngFwd.process(pars1, pars2); } else { return; @@ -2756,7 +3977,7 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, if constexpr (eventHasVtxCov) { - std::array covMatrixPCA; + std::array covMatrixPCA{}; // get track impact parameters // This modifies track momenta! o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); @@ -2833,6 +4054,7 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, 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.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() / TMath::Abs(v12.Pz()); values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v12.M() / (v12.P()); @@ -2921,6 +4143,7 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, 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.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() / TMath::Abs(KFGeoTwoProng.GetPz()); } @@ -2986,20 +4209,8 @@ void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, } if (propToSV) { if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { - double chi21 = t1.chi2(); - double chi22 = t2.chi2(); - SMatrix5 t1pars(t1.x(), t1.y(), t1.phi(), t1.tgl(), t1.signed1Pt()); - std::vector c1{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(c1.begin(), c1.end()); - o2::track::TrackParCovFwd pars1{t1.z(), t1pars, t1covs, chi21}; - SMatrix5 t2pars(t2.x(), t2.y(), t2.phi(), t2.tgl(), t2.signed1Pt()); - std::vector c2{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(c2.begin(), c2.end()); - o2::track::TrackParCovFwd pars2{t2.z(), t2pars, t2covs, chi22}; + o2::track::TrackParCovFwd pars1 = FwdToTrackPar(t1, t1); + o2::track::TrackParCovFwd pars2 = FwdToTrackPar(t2, t2); auto geoMan1 = o2::base::GeometryManager::meanMaterialBudget(t1.x(), t1.y(), t1.z(), KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY(), KFGeoTwoProng.GetZ()); auto geoMan2 = o2::base::GeometryManager::meanMaterialBudget(t2.x(), t2.y(), t2.z(), KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY(), KFGeoTwoProng.GetZ()); @@ -3118,6 +4329,7 @@ void VarManager::FillTripletVertexing(C const& collision, T const& t1, T const& values[VarManager::kVertexingProcCode] = procCode; if (procCode == 0) { // TODO: set the other variables to appropriate values and return + values[kVertexingChi2PCA] = -999.; values[kVertexingLxy] = -999.; values[kVertexingLxyz] = -999.; values[kVertexingLz] = -999.; @@ -3152,6 +4364,11 @@ void VarManager::FillTripletVertexing(C const& collision, T const& t1, T const& o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; auto covMatrixPV = primaryVertex.getCov(); + if (fgUsedVars[kVertexingChi2PCA]) { + auto chi2PCA = fgFitterThreeProngBarrel.getChi2AtPCACandidate(); + values[VarManager::kVertexingChi2PCA] = chi2PCA; + } + 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()) + @@ -3175,6 +4392,10 @@ void VarManager::FillTripletVertexing(C const& collision, T const& t1, T const& 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()); @@ -3298,29 +4519,10 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton mlepton2 = o2::constants::physics::MassMuon; mtrack = o2::constants::physics::MassMuon; - double chi21 = lepton1.chi2(); - double chi22 = lepton2.chi2(); - double chi23 = track.chi2(); - SMatrix5 t1pars(lepton1.x(), lepton1.y(), lepton1.phi(), lepton1.tgl(), lepton1.signed1Pt()); - std::vector v1{lepton1.cXX(), lepton1.cXY(), lepton1.cYY(), lepton1.cPhiX(), lepton1.cPhiY(), - lepton1.cPhiPhi(), lepton1.cTglX(), lepton1.cTglY(), lepton1.cTglPhi(), lepton1.cTglTgl(), - lepton1.c1PtX(), lepton1.c1PtY(), lepton1.c1PtPhi(), lepton1.c1PtTgl(), lepton1.c1Pt21Pt2()}; - SMatrix55 t1covs(v1.begin(), v1.end()); - o2::track::TrackParCovFwd pars1{lepton1.z(), t1pars, t1covs, chi21}; - - SMatrix5 t2pars(lepton2.x(), lepton2.y(), lepton2.phi(), lepton2.tgl(), lepton2.signed1Pt()); - std::vector v2{lepton2.cXX(), lepton2.cXY(), lepton2.cYY(), lepton2.cPhiX(), lepton2.cPhiY(), - lepton2.cPhiPhi(), lepton2.cTglX(), lepton2.cTglY(), lepton2.cTglPhi(), lepton2.cTglTgl(), - lepton2.c1PtX(), lepton2.c1PtY(), lepton2.c1PtPhi(), lepton2.c1PtTgl(), lepton2.c1Pt21Pt2()}; - SMatrix55 t2covs(v2.begin(), v2.end()); - o2::track::TrackParCovFwd pars2{lepton2.z(), t2pars, t2covs, chi22}; - - SMatrix5 t3pars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); - std::vector v3{track.cXX(), track.cXY(), track.cYY(), track.cPhiX(), track.cPhiY(), - track.cPhiPhi(), track.cTglX(), track.cTglY(), track.cTglPhi(), track.cTglTgl(), - track.c1PtX(), track.c1PtY(), track.c1PtPhi(), track.c1PtTgl(), track.c1Pt21Pt2()}; - SMatrix55 t3covs(v3.begin(), v3.end()); - o2::track::TrackParCovFwd pars3{track.z(), t3pars, t3covs, chi23}; + o2::track::TrackParCovFwd pars1 = FwdToTrackPar(lepton1, lepton1); + o2::track::TrackParCovFwd pars2 = FwdToTrackPar(lepton2, lepton2); + o2::track::TrackParCovFwd pars3 = FwdToTrackPar(track, track); + procCode = VarManager::fgFitterThreeProngFwd.process(pars1, pars2, pars3); procCodeJpsi = VarManager::fgFitterTwoProngFwd.process(pars1, pars2); } else if constexpr ((candidateType == kBtoJpsiEEK || candidateType == kDstarToD0KPiPi) && trackHasCov) { @@ -3364,12 +4566,16 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton values[VarManager::kMassDau] = mtrack; values[VarManager::kDeltaMass] = v123.M() - v12.M(); values[VarManager::kPairPt] = v123.Pt(); + values[VarManager::kPairRap] = -v123.Rapidity(); values[VarManager::kPairEta] = v123.Eta(); if (fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau]) { values[VarManager::kPairMassDau] = v12.M(); values[VarManager::kPairPtDau] = v12.Pt(); } values[VarManager::kPt] = track.pt(); + values[kS12] = (v1 + v2).M2(); + values[kS13] = (v1 + v3).M2(); + values[kS23] = (v2 + v3).M2(); values[VarManager::kVertexingProcCode] = procCode; if (procCode == 0 || procCodeJpsi == 0) { @@ -3411,9 +4617,10 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton covMatrixPCA = fgFitterThreeProngFwd.calcPCACovMatrixFlat(); } - auto chi2PCA = fgFitterThreeProngBarrel.getChi2AtPCACandidate(); - if (fgUsedVars[kVertexingChi2PCA]) + if (fgUsedVars[kVertexingChi2PCA]) { + auto chi2PCA = fgFitterThreeProngBarrel.getChi2AtPCACandidate(); values[VarManager::kVertexingChi2PCA] = chi2PCA; + } double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); double theta = std::atan2(secondaryVertex[2] - collision.posZ(), @@ -3423,10 +4630,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]); } @@ -3545,9 +4752,9 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; 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 @@ -3615,7 +4822,22 @@ 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 @@ -3647,21 +4869,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; @@ -3670,9 +4892,9 @@ 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 @@ -3723,17 +4945,17 @@ void VarManager::FillQVectorFromCentralFW(C const& collision, float* values) float epBNegs = epHelper.GetEventPlane(xQVecBNeg, yQVecBNeg, 2); float epTPCFull = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); - values[kR2EP_AB] = std::cos(2 * getDeltaPsiInRange(epTPCFull, epFT0a, 2)); - values[kR2EP_AC] = std::cos(2 * getDeltaPsiInRange(epTPCFull, epFT0c, 2)); - values[kR2EP_BC] = std::cos(2 * getDeltaPsiInRange(epFT0a, epFT0c, 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)); + 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 @@ -3871,12 +5093,14 @@ 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[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]); @@ -3888,15 +5112,19 @@ void VarManager::FillPairVn(T1 const& t1, T2 const& t2, float* values) 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[kCos2DeltaPhi] = std::cos(2 * (v12.Phi() - Psi2A)); - values[kCos3DeltaPhi] = std::cos(3 * (v12.Phi() - Psi3A)); + 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)); - values[kCos2DeltaPhiMu1] = std::cos(2 * (v1.Phi() - v12.Phi())); - values[kCos2DeltaPhiMu2] = std::cos(2 * (v2.Phi() - v12.Phi())); + 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.; @@ -3919,25 +5147,93 @@ void VarManager::FillPairVn(T1 const& t1, T2 const& t2, float* values) values[kR3EP] = -999.; } + // global polarization parameters + bool useGlobalPolarizatiobSpinOne = fgUsedVars[kCosThetaStarTPC] || fgUsedVars[kCosThetaStarFT0A] || fgUsedVars[kCosThetaStarFT0C]; + if (useGlobalPolarizatiobSpinOne) { + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; + + // using positive sign convention for the first track + ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); + + ROOT::Math::XYZVector zaxisTPC = ROOT::Math::XYZVector(TMath::Cos(Psi2A), TMath::Sin(Psi2A), 0).Unit(); + values[kCosThetaStarTPC] = v_CM.Dot(zaxisTPC); + + ROOT::Math::XYZVector zaxisFT0A = ROOT::Math::XYZVector(TMath::Cos(Psi2B), TMath::Sin(Psi2B), 0).Unit(); + values[kCosThetaStarFT0A] = v_CM.Dot(zaxisFT0A); + + ROOT::Math::XYZVector zaxisFT0C = ROOT::Math::XYZVector(TMath::Cos(Psi2C), TMath::Sin(Psi2C), 0).Unit(); + values[kCosThetaStarFT0C] = v_CM.Dot(zaxisFT0C); + } + // kV4, kC4POI, kC4REF etc. 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(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[kM01POIoverMp] = values[kMultDimuons] > 0 && !(isnan(values[kM01POI]) || isinf(values[kM01POI])) ? values[kM01POI] / values[kMultDimuons] : 0; - values[kM0111POIoverMp] = values[kMultDimuons] > 0 && !(isnan(values[kM0111POI]) || isinf(values[kM0111POI])) ? values[kM0111POI] / values[kMultDimuons] : 0; - values[kM11REFoverMp] = values[kMultDimuons] > 0 && !(isnan(values[kM11REF]) || isinf(values[kM11REF])) ? values[kM11REF] / values[kMultDimuons] : 0; - values[kM1111REFoverMp] = values[kMultDimuons] > 0 && !(isnan(values[kM1111REF]) || isinf(values[kM1111REF])) ? values[kM1111REF] / values[kMultDimuons] : 0; - values[kCORR2POIMp] = isnan(values[kCORR2POI]) || isinf(values[kCORR2POI]) ? 0 : values[kCORR2POI] * values[kMultDimuons]; - values[kCORR4POIMp] = isnan(values[kCORR4POI]) || isinf(values[kCORR4POI]) ? 0 : values[kCORR4POI] * values[kMultDimuons]; - values[kCORR2REF] = isnan(values[kCORR2REF]) || isinf(values[kCORR2REF]) ? 0 : values[kCORR2REF]; - values[kCORR4REF] = isnan(values[kCORR4REF]) || isinf(values[kCORR4REF]) ? 0 : values[kCORR4REF]; - } + 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 @@ -3964,7 +5260,7 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = fgValues; } - if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi] || fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau]) { + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi] || fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau] || fgUsedVars[kDileptonHadronKstar]) { ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); ROOT::Math::PtEtaPhiMVector v2(hadron.pt(), hadron.eta(), hadron.phi(), hadronMass); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; @@ -3976,7 +5272,60 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values[kPairPtDau] = dilepton.pt(); values[kMassDau] = hadronMass; values[kDeltaMass] = v12.M() - dilepton.mass(); + // Calculate kstar of Dilepton and hadron pair + ROOT::Math::PtEtaPhiMVector v12_Qvect = v1 - v2; + double Pinv = v12.M(); + double Q1 = (dilepton.mass() * dilepton.mass() - hadronMass * hadronMass) / Pinv; + values[kDileptonHadronKstar] = sqrt(Q1 * Q1 - v12_Qvect.M2()) / 2.0; + } + if (fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kEtaDau] || fgUsedVars[kPhiDau] || fgUsedVars[kCosChi_randomPhi_trans] || fgUsedVars[kCosChi_randomPhi_toward] || fgUsedVars[kCosChi_randomPhi_away]) { + ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); + ROOT::Math::PtEtaPhiMVector v2(hadron.pt(), hadron.eta(), hadron.phi(), o2::constants::physics::MassPionCharged); + values[kCosChi] = LorentzTransformJpsihadroncosChi("coschi", v1, v2); + float E_boost = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2); + values[kECWeight] = E_boost / v1.M(); + values[kCosTheta] = LorentzTransformJpsihadroncosChi("costheta", v1, v2); + values[kEWeight_before] = v2.Pt() / v1.M(); + values[kPtDau] = v2.pt(); + values[kEtaDau] = v2.eta(); + values[kPhiDau] = RecoDecay::constrainAngle(v2.phi(), -o2::constants::math::PIHalf); + + float deltaphi = RecoDecay::constrainAngle(v1.phi() - v2.phi(), -o2::constants::math::PIHalf); + values[kCosChi_randomPhi_trans] = -999.9f; + values[kCosChi_randomPhi_toward] = -999.9f; + values[kCosChi_randomPhi_away] = -999.9f; + + values[kdeltaphi_randomPhi_trans] = -999.9f; + values[kdeltaphi_randomPhi_toward] = -999.9f; + values[kdeltaphi_randomPhi_away] = -999.9f; + + float randomPhi_trans = -o2::constants::math::PIHalf; + float randomPhi_toward = -o2::constants::math::PIHalf; + float randomPhi_away = -o2::constants::math::PIHalf; + + if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { + randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); + values[kWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); + values[kWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); + values[kWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); + + values[kdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); + values[kdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); + values[kdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); + } } + if (fgUsedVars[kDeltaPhi]) { double delta = dilepton.phi() - hadron.phi(); if (delta > 3.0 / 2.0 * M_PI) { @@ -4108,9 +5457,13 @@ void VarManager::FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T values[kQuadEta] = v123.Eta(); values[kQuadPhi] = v123.Phi(); - values[kTrackDCAxy] = hadron1.dcaXY(); - values[kTrackDCAz] = hadron1.dcaZ(); - values[kPt] = hadron1.pt(); + 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; @@ -4120,12 +5473,308 @@ void VarManager::FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T 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] = sqrt(pow(v1.Eta() - v2.Eta(), 2) + pow(v1.Phi() - v2.Phi(), 2)); - values[kDeltaR2] = sqrt(pow(v1.Eta() - v3.Eta(), 2) + pow(v1.Phi() - v3.Phi(), 2)); + 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::FillDileptonTrackTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track1, T1 const& track2, float* values) +{ + constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); + constexpr bool trackHasCov = ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0); + + if (!eventHasVtxCov || !trackHasCov) { + return; + } + + if (!values) { + values = fgValues; + } + + float mtrack1, mtrack2; + float mlepton1, mlepton2; + + if constexpr (candidateType == kXtoJpsiPiPi || candidateType == kPsi2StoJpsiPiPi) { + mlepton1 = o2::constants::physics::MassElectron; + mlepton2 = o2::constants::physics::MassElectron; + mtrack1 = o2::constants::physics::MassPionCharged; + mtrack2 = o2::constants::physics::MassPionCharged; + } + + 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(track1.pt(), track1.eta(), track1.phi(), mtrack1); + ROOT::Math::PtEtaPhiMVector v4(track2.pt(), track2.eta(), track2.phi(), mtrack2); + ROOT::Math::PtEtaPhiMVector v1234 = v1 + v2 + v3 + v4; + + int procCodeDilepton = 0; + int procCodeDileptonTrackTrack = 0; + + values[kUsedKF] = fgUsedKF; + if (!fgUsedKF) { + // create covariance matrix + 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(), + lepton1.c1PtY(), lepton1.c1PtZ(), lepton1.c1PtSnp(), lepton1.c1PtTgl(), lepton1.c1Pt21Pt2()}; + o2::track::TrackParCov pars1{lepton1.x(), lepton1.alpha(), lepton1pars, lepton1covs}; + std::array lepton2pars = {lepton2.y(), lepton2.z(), lepton2.snp(), lepton2.tgl(), lepton2.signed1Pt()}; + std::array lepton2covs = {lepton2.cYY(), lepton2.cZY(), lepton2.cZZ(), lepton2.cSnpY(), lepton2.cSnpZ(), + lepton2.cSnpSnp(), lepton2.cTglY(), lepton2.cTglZ(), lepton2.cTglSnp(), lepton2.cTglTgl(), + lepton2.c1PtY(), lepton2.c1PtZ(), lepton2.c1PtSnp(), lepton2.c1PtTgl(), lepton2.c1Pt21Pt2()}; + o2::track::TrackParCov pars2{lepton2.x(), lepton2.alpha(), lepton2pars, lepton2covs}; + std::array track1pars = {track1.y(), track1.z(), track1.snp(), track1.tgl(), track1.signed1Pt()}; + std::array track1covs = {track1.cYY(), track1.cZY(), track1.cZZ(), track1.cSnpY(), track1.cSnpZ(), + track1.cSnpSnp(), track1.cTglY(), track1.cTglZ(), track1.cTglSnp(), track1.cTglTgl(), + track1.c1PtY(), track1.c1PtZ(), track1.c1PtSnp(), track1.c1PtTgl(), track1.c1Pt21Pt2()}; + o2::track::TrackParCov pars3{track1.x(), track1.alpha(), track1pars, track1covs}; + std::array track2pars = {track2.y(), track2.z(), track2.snp(), track2.tgl(), track2.signed1Pt()}; + std::array track2covs = {track2.cYY(), track2.cZY(), track2.cZZ(), track2.cSnpY(), track2.cSnpZ(), + track2.cSnpSnp(), track2.cTglY(), track2.cTglZ(), track2.cTglSnp(), track2.cTglTgl(), + track2.c1PtY(), track2.c1PtZ(), track2.c1PtSnp(), track2.c1PtTgl(), track2.c1Pt21Pt2()}; + o2::track::TrackParCov pars4{track2.x(), track2.alpha(), track2pars, track2covs}; + + procCodeDilepton = VarManager::fgFitterTwoProngBarrel.process(pars1, pars2); + // create dilepton track + // o2::track::TrackParCov parsDilepton = VarManager::fgFitterTwoProngBarrel.createParentTrackParCov(0); + // procCodeDileptonTrackTrack = VarManager::fgFitterThreeProngBarrel.process(parsDilepton, pars3, pars4); + procCodeDileptonTrackTrack = VarManager::fgFitterFourProngBarrel.process(pars1, pars2, pars3, pars4); + + // fill values + if (procCodeDilepton == 0 && procCodeDileptonTrackTrack == 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[kVertexingTauxyErr] = -999.; + values[kVertexingTauz] = -999.; + values[kVertexingTauzErr] = -999.; + values[kVertexingLzProjected] = -999.; + values[kVertexingLxyProjected] = -999.; + values[kVertexingLxyzProjected] = -999.; + values[kVertexingTauzProjected] = -999.; + values[kVertexingTauxyProjected] = -999.; + values[kVertexingTauxyzProjected] = -999.; + return; + } else { + Vec3D secondaryVertex; + std::array covMatrixPCA; + secondaryVertex = fgFitterFourProngBarrel.getPCACandidate(); + covMatrixPCA = fgFitterFourProngBarrel.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]) * v1234.M() / (TMath::Abs(v1234.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v1234.M() / (v1234.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kVertexingTauzErr] = values[kVertexingLzErr] * v1234.M() / (TMath::Abs(v1234.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v1234.M() / (v1234.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v1234.Px() + + (collision.posY() - secondaryVertex[1]) * v1234.Py() + + (collision.posZ() - secondaryVertex[2]) * v1234.Pz()) / + (v1234.P() * values[VarManager::kVertexingLxyz]); + // // run 2 definitions: Decay length projected onto the momentum vector of the candidate + values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v1234.Pz(); + values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v1234.Pz() * v1234.Pz()); + values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v1234.Px()) + ((secondaryVertex[1] - collision.posY()) * v1234.Py()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v1234.Px() * v1234.Px()) + (v1234.Py() * v1234.Py())); + values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v1234.Px()) + ((secondaryVertex[1] - collision.posY()) * v1234.Py()) + ((secondaryVertex[2] - collision.posZ()) * v1234.Pz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v1234.Px() * v1234.Px()) + (v1234.Py() * v1234.Py()) + (v1234.Pz() * v1234.Pz())); + + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v1234.M() / TMath::Abs(v1234.Pz()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v1234.M() / (v1234.Pt()); + values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v1234.M() / (v1234.P()); + } + } else if (fgUsedKF) { + KFParticle lepton1KF; // lepton1 + KFParticle lepton2KF; // lepton2 + KFParticle KFGeoTwoLeptons; + KFParticle trk1KF; // track1 + KFParticle trk2KF; // track2 + KFParticle KFGeoTwoTracks; + KFParticle KFGeoFourProng; + if constexpr (candidateType == kXtoJpsiPiPi) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(lepton1); + lepton1KF = KFParticle(kfpTrack0, -11 * lepton1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(lepton2); + lepton2KF = KFParticle(kfpTrack1, -11 * lepton2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(track1); + trk1KF = KFParticle(kfpTrack2, 211 * track1.sign()); + KFPTrack kfpTrack3 = createKFPTrackFromTrack(track2); + trk2KF = KFParticle(kfpTrack3, 211 * track2.sign()); + + KFGeoTwoLeptons.SetConstructMethod(2); + KFGeoTwoLeptons.AddDaughter(lepton1KF); + KFGeoTwoLeptons.AddDaughter(lepton2KF); + + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt]) { + values[VarManager::kPairMass] = KFGeoTwoLeptons.GetMass(); + values[VarManager::kPairPt] = KFGeoTwoLeptons.GetPt(); + } + + KFGeoTwoTracks.SetConstructMethod(2); + KFGeoTwoTracks.AddDaughter(trk1KF); + KFGeoTwoTracks.AddDaughter(trk2KF); + + if (fgUsedVars[kDitrackMass] || fgUsedVars[kDitrackPt]) { + values[VarManager::kDitrackMass] = KFGeoTwoTracks.GetMass(); + values[VarManager::kDitrackPt] = KFGeoTwoTracks.GetPt(); + } + + KFGeoFourProng.SetConstructMethod(2); + KFGeoFourProng.AddDaughter(KFGeoTwoLeptons); + KFGeoFourProng.AddDaughter(KFGeoTwoTracks); + } + + if constexpr (candidateType == kPsi2StoJpsiPiPi) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(lepton1); + lepton1KF = KFParticle(kfpTrack0, -11 * lepton1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(lepton2); + lepton2KF = KFParticle(kfpTrack1, -11 * lepton2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(track1); + trk1KF = KFParticle(kfpTrack2, 211 * track1.sign()); + KFPTrack kfpTrack3 = createKFPTrackFromTrack(track2); + trk2KF = KFParticle(kfpTrack3, 211 * track2.sign()); + + KFGeoTwoLeptons.SetConstructMethod(2); + KFGeoTwoLeptons.AddDaughter(lepton1KF); + KFGeoTwoLeptons.AddDaughter(lepton2KF); + + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt]) { + values[VarManager::kPairMass] = KFGeoTwoLeptons.GetMass(); + values[VarManager::kPairPt] = KFGeoTwoLeptons.GetPt(); + } + + KFGeoFourProng.SetConstructMethod(2); + KFGeoFourProng.AddDaughter(KFGeoTwoLeptons); + KFGeoFourProng.AddDaughter(trk1KF); + KFGeoFourProng.AddDaughter(trk2KF); + } + + if (fgUsedVars[kKFMass]) { + float mass = 0., massErr = 0.; + if (!KFGeoFourProng.GetMass(mass, massErr)) + values[kKFMass] = mass; + else + values[kKFMass] = -999.; + } + + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + values[kKFNContributorsPV] = kfpVertex.GetNContributors(); + KFParticle KFPV(kfpVertex); + double dxQuadlet2PV = KFGeoFourProng.GetX() - KFPV.GetX(); + double dyQuadlet2PV = KFGeoFourProng.GetY() - KFPV.GetY(); + double dzQuadlet2PV = KFGeoFourProng.GetZ() - KFPV.GetZ(); + + values[kVertexingLxy] = std::sqrt(dxQuadlet2PV * dxQuadlet2PV + dyQuadlet2PV * dyQuadlet2PV); + values[kVertexingLz] = std::sqrt(dzQuadlet2PV * dzQuadlet2PV); + values[kVertexingLxyz] = std::sqrt(dxQuadlet2PV * dxQuadlet2PV + dyQuadlet2PV * dyQuadlet2PV + dzQuadlet2PV * dzQuadlet2PV); + + values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoFourProng.GetCovariance(0)) * dxQuadlet2PV * dxQuadlet2PV + (KFPV.GetCovariance(2) + KFGeoFourProng.GetCovariance(2)) * dyQuadlet2PV * dyQuadlet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoFourProng.GetCovariance(1)) * dxQuadlet2PV * dyQuadlet2PV); + values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoFourProng.GetCovariance(5)) * dzQuadlet2PV * dzQuadlet2PV; + values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoFourProng.GetCovariance(0)) * dxQuadlet2PV * dxQuadlet2PV + (KFPV.GetCovariance(2) + KFGeoFourProng.GetCovariance(2)) * dyQuadlet2PV * dyQuadlet2PV + (KFPV.GetCovariance(5) + KFGeoFourProng.GetCovariance(5)) * dzQuadlet2PV * dzQuadlet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoFourProng.GetCovariance(1)) * dxQuadlet2PV * dyQuadlet2PV + (KFPV.GetCovariance(3) + KFGeoFourProng.GetCovariance(3)) * dxQuadlet2PV * dzQuadlet2PV + (KFPV.GetCovariance(4) + KFGeoFourProng.GetCovariance(4)) * dyQuadlet2PV * dzQuadlet2PV); + + 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] = KFGeoFourProng.GetPseudoProperDecayTime(KFPV, KFGeoFourProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauz] = -1 * dzQuadlet2PV * KFGeoFourProng.GetMass() / (TMath::Abs(KFGeoFourProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingPz] = TMath::Abs(KFGeoFourProng.GetPz()); + values[kVertexingSV] = KFGeoFourProng.GetZ(); + + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoFourProng.GetMass() / (KFGeoFourProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauzErr] = values[kVertexingLzErr] * KFGeoFourProng.GetMass() / (TMath::Abs(KFGeoFourProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingChi2PCA] = KFGeoFourProng.GetChi2(); + values[kCosPointingAngle] = (std::sqrt(dxQuadlet2PV * dxQuadlet2PV) * v1234.Px() + + std::sqrt(dyQuadlet2PV * dyQuadlet2PV) * v1234.Py() + + std::sqrt(dzQuadlet2PV * dzQuadlet2PV) * v1234.Pz()) / + (v1234.P() * values[VarManager::kVertexingLxyz]); + // // run 2 definitions: Decay length projected onto the momentum vector of the candidate + values[kVertexingLzProjected] = (dzQuadlet2PV * KFGeoFourProng.GetPz()) / TMath::Sqrt(KFGeoFourProng.GetPz() * KFGeoFourProng.GetPz()); + values[kVertexingLxyProjected] = (dxQuadlet2PV * KFGeoFourProng.GetPx()) + (dyQuadlet2PV * KFGeoFourProng.GetPy()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoFourProng.GetPx() * KFGeoFourProng.GetPx()) + (KFGeoFourProng.GetPy() * KFGeoFourProng.GetPy())); + values[kVertexingLxyzProjected] = (dxQuadlet2PV * KFGeoFourProng.GetPx()) + (dyQuadlet2PV * KFGeoFourProng.GetPy()) + (dzQuadlet2PV * KFGeoFourProng.GetPz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoFourProng.GetPx() * KFGeoFourProng.GetPx()) + (KFGeoFourProng.GetPy() * KFGeoFourProng.GetPy()) + (KFGeoFourProng.GetPz() * KFGeoFourProng.GetPz())); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoFourProng.GetMass() / (KFGeoFourProng.GetPt()); + values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoFourProng.GetMass() / TMath::Abs(KFGeoFourProng.GetPz()); + values[kKFChi2OverNDFGeo] = KFGeoFourProng.GetChi2() / KFGeoFourProng.GetNDF(); + } else { + return; + } +} + +//__________________________________________________________________ +template +void VarManager::FillQuadMC(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) @@ -4241,4 +5890,102 @@ float VarManager::calculatePhiV(T1 const& t1, T2 const& t2) return pairPhiV; } +/// Fill BDT score values. +/// Supports binary (1 output) and multiclass (3 outputs) models. +template +void VarManager::FillBdtScore(T1 const& bdtScore, float* values) +{ + if (!values) { + values = fgValues; + } + + if (bdtScore.size() == 1) { + values[kBdtBackground] = bdtScore[0]; + } else if (bdtScore.size() == 3) { + values[kBdtBackground] = bdtScore[0]; + values[kBdtPrompt] = bdtScore[1]; + values[kBdtNonprompt] = bdtScore[2]; + } else { + LOG(warning) << "Unexpected number of BDT outputs: " << bdtScore.size(); + } +} +//__________________________________________________________________ +template +float VarManager::LorentzTransformJpsihadroncosChi(TString Option, T1 const& v1, T2 const& v2) +{ + float value = -999.0f; + auto beta_v1 = v1.BoostToCM(); + ROOT::Math::Boost boostv1{beta_v1}; + auto v2_boost = boostv1(v2); + auto p_v1_lab = v1.Vect(); + float p1_lab = p_v1_lab.R(); + if (Option == "coschi") { + auto p_v2_boost = v2_boost.Vect(); + float p_boost = p_v2_boost.R(); + value = p_v2_boost.Dot(p_v1_lab) / (p1_lab * p_boost); + } else if (Option == "costheta") { + auto p_v2_lab = v2.Vect(); + float p2_lab = p_v2_lab.R(); + value = p_v1_lab.Dot(p_v2_lab) / (p1_lab * p2_lab); + } else if (Option == "weight_boost") { + value = v2_boost.E(); + } + return value; +} +template +void VarManager::FillFIT(T1 const& bc, T2 const& bcs, T3 const& ft0s, T4 const& fv0as, T5 const& fdds, float* values) +{ + if (!values) { + values = fgValues; + } + + // Initialize FIT info structure + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); + + // Fill FT0 information + values[kAmplitudeFT0A] = fitInfo.ampFT0A; + values[kAmplitudeFT0C] = fitInfo.ampFT0C; + values[kTimeFT0A] = fitInfo.timeFT0A; + values[kTimeFT0C] = fitInfo.timeFT0C; + values[kTriggerMaskFT0] = static_cast(fitInfo.triggerMaskFT0); + const auto ft0Index = bc.ft0Id(); + if (ft0Index < 0 || ft0Index >= ft0s.size()) { + values[kNFiredChannelsFT0A] = -1; + values[kNFiredChannelsFT0C] = -1; + } else { + const auto ft0 = ft0s.iteratorAt(ft0Index); + values[kNFiredChannelsFT0A] = ft0.channelA().size(); + values[kNFiredChannelsFT0C] = ft0.channelC().size(); + } + // Fill FDD information + values[kAmplitudeFDDA] = fitInfo.ampFDDA; + values[kAmplitudeFDDC] = fitInfo.ampFDDC; + values[kTimeFDDA] = fitInfo.timeFDDA; + values[kTimeFDDC] = fitInfo.timeFDDC; + values[kTriggerMaskFDD] = static_cast(fitInfo.triggerMaskFDD); + + // Fill FV0A information + values[kAmplitudeFV0A] = fitInfo.ampFV0A; + values[kTimeFV0A] = fitInfo.timeFV0A; + values[kTriggerMaskFV0A] = static_cast(fitInfo.triggerMaskFV0A); + const auto fv0aIndex = bc.fv0aId(); + if (fv0aIndex < 0 || fv0aIndex >= fv0as.size()) { + values[kNFiredChannelsFV0A] = -1; + } else { + const auto fv0a = fv0as.iteratorAt(fv0aIndex); + values[kNFiredChannelsFV0A] = fv0a.channel().size(); + } + // Fill pileup flags + values[kBBFT0Apf] = static_cast(fitInfo.BBFT0Apf); + values[kBGFT0Apf] = static_cast(fitInfo.BGFT0Apf); + values[kBBFT0Cpf] = static_cast(fitInfo.BBFT0Cpf); + values[kBGFT0Cpf] = static_cast(fitInfo.BGFT0Cpf); + values[kBBFV0Apf] = static_cast(fitInfo.BBFV0Apf); + values[kBGFV0Apf] = static_cast(fitInfo.BGFV0Apf); + values[kBBFDDApf] = static_cast(fitInfo.BBFDDApf); + values[kBGFDDApf] = static_cast(fitInfo.BGFDDApf); + values[kBBFDDCpf] = static_cast(fitInfo.BBFDDCpf); + values[kBGFDDCpf] = static_cast(fitInfo.BGFDDCpf); +} #endif // PWGDQ_CORE_VARMANAGER_H_ diff --git a/PWGDQ/DataModel/ReducedInfoTables.h b/PWGDQ/DataModel/ReducedInfoTables.h index d72df05f0c4..68f91acb420 100644 --- a/PWGDQ/DataModel/ReducedInfoTables.h +++ b/PWGDQ/DataModel/ReducedInfoTables.h @@ -15,116 +15,157 @@ #ifndef PWGDQ_DATAMODEL_REDUCEDINFOTABLES_H_ #define PWGDQ_DATAMODEL_REDUCEDINFOTABLES_H_ -#include -#include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGHF/Utils/utilsPid.h" + #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Qvectors.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Qvectors.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" #include "MathUtils/Utils.h" +#include +#include + namespace o2::aod { namespace dqppfilter { DECLARE_SOA_COLUMN(EventFilter, eventFilter, uint64_t); //! Bit-field used for the high level event triggering -} +DECLARE_SOA_COLUMN(NewBcIndex, newBcIndex, uint64_t); //! globalIndex of the new BC determined in filterPbPb +} // namespace dqppfilter 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::NewBcIndex); + 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(NTPCpileupContribA, nTPCpileupContribA, int); //! Number of TPC pileup tracks on A side -DECLARE_SOA_COLUMN(NTPCpileupContribC, nTPCpileupContribC, int); //! Number of TPC pileup tracks on C side -DECLARE_SOA_COLUMN(NTPCpileupZA, nTPCpileupZA, float); //! Median Z position of pileup tracks on A side -DECLARE_SOA_COLUMN(NTPCpileupZC, nTPCpileupZC, float); //! Median Z position of pileup tracks on C side -DECLARE_SOA_COLUMN(NTPCtracksInPast, nTPCtracksInPast, int); //! Number of TPC tracks in the past events (configurable, but e.g. one drift time) -DECLARE_SOA_COLUMN(NTPCtracksInFuture, nTPCtracksInFuture, int); //! Number of TPC tracks in the future events (configurable, but e.g. one drift time) - -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) -DECLARE_SOA_COLUMN(Q1Y0B, q1y0b, float); //! Q-vector y component, with event eta gap B (harmonic 1 and power 1) -DECLARE_SOA_COLUMN(Q1X0C, q1x0c, float); //! Q-vector x component, with event eta gap C (harmonic 1 and power 1) -DECLARE_SOA_COLUMN(Q1Y0C, q1y0c, float); //! Q-vector y component, with event eta gap C (harmonic 1 and power 1) -DECLARE_SOA_COLUMN(Q2X0A, q2x0a, float); //! Q-vector x component, with event eta gap A (harmonic 2 and power 1) -DECLARE_SOA_COLUMN(Q2Y0A, q2y0a, float); //! Q-vector y component, with event eta gap A (harmonic 2 and power 1) -DECLARE_SOA_COLUMN(Q2X0B, q2x0b, float); //! Q-vector x component, with event eta gap B (harmonic 2 and power 1) -DECLARE_SOA_COLUMN(Q2Y0B, q2y0b, float); //! Q-vector y component, with event eta gap B (harmonic 2 and power 1) -DECLARE_SOA_COLUMN(Q2X0C, q2x0c, float); //! Q-vector x component, with event eta gap C (harmonic 2 and power 1) -DECLARE_SOA_COLUMN(Q2Y0C, q2y0c, float); //! Q-vector y component, with event eta gap C (harmonic 2 and power 1) -DECLARE_SOA_COLUMN(MultA, multa, float); //! Event multiplicity eta gap A -DECLARE_SOA_COLUMN(MultB, multb, float); //! Event multiplicity eta gap B -DECLARE_SOA_COLUMN(MultC, multc, float); //! Event multiplicity eta gap C -DECLARE_SOA_COLUMN(Q3X0A, q3x0a, float); //! Q-vector x component, with event eta gap A (harmonic 3 and power 1) -DECLARE_SOA_COLUMN(Q3Y0A, q3y0a, float); //! Q-vector y component, with event eta gap A (harmonic 3 and power 1) -DECLARE_SOA_COLUMN(Q3X0B, q3x0b, float); //! Q-vector x component, with event eta gap B (harmonic 3 and power 1) -DECLARE_SOA_COLUMN(Q3Y0B, q3y0b, float); //! Q-vector y component, with event eta gap B (harmonic 3 and power 1) -DECLARE_SOA_COLUMN(Q3X0C, q3x0c, float); //! Q-vector x component, with event eta gap C (harmonic 3 and power 1) -DECLARE_SOA_COLUMN(Q3Y0C, q3y0c, float); //! Q-vector y component, with event eta gap C (harmonic 3 and power 1) -DECLARE_SOA_COLUMN(Q4X0A, q4x0a, float); //! Q-vector x component, with event eta gap A (harmonic 4 and power 1) -DECLARE_SOA_COLUMN(Q4Y0A, q4y0a, float); //! Q-vector y component, with event eta gap A (harmonic 4 and power 1) -DECLARE_SOA_COLUMN(Q4X0B, q4x0b, float); //! Q-vector x component, with event eta gap B (harmonic 4 and power 1) -DECLARE_SOA_COLUMN(Q4Y0B, q4y0b, float); //! Q-vector y component, with event eta gap B (harmonic 4 and power 1) -DECLARE_SOA_COLUMN(Q4X0C, q4x0c, float); //! Q-vector x component, with event eta gap C (harmonic 4 and power 1) -DECLARE_SOA_COLUMN(Q4Y0C, q4y0c, float); //! Q-vector y component, with event eta gap C (harmonic 4 and power 1) -DECLARE_SOA_COLUMN(Q42XA, q42xa, float); //! Q-vector x component, with event eta gap A (harmonic 4 and power 2) -DECLARE_SOA_COLUMN(Q42YA, q42ya, float); //! Q-vector y component, with event eta gap A (harmonic 4 and power 2) -DECLARE_SOA_COLUMN(Q23XA, q23xa, float); //! Q-vector x component, with event eta gap A (harmonic 2 and power 3) -DECLARE_SOA_COLUMN(Q23YA, q23ya, float); //! Q-vector y component, with event eta gap A (harmonic 2 and power 3) -DECLARE_SOA_COLUMN(S11A, s11a, float); //! Weighted multiplicity (p = 1, k = 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(CORR2REF, corr2ref, 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_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) +DECLARE_SOA_COLUMN(Q1Y0B, q1y0b, float); //! Q-vector y component, with event eta gap B (harmonic 1 and power 1) +DECLARE_SOA_COLUMN(Q1X0C, q1x0c, float); //! Q-vector x component, with event eta gap C (harmonic 1 and power 1) +DECLARE_SOA_COLUMN(Q1Y0C, q1y0c, float); //! Q-vector y component, with event eta gap C (harmonic 1 and power 1) +DECLARE_SOA_COLUMN(Q2X0A, q2x0a, float); //! Q-vector x component, with event eta gap A (harmonic 2 and power 1) +DECLARE_SOA_COLUMN(Q2Y0A, q2y0a, float); //! Q-vector y component, with event eta gap A (harmonic 2 and power 1) +DECLARE_SOA_COLUMN(Q2X0B, q2x0b, float); //! Q-vector x component, with event eta gap B (harmonic 2 and power 1) +DECLARE_SOA_COLUMN(Q2Y0B, q2y0b, float); //! Q-vector y component, with event eta gap B (harmonic 2 and power 1) +DECLARE_SOA_COLUMN(Q2X0C, q2x0c, float); //! Q-vector x component, with event eta gap C (harmonic 2 and power 1) +DECLARE_SOA_COLUMN(Q2Y0C, q2y0c, float); //! Q-vector y component, with event eta gap C (harmonic 2 and power 1) +DECLARE_SOA_COLUMN(MultA, multa, float); //! Event multiplicity eta gap A +DECLARE_SOA_COLUMN(MultB, multb, float); //! Event multiplicity eta gap B +DECLARE_SOA_COLUMN(MultC, multc, float); //! Event multiplicity eta gap C +DECLARE_SOA_COLUMN(Q3X0A, q3x0a, float); //! Q-vector x component, with event eta gap A (harmonic 3 and power 1) +DECLARE_SOA_COLUMN(Q3Y0A, q3y0a, float); //! Q-vector y component, with event eta gap A (harmonic 3 and power 1) +DECLARE_SOA_COLUMN(Q3X0B, q3x0b, float); //! Q-vector x component, with event eta gap B (harmonic 3 and power 1) +DECLARE_SOA_COLUMN(Q3Y0B, q3y0b, float); //! Q-vector y component, with event eta gap B (harmonic 3 and power 1) +DECLARE_SOA_COLUMN(Q3X0C, q3x0c, float); //! Q-vector x component, with event eta gap C (harmonic 3 and power 1) +DECLARE_SOA_COLUMN(Q3Y0C, q3y0c, float); //! Q-vector y component, with event eta gap C (harmonic 3 and power 1) +DECLARE_SOA_COLUMN(Q4X0A, q4x0a, float); //! Q-vector x component, with event eta gap A (harmonic 4 and power 1) +DECLARE_SOA_COLUMN(Q4Y0A, q4y0a, float); //! Q-vector y component, with event eta gap A (harmonic 4 and power 1) +DECLARE_SOA_COLUMN(Q4X0B, q4x0b, float); //! Q-vector x component, with event eta gap B (harmonic 4 and power 1) +DECLARE_SOA_COLUMN(Q4Y0B, q4y0b, float); //! Q-vector y component, with event eta gap B (harmonic 4 and power 1) +DECLARE_SOA_COLUMN(Q4X0C, q4x0c, float); //! Q-vector x component, with event eta gap C (harmonic 4 and power 1) +DECLARE_SOA_COLUMN(Q4Y0C, q4y0c, float); //! Q-vector y component, with event eta gap C (harmonic 4 and power 1) +DECLARE_SOA_COLUMN(Q42XA, q42xa, float); //! Q-vector x component, with event eta gap A (harmonic 4 and power 2) +DECLARE_SOA_COLUMN(Q42YA, q42ya, float); //! Q-vector y component, with event eta gap A (harmonic 4 and power 2) +DECLARE_SOA_COLUMN(Q23XA, q23xa, float); //! Q-vector x component, with event eta gap A (harmonic 2 and power 3) +DECLARE_SOA_COLUMN(Q23YA, q23ya, float); //! Q-vector y component, with event eta gap A (harmonic 2 and power 3) +DECLARE_SOA_COLUMN(S11A, s11a, float); //! Weighted multiplicity (p = 1, k = 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(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(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(StoredReducedEvents, "AOD1", "REDUCEDEVENT", //! Main event information table - o2::soa::Index<>, - reducedevent::Tag, bc::RunNumber, - collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, - collision::CollisionTime, collision::CollisionTimeRes, - o2::soa::Marker<1>); +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 +DECLARE_SOA_TABLE(ReducedEventsExtended_000, "AOD", "REEXTENDED", //! Extended event information bc::GlobalBC, evsel::Alias, evsel::Selection, timestamp::Timestamp, cent::CentRun2V0M, mult::MultTPC, mult::MultFV0A, mult::MultFV0C, mult::MultFT0A, mult::MultFT0C, mult::MultFDDA, mult::MultFDDC, mult::MultZNA, mult::MultZNC, mult::MultTracklets, mult::MultNTracksPV, cent::CentFT0C); -DECLARE_SOA_TABLE(ReducedEventsMultPV, "AOD", "REMULTPV", //! Multiplicity information for primary vertex +DECLARE_SOA_TABLE_VERSIONED(ReducedEventsExtended_001, "AOD", "REEXTENDED", 1, //! Extended event information + bc::GlobalBC, evsel::Alias, evsel::Selection, timestamp::Timestamp, cent::CentRun2V0M, + mult::MultTPC, mult::MultFV0A, mult::MultFV0C, mult::MultFT0A, mult::MultFT0C, + mult::MultFDDA, mult::MultFDDC, mult::MultZNA, mult::MultZNC, mult::MultTracklets, mult::MultNTracksPV, + cent::CentFT0C, cent::CentFT0A, cent::CentFT0M); + +using ReducedEventsExtended = ReducedEventsExtended_001; + +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::NTPCpileupContribA, reducedevent::NTPCpileupContribC, reducedevent::NTPCpileupZA, reducedevent::NTPCpileupZC, - reducedevent::NTPCtracksInPast, reducedevent::NTPCtracksInFuture); + 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, @@ -142,11 +183,14 @@ 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); @@ -158,11 +202,20 @@ DECLARE_SOA_TABLE(ReducedEventsInfo, "AOD", "REDUCEVENTINFO", //! Main event i // There is no explicit accounting for MC events which were not reconstructed!!! // However, for analysis which will require these events, a special skimming process function // can be constructed and the same data model could be used -DECLARE_SOA_TABLE(ReducedMCEvents, "AOD", "REDUCEDMCEVENT", //! Event level MC truth information + +DECLARE_SOA_TABLE(ReducedMCEvents_000, "AOD", "REDUCEDMCEVENT", //! Event level MC truth information o2::soa::Index<>, mccollision::GeneratorsID, reducedevent::MCPosX, reducedevent::MCPosY, reducedevent::MCPosZ, mccollision::T, mccollision::Weight, mccollision::ImpactParameter); +DECLARE_SOA_TABLE_VERSIONED(ReducedMCEvents_001, "AOD", "REDUCEDMCEVENT", 1, //! Event level MC truth information + o2::soa::Index<>, + mccollision::GeneratorsID, reducedevent::MCPosX, reducedevent::MCPosY, reducedevent::MCPosZ, + mccollision::T, mccollision::Weight, mccollision::ImpactParameter, cent::CentFT0C, + mult::MultMCNParticlesEta05, mult::MultMCNParticlesEta08, mult::MultMCNParticlesEta10); + +using ReducedMCEvents = ReducedMCEvents_001; + using ReducedEvent = ReducedEvents::iterator; using StoredReducedEvent = StoredReducedEvents::iterator; using ReducedEventExtended = ReducedEventsExtended::iterator; @@ -172,6 +225,7 @@ 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; @@ -219,6 +273,56 @@ DECLARE_SOA_TABLE(ReducedZdcsExtra, "AOD", "REDUCEDZDCEXTRA", //! Event ZDC ex using ReducedZdc = ReducedZdcs::iterator; using ReducedZdcExtra = ReducedZdcsExtra::iterator; +namespace reducedfit +{ +// FIT detector information (based on upchelpers::FITInfo structure) +DECLARE_SOA_COLUMN(AmplitudeFT0A, amplitudeFT0A, float); //! FT0A total amplitude +DECLARE_SOA_COLUMN(AmplitudeFT0C, amplitudeFT0C, float); //! FT0C total amplitude +DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); //! FT0A time +DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); //! FT0C time +DECLARE_SOA_COLUMN(TriggerMaskFT0, triggerMaskFT0, uint8_t); //! FT0 trigger mask +DECLARE_SOA_COLUMN(NFiredChannelsFT0A, nFiredChannelsFT0A, int); //! Number of fired channels in FT0A +DECLARE_SOA_COLUMN(NFiredChannelsFT0C, nFiredChannelsFT0C, int); //! Number of fired channels in FT0C +DECLARE_SOA_COLUMN(AmplitudeFDDA, amplitudeFDDA, float); //! FDDA total amplitude +DECLARE_SOA_COLUMN(AmplitudeFDDC, amplitudeFDDC, float); //! FDDC total amplitude +DECLARE_SOA_COLUMN(TimeFDDA, timeFDDA, float); //! FDDA time +DECLARE_SOA_COLUMN(TimeFDDC, timeFDDC, float); //! FDDC time +DECLARE_SOA_COLUMN(TriggerMaskFDD, triggerMaskFDD, uint8_t); //! FDD trigger mask +DECLARE_SOA_COLUMN(AmplitudeFV0A, amplitudeFV0A, float); //! FV0A total amplitude +DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); //! FV0A time +DECLARE_SOA_COLUMN(TriggerMaskFV0A, triggerMaskFV0A, uint8_t); //! FV0A trigger mask +DECLARE_SOA_COLUMN(NFiredChannelsFV0A, nFiredChannelsFV0A, int); //! Number of fired channels in FV0A +DECLARE_SOA_COLUMN(BBFT0Apf, bbFT0Apf, int32_t); //! Beam-beam flags for FT0A +DECLARE_SOA_COLUMN(BGFT0Apf, bgFT0Apf, int32_t); //! Beam-gas flags for FT0A +DECLARE_SOA_COLUMN(BBFT0Cpf, bbFT0Cpf, int32_t); //! Beam-beam flags for FT0C +DECLARE_SOA_COLUMN(BGFT0Cpf, bgFT0Cpf, int32_t); //! Beam-gas flags for FT0C +DECLARE_SOA_COLUMN(BBFV0Apf, bbFV0Apf, int32_t); //! Beam-beam flags for FV0A +DECLARE_SOA_COLUMN(BGFV0Apf, bgFV0Apf, int32_t); //! Beam-gas flags for FV0A +DECLARE_SOA_COLUMN(BBFDDApf, bbFDDApf, int32_t); //! Beam-beam flags for FDDA +DECLARE_SOA_COLUMN(BGFDDApf, bgFDDApf, int32_t); //! Beam-gas flags for FDDA +DECLARE_SOA_COLUMN(BBFDDCpf, bbFDDCpf, int32_t); //! Beam-beam flags for FDDC +DECLARE_SOA_COLUMN(BGFDDCpf, bgFDDCpf, int32_t); //! Beam-gas flags for FDDC +} // namespace reducedfit + +DECLARE_SOA_TABLE(ReducedFITs, "AOD", "REDUCEDFIT", //! FIT detector information + reducedfit::AmplitudeFT0A, reducedfit::AmplitudeFT0C, + reducedfit::TimeFT0A, reducedfit::TimeFT0C, + reducedfit::TriggerMaskFT0, + reducedfit::NFiredChannelsFT0A, reducedfit::NFiredChannelsFT0C, + reducedfit::AmplitudeFDDA, reducedfit::AmplitudeFDDC, + reducedfit::TimeFDDA, reducedfit::TimeFDDC, + reducedfit::TriggerMaskFDD, + reducedfit::AmplitudeFV0A, reducedfit::TimeFV0A, + reducedfit::TriggerMaskFV0A, + reducedfit::NFiredChannelsFV0A, + reducedfit::BBFT0Apf, reducedfit::BGFT0Apf, + reducedfit::BBFT0Cpf, reducedfit::BGFT0Cpf, + reducedfit::BBFV0Apf, reducedfit::BGFV0Apf, + reducedfit::BBFDDApf, reducedfit::BGFDDApf, + reducedfit::BBFDDCpf, reducedfit::BGFDDCpf); + +using ReducedFIT = ReducedFITs::iterator; + namespace reducedtrack { // basic track information @@ -357,6 +461,7 @@ DECLARE_SOA_TABLE(ReducedMCTracks, "AOD", "REDUCEDMCTRACK", //! MC track inform mcparticle::FromBackgroundEvent, mcparticle::GetGenStatusCode, mcparticle::GetProcess, + mcparticle::GetHepMCStatusCode, mcparticle::IsPhysicalPrimary); using ReducedMCTrack = ReducedMCTracks::iterator; @@ -388,6 +493,9 @@ 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 @@ -400,8 +508,13 @@ 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 @@ -554,38 +667,42 @@ DECLARE_SOA_COLUMN(Vt2, vt2, float); //! Production vertex time DECLARE_SOA_COLUMN(IsAmbig1, isAmbig1, int); //! DECLARE_SOA_COLUMN(IsAmbig2, isAmbig2, int); //! -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(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(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(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 @@ -601,56 +718,58 @@ DECLARE_SOA_COLUMN(DeviationxyTrk1KF, deviationxyTrk1KF, float); //! 2D chi2 dev // pair information 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_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_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) -DECLARE_SOA_COLUMN(VertexPz, vertexPz, float); //! Longitudinal projection of impulsion -DECLARE_SOA_COLUMN(SVertex, sVertex, float); //! Secondary vertex of lepton pair -DECLARE_SOA_COLUMN(Tauxy, tauxy, float); //! Transverse pseudo-proper time of lepton pair (in ns) -DECLARE_SOA_COLUMN(TauxyErr, tauxyErr, float); //! Error on transverse pseudo-proper time of lepton pair (in ns) -DECLARE_SOA_COLUMN(Lz, lz, float); //! Longitudinal projection of decay length -DECLARE_SOA_COLUMN(Lxy, lxy, float); //! Transverse projection of decay length -DECLARE_SOA_COLUMN(Chi2pca, chi2pca, float); //! Chi2 for PCA of the dilepton -DECLARE_SOA_COLUMN(CosPointingAngle, cosPointingAngle, float); //! Cosine of the pointing angle -DECLARE_SOA_COLUMN(U2Q2, u2q2, float); //! Scalar product between unitary vector with event flow vector (harmonic 2) -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_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(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, 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_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) +DECLARE_SOA_COLUMN(VertexPz, vertexPz, float); //! Longitudinal projection of impulsion +DECLARE_SOA_COLUMN(SVertex, sVertex, float); //! Secondary vertex of lepton pair +DECLARE_SOA_COLUMN(Tauxy, tauxy, float); //! Transverse pseudo-proper time of lepton pair (in ns) +DECLARE_SOA_COLUMN(TauxyErr, tauxyErr, float); //! Error on transverse pseudo-proper time of lepton pair (in ns) +DECLARE_SOA_COLUMN(Lz, lz, float); //! Longitudinal projection of decay length +DECLARE_SOA_COLUMN(Lxy, lxy, float); //! Transverse projection of decay length +DECLARE_SOA_COLUMN(Chi2pca, chi2pca, float); //! Chi2 for PCA of the dilepton +DECLARE_SOA_COLUMN(CosPointingAngle, cosPointingAngle, float); //! Cosine of the pointing angle +DECLARE_SOA_COLUMN(U2Q2, u2q2, float); //! Scalar product between unitary vector with event flow vector (harmonic 2) +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_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(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, 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 @@ -663,7 +782,20 @@ DECLARE_SOA_COLUMN(PairDCAxy, pairDCAxy, float); 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, //! +DECLARE_SOA_COLUMN(CosThetaHE, costhetaHE, float); //! Cosine in the helicity frame +DECLARE_SOA_COLUMN(PhiHE, phiHe, float); //! Phi in the helicity frame +DECLARE_SOA_COLUMN(PhiTildeHE, phiTildeHe, float); //! Tilde Phi in the helicity frame +DECLARE_SOA_COLUMN(CosThetaCS, costhetaCS, float); //! Cosine in the Collins-Soper frame +DECLARE_SOA_COLUMN(PhiCS, phiCS, float); //! Phi in the Collins-Soper frame +DECLARE_SOA_COLUMN(PhiTildeCS, phiTildeCS, float); //! Tilde Phi in the Collins-Soper frame +DECLARE_SOA_COLUMN(CosThetaPP, costhetaPP, float); //! Cosine in the Production Plane frame +DECLARE_SOA_COLUMN(PhiPP, phiPP, float); //! Phi in the Production Plane frame +DECLARE_SOA_COLUMN(PhiTildePP, phiTildePP, float); //! Tilde Phi in the Production Plane frame +DECLARE_SOA_COLUMN(CosThetaRM, costhetaRM, float); //! Cosine in the Random frame +DECLARE_SOA_COLUMN(CosThetaStarTPC, costhetaStarTPC, float); //! global polarization, event plane reconstructed from TPC tracks +DECLARE_SOA_COLUMN(CosThetaStarFT0A, costhetaStarFT0A, float); //! global polarization, event plane reconstructed from FT0A tracks +DECLARE_SOA_COLUMN(CosThetaStarFT0C, costhetaStarFT0C, float); //! global polarization, event plane reconstructed from FT0C tracks +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); }); @@ -677,28 +809,16 @@ 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(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::Y, - reducedpair::Px, - reducedpair::Py, - reducedpair::Pz, - reducedpair::P); - -DECLARE_SOA_TABLE(StoredDielectrons, "AOD1", "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, - o2::soa::Marker<1>); +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, @@ -744,21 +864,25 @@ DECLARE_SOA_TABLE(DileptonsFlow, "AOD", "RTDILEPTONFLOW", //! 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::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::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_STAGED(DielectronsAll, "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, + reducedpair::Tauz, reducedpair::Tauxy, + reducedpair::Lz, + reducedpair::Lxy); 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, @@ -793,6 +917,30 @@ 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); + +DECLARE_SOA_TABLE(DileptonsPolarization, "AOD", "RTDILPOLAR", //! + reducedpair::CosThetaHE, reducedpair::PhiHE, reducedpair::PhiTildeHE, + reducedpair::CosThetaCS, reducedpair::PhiCS, reducedpair::PhiTildeCS, + reducedpair::CosThetaPP, reducedpair::PhiPP, reducedpair::PhiTildePP, + reducedpair::CosThetaRM, + reducedpair::CosThetaStarTPC, reducedpair::CosThetaStarFT0A, reducedpair::CosThetaStarFT0C); + using Dielectron = Dielectrons::iterator; using StoredDielectron = StoredDielectrons::iterator; using Dimuon = Dimuons::iterator; @@ -803,12 +951,16 @@ using DileptonFlow = DileptonsFlow::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; +using DileptonPolarization = DileptonsPolarization::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::FilterMap, reducedpair::PairFilterMap, reducedpair::CommonFilterMap, reducedpair::Rap, reducedpair::Y, reducedpair::Px, @@ -826,17 +978,18 @@ DECLARE_SOA_TABLE(DitracksExtra, "AOD", "RTDITRKEXTRA", //! // 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, uint32_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; @@ -866,6 +1019,134 @@ 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(DileptonTPCnSigmaEl1, dileptonTPCnSigmaEl1, float); //! +DECLARE_SOA_COLUMN(DileptonTPCnSigmaPi1, dileptonTPCnSigmaPi1, float); //! +DECLARE_SOA_COLUMN(DileptonTPCnSigmaPr1, dileptonTPCnSigmaPr1, float); //! +DECLARE_SOA_COLUMN(DileptonTPCnCls1, dileptonTPCnCls1, float); //! +DECLARE_SOA_COLUMN(DileptonTPCnSigmaEl2, dileptonTPCnSigmaEl2, float); //! +DECLARE_SOA_COLUMN(DileptonTPCnSigmaPi2, dileptonTPCnSigmaPi2, float); //! +DECLARE_SOA_COLUMN(DileptonTPCnSigmaPr2, dileptonTPCnSigmaPr2, float); //! +DECLARE_SOA_COLUMN(DileptonTPCnCls2, dileptonTPCnCls2, float); //! +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); //! +DECLARE_SOA_COLUMN(TrackTPCNSigmaPi1, trackTPCNSigmaPi1, float); //! +DECLARE_SOA_COLUMN(TrackTPCNSigmaPi2, trackTPCNSigmaPi2, float); //! +DECLARE_SOA_COLUMN(TrackTPCNSigmaKa1, trackTPCNSigmaKa1, float); //! +DECLARE_SOA_COLUMN(TrackTPCNSigmaKa2, trackTPCNSigmaKa2, float); //! +DECLARE_SOA_COLUMN(TrackTPCNSigmaPr1, trackTPCNSigmaPr1, float); //! +DECLARE_SOA_COLUMN(TrackTPCNSigmaPr2, trackTPCNSigmaPr2, float); //! +DECLARE_SOA_COLUMN(TrackTPCNCls1, trackTPCNCls1, float); //! +DECLARE_SOA_COLUMN(TrackTPCNCls2, trackTPCNCls2, float); //! +DECLARE_SOA_COLUMN(KFMass, kfMass, float); //! +DECLARE_SOA_COLUMN(VertexingProcCode, vertexingProcCode, float); //! +DECLARE_SOA_COLUMN(VertexingChi2PCA, vertexingChi2PCA, float); //! +DECLARE_SOA_COLUMN(CosPointingAngle, cosPointingAngle, float); //! +DECLARE_SOA_COLUMN(KFDCAxyzBetweenProngs, kfDCAxyzBetweenProngs, float); //! +DECLARE_SOA_COLUMN(KFChi2OverNDFGeo, kfChi2OverNDFGeo, float); //! +DECLARE_SOA_COLUMN(VertexingLz, vertexingLz, float); //! +DECLARE_SOA_COLUMN(VertexingLxy, vertexingLxy, float); //! +DECLARE_SOA_COLUMN(VertexingLxyz, vertexingLxyz, float); //! +DECLARE_SOA_COLUMN(VertexingTauz, vertexingTauz, float); //! +DECLARE_SOA_COLUMN(VertexingTauxy, vertexingTauxy, float); //! +DECLARE_SOA_COLUMN(VertexingLzErr, vertexingLzErr, float); //! +DECLARE_SOA_COLUMN(VertexingLxyzErr, vertexingLxyzErr, float); //! +DECLARE_SOA_COLUMN(VertexingTauzErr, vertexingTauzErr, float); //! +DECLARE_SOA_COLUMN(VertexingLzProjected, vertexingLzProjected, float); //! +DECLARE_SOA_COLUMN(VertexingLxyProjected, vertexingLxyProjected, float); //! +DECLARE_SOA_COLUMN(VertexingLxyzProjected, vertexingLxyzProjected, float); //! +DECLARE_SOA_COLUMN(VertexingTauzProjected, vertexingTauzProjected, float); //! +DECLARE_SOA_COLUMN(VertexingTauxyProjected, vertexingTauxyProjected, float); //! +} // 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::DileptonTPCnSigmaEl1, + dileptonTrackTrackCandidate::DileptonTPCnSigmaPi1, + dileptonTrackTrackCandidate::DileptonTPCnSigmaPr1, + dileptonTrackTrackCandidate::DileptonTPCnCls1, + dileptonTrackTrackCandidate::DileptonTPCnSigmaEl2, + dileptonTrackTrackCandidate::DileptonTPCnSigmaPi2, + dileptonTrackTrackCandidate::DileptonTPCnSigmaPr2, + dileptonTrackTrackCandidate::DileptonTPCnCls2, + dileptonTrackTrackCandidate::DiTracksMass, + dileptonTrackTrackCandidate::DiTracksPt, + dileptonTrackTrackCandidate::TrackPt1, + dileptonTrackTrackCandidate::TrackPt2, + dileptonTrackTrackCandidate::TrackEta1, + dileptonTrackTrackCandidate::TrackEta2, + dileptonTrackTrackCandidate::TrackPhi1, + dileptonTrackTrackCandidate::TrackPhi2, + dileptonTrackTrackCandidate::TrackSign1, + dileptonTrackTrackCandidate::TrackSign2, + dileptonTrackTrackCandidate::TrackTPCNSigmaPi1, + dileptonTrackTrackCandidate::TrackTPCNSigmaPi2, + dileptonTrackTrackCandidate::TrackTPCNSigmaKa1, + dileptonTrackTrackCandidate::TrackTPCNSigmaKa2, + dileptonTrackTrackCandidate::TrackTPCNSigmaPr1, + dileptonTrackTrackCandidate::TrackTPCNSigmaPr2, + dileptonTrackTrackCandidate::TrackTPCNCls1, + dileptonTrackTrackCandidate::TrackTPCNCls2, + dileptonTrackTrackCandidate::KFMass, + dileptonTrackTrackCandidate::VertexingProcCode, + dileptonTrackTrackCandidate::VertexingChi2PCA, + dileptonTrackTrackCandidate::CosPointingAngle, + dileptonTrackTrackCandidate::KFDCAxyzBetweenProngs, + dileptonTrackTrackCandidate::KFChi2OverNDFGeo, + dileptonTrackTrackCandidate::VertexingLz, + dileptonTrackTrackCandidate::VertexingLxy, + dileptonTrackTrackCandidate::VertexingLxyz, + dileptonTrackTrackCandidate::VertexingTauz, + dileptonTrackTrackCandidate::VertexingTauxy, + dileptonTrackTrackCandidate::VertexingLzErr, + dileptonTrackTrackCandidate::VertexingLxyzErr, + dileptonTrackTrackCandidate::VertexingTauzErr, + dileptonTrackTrackCandidate::VertexingLzProjected, + dileptonTrackTrackCandidate::VertexingLxyProjected, + dileptonTrackTrackCandidate::VertexingLxyzProjected, + dileptonTrackTrackCandidate::VertexingTauzProjected, + dileptonTrackTrackCandidate::VertexingTauxyProjected); + +using DileptonTrackTrackCandidate = DileptonTrackTrackCandidates::iterator; + namespace v0bits { DECLARE_SOA_COLUMN(PIDBit, pidbit, uint8_t); //! @@ -878,6 +1159,22 @@ DECLARE_SOA_TABLE(V0Bits, "AOD", "V0BITS", //! // iterators using V0Bit = V0Bits::iterator; +namespace v0mapID +{ +DECLARE_SOA_COLUMN(V0AddID, v0addid, int8_t); //! +} // namespace v0mapID + +DECLARE_SOA_TABLE(V0MapID, "AOD", "V0MAPID", //! + v0mapID::V0AddID); + +namespace cascmapID +{ +DECLARE_SOA_COLUMN(CascAddID, cascaddid, int8_t); //! +} // namespace cascmapID + +DECLARE_SOA_TABLE(CascMapID, "AOD", "CASCMAPID", //! + cascmapID::CascAddID); + namespace DalBits { DECLARE_SOA_COLUMN(DALITZBits, dalitzBits, uint8_t); //! @@ -895,33 +1192,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", //! @@ -952,6 +1278,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); @@ -966,18 +1316,22 @@ 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 { @@ -1005,6 +1359,30 @@ DECLARE_SOA_TABLE(ReducedMuonsDca, "AOD", "RTMUONDCA", 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/Prompt-np-Seprataion.zip b/PWGDQ/Macros/Prompt-np-Seprataion.zip new file mode 100644 index 00000000000..06471293445 Binary files /dev/null and b/PWGDQ/Macros/Prompt-np-Seprataion.zip differ diff --git a/PWGDQ/Macros/bdtCut.json b/PWGDQ/Macros/bdtCut.json new file mode 100644 index 00000000000..2e015fa8618 --- /dev/null +++ b/PWGDQ/Macros/bdtCut.json @@ -0,0 +1,89 @@ +{ + "TestCut": { + "type": "Binary", + "title": "MyBDTModel", + "inputFeatures": [ + "kMass", + "kPt", + "kEta", + "kPhi", + "kPt1", + "kITSChi2NCl1", + "kTPCNClsCR1", + "kTPCNClsFound1", + "kTPCChi2NCl1", + "kDcaXY1", + "kDcaZ1", + "kTPCNSigmaEl1", + "kTPCNSigmaPi1", + "kTPCNSigmaPr1", + "kTOFNSigmaEl1", + "kTOFNSigmaPi1", + "kTOFNSigmaPr1", + "kPt2", + "kITSChi2NCl2", + "kTPCNClsCR2", + "kTPCNClsFound2", + "kTPCChi2NCl2", + "kDcaXY2", + "kDcaZ2", + "kTPCNSigmaEl2", + "kTPCNSigmaPi2", + "kTPCNSigmaPr2", + "kTOFNSigmaEl2", + "kTOFNSigmaPi2", + "kTOFNSigmaPr2" + ], + "modelFiles": [ + "cent_10_30_pt0_2_onnx.onnx", + "cent_10_30_pt2_20_onnx.onnx", + "cent_30_50_pt0_2_onnx.onnx", + "cent_30_50_pt2_20_onnx.onnx" + ], + "cent": "kCentFT0C", + "AddCentCut-Cent1030": { + "centMin": 10, + "centMax": 30, + "AddPtCut-pTBin1": { + "pTMin": 0, + "pTMax": 2, + "AddMLCut-background": { + "var": "kBdtBackground", + "cut": 0.5, + "exclude": false + } + }, + "AddPtCut-pTBin2": { + "pTMin": 2, + "pTMax": 20, + "AddMLCut-background": { + "var": "kBdtBackground", + "cut": 0.5, + "exclude": false + } + } + }, + "AddCentCut-Cent3050": { + "centMin": 30, + "centMax": 50, + "AddPtCut-pTBin1": { + "pTMin": 0, + "pTMax": 2, + "AddMLCut-background": { + "var": "kBdtBackground", + "cut": 0.5, + "exclude": false + } + }, + "AddPtCut-pTBin2": { + "pTMin": 2, + "pTMax": 20, + "AddMLCut-background": { + "var": "kBdtBackground", + "cut": 0.5, + "exclude": false + } + } + } + } +} diff --git a/PWGDQ/Macros/bdtCutMulti.json b/PWGDQ/Macros/bdtCutMulti.json new file mode 100644 index 00000000000..ba687e36200 --- /dev/null +++ b/PWGDQ/Macros/bdtCutMulti.json @@ -0,0 +1,129 @@ +{ + "TestCut": { + "type": "MultiClass", + "title": "MyBDTModel", + "inputFeatures": [ + "kMass", + "kPt", + "kEta", + "kPhi", + "kPt1", + "kITSChi2NCl1", + "kTPCNClsCR1", + "kTPCNClsFound1", + "kTPCChi2NCl1", + "kDcaXY1", + "kDcaZ1", + "kTPCNSigmaEl1", + "kTPCNSigmaPi1", + "kTPCNSigmaPr1", + "kTOFNSigmaEl1", + "kTOFNSigmaPi1", + "kTOFNSigmaPr1", + "kPt2", + "kITSChi2NCl2", + "kTPCNClsCR2", + "kTPCNClsFound2", + "kTPCChi2NCl2", + "kDcaXY2", + "kDcaZ2", + "kTPCNSigmaEl2", + "kTPCNSigmaPi2", + "kTPCNSigmaPr2", + "kTOFNSigmaEl2", + "kTOFNSigmaPi2", + "kTOFNSigmaPr2" + ], + "modelFiles": [ + "cent_10_30_pt_1_2_onnx.onnx", + "cent_10_30_pt_2_20_onnx.onnx", + "cent_30_50_pt_1_2_onnx.onnx", + "cent_30_50_pt_2_20_onnx.onnx" + ], + "cent": "kCentFT0C", + "AddCentCut-Cent1030": { + "centMin": 10, + "centMax": 30, + "AddPtCut-pTBin1": { + "pTMin": 1, + "pTMax": 2, + "AddMLCut-background": { + "var": "kBdtBackground", + "cut": 0.1, + "exclude": true + }, + "AddMLCut-prompt": { + "var": "kBdtPrompt", + "cut": 0.1, + "exclude": true + }, + "AddMLCut-nonprompt": { + "var": "kBdtNonprompt", + "cut": 0.5, + "exclude": false + } + }, + "AddPtCut-pTBin2": { + "pTMin": 2, + "pTMax": 20, + "AddMLCut-background": { + "var": "kBdtBackground", + "cut": 0.1, + "exclude": true + }, + "AddMLCut-prompt": { + "var": "kBdtPrompt", + "cut": 0.1, + "exclude": true + }, + "AddMLCut-nonprompt": { + "var": "kBdtNonprompt", + "cut": 0.5, + "exclude": false + } + } + }, + "AddCentCut-Cent3050": { + "centMin": 30, + "centMax": 50, + "AddPtCut-pTBin1": { + "pTMin": 1, + "pTMax": 2, + "AddMLCut-background": { + "var": "kBdtBackground", + "cut": 0.1, + "exclude": true + }, + "AddMLCut-prompt": { + "var": "kBdtPrompt", + "cut": 0.1, + "exclude": true + }, + "AddMLCut-nonprompt": { + "var": "kBdtNonprompt", + "cut": 0.5, + "exclude": false + } + }, + "AddPtCut-pTBin2": { + "pTMin": 2, + "pTMax": 20, + "AddMLCut-background": { + "var": "kBdtBackground", + "cut": 0.1, + "exclude": true + }, + "AddMLCut-prompt": { + "var": "kBdtPrompt", + "cut": 0.1, + "exclude": true + }, + "AddMLCut-nonprompt": { + "var": "kBdtNonprompt", + "cut": 0.5, + "exclude": false + } + } + } + } +} 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 7663568572f..b8fd20d356d 100644 --- a/PWGDQ/TableProducer/CMakeLists.txt +++ b/PWGDQ/TableProducer/CMakeLists.txt @@ -31,10 +31,15 @@ o2physics_add_dpl_workflow(table-maker-mc-with-assoc 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..9d578c4e916 --- /dev/null +++ b/PWGDQ/TableProducer/generatedQuarkoniaMC.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. +// +//__________________________________________________ +// 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 "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +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 83971f743c8..5eb39ddd4d4 100644 --- a/PWGDQ/TableProducer/tableMaker.cxx +++ b/PWGDQ/TableProducer/tableMaker.cxx @@ -17,45 +17,56 @@ // 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 "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/DataTypes.h" -#include "Framework/runDataProcessing.h" -#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 "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGDQ/Core/VarManager.h" -#include "PWGDQ/Core/HistogramManager.h" -#include "PWGDQ/Core/AnalysisCut.h" +#include +#include +#include +#include +// other includes #include "PWGDQ/Core/AnalysisCompositeCut.h" -#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/AnalysisCut.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 "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/Zorro.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FwdTrackReAlignTables.h" +#include "Common/DataModel/MftmchMatchingML.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonDataFormat/InteractionRecord.h" -#include "DetectorsVertexing/PVertexerParams.h" -#include "MathUtils/Primitive2D.h" #include "DataFormatsGlobalTracking/RecoContainer.h" -#include "Common/DataModel/CollisionAssociationTables.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DataFormatsITSMFT/ROFRecord.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsVertexing/PVertexerParams.h" +#include "DetectorsVertexing/VertexTrackMatcher.h" #include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Primitive2D.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" + #include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "EventFiltering/Zorro.h" using std::cout; using std::endl; @@ -77,6 +88,11 @@ using MyBarrelTracksWithCov = soa::Join; +using MyBarrelTracksWithCovOnlyStdPID = soa::Join; using MyBarrelTracksWithV0Bits = soa::Join; +using MyBarrelTracksForElectronMuon = soa::Join; using MyEvents = soa::Join; using MyEventsWithMults = soa::Join; using MyEventsWithFilter = soa::Join; using MyEventsWithMultsAndFilter = soa::Join; -using MyEventsWithCent = soa::Join; -using MyEventsWithCentAndMults = soa::Join; +using MyEventsWithCent = soa::Join; +using MyEventsWithCentAndMults = soa::Join; using MyMuons = soa::Join; using MyMuonsWithCov = soa::Join; using MyMuonsColl = soa::Join; using MyMuonsCollWithCov = soa::Join; +using MyMuonsRealignCollWithCov = 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 | VarManager::ObjTypes::CollisionMultExtra; constexpr static uint32_t gkEventFillMapWithMultsAndEventFilter = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra | VarManager::ObjTypes::EventFilter; @@ -123,13 +134,16 @@ constexpr static uint32_t gkEventFillMapWithCentAndMults = VarManager::ObjTypes: // 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 gkMuonFillMapWithCovAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov | VarManager::ObjTypes::AmbiMuon; +constexpr static uint32_t gkMuonRealignFillMapWithCovAmbi = VarManager::ObjTypes::MuonRealign | VarManager::ObjTypes::MuonCovRealign | VarManager::ObjTypes::AmbiMuon; constexpr static uint32_t gkTrackFillMapWithAmbi = VarManager::ObjTypes::Track | VarManager::ObjTypes::AmbiTrack; constexpr static uint32_t gkMFTFillMap = VarManager::ObjTypes::TrackMFT; @@ -157,41 +171,59 @@ 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 fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro [WARNING: under debug, do not enable!]"}; - Configurable fConfigZorroTrigMask{"cfgZorroTriggerMask", "fDiMuon", "DQ Trigger masks: fSingleE,fLMeeIMR,fLMeeHMR,fDiElectron,fSingleMuLow,fSingleMuHigh,fDiMuon"}; - 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/r/rlietava/EventFiltering/OTS/", "base path to the ccdb object for zorro"}; + + 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"}; Configurable fConfigIsOnlyforMaps{"cfgIsforMaps", false, "If true, run for postcalibration maps only"}; - Configurable fConfigDummyRunlist{"cfgDummyRunlist", false, "If true, use dummy runlist"}; - Configurable fConfigInitRunNumber{"cfgInitRunNumber", 543215, "Initial run number used in run by run checks"}; Configurable fPropMuon{"cfgPropMuon", false, "Propgate muon tracks through absorber"}; 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 @@ -201,23 +233,30 @@ struct TableMaker { Preslice perCollisionMuons = aod::fwdtrack::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; - 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); @@ -242,16 +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("processMuonOnlyWithCovAndCent") || + 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("processMuonsAndMFT") || context.mOptions.get("processMuonsAndMFTWithFilter") || context.mOptions.get("processMuonMLOnly") || context.mOptions.get("processAssociatedMuonOnlyWithCov") || context.mOptions.get("processAssociatedRealignedMuonOnlyWithCov")); if (enableBarrelHistos) { if (fDoDetailedQA) { @@ -295,16 +334,12 @@ struct TableMaker { } } - if (fConfigDummyRunlist) { - VarManager::SetDummyRunlist(fConfigInitRunNumber); - } - DefineHistograms(histClasses); // 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->setURL(useCCDBConfigurations.fConfigCcdbUrl.value); fCCDB->setCaching(true); fCCDB->setLocalObjectValidityChecking(); // Not later than now objects @@ -316,11 +351,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) { @@ -329,7 +364,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) { @@ -347,7 +382,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")); @@ -372,6 +407,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(); } @@ -382,11 +422,11 @@ 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) { - if (!fConfigRunZorro) { + if (!useZorro.fConfigRunZorro) { tag |= (collision.eventFilter() << 56); } } @@ -397,7 +437,6 @@ struct TableMaker { 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::FillEvent(collision); // extract event information and place it in the fValues array if (fDoDetailedQA) { fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); @@ -406,18 +445,24 @@ 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)) { + 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 (fConfigRunZorro) { - zorro.setBaseCCDBPath(fConfigCcdbPathZorro.value); - zorro.initCCDB(fCCDB.service, fCurrentRun, bc.timestamp(), fConfigZorroTrigMask.value); - if (zorro.isSelected(bc.globalBC())) { + 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; @@ -426,7 +471,7 @@ struct TableMaker { // 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)); } } @@ -440,25 +485,26 @@ struct TableMaker { 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()); + collision.centFT0C(), collision.centFT0A(), collision.centFT0M()); } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0) { 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); + -1, -1, -1); } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { 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()); + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, collision.centFT0C(), collision.centFT0A(), collision.centFT0M()); } else { - 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); + 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, -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.trackOccupancyInTimeRange()); + 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, 0.0, 0.0, 0.0, 0.0); } uint64_t trackFilteringTag = 0; @@ -488,7 +534,7 @@ struct TableMaker { } } - trackFilteringTag = uint64_t(0); + trackFilteringTag = static_cast(0); trackTempFilterMap = uint8_t(0); VarManager::FillTrack(track); if (fDoDetailedQA) { @@ -524,35 +570,35 @@ 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)); } } 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 } } @@ -578,11 +624,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) @@ -643,7 +701,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); @@ -786,7 +844,7 @@ struct TableMaker { } } } // end if constexpr (TMuonFillMap) - } // end fullSkimming() + } // end fullSkimming() // Templated function instantianed for all of the process functions template @@ -795,7 +853,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")); @@ -820,6 +878,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(); } @@ -832,11 +895,11 @@ 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) { - if (!fConfigRunZorro) { + if (!useZorro.fConfigRunZorro) { tag |= (collision.eventFilter() << 56); } } @@ -847,7 +910,6 @@ struct TableMaker { 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::FillEvent(collision); // extract event information and place it in the fValues array if (fDoDetailedQA) { fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); @@ -855,18 +917,24 @@ struct TableMaker { // 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)); } } (reinterpret_cast(fStatsList->At(0)))->Fill(2.0, static_cast(kNaliases)); - if (fConfigRunZorro) { - zorro.setBaseCCDBPath(fConfigCcdbPathZorro.value); - zorro.initCCDB(fCCDB.service, fCurrentRun, bc.timestamp(), fConfigZorroTrigMask.value); - if (zorro.isSelected(bc.globalBC())) { + 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; @@ -875,7 +943,7 @@ struct TableMaker { // 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)); } } @@ -889,19 +957,27 @@ struct TableMaker { 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()); + collision.centFT0C(), collision.centFT0A(), collision.centFT0M()); } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0) { 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); + -1, -1, -1); } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { 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()); + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, collision.centFT0C(), collision.centFT0A(), collision.centFT0M()); } else { - 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); + 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, -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; @@ -923,7 +999,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) { @@ -953,37 +1029,37 @@ 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)); } } 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()); @@ -1006,11 +1082,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) @@ -1020,7 +1108,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) || (TMuonFillMap & VarManager::ObjTypes::MuonCovRealign))) { muonCov.reserve(tracksMuon.size()); } // loop over muons @@ -1032,8 +1120,9 @@ struct TableMaker { std::map newMatchIndex; for (const auto& muonId : fwdtrackIndices) { // start loop over tracks - auto muon = muonId.template fwdtrack_as(); - trackFilteringTag = uint64_t(0); + auto muon = tracksMuon.rawIteratorAt(muonId.fwdtrackId()); + trackFilteringTag = static_cast(0); + VarManager::FillTrack(muon); if (muon.index() > idxPrev + 1) { // checks if some muons are filtered even before the skimming function @@ -1057,15 +1146,21 @@ struct TableMaker { // now let's save the muons with the correct indices and matches for (const auto& muonId : fwdtrackIndices) { // start loop over tracks - auto muon = muonId.template fwdtrack_as(); + auto muon = tracksMuon.rawIteratorAt(muonId.fwdtrackId()); if constexpr ((TMuonFillMap & VarManager::ObjTypes::AmbiMuon) > 0) { if (fIsAmbiguous) { isAmbiguous = (muon.compatibleCollIds().size() != 1); } } - trackFilteringTag = uint64_t(0); + trackFilteringTag = static_cast(0); trackTempFilterMap = uint8_t(0); + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonRealign)) { + if (static_cast(muon.isRemovable())) { + continue; + } + } + VarManager::FillTrack(muon); // recalculte pDca for global muon tracks @@ -1127,30 +1222,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) || (TMuonFillMap & VarManager::ObjTypes::MuonCovRealign))) { 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) { @@ -1174,28 +1269,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); @@ -1203,7 +1298,13 @@ 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"}; @@ -1216,7 +1317,7 @@ 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) TH1D* histTracks = new TH1D("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); @@ -1228,13 +1329,19 @@ struct TableMaker { for (ib = 0; ib < 5; ib++) { histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ib, v0TagNames[ib]); } - fStatsList->Add(histTracks); + 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 ------------------------------------------------------------------------------------------------------------- @@ -1301,6 +1408,13 @@ struct TableMaker { } } + // 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) @@ -1308,6 +1422,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) @@ -1439,6 +1560,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) @@ -1447,10 +1575,10 @@ struct TableMaker { } // 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 -------------------------------------------------------------------------------------------- @@ -1500,7 +1628,7 @@ struct TableMaker { } void processAssociatedMuonOnlyWithCov(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon, aod::AmbiguousTracksFwd const&, aod::FwdTrackAssoc const& fwdtrackIndices) + soa::Filtered const& tracksMuon, aod::AmbiguousFwdTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices) { for (auto& collision : collisions) { auto muonIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); @@ -1508,17 +1636,26 @@ struct TableMaker { } } - void processAssociatedMuonOnlyWithCovAndCent(MyEventsWithCent 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, 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); + } + } + + 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, muonIdsThisCollision); } } void processAssociatedMuonOnlyWithCovAndMults(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, - soa::Filtered const& tracksMuon, aod::AmbiguousTracksFwd const&, aod::FwdTrackAssoc const& fwdtrackIndices) + soa::Filtered const& tracksMuon, aod::AmbiguousFwdTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices) { for (auto& collision : collisions) { auto muonIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); @@ -1527,7 +1664,7 @@ struct TableMaker { } 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) { @@ -1551,7 +1688,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) { @@ -1658,7 +1795,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); @@ -1672,8 +1811,9 @@ 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, 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, processMuonOnlyWithCovAndEventFilter, "Build muon-only DQ skimmed data model, w/ muon cov matrix, w/ event filter", false); PROCESS_SWITCH(TableMaker, processMuonMLOnly, "Build muon-only DQ skimmed data model with global muon track by ML matching", false); @@ -1681,7 +1821,8 @@ struct TableMaker { 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, 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); 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 40d3c346b58..e2c529a5a7d 100644 --- a/PWGDQ/TableProducer/tableMakerMC.cxx +++ b/PWGDQ/TableProducer/tableMakerMC.cxx @@ -16,37 +16,46 @@ // 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 "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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" #include "PWGDQ/Core/MCSignal.h" #include "PWGDQ/Core/MCSignalLibrary.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" #include "Field/MagneticField.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" + #include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "CCDB/BasicCCDBManager.h" +#include "TList.h" + +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -79,18 +88,12 @@ using MyMuonsWithCov = soa::Join; using MyMuonsCollWithCov = soa::Join; +using MyMftTracks = soa::Join; + using MyEvents = 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 MyEventsWithCent = soa::Join; +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; @@ -105,6 +108,7 @@ constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | Va 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 { @@ -127,6 +131,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; @@ -316,9 +323,9 @@ struct TableMakerMC { 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 @@ -399,7 +406,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(); @@ -415,7 +422,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)); } } @@ -431,7 +438,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)); } } @@ -442,33 +449,34 @@ struct TableMakerMC { 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()); + collision.centFT0C(), collision.centFT0A(), collision.centFT0M()); } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMult) > 0) { 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); + -1, -1, -1); } else if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionCent) > 0) { 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()); + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, collision.centFT0C(), collision.centFT0A(), collision.centFT0M()); } else { - 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); + 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, -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()); + mcCollision.t(), mcCollision.weight(), mcCollision.impactParameter(), 1, 1, 1, 1); fEventLabels[mcCollision.globalIndex()] = fCounters[1]; 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.trackOccupancyInTimeRange()); + 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, 0.0, 0.0, 0.0, 0.0); } // loop over the MC truth tracks and find those that need to be written @@ -486,7 +494,7 @@ struct TableMakerMC { checked = sig.CheckSignal(true, mctrack); } if (checked) { - mcflags |= (uint16_t(1) << i); + mcflags |= (static_cast(1) << i); } i++; } @@ -507,7 +515,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); } } @@ -541,8 +549,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()) { @@ -578,23 +586,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 @@ -602,7 +610,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) { @@ -650,7 +658,72 @@ struct TableMakerMC { track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()); } } // end loop over reconstructed tracks - } // end if constexpr (static_cast(TTrackFillMap)) + } // 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 @@ -669,10 +742,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; @@ -693,10 +767,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++; } @@ -721,8 +791,8 @@ struct TableMakerMC { } } - trackFilteringTag = uint64_t(0); - trackTempFilterMap = uint8_t(0); + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); if (!muon.has_mcParticle()) { continue; @@ -745,7 +815,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); } @@ -757,7 +826,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 @@ -765,8 +834,9 @@ 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 : fMuonCuts) { if (trackTempFilterMap & (uint8_t(1) << j)) { fHistMan->FillHistClass(Form("Muons_%s_%s", cut.GetName(), sig.GetName()), VarManager::fgValues); // fill the reconstructed truth @@ -792,16 +862,28 @@ 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 + + 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; } + + // 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) { @@ -809,7 +891,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], @@ -838,7 +920,7 @@ struct TableMakerMC { muonLabels(fNewLabels.find(mctrack.index())->second, muon.mcMask(), mcflags); } } // end if constexpr (static_cast(TMuonFillMap)) - } // end loop over collisions + } // 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) { @@ -886,7 +968,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)); } } @@ -959,7 +1041,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(); @@ -975,7 +1057,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)); } } @@ -991,7 +1073,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)); } } @@ -1002,24 +1084,24 @@ struct TableMakerMC { 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()); + collision.centFT0C(), collision.centFT0A(), collision.centFT0M()); } 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); + -1, -1, -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()); + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, collision.centFT0C(), collision.centFT0A(), collision.centFT0M()); } 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(), bc.triggerMask(), bc.timestamp(), triggerAliases, VarManager::fgValues[VarManager::kCentVZERO], -1, -1, -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()); + mcCollision.t(), mcCollision.weight(), mcCollision.impactParameter(), 1, 1, 1, 1); fEventLabels[mcCollision.globalIndex()] = fCounters[1]; fCounters[1]++; } @@ -1040,7 +1122,7 @@ struct TableMakerMC { checked = sig.CheckSignal(true, mctrack); } if (checked) { - mcflags |= (uint16_t(1) << i); + mcflags |= (static_cast(1) << i); } i++; } @@ -1061,7 +1143,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); } } @@ -1090,8 +1172,8 @@ struct TableMakerMC { isAmbiguous = (track.compatibleCollIds().size() != 1); } } - 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()) { @@ -1127,23 +1209,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 @@ -1151,7 +1233,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) { @@ -1199,7 +1281,7 @@ struct TableMakerMC { track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()); } } // end loop over reconstructed tracks - } // end if constexpr (static_cast(TTrackFillMap)) + } // end if constexpr (static_cast(TTrackFillMap)) if constexpr (static_cast(TMuonFillMap)) { // build the muon tables @@ -1218,11 +1300,12 @@ struct TableMakerMC { int idxPrev = -1; std::map newEntryNb; std::map newMatchIndex; + std::map newMFTMatchIndex; for (auto& muonId : fwdtrackIdsThisCollision) { auto muon = muonId.template fwdtrack_as(); - trackFilteringTag = uint64_t(0); - trackTempFilterMap = uint8_t(0); + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); if (!muon.has_mcParticle()) { continue; @@ -1243,10 +1326,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++; } @@ -1266,8 +1345,8 @@ struct TableMakerMC { } } - trackFilteringTag = uint64_t(0); - trackTempFilterMap = uint8_t(0); + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); if (!muon.has_mcParticle()) { continue; @@ -1304,7 +1383,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 @@ -1312,8 +1391,9 @@ 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 : fMuonCuts) { if (trackTempFilterMap & (uint8_t(1) << j)) { fHistMan->FillHistClass(Form("Muons_%s_%s", cut.GetName(), sig.GetName()), VarManager::fgValues); // fill the reconstructed truth @@ -1379,7 +1459,7 @@ struct TableMakerMC { muonLabels(fNewLabels.find(mctrack.index())->second, muon.mcMask(), mcflags); } } // end if constexpr (static_cast(TMuonFillMap)) - } // end loop over collisions + } // 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) { @@ -1427,7 +1507,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)); } } @@ -1529,14 +1609,14 @@ struct TableMakerMC { 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); + 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); + fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mcEvents, mcTracks, nullptr, nullptr, nullptr); } // Produce barrel only tables ------------------------------------------------------------------------------------ @@ -1544,7 +1624,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 multiplicity ------------------------------------------------------------------------------------ @@ -1552,7 +1632,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 ------------------------------------------------------------------------------------ @@ -1560,7 +1640,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 ------------------------------------------------------------------- @@ -1568,7 +1648,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----------------------------------------------------------------------- @@ -1576,7 +1656,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, multiplicity and cov matrix ------------------------------------------------------------------- @@ -1584,7 +1664,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 and dalitz bits----------------------------------------------------------------------- @@ -1592,7 +1672,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 ------------------------------------------------------------------------------------ @@ -1600,21 +1680,28 @@ 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, @@ -1647,24 +1734,24 @@ struct TableMakerMC { // 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) @@ -1688,6 +1775,7 @@ struct TableMakerMC { 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); diff --git a/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx b/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx index c1161fa0d9d..a0f39c9e34b 100644 --- a/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx @@ -16,37 +16,52 @@ // 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 "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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" #include "PWGDQ/Core/MCSignal.h" #include "PWGDQ/Core/MCSignalLibrary.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGDQ/Core/MuonMatchingMlResponse.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FwdTrackReAlignTables.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" #include "Field/MagneticField.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" + #include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "CCDB/BasicCCDBManager.h" +#include "TList.h" + +#include +#include +#include +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -56,6 +71,7 @@ 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 MyMuons = soa::Join; using MyMuonsWithCov = soa::Join; +using MyMuonsRealignWithCov = soa::Join; using MyEvents = soa::Join; using MyEventsWithMults = soa::Join; -using MyEventsWithCent = soa::Join; -using MyEventsWithCentAndMults = soa::Join; - -// constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision; +using MyEventsWithMultsAndRapidityGapFilter = soa::Join; +using MyEventsWithCent = soa::Join; +using MyEventsWithCentAndMults = soa::Join; +using MFTTrackLabeled = soa::Join; +using MyEventsMcWithMults = 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 gkEventFillMapWithMultsRapidityGapFilter = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra | VarManager::ObjTypes::RapidityGapFilter; +constexpr static uint32_t gkEventMcFillMap = VarManager::ObjTypes::CollisionMC; +constexpr static uint32_t gkEventMcFillMapWithCent = VarManager::ObjTypes::CollisionMC | VarManager::ObjTypes::CollisionCent; // 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 gkMuonRealignFillMapWithCov = VarManager::ObjTypes::MuonRealign | VarManager::ObjTypes::MuonCovRealign; // 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; +constexpr static uint32_t gkMFTCovFillMap = VarManager::ObjTypes::TrackMFT | VarManager::ObjTypes::MFTCov; + +template +void PrintBitMap(TMap map, int nbits) +{ + for (int i = 0; i < nbits; i++) { + cout << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); + } +} struct TableMakerMC { @@ -127,62 +160,88 @@ struct TableMakerMC { 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 - Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; - Configurable fConfigTrackCuts{"cfgBarrelTrackCuts", "jpsiPID1", "barrel track cut"}; - Configurable fConfigMuonCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + 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 - 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"}; + 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 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 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"}; + */ // CCDB connection configurables - 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"}; - 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)"}; - - // 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"}; + 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)"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + } 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 fUseML{"cfgUseML", false, "Import ONNX model from ccdb to decide which matching candidates to keep"}; + 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"}; + Configurable fzMatching{"cfgzMatching", -77.5f, "Plane for MFT-MCH matching"}; + Configurable> fModelPathsCCDB{"fModelPathsCCDB", std::vector{"Users/m/mcoquet/MLTest"}, "Paths of models on CCDB"}; + Configurable> fInputFeatures{"cfgInputFeatures", std::vector{"chi2MCHMFT"}, "Names of ML model input features"}; + Configurable> fModelNames{"cfgModelNames", std::vector{"model.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + } 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 + 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::vector fMCSignals; std::map fLabelsMap; std::map fLabelsMapReversed; std::map fMCFlags; @@ -193,95 +252,150 @@ struct TableMakerMC { 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; + std::unordered_map map_mfttrackcovs; + + o2::analysis::MlResponseMFTMuonMatch matchingMlResponse; + std::vector binsPtMl; + std::array cutValues; + std::vector cutDirMl; + 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") || context.mOptions.get("processPbPbWithFilterBarrelOnly")); + bool isMuonEnabled = (context.mOptions.get("processPP") || context.mOptions.get("processPPMuonOnlyBasic") || context.mOptions.get("processPPMuonOnly") || context.mOptions.get("processPPRealignedMuonOnly") || context.mOptions.get("processPbPbMuonOnly") || context.mOptions.get("processPbPbRealignedMuonOnly")) || context.mOptions.get("processPPMuonRefit"); + // 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(); - VarManager::SetDefaultVarNames(); 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 TString histClasses = ""; + // Event histograms before any cuts if (fDoDetailedQA) { histClasses += "Event_BeforeCuts;"; } - if (fConfigQA) { + // Event histograms after cuts and for MC truth collisions + if (fConfigHistOutput.fConfigQA) { histClasses += "Event_AfterCuts;"; histClasses += "Event_MCTruth;"; } - bool enableBarrelHistos = (context.mOptions.get("processPP") || context.mOptions.get("processPPBarrelOnly") || context.mOptions.get("processPbPbBarrelOnly")); - bool enableMuonHistos = (context.mOptions.get("processPP") || context.mOptions.get("processPPMuonOnly") || context.mOptions.get("processPbPbMuonOnly")); - - LOG(info) << "enable barrel/muon histograms :: " << enableBarrelHistos << " / " << enableMuonHistos; - - // TODO: switch on/off histogram classes depending on which process function we run - if (enableBarrelHistos) { + if (isBarrelEnabled) { + // Barrel track histograms before cuts if (fDoDetailedQA) { histClasses += "TrackBarrel_BeforeCuts;"; } - if (fConfigQA) { + // Barrel track histograms after cuts; one directory per cut + if (fConfigHistOutput.fConfigQA) { for (auto& cut : fTrackCuts) { - histClasses += Form("TrackBarrel_%s;", cut.GetName()); + histClasses += Form("TrackBarrel_%s;", cut->GetName()); } } } - if (enableMuonHistos) { + if (isMuonEnabled) { + // Muon track histograms before cuts if (fDoDetailedQA) { histClasses += "Muons_BeforeCuts;"; } - if (fConfigQA) { + // Muon track histograms after cuts; one directory per cut + if (fConfigHistOutput.fConfigQA) { for (auto& muonCut : fMuonCuts) { - histClasses += Form("Muons_%s;", muonCut.GetName()); + 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); - if (fConfigQA) { - histClasses += Form("MCTruth_%s;", objArray->At(isig)->GetName()); - } - } else { - continue; + fMCSignals.push_back(sig); } - if (fDoDetailedQA) { - if (enableBarrelHistos) { - for (auto& cut : fTrackCuts) { - histClasses += Form("TrackBarrel_%s_%s;", cut.GetName(), objArray->At(isig)->GetName()); - } + } + } + // 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 (enableMuonHistos) { - for (auto& cut : fMuonCuts) { - histClasses += Form("Muons_%s_%s;", cut.GetName(), objArray->At(isig)->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 + 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()); - fCCDB->setURL(fConfigCcdbUrl); + // Setup the CCDB + fCCDB->setURL(fConfigCCDB.fConfigCcdbUrl); fCCDB->setCaching(true); fCCDB->setLocalObjectValidityChecking(); if (!o2::base::GeometryManager::isGeometryLoaded()) { - fCCDB->get(geoPath); + fCCDB->get(fConfigCCDB.fGeoPath); + } + fCCDBApi.init(fConfigCCDB.fConfigCcdbUrl.value); + VarManager::SetMatchingPlane(fConfigVariousOptions.fzMatching.value); + + if (fConfigVariousOptions.fUseML.value) { + // TODO : for now we use hard coded values since the current models use 1 pT bin + binsPtMl = {-1e-6, 1000.0}; + cutValues = {0.0}; + cutDirMl = {cuts_ml::CutNot}; + o2::framework::LabeledArray mycutsMl(cutValues.data(), 1, 1, std::vector{"pT bin 0"}, std::vector{"score"}); + matchingMlResponse.configure(binsPtMl, mycutsMl, cutDirMl, 1); + matchingMlResponse.setModelPathsCCDB(fConfigVariousOptions.fModelNames.value, fCCDBApi, fConfigVariousOptions.fModelPathsCCDB.value, fConfigCCDB.timestampCCDB.value); + matchingMlResponse.cacheInputFeaturesIndices(fConfigVariousOptions.fInputFeatures.value); + matchingMlResponse.init(); } } @@ -289,24 +403,48 @@ struct TableMakerMC { { // Event cuts fEventCut = new AnalysisCompositeCut(true); - TString eventCutStr = fConfigEventCuts.value; + 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 = 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())); + } + } + // 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 = 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())); + } + } + // 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)); } } @@ -317,68 +455,109 @@ struct TableMakerMC { Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; Preslice mfttrackIndicesPerCollision = aod::track_association::collisionId; - void skimMCCollisions(aod::McCollisions const& mcCollisions) + void skimMCCollisions(MyEventsMcWithMults 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) { - VarManager::FillEvent(mcCollision); + // 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()); + mcCollision.t(), mcCollision.weight(), mcCollision.impactParameter(), mcCollision.bestCollisionCentFT0C(), + mcCollision.multMCNParticlesEta05(), mcCollision.multMCNParticlesEta08(), mcCollision.multMCNParticlesEta10()); } } - void skimMCParticles(aod::McParticles const& mcTracks, aod::McCollisions const&) + void skimMCParticles(aod::McParticles const& mcTracks, MyEventsMcWithMults const&) { - // select MC particles which fulfill at least one of the specified MC signals + // 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 = 0; + 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 a decision bit map + // 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(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++; } + + /*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 (!(fLabelsMap.find(mctrack.globalIndex()) != fLabelsMap.end())) { + // 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++; - // 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) { + if (fConfigHistOutput.fConfigQA) { VarManager::FillTrackMC(mcTracks, mctrack); - VarManager::FillEvent(mctrack.mcCollision()); + auto mcCollision = mctrack.template mcCollision_as(); + VarManager::FillEvent(mcCollision); int j = 0; for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, j++) { - if (mcflags & (uint16_t(1) << j)) { - fHistMan->FillHistClass(Form("MCTruth_%s", (*signal).GetName()), VarManager::fgValues); + if (mcflags & (static_cast(1) << j)) { + fHistMan->FillHistClass(Form("MCTruth_%s", (*signal)->GetName()), VarManager::fgValues); } } } @@ -389,7 +568,9 @@ struct TableMakerMC { template void skimCollisions(TEvents const& collisions, BCsWithTimestamps const& /*bcs*/) { - // Skim collisions + // 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; @@ -403,9 +584,13 @@ struct TableMakerMC { int multTracklets = -1.0; int multTracksPV = -1.0; float centFT0C = -1.0; + float centFT0A = -1.0; + float centFT0M = -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)); @@ -415,18 +600,26 @@ struct TableMakerMC { auto bc = collision.template bc_as(); // store the selection decisions - uint64_t tag = 0; + 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() + // 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 |= (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::RapidityGapFilter) > 0) { + tag |= (collision.eventFilter() << 56); } + // 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 - VarManager::FillEvent(collision.mcCollision()); + if (collision.has_mcCollision()) { + auto mcCollision = collision.template mcCollision_as(); + VarManager::FillEvent(mcCollision); + } if (fDoDetailedQA) { fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); } @@ -439,6 +632,7 @@ struct TableMakerMC { } (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; } @@ -451,38 +645,43 @@ struct TableMakerMC { } (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(); + 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(); + centFT0A = collision.centFT0A(); + centFT0M = collision.centFT0M(); } 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); + multTPC, multFV0A, multFV0C, multFT0A, multFT0C, multFDDA, multFDDC, multZNA, multZNC, multTracklets, multTracksPV, centFT0C, centFT0A, centFT0M); 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.trackOccupancyInTimeRange()); + 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, 0.0, 0.0, 0.0, 0.0); } + // add an element for this collision into the map fCollIndexMap[collision.globalIndex()] = event.lastIndex(); } } @@ -490,44 +689,49 @@ struct TableMakerMC { template void skimTracks(TEvent const& collision, TTracks const& /*tracks*/, TrackAssoc const& assocs, aod::McParticles const& mcTracks) { - // Skim the barrel tracks - // Loop over the collision-track associations, retrieve the track, and apply track cuts for selection - // Tracks are written only once, even if they constribute to more than one association - // It is assumed that we do not apply cuts which depend on the track-collision association at the skimming time (e.g. DCA) - - uint64_t trackFilteringTag = uint64_t(0); - uint64_t trackTempFilterMap = uint8_t(0); - uint16_t mcflags = 0; + // 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 this track exists already in the index map, it was checked already. - // So at this point we just skim the association and continue - // NOTE: This means we do not make cuts based on the barrel track-collision association in the skimming - if (fTrackIndexMap.find(track.globalIndex()) != fTrackIndexMap.end()) { - trackBarrelAssoc(fCollIndexMap[collision.globalIndex()], fTrackIndexMap[track.globalIndex()]); + // 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; } - // Here we have new tracks - trackFilteringTag = uint64_t(0); - trackTempFilterMap = uint8_t(0); + 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 stats histogram + // 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 |= (uint8_t(1) << i); - // NOTE: the QA is filled here for every (collision,track) association - // 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); + if (fConfigHistOutput.fConfigQA) { + fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut)->GetName()), VarManager::fgValues); } (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); } @@ -536,9 +740,16 @@ struct TableMakerMC { continue; } - // store selection information in the track tag + // 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 |= 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)); @@ -546,18 +757,17 @@ struct TableMakerMC { } } // 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 // 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 = -1; - if (track.has_collision() && - fCollIndexMap.find(track.collisionId()) != fCollIndexMap.end()) { // if the original track collisionId is from a not skimmed collision, keep -1 as coll index - reducedEventIdx = fCollIndexMap[track.collisionId()]; - } + 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(), @@ -594,13 +804,14 @@ struct TableMakerMC { 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 |= (uint16_t(1) << i); + 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 + fHistMan->FillHistClass(Form("TrackBarrel_%s_%s", cut->GetName(), sig->GetName()), VarManager::fgValues); // fill the reconstructed truth } j++; } @@ -624,15 +835,18 @@ struct TableMakerMC { } // end loop over associations } // end skimTracks - template - void skimMFT(TEvent const& collision, MFTTracks const& /*mfts*/, MFTTrackAssoc const& mftAssocs) + 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(); + auto track = assoc.template mfttrack_as(); - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { VarManager::FillTrack(track); fHistMan->FillHistClass("MftTracks", VarManager::fgValues); } @@ -640,48 +854,162 @@ struct TableMakerMC { // 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()); - // TODO: We are not writing the DCA at the moment, because this depend on the collision association + 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 skimMuons(TEvent const& collision, TMuons const& muons, FwdTrackAssoc const& muonAssocs, aod::McParticles const& mcTracks, MFTTracks const& /*mftTracks*/) + 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 (fConfigVariousOptions.fUseML.value) { + std::vector output; + std::vector inputML = matchingMlResponse.getInputFeaturesTest(muon); + matchingMlResponse.isSelectedMl(inputML, 0, output); + chi2 = output[0]; + } + 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 skimBestMuonMatchesML(TMuons const& muons, TMFTTracks const& /*mfttracks*/, TMFTCovs const& mfCovs, TEvent const& collision) + { + std::unordered_map> mCandidates; + for (const auto& muon : muons) { + if (static_cast(muon.trackType()) < 2) { + auto muonID = muon.matchMCHTrackId(); + auto muontrack = muon.template matchMCHTrack_as(); + auto mfttrack = muon.template matchMFTTrack_as(); + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + o2::track::TrackParCovFwd mftprop = VarManager::FwdToTrackPar(mfttrack, mfttrackcov); + o2::dataformats::GlobalFwdTrack muonprop = VarManager::FwdToTrackPar(muontrack, muontrack); + if (fConfigVariousOptions.fzMatching.value < 0.) { + mftprop = VarManager::PropagateFwd(mfttrack, mfttrackcov, fConfigVariousOptions.fzMatching.value); + muonprop = VarManager::PropagateMuon(muontrack, collision, VarManager::kToMatching); + } + std::vector output; + std::vector inputML = matchingMlResponse.getInputFeaturesGlob(muon, muonprop, mftprop, collision); + matchingMlResponse.isSelectedMl(inputML, 0, output); + float score = output[0]; + if (mCandidates.find(muonID) == mCandidates.end()) { + mCandidates[muonID] = {score, muon.globalIndex()}; + } else { + if (score < mCandidates[muonID].first) { + mCandidates[muonID] = {score, 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*/, TMFTCovs const& mfCovs) { // 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); + uint8_t trackFilteringTag = static_cast(0); + uint8_t trackTempFilterMap = static_cast(0); fFwdTrackIndexMapReversed.clear(); - uint16_t mcflags = 0; + 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(); + auto muon = muons.rawIteratorAt(assoc.fwdtrackId()); + if (fConfigVariousOptions.fKeepBestMatch && static_cast(muon.trackType()) < 2) { + if (fBestMatch.find(muon.globalIndex()) == fBestMatch.end()) { + continue; + } + } trackFilteringTag = uint8_t(0); + trackTempFilterMap = uint8_t(0); + + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonRealign)) { + // Check refit flag in case of realigned muons + if (static_cast(muon.isRemovable())) { + continue; + } + } + 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 (fPropMuon) { + if (fConfigVariousOptions.fPropMuon) { VarManager::FillPropagateMuon(muon, collision); } // recalculte pDca and global muon kinematics - if (static_cast(muon.trackType()) < 2 && fRefitGlobalMuon) { + if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { auto muontrack = muon.template matchMCHTrack_as(); - auto mfttrack = muon.template matchMFTTrack_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); + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + } else { + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } } else { VarManager::FillTrackCollision(muon, collision); } @@ -689,13 +1017,13 @@ struct TableMakerMC { if (fDoDetailedQA) { fHistMan->FillHistClass("Muons_BeforeCuts", VarManager::fgValues); } - // check the cuts and filters + // 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)) { + if ((*cut)->IsSelected(VarManager::fgValues)) { trackTempFilterMap |= (uint8_t(1) << i); - if (fConfigQA) { - fHistMan->FillHistClass(Form("Muons_%s", (*cut).GetName()), VarManager::fgValues); + if (fConfigHistOutput.fConfigQA) { + fHistMan->FillHistClass(Form("Muons_%s", (*cut)->GetName()), VarManager::fgValues); } (reinterpret_cast(fStatsList->At(2)))->Fill(static_cast(i)); } @@ -729,12 +1057,13 @@ struct TableMakerMC { 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 |= (uint16_t(1) << i); + if (sig->CheckSignal(true, mctrack)) { + mcflags |= (static_cast(1) << i); if (fDoDetailedQA) { + j = 0; 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 + fHistMan->FillHistClass(Form("Muons_%s_%s", cut->GetName(), sig->GetName()), VarManager::fgValues); // fill the reconstructed truth } j++; } @@ -752,7 +1081,7 @@ struct TableMakerMC { trackCounter++; } - } // end if (has_mcParticle) + } // end if (has_mcParticle) } else { // if muon already in the map, make a bitwise OR with previous existing cuts fFwdTrackFilterMap[muon.globalIndex()] |= trackFilteringTag; } @@ -784,27 +1113,42 @@ struct TableMakerMC { mftIdx = fMftIndexMap[muon.matchMFTTrackId()]; } } + + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonRealign)) { + // Check refit flag in case of realigned muons + if (static_cast(muon.isRemovable())) { + continue; + } + } + VarManager::FillTrack(muon); - if (fPropMuon) { + if (fConfigVariousOptions.fPropMuon) { VarManager::FillPropagateMuon(muon, collision); } // recalculte pDca and global muon kinematics - if (static_cast(muon.trackType()) < 2 && fRefitGlobalMuon) { + int globalClusters = muon.nClusters(); + if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { auto muontrack = muon.template matchMCHTrack_as(); - auto mfttrack = muon.template matchMFTTrack_as(); + auto mfttrack = muon.template matchMFTTrack_as(); + globalClusters += mfttrack.nClusters(); VarManager::FillTrackCollision(muontrack, collision); - VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + } else { + 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(), + muonExtra(globalClusters, VarManager::fgValues[VarManager::kMuonPDca], VarManager::fgValues[VarManager::kMuonRAtAbsorberEnd], + 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()); - if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov)) { + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCov) || static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCovRealign)) { 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], @@ -819,25 +1163,36 @@ struct TableMakerMC { } // end loop over selected muons } // end skimMuons - template + 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) + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles, TMFTCov const& mftCovs) { + // Check whether the run changed and update CCDB if it did if (bcs.size() > 0 && fCurrentRun != bcs.begin().runNumber()) { if (fIsRun2 == true) { - grpmagrun2 = fCCDB->getForTimeStamp(grpmagPathRun2, bcs.begin().timestamp()); - if (grpmagrun2 != nullptr) { - o2::base::Propagator::initFieldFromGRP(grpmagrun2); + fGrpMagRun2 = fCCDB->getForTimeStamp(fConfigCCDB.fGrpMagPathRun2, bcs.begin().timestamp()); + if (fGrpMagRun2 != nullptr) { + o2::base::Propagator::initFieldFromGRP(fGrpMagRun2); } } else { - grpmag = fCCDB->getForTimeStamp(grpmagPath, bcs.begin().timestamp()); - if (grpmag != nullptr) { - o2::base::Propagator::initFieldFromGRP(grpmag); + fGrpMag = fCCDB->getForTimeStamp(fConfigCCDB.fGrpMagPath, bcs.begin().timestamp()); + if (fGrpMag != nullptr) { + o2::base::Propagator::initFieldFromGRP(fGrpMag); + VarManager::SetMagneticField(fGrpMag->getNominalL3Field()); + } + 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(); } @@ -845,10 +1200,6 @@ struct TableMakerMC { 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()); @@ -860,6 +1211,13 @@ struct TableMakerMC { return; } + // 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 + // Only skim MC particles when the MC collision is reconstructed + // Because in the first five DFs of each run, the MC collisions are not reconstructed + skimMCParticles(mcParticles, mcCollisions); + + // Clear index map and reserve memory for barrel tables if constexpr (static_cast(TTrackFillMap)) { fTrackIndexMap.clear(); trackBarrelInfo.reserve(tracksBarrel.size()); @@ -871,16 +1229,21 @@ struct TableMakerMC { trackBarrelLabels.reserve(tracksBarrel.size()); } + // Clear index map and reserve memory for MFT tables if constexpr (static_cast(TMFTFillMap)) { fMftIndexMap.clear(); + map_mfttrackcovs.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()); @@ -888,6 +1251,12 @@ struct TableMakerMC { muonLabels.reserve(muons.size()); } + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + for (auto& mfttrackConv : mftCovs) { + map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + } + } + // loop over selected collisions and select the tracks and fwd tracks to be skimmed if (fCollIndexMap.size() > 0) { for (auto const& [origIdx, skimIdx] : fCollIndexMap) { @@ -899,11 +1268,29 @@ struct TableMakerMC { } if constexpr (static_cast(TMFTFillMap)) { auto groupedMFTIndices = mftAssocs.sliceBy(mfttrackIndicesPerCollision, origIdx); - skimMFT(collision, mftTracks, groupedMFTIndices); + skimMFT(collision, mftTracks, groupedMFTIndices, mcParticles); } - if constexpr (static_cast(TMuonFillMap) && static_cast(TMFTFillMap)) { - auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); - skimMuons(collision, muons, groupedMuonIndices, mcParticles, mftTracks); + if constexpr (static_cast(TMuonFillMap)) { + if constexpr (static_cast(TMFTFillMap)) { + auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); + if (fConfigVariousOptions.fKeepBestMatch) { + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + if (fConfigVariousOptions.fUseML.value) { + skimBestMuonMatchesML(muons, mftTracks, mftCovs, collision); + } + } else { + skimBestMuonMatches(muons); + } + } + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + skimMuons(collision, muons, groupedMuonIndices, mcParticles, mftTracks, mftCovs); + } else { + skimMuons(collision, muons, groupedMuonIndices, mcParticles, mftTracks, nullptr); + } + } else { + auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); + skimMuons(collision, muons, groupedMuonIndices, mcParticles, nullptr, nullptr); + } } } // end loop over skimmed collisions } @@ -950,12 +1337,13 @@ struct TableMakerMC { } // 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(), + auto mcCollision = mctrack.template mcCollision_as(); + trackMC(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 & (uint16_t(1) << isig)) { + if (mcflags & (static_cast(1) << isig)) { (reinterpret_cast(fStatsList->At(3)))->Fill(static_cast(isig)); } } @@ -970,36 +1358,36 @@ struct TableMakerMC { 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()); } - TString histEventName = fConfigAddEventHistogram.value; + TString histEventName = fConfigHistOutput.fConfigAddEventHistogram.value; if (classStr.Contains("Event")) { - if (fConfigQA && !classStr.Contains("MCTruth")) { + 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 = 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 histMCTruthName = fConfigAddMCTruthHistogram.value; + TString histMCTruthName = fConfigHistOutput.fConfigAddMCTruthHistogram.value; if (classStr.Contains("MCTruth") && !classStr.Contains("Event")) { - if (fConfigQA) { + if (fConfigHistOutput.fConfigQA) { dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "mctruth_track", histMCTruthName); } } @@ -1024,7 +1412,7 @@ struct TableMakerMC { 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()); + 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++) { @@ -1034,62 +1422,117 @@ struct TableMakerMC { 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()); + 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(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, aod::MFTTracks const& mftTracks, + 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) + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) { - fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles, nullptr); } void processPPBarrelOnly(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, MyBarrelTracksWithCov const& tracksBarrel, aod::TrackAssoc const& trackAssocs, - aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, mcCollisions, mcParticles, nullptr); + } + + void processPPMuonOnlyBasic(MyEvents const& collisions, aod::BCsWithTimestamps const& bcs, + MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, mcCollisions, mcParticles); + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles, nullptr); } void processPPMuonOnly(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, - MyMuonsWithCov const& tracksMuon, aod::MFTTracks const& mftTracks, + MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, - aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles, nullptr); + } + + void processPPMuonRefit(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles, aod::MFTTracksCov const& mftCovs) { - fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles, mftCovs); + } + + void processPPRealignedMuonOnly(MyEventsWithMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyMuonsRealignWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles, nullptr); } void processPbPb(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, - MyBarrelTracksWithCov const& tracksBarrel, MyMuonsWithCov const& tracksMuon, aod::MFTTracks const& mftTracks, + 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) + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) { - fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + fullSkimming(collisions, bcs, tracksBarrel, tracksMuon, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles, nullptr); } void processPbPbBarrelOnly(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, MyBarrelTracksWithCov const& tracksBarrel, aod::TrackAssoc const& trackAssocs, - aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) { - fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, mcCollisions, mcParticles); + fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, mcCollisions, mcParticles, nullptr); + } + + void processPbPbWithFilterBarrelOnly(MyEventsWithMultsAndRapidityGapFilter const& collisions, aod::BCsWithTimestamps const& bcs, + MyBarrelTracksWithCov const& tracksBarrel, aod::TrackAssoc const& trackAssocs, + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, mcCollisions, mcParticles, nullptr); } void processPbPbMuonOnly(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, - MyMuonsWithCov const& tracksMuon, aod::MFTTracks const& mftTracks, + MyMuonsWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, - aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) + { + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles, nullptr); + /*LOGP(info, "---------------------------"); + for (auto& mcCollision : mcCollisions) { + LOGP(info, "Gen. FT0C centrality = {}", mcCollision.bestCollisionCentFT0C()); + //LOGP(info, "Gen. FT0C centrality = {}", mcCollision.posZ()); + } + for (const auto& collision : collisions) { + if (collision.has_mcCollision()) { + LOGP(info, "*************************"); + auto mcCollision = collision.template mcCollision_as(); + //LOGP(info, "Gen. FT0C centrality = {}", collision.mcCollision().posZ()); + LOGP(info, "Gen. FT0C centrality = {}", mcCollision.bestCollisionCentFT0C()); + LOGP(info, "Rec. FT0C centrality = {}", collision.centFT0C()); + LOGP(info, "*************************"); + } + } + LOGP(info, "---------------------------");*/ + } + + void processPbPbRealignedMuonOnly(MyEventsWithCentAndMults const& collisions, aod::BCsWithTimestamps const& bcs, + MyMuonsRealignWithCov const& tracksMuon, MFTTrackLabeled const& mftTracks, + aod::FwdTrackAssoc const& fwdTrackAssocs, aod::MFTTrackAssoc const& mftAssocs, + MyEventsMcWithMults const& mcCollisions, aod::McParticles const& mcParticles) { - fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles); + fullSkimming(collisions, bcs, nullptr, tracksMuon, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mcCollisions, mcParticles, nullptr); } // Process the BCs and store stats for luminosity retrieval ----------------------------------------------------------------------------------- @@ -1105,10 +1548,15 @@ struct TableMakerMC { 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, processPPMuonRefit, "Produce only muon skims, pp settings", false); + PROCESS_SWITCH(TableMakerMC, processPPRealignedMuonOnly, "Build realigned muon only DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb", 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, processPbPbWithFilterBarrelOnly, "Produce only barrel skims, pp settings with rapidity gap filter ", false); PROCESS_SWITCH(TableMakerMC, processPbPbMuonOnly, "Produce only muon skims, PbPb settings", false); + PROCESS_SWITCH(TableMakerMC, processPbPbRealignedMuonOnly, "Build realigned muon only DQ skimmed data model typically for Pb-Pb, w/o event filtering", false); PROCESS_SWITCH(TableMakerMC, processOnlyBCs, "Analyze the BCs to store sampled lumi", false); }; diff --git a/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx b/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx index a15c1a98a8c..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; diff --git a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx index c4498fb6361..9383e58143a 100644 --- a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx @@ -17,44 +17,59 @@ // 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 "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/DataTypes.h" -#include "Framework/runDataProcessing.h" -#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 "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGDQ/Core/VarManager.h" -#include "PWGDQ/Core/HistogramManager.h" -#include "PWGDQ/Core/AnalysisCut.h" +// C++ includes +#include +#include +#include +#include +#include +#include +// other includes #include "PWGDQ/Core/AnalysisCompositeCut.h" -#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/AnalysisCut.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 "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MuonMatchingMlResponse.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TableHelper.h" +#include "Common/Core/Zorro.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FwdTrackReAlignTables.h" +#include "Common/DataModel/MftmchMatchingML.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonDataFormat/InteractionRecord.h" -#include "DetectorsVertexing/PVertexerParams.h" -#include "MathUtils/Primitive2D.h" #include "DataFormatsGlobalTracking/RecoContainer.h" -#include "Common/DataModel/CollisionAssociationTables.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DataFormatsITSMFT/ROFRecord.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsVertexing/PVertexerParams.h" +#include "DetectorsVertexing/VertexTrackMatcher.h" #include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Primitive2D.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" + #include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "EventFiltering/Zorro.h" using namespace o2; using namespace o2::framework; @@ -63,6 +78,7 @@ 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 MyBarrelTracksWithCovNoTOF = soa::Join; using MyBarrelTracksWithV0Bits = 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 MyEventsWithCent = soa::Join; -using MyEventsWithCentAndMults = soa::Join; +using MyEventsWithMultsAndRapidityGapFilter = soa::Join; +using MyEventsWithCent = soa::Join; +using MyEventsWithCentAndMults = soa::Join; +using MyEventsWithMultsExtra = soa::Join; using MyMuons = soa::Join; using MyMuonsWithCov = soa::Join; +using MyMuonsRealignWithCov = soa::Join; using MyMuonsColl = soa::Join; using MyMuonsCollWithCov = soa::Join; -using MyBCs = 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 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::EventFilter | VarManager::ObjTypes::Zdc; +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 gkEventFillMapWithMultsRapidityGapFilterZdcFit = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionMult | VarManager::ObjTypes::CollisionMultExtra | VarManager::ObjTypes::RapidityGapFilter | VarManager::ObjTypes::Zdc | VarManager::ObjTypes::ReducedFit; // 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 gkTrackFillMapNoTOF = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | 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; +constexpr static uint32_t gkMuonRealignFillMapWithCov = VarManager::ObjTypes::MuonRealign | VarManager::ObjTypes::MuonCovRealign; // 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; +constexpr static uint32_t gkMFTCovFillMap = VarManager::ObjTypes::TrackMFT | VarManager::ObjTypes::MFTCov; + +// 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 { @@ -136,6 +168,7 @@ struct TableMaker { Produces eventVtxCov; Produces eventInfo; Produces zdc; + Produces fit; Produces multPV; Produces multAll; Produces trackBarrelInfo; @@ -159,64 +192,101 @@ struct TableMaker { 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"}; - Configurable fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro [WARNING: under debug, do not enable!]"}; - Configurable fConfigZorroTrigMask{"cfgZorroTriggerMask", "fDiMuon", "DQ Trigger masks: fSingleE,fLMeeIMR,fLMeeHMR,fDiElectron,fSingleMuLow,fSingleMuHigh,fDiMuon"}; + 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 fConfigCcdbPathZorro{"ccdb-path-zorro", "Users/r/rlietava/EventFiltering/OTS/", "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 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"}; - - // Track related options - Configurable fPropTrack{"cfgPropTrack", true, "Propgate 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"}; + struct : ConfigurableGroup { + Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas(electrons, pions, protons)"}; + Configurable fConfigTPCpostCalibType{"cfgTPCpostCalibType", 1, "1: (TPCncls,pIN,eta) calibration typically for pp, 2: (eta,nPV,nLong,tLong) calibration typically for PbPb"}; + Configurable fConfigTPCuseInterpolatedCalib{"cfgTPCpostCalibUseInterpolation", true, "If true, use interpolated calibration values (default: true)"}; + 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"}; + } 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 fKeepBestMatch{"cfgKeepBestMatch", false, "Keep only the best match global muons in the skimming"}; + Configurable fUseML{"cfgUseML", false, "Import ONNX model from ccdb to decide which matching candidates to keep"}; + 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"}; + Configurable fzMatching{"cfgzMatching", -77.5f, "Plane for MFT-MCH matching"}; + Configurable> fModelPathsCCDB{"fModelPathsCCDB", std::vector{"Users/m/mcoquet/MLTest"}, "Paths of models on CCDB"}; + Configurable> fInputFeatures{"cfgInputFeatures", std::vector{"chi2MCHMFT"}, "Names of ML model input features"}; + Configurable> fModelNames{"cfgModelNames", std::vector{"model.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + + // 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 + AnalysisCompositeCut* fEventCut; //! Event selection cut + 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. @@ -228,97 +298,165 @@ struct TableMaker { 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; + std::unordered_map map_mfttrackcovs; + + o2::analysis::MlResponseMFTMuonMatch matchingMlResponse; + std::vector binsPtMl; + std::array cutValues; + std::vector cutDirMl; + // FIXME: For now, the skimming is done using the Common track-collision association task, which does not allow to use // 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))); + + Preslice presliceWithCovNoTOF = aod::track::collisionId; + Partition tracksPosWithCovNoTOF = (((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)) && (aod::track::tgl > static_cast(0.05))); + Partition tracksNegWithCovNoTOF = (((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)) && (aod::track::tgl < static_cast(-0.05))); + + Preslice presliceWithCov = aod::track::collisionId; + Partition tracksPosWithCov = (((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)) && (aod::track::tgl > static_cast(0.05))); + Partition tracksNegWithCov = (((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") || - context.mOptions.get("processPbPb") || context.mOptions.get("processPbPbMuonOnly") || context.mOptions.get("processPbPbMuonMFT")); + // 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") || context.mOptions.get("processPbPbBarrelOnlyNoTOF"); + + bool enableMuonHistos = (context.mOptions.get("processPPWithFilter") || context.mOptions.get("processPPWithFilterMuonOnly") || context.mOptions.get("processPPWithFilterMuonMFT") || context.mOptions.get("processPPMuonOnly") || context.mOptions.get("processPPRealignedMuonOnly") || context.mOptions.get("processPPMuonMFT") || context.mOptions.get("processPPMuonMFTWithMultsExtra") || + context.mOptions.get("processPbPb") || context.mOptions.get("processPbPbMuonOnly") || context.mOptions.get("processPbPbRealignedMuonOnly") || 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); + 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()); } - - DefineHistograms(histClasses); // 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); + VarManager::SetMatchingPlane(fConfigVariousOptions.fzMatching.value); + + if (fConfigVariousOptions.fUseML.value) { + // TODO : for now we use hard coded values since the current models use 1 pT bin + binsPtMl = {-1e-6, 1000.0}; + cutValues = {0.0}; + cutDirMl = {cuts_ml::CutNot}; + o2::framework::LabeledArray mycutsMl(cutValues.data(), 1, 1, std::vector{"pT bin 0"}, std::vector{"score"}); + matchingMlResponse.configure(binsPtMl, mycutsMl, cutDirMl, 1); + matchingMlResponse.setModelPathsCCDB(fConfigVariousOptions.fModelNames.value, fCCDBApi, fConfigVariousOptions.fModelPathsCCDB.value, fConfigCCDB.fConfigNoLaterThan.value); + matchingMlResponse.cacheInputFeaturesIndices(fConfigVariousOptions.fInputFeatures.value); + matchingMlResponse.init(); } } @@ -326,24 +464,50 @@ struct TableMaker { { // 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)); } } @@ -352,15 +516,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"); } @@ -372,36 +537,42 @@ 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"}; @@ -414,32 +585,223 @@ 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) 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); + 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->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 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(); } - fStatsList->Add(histMuons); + + // 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*/) + template + void skimCollisions(TEvents const& collisions, TBCs const& bcs, TZdcs const& /*zdcs*/, + TTrackAssoc const& trackAssocs, TTracks const& tracks, + TFt0s const& ft0s, TFv0as const& fv0as, TFdds const& fdds) { // 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(); @@ -455,15 +817,17 @@ struct TableMaker { int multTracklets = -1.0; int multTracksPV = -1.0; float centFT0C = -1.0; + float centFT0A = -1.0; + float centFT0M = -1.0; for (const auto& collision : collisions) { 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) { @@ -479,10 +843,10 @@ 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) { + // Put the 8 first bits of the rapidity gap filter in the last 8 bits of the tag + if constexpr ((TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { tag |= (collision.eventFilter() << 56); } @@ -490,11 +854,50 @@ struct TableMaker { VarManager::FillBC(bc); VarManager::FillEvent(collision); // extract event information and place it in the fValues array if constexpr ((TEventFillMap & VarManager::ObjTypes::Zdc) > 0) { - if (bcEvSel.has_zdc()) { + if constexpr ((TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { + // The DQRapidityGapFilter contains the index of the bc we want to get ZDC info from + auto newbc = bcs.rawIteratorAt(collision.newBcIndex()); + if (newbc.has_zdc()) { + auto newbc_zdc = newbc.zdc(); + VarManager::FillZDC(newbc_zdc); + } + } else if (bcEvSel.has_zdc()) { auto bc_zdc = bcEvSel.zdc(); VarManager::FillZDC(bc_zdc); } } + // Fill FIT info using newbc pattern for UPC events (similar to ZDC) + if constexpr ((TEventFillMap & VarManager::ObjTypes::ReducedFit) > 0) { + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + if constexpr ((TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { + auto newbc = bcs.rawIteratorAt(collision.newBcIndex()); + VarManager::FillFIT(newbc, bcs, ft0s, fv0as, fdds); + } else { + VarManager::FillFIT(bcEvSel, bcs, ft0s, fv0as, fdds); + } + } + } + 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); } @@ -502,57 +905,80 @@ 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)); + (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))); + + if (!fEventCut->IsSelected(VarManager::fgValues)) { + continue; + } - if (fConfigRunZorro) { - zorro.setBaseCCDBPath(fConfigCcdbPathZorro.value); - zorro.initCCDB(fCCDB.service, fCurrentRun, bc.timestamp(), fConfigZorroTrigMask.value); - if (zorro.isSelected(bc.globalBC())) { + 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)) { + continue; + } } else { if (!fEventCut->IsSelected(VarManager::fgValues)) { - return; + 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) { + multFV0C = collision.multFV0C(); multTPC = collision.multTPC(); + multZNA = collision.multZNA(); + multZNC = collision.multZNC(); + multTracklets = collision.multTracklets(); + multTracksPV = collision.multNTracksPV(); 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(); + centFT0A = collision.centFT0A(); + centFT0M = collision.centFT0M(); } 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); + multTPC, multFV0A, multFV0C, multFT0A, multFT0C, multFDDA, multFDDC, multZNA, multZNC, multTracklets, multTracksPV, centFT0C, centFT0A, centFT0M); 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 (bcEvSel.has_zdc()) { + if constexpr ((TEventFillMap & VarManager::ObjTypes::RapidityGapFilter) > 0) { + // The DQRapidityGapFilter contains the index of the bc we want to get ZDC info from + auto newbc = bcs.rawIteratorAt(collision.newBcIndex()); + if (newbc.has_zdc()) { + auto newbc_zdc = newbc.zdc(); + zdc(newbc_zdc.energyCommonZNA(), newbc_zdc.energyCommonZNC(), newbc_zdc.energyCommonZPA(), newbc_zdc.energyCommonZPC(), + newbc_zdc.timeZNA(), newbc_zdc.timeZNC(), newbc_zdc.timeZPA(), newbc_zdc.timeZPC()); + } else { + zdc(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0); + } + } 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()); @@ -560,11 +986,42 @@ struct TableMaker { zdc(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0); } } + // Fill FIT table if requested + if constexpr ((TEventFillMap & VarManager::ObjTypes::ReducedFit) > 0) { + fit(VarManager::fgValues[VarManager::kAmplitudeFT0A], VarManager::fgValues[VarManager::kAmplitudeFT0C], + VarManager::fgValues[VarManager::kTimeFT0A], VarManager::fgValues[VarManager::kTimeFT0C], + static_cast(VarManager::fgValues[VarManager::kTriggerMaskFT0]), + static_cast(VarManager::fgValues[VarManager::kNFiredChannelsFT0A]), + static_cast(VarManager::fgValues[VarManager::kNFiredChannelsFT0C]), + VarManager::fgValues[VarManager::kAmplitudeFDDA], VarManager::fgValues[VarManager::kAmplitudeFDDC], + VarManager::fgValues[VarManager::kTimeFDDA], VarManager::fgValues[VarManager::kTimeFDDC], + static_cast(VarManager::fgValues[VarManager::kTriggerMaskFDD]), + VarManager::fgValues[VarManager::kAmplitudeFV0A], VarManager::fgValues[VarManager::kTimeFV0A], + static_cast(VarManager::fgValues[VarManager::kTriggerMaskFV0A]), + static_cast(VarManager::fgValues[VarManager::kNFiredChannelsFV0A]), + static_cast(VarManager::fgValues[VarManager::kBBFT0Apf]), + static_cast(VarManager::fgValues[VarManager::kBGFT0Apf]), + static_cast(VarManager::fgValues[VarManager::kBBFT0Cpf]), + static_cast(VarManager::fgValues[VarManager::kBGFT0Cpf]), + static_cast(VarManager::fgValues[VarManager::kBBFV0Apf]), + static_cast(VarManager::fgValues[VarManager::kBGFV0Apf]), + static_cast(VarManager::fgValues[VarManager::kBBFDDApf]), + static_cast(VarManager::fgValues[VarManager::kBGFDDApf]), + static_cast(VarManager::fgValues[VarManager::kBBFDDCpf]), + static_cast(VarManager::fgValues[VarManager::kBGFDDCpf])); + } if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionMultExtra) > 0) { multPV(collision.multNTracksHasITS(), collision.multNTracksHasTPC(), collision.multNTracksHasTOF(), collision.multNTracksHasTRD(), - collision.multNTracksITSOnly(), collision.multNTracksTPCOnly(), collision.multNTracksITSTPC(), collision.trackOccupancyInTimeRange()); + 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); + 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(); @@ -579,23 +1036,31 @@ struct TableMaker { // 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 track + // 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 (fPropTrack && (track.collisionId() != collision.globalIndex())) { + if (fConfigVariousOptions.fPropTrack && (track.collisionId() != collision.globalIndex())) { VarManager::FillTrackCollisionMatCorr(track, collision, noMatCorr, o2::base::Propagator::Instance()); } @@ -606,98 +1071,123 @@ 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 + // TODO: this part should be removed since the calibration histogram can be filled as any other histogram + 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(), 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 = (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, TBCs const& /*bcs*/, MFTTracks const& /*mfts*/, MFTTrackAssoc const& mftAssocs) @@ -708,7 +1198,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); } @@ -716,7 +1206,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()); @@ -726,37 +1216,120 @@ struct TableMaker { } } - template - void skimMuons(TEvent const& collision, TBCs const& /*bcs*/, TMuons const& muons, FwdTrackAssoc const& muonAssocs, MFTTracks const& /*mftTracks*/) + 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 skimBestMuonMatchesML(TMuons const& muons, TMFTTracks const& /*mfttracks*/, TMFTCovs const& mfCovs, TEvent const& collision) + { + std::unordered_map> mCandidates; + for (const auto& muon : muons) { + if (static_cast(muon.trackType()) < 2) { + auto muonID = muon.matchMCHTrackId(); + auto muontrack = muon.template matchMCHTrack_as(); + auto mfttrack = muon.template matchMFTTrack_as(); + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + o2::track::TrackParCovFwd mftprop = VarManager::FwdToTrackPar(mfttrack, mfttrackcov); + o2::dataformats::GlobalFwdTrack muonprop = VarManager::FwdToTrackPar(muontrack, muontrack); + if (fConfigVariousOptions.fzMatching.value < 0.) { + mftprop = VarManager::PropagateFwd(mfttrack, mfttrackcov, fConfigVariousOptions.fzMatching.value); + muonprop = VarManager::PropagateMuon(muontrack, collision, VarManager::kToMatching); + } + std::vector output; + std::vector inputML = matchingMlResponse.getInputFeaturesGlob(muon, muonprop, mftprop, collision); + matchingMlResponse.isSelectedMl(inputML, 0, output); + float score = output[0]; + if (mCandidates.find(muonID) == mCandidates.end()) { + mCandidates[muonID] = {score, muon.globalIndex()}; + } else { + if (score < mCandidates[muonID].first) { + mCandidates[muonID] = {score, muon.globalIndex()}; + } + } + } + } + for (auto& pairCand : mCandidates) { + fBestMatch[pairCand.second.second] = true; + } + } + + template + void skimMuons(TEvent const& collision, TBCs const& /*bcs*/, TMuons const& muons, FwdTrackAssoc const& muonAssocs, TMFTTracks const& /*mftTracks*/, TMFTCovs const& mfCovs) { // 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(); uint32_t counter = 0; for (const auto& assoc : muonAssocs) { // get the muon - auto muon = assoc.template fwdtrack_as(); + auto muon = muons.rawIteratorAt(assoc.fwdtrackId()); + if (fConfigVariousOptions.fKeepBestMatch && static_cast(muon.trackType()) < 2) { + if (fBestMatch.find(muon.globalIndex()) == fBestMatch.end()) { + continue; + } + } + + trackFilteringTag = static_cast(0); + trackTempFilterMap = static_cast(0); + + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonRealign)) { + // Check refit flag in case of realigned muons + if (static_cast(muon.isRemovable())) { + continue; + } + } - trackFilteringTag = uint8_t(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 - if (fPropMuon) { + if (fConfigVariousOptions.fPropMuon) { VarManager::FillPropagateMuon(muon, collision); } - // recalculte pDca and global muon kinematics - if (static_cast(muon.trackType()) < 2 && fRefitGlobalMuon) { + // 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; + } auto mfttrack = muon.template matchMFTTrack_as(); VarManager::FillTrackCollision(muontrack, collision); - VarManager::FillGlobalMuonRefit(muontrack, mfttrack, 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 ? + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + } else { + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } } else { VarManager::FillTrackCollision(muon, collision); } @@ -767,12 +1340,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)); } } @@ -807,13 +1383,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()]; } @@ -821,75 +1397,113 @@ struct TableMaker { mftIdx = fMftIndexMap[muon.matchMFTTrackId()]; } } + + if constexpr (static_cast(TMuonFillMap & VarManager::ObjTypes::MuonRealign)) { + // Check refit flag in case of realigned muons + if (static_cast(muon.isRemovable())) { + continue; + } + } + VarManager::FillTrack(muon); - if (fPropMuon) { + if (fConfigVariousOptions.fPropMuon) { VarManager::FillPropagateMuon(muon, collision); } // recalculte pDca and global muon kinematics - if (static_cast(muon.trackType()) < 2 && fRefitGlobalMuon) { + int globalClusters = muon.nClusters(); + if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { auto muontrack = muon.template matchMCHTrack_as(); auto mfttrack = muon.template matchMFTTrack_as(); + globalClusters += mfttrack.nClusters(); VarManager::FillTrackCollision(muontrack, collision); - VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + } else { + 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(), + muonExtra(globalClusters, VarManager::fgValues[VarManager::kMuonPDca], VarManager::fgValues[VarManager::kMuonRAtAbsorberEnd], + 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()); 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) || static_cast(TMuonFillMap & VarManager::ObjTypes::MuonCovRealign)) { 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 + typename TTrackAssoc, typename TFwdTrackAssoc, typename TMFTTrackAssoc, typename TMFTCov, typename TFt0s, typename TFv0as, typename TFdds> 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) + TTrackAssoc const& trackAssocs, TFwdTrackAssoc const& fwdTrackAssocs, TMFTTrackAssoc const& mftAssocs, TMFTCov const& mftCovs, TFt0s const& ft0s, TFv0as const& fv0as, TFdds const& fdds) { - 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 (fConfigPostCalibTPC.fConfigTPCpostCalibType == 2) { + VarManager::SetCalibrationObject(VarManager::kTPCElectronStatus, calibList->FindObject("status_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCPionStatus, calibList->FindObject("status_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonStatus, calibList->FindObject("status_map_proton")); + if (fConfigPostCalibTPC.fConfigComputeTPCpostCalibKaon) { + VarManager::SetCalibrationObject(VarManager::kTPCKaonStatus, calibList->FindObject("status_map_kaon")); + } + } + VarManager::SetCalibrationType(fConfigPostCalibTPC.fConfigTPCpostCalibType, fConfigPostCalibTPC.fConfigTPCuseInterpolatedCalib); } 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); + VarManager::SetMagneticField(fGrpMag->getNominalL3Field()); + } + 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, zdcs); + event.reserve(collisions.size()); + eventExtended.reserve(collisions.size()); + eventVtxCov.reserve(collisions.size()); + + skimCollisions(collisions, bcs, zdcs, trackAssocs, tracksBarrel, ft0s, fv0as, fdds); if (fCollIndexMap.size() == 0) { return; } @@ -906,6 +1520,7 @@ struct TableMaker { if constexpr (static_cast(TMFTFillMap)) { fMftIndexMap.clear(); + map_mfttrackcovs.clear(); mftTrack.reserve(mftTracks.size()); mftTrackExtra.reserve(mftTracks.size()); mftAssoc.reserve(mftTracks.size()); @@ -914,6 +1529,7 @@ struct TableMaker { if constexpr (static_cast(TMuonFillMap)) { fFwdTrackIndexMap.clear(); fFwdTrackFilterMap.clear(); + fBestMatch.clear(); muonBasic.reserve(muons.size()); muonExtra.reserve(muons.size()); muonInfo.reserve(muons.size()); @@ -921,23 +1537,53 @@ struct TableMaker { muonAssoc.reserve(muons.size()); } - // loop over selected collisions and select the tracks and fwd tracks to be skimmed + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + for (auto& mfttrackConv : mftCovs) { + map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + } + } + + // 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); } - if constexpr (static_cast(TMuonFillMap) && static_cast(TMFTFillMap)) { - auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); - skimMuons(collision, bcs, muons, groupedMuonIndices, mftTracks); + // group the muon associations for this collision + if constexpr (static_cast(TMuonFillMap)) { + if constexpr (static_cast(TMFTFillMap)) { + auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); + if (fConfigVariousOptions.fKeepBestMatch) { + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + if (fConfigVariousOptions.fUseML.value) { + skimBestMuonMatchesML(muons, mftTracks, mftCovs, collision); + } + } else { + skimBestMuonMatches(muons); + } + } + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + skimMuons(collision, bcs, muons, groupedMuonIndices, mftTracks, mftCovs); + } else { + skimMuons(collision, bcs, muons, groupedMuonIndices, mftTracks, nullptr); + } + } else { + auto groupedMuonIndices = fwdTrackAssocs.sliceBy(fwdtrackIndicesPerCollision, origIdx); + skimMuons(collision, bcs, muons, groupedMuonIndices, nullptr, 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) @@ -947,7 +1593,7 @@ struct TableMaker { TrackAssoc const& trackAssocs, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) { - fullSkimming(collisions, bcs, nullptr, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, nullptr, nullptr, nullptr, nullptr); } // 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) @@ -955,18 +1601,14 @@ struct TableMaker { 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, zdcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + fullSkimming(collisions, bcs, zdcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, nullptr, nullptr, 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, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr); + fullSkimming(collisions, bcs, nullptr, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr, nullptr, nullptr, nullptr, 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) @@ -974,7 +1616,53 @@ struct TableMaker { MyMuonsWithCov const& muons, MFTTracks const& mftTracks, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) { - fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs); + fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, nullptr, nullptr, nullptr, nullptr); + } + + // 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, nullptr, nullptr, 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, nullptr, nullptr, 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, nullptr, nullptr, nullptr, nullptr); + } + + // produce the realigned muon-only DQ skimmed data model typically for pp/p-Pb or UPC Pb-Pb (no centrality), meant to run on skimmed data + void processPPRealignedMuonOnly(MyEventsWithMults const& collisions, BCsWithTimestamps const& bcs, + MyMuonsRealignWithCov const& muons, FwdTrackAssoc const& fwdTrackAssocs) + { + fullSkimming(collisions, bcs, nullptr, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr, nullptr, nullptr, nullptr, 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, nullptr, nullptr, nullptr, nullptr); + } + + // 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, nullptr, nullptr, nullptr, nullptr); } // produce the full DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter @@ -984,7 +1672,7 @@ struct TableMaker { TrackAssoc const& trackAssocs, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) { - fullSkimming(collisions, bcs, nullptr, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, nullptr, nullptr, nullptr, nullptr); } // produce the barrel only DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter @@ -992,14 +1680,57 @@ struct TableMaker { MyBarrelTracksWithCov const& tracksBarrel, TrackAssoc const& trackAssocs) { - fullSkimming(collisions, bcs, nullptr, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + } + + // produce the barrel only DQ skimmed data model typically for Pb-Pb (with centrality), no TOF + void processPbPbBarrelOnlyNoTOF(MyEventsWithCentAndMults const& collisions, BCsWithTimestamps const& bcs, + MyBarrelTracksWithCovNoTOF const& tracksBarrel, + TrackAssoc const& trackAssocs) + { + computeOccupancyEstimators(collisions, tracksPosWithCovNoTOF, tracksNegWithCovNoTOF, presliceWithCovNoTOF, bcs); + fullSkimming(collisions, bcs, nullptr, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, nullptr, nullptr, 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, aod::FT0s& ft0s, aod::FV0As& fv0as, aod::FDDs& fdds) + { + computeOccupancyEstimators(collisions, tracksPosWithCov, tracksNegWithCov, presliceWithCov, bcs); + fullSkimming(collisions, bcs, zdcs, tracksBarrel, nullptr, nullptr, trackAssocs, nullptr, nullptr, nullptr, ft0s, fv0as, fdds); + } + + // 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, nullptr, nullptr, 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, nullptr, nullptr, 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, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr); + fullSkimming(collisions, bcs, nullptr, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr, nullptr, nullptr, nullptr, nullptr); + } + + // produce the realigned muon only DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter + void processPbPbRealignedMuonOnly(MyEventsWithCentAndMults const& collisions, BCsWithTimestamps const& bcs, + MyMuonsRealignWithCov const& muons, FwdTrackAssoc const& fwdTrackAssocs) + { + fullSkimming(collisions, bcs, nullptr, nullptr, muons, nullptr, nullptr, fwdTrackAssocs, nullptr, nullptr, nullptr, nullptr, nullptr); } // produce the muon+mft DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter @@ -1007,7 +1738,16 @@ struct TableMaker { MyMuonsWithCov const& muons, MFTTracks const& mftTracks, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs) { - fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs); + fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, nullptr, nullptr, nullptr, nullptr); + } + + // produce the muon+mft DQ skimmed data model typically including MFT covariances + void processPPMuonRefit(MyEventsWithMults const& collisions, BCsWithTimestamps const& bcs, + MyMuonsWithCov const& muons, MFTTracks const& mftTracks, + FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs, + aod::MFTTracksCov const& mftCovs) + { + fullSkimming(collisions, bcs, nullptr, nullptr, muons, mftTracks, nullptr, fwdTrackAssocs, mftAssocs, mftCovs, nullptr, nullptr, nullptr); } // Process the BCs and store stats for luminosity retrieval ----------------------------------------------------------------------------------- @@ -1015,19 +1755,30 @@ 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, processPPRealignedMuonOnly, "Build realigned 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, processPbPbBarrelOnlyNoTOF, "Build barrel only DQ skimmed data model typically for Pb-Pb, w/o event filtering, no TOF", 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, processPbPbRealignedMuonOnly, "Build realigned 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 7ba233973ab..0b57b90f48f 100644 --- a/PWGDQ/Tasks/CMakeLists.txt +++ b/PWGDQ/Tasks/CMakeLists.txt @@ -11,12 +11,12 @@ o2physics_add_dpl_workflow(table-reader SOURCES tableReader.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(table-reader-with-assoc SOURCES tableReader_withAssoc.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::PWGDQCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::PWGDQCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(efficiency @@ -41,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 @@ -102,4 +102,39 @@ 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) + +o2physics_add_dpl_workflow(model-converter-event-extended + SOURCES ModelConverterEventExtended.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(model-converter-mc-reduced-event + SOURCES ModelConverterReducedMCEvents.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tag-and-probe + SOURCES TagAndProbe.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::PWGDQCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(qa-matching + SOURCES qaMatching.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore + COMPONENT_NAME Analysis) diff --git a/PWGDQ/Tasks/DalitzSelection.cxx b/PWGDQ/Tasks/DalitzSelection.cxx old mode 100755 new mode 100644 index 6b285d4e04a..c0023ff8de7 --- a/PWGDQ/Tasks/DalitzSelection.cxx +++ b/PWGDQ/Tasks/DalitzSelection.cxx @@ -13,26 +13,29 @@ // It can produce track and pair histograms for selected tracks // It creates a bitmap with selections to be stored during skimming // -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/DataTypes.h" -#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 "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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; diff --git a/PWGDQ/Tasks/MIDefficiency.cxx b/PWGDQ/Tasks/MIDefficiency.cxx index efcbe07af85..3dcbcc4d595 100644 --- a/PWGDQ/Tasks/MIDefficiency.cxx +++ b/PWGDQ/Tasks/MIDefficiency.cxx @@ -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. // @@ -16,14 +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" @@ -42,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 { @@ -50,20 +51,33 @@ 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 nBinsTrackType{"nBinsTrackType", 5, "N bins in track type debug histo"}; - Configurable createRootFile{"createRootFile", false, "if true it creates the mid-reco.root file for debug purposes"}; - - // Vector of MID tracks to pass to the efficiency calculator - std::vector dummyTrack; + // 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"}; + // MID track placeholder for processing o2::mid::Track trk; // MID mapping for LB calculation o2::mid::Mapping mapping; - // Filter only for MCH-MID tracks + // Filter only for MCH-MID matched tracks Filter muonTrackType = aod::fwdtrack::trackType == uint8_t(3); void init(o2::framework::InitContext const& /*ic*/) @@ -72,14 +86,18 @@ struct midEfficiency { 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 axisTrackType{nBinsTrackType, -0.5, 4.5, "Muon track type"}; + 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}); @@ -95,16 +113,62 @@ struct midEfficiency { histos.add("nFiredNBPperPlane", "nFiredNBPperPlane", kTH1F, {axisPlanes}); histos.add("nFiredBothperPlane", "nFiredBothperPlane", kTH1F, {axisPlanes}); histos.add("nTotperPlane", "nTotperPlane", kTH1F, {axisPlanes}); - // Track type for debug only + // 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 for (auto& track : muons) { @@ -119,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; } @@ -126,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; @@ -145,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, soa::Filtered 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 } diff --git a/PWGDQ/Tasks/ModelConverterEventExtended.cxx b/PWGDQ/Tasks/ModelConverterEventExtended.cxx new file mode 100644 index 00000000000..ec0a6a0c4be --- /dev/null +++ b/PWGDQ/Tasks/ModelConverterEventExtended.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. +// +// 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 "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +struct eventExtendedConverter000_001 { + Produces eventExtended_001; + + void process(aod::ReducedEventsExtended_000 const& events) + { + for (const auto& event : events) { + eventExtended_001(event.globalBC(), event.alias_raw(), event.selection_raw(), event.timestamp(), event.centRun2V0M(), + event.multTPC(), event.multFV0A(), event.multFV0C(), event.multFT0A(), event.multFT0C(), + event.multFDDA(), event.multFDDC(), event.multZNA(), event.multZNC(), event.multTracklets(), event.multNTracksPV(), + event.centFT0C(), -1.0f, -1.0f); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} 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/ModelConverterReducedMCEvents.cxx b/PWGDQ/Tasks/ModelConverterReducedMCEvents.cxx new file mode 100644 index 00000000000..f4e28daee31 --- /dev/null +++ b/PWGDQ/Tasks/ModelConverterReducedMCEvents.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. +// +// 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 "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +struct reducedMCeventConverter000_001 { + Produces reducedMCevent_001; + + void process(aod::ReducedMCEvents_000 const& events) + { + for (const auto& event : events) { + reducedMCevent_001(event.generatorsID(), event.mcPosX(), event.mcPosY(), event.mcPosZ(), + event.t(), event.weight(), event.impactParameter(), + -1.0f, -1.0f, -1.0f, -1.0f); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGDQ/Tasks/TagAndProbe.cxx b/PWGDQ/Tasks/TagAndProbe.cxx new file mode 100644 index 00000000000..2a35b33b87e --- /dev/null +++ b/PWGDQ/Tasks/TagAndProbe.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. +// +/// \file TagAndProbe.cxx +/// \brief Task Tag-And-Probe matching efficiency studies + +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/TableHelper.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/OutputObjHeader.h" +#include "Framework/runDataProcessing.h" +#include "ITSMFTBase/DPLAlpideParam.h" + +#include "TGeoGlobalMagField.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, 8); //! Event decision +DECLARE_SOA_BITMAP_COLUMN(IsMuonSelected, isMuonSelected, 32); //! Muon track decisions (joinable to ReducedMuonsAssoc) +} // namespace dqanalysisflags + +DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTSA", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents +DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTSA", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc //! joinable to ReducedTracksAssoc +} // namespace o2::aod + +// Declarations of various short names +using MyEvents = soa::Join; +using MyEventsVtxCov = soa::Join; + +using MyMuonTracksWithCov = soa::Join; + +// bit maps used for the Fill functions of the VarManager +constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov; + +constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; + +// 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"); + } +} + +// Run the AnalysisTagAndProbe +// This task assumes that both legs of the resonance fulfill the same cuts (symmetric decay channel) +// Runs combinatorics for muon-muon combinations +struct AnalysisTagAndProbe { + + 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 muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; + // TODO: Add pair cuts via JSON + } fConfigCuts; + + Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + 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; + + HistogramManager* fHistMan; + + // keep histogram class names in maps, so we don't have to buld their names in the pair loops + std::map> fMuonHistNames; + + uint32_t fMuonFilterMask; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream + int fNCutsMuon; + + bool fEnableMuonHistos; + + Preslice muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + + void init(o2::framework::InitContext& context) + { + fEnableMuonHistos = context.mOptions.get("processMuonTagAndProbe"); + + if (context.mOptions.get("processDummy")) { + if (fEnableMuonHistos) { + 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; + + // get the list of cuts for muons + // and make a mask for active cuts (muon selection tasks may run more cuts, needed for other analyses) + TString muonCutsStr = fConfigCuts.muon.value; + TObjArray* objArrayMuonCuts = nullptr; + if (!muonCutsStr.IsNull()) { + objArrayMuonCuts = muonCutsStr.Tokenize(","); + } + + // get the muon track selection cuts + TString tempCutsStr = fConfigCuts.muon.value; + + 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 |= (static_cast(1) << icut); + + if (fEnableMuonHistos) { + // no pair cuts + names = { + Form("PairsMuonSEPM_%s", objArray->At(icut)->GetName()), + Form("PairsMuonSEPM_%s_PassingProbes", objArray->At(icut)->GetName()), + Form("PairsMuonSEPM_%s_FailingProbes", objArray->At(icut)->GetName())}; + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + fMuonHistNames[icut] = names; + } + } + } + } + + fCurrentRun = 0; + + fCCDB->setURL(fConfigCCDB.url.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDBApi.init(fConfigCCDB.url.value); + + 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); + } + + 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, int runNumber, 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 + } + } + + 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 run Tag And Probe (muon-muon) + template + void runTagAndProbe(TEvents const& events, Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/) + { + 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 = fConfigCuts.muon.value; + std::map> histNames = fMuonHistNames; + int ncuts = fNCutsMuon; + int sign1 = 0; + int sign2 = 0; + + if (events.size() > 0) { + for (auto& event : events) { + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + // VarManager::FillEvent(event, VarManager::fgValues); + VarManager::FillEvent(event, 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::kDecayToMuMu) { + + 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(); + + VarManager::FillPair(t1, t2); + + for (int icut = 0; icut < ncuts; icut++) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + + if (static_cast(t1.trackType()) == 3) { // t1 is the tag (track MCHMID) + if (static_cast(t2.trackType()) == 3) { // t2 is the passing probe (track MCHMID) + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + } else if (static_cast(t2.trackType()) == 4) { // t2 is the failing probe (MCHStandalone) + fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + } else { + continue; + } + } + } + } // end loop (cuts) + } // end if (kDecayToMuMu) + } // end loop over pairs of track associations + } // end loop over events + } // end if (events.size() > 0) + + } // end runTagAndProbe + + void processMuonTagAndProbe(MyEventsVtxCov const& events, + aod::ReducedMuonsAssoc const& muonAssocs, MyMuonTracksWithCov const& muons) + { + runTagAndProbe(events, muonAssocsPerCollision, muonAssocs, muons); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisTagAndProbe, processMuonTagAndProbe, "Run muon - pairing & TagAndProbe", false); + PROCESS_SWITCH(AnalysisTagAndProbe, processDummy, "Dummy function, enabled only if none of the others are enabled", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + 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("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")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + } + } + + 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("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/dqCorrelation.cxx b/PWGDQ/Tasks/dqCorrelation.cxx index 353a7fbf575..ec240fa66fe 100644 --- a/PWGDQ/Tasks/dqCorrelation.cxx +++ b/PWGDQ/Tasks/dqCorrelation.cxx @@ -11,44 +11,45 @@ /// @author Victor Valencia // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // -#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 "PWGCF/GenericFramework/Core/FlowContainer.h" -#include "PWGCF/GenericFramework/Core/GFWCumulant.h" #include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWCumulant.h" +#include "PWGCF/GenericFramework/Core/GFWPowerArray.h" #include "PWGCF/GenericFramework/Core/GFWWeights.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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" #include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" -#include "Field/MagneticField.h" -#include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" +#include "DataFormatsParameters/GRPObject.h" #include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" -#include "PWGCF/GenericFramework/Core/GFWPowerArray.h" +#include "TGeoGlobalMagField.h" #include "TProfile.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include using std::cout; using std::endl; @@ -116,9 +117,9 @@ 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 fConfigTrackCuts{"cfgLeptonCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; Configurable fConfigCutPtMin{"cfgCutPtMin", 1.0f, "Minimal pT for tracks"}; Configurable fConfigCutPtMax{"cfgCutPtMax", 12.0f, "Maximal pT for tracks"}; Configurable fConfigCutEtaMin{"cfgCutEtaMin", -0.8f, "Eta min range for tracks"}; @@ -303,7 +304,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 2704cbc36a1..3f97216f52d 100644 --- a/PWGDQ/Tasks/dqEfficiency.cxx +++ b/PWGDQ/Tasks/dqEfficiency.cxx @@ -13,27 +13,33 @@ // // Analysis task for processing O2::DQ MC skimmed AODs // -#include -#include -#include -#include -#include -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" #include "PWGDQ/Core/MCSignal.h" #include "PWGDQ/Core/MCSignalLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" #include "DetectorsBase/GeometryManager.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -97,8 +103,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 +177,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 +270,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 +291,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++) { @@ -297,19 +311,24 @@ 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 } void processSkimmed(MyEventsSelected::iterator const& event, MyBarrelTracks const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) { 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 +346,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()) { @@ -417,7 +440,7 @@ struct AnalysisMuonSelection { 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 +464,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++) { @@ -461,8 +484,8 @@ struct AnalysisMuonSelection { fHistMan->FillHistClass(fHistNamesMCMatched[j][i].Data(), VarManager::fgValues); } } // end loop over cuts - } // end loop over MC signals - } // end loop over muons + } // end loop over MC signals + } // end loop over muons } void processSkimmed(MyEventsSelected::iterator const& event, MyMuonTracks const& muons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) @@ -532,6 +555,10 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fCurrentRun = 0; ccdb->setURL(ccdburl.value); @@ -598,8 +625,8 @@ struct AnalysisSameEventPairing { } fBarrelHistNamesMCmatched.push_back(mcSigClasses); } // end loop over cuts - } // end if(cutNames.IsNull()) - } // end if processBarrel + } // end if(cutNames.IsNull()) + } // end if processBarrel if (enableMuonHistos) { TString cutNames = fConfigMuonCuts.value; @@ -626,8 +653,8 @@ struct AnalysisSameEventPairing { } fMuonHistNamesMCmatched.push_back(mcSigClasses); } // end loop over cuts - } // end if(cutNames.IsNull()) - } // end if processMuon + } // end if(cutNames.IsNull()) + } // end if processMuon // NOTE: For the electron-muon pairing, the policy is that the user specifies n track and n muon cuts via configurables // So for each barrel cut there is a corresponding muon cut @@ -751,13 +778,13 @@ struct AnalysisSameEventPairing { 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; @@ -774,12 +801,12 @@ 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 @@ -797,13 +824,15 @@ struct AnalysisSameEventPairing { 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.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.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(), + 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]); + VarManager::fgValues[VarManager::kKFMassGeoTop], VarManager::fgValues[VarManager::kKFChi2OverNDFGeoTop], + VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjected], + VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); } } } @@ -816,6 +845,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, @@ -849,7 +879,7 @@ struct AnalysisSameEventPairing { 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); @@ -872,7 +902,7 @@ struct AnalysisSameEventPairing { } } } // end loop over barrel track pairs - } // end runPairing + } // end runPairing template void runMCGen(TTracksMC& groupedMCTracks) @@ -917,12 +947,12 @@ 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); } } } // end of true pairing loop - } // end runMCGen + } // end runMCGen // Preslice perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; @@ -1015,9 +1045,18 @@ struct AnalysisSameEventPairing { struct AnalysisDileptonTrack { Produces dileptontrackcandidatesList; OutputObj fOutputList{"output"}; + Service ccdb; + o2::base::MatLayerCylSet* lut = nullptr; + // TODO: For now this is only used to determine the position in the filter bit map for the hadron cut - Configurable fConfigTrackCuts{"cfgLeptonCuts", "", "Comma separated list of barrel track cuts"}; + Configurable fConfigTrackCuts{"cfgLeptonCuts", "", "Comma separated list of barrel track cuts"}; Configurable fConfigFillCandidateTable{"cfgFillCandidateTable", false, "Produce a single flat tables with all relevant information dilepton-track candidates"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fCorrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; + Configurable fNoCorr{"cfgNoCorrFwdProp", false, "Do not correct for MCS effects in track propagation"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Filter eventFilter = aod::dqanalysisflags::isEventSelected == 1; // Filter dileptonFilter = aod::reducedpair::mass > 2.92f && aod::reducedpair::mass < 3.16f && aod::reducedpair::sign == 0; // Filter dileptonFilter = aod::reducedpair::mass > 2.6f && aod::reducedpair::mass < 3.5f && aod::reducedpair::sign == 0; @@ -1046,6 +1085,25 @@ struct AnalysisDileptonTrack { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + + ccdb->setURL(ccdburl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + if (fNoCorr) { + VarManager::SetupFwdDCAFitterNoCorr(); + } else if (fCorrFullGeo) { + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + } else { + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + VarManager::SetupMatLUTFwdDCAFitter(lut); + } + TString sigNamesStr = fConfigMCRecSignals.value; std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); TString histNames; @@ -1175,13 +1233,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); } } @@ -1207,7 +1265,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); } } } @@ -1217,7 +1275,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); } } @@ -1281,6 +1339,317 @@ 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)"}; + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable fConfigUseDCAVertexing{"cfgUseDCAVertexing", false, "Use DCA for secondary vertex reconstruction (DCAFitter is used by default)"}; + + 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("MCTruthRecQuad_%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("MCTruthGenQuad_%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); + + // set up KF or DCAfitter + if (fConfigUseDCAVertexing) { + VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + // VarManager::SetupThreeProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + VarManager::SetupFourProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + } else if (fConfigUseKFVertexing) { + VarManager::SetupFourProngKFParticle(5.0f); + } + + // 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); + // reconstruct the secondary vertex + if (fConfigUseDCAVertexing || fConfigUseKFVertexing) { + VarManager::FillDileptonTrackTrackVertexing(event, lepton1, lepton2, 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("MCTruthRecQuad_%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(), + lepton1.tpcNSigmaEl(), lepton1.tpcNSigmaPi(), lepton1.tpcNSigmaPr(), lepton1.tpcNClsFound(), + lepton2.tpcNSigmaEl(), lepton2.tpcNSigmaPi(), lepton2.tpcNSigmaPr(), lepton2.tpcNClsFound(), + fValuesQuadruplet[VarManager::kDitrackMass], fValuesQuadruplet[VarManager::kDitrackPt], t1.pt(), t2.pt(), t1.eta(), t2.eta(), t1.phi(), t2.phi(), t1.sign(), t2.sign(), t1.tpcNSigmaPi(), t2.tpcNSigmaPi(), t1.tpcNSigmaKa(), t2.tpcNSigmaKa(), t1.tpcNSigmaPr(), t1.tpcNSigmaPr(), t1.tpcNClsFound(), t2.tpcNClsFound(), + fValuesQuadruplet[VarManager::kKFMass], fValuesQuadruplet[VarManager::kVertexingProcCode], fValuesQuadruplet[VarManager::kVertexingChi2PCA], fValuesQuadruplet[VarManager::kCosPointingAngle], fValuesQuadruplet[VarManager::kKFDCAxyzBetweenProngs], fValuesQuadruplet[VarManager::kKFChi2OverNDFGeo], + fValuesQuadruplet[VarManager::kVertexingLz], fValuesQuadruplet[VarManager::kVertexingLxy], fValuesQuadruplet[VarManager::kVertexingLxyz], fValuesQuadruplet[VarManager::kVertexingTauz], fValuesQuadruplet[VarManager::kVertexingTauxy], fValuesQuadruplet[VarManager::kVertexingLzErr], fValuesQuadruplet[VarManager::kVertexingLxyzErr], + fValuesQuadruplet[VarManager::kVertexingTauzErr], fValuesQuadruplet[VarManager::kVertexingLzProjected], fValuesQuadruplet[VarManager::kVertexingLxyProjected], fValuesQuadruplet[VarManager::kVertexingLxyzProjected], fValuesQuadruplet[VarManager::kVertexingTauzProjected], fValuesQuadruplet[VarManager::kVertexingTauxyProjected]); + } // 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::FillQuadMC(dilepton, track1, track2); + } + fHistMan->FillHistClass(Form("MCTruthGenQuad_%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{ @@ -1288,7 +1657,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } void DefineHistograms(HistogramManager* histMan, TString histClasses) @@ -1333,6 +1703,9 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses) // 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("MCTruthGenQuad")) { + 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_Rapidity", "MC generator p_{T}, y distribution", false, 120, 0.0, 30.0, VarManager::kMCPt, 150, 2.5, 4.0, VarManager::kMCY); @@ -1349,6 +1722,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("MCTruthRecQuad")) { + 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 index b288c1f3974..157a19f0935 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -12,37 +12,47 @@ // 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 "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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" -#include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" #include "PWGDQ/Core/MCSignal.h" #include "PWGDQ/Core/MCSignalLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/Core/TableHelper.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" #include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + #include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "Common/Core/TableHelper.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -58,30 +68,144 @@ namespace o2::aod { namespace dqanalysisflags { +DECLARE_SOA_COLUMN(MixingHash, mixingHash, int); //! Hash used in event mixing //need to understand 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(RunNumber, runNumber, uint64_t); +DECLARE_SOA_COLUMN(EventIdx, eventIdx, uint64_t); +DECLARE_SOA_COLUMN(EventTimestamp, eventTimestamp, uint64_t); 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(EtaBcandidate, etaBcandidate, float); +DECLARE_SOA_COLUMN(PhiBcandidate, phiBcandidate, float); +DECLARE_SOA_COLUMN(RapBcandidate, rapBcandidate, float); DECLARE_SOA_COLUMN(LxyBcandidate, lxyBcandidate, float); +DECLARE_SOA_COLUMN(LxyBcandidateErr, lxyBcandidateErr, float); DECLARE_SOA_COLUMN(LxyzBcandidate, lxyzBcandidate, float); +DECLARE_SOA_COLUMN(LxyzBcandidateErr, lxyzBcandidateErr, float); DECLARE_SOA_COLUMN(LzBcandidate, lzBcandidate, float); +DECLARE_SOA_COLUMN(LzBcandidateErr, lzBcandidateErr, float); DECLARE_SOA_COLUMN(TauxyBcandidate, tauxyBcandidate, float); +DECLARE_SOA_COLUMN(TauxyBcandidateErr, tauxyBcandidateErr, float); DECLARE_SOA_COLUMN(TauzBcandidate, tauzBcandidate, float); +DECLARE_SOA_COLUMN(TauzBcandidateErr, tauzBcandidateErr, float); +DECLARE_SOA_COLUMN(MCLxyBcandidate, MClxyBcandidate, float); +DECLARE_SOA_COLUMN(MCLxyzBcandidate, MClxyzBcandidate, float); +DECLARE_SOA_COLUMN(MCLzBcandidate, MClzBcandidate, float); +DECLARE_SOA_COLUMN(MCTauxyBcandidate, MCtauxyBcandidate, float); +DECLARE_SOA_COLUMN(MCTauzBcandidate, MCtauzBcandidate, float); DECLARE_SOA_COLUMN(CosPBcandidate, cosPBcandidate, float); +DECLARE_SOA_COLUMN(MCCosPBcandidate, MCcosPBcandidate, float); DECLARE_SOA_COLUMN(Chi2Bcandidate, chi2Bcandidate, float); +DECLARE_SOA_COLUMN(GlobalIndexassoc, globalIndexassoc, uint64_t); +DECLARE_SOA_COLUMN(GlobalIndexleg1, globalIndexleg1, uint64_t); +DECLARE_SOA_COLUMN(GlobalIndexleg2, globalIndexleg2, uint64_t); +DECLARE_SOA_COLUMN(Ptassoc, ptassoc, float); +DECLARE_SOA_COLUMN(PINassoc, pINassoc, float); +DECLARE_SOA_COLUMN(Etaassoc, etaassoc, float); +DECLARE_SOA_COLUMN(Phiassoc, phiassoc, float); +DECLARE_SOA_COLUMN(Ptpair, ptpair, float); +DECLARE_SOA_COLUMN(Etapair, etapair, float); +DECLARE_SOA_COLUMN(Ptleg1, ptleg1, float); +DECLARE_SOA_COLUMN(PINleg1, pINleg1, float); +DECLARE_SOA_COLUMN(Etaleg1, etaleg1, float); +DECLARE_SOA_COLUMN(Phileg1, phileg1, float); +DECLARE_SOA_COLUMN(Ptleg2, ptleg2, float); +DECLARE_SOA_COLUMN(PINleg2, pINleg2, float); +DECLARE_SOA_COLUMN(Etaleg2, etaleg2, float); +DECLARE_SOA_COLUMN(Phileg2, phileg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaKaassoc, tpcnsigmaKaassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaPiassoc, tpcnsigmaPiassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrassoc, tpcnsigmaPrassoc, float); +DECLARE_SOA_COLUMN(TOFnsigmaKaassoc, tofnsigmaKaassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaElleg1, tpcnsigmaElleg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaPileg1, tpcnsigmaPileg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrleg1, tpcnsigmaPrleg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaElleg2, tpcnsigmaElleg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaPileg2, tpcnsigmaPileg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrleg2, tpcnsigmaPrleg2, float); +DECLARE_SOA_COLUMN(ITSClusterMapassoc, itsClusterMapassoc, uint8_t); +DECLARE_SOA_COLUMN(ITSClusterMapleg1, itsClusterMapleg1, uint8_t); +DECLARE_SOA_COLUMN(ITSClusterMapleg2, itsClusterMapleg2, uint8_t); +DECLARE_SOA_COLUMN(ITSChi2assoc, itsChi2assoc, float); +DECLARE_SOA_COLUMN(ITSChi2leg1, itsChi2leg1, float); +DECLARE_SOA_COLUMN(ITSChi2leg2, itsChi2leg2, float); +DECLARE_SOA_COLUMN(TPCNclsassoc, tpcNclsassoc, float); +DECLARE_SOA_COLUMN(TPCNclsleg1, tpcNclsleg1, float); +DECLARE_SOA_COLUMN(TPCNclsleg2, tpcNclsleg2, float); +DECLARE_SOA_COLUMN(TPCChi2assoc, tpcChi2assoc, float); +DECLARE_SOA_COLUMN(TPCChi2leg1, tpcChi2leg1, float); +DECLARE_SOA_COLUMN(TPCChi2leg2, tpcChi2leg2, 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(Etaee, etaee, float); +DECLARE_SOA_COLUMN(Rapee, rapee, float); +DECLARE_SOA_COLUMN(Phiee, phiee, 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(MultiplicityFT0A, multiplicityFT0AJPsi2ee, float); +DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0CJPsi2ee, float); +DECLARE_SOA_COLUMN(PercentileFT0M, percentileFT0MJPsi2ee, float); +DECLARE_SOA_COLUMN(MultiplicityNContrib, multiplicityNContribJPsi2ee, float); +DECLARE_SOA_COLUMN(AmbiguousInBunchPairs, AmbiguousJpsiPairsInBunch, bool); +DECLARE_SOA_COLUMN(AmbiguousOutOfBunchPairs, AmbiguousJpsiPairsOutOfBunch, bool); +DECLARE_SOA_COLUMN(Corrassoc, corrassoc, bool); +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); +// Candidate columns efficiency calculation for prompt-non-prompt JPsi separation +DECLARE_SOA_COLUMN(OniaPt, oniaPt, float); +DECLARE_SOA_COLUMN(OniaY, oniaY, float); +DECLARE_SOA_COLUMN(OniaEta, oniaEta, float); +DECLARE_SOA_COLUMN(OniaPhi, oniaPhi, float); +DECLARE_SOA_COLUMN(OniaVz, oniaVz, float); +DECLARE_SOA_COLUMN(OniaVtxZ, oniaVtxZ, float); } // namespace dqanalysisflags DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents +DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASHA", 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(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::pTBcandidate, dqanalysisflags::LxyBcandidate, dqanalysisflags::LxyzBcandidate, dqanalysisflags::LzBcandidate, dqanalysisflags::TauxyBcandidate, dqanalysisflags::TauzBcandidate, dqanalysisflags::CosPBcandidate, dqanalysisflags::Chi2Bcandidate); +DECLARE_SOA_TABLE(BmesonCandidates, "AOD", "DQBMESONS", + dqanalysisflags::RunNumber, dqanalysisflags::EventIdx, dqanalysisflags::EventTimestamp, + dqanalysisflags::massBcandidate, dqanalysisflags::MassDileptonCandidate, dqanalysisflags::deltaMassBcandidate, dqanalysisflags::pTBcandidate, dqanalysisflags::EtaBcandidate, dqanalysisflags::PhiBcandidate, dqanalysisflags::RapBcandidate, + dqanalysisflags::LxyBcandidate, dqanalysisflags::LxyBcandidateErr, dqanalysisflags::LxyzBcandidate, dqanalysisflags::LxyzBcandidateErr, dqanalysisflags::LzBcandidate, dqanalysisflags::LzBcandidateErr, + dqanalysisflags::TauxyBcandidate, dqanalysisflags::TauxyBcandidateErr, dqanalysisflags::TauzBcandidate, dqanalysisflags::TauzBcandidateErr, dqanalysisflags::CosPBcandidate, dqanalysisflags::Chi2Bcandidate, + dqanalysisflags::MCLxyBcandidate, dqanalysisflags::MCLxyzBcandidate, dqanalysisflags::MCLzBcandidate, + dqanalysisflags::MCTauxyBcandidate, dqanalysisflags::MCTauzBcandidate, dqanalysisflags::MCCosPBcandidate, + dqanalysisflags::GlobalIndexassoc, dqanalysisflags::GlobalIndexleg1, dqanalysisflags::GlobalIndexleg2, + dqanalysisflags::PINassoc, dqanalysisflags::Etaassoc, dqanalysisflags::Ptpair, dqanalysisflags::Etapair, + dqanalysisflags::PINleg1, dqanalysisflags::Etaleg1, dqanalysisflags::PINleg2, dqanalysisflags::Etaleg2, + dqanalysisflags::TPCnsigmaKaassoc, dqanalysisflags::TPCnsigmaPiassoc, dqanalysisflags::TPCnsigmaPrassoc, dqanalysisflags::TOFnsigmaKaassoc, + dqanalysisflags::TPCnsigmaElleg1, dqanalysisflags::TPCnsigmaPileg1, dqanalysisflags::TPCnsigmaPrleg1, + dqanalysisflags::TPCnsigmaElleg2, dqanalysisflags::TPCnsigmaPileg2, dqanalysisflags::TPCnsigmaPrleg2, + dqanalysisflags::ITSClusterMapassoc, dqanalysisflags::ITSClusterMapleg1, dqanalysisflags::ITSClusterMapleg2, + dqanalysisflags::ITSChi2assoc, dqanalysisflags::ITSChi2leg1, dqanalysisflags::ITSChi2leg2, + dqanalysisflags::TPCNclsassoc, dqanalysisflags::TPCNclsleg1, dqanalysisflags::TPCNclsleg2, + dqanalysisflags::TPCChi2assoc, dqanalysisflags::TPCChi2leg1, dqanalysisflags::TPCChi2leg2, + dqanalysisflags::IsJpsiFromBSelected, dqanalysisflags::IsBarrelSelected, dqanalysisflags::McFlag); +DECLARE_SOA_TABLE(JPsiMuonCandidates, "AOD", "DQJPSIMUONA", + dqanalysisflags::DeltaEta, dqanalysisflags::DeltaPhi, + dqanalysisflags::MassDileptonCandidate, dqanalysisflags::Ptpair, dqanalysisflags::Etapair, dqanalysisflags::Ptassoc, dqanalysisflags::Etaassoc, dqanalysisflags::Phiassoc, + dqanalysisflags::Ptleg1, dqanalysisflags::Etaleg1, dqanalysisflags::Phileg1, dqanalysisflags::Ptleg2, dqanalysisflags::Etaleg2, dqanalysisflags::Phileg2, + dqanalysisflags::McFlag); +DECLARE_SOA_TABLE(JPsieeCandidates, "AOD", "DQPSEUDOPROPER", dqanalysisflags::Massee, dqanalysisflags::Ptee, dqanalysisflags::Etaee, dqanalysisflags::Rapee, dqanalysisflags::Phiee, dqanalysisflags::Lxyee, dqanalysisflags::LxyeePoleMass, dqanalysisflags::Lzee, dqanalysisflags::AmbiguousInBunchPairs, dqanalysisflags::AmbiguousOutOfBunchPairs, dqanalysisflags::Corrassoc, dqanalysisflags::MultiplicityFT0A, dqanalysisflags::MultiplicityFT0C, dqanalysisflags::PercentileFT0M, dqanalysisflags::MultiplicityNContrib); +DECLARE_SOA_TABLE(OniaMCTruth, "AOD", "MCTRUTHONIA", dqanalysisflags::OniaPt, dqanalysisflags::OniaEta, dqanalysisflags::OniaY, dqanalysisflags::OniaPhi, dqanalysisflags::OniaVz, dqanalysisflags::OniaVtxZ, dqanalysisflags::MultiplicityFT0A, dqanalysisflags::MultiplicityFT0C, dqanalysisflags::PercentileFT0M, dqanalysisflags::MultiplicityNContrib); } // namespace o2::aod // Declarations of various short names @@ -89,8 +213,10 @@ using MyEvents = soa::Join; using MyEventsVtxCov = soa::Join; using MyEventsVtxCovSelected = soa::Join; +using MyEventsVtxCovSelectedMultExtra = soa::Join; using MyEventsVtxCovSelectedQvector = soa::Join; using MyEventsQvector = soa::Join; +using MyEventsVtxCovHashSelected = soa::Join; using MyBarrelTracks = soa::Join; using MyBarrelTracksWithAmbiguities = soa::Join; @@ -98,14 +224,17 @@ using MyBarrelTracksWithCov = 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 gkEventFillMapWithCovMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::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; @@ -131,17 +260,26 @@ void PrintBitMap(TMap map, int nbits) // Analysis task that produces event decisions and the Hash table used in event mixing struct AnalysisEventSelection { Produces eventSel; + Produces hash; OutputObj fOutputList{"output"}; - - Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + 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 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; + MixingHandler* fMixHandler = nullptr; + AnalysisCompositeCut* fEventCut; Service fCCDB; @@ -152,24 +290,56 @@ struct AnalysisEventSelection { std::map fMetadataRCT, fHeader; int fCurrentRun; - void init(o2::framework::InitContext&) + void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + 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;OutOfBunchCorrelations;SameBunchCorrelations;", fConfigAddEventHistogram.value.data()); // define all histograms - DefineHistograms(fHistMan, "EventsMC", fConfigAddEventMCHistogram.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, "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()); } + 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()); + } + } + fCurrentRun = -1; fCCDB->setURL(fConfigCcdbUrl.value); fCCDB->setCaching(true); @@ -185,8 +355,7 @@ struct AnalysisEventSelection { 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; - // TODO: send SOR to VarManager and compute event times relative to SOR + VarManager::SetSORandEOR(sor, eor); } fSelMap.clear(); @@ -196,7 +365,9 @@ struct AnalysisEventSelection { // Reset the fValues array and fill event observables VarManager::ResetValues(0, VarManager::kNEventWiseVariables); VarManager::FillEvent(event); - VarManager::FillEvent(event.reducedMCevent()); + if (event.has_reducedMCevent()) { + VarManager::FillEvent(event.reducedMCevent()); + } bool decision = false; // if QA is requested fill histograms before event selections @@ -217,6 +388,10 @@ struct AnalysisEventSelection { auto& evIndices = fBCCollMap[event.globalBC()]; evIndices.push_back(event.globalIndex()); } + if (fMixHandler != nullptr) { + int hh = fMixHandler->FindEventCategory(VarManager::fgValues); + hash(hh); + } } for (auto& event : mcEvents) { @@ -236,78 +411,67 @@ struct AnalysisEventSelection { // 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 - // TODO: add also correlations for out of bunch events - // TODO: check event time resolution as a function of various multiplicity estimators - - // for (auto& [bc, evIndices] : fBCCollMap) { - for (auto it1 = fBCCollMap.begin(); it1 != fBCCollMap.end(); it1++) { - - // correlate events in neighbouring BCs (within one orbit) - for (auto it2 = it1; it2 != fBCCollMap.end(); it2++) { - if (it2 == it1) { - continue; - } - - if ((it2->first - it1->first) > 100) { + // 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 const& 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) { break; } - - for (auto& ev1Idx : it1->second) { - if (!fSelMap[ev1Idx]) { - continue; - } - auto ev1 = events.rawIteratorAt(ev1Idx); - for (auto& ev2Idx : it2->second) { - if (!fSelMap[ev2Idx]) { - continue; - } - auto ev2 = events.rawIteratorAt(ev2Idx); + auto const& 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); } } } - - auto evIndices = it1->second; - if (evIndices.size() < 2) { - continue; - } - - // correlate the events inside one BC - 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; - } - 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; - } - fHistMan->FillHistClass("SameBunchCorrelations", VarManager::fgValues); - } - } } // publish the table - uint32_t evSel = 0; + uint32_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); } @@ -325,7 +489,7 @@ struct AnalysisEventSelection { } PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); - PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", false); + PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", true); }; // Produces a table with barrel track decisions (joinable to the ReducedTracksAssociations) @@ -335,24 +499,26 @@ struct AnalysisTrackSelection { Produces trackAmbiguities; OutputObj fOutputList{"output"}; - Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + 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 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 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 fTrackCuts; + std::vector fMCSignals; // list of signals to be checked std::vector fHistNamesReco; std::vector fHistNamesMCMatched; @@ -361,14 +527,27 @@ struct AnalysisTrackSelection { 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) { + 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())); + } + } + // 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(reinterpret_cast(t)); } } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill @@ -382,12 +561,22 @@ struct AnalysisTrackSelection { if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals continue; } - fMCSignals.push_back(*sig); + 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) { - VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); @@ -396,28 +585,28 @@ struct AnalysisTrackSelection { // 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()); + 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()); + 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()); + 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()); - DefineHistograms(fHistMan, "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;", "ambiguity"); - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + 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); @@ -468,8 +657,9 @@ struct AnalysisTrackSelection { VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); // fill event information which might be needed in histograms/cuts that combine track and event properties VarManager::FillEvent(event); - auto eventMC = event.reducedMCevent(); - VarManager::FillEvent(eventMC); + if (event.has_reducedMCevent()) { + VarManager::FillEvent(event.reducedMCevent()); + } auto track = assoc.template reducedtrack_as(); VarManager::FillTrack(track); @@ -480,7 +670,9 @@ struct AnalysisTrackSelection { if (track.has_reducedMCTrack()) { auto trackMC = track.reducedMCTrack(); auto eventMCfromTrack = trackMC.reducedMCevent(); - isCorrectAssoc = (eventMCfromTrack.globalIndex() == eventMC.globalIndex()); + if (event.has_reducedMCevent()) { + isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reducedMCevent().globalIndex()); + } VarManager::FillTrackMC(tracksMC, trackMC); } @@ -489,10 +681,10 @@ struct AnalysisTrackSelection { } int iCut = 0; - uint32_t filterMap = 0; + uint32_t filterMap = static_cast(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(fHistNamesReco[iCut], VarManager::fgValues); } @@ -501,24 +693,33 @@ struct AnalysisTrackSelection { trackSel(filterMap); // compute MC matching decisions and fill histograms for matched associations - uint32_t mcDecision = 0; int isig = 0; - if (filterMap > 0) { + if (filterMap > 0 && track.has_reducedMCTrack() && fConfigQA) { + // loop over all MC signals for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { - if (track.has_reducedMCTrack()) { - if ((*sig).CheckSignal(false, track.reducedMCTrack())) { - mcDecision |= (uint32_t(1) << 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 & (uint32_t(1) << i))) { + /*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 & (uint32_t(1) << j)) { + if (filterMap & (static_cast(1) << j)) { if (isCorrectAssoc) { fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); } else { @@ -526,12 +727,14 @@ struct AnalysisTrackSelection { } } } // end loop over cuts - } // end loop over MC signals - } // end if (filterMap > 0) + } // end loop over MC signals + */ + } // end if (filterMap > 0) // count the number of associations per track - if (filterMap > 0) { + 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; @@ -554,39 +757,43 @@ struct AnalysisTrackSelection { // 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 - 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) { + 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 } - 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 runTrackSelection() @@ -605,46 +812,65 @@ struct AnalysisTrackSelection { 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); + PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", true); }; // 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 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 fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + 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 fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; 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 fMuonCuts; std::vector fHistNamesReco; std::vector fHistNamesMCMatched; - std::vector fMCSignals; // list of signals to be checked + 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&) + 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())); + } + } + // 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(reinterpret_cast(t)); } } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill @@ -658,12 +884,22 @@ struct AnalysisMuonSelection { if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals continue; } - fMCSignals.push_back(*sig); + 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) { - VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); @@ -672,22 +908,25 @@ struct AnalysisMuonSelection { // 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()); + 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()); + 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()); + nameStr2 = Form("AssocsIncorrectMuon_%s_%s", cut->GetName(), sig->GetName()); fHistNamesMCMatched.push_back(nameStr2); histClasses += Form("%s;", nameStr2.Data()); } } - histClasses += "Muon_AmbiguityInBunch;Muon_AmbiguityOutOfBunch;"; + if (fConfigPublishAmbiguity) { + histClasses += "Muon_AmbiguityInBunch;Muon_AmbiguityOutOfBunch;"; + } - DefineHistograms(fHistMan, histClasses.Data(), fConfigAddMuonHistogram.value.data()); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + 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()); } @@ -709,7 +948,9 @@ struct AnalysisMuonSelection { 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()); + // LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + // If the magnetic field is not found it is configured by had by the user + VarManager::SetMagneticField(fConfigMagField.value); } fCurrentRun = events.begin().runNumber(); } @@ -731,8 +972,6 @@ struct AnalysisMuonSelection { auto track = assoc.template reducedmuon_as(); VarManager::FillTrack(track); - // compute quantities which depend on the associated collision - VarManager::FillPropagateMuon(track, event); bool isCorrectAssoc = false; if (track.has_reducedMCTrack()) { @@ -747,16 +986,17 @@ struct AnalysisMuonSelection { } int iCut = 0; - uint32_t filterMap = 0; + uint32_t filterMap = static_cast(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(fHistNamesReco[iCut].Data(), VarManager::fgValues); } } } // end loop over cuts muonSel(filterMap); + muonAmbiguities.reserve(muons.size()); // if no filter fulfilled, continue if (!filterMap) { @@ -769,13 +1009,13 @@ struct AnalysisMuonSelection { } // compute MC matching decisions - uint32_t mcDecision = 0; + 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(false, track.reducedMCTrack())) { - mcDecision |= (uint32_t(1) << isig); + if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); } } } @@ -783,36 +1023,38 @@ struct AnalysisMuonSelection { // 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 < fMuonCuts.size(); j++) { - if (filterMap & (uint8_t(1) << j)) { + if (filterMap & (static_cast(1) << j)) { if (isCorrectAssoc) { - fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); + fHistMan->FillHistClass(fHistNamesMCMatched[j * 2 * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); } else { - fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i + 1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(fHistNamesMCMatched[j * 2 * fMCSignals.size() + 2 * i + 1].Data(), VarManager::fgValues); } } } // end loop over cuts - } // end loop over MC signals + } // end loop over MC signals // count the number of associations per track - 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; + 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 { - auto& evVector = fNAssocsOutOfBunch[track.globalIndex()]; - evVector.push_back(event.globalIndex()); + 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 @@ -820,27 +1062,42 @@ struct AnalysisMuonSelection { // 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 - 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; + 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); } - 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 + } } void processSkimmed(ReducedMuonsAssoc const& assocs, MyEventsSelected const& events, MyMuonTracks const& muons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) @@ -859,7 +1116,7 @@ struct AnalysisMuonSelection { 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); + PROCESS_SWITCH(AnalysisMuonSelection, processDummy, "Dummy function", true); }; // Run the prefilter selection (e.g. electron prefiltering for photon conversions) @@ -874,6 +1131,8 @@ struct AnalysisPrefilterSelection { 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; @@ -882,53 +1141,75 @@ 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; + } + + 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; 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 @@ -938,9 +1219,12 @@ struct AnalysisPrefilterSelection { VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); } - template - void runPrefilter(soa::Join const& assocs, TTracks const& /*tracks*/) + 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(); @@ -964,6 +1248,9 @@ struct AnalysisPrefilterSelection { // 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) { @@ -984,18 +1271,29 @@ struct AnalysisPrefilterSelection { for (auto& event : events) { auto groupedAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); if (groupedAssocs.size() > 1) { - runPrefilter(groupedAssocs, tracks); + runPrefilter(event, 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); } } @@ -1005,7 +1303,7 @@ struct AnalysisPrefilterSelection { } PROCESS_SWITCH(AnalysisPrefilterSelection, processBarrelSkimmed, "Run Prefilter selection on reduced tracks", false); - PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", false); + PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", true); }; // Run the same-event pairing @@ -1019,46 +1317,73 @@ struct AnalysisSameEventPairing { Produces dimuonList; Produces dielectronsExtraList; Produces dielectronInfoList; + Produces dielectronAllList; Produces dimuonsExtraList; Produces dimuonAllList; - Produces dileptonFlowList; + Produces dileptonMiniTreeGen; + Produces dileptonMiniTreeRec; Produces dileptonInfoList; + Produces PromptNonPromptSepTable; + Produces MCTruthTableEffi; 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, !!! Use only if you know what you are doing, otherwise leave empty"}; - - 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"}; + 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"}; + Configurable MCgenAcc{"cfgMCGenAccCut", "", "cut for MC generated particles acceptance"}; + // 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 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 fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; - Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; - Configurable fConfigSkimSignalOnly{"fConfigSkimSignalOnly", false, "Configurable to select only matched candidates"}; + 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"}; + } 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); + Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); HistogramManager* fHistMan; @@ -1067,10 +1392,12 @@ struct AnalysisSameEventPairing { std::map> fBarrelHistNamesMCmatched; std::map> fMuonHistNames; std::map> fMuonHistNamesMCmatched; - std::vector fRecMCSignals; - std::vector fGenMCSignals; + std::vector fRecMCSignals; + std::vector fGenMCSignals; std::vector fPairCuts; + AnalysisCompositeCut fMCGenAccCut; + bool fUseMCGenAccCut = false; 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 @@ -1087,22 +1414,18 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithGrouping") || context.mOptions.get("processBarrelOnlySkimmed"); + VarManager::SetDefaultVarNames(); + fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed") || context.mOptions.get("processBarrelOnlyWithCollSkimmed"); fEnableMuonHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processMuonOnlySkimmed"); - bool isDummy = context.mOptions.get("processDummy"); - if (isDummy) { - if (fEnableBarrelHistos || fEnableMuonHistos) { - 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; - } - } // Keep track of all the histogram class names to avoid composing strings in the pairing loop TString histNames = ""; - - TString cutNamesStr = fConfigPairCuts.value; + TString cutNamesStr = fConfigCuts.pair.value; if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { @@ -1112,28 +1435,39 @@ 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(","); } // Setting the MC rec signal names - TString sigNamesStr = fConfigMCRecSignals.value; + 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); + 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); } } @@ -1141,6 +1475,26 @@ 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()); + } + } + + // get the mc generated acceptance cut + TString mcGenAccCutStr = fConfigCuts.MCgenAcc.value; + if (mcGenAccCutStr != "") { + AnalysisCut* cut = dqcuts::GetAnalysisCut(mcGenAccCutStr.Data()); + if (cut != nullptr) { + fMCGenAccCut.AddCut(cut); + } + fUseMCGenAccCut = true; + } + // 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 @@ -1151,7 +1505,7 @@ struct AnalysisSameEventPairing { // 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 |= (uint32_t(1) << icut); + fTrackFilterMask |= (static_cast(1) << icut); if (fEnableBarrelHistos) { // assign the pair hist directories for the current cut @@ -1159,13 +1513,15 @@ struct AnalysisSameEventPairing { Form("PairsBarrelSEPM_%s", objArray->At(icut)->GetName()), Form("PairsBarrelSEPP_%s", objArray->At(icut)->GetName()), Form("PairsBarrelSEMM_%s", objArray->At(icut)->GetName())}; - // 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())); + 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()); } @@ -1174,7 +1530,7 @@ struct AnalysisSameEventPairing { // 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 = fConfigPairCuts.value; + TString cutNamesStr = fConfigCuts.pair.value; if (!cutNamesStr.IsNull()) { // if pair cuts std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); @@ -1187,25 +1543,32 @@ struct AnalysisSameEventPairing { // 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) + } // end if (pair cuts) // assign hist directories for the MC matched pairs for each (track cut,MCsignal) combination if (!sigNamesStr.IsNull()) { - for (auto& sig : fRecMCSignals) { + 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("PairsBarrelSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsBarrelSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsBarrelSEPM_ambiguousInBunch_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsBarrelSEPM_ambiguousInBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsBarrelSEPM_ambiguousInBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsBarrelSEPM_ambiguousOutOfBunch_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsBarrelSEPM_ambiguousOutOfBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsBarrelSEPM_ambiguousOutOfBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig.GetName())}; - histNames += Form("%s;%s;%s;%s;%s;%s;%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data(), names[3].Data(), names[4].Data(), names[5].Data(), names[6].Data(), names[7].Data(), names[8].Data()); + 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 } - fBarrelHistNamesMCmatched[icut] = names; } // end if enableBarrelHistos } } @@ -1214,6 +1577,16 @@ struct AnalysisSameEventPairing { // 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 @@ -1223,7 +1596,7 @@ struct AnalysisSameEventPairing { TString tempStr = objArray->At(icut)->GetName(); if (objArrayMuonCuts->FindObject(tempStr.Data()) != nullptr) { // update the filter mask - fMuonFilterMask |= (uint32_t(1) << icut); + fMuonFilterMask |= (static_cast(1) << icut); if (fEnableMuonHistos) { // assign pair hist directories for each required muon cut @@ -1231,11 +1604,22 @@ 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()); - fMuonHistNames[icut] = names; - + 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 = fConfigPairCuts.value; + TString cutNamesStr = fConfigCuts.pair.value; if (!cutNamesStr.IsNull()) { // if pair cuts std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); @@ -1247,38 +1631,69 @@ 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) // assign hist directories for pairs matched to MC signals for each (muon cut, MCrec signal) combination if (!sigNamesStr.IsNull()) { - for (auto& sig : fRecMCSignals) { + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); names = { - Form("PairsMuonsSEPM_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsMuonsSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), - Form("PairsMuonsSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig.GetName()), + 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()), }; - histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + 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()); + } + fMuonHistNamesMCmatched.try_emplace(icut * fRecMCSignals.size() + isig, names); } // end loop over MC signals } - fMuonHistNamesMCmatched[icut] = names; } } } // end loop over cuts - } // end if (muonCutsStr) + } // 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 = fConfigMCGenSignals.value; + 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) { - if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required - fGenMCSignals.push_back(*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); + } + } + + if (isMCGen) { + 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) { // NOTE: 2-prong signals required - fGenMCSignals.push_back(*sig); + histNames += Form("MCTruthGenSel_%s;", sig->GetName()); + } else if (sig->GetNProngs() == 2) { histNames += Form("MCTruthGenPair_%s;", sig->GetName()); + histNames += Form("MCTruthGenPairSel_%s;", sig->GetName()); fHasTwoProngGenMCsignals = true; } } @@ -1286,37 +1701,37 @@ struct AnalysisSameEventPairing { fCurrentRun = 0; - fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setURL(fConfigCCDB.url.value); fCCDB->setCaching(true); fCCDB->setLocalObjectValidityChecking(); - 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); - VarManager::SetCollisionSystem((TString)fConfigCollisionSystem, fConfigCenterMassEnergy); // set collision system and center of mass energy + 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 - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + 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 (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(); @@ -1324,25 +1739,25 @@ 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 } } } @@ -1351,26 +1766,30 @@ struct AnalysisSameEventPairing { template void runSameEventPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } if (fCurrentRun != events.begin().runNumber()) { initParamsFromCCDB(events.begin().timestamp(), TTwoProngFitter); fCurrentRun = events.begin().runNumber(); } - TString cutNames = fConfigTrackCuts.value; + TString cutNames = fConfigCuts.track.value; std::map> histNames = fTrackHistNames; std::map> histNamesMC = fBarrelHistNamesMCmatched; int ncuts = fNCutsBarrel; if constexpr (TPairType == VarManager::kDecayToMuMu) { - cutNames = fConfigMuonCuts.value; + cutNames = fConfigCuts.muon.value; histNames = fMuonHistNames; histNamesMC = fMuonHistNamesMCmatched; ncuts = fNCutsMuon; } - uint32_t twoTrackFilter = 0; + uint32_t twoTrackFilter = static_cast(0); int sign1 = 0; int sign2 = 0; - uint32_t mcDecision = 0; + uint32_t mcDecision = static_cast(0); bool isCorrectAssoc_leg1 = false; bool isCorrectAssoc_leg2 = false; dielectronList.reserve(1); @@ -1379,9 +1798,14 @@ struct AnalysisSameEventPairing { dimuonsExtraList.reserve(1); dielectronInfoList.reserve(1); dileptonInfoList.reserve(1); - if (fConfigFlatTables.value) { + if (fConfigOptions.flatTables.value) { + dielectronAllList.reserve(1); 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); @@ -1389,6 +1813,7 @@ struct AnalysisSameEventPairing { 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); @@ -1401,7 +1826,7 @@ struct AnalysisSameEventPairing { 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 @@ -1414,16 +1839,16 @@ struct AnalysisSameEventPairing { 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 |= (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); } // run MC matching for this pair @@ -1431,8 +1856,8 @@ struct AnalysisSameEventPairing { mcDecision = 0; for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { - if ((*sig).CheckSignal(false, t1.reducedMCTrack(), t2.reducedMCTrack())) { - mcDecision |= (uint32_t(1) << isig); + if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); } } } // end loop over MC signals @@ -1442,13 +1867,16 @@ struct AnalysisSameEventPairing { } VarManager::FillPair(t1, t2); + if (fPropTrack) { + 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); } - if (!fConfigSkimSignalOnly || (fConfigSkimSignalOnly && mcDecision > 0)) { + 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); @@ -1459,6 +1887,20 @@ struct AnalysisSameEventPairing { } 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::ReducedTrackCollInfo) > 0) { + if (fConfigOptions.flatTables.value && t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + dielectronAllList(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), twoTrackFilter, mcDecision, + 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], + VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjected], + VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + } + } } } } @@ -1470,16 +1912,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); + } // 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(false, t1.reducedMCTrack(), t2.reducedMCTrack())) { - mcDecision |= (uint32_t(1) << isig); + if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); } } } // end loop over MC signals @@ -1490,8 +1949,11 @@ struct AnalysisSameEventPairing { } VarManager::FillPair(t1, t2); + if (fPropTrack) { + 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); @@ -1506,11 +1968,12 @@ 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 && t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { dimuonAllList(event.posX(), event.posY(), event.posZ(), event.numContrib(), - -999., -999., -999., + event.selection_raw(), evSel, + event.reducedMCevent().mcPosX(), event.reducedMCevent().mcPosY(), event.reducedMCevent().mcPosZ(), VarManager::fgValues[VarManager::kMass], - false, + 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], @@ -1518,15 +1981,15 @@ struct AnalysisSameEventPairing { 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(), - 0., 0., + t1.mcMask(), t2.mcMask(), 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., - t1.isAmbiguous(), t2.isAmbiguous(), + 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], @@ -1539,61 +2002,118 @@ 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]); - } - // 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 & (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)); 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 & (uint32_t(1) << isig)) { - fHistMan->FillHistClass(histNamesMC[icut][isig * fRecMCSignals.size()].Data(), VarManager::fgValues); // matched signal - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { // correct track-collision association - fHistMan->FillHistClass(histNamesMC[icut][isig * fRecMCSignals.size() + 1].Data(), VarManager::fgValues); - } else { // incorrect track-collision association - fHistMan->FillHistClass(histNamesMC[icut][isig * fRecMCSignals.size() + 2].Data(), VarManager::fgValues); - } - if (isAmbiInBunch) { // ambiguous in bunch - fHistMan->FillHistClass(histNames[icut][isig * fRecMCSignals.size() + 3].Data(), VarManager::fgValues); - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { - fHistMan->FillHistClass(histNamesMC[icut][isig * fRecMCSignals.size() + 4].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(histNamesMC[icut][isig * fRecMCSignals.size() + 5].Data(), VarManager::fgValues); + if (mcDecision & (static_cast(1) << isig)) { + PromptNonPromptSepTable(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kRap], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kVertexingTauxyProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjectedPoleJPsiMass], VarManager::fgValues[VarManager::kVertexingTauzProjected], isAmbiInBunch, isAmbiOutOfBunch, isCorrect_pair, VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + 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) { + // In the miniTree the positive daughter is positioned as first + if (t1.sign() > 0) { + 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(), + t1.pt(), t1.eta(), t1.phi(), + t2.pt(), t2.eta(), t2.phi()); + } else { + dileptonMiniTreeRec(mcDecision, + VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kCentFT0C], + t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), + t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), + t2.pt(), t2.eta(), t2.phi(), + t1.pt(), t1.eta(), t1.phi()); + } + } } } - if (isAmbiOutOfBunch) { // ambiguous out of bunch - fHistMan->FillHistClass(histNames[icut][isig * fRecMCSignals.size() + 6].Data(), VarManager::fgValues); - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { - fHistMan->FillHistClass(histNamesMC[icut][isig * fRecMCSignals.size() + 7].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(histNamesMC[icut][isig * fRecMCSignals.size() + 8].Data(), VarManager::fgValues); + 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); - if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][4].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 (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][4 + 3].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); - if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][5].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 (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][5 + 3].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); + } } } } @@ -1602,80 +2122,161 @@ struct AnalysisSameEventPairing { if (!(cut.IsSelected(VarManager::fgValues))) // apply pair cuts continue; if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][0].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][0].Data(), VarManager::fgValues); } else { if (sign1 > 0) { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][1].Data(), VarManager::fgValues); } else { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][2].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][2].Data(), VarManager::fgValues); } } } // 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 } - // Preslice perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; - void runMCGen(ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + template + void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, 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); + // if we have a mc generated acceptance cut, apply it here + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } // 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 + if (sig->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + // Fill Generated histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + for (auto& track : mcTracks) { + if (track.reducedMCeventId() != event.reducedMCeventId()) { continue; } - bool checked = false; - /*if constexpr (soa::is_soa_filtered_v) { - auto mctrack_raw = groupedMCTracks.rawIteratorAt(mctrack.globalIndex()); - checked = sig.CheckSignal(false, mctrack_raw); - } else {*/ - checked = sig.CheckSignal(false, mctrack); - //} - if (checked) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig.GetName()), VarManager::fgValues); + VarManager::FillTrackMC(mcTracks, track); + // if we have a mc generated acceptance cut, apply it here + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } + auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); + } + } + isig++; } } - } + } // end loop over reconstructed events 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& [t1, t2] : combinations(mcTracks, mcTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { for (auto& sig : fGenMCSignals) { - if (sig.GetNProngs() != 2) { // NOTE: 2-prong signals required here + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here continue; } - if (sig.CheckSignal(false, t1_raw, t2_raw)) { - VarManager::FillPairMC(t1, t2); - fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig.GetName()), VarManager::fgValues); + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + VarManager::FillPairMC(t1, t2); + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); } - } // end loop over MC signals - } // end loop over pairs - } // end loop over events + } + } + } + } + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS + if (fHasTwoProngGenMCsignals) { + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + mcDecision = 0; + isig = 0; + 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); + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } + } + isig++; + } + } + } + } // end loop over reconstructed events } - } // end runMCGen + } 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, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons, mcEvents, mcTracks); - runMCGen(mcEvents, mcTracks); + // Feature replaced by processMCGen + /*if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + }*/ // runSameEventPairing(event, tracks, muons); } @@ -1684,7 +2285,7 @@ struct AnalysisSameEventPairing { MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - runMCGen(mcEvents, mcTracks); + runMCGenWithGrouping(events, mcEvents, mcTracks); } void processBarrelOnlyWithCollSkimmed(MyEventsVtxCovSelected const& events, @@ -1692,203 +2293,1669 @@ struct AnalysisSameEventPairing { MyBarrelTracksWithCovWithAmbiguitiesWithColl const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - runMCGen(mcEvents, mcTracks); + // Feature replaced by processMCGen + /* if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + }*/ } void processMuonOnlySkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& muonAssocs, MyMuonTracksWithCov const& muons, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons, mcEvents, mcTracks); - runMCGen(mcEvents, mcTracks); - } - - void processDummy(MyEvents&) - { - // do nothing + // Feature replaced by processMCGen + /* if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + }*/ } - 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); -}; - -// 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 fConfigTrackCut{"cfgTrackCut", "kaonPID", "Cut 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"}; - 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 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{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; - Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; - - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - int fNCuts; - int fTrackCutBit; - std::map fHistNamesDileptonTrack; - std::map> fHistNamesDileptonTrackMCmatched; - std::vector fHistNamesMCgen; - std::map fHistNamesDileptons; - - 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(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); - - 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; + PresliceUnsorted perReducedMcGenEvent = aod::reducedtrackMC::reducedMCeventId; - void init(o2::framework::InitContext& context) + void processMCGen(soa::Filtered const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { - bool isBarrel = context.mOptions.get("processBarrelSkimmed"); - bool isMuon = context.mOptions.get("processMuonSkimmed"); - bool isAnyProcessEnabled = isBarrel || isMuon; - 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; - } - } - - fCurrentRun = 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->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + // Fill Generated histograms taking into account all generated tracks + uint32_t mcDecision = 0; + int isig = 0; - 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) { - continue; - } - fRecMCSignals.push_back(*sig); + 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->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); } } } - // 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); - } else { - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCutsSingle, false); - } - TString tempCutsSingleStr = tempCutsSingle; - TObjArray* objArraySingleCuts = nullptr; - if (!tempCutsSingleStr.IsNull()) { - objArraySingleCuts = tempCutsSingleStr.Tokenize(","); + // Fill Generated histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; } - 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!"; + if (!event.has_reducedMCevent()) { + continue; } - // get the cuts employed for same-event pairing - string tempCutsPair; - 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 - std::vector mcHistNames; - for (auto& sig : fRecMCSignals) { - mcHistNames.push_back(Form("DileptonTrackMCMatched_%s_%s_%s", tempStr.Data(), fConfigTrackCut.value.data(), sig.GetName())); - DefineHistograms(fHistMan, mcHistNames[mcHistNames.size() - 1], ""); + VarManager::FillEvent(event, VarManager::fgValues); + VarManager::FillEvent(event.reducedMCevent(), VarManager::fgValues); + // auto groupedMCTracks = mcTracks.sliceBy(perReducedMcGenEvent, event.reducedMCeventId()); + // groupedMCTracks.bindInternalIndicesTo(&mcTracks); + // for (auto& track : groupedMCTracks) { + for (auto& track : mcTracks) { + if (track.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + VarManager::FillTrackMC(mcTracks, track); + auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); + // auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); } - fHistNamesDileptonTrackMCmatched[icut] = mcHistNames; - } - if (tempStr.CompareTo(fConfigTrackCut.value.data()) == 0) { - fTrackCutBit = icut; // the bit corresponding to the track to be combined with dileptons } + isig++; } } - // 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); - fHistNamesMCgen.push_back(Form("MCTruthGen_%s", sig->GetName())); - DefineHistograms(fHistMan, fHistNamesMCgen[fHistNamesMCgen.size() - 1], ""); + } // end loop over reconstructed events + if (fHasTwoProngGenMCsignals) { + for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + } } } } } - if (fHistNamesDileptons.size() == 0) { - LOG(fatal) << " No valid dilepton cuts "; - } + // Fill Generated PAIR histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } - VarManager::SetUseVars(fHistMan->GetUsedVars()); - fOutputList.setObject(fHistMan->GetMainHistogramList()); + if (fHasTwoProngGenMCsignals) { + for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { + if (t1.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + if (t2.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + mcDecision = 0; + isig = 0; + 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); // NOTE: This feature will only work for muons + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } + } + isig++; + } + } + } + } + } // end loop over reconstructed events } - // init parameters from CCDB - void initParamsFromCCDB(uint64_t timestamp) + void processMCGenWithGrouping(soa::Filtered const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { - 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 - } + 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->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + // Fill Generated histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + for (auto& track : mcTracks) { + if (track.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + VarManager::FillTrackMC(mcTracks, track); + auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); + } + } + isig++; + } + } + } // end loop over reconstructed events + if (fHasTwoProngGenMCsignals) { + for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS + if (fHasTwoProngGenMCsignals) { + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { + auto t1_raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + mcDecision = 0; + isig = 0; + 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); // NOTE: This feature will only work for muons + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } + } + isig++; + } + } + } + } // end loop over reconstructed events + } + } + + 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, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMCGenWithGrouping, "Loop over MC particle stack (grouped MCTracks) and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); +}; + +// 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 fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable fConfigMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; + Configurable fConfigMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; + + Service fCCDB; + + HistogramManager* fHistMan; + + 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; + // vectors for cut names and signal names, for easy access when calling FillHistogramList() + std::vector fLegCutNames; + std::vector fPairCutNames; + std::vector fCommonCutNames; + std::vector fRecMCSignalNames; + + Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); + + 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) + { + bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithEventSelection"); + if (context.mOptions.get("processDummy")) { + return; + } + + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Get the leg cut filter masks + 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(reinterpret_cast(t)); + cutNamesStr += Form(",%s", t->GetName()); + } + } + std::unique_ptr objArrayPairCuts(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPairCuts->GetEntries(); + for (int j = 0; j < fNPairCuts; j++) { + fPairCutNames.push_back(objArrayPairCuts->At(j)->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); + } + } + // 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() != 2 && mcIt->GetNProngs() != 3) { + LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 2 or 3 prongs! Fix it"; + } + fRecMCSignals.push_back(mcIt); + sigNamesStr += Form(",%s", mcIt->GetName()); + } + } + // Put all the reco MCSignal names in the vector for histogram naming + std::unique_ptr objArrayRecMCSignals(sigNamesStr.Tokenize(",")); + for (int i = 0; i < objArrayRecMCSignals->GetEntries(); i++) { + fRecMCSignalNames.push_back(objArrayRecMCSignals->At(i)->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)); + fCommonCutNames.push_back(objArrayCommon->At(icut)->GetName()); + } 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 && !isMCGen) { + 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; + } + } + // Leg cut config is fine, store the leg cut name in a vector + fLegCutNames.push_back(legsStr); + + // Define histogram and histogram directory names + if (isThreeProng[icut]) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); + if (fConfigQA) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } + + 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 + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } // 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); + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + } // end loop over MC signals + } // end if (MC signals) + } else { + 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) { + DefineHistograms(fHistMan, Form("%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + if (fConfigQA) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_ambiguous_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + } + if (fConfigReflectedHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_reflected_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + } + + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } + } + + 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 + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } + } // 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); + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + if (fConfigReflectedHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_reflected_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + } + + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + } // 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); + DefineHistograms(fHistMan, Form("MCTruthGen_%s;", sig->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + DefineHistograms(fHistMan, Form("MCTruthGenSel_%s;", sig->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + } + } + } + + // 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); + DefineHistograms(fHistMan, Form("MCTruthGen_%s;", mcIt->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + DefineHistograms(fHistMan, Form("MCTruthGenSel_%s;", mcIt->GetName()), fConfigHistogramSubgroups.value.data()); // 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); + + 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(); + } + } + + 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(Form("PairsBarrelSEPM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); // reconstructed, unmatched + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { // ++ pairs + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } else { // -- pairs + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } + } + } + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].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(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].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(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].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(); + } + } + + 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); + } + } else if (tripletType == VarManager::kTripleCandidateToKPiPi) { + for (auto& a1 : groupedLegAAssocs) { + for (auto& [a2, a3] : combinations(groupedLegBAssocs, groupedLegCAssocs)) { + readTriplet(a1, a2, a3, tracks, event, tripletType); + } + } + } 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) + { + 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(Form("TripletsBarrelSE_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + if (fConfigQA && isAmbi) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].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(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].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(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + } + + 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); + } + + void processKaonPionSkimmedMultExtra(MyEventsVtxCovSelectedMultExtra const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, 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); + } + + 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) { + + 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); + } + } + } + } // end loop over reconstructed events + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmed, "Run kaon pion pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmedMultExtra, "Run kaon pion pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionPionSkimmed, "Run kaon pion pion triplets, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", 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; + Produces DileptonTrackTable; + 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 fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap cut for dileptons used in the triplet vertexing"}; + 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 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 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"}; + Configurable fConfigUseMCRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing(reconstructed)"}; + Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; + + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + int fNCuts; + int fNLegCuts; + 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; + std::vector fLegCutNames; + // 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 > fConfigDileptonLowpTCut&& aod::reducedpair::pt 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; + + NoBinningPolicy fHashBin; + + 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"); + bool isMCGen_energycorrelators = context.mOptions.get("processMCGenEnergyCorrelators") || context.mOptions.get("processMCGenEnergyCorrelatorsPion"); + bool isMCGen_energycorrelatorsME = context.mOptions.get("processMCGenEnergyCorrelatorsME") || context.mOptions.get("processMCGenEnergyCorrelatorsPionME"); + + 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; + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + fCCDB->get(fConfigGeoPath); + } + + 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 |= (static_cast(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_PairCutsJSON; + 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 asymmetric-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) + + // Get also the pair cuts specified via the JSON parameters + if (isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCutsJSON", cfgPairing_PairCutsJSON, false); + TString addPairCutsStr = cfgPairing_PairCutsJSON; + if (addPairCutsStr != "") { + std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); + for (auto& t : addPairCuts) { + cfgPairing_PairCuts += Form(",%s", t->GetName()); + } + } + } + + 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(",")); + // If asymmetric pairs are used, the number of cuts should come from the asymmetric-pairing task + if (isBarrelAsymmetric) { + fNLegCuts = cfgPairing_objArrayTrackCuts->GetEntries(); + } else { + fNLegCuts = fNCuts; + } + + // loop over single lepton cuts + if (isBarrel || isBarrelAsymmetric || isMuon) { + for (int icut = 0; icut < fNLegCuts; ++icut) { + + TString pairLegCutName; + + // here we check that this cut is one of those used for building the dileptons + if (!isBarrelAsymmetric) { + if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { + continue; + } + pairLegCutName = fTrackCutNames[icut].Data(); + } else { + // For asymmetric pairs we access the leg cuts instead + pairLegCutName = static_cast(cfgPairing_objArrayTrackCuts->At(icut))->GetString(); + } + fLegCutNames.push_back(pairLegCutName); + + // 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 & (static_cast(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("DileptonsSelected_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data()), "barrel,vertexing"); + 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()); + } + } + } + + if (fNPairCuts != 0) { + + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + 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()); + } + + if (!cfgPairing_strCommonTrackCuts.IsNull()) { + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + 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()); + } + } + } + } + } + } // 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()), ""); + } + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthGenSelBR_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), ""); + } + } + + if (isMCGen_energycorrelators) { + for (auto& sig : fGenMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelators_%s", sig->GetName()), ""); + } + } + + if (isMCGen_energycorrelatorsME) { + for (auto& sig : fGenMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), ""); + } + } + + 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); @@ -1900,7 +3967,7 @@ struct AnalysisDileptonTrack { // 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*/) + 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); @@ -1909,37 +3976,142 @@ struct AnalysisDileptonTrack { VarManager::FillEvent(event, fValuesDilepton); VarManager::FillEvent(event.reducedMCevent(), fValuesDilepton); - uint32_t mcDecision = 0; + 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()); + if (!lepton1.has_reducedMCTrack() || !lepton2.has_reducedMCTrack()) { + continue; + } auto lepton1MC = lepton1.reducedMCTrack(); auto lepton2MC = lepton2.reducedMCTrack(); // Check that the dilepton has zero charge if (dilepton.sign() != 0) { continue; } + // dilepton rap cut + float rap = dilepton.rap(); + if (fConfigUseMCRapcut && abs(rap) > fConfigDileptonRapCutAbs) + continue; VarManager::FillTrack(dilepton, fValuesDilepton); - for (int icut = 0; icut < fNCuts; icut++) { - if (dilepton.filterMap_bit(icut)) { - fHistMan->FillHistClass(fHistNamesDileptons[icut].Data(), fValuesDilepton); + + // fill selected dilepton histograms for each specified selection + for (int icut = 0; icut < fNLegCuts; icut++) { + + if (!dilepton.filterMap_bit(icut)) { + continue; + } + + // regular dileptons + fHistMan->FillHistClass(Form("DileptonsSelected_%s", fLegCutNames[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", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data()), fValuesDilepton); + } + } + for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { + if (dilepton.pairFilterMap_bit(iPairCut)) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fLegCutNames[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", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); + } + } + } + } } } - // loop over hadrons + // loop over track associations for (auto& assoc : assocs) { + VarManager::ResetValues(0, VarManager::kNVars, fValuesHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton); + + 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); + + 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 MC truth values for the B hadron + auto currentMCParticle = trackMC; + if (mcDecision > 0) { + while (true) { + if (currentMCParticle.has_mothers()) { + currentMCParticle = currentMCParticle.template mothers_first_as(); + if (std::abs(currentMCParticle.pdgCode()) > 500 && std::abs(currentMCParticle.pdgCode()) < 549) { // nb! hardcoded pdgcodes + VarManager::FillTrackMC(mcTracks, currentMCParticle, fValuesHadron); + break; + } + } else { + break; + } + } + // fill mc truth vertexing (for the associated track as this will have a displaced vertex, while the B hadron is produced in the PV) + VarManager::FillTrackCollisionMC(trackMC, currentMCParticle, event.reducedMCevent(), fValuesHadron); + } + + // table to be written out for ML analysis + BmesonsTable(event.runNumber(), event.globalIndex(), event.timestamp(), + fValuesHadron[VarManager::kPairMass], dilepton.mass(), fValuesHadron[VarManager::kDeltaMass], fValuesHadron[VarManager::kPairPt], fValuesHadron[VarManager::kPairEta], fValuesHadron[VarManager::kPairPhi], fValuesHadron[VarManager::kPairRap], + fValuesHadron[VarManager::kVertexingLxy], fValuesHadron[VarManager::kVertexingLxyErr], fValuesHadron[VarManager::kVertexingLxyz], fValuesHadron[VarManager::kVertexingLxyzErr], fValuesHadron[VarManager::kVertexingLz], fValuesHadron[VarManager::kVertexingLzErr], + fValuesHadron[VarManager::kVertexingTauxy], fValuesHadron[VarManager::kVertexingTauxyErr], fValuesHadron[VarManager::kVertexingTauz], fValuesHadron[VarManager::kVertexingTauzErr], fValuesHadron[VarManager::kCosPointingAngle], + fValuesHadron[VarManager::kVertexingChi2PCA], + fValuesHadron[VarManager::kMCVertexingLxy], fValuesHadron[VarManager::kMCVertexingLxyz], fValuesHadron[VarManager::kMCVertexingLz], + fValuesHadron[VarManager::kMCVertexingTauxy], fValuesHadron[VarManager::kMCVertexingTauz], fValuesHadron[VarManager::kMCCosPointingAngle], + track.globalIndex(), lepton1.globalIndex(), lepton2.globalIndex(), + track.tpcInnerParam(), track.eta(), dilepton.pt(), dilepton.eta(), lepton1.tpcInnerParam(), lepton1.eta(), lepton2.tpcInnerParam(), lepton2.eta(), + track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tpcNSigmaPr(), track.tofNSigmaKa(), + lepton1.tpcNSigmaEl(), lepton1.tpcNSigmaPi(), lepton1.tpcNSigmaPr(), + lepton2.tpcNSigmaEl(), lepton2.tpcNSigmaPi(), lepton2.tpcNSigmaPr(), + track.itsClusterMap(), lepton1.itsClusterMap(), lepton2.itsClusterMap(), + track.itsChi2NCl(), lepton1.itsChi2NCl(), lepton2.itsChi2NCl(), + track.tpcNClsFound(), lepton1.tpcNClsFound(), lepton2.tpcNClsFound(), + track.tpcChi2NCl(), lepton1.tpcChi2NCl(), lepton2.tpcChi2NCl(), + dilepton.filterMap_raw(), trackSelection, mcDecision); + } + + 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); @@ -1947,15 +4119,18 @@ struct AnalysisDileptonTrack { mcDecision = 0; isig = 0; for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if ((*sig).CheckSignal(false, lepton1MC, lepton2MC, trackMC)) { - mcDecision |= (uint32_t(1) << isig); + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { + mcDecision |= (static_cast(1) << isig); } } } + if constexpr (TCandidateType == VarManager::kBcToThreeMuons) { - if (!assoc.isMuonSelected_bit(fTrackCutBit)) { + trackSelection = (assoc.isMuonSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { continue; } + auto track = assoc.template reducedmuon_as(); if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { continue; @@ -1964,35 +4139,87 @@ struct AnalysisDileptonTrack { VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + if (!track.has_reducedMCTrack()) { + continue; + } auto trackMC = track.reducedMCTrack(); mcDecision = 0; isig = 0; for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if ((*sig).CheckSignal(false, lepton1MC, lepton2MC, trackMC)) { - mcDecision |= (uint32_t(1) << isig); + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { + mcDecision |= (static_cast(1) << isig); } } + // Fill table for correlation analysis + DileptonTrackTable(fValuesHadron[VarManager::kDeltaEta], fValuesHadron[VarManager::kDeltaPhi], + dilepton.mass(), dilepton.pt(), dilepton.eta(), track.pt(), track.eta(), track.phi(), + lepton1.pt(), lepton1.eta(), lepton1.phi(), lepton2.pt(), lepton2.eta(), lepton2.phi(), + mcDecision); } + // 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)) { - fHistMan->FillHistClass(fHistNamesDileptonTrack[icut].Data(), fValuesHadron); - for (isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (uint32_t(1) << isig)) { - // TODO: check also whether the collision association is correct (add dedicated histogram dirs) - fHistMan->FillHistClass(fHistNamesDileptonTrackMCmatched[icut][isig], 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 & (static_cast(1) << iTrackCut))) { + continue; + } + + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); } } - } - } - // 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]); - } + + 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", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[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", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[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", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s_%s", fLegCutNames[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 + } // 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, @@ -2017,6 +4244,26 @@ struct AnalysisDileptonTrack { } } + 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; @@ -2048,30 +4295,271 @@ struct AnalysisDileptonTrack { // 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()); - int isig = 0; - for (auto& track : mcTracks) { - VarManager::FillTrackMC(mcTracks, track); + 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 - isig = 0; for (auto& sig : fGenMCSignals) { - if (sig.CheckSignal(false, track)) { - fHistMan->FillHistClass(fHistNamesMCgen[isig++], VarManager::fgValues); + 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); + } + } + } + + // make a list of all MC tracks in the MC collision corresponding to the current reconstructed event + std::vector mcTrackIndices; + for (auto& t : groupedMCTracks) { + mcTrackIndices.push_back(t.globalIndex()); + } + + // make a three nested for loop over all MC tracks in the vector + for (auto t1 : mcTrackIndices) { + auto track1 = mcTracks.rawIteratorAt(*(&t1)); + for (auto t2 : mcTrackIndices) { + if (t1 == t2) + continue; + // if (t2 < t1) continue; + auto track2 = mcTracks.rawIteratorAt(*(&t2)); + for (auto t3 : mcTrackIndices) { + if (t3 == t1) + continue; + if (t3 == t2) + continue; + auto track3 = mcTracks.rawIteratorAt(*(&t3)); + + for (auto& sig : fRecMCSignals) { + if (sig->CheckSignal(true, track1, track2, track3)) { + + VarManager::FillTripleMC(track1, track2, track3, VarManager::fgValues); // nb! hardcoded for jpsiK + + fHistMan->FillHistClass(Form("MCTruthGenSelBR_%s", sig->GetName()), VarManager::fgValues); + + // apply kinematic cuts + if (track1.pt() < fConfigMCGenDileptonLegPtMin.value || std::abs(track1.eta()) > fConfigMCGenDileptonLegEtaAbs.value) { + continue; + } + if (track2.pt() < fConfigMCGenDileptonLegPtMin.value || std::abs(track2.eta()) > fConfigMCGenDileptonLegEtaAbs.value) { + continue; + } + if (track3.pt() < fConfigMCGenHadronPtMin.value || std::abs(track3.eta()) > fConfigMCGenHadronEtaAbs.value) { + continue; + } + fHistMan->FillHistClass(Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + } // end loop over reconstructed events + } + + template + void runEnergyCorrelators(TEvent const& event, TMCTracks const& mcTracks) + { + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& t1 : groupedMCTracks) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + // apply kinematic cuts for signal + if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) + continue; + if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) + continue; + // for the energy correlators + for (auto& t2 : groupedMCTracks) { + auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); + if (TMath::Abs(t2_raw.pdgCode()) == 443 || TMath::Abs(t2_raw.pdgCode()) == 11 || TMath::Abs(t2_raw.pdgCode()) == 22) + continue; + if (t2_raw.pt() < fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCGenHadronEtaAbs.value) + continue; + if (t2_raw.getGenStatusCode() <= 0) + continue; + VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelators_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + void processMCGenEnergyCorrelators(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + runEnergyCorrelators(event, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsPion(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + runEnergyCorrelators(event, mcTracks); + } + } + + template + void runEnergyCorrelatorsMixedEvent(TEvent const& event1, TEvent const& event2, TMCTracks const& mcTracks) + { + auto groupedMCTracks1 = mcTracks.sliceBy(perReducedMcEvent, event1.reducedMCeventId()); + auto groupedMCTracks2 = mcTracks.sliceBy(perReducedMcEvent, event2.reducedMCeventId()); + groupedMCTracks1.bindInternalIndicesTo(&mcTracks); + groupedMCTracks2.bindInternalIndicesTo(&mcTracks); + for (auto& t1 : groupedMCTracks1) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + // apply kinematic cuts for signal + if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) + continue; + if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) + continue; + // for the energy correlators + for (auto& t2 : groupedMCTracks2) { + auto t2_raw = groupedMCTracks2.rawIteratorAt(t2.globalIndex()); + if (TMath::Abs(t2_raw.pdgCode()) == 443 || TMath::Abs(t2_raw.pdgCode()) == 11 || TMath::Abs(t2_raw.pdgCode()) == 22) + continue; + if (t2_raw.pt() < fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCGenHadronEtaAbs.value) + continue; + if (t2_raw.getGenStatusCode() <= 0) + continue; + VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), VarManager::fgValues); + } } } } } + void processMCGenEnergyCorrelatorsME(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + // loop over two event comibnations + for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { + if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { + continue; + } + if (!event1.has_reducedMCevent() || !event2.has_reducedMCevent()) { + continue; + } + runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsPionME(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + // loop over two event comibnations + for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { + if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { + continue; + } + if (!event1.has_reducedMCevent() || !event2.has_reducedMCevent()) { + continue; + } + runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); + } + } + 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, processDummy, "Dummy function", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelators, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPion, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPionME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) @@ -2082,6 +4570,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; } @@ -2120,11 +4609,11 @@ 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")) { + if (classStr.Contains("Muon") && !classStr.Contains("Pairs")) { if (!classStr.Contains("Ambiguity")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); } else { @@ -2136,14 +4625,24 @@ 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("MCTruthGenPair")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair", histName); } - if (classStr.Contains("MCTruthGen")) { + if (classStr.Contains("MCTruthGenSelBR")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_triple"); + } else if (classStr.Contains("MCTruthGen")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); } + // 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"); } @@ -2167,5 +4666,10 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char if (classStr.Contains("DileptonHadronCorrelation")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); } + + if (classStr.Contains("MCTruthEenergyCorrelators")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy-correlator-gen"); + } + } // end loop over histogram classes } diff --git a/PWGDQ/Tasks/dqFlow.cxx b/PWGDQ/Tasks/dqFlow.cxx index 7bcef060827..52e3ca8c29c 100644 --- a/PWGDQ/Tasks/dqFlow.cxx +++ b/PWGDQ/Tasks/dqFlow.cxx @@ -16,11 +16,13 @@ /// o2-analysis-timestamp --aod-file AO2D.root -b | o2-analysis-event-selection -b | o2-analysis-multiplicity-table -b | o2-analysis-centrality-table -b | o2-analysis-fdd-converter -b | o2-analysis-trackselection -b | o2-analysis-trackextension -b | o2-analysis-pid-tpc-full -b | o2-analysis-pid-tof-full -b | o2-analysis-pid-tof-base -b | o2-analysis-pid-tof-beta -b | o2-analysis-dq-flow -b /// tested (June 2, 2022) on AO2D.root files from train production 242 +#include +#include +#include +#include #include #include #include -#include -#include #include #include "CCDB/BasicCCDBManager.h" #include "Framework/runDataProcessing.h" @@ -64,26 +66,30 @@ using MyBcs = soa::Join; using MyEvents = soa::Join; using MyEventsWithCent = soa::Join; -using MyEventsWithCentRun3 = soa::Join; -using MyEventsWithCentQvectRun3 = soa::Join; - -using MyBarrelTracks = soa::Join; -using MyBarrelTracksWithCov = soa::Join; +using MyEventsWithCentRun3 = soa::Join; +// using MyEventsWithCentQvectRun3 = soa::Join; +// using MyEventsWithCentQvectRun3 = soa::Join; +using MyEventsWithCentQvectRun3 = soa::Join; + +// using MyBarrelTracks = soa::Join; +// using MyBarrelTracksWithCov = soa::Joini; + +using MyBarrelTracks = soa::Join; +using MyBarrelTracksWithCov = soa::Join; using MyTracks = soa::Filtered>; using MyMuons = aod::FwdTracks; 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); @@ -99,10 +105,9 @@ 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"}; @@ -112,9 +117,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 @@ -128,7 +134,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 @@ -186,7 +192,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 @@ -216,6 +222,45 @@ struct DQEventQvector { 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) { @@ -293,8 +338,9 @@ 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()); } } @@ -333,9 +379,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) { @@ -348,7 +399,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; } @@ -459,10 +510,10 @@ 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 (bc.has_zdc()) { @@ -479,18 +530,13 @@ struct DQEventQvector { } } 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); } } } diff --git a/PWGDQ/Tasks/filterPP.cxx b/PWGDQ/Tasks/filterPP.cxx index 6cd9fad6d7e..61065f3fc74 100644 --- a/PWGDQ/Tasks/filterPP.cxx +++ b/PWGDQ/Tasks/filterPP.cxx @@ -11,33 +11,40 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // -#include -#include -#include -#include -#include -#include -#include -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/DataTypes.h" -#include "Framework/runDataProcessing.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + #include "Common/CCDB/TriggerAliases.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" #include "EventFiltering/filterTables.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 "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -59,6 +66,7 @@ enum DQTriggers { kSingleMuLow, kSingleMuHigh, kDiMuon, + kElectronMuon, kNTriggersDQ }; } // namespace @@ -176,8 +184,8 @@ struct DQBarrelTrackSelection { Configurable fConfigCuts{"cfgBarrelTrackCuts", "jpsiPID1", "Comma separated list of barrel track cuts"}; Configurable fConfigQA{"cfgWithQA", false, "If true, fill QA histograms"}; - 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 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"}; Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; @@ -247,14 +255,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) { @@ -263,7 +271,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); } @@ -331,16 +339,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) { @@ -349,7 +357,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); } @@ -386,8 +394,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 @@ -496,14 +504,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; } @@ -515,7 +523,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; } } @@ -526,7 +534,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) } @@ -539,7 +547,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); } } @@ -556,12 +564,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)) { @@ -579,7 +587,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; } } @@ -590,7 +598,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) } @@ -603,7 +611,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); } } @@ -620,12 +628,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)) { @@ -648,7 +656,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; @@ -657,7 +665,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; @@ -665,7 +673,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 4f92cf7cc90..850b5811d8a 100644 --- a/PWGDQ/Tasks/filterPPwithAssociation.cxx +++ b/PWGDQ/Tasks/filterPPwithAssociation.cxx @@ -11,42 +11,49 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // -#include -#include -#include -#include -#include -#include -#include -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/DataTypes.h" -#include "Framework/runDataProcessing.h" -#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 "EventFiltering/filterTables.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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" -#include "CommonConstants/LHCConstants.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/TriggerAliases.h" #include "Common/Core/CollisionAssociation.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "EventFiltering/filterTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" #include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" #include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" + #include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -68,6 +75,7 @@ enum DQTriggers { kSingleMuLow, kSingleMuHigh, kDiMuon, + kElectronMuon, kNTriggersDQ }; } // namespace @@ -78,14 +86,18 @@ namespace dqppfilter DECLARE_SOA_COLUMN(IsDQEventSelected, isDQEventSelected, int); DECLARE_SOA_COLUMN(IsDQBarrelSelected, isDQBarrelSelected, uint32_t); DECLARE_SOA_COLUMN(IsDQMuonSelected, isDQMuonSelected, uint32_t); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision index -DECLARE_SOA_INDEX_COLUMN(Track, track); //! Track index -DECLARE_SOA_INDEX_COLUMN(FwdTrack, fwdtrack); //! FwdTrack index +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 } // namespace dqppfilter 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; @@ -98,21 +110,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; @@ -122,6 +142,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&) @@ -143,14 +164,14 @@ struct DQEventSelectionTask { 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;", 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); @@ -169,9 +190,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&) @@ -185,14 +206,17 @@ 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 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 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"}; Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; @@ -201,6 +225,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. @@ -208,6 +233,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) { @@ -219,6 +245,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) { @@ -233,18 +270,15 @@ struct DQBarrelTrackSelection { fCutHistNames.push_back(Form("TrackBarrel_%s", cut.GetName())); } - DefineHistograms(fHistMan, cutNames.Data()); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + 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); } } @@ -255,8 +289,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")); @@ -270,21 +310,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); @@ -292,13 +335,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 } @@ -310,24 +360,36 @@ 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 fConfigCcdbUrl{"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"}; @@ -341,6 +403,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&) @@ -355,12 +418,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) { @@ -375,8 +445,8 @@ struct DQMuonsSelection { fCutHistNames.push_back(Form("Muon_%s", fTrackCuts[i].GetName())); } - DefineHistograms(fHistMan, cutNames.Data()); // define all histograms - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + 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()); } } @@ -396,13 +466,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) { @@ -414,13 +487,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 } @@ -440,67 +520,6 @@ 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; @@ -510,12 +529,13 @@ struct DQFilterPPTask { 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 fConfigCcdbUrl{"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"}; @@ -524,20 +544,29 @@ struct DQFilterPPTask { int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - int fNBarrelCuts; // number of barrel selections - int fNMuonCuts; // number of 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 fBarrelNreqObjs; // minimal number of tracks/pairs required (barrel) - std::vector fMuonNreqObjs; // minimal number of tracks/pairs required (muon) - std::map fBarrelPairCuts; // map of barrel pair cuts - std::map fMuonPairCuts; // map of 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 + 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; @@ -584,10 +613,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 TH1D("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) { @@ -600,6 +651,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&) @@ -614,6 +670,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(); @@ -629,7 +718,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()); } @@ -657,161 +750,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(); - // 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; + } - // 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) { + // 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; + } + } + + 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; @@ -822,24 +1061,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 barrelMask = 0; - for (int i = 0; i < fNBarrelCuts; i++) { - barrelMask |= (uint64_t(1) << i); + 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++; } - uint64_t muonMask = 0; - for (int i = fNBarrelCuts; i < fNBarrelCuts + fNMuonCuts; i++) { - muonMask |= (uint64_t(1) << i); + + // 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); + + 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 = 0; i < fNMuonCuts; i++) { + muonMask |= (static_cast(1) << i); + } // Loop over collisions // int event = 0; int eventsFired = 0; @@ -849,14 +1145,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++; @@ -865,21 +1160,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()) { @@ -894,33 +1181,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) { @@ -960,23 +1220,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]); } } @@ -990,6 +1250,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); }; @@ -1003,7 +1264,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. @@ -1014,23 +1275,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 a562b34d4df..4841078f61d 100644 --- a/PWGDQ/Tasks/filterPbPb.cxx +++ b/PWGDQ/Tasks/filterPbPb.cxx @@ -9,14 +9,21 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGUD/Core/SGSelector.h" + +#include "CommonConstants/LHCConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Vertex.h" #include + #include + #include -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGDQ/Core/VarManager.h" -#include "CommonConstants/LHCConstants.h" +#include +#include using namespace std; @@ -29,11 +36,9 @@ using MyEvents = soa::Join; using MyBCs = soa::Join; struct DQFilterPbPbTask { - Produces eventFilter; - OutputObj fStats{"Statistics"}; + Produces eventRapidityGapFilter; 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,221 +56,78 @@ 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 TH1D("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 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, "!A && !C"); - fFilterOutcome->GetXaxis()->SetBinLabel(4, "!A && C"); - fFilterOutcome->GetXaxis()->SetBinLabel(5, "A && !C"); - fFilterOutcome->GetXaxis()->SetBinLabel(6, "A && C"); - fFilterOutcome->GetXaxis()->SetBinLabel(7, Form("numContrib not in [%d, %d]", fConfigMinNPVCs.value, fConfigMaxNPVCs.value)); - fFilterOutcome->GetXaxis()->SetBinLabel(8, "BC not found"); - - 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"); - } + 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"); + + 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, - bool useFV0, bool useFT0, bool useFDD) + void processUDSGSelector(MyEvents::iterator const& collision, MyBCs const& bcs, + aod::FT0s& ft0s, aod::FV0As& fv0as, aod::FDDs& fdds, aod::Zdcs& /*zdcs*/) { - fFilterOutcome->Fill(1., 1.); - // Find BC associated with collision + uint64_t filter = 0; + fFilterOutcome->Fill(1, 1.); if (!collision.has_foundBC()) { - fFilterOutcome->Fill(8., 1); - return 0; - } - // foundBCId is stored in EvSels - auto bc = collision.template foundBC_as(); - - // Obtain slice of compatible BCs - uint64_t mostProbableBC = bc.globalBC(); - uint64_t meanBC = mostProbableBC + std::lround(collision.collisionTime() / o2::constants::lhc::LHCBunchSpacingNS); - int deltaBC = std::ceil(collision.collisionTimeRes() / o2::constants::lhc::LHCBunchSpacingNS * nDtColl); - if (deltaBC < minNBCs) { - deltaBC = minNBCs; - } - - // Range of BCs to consider - uint64_t minBC = (uint64_t)deltaBC < meanBC ? meanBC - (uint64_t)deltaBC : 0; - uint64_t maxBC = meanBC + (uint64_t)deltaBC; - - int slicemin = 0; - int slicemax = 0; - // Check if there is overlap between acceptable and possible BCs - if (maxBC > bcs.iteratorAt(0).globalBC() && minBC < bcs.iteratorAt(bcs.size() - 1).globalBC()) { - // find slice of BCs table with BC in [minBC, maxBC] - int moveCount = 0; - int64_t minBCId = bc.globalIndex(); - int64_t maxBCId = bc.globalIndex(); - // lower limit - if (bc.globalBC() < minBC) { - while (bc != bcs.end() && bc.globalBC() < minBC) { - ++bc; - ++moveCount; - minBCId = bc.globalIndex(); - } - } else { - while (bc.globalIndex() > 0 && bc.globalBC() >= minBC) { - minBCId = bc.globalIndex(); - --bc; - --moveCount; - } - } - // upper limit - if (bc.globalBC() < maxBC) { - while (bc != bcs.end() && bc.globalBC() <= maxBC) { - maxBCId = bc.globalIndex(); - ++bc; - ++moveCount; - } - } else { - while (bc.globalIndex() > 0 && bc.globalBC() > maxBC) { - --bc; - --moveCount; - maxBCId = bc.globalIndex(); - } - } - // reset bc - bc.moveByIndex(-moveCount); - // Create BC slice - slicemin = minBCId; - slicemax = maxBCId - minBCId + 1; - } - MyBCs bcrange{{bcs.asArrowTable()->Slice(slicemin, slicemax)}, (uint16_t)slicemin}; - // Rapidity gap condition: Check FIT activity in BC range - bool isSideAClean = true; - bool isSideCClean = true; - - for (auto const& bc : bcrange) { - if (useFV0) { - if (bc.has_foundFV0()) { - auto fv0a = fv0as.iteratorAt(bc.foundFV0Id()); - float FV0Amplitude = 0; - for (auto amp : fv0a.amplitude()) { - FV0Amplitude += amp; - } - float FV0Time = std::abs(fv0a.time()); - if (FV0Amplitude > FITAmpLimits[0] || FV0Time > maxFITTime) { - isSideAClean = false; - } - } - } - if (useFT0) { - if (bc.has_foundFT0()) { - auto ft0 = ft0s.iteratorAt(bc.foundFT0Id()); - float FT0AAmplitude = 0; - float FT0CAmplitude = 0; - for (auto amp : ft0.amplitudeA()) { - FT0AAmplitude += amp; - } - for (auto amp : ft0.amplitudeC()) { - FT0CAmplitude += amp; - } - float FT0ATime = std::abs(ft0.timeA()); - float FT0CTime = std::abs(ft0.timeC()); - if (FT0AAmplitude > FITAmpLimits[1] || FT0ATime > maxFITTime) { - isSideAClean = false; - } - if (FT0CAmplitude > FITAmpLimits[2] || FT0CTime > maxFITTime) { - isSideCClean = false; - } - } - } - if (useFDD) { - if (bc.has_foundFDD()) { - auto fdd = fdds.iteratorAt(bc.foundFDDId()); - float FDDAAmplitude = 0; - float FDDCAmplitude = 0; - for (auto amp : fdd.chargeA()) { - FDDAAmplitude += amp; - } - for (auto amp : fdd.chargeC()) { - FDDCAmplitude += amp; - } - float FDDATime = std::abs(fdd.timeA()); - float FDDCTime = std::abs(fdd.timeC()); - if (FDDAAmplitude > FITAmpLimits[3] || FDDATime > maxFITTime) { - isSideAClean = false; - } - if (FDDCAmplitude > FITAmpLimits[4] || FDDCTime > maxFITTime) { - isSideCClean = false; - } - } - } + fFilterOutcome->Fill(7, 1); + return; } - // Compute FIT decision - uint64_t FITDecision = 0; - if (isSideAClean && isSideCClean) { + 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 |= (static_cast(1) << VarManager::kSingleGapA); fFilterOutcome->Fill(3, 1); - if (eventTypes & (uint32_t(1) << 0)) { - FITDecision |= (uint64_t(1) << VarManager::kDoubleGap); - } - } - if (isSideAClean && !isSideCClean) { + } else if (issgevent == 1) { + filter |= (static_cast(1) << VarManager::kSingleGapC); fFilterOutcome->Fill(4, 1); - if (eventTypes & (uint32_t(1) << 1)) { - FITDecision |= (uint64_t(1) << VarManager::kSingleGapA); - } - } else if (!isSideAClean && isSideCClean) { + } else if (issgevent == 2) { + filter |= (static_cast(1) << VarManager::kDoubleGap); + fFilterOutcome->Fill(2, 1); + } else if (issgevent == 3) { fFilterOutcome->Fill(5, 1); - if (eventTypes & (uint32_t(1) << 1)) { - FITDecision |= (uint64_t(1) << VarManager::kSingleGapC); - } - } else if (!isSideAClean && !isSideCClean) { + } else if (issgevent == 4) { fFilterOutcome->Fill(6, 1); } - if (!FITDecision) { - return 0; + // 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); - // Number of primary vertex contributors - if (collision.numContrib() < minNPVCs || collision.numContrib() > maxNPVCs) { - fFilterOutcome->Fill(7, 1); - return 0; + // Record whether UPC settings were used for this event + if (collision.flags() & dataformats::Vertex>::Flags::UPCMode) { + filter |= (static_cast(1) << VarManager::kITSUPCMode); + fFilterOutcome->Fill(8, 1); } - // If we made it here, the event passed - fFilterOutcome->Fill(2, 1); - // Return filter bitmap corresponding to FIT decision - return FITDecision; - } - - 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, - fConfigUseFV0, fConfigUseFT0, fConfigUseFDD); - - bool isSelected = filter; - fStats->Fill(-1.0, isSelected); - - eventFilter(filter); + eventRapidityGapFilter(filter, newbc.globalIndex()); } void processDummy(MyEvents&) @@ -273,7 +135,7 @@ struct DQFilterPbPbTask { // do nothing } - 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..c3dbce0865f 100644 --- a/PWGDQ/Tasks/mchAlignRecord.cxx +++ b/PWGDQ/Tasks/mchAlignRecord.cxx @@ -14,62 +14,61 @@ /// /// \author Chi ZHANG, CEA-Saclay, chi.zhang@cern.ch -#include -#include -#include -#include -#include -#include +#include "PWGDQ/Core/VarManager.h" + +#include "Common/DataModel/EventSelection.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "CommonUtils/NameConf.h" +#include "DataFormatsMCH/Cluster.h" +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/DetectorNameConf.h" #include "Framework/AnalysisTask.h" +#include "Framework/CallbackService.h" +#include "Framework/Logger.h" #include "Framework/runDataProcessing.h" +#include "MCHAlign/Aligner.h" +#include "MCHBase/TrackerParam.h" +#include "MCHGeometryTransformer/Transformations.h" +#include "MCHTracking/Track.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackFitter.h" +#include "MCHTracking/TrackParam.h" +#include "ReconstructionDataFormats/TrackMCHMID.h" #include +#include #include #include #include +#include +#include #include #include #include +#include #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include "CommonConstants/LHCConstants.h" -#include "CommonUtils/NameConf.h" -#include "Common/DataModel/EventSelection.h" -#include "PWGDQ/Core/VarManager.h" - -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/GRPGeomHelper.h" -#include "DetectorsBase/Propagator.h" -#include "Framework/Logger.h" -#include "Framework/CallbackService.h" -#include "CCDB/BasicCCDBManager.h" - -#include "MCHGeometryTransformer/Transformations.h" -#include "DataFormatsMCH/Cluster.h" -#include "DataFormatsMCH/TrackMCH.h" -#include "MCHTracking/Track.h" -#include "MCHTracking/TrackExtrap.h" -#include "MCHTracking/TrackParam.h" -#include "MCHTracking/TrackFitter.h" -#include "MCHBase/TrackerParam.h" -#include "ReconstructionDataFormats/TrackMCHMID.h" -#include "MCHAlign/Aligner.h" -#include "DetectorsCommonDataFormats/AlignParam.h" -#include "DetectorsCommonDataFormats/DetID.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -104,13 +103,32 @@ struct mchAlignRecordTask { map transformNew; mch::geo::TransformationCreator transformation; - 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"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fFixChamber{"fix-chamber", "", "Fixing chamber"}; + 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"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fFixChamber{"fix-chamber", "", "Fixing chamber"}; 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 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 +140,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 +336,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 index b2031418d5c..897ed273322 100644 --- a/PWGDQ/Tasks/muonDCA.cxx +++ b/PWGDQ/Tasks/muonDCA.cxx @@ -13,14 +13,15 @@ /// \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 "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + #include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGDQ/Core/VarManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "GlobalTracking/MatchGlobalFwd.h" using namespace o2; using namespace o2::framework; @@ -44,7 +45,7 @@ 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"}; + 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 diff --git a/PWGDQ/Tasks/qaMatching.cxx b/PWGDQ/Tasks/qaMatching.cxx new file mode 100644 index 00000000000..885aa65b646 --- /dev/null +++ b/PWGDQ/Tasks/qaMatching.cxx @@ -0,0 +1,1834 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file qaMatching.cxx +/// \brief Task to compute and evaluate DCA quantities +/// \author Nicolas Bizé , SUBATECH +// +#include "PWGDQ/Core/MuonMatchingMlResponse.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MFTTracking/Constants.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod; + +using MyEvents = soa::Join; +using MyMuonsWithCov = soa::Join; +using MyMuonsMC = soa::Join; +using MyMFTs = aod::MFTTracks; +using MyMFTCovariances = aod::MFTTracksCov; +using MyMFTsMC = soa::Join; + +using MyMuon = MyMuonsWithCov::iterator; +using MyMuonMC = MyMuonsMC::iterator; +using MyMFT = MyMFTs::iterator; +using MyMFTCovariance = MyMFTCovariances::iterator; + +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; + +static float chi2ToScore(float chi2) +{ + return (1.f / (chi2 / 100.f + 1.f)); +} + +struct qaMatching { + //// Variables for selecting muon tracks + 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, ""}; + + //// 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 for selecting global tracks + Configurable fMatchingChi2ScoreMftMchLow{"cfgMatchingChi2ScoreMftMchLow", chi2ToScore(50.f), ""}; + + //// Variables for selecting tagged muons + Configurable fMuonTaggingNCrossedMftPlanesLow{"cfgMuonTaggingNCrossedMftPlanesLow", 5, ""}; + Configurable fMuonTaggingTrackChi2MchUp{"cfgMuonTaggingTrackChi2MchUp", 5.f, ""}; + Configurable fMuonTaggingPMchLow{"cfgMuonTaggingPMchLow", 0.0f, ""}; + Configurable fMuonTaggingPtMchLow{"cfgMuonTaggingPtMchLow", 0.7f, ""}; + Configurable fMuonTaggingEtaMchLow{"cfgMuonTaggingEtaMchLow", -3.6f, ""}; + Configurable fMuonTaggingEtaMchUp{"cfgMuonTaggingEtaMchUp", -2.5f, ""}; + Configurable fMuonTaggingRabsLow{"cfgMuonTaggingRabsLow", 17.6f, ""}; + Configurable fMuonTaggingRabsUp{"cfgMuonTaggingRabsUp", 89.5f, ""}; + Configurable fMuonTaggingSigmaPdcaUp{"cfgMuonTaggingPdcaUp", 4.f, ""}; + Configurable fMuonTaggingChi2DiffLow{"cfgMuonTaggingChi2DiffLow", 100.f, ""}; + + /// Variables to event mixing criteria + Configurable fSaveMixedMatchingParamsRate{"cfgSaveMixedMatchingParamsRate", 0.002f, ""}; + Configurable fEventMaxDeltaNMFT{"cfgEventMaxDeltaNMFT", 1, ""}; + Configurable fEventMaxDeltaVtxZ{"cfgEventMaxDeltaVtxZ", 1.f, ""}; + Configurable fEventMinDeltaBc{"cfgEventMinDeltaBc", 500, ""}; + + //// 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"}; + + // CCDB connection configurables + struct : ConfigurableGroup { + 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"}; + Configurable fConfigGrpPath{"grpPath-", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable fConfigGeoPath{"geoPath-", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable fConfigGrpMagPath{"grpmagPath-", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + } fConfigCCDB; + + /// Variables for histograms configuration + Configurable fNCandidatesMax{"nCandidatesMax", 5, ""}; + + double mBzAtMftCenter{0}; + + o2::globaltracking::MatchGlobalFwd mExtrap; + + using MatchingFunc_t = std::function; + std::map mMatchingFunctionMap; ///< MFT-MCH Matching function + + // Chi2 matching interface + static constexpr int sChi2FunctionsNum = 3; + struct : ConfigurableGroup { + std::array, sChi2FunctionsNum> fFunctionLabel{{ + {"cfgChi2FunctionLabel_0", std::string{"ProdAll"}, "Text label identifying this chi2 matching method"}, + {"cfgChi2FunctionLabel_1", std::string{"MatchXYPhiTanlMom"}, "Text label identifying this chi2 matching method"}, + {"cfgChi2FunctionLabel_2", std::string{"MatchXYPhiTanl"}, "Text label identifying this chi2 matching method"}, + }}; + std::array, sChi2FunctionsNum> fFunctionName{{{"cfgChi2FunctionNames_0", std::string{"prod"}, "Name of the chi2 matching function"}, + {"cfgChi2FunctionNames_1", std::string{"matchALL"}, "Name of the chi2 matching function"}, + {"cfgChi2FunctionNames_2", std::string{"matchXYPhiTanl"}, "Name of the chi2 matching function"}}}; + std::array, sChi2FunctionsNum> fMatchingScoreCut{{ + {"cfgChi2FunctionMatchingScoreCut_0", 0.f, "Minimum score value for selecting good matches"}, + {"cfgChi2FunctionMatchingScoreCut_1", chi2ToScore(50.f), "Minimum score value for selecting good matches"}, + {"cfgChi2FunctionMatchingScoreCut_2", chi2ToScore(50.f), "Minimum score value for selecting good matches"}, + }}; + std::array, sChi2FunctionsNum> fMatchingPlaneZ{{ + {"cfgChi2FunctionMatchingPlaneZ_0", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}, + {"cfgChi2FunctionMatchingPlaneZ_1", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}, + {"cfgChi2FunctionMatchingPlaneZ_2", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}, + }}; + } fConfigChi2MatchingOptions; + + // ML interface + static constexpr int sMLModelsNum = 2; + struct : ConfigurableGroup { + std::array, sMLModelsNum> fModelLabel{{ + {"cfgMLModelLabel_0", std::string{"TestModel"}, "Text label identifying this group of ML models"}, + {"cfgMLModelLabel_1", std::string{""}, "Text label identifying this group of ML models"}, + }}; + std::array>, sMLModelsNum> fModelPathsCCDB{{{"cfgMLModelPathsCCDB_0", std::vector{"Users/m/mcoquet/MLTest"}, "Paths of models on CCDB"}, + {"cfgMLModelPathsCCDB_1", std::vector{}, "Paths of models on CCDB"}}}; + std::array>, sMLModelsNum> fInputFeatures{{{"cfgMLInputFeatures_0", std::vector{"chi2MCHMFT"}, "Names of ML model input features"}, + {"cfgMLInputFeatures_1", std::vector{}, "Names of ML model input features"}}}; + std::array>, sMLModelsNum> fModelNames{{{"cfgMLModelNames_0", std::vector{"model.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}, + {"cfgMLModelNames_1", std::vector{}, "ONNX file names for each pT bin (if not from CCDB full path)"}}}; + std::array, sMLModelsNum> fMatchingScoreCut{{ + {"cfgMLModelMatchingScoreCut_0", 0.f, "Minimum score value for selecting good matches"}, + {"cfgMLModelMatchingScoreCut_1", 0.f, "Minimum score value for selecting good matches"}, + }}; + std::array, sMLModelsNum> fMatchingPlaneZ{{ + {"cfgMLModelMatchingPlaneZ_0", static_cast(o2::mft::constants::mft::LayerZCoordinate()[9]), "Z position of the matching plane"}, + {"cfgMLModelMatchingPlaneZ_1", 0.f, "Z position of the matching plane"}, + }}; + } fConfigMlOptions; + + std::vector binsPtMl; + std::array cutValues; + std::vector cutDirMl; + std::map> matchingMlResponses; + std::map matchingChi2Functions; + std::map matchingPlanesZ; + std::map matchingScoreCuts; + + int mRunNumber{0}; // needed to detect if the run changed and trigger update of magnetic field + + Service ccdbManager; + o2::ccdb::CcdbApi fCCDBApi; + + o2::aod::rctsel::RCTFlagsChecker rctChecker{"CBT_muon_glo", false, false, true}; + + // vector of all MFT-MCH(-MID) matching candidates associated to the same MCH(-MID) track, + // to be sorted in descending order with respect to the matching score + // the map key is the MCH(-MID) track global index + // the elements are pairs og global muon track indexes and associated matching scores + // for matching candidates computed with the chi2 method, the score is defined as 1/(1+chi2) + using MatchingCandidates = std::map>>; + + struct CollisionInfo { + int64_t index{0}; + uint64_t bc{0}; + // z position of the collision + double zVertex{0}; + // number of MFT tracks associated to the collision + int mftTracksMultiplicity{0}; + // vector of MFT track indexes + std::vector mftTracks; + // vector of MCH(-MID) track indexes + std::vector mchTracks; + // matching candidates + MatchingCandidates matchingCandidates; + // vector of MFT-MCH track index pairs belonging to the same MC particle + std::vector> matchablePairs; + // vector of MCH track indexes that are expected to have an associated MFT track + std::vector taggedMuons; + }; + + using CollisionInfos = std::map; + + std::unordered_map mftTrackCovs; + + std::vector> fMatchablePairs; + MatchingCandidates fMatchingCandidates; + std::vector fTaggedMuons; + + HistogramRegistry registry{"registry", {}}; + HistogramRegistry registryMatching{"registryMatching", {}}; + HistogramRegistry registryAlignment{"registryAlignment", {}}; + + std::unordered_map matchingHistos; + + struct EfficiencyPlotter { + o2::framework::HistPtr p_num; + o2::framework::HistPtr p_den; + o2::framework::HistPtr pt_num; + o2::framework::HistPtr pt_den; + o2::framework::HistPtr phi_num; + o2::framework::HistPtr phi_den; + o2::framework::HistPtr eta_num; + o2::framework::HistPtr eta_den; + + EfficiencyPlotter(std::string path, std::string title, + HistogramRegistry& registry) + { + AxisSpec pAxis = {100, 0, 100, "p (GeV/c)"}; + AxisSpec pTAxis = {100, 0, 10, "p_{T} (GeV/c)"}; + AxisSpec etaAxis = {100, -4, -2, "#eta"}; + AxisSpec phiAxis = {90, -180, 180, "#phi (degrees)"}; + + std::string histName; + std::string histTitle; + + // momentum dependence + histName = path + "p_num"; + histTitle = title + " vs. p - num"; + p_num = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {pAxis}}); + + histName = path + "p_den"; + histTitle = title + " vs. p - den"; + p_den = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {pAxis}}); + + // pT dependence + histName = path + "pt_num"; + histTitle = title + " vs. p_{T} - num"; + pt_num = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {pTAxis}}); + + histName = path + "pt_den"; + histTitle = title + " vs. p_{T} - den"; + pt_den = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {pTAxis}}); + + // eta dependence + histName = path + "eta_num"; + histTitle = title + " vs. #eta - num"; + eta_num = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {etaAxis}}); + + histName = path + "eta_den"; + histTitle = title + " vs. #eta - den"; + eta_den = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {etaAxis}}); + + // phi dependence + histName = path + "phi_num"; + histTitle = title + " vs. #phi - num"; + phi_num = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {phiAxis}}); + + histName = path + "phi_den"; + histTitle = title + " vs. #phi - den"; + phi_den = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {phiAxis}}); + } + + template + void Fill(const T& track, bool passed) + { + double phi = track.phi() * 180 / TMath::Pi(); + std::get>(p_den)->Fill(track.p()); + std::get>(pt_den)->Fill(track.pt()); + std::get>(eta_den)->Fill(track.eta()); + std::get>(phi_den)->Fill(phi); + + if (passed) { + std::get>(p_num)->Fill(track.p()); + std::get>(pt_num)->Fill(track.pt()); + std::get>(eta_num)->Fill(track.eta()); + std::get>(phi_num)->Fill(phi); + } + } + }; + + struct MatchingPlotter { + o2::framework::HistPtr fTrueMatchRanking; + o2::framework::HistPtr fTrueMatchRankingVsP; + o2::framework::HistPtr fTrueMatchRankingVsPt; + //- + o2::framework::HistPtr fTrueMatchRankingGoodMCH; + o2::framework::HistPtr fTrueMatchRankingGoodMCHVsP; + o2::framework::HistPtr fTrueMatchRankingGoodMCHVsPt; + //- + o2::framework::HistPtr fTrueMatchRankingPairedMCH; + o2::framework::HistPtr fTrueMatchRankingPairedMCHVsP; + o2::framework::HistPtr fTrueMatchRankingPairedMCHVsPt; + //- + o2::framework::HistPtr fTrueMatchRankingGoodPairedMCH; + o2::framework::HistPtr fTrueMatchRankingGoodPairedMCHVsP; + o2::framework::HistPtr fTrueMatchRankingGoodPairedMCHVsPt; + //- + o2::framework::HistPtr fTrueMatchRankingGoodPairedMCHMFT; + o2::framework::HistPtr fTrueMatchRankingGoodPairedMCHMFTVsP; + o2::framework::HistPtr fTrueMatchRankingGoodPairedMCHMFTVsPt; + //- + o2::framework::HistPtr fMissedMatches; + o2::framework::HistPtr fMissedMatchesGoodMCH; + o2::framework::HistPtr fMissedMatchesGoodMCHMFT; + //- + o2::framework::HistPtr fMatchRankingWrtProd; + o2::framework::HistPtr fMatchRankingWrtProdVsP; + o2::framework::HistPtr fMatchRankingWrtProdVsPt; + //- + o2::framework::HistPtr fTrueMatchScore; + o2::framework::HistPtr fTrueMatchScoreVsP; + o2::framework::HistPtr fTrueMatchScoreVsPt; + o2::framework::HistPtr fFakeMatchScore; + o2::framework::HistPtr fFakeMatchScoreVsP; + o2::framework::HistPtr fFakeMatchScoreVsPt; + EfficiencyPlotter fMatchingPurityPlotter; + EfficiencyPlotter fPairingEfficiencyPlotter; + EfficiencyPlotter fMatchingEfficiencyPlotter; + EfficiencyPlotter fFakeMatchingEfficiencyPlotter; + + MatchingPlotter(std::string path, + HistogramRegistry& registry) + : fMatchingPurityPlotter(path + "matching-purity/", "Matching purity", registry), + fPairingEfficiencyPlotter(path + "pairing-efficiency/", "Pairing efficiency", registry), + fMatchingEfficiencyPlotter(path + "matching-efficiency/", "Matching efficiency", registry), + fFakeMatchingEfficiencyPlotter(path + "fake-matching-efficiency/", "Fake matching efficiency", registry) + { + AxisSpec pAxis = {100, 0, 100, "p (GeV/c)"}; + AxisSpec ptAxis = {100, 0, 10, "p_{T} (GeV/c)"}; + + AxisSpec indexAxis = {6, 0, 6, "ranking index"}; + std::string histName = path + "trueMatchRanking"; + std::string histTitle = "True match ranking"; + fTrueMatchRanking = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {indexAxis}}); + histName = path + "trueMatchRankingVsP"; + histTitle = "True match ranking vs. p"; + fTrueMatchRankingVsP = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {pAxis, indexAxis}}); + histName = path + "trueMatchRankingVsPt"; + histTitle = "True match ranking vs. p_{T}"; + fTrueMatchRankingVsPt = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {ptAxis, indexAxis}}); + //- + histName = path + "trueMatchRankingGoodMCH"; + histTitle = "True match ranking - good MCH tracks"; + fTrueMatchRankingGoodMCH = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {indexAxis}}); + histName = path + "trueMatchRankingGoodMCHVsP"; + histTitle = "True match ranking vs. p - good MCH tracks"; + fTrueMatchRankingGoodMCHVsP = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {pAxis, indexAxis}}); + histName = path + "trueMatchRankingGoodMCHVsPt"; + histTitle = "True match ranking vs. p_{T} - good MCH tracks"; + fTrueMatchRankingGoodMCHVsPt = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {ptAxis, indexAxis}}); + //- + histName = path + "trueMatchRankingPairedMCH"; + histTitle = "True match ranking - paired MCH tracks"; + fTrueMatchRankingPairedMCH = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {indexAxis}}); + histName = path + "trueMatchRankingPairedMCHVsP"; + histTitle = "True match ranking vs. p - paired MCH tracks"; + fTrueMatchRankingPairedMCHVsP = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {pAxis, indexAxis}}); + histName = path + "trueMatchRankingPairedMCHVsPt"; + histTitle = "True match ranking vs. p_{T} - paired MCH tracks"; + fTrueMatchRankingPairedMCHVsPt = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {ptAxis, indexAxis}}); + //- + histName = path + "trueMatchRankingGoodPairedMCH"; + histTitle = "True match ranking - good paired MCH tracks"; + fTrueMatchRankingGoodPairedMCH = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {indexAxis}}); + histName = path + "trueMatchRankingGoodPairedMCHVsP"; + histTitle = "True match ranking vs. p - good paired MCH tracks"; + fTrueMatchRankingGoodPairedMCHVsP = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {pAxis, indexAxis}}); + histName = path + "trueMatchRankingGoodPairedMCHVsPt"; + histTitle = "True match ranking vs. p_{T} - good paired MCH tracks"; + fTrueMatchRankingGoodPairedMCHVsPt = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {ptAxis, indexAxis}}); + //- + histName = path + "trueMatchRankingGoodPairedMCHMFT"; + histTitle = "True match ranking - good paired MFT and MCH tracks"; + fTrueMatchRankingGoodPairedMCHMFT = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {indexAxis}}); + histName = path + "trueMatchRankingGoodPairedMCHMFTVsP"; + histTitle = "True match ranking vs. p - good paired MFT and MCH tracks"; + fTrueMatchRankingGoodPairedMCHMFTVsP = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {pAxis, indexAxis}}); + histName = path + "trueMatchRankingGoodPairedMCHMFTVsPt"; + histTitle = "True match ranking vs. p_{T} - good paired MFT and MCH tracks"; + fTrueMatchRankingGoodPairedMCHMFTVsPt = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {ptAxis, indexAxis}}); + + AxisSpec missedMatchAxis = {5, 0, 5, ""}; + histName = path + "missedMatches"; + histTitle = "Missed matches"; + fMissedMatches = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {missedMatchAxis}}); + std::get>(fMissedMatches)->GetXaxis()->SetBinLabel(1, "not paired"); + std::get>(fMissedMatches)->GetXaxis()->SetBinLabel(2, "not matched"); + std::get>(fMissedMatches)->GetXaxis()->SetBinLabel(3, "match missing"); + histName = path + "missedMatchesGoodMCH"; + histTitle = "Missed matches - good MCH tracks"; + fMissedMatchesGoodMCH = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {missedMatchAxis}}); + std::get>(fMissedMatchesGoodMCH)->GetXaxis()->SetBinLabel(1, "not paired"); + std::get>(fMissedMatchesGoodMCH)->GetXaxis()->SetBinLabel(2, "not matched"); + std::get>(fMissedMatchesGoodMCH)->GetXaxis()->SetBinLabel(3, "match missing"); + histName = path + "missedMatchesGoodMCHMFT"; + histTitle = "Missed matches - good MFT and MCH tracks"; + fMissedMatchesGoodMCHMFT = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {missedMatchAxis}}); + std::get>(fMissedMatchesGoodMCHMFT)->GetXaxis()->SetBinLabel(1, "not paired"); + std::get>(fMissedMatchesGoodMCHMFT)->GetXaxis()->SetBinLabel(2, "not matched"); + std::get>(fMissedMatchesGoodMCHMFT)->GetXaxis()->SetBinLabel(3, "match missing"); + + AxisSpec scoreAxis = {100, 0, 1, "matching score"}; + histName = path + "trueMatchScore"; + histTitle = "True match score"; + fTrueMatchScore = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {scoreAxis}}); + histName = path + "trueMatchScoreVsP"; + histTitle = "True match score vs. p"; + fTrueMatchScoreVsP = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {pAxis, scoreAxis}}); + histName = path + "trueMatchScoreVsPt"; + histTitle = "True match score vs. p_{T}"; + fTrueMatchScoreVsPt = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {ptAxis, scoreAxis}}); + + histName = path + "fakeMatchScore"; + histTitle = "Fake match score"; + fFakeMatchScore = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH1F, {scoreAxis}}); + histName = path + "fakeMatchScoreVsP"; + histTitle = "Fake match score vs. p"; + fFakeMatchScoreVsP = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {pAxis, scoreAxis}}); + histName = path + "fakeMatchScoreVsPt"; + histTitle = "Fake match score vs. p_{T}"; + fFakeMatchScoreVsPt = registry.add(histName.c_str(), histTitle.c_str(), {HistType::kTH2F, {ptAxis, scoreAxis}}); + } + }; + + std::unique_ptr fChi2MatchingPlotter; + std::map> fMatchingPlotters; + std::unique_ptr fTaggedMuonsMatchingPlotter; + std::unique_ptr fSelectedMuonsMatchingPlotter; + + CollisionInfos fCollisionInfos; + + template + void initCCDB(BC const& bc) + { + if (mRunNumber == bc.runNumber()) + return; + + mRunNumber = bc.runNumber(); + std::map metadata; + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(fCCDBApi, mRunNumber); + auto ts = soreor.first; + auto grpmag = fCCDBApi.retrieveFromTFileAny(grpmagPath, metadata, ts); + o2::base::Propagator::initFieldFromGRP(grpmag); + LOGF(info, "Set field for muons"); + VarManager::SetupMuonMagField(); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdbManager->get(geoPath); + } + o2::mch::TrackExtrap::setField(); + auto* fieldB = static_cast(TGeoGlobalMagField::Instance()->GetField()); + if (fieldB) { + double centerMFT[3] = {0, 0, -61.4}; // Field at center of MFT + mBzAtMftCenter = fieldB->getBz(centerMFT); + // std::cout << "fieldB: " << (void*)fieldB << std::endl; + } + } + + void createMatchingHistosMC() + { + AxisSpec chi2Axis = {1000, 0, 1000, "chi^{2}"}; + AxisSpec pAxis = {1000, 0, 100, "p (GeV/c)"}; + AxisSpec pTAxis = {100, 0, 10, "p_{T} (GeV/c)"}; + AxisSpec etaAxis = {100, -4, -2, "#eta"}; + AxisSpec phiAxis = {90, -180, 180, "#phi (degrees)"}; + std::string histPath = "matching/MC/"; + + AxisSpec trackPositionXAtMFTAxis = {100, -15, 15, "MFT x (cm)"}; + AxisSpec trackPositionYAtMFTAxis = {100, -15, 15, "MFT y (cm)"}; + registry.add((histPath + "pairedMCHTracksAtMFT").c_str(), "Paired MCH tracks position at MFT end", {HistType::kTH2F, {trackPositionXAtMFTAxis, trackPositionYAtMFTAxis}}); + registry.add((histPath + "pairedMFTTracksAtMFT").c_str(), "Paired MFT tracks position at MFT end", {HistType::kTH2F, {trackPositionXAtMFTAxis, trackPositionYAtMFTAxis}}); + registry.add((histPath + "selectedMCHTracksAtMFT").c_str(), "Selected MCH tracks position at MFT end", {HistType::kTH2F, {trackPositionXAtMFTAxis, trackPositionYAtMFTAxis}}); + registry.add((histPath + "selectedMCHTracksAtMFTTrue").c_str(), "Selected MCH tracks position at MFT end - true", {HistType::kTH2F, {trackPositionXAtMFTAxis, trackPositionYAtMFTAxis}}); + registry.add((histPath + "selectedMCHTracksAtMFTFake").c_str(), "Selected MCH tracks position at MFT end - fake", {HistType::kTH2F, {trackPositionXAtMFTAxis, trackPositionYAtMFTAxis}}); + + AxisSpec pairableType = {2, 0, 2, ""}; + auto pairableTypeHist = registry.add((histPath + "pairableType").c_str(), "Pairable MCH tracks type", {HistType::kTH1F, {pairableType}}); + std::get>(pairableTypeHist)->GetXaxis()->SetBinLabel(1, "direct"); + std::get>(pairableTypeHist)->GetXaxis()->SetBinLabel(2, "decay"); + + fChi2MatchingPlotter = std::make_unique(histPath + "Prod/", registryMatching); + for (const auto& [label, func] : matchingChi2Functions) { + fMatchingPlotters[label] = std::make_unique(histPath + label + "/", registryMatching); + } + for (const auto& [label, response] : matchingMlResponses) { + fMatchingPlotters[label] = std::make_unique(histPath + label + "/", registryMatching); + } + + fTaggedMuonsMatchingPlotter = std::make_unique(histPath + "Tagged/", registryMatching); + fSelectedMuonsMatchingPlotter = std::make_unique(histPath + "Selected/", registryMatching); + } + + void createAlignmentHistos() + { + AxisSpec dxAxis = {200, -10, 10, "#Delta x (cm)"}; + AxisSpec dyAxis = {200, -10, 10, "#Delta y (cm)"}; + AxisSpec pAxis = {100, 0, 100, "p (GeV/c)"}; + std::string histPath = "alignment/"; + + registryAlignment.add((histPath + "trackDxAtMFTVsP").c_str(), "Track #Delta x vs. p", {HistType::kTH2F, {pAxis, dxAxis}}); + registryAlignment.add((histPath + "trackDyAtMFTVsP").c_str(), "Track #Delta y vs. p", {HistType::kTH2F, {pAxis, dyAxis}}); + registryAlignment.add((histPath + "trackDxAtMFTVsP_alt").c_str(), "Track #Delta x vs. p (alt method)", {HistType::kTH2F, {pAxis, dxAxis}}); + registryAlignment.add((histPath + "trackDyAtMFTVsP_alt").c_str(), "Track #Delta y vs. p (alt method)", {HistType::kTH2F, {pAxis, dyAxis}}); + + registryAlignment.add((histPath + "trackDxAtMFTVsP_fake").c_str(), "Track #Delta x vs. p (fake pairs)", {HistType::kTH2F, {pAxis, dxAxis}}); + registryAlignment.add((histPath + "trackDyAtMFTVsP_fake").c_str(), "Track #Delta y vs. p (fake pairs)", {HistType::kTH2F, {pAxis, dyAxis}}); + registryAlignment.add((histPath + "trackDxAtMFTVsP_alt_fake").c_str(), "Track #Delta x vs. p (alt method, fake pairs)", {HistType::kTH2F, {pAxis, dxAxis}}); + registryAlignment.add((histPath + "trackDyAtMFTVsP_alt_fake").c_str(), "Track #Delta y vs. p (alt method, fake pairs)", {HistType::kTH2F, {pAxis, dyAxis}}); + } + + void InitMatchingFunctions() + { + using SMatrix55Std = ROOT::Math::SMatrix; + using SMatrix55Sym = ROOT::Math::SMatrix>; + + using SVector2 = ROOT::Math::SVector; + using SVector4 = ROOT::Math::SVector; + using SVector5 = ROOT::Math::SVector; + + using SMatrix44 = ROOT::Math::SMatrix; + using SMatrix45 = ROOT::Math::SMatrix; + using SMatrix22 = ROOT::Math::SMatrix; + using SMatrix25 = ROOT::Math::SMatrix; + + // Define built-in matching functions + //________________________________________________________________________________ + mMatchingFunctionMap["matchALL"] = [](const o2::dataformats::GlobalFwdTrack& mchTrack, const o2::track::TrackParCovFwd& mftTrack) -> double { + // Match two tracks evaluating all parameters: X,Y, phi, tanl & q/pt + + SMatrix55Sym H_k, V_k; + SVector5 m_k(mftTrack.getX(), mftTrack.getY(), mftTrack.getPhi(), + mftTrack.getTanl(), mftTrack.getInvQPt()), + r_k_kminus1; + SVector5 GlobalMuonTrackParameters = mchTrack.getParameters(); + SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances(); + V_k(0, 0) = mftTrack.getCovariances()(0, 0); + V_k(1, 1) = mftTrack.getCovariances()(1, 1); + V_k(2, 2) = mftTrack.getCovariances()(2, 2); + V_k(3, 3) = mftTrack.getCovariances()(3, 3); + V_k(4, 4) = mftTrack.getCovariances()(4, 4); + H_k(0, 0) = 1.0; + H_k(1, 1) = 1.0; + H_k(2, 2) = 1.0; + H_k(3, 3) = 1.0; + H_k(4, 4) = 1.0; + + // Covariance of residuals + SMatrix55Std invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances)); + invResCov.Invert(); + + // Update Parameters + r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters; // Residuals of prediction + + auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov); + + return matchChi2Track; + }; + + //________________________________________________________________________________ + mMatchingFunctionMap["matchXYPhiTanl"] = [](const o2::dataformats::GlobalFwdTrack& mchTrack, const o2::track::TrackParCovFwd& mftTrack) -> double { + + // Match two tracks evaluating positions & angles + + SMatrix45 H_k; + SMatrix44 V_k; + SVector4 m_k(mftTrack.getX(), mftTrack.getY(), mftTrack.getPhi(), + mftTrack.getTanl()), + r_k_kminus1; + SVector5 GlobalMuonTrackParameters = mchTrack.getParameters(); + SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances(); + V_k(0, 0) = mftTrack.getCovariances()(0, 0); + V_k(1, 1) = mftTrack.getCovariances()(1, 1); + V_k(2, 2) = mftTrack.getCovariances()(2, 2); + V_k(3, 3) = mftTrack.getCovariances()(3, 3); + H_k(0, 0) = 1.0; + H_k(1, 1) = 1.0; + H_k(2, 2) = 1.0; + H_k(3, 3) = 1.0; + + // Covariance of residuals + SMatrix44 invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances)); + invResCov.Invert(); + + // Residuals of prediction + r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters; + + auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov); + + return matchChi2Track; }; + + //________________________________________________________________________________ + mMatchingFunctionMap["matchXY"] = [](const o2::dataformats::GlobalFwdTrack& mchTrack, const o2::track::TrackParCovFwd& mftTrack) -> double { + + // Calculate Matching Chi2 - X and Y positions + + SMatrix25 H_k; + SMatrix22 V_k; + SVector2 m_k(mftTrack.getX(), mftTrack.getY()), r_k_kminus1; + SVector5 GlobalMuonTrackParameters = mchTrack.getParameters(); + SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances(); + V_k(0, 0) = mftTrack.getCovariances()(0, 0); + V_k(1, 1) = mftTrack.getCovariances()(1, 1); + H_k(0, 0) = 1.0; + H_k(1, 1) = 1.0; + + // Covariance of residuals + SMatrix22 invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances)); + invResCov.Invert(); + + // Residuals of prediction + r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters; + auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov); + + return matchChi2Track; }; + } + + void init(o2::framework::InitContext&) + { + // Load geometry + ccdbManager->setURL(ccdburl); + ccdbManager->setCaching(true); + ccdbManager->setLocalObjectValidityChecking(); + fCCDBApi.init(ccdburl); + mRunNumber = 0; + + if (!o2::base::GeometryManager::isGeometryLoaded()) { + LOGF(info, "Load geometry from CCDB"); + ccdbManager->get(geoPath); + } + + // Matching functions + InitMatchingFunctions(); + for (size_t funcId = 0; funcId < sChi2FunctionsNum; funcId++) { + auto label = fConfigChi2MatchingOptions.fFunctionLabel[funcId].value; + auto funcName = fConfigChi2MatchingOptions.fFunctionName[funcId].value; + auto scoreMin = fConfigChi2MatchingOptions.fMatchingScoreCut[funcId].value; + auto matchingPlaneZ = fConfigChi2MatchingOptions.fMatchingPlaneZ[funcId].value; + + if (label == "" || funcName == "") + break; + + matchingChi2Functions[label] = funcName; + + matchingScoreCuts[label] = scoreMin; + matchingPlanesZ[label] = matchingPlaneZ; + } + + // Matching ML models + // TODO : for now we use hard coded values since the current models use 1 pT bin + binsPtMl = {-1e-6, 1000.0}; + cutValues = {0.0}; + cutDirMl = {cuts_ml::CutNot}; + o2::framework::LabeledArray mycutsMl(cutValues.data(), 1, 1, std::vector{"pT bin 0"}, std::vector{"score"}); + + for (size_t modelId = 0; modelId < sMLModelsNum; modelId++) { + auto label = fConfigMlOptions.fModelLabel[modelId].value; + auto modelPaths = fConfigMlOptions.fModelPathsCCDB[modelId].value; + auto inputFeatures = fConfigMlOptions.fInputFeatures[modelId].value; + auto modelNames = fConfigMlOptions.fModelNames[modelId].value; + auto scoreMin = fConfigMlOptions.fMatchingScoreCut[modelId].value; + auto matchingPlaneZ = fConfigMlOptions.fMatchingPlaneZ[modelId].value; + + if (label == "" || modelPaths.empty() || inputFeatures.empty() || modelNames.empty()) + break; + + matchingMlResponses[label].configure(binsPtMl, mycutsMl, cutDirMl, 1); + matchingMlResponses[label].setModelPathsCCDB(modelNames, fCCDBApi, modelPaths, fConfigCCDB.fConfigNoLaterThan.value); + matchingMlResponses[label].cacheInputFeaturesIndices(inputFeatures); + matchingMlResponses[label].init(); + + matchingScoreCuts[label] = scoreMin; + matchingPlanesZ[label] = matchingPlaneZ; + } + + int nTrackTypes = static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MCHStandaloneTrack) + 1; + AxisSpec trackTypeAxis = {static_cast(nTrackTypes), 0.0, static_cast(nTrackTypes), "track type"}; + registry.add("nTracksPerType", "Number of tracks per type", {HistType::kTH1F, {trackTypeAxis}}); + + AxisSpec tracksMultiplicityAxis = {10000, 0, 10000, "tracks multiplicity"}; + registry.add("tracksMultiplicityMFT", "MFT tracks multiplicity", {HistType::kTH1F, {tracksMultiplicityAxis}}); + + createMatchingHistosMC(); + createAlignmentHistos(); + } + + template + bool pDCACut(const T& mchTrack, const C& collision, 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(mchTrack.rAtAbsorberEnd() / 505.) * TMath::RadToDeg(); + + // propagate muon track to vertex + auto mchTrackAtVertex = VarManager::PropagateMuon(mchTrack, collision, VarManager::kToVertex); + + // double pUncorr = mchTrack.p(); + double p = mchTrackAtVertex.getP(); + + double pDCA = mchTrack.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 IsGoodMuon(const T& mchTrack, const C& collision, + double chi2Cut, + double pCut, + double pTCut, + std::array etaCut, + std::array rAbsCut, + double nSigmaPdcaCut) + { + // chi2 cut + if (mchTrack.chi2() > chi2Cut) + return false; + + // momentum cut + if (mchTrack.p() < pCut) { + return false; // skip low-momentum tracks + } + + // transverse momentum cut + if (mchTrack.pt() < pTCut) { + return false; // skip low-momentum tracks + } + + // Eta cut + double eta = mchTrack.eta(); + if ((eta < etaCut[0] || eta > etaCut[1])) { + return false; + } + + // RAbs cut + double rAbs = mchTrack.rAtAbsorberEnd(); + if ((rAbs < rAbsCut[0] || rAbs > rAbsCut[1])) { + return false; + } + + // pDCA cut + if (!pDCACut(mchTrack, collision, nSigmaPdcaCut)) { + return false; + } + + return true; + } + + template + bool IsGoodMuon(const T& muonTrack, const C& collision) + { + return IsGoodMuon(muonTrack, collision, fTrackChi2MchUp, fPMchLow, fPtMchLow, {fEtaMchLow, fEtaMchUp}, {fRabsLow, fRabsUp}, fSigmaPdcaUp); + } + + template + bool IsGoodGlobalMuon(const T& muonTrack, const C& collision) + { + return IsGoodMuon(muonTrack, collision, fTrackChi2MchUp, fPMchLow, fPtMchLow, {fEtaMftLow, fEtaMftUp}, {fRabsLow, fRabsUp}, fSigmaPdcaUp); + } + + template + bool IsGoodMFT(const T& mftTrack, + double chi2Cut, + int nClustersCut) + { + // std::cout << std::format("Checking MFT track") << std::endl; + // std::cout << std::format(" chi2={}", mftTrack.chi2()) << std::endl; + // std::cout << std::format(" nClusters={}", mftTrack.nClusters()) << std::endl; + // chi2 cut + if (mftTrack.chi2() > chi2Cut) + return false; + + // number of clusters cut + if (mftTrack.nClusters() < nClustersCut) + return false; + + return true; + } + + template + bool IsGoodMFT(const T& mftTrack) + { + return IsGoodMFT(mftTrack, fTrackChi2MftUp, fTrackNClustMftLow); + } + + template + bool IsGoodGlobalMatching(const TMUON& muonTrack, + double matchingScore, + double matchingScoreCut) + { + if (static_cast(muonTrack.trackType()) > 2) + return false; + + // MFT-MCH matching score cut + if (matchingScore < matchingScoreCut) + return false; + + return true; + } + + template + bool IsGoodGlobalMatching(const TMUON& muonTrack, double matchingScore) + { + return IsGoodGlobalMatching(muonTrack, matchingScore, fMatchingChi2ScoreMftMchLow); + } + + template + bool IsTrueGlobalMatching(const TMUON& muonTrack, const std::vector>& matchablePairs) + { + if (static_cast(muonTrack.trackType()) > 2) + return false; + + int64_t mchTrackId = static_cast(muonTrack.matchMCHTrackId()); + int64_t mftTrackId = static_cast(muonTrack.matchMFTTrackId()); + + std::pair trackIndexes = std::make_pair(mchTrackId, mftTrackId); + + return (std::find(matchablePairs.begin(), matchablePairs.end(), trackIndexes) != matchablePairs.end()); + } + + bool IsMatchableMCH(int64_t mchTrackId, const std::vector>& matchablePairs) + { + for (auto [id1, id2] : matchablePairs) { + if (mchTrackId == id1) + return true; + } + return false; + } + + std::optional> GetMatchablePairForMCH(int64_t mchTrackId, const std::vector>& matchablePairs) + { + for (auto pair : matchablePairs) { + if (mchTrackId == pair.first) + return pair; + } + return {}; + } + + template + o2::dataformats::GlobalFwdTrack FwdToTrackPar(const T& track) + { + double chi2 = track.chi2(); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.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 trackparCov{track.z(), tpars, tcovs, chi2}; + o2::dataformats::GlobalFwdTrack fwdtrack; + fwdtrack.setParameters(trackparCov.getParameters()); + fwdtrack.setZ(trackparCov.getZ()); + fwdtrack.setCovariances(trackparCov.getCovariances()); + return fwdtrack; + } + + template + o2::dataformats::GlobalFwdTrack FwdToTrackPar(const T& track, const C& cov) + { + double chi2 = track.chi2(); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), + cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), + cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; + o2::dataformats::GlobalFwdTrack fwdtrack; + fwdtrack.setParameters(trackparCov.getParameters()); + fwdtrack.setZ(trackparCov.getZ()); + fwdtrack.setCovariances(trackparCov.getCovariances()); + return fwdtrack; + } + + o2::dataformats::GlobalFwdTrack PropagateToZMCH(const o2::dataformats::GlobalFwdTrack& muon, const double z) + { + auto mchTrack = mExtrap.FwdtoMCH(muon); + + float absFront = -90.f; + float absBack = -505.f; + + if (muon.getZ() < absBack && z > absFront) { + // extrapolation through the absorber in the upstream direction + // std::cout << " extrapToVertexWithoutBranson()" << std::endl; + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, z); + } else { + // all other cases + // std::cout << " extrapToZ()" << std::endl; + o2::mch::TrackExtrap::extrapToZ(mchTrack, z); + } + + auto proptrack = mExtrap.MCHtoFwd(mchTrack); + o2::dataformats::GlobalFwdTrack propmuon; + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + + return propmuon; + } + + template + o2::dataformats::GlobalFwdTrack PropagateToZMCH(const T& muon, const double z) + { + 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 track; + track.setParameters(fwdtrack.getParameters()); + track.setZ(fwdtrack.getZ()); + track.setCovariances(fwdtrack.getCovariances()); + auto mchTrack = mExtrap.FwdtoMCH(track); + + float absFront = -90.f; + float absBack = -505.f; + + if (fwdtrack.getZ() < absBack && z > absFront) { + // extrapolation through the absorber in the upstream direction + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, z); + } else { + // all other cases + o2::mch::TrackExtrap::extrapToZ(mchTrack, z); + } + + auto proptrack = mExtrap.MCHtoFwd(mchTrack); + o2::dataformats::GlobalFwdTrack propmuon; + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + + return propmuon; + } + + o2::dataformats::GlobalFwdTrack PropagateToZMFT(const o2::dataformats::GlobalFwdTrack& mftTrack, const double z) + { + o2::dataformats::GlobalFwdTrack fwdtrack{mftTrack}; + fwdtrack.propagateToZhelix(z, mBzAtMftCenter); + return fwdtrack; + } + + template + o2::dataformats::GlobalFwdTrack PropagateToZMFT(const TMFT& mftTrack, const CMFT& mftCov, const double z) + { + o2::dataformats::GlobalFwdTrack fwdtrack = FwdToTrackPar(mftTrack, mftCov); + return PropagateToZMFT(fwdtrack, z); + } + + template + void InitCollisions(EVT const& collisions, + BC const& bcs, + TMUON const& muonTracks, + TMFT const& mftTracks, + CollisionInfos& collisionInfos) + { + collisionInfos.clear(); + + // fill collision information for global muon tracks (MFT-MCH-MID matches) + for (auto muonTrack : muonTracks) { + if (!muonTrack.has_collision()) + continue; + + auto collision = collisions.rawIteratorAt(muonTrack.collisionId()); + int64_t collisionIndex = collision.globalIndex(); + + // std::cout << std::format("Collision indexes: {} / {}", collisionIndex, muonTrack.collisionId()) << std::endl; + + auto bc = bcs.rawIteratorAt(collision.bcId()); + + auto& collisionInfo = collisionInfos[collisionIndex]; + collisionInfo.index = collisionIndex; + collisionInfo.bc = bc.globalBC(); + collisionInfo.zVertex = collision.posZ(); + + if (static_cast(muonTrack.trackType()) > 2) { + // standalone MCH or MCH-MID tracks + int64_t mchTrackIndex = muonTrack.globalIndex(); + // if (!IsGoodMuon(muonTrack, collision)) continue; + collisionInfo.mchTracks.push_back(mchTrackIndex); + } else { + // global muon tracks (MFT-MCH or MFT-MCH-MID) + int64_t muonTrackIndex = muonTrack.globalIndex(); + double matchingScore = chi2ToScore(muonTrack.chi2MatchMCHMFT()); + auto const& mchTrack = muonTrack.template matchMCHTrack_as(); + int64_t mchTrackIndex = mchTrack.globalIndex(); + + // check if a vector of global muon candidates is already available for the current MCH index + // if not, initialize a new one and add the current global muon track + // bool globalMuonTrackFound = false; + auto matchingCandidateIterator = collisionInfo.matchingCandidates.find(mchTrackIndex); + if (matchingCandidateIterator != collisionInfo.matchingCandidates.end()) { + matchingCandidateIterator->second.push_back(std::make_pair(muonTrackIndex, matchingScore)); + // globalMuonTrackFound = true; + } else { + collisionInfo.matchingCandidates[mchTrackIndex].push_back(std::make_pair(muonTrackIndex, matchingScore)); + } + } + } + + // fill collision information for MFT standalone tracks + for (auto mftTrack : mftTracks) { + if (!mftTrack.has_collision()) + continue; + + auto collision = collisions.rawIteratorAt(mftTrack.collisionId()); + int64_t collisionIndex = collision.globalIndex(); + + auto bc = bcs.rawIteratorAt(collision.bcId()); + + int64_t mftTrackIndex = mftTrack.globalIndex(); + + auto& collisionInfo = collisionInfos[collisionIndex]; + collisionInfo.index = collisionIndex; + collisionInfo.bc = bc.globalBC(); + collisionInfo.zVertex = collision.posZ(); + + collisionInfo.mftTracks.push_back(mftTrackIndex); + } + + // sort the vectors of matching candidates in ascending order based on the matching score value + auto compareMatchingScore = [](std::pair track1, std::pair track2) -> bool { + return (track1.second > track2.second); + }; + + for (auto& [collisionIndex, collisionInfo] : collisionInfos) { + for (auto& [mchIndex, globalTracksVector] : collisionInfo.matchingCandidates) { + std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareMatchingScore); + } + } + } + + template + void GetMatchablePairs(const CollisionInfo& collisionInfo, + TMUON const& muonTracks, + TMFT const& mftTracks, + std::vector>& matchablePairs) + { + matchablePairs.clear(); + for (const auto& muonTrack : muonTracks) { + // only consider MCH standalone or MCH-MID matches + if (static_cast(muonTrack.trackType()) <= 2) + continue; + + // only consider tracks associated to the current collision + if (!muonTrack.has_collision()) + continue; + if (muonTrack.collisionId() != collisionInfo.index) + continue; + + // skip tracks that do not have an associated MC particle + if (!muonTrack.has_mcParticle()) + continue; + // get the index associated to the MC particle + auto muonMcParticle = muonTrack.mcParticle(); + int64_t muonMcTrackIndex = muonMcParticle.globalIndex(); + + for (const auto& mftTrack : mftTracks) { + // skip tracks that do not have an associated MC particle + if (!mftTrack.has_mcParticle()) + continue; + // get the index associated to the MC particle + auto mftMcParticle = mftTrack.mcParticle(); + int64_t mftMcTrackIndex = mftMcParticle.globalIndex(); + + if (muonMcTrackIndex == mftMcTrackIndex) { + matchablePairs.emplace_back(std::make_pair(static_cast(muonTrack.globalIndex()), + static_cast(mftTrack.globalIndex()))); + } else { + // check if the muon particle is a decay product of the MFT particle + for (auto& motherParticle : muonMcParticle.template mothers_as()) { + if (motherParticle.globalIndex() == mftMcTrackIndex) { + matchablePairs.emplace_back(std::make_pair(static_cast(muonTrack.globalIndex()), + static_cast(mftTrack.globalIndex()))); + break; + } + } + } + } + } + } + + template + int GetTrueMatchIndex(TMUON const& muonTracks, + const std::vector>& matchCandidatesVector, + const std::vector>& matchablePairs) + { + // find the index of the matching candidate that corresponds to the true match + // index=1 corresponds to the leading candidate + // index=0 means no candidate was found that corresponds to the true match + int trueMatchIndex = 0; + for (size_t i = 0; i < matchCandidatesVector.size(); i++) { + auto const& muonTrack = muonTracks.rawIteratorAt(matchCandidatesVector[i].first); + + if (IsTrueGlobalMatching(muonTrack, matchablePairs)) { + trueMatchIndex = i + 1; + break; + } + } + return trueMatchIndex; + } + + // for each MCH standalone track, collect the associated matching candidates + template + void GetSelectedMuons(const CollisionInfo& collisionInfo, + C const& collisions, + TMUON const& muonTracks, + std::vector& selectedMuons) + { + selectedMuons.clear(); + for (auto muonTrack : muonTracks) { + + // only consider MCH-MID matches + if (static_cast(muonTrack.trackType()) != 3) { + continue; + } + + // only select MCH-MID tracks from the current collision + if (!muonTrack.has_collision()) + continue; + if (static_cast(muonTrack.collisionId()) != collisionInfo.index) + continue; + + const auto& collision = collisions.rawIteratorAt(muonTrack.collisionId()); + + // select MCH tracks with strict quality cuts + if (!IsGoodMuon(muonTrack, collision, + fMuonTaggingTrackChi2MchUp, + fMuonTaggingPMchLow, + fMuonTaggingPtMchLow, + {fMuonTaggingEtaMchLow, fMuonTaggingEtaMchUp}, + {fMuonTaggingRabsLow, fMuonTaggingRabsUp}, + fMuonTaggingSigmaPdcaUp)) { + continue; + } + + // propagate MCH track to the vertex + auto mchTrackAtVertex = VarManager::PropagateMuon(muonTrack, collision, VarManager::kToVertex); + + // propagate the track from the vertex to the first MFT plane + const auto& extrapToMFTfirst = PropagateToZMCH(mchTrackAtVertex, o2::mft::constants::mft::LayerZCoordinate()[0]); + double rFront = std::sqrt(extrapToMFTfirst.getX() * extrapToMFTfirst.getX() + extrapToMFTfirst.getY() * extrapToMFTfirst.getY()); + double rMinFront = 3.f; + double rMaxFront = 9.f; + if (rFront < rMinFront || rFront > rMaxFront) + continue; + + // propagate the track from the vertex to the last MFT plane + const auto& extrapToMFTlast = PropagateToZMCH(mchTrackAtVertex, o2::mft::constants::mft::LayerZCoordinate()[9]); + double rBack = std::sqrt(extrapToMFTlast.getX() * extrapToMFTlast.getX() + extrapToMFTlast.getY() * extrapToMFTlast.getY()); + double rMinBack = 5.f; + double rMaxBack = 12.f; + if (rBack < rMinBack || rBack > rMaxBack) + continue; + + int64_t muonTrackIndex = muonTrack.globalIndex(); + selectedMuons.emplace_back(muonTrackIndex); + } + } + + // for each MCH standalone track, collect the associated matching candidates + template + void GetTaggedMuons(const CollisionInfo& collisionInfo, + TMUON const& muonTracks, + const std::vector& selectedMuons, + std::vector& taggedMuons) + { + taggedMuons.clear(); + for (auto [mchIndex, globalTracksVector] : collisionInfo.matchingCandidates) { + + // check if the current muon is selected + if (std::find(selectedMuons.begin(), selectedMuons.end(), mchIndex) == selectedMuons.end()) + continue; + + // if there is only one candidate, mark the muon as select + if (globalTracksVector.size() == 1) { + taggedMuons.emplace_back(mchIndex); + continue; + } + + auto const& muonTrack0 = muonTracks.rawIteratorAt(globalTracksVector[0].first); + auto const& muonTrack1 = muonTracks.rawIteratorAt(globalTracksVector[1].first); + + double chi2diff = muonTrack1.chi2MatchMCHMFT() - muonTrack0.chi2MatchMCHMFT(); + if (chi2diff < fMuonTaggingChi2DiffLow) + continue; + + taggedMuons.emplace_back(mchIndex); + } + } + + template + void FillMatchingPlotsMC(C const& collision, + TMUON const& muonTracks, + TMFT const& mftTracks, + const MatchingCandidates& matchingCandidates, + const std::vector>& matchablePairs, + double matchingScoreCut, + MatchingPlotter* plotter) + { + // ==================================== + // Matching candidates hierarchy + + for (const auto& [mchIndex, globalTracksVector] : matchingCandidates) { + // check if the MCH track belongs to a matchable pair + bool isPairedMCH = IsMatchableMCH(static_cast(mchIndex), matchablePairs); + + // get the standalone MCH track + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + double mchMom = mchTrack.p(); + double mchPt = mchTrack.pt(); + + // MCH track quality flag + bool isGoodMCH = IsGoodGlobalMuon(mchTrack, collision); + + auto matchablePair = GetMatchablePairForMCH(static_cast(mchIndex), matchablePairs); + bool hasMatchablePair = matchablePair.has_value(); + bool isGoodPair = false; + if (hasMatchablePair) { + auto const& pairedMftTrack = mftTracks.rawIteratorAt(matchablePair.value().second); + isGoodPair = isGoodMCH && IsGoodMFT(pairedMftTrack); + } + + // std::cout << std::format("Checking matchable MCH track #{}", mchIndex) << std::endl; + + // find the index of the matching candidate that corresponds to the true match + // index=1 corresponds to the leading candidate + // index=0 means no candidate was found that corresponds to the true match + int trueMatchIndex = GetTrueMatchIndex(muonTracks, globalTracksVector, matchablePairs); + + std::get>(plotter->fTrueMatchRanking)->Fill(trueMatchIndex); + std::get>(plotter->fTrueMatchRankingVsP)->Fill(mchMom, trueMatchIndex); + std::get>(plotter->fTrueMatchRankingVsPt)->Fill(mchPt, trueMatchIndex); + + if (isGoodMCH) { + std::get>(plotter->fTrueMatchRankingGoodMCH)->Fill(trueMatchIndex); + std::get>(plotter->fTrueMatchRankingGoodMCHVsP)->Fill(mchMom, trueMatchIndex); + std::get>(plotter->fTrueMatchRankingGoodMCHVsPt)->Fill(mchPt, trueMatchIndex); + } + + if (isPairedMCH) { + std::get>(plotter->fTrueMatchRankingPairedMCH)->Fill(trueMatchIndex); + std::get>(plotter->fTrueMatchRankingPairedMCHVsP)->Fill(mchMom, trueMatchIndex); + std::get>(plotter->fTrueMatchRankingPairedMCHVsPt)->Fill(mchPt, trueMatchIndex); + } + + if (isGoodMCH && isPairedMCH) { + std::get>(plotter->fTrueMatchRankingGoodPairedMCH)->Fill(trueMatchIndex); + std::get>(plotter->fTrueMatchRankingGoodPairedMCHVsP)->Fill(mchMom, trueMatchIndex); + std::get>(plotter->fTrueMatchRankingGoodPairedMCHVsPt)->Fill(mchPt, trueMatchIndex); + } + + if (isGoodPair) { + std::get>(plotter->fTrueMatchRankingGoodPairedMCHMFT)->Fill(trueMatchIndex); + std::get>(plotter->fTrueMatchRankingGoodPairedMCHMFTVsP)->Fill(mchMom, trueMatchIndex); + std::get>(plotter->fTrueMatchRankingGoodPairedMCHMFTVsP)->Fill(mchPt, trueMatchIndex); + } + + if (trueMatchIndex == 0) { + // missed matches + if (!isPairedMCH) { + // the MCH track does not have a corresponding MFT track for matching + std::get>(plotter->fMissedMatches)->Fill(0); + if (isGoodMCH) { + std::get>(plotter->fMissedMatchesGoodMCH)->Fill(0); + } + } else { + if (globalTracksVector.empty()) { + // the MCH track was not matched to any MFT track + std::get>(plotter->fMissedMatches)->Fill(1); + if (isGoodMCH) { + std::get>(plotter->fMissedMatchesGoodMCH)->Fill(1); + } + if (isGoodPair) { + std::get>(plotter->fMissedMatchesGoodMCHMFT)->Fill(1); + } + } else { + // the correct match is not among the stored candidates + std::get>(plotter->fMissedMatches)->Fill(2); + if (isGoodMCH) { + std::get>(plotter->fMissedMatchesGoodMCH)->Fill(2); + } + if (isGoodPair) { + std::get>(plotter->fMissedMatchesGoodMCHMFT)->Fill(2); + } + } + } + } + } + + // ==================================== + // Matching properties + + for (auto [mchIndex, globalTracksVector] : matchingCandidates) { + if (globalTracksVector.size() < 1) + continue; + + // get the standalone MCH track + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + + // get leading matching candidate + auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0].first); + + auto const& mftTrack = muonTrack.template matchMFTTrack_as(); + + // skip global muon tracks that do not pass the MCH and MFT quality cuts + if (!IsGoodGlobalMuon(mchTrack, collision)) + continue; + if (!IsGoodMFT(mftTrack)) + continue; + + double matchingScore = globalTracksVector[0].second; + double mchMom = mchTrack.p(); + double mchPt = mchTrack.pt(); + + // check the matching quality, but set the minimum matching score to zero + bool isGoodMatchNoScore = IsGoodGlobalMatching(muonTrack, matchingScore, 0); + // bool isGoodMatch = IsGoodGlobalMatching(muonTrack, matchingScore, matchingScoreCut); + + bool isTrueMatch = IsTrueGlobalMatching(muonTrack, matchablePairs); + + // matching score analysis + if (isGoodMatchNoScore) { + if (isTrueMatch) { + std::get>(plotter->fTrueMatchScore)->Fill(matchingScore); + std::get>(plotter->fTrueMatchScoreVsP)->Fill(mchMom, matchingScore); + std::get>(plotter->fTrueMatchScoreVsPt)->Fill(mchPt, matchingScore); + } else { + std::get>(plotter->fFakeMatchScore)->Fill(matchingScore); + std::get>(plotter->fFakeMatchScoreVsP)->Fill(mchMom, matchingScore); + std::get>(plotter->fFakeMatchScoreVsPt)->Fill(mchPt, matchingScore); + } + } + } + + // ==================================== + // Matching purity + + for (auto [mchIndex, globalTracksVector] : matchingCandidates) { + if (globalTracksVector.size() < 1) + continue; + + // get the leading matching candidate + auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0].first); + double matchingScore = globalTracksVector[0].second; + + // get the standalone MCH and MFT tracks + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + auto const& mftTrack = muonTrack.template matchMFTTrack_as(); + + // skip global muon tracks that do not pass the MCH and MFT quality cuts + if (!IsGoodGlobalMuon(mchTrack, collision)) + continue; + if (!IsGoodMFT(mftTrack)) + continue; + + // skip candidates that do not pass the matching quality cuts + if (!IsGoodGlobalMatching(muonTrack, matchingScore, matchingScoreCut)) + continue; + + // check if the matching candidate is a true one + bool isTrueMatch = IsTrueGlobalMatching(muonTrack, matchablePairs); + + // fill matching purity plots + plotter->fMatchingPurityPlotter.Fill(mchTrack, isTrueMatch); + } + + // ==================================== + // Matching efficiencies + + // outer loop on matchable pairs + for (auto [matchableMchIndex, matchableMftIndex] : matchablePairs) { + // get the standalone MCH track + // std::cout << std::format("Retrieving paired tracks: {} / {}", matchableMchIndex, matchableMftIndex) << std::endl; + auto const& mchTrack = muonTracks.rawIteratorAt(matchableMchIndex); + auto const& pairedMftTrack = mftTracks.rawIteratorAt(matchableMftIndex); + // std::cout << std::format("... done.") << std::endl; + + // skip track pairs that do not pass the MCH and MFT quality cuts + // we only consider matchable pairs that fulfill the track quality requirements + // std::cout << std::format("Checking tracks...") << std::endl; + if (!IsGoodGlobalMuon(mchTrack, collision)) + continue; + // std::cout << std::format("... MCH ok.") << std::endl; + if (!IsGoodMFT(pairedMftTrack)) + continue; + // std::cout << std::format("... MFT ok.") << std::endl; + + bool goodMatchFound = false; + bool isTrueMatch = false; + + // check if we have some matching candidates for the current matchable MCH track + if (matchingCandidates.count(matchableMchIndex) > 0) { + // std::cout << std::format("Getting matching candidates for MCH track {}", matchableMchIndex) << std::endl; + const auto& globalTracksVector = matchingCandidates.at(static_cast(matchableMchIndex)); + // std::cout << std::format("Number of matching candidates: {}", globalTracksVector.size()) << std::endl; + if (!globalTracksVector.empty()) { + // get the leading matching candidate + // std::cout << std::format("Getting leading matching candidate: {}", globalTracksVector[0].first) << std::endl; + auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0].first); + double matchingScore = globalTracksVector[0].second; + // std::cout << std::format("... done.") << std::endl; + + // get the standalone MFT track + // std::cout << std::format("Getting MFT track") << std::endl; + auto const& mftTrack = muonTrack.template matchMFTTrack_as(); + auto mftIndex = mftTrack.globalIndex(); + // std::cout << std::format("... done.") << std::endl; + + // a good match must pass the MFT and matching quality cuts + // the MCH track quality is already checked in the outer loop + // std::cout << std::format("Checking matched track quality") << std::endl; + goodMatchFound = IsGoodMFT(mftTrack) && IsGoodGlobalMatching(muonTrack, matchingScore, matchingScoreCut); + isTrueMatch = (mftIndex == matchableMftIndex); + // std::cout << std::format("... done: {}", goodMatchFound) << std::endl; + } + } + + // fill matching efficiency plots + plotter->fPairingEfficiencyPlotter.Fill(mchTrack, goodMatchFound); + plotter->fMatchingEfficiencyPlotter.Fill(mchTrack, (goodMatchFound && isTrueMatch)); + plotter->fFakeMatchingEfficiencyPlotter.Fill(mchTrack, (goodMatchFound && !isTrueMatch)); + } + } + + template + void RunChi2Matching(C const& collisions, + TMUON const& muonTracks, + TMFT const& /*mftTracks*/, + CMFT const& mftCovs, + std::string label, + const MatchingCandidates& matchingCandidates, + MatchingCandidates& newMatchingCandidates) + { + newMatchingCandidates.clear(); + + auto funcIter = matchingChi2Functions.find(label); + if (funcIter == matchingChi2Functions.end()) + return; + + auto funcName = funcIter->second; + + if (funcName == "prod") { + newMatchingCandidates = matchingCandidates; + return; + } + + if (mMatchingFunctionMap.count(funcName) < 1) + return; + + // std::cout << std::format("Processing {} matches with chi2 function {}", matchingCandidates.size(), funcName) << std::endl; + + auto matchingFunc = mMatchingFunctionMap.at(funcName); + for (auto& [mchIndex, globalTracksVector] : matchingCandidates) { + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + + for (auto& [muonIndex, score] : globalTracksVector) { + auto const& muonTrack = muonTracks.rawIteratorAt(muonIndex); + if (!muonTrack.has_collision()) + continue; + + auto collision = collisions.rawIteratorAt(muonTrack.collisionId()); + + // get MCH and MFT standalone tracks + // auto mchTrack = muonTrack.template matchMCHTrack_as(); + auto const& mftTrack = muonTrack.template matchMFTTrack_as(); + if (mftTrackCovs.count(mftTrack.globalIndex()) < 1) { + // std::cout << std::format("Covariance matrix for MFT track #{} not found", mftTrack.globalIndex()) << std::endl; + continue; + } + auto const& mftTrackCov = mftCovs.rawIteratorAt(mftTrackCovs[mftTrack.globalIndex()]); + + // get tracks parameters in O2 format + auto mftTrackProp = FwdToTrackPar(mftTrack, mftTrackCov); + auto mchTrackProp = FwdToTrackPar(mchTrack, mchTrack); + auto mchTrackPropAlt = FwdToTrackPar(mchTrack, mchTrack); + + // extrapolate to the matching plane + auto matchingPlaneZ = matchingPlanesZ[label]; + // std::cout << std::format("Extrapolating tracks to z={}", matchingPlaneZ) << std::endl; + if (matchingPlaneZ < 0.) { + mftTrackProp = PropagateToZMFT(mftTrackProp, matchingPlaneZ); + mchTrackProp = PropagateToZMCH(mchTrackProp, matchingPlaneZ); + auto mchTrackAtVertex = VarManager::PropagateMuon(mchTrack, collision, VarManager::kToVertex); + mchTrackPropAlt = PropagateToZMCH(mchTrackAtVertex, matchingPlaneZ); + } + + // run the chi2 matching function + float matchingChi2 = matchingFunc(mchTrackProp, mftTrackProp); + float matchingScore = chi2ToScore(matchingChi2); + // std::cout << std::format("Matching chi2: {}, original chi2: {}", matchingChi2, muonTrack.chi2MatchMCHMFT()) << std::endl; + + // check if a vector of global muon candidates is already available for the current MCH index + // if not, initialize a new one and add the current global muon track + auto matchingCandidateIterator = newMatchingCandidates.find(mchIndex); + if (matchingCandidateIterator != newMatchingCandidates.end()) { + matchingCandidateIterator->second.push_back(std::make_pair(muonIndex, matchingScore)); + } else { + newMatchingCandidates[mchIndex].push_back(std::make_pair(muonIndex, matchingScore)); + } + } + } + } + + template + void RunMLMatching(C const& collisions, + TMUON const& muonTracks, + TMFT const& /*mftTracks*/, + CMFT const& mftCovs, + std::string label, + const MatchingCandidates& matchingCandidates, + MatchingCandidates& newMatchingCandidates) + { + newMatchingCandidates.clear(); + auto mlIter = matchingMlResponses.find(label); + if (mlIter == matchingMlResponses.end()) + return; + + auto& mlResponse = mlIter->second; + for (auto& [mchIndex, globalTracksVector] : matchingCandidates) { + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + for (auto& [muonIndex, score] : globalTracksVector) { + auto const& muonTrack = muonTracks.rawIteratorAt(muonIndex); + if (!muonTrack.has_collision()) + continue; + + auto collision = collisions.rawIteratorAt(muonTrack.collisionId()); + + // get MFT standalone track + auto const& mftTrack = muonTrack.template matchMFTTrack_as(); + if (mftTrackCovs.count(mftTrack.globalIndex()) < 1) { + // std::cout << std::format("Covariance matrix for MFT track #{} not found", mftTrack.globalIndex()) << std::endl; + continue; + } + // std::cout << fmt::format("Getting covariance matrix for MFT track #{} -> {}", mftTrack.globalIndex(), mftTrackCovs[mftTrack.globalIndex()]) << std::endl; + auto const& mftTrackCov = mftCovs.rawIteratorAt(mftTrackCovs[mftTrack.globalIndex()]); + // std::cout << fmt::format("Covariance matrix for MFT track #{} retrieved", mftTrack.globalIndex()) << std::endl; + + // get tracks parameters in O2 format + auto mftTrackProp = FwdToTrackPar(mftTrack, mftTrackCov); + auto mchTrackProp = FwdToTrackPar(mchTrack, mchTrack); + + // extrapolate to the matching plane + auto matchingPlaneZ = matchingPlanesZ[label]; + if (matchingPlaneZ < 0.) { + mftTrackProp = PropagateToZMFT(mftTrackProp, matchingPlaneZ); + mchTrackProp = PropagateToZMCH(mchTrackProp, matchingPlaneZ); + } + + // run the ML model + std::vector output; + std::vector inputML = mlResponse.getInputFeaturesGlob(muonTrack, mchTrackProp, mftTrackProp, collision); + mlResponse.isSelectedMl(inputML, 0, output); + float matchingScore = output[0]; + // std::cout << std::format("Matching score: {}, Chi2: {}", matchingScore, muonTrack.chi2MatchMCHMFT()) << std::endl; + + // check if a vector of global muon candidates is already available for the current MCH index + // if not, initialize a new one and add the current global muon track + auto matchingCandidateIterator = newMatchingCandidates.find(mchIndex); + if (matchingCandidateIterator != newMatchingCandidates.end()) { + matchingCandidateIterator->second.push_back(std::make_pair(muonIndex, matchingScore)); + } else { + newMatchingCandidates[mchIndex].push_back(std::make_pair(muonIndex, matchingScore)); + } + } + } + } + + template + void ProcessCollisionMC(const CollisionInfo& collisionInfo, + C const& collisions, + TMUON const& muonTracks, + TMFT const& mftTracks, + CMFT const& mftCovs) + { + // std::cout << std::endl << std::format("ProcessMatching() collision #{}", collisionInfo.index) << std::endl; + auto collision = collisions.rawIteratorAt(collisionInfo.index); + + std::vector> matchablePairs; + GetMatchablePairs(collisionInfo, muonTracks, mftTracks, matchablePairs); + for (auto [mchIndex, mftIndex] : matchablePairs) { + auto const& muonTrack = muonTracks.rawIteratorAt(mchIndex); + auto muonMcParticle = muonTrack.mcParticle(); + int64_t muonMcTrackIndex = muonMcParticle.globalIndex(); + double mchMom = muonTrack.p(); + + // std::cout << std::format("TOTO1 MCH track #{} type={} p={:0.3} - MFT track #{} - collision #{} - has_collision={}", + // mchIndex, muonTrack.trackType(), mchMom, mftIndex, muonTrack.collisionId(), muonTrack.has_collision()) << std::endl; + + auto const& mftTrack = mftTracks.rawIteratorAt(mftIndex); + auto mftMcParticle = mftTrack.mcParticle(); + int64_t mftMcTrackIndex = mftMcParticle.globalIndex(); + + if (muonMcTrackIndex == mftMcTrackIndex) { + registry.get(HIST("matching/MC/pairableType"))->Fill(0); + } else { + registry.get(HIST("matching/MC/pairableType"))->Fill(1); + } + + if (mftTrackCovs.count(mftTrack.globalIndex()) < 1) { + // std::cout << std::format("Covariance matrix for MFT track #{} not found", mftTrack.globalIndex()) << std::endl; + continue; + } + auto const& mftTrackCov = mftCovs.rawIteratorAt(mftTrackCovs[mftTrack.globalIndex()]); + + // propagate tracks at the last MFT plane + auto mftTrackProp = FwdToTrackPar(mftTrack, mftTrackCov); + auto mchTrackProp = FwdToTrackPar(muonTrack, muonTrack); + auto mchTrackPropAlt = FwdToTrackPar(muonTrack, muonTrack); + + auto z = o2::mft::constants::mft::LayerZCoordinate()[9]; + // std::cout << std::format("Extrapolating tracks to z={}", matchingPlaneZ) << std::endl; + mftTrackProp = PropagateToZMFT(mftTrackProp, z); + mchTrackProp = PropagateToZMCH(mchTrackProp, z); + auto mchTrackAtVertex = VarManager::PropagateMuon(muonTrack, collision, VarManager::kToVertex); + mchTrackPropAlt = PropagateToZMCH(mchTrackAtVertex, z); + + float dx = mchTrackProp.getX() - mftTrackProp.getX(); + float dy = mchTrackProp.getY() - mftTrackProp.getY(); + registryAlignment.get(HIST("alignment/trackDxAtMFTVsP"))->Fill(mchMom, dx); + registryAlignment.get(HIST("alignment/trackDyAtMFTVsP"))->Fill(mchMom, dy); + + float dxAlt = mchTrackPropAlt.getX() - mftTrackProp.getX(); + float dyAlt = mchTrackPropAlt.getY() - mftTrackProp.getY(); + registryAlignment.get(HIST("alignment/trackDxAtMFTVsP_alt"))->Fill(mchMom, dxAlt); + registryAlignment.get(HIST("alignment/trackDyAtMFTVsP_alt"))->Fill(mchMom, dyAlt); + + // std::cout << std::format("MCH track position: x={} y={}", mchTrackProp.getX(), mchTrackProp.getY()) << std::endl; + // std::cout << std::format("MCH track pos. alt: x={} y={}", mchTrackPropAlt.getX(), mchTrackPropAlt.getY()) << std::endl; + // std::cout << std::format("MFT track position: x={} y={}", mftTrackProp.getX(), mftTrackProp.getY()) << std::endl; + } + + // plot MFT-MCH tracks difference at matching plane for wrong pairs + // outer loop on MCH tracks associated to the current collision + for (auto const& mchTrackIndex : collisionInfo.mchTracks) { + auto matchablePair = GetMatchablePairForMCH(mchTrackIndex, matchablePairs); + if (!matchablePair.has_value()) + continue; + + auto const& mchTrack = muonTracks.rawIteratorAt(mchTrackIndex); + double mchMom = mchTrack.p(); + + // std::cout << std::format("TOTO2 MCH track #{} type={} p={:0.3} - MFT track #{} - collision #{}", + // mchTrackIndex, mchTrack.trackType(), mchMom, matchablePair.value().second, mchTrack.collisionId()) << std::endl; + + // extrapolate the MCH track to the last MFT plane + auto z = o2::mft::constants::mft::LayerZCoordinate()[9]; + auto mchTrackProp = PropagateToZMCH(FwdToTrackPar(mchTrack, mchTrack), z); + auto mchTrackAtVertex = VarManager::PropagateMuon(mchTrack, collision, VarManager::kToVertex); + auto mchTrackPropAlt = PropagateToZMCH(mchTrackAtVertex, z); + + // inner loop on MFT tracks associated to the current collision + for (auto const& mftTrackIndex : collisionInfo.mftTracks) { + // skip true matches + if (mftTrackIndex == matchablePair.value().second) + continue; + auto const& mftTrack = mftTracks.rawIteratorAt(mftTrackIndex); + + // get the corresponding covariance matrix + if (mftTrackCovs.count(mftTrackIndex) < 1) { + continue; + } + auto const& mftTrackCov = mftCovs.rawIteratorAt(mftTrackCovs[mftTrackIndex]); + + auto mftTrackProp = PropagateToZMFT(FwdToTrackPar(mftTrack, mftTrackCov), z); + + float dx = mchTrackProp.getX() - mftTrackProp.getX(); + float dy = mchTrackProp.getY() - mftTrackProp.getY(); + registryAlignment.get(HIST("alignment/trackDxAtMFTVsP_fake"))->Fill(mchMom, dx); + registryAlignment.get(HIST("alignment/trackDyAtMFTVsP_fake"))->Fill(mchMom, dy); + + float dxAlt = mchTrackPropAlt.getX() - mftTrackProp.getX(); + float dyAlt = mchTrackPropAlt.getY() - mftTrackProp.getY(); + registryAlignment.get(HIST("alignment/trackDxAtMFTVsP_alt_fake"))->Fill(mchMom, dxAlt); + registryAlignment.get(HIST("alignment/trackDyAtMFTVsP_alt_fake"))->Fill(mchMom, dyAlt); + } + } + + // Chi2-based matching analysis + FillMatchingPlotsMC(collision, muonTracks, mftTracks, collisionInfo.matchingCandidates, matchablePairs, fMatchingChi2ScoreMftMchLow, fChi2MatchingPlotter.get()); + for (auto& [label, func] : matchingChi2Functions) { + MatchingCandidates matchingCandidates; + RunChi2Matching(collisions, muonTracks, mftTracks, mftCovs, label, collisionInfo.matchingCandidates, matchingCandidates); + + auto* plotter = fMatchingPlotters.at(label).get(); + double matchingScoreCut = matchingScoreCuts.at(label); + + // std::cout << std::format("Calling FillMatchingPlotsMC() for label \"{}\" and score cut {}", label, matchingScoreCut) << std::endl; + FillMatchingPlotsMC(collision, muonTracks, mftTracks, matchingCandidates, matchablePairs, matchingScoreCut, plotter); + } + + // ML-based matching analysis + for (auto& [label, mlResponse] : matchingMlResponses) { + MatchingCandidates matchingCandidates; + RunMLMatching(collisions, muonTracks, mftTracks, mftCovs, label, collisionInfo.matchingCandidates, matchingCandidates); + + auto* plotter = fMatchingPlotters.at(label).get(); + double matchingScoreCut = matchingScoreCuts.at(label); + + FillMatchingPlotsMC(collision, muonTracks, mftTracks, matchingCandidates, matchablePairs, matchingScoreCut, plotter); + } + + // Muons tagging + for (auto [mchIndex, mftIndex] : matchablePairs) { + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + if (!mchTrack.has_collision()) + continue; + auto collision = collisions.rawIteratorAt(mchTrack.collisionId()); + + auto const& mftTrack = mftTracks.rawIteratorAt(mftIndex); + if (mftTrackCovs.count(mftTrack.globalIndex()) < 1) { + continue; + } + auto const& mftTrackCov = mftCovs.rawIteratorAt(mftTrackCovs[mftTrack.globalIndex()]); + + auto mchTrackAtVertex = VarManager::PropagateMuon(mchTrack, collision, VarManager::kToVertex); + + // extrapolate to the matching plane + auto z = o2::mft::constants::mft::LayerZCoordinate()[9]; + auto mchTrackProp = PropagateToZMCH(mchTrackAtVertex, z); + auto mftTrackProp = PropagateToZMFT(FwdToTrackPar(mftTrack, mftTrackCov), z); + + registry.get(HIST("matching/MC/pairedMCHTracksAtMFT"))->Fill(mchTrackProp.getX(), mchTrackProp.getY()); + registry.get(HIST("matching/MC/pairedMFTTracksAtMFT"))->Fill(mftTrackProp.getX(), mftTrackProp.getY()); + } + + std::vector selectedMuons; + GetSelectedMuons(collisionInfo, collisions, muonTracks, selectedMuons); + for (auto mchIndex : selectedMuons) { + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + if (!mchTrack.has_collision()) + continue; + auto collision = collisions.rawIteratorAt(mchTrack.collisionId()); + + auto mchTrackAtVertex = VarManager::PropagateMuon(mchTrack, collision, VarManager::kToVertex); + + // extrapolate to the matching plane + auto z = o2::mft::constants::mft::LayerZCoordinate()[9]; + auto mchTrackProp = PropagateToZMCH(mchTrackAtVertex, z); + + registry.get(HIST("matching/MC/selectedMCHTracksAtMFT"))->Fill(mchTrackProp.getX(), mchTrackProp.getY()); + + bool isPairedMCH = IsMatchableMCH(static_cast(mchIndex), matchablePairs); + if (isPairedMCH) { + registry.get(HIST("matching/MC/selectedMCHTracksAtMFTTrue"))->Fill(mchTrackProp.getX(), mchTrackProp.getY()); + } else { + registry.get(HIST("matching/MC/selectedMCHTracksAtMFTFake"))->Fill(mchTrackProp.getX(), mchTrackProp.getY()); + } + } + + MatchingCandidates selectedMatchingCandidates; + for (auto [mchIndex, globalTracksVector] : collisionInfo.matchingCandidates) { + if (std::find(selectedMuons.begin(), selectedMuons.end(), mchIndex) != selectedMuons.end()) { + selectedMatchingCandidates[mchIndex] = globalTracksVector; + } + } + FillMatchingPlotsMC(collision, muonTracks, mftTracks, selectedMatchingCandidates, matchablePairs, fMatchingChi2ScoreMftMchLow, fSelectedMuonsMatchingPlotter.get()); + + std::vector taggedMuons; + GetTaggedMuons(collisionInfo, muonTracks, selectedMuons, taggedMuons); + + MatchingCandidates taggedMatchingCandidates; + for (auto [mchIndex, globalTracksVector] : collisionInfo.matchingCandidates) { + if (std::find(taggedMuons.begin(), taggedMuons.end(), mchIndex) != taggedMuons.end()) { + taggedMatchingCandidates[mchIndex] = globalTracksVector; + } + } + FillMatchingPlotsMC(collision, muonTracks, mftTracks, taggedMatchingCandidates, matchablePairs, fMatchingChi2ScoreMftMchLow, fTaggedMuonsMatchingPlotter.get()); + } + + void processQAMC(MyEvents const& collisions, + aod::BCsWithTimestamps const& bcs, + MyMuonsMC const& muonTracks, + MyMFTsMC const& mftTracks, + MyMFTCovariances const& mftCovs, + aod::McParticles const& /*mcParticles*/) + { + auto bc = bcs.begin(); + initCCDB(bc); + + for (auto& muon : muonTracks) { + registry.get(HIST("nTracksPerType"))->Fill(static_cast(muon.trackType())); + } + + InitCollisions(collisions, bcs, muonTracks, mftTracks, fCollisionInfos); + + mftTrackCovs.clear(); + for (auto& mftTrackCov : mftCovs) { + mftTrackCovs[mftTrackCov.matchMFTTrackId()] = mftTrackCov.globalIndex(); + } + + for (auto const& [collisionIndex, collisionInfo] : fCollisionInfos) { + ProcessCollisionMC(collisionInfo, collisions, muonTracks, mftTracks, mftCovs); + } + } + + PROCESS_SWITCH(qaMatching, processQAMC, "process qa MC", true); +}; + +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..d4f5d394fbe --- /dev/null +++ b/PWGDQ/Tasks/quarkoniaToHyperons.cxx @@ -0,0 +1,2351 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// 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"}; + + // Custom grouping + std::vector> v0sGrouped; + std::vector> cascadesGrouped; + + // vector of selected V0/cascade indices + std::vector selK0ShortIndices; + std::vector selLambdaIndices; + std::vector selAntiLambdaIndices; + std::vector selXiIndices; + std::vector selAntiXiIndices; + std::vector selOmIndices; + std::vector selAntiOmIndices; + + // 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 + if (passK0ShortSelections) + selK0ShortIndices.push_back(v0.globalIndex()); + if (passLambdaSelections) + selLambdaIndices.push_back(v0.globalIndex()); + if (passAntiLambdaSelections) + selAntiLambdaIndices.push_back(v0.globalIndex()); + } + + 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 (std::size_t iHyp = 0; iHyp < selHypIndices.size(); iHyp++) { + auto hyperon = fullHyperons.rawIteratorAt(selHypIndices[iHyp]); + + // 2nd loop over all v0s/cascade + for (std::size_t iAntiHyp = 0; iAntiHyp < selAntiHypIndices.size(); iAntiHyp++) { + // check we don't look at the same v0s/cascades + if (selHypIndices[iHyp] == selAntiHypIndices[iAntiHyp]) { + continue; + } + + auto antiHyperon = fullHyperons.rawIteratorAt(selAntiHypIndices[iAntiHyp]); + // 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 + + // 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 const& collisions, V0Candidates const& fullV0s, CascadeCandidates const& fullCascades, DauTracks const&) + { + // Custom grouping + v0sGrouped.clear(); + cascadesGrouped.clear(); + v0sGrouped.resize(collisions.size()); + cascadesGrouped.resize(collisions.size()); + + for (const auto& v0 : fullV0s) { + v0sGrouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + for (const auto& cascade : fullCascades) { + cascadesGrouped[cascade.straCollisionId()].push_back(cascade.globalIndex()); + } + + for (const auto& collision : collisions) { + // 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::size_t nV0sThisColl = v0sGrouped[collision.globalIndex()].size(); + selK0ShortIndices.clear(); + selLambdaIndices.clear(); + selAntiLambdaIndices.clear(); + for (std::size_t i = 0; i < nV0sThisColl; i++) { + auto v0 = fullV0s.rawIteratorAt(v0sGrouped[collision.globalIndex()][i]); + + 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 + std::size_t nK0Shorts = selK0ShortIndices.size(); + std::size_t nLambdas = selLambdaIndices.size(); + std::size_t nAntiLambdas = selAntiLambdaIndices.size(); + + 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::size_t nCascadesThisColl = cascadesGrouped[collision.globalIndex()].size(); + + selXiIndices.clear(); + selAntiXiIndices.clear(); + selOmIndices.clear(); + selAntiOmIndices.clear(); + for (std::size_t i = 0; i < nCascadesThisColl; i++) { + auto cascade = fullCascades.rawIteratorAt(cascadesGrouped[collision.globalIndex()][i]); + + 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 (isCascadeSelected(cascade, collision, cascade.yXi(), true)) { + if (cascade.sign() < 0) { + selXiIndices.push_back(cascade.globalIndex()); + } else { + selAntiXiIndices.push_back(cascade.globalIndex()); + } + } + } + if (buildOmOmBarPairs) { + if (isCascadeSelected(cascade, collision, cascade.yOmega(), false)) { + if (cascade.sign() < 0) { + selOmIndices.push_back(cascade.globalIndex()); + } else { + selAntiOmIndices.push_back(cascade.globalIndex()); + } + } + } + } // end cascade loop + + // count the number of Xi and antiXi passsing the selections + std::size_t nXis = selXiIndices.size(); + std::size_t nAntiXis = selAntiXiIndices.size(); + std::size_t nOmegas = selOmIndices.size(); + std::size_t nAntiOmegas = selAntiOmIndices.size(); + + // 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 const& collisions, V0MCCandidates const& fullV0s, CascadeMCCandidates const& fullCascades, DauTracks const&, aod::MotherMCParts const&, soa::Join const& /*mccollisions*/, soa::Join const&, soa::Join const&) + { + // Custom grouping + v0sGrouped.clear(); + cascadesGrouped.clear(); + v0sGrouped.resize(collisions.size()); + cascadesGrouped.resize(collisions.size()); + + for (const auto& v0 : fullV0s) { + v0sGrouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + for (const auto& cascade : fullCascades) { + cascadesGrouped[cascade.straCollisionId()].push_back(cascade.globalIndex()); + } + + for (const auto& collision : collisions) { + // 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::size_t nV0sThisColl = v0sGrouped[collision.globalIndex()].size(); + selK0ShortIndices.clear(); + selLambdaIndices.clear(); + selAntiLambdaIndices.clear(); + for (std::size_t i = 0; i < nV0sThisColl; i++) { + auto v0 = fullV0s.rawIteratorAt(v0sGrouped[collision.globalIndex()][i]); + + 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 + std::size_t nK0Shorts = selK0ShortIndices.size(); + std::size_t nLambdas = selLambdaIndices.size(); + std::size_t nAntiLambdas = selAntiLambdaIndices.size(); + + 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::size_t nCascadesThisColl = cascadesGrouped[collision.globalIndex()].size(); + + selXiIndices.clear(); + selAntiXiIndices.clear(); + selOmIndices.clear(); + selAntiOmIndices.clear(); + for (std::size_t i = 0; i < nCascadesThisColl; i++) { + auto cascade = fullCascades.rawIteratorAt(cascadesGrouped[collision.globalIndex()][i]); + + 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 (isCascadeSelected(cascade, collision, ymc, true)) { + if (cascade.sign() < 0) { + selXiIndices.push_back(cascade.globalIndex()); + } else { + selAntiXiIndices.push_back(cascade.globalIndex()); + } + } + } + if (buildOmOmBarPairs) { + if (isCascadeSelected(cascade, collision, ymc, false)) { + if (cascade.sign() < 0) { + selOmIndices.push_back(cascade.globalIndex()); + } else { + selAntiOmIndices.push_back(cascade.globalIndex()); + } + } + } + } // end cascade loop + + // count the number of Xi and antiXi passsing the selections + std::size_t nXis = selXiIndices.size(); + std::size_t nAntiXis = selAntiXiIndices.size(); + std::size_t nOmegas = selOmIndices.size(); + std::size_t nAntiOmegas = selAntiOmIndices.size(); + + // 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 39e3b83a058..2b35db2611c 100644 --- a/PWGDQ/Tasks/tableReader.cxx +++ b/PWGDQ/Tasks/tableReader.cxx @@ -11,36 +11,44 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // -#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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/DQMlResponse.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" #include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/EventSelectionParams.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" -#include "Field/MagneticField.h" -#include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" +#include "DataFormatsParameters/GRPObject.h" #include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" #include "ITSMFTBase/DPLAlpideParam.h" -#include "Common/CCDB/EventSelectionParams.h" + +#include "TGeoGlobalMagField.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -76,22 +84,6 @@ DECLARE_SOA_COLUMN(TauxyBcandidate, tauxyBcandidate, float); DECLARE_SOA_COLUMN(TauzBcandidate, tauzBcandidate, float); DECLARE_SOA_COLUMN(CosPBcandidate, cosPBcandidate, float); DECLARE_SOA_COLUMN(Chi2Bcandidate, chi2Bcandidate, float); - -// Xcandidate columns -DECLARE_SOA_COLUMN(massXcandidate, MXcandidate, float); -DECLARE_SOA_COLUMN(pTXcandidate, PtXcandidate, float); -DECLARE_SOA_COLUMN(rapidityXcandidate, YXcandidate, float); -DECLARE_SOA_COLUMN(etaXcandidate, EtaXcandidate, float); -DECLARE_SOA_COLUMN(massJpsicandidate, MJpsicandidate, float); -DECLARE_SOA_COLUMN(massDipioncandidate, MDipioncandidate, float); -DECLARE_SOA_COLUMN(pTJpsicandidate, PtJpsicandidate, float); -DECLARE_SOA_COLUMN(massDiff, Q, float); -DECLARE_SOA_COLUMN(angDistPion1, DeltaR1, float); -DECLARE_SOA_COLUMN(angDistPion2, DeltaR2, float); -DECLARE_SOA_COLUMN(cosDileptonDipion, CosDileptonDipion, float); -DECLARE_SOA_COLUMN(dcaxy, DcaXY, float); -DECLARE_SOA_COLUMN(dcaz, DcaZ, float); - } // namespace dqanalysisflags DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); @@ -100,16 +92,18 @@ DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBar DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTS", dqanalysisflags::IsMuonSelected); DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTER", dqanalysisflags::IsPrefilterVetoed); 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(XCandidates, "AOD", "DQX3872", dqanalysisflags::massXcandidate, dqanalysisflags::pTXcandidate, dqanalysisflags::rapidityXcandidate, dqanalysisflags::etaXcandidate, dqanalysisflags::massJpsicandidate, dqanalysisflags::massDipioncandidate, dqanalysisflags::pTJpsicandidate, dqanalysisflags::massDiff, dqanalysisflags::angDistPion1, dqanalysisflags::angDistPion2, dqanalysisflags::cosDileptonDipion, dqanalysisflags::dcaxy, dqanalysisflags::dcaz); } // namespace o2::aod // 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 MyEventsVtxCovQvectorExtraWithRefFlow = soa::Join; using MyEventsVtxCovSelectedQvectorExtraWithRefFlow = soa::Join; using MyEventsVtxCovSelectedQvectorCentr = soa::Join; using MyEventsQvector = soa::Join; @@ -118,8 +112,9 @@ using MyEventsQvectorCentr = 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; @@ -139,11 +134,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 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; @@ -165,14 +162,14 @@ struct AnalysisEventSelection { 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 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"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; HistogramManager* fHistMan = nullptr; MixingHandler* fMixHandler = nullptr; @@ -181,8 +178,12 @@ struct AnalysisEventSelection { 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())); @@ -222,11 +223,12 @@ struct AnalysisEventSelection { 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); + // Part temporary removed to study the issue to run on derived data on hyperloop + // 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(); } @@ -269,6 +271,10 @@ struct AnalysisEventSelection { { runEventSelection(event); } + void processSkimmedWithMultPV(MyEventsMultExtra::iterator const& event) + { + runEventSelection(event); + } void processSkimmedQVector(MyEventsQvector::iterator const& event) { runEventSelection(event); @@ -285,16 +291,27 @@ struct AnalysisEventSelection { { 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 }; @@ -306,17 +323,15 @@ struct AnalysisTrackSelection { // 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 fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + 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 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"}; Service fCCDB; @@ -325,8 +340,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; @@ -355,9 +374,6 @@ struct AnalysisTrackSelection { 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); @@ -406,7 +422,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; @@ -442,15 +458,21 @@ struct AnalysisTrackSelection { struct AnalysisMuonSelection { Produces muonSel; OutputObj fOutputList{"output"}; - Configurable fConfigCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + Configurable fConfigCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; 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(",")); @@ -488,6 +510,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); @@ -498,7 +540,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); } @@ -512,12 +554,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); }; @@ -543,8 +591,12 @@ 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); @@ -626,18 +678,28 @@ struct AnalysisEventMixing { // 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 fConfigTrackCuts{"cfgTrackCuts", "", "Comma separated list of barrel track cuts"}; - Configurable fConfigMuonCuts{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; + Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Comma separated list of barrel track cuts"}; + 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; - 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 + 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; @@ -655,6 +717,10 @@ struct AnalysisEventMixing { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fCurrentRun = 0; ccdb->setURL(ccdburl.value); @@ -679,11 +745,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(",")); @@ -698,7 +764,7 @@ struct AnalysisEventMixing { 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); } } } @@ -716,15 +782,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()); } @@ -744,34 +812,42 @@ 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())) { @@ -791,9 +867,9 @@ struct AnalysisEventMixing { } } } // 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 @@ -807,6 +883,30 @@ struct AnalysisEventMixing { } 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(); } @@ -823,6 +923,9 @@ struct AnalysisEventMixing { tracks2.bindExternalIndices(&events); VarManager::FillTwoMixEvents(event1, event2, tracks1, tracks2); + if (fConfigFlowReso) { + VarManager::FillTwoMixEventsFlowResoFactor(ResoFlowSP, ResoFlowEP); + } runMixedPairing(tracks1, tracks2); } // end event loop } @@ -884,6 +987,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&) @@ -897,6 +1004,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); }; @@ -911,17 +1019,22 @@ struct AnalysisSameEventPairing { Produces dimuonAllList; Produces dileptonFlowList; 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"}; - Configurable fConfigMuonCuts{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; - 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 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"}; + 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"}; @@ -940,6 +1053,21 @@ 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"}; + // ML inference + Configurable applyBDT{"applyBDT", false, "Flag to apply ML selections"}; + Configurable fConfigBdtCutsJSON{"fConfigBdtCutsJSON", "", "Additional list of BDT cuts in JSON format"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/j/jseo/ML/PbPbPsi/default/"}, "Paths of models on CCDB"}; + 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"}; + + // 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; @@ -950,6 +1078,10 @@ struct AnalysisSameEventPairing { HistogramManager* fHistMan; + o2::analysis::DQMlResponse fDQMlResponse; + std::vector fOutputMlPsi2ee = {}; // TODO: check this is needed or not + o2::ccdb::CcdbApi ccdbApi; + // 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 @@ -962,6 +1094,10 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { + if (context.mOptions.get("processDummy")) { + return; + } + fCurrentRun = 0; ccdb->setURL(ccdburl.value); @@ -996,12 +1132,60 @@ struct AnalysisSameEventPairing { } } + if (applyBDT) { + // BDT cuts via JSON + std::vector binsMl; + o2::framework::LabeledArray cutsMl; + std::vector cutDirMl; + int nClassesMl = 1; + std::vector namesInputFeatures; + std::vector onnxFileNames; + + auto config = o2::aod::dqmlcuts::GetBdtScoreCutsAndConfigFromJSON(fConfigBdtCutsJSON.value.c_str()); + + if (std::holds_alternative(config)) { + auto& cfg = std::get(config); + binsMl = cfg.binsMl; + nClassesMl = 1; + cutsMl = cfg.cutsMl; + cutDirMl = cfg.cutDirs; + namesInputFeatures = cfg.inputFeatures; + onnxFileNames = cfg.onnxFiles; + fDQMlResponse.setBinsCent(cfg.binsCent); + fDQMlResponse.setBinsPt(cfg.binsPt); + fDQMlResponse.setCentType(cfg.centType); + LOG(info) << "Using BDT cuts for binary classification"; + } else { + auto& cfg = std::get(config); + binsMl = cfg.binsMl; + nClassesMl = 3; + cutsMl = cfg.cutsMl; + cutDirMl = cfg.cutDirs; + namesInputFeatures = cfg.inputFeatures; + onnxFileNames = cfg.onnxFiles; + fDQMlResponse.setBinsCent(cfg.binsCent); + fDQMlResponse.setBinsPt(cfg.binsPt); + fDQMlResponse.setCentType(cfg.centType); + LOG(info) << "Using BDT cuts for multiclass classification"; + } + + fDQMlResponse.configure(binsMl, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + fDQMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + fDQMlResponse.setModelPathsLocal(onnxFileNames); + } + fDQMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + fDQMlResponse.init(); + } + if (context.mOptions.get("processDecayToEESkimmed") || context.mOptions.get("processDecayToEESkimmedNoTwoProngFitter") || context.mOptions.get("processDecayToEESkimmedWithCov") || context.mOptions.get("processDecayToEESkimmedWithCovNoTwoProngFitter") || context.mOptions.get("processDecayToEEVertexingSkimmed") || context.mOptions.get("processVnDecayToEESkimmed") || context.mOptions.get("processDecayToEEPrefilterSkimmed") || context.mOptions.get("processDecayToEEPrefilterSkimmedNoTwoProngFitter") || context.mOptions.get("processDecayToEESkimmedWithColl") || context.mOptions.get("processDecayToEESkimmedWithCollNoTwoProngFitter") || context.mOptions.get("processDecayToPiPiSkimmed") || context.mOptions.get("processAllSkimmed")) { TString cutNames = fConfigTrackCuts.value; 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()), @@ -1025,17 +1209,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("processVnDecayToMuMuSkimmedWithWeightsAndColl") || 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()), @@ -1059,9 +1243,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; @@ -1071,8 +1255,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()), @@ -1092,10 +1276,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 @@ -1106,8 +1290,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()); } @@ -1115,6 +1300,10 @@ 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) { grpmag = ccdb->getForTimeStamp(grpmagPath, event.timestamp()); @@ -1143,6 +1332,16 @@ struct AnalysisSameEventPairing { } 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(); } @@ -1173,14 +1372,33 @@ struct AnalysisSameEventPairing { dielectronAllList.reserve(1); dimuonAllList.reserve(1); } + if (useMiniTree.fConfigMiniTree) { + dileptonMiniTree.reserve(1); + } + + bool isSelectedBDT = false; 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())) { @@ -1189,17 +1407,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; @@ -1231,15 +1456,52 @@ struct AnalysisSameEventPairing { } } if constexpr ((TPairType == pairTypeEE) && (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelPID) > 0) { + if (applyBDT) { + std::vector dqInputFeatures = fDQMlResponse.getInputFeatures(t1, t2, VarManager::fgValues); + + if (dqInputFeatures.empty()) { + LOG(fatal) << "Input features for ML selection are empty! Please check your configuration."; + return; + } + + int modelIndex = -1; + const auto& binsCent = fDQMlResponse.getBinsCent(); + const auto& binsPt = fDQMlResponse.getBinsPt(); + const std::string& centType = fDQMlResponse.getCentType(); + + if ("kCentFT0C" == centType) { + modelIndex = o2::aod::dqmlcuts::getMlBinIndex(VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kPt], binsCent, binsPt); + } else if ("kCentFT0A" == centType) { + modelIndex = o2::aod::dqmlcuts::getMlBinIndex(VarManager::fgValues[VarManager::kCentFT0A], VarManager::fgValues[VarManager::kPt], binsCent, binsPt); + } else if ("kCentFT0M" == centType) { + modelIndex = o2::aod::dqmlcuts::getMlBinIndex(VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kPt], binsCent, binsPt); + } else { + LOG(fatal) << "Unknown centrality estimation type: " << centType; + return; + } + + if (modelIndex < 0) { + LOG(debug) << "Ml index is negative! This means that the centrality/pt is not in the range of the model bins."; + continue; + } + + LOG(debug) << "Model index: " << modelIndex << ", pT: " << VarManager::fgValues[VarManager::kPt] << ", centrality (kCentFT0C): " << VarManager::fgValues[VarManager::kCentFT0C]; + isSelectedBDT = fDQMlResponse.isSelectedMl(dqInputFeatures, modelIndex, fOutputMlPsi2ee); + VarManager::FillBdtScore(fOutputMlPsi2ee); // TODO: check if this is needed or not + } + + if (applyBDT && !isSelectedBDT) + continue; + 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.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.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(), + 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]); + VarManager::fgValues[VarManager::kKFMassGeoTop], VarManager::fgValues[VarManager::kKFChi2OverNDFGeoTop], VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); } } if constexpr (TPairType == pairTypeMuMu) { @@ -1258,6 +1520,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, @@ -1303,14 +1566,33 @@ struct AnalysisSameEventPairing { } } + if (applyBDT && !isSelectedBDT) + continue; + 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) { + // In the miniTree the positive daughter is positioned as first + if (t1.sign() > 0) { + dileptonMiniTree(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kRap], + VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kCos2DeltaPhi], + t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } else { + dileptonMiniTree(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kRap], + VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kCos2DeltaPhi], + t2.pt(), t2.eta(), t2.phi(), t1.pt(), t1.eta(), t1.phi()); + } + } + } } else { if (t1.sign() > 0) { fHistMan->FillHistClass(histNames[iCut][1].Data(), VarManager::fgValues); @@ -1347,12 +1629,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) @@ -1362,6 +1644,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 @@ -1425,6 +1714,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 @@ -1506,6 +1802,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); @@ -1515,6 +1812,7 @@ 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); @@ -1528,61 +1826,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 @@ -1600,7 +1843,7 @@ struct AnalysisDileptonHadron { OutputObj fOutputList{"output"}; // TODO: For now this is only used to determine the position in the filter bit map for the hadron cut - Configurable fConfigTrackCuts{"cfgLeptonCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable fConfigTrackCuts{"cfgLeptonCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; // comment: add list of subgroups (must define subgroups under ) Configurable fConfigAddDileptonHadHistogram{"cfgAddDileptonHadHistogram", "", "Comma separated list of histograms"}; Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; @@ -1635,6 +1878,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]; @@ -1739,7 +1986,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; } @@ -1785,7 +2032,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; } @@ -1793,7 +2040,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 } @@ -1811,39 +2058,41 @@ struct AnalysisDileptonHadron { struct AnalysisDileptonTrackTrack { OutputObj fOutputList{"output"}; - Configurable fConfigTrackCuts{"cfgTrackCuts", "pionPIDCut1", "Comma separated list of barrel track cuts"}; // used for select the tracks from SelectedTracks + 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 fConfigDitrackCut{"cfgDiTrackCut", "DipionPairCut1", "Track-Track cut"}; - Configurable fConfigQuadrupletCut{"cfgQuadrupletCut", "pairX3872Cut1", "Dilepton-Track-Track cut"}; + Configurable fConfigQuadrupletCuts{"cfgQuadrupletCuts", "pairX3872Cut1", "Comma separated list of Dilepton-Track-Track cut"}; Configurable fConfigAddDileptonHistogram{"cfgAddDileptonHistogram", "barrel", "Comma separated list of histograms"}; - Configurable fConfigAddDitrackHistogram{"cfgAddDitrackHistogram", "barrel", "Comma separated list of histograms"}; Configurable fConfigAddQuadrupletHistogram{"cfgAddQuadrupletHistogram", "xtojpsipipi", "Comma separated list of histograms"}; + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable fConfigUseDCAVertexing{"cfgUseDCAVertexing", false, "Use DCA for secondary vertex reconstruction (DCAFitter is used by default)"}; - Produces XTable; + 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 // use some values array to avoid mixing up the quantities - float* fValuesDitrack; 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); @@ -1851,29 +2100,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("Pairs_%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); + } } } @@ -1884,43 +2138,52 @@ 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); // LOGF(info, "Number of dileptons: %d", dileptons.size()); + // set up KF or DCAfitter + if (fConfigUseDCAVertexing) { + VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + // VarManager::SetupThreeProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + VarManager::SetupFourProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + } else if (fConfigUseKFVertexing) { + VarManager::SetupFourProngKFParticle(5.0f); + } + + 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) { - 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("Pairs_%s", fDileptonCut.GetName()), fValuesQuadruplet); // 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); + // loop over hadrons pairs for (auto& [t1, t2] : combinations(tracks, tracks)) { // avoid self-combinations @@ -1928,61 +2191,81 @@ struct AnalysisDileptonTrackTrack { continue; } - // fill variables - VarManager::FillPair(t1, t2, fValuesDitrack); - if constexpr (TCandidateType == VarManager::kChictoJpsiEE) { - VarManager::FillPair(t1, t2, fValuesDitrack); + if (fIsSameTrackCut) { + if (!(static_cast(t1.isBarrelSelected()) & (static_cast(1) << 1)) || !(static_cast(t2.isBarrelSelected()) & (static_cast(1) << 1))) { + continue; + } + } else { + if (!(static_cast(t1.isBarrelSelected()) & (static_cast(1) << 1)) || !(static_cast(t2.isBarrelSelected()) & (static_cast(1) << 2))) { + continue; + } } - VarManager::FillDileptonTrackTrack(dilepton, t1, t2, fValuesQuadruplet); - if (t1.sign() * t2.sign() > 0) { - fIsUnlikeSignDitrack = 0; - } else { - fIsUnlikeSignDitrack = 1; + // fill variables + VarManager::FillDileptonTrackTrack(dilepton, t1, t2, fValuesQuadruplet); + // reconstruct the secondary vertex + if (fConfigUseDCAVertexing || fConfigUseKFVertexing) { + VarManager::FillDileptonTrackTrackVertexing(event, lepton1, lepton2, t1, t2, fValuesQuadruplet); } - 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); - XTable(fValuesQuadruplet[VarManager::kQuadMass], fValuesQuadruplet[VarManager::kQuadPt], fValuesQuadruplet[VarManager::kRap], fValuesQuadruplet[VarManager::kQuadEta], fValuesQuadruplet[VarManager::kPairMass], fValuesQuadruplet[VarManager::kDitrackMass], fValuesQuadruplet[VarManager::kPairPt], fValuesQuadruplet[VarManager::kQ], fValuesQuadruplet[VarManager::kDeltaR1], fValuesQuadruplet[VarManager::kDeltaR2], fValuesQuadruplet[VarManager::kCosthetaDileptonDitrack], fValuesQuadruplet[VarManager::kTrackDCAxy], fValuesQuadruplet[VarManager::kTrackDCAz]); - - } 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); - } - } + 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(), + lepton1.tpcNSigmaEl(), lepton1.tpcNSigmaPi(), lepton1.tpcNSigmaPr(), lepton1.tpcNClsFound(), + lepton2.tpcNSigmaEl(), lepton2.tpcNSigmaPi(), lepton2.tpcNSigmaPr(), lepton2.tpcNClsFound(), + fValuesQuadruplet[VarManager::kDitrackMass], fValuesQuadruplet[VarManager::kDitrackPt], t1.pt(), t2.pt(), t1.eta(), t2.eta(), t1.phi(), t2.phi(), t1.sign(), t2.sign(), t1.tpcNSigmaPi(), t2.tpcNSigmaPi(), t1.tpcNSigmaKa(), t2.tpcNSigmaKa(), t1.tpcNSigmaPr(), t1.tpcNSigmaPr(), t1.tpcNClsFound(), t2.tpcNClsFound(), + fValuesQuadruplet[VarManager::kKFMass], fValuesQuadruplet[VarManager::kVertexingProcCode], fValuesQuadruplet[VarManager::kVertexingChi2PCA], fValuesQuadruplet[VarManager::kCosPointingAngle], fValuesQuadruplet[VarManager::kKFDCAxyzBetweenProngs], fValuesQuadruplet[VarManager::kKFChi2OverNDFGeo], + fValuesQuadruplet[VarManager::kVertexingLz], fValuesQuadruplet[VarManager::kVertexingLxy], fValuesQuadruplet[VarManager::kVertexingLxyz], fValuesQuadruplet[VarManager::kVertexingTauz], fValuesQuadruplet[VarManager::kVertexingTauxy], fValuesQuadruplet[VarManager::kVertexingLzErr], fValuesQuadruplet[VarManager::kVertexingLxyzErr], + fValuesQuadruplet[VarManager::kVertexingTauzErr], fValuesQuadruplet[VarManager::kVertexingLzProjected], fValuesQuadruplet[VarManager::kVertexingLxyProjected], fValuesQuadruplet[VarManager::kVertexingLxyzProjected], fValuesQuadruplet[VarManager::kVertexingTauzProjected], fValuesQuadruplet[VarManager::kVertexingTauxyProjected]); + } // end loop over track-track pairs + } // end loop over dileptons } - void processJpsiPiPi(soa::Filtered::iterator const& event, MyBarrelTracksSelectedWithCov const& tracks, soa::Filtered const& dileptons) + void processChicToJpsiPiPi(soa::Filtered::iterator const& event, MyBarrelTracksSelectedWithCov const& tracks, soa::Filtered const& dileptons) { runDileptonTrackTrack(event, tracks, dileptons); } + void processPsi2SToJpsiPiPi(soa::Filtered::iterator const& event, MyBarrelTracksSelectedWithCov const& tracks, soa::Filtered const& dileptons) + { + runDileptonTrackTrack(event, tracks, dileptons); + } + void processDummy(MyEvents&) { // do nothing } - PROCESS_SWITCH(AnalysisDileptonTrackTrack, processJpsiPiPi, "Run dilepton-dihadron pairing to study X(3872), using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrackTrack, processChicToJpsiPiPi, "Run dilepton-dihadron pairing to study X(3872), using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrackTrack, processPsi2SToJpsiPiPi, "Run dilepton-dihadron pairing to study Psi(2S), using skimmed data", false); PROCESS_SWITCH(AnalysisDileptonTrackTrack, processDummy, "Dummy function", false); }; @@ -1995,7 +2278,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 aa5b0f30372..6c9297db8bb 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc.cxx @@ -12,43 +12,55 @@ // 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 "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/DQMlResponse.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/TableHelper.h" + #include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" #include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/Configurable.h" #include "Framework/OutputObjHeader.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 "Common/Core/TableHelper.h" #include "ITSMFTBase/DPLAlpideParam.h" -#include "Common/CCDB/EventSelectionParams.h" + +#include "TGeoGlobalMagField.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -65,15 +77,25 @@ 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(RunNumber, runNumber, uint64_t); +DECLARE_SOA_COLUMN(EventIdx, eventIdx, uint64_t); +DECLARE_SOA_COLUMN(EventTimestamp, eventTimestamp, uint64_t); 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(EtaBcandidate, etaBcandidate, float); +DECLARE_SOA_COLUMN(PhiBcandidate, phiBcandidate, float); +DECLARE_SOA_COLUMN(RapBcandidate, rapBcandidate, float); DECLARE_SOA_COLUMN(LxyBcandidate, lxyBcandidate, float); DECLARE_SOA_COLUMN(LxyzBcandidate, lxyzBcandidate, float); DECLARE_SOA_COLUMN(LzBcandidate, lzBcandidate, float); @@ -81,28 +103,114 @@ 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(GlobalIndexassoc, globalIndexassoc, uint64_t); +DECLARE_SOA_COLUMN(GlobalIndexleg1, globalIndexleg1, uint64_t); +DECLARE_SOA_COLUMN(GlobalIndexleg2, globalIndexleg2, uint64_t); +DECLARE_SOA_COLUMN(Ptassoc, ptassoc, float); +DECLARE_SOA_COLUMN(PINassoc, pINassoc, float); +DECLARE_SOA_COLUMN(Etaassoc, etaassoc, float); +DECLARE_SOA_COLUMN(Phiassoc, phiassoc, float); +DECLARE_SOA_COLUMN(Ptpair, ptpair, float); +DECLARE_SOA_COLUMN(Etapair, etapair, float); +DECLARE_SOA_COLUMN(Ptleg1, ptleg1, float); +DECLARE_SOA_COLUMN(PINleg1, pINleg1, float); +DECLARE_SOA_COLUMN(Etaleg1, etaleg1, float); +DECLARE_SOA_COLUMN(Phileg1, phileg1, float); +DECLARE_SOA_COLUMN(Ptleg2, ptleg2, float); +DECLARE_SOA_COLUMN(PINleg2, pINleg2, float); +DECLARE_SOA_COLUMN(Etaleg2, etaleg2, float); +DECLARE_SOA_COLUMN(Phileg2, phileg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaKaassoc, tpcnsigmaKaassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaPiassoc, tpcnsigmaPiassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrassoc, tpcnsigmaPrassoc, float); +DECLARE_SOA_COLUMN(TOFnsigmaKaassoc, tofnsigmaKaassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaElleg1, tpcnsigmaElleg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaPileg1, tpcnsigmaPileg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrleg1, tpcnsigmaPrleg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaElleg2, tpcnsigmaElleg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaPileg2, tpcnsigmaPileg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrleg2, tpcnsigmaPrleg2, float); +DECLARE_SOA_COLUMN(ITSClusterMapassoc, itsClusterMapassoc, uint8_t); +DECLARE_SOA_COLUMN(ITSClusterMapleg1, itsClusterMapleg1, uint8_t); +DECLARE_SOA_COLUMN(ITSClusterMapleg2, itsClusterMapleg2, uint8_t); +DECLARE_SOA_COLUMN(ITSChi2assoc, itsChi2assoc, float); +DECLARE_SOA_COLUMN(ITSChi2leg1, itsChi2leg1, float); +DECLARE_SOA_COLUMN(ITSChi2leg2, itsChi2leg2, float); +DECLARE_SOA_COLUMN(TPCNclsassoc, tpcNclsassoc, float); +DECLARE_SOA_COLUMN(TPCNclsleg1, tpcNclsleg1, float); +DECLARE_SOA_COLUMN(TPCNclsleg2, tpcNclsleg2, float); +DECLARE_SOA_COLUMN(TPCChi2assoc, tpcChi2assoc, float); +DECLARE_SOA_COLUMN(TPCChi2leg1, tpcChi2leg1, float); +DECLARE_SOA_COLUMN(TPCChi2leg2, tpcChi2leg2, 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); +DECLARE_SOA_COLUMN(MultiplicityFT0A, multiplicityFT0AJPsi2ee, float); +DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0CJPsi2ee, float); +DECLARE_SOA_COLUMN(PercentileFT0M, percentileFT0MJPsi2ee, float); +DECLARE_SOA_COLUMN(MultiplicityNContrib, multiplicityNContribJPsi2ee, float); +// Candidate columns for JPsi/muon correlations +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); } // 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::RunNumber, dqanalysisflags::EventIdx, dqanalysisflags::EventTimestamp, + dqanalysisflags::massBcandidate, dqanalysisflags::MassDileptonCandidate, dqanalysisflags::deltamassBcandidate, dqanalysisflags::pTBcandidate, dqanalysisflags::EtaBcandidate, dqanalysisflags::PhiBcandidate, dqanalysisflags::RapBcandidate, + dqanalysisflags::LxyBcandidate, dqanalysisflags::LxyzBcandidate, dqanalysisflags::LzBcandidate, + dqanalysisflags::TauxyBcandidate, dqanalysisflags::TauzBcandidate, dqanalysisflags::CosPBcandidate, dqanalysisflags::Chi2Bcandidate, + dqanalysisflags::GlobalIndexassoc, dqanalysisflags::GlobalIndexleg1, dqanalysisflags::GlobalIndexleg2, + dqanalysisflags::PINassoc, dqanalysisflags::Etaassoc, dqanalysisflags::Ptpair, dqanalysisflags::Etapair, + dqanalysisflags::PINleg1, dqanalysisflags::Etaleg1, dqanalysisflags::PINleg2, dqanalysisflags::Etaleg2, + dqanalysisflags::TPCnsigmaKaassoc, dqanalysisflags::TPCnsigmaPiassoc, dqanalysisflags::TPCnsigmaPrassoc, dqanalysisflags::TOFnsigmaKaassoc, + dqanalysisflags::TPCnsigmaElleg1, dqanalysisflags::TPCnsigmaPileg1, dqanalysisflags::TPCnsigmaPrleg1, + dqanalysisflags::TPCnsigmaElleg2, dqanalysisflags::TPCnsigmaPileg2, dqanalysisflags::TPCnsigmaPrleg2, + dqanalysisflags::ITSClusterMapassoc, dqanalysisflags::ITSClusterMapleg1, dqanalysisflags::ITSClusterMapleg2, + dqanalysisflags::ITSChi2assoc, dqanalysisflags::ITSChi2leg1, dqanalysisflags::ITSChi2leg2, + dqanalysisflags::TPCNclsassoc, dqanalysisflags::TPCNclsleg1, dqanalysisflags::TPCNclsleg2, + dqanalysisflags::TPCChi2assoc, dqanalysisflags::TPCChi2leg1, dqanalysisflags::TPCChi2leg2, + dqanalysisflags::IsJpsiFromBSelected, dqanalysisflags::IsBarrelSelected); +DECLARE_SOA_TABLE(JPsiMuonCandidates, "AOD", "DQJPSIMUONA", + dqanalysisflags::DeltaEta, dqanalysisflags::DeltaPhi, + dqanalysisflags::MassDileptonCandidate, dqanalysisflags::Ptpair, dqanalysisflags::Etapair, dqanalysisflags::Ptassoc, dqanalysisflags::Etaassoc, dqanalysisflags::Phiassoc, + dqanalysisflags::Ptleg1, dqanalysisflags::Etaleg1, dqanalysisflags::Phileg1, dqanalysisflags::Ptleg2, dqanalysisflags::Etaleg2, dqanalysisflags::Phileg2); +DECLARE_SOA_TABLE(JPsieeCandidates, "AOD", "DQPSEUDOPROPER", dqanalysisflags::Massee, dqanalysisflags::Ptee, dqanalysisflags::Lxyee, dqanalysisflags::LxyeePoleMass, dqanalysisflags::Lzee, dqanalysisflags::AmbiguousInBunchPairs, dqanalysisflags::AmbiguousOutOfBunchPairs, dqanalysisflags::MultiplicityFT0A, dqanalysisflags::MultiplicityFT0C, dqanalysisflags::PercentileFT0M, dqanalysisflags::MultiplicityNContrib); } // namespace o2::aod // Declarations of various short names using MyEvents = soa::Join; +using MyEventsMultExtra = soa::Join; +using MyEventsMultExtraQVector = 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 MyEventsVtxCovSelectedQvector = soa::Join; +using MyEventsVtxCovSelectedQvectorWithHash = soa::Join; using MyEventsVtxCovZdcSelected = soa::Join; +using MyEventsVtxCovZdcSelectedMultExtra = soa::Join; using MyEventsQvector = soa::Join; using MyEventsHashSelectedQvector = soa::Join; +using MyEventsQvectorCentr = soa::Join; +using MyEventsQvectorCentrSelected = soa::Join; +using MyEventsHashSelectedQvectorCentr = soa::Join; using MyBarrelTracks = soa::Join; using MyBarrelTracksWithAmbiguities = soa::Join; @@ -114,13 +222,21 @@ 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::ObjTypes::ReducedZdc; +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 gkEventFillMapWithCovFlow = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector; 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; +// New fillmap +constexpr static uint32_t gkEventFillMapWithMultExtraWithQVector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventMultExtra | VarManager::ObjTypes::CollisionQvect; +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 gkEventFillMapWithQvectorCentr = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::CollisionQvect | VarManager::ObjTypes::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; @@ -146,18 +262,30 @@ 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 fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of 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 fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + 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"}; HistogramManager* fHistMan = nullptr; @@ -169,23 +297,58 @@ 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") || context.mOptions.get("processSkimmedWithQvectorCentr"); + 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(); - 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 - fOutputList.setObject(fHistMan->GetMainHistogramList()); + 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, "SameBunchCorrelations;OutOfBunchCorrelations;", ""); + } + // Additional histograms via JSON + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); + VarManager::SetUseVars(fHistMan->GetUsedVars()); + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } TString mixVarsString = fConfigMixingVariables.value; std::unique_ptr objArray(mixVarsString.Tokenize(",")); @@ -209,18 +372,17 @@ 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()); - LOGP(debug, "=========================== SOR / EOR is {} / {}", sor, eor); - // 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); - LOGP(debug, "==============++++++++++++========== roBias / roLength / start / end :: {} / {} / {} / {}", alppar->roFrameBiasInBC, alppar->roFrameLengthInBC, itsROFrameStartBorderMargin, itsROFrameEndBorderMargin); - // cout << "==============++++++++++++========== roBias / roLength / start / end :: " << alppar->roFrameBiasInBC << " / " << alppar->roFrameLengthInBC << " / " << itsROFrameStartBorderMargin << " / " << itsROFrameEndBorderMargin << endl; fCurrentRun = events.begin().runNumber(); } @@ -233,12 +395,32 @@ struct AnalysisEventSelection { VarManager::FillEvent(event); bool decision = false; - fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + // Fill histograms in the class Event, before cuts + if (fConfigQA) { + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); + } + + // Apply event cuts and fill histograms after selection if (fEventCut->IsSelected(VarManager::fgValues)) { - fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); - decision = true; + 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; + } } + + // 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; @@ -247,6 +429,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); @@ -257,49 +440,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); } @@ -315,6 +528,21 @@ struct AnalysisEventSelection { runEventSelection(events); publishSelections(events); } + void processSkimmedWithMultExtra(MyEventsMultExtra const& events) + { + runEventSelection(events); + publishSelections(events); + } + void processSkimmedWithMultExtraZdc(MyEventsMultExtraZdc const& events) + { + runEventSelection(events); + publishSelections(events); + } + void processSkimmedWithQvectorCentr(MyEventsQvectorCentr const& events) + { + runEventSelection(events); + publishSelections(events); + } void processDummy(MyEvents&) { // do nothing @@ -322,7 +550,10 @@ struct AnalysisEventSelection { 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, processDummy, "Dummy function", 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, processSkimmedWithQvectorCentr, "Run event selection on DQ skimmed events, with Q-vector", false); + PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", true); }; // Produces a table with barrel track decisions (joinable to the ReducedTracksAssociations) @@ -332,45 +563,62 @@ struct AnalysisTrackSelection { Produces trackAmbiguities; OutputObj fOutputList{"output"}; - Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + 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 fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of 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 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 fConfigTPCpostCalibType{"cfgTPCpostCalibType", 1, "1: (TPCncls,pIN,eta) calibration typically for pp, 2: (eta,nPV,nLong,tLong) calibration typically for PbPb"}; + Configurable fConfigTPCuseInterpolatedCalib{"cfgTPCpostCalibUseInterpolation", true, "If true, use interpolated calibration values (default: true)"}; 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(reinterpret_cast(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); @@ -378,23 +626,23 @@ 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 @@ -403,14 +651,22 @@ 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")); + if (fConfigTPCpostCalibType == 2) { + VarManager::SetCalibrationObject(VarManager::kTPCElectronStatus, calibList->FindObject("status_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCPionStatus, calibList->FindObject("status_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonStatus, calibList->FindObject("status_map_proton")); + } + VarManager::SetCalibrationType(fConfigTPCpostCalibType, fConfigTPCuseInterpolatedCalib); + } o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); if (grpmag != nullptr) { @@ -419,15 +675,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); @@ -438,7 +702,7 @@ 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 if (fPropTrack) { @@ -449,18 +713,20 @@ struct AnalysisTrackSelection { } 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()}; @@ -481,41 +747,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; - } - 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(); + 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 + } + + // 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() @@ -523,6 +795,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); @@ -533,20 +809,26 @@ 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); + PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", true); }; // 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 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 fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + 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"}; @@ -554,24 +836,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(reinterpret_cast(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); @@ -579,10 +877,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()); } @@ -597,8 +899,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) { @@ -611,7 +916,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) { @@ -620,29 +926,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) @@ -655,7 +1020,7 @@ struct AnalysisMuonSelection { } PROCESS_SWITCH(AnalysisMuonSelection, processSkimmed, "Run muon selection on DQ skimmed muons", false); - PROCESS_SWITCH(AnalysisMuonSelection, processDummy, "Dummy function", false); + PROCESS_SWITCH(AnalysisMuonSelection, processDummy, "Dummy function", true); }; // Run the prefilter selection (e.g. electron prefiltering for photon conversions) @@ -670,6 +1035,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; @@ -677,69 +1044,89 @@ struct AnalysisPrefilterSelection { Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - void init(o2::framework::InitContext& initContext) + void init(o2::framework::InitContext& context) { - if (initContext.mOptions.get("processDummy")) { - LOG(info) << "Dummy function enabled. Skipping the rest of init()" << endl; + 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(); @@ -757,6 +1144,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; } @@ -777,7 +1165,6 @@ struct AnalysisPrefilterSelection { void processBarrelSkimmed(MyEvents const& events, soa::Join const& assocs, MyBarrelTracks const& tracks) { - fPrefilterMap.clear(); for (auto& event : events) { @@ -786,15 +1173,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); } } @@ -804,7 +1202,7 @@ struct AnalysisPrefilterSelection { } PROCESS_SWITCH(AnalysisPrefilterSelection, processBarrelSkimmed, "Run Prefilter selection on reduced tracks", false); - PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", false); + PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", true); }; // Run the same-event pairing @@ -823,49 +1221,77 @@ struct AnalysisSameEventPairing { Produces dimuonAllList; Produces dileptonFlowList; Produces dileptonInfoList; + Produces PromptNonPromptSepTable; + Produces dileptonPolarList; 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 fConfigAddEventMixingHistogram{"cfgAddEventMixingHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + 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"}; + Configurable GrpLhcIfPath{"grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; + } 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 polarTables{"cfgPolarTables", false, "Produce tables with dilepton polarization information"}; + 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"}; + Configurable useRemoteCollisionInfo{"cfgUseRemoteCollisionInfo", false, "Use remote collision information from CCDB"}; + } fConfigOptions; + struct : ConfigurableGroup { + Configurable applyBDT{"applyBDT", false, "Flag to apply ML selections"}; + Configurable fConfigBdtCutsJSON{"fConfigBdtCutsJSON", "", "Additional list of BDT cuts in JSON format"}; + + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/j/jseo/ML/PbPbPsi/default/"}, "Paths of models on CCDB"}; + 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"}; + } fConfigML; - 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"}; + Service fCCDB; + o2::ccdb::CcdbApi fCCDBApi; - 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"}; - - Service fCCDB; - - Filter filterEventSelected = aod::dqanalysisflags::isEventSelected == uint32_t(1); + Filter filterEventSelected = aod::dqanalysisflags::isEventSelected > static_cast(0); HistogramManager* fHistMan; + o2::analysis::DQMlResponse fDQMlResponse; + std::vector fOutputMlPsi2ee = {}; // TODO: check this is needed or not + // keep histogram class names in maps, so we don't have to buld their names in the pair loops std::map> fTrackHistNames; std::map> fMuonHistNames; std::map> fTrackMuonHistNames; std::vector fPairCuts; + std::vector fTrackCuts; + std::map, uint32_t> fAmbiguousPairs; 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 @@ -885,25 +1311,26 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { - fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed") || context.mOptions.get("processBarrelOnlyWithCollSkimmed"); - fEnableBarrelMixingHistos = context.mOptions.get("processMixingAllSkimmed") || context.mOptions.get("processMixingBarrelSkimmed"); - 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") || context.mOptions.get("processBarrelOnlyWithQvectorCentrSkimmedNoCov"); + fEnableBarrelMixingHistos = context.mOptions.get("processMixingAllSkimmed") || context.mOptions.get("processMixingBarrelSkimmed") || context.mOptions.get("processMixingBarrelSkimmedFlow") || context.mOptions.get("processMixingBarrelWithQvectorCentrSkimmedNoCov"); + fEnableMuonHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processMuonOnlySkimmed") || context.mOptions.get("processMuonOnlySkimmedMultExtra") || context.mOptions.get("processMuonOnlySkimmedFlow") || 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; + fTrackCuts.clear(); - 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) { @@ -913,28 +1340,86 @@ 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(","); } + if (fConfigML.applyBDT) { + // BDT cuts via JSON + std::vector binsMl; + o2::framework::LabeledArray cutsMl; + std::vector cutDirMl; + int nClassesMl = 1; + std::vector namesInputFeatures; + std::vector onnxFileNames; + + auto config = o2::aod::dqmlcuts::GetBdtScoreCutsAndConfigFromJSON(fConfigML.fConfigBdtCutsJSON.value.c_str()); + + if (std::holds_alternative(config)) { + auto& cfg = std::get(config); + binsMl = cfg.binsMl; + nClassesMl = 1; + cutsMl = cfg.cutsMl; + cutDirMl = cfg.cutDirs; + namesInputFeatures = cfg.inputFeatures; + onnxFileNames = cfg.onnxFiles; + fDQMlResponse.setBinsCent(cfg.binsCent); + fDQMlResponse.setBinsPt(cfg.binsPt); + fDQMlResponse.setCentType(cfg.centType); + LOG(info) << "Using BDT cuts for binary classification"; + } else { + auto& cfg = std::get(config); + binsMl = cfg.binsMl; + nClassesMl = 3; + cutsMl = cfg.cutsMl; + cutDirMl = cfg.cutDirs; + namesInputFeatures = cfg.inputFeatures; + onnxFileNames = cfg.onnxFiles; + fDQMlResponse.setBinsCent(cfg.binsCent); + fDQMlResponse.setBinsPt(cfg.binsPt); + fDQMlResponse.setCentType(cfg.centType); + LOG(info) << "Using BDT cuts for multiclass classification"; + } + + fDQMlResponse.configure(binsMl, cutsMl, cutDirMl, nClassesMl); + if (fConfigML.loadModelsFromCCDB) { + fCCDBApi.init(fConfigCCDB.url); + fDQMlResponse.setModelPathsCCDB(onnxFileNames, fCCDBApi, fConfigML.modelPathsCCDB, fConfigML.timestampCCDB); + } else { + fDQMlResponse.setModelPathsLocal(onnxFileNames); + } + fDQMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + fDQMlResponse.init(); + } + // 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()); + } + } 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(); + fTrackCuts.push_back(tempStr); if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { - fTrackFilterMask |= (uint32_t(1) << icut); + fTrackFilterMask |= (static_cast(1) << icut); if (fEnableBarrelHistos) { names = { @@ -942,23 +1427,19 @@ struct AnalysisSameEventPairing { Form("PairsBarrelSEPP_%s", objArray->At(icut)->GetName()), Form("PairsBarrelSEMM_%s", objArray->At(icut)->GetName())}; histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + names.push_back(Form("PairsBarrelSEPM_ambiguousextra_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEPP_ambiguousextra_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEMM_ambiguousextra_%s", objArray->At(icut)->GetName())); + histNames += Form("%s;%s;%s;", names[3].Data(), names[4].Data(), names[5].Data()); if (fEnableBarrelMixingHistos) { names.push_back(Form("PairsBarrelMEPM_%s", objArray->At(icut)->GetName())); names.push_back(Form("PairsBarrelMEPP_%s", objArray->At(icut)->GetName())); names.push_back(Form("PairsBarrelMEMM_%s", objArray->At(icut)->GetName())); - histNames += Form("%s;%s;%s;", names[3].Data(), names[4].Data(), names[5].Data()); + histNames += Form("%s;%s;%s;", names[6].Data(), names[7].Data(), names[8].Data()); } - 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())); - histNames += Form("%s;%s;%s;", names[(fEnableBarrelMixingHistos ? 6 : 3)].Data(), names[(fEnableBarrelMixingHistos ? 7 : 4)].Data(), names[(fEnableBarrelMixingHistos ? 8 : 5)].Data()); - 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(); @@ -970,21 +1451,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 @@ -999,9 +1491,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(); @@ -1013,7 +1531,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) } } } @@ -1021,29 +1539,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(",")); @@ -1057,7 +1571,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 @@ -1074,18 +1588,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(); @@ -1093,27 +1612,38 @@ 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); + + if (fConfigOptions.useRemoteCollisionInfo) { + o2::parameters::GRPLHCIFData* grpo = fCCDB->getForTimeStamp(fConfigCCDB.GrpLhcIfPath, timestamp); + VarManager::SetCollisionSystem(grpo); + } } // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) @@ -1122,32 +1652,35 @@ struct AnalysisSameEventPairing { { if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() if (fCurrentRun != events.begin().runNumber()) { - initParamsFromCCDB(events.begin().timestamp(), TTwoProngFitter); + 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 dileptonMcDecision = 0; // placeholder, copy of the dqEfficiency.cxx one + 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); @@ -1157,21 +1690,31 @@ struct AnalysisSameEventPairing { dimuonsExtraList.reserve(1); dileptonInfoList.reserve(1); dileptonFlowList.reserve(1); - if (fConfigFlatTables.value) { + if (fConfigOptions.flatTables.value) { dielectronAllList.reserve(1); dimuonAllList.reserve(1); } + if (fConfigOptions.polarTables.value) { + dileptonPolarList.reserve(1); + } + fAmbiguousPairs.clear(); 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); + bool isSelectedBDT = false; 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) { @@ -1180,8 +1723,7 @@ struct AnalysisSameEventPairing { 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 @@ -1193,26 +1735,34 @@ 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); } + if constexpr (eventHasQvectorCentr) { + VarManager::FillPairVn(t1, t2); + } dielectronList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], @@ -1222,18 +1772,63 @@ struct AnalysisSameEventPairing { dielectronInfoList(t1.collisionId(), t1.trackId(), t2.trackId()); dileptonInfoList(t1.collisionId(), event.posX(), event.posY(), event.posZ()); } + if (fConfigOptions.polarTables.value) { + dileptonPolarList(VarManager::fgValues[VarManager::kCosThetaHE], VarManager::fgValues[VarManager::kPhiHE], VarManager::fgValues[VarManager::kPhiTildeHE], + VarManager::fgValues[VarManager::kCosThetaCS], VarManager::fgValues[VarManager::kPhiCS], VarManager::fgValues[VarManager::kPhiTildeCS], + VarManager::fgValues[VarManager::kCosThetaPP], VarManager::fgValues[VarManager::kPhiPP], VarManager::fgValues[VarManager::kPhiTildePP], + VarManager::fgValues[VarManager::kCosThetaRM], + VarManager::fgValues[VarManager::kCosThetaStarTPC], VarManager::fgValues[VarManager::kCosThetaStarFT0A], VarManager::fgValues[VarManager::kCosThetaStarFT0C]); + } 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 (fConfigFlatTables.value) { + if (fConfigML.applyBDT) { + std::vector dqInputFeatures = fDQMlResponse.getInputFeatures(t1, t2, VarManager::fgValues); + + if (dqInputFeatures.empty()) { + LOG(fatal) << "Input features for ML selection are empty! Please check your configuration."; + return; + } + + int modelIndex = -1; + const auto& binsCent = fDQMlResponse.getBinsCent(); + const auto& binsPt = fDQMlResponse.getBinsPt(); + const std::string& centType = fDQMlResponse.getCentType(); + + if ("kCentFT0C" == centType) { + modelIndex = o2::aod::dqmlcuts::getMlBinIndex(VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kPt], binsCent, binsPt); + } else if ("kCentFT0A" == centType) { + modelIndex = o2::aod::dqmlcuts::getMlBinIndex(VarManager::fgValues[VarManager::kCentFT0A], VarManager::fgValues[VarManager::kPt], binsCent, binsPt); + } else if ("kCentFT0M" == centType) { + modelIndex = o2::aod::dqmlcuts::getMlBinIndex(VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kPt], binsCent, binsPt); + } else { + LOG(fatal) << "Unknown centrality estimation type: " << centType; + return; + } + + if (modelIndex < 0) { + LOG(info) << "Ml index is negative! This means that the centrality/pt is not in the range of the model bins."; + continue; + } + + LOG(debug) << "Model index: " << modelIndex << ", pT: " << VarManager::fgValues[VarManager::kPt] << ", centrality (kCentFT0C): " << VarManager::fgValues[VarManager::kCentFT0C]; + isSelectedBDT = fDQMlResponse.isSelectedMl(dqInputFeatures, modelIndex, fOutputMlPsi2ee); + VarManager::FillBdtScore(fOutputMlPsi2ee); // TODO: check if this is needed or not + } + + if (fConfigML.applyBDT && !isSelectedBDT) + continue; + + 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.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.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(), + 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]); + VarManager::fgValues[VarManager::kKFMassGeoTop], + VarManager::fgValues[VarManager::kKFChi2OverNDFGeoTop], VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); } } } @@ -1247,16 +1842,40 @@ 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); } + if constexpr (eventHasQvectorCentr) { + VarManager::FillPairVn(t1, t2); + } dimuonList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], @@ -1267,8 +1886,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, @@ -1287,7 +1907,7 @@ 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_AB], VarManager::fgValues[VarManager::kR2SP_AB], VarManager::fgValues[VarManager::kCentFT0C], VarManager::fgValues[VarManager::kCos2DeltaPhi], VarManager::fgValues[VarManager::kCos3DeltaPhi], @@ -1320,34 +1940,93 @@ struct AnalysisSameEventPairing { // Fill histograms bool isAmbiInBunch = false; bool isAmbiOutOfBunch = false; + bool isUnambiguous = false; + bool isLeg1Ambi = false; + bool isLeg2Ambi = false; + bool isAmbiExtra = false; + + if (fConfigML.applyBDT && !isSelectedBDT) + continue; + 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); + isLeg1Ambi = (twoTrackFilter & (static_cast(1) << 28) || (twoTrackFilter & (static_cast(1) << 30))); + isLeg2Ambi = (twoTrackFilter & (static_cast(1) << 29) || (twoTrackFilter & (static_cast(1) << 31))); + if constexpr (TPairType == VarManager::kDecayToEE) { + if (isLeg1Ambi && isLeg2Ambi) { + std::pair iPair(a1.reducedtrackId(), a2.reducedtrackId()); + if (fAmbiguousPairs.find(iPair) != fAmbiguousPairs.end()) { + if (fAmbiguousPairs[iPair] & (static_cast(1) << icut)) { // if this pair is already stored with this cut + isAmbiExtra = true; + } else { + fAmbiguousPairs[iPair] |= static_cast(1) << icut; + } + } else { + fAmbiguousPairs[iPair] = static_cast(1) << icut; + } + } + } if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); - if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][3 + histIdxOffset].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, VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + if constexpr (TPairType == VarManager::kDecayToMuMu) { + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][3 + histIdxOffset].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][3 + histIdxOffset + 3].Data(), VarManager::fgValues); + } + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][3 + histIdxOffset + 6].Data(), VarManager::fgValues); + } } - if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][3 + histIdxOffset + 3].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToEE) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s", fTrackCuts[icut].Data()), VarManager::fgValues); + if (isAmbiExtra) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_ambiguousextra_%s", fTrackCuts[icut].Data()), VarManager::fgValues); + } } } else { if (sign1 > 0) { - fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); - if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][4 + histIdxOffset].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToMuMu) { + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][4 + histIdxOffset].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][4 + histIdxOffset + 3].Data(), VarManager::fgValues); + } + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][4 + histIdxOffset + 6].Data(), VarManager::fgValues); + } } - if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][4 + histIdxOffset + 3].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToEE) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s", fTrackCuts[icut].Data()), VarManager::fgValues); + if (isAmbiExtra) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_ambiguousextra_%s", fTrackCuts[icut].Data()), VarManager::fgValues); + } } } else { - fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); - if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][5 + histIdxOffset].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToMuMu) { + fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][5 + histIdxOffset].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][5 + histIdxOffset + 3].Data(), VarManager::fgValues); + } + if (isUnambiguous) { + fHistMan->FillHistClass(histNames[icut][5 + histIdxOffset + 6].Data(), VarManager::fgValues); + } } - if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][5 + histIdxOffset + 3].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToEE) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s", fTrackCuts[icut].Data()), VarManager::fgValues); + if (isAmbiExtra) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_ambiguousextra_%s", fTrackCuts[icut].Data()), VarManager::fgValues); + } } } } @@ -1367,8 +2046,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 @@ -1377,7 +2056,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) { @@ -1386,10 +2065,13 @@ 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); + } + if constexpr ((TEventFillMap & VarManager::ObjTypes::CollisionQvect) > 0) { + VarManager::FillPairVn(t1, t2); } pairSign = t1.sign() + t2.sign(); ncuts = fNCutsBarrel; @@ -1400,34 +2082,129 @@ 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) { + fHistMan->FillHistClass(histNames[icut][3].Data(), VarManager::fgValues); + 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); + } + } + if constexpr (TPairType == VarManager::kDecayToEE) { + fHistMan->FillHistClass(Form("PairsBarrelMEPM_%s", fTrackCuts[icut].Data()), VarManager::fgValues); + } } else { if (pairSign > 0) { - fHistMan->FillHistClass(histNames[icut][4].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToMuMu) { + fHistMan->FillHistClass(histNames[icut][4].Data(), VarManager::fgValues); + 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); + } + } + if constexpr (TPairType == VarManager::kDecayToEE) { + fHistMan->FillHistClass(Form("PairsBarrelMEPP_%s", fTrackCuts[icut].Data()), VarManager::fgValues); + } } else { - fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); + if constexpr (TPairType == VarManager::kDecayToMuMu) { + fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); + 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); + } + } + if constexpr (TPairType == VarManager::kDecayToEE) { + fHistMan->FillHistClass(Form("PairsBarrelMEMM_%s", fTrackCuts[icut].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 @@ -1436,6 +2213,7 @@ struct AnalysisSameEventPairing { { events.bindExternalIndices(&assocs); int mixingDepth = fConfigMixingDepth.value; + fAmbiguousPairs.clear(); for (auto& [event1, event2] : selfCombinations(hashBin, mixingDepth, -1, events, events)) { VarManager::ResetValues(0, VarManager::kNVars); VarManager::FillEvent(event1, VarManager::fgValues); @@ -1452,7 +2230,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); @@ -1466,6 +2244,27 @@ struct AnalysisSameEventPairing { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } + void processBarrelOnlySkimmedFlow(MyEventsVtxCovSelectedQvector const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithAmbiguities const& barrelTracks) + { + 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) @@ -1473,26 +2272,63 @@ struct AnalysisSameEventPairing { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } + void processBarrelOnlyWithQvectorCentrSkimmedNoCov(MyEventsQvectorCentrSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithAmbiguities 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 processMuonOnlySkimmedFlow(MyEventsQvectorCentrSelected 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, MyBarrelTracksWithCov const& tracks) + soa::Join const& trackAssocs, aod::ReducedTracks const& tracks) { runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); } + void processMixingBarrelSkimmedFlow(soa::Filtered& events, + soa::Join const& trackAssocs, aod::ReducedTracks const& tracks) + { + runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); + } + + void processMixingBarrelWithQvectorCentrSkimmedNoCov(soa::Filtered& events, + soa::Join const& trackAssocs, MyBarrelTracksWithAmbiguities const& tracks) + { + runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); + } + + void processMixingMuonSkimmed(soa::Filtered& events, + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + { + runSameSideMixing(events, muonAssocs, muons, muonAssocsPerCollision); + } + void processDummy(MyEvents&) { // do nothing @@ -1501,10 +2337,19 @@ 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, processBarrelOnlyWithQvectorCentrSkimmedNoCov, "Run barrel only pairing (no covariances), with skimmed tracks, with Qvector from central framework", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlySkimmedFlow, "Run barrel only pairing, with skimmed tracks and with flow", 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, processMuonOnlySkimmedFlow, "Run muon only pairing, with skimmed tracks and flow", 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, processDummy, "Dummy function, enabled only if none of the others are enabled", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMixingBarrelSkimmedFlow, "Run barrel type mixing pairing, with flow, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMixingBarrelWithQvectorCentrSkimmedNoCov, "Run barrel type mixing pairing, with skimmed tracks and with Qvector from central framework", 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", true); }; // Run pairing for resonance with legs fulfilling separate cuts (asymmetric decay channel) @@ -1520,15 +2365,22 @@ struct AnalysisAsymmetricPairing { OutputObj fOutputList{"output"}; // Configurables - Configurable fConfigLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; - Configurable fConfigCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; - Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + 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 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"}; @@ -1542,15 +2394,17 @@ struct AnalysisAsymmetricPairing { HistogramManager* fHistMan; - std::map> fTrackHistNames; - std::vector fPairCuts; + std::vector fPairCuts; + int fNPairHistPrefixes; // Filter masks to find legs in BarrelTrackCuts table uint32_t fLegAFilterMask; uint32_t fLegBFilterMask; uint32_t fLegCFilterMask; - // Map tracking which pair of leg cuts the track cuts participate in - std::map fTrackCutFilterMasks; + // 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 @@ -1559,32 +2413,71 @@ struct AnalysisAsymmetricPairing { int fNLegCuts; int fNPairCuts; int fNCommonTrackCuts; + // vectors for cut names and signal names, for easy access when calling FillHistogramList() + std::vector fLegCutNames; + std::vector fPairCutNames; + std::vector fCommonCutNames; 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) { - bool isDummy = context.mOptions.get("processDummy"); - if (isDummy) { - LOG(info) << "Dummy function enabled. Skipping the rest of init()" << endl; + if (context.mOptions.get("processDummy")) { return; } - TString histNames = ""; - std::vector names; + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + // 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())); + 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(reinterpret_cast(t)); + cutNamesStr += Form(",%s", t->GetName()); } } + std::unique_ptr objArrayPairCuts(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPairCuts->GetEntries(); + for (int j = 0; j < fNPairCuts; j++) { + fPairCutNames.push_back(objArrayPairCuts->At(j)->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; @@ -1595,14 +2488,29 @@ struct AnalysisAsymmetricPairing { for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { commonCutIdx = objArray->IndexOf(objArrayCommon->At(icut)); if (commonCutIdx >= 0) { - fCommonTrackCutMask |= uint32_t(1) << objArray->IndexOf(objArrayCommon->At(icut)); - fCommonTrackCutFilterMasks[icut] = uint32_t(1) << objArray->IndexOf(objArrayCommon->At(icut)); + fCommonTrackCutMask |= static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); + fCommonTrackCutFilterMasks[icut] = static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); + fCommonCutNames.push_back(objArrayCommon->At(icut)->GetName()); } 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) { @@ -1628,16 +2536,16 @@ struct AnalysisAsymmetricPairing { // Find leg cuts in the track selection cuts legAIdx = objArray->IndexOf(legs->At(0)); if (legAIdx >= 0) { - fLegAFilterMask |= (uint32_t(1) << legAIdx); - fTrackCutFilterMasks[icut] |= uint32_t(1) << legAIdx; + 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) { - fLegBFilterMask |= (uint32_t(1) << legBIdx); - fTrackCutFilterMasks[icut] |= uint32_t(1) << legBIdx; + 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; @@ -1645,101 +2553,93 @@ struct AnalysisAsymmetricPairing { if (isThreeProng[icut]) { legCIdx = objArray->IndexOf(legs->At(2)); if (legCIdx >= 0) { - fLegCFilterMask |= (uint32_t(1) << legCIdx); - fTrackCutFilterMasks[icut] |= uint32_t(1) << legCIdx; + 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; } } + // Leg cut config is fine, store the leg cut name in a vector + fLegCutNames.push_back(legsStr); + if (isThreeProng[icut]) { - names = { - Form("TripletsBarrelSE_%s", legsStr.Data())}; - histNames += Form("%s;", names[0].Data()); + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); if (fConfigAmbiguousHistograms.value) { - names.push_back(Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data())); - histNames += Form("%s;", names[1].Data()); + DefineHistograms(fHistMan, Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data()), fConfigHistogramSubgroups.value.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; + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); } - 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; + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); 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; + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); } // end loop (common cuts) } // end loop (pair cuts) - } // end if (pair cuts) + } // end if (pair cuts) } else { - names = {}; std::vector pairHistPrefixes = {"PairsBarrelSEPM"}; if (fConfigSameSignHistograms.value) { pairHistPrefixes.push_back("PairsBarrelSEPP"); pairHistPrefixes.push_back("PairsBarrelSEMM"); } - int fNPairHistPrefixes = pairHistPrefixes.size(); + 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()); + DefineHistograms(fHistMan, Form("%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.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()); + DefineHistograms(fHistMan, Form("%s_ambiguous_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + } + if (fConfigReflectedHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_reflected_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.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()); + DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.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()); + DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.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()); + DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.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) + } // 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) { @@ -1755,13 +2655,8 @@ struct AnalysisAsymmetricPairing { fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigLutPath)); VarManager::SetupMatLUTFwdDCAFitter(fLUT); - VarManager::SetDefaultVarNames(); - 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 - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + 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()); } @@ -1807,8 +2702,10 @@ struct AnalysisAsymmetricPairing { // 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*/) + 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); @@ -1816,8 +2713,6 @@ struct AnalysisAsymmetricPairing { } } - std::map> histNames = fTrackHistNames; - int sign1 = 0; int sign2 = 0; ditrackList.reserve(1); @@ -1833,145 +2728,164 @@ struct AnalysisAsymmetricPairing { VarManager::ResetValues(0, VarManager::kNVars); VarManager::FillEvent(event, VarManager::fgValues); - auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); - if (groupedAssocs.size() == 0) { + auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegAAssocs.size() == 0) { + continue; + } + auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegBAssocs.size() == 0) { continue; } - // TODO: Think about double counting - for (auto& a1 : groupedAssocs) { - // Check if a1 is a leg A candidate - uint32_t a1AFilter = a1.isBarrelSelected_raw() & fLegAFilterMask; - if (!a1AFilter) { - continue; - } - for (auto& a2 : groupedAssocs) { - // Check if a2 is a leg B candidate - uint32_t a2BFilter = a2.isBarrelSelected_raw() & fLegBFilterMask; - if (!a2BFilter) { - continue; - } + for (auto& [a1, a2] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { - uint32_t twoTrackFilter = 0; - uint32_t pairFilter = 0; + 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 - for (int icut = 0; icut < fNLegCuts; ++icut) { - if (((a1AFilter | a2BFilter) & fTrackCutFilterMasks[icut]) == fTrackCutFilterMasks[icut]) { - twoTrackFilter |= (uint32_t(1) << icut); + 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); + } } } - // Find common track cuts both candidates pass - twoTrackFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; + } + if (!twoTrackFilter) { + continue; + } - 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(); + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); - // Avoid self-pairs - if (t1.globalIndex() == t2.globalIndex()) { - continue; - } + // Avoid self-pairs + if (t1.globalIndex() == t2.globalIndex()) { + 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.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= (uint32_t(1) << 30); - } - if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= (uint32_t(1) << 31); - } + 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; - VarManager::FillPair(t1, t2); - if constexpr (TTwoProngFitter) { - VarManager::FillPairVertexing(event, t1, t2, fConfigPropToPCA); - } + 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); + } - // Fill histograms - bool isAmbi = false; - for (int icut = 0; icut < fNLegCuts; icut++) { - if (twoTrackFilter & (uint32_t(1) << icut)) { - isAmbi = (twoTrackFilter & (uint32_t(1) << 30)) || (twoTrackFilter & (uint32_t(1) << 31)); - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); + 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(Form("PairsBarrelSEPM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); // reconstructed, unmatched + if (isAmbi && fConfigAmbiguousHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s", fLegCutNames[icut].Data()), VarManager::fgValues); if (isAmbi && fConfigAmbiguousHistograms.value) { - fHistMan->FillHistClass(histNames[icut][3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (isAmbi && fConfigAmbiguousHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].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(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].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][4].Data(), VarManager::fgValues); - } + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); } else { - fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); - if (isAmbi && fConfigAmbiguousHistograms.value) { - fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); - } + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); } } - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (twoTrackFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + // 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 + icut * fNCommonTrackCuts + iCommonCut][0].Data(), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); } else if (fConfigSameSignHistograms.value) { if (sign1 > 0) { - fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); } else { - fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][2].Data(), VarManager::fgValues); + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); } } } - } // end loop (common cuts) - for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++) { - AnalysisCompositeCut cut = fPairCuts.at(iPairCut); - if (!(cut.IsSelected(VarManager::fgValues))) // apply pair cuts - continue; - pairFilter |= (uint32_t(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 (twoTrackFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts + 1) + 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 + 1) + iCommonCut * (1 + fNPairCuts) + iPairCut][1].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts + 1) + 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); - if constexpr (trackHasCov && TTwoProngFitter) { - ditrackExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + } + } // end loop (pair cuts) } - } // end inner assoc loop (leg A) - } // end outer assoc loop (leg B) - } // end event loop + } // 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) + 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()) { @@ -1980,8 +2894,6 @@ struct AnalysisAsymmetricPairing { } } - std::map> histNames = fTrackHistNames; - for (auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; @@ -1990,31 +2902,28 @@ struct AnalysisAsymmetricPairing { VarManager::ResetValues(0, VarManager::kNVars); VarManager::FillEvent(event, VarManager::fgValues); - auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); - if (groupedAssocs.size() == 0) { + 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; } - - // Partitions based on leg selections - Partition legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fLegAFilterMask) > uint32_t(0); - legACandidateAssocs.bindTable(groupedAssocs); - legACandidateAssocs.bindExternalIndices(&tracks); - Partition legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fLegBFilterMask) > uint32_t(0); - legBCandidateAssocs.bindTable(groupedAssocs); - legBCandidateAssocs.bindExternalIndices(&tracks); - Partition legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fLegCFilterMask) > uint32_t(0); - legCCandidateAssocs.bindTable(groupedAssocs); - legCCandidateAssocs.bindExternalIndices(&tracks); // Based on triplet type, make suitable combinations of the partitions if (tripletType == VarManager::kTripleCandidateToPKPi) { - for (auto& [a1, a2, a3] : combinations(soa::CombinationsFullIndexPolicy(legACandidateAssocs, legBCandidateAssocs, legCCandidateAssocs))) { - readTriplet(a1, a2, a3, tracks, event, tripletType, histNames); + for (auto& [a1, a2, a3] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs, groupedLegCAssocs))) { + readTriplet(a1, a2, a3, tracks, event, tripletType); } } else if (tripletType == VarManager::kTripleCandidateToKPiPi) { - for (auto& a1 : legACandidateAssocs) { - for (auto& [a2, a3] : combinations(legBCandidateAssocs, legCCandidateAssocs)) { - readTriplet(a1, a2, a3, tracks, event, tripletType, histNames); + for (auto& a1 : groupedLegAAssocs) { + for (auto& [a2, a3] : combinations(groupedLegBAssocs, groupedLegCAssocs)) { + readTriplet(a1, a2, a3, tracks, event, tripletType); } } } else { @@ -2025,22 +2934,39 @@ struct AnalysisAsymmetricPairing { // 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) + void readTriplet(TTrackAssoc const& a1, TTrackAssoc const& a2, TTrackAssoc const& a3, TTracks const& /*tracks*/, TEvent const& event, VarManager::PairCandidateType tripletType) { - uint32_t threeTrackFilter = 0; - // Find out which leg cut combination the triplet passes + uint32_t threeTrackFilter = static_cast(0); + uint32_t threeTrackCommonFilter = static_cast(0); for (int icut = 0; icut < fNLegCuts; ++icut) { - if ((((a1.isBarrelSelected_raw() & fLegAFilterMask) | (a2.isBarrelSelected_raw() & fLegBFilterMask) | (a3.isBarrelSelected_raw() & fLegCFilterMask)) & fTrackCutFilterMasks[icut]) == fTrackCutFilterMasks[icut]) { - threeTrackFilter |= (uint32_t(1) << 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; + } + } } } - // Find common track cuts both candidates pass - threeTrackFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; - 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(); @@ -2049,16 +2975,27 @@ struct AnalysisAsymmetricPairing { 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 |= (uint32_t(1) << 29); + threeTrackFilter |= (static_cast(1) << 29); } if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { - threeTrackFilter |= (uint32_t(1) << 30); + threeTrackFilter |= (static_cast(1) << 30); } if (t3.barrelAmbiguityInBunch() > 1 || t3.barrelAmbiguityOutOfBunch() > 1) { - threeTrackFilter |= (uint32_t(1) << 31); + threeTrackFilter |= (static_cast(1) << 31); } VarManager::FillTriple(t1, t2, t3, VarManager::fgValues, tripletType); @@ -2068,27 +3005,26 @@ struct AnalysisAsymmetricPairing { // Fill histograms for (int icut = 0; icut < fNLegCuts; icut++) { - if (threeTrackFilter & (uint32_t(1) << icut)) { - fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); - if (fConfigAmbiguousHistograms.value && ((threeTrackFilter & (uint32_t(1) << 29)) || (threeTrackFilter & (uint32_t(1) << 30)) || (threeTrackFilter & (uint32_t(1) << 31)))) { - fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + if (threeTrackFilter & (static_cast(1) << icut)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (fConfigAmbiguousHistograms.value && ((threeTrackFilter & (static_cast(1) << 29)) || (threeTrackFilter & (static_cast(1) << 30)) || (threeTrackFilter & (static_cast(1) << 31)))) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); } for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (threeTrackFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - fHistMan->FillHistClass(histNames[fNLegCuts + icut * fNCommonTrackCuts + iCommonCut][0].Data(), VarManager::fgValues); + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); } } // end loop (common cuts) - for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++) { - AnalysisCompositeCut cut = fPairCuts.at(iPairCut); - if (!(cut.IsSelected(VarManager::fgValues))) { // apply pair 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); + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); // Histograms with pair cuts and common track cuts for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - if (threeTrackFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - fHistMan->FillHistClass(histNames[(fNLegCuts * (fNCommonTrackCuts + 1) + fNLegCuts * fNPairCuts) + icut * (fNPairCuts * fNCommonTrackCuts + 1) + iCommonCut * (1 + fNPairCuts) + iPairCut][0].Data(), VarManager::fgValues); + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); } } } // end loop (pair cuts) @@ -2103,6 +3039,13 @@ struct AnalysisAsymmetricPairing { 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) @@ -2110,6 +3053,13 @@ struct AnalysisAsymmetricPairing { 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) @@ -2124,6 +3074,8 @@ struct AnalysisAsymmetricPairing { 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); }; @@ -2133,37 +3085,53 @@ struct AnalysisAsymmetricPairing { // tracks passing the fConfigTrackCut cut. The dileptons cuts from the same-event pairing task are auto-detected struct AnalysisDileptonTrack { Produces BmesonsTable; + Produces DileptonTrackTable; 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"}; + Configurable fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap 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 fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; 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 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"}; + Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable fConfigUseRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing"}; + Configurable fConfigEnergycorrelator{"cfgEnergycorrelator", false, "Add some hist for energy correlator study"}; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - int fNCuts; - int fNPairCuts; - int fTrackCutBit; - std::map fHistNamesDileptonTrack; - std::map fHistNamesDileptons; - std::map fHistNamesME; + int fNCuts; // number of dilepton leg cuts + int fNLegCuts; + 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; + std::vector fLegCutNames; + // 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 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 eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); + Filter dileptonFilter = aod::reducedpair::pt > fConfigDileptonLowpTCut&& aod::reducedpair::pt 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 @@ -2181,119 +3149,223 @@ struct AnalysisDileptonTrack { 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 || isBarrelAsymmetric) { - // get the list of single track and muon cuts computed in the dedicated tasks upstream - string tempCutsSingle; + // 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", tempCutsSingle, false); + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", cfgTrackSelection_TrackCuts, false); } else { - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCutsSingle, false); + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", cfgTrackSelection_TrackCuts, false); } - TString tempCutsSingleStr = tempCutsSingle; - TObjArray* objArraySingleCuts = nullptr; - if (!tempCutsSingleStr.IsNull()) { - objArraySingleCuts = tempCutsSingleStr.Tokenize(","); + + 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 { + LOG(fatal) << " No track cuts specified! Check it out!"; + } + 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 |= (static_cast(1) << icut); + } } + fNCuts = fTrackCutNames.size(); + // get the cuts employed for same-event pairing - string tempCutsSinglePair; - string pairCuts; + // 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_PairCutsJSON; + string cfgPairing_CommonTrackCuts; if (isBarrel) { - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", tempCutsSinglePair, false); - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", pairCuts, false); + 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", tempCutsSinglePair, false); - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", pairCuts, false); + 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", tempCutsSinglePair, false); - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCuts", pairCuts, false); - } - - TString tempCutsSinglePairStr = tempCutsSinglePair; - bool cutFound; - if (!tempCutsSingleStr.IsNull() && !tempCutsSinglePairStr.IsNull()) { - std::unique_ptr objArray(tempCutsSinglePairStr.Tokenize(",")); - fNCuts = objArray->GetEntries(); - for (int icut = 0; icut < fNCuts; ++icut) { - TString tempStr = objArray->At(icut)->GetName(); - if (!isBarrelAsymmetric) { - cutFound = objArraySingleCuts->FindObject(tempStr.Data()) != nullptr; - } else { - std::unique_ptr legObjArray(tempStr.Tokenize(":")); - cutFound = true; - for (int iicut = 0; iicut < legObjArray->GetEntries(); ++iicut) { - TString tempLegStr = legObjArray->At(iicut)->GetName(); - if (objArraySingleCuts->FindObject(tempLegStr.Data()) == nullptr) { - cutFound = false; - } - } - } - if (cutFound) { - fHistNamesDileptonTrack[icut] = Form("DileptonTrack_%s_%s", tempStr.Data(), fConfigTrackCut.value.data()); - fHistNamesDileptons[icut] = Form("DileptonsSelected_%s", tempStr.Data()); - TString pairCutsStr = pairCuts; - DefineHistograms(fHistMan, fHistNamesDileptonTrack[icut], fConfigHistogramSubgroups.value.data()); // define dilepton-track histograms - DefineHistograms(fHistMan, fHistNamesDileptons[icut], "barrel,vertexing"); // define dilepton histograms - if (!pairCutsStr.IsNull()) { - std::unique_ptr objArrayPairCuts(pairCutsStr.Tokenize(",")); - fNPairCuts = objArrayPairCuts->GetEntries(); - for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { - fHistNamesDileptonTrack[fNCuts + icut * fNPairCuts + iPairCut] = Form("DileptonTrack_%s_%s_%s", tempStr.Data(), objArrayPairCuts->At(iPairCut)->GetName(), fConfigTrackCut.value.data()); - fHistNamesDileptons[fNCuts + icut * fNPairCuts + iPairCut] = Form("DileptonsSelected_%s_%s", tempStr.Data(), objArrayPairCuts->At(iPairCut)->GetName()); - DefineHistograms(fHistMan, fHistNamesDileptonTrack[fNCuts + icut * fNPairCuts + iPairCut], fConfigHistogramSubgroups.value.data()); // define dilepton-track histograms - DefineHistograms(fHistMan, fHistNamesDileptons[fNCuts + icut * fNPairCuts + iPairCut], "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-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 asymmetric-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()); } } } - for (int icut = 0; icut < objArraySingleCuts->GetEntries(); ++icut) { - TString tempStr = objArraySingleCuts->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) + // Get also the pair cuts specified via the JSON parameters + if (isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCutsJSON", cfgPairing_PairCutsJSON, false); + TString addPairCutsStr = cfgPairing_PairCutsJSON; + if (addPairCutsStr != "") { + std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); + for (auto& t : addPairCuts) { + cfgPairing_PairCuts += Form(",%s", t->GetName()); } } } - } - if (fHistNamesDileptons.size() == 0) { - LOG(fatal) << " No valid dilepton cuts "; - } - if (context.mOptions.get("processBarrelMixedEvent")) { - DefineHistograms(fHistMan, "DileptonTrackME", "mixedevent"); // define all histograms + 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(",")); + // If asymmetric pairs are used, the number of cuts should come from the asymmetric-pairing task + if (isBarrelAsymmetric) { + fNLegCuts = cfgPairing_objArrayTrackCuts->GetEntries(); + } else { + fNLegCuts = fNCuts; + } + // loop over single lepton cuts + for (int icut = 0; icut < fNLegCuts; ++icut) { + + TString pairLegCutName; + + // here we check that this cut is one of those used for building the dileptons + if (!isBarrelAsymmetric) { + if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { + continue; + } + pairLegCutName = fTrackCutNames[icut].Data(); + } else { + // For asymmetric pairs we access the leg cuts instead + pairLegCutName = static_cast(cfgPairing_objArrayTrackCuts->At(icut))->GetString(); + } + fLegCutNames.push_back(pairLegCutName); + + // 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 & (static_cast(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("DileptonsSelected_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data()), "barrel,vertexing"); + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + } + } + + if (fNPairCuts != 0) { + + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].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("DileptonsSelected_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + } + } + } + } + + if (isBarrelME || isMuonME) { + DefineHistograms(fHistMan, Form("DileptonTrackME_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), "dilepton-hadron-array-correlation"); // define ME histograms + if (fConfigEnergycorrelator) { + DefineHistograms(fHistMan, Form("DileptonTrackECME_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), "energy-correlator"); // 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()); + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + LOG(info) << "Loading geometry from CCDB in dilepton-track task"; + fCCDB->get(fConfigGeoPath); + } } // init parameters from CCDB @@ -2338,36 +3410,98 @@ struct AnalysisDileptonTrack { if (dilepton.sign() != 0) { continue; } + // dilepton rap cut + float rap = dilepton.rap(); + if (fConfigUseRapcut && abs(rap) > fConfigDileptonRapCutAbs) + continue; VarManager::FillTrack(dilepton, fValuesDilepton); - for (int icut = 0; icut < fNCuts; icut++) { - if (dilepton.filterMap_bit(icut)) { - fHistMan->FillHistClass(fHistNamesDileptons[icut].Data(), fValuesDilepton); - if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column - for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { - if (dilepton.pairFilterMap_bit(iPairCut)) { - fHistMan->FillHistClass(fHistNamesDileptons[fNCuts + icut * fNPairCuts + iPairCut].Data(), fValuesDilepton); + + // loop over existing dilepton leg cuts (e.g. electron1, electron2, etc) + for (int icut = 0; icut < fNLegCuts; icut++) { + + if (!dilepton.filterMap_bit(icut)) { + continue; + } + + // regular dileptons + fHistMan->FillHistClass(Form("DileptonsSelected_%s", fLegCutNames[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", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data()), fValuesDilepton); + } + } + for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { + if (dilepton.pairFilterMap_bit(iPairCut)) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fLegCutNames[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", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); + } } } } } - } + } // end loop over single lepton selections // loop over hadrons for (auto& assoc : assocs) { - if constexpr (TCandidateType == VarManager::kBtoJpsiEEK || TCandidateType == VarManager::kDstarToD0KPiPi) { - if (!assoc.isBarrelSelected_bit(fTrackCutBit)) { + + 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); + // table to be written out for ML analysis + BmesonsTable(event.runNumber(), event.globalIndex(), event.timestamp(), fValuesHadron[VarManager::kPairMass], dilepton.mass(), fValuesHadron[VarManager::kDeltaMass], fValuesHadron[VarManager::kPairPt], fValuesHadron[VarManager::kPairEta], fValuesHadron[VarManager::kPairPhi], fValuesHadron[VarManager::kPairRap], + fValuesHadron[VarManager::kVertexingLxy], fValuesHadron[VarManager::kVertexingLxyz], fValuesHadron[VarManager::kVertexingLz], + fValuesHadron[VarManager::kVertexingTauxy], fValuesHadron[VarManager::kVertexingTauz], fValuesHadron[VarManager::kCosPointingAngle], + fValuesHadron[VarManager::kVertexingChi2PCA], + track.globalIndex(), lepton1.globalIndex(), lepton2.globalIndex(), + track.tpcInnerParam(), track.eta(), dilepton.pt(), dilepton.eta(), lepton1.tpcInnerParam(), lepton1.eta(), lepton2.tpcInnerParam(), lepton2.eta(), + track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tpcNSigmaPr(), track.tofNSigmaKa(), + lepton1.tpcNSigmaEl(), lepton1.tpcNSigmaPi(), lepton1.tpcNSigmaPr(), + lepton2.tpcNSigmaEl(), lepton2.tpcNSigmaPi(), lepton2.tpcNSigmaPr(), + track.itsClusterMap(), lepton1.itsClusterMap(), lepton2.itsClusterMap(), + track.itsChi2NCl(), lepton1.itsChi2NCl(), lepton2.itsChi2NCl(), + track.tpcNClsFound(), lepton1.tpcNClsFound(), lepton2.tpcNClsFound(), + track.tpcChi2NCl(), lepton1.tpcChi2NCl(), lepton2.tpcChi2NCl(), + dilepton.filterMap_raw(), trackSelection); + } + 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(); @@ -2377,22 +3511,47 @@ struct AnalysisDileptonTrack { VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + // Fill table for correlation analysis + DileptonTrackTable(fValuesHadron[VarManager::kDeltaEta], fValuesHadron[VarManager::kDeltaPhi], + dilepton.mass(), dilepton.pt(), dilepton.eta(), track.pt(), track.eta(), track.phi(), + lepton1.pt(), lepton1.eta(), lepton1.phi(), lepton2.pt(), lepton2.eta(), lepton2.phi()); } - for (int icut = 0; icut < fNCuts; icut++) { - if (dilepton.filterMap_bit(icut)) { - fHistMan->FillHistClass(fHistNamesDileptonTrack[icut].Data(), fValuesHadron); + // Fill histograms for the triplets + // loop over dilepton / ditrack cuts + for (int icut = 0; icut < fNLegCuts; 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 & (static_cast(1) << iTrackCut))) { + continue; + } + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s", fLegCutNames[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", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + } + } for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { if (dilepton.pairFilterMap_bit(iPairCut)) { - fHistMan->FillHistClass(fHistNamesDileptonTrack[fNCuts + icut * fNPairCuts + iPairCut].Data(), fValuesHadron); + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fLegCutNames[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", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + } + } } } } - } - } - // 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]); + } // end loop over track cuts + } // end loop over dilepton cuts } } } @@ -2471,32 +3630,55 @@ 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 & (static_cast(1) << iTrackCut)) { + fHistMan->FillHistClass(Form("DileptonTrackME_%s_%s", fTrackCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), VarManager::fgValues); + if (fConfigEnergycorrelator) { + fHistMan->FillHistClass(Form("DileptonTrackECME_%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, @@ -2521,7 +3703,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(); @@ -2529,13 +3712,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 & (static_cast(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&) @@ -2548,7 +3736,258 @@ struct AnalysisDileptonTrack { 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); - PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", true); +}; + +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 fConfigAddDileptonHistogram{"cfgAddDileptonHistogram", "barrel", "Comma separated list of histograms"}; + Configurable fConfigAddQuadrupletHistogram{"cfgAddQuadrupletHistogram", "xtojpsipipi", "Comma separated list of histograms"}; + + Configurable fConfigSetupFourProngFitter{"cfgSetupFourProngFitter", false, "Use DCA for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + 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"}; + + Produces DileptonTrackTrackTable; + + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + // uint32_t fTrackCutBitMap; // track cut bit mask to be used in the selection of tracks associated with dileptons + // cut name setting + TString fTrackCutName1; + TString fTrackCutName2; + bool fIsSameTrackCut = false; + AnalysisCompositeCut fDileptonCut; + std::vector fQuadrupletCutNames; + std::vector fQuadrupletCuts; + + Service fCCDB; + + Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); + Filter dileptonFilter = aod::reducedpair::sign == 0; + Filter filterBarrelTrackSelected = aod::dqanalysisflags::isBarrelSelected > static_cast(0); + + constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map + + // use some values array to avoid mixing up the quantities + float* fValuesQuadruplet; + HistogramManager* fHistMan; + + void init(o2::framework::InitContext& context) + { + // bool isBarrel = context.mOptions.get("processJpsiPiPi"); + + if (context.mOptions.get("processDummy")) { + return; + } + + fCurrentRun = 0; + + fValuesQuadruplet = new float[VarManager::kNVars]; + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // define cuts + fTrackCutName1 = fConfigTrackCut1.value; + fTrackCutName2 = fConfigTrackCut2.value; + if (fTrackCutName1 == fTrackCutName2) { + fIsSameTrackCut = true; + } + TString configDileptonCutNamesStr = fConfigDileptonCut.value; + fDileptonCut = *dqcuts::GetCompositeCut(configDileptonCutNamesStr.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")) { + DefineHistograms(fHistMan, Form("Pairs_%s", configDileptonCutNamesStr.Data()), fConfigAddDileptonHistogram.value.data()); + if (!configQuadruletCutNamesStr.IsNull()) { + for (std::size_t icut = 0; icut < fQuadrupletCutNames.size(); ++icut) { + if (fIsSameTrackCut) { + DefineHistograms(fHistMan, Form("QuadrupletSEPM_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram.value.data()); + } else { + DefineHistograms(fHistMan, Form("QuadrupletSEPM_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram.value.data()); + DefineHistograms(fHistMan, Form("QuadrupletSEMP_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram.value.data()); + } + DefineHistograms(fHistMan, Form("QuadrupletSEPP_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram.value.data()); + DefineHistograms(fHistMan, Form("QuadrupletSEMM_%s", fQuadrupletCutNames[icut].Data()), fConfigAddQuadrupletHistogram.value.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::SetupTwoProngKFParticle(magField); + VarManager::SetupFourProngKFParticle(magField); + } else if (fConfigSetupFourProngFitter.value) { + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + VarManager::SetupFourProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(fConfigMagField.value); + VarManager::SetupFourProngKFParticle(fConfigMagField.value); + } else if (fConfigSetupFourProngFitter.value) { + LOGP(info, "Setting up DCA fitter for two and four prong candidates"); + VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + VarManager::SetupFourProngDCAFitter(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 runDileptonTrackTrack(TEvent const& event, TTrackAssocs const& assocs, TTracks const& tracks, TDileptons const& dileptons) + { + VarManager::ResetValues(0, VarManager::kNVars, fValuesQuadruplet); + VarManager::FillEvent(event, fValuesQuadruplet); + // int indexOffset = -999; + // std::vector trackGlobalIndexes; + + for (auto dilepton : dileptons) { + // get full track info of tracks based on the index + + int indexLepton1 = dilepton.index0Id(); + int indexLepton2 = dilepton.index1Id(); + auto lepton1 = tracks.rawIteratorAt(dilepton.index0Id()); + auto lepton2 = tracks.rawIteratorAt(dilepton.index1Id()); + // Check that the dilepton has zero charge + if (dilepton.sign() != 0) { + continue; + } + VarManager::FillTrack(dilepton, fValuesQuadruplet); + // LOGP(info, "is dilepton selected: {}", fDileptonCut.IsSelected(fValuesQuadruplet)); + + // apply the dilepton cut + if (!fDileptonCut.IsSelected(fValuesQuadruplet)) + continue; + + fHistMan->FillHistClass(Form("Pairs_%s", fDileptonCut.GetName()), fValuesQuadruplet); + + // loop over hadrons pairs + for (auto& [a1, a2] : o2::soa::combinations(assocs, assocs)) { + uint32_t trackSelection = 0; + if (fIsSameTrackCut) { + trackSelection = ((a1.isBarrelSelected_raw() & (static_cast(1) << 1)) || (a2.isBarrelSelected_raw() & (static_cast(1) << 1))); + } else { + trackSelection = ((a1.isBarrelSelected_raw() & (static_cast(1) << 1)) && (a2.isBarrelSelected_raw() & (static_cast(1) << 2))); + } + // LOGP(info, "trackSelection: {}, a1: {}, a2: {}", trackSelection, a1.isBarrelSelected_raw(), a2.isBarrelSelected_raw()); + if (!trackSelection) { + continue; + } + + // get the track from this association + auto track1 = a1.template reducedtrack_as(); + auto track2 = a2.template reducedtrack_as(); + // avoid self combinations + if (track1.globalIndex() == indexLepton1 || track1.globalIndex() == indexLepton2 || track2.globalIndex() == indexLepton1 || track2.globalIndex() == indexLepton2) { + continue; + } + + // fill variables + VarManager::FillDileptonTrackTrack(dilepton, track1, track2, fValuesQuadruplet); + if (fConfigSetupFourProngFitter || fConfigUseKFVertexing) { + // LOGP(info, "Using KF or DCA fitter for secondary vertexing"); + VarManager::FillDileptonTrackTrackVertexing(event, lepton1, lepton2, track1, track2, 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 (track1.sign() * track2.sign() < 0) { + fHistMan->FillHistClass(Form("QuadrupletSEPM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } + } else { + if ((track1.sign() < 0) && (track2.sign() > 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEMP_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } else if ((track1.sign() > 0) && (track2.sign() < 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEPM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } + } + if ((track1.sign() > 0) && (track2.sign() > 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEPP_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } else if ((track1.sign() < 0) && (track2.sign() < 0)) { + fHistMan->FillHistClass(Form("QuadrupletSEMM_%s", fQuadrupletCutNames[iCut].Data()), fValuesQuadruplet); + } + } + } // loop over dilepton-track-track cuts + + // fill table + 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(), + lepton1.tpcNSigmaEl(), lepton1.tpcNSigmaPi(), lepton1.tpcNSigmaPr(), lepton1.tpcNClsFound(), + lepton2.tpcNSigmaEl(), lepton2.tpcNSigmaPi(), lepton2.tpcNSigmaPr(), lepton2.tpcNClsFound(), + fValuesQuadruplet[VarManager::kDitrackMass], fValuesQuadruplet[VarManager::kDitrackPt], track1.pt(), track2.pt(), track1.eta(), track2.eta(), track1.phi(), track2.phi(), track1.sign(), track2.sign(), track1.tpcNSigmaPi(), track2.tpcNSigmaPi(), track1.tpcNSigmaKa(), track2.tpcNSigmaKa(), track1.tpcNSigmaPr(), track1.tpcNSigmaPr(), track1.tpcNClsFound(), track2.tpcNClsFound(), + fValuesQuadruplet[VarManager::kKFMass], fValuesQuadruplet[VarManager::kVertexingProcCode], fValuesQuadruplet[VarManager::kVertexingChi2PCA], fValuesQuadruplet[VarManager::kCosPointingAngle], fValuesQuadruplet[VarManager::kKFDCAxyzBetweenProngs], fValuesQuadruplet[VarManager::kKFChi2OverNDFGeo], + fValuesQuadruplet[VarManager::kVertexingLz], fValuesQuadruplet[VarManager::kVertexingLxy], fValuesQuadruplet[VarManager::kVertexingLxyz], fValuesQuadruplet[VarManager::kVertexingTauz], fValuesQuadruplet[VarManager::kVertexingTauxy], fValuesQuadruplet[VarManager::kVertexingLzErr], fValuesQuadruplet[VarManager::kVertexingLxyzErr], + fValuesQuadruplet[VarManager::kVertexingTauzErr], fValuesQuadruplet[VarManager::kVertexingLzProjected], fValuesQuadruplet[VarManager::kVertexingLxyProjected], fValuesQuadruplet[VarManager::kVertexingLxyzProjected], fValuesQuadruplet[VarManager::kVertexingTauzProjected], fValuesQuadruplet[VarManager::kVertexingTauxyProjected]); + } + } + } + + Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + Preslice dielectronsPerCollision = aod::reducedpair::reducedeventId; + Preslice ditracksPerCollision = aod::reducedpair::reducedeventId; + + void processJpsiPiPi(soa::Filtered const& events, + soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons) + { + 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 groupedDielectrons = dileptons.sliceBy(dielectronsPerCollision, event.globalIndex()); + runDileptonTrackTrack(event, groupedBarrelAssocs, tracks, groupedDielectrons); + } + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisDileptonTrackTrack, processJpsiPiPi, "Run barrel pairing of J/psi with pion candidate", false); + PROCESS_SWITCH(AnalysisDileptonTrackTrack, processDummy, "Dummy function", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) @@ -2560,7 +3999,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) @@ -2581,7 +4021,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); } @@ -2598,7 +4038,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")) { @@ -2623,7 +4063,11 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char } if (classStr.Contains("DileptonTrackME")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "mixedevent"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "dilepton-hadron-array-correlation"); + } + + if (classStr.Contains("DileptonTrackECME")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "energy-correlator"); } if (classStr.Contains("HadronsSelected")) { @@ -2637,5 +4081,9 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char if (classStr.Contains("DileptonHadronCorrelation")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); } + + if (classStr.Contains("Quadruplet")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-dihadron", histName); + } } // end loop over histogram classes } diff --git a/PWGDQ/Tasks/taskFwdTrackPid.cxx b/PWGDQ/Tasks/taskFwdTrackPid.cxx new file mode 100644 index 00000000000..cbe6e233630 --- /dev/null +++ b/PWGDQ/Tasks/taskFwdTrackPid.cxx @@ -0,0 +1,269 @@ +// 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 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..ef415259a02 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"}; @@ -93,50 +97,60 @@ struct taskJPsiHf { float deltaRap = -999; float deltaPhi = -999; - for (auto& dilepton : dileptons) { + for (auto const& 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) { + for (auto const& dmeson : dmesons) { ptDmeson = RecoDecay::pt(dmeson.px(), dmeson.py()); phiDmeson = RecoDecay::phi(dmeson.px(), dmeson.py()); - deltaPhi = RecoDecay::constrainAngle(phiDilepton - phiDmeson, -o2::constants::math::PIHalf); + float absDeltaPhiRaw = std::abs(phiDilepton - phiDmeson); + deltaPhi = (absDeltaPhiRaw < o2::constants::math::PI) ? absDeltaPhiRaw : o2::constants::math::TwoPI - absDeltaPhiRaw; auto ptBinDmesForBdt = findBin(binsPtDmesForBdt, ptDmeson); if (ptBinDmesForBdt == -1) { 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 cdb61eee77c..4a809dc9b86 100644 --- a/PWGDQ/Tasks/v0selector.cxx +++ b/PWGDQ/Tasks/v0selector.cxx @@ -17,39 +17,51 @@ // Comments, questions, complaints, suggestions? // Please write to: daiki.sekihata@cern.ch // -#include -#include -#include "Math/Vector4D.h" -#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 "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "DCAFitter/DCAFitterN.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGDQ/Core/VarManager.h" -#include "PWGDQ/Core/HistogramManager.h" -#include "PWGDQ/Core/HistogramsLibrary.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -using FullTracksExt = soa::Join;*/ +using FullTracksExt = soa::Join; @@ -69,6 +81,7 @@ struct v0selector { Configurable cutQTK0SHigh{"cutQTK0SHigh", 0.215, "cutQTK0SHigh"}; Configurable cutAPK0SLow{"cutAPK0SLow", 0.199, "cutAPK0SLow"}; Configurable cutAPK0SHigh{"cutAPK0SHigh", 0.8, "cutAPK0SHigh"}; + Configurable cutAPK0SHighTop{"cutAPK0SHighTop", 0.9, "cutAPK0SHighTop"}; // Lambda & A-Lambda cuts Configurable cutQTL{"cutQTL", 0.03, "cutQTL"}; Configurable cutAlphaLLow{"cutAlphaLLow", 0.35, "cutAlphaLLow"}; @@ -78,6 +91,24 @@ struct v0selector { Configurable cutAPL1{"cutAPL1", 0.107, "cutAPL1"}; Configurable cutAPL2{"cutAPL2", -0.69, "cutAPL2"}; Configurable cutAPL3{"cutAPL3", 0.5, "cutAPL3"}; + // Omega & A-Omega cuts + Configurable cutAPOmegaUp1{"cutAPOmegaUp1", 0.25, "cutAPOmegaUp1"}; + Configurable cutAPOmegaUp2{"cutAPOmegaUp2", 0.358, "cutAPOmegaUp2"}; + Configurable cutAPOmegaUp3{"cutAPOmegaUp3", 0.35, "cutAPOmegaUp3"}; + Configurable cutAPOmegaDown1{"cutAPOmegaDown1", 0.15, "cutAPOmegaDown1"}; + Configurable cutAPOmegaDown2{"cutAPOmegaDown2", 0.358, "cutAPOmegaDown2"}; + Configurable cutAPOmegaDown3{"cutAPOmegaDown3", 0.16, "cutAPOmegaDown3"}; + Configurable cutAlphaOmegaHigh{"cutAlphaOmegaHigh", 0.358, "cutAlphaOmegaHigh"}; + Configurable cutAlphaOmegaLow{"cutAlphaOmegaLow", 0., "cutAlphaOmegaLow"}; + Configurable cutQTOmegaLowOuterArc{"cutQTOmegaLowOuterArc", 0.14, "cutQTOmegaLowOuterArc"}; + Configurable cutMassOmegaHigh{"cutMassOmegaHigh", 1.677, "cutMassOmegaHigh"}; + Configurable cutMassOmegaLow{"cutMassOmegaLow", 1.667, "cutMassOmegaLow"}; + Configurable cutMassCascV0Low{"cutMassCascV0Low", 1.110, "cutMassCascV0Low"}; + Configurable cutMassCascV0High{"cutMassCascV0High", 1.120, "cutMassCascV0High"}; + + Configurable produceV0ID{"produceV0ID", false, "Produce additional V0ID table"}; + Configurable selectCascades{"selectCascades", false, "Select cascades in addition to v0s"}; + Configurable produceCascID{"produceCascID", false, "Produce additional CascID table"}; enum { // Reconstructed V0 kUndef = -1, @@ -85,10 +116,13 @@ struct v0selector { kK0S = 1, kLambda = 2, kAntiLambda = 3, - kOmega = 4 + kOmega = 4, + kAntiOmega = 5 }; Produces v0bits; + Produces v0mapID; + Produces cascmapID; // int checkV0(const array& ppos, const array& pneg) int checkV0(const float alpha, const float qt) @@ -112,31 +146,32 @@ struct v0selector { // const float cutAPL[3] = {0.107, -0.69, 0.5}; // parameters for curved QT cut if (qt < cutQTG) { - if ((TMath::Abs(alpha) < cutAlphaG)) { + if ((std::abs(alpha) < cutAlphaG)) { return kGamma; } } if (qt < cutQTG2) { // additional region - should help high pT gammas - if ((TMath::Abs(alpha) > cutAlphaGLow) && (TMath::Abs(alpha) < cutAlphaGHigh)) { + if ((std::abs(alpha) > cutAlphaGLow) && (std::abs(alpha) < cutAlphaGHigh)) { return kGamma; } } // Check for K0S candidates - float q = cutAPK0SLow * TMath::Sqrt(TMath::Abs(1 - alpha * alpha / (cutAPK0SHigh * cutAPK0SHigh))); - if ((qt > cutQTK0SLow) && (qt < cutQTK0SHigh) && (qt > q)) { + float q = cutAPK0SLow * std::sqrt(std::abs(1.0f - alpha * alpha / (cutAPK0SHigh * cutAPK0SHigh))); + float qtop = cutQTK0SHigh * std::sqrt(std::abs(1.0f - alpha * alpha / (cutAPK0SHighTop * cutAPK0SHighTop))); + if ((qt > cutQTK0SLow) && (qt < cutQTK0SHigh) && (qt > q) && (qt < qtop)) { return kK0S; } // Check for Lambda candidates - q = cutAPL1 * TMath::Sqrt(TMath::Abs(1 - ((alpha + cutAPL2) * (alpha + cutAPL2)) / (cutAPL3 * cutAPL3))); + q = cutAPL1 * std::sqrt(std::abs(1.0f - ((alpha + cutAPL2) * (alpha + cutAPL2)) / (cutAPL3 * cutAPL3))); if ((alpha > cutAlphaLLow) && (alpha < cutAlphaLHigh) && (qt > cutQTL) && (qt < q)) { return kLambda; } // Check for AntiLambda candidates - q = cutAPL1 * TMath::Sqrt(TMath::Abs(1 - ((alpha - cutAPL2) * (alpha - cutAPL2)) / (cutAPL3 * cutAPL3))); + q = cutAPL1 * std::sqrt(std::abs(1.0f - ((alpha - cutAPL2) * (alpha - cutAPL2)) / (cutAPL3 * cutAPL3))); if ((alpha > cutAlphaALLow) && (alpha < cutAlphaALHigh) && (qt > cutQTL) && (qt < q)) { return kAntiLambda; } @@ -144,6 +179,29 @@ struct v0selector { return kUndef; } + int checkCascade(float alpha, float qt) + { + const bool isAlphaPos = alpha > 0; + alpha = std::fabs(alpha); + + const float qUp = std::abs(alpha - cutAPOmegaUp2) > std::abs(cutAPOmegaUp3) ? 0. : cutAPOmegaUp1 * std::sqrt(1.0f - ((alpha - cutAPOmegaUp2) * (alpha - cutAPOmegaUp2)) / (cutAPOmegaUp3 * cutAPOmegaUp3)); + const float qDown = std::abs(alpha - cutAPOmegaDown2) > std::abs(cutAPOmegaDown3) ? 0. : cutAPOmegaDown1 * std::sqrt(1.0f - ((alpha - cutAPOmegaDown2) * (alpha - cutAPOmegaDown2)) / (cutAPOmegaDown3 * cutAPOmegaDown3)); + + if (alpha < cutAlphaOmegaLow || alpha > cutAlphaOmegaHigh || qt < qDown || qt > qUp) { + return kUndef; + } + + if (alpha > cutAPOmegaUp2 && qt < cutQTOmegaLowOuterArc) { + return kUndef; + } + + if (isAlphaPos) { + return kOmega; + } else { + return kAntiOmega; + } + } + // Configurables Configurable v0max_mee{"v0max_mee", 0.1, "max mee for photon"}; Configurable maxpsipair{"maxpsipair", 1.6, "max psi_pair for photon"}; @@ -156,12 +214,28 @@ 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"}; + // Cascade-related Configurables + Configurable cascDcaMax{"cascDcaMax", 0.3, "DCA cascade daughters"}; + Configurable cascV0DcaMax{"cascV0DcaMax", 0.3, "DCA V0 daughters of the cascade"}; + Configurable cascRadiusMin{"cascRadiusMin", 0.0, "Cascade Radius min"}; + Configurable cascRadiusMax{"cascRadiusMax", 90.0, "Cascade Radius max"}; + Configurable cascV0RadiusMin{"cascV0RadiusMin", 0.0, "V0 of the Cascade Radius min"}; + Configurable cascV0RadiusMax{"cascV0RadiusMax", 90.0, "V0 of the Cascade Radius max"}; + Configurable cascCosinePAMin{"cascCosinePAMin", 0.998, "Cascade CosPA min"}; + Configurable cascV0CosinePAMin{"cascV0CosinePAMin", 0.995, "V0 of the Cascade CosPA min"}; + Configurable cascV0CosinePAMax{"cascV0CosinePAMax", 1.000, "V0 of the Cascade CosPA max"}; + // cutNsigmaElTPC, cutNsigmaPiTPC, cutNsigmaPrTPC, cutNsigmaKaTPC + Configurable cutNsigmaElTPC{"cutNsigmaElTPC", 5.0, "cutNsigmaElTPC"}; + Configurable cutNsigmaPiTPC{"cutNsigmaPiTPC", 5.0, "cutNsigmaPiTPC"}; + Configurable cutNsigmaPrTPC{"cutNsigmaPrTPC", 5.0, "cutNsigmaPrTPC"}; + Configurable cutNsigmaKaTPC{"cutNsigmaKaTPC", 5.0, "cutNsigmaKaTPC"}; HistogramRegistry registry{"registry"}; void init(o2::framework::InitContext&) { if (fillhisto) { registry.add("hV0Candidate", "hV0Candidate", HistType::kTH1F, {{2, 0.5f, 2.5f}}); + registry.add("hCascCandidate", "hCascCandidate", HistType::kTH1F, {{2, 0.5f, 2.5f}}); 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}}); @@ -180,14 +254,56 @@ struct v0selector { registry.add("hDCAzNegToPV", "hDCAzNegToPV", HistType::kTH1F, {{1000, -5.0f, 5.0f}}); registry.add("hDCAV0Dau", "hDCAV0Dau", HistType::kTH1F, {{1000, 0.0f, 10.0f}}); registry.add("hV0APplot", "hV0APplot", HistType::kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}); + registry.add("hV0APplotSelected", "hV0APplotSelected", HistType::kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}); registry.add("hV0Psi", "hV0Psi", HistType::kTH2F, {{100, 0, TMath::PiOver2()}, {100, 0, 0.1}}); + if (selectCascades) { + registry.add("hCascPt", "pT", HistType::kTH1F, {{100, 0.0f, 10}}); + registry.add("hCascEtaPhi", "#eta vs. #varphi", HistType::kTH2F, {{63, 0, 6.3}, {20, -1.0f, 1.0f}}); + registry.add("hCascDCAxyPosToPV", "hCascDCAxyPosToPV", HistType::kTH1F, {{1000, -5.0f, 5.0f}}); + registry.add("hCascDCAxyNegToPV", "hCascDCAxyNegToPV", HistType::kTH1F, {{1000, -5.0f, 5.0f}}); + registry.add("hCascDCAxyBachToPV", "hCascDCAxyBachToPV", HistType::kTH1F, {{1000, -5.0f, 5.0f}}); + registry.add("hCascDCAzPosToPV", "hCascDCAzPosToPV", HistType::kTH1F, {{1000, -5.0f, 5.0f}}); + registry.add("hCascDCAzNegToPV", "hCascDCAzNegToPV", HistType::kTH1F, {{1000, -5.0f, 5.0f}}); + registry.add("hCascDCAzBachToPV", "hCascDCAzBachToPV", HistType::kTH1F, {{1000, -5.0f, 5.0f}}); + registry.add("hCascAPplot", "hCascAPplot", HistType::kTH2F, {{200, -1.0f, +1.0f}, {300, 0.0f, 0.3f}}); + registry.add("hCascV0APplot", "hCascV0APplot", HistType::kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}); + registry.add("hCascAPplotSelected", "hCascAPplotSelected", HistType::kTH2F, {{200, -1.0f, +1.0f}, {300, 0.0f, 0.3f}}); + registry.add("hCascV0APplotSelected", "hCascV0APplotSelected", HistType::kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}); + registry.add("hCascRadius", "hCascRadius", HistType::kTH1F, {{1000, 0.0f, 100.0f}}); + registry.add("hCascV0Radius", "hCascV0Radius", HistType::kTH1F, {{1000, 0.0f, 100.0f}}); + registry.add("hCascCosPA", "hCascCosPA", HistType::kTH1F, {{50, 0.95f, 1.0f}}); + registry.add("hCascV0CosPA", "hCascV0CosPA", HistType::kTH1F, {{50, 0.95f, 1.0f}}); + registry.add("hMassOmega", "hMassOmega", HistType::kTH2F, {{900, 0.0f, 90.0f}, {100, 1.62f, 1.72f}}); + registry.add("hMassAntiOmega", "hMassAntiOmega", HistType::kTH2F, {{900, 0.0f, 90.0f}, {100, 1.62f, 1.72f}}); + registry.add("hCascDCADau", "hCascDCADau", HistType::kTH1F, {{1000, 0.0f, 10.0f}}); + registry.add("hCascV0DCADau", "hCascV0DCADau", HistType::kTH1F, {{1000, 0.0f, 10.0f}}); + } + } + + if (selectCascades == false && produceCascID == true) { + LOGP(error, "produceCascID is available only when selectCascades is enabled"); + } + if (cutAPOmegaUp1 < cutAPOmegaDown1) { + LOGP(error, "cutAPOmegaUp1 must be greater than cutAPOmegaDown1"); } } - void process(aod::V0Datas const& V0s, FullTracksExt const& tracks, aod::Collisions const&) + void process(aod::V0Datas const& V0s, aod::CascDatas const& Cascs, FullTracksExt const& tracks, aod::Collisions const&) { - std::map pidmap; - + std::vector pidmap; + pidmap.clear(); + pidmap.resize(tracks.size(), 0); + + std::vector v0pidmap; + v0pidmap.clear(); + if (produceV0ID.value) { + v0pidmap.resize(V0s.size(), -1); + } + std::vector cascpidmap; + cascpidmap.clear(); + if (produceCascID.value) { + cascpidmap.resize(Cascs.size(), kUndef); + } for (auto& V0 : V0s) { // if (!(V0.posTrack_as().trackType() & o2::aod::track::TPCrefit)) { // continue; @@ -200,58 +316,22 @@ struct v0selector { if (fillhisto) { registry.fill(HIST("hV0Candidate"), 1); } - if (fabs(V0.posTrack_as().eta()) > 0.9) { - continue; - } - if (fabs(V0.negTrack_as().eta()) > 0.9) { - continue; - } - - if (V0.posTrack_as().tpcNClsCrossedRows() < mincrossedrows) { - continue; - } - if (V0.negTrack_as().tpcNClsCrossedRows() < mincrossedrows) { - continue; - } - if (V0.posTrack_as().tpcChi2NCl() > maxchi2tpc) { - continue; - } - if (V0.negTrack_as().tpcChi2NCl() > maxchi2tpc) { - continue; - } - - if (fabs(V0.posTrack_as().dcaXY()) < dcamin) { - continue; - } - if (fabs(V0.negTrack_as().dcaXY()) < dcamin) { - continue; - } + const auto& posTrack = V0.posTrack_as(); + const auto& negTrack = V0.negTrack_as(); - if (fabs(V0.posTrack_as().dcaXY()) > dcamax) { - continue; - } - if (fabs(V0.negTrack_as().dcaXY()) > dcamax) { - continue; + bool isRejectV0{false}; + for (const auto& prong : {posTrack, negTrack}) { + isRejectV0 = isRejectV0 || std::fabs(prong.eta()) > 0.9; + isRejectV0 = isRejectV0 || prong.tpcNClsCrossedRows() < mincrossedrows; + isRejectV0 = isRejectV0 || prong.tpcChi2NCl() > maxchi2tpc; + isRejectV0 = isRejectV0 || std::fabs(prong.dcaXY()) < dcamin; + isRejectV0 = isRejectV0 || std::fabs(prong.dcaXY()) > dcamax; } + isRejectV0 = isRejectV0 || (posTrack.sign() * negTrack.sign() > 0); - if (V0.posTrack_as().sign() * V0.negTrack_as().sign() > 0) { // reject same sign pair + if (isRejectV0) continue; - } - - // if (V0.posTrack_as().collisionId() != V0.negTrack_as().collisionId()) { - // continue; - // } - - // if (!V0.posTrack_as().has_collision() || !V0.negTrack_as().has_collision()) { - // continue; - // } - - // auto const& collision = V0.collision_as(); - - // if (V0.collisionId() != collision.globalIndex()) { - // continue; - // } float V0dca = V0.dcaV0daughters(); float V0CosinePA = V0.v0cosPA(); @@ -295,15 +375,24 @@ struct v0selector { // printf("This is not [Gamma/K0S/Lambda/AntiLambda] candidate.\n"); continue; } + if (fillhisto) { + registry.fill(HIST("hV0APplotSelected"), V0.alpha(), V0.qtarm()); + } + auto storeV0AddID = [&](auto gix, auto id) { + if (produceV0ID.value) { + v0pidmap[gix] = id; + } + }; if (v0id == kGamma) { // photon conversion if (fillhisto) { 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 && std::abs(V0.posTrack_as().tpcNSigmaEl()) < cutNsigmaElTPC && std::abs(V0.negTrack_as().tpcNSigmaEl()) < cutNsigmaElTPC && std::abs(psipair) < maxpsipair) { pidmap[V0.posTrackId()] |= (uint8_t(1) << kGamma); pidmap[V0.negTrackId()] |= (uint8_t(1) << kGamma); + storeV0AddID(V0.globalIndex(), kGamma); if (fillhisto) { registry.fill(HIST("hGammaRxy"), V0.x(), V0.y()); } @@ -315,33 +404,167 @@ struct v0selector { 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) && std::abs(V0.posTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC && std::abs(V0.negTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC) { pidmap[V0.posTrackId()] |= (uint8_t(1) << kK0S); pidmap[V0.negTrackId()] |= (uint8_t(1) << kK0S); + storeV0AddID(V0.globalIndex(), kK0S); } } else if (v0id == kLambda) { // L->p + pi- 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) && std::abs(V0.posTrack_as().tpcNSigmaPr()) < cutNsigmaPrTPC && std::abs(V0.negTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC) { pidmap[V0.posTrackId()] |= (uint8_t(1) << kLambda); pidmap[V0.negTrackId()] |= (uint8_t(1) << kLambda); + storeV0AddID(V0.globalIndex(), kLambda); } } else if (v0id == kAntiLambda) { // Lbar -> pbar + pi+ 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) && std::abs(V0.posTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC && std::abs(V0.negTrack_as().tpcNSigmaPr()) < cutNsigmaPrTPC) { pidmap[V0.posTrackId()] |= (uint8_t(1) << kAntiLambda); pidmap[V0.negTrackId()] |= (uint8_t(1) << kAntiLambda); + storeV0AddID(V0.globalIndex(), kAntiLambda); } } - // printf("posTrackId = %d\n",V0.posTrackId()); // printf("negTrackId = %d\n",V0.negTrackId()); } // end of V0 loop + if (produceV0ID.value) { + for (auto& V0 : V0s) { + v0mapID(v0pidmap[V0.globalIndex()]); + } + } + + if (selectCascades) { + for (const auto& casc : Cascs) { + if (fillhisto) { + registry.fill(HIST("hCascCandidate"), 1); + } + + const auto& posTrack = casc.posTrack_as(); + const auto& negTrack = casc.negTrack_as(); + const auto& bachelor = casc.bachelor_as(); + + bool isRejectCascade{false}; + for (const auto& prong : {posTrack, negTrack, bachelor}) { + isRejectCascade = isRejectCascade || std::fabs(prong.eta()) > 0.9; + isRejectCascade = isRejectCascade || prong.tpcNClsCrossedRows() < mincrossedrows; + isRejectCascade = isRejectCascade || prong.tpcChi2NCl() > maxchi2tpc; + isRejectCascade = isRejectCascade || std::fabs(prong.dcaXY()) < dcamin; + isRejectCascade = isRejectCascade || std::fabs(prong.dcaXY()) > dcamax; + } + isRejectCascade = isRejectCascade || (posTrack.sign() * negTrack.sign() > 0); + + if (isRejectCascade) + continue; + if (fillhisto) { + registry.fill(HIST("hCascCandidate"), 2); + } + + auto collision = casc.collision_as(); + const float collisionX = collision.posX(); + const float collisionY = collision.posY(); + const float collisionZ = collision.posZ(); + + const float cascDca = casc.dcacascdaughters(); // NOTE the name of getter is misleading. In case of no-KF this is sqrt(Chi2) + const float cascV0Dca = casc.dcaV0daughters(); // NOTE the name of getter is misleading. In case of kfDoDCAFitterPreMinimV0 this is sqrt(Chi2) + const float cascRadius = casc.cascradius(); + const float cascV0Radius = casc.dcaV0daughters(); + const float cascCosinePA = casc.casccosPA(collisionX, collisionY, collisionZ); + const float cascV0CosinePA = casc.v0cosPA(collisionX, collisionY, collisionZ); + + if (cascDca > cascDcaMax) { + continue; + } + if (cascV0Dca > cascV0DcaMax) { + continue; + } + if (cascRadius < cascRadiusMin || cascRadius > cascRadiusMax) { + continue; + } + if (cascV0Radius < cascV0RadiusMin || cascV0Radius > cascV0RadiusMax) { + continue; + } + if (cascCosinePA < cascCosinePAMin) { + continue; + } + if (cascV0CosinePA < cascV0CosinePAMin || cascV0CosinePA > cascV0CosinePAMax) { + continue; + } + + const float mOmega = casc.mOmega(); + const float mV0Lambda = casc.mLambda(); + const float alpha = casc.alpha(); + const float qt = casc.qtarm(); + const float v0Alpha = casc.v0Alpha(); + const float v0Qt = casc.v0Qtarm(); + + if (fillhisto) { + registry.fill(HIST("hCascPt"), casc.pt()); + registry.fill(HIST("hCascEtaPhi"), casc.phi(), casc.eta()); + registry.fill(HIST("hCascDCAxyPosToPV"), casc.posTrack_as().dcaXY()); + registry.fill(HIST("hCascDCAxyNegToPV"), casc.negTrack_as().dcaXY()); + registry.fill(HIST("hCascDCAxyBachToPV"), casc.bachelor_as().dcaXY()); + registry.fill(HIST("hCascDCAzPosToPV"), casc.posTrack_as().dcaZ()); + registry.fill(HIST("hCascDCAzNegToPV"), casc.negTrack_as().dcaZ()); + registry.fill(HIST("hCascDCAzBachToPV"), casc.bachelor_as().dcaZ()); + registry.fill(HIST("hCascAPplot"), alpha, qt); + registry.fill(HIST("hCascV0APplot"), v0Alpha, v0Qt); + registry.fill(HIST("hCascRadius"), cascRadius); + registry.fill(HIST("hCascV0Radius"), cascV0Radius); + registry.fill(HIST("hCascCosPA"), cascCosinePA); + registry.fill(HIST("hCascV0CosPA"), cascV0CosinePA); + registry.fill(HIST("hCascDCADau"), cascDca); + registry.fill(HIST("hCascV0DCADau"), cascV0Dca); + } + + const int cascid = checkCascade(alpha, qt); + const int v0id = checkV0(v0Alpha, v0Qt); + if (cascid < 0) { + continue; + } + if (v0id != kLambda && v0id != kAntiLambda) { + continue; + } + if (fillhisto) { + registry.fill(HIST("hCascAPplotSelected"), alpha, qt); + registry.fill(HIST("hCascV0APplotSelected"), v0Alpha, v0Qt); + } + + auto storeCascAddID = [&](auto gix, auto id) { + if (produceCascID.value) { + cascpidmap[gix] = id; + } + }; + + if (cascid == kOmega && v0id == kLambda) { + if (fillhisto) { + registry.fill(HIST("hMassOmega"), cascRadius, mOmega); + } + if (cutMassOmegaLow < mOmega && mOmega < cutMassOmegaHigh && cutMassCascV0Low < mV0Lambda && mV0Lambda < cutMassCascV0High && std::abs(casc.posTrack_as().tpcNSigmaPr()) < cutNsigmaPrTPC && std::abs(casc.negTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC && std::abs(casc.bachelor_as().tpcNSigmaKa()) < cutNsigmaKaTPC) { + pidmap[casc.bachelorId()] |= (uint8_t(1) << kOmega); + storeCascAddID(casc.globalIndex(), kOmega); + } + } else if (cascid == kAntiOmega && v0id == kAntiLambda) { + if (fillhisto) { + registry.fill(HIST("hMassAntiOmega"), cascRadius, mOmega); + } + if (cutMassOmegaLow < mOmega && mOmega < cutMassOmegaHigh && cutMassCascV0Low < mV0Lambda && mV0Lambda < cutMassCascV0High && std::abs(casc.posTrack_as().tpcNSigmaPi()) < cutNsigmaPiTPC && std::abs(casc.negTrack_as().tpcNSigmaPr()) < cutNsigmaPrTPC && std::abs(casc.bachelor_as().tpcNSigmaKa()) < cutNsigmaKaTPC) { + pidmap[casc.bachelorId()] |= (uint8_t(1) << kAntiOmega); + storeCascAddID(casc.globalIndex(), kAntiOmega); + } + } + } // end of Casc loop + if (produceCascID.value) { + for (auto& casc : Cascs) { + cascmapID(cascpidmap[casc.globalIndex()]); + } + } + } for (auto& track : tracks) { // printf("setting pidmap[%lld] = %d\n",track.globalIndex(),pidmap[track.globalIndex()]); v0bits(pidmap[track.globalIndex()]); @@ -446,15 +669,15 @@ struct trackPIDQA { continue; } - if (fabs(track.dcaXY()) < dcamin) { + if (std::fabs(track.dcaXY()) < dcamin) { continue; } - if (fabs(track.dcaXY()) > dcamax) { + if (std::fabs(track.dcaXY()) > dcamax) { continue; } - if (fabs(track.eta()) > 0.9) { + if (std::fabs(track.eta()) > 0.9) { continue; } @@ -540,7 +763,7 @@ struct trackPIDQA { } } // end of track loop - } // end of process + } // end of process void DefineHistograms(TString histClasses) { diff --git a/PWGEM/CMakeLists.txt b/PWGEM/CMakeLists.txt index 2b881e0ca4a..0fcbe0741a3 100644 --- a/PWGEM/CMakeLists.txt +++ b/PWGEM/CMakeLists.txt @@ -13,4 +13,3 @@ add_subdirectory(Dilepton) add_subdirectory(PhotonMeson) add_subdirectory(Tasks) - diff --git a/PWGEM/Dilepton/Core/CMakeLists.txt b/PWGEM/Dilepton/Core/CMakeLists.txt index 92d06924294..97501004c4a 100644 --- a/PWGEM/Dilepton/Core/CMakeLists.txt +++ b/PWGEM/Dilepton/Core/CMakeLists.txt @@ -13,10 +13,12 @@ o2physics_add_library(PWGEMDileptonCore SOURCES EMEventCut.cxx DielectronCut.cxx DimuonCut.cxx + EMTrackCut.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore) o2physics_target_root_dictionary(PWGEMDileptonCore HEADERS EMEventCut.h DielectronCut.h DimuonCut.h + EMTrackCut.h LINKDEF PWGEMDileptonCoreLinkDef.h) diff --git a/PWGEM/Dilepton/Core/DielectronCut.cxx b/PWGEM/Dilepton/Core/DielectronCut.cxx index da10ac6f928..b5ecd733985 100644 --- a/PWGEM/Dilepton/Core/DielectronCut.cxx +++ b/PWGEM/Dilepton/Core/DielectronCut.cxx @@ -10,15 +10,17 @@ // or submit itself to any jurisdiction. // -// Class for dilepton Cut +// Class for dielectron Cut // -#include "Framework/Logger.h" #include "PWGEM/Dilepton/Core/DielectronCut.h" -ClassImp(DielectronCut); +#include "Framework/Logger.h" + +#include +#include -const char* DielectronCut::mCutNames[static_cast(DielectronCut::DielectronCuts::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"}; +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. @@ -33,7 +35,7 @@ void DielectronCut::SetPairYRange(float minY, float maxY) { mMinPairY = minY; mMaxPairY = maxY; - LOG(info) << "Dielectron Cut, set pair eta range: " << mMinPairY << " - " << mMaxPairY; + LOG(info) << "Dielectron Cut, set pair y range: " << mMinPairY << " - " << mMaxPairY; } void DielectronCut::SetPairDCARange(float min, float max) { @@ -47,16 +49,37 @@ void DielectronCut::SetMeeRange(float min, float max) mMaxMee = max; LOG(info) << "Dielectron Cut, set mee range: " << mMinMee << " - " << mMaxMee; } -void DielectronCut::SetMaxPhivPairMeeDep(std::function meeDepCut) +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) { - mMaxPhivPairMeeDep = meeDepCut; - LOG(info) << "Dielectron Cut, set max phiv pair mee dep: " << mMaxPhivPairMeeDep(0.02); + 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 flag1, bool flag2, float min_deta, float min_dphi) +{ + mApplydEtadPhi = flag1; + mApplydEtadPhiPosition = flag2; + mMinDeltaEta = min_deta; + mMinDeltaPhi = min_dphi; + LOG(info) << "Dielectron Cut, set apply deta-dphi cut: " << mApplydEtadPhi << " apply deta-dphi* cut: " << mApplydEtadPhiPosition << " 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; @@ -69,6 +92,24 @@ void DielectronCut::SetTrackEtaRange(float minEta, float maxEta) mMaxTrackEta = maxEta; LOG(info) << "Dielectron Cut, set track eta range: " << mMinTrackEta << " - " << mMaxTrackEta; } +void DielectronCut::SetTrackPhiRange(float minPhi, float maxPhi, bool mirror, bool reject) +{ + mMinTrackPhi = minPhi; + mMaxTrackPhi = maxPhi; + mMirrorTrackPhi = mirror; + mRejectTrackPhi = reject; + LOG(info) << "Dielectron Cut, set track phi range (rad.): " << mMinTrackPhi << " - " << mMaxTrackPhi << " with mirror: " << mMirrorTrackPhi << " and rejection: " << mRejectTrackPhi; +} +void DielectronCut::SetTrackPhiPositionRange(float minPhi, float maxPhi, float refR, float bz, bool mirror) +{ + mMinTrackPhiPosition = minPhi; + mMaxTrackPhiPosition = maxPhi; + mRefR = refR; + mBz = bz; + mMirrorTrackPhi = mirror; + LOG(info) << "Dielectron Cut, set track phi position range (rad.): " << mMinTrackPhiPosition << " - " << mMaxTrackPhiPosition << " at Rxy = " << mRefR << " with mirror: " << mMirrorTrackPhi; + LOG(info) << "Dielectron Cut, set Bz in kG: " << mBz; +} void DielectronCut::SetMinNClustersTPC(int minNClustersTPC) { mMinNClustersTPC = minNClustersTPC; @@ -84,6 +125,17 @@ void DielectronCut::SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedR 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; @@ -103,30 +155,39 @@ void DielectronCut::SetChi2PerClusterITS(float min, float max) mMaxChi2PerClusterITS = max; LOG(info) << "Dielectron Cut, set chi2 per cluster ITS range: " << mMinChi2PerClusterITS << " - " << mMaxChi2PerClusterITS; } -void DielectronCut::SetMeanClusterSizeITSob(float min, float max) +void DielectronCut::SetMeanClusterSizeITS(float min, float max) { mMinMeanClusterSizeITS = min; mMaxMeanClusterSizeITS = max; + // mMinP_ITSClusterSize = minP; + // mMaxP_ITSClusterSize = maxP; LOG(info) << "Dielectron Cut, set mean cluster size ITS range: " << mMinMeanClusterSizeITS << " - " << mMaxMeanClusterSizeITS; } -void DielectronCut::SetDca3DRange(float min, float max) +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::SetMaxDcaXY(float maxDcaXY) +void DielectronCut::SetTrackMaxDcaXY(float maxDcaXY) { mMaxDcaXY = maxDcaXY; LOG(info) << "Dielectron Cut, set max DCA xy: " << mMaxDcaXY; } -void DielectronCut::SetMaxDcaZ(float maxDcaZ) +void DielectronCut::SetTrackMaxDcaZ(float maxDcaZ) { mMaxDcaZ = maxDcaZ; LOG(info) << "Dielectron Cut, set max DCA z: " << mMaxDcaZ; } -void DielectronCut::SetMaxDcaXYPtDep(std::function ptDepCut) +void DielectronCut::SetTrackMaxDcaXYPtDep(std::function ptDepCut) { mMaxDcaXYPtDep = ptDepCut; LOG(info) << "Dielectron Cut, set max DCA xy pt dep: " << mMaxDcaXYPtDep(1.0); @@ -159,12 +220,11 @@ void DielectronCut::SetMuonExclusionTPC(bool flag) LOG(info) << "Dielectron Cut, set flag for muon exclusion in TPC: " << mMuonExclusionTPC; } -void DielectronCut::SetTOFbetaRange(bool flag, float min, float max) +void DielectronCut::SetTOFbetaRange(float min, float max) { - mApplyTOFbeta = flag; mMinTOFbeta = min; mMaxTOFbeta = max; - LOG(info) << "Dielectron Cut, set TOF beta rejection range: " << mMinTOFbeta << " - " << mMaxTOFbeta; + LOG(info) << "Dielectron Cut, set TOF beta range (TOFif): " << mMinTOFbeta << " - " << mMaxTOFbeta; } void DielectronCut::SetTPCNsigmaElRange(float min, float max) @@ -173,12 +233,12 @@ void DielectronCut::SetTPCNsigmaElRange(float min, float max) 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::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; @@ -204,12 +264,12 @@ void DielectronCut::SetTOFNsigmaElRange(float min, float max) 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::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; @@ -228,10 +288,57 @@ void DielectronCut::SetTOFNsigmaPrRange(float min, float max) mMaxTOFNsigmaPr = max; LOG(info) << "Dielectron Cut, set TOF n sigma Pr range: " << mMinTOFNsigmaPr << " - " << mMaxTOFNsigmaPr; } -void DielectronCut::SetMaxPinMuonTPConly(float max) + +// 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::SetPinRangeForPionRejectionTPC(float min, float max) { - mMaxPinMuonTPConly = max; - LOG(info) << "Dielectron Cut, set max pin for Muon ID with TPC only: " << mMaxPinMuonTPConly; + mMinPinForPionRejectionTPC = min; + mMaxPinForPionRejectionTPC = max; + LOG(info) << "Dielectron Cut, set pin range for pion rejection in TPC: " << mMinPinForPionRejectionTPC << " - " << mMaxPinForPionRejectionTPC; } void DielectronCut::RequireITSibAny(bool flag) { @@ -243,38 +350,9 @@ void DielectronCut::RequireITSib1st(bool flag) mRequireITSib1st = flag; LOG(info) << "Dielectron Cut, require ITS ib 1st: " << mRequireITSib1st; } - -void DielectronCut::print() const -{ - LOG(info) << "Dalitz EE Cut:"; - for (int i = 0; i < static_cast(DielectronCuts::kNCuts); i++) { - switch (static_cast(i)) { - case DielectronCuts::kTrackPtRange: - LOG(info) << mCutNames[i] << " in [" << mMinTrackPt << ", " << mMaxTrackPt << "]"; - break; - case DielectronCuts::kTrackEtaRange: - LOG(info) << mCutNames[i] << " in [" << mMinTrackEta << ", " << mMaxTrackEta << "]"; - break; - case DielectronCuts::kTPCNCls: - LOG(info) << mCutNames[i] << " > " << mMinNClustersTPC; - break; - case DielectronCuts::kTPCCrossedRows: - LOG(info) << mCutNames[i] << " > " << mMinNCrossedRowsTPC; - break; - case DielectronCuts::kTPCCrossedRowsOverNCls: - LOG(info) << mCutNames[i] << " > " << mMinNCrossedRowsOverFindableClustersTPC; - break; - case DielectronCuts::kTPCChi2NDF: - LOG(info) << mCutNames[i] << " < " << mMaxChi2PerClusterTPC; - break; - case DielectronCuts::kDCAxy: - LOG(info) << mCutNames[i] << " < " << mMaxDcaXY; - break; - case DielectronCuts::kDCAz: - LOG(info) << mCutNames[i] << " < " << mMaxDcaZ; - break; - default: - LOG(fatal) << "Cut unknown!"; - } - } +void DielectronCut::IncludeITSsa(bool flag, float max) +{ + mIncludeITSsa = flag; + mMaxPtITSsa = max; + LOG(info) << "Dielectron Cut, include ITSsa tracks: " << mIncludeITSsa << ", mMaxPtITSsa = " << mMaxPtITSsa; } diff --git a/PWGEM/Dilepton/Core/DielectronCut.h b/PWGEM/Dilepton/Core/DielectronCut.h index ef5e47fbe60..64bdd069f18 100644 --- a/PWGEM/Dilepton/Core/DielectronCut.h +++ b/PWGEM/Dilepton/Core/DielectronCut.h @@ -16,24 +16,25 @@ #ifndef PWGEM_DILEPTON_CORE_DIELECTRONCUT_H_ #define PWGEM_DILEPTON_CORE_DIELECTRONCUT_H_ +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/DataTypes.h" +#include "Framework/Logger.h" + +#include "Math/Vector4D.h" +#include "TNamed.h" + #include #include -#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 "CommonConstants/PhysicsConstants.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" -#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include +#include using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; +using namespace o2::aod::pwgem::dilepton::utils::pairutil; class DielectronCut : public TNamed { @@ -52,39 +53,34 @@ class DielectronCut : public TNamed // track cut kTrackPtRange, kTrackEtaRange, + kTrackPhiRange, + kTrackPhiPositionRange, kTPCNCls, kTPCCrossedRows, kTPCCrossedRowsOverNCls, + kTPCFracSharedClusters, + kRelDiffPin, kTPCChi2NDF, - kTPCNsigmaEl, - kTPCNsigmaMu, - kTPCNsigmaPi, - kTPCNsigmaKa, - kTPCNsigmaPr, - kTOFNsigmaEl, - kTOFNsigmaMu, - kTOFNsigmaPi, - kTOFNsigmaKa, - kTOFNsigmaPr, kDCA3Dsigma, kDCAxy, kDCAz, kITSNCls, kITSChi2NDF, - kITSCluserSize, + kITSClusterSize, kPrefilter, kNCuts }; - static const char* mCutNames[static_cast(DielectronCuts::kNCuts)]; enum class PIDSchemes : int { - kUnDef = -1, + kNoPID = -1, kTOFreq = 0, kTPChadrej = 1, kTPChadrejORTOFreq = 2, kTPConly = 3, kTOFif = 4, - kPIDML = 5 + kPIDML = 5, + kTPChadrejORTOFreq_woTOFif = 6, + kTPChadrejORTOFreqLowB = 7, }; template @@ -105,46 +101,92 @@ class DielectronCut : public TNamed return true; } - template - bool IsSelectedPair(TTrack1 const& t1, TTrack2 const& t2, const float bz) const + template + bool IsSelectedPair(TTrack1 const& t1, TTrack2 const& t2, const float bz, const float refR) 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_t1_3d = dca3DinSigma(t1); - float dca_t2_3d = dca3DinSigma(t2); - float dca_ee_3d = std::sqrt((dca_t1_3d * dca_t1_3d + dca_t2_3d * dca_t2_3d) / 2.); - 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); + 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 (v12.Rapidity() < mMinPairY || mMaxPairY < v12.Rapidity()) { + if (v12.Pt() < mMinPairPt || mMaxPairPt < v12.Pt()) { return false; } - if (mApplyPhiV && ((phiv < mMinPhivPair || (mMaxPhivPairMeeDep ? mMaxPhivPairMeeDep(v12.M()) : mMaxPhivPair) < phiv) ^ mSelectPC)) { + 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; + } + + if (mApplydEtadPhi && mApplydEtadPhiPosition) { // applying both cuts is not allowed. + 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; + } + + float phiPosition1 = t1.phi() + std::asin(t1.sign() * 0.30282 * (bz * 0.1) * refR / (2.f * t1.pt())); + float phiPosition2 = t2.phi() + std::asin(t2.sign() * 0.30282 * (bz * 0.1) * refR / (2.f * t2.pt())); + + phiPosition1 = RecoDecay::constrainAngle(phiPosition1, 0, 1); // 0-2pi + phiPosition2 = RecoDecay::constrainAngle(phiPosition2, 0, 1); // 0-2pi + float dphiPosition = phiPosition1 - phiPosition2; + o2::math_utils::bringToPMPi(dphiPosition); + if (mApplydEtadPhiPosition && std::pow(deta / mMinDeltaEta, 2) + std::pow(dphiPosition / mMinDeltaPhi, 2) < 1.f) { + return false; + } + return true; } - template - bool IsSelectedTrack(TTrack const& track, TCollision const& collision = 0) const + template + bool IsSelectedTrack(TTrack const& track) const { - if (!track.hasITS() || !track.hasTPC()) { // track has to be ITS-TPC matched track + if (!track.hasITS()) { return false; } - if (!IsSelectedTrack(track, DielectronCuts::kTrackPtRange)) { + 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::kTrackEtaRange)) { + if (!IsSelectedTrack(track, DielectronCuts::kTrackPhiPositionRange)) { return false; } if (!IsSelectedTrack(track, DielectronCuts::kDCA3Dsigma)) { @@ -164,7 +206,8 @@ class DielectronCut : public TNamed if (!IsSelectedTrack(track, DielectronCuts::kITSChi2NDF)) { return false; } - if (!IsSelectedTrack(track, DielectronCuts::kITSCluserSize)) { + + if (!IsSelectedTrack(track, DielectronCuts::kITSClusterSize)) { return false; } @@ -182,58 +225,65 @@ class DielectronCut : public TNamed } } - // TPC cuts - if (!IsSelectedTrack(track, DielectronCuts::kTPCNCls)) { - return false; - } - if (!IsSelectedTrack(track, DielectronCuts::kTPCCrossedRows)) { - return false; - } - if (!IsSelectedTrack(track, DielectronCuts::kTPCCrossedRowsOverNCls)) { + if (!mIncludeITSsa && (!track.hasITS() || !track.hasTPC())) { // track has to be ITS-TPC matched track return false; } - if (!IsSelectedTrack(track, DielectronCuts::kTPCChi2NDF)) { + + if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && track.pt() > mMaxPtITSsa) { // ITSsa return false; } - if (mApplyPF && !IsSelectedTrack(track, DielectronCuts::kPrefilter)) { - return false; + // TPC cuts + if (track.hasTPC()) { + 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 (mApplyTOFbeta && (mMinTOFbeta < track.beta() && track.beta() < mMaxTOFbeta)) { + 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; - } + if (!PassPID(track)) { + return false; } return true; } - template - bool PassPIDML(TTrack const& track, TCollision const& collision) const + template + bool PassPIDML(TTrack const& track) const { - std::vector inputFeatures{static_cast(collision.numContrib()), track.p(), track.tgl(), - track.tpcNSigmaEl(), /*track.tpcNSigmaMu(),*/ track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), - track.tofNSigmaEl(), /*track.tofNSigmaMu(),*/ track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))}; - - // calculate classifier - float prob_ele = mPIDModel->evalModel(inputFeatures)[0]; - // LOGF(info, "prob_ele = %f", prob_ele); - if (prob_ele < 0.95) { + bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; + bool is_el_included_TOF = track.hasTOF() ? (mMinTOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < mMaxTOFNsigmaEl) : true; + if (!is_el_included_TPC || !is_el_included_TOF) { // outside of trained range return false; - } else { - return true; } + + int pbin = lower_bound(mMLBins.begin(), mMLBins.end(), track.tpcInnerParam()) - mMLBins.begin() - 1; + if (pbin < 0) { + pbin = 0; + } else if (static_cast(mMLBins.size()) - 2 < pbin) { + pbin = static_cast(mMLBins.size()) - 2; + } + // LOGF(info, "track.tpcInnerParam() = %f, pbin = %d, track.probElBDT() = %f, mMLCuts[pbin] = %f", track.tpcInnerParam(), pbin, track.probElBDT(), mMLCuts[pbin]); + return track.probElBDT() > mMLCuts[pbin]; } template @@ -249,6 +299,9 @@ class DielectronCut : public TNamed case static_cast(PIDSchemes::kTPChadrejORTOFreq): return PassTPChadrej(track) || PassTOFreq(track); + case static_cast(PIDSchemes::kTPChadrejORTOFreqLowB): + return PassTPChadrej(track) || PassTOFreqLowB(track); + case static_cast(PIDSchemes::kTPConly): return PassTPConly(track); @@ -256,9 +309,12 @@ class DielectronCut : public TNamed return PassTOFif(track); case static_cast(PIDSchemes::kPIDML): - return true; // don't use kPIDML here. + return PassPIDML(track); + + case static_cast(PIDSchemes::kTPChadrejORTOFreq_woTOFif): + return PassTPConlyhadrej(track) || PassTOFreq(track); - case static_cast(PIDSchemes::kUnDef): + case static_cast(PIDSchemes::kNoPID): return true; default: @@ -266,12 +322,25 @@ class DielectronCut : public TNamed } } + template + bool PassTOFreqLowB(T const& track) const + { + bool is_el_included_TPC = mMinTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; + bool is_pi_excluded_TPC = (track.tpcInnerParam() > mMinPinForPionRejectionTPC && 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; + } + 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; + 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; } @@ -279,27 +348,46 @@ class DielectronCut : public TNamed 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_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(); - return is_el_included_TPC && is_mu_excluded_TPC && is_pi_excluded_TPC && is_ka_excluded_TPC && is_pr_excluded_TPC; + bool is_el_included_TOF = track.hasTOF() ? (mMinTOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < mMaxTOFNsigmaEl) : 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_ka_excluded_TPC && is_pr_excluded_TPC && is_el_included_TOF; } template bool PassTPConly(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(); - return is_el_included_TPC && is_pi_excluded_TPC; + // 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; + } + + 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_pi_excluded_TPC && is_ka_excluded_TPC && is_pr_excluded_TPC; } template bool PassTOFif(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_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) : 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; } @@ -308,10 +396,44 @@ class DielectronCut : public TNamed { switch (cut) { case DielectronCuts::kTrackPtRange: - return track.pt() >= mMinTrackPt && track.pt() <= mMaxTrackPt; + return track.pt() > mMinTrackPt && track.pt() < mMaxTrackPt; case DielectronCuts::kTrackEtaRange: - return track.eta() >= mMinTrackEta && track.eta() <= mMaxTrackEta; + return track.eta() > mMinTrackEta && track.eta() < mMaxTrackEta; + + case DielectronCuts::kTrackPhiRange: + if (!mMirrorTrackPhi) { + bool is_in_phi_range = track.phi() > mMinTrackPhi && track.phi() < mMaxTrackPhi; + return mRejectTrackPhi ? !is_in_phi_range : is_in_phi_range; + } else { + float minTrackPhiMirror = mMinTrackPhi + M_PI; + float maxTrackPhiMirror = mMaxTrackPhi + M_PI; + bool is_in_phi_range = (track.phi() > mMinTrackPhi && track.phi() < mMaxTrackPhi) || (track.phi() > minTrackPhiMirror && track.phi() < maxTrackPhiMirror); + return mRejectTrackPhi ? !is_in_phi_range : is_in_phi_range; + } + + case DielectronCuts::kTrackPhiPositionRange: { + float phiPosition = track.phi() + std::asin(-0.30282 * track.sign() * (mBz * 0.1) * mRefR / (2.f * track.pt())); + + if (mMinTrackPhiPosition < 0.f && mMaxTrackPhiPosition < M_PI) { // threshold across 0 rad. + o2::math_utils::bringToPMPi(phiPosition); + bool isInAcc = mMinTrackPhiPosition < phiPosition && phiPosition < mMaxTrackPhiPosition; + bool isInAccMirrored = false; + if (mMirrorTrackPhi) { + o2::math_utils::bringTo02Pi(phiPosition); + isInAccMirrored = mMinTrackPhiPosition + M_PI < phiPosition && phiPosition < mMaxTrackPhiPosition + M_PI; + } + return isInAcc || isInAccMirrored; + } else { + o2::math_utils::bringTo02Pi(phiPosition); + bool isInAcc = mMinTrackPhiPosition < phiPosition && phiPosition < mMaxTrackPhiPosition; + bool isInAccMirrored = false; + if (mMirrorTrackPhi) { + isInAccMirrored = mMinTrackPhiPosition + M_PI < phiPosition && phiPosition < mMaxTrackPhiPosition + M_PI; + } + return isInAcc || isInAccMirrored; + } + } case DielectronCuts::kTPCNCls: return track.tpcNClsFound() >= mMinNClustersTPC; @@ -320,19 +442,25 @@ class DielectronCut : public TNamed return track.tpcNClsCrossedRows() >= mMinNCrossedRowsTPC; case DielectronCuts::kTPCCrossedRowsOverNCls: - return track.tpcCrossedRowsOverFindableCls() >= mMinNCrossedRowsOverFindableClustersTPC; + return track.tpcCrossedRowsOverFindableCls() > mMinNCrossedRowsOverFindableClustersTPC; + + case DielectronCuts::kTPCFracSharedClusters: + return track.tpcFractionSharedCls() < mMaxFracSharedClustersTPC; + + case DielectronCuts::kRelDiffPin: + return mMinRelDiffPin < (track.p() - track.tpcInnerParam()) / track.tpcInnerParam() && (track.p() - track.tpcInnerParam()) / track.tpcInnerParam() < 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 + return mMinDca3D < dca3DinSigma(track) && dca3DinSigma(track) < mMaxDca3D; // in sigma for single leg case DielectronCuts::kDCAxy: - return abs(track.dcaXY()) <= ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); + return std::fabs(track.dcaXY()) < ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); case DielectronCuts::kDCAz: - return abs(track.dcaZ()) <= mMaxDcaZ; + return std::fabs(track.dcaZ()) < mMaxDcaZ; case DielectronCuts::kITSNCls: return mMinNClustersITS <= track.itsNCls() && track.itsNCls() <= mMaxNClustersITS; @@ -340,8 +468,8 @@ class DielectronCut : public TNamed case DielectronCuts::kITSChi2NDF: return mMinChi2PerClusterITS < track.itsChi2NCl() && track.itsChi2NCl() < mMaxChi2PerClusterITS; - case DielectronCuts::kITSCluserSize: - return mMinMeanClusterSizeITS < track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl())) && track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl())) < mMaxMeanClusterSizeITS; + case DielectronCuts::kITSClusterSize: + return mMinMeanClusterSizeITS < track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) && track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) < mMaxMeanClusterSizeITS; case DielectronCuts::kPrefilter: return track.pfb() <= 0; @@ -356,55 +484,82 @@ class DielectronCut : public TNamed 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 SetMaxPhivPairMeeDep(std::function meeDepCut); + 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 applydEtadPhi, bool applydEtadPhiPosition, 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, bool mirror = false, bool reject = false); + void SetTrackPhiPositionRange(float minPhi, float maxPhi, float refR, float bz, bool mirror); 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 SetMeanClusterSizeITSob(float min, float max); + void SetMeanClusterSizeITS(float min, float max); + void SetChi2TOF(float min, float max); void SetPIDScheme(int 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 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 SetPinRangeForPionRejectionTPC(float min, float max); void RequireITSibAny(bool flag); void RequireITSib1st(bool flag); - void SetDca3DRange(float min, float max); // in sigma - void SetMaxDcaXY(float maxDcaXY); // in cm - void SetMaxDcaZ(float maxDcaZ); // in cm - void SetMaxDcaXYPtDep(std::function ptDepCut); + 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 IncludeITSsa(bool flag, float maxpt); - void SetPIDModel(o2::ml::OnnxModel* model) + void SetPIDMlResponse(o2::analysis::MlResponseDielectronSingleTrack* mlResponse) { - mPIDModel = model; + mPIDMlResponse = mlResponse; + } + + void SetMLThresholds(const std::vector bins, const std::vector cuts) + { + if (bins.size() != cuts.size() + 1) { + LOG(fatal) << "cuts.size() + 1 mutst be exactly the same as bins.size(). Check your bins and thresholds."; + } + mMLBins = bins; + mMLCuts = cuts; + // for (int i = 0; i < static_cast(mMLBins.size()) - 1; i++) { + // printf("Dielectron cut: mMLBins[%d] = %3.2f, mMLBins[%d] = %3.2f, mMLCuts[%d] = %3.2f\n", i, mMLBins[i], i + 1, mMLBins[i + 1], i, mMLCuts[i]); + // } } // 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; @@ -414,23 +569,37 @@ class DielectronCut : public TNamed 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 mMaxPhivPairMeeDep{}; // max phiv as a function of mee - bool mSelectPC{false}; // flag to select photon conversion used in mMaxPhivPairMeeDep + 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 + bool mApplydEtadPhiPosition{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 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 + float mMinTrackPhiPosition{0.f}, mMaxTrackPhiPosition{2.f * M_PI}; // range in phi + bool mMirrorTrackPhi{false}, mRejectTrackPhi{false}; // phi cut mirror by Pi, rejected/accepted + float mRefR{0.5}; // reference radius in m + float mBz{0.0}; // solenoid magnetic field along Z in kG // 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 - 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 + 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 mMinPinForPionRejectionTPC{0.f}, mMaxPinForPionRejectionTPC{1e10f}; // pin range 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 @@ -439,26 +608,39 @@ class DielectronCut : public TNamed 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 mMinMeanClusterSizeITS{0.0}, mMaxMeanClusterSizeITS{1e10f}; // x cos(lmabda) + // float mMinP_ITSClusterSize{0.0}, mMaxP_ITSClusterSize{0.0}; + bool mIncludeITSsa{false}; + float mMaxPtITSsa{0.15}; // 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 - bool mApplyTOFbeta{false}; // flag to reject hadron contamination with TOF - float mMinTOFbeta{0.0}, mMaxTOFbeta{0.96}; + float mMinTOFbeta{-999}, mMaxTOFbeta{999}; float mMinTPCNsigmaEl{-1e+10}, mMaxTPCNsigmaEl{+1e+10}; - float mMinTPCNsigmaMu{-1e+10}, mMaxTPCNsigmaMu{+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 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}; - o2::ml::OnnxModel* mPIDModel{nullptr}; + + // 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}; + std::vector mMLBins{}; // binning for a feature variable. e.g. tpcInnerParam + std::vector mMLCuts{}; // threshold for each bin. mMLCuts.size() must be mMLBins.size()-1. ClassDef(DielectronCut, 1); }; diff --git a/PWGEM/Dilepton/Core/Dilepton.h b/PWGEM/Dilepton/Core/Dilepton.h index 29e98bd3afb..bbd0f4b6be3 100644 --- a/PWGEM/Dilepton/Core/Dilepton.h +++ b/PWGEM/Dilepton/Core/Dilepton.h @@ -17,45 +17,49 @@ #ifndef PWGEM_DILEPTON_CORE_DILEPTON_H_ #define PWGEM_DILEPTON_CORE_DILEPTON_H_ -#include -#include -#include -#include -#include -#include -#include -#include -#include "TString.h" -#include "Math/Vector4D.h" +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMFwdTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" +#include "Common/CCDB/RCTSelectionFlags.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" -#include "DCAFitter/DCAFitterN.h" -#include "DCAFitter/FwdDCAFitterN.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" -#include "DataFormatsParameters/GRPLHCIFData.h" #include "DataFormatsParameters/GRPECSObject.h" - -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" #include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "Tools/ML/MlResponse.h" -#include "Tools/ML/model.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.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 "Math/Vector4D.h" +#include "TH1D.h" +#include "TString.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -64,25 +68,26 @@ 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 MyCollisionsWithSWT = soa::Join; using MyCollisionWithSWT = MyCollisionsWithSWT::iterator; -using MyElectrons = soa::Join; +using MyElectrons = soa::Join; using MyElectron = MyElectrons::iterator; using FilteredMyElectrons = soa::Filtered; using FilteredMyElectron = FilteredMyElectrons::iterator; -using MyMuons = soa::Join; +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, EMFwdTrackWithCov>; +using MyEMH_electron = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMTrack>; +using MyEMH_muon = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMFwdTrack>; template struct Dilepton { @@ -93,43 +98,74 @@ struct Dilepton { 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 cfgAnalysisType{"cfgAnalysisType", static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kQC), "kQC:0, kUPC:1, kFlowV2:2, kFlowV3:3, kPolarization:4, kHFll:5"}; 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, NTPV:3"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgCentMin{"cfgCentMin", -1, "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 ndepth{"ndepth", 1000, "depth for event mixing"}; + Configurable ndiff_bc_mix{"ndiff_bc_mix", 594, "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", {VARIABLE_WIDTH, -M_PI / 2, -M_PI / 4, 0.0f, +M_PI / 4, +M_PI / 2}, "Mixing bins - event plane angle"}; + 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 cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + // Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; 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"}; + Configurable cfgPolarizationFrame{"cfgPolarizationFrame", 0, "frame of polarization. 0:CS, 1:HX, else:FATAL"}; 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{"ConYllBins", {1, -1.f, 1.f}, "yll bins for output histograms"}; // pair rapidity // 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"}; + ConfigurableAxis ConfPolarizationCosThetaBins{"ConfPolarizationCosThetaBins", {20, -1.f, 1.f}, "cos(theta) bins for polarization analysis"}; + ConfigurableAxis ConfPolarizationPhiBins{"ConfPolarizationPhiBins", {1, -M_PI, M_PI}, "phi bins for polarization analysis"}; + ConfigurableAxis ConfPolarizationQuadMomBins{"ConfPolarizationQuadMomBins", {15, -0.5, 1}, "quadrupole moment bins for polarization analysis"}; // quardrupole moment <(3 x cos^2(theta) -1)/2> + EMEventCut fEMEventCut; struct : ConfigurableGroup { std::string prefix = "eventcut_group"; - Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + 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 cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF 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"}; + 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_hadronPID, 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; @@ -144,28 +180,55 @@ struct Dilepton { 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_apply_detadphi{"cfg_apply_detadphi", false, "flag to apply deta-dphi elliptic cut at PV"}; + 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_20MeV : 2, kElFromPi0_40MeV : 4, kElFromPi0_60MeV : 8, kElFromPi0_80MeV : 16, kElFromPi0_100MeV : 32, kElFromPi0_120MeV : 64, kElFromPi0_140MeV : 128] 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_mirror_phi_track{"cfg_mirror_phi_track", false, "mirror the phi cut around Pi, min and max Phi should be in 0-Pi"}; + Configurable cfg_reject_phi_track{"cfg_reject_phi_track", false, "reject the phi interval"}; 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_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_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3]"}; + 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_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 cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. + Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; + Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; + + 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_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"}; @@ -174,11 +237,19 @@ struct Dilepton { 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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; - - // CCDB configuration for PID ML - Configurable BDTLocalPathGamma{"BDTLocalPathGamma", "pid_ml_xgboost.onnx", "Path to the local .onnx file"}; - Configurable BDTPathCCDB{"BDTPathCCDB", "Users/d/dsekihat/pwgem/pidml/", "Path on CCDB"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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)"}; @@ -195,38 +266,50 @@ struct Dilepton { 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.1, "min pT for single track"}; + 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+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_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; + 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"}; + Configurable cfg_max_relDPt_wrt_matchedMCHMID{"cfg_max_relDPt_wrt_matchedMCHMID", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DEta_wrt_matchedMCHMID{"cfg_max_DEta_wrt_matchedMCHMID", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; } dimuoncuts; - o2::ccdb::CcdbApi ccdbApi; + o2::aod::rctsel::RCTFlagsChecker rctChecker; + // o2::ccdb::CcdbApi ccdbApi; Service ccdb; int mRunNumber; float d_bz; - // o2::vertexing::DCAFitterN<2> fitter; - // o2::vertexing::FwdDCAFitterN<2> fwdfitter; - // 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_cut_types[2] = {"before/", "after/"}; static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + std::mt19937 engine; 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 float leptonM1 = 0.f; float leptonM2 = 0.f; @@ -237,6 +320,7 @@ struct Dilepton { 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*/) { @@ -247,18 +331,76 @@ struct Dilepton { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + rctChecker.init(eventcuts.cfgRCTLabel.value, eventcuts.cfgCheckZDC.value, eventcuts.cfgTreatLimitedAcceptanceAsBad.value); - zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); - zvtx_bin_edges.erase(zvtx_bin_edges.begin()); + 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]); + } + } - cent_bin_edges = std::vector(ConfCentBins.value.begin(), ConfCentBins.value.end()); - cent_bin_edges.erase(cent_bin_edges.begin()); + 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]); + } + } - ep_bin_edges = std::vector(ConfEPBins.value.begin(), ConfEPBins.value.end()); - ep_bin_edges.erase(ep_bin_edges.begin()); + 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]); + } + } - occ_bin_edges = std::vector(ConfOccupancyBins.value.begin(), ConfOccupancyBins.value.end()); - occ_bin_edges.erase(occ_bin_edges.begin()); + 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); @@ -269,34 +411,39 @@ struct Dilepton { DefineDielectronCut(); leptonM1 = o2::constants::physics::MassElectron; leptonM2 = o2::constants::physics::MassElectron; - // fitter.setPropagateToPCA(true); - // fitter.setMaxR(5.f); - // fitter.setMinParamChange(1e-3); - // fitter.setMinRelChi2Change(0.9); - // fitter.setMaxDZIni(1e9); - // fitter.setMaxChi2(1e9); - // fitter.setUseAbsDCA(true); - // fitter.setWeightedFinalPCA(false); - // fitter.setMatCorrType(matCorr); } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { DefineDimuonCut(); leptonM1 = o2::constants::physics::MassMuon; leptonM2 = o2::constants::physics::MassMuon; - // fwdfitter.setPropagateToPCA(true); - // fwdfitter.setMaxR(90.f); - // fwdfitter.setMinParamChange(1e-3); - // fwdfitter.setMinRelChi2Change(0.9); - // fwdfitter.setMaxChi2(1e9); - // fwdfitter.setUseAbsDCA(true); - // fwdfitter.setTGeoMat(false); } + 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"); + fRegistry.add("Event/norm/hZvtx", "hZvtx;Z_{vtx} (cm)", kTH1D, {{100, -50, +50}}, false); + } if (doprocessTriggerAnalysis) { - fRegistry.add("Event/hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + LOGF(info, "Trigger analysis is enabled. Desired trigger name = %s", cfg_swt_name.value.data()); + fRegistry.add("NormTrigger/hInspectedTVX", "inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + fRegistry.add("NormTrigger/hScalers", "trigger counter before DS;run number;counter", kTProfile, {{80000, 520000.5, 600000.5}}, true); + fRegistry.add("NormTrigger/hSelections", "trigger counter after DS;run number;counter", kTProfile, {{80000, 520000.5, 600000.5}}, true); + auto hTriggerCounter = fRegistry.add("NormTrigger/hTriggerCounter", Form("trigger counter of %s;run number;", cfg_swt_name.value.data()), kTH2D, {{80000, 520000.5, 600000.5}, {2, -0.5, 1.5}}, false); + hTriggerCounter->GetYaxis()->SetBinLabel(1, "Analyzed Trigger"); + hTriggerCounter->GetYaxis()->SetBinLabel(2, "Analyzed TOI"); + } + 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 + template void initCCDB(TCollision const& collision) { if (mRunNumber == collision.runNumber()) { @@ -307,12 +454,11 @@ struct Dilepton { 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); mRunNumber = collision.runNumber(); - // fitter.setBz(d_bz); - // fwdfitter.setBz(d_bz); return; } @@ -322,21 +468,22 @@ struct Dilepton { 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"; + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kG"; } 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"; + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kG"; } mRunNumber = collision.runNumber(); - // fitter.setBz(d_bz); - // fwdfitter.setBz(d_bz); + fDielectronCut.SetTrackPhiPositionRange(dielectroncuts.cfg_min_phiposition_track, dielectroncuts.cfg_max_phiposition_track, dielectroncuts.cfgRefR, d_bz, dielectroncuts.cfg_mirror_phi_track); auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", collision.timestamp()); int beamZ1 = grplhcif->getBeamZ(o2::constants::lhc::BeamC); @@ -351,10 +498,10 @@ struct Dilepton { 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)); } } @@ -365,42 +512,55 @@ struct Dilepton { delete emh_neg; emh_neg = 0x0; - map_mixed_eventId_to_qvector.clear(); - - used_trackIds.clear(); - used_trackIds.shrink_to_fit(); + used_trackIds_per_col.clear(); + used_trackIds_per_col.shrink_to_fit(); + map_mixed_eventId_to_globalBC.clear(); - if (eid_bdt) { - delete eid_bdt; - } + delete h2sp_resolution; } void addhistograms() { - std::string_view qvec_det_names[6] = {"FT0M", "FT0A", "FT0C", "BTot", "BPos", "BNeg"}; + 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)"; + std::string pair_y_axis_title = "y_{ll}"; 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)"; + } + 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_y_axis_title = "y_{#mu#mu}"; } // 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}; + const AxisSpec axis_y{ConfYllBins, pair_y_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/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y}, 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 (rad.);m_{ee} (GeV/c^{2})", kTH2D, {{90, 0, M_PI}, {100, 0.0f, 0.1f}}, true); // phiv is only for dielectron + 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/"); @@ -409,8 +569,17 @@ struct Dilepton { 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); + + std::string frameName = "CS"; + if (cfgPolarizationFrame == 0) { + frameName = "CS"; + } else if (cfgPolarizationFrame == 1) { + frameName = "HX"; + } else { + LOG(fatal) << "set 0 or 1 to cfgPolarizationFrame!"; + } + const AxisSpec axis_cos_theta{ConfPolarizationCosThetaBins, Form("cos(#theta^{%s})", frameName.data())}; + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y, axis_aco, axis_asym_pt, axis_dphi_e_ee, axis_cos_theta}, true); fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); fRegistry.addClone("Pair/same/", "Pair/mix/"); @@ -420,53 +589,44 @@ struct Dilepton { } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV3)) { nmod = 3; } - fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca}, true); - fRegistry.add("Pair/same/uls/hPrfUQ", Form("dilepton <#vec{u}_{%d,ll} #upoint #vec{Q}_{%d}^{%s}>", nmod, nmod, qvec_det_names[cfgQvecEstimator].data()), kTProfile3D, {axis_mass, axis_pt, axis_dca}, true); + + 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_y, 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.add("Pair/mix/uls/hs_woEPmix", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca}, true); - fRegistry.add("Pair/mix/uls/hPrfUQCosDPhi", Form("dilepton <#vec{u}_{%d,l1} #upoint #vec{Q}_{%d,ev1}^{%s} cos(%d(#varphi_{l1} - #varphi_{ll}))> + <#vec{u}_{%d,l2} #upoint #vec{Q}_{%d,ev2}^{%s} cos(%d(#varphi_{l2} - #varphi_{ll}))>", nmod, nmod, qvec_det_names[cfgQvecEstimator].data(), nmod, nmod, nmod, qvec_det_names[cfgQvecEstimator].data(), nmod), kTProfile3D, {axis_mass, axis_pt, axis_dca}, true); - fRegistry.add("Pair/mix/uls/hPrf2UQ1UQ2CosDPhi12", Form("dilepton <2 #vec{u}_{%d,l1} #upoint #vec{Q}_{%d,ev1}^{%s} #vec{u}_{%d,l2} #upoint #vec{Q}_{%d,ev2}^{%s} cos(%d(#varphi_{l1} - #varphi_{l2}))>", nmod, nmod, qvec_det_names[cfgQvecEstimator].data(), nmod, nmod, qvec_det_names[cfgQvecEstimator].data(), nmod), kTProfile3D, {axis_mass, axis_pt, axis_dca}, true); + fRegistry.add("Pair/mix/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y}, 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; + std::string frameName = "CS"; + if (cfgPolarizationFrame == 0) { + frameName = "CS"; + } else if (cfgPolarizationFrame == 1) { + frameName = "HX"; + } else { + LOG(fatal) << "set 0 or 1 to cfgPolarizationFrame!"; } - 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); + + const AxisSpec axis_cos_theta{ConfPolarizationCosThetaBins, Form("cos(#theta^{%s})", frameName.data())}; + const AxisSpec axis_phi{ConfPolarizationPhiBins, Form("#varphi^{%s} (rad.)", frameName.data())}; + const AxisSpec axis_quadmom{ConfPolarizationQuadMomBins, Form("#frac{3 cos^{2}(#theta^{%s}) -1}{2}", frameName.data())}; + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y, axis_cos_theta, axis_phi, axis_quadmom}, 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{18, 0, M_PI, "#Delta#varphi = #varphi_{e1} - #varphi_{e2} (rad.)"}; - fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_dphi_ee}, true); + 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_y, 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.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/"); @@ -489,16 +649,24 @@ struct Dilepton { fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); - fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireVertexTOFmatched(eventcuts.cfgRequireVertexTOFmatched); fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); + 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::ml::OnnxModel* eid_bdt = nullptr; + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -508,50 +676,79 @@ struct Dilepton { 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.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dielectroncuts.cfg_phiv_intercept) / dielectroncuts.cfg_phiv_slope; }); + 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); + fDielectronCut.SetMindEtadPhi(dielectroncuts.cfg_apply_detadphi, false, 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, 1e+10f); + 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, dielectroncuts.cfg_mirror_phi_track, dielectroncuts.cfg_reject_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.SetMeanClusterSizeITSob(0, 16); - fDielectronCut.SetMaxDcaXY(dielectroncuts.cfg_max_dcaxy); - fDielectronCut.SetMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); // 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.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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, dielectroncuts.cfg_max_pin_pirejTPC); if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut - eid_bdt = new o2::ml::OnnxModel(); - if (dielectroncuts.loadModelsFromCCDB) { - ccdbApi.init(ccdburl); - std::map metadata; - bool retrieveSuccessGamma = ccdbApi.retrieveBlob(dielectroncuts.BDTPathCCDB.value, ".", metadata, dielectroncuts.timestampCCDB.value, false, dielectroncuts.BDTLocalPathGamma.value); - if (retrieveSuccessGamma) { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); - } else { - LOG(fatal) << "Error encountered while fetching/loading the Gamma model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; - } - } else { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); + std::vector binsML{}; + binsML.reserve(dielectroncuts.binsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(dielectroncuts.binsMl.value[i]); } - - fDielectronCut.SetPIDModel(eid_bdt); + std::vector thresholdsML{}; + thresholdsML.reserve(dielectroncuts.cutsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + + // static constexpr int nClassesMl = 2; + // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + // const std::vector labelsClasses = {"Background", "Signal"}; + // 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] = 0.; + // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; + // } + // 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 } @@ -563,28 +760,33 @@ struct Dilepton { 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.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, 1e10f); + 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.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); 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); }); + fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons + fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); } template bool isGoodQvector(TQvectors const& qvectors) { bool is_good = true; - for (auto& qn : qvectors[nmod]) { - if (abs(qn[0]) > 100.f || abs(qn[1]) > 100.f) { + for (const auto& qn : qvectors[nmod]) { + if (std::fabs(qn[0]) > 20.f || std::fabs(qn[1]) > 20.f) { is_good = false; break; } @@ -592,129 +794,177 @@ struct Dilepton { return is_good; } - template - bool fillPairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TMixedQvectors const& qvectors_mix) + float getSPresolution(const float centrality, const int occupancy) { - if constexpr (ev_id == 1) { - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - if (t1.has_ambiguousElectrons() && t2.has_ambiguousElectrons()) { - for (auto& possible_id1 : t1.ambiguousElectronsIds()) { - for (auto& possible_id2 : t2.ambiguousElectronsIds()) { - if (possible_id1 == possible_id2) { - // LOGF(info, "event id = %d: same track is found. t1.trackId() = %d, t1.collisionId() = %d, t1.pt() = %f, t1.eta() = %f, t1.phi() = %f, t2.trackId() = %d, t2.collisionId() = %d, t2.pt() = %f, t2.eta() = %f, t2.phi() = %f", ev_id, t1.trackId(), t1.collisionId(), t1.pt(), t1.eta(), t1.phi(), t2.trackId(), t2.collisionId(), t2.pt(), t2.eta(), 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) { - if (t1.has_ambiguousMuons() && t2.has_ambiguousMuons()) { - for (auto& possible_id1 : t1.ambiguousMuonsIds()) { - for (auto& possible_id2 : t2.ambiguousMuonsIds()) { - if (possible_id1 == possible_id2) { - // LOGF(info, "event id = %d: same track is found. t1.trackId() = %d, t1.collisionId() = %d, t1.pt() = %f, t1.eta() = %f, t1.phi() = %f, t2.trackId() = %d, t2.collisionId() = %d, t2.pt() = %f, t2.eta() = %f, t2.phi() = %f", ev_id, t1.trackId(), t1.collisionId(), t1.pt(), t1.eta(), t1.phi(), t2.trackId(), t2.collisionId(), t2.pt(), t2.eta(), 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 (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 == 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)) { + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { return false; } } else { // cut-based - if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + 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)) { + 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)) { + if (!cut.IsSelectedPair(t1, t2, d_bz, 0)) { return false; } } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { - if (!cut.template IsSelectedPair(t1, t2)) { + if (!cut.IsSelectedPair(t1, t2)) { return false; } } - // float pca = 999.f, lxy = 999.f; // in unit of cm - // o2::aod::pwgem::dilepton::utils::pairutil::isSVFound(fitter, collision, t1, t2, pca, lxy); - // o2::aod::pwgem::dilepton::utils::pairutil::isSVFoundFwd(fwdfitter, collision, t1, t2, pca, lxy); - float weight = 1.f; - if (cfgApplyWeightTTCA) { - weight = map_weight[std::make_pair(t1.globalIndex(), t2.globalIndex())]; - } - if (ev_id == 1) { - weight = 1.f; + if constexpr (ev_id == 0) { + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(t1.globalIndex(), t2.globalIndex())]; + } } - // 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 dca_t1 = 999.f, dca_t2 = 999.f, pair_dca = 999.f; + float pair_dca = 999.f; if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - dca_t1 = dca3DinSigma(t1); - dca_t2 = dca3DinSigma(t2); - pair_dca = std::sqrt((dca_t1 * dca_t1 + dca_t2 * dca_t2) / 2.); + 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) { - dca_t1 = fwdDcaXYinSigma(t1); - dca_t2 = fwdDcaXYinSigma(t2); - pair_dca = std::sqrt((dca_t1 * dca_t1 + dca_t2 * dca_t2) / 2.); + 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); 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/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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); + if (cfgDCAType == 1) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hDCA1vsDCA2"), dcaXYinSigma(t1), dcaXYinSigma(t2), weight); + } else if (cfgDCAType == 2) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hDCA1vsDCA2"), dcaZinSigma(t1), dcaZinSigma(t2), 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/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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); + if (cfgDCAType == 1) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hDCA1vsDCA2"), dcaXYinSigma(t1), dcaXYinSigma(t2), weight); + } else if (cfgDCAType == 2) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hDCA1vsDCA2"), dcaZinSigma(t1), dcaZinSigma(t2), 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/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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); + if (cfgDCAType == 1) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hDCA1vsDCA2"), dcaXYinSigma(t1), dcaXYinSigma(t2), weight); + } else if (cfgDCAType == 2) { + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hDCA1vsDCA2"), dcaZinSigma(t1), dcaZinSigma(t2), 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 - abs(dphi) / M_PI; - float asym = abs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); + 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); + float cos_thetaPol = 999, phiPol = 999.f; + auto arrM = std::array{static_cast(v12.Px()), static_cast(v12.Py()), static_cast(v12.Pz()), static_cast(v12.M())}; + auto arrD = t1.sign() * t1.pt() > t2.sign() * t2.pt() ? std::array{t1.px(), t1.py(), t1.pz(), leptonM1} : std::array{t2.px(), t2.py(), t2.pz(), leptonM2}; + + if (cfgPolarizationFrame == 0) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } else if (cfgPolarizationFrame == 1) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } + + o2::math_utils::bringToPMPi(phiPol); 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, abs(dphi_e_ee), abs(cos_thetaCS), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), aco, asym, std::fabs(dphi_e_ee), cos_thetaPol, 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, abs(dphi_e_ee), abs(cos_thetaCS), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), aco, asym, std::fabs(dphi_e_ee), cos_thetaPol, 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, abs(dphi_e_ee), abs(cos_thetaCS), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), aco, asym, std::fabs(dphi_e_ee), cos_thetaPol, 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()}; @@ -734,166 +984,117 @@ struct Dilepton { {{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 - {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 4th harmonics }; if constexpr (ev_id == 0) { - float sp = RecoDecay::dotProd(std::array{static_cast(std::cos(nmod * v12.Phi())), static_cast(std::sin(nmod * v12.Phi()))}, qvectors[nmod][cfgQvecEstimator]); + // 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, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hPrfUQ"), v12.M(), v12.Pt(), pair_dca, sp, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hPrfUQ"), v12.M(), v12.Pt(), pair_dca, sp, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hPrfUQ"), v12.M(), v12.Pt(), pair_dca, sp, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), sp, weight); } } else if constexpr (ev_id == 1) { - if (!isOverEPbin) { - 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 { - float sp1 = RecoDecay::dotProd(std::array{static_cast(std::cos(nmod * v1.Phi())), static_cast(std::sin(nmod * v1.Phi()))}, qvectors[nmod][cfgQvecEstimator]); - float sp2 = RecoDecay::dotProd(std::array{static_cast(std::cos(nmod * v2.Phi())), static_cast(std::sin(nmod * v2.Phi()))}, qvectors_mix[nmod][cfgQvecEstimator]); - float cos_dphi1 = std::cos(nmod * (v1.Phi() - v12.Phi())); - float cos_dphi2 = std::cos(nmod * (v2.Phi() - v12.Phi())); - float cos_dphi12 = std::cos(nmod * (v1.Phi() - v2.Phi())); - - if (t1.sign() * t2.sign() < 0) { // ULS - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs_woEPmix"), v12.M(), v12.Pt(), pair_dca, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hPrfUQCosDPhi"), v12.M(), v12.Pt(), pair_dca, sp1 * cos_dphi1 + sp2 * cos_dphi2, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hPrf2UQ1UQ2CosDPhi12"), v12.M(), v12.Pt(), pair_dca, 2.f * sp1 * sp2 * cos_dphi12, weight); - } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs_woEPmix"), v12.M(), v12.Pt(), pair_dca, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hPrfUQCosDPhi"), v12.M(), v12.Pt(), pair_dca, sp1 * cos_dphi1 + sp2 * cos_dphi2, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hPrf2UQ1UQ2CosDPhi12"), v12.M(), v12.Pt(), pair_dca, 2.f * sp1 * sp2 * cos_dphi12, weight); - } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs_woEPmix"), v12.M(), v12.Pt(), pair_dca, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hPrfUQCosDPhi"), v12.M(), v12.Pt(), pair_dca, sp1 * cos_dphi1 + sp2 * cos_dphi2, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hPrf2UQ1UQ2CosDPhi12"), v12.M(), v12.Pt(), pair_dca, 2.f * sp1 * sp2 * cos_dphi12, weight); - } + 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::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, abs(cos_thetaCS), abs(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, abs(cos_thetaCS), abs(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, abs(cos_thetaCS), abs(phiCS), weight); + float cos_thetaPol = 999, phiPol = 999.f; + auto arrM = std::array{static_cast(v12.Px()), static_cast(v12.Py()), static_cast(v12.Pz()), static_cast(v12.M())}; + auto random_sign = std::pow(-1, engine() % 2); // -1^0 = +1 or -1^1 = -1; + auto arrD = t1.sign() * t2.sign() < 0 ? (t1.sign() > 0 ? std::array{t1.px(), t1.py(), t1.pz(), leptonM1} : std::array{t2.px(), t2.py(), t2.pz(), leptonM2}) : (random_sign > 0 ? std::array{t1.px(), t1.py(), t1.pz(), leptonM1} : std::array{t2.px(), t2.py(), t2.pz(), leptonM2}); + + if (cfgPolarizationFrame == 0) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } else if (cfgPolarizationFrame == 1) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); } - } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kVM)) { + o2::math_utils::bringToPMPi(phiPol); + float quadmom = (3.f * std::pow(cos_thetaPol, 2) - 1.f) / 2.f; + 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); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), cos_thetaPol, phiPol, quadmom, 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); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), cos_thetaPol, phiPol, quadmom, 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); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), cos_thetaPol, phiPol, quadmom, weight); } + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kHFll)) { float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); + 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, abs(dphi), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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, abs(dphi), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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, abs(dphi), weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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); + 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, weight); + 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, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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 (std::find(used_trackIds_per_col.begin(), used_trackIds_per_col.end(), t1.globalIndex()) == used_trackIds_per_col.end()) { + used_trackIds_per_col.emplace_back(t1.globalIndex()); if (cfgDoMix) { if (t1.sign() > 0) { - emh_pos->AddTrackToEventPool(key_df_collision, EMTrackWithCov(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())); + emh_pos->AddTrackToEventPool(key_df_collision, EMTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.dcaXY(), t1.dcaZ(), t1.cYY(), t1.cZY(), t1.cZZ())); } else { - emh_neg->AddTrackToEventPool(key_df_collision, EMTrackWithCov(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())); + emh_neg->AddTrackToEventPool(key_df_collision, EMTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.dcaXY(), t1.dcaZ(), t1.cYY(), t1.cZY(), t1.cZZ())); } } } - if (std::find(used_trackIds.begin(), used_trackIds.end(), pair_tmp_id2) == used_trackIds.end()) { - used_trackIds.emplace_back(pair_tmp_id2); + if (std::find(used_trackIds_per_col.begin(), used_trackIds_per_col.end(), t2.globalIndex()) == used_trackIds_per_col.end()) { + used_trackIds_per_col.emplace_back(t2.globalIndex()); if (cfgDoMix) { if (t2.sign() > 0) { - emh_pos->AddTrackToEventPool(key_df_collision, EMTrackWithCov(t2.globalIndex(), collision.globalIndex(), t2.trackId(), t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.dcaXY(), t2.dcaZ(), possibleIds1, - 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())); + emh_pos->AddTrackToEventPool(key_df_collision, EMTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.dcaXY(), t2.dcaZ(), t2.cYY(), t2.cZY(), t2.cZZ())); } else { - emh_neg->AddTrackToEventPool(key_df_collision, EMTrackWithCov(t2.globalIndex(), collision.globalIndex(), t2.trackId(), t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.dcaXY(), t2.dcaZ(), possibleIds1, - 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())); + emh_neg->AddTrackToEventPool(key_df_collision, EMTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.dcaXY(), t2.dcaZ(), t2.cYY(), t2.cZY(), t2.cZZ())); } } } } 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 (std::find(used_trackIds_per_col.begin(), used_trackIds_per_col.end(), t1.globalIndex()) == used_trackIds_per_col.end()) { + used_trackIds_per_col.emplace_back(t1.globalIndex()); if (cfgDoMix) { if (t1.sign() > 0) { - emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrackWithCov(t1.globalIndex(), collision.globalIndex(), t1.fwdtrackId(), t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), possibleIds1, - t1.x(), t1.y(), t1.z(), t1.tgl(), 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(), t1.chi2())); + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); } else { - emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrackWithCov(t1.globalIndex(), collision.globalIndex(), t1.fwdtrackId(), t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), possibleIds1, - t1.x(), t1.y(), t1.z(), t1.tgl(), 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(), t1.chi2())); + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), 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 (std::find(used_trackIds_per_col.begin(), used_trackIds_per_col.end(), t2.globalIndex()) == used_trackIds_per_col.end()) { + used_trackIds_per_col.emplace_back(t2.globalIndex()); if (cfgDoMix) { if (t2.sign() > 0) { - emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrackWithCov(t2.globalIndex(), collision.globalIndex(), t2.fwdtrackId(), t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), possibleIds2, - t2.x(), t2.y(), t2.z(), t2.tgl(), 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(), t2.chi2())); + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); } else { - emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrackWithCov(t2.globalIndex(), collision.globalIndex(), t2.fwdtrackId(), t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassMuon, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), possibleIds2, - t2.x(), t2.y(), t2.z(), t2.tgl(), 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(), t2.chi2())); + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); } } } @@ -903,36 +1104,56 @@ struct Dilepton { } 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_numContrib = cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < cfgNumContribMax; + 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 && 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) && (o2::aod::pidtpc::tpcNSigmaPi < dielectroncuts.cfg_min_TPCNsigmaPi || dielectroncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi) && ((0.96f < o2::aod::pidtofbeta::beta && o2::aod::pidtofbeta::beta < 1.04f) || o2::aod::pidtofbeta::beta < 0.f); + 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 && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; 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_20MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_20MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_40MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_40MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_60MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_60MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_80MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_80MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_100MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_100MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_120MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_120MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_140MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_140MeV))) <= 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 && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track; + 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; 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, std::vector>>> map_mixed_eventId_to_qvector; - std::vector> used_trackIds; + std::map, uint64_t> map_mixed_eventId_to_globalBC; + + std::vector used_trackIds_per_col; int ndf = 0; - template - void runPairing(TCollisions const& collisions, TLeptons const& posTracks, TLeptons const& negTracks, TPresilce const& perCollision, TCut const& cut) + template + void runPairing(TCollisions const& collisions, TLeptons const& posTracks, TLeptons const& negTracks, TPresilce const& perCollision, TCut const& cut, TAllTracks const& tracks) { - for (auto& collision : collisions) { - initCCDB(collision); - const float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + 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; @@ -964,7 +1185,6 @@ struct Dilepton { {{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 - {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 4th harmonics }; if (nmod == 2) { @@ -982,6 +1202,9 @@ struct Dilepton { if (!fEMEventCut.IsSelected(collision)) { continue; } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } if (nmod > 0 && !isGoodQvector(qvectors)) { continue; @@ -1004,25 +1227,28 @@ struct Dilepton { 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()); + used_trackIds_per_col.reserve(posTracks_per_coll.size() + negTracks_per_coll.size()); int nuls = 0, nlspp = 0, nlsmm = 0; - for (auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS - bool is_pair_ok = fillPairInfo<0, false>(collision, pos, neg, cut, nullptr); + 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 (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ - bool is_pair_ok = fillPairInfo<0, false>(collision, pos1, pos2, cut, nullptr); + 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 (auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- - bool is_pair_ok = fillPairInfo<0, false>(collision, neg1, neg2, cut, nullptr); + 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++; } } + used_trackIds_per_col.clear(); + used_trackIds_per_col.shrink_to_fit(); if (!cfgDoMix || !(nuls > 0 || nlspp > 0 || nlsmm > 0)) { continue; @@ -1050,7 +1276,15 @@ struct Dilepton { epbin = static_cast(ep_bin_edges.size()) - 2; } - int occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.trackOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + 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) { @@ -1060,7 +1294,7 @@ struct Dilepton { // 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()); + std::pair key_df_collision = std::make_pair(ndf, collision.globalIndex()); // this gives the current event. // make a vector of selected photons in this collision. auto selected_posTracks_in_this_event = emh_pos->GetTracksPerCollision(key_df_collision); @@ -1070,132 +1304,91 @@ struct Dilepton { 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 (auto& mix_dfId_collisionId : collisionIds_in_mixing_pool) { + 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 qvectors_mix = map_mixed_eventId_to_qvector[mix_dfId_collisionId]; + 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 (auto& pos : selected_posTracks_in_this_event) { // ULS mix - for (auto& neg : negTracks_from_event_pool) { - fillPairInfo<1, false>(collision, pos, neg, cut, qvectors_mix); + 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, nullptr); } } - for (auto& neg : selected_negTracks_in_this_event) { // ULS mix - for (auto& pos : posTracks_from_event_pool) { - fillPairInfo<1, false>(collision, neg, pos, cut, qvectors_mix); + 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, nullptr); } } - for (auto& pos1 : selected_posTracks_in_this_event) { // LS++ mix - for (auto& pos2 : posTracks_from_event_pool) { - fillPairInfo<1, false>(collision, pos1, pos2, cut, qvectors_mix); + 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, nullptr); } } - for (auto& neg1 : selected_negTracks_in_this_event) { // LS-- mix - for (auto& neg2 : negTracks_from_event_pool) { - fillPairInfo<1, false>(collision, neg1, neg2, cut, qvectors_mix); + 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, nullptr); } } } // end of loop over mixed event pool - // run mixed event loop for flow measurement. Don't divide mixed-event categories by event planes, if you do flow measurement. - if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV2) || cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonAnalysisType::kFlowV3)) { - - for (int epbin_tmp = 0; epbin_tmp < static_cast(ep_bin_edges.size()) - 1; epbin_tmp++) { - std::tuple key_bin = std::make_tuple(zbin, centbin, epbin_tmp, occbin); - 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 (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 qvectors_mix = map_mixed_eventId_to_qvector[mix_dfId_collisionId]; - - 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 (auto& pos : selected_posTracks_in_this_event) { // ULS mix - for (auto& neg : negTracks_from_event_pool) { - fillPairInfo<1, true>(collision, pos, neg, cut, qvectors_mix); - } - } - - for (auto& neg : selected_negTracks_in_this_event) { // ULS mix - for (auto& pos : posTracks_from_event_pool) { - fillPairInfo<1, true>(collision, neg, pos, cut, qvectors_mix); - } - } - - for (auto& pos1 : selected_posTracks_in_this_event) { // LS++ mix - for (auto& pos2 : posTracks_from_event_pool) { - fillPairInfo<1, true>(collision, pos1, pos2, cut, qvectors_mix); - } - } - - for (auto& neg1 : selected_negTracks_in_this_event) { // LS-- mix - for (auto& neg2 : negTracks_from_event_pool) { - fillPairInfo<1, true>(collision, neg1, neg2, cut, qvectors_mix); - } - } - } // end of loop over mixed event pool - - } // end of ep bin loop - - } // end of mixing loop for flow - if (nuls > 0 || nlspp > 0 || nlsmm > 0) { - if (nmod > 0) { - map_mixed_eventId_to_qvector[key_df_collision] = qvectors; - } + 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 if pair exist } // end of collision loop - ndf++; } // end of DF - template - bool isPairOK(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut) + template + bool isPairOK(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)) { + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { return false; } } else { // cut-based - if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + 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)) { + 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.template IsSelectedPair(t1, t2, d_bz)) { + if (!cut.IsSelectedPair(t1, t2, d_bz, 0.0)) { return false; } } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { - if (!cut.template IsSelectedPair(t1, t2)) { + if (!cut.IsSelectedPair(t1, t2)) { return false; } } @@ -1209,9 +1402,9 @@ struct Dilepton { std::vector> passed_pairIds; passed_pairIds.reserve(posTracks.size() * negTracks.size()); - for (auto& collision : collisions) { - initCCDB(collision); - const float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + 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; } @@ -1240,12 +1433,14 @@ struct Dilepton { {{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 - {{999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}, {999.f, 999.f}}, // 4th harmonics }; if (!fEMEventCut.IsSelected(collision)) { continue; } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } if (nmod > 0 && !isGoodQvector(qvectors)) { continue; @@ -1254,32 +1449,32 @@ struct Dilepton { auto posTracks_per_coll = posTracks.sliceByCached(perCollision, collision.globalIndex(), cache); auto negTracks_per_coll = negTracks.sliceByCached(perCollision, collision.globalIndex(), cache); - for (auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS - if (isPairOK(collision, pos, neg, cut)) { + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + if (isPairOK(pos, neg, cut, tracks)) { passed_pairIds.emplace_back(std::make_pair(pos.globalIndex(), neg.globalIndex())); } } - for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ - if (isPairOK(collision, pos1, pos2, cut)) { + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + if (isPairOK(pos1, pos2, cut, tracks)) { passed_pairIds.emplace_back(std::make_pair(pos1.globalIndex(), pos2.globalIndex())); } } - for (auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- - if (isPairOK(collision, neg1, neg2, cut)) { + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + if (isPairOK(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 (auto& pairId : passed_pairIds) { + 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 (auto& ambId1 : t1.ambiguousElectronsIds()) { - for (auto& ambId2 : t2.ambiguousElectronsIds()) { + 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; } @@ -1288,13 +1483,13 @@ struct Dilepton { map_weight[pairId] = 1.f / n; } // end of passed_pairIds loop } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { - for (auto& pairId : passed_pairIds) { + 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 (auto& ambId1 : t1.ambiguousMuonsIds()) { - for (auto& ambId2 : t2.ambiguousMuonsIds()) { + 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; } @@ -1314,38 +1509,159 @@ struct Dilepton { 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); + 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); + 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) + void processTriggerAnalysis(FilteredMyCollisionsWithSWT const& collisions, aod::EMSWTriggerInfos const& cefpinfos, aod::EMSWTriggerATCounters const& countersAT, aod::EMSWTriggerTOICounters const& countersTOI, 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); + 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); + runPairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons); } map_weight.clear(); + ndf++; + + // for nomalization + int emswtId = o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value); + for (const auto& counter : countersAT) { + if (counter.isAnalyzed_bit(emswtId)) { + fRegistry.fill(HIST("NormTrigger/hTriggerCounter"), mRunNumber, 0); + } + } + for (const auto& counter : countersTOI) { + if (counter.isAnalyzedToI_bit(emswtId)) { + fRegistry.fill(HIST("NormTrigger/hTriggerCounter"), mRunNumber, 1); + } + } + + for (const auto& info : cefpinfos) { + fRegistry.fill(HIST("NormTrigger/hInspectedTVX"), info.runNumber(), info.nInspectedTVX()); + fRegistry.fill(HIST("NormTrigger/hScalers"), info.runNumber(), info.nScalers()[emswtId]); + fRegistry.fill(HIST("NormTrigger/hSelections"), info.runNumber(), info.nSelections()[emswtId]); + } } PROCESS_SWITCH(Dilepton, processTriggerAnalysis, "run dilepton analysis on triggered data", false); + void processNorm(aod::EMEventNormInfos const& collisions) + { + for (const auto& collision : collisions) { + if (collision.centFT0C() < cfgCentMin || cfgCentMax < collision.centFT0C()) { + continue; + } + fRegistry.fill(HIST("Event/norm/hZvtx"), collision.posZ()); + + 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); }; diff --git a/PWGEM/Dilepton/Core/DileptonHadronMPC.h b/PWGEM/Dilepton/Core/DileptonHadronMPC.h new file mode 100644 index 00000000000..dec2d9eb9dd --- /dev/null +++ b/PWGEM/Dilepton/Core/DileptonHadronMPC.h @@ -0,0 +1,1432 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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_DILEPTONHADRONMPC_H_ +#define PWGEM_DILEPTON_CORE_DILEPTONHADRONMPC_H_ + +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/Core/EMTrackCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMFwdTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" + +#include "Math/Vector4D.h" +#include "TH1D.h" +#include "TString.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, EMTrack>; +using MyEMH_muon = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMFwdTrack>; +using MyEMH_track = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMTrack>; // for charged track + +template +struct DileptonHadronMPC { + + // 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 cfgAnalysisType{"cfgAnalysisType", static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kAzimuthalCorrelation), "kAzimuthalCorrelation:0, kCumulant:1"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + Configurable ndepth_lepton{"ndepth_lepton", 100, "depth for event mixing between lepton-lepton"}; + Configurable ndepth_hadron{"ndepth_hadron", 1, "depth for event mixing between hadron-hadron"}; + Configurable ndiff_bc_mix{"ndiff_bc_mix", 594, "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 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"}; + + 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.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.00}, "pTll bins for output histograms"}; + ConfigurableAxis ConfDCAllBins{"ConfDCAllBins", {VARIABLE_WIDTH, 0.0, 0.5, 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}, "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 ConfPtHadronBins{"ConfPtHadronBins", {VARIABLE_WIDTH, 0.00, 0.15, 0.2, 0.3, 0.4, 0.50, 1.00, 2.00, 3.00, 4.00, 5.00}, "pT,h bins for output histograms"}; + ConfigurableAxis ConfYllBins{"ConfYllBins", {1, -1.f, 1.f}, "yll bins for output histograms"}; // pair rapidity + ConfigurableAxis ConfDEtaBins{"ConfDEtaBins", {120, -6, 6}, "deta bins for output histograms"}; + Configurable cfgNbinsDPhi{"cfgNbinsDPhi", 36, "nbins in dphi for output histograms"}; + Configurable cfgNbinsCosNDPhi{"cfgNbinsCosNDPhi", 200, "nbins in cos(n(dphi)) for output histograms"}; + Configurable cfgNmod{"cfgNmod", 2, "n-th harmonics"}; + + 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 cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF 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_hadronPID, 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 at PV"}; + Configurable cfg_apply_detadphiposition{"cfg_apply_detadphiposition", false, "flag to apply deta-dphi elliptic cut at certain radius"}; + 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_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_20MeV : 2, kElFromPi0_40MeV : 4, kElFromPi0_60MeV : 8, kElFromPi0_80MeV : 16, kElFromPi0_100MeV : 32, kElFromPi0_120MeV : 64, kElFromPi0_140MeV : 128] 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", 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_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 cfgRefR{"cfgRefR", 1.2, "reference R (in m) for extrapolation"}; // https://cds.cern.ch/record/1419204 + + 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_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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; + Configurable enableTTCA{"enableTTCA", false, "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", 6, "min ncluster MFT"}; + Configurable cfg_min_ncluster_mch{"cfg_min_ncluster_mch", 8, "min ncluster MCH"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; + 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", false, "Flag to enable or disable TTCA"}; + Configurable cfg_max_relDPt_wrt_matchedMCHMID{"cfg_max_relDPt_wrt_matchedMCHMID", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DEta_wrt_matchedMCHMID{"cfg_max_DEta_wrt_matchedMCHMID", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; + } dimuoncuts; + + EMTrackCut fEMTrackCut; + struct : ConfigurableGroup { + std::string prefix = "trackcut_group"; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for ref. track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 3.0, "max pT for ref. track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.8, "min eta for ref. track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.8, "max eta for ref. track"}; + // Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.0, "min phi for ref. track"}; + // Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for ref. track"}; + // Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.5, "max dca XY for single track in cm"}; + // Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.5, "max dca Z for single track in cm"}; + Configurable cfg_track_bits{"cfg_track_bits", 5765, "required track bits"}; // default:645, loose:0, tight:778 + } trackcuts; + + 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 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; + + 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]); + } + } + + 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_lepton); + emh_neg = new TEMH(ndepth_lepton); + emh_ref = new MyEMH_track(ndepth_hadron); // for reference flow + + DefineEMEventCut(); + DefineEMTrackCut(); + 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; + } + + if (doprocessTriggerAnalysis) { + LOGF(info, "Trigger analysis is enabled. Desired trigger name = %s", cfg_swt_name.value); + fRegistry.add("NormTrigger/hInspectedTVX", "inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + fRegistry.add("NormTrigger/hScalers", "trigger counter before DS;run number;counter", kTProfile, {{80000, 520000.5, 600000.5}}, true); + fRegistry.add("NormTrigger/hSelections", "trigger counter after DS;run number;counter", kTProfile, {{80000, 520000.5, 600000.5}}, true); + auto hTriggerCounter = fRegistry.add("NormTrigger/hTriggerCounter", Form("trigger counter of %s;run number;", cfg_swt_name.value.data()), kTH2D, {{80000, 520000.5, 600000.5}, {2, -0.5, 1.5}}, false); + hTriggerCounter->GetYaxis()->SetBinLabel(1, "Analyzed Trigger"); + hTriggerCounter->GetYaxis()->SetBinLabel(2, "Analyzed TOI"); + } + } + + 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(); + + 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()); + } + } + + ~DileptonHadronMPC() + { + delete emh_pos; + emh_pos = 0x0; + delete emh_neg; + emh_neg = 0x0; + delete emh_ref; + emh_ref = 0x0; + + used_trackIds_per_col.clear(); + used_trackIds_per_col.shrink_to_fit(); + map_mixed_eventId_to_globalBC.clear(); + } + + void addhistograms() + { + // event info + o2::aod::pwgem::dilepton::utils::eventhistogram::addEventHistograms<-1>(&fRegistry); + + 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)"; + std::string pair_rapidity_axis_title = "y_{ll}"; + std::string deta_axis_title = "#Delta#eta = #eta_{ll} - #eta_{h}"; + std::string dphi_axis_title = "#Delta#varphi = #varphi_{ll} - #varphi_{h} (rad.)"; + std::string cosndphi_axis_title = std::format("cos({0:d}(#varphi_{{ll}} - #varphi_{{h}}))", cfgNmod.value); + + 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_rapidity_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)"; + } + deta_axis_title = "#Delta#eta = #eta_{ee} - #eta_{h}"; + dphi_axis_title = "#Delta#varphi = #varphi_{ee} - #varphi_{h} (rad.)"; + cosndphi_axis_title = std::format("cos({0:d}(#varphi_{{ee}} - #varphi_{{h}}))", cfgNmod.value); + } 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_rapidity_axis_title = "y_{#mu#mu}"; + pair_dca_axis_title = "DCA_{#mu#mu}^{XY} (#sigma)"; + deta_axis_title = "#Delta#eta = #eta_{#mu#mu} - #eta_{h}"; + dphi_axis_title = "#Delta#varphi = #varphi_{#mu#mu} - #varphi_{h} (rad.)"; + cosndphi_axis_title = std::format("cos({0:d}(#varphi_{{#mu#mu}} - #varphi_{{h}}))", cfgNmod.value); + } + + // dilepton 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}; + const AxisSpec axis_y{ConfYllBins, pair_rapidity_axis_title}; + + // dilepton-hadron info + const AxisSpec axis_deta{ConfDEtaBins, deta_axis_title}; + + // hadron-hadron info + const AxisSpec axis_deta_hh{60, -3, +3, "#Delta#eta = #eta_{h}^{ref1} - #eta_{h}^{ref2}"}; + + const AxisSpec axis_pt_trg{ConfPtHadronBins, "p_{T,h} (GeV/c)"}; + const AxisSpec axis_eta_trg{40, -2, +2, "#eta_{h}"}; + const AxisSpec axis_phi_trg{36, 0, 2 * M_PI, "#varphi_{h} (rad.)"}; + fRegistry.add("Hadron/hs", "hadron", kTHnSparseD, {axis_pt_trg, axis_eta_trg, axis_phi_trg}, false); + fRegistry.add("Hadron/hTrackBit", "track bit", kTH1D, {{65536, -0.5, 65535.5}}, false); + + fRegistry.add("Dilepton/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y}, true); + fRegistry.addClone("Dilepton/same/uls/", "Dilepton/same/lspp/"); + fRegistry.addClone("Dilepton/same/uls/", "Dilepton/same/lsmm/"); + fRegistry.addClone("Dilepton/same/", "Dilepton/mix/"); + + if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kAzimuthalCorrelation)) { + const AxisSpec axis_dphi{cfgNbinsDPhi, -M_PI / 2, 3 * M_PI / 2, dphi_axis_title}; + // dilepton-hadron + fRegistry.add("DileptonHadron/same/uls/hs", "dilepton-hadron 2PC", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y, axis_deta, axis_dphi}, true); + fRegistry.addClone("DileptonHadron/same/uls/", "DileptonHadron/same/lspp/"); + fRegistry.addClone("DileptonHadron/same/uls/", "DileptonHadron/same/lsmm/"); + // fRegistry.addClone("DileptonHadron/same/", "DileptonHadron/mix/"); + + // hadron-hadron + const AxisSpec axis_dphi_hh{90, -M_PI / 2, 3 * M_PI / 2, "#Delta#varphi = #varphi_{h}^{ref1} - #varphi_{h}^{ref2} (rad.)"}; + fRegistry.add("HadronHadron/same/hDEtaDPhi", "hadron-hadron 2PC", kTH2D, {axis_dphi_hh, axis_deta_hh}, true); + fRegistry.addClone("HadronHadron/same/", "HadronHadron/mix/"); + fRegistry.add("HadronHadron/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kCumulant)) { + const AxisSpec axis_cos_ndphi{cfgNbinsCosNDPhi, -1, +1, cosndphi_axis_title}; + + // dilepton-hadron + fRegistry.add("DileptonHadron/same/uls/hs", "dilepton-hadron 2PC", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y, axis_deta, axis_cos_ndphi}, true); + fRegistry.addClone("DileptonHadron/same/uls/", "DileptonHadron/same/lspp/"); + fRegistry.addClone("DileptonHadron/same/uls/", "DileptonHadron/same/lsmm/"); + fRegistry.addClone("DileptonHadron/same/", "DileptonHadron/mix/"); + + // hadron-hadron + const AxisSpec axis_cosndphi_hh{cfgNbinsCosNDPhi, -1, +1, std::format("cos({0:d}(#varphi_{{h}}^{{ref1}} - #varphi_{{h}}^{{ref2}}))", cfgNmod.value)}; + fRegistry.add("HadronHadron/same/hDEtaCosNDPhi", "hadron-hadron 2PC", kTH2D, {axis_cosndphi_hh, axis_deta_hh}, true); + } + fRegistry.add("Dilepton/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); + } + + 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.SetRequireVertexTOFmatched(eventcuts.cfgRequireVertexTOFmatched); + 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_apply_detadphiposition, dielectroncuts.cfg_min_deta, dielectroncuts.cfg_min_dphi); + fDielectronCut.SetPairOpAng(0.f, 6.3); + 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, false, false); + 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(0.f, 16.f); + 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(-1e+10, +1e+10); + fDielectronCut.IncludeITSsa(false, 0.15); + + // for eID + fDielectronCut.SetPIDScheme(dielectroncuts.cfg_pid_scheme); + fDielectronCut.SetTPCNsigmaElRange(dielectroncuts.cfg_min_TPCNsigmaEl, dielectroncuts.cfg_max_TPCNsigmaEl); + 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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, dielectroncuts.cfg_max_pin_pirejTPC); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + std::vector binsML{}; + binsML.reserve(dielectroncuts.binsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(dielectroncuts.binsMl.value[i]); + } + std::vector thresholdsML{}; + thresholdsML.reserve(dielectroncuts.cutsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + + // static constexpr int nClassesMl = 2; + // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + // const std::vector labelsClasses = {"Background", "Signal"}; + // 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] = 0.; + // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; + // } + // 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, 20); + fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); + 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); }); + fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons + fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + } + + void DefineEMTrackCut() + { + fEMTrackCut = EMTrackCut("fEMTrackCut", "fEMTrackCut"); + fEMTrackCut.SetTrackPtRange(trackcuts.cfg_min_pt_track, trackcuts.cfg_max_pt_track); + fEMTrackCut.SetTrackEtaRange(trackcuts.cfg_min_eta_track, trackcuts.cfg_max_eta_track); + // fEMTrackCut.SetTrackPhiRange(trackcuts.cfg_min_phi_track, trackcuts.cfg_max_phi_track); + // fEMTrackCut.SetTrackMaxDcaXY(trackcuts.cfg_max_dcaxy); + // fEMTrackCut.SetTrackMaxDcaZ(trackcuts.cfg_max_dcaz); + fEMTrackCut.SetTrackBit(trackcuts.cfg_track_bits); + } + + template + bool fillDilepton(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks) + { + 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) || !cut.template IsSelectedTrack(t2)) { + 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, dielectroncuts.cfgRefR)) { + 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 constexpr (ev_id == 0) { + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(t1.globalIndex(), t2.globalIndex())]; + } + } + + 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)); + } + + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Dilepton/") + 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("Dilepton/") + 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("Dilepton/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), 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()); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (std::find(used_trackIds_per_col.begin(), used_trackIds_per_col.end(), t1.globalIndex()) == used_trackIds_per_col.end()) { + used_trackIds_per_col.emplace_back(t1.globalIndex()); + if (cfgDoMix) { + if (t1.sign() > 0) { + emh_pos->AddTrackToEventPool(key_df_collision, EMTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.dcaXY(), t1.dcaZ(), t1.cYY(), t1.cZY(), t1.cZZ())); + } else { + emh_neg->AddTrackToEventPool(key_df_collision, EMTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.dcaXY(), t1.dcaZ(), t1.cYY(), t1.cZY(), t1.cZZ())); + } + } + } + if (std::find(used_trackIds_per_col.begin(), used_trackIds_per_col.end(), t2.globalIndex()) == used_trackIds_per_col.end()) { + used_trackIds_per_col.emplace_back(t2.globalIndex()); + if (cfgDoMix) { + if (t2.sign() > 0) { + emh_pos->AddTrackToEventPool(key_df_collision, EMTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.dcaXY(), t2.dcaZ(), t2.cYY(), t2.cZY(), t2.cZZ())); + } else { + emh_neg->AddTrackToEventPool(key_df_collision, EMTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.dcaXY(), t2.dcaZ(), t2.cYY(), t2.cZY(), t2.cZZ())); + } + } + } + } else if (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (std::find(used_trackIds_per_col.begin(), used_trackIds_per_col.end(), t1.globalIndex()) == used_trackIds_per_col.end()) { + used_trackIds_per_col.emplace_back(t1.globalIndex()); + if (cfgDoMix) { + if (t1.sign() > 0) { + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); + } else { + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t1.pt(), t1.eta(), t1.phi(), leptonM1, t1.sign(), t1.fwdDcaX(), t1.fwdDcaY(), t1.cXXatDCA(), t1.cXYatDCA(), t1.cYYatDCA())); + } + } + } + if (std::find(used_trackIds_per_col.begin(), used_trackIds_per_col.end(), t2.globalIndex()) == used_trackIds_per_col.end()) { + used_trackIds_per_col.emplace_back(t2.globalIndex()); + if (cfgDoMix) { + if (t2.sign() > 0) { + emh_pos->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); + } else { + emh_neg->AddTrackToEventPool(key_df_collision, EMFwdTrack(t2.pt(), t2.eta(), t2.phi(), leptonM2, t2.sign(), t2.fwdDcaX(), t2.fwdDcaY(), t2.cXXatDCA(), t2.cXYatDCA(), t2.cYYatDCA())); + } + } + } + } + } + return true; + } + + template + bool fillDileptonHadron(TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const& tracks, TRefTrack const& t3) + { + // this function must be called, if dilepton passes the cut. + + 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) || !cut.template IsSelectedTrack(t2)) { + return false; + } + } else { // cut-based + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + return false; + } + } + if (t1.trackId() == t3.trackId() || t2.trackId() == t3.trackId()) { + 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 (!fEMTrackCut.IsSelected(t3)) { // for charged track + return false; + } + } + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (!cut.IsSelectedPair(t1, t2, d_bz, dielectroncuts.cfgRefR)) { + 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; + } + + 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; + + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), 0.139); // mass of hadron does not matter. + float deta = v12.Eta() - v3.Eta(); + float dphi = v12.Phi() - v3.Phi(); + + 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)); + } + + if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kAzimuthalCorrelation)) { + dphi = RecoDecay::constrainAngle(dphi, -M_PI / 2, 1U); + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("DileptonHadron/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), deta, dphi, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("DileptonHadron/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), deta, dphi, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("DileptonHadron/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), deta, dphi, weight); + } + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kCumulant)) { + o2::math_utils::bringTo02Pi(dphi); + float cosndphi = std::cos(cfgNmod * dphi); + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("DileptonHadron/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), deta, cosndphi, weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("DileptonHadron/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), deta, cosndphi, weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("DileptonHadron/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), deta, cosndphi, weight); + } + } + + return true; + } + + template + bool fillHadronHadron(TRefTrack const& t1, TRefTrack const& t2, TLeptons const& posLeptons, TLeptons const& negLeptons, TLeptonCut const& cut) + { + if constexpr (ev_id == 0) { + if (!fEMTrackCut.IsSelected(t1) || !fEMTrackCut.IsSelected(t2)) { // for charged track + return false; + } + + // Leptons should not be in reference track sample. + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + for (const auto& pos : posLeptons) { // leptons per collision + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(pos)) { + continue; + } + } else { // cut based + if (!cut.template IsSelectedTrack(pos)) { + continue; + } + } + if (t1.trackId() == pos.trackId() || t2.trackId() == pos.trackId()) { + return false; + } + } // end of pos lepton loop + + for (const auto& neg : negLeptons) { // leptons per collision + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { + if (!cut.template IsSelectedTrack(neg)) { + continue; + } + } else { // cut based + if (!cut.template IsSelectedTrack(neg)) { + continue; + } + } + if (t1.trackId() == neg.trackId() || t2.trackId() == neg.trackId()) { + return false; + } + } // end of neg lepton lopp + + } // end of if kDielectron + } // end of if same event + + float weight = 1.f; + float deta = t1.eta() - t2.eta(); // t1 is trigger, t2 is associated + float dphi = t1.phi() - t2.phi(); // t1 is trigger, t2 is associated + + if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kAzimuthalCorrelation)) { + dphi = RecoDecay::constrainAngle(dphi, -M_PI / 2, 1U); + fRegistry.fill(HIST("HadronHadron/") + HIST(event_pair_types[ev_id]) + HIST("hDEtaDPhi"), dphi, deta, weight); + } else if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kCumulant)) { + o2::math_utils::bringTo02Pi(dphi); + float cosndphi = std::cos(cfgNmod * dphi); + fRegistry.fill(HIST("HadronHadron/") + HIST(event_pair_types[ev_id]) + HIST("hDEtaCosNDPhi"), cosndphi, deta, weight); + } + 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 && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + 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_20MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_20MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_40MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_40MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_60MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_60MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_80MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_80MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_100MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_100MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_120MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_120MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_140MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_140MeV))) <= 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); + + using RefTracks = soa::Join; + using RefTrack = RefTracks::iterator; + Preslice perCollision_track = aod::emprimarytrack::emeventId; + Filter refTrackFilter = trackcuts.cfg_min_pt_track < 1 / nabs(o2::aod::emprimarytrack::signed1Pt) && 1 / nabs(o2::aod::emprimarytrack::signed1Pt) < trackcuts.cfg_max_pt_track && trackcuts.cfg_min_eta_track < o2::aod::emprimarytrack::eta && o2::aod::emprimarytrack::eta < trackcuts.cfg_max_eta_track; + using FilteredRefTracks = soa::Filtered; + using FilteredRefTrack = FilteredRefTracks::iterator; + + TEMH* emh_pos = nullptr; + TEMH* emh_neg = nullptr; + MyEMH_track* emh_ref = nullptr; // for reference flow + std::map, uint64_t> map_mixed_eventId_to_globalBC; + + std::vector used_trackIds_per_col; + int ndf = 0; + + template + void run2PC(TCollisions const& collisions, TLeptons const& posTracks, TLeptons const& negTracks, TPresilce const& perCollision, TCut const& cut, TAllTracks const& tracks, TRefTracks const& refTracks) + { + 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; + } + } + + 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 refTracks_per_coll = refTracks.sliceBy(perCollision_track, collision.globalIndex()); + + auto posTracks_per_coll = posTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + used_trackIds_per_col.reserve(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 = fillDilepton<0>(collision, pos, neg, cut, tracks); + if (is_pair_ok) { + nuls++; + for (const auto& refTrack : refTracks_per_coll) { + fillDileptonHadron<0>(pos, neg, cut, tracks, refTrack); + } + } + } + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + bool is_pair_ok = fillDilepton<0>(collision, pos1, pos2, cut, tracks); + if (is_pair_ok) { + nlspp++; + for (const auto& refTrack : refTracks_per_coll) { + fillDileptonHadron<0>(pos1, pos2, cut, tracks, refTrack); + } + } + } + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + bool is_pair_ok = fillDilepton<0>(collision, neg1, neg2, cut, tracks); + if (is_pair_ok) { + nlsmm++; + for (const auto& refTrack : refTracks_per_coll) { + fillDileptonHadron<0>(neg1, neg2, cut, tracks, refTrack); + } + } + } + used_trackIds_per_col.clear(); + used_trackIds_per_col.shrink_to_fit(); + + std::pair key_df_collision = std::make_pair(ndf, collision.globalIndex()); + + if (nuls > 0 || nlspp > 0 || nlsmm > 0) { // at least 1 pair exists. + emh_ref->ReserveNTracksPerCollision(key_df_collision, refTracks_per_coll.size()); + for (const auto& track : refTracks_per_coll) { + if (fEMTrackCut.IsSelected(track)) { + fRegistry.fill(HIST("Hadron/hs"), track.pt(), track.eta(), track.phi()); + fRegistry.fill(HIST("Hadron/hTrackBit"), track.trackBit()); + + // store ref tracks for mixed event in case of kAzimuthalCorrelation + if (cfgDoMix && cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kAzimuthalCorrelation)) { + emh_ref->AddTrackToEventPool(key_df_collision, EMTrack(track.pt(), track.eta(), track.phi(), 0.139)); + } // store ref tracks + } + } + for (const auto& [ref1, ref2] : combinations(CombinationsStrictlyUpperIndexPolicy(refTracks_per_coll, refTracks_per_coll))) { + fillHadronHadron<0>(ref1, ref2, posTracks_per_coll, negTracks_per_coll, cut); + } + } + + 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 = 0; + + 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; + } + + std::tuple key_bin = std::make_tuple(zbin, centbin, epbin, occbin); + + // make a vector of selected electrons 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); + + auto collisionIds_in_mixing_pool = emh_pos->GetCollisionIdsFromEventPool(key_bin); // pos/neg does not matter. + + // LOGF(info, "selected_posTracks_in_this_event.size() = %d, selected_negTracks_in_this_event.size() = %d, collisionIds_in_mixing_pool.size() = %d", selected_posTracks_in_this_event.size(), selected_negTracks_in_this_event.size(), collisionIds_in_mixing_pool.size()); + + // perform event mixing, only if at least 1 dilepton exists. + + 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("Dilepton/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, "posTracks_from_event_pool.size() = %d, negTracks_from_event_pool.size() = %d", 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) { + fillDilepton<1>(collision, pos, neg, cut, nullptr); + } + } + + for (const auto& neg : selected_negTracks_in_this_event) { // ULS mix + for (const auto& pos : posTracks_from_event_pool) { + fillDilepton<1>(collision, neg, pos, cut, nullptr); + } + } + + for (const auto& pos1 : selected_posTracks_in_this_event) { // LS++ mix + for (const auto& pos2 : posTracks_from_event_pool) { + fillDilepton<1>(collision, pos1, pos2, cut, nullptr); + } + } + + for (const auto& neg1 : selected_negTracks_in_this_event) { // LS-- mix + for (const auto& neg2 : negTracks_from_event_pool) { + fillDilepton<1>(collision, neg1, neg2, cut, nullptr); + } + } + } // end of loop over mixed event pool for lepton-lepton + + if (cfgAnalysisType == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonHadronAnalysisType::kAzimuthalCorrelation)) { + auto selected_refTracks_in_this_event = emh_ref->GetTracksPerCollision(key_df_collision); + auto collisionIds_in_mixing_pool_hadron = emh_ref->GetCollisionIdsFromEventPool(key_bin); + + for (const auto& mix_dfId_collisionId : collisionIds_in_mixing_pool_hadron) { + 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("HadronHadron/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto refTracks_from_event_pool = emh_ref->GetTracksPerCollision(mix_dfId_collisionId); + // LOGF(info, "selected_refTracks_in_this_event.size() = %d, collisionIds_in_mixing_pool_hadron.size() = %d, refTracks_from_event_pool.size() = %d", selected_refTracks_in_this_event.size(), collisionIds_in_mixing_pool_hadron.size(), refTracks_from_event_pool.size()); + for (const auto& ref1 : selected_refTracks_in_this_event) { // ref-ref mix + for (const auto& ref2 : refTracks_from_event_pool) { + // LOGF(info, "ref1.pt() = %f, ref2.pt() = %f", ref1.pt(), ref2.pt()); + fillHadronHadron<1>(ref1, ref2, nullptr, nullptr, nullptr); + } + } + } // end of loop over mixed event pool for hadron-hadron + } + + 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); + emh_ref->AddCollisionIdAtLast(key_bin, key_df_collision); + } + + } // end of collision loop + + } // end of DF + + template + bool isPairOK(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) || !cut.template IsSelectedTrack(t2)) { + 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, dielectroncuts.cfgRefR)) { + 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; + } + } + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + 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(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(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(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)); + + 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, FilteredRefTracks const& refTracks, 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); + } + run2PC(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, electrons, refTracks); + } 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); + } + run2PC(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons, refTracks); + } + map_weight.clear(); + ndf++; + } + PROCESS_SWITCH(DileptonHadronMPC, processAnalysis, "run dilepton analysis", true); + + using FilteredMyCollisionsWithSWT = soa::Filtered; + void processTriggerAnalysis(FilteredMyCollisionsWithSWT const& collisions, FilteredRefTracks const& refTracks, aod::EMSWTriggerInfos const& cefpinfos, aod::EMSWTriggerATCounters const& countersAT, aod::EMSWTriggerTOICounters const& countersTOI, 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); + } + run2PC(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, electrons, refTracks); + } 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); + } + run2PC(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, muons, refTracks); + } + map_weight.clear(); + ndf++; + + // for nomalization + int emswtId = o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value); + for (const auto& counter : countersAT) { + if (counter.isAnalyzed_bit(emswtId)) { + fRegistry.fill(HIST("NormTrigger/hTriggerCounter"), mRunNumber, 0); + } + } + for (const auto& counter : countersTOI) { + if (counter.isAnalyzedToI_bit(emswtId)) { + fRegistry.fill(HIST("NormTrigger/hTriggerCounter"), mRunNumber, 1); + } + } + + for (const auto& info : cefpinfos) { + fRegistry.fill(HIST("NormTrigger/hInspectedTVX"), info.runNumber(), info.nInspectedTVX()); + fRegistry.fill(HIST("NormTrigger/hScalers"), info.runNumber(), info.nScalers()[emswtId]); + fRegistry.fill(HIST("NormTrigger/hSelections"), info.runNumber(), info.nSelections()[emswtId]); + } + } + PROCESS_SWITCH(DileptonHadronMPC, processTriggerAnalysis, "run dilepton analysis on triggered data", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(DileptonHadronMPC, processDummy, "Dummy function", false); +}; + +#endif // PWGEM_DILEPTON_CORE_DILEPTONHADRONMPC_H_ diff --git a/PWGEM/Dilepton/Core/DileptonMC.h b/PWGEM/Dilepton/Core/DileptonMC.h index 4b21267d2b2..c5b976f0405 100644 --- a/PWGEM/Dilepton/Core/DileptonMC.h +++ b/PWGEM/Dilepton/Core/DileptonMC.h @@ -17,38 +17,43 @@ #ifndef PWGEM_DILEPTON_CORE_DILEPTONMC_H_ #define PWGEM_DILEPTON_CORE_DILEPTONMC_H_ -#include -#include +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" -#include "TString.h" -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" -#include "DataFormatsParameters/GRPLHCIFData.h" #include "DataFormatsParameters/GRPECSObject.h" - -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" #include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "Tools/ML/MlResponse.h" -#include "Tools/ML/model.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "DCAFitter/DCAFitterN.h" -#include "DCAFitter/FwdDCAFitterN.h" +#include "Math/Vector4D.h" +#include "TString.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 +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -57,16 +62,20 @@ 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 MyMCElectrons = soa::Join; +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 MyMCMuons = soa::Join; using MyMCMuon = MyMCMuons::iterator; using FilteredMyMCMuons = soa::Filtered; using FilteredMyMCMuon = FilteredMyMCMuons::iterator; @@ -88,31 +97,72 @@ struct DileptonMC { 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, NTPV:3"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + 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", -1, "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 cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; + 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"}; + Configurable cfgFillSeparateCharmHadronPairs{"cfgFillSeparateCharmHadronPairs", false, "flag to fill different ccbar pairs separately"}; 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 ConfDPtBins{"ConfDPtBins", {220, -1.0, +10.0}, "dpt bins for output histograms"}; + ConfigurableAxis ConfDCAllNarrowBins{"ConfDCAllNarrowBins", {200, 0.0, 10.0}, "narrow DCAll bins for output histograms"}; + ConfigurableAxis ConfTrackDCA{"ConfTrackDCA", {VARIABLE_WIDTH, -10, -9, -8, -7, -6, -5, -4.5, -4, -3.5, -3, -2.5, -2, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.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.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10}, "DCA binning for single tacks"}; + + ConfigurableAxis ConfYllBins{"ConfYllBins", {1, -1.f, +1.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"}; // 10 + 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 + ConfigurableAxis ConfPolarizationCosThetaBins{"ConfPolarizationCosThetaBins", {1, -1.f, 1.f}, "cos(theta) bins for polarization analysis"}; + ConfigurableAxis ConfPolarizationPhiBins{"ConfPolarizationPhiBins", {1, -M_PI, M_PI}, "phi bins for polarization analysis"}; + Configurable cfgPolarizationFrame{"cfgPolarizationFrame", 0, "frame of polarization. 0:CS, 1:HX, else:FATAL"}; + ConfigurableAxis ConfPolarizationQuadMomBins{"ConfPolarizationQuadMomBins", {1, -0.5, 1}, "quadrupole moment bins for polarization analysis"}; // quardrupole moment <(3 x cos^2(theta) -1)/2> + 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 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 cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF 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"}; + 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_hadronPID, 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; @@ -126,30 +176,56 @@ struct DileptonMC { 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_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_apply_detadphi{"cfg_apply_detadphi", false, "flag to apply deta-dphi elliptic cut at PV"}; + 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_20MeV : 2, kElFromPi0_40MeV : 4, kElFromPi0_60MeV : 8, kElFromPi0_80MeV : 16, kElFromPi0_100MeV : 32, kElFromPi0_120MeV : 64, kElFromPi0_140MeV : 128] 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_min_eta_track{"cfg_min_eta_track", -0.8, "max eta 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_mirror_phi_track{"cfg_mirror_phi_track", false, "mirror the phi cut around Pi, min and max Phi should be in 0-Pi"}; + Configurable cfg_reject_phi_track{"cfg_reject_phi_track", false, "reject the phi interval"}; 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_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_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3]"}; + 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_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 cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. + Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; + Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; + + 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_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"}; @@ -158,11 +234,19 @@ struct DileptonMC { 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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; - - // CCDB configuration for PID ML - Configurable BDTLocalPathGamma{"BDTLocalPathGamma", "pid_ml_xgboost.onnx", "Path to the local .onnx file"}; - Configurable BDTPathCCDB{"BDTPathCCDB", "Users/d/dsekihat/pwgem/pidml/", "Path on CCDB"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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)"}; @@ -179,126 +263,218 @@ struct DileptonMC { 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.1, "min pT for single track"}; + 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+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_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; + 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"}; + Configurable cfg_max_relDPt_wrt_matchedMCHMID{"cfg_max_relDPt_wrt_matchedMCHMID", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DEta_wrt_matchedMCHMID{"cfg_max_DEta_wrt_matchedMCHMID", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; + Configurable rejectWrongMatch{"rejectWrongMatch", false, "flag to reject wrong match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. } dimuoncuts; + o2::aod::rctsel::RCTFlagsChecker rctChecker; o2::ccdb::CcdbApi ccdbApi; Service ccdb; - // o2::vertexing::DCAFitterN<2> fitter; - // o2::vertexing::FwdDCAFitterN<2> fwdfitter; - // o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + 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"}; - Configurable max_mcPt{"max_mcPt", 1e+10, "max. MC pT"}; - Configurable min_mcEta{"min_mcEta", -0.8, "max. MC eta"}; - Configurable max_mcEta{"max_mcEta", +0.8, "max. MC eta"}; + 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() - { - if (eid_bdt) { - delete eid_bdt; - } - } + static constexpr std::string_view pair_sign_types[3] = {"uls/", "lspp/", "lsmm/"}; + static constexpr std::string_view dilepton_source_types[20] = { + "sm/Photon/", // 0 + "sm/PromptPi0/", // 1 + "sm/NonPromptPi0/", // 2 + "sm/Eta/", // 3 + "sm/EtaPrime/", // 4 + "sm/Rho/", // 5 + "sm/Omega/", // 6 + "sm/Phi/", // 7 + "sm/PromptJPsi/", // 8 + "sm/NonPromptJPsi/", // 9 + "sm/PromptPsi2S/", // 10 + "sm/NonPromptPsi2S/", // 11 + "sm/Upsilon1S/", // 12 + "sm/Upsilon2S/", // 13 + "sm/Upsilon3S/", // 14 + "ccbar/c2l_c2l/", // 15 + "bbbar/b2l_b2l/", // 16 + "bbbar/b2c2l_b2c2l/", // 17 + "bbbar/b2c2l_b2l_sameb/", // 18 + "bbbar/b2c2l_b2l_diffb/" // 19 + }; // unordered_map is better, but cannot be constexpr. + static constexpr std::string_view unfolding_dilepton_source_types[3] = {"sm/", "ccbar/", "bbbar/"}; + + ~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)"; - 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) { 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)"; - nbin_y = 20; - min_y = -1.0; - max_y = +1.0; + 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)"; - nbin_y = 25; - min_y = -4.5; - max_y = -2.0; } // pair info const AxisSpec axis_mass{ConfMllBins, mass_axis_title}; const AxisSpec axis_pt{ConfPtllBins, pair_pt_axis_title}; - const AxisSpec axis_y{nbin_y, min_y, max_y, pair_y_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{nbin_y, min_y, max_y, "y"}; // rapidity of meson + const AxisSpec axis_pt_meson{ConfPtllBins, "p_{T}^{VM} (GeV/c)"}; // for omega, phi meson pT spectra + const AxisSpec axis_y_meson{ConfYllBins, "y^{VM}"}; // for omega, phi meson pT spectra + + const AxisSpec axis_dca_narrow{ConfDCAllNarrowBins, pair_dca_axis_title}; + const AxisSpec axis_dpt{ConfDPtBins, "#Delta p_{T,1}^{gen-rec} + #Delta p_{T,2}^{gen-rec} (GeV/c)"}; + const AxisSpec axis_dca_track1{ConfTrackDCA, "DCA_{e,1}^{Z} (#sigma)"}; + const AxisSpec axis_dca_track2{ConfTrackDCA, "DCA_{e,2}^{Z} (#sigma)"}; + + std::string frameName = "CS"; + if (cfgPolarizationFrame == 0) { + frameName = "CS"; + } else if (cfgPolarizationFrame == 1) { + frameName = "HX"; + } else { + LOG(fatal) << "set 0 or 1 to cfgPolarizationFrame!"; + } - const AxisSpec axis_dphi_ee{18, 0, M_PI, "#Delta#varphi = #varphi_{l1} - #varphi_{l2} (rad.)"}; // for kHFll - const AxisSpec axis_cos_theta_cs{10, 0.f, 1.f, "|cos(#theta_{CS})|"}; // for kPolarization - const AxisSpec axis_phi_cs{18, 0.f, M_PI, "|#varphi_{CS}| (rad.)"}; // for kPolarization - const AxisSpec axis_aco{10, 0, 1.f, "#alpha = 1 - #frac{|#varphi_{l^{+}} - #varphi_{l^{-}}|}{#pi}"}; // for kUPC - const AxisSpec axis_asym_pt{10, 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{18, 0, M_PI, "#Delta#varphi = #varphi_{l} - #varphi_{ll} (rad.)"}; // for kUPC + 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_pol{ConfPolarizationCosThetaBins, Form("cos(#theta^{%s})", frameName.data())}; // for kPolarization, kUPC + const AxisSpec axis_phi_pol{ConfPolarizationPhiBins, Form("#varphi^{%s} (rad.)", frameName.data())}; // for kPolarization + const AxisSpec axis_quadmom{ConfPolarizationQuadMomBins, Form("#frac{3 cos^{2}(#theta^{%s}) -1}{2}", frameName.data())}; // 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/Pi0/hs", "gen. dilepton signal", kTHnSparseF, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_cos_theta_cs, axis_phi_cs, axis_aco, axis_asym_pt, axis_dphi_e_ee}, 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/Omega2ll/"); - fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Phi/"); - fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Phi2ll/"); - fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/PromptJPsi/"); - fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/NonPromptJPsi/"); - fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/PromptPsi2S/"); - fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/NonPromptPsi2S/"); - fRegistry.add("Generated/sm/Omega2ll/hPt", "pT of #omega meson", kTH1F, {axis_pt_meson}, true); - fRegistry.add("Generated/sm/Omega2ll/hY", "rapidity of #omega meson", kTH1F, {axis_y_meson}, true); - fRegistry.add("Generated/sm/Phi2ll/hPt", "pT of #phi meson", kTH1F, {axis_pt_meson}, true); - fRegistry.add("Generated/sm/Phi2ll/hY", "rapidity of #phi meson", kTH1F, {axis_y_meson}, true); - - fRegistry.add("Generated/ccbar/c2l_c2l/hadron_hadron/hs", "generated dilepton signal", kTHnSparseF, {axis_mass, axis_pt, axis_y, axis_dphi_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.add("Generated/sm/PromptPi0/uls/hs", "gen. dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_pol, axis_phi_pol, axis_quadmom, axis_aco, axis_asym_pt, axis_dphi_e_ee}, true); + fRegistry.addClone("Generated/sm/PromptPi0/uls/", "Generated/sm/PromptPi0/lspp/"); + fRegistry.addClone("Generated/sm/PromptPi0/uls/", "Generated/sm/PromptPi0/lsmm/"); + + 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.addClone("Generated/sm/PromptPi0/", "Generated/sm/Upsilon1S/"); + // fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/Upsilon2S/"); + // fRegistry.addClone("Generated/sm/PromptPi0/", "Generated/sm/Upsilon3S/"); + + fRegistry.add("Generated/ccbar/c2l_c2l/uls/hs", "generated dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_pol, axis_phi_pol, axis_quadmom, axis_aco, axis_asym_pt, axis_dphi_e_ee}, true); + fRegistry.addClone("Generated/ccbar/c2l_c2l/uls/", "Generated/ccbar/c2l_c2l/lspp/"); + fRegistry.addClone("Generated/ccbar/c2l_c2l/uls/", "Generated/ccbar/c2l_c2l/lsmm/"); + 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 - // reconstructed pair info - fRegistry.add("Pair/sm/Photon/hs", "rec. dilepton signal", kTHnSparseF, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_cos_theta_cs, axis_phi_cs, axis_aco, axis_asym_pt, axis_dphi_e_ee, axis_dca}, true); - 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, 0.1f}}, true); + // 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"}; + + if (cfgFillSeparateCharmHadronPairs) { + for (int im = 0; im < nm; im++) { + fRegistry.addClone("Generated/ccbar/c2l_c2l/", Form("Generated/ccbar/%s_%s/", charmed_mesons[im].data(), anti_charmed_mesons[im].data())); + } + for (int ib = 0; ib < nb; ib++) { + fRegistry.addClone("Generated/ccbar/c2l_c2l/", Form("Generated/ccbar/%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/", Form("Generated/ccbar/%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/", Form("Generated/ccbar/%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/", Form("Generated/ccbar/%s_%s/", sum_charmed_mesons[im].data(), sum_charmed_baryons[ib].data())); + } + } } - fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Pi0/"); + + // evaluate acceptance for polarization + fRegistry.add("Generated/VM/All/Phi/hs", "gen. VM #rightarrow ll", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_cos_theta_pol, axis_phi_pol, axis_quadmom}, true); + fRegistry.addClone("Generated/VM/All/Phi/", "Generated/VM/All/Rho/"); + fRegistry.addClone("Generated/VM/All/Phi/", "Generated/VM/All/Omega/"); + fRegistry.addClone("Generated/VM/All/Phi/", "Generated/VM/All/PromptJPsi/"); + fRegistry.addClone("Generated/VM/All/Phi/", "Generated/VM/All/NonPromptJPsi/"); + fRegistry.addClone("Generated/VM/All/", "Generated/VM/Acc/"); + + // reconstructed pair info + fRegistry.add("Pair/sm/Photon/uls/hs", "rec. dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_pol, axis_phi_pol, axis_quadmom, axis_aco, axis_asym_pt, axis_dphi_e_ee, axis_dca}, true); + + fRegistry.addClone("Pair/sm/Photon/uls/", "Pair/sm/Photon/lspp/"); + fRegistry.addClone("Pair/sm/Photon/uls/", "Pair/sm/Photon/lsmm/"); + 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/"); @@ -310,22 +486,88 @@ struct DileptonMC { fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/NonPromptJPsi/"); fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/PromptPsi2S/"); fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/NonPromptPsi2S/"); + // fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Upsilon1S/"); + // fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Upsilon2S/"); + // fRegistry.addClone("Pair/sm/Photon/", "Pair/sm/Upsilon3S/"); + + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + fRegistry.add("Pair/sm/Photon/uls/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/uls/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); + for (const auto& strSign : pair_sign_types) { + fRegistry.add(std::format("Pair/sm/PromptPi0/{0}hMvsPhiV", strSign), "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(std::format("Pair/sm/PromptPi0/{0}hDeltaPtvsDCA", strSign), "#Delta p_{T,1}^{gen-rec} + #Delta p_{T,2}^{gen-rec} vs. DCA_{ee}", kTH2F, {axis_dca_narrow, axis_dpt}, true); + fRegistry.add(std::format("Pair/sm/PromptPi0/{0}hDCAz1vsDCAz2", strSign), "DCA_{z,1} vs DCA_{z,2}", kTH2F, {axis_dca_track1, axis_dca_track2}, true); + + fRegistry.add(std::format("Pair/sm/NonPromptPi0/{0}hMvsPhiV", strSign), "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(std::format("Pair/sm/NonPromptPi0/{0}hDeltaPtvsDCA", strSign), "#Delta p_{T,1}^{gen-rec} + #Delta p_{T,2}^{gen-rec} vs. DCA_{ee}", kTH2F, {axis_dca_narrow, axis_dpt}, true); + fRegistry.add(std::format("Pair/sm/NonPromptPi0/{0}hDCAz1vsDCAz2", strSign), "DCA_{z,1} vs DCA_{z,2}", kTH2F, {axis_dca_track1, axis_dca_track2}, true); + + fRegistry.add(std::format("Pair/sm/PromptJPsi/{0}hDeltaPtvsDCA", strSign), "#Delta p_{T,1}^{gen-rec} + #Delta p_{T,2}^{gen-rec} vs. DCA_{ee}", kTH2F, {axis_dca_narrow, axis_dpt}, true); + fRegistry.add(std::format("Pair/sm/PromptJPsi/{0}hDCAz1vsDCAz2", strSign), "DCA_{z,1} vs DCA_{z,2}", kTH2F, {axis_dca_track1, axis_dca_track2}, true); + fRegistry.add(std::format("Pair/sm/NonPromptJPsi/{0}hDeltaPtvsDCA", strSign), "#Delta p_{T,1}^{gen-rec} + #Delta p_{T,2}^{gen-rec} vs. DCA_{ee}", kTH2F, {axis_dca_narrow, axis_dpt}, true); + fRegistry.add(std::format("Pair/sm/NonPromptJPsi/{0}hDCAz1vsDCAz2", strSign), "DCA_{z,1} vs DCA_{z,2}", kTH2F, {axis_dca_track1, axis_dca_track2}, true); + } + } + + fRegistry.add("Pair/ccbar/c2l_c2l/uls/hs", "rec. dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_y, axis_dphi_ee, axis_deta_ee, axis_cos_theta_pol, axis_phi_pol, axis_quadmom, axis_aco, axis_asym_pt, axis_dphi_e_ee, axis_dca}, true); + fRegistry.addClone("Pair/ccbar/c2l_c2l/uls/", "Pair/ccbar/c2l_c2l/lspp/"); + fRegistry.addClone("Pair/ccbar/c2l_c2l/uls/", "Pair/ccbar/c2l_c2l/lsmm/"); - fRegistry.add("Pair/ccbar/c2l_c2l/hadron_hadron/hs", "hs pair", kTHnSparseF, {axis_mass, axis_pt, axis_y, axis_dphi_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 + if (cfgFillSeparateCharmHadronPairs) { + for (int im = 0; im < nm; im++) { + fRegistry.addClone("Pair/ccbar/c2l_c2l/", Form("Pair/ccbar/%s_%s/", charmed_mesons[im].data(), anti_charmed_mesons[im].data())); + } + for (int ib = 0; ib < nb; ib++) { + fRegistry.addClone("Pair/ccbar/c2l_c2l/", Form("Pair/ccbar/%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/", Form("Pair/ccbar/%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/", Form("Pair/ccbar/%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/", Form("Pair/ccbar/%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_eh/uls/hs", "rec. bkg", kTHnSparseF, {axis_mass, axis_pt, axis_y, axis_dphi_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_eh/uls/", "Pair/corr_bkg_eh/lspp/"); - fRegistry.addClone("Pair/corr_bkg_eh/uls/", "Pair/corr_bkg_eh/lsmm/"); - fRegistry.addClone("Pair/corr_bkg_eh/", "Pair/corr_bkg_hh/"); - fRegistry.addClone("Pair/corr_bkg_eh/", "Pair/comb_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_pol, axis_phi_pol, axis_quadmom, 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 (doprocessGen_VM) { + fRegistry.add("Generated/VM/Omega/hPtY", "pT vs. y of #omega", kTH2D, {axis_y_meson, axis_pt_meson}, true); // for pT spectrum + fRegistry.add("Generated/VM/Phi/hPtY", "pT vs. y of #phi", kTH2D, {axis_y_meson, axis_pt_meson}, true); // for pT spectrum + } + + 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/sm/uls/hsRM", "response matrix", kTHnSparseD, {axis_mass_gen, axis_pt_gen, axis_mass_rec, axis_pt_rec}, true); + fRegistry.add("Unfold/sm/uls/hMiss", "missing dilepton", 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/sm/uls/hFake", "fake dilepton", 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/sm/uls/", "Unfold/sm/lspp/"); + fRegistry.addClone("Unfold/sm/uls/", "Unfold/sm/lsmm/"); + fRegistry.addClone("Unfold/sm/", "Unfold/ccbar/"); + fRegistry.addClone("Unfold/sm/", "Unfold/bbbar/"); + } } float beamM1 = o2::constants::physics::MassProton; // mass of beam @@ -351,6 +593,7 @@ struct DileptonMC { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + rctChecker.init(eventcuts.cfgRCTLabel.value, eventcuts.cfgCheckZDC.value, eventcuts.cfgTreatLimitedAcceptanceAsBad.value); DefineEMEventCut(); addhistograms(); @@ -360,27 +603,23 @@ struct DileptonMC { leptonM1 = o2::constants::physics::MassElectron; leptonM2 = o2::constants::physics::MassElectron; pdg_lepton = 11; - // fitter.setPropagateToPCA(true); - // fitter.setMaxR(5.f); - // fitter.setMinParamChange(1e-3); - // fitter.setMinRelChi2Change(0.9); - // fitter.setMaxDZIni(1e9); - // fitter.setMaxChi2(1e9); - // fitter.setUseAbsDCA(true); - // fitter.setWeightedFinalPCA(false); - // fitter.setMatCorrType(matCorr); } 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; - // fwdfitter.setPropagateToPCA(true); - // fwdfitter.setMaxR(90.f); - // fwdfitter.setMinParamChange(1e-3); - // fwdfitter.setMinRelChi2Change(0.9); - // fwdfitter.setMaxChi2(1e9); - // fwdfitter.setUseAbsDCA(true); - // fwdfitter.setTGeoMat(false); + } + 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"); } } @@ -395,12 +634,11 @@ struct DileptonMC { 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); mRunNumber = collision.runNumber(); - // fitter.setBz(d_bz); - // fwdfitter.setBz(d_bz); return; } @@ -410,28 +648,22 @@ struct DileptonMC { 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"; + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kG"; } 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"; + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kG"; } mRunNumber = collision.runNumber(); - // fitter.setBz(d_bz); - // fwdfitter.setBz(d_bz); - - //// for muon - // o2::base::Propagator::initFieldFromGRP(grpmag); - // if (!o2::base::GeometryManager::isGeometryLoaded()) { - // ccdb->get(geoPath); - // } - // o2::mch::TrackExtrap::setField(); + fDielectronCut.SetTrackPhiPositionRange(dielectroncuts.cfg_min_phiposition_track, dielectroncuts.cfg_max_phiposition_track, dielectroncuts.cfgRefR, d_bz, dielectroncuts.cfg_mirror_phi_track); auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", collision.timestamp()); int beamZ1 = grplhcif->getBeamZ(o2::constants::lhc::BeamC); @@ -452,16 +684,24 @@ struct DileptonMC { fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); - fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireVertexTOFmatched(eventcuts.cfgRequireVertexTOFmatched); fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); + 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::ml::OnnxModel* eid_bdt = nullptr; + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -471,51 +711,79 @@ struct DileptonMC { 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.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dielectroncuts.cfg_phiv_intercept) / dielectroncuts.cfg_phiv_slope; }); + 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); + fDielectronCut.SetMindEtadPhi(dielectroncuts.cfg_apply_detadphi, false, 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, 1e+10f); - fDielectronCut.SetTrackEtaRange(-dielectroncuts.cfg_max_eta_track, +dielectroncuts.cfg_max_eta_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, dielectroncuts.cfg_mirror_phi_track, dielectroncuts.cfg_reject_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.SetMeanClusterSizeITSob(0, 16); - fDielectronCut.SetMaxDcaXY(dielectroncuts.cfg_max_dcaxy); - fDielectronCut.SetMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); // 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.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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, dielectroncuts.cfg_max_pin_pirejTPC); - if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDielectronCut - // o2::ml::OnnxModel* eid_bdt = new o2::ml::OnnxModel(); - eid_bdt = new o2::ml::OnnxModel(); - if (dielectroncuts.loadModelsFromCCDB) { - ccdbApi.init(ccdburl); - std::map metadata; - bool retrieveSuccessGamma = ccdbApi.retrieveBlob(dielectroncuts.BDTPathCCDB.value, ".", metadata, dielectroncuts.timestampCCDB.value, false, dielectroncuts.BDTLocalPathGamma.value); - if (retrieveSuccessGamma) { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); - } else { - LOG(fatal) << "Error encountered while fetching/loading the Gamma model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; - } - } else { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + std::vector binsML{}; + binsML.reserve(dielectroncuts.binsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(dielectroncuts.binsMl.value[i]); } - - fDielectronCut.SetPIDModel(eid_bdt); + std::vector thresholdsML{}; + thresholdsML.reserve(dielectroncuts.cutsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + + // static constexpr int nClassesMl = 2; + // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + // const std::vector labelsClasses = {"Background", "Signal"}; + // 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] = 0.; + // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; + // } + // 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 } @@ -528,38 +796,73 @@ struct DileptonMC { 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, 1e10f); + 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.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); 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); }); + fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons + fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + } + + template + int FindSMULS(TTrack const& t1mc, TTrack const& t2mc, TMCParticles const& mcparticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 22, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 111, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 221, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 331, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 113, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 223, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 333, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 443, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 100443, mcparticles) + // FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 553, mcparticles), + // FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 100553, mcparticles), + // FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, pdg_lepton, 200553, mcparticles) + }; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; + } + + template + int FindSMLSPP(TTrack const& t1mc, TTrack const& t2mc, TMCParticles const& mcparticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, -pdg_lepton, 111, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, -pdg_lepton, 221, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, -pdg_lepton, 331, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, -pdg_lepton, 113, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, -pdg_lepton, 223, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -pdg_lepton, -pdg_lepton, 333, mcparticles)}; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; } template - int FindLF(TTrack const& posmc, TTrack const& negmc, TMCParticles const& mcparticles) + int FindSMLSMM(TTrack const& t1mc, TTrack const& t2mc, 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)}; + FindCommonMotherFrom2Prongs(t1mc, t2mc, pdg_lepton, pdg_lepton, 111, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, pdg_lepton, pdg_lepton, 221, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, pdg_lepton, pdg_lepton, 331, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, pdg_lepton, pdg_lepton, 113, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, pdg_lepton, pdg_lepton, 223, mcparticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, pdg_lepton, pdg_lepton, 333, mcparticles)}; int size = sizeof(arr) / sizeof(*arr); int max = *std::max_element(arr, arr + size); return max; @@ -590,6 +893,17 @@ struct DileptonMC { eta = lepton.eta(); } + return isInAcceptance(pt, eta); + + // if ((mctrackcuts.min_mcPt < pt && pt < mctrackcuts.max_mcPt) && (mctrackcuts.min_mcEta < eta && eta < mctrackcuts.max_mcEta)) { + // return true; + // } else { + // return false; + // } + } + + bool isInAcceptance(const float pt, const float eta) + { if ((mctrackcuts.min_mcPt < pt && pt < mctrackcuts.max_mcPt) && (mctrackcuts.min_mcEta < eta && eta < mctrackcuts.max_mcEta)) { return true; } else { @@ -597,315 +911,1138 @@ struct DileptonMC { } } - template - bool fillTruePairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TMCParticles const& mcparticles) + template + void fillGenHistograms(const int sign1, const int sign2, const int pdgMotherC1, const int pdgMotherC2, const float mass, const float pt, const float rapidity, const float dphi, const float deta, const float cos_thetaPol, const float phiPol, const float quadmom, const float aco, const float asym, const float dphi_e_ee, const float weight) + { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/") + HIST(dilepton_source_types[sourceId]) + HIST("uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/") + HIST(dilepton_source_types[sourceId]) + HIST("lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/") + HIST(dilepton_source_types[sourceId]) + HIST("lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + + if (dilepton_source_types[sourceId].find("ccbar") != std::string_view::npos && cfgFillSeparateCharmHadronPairs) { + if (std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 411) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dplus_Dminus/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dplus_Dminus/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dplus_Dminus/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if (std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 421) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/D0_D0bar/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/D0_D0bar/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/D0_D0bar/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if (std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 431) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dsplus_Dsminus/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dsplus_Dsminus/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dsplus_Dsminus/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 421) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 421)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dpm_D0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dpm_D0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dpm_D0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 431) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 431)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dpm_Dspm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dpm_Dspm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dpm_Dspm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 431) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 431)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/D0_Dspm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/D0_Dspm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/D0_Dspm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if (std::abs(pdgMotherC1) == 4122 && std::abs(pdgMotherC2) == 4122) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Lcplus_Lcminus/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Lcplus_Lcminus/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Lcplus_Lcminus/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if (std::abs(pdgMotherC1) == 4232 && std::abs(pdgMotherC2) == 4232) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Xicplus_Xicminus/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Xicplus_Xicminus/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Xicplus_Xicminus/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if (std::abs(pdgMotherC1) == 4132 && std::abs(pdgMotherC2) == 4132) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Xic0_Xic0bar/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Xic0_Xic0bar/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Xic0_Xic0bar/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if (std::abs(pdgMotherC1) == 4332 && std::abs(pdgMotherC2) == 4332) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Omegac0_Omegac0bar/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Omegac0_Omegac0bar/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Omegac0_Omegac0bar/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 4122 && std::abs(pdgMotherC2) == 4232) || (std::abs(pdgMotherC2) == 4122 && std::abs(pdgMotherC1) == 4232)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Xicpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Xicpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Xicpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 4122 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 4122 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 4122 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 4122 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Lcpm_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 4232 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 4232 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Xicpm_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Xicpm_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Xicpm_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 4232 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 4232 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Xicpm_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Xicpm_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Xicpm_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 4132 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 4132 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Xic0_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Xic0_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Xic0_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 4122) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 4122)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dpm_Lcpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dpm_Lcpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dpm_Lcpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 4232) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 4232)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dpm_Xicpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dpm_Xicpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dpm_Xicpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dpm_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dpm_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dpm_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dpm_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dpm_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dpm_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 4122) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 4122)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/D0_Lcpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/D0_Lcpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/D0_Lcpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 4232) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 4232)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/D0_Xicpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/D0_Xicpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/D0_Xicpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/D0_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/D0_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/D0_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/D0_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/D0_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/D0_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 4122) || (std::abs(pdgMotherC2) == 431 && std::abs(pdgMotherC1) == 4122)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dspm_Lcpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dspm_Lcpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dspm_Lcpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 4232) || (std::abs(pdgMotherC2) == 431 && std::abs(pdgMotherC1) == 4232)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dspm_Xicpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dspm_Xicpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dspm_Xicpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 431 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dspm_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dspm_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dspm_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } else if ((std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 431 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Generated/ccbar/Dspm_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Generated/ccbar/Dspm_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Generated/ccbar/Dspm_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, weight); + } + } + } + } + + template + void fillRecHistograms(const int sign1, const int sign2, const int pdgMotherC1, const int pdgMotherC2, const float mass, const float pt, const float rapidity, const float dphi, const float deta, const float cos_thetaPol, const float phiPol, const float quadmom, const float aco, const float asym, const float dphi_e_ee, const float pair_dca, const float weight) + { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(dilepton_source_types[sourceId]) + HIST("uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(dilepton_source_types[sourceId]) + HIST("lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(dilepton_source_types[sourceId]) + HIST("lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + + if (dilepton_source_types[sourceId].find("ccbar") != std::string_view::npos && cfgFillSeparateCharmHadronPairs) { + if (std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 411) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dplus_Dminus/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dplus_Dminus/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dplus_Dminus/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if (std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 421) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/D0_D0bar/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/D0_D0bar/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/D0_D0bar/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if (std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 431) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dsplus_Dsminus/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dsplus_Dsminus/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dsplus_Dsminus/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 421) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 421)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dpm_D0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dpm_D0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dpm_D0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 431) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 431)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dpm_Dspm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dpm_Dspm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dpm_Dspm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 431) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 431)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/D0_Dspm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/D0_Dspm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/D0_Dspm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if (std::abs(pdgMotherC1) == 4122 && std::abs(pdgMotherC2) == 4122) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Lcplus_Lcminus/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Lcplus_Lcminus/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Lcplus_Lcminus/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if (std::abs(pdgMotherC1) == 4232 && std::abs(pdgMotherC2) == 4232) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Xicplus_Xicminus/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Xicplus_Xicminus/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Xicplus_Xicminus/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if (std::abs(pdgMotherC1) == 4132 && std::abs(pdgMotherC2) == 4132) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Xic0_Xic0bar/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Xic0_Xic0bar/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Xic0_Xic0bar/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if (std::abs(pdgMotherC1) == 4332 && std::abs(pdgMotherC2) == 4332) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Omegac0_Omegac0bar/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Omegac0_Omegac0bar/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Omegac0_Omegac0bar/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 4122 && std::abs(pdgMotherC2) == 4232) || (std::abs(pdgMotherC2) == 4122 && std::abs(pdgMotherC1) == 4232)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Xicpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Xicpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Xicpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 4122 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 4122 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 4122 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 4122 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Lcpm_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 4232 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 4232 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Xicpm_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Xicpm_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Xicpm_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 4232 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 4232 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Xicpm_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Xicpm_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Xicpm_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 4132 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 4132 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Xic0_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Xic0_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Xic0_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 4122) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 4122)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dpm_Lcpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dpm_Lcpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dpm_Lcpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 4232) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 4232)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dpm_Xicpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dpm_Xicpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dpm_Xicpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dpm_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dpm_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dpm_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 411 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 411 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dpm_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dpm_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dpm_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 4122) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 4122)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/D0_Lcpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/D0_Lcpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/D0_Lcpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 4232) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 4232)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/D0_Xicpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/D0_Xicpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/D0_Xicpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/D0_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/D0_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/D0_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 421 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 421 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/D0_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/D0_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/D0_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 4122) || (std::abs(pdgMotherC2) == 431 && std::abs(pdgMotherC1) == 4122)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dspm_Lcpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dspm_Lcpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dspm_Lcpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 4232) || (std::abs(pdgMotherC2) == 431 && std::abs(pdgMotherC1) == 4232)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dspm_Xicpm/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dspm_Xicpm/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dspm_Xicpm/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 4132) || (std::abs(pdgMotherC2) == 431 && std::abs(pdgMotherC1) == 4132)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dspm_Xic0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dspm_Xic0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dspm_Xic0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } else if ((std::abs(pdgMotherC1) == 431 && std::abs(pdgMotherC2) == 4332) || (std::abs(pdgMotherC2) == 431 && std::abs(pdgMotherC1) == 4332)) { + if (sign1 * sign2 < 0) { // ULS + fRegistry.fill(HIST("Pair/ccbar/Dspm_Omegac0/uls/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 > 0 && sign2 > 0) { // LS++ + fRegistry.fill(HIST("Pair/ccbar/Dspm_Omegac0/lspp/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } else if (sign1 < 0 && sign2 < 0) { // LS-- + fRegistry.fill(HIST("Pair/ccbar/Dspm_Omegac0/lsmm/hs"), mass, pt, rapidity, dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, dphi_e_ee, pair_dca, weight); + } + } + } + } + + 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)) { + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { return false; } } else { // cut-based - if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { return false; } } - if (!cut.template IsSelectedPair(t1, t2, d_bz)) { + if (!cut.IsSelectedPair(t1, t2, d_bz, 0.0)) { return false; } } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { - if (!cut.template IsSelectedTrack(t1) || !cut.template IsSelectedTrack(t2)) { + 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 (dimuoncuts.rejectWrongMatch) { + if (t1.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && t1.emmcparticleId() != t1.emmftmcparticleId()) { + return false; + } + if (t2.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && t2.emmcparticleId() != t2.emmftmcparticleId()) { + 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; } - if (!cut.template IsSelectedPair(t1, t2)) { + } 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 pca = 999.f, lxy = 999.f; // in unit of cm - // o2::aod::pwgem::dilepton::utils::pairutil::isSVFound(fitter, collision, t1, t2, pca, lxy); + 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 dca_t1 = 999.f, dca_t2 = 999.f, pair_dca = 999.f; + float pair_dca = 999.f; if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - dca_t1 = dca3DinSigma(t1); - dca_t2 = dca3DinSigma(t2); - pair_dca = std::sqrt((dca_t1 * dca_t1 + dca_t2 * dca_t2) / 2.); + 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) { - dca_t1 = fwdDcaXYinSigma(t1); - dca_t2 = fwdDcaXYinSigma(t2); - pair_dca = std::sqrt((dca_t1 * dca_t1 + dca_t2 * dca_t2) / 2.); + 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 - abs(dphi) / M_PI; - float asym = abs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); + + 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); - o2::math_utils::bringToPMPi(phiCS); - - auto t1mc = mcparticles.iteratorAt(t1.emmcparticleId()); - auto t2mc = mcparticles.iteratorAt(t2.emmcparticleId()); - bool is_from_same_mcevent = (t1mc.emmceventId() == t2mc.emmceventId()) && (collision.emmceventId() == t1mc.emmceventId()) && (collision.emmceventId() == t2mc.emmceventId()); - - if (FindCommonMotherFrom2ProngsWithoutPDG(t1mc, t2mc) > 0 || IsHF(t1mc, t2mc, mcparticles) > 0) { // for bkg study - if (abs(t1mc.pdgCode()) != pdg_lepton || abs(t2mc.pdgCode()) != pdg_lepton) { // hh or eh correlated bkg - if (abs(t1mc.pdgCode()) != pdg_lepton && 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + dphi = RecoDecay::constrainAngle(dphi, -o2::constants::math::PIHalf, 1); // shift dphi in [-pi/2, +3pi/2] rad. + + std::array arrP1 = {t1.px(), t1.py(), t1.pz(), leptonM1}; + std::array arrP2 = {t2.px(), t2.py(), t2.pz(), leptonM2}; + float cos_thetaPol = 999, phiPol = 999.f; + if (cfgPolarizationFrame == 0) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrP1, arrP2, beamE1, beamE2, beamP1, beamP2, t1.sign(), cos_thetaPol, phiPol); + } else if (cfgPolarizationFrame == 1) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrP1, arrP2, beamE1, beamE2, beamP1, beamP2, t1.sign(), cos_thetaPol, phiPol); + } + o2::math_utils::bringToPMPi(phiPol); + float quadmom = (3.f * std::pow(cos_thetaPol, 2) - 1.f) / 2.f; + + 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, cos_thetaPol, phiPol, quadmom, 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fRegistry.fill(HIST("Pair/corr_bkg_hh/lspp/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fRegistry.fill(HIST("Pair/corr_bkg_hh/lsmm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); } - } else { // eh correlated bkg + } else { // lh correlated bkg if (t1.sign() * t2.sign() < 0) { // ULS - fRegistry.fill(HIST("Pair/corr_bkg_eh/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fRegistry.fill(HIST("Pair/corr_bkg_lh/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, 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_eh/lspp/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fRegistry.fill(HIST("Pair/corr_bkg_lh/lspp/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, 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_eh/lsmm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fRegistry.fill(HIST("Pair/corr_bkg_lh/lsmm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fRegistry.fill(HIST("Pair/comb_bkg/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fRegistry.fill(HIST("Pair/comb_bkg/lspp/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fRegistry.fill(HIST("Pair/comb_bkg/lsmm/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); } } - if (abs(t1mc.pdgCode()) != pdg_lepton || abs(t2mc.pdgCode()) != pdg_lepton) { + if (std::abs(t1mc.pdgCode()) != pdg_lepton || std::abs(t2mc.pdgCode()) != pdg_lepton) { + return false; + } + + if (!is_pair_from_same_mcevent) { return false; } - if (!is_from_same_mcevent) { + if (cfgRequireTrueAssociation && (t1mc.emmceventId() != collision.emmceventId() || t2mc.emmceventId() != collision.emmceventId())) { return false; } - int mother_id = FindLF(t1mc, t2mc, mcparticles); + int mother_id = std::max({FindSMULS(t1mc, t2mc, mcparticles), FindSMULS(t2mc, t1mc, mcparticles), FindSMLSPP(t1mc, t2mc, mcparticles), FindSMLSMM(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) { + if (mother_id > -1) { auto mcmother = mcparticles.iteratorAt(mother_id); if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { if ((t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && (t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { - switch (abs(mcmother.pdgCode())) { + float deltaPt1 = t1mc.pt() - t1.pt(); + float deltaPt2 = t2mc.pt() - t2.pt(); + switch (std::abs(mcmother.pdgCode())) { case 111: - fRegistry.fill(HIST("Pair/sm/Pi0/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/Pi0/hMvsPhiV"), phiv, v12.M()); + if (IsFromCharm(mcmother, mcparticles) < 0 && IsFromBeauty(mcmother, mcparticles) < 0) { // prompt pi0 + fillRecHistograms<1>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // prompt pi0 + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/sm/PromptPi0/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/sm/PromptPi0/uls/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/PromptPi0/uls/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/sm/PromptPi0/lspp/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/sm/PromptPi0/lspp/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/PromptPi0/lspp/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/sm/PromptPi0/lsmm/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/sm/PromptPi0/lsmm/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/PromptPi0/lsmm/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } + } + } else { // non-prompt pi0 + fillRecHistograms<2>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // non-prompt pi0 + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/uls/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/uls/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/uls/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/lspp/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/lspp/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/lspp/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/lsmm/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/lsmm/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/NonPromptPi0/lsmm/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } + } } break; case 221: - fRegistry.fill(HIST("Pair/sm/Eta/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/Eta/hMvsPhiV"), phiv, v12.M()); - } + fillRecHistograms<3>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // eta break; case 331: - fRegistry.fill(HIST("Pair/sm/EtaPrime/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/EtaPrime/hMvsPhiV"), phiv, v12.M()); - } + fillRecHistograms<4>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // eta' break; case 113: - fRegistry.fill(HIST("Pair/sm/Rho/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/Rho/hMvsPhiV"), phiv, v12.M()); - } + fillRecHistograms<5>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // rho break; case 223: - fRegistry.fill(HIST("Pair/sm/Omega/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/Omega/hMvsPhiV"), phiv, v12.M()); - } - if (mcmother.daughtersIds().size() == 2) { // omeag->ee - fRegistry.fill(HIST("Pair/sm/Omega2ll/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/Omega2ll/hMvsPhiV"), phiv, v12.M()); + fillRecHistograms<6>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // omega + if (mcmother.daughtersIds().size() == 2) { + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/sm/Omega2ll/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // omeag->ee } } break; case 333: - fRegistry.fill(HIST("Pair/sm/Phi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/Phi/hMvsPhiV"), phiv, v12.M()); - } - if (mcmother.daughtersIds().size() == 2) { // phi->ee - fRegistry.fill(HIST("Pair/sm/Phi2ll/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/Phi2ll/hMvsPhiV"), phiv, v12.M()); + fillRecHistograms<7>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // phi + if (mcmother.daughtersIds().size() == 2) { + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/sm/Phi2ll/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // phi->ee } } break; - case 443: { + case 443: if (IsFromBeauty(mcmother, mcparticles) > 0) { - fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fillRecHistograms<9>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // non-prompt J/psi if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/hMvsPhiV"), phiv, v12.M()); + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/uls/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/uls/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/lspp/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/lspp/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/lsmm/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/NonPromptJPsi/lsmm/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } } } else { - fRegistry.fill(HIST("Pair/sm/PromptJPsi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fillRecHistograms<8>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // prompt J/psi if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/PromptJPsi/hMvsPhiV"), phiv, v12.M()); + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Pair/sm/PromptJPsi/uls/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/PromptJPsi/uls/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Pair/sm/PromptJPsi/lspp/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/PromptJPsi/lspp/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Pair/sm/PromptJPsi/lsmm/hDeltaPtvsDCA"), pair_dca, deltaPt1 + deltaPt2); + fRegistry.fill(HIST("Pair/sm/PromptJPsi/lsmm/hDCAz1vsDCAz2"), dcaZinSigma(t1), dcaZinSigma(t2)); + } } } break; - } - case 100443: { + case 100443: if (IsFromBeauty(mcmother, mcparticles) > 0) { - fRegistry.fill(HIST("Pair/sm/NonPromptPsi2S/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/NonPromptPsi2S/hMvsPhiV"), phiv, v12.M()); - } + fillRecHistograms<11>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // non-prompt psi2S } else { - fRegistry.fill(HIST("Pair/sm/PromptPsi2S/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/PromptPsi2S/hMvsPhiV"), phiv, v12.M()); - } + fillRecHistograms<10>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // prompt psi2S } break; - } default: break; } - } else if (!(t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && !(t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { - switch (abs(mcmother.pdgCode())) { + switch (std::abs(mcmother.pdgCode())) { case 22: - fRegistry.fill(HIST("Pair/sm/Photon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); + fillRecHistograms<0>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // photon conversion if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - fRegistry.fill(HIST("Pair/sm/Photon/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/sm/Photon/uls/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/uls/hMvsRxy"), rxy_gen, v12.M()); } break; default: break; } } // end of primary/secondary selection - } // end of primary selection for same mother + } // 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if (isCharmMeson(mp1) && isCharmMeson(mp2)) { - fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } else if (isCharmBaryon(mp1) && isCharmBaryon(mp2)) { - fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } else { - fRegistry.fill(HIST("Pair/ccbar/c2l_c2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } - break; + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + fillRecHistograms<15>(t1.sign(), t2.sign(), mp1.pdgCode(), mp2.pdgCode(), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // c2l_c2l + break; + case static_cast(EM_HFeeType::kBe_Be): + fillRecHistograms<16>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // b2l_b2l + break; + case static_cast(EM_HFeeType::kBCe_BCe): + fillRecHistograms<17>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // b2c2l_b2c2l + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): + fillRecHistograms<18>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // b2c2l_b2l_sameb + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): + fillRecHistograms<19>(t1.sign(), t2.sign(), 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), pair_dca, weight); // b2c2l_b2l_diffb + break; + default: + break; + } + } + } // end of HF evaluation + return true; + } + + template + bool fillGenPairInfo(TMCParticle const& t1, TMCParticle const& t2, TMCParticles const& mcparticles) + { + if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { + return false; + } + if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { + return false; + } + + int mother_id = std::max({FindSMULS(t1, t2, mcparticles), FindSMULS(t2, t1, mcparticles), FindSMLSPP(t1, t2, mcparticles), FindSMLSMM(t1, t2, mcparticles)}); + int hfee_type = IsHF(t1, t2, mcparticles); + if (mother_id < 0 && hfee_type < 0) { + 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 = 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()) { + return false; + } + // 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()) { + return false; + } + // if (dimuoncuts.cfg_apply_detadphi && std::pow(deta / dimuoncuts.cfg_min_deta, 2) + std::pow(dphi / dimuoncuts.cfg_min_dphi, 2) < 1.f) { + // continue; + // } + } + + int sign1 = -t1.pdgCode() / pdg_lepton; + int sign2 = -t2.pdgCode() / pdg_lepton; + + 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. + + std::array arrP1 = {static_cast(v1.Px()), static_cast(v1.Py()), static_cast(v1.Pz()), leptonM1}; + std::array arrP2 = {static_cast(v2.Px()), static_cast(v2.Py()), static_cast(v2.Pz()), leptonM2}; + float cos_thetaPol = 999, phiPol = 999.f; + if (cfgPolarizationFrame == 0) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrP1, arrP2, beamE1, beamE2, beamP1, beamP2, -t1.pdgCode() / pdg_lepton, cos_thetaPol, phiPol); + } else if (cfgPolarizationFrame == 1) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrP1, arrP2, beamE1, beamE2, beamP1, beamP2, -t1.pdgCode() / pdg_lepton, cos_thetaPol, phiPol); + } + o2::math_utils::bringToPMPi(phiPol); + float quadmom = (3.f * std::pow(cos_thetaPol, 2) - 1.f) / 2.f; + + if (!isInAcceptance(t1) || !isInAcceptance(t2)) { + return false; + } + + float weight = 1.f; + 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 + fillGenHistograms<1>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // prompt pi0 + } else { // non-prompt pi0 + fillGenHistograms<2>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // non-prompt pi0 } - case static_cast(EM_HFeeType::kBe_Be): { - fRegistry.fill(HIST("Pair/bbbar/b2l_b2l/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if (isBeautyMeson(mp1) && isBeautyMeson(mp2)) { - fRegistry.fill(HIST("Pair/bbbar/b2l_b2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } else if (isBeautyBaryon(mp1) && isBeautyBaryon(mp2)) { - fRegistry.fill(HIST("Pair/bbbar/b2l_b2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } else { - fRegistry.fill(HIST("Pair/bbbar/b2l_b2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } - break; + break; + case 221: + fillGenHistograms<3>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // eta + break; + case 331: + fillGenHistograms<4>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // eta' + break; + case 113: + fillGenHistograms<5>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // rho + break; + case 223: + fillGenHistograms<6>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // omega + if (mcmother.daughtersIds().size() == 2) { + fRegistry.fill(HIST("Generated/sm/Omega2ll/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // omega->ee } - case static_cast(EM_HFeeType::kBCe_BCe): { - fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2c2l/hadron_hadron/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - if (isCharmMeson(mp1) && isCharmMeson(mp2)) { - fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2c2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } else if (isCharmBaryon(mp1) && isCharmBaryon(mp2)) { - fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2c2l/baryon_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } else { - fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2c2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } - break; + break; + case 333: + fillGenHistograms<7>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // phi + if (mcmother.daughtersIds().size() == 2) { + fRegistry.fill(HIST("Generated/sm/Phi2ll/uls/hs"), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee)); // phi->ee } - 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } else { - fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_sameb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } - break; + break; + case 443: + if (IsFromBeauty(mcmother, mcparticles) > 0) { + fillGenHistograms<9>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // non-prompt J/psi + } else { + fillGenHistograms<8>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // prompt J/psi } - 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } else { - fRegistry.fill(HIST("Pair/bbbar/b2c2l_b2l_diffb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee), pair_dca); - } - break; + break; + case 100443: + if (IsFromBeauty(mcmother, mcparticles) > 0) { + fillGenHistograms<11>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // non-prompt psi2S + } else { + fillGenHistograms<10>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // prompt psi2S } - default: - break; - } + 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): + fillGenHistograms<15>(sign1, sign2, mp1.pdgCode(), mp2.pdgCode(), v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // c2l_c2l + break; + case static_cast(EM_HFeeType::kBe_Be): + fillGenHistograms<16>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // b2l_b2l + break; + case static_cast(EM_HFeeType::kBCe_BCe): + fillGenHistograms<17>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // b2c2l_b2c2l + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): + fillGenHistograms<18>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // b2c2l_b2l_sameb + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): + fillGenHistograms<19>(sign1, sign2, 0, 0, v12.M(), v12.Pt(), v12.Rapidity(), dphi, deta, cos_thetaPol, phiPol, quadmom, aco, asym, std::fabs(dphi_e_ee), weight); // b2c2l_b2l_diffb + break; + default: + break; + } } // end of HF evaluation - return true; + return false; } - 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 && 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) && (o2::aod::pidtpc::tpcNSigmaPi < dielectroncuts.cfg_min_TPCNsigmaPi || dielectroncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi) && ((0.96f < o2::aod::pidtofbeta::beta && o2::aod::pidtofbeta::beta < 1.04f) || o2::aod::pidtofbeta::beta < 0.f); - Filter ttcaFilter_electron = ifnode(dielectroncuts.enableTTCA.node(), o2::aod::emprimaryelectron::isAssociatedToMPC == true || o2::aod::emprimaryelectron::isAssociatedToMPC == false, o2::aod::emprimaryelectron::isAssociatedToMPC == true); + template + bool fillGenParticleAcc(TMCParticle const& mcParticle, TMCParticles const& mcParticles) + { + if (!mcParticle.isPhysicalPrimary() && !mcParticle.producedByGenerator()) { + return false; + } + if (mcParticle.daughtersIds().size() < 2) { + return false; + } - 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 && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track; - Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + if (mcParticle.y() < dielectroncuts.cfg_min_pair_y || dielectroncuts.cfg_max_pair_y < mcParticle.y()) { + return false; + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + if (mcParticle.y() < dimuoncuts.cfg_min_pair_y || dimuoncuts.cfg_max_pair_y < mcParticle.y()) { + return false; + } + } - 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; - using FilteredMyCollisions = soa::Filtered; + int pdg = mcParticle.pdgCode(); + if (std::abs(pdg) == 113 && mcParticle.daughtersIds().size() != 2) { // reject dalitz decay + return false; + } + if (std::abs(pdg) == 223 && mcParticle.daughtersIds().size() != 2) { // reject dalitz decay + return false; + } + if (std::abs(pdg) == 333 && mcParticle.daughtersIds().size() != 2) { // reject dalitz decay + return false; + } + // accept radiative decay of charmonia (ee + multiple gamma). + + // float pt1 = 0.f, eta1 = 0.f, phi1 = 0.f, sign1 = 0.f; + // float pt2 = 0.f, eta2 = 0.f, phi2 = 0.f, sign2 = 0.f; + std::vector> vDau; + vDau.reserve(mcParticle.daughtersIds().size()); + for (const auto& daughterId : mcParticle.daughtersIds()) { + auto dau = mcParticles.rawIteratorAt(daughterId); + if (std::abs(dau.pdgCode()) == pdg_lepton) { + vDau.emplace_back(std::array{dau.pt(), dau.eta(), dau.phi(), dau.pdgCode() > 0 ? -1.f : +1.f}); + } + } + if (vDau.size() != 2 || vDau[0][3] * vDau[1][3] > 0.f) { // decay objects must be ULS 2 leptons. + vDau.clear(); + vDau.shrink_to_fit(); + return false; + } + + // LOGF(info, "mcParticle.globalIndex() = %d, mcParticle.pdgCode() = %d, mcParticle.daughtersIds().size() = %d", mcParticle.globalIndex(), mcParticle.pdgCode(), mcParticle.daughtersIds().size()); - template - void runTruePairing(TCollisions const& collisions, TMCLeptons const& posTracks, TMCLeptons const& negTracks, TPreslice const& perCollision, TCut const& cut, TMCCollisions const&, TMCParticles const& mcparticles) + ROOT::Math::PtEtaPhiMVector v1(vDau[0][0], vDau[0][1], vDau[0][2], leptonM1); + ROOT::Math::PtEtaPhiMVector v2(vDau[1][0], vDau[1][1], vDau[1][2], leptonM2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + std::array arrP1 = {static_cast(v1.Px()), static_cast(v1.Py()), static_cast(v1.Pz()), leptonM1}; + std::array arrP2 = {static_cast(v2.Px()), static_cast(v2.Py()), static_cast(v2.Pz()), leptonM2}; + float cos_thetaPol = 999, phiPol = 999.f; + if (cfgPolarizationFrame == 0) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrP1, arrP2, beamE1, beamE2, beamP1, beamP2, vDau[0][3] > 0 ? 1 : -1, cos_thetaPol, phiPol); + } else if (cfgPolarizationFrame == 1) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrP1, arrP2, beamE1, beamE2, beamP1, beamP2, vDau[0][3] > 0 ? 1 : -1, cos_thetaPol, phiPol); + } + o2::math_utils::bringToPMPi(phiPol); + float quadmom = (3.f * std::pow(cos_thetaPol, 2) - 1.f) / 2.f; + + float weight = 1.f; + switch (std::abs(mcParticle.pdgCode())) { + case 113: + fRegistry.fill(HIST("Generated/VM/All/Rho/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + if (isInAcceptance(v1.Pt(), v1.Eta()) && isInAcceptance(v2.Pt(), v2.Eta())) { + fRegistry.fill(HIST("Generated/VM/Acc/Rho/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + } + break; + case 223: + fRegistry.fill(HIST("Generated/VM/All/Omega/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + if (isInAcceptance(v1.Pt(), v1.Eta()) && isInAcceptance(v2.Pt(), v2.Eta())) { + fRegistry.fill(HIST("Generated/VM/Acc/Omega/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + } + break; + case 333: + fRegistry.fill(HIST("Generated/VM/All/Phi/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + if (isInAcceptance(v1.Pt(), v1.Eta()) && isInAcceptance(v2.Pt(), v2.Eta())) { + fRegistry.fill(HIST("Generated/VM/Acc/Phi/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + } + break; + case 443: + if (IsFromBeauty(mcParticle, mcParticles) > 0) { + fRegistry.fill(HIST("Generated/VM/All/NonPromptJPsi/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + if (isInAcceptance(v1.Pt(), v1.Eta()) && isInAcceptance(v2.Pt(), v2.Eta())) { + fRegistry.fill(HIST("Generated/VM/Acc/NonPromptJPsi/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + } + } else { + fRegistry.fill(HIST("Generated/VM/All/PromptJPsi/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + if (isInAcceptance(v1.Pt(), v1.Eta()) && isInAcceptance(v2.Pt(), v2.Eta())) { + fRegistry.fill(HIST("Generated/VM/Acc/PromptJPsi/hs"), v12.M(), mcParticle.pt(), mcParticle.y(), cos_thetaPol, phiPol, quadmom, weight); + } + } + break; + default: + break; + } + + vDau.clear(); + vDau.shrink_to_fit(); + return false; + } + + 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 (auto& collision : collisions) { + for (const auto& collision : collisions) { initCCDB(collision); - float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -914,6 +2051,9 @@ struct DileptonMC { 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 @@ -922,477 +2062,531 @@ struct DileptonMC { 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 (auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS - fillTruePairInfo(collision, pos, neg, cut, mcparticles); + 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 (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ - fillTruePairInfo(collision, pos1, pos2, cut, 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 (auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS__ - fillTruePairInfo(collision, neg1, neg2, cut, mcparticles); - } // end of ULS 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 - - } // end of process + } template - void runGenInfo(TCollisions const& collisions, TMCCollisions const&, TMCLeptons const& posTracksMC, TMCLeptons const& negTracksMC, TMCParticles const& mcparticles) + void runGenInfo(TCollisions const& collisions, TMCCollisions const& mccollisions, TMCLeptons const& posTracksMC, TMCLeptons const& negTracksMC, 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 (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()); - for (auto& collision : collisions) { - float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + 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; } - auto mccollision = collision.template emmcevent_as(); + 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 (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS - // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + fillGenPairInfo(t1, t2, mcparticles); + } // end of true ULS pair loop + + for (const auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + fillGenPairInfo(t1, t2, mcparticles); + } // end of true LS++ pair loop + + for (const auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + fillGenPairInfo(t1, t2, mcparticles); + } // end of true LS-- pair loop + + // acceptance for polarization of vector mesons + auto mcParticles_per_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); + for (const auto& mcParticle : mcParticles_per_coll) { + if (!mcParticle.isPhysicalPrimary() && !mcParticle.producedByGenerator()) { + continue; + } + int pdg = std::abs(mcParticle.pdgCode()); + if (pdg == 113 || pdg == 223 || pdg == 333 || pdg == 443) { // select only VMs + fillGenParticleAcc(mcParticle, mcparticles); // VMs that decay into dilepton are stored in derived data. This is sufficient for polarization. + } + } // end of mc particle loop + } // end of collision loop + } + + template + bool isPairOK(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) || !cut.template IsSelectedTrack(t2)) { + 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, 0.0)) { + 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); - if (!isInAcceptance(t1) || !isInAcceptance(t2)) { + 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 (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { + if (isPairOK(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; } - if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { + auto mcpos2 = mcparticles.iteratorAt(pos2.emmcparticleId()); + auto mccollision_from_pos2 = mcpos2.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_pos2.getSubGeneratorId() != cfgEventGeneratorType) { continue; } - int mother_id = FindLF(t1, t2, mcparticles); - int hfee_type = IsHF(t1, t2, mcparticles); - if (mother_id < 0 && hfee_type < 0) { + if (isPairOK(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(neg1, neg2, cut, tracks)) { + passed_pairIds.emplace_back(std::make_pair(neg1.globalIndex(), neg2.globalIndex())); + } + } + } // end of collision loop - 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(); + 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; } } - } 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; - - 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; + 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(); + } - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - float aco = 1.f - abs(dphi) / M_PI; - float asym = abs(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); - o2::math_utils::bringToPMPi(phiCS); - - 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/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - break; - case 221: - fRegistry.fill(HIST("Generated/sm/Eta/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - break; - case 331: - fRegistry.fill(HIST("Generated/sm/EtaPrime/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - break; - case 113: - fRegistry.fill(HIST("Generated/sm/Rho/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - break; - case 223: - fRegistry.fill(HIST("Generated/sm/Omega/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - if (mcmother.daughtersIds().size() == 2) { // omega->ee - fRegistry.fill(HIST("Generated/sm/Omega2ll/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } - break; - case 333: - fRegistry.fill(HIST("Generated/sm/Phi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - if (mcmother.daughtersIds().size() == 2) { // phi->ee - fRegistry.fill(HIST("Generated/sm/Phi2ll/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } - break; - case 443: { - if (IsFromBeauty(mcmother, mcparticles) > 0) { - fRegistry.fill(HIST("Generated/sm/NonPromptJPsi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } else { - fRegistry.fill(HIST("Generated/sm/PromptJPsi/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } - break; - } - case 100443: { - if (IsFromBeauty(mcmother, mcparticles) > 0) { - fRegistry.fill(HIST("Generated/sm/NonPromptPsi2S/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } else { - fRegistry.fill(HIST("Generated/sm/PromptPsi2S/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - if (isCharmMeson(mp1) && isCharmMeson(mp2)) { - fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } else { - fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - if (isBeautyMeson(mp1) && isBeautyMeson(mp2)) { - fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } else { - fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - if (isCharmMeson(mp1) && isCharmMeson(mp2)) { - fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/meson_meson/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } else { - fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } else { - fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_sameb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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 + 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; + } - for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { - // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); + template + void fillHistogramsUnfolding(TTrack const& t1, TTrack const& t2, TMCParticles const& mcparticles) + { + auto t1mc = mcparticles.iteratorAt(t1.emmcparticleId()); + auto t2mc = mcparticles.iteratorAt(t2.emmcparticleId()); - if (!isInAcceptance(t1) || !isInAcceptance(t2)) { - continue; - } + ROOT::Math::PtEtaPhiMVector v1rec(t1.pt(), t1.eta(), t1.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2rec(t2.pt(), t2.eta(), t2.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12rec = v1rec + v2rec; - if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { - continue; - } - if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { - continue; - } + ROOT::Math::PtEtaPhiMVector v1mc(t1mc.pt(), t1mc.eta(), t1mc.phi(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2mc(t2mc.pt(), t2mc.eta(), t2mc.phi(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12mc = v1mc + v2mc; - int hfee_type = IsHF(t1, t2, mcparticles); - if (hfee_type < 0) { - continue; - } + float weight = 1.f; + if (cfgApplyWeightTTCA) { + weight = map_weight[std::make_pair(t1.globalIndex(), t2.globalIndex())]; + } - 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(); - } + if (isPairInAcc(t1, t2) && isPairInAcc(t1mc, t2mc)) { // both rec and mc info are in acceptance. + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("uls/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("lspp/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("lsmm/hsRM"), v12mc.M(), v12mc.Pt(), v12rec.M(), v12rec.Pt(), weight); + } + } else if (!isPairInAcc(t1, t2) && isPairInAcc(t1mc, t2mc)) { + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("uls/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("lspp/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("lsmm/hMiss"), v12mc.M(), v12mc.Pt(), weight); + } + } else if (isPairInAcc(t1, t2) && !isPairInAcc(t1mc, t2mc)) { + if (t1.sign() * t2.sign() < 0) { // ULS + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("uls/hFake"), v12rec.M(), v12rec.Pt(), weight); + } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("lspp/hFake"), v12rec.M(), v12rec.Pt(), weight); + } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- + fRegistry.fill(HIST("Unfold/") + HIST(unfolding_dilepton_source_types[sourceId]) + HIST("lsmm/hFake"), v12rec.M(), v12rec.Pt(), weight); + } + } + } - ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, leptonM1); - ROOT::Math::PtEtaPhiMVector v2(pt2, eta2, phi2, leptonM2); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + template + bool fillPairUnfolding(TTrack const& t1, TTrack const& t2, TTracks const& tracks, TCut const& cut, TMCCollisions const&, TMCParticles const& mcparticles) + { + auto t1mc = mcparticles.iteratorAt(t1.emmcparticleId()); + auto mccollision_from_t1 = t1mc.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_t1.getSubGeneratorId() != cfgEventGeneratorType) { + return false; + } - 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; - } - } + auto t2mc = mcparticles.iteratorAt(t2.emmcparticleId()); + auto mccollision_from_t2 = t2mc.template emmcevent_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_t2.getSubGeneratorId() != cfgEventGeneratorType) { + return false; + } - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - float aco = 1.f - abs(dphi) / M_PI; - float asym = abs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); - float dphi_e_ee = v1.Phi() - v12.Phi(); - o2::math_utils::bringToPMPi(dphi_e_ee); + if ((std::abs(t1mc.pdgCode()) != pdg_lepton || std::abs(t2mc.pdgCode()) != pdg_lepton) || (t1mc.emmceventId() != t2mc.emmceventId())) { + return false; + } + if (t1mc.pdgCode() * t2mc.pdgCode() > 0) { // ULS + return false; + } + if (!((t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && (t2mc.isPhysicalPrimary() || t2mc.producedByGenerator()))) { + return false; + } + int mother_id = std::max({FindSMULS(t1mc, t2mc, mcparticles), FindSMULS(t2mc, t1mc, mcparticles), FindSMLSPP(t1mc, t2mc, mcparticles), FindSMLSMM(t1mc, t2mc, mcparticles)}); + int hfee_type = IsHF(t1mc, t2mc, mcparticles); + if (mother_id < 0 && hfee_type < 0) { + return false; + } - 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 (!isPairOK(t1, t2, cut, tracks)) { // without acceptance + return false; + } - 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } else { - fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } - break; - } - default: - break; - } - } - } // end of true LS++ pair loop + // ROOT::Math::PtEtaPhiMVector v1rec(t1.pt(), t1.eta(), t1.phi(), leptonM1); + // ROOT::Math::PtEtaPhiMVector v2rec(t2.pt(), t2.eta(), t2.phi(), leptonM2); + // ROOT::Math::PtEtaPhiMVector v12rec = v1rec + v2rec; - for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { - // LOGF(info, "pdg1 = %d, pdg2 = %d", t1.pdgCode(), t2.pdgCode()); + // ROOT::Math::PtEtaPhiMVector v1mc(t1mc.pt(), t1mc.eta(), t1mc.phi(), leptonM1); + // ROOT::Math::PtEtaPhiMVector v2mc(t2mc.pt(), t2mc.eta(), t2mc.phi(), leptonM2); + // ROOT::Math::PtEtaPhiMVector v12mc = v1mc + v2mc; - if (!isInAcceptance(t1) || !isInAcceptance(t2)) { - continue; - } + if (mother_id > -1) { + auto mcmother = mcparticles.iteratorAt(mother_id); + if (!(mcmother.isPhysicalPrimary() || mcmother.producedByGenerator())) { + return false; + } + switch (std::abs(mcmother.pdgCode())) { + case 111: + case 221: + case 331: + case 113: + case 223: + case 333: + case 443: + case 100443: + fillHistogramsUnfolding<0>(t1, t2, mcparticles); + break; + default: + break; + } + } else if (hfee_type > -1) { + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + fillHistogramsUnfolding<1>(t1, t2, mcparticles); + break; + case static_cast(EM_HFeeType::kBe_Be): + fillHistogramsUnfolding<2>(t1, t2, mcparticles); + break; + case static_cast(EM_HFeeType::kBCe_BCe): + fillHistogramsUnfolding<2>(t1, t2, mcparticles); + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): + fillHistogramsUnfolding<2>(t1, t2, mcparticles); + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): + fillHistogramsUnfolding<2>(t1, t2, mcparticles); + break; + default: + break; + } + } + return true; + } - if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { - continue; - } - if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { - continue; - } + template + void fillUnfolding(TCollisions const& collisions, TTracks1 const& posTracks, TTracks2 const& negTracks, TPresilce 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; + } - int hfee_type = IsHF(t1, t2, mcparticles); - if (hfee_type < 0) { - continue; - } + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + 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(); - } + 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 + fillPairUnfolding(pos, neg, tracks, cut, mcCollisions, mcparticles); + } // end of ULS pairing + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + fillPairUnfolding(pos1, pos2, tracks, cut, mcCollisions, mcparticles); + } // end of LS++ pairing + for (const auto& [neg1, neg2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_per_coll, negTracks_per_coll))) { // LS-- + fillPairUnfolding(neg1, neg2, tracks, cut, mcCollisions, mcparticles); + } // end of LS-- pairing + } // end of collision loop + } - ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, leptonM1); - ROOT::Math::PtEtaPhiMVector v2(pt2, eta2, phi2, leptonM2); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + SliceCache cache; + Preslice perCollision_electron = aod::emprimaryelectron::emeventId; + Filter trackFilter_electron = nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + 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_20MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_20MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_40MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_40MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_60MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_60MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_80MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_80MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_100MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_100MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_120MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_120MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_140MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_140MeV))) <= static_cast(0), true), + o2::aod::emprimaryelectron::pfb >= static_cast(0)); - 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; - } - } + Preslice perCollision_muon = aod::emprimarymuon::emeventId; + Filter trackFilter_muon = o2::aod::fwdtrack::trackType == dimuoncuts.cfg_track_type; + Filter ttcaFilter_muon = ifnode(dimuoncuts.enableTTCA.node(), o2::aod::emprimarymuon::isAssociatedToMPC == true || o2::aod::emprimarymuon::isAssociatedToMPC == false, o2::aod::emprimarymuon::isAssociatedToMPC == true); - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - float aco = 1.f - abs(dphi) / M_PI; - float asym = abs(v1.Pt() - v2.Pt()) / (v1.Pt() + v2.Pt()); - float dphi_e_ee = v1.Phi() - v12.Phi(); - o2::math_utils::bringToPMPi(dphi_e_ee); + 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_numContrib = cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < cfgNumContribMax; + 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; - 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); + 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 - 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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(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(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } else { - fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/meson_baryon/hs"), v12.M(), v12.Pt(), v12.Rapidity(), abs(dphi), abs(cos_thetaCS), abs(phiCS), aco, asym, abs(dphi_e_ee)); - } - break; - } - default: - break; - } - } - } // end of true LS++ pair loop - } // end of collision loop + 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 (auto& collision : collisions) { - float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + for (const auto& collision : collisions) { + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -1400,11 +2594,16 @@ struct DileptonMC { if (!fEMEventCut.IsSelected(collision)) { continue; } - auto mccollision = collision.template emmcevent_as(); - auto mctracks_per_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); - - for (auto& mctrack : mctracks_per_coll) { + 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; } @@ -1419,65 +2618,118 @@ struct DileptonMC { } } - switch (abs(mctrack.pdgCode())) { + switch (std::abs(mctrack.pdgCode())) { case 223: - fRegistry.fill(HIST("Generated/sm/Omega2ll/hPt"), mctrack.pt()); - fRegistry.fill(HIST("Generated/sm/Omega2ll/hY"), mctrack.y()); + fRegistry.fill(HIST("Generated/VM/Omega/hPtY"), mctrack.y(), mctrack.pt(), 1.f / mctrack.dsf()); break; case 333: - fRegistry.fill(HIST("Generated/sm/Phi2ll/hPt"), mctrack.pt()); - fRegistry.fill(HIST("Generated/sm/Phi2ll/hY"), mctrack.y()); + fRegistry.fill(HIST("Generated/VM/Phi/hPtY"), mctrack.y(), mctrack.pt(), 1.f / mctrack.dsf()); break; default: break; } } // end of mctracks per mccollision - } // end of collision loop + } // end of collision loop } + PROCESS_SWITCH(DileptonMC, processGen_VM, "process generated info for vector mesons", false); - 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; - - // void processAnalysis(FilteredMyCollisions const& collisions, aod::EMMCEvents const& mccollisions, aod::EMMCParticles const& mcparticles, Types const&...) - void processAnalysis(FilteredMyCollisions const& collisions, aod::EMMCEvents const& mccollisions, aod::EMMCParticles const& mcparticles, TLeptons const&) + void processNorm(aod::EMEventNormInfos const& collisions) { - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - runTruePairing(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, mccollisions, mcparticles); - runGenInfo(collisions, mccollisions, positive_electronsMC, negative_electronsMC, mcparticles); - } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { - runTruePairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, mccollisions, mcparticles); - runGenInfo(collisions, mccollisions, positive_muonsMC, negative_muonsMC, mcparticles); - } + 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, 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- + PROCESS_SWITCH(DileptonMC, processNorm, "process normalization info", false); - void processAnalysis_Smeared(FilteredMyCollisions const& collisions, aod::EMMCEvents const& mccollisions, TLeptons const&, TSmeardMCParitlces const& mcparticles_smeared) + void processBC(aod::EMBCs const& bcs) { - if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - runTruePairing(collisions, positive_electrons, negative_electrons, o2::aod::emprimaryelectron::emeventId, fDielectronCut, mccollisions, mcparticles_smeared); - runGenInfo(collisions, mccollisions, positive_electronsMC_smeared, negative_electronsMC_smeared, mcparticles_smeared); - } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { - runTruePairing(collisions, positive_muons, negative_muons, o2::aod::emprimarymuon::emeventId, fDimuonCut, mccollisions, mcparticles_smeared); - runGenInfo(collisions, mccollisions, positive_muonsMC_smeared, negative_muonsMC_smeared, mcparticles_smeared); + 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, processAnalysis_Smeared, "run dilepton mc analysis with smearing", false); + PROCESS_SWITCH(DileptonMC, processBC, "process BC counter", false); - void processDummy(MyCollisions const&) {} + void processDummy(FilteredMyCollisions const&) {} PROCESS_SWITCH(DileptonMC, processDummy, "Dummy function", false); }; diff --git a/PWGEM/Dilepton/Core/DileptonProducer.h b/PWGEM/Dilepton/Core/DileptonProducer.h new file mode 100644 index 00000000000..c206ac14d3f --- /dev/null +++ b/PWGEM/Dilepton/Core/DileptonProducer.h @@ -0,0 +1,781 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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_DILEPTONPRODUCER_H_ +#define PWGEM_DILEPTON_CORE_DILEPTONPRODUCER_H_ + +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMFwdTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 DileptonProducer { + Produces eventTable; + Produces normTable; + Produces dileptonTable; + + // 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 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 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 cfgStoreULS{"cfgStoreULS", true, "flag to store ULS pairs"}; + Configurable cfgStoreLS{"cfgStoreLS", true, "flag to store LS pairs"}; + + EMEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + 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 cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF 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_hadronPID, 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 at PV"}; + 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_20MeV : 2, kElFromPi0_40MeV : 4, kElFromPi0_60MeV : 8, kElFromPi0_80MeV : 16, kElFromPi0_100MeV : 32, kElFromPi0_120MeV : 64, kElFromPi0_140MeV : 128] 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_mirror_phi_track{"cfg_mirror_phi_track", false, "mirror the phi cut around Pi, min and max Phi should be in 0-Pi"}; + Configurable cfg_reject_phi_track{"cfg_reject_phi_track", false, "reject the phi interval"}; + 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_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 cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. + Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; + Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; + + 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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; + Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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/ndf"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; + 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"}; + Configurable cfg_max_relDPt_wrt_matchedMCHMID{"cfg_max_relDPt_wrt_matchedMCHMID", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DEta_wrt_matchedMCHMID{"cfg_max_DEta_wrt_matchedMCHMID", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; + } dimuoncuts; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + Service ccdb; + int mRunNumber; + float d_bz; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + + std::mt19937 engine; + float leptonM1 = 0.f; + float leptonM2 = 0.f; + + 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); + + std::random_device seed_gen; + engine = std::mt19937(seed_gen()); + + 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; + } + } + + 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 << " kG"; + } 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 << " kG"; + } + mRunNumber = collision.runNumber(); + fDielectronCut.SetTrackPhiPositionRange(dielectroncuts.cfg_min_phiposition_track, dielectroncuts.cfg_max_phiposition_track, dielectroncuts.cfgRefR, d_bz, dielectroncuts.cfg_mirror_phi_track); + } + + ~DileptonProducer() + { + } + + void addhistograms() + { + } + + 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.SetRequireVertexTOFmatched(eventcuts.cfgRequireVertexTOFmatched); + 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, false, 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, dielectroncuts.cfg_mirror_phi_track, dielectroncuts.cfg_reject_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); + 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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); + + // 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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, dielectroncuts.cfg_max_pin_pirejTPC); + + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + std::vector binsML{}; + binsML.reserve(dielectroncuts.binsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(dielectroncuts.binsMl.value[i]); + } + std::vector thresholdsML{}; + thresholdsML.reserve(dielectroncuts.cutsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + } // 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, 20); + fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); + 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); }); + fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons + fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); + } + + template + bool fillPairInfo(TCollision const&, 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) || !cut.template IsSelectedTrack(t2)) { + 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, 0)) { + 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())]; + } + + 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 dca1 = 999.f, dca2 = 999.f; + if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { + dca1 = dca3DinSigma(t1); + dca2 = dca3DinSigma(t2); + if (cfgDCAType == 1) { + dca1 = dcaXYinSigma(t1); + dca2 = dcaXYinSigma(t2); + } else if (cfgDCAType == 2) { + dca1 = dcaZinSigma(t1); + dca2 = dcaZinSigma(t2); + } + } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { + dca1 = fwdDcaXYinSigma(t1); + dca2 = fwdDcaXYinSigma(t2); + } + + // fill table here + dileptonTable(eventTable.lastIndex() + 1, // lastIndex starts from -1. + t1.pt(), t1.eta(), t1.phi(), t1.sign(), dca1, + t2.pt(), t2.eta(), t2.phi(), t2.sign(), dca2, + weight); + + return true; + } + + Filter collisionFilter_centrality = (eventcuts.cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < eventcuts.cfgCentMax) || (eventcuts.cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < eventcuts.cfgCentMax); + // Filter collisionFilter_numContrib = cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < cfgNumContribMax; + 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 && nabs(o2::aod::track::dcaXY) < dielectroncuts.cfg_max_dcaxy && nabs(o2::aod::track::dcaZ) < dielectroncuts.cfg_max_dcaz; + 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_20MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_20MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_40MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_40MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_60MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_60MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_80MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_80MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_100MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_100MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_120MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_120MeV))) <= static_cast(0), true) && + ifnode((dielectroncuts.cfg_prefilter_bits.node() & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_140MeV))) > static_cast(0), (o2::aod::emprimaryelectron::pfb & static_cast(1 << int(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_140MeV))) <= 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; + 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); + + 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] < eventcuts.cfgCentMin || eventcuts.cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + 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]; + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + + auto posTracks_per_coll = posTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + auto negTracks_per_coll = negTracks.sliceByCached(perCollision, collision.globalIndex(), cache); + + int nuls = 0, nlspp = 0, nlsmm = 0; + + if (cfgStoreULS) { + for (const auto& [pos, neg] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { // ULS + bool is_pair_ok = fillPairInfo(collision, pos, neg, cut, tracks); + if (is_pair_ok) { + nuls++; + } + } + } + if (cfgStoreLS) { + for (const auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_per_coll, posTracks_per_coll))) { // LS++ + bool is_pair_ok = fillPairInfo(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(collision, neg1, neg2, cut, tracks); + if (is_pair_ok) { + nlsmm++; + } + } + } + + if (nuls > 0 || nlspp > 0 || nlsmm > 0) { + eventTable(collision.runNumber(), collision.globalBC(), collision.timestamp(), collision.posZ(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.centFT0C(), ep2); + } + } // end of collision loop + } // end of DF + + template + bool isPairOK(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) || !cut.template IsSelectedTrack(t2)) { + 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, 0.0)) { + 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] < eventcuts.cfgCentMin || eventcuts.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); + 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(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(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(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(DileptonProducer, processAnalysis, "run dilepton analysis", true); + + void processNorm(aod::EMEventNormInfos const& collisions) + { + for (const auto& collision : collisions) { + if (collision.centFT0C() < eventcuts.cfgCentMin || eventcuts.cfgCentMax < collision.centFT0C()) { + continue; + } + + normTable(collision.selection_raw(), collision.rct_raw(), collision.posZint16(), collision.centFT0Cuint16()); + + } // end of collision loop + } + PROCESS_SWITCH(DileptonProducer, processNorm, "process normalization info", true); +}; + +#endif // PWGEM_DILEPTON_CORE_DILEPTONPRODUCER_H_ diff --git a/PWGEM/Dilepton/Core/DimuonCut.cxx b/PWGEM/Dilepton/Core/DimuonCut.cxx index 8f55e811dcb..c9cded44408 100644 --- a/PWGEM/Dilepton/Core/DimuonCut.cxx +++ b/PWGEM/Dilepton/Core/DimuonCut.cxx @@ -13,9 +13,12 @@ // Class for dimuon Cut // -#include "Framework/Logger.h" #include "PWGEM/Dilepton/Core/DimuonCut.h" +#include "Framework/Logger.h" + +#include + ClassImp(DimuonCut); void DimuonCut::SetMassRange(float min, float max) @@ -34,7 +37,7 @@ void DimuonCut::SetPairYRange(float minY, float maxY) { mMinPairY = minY; mMaxPairY = maxY; - LOG(info) << "Dimuon Cut, set pair eta range: " << mMinPairY << " - " << mMaxPairY; + LOG(info) << "Dimuon Cut, set pair rapidity range: " << mMinPairY << " - " << mMaxPairY; } void DimuonCut::SetPairDCAxyRange(float min, float max) { @@ -42,6 +45,13 @@ void DimuonCut::SetPairDCAxyRange(float min, float max) 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; @@ -59,12 +69,24 @@ void DimuonCut::SetTrackEtaRange(float minEta, float maxEta) 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::SetChi2MFT(float min, float max) +{ + mMinChi2MFT = min; + mMaxChi2MFT = max; + LOG(info) << "Dimuon Cut, set chi2mft range: " << mMinChi2MFT << " - " << mMaxChi2MFT; +} void DimuonCut::SetMatchingChi2MCHMFT(float min, float max) { mMinMatchingChi2MCHMFT = min; @@ -106,3 +128,22 @@ void DimuonCut::SetMaxPDCARabsDep(std::function RabsDepCut) mMaxPDCARabsDep = RabsDepCut; LOG(info) << "Dimuon Cut, set max pDCA as a function of Rabs: " << mMaxPDCARabsDep(10.0); } +void DimuonCut::SetMFTHitMap(bool flag, std::vector hitMap) +{ + mApplyMFTHitMap = flag; + mRequiredMFTDisks = hitMap; + if (mApplyMFTHitMap) { + for (const auto& iDisk : mRequiredMFTDisks) { + LOG(info) << "Dimuon Cut, require MFT hit on Disk: " << iDisk; + } + } +} +void DimuonCut::SetMaxdPtdEtadPhiwrtMCHMID(float reldPtMax, float dEtaMax, float dPhiMax) +{ + mMaxReldPtwrtMCHMID = reldPtMax; + mMaxdEtawrtMCHMID = dEtaMax; + mMaxdPhiwrtMCHMID = dPhiMax; + LOG(info) << "Dimuon Cut, set max rel. dpt between MFT-MCH-MID and associated MCH-MID: " << mMaxReldPtwrtMCHMID; + LOG(info) << "Dimuon Cut, set max deta between MFT-MCH-MID and associated MCH-MID: " << mMaxdEtawrtMCHMID; + LOG(info) << "Dimuon Cut, set max dphi between MFT-MCH-MID and associated MCH-MID: " << mMaxdPhiwrtMCHMID; +} diff --git a/PWGEM/Dilepton/Core/DimuonCut.h b/PWGEM/Dilepton/Core/DimuonCut.h index 8af3161d670..80968cc9e81 100644 --- a/PWGEM/Dilepton/Core/DimuonCut.h +++ b/PWGEM/Dilepton/Core/DimuonCut.h @@ -16,18 +16,21 @@ #ifndef PWGEM_DILEPTON_CORE_DIMUONCUT_H_ #define PWGEM_DILEPTON_CORE_DIMUONCUT_H_ +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/DataTypes.h" +#include "Framework/Logger.h" +#include "MathUtils/Utils.h" + +#include "Math/Vector4D.h" +#include "TNamed.h" + #include #include -#include -#include #include -#include "TNamed.h" -#include "Math/Vector4D.h" - -#include "Framework/Logger.h" -#include "Framework/DataTypes.h" -#include "CommonConstants/PhysicsConstants.h" -#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include +#include using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; @@ -49,14 +52,18 @@ class DimuonCut : public TNamed kTrackType, kTrackPtRange, kTrackEtaRange, + kTrackPhiRange, kDCAxy, kMFTNCls, kMCHMIDNCls, kChi2, kMatchingChi2MCHMFT, kMatchingChi2MCHMID, + kChi2MFT, kRabs, kPDCA, + kMFTHitMap, + kDPtDEtaDPhiwrtMCHMID, kNCuts }; @@ -77,7 +84,7 @@ class DimuonCut : public TNamed return true; } - template + template bool IsSelectedPair(TTrack1 const& t1, TTrack2 const& t2) const { ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassMuon); @@ -96,26 +103,40 @@ class DimuonCut : public TNamed return false; } - if (v12.Rapidity() < mMinPairY || mMaxPairY < v12.Rapidity()) { + 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 + template bool IsSelectedTrack(TTrack const& track) const { if (!IsSelectedTrack(track, DimuonCuts::kTrackType)) { return false; } - if (!IsSelectedTrack(track, DimuonCuts::kTrackPtRange)) { - return false; + + if (!dont_require_pteta) { + if (!IsSelectedTrack(track, DimuonCuts::kTrackPtRange)) { + return false; + } + if (!IsSelectedTrack(track, DimuonCuts::kTrackEtaRange)) { + return false; + } } - if (!IsSelectedTrack(track, DimuonCuts::kTrackEtaRange)) { + if (!IsSelectedTrack(track, DimuonCuts::kTrackPhiRange)) { return false; } if (!IsSelectedTrack(track, DimuonCuts::kDCAxy)) { @@ -136,12 +157,21 @@ class DimuonCut : public TNamed if (!IsSelectedTrack(track, DimuonCuts::kMatchingChi2MCHMID)) { return false; } + if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && !IsSelectedTrack(track, DimuonCuts::kChi2MFT)) { + return false; + } if (!IsSelectedTrack(track, DimuonCuts::kPDCA)) { return false; } if (!IsSelectedTrack(track, DimuonCuts::kRabs)) { return false; } + if (mApplyMFTHitMap && track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && !IsSelectedTrack(track, DimuonCuts::kMFTHitMap)) { + return false; + } + if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && !IsSelectedTrack(track, DimuonCuts::kDPtDEtaDPhiwrtMCHMID)) { + return false; + } return true; } @@ -159,6 +189,9 @@ class DimuonCut : public TNamed 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; @@ -169,7 +202,10 @@ class DimuonCut : public TNamed return track.nClusters() >= mMinNClustersMCHMID; case DimuonCuts::kChi2: - return track.chi2() < mMaxChi2; + return track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2() / (2.f * (track.nClusters() + track.nClustersMFT()) - 5.f) < mMaxChi2 : track.chi2() < mMaxChi2; + + case DimuonCuts::kChi2MFT: + return track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2MFT() / (2.f * track.nClustersMFT() - 5.f) < mMaxChi2MFT : true; case DimuonCuts::kMatchingChi2MCHMFT: return track.chi2MatchMCHMFT() < mMaxMatchingChi2MCHMFT; @@ -183,6 +219,19 @@ class DimuonCut : public TNamed case DimuonCuts::kRabs: return mMinRabs < track.rAtAbsorberEnd() && track.rAtAbsorberEnd() < mMaxRabs; + case DimuonCuts::kMFTHitMap: { + std::vector mftHitMap{checkMFTHitMap<0, 1>(track), checkMFTHitMap<2, 3>(track), checkMFTHitMap<4, 5>(track), checkMFTHitMap<6, 7>(track), checkMFTHitMap<8, 9>(track)}; + for (const auto& iDisk : mRequiredMFTDisks) { + if (!mftHitMap[iDisk]) { + return false; + } + } + return true; + } + + case DimuonCuts::kDPtDEtaDPhiwrtMCHMID: + return std::fabs(track.ptMatchedMCHMID() - track.pt()) / track.pt() < mMaxReldPtwrtMCHMID && std::sqrt(std::pow((track.etaMatchedMCHMID() - track.eta()) / mMaxdEtawrtMCHMID, 2) + std::pow((track.phiMatchedMCHMID() - track.phi()) / mMaxdPhiwrtMCHMID, 2)) < 1.f; + default: return false; } @@ -193,18 +242,23 @@ class DimuonCut : public TNamed 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 SetChi2MFT(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); + void SetMFTHitMap(bool flag, std::vector hitMap); + void SetMaxdPtdEtadPhiwrtMCHMID(float reldPtMax, float dEtaMax, float dPhiMax); // this is relevant for global muons private: // pair cuts @@ -212,22 +266,30 @@ class DimuonCut : public TNamed 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 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 + int mMinNClustersMFT{0}, mMaxNClustersMFT{10}; // min number of MFT clusters + int mMinNClustersMCHMID{0}, mMaxNClustersMCHMID{20}; // min number of MCH-MID clusters + float mMinChi2{0.f}, mMaxChi2{1e10f}; // max chi2 per MFT + MCH cluster + float mMinChi2MFT{0.f}, mMaxChi2MFT{1e10f}; // max chi2 per MFT cluster + float mMinMatchingChi2MCHMFT{0.f}, mMaxMatchingChi2MCHMFT{1e10f}; // max matching chi2 between MCH-MFT + float mMinMatchingChi2MCHMID{0.f}, mMaxMatchingChi2MCHMID{1e10f}; // max matching chi2 between MCH-MID 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}; + float mMaxReldPtwrtMCHMID{1e10f}, mMaxdEtawrtMCHMID{1e10f}, mMaxdPhiwrtMCHMID{1e10f}; + bool mApplyMFTHitMap{false}; + std::vector mRequiredMFTDisks{}; ClassDef(DimuonCut, 1); }; diff --git a/PWGEM/Dilepton/Core/EMEventCut.cxx b/PWGEM/Dilepton/Core/EMEventCut.cxx index c4f5372597b..58e3c5be4e8 100644 --- a/PWGEM/Dilepton/Core/EMEventCut.cxx +++ b/PWGEM/Dilepton/Core/EMEventCut.cxx @@ -13,9 +13,10 @@ // Class for em event selection // -#include "Framework/Logger.h" #include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "Framework/Logger.h" + ClassImp(EMEventCut); void EMEventCut::SetRequireSel8(bool flag) @@ -37,13 +38,6 @@ void EMEventCut::SetZvtxRange(float min, float max) LOG(info) << "EM Event Cut, set z vtx range: " << mMinZvtx << " - " << mMaxZvtx; } -void EMEventCut::SetOccupancyRange(int min, int max) -{ - mMinOccupancy = min; - mMaxOccupancy = max; - LOG(info) << "EM Event Cut, set occupancy range: " << mMinOccupancy << " - " << mMaxOccupancy; -} - void EMEventCut::SetRequireNoTFB(bool flag) { mRequireNoTFB = flag; @@ -68,8 +62,61 @@ void EMEventCut::SetRequireVertexITSTPC(bool flag) LOG(info) << "EM Event Cut, require vertex reconstructed by ITS-TPC matched track: " << mRequireVertexITSTPC; } +void EMEventCut::SetRequireVertexTOFmatched(bool flag) +{ + mRequireVertexTOFmatched = flag; + LOG(info) << "EM Event Cut, require vertex reconstructed by ITS-TPC-TOF matched track: " << mRequireVertexTOFmatched; +} + void EMEventCut::SetRequireGoodZvtxFT0vsPV(bool flag) { mRequireGoodZvtxFT0vsPV = flag; LOG(info) << "EM Event Cut, require good Zvtx between FT0 vs. PV: " << mRequireGoodZvtxFT0vsPV; } + +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/Dilepton/Core/EMEventCut.h b/PWGEM/Dilepton/Core/EMEventCut.h index 1950414c0c4..8dc1b7ef961 100644 --- a/PWGEM/Dilepton/Core/EMEventCut.h +++ b/PWGEM/Dilepton/Core/EMEventCut.h @@ -16,10 +16,11 @@ #ifndef PWGEM_DILEPTON_CORE_EMEVENTCUT_H_ #define PWGEM_DILEPTON_CORE_EMEVENTCUT_H_ -#include "TNamed.h" #include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/TriggerAliases.h" +#include "TNamed.h" + using namespace std; class EMEventCut : public TNamed @@ -37,8 +38,16 @@ class EMEventCut : public TNamed kNoITSROFB, // no ITS read out frame border kNoSameBunchPileup, kIsVertexITSTPC, + kIsVertexTOFmatched, kIsGoodZvtxFT0vsPV, - kOccupancy, + kNoCollInTimeRangeStandard, + kNoCollInTimeRangeStrict, + kNoCollInITSROFStandard, + kNoCollInITSROFStrict, + kNoHighMultCollInPrevRof, + kIsGoodITSLayer3, + kIsGoodITSLayer0123, + kIsGoodITSLayersAll, kNCuts }; @@ -66,10 +75,34 @@ class EMEventCut : public TNamed if (mRequireVertexITSTPC && !IsSelected(collision, EMEventCuts::kIsVertexITSTPC)) { return false; } + if (mRequireVertexTOFmatched && !IsSelected(collision, EMEventCuts::kIsVertexTOFmatched)) { + return false; + } if (mRequireGoodZvtxFT0vsPV && !IsSelected(collision, EMEventCuts::kIsGoodZvtxFT0vsPV)) { return false; } - if (!IsSelected(collision, EMEventCuts::kOccupancy)) { + 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,16 +133,36 @@ class EMEventCut : public TNamed case EMEventCuts::kIsVertexITSTPC: return collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC); + case EMEventCuts::kIsVertexTOFmatched: + return collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched); + case EMEventCuts::kIsGoodZvtxFT0vsPV: return collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); - case EMEventCuts::kOccupancy: { - if (mMinOccupancy < 0) { - return true; - } else { - return mMinOccupancy <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < mMaxOccupancy; - } - } + 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 true; } @@ -119,23 +172,39 @@ class EMEventCut : public TNamed void SetRequireSel8(bool flag); void SetRequireFT0AND(bool flag); void SetZvtxRange(float min, float max); - void SetOccupancyRange(int min, int max); void SetRequireNoTFB(bool flag); void SetRequireNoITSROFB(bool flag); void SetRequireNoSameBunchPileup(bool flag); void SetRequireVertexITSTPC(bool flag); + void SetRequireVertexTOFmatched(bool flag); 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}; - int mMinOccupancy{static_cast(-1e+9)}, mMaxOccupancy{static_cast(+1e+9)}; - bool mRequireNoTFB{true}; - bool mRequireNoITSROFB{true}; + bool mRequireNoTFB{false}; + bool mRequireNoITSROFB{false}; bool mRequireNoSameBunchPileup{false}; bool mRequireVertexITSTPC{false}; + bool mRequireVertexTOFmatched{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); }; diff --git a/PWGEM/Dilepton/Core/EMTrackCut.cxx b/PWGEM/Dilepton/Core/EMTrackCut.cxx new file mode 100644 index 00000000000..2ea7934a30b --- /dev/null +++ b/PWGEM/Dilepton/Core/EMTrackCut.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. + +// +// Class for track Cut +// + +#include "PWGEM/Dilepton/Core/EMTrackCut.h" + +#include "Framework/Logger.h" + +#include +#include + +ClassImp(EMTrackCut); + +const std::pair> EMTrackCut::its_ib_any_Requirement = {1, {0, 1, 2}}; // hits on any ITS ib layers. +const std::pair> EMTrackCut::its_ib_1st_Requirement = {1, {0}}; // hit on 1st ITS ib layers. + +void EMTrackCut::SetTrackPtRange(float minPt, float maxPt) +{ + mMinTrackPt = minPt; + mMaxTrackPt = maxPt; + LOG(info) << "EMTrack Cut, set track pt range: " << mMinTrackPt << " - " << mMaxTrackPt; +} +void EMTrackCut::SetTrackEtaRange(float minEta, float maxEta) +{ + mMinTrackEta = minEta; + mMaxTrackEta = maxEta; + LOG(info) << "EMTrack Cut, set track eta range: " << mMinTrackEta << " - " << mMaxTrackEta; +} +void EMTrackCut::SetTrackPhiRange(float minPhi, float maxPhi) +{ + mMinTrackPhi = minPhi; + mMaxTrackPhi = maxPhi; + LOG(info) << "EMTrack Cut, set track phi range (rad.): " << mMinTrackPhi << " - " << mMaxTrackPhi; +} +void EMTrackCut::SetMinNClustersTPC(int minNClustersTPC) +{ + mMinNClustersTPC = minNClustersTPC; + LOG(info) << "EMTrack Cut, set min N clusters TPC: " << mMinNClustersTPC; +} +void EMTrackCut::SetMinNCrossedRowsTPC(int minNCrossedRowsTPC) +{ + mMinNCrossedRowsTPC = minNCrossedRowsTPC; + LOG(info) << "EMTrack Cut, set min N crossed rows TPC: " << mMinNCrossedRowsTPC; +} +void EMTrackCut::SetMinNCrossedRowsOverFindableClustersTPC(float minNCrossedRowsOverFindableClustersTPC) +{ + mMinNCrossedRowsOverFindableClustersTPC = minNCrossedRowsOverFindableClustersTPC; + LOG(info) << "EMTrack Cut, set min N crossed rows over findable clusters TPC: " << mMinNCrossedRowsOverFindableClustersTPC; +} +void EMTrackCut::SetMaxFracSharedClustersTPC(float max) +{ + mMaxFracSharedClustersTPC = max; + LOG(info) << "EMTrack Cut, set max fraction of shared clusters in TPC: " << mMaxFracSharedClustersTPC; +} +void EMTrackCut::SetChi2PerClusterTPC(float min, float max) +{ + mMinChi2PerClusterTPC = min; + mMaxChi2PerClusterTPC = max; + LOG(info) << "EMTrack Cut, set chi2 per cluster TPC range: " << mMinChi2PerClusterTPC << " - " << mMaxChi2PerClusterTPC; +} + +void EMTrackCut::SetNClustersITS(int min, int max) +{ + mMinNClustersITS = min; + mMaxNClustersITS = max; + LOG(info) << "EMTrack Cut, set N clusters ITS range: " << mMinNClustersITS << " - " << mMaxNClustersITS; +} +void EMTrackCut::SetChi2PerClusterITS(float min, float max) +{ + mMinChi2PerClusterITS = min; + mMaxChi2PerClusterITS = max; + LOG(info) << "EMTrack Cut, set chi2 per cluster ITS range: " << mMinChi2PerClusterITS << " - " << mMaxChi2PerClusterITS; +} + +void EMTrackCut::SetTrackMaxDcaXY(float maxDcaXY) +{ + mMaxDcaXY = maxDcaXY; + LOG(info) << "EMTrack Cut, set max DCA xy: " << mMaxDcaXY; +} +void EMTrackCut::SetTrackMaxDcaZ(float maxDcaZ) +{ + mMaxDcaZ = maxDcaZ; + LOG(info) << "EMTrack Cut, set max DCA z: " << mMaxDcaZ; +} + +void EMTrackCut::SetTrackMaxDcaXYPtDep(std::function ptDepCut) +{ + mMaxDcaXYPtDep = ptDepCut; + LOG(info) << "EMTrack Cut, set max DCA xy pt dep: " << mMaxDcaXYPtDep(1.0); +} + +void EMTrackCut::RequireITSibAny(bool flag) +{ + mRequireITSibAny = flag; + LOG(info) << "EMTrack Cut, require ITS ib any: " << mRequireITSibAny; +} + +void EMTrackCut::RequireITSib1st(bool flag) +{ + mRequireITSib1st = flag; + LOG(info) << "EMTrack Cut, require ITS ib 1st: " << mRequireITSib1st; +} + +void EMTrackCut::SetTrackBit(uint16_t bit) +{ + mTrackBit = bit; + LOG(info) << "EMTrack Cut, require track bits: " << mTrackBit; +} diff --git a/PWGEM/Dilepton/Core/EMTrackCut.h b/PWGEM/Dilepton/Core/EMTrackCut.h new file mode 100644 index 00000000000..d70a009aaac --- /dev/null +++ b/PWGEM/Dilepton/Core/EMTrackCut.h @@ -0,0 +1,234 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 track selection +// + +#ifndef PWGEM_DILEPTON_CORE_EMTRACKCUT_H_ +#define PWGEM_DILEPTON_CORE_EMTRACKCUT_H_ + +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/DataTypes.h" +#include "Framework/Logger.h" + +#include "Math/Vector4D.h" +#include "TNamed.h" + +#include +#include +#include +#include +#include + +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; + +class EMTrackCut : public TNamed +{ + public: + EMTrackCut() = default; + EMTrackCut(const char* name, const char* title) : TNamed(name, title) {} + ~EMTrackCut() {} + + enum class EMTrackCuts : int { + // track cut + kTrackPtRange, + kTrackEtaRange, + kTrackPhiRange, + // kDCAxy, + // kDCAz, + // kTPCNCls, + // kTPCCrossedRows, + // kTPCCrossedRowsOverNCls, + // kTPCFracSharedClusters, + // kTPCChi2NDF, + // kITSNCls, + // kITSChi2NDF, + kTrackBit, + kNCuts + }; + + template + bool IsSelected(TTrack const& track) const + { + // if (!track.hasITS() || !track.hasTPC()) { + // return false; + // } + + if (!IsSelectedTrack(track, EMTrackCuts::kTrackPtRange)) { + return false; + } + if (!IsSelectedTrack(track, EMTrackCuts::kTrackEtaRange)) { + return false; + } + if (!IsSelectedTrack(track, EMTrackCuts::kTrackPhiRange)) { + return false; + } + + // if (!IsSelectedTrack(track, EMTrackCuts::kDCAxy)) { + // return false; + // } + // if (!IsSelectedTrack(track, EMTrackCuts::kDCAz)) { + // return false; + // } + + if (!IsSelectedTrack(track, EMTrackCuts::kTrackBit)) { + return false; + } + + // // ITS cuts + // if (!IsSelectedTrack(track, EMTrackCuts::kITSNCls)) { + // return false; + // } + // if (!IsSelectedTrack(track, EMTrackCuts::kITSChi2NDF)) { + // 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, EMTrackCuts::kTPCNCls)) { + // return false; + // } + // if (!IsSelectedTrack(track, EMTrackCuts::kTPCCrossedRows)) { + // return false; + // } + // if (!IsSelectedTrack(track, EMTrackCuts::kTPCCrossedRowsOverNCls)) { + // return false; + // } + // if (!IsSelectedTrack(track, EMTrackCuts::kTPCFracSharedClusters)) { + // return false; + // } + // if (!IsSelectedTrack(track, EMTrackCuts::kTPCChi2NDF)) { + // return false; + // } + + return true; + } + + template + bool IsSelectedTrack(T const& track, const EMTrackCuts& cut) const + { + switch (cut) { + case EMTrackCuts::kTrackPtRange: + return track.pt() > mMinTrackPt && track.pt() < mMaxTrackPt; + + case EMTrackCuts::kTrackEtaRange: + return track.eta() > mMinTrackEta && track.eta() < mMaxTrackEta; + + case EMTrackCuts::kTrackPhiRange: + return track.phi() > mMinTrackPhi && track.phi() < mMaxTrackPhi; + + // case EMTrackCuts::kDCAxy: + // return std::fabs(track.dcaXY()) < ((mMaxDcaXYPtDep) ? mMaxDcaXYPtDep(track.pt()) : mMaxDcaXY); + + // case EMTrackCuts::kDCAz: + // return std::fabs(track.dcaZ()) < mMaxDcaZ; + + case EMTrackCuts::kTrackBit: { + // for (int i = 0; i < 10; i++) { + // if ((mTrackBit & (1 << i)) > 0 && !((track.trackBit() & (1 << i)) > 0)) { + // return false; + // } + // } + // return true; + return (track.trackBit() & mTrackBit) >= mTrackBit; + } + + // case EMTrackCuts::kTPCNCls: + // return track.tpcNClsFound() >= mMinNClustersTPC; + + // case EMTrackCuts::kTPCCrossedRows: + // return track.tpcNClsCrossedRows() >= mMinNCrossedRowsTPC; + + // case EMTrackCuts::kTPCCrossedRowsOverNCls: + // return track.tpcCrossedRowsOverFindableCls() > mMinNCrossedRowsOverFindableClustersTPC; + + // case EMTrackCuts::kTPCFracSharedClusters: + // return track.tpcFractionSharedCls() < mMaxFracSharedClustersTPC; + + // case EMTrackCuts::kTPCChi2NDF: + // return mMinChi2PerClusterTPC < track.tpcChi2NCl() && track.tpcChi2NCl() < mMaxChi2PerClusterTPC; + + // case EMTrackCuts::kITSNCls: + // return mMinNClustersITS <= track.itsNCls() && track.itsNCls() <= mMaxNClustersITS; + + // case EMTrackCuts::kITSChi2NDF: + // return mMinChi2PerClusterITS < track.itsChi2NCl() && track.itsChi2NCl() < mMaxChi2PerClusterITS; + + default: + return false; + } + } + + // Setters + 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 = 6.3f); + 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 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 RequireITSibAny(bool flag); + void RequireITSib1st(bool flag); + void SetTrackBit(uint16_t bits); + + private: + static const std::pair> its_ib_any_Requirement; + static const std::pair> its_ib_1st_Requirement; + + // kinematic cuts + float mMinTrackPt{0.f}, mMaxTrackPt{1e10f}; // range in pT + float mMinTrackEta{-1e10f}, mMaxTrackEta{1e10f}; // range in eta + float mMinTrackPhi{0.f}, mMaxTrackPhi{6.3}; // 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{0.f}, 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{0.f}, mMaxChi2PerClusterITS{1e10f}; // max its fit chi2 per ITS cluster + bool mRequireITSibAny{true}; + bool mRequireITSib1st{false}; + uint16_t mTrackBit{0}; + + 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 + + ClassDef(EMTrackCut, 1); +}; + +#endif // PWGEM_DILEPTON_CORE_EMTRACKCUT_H_ diff --git a/PWGEM/Dilepton/Core/PWGEMDileptonCoreLinkDef.h b/PWGEM/Dilepton/Core/PWGEMDileptonCoreLinkDef.h index c1af31aa27b..fe78534478e 100644 --- a/PWGEM/Dilepton/Core/PWGEMDileptonCoreLinkDef.h +++ b/PWGEM/Dilepton/Core/PWGEMDileptonCoreLinkDef.h @@ -19,5 +19,6 @@ #pragma link C++ class EMEventCut + ; #pragma link C++ class DielectronCut + ; #pragma link C++ class DimuonCut + ; +#pragma link C++ class EMTrackCut + ; #endif // PWGEM_DILEPTON_CORE_PWGEMDILEPTONCORELINKDEF_H_ diff --git a/PWGEM/Dilepton/Core/PhotonHBT.h b/PWGEM/Dilepton/Core/PhotonHBT.h index c9f1e3739c6..dad67122eeb 100644 --- a/PWGEM/Dilepton/Core/PhotonHBT.h +++ b/PWGEM/Dilepton/Core/PhotonHBT.h @@ -17,39 +17,42 @@ #ifndef PWGEM_DILEPTON_CORE_PHOTONHBT_H_ #define PWGEM_DILEPTON_CORE_PHOTONHBT_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/EventMixingHandler.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TString.h" + +#include #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 "Tools/ML/model.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" - namespace o2::aod::pwgem::dilepton::core::photonhbt { enum class ggHBTPairType : int { @@ -71,13 +74,13 @@ using namespace o2::aod::pwgem::dilepton::core::photonhbt; using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyCollisionsWithSWT = soa::Join; +using MyCollisionsWithSWT = soa::Join; using MyCollisionWithSWT = MyCollisionsWithSWT::iterator; using MyV0Photons = soa::Join; using MyV0Photon = MyV0Photons::iterator; -using MyTracks = soa::Join; +using MyTracks = soa::Join; using MyTrack = MyTracks::iterator; using FilteredMyTracks = soa::Filtered; using FilteredMyTrack = FilteredMyTracks::iterator; @@ -92,30 +95,36 @@ struct PhotonHBT { 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, NTPV:3"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; - Configurable cfgSpherocityMin{"cfgSpherocityMin", -999.f, "min. spherocity"}; - Configurable cfgSpherocityMax{"cfgSpherocityMax", +999.f, "max. spherocity"}; 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", {VARIABLE_WIDTH, -M_PI / 2, -M_PI / 4, 0.0f, +M_PI / 4, +M_PI / 2}, "Mixing bins - event plane angle"}; + 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 cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; 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 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}, "kT bins for output histograms"}; + 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 cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + 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"}; @@ -123,8 +132,18 @@ struct PhotonHBT { 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"}; + 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; @@ -133,7 +152,6 @@ struct PhotonHBT { 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_require_v0_on_wwire_ib{"cfg_require_v0_on_wwire_ib", false, "flag to select V0s on W wires ITSib"}; 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"}; @@ -142,12 +160,14 @@ struct PhotonHBT { 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_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; 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"}; @@ -158,36 +178,46 @@ struct PhotonHBT { 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", 2.5, "max mass"}; // this is valid, because only ULS is used. + 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", 2.0, "max 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.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_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_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_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]"}; + 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_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"}; @@ -196,12 +226,27 @@ struct PhotonHBT { 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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; + 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"}; - - // CCDB configuration for PID ML - Configurable BDTLocalPathGamma{"BDTLocalPathGamma", "pid_ml_xgboost.onnx", "Path to the local .onnx file"}; - - Configurable BDTPathCCDB{"BDTPathCCDB", "Users/d/dsekihat/pwgem/pidml/", "Path on CCDB"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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)"}; @@ -209,9 +254,17 @@ struct PhotonHBT { struct : ConfigurableGroup { std::string prefix = "ggpaircut_group"; - Configurable applydR{"applydR", false, "apply deta-dphi cut to avoid track splitting/merging"}; - Configurable cfgMinDeltaEta{"cfgMinDeltaEta", 0.f, "min. delta-eta between 2 photons"}; - Configurable cfgMinDeltaPhi{"cfgMinDeltaPhi", 0.f, "min. delta-phi between 2 photons"}; + // 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() @@ -221,20 +274,21 @@ struct PhotonHBT { 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(); - if (eid_bdt) { - delete eid_bdt; - } + used_photonIds_per_col.clear(); + used_photonIds_per_col.shrink_to_fit(); + used_dileptonIds_per_col.clear(); + used_dileptonIds_per_col.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; @@ -247,17 +301,74 @@ struct PhotonHBT { void init(InitContext& /*context*/) { - zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); - zvtx_bin_edges.erase(zvtx_bin_edges.begin()); + 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]); + } + } - cent_bin_edges = std::vector(ConfCentBins.value.begin(), ConfCentBins.value.end()); - cent_bin_edges.erase(cent_bin_edges.begin()); + 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]); + } + } - ep_bin_edges = std::vector(ConfEPBins.value.begin(), ConfEPBins.value.end()); - ep_bin_edges.erase(ep_bin_edges.begin()); + 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]); + } + } - occ_bin_edges = std::vector(ConfOccupancyBins.value.begin(), ConfOccupancyBins.value.end()); - occ_bin_edges.erase(occ_bin_edges.begin()); + 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]); + } + } emh1 = new MyEMH(ndepth); emh2 = new MyEMH(ndepth); @@ -272,8 +383,19 @@ struct PhotonHBT { 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); + LOGF(info, "Trigger analysis is enabled. Desired trigger name = %s", cfg_swt_name.value); + fRegistry.add("NormTrigger/hInspectedTVX", "inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + fRegistry.add("NormTrigger/hScalers", "trigger counter before DS;run number;counter", kTProfile, {{80000, 520000.5, 600000.5}}, true); + fRegistry.add("NormTrigger/hSelections", "trigger counter after DS;run number;counter", kTProfile, {{80000, 520000.5, 600000.5}}, true); + auto hTriggerCounter = fRegistry.add("NormTrigger/hTriggerCounter", Form("trigger counter of %s;run number;", cfg_swt_name.value.data()), kTH2D, {{80000, 520000.5, 600000.5}, {2, -0.5, 1.5}}, false); + hTriggerCounter->GetYaxis()->SetBinLabel(1, "Analyzed Trigger"); + hTriggerCounter->GetYaxis()->SetBinLabel(2, "Analyzed TOI"); } } @@ -288,7 +410,7 @@ struct PhotonHBT { 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)); } mRunNumber = collision.runNumber(); @@ -317,8 +439,8 @@ struct PhotonHBT { 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()); + // LOGF(info, "total inspected TVX events = %d in run number %d", collision.nInspectedTVX(), collision.runNumber()); + // fRegistry.fill(HIST("Event/hNInspectedTVX"), collision.runNumber(), collision.nInspectedTVX()); } } @@ -330,17 +452,44 @@ struct PhotonHBT { 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); + } + } - const AxisSpec axis_qinv{30, 0.0, +0.3, "q_{inv} (GeV/c)"}; - const AxisSpec axis_qabs_lcms{30, 0.0, +0.3, "|#bf{q}|^{LCMS} (GeV/c)"}; - const AxisSpec axis_qout{60, -0.3, +0.3, "q_{out} (GeV/c)"}; // qout does not change between LAB and LCMS frame - const AxisSpec axis_qside{60, -0.3, +0.3, "q_{side} (GeV/c)"}; // qside does not change between LAB and LCMS frame - const AxisSpec axis_qlong{60, -0.3, +0.3, "q_{long} (GeV/c)"}; + 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.add("Pair/same/hs_1d", "diphoton correlation 1D", kTHnSparseD, {axis_kt, axis_qinv, axis_qabs_lcms}, true); - fRegistry.add("Pair/same/hs_3d", "diphoton correlation 3D LCMS", kTHnSparseD, {axis_kt, axis_qout, axis_qside, axis_qlong}, true); - fRegistry.add("Pair/same/hDeltaEtaDeltaPhi", "diphoton distance in #eta-#varphi plane;#Delta#varphi (rad);#Delta#eta", kTH2D, {{200, -0.1, +0.1}, {200, -0.1, 0.1}}, false); fRegistry.addClone("Pair/same/", "Pair/mix/"); } @@ -349,13 +498,20 @@ struct PhotonHBT { fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); - fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + 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.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); + 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() @@ -367,53 +523,29 @@ struct PhotonHBT { 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.SetTrackPtRange(pcmcuts.cfg_min_pt_v0 * 0.5, 1e+10f); - fV0PhotonCut.SetTrackEtaRange(-pcmcuts.cfg_max_eta_v0, +pcmcuts.cfg_max_eta_v0); 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); - - if (pcmcuts.cfg_reject_v0_on_itsib) { - fV0PhotonCut.SetNClustersITS(2, 4); - } else { - fV0PhotonCut.SetNClustersITS(0, 7); - } + 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); - - if (pcmcuts.cfg_require_v0_with_itstpc) { - fV0PhotonCut.SetRequireITSTPC(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 40); - } - if (pcmcuts.cfg_require_v0_with_itsonly) { - fV0PhotonCut.SetRequireITSonly(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 24); - } - if (pcmcuts.cfg_require_v0_with_tpconly) { - fV0PhotonCut.SetRequireTPConly(true); - fV0PhotonCut.SetMaxPCA(3.0); - fV0PhotonCut.SetRxyRange(36, 90); - } - if (pcmcuts.cfg_require_v0_on_wwire_ib) { - fV0PhotonCut.SetMaxPCA(0.3); - fV0PhotonCut.SetOnWwireIB(true); - fV0PhotonCut.SetOnWwireOB(false); - fV0PhotonCut.SetRxyRange(7, 14); - } + 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::ml::OnnxModel* eid_bdt = nullptr; + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDileptonCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); @@ -422,7 +554,7 @@ struct PhotonHBT { 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.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dielectroncuts.cfg_phiv_intercept) / dielectroncuts.cfg_phiv_slope; }); + 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); @@ -430,79 +562,100 @@ struct PhotonHBT { fDielectronCut.RequireITSib1st(dielectroncuts.cfg_require_itsib_1st); // for track - fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, 1e+10f); + 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.SetMeanClusterSizeITSob(0, 16); - fDielectronCut.SetMaxDcaXY(dielectroncuts.cfg_max_dcaxy); - fDielectronCut.SetMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); // 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.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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, 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 - eid_bdt = new o2::ml::OnnxModel(); - if (dielectroncuts.loadModelsFromCCDB) { - ccdbApi.init(ccdburl); - std::map metadata; - bool retrieveSuccessGamma = ccdbApi.retrieveBlob(dielectroncuts.BDTPathCCDB.value, ".", metadata, dielectroncuts.timestampCCDB.value, false, dielectroncuts.BDTLocalPathGamma.value); - if (retrieveSuccessGamma) { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); - } else { - LOG(fatal) << "Error encountered while fetching/loading the Gamma model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; - } - } else { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); + std::vector binsML{}; + binsML.reserve(dielectroncuts.binsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(dielectroncuts.binsMl.value[i]); } - - fDielectronCut.SetPIDModel(eid_bdt); + std::vector thresholdsML{}; + thresholdsML.reserve(dielectroncuts.cutsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + + // static constexpr int nClassesMl = 2; + // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + // const std::vector labelsClasses = {"Background", "Signal"}; + // 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] = 0.; + // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; + // } + // 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& /*collision*/, const ROOT::Math::PtEtaPhiMVector v1, const ROOT::Math::PtEtaPhiMVector v2, const float weight = 1.f) + void fillPairHistogram(TCollision const&, const ROOT::Math::PtEtaPhiMVector v1, const ROOT::Math::PtEtaPhiMVector v2, const float weight = 1.f) { - // if constexpr (ev_id == 1 && pairtype == ggHBTPairType::kEEEE) { - // if (t1.has_ambiguousElectrons() && t2.has_ambiguousElectrons()) { - // for (auto& possible_id1 : t1.ambiguousElectronsIds()) { - // for (auto& possible_id2 : t2.ambiguousElectronsIds()) { - // if (possible_id1 == possible_id2) { - // // LOGF(info, "event id = %d: same track is found. t1.trackId() = %d, t1.collisionId() = %d, t1.pt() = %f, t1.eta() = %f, t1.phi() = %f, t2.trackId() = %d, t2.collisionId() = %d, t2.pt() = %f, t2.eta() = %f, t2.phi() = %f", ev_id, t1.trackId(), t1.collisionId(), t1.pt(), t1.eta(), t1.phi(), t2.trackId(), t2.collisionId(), t2.pt(), t2.eta(), 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. - // } - // } - // } - // } - // } - - // center-of-mass system (CMS) - ROOT::Math::PtEtaPhiMVector q12 = v1 - v2; + 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(); + float qinv = -q12.M(); // for identical particles -> qinv = 2 x kstar float kt = k12.Pt(); - // 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 qlong_lab = q_3d.Dot(uv_long); + + 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::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); ROOT::Math::XYZVector q_3d_lcms = q12_lcms.Vect(); // 3D q vector in LCMS @@ -511,6 +664,17 @@ struct PhotonHBT { 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); @@ -525,21 +689,24 @@ struct PhotonHBT { // float qabs_lcms_tmp = q12_lcms.P(); // LOGF(info, "qabs_lcms = %f, qabs_lcms_tmp = %f", qabs_lcms, qabs_lcms_tmp); - float deta = v1.Eta() - v2.Eta(); - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hDeltaEtaDeltaPhi"), dphi, deta, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hs_1d"), kt, qinv, qabs_lcms, weight); - fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("hs_3d"), kt, qout_lcms, qside_lcms, qlong_lcms, weight); + 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) { + for (const auto& collision : collisions) { initCCDB(collision); int ndiphoton = 0; - const float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -547,10 +714,10 @@ struct PhotonHBT { 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()); + // 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]; @@ -587,7 +754,15 @@ struct PhotonHBT { epbin = static_cast(ep_bin_edges.size()) - 2; } - int occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.trackOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + 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) { @@ -602,7 +777,7 @@ struct PhotonHBT { 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))) { + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photons1_coll, photons2_coll))) { if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { continue; } @@ -617,25 +792,55 @@ struct PhotonHBT { ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - float deta = v1.Eta() - v2.Eta(); - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - if (ggpaircuts.applydR && std::pow(deta / ggpaircuts.cfgMinDeltaEta, 2) + std::pow(dphi / ggpaircuts.cfgMinDeltaPhi, 2) < 1.f) { + + // 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()) { - emh1->AddTrackToEventPool(key_df_collision, EMTrack(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_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + EMPair g1tmp = EMPair(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_per_col.emplace_back(g1.globalIndex()); } - if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id2) == used_photonIds.end()) { - emh1->AddTrackToEventPool(key_df_collision, EMTrack(g2.globalIndex(), collision.globalIndex(), g2.globalIndex(), g2.pt(), g2.eta(), g2.phi(), 0)); - used_photonIds.emplace_back(pair_tmp_id2); + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g2.globalIndex()) == used_photonIds_per_col.end()) { + EMPair g2tmp = EMPair(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_per_col.emplace_back(g2.globalIndex()); } } // end of pairing loop } else if constexpr (pairtype == ggHBTPairType::kEEEE) { @@ -643,49 +848,50 @@ struct PhotonHBT { 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))) { + for (const 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)) { + if (!cut1.template IsSelectedTrack(pos1) || !cut1.template IsSelectedTrack(ele1)) { continue; } } else { // cut-based - if (!cut1.template IsSelectedTrack(pos1, collision) || !cut1.template IsSelectedTrack(ele1, collision)) { + if (!cut1.template IsSelectedTrack(pos1) || !cut1.template IsSelectedTrack(ele1)) { continue; } } - if (!cut1.IsSelectedPair(pos1, ele1, d_bz)) { + if (!cut1.IsSelectedPair(pos1, ele1, d_bz, 0.0)) { 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 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))) { + 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. // 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)) { + if (!cut2.template IsSelectedTrack(pos2) || !cut2.template IsSelectedTrack(ele2)) { continue; } } else { // cut-based - if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + if (!cut2.template IsSelectedTrack(pos2) || !cut2.template IsSelectedTrack(ele2)) { continue; } } - if (!cut2.IsSelectedPair(pos2, ele2, d_bz)) { + if (!cut2.IsSelectedPair(pos2, ele2, d_bz, 0.0)) { continue; } @@ -698,9 +904,9 @@ struct PhotonHBT { 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.); + // 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); @@ -708,35 +914,53 @@ struct PhotonHBT { 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 = v1_ee.Eta() - v2_ee.Eta(); - float dphi = v1_ee.Phi() - v2_ee.Phi(); - o2::math_utils::bringToPMPi(dphi); - if (ggpaircuts.applydR && std::pow(deta / ggpaircuts.cfgMinDeltaEta, 2) + std::pow(dphi / ggpaircuts.cfgMinDeltaPhi, 2) < 1.f) { + // 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)); - ndiphoton++; - - 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()) { - EMTrack g1pair = EMTrack(-1, collision.globalIndex(), -1, v1_ee.Pt(), v1_ee.Eta(), v1_ee.Phi(), v1_ee.M()); - g1pair.setPairDca3DinSigmaOTF(dca1_3d); + // 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::pair tuple_tmp_id1 = std::make_pair(pos1.globalIndex(), ele1.globalIndex()); + std::pair tuple_tmp_id2 = std::make_pair(pos2.globalIndex(), ele2.globalIndex()); + if (std::find(used_dileptonIds_per_col.begin(), used_dileptonIds_per_col.end(), tuple_tmp_id1) == used_dileptonIds_per_col.end()) { + EMPair g1pair = EMPair(v1_ee.Pt(), v1_ee.Eta(), v1_ee.Phi(), v1_ee.M()); + g1pair.setPositiveLegPtEtaPhiM(pos1.pt(), pos1.eta(), pos1.phi(), o2::constants::physics::MassElectron); + g1pair.setNegativeLegPtEtaPhiM(ele1.pt(), ele1.eta(), ele1.phi(), o2::constants::physics::MassElectron); emh1->AddTrackToEventPool(key_df_collision, g1pair); - used_dileptonIds.emplace_back(tuple_tmp_id1); + used_dileptonIds_per_col.emplace_back(tuple_tmp_id1); } - if (std::find(used_dileptonIds.begin(), used_dileptonIds.end(), tuple_tmp_id2) == used_dileptonIds.end()) { - EMTrack g2pair = EMTrack(-1, collision.globalIndex(), -1, v2_ee.Pt(), v2_ee.Eta(), v2_ee.Phi(), v2_ee.M()); - g2pair.setPairDca3DinSigmaOTF(dca2_3d); + if (std::find(used_dileptonIds_per_col.begin(), used_dileptonIds_per_col.end(), tuple_tmp_id2) == used_dileptonIds_per_col.end()) { + EMPair g2pair = EMPair(v2_ee.Pt(), v2_ee.Eta(), v2_ee.Phi(), v2_ee.M()); + g2pair.setPositiveLegPtEtaPhiM(pos2.pt(), pos2.eta(), pos2.phi(), o2::constants::physics::MassElectron); + g2pair.setNegativeLegPtEtaPhiM(ele2.pt(), ele2.eta(), ele2.phi(), o2::constants::physics::MassElectron); emh1->AddTrackToEventPool(key_df_collision, g2pair); - used_dileptonIds.emplace_back(tuple_tmp_id2); + used_dileptonIds_per_col.emplace_back(tuple_tmp_id2); } } } // end of g2 loop - } // end of g1 loop + } // end of g1 loop used_pairs_per_collision.clear(); used_pairs_per_collision.shrink_to_fit(); } else if constexpr (pairtype == ggHBTPairType::kPCMEE) { @@ -744,7 +968,7 @@ struct PhotonHBT { 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) { + for (const auto& g1 : photons1_per_collision) { if (!cut1.template IsSelected(g1)) { continue; } @@ -752,20 +976,20 @@ struct PhotonHBT { 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))) { + 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. // 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)) { + if (!cut2.template IsSelectedTrack(pos2) || !cut2.template IsSelectedTrack(ele2)) { continue; } } else { // cut-based - if (!cut2.template IsSelectedTrack(pos2, collision) || !cut2.template IsSelectedTrack(ele2, collision)) { + if (!cut2.template IsSelectedTrack(pos2) || !cut2.template IsSelectedTrack(ele2)) { continue; } } - if (!cut2.IsSelectedPair(pos2, ele2, d_bz)) { + if (!cut2.IsSelectedPair(pos2, ele2, d_bz, 0.0)) { continue; } @@ -779,38 +1003,64 @@ struct PhotonHBT { } // 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.); + // 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 = v1_gamma.Eta() - v2_ee.Eta(); - float dphi = v1_gamma.Phi() - v2_ee.Phi(); - o2::math_utils::bringToPMPi(dphi); - if (ggpaircuts.applydR && std::pow(deta / ggpaircuts.cfgMinDeltaEta, 2) + std::pow(dphi / ggpaircuts.cfgMinDeltaPhi, 2) < 1.f) { + + // 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()) { - emh1->AddTrackToEventPool(key_df_collision, EMTrack(g1.globalIndex(), collision.globalIndex(), g1.globalIndex(), g1.pt(), g1.eta(), g1.phi(), 0)); - used_photonIds.emplace_back(pair_tmp_id1); + std::pair tuple_tmp_id2 = std::make_pair(pos2.globalIndex(), ele2.globalIndex()); + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + EMPair g1tmp = EMPair(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_per_col.emplace_back(g1.globalIndex()); } - if (std::find(used_dileptonIds.begin(), used_dileptonIds.end(), tuple_tmp_id2) == used_dileptonIds.end()) { - EMTrack g2pair = EMTrack(-1, collision.globalIndex(), -1, v2_ee.Pt(), v2_ee.Eta(), v2_ee.Phi(), v2_ee.M()); - g2pair.setPairDca3DinSigmaOTF(dca2_3d); + if (std::find(used_dileptonIds_per_col.begin(), used_dileptonIds_per_col.end(), tuple_tmp_id2) == used_dileptonIds_per_col.end()) { + EMPair g2pair = EMPair(v2_ee.Pt(), v2_ee.Eta(), v2_ee.Phi(), v2_ee.M()); + 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); + used_dileptonIds_per_col.emplace_back(tuple_tmp_id2); } } // end of g2 loop - } // end of g1 loop + } // end of g1 loop } + used_photonIds_per_col.clear(); + used_photonIds_per_col.shrink_to_fit(); + used_dileptonIds_per_col.clear(); + used_dileptonIds_per_col.shrink_to_fit(); + // event mixing if (!cfgDoMix || !(ndiphoton > 0)) { continue; @@ -824,7 +1074,7 @@ struct PhotonHBT { auto collisionIds2_in_mixing_pool = emh2->GetCollisionIdsFromEventPool(key_bin); if constexpr (pairtype == ggHBTPairType::kPCMPCM) { - for (auto& mix_dfId_collisionId : collisionIds1_in_mixing_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; @@ -832,97 +1082,213 @@ struct PhotonHBT { 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) { + 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.); - float deta = v1.Eta() - v2.Eta(); - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - if (ggpaircuts.applydR && std::pow(deta / ggpaircuts.cfgMinDeltaEta, 2) + std::pow(dphi / ggpaircuts.cfgMinDeltaPhi, 2) < 1.f) { + + // 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) { + 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 (auto& g1 : selected_photons1_in_this_event) { - for (auto& g2 : photons1_from_event_pool) { + for (const auto& g1 : selected_photons1_in_this_event) { + for (const auto& g2 : photons1_from_event_pool) { + // auto pos1 = g1.getPositiveLeg(); + // auto ele1 = g1.getNegativeLeg(); + // auto pos2 = g2.getPositiveLeg(); + // auto ele2 = g2.getNegativeLeg(); + 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 = v1.Eta() - v2.Eta(); - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - if (ggpaircuts.applydR && std::pow(deta / ggpaircuts.cfgMinDeltaEta, 2) + std::pow(dphi / ggpaircuts.cfgMinDeltaPhi, 2) < 1.f) { + + // 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 + } // 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) { + 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 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 + for (const auto& g1 : selected_photons1_in_this_event) { // PCM + for (const 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()); - float deta = v1.Eta() - v2.Eta(); - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - if (ggpaircuts.applydR && std::pow(deta / ggpaircuts.cfgMinDeltaEta, 2) + std::pow(dphi / ggpaircuts.cfgMinDeltaPhi, 2) < 1.f) { + + // 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) { + 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 (auto& g1 : selected_photons2_in_this_event) { // dielectron - for (auto& g2 : photons1_from_event_pool) { // PCM + for (const auto& g1 : selected_photons2_in_this_event) { // dielectron + for (const 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()); - float deta = v1.Eta() - v2.Eta(); - float dphi = v1.Phi() - v2.Phi(); - o2::math_utils::bringToPMPi(dphi); - if (ggpaircuts.applydR && std::pow(deta / ggpaircuts.cfgMinDeltaEta, 2) + std::pow(dphi / ggpaircuts.cfgMinDeltaPhi, 2) < 1.f) { + + // 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); } } @@ -932,6 +1298,7 @@ struct PhotonHBT { 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 } @@ -943,9 +1310,9 @@ struct PhotonHBT { std::vector> passed_pairIds; passed_pairIds.reserve(positrons.size() * electrons.size()); - for (auto& collision : collisions) { + for (const auto& collision : collisions) { initCCDB(collision); - const float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -953,9 +1320,6 @@ struct PhotonHBT { 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; @@ -964,34 +1328,34 @@ struct PhotonHBT { 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))) { + for (const 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)) { + if (!cut.template IsSelectedTrack(pos) || !cut.template IsSelectedTrack(ele)) { continue; } } else { // cut-based - if (!cut.template IsSelectedTrack(pos, collision) || !cut.template IsSelectedTrack(ele, collision)) { + if (!cut.template IsSelectedTrack(pos) || !cut.template IsSelectedTrack(ele)) { continue; } } - if (!cut.IsSelectedPair(pos, ele, d_bz)) { + if (!cut.IsSelectedPair(pos, ele, d_bz, 0.0)) { continue; } passed_pairIds.emplace_back(std::make_pair(pos.globalIndex(), ele.globalIndex())); } // end of dielectron pairing loop - } // end of collision loop + } // end of collision loop - for (auto& pairId : passed_pairIds) { + 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 (auto& ambId1 : t1.ambiguousElectronsIds()) { - for (auto& ambId2 : t2.ambiguousElectronsIds()) { + 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()) { // 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; @@ -1007,24 +1371,27 @@ struct PhotonHBT { } 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) && (o2::aod::pidtpc::tpcNSigmaPi < dielectroncuts.cfg_min_TPCNsigmaPi || dielectroncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi) && ((0.96f < o2::aod::pidtofbeta::beta && o2::aod::pidtofbeta::beta < 1.04f) || o2::aod::pidtofbeta::beta < 0.f); + 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>; + using MyEMH = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMPair>; MyEMH* emh1 = nullptr; MyEMH* emh2 = nullptr; - std::vector> used_photonIds; // - std::vector> used_dileptonIds; // + std::vector used_photonIds_per_col; // + std::vector> used_dileptonIds_per_col; // + 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_numContrib = cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < cfgNumContribMax; + 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; @@ -1054,7 +1421,7 @@ struct PhotonHBT { PROCESS_SWITCH(PhotonHBT, processAnalysis, "pairing for analysis", false); using FilteredMyCollisionsWithSWT = soa::Filtered; - void processTriggerAnalysis(FilteredMyCollisionsWithSWT const& collisions, Types const&... args) + void processTriggerAnalysis(FilteredMyCollisionsWithSWT const& collisions, aod::EMSWTriggerInfos const& cefpinfos, aod::EMSWTriggerATCounters const& countersAT, aod::EMSWTriggerTOICounters const& countersTOI, Types const&... args) { if constexpr (pairtype == ggHBTPairType::kPCMPCM) { auto v0photons = std::get<0>(std::tie(args...)); @@ -1076,6 +1443,25 @@ struct PhotonHBT { runPairing(collisions, nullptr, nullptr, emprimaryelectrons, emprimaryelectrons, perCollision_electron, perCollision_electron, fDielectronCut, fDielectronCut); } ndf++; + + // for nomalization + int emswtId = o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value); + for (const auto& counter : countersAT) { + if (counter.isAnalyzed_bit(emswtId)) { + fRegistry.fill(HIST("NormTrigger/hTriggerCounter"), mRunNumber, 0); + } + } + for (const auto& counter : countersTOI) { + if (counter.isAnalyzedToI_bit(emswtId)) { + fRegistry.fill(HIST("NormTrigger/hTriggerCounter"), mRunNumber, 1); + } + } + + for (const auto& info : cefpinfos) { + fRegistry.fill(HIST("NormTrigger/hInspectedTVX"), info.runNumber(), info.nInspectedTVX()); + fRegistry.fill(HIST("NormTrigger/hScalers"), info.runNumber(), info.nScalers()[emswtId]); + fRegistry.fill(HIST("NormTrigger/hSelections"), info.runNumber(), info.nSelections()[emswtId]); + } } PROCESS_SWITCH(PhotonHBT, processTriggerAnalysis, "pairing analysis on trigger data", false); diff --git a/PWGEM/Dilepton/Core/SingleTrackQC.h b/PWGEM/Dilepton/Core/SingleTrackQC.h index b129804a99f..6efef833fb7 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQC.h @@ -17,32 +17,35 @@ #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 "Tools/ML/model.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/DataModel/dileptonTables.h" #include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -53,15 +56,15 @@ using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyCollisionsWithSWT = soa::Join; +using MyCollisionsWithSWT = soa::Join; using MyCollisionWithSWT = MyCollisionsWithSWT::iterator; -using MyElectrons = soa::Join; +using MyElectrons = soa::Join; using MyElectron = MyElectrons::iterator; using FilteredMyElectrons = soa::Filtered; using FilteredMyElectron = FilteredMyElectrons::iterator; -using MyMuons = soa::Join; +using MyMuons = soa::Join; using MyMuon = MyMuons::iterator; using FilteredMyMuons = soa::Filtered; using FilteredMyMuon = FilteredMyMuons::iterator; @@ -71,30 +74,54 @@ struct SingleTrackQC { // 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, NTPV:3"}; - Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1, "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 cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; Configurable cfgApplyWeightTTCA{"cfgApplyWeightTTCA", false, "flag to apply weighting by 1/N"}; 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 ConfDCA3DBins{"ConfDCA3DBins", {VARIABLE_WIDTH, 0.0, 10.0}, "DCA3d bins in sigma for output histograms"}; + ConfigurableAxis ConfDCAXYBins{"ConfDCAXYBins", {VARIABLE_WIDTH, -10.0, 10.0}, "DCAxy bins in sigma for output histograms"}; + ConfigurableAxis ConfDCAZBins{"ConfDCAZBins", {VARIABLE_WIDTH, -10.0, 10.0}, "DCAz bins in sigma for output histograms"}; EMEventCut fEMEventCut; struct : ConfigurableGroup { std::string prefix = "eventcut_group"; - Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + 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 cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF 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"}; + 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_hadronPID, 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; @@ -102,23 +129,37 @@ struct SingleTrackQC { std::string prefix = "dielectroncut_group"; Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for single track"}; - Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.8, "max eta 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_mirror_phi_track{"cfg_mirror_phi_track", false, "mirror the phi cut around Pi, min and max phi should be in 0-Pi"}; + Configurable cfg_reject_phi_track{"cfg_reject_phi_track", false, "reject the phi interval"}; 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_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_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_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3]"}; + 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_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 cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. + Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; + Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; + + 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_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"}; @@ -127,11 +168,19 @@ struct SingleTrackQC { 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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; - - // CCDB configuration for PID ML - Configurable BDTLocalPathGamma{"BDTLocalPathGamma", "pid_ml_xgboost.onnx", "Path to the local .onnx file"}; - Configurable BDTPathCCDB{"BDTPathCCDB", "Users/d/dsekihat/pwgem/pidml/", "Path on CCDB"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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)"}; @@ -140,40 +189,39 @@ struct SingleTrackQC { 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_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_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.1, "min pT for single track"}; + 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+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_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; + 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"}; + Configurable cfg_max_relDPt_wrt_matchedMCHMID{"cfg_max_relDPt_wrt_matchedMCHMID", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DEta_wrt_matchedMCHMID{"cfg_max_DEta_wrt_matchedMCHMID", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; } 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() - { - if (eid_bdt) { - delete eid_bdt; - } - } + ~SingleTrackQC() {} void addhistograms() { @@ -184,55 +232,74 @@ struct SingleTrackQC { 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)"}; + const AxisSpec axis_phiposition{36, 0.0, 2 * M_PI, "#varphi_{e}^{*} (rad.)"}; + const AxisSpec axis_dca3D{ConfDCA3DBins, "DCA_{e}^{3D} (#sigma)"}; + const AxisSpec axis_dcaXY{ConfDCAXYBins, "DCA_{e}^{XY} (#sigma)"}; + const AxisSpec axis_dcaZ{ConfDCAZBins, "DCA_{e}^{Z} (#sigma)"}; // 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}, {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/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/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/hs", "rec. single electron", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_dca3D, axis_dcaXY, axis_dcaZ}, true); + fRegistry.add("Track/positive/hPhiPosition", Form("phi position at r_{xy} = %3.2f m", dielectroncuts.cfgRefR.value), kTH1F, {axis_phiposition}, false); + fRegistry.add("Track/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{4000, -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.f, 1.f}}, false); + fRegistry.add("Track/positive/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{400, -20.0f, 20.0f}, {400, -20.0f, 20.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., 500}}, 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_Pt", "number of TPC clusters;p_{T,e} (GeV/c);TPC N_{cls}", kTH2F, {axis_pt, {161, -0.5, 160.5}}, false); + fRegistry.add("Track/positive/hNcrTPC_Pt", "number of TPC crossed rows;p_{T,e} (GeV/c);TPC N_{CR}", kTH2F, {axis_pt, {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_{in} (GeV/c);(p_{pv} - p_{in})/p_{in}", 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/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {32, 0, 16}}, false); - fRegistry.add("Track/positive/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTOFNsigmaMu", "TOF n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTOFNsigmaKa", "TOF n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/positive/hTOFNsigmaPr", "TOF n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, 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/hProbElBDT", "probability to be e from BDT;p_{in} (GeV/c);BDT score;", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, 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.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{25, -4.5, -2.0, "#eta_{#mu}"}; - const AxisSpec axis_phi{36, 0.0, 2 * M_PI, "#varphi_{#mu} (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_{#mu}^{XY} (#sigma)"}; + 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{ConfDCAXYBins, "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/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + 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/hsDelta", "diff. between GL and associated SA;p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl};#Delta#eta;#Delta#varphi (rad.);", kTHnSparseF, {axis_pt, {100, -0.5, +0.5}, {100, -0.5, +0.5}, {90, -M_PI / 4, M_PI / 4}}, false); + fRegistry.add("Track/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{1000, -5, 5}}, 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, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, 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}, {200, 0., 400}}, false); - fRegistry.add("Track/positive/hDCAyRes_Pt", "DCA_{y} resolution vs. pT;p_{T} (GeV/c);DCA_{y} resolution (#mum)", kTH2F, {{200, 0, 10}, {200, 0., 400}}, 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;p_{T} at PV (GeV/c);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 10}, {100, 0.0f, 1000}}, false); - fRegistry.add("Track/positive/hChi2", "chi2;chi2", kTH1F, {{100, 0.0f, 100}}, 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/ndf", kTH1F, {{100, 0.0f, 10}}, false); + fRegistry.add("Track/positive/hChi2MFT", "chi2MFT;chi2/ndf", kTH1F, {{100, 0.0f, 10}}, 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); @@ -241,38 +308,85 @@ struct SingleTrackQC { } int mRunNumber; + float d_bz; 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; + d_bz = 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); + LOGF(info, "Trigger analysis is enabled. Desired trigger name = %s", cfg_swt_name.value.data()); + fRegistry.add("NormTrigger/hInspectedTVX", "inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + fRegistry.add("NormTrigger/hScalers", "trigger counter before DS;run number;counter", kTProfile, {{80000, 520000.5, 600000.5}}, true); + fRegistry.add("NormTrigger/hSelections", "trigger counter after DS;run number;counter", kTProfile, {{80000, 520000.5, 600000.5}}, true); + auto hTriggerCounter = fRegistry.add("NormTrigger/hTriggerCounter", Form("trigger counter of %s;run number;", cfg_swt_name.value.data()), kTH2D, {{80000, 520000.5, 600000.5}, {2, -0.5, 1.5}}, false); + hTriggerCounter->GetYaxis()->SetBinLabel(1, "Analyzed Trigger"); + hTriggerCounter->GetYaxis()->SetBinLabel(2, "Analyzed TOI"); + } + 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 + template void initCCDB(TCollision const& collision) { if (mRunNumber == collision.runNumber()) { return; } + 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; + } - 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()); + 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 << " kG"; + } 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 << " kG"; } + + mRunNumber = collision.runNumber(); + fDielectronCut.SetTrackPhiPositionRange(dielectroncuts.cfg_min_phiposition_track, dielectroncuts.cfg_max_phiposition_track, dielectroncuts.cfgRefR, d_bz, dielectroncuts.cfg_mirror_phi_track); } void DefineEMEventCut() @@ -280,60 +394,95 @@ struct SingleTrackQC { fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); - fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireVertexTOFmatched(eventcuts.cfgRequireVertexTOFmatched); fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); + 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::ml::OnnxModel* eid_bdt = nullptr; + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); // for track - fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, 1e+10f); + 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, dielectroncuts.cfg_mirror_phi_track, dielectroncuts.cfg_reject_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.SetMeanClusterSizeITSob(0, 16); - fDielectronCut.SetMaxDcaXY(dielectroncuts.cfg_max_dcaxy); - fDielectronCut.SetMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); // 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.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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, dielectroncuts.cfg_max_pin_pirejTPC); - if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDielectronCut - eid_bdt = new o2::ml::OnnxModel(); - if (dielectroncuts.loadModelsFromCCDB) { - ccdbApi.init(ccdburl); - std::map metadata; - bool retrieveSuccessGamma = ccdbApi.retrieveBlob(dielectroncuts.BDTPathCCDB.value, ".", metadata, dielectroncuts.timestampCCDB.value, false, dielectroncuts.BDTLocalPathGamma.value); - if (retrieveSuccessGamma) { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); - } else { - LOG(fatal) << "Error encountered while fetching/loading the Gamma model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; - } - } else { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); + if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut + std::vector binsML{}; + binsML.reserve(dielectroncuts.binsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(dielectroncuts.binsMl.value[i]); } - - fDielectronCut.SetPIDModel(eid_bdt); + std::vector thresholdsML{}; + thresholdsML.reserve(dielectroncuts.cutsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + + // static constexpr int nClassesMl = 2; + // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + // const std::vector labelsClasses = {"Background", "Signal"}; + // 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] = 0.; + // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; + // } + // 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 } @@ -341,23 +490,22 @@ struct SingleTrackQC { { 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.SetPairDCAxyRange(dimuoncuts.cfg_min_pair_dcaxy, dimuoncuts.cfg_max_pair_dcaxy); // DCAxy in cm - // for track fDimuonCut.SetTrackType(dimuoncuts.cfg_track_type); - fDimuonCut.SetTrackPtRange(dimuoncuts.cfg_min_pt_track, 1e10f); + 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.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); 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); }); + fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons + fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); } template @@ -367,65 +515,91 @@ struct SingleTrackQC { if (cfgApplyWeightTTCA) { weight = map_weight[track.globalIndex()]; } - float dca_3d = dca3DinSigma(track); + + float dca3D = dca3DinSigma(track); + float dcaXY = dcaXYinSigma(track); + float dcaZ = dcaZinSigma(track); + float phiPosition = track.phi() + std::asin(-0.30282 * track.sign() * (d_bz * 0.1) * dielectroncuts.cfgRefR / (2.f * track.pt())); + o2::math_utils::bringTo02Pi(phiPosition); + if (track.sign() > 0) { - fRegistry.fill(HIST("Track/positive/hs"), track.pt(), track.eta(), track.phi(), dca_3d, weight); + fRegistry.fill(HIST("Track/positive/hs"), track.pt(), track.eta(), track.phi(), dca3D, dcaXY, dcaZ, weight); + fRegistry.fill(HIST("Track/positive/hPhiPosition"), phiPosition); 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() / 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/hDCAxyzSigma"), dcaXY, dcaZ); + 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/hNclsTPC_Pt"), track.pt(), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/positive/hNcrTPC_Pt"), track.pt(), 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()); + if (track.hasTPC()) { + fRegistry.fill(HIST("Track/positive/hDeltaPin"), track.tpcInnerParam(), (track.p() - track.tpcInnerParam()) / track.tpcInnerParam()); + } 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/hProbElBDT"), track.tpcInnerParam(), track.probElBDT()); 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/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/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/hs"), track.pt(), track.eta(), track.phi(), dca3D, dcaXY, dcaZ, weight); + fRegistry.fill(HIST("Track/negative/hPhiPosition"), phiPosition); 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() / 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/hDCAxyzSigma"), dcaXY, dcaZ); + 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/hNclsTPC_Pt"), track.pt(), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/negative/hNcrTPC_Pt"), track.pt(), 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()); + if (track.hasTPC()) { + fRegistry.fill(HIST("Track/negative/hDeltaPin"), track.tpcInnerParam(), (track.p() - track.tpcInnerParam()) / track.tpcInnerParam()); + } 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/hProbElBDT"), track.tpcInnerParam(), track.probElBDT()); 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/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/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()); } } @@ -437,33 +611,47 @@ struct SingleTrackQC { weight = map_weight[track.globalIndex()]; } float dca_xy = fwdDcaXYinSigma(track); + + float reldpt = (track.ptMatchedMCHMID() - track.pt()) / track.pt(); + float deta = track.etaMatchedMCHMID() - track.eta(); + float dphi = track.phiMatchedMCHMID() - track.phi(); + o2::math_utils::bringToPMPi(dphi); + 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/hsDelta"), track.pt(), reldpt, deta, dphi, 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.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); - fRegistry.fill(HIST("Track/positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXX()) * 1e+4); - fRegistry.fill(HIST("Track/positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); + 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.pt(), track.pDca()); - fRegistry.fill(HIST("Track/positive/hChi2"), track.chi2()); + fRegistry.fill(HIST("Track/positive/hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/positive/hChi2"), track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2() / (2.f * (track.nClusters() + track.nClustersMFT()) - 5.f) : track.chi2()); + fRegistry.fill(HIST("Track/positive/hChi2MFT"), track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2MFT() / (2.f * track.nClustersMFT() - 5.f) : 0); 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/hsDelta"), track.pt(), reldpt, deta, dphi, 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.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); - fRegistry.fill(HIST("Track/negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXX()) * 1e+4); - fRegistry.fill(HIST("Track/negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); + 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.pt(), track.pDca()); - fRegistry.fill(HIST("Track/negative/hChi2"), track.chi2()); + fRegistry.fill(HIST("Track/negative/hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/negative/hChi2"), track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2() / (2.f * (track.nClusters() + track.nClustersMFT()) - 5.f) : track.chi2()); + fRegistry.fill(HIST("Track/negative/hChi2MFT"), track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2MFT() / (2.f * track.nClustersMFT() - 5.f) : 0); fRegistry.fill(HIST("Track/negative/hChi2MatchMCHMID"), track.chi2MatchMCHMID()); fRegistry.fill(HIST("Track/negative/hChi2MatchMCHMFT"), track.chi2MatchMCHMFT()); fRegistry.fill(HIST("Track/negative/hMFTClusterMap"), track.mftClusterMap()); @@ -473,9 +661,9 @@ struct SingleTrackQC { template void runQC(TCollisions const& collisions, TTracks const& tracks, TPreslice const& perCollision, TCut const& cut) { - for (auto& collision : collisions) { - initCCDB(collision); - float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + for (const auto& collision : collisions) { + initCCDB(collision); + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -489,6 +677,9 @@ struct SingleTrackQC { 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 @@ -496,23 +687,27 @@ struct SingleTrackQC { auto tracks_per_coll = tracks.sliceBy(perCollision, collision.globalIndex()); if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - for (auto& track : tracks_per_coll) { + for (const auto& track : tracks_per_coll) { if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { - if (!cut.template IsSelectedTrack(track, collision)) { + if (!cut.template IsSelectedTrack(track)) { continue; } } else { // cut-based - if (!cut.template IsSelectedTrack(track)) { + 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 (auto& track : tracks_per_coll) { - if (!cut.template IsSelectedTrack(track)) { + 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 } @@ -525,9 +720,9 @@ struct SingleTrackQC { { std::vector passed_trackIds; passed_trackIds.reserve(tracks.size()); - for (auto& collision : collisions) { - initCCDB(collision); - float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + for (const auto& collision : collisions) { + initCCDB(collision); + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -540,25 +735,31 @@ struct SingleTrackQC { 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 (auto& track : tracks_per_coll) { + for (const auto& track : tracks_per_coll) { if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { - if (!cut.template IsSelectedTrack(track, collision)) { + if (!cut.template IsSelectedTrack(track)) { continue; } } else { // cut-based - if (!cut.template IsSelectedTrack(track)) { + 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 (auto& track : tracks_per_coll) { - if (!cut.template IsSelectedTrack(track)) { + 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()); @@ -567,11 +768,11 @@ struct SingleTrackQC { } // end of collision loop if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { - for (auto& trackId : passed_trackIds) { + for (const auto& trackId : passed_trackIds) { auto track = tracks.rawIteratorAt(trackId); auto ambIds = track.ambiguousElectronsIds(); float n = 1.f; // include myself. - for (auto& ambId : ambIds) { + for (const auto& ambId : ambIds) { if (std::find(passed_trackIds.begin(), passed_trackIds.end(), ambId) != passed_trackIds.end()) { n += 1.f; } @@ -579,11 +780,11 @@ struct SingleTrackQC { map_weight[trackId] = 1.f / n; } } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { - for (auto& trackId : passed_trackIds) { + for (const auto& trackId : passed_trackIds) { auto track = tracks.rawIteratorAt(trackId); auto ambIds = track.ambiguousMuonsIds(); float n = 1.f; // include myself. - for (auto& ambId : ambIds) { + for (const auto& ambId : ambIds) { if (std::find(passed_trackIds.begin(), passed_trackIds.end(), ambId) != passed_trackIds.end()) { n += 1.f; } @@ -599,15 +800,17 @@ struct SingleTrackQC { 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 && 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) && (o2::aod::pidtpc::tpcNSigmaPi < dielectroncuts.cfg_min_TPCNsigmaPi || dielectroncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi) && ((0.96f < o2::aod::pidtofbeta::beta && o2::aod::pidtofbeta::beta < 1.04f) || o2::aod::pidtofbeta::beta < 0.f); + 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 && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track; + 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_numContrib = cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < cfgNumContribMax; + 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) @@ -631,7 +834,7 @@ struct SingleTrackQC { PROCESS_SWITCH(SingleTrackQC, processQC, "run single track QC", true); using FilteredMyCollisionsWithSWT = soa::Filtered; - void processQC_TriggeredData(FilteredMyCollisionsWithSWT const& collisions, Types const&... args) + void processQC_TriggeredData(FilteredMyCollisionsWithSWT const& collisions, aod::EMSWTriggerInfos const& cefpinfos, aod::EMSWTriggerATCounters const& countersAT, aod::EMSWTriggerTOICounters const& countersTOI, Types const&... args) { if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { auto electrons = std::get<0>(std::tie(args...)); @@ -646,11 +849,124 @@ struct SingleTrackQC { } runQC(collisions, muons, perCollision_muon, fDimuonCut); } - map_weight.clear(); + + // for nomalization + int emswtId = o2::aod::pwgem::dilepton::swt::aliasLabels.at(cfg_swt_name.value); + for (const auto& counter : countersAT) { + if (counter.isAnalyzed_bit(emswtId)) { + fRegistry.fill(HIST("NormTrigger/hTriggerCounter"), mRunNumber, 0); + } + } + for (const auto& counter : countersTOI) { + if (counter.isAnalyzedToI_bit(emswtId)) { + fRegistry.fill(HIST("NormTrigger/hTriggerCounter"), mRunNumber, 1); + } + } + + for (const auto& info : cefpinfos) { + fRegistry.fill(HIST("NormTrigger/hInspectedTVX"), info.runNumber(), info.nInspectedTVX()); + fRegistry.fill(HIST("NormTrigger/hScalers"), info.runNumber(), info.nScalers()[emswtId]); + fRegistry.fill(HIST("NormTrigger/hSelections"), info.runNumber(), info.nSelections()[emswtId]); + } } 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); }; diff --git a/PWGEM/Dilepton/Core/SingleTrackQCMC.h b/PWGEM/Dilepton/Core/SingleTrackQCMC.h index d63139da476..5f707ebb839 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQCMC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQCMC.h @@ -17,31 +17,36 @@ #ifndef PWGEM_DILEPTON_CORE_SINGLETRACKQCMC_H_ #define PWGEM_DILEPTON_CORE_SINGLETRACKQCMC_H_ -#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 "Tools/ML/model.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/DataModel/dileptonTables.h" #include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" #include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -53,11 +58,14 @@ using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; -using MyMCElectrons = soa::Join; +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 MyMCMuons = soa::Join; using MyMCMuon = MyMCMuons::iterator; using FilteredMyMCMuons = soa::Filtered; @@ -67,59 +75,98 @@ using MySmearedElectron = MySmearedElectrons::iterator; using MySmearedMuons = soa::Join; using MySmearedMuon = MySmearedMuons::iterator; -// template template struct SingleTrackQCMC { // 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 cfgCentMin{"cfgCentMin", -1, "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 cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; Configurable cfgFillQA{"cfgFillQA", false, "flag to fill QA histograms"}; + Configurable cfgApplyWeightTTCA{"cfgApplyWeightTTCA", false, "flag to apply weighting by 1/N"}; + 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 ConfDCA3DBins{"ConfDCA3DBins", {VARIABLE_WIDTH, 0.0, 10.0}, "DCA3d bins in sigma for output histograms"}; + ConfigurableAxis ConfDCAXYBins{"ConfDCAXYBins", {VARIABLE_WIDTH, -10.0, 10.0}, "DCAxy bins in sigma for output histograms"}; + ConfigurableAxis ConfDCAZBins{"ConfDCAZBins", {VARIABLE_WIDTH, -10.0, 10.0}, "DCAz bins in sigma 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 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", true, "require No time frame border in event cut"}; - Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", true, "require no ITS readout frame border 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 cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF 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"}; + 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_hadronPID, 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_min_eta_track{"cfg_min_eta_track", -0.8, "max eta 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_mirror_phi_track{"cfg_mirror_phi_track", false, "mirror the phi cut around Pi, min and max Phi should be in 0-Pi"}; + Configurable cfg_reject_phi_track{"cfg_reject_phi_track", false, "reject the phi interval"}; 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_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_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_pid_scheme{"cfg_pid_scheme", static_cast(DielectronCut::PIDSchemes::kTPChadrejORTOFreq), "pid scheme [kTOFreq : 0, kTPChadrej : 1, kTPChadrejORTOFreq : 2, kTPConly : 3]"}; + 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_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 cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. + Configurable cfg_min_phiposition_track{"cfg_min_phiposition_track", 0.f, "min phi position for single track at certain radius"}; + Configurable cfg_max_phiposition_track{"cfg_max_phiposition_track", 6.3, "max phi position for single track at certain radius"}; + + 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_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"}; @@ -128,11 +175,19 @@ struct SingleTrackQCMC { 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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.f, "min. pin for pion rejection in TPC"}; + Configurable cfg_max_pin_pirejTPC{"cfg_max_pin_pirejTPC", 1e+10, "max. pin for pion rejection in TPC"}; Configurable enableTTCA{"enableTTCA", true, "Flag to enable or disable TTCA"}; - - // CCDB configuration for PID ML - Configurable BDTLocalPathGamma{"BDTLocalPathGamma", "pid_ml_xgboost.onnx", "Path to the local .onnx file"}; - Configurable BDTPathCCDB{"BDTPathCCDB", "Users/d/dsekihat/pwgem/pidml/", "Path on CCDB"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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)"}; @@ -143,55 +198,68 @@ struct SingleTrackQCMC { 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+10, "max chi2"}; - Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 1e+10, "max chi2 for MFT-MCH matching"}; + Configurable cfg_max_chi2{"cfg_max_chi2", 1e+6, "max chi2/ndf"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+6, "max chi2/ndf"}; + 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"}; + Configurable cfg_max_relDPt_wrt_matchedMCHMID{"cfg_max_relDPt_wrt_matchedMCHMID", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DEta_wrt_matchedMCHMID{"cfg_max_DEta_wrt_matchedMCHMID", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_DPhi_wrt_matchedMCHMID{"cfg_max_DPhi_wrt_matchedMCHMID", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to apply MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; + Configurable rejectWrongMatch{"rejectWrongMatch", false, "flag to reject wrong match between MFT and MCH-MID"}; // this is only for MC study, as we don't know correct match in data. } 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"}; - Configurable max_mcPt{"max_mcPt", 1e+10, "max. MC pT"}; - Configurable min_mcEta{"min_mcEta", -0.8, "max. MC eta"}; - Configurable max_mcEta{"max_mcEta", +0.8, "max. MC eta"}; + 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[9] = {"lf/", "Photon/", "PromptJPsi/", "NonPromptJPsi/", "PromptPsi2S/", "NonPromptPsi2S/", "c2l/", "b2l/", "b2c2l/"}; + static constexpr std::string_view lepton_source_types[10] = {"lf/", "lf_prompt/", "Photon/", "PromptJPsi/", "NonPromptJPsi/", "PromptPsi2S/", "NonPromptPsi2S/", "c2l/", "b2l/", "b2c2l/"}; - ~SingleTrackQCMC() - { - if (eid_bdt) { - delete eid_bdt; - } - } + ~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_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)"}; + const AxisSpec axis_phiposition{36, 0.0, 2 * M_PI, "#varphi_{e}^{*} (rad.)"}; const AxisSpec axis_charge_gen{3, -1.5, +1.5, "true charge"}; + const AxisSpec axis_dca3D{ConfDCA3DBins, "DCA_{e}^{3D} (#sigma)"}; + const AxisSpec axis_dcaXY{ConfDCAXYBins, "DCA_{e}^{XY} (#sigma)"}; + const AxisSpec axis_dcaZ{ConfDCAZBins, "DCA_{e}^{Z} (#sigma)"}; // 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/"); @@ -201,26 +269,35 @@ struct SingleTrackQCMC { 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); + fRegistry.add("Track/lf/positive/hs", "rec. single electron", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_dca3D, axis_dcaXY, axis_dcaZ, axis_charge_gen}, true); + if (fillGenValuesForRec) { + fRegistry.add("Track/lf/positive/hsGenRec", "rec. single electron", kTHnSparseD, {axis_pt, axis_eta, axis_phi, axis_dca3D, axis_dcaXY, axis_dcaZ, 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}, {200, 0., 400}}, 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}, {200, 0., 400}}, 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/hPhiPosition", Form("phi position at r_{xy} = %3.2f m", dielectroncuts.cfgRefR.value), kTH1F, {axis_phiposition}, false); + fRegistry.add("Track/lf/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{4000, -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.f, 1.f}}, false); + fRegistry.add("Track/lf/positive/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{400, -20.0f, 20.0f}, {400, -20.0f, 20.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_Pt", "number of TPC clusters;p_{T,e} (GeV/c);;TPC N_{cls}", kTH2F, {axis_pt, {161, -0.5, 160.5}}, false); + fRegistry.add("Track/lf/positive/hNcrTPC_Pt", "number of TPC crossed rows;p_{T,e} (GeV/c);;TPC N_{CR}", kTH2F, {axis_pt, {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_{in} (GeV/c);(p_{pv} - p_{in})/p_{in}", 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/"); @@ -229,32 +306,33 @@ struct SingleTrackQCMC { fRegistry.addClone("Track/lf/", "Track/c2l/"); fRegistry.addClone("Track/lf/", "Track/b2l/"); fRegistry.addClone("Track/lf/", "Track/b2c2l/"); + fRegistry.add("Track/Photon/positive/hProdVtx", "production vertex of e from #gamma;p_{T,e}^{rec} (GeV/c);r_{xy}^{gen} (cm);", kTH2F, {axis_pt, {100, 0, 100}}, false); + fRegistry.addClone("Track/Photon/positive/hProdVtx", "Track/Photon/negative/hProdVtx"); 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/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda)", kTH2F, {{1000, 0.f, 10.f}, {32, 0, 16}}, false); - fRegistry.add("Track/PID/positive/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTPCNsigmaMu", "TPC n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTPCNsigmaKa", "TPC n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTPCNsigmaPr", "TPC n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TPC}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTOFNsigmaMu", "TOF n sigma mu;p_{pv} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTOFNsigmaKa", "TOF n sigma ka;p_{pv} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, false); - fRegistry.add("Track/PID/positive/hTOFNsigmaPr", "TOF n sigma pr;p_{pv} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {80, -4, +4}}, 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/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.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{25, -4.5, -2.0, "#eta_{#mu}"}; + 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{{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_{#mu}^{XY} (#sigma)"}; + const AxisSpec axis_dca{ConfDCAXYBins, "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/"); @@ -265,17 +343,24 @@ struct SingleTrackQCMC { // 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 (fillGenValuesForRec) { + fRegistry.add("Track/lf/positive/hsGenRec", "gen. info of rec. single muon", 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/hEtaPhi_MatchMCHMID", "#eta vs. #varphi of matched MCHMID", kTH2F, {{180, 0, 2.f * M_PI}, {100, -6, -1}}, false); + fRegistry.add("Track/lf/positive/hdEtadPhi", "#Delta#eta vs. #Delta#varphi between MFT-MCH-MID and MCH-MID;#varphi_{sa} - #varphi_{gl} (rad.);#eta_{sa} - #eta_{gl}", kTH2F, {{90, -M_PI / 4, M_PI / 4}, {100, -0.5, +0.5}}, false); + fRegistry.add("Track/lf/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{1000, -5, 5}}, 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, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, 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}, {200, 0., 400}}, 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}, {200, 0., 400}}, 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;p_{T} at PV (GeV/c);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 10}, {100, 0.0f, 1000}}, false); - fRegistry.add("Track/lf/positive/hChi2", "chi2;chi2", kTH1F, {{100, 0.0f, 100}}, 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/ndf", kTH1F, {{100, 0.0f, 10}}, false); + fRegistry.add("Track/lf/positive/hChi2MFT", "chi2MFT;chi2/ndf", kTH1F, {{100, 0.0f, 10}}, 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); @@ -284,6 +369,7 @@ struct SingleTrackQCMC { 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/"); @@ -295,17 +381,25 @@ struct SingleTrackQCMC { } } + bool fillGenValuesForRec = false; 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."); } + if (doprocessQCMC) { + fillGenValuesForRec = true; + } + + 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(); @@ -317,6 +411,63 @@ struct SingleTrackQCMC { 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"); + } + } + + int mRunNumber; + float d_bz; + + template + void initCCDB(TCollision const& collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + 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 << " kG"; + } 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 << " kG"; + } + + mRunNumber = collision.runNumber(); + fDielectronCut.SetTrackPhiPositionRange(dielectroncuts.cfg_min_phiposition_track, dielectroncuts.cfg_max_phiposition_track, dielectroncuts.cfgRefR, d_bz, dielectroncuts.cfg_mirror_phi_track); } void DefineEMEventCut() @@ -324,60 +475,95 @@ struct SingleTrackQCMC { fEMEventCut = EMEventCut("fEMEventCut", "fEMEventCut"); fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); - fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireVertexTOFmatched(eventcuts.cfgRequireVertexTOFmatched); fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); + 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::ml::OnnxModel* eid_bdt = nullptr; + o2::analysis::MlResponseDielectronSingleTrack mlResponseSingleTrack; void DefineDielectronCut() { fDielectronCut = DielectronCut("fDielectronCut", "fDielectronCut"); // for track - fDielectronCut.SetTrackPtRange(dielectroncuts.cfg_min_pt_track, 1e+10f); + 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, dielectroncuts.cfg_mirror_phi_track, dielectroncuts.cfg_reject_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.SetMeanClusterSizeITSob(0, 16); - fDielectronCut.SetMaxDcaXY(dielectroncuts.cfg_max_dcaxy); - fDielectronCut.SetMaxDcaZ(dielectroncuts.cfg_max_dcaz); + fDielectronCut.SetMeanClusterSizeITS(dielectroncuts.cfg_min_its_cluster_size, dielectroncuts.cfg_max_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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); // 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.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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, dielectroncuts.cfg_max_pin_pirejTPC); if (dielectroncuts.cfg_pid_scheme == static_cast(DielectronCut::PIDSchemes::kPIDML)) { // please call this at the end of DefineDileptonCut - eid_bdt = new o2::ml::OnnxModel(); - if (dielectroncuts.loadModelsFromCCDB) { - ccdbApi.init(ccdburl); - std::map metadata; - bool retrieveSuccessGamma = ccdbApi.retrieveBlob(dielectroncuts.BDTPathCCDB.value, ".", metadata, dielectroncuts.timestampCCDB.value, false, dielectroncuts.BDTLocalPathGamma.value); - if (retrieveSuccessGamma) { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); - } else { - LOG(fatal) << "Error encountered while fetching/loading the Gamma model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; - } - } else { - eid_bdt->initModel(dielectroncuts.BDTLocalPathGamma.value, dielectroncuts.enableOptimizations.value); + std::vector binsML{}; + binsML.reserve(dielectroncuts.binsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(dielectroncuts.binsMl.value[i]); } - - fDielectronCut.SetPIDModel(eid_bdt); + std::vector thresholdsML{}; + thresholdsML.reserve(dielectroncuts.cutsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + + // static constexpr int nClassesMl = 2; + // const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + // const std::vector labelsClasses = {"Background", "Signal"}; + // 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] = 0.; + // cutsMlArr[i][1] = dielectroncuts.cutsMl.value[i]; + // } + // 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 } @@ -387,16 +573,20 @@ struct SingleTrackQCMC { // for track fDimuonCut.SetTrackType(dimuoncuts.cfg_track_type); - fDimuonCut.SetTrackPtRange(dimuoncuts.cfg_min_pt_track, 1e10f); + 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.SetNClustersMCHMID(dimuoncuts.cfg_min_ncluster_mch, 20); fDimuonCut.SetChi2(0.f, dimuoncuts.cfg_max_chi2); + fDimuonCut.SetChi2MFT(0.f, dimuoncuts.cfg_max_chi2mft); 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); }); + fDimuonCut.SetMaxdPtdEtadPhiwrtMCHMID(dimuoncuts.cfg_max_relDPt_wrt_matchedMCHMID, dimuoncuts.cfg_max_DEta_wrt_matchedMCHMID, dimuoncuts.cfg_max_DPhi_wrt_matchedMCHMID); // this is relevant for global muons + fDimuonCut.SetMFTHitMap(dimuoncuts.requireMFTHitMap, dimuoncuts.requiredMFTDisks); } template @@ -445,23 +635,47 @@ struct SingleTrackQCMC { void fillElectronInfo(TTrack const& track) { auto mctrack = track.template emmcparticle_as(); - float dca_3d = dca3DinSigma(track); + float dca3D = dca3DinSigma(track); + float dcaXY = dcaXYinSigma(track); + float dcaZ = dcaZinSigma(track); + float phiPosition = track.phi() + std::asin(-0.30282 * track.sign() * (d_bz * 0.1) * dielectroncuts.cfgRefR / (2.f * track.pt())); + o2::math_utils::bringTo02Pi(phiPosition); + + 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_3d, -mctrack.pdgCode() / pdg_lepton); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hs"), track.pt(), track.eta(), track.phi(), dca3D, dcaXY, dcaZ, -mctrack.pdgCode() / pdg_lepton, weight); + if constexpr (lepton_source_id == 2) { // for electron from photon conversion + fRegistry.fill(HIST("Track/Photon/positive/hProdVtx"), track.pt(), std::sqrt(std::pow(mctrack.vx(), 2) + std::pow(mctrack.vy(), 2)), weight); + } + + if (fillGenValuesForRec) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hsGenRec"), mctrack.pt(), mctrack.eta(), mctrack.phi(), dca3D, dcaXY, dcaZ, -mctrack.pdgCode() / pdg_lepton, weight); + } if (cfgFillQA) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPhiPosition"), phiPosition); 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() / sqrt(track.cYY()), track.dcaZ() / sqrt(track.cZZ())); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyRes_Pt"), track.pt(), 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(), sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyzSigma"), dcaXY, dcaZ); + 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/hNclsTPC_Pt"), track.pt(), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hNcrTPC_Pt"), track.pt(), 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()); + if (track.hasTPC()) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDeltaPin"), track.tpcInnerParam(), (track.p() - track.tpcInnerParam()) / track.tpcInnerParam()); + } 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()); @@ -470,32 +684,43 @@ struct SingleTrackQCMC { 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/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.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaMu"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaPi"), track.tpcInnerParam(), track.tofNSigmaPi()); - fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaKa"), track.tpcInnerParam(), track.tofNSigmaKa()); - fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaPr"), track.tpcInnerParam(), track.tofNSigmaPr()); + fRegistry.fill(HIST("Track/PID/positive/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); } } else { - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hs"), track.pt(), track.eta(), track.phi(), dca_3d, -mctrack.pdgCode() / pdg_lepton); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hs"), track.pt(), track.eta(), track.phi(), dca3D, dcaXY, dcaZ, -mctrack.pdgCode() / pdg_lepton, weight); + if constexpr (lepton_source_id == 2) { // for electron from photon conversion + fRegistry.fill(HIST("Track/Photon/negative/hProdVtx"), track.pt(), std::sqrt(std::pow(mctrack.vx(), 2) + std::pow(mctrack.vy(), 2)), weight); + } + if (fillGenValuesForRec) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hsGenRec"), mctrack.pt(), mctrack.eta(), mctrack.phi(), dca3D, dcaXY, dcaZ, -mctrack.pdgCode() / pdg_lepton, weight); + } if (cfgFillQA) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPhiPosition"), phiPosition); 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() / sqrt(track.cYY()), track.dcaZ() / sqrt(track.cZZ())); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyRes_Pt"), track.pt(), 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(), sqrt(track.cZZ()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyzSigma"), dcaXY, dcaZ); + 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/hNclsTPC_Pt"), track.pt(), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hNcrTPC_Pt"), track.pt(), 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()); + if (track.hasTPC()) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDeltaPin"), track.tpcInnerParam(), (track.p() - track.tpcInnerParam()) / track.tpcInnerParam()); + } 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()); @@ -504,16 +729,14 @@ struct SingleTrackQCMC { 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/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.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaMu"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaPi"), track.tpcInnerParam(), track.tofNSigmaPi()); - fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaKa"), track.tpcInnerParam(), track.tofNSigmaKa()); - fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaPr"), track.tpcInnerParam(), track.tofNSigmaPr()); + fRegistry.fill(HIST("Track/PID/negative/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); } } } @@ -523,19 +746,36 @@ struct SingleTrackQCMC { { auto mctrack = track.template emmcparticle_as(); float dca_xy = fwdDcaXYinSigma(track); + float deta = track.etaMatchedMCHMID() - track.eta(); + float dphi = track.phiMatchedMCHMID() - track.phi(); + o2::math_utils::bringToPMPi(dphi); + + 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); + 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 (fillGenValuesForRec) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hsGenRec"), mctrack.pt(), mctrack.eta(), mctrack.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/hdEtadPhi"), dphi, deta, 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.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXX()) * 1e+4); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); + 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.pt(), 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/hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2"), track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2() / (2.f * (track.nClusters() + track.nClustersMFT()) - 5.f) : track.chi2()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2MFT"), track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2MFT() / (2.f * track.nClustersMFT() - 5.f) : 0); 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()); @@ -544,18 +784,25 @@ struct SingleTrackQCMC { 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); + 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 (fillGenValuesForRec) { + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hsGenRec"), mctrack.pt(), mctrack.eta(), mctrack.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/hdEtadPhi"), dphi, deta, 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.cXX()), track.fwdDcaY() / std::sqrt(track.cYY())); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXX()) * 1e+4); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); + 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.pt(), 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/hPDCA"), track.rAtAbsorberEnd(), track.pDca()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2"), track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2() / (2.f * (track.nClusters() + track.nClustersMFT()) - 5.f) : track.chi2()); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2MFT"), track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) ? track.chi2MFT() / (2.f * track.nClustersMFT() - 5.f) : 0); 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()); @@ -566,10 +813,11 @@ struct SingleTrackQCMC { } } - template + template void runQCMC(TCollisions const& collisions, TTracks const& tracks, TPreslice const& perCollision, TCut const& cut, TMCCollisions const&, TMCParticles const& mcparticles) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { + initCCDB(collision); float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; @@ -579,75 +827,93 @@ struct SingleTrackQCMC { 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 mccollision = collision.template emmcevent_as(); - if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { - continue; - } - auto tracks_per_coll = tracks.sliceBy(perCollision, collision.globalIndex()); - for (auto& track : tracks_per_coll) { + for (const auto& track : tracks_per_coll) { auto mctrack = track.template emmcparticle_as(); - if (abs(mctrack.pdgCode()) != pdg_lepton) { + 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 (mctrack.emmceventId() != collision.emmceventId()) { + 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)) { + if (!cut.template IsSelectedTrack(track)) { continue; } } else { // cut-based - if (!cut.template IsSelectedTrack(track)) { + if (!cut.template IsSelectedTrack(track)) { continue; } } } else if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon) { - if (!cut.template IsSelectedTrack(track)) { + if (!cut.template IsSelectedTrack(track)) { + continue; + } + if (!o2::aod::pwgem::dilepton::utils::emtrackutil::isBestMatch(track, cut, tracks)) { + continue; + } + if (dimuoncuts.rejectWrongMatch && track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && track.emmcparticleId() != track.emmftmcparticleId()) { continue; } } - if (!mctrack.has_mothers()) { - continue; - } auto mcmother = mcparticles.iteratorAt(mctrack.mothersIds()[0]); - int pdg_mother = abs(mcmother.pdgCode()); + 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); + 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<3, TMCParticles>(track); + fillTrackInfo<4, TMCParticles>(track); } else { - fillTrackInfo<2, TMCParticles>(track); + fillTrackInfo<3, TMCParticles>(track); } } else if (pdg_mother == 100443) { if (IsFromBeauty(mcmother, mcparticles) > 0) { // b is found in full decay chain. - fillTrackInfo<5, TMCParticles>(track); + fillTrackInfo<6, TMCParticles>(track); } else { - fillTrackInfo<4, TMCParticles>(track); + 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<8, TMCParticles>(track); + } else if (isWeakDecayFromBeautyHadron(mctrack, mcparticles)) { // hb->l is found in full decay chain. + fillTrackInfo<8, TMCParticles>(track); + } else if (isWeakDecayFromCharmHadron(mctrack, mcparticles)) { // hc->l is found in full decay chain. + if (IsFromBeauty(mcmother, mcparticles) > 0) { + fillTrackInfo<9, TMCParticles>(track); // hb->hc->l is fond. } else { - fillTrackInfo<7, TMCParticles>(track); + fillTrackInfo<7, TMCParticles>(track); // prompt hc->l is found. } - } else if (IsFromCharm(mctrack, mcparticles) > 0) { // c is found in full decay chain. Not from b. - fillTrackInfo<6, TMCParticles>(track); } } else { - fillTrackInfo<1, TMCParticles>(track); + if (pdg_mother == 22) { // photon conversion + fillTrackInfo<2, TMCParticles>(track); + } } } // end of track loop @@ -656,32 +922,34 @@ struct SingleTrackQCMC { } // end of process template - void runGenInfo(TCollisions const& collisions, TMCLeptons const& leptonsMC, TMCCollisions const&, TMCParticles const& mcparticles) + void runGenInfo(TCollisions const& collisions, TMCLeptons const& leptonsMC, 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 (const auto& mccollision : mccollisions) { + if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + fRegistry.fill(HIST("MCEvent/before/hZvtx"), mccollision.posZ()); - for (auto& collision : collisions) { - float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + 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; } - - auto mccollision = collision.template emmcevent_as(); - // LOGF(info, "mccollision.getGeneratorId() = %d", mccollision.getGeneratorId()); - // LOGF(info, "mccollision.getSubGeneratorId() = %d", mccollision.getSubGeneratorId()); - // LOGF(info, "mccollision.getSourceId() = %d", mccollision.getSourceId()); - if (cfgEventGeneratorType >= 0 && mccollision.getSubGeneratorId() != cfgEventGeneratorType) { + 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 (auto& lepton : leptonsMC_per_coll) { + for (const auto& lepton : leptonsMC_per_coll) { if (!(lepton.isPhysicalPrimary() || lepton.producedByGenerator())) { continue; } @@ -692,7 +960,7 @@ struct SingleTrackQCMC { continue; } auto mcmother = mcparticles.iteratorAt(lepton.mothersIds()[0]); - int pdg_mother = abs(mcmother.pdgCode()); + int pdg_mother = std::abs(mcmother.pdgCode()); float pt = 0.f, eta = 0.f, phi = 0.f; if constexpr (isSmeared) { @@ -723,6 +991,9 @@ struct SingleTrackQCMC { 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); @@ -735,68 +1006,274 @@ struct SingleTrackQCMC { } 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 if (isWeakDecayFromBeautyHadron(lepton, mcparticles)) { // hb->l is found + fRegistry.fill(HIST("Generated/b2l/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + } else if (isWeakDecayFromCharmHadron(lepton, mcparticles)) { // hc->l is found in full decay chain. + if (IsFromBeauty(mcmother, mcparticles) > 0) { + fRegistry.fill(HIST("Generated/b2c2l/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); // hb->hc->l is found in full decay chain. } else { - fRegistry.fill(HIST("Generated/b2l/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); + fRegistry.fill(HIST("Generated/c2l/hs"), pt, eta, phi, -lepton.pdgCode() / pdg_lepton); // prompt hc->l is found in full decay chain. } - } 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) { + initCCDB(collision); + 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)) { + 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_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) && (o2::aod::pidtpc::tpcNSigmaPi < dielectroncuts.cfg_min_TPCNsigmaPi || dielectroncuts.cfg_max_TPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi) && ((0.96f < o2::aod::pidtofbeta::beta && o2::aod::pidtofbeta::beta < 1.04f) || o2::aod::pidtofbeta::beta < 0.f); + Filter trackFilter_electron = 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 && dimuoncuts.cfg_min_eta_track < o2::aod::fwdtrack::eta && o2::aod::fwdtrack::eta < dimuoncuts.cfg_max_eta_track; + 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_numContrib = cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < cfgNumContribMax; + 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; - // void processQCMC(FilteredMyCollisions const& collisions, aod::EMMCEvents const& mccollisions, aod::EMMCParticles const& mcparticles, Types const&... args) - void processQCMC(FilteredMyCollisions const& collisions, aod::EMMCEvents const& mccollisions, aod::EMMCParticles const& mcparticles, TLeptons const& tracks) + // 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) { - runQCMC(collisions, tracks, perCollision_electron, fDielectronCut, mccollisions, mcparticles); + 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) { - runQCMC(collisions, tracks, perCollision_muon, fDimuonCut, mccollisions, mcparticles); + 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, aod::EMMCEvents const& mccollisions, Types const&... args) - void processQCMC_Smeared(FilteredMyCollisions const& collisions, aod::EMMCEvents const& mccollisions, TLeptons const& tracks, TSmearedMCParticles const& mcparticles_smeared) + 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) { - runQCMC(collisions, tracks, perCollision_electron, fDielectronCut, mccollisions, mcparticles_smeared); + 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) { - runQCMC(collisions, tracks, perCollision_muon, fDimuonCut, mccollisions, mcparticles_smeared); + 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 processDummy(MyCollisions const&) {} + 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); }; diff --git a/PWGEM/Dilepton/DataModel/dileptonTables.h b/PWGEM/Dilepton/DataModel/dileptonTables.h index 020b4968810..1be31d372bf 100644 --- a/PWGEM/Dilepton/DataModel/dileptonTables.h +++ b/PWGEM/Dilepton/DataModel/dileptonTables.h @@ -9,18 +9,28 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include -#include +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/RecoDecay.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include #ifndef PWGEM_DILEPTON_DATAMODEL_DILEPTONTABLES_H_ #define PWGEM_DILEPTON_DATAMODEL_DILEPTONTABLES_H_ @@ -32,35 +42,44 @@ namespace pwgem::dilepton::swt { enum class swtAliases : int { // software trigger aliases for EM kHighTrackMult = 0, - kHighFt0Mult, - // kSingleE, - // kLMeeIMR, - // kLMeeHMR, - // kDiElectron, - // kSingleMuLow, - // kSingleMuHigh, - // kDiMuon, + kHighFt0cFv0Mult, + 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)}, + {"fHighFt0cFv0Mult", static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kHighFt0cFv0Mult)}, + {"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 +DECLARE_SOA_TABLE(EMBCs, "AOD", "EMBC", //! bc information for normalization + o2::soa::Index<>, evsel::Selection, evsel::Rct); +using EMBC = EMBCs::iterator; + namespace emevent { DECLARE_SOA_COLUMN(CollisionId, collisionId, int); -DECLARE_SOA_BITMAP_COLUMN(SWTAlias, swtalias, 16); //! Bitmask of fired trigger aliases (see above for definitions) -DECLARE_SOA_COLUMN(NInspectedTVX, nInspectedTVX, uint64_t); +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); //! the number of inspected TVX bcs per run +DECLARE_SOA_COLUMN(NScalars, nScalers, std::vector); //! the number of triggered bcs before down scaling per run +DECLARE_SOA_COLUMN(NSelections, nSelections, std::vector); //! the number of triggered bcs after down scaling per run +DECLARE_SOA_BITMAP_COLUMN(IsAnalyzed, isAnalyzed, 16); +DECLARE_SOA_BITMAP_COLUMN(IsAnalyzedToI, isAnalyzedToI, 16); DECLARE_SOA_COLUMN(NeeULS, neeuls, int); DECLARE_SOA_COLUMN(NeeLSpp, neelspp, int); DECLARE_SOA_COLUMN(NeeLSmm, neelsmm, int); @@ -71,6 +90,8 @@ DECLARE_SOA_COLUMN(Q2xFT0A, q2xft0a, float); //! 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 @@ -83,6 +104,8 @@ DECLARE_SOA_COLUMN(Q3xFT0A, q3xft0a, float); //! 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 @@ -95,6 +118,8 @@ DECLARE_SOA_COLUMN(Q4xFT0A, q4xft0a, float); //! 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(Q4xFV0A, q4xfv0a, float); //! Qx for 4th harmonics in FV0A (i.e. positive eta) +DECLARE_SOA_COLUMN(Q4yFV0A, q4yfv0a, float); //! Qy for 4th harmonics in FV0A (i.e. positive 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 @@ -104,34 +129,69 @@ DECLARE_SOA_COLUMN(Q4yBTot, q4ybtot, float); //! 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(PosX, posX, float); //! only for treeCreatetorML.cxx +DECLARE_SOA_COLUMN(PosY, posY, float); //! only for treeCreatetorML.cxx +DECLARE_SOA_COLUMN(PosZint16, posZint16, int16_t); //! this is only to reduce data size +DECLARE_SOA_COLUMN(CentFT0Cuint16, centFT0Cuint16, uint16_t); //! this is only to reduce data size +DECLARE_SOA_DYNAMIC_COLUMN(PosZ, posZ, [](int16_t posZint16) -> float { return (posZint16 < 0 ? std::nextafter(posZint16 * 0.01f, -std::numeric_limits::infinity()) : std::nextafter(posZint16 * 0.01f, std::numeric_limits::infinity())); }); //! poZ is multiplied by 100 in createEMEventDileton.cxx +DECLARE_SOA_DYNAMIC_COLUMN(CentFT0C, centFT0C, [](uint16_t centuint16) -> float { return std::nextafter(centuint16 * 0.002f, std::numeric_limits::infinity()); }); //! centrality is multiplied by 500 in createEMEventDilepton.cxx 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(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; }); 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(EP3FV0A, ep3fv0a, [](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(EP4FV0A, ep4fv0a, [](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(EMEvents, "AOD", "EMEVENT", //! 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, emevent::Sel8); +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); + +DECLARE_SOA_TABLE_VERSIONED(EMEvents_003, "AOD", "EMEVENT", 3, //! Main event information table + o2::soa::Index<>, emevent::CollisionId, bc::RunNumber, bc::GlobalBC, evsel::Alias, evsel::Selection, evsel::Rct, timestamp::Timestamp, + collision::PosZ, + collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, emevent::Sel8); + +DECLARE_SOA_TABLE_VERSIONED(EMEvents_004, "AOD", "EMEVENT", 4, //! Main event information table + o2::soa::Index<>, emevent::CollisionId, bc::RunNumber, bc::GlobalBC, evsel::Selection, evsel::Rct, timestamp::Timestamp, + collision::PosZ, + collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, emevent::Sel8); + +using EMEvents = EMEvents_004; using EMEvent = EMEvents::iterator; +DECLARE_SOA_TABLE_VERSIONED(EMEventsAlias_000, "AOD", "EMEVENTALIAS", 0, evsel::Alias) //! joinable to EMEvents +using EMEventsAlias = EMEventsAlias_000; +using EMEventAlias = EMEventsAlias::iterator; + +DECLARE_SOA_TABLE(EMEventsXY, "AOD", "EMEVENTXY", emevent::PosX, emevent::PosY); // joinable to EMEvents, only for treeCreatetorML.cxx +using EMEventXY = EMEventsXY::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; @@ -140,72 +200,130 @@ DECLARE_SOA_TABLE(EMEventsBz, "AOD", "EMEVENTBZ", emevent::Bz); // joinable to E using EMEventBz = EMEventsBz::iterator; DECLARE_SOA_TABLE(EMEventsMult, "AOD", "EMEVENTMULT", //! event multiplicity table, joinable to EMEvents - mult::MultFT0A, mult::MultFT0C, - mult::MultTPC, mult::MultNTracksPV, mult::MultNTracksPVeta1, mult::MultNTracksPVetaHalf, + 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, cent::CentNTPV); + 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); +DECLARE_SOA_TABLE_VERSIONED(EMEventsQvec_000, "AOD", "EMEVENTQVEC", 0, //! 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, + + // 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); + +DECLARE_SOA_TABLE_VERSIONED(EMEventsQvec_001, "AOD", "EMEVENTQVEC", 1, //! Main event information table + 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::Q2xBTot, emevent::Q2yBTot, + emevent::Q3xFT0M, emevent::Q3yFT0M, emevent::Q3xFT0A, emevent::Q3yFT0A, emevent::Q3xFT0C, emevent::Q3yFT0C, + emevent::Q3xFV0A, emevent::Q3yFV0A, + emevent::Q3xBPos, emevent::Q3yBPos, emevent::Q3xBNeg, emevent::Q3yBNeg, emevent::Q3xBTot, emevent::Q3yBTot, + + // Dynamic columns + emevent::EP2FT0M, + emevent::EP2FT0A, + emevent::EP2FT0C, + emevent::EP2FV0A, + emevent::EP2BPos, + emevent::EP2BNeg, + emevent::EP2BTot, + emevent::EP3FT0M, + emevent::EP3FT0A, + emevent::EP3FT0C, + emevent::EP3FV0A, + emevent::EP3BPos, + emevent::EP3BNeg, + emevent::EP3BTot); + +using EMEventsQvec = EMEventsQvec_001; using EMEventQvec = EMEventsQvec::iterator; -DECLARE_SOA_TABLE(EMSWTriggerInfos, "AOD", "EMSWTRIGGERINFO", //! joinable to EMEvents - emevent::SWTAlias, emevent::NInspectedTVX); +DECLARE_SOA_TABLE(EMSWTriggerBits, "AOD", "EMSWTBIT", emevent::SWTAlias, o2::soa::Marker<1>); //! joinable to EMEvents +using EMSWTriggerBit = EMSWTriggerBits::iterator; + +DECLARE_SOA_TABLE(EMSWTriggerInfos, "AOD", "EMSWTINFO", bc::RunNumber, emevent::NInspectedTVX, emevent::NScalars, emevent::NSelections, o2::soa::Marker<1>); //! independent table. Don't join anything. using EMSWTriggerInfo = EMSWTriggerInfos::iterator; +DECLARE_SOA_TABLE(EMSWTriggerATCounters, "AOD", "EMSWTAT", emevent::IsAnalyzed, o2::soa::Marker<1>); //! independent table. Don't join anything. +using EMSWTriggerATCounter = EMSWTriggerATCounters::iterator; + +DECLARE_SOA_TABLE(EMSWTriggerTOICounters, "AOD", "EMSWTTOI", emevent::IsAnalyzedToI, o2::soa::Marker<1>); //! independent table. Don't join anything. +using EMSWTriggerTOICounter = EMSWTriggerTOICounters::iterator; + +DECLARE_SOA_TABLE(EMSWTriggerBitsTMP, "AOD", "EMSWTBITTMP", emevent::SWTAliasTmp, o2::soa::Marker<2>); //! joinable to aod::Collisions +using EMSWTriggerBitTMP = EMSWTriggerBitsTMP::iterator; + +DECLARE_SOA_TABLE(EMSWTriggerInfosTMP, "AOD", "EMSWTINFOTMP", bc::RunNumber, emevent::NInspectedTVX, emevent::NScalars, emevent::NSelections, o2::soa::Marker<2>); +using EMSWTriggerInfoTMP = EMSWTriggerInfosTMP::iterator; + +DECLARE_SOA_TABLE(EMSWTriggerATCountersTMP, "AOD", "EMSWTATTMP", emevent::IsAnalyzed, o2::soa::Marker<2>); //! independent table. Don't join anything. +using EMSWTriggerATCounterTMP = EMSWTriggerATCountersTMP::iterator; + +DECLARE_SOA_TABLE(EMSWTriggerTOICountersTMP, "AOD", "EMSWTTOITMP", emevent::IsAnalyzedToI, o2::soa::Marker<2>); //! independent table. Don't join anything. +using EMSWTriggerTOICounterTMP = EMSWTriggerTOICountersTMP::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 +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_VERSIONED(EMEventNormInfos_000, "AOD", "EMEVENTNORMINFO", 0, //! event information for normalization + o2::soa::Index<>, evsel::Alias, evsel::Selection, evsel::Rct, emevent::PosZint16, cent::CentFT0C, + emevent::Sel8); + +DECLARE_SOA_TABLE_VERSIONED(EMEventNormInfos_001, "AOD", "EMEVENTNORMINFO", 1, //! event information for normalization + o2::soa::Index<>, evsel::Selection, evsel::Rct, emevent::PosZint16, emevent::CentFT0Cuint16, + emevent::Sel8, emevent::PosZ, emevent::CentFT0C, o2::soa::Marker<1>); +using EMEventNormInfos = EMEventNormInfos_001; +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::T, mccollision::ImpactParameter, + 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 @@ -235,8 +353,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Particle rapidity }); } // 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) +// This table contains all MC truth tracks +DECLARE_SOA_TABLE_FULL(EMMCParticles_000, "EMMCParticles", "AOD", "EMMCPARTICLE", //! MC track information (on disk) o2::soa::Index<>, emmcparticle::EMMCEventId, mcparticle::PdgCode, mcparticle::Flags, emmcparticle::MothersIds, emmcparticle::DaughtersIds, @@ -247,15 +365,60 @@ DECLARE_SOA_TABLE_FULL(EMMCParticles, "EMMCParticles", "AOD", "EMMCPARTICLE", // emmcparticle::Pt, emmcparticle::Eta, emmcparticle::Phi, - emmcparticle::P, emmcparticle::Y, mcparticle::ProducedByGenerator, mcparticle::FromBackgroundEvent, mcparticle::IsPhysicalPrimary); +DECLARE_SOA_TABLE_VERSIONED(EMMCParticles_001, "AOD", "EMMCPARTICLE", 1, //! MC track information (on disk) + o2::soa::Index<>, emmcparticle::EMMCEventId, + mcparticle::PdgCode, mcparticle::Flags, mcparticle::StatusCode, + 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, + mcparticle::GetGenStatusCode, + mcparticle::GetHepMCStatusCode, + mcparticle::GetProcess); + +using EMMCParticles = EMMCParticles_001; 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); @@ -307,6 +470,18 @@ DECLARE_SOA_TABLE(EMPrimaryMuonMCLabels, "AOD", "EMPRMMUMCLABEL", //! emprimarymuonmclabel::EMMCParticleId, emprimarymuonmclabel::McMask); using EMPrimaryMuonMCLabel = EMPrimaryMuonMCLabels::iterator; +namespace emmftmclabel +{ +// DECLARE_SOA_INDEX_COLUMN_FULL(EMMCParticle, emmcparticle); +DECLARE_SOA_INDEX_COLUMN_FULL(EMMFTMCParticle, emmftmcparticle, int, EMMCParticles, "_MFT"); +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); +} // namespace emmftmclabel + +// NOTE: MC labels. This table has one entry for each reconstructed track (joinable with EMPrimaryMuons table) +DECLARE_SOA_TABLE(EMMFTMCLabels, "AOD", "EMMFTMCLABEL", //! + emmftmclabel::EMMFTMCParticleId, emmftmclabel::McMask); +using EMMFTMCLabel = EMMFTMCLabels::iterator; + namespace emprimaryelectron { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! @@ -314,13 +489,25 @@ 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(IsAmbiguous, isAmbiguous, bool); //! is ambiguous DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! DECLARE_SOA_COLUMN(PrefilterBit, pfb, uint8_t); //! +DECLARE_SOA_COLUMN(PrefilterBitDerived, pfbderived, uint16_t); //! +DECLARE_SOA_COLUMN(ProbElBDT, probElBDT, float); //! + +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 o2::constants::math::PIHalf - std::atan(tgl); }); +DECLARE_SOA_DYNAMIC_COLUMN(Tgl, tgl, [](float eta) -> float { return std::tan(o2::constants::math::PIHalf - 2 * std::atan(std::exp(-eta))); }); 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++) { @@ -367,37 +554,168 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32 } }); } // namespace emprimaryelectron -DECLARE_SOA_TABLE(EMPrimaryElectrons, "AOD", "EMPRIMARYEL", //! - 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::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::X, track::Alpha, track::Y, track::Z, track::Snp, track::Tgl, emprimaryelectron::IsAssociatedToMPC, - // 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, - emprimaryelectron::Signed1Pt, - emprimaryelectron::P, - emprimaryelectron::Px, - emprimaryelectron::Py, - emprimaryelectron::Pz, - emprimaryelectron::MeanClusterSizeITS, - emprimaryelectron::MeanClusterSizeITSib, - emprimaryelectron::MeanClusterSizeITSob); +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); + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectrons_003, "AOD", "EMPRIMARYEL", 3, //! + 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, + mcpidtpc::DeDxTunedMc, + + // 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_004, "AOD", "EMPRIMARYEL", 4, //! + o2::soa::Index<>, emprimaryelectron::CollisionId, + emprimaryelectron::TrackId, emprimaryelectron::Sign, + track::Pt, track::Eta, track::Phi, + track::DcaXY, track::DcaZ, aod::track::CYY, aod::track::CZY, aod::track::CZZ, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, + track::TPCChi2NCl, track::TPCInnerParam, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, /*pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr,*/ + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, /*track::Tgl,*/ + emprimaryelectron::IsAssociatedToMPC, emprimaryelectron::IsAmbiguous, emprimaryelectron::ProbElBDT, + mcpidtpc::DeDxTunedMc, + + // 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::Tgl, + emprimaryelectron::MeanClusterSizeITS, + emprimaryelectron::MeanClusterSizeITSib, + emprimaryelectron::MeanClusterSizeITSob); + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectrons_005, "AOD", "EMPRIMARYEL", 5, //! + o2::soa::Index<>, emprimaryelectron::CollisionId, + emprimaryelectron::TrackId, emprimaryelectron::Sign, + track::Pt, track::Eta, track::Phi, + track::DcaXY, track::DcaZ, aod::track::CYY, aod::track::CZY, aod::track::CZZ, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusPID, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, + track::TPCChi2NCl, track::TPCInnerParam, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, /*pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr,*/ + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, /*track::Tgl,*/ + emprimaryelectron::IsAssociatedToMPC, emprimaryelectron::IsAmbiguous, emprimaryelectron::ProbElBDT, + mcpidtpc::DeDxTunedMc, + + // dynamic column + track::TPCNClsFound, + track::TPCNClsPID, + 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::Tgl, + emprimaryelectron::MeanClusterSizeITS, + emprimaryelectron::MeanClusterSizeITSib, + emprimaryelectron::MeanClusterSizeITSob); + +using EMPrimaryElectrons = EMPrimaryElectrons_005; // iterators using EMPrimaryElectron = EMPrimaryElectrons::iterator; -DECLARE_SOA_TABLE(EMPrimaryElectronsCov, "AOD", "EMPRIMARYELCOV", //! +DECLARE_SOA_TABLE(EMPrimaryElectronsCov_000, "AOD", "EMPRIMARYELCOV", //! aod::track::CYY, aod::track::CZY, aod::track::CZZ, @@ -413,9 +731,35 @@ DECLARE_SOA_TABLE(EMPrimaryElectronsCov, "AOD", "EMPRIMARYELCOV", //! aod::track::C1PtSnp, aod::track::C1PtTgl, aod::track::C1Pt21Pt2, o2::soa::Marker<1>); + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectronsCov_001, "AOD", "EMPRIMARYELCOV", 1, //! + aod::track::X, + aod::track::Alpha, + aod::track::Y, + aod::track::Z, + aod::track::Snp, + 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); // CYY, CZY, CZZ, Tgl are in the main electron table. + +using EMPrimaryElectronsCov = EMPrimaryElectronsCov_001; // iterators using EMPrimaryElectronCov = EMPrimaryElectronsCov::iterator; +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectronsDeDxMC_000, "AOD", "EMPRMELDEDXMC", 0, mcpidtpc::DeDxTunedMc, o2::soa::Marker<1>); +using EMPrimaryElectronsDeDxMC = EMPrimaryElectronsDeDxMC_000; +// iterators +using EMPrimaryElectronDeDxMC = EMPrimaryElectronsDeDxMC::iterator; + DECLARE_SOA_TABLE(EMPrimaryElectronEMEventIds, "AOD", "PRMELMEVENTID", emprimaryelectron::EMEventId); // To be joined with EMPrimaryElectrons table at analysis level. // iterators using EMPrimaryElectronEMEventId = EMPrimaryElectronEMEventIds::iterator; @@ -428,22 +772,39 @@ DECLARE_SOA_TABLE(EMAmbiguousElectronSelfIds, "AOD", "EMAMBELSELFID", emprimarye // 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_SELF_INDEX_COLUMN_FULL(MCHTrack, matchMCHTrack, int, "EMPRIMARYMUs_MatchMCHTrack"); //! Index of matched MCH track for GlobalMuonTracks and GlobalForwardTracks +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(PtMatchedMCHMID, ptMatchedMCHMID, float); //! pt of MCH-MID track in MFT-MCH-MID track at PV +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(EtaMatchedMCHMIDatMP, etaMatchedMCHMIDatMP, float); //! eta of MCH-MID track in MFT-MCH-MID track at matching plane +DECLARE_SOA_COLUMN(PhiMatchedMCHMIDatMP, phiMatchedMCHMIDatMP, float); //! phi of MCH-MID track in MFT-MCH-MID track at matching plane +DECLARE_SOA_COLUMN(EtaMatchedMFTatMP, etaMatchedMFTatMP, float); //! eta of MFT track in MFT-MCH-MID track at matching plane +DECLARE_SOA_COLUMN(PhiMatchedMFTatMP, phiMatchedMFTatMP, float); //! phi of MFT track in MFT-MCH-MID track at matching plane + 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(Chi2MFTsa, chi2MFTsa, float); //! chi2 of MFT standalone track +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(DcaXY, dcaXY, [](float dcaX, float dcaY) -> float { return std::sqrt(dcaX * dcaX + dcaY * dcaY); }); DECLARE_SOA_DYNAMIC_COLUMN(NClustersMFT, nClustersMFT, //! Number of MFT clusters [](uint64_t mftClusterSizesAndTrackFlags) -> uint8_t { uint8_t nClusters = 0; @@ -465,19 +826,18 @@ DECLARE_SOA_DYNAMIC_COLUMN(MFTClusterMap, mftClusterMap, //! MFT cluster map, on return clmap; }); } // namespace emprimarymuon -DECLARE_SOA_TABLE(EMPrimaryMuons, "AOD", "EMPRIMARYMU", //! +DECLARE_SOA_TABLE(EMPrimaryMuons_000, "AOD", "EMPRIMARYMU", //! o2::soa::Index<>, emprimarymuon::CollisionId, - emprimarymuon::FwdTrackId, fwdtrack::TrackType, + emprimarymuon::FwdTrackId, emprimarymuon::MFTTrackId, emprimarymuon::MCHTrackId, fwdtrack::TrackType, fwdtrack::Pt, fwdtrack::Eta, fwdtrack::Phi, emprimarymuon::Sign, - fwdtrack::FwdDcaX, fwdtrack::FwdDcaY, - fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Tgl, + fwdtrack::FwdDcaX, fwdtrack::FwdDcaY, emprimarymuon::CXXatDCA, emprimarymuon::CYYatDCA, emprimarymuon::CXYatDCA, + emprimarymuon::PtMatchedMCHMID, 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::MatchScoreMCHMFT, fwdtrack::MFTTrackId, fwdtrack::MCHTrackId, - emprimarymuon::MCHTrackId, fwdtrack::MCHBitMap, fwdtrack::MIDBitMap, fwdtrack::MIDBoards, - fwdtrack::MFTClusterSizesAndTrackFlags, emprimarymuon::Chi2MFTsa, emprimarymuon::IsAssociatedToMPC, + fwdtrack::MFTClusterSizesAndTrackFlags, emprimarymuon::Chi2MFT, emprimarymuon::IsAssociatedToMPC, emprimarymuon::IsAmbiguous, // dynamic column emprimarymuon::Signed1Pt, @@ -486,8 +846,32 @@ DECLARE_SOA_TABLE(EMPrimaryMuons, "AOD", "EMPRIMARYMU", //! emprimarymuon::P, emprimarymuon::Px, emprimarymuon::Py, - emprimarymuon::Pz, - emprimarymuon::DcaXY); + emprimarymuon::Pz); + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryMuons_001, "AOD", "EMPRIMARYMU", 1, //! + 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::PtMatchedMCHMID, emprimarymuon::EtaMatchedMCHMID, emprimarymuon::PhiMatchedMCHMID, + emprimarymuon::EtaMatchedMCHMIDatMP, emprimarymuon::PhiMatchedMCHMIDatMP, + emprimarymuon::EtaMatchedMFTatMP, emprimarymuon::PhiMatchedMFTatMP, + + 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); + +using EMPrimaryMuons = EMPrimaryMuons_001; // iterators using EMPrimaryMuon = EMPrimaryMuons::iterator; @@ -518,6 +902,130 @@ DECLARE_SOA_TABLE(EMAmbiguousMuonSelfIds, "AOD", "EMAMBMUSELFID", emprimarymuon: // 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 oldemprimarytrack +{ +DECLARE_SOA_COLUMN(Sign, sign, int8_t); +} // namespace oldemprimarytrack + +namespace emprimarytrack +{ +DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! +DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! +DECLARE_SOA_COLUMN(TrackId, trackId, int); //! +DECLARE_SOA_COLUMN(TrackBit, trackBit, uint16_t); //! +DECLARE_SOA_COLUMN(Signed1Pt, signed1Pt, float); //! (sign of charge)/Pt in c/GeV. Use pt() and sign() instead +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float signed1Pt) -> float { return 1.f / std::fabs(signed1Pt); }); +DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, [](float signed1Pt) -> short { return (signed1Pt > 0) ? 1 : -1; }); //! Charge: positive: 1, negative: -1 +} // namespace emprimarytrack + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryTracks_000, "AOD", "EMPRIMARYTRACK", 0, //! primary charged track table for 2PC + o2::soa::Index<>, emprimarytrack::CollisionId, emprimarytrack::TrackId, oldemprimarytrack::Sign, track::Pt, track::Eta, track::Phi, emprimarytrack::TrackBit); + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryTracks_001, "AOD", "EMPRIMARYTRACK", 1, //! primary charged track table for 2PC + o2::soa::Index<>, emprimarytrack::CollisionId, emprimarytrack::TrackId, + emprimarytrack::Signed1Pt, emprimarytrack::Eta, emprimarytrack::Phi, emprimarytrack::TrackBit, + // dynamic column + emprimarytrack::Sign, emprimarytrack::Pt); + +using EMPrimaryTracks = EMPrimaryTracks_001; +// iterators +using EMPrimaryTrack = EMPrimaryTracks::iterator; + +DECLARE_SOA_TABLE(EMPrimaryTrackEMEventIds, "AOD", "PRMTRKEMEVENTID", emprimarytrack::EMEventId); // To be joined with EMPrimaryTracks table at analysis level. +// iterators +using EMPrimaryTrackEMEventId = EMPrimaryTrackEMEventIds::iterator; + +DECLARE_SOA_TABLE(EMPrimaryTrackEMEventIdsTMP, "AOD", "PRMTRKEVIDTMP", track::CollisionId); // To be joined with EMPrimaryTracks in associateDileptonToEMEvent +// iterators +using EMPrimaryTrackEMEventIdTMP = EMPrimaryTrackEMEventIdsTMP::iterator; + +namespace emthinevent +{ +DECLARE_SOA_COLUMN(EP2, ep2, float); //! +} // namespace emthinevent +DECLARE_SOA_TABLE_VERSIONED(EMThinEvents_000, "AOD", "EMTHINEVENT", 0, //! Thin event information table + o2::soa::Index<>, bc::RunNumber, bc::GlobalBC, timestamp::Timestamp, collision::PosZ, + evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, cent::CentFT0C, emthinevent::EP2); +using EMThinEvents = EMThinEvents_000; +using EMThinEvent = EMThinEvents::iterator; + +DECLARE_SOA_TABLE_VERSIONED(EMThinEventNormInfos_000, "AOD", "EMTHINEVENTNORM", 0, //! event information for normalization + o2::soa::Index<>, evsel::Selection, evsel::Rct, emevent::PosZint16, emevent::CentFT0Cuint16, + emevent::Sel8, emevent::PosZ, emevent::CentFT0C, o2::soa::Marker<2>); +using EMThinEventNormInfos = EMThinEventNormInfos_000; +using EMThinEventNormInfo = EMThinEventNormInfos::iterator; + +namespace emdilepton +{ +DECLARE_SOA_INDEX_COLUMN(EMThinEvent, emthinevent); //! +DECLARE_SOA_COLUMN(Pt1, pt1, float); //! +DECLARE_SOA_COLUMN(Eta1, eta1, float); //! +DECLARE_SOA_COLUMN(Phi1, phi1, float); //! +DECLARE_SOA_COLUMN(Sign1, sign1, short); //! +DECLARE_SOA_COLUMN(DCA1, dca1, float); //! DCA in sigma. Users should decide 3D or XY or Z +DECLARE_SOA_COLUMN(Pt2, pt2, float); //! +DECLARE_SOA_COLUMN(Eta2, eta2, float); //! +DECLARE_SOA_COLUMN(Phi2, phi2, float); //! +DECLARE_SOA_COLUMN(DCA2, dca2, float); //! DCA in sigma. Users should decide 3D or XY or Z +DECLARE_SOA_COLUMN(Sign2, sign2, short); //! +DECLARE_SOA_COLUMN(Weight, weight, float); //! possible pair weight +} // namespace emdilepton + +DECLARE_SOA_TABLE_VERSIONED(EMDileptons_000, "AOD", "EMDILEPTON", 0, + o2::soa::Index<>, emdilepton::EMThinEventId, + emdilepton::Pt1, emdilepton::Eta1, emdilepton::Phi1, emdilepton::Sign1, emdilepton::DCA1, + emdilepton::Pt2, emdilepton::Eta2, emdilepton::Phi2, emdilepton::Sign2, emdilepton::DCA2, + emdilepton::Weight); +using EMDileptons = EMDileptons_000; +using EMDilepton = EMDileptons::iterator; + +// Dummy data for MC +namespace emdummydata +{ +DECLARE_SOA_COLUMN(A, a, float); +DECLARE_SOA_COLUMN(B, b, float); +DECLARE_SOA_COLUMN(C, c, float); +DECLARE_SOA_COLUMN(D, d, float); +DECLARE_SOA_COLUMN(E, e, float); +DECLARE_SOA_COLUMN(F, f, float); +DECLARE_SOA_COLUMN(G, g, float); +DECLARE_SOA_COLUMN(H, h, float); +DECLARE_SOA_COLUMN(I, i, float); +DECLARE_SOA_COLUMN(J, j, float); +DECLARE_SOA_COLUMN(K, k, float); +DECLARE_SOA_COLUMN(L, l, float); +DECLARE_SOA_COLUMN(M, m, float); +DECLARE_SOA_COLUMN(N, n, float); +DECLARE_SOA_COLUMN(O, o, float); +DECLARE_SOA_COLUMN(P, p, float); +DECLARE_SOA_COLUMN(Q, q, float); +DECLARE_SOA_COLUMN(R, r, float); +DECLARE_SOA_COLUMN(S, s, float); +DECLARE_SOA_COLUMN(T, t, float); +DECLARE_SOA_COLUMN(U, u, float); +DECLARE_SOA_COLUMN(V, v, float); +DECLARE_SOA_COLUMN(W, w, float); +DECLARE_SOA_COLUMN(X, x, float); +DECLARE_SOA_COLUMN(Y, y, float); +DECLARE_SOA_COLUMN(Z, z, float); +} // namespace emdummydata +DECLARE_SOA_TABLE(EMDummyDatas, "AOD", "EMDUMMYDATA", + o2::soa::Index<>, + emdummydata::A, emdummydata::B, emdummydata::C, emdummydata::D, emdummydata::E, + emdummydata::F, emdummydata::G, emdummydata::H, emdummydata::I, emdummydata::J, + emdummydata::K, emdummydata::L, emdummydata::M, emdummydata::N, emdummydata::O, + emdummydata::P, emdummydata::Q, emdummydata::R, emdummydata::S, emdummydata::T, + emdummydata::U, emdummydata::V, emdummydata::W, emdummydata::X, emdummydata::Y, + emdummydata::Z); + +// iterators +using EMDummyData = EMDummyDatas::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..876a0bf3d4f 100644 --- a/PWGEM/Dilepton/DataModel/lmeeMLTables.h +++ b/PWGEM/Dilepton/DataModel/lmeeMLTables.h @@ -9,14 +9,16 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisDataModel.h" + +#include #ifndef PWGEM_DILEPTON_DATAMODEL_LMEEMLTABLES_H_ #define PWGEM_DILEPTON_DATAMODEL_LMEEMLTABLES_H_ @@ -24,32 +26,36 @@ namespace o2::aod { -namespace pwgem::dilepton +namespace pwgem::dilepton::ml { -enum class PID_Label : int { - kUnDef = -1, +enum class PID_Label : uint8_t { kElectron = 0, kMuon = 1, 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 { +enum class Track_Type : uint8_t { kPrimary = 0, kSecondary = 1, }; // this can be used for selecting electron from primary or photon conversion. -} // namespace pwgem::dilepton +} // namespace pwgem::dilepton::ml -namespace emprimarytrack +namespace emmltrack { -DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! -DECLARE_SOA_COLUMN(PIDLabel, pidlabel, int); //! -DECLARE_SOA_COLUMN(TrackType, tracktype, int); //! -DECLARE_SOA_COLUMN(TPCNClsFound, tpcNClsFound, int); //! -DECLARE_SOA_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, int); //! -DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, float); //! +DECLARE_SOA_COLUMN(PIDLabel, pidlabel, uint8_t); //! +DECLARE_SOA_COLUMN(TrackType, tracktype, uint8_t); //! +DECLARE_SOA_COLUMN(TPCNClsFound, tpcNClsFound, uint8_t); //! +DECLARE_SOA_COLUMN(TPCNClsCrossedRows, tpcNClsCrossedRows, uint8_t); //! +DECLARE_SOA_COLUMN(TPCNClsPID, tpcNClsPID, uint8_t); //! +DECLARE_SOA_COLUMN(IsForValidation, isForValidation, bool); //! +DECLARE_SOA_COLUMN(Sign, sign, short); //! +DECLARE_SOA_COLUMN(P, p, float); //! +// DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); 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++) { @@ -65,25 +71,48 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITS, meanClusterSizeITS, [](uint32_t i return 0; } }); -} // namespace emprimarytrack +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 emmltrack // reconstructed track information -DECLARE_SOA_TABLE(EMPrimaryTracks, "AOD", "EMPTRACK", //! - o2::soa::Index<>, emprimarytrack::CollisionId, collision::PosZ, collision::NumContrib, - track::Pt, track::Eta, track::Phi, track::Tgl, track::Signed1Pt, - track::DcaXY, track::DcaZ, track::CYY, track::CZZ, track::CZY, - track::TPCNClsFindable, emprimarytrack::TPCNClsFound, emprimarytrack::TPCNClsCrossedRows, +DECLARE_SOA_TABLE(EMTracksForMLPID, "AOD", "EMTRACKMLPID", //! + o2::soa::Index<>, collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, emmltrack::HadronicRate, + emmltrack::P, track::Tgl, emmltrack::Sign, + track::TPCNClsFindable, emmltrack::TPCNClsFound, emmltrack::TPCNClsCrossedRows, emmltrack::TPCNClsPID, 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::TPCSignal, + pidtofbeta::Beta, + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, emmltrack::PIDLabel, // dynamic column - emprimarytrack::P, - emprimarytrack::MeanClusterSizeITS); + emmltrack::MeanClusterSizeITS, + emmltrack::MeanClusterSizeITSob); + +DECLARE_SOA_TABLE(EMPIDsEl, "AOD", "EMPIDEL", pidtpc::TPCNSigmaEl, pidtof::TOFNSigmaEl); // Joinable with EMTracksForMLPID +DECLARE_SOA_TABLE(EMPIDsPi, "AOD", "EMPIDPI", pidtpc::TPCNSigmaPi, pidtof::TOFNSigmaPi); // Joinable with EMTracksForMLPID +DECLARE_SOA_TABLE(EMPIDsKa, "AOD", "EMPIDKA", pidtpc::TPCNSigmaKa, pidtof::TOFNSigmaKa); // Joinable with EMTracksForMLPID +DECLARE_SOA_TABLE(EMPIDsPr, "AOD", "EMPIDPR", pidtpc::TPCNSigmaPr, pidtof::TOFNSigmaPr); // Joinable with EMTracksForMLPID // iterators -using EMPrimaryTrack = EMPrimaryTracks::iterator; +using EMTrackForMLPID = EMTracksForMLPID::iterator; +using EMPIDEl = EMPIDsEl::iterator; +using EMPIDPi = EMPIDsPi::iterator; +using EMPIDKa = EMPIDsKa::iterator; +using EMPIDPr = EMPIDsPr::iterator; } // namespace o2::aod diff --git a/PWGEM/Dilepton/TableProducer/CMakeLists.txt b/PWGEM/Dilepton/TableProducer/CMakeLists.txt index 00189858282..94eb9568d51 100644 --- a/PWGEM/Dilepton/TableProducer/CMakeLists.txt +++ b/PWGEM/Dilepton/TableProducer/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(Converters) o2physics_add_dpl_workflow(tree-creator-electron-ml SOURCES treeCreatorElectronML.cxx @@ -17,36 +18,36 @@ o2physics_add_dpl_workflow(tree-creator-electron-ml o2physics_add_dpl_workflow(tree-creator-electron-ml-dda SOURCES treeCreatorElectronMLDDA.cxx - 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 - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(tree-creator-single-electron-qa - SOURCES treeCreatorSingleElectronQA.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(skimmer-primary-electron SOURCES skimmerPrimaryElectron.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(skimmer-primary-electron-qc + SOURCES skimmerPrimaryElectronQC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(skimmer-primary-muon SOURCES skimmerPrimaryMuon.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(skimmer-secondary-electron - SOURCES skimmerSecondaryElectron.cxx +o2physics_add_dpl_workflow(skimmer-primary-track + SOURCES skimmerPrimaryTrack.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) @@ -55,3 +56,22 @@ o2physics_add_dpl_workflow(associate-mc-info-dilepton 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) + +o2physics_add_dpl_workflow(dielectron-producer + SOURCES dielectronProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dimuon-producer + SOURCES dimuonProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/Dilepton/TableProducer/Converters/CMakeLists.txt b/PWGEM/Dilepton/TableProducer/Converters/CMakeLists.txt new file mode 100644 index 00000000000..eea03e885e6 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/CMakeLists.txt @@ -0,0 +1,72 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does 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(event-converter3 + SOURCES eventConverter3.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-converter4 + SOURCES eventConverter4.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) + +o2physics_add_dpl_workflow(electron-converter3 + SOURCES electronConverter3.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(electron-converter4 + SOURCES electronConverter4.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(electron-converter5 + SOURCES electronConverter5.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(track-converter1 + SOURCES trackConverter1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(muon-converter1 + SOURCES muonConverter1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(mcparticle-converter1 + SOURCES mcParticleConverter1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(qvec-converter + SOURCES qvecConverter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-norm-converter1 + SOURCES eventNormConverter1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + diff --git a/PWGEM/Dilepton/TableProducer/Converters/electronConverter2.cxx b/PWGEM/Dilepton/TableProducer/Converters/electronConverter2.cxx new file mode 100644 index 00000000000..4a3af5c4313 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/electronConverter2.cxx @@ -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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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 (const 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/TableProducer/Converters/electronConverter3.cxx b/PWGEM/Dilepton/TableProducer/Converters/electronConverter3.cxx new file mode 100644 index 00000000000..87e49f9fb5e --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/electronConverter3.cxx @@ -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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct electronConverter3 { + Produces track_003; + + void process(aod::EMPrimaryElectrons_002 const& tracks) + { + for (const auto& track : tracks) { + track_003(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(), + // track.itsNSigmaEl(), + // track.itsNSigmaMu(), + // track.itsNSigmaPi(), + // track.itsNSigmaKa(), + // track.itsNSigmaPr(), + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap(), + track.x(), + track.alpha(), + track.y(), + track.z(), + track.snp(), + track.tgl(), + track.isAssociatedToMPC(), + -1); + } // end of track loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"electron-converter3"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/electronConverter4.cxx b/PWGEM/Dilepton/TableProducer/Converters/electronConverter4.cxx new file mode 100644 index 00000000000..dcca6b5edc1 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/electronConverter4.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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct electronConverter4 { + Produces track_004; + + using MyElectrons002 = soa::Join; + void process002to004(MyElectrons002 const& tracks) + { + for (const auto& track : tracks) { + track_004(track.collisionId(), + track.trackId(), + 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.tpcNSigmaKa(), + track.tpcNSigmaPr(), + track.beta(), + track.tofNSigmaEl(), + // track.tofNSigmaPi(), + // track.tofNSigmaKa(), + // track.tofNSigmaPr(), + track.itsClusterSizes(), + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap(), + // track.tgl(), + track.isAssociatedToMPC(), + false, + 0.f, + 0.f); + } // end of track loop + } + PROCESS_SWITCH(electronConverter4, process002to004, "convert from 002 into 004", false); + + using MyElectrons003 = soa::Join; + void process003to004(MyElectrons003 const& tracks) + { + for (const auto& track : tracks) { + track_004(track.collisionId(), + track.trackId(), + 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.tpcNSigmaKa(), + track.tpcNSigmaPr(), + track.beta(), + track.tofNSigmaEl(), + // track.tofNSigmaPi(), + // track.tofNSigmaKa(), + // track.tofNSigmaPr(), + track.itsClusterSizes(), + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap(), + // track.tgl(), + track.isAssociatedToMPC(), + false, + 0.f, + track.mcTunedTPCSignal()); + } // end of track loop + } + PROCESS_SWITCH(electronConverter4, process003to004, "convert from 003 into 004", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"electron-converter4"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/electronConverter5.cxx b/PWGEM/Dilepton/TableProducer/Converters/electronConverter5.cxx new file mode 100644 index 00000000000..60ea4f0db2e --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/electronConverter5.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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct electronConverter5 { + Produces track_005; + + using MyElectrons002 = soa::Join; + void process002to005(MyElectrons002 const& tracks) + { + for (const auto& track : tracks) { + track_005(track.collisionId(), + track.trackId(), + track.sign(), + track.pt(), + track.eta(), + track.phi(), + track.dcaXY(), + track.dcaZ(), + track.cYY(), + track.cZY(), + track.cZZ(), + track.tpcNClsFindable(), + track.tpcNClsFindableMinusFound(), + 0, + track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsShared(), + track.tpcChi2NCl(), + track.tpcInnerParam(), + track.tpcSignal(), + track.tpcNSigmaEl(), + track.tpcNSigmaPi(), + track.tpcNSigmaKa(), + track.tpcNSigmaPr(), + track.beta(), + track.tofNSigmaEl(), + // track.tofNSigmaPi(), + // track.tofNSigmaKa(), + // track.tofNSigmaPr(), + track.itsClusterSizes(), + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap(), + // track.tgl(), + track.isAssociatedToMPC(), + false, + 0.f, + 0.f); + } // end of track loop + } + PROCESS_SWITCH(electronConverter5, process002to005, "convert from 002 into 005", false); + + using MyElectrons003 = soa::Join; + void process003to005(MyElectrons003 const& tracks) + { + for (const auto& track : tracks) { + track_005(track.collisionId(), + track.trackId(), + track.sign(), + track.pt(), + track.eta(), + track.phi(), + track.dcaXY(), + track.dcaZ(), + track.cYY(), + track.cZY(), + track.cZZ(), + track.tpcNClsFindable(), + track.tpcNClsFindableMinusFound(), + 0, + track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsShared(), + track.tpcChi2NCl(), + track.tpcInnerParam(), + track.tpcSignal(), + track.tpcNSigmaEl(), + track.tpcNSigmaPi(), + track.tpcNSigmaKa(), + track.tpcNSigmaPr(), + track.beta(), + track.tofNSigmaEl(), + // track.tofNSigmaPi(), + // track.tofNSigmaKa(), + // track.tofNSigmaPr(), + track.itsClusterSizes(), + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap(), + // track.tgl(), + track.isAssociatedToMPC(), + false, + 0.f, + track.mcTunedTPCSignal()); + } // end of track loop + } + PROCESS_SWITCH(electronConverter5, process003to005, "convert from 003 into 005", false); + + void process004to005(aod::EMPrimaryElectrons_004 const& tracks) + { + for (const auto& track : tracks) { + track_005(track.collisionId(), + track.trackId(), + track.sign(), + track.pt(), + track.eta(), + track.phi(), + track.dcaXY(), + track.dcaZ(), + track.cYY(), + track.cZY(), + track.cZZ(), + track.tpcNClsFindable(), + track.tpcNClsFindableMinusFound(), + 0, + track.tpcNClsFindableMinusCrossedRows(), + track.tpcNClsShared(), + track.tpcChi2NCl(), + track.tpcInnerParam(), + track.tpcSignal(), + track.tpcNSigmaEl(), + track.tpcNSigmaPi(), + track.tpcNSigmaKa(), + track.tpcNSigmaPr(), + track.beta(), + track.tofNSigmaEl(), + // track.tofNSigmaPi(), + // track.tofNSigmaKa(), + // track.tofNSigmaPr(), + track.itsClusterSizes(), + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap(), + // track.tgl(), + track.isAssociatedToMPC(), + track.isAmbiguous(), + track.probElBDT(), + track.mcTunedTPCSignal()); + } // end of track loop + } + PROCESS_SWITCH(electronConverter5, process004to005, "convert from 004 into 005", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"electron-converter5"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/eventConverter2.cxx b/PWGEM/Dilepton/TableProducer/Converters/eventConverter2.cxx new file mode 100644 index 00000000000..791876beb15 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/eventConverter2.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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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 (const 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/TableProducer/Converters/eventConverter3.cxx b/PWGEM/Dilepton/TableProducer/Converters/eventConverter3.cxx new file mode 100644 index 00000000000..77f3e070980 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/eventConverter3.cxx @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct eventConverter3 { + Produces event_003; + + void process(aod::EMEvents_002 const& collisions) + { + for (const auto& collision : collisions) { + event_003( + collision.globalIndex(), + collision.runNumber(), + collision.globalBC(), + collision.alias_raw(), + collision.selection_raw(), + collision.rct_raw(), + collision.timestamp(), + collision.posZ(), + collision.numContrib(), + collision.trackOccupancyInTimeRange(), + collision.ft0cOccupancyInTimeRange()); + } // end of collision loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"event-converter3"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/eventConverter4.cxx b/PWGEM/Dilepton/TableProducer/Converters/eventConverter4.cxx new file mode 100644 index 00000000000..848c24a5c69 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/eventConverter4.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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct eventConverter4 { + Produces event_004; + Produces eventalias_000; + + void process003to004(aod::EMEvents_003 const& collisions) + { + for (const auto& collision : collisions) { + event_004( + collision.globalIndex(), + collision.runNumber(), + collision.globalBC(), + collision.selection_raw(), + collision.rct_raw(), + collision.timestamp(), + collision.posZ(), + collision.numContrib(), + collision.trackOccupancyInTimeRange(), + collision.ft0cOccupancyInTimeRange()); + } // end of collision loop + } + PROCESS_SWITCH(eventConverter4, process003to004, "convert from 003 into 004", true); + + void processAlias(aod::EMEvents_003 const& collisions) + { + for (const auto& collision : collisions) { + eventalias_000( + collision.alias_raw()); + } // end of collision loop + } + PROCESS_SWITCH(eventConverter4, processAlias, "convert from 003 into alias", false); // only for photon PAG. +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"event-converter4"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/eventNormConverter1.cxx b/PWGEM/Dilepton/TableProducer/Converters/eventNormConverter1.cxx new file mode 100644 index 00000000000..2965c836239 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/eventNormConverter1.cxx @@ -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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct eventNormConverter1 { + Produces event_001; + + void process(aod::EMEventNormInfos_000 const& collisions) + { + for (const auto& collision : collisions) { + event_001( + collision.selection_raw(), + collision.rct_raw(), + static_cast(collision.posZint16() * 10.f), + static_cast(collision.centFT0C() * 500.f)); + } // end of collision loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"event-norm-converter1"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/mcParticleConverter1.cxx b/PWGEM/Dilepton/TableProducer/Converters/mcParticleConverter1.cxx new file mode 100644 index 00000000000..5f219f459ca --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/mcParticleConverter1.cxx @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 emmctable table 001 from 000. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct mcParticleConverter1 { + Produces mcParticle_001; + + void process(aod::EMMCParticles_000 const& mcParticles) + { + for (const auto& mcParticle : mcParticles) { + // LOGF(info, "mcParticles.emmceventId() = %d, mcParticle.mothersIds().size() = %d, mcParticle.daughtersIds().size() = %d", mcParticle.emmceventId(), mcParticle.mothersIds().size(), mcParticle.daughtersIds().size()); + + std::vector mothersIds; + for (const auto& id : mcParticle.mothersIds()) { + mothersIds.emplace_back(id); + } + + std::vector daughtersIds; + for (const auto& id : mcParticle.daughtersIds()) { + daughtersIds.emplace_back(id); + } + + mcParticle_001( + mcParticle.emmceventId(), mcParticle.pdgCode(), mcParticle.flags(), 0, + mothersIds, daughtersIds, + mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e(), + mcParticle.vx(), mcParticle.vy(), mcParticle.vz()); + } // end of mc particle loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"mcparticle-converter1"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/muonConverter1.cxx b/PWGEM/Dilepton/TableProducer/Converters/muonConverter1.cxx new file mode 100644 index 00000000000..527faf7c723 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/muonConverter1.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. +// +// ======================== +// +// This code produces muon table 001 from 000. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct muonConverter1 { + Produces muon_001; + + void process(aod::EMPrimaryMuons_000 const& muons) + { + for (const auto& muon : muons) { + muon_001( + muon.collisionId(), + muon.fwdtrackId(), muon.mfttrackId(), muon.mchtrackId(), muon.trackType(), + muon.pt(), muon.eta(), muon.phi(), muon.sign(), + muon.fwdDcaX(), muon.fwdDcaY(), muon.cXXatDCA(), muon.cYYatDCA(), muon.cXYatDCA(), + muon.ptMatchedMCHMID(), muon.etaMatchedMCHMID(), muon.phiMatchedMCHMID(), + 0, 0, 0, 0, + muon.nClusters(), muon.pDca(), muon.rAtAbsorberEnd(), + muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), + muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), + muon.mftClusterSizesAndTrackFlags(), muon.chi2MFT(), muon.isAssociatedToMPC(), muon.isAmbiguous()); + } // end of muon loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"muon-converter1"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/qvecConverter.cxx b/PWGEM/Dilepton/TableProducer/Converters/qvecConverter.cxx new file mode 100644 index 00000000000..d0164dac5ab --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/qvecConverter.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 qvecConverter.cxx +/// \brief Analysis task for neutral pion flow with EMCal +/// \author M. Hemmer, marvin.hemmer@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +// Converts EMEventsQvec_000 into EMEventsQvec_001 +struct QvecConverter { + Produces qvec001; + + void process(aod::EMEventsQvec_000 const& emEventsQVec) + { + for (const auto& qvec : emEventsQVec) { + constexpr float EmptyV0 = -999.f; + qvec001(qvec.q2xft0m(), qvec.q2yft0m(), qvec.q2xft0a(), qvec.q2yft0a(), qvec.q2xft0c(), qvec.q2yft0c(), EmptyV0, EmptyV0, qvec.q2xbpos(), qvec.q2ybpos(), qvec.q2xbneg(), qvec.q2ybneg(), qvec.q2xbtot(), qvec.q2ybtot(), qvec.q3xft0m(), qvec.q3yft0m(), qvec.q3xft0a(), qvec.q3yft0a(), qvec.q3xft0c(), qvec.q3yft0c(), EmptyV0, EmptyV0, qvec.q3xbpos(), qvec.q3ybpos(), qvec.q3xbneg(), qvec.q3ybneg(), qvec.q3xbtot(), qvec.q3ybtot()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGEM/Dilepton/TableProducer/Converters/trackConverter1.cxx b/PWGEM/Dilepton/TableProducer/Converters/trackConverter1.cxx new file mode 100644 index 00000000000..c6f7bfce634 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/Converters/trackConverter1.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct trackConverter1 { + Produces track_001; + + void process(aod::EMPrimaryTracks_000 const& tracks) + { + for (const auto& track : tracks) { + track_001(track.collisionId(), + track.trackId(), + track.sign() / track.pt(), + track.eta(), + track.phi(), + track.trackBit()); + } // end of track loop + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"track-converter1"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx b/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx index be235eb6ffe..1b4044f4bf3 100644 --- a/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx +++ b/PWGEM/Dilepton/TableProducer/associateMCinfoDilepton.cxx @@ -14,23 +14,27 @@ // 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/Dilepton/DataModel/dileptonTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "Common/Core/TableHelper.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include + 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, @@ -38,42 +42,86 @@ struct AssociateMCInfoDilepton { kPCM = 0x4, }; + using MyCollisionsMC = soa::Join; + using TracksMC = soa::Join; + using FwdTracksMC = soa::Join; + using MFTTracksMC = soa::Join; + Produces mcevents; Produces mceventlabels; Produces emmcparticles; + Produces emmcgenvms; Produces v0legmclabels; Produces emprimaryelectronmclabels; Produces emprimarymuonmclabels; + Produces emmftmclabels; + Produces emdummydata; - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; - Configurable min_eta_gen_primary{"min_eta_gen_primary", -1.2, "min rapidity Y to store generated information"}; // smearing might be applied at analysis stage. set wider value. - Configurable max_eta_gen_primary{"max_eta_gen_primary", +1.2, "max rapidity Y to store generated information"}; // smearing might be applied at analysis stage. set wider value. - Configurable min_eta_gen_primary_fwd{"min_eta_gen_primary_fwd", -4.5, "min eta to store generated information"}; // smearing might be applied at analysis stage. set wider value. - Configurable max_eta_gen_primary_fwd{"max_eta_gen_primary_fwd", -2.0, "max eta to store generated information"}; // smearing might be applied at analysis stage. set wider value. + Configurable n_dummy_loop{"n_dummy_loop", 0, "for loop runs over n times"}; + 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 eta 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 eta to store generated information"}; // smearing is applied at analysis stage. set wider value. + Configurable min_eta_gen_primary_fwd{"min_eta_gen_primary_fwd", -6.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.0, "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 isInMidrapidity(TMCParticle const& mctrack) + template + bool isDecayDielectronInAcceptance(TMCParticle const& mctrack, TMCParticles const& mcTracks) { - if (min_eta_gen_primary < mctrack.eta() && mctrack.eta() < max_eta_gen_primary) { + 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 isInFwdrapidity(TMCParticle const& mctrack) + template + bool isDecayDimuonInAcceptance(TMCParticle const& mctrack, TMCParticles const& mcTracks) { - if (min_eta_gen_primary_fwd < mctrack.eta() && mctrack.eta() < max_eta_gen_primary_fwd) { + 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; @@ -89,10 +137,10 @@ struct AssociateMCInfoDilepton { // 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 = nabs(o2::aod::mcparticle::pdgCode) == 223 || nabs(o2::aod::mcparticle::pdgCode) == 333; + 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) + template + void skimmingMC(MyCollisionsMC const& collisions, aod::BCs const&, aod::McCollisions const& mcCollisions, aod::McParticles const& mcTracks, TTracks const& o2tracks, TFwdTracks const& o2fwdtracks, TMFTTracks const&, TPCMs const& v0photons, TPCMLegs const&, TEMPrimaryElectrons const& emprimaryelectrons, TEMPrimaryMuons const& emprimarymuons) { // temporary variables used for the indexing of the skimmed MC stack std::map fNewLabels; @@ -103,16 +151,16 @@ struct AssociateMCInfoDilepton { 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 (auto& mcCollision : mcCollisions) { + 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.t(), mcCollision.impactParameter()); + 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 (auto& collision : collisions) { + for (const auto& collision : collisions) { registry.fill(HIST("hEventCounter"), 1); // TODO: investigate the collisions without corresponding mcCollision @@ -120,7 +168,11 @@ struct AssociateMCInfoDilepton { continue; } - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { + continue; + } + + if (!collision.isEoI()) { // events with at least 1 lepton for data reduction. continue; } @@ -130,181 +182,192 @@ struct AssociateMCInfoDilepton { } // end of reconstructed collision loop - // store MC true information - for (auto& mctrack : mcelectrons) { // 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) { + 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()); - 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]++; + 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()); - int motherid = -999; // first mother index + // 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 = mctrack.mothersIds()[0]; // first mother index + motherid_tmp = 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); + auto mp_tmp = mcTracks.iteratorAt(motherid_tmp); + int ndau_tmp = mp_tmp.daughtersIds()[1] - mp_tmp.daughtersIds()[0] + 1; + if (ndau_tmp < 10) { - // 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 (!(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 (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; // first mother index - } else { - motherid = -999; - } - } else { - motherid = -999; + int motherid = -999; // first mother index + if (mctrack.has_mothers()) { + motherid = mctrack.mothersIds()[0]; // first mother index } - } // end of mother chain loop - } // end of ndau protection - } // end of mc electron loop + while (motherid > -1) { + if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcTracks.iteratorAt(motherid); - for (auto& mctrack : mcmuons) { // store necessary information for denominator of efficiency - if (!mctrack.isPhysicalPrimary() && !mctrack.producedByGenerator()) { - continue; - } - auto mcCollision = mcCollisions.iteratorAt(mctrack.mcCollisionId()); + // 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]++; + } - // 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 (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 - 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]++; + 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()); - int motherid = -999; // first mother index + // 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 = mctrack.mothersIds()[0]; // first mother index + motherid_tmp = 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); + auto mp_tmp = mcTracks.iteratorAt(motherid_tmp); + int ndau_tmp = mp_tmp.daughtersIds()[1] - mp_tmp.daughtersIds()[0] + 1; + if (ndau_tmp < 10) { - // 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 (!(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 (mp.has_mothers()) { - motherid = mp.mothersIds()[0]; // first mother index + 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; } - } else { - motherid = -999; - } - } // end of mother chain loop - } // end of ndau protection - } // end of mc muon loop - - for (auto& mctrack : mcvectormesons) { // store necessary information for denominator of efficiency - // Be careful!! dilepton rapidity is different from meson rapidity! No acceptance cut here. + } // end of mother chain loop + } // end of ndau protection + } // end of mc muon loop - if (!mctrack.isPhysicalPrimary() && !mctrack.producedByGenerator()) { - continue; - } - auto mcCollision = mcCollisions.iteratorAt(mctrack.mcCollisionId()); + 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. - int ndau = mctrack.daughtersIds()[1] - mctrack.daughtersIds()[0] + 1; - if (ndau < 10) { + if (!mctrack.isPhysicalPrimary() && !mctrack.producedByGenerator()) { + continue; + } - 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 (!isDecayDielectronInAcceptance(mctrack, mcTracks) && !isDecayDimuonInAcceptance(mctrack, mcTracks)) { // acceptance cut to decay dileptons + continue; } - // 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 (abs(daughter.pdgCode()) == 11 || 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; - } + // 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]++; } - 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); + // 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 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]++; + 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; } - } // end of daughter loop + } + + 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 ndau protection + } // end of generated vector mesons loop + + } // end of mc collision loop if constexpr (static_cast(system & kPCM)) { - for (auto& v0 : v0photons) { + for (const auto& v0 : v0photons) { auto collision_from_v0 = collisions.iteratorAt(v0.collisionId()); if (!collision_from_v0.has_mcCollision()) { continue; } - auto mcCollision_from_v0 = collision_from_v0.mcCollision(); - auto ele = v0.template negTrack_as(); - auto pos = v0.template posTrack_as(); + 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()); @@ -313,7 +376,7 @@ struct AssociateMCInfoDilepton { continue; // If no MC particle is found, skip the v0 } - for (auto& leg : {pos, ele}) { // be carefull of order {pos, ele}! + 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. @@ -323,7 +386,7 @@ struct AssociateMCInfoDilepton { fNewLabels[mctrack.globalIndex()] = fCounters[0]; fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); // fMCFlags[mctrack.globalIndex()] = mcflags; - fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision_from_v0.globalIndex())->second; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mctrack.mcCollisionId())->second; fCounters[0]++; } v0legmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); @@ -342,7 +405,7 @@ struct AssociateMCInfoDilepton { fNewLabels[mp.globalIndex()] = fCounters[0]; fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); // fMCFlags[mp.globalIndex()] = mcflags; - fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision_from_v0.globalIndex())->second; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mp.mcCollisionId())->second; fCounters[0]++; } @@ -355,18 +418,17 @@ struct AssociateMCInfoDilepton { motherid = -999; } } // end of mother chain loop - } // end of leg loop - } // end of v0 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 (auto& emprimaryelectron : emprimaryelectrons) { + for (const 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()) { @@ -379,7 +441,7 @@ struct AssociateMCInfoDilepton { fNewLabels[mctrack.globalIndex()] = fCounters[0]; fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); // fMCFlags[mctrack.globalIndex()] = mcflags; - fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision_from_el.globalIndex())->second; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mctrack.mcCollisionId())->second; fCounters[0]++; } emprimaryelectronmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); @@ -398,7 +460,7 @@ struct AssociateMCInfoDilepton { fNewLabels[mp.globalIndex()] = fCounters[0]; fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); // fMCFlags[mp.globalIndex()] = mcflags; - fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision_from_el.globalIndex())->second; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mp.mcCollisionId())->second; fCounters[0]++; } @@ -414,14 +476,14 @@ struct AssociateMCInfoDilepton { } // end of em primary electron loop } + if constexpr (static_cast(system & kFwdMuon)) { // auto emprimarymuons_coll = emprimarymuons.sliceBy(perCollision_mu, collision.globalIndex()); - for (auto& emprimarymuon : emprimarymuons) { + for (const auto& emprimarymuon : emprimarymuons) { auto collision_from_mu = collisions.iteratorAt(emprimarymuon.collisionId()); if (!collision_from_mu.has_mcCollision()) { continue; } - auto mcCollision_from_mu = collision_from_mu.mcCollision(); auto o2track = o2fwdtracks.iteratorAt(emprimarymuon.fwdtrackId()); if (!o2track.has_mcParticle()) { @@ -434,7 +496,7 @@ struct AssociateMCInfoDilepton { fNewLabels[mctrack.globalIndex()] = fCounters[0]; fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); // fMCFlags[mctrack.globalIndex()] = mcflags; - fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision_from_mu.globalIndex())->second; + fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mctrack.mcCollisionId())->second; fCounters[0]++; } emprimarymuonmclabels(fNewLabels.find(mctrack.index())->second, o2track.mcMask()); @@ -453,7 +515,7 @@ struct AssociateMCInfoDilepton { fNewLabels[mp.globalIndex()] = fCounters[0]; fNewLabelsReversed[fCounters[0]] = mp.globalIndex(); // fMCFlags[mp.globalIndex()] = mcflags; - fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollision_from_mu.globalIndex())->second; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mp.mcCollisionId())->second; fCounters[0]++; } @@ -467,6 +529,54 @@ struct AssociateMCInfoDilepton { } } // end of mother chain loop + // mc label for tracks registered in MFT in global muons + if (o2track.matchMFTTrackId() > -1) { + auto o2mfttrack = o2track.template matchMFTTrack_as(); + if (!o2mfttrack.has_mcParticle()) { + emmftmclabels(-1, 0); + break; + } + + auto mco2mfttrack = o2mfttrack.template mcParticle_as(); + if (!(fNewLabels.find(mco2mfttrack.globalIndex()) != fNewLabels.end())) { + fNewLabels[mco2mfttrack.globalIndex()] = fCounters[0]; + fNewLabelsReversed[fCounters[0]] = mco2mfttrack.globalIndex(); + // fMCFlags[mco2mfttrack.globalIndex()] = mcflags; + fEventIdx[mco2mfttrack.globalIndex()] = fEventLabels.find(mco2mfttrack.mcCollisionId())->second; + fCounters[0]++; + } + emmftmclabels(fNewLabels.find(mco2mfttrack.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 + } else { + emmftmclabels(-1, 0); + } } // end of em primary muon loop } @@ -477,7 +587,7 @@ struct AssociateMCInfoDilepton { std::vector mothers; if (mctrack.has_mothers()) { - for (auto& m : mctrack.mothersIds()) { + 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); @@ -515,7 +625,7 @@ struct AssociateMCInfoDilepton { } } - emmcparticles(fEventIdx.find(oldLabel)->second, mctrack.pdgCode(), mctrack.flags(), + emmcparticles(fEventIdx.find(oldLabel)->second, mctrack.pdgCode(), mctrack.flags(), mctrack.statusCode(), mothers, daughters, mctrack.px(), mctrack.py(), mctrack.pz(), mctrack.e(), mctrack.vx(), mctrack.vy(), mctrack.vz()); @@ -526,6 +636,26 @@ struct AssociateMCInfoDilepton { 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(); @@ -538,36 +668,49 @@ struct AssociateMCInfoDilepton { 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); + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, 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) + void processMC_FwdMuon(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, FwdTracksMC const& o2fwdtracks, MFTTracksMC const& o2mfttracks, aod::EMPrimaryMuons const& emprimarymuons) { const uint8_t sysflag = kFwdMuon; - skimmingMC(collisions, bcs, mccollisions, mcTracks, nullptr, o2fwdtracks, nullptr, nullptr, nullptr, emprimarymuons); + skimmingMC(collisions, bcs, mccollisions, mcTracks, nullptr, o2fwdtracks, o2mfttracks, 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) + 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, MFTTracksMC const& o2mfttracks, 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); + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, o2fwdtracks, o2mfttracks, 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) + 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, MFTTracksMC const& o2mfttracks, 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); + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, o2fwdtracks, o2mfttracks, 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); + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, 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); + skimmingMC(collisions, bcs, mccollisions, mcTracks, o2tracks, nullptr, nullptr, v0photons, v0legs, nullptr, nullptr); + } + + void processGenDummy(MyCollisionsMC const&) + { + for (int i = 0; i < n_dummy_loop; i++) { + emdummydata( + 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, 0.f, 0.f, 0.f, 0.f, + 0.f); + } } void processDummy(MyCollisionsMC const&) {} @@ -578,6 +721,7 @@ struct AssociateMCInfoDilepton { 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, processGenDummy, "produce dummy data", false); PROCESS_SWITCH(AssociateMCInfoDilepton, processDummy, "processDummy", true); }; diff --git a/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx b/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx index 7ddf963f617..299543874d8 100644 --- a/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx +++ b/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx @@ -9,50 +9,70 @@ // 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 "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "EventFiltering/Zorro.h" -#include "Common/Core/TableHelper.h" +/// \file createEMEventDilepton.cxx +/// \brief This code produces reduced events for dilepton analyses. +/// \author Daiki Sekihata, daiki.sekihata@cern.ch #include "PWGEM/Dilepton/DataModel/dileptonTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Qvectors.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + 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 MyQvectors = soa::Join; -using MyCollisions = soa::Join; -using MyCollisions_Cent = soa::Join; // centrality table has dependency on multiplicity table. +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 = soa::Join; // centrality table has dependency on multiplicity table. using MyCollisionsMC_Cent_Qvec = soa::Join; struct CreateEMEventDilepton { + Produces embc; Produces event; + Produces eventXY; // Produces eventcov; Produces event_mult; Produces event_cent; Produces event_qvec; - Produces emswtbit; + Produces emswtbit; + Produces emswtinfo; + Produces emswtATcounter; + Produces emswtTOIcounter; + Produces event_norm_info; enum class EMEventType : int { kEvent = 0, @@ -60,228 +80,236 @@ struct CreateEMEventDilepton { 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"}; - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; - Configurable enable_swt{"enable_swt", false, "flag to process skimmed data (swt triggered)"}; - 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! + // // CCDB options + // Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; 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() - { - swt_names.clear(); - swt_names.shrink_to_fit(); } - Zorro zorro; - std::vector mTOIidx; - std::vector swt_names; - uint64_t mNinspectedTVX{0}; + ~CreateEMEventDilepton() {} - int mRunNumber; - float d_bz; - Service ccdb; + int mRunNumber{0}; + // Service ccdb; - template - void initCCDB(TBC const& bc) + template + void skimEvent(TCollisions const& collisions, TBCs const& bcs) { - if (mRunNumber == bc.runNumber()) { - return; - } - - if (enable_swt) { - LOGF(info, "enable software triggers : %s", cfg_swt_names.value.data()); - mTOIidx = zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); - std::stringstream tokenizer(cfg_swt_names.value); - std::string token; - while (std::getline(tokenizer, token, ',')) { - swt_names.emplace_back(token); - } - 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); - } - - // 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)); + for (const auto& bc : bcs) { + if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + embc(bc.selection_raw(), bc.rct_raw()); // TVX is fired. } - 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 perCollision_pcm = aod::v0photonkf::collisionId; - PresliceUnsorted perCollision_el = aod::emprimaryelectron::collisionId; - PresliceUnsorted perCollision_mu = aod::emprimarymuon::collisionId; + } // end of bc loop - template - void skimEvent(TCollisions const& collisions, TBCs const&) - { - for (auto& collision : collisions) { + 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 (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + int16_t posZint16 = static_cast(collision.posZ() * 100.f); + if (posZint16 == 0) { + if (collision.posZ() < 0.f) { + posZint16 = -1; + } else { + posZint16 = +1; + } + } + if constexpr (eventtype == EMEventType::kEvent) { + event_norm_info(collision.selection_raw(), collision.rct_raw(), posZint16, static_cast(105.f * 500.f)); + } else if constexpr (eventtype == EMEventType::kEvent_Cent || eventtype == EMEventType::kEvent_Cent_Qvec) { + event_norm_info(collision.selection_raw(), collision.rct_raw(), posZint16, static_cast(collision.centFT0C() * 500.f)); + } else { + event_norm_info(collision.selection_raw(), collision.rct_raw(), posZint16, static_cast(105.f * 500.f)); + } + } + + if (!collision.isSelected()) { // minimal cut for MB continue; } - if (enable_swt) { - 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()); - uint16_t trigger_bitmap = 0; - 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)); - } - } - emswtbit(trigger_bitmap, mNinspectedTVX); - } else { // rejected + 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()); } } - // LOGF(info, "collision.multNTracksPV() = %d, collision.multFT0A() = %f, collision.multFT0C() = %f", collision.multNTracksPV(), collision.multFT0A(), collision.multFT0C()); + registry.fill(HIST("hEventCounter"), 2); - registry.fill(HIST("hEventCounter"), 1); + event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.selection_raw(), collision.rct_raw(), bc.timestamp(), + collision.posZ(), + collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); - event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), - collision.posX(), collision.posY(), collision.posZ(), - collision.numContrib(), collision.trackOccupancyInTimeRange()); + eventXY(collision.posX(), collision.posY()); // eventcov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); - event_mult(collision.multFT0A(), collision.multFT0C(), collision.multTPC(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); + 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, 105.f); + 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, - 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()); + 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, 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, - 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()); - 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; - float q4xft0m = 999.f, q4yft0m = 999.f, q4xft0a = 999.f, q4yft0a = 999.f, q4xft0c = 999.f, q4yft0c = 999.f, q4xbpos = 999.f, q4ybpos = 999.f, q4xbneg = 999.f, q4ybneg = 999.f, q4xbtot = 999.f, q4ybtot = 999.f; - - if (collision.qvecFT0CReVec().size() >= 3) { // harmonics 2,3,4 - 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]; - q4xft0m = collision.qvecFT0MReVec()[2], q4xft0a = collision.qvecFT0AReVec()[2], q4xft0c = collision.qvecFT0CReVec()[2], q4xbpos = collision.qvecBPosReVec()[2], q4xbneg = collision.qvecBNegReVec()[2], q4xbtot = collision.qvecBTotReVec()[2]; - q4yft0m = collision.qvecFT0MImVec()[2], q4yft0a = collision.qvecFT0AImVec()[2], q4yft0c = collision.qvecFT0CImVec()[2], q4ybpos = collision.qvecBPosImVec()[2], q4ybneg = collision.qvecBNegImVec()[2], q4ybtot = collision.qvecBTotImVec()[2]; - } else 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]; + 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, 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, q2xfv0a = 999.f, q2yfv0a = 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, q3xfv0a = 999.f, q3yfv0a = 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], q2xfv0a = collision.qvecFV0AReVec()[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], q2yfv0a = collision.qvecFV0AImVec()[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], q3xfv0a = collision.qvecFV0AReVec()[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], q3yfv0a = collision.qvecFV0AImVec()[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]; + q2xft0m = collision.qvecFT0MReVec()[0], q2xft0a = collision.qvecFT0AReVec()[0], q2xft0c = collision.qvecFT0CReVec()[0], q2xfv0a = collision.qvecFV0AReVec()[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], q2yfv0a = collision.qvecFV0AImVec()[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, - q4xft0m, q4yft0m, q4xft0a, q4yft0a, q4xft0c, q4yft0c, q4xbpos, q4ybpos, q4xbneg, q4ybneg, q4xbtot, q4ybtot); + q2xft0m, q2yft0m, q2xft0a, q2yft0a, q2xft0c, q2yft0c, q2xfv0a, q2yfv0a, q2xbpos, q2ybpos, q2xbneg, q2ybneg, q2xbtot, q2ybtot, + q3xft0m, q3yft0m, q3xft0a, q3yft0a, q3xft0c, q3yft0c, q3xfv0a, q3yfv0a, q3xbpos, q3ybpos, q3xbneg, q3ybneg, q3xbtot, q3ybtot); } else { - event_cent(105.f, 105.f, 105.f, 105.f); + 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, - 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, 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 + } // end of skimEvent + + //---------- for data ---------- void processEvent(MyCollisions const& collisions, MyBCs const& bcs) { - skimEvent(collisions, 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); + 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); + 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, aod::EMSWTriggerInfosTMP const& emswtinfostmp, aod::EMSWTriggerATCountersTMP const& emswtATcounterstmp, aod::EMSWTriggerTOICountersTMP const& emswtTOIcounterstmp) + { + skimEvent(collisions, bcs); + + for (const auto& info : emswtinfostmp) { + if (mRunNumber != info.runNumber()) { + std::vector scalers; + std::vector selections; + std::copy(info.nScalers().begin(), info.nScalers().end(), std::back_inserter(scalers)); + std::copy(info.nSelections().begin(), info.nSelections().end(), std::back_inserter(selections)); + emswtinfo(info.runNumber(), info.nInspectedTVX(), scalers, selections); + mRunNumber = info.runNumber(); + } + } + for (const auto& counter : emswtATcounterstmp) { + emswtATcounter(counter.isAnalyzed_raw()); + } + for (const auto& counter : emswtTOIcounterstmp) { + emswtTOIcounter(counter.isAnalyzedToI_raw()); + } + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent_SWT, "process event info", false); + + void processEvent_SWT_Cent(MyCollisionsWithSWT_Cent const& collisions, MyBCs const& bcs, aod::EMSWTriggerInfosTMP const& emswtinfostmp, aod::EMSWTriggerATCountersTMP const& emswtATcounterstmp, aod::EMSWTriggerTOICountersTMP const& emswtTOIcounterstmp) + { + skimEvent(collisions, bcs); + + for (const auto& info : emswtinfostmp) { + if (mRunNumber != info.runNumber()) { + std::vector scalers; + std::vector selections; + std::copy(info.nScalers().begin(), info.nScalers().end(), std::back_inserter(scalers)); + std::copy(info.nSelections().begin(), info.nSelections().end(), std::back_inserter(selections)); + emswtinfo(info.runNumber(), info.nInspectedTVX(), scalers, selections); + mRunNumber = info.runNumber(); + } + } + for (const auto& counter : emswtATcounterstmp) { + emswtATcounter(counter.isAnalyzed_raw()); + } + for (const auto& counter : emswtTOIcounterstmp) { + emswtTOIcounter(counter.isAnalyzedToI_raw()); + } + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent_SWT_Cent, "process event info", false); + + void processEvent_SWT_Cent_Qvec(MyCollisionsWithSWT_Cent_Qvec const& collisions, MyBCs const& bcs, aod::EMSWTriggerInfosTMP const& emswtinfostmp, aod::EMSWTriggerATCountersTMP const& emswtATcounterstmp, aod::EMSWTriggerTOICountersTMP const& emswtTOIcounterstmp) + { + skimEvent(collisions, bcs); + + for (const auto& info : emswtinfostmp) { + if (mRunNumber != info.runNumber()) { + std::vector scalers; + std::vector selections; + std::copy(info.nScalers().begin(), info.nScalers().end(), std::back_inserter(scalers)); + std::copy(info.nSelections().begin(), info.nSelections().end(), std::back_inserter(selections)); + emswtinfo(info.runNumber(), info.nInspectedTVX(), scalers, selections); + mRunNumber = info.runNumber(); + } + } + for (const auto& counter : emswtATcounterstmp) { + emswtATcounter(counter.isAnalyzed_raw()); + } + for (const auto& counter : emswtTOIcounterstmp) { + emswtTOIcounter(counter.isAnalyzedToI_raw()); + } + } + PROCESS_SWITCH(CreateEMEventDilepton, processEvent_SWT_Cent_Qvec, "process event info", false); + + //---------- for MC ---------- + void processEventMC(MyCollisionsMC const& collisions, MyBCs const& bcs) { - skimEvent(collisions, 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); + 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); + skimEvent(collisions, bcs); } PROCESS_SWITCH(CreateEMEventDilepton, processEventMC_Cent_Qvec, "process event info", false); @@ -292,24 +320,27 @@ struct AssociateDileptonToEMEvent { Produces v0kfeventid; Produces prmeleventid; Produces prmmueventid; + Produces prmtrackeventid; Preslice perCollision_pcm = aod::v0photonkf::collisionId; PresliceUnsorted perCollision_el = aod::emprimaryelectron::collisionId; PresliceUnsorted perCollision_mu = aod::emprimarymuon::collisionId; + Preslice perCollision_track = aod::emprimarytrack::collisionId; + // Preslice perCollision_track = aod::track::collisionId; void init(o2::framework::InitContext&) {} template void fillEventId(TCollisions const& collisions, TLeptons const& leptons, TEventIds& eventIds, TPreslice const& perCollision) { - for (auto& collision : collisions) { + 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 + } // end of collision loop } // This struct is for both data and MC. @@ -330,177 +361,24 @@ struct AssociateDileptonToEMEvent { 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); -}; -struct EMEventPropertyTask { - SliceCache cache; - Preslice perCollision = aod::track::collisionId; - using Run3Tracks = soa::Join; - Zorro zorro; - - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; - Configurable enable_swt{"enable_swt", false, "flag to process skimmed data (swt triggered)"}; - Configurable cfg_swt_names{"cfg_swt_names", "", "comma-separated software trigger names"}; - Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; - - Produces evprop; - struct : ConfigurableGroup { - std::string prefix = "spherocity_cutgroup"; - Configurable require_isPVContributor{"require_isPVContributor", false, "require tracks to be PV contributors"}; - Configurable min_ntrack{"min_ntrack", 3, "min. number of tracks"}; - Configurable min_pt{"min_pt", 0.15, "min. pT of track in GeV/c"}; - Configurable min_eta{"min_eta", -0.8, "min. eta of track"}; - Configurable max_eta{"max_eta", +0.8, "max. eta of track"}; - Configurable max_dcaxy{"max_dcaxy", 2.4, "max. DCAxy of track in cm"}; - Configurable max_dcaz{"max_dcaz", 3.2, "max. DCAz of track in cm"}; - Configurable min_ncluster_tpc{"min_ncluster_tpc", 50, "min. number of TPC clusters"}; - Configurable max_chi2tpc{"max_chi2tpc", 4.0, "max. chi2/ncls TPC"}; - } spherocity_cuts; - - HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - void init(InitContext& initContext) - { - getTaskOptionValue(initContext, "create-emevent-dilepton", "applyEveSel_at_skimming", applyEveSel_at_skimming.value, true); // for EM users. - getTaskOptionValue(initContext, "create-emevent-dilepton", "enable_swt", enable_swt.value, true); // for EM users. - getTaskOptionValue(initContext, "create-emevent-dilepton", "cfg_swt_names", cfg_swt_names.value, true); // for EM users. - - if (fillQAHistogram) { - fRegistry.add("Spherocity/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{200, 0.0f, 10}}, false); - fRegistry.add("Spherocity/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {40, -1.0f, 1.0f}}, false); - fRegistry.add("Spherocity/hSpherocity_ptweighted", "spherocity;Number of used tracks;spherocity", kTH2F, {{101, -0.5, 100.5}, {100, 0.0f, 1}}, false); - fRegistry.add("Spherocity/hSpherocity_ptunweighted", "spherocity;Number of used tracks;spherocity", kTH2F, {{101, -0.5, 100.5}, {100, 0.0f, 1}}, false); - } - } - - Service ccdb; - int mRunNumber = 0; - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + void processChargedTrack(aod::EMEvents const& collisions, aod::EMPrimaryTracks const& tracks) + // void processChargedTrack(aod::EMEvents const& collisions, aod::EMPrimaryTrackEMEventIdsTMP const& tracks) { - if (mRunNumber == bc.runNumber()) { - return; - } - if (enable_swt) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); - } - mRunNumber = bc.runNumber(); + fillEventId(collisions, tracks, prmtrackeventid, perCollision_track); } - template - int getSpherocity(TTracks const& tracks, float& spherocity_ptweighted, float& spherocity_ptunweighted) - { - // Reference for spherocity : https://arxiv.org/pdf/1905.07208, https://arxiv.org/abs/2310.20406, https://arxiv.org/abs/1205.3963 - int used_ntrack_spherocity = 0; - float sum_pt = 0.f, sum_ntrack = 0.f; - - for (auto const& track : tracks) { - if (spherocity_cuts.require_isPVContributor && !track.isPVContributor()) { - continue; - } - if (track.tpcNClsFound() < spherocity_cuts.min_ncluster_tpc) { - continue; - } - - sum_pt += track.pt(); - sum_ntrack += 1.f; - - if (fillQAHistogram) { - fRegistry.fill(HIST("Spherocity/hPt"), track.pt()); - fRegistry.fill(HIST("Spherocity/hEtaPhi"), track.phi(), track.eta()); - } - used_ntrack_spherocity++; - } // end of track loop per collision - - float tempSph = 1.f, tempSph_pt1 = 1.f; - for (int i = 0; i < 360 / 0.1; i++) { - float nx = std::cos(M_PI / 180.f * i * 0.1); - float ny = std::sin(M_PI / 180.f * i * 0.1); - float sum_crossprod = 0.f, sum_crossprod_pt1 = 0.f; - for (auto const& track : tracks) { - if (spherocity_cuts.require_isPVContributor && !track.isPVContributor()) { - continue; - } - if (track.tpcNClsFound() < spherocity_cuts.min_ncluster_tpc) { - continue; - } - float px = track.px(); - float py = track.py(); - sum_crossprod += abs(px * ny - py * nx); - sum_crossprod_pt1 += abs(std::cos(track.phi()) * ny - std::sin(track.phi()) * nx); - } - float sph = std::pow(sum_crossprod / sum_pt, 2); - float sph_pt1 = std::pow(sum_crossprod_pt1 / sum_ntrack, 2); - if (sph < tempSph) { - tempSph = sph; - } - if (sph_pt1 < tempSph_pt1) { - tempSph_pt1 = sph_pt1; - } - } // end of track loop per collision - spherocity_ptweighted = std::pow(M_PI_2, 2) * tempSph; - spherocity_ptunweighted = std::pow(M_PI_2, 2) * tempSph_pt1; - if (used_ntrack_spherocity < spherocity_cuts.min_ntrack) { - spherocity_ptweighted = -1.f; - spherocity_ptunweighted = -1.f; - } - return used_ntrack_spherocity; - } - - Partition tracks_for_spherocity = spherocity_cuts.min_pt < aod::track::pt && spherocity_cuts.min_eta < o2::aod::track::eta && o2::aod::track::eta < spherocity_cuts.max_eta && nabs(o2::aod::track::dcaXY) < spherocity_cuts.max_dcaxy && nabs(o2::aod::track::dcaZ) < spherocity_cuts.max_dcaz && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC) == true && o2::aod::track::tpcChi2NCl < spherocity_cuts.max_chi2tpc; // ITS-TPC matched tracks - - void processProp(soa::Join const& collisions, Run3Tracks const&, aod::BCsWithTimestamps const&) - { - for (auto& collision : collisions) { - - auto bc = collision.template foundBC_as(); - initCCDB(bc); - - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { - continue; - } - if (enable_swt && !zorro.isSelected(bc.globalBC())) { - continue; - } - - auto tracks_for_spherocity_per_collision = tracks_for_spherocity->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - float spherocity_ptweighted = -1.f, spherocity_ptunweighted = -1.f; - int ntrack = getSpherocity(tracks_for_spherocity_per_collision, spherocity_ptweighted, spherocity_ptunweighted); - if (fillQAHistogram) { - fRegistry.fill(HIST("Spherocity/hSpherocity_ptweighted"), ntrack, spherocity_ptweighted); - fRegistry.fill(HIST("Spherocity/hSpherocity_ptunweighted"), ntrack, spherocity_ptunweighted); - } - evprop(spherocity_ptweighted, spherocity_ptunweighted, ntrack); - } // end of collision loop - } - PROCESS_SWITCH(EMEventPropertyTask, processProp, "process event property", true); - - void processDummy(soa::Join const& collisions, aod::BCsWithTimestamps const&) - { - for (auto& collision : collisions) { - auto bc = collision.template foundBC_as(); - initCCDB(bc); + void processDummy(aod::EMEvents const&) {} - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { - continue; - } - if (enable_swt && !zorro.isSelected(bc.globalBC())) { - continue; - } - evprop(-1.f, -1.f, 0); - } // end of collision loop - } - PROCESS_SWITCH(EMEventPropertyTask, processDummy, "process dummy", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent, processPCM, "process indexing for PCM", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent, processElectron, "process indexing for electrons", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent, processFwdMuon, "process indexing for forward muons", false); + PROCESS_SWITCH(AssociateDileptonToEMEvent, processChargedTrack, "process indexing for charged tracks", 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"}), - adaptAnalysisTask(cfgc, TaskName{"emevent-property"}), }; } 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/dielectronProducer.cxx b/PWGEM/Dilepton/TableProducer/dielectronProducer.cxx new file mode 100644 index 00000000000..ed9b5047afc --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/dielectronProducer.cxx @@ -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. +// +// ======================== +// +// This code is for dielectron analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/Core/DileptonProducer.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask>(cfgc, TaskName{"dielectron-producer"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/dimuonProducer.cxx b/PWGEM/Dilepton/TableProducer/dimuonProducer.cxx new file mode 100644 index 00000000000..32cd1bafa72 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/dimuonProducer.cxx @@ -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. +// +// ======================== +// +// This code is for dimuon analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/Core/DileptonProducer.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask>(cfgc, TaskName{"dimuon-producer"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/eventSelection.cxx b/PWGEM/Dilepton/TableProducer/eventSelection.cxx new file mode 100644 index 00000000000..89acb23000c --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/eventSelection.cxx @@ -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. +// +// ======================== +// +// 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_hadronPID, 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"}; + + Configurable cfgRequireTVXinEMC{"cfgRequireTVXinEMC", false, "require kTVXinEMC (only for EMC analyses)"}; + + 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 (cfgRequireTVXinEMC && !collision.alias_bit(triggerAliases::kTVXinEMC)) { + 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/filterEoI.cxx b/PWGEM/Dilepton/TableProducer/filterEoI.cxx new file mode 100644 index 00000000000..2300cbfb458 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/filterEoI.cxx @@ -0,0 +1,181 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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, + kPCM = 0x4, + kElectronFromDalitz = 0x8, + }; + Produces emeoi; + Configurable inheritFromOtherTask{"inheritFromOtherTask", true, "Flag to iherit all common configurables from skimmerPrimaryElectron or skimmerPrimaryMuon"}; + Configurable minNelectron{"minNelectron", -1, "min number of electron candidates per collision"}; + Configurable minNmuon{"minNmuon", -1, "min number of muon candidates per collision"}; + + HistogramRegistry fRegistry{"output"}; + void init(o2::framework::InitContext& initContext) + { + if (inheritFromOtherTask.value) { // Inheriting from other task + getTaskOptionValue(initContext, "skimmer-primary-electron", "minNelectron", minNelectron.value, true); + getTaskOptionValue(initContext, "skimmer-primary-muon", "minNmuon", minNmuon.value, true); + } + + LOGF(info, "minNelectron = %d", minNelectron.value); + LOGF(info, "minNmuon = %d", minNmuon.value); + + auto hEventCounter = fRegistry.add("hEventCounter", "hEventCounter", kTH1D, {{8, 0.5f, 8.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 v0"); + hEventCounter->GetXaxis()->SetBinLabel(5, "event with electron or forward muon"); + hEventCounter->GetXaxis()->SetBinLabel(6, "event with electron and forward muon"); + hEventCounter->GetXaxis()->SetBinLabel(7, "event with electron or forward muon or v0"); + hEventCounter->GetXaxis()->SetBinLabel(8, "event with v0 or electrons from dalitz"); + } + + SliceCache cache; + Preslice perCollision_el = aod::emprimaryelectron::collisionId; + Preslice perCollision_mu = aod::emprimarymuon::collisionId; + Preslice perCollision_v0 = aod::v0photonkf::collisionId; + Preslice perCollision_elda = aod::emprimaryelectron::collisionId; + + template + void selectEoI(TCollisions const& collisions, TElectrons const& electrons, TMuons const& muons, TV0s const& v0s, TElectronsDA const& electronsda) + { + for (const auto& collision : collisions) { + bool does_electron_exist = false; + bool does_fwdmuon_exist = false; + bool does_pcm_exist = false; + bool does_electronda_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() >= minNelectron) { + 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() >= minNmuon) { + does_fwdmuon_exist = true; + fRegistry.fill(HIST("hEventCounter"), 3); + } + } + if constexpr (static_cast(system & kPCM)) { + auto v0s_coll = v0s.sliceBy(perCollision_v0, collision.globalIndex()); + if (v0s_coll.size() >= 1) { + does_pcm_exist = true; + fRegistry.fill(HIST("hEventCounter"), 4); + } + } + if constexpr (static_cast(system & kElectronFromDalitz)) { + auto electronsda_coll = electronsda.sliceBy(perCollision_elda, collision.globalIndex()); + if (electronsda_coll.size() >= 2) { + does_electronda_exist = true; + } + } + + if (does_electron_exist || does_fwdmuon_exist) { + fRegistry.fill(HIST("hEventCounter"), 5); + } + if (does_electron_exist && does_fwdmuon_exist) { + fRegistry.fill(HIST("hEventCounter"), 6); + } + if (does_electron_exist || does_fwdmuon_exist || does_pcm_exist) { + fRegistry.fill(HIST("hEventCounter"), 7); + } + if (does_pcm_exist || does_electronda_exist) { + fRegistry.fill(HIST("hEventCounter"), 8); + } + + emeoi(does_electron_exist || does_fwdmuon_exist || does_pcm_exist || does_electronda_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, nullptr, nullptr); + } + + void process_FwdMuon(aod::Collisions const& collisions, aod::EMPrimaryMuons const& muons) + { + const uint8_t sysflag = kFwdMuon; + selectEoI(collisions, nullptr, muons, nullptr, nullptr); + } + + 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, nullptr, nullptr); + } + + void process_PCM(aod::Collisions const& collisions, aod::V0PhotonsKF const& v0s) + { + const uint8_t sysflag = kPCM; + selectEoI(collisions, nullptr, nullptr, v0s, nullptr); + } + + void process_Electron_FwdMuon_PCM(aod::Collisions const& collisions, aod::EMPrimaryElectrons const& electrons, aod::EMPrimaryMuons const& muons, aod::V0PhotonsKF const& v0s) + { + const uint8_t sysflag = kElectron | kFwdMuon | kPCM; + selectEoI(collisions, electrons, muons, v0s, nullptr); + } + + void process_PCM_ElectronFromDalitz(aod::Collisions const& collisions, aod::V0PhotonsKF const& v0s, aod::EMPrimaryElectronsFromDalitz const& electronsda) + { + const uint8_t sysflag = kPCM | kElectronFromDalitz; + selectEoI(collisions, nullptr, nullptr, v0s, electronsda); + } + + 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_PCM, "create filter bit for PCM", false); + PROCESS_SWITCH(filterEoI, process_Electron_FwdMuon, "create filter bit for Electron, FwdMuon", false); + PROCESS_SWITCH(filterEoI, process_Electron_FwdMuon_PCM, "create filter bit for Electron, FwdMuon, PCM", false); + PROCESS_SWITCH(filterEoI, process_PCM_ElectronFromDalitz, "create filter bit for PCM, ElectronFromDalitz", 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..b37ae9d8dc6 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx @@ -0,0 +1,181 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Common/Core/TableHelper.h" +#include "Common/Core/Zorro.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct skimmerOTS { + Produces swtinfo_tmp; // Join aod::Collision later. + Produces swtbit_tmp; + Produces swtcounterAT_tmp; + Produces swtcounterTOI_tmp; + + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfg_swt_names{"cfg_swt_names", "fLMeeIMR,fLMeeHMR", "comma-separated software trigger names"}; // !trigger names have to be pre-registered in dileptonTable.h for bit operation! + o2::framework::Configurable ccdbPathSoftwareTrigger{"ccdbPathSoftwareTrigger", "EventFiltering/Zorro/", "ccdb path for ZORRO objects"}; + Configurable bcMarginForSoftwareTrigger{"bcMarginForSoftwareTrigger", 100, "Number of BCs of margin for software triggers"}; + + std::vector swt_names; + int mRunNumber; + Service ccdb; + Zorro zorro; + std::vector mTOIidx; + uint64_t mNinspectedTVX{0}; + std::vector mScalers; + std::vector mSelections; + std::vector mTOICounters; + std::vector mATCounters; + + HistogramRegistry registry{"registry"}; + + void init(o2::framework::InitContext&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + mRunNumber = 0; + + 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); + } + + int nbin = swt_names.size(); + auto hCollisionCounter = registry.add("hCollisionCounter", "hCollisionCounter;;Number of collisions", kTH1D, {{nbin + 1, 0.5f, nbin + 1 + 0.5f}}); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + for (size_t idx = 0; idx < swt_names.size(); idx++) { + hCollisionCounter->GetXaxis()->SetBinLabel(idx + 2, swt_names[idx].data()); + } + + const int ntrg = static_cast(o2::aod::pwgem::dilepton::swt::swtAliases::kNaliases); + mNinspectedTVX = 0; + mScalers.resize(ntrg); + mSelections.resize(ntrg); + mTOICounters.resize(ntrg); + mATCounters.resize(ntrg); + for (int idx = 0; idx < ntrg; idx++) { + mTOICounters[idx] = 0; + mATCounters[idx] = 0; + mScalers[idx] = 0; + mSelections[idx] = 0; + } + } + + ~skimmerOTS() + { + swt_names.clear(); + swt_names.shrink_to_fit(); + mTOICounters.clear(); + mTOICounters.shrink_to_fit(); + mATCounters.clear(); + mATCounters.shrink_to_fit(); + } + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + zorro.setCCDBpath(ccdbPathSoftwareTrigger); + zorro.setBCtolerance(bcMarginForSoftwareTrigger); // this does nothing. + mTOIidx = zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); + zorro.populateHistRegistry(registry, bc.runNumber()); + + mNinspectedTVX = zorro.getInspectedTVX()->GetBinContent(1); + LOGF(info, "total inspected TVX events = %llu in run number %d", mNinspectedTVX, bc.runNumber()); + + for (size_t idx = 0; idx < mTOIidx.size(); idx++) { + auto swtname = swt_names[idx]; + int emswtId = o2::aod::pwgem::dilepton::swt::aliasLabels.at(swtname); + mScalers[emswtId] = zorro.getScalers()->GetBinContent(mTOIidx[idx] + 2); + mSelections[emswtId] = zorro.getSelections()->GetBinContent(mTOIidx[idx] + 2); + LOGF(info, "Trigger of Interest : index = %d in Zorro, %d in EM, scaler = %llu, selection = %llu", mTOIidx[idx], emswtId, mScalers[emswtId], mSelections[emswtId]); + } + swtinfo_tmp(bc.runNumber(), mNinspectedTVX, mScalers, mSelections); + mRunNumber = bc.runNumber(); + } + + void process(aod::Collisions const& collisions, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); // don't use foundBC. + initCCDB(bc); + + uint16_t trigger_bitmap = 0; + // uint16_t analyzed_bitmap = 0; + // uint16_t analyzedToI_bitmap = 0; + registry.fill(HIST("hCollisionCounter"), 1); // all + + if (zorro.isSelected(bc.globalBC(), bcMarginForSoftwareTrigger)) { // triggered event + auto swt_bitset = zorro.getLastResult(); // this has to be called after zorro::isSelected, or simply call zorro.fetch + auto TOIcounters = zorro.getTOIcounters(); // this has to be called after zorro::isSelected, or simply call zorro.fetch + auto ATcounters = zorro.getATcounters(); // 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]; + int emswtId = o2::aod::pwgem::dilepton::swt::aliasLabels.at(swtname); + trigger_bitmap |= BIT(emswtId); + // 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("hCollisionCounter"), idx + 2); // fired trigger + + // LOGF(info, "ATcounters[mTOIidx[idx]] = %d, TOIcounters[idx] = %d", ATcounters[mTOIidx[idx]], TOIcounters[idx]); + + while (ATcounters[mTOIidx[idx]] > mATCounters[emswtId]) { + mATCounters[emswtId]++; + swtcounterAT_tmp(BIT(emswtId)); + } + + while (TOIcounters[idx] > mTOICounters[emswtId]) { + mTOICounters[emswtId]++; // always incremented by 1 in zorro!! + swtcounterTOI_tmp(BIT(emswtId)); + } + + // LOGF(info, "collision.globalIndex() = %d, bc.globalBC() = %llu, mTOICounters[%d] = %d, mATcounters[%d] = %d", collision.globalIndex(), bc.globalBC(), emswtId, mTOICounters[emswtId], emswtId, mATCounters[emswtId]); + } + } // end of TOI loop + } + swtbit_tmp(trigger_bitmap); + } // end of collision loop + } // end of process +}; +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 index a04c609d334..f28cf0b8755 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectron.cxx @@ -12,24 +12,36 @@ /// \brief write relevant information about primary electrons. /// \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 "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/MlResponseO2Track.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/Core/TableHelper.h" #include "Common/Core/trackUtilities.h" -#include "CommonConstants/PhysicsConstants.h" #include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/Core/TableHelper.h" -#include "EventFiltering/Zorro.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Tools/ML/MlResponse.h" -#include "PWGEM/Dilepton/DataModel/dileptonTables.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::soa; @@ -37,22 +49,19 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::constants::physics; -using MyTracks = soa::Join; +using MyCollisions = soa::Join; +using MyCollisionsWithSWT = soa::Join; + +using MyTracks = soa::Join; using MyTrack = MyTracks::iterator; -using MyTracksMC = soa::Join; +using MyTracksMC = soa::Join; using MyTrackMC = MyTracksMC::iterator; struct skimmerPrimaryElectron { - enum class EM_EEPairType : int { - kULS = 0, - kLSpp = +1, - kLSmm = -1, - }; - SliceCache cache; - Preslice perCol = o2::aod::track::collisionId; + Preslice perCol = o2::aod::track::collisionId; Produces emprimaryelectrons; Produces emprimaryelectronscov; @@ -60,48 +69,70 @@ struct skimmerPrimaryElectron { 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"}; - Configurable enable_swt{"enable_swt", false, "flag to process skimmed data (swt triggered)"}; - Configurable cfg_swt_names{"cfg_swt_names", "", "comma-separated software trigger names"}; - Configurable inherit_from_emevent_dilepton{"inherit_from_emevent_dilepton", false, "flag to inherit task options from emevent-dilepton"}; // Operation and minimisation criteria Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; 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 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_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 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.8, "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 minpt{"minpt", 0.15, "min pt for ITS-TPC track"}; + Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 1.0, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 1.0, "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", 0.0, "max. TPC n sigma for kaon exclusion"}; - Configurable minTPCNsigmaKa{"minTPCNsigmaKa", 0.0, "min. TPC n sigma for kaon exclusion"}; - Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", 0.0, "max. TPC n sigma for proton exclusion"}; - Configurable minTPCNsigmaPr{"minTPCNsigmaPr", 0.0, "min. TPC n sigma for proton exclusion"}; + 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 min_pin_for_pion_rejection{"min_pin_for_pion_rejection", 0.0, "pion rejection is applied above this pin"}; // this is used only in TOFreq + Configurable max_pin_for_pion_rejection{"max_pin_for_pion_rejection", 0.5, "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 includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; + Configurable maxpt_itssa{"maxpt_itssa", 0.15, "max pt for ITSsa track"}; + Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; + Configurable storeOnlyTrueElectronMC{"storeOnlyTrueElectronMC", false, "Flag to store only true electron in MC"}; + Configurable minNelectron{"minNelectron", 0, "min number of electron candidates per collision"}; + + // configuration for PID ML + Configurable usePIDML{"usePIDML", false, "Flag to use 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)"}; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + o2::analysis::MlResponseO2Track mlResponseSingleTrack; - std::pair> itsRequirement = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. - - Zorro zorro; 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::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; + o2::ccdb::CcdbApi ccdbApi; - void init(InitContext& initContext) + void init(InitContext&) { mRunNumber = 0; d_bz = 0; @@ -110,46 +141,70 @@ struct skimmerPrimaryElectron { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); - - if (inherit_from_emevent_dilepton) { - getTaskOptionValue(initContext, "create-emevent-dilepton", "applyEveSel_at_skimming", applyEveSel_at_skimming.value, true); // for EM users. - getTaskOptionValue(initContext, "create-emevent-dilepton", "enable_swt", enable_swt.value, true); // for EM users. - getTaskOptionValue(initContext, "create-emevent-dilepton", "cfg_swt_names", cfg_swt_names.value, true); // for EM users. - } + ccdbApi.init(ccdburl); 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/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{4000, -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/hDCAxy_Pt", "DCA_{xy} vs. pT;p_{T} (GeV/c);DCA_{xy} (cm)", kTH2F, {{1000, 0, 10}, {200, -1, 1}}, false); - fRegistry.add("Track/hDCAz_Pt", "DCA_{z} vs. pT;p_{T} (GeV/c);DCA_{z} (cm)", kTH2F, {{1000, 0, 10}, {200, -1, 1}}, 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/hTPCdEdxMC", "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/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);#beta", kTH2F, {{1000, 0, 10}, {1000, 0.8, 1.8}}, 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/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; on ITS #times cos(#lambda)", kTH1F, {{32, 0, 16}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hMeanClusterSizeITSib", "mean cluster size ITSib;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hMeanClusterSizeITSob", "mean cluster size ITSob;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hProbElBDT", "probability to be e from BDT;p_{in} (GeV/c);BDT score;", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/hNe", "electron counts;N_{e} per collision", kTH1F, {{51, -0.5, 50.5}}, false); } + + if (usePIDML) { + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + const std::vector labelsClasses = {"Background", "Signal"}; + const uint32_t nBinsMl = 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] = 0.0; + cutsMlArr[i][1] = cutsMl.value[i]; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(onnxFileNames.value, ccdbApi, onnxPathsCCDB.value, timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(nameBinningFeature); + mlResponseSingleTrack.init(enableOptimizations.value); + } // end of PID ML } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -158,18 +213,24 @@ struct skimmerPrimaryElectron { return; } - if (enable_swt) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); + // 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 (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; } @@ -177,10 +238,13 @@ struct skimmerPrimaryElectron { auto run3grp_timestamp = bc.timestamp(); o2::parameters::GRPObject* grpo = 0x0; o2::parameters::GRPMagField* grpmag = 0x0; - if (!skipGRPOquery) + 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"; @@ -190,6 +254,9 @@ struct skimmerPrimaryElectron { 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"; @@ -204,93 +271,167 @@ struct skimmerPrimaryElectron { if (!track.has_mcParticle()) { return false; } + if (storeOnlyTrueElectronMC) { + const auto& mcParticle = track.template mcParticle_as(); + if (std::abs(mcParticle.pdgCode()) != 11) { + return false; + } + } } - if (track.tpcChi2NCl() > maxchi2tpc) { + if (requireTOF && !(track.hasTOF() && std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl)) { return false; } - if (track.itsChi2NCl() > maxchi2its) { + if (!track.hasITS()) { return false; } - if (!track.hasITS() || !track.hasTPC()) { + if (track.itsChi2NCl() < 0.f || maxchi2its < track.itsChi2NCl()) { + return false; + } + if (track.itsNCls() < min_ncluster_its) { return false; } - if (track.itsNCls() < minitsncls) { + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { return false; } - auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - if (hits < itsRequirement.first) { + if (!includeITSsa && (!track.hasITS() || !track.hasTPC())) { 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++; + if (track.hasTPC()) { + if (track.tpcChi2NCl() < 0.f || maxchi2tpc < track.tpcChi2NCl()) { + 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; } - 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) { + + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { return false; } + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); - if (track.tpcNClsFound() < min_ncluster_tpc) { + if (std::fabs(dcaXY) > dca_xy_max || std::fabs(dcaZ) > dca_z_max) { return false; } - if (track.tpcNClsCrossedRows() < mincrossedrows) { + float dca_3d = 999.f; + float det = trackParCov.getSigmaY2() * trackParCov.getSigmaZ2() - trackParCov.getSigmaZY() * trackParCov.getSigmaZY(); + if (det < 0) { + dca_3d = 999.f; + } else { + float chi2 = (dcaXY * dcaXY * trackParCov.getSigmaZ2() + dcaZ * dcaZ * trackParCov.getSigmaY2() - 2. * dcaXY * dcaZ * trackParCov.getSigmaZY()) / det; + dca_3d = std::sqrt(std::fabs(chi2) / 2.); + } + if (dca_3d > dca_3d_sigma_max) { return false; } - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + if (trackParCov.getPt() < minpt || std::fabs(trackParCov.getEta()) > maxeta) { return false; } - if ((0.0 < track.beta() && track.beta() < 0.95) || 1.05 < track.beta()) { + if ((track.hasITS() && !track.hasTPC() && !track.hasTOF() && !track.hasTRD()) && maxpt_itssa < trackParCov.getPt()) { 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]; + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } - if (abs(dcaXY) > dca_xy_max || abs(dcaZ) > dca_z_max) { + if (maxMeanITSClusterSize < static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(trackParCov.getTgl()))) { return false; } - if (track_par_cov_recalc.getPt() < minpt || abs(track_par_cov_recalc.getEta()) > maxeta) { - return false; + return true; + } + + template + bool isElectron(TCollision const& collision, TTrack const& track, float& probaEl) + { + probaEl = 1.f; + if (includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) { + return true; } - 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; + if (usePIDML) { + if (!isElectron_TOFif(track)) { + return false; + } + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision); + float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision); + + // std::vector outputs = {}; + // bool isSelected = mlResponseSingleTrack.isSelectedMl(inputFeatures, binningFeature, outputs); // 0: hadron, 1:electron + // probaEl = outputs[1]; + // outputs.clear(); + // outputs.shrink_to_fit(); + + // std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision); + // float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision); + + int pbin = lower_bound(binsMl.value.begin(), binsMl.value.end(), binningFeature) - binsMl.value.begin() - 1; + if (pbin < 0) { + pbin = 0; + } else if (static_cast(binsMl.value.size()) - 2 < pbin) { + pbin = static_cast(binsMl.value.size()) - 2; + } + // LOGF(info, "track.tpcInnerParam() = %f (GeV/c), pbin = %d", track.tpcInnerParam(), pbin); + + probaEl = mlResponseSingleTrack.getModelOutput(inputFeatures, pbin)[1]; // 0: hadron, 1:electron + return probaEl > cutsMl.value[pbin]; + // return isSelected; } 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 isElectron_TPChadrej(track) || isElectron_TOFreq(track); } - - return true; } template - bool isElectron(TTrack const& track) + bool isElectron_TOFif(TTrack const& track) { - return isElectron_TPChadrej(track) || isElectron_TOFreq(track); + bool is_EL_TPC = minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl; + bool is_EL_TOF = track.hasTOF() ? (std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl) : true; // TOFif + return is_EL_TPC && is_EL_TOF; } template @@ -299,7 +440,7 @@ struct skimmerPrimaryElectron { if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { return false; } - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi) { + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { return false; } if (minTPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < maxTPCNsigmaKa) { @@ -308,7 +449,7 @@ struct skimmerPrimaryElectron { if (minTPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < maxTPCNsigmaPr) { return false; } - if (!(track.beta() < 0.f || (0.96 < track.beta() && track.beta() < 1.04))) { + if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(track.tofNSigmaEl()))) { return false; } return true; @@ -317,256 +458,458 @@ struct skimmerPrimaryElectron { template bool isElectron_TOFreq(TTrack const& track) { - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi) { - return false; - } - if (!(track.beta() < 0.f || (0.96 < track.beta() && track.beta() < 1.04))) { + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && (min_pin_for_pion_rejection < track.tpcInnerParam() && track.tpcInnerParam() < max_pin_for_pion_rejection)) { return false; } - return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && abs(track.tofNSigmaEl()) < maxTOFNsigmaEl; + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(track.tofNSigmaEl()) < maxTOFNsigmaEl; } - template - void fillTrackTable(TCollision const& collision, TTrack const& track) + template + void fillTrackTable(TCollision const& collision, TTrack const& track, const float probaEl) { 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(); + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return; + } + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + float pt_recalc = trackParCov.getPt(); + float eta_recalc = trackParCov.getEta(); + float phi_recalc = trackParCov.getPhi(); + o2::math_utils::bringTo02Pi(phi_recalc); bool isAssociatedToMPC = collision.globalIndex() == track.collisionId(); + float mcTunedTPCSignal = 0.f; + if constexpr (isMC) { + mcTunedTPCSignal = track.mcTunedTPCSignal(); + } emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), - pt_recalc, eta_recalc, phi_recalc, dcaXY, dcaZ, - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), + pt_recalc, eta_recalc, phi_recalc, + dcaXY, dcaZ, trackParCov.getSigmaY2(), trackParCov.getSigmaZY(), trackParCov.getSigmaZ2(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusPID(), 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.itsChi2NCl(), 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); + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), track.tofNSigmaEl(), /*track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(),*/ + track.itsClusterSizes(), + track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), + isAssociatedToMPC, false, probaEl, mcTunedTPCSignal); 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()); + trackParCov.getX(), + trackParCov.getAlpha(), + trackParCov.getY(), + trackParCov.getZ(), + trackParCov.getSnp(), + // trackParCov.getTgl(), + // trackParCov.getSigmaY2(), + // trackParCov.getSigmaZY(), + // trackParCov.getSigmaZ2(), + trackParCov.getSigmaSnpY(), + trackParCov.getSigmaSnpZ(), + trackParCov.getSigmaSnp2(), + trackParCov.getSigmaTglY(), + trackParCov.getSigmaTglZ(), + trackParCov.getSigmaTglSnp(), + trackParCov.getSigmaTgl2(), + trackParCov.getSigma1PtY(), + trackParCov.getSigma1PtZ(), + trackParCov.getSigma1PtSnp(), + trackParCov.getSigma1PtTgl(), + trackParCov.getSigma1Pt2()); stored_trackIds.emplace_back(std::pair{collision.globalIndex(), track.globalIndex()}); if (fillQAHistogram) { - uint32_t itsClusterSizes = track.itsClusterSizes(); + // 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; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); if (cluster_size_per_layer > 0) { nl++; } total_cluster_size += cluster_size_per_layer; } + int total_cluster_size_ib = 0, nl_ib = 0; + for (unsigned int layer = 0; layer < 3; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl_ib++; + } + total_cluster_size_ib += cluster_size_per_layer; + } + + int total_cluster_size_ob = 0, nl_ob = 0; + for (unsigned int layer = 3; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl_ob++; + } + total_cluster_size_ob += 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/hDCAxy_Pt"), pt_recalc, dcaXY); - fRegistry.fill(HIST("Track/hDCAz_Pt"), pt_recalc, dcaZ); - 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/hDCAxyzSigma"), dcaXY / std::sqrt(trackParCov.getSigmaY2()), dcaZ / std::sqrt(trackParCov.getSigmaZ2())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt_recalc, std::sqrt(trackParCov.getSigmaY2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt_recalc, std::sqrt(trackParCov.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/hMeanClusterSizeITS"), 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/hTPCdEdxMC"), track.tpcInnerParam(), mcTunedTPCSignal); fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); - fRegistry.fill(HIST("Track/hTPCNsigmaMu"), track.tpcInnerParam(), track.tpcNSigmaMu()); + // 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/hTOFbeta"), trackParCov.getP(), track.beta()); fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/hTOFNsigmaMu"), track.tpcInnerParam(), track.tofNSigmaMu()); + // 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"), trackParCov.getP(), static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(trackParCov.getTgl()))); + fRegistry.fill(HIST("Track/hMeanClusterSizeITSib"), trackParCov.getP(), static_cast(total_cluster_size_ib) / static_cast(nl_ib) * std::cos(std::atan(trackParCov.getTgl()))); + fRegistry.fill(HIST("Track/hMeanClusterSizeITSob"), trackParCov.getP(), static_cast(total_cluster_size_ob) / static_cast(nl_ob) * std::cos(std::atan(trackParCov.getTgl()))); + fRegistry.fill(HIST("Track/hProbElBDT"), track.tpcInnerParam(), probaEl); } } } + 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 && ((0.96f < o2::aod::pidtofbeta::beta && o2::aod::pidtofbeta::beta < 1.04f) || o2::aod::pidtofbeta::beta < 0.f) && (o2::aod::pidtpc::tpcNSigmaPi < minTPCNsigmaPi || maxTPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi); + Filter trackFilter = o2::aod::track::itsChi2NCl < maxchi2its && 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; + std::map, float> mapProbEl; // map pair(collisionId, trackId) -> probaEl + std::unordered_multimap multiMapTracksPerCollision; // collisionId -> trackIds + // ---------- for data ---------- - void processRec_SA(Join const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) + void processRec_SA(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; + } + + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + float probaEl = 1.0; + if (!checkTrack(collision, track)) { + continue; + } + if (!isElectron(collision, track, probaEl)) { + continue; + } + mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; + multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); + } + } // end of collision loop + + for (const auto& collision : collisions) { + int count_electrons = multiMapTracksPerCollision.count(collision.globalIndex()); + if (fillQAHistogram) { + fRegistry.fill(HIST("Track/hNe"), count_electrons); + } + if (count_electrons >= minNelectron) { + auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_electrons.first; it != range_electrons.second; it++) { + auto track = tracks.rawIteratorAt(it->second); + fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } + } // end of collision loop + + mapProbEl.clear(); + multiMapTracksPerCollision.clear(); + 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) + { + 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(); + float probaEl = 1.0; + if (!checkTrack(collision, track)) { + continue; + } + if (!isElectron(collision, track, probaEl)) { + continue; + } + mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; + multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); + } + } // end of collision loop + + for (const auto& collision : collisions) { + int count_electrons = multiMapTracksPerCollision.count(collision.globalIndex()); + if (fillQAHistogram) { + fRegistry.fill(HIST("Track/hNe"), count_electrons); + } + if (count_electrons >= minNelectron) { + auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_electrons.first; it != range_electrons.second; it++) { + auto track = tracks.rawIteratorAt(it->second); + fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } + } // end of collision loop + + mapProbEl.clear(); + multiMapTracksPerCollision.clear(); + 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) { stored_trackIds.reserve(tracks.size()); - for (auto& collision : collisions) { + for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { continue; } - if (enable_swt && !zorro.isSelected(bc.globalBC())) { + + if (collision.swtaliastmp_raw() == 0) { continue; } auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); - for (auto& track : tracks_per_coll) { - if (!checkTrack(collision, track) || !isElectron(track)) { + for (const auto& track : tracks_per_coll) { + float probaEl = 1.0; + if (!checkTrack(collision, track)) { + continue; + } + if (!isElectron(collision, track, probaEl)) { continue; } - fillTrackTable(collision, track); + mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; + multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); } } // end of collision loop + for (const auto& collision : collisions) { + int count_electrons = multiMapTracksPerCollision.count(collision.globalIndex()); + if (fillQAHistogram) { + fRegistry.fill(HIST("Track/hNe"), count_electrons); + } + if (count_electrons >= minNelectron) { + auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_electrons.first; it != range_electrons.second; it++) { + auto track = tracks.rawIteratorAt(it->second); + fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } + } // end of collision loop + + mapProbEl.clear(); + multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); } - PROCESS_SWITCH(skimmerPrimaryElectron, processRec_SA, "process reconstructed info only", true); // standalone + PROCESS_SWITCH(skimmerPrimaryElectron, processRec_SA_SWT, "process reconstructed info only", false); // standalone with swt - Preslice trackIndicesPerCollision = aod::track_association::collisionId; - void processRec_TTCA(Join const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::TrackAssoc const& trackIndices) + 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) { + for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { continue; } - if (enable_swt && !zorro.isSelected(bc.globalBC())) { + if (collision.swtaliastmp_raw() == 0) { continue; } 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) { + for (const auto& trackId : trackIdsThisCollision) { auto track = trackId.template track_as(); - if (!checkTrack(collision, track) || !isElectron(track)) { + float probaEl = 1.0; + if (!checkTrack(collision, track)) { continue; } - fillTrackTable(collision, track); + if (!isElectron(collision, track, probaEl)) { + continue; + } + mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; + multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); + } + } // end of collision loop + + for (const auto& collision : collisions) { + int count_electrons = multiMapTracksPerCollision.count(collision.globalIndex()); + if (fillQAHistogram) { + fRegistry.fill(HIST("Track/hNe"), count_electrons); + } + if (count_electrons >= minNelectron) { + auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_electrons.first; it != range_electrons.second; it++) { + auto track = tracks.rawIteratorAt(it->second); + fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } } - // posTracks_per_coll.clear(); - // negTracks_per_coll.clear(); - // posTracks_per_coll.shrink_to_fit(); - // negTracks_per_coll.shrink_to_fit(); } // end of collision loop + mapProbEl.clear(); + multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); } - PROCESS_SWITCH(skimmerPrimaryElectron, processRec_TTCA, "process reconstructed info only", false); // with TTCA + 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) + void processMC_SA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::McParticles const&) { stored_trackIds.reserve(tracks.size()); - for (auto& collision : collisions) { + for (const auto& collision : collisions) { if (!collision.has_mcCollision()) { continue; } auto bc = collision.template foundBC_as(); initCCDB(bc); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { continue; } auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); - for (auto& track : tracks_per_coll) { - if (!checkTrack(collision, track) || !isElectron(track)) { + for (const auto& track : tracks_per_coll) { + float probaEl = 1.0; + if (!checkTrack(collision, track)) { continue; } - fillTrackTable(collision, track); + if (!isElectron(collision, track, probaEl)) { + continue; + } + mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; + multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); + } + } // end of collision loop + + for (const auto& collision : collisions) { + int count_electrons = multiMapTracksPerCollision.count(collision.globalIndex()); + if (fillQAHistogram) { + fRegistry.fill(HIST("Track/hNe"), count_electrons); + } + if (count_electrons >= minNelectron) { + auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_electrons.first; it != range_electrons.second; it++) { + auto track = tracks.rawIteratorAt(it->second); + fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } } } // end of collision loop + mapProbEl.clear(); + multiMapTracksPerCollision.clear(); 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&, MyFilteredTracksMC const& tracks, aod::TrackAssoc const& trackIndices) + void processMC_TTCA(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyTracksMC const& tracks, aod::TrackAssoc const& trackIndices, aod::McParticles const&) { stored_trackIds.reserve(tracks.size() * 2); - for (auto& collision : collisions) { + for (const auto& collision : collisions) { if (!collision.has_mcCollision()) { continue; } auto bc = collision.template foundBC_as(); initCCDB(bc); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { continue; } 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)) { + + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + float probaEl = 1.0; + if (!checkTrack(collision, track)) { continue; } - fillTrackTable(collision, track); + if (!isElectron(collision, track, probaEl)) { + continue; + } + mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())] = probaEl; + multiMapTracksPerCollision.insert(std::make_pair(collision.globalIndex(), track.globalIndex())); } - // 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& collision : collisions) { + int count_electrons = multiMapTracksPerCollision.count(collision.globalIndex()); + if (fillQAHistogram) { + fRegistry.fill(HIST("Track/hNe"), count_electrons); + } + if (count_electrons >= minNelectron) { + auto range_electrons = multiMapTracksPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_electrons.first; it != range_electrons.second; it++) { + auto track = tracks.rawIteratorAt(it->second); + fillTrackTable(collision, track, mapProbEl[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } + } // end of collision loop + + mapProbEl.clear(); + multiMapTracksPerCollision.clear(); stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); } @@ -574,49 +917,54 @@ struct skimmerPrimaryElectron { }; 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; + 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 applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; 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 fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; + Configurable max_dcaxy{"max_dcaxy", 1.0, "DCAxy To PV for loose track sample"}; + Configurable max_dcaz{"max_dcaz", 1.0, "DCAz To PV for loose track sample"}; + Configurable minpt{"minpt", 0.1, "min pt for ITS-TPC track"}; Configurable maxeta{"maxeta", 1.2, "eta acceptance for loose track sample"}; - Configurable mincrossedrows{"mincrossedrows", 40, "min crossed rows"}; + 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 minTPCNsigmaEl{"minTPCNsigmaEl", -3.0, "min. TPC n sigma for electron inclusion"}; + Configurable maxchi2its{"maxchi2its", 36.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 includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; + Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; - 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}}}}, - }, - }; + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + const std::vector max_mee_vec{0.02, 0.04, 0.06, 0.08, 0.10, 0.12, 0.14}; 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::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&) { @@ -627,6 +975,22 @@ struct prefilterPrimaryElectron { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + + if (!doprocessDummy && fillQAHistogram) { + 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) @@ -635,14 +999,24 @@ struct prefilterPrimaryElectron { 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 (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; } @@ -654,6 +1028,8 @@ struct prefilterPrimaryElectron { 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"; @@ -663,6 +1039,8 @@ struct prefilterPrimaryElectron { 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"; @@ -672,12 +1050,6 @@ struct prefilterPrimaryElectron { o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - template - bool isITSonlyTrack(TTrack const& track) - { - return track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF(); - } - template bool checkTrack(TCollision const& collision, TTrack const& track) { @@ -687,34 +1059,69 @@ struct prefilterPrimaryElectron { if (track.itsChi2NCl() > maxchi2its) { return false; } + if (track.itsNCls() < min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { + return false; + } + + if (!includeITSsa && (!track.hasITS() || !track.hasTPC())) { + return false; + } if (track.hasTPC()) { 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.tpcChi2NCl() > maxchi2its) { + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + if (track.tpcChi2NCl() > maxchi2tpc) { 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); + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); - if (abs(dcaInfo[0]) < min_dcatopv) { + if (std::fabs(dcaXY) > max_dcaxy || std::fabs(dcaZ) > max_dcaz) { return false; } - if (isITSonlyTrack(track) && track_par_cov_recalc.getPt() > max_pt_itsonly) { + if (trackParCov.getPt() < minpt || std::fabs(trackParCov.getEta()) > maxeta) { return false; } - if (abs(track_par_cov_recalc.getEta()) > maxeta) { + + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + if (maxMeanITSClusterSize < static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(trackParCov.getTgl()))) { return false; } @@ -724,38 +1131,43 @@ struct prefilterPrimaryElectron { 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; + 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({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); - getPxPyPz(track_par_cov_recalc, pVec_recalc); + auto trackParCov = getTrackParCov(pos); + trackParCov.setPID(o2::track::PID::Electron); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + getPxPyPz(trackParCov, 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 v2(trackParCov.getPt(), trackParCov.getEta(), trackParCov.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({collision.posX(), collision.posY(), collision.posZ()}, track_par_cov_recalc, 2.f, matCorr, &dcaInfo); - getPxPyPz(track_par_cov_recalc, pVec_recalc); + auto trackParCov = getTrackParCov(ele); + trackParCov.setPID(o2::track::PID::Electron); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + getPxPyPz(trackParCov, 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 v1(trackParCov.getPt(), trackParCov.getEta(), trackParCov.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); } - fRegistry.fill(HIST("hMvsPhiV_PV"), phiv, mee); - if (mee < slope * phiv + intercept) { return true; } else { @@ -765,8 +1177,7 @@ struct prefilterPrimaryElectron { 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; - 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; + Filter trackFilter = o2::aod::track::itsChi2NCl < maxchi2its && 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; @@ -774,14 +1185,14 @@ struct prefilterPrimaryElectron { Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0); Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0); - void processPrefilter_TTCA(Join const& collisions, aod::BCsWithTimestamps const&, MyTracks const&, aod::EMPrimaryElectrons const& primaryelectrons, aod::TrackAssoc const& trackIndices) + 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 (auto& collision : collisions) { + for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { continue; } @@ -794,12 +1205,15 @@ struct prefilterPrimaryElectron { posTracks_per_coll.reserve(trackIdsThisCollision.size()); negTracks_per_coll.reserve(trackIdsThisCollision.size()); - for (auto& trackId : trackIdsThisCollision) { + for (const auto& trackId : trackIdsThisCollision) { auto track = trackId.template track_as(); if (!checkTrack(collision, track)) { continue; } - + if (fillQAHistogram) { + 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 { @@ -807,37 +1221,165 @@ struct prefilterPrimaryElectron { } } - 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)) { + 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 trackParCov = getTrackParCov(ele); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + continue; + } + getPxPyPz(trackParCov, pVec_recalc); + + for (const auto& empos : positrons_per_coll) { + if (empos.trackId() == ele.globalIndex()) { continue; } - if (empos.trackId() == ele.globalIndex()) { + + ROOT::Math::PtEtaPhiMVector v1(trackParCov.getPt(), trackParCov.getEta(), trackParCov.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); + if (fillQAHistogram) { + 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)) { + if (fillQAHistogram) { + 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_20MeV) + 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 trackParCov = getTrackParCov(pos); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + continue; + } + getPxPyPz(trackParCov, pVec_recalc); + for (const auto& emele : electrons_per_coll) { + if (emele.trackId() == pos.globalIndex()) { continue; } - bool isPC = reconstructPC<-1>(collision, ele, empos); - if (isPC) { - pfb_map[empos.globalIndex()] |= (uint8_t(1) << static_cast(EM_Electron_PF::kElFromPC)); + + ROOT::Math::PtEtaPhiMVector v1(emele.pt(), emele.eta(), emele.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v2(trackParCov.getPt(), trackParCov.getEta(), trackParCov.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); + if (fillQAHistogram) { + 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)) { + if (fillQAHistogram) { + 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_20MeV) + i)); + } } - } // 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 + 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 trackParCov = getTrackParCov(pos); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + continue; + } + getPxPyPz(trackParCov, pVec_recalc); + for (const auto& empos : positrons_per_coll) { + if (empos.trackId() == pos.globalIndex()) { continue; } - if (emele.trackId() == pos.globalIndex()) { + + ROOT::Math::PtEtaPhiMVector v1(empos.pt(), empos.eta(), empos.phi(), o2::constants::physics::MassElectron); // signal track + ROOT::Math::PtEtaPhiMVector v2(trackParCov.getPt(), trackParCov.getEta(), trackParCov.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); + if (fillQAHistogram) { + 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 trackParCov = getTrackParCov(ele); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + continue; + } + getPxPyPz(trackParCov, pVec_recalc); + + for (const auto& emele : electrons_per_coll) { + if (emele.trackId() == ele.globalIndex()) { continue; } - bool isPC = reconstructPC<+1>(collision, emele, pos); - if (isPC) { - pfb_map[emele.globalIndex()] |= (uint8_t(1) << static_cast(EM_Electron_PF::kElFromPC)); + + ROOT::Math::PtEtaPhiMVector v1(trackParCov.getPt(), trackParCov.getEta(), trackParCov.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); + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPhiV"), phiv, v12.M()); + fRegistry.fill(HIST("Pair/before/lsmm/hMvsPt"), v12.M(), v12.Pt()); } - } // end of loose positon loop - } // end of signal electron loop + + } // end of signal electron loop + } // end of loose electron loop posTracks_per_coll.clear(); negTracks_per_coll.clear(); @@ -845,22 +1387,43 @@ struct prefilterPrimaryElectron { negTracks_per_coll.shrink_to_fit(); } // end of collision loop - for (auto& ele : primaryelectrons) { + 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); + if (fillQAHistogram) { + 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(Join const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const&, aod::EMPrimaryElectrons const& primaryelectrons) + 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 (auto& collision : collisions) { + for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { continue; } @@ -870,7 +1433,26 @@ struct prefilterPrimaryElectron { 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))) { + for (const auto& pos : posTracks_per_coll) { + if (!checkTrack(collision, pos)) { // track cut is applied to loose sample + continue; + } + if (fillQAHistogram) { + 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; + } + if (fillQAHistogram) { + 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; @@ -879,13 +1461,32 @@ struct prefilterPrimaryElectron { continue; } - bool isPC = reconstructPC<-1>(collision, ele, empos); - if (isPC) { - pfb_map[empos.globalIndex()] |= (uint8_t(1) << static_cast(EM_Electron_PF::kElFromPC)); + 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); + if (fillQAHistogram) { + 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)) { + if (fillQAHistogram) { + 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_20MeV) + i)); + } } - } - for (auto& [pos, emele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, electrons_per_coll))) { + 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; @@ -893,17 +1494,97 @@ struct prefilterPrimaryElectron { 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)); + + 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); + if (fillQAHistogram) { + 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)) { + if (fillQAHistogram) { + 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_20MeV) + 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); + if (fillQAHistogram) { + 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); + if (fillQAHistogram) { + 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) { + 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); + if (fillQAHistogram) { + 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); @@ -926,10 +1607,10 @@ struct associateAmbiguousElectron { void process(aod::EMPrimaryElectrons const& electrons) { - for (auto& electron : 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 (auto& amb_ele : electrons_with_same_trackId) { + for (const auto& amb_ele : electrons_with_same_trackId) { if (amb_ele.globalIndex() == electron.globalIndex()) { // don't store myself. continue; } diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectronQC.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectronQC.cxx new file mode 100644 index 00000000000..5a22177b664 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryElectronQC.cxx @@ -0,0 +1,809 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/MlResponseO2Track.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/Core/TableHelper.h" +#include "Common/Core/trackUtilities.h" +// #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include + +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 skimmerPrimaryElectronQC { + 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"}; + + struct : ConfigurableGroup { + std::string prefix = "trackcut"; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 40, "min. crossed rows"}; + Configurable min_ncluster_its{"min_ncluster_its", 2, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 0, "min ncluster itsib"}; + 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 maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 36.0, "max. chi2/NclsITS"}; + Configurable minchi2its{"minchi2its", -1e+10, "min. chi2/NclsITS"}; + Configurable minpt{"minpt", 0.05, "min pt for ITS-TPC track"}; + Configurable maxeta{"maxeta", 0.9, "eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 1.0, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 1.0, "max DCAz in cm"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -3.5, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", +3.5, "max. TPC n sigma for electron inclusion"}; + } trackcut; + + struct : ConfigurableGroup { + std::string prefix = "tighttrackcut"; + Configurable min_ncluster_tpc_pid{"min_ncluster_tpc_pid", 60, "min ncluster tpc used for PID"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 100, "min. crossed rows"}; + Configurable min_ncluster_its{"min_ncluster_its", 5, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 3, "min ncluster itsib"}; + 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", 0.7, "max fraction of shared clusters in TPC"}; + Configurable maxchi2tpc{"maxchi2tpc", 4.0, "max. chi2/NclsTPC"}; + Configurable maxchi2its{"maxchi2its", 5.0, "max. chi2/NclsITS"}; + Configurable dca_xy_max{"dca_xy_max", 0.2, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 0.2, "max DCAz in cm"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; // Don't change. + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", +2.0, "max. TPC n sigma for electron inclusion"}; // Don't change. + Configurable minTOFNsigmaEl{"minTOFNsigmaEl", -2.0, "min. TOF n sigma for electron inclusion"}; // Don't change. + Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", +2.0, "max. TOF n sigma for electron inclusion"}; // Don't change. + } tighttrackcut; + + Configurable storeOnlyTrueElectronMC{"storeOnlyTrueElectronMC", false, "Flag to store only true electron in MC"}; + Configurable maxMee{"maxMee", 0.005, "max mee for pi0 -> ee"}; + Configurable maxPhiV{"maxPhiV", M_PI / 2, "max phiv for pi0 -> ee"}; + + // configuration for PID ML + Configurable usePIDML{"usePIDML", false, "Flag to use 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)"}; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + o2::analysis::MlResponseO2Track mlResponseSingleTrack; + + 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; + o2::dataformats::DCA mDcaInfoCov; + + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + o2::ccdb::CcdbApi ccdbApi; + + void init(InitContext&) + { + mRunNumber = 0; + d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + ccdbApi.init(ccdburl); + + 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, {{4000, -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, {{400, 0, 40}}, 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/hTPCdEdxMC", "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/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/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); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hMeanClusterSizeITSib", "mean cluster size ITSib;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hMeanClusterSizeITSob", "mean cluster size ITSob;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hProbElBDT", "probability to be e from BDT;p_{in} (GeV/c);BDT score;", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Pair/hMvsPhiV", "m_{ee} vs. #varphi_{V} ULS;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{90, 0.f, M_PI}, {100, 0, 0.1}}); + } + + if (usePIDML) { + static constexpr int nClassesMl = 2; + const std::vector cutDirMl = {o2::cuts_ml::CutNot, o2::cuts_ml::CutSmaller}; + const std::vector labelsClasses = {"Background", "Signal"}; + const uint32_t nBinsMl = 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] = 0.0; + cutsMlArr[i][1] = cutsMl.value[i]; + } + o2::framework::LabeledArray cutsMl = {cutsMlArr[0], nBinsMl, nClassesMl, labelsBins, labelsClasses}; + + mlResponseSingleTrack.configure(binsMl.value, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + mlResponseSingleTrack.setModelPathsCCDB(onnxFileNames.value, ccdbApi, onnxPathsCCDB.value, timestampCCDB.value); + } else { + mlResponseSingleTrack.setModelPathsLocal(onnxFileNames.value); + } + mlResponseSingleTrack.cacheInputFeaturesIndices(namesInputFeatures); + mlResponseSingleTrack.cacheBinningIndex(nameBinningFeature); + mlResponseSingleTrack.init(enableOptimizations.value); + } // end of PID ML + } + + 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 (storeOnlyTrueElectronMC) { + const auto& mcParticle = track.template mcParticle_as(); + if (std::abs(mcParticle.pdgCode()) != 11) { + return false; + } + } + } + + if (!track.hasITS()) { + return false; + } + + if (track.itsChi2NCl() < trackcut.minchi2its || trackcut.maxchi2its < track.itsChi2NCl()) { // accept ITS afterburner (itsChi2NCl = -999) + return false; + } + if (track.itsNCls() < trackcut.min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < trackcut.min_ncluster_itsib) { + return false; + } + + if (!trackcut.includeITSsa && (!track.hasITS() || !track.hasTPC())) { + return false; + } + + if (track.hasTPC()) { + if (track.tpcChi2NCl() < 0.f || trackcut.maxchi2tpc < track.tpcChi2NCl()) { + return false; + } + + if (track.tpcNClsFound() < trackcut.min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < trackcut.mincrossedrows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < trackcut.min_tpc_cr_findable_ratio) { + return false; + } + + if (track.tpcFractionSharedCls() > trackcut.max_frac_shared_clusters_tpc) { + return false; + } + } + + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (std::fabs(dcaXY) > trackcut.dca_xy_max || std::fabs(dcaZ) > trackcut.dca_z_max) { + return false; + } + + if (trackParCov.getPt() < trackcut.minpt || std::fabs(trackParCov.getEta()) > trackcut.maxeta) { + return false; + } + + return true; + } + + template + bool checkTrackTight(TCollision const& collision, TTrack const& track) + { + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + if (storeOnlyTrueElectronMC) { + const auto& mcParticle = track.template mcParticle_as(); + if (std::abs(mcParticle.pdgCode()) != 11) { + return false; + } + } + } + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + + if (track.itsChi2NCl() < 0.f || tighttrackcut.maxchi2its < track.itsChi2NCl()) { + return false; + } + if (track.itsNCls() < tighttrackcut.min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < tighttrackcut.min_ncluster_itsib) { + return false; + } + + if (track.tpcChi2NCl() < 0.f || tighttrackcut.maxchi2tpc < track.tpcChi2NCl()) { + return false; + } + + if (track.tpcNClsFound() < tighttrackcut.min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < tighttrackcut.mincrossedrows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < tighttrackcut.min_tpc_cr_findable_ratio) { + return false; + } + + if (track.tpcFractionSharedCls() > tighttrackcut.max_frac_shared_clusters_tpc) { + return false; + } + + if (track.tpcNClsPID() < tighttrackcut.min_ncluster_tpc_pid) { + return false; + } + + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (std::fabs(dcaXY) > tighttrackcut.dca_xy_max || std::fabs(dcaZ) > tighttrackcut.dca_z_max) { + return false; + } + + if (trackParCov.getPt() < trackcut.minpt || std::fabs(trackParCov.getEta()) > trackcut.maxeta) { + return false; + } + + return true; + } + + template + bool isElectron(TTrack const& track) + { + if (track.hasTPC()) { + if (trackcut.minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < trackcut.maxTPCNsigmaEl) { + return true; + } else { + return false; + } + } else { // accept ITSsa too + return true; + } + } + + template + bool isElectronTight(TTrack const& track) + { + bool is_El_TPC = tighttrackcut.minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < tighttrackcut.maxTPCNsigmaEl; + bool is_El_TOF = tighttrackcut.minTOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < tighttrackcut.maxTOFNsigmaEl; + return is_El_TPC && is_El_TOF; + } + + 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()) { + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return; + } + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + float pt_recalc = trackParCov.getPt(); + float eta_recalc = trackParCov.getEta(); + float phi_recalc = trackParCov.getPhi(); + o2::math_utils::bringTo02Pi(phi_recalc); + + bool isAssociatedToMPC = collision.globalIndex() == track.collisionId(); + float mcTunedTPCSignal = 0.f; + if constexpr (isMC) { + mcTunedTPCSignal = track.mcTunedTPCSignal(); + } + + float probaEl = 1.0; + if (usePIDML) { + std::vector inputFeatures = mlResponseSingleTrack.getInputFeatures(track, trackParCov, collision); + float binningFeature = mlResponseSingleTrack.getBinningFeature(track, trackParCov, collision); + + int pbin = lower_bound(binsMl.value.begin(), binsMl.value.end(), binningFeature) - binsMl.value.begin() - 1; + if (pbin < 0) { + pbin = 0; + } else if (static_cast(binsMl.value.size()) - 2 < pbin) { + pbin = static_cast(binsMl.value.size()) - 2; + } + probaEl = mlResponseSingleTrack.getModelOutput(inputFeatures, pbin)[1]; // 0: hadron, 1:electron + } + + emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), + pt_recalc, eta_recalc, phi_recalc, + dcaXY, dcaZ, trackParCov.getSigmaY2(), trackParCov.getSigmaZY(), trackParCov.getSigmaZ2(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusPID(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.beta(), track.tofNSigmaEl(), /*track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(),*/ + track.itsClusterSizes(), + track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), + // trackParCov.getTgl(), + isAssociatedToMPC, false, probaEl, mcTunedTPCSignal); + + emprimaryelectronscov( + trackParCov.getX(), + trackParCov.getAlpha(), + trackParCov.getY(), + trackParCov.getZ(), + trackParCov.getSnp(), + // trackParCov.getTgl(), + // trackParCov.getSigmaY2(), + // trackParCov.getSigmaZY(), + // trackParCov.getSigmaZ2(), + trackParCov.getSigmaSnpY(), + trackParCov.getSigmaSnpZ(), + trackParCov.getSigmaSnp2(), + trackParCov.getSigmaTglY(), + trackParCov.getSigmaTglZ(), + trackParCov.getSigmaTglSnp(), + trackParCov.getSigmaTgl2(), + trackParCov.getSigma1PtY(), + trackParCov.getSigma1PtZ(), + trackParCov.getSigma1PtSnp(), + trackParCov.getSigma1PtTgl(), + trackParCov.getSigma1Pt2()); + + stored_trackIds.emplace_back(std::pair{collision.globalIndex(), track.globalIndex()}); + + if (fillQAHistogram) { + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + int total_cluster_size_ib = 0, nl_ib = 0; + for (unsigned int layer = 0; layer < 3; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl_ib++; + } + total_cluster_size_ib += cluster_size_per_layer; + } + + int total_cluster_size_ob = 0, nl_ob = 0; + for (unsigned int layer = 3; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl_ob++; + } + total_cluster_size_ob += 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(trackParCov.getSigmaY2()), dcaZ / std::sqrt(trackParCov.getSigmaZ2())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt_recalc, std::sqrt(trackParCov.getSigmaY2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt_recalc, std::sqrt(trackParCov.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/hTPCdEdxMC"), track.tpcInnerParam(), mcTunedTPCSignal); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + 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"), trackParCov.getP(), track.beta()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.tpcInnerParam(), track.tofNSigmaEl()); + 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"), trackParCov.getP(), static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(trackParCov.getTgl()))); + fRegistry.fill(HIST("Track/hMeanClusterSizeITSib"), trackParCov.getP(), static_cast(total_cluster_size_ib) / static_cast(nl_ib) * std::cos(std::atan(trackParCov.getTgl()))); + fRegistry.fill(HIST("Track/hMeanClusterSizeITSob"), trackParCov.getP(), static_cast(total_cluster_size_ob) / static_cast(nl_ob) * std::cos(std::atan(trackParCov.getTgl()))); + fRegistry.fill(HIST("Track/hProbElBDT"), track.tpcInnerParam(), probaEl); + } + } + } + + template + bool isDielectronFromPi0(TCollision const& collision, TTrack const& t1, TTrack const& t2) + { + mDcaInfoCov.set(999, 999, 999, 999, 999); + std::array pVec1 = {0, 0, 0}; // px, py, pz + std::array pVec2 = {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()); + + auto t1ParCov = getTrackParCov(t1); + t1ParCov.setPID(o2::track::PID::Electron); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, t1ParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + getPxPyPz(t1ParCov, pVec1); + + auto t2ParCov = getTrackParCov(t2); + t2ParCov.setPID(o2::track::PID::Electron); + isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, t2ParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + getPxPyPz(t2ParCov, pVec2); + + ROOT::Math::PtEtaPhiMVector v1(t1ParCov.getPt(), t1ParCov.getEta(), t1ParCov.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2ParCov.getPt(), t2ParCov.getEta(), t2ParCov.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float mee = v12.M(); + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(pVec1[0], pVec1[1], pVec1[2], pVec2[0], pVec2[1], pVec2[2], t1.sign(), t2.sign(), d_bz); + + if (fillQAHistogram) { + fRegistry.fill(HIST("Pair/hMvsPhiV"), phiv, mee); + } + if (mee < maxMee && phiv < maxPhiV) { + return true; + } else { + return false; + } + } + + std::vector> stored_trackIds; + Filter trackFilter = trackcut.minpt < o2::aod::track::pt && nabs(o2::aod::track::eta) < trackcut.maxeta && o2::aod::track::itsChi2NCl < trackcut.maxchi2its && 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; + + // ---------- 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; + } + + const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + for (const auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if ((checkTrackTight(collision, pos) && isElectronTight(pos)) && (checkTrack(collision, ele) && isElectron(ele))) { + if (isDielectronFromPi0(collision, pos, ele)) { + fillTrackTable(collision, ele); + } + } + if ((checkTrackTight(collision, ele) && isElectronTight(ele)) && (checkTrack(collision, pos) && isElectron(pos))) { + if (isDielectronFromPi0(collision, pos, ele)) { + fillTrackTable(collision, pos); + } + } + + } // end of ULS pairing + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectronQC, processRec, "process reconstructed info only", true); // standalone + + void processRec_SWT(MyCollisionsWithSWT 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.swtaliastmp_raw() == 0) { + continue; + } + + const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + for (const auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if ((checkTrackTight(collision, pos) && isElectronTight(pos)) && (checkTrack(collision, ele) && isElectron(ele))) { + if (isDielectronFromPi0(collision, pos, ele)) { + fillTrackTable(collision, ele); + } + } + if ((checkTrackTight(collision, ele) && isElectronTight(ele)) && (checkTrack(collision, pos) && isElectron(pos))) { + if (isDielectronFromPi0(collision, pos, ele)) { + fillTrackTable(collision, pos); + } + } + + } // end of ULS pairing + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectronQC, processRec_SWT, "process reconstructed info only", false); // standalone 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(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::McParticles const&) + { + 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; + } + const auto& posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + + for (const auto& [pos, ele] : combinations(CombinationsFullIndexPolicy(posTracks_per_coll, negTracks_per_coll))) { + if ((checkTrackTight(collision, pos) && isElectronTight(pos)) && (checkTrack(collision, ele) && isElectron(ele))) { + if (isDielectronFromPi0(collision, pos, ele)) { + fillTrackTable(collision, ele); + } + } + if ((checkTrackTight(collision, ele) && isElectronTight(ele)) && (checkTrack(collision, pos) && isElectron(pos))) { + if (isDielectronFromPi0(collision, pos, ele)) { + fillTrackTable(collision, pos); + } + } + + } // end of ULS pairing + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectronQC, processMC, "process reconstructed and MC info ", false); +}; + +struct prefilterPrimaryElectron { + Produces ele_pfb; + + void init(InitContext&) {} + + void process(aod::EMPrimaryElectrons const& primaryelectrons) + { + for (int i = 0; i < primaryelectrons.size(); i++) { + ele_pfb(0); + } + } +}; + +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-qc"}), + 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 index 812b046adf7..9de70407e65 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx @@ -9,94 +9,97 @@ // 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. +/// \brief write relevant information for muons. /// \author daiki.sekihata@cern.ch -#include "Math/Vector4D.h" -#include "Math/SMatrix.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.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 "EventFiltering/Zorro.h" +#include "Common/Core/fwdtrackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" #include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" #include "DataFormatsParameters/GRPMagField.h" -#include "TGeoGlobalMagField.h" -#include "Field/MagneticField.h" - #include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" #include "GlobalTracking/MatchGlobalFwd.h" #include "MCHTracking/TrackExtrap.h" #include "MCHTracking/TrackParam.h" #include "ReconstructionDataFormats/TrackFwd.h" -#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "Math/SMatrix.h" +#include "Math/Vector4D.h" +#include "TGeoGlobalMagField.h" + +#include +#include +#include +#include +#include +#include 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; -using MyTracks = soa::Join; // muon tracks are repeated. i.e. not exclusive. -using MyTrack = MyTracks::iterator; - -using MyTracksMC = soa::Join; -using MyTrackMC = MyTracksMC::iterator; +struct skimmerPrimaryMuon { + using MyCollisions = soa::Join; + using MyCollisionsWithSWT = soa::Join; -using MFTTracksMC = soa::Join; -using MFTTrackMC = MFTTracksMC::iterator; + using MyFwdTracks = soa::Join; // muon tracks are repeated. i.e. not exclusive. + using MyFwdTrack = MyFwdTracks::iterator; -struct skimmerPrimaryMuon { - // 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 MyFwdTracksMC = soa::Join; + using MyFwdTrackMC = MyFwdTracksMC::iterator; - using SMatrix55 = ROOT::Math::SMatrix>; - using SMatrix5 = ROOT::Math::SVector; + using MFTTracksMC = soa::Join; + using MFTTrackMC = MFTTracksMC::iterator; - SliceCache cache; - Preslice perCollision = o2::aod::fwdtrack::collisionId; - Preslice perCollision_mft = o2::aod::fwdtrack::collisionId; - Produces emprimarymuons; + Produces emprimarymuons; Produces emprimarymuonscov; // Configurables - Configurable fillQAHistogram{"fillQAHistogram", false, "flag to fill QA histograms"}; - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; 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 fillQAHistograms{"fillQAHistograms", false, "flag to fill QA histograms"}; + Configurable minPt{"minPt", 0.1, "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 enable_swt{"enable_swt", false, "flag to process skimmed data (swt triggered)"}; - Configurable cfg_swt_names{"cfg_swt_names", "", "comma-separated software trigger names"}; - Configurable inherit_from_emevent_dilepton{"inherit_from_emevent_dilepton", false, "flag to inherit task options from emevent-dilepton"}; + Configurable maxDCAxy{"maxDCAxy", 1, "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", 10, "max. chi2 for global muon"}; + Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; + Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; + Configurable minNmuon{"minNmuon", 0, "min number of muon candidates per collision"}; - Zorro zorro; o2::ccdb::CcdbApi ccdbApi; Service ccdb; - int mRunNumber; + int mRunNumber = 0; + float mBz = 0; - 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& initContext) + void init(InitContext&) { ccdb->setURL(ccdburl); ccdb->setCaching(true); @@ -104,16 +107,11 @@ struct skimmerPrimaryMuon { ccdb->setFatalWhenNull(false); ccdbApi.init(ccdburl); - // o2::mch::TrackExtrap::setField(); - addHistograms(); - - mRunNumber = 0; - - if (inherit_from_emevent_dilepton) { - getTaskOptionValue(initContext, "create-emevent-dilepton", "applyEveSel_at_skimming", applyEveSel_at_skimming.value, true); // for EM users. - getTaskOptionValue(initContext, "create-emevent-dilepton", "enable_swt", enable_swt.value, true); // for EM users. - getTaskOptionValue(initContext, "create-emevent-dilepton", "cfg_swt_names", cfg_swt_names.value, true); // for EM users. + if (fillQAHistograms) { + addHistograms(); } + mRunNumber = 0; + mBz = 0; } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -121,13 +119,9 @@ struct skimmerPrimaryMuon { if (mRunNumber == bc.runNumber()) { return; } - - if (enable_swt) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); - } - mRunNumber = bc.runNumber(); - std::map metadata; + + std::map metadata; auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); auto ts = soreor.first; auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); @@ -136,550 +130,1082 @@ struct skimmerPrimaryMuon { ccdb->get(geoPath); } o2::mch::TrackExtrap::setField(); + const double centerMFT[3] = {0, 0, -61.4}; + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + mBz = field->getBz(centerMFT); // Get field at centre of MFT + LOGF(info, "Bz at center of MFT = %f kZG", mBz); } void addHistograms() { - fRegistry.add("Event/hCollisionCounter", "collision counter", kTH1F, {{2, -0.5f, 1.5}}, false); - fRegistry.add("Event/hNmuon", "Number of #mu per event;N_{#mu^{#minus}};N_{#mu^{+}}", kTH2F, {{101, -0.5f, 100.5}, {101, -0.5f, 100.5}}, false); - - // for track - if (fillQAHistogram) { - 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, {{200, 0.0f, 200}}, false); - fRegistry.add("Track/MFTMCHMID/hPDCA", "pDCA;p_{T,#mu} at PV (GeV/c);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 10}, {100, 0.0f, 1000}}, false); - fRegistry.add("Track/MFTMCHMID/hPDCA_recalc", "pDCA relcalculated;p_{T,#mu} at PV (GeV/c);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 10}, {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/hMatchScoreMCHMFT", "match score MCH-MFT;score", 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/hDCAxySigma", "DCA_{xy};DCA_{xy} (#sigma);", kTH1F, {{100, 0, 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.add("Track/MFTMCHMID/hChi2MatchMCHMFT_DCAxySigma", "chi2 match MCH-MFT;DCA_{xy,#mu} (#sigma);MFT-MCH matching chi2", kTH2F, {{100, 0, 10}, {100, 0.0f, 100}}, false); - fRegistry.add("Track/MFTMCHMID/hChi2MatchMCHMFT_Pt", "chi2 match MCH-MFT;p_{T,#mu} (GeV/c);MFT-MCH matching chi2", kTH2F, {{100, 0, 10}, {100, 0.0f, 100}}, false); - fRegistry.addClone("Track/MFTMCHMID/", "Track/MCHMID/"); - } + 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/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/hDeltaPt_Pt", "#Deltap_{T}/p_{T} vs. p_{T};p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl}", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); + fRegistry.add("MFTMCHMID/hDeltaEta_Pt", "#Delta#eta vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#eta", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); + fRegistry.add("MFTMCHMID/hDeltaPhi_Pt", "#Delta#varphi vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); + fRegistry.add("MFTMCHMID/hDeltaEtaAtMP_Pt", "#Delta#eta vs. p_{T} at MP;p_{T}^{gl} (GeV/c);#Delta#eta", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); + fRegistry.add("MFTMCHMID/hDeltaPhiAtMP_Pt", "#Delta#varphi vs. p_{T} at MP;p_{T}^{gl} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5, +0.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/ndf", kTH1F, {{100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/hChi2MFT", "chi2 MFT;chi2 MFT/ndf", kTH1F, {{100, 0.0f, 10}}, 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/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -1, 1}, {200, -1, +1}}, 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/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{100, 0, 1}, {200, -0.1, 0.1}}, false); + fRegistry.add("MFTMCHMID/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("MFTMCHMID/hNmu", "#mu multiplicity;N_{#mu} per collision", kTH1F, {{21, -0.5, 20.5}}, 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("MFTMCHMID/hDCAxyResolutionvsPt", "DCA_{xy} 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); + fRegistry.add("MCHMID/hDCAxyResolutionvsPt", "DCA_{xy} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); } - template - void fillTrackHistogram(TTrack const& track, TCollision const& collision) + bool isSelected(const float pt, const float eta, const float rAtAbsorberEnd, const float pDCA, const float chi2_per_ndf, const uint8_t trackType, const float dcaXY) { - o2::dataformats::GlobalFwdTrack propmuonAtPV = PropagateMuon(track, collision, skimmerPrimaryMuon::MuonExtrapolation::kToVertex); // this is for MCH-MID tracks that cannot see the primary vertex. - o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(track, collision, skimmerPrimaryMuon::MuonExtrapolation::kToDCA); - - float p = propmuonAtPV.getP(); - float pt = propmuonAtPV.getPt(); - float eta = propmuonAtPV.getEta(); - float phi = propmuonAtPV.getPhi(); - - o2::math_utils::bringTo02Pi(phi); - if (phi < 0.f || 2.f * M_PI < phi) { - return; + if (pt < minPt || maxPt < pt) { + return false; } - - if (eta < mineta || maxeta < eta) { - return; + if (rAtAbsorberEnd < minRabs || maxRabs < rAtAbsorberEnd) { + return false; + } + if (rAtAbsorberEnd < midRabs ? pDCA > maxPDCAforSmallR : pDCA > maxPDCAforLargeR) { + return false; } - if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (eta < mineta_mft || maxeta_mft < eta) { - return; + if (trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (eta < minEtaGL || maxEtaGL < eta) { + return false; + } + if (maxDCAxy < dcaXY) { + return false; + } + if (maxChi2GL < chi2_per_ndf) { + 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 (maxChi2SA < chi2_per_ndf) { + return false; } + } else { + return false; } - float rAtAbsorberEnd = track.rAtAbsorberEnd(); - if (static_cast(track.trackType()) > 2) { // only for MUON standalone - o2::dataformats::GlobalFwdTrack propmuonAtRabs = PropagateMuon(track, collision, skimmerPrimaryMuon::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 + return true; + } + + template + bool fillFwdTrackTable(TCollision const& collision, TFwdTrack fwdtrack, TMFTTracksCov const& mftCovs, const bool isAmbiguous) + { + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.chi2MatchMCHMFT() > maxMatchingChi2MCHMFT) { + return false; + } // 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 false; } - if (rAtAbsorberEnd < minRabs || maxRabs < rAtAbsorberEnd) { - return; + if (fwdtrack.chi2() < 0.f) { // this should never happen. only for protection. + return false; } - float dcaX = (propmuonAtDCA.getX() - collision.posX()); - float dcaY = (propmuonAtDCA.getY() - collision.posY()); + o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz); + float pt = propmuonAtPV.getPt(); + float eta = propmuonAtPV.getEta(); + float phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + float dcaX = propmuonAtPV.getX() - collision.posX(); + float dcaY = propmuonAtPV.getY() - collision.posY(); + float dcaZ = propmuonAtPV.getZ() - collision.posZ(); float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - float cXX = propmuonAtDCA.getSigma2X(); - float cYY = propmuonAtDCA.getSigma2Y(); - float cXY = propmuonAtDCA.getSigmaXY(); + float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack + float cXX = propmuonAtPV.getSigma2X(); + float cYY = propmuonAtPV.getSigma2Y(); + float cXY = propmuonAtPV.getSigmaXY(); + float det = cXX * cYY - cXY * cXY; // determinanat float dcaXYinSigma = 999.f; - float det = cXX * cYY - cXY * cXY; if (det < 0) { dcaXYinSigma = 999.f; } else { - float chi2 = (dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2. * dcaX * dcaY * cXY) / det; - dcaXYinSigma = std::sqrt(std::abs(chi2) / 2.); // in sigma - } - - fRegistry.fill(HIST("Track/hMuonType"), track.trackType()); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hPt"), pt); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hEtaPhi"), phi, 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"), pt, track.pDca()); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hPDCA_recalc"), pt, p * dcaXY); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hRatAbsorberEnd"), 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("hMatchScoreMCHMFT"), track.matchScoreMCHMFT()); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAxy2D"), dcaX, dcaY); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAxySigma"), dcaXYinSigma); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hChi2MatchMCHMFT_DCAxySigma"), dcaXYinSigma, track.chi2MatchMCHMFT()); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hChi2MatchMCHMFT_Pt"), pt, track.chi2MatchMCHMFT()); - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um - fRegistry.fill(HIST("Track/") + HIST(muon_types[mu_id]) + HIST("hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um - } - - template - o2::dataformats::GlobalFwdTrack PropagateMuon(T const& muon, C const& collision, const skimmerPrimaryMuon::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 == skimmerPrimaryMuon::MuonExtrapolation::kToVertex) { - o2::mch::TrackExtrap::extrapToVertex(mchTrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); - } - if (endPoint == skimmerPrimaryMuon::MuonExtrapolation::kToDCA) { - o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, collision.posZ()); - } - if (endPoint == skimmerPrimaryMuon::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()); + dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2.f * dcaX * dcaY * cXY) / det / 2.f)); // dca xy in sigma } - - v1.clear(); - v1.shrink_to_fit(); - - return propmuon; - } - - template - bool isSelected(TMuon const& muon, TCollision const& collision) - { - if constexpr (isMC) { - if (!muon.has_mcParticle()) { + float sigma_dcaXY = dcaXY / dcaXYinSigma; + + float pDCA = propmuonAtPV.getP() * dcaXY; + int nClustersMFT = 0; + float ptMatchedMCHMID = propmuonAtPV.getPt(); + 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 tgl = fwdtrack.tgl(); + float chi2mft = 0.f; + uint64_t mftClusterSizesAndTrackFlags = 0; + int ndf_mchmft = 1; + int ndf_mft = 1; + + float etaMatchedMCHMIDatMP = 999.f; + float phiMatchedMCHMIDatMP = 999.f; + float etaMatchedMFTatMP = 999.f; + float phiMatchedMFTatMP = 999.f; + + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + // apply r-absorber cut here to minimize the number of calling propagateMuon. + if (fwdtrack.rAtAbsorberEnd() < minRabsGL || maxRabs < fwdtrack.rAtAbsorberEnd()) { return false; } - } - o2::dataformats::GlobalFwdTrack propmuonAtPV = PropagateMuon(muon, collision, skimmerPrimaryMuon::MuonExtrapolation::kToVertex); + // apply dca cut here to minimize the number of calling propagateMuon. + if (maxDCAxy < dcaXY) { + return false; + } - float pt = propmuonAtPV.getPt(); - float eta = propmuonAtPV.getEta(); - float phi = propmuonAtPV.getPhi(); + auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID + auto mfttrack = fwdtrack.template matchMFTTrack_as(); // MFTsa - if (pt < minpt) { - return false; - } + if constexpr (isMC) { + if (!mfttrack.has_mcParticle()) { + return false; + } + } - if (eta < mineta || maxeta < eta) { - return false; - } + nClustersMFT = mfttrack.nClusters(); + mftClusterSizesAndTrackFlags = mfttrack.mftClusterSizesAndTrackFlags(); + ndf_mchmft = 2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f; + ndf_mft = 2.f * nClustersMFT - 5.f; + chi2mft = mfttrack.chi2(); + // chi2mft = mfttrack.chi2() / (2.f * nClustersMFT - 5.f); - o2::math_utils::bringTo02Pi(phi); - if (phi < 0.f || 2.f * M_PI < phi) { - return false; - } + // apply chi2/ndf cut here to minimize the number of calling propagateMuon. + if (maxChi2GL < fwdtrack.chi2() / ndf_mchmft) { + return false; + } - // float dcaX = propmuonAtDCA.getX() - collision.posX(); - // float dcaY = propmuonAtDCA.getY() - collision.posY(); - float rAtAbsorberEnd = muon.rAtAbsorberEnd(); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz); + ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); + etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); + phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz); + 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; + + if constexpr (withMFTCov) { + auto mfttrackcov = mftCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, matchingZ, mBz); // propagated to matching plane + o2::track::TrackParCovFwd mftsaAtMP = getTrackParCovFwd(mfttrack, mfttrackcov); // values at innermost update + mftsaAtMP.propagateToZhelix(matchingZ, mBz); // propagated to matching plane + etaMatchedMFTatMP = mftsaAtMP.getEta(); + phiMatchedMFTatMP = mftsaAtMP.getPhi(); + etaMatchedMCHMIDatMP = muonAtMP.getEta(); + phiMatchedMCHMIDatMP = muonAtMP.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMIDatMP); + o2::math_utils::bringTo02Pi(phiMatchedMFTatMP); + + o2::track::TrackParCovFwd mftsa = getTrackParCovFwd(mfttrack, mfttrackcov); // values at innermost update + o2::dataformats::GlobalFwdTrack globalMuonRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuonAtPV_Matched, mftsa); // this is track at IU. + auto globalMuon = o2::aod::fwdtrackutils::propagateTrackParCovFwd(globalMuonRefit, fwdtrack.trackType(), collision, propagationPoint::kToVertex, matchingZ, mBz); + pt = globalMuon.getPt(); + eta = globalMuon.getEta(); + phi = globalMuon.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + cXX = globalMuon.getSigma2X(); + cYY = globalMuon.getSigma2Y(); + cXY = globalMuon.getSigmaXY(); + dcaX = globalMuon.getX() - collision.posX(); + dcaY = globalMuon.getY() - collision.posY(); + dcaZ = globalMuon.getZ() - collision.posZ(); + dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + det = cXX * cYY - cXY * cXY; // determinanat + dcaXYinSigma = 999.f; + if (det < 0) { + dcaXYinSigma = 999.f; + } else { + dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2.f * dcaX * dcaY * cXY) / det / 2.f)); // dca xy in sigma + } + sigma_dcaXY = dcaXY / dcaXYinSigma; + } - if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (eta < mineta_mft || maxeta_mft < eta) { - return false; + if (refitGlobalMuon) { + pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); } - } else if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - o2::dataformats::GlobalFwdTrack propmuonAtRabs = PropagateMuon(muon, collision, skimmerPrimaryMuon::MuonExtrapolation::kToRabs); + } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToRabs, matchingZ, mBz); // 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 + + o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz); + cXX = propmuonAtDCA.getSigma2X(); + cYY = propmuonAtDCA.getSigma2Y(); + cXY = propmuonAtDCA.getSigmaXY(); + dcaX = propmuonAtDCA.getX() - collision.posX(); + dcaY = propmuonAtDCA.getY() - collision.posY(); + dcaZ = propmuonAtDCA.getZ() - collision.posZ(); + dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + pDCA = fwdtrack.p() * dcaXY; + + det = cXX * cYY - cXY * cXY; // determinanat + dcaXYinSigma = 999.f; + if (det < 0) { + dcaXYinSigma = 999.f; + } else { + dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2.f * dcaX * dcaY * cXY) / det / 2.f)); // dca xy in sigma + } + sigma_dcaXY = dcaXY / dcaXYinSigma; } else { return false; } - if (rAtAbsorberEnd < minRabs || maxRabs < rAtAbsorberEnd) { + if (!isSelected(pt, eta, rAtAbsorberEnd, pDCA, fwdtrack.chi2() / ndf_mchmft, fwdtrack.trackType(), dcaXY)) { return false; } - return true; - } - - template - void fillMuonTable(TMuon const& muon, TCollision const& collision, const int new_muon_sa_id) - { - o2::dataformats::GlobalFwdTrack propmuonAtPV = PropagateMuon(muon, collision, skimmerPrimaryMuon::MuonExtrapolation::kToVertex); - o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(muon, collision, skimmerPrimaryMuon::MuonExtrapolation::kToDCA); - - float pt = propmuonAtPV.getPt(); - float eta = propmuonAtPV.getEta(); - float phi = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phi); + if constexpr (fillTable) { + float dpt = (ptMatchedMCHMID - pt) / pt; + float deta = etaMatchedMCHMID - eta; + float dphi = phiMatchedMCHMID - phi; + o2::math_utils::bringToPMPi(dphi); - float dcaX = propmuonAtDCA.getX() - collision.posX(); - float dcaY = propmuonAtDCA.getY() - collision.posY(); - float rAtAbsorberEnd = muon.rAtAbsorberEnd(); + float detaMP = etaMatchedMCHMIDatMP - etaMatchedMFTatMP; + float dphiMP = phiMatchedMCHMIDatMP - phiMatchedMFTatMP; + o2::math_utils::bringToPMPi(dphiMP); - if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - o2::dataformats::GlobalFwdTrack propmuonAtRabs = PropagateMuon(muon, collision, skimmerPrimaryMuon::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 - } + 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()); - bool isAssociatedToMPC = collision.globalIndex() == muon.collisionId(); - auto fwdcov = propmuonAtDCA.getCovariances(); - if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - auto mftsa_track = muon.template matchMFTTrack_as(); + emprimarymuons(collision.globalIndex(), fwdtrack.globalIndex(), fwdtrack.matchMFTTrackId(), fwdtrack.matchMCHTrackId(), fwdtrack.trackType(), + pt, eta, phi, fwdtrack.sign(), dcaX, dcaY, cXX, cYY, cXY, ptMatchedMCHMID, etaMatchedMCHMID, phiMatchedMCHMID, + etaMatchedMCHMIDatMP, phiMatchedMCHMIDatMP, etaMatchedMFTatMP, phiMatchedMFTatMP, + fwdtrack.nClusters(), pDCA, rAtAbsorberEnd, fwdtrack.chi2(), fwdtrack.chi2MatchMCHMID(), fwdtrack.chi2MatchMCHMFT(), + fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards(), mftClusterSizesAndTrackFlags, chi2mft, isAssociatedToMPC, isAmbiguous); - emprimarymuons(collision.globalIndex(), muon.globalIndex(), muon.trackType(), pt, eta, phi, muon.sign(), dcaX, dcaY, - propmuonAtDCA.getX(), propmuonAtDCA.getY(), propmuonAtDCA.getZ(), propmuonAtDCA.getTgl(), - muon.nClusters(), muon.pDca(), rAtAbsorberEnd, muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), - new_muon_sa_id, - muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), mftsa_track.mftClusterSizesAndTrackFlags(), mftsa_track.chi2(), isAssociatedToMPC); - emprimarymuonscov( - fwdcov(0, 0), - fwdcov(0, 1), fwdcov(1, 1), - fwdcov(2, 0), fwdcov(2, 1), fwdcov(2, 2), - fwdcov(3, 0), fwdcov(3, 1), fwdcov(3, 2), fwdcov(3, 3), - fwdcov(4, 0), fwdcov(4, 1), fwdcov(4, 2), fwdcov(4, 3), fwdcov(4, 4)); - } else if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - emprimarymuons(collision.globalIndex(), muon.globalIndex(), muon.trackType(), pt, eta, phi, muon.sign(), dcaX, dcaY, - propmuonAtDCA.getX(), propmuonAtDCA.getY(), propmuonAtDCA.getZ(), propmuonAtDCA.getTgl(), - muon.nClusters(), muon.pDca(), rAtAbsorberEnd, muon.chi2(), muon.chi2MatchMCHMID(), muon.chi2MatchMCHMFT(), - new_muon_sa_id, - muon.mchBitMap(), muon.midBitMap(), muon.midBoards(), 0, 999999.f, isAssociatedToMPC); + const auto& fwdcov = propmuonAtPV.getCovariances(); // covatiance matrix at PV emprimarymuonscov( fwdcov(0, 0), fwdcov(0, 1), fwdcov(1, 1), fwdcov(2, 0), fwdcov(2, 1), fwdcov(2, 2), fwdcov(3, 0), fwdcov(3, 1), fwdcov(3, 2), fwdcov(3, 3), fwdcov(4, 0), fwdcov(4, 1), fwdcov(4, 2), fwdcov(4, 3), fwdcov(4, 4)); + + // See definition DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h + // Covariance matrix of track parameters, ordered as follows: + // + // + // + // + // + + 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/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFTMCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MFTMCHMID/hDeltaPt_Pt"), pt, dpt); + fRegistry.fill(HIST("MFTMCHMID/hDeltaEta_Pt"), pt, deta); + fRegistry.fill(HIST("MFTMCHMID/hDeltaPhi_Pt"), pt, dphi); + fRegistry.fill(HIST("MFTMCHMID/hDeltaEtaAtMP_Pt"), pt, detaMP); + fRegistry.fill(HIST("MFTMCHMID/hDeltaPhiAtMP_Pt"), pt, dphiMP); + 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() / ndf_mchmft); + fRegistry.fill(HIST("MFTMCHMID/hChi2MFT"), chi2mft / ndf_mft); + fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MFTMCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + fRegistry.fill(HIST("MFTMCHMID/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("MFTMCHMID/hDCAxyinSigma"), dcaXYinSigma); + fRegistry.fill(HIST("MFTMCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 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/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MCHMID/hDeltaPt_Pt"), pt, dpt); + fRegistry.fill(HIST("MCHMID/hDeltaEta_Pt"), pt, deta); + fRegistry.fill(HIST("MCHMID/hDeltaPhi_Pt"), pt, dphi); + fRegistry.fill(HIST("MCHMID/hDeltaEtaAtMP_Pt"), pt, detaMP); + fRegistry.fill(HIST("MCHMID/hDeltaPhiAtMP_Pt"), pt, dphiMP); + 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 / ndf_mft); + fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MCHMID/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + fRegistry.fill(HIST("MCHMID/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MCHMID/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("MCHMID/hDCAxyinSigma"), dcaXYinSigma); + fRegistry.fill(HIST("MCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + } + } } + return true; + } - // See definition DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h - /// Covariance matrix of track parameters, ordered as follows:

-    ///                                     
-    ///                                     
-    ///                            
-    ///                        
-    ///                 
map_mfttrackcovs; + std::vector> vec_min_chi2MatchMCHMFT; // std::pair -> chi2MatchMCHMFT; + template + void findBestMatchPerMCHMID(TMuons const& muons) + { + vec_min_chi2MatchMCHMFT.reserve(muons.size()); + for (const auto& muon : muons) { + if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + const auto& muons_per_MCHMID = muons.sliceBy(fwdtracksPerMCHTrack, muon.globalIndex()); + // LOGF(info, "stanadalone: muon.globalIndex() = %d, muon.chi2MatchMCHMFT() = %f", muon.globalIndex(), muon.chi2MatchMCHMFT()); + // LOGF(info, "muons_per_MCHMID.size() = %d", muons_per_MCHMID.size()); + + float min_chi2MatchMCHMFT = 1e+10; + std::tuple tupleIds_at_min; + for (const auto& muon_tmp : muons_per_MCHMID) { + if (muon_tmp.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + // LOGF(info, "muon_tmp.globalIndex() = %d, muon_tmp.matchMCHTrackId() = %d, muon_tmp.matchMFTTrackId() = %d, muon_tmp.chi2MatchMCHMFT() = %f", muon_tmp.globalIndex(), muon_tmp.matchMCHTrackId(), muon_tmp.matchMFTTrackId(), muon_tmp.chi2MatchMCHMFT()); + if (0.f < muon_tmp.chi2MatchMCHMFT() && muon_tmp.chi2MatchMCHMFT() < min_chi2MatchMCHMFT) { + min_chi2MatchMCHMFT = muon_tmp.chi2MatchMCHMFT(); + tupleIds_at_min = std::make_tuple(muon_tmp.globalIndex(), muon_tmp.matchMCHTrackId(), muon_tmp.matchMFTTrackId()); + } + } + } + vec_min_chi2MatchMCHMFT.emplace_back(tupleIds_at_min); + // LOGF(info, "min: muon_tmp.globalIndex() = %d, muon_tmp.matchMCHTrackId() = %d, muon_tmp.matchMFTTrackId() = %d, muon_tmp.chi2MatchMCHMFT() = %f", std::get<0>(tupleIds_at_min), std::get<1>(tupleIds_at_min), std::get<2>(tupleIds_at_min), min_chi2MatchMCHMFT); + } + } // end of muon loop } - std::map, int> map_new_sa_muon_index; // new standalone muon index + SliceCache cache; + Preslice perCollision = o2::aod::fwdtrack::collisionId; + Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; + PresliceUnsorted fwdtrackIndicesPerFwdTrack = aod::track_association::fwdtrackId; + PresliceUnsorted fwdtracksPerMCHTrack = aod::fwdtrack::matchMCHTrackId; + std::unordered_multimap multiMapSAMuonsPerCollision; // collisionId -> trackIds + std::unordered_multimap multiMapGLMuonsPerCollision; // collisionId -> trackIds - // Preslice fwdtrackIndicesPerMFTsa = aod::fwdtrack::matchMFTTrackId; + void processRec_SA(MyCollisions const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&) + { + findBestMatchPerMCHMID(fwdtracks); - 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 + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); + initCCDB(bc); - void processRec_SA(Join const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::MFTTracks const&) + if (!collision.isSelected()) { + continue; + } + + 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; + } + + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; + } + + if (!fillFwdTrackTable(collision, fwdtrack, nullptr, false)) { + continue; + } + + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, false); + } + } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, false); + } + } + } // end of collision loop + + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processRec_SA, "process reconstructed info", false); + + void processRec_TTCA(MyCollisions const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices) { - for (auto& collision : collisions) { - auto bc = collision.template foundBC_as(); + findBestMatchPerMCHMID(fwdtracks); + + 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); - fRegistry.fill(HIST("Event/hCollisionCounter"), 0.f); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + + if (!collision.isSelected()) { continue; } - if (enable_swt && !zorro.isSelected(bc.globalBC())) { - continue; + + 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; + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; + } + + if (!fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()])) { + continue; + } + + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()]); + } } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()]); + } + } + } // end of collision loop - 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); + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + mapAmb.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processRec_TTCA, "process reconstructed info", false); + + void processRec_TTCA_withMFTCov(MyCollisions const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices, aod::MFTTracksCov const& mftCovs) + { + for (const auto& mfttrackConv : mftCovs) { + map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + } + findBestMatchPerMCHMID(fwdtracks); - int counter = 0; - int offset = emprimarymuons.lastIndex() + 1; + 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 (auto& track : sa_muons_per_coll) { - if (fillQAHistogram) { - fillTrackHistogram<3>(track, collision); + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + + 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; } - if (isSelected(track, collision)) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.globalIndex())] = counter + offset; - counter++; + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; } - } // end of standalone muon loop - for (auto& track : global_muons_per_coll) { - if (fillQAHistogram) { - fillTrackHistogram<0>(track, collision); + + if (!fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()])) { + continue; } - if (map_new_sa_muon_index.find(std::make_pair(collision.globalIndex(), track.matchMCHTrackId())) == map_new_sa_muon_index.end()) { // don't apply muon selection to MCH-MID track in MFT-MCH-MID track - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.matchMCHTrackId())] = counter + offset; - counter++; + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); } - if (isSelected(track, collision)) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.globalIndex())] = counter + offset; - counter++; + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); } - } // end of global muon loop - // fill table after mapping - for (const auto& [key, value] : map_new_sa_muon_index) { - // int collisionId = std::get<0>(key); - // int fwdtrackId = std::get<1>(key); - // int new_fwdtrackId = value; - // LOGF(info, "collisionId = %d, fwdtrackId = %d, new_fwdtrackId = %d", collisionId, fwdtrackId, new_fwdtrackId); - auto track = tracks.iteratorAt(std::get<1>(key)); - if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - fillMuonTable(track, collision, value); - } else if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - fillMuonTable(track, collision, map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.matchMCHTrackId())]); + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()]); + } + } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()]); } } - - map_new_sa_muon_index.clear(); } // end of collision loop + + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + mapAmb.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); } - PROCESS_SWITCH(skimmerPrimaryMuon, processRec_SA, "process reconstructed info only with standalone", true); + PROCESS_SWITCH(skimmerPrimaryMuon, processRec_TTCA_withMFTCov, "process reconstructed info", false); - Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; - void processRec_TTCA(Join const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::MFTTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices) + void processRec_SA_SWT(MyCollisionsWithSWT const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&) { - for (auto& collision : collisions) { - auto bc = collision.template foundBC_as(); + findBestMatchPerMCHMID(fwdtracks); + + for (const auto& collision : collisions) { + const auto& bc = collision.template bc_as(); initCCDB(bc); - fRegistry.fill(HIST("Event/hCollisionCounter"), 0.f); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + + if (!collision.isSelected()) { continue; } - if (enable_swt && !zorro.isSelected(bc.globalBC())) { + + if (collision.swtaliastmp_raw() == 0) { continue; } - int counter = 0; - int offset = emprimarymuons.lastIndex() + 1; - - auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); - for (auto& fwdtrackId : fwdtrackIdsThisCollision) { - auto track = fwdtrackId.template fwdtrack_as(); - // LOGF(info, "TTCA | collision.globalIndex() = %d, track.globalIndex() = %d, track.trackType() = %d, track.matchMFTTrackId() = %d, track.matchMCHTrackId() = %d, track.offsets() = %d", collision.globalIndex(), track.globalIndex(), track.trackType(), track.matchMFTTrackId(), track.matchMCHTrackId(), track.offsets()); + 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; + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; + } - // auto collision_in_track = track.collision_as(); - // auto bc_in_track = collision_in_track.bc_as(); - // LOGF(info, "track.globalIndex() = %d , bc_in_track.globalBC() = %lld", track.globalIndex(), bc_in_track.globalBC()); + if (!fillFwdTrackTable(collision, fwdtrack, nullptr, false)) { + continue; + } - if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - if (fillQAHistogram) { - fillTrackHistogram<3>(track, collision); - } - if (isSelected(track, collision)) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.globalIndex())] = counter + offset; - counter++; - } - } else if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (fillQAHistogram) { - fillTrackHistogram<0>(track, collision); - } - if (map_new_sa_muon_index.find(std::make_pair(collision.globalIndex(), track.matchMCHTrackId())) == map_new_sa_muon_index.end()) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.matchMCHTrackId())] = counter + offset; - counter++; - } - if (isSelected(track, collision)) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.globalIndex())] = counter + offset; - counter++; - } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); } - } // end of track loop - for (const auto& [key, value] : map_new_sa_muon_index) { - // int collisionId = std::get<0>(key); - // int fwdtrackId = std::get<1>(key); - // int new_fwdtrackId = value; - auto track = tracks.iteratorAt(std::get<1>(key)); - if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - fillMuonTable(track, collision, value); - } else if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - fillMuonTable(track, collision, map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.matchMCHTrackId())]); + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, false); + } + } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, false); } } - - map_new_sa_muon_index.clear(); } // end of collision loop - } - PROCESS_SWITCH(skimmerPrimaryMuon, processRec_TTCA, "process reconstructed info only with TTCA", false); - Partition global_muons_mc = o2::aod::fwdtrack::trackType == uint8_t(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack); // MFT-MCH-MID - Partition sa_muons_mc = o2::aod::fwdtrack::trackType == uint8_t(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack); // MCH-MID + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processRec_SA_SWT, "process reconstructed info only with standalone", false); - void processMC_SA(soa::Join const& collisions, aod::BCsWithTimestamps const&, MyTracksMC const& tracks, MFTTracksMC const&) + void processRec_TTCA_SWT(MyCollisionsWithSWT const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices) { - for (auto& collision : collisions) { - if (!collision.has_mcCollision()) { + findBestMatchPerMCHMID(fwdtracks); + + 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); + if (!collision.isSelected()) { continue; } - auto bc = collision.template foundBC_as(); - initCCDB(bc); - fRegistry.fill(HIST("Event/hCollisionCounter"), 0.f); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (collision.swtaliastmp_raw() == 0) { continue; } - auto sa_muons_mc_per_coll = sa_muons_mc->sliceByCached(o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); - auto global_muons_mc_per_coll = global_muons_mc->sliceByCached(o2::aod::fwdtrack::collisionId, collision.globalIndex(), cache); + 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; + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; + } - int counter = 0; - int offset = emprimarymuons.lastIndex() + 1; + if (!fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()])) { + continue; + } - for (auto& track : sa_muons_mc_per_coll) { - if (fillQAHistogram) { - fillTrackHistogram<3>(track, collision); + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); } - if (isSelected(track, collision)) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.globalIndex())] = counter + offset; - counter++; + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); } - } // end of standalone muon loop - for (auto& track : global_muons_mc_per_coll) { - auto sa_muon = tracks.iteratorAt(track.matchMCHTrackId()); - if (!sa_muon.has_mcParticle()) { + + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()]); + } + } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()]); + } + } + } // end of collision loop + + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + mapAmb.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processRec_TTCA_SWT, "process reconstructed info", false); + + void processRec_TTCA_SWT_withMFTCov(MyCollisionsWithSWT const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices, aod::MFTTracksCov const& mftCovs) + { + for (const auto& mfttrackConv : mftCovs) { + map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + } + findBestMatchPerMCHMID(fwdtracks); + + std::unordered_map mapAmb; // fwdtrack.globalIndex() -> bool isAmb; + for (const auto& fwdtrack : fwdtracks) { + 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) { + auto bc = collision.template bc_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } + if (collision.swtaliastmp_raw() == 0) { + continue; + } + + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto fwdtrack = fwdtrackId.template fwdtrack_as(); + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + continue; + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { continue; } - if (fillQAHistogram) { - fillTrackHistogram<0>(track, collision); + + if (!fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()])) { + continue; } - if (map_new_sa_muon_index.find(std::make_pair(collision.globalIndex(), track.matchMCHTrackId())) == map_new_sa_muon_index.end()) { // don't apply muon selection to MCH-MID track in MFT-MCH-MID track - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.matchMCHTrackId())] = counter + offset; - counter++; + + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); } - if (isSelected(track, collision)) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.globalIndex())] = counter + offset; - counter++; + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); } - } // end of global muon loop - // fill table after mapping - for (const auto& [key, value] : map_new_sa_muon_index) { - // int collisionId = std::get<0>(key); - // int fwdtrackId = std::get<1>(key); - // int new_fwdtrackId = value; - // LOGF(info, "collisionId = %d, fwdtrackId = %d, new_fwdtrackId = %d", collisionId, fwdtrackId, new_fwdtrackId); - auto track = tracks.iteratorAt(std::get<1>(key)); - if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - fillMuonTable(track, collision, value); - } else if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - fillMuonTable(track, collision, map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.matchMCHTrackId())]); + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()]); + } + } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()]); } } + } // end of collision loop + + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + mapAmb.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processRec_TTCA_SWT_withMFTCov, "process reconstructed info", false); + + void processMC_SA(soa::Join const& collisions, MyFwdTracksMC const& fwdtracks, MFTTracksMC const&, aod::BCsWithTimestamps const&) + { + findBestMatchPerMCHMID(fwdtracks); + + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } + if (!collision.has_mcCollision()) { + continue; + } + + auto fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); + for (const auto& fwdtrack : fwdtracks_per_coll) { + if (!fwdtrack.has_mcParticle()) { + continue; + } + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + continue; + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; + } + + if (!fillFwdTrackTable(collision, fwdtrack, nullptr, false)) { + continue; + } - map_new_sa_muon_index.clear(); + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, false); + } + } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, false); + } + } } // end of collision loop + + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); } PROCESS_SWITCH(skimmerPrimaryMuon, processMC_SA, "process reconstructed and MC info", false); - void processMC_TTCA(soa::Join const& collisions, aod::BCsWithTimestamps const&, MyTracksMC const& tracks, MFTTracksMC const&, aod::FwdTrackAssoc const& fwdtrackIndices) + void processMC_TTCA(soa::Join const& collisions, MyFwdTracksMC const& fwdtracks, MFTTracksMC const&, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices) { - for (auto& collision : collisions) { + findBestMatchPerMCHMID(fwdtracks); + + std::unordered_map mapAmb; // fwdtrack.globalIndex() -> bool isAmb; + for (const auto& fwdtrack : fwdtracks) { + 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) { + auto bc = collision.template bc_as(); + initCCDB(bc); + if (!collision.isSelected()) { + continue; + } if (!collision.has_mcCollision()) { continue; } - auto bc = collision.template foundBC_as(); + + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto fwdtrack = fwdtrackId.template fwdtrack_as(); + if (!fwdtrack.has_mcParticle()) { + continue; + } + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + continue; + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; + } + + if (!fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()])) { + continue; + } + + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()]); + } + } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, nullptr, mapAmb[fwdtrack.globalIndex()]); + } + } + } // end of collision loop + + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + mapAmb.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryMuon, processMC_TTCA, "process reconstructed and MC info", false); + + void processMC_TTCA_withMFTCov(soa::Join const& collisions, MyFwdTracksMC const& fwdtracks, MFTTracksMC const&, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices, aod::MFTTracksCov const& mftCovs) + { + for (const auto& mfttrackConv : mftCovs) { + map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + } + findBestMatchPerMCHMID(fwdtracks); + + std::unordered_map mapAmb; // fwdtrack.globalIndex() -> bool isAmb; + for (const auto& fwdtrack : fwdtracks) { + 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) { + auto bc = collision.template bc_as(); initCCDB(bc); - fRegistry.fill(HIST("Event/hCollisionCounter"), 0.f); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { + continue; + } + if (!collision.has_mcCollision()) { continue; } - - int counter = 0; - int offset = emprimarymuons.lastIndex() + 1; auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); - for (auto& fwdtrackId : fwdtrackIdsThisCollision) { - auto track = fwdtrackId.template fwdtrack_as(); - // LOGF(info, "TTCA | track.globalIndex() = %d, track.trackType() = %d, track.matchMFTTrackId() = %d, track.matchMCHTrackId() = %d, track.offsets() = %d", track.globalIndex(), track.trackType(), track.matchMFTTrackId(), track.matchMCHTrackId(), track.offsets()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto fwdtrack = fwdtrackId.template fwdtrack_as(); + if (!fwdtrack.has_mcParticle()) { + continue; + } + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + continue; + } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; + } - if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - if (fillQAHistogram) { - fillTrackHistogram<3>(track, collision); - } - if (isSelected(track, collision)) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.globalIndex())] = counter + offset; - counter++; - } - } else if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - auto sa_muon = tracks.iteratorAt(track.matchMCHTrackId()); - if (!sa_muon.has_mcParticle()) { - continue; - } - if (fillQAHistogram) { - fillTrackHistogram<0>(track, collision); - } - if (map_new_sa_muon_index.find(std::make_pair(collision.globalIndex(), track.matchMCHTrackId())) == map_new_sa_muon_index.end()) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.matchMCHTrackId())] = counter + offset; - counter++; - } - if (isSelected(track, collision)) { - map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.globalIndex())] = counter + offset; - counter++; - } + if (!fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()])) { + continue; } - } // end of track loop - for (const auto& [key, value] : map_new_sa_muon_index) { - // int collisionId = std::get<0>(key); - // int fwdtrackId = std::get<1>(key); - // int new_fwdtrackId = value; - auto track = tracks.iteratorAt(std::get<1>(key)); - if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - fillMuonTable(track, collision, value); - } else if (track.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - fillMuonTable(track, collision, map_new_sa_muon_index[std::make_pair(collision.globalIndex(), track.matchMCHTrackId())]); + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + multiMapGLMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); } - } + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + multiMapSAMuonsPerCollision.insert(std::make_pair(collision.globalIndex(), fwdtrack.globalIndex())); + } + + } // end of fwdtrack loop + } // end of collision loop - map_new_sa_muon_index.clear(); + for (const auto& collision : collisions) { + int count_samuons = multiMapSAMuonsPerCollision.count(collision.globalIndex()); + int count_glmuons = multiMapGLMuonsPerCollision.count(collision.globalIndex()); + if (fillQAHistograms) { + fRegistry.fill(HIST("MCHMID/hNmu"), count_samuons); + fRegistry.fill(HIST("MFTMCHMID/hNmu"), count_glmuons); + } + if (count_samuons >= minNmuon) { + auto range_samuons = multiMapSAMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_samuons.first; it != range_samuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()]); + } + } + if (count_glmuons >= minNmuon) { + auto range_glmuons = multiMapGLMuonsPerCollision.equal_range(collision.globalIndex()); + for (auto it = range_glmuons.first; it != range_glmuons.second; it++) { + auto fwdtrack = fwdtracks.rawIteratorAt(it->second); + fillFwdTrackTable(collision, fwdtrack, mftCovs, mapAmb[fwdtrack.globalIndex()]); + } + } } // end of collision loop + + multiMapSAMuonsPerCollision.clear(); + multiMapGLMuonsPerCollision.clear(); + mapAmb.clear(); + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); } - PROCESS_SWITCH(skimmerPrimaryMuon, processMC_TTCA, "process reconstructed and MC info with TTCA", false); + PROCESS_SWITCH(skimmerPrimaryMuon, processMC_TTCA_withMFTCov, "process reconstructed and MC with MFTCov info", false); + + void processDummy(aod::Collisions const&) {} + PROCESS_SWITCH(skimmerPrimaryMuon, processDummy, "process dummy", true); }; struct associateAmbiguousMuon { Produces em_amb_muon_ids; @@ -690,28 +1216,55 @@ struct associateAmbiguousMuon { void process(aod::EMPrimaryMuons const& muons) { - for (auto& muon : 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 (auto& amp_muon : muons_with_same_trackId) { - if (amp_muon.globalIndex() == muon.globalIndex()) { // don't store myself. + 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(amp_muon.globalIndex()); + 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; - // for (auto& muon : muons) { - // auto sa_muon = muon.template matchMCHTrack_as(); - // LOGF(info, "muon.collisionId() = %d , muon.globalIndex() = %d, muon.fwdtrackId() = %d , muon.trackType() = %d, muon.matchMCHTrackId() = %d, sa_muon.fwdtrackId() = %d", muon.collisionId(), muon.globalIndex(), muon.fwdtrackId(), muon.trackType(), muon.matchMCHTrackId(), sa_muon.fwdtrackId()); - // } + 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 { + em_same_mft_ids(std::vector{}); // empty for standalone muons + } + } // end of muon loop } }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-muon"}), - adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-muon"})}; + 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/skimmerPrimaryTrack.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryTrack.cxx new file mode 100644 index 00000000000..7dba6b78b36 --- /dev/null +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryTrack.cxx @@ -0,0 +1,468 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 tracks. +/// \author daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" + +#include "Common/Core/TableHelper.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/PIDResponseITS.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include + +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 MyCollisions = soa::Join; +using MyCollisionsWithSWT = soa::Join; + +using MyTracks = soa::Join; +using MyTrack = MyTracks::iterator; +using MyTracksMC = soa::Join; +using MyTrackMC = MyTracksMC::iterator; + +struct skimmerPrimaryTrack { + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + Produces emprimarytracks; + // Produces prmtrackeventidtmp; + + // 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 minpt{"minpt", 0.2, "min pt for ITS-TPC track"}; + Configurable maxpt{"maxpt", 5.0, "max pt for ITS-TPC track"}; + Configurable maxeta{"maxeta", 0.8, "eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 1.0, "max DCAxy in cm"}; + Configurable dca_z_max{"dca_z_max", 1.0, "max DCAz in cm"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + + // 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 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", 36.0, "max. chi2/NclsITS"}; + + 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, {{4000, -20, 20}}, 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/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/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, {{800, 0, 40}}, 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); + } + } + + 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 (!track.hasITS() || !track.hasTPC()) { + return false; + } + + if (track.itsChi2NCl() > 36.f) { + return false; + } + if (track.itsNCls() < 4) { + return false; + } + if (track.itsNClsInnerBarrel() < 1) { + return false; + } + + if (track.tpcChi2NCl() > 5.f) { + return false; + } + + if (track.tpcNClsFound() < 0) { + return false; + } + + if (track.tpcNClsCrossedRows() < 50) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < 0.8) { + return false; + } + + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (std::fabs(dcaXY) > dca_xy_max || std::fabs(dcaZ) > dca_z_max) { + return false; + } + if (std::fabs(dcaZ) > 3.f) { + return false; + } + + if (std::fabs(trackParCov.getEta()) > maxeta || trackParCov.getPt() < minpt || maxpt < trackParCov.getPt()) { + return false; + } + if (trackParCov.getPt() > 5.f) { + 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()) { + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + float pt = trackParCov.getPt(); + float eta = trackParCov.getEta(); + float phi = trackParCov.getPhi(); + o2::math_utils::bringTo02Pi(phi); + uint16_t trackBit = 0; + + // As minimal cuts, following cuts are applied. The cut values are hardcoded on the purpose for consistent bit operation. + // has info on ITS and TPC + // a hit on ITSib any + // Ncls ITS >= 4 + // chi2/Ncls ITS < 36 + // Ncr TPC >= 50 + // chi2/Ncls TPC < 5 + // Ncr/Nf ratio in TPC > 0.8 + + if (track.itsNCls() >= 5) { + trackBit |= static_cast(RefTrackBit::kNclsITS5); + } + if (track.itsNCls() >= 6) { + trackBit |= static_cast(RefTrackBit::kNclsITS6); + } + + if (track.tpcNClsCrossedRows() >= 70) { + trackBit |= static_cast(RefTrackBit::kNcrTPC70); + } + if (track.tpcNClsCrossedRows() >= 90) { + trackBit |= static_cast(RefTrackBit::kNcrTPC90); + } + if (track.tpcNClsFound() >= 50) { + trackBit |= static_cast(RefTrackBit::kNclsTPC50); + } + if (track.tpcNClsFound() >= 70) { + trackBit |= static_cast(RefTrackBit::kNclsTPC70); + } + if (track.tpcNClsFound() >= 90) { + trackBit |= static_cast(RefTrackBit::kNclsTPC90); + } + if (track.tpcChi2NCl() < 4.f) { + trackBit |= static_cast(RefTrackBit::kChi2TPC4); + } + if (track.tpcChi2NCl() < 3.f) { + trackBit |= static_cast(RefTrackBit::kChi2TPC3); + } + if (track.tpcFractionSharedCls() < 0.7) { + trackBit |= static_cast(RefTrackBit::kFracSharedTPC07); + } + + if (std::fabs(dcaZ) < 0.5) { + trackBit |= static_cast(RefTrackBit::kDCAz05cm); + } + if (std::fabs(dcaZ) < 0.3) { + trackBit |= static_cast(RefTrackBit::kDCAz03cm); + } + + if (std::fabs(dcaXY) < 0.5) { + trackBit |= static_cast(RefTrackBit::kDCAxy05cm); + } + if (std::fabs(dcaXY) < 0.3) { + trackBit |= static_cast(RefTrackBit::kDCAxy03cm); + } + + emprimarytracks(collision.globalIndex(), track.globalIndex(), track.sign() / pt, eta, phi, trackBit); + // prmtrackeventidtmp(collision.globalIndex()); + + stored_trackIds.emplace_back(std::pair{collision.globalIndex(), track.globalIndex()}); + + if (fillQAHistogram) { + fRegistry.fill(HIST("Track/hPt"), pt); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / pt); + fRegistry.fill(HIST("Track/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("Track/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), dcaXY / std::sqrt(trackParCov.getSigmaY2()), dcaZ / std::sqrt(trackParCov.getSigmaZ2())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), pt, std::sqrt(trackParCov.getSigmaY2()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), pt, std::sqrt(trackParCov.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/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + } + } + } + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + std::vector> stored_trackIds; + Filter trackFilter = o2::aod::track::itsChi2NCl < 36.f && o2::aod::track::tpcChi2NCl < 5.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; + using MyFilteredTracks = soa::Filtered; + + // ---------- 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.isEoI()) { // events with at least 1 lepton for data reduction. + continue; + } + + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!checkTrack(collision, track)) { + continue; + } + fillTrackTable(collision, track); + } + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryTrack, processRec, "process reconstructed info only", true); // standalone + + void processRec_SWT(MyCollisionsWithSWT 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.isEoI()) { // events with at least 1 lepton for data reduction. + continue; + } + if (collision.swtaliastmp_raw() == 0) { + continue; + } + + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!checkTrack(collision, track)) { + continue; + } + fillTrackTable(collision, track); + } + + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryTrack, processRec_SWT, "process reconstructed info only", false); // standalone with swt + + // ---------- for MC ---------- + + using MyFilteredTracksMC = soa::Filtered; + void processMC(soa::Join 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; + } + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!collision.isSelected()) { + continue; + } + if (!collision.isEoI()) { // events with at least 1 lepton for data reduction. + continue; + } + + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!checkTrack(collision, track)) { + continue; + } + fillTrackTable(collision, track); + } + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryTrack, processMC, "process reconstructed and MC info ", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-track"})}; +} diff --git a/PWGEM/Dilepton/TableProducer/skimmerSecondaryElectron.cxx b/PWGEM/Dilepton/TableProducer/skimmerSecondaryElectron.cxx deleted file mode 100644 index 1b48e7534a9..00000000000 --- a/PWGEM/Dilepton/TableProducer/skimmerSecondaryElectron.cxx +++ /dev/null @@ -1,620 +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 about primary electrons. -/// \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/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"}; - - 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);#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; on ITS #times cos(#lambda)", kTH1F, {{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.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_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"), 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 > slope * phiv + intercept) { // 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(), bc.timestamp(), - collision.posX(), collision.posY(), collision.posZ(), - collision.numContrib(), collision.trackOccupancyInTimeRange()); - event_mult(collision.multFT0A(), collision.multFT0C(), collision.multTPC(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); - event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); - } // 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 > slope * phiv + intercept) { // 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(), bc.timestamp(), - collision.posX(), collision.posY(), collision.posZ(), - collision.numContrib(), collision.trackOccupancyInTimeRange()); - event_mult(collision.multFT0A(), collision.multFT0C(), collision.multTPC(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); - event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); - } // 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.t(), mcCollision.impactParameter()); - 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 c1413a8aa68..f0aa4f1e9aa 100644 --- a/PWGEM/Dilepton/TableProducer/treeCreatorElectronML.cxx +++ b/PWGEM/Dilepton/TableProducer/treeCreatorElectronML.cxx @@ -14,29 +14,38 @@ // This code will create data table for inputs to machine learning for electrons. // Please write to: daiki.sekihata@cern.ch -#include -#include "Math/Vector4D.h" -#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 "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" -#include "DetectorsBase/Propagator.h" -#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 "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -64,10 +73,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 @@ -89,14 +97,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::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::TPCSignal, pidtpc::TPCNSigmaEl, /*pidtpc::TPCNSigmaMu,*/ pidtpc::TPCNSigmaPi, pidtpc::TPCNSigmaKa, pidtpc::TPCNSigmaPr, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, /*pidtof::TOFNSigmaMu,*/ pidtof::TOFNSigmaPi, pidtof::TOFNSigmaKa, pidtof::TOFNSigmaPr, track::TOFChi2, track::ITSChi2NCl, track::ITSClusterSizes, - track::TRDSignal, track::TRDPattern, mytrack::MCVx, mytrack::MCVy, mytrack::MCVz, mcparticle::PdgCode, mytrack::IsPhysicalPrimary, mytrack::MotherIds, mytrack::MotherPdgCodes); @@ -132,7 +139,7 @@ DECLARE_SOA_TABLE(MyPairs, "AOD", "MYPAIR", //! 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 @@ -163,7 +170,7 @@ struct TreeCreatorElectronML { HistogramRegistry registry{ "registry", { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{5, 0.5f, 5.5f}}}}, + {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{2, 0.f, 2.f}}}}, }, }; @@ -180,6 +187,11 @@ struct TreeCreatorElectronML { 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"}; @@ -189,8 +201,8 @@ struct TreeCreatorElectronML { 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 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"}; @@ -198,6 +210,10 @@ struct TreeCreatorElectronML { 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"}; @@ -257,7 +273,8 @@ struct TreeCreatorElectronML { fitter.setMatCorrType(matCorr); } - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + template + void initCCDB(TBC const& bc) { if (mRunNumber == bc.runNumber()) { return; @@ -306,102 +323,6 @@ struct TreeCreatorElectronML { } } - 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(); - - 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; - } - template int FindCommonMotherFrom2Prongs(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcparticles) { @@ -466,6 +387,15 @@ struct TreeCreatorElectronML { 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; } @@ -516,18 +446,14 @@ struct TreeCreatorElectronML { } template - void doPair(TTrack const& t1, TTrack const& t2, int pairtype, TMCParticles const& mctracks, TCollision const& collision, std::map& fNewLabels, std::vector& fSelected_old_labels, int& fCounter) + 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; } - if (!t1.has_mcParticle() || !t2.has_mcParticle()) { - return; - } - - auto mc1 = mctracks.iteratorAt(t1.mcParticleId()); - auto mc2 = mctracks.iteratorAt(t2.mcParticleId()); + auto mc1 = mctracks.iteratorAt(mc1_id); + auto mc2 = mctracks.iteratorAt(mc2_id); if (abs(mc1.pdgCode()) != 11 || abs(mc2.pdgCode()) != 11) { return; @@ -541,7 +467,7 @@ struct TreeCreatorElectronML { return; } - float phiv = get_phiv(t1, 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 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.); @@ -557,7 +483,6 @@ struct TreeCreatorElectronML { bool is_prompt = false; int pdgCode = 0; - int statusCode = 0; uint8_t flags = 0; float vx = 0.f; float vy = 0.f; @@ -572,7 +497,6 @@ struct TreeCreatorElectronML { auto mcpair = mctracks.iteratorAt(common_mother_id); is_prompt = true; // only relevant for prompt jpsi pdgCode = mcpair.pdgCode(); - statusCode = mcpair.statusCode(); flags = mcpair.flags(); vx = mcpair.vx(); vy = mcpair.vy(); @@ -617,181 +541,303 @@ struct TreeCreatorElectronML { fSelected_old_labels.push_back(t2.globalIndex()); fCounter++; } - mypair(mycollision.lastIndex(), fNewLabels[t1.globalIndex()], fNewLabels[t2.globalIndex()], + 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, statusCode, flags, + 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); + } + + if constexpr (isDerived) { + 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(),*/ 0, 0, 0, + track.tofChi2(), track.itsChi2NCl(), track.itsClusterSizes(), + mctrack.vx(), mctrack.vy(), mctrack.vz(), + mctrack.pdgCode(), mctrack.isPhysicalPrimary(), mothers_id, mothers_pdg); + } else { + 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; - if (downSample(abs(mctrack.pdgCode()))) { - mytrack(mycollision.lastIndex(), - track.sign(), track.pt(), track.eta(), track.phi(), 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(), - track.trdSignal(), track.trdPattern(), - mctrack.vx(), mctrack.vy(), mctrack.vz(), - mctrack.pdgCode(), mctrack.isPhysicalPrimary(), mothers_id, mothers_pdg); + for (auto& collision : collisions) { + if (!collision.has_emmcevent()) { + continue; + } + registry.fill(HIST("hEventCounter"), 0.5); + + 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) { - std::vector fSelected_old_labels; - // 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& [ele, pos] : combinations(CombinationsFullIndexPolicy(negTracks_coll, posTracks_coll))) { - doPair(pos, ele, EM_EEPairType::kULS, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter); + 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 (!doLS) { continue; } for (auto& [pos1, pos2] : combinations(CombinationsStrictlyUpperIndexPolicy(posTracks_coll, posTracks_coll))) { - doPair(pos1, pos2, EM_EEPairType::kLSpp, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter); + 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); } for (auto& [ele1, ele2] : combinations(CombinationsStrictlyUpperIndexPolicy(negTracks_coll, negTracks_coll))) { - doPair(ele1, ele2, EM_EEPairType::kLSnn, mctracks, collision, fNewLabels, fSelected_old_labels, fCounter); + 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); } // 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(); - // 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()); - } - } - } - mytrack(mycollision.lastIndex(), - track.sign(), track.pt(), track.eta(), track.phi(), 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(), - track.trdSignal(), track.trdPattern(), - mctrack.vx(), mctrack.vy(), mctrack.vz(), - mctrack.pdgCode(), mctrack.isPhysicalPrimary(), mothers_id, mothers_pdg); - - mothers_id.shrink_to_fit(); - mothers_pdg.shrink_to_fit(); + doSingleTrack(track, mctrack, mctracks, collision.globalIndex(), collisions_old_labels, collisions_counter, false); } // end of track loop } // end of collision loop + + 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); - void processDummy(soa::Join const&) {} - PROCESS_SWITCH(TreeCreatorElectronML, processDummy, "process dummy", true); + Partition posTracksSkimmed = o2::aod::emprimaryelectron::sign > static_cast(0); + Partition negTracksSkimmed = o2::aod::emprimaryelectron::sign < static_cast(0); + + void processPairSkimmed(MyFilteredCollisionsSkimmed const& collisions, MyFilteredTracksMCSkimmed const& tracks, aod::EMMCParticles const& mctracks, aod::EMMCEvents const&) + { + std::map fNewLabels; + int fCounter = 0; + + std::vector collisions_old_labels; + int collisions_counter = -1; + std::vector collisions_old_labels_track = {}; + int collisions_counter_track = -1; + + for (auto& collision : collisions) { + if (!collision.has_emmcevent()) { + continue; + } + registry.fill(HIST("hEventCounter"), 0.5); + + initCCDB(collision); + std::vector fSelected_old_labels; + + auto negTracks_coll = negTracksSkimmed->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + auto posTracks_coll = posTracksSkimmed->sliceByCached(o2::aod::emprimaryelectron::emeventId, collision.globalIndex(), cache); + + 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 (!pos1.has_emmcparticle() || !pos2.has_emmcparticle()) { + continue; + } + 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 (!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); + } + + // 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(); + + doSingleTrack(track, mctrack, mctracks, collision.globalIndex(), collisions_old_labels_track, collisions_counter_track, false); + + } // 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, 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 a3f25e08021..70a28bfc0d2 100644 --- a/PWGEM/Dilepton/TableProducer/treeCreatorElectronMLDDA.cxx +++ b/PWGEM/Dilepton/TableProducer/treeCreatorElectronMLDDA.cxx @@ -14,32 +14,43 @@ // This code will create data table for inputs to machine learning for electrons. // Please write to: daiki.sekihata@cern.ch -#include -#include -#include -#include "Math/Vector4D.h" -#include "DCAFitter/DCAFitterN.h" -#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 "PWGEM/Dilepton/DataModel/lmeeMLTables.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsCalibration/MeanVertexObject.h" #include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "PWGEM/Dilepton/DataModel/lmeeMLTables.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -47,169 +58,250 @@ 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 MyTracks = soa::Join; using MyTrack = MyTracks::iterator; struct TreeCreatorElectronMLDDA { - enum class EM_V0_Label : int { // Reconstructed V0 - kUndef = -1, - kGamma = 0, - kK0S = 1, - kLambda = 2, - kAntiLambda = 3, - }; - SliceCache cache; - Produces emprimarytracks; // flat table containing collision + track information + Produces emprimarytracks; // flat table containing collision + track information + Produces empidel; + Produces empidpi; + Produces empidka; + Produces empidpr; // Basic checks HistogramRegistry registry{ "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}}}}, - {"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}}}}, - - {"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}}}}, + {"Event/hEventCounter", "hEventCounter", {HistType::kTH1F, {{5, 0.5f, 5.5f}}}}, + {"Event/hNumContrib", "Number of contributors to PV;N_{contrib}^{PV};Entries", {HistType::kTH1F, {{65001, -0.5f, 65000.5f}}}}, + {"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, {{50, 0.f, 0.5f}}}}, + {"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.08, 1.18}}}}, + {"V0/hMassAntiLambda", "V0 mass AntiLambda", {HistType::kTH1F, {{100, 1.08, 1.18}}}}, + + {"V0/hTPCdEdx_P_El", "TPC dEdx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + {"V0/hTPCdEdx_P_Pi", "TPC dEdx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + {"V0/hTPCdEdx_P_Ka", "TPC dEdx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + {"V0/hTPCdEdx_P_Pr", "TPC dEdx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0, 5}, {200, 0, 200}}}}, + {"V0/hTOFbeta_P_El", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + {"V0/hTOFbeta_P_Pi", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + {"V0/hTOFbeta_P_Ka", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + {"V0/hTOFbeta_P_Pr", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0, 5}, {220, 0, 1.1}}}}, + {"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/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/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/hV0CosPA", "V0 cosine of pointing angle", {HistType::kTH1F, {{100, 0.99, 1.f}}}}, + {"Cascade/hV0PCA", "V0 distance between 2 legs", {HistType::kTH1F, {{50, 0.f, 0.5}}}}, + {"Cascade/hCosPA", "cascade cosine of pointing angle", {HistType::kTH1F, {{100, 0.99, 1.f}}}}, + {"Cascade/hPCA", "cascade distance between 2 legs", {HistType::kTH1F, {{50, 0.f, 0.5}}}}, + {"Cascade/hMassLambda", "V0 mass Lambda in cascade", {HistType::kTH1F, {{100, 1.08, 1.18}}}}, {"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_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}}}}, }, }; - // Configurables - // 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 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 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 minitsibncls{"minitsibncls", 1, "min. number of ITSib clusters"}; - Configurable minitsncls{"minitsncls", 4, "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 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 + Configurable d_bz_input{"d_bz_input", -999, "bz field, -999 is automatic"}; + Configurable useMatCorrType{"useMatCorrType", 2, "0: none, 1: TGeo, 2: LUT"}; + Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + // for zorro + Configurable cfg_swt_names{"cfg_swt_names", "fHighTrackMult,fHighFt0cFv0Mult", "comma-separated software trigger names"}; + o2::framework::Configurable ccdbPathSoftwareTrigger{"ccdbPathSoftwareTrigger", "EventFiltering/Zorro/", "ccdb path for ZORRO objects"}; + Configurable bcMarginForSoftwareTrigger{"bcMarginForSoftwareTrigger", 100, "Number of BCs of margin for software triggers"}; + Configurable cfgUseZorro{"cfgUseZorro", false, "flag to analyze software-triggered data"}; + + Configurable downscaling_electron_highP{"downscaling_electron_highP", 1.1, "down scaling factor to store electron at high p"}; + Configurable downscaling_pion_highP{"downscaling_pion_highP", 1.1, "down scaling factor to store pion at high p"}; + Configurable downscaling_kaon_highP{"downscaling_kaon_highP", 1.1, "down scaling factor to store kaon at high p"}; + Configurable downscaling_proton_highP{"downscaling_proton_highP", 1.1, "down scaling factor to store proton at high p"}; + + Configurable downscaling_electron_midP{"downscaling_electron_midP", 0.1, "down scaling factor to store electron at intermediate p"}; + + Configurable downscaling_electron_lowP{"downscaling_electron_lowP", 0.01, "down scaling factor to store electron at low p"}; + Configurable downscaling_pion_lowP{"downscaling_pion_lowP", 0.01, "down scaling factor to store pion at low p"}; + Configurable downscaling_kaon_lowP{"downscaling_kaon_lowP", 1.1, "down scaling factor to store kaon at low p"}; + Configurable downscaling_proton_lowP{"downscaling_proton_lowP", 0.01, "down scaling factor to store proton at low p"}; + + Configurable mid_p_for_downscaling_electron{"mid_p_for_downscaling_electron", 0.8, "intermediate p to apply down scaling factor to store electron"}; + + Configurable max_p_for_downscaling_electron{"max_p_for_downscaling_electron", 2.0, "max p to apply down scaling factor to store electron"}; + Configurable max_p_for_downscaling_pion{"max_p_for_downscaling_pion", 2.0, "max p to apply down scaling factor to store pion"}; + Configurable max_p_for_downscaling_kaon{"max_p_for_downscaling_kaon", 0.0, "max p to apply down scaling factor to store kaon"}; + Configurable max_p_for_downscaling_proton{"max_p_for_downscaling_proton", 2.0, "max p to apply down scaling factor to store proton"}; + Configurable store_ele_band_only{"store_ele_band_only", false, "flag to store tracks around electron band only to reduce output size"}; + + 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 cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF matched track contributes PV. + 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 "}; + Configurable cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; + } eventcuts; + + 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.113, "min mass for Lambda"}; + Configurable cfg_max_mass_lambda{"cfg_max_mass_lambda", 1.118, "max mass for Lambda"}; + + Configurable cfg_min_mass_k0s_veto{"cfg_min_mass_k0s_veto", 0.47, "min mass for K0S veto"}; + Configurable cfg_max_mass_k0s_veto{"cfg_max_mass_k0s_veto", 0.52, "max mass for K0S veto"}; + Configurable cfg_min_mass_lambda_veto{"cfg_min_mass_lambda_veto", 1.105, "min mass for Lambda veto"}; + Configurable cfg_max_mass_lambda_veto{"cfg_max_mass_lambda_veto", 1.125, "max mass for Lambda veto"}; + + Configurable cfg_min_cospa{"cfg_min_cospa", 0.9998, "min cospa for v0"}; + Configurable cfg_max_dcadau{"cfg_max_dcadau", 0.1, "max distance between 2 legs for v0"}; + Configurable cfg_min_qt_strangeness{"cfg_min_qt_strangeness", 0.02, "min qt for Lambda and K0S"}; + Configurable cfg_min_qt_k0s{"cfg_min_qt_k0s", 0.11, "min qt for K0S"}; + + 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_pid{"cfg_min_ncluster_tpc_pid", 0, "min ncluster tpc"}; + 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", 36.0, "max chi2/NclsITS"}; + Configurable cfg_min_chi2its{"cfg_min_chi2its", 0.0, "min chi2/NclsITS"}; // remove ITS afterburner + Configurable cfg_min_dcaxy_v0leg{"cfg_min_dcaxy_v0leg", 0.1, "min dca XY to PV for v0 legs in cm"}; + Configurable cfg_includeITSsa{"cfg_includeITSsa", false, "Flag to include ITSsa tracks"}; + Configurable cfg_max_pt_itssa{"cfg_max_pt_itssa", 0.15, "mix pt for ITSsa track"}; + + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -5, "min n sigma e in TPC"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +5, "max n sigma e in TPC"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -5, "min n sigma pi in TPC"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +5, "max n sigma pi in TPC"}; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -5, "min n sigma ka in TPC"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +5, "max n sigma ka in TPC"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -5, "min n sigma pr in TPC"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +5, "max n sigma pr in TPC"}; + + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -5, "min n sigma e in TOF"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +5, "max n sigma e in TOF"}; + Configurable cfg_min_TOFNsigmaPi{"cfg_min_TOFNsigmaPi", -5, "min n sigma pi in TOF"}; + Configurable cfg_max_TOFNsigmaPi{"cfg_max_TOFNsigmaPi", +5, "max n sigma pi in TOF"}; + Configurable cfg_min_TOFNsigmaKa{"cfg_min_TOFNsigmaKa", -5, "min n sigma ka in TOF"}; + Configurable cfg_max_TOFNsigmaKa{"cfg_max_TOFNsigmaKa", +5, "max n sigma ka in TOF"}; + Configurable cfg_min_TOFNsigmaPr{"cfg_min_TOFNsigmaPr", -5, "min n sigma pr in TOF"}; + Configurable cfg_max_TOFNsigmaPr{"cfg_max_TOFNsigmaPr", +5, "max n sigma pr in TOF"}; + } v0cuts; + + struct : ConfigurableGroup { + std::string prefix = "tightv0cut_group"; + 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", 80, "min ncrossed rows"}; + Configurable cfg_min_ncluster_tpc_pid{"cfg_min_ncluster_tpc_pid", 60, "min ncluster tpc"}; + 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", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 5.0, "max chi2/NclsITS"}; + Configurable cfg_min_chi2its{"cfg_min_chi2its", -1e+10, "min chi2/NclsITS"}; // remove ITS afterburner + Configurable cfg_max_chi2tof{"cfg_max_chi2tof", 1e+10, "max chi2 TOF"}; // distance in cm + + Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2, "min n sigma e in TPC for pc->ee"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +2, "max n sigma e in TPC for pc->ee"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -2, "min n sigma e in TOF for pc->ee"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +2, "max n sigma e in TOF for pc->ee"}; + + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -2, "min n sigma pi in TPC for Lambda and cascade"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +2, "max n sigma pi in TPC for Lambda and cascade"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -2, "min n sigma pr in TPC for cascade"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +2, "max n sigma pr in TPC for cascade"}; + + Configurable cfg_min_TOFNsigmaPi{"cfg_min_TOFNsigmaPi", -2, "min n sigma pi in TOF for Lambda and cascade"}; + Configurable cfg_max_TOFNsigmaPi{"cfg_max_TOFNsigmaPi", +2, "max n sigma pi in TOF for Lambda and cascade"}; + Configurable cfg_min_TOFNsigmaPr{"cfg_min_TOFNsigmaPr", -2, "min n sigma pr in TOF for cascade"}; + Configurable cfg_max_TOFNsigmaPr{"cfg_max_TOFNsigmaPr", +2, "max n sigma pr in TOF for cascade"}; + } tightv0cuts; + + 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_veto{"cfg_min_mass_Xi_veto", 1.31, "min mass for Xi veto"}; + Configurable cfg_max_mass_Xi_veto{"cfg_max_mass_Xi_veto", 1.33, "max mass for Xi veto"}; + Configurable cfg_min_mass_Omega{"cfg_min_mass_Omega", 1.669, "min mass for Omega"}; + Configurable cfg_max_mass_Omega{"cfg_max_mass_Omega", 1.675, "max mass for Omega"}; + Configurable cfg_min_cospa_v0{"cfg_min_cospa_v0", 0.995, "minimum V0 CosPA in cascade"}; + Configurable cfg_max_dcadau_v0{"cfg_max_dcadau_v0", 0.1, "max distance between V0 Daughters in cascade"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.9998, "minimum cascade CosPA"}; + Configurable cfg_max_dcadau{"cfg_max_dcadau", 0.1, "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.05, "min dca XY for bachelor in cm"}; + Configurable cfg_min_dcaxy_v0{"cfg_min_dcaxy_v0", 0.05, "min dca XY for V0 in cm"}; + } cascadecuts; + + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadronPID, 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"}; 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; + o2::aod::rctsel::RCTFlagsChecker rctChecker; + ctpRateFetcher mRateFetcher; + Zorro zorro; std::mt19937 engine; std::uniform_real_distribution dist01; @@ -218,14 +310,14 @@ 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); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + rctChecker.init(cfgRCTLabel.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + if (useMatCorrType == 1) { LOGF(info, "TGeo correction requested, loading geometry"); if (!o2::base::GeometryManager::isGeometryLoaded()) { @@ -237,22 +329,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); @@ -264,15 +340,31 @@ struct TreeCreatorElectronMLDDA { return; } + if (cfgUseZorro) { + zorro.setCCDBpath(ccdbPathSoftwareTrigger); + zorro.setBCtolerance(bcMarginForSoftwareTrigger); // this does nothing. + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + + // 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; } @@ -284,6 +376,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"; @@ -293,752 +387,629 @@ 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) - { - 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)); } - EM_V0_Label checkV0(const float alpha, const float qt) + template + float meanClusterSizeITS(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; - } - - // 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; - } - - // 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; + 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++; + } } - - // 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 (nl > 0) { + return static_cast(total_size) / static_cast(nl); + } else { + return 0.f; } - - return EM_V0_Label::kUndef; } - template - bool IsSelected(TTrack const& track) + template + bool isSelectedV0Leg(TCollision const& collision, TTrack const& track) { - if (abs(track.eta()) > maxeta || track.pt() < minpt) { + if (!track.hasITS()) { return false; } - if (!track.hasITS() || !track.hasTPC()) { + if (track.itsNCls() < v0cuts.cfg_min_ncluster_its) { return false; } - - if (track.itsNClsInnerBarrel() < minitsibncls) { + if (track.itsNClsInnerBarrel() < v0cuts.cfg_min_ncluster_itsib) { return false; } - if (track.itsNCls() < minitsncls) { + if (track.itsChi2NCl() < v0cuts.cfg_min_chi2its || v0cuts.cfg_max_chi2its < track.itsChi2NCl()) { return false; } - if (track.itsChi2NCl() > maxchi2its) { + + if (!v0cuts.cfg_includeITSsa && (!track.hasITS() || !track.hasTPC())) { return false; } - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; + if (track.hasTPC()) { + if (track.tpcNClsCrossedRows() < v0cuts.cfg_min_ncrossedrows_tpc) { + return false; + } + if (track.tpcNClsFound() < v0cuts.cfg_min_ncluster_tpc) { + return false; + } + 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.tpcNClsPID() < v0cuts.cfg_min_ncluster_tpc_pid) { + return false; + } } - if (track.tpcChi2NCl() > maxchi2tpc) { + + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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, trackParCov, 2.f, matCorr, &mDcaInfoCov); + // float dcaXY = mDcaInfoCov.getY(); + // float dcaZ = mDcaInfoCov.getZ(); + + // if (std::fabs(dcaXY) < v0cuts.cfg_min_dcaxy_v0leg) { // this is applied in filter. + // return false; + // } + + if (std::fabs(trackParCov.getEta()) > v0cuts.cfg_max_eta || trackParCov.getPt() < v0cuts.cfg_min_pt) { return false; } - if (track.tpcCrossedRowsOverFindableCls() < 0.8) { - return false; + + if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && v0cuts.cfg_max_pt_itssa < track.pt()) { + return true; } + return true; } - template - bool IsSelectedTag(TTrack const& track) + template + bool isSelectedV0LegTight(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() < tightv0cuts.cfg_min_ncluster_its) { return false; } - - if (abs(track.dcaXY()) > 0.1 || abs(track.dcaZ()) > 0.1) { + if (track.itsNClsInnerBarrel() < tightv0cuts.cfg_min_ncluster_itsib) { + return false; + } + if (track.itsChi2NCl() < tightv0cuts.cfg_min_chi2its || tightv0cuts.cfg_max_chi2its < track.itsChi2NCl()) { return false; } - if (track.itsNCls() < 5) { + if (track.tpcNClsCrossedRows() < tightv0cuts.cfg_min_ncrossedrows_tpc) { return false; } - if (track.itsChi2NCl() > 5.f) { + if (track.tpcNClsFound() < tightv0cuts.cfg_min_ncluster_tpc) { return false; } - - if (track.tpcNClsCrossedRows() < 100) { + if (track.tpcChi2NCl() < 0.f || tightv0cuts.cfg_max_chi2tpc < track.tpcChi2NCl()) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < tightv0cuts.cfg_min_cr2findable_ratio_tpc) { + return false; + } + if (track.tpcFractionSharedCls() > tightv0cuts.cfg_max_frac_shared_clusters_tpc) { return false; } - if (track.tpcChi2NCl() > 4.f) { + if (track.tpcNClsPID() < tightv0cuts.cfg_min_ncluster_tpc_pid) { return false; } - if (track.tpcCrossedRowsOverFindableCls() < 0.8) { + + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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, trackParCov, 2.f, matCorr, &mDcaInfoCov); + // float dcaXY = mDcaInfoCov.getY(); + // float dcaZ = mDcaInfoCov.getZ(); + + // if (std::fabs(dcaXY) < v0cuts.cfg_min_dcaxy_v0leg) { // this is applied in filter. + // return false; + // } + + if (std::fabs(trackParCov.getEta()) > v0cuts.cfg_max_eta || trackParCov.getPt() < v0cuts.cfg_min_pt) { 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); + if (v0cuts.cfg_includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) { + return true; + } + 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 (v0cuts.cfg_includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) { + return true; } - 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 isKaon(TTrack const& track) + { + if (v0cuts.cfg_includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) { + return true; } + 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 IsPion(TTrack const& track) + bool isProton(TTrack const& track) { - return abs(track.tpcNSigmaPi()) < maxTPCNsigmaPi && (abs(track.tofNSigmaPi()) < maxTOFNsigmaPi || track.beta() < 0.f); + if (v0cuts.cfg_includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) { + return true; + } + 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 isElectronTight(TTrack const& track) + { + bool is_El_TPC = tightv0cuts.cfg_min_TPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < tightv0cuts.cfg_max_TPCNsigmaEl; + bool is_El_TOF = track.hasTOF() ? tightv0cuts.cfg_min_TOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < tightv0cuts.cfg_max_TOFNsigmaEl : true; // TOFif + return is_El_TPC && is_El_TOF; } template - bool IsKaon(TTrack const& track) + bool isPionTight(TTrack const& track) { - return abs(track.tpcNSigmaKa()) < maxTPCNsigmaKa && (abs(track.tofNSigmaKa()) < maxTOFNsigmaKa || track.beta() < 0.f); + bool is_Pi_TPC = tightv0cuts.cfg_min_TPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < tightv0cuts.cfg_max_TPCNsigmaPi; + bool is_Pi_TOF = track.hasTOF() ? tightv0cuts.cfg_min_TOFNsigmaPi < track.tofNSigmaPi() && track.tofNSigmaPi() < tightv0cuts.cfg_max_TOFNsigmaPi : true; // TOFif + return is_Pi_TPC && is_Pi_TOF; } template - bool IsProton(TTrack const& track) + bool isProtonTight(TTrack const& track) { - return abs(track.tpcNSigmaPr()) < maxTPCNsigmaPr && (abs(track.tofNSigmaPr()) < maxTOFNsigmaPr || track.beta() < 0.f); + bool is_Pr_TPC = tightv0cuts.cfg_min_TPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < tightv0cuts.cfg_max_TPCNsigmaPr; + bool is_Pr_TOF = track.hasTOF() ? tightv0cuts.cfg_min_TOFNsigmaPr < track.tofNSigmaPr() && track.tofNSigmaPr() < tightv0cuts.cfg_max_TOFNsigmaPr : true; // TOFif + return is_Pr_TPC && is_Pr_TOF; + } + + template + bool isPionTightTOFreq(TTrack const& track) + { + // only for K0S-> pi+ pi- + bool is_Pi_TPC = tightv0cuts.cfg_min_TPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < tightv0cuts.cfg_max_TPCNsigmaPi; + bool is_Pi_TOF = tightv0cuts.cfg_min_TOFNsigmaPi < track.tofNSigmaPi() && track.tofNSigmaPi() < tightv0cuts.cfg_max_TOFNsigmaPi && std::fabs(track.tofChi2()) < tightv0cuts.cfg_max_chi2tof; // TOFreq + return is_Pi_TPC && is_Pi_TOF; } template - void fillTrackTable(TCollision const& collision, TTrack const& track, const int pidlabel, const int tracktype) + void fillTrackTable(TCollision const& collision, TTrack const& track, const uint8_t pidlabel, const float hadronicRate) { + if (store_ele_band_only && !isElectron(track)) { + return; + } + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + // trackParCov.setPID(track.pidForTracking()); + trackParCov.setPID(o2::track::PID::Electron); // This is for eID in the end! + 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, trackParCov, 2.f, matCorr, &mDcaInfoCov); + // float dcaXY = mDcaInfoCov.getY(); + // float dcaZ = mDcaInfoCov.getZ(); + + if (pidlabel == static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kElectron)) { + if (track.tpcInnerParam() < mid_p_for_downscaling_electron) { + if (dist01(engine) > downscaling_electron_lowP) { + return; + } + } else if (track.tpcInnerParam() < max_p_for_downscaling_electron) { + if (dist01(engine) > downscaling_electron_midP) { + return; + } + } else { + if (dist01(engine) > downscaling_electron_highP) { + return; + } + } + } else if (pidlabel == static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kPion)) { + if (track.tpcInnerParam() < max_p_for_downscaling_pion) { + if (dist01(engine) > downscaling_pion_lowP) { + return; + } + } else { + if (dist01(engine) > downscaling_pion_highP) { + return; + } + } + } else if (pidlabel == static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kKaon)) { + if (track.tpcInnerParam() < max_p_for_downscaling_kaon) { + if (dist01(engine) > downscaling_kaon_lowP) { + return; + } + } else { + if (dist01(engine) > downscaling_kaon_highP) { + return; + } + } + } else if (pidlabel == static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kProton)) { + if (track.tpcInnerParam() < max_p_for_downscaling_proton) { + if (dist01(engine) > downscaling_proton_lowP) { + return; + } + } else { + if (dist01(engine) > downscaling_proton_highP) { + return; + } + } + } + if (std::find(stored_trackIds.begin(), stored_trackIds.end(), track.globalIndex()) == stored_trackIds.end()) { - 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(), - track.tpcNClsFindable(), track.tpcNClsFound(), track.tpcNClsCrossedRows(), + emprimarytracks(collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), hadronicRate, + trackParCov.getP(), trackParCov.getTgl(), track.sign(), + track.tpcNClsFindable(), track.tpcNClsFound(), track.tpcNClsCrossedRows(), track.tpcNClsPID(), 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.tpcSignal(), + track.beta(), + track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap(), pidlabel); + + empidel(track.tpcNSigmaEl(), track.tofNSigmaEl()); + empidpi(track.tpcNSigmaPi(), track.tofNSigmaPi()); + empidka(track.tpcNSigmaKa(), track.tofNSigmaKa()); + empidpr(track.tpcNSigmaPr(), track.tofNSigmaPr()); + 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; + 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.cfgRequireVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + + if (eventcuts.cfgRequireVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + 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; + } + + //! 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&& 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 && 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_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; + Filter collisionFilter_numContrib = eventcuts.cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < eventcuts.cfgNumContribMax; + 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; + Partition negTracks = o2::aod::track::signed1Pt < 0.f && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == 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) { - registry.fill(HIST("hEventCounter"), 1.0); // all + for (const auto& collision : collisions) { + registry.fill(HIST("Event/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)) { + if (!isSelectedEvent(collision)) { continue; } - std::array pVtx = {collision.posX(), collision.posY(), collision.posZ()}; + if (cfgUseZorro && !zorro.isSelected(bc.globalBC(), bcMarginForSoftwareTrigger)) { + continue; + } + + if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + registry.fill(HIST("Event/hEventCounter"), 2.0); // selected + registry.fill(HIST("Event/hNumContrib"), collision.numContrib()); + + float hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * 1.e-3; // kHz + 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 o2v0 = v0.template v0_as(); auto pos = v0.template posTrack_as(); auto neg = v0.template negTrack_as(); - if (!IsSelected(pos) || !IsSelected(neg)) { - continue; - } - if (pos.sign() * neg.sign() > 0) { - continue; - } + // LOGF(info, "v0.globalIndex() = %d, v0.collisionId() = %d, v0.posTrackId() = %d, v0.negTrackId() = %d", v0.globalIndex(), v0.collisionId(), v0.posTrackId(), v0.negTrackId()); + // LOGF(info, "is pos ITSsa = %d", pos.hasITS() && !pos.hasTPC() && !pos.hasTRD() && !pos.hasTOF()); + // LOGF(info, "is neg ITSsa = %d", neg.hasITS() && !neg.hasTPC() && !neg.hasTRD() && !neg.hasTOF()); - // 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) { + if (v0.dcaV0daughters() > v0cuts.cfg_max_dcadau) { 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; - } - - // 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) { + if (pos.sign() * neg.sign() > 0) { continue; } - if (v0CosinePA < minv0cospa) { + if (!isSelectedV0Leg(collision, pos) || !isSelectedV0Leg(collision, neg)) { 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 (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 (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/hPCA"), v0.dcaV0daughters()); + registry.fill(HIST("V0/hCosPA"), v0.v0cosPA()); + registry.fill(HIST("V0/hAP"), v0.alpha(), v0.qtarm()); + + if (v0cuts.cfg_min_qt_strangeness < v0.qtarm()) { + if (v0cuts.cfg_min_qt_k0s < v0.qtarm()) { + if (!(v0cuts.cfg_min_mass_lambda_veto < v0.mLambda() && v0.mLambda() < v0cuts.cfg_max_mass_lambda_veto) && !(v0cuts.cfg_min_mass_lambda_veto < v0.mAntiLambda() && v0.mAntiLambda() < v0cuts.cfg_max_mass_lambda_veto)) { + if ((isPionTightTOFreq(pos) && isSelectedV0LegTight(collision, pos)) && (isPion(neg) && isSelectedV0Leg(collision, 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.tpcInnerParam(), neg.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Pi"), neg.tpcInnerParam(), neg.beta()); + fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kPion), hadronicRate); + } + } + if (isPion(pos) && isSelectedV0Leg(collision, pos) && isPionTightTOFreq(neg) && isSelectedV0LegTight(collision, 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"), pos.tpcInnerParam(), pos.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Pi"), pos.tpcInnerParam(), pos.beta()); + fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kPion), hadronicRate); + } + } + } // end of K0S } - } else if (v0id == EM_V0_Label::kLambda && (IsProton(pos) && IsPion(neg))) { - registry.fill(HIST("hMassLambda"), mLambda); - if (abs(mLambda - 1.115) < 0.005) { - 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)); - } - } - } 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 (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()); - } - } - } // 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; - } + if (!(v0cuts.cfg_min_mass_k0s_veto < v0.mK0Short() && v0.mK0Short() < v0cuts.cfg_max_mass_k0s_veto)) { + if (isProton(pos) && isSelectedV0Leg(collision, pos) && isPionTight(neg) && isSelectedV0LegTight(collision, neg)) { + registry.fill(HIST("V0/hMassLambda"), v0.mLambda()); + if (v0cuts.cfg_min_mass_lambda < v0.mLambda() && v0.mLambda() < v0cuts.cfg_max_mass_lambda) { + fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kProton), hadronicRate); + registry.fill(HIST("V0/hTPCdEdx_P_Pr"), pos.tpcInnerParam(), pos.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Pr"), pos.tpcInnerParam(), pos.beta()); + } + } // end of Lambda + if (isPionTight(pos) && isSelectedV0LegTight(collision, pos) && isProton(neg) && isSelectedV0Leg(collision, neg)) { + registry.fill(HIST("V0/hMassAntiLambda"), v0.mAntiLambda()); + if (v0cuts.cfg_min_mass_lambda < v0.mAntiLambda() && v0.mAntiLambda() < v0cuts.cfg_max_mass_lambda) { + fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kProton), hadronicRate); + registry.fill(HIST("V0/hTPCdEdx_P_Pr"), neg.tpcInnerParam(), neg.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Pr"), neg.tpcInnerParam(), neg.beta()); + } + } // end of AntiLambda + } - 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); - registry.fill(HIST("hMvsPhiV"), phiv, v12.M()); + } // end of stangeness - 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 (isElectronTight(pos) && isSelectedV0LegTight(collision, pos) && isElectron(neg) && isSelectedV0Leg(collision, neg)) { + registry.fill(HIST("V0/hMassGamma"), v0.mGamma()); + 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) { + registry.fill(HIST("V0/hXY_Gamma"), v0.x(), v0.y()); + fillTrackTable(collision, neg, static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kElectron), hadronicRate); + registry.fill(HIST("V0/hTPCdEdx_P_El"), neg.tpcInnerParam(), neg.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_El"), neg.tpcInnerParam(), neg.beta()); } - 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 photon conversion + + if (isElectron(pos) && isSelectedV0Leg(collision, pos) && isElectronTight(neg) && isSelectedV0LegTight(collision, neg)) { + registry.fill(HIST("V0/hMassGamma"), v0.mGamma()); + 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) { + registry.fill(HIST("V0/hXY_Gamma"), v0.x(), v0.y()); + fillTrackTable(collision, pos, static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kElectron), hadronicRate); + registry.fill(HIST("V0/hTPCdEdx_P_El"), pos.tpcInnerParam(), pos.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_El"), pos.tpcInnerParam(), 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)); - } - 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)); - } - } - } // end of ULS pair loop - - auto tracks_coll = tracks.sliceBy(perCollision_track, collision.globalIndex()); - for (auto& track : tracks_coll) { - if (!IsSelectedTag(track)) { - continue; - } + } // end of photon conversion - 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 + } // end of v0 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)) { - continue; - } - + auto pos = cascade.template posTrack_as(); + auto neg = cascade.template negTrack_as(); if (pos.sign() * neg.sign() > 0) { 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) { + if (!(cascadecuts.cfg_min_mass_lambda < cascade.mLambda() && cascade.mLambda() < cascadecuts.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); - - if (v0dca_casc > maxdcav0dau_casc) { - continue; - } - if (v0CosinePA_casc < minv0cospa_casc) { + if (cascade.dcaV0daughters() > cascadecuts.cfg_max_dcadau_v0) { continue; } - if (bachelor.sign() < 0 && abs(mLambda - 1.115) > 0.005) { + if (cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadecuts.cfg_min_cospa_v0) { continue; } - if (bachelor.sign() > 0 && abs(mAntiLambda - 1.115) > 0.005) { + if (cascade.v0radius() < cascadecuts.cfg_min_rxy_v0) { 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) { + if (cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadecuts.cfg_min_cospa) { continue; } - if (casc_cpa < min_casc_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)); - // } - // } - } - 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 (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 + if (cascade.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) < cascadecuts.cfg_min_dcaxy_v0) { continue; } - if (!IsSelected(pos) || !IsElectron(pos)) { + if (!isSelectedV0LegTight(collision, pos) || !isSelectedV0LegTight(collision, neg) || !isSelectedV0Leg(collision, bachelor)) { 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); - 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)); - } + registry.fill(HIST("Cascade/hMassLambda"), cascade.mLambda()); + 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())); + + 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/hRxy_Xi"), cascade.mXi(), cascade.cascradius()); + registry.fill(HIST("Cascade/hCTau_Xi"), cascade.mXi(), ctauXi); } - } // 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 = 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); - 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)); + if (!(cascadecuts.cfg_min_mass_Xi_veto < cascade.mXi() && cascade.mXi() < cascadecuts.cfg_max_mass_Xi_veto) && 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/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.tpcInnerParam(), bachelor.tpcSignal()); + registry.fill(HIST("V0/hTOFbeta_P_Ka"), bachelor.tpcInnerParam(), bachelor.beta()); + fillTrackTable(collision, bachelor, static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kKaon), hadronicRate); } } - } // 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 = 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); - 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 = 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); - 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 - + } // end of cascade 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, processDummy, "process dummy", true); + PROCESS_SWITCH(TreeCreatorElectronMLDDA, processPID, "produce ML input for single track level", true); // 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", false); }; struct MLTrackQC { @@ -1046,66 +1017,72 @@ struct MLTrackQC { HistogramRegistry registry{ "registry", { - {"hTPCdEdx_P_All", "TPC dE/dx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0.f, 5.f}, {200, 0, 200}}}}, - {"hTOFbeta_P_All", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0.f, 5.f}, {220, 0.0, 1.1}}}}, - {"hITSClusterSize_P_All", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {64, 0.0, 16}}}}, - {"hTPCdEdx_P_Electron", "TPC dE/dx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0.f, 5.f}, {200, 0, 200}}}}, - {"hTOFbeta_P_Electron", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0.f, 5.f}, {220, 0.0, 1.1}}}}, - {"hITSClusterSize_P_Electron", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {64, 0.0, 16}}}}, - {"hTPCdEdx_P_Pion", "TPC dE/dx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0.f, 5.f}, {200, 0, 200}}}}, - {"hTOFbeta_P_Pion", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0.f, 5.f}, {220, 0.0, 1.1}}}}, - {"hITSClusterSize_P_Pion", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {64, 0.0, 16}}}}, - {"hTPCdEdx_P_Kaon", "TPC dE/dx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0.f, 5.f}, {200, 0, 200}}}}, - {"hTOFbeta_P_Kaon", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0.f, 5.f}, {220, 0.0, 1.1}}}}, - {"hITSClusterSize_P_Kaon", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {64, 0.0, 16}}}}, - {"hTPCdEdx_P_Proton", "TPC dE/dx vs. p;p^{ITS-TPC} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{500, 0.f, 5.f}, {200, 0, 200}}}}, - {"hTOFbeta_P_Proton", "TOF beta vs. p;p^{ITS-TPC} (GeV/c);TOF #beta", {HistType::kTH2F, {{500, 0.f, 5.f}, {220, 0.0, 1.1}}}}, - {"hITSClusterSize_P_Proton", "mean ITS cluster size vs. p;p^{ITS-TPC} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{500, 0.f, 5.f}, {64, 0.0, 16}}}}, - - {"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}}}}, - {"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}}}}, - {"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}}}}, + {"hTPCdEdx_P_All", "TPC dE/dx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0, 200}}}}, + {"hTOFbeta_P_All", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 10.f}, {220, 0.0, 1.1}}}}, + {"hITSobClusterSize_P_All", "mean ITSob cluster size vs. p;p_{in} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{1000, 0.f, 10.f}, {150, 0.0, 15}}}}, + {"hTPCdEdx_P_Electron", "TPC dE/dx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0, 200}}}}, + {"hTOFbeta_P_Electron", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 10.f}, {220, 0.0, 1.1}}}}, + {"hITSobClusterSize_P_Electron", "mean ITSob cluster size vs. p;p_{in} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{1000, 0.f, 10.f}, {150, 0.0, 15}}}}, + {"hTPCdEdx_P_Pion", "TPC dE/dx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0, 200}}}}, + {"hTOFbeta_P_Pion", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 10.f}, {220, 0.0, 1.1}}}}, + {"hITSobClusterSize_P_Pion", "mean ITSob cluster size vs. p;p_{in} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{1000, 0.f, 10.f}, {150, 0.0, 15}}}}, + {"hTPCdEdx_P_Kaon", "TPC dE/dx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0, 200}}}}, + {"hTOFbeta_P_Kaon", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 10.f}, {220, 0.0, 1.1}}}}, + {"hITSobClusterSize_P_Kaon", "mean ITSob cluster size vs. p;p_{in} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{1000, 0.f, 10.f}, {150, 0.0, 15}}}}, + {"hTPCdEdx_P_Proton", "TPC dE/dx vs. p;p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0, 200}}}}, + {"hTOFbeta_P_Proton", "TOF beta vs. p;p_{in} (GeV/c);TOF #beta", {HistType::kTH2F, {{1000, 0.f, 10.f}, {220, 0.0, 1.1}}}}, + {"hITSobClusterSize_P_Proton", "mean ITSob cluster size vs. p;p_{in} (GeV/c); #times cos(#lambda)", {HistType::kTH2F, {{1000, 0.f, 10.f}, {150, 0.0, 15}}}}, + + {"hTPCNsigmaEl_P", "TPC n#sigma_{e} vs. p;p_{in} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5, +5}}}}, + {"hTPCNsigmaPi_P", "TPC n#sigma_{#pi} vs. p;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5, +5}}}}, + {"hTPCNsigmaKa_P", "TPC n#sigma_{K} vs. p;p_{in} (GeV/c);n #sigma_{K}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5, +5}}}}, + {"hTPCNsigmaPr_P", "TPC n#sigma_{p} vs. p;p_{in} (GeV/c);n #sigma_{p}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5, +5}}}}, + {"hTOFNsigmaEl_P", "TOF n#sigma_{e} vs. p;p_{in} (GeV/c);n #sigma_{e}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5, +5}}}}, + {"hTOFNsigmaPi_P", "TOF n#sigma_{#pi} vs. p;p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5, +5}}}}, + {"hTOFNsigmaKa_P", "TOF n#sigma_{K} vs. p;p_{in} (GeV/c);n #sigma_{K}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5, +5}}}}, + {"hTOFNsigmaPr_P", "TOF n#sigma_{p} vs. p;p_{in} (GeV/c);n #sigma_{p}^{TOF}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5, +5}}}}, }, }; - void process(aod::EMPrimaryTracks const& tracks) + using MyPIDTracks = soa::Join; + + void processQC(MyPIDTracks const& tracks) { - for (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()))); - if (track.pidlabel() == static_cast(o2::aod::pwgem::dilepton::PID_Label::kElectron)) { - registry.fill(HIST("hTPCdEdx_P_Electron"), track.p(), track.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Electron"), track.p(), track.beta()); - registry.fill(HIST("hITSClusterSize_P_Electron"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); - registry.fill(HIST("hTPCNsigmaEl_P"), track.p(), track.tpcNSigmaEl()); - registry.fill(HIST("hTOFNsigmaEl_P"), track.p(), track.tofNSigmaEl()); - } else if (track.pidlabel() == static_cast(o2::aod::pwgem::dilepton::PID_Label::kPion)) { - registry.fill(HIST("hTPCdEdx_P_Pion"), track.p(), track.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Pion"), track.p(), track.beta()); - registry.fill(HIST("hITSClusterSize_P_Pion"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); - registry.fill(HIST("hTPCNsigmaPi_P"), track.p(), track.tpcNSigmaPi()); - registry.fill(HIST("hTOFNsigmaPi_P"), track.p(), track.tofNSigmaPi()); - } else if (track.pidlabel() == static_cast(o2::aod::pwgem::dilepton::PID_Label::kKaon)) { - registry.fill(HIST("hTPCdEdx_P_Kaon"), track.p(), track.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Kaon"), track.p(), track.beta()); - registry.fill(HIST("hITSClusterSize_P_Kaon"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); - registry.fill(HIST("hTPCNsigmaKa_P"), track.p(), track.tpcNSigmaKa()); - registry.fill(HIST("hTOFNsigmaKa_P"), track.p(), track.tofNSigmaKa()); - } else if (track.pidlabel() == static_cast(o2::aod::pwgem::dilepton::PID_Label::kProton)) { - registry.fill(HIST("hTPCdEdx_P_Proton"), track.p(), track.tpcSignal()); - registry.fill(HIST("hTOFbeta_P_Proton"), track.p(), track.beta()); - registry.fill(HIST("hITSClusterSize_P_Proton"), track.p(), track.meanClusterSizeITS() * std::cos(std::atan(track.tgl()))); - registry.fill(HIST("hTPCNsigmaPr_P"), track.p(), track.tpcNSigmaPr()); - registry.fill(HIST("hTOFNsigmaPr_P"), track.p(), track.tofNSigmaPr()); + for (const auto& track : tracks) { + registry.fill(HIST("hTPCdEdx_P_All"), track.tpcInnerParam(), track.tpcSignal()); + registry.fill(HIST("hTOFbeta_P_All"), track.tpcInnerParam(), track.beta()); + registry.fill(HIST("hITSobClusterSize_P_All"), track.tpcInnerParam(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + if (track.pidlabel() == static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kElectron)) { + registry.fill(HIST("hTPCdEdx_P_Electron"), track.tpcInnerParam(), track.tpcSignal()); + registry.fill(HIST("hTOFbeta_P_Electron"), track.tpcInnerParam(), track.beta()); + registry.fill(HIST("hITSobClusterSize_P_Electron"), track.tpcInnerParam(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + registry.fill(HIST("hTPCNsigmaEl_P"), track.tpcInnerParam(), track.tpcNSigmaEl()); + registry.fill(HIST("hTOFNsigmaEl_P"), track.tpcInnerParam(), track.tofNSigmaEl()); + } else if (track.pidlabel() == static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kPion)) { + registry.fill(HIST("hTPCdEdx_P_Pion"), track.tpcInnerParam(), track.tpcSignal()); + registry.fill(HIST("hTOFbeta_P_Pion"), track.tpcInnerParam(), track.beta()); + registry.fill(HIST("hITSobClusterSize_P_Pion"), track.tpcInnerParam(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + registry.fill(HIST("hTPCNsigmaPi_P"), track.tpcInnerParam(), track.tpcNSigmaPi()); + registry.fill(HIST("hTOFNsigmaPi_P"), track.tpcInnerParam(), track.tofNSigmaPi()); + } else if (track.pidlabel() == static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kKaon)) { + registry.fill(HIST("hTPCdEdx_P_Kaon"), track.tpcInnerParam(), track.tpcSignal()); + registry.fill(HIST("hTOFbeta_P_Kaon"), track.tpcInnerParam(), track.beta()); + registry.fill(HIST("hITSobClusterSize_P_Kaon"), track.tpcInnerParam(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + registry.fill(HIST("hTPCNsigmaKa_P"), track.tpcInnerParam(), track.tpcNSigmaKa()); + registry.fill(HIST("hTOFNsigmaKa_P"), track.tpcInnerParam(), track.tofNSigmaKa()); + } else if (track.pidlabel() == static_cast(o2::aod::pwgem::dilepton::ml::PID_Label::kProton)) { + registry.fill(HIST("hTPCdEdx_P_Proton"), track.tpcInnerParam(), track.tpcSignal()); + registry.fill(HIST("hTOFbeta_P_Proton"), track.tpcInnerParam(), track.beta()); + registry.fill(HIST("hITSobClusterSize_P_Proton"), track.tpcInnerParam(), track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl()))); + registry.fill(HIST("hTPCNsigmaPr_P"), track.tpcInnerParam(), track.tpcNSigmaPr()); + registry.fill(HIST("hTOFNsigmaPr_P"), track.tpcInnerParam(), track.tofNSigmaPr()); } } // end of track loop } + PROCESS_SWITCH(MLTrackQC, processQC, "process QC for single track level", false); + + void processDummy(aod::EMTracksForMLPID const&) {} + PROCESS_SWITCH(MLTrackQC, processDummy, "process dummy", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGEM/Dilepton/TableProducer/treeCreatorSingleElectronQA.cxx b/PWGEM/Dilepton/TableProducer/treeCreatorSingleElectronQA.cxx deleted file mode 100644 index b7f09e9349d..00000000000 --- a/PWGEM/Dilepton/TableProducer/treeCreatorSingleElectronQA.cxx +++ /dev/null @@ -1,403 +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 "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 "PWGEM/PhotonMeson/DataModel/gammaTables.h" - -using namespace o2; -using namespace o2::soa; -using namespace o2::framework; -using namespace o2::framework::expressions; - -using MyBCs = soa::Join; - -using MyCollisions = soa::Join; -using MyCollisions_Cent = soa::Join; // centrality table has dependency on multiplicity table. - -using MyCollisionsMC = soa::Join; -using MyCollisionsMC_Cent = soa::Join; // centrality table has dependency on multiplicity table. - -using MyTracks = soa::Join; -using MyTrack = MyTracks::iterator; -using MyTracksMC = soa::Join; -using MyTrackMC = MyTracksMC::iterator; - -struct TreeCreatorSingleElectronQA { - - Produces event; - Produces event_mult; - Produces event_cent; - Produces emprimaryelectrons; - Produces prmeleventid; - - // 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 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.1, "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 minTPCNsigmaEl{"minTPCNsigmaEl", -1e+10, "min. TPC n sigma for electron inclusion"}; - Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", +1e+10, "max. TPC n sigma for electron inclusion"}; - Configurable minTPCNsigmaPi{"minTPCNsigmaPi", 0.0, "min. TPC n sigma for pion exclusion"}; - Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 0.0, "max. TPC n sigma for pion exclusion"}; - Configurable down_scaling{"down_scaling", 1e-3, "down scaling factor to store charged particles"}; - - 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; - - HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - std::mt19937 engine; - std::uniform_real_distribution dist01; - - void init(InitContext&) - { - mRunNumber = 0; - d_bz = 0; - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - addHistograms(); - std::random_device seed_gen; - engine = std::mt19937(seed_gen()); - dist01 = std::uniform_real_distribution(0.0f, 1.0f); - } - - void addHistograms() - { - fRegistry.add("hCollisionCounter", "collision counter", kTH1F, {{2, -0.5f, 1.5}}, false); - // for track info - fRegistry.add("Track/positive/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); - fRegistry.add("Track/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); - fRegistry.add("Track/positive/hPtPhi", "pT vs. #varphi;#varphi (rad.);p_{T} (GeV/c)", kTH2F, {{360, 0, 2 * M_PI}, {1000, 0.0f, 10.f}}, false); - fRegistry.add("Track/positive/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{360, 0, 2 * M_PI}, {40, -2.0f, 2.0f}}, 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, {{1000, 0, 10}, {100, 0., 1000}}, false); - fRegistry.add("Track/positive/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{1000, 0, 10}, {100, 0., 1000}}, 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/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_{in} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {600, 0, 1.2}}, false); - fRegistry.add("Track/positive/h1OverTOFbeta", "1/TOF beta;p_{in} (GeV/c);1/#beta", kTH2F, {{1000, 0, 10}, {1000, 0.8, 1.8}}, false); - fRegistry.add("Track/positive/hTOFNsigmaEl", "TOF n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/positive/hTOFNsigmaMu", "TOF n sigma mu;p_{in} (GeV/c);n #sigma_{#mu}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/positive/hTOFNsigmaPi", "TOF n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/positive/hTOFNsigmaKa", "TOF n sigma ka;p_{in} (GeV/c);n #sigma_{K}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/positive/hTOFNsigmaPr", "TOF n sigma pr;p_{in} (GeV/c);n #sigma_{p}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, 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/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.addClone("Track/positive/", "Track/negative/"); - } - - 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)); - } - 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.pt() < minpt || abs(track.eta()) > maxeta) { - 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 (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { - return false; - } - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi) { - return false; - } - - return true; - } - - template - void fillTrackHistograms(TTrack const& track) - { - if (track.sign() > 0) { - fRegistry.fill(HIST("Track/positive/hPt"), track.pt()); - fRegistry.fill(HIST("Track/positive/hQoverPt"), track.sign() / track.pt()); - fRegistry.fill(HIST("Track/positive/hEtaPhi"), track.phi(), track.eta()); - fRegistry.fill(HIST("Track/positive/hPtPhi"), track.phi(), track.pt()); - 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/hChi2ITS"), track.itsChi2NCl()); - fRegistry.fill(HIST("Track/positive/hITSClusterMap"), track.itsClusterMap()); - fRegistry.fill(HIST("Track/positive/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); - 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/hTOFbeta"), track.tpcInnerParam(), track.beta()); - fRegistry.fill(HIST("Track/positive/h1OverTOFbeta"), track.tpcInnerParam(), 1.f / track.beta()); - fRegistry.fill(HIST("Track/positive/hTOFNsigmaEl"), track.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/positive/hTOFNsigmaMu"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/positive/hTOFNsigmaPi"), track.tpcInnerParam(), track.tofNSigmaPi()); - fRegistry.fill(HIST("Track/positive/hTOFNsigmaKa"), track.tpcInnerParam(), track.tofNSigmaKa()); - fRegistry.fill(HIST("Track/positive/hTOFNsigmaPr"), track.tpcInnerParam(), track.tofNSigmaPr()); - } else { - fRegistry.fill(HIST("Track/negative/hPt"), track.pt()); - fRegistry.fill(HIST("Track/negative/hQoverPt"), track.sign() / track.pt()); - fRegistry.fill(HIST("Track/negative/hEtaPhi"), track.phi(), track.eta()); - fRegistry.fill(HIST("Track/negative/hPtPhi"), track.phi(), track.pt()); - 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/hChi2ITS"), track.itsChi2NCl()); - fRegistry.fill(HIST("Track/negative/hITSClusterMap"), track.itsClusterMap()); - fRegistry.fill(HIST("Track/negative/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); - 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/hTOFbeta"), track.tpcInnerParam(), track.beta()); - fRegistry.fill(HIST("Track/negative/h1OverTOFbeta"), track.tpcInnerParam(), 1.f / track.beta()); - fRegistry.fill(HIST("Track/negative/hTOFNsigmaEl"), track.tpcInnerParam(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/negative/hTOFNsigmaMu"), track.tpcInnerParam(), track.tofNSigmaMu()); - fRegistry.fill(HIST("Track/negative/hTOFNsigmaPi"), track.tpcInnerParam(), track.tofNSigmaPi()); - fRegistry.fill(HIST("Track/negative/hTOFNsigmaKa"), track.tpcInnerParam(), track.tofNSigmaKa()); - fRegistry.fill(HIST("Track/negative/hTOFNsigmaPr"), track.tpcInnerParam(), track.tofNSigmaPr()); - } - } - - template - void fillTrackTable(TTrack const& track) - { - emprimaryelectrons(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.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), true); - } - - SliceCache cache; - Preslice perCollision_track = o2::aod::track::collisionId; - - 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) && (o2::aod::pidtpc::tpcNSigmaPi < minTPCNsigmaPi || maxTPCNsigmaPi < o2::aod::pidtpc::tpcNSigmaPi); - using MyFilteredTracks = soa::Filtered; - - // ---------- for data ---------- - void processRec(MyCollisions_Cent const& collisions, MyBCs const&, MyFilteredTracks const& tracks) - { - for (auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - - fRegistry.fill(HIST("hCollisionCounter"), 0.f); - if (dist01(engine) > down_scaling) { - continue; - } - fRegistry.fill(HIST("hCollisionCounter"), 1.f); - - event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), - collision.posX(), collision.posY(), collision.posZ(), - collision.numContrib(), collision.trackOccupancyInTimeRange()); - event_mult(collision.multFT0A(), collision.multFT0C(), collision.multTPC(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); - event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); - - auto tracks_per_collision = tracks.sliceBy(perCollision_track, collision.globalIndex()); - - for (auto& track : tracks_per_collision) { - if (!checkTrack(track)) { - continue; - } - fillTrackTable(track); - prmeleventid(event.lastIndex()); - fillTrackHistograms(track); - } // end of track loop - - } // end of collision loop - } - PROCESS_SWITCH(TreeCreatorSingleElectronQA, processRec, "process reconstructed info only", true); // standalone - - // ---------- for MC ---------- - using MyFilteredTracksMC = soa::Filtered; - void processMC(MyCollisionsMC_Cent const& collisions, aod::McCollisions const&, MyBCs const&, MyFilteredTracksMC const& tracks) - { - for (auto& collision : collisions) { - if (!collision.has_mcCollision()) { - continue; - } - auto bc = collision.bc_as(); - initCCDB(bc); - - fRegistry.fill(HIST("hCollisionCounter"), 0.f); - if (dist01(engine) > down_scaling) { - continue; - } - fRegistry.fill(HIST("hCollisionCounter"), 1.f); - - event(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), - collision.posX(), collision.posY(), collision.posZ(), - collision.numContrib(), collision.trackOccupancyInTimeRange()); - event_mult(collision.multFT0A(), collision.multFT0C(), collision.multTPC(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); - event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); - - auto tracks_per_collision = tracks.sliceBy(perCollision_track, collision.globalIndex()); - - for (auto& track : tracks_per_collision) { - if (!checkTrack(track)) { - continue; - } - fillTrackTable(track); - prmeleventid(event.lastIndex()); - fillTrackHistograms(track); - } // end of track loop - - } // end of collision loop - } - PROCESS_SWITCH(TreeCreatorSingleElectronQA, processMC, "process reconstructed and MC info ", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"tree-creator-single-electron-qa"}), - }; -} diff --git a/PWGEM/Dilepton/Tasks/CMakeLists.txt b/PWGEM/Dilepton/Tasks/CMakeLists.txt index 644490bbddf..804331bb688 100644 --- a/PWGEM/Dilepton/Tasks/CMakeLists.txt +++ b/PWGEM/Dilepton/Tasks/CMakeLists.txt @@ -12,12 +12,12 @@ 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 @@ -27,12 +27,12 @@ o2physics_add_dpl_workflow(lmee-hf-cocktail 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 @@ -42,7 +42,17 @@ o2physics_add_dpl_workflow(create-resolution-map o2physics_add_dpl_workflow(table-reader-barrel SOURCES tableReaderBarrel.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(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 O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(single-electron-qc @@ -55,6 +65,16 @@ o2physics_add_dpl_workflow(single-electron-qc-mc 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 @@ -67,22 +87,22 @@ o2physics_add_dpl_workflow(single-muon-qc-mc o2physics_add_dpl_workflow(dielectron SOURCES dielectron.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2::DCAFitter O2Physics::PWGEMDileptonCore + 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 O2::DCAFitter O2Physics::PWGEMDileptonCore + 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 O2::DCAFitter O2Physics::PWGEMDileptonCore + 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 O2::DCAFitter O2Physics::PWGEMDileptonCore + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMDileptonCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(photon-hbt-pcmpcm @@ -100,3 +120,62 @@ o2physics_add_dpl_workflow(photon-hbt-pcmee 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) + +o2physics_add_dpl_workflow(tagging-hfe + SOURCES taggingHFE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(qvector-dummy-otf + SOURCES qVectorDummyOTF.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dielectron-hadron-mpc + SOURCES dielectronHadronMPC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dimuon-hadron-mpc + SOURCES dimuonHadronMPC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::PWGEMDileptonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(mc-particle-predictions-otf + SOURCES mcParticlePredictionsOTF.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(study-dcafitter + SOURCES studyDCAFitter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(evaluate-acceptance + SOURCES evaluateAcceptance.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dilepton-polarization + SOURCES dileptonPolarization.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/Dilepton/Tasks/MCtemplates.cxx b/PWGEM/Dilepton/Tasks/MCtemplates.cxx index 5b1bf9548ae..3288bd2745e 100644 --- a/PWGEM/Dilepton/Tasks/MCtemplates.cxx +++ b/PWGEM/Dilepton/Tasks/MCtemplates.cxx @@ -243,13 +243,13 @@ struct AnalysisTrackSelection { if (fConfigQA) { if (fConfigMCTruthGen) { // Add histogram classes for each MC signal at generated level - std::vector mcnamesgen; + // 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); + // 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 } } @@ -333,9 +333,9 @@ 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) @@ -604,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); } } 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..0aef371fa63 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/bcCounter.cxx @@ -0,0 +1,144 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" + +#include "TString.h" + +#include +#include +#include +#include +#include + +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 index 843cce77eb4..5df5855d171 100644 --- a/PWGEM/Dilepton/Tasks/createResolutionMap.cxx +++ b/PWGEM/Dilepton/Tasks/createResolutionMap.cxx @@ -13,57 +13,119 @@ // Analysis task to produce resolution mapfor electrons/muons in dilepton analysis // Please write to: daiki.sekihata@cern.ch -#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 "PWGEM/Dilepton/Utils/MCUtilities.h" + +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/fwdtrackUtilities.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "CCDB/BasicCCDBManager.h" +#include "DataFormatsCalibration/MeanVertexObject.h" #include "DataFormatsParameters/GRPMagField.h" -#include "TGeoGlobalMagField.h" -#include "Field/MagneticField.h" - #include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" #include "GlobalTracking/MatchGlobalFwd.h" #include "MCHTracking/TrackExtrap.h" #include "MCHTracking/TrackParam.h" #include "ReconstructionDataFormats/TrackFwd.h" +#include "TGeoGlobalMagField.h" + +#include +#include +#include +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::aod; using namespace o2::soa; - -using MyCollisions = Join; -using MyCollision = MyCollisions::iterator; - -using MyMCTracks = soa::Join; -using MyMCTrack = MyMCTracks::iterator; - -using MyMCFwdTracks = soa::Join; -using MyMCFwdTrack = MyMCFwdTracks::iterator; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; +using namespace o2::aod::fwdtrackutils; 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 applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; 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", false, "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_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.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", {36, 0, 2.f * M_PI}, "gen. phi bins at forward rapidity for output histograms"}; + // ConfigurableAxis ConfPhiPositionCBGenBins{"ConfPhiPositionCBGenBins", {VARIABLE_WIDTH, 2.3 - M_PI, 0.85, 2.3, 0.85 + M_PI, 2.3 + M_PI}, "gen. phi psotion bins at forward rapidity for output histograms"}; // default is adjusted at R = 0.50 m + // ConfigurableAxis ConfPhiPositionFWDGenBins{"ConfPhiPositionFWDGenBins", {1, 0, 2 * M_PI}, "gen. phi psotion bins at forward rapidity for output histograms"}; + Configurable cfgRefR{"cfgRefR", 0.50, "ref. radius (m) for calculating phi position"}; // 0.50 +/- 0.06 can be syst. unc. + + ConfigurableAxis ConfRelDeltaPtCBBins{"ConfRelDeltaPtCBBins", {200, -1.f, +1.f}, "rel. dpt for output histograms at midrapidity"}; + ConfigurableAxis ConfRelDeltaPtFWDBins{"ConfRelDeltaPtFWDBins", {200, -1.f, +1.f}, "rel. dpt for output histograms at fwd rapidity"}; + + ConfigurableAxis ConfDeltaEtaCBBins{"ConfDeltaEtaCBBins", {200, -0.5f, +0.5f}, "deta bins for output histograms at midrapidity"}; + ConfigurableAxis ConfDeltaEtaFWDBins{"ConfDeltaEtaFWDBins", {200, -0.5f, +0.5f}, "deta bins for output histograms at fwd rapidity"}; + ConfigurableAxis ConfDeltaPhiBins{"ConfDeltaPhiBins", {200, -0.5f, +0.5f}, "dphi bins for output histograms"}; + + Configurable cfgFillTHnSparse{"cfgFillTHnSparse", true, "fill THnSparse for output"}; + Configurable cfgFillTH2{"cfgFillTH2", false, "fill TH2 for output"}; + + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabelCB{"cfgRCTLabelCB", "CBT_hadronPID", "select 1 [CBT, CBT_hadron] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgRCTLabelFWDSA{"cfgRCTLabelFWDSA", "CBT_muon", "select 1 [CBT_muon] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgRCTLabelFWDGL{"cfgRCTLabelFWDGL", "CBT_muon_glo", "select 1 [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"}; + + 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"; @@ -71,58 +133,158 @@ struct CreateResolutionMap { 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", 0, "min ncluster tpc"}; - Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 4, "min ncluster its"}; + 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", 80, "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", 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_require_itsib_1st{"cfg_require_itsib_1st", false, "flag to require ITS ib 1st hit"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; + Configurable maxpt_itssa{"maxpt_itssa", 0.15, "max pt for ITSsa track"}; + Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; } 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.0, "min eta for single track"}; - Configurable cfg_max_eta_track{"cfg_max_eta_track", -1.5, "max eta for single track"}; + Configurable cfg_min_eta_track_sa{"cfg_min_eta_track_sa", -5.5, "min eta for standalone muon track"}; + Configurable cfg_max_eta_track_sa{"cfg_max_eta_track_sa", -1.5, "max eta for standalone muon track"}; + Configurable cfg_min_eta_track_gl{"cfg_min_eta_track_gl", -5.5, "min eta for global muon track"}; + Configurable cfg_max_eta_track_gl{"cfg_max_eta_track_gl", -1.5, "max eta for global muon 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"}; + Configurable cfg_max_chi2_sa{"cfg_max_chi2_sa", 1e+10, "max chi2/ndf for standalone muon track"}; + Configurable cfg_max_chi2_gl{"cfg_max_chi2_gl", 4, "max chi2/ndf for global muon track"}; + Configurable cfg_max_chi2mft{"cfg_max_chi2mft", 1e+10, "max chi2/ndf for MFTsa track"}; + Configurable cfg_max_matching_chi2_mftmch{"cfg_max_matching_chi2_mftmch", 40, "max chi2/ndf for MFT-MCH matching"}; + Configurable cfg_max_matching_chi2_mchmid{"cfg_max_matching_chi2_mchmid", 1e+10, "max chi2/ndf for MCH-MID matching"}; + Configurable cfg_max_dcaxy_gl{"cfg_max_dcaxy_gl", 0.1, "max dca XY for single track in cm"}; + Configurable cfg_min_rabs_sa{"cfg_min_rabs_sa", 17.6, "min Radius at the absorber end for standalone muon track"}; + Configurable cfg_max_rabs_sa{"cfg_max_rabs_sa", 89.5, "max Radius at the absorber end for standalone muon track"}; + Configurable cfg_min_rabs_gl{"cfg_min_rabs_gl", 27.6, "min Radius at the absorber end for global muon track"}; + Configurable cfg_max_rabs_gl{"cfg_max_rabs_gl", 89.5, "max Radius at the absorber end for global muon track"}; + Configurable cfg_mid_rabs{"cfg_mid_rabs", 26.5, "middle R at absorber end for pDCA cut"}; + Configurable cfg_max_pdca_forLargeR{"cfg_max_pdca_forLargeR", 324.f, "max. pDCA for large R at absorber end"}; + Configurable cfg_max_pdca_forSmallR{"cfg_max_pdca_forSmallR", 594.f, "max. pDCA for small R at absorber end"}; + Configurable cfg_max_reldpt{"cfg_max_reldpt", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_deta{"cfg_max_deta", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_dphi{"cfg_max_dphi", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable cfg_max_detaMP{"cfg_max_detaMP", 1e+10f, "max. deta between MFT and MCH-MID at matching plane"}; + Configurable cfg_max_dphiMP{"cfg_max_dphiMP", 1e+10f, "max. dphi between MFT and MCH-MID at matching plane"}; + Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to require MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{4}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; + Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; } muoncuts; HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + o2::aod::rctsel::RCTFlagsChecker rctCheckerCB; + o2::aod::rctsel::RCTFlagsChecker rctCheckerFWDSA; + o2::aod::rctsel::RCTFlagsChecker rctCheckerFWDGL; o2::ccdb::CcdbApi ccdbApi; Service ccdb; - o2::globaltracking::MatchGlobalFwd mMatching; int mRunNumber = 0; + float mBzMFT = 0; + float d_bz = 0; + // 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; + // std::vector phiPosition_bin_edges; + + ~CreateResolutionMap() + { + // phiPosition_bin_edges.clear(); + // phiPosition_bin_edges.shrink_to_fit(); + } 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); + rctCheckerCB.init(cfgRCTLabelCB.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + rctCheckerFWDSA.init(cfgRCTLabelFWDSA.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + rctCheckerFWDGL.init(cfgRCTLabelFWDGL.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + + mRunNumber = 0; + d_bz = 0; + mBzMFT = 0; + + // if (ConfPhiPositionCBGenBins.value[0] == VARIABLE_WIDTH) { + // phiPosition_bin_edges = std::vector(ConfPhiPositionCBGenBins.value.begin(), ConfPhiPositionCBGenBins.value.end()); + // phiPosition_bin_edges.erase(phiPosition_bin_edges.begin()); + // // for (const auto& edge : phiPosition_bin_edges) { + // // LOGF(info, "VARIABLE_WIDTH: phiPosition_bin_edges = %f", edge); + // // } + // } else { // FIXED bin width + // int nbins = static_cast(ConfPhiPositionCBGenBins.value[0]); + // float xmin = static_cast(ConfPhiPositionCBGenBins.value[1]); + // float xmax = static_cast(ConfPhiPositionCBGenBins.value[2]); + // phiPosition_bin_edges.resize(nbins + 1); + // for (int i = 0; i < nbins + 1; i++) { + // phiPosition_bin_edges[i] = (xmax - xmin) / (nbins)*i + xmin; + // // LOGF(info, "FIXED_WIDTH: phiPosition_bin_edges[%d] = %f", i, phiPosition_bin_edges[i]); + // } + // } - const AxisSpec axis_pt_gen{{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}, "p_{T,l}^{gen} (GeV/c)"}; - const AxisSpec axis_dpt{400, -1, 1, "(p_{T,l}^{gen.} - p_{T,l}^{rec.})/p_{T,l}^{gen.}"}; - const AxisSpec axis_deta{500, -0.5, +0.5, "#eta_{l}^{gen.} - #eta_{l}^{rec.}"}; - const AxisSpec axis_dphi{500, -0.5, +0.5, "#varphi_{l}^{gen.} - #varphi_{l}^{rec.} (rad.)"}; - - 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/"); + 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_cb{ConfRelDeltaPtCBBins, "(p_{T,l}^{gen} - p_{T,l}^{rec})/p_{T,l}^{gen}"}; + const AxisSpec axis_dpt_fwd{ConfRelDeltaPtFWDBins, "(p_{T,l}^{gen} - p_{T,l}^{rec})/p_{T,l}^{gen}"}; + const AxisSpec axis_deta_cb{ConfDeltaEtaCBBins, "#eta_{l}^{gen} - #eta_{l}^{rec}"}; + const AxisSpec axis_deta_fwd{ConfDeltaEtaFWDBins, "#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"}; + // const AxisSpec axis_phiPositionCB_gen{ConfPhiPositionCBGenBins, Form("#varphi^{*, gen} (rad.) at r_{xy} = %3.2f m", cfgRefR.value)}; + // const AxisSpec axis_phiPositionFWD_gen{ConfPhiPositionFWDGenBins, "#varphi^{*, gen} (rad.)"}; + + // 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/Electron/hImpPar_Centrality", "true imapact parameter vs. estimated centrality;impact parameter (fm);centrality (%)", kTH2F, {{200, 0, 20}, {110, 0, 110}}, true); + if (doprocessGen) { + registry.add("Event/hGenID", "generator ID;generator ID;Number of mc collisions", kTH1F, {{7, -1.5, 5.5}}, true); + } + if (cfgFillTH2) { + registry.add("Electron/hPt", "rec. p_{T,e};p_{T,e} (GeV/c)", kTH1F, {{1000, 0, 10}}, false); + registry.add("Electron/hEtaPhi", "rec. #eta vs. #varphi;#varphi_{e} (rad.);#eta_{e}", kTH2F, {{90, 0, 2 * M_PI}, {100, -5, +5}}, false); + registry.add("Electron/Ptgen_RelDeltaPt", "resolution", kTH2F, {{axis_pt_gen}, {axis_dpt_cb}}, true); + registry.add("Electron/Ptgen_DeltaEta", "resolution", kTH2F, {{axis_pt_gen}, {axis_deta_cb}}, 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.add("StandaloneMuon/hPt", "rec. p_{T,#mu};p_{T,#mu} (GeV/c)", kTH1F, {{1000, 0, 10}}, false); + registry.add("StandaloneMuon/hEtaPhi", "rec. #eta vs. #varphi;#varphi_{#mu} (rad.);#eta_{#mu}", kTH2F, {{90, 0, 2 * M_PI}, {100, -5, +5}}, false); + registry.add("StandaloneMuon/Ptgen_RelDeltaPt", "resolution", kTH2F, {{axis_pt_gen}, {axis_dpt_fwd}}, true); + registry.add("StandaloneMuon/Ptgen_DeltaEta", "resolution", kTH2F, {{axis_pt_gen}, {axis_deta_fwd}}, true); + registry.add("StandaloneMuon/Ptgen_DeltaPhi_Pos", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + registry.add("StandaloneMuon/Ptgen_DeltaPhi_Neg", "resolution", kTH2F, {{axis_pt_gen}, {axis_dphi}}, true); + registry.addClone("StandaloneMuon/", "GlobalMuon/"); + } + + if (cfgFillTHnSparse) { + registry.add("Electron/hs_reso", "8D resolution", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_cb_gen, axis_phi_gen, axis_charge_gen, axis_dpt_cb, axis_deta_cb, axis_dphi}, true); + registry.add("StandaloneMuon/hs_reso", "8D resolution", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_fwd_gen, axis_phi_gen, axis_charge_gen, axis_dpt_fwd, axis_deta_fwd, axis_dphi}, true); + registry.add("GlobalMuon/hs_reso", "8D resolution", kTHnSparseF, {axis_cent, axis_pt_gen, axis_eta_fwd_gen, axis_phi_gen, axis_charge_gen, axis_dpt_fwd, axis_deta_fwd, axis_dphi}, true); + } } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -131,25 +293,159 @@ struct CreateResolutionMap { 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); + // 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(); + mBzMFT = d_bz; + LOGF(info, "Bz at center of MFT = %f kZG manually", mBzMFT); + } + + 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"; + } + + // 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(); + const double centerMFT[3] = {0, 0, -61.4}; + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + mBzMFT = field->getBz(centerMFT); // Get field at centre of MFT + LOGF(info, "Bz at center of MFT = %f kZG", mBzMFT); + mRunNumber = bc.runNumber(); + } + + 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 checkTrack(TTrack const& track) + bool isSelectedTrack(TTrack const& track) { - if (track.tpcChi2NCl() > electroncuts.cfg_max_chi2tpc) { + if (!track.hasITS()) { return false; } @@ -160,6 +456,9 @@ struct CreateResolutionMap { 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) { @@ -172,227 +471,640 @@ struct CreateResolutionMap { } } - if (track.tpcNClsFound() < electroncuts.cfg_min_ncluster_tpc) { + if (!electroncuts.includeITSsa && (!track.hasITS() || !track.hasTPC())) { return false; } - if (track.tpcNClsCrossedRows() < electroncuts.cfg_min_ncrossedrows) { - return false; - } + if (track.hasTPC()) { + if (track.tpcChi2NCl() > electroncuts.cfg_max_chi2tpc) { + return false; + } - if (track.tpcCrossedRowsOverFindableCls() < electroncuts.cfg_min_tpc_cr_findable_ratio) { - 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; + } } return true; } - template - o2::dataformats::GlobalFwdTrack PropagateMuon(T const& muon, C const& collision, const CreateResolutionMap::MuonExtrapolation endPoint) + template + bool isSelectedTrackWithKine(TTrack const& track, const float pt, const float eta, const float tgl, const float dcaXY, const float dcaZ) { - 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; - } + if (!isSelectedTrack(track)) { + return false; + } - template - bool checkFwdTrack(TMuon const& muon, TCollision const& collision) - { - o2::dataformats::GlobalFwdTrack propmuonAtPV = PropagateMuon(muon, collision, CreateResolutionMap::MuonExtrapolation::kToVertex); - float pt = propmuonAtPV.getPt(); - float eta = propmuonAtPV.getEta(); - float phi = propmuonAtPV.getPhi(); + if (std::fabs(dcaXY) > electroncuts.cfg_max_dcaxy || std::fabs(dcaZ) > electroncuts.cfg_max_dcaz) { + return false; + } - if (pt < muoncuts.cfg_min_pt_track) { + if (pt < electroncuts.cfg_min_pt_track || std::fabs(eta) > electroncuts.cfg_max_eta_track) { return false; } - if (eta < muoncuts.cfg_min_eta_track || muoncuts.cfg_max_eta_track < eta) { + if ((track.hasITS() && !track.hasTPC() && !track.hasTOF() && !track.hasTRD()) && electroncuts.maxpt_itssa < pt) { return false; } - o2::math_utils::bringTo02Pi(phi); - if (phi < 0.f || 2.f * M_PI < phi) { + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + if (electroncuts.maxMeanITSClusterSize < static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(tgl))) { return false; } - float rAtAbsorberEnd = muon.rAtAbsorberEnd(); - if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - o2::dataformats::GlobalFwdTrack propmuonAtRabs = PropagateMuon(muon, collision, CreateResolutionMap::MuonExtrapolation::kToRabs); + return true; + } + + template + void fillMuon(TCollision const& collision, TMuon const& muon, TMFTTracksCov const& mftCovs, 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; + } + + if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(muon.globalIndex(), muon.matchMCHTrackId(), muon.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + return; + } + + if (muon.chi2MatchMCHMID() < 0.f) { // this should never happen. only for protection. + return; + } + o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(muon, muon, collision, propagationPoint::kToVertex, muoncuts.matchingZ, mBzMFT); + + float pt = propmuonAtPV.getPt(); + float eta = propmuonAtPV.getEta(); + float phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + float dcaX = propmuonAtPV.getX() - collision.posX(); + float dcaY = propmuonAtPV.getY() - collision.posY(); + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + + float rAtAbsorberEnd = muon.rAtAbsorberEnd(); // this works only for GlobalMuonTrack + float pDCA = propmuonAtPV.getP() * dcaXY; + int nClustersMFT = 0; + float ptMatchedMCHMID = propmuonAtPV.getPt(); + float etaMatchedMCHMID = propmuonAtPV.getEta(); + float phiMatchedMCHMID = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + + float etaMatchedMCHMIDatMP = 999.f; + float phiMatchedMCHMIDatMP = 999.f; + float etaMatchedMFTatMP = 999.f; + float phiMatchedMFTatMP = 999.f; + + if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + // mcparticle for global MFT-MCH-MID is identical to mcparticle of MCH-MID track. If not, mismatch. + auto mchtrack = muon.template matchMCHTrack_as(); // MCH-MID + auto mfttrack = muon.template matchMFTTrack_as(); // MFTsa + if (!mchtrack.has_mcParticle() || !mfttrack.has_mcParticle()) { + return; + } + auto mcparticle_MCHMID = mchtrack.template mcParticle_as(); + auto mcparticle_MFT = mfttrack.template mcParticle_as(); + if (mcparticle.globalIndex() != mcparticle_MCHMID.globalIndex()) { // this should not happen. this is only for protection. + return; + } + if (cfg_reject_fake_match_mft_mch && mcparticle.globalIndex() != mcparticle_MFT.globalIndex()) { // evaluate mismatch + return; + } + + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, muoncuts.matchingZ, mBzMFT); + ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); + etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); + phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + + // o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, muoncuts.matchingZ, mBzMFT); + // 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; + pDCA = propmuonAtPV.getP() * dcaXY; + + nClustersMFT = mfttrack.nClusters(); + float chi2mft = mfttrack.chi2() / (2.f * nClustersMFT - 5.f); + + if (nClustersMFT < muoncuts.cfg_min_ncluster_mft) { + return; + } + + if (chi2mft < 0.f || muoncuts.cfg_max_chi2mft < chi2mft) { + return; + } + + if (muon.chi2MatchMCHMFT() > muoncuts.cfg_max_matching_chi2_mftmch) { + return; + } + + if constexpr (withMFTCov) { + auto mfttrackcov = mftCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, muoncuts.matchingZ, mBzMFT); // propagated to matching plane + o2::track::TrackParCovFwd mftsaAtMP = getTrackParCovFwd(mfttrack, mfttrackcov); // values at innermost update + mftsaAtMP.propagateToZhelix(muoncuts.matchingZ, mBzMFT); // propagated to matching plane + etaMatchedMFTatMP = mftsaAtMP.getEta(); + phiMatchedMFTatMP = mftsaAtMP.getPhi(); + etaMatchedMCHMIDatMP = muonAtMP.getEta(); + phiMatchedMCHMIDatMP = muonAtMP.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMIDatMP); + o2::math_utils::bringTo02Pi(phiMatchedMFTatMP); + + o2::track::TrackParCovFwd mftsa = getTrackParCovFwd(mfttrack, mfttrackcov); // values at innermost update + o2::dataformats::GlobalFwdTrack globalMuonRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuonAtPV_Matched, mftsa); // this is track at IU. + auto globalMuonAtPV = o2::aod::fwdtrackutils::propagateTrackParCovFwd(globalMuonRefit, muon.trackType(), collision, propagationPoint::kToVertex, muoncuts.matchingZ, mBzMFT); + pt = globalMuonAtPV.getPt(); + eta = globalMuonAtPV.getEta(); + phi = globalMuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + dcaX = globalMuonAtPV.getX() - collision.posX(); + dcaY = globalMuonAtPV.getY() - collision.posY(); + dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + } + + if (muoncuts.refitGlobalMuon) { + pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); + } + + float dpt = (ptMatchedMCHMID - pt) / pt; + if (std::fabs(dpt) > muoncuts.cfg_max_reldpt) { + return; + } + float deta = etaMatchedMCHMID - eta; + float dphi = phiMatchedMCHMID - phi; + o2::math_utils::bringToPMPi(dphi); + if (std::sqrt(std::pow(deta / muoncuts.cfg_max_deta, 2) + std::pow(dphi / muoncuts.cfg_max_dphi, 2)) > 1.f) { + return; + } + + float detaMP = etaMatchedMCHMIDatMP - etaMatchedMFTatMP; + float dphiMP = phiMatchedMCHMIDatMP - phiMatchedMFTatMP; + o2::math_utils::bringToPMPi(dphiMP); + if (std::sqrt(std::pow(detaMP / muoncuts.cfg_max_detaMP, 2) + std::pow(dphiMP / muoncuts.cfg_max_dphiMP, 2)) > 1.f) { + return; + } + + if (muoncuts.requireMFTHitMap) { + std::vector hasMFTs{hasMFT<0, 1>(mfttrack), hasMFT<2, 3>(mfttrack), hasMFT<4, 5>(mfttrack), hasMFT<6, 7>(mfttrack), hasMFT<8, 9>(mfttrack)}; + for (int i = 0; i < static_cast(muoncuts.requiredMFTDisks->size()); i++) { + if (!hasMFTs[muoncuts.requiredMFTDisks->at(i)]) { + return; + } + } + } + + } else if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(muon, muon, collision, propagationPoint::kToRabs, muoncuts.matchingZ, mBzMFT); // 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 + + o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(muon, muon, collision, propagationPoint::kToDCA, muoncuts.matchingZ, mBzMFT); + dcaX = propmuonAtDCA.getX() - collision.posX(); + dcaY = propmuonAtDCA.getY() - collision.posY(); + dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + pDCA = muon.p() * dcaXY; + } else { + return; } - if (rAtAbsorberEnd < muoncuts.cfg_min_rabs || muoncuts.cfg_max_rabs < rAtAbsorberEnd) { - return false; + if (muon.nClusters() < muoncuts.cfg_min_ncluster_mch) { + return; } - if (rAtAbsorberEnd < 26.5) { - if (muon.pDca() > 594.f) { - return false; + if (!isSelectedMuon(pt, eta, rAtAbsorberEnd, pDCA, muon.chi2() / (2.f * (muon.nClusters() + nClustersMFT) - 5.f), muon.trackType(), dcaXY)) { + return; + } + + if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (cfgRequireGoodRCT && !rctCheckerFWDSA.checkTable(collision)) { + return; } - } else { - if (muon.pDca() > 324.f) { - return false; + if (cfgFillTHnSparse) { + 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); + } + + if (cfgFillTH2) { + registry.fill(HIST("StandaloneMuon/hPt"), pt); + registry.fill(HIST("StandaloneMuon/hEtaPhi"), phi, eta); + 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)) { + if (cfgRequireGoodRCT && !rctCheckerFWDGL.checkTable(collision)) { + return; + } + if (cfgFillTHnSparse) { + 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); + } + if (cfgFillTH2) { + registry.fill(HIST("GlobalMuon/hPt"), pt); + registry.fill(HIST("GlobalMuon/hEtaPhi"), phi, eta); + 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; + } - if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && muon.chi2MatchMCHMFT() > muoncuts.cfg_max_matching_chi2_mftmch) { + bool isSelectedMuon(const float pt, const float eta, const float rAtAbsorberEnd, const float pDCA, const float chi2, const uint8_t trackType, const float dcaXY) + { + if (pt < muoncuts.cfg_min_pt_track) { + return false; + } + if (rAtAbsorberEnd < muoncuts.cfg_min_rabs_sa || muoncuts.cfg_max_rabs_sa < rAtAbsorberEnd) { + return false; + } + if (rAtAbsorberEnd < muoncuts.cfg_mid_rabs ? pDCA > muoncuts.cfg_max_pdca_forSmallR : pDCA > muoncuts.cfg_max_pdca_forLargeR) { return false; } - auto mctrack = muon.template mcParticle_as(); - if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - registry.fill(HIST("StandaloneMuon/Ptgen_RelDeltaPt"), mctrack.pt(), (mctrack.pt() - pt) / mctrack.pt()); - registry.fill(HIST("StandaloneMuon/Ptgen_DeltaEta"), mctrack.pt(), mctrack.eta() - eta); - if (mctrack.pdgCode() == -13) { // positron - registry.fill(HIST("StandaloneMuon/Ptgen_DeltaPhi_Pos"), mctrack.pt(), mctrack.phi() - phi); - } else if (mctrack.pdgCode() == 13) { // electron - registry.fill(HIST("StandaloneMuon/Ptgen_DeltaPhi_Neg"), mctrack.pt(), mctrack.phi() - phi); + if (trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { + if (eta < muoncuts.cfg_min_eta_track_gl || muoncuts.cfg_max_eta_track_gl < eta) { + return false; } - } else if (muon.trackType() == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - registry.fill(HIST("GlobalMuon/Ptgen_RelDeltaPt"), mctrack.pt(), (mctrack.pt() - pt) / mctrack.pt()); - registry.fill(HIST("GlobalMuon/Ptgen_DeltaEta"), mctrack.pt(), mctrack.eta() - eta); - if (mctrack.pdgCode() == -13) { // positive muon - registry.fill(HIST("GlobalMuon/Ptgen_DeltaPhi_Pos"), mctrack.pt(), mctrack.phi() - phi); - } else if (mctrack.pdgCode() == 13) { // negative muon - registry.fill(HIST("GlobalMuon/Ptgen_DeltaPhi_Neg"), mctrack.pt(), mctrack.phi() - phi); + if (muoncuts.cfg_max_dcaxy_gl < dcaXY) { + return false; } + if (chi2 < 0.f || muoncuts.cfg_max_chi2_gl < chi2) { // chi2/ndf + return false; + } + if (rAtAbsorberEnd < muoncuts.cfg_min_rabs_gl || muoncuts.cfg_max_rabs_gl < rAtAbsorberEnd) { + return false; + } + } else if (trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (eta < muoncuts.cfg_min_eta_track_sa || muoncuts.cfg_max_eta_track_sa < eta) { + return false; + } + if (chi2 < 0.f || muoncuts.cfg_max_chi2_sa < chi2) { + return false; + } + } else { + return false; } + return true; } + template + bool hasMFT(T const& track) + { + // logical-OR + uint64_t mftClusterSizesAndTrackFlags = track.mftClusterSizesAndTrackFlags(); + uint16_t clmap = 0; + for (unsigned int layer = begin; layer <= end; layer++) { + if ((mftClusterSizesAndTrackFlags >> (layer * 6)) & 0x3f) { + clmap |= (1 << layer); + } + } + return (clmap > 0); + } + SliceCache cache; - Preslice perCollision_mid = o2::aod::track::collisionId; + Preslice perCollision_mid = o2::aod::track::collisionId; Preslice perCollision_fwd = o2::aod::fwdtrack::collisionId; + PresliceUnsorted fwdtracksPerMCHTrack = aod::fwdtrack::matchMCHTrackId; + + using MyCollisions = Join; + using MyCollision = MyCollisions::iterator; + + using MyTracks = soa::Join; + using MyTrack = MyTracks::iterator; + + using MyFwdTracks = soa::Join; + using MyFwdTrack = MyFwdTracks::iterator; + + using MyMFTTracks = soa::Join; + using MyMFTTrack = MyMFTTracks::iterator; + + template + void fillElectron(TCollision const& collision, TTrack const& track, const float centrality) + { + if (cfgRequireGoodRCT && !rctCheckerCB.checkTable(collision)) { + return; + } + const 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(track)) { + return; + } + + o2::dataformats::DCA mDcaInfoCov; + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.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, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + float pt = trackParCov.getPt(); + float eta = trackParCov.getEta(); + float phi = trackParCov.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + // float phiPosition = mcparticle.phi() + std::asin(-0.30282 * (-mcparticle.pdgCode() / 11) * (d_bz * 0.1) * cfgRefR / (2.f * mcparticle.pt())); + // phiPosition = RecoDecay::constrainAngle(phiPosition, phiPosition_bin_edges[0], 1U); - Filter collisionFilter = o2::aod::evsel::sel8 == true && nabs(o2::aod::collision::posZ) < 10.f; - using MyFilteredCollisions = soa::Filtered; + if (!isSelectedTrackWithKine(track, pt, eta, trackParCov.getTgl(), dcaXY, dcaZ)) { + return; + } + + if (cfgFillTHnSparse) { + 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); + } + if (cfgFillTH2) { + registry.fill(HIST("Electron/hPt"), pt); + registry.fill(HIST("Electron/hEtaPhi"), phi, eta); + 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); + } + } + } - Filter trackFilter_mid = o2::aod::track::pt > electroncuts.cfg_min_pt_track&& electroncuts.cfg_min_eta_track < o2::aod::track::eta&& o2::aod::track::eta < electroncuts.cfg_max_eta_track&& o2::aod::track::tpcChi2NCl < electroncuts.cfg_max_chi2tpc&& o2::aod::track::itsChi2NCl < electroncuts.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 && nabs(o2::aod::track::dcaXY) < electroncuts.cfg_max_dcaxy&& nabs(o2::aod::track::dcaZ) < electroncuts.cfg_max_dcaz; - using MyFilteredMCTracks = soa::Filtered; + std::vector> vec_min_chi2MatchMCHMFT; // std::pair -> chi2MatchMCHMFT; + template + void findBestMatchPerMCHMID(TMuons const& muons) + { + vec_min_chi2MatchMCHMFT.reserve(muons.size()); + for (const auto& muon : muons) { + if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + const auto& muons_per_MCHMID = muons.sliceBy(fwdtracksPerMCHTrack, muon.globalIndex()); + // LOGF(info, "stanadalone: muon.globalIndex() = %d, muon.chi2MatchMCHMFT() = %f", muon.globalIndex(), muon.chi2MatchMCHMFT()); + // LOGF(info, "muons_per_MCHMID.size() = %d", muons_per_MCHMID.size()); - 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 + float min_chi2MatchMCHMFT = 1e+10; + std::tuple tupleIds_at_min; + for (const auto& muon_tmp : muons_per_MCHMID) { + if (muon_tmp.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + // LOGF(info, "muon_tmp.globalIndex() = %d, muon_tmp.matchMCHTrackId() = %d, muon_tmp.matchMFTTrackId() = %d, muon_tmp.chi2MatchMCHMFT() = %f", muon_tmp.globalIndex(), muon_tmp.matchMCHTrackId(), muon_tmp.matchMFTTrackId(), muon_tmp.chi2MatchMCHMFT()); + if (0.f < muon_tmp.chi2MatchMCHMFT() && muon_tmp.chi2MatchMCHMFT() < min_chi2MatchMCHMFT) { + min_chi2MatchMCHMFT = muon_tmp.chi2MatchMCHMFT(); + tupleIds_at_min = std::make_tuple(muon_tmp.globalIndex(), muon_tmp.matchMCHTrackId(), muon_tmp.matchMFTTrackId()); + } + } + } + vec_min_chi2MatchMCHMFT.emplace_back(tupleIds_at_min); + // LOGF(info, "min: muon_tmp.globalIndex() = %d, muon_tmp.matchMCHTrackId() = %d, muon_tmp.matchMFTTrackId() = %d, muon_tmp.chi2MatchMCHMFT() = %f", std::get<0>(tupleIds_at_min), std::get<1>(tupleIds_at_min), std::get<2>(tupleIds_at_min), min_chi2MatchMCHMFT); + } + } // end of muon loop + } - void process(MyFilteredCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredMCTracks const& tracks, MyMCFwdTracks const&, aod::McCollisions const&, aod::McParticles const&) + void processElectronSA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks, aod::McCollisions const&, aod::McParticles const&) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { auto bc = collision.template foundBC_as(); initCCDB(bc); + if (!isSelectedEvent(collision)) { + continue; + } + if (!collision.has_mcCollision()) { continue; } + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + // auto mccollision = collision.template mcCollision_as(); + // 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) { + for (const auto& track : tracks_per_coll) { if (!track.has_mcParticle()) { continue; } + auto mctrack = track.template mcParticle_as(); - if (mctrack.mcCollisionId() != collision.mcCollisionId()) { + auto mccollision_from_mctrack = mctrack.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_mctrack.getSubGeneratorId() != cfgEventGeneratorType) { continue; } - if (abs(mctrack.pdgCode()) != 11 || !(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + + 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 (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!isSelectedEvent(collision)) { + continue; + } + + if (!collision.has_mcCollision()) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + // auto mccollision = collision.template mcCollision_as(); + // registry.fill(HIST("Event/Electron/hImpPar_Centrality"), mccollision.impactParameter(), centrality); + + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!track.has_mcParticle()) { continue; } - if (!checkTrack(track)) { + auto mctrack = track.template mcParticle_as(); + auto mccollision_from_mctrack = mctrack.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_mctrack.getSubGeneratorId() != cfgEventGeneratorType) { 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); - registry.fill(HIST("Electron/Ptgen_RelDeltaPt"), mctrack.pt(), (mctrack.pt() - track.pt()) / mctrack.pt()); - registry.fill(HIST("Electron/Ptgen_DeltaEta"), mctrack.pt(), mctrack.eta() - track.eta()); - if (mctrack.pdgCode() == -11) { // positron - registry.fill(HIST("Electron/Ptgen_DeltaPhi_Pos"), mctrack.pt(), mctrack.phi() - track.phi()); - } else if (mctrack.pdgCode() == 11) { // electron - registry.fill(HIST("Electron/Ptgen_DeltaPhi_Neg"), mctrack.pt(), mctrack.phi() - track.phi()); - } + // 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 - } // end of track loop + void processMuonSA(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFwdTracks const& fwdtracks, MyMFTTracks const&, aod::McCollisions const&, aod::McParticles const&) + { + findBestMatchPerMCHMID(fwdtracks); + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); - 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); + if (!isSelectedEvent(collision)) { + continue; + } - for (auto& muon : sa_muons_per_coll) { + if (!collision.has_mcCollision()) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + // auto mccollision = collision.template mcCollision_as(); + // registry.fill(HIST("Event/Muon/hImpPar_Centrality"), mccollision.impactParameter(), centrality); + + const auto& fwdtracks_per_coll = fwdtracks.sliceBy(perCollision_fwd, collision.globalIndex()); + for (const auto& muon : fwdtracks_per_coll) { if (!muon.has_mcParticle()) { continue; } + auto mctrack = muon.template mcParticle_as(); - if (mctrack.mcCollisionId() != collision.mcCollisionId()) { - continue; - } - if (abs(mctrack.pdgCode()) != 13 || !(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { - continue; - } - if (!checkFwdTrack(muon, collision)) { + auto mccollision_from_mctrack = mctrack.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_mctrack.getSubGeneratorId() != cfgEventGeneratorType) { continue; } + fillMuon(collision, muon, nullptr, centrality); } // end of standalone muon loop - for (auto& muon : global_muons_per_coll) { + } // end of collision loop + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + 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& fwdtracks, MyMFTTracks const&, aod::FwdTrackAssoc const& fwdtrackIndices, aod::McCollisions const&, aod::McParticles const&) + { + findBestMatchPerMCHMID(fwdtracks); + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!isSelectedEvent(collision)) { + continue; + } + + if (!collision.has_mcCollision()) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + // auto mccollision = collision.template mcCollision_as(); + // registry.fill(HIST("Event/Muon/hImpPar_Centrality"), mccollision.impactParameter(), centrality); + + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto muon = fwdtrackId.template fwdtrack_as(); if (!muon.has_mcParticle()) { continue; } auto mctrack = muon.template mcParticle_as(); - if (mctrack.mcCollisionId() != collision.mcCollisionId()) { + auto mccollision_from_mctrack = mctrack.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_mctrack.getSubGeneratorId() != cfgEventGeneratorType) { continue; } - if (abs(mctrack.pdgCode()) != 13 || !(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + fillMuon(collision, muon, nullptr, centrality); + } // end of fwdtrack loop + } // end of collision loop + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + PROCESS_SWITCH(CreateResolutionMap, processMuonTTCA, "create resolution map for muon at forward rapidity", false); + + std::unordered_map map_mfttrackcovs; + void processMuonTTCA_withMFTCov(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFwdTracks const& fwdtracks, MyMFTTracks const&, aod::MFTTracksCov const& mftCovs, aod::FwdTrackAssoc const& fwdtrackIndices, aod::McCollisions const&, aod::McParticles const&) + { + for (const auto& mfttrackConv : mftCovs) { + map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + } + findBestMatchPerMCHMID(fwdtracks); + + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); + + if (!isSelectedEvent(collision)) { + continue; + } + + if (!collision.has_mcCollision()) { + continue; + } + + float centrality = std::array{collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}[cfgCentEstimator]; + // auto mccollision = collision.template mcCollision_as(); + // registry.fill(HIST("Event/Muon/hImpPar_Centrality"), mccollision.impactParameter(), centrality); + + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto muon = fwdtrackId.template fwdtrack_as(); + if (!muon.has_mcParticle()) { continue; } - if (!checkFwdTrack(muon, collision)) { + auto mctrack = muon.template mcParticle_as(); + auto mccollision_from_mctrack = mctrack.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mccollision_from_mctrack.getSubGeneratorId() != cfgEventGeneratorType) { continue; } - - } // end of global muon loop - + fillMuon(collision, muon, mftCovs, centrality); + } // end of fwdtrack loop } // end of collision loop + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + } + PROCESS_SWITCH(CreateResolutionMap, processMuonTTCA_withMFTCov, "create resolution map for muon at forward rapidity", false); + + void processGen(aod::McCollisions const& mcCollisions) + { + for (const auto& mccollision : mcCollisions) { + registry.fill(HIST("Event/hGenID"), mccollision.getSubGeneratorId()); + } } + PROCESS_SWITCH(CreateResolutionMap, processGen, "process generated info", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGEM/Dilepton/Tasks/dielectronHadronMPC.cxx b/PWGEM/Dilepton/Tasks/dielectronHadronMPC.cxx new file mode 100644 index 00000000000..42cfa2eac28 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/dielectronHadronMPC.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 "PWGEM/Dilepton/Core/DileptonHadronMPC.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"dielectron-hadron-2pc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/dileptonPolarization.cxx b/PWGEM/Dilepton/Tasks/dileptonPolarization.cxx new file mode 100644 index 00000000000..3ce010a8c40 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/dileptonPolarization.cxx @@ -0,0 +1,689 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMFwdTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +// #include "DataFormatsParameters/GRPMagField.h" +// #include "DataFormatsParameters/GRPObject.h" +// #include "DetectorsBase/GeometryManager.h" +// #include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +struct DileptonPolarization { + // 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 cfgPairType{"cfgPairType", 0, "0:dielectron, 1:dimuon"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + Configurable ndepth{"ndepth", 10000, "depth for event mixing"}; + Configurable ndiff_bc_mix{"ndiff_bc_mix", 594, "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, 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", {1, -M_PI / 2, +M_PI / 2}, "Mixing bins - event plane angle"}; + ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; + Configurable cfgPolarizationFrame{"cfgPolarizationFrame", 0, "frame of polarization. 0:CS, 1:HX, else:FATAL"}; + Configurable cfgUseAbs{"cfgUseAbs", false, "flag to use absolute value for cos_theta and phi"}; // this is to increase statistics per bin. + + 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, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 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.1, 11.2, 11.3, 11.4, 11.50, 11.6, 11.7, 11.8, 11.9, 12.0}, "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{"ConYllBins", {1, -1.f, 1.f}, "yll bins for output histograms"}; // pair rapidity + + ConfigurableAxis ConfPolarizationCosThetaBins{"ConfPolarizationCosThetaBins", {20, -1.f, 1.f}, "cos(theta) bins for polarization analysis"}; + ConfigurableAxis ConfPolarizationPhiBins{"ConfPolarizationPhiBins", {1, -M_PI, M_PI}, "phi bins for polarization analysis"}; + ConfigurableAxis ConfPolarizationQuadMomBins{"ConfPolarizationQuadMomBins", {15, -0.5, 1}, "quadrupole moment bins for polarization analysis"}; // quardrupole moment <(3 x cos^2(theta) -1)/2> + + 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 cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF matched track contributes PV. + // Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + 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; + + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + Configurable cfg_min_pair_mass{"cfg_min_pair_mass", 0.0, "min pair mass"}; + Configurable cfg_max_pair_mass{"cfg_max_pair_mass", 1e+10, "max pair 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_track_pt{"cfg_min_track_pt", 0.2, "min pT for single track"}; + Configurable cfg_max_track_pt{"cfg_max_track_pt", 1e+10, "max pT for single track"}; + Configurable cfg_min_track_eta{"cfg_min_track_eta", -0.9, "min eta for single track"}; + Configurable cfg_max_track_eta{"cfg_max_track_eta", +0.9, "max eta for single track"}; + } dileptoncuts; + + struct : ConfigurableGroup { + std::string prefix = "accBins"; + Configurable cfgDM{"cfgDM", 0.1, "dm for lorentz boost"}; + Configurable cfgDPt{"cfgDPt", 0.1, "dpT for lorentz boost"}; + Configurable cfgDEta{"cfgDEta", 0.1, "deta for lorentz boost"}; + Configurable cfgDPhi{"cfgDPhi", 0.1, "dphi (rad.) for lorentz boost"}; + } accBins; + + Service ccdb; + int mRunNumber; + // float d_bz; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_pair_types[2] = {"same/", "mix/"}; + static constexpr std::string_view pair_sign_types[3] = {"uls/", "lspp/", "lsmm/"}; + + std::mt19937 engine; + std::vector zvtx_bin_edges; + std::vector cent_bin_edges; + std::vector ep_bin_edges; + std::vector occ_bin_edges; + + 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 + + void init(InitContext& /*context*/) + { + mRunNumber = 0; + // d_bz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + if (cfgPairType.value == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron)) { + leptonM1 = o2::constants::physics::MassElectron; + leptonM2 = o2::constants::physics::MassElectron; + } else if (cfgPairType.value == static_cast(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDimuon)) { + leptonM1 = o2::constants::physics::MassMuon; + leptonM2 = o2::constants::physics::MassMuon; + } else { + LOG(fatal) << "Please select either dielectron or dimuon"; + } + + 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]); + } + } + + std::random_device seed_gen; + engine = std::mt19937(seed_gen()); + + addhistograms(); + + fRegistry.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.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)); + // } + // 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 << " kG"; + // } 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 << " kG"; + // } + + 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); + + mRunNumber = collision.runNumber(); + } + + ~DileptonPolarization() + { + delete emh_pair_uls; + emh_pair_uls = 0x0; + delete emh_pair_lspp; + emh_pair_lspp = 0x0; + delete emh_pair_lsmm; + emh_pair_lsmm = 0x0; + + map_mixed_eventId_to_globalBC.clear(); + } + + void addhistograms() + { + auto hCollisionCounter = fRegistry.add("Event/before/hCollisionCounter", "collision counter;;Number of events", kTH1D, {{9, 0.5, 9 + 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, "sel8"); + hCollisionCounter->GetXaxis()->SetBinLabel(8, "|Z_{vtx}| < 10 cm"); + hCollisionCounter->GetXaxis()->SetBinLabel(9, "accepted"); + + fRegistry.add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1D, {{100, -50, +50}}, false); + fRegistry.add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1D, {{110, 0, 110}}, false); + fRegistry.add("Event/before/hCorrOccupancy", "occupancy correlation;FT0C occupancy;track occupancy", kTH2D, {{200, 0, 200000}, {200, 0, 20000}}, false); + fRegistry.add("Event/before/hEP2_CentFT0C_forMix", "2nd harmonics event plane for mix;centrality FT0C (%);#Psi_{2} (rad.)", kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); + fRegistry.addClone("Event/before/", "Event/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_dca_axis_title = "DCA_{ll} (#sigma)"; + std::string pair_y_axis_title = "y_{ll}"; + + if (cfgPairType == static_cast(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} (#sigma)"; + pair_y_axis_title = "y_{ee}"; + } else if (cfgPairType == static_cast(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} (#sigma)"; + pair_y_axis_title = "y_{#mu#mu}"; + } + + // 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}; + const AxisSpec axis_y{ConfYllBins, pair_y_axis_title}; + + std::string frameName = "CS"; + if (cfgPolarizationFrame == 0) { + frameName = "CS"; + } else if (cfgPolarizationFrame == 1) { + frameName = "HX"; + } else { + LOG(fatal) << "set 0 or 1 to cfgPolarizationFrame!"; + } + + const AxisSpec axis_cos_theta{ConfPolarizationCosThetaBins, Form("cos(#theta^{%s})", frameName.data())}; + const AxisSpec axis_phi{ConfPolarizationPhiBins, Form("#varphi^{%s} (rad.)", frameName.data())}; + const AxisSpec axis_quadmom{ConfPolarizationQuadMomBins, Form("#frac{3 cos^{2}(#theta^{%s}) -1}{2}", frameName.data())}; + fRegistry.add("Pair/same/uls/hs", "dilepton", kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y, axis_cos_theta, axis_phi, axis_quadmom}, true); + fRegistry.add("Pair/same/uls/hEta", "#eta_{ll}", kTH1D, {{2000, -10, 10}}, true); + + fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); + fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); + fRegistry.addClone("Pair/same/", "Pair/mix/"); + } + + template + bool fillPairInfo(TCollision const& collision, TDilepton const& dilepton) + { + float weight = 1.f; + ROOT::Math::PtEtaPhiMVector v1(dilepton.pt1(), dilepton.eta1(), dilepton.phi1(), leptonM1); + ROOT::Math::PtEtaPhiMVector v2(dilepton.pt2(), dilepton.eta2(), dilepton.phi2(), leptonM2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + + if (v12.M() < dileptoncuts.cfg_min_pair_mass || dileptoncuts.cfg_max_pair_mass < v12.M()) { + return false; + } + + if (v12.Pt() < dileptoncuts.cfg_min_pair_pt || dileptoncuts.cfg_max_pair_pt < v12.Pt()) { + return false; + } + + if (v12.Rapidity() < dileptoncuts.cfg_min_pair_y || dileptoncuts.cfg_max_pair_y < v12.Rapidity()) { + return false; + } + + float pair_dca = pairDCAQuadSum(dilepton.dca1(), dilepton.dca2()); + float cos_thetaPol = 999, phiPol = 999.f; + auto arrM = std::array{static_cast(v12.Px()), static_cast(v12.Py()), static_cast(v12.Pz()), static_cast(v12.M())}; + auto random_sign = std::pow(-1, engine() % 2); // -1^0 = +1 or -1^1 = -1; + auto arrD = dilepton.sign1() * dilepton.sign2() < 0 ? (dilepton.sign1() > 0 ? std::array{static_cast(v1.Px()), static_cast(v1.Py()), static_cast(v1.Pz()), leptonM1} : std::array{static_cast(v2.Px()), static_cast(v2.Py()), static_cast(v2.Pz()), leptonM2}) : (random_sign > 0 ? std::array{static_cast(v1.Px()), static_cast(v1.Py()), static_cast(v1.Pz()), leptonM1} : std::array{static_cast(v2.Px()), static_cast(v2.Py()), static_cast(v2.Pz()), leptonM2}); + if (cfgPolarizationFrame == 0) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } else if (cfgPolarizationFrame == 1) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } + o2::math_utils::bringToPMPi(phiPol); + float quadmom = (3.f * std::pow(cos_thetaPol, 2) - 1.f) / 2.f; + + if (cfgUseAbs) { + cos_thetaPol = std::fabs(cos_thetaPol); + phiPol = std::fabs(phiPol); + } + + if (dilepton.sign1() * dilepton.sign2() < 0) { // ULS + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), cos_thetaPol, phiPol, quadmom, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hEta"), v12.Eta(), weight); + } else if (dilepton.sign1() > 0 && dilepton.sign2() > 0) { // LS++ + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), cos_thetaPol, phiPol, quadmom, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hEta"), v12.Eta(), weight); + } else if (dilepton.sign1() < 0 && dilepton.sign2() < 0) { // LS-- + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), cos_thetaPol, phiPol, quadmom, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hEta"), v12.Eta(), weight); + } + + if constexpr (ev_id == 0) { // same event + auto key_df_collision = std::make_pair(ndf, collision.globalIndex()); + float phi12_tmp = v12.Phi(); + o2::math_utils::bringTo02Pi(phi12_tmp); + EMPair empair = EMPair(v12.Pt(), v12.Eta(), phi12_tmp, v12.M(), 0); + empair.setPositiveLegPxPyPzM(arrD[0], arrD[1], arrD[2], leptonM1); + // empair.setNegativeLegPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), leptonM2); + empair.setPairDCA(pair_dca); + if (dilepton.sign1() * dilepton.sign2() < 0) { // ULS + emh_pair_uls->AddTrackToEventPool(key_df_collision, empair); + } else if (dilepton.sign1() > 0 && dilepton.sign2() > 0) { // LS++ + emh_pair_lspp->AddTrackToEventPool(key_df_collision, empair); + } else if (dilepton.sign1() < 0 && dilepton.sign2() < 0) { // LS-- + emh_pair_lsmm->AddTrackToEventPool(key_df_collision, empair); + } + } + return true; + } + + template + void fillMixedPairInfo(TCollisions const& collisions, TEMH const& emh) + { + const float weight = 1.f; + for (const auto& col1 : collisions) { + auto globalBC1 = map_mixed_eventId_to_globalBC[col1]; + auto pairs_from_col1 = emh->GetTracksPerCollision(col1); + + for (const auto& col2 : collisions) { + auto globalBC2 = map_mixed_eventId_to_globalBC[col2]; + auto pairs_from_col2 = emh->GetTracksPerCollision(col2); + + if (col1.second <= col2.second) { + continue; + } + + uint64_t diffBC = std::max(globalBC1, globalBC2) - std::min(globalBC1, globalBC2); + fRegistry.fill(HIST("Pair/mix/hDiffBC"), diffBC); + if (diffBC < ndiff_bc_mix) { + continue; + } + + for (const auto& empair1 : pairs_from_col1) { + auto v_pos = empair1.getPositiveLeg(); // pt, eta, phi, M + auto arrD = std::array{static_cast(v_pos.Px()), static_cast(v_pos.Py()), static_cast(v_pos.Pz()), leptonM1}; + + auto pairs_from_col2_sliced = std::views::filter(pairs_from_col2, [&](EMPair t) { return std::fabs(t.mass() - empair1.mass()) < accBins.cfgDM && std::fabs(t.pt() - empair1.pt()) < accBins.cfgDPt && std::fabs(t.eta() - empair1.eta()) < accBins.cfgDEta && std::fabs(RecoDecay::constrainAngle(t.phi() - empair1.phi(), -o2::constants::math::PI, 1U)) < accBins.cfgDPhi; }); + for (const auto& empair2 : pairs_from_col2_sliced) { + auto arrM = std::array{static_cast(empair2.px()), static_cast(empair2.py()), static_cast(empair2.pz()), static_cast(empair2.mass())}; + // LOGF(info, "[col1, col2] : empair1.mass() = %f, empair1.pt() = %f, empair1.eta() = %f, empair1.phi() = %f, empair2.mass() = %f, empair2.pt() = %f, empair2.eta() = %f, empair2.phi() = %f", empair1.mass(), empair1.pt(), empair1.eta(), empair1.phi(), empair2.mass(), empair2.pt(), empair2.eta(), empair2.phi()); + + float cos_thetaPol = 999.f, phiPol = 999.f; + if (cfgPolarizationFrame == 0) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } else if (cfgPolarizationFrame == 1) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } + o2::math_utils::bringToPMPi(phiPol); + float quadmom = (3.f * std::pow(cos_thetaPol, 2) - 1.f) / 2.f; + if (cfgUseAbs) { + cos_thetaPol = std::fabs(cos_thetaPol); + phiPol = std::fabs(phiPol); + } + fRegistry.fill(HIST("Pair/mix/") + HIST(pair_sign_types[signType]) + HIST("hs"), empair1.mass(), empair1.pt(), empair1.getPairDCA(), empair1.rapidity(), cos_thetaPol, phiPol, quadmom, weight); + } + } + + for (const auto& empair2 : pairs_from_col2) { + auto v_pos = empair2.getPositiveLeg(); // pt, eta, phi, M + auto arrD = std::array{static_cast(v_pos.Px()), static_cast(v_pos.Py()), static_cast(v_pos.Pz()), leptonM2}; + + auto pairs_from_col1_sliced = std::views::filter(pairs_from_col1, [&](EMPair t) { return std::fabs(t.mass() - empair2.mass()) < accBins.cfgDM && std::fabs(t.pt() - empair2.pt()) < accBins.cfgDPt && std::fabs(t.eta() - empair2.eta()) < accBins.cfgDEta && std::fabs(RecoDecay::constrainAngle(t.phi() - empair2.phi(), -o2::constants::math::PI, 1U)) < accBins.cfgDPhi; }); + for (const auto& empair1 : pairs_from_col1_sliced) { + auto arrM = std::array{static_cast(empair1.px()), static_cast(empair1.py()), static_cast(empair1.pz()), static_cast(empair2.mass())}; + // LOGF(info, "[col2, col1] : empair2.mass() = %f, empair2.pt() = %f, empair2.eta() = %f, empair2.phi() = %f, empair1.mass() = %f, empair1.pt() = %f, empair1.eta() = %f, empair1.phi() = %f", empair2.mass(), empair2.pt(), empair2.eta(), empair2.phi(), empair1.mass(), empair1.pt(), empair1.eta(), empair1.phi()); + + float cos_thetaPol = 999.f, phiPol = 999.f; + if (cfgPolarizationFrame == 0) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } else if (cfgPolarizationFrame == 1) { + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrM, arrD, beamE1, beamE2, beamP1, beamP2, cos_thetaPol, phiPol); + } + o2::math_utils::bringToPMPi(phiPol); + float quadmom = (3.f * std::pow(cos_thetaPol, 2) - 1.f) / 2.f; + if (cfgUseAbs) { + cos_thetaPol = std::fabs(cos_thetaPol); + phiPol = std::fabs(phiPol); + } + fRegistry.fill(HIST("Pair/mix/") + HIST(pair_sign_types[signType]) + HIST("hs"), empair2.mass(), empair2.pt(), empair2.getPairDCA(), empair2.rapidity(), cos_thetaPol, phiPol, quadmom, weight); + } + } + + } // end of col2 loop + } // end of col1 loop + } + + Filter collisionFilter_centrality = eventcuts.cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < eventcuts.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 filteredCollisions = soa::Filtered; + + Filter dileptonFilter_track1 = (dileptoncuts.cfg_min_track_pt < o2::aod::emdilepton::pt1 && o2::aod::emdilepton::pt1 < dileptoncuts.cfg_max_track_pt) && (dileptoncuts.cfg_min_track_eta < o2::aod::emdilepton::eta1 && o2::aod::emdilepton::eta1 < dileptoncuts.cfg_max_track_eta); + Filter dileptonFilter_track2 = (dileptoncuts.cfg_min_track_pt < o2::aod::emdilepton::pt2 && o2::aod::emdilepton::pt2 < dileptoncuts.cfg_max_track_pt) && (dileptoncuts.cfg_min_track_eta < o2::aod::emdilepton::eta2 && o2::aod::emdilepton::eta2 < dileptoncuts.cfg_max_track_eta); + using filteredDileptons = soa::Filtered; + + SliceCache cache; + Preslice perCollision = aod::emdilepton::emthineventId; + Partition dileptonsULS = (o2::aod::emdilepton::sign1 > static_cast(0) && o2::aod::emdilepton::sign2 < static_cast(0)) || (o2::aod::emdilepton::sign1 < static_cast(0) && o2::aod::emdilepton::sign2 > static_cast(0)); + Partition dileptonsLSPP = o2::aod::emdilepton::sign1 > static_cast(0) && o2::aod::emdilepton::sign2 > static_cast(0); + Partition dileptonsLSMM = o2::aod::emdilepton::sign1 < static_cast(0) && o2::aod::emdilepton::sign2 < static_cast(0); + + // using MyEMH_pair = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, std::tuple>; + using MyEMH_pair = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMPair>; + MyEMH_pair* emh_pair_uls = nullptr; + MyEMH_pair* emh_pair_lspp = nullptr; + MyEMH_pair* emh_pair_lsmm = nullptr; + + std::map, uint64_t> map_mixed_eventId_to_globalBC; + static constexpr int ndf = 0; + + template + void runPairing(TCollisions const& collisions, TDileptons const&) + { + emh_pair_uls = new MyEMH_pair(ndepth); + emh_pair_lspp = new MyEMH_pair(ndepth); + emh_pair_lsmm = new MyEMH_pair(ndepth); + + for (const auto& collision : collisions) { + initCCDB(collision); + float centrality = collision.centFT0C(); + if (centrality < eventcuts.cfgCentMin || eventcuts.cfgCentMax < centrality) { + continue; + } + + float ep2 = collision.ep2(); + fRegistry.fill(HIST("Event/after/hZvtx"), collision.posZ()); + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 9); + fRegistry.fill(HIST("Event/after/hCorrOccupancy"), collision.ft0cOccupancyInTimeRange(), collision.trackOccupancyInTimeRange()); + fRegistry.fill(HIST("Event/after/hEP2_CentFT0C_forMix"), collision.centFT0C(), ep2); + + // 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; + } + + auto dileptons_uls_per_coll = dileptonsULS->sliceByCached(aod::emdilepton::emthineventId, collision.globalIndex(), cache); + auto dileptons_lspp_per_coll = dileptonsLSPP->sliceByCached(aod::emdilepton::emthineventId, collision.globalIndex(), cache); + auto dileptons_lsmm_per_coll = dileptonsLSMM->sliceByCached(aod::emdilepton::emthineventId, collision.globalIndex(), cache); + // LOGF(info, "collision.globalIndex() = %d, dileptons_uls_per_coll.size() = %d, dileptons_lspp_per_coll.size() = %d, dileptons_lsmm_per_coll.size() = %d", collision.globalIndex(), dileptons_uls_per_coll.size(), dileptons_lspp_per_coll.size(), dileptons_lsmm_per_coll.size()); + + int nuls = 0, nlspp = 0, nlsmm = 0; + for (const auto& dilepton : dileptons_uls_per_coll) { // ULS + bool is_pair_ok = fillPairInfo<0>(collision, dilepton); + if (is_pair_ok) { + nuls++; + } + } + for (const auto& dilepton : dileptons_lspp_per_coll) { // LS++ + bool is_pair_ok = fillPairInfo<0>(collision, dilepton); + if (is_pair_ok) { + nlspp++; + } + } + for (const auto& dilepton : dileptons_lsmm_per_coll) { // LS-- + bool is_pair_ok = fillPairInfo<0>(collision, dilepton); + if (is_pair_ok) { + nlsmm++; + } + } + + if (!cfgDoMix || !(nuls > 0 || nlspp > 0 || nlsmm > 0)) { + continue; + } + + // LOGF(info, "collision.globalIndex() = %d, collision.posZ() = %f, centrality = %f, ep2 = %f, collision.ft0cOccupancyInTimeRange() = %f, zbin = %d, centbin = %d, epbin = %d, occbin = %d", collision.globalIndex(), collision.posZ(), centrality, ep2, collision.ft0cOccupancyInTimeRange(), zbin, centbin, epbin, occbin); + + auto key_bin = std::make_tuple(zbin, centbin, epbin, occbin); + auto key_df_collision = std::make_pair(ndf, collision.globalIndex()); // this gives the current event. + + if (nuls > 0 || nlspp > 0 || nlsmm > 0) { + map_mixed_eventId_to_globalBC[key_df_collision] = collision.globalBC(); + emh_pair_uls->AddCollisionIdAtLast(key_bin, key_df_collision); + emh_pair_lspp->AddCollisionIdAtLast(key_bin, key_df_collision); + emh_pair_lsmm->AddCollisionIdAtLast(key_bin, key_df_collision); + } // end of if pair exist + + } // end of collision loop + + for (int iz = 0; iz < static_cast(zvtx_bin_edges.size()) - 1; iz++) { + for (int icent = 0; icent < static_cast(cent_bin_edges.size()) - 1; icent++) { + for (int iep = 0; iep < static_cast(ep_bin_edges.size()) - 1; iep++) { + for (int iocc = 0; iocc < static_cast(occ_bin_edges.size()) - 1; iocc++) { + auto key_bin = std::make_tuple(iz, icent, iep, iocc); + auto collisionIds_in_mixing_pool = emh_pair_uls->GetCollisionIdsFromEventPool(key_bin); + LOGF(info, "iz = %d, icent = %d, iep = %d, iocc = %d, collisionIds_in_mixing_pool.size() = %d", iz, icent, iep, iocc, collisionIds_in_mixing_pool.size()); + + fillMixedPairInfo<0>(collisionIds_in_mixing_pool, emh_pair_uls); + fillMixedPairInfo<1>(collisionIds_in_mixing_pool, emh_pair_lspp); + fillMixedPairInfo<2>(collisionIds_in_mixing_pool, emh_pair_lsmm); + } + } + } + } + + delete emh_pair_uls; + emh_pair_uls = 0x0; + delete emh_pair_lspp; + emh_pair_lspp = 0x0; + delete emh_pair_lsmm; + emh_pair_lsmm = 0x0; + + } // end of DF + + void processAnalysis(filteredCollisions const& collisions, filteredDileptons const& dileptons) + { + runPairing(collisions, dileptons); + } + PROCESS_SWITCH(DileptonPolarization, processAnalysis, "run dilepton analysis", true); + + void processDummy(aod::EMThinEvents const&) {} + PROCESS_SWITCH(DileptonPolarization, processDummy, "Dummy function", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"dilepton-polarization"})}; +} diff --git a/PWGEM/Dilepton/Tasks/dimuonHadronMPC.cxx b/PWGEM/Dilepton/Tasks/dimuonHadronMPC.cxx new file mode 100644 index 00000000000..2e0cf5f5e59 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/dimuonHadronMPC.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 "PWGEM/Dilepton/Core/DileptonHadronMPC.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"dimuon-hadron-mpc"})}; +} diff --git a/PWGEM/Dilepton/Tasks/emEfficiencyEE.cxx b/PWGEM/Dilepton/Tasks/emEfficiencyEE.cxx index 3d144d80ea3..907161d9de2 100644 --- a/PWGEM/Dilepton/Tasks/emEfficiencyEE.cxx +++ b/PWGEM/Dilepton/Tasks/emEfficiencyEE.cxx @@ -12,41 +12,46 @@ // // Analysis task for calculating single electron and dielectron efficiency // -#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/ASoA.h" -#include "Framework/DataTypes.h" -#include "Framework/HistogramRegistry.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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" #include "PWGDQ/Core/MCSignal.h" #include "PWGDQ/Core/MCSignalLibrary.h" +#include "PWGDQ/Core/VarManager.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + #include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" #include "Field/MagneticField.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + #include "TGeoGlobalMagField.h" -#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include +#include +#include +#include +#include + +#include +#include using std::cout; using std::endl; @@ -93,7 +98,7 @@ 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 @@ -119,9 +124,12 @@ struct AnalysisEventSelection { 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&) { @@ -138,6 +146,11 @@ struct AnalysisEventSelection { 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); } } @@ -148,23 +161,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 { @@ -197,6 +227,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; @@ -431,7 +462,7 @@ struct AnalysisTrackSelection { 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"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; // output lists OutputObj fOutputQA{"SingleElectronQA"}; @@ -459,6 +490,8 @@ struct AnalysisTrackSelection { std::vector> fHistRecNegSingleRecPartMC; std::vector> fHistRecPosClassCollDoubleCountPartMC; std::vector> fHistRecNegClassCollDoubleCountPartMC; + std::vector> fHistRecPosClassAmbigCollDoubleCountPartMC; + std::vector> fHistRecNegClassAmbigCollDoubleCountPartMC; // Res histos std::vector> fHistRes; @@ -467,7 +500,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&) { @@ -482,6 +515,7 @@ struct AnalysisTrackSelection { 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 @@ -551,22 +585,23 @@ 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, axisAmbig}, 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, axisAmbig}, 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, axisAmbig}, 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, axisAmbig}, 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 @@ -577,23 +612,24 @@ struct AnalysisTrackSelection { 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, axisAmbig}, true)); - fHistRecNegClassCollDoubleCountPartMC.push_back(registry.add(Form("SingleElectron/NoCut_MCVars/Nrec_Neg_ClassCollDoubleCount_%s", fMCSignals.at(i).GetName()), "", HistType::kTH3D, {axisPt, axisMCColl, axisAmbig}, 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, axisAmbig}, 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, axisAmbig}, 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)"}; @@ -635,13 +671,14 @@ 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); @@ -773,8 +810,8 @@ 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++) { @@ -795,8 +832,9 @@ struct AnalysisTrackSelection { if constexpr (smeared) fHistGenSmearedPosPart[isig]->Fill(mctrack.ptSmeared(), mctrack.etaSmeared(), mctrack.phiSmeared()); } - if (fConfigQA) - fHistManQA->FillHistClass(Form("MCTruthGen_%s", (*sig).GetName()), VarManager::fgValues); + if (fConfigQA) { + fHistManQA->FillHistClass(fHistNamesMCQA[isig].Data(), VarManager::fgValues); + } } } } @@ -817,6 +855,7 @@ struct AnalysisTrackSelection { 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++) { @@ -838,7 +877,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); } } } @@ -848,19 +888,10 @@ struct AnalysisTrackSelection { void runRecTrack(TTracks const& groupedTracks, TTracksMC const& tracksMC, bool pass, bool write) { - 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; VarManager::ResetValues(0, VarManager::kNMCParticleVariables); @@ -903,11 +934,6 @@ struct AnalysisTrackSelection { // 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::ReducedTrack) > 0) { @@ -920,38 +946,6 @@ struct AnalysisTrackSelection { 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; - } - - 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; } } } @@ -962,38 +956,6 @@ struct AnalysisTrackSelection { 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 (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); - } 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); - } - } - // track cuts for (unsigned int j = 0; j < fTrackCuts.size(); j++) { if (filterMap & (uint8_t(1) << j)) { if (track.sign() < 0) { @@ -1004,14 +966,29 @@ struct AnalysisTrackSelection { if (fConfigRecWithMC) { + Double_t mcpt = -10000.; + Double_t mceta = -10000.; + Double_t mcphi = -1000.; + + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrack) > 0) { + auto mctrack = track.reducedMCTrack(); + mcpt = mctrack.pt(); + mceta = mctrack.eta(); + mcphi = mctrack.phi(); + } + if constexpr ((TTrackFillMap & VarManager::ObjTypes::Track) > 0) { + if (track.has_mcParticle()) { + auto mctrack = track.template mcParticle_as(); + mcpt = mctrack.pt(); + mceta = mctrack.eta(); + mcphi = mctrack.phi(); + } + } + 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); + fHistRecNegPartMC[j * fMCSignals.size() + i]->Fill(mcpt, mceta, mcphi); } else { - fHistRecPosPartMC[j * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); - if (doublereconstructedtrack[j] == 0) - fHistRecPosSingleRecPartMC[j * fMCSignals.size() + i]->Fill(mmcpt, mmceta, mmcphi); + fHistRecPosPartMC[j * fMCSignals.size() + i]->Fill(mcpt, mceta, mcphi); } } @@ -1055,8 +1032,8 @@ struct AnalysisTrackSelection { 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 + } // end loop over MC signals + } // end loop over reconstructed track belonging to the events } template @@ -1100,25 +1077,31 @@ struct AnalysisTrackSelection { 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) + if (event.isEventSelected() == 1) { VarManager::FillEvent(event); - // printf("Global index of collision %d\n",event.globalIndex()); - if ((reccollisionid == event.globalIndex()) && (event.isEventSelected() == 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(); + // 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 with mccollision but is ambiguous\n"); - } else { - if (ambiguousinfo == 1) - printf("Has reccollision but without mccollision and is ambiguous\n"); + 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; } - 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"); } @@ -1186,36 +1169,36 @@ struct AnalysisTrackSelection { } } - // 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; - } + // // 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; + // } - for (unsigned int j = 0; j < fTrackCuts.size(); j++) { - if (filterMap & (uint8_t(1) << j)) { + // 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; - } + 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++) { @@ -1227,7 +1210,6 @@ struct AnalysisTrackSelection { Double_t mmcphi = -1000.; // No track cut if (fConfigRecWithMC) { - if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrack) > 0) { auto mctrack = track.reducedMCTrack(); mmcpt = mctrack.pt(); @@ -1250,6 +1232,7 @@ struct AnalysisTrackSelection { 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); @@ -1257,6 +1240,7 @@ struct AnalysisTrackSelection { 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()]); } } } @@ -1278,6 +1262,7 @@ struct AnalysisTrackSelection { 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); @@ -1285,6 +1270,7 @@ struct AnalysisTrackSelection { 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()]); } } } @@ -1294,8 +1280,8 @@ struct AnalysisTrackSelection { 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 + } // 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) @@ -1323,6 +1309,7 @@ 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); } @@ -1333,6 +1320,7 @@ struct AnalysisTrackSelection { // } void processMCNoSkimmedMore(soa::Filtered::iterator const& eventMC, MyMCTrackNoSkimmed const& tracksMC) + // void processMCNoSkimmedMore(aod::McCollisions::iterator const& eventMC, MyMCTrackNoSkimmed const& tracksMC) { runMCFillMore(eventMC, tracksMC); } @@ -1353,7 +1341,7 @@ struct AnalysisTrackSelection { // // runDataFill(event, tracks, tracksMC, false); // } - void processDataNoSkimmedMore(MyEventsSelectedNoSkimmed const& events, aod::McCollisions const& eventsMC, MyBarrelTracksNoSkimmed const& tracks, aod::McParticles const& tracksMC, aod::AmbiguousTracks const& ambiTracksMid) + 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); } @@ -1618,7 +1606,7 @@ struct AnalysisSameEventPairing { runRecPair(groupedTracks, tracksMC); } } // end loop over reconstructed event - } // end loop pairing function + } // end loop pairing function template void runMCPairing(TEventMC const& /*eventMC*/, TTracksMC const& tracksMC) @@ -1733,7 +1721,7 @@ struct AnalysisSameEventPairing { } } } // end of true pairing loop - } // end runMCGen + } // end runMCGen template void runRecPair(TTracks const& tracks, TTracksMC const& /*tracksMC*/) @@ -2054,7 +2042,7 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurab 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"); diff --git a/PWGEM/Dilepton/Tasks/evaluateAcceptance.cxx b/PWGEM/Dilepton/Tasks/evaluateAcceptance.cxx new file mode 100644 index 00000000000..9a552f407ae --- /dev/null +++ b/PWGEM/Dilepton/Tasks/evaluateAcceptance.cxx @@ -0,0 +1,406 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file evaluateAcceptance.cxx +/// \brief a task to evaluate pair acceptance in MC +/// \author daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TableHelper.h" + +// #include "Common/Core/trackUtilities.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 "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPLHCIFData.h" + +// #include "DataFormatsCalibration/MeanVertexObject.h" +// #include "DataFormatsParameters/GRPMagField.h" +// #include "DataFormatsParameters/GRPObject.h" +// #include "DetectorsBase/GeometryManager.h" +// #include "DetectorsBase/Propagator.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include +#include +#include + +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::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::pairutil; + +struct evaluateAcceptance { + // 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 cfgPdgLepton{"cfgPdgLepton", 11, "pdg code 11 or 13"}; + ConfigurableAxis ConfMllBins{"ConfMllBins", {400, 0, 4}, "mll bins"}; + ConfigurableAxis ConfPtllBins{"ConfPtllBins", {100, 0, 10}, "pTll bins"}; + ConfigurableAxis ConfYllBins{"ConfYllBins", {400, -10, +10}, "yll bins"}; + ConfigurableAxis ConfCosThetaBins{"ConfCosThetaBins", {40, -1, +1}, "cos theta bins for polarization"}; + ConfigurableAxis ConfPhiBins{"ConfPhiBins", {72, -M_PI, M_PI}, "phi bins for polarization"}; + ConfigurableAxis ConfQuadMomBins{"ConfQuadMomBins", {150, -0.5, 1}, "quadrupole moment bins for polarization"}; + ConfigurableAxis ConfPtlBins{"ConfPtlBins", {200, 0, 10}, "pTl bins"}; + ConfigurableAxis ConfEtalBins{"ConfEtalBins", {200, -10, 10}, "etal bins"}; + + HistogramRegistry fRegistry{"fRegistry"}; + Service ccdb; + int mRunNumber = 0; + + 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; + void init(o2::framework::InitContext&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + if (cfgPdgLepton.value == 11) { + leptonM1 = o2::constants::physics::MassElectron; + leptonM2 = o2::constants::physics::MassElectron; + } else if (cfgPdgLepton.value == 13) { + leptonM1 = o2::constants::physics::MassMuon; + leptonM2 = o2::constants::physics::MassMuon; + } else { + LOGF(fatal, "pdg code must be 11 or 13."); + } + + addHistograms(); + } + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", bc.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); + mRunNumber = bc.runNumber(); + } + + static constexpr std::string_view pair_sign_types[3] = {"uls/", "lspp/", "lsmm/"}; + static constexpr std::string_view dilepton_source_types[20] = { + "sm/Pi0/", // 0 + "sm/Eta/", // 1 + "sm/EtaPrime/", // 2 + "sm/Rho/", // 3 + "sm/Omega/", // 4 + "sm/Omega2ll/", // 5 + "sm/Phi/", // 6 + "sm/Phi2ll/", // 7 + "sm/PromptJPsi/", // 8 + "sm/NonPromptJPsi/", // 9 + "sm/PromptPsi2S/", // 10 + "sm/NonPromptPsi2S/", // 11 + "sm/Upsilon1S/", // 12 + "sm/Upsilon2S/", // 13 + "sm/Upsilon3S/", // 14 + "ccbar/c2l_c2l/", // 15 + "bbbar/b2l_b2l/", // 16 + "bbbar/b2c2l_b2c2l/", // 17 + "bbbar/b2c2l_b2l_sameb/", // 18 + "bbbar/b2c2l_b2l_diffb/" // 19 + }; // unordered_map is better, but cannot be constexpr. + + void addHistograms() + { + auto hCollisionCounter = fRegistry.add("Event/hCollisionCounter", "collision counter", kTH1D, {{2, -0.5f, 1.5f}}, false); + hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); + hCollisionCounter->GetXaxis()->SetBinLabel(2, "accepted"); + + const AxisSpec axisMll{ConfMllBins, "m_{ll} (GeV/c^{2})"}; + const AxisSpec axisPtll{ConfPtllBins, "p_{T,ll} (GeV/c)"}; + const AxisSpec axisYll{ConfYllBins, "y_{ll}"}; + const AxisSpec axisCosThetaCS{ConfCosThetaBins, "cos(#theta^{CS})"}; + const AxisSpec axisPhiCS{ConfPhiBins, "#varphi^{CS} (rad.)"}; + const AxisSpec axisQuadMomCS{ConfQuadMomBins, "#frac{3 cos^{2}(#theta^{CS}) #minus 1}{2}"}; + const AxisSpec axisCosThetaHX{ConfCosThetaBins, "cos(#theta^{HX})"}; + const AxisSpec axisPhiHX{ConfPhiBins, "#varphi^{HX} (rad.)"}; + const AxisSpec axisQuadMomHX{ConfQuadMomBins, "#frac{3 cos^{2}(#theta^{HX}) #minus 1}{2}"}; + + const AxisSpec axisPtl1{ConfPtlBins, "p_{T,l1} (GeV/c)"}; + const AxisSpec axisPtl2{ConfPtlBins, "p_{T,l2} (GeV/c)"}; + const AxisSpec axisEtal1{ConfEtalBins, "#eta_{l1}"}; + const AxisSpec axisEtal2{ConfEtalBins, "#eta_{l2}"}; + + // for pairs + fRegistry.add("Generated/sm/Pi0/uls/hs", "gen. dilepton", kTHnSparseD, {axisMll, axisPtll, axisYll, axisCosThetaCS, axisPhiCS, axisQuadMomCS, axisCosThetaHX, axisPhiHX, axisQuadMomHX, axisPtl1, axisPtl2, axisEtal1, axisEtal2}, true); + fRegistry.addClone("Generated/sm/Pi0/uls/", "Generated/sm/Pi0/lspp/"); + fRegistry.addClone("Generated/sm/Pi0/uls/", "Generated/sm/Pi0/lsmm/"); + 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/Omega2ll/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Phi/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Phi2ll/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/PromptJPsi/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/NonPromptJPsi/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/PromptPsi2S/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/NonPromptPsi2S/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Upsilon1S/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Upsilon2S/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/sm/Upsilon3S/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/ccbar/c2l_c2l/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/bbbar/b2l_b2l/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/bbbar/b2c2l_b2c2l/"); + fRegistry.addClone("Generated/sm/Pi0/", "Generated/bbbar/b2c2l_b2l_sameb/"); // ULS + fRegistry.addClone("Generated/sm/Pi0/", "Generated/bbbar/b2c2l_b2l_diffb/"); // LS + } + + template + void fillGenPairInfo(TLepton const& t1, TLepton const& t2, TMCParticles const& mcParticles) + { + if (!t1.isPhysicalPrimary() && !t1.producedByGenerator()) { + return; + } + if (!t2.isPhysicalPrimary() && !t2.producedByGenerator()) { + return; + } + + int mother_id = std::max({FindSMULS(t1, t2, mcParticles), FindSMULS(t2, t1, mcParticles), FindSMLSPP(t1, t2, mcParticles), FindSMLSMM(t1, t2, mcParticles)}); + int hfee_type = IsHF(t1, t2, mcParticles); + if (mother_id < 0 && hfee_type < 0) { + return; + } + + 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; + + int sign1 = t1.pdgCode() > 0 ? -1 : 1; + std::array arrP1 = {t1.px(), t1.py(), t1.pz(), leptonM1}; + std::array arrP2 = {t2.px(), t2.py(), t2.pz(), leptonM2}; + float cosThetaCS = 999, phiCS = 999.f; + float cosThetaHX = 999, phiHX = 999.f; + o2::aod::pwgem::dilepton::utils::pairutil::getAngleCS(arrP1, arrP2, beamE1, beamE2, beamP1, beamP2, sign1, cosThetaCS, phiCS); + o2::aod::pwgem::dilepton::utils::pairutil::getAngleHX(arrP1, arrP2, beamE1, beamE2, beamP1, beamP2, sign1, cosThetaHX, phiHX); + o2::math_utils::bringToPMPi(phiCS); + o2::math_utils::bringToPMPi(phiHX); + float quadmomCS = (3.f * std::pow(cosThetaCS, 2) - 1.f) / 2.f; + float quadmomHX = (3.f * std::pow(cosThetaHX, 2) - 1.f) / 2.f; + + if (mother_id > -1) { + auto mcmother = mcParticles.iteratorAt(mother_id); + int nd = mcmother.daughtersIds()[1] - mcmother.daughtersIds()[0] + 1; // number of daughters + switch (std::abs(mcmother.pdgCode())) { + case 111: + fRegistry.fill(HIST("Generated/sm/Pi0/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case 221: + fRegistry.fill(HIST("Generated/sm/Eta/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case 331: + fRegistry.fill(HIST("Generated/sm/EtaPrime/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case 113: + fRegistry.fill(HIST("Generated/sm/Rho/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case 223: + fRegistry.fill(HIST("Generated/sm/Omega/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + if (nd == 2) { + fRegistry.fill(HIST("Generated/sm/Omega2ll/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + } + break; + case 333: + fRegistry.fill(HIST("Generated/sm/Phi/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + if (nd == 2) { + fRegistry.fill(HIST("Generated/sm/Phi2ll/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + } + break; + case 443: + if (IsFromBeauty(mcmother, mcParticles) > 0) { + fRegistry.fill(HIST("Generated/sm/NonPromptJPsi/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + } else { + fRegistry.fill(HIST("Generated/sm/PromptJPsi/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + } + break; + case 100443: + if (IsFromBeauty(mcmother, mcParticles) > 0) { + fRegistry.fill(HIST("Generated/sm/NonPromptPsi2S/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + } else { + fRegistry.fill(HIST("Generated/sm/PromptPsi2S/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + } + break; + case 553: + fRegistry.fill(HIST("Generated/sm/Upsilon1S/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case 100553: + fRegistry.fill(HIST("Generated/sm/Upsilon2S/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case 200553: + fRegistry.fill(HIST("Generated/sm/Upsilon3S/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + default: + break; + } + } else if (hfee_type > -1) { + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + fRegistry.fill(HIST("Generated/ccbar/c2l_c2l/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case static_cast(EM_HFeeType::kBe_Be): + fRegistry.fill(HIST("Generated/bbbar/b2l_b2l/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case static_cast(EM_HFeeType::kBCe_BCe): + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2c2l/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_sameb/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): + fRegistry.fill(HIST("Generated/bbbar/b2c2l_b2l_diffb/") + HIST(pair_sign_types[pairSignId]) + HIST("hs"), v12.M(), v12.Pt(), v12.Rapidity(), cosThetaCS, phiCS, quadmomCS, cosThetaHX, phiHX, quadmomHX, t1.pt(), t2.pt(), t1.eta(), t2.eta()); + break; + default: + break; + } + } + } + + template + int FindSMULS(TTrack const& t1mc, TTrack const& t2mc, TMCParticles const& mcParticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 111, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 221, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 331, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 113, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 223, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 333, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 443, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 100443, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 553, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 100553, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, cfgPdgLepton, 200553, mcParticles)}; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; + } + + template + int FindSMLSPP(TTrack const& t1mc, TTrack const& t2mc, TMCParticles const& mcParticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, -cfgPdgLepton, 221, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, -cfgPdgLepton, 331, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, -cfgPdgLepton, 113, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, -cfgPdgLepton, 223, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, -cfgPdgLepton, -cfgPdgLepton, 333, mcParticles)}; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; + } + + template + int FindSMLSMM(TTrack const& t1mc, TTrack const& t2mc, TMCParticles const& mcParticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(t1mc, t2mc, cfgPdgLepton, cfgPdgLepton, 221, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, cfgPdgLepton, cfgPdgLepton, 331, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, cfgPdgLepton, cfgPdgLepton, 113, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, cfgPdgLepton, cfgPdgLepton, 223, mcParticles), + FindCommonMotherFrom2Prongs(t1mc, t2mc, cfgPdgLepton, cfgPdgLepton, 333, mcParticles)}; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; + } + + SliceCache cache; + Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; + Partition posLeptons = o2::aod::mcparticle::pdgCode == -cfgPdgLepton; // l+ + Partition negLeptons = o2::aod::mcparticle::pdgCode == cfgPdgLepton; // l- + + void process(aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) + { + for (const auto& mcCollision : mcCollisions) { + auto bc = mcCollision.template bc_as(); + initCCDB(bc); + + fRegistry.fill(HIST("Event/hCollisionCounter"), 0); + if (cfgEventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + fRegistry.fill(HIST("Event/hCollisionCounter"), 1); + + auto posLeptons_per_coll = posLeptons->sliceByCached(o2::aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + auto negLeptons_per_coll = negLeptons->sliceByCached(o2::aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + // LOGF(info, "mcCollision.globalIndex() = %d, posLeptons_per_coll.size() = %d, negLeptons_per_coll.size() = %d", mcCollision.globalIndex(), posLeptons_per_coll.size(), negLeptons_per_coll.size()); + + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(posLeptons_per_coll, negLeptons_per_coll))) { // ULS + if (!(t1.isPhysicalPrimary() || t1.producedByGenerator()) || !(t2.isPhysicalPrimary() || t2.producedByGenerator())) { + continue; + } + fillGenPairInfo<0>(t1, t2, mcParticles); + } // end of ULS pairing + + for (const auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(posLeptons_per_coll, posLeptons_per_coll))) { // LS++ + if (!(t1.isPhysicalPrimary() || t1.producedByGenerator()) || !(t2.isPhysicalPrimary() || t2.producedByGenerator())) { + continue; + } + fillGenPairInfo<1>(t1, t2, mcParticles); + } // end of LS++ pairing + + for (const auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(negLeptons_per_coll, negLeptons_per_coll))) { // LS-- + if (!(t1.isPhysicalPrimary() || t1.producedByGenerator()) || !(t2.isPhysicalPrimary() || t2.producedByGenerator())) { + continue; + } + fillGenPairInfo<2>(t1, t2, mcParticles); + } // end of LS++ pairing + + } // end of mc collision loop + } +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"evaluate-acceptance"})}; +} diff --git a/PWGEM/Dilepton/Tasks/eventQC.cxx b/PWGEM/Dilepton/Tasks/eventQC.cxx new file mode 100644 index 00000000000..ab4da666df8 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/eventQC.cxx @@ -0,0 +1,997 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" + +#include "TString.h" + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct eventQC { + 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; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + Configurable cfg_swt_name{"cfg_swt_name", "fHighTrackMult", "desired software trigger name"}; + Configurable cfgFillEvent{"cfgFillEvent", false, "fill event histograms"}; + Configurable cfgFillTrack{"cfgFillTrack", false, "fill track histograms"}; + Configurable cfgFillPID{"cfgFillPID", false, "fill PID 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", -1.f, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + Configurable cfgNumContribMin{"cfgNumContribMin", 0, "min. numContrib"}; + Configurable cfgNumContribMax{"cfgNumContribMax", 65000, "max. numContrib"}; + 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"}; + + ConfigurableAxis ConfFT0AMultBins{"ConfFT0AMultBins", {200, 0, 200e+3}, "FT0A multiplicity bins for output histograms"}; + ConfigurableAxis ConfFT0CMultBins{"ConfFT0CMultBins", {600, 0, 60e+3}, "FT0C multiplicity bins for output histograms"}; + ConfigurableAxis ConfFV0AMultBins{"ConfFV0AMultBins", {200, 0, 200e+3}, "FV0A multiplicity bins for output histograms"}; + ConfigurableAxis ConfTrackMultBins{"ConfTrackMultBins", {6001, -0.5, 6e+3 + 0.5}, "Track multiplicity bins for output histograms"}; + ConfigurableAxis ConfCentBins{"ConfCentBins", {110, 0, 110}, "centrality bins for output histograms"}; + + struct : ConfigurableGroup { + std::string prefix = "eventcut_group"; + 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 cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF matched track contributes PV. + 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; + + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadronPID, 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"}; + o2::aod::rctsel::RCTFlagsChecker rctChecker; + + Zorro zorro; + std::vector mTOIidx; + uint64_t mNinspectedTVX{0}; + std::vector swt_names; + + int mRunNumber; + Service ccdb; + + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::string_view event_types[2] = {"before/", "after/"}; + + void init(InitContext&) + { + mRunNumber = 0; + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + rctChecker.init(cfgRCTLabel.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + + addhistograms(); + } + + ~eventQC() {} + + template + void initCCDB(TBC const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + + mTOIidx = zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_name.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()); + fRegistry.fill(HIST("hNInspectedTVX"), bc.runNumber(), mNinspectedTVX); + + mRunNumber = bc.runNumber(); + } + + void addhistograms() + { + const AxisSpec axis_cent_ft0m{ConfCentBins, "centrality FT0M (%)"}; + const AxisSpec axis_cent_ft0a{ConfCentBins, "centrality FT0A (%)"}; + const AxisSpec axis_cent_ft0c{ConfCentBins, "centrality FT0C (%)"}; + + const AxisSpec axis_mult_ft0a{ConfFT0AMultBins, "FT0A multiplicity"}; + const AxisSpec axis_mult_ft0c{ConfFT0CMultBins, "FT0C multiplicity"}; + const AxisSpec axis_mult_fv0a{ConfFV0AMultBins, "FV0A multiplicity"}; + const AxisSpec axis_mult_ncontrib{ConfTrackMultBins, "N_{track} to PV"}; + const AxisSpec axis_mult_ncontrib08{ConfTrackMultBins, "N_{track} to PV in |#eta| < 0.8"}; + const AxisSpec axis_mult_global_ncontrib08{ConfTrackMultBins, "N_{track}^{global} to PV in |#eta| < 0.8"}; + const AxisSpec axis_mult_globalTrack{ConfTrackMultBins, "N_{track}^{global} in |#eta| < 0.8"}; + + if (doprocessEventQC_SWT) { + fRegistry.add("BC/hNcoll", "Number of collisions per triggered BC;N_{collision} per triggered BC", kTH1F, {{11, -0.5, +10.5}}, false); + fRegistry.add("BC/Collision/hMultNTracksPV", "hMultNTracksPV;N_{track} to PV", kTH1F, {{axis_mult_ncontrib}}, false); + fRegistry.add("BC/Collision/hMultFT0AFT0C", "hMultFT0AFT0C;mult. FT0A;mult. FT0C", kTH2F, {{axis_mult_ft0a}, {axis_mult_ft0c}}, false); + fRegistry.add("BC/Collision/hMultFT0AFV0A", "hMultFT0AFV0A;mult. FT0A;mult. FV0A", kTH2F, {{axis_mult_ft0a}, {axis_mult_fv0a}}, false); + fRegistry.add("BC/Collision/hMultFT0CFV0A", "hMultFT0CFV0A;mult. FT0C;mult. FV0A", kTH2F, {{axis_mult_ft0c}, {axis_mult_fv0a}}, false); + + fRegistry.add("perBC/hDeltaTZ", "#DeltaZ_{vtx} vs. #DeltaT of collisions per BC;#DeltaZ_{vtx} (cm);#DeltaT (ns)", kTH2F, {{100, -5, +5}, {50, -25, +25}}, false); + fRegistry.add("perBC/hCorrNcontrib", "hMultNTracksPV;", kTH2F, {{axis_mult_ncontrib}, {axis_mult_ncontrib}}, false); + // fRegistry.addClone("perBC/", "beyondBC/"); + } + + // 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"); + + fRegistry.add("hNInspectedTVX", "N inspected TVX;run number;N_{TVX}", kTProfile, {{80000, 520000.5, 600000.5}}, true); + + 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, {{axis_mult_ncontrib}}, false); + fRegistry.add("Event/before/hMultNTracksPV08", "hMultNTracksPV08; N_{track} to PV in |#eta| < 0.8", kTH1F, {{axis_mult_ncontrib08}}, false); + fRegistry.add("Event/before/hMultFT0AFT0C", "hMultFT0AFT0C;mult. FT0A;mult. FT0C", kTH2F, {{axis_mult_ft0a}, {axis_mult_ft0c}}, false); + fRegistry.add("Event/before/hMultFT0AFV0A", "hMultFT0AFV0A;mult. FT0A;mult. FV0A", kTH2F, {{axis_mult_ft0a}, {axis_mult_fv0a}}, false); + fRegistry.add("Event/before/hMultFT0CFV0A", "hMultFT0CFV0A;mult. FT0C;mult. FV0A", kTH2F, {{axis_mult_ft0c}, {axis_mult_fv0a}}, false); + fRegistry.add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{axis_cent_ft0a}}, false); + fRegistry.add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{axis_cent_ft0c}}, false); + fRegistry.add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{axis_cent_ft0m}}, false); + fRegistry.add("Event/before/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV in |#eta| < 0.8", kTH2F, {{axis_cent_ft0c}, {axis_mult_ncontrib08}}, false); + fRegistry.add("Event/before/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV in |#eta| < 0.8", kTH2F, {{axis_mult_ft0c}, {axis_mult_ncontrib08}}, false); + fRegistry.add("Event/before/hMultFT0CvsTrackOccupancy", "hMultFT0CvsTrackOccupancy;mult. FT0C;N_{track} in time range", kTH2F, {{axis_mult_ft0c}, {200, 0, 20000}}, false); + fRegistry.add("Event/before/hMultFV0AvsMultNTracksPV", "hMultFV0AvsMultNTracksPV;mult. FV0A;N_{track} to PV in |#eta| < 0.8", kTH2F, {{axis_mult_fv0a}, {axis_mult_ncontrib08}}, false); + fRegistry.add("Event/before/hNTracksPVvsTrackOccupancy", "hNTracksPVvsTrackOccupancy;N_{track} to PV in |#eta| < 0.8;N_{track} in time range", kTH2F, {{axis_mult_ncontrib08}, {200, 0, 20000}}, false); + fRegistry.add("Event/before/hNGlobalTracksvsTrackOccupancy", "hNGlobalTracksvsTrackOccupancy;N_{track}^{global} in |#eta| < 0.8;N_{track} in time range", kTH2F, {{axis_mult_globalTrack}, {200, 0, 20000}}, false); + fRegistry.add("Event/before/hNGlobalTracksPVvsTrackOccupancy", "hNGlobalTracksPVvsTrackOccupancy;N_{track}^{global} to PV in |#eta| < 0.8;N_{track} in time range", kTH2F, {{axis_mult_global_ncontrib08}, {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} in |#eta| < 0.8", kTH1F, {{axis_mult_globalTrack}}, false); + fRegistry.add("Event/after/hCentFT0CvsMultNGlobalTracks", "hCentFT0CvsMultNGlobalTracks;centrality FT0C (%);N_{track}^{global} in |#eta| < 0.8", kTH2F, {{axis_cent_ft0c}, {axis_mult_globalTrack}}, false); + fRegistry.add("Event/after/hMultFT0CvsMultNGlobalTracks", "hMultFT0CvsMultNGlobalTracks;mult. FT0C;N_{track}^{global} in |#eta| < 0.8", kTH2F, {{axis_mult_ft0c}, {axis_mult_globalTrack}}, false); + fRegistry.add("Event/after/hMultNGlobalTracksPV", "hMultNGlobalTracksPV; N_{track}^{global} to PV in |#eta| < 0.8", kTH1F, {{axis_mult_global_ncontrib08}}, false); + fRegistry.add("Event/after/hCentFT0CvsMultNGlobalTracksPV", "hCentFT0CvsMultNGlobalTracksPV;centrality FT0C (%);N_{track}^{global} to PV in |#eta| < 0.8", kTH2F, {{axis_cent_ft0c}, {axis_mult_global_ncontrib08}}, false); + fRegistry.add("Event/after/hMultFT0CvsMultNGlobalTracksPV", "hMultFT0CvsMultNGlobalTracksPV;mult. FT0C;N_{track}^{global} to PV in |#eta| < 0.8", kTH2F, {{axis_mult_ft0c}, {axis_mult_global_ncontrib08}}, 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, -2.0, +2.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/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); + 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); + 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/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); on ITS #times cos(#lambda);", kTH2F, {{1000, 0.f, 10.f}, {150, 0, 15}}, 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/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/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + fRegistry.fill(HIST("Track/hTOFNsigmaKa"), track.p(), track.tofNSigmaKa()); + fRegistry.fill(HIST("Track/hTOFNsigmaPr"), track.p(), track.tofNSigmaPr()); + + 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()))); + } + } + + 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.numContrib()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultNTracksPV08"), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0AFT0C"), collision.multFT0A(), collision.multFT0C()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0AFV0A"), collision.multFT0A(), collision.multFV0A()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0CFV0A"), collision.multFT0C(), collision.multFV0A()); + 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("hMultFV0AvsMultNTracksPV"), collision.multFV0A(), collision.multNTracksPV()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0CvsTrackOccupancy"), collision.multFT0C(), collision.trackOccupancyInTimeRange()); + fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hNTracksPVvsTrackOccupancy"), 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 isSelectedCollision(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.cfgRequireVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + + if (eventcuts.cfgRequireVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + 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 = ifnode(eventcuts.cfgRequireSel8.node(), o2::aod::evsel::sel8 == true, true); + Filter collisionFilter_zvtx = 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_numContrib = cfgNumContribMin <= o2::aod::collision::numContrib && o2::aod::collision::numContrib < cfgNumContribMax; + 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 perBC = o2::aod::collision::bcId; + PresliceUnsorted perFoundBC = aod::evsel::foundBCId; + + template + void runQC(TBCs const& bcs, TCollisions const& collisions, TTracks const& tracks) + { + if constexpr (isTriggerAnalysis) { + // std::vector selectedCollisionIds; + // selectedCollisionIds.reserve(collisions.size()); + + for (const auto& bc : bcs) { + initCCDB(bc); + if (!zorro.isSelected(bc.globalBC())) { // triggered BC + continue; + } + + // const auto& collisions_per_bc = collisions.sliceBy(perBC, bc.globalIndex()); + const auto& collisions_per_bc = collisions.sliceBy(perFoundBC, bc.globalIndex()); + fRegistry.fill(HIST("BC/hNcoll"), collisions_per_bc.size()); + for (const auto& collision : collisions_per_bc) { + if (!isSelectedCollision(collision)) { + continue; + } + + fRegistry.fill(HIST("BC/Collision/hMultNTracksPV"), collision.numContrib()); + fRegistry.fill(HIST("BC/Collision/hMultFT0AFT0C"), collision.multFT0A(), collision.multFT0C()); + fRegistry.fill(HIST("BC/Collision/hMultFT0AFV0A"), collision.multFT0A(), collision.multFV0A()); + fRegistry.fill(HIST("BC/Collision/hMultFT0CFV0A"), collision.multFT0C(), collision.multFV0A()); + // selectedCollisionIds.emplace_back(collision.globalIndex()); + } + + for (const auto& [col1, col2] : combinations(CombinationsStrictlyUpperIndexPolicy(collisions_per_bc, collisions_per_bc))) { + if (!isSelectedCollision(col1) || !isSelectedCollision(col2)) { + continue; + } + fRegistry.fill(HIST("perBC/hDeltaTZ"), col1.posZ() - col2.posZ(), col1.collisionTime() - col2.collisionTime()); + fRegistry.fill(HIST("perBC/hCorrNcontrib"), col1.numContrib(), col2.numContrib()); + } // end of pairing + } // end of bc loop + + // for (const auto& collisionId1 : selectedCollisionIds) { + // const auto& col1 = collisions.rawIteratorAt(collisionId1); + // for (const auto& col2 : collisions) { + // if (!isSelectedCollision(col2)) { + // continue; + // } + + // const auto& bc1 = col1.template bc_as(); // don't use foundBC for CEFP. + // const auto& bc2 = col2.template bc_as(); // don't use foundBC for CEFP. + // if (bc1.globalBC() == bc2.globalBC()) { + // continue; + // } + // fRegistry.fill(HIST("beyondBC/hDeltaTZ"), col1.posZ() - col2.posZ(), col1.collisionTime() - col2.collisionTime()); + // fRegistry.fill(HIST("beyondBC/hCorrNcontrib"), col1.numContrib(), col2.numContrib()); + // } // end of all collision loop + // } // end of selected collision loop + + // selectedCollisionIds.clear(); + // selectedCollisionIds.shrink_to_fit(); + } // end of trigger QC + + for (const auto& collision : collisions) { + if constexpr (isTriggerAnalysis) { + const auto& bc = collision.template bc_as(); // don't use foundBC for CEFP. + initCCDB(bc); + if (!zorro.isSelected(bc.globalBC())) { // triggered event + continue; + } + } + + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + + if (cfgFillEvent) { + fillEventInfo<0>(collision); + } + if (!isSelectedCollision(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 (const 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/hNGlobalTracksvsTrackOccupancy"), nGlobalTracks, collision.trackOccupancyInTimeRange()); + fRegistry.fill(HIST("Event/after/hNGlobalTracksPVvsTrackOccupancy"), nGlobalTracksPV, collision.trackOccupancyInTimeRange()); + fRegistry.fill(HIST("Event/after/hCentFT0CvsMultNGlobalTracks"), collision.centFT0C(), nGlobalTracks); + fRegistry.fill(HIST("Event/after/hCentFT0CvsMultNGlobalTracksPV"), collision.centFT0C(), nGlobalTracksPV); + } + + } // end of collision loop + } // end of process + + void processEventQC(MyBCs const& bcs, FilteredMyCollisions const& collisions, FilteredMyTracks const& tracks) + { + runQC(bcs, collisions, tracks); + } + PROCESS_SWITCH(eventQC, processEventQC, "event QC", true); + + void processEventQC_SWT(MyBCs const& bcs, FilteredMyCollisions const& collisions, FilteredMyTracks const& tracks) + { + runQC(bcs, collisions, tracks); + } + PROCESS_SWITCH(eventQC, processEventQC_SWT, "event QC", false); + + void processEventQC_Cent_Qvec(MyBCs const& bcs, FilteredMyCollisions_Qvec const& collisions, FilteredMyTracks const& tracks) + { + runQC(bcs, collisions, tracks); + } + PROCESS_SWITCH(eventQC, processEventQC_Cent_Qvec, "event QC + q vector", 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 index f1b9148ab8e..49d6a823d05 100644 --- a/PWGEM/Dilepton/Tasks/lmeeHFCocktail.cxx +++ b/PWGEM/Dilepton/Tasks/lmeeHFCocktail.cxx @@ -15,13 +15,18 @@ /// \author Daniel Samitz, , SMI Vienna /// Elisa Meninno, , SMI Vienna -#include "Math/Vector4D.h" -#include "Framework/Task.h" -#include "Framework/runDataProcessing.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "PWGEM/Dilepton/Utils/MCUtilities.h" -#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "Framework/Task.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" + +#include "Math/Vector4D.h" + +#include using namespace o2; using namespace o2::framework; @@ -49,6 +54,8 @@ 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, @@ -57,21 +64,48 @@ DECLARE_SOA_TABLE(HfTable, "AOD", "HFTABLE", hftable::BQuarkId, hftable::CQuarkId, hftable::BQuarkOriginId, - hftable::CQuarkOriginId); + hftable::CQuarkOriginId, + hftable::BQuarkRap, + hftable::CQuarkRap); } // namespace o2::aod -const char* stageNames[3] = {"gen", "eff", "eff_and_acc"}; +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 ptMax, float etaMax, int pdg) +{ + float pt[Nstages] = {p.pt(), p.ptSmeared(), p.ptSmeared()}; + float eta[Nstages] = {p.eta(), p.etaSmeared(), p.etaSmeared()}; + float cut_ptMin[Nstages] = {0., 0., ptMin}; + float cut_ptMax[Nstages] = {99999., 99999., ptMax}; + float cut_eta[Nstages] = {99999., 99999., etaMax}; + for (int i = 0; i < Nstages; i++) { + if (pt[i] > cut_ptMin[i] && pt[i] < cut_ptMax[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) +void doSingle(T& p, std::vector> hEta, std::vector> hPt, std::vector> hPtEta, float ptMin, float ptMax, float etaMax) { - float weight[3] = {p.weight(), p.efficiency() * p.weight(), p.efficiency() * p.weight()}; - float pt[3] = {p.pt(), p.ptSmeared(), p.ptSmeared()}; - float eta[3] = {p.eta(), p.etaSmeared(), p.etaSmeared()}; - float cut_pt[3] = {0., 0., ptMin}; - float cut_eta[3] = {9999., 99999., etaMax}; - for (int i = 0; i < 3; i++) { - if (pt[i] > cut_pt[i] && abs(eta[i]) < cut_eta[i]) { + 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_ptMin[Nstages] = {0., 0., ptMin}; + float cut_ptMax[Nstages] = {99999., 99999., ptMax}; + float cut_eta[Nstages] = {99999., 99999., etaMax}; + for (int i = 0; i < Nstages; i++) { + if (pt[i] > cut_ptMin[i] && pt[i] < cut_ptMax[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]); @@ -80,7 +114,7 @@ void doSingle(T& p, std::vector> hEta, std::vector -void doPair(T& p1, T& p2, std::vector> hMee, std::vector> hMeePtee, float ptMin, float etaMax) +void doPair(T& p1, T& p2, std::vector> hMee, std::vector> hMeePtee, float ptMin, float ptMax, 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); @@ -90,18 +124,26 @@ void doPair(T& p1, T& p2, std::vector> hMee, std::vector cut_pt[i] && pt2[i] > cut_pt[i] && abs(eta1[i]) < cut_eta[i] && abs(eta2[i]) < cut_eta[i]) { + 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_ptMin[Nstages] = {0., 0., ptMin}; + float cut_ptMax[Nstages] = {99999., 99999., ptMax}; + float cut_eta[Nstages] = {99999., 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_ptMin[i] && pt2[i] > cut_ptMin[i] && pt1[i] < cut_ptMax[i] && pt2[i] < cut_ptMax[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]); } @@ -109,36 +151,78 @@ void doPair(T& p1, T& p2, std::vector> hMee, std::vector fConfigPtMin{"cfgPtMin", 0.2, "min. pT"}; - Configurable fConfigEtaMax{"cfgEtaMax", 0.8, "max. |eta|"}; - ConfigurableAxis fConfigPtBins{"cfgPtBins", {200, 0.f, 10.f}, "pT binning"}; - ConfigurableAxis fConfigEtaBins{"cfgEtaBins", {200, -10.f, 10.f}, "eta binning"}; + Configurable fConfigPtMin{"cfgPtMin", 0.2, "min. pT of single electrons"}; + Configurable fConfigPtMax{"cfgPtMax", 99999., "max. 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 { + HistogramRegistry registry{"registry", {}}; + std::vector> hRapQuark; Produces hfTable; + ConfigurableAxis fConfigRapBins{"cfgRapBins", {200, -10.f, 10.f}, "Quark rapidity binning"}; + + void init(o2::framework::InitContext&) + { + const int Nchannels = 2; + const char* typeNamesSingle[Nchannels] = {"b", "c"}; + const char* typeTitlesSingle[Nchannels] = {"b", "c"}; + + AxisSpec rap_axis = {fConfigRapBins, "y_{b}"}; + + // quark histograms + for (int i = 0; i < Nchannels; i++) { + hRapQuark.push_back(registry.add(Form("Quark_Rap_%s", typeNamesSingle[i]), Form("Rap Quark %s", typeTitlesSingle[i]), HistType::kTH1F, {rap_axis}, true)); + } + } + void process(aod::McParticles const& mcParticles) { for (auto const& p : mcParticles) { + // Look at quarks which fragment + if (abs(p.pdgCode()) == 5 || abs(p.pdgCode()) == 4) { + bool foundhadrons = kFALSE; + if (p.has_daughters()) { + const auto& daughtersSlice = p.daughters_as(); + for (auto& d : daughtersSlice) { + int pdgfragment = d.pdgCode(); + if (static_cast(abs(pdgfragment) / 100.) == abs(p.pdgCode()) || static_cast(abs(pdgfragment) / 1000.) == abs(p.pdgCode())) { + foundhadrons = kTRUE; + } + } + } + if (foundhadrons) { + if (abs(p.pdgCode()) == 4) + hRapQuark[1]->Fill(p.y()); + else if (abs(p.pdgCode()) == 5) + hRapQuark[0]->Fill(p.y()); + } + } + // Look at electrons if (abs(p.pdgCode()) != 11 || o2::mcgenstatus::getHepMCStatusCode(p.statusCode()) != 1 || !p.has_mothers()) { - hfTable(EFromHFType::kNoE, -1, -1, -1, -1, -1, -1); + 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 - } + // Mother is an open-charm hadon (meson or baryon) expected to decay semi-leptonicly + bool direct_charm_mother = ((std::abs(mother_pdg) >= 400) && (std::abs(mother_pdg) <= 439)) || ((std::abs(mother_pdg) >= 4000) && (std::abs(mother_pdg) <= 4399)); 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'); + // Mother is an open-beuaty hadron (meson or baryon) expected to decay semi-leptonicly + bool direct_beauty_mother = ((std::abs(mother_pdg) >= 500) && (std::abs(mother_pdg) <= 549)) || ((std::abs(mother_pdg) >= 5000) && (std::abs(mother_pdg) <= 5499)); int bHadronId = IsFromBeauty(p, mcParticles); int bQuarkId = -1; @@ -146,6 +230,9 @@ struct lmeehfcocktailprefilter { int cQuarkOriginId = -1; int bQuarkOriginId = -1; + float bQuarkRap = -999.; + float cQuarkRap = -999.; + int isHF = EFromHFType::kNoHFE; if (direct_beauty_mother) { // b->e @@ -155,6 +242,7 @@ struct lmeehfcocktailprefilter { 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; @@ -163,12 +251,14 @@ struct lmeehfcocktailprefilter { 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; @@ -177,10 +267,11 @@ struct lmeehfcocktailprefilter { 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); + hfTable(isHF, bHadronId, cHadronId, bQuarkId, cQuarkId, bQuarkOriginId, cQuarkOriginId, bQuarkRap, cQuarkRap); } } }; @@ -189,6 +280,7 @@ struct lmeehfcocktailbeauty { HistogramRegistry registry{"registry", {}}; + std::vector>> hRapQuark; std::vector>> hEta, hPt; std::vector>> hPtEta; std::vector> hLS_Mee, hULS_Mee; @@ -211,22 +303,33 @@ struct lmeehfcocktailbeauty { { registry.add("NEvents", "NEvents", HistType::kTH1F, {{1, 0, 1}}, false); - const char* typeNamesSingle[2] = {"be", "bce"}; - const char* typeTitlesSingle[2] = {"b->e", "b->c->e"}; + const int Nchannels = 2; + const char* typeNamesSingle[Nchannels] = {"be", "bce"}; + const char* typeTitlesSingle[Nchannels] = {"b->e", "b->c->e"}; - AxisSpec eta_axis = {myConfigs.fConfigEtaBins, "#eta"}; - AxisSpec pt_axis = {myConfigs.fConfigPtBins, "#it{p}_{T} (GeV/c)"}; + 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 < 2; i++) { + for (int i = 0; i < Nchannels; i++) { std::vector> hEta_temp, hPt_temp; std::vector> hPtEta_temp; - for (int j = 0; j < 3; j++) { - hEta_temp.push_back(registry.add(Form("Eta_%s_%s", typeNamesSingle[i], stageNames[j]), Form("Eta %s %s", typeTitlesSingle[i], stageNames[j]), HistType::kTH1F, {eta_axis}, true)); - hPt_temp.push_back(registry.add(Form("Pt_%s_%s", typeNamesSingle[i], stageNames[j]), Form("Pt %s %s", typeTitlesSingle[i], stageNames[j]), HistType::kTH1F, {pt_axis}, true)); - hPtEta_temp.push_back(registry.add(Form("PtEta_%s_%s", typeNamesSingle[i], stageNames[j]), Form("Pt vs. Eta %s %s", typeTitlesSingle[i], stageNames[j]), HistType::kTH2F, {pt_axis, eta_axis}, true)); + 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); @@ -235,7 +338,7 @@ struct lmeehfcocktailbeauty { // pair histograms // ULS - for (int j = 0; j < 3; j++) { + 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)); @@ -243,7 +346,7 @@ struct lmeehfcocktailbeauty { 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 < 3; j++) { + 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)); @@ -256,7 +359,8 @@ struct lmeehfcocktailbeauty { { 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); + doSingle(p, hEta[from_quark], hPt[from_quark], hPtEta[from_quark], myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax); + doQuark(p, hRapQuark[from_quark], myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax, 5); } for (auto const& collision : collisions) { @@ -272,11 +376,11 @@ struct lmeehfcocktailbeauty { 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); + doPair(particle1, particle2, hULS_Mee, hULS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, 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); + doPair(particle1, particle2, hULS_Mee_wPartonicCheck, hULS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); } // LS spectrum for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(electronsGrouped, electronsGrouped))) { @@ -285,11 +389,11 @@ struct lmeehfcocktailbeauty { 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); + doPair(particle1, particle2, hLS_Mee, hLS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, 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); + doPair(particle1, particle2, hLS_Mee_wPartonicCheck, hLS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); } for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(positronsGrouped, positronsGrouped))) { @@ -297,11 +401,11 @@ struct lmeehfcocktailbeauty { 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); + doPair(particle1, particle2, hLS_Mee, hLS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, 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); + doPair(particle1, particle2, hLS_Mee_wPartonicCheck, hLS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); } } } @@ -319,6 +423,7 @@ 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; @@ -341,21 +446,27 @@ struct lmeehfcocktailcharm { const char* typeNamesSingle = "ce"; const char* typeTitlesSingle = "c->e"; - AxisSpec eta_axis = {myConfigs.fConfigEtaBins, "#eta"}; - AxisSpec pt_axis = {myConfigs.fConfigPtBins, "#it{p}_{T} (GeV/c)"}; + 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 < 3; j++) { - hEta.push_back(registry.add(Form("Eta_%s_%s", typeNamesSingle, stageNames[j]), Form("Eta %s %s", typeTitlesSingle, stageNames[j]), HistType::kTH1F, {eta_axis}, true)); - hPt.push_back(registry.add(Form("Pt_%s_%s", typeNamesSingle, stageNames[j]), Form("Pt %s %s", typeTitlesSingle, stageNames[j]), HistType::kTH1F, {pt_axis}, true)); - hPtEta.push_back(registry.add(Form("PtEta_%s_%s", typeNamesSingle, stageNames[j]), Form("Pt vs. Eta %s %s", typeTitlesSingle, stageNames[j]), HistType::kTH2F, {pt_axis, eta_axis}, true)); + 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 < 3; j++) { + 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)); @@ -363,7 +474,7 @@ struct lmeehfcocktailcharm { 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 < 3; j++) { + 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)); @@ -375,7 +486,8 @@ struct lmeehfcocktailcharm { void processCharm(aod::McCollisions const& collisions, MyFilteredMcParticlesSmeared const& mcParticles) { for (auto const& p : mcParticles) { - doSingle(p, hEta, hPt, hPtEta, myConfigs.fConfigPtMin, myConfigs.fConfigEtaMax); + doSingle(p, hEta, hPt, hPtEta, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax); + doQuark(p, hRapQuark, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax, 4); } for (auto const& collision : collisions) { @@ -391,11 +503,11 @@ struct lmeehfcocktailcharm { 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); + doPair(particle1, particle2, hULS_Mee, hULS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, 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); + doPair(particle1, particle2, hULS_Mee_wPartonicCheck, hULS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); } // LS for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(electronsGrouped, electronsGrouped))) { @@ -404,11 +516,11 @@ struct lmeehfcocktailcharm { 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); + doPair(particle1, particle2, hLS_Mee, hLS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, 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); + doPair(particle1, particle2, hLS_Mee_wPartonicCheck, hLS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); } for (auto const& [particle1, particle2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(positronsGrouped, positronsGrouped))) { @@ -416,11 +528,11 @@ struct lmeehfcocktailcharm { 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); + doPair(particle1, particle2, hLS_Mee, hLS_MeePtee, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, 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); + doPair(particle1, particle2, hLS_Mee_wPartonicCheck, hLS_MeePtee_wPartonicCheck, myConfigs.fConfigPtMin, myConfigs.fConfigPtMax, myConfigs.fConfigEtaMax, myConfigs.fConfigApplyDEtaDPhi, myConfigs.fConfigMinDEta, myConfigs.fConfigMinDPhi); } } } 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..9b0d1d6d2d2 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/matchingMFT.cxx @@ -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. + +/// \file matchingMFT.cxx +/// \brief a task to study matching MFT-[MCH-MID] in MC +/// \author daiki.sekihata@cern.ch + +#include "TableHelper.h" + +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/fwdtrackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackParam.h" +#include "ReconstructionDataFormats/TrackFwd.h" + +#include "TGeoGlobalMagField.h" + +#include +#include +#include +#include +#include +#include + +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+6f, "max. chi2 for standalone muon"}; + Configurable maxChi2GL{"maxChi2GL", 1e+6f, "max. chi2 for global muon"}; + Configurable maxChi2MFT{"maxChi2MFT", 1e+6f, "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 maxRelDPt{"maxRelDPt", 1e+10f, "max. relative dpt between MFT-MCH-MID and MCH-MID"}; + Configurable maxDEta{"maxDEta", 1e+10f, "max. deta between MFT-MCH-MID and MCH-MID"}; + Configurable maxDPhi{"maxDPhi", 1e+10f, "max. dphi between MFT-MCH-MID and MCH-MID"}; + Configurable maxDEtaMP{"maxDEtaMP", 1e+10f, "max. deta between MFT and MCH-MID at matching plane Z"}; + Configurable maxDPhiMP{"maxDPhiMP", 1e+10f, "max. dphi between MFT and MCH-MID at matching plane Z"}; + Configurable requireMFTHitMap{"requireMFTHitMap", false, "flag to require MFT hit map"}; + Configurable> requiredMFTDisks{"requiredMFTDisks", std::vector{0}, "hit map on MFT disks [0,1,2,3,4]. logical-OR of each double-sided disk"}; + Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; + Configurable cfgBestMatchFinder{"cfgBestMatchFinder", 0, "matching chi2:0, dr:1"}; + + 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"}; + + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_muon_glo", "select 1 [CBT_muon, 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"}; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + + 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); + rctChecker.init(cfgRCTLabel.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + + addHistograms(); + } + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + int mRunNumber = -1; + float mBz = 0; + + 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(); + const double centerMFT[3] = {0, 0, -61.4}; + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + mBz = field->getBz(centerMFT); // Get field at centre of MFT + LOGF(info, "Bz at center of MFT = %f kZG", mBz); + } + + 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"); + + const AxisSpec axis_pt{{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.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10}, "p_{T}^{gl} (GeV/c)"}; + + 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}, {80, -5.f, -1.f}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -5.f, -1.f}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hsDelta", "diff. between GL and associated SA;p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl};#eta^{sa} - #eta^{gl};#varphi^{sa} - #varphi^{gl} (rad.);", kTHnSparseF, {axis_pt, {200, -0.5, +0.5}, {200, -1, +1}, {90, -M_PI / 4, M_PI / 4}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hsDeltaAtMP", "diff. between MFT and MCH-MID;p_{T}^{gl} (GeV/c);#varphi^{MCH-MID} - #varphi^{MFT} (rad.);#eta^{MCH-MID} - #eta^{MFT};", kTHnSparseF, {axis_pt, {90, -M_PI / 4, M_PI / 4}, {200, -1, +1}}, 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/hMFTClusterMap", "MFT cluster map", kTH1F, {{1024, -0.5, 1023.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, 10}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2", "chi2;chi2/ndf", kTH1F, {{100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hChi2MFT", "chi2 MFT/ndf;chi2 MFT/ndf", kTH1F, {{100, 0.0f, 10}}, 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/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/hDCAz", "DCAz;DCA_{z} (cm);", kTH1F, {{200, -0.1, 0.1}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm);", kTH2F, {{100, 0, 1}, {200, -0.1, 0.1}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hMCHBitMap", "MCH bit map;MCH bit map", kTH1F, {{1024, -0.5, 1023.5}}, false); + fRegistry.add("MFTMCHMID/primary/correct/hMIDBitMap", "MID bit map;MID bit map", kTH1F, {{256, -0.5, 255.5}}, false); + + fRegistry.add("MFTMCHMID/primary/correct/hProdVtxZ", "prod. vtx Z of muon;V_{z} (cm)", kTH1F, {{200, -100, 100}}, 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}, {200, -1, +1}}, false); + 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}}, false); + 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}}, false); + 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}}, false); + 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}}, false); + fRegistry.addClone("MFTMCHMID/primary/correct/", "MFTMCHMID/primary/wrong/"); + fRegistry.addClone("MFTMCHMID/primary/", "MFTMCHMID/secondary/"); + } + + bool isSelected(const float pt, const float eta, const float rAtAbsorberEnd, const float pDCA, const float chi2_per_ndf, 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_per_ndf < 0.f || maxChi2GL < chi2_per_ndf) { + return false; + } + } else if (trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { + if (eta < minEtaSA || maxEtaSA < eta) { + return false; + } + if (chi2_per_ndf < 0.f || maxChi2SA < chi2_per_ndf) { + return false; + } + } else { + return false; + } + + return true; + } + + template + uint16_t mftClusterMap(T const& track) + { + uint64_t mftClusterSizesAndTrackFlags = track.mftClusterSizesAndTrackFlags(); + uint16_t clmap = 0; + for (unsigned int layer = 0; layer < 10; layer++) { + if ((mftClusterSizesAndTrackFlags >> (layer * 6)) & 0x3f) { + clmap |= (1 << layer); + } + } + return clmap; + } + + template + bool hasMFT(T const& track) + { + // logical-OR + uint64_t mftClusterSizesAndTrackFlags = track.mftClusterSizesAndTrackFlags(); + uint16_t clmap = 0; + for (unsigned int layer = begin; layer <= end; layer++) { + if ((mftClusterSizesAndTrackFlags >> (layer * 6)) & 0x3f) { + clmap |= (1 << layer); + } + } + return (clmap > 0); + } + + // template + // float meanClusterSizeMFT(T const& track) + // { + // uint64_t mftClusterSizesAndTrackFlags = track.mftClusterSizesAndTrackFlags(); + // uint16_t clsSize = 0; + // uint16_t n = 0; + // for (unsigned int layer = 0; layer < 10; layer++) { + // uint16_t size_per_layer = (mftClusterSizesAndTrackFlags >> (layer * 6)) & 0x3f; + // clsSize += size_per_layer; + // if (size_per_layer > 0) { + // n++; + // } + // // LOGF(info, "track.globalIndex() = %d, layer = %d, size_per_layer = %d", track.globalIndex(), layer, size_per_layer); + // } + + // if (n > 0) { + // return static_cast(clsSize) / static_cast(n) * std::fabs(std::sin(std::atan(track.tgl()))); + // } else { + // return 0.f; + // } + // } + + template + void getDeltaEtaDeltaPhiAtMatchingPlane(TCollision const& collision, TFwdTrack const& fwdtrack, TMFTrackCov const& mftCovs, float& deta, float& dphi) + { + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + deta = 999.f; + dphi = 999.f; + return; // do nothing + } + + auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID + auto mfttrack = fwdtrack.template matchMFTTrack_as(); + + if (mchtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + deta = 999.f; + dphi = 999.f; + return; // do nothing + } + + o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, matchingZ, mBz); + auto mfttrackcov = mftCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + + auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, matchingZ, mBz); // propagated to matching plane + o2::track::TrackParCovFwd mftsaAtMP = getTrackParCovFwd(mfttrack, mfttrackcov); // values at innermost update + mftsaAtMP.propagateToZhelix(matchingZ, mBz); // propagated to matching plane + deta = muonAtMP.getEta() - mftsaAtMP.getEta(); + dphi = muonAtMP.getPhi() - mftsaAtMP.getPhi(); + o2::math_utils::bringToPMPi(dphi); + } + + template + void fillHistograms(TCollision const& collision, TFwdTrack fwdtrack, TFwdTracks const&, TMFTTracks const&, TMFTTracksCov const& mftCovs) + { + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { // only for protection + return; + } + + auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID + auto mfttrack = fwdtrack.template matchMFTTrack_as(); + + if (!fwdtrack.has_mcParticle() || !mchtrack.has_mcParticle() || !mfttrack.has_mcParticle()) { + return; + } + + auto mcParticle_MFTMCHMID = fwdtrack.template mcParticle_as(); // this is identical to mcParticle_MCHMID + auto mcParticle_MCHMID = mchtrack.template mcParticle_as(); // this is identical to mcParticle_MFTMCHMID + 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()); + + int nClustersMFT = mfttrack.nClusters(); + float chi2mft = mfttrack.chi2() / (2.f * nClustersMFT - 5.f); + if (chi2mft < 0.f || maxChi2MFT < chi2mft) { + return; + } + + if (fwdtrack.chi2MatchMCHMFT() > maxMatchingChi2MCHMFT) { + return; + } + + if (fwdtrack.chi2() < 0.f || maxChi2GL < fwdtrack.chi2() / (2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f)) { + return; + } + + if (fwdtrack.rAtAbsorberEnd() < minRabs || maxRabs < fwdtrack.rAtAbsorberEnd()) { + return; + } + + if (nClustersMFT < 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, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz); + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz); + + float pt = propmuonAtPV.getPt(); + float eta = propmuonAtPV.getEta(); + float phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + float cXX = propmuonAtPV.getSigma2X(); + float cYY = propmuonAtPV.getSigma2Y(); + float cXY = propmuonAtPV.getSigmaXY(); + + float dcaX = propmuonAtPV.getX() - collision.posX(); + float dcaY = propmuonAtPV.getY() - collision.posY(); + float dcaZ = propmuonAtPV.getZ() - collision.posZ(); // 0 at this point. + float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + float det = cXX * cYY - cXY * cXY; // determinanat + + float dcaXYinSigma = 999.f; + if (det < 0) { + dcaXYinSigma = 999.f; + } else { + dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2. * dcaX * dcaY * cXY) / det / 2.)); // dca xy in sigma + } + float sigma_dcaXY = dcaXY / dcaXYinSigma; + + 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; + // float pDCA = propmuonAtPV.getP() * dcaXY; + float dphiMP = 999.f, detaMP = 999.f; + + pt = propmuonAtPV.getPt(); + eta = propmuonAtPV.getEta(); + phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + if constexpr (withMFTCov) { + auto mfttrackcov = mftCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + o2::track::TrackParCovFwd mftsa = getTrackParCovFwd(mfttrack, mfttrackcov); // values at innermost update + o2::dataformats::GlobalFwdTrack globalMuonRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuonAtPV_Matched, mftsa); // this is track at IU. + auto globalMuonAtPV = o2::aod::fwdtrackutils::propagateTrackParCovFwd(globalMuonRefit, fwdtrack.trackType(), collision, propagationPoint::kToVertex, matchingZ, mBz); + + pt = globalMuonAtPV.getPt(); + eta = globalMuonAtPV.getEta(); + phi = globalMuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + cXX = globalMuonAtPV.getSigma2X(); + cYY = globalMuonAtPV.getSigma2Y(); + cXY = globalMuonAtPV.getSigmaXY(); + dcaX = globalMuonAtPV.getX() - collision.posX(); + dcaY = globalMuonAtPV.getY() - collision.posY(); + dcaZ = globalMuonAtPV.getZ() - collision.posZ(); + dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + det = cXX * cYY - cXY * cXY; // determinanat + if (det < 0) { + dcaXYinSigma = 999.f; + } else { + dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2. * dcaX * dcaY * cXY) / det / 2.)); // dca xy in sigma + } + sigma_dcaXY = dcaXY / dcaXYinSigma; + + getDeltaEtaDeltaPhiAtMatchingPlane(collision, fwdtrack, mftCovs, detaMP, dphiMP); + o2::math_utils::bringToPMPi(dphiMP); + } + + if (refitGlobalMuon) { + pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); + } + + float ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); + float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); + float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); + o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + float dpt = (ptMatchedMCHMID - pt) / pt; + float deta = etaMatchedMCHMID - eta; + float dphi = phiMatchedMCHMID - phi; + o2::math_utils::bringToPMPi(dphi); + if (std::sqrt(std::pow(deta / maxDEta, 2) + std::pow(dphi / maxDPhi, 2)) > 1.f) { + return; + } + if (std::sqrt(std::pow(detaMP / maxDEtaMP, 2) + std::pow(dphiMP / maxDPhiMP, 2)) > 1.f) { + return; + } + if (std::fabs(dpt) > maxRelDPt) { + return; + } + + if (!isSelected(pt, eta, rAtAbsorberEnd, pDCA, fwdtrack.chi2() / (2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f), fwdtrack.trackType(), dcaXY)) { + return; + } + + if (requireMFTHitMap) { + std::vector hasMFTs{hasMFT<0, 1>(mfttrack), hasMFT<2, 3>(mfttrack), hasMFT<4, 5>(mfttrack), hasMFT<6, 7>(mfttrack), hasMFT<8, 9>(mfttrack)}; + for (int i = 0; i < static_cast(requiredMFTDisks->size()); i++) { + if (!hasMFTs[requiredMFTDisks->at(i)]) { + 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/hsDelta"), pt, dpt, deta, dphi); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hsDeltaAtMP"), pt, dphiMP, detaMP); + 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/hMFTClusterMap"), mftClusterMap(mfttrack)); + 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() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); + 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/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAz"), dcaZ); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxyinSigma"), dcaXYinSigma); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hMCHBitMap"), fwdtrack.mchBitMap()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hMIDBitMap"), fwdtrack.midBitMap()); + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/primary/correct/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 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/hProdVtxZ"), mcParticle_MFTMCHMID.vz()); + + 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/hsDelta"), pt, dpt, deta, dphi); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hsDeltaAtMP"), pt, dphiMP, detaMP); + 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/hMFTClusterMap"), mftClusterMap(mfttrack)); + 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() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); + 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/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAz"), dcaZ); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxyinSigma"), dcaXYinSigma); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hMCHBitMap"), fwdtrack.mchBitMap()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hMIDBitMap"), fwdtrack.midBitMap()); + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/primary/wrong/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 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/hProdVtxZ"), mcParticle_MFTMCHMID.vz()); + + 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/hsDelta"), pt, dpt, deta, dphi); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hsDeltaAtMP"), pt, dphiMP, detaMP); + 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/hMFTClusterMap"), mftClusterMap(mfttrack)); + 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() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); + 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/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAz"), dcaZ); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxyinSigma"), dcaXYinSigma); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hMCHBitMap"), fwdtrack.mchBitMap()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hMIDBitMap"), fwdtrack.midBitMap()); + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/secondary/correct/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 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/hProdVtxZ"), mcParticle_MFTMCHMID.vz()); + + 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/hsDelta"), pt, dpt, deta, dphi); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hsDeltaAtMP"), pt, dphiMP, detaMP); + 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/hMFTClusterMap"), mftClusterMap(mfttrack)); + 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() / (2.f * (fwdtrack.nClusters() + nClustersMFT) - 5.f)); + 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/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAz"), dcaZ); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxyz"), dcaXY, dcaZ); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxyinSigma"), dcaXYinSigma); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hMCHBitMap"), fwdtrack.mchBitMap()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hMIDBitMap"), fwdtrack.midBitMap()); + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/secondary/wrong/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 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/hProdVtxZ"), mcParticle_MFTMCHMID.vz()); + + 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()); + } + + std::vector> vec_min_chi2MatchMCHMFT; // std::pair -> chi2MatchMCHMFT; + std::vector> vec_min_dr; // std::pair -> deta + dphi; + std::map, bool> mapCorrectMatch; + + template + void findBestMatchPerMCHMID(TCollision const& collision, TFwdTrack const& fwdtrack, TFwdTracks const& fwdtracks, TMFTTracks const&, TMFTTracksCov const& mftCovs) + { + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { + return; + } + if (!fwdtrack.has_mcParticle()) { + return; + } + + std::tuple tupleIds_at_min_chi2mftmch; + std::tuple tupleIds_at_min_dr; + float min_chi2MatchMCHMFT = 1e+10; + float min_dr = 1e+10; + auto muons_per_MCHMID = fwdtracks.sliceBy(fwdtracksPerMCHTrack, fwdtrack.globalIndex()); + // LOGF(info, "muons_per_MCHMID.size() = %d", muons_per_MCHMID.size()); + + for (const auto& muon_tmp : muons_per_MCHMID) { + if (muon_tmp.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + + auto tupleId = std::make_tuple(muon_tmp.globalIndex(), muon_tmp.matchMCHTrackId(), muon_tmp.matchMFTTrackId()); + auto mchtrack = muon_tmp.template matchMCHTrack_as(); // MCH-MID + auto mfttrack = muon_tmp.template matchMFTTrack_as(); + + if (!muon_tmp.has_mcParticle() || !mchtrack.has_mcParticle() || !mfttrack.has_mcParticle()) { + continue; + } + + float deta = 999.f, dphi = 999.f; + getDeltaEtaDeltaPhiAtMatchingPlane(collision, muon_tmp, mftCovs, deta, dphi); + float dr = std::sqrt(deta * deta + dphi * dphi); + + // auto mcParticle_MFTMCHMID = muon_tmp.template mcParticle_as(); // this is identical to mcParticle_MCHMID + auto mcParticle_MCHMID = mchtrack.template mcParticle_as(); // this is identical to mcParticle_MFTMCHMID + auto mcParticle_MFT = mfttrack.template mcParticle_as(); + // float chi2ndf = muon_tmp.chi2() / (2.f * (mchtrack.nClusters() + mfttrack.nClusters()) - 5.f); + + if (mcParticle_MFT.globalIndex() == mcParticle_MCHMID.globalIndex()) { + mapCorrectMatch[tupleId] = true; + } else { + mapCorrectMatch[tupleId] = false; + } + + // if (std::abs(mcParticle_MCHMID.pdgCode()) == 13 && mcParticle_MCHMID.isPhysicalPrimary()) { + // if (mcParticle_MFT.globalIndex() == mcParticle_MCHMID.globalIndex()) { + // LOGF(info, "This is correct match between MFT and MCH-MID: muon_tmp.globalIndex() = %d, chi2/ndf = %f, matching chi2/ndf = %f, mcParticle.pt() = %f, mcParticle.eta() = %f, mcParticle.phi() = %f, reldpt = %f, deta = %f, dphi = %f, dr = %f", muon_tmp.globalIndex(), chi2ndf, muon_tmp.chi2MatchMCHMFT(), mcParticle_MCHMID.pt(), mcParticle_MCHMID.eta(), mcParticle_MCHMID.phi(), reldpt, deta, dphi, dr); + // } else { + // LOGF(info, "This is wrong match between MFT and MCH-MID: muon_tmp.globalIndex() = %d, chi2/ndf = %f, matching chi2/ndf = %f , mcParticle.pt() = %f, mcParticle.eta() = %f, mcParticle.phi() = %f, reldpt = %f, deta = %f, dphi = %f, dr = %f" , muon_tmp.globalIndex(), chi2ndf, muon_tmp.chi2MatchMCHMFT(), mcParticle_MCHMID.pt(), mcParticle_MCHMID.eta(), mcParticle_MCHMID.phi(), reldpt, deta, dphi, dr); + // } + // } + + if (0.f < muon_tmp.chi2MatchMCHMFT() && muon_tmp.chi2MatchMCHMFT() < min_chi2MatchMCHMFT) { + min_chi2MatchMCHMFT = muon_tmp.chi2MatchMCHMFT(); + tupleIds_at_min_chi2mftmch = tupleId; + } + + if (dr < min_dr) { + min_dr = dr; + tupleIds_at_min_dr = tupleId; + } + + } // end of if global muon + } // end of candidates loop + + vec_min_chi2MatchMCHMFT.emplace_back(tupleIds_at_min_chi2mftmch); + vec_min_dr.emplace_back(tupleIds_at_min_dr); + + // auto mcParticleTMP = fwdtrack.template mcParticle_as(); // this is identical to mcParticle_MFTMCHMID + // if (std::abs(mcParticleTMP.pdgCode()) == 13 && mcParticleTMP.isPhysicalPrimary()) { + // LOGF(info, "min chi2: muon_tmp.globalIndex() = %d, muon_tmp.matchMCHTrackId() = %d, muon_tmp.matchMFTTrackId() = %d, muon_tmp.chi2MatchMCHMFT() = %f, correct match = %d", std::get<0>(tupleIds_at_min_chi2mftmch), std::get<1>(tupleIds_at_min_chi2mftmch), std::get<2>(tupleIds_at_min_chi2mftmch), min_chi2MatchMCHMFT, mapCorrectMatch[tupleIds_at_min_chi2mftmch]); + // LOGF(info, "min dr: muon_tmp.globalIndex() = %d, muon_tmp.matchMCHTrackId() = %d, muon_tmp.matchMFTTrackId() = %d, dr = %f, correct match = %d", std::get<0>(tupleIds_at_min_dr), std::get<1>(tupleIds_at_min_dr), std::get<2>(tupleIds_at_min_dr), min_dr, mapCorrectMatch[tupleIds_at_min_dr]); + // } + } + + SliceCache cache; + PresliceUnsorted fwdtracksPerMCHTrack = aod::fwdtrack::matchMCHTrackId; + 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&) + { + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + fRegistry.fill(HIST("Event/hCollisionCounter"), 0); + if (!collision.has_mcCollision()) { + continue; + } + if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + 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); + + 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, nullptr); + } // end of fwdtrack loop + } // end of collision loop + + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + vec_min_dr.clear(); + vec_min_dr.shrink_to_fit(); + } + 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&) + { + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + fRegistry.fill(HIST("Event/hCollisionCounter"), 0); + if (!collision.has_mcCollision()) { + continue; + } + if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + 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); + + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto fwdtrack = fwdtrackId.template fwdtrack_as(); + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + continue; + } + fillHistograms(collision, fwdtrack, fwdtracks, mfttracks, nullptr); + } // end of fwdtrack loop + } // end of collision loop + + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + vec_min_dr.clear(); + vec_min_dr.shrink_to_fit(); + } + PROCESS_SWITCH(matchingMFT, processWithFTTCA, "process with FTTCA", true); + + std::unordered_map map_mfttrackcovs; + + void processWithFTTCA_withMFTCov(FilteredMyCollisions const& collisions, MyFwdTracks const& fwdtracks, MyMFTTracks const& mfttracks, aod::MFTTracksCov const& mftCovs, aod::BCsWithTimestamps const&, aod::FwdTrackAssoc const& fwdtrackIndices, aod::McParticles const&) + { + for (const auto& mfttrackConv : mftCovs) { + map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + } + + vec_min_chi2MatchMCHMFT.reserve(fwdtracks.size()); + vec_min_dr.reserve(fwdtracks.size()); + + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto fwdtrack = fwdtrackId.template fwdtrack_as(); + findBestMatchPerMCHMID(collision, fwdtrack, fwdtracks, mfttracks, mftCovs); + } // end of fwdtrack loop + } // end of collision loop + + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + fRegistry.fill(HIST("Event/hCollisionCounter"), 0); + if (!collision.has_mcCollision()) { + continue; + } + if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + 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); + + auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); + for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { + auto fwdtrack = fwdtrackId.template fwdtrack_as(); + + if (cfgBestMatchFinder == 0) { // chi2 + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { + continue; + } + } else if (cfgBestMatchFinder == 1) { // dr + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && std::find(vec_min_dr.begin(), vec_min_dr.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_dr.end()) { + continue; + } + } else { // best match is not selected. Histograms are filled with all global muons. + if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { + continue; + } + } + fillHistograms(collision, fwdtrack, fwdtracks, mfttracks, mftCovs); + } // end of fwdtrack loop + } // end of collision loop + + map_mfttrackcovs.clear(); + vec_min_chi2MatchMCHMFT.clear(); + vec_min_chi2MatchMCHMFT.shrink_to_fit(); + vec_min_dr.clear(); + vec_min_dr.shrink_to_fit(); + } + PROCESS_SWITCH(matchingMFT, processWithFTTCA_withMFTCov, "process with FTTCA with MFTCov", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"matching-mft"})}; +} diff --git a/PWGEM/Dilepton/Tasks/mcParticlePredictionsOTF.cxx b/PWGEM/Dilepton/Tasks/mcParticlePredictionsOTF.cxx new file mode 100644 index 00000000000..9ec7f079712 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/mcParticlePredictionsOTF.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 mcParticlePrediction.cxx +/// \author Sebastian Scheid, s.scheid@cern.ch +/// \brief Task to build the predictions from the models based on the generated particles +/// + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; + +struct otfParticlePrediction { + // histogram registry + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // define configurables + ConfigurableAxis binsEta{"binsEta", {100, -5, 5}, "Binning of the Eta axis"}; + ConfigurableAxis binsPt{"binsPt", {100, 0, 10}, "Binning of the Pt axis"}; + + Configurable maxYParticle{"maxYParticle", 5.f, "Max rapidity of particles considered"}; + + // init function + void init(InitContext&) + { + + const AxisSpec axisEta{binsEta, "#eta"}; + const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + + histos.add("collisions/generated", "collisions", kTH1D, {{2, -0.5, 1.5}}); + histos.add("particles/generated/pi0", "pi0", kTH2D, {axisPt, axisEta}); + histos.add("particles/generated/eta", "eta", kTH2D, {axisPt, axisEta}); + histos.add("particles/generated/etaP", "etaP", kTH2D, {axisPt, axisEta}); + histos.add("particles/generated/rho", "rho", kTH2D, {axisPt, axisEta}); + histos.add("particles/generated/omega", "omega", kTH2D, {axisPt, axisEta}); + histos.add("particles/generated/phi", "phi", kTH2D, {axisPt, axisEta}); + } + + void process(aod::McCollisions const& mcCollisions, + aod::McParticles const& mcParticles) + { + + histos.fill(HIST("collisions/generated"), 0, mcCollisions.size()); + + for (const auto& particle : mcParticles) { + auto pdg = std::abs(particle.pdgCode()); + if (std::abs(particle.y()) > maxYParticle) { + continue; + } + // if (!(particle.isPhysicalPrimary())) { + // continue; + // } + if (pdg < 100) { + continue; + } + if (pdg > 1000) { + continue; + } + switch (pdg) { + case 111: + histos.fill(HIST("particles/generated/pi0"), particle.pt(), particle.y()); + break; + case 221: + histos.fill(HIST("particles/generated/eta"), particle.pt(), particle.y()); + break; + case 331: + histos.fill(HIST("particles/generated/etaP"), particle.pt(), particle.y()); + break; + case 223: + histos.fill(HIST("particles/generated/omega"), particle.pt(), particle.y()); + break; + case 113: + histos.fill(HIST("particles/generated/rho"), particle.pt(), particle.y()); + break; + case 333: + histos.fill(HIST("particles/generated/phi"), particle.pt(), particle.y()); + break; + default: + break; + } + } + } +}; + +WorkflowSpec + defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx b/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx new file mode 100644 index 00000000000..28051e2df08 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/prefilterDielectron.cxx @@ -0,0 +1,569 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include +#include +#include + +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.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_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", 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_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_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 cfgRefR{"cfgRefR", 1.2, "reference R (in m) for extrapolation"}; // https://cds.cern.ch/record/1419204 + + 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"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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}, {400, -2, +2}}, 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, 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); + 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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); + + // 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 + std::vector binsML{}; + binsML.reserve(dielectroncuts.binsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.binsMl.value.size(); i++) { + binsML.emplace_back(dielectroncuts.binsMl.value[i]); + } + std::vector thresholdsML{}; + thresholdsML.reserve(dielectroncuts.cutsMl.value.size()); + for (size_t i = 0; i < dielectroncuts.cutsMl.value.size(); i++) { + thresholdsML.emplace_back(dielectroncuts.cutsMl.value[i]); + } + fDielectronCut.SetMLThresholds(binsML, thresholdsML); + + // 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); + } + } // end of ULS pairing + + 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); + } + } // end of LS++ pairing + + 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 LS-- pairing + + } // 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/qVectorDummyOTF.cxx b/PWGEM/Dilepton/Tasks/qVectorDummyOTF.cxx new file mode 100644 index 00000000000..31dc12982d5 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/qVectorDummyOTF.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 on-the-fly dummy qvector table. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct qVectorDummyOTF { + Produces event_qvec; + + void init(InitContext&) {} + ~qVectorDummyOTF() {} + + void process(aod::EMEvents const& collisions) + { + for (int i = 0; i < collisions.size(); i++) { + 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, 999.f, 999.f, 999.f, 999.f); + } // end of collision loop + } // end of process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"qvector-dummy-otf"})}; +} diff --git a/PWGEM/Dilepton/Tasks/smearing.cxx b/PWGEM/Dilepton/Tasks/smearing.cxx index 97ac1390c84..03d0b272f46 100644 --- a/PWGEM/Dilepton/Tasks/smearing.cxx +++ b/PWGEM/Dilepton/Tasks/smearing.cxx @@ -13,35 +13,57 @@ // Analysis task to produce smeared pt, eta, phi for electrons/muons in dilepton analysis // Please write to: daiki.sekihata@cern.ch -#include -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/MomentumSmearer.h" + +#include "CCDB/BasicCCDBManager.h" #include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/DataTypes.h" #include "Framework/HistogramRegistry.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" +#include "Framework/runDataProcessing.h" + +#include +#include +#include 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 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"}; @@ -53,11 +75,14 @@ struct ApplySmearing { 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"}; @@ -69,11 +94,14 @@ struct ApplySmearing { 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"}; @@ -85,6 +113,7 @@ struct ApplySmearing { 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_Electron; @@ -94,7 +123,9 @@ struct ApplySmearing { void init(InitContext&) { + 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)); @@ -103,8 +134,11 @@ struct ApplySmearing { 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)); @@ -113,8 +147,11 @@ struct ApplySmearing { 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)); @@ -123,6 +160,7 @@ struct ApplySmearing { 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); @@ -153,8 +191,8 @@ struct ApplySmearing { 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(); @@ -163,15 +201,30 @@ struct ApplySmearing { 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) == 11) { + if (std::abs(pdgCode) == 11) { int ch = -1; if (pdgCode < 0) { ch = 1; } // apply smearing for electrons or muons. - float ptsmeared, etasmeared, phismeared; - smearer_Electron.applySmearing(ch, ptgen, etagen, phigen, 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 @@ -179,63 +232,76 @@ struct ApplySmearing { // 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 (abs(pdgCode) == 13) { + } 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(ch, ptgen, etagen, phigen, ptsmeared_sa, etasmeared_sa, phismeared_sa); + 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(ch, ptgen, etagen, phigen, ptsmeared_gl, etasmeared_gl, phismeared_gl); + 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 smearedelectron(ptgen, etagen, phigen, efficiency, dca); smearedmuon(ptgen, etagen, phigen, efficiency, dca, ptgen, etagen, phigen, efficiency, dca); } - } + } // end of mc track loop } - void processMCanalysisEM(aod::EMMCParticles 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 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&) {} - PROCESS_SWITCH(ApplySmearing, processMCanalysisEM, "Run for MC analysis", false); - PROCESS_SWITCH(ApplySmearing, processMCanalysisDQ, "Run for MC analysis", false); + PROCESS_SWITCH(ApplySmearing, processMCanalysisEM, "Run for MC analysis which uses skimmed EM 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, processDummyCocktail, "Dummy process function", true); }; struct CheckSmearing { - 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 + using EMMCParticlesWithSmearing = soa::Join; + using MyCocktailTracks = soa::Join; // Run for electrons or muons Configurable fPdgCode{"cfgPdgCode", 11, "Set the type of particle to be checked"}; @@ -252,9 +318,9 @@ struct CheckSmearing { void init(o2::framework::InitContext&) { - 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()}}}); + registry.add("Electron/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("Electron/hCorrelation_Eta", "eta correlation;#eta_{l}^{gen};#eta_{l}^{smeared}", {HistType::kTH2F, {{200, -1.0f, +1.0f}, {200, -1.0f, +1.0f}}}); + registry.add("Electron/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,l} (GeV/#it{c})"}; @@ -263,66 +329,108 @@ struct CheckSmearing { 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_Neg", "", HistType::kTH2D, {axisPtRes, axisDeltaphiRes}, true); - registry.add("PtGen_DeltaPhi_Pos", "", HistType::kTH2D, {axisPtRes, axisDeltaphiRes}, true); + registry.add("Electron/PtGen_DeltaPtOverPtGen", "", HistType::kTH2D, {axisPtRes, axisDeltaptRes}, true); + registry.add("Electron/PtGen_DeltaEta", "", HistType::kTH2D, {axisPtRes, axisDeltaetaRes}, true); + registry.add("Electron/PtGen_DeltaPhi_Neg", "", HistType::kTH2D, {axisPtRes, axisDeltaphiRes}, true); + registry.add("Electron/PtGen_DeltaPhi_Pos", "", HistType::kTH2D, {axisPtRes, axisDeltaphiRes}, true); } else { - 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); + registry.add("Electron/PtGen_DeltaPtOverPtGen", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}, axisDeltaptRes}, true); + registry.add("Electron/PtGen_DeltaEta", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}, axisDeltaetaRes}, true); + registry.add("Electron/PtGen_DeltaPhi_Neg", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}, axisDeltaphiRes}, true); + registry.add("Electron/PtGen_DeltaPhi_Pos", "", HistType::kTH2D, {{ptResBinsVec, "#it{p}^{gen}_{T,l} (GeV/#it{c})"}, axisDeltaphiRes}, true); } + + registry.addClone("Electron/", "GlobalMuon/"); + registry.addClone("Electron/", "StandaloneMuon/"); } - 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; } - float deltaptoverpt = -1000.; - if (mctrack.pt() > 0.) - deltaptoverpt = (mctrack.pt() - mctrack.ptSmeared()) / mctrack.pt(); - float deltaeta = mctrack.eta() - mctrack.etaSmeared(); - float deltaphi = mctrack.phi() - mctrack.phiSmeared(); - 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_Neg"), mctrack.pt(), deltaphi); - } else { - registry.fill(HIST("PtGen_DeltaPhi_Pos"), mctrack.pt(), deltaphi); + 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; + } } - registry.fill(HIST("hCorrelation_Pt"), mctrack.pt(), mctrack.ptSmeared()); - registry.fill(HIST("hCorrelation_Eta"), mctrack.eta(), mctrack.etaSmeared()); - registry.fill(HIST("hCorrelation_Phi"), mctrack.phi(), mctrack.phiSmeared()); - } // end of mctrack loop - } - void processCheckMCanalysisEM(EMMCParticlesWithSmearing const& tracksMC) - { - Check(tracksMC); + if (std::abs(mctrack.pdgCode()) == 11) { // for electrons + float deltaptoverpt = -1000.f; + if (mctrack.pt() > 0.f) { + deltaptoverpt = (mctrack.pt() - mctrack.ptSmeared()) / mctrack.pt(); + } + float deltaeta = mctrack.eta() - mctrack.etaSmeared(); + float deltaphi = mctrack.phi() - mctrack.phiSmeared(); + registry.fill(HIST("Electron/PtGen_DeltaPtOverPtGen"), mctrack.pt(), deltaptoverpt); + registry.fill(HIST("Electron/PtGen_DeltaEta"), mctrack.pt(), deltaeta); + if (mctrack.pdgCode() < 0) { // e+ + registry.fill(HIST("Electron/PtGen_DeltaPhi_Pos"), mctrack.pt(), deltaphi); + } else { // e- + registry.fill(HIST("Electron/PtGen_DeltaPhi_Neg"), mctrack.pt(), deltaphi); + } + registry.fill(HIST("Electron/hCorrelation_Pt"), mctrack.pt(), mctrack.ptSmeared()); + registry.fill(HIST("Electron/hCorrelation_Eta"), mctrack.eta(), mctrack.etaSmeared()); + registry.fill(HIST("Electron/hCorrelation_Phi"), mctrack.phi(), mctrack.phiSmeared()); + } else if (std::abs(mctrack.pdgCode()) == 13) { // for muons + float deltaptoverpt = -1000.f; + // for standalone muons + if (mctrack.pt() > 0.f) { + deltaptoverpt = (mctrack.pt() - mctrack.ptSmeared_sa_muon()) / mctrack.pt(); + } + float deltaeta = mctrack.eta() - mctrack.etaSmeared_sa_muon(); + float deltaphi = mctrack.phi() - mctrack.phiSmeared_sa_muon(); + registry.fill(HIST("StandaloneMuon/PtGen_DeltaPtOverPtGen"), mctrack.pt(), deltaptoverpt); + registry.fill(HIST("StandaloneMuon/PtGen_DeltaEta"), mctrack.pt(), deltaeta); + if (mctrack.pdgCode() < 0) { // mu+ + registry.fill(HIST("StandaloneMuon/PtGen_DeltaPhi_Pos"), mctrack.pt(), deltaphi); + } else { // mu- + registry.fill(HIST("StandaloneMuon/PtGen_DeltaPhi_Neg"), mctrack.pt(), deltaphi); + } + registry.fill(HIST("StandaloneMuon/hCorrelation_Pt"), mctrack.pt(), mctrack.ptSmeared_sa_muon()); + registry.fill(HIST("StandaloneMuon/hCorrelation_Eta"), mctrack.eta(), mctrack.etaSmeared_sa_muon()); + registry.fill(HIST("StandaloneMuon/hCorrelation_Phi"), mctrack.phi(), mctrack.phiSmeared_sa_muon()); + + // for global muons + if (mctrack.pt() > 0.f) { + deltaptoverpt = (mctrack.pt() - mctrack.ptSmeared_gl_muon()) / mctrack.pt(); + } + deltaeta = mctrack.eta() - mctrack.etaSmeared_gl_muon(); + deltaphi = mctrack.phi() - mctrack.phiSmeared_gl_muon(); + registry.fill(HIST("GlobalMuon/PtGen_DeltaPtOverPtGen"), mctrack.pt(), deltaptoverpt); + registry.fill(HIST("GlobalMuon/PtGen_DeltaEta"), mctrack.pt(), deltaeta); + if (mctrack.pdgCode() < 0) { // mu+ + registry.fill(HIST("GlobalMuon/PtGen_DeltaPhi_Pos"), mctrack.pt(), deltaphi); + } else { // mu- + registry.fill(HIST("GlobalMuon/PtGen_DeltaPhi_Neg"), mctrack.pt(), deltaphi); + } + registry.fill(HIST("GlobalMuon/hCorrelation_Pt"), mctrack.pt(), mctrack.ptSmeared_gl_muon()); + registry.fill(HIST("GlobalMuon/hCorrelation_Eta"), mctrack.eta(), mctrack.etaSmeared_gl_muon()); + registry.fill(HIST("GlobalMuon/hCorrelation_Phi"), mctrack.phi(), mctrack.phiSmeared_gl_muon()); + } + } // end of mctrack loop } - void processCheckMCanalysisDQ(MyReducedTracks const& tracksMC) + void processCheckMCanalysisEM(EMMCParticlesWithSmearing const& tracksMC, MyMCCollisions const& mccollisions) { - Check(tracksMC); + Check(tracksMC, mccollisions); } void processCheckCocktail(MyCocktailTracks const& tracksMC) { - Check(tracksMC); + Check(tracksMC, nullptr); } - void processDummyMCanalysis(ReducedMCTracks const&) {} + void processDummyMCanalysisEM(aod::EMMCParticles const&) {} void processDummyCocktail(aod::McParticles const&) {} 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, processDummyCocktail, "Dummy process function", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGEM/Dilepton/Tasks/studyDCAFitter.cxx b/PWGEM/Dilepton/Tasks/studyDCAFitter.cxx new file mode 100644 index 00000000000..d1d6452a50a --- /dev/null +++ b/PWGEM/Dilepton/Tasks/studyDCAFitter.cxx @@ -0,0 +1,974 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file studyDCAFitter.cxx +/// \brief a task to study tagging e from charm hadron decays in MC +/// \author daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TableHelper.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include +#include + +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::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::pairutil; + +struct studyDCAFitter { + using MyCollisions = soa::Join; + + using MyTracks = soa::Join; + + struct DielectronAtSV { // ee pair at SV + bool isfound{false}; + float mass{-999.f}; + float pt{-999.f}; + float dca2legs{-999.f}; + float cospa{-999.f}; + float lxy{-999.f}; + float lz{-999.f}; + float lxyz = std::sqrt(std::pow(lxy, 2) + std::pow(lz, 2)); + }; + + // 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"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; + Configurable d_UseWeightedPCA{"d_UseWeightedPCA", false, "Vertices use cov matrices"}; + + struct : ConfigurableGroup { + std::string prefix = "electroncut"; + 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", -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", 0.7, "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", 3, "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_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_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2, "min TPC n sigma el inclusion"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3, "max TPC n sigma el inclusion"}; + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -1e+10, "min TPC n sigma pi exclusion"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +3, "max TPC n sigma pi exclusion"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3, "min TOF n sigma el inclusion"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3, "max TOF n sigma el inclusion"}; + } electroncut; + + struct : ConfigurableGroup { + std::string prefix = "svcut"; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "min cospa"}; + Configurable cfg_max_dca2legs{"cfg_max_dca2legs", 0.1, "max distance between 2 legs"}; + } svcut; + + 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"}; + + Configurable cfgEventGeneratorType{"cfgEventGeneratorType", -1, "if positive, select event generator type. i.e. gap or signal"}; + + HistogramRegistry fRegistry{"fRegistry"}; + static constexpr std::string_view hadron_names[6] = {"LF/", "Jpsi/", "D0/", "Dpm/", "Ds/", "Lc/"}; + static constexpr std::string_view pair_names[3] = {"e_Kpm/", "e_K0S/", "e_Lambda/"}; + static constexpr std::string_view hTypes[4] = {"findable/", "correct/", "fake/", "miss/"}; + static constexpr std::string_view promptTypes[2] = {"prompt/", "nonprompt/"}; + + void init(o2::framework::InitContext&) + { + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + fitter.setPropagateToPCA(true); + fitter.setMaxR(5.f); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(d_UseAbsDCA); + fitter.setWeightedFinalPCA(d_UseWeightedPCA); + fitter.setMatCorrType(matCorr); + + addHistograms(); + } + + 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; + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + o2::vertexing::DCAFitterN<2> fitter; + o2::dataformats::DCA mDcaInfoCov; + o2::dataformats::VertexBase mVtx; + + template + void initCCDB(TBC 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(); + fitter.setBz(d_bz); + } + + void addHistograms() + { + auto hCollisionCounter = fRegistry.add("Event/hCollisionCounter", "collision counter", kTH1D, {{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); + + // for pairs + fRegistry.add("Pair/PV/Data/uls/hs", "hs;m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c);DCA_{ee}^{3D} (#sigma);", kTHnSparseF, {{500, 0, 5}, {100, 0, 10}, {100, 0, 10}}, true); + fRegistry.addClone("Pair/PV/Data/uls/", "Pair/PV/Data/lspp/"); + fRegistry.addClone("Pair/PV/Data/uls/", "Pair/PV/Data/lsmm/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/PromptPhi/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/NonPromptPhi/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/PromptOmega/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/NonPromptOmega/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/PromptJpsi/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/NonPromptJpsi/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/c2e_c2e/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/b2e_b2e/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/b2c2e_b2c2e/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/b2c2e_b2e_sameb/"); + fRegistry.addClone("Pair/PV/Data/", "Pair/PV/MC/b2c2e_b2e_diffb/"); + + fRegistry.add("Pair/SV/Data/uls/hs", "hs;m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c);L_{xy} m_{ee}/p_{T,ee} (mm);", kTHnSparseF, {{500, 0, 5}, {100, 0, 10}, {200, -10, 10}}, true); + fRegistry.add("Pair/SV/Data/uls/hCosPA", "cosPA;cosPA;", kTH1F, {{200, -1, 1}}, false); + fRegistry.add("Pair/SV/Data/uls/hDCA2Legs", "distance between 2 legs at PCA;distance between 2 legs (cm);", kTH1F, {{100, 0, 0.1}}, false); + fRegistry.addClone("Pair/SV/Data/uls/", "Pair/SV/Data/lspp/"); + fRegistry.addClone("Pair/SV/Data/uls/", "Pair/SV/Data/lsmm/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/PromptPhi/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/NonPromptPhi/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/PromptOmega/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/NonPromptOmega/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/PromptJpsi/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/NonPromptJpsi/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/c2e_c2e/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/b2e_b2e/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/b2c2e_b2c2e/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/b2c2e_b2e_sameb/"); + fRegistry.addClone("Pair/SV/Data/", "Pair/SV/MC/b2c2e_b2e_diffb/"); + } + + template + bool isElectron(TTrack const& track) + { + // TOFif + bool is_el_included_TPC = electroncut.cfg_min_TPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < electroncut.cfg_max_TPCNsigmaEl; + bool is_el_included_TOF = track.hasTOF() ? (electroncut.cfg_min_TOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < electroncut.cfg_max_TOFNsigmaEl) : true; + return is_el_included_TPC && is_el_included_TOF; + } + + template + bool isSelectedTrack(TTrack const& track, TTrackParCov const& trackParCov, const float dcaXY, const float dcaZ) + { + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + + if (trackParCov.getPt() < electroncut.cfg_min_pt_track || electroncut.cfg_max_pt_track < trackParCov.getPt()) { + return false; + } + + if (trackParCov.getEta() < electroncut.cfg_min_eta_track || electroncut.cfg_max_eta_track < trackParCov.getEta()) { + return false; + } + + if (std::fabs(dcaXY) > electroncut.cfg_max_dcaxy) { + return false; + } + + if (std::fabs(dcaZ) > electroncut.cfg_max_dcaz) { + return false; + } + + if (track.itsChi2NCl() > electroncut.cfg_max_chi2its) { + return false; + } + + if (track.itsNCls() < electroncut.cfg_min_ncluster_its) { + return false; + } + + if (track.itsNClsInnerBarrel() < electroncut.cfg_min_ncluster_itsib) { + return false; + } + + if (track.tpcChi2NCl() > electroncut.cfg_max_chi2tpc) { + return false; + } + + if (track.tpcNClsFound() < electroncut.cfg_min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < electroncut.cfg_min_ncrossedrows_tpc) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < electroncut.cfg_min_cr2findable_ratio_tpc) { + return false; + } + + if (track.tpcFractionSharedCls() > electroncut.cfg_max_frac_shared_clusters_tpc) { + return false; + } + + return true; + } + + 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 fillElectronHistograms(TTrack const& track, TTrackParCov const& trackParCov, const float dcaXY, const float dcaZ) + { + if (std::find(used_electronIds.begin(), used_electronIds.end(), std::make_pair(findId, track.globalIndex())) == used_electronIds.end()) { + float dca3DinSigma = dca3DinSigmaOTF(dcaXY, dcaZ, trackParCov.getSigmaY2(), trackParCov.getSigmaZ2(), trackParCov.getSigmaZY()); + fRegistry.fill(HIST(hadron_names[charmHadronId]) + HIST("electron/") + HIST(promptTypes[promptId]) + HIST(hTypes[findId]) + HIST("hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + fRegistry.fill(HIST(hadron_names[charmHadronId]) + HIST("electron/") + HIST(promptTypes[promptId]) + HIST(hTypes[findId]) + HIST("hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST(hadron_names[charmHadronId]) + HIST("electron/") + HIST(promptTypes[promptId]) + HIST(hTypes[findId]) + HIST("hTOFbeta"), trackParCov.getP(), track.beta()); + used_electronIds.emplace_back(std::make_pair(findId, track.globalIndex())); + } + } + + float dca3DinSigmaOTF(const float dcaXY, const float dcaZ, const float cYY, const float cZZ, const float cZY) + { + 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 + int FindLF(TTrack const& posmc, TTrack const& negmc, TMCParticles const& mcparticles) + { + int arr[] = { + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 22, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 111, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 221, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 331, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 113, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 223, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 333, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 443, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 100443, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 553, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 100553, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 200553, mcparticles), + FindCommonMotherFrom2Prongs(posmc, negmc, -11, 11, 300553, mcparticles)}; + int size = sizeof(arr) / sizeof(*arr); + int max = *std::max_element(arr, arr + size); + return max; + } + + template + void runPairingAtPV(TTrack const& t1, TTrack const& t2, TMCParticles const& mcParticles) + { + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov1 = getTrackParCov(t1); + trackParCov1.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov1, 2.f, matCorr, &mDcaInfoCov); + float dcaXY1 = mDcaInfoCov.getY(); + float dcaZ1 = mDcaInfoCov.getZ(); + + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov2 = getTrackParCov(t2); + trackParCov2.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov2, 2.f, matCorr, &mDcaInfoCov); + float dcaXY2 = mDcaInfoCov.getY(); + float dcaZ2 = mDcaInfoCov.getZ(); + + ROOT::Math::PtEtaPhiMVector v1(trackParCov1.getPt(), trackParCov1.getEta(), trackParCov1.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(trackParCov2.getPt(), trackParCov2.getEta(), trackParCov2.getPhi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float dca3DinSigma1 = dca3DinSigmaOTF(dcaXY1, dcaZ1, trackParCov1.getSigmaY2(), trackParCov1.getSigmaZ2(), trackParCov1.getSigmaZY()); + float dca3DinSigma2 = dca3DinSigmaOTF(dcaXY2, dcaZ2, trackParCov2.getSigmaY2(), trackParCov2.getSigmaZ2(), trackParCov2.getSigmaZY()); + float pair_dca = pairDCAQuadSum(dca3DinSigma1, dca3DinSigma2); + + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/Data/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/Data/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/Data/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + + if constexpr (isMC) { + const auto& t1mc = t1.template mcParticle_as(); + const auto& t2mc = t2.template mcParticle_as(); + if (std::abs(t1mc.pdgCode()) != 11) { + return; + } + if (!(t1mc.isPhysicalPrimary() || t1mc.producedByGenerator())) { + return; + } + if (std::abs(t2mc.pdgCode()) != 11) { + return; + } + if (!(t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + return; + } + // const auto& mp1 = t1mc.template mothers_first_as(); // mother particle of t1 + // const auto& mp2 = t2mc.template mothers_first_as(); // mother particle of t2 + int mcCommonMotherid = FindLF(t1mc, t2mc, mcParticles); + int hfee_type = IsHF(t1mc, t2mc, mcParticles); + + if (mcCommonMotherid > -1) { + const auto cmp = mcParticles.rawIteratorAt(mcCommonMotherid); + switch (std::abs(cmp.pdgCode())) { + case 223: + if (IsFromCharm(cmp, mcParticles) < 0 && IsFromBeauty(cmp, mcParticles) < 0) { // prompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/PromptOmega/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/PromptOmega/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/PromptOmega/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + } else { // nonprompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/NonPromptOmega/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/NonPromptOmega/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/NonPromptOmega/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + } + break; + case 333: + if (IsFromCharm(cmp, mcParticles) < 0 && IsFromBeauty(cmp, mcParticles) < 0) { // prompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/PromptPhi/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/PromptPhi/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/PromptPhi/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + } else { // nonprompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/NonPromptPhi/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/NonPromptPhi/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/NonPromptPhi/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + } + break; + case 443: + if (IsFromCharm(cmp, mcParticles) < 0 && IsFromBeauty(cmp, mcParticles) < 0) { // prompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/PromptJpsi/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/PromptJpsi/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/PromptJpsi/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + } else { // nonprompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/NonPromptJpsi/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/NonPromptJpsi/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/NonPromptJpsi/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + } + break; + default: + break; + } // end of switch for LF + } else if (hfee_type > -1) { + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/c2e_c2e/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/c2e_c2e/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/c2e_c2e/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + break; + case static_cast(EM_HFeeType::kBe_Be): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/b2e_b2e/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/b2e_b2e/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/b2e_b2e/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + break; + case static_cast(EM_HFeeType::kBCe_BCe): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2c2e/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2c2e/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2c2e/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2e_sameb/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2e_sameb/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2e_sameb/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2e_diffb/uls/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 1) { // LS+diff + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2e_diffb/lspp/hs"), v12.M(), v12.Pt(), pair_dca); + } else if constexpr (signType == 2) { // LS-diff + fRegistry.fill(HIST("Pair/PV/MC/b2c2e_b2e_diffb/lsmm/hs"), v12.M(), v12.Pt(), pair_dca); + } + break; + + default: + break; + } // end of switch for HFee + } // end of HFee + } // end of isMC + } + + template + void runSVFinder(TCollision const& collision, TTrack const& t1, TTrack const& t2, TMCParticles const& mcParticles) + { + DielectronAtSV eeatsv; + + auto trackParCov1 = getTrackParCov(t1); + trackParCov1.setPID(o2::track::PID::Electron); + auto trackParCov2 = getTrackParCov(t2); + trackParCov2.setPID(o2::track::PID::Electron); + + std::array pVtx = {collision.posX(), collision.posY(), collision.posZ()}; + std::array svpos = {0.}; // secondary vertex position + std::array pvec0 = {0.}; + std::array pvec1 = {0.}; + + int nCand = 0; + try { + nCand = fitter.process(trackParCov1, trackParCov2); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + return; + } + if (nCand == 0) { + return; + } + + fitter.propagateTracksToVertex(); // propagate e and K to D vertex + if (!fitter.isPropagateTracksToVertexDone()) { + return; + } + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + svpos[i] = vtx[i]; + } + fitter.getTrack(0).getPxPyPzGlo(pvec0); + fitter.getTrack(1).getPxPyPzGlo(pvec1); + std::array pvecSum = {pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}; + + float cpa = RecoDecay::cpa(pVtx, svpos, pvecSum); + float dca2legs = std::sqrt(fitter.getChi2AtPCACandidate()); + // float lxy = std::sqrt(std::pow(svpos[0] - collision.posX(), 2) + std::pow(svpos[1] - collision.posY(), 2)); // in cm + float lz = std::fabs(svpos[2] - collision.posZ()); // in cm + + float meeAtSV = RecoDecay::m(std::array{pvec0, pvec1}, std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + float pteeAtSV = RecoDecay::sqrtSumOfSquares(pvecSum[0], pvecSum[1]); + float lxy = RecoDecay::dotProd(std::array{pvecSum[0], pvecSum[1]}, std::array{svpos[0] - collision.posX(), svpos[1] - collision.posY()}) / pteeAtSV; + float ppdl = lxy * 1e-2 * meeAtSV / pteeAtSV * 1e+3; // pseudo-proper decay length in mm + + if (cpa < svcut.cfg_min_cospa || svcut.cfg_max_dca2legs < dca2legs) { + return; + } + + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/Data/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/Data/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/Data/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/Data/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/Data/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/Data/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/Data/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/Data/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/Data/lsmm/hDCA2Legs"), dca2legs); + } + + if constexpr (isMC) { + const auto& t1mc = t1.template mcParticle_as(); + const auto& t2mc = t2.template mcParticle_as(); + if (std::abs(t1mc.pdgCode()) != 11) { + return; + } + if (!(t1mc.isPhysicalPrimary() || t1mc.producedByGenerator())) { + return; + } + if (std::abs(t2mc.pdgCode()) != 11) { + return; + } + if (!(t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { + return; + } + // const auto& mp1 = t1mc.template mothers_first_as(); // mother particle of t1 + // const auto& mp2 = t2mc.template mothers_first_as(); // mother particle of t2 + int mcCommonMotherid = FindLF(t1mc, t2mc, mcParticles); + int hfee_type = IsHF(t1mc, t2mc, mcParticles); + + if (mcCommonMotherid > -1) { + const auto cmp = mcParticles.rawIteratorAt(mcCommonMotherid); + switch (cmp.pdgCode()) { + case 223: + if (IsFromCharm(cmp, mcParticles) < 0 && IsFromBeauty(cmp, mcParticles) < 0) { // prompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptOmega/lsmm/hDCA2Legs"), dca2legs); + } + } else { // nonprompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptOmega/lsmm/hDCA2Legs"), dca2legs); + } + } + break; + case 333: + if (IsFromCharm(cmp, mcParticles) < 0 && IsFromBeauty(cmp, mcParticles) < 0) { // prompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptPhi/lsmm/hDCA2Legs"), dca2legs); + } + } else { // nonprompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptPhi/lsmm/hDCA2Legs"), dca2legs); + } + } + break; + case 443: + if (IsFromCharm(cmp, mcParticles) < 0 && IsFromBeauty(cmp, mcParticles) < 0) { // prompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/PromptJpsi/lsmm/hDCA2Legs"), dca2legs); + } + } else { // nonprompt + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/NonPromptJpsi/lsmm/hDCA2Legs"), dca2legs); + } + } + break; + default: + break; + } // end of switch for LF + } else if (hfee_type > -1) { + switch (hfee_type) { + case static_cast(EM_HFeeType::kCe_Ce): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/c2e_c2e/lsmm/hDCA2Legs"), dca2legs); + } + break; + case static_cast(EM_HFeeType::kBe_Be): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2e_b2e/lsmm/hDCA2Legs"), dca2legs); + } + break; + case static_cast(EM_HFeeType::kBCe_BCe): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2c2e/lsmm/hDCA2Legs"), dca2legs); + } + break; + case static_cast(EM_HFeeType::kBCe_Be_SameB): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS++ + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-- + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_sameb/lsmm/hDCA2Legs"), dca2legs); + } + break; + case static_cast(EM_HFeeType::kBCe_Be_DiffB): + if constexpr (signType == 0) { // ULS + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/uls/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/uls/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/uls/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 1) { // LS+diff + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/lspp/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/lspp/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/lspp/hDCA2Legs"), dca2legs); + } else if constexpr (signType == 2) { // LS-diff + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/lsmm/hs"), meeAtSV, pteeAtSV, ppdl); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/lsmm/hCosPA"), cpa); + fRegistry.fill(HIST("Pair/SV/MC/b2c2e_b2e_diffb/lsmm/hDCA2Legs"), dca2legs); + } + break; + + default: + break; + } // end of switch for HFee + } // end of HFee + } // end of isMC + + eeatsv.isfound = true; + eeatsv.mass = meeAtSV; + eeatsv.pt = pteeAtSV; + eeatsv.cospa = cpa; + eeatsv.dca2legs = dca2legs; + eeatsv.lxy = lxy; + eeatsv.lz = lz; + return; + } + + template + void run(TBCs const&, TCollisions const& collisions, TTracks const& tracks, TTrackAssoc const& trackIndices, TMCCollisions const&, TMCParticles const& mcParticles) + { + used_electronIds.reserve(tracks.size()); + + for (const auto& collision : collisions) { + const auto& bc = collision.template foundBC_as(); + initCCDB(bc); + fRegistry.fill(HIST("Event/hCollisionCounter"), 0); + + 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& trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + electronIds.reserve(trackIdsThisCollision.size()); + positronIds.reserve(trackIdsThisCollision.size()); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + + for (const auto& trackId : trackIdsThisCollision) { + const auto& track = trackId.template track_as(); + if (!track.hasITS() || !track.hasTPC()) { + continue; + } + + if constexpr (isMC) { + if (!track.has_mcParticle()) { + continue; + } + const auto& mctrack = track.template mcParticle_as(); + const auto& mcCollision = mctrack.template mcCollision_as(); + if (cfgEventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != cfgEventGeneratorType) { + continue; + } + if (!mctrack.has_mothers()) { + continue; + } + } + + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (isSelectedTrack(track, trackParCov, dcaXY, dcaZ) && isElectron(track)) { + if (track.sign() > 0) { // positron + positronIds.emplace_back(trackId.trackId()); + } else { // electron + electronIds.emplace_back(trackId.trackId()); + } + } + } // end of track loop for electron selection + + for (const auto& posId : positronIds) { + const auto& pos = tracks.rawIteratorAt(posId); + for (const auto& eleId : electronIds) { + const auto& ele = tracks.rawIteratorAt(eleId); + runSVFinder(collision, pos, ele, mcParticles); + runPairingAtPV(pos, ele, mcParticles); + } // end of electron loop + } // end of positron loop + + for (const auto& posId1 : positronIds) { + const auto& pos1 = tracks.rawIteratorAt(posId1); + for (const auto& posId2 : positronIds) { + const auto& pos2 = tracks.rawIteratorAt(posId2); + if (pos1.globalIndex() == pos2.globalIndex()) { + continue; + } + runSVFinder(collision, pos1, pos2, mcParticles); + runPairingAtPV(pos1, pos2, mcParticles); + } // end of positron loop + } // end of positron loop + + for (const auto& eleId1 : electronIds) { + const auto& ele1 = tracks.rawIteratorAt(eleId1); + for (const auto& eleId2 : electronIds) { + const auto& ele2 = tracks.rawIteratorAt(eleId2); + if (ele1.globalIndex() == ele2.globalIndex()) { + continue; + } + runSVFinder(collision, ele1, ele2, mcParticles); + runPairingAtPV(ele1, ele2, mcParticles); + } // end of electron loop + } // end of electron loop + + electronIds.clear(); + electronIds.shrink_to_fit(); + positronIds.clear(); + positronIds.shrink_to_fit(); + } // end of collision loop + + used_electronIds.clear(); + used_electronIds.shrink_to_fit(); + } + + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + + 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; + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + // Partition posTracks = o2::aod::track::signed1Pt > 0.f; + // Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + std::vector electronIds; + std::vector positronIds; + std::vector> used_electronIds; // pair of hTypeId and electronId + + void processMC(FilteredMyCollisions const& collisions, aod::BCsWithTimestamps const& bcs, MyTracks const& tracks, aod::TrackAssoc const& trackIndices, aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + run(bcs, collisions, tracks, trackIndices, mcCollisions, mcParticles); + } + PROCESS_SWITCH(studyDCAFitter, processMC, "processMC", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"study-dcafitter"})}; +} 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 index 227e070baca..9787a5bae04 100644 --- a/PWGEM/Dilepton/Tasks/tableReaderBarrel.cxx +++ b/PWGEM/Dilepton/Tasks/tableReaderBarrel.cxx @@ -11,36 +11,44 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // -#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/AnalysisCut.h" #include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" #include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/CCDB/EventSelectionParams.h" + +#include "CCDB/BasicCCDBManager.h" #include "DataFormatsParameters/GRPMagField.h" -#include "Field/MagneticField.h" -#include "TGeoGlobalMagField.h" -#include "DetectorsBase/Propagator.h" +#include "DataFormatsParameters/GRPObject.h" #include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" #include "ITSMFTBase/DPLAlpideParam.h" -#include "Common/CCDB/EventSelectionParams.h" + +#include "TGeoGlobalMagField.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include using std::cout; using std::endl; @@ -119,12 +127,12 @@ struct AnalysisEventSelection { 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 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"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; AnalysisCompositeCut* fEventCut; struct : ConfigurableGroup { @@ -137,8 +145,8 @@ struct AnalysisEventSelection { 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 cfgOccupancyMin{"cfgOccupancyMin", -1000000000, "min. occupancy"}; - Configurable cfgOccupancyMax{"cfgOccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -1000000000, "min. occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; } eventcuts; HistogramManager* fHistMan = nullptr; @@ -233,7 +241,7 @@ struct AnalysisEventSelection { if (eventcuts.cfgRequireGoodZvtxFT0vsPV) cut->AddCut(VarManager::kIsGoodZvtxFT0vsPV, 0.5, 1.5); cut->AddCut(VarManager::kCentFT0C, eventcuts.cfgCentFT0CMin, eventcuts.cfgCentFT0CMax); - cut->AddCut(VarManager::kTrackOccupancyInTimeRange, eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); + cut->AddCut(VarManager::kTrackOccupancyInTimeRange, eventcuts.cfgTrackOccupancyMin, eventcuts.cfgTrackOccupancyMax); return cut; } @@ -280,16 +288,14 @@ struct AnalysisTrackSelection { // 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 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 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"}; + Configurable fConfigNbTrackCut{"cfgNbTrackCut", 1, "Number of cuts including prefilter cut, need to be below 30"}; std::vector fTrackCuts; struct : ConfigurableGroup { @@ -341,10 +347,9 @@ struct AnalysisTrackSelection { { fCurrentRun = 0; - int nbofcuts = fConfigNbTrackCut; - if (nbofcuts > 0 && CheckSize()) { - for (unsigned int icut = 0; icut < nbofcuts; ++icut) { - AnalysisCompositeCut* cut = new AnalysisCompositeCut(Form("trackcut%d", icut), Form("trackcut%d", icut)); + 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); @@ -369,9 +374,6 @@ struct AnalysisTrackSelection { 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); @@ -639,7 +641,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; @@ -791,7 +793,7 @@ struct AnalysisEventMixing { // 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 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"}; @@ -828,14 +830,14 @@ struct AnalysisEventMixing { // 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 (int icut = 0; icut < fConfigNbTrackCut; ++icut) { + for (std::size_t icut = 0; icut < fConfigNbTrackCut; ++icut) { std::vector names = { - Form("PairsBarrelMEPM_trackcut%d", icut), - Form("PairsBarrelMEPP_trackcut%d", icut), - Form("PairsBarrelMEMM_trackcut%d", icut)}; + 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 |= (uint32_t(1) << icut); + fTwoTrackFilterMask |= (static_cast(1) << icut); } } @@ -854,12 +856,12 @@ struct AnalysisEventMixing { uint32_t twoTrackFilter = 0; for (auto& track1 : tracks1) { for (auto& track2 : tracks2) { - twoTrackFilter = uint32_t(track1.isBarrelSelected()) & uint32_t(track2.isBarrelSelected()) & fTwoTrackFilterMask; + 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); + VarManager::FillPairME(track1, track2); constexpr bool eventHasQvector = (VarManager::ObjTypes::ReducedEventQvector > 0); if constexpr (eventHasQvector) { @@ -871,7 +873,7 @@ struct AnalysisEventMixing { } 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); } else { @@ -882,9 +884,9 @@ struct AnalysisEventMixing { } } } // 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 @@ -948,10 +950,10 @@ struct AnalysisSameEventPairing { 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 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"}; @@ -1069,35 +1071,34 @@ struct AnalysisSameEventPairing { std::vector names; if (fConfigNbPairCut > 0 && CheckSize()) { - for (int icut = 0; icut < fConfigNbPairCut; ++icut) { + for (std::size_t icut = 0; icut < fConfigNbPairCut; ++icut) { fPairCuts.push_back(*GetPairCut(icut)); } } - if (fConfigNbTrackCut > 0 && fConfigNbTrackCut < 31) { // if track cuts - for (int icut = 0; icut < fConfigNbTrackCut; ++icut) { // loop over track cuts - fTwoTrackFilterMask |= (uint32_t(1) << 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%d", icut), - Form("PairsBarrelSEPP_trackcut%d", icut), - Form("PairsBarrelSEMM_trackcut%d", icut)}; + 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); - unsigned int npaircuts = fPairCuts.size(); - for (int iPairCut = 0; iPairCut < npaircuts; ++iPairCut) { // loop over pair cuts + for (std::size_t iPairCut = 0; iPairCut < fPairCuts.size(); ++iPairCut) { // loop over pair cuts names = { - Form("PairsBarrelSEPM_trackcut%d_paircut%d", icut, iPairCut), - Form("PairsBarrelSEPP_trackcut%d_paircut%d", icut, iPairCut), - Form("PairsBarrelSEMM_trackcut%d_paircut%d", icut, iPairCut)}; + 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) + } // 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 @@ -1125,7 +1126,7 @@ struct AnalysisSameEventPairing { uint32_t twoTrackFilter = 0; for (auto& [t1, t2] : combinations(tracks1, tracks2)) { - twoTrackFilter = uint32_t(t1.isBarrelSelected()) & uint32_t(t2.isBarrelSelected()) & fTwoTrackFilterMask; + 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; @@ -1143,8 +1144,8 @@ struct AnalysisSameEventPairing { } int iCut = 0; - for (int icut = 0; icut < fConfigNbTrackCut; icut++) { - if (twoTrackFilter & (uint32_t(1) << icut)) { + 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 { @@ -1168,12 +1169,12 @@ struct AnalysisSameEventPairing { fHistMan->FillHistClass(histNames[iCut][2].Data(), VarManager::fgValues); } } - } // 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) diff --git a/PWGEM/Dilepton/Tasks/taggingHFE.cxx b/PWGEM/Dilepton/Tasks/taggingHFE.cxx new file mode 100644 index 00000000000..02bce88073e --- /dev/null +++ b/PWGEM/Dilepton/Tasks/taggingHFE.cxx @@ -0,0 +1,1674 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file taggingHFE.cxx +/// \brief a task to study tagging e from charm hadron decays in MC +/// \author daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TableHelper.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include +#include +#include + +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::mcutil; + +struct taggingHFE { + using MyCollisions = soa::Join; + using MyCollisionsWithMCLabel = soa::Join; + + using MyTracks = soa::Join; + using MyTracksWithMCLabel = soa::Join; + + using MyV0s = soa::Join; + using MyCascades = soa::Join; + + struct EBPair { // electron-baryon pair + float mass{-999.f}; + float dca2legs{-999.f}; + float cospa{-999.f}; + float lxy{-999.f}; + float lz{-999.f}; + float ptepv{-999.f}; + float dca3dinsigma{-999.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 mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; + Configurable d_UseWeightedPCA{"d_UseWeightedPCA", false, "Vertices use cov matrices"}; + + struct : ConfigurableGroup { + std::string prefix = "electroncut"; + 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", -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", 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", 5, "min ncluster its"}; + Configurable cfg_min_ncluster_itsib{"cfg_min_ncluster_itsib", 3, "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_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_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2, "min n sigma el in TPC"}; + Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3, "max n sigma el in TPC"}; + Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3, "min n sigma el in TOF"}; + Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3, "max n sigma el in TOF"}; + } electroncut; + + struct : ConfigurableGroup { + std::string prefix = "loose_electroncut"; + 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", -1.2, "min eta for single track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +1.2, "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", 40, "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", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.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"}; + } loose_electroncut; + + struct : ConfigurableGroup { + std::string prefix = "kaoncut"; + Configurable cfg_min_TPCNsigmaKa{"cfg_min_TPCNsigmaKa", -3, "min n sigma ka in TPC"}; + Configurable cfg_max_TPCNsigmaKa{"cfg_max_TPCNsigmaKa", +3, "max n sigma ka in TPC"}; + Configurable cfg_min_TOFNsigmaKa{"cfg_min_TOFNsigmaKa", -3, "min n sigma ka in TOF"}; + Configurable cfg_max_TOFNsigmaKa{"cfg_max_TOFNsigmaKa", +3, "max n sigma ka in TOF"}; + } kaoncut; + + struct : ConfigurableGroup { + std::string prefix = "v0cut"; + Configurable cfg_min_mass_k0s_veto{"cfg_min_mass_k0s_veto", 0.47, "min mass for K0S veto"}; + Configurable cfg_max_mass_k0s_veto{"cfg_max_mass_k0s_veto", 0.52, "max mass for K0S veto"}; + Configurable cfg_min_mass_lambda{"cfg_min_mass_lambda", 1.113, "min mass for Lambda"}; + Configurable cfg_max_mass_lambda{"cfg_max_mass_lambda", 1.118, "max mass for Lambda"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "min cospa for v0hadron"}; + Configurable cfg_max_dca2legs{"cfg_max_dca2legs", 0.1, "max distance between 2 legs for v0hadron"}; + // Configurable cfg_min_radius{"cfg_min_radius", 0.1, "min rxy for v0hadron"}; + 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_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.0, "max chi2/NclsITS"}; + 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_min_dcaxy{"cfg_min_dcaxy", 0.1, "min dca XY for v0 legs in cm"}; + + Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -2, "min n sigma pi in TPC"}; + Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +2, "max n sigma pi in TPC"}; + Configurable cfg_min_TPCNsigmaPr{"cfg_min_TPCNsigmaPr", -2, "min n sigma pr in TPC"}; + Configurable cfg_max_TPCNsigmaPr{"cfg_max_TPCNsigmaPr", +2, "max n sigma pr in TPC"}; + 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"}; + Configurable cfg_min_TOFNsigmaPr{"cfg_min_TOFNsigmaPr", -2, "min n sigma pr in TOF"}; + Configurable cfg_max_TOFNsigmaPr{"cfg_max_TOFNsigmaPr", +2, "max n sigma pr in TOF"}; + } v0cut; + + struct : ConfigurableGroup { + std::string prefix = "cascadecut"; + 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.316, "min mass for Xi"}; + Configurable cfg_max_mass_Xi{"cfg_max_mass_Xi", 1.326, "max mass for Xi"}; + Configurable cfg_min_mass_Xi_veto{"cfg_min_mass_Xi_veto", 1.31, "min mass for Xi veto"}; + Configurable cfg_max_mass_Xi_veto{"cfg_max_mass_Xi_veto", 1.33, "max mass for Xi veto"}; + Configurable cfg_min_mass_Omega{"cfg_min_mass_Omega", 1.669, "min mass for Omega"}; + Configurable cfg_max_mass_Omega{"cfg_max_mass_Omega", 1.675, "max mass for Omega"}; + Configurable cfg_min_mass_Omega_veto{"cfg_min_mass_Omega_veto", 1.66, "min mass for Omega veto"}; + Configurable cfg_max_mass_Omega_veto{"cfg_max_mass_Omega_veto", 1.68, "max mass for Omega veto"}; + Configurable cfg_min_cospa_v0{"cfg_min_cospa_v0", 0.995, "minimum V0 CosPA in cascade"}; + Configurable cfg_max_dcadau_v0{"cfg_max_dcadau_v0", 0.1, "max distance between V0 Daughters in cascade"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.9998, "minimum cascade CosPA"}; + Configurable cfg_max_dcadau{"cfg_max_dcadau", 0.1, "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.05, "min dca XY for bachelor in cm"}; + Configurable cfg_min_dcaxy_v0{"cfg_min_dcaxy_v0", 0.05, "min dca XY for V0 in cm"}; + } cascadecut; + + struct : ConfigurableGroup { + std::string prefix = "eventcut"; + 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"}; + Configurable cfgEventGeneratorType{"cfgEventGeneratorType", -1, "if positive, select event generator type. i.e. gap or signal"}; + } eventcut; + + Configurable cfgMeeMaxPF{"cfgMeeMaxPF", 0.04, "max mee for prefilter to reject pi0->ee and gamma->ee in LMR"}; + + HistogramRegistry fRegistry{"fRegistry"}; + static constexpr std::string_view hadron_names[6] = {"LF/", "Jpsi/", "D0/", "Dpm/", "Ds/", "Lc/"}; + static constexpr std::string_view pair_names[3] = {"e_Kpm/", "e_K0S/", "e_Lambda/"}; + static constexpr std::string_view hTypes[4] = {"findable/", "correct/", "fake/", "miss/"}; + static constexpr std::string_view promptTypes[2] = {"prompt/", "nonprompt/"}; + + void init(o2::framework::InitContext&) + { + // if (doprocessSA && doprocessTTCA) { + // 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); + + fitter.setPropagateToPCA(true); + fitter.setMaxR(10.f); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(d_UseAbsDCA); + fitter.setWeightedFinalPCA(d_UseWeightedPCA); + fitter.setMatCorrType(matCorr); + + addHistograms(); + } + + 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; + const o2::dataformats::MeanVertexObject* mMeanVtx = nullptr; + o2::base::MatLayerCylSet* lut = nullptr; + o2::vertexing::DCAFitterN<2> fitter; + o2::dataformats::DCA mDcaInfoCov; + o2::dataformats::VertexBase mVtx; + + 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(); + fitter.setBz(d_bz); + } + + void addHistograms() + { + auto hCollisionCounter = fRegistry.add("Event/hCollisionCounter", "collision counter", kTH1D, {{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); + + fRegistry.add("Prefilter/before/uls/hMee", "hMee;m_{ee} (GeV/c^{2});", kTH1F, {{500, 0, 5}}, false); + fRegistry.addClone("Prefilter/before/uls/", "Prefilter/before/lspp/"); + fRegistry.addClone("Prefilter/before/uls/", "Prefilter/before/lsmm/"); + fRegistry.addClone("Prefilter/before/", "Prefilter/after/"); + + // electron-related histograms + fRegistry.add("Data/electron/hs", "hs;p_{T,e} (GeV/c);#eta_{e};#varphi_{e} (rad.);DCA_{e}^{3D} (#sigma);", kTHnSparseF, {{100, 0, 10}, {20, -1, +1}, {90, 0, 2 * M_PI}, {100, 0, 10}}, false); + fRegistry.addClone("Data/electron/", "MC/eFromPromptLF/"); + fRegistry.addClone("Data/electron/", "MC/eFromNonPromptLF/"); + fRegistry.addClone("Data/electron/", "MC/eFromPromptJpsi/"); + fRegistry.addClone("Data/electron/", "MC/eFromNonPromptJpsi/"); + fRegistry.addClone("Data/electron/", "MC/eFromPromptD0/"); + fRegistry.addClone("Data/electron/", "MC/eFromPromptDpm/"); + fRegistry.addClone("Data/electron/", "MC/eFromPromptDs/"); + fRegistry.addClone("Data/electron/", "MC/eFromPromptLcpm/"); + fRegistry.addClone("Data/electron/", "MC/eFromPromptXic0/"); + // fRegistry.addClone("Data/electron/", "MC/eFromPromptXicpm/"); // cannot be detected + fRegistry.addClone("Data/electron/", "MC/eFromPromptOmegac0/"); + fRegistry.addClone("Data/electron/", "MC/eFromNonPromptD0/"); + fRegistry.addClone("Data/electron/", "MC/eFromNonPromptDpm/"); + fRegistry.addClone("Data/electron/", "MC/eFromNonPromptDs/"); + fRegistry.addClone("Data/electron/", "MC/eFromNonPromptLcpm/"); + fRegistry.addClone("Data/electron/", "MC/eFromNonPromptXic0/"); + // fRegistry.addClone("Data/electron/", "MC/eFromNonPromptXicpm/"); // cannot be detected + fRegistry.addClone("Data/electron/", "MC/eFromNonPromptOmegac0/"); + fRegistry.addClone("Data/electron/", "MC/eFromB0/"); + fRegistry.addClone("Data/electron/", "MC/eFromBpm/"); + fRegistry.addClone("Data/electron/", "MC/eFromBs/"); + fRegistry.addClone("Data/electron/", "MC/eFromBc/"); + fRegistry.addClone("Data/electron/", "MC/eFromLb0/"); + + // for V0 (Lambda) + fRegistry.add("Data/V0/hPt", "pT of V0;p_{T} (GeV/c)", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Data/V0/hYPhi", "rapidity vs. #varphi of V0;#varphi (rad.);rapidity_{#Lambda}", kTH2F, {{90, 0, 2 * M_PI}, {80, -2, +2}}, false); + fRegistry.add("Data/V0/hAP", "Ap plot;#alpha;q_{T} (GeV/c)", kTH2F, {{200, -1, 1}, {250, 0, 0.25}}, false); + fRegistry.add("Data/V0/hLxy", "decay length from PV;L_{xy} (cm)", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Data/V0/hCosPA", "cosPA;cosine of pointing angle", kTH1F, {{200, -1, 1}}, false); + fRegistry.add("Data/V0/hDCA2Legs", "distance between 2 legs at PCA;distance between 2 legs (cm)", kTH1F, {{100, 0, 1}}, false); + fRegistry.add("Data/V0/hMassK0S", "K0S mass;m_{#pi#pi} (GeV/c^{2})", kTH1F, {{100, 0.45, 0.55}}, false); + fRegistry.add("Data/V0/hMassLambda", "Lambda mass;m_{p#pi^{-}} (GeV/c^{2})", kTH1F, {{100, 1.08, 1.18}}, false); + fRegistry.add("Data/V0/hMassAntiLambda", "Anti-Lambda mass;m_{#bar{p}#pi^{+}} (GeV/c^{2})", kTH1F, {{100, 1.08, 1.18}}, false); + + // for cascade + fRegistry.add("Data/Cascade/hPt", "pT of V0;p_{T} (GeV/c)", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Data/Cascade/hYPhi", "rapidity vs. #varphi of V0;#varphi (rad.);rapidity_{#Lambda}", kTH2F, {{90, 0, 2 * M_PI}, {80, -2, +2}}, false); + fRegistry.add("Data/Cascade/hCosPA", "cosPA;cosine of pointing angle", kTH1F, {{200, -1, 1}}, false); + fRegistry.add("Data/Cascade/hDCA2Legs", "distance between 2 legs at PCA;distance between 2 legs (cm)", kTH1F, {{100, 0, 1}}, false); + fRegistry.add("Data/Cascade/hV0CosPA", "cosPA of V0 in cascade;cosine of pointing angle", kTH1F, {{100, 0.99, 1}}, false); + fRegistry.add("Data/Cascade/hV0DCA2Legs", "distance between 2 legs at PCA of V0 in cascade;distance between 2 legs (cm)", kTH1F, {{100, 0, 1}}, false); + + fRegistry.add("Data/Cascade/hMassLambda", "Lambda mass;m_{p#pi^{-}} (GeV/c^{2})", kTH1F, {{100, 1.08, 1.18}}, false); + fRegistry.add("Data/Cascade/hMassXi", "#Xi mass;m_{#Lambda#pi} (GeV/c^{2})", kTH1F, {{100, 1.27, 1.37}}, false); + fRegistry.add("Data/Cascade/hMassOmega", "#Omega mass;m_{#LambdaK} (GeV/c^{2})", kTH1F, {{100, 1.62, 1.72}}, false); + + // for e-L pair + fRegistry.add("Data/eL/RS/hs", "hs;m_{e#Lambda} (GeV/c^{2});p_{T,e} (GeV/c);DCA_{e}^{3D} (#sigma);L_{xy} (cm);", kTHnSparseF, {{20, 1.1, 3.1}, {100, 0, 10}, {100, 0, 10}, {100, 0, 1.0}}, false); + fRegistry.add("Data/eL/RS/hCosPA", "cos PA;cosPA", kTH1F, {{200, -1, 1}}, false); + fRegistry.add("Data/eL/RS/hDCA2Legs", "distance between 2 legs at PCA;distance between 2 legs at PCA (cm)", kTH1F, {{500, 0.0, 0.5}}, false); + fRegistry.add("Data/eL/RS/hLxy", "distance between PV and SV in XY;L_{xy} (cm)", kTH1F, {{100, 0.0, 1}}, false); + fRegistry.add("Data/eL/RS/hLz", "distance between PV and SV in Z;L_{z} (cm)", kTH1F, {{100, 0.0, 1}}, false); + fRegistry.addClone("Data/eL/RS/", "Data/eL/WS/"); // right and wrong sign + fRegistry.addClone("Data/eL/RS/", "MC/eLfromPromptLcpm/"); + fRegistry.addClone("Data/eL/RS/", "MC/eLfromNonPromptLcpm/"); + + // for e-Xi pair + fRegistry.add("Data/eXi/RS/hs", "hs;m_{e#Xi} (GeV/c^{2});p_{T,e} (GeV/c);DCA_{e}^{3D} (#sigma);L_{xy} (cm);", kTHnSparseF, {{20, 1.3, 3.3}, {100, 0, 10}, {100, 0, 10}, {100, 0, 1.0}}, false); + fRegistry.add("Data/eXi/RS/hCosPA", "cos PA;cosPA", kTH1F, {{200, -1, 1}}, false); + fRegistry.add("Data/eXi/RS/hDCA2Legs", "distance between 2 legs at PCA;distance between 2 legs at PCA (cm)", kTH1F, {{500, 0.0, 0.5}}, false); + fRegistry.add("Data/eXi/RS/hLxy", "distance between PV and SV in XY;L_{xy} (cm)", kTH1F, {{100, 0.0, 1}}, false); + fRegistry.add("Data/eXi/RS/hLz", "distance between PV and SV in Z;L_{z} (cm)", kTH1F, {{100, 0.0, 1}}, false); + fRegistry.addClone("Data/eXi/RS/", "Data/eXi/WS/"); // right and wrong sign + fRegistry.addClone("Data/eXi/RS/", "MC/eXifromPromptXic0/"); + fRegistry.addClone("Data/eXi/RS/", "MC/eXifromNonPromptXic0/"); + + // for e-Omega pair + fRegistry.add("Data/eOmega/RS/hs", "hs;m_{e#Omega} (GeV/c^{2});p_{T,e} (GeV/c);DCA_{e}^{3D} (#sigma);L_{xy} (cm);", kTHnSparseF, {{20, 1.6, 3.6}, {100, 0, 10}, {100, 0, 10}, {100, 0, 1.0}}, false); + fRegistry.add("Data/eOmega/RS/hCosPA", "cos PA;cosPA", kTH1F, {{200, -1, 1}}, false); + fRegistry.add("Data/eOmega/RS/hDCA2Legs", "distance between 2 legs at PCA;distance between 2 legs at PCA (cm)", kTH1F, {{500, 0.0, 0.5}}, false); + fRegistry.add("Data/eOmega/RS/hLxy", "distance between PV and SV in XY;L_{xy} (cm)", kTH1F, {{100, 0.0, 1}}, false); + fRegistry.add("Data/eOmega/RS/hLz", "distance between PV and SV in Z;L_{z} (cm)", kTH1F, {{100, 0.0, 1}}, false); + fRegistry.addClone("Data/eOmega/RS/", "Data/eOmega/WS/"); // right and wrong sign + fRegistry.addClone("Data/eOmega/RS/", "MC/eOmegafromPromptOmegac0/"); + fRegistry.addClone("Data/eOmega/RS/", "MC/eOmegafromNonPromptOmegac0/"); + } + + template + bool isKaon(TTrack const& track) + { + // TOFif + bool is_ka_included_TPC = kaoncut.cfg_min_TPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < kaoncut.cfg_max_TPCNsigmaKa; + bool is_ka_included_TOF = track.hasTOF() ? (kaoncut.cfg_min_TOFNsigmaKa < track.tofNSigmaKa() && track.tofNSigmaKa() < kaoncut.cfg_max_TOFNsigmaKa) : true; + return is_ka_included_TPC && is_ka_included_TOF; + } + + template + bool isPion(TTrack const& track) + { + // TOFif + bool is_pi_included_TPC = v0cut.cfg_min_TPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < v0cut.cfg_max_TPCNsigmaPi; + bool is_pi_included_TOF = track.hasTOF() ? (v0cut.cfg_min_TOFNsigmaPi < track.tofNSigmaPi() && track.tofNSigmaPi() < v0cut.cfg_max_TOFNsigmaPi) : true; + return is_pi_included_TPC && is_pi_included_TOF; + } + + template + bool isProton(TTrack const& track) + { + // TOFif + bool is_pr_included_TPC = v0cut.cfg_min_TPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < v0cut.cfg_max_TPCNsigmaPr; + bool is_pr_included_TOF = track.hasTOF() ? (v0cut.cfg_min_TOFNsigmaPr < track.tofNSigmaPr() && track.tofNSigmaPr() < v0cut.cfg_max_TOFNsigmaPr) : true; + return is_pr_included_TPC && is_pr_included_TOF; + } + + template + bool isElectron(TTrack const& track) + { + // TOFif + bool is_el_included_TPC = electroncut.cfg_min_TPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < electroncut.cfg_max_TPCNsigmaEl; + bool is_el_included_TOF = track.hasTOF() ? (electroncut.cfg_min_TOFNsigmaEl < track.tofNSigmaEl() && track.tofNSigmaEl() < electroncut.cfg_max_TOFNsigmaEl) : true; + return is_el_included_TPC && is_el_included_TOF; + } + + template + bool isSelectedElectron(TTrack const& track, TTrackParCov const& trackParCov, const float dcaXY, const float dcaZ) + { + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + + if (trackParCov.getPt() < electroncut.cfg_min_pt_track || electroncut.cfg_max_pt_track < trackParCov.getPt()) { + return false; + } + + if (trackParCov.getEta() < electroncut.cfg_min_eta_track || electroncut.cfg_max_eta_track < trackParCov.getEta()) { + return false; + } + + if (std::fabs(dcaXY) > electroncut.cfg_max_dcaxy) { + return false; + } + + if (std::fabs(dcaZ) > electroncut.cfg_max_dcaz) { + return false; + } + + if (track.itsChi2NCl() < 0.f || electroncut.cfg_max_chi2its < track.itsChi2NCl()) { + return false; + } + + if (track.itsNCls() < electroncut.cfg_min_ncluster_its) { + return false; + } + + if (track.itsNClsInnerBarrel() < electroncut.cfg_min_ncluster_itsib) { + return false; + } + + if (track.tpcChi2NCl() < 0.f || electroncut.cfg_max_chi2tpc < track.tpcChi2NCl()) { + return false; + } + + if (track.tpcNClsFound() < electroncut.cfg_min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < electroncut.cfg_min_ncrossedrows_tpc) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < electroncut.cfg_min_cr2findable_ratio_tpc) { + return false; + } + + if (track.tpcFractionSharedCls() > electroncut.cfg_max_frac_shared_clusters_tpc) { + return false; + } + + if (!isElectron(track)) { + return false; + } + + return true; + } + + template + bool isSelectedElectronLoose(TTrack const& track, TTrackParCov const& trackParCov, const float dcaXY, const float dcaZ) + { + if (!track.hasITS()) { + return false; + } + + if (trackParCov.getPt() < loose_electroncut.cfg_min_pt_track || loose_electroncut.cfg_max_pt_track < trackParCov.getPt()) { + return false; + } + + if (trackParCov.getEta() < loose_electroncut.cfg_min_eta_track || loose_electroncut.cfg_max_eta_track < trackParCov.getEta()) { + return false; + } + + if (std::fabs(dcaXY) > loose_electroncut.cfg_max_dcaxy) { + return false; + } + + if (std::fabs(dcaZ) > loose_electroncut.cfg_max_dcaz) { + return false; + } + + if (loose_electroncut.cfg_max_chi2its < track.itsChi2NCl()) { + return false; + } + + if (track.itsNCls() < loose_electroncut.cfg_min_ncluster_its) { + return false; + } + + if (track.itsNClsInnerBarrel() < loose_electroncut.cfg_min_ncluster_itsib) { + return false; + } + + if (track.hasTPC()) { + if (loose_electroncut.cfg_max_chi2tpc < track.tpcChi2NCl()) { + return false; + } + + if (track.tpcNClsFound() < loose_electroncut.cfg_min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < loose_electroncut.cfg_min_ncrossedrows_tpc) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < loose_electroncut.cfg_min_cr2findable_ratio_tpc) { + return false; + } + + if (track.tpcFractionSharedCls() > loose_electroncut.cfg_max_frac_shared_clusters_tpc) { + return false; + } + + if (!isElectron(track)) { + return false; + } + } + + return true; + } + + template + bool isLambda(TV0 const& v0) + { + return (v0cut.cfg_min_mass_lambda < v0.mLambda() && v0.mLambda() < v0cut.cfg_max_mass_lambda) && (v0.mK0Short() < v0cut.cfg_min_mass_k0s_veto || v0cut.cfg_max_mass_k0s_veto < v0.mK0Short()); + } + + template + bool isAntiLambda(TV0 const& v0) + { + return (v0cut.cfg_min_mass_lambda < v0.mAntiLambda() && v0.mAntiLambda() < v0cut.cfg_max_mass_lambda) && (v0.mK0Short() < v0cut.cfg_min_mass_k0s_veto || v0cut.cfg_max_mass_k0s_veto < v0.mK0Short()); + } + + template + bool isXi(TCascade const& cascade) + { + return (cascadecut.cfg_min_mass_Xi < cascade.mXi() && cascade.mXi() < cascadecut.cfg_max_mass_Xi) && (cascade.mOmega() < cascadecut.cfg_min_mass_Omega_veto || cascadecut.cfg_max_mass_Omega_veto < cascade.mOmega()); + } + + template + bool isOmega(TCascade const& cascade) + { + return (cascadecut.cfg_min_mass_Omega < cascade.mOmega() && cascade.mOmega() < cascadecut.cfg_max_mass_Omega) && (cascade.mXi() < cascadecut.cfg_min_mass_Xi || cascadecut.cfg_max_mass_Xi < cascade.mXi()); + } + + template + bool isSelectedV0Leg(TTrack const& track) + { + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + + if (track.itsChi2NCl() > v0cut.cfg_max_chi2its) { + return false; + } + + if (track.itsNCls() < v0cut.cfg_min_ncluster_its) { + return false; + } + + if (track.itsNClsInnerBarrel() < v0cut.cfg_min_ncluster_itsib) { + return false; + } + + if (track.tpcChi2NCl() > v0cut.cfg_max_chi2tpc) { + return false; + } + + if (track.tpcNClsFound() < v0cut.cfg_min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < v0cut.cfg_min_ncrossedrows_tpc) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < v0cut.cfg_min_cr2findable_ratio_tpc) { + return false; + } + + if (track.tpcFractionSharedCls() > v0cut.cfg_max_frac_shared_clusters_tpc) { + return false; + } + + return true; + } + + 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 fillV0Histograms(TV0 const& v0) + { + fRegistry.fill(HIST("Data/V0/hPt"), v0.pt()); + fRegistry.fill(HIST("Data/V0/hYPhi"), v0.phi(), v0.yLambda()); + fRegistry.fill(HIST("Data/V0/hAP"), v0.alpha(), v0.qtarm()); + fRegistry.fill(HIST("Data/V0/hCosPA"), v0.v0cosPA()); + fRegistry.fill(HIST("Data/V0/hLxy"), v0.v0radius()); + fRegistry.fill(HIST("Data/V0/hDCA2Legs"), v0.dcaV0daughters()); + fRegistry.fill(HIST("Data/V0/hMassK0S"), v0.mK0Short()); + fRegistry.fill(HIST("Data/V0/hMassLambda"), v0.mLambda()); + fRegistry.fill(HIST("Data/V0/hMassAntiLambda"), v0.mAntiLambda()); + } + + template + void fillCascadeHistograms(TCollision const& collision, TCascade const& cascade) + { + fRegistry.fill(HIST("Data/Cascade/hPt"), cascade.pt()); + fRegistry.fill(HIST("Data/Cascade/hMassLambda"), cascade.mLambda()); + fRegistry.fill(HIST("Data/Cascade/hCosPA"), cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + fRegistry.fill(HIST("Data/Cascade/hDCA2Legs"), cascade.dcacascdaughters()); + fRegistry.fill(HIST("Data/Cascade/hV0CosPA"), cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + fRegistry.fill(HIST("Data/Cascade/hV0DCA2Legs"), cascade.dcaV0daughters()); + fRegistry.fill(HIST("Data/Cascade/hMassXi"), cascade.mXi()); + fRegistry.fill(HIST("Data/Cascade/hMassOmega"), cascade.mOmega()); + } + + template + void fillElectronHistograms(TTrack const& track, TMCParticles const& mcParticles) + { + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + float dca3DinSigma = dca3DinSigmaOTF(dcaXY, dcaZ, trackParCov.getSigmaY2(), trackParCov.getSigmaZ2(), trackParCov.getSigmaZY()); + + if (!isSelectedElectron(track, trackParCov, dcaXY, dcaZ)) { + return; + } + fRegistry.fill(HIST("Data/electron/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + + if constexpr (isMC) { + const auto& mctrack = track.template mcParticle_as(); + if (std::abs(mctrack.pdgCode()) != 11) { + return; + } + if (!(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + return; + } + const auto& mcmother = mctrack.template mothers_first_as(); // mother particle of electron + int pdg_mother = std::abs(mcmother.pdgCode()); + + if (pdg_mother == 111 || pdg_mother == 221 || pdg_mother == 331 || pdg_mother == 113 || pdg_mother == 223 || pdg_mother == 333) { // LF + if (IsFromCharm(mcmother, mcParticles) < 0 && IsFromBeauty(mcmother, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eFromPromptLF/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else { + fRegistry.fill(HIST("MC/eFromNonPromptLF/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } else if (pdg_mother == 443) { // Jpsi + if (IsFromBeauty(mcmother, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eFromPromptJpsi/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else { + fRegistry.fill(HIST("MC/eFromNonPromptJpsi/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } else if (pdg_mother == 411) { // D+/- + if (IsFromBeauty(mcmother, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eFromPromptDpm/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else { + fRegistry.fill(HIST("MC/eFromNonPromptDpm/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } else if (pdg_mother == 421) { // D0 + if (IsFromBeauty(mcmother, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eFromPromptD0/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else { + fRegistry.fill(HIST("MC/eFromNonPromptD0/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } else if (pdg_mother == 431) { // Ds+/- + if (IsFromBeauty(mcmother, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eFromPromptDs/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else { + fRegistry.fill(HIST("MC/eFromNonPromptDs/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } else if (pdg_mother == 4122) { // Lc+/- + if (IsFromBeauty(mcmother, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eFromPromptLcpm/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else { + fRegistry.fill(HIST("MC/eFromNonPromptLcpm/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } else if (pdg_mother == 4132) { // Xic0 + if (IsFromBeauty(mcmother, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eFromPromptXic0/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else { + fRegistry.fill(HIST("MC/eFromNonPromptXic0/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } else if (pdg_mother == 4332) { // Omegac0 + if (IsFromBeauty(mcmother, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eFromPromptOmegac0/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else { + fRegistry.fill(HIST("MC/eFromNonPromptOmegac0/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } else if (pdg_mother == 511) { // B0 + fRegistry.fill(HIST("MC/eFromB0/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else if (pdg_mother == 521) { // B+/- + fRegistry.fill(HIST("MC/eFromBpm/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else if (pdg_mother == 531) { // Bs0 + fRegistry.fill(HIST("MC/eFromBs/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else if (pdg_mother == 541) { // Bc+/- + fRegistry.fill(HIST("MC/eFromBc/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } else if (pdg_mother == 5122) { // Lb0 + fRegistry.fill(HIST("MC/eFromLb0/hs"), trackParCov.getPt(), trackParCov.getEta(), trackParCov.getPhi(), dca3DinSigma); + } + } + } + + float dca3DinSigmaOTF(const float dcaXY, const float dcaZ, const float cYY, const float cZZ, const float cZY) + { + 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 + bool isSemiLeptonic(TMCParticle const& mcParticle, TMCParticles const& mcParticles) + { + if (!mcParticle.has_daughters()) { + return false; + } + bool is_lepton_involved = false; + bool is_neutrino_involved = false; + for (int d = mcParticle.daughtersIds()[0]; d <= mcParticle.daughtersIds()[1]; ++d) { + if (d < mcParticles.size()) { // protect against bad daughter indices + const auto& daughter = mcParticles.rawIteratorAt(d); + if (daughter.pdgCode() == pdgLepton) { + is_lepton_involved = true; + } else if (daughter.pdgCode() == pdgNeutrino) { + is_neutrino_involved = true; + } + } else { + std::cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcParticles.size() << ")" << std::endl; + std::cout << " Check the MC generator" << std::endl; + return false; + } + } + + if (is_lepton_involved && is_neutrino_involved) { + return true; + } else { + return false; + } + } + + template + EBPair makeELPair(TCollision const& collision, TTrack const& track, TV0 const& v0) + { + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + float dca3DinSigma = dca3DinSigmaOTF(dcaXY, dcaZ, trackParCov.getSigmaY2(), trackParCov.getSigmaZ2(), trackParCov.getSigmaZY()); + + EBPair eLpair; + eLpair.ptepv = trackParCov.getPt(); + eLpair.dca3dinsigma = dca3DinSigma; + + const std::array vertex = {collision.posX(), collision.posY(), collision.posZ()}; + const std::array vertexV0 = {v0.x(), v0.y(), v0.z()}; + const std::array momV0 = {v0.px(), v0.py(), v0.pz()}; + std::array covV0 = {0.f}; + + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + covV0[MomInd[i]] = v0.momentumCovMat()[i]; + covV0[i] = v0.positionCovMat()[i]; + } + + auto v0ParCov = o2::track::TrackParCov(vertexV0, momV0, covV0, 0, true); + v0ParCov.setAbsCharge(0); + v0ParCov.setPID(o2::track::PID::Lambda); + + std::array svpos = {0.}; // secondary vertex position + std::array pvec0 = {0.}; + std::array pvec1 = {0.}; + + int nCand = 0; + try { + nCand = fitter.process(trackParCov, v0ParCov); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + return eLpair; + } + if (nCand == 0) { + return eLpair; + } + + fitter.propagateTracksToVertex(); // propagate e and K to D vertex + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + svpos[i] = vtx[i]; + } + fitter.getTrack(0).getPxPyPzGlo(pvec0); // electron + fitter.getTrack(1).getPxPyPzGlo(pvec1); // v0 + std::array pvecSum = {pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}; + + float cospa = RecoDecay::cpa(vertex, svpos, pvecSum); + float dca2legs = std::sqrt(fitter.getChi2AtPCACandidate()); + float lxy = std::sqrt(std::pow(svpos[0] - collision.posX(), 2) + std::pow(svpos[1] - collision.posY(), 2)); + float lz = std::fabs(svpos[2] - collision.posZ()); + ROOT::Math::PxPyPzMVector v1(pvec0[0], pvec0[1], pvec0[2], o2::constants::physics::MassElectron); + ROOT::Math::PxPyPzMVector v2(pvec1[0], pvec1[1], pvec1[2], o2::constants::physics::MassLambda); + ROOT::Math::PxPyPzMVector v12 = v1 + v2; + + eLpair.mass = v12.M(); + eLpair.dca2legs = dca2legs; + eLpair.cospa = cospa; + eLpair.lxy = lxy; + eLpair.lz = lz; + return eLpair; + } + + template + EBPair makeECascadePair(TCollision const& collision, TTrack const& track, TCascade const& cascade) + { + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + float dca3DinSigma = dca3DinSigmaOTF(dcaXY, dcaZ, trackParCov.getSigmaY2(), trackParCov.getSigmaZ2(), trackParCov.getSigmaZY()); + + EBPair eCascPair; + eCascPair.ptepv = trackParCov.getPt(); + eCascPair.dca3dinsigma = dca3DinSigma; + + const std::array vertex = {collision.posX(), collision.posY(), collision.posZ()}; + const std::array vertexCasc = {cascade.x(), cascade.y(), cascade.z()}; + const std::array momCasc = {cascade.px(), cascade.py(), cascade.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]] = cascade.momentumCovMat()[i]; + covCasc[i] = cascade.positionCovMat()[i]; + } + + auto cascParCov = o2::track::TrackParCov(vertexCasc, momCasc, covCasc, cascade.sign(), true); + cascParCov.setAbsCharge(1); + if constexpr (cascType == 0) { + cascParCov.setPID(o2::track::PID::XiMinus); + } else if constexpr (cascType == 1) { + cascParCov.setPID(o2::track::PID::OmegaMinus); + } + std::array svpos = {0.}; // secondary vertex position + std::array pvec0 = {0.}; + std::array pvec1 = {0.}; + + int nCand = 0; + try { + nCand = fitter.process(trackParCov, cascParCov); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + return eCascPair; + } + if (nCand == 0) { + return eCascPair; + } + + fitter.propagateTracksToVertex(); // propagate e and Xi/Omega to decay vertex of charm baryon + const auto& vtx = fitter.getPCACandidate(); + for (int i = 0; i < 3; i++) { + svpos[i] = vtx[i]; + } + fitter.getTrack(0).getPxPyPzGlo(pvec0); // electron + fitter.getTrack(1).getPxPyPzGlo(pvec1); // v0 + std::array pvecSum = {pvec0[0] + pvec1[0], pvec0[1] + pvec1[1], pvec0[2] + pvec1[2]}; + + float cospa = RecoDecay::cpa(vertex, svpos, pvecSum); + float dca2legs = std::sqrt(fitter.getChi2AtPCACandidate()); + float lxy = std::sqrt(std::pow(svpos[0] - collision.posX(), 2) + std::pow(svpos[1] - collision.posY(), 2)); + float lz = std::fabs(svpos[2] - collision.posZ()); + ROOT::Math::PxPyPzMVector v1(pvec0[0], pvec0[1], pvec0[2], o2::constants::physics::MassElectron); + ROOT::Math::PxPyPzMVector v2(pvec1[0], pvec1[1], pvec1[2], o2::constants::physics::MassXiMinus); + if constexpr (cascType == 0) { + v2.SetM(o2::constants::physics::MassXiMinus); + } else if constexpr (cascType == 1) { + v2.SetM(o2::constants::physics::MassOmegaMinus); + } + ROOT::Math::PxPyPzMVector v12 = v1 + v2; + + eCascPair.mass = v12.M(); + eCascPair.dca2legs = dca2legs; + eCascPair.cospa = cospa; + eCascPair.lxy = lxy; + eCascPair.lz = lz; + return eCascPair; + } + + template + void runPairing(TBCs const&, TCollisions const& collisions, TTracks const& tracks, TTrackAssoc const& trackIndices, TV0s const& v0s, TCascades const& cascades, TMCCollisions const&, TMCParticles const& mcParticles) + { + used_electronIds.reserve(tracks.size()); + + for (const auto& collision : collisions) { + const auto& bc = collision.template foundBC_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[eventcut.cfgCentEstimator] < eventcut.cfgCentMin || eventcut.cfgCentMax < centralities[eventcut.cfgCentEstimator]) { + continue; + } + fRegistry.fill(HIST("Event/hCollisionCounter"), 1); + const auto& mcCollision = collision.template mcCollision_as(); + if (eventcut.cfgEventGeneratorType < 0 || mcCollision.getSubGeneratorId() == eventcut.cfgEventGeneratorType) { + fillEventHistograms(collision); + } + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + + const auto& trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + electronIds.reserve(trackIdsThisCollision.size()); + positronIds.reserve(trackIdsThisCollision.size()); + + for (const auto& trackId : trackIdsThisCollision) { + const auto& track = trackId.template track_as(); + if (!track.hasITS() || !track.hasTPC()) { + continue; + } + + if constexpr (isMC) { + if (!track.has_mcParticle()) { + continue; + } + const auto& mctrack = track.template mcParticle_as(); + const auto& mcCollision = mctrack.template mcCollision_as(); + if (eventcut.cfgEventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventcut.cfgEventGeneratorType) { + continue; + } + if (!mctrack.has_mothers() || !(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + continue; + } + + fillElectronHistograms(track, mcParticles); + } + + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (isSelectedElectron(track, trackParCov, dcaXY, dcaZ)) { + if (track.sign() > 0) { // positron + positronIds.emplace_back(trackId.trackId()); + } else { // electron + electronIds.emplace_back(trackId.trackId()); + } + } + + if (isSelectedElectronLoose(track, trackParCov, dcaXY, dcaZ)) { + if (track.sign() > 0) { // positron + positronIdsLoose.emplace_back(trackId.trackId()); + } else { // electron + electronIdsLoose.emplace_back(trackId.trackId()); + } + } + } // end of track loop for electron selection + + // First, apply pi0 prefilter to imporove S/B + std::vector vec_eFromPi0; + vec_eFromPi0.reserve(electronIds.size() + positronIds.size()); + + for (const auto& positronId : positronIds) { + const auto& pos = tracks.rawIteratorAt(positronId); + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto posParCov = getTrackParCov(pos); + posParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, posParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v1(posParCov.getPt(), posParCov.getEta(), posParCov.getPhi(), o2::constants::physics::MassElectron); + + for (const auto& electronId : electronIdsLoose) { + const auto& ele = tracks.rawIteratorAt(electronId); + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto eleParCov = getTrackParCov(ele); + eleParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, eleParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v2(eleParCov.getPt(), eleParCov.getEta(), eleParCov.getPhi(), o2::constants::physics::MassElectron); + + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float mee = v12.M(); + fRegistry.fill(HIST("Prefilter/before/uls/hMee"), mee); + if (mee < cfgMeeMaxPF) { + vec_eFromPi0.emplace_back(positronId); + } + } // end of loose electron sample + } // end of main positron sample + + for (const auto& electronId : electronIds) { + const auto& ele = tracks.rawIteratorAt(electronId); + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto eleParCov = getTrackParCov(ele); + eleParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, eleParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v1(eleParCov.getPt(), eleParCov.getEta(), eleParCov.getPhi(), o2::constants::physics::MassElectron); + + for (const auto& positronId : positronIdsLoose) { + const auto& pos = tracks.rawIteratorAt(positronId); + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto posParCov = getTrackParCov(pos); + posParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, posParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v2(posParCov.getPt(), posParCov.getEta(), posParCov.getPhi(), o2::constants::physics::MassElectron); + + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float mee = v12.M(); + fRegistry.fill(HIST("Prefilter/before/uls/hMee"), mee); + if (mee < cfgMeeMaxPF) { + vec_eFromPi0.emplace_back(electronId); + } + } // end of loose positron sample + } // end of main electron sample + + for (const auto& positronId1 : positronIds) { + const auto& pos1 = tracks.rawIteratorAt(positronId1); + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto pos1ParCov = getTrackParCov(pos1); + pos1ParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, pos1ParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v1(pos1ParCov.getPt(), pos1ParCov.getEta(), pos1ParCov.getPhi(), o2::constants::physics::MassElectron); + + for (const auto& positronId2 : positronIdsLoose) { + const auto& pos2 = tracks.rawIteratorAt(positronId2); + if (positronId1 == positronId2) { + continue; + } + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto pos2ParCov = getTrackParCov(pos2); + pos2ParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, pos2ParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v2(pos2ParCov.getPt(), pos2ParCov.getEta(), pos2ParCov.getPhi(), o2::constants::physics::MassElectron); + + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float mee = v12.M(); + fRegistry.fill(HIST("Prefilter/before/lspp/hMee"), mee); + } // end of loose positron sample + } // end of main positron sample + + for (const auto& electronId1 : electronIds) { + const auto& ele1 = tracks.rawIteratorAt(electronId1); + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto ele1ParCov = getTrackParCov(ele1); + ele1ParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, ele1ParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v1(ele1ParCov.getPt(), ele1ParCov.getEta(), ele1ParCov.getPhi(), o2::constants::physics::MassElectron); + + for (const auto& electronId2 : electronIdsLoose) { + const auto& ele2 = tracks.rawIteratorAt(electronId2); + if (electronId1 == electronId2) { + continue; + } + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto ele2ParCov = getTrackParCov(ele2); + ele2ParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, ele2ParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v2(ele2ParCov.getPt(), ele2ParCov.getEta(), ele2ParCov.getPhi(), o2::constants::physics::MassElectron); + + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float mee = v12.M(); + fRegistry.fill(HIST("Prefilter/before/lsmm/hMee"), mee); + } // end of loose electron sample + } // end of main electron sample + + std::vector vec_diff_pos; + std::set_difference(positronIds.begin(), positronIds.end(), vec_eFromPi0.begin(), vec_eFromPi0.end(), std::back_inserter(vec_diff_pos)); + positronIds = vec_diff_pos; + + std::vector vec_diff_ele; + std::set_difference(electronIds.begin(), electronIds.end(), vec_eFromPi0.begin(), vec_eFromPi0.end(), std::back_inserter(vec_diff_ele)); + electronIds = vec_diff_ele; + + vec_eFromPi0.clear(); + vec_eFromPi0.shrink_to_fit(); + + for (const auto& electronId : electronIds) { + const auto& ele = tracks.rawIteratorAt(electronId); + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto eleParCov = getTrackParCov(ele); + eleParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, eleParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v1(eleParCov.getPt(), eleParCov.getEta(), eleParCov.getPhi(), o2::constants::physics::MassElectron); + + for (const auto& positronId : positronIds) { + const auto& pos = tracks.rawIteratorAt(positronId); + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto posParCov = getTrackParCov(pos); + posParCov.setPID(o2::track::PID::Electron); + o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, posParCov, 2.f, matCorr, &mDcaInfoCov); + ROOT::Math::PtEtaPhiMVector v2(posParCov.getPt(), posParCov.getEta(), posParCov.getPhi(), o2::constants::physics::MassElectron); + + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float mee = v12.M(); + fRegistry.fill(HIST("Prefilter/after/uls/hMee"), mee); + } // end of main positron sample + } // end of main electron sample + + const auto& v0s_per_coll = v0s.sliceBy(perCol_v0, collision.globalIndex()); + lambdaIds.reserve(v0s_per_coll.size()); + lambdaIds.reserve(v0s_per_coll.size()); + antilambdaIds.reserve(v0s_per_coll.size()); + antilambdaIds.reserve(v0s_per_coll.size()); + for (const auto& v0 : v0s_per_coll) { + auto pos = v0.template posTrack_as(); + auto neg = v0.template negTrack_as(); + if (!isSelectedV0Leg(pos) || !isSelectedV0Leg(neg)) { + continue; + } + fillV0Histograms(v0); + if (isLambda(v0) && isProton(pos) && isPion(neg)) { + lambdaIds.emplace_back(v0.globalIndex()); + } else if (isAntiLambda(v0) && isProton(neg) && isPion(pos)) { + antilambdaIds.emplace_back(v0.globalIndex()); + } + } // end of V0 loop + + const auto& cascades_per_coll = cascades.sliceBy(perCol_casc, collision.globalIndex()); + xiPlusIds.reserve(cascades_per_coll.size()); + xiPlusIds.reserve(cascades_per_coll.size()); + xiMinusIds.reserve(cascades_per_coll.size()); + xiMinusIds.reserve(cascades_per_coll.size()); + omegaPlusIds.reserve(cascades_per_coll.size()); + omegaPlusIds.reserve(cascades_per_coll.size()); + omegaMinusIds.reserve(cascades_per_coll.size()); + omegaMinusIds.reserve(cascades_per_coll.size()); + for (const auto& cascade : cascades_per_coll) { + auto pos = cascade.template posTrack_as(); + auto neg = cascade.template negTrack_as(); + auto bachelor = cascade.template bachelor_as(); + if (pos.sign() * neg.sign() > 0) { + continue; + } + if (cascade.mLambda() < cascadecut.cfg_min_mass_lambda || cascadecut.cfg_max_mass_lambda < cascade.mLambda()) { + continue; + } + + if (!isSelectedV0Leg(pos) || !isSelectedV0Leg(neg) || !isSelectedV0Leg(bachelor)) { + continue; + } + + if (cascade.sign() < 0) { // L-> p pi- + if (!isProton(pos) || !isPion(neg)) { + continue; + } + } else { // Lbar-> pbar pi+ + if (!isProton(neg) || !isPion(pos)) { + continue; + } + } + + if (cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadecut.cfg_min_cospa) { + continue; + } + if (cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadecut.cfg_min_cospa_v0) { + continue; + } + + fillCascadeHistograms(collision, cascade); + if (cascade.sign() < 0) { // Xi- or Omega- + if (isXi(cascade) && isPion(bachelor)) { + xiMinusIds.emplace_back(cascade.globalIndex()); + } else if (isOmega(cascade) && isKaon(bachelor)) { + omegaMinusIds.emplace_back(cascade.globalIndex()); + } + } else { // Xi+ or Omega+ + if (isXi(cascade) && isPion(bachelor)) { + xiPlusIds.emplace_back(cascade.globalIndex()); + } else if (isOmega(cascade) && isKaon(bachelor)) { + omegaPlusIds.emplace_back(cascade.globalIndex()); + } + } + } // end of cascade loop + + // Lc+ -> e+ Lambda nu_e, br = 0.0356, ctau = 60.75 um, m = 2286 MeV/c2 + for (const auto& positronId : positronIds) { + const auto& pos = tracks.rawIteratorAt(positronId); + + for (const auto& lambdaId : lambdaIds) { + const auto& lambda = v0s.rawIteratorAt(lambdaId); + const auto& eLpair = makeELPair(collision, pos, lambda); // RS + fRegistry.fill(HIST("Data/eL/RS/hs"), eLpair.mass, eLpair.ptepv, eLpair.dca3dinsigma, eLpair.lxy); + fRegistry.fill(HIST("Data/eL/RS/hCosPA"), eLpair.cospa); + fRegistry.fill(HIST("Data/eL/RS/hDCA2Legs"), eLpair.dca2legs); + fRegistry.fill(HIST("Data/eL/RS/hLxy"), eLpair.lxy); + fRegistry.fill(HIST("Data/eL/RS/hLz"), eLpair.lz); + + if constexpr (isMC) { + const auto& mcpos = pos.template mcParticle_as(); + auto posLeg = lambda.template posTrack_as(); + auto negLeg = lambda.template negTrack_as(); + const auto& mcposLeg = posLeg.template mcParticle_as(); + const auto& mcnegLeg = negLeg.template mcParticle_as(); + int mcLambdaId = FindCommonMotherFrom2Prongs(mcposLeg, mcnegLeg, 2212, -211, 3122, mcParticles); + if (mcLambdaId > 0) { // true lambda + const auto& mcLambda = mcParticles.rawIteratorAt(mcLambdaId); + int mcLambdacId = FindCommonMotherFrom2Prongs(mcpos, mcLambda, -11, 3122, 4122, mcParticles); + if (mcLambdacId > 0) { // true Lc0 + const auto& mcLambdac0 = mcParticles.rawIteratorAt(mcLambdacId); + if (IsFromBeauty(mcLambdac0, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hs"), eLpair.mass, eLpair.ptepv, eLpair.dca3dinsigma, eLpair.lxy); + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hCosPA"), eLpair.cospa); + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hDCA2Legs"), eLpair.dca2legs); + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hLxy"), eLpair.lxy); + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hLz"), eLpair.lz); + } else { + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hs"), eLpair.mass, eLpair.ptepv, eLpair.dca3dinsigma, eLpair.lxy); + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hCosPA"), eLpair.cospa); + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hDCA2Legs"), eLpair.dca2legs); + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hLxy"), eLpair.lxy); + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hLz"), eLpair.lz); + } + } + } + } // end of MC truth + } // end of Lambda loop + + for (const auto& antilambdaId : antilambdaIds) { + const auto& antilambda = v0s.rawIteratorAt(antilambdaId); + const auto& eLpair = makeELPair(collision, pos, antilambda); // WS + fRegistry.fill(HIST("Data/eL/WS/hs"), eLpair.mass, eLpair.ptepv, eLpair.dca3dinsigma, eLpair.lxy); + fRegistry.fill(HIST("Data/eL/WS/hCosPA"), eLpair.cospa); + fRegistry.fill(HIST("Data/eL/WS/hDCA2Legs"), eLpair.dca2legs); + fRegistry.fill(HIST("Data/eL/WS/hLxy"), eLpair.lxy); + fRegistry.fill(HIST("Data/eL/WS/hLz"), eLpair.lz); + } // end of AntiLambda loop + + } // end of main positron sample + + for (const auto& electronId : electronIds) { + const auto& ele = tracks.rawIteratorAt(electronId); + + for (const auto& lambdaId : lambdaIds) { + const auto& lambda = v0s.rawIteratorAt(lambdaId); + const auto& eLpair = makeELPair(collision, ele, lambda); // WS + fRegistry.fill(HIST("Data/eL/WS/hs"), eLpair.mass, eLpair.ptepv, eLpair.dca3dinsigma, eLpair.lxy); + fRegistry.fill(HIST("Data/eL/WS/hCosPA"), eLpair.cospa); + fRegistry.fill(HIST("Data/eL/WS/hDCA2Legs"), eLpair.dca2legs); + fRegistry.fill(HIST("Data/eL/WS/hLxy"), eLpair.lxy); + fRegistry.fill(HIST("Data/eL/WS/hLz"), eLpair.lz); + } // end of Lambda loop + + for (const auto& antilambdaId : antilambdaIds) { + const auto& antilambda = v0s.rawIteratorAt(antilambdaId); + const auto& eLpair = makeELPair(collision, ele, antilambda); // RS + fRegistry.fill(HIST("Data/eL/RS/hs"), eLpair.mass, eLpair.ptepv, eLpair.dca3dinsigma, eLpair.lxy); + fRegistry.fill(HIST("Data/eL/RS/hCosPA"), eLpair.cospa); + fRegistry.fill(HIST("Data/eL/RS/hDCA2Legs"), eLpair.dca2legs); + fRegistry.fill(HIST("Data/eL/RS/hLxy"), eLpair.lxy); + fRegistry.fill(HIST("Data/eL/RS/hLz"), eLpair.lz); + + if constexpr (isMC) { + const auto& mcele = ele.template mcParticle_as(); + auto posLeg = antilambda.template posTrack_as(); + auto negLeg = antilambda.template negTrack_as(); + const auto& mcposLeg = posLeg.template mcParticle_as(); + const auto& mcnegLeg = negLeg.template mcParticle_as(); + int mcLambdaId = FindCommonMotherFrom2Prongs(mcposLeg, mcnegLeg, 221, -2212, -3122, mcParticles); + if (mcLambdaId > 0) { // true lambda + const auto& mcLambda = mcParticles.rawIteratorAt(mcLambdaId); + int mcLambdacId = FindCommonMotherFrom2Prongs(mcele, mcLambda, 11, -3122, -4122, mcParticles); + if (mcLambdacId > 0) { // true Lc0 + const auto& mcLambdac0 = mcParticles.rawIteratorAt(mcLambdacId); + if (IsFromBeauty(mcLambdac0, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hs"), eLpair.mass, eLpair.ptepv, eLpair.dca3dinsigma, eLpair.lxy); + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hCosPA"), eLpair.cospa); + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hDCA2Legs"), eLpair.dca2legs); + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hLxy"), eLpair.lxy); + fRegistry.fill(HIST("MC/eLfromPromptLcpm/hLz"), eLpair.lz); + } else { + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hs"), eLpair.mass, eLpair.ptepv, eLpair.dca3dinsigma, eLpair.lxy); + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hCosPA"), eLpair.cospa); + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hDCA2Legs"), eLpair.dca2legs); + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hLxy"), eLpair.lxy); + fRegistry.fill(HIST("MC/eLfromNonPromptLcpm/hLz"), eLpair.lz); + } + } + } + } // end of MC truth + + } // end of AntiLambda loop + + } // end of main electron sample + + // Xic0 -> e+ Xi- nu_e, br = 0.0105, ctau = 45.1 um, m = 2470 MeV/c2 + for (const auto& positronId : positronIds) { + const auto& pos = tracks.rawIteratorAt(positronId); + + for (const auto& xiMinusId : xiMinusIds) { + const auto& xiMinus = cascades.rawIteratorAt(xiMinusId); + const auto& eXipair = makeECascadePair<0>(collision, pos, xiMinus); // RS + fRegistry.fill(HIST("Data/eXi/RS/hs"), eXipair.mass, eXipair.ptepv, eXipair.dca3dinsigma, eXipair.lxy); + fRegistry.fill(HIST("Data/eXi/RS/hCosPA"), eXipair.cospa); + fRegistry.fill(HIST("Data/eXi/RS/hDCA2Legs"), eXipair.dca2legs); + fRegistry.fill(HIST("Data/eXi/RS/hLxy"), eXipair.lxy); + fRegistry.fill(HIST("Data/eXi/RS/hLz"), eXipair.lz); + + if constexpr (isMC) { + const auto& mcpos = pos.template mcParticle_as(); + auto posLeg = xiMinus.template posTrack_as(); + auto negLeg = xiMinus.template negTrack_as(); + auto bachelor = xiMinus.template bachelor_as(); + const auto& mcposLeg = posLeg.template mcParticle_as(); + const auto& mcnegLeg = negLeg.template mcParticle_as(); + const auto& mcbachelor = bachelor.template mcParticle_as(); + int mcLambdaId = FindCommonMotherFrom2Prongs(mcposLeg, mcnegLeg, 2212, -211, 3122, mcParticles); + if (mcLambdaId > 0) { // true Lambda + const auto& mcLambda = mcParticles.rawIteratorAt(mcLambdaId); + int mcXiId = FindCommonMotherFrom2Prongs(mcLambda, mcbachelor, 3122, -211, 3312, mcParticles); + if (mcXiId > 0) { // true xiMinus + const auto& mcXi = mcParticles.rawIteratorAt(mcXiId); + int mcXic0Id = FindCommonMotherFrom2Prongs(mcpos, mcXi, -11, 3312, 4132, mcParticles); + if (mcXic0Id > 0) { // true Xic0 + const auto& mcXic0 = mcParticles.rawIteratorAt(mcXic0Id); + if (IsFromBeauty(mcXic0, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eXifromPromptXic0/hs"), eXipair.mass, eXipair.ptepv, eXipair.dca3dinsigma, eXipair.lxy); + fRegistry.fill(HIST("MC/eXifromPromptXic0/hCosPA"), eXipair.cospa); + fRegistry.fill(HIST("MC/eXifromPromptXic0/hDCA2Legs"), eXipair.dca2legs); + fRegistry.fill(HIST("MC/eXifromPromptXic0/hLxy"), eXipair.lxy); + fRegistry.fill(HIST("MC/eXifromPromptXic0/hLz"), eXipair.lz); + } else { + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hs"), eXipair.mass, eXipair.ptepv, eXipair.dca3dinsigma, eXipair.lxy); + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hCosPA"), eXipair.cospa); + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hDCA2Legs"), eXipair.dca2legs); + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hLxy"), eXipair.lxy); + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hLz"), eXipair.lz); + } + } + } + } + } // end of MC truth + } // end of Lambda loop + + for (const auto& xiPlusId : xiPlusIds) { + const auto& xiPlus = cascades.rawIteratorAt(xiPlusId); + const auto& eXipair = makeECascadePair<0>(collision, pos, xiPlus); // WS + fRegistry.fill(HIST("Data/eXi/WS/hs"), eXipair.mass, eXipair.ptepv, eXipair.dca3dinsigma, eXipair.lxy); + fRegistry.fill(HIST("Data/eXi/WS/hCosPA"), eXipair.cospa); + fRegistry.fill(HIST("Data/eXi/WS/hDCA2Legs"), eXipair.dca2legs); + fRegistry.fill(HIST("Data/eXi/WS/hLxy"), eXipair.lxy); + fRegistry.fill(HIST("Data/eXi/WS/hLz"), eXipair.lz); + } // end of AntiLambda loop + } // end of main positron sample + + for (const auto& electronId : electronIds) { + const auto& ele = tracks.rawIteratorAt(electronId); + + for (const auto& xiMinusId : xiMinusIds) { + const auto& xiMinus = cascades.rawIteratorAt(xiMinusId); + const auto& eXipair = makeECascadePair<0>(collision, ele, xiMinus); // WS + fRegistry.fill(HIST("Data/eXi/WS/hs"), eXipair.mass, eXipair.ptepv, eXipair.dca3dinsigma, eXipair.lxy); + fRegistry.fill(HIST("Data/eXi/WS/hCosPA"), eXipair.cospa); + fRegistry.fill(HIST("Data/eXi/WS/hDCA2Legs"), eXipair.dca2legs); + fRegistry.fill(HIST("Data/eXi/WS/hLxy"), eXipair.lxy); + fRegistry.fill(HIST("Data/eXi/WS/hLz"), eXipair.lz); + + } // end of Xi- loop + + for (const auto& xiPlusId : xiPlusIds) { + const auto& xiPlus = cascades.rawIteratorAt(xiPlusId); + const auto& eXipair = makeECascadePair<0>(collision, ele, xiPlus); // RS + fRegistry.fill(HIST("Data/eXi/RS/hs"), eXipair.mass, eXipair.ptepv, eXipair.dca3dinsigma, eXipair.lxy); + fRegistry.fill(HIST("Data/eXi/RS/hCosPA"), eXipair.cospa); + fRegistry.fill(HIST("Data/eXi/RS/hDCA2Legs"), eXipair.dca2legs); + fRegistry.fill(HIST("Data/eXi/RS/hLxy"), eXipair.lxy); + fRegistry.fill(HIST("Data/eXi/RS/hLz"), eXipair.lz); + + if constexpr (isMC) { + const auto& mcele = ele.template mcParticle_as(); + auto posLeg = xiPlus.template posTrack_as(); + auto negLeg = xiPlus.template negTrack_as(); + auto bachelor = xiPlus.template bachelor_as(); + const auto& mcposLeg = posLeg.template mcParticle_as(); + const auto& mcnegLeg = negLeg.template mcParticle_as(); + const auto& mcbachelor = bachelor.template mcParticle_as(); + int mcLambdaId = FindCommonMotherFrom2Prongs(mcposLeg, mcnegLeg, 211, -2212, -3122, mcParticles); + if (mcLambdaId > 0) { // true AntiLambda + const auto& mcLambda = mcParticles.rawIteratorAt(mcLambdaId); + int mcXiId = FindCommonMotherFrom2Prongs(mcLambda, mcbachelor, -3122, 211, -3312, mcParticles); + if (mcXiId > 0) { // true xiPlus + const auto& mcXi = mcParticles.rawIteratorAt(mcXiId); + int mcXic0Id = FindCommonMotherFrom2Prongs(mcele, mcXi, 11, -3312, 4132, mcParticles); + if (mcXic0Id > 0) { // true Xic0 + const auto& mcXic0 = mcParticles.rawIteratorAt(mcXic0Id); + if (IsFromBeauty(mcXic0, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eXifromPromptXic0/hs"), eXipair.mass, eXipair.ptepv, eXipair.dca3dinsigma, eXipair.lxy); + fRegistry.fill(HIST("MC/eXifromPromptXic0/hCosPA"), eXipair.cospa); + fRegistry.fill(HIST("MC/eXifromPromptXic0/hDCA2Legs"), eXipair.dca2legs); + fRegistry.fill(HIST("MC/eXifromPromptXic0/hLxy"), eXipair.lxy); + fRegistry.fill(HIST("MC/eXifromPromptXic0/hLz"), eXipair.lz); + } else { + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hs"), eXipair.mass, eXipair.ptepv, eXipair.dca3dinsigma, eXipair.lxy); + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hCosPA"), eXipair.cospa); + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hDCA2Legs"), eXipair.dca2legs); + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hLxy"), eXipair.lxy); + fRegistry.fill(HIST("MC/eXifromNonPromptXic0/hLz"), eXipair.lz); + } + } + } + } + } // end of MC truth + + } // end of Xi+ loop + } // end of main electron sample + + // Omegac0 -> e+ Omega- nu_e, br(Omegac0 -> e+ Omega- nu_e) / br(Omegac0 -> Omega- pi+) = 1.98, ctau = 82 um, m = 2695 MeV/c2 + for (const auto& positronId : positronIds) { + const auto& pos = tracks.rawIteratorAt(positronId); + + for (const auto& omegaMinusId : omegaMinusIds) { + const auto& omegaMinus = cascades.rawIteratorAt(omegaMinusId); + const auto& eOmegapair = makeECascadePair<1>(collision, pos, omegaMinus); // RS + fRegistry.fill(HIST("Data/eOmega/RS/hs"), eOmegapair.mass, eOmegapair.ptepv, eOmegapair.dca3dinsigma, eOmegapair.lxy); + fRegistry.fill(HIST("Data/eOmega/RS/hCosPA"), eOmegapair.cospa); + fRegistry.fill(HIST("Data/eOmega/RS/hDCA2Legs"), eOmegapair.dca2legs); + fRegistry.fill(HIST("Data/eOmega/RS/hLxy"), eOmegapair.lxy); + fRegistry.fill(HIST("Data/eOmega/RS/hLz"), eOmegapair.lz); + + if constexpr (isMC) { + const auto& mcpos = pos.template mcParticle_as(); + auto posLeg = omegaMinus.template posTrack_as(); + auto negLeg = omegaMinus.template negTrack_as(); + auto bachelor = omegaMinus.template bachelor_as(); + const auto& mcposLeg = posLeg.template mcParticle_as(); + const auto& mcnegLeg = negLeg.template mcParticle_as(); + const auto& mcbachelor = bachelor.template mcParticle_as(); + int mcLambdaId = FindCommonMotherFrom2Prongs(mcposLeg, mcnegLeg, 2212, -211, 3122, mcParticles); + if (mcLambdaId > 0) { // true Lambda + const auto& mcLambda = mcParticles.rawIteratorAt(mcLambdaId); + int mcOmegaId = FindCommonMotherFrom2Prongs(mcLambda, mcbachelor, 3122, -321, 3334, mcParticles); + if (mcOmegaId > 0) { // true omegaMinus + const auto& mcOmega = mcParticles.rawIteratorAt(mcOmegaId); + int mcOmegac0Id = FindCommonMotherFrom2Prongs(mcpos, mcOmega, -11, 3334, 4332, mcParticles); + if (mcOmegac0Id > 0) { // true Omegac0 + const auto& mcOmegac0 = mcParticles.rawIteratorAt(mcOmegac0Id); + if (IsFromBeauty(mcOmegac0, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hs"), eOmegapair.mass, eOmegapair.ptepv, eOmegapair.dca3dinsigma, eOmegapair.lxy); + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hCosPA"), eOmegapair.cospa); + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hDCA2Legs"), eOmegapair.dca2legs); + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hLxy"), eOmegapair.lxy); + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hLz"), eOmegapair.lz); + } else { + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hs"), eOmegapair.mass, eOmegapair.ptepv, eOmegapair.dca3dinsigma, eOmegapair.lxy); + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hCosPA"), eOmegapair.cospa); + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hDCA2Legs"), eOmegapair.dca2legs); + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hLxy"), eOmegapair.lxy); + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hLz"), eOmegapair.lz); + } + } + } + } + } // end of MC truth + } // end of Lambda loop + + for (const auto& omegaPlusId : omegaPlusIds) { + const auto& omegaPlus = cascades.rawIteratorAt(omegaPlusId); + const auto& eOmegapair = makeECascadePair<1>(collision, pos, omegaPlus); // WS + fRegistry.fill(HIST("Data/eOmega/WS/hs"), eOmegapair.mass, eOmegapair.ptepv, eOmegapair.dca3dinsigma, eOmegapair.lxy); + fRegistry.fill(HIST("Data/eOmega/WS/hCosPA"), eOmegapair.cospa); + fRegistry.fill(HIST("Data/eOmega/WS/hDCA2Legs"), eOmegapair.dca2legs); + fRegistry.fill(HIST("Data/eOmega/WS/hLxy"), eOmegapair.lxy); + fRegistry.fill(HIST("Data/eOmega/WS/hLz"), eOmegapair.lz); + } // end of AntiLambda loop + } // end of main positron sample + + for (const auto& electronId : electronIds) { + const auto& ele = tracks.rawIteratorAt(electronId); + + for (const auto& omegaMinusId : omegaMinusIds) { + const auto& omegaMinus = cascades.rawIteratorAt(omegaMinusId); + const auto& eOmegapair = makeECascadePair<1>(collision, ele, omegaMinus); // WS + fRegistry.fill(HIST("Data/eOmega/WS/hs"), eOmegapair.mass, eOmegapair.ptepv, eOmegapair.dca3dinsigma, eOmegapair.lxy); + fRegistry.fill(HIST("Data/eOmega/WS/hCosPA"), eOmegapair.cospa); + fRegistry.fill(HIST("Data/eOmega/WS/hDCA2Legs"), eOmegapair.dca2legs); + fRegistry.fill(HIST("Data/eOmega/WS/hLxy"), eOmegapair.lxy); + fRegistry.fill(HIST("Data/eOmega/WS/hLz"), eOmegapair.lz); + + } // end of Omega- loop + + for (const auto& omegaPlusId : omegaPlusIds) { + const auto& omegaPlus = cascades.rawIteratorAt(omegaPlusId); + const auto& eOmegapair = makeECascadePair<1>(collision, ele, omegaPlus); // RS + fRegistry.fill(HIST("Data/eOmega/RS/hs"), eOmegapair.mass, eOmegapair.ptepv, eOmegapair.dca3dinsigma, eOmegapair.lxy); + fRegistry.fill(HIST("Data/eOmega/RS/hCosPA"), eOmegapair.cospa); + fRegistry.fill(HIST("Data/eOmega/RS/hDCA2Legs"), eOmegapair.dca2legs); + fRegistry.fill(HIST("Data/eOmega/RS/hLxy"), eOmegapair.lxy); + fRegistry.fill(HIST("Data/eOmega/RS/hLz"), eOmegapair.lz); + + if constexpr (isMC) { + const auto& mcele = ele.template mcParticle_as(); + auto posLeg = omegaPlus.template posTrack_as(); + auto negLeg = omegaPlus.template negTrack_as(); + auto bachelor = omegaPlus.template bachelor_as(); + const auto& mcposLeg = posLeg.template mcParticle_as(); + const auto& mcnegLeg = negLeg.template mcParticle_as(); + const auto& mcbachelor = bachelor.template mcParticle_as(); + int mcLambdaId = FindCommonMotherFrom2Prongs(mcposLeg, mcnegLeg, 211, -2212, -3122, mcParticles); + if (mcLambdaId > 0) { // true AntiLambda + const auto& mcLambda = mcParticles.rawIteratorAt(mcLambdaId); + int mcOmegaId = FindCommonMotherFrom2Prongs(mcLambda, mcbachelor, -3122, 321, -3334, mcParticles); + if (mcOmegaId > 0) { // true omegaPlus + const auto& mcOmega = mcParticles.rawIteratorAt(mcOmegaId); + int mcOmegac0Id = FindCommonMotherFrom2Prongs(mcele, mcOmega, 11, -3334, 4332, mcParticles); + if (mcOmegac0Id > 0) { // true Omegac0 + const auto& mcOmegac0 = mcParticles.rawIteratorAt(mcOmegac0Id); + if (IsFromBeauty(mcOmegac0, mcParticles) < 0) { + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hs"), eOmegapair.mass, eOmegapair.ptepv, eOmegapair.dca3dinsigma, eOmegapair.lxy); + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hCosPA"), eOmegapair.cospa); + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hDCA2Legs"), eOmegapair.dca2legs); + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hLxy"), eOmegapair.lxy); + fRegistry.fill(HIST("MC/eOmegafromPromptOmegac0/hLz"), eOmegapair.lz); + } else { + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hs"), eOmegapair.mass, eOmegapair.ptepv, eOmegapair.dca3dinsigma, eOmegapair.lxy); + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hCosPA"), eOmegapair.cospa); + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hDCA2Legs"), eOmegapair.dca2legs); + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hLxy"), eOmegapair.lxy); + fRegistry.fill(HIST("MC/eOmegafromNonPromptOmegac0/hLz"), eOmegapair.lz); + } + } + } + } + } // end of MC truth + + } // end of Omega+ loop + } // end of main electron sample + + electronIdsLoose.clear(); + electronIdsLoose.shrink_to_fit(); + positronIdsLoose.clear(); + positronIdsLoose.shrink_to_fit(); + electronIds.clear(); + electronIds.shrink_to_fit(); + positronIds.clear(); + positronIds.shrink_to_fit(); + + lambdaIds.clear(); + lambdaIds.shrink_to_fit(); + antilambdaIds.clear(); + antilambdaIds.shrink_to_fit(); + + xiPlusIds.clear(); + xiPlusIds.shrink_to_fit(); + xiMinusIds.clear(); + xiMinusIds.shrink_to_fit(); + + omegaPlusIds.clear(); + omegaPlusIds.shrink_to_fit(); + omegaMinusIds.clear(); + omegaMinusIds.shrink_to_fit(); + } // end of collision loop + + used_electronIds.clear(); + used_electronIds.shrink_to_fit(); + } + + SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + Preslice perCol_v0 = o2::aod::v0data::collisionId; + Preslice perCol_casc = o2::aod::cascdata::collisionId; + + Filter collisionFilter_evsel = o2::aod::evsel::sel8 == true && (eventcut.cfgZvtxMin < o2::aod::collision::posZ && o2::aod::collision::posZ < eventcut.cfgZvtxMax); + Filter collisionFilter_centrality = (eventcut.cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < eventcut.cfgCentMax) || (eventcut.cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < eventcut.cfgCentMax) || (eventcut.cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < eventcut.cfgCentMax); + using FilteredMyCollisions = soa::Filtered; + using FilteredMyCollisionsWithMCLabel = soa::Filtered; + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + std::vector> stored_trackIds; + + // Filter trackFilter = 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; + // using MyFilteredTracksWithMCLabel = soa::Filtered; + // Partition posTracks = o2::aod::track::signed1Pt > 0.f; + // Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + //! type of V0. 0: built solely for cascades (does not pass standard V0 cut), 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 > v0cut.cfg_min_cospa&& o2::aod::v0data::dcaV0daughters v0cut.cfg_min_dcaxy&& nabs(o2::aod::v0data::dcanegtopv) > v0cut.cfg_min_dcaxy; + using filteredV0s = soa::Filtered; + + Filter cascadeFilter = nabs(o2::aod::cascdata::dcanegtopv) > cascadecut.cfg_min_dcaxy_v0leg&& nabs(o2::aod::cascdata::dcanegtopv) > cascadecut.cfg_min_dcaxy_v0leg&& nabs(o2::aod::cascdata::dcabachtopv) > cascadecut.cfg_min_dcaxy_bachelor; + Filter cascadeFilter_dca = o2::aod::cascdata::dcacascdaughters < cascadecut.cfg_max_dcadau && o2::aod::cascdata::dcaV0daughters < cascadecut.cfg_max_dcadau_v0; + using filteredMyCascades = soa::Filtered; + + std::vector electronIdsLoose; + std::vector positronIdsLoose; + std::vector electronIds; + std::vector positronIds; + + std::vector lambdaIds; + std::vector antilambdaIds; + + std::vector xiPlusIds; + std::vector xiMinusIds; + std::vector omegaPlusIds; + std::vector omegaMinusIds; + + std::vector> used_electronIds; // pair of hTypeId and electronId + + void processMC(FilteredMyCollisionsWithMCLabel const& collisions, aod::BCsWithTimestamps const& bcs, MyTracksWithMCLabel const& tracks, aod::TrackAssoc const& trackIndices, filteredV0s const& v0s, filteredMyCascades const& cascades, aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + runPairing(bcs, collisions, tracks, trackIndices, v0s, cascades, mcCollisions, mcParticles); + } + PROCESS_SWITCH(taggingHFE, processMC, "process with TTCA", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"tagging-hfe"})}; +} diff --git a/PWGEM/Dilepton/Tasks/vpPairQC.cxx b/PWGEM/Dilepton/Tasks/vpPairQC.cxx new file mode 100644 index 00000000000..ffa82e3c3e5 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/vpPairQC.cxx @@ -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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include + +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_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 cfgRefR{"cfgRefR", 1.2, "reference R (in m) for extrapolation"}; // https://cds.cern.ch/record/1419204 + + 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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.5, "min. pin for pion rejection in TPC"}; + 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"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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); + 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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); + + // 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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, 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, dielectroncuts.cfgRefR)) { + 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/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/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..d470a92afa2 --- /dev/null +++ b/PWGEM/Dilepton/Tasks/vpPairQCMC.cxx @@ -0,0 +1,669 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGEM/Dilepton/Core/DielectronCut.h" +#include "PWGEM/Dilepton/Core/EMEventCut.h" +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventHistograms.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include + +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_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 cfgRefR{"cfgRefR", 1.2, "reference R (in m) for extrapolation"}; // https://cds.cern.ch/record/1419204 + + 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_min_pin_pirejTPC{"cfg_min_pin_pirejTPC", 0.5, "min. pin for pion rejection in TPC"}; + 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"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + // 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); + 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); + fDielectronCut.IncludeITSsa(dielectroncuts.includeITSsa, dielectroncuts.cfg_max_pt_track_ITSsa); + + // 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.SetPinRangeForPionRejectionTPC(dielectroncuts.cfg_min_pin_pirejTPC, 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, dielectroncuts.cfgRefR)) { + 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 index 3385f2b4977..3ef4cecfe7d 100644 --- a/PWGEM/Dilepton/Utils/EMFwdTrack.h +++ b/PWGEM/Dilepton/Utils/EMFwdTrack.h @@ -22,11 +22,8 @@ namespace o2::aod::pwgem::dilepton::utils class EMFwdTrack { public: - EMFwdTrack(int globalId, int collisionId, int trackId, float pt, float eta, float phi, float mass, int8_t charge = 0, float dcaX = 0.f, float dcaY = 0.f, std::vector amb_muon_self_ids = {}) + EMFwdTrack(float pt, float eta, float phi, float mass, int8_t charge, float dcaX, float dcaY, float cXX, float cXY, float cYY) { - fGlobalId = globalId; - fCollisionId = collisionId; - fTrackId = trackId; fPt = pt; fEta = eta; fPhi = phi; @@ -34,21 +31,14 @@ class EMFwdTrack 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 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; } @@ -61,17 +51,13 @@ class EMFwdTrack 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 pairDcaXYinSigmaOTF() const { return fPairDCAXYinSigmaOTF; } - void setPairDcaXYinSigmaOTF(float dca) { fPairDCAXYinSigmaOTF = dca; } + float cXXatDCA() const { return fCXX; } + float cXYatDCA() const { return fCXY; } + float cYYatDCA() const { return fCYY; } protected: - int fGlobalId; - int fCollisionId; - int fTrackId; float fPt; float fEta; float fPhi; @@ -79,89 +65,9 @@ class EMFwdTrack int8_t fCharge; float fDCAx; float fDCAy; - float fPairDCAXYinSigmaOTF; - bool fIsAmbiguous; - std::vector fAmbMuonSelfIds; -}; - -class EMFwdTrackWithCov : public EMFwdTrack -{ - public: - EMFwdTrackWithCov(int globalId, int collisionId, int trackId, float pt, float eta, float phi, float mass, int8_t charge = 0, float dcaX = 0.f, float dcaY = 0.f, std::vector amb_muon_self_ids = {}, - float X = 0.f, float Y = 0.f, float Z = 0.f, float Tgl = 0.f, - float CXX = 0.f, float CXY = 0.f, float CYY = 0.f, - float CPhiX = 0.f, float CPhiY = 0.f, float CPhiPhi = 0.f, - float CTglX = 0.f, float CTglY = 0.f, float CTglPhi = 0.f, float CTglTgl = 0.f, - float C1PtX = 0.f, float C1PtY = 0.f, float C1PtPhi = 0.f, float C1PtTgl = 0.f, float C1Pt21Pt2 = 0.f, float chi2 = 0.f) : EMFwdTrack(globalId, collisionId, trackId, pt, eta, phi, mass, charge, dcaX, dcaY, amb_muon_self_ids) - { - fX = X; - fY = Y; - fZ = Z; - fTgl = Tgl; - fCXX = CXX; - fCXY = CXY; - fCYY = CYY; - fCPhiX = CPhiX; - fCPhiY = CPhiY; - fCPhiPhi = CPhiPhi; - fCTglX = CTglX; - fCTglY = CTglY; - fCTglPhi = CTglPhi; - fCTglTgl = CTglTgl; - fC1PtX = C1PtX; - fC1PtY = C1PtY; - fC1PtPhi = C1PtPhi; - fC1PtTgl = C1PtTgl; - fC1Pt21Pt2 = C1Pt21Pt2; - fChi2 = chi2; - } - - float x() const { return fX; } - float y() const { return fY; } - float z() const { return fZ; } - float tgl() const { return fTgl; } - float cXX() const { return fCXX; } - float cXY() const { return fCXY; } - float cYY() const { return fCYY; } - float cPhiX() const { return fCPhiX; } - float cPhiY() const { return fCPhiY; } - float cPhiPhi() const { return fCPhiPhi; } - float cTglX() const { return fCTglX; } - float cTglY() const { return fCTglY; } - float cTglPhi() const { return fCTglPhi; } - float cTglTgl() const { return fCTglTgl; } - float c1PtX() const { return fC1PtX; } - float c1PtY() const { return fC1PtY; } - float c1PtPhi() const { return fC1PtPhi; } - float c1PtTgl() const { return fC1PtTgl; } - float c1Pt21Pt2() const { return fC1Pt21Pt2; } - float chi2() const { return fChi2; } - - void setCXX(float cXX) { fCXX = cXX; } - void setCXY(float cXY) { fCXY = cXY; } - void setCYY(float cYY) { fCYY = cYY; } - - protected: - float fX; - float fY; - float fZ; - float fTgl; float fCXX; float fCXY; float fCYY; - float fCPhiX; - float fCPhiY; - float fCPhiPhi; - float fCTglX; - float fCTglY; - float fCTglPhi; - float fCTglTgl; - float fC1PtX; - float fC1PtY; - float fC1PtPhi; - float fC1PtTgl; - float fC1Pt21Pt2; - float fChi2; }; } // namespace o2::aod::pwgem::dilepton::utils diff --git a/PWGEM/Dilepton/Utils/EMTrack.h b/PWGEM/Dilepton/Utils/EMTrack.h index 37615a11e3d..14755d4f406 100644 --- a/PWGEM/Dilepton/Utils/EMTrack.h +++ b/PWGEM/Dilepton/Utils/EMTrack.h @@ -15,6 +15,8 @@ #ifndef PWGEM_DILEPTON_UTILS_EMTRACK_H_ #define PWGEM_DILEPTON_UTILS_EMTRACK_H_ +#include "Math/Vector4D.h" + #include namespace o2::aod::pwgem::dilepton::utils @@ -22,11 +24,8 @@ namespace o2::aod::pwgem::dilepton::utils class EMTrack { public: - EMTrack(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 = {}) + EMTrack(float pt, float eta, float phi, float mass, int8_t charge = 0, float dcaXY = 0.f, float dcaZ = 0.f, float CYY = 0, float CZY = 0, float CZZ = 0) { - fGlobalId = globalId; - fCollisionId = collisionId; - fTrackId = trackId; fPt = pt; fEta = eta; fPhi = phi; @@ -34,21 +33,13 @@ class EMTrack fCharge = charge; fDCAxy = dcaXY; fDCAz = dcaZ; - fPairDCA3DinSigmaOTF = 0; - - fAmbEleSelfIds = amb_ele_self_ids; - if (fAmbEleSelfIds.size() > 0) { - fIsAmbiguous = true; - } else { - fIsAmbiguous = false; - } + fCYY = CYY; + fCZY = CZY; + fCZZ = CZZ; } ~EMTrack() {} - 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; } @@ -56,21 +47,19 @@ class EMTrack int8_t sign() const { return fCharge; } float dcaXY() const { return fDCAxy; } float dcaZ() const { return fDCAz; } + + float cYY() const { return fCYY; } + float cZY() const { return fCZY; } + float cZZ() const { return fCZZ; } + + float rapidity() const { return std::log((std::sqrt(std::pow(fMass, 2) + std::pow(fPt * std::cosh(fEta), 2)) + fPt * std::sinh(fEta)) / std::sqrt(std::pow(fMass, 2) + std::pow(fPt, 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_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; } - protected: - int fGlobalId; - int fCollisionId; - int fTrackId; float fPt; float fEta; float fPhi; @@ -78,20 +67,20 @@ class EMTrack int8_t fCharge; float fDCAxy; float fDCAz; - float fPairDCA3DinSigmaOTF; - bool fIsAmbiguous; - std::vector fAmbEleSelfIds; + float fCYY; + float fCZY; + float fCZZ; }; class EMTrackWithCov : public EMTrack { public: - EMTrackWithCov(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 = {}, + EMTrackWithCov(float pt, float eta, float phi, float mass, int8_t charge = 0, float dcaXY = 0.f, float dcaZ = 0.f, 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(globalId, collisionId, trackId, pt, eta, phi, mass, charge, dcaXY, dcaZ, amb_ele_self_ids) + float C1PtY = 0.f, float C1PtZ = 0.f, float C1PtSnp = 0.f, float C1PtTgl = 0.f, float C1Pt21Pt2 = 0.f) : EMTrack(pt, eta, phi, mass, charge, dcaXY, dcaZ) { fX = X; fY = Y; @@ -116,6 +105,8 @@ class EMTrackWithCov : public EMTrack fC1Pt21Pt2 = C1Pt21Pt2; } + ~EMTrackWithCov() {} + float x() const { return fX; } float y() const { return fY; } float z() const { return fZ; } @@ -123,9 +114,6 @@ class EMTrackWithCov : public EMTrack 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; } @@ -139,10 +127,6 @@ class EMTrackWithCov : public EMTrack 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; @@ -150,9 +134,6 @@ class EMTrackWithCov : public EMTrack float fAlpha; float fSnp; float fTgl; - float fCYY; - float fCZY; - float fCZZ; float fCSnpY; float fCSnpZ; float fCSnpSnp; @@ -167,5 +148,94 @@ class EMTrackWithCov : public EMTrack float fC1Pt21Pt2; }; +class EMPair : public EMTrack +{ + public: + EMPair(float pt, float eta, float phi, float mass, int8_t charge = 0) : EMTrack(pt, eta, phi, mass, charge, 0, 0, 0, 0, 0) + { + fPairDCA = 999.f; + fVPos = ROOT::Math::PtEtaPhiMVector(0, 0, 0, 0); + fVNeg = ROOT::Math::PtEtaPhiMVector(0, 0, 0, 0); + fVx = 0.f; + fVy = 0.f; + fVz = 0.f; + } + + ~EMPair() {} + + void setPairDCA(float dca) { fPairDCA = dca; } + float getPairDCA() const { return fPairDCA; } + + 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); + } + + void setPositiveLegPxPyPzM(float px, float py, float pz, float m) + { + float pt = std::sqrt(px * px + py * py); + float eta = std::atanh(pz / std::sqrt(std::pow(px, 2) + std::pow(py, 2) + std::pow(pz, 2))); + float phi = std::atan2(py, px); + if (phi < 0.f) { + phi += 2.f * M_PI; + } + + fVPos.SetPt(pt); + fVPos.SetEta(eta); + fVPos.SetPhi(phi); + fVPos.SetM(m); + } + void setNegativeLegPxPyPzM(float px, float py, float pz, float m) + { + float pt = std::sqrt(px * px + py * py); + float eta = std::atanh(pz / std::sqrt(std::pow(px, 2) + std::pow(py, 2) + std::pow(pz, 2))); + float phi = std::atan2(py, px); + if (phi < 0.f) { + phi += 2.f * M_PI; + } + + 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 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 / std::sqrt(std::pow(fVx, 2) + std::pow(fVy, 2) + std::pow(fVz, 2))); } + float phi_cp() const { return std::atan2(fVy, fVx); } + + protected: + float fPairDCA; + ROOT::Math::PtEtaPhiMVector fVPos; + ROOT::Math::PtEtaPhiMVector fVNeg; + + // only for photon conversion point + float fVx; + float fVy; + float fVz; +}; + } // 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 index 67830f4eee0..5c5b21e6ea0 100644 --- a/PWGEM/Dilepton/Utils/EMTrackUtilities.h +++ b/PWGEM/Dilepton/Utils/EMTrackUtilities.h @@ -15,13 +15,36 @@ #ifndef PWGEM_DILEPTON_UTILS_EMTRACKUTILITIES_H_ #define PWGEM_DILEPTON_UTILS_EMTRACKUTILITIES_H_ +#include "Framework/DataTypes.h" +#include "Framework/Logger.h" + +#include +#include #include #include -#include //_______________________________________________________________________ namespace o2::aod::pwgem::dilepton::utils::emtrackutil { + +enum class RefTrackBit : uint16_t { // This is not for leptons, but charged tracks for reference flow. + kNclsITS5 = 1, + kNclsITS6 = 2, + kNcrTPC70 = 4, + kNcrTPC90 = 8, + kNclsTPC50 = 16, // (not necessary, if ncr is used.) + kNclsTPC70 = 32, // (not necessary, if ncr is used.) + kNclsTPC90 = 64, // (not necessary, if ncr is used.) + kChi2TPC4 = 128, + kChi2TPC3 = 256, + kFracSharedTPC07 = 512, + kDCAxy05cm = 1024, // default is 1 cm + kDCAxy03cm = 2048, + kDCAz05cm = 4096, // default is 1cm + kDCAz03cm = 8192, +}; + +//_______________________________________________________________________ template float dca3DinSigma(T const& track) { @@ -35,27 +58,128 @@ float dca3DinSigma(T const& track) 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 + 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.cXX(); - float cYY = track.cYY(); - float cXY = track.cXY(); - float dcaX = track.fwdDcaX(); // in cm - float dcaY = track.fwdDcaY(); // in cm - + 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::abs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2. * dcaX * dcaY * cXY) / det / 2.)); // dca xy in sigma + 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 checkMFTHitMap(T const& track) +{ + // logical-OR + uint64_t mftClusterSizesAndTrackFlags = track.mftClusterSizesAndTrackFlags(); + uint16_t clmap = 0; + for (unsigned int layer = begin; layer <= end; layer++) { + if ((mftClusterSizesAndTrackFlags >> (layer * 6)) & 0x3f) { + clmap |= (1 << layer); + } + } + return (clmap > 0); +} +//_______________________________________________________________________ +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 index 85b2778a71c..207b0c3cb68 100644 --- a/PWGEM/Dilepton/Utils/EventHistograms.h +++ b/PWGEM/Dilepton/Utils/EventHistograms.h @@ -14,16 +14,19 @@ #ifndef PWGEM_DILEPTON_UTILS_EVENTHISTOGRAMS_H_ #define PWGEM_DILEPTON_UTILS_EVENTHISTOGRAMS_H_ + +#include "Framework/HistogramRegistry.h" + using namespace o2::framework; namespace o2::aod::pwgem::dilepton::utils::eventhistogram { -const int nbin_ev = 13; +const int nbin_ev = 21; template void addEventHistograms(HistogramRegistry* fRegistry) { // event info - auto hCollisionCounter = fRegistry->add("Event/before/hCollisionCounter", "collision counter;;Number of events", kTH1F, {{nbin_ev, 0.5, nbin_ev + 0.5}}, false); + 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"); @@ -35,117 +38,127 @@ void addEventHistograms(HistogramRegistry* fRegistry) 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, "Calibrated Q vector"); - hCollisionCounter->GetXaxis()->SetBinLabel(13, "accepted"); + 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}, {2000, 0, 20000}}, false); - fRegistry->add("Event/before/hSpherocity", "hSpherocity;spherocity", kTH1F, {{100, 0, 1}}, false); + const AxisSpec axis_cent_ft0m{{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, + 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, 102, 103, 104, 105, 106, 107, 108, 109, 110}, + "centrality FT0M (%)"}; - if constexpr (nmod == 2) { // Q2 - fRegistry->add("Event/before/hQ2xFT0M_CentFT0C", "hQ2xFT0M_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0M}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2yFT0M_CentFT0C", "hQ2yFT0M_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0M}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2xFT0A_CentFT0C", "hQ2xFT0A_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0A}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2yFT0A_CentFT0C", "hQ2yFT0A_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0A}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2xFT0C_CentFT0C", "hQ2xFT0C_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0C}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2yFT0C_CentFT0C", "hQ2yFT0C_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0C}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2xBPos_CentFT0C", "hQ2xBPos_CentFT0C;centrality FT0C (%);Q_{2,x}^{BPos}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2yBPos_CentFT0C", "hQ2yBPos_CentFT0C;centrality FT0C (%);Q_{2,y}^{BPos}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2xBNeg_CentFT0C", "hQ2xBNeg_CentFT0C;centrality FT0C (%);Q_{2,x}^{BNeg}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2yBNeg_CentFT0C", "hQ2yBNeg_CentFT0C;centrality FT0C (%);Q_{2,y}^{BNeg}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2xBTot_CentFT0C", "hQ2xBTot_CentFT0C;centrality FT0C (%);Q_{2,x}^{BTot}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ2yBTot_CentFT0C", "hQ2yBTot_CentFT0C;centrality FT0C (%);Q_{2,y}^{BTot}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); + const AxisSpec axis_cent_ft0a{{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, + 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, 102, 103, 104, 105, 106, 107, 108, 109, 110}, + "centrality FT0A (%)"}; - fRegistry->add("Event/before/hEP2FT0M_CentFT0C", "2nd harmonics event plane FT0M;centrality FT0C (%);#Psi_{2}^{FT0M} (rad.)", kTH2F, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); + const AxisSpec axis_cent_ft0c{{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, + 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, 102, 103, 104, 105, 106, 107, 108, 109, 110}, + "centrality FT0C (%)"}; - fRegistry->add("Event/before/hPrfQ2FT0MQ2BPos_CentFT0C", "Q_{2}^{FT0M} #upoint Q_{2}^{BPos};centrality FT0C (%);Q_{2}^{FT0M} #upoint Q_{2}^{BPos}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ2FT0MQ2BNeg_CentFT0C", "Q_{2}^{FT0M} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{FT0M} #upoint Q_{2}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ2BPosQ2BNeg_CentFT0C", "Q_{2}^{BPos} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{BPos} #upoint Q_{2}^{BNeg}", kTProfile, {{110, 0, 110}}, 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, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ2FT0CQ2BNeg_CentFT0C", "Q_{2}^{FT0C} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{FT0C} #upoint Q_{2}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ2FT0CQ2BTot_CentFT0C", "Q_{2}^{FT0C} #upoint Q_{2}^{BTot};centrality FT0C (%);Q_{2}^{FT0C} #upoint Q_{2}^{BTot}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ2FT0AQ2BPos_CentFT0C", "Q_{2}^{FT0A} #upoint Q_{2}^{BPos};centrality FT0C (%);Q_{2}^{FT0A} #upoint Q_{2}^{BPos}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ2FT0AQ2BNeg_CentFT0C", "Q_{2}^{FT0A} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{FT0A} #upoint Q_{2}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ2FT0AQ2BTot_CentFT0C", "Q_{2}^{FT0A} #upoint Q_{2}^{BTot};centrality FT0C (%);Q_{2}^{FT0A} #upoint Q_{2}^{BTot}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ2FT0AQ2FT0C_CentFT0C", "Q_{2}^{FT0A} #upoint Q_{2}^{FT0C};centrality FT0C (%);Q_{2}^{FT0A} #upoint Q_{2}^{FT0C}", kTProfile, {{110, 0, 110}}, 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, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3yFT0M_CentFT0C", "hQ3yFT0M_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0M}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3xFT0A_CentFT0C", "hQ3xFT0A_CentFT0C;centrality FT0C (%);Q_{3,x}^{FT0A}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3yFT0A_CentFT0C", "hQ3yFT0A_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0A}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3xFT0C_CentFT0C", "hQ3xFT0C_CentFT0C;centrality FT0C (%);Q_{3,x}^{FT0C}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3yFT0C_CentFT0C", "hQ3yFT0C_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0C}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3xBPos_CentFT0C", "hQ3xBPos_CentFT0C;centrality FT0C (%);Q_{3,x}^{BPos}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3yBPos_CentFT0C", "hQ3yBPos_CentFT0C;centrality FT0C (%);Q_{3,y}^{BPos}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3xBNeg_CentFT0C", "hQ3xBNeg_CentFT0C;centrality FT0C (%);Q_{3,x}^{BNeg}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3yBNeg_CentFT0C", "hQ3yBNeg_CentFT0C;centrality FT0C (%);Q_{3,y}^{BNeg}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3xBTot_CentFT0C", "hQ3xBTot_CentFT0C;centrality FT0C (%);Q_{3,x}^{BTot}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ3yBTot_CentFT0C", "hQ3yBTot_CentFT0C;centrality FT0C (%);Q_{3,y}^{BTot}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1D, {{100, -50, +50}}, false); + fRegistry->add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1D, {{6001, -0.5, 6000.5}}, false); + fRegistry->add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1D, {{6001, -0.5, 6000.5}}, false); + fRegistry->add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2D, {{200, 0, 200000}, {60, 0, 60000}}, false); + fRegistry->add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1D, {{axis_cent_ft0a}}, false); + fRegistry->add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1D, {{axis_cent_ft0c}}, false); + fRegistry->add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1D, {{axis_cent_ft0m}}, false); + fRegistry->add("Event/before/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", kTH2D, {{110, 0, 110}, {600, 0, 6000}}, false); + fRegistry->add("Event/before/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", kTH2D, {{60, 0, 60000}, {600, 0, 6000}}, false); + fRegistry->add("Event/before/hMultFT0CvsOccupancy", "hMultFT0CvsOccupancy;mult. FT0C;N_{track} in time range", kTH2D, {{60, 0, 60000}, {200, 0, 20000}}, false); + fRegistry->add("Event/before/hNTracksPVvsOccupancy", "hNTracksPVvsOccupancy;N_{track} to PV;N_{track} in time range", kTH2D, {{600, 0, 6000}, {200, 0, 20000}}, false); + fRegistry->add("Event/before/hCorrOccupancy", "occupancy correlation;FT0C occupancy;track occupancy", kTH2D, {{200, 0, 200000}, {200, 0, 20000}}, false); - fRegistry->add("Event/before/hEP3FT0M_CentFT0C", "3rd harmonics event plane FT0M;centrality FT0C (%);#Psi_{3}^{FT0M} (rad.)", kTH2F, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -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, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); + if constexpr (nmod == 2) { + fRegistry->add("Event/before/hQ2xFT0M_CentFT0C", "hQ2xFT0M_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0M}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yFT0M_CentFT0C", "hQ2yFT0M_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0M}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xFT0A_CentFT0C", "hQ2xFT0A_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0A}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yFT0A_CentFT0C", "hQ2yFT0A_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0A}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xFT0C_CentFT0C", "hQ2xFT0C_CentFT0C;centrality FT0C (%);Q_{2,x}^{FT0C}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yFT0C_CentFT0C", "hQ2yFT0C_CentFT0C;centrality FT0C (%);Q_{2,y}^{FT0C}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xFV0A_CentFT0C", "hQ2xFV0A_CentFT0C;centrality FT0C (%);Q_{2,x}^{FV0A}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yFV0A_CentFT0C", "hQ2yFV0A_CentFT0C;centrality FT0C (%);Q_{2,y}^{FV0A}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xBPos_CentFT0C", "hQ2xBPos_CentFT0C;centrality FT0C (%);Q_{2,x}^{BPos}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yBPos_CentFT0C", "hQ2yBPos_CentFT0C;centrality FT0C (%);Q_{2,y}^{BPos}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xBNeg_CentFT0C", "hQ2xBNeg_CentFT0C;centrality FT0C (%);Q_{2,x}^{BNeg}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yBNeg_CentFT0C", "hQ2yBNeg_CentFT0C;centrality FT0C (%);Q_{2,y}^{BNeg}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2xBTot_CentFT0C", "hQ2xBTot_CentFT0C;centrality FT0C (%);Q_{2,x}^{BTot}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ2yBTot_CentFT0C", "hQ2yBTot_CentFT0C;centrality FT0C (%);Q_{2,y}^{BTot}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hPrfQ3FT0MQ3BPos_CentFT0C", "Q_{3}^{FT0M} #upoint Q_{3}^{BPos};centrality FT0C (%);Q_{3}^{FT0M} #upoint Q_{3}^{BPos}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ3FT0MQ3BNeg_CentFT0C", "Q_{3}^{FT0M} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{FT0M} #upoint Q_{3}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ3BPosQ3BNeg_CentFT0C", "Q_{3}^{BPos} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{BPos} #upoint Q_{3}^{BNeg}", kTProfile, {{110, 0, 110}}, 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, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ3FT0CQ3BNeg_CentFT0C", "Q_{3}^{FT0C} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{FT0C} #upoint Q_{3}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ3FT0CQ3BTot_CentFT0C", "Q_{3}^{FT0C} #upoint Q_{3}^{BTot};centrality FT0C (%);Q_{3}^{FT0C} #upoint Q_{3}^{BTot}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ3FT0AQ3BPos_CentFT0C", "Q_{3}^{FT0A} #upoint Q_{3}^{BPos};centrality FT0C (%);Q_{3}^{FT0A} #upoint Q_{3}^{BPos}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ3FT0AQ3BNeg_CentFT0C", "Q_{3}^{FT0A} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{FT0A} #upoint Q_{3}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ3FT0AQ3BTot_CentFT0C", "Q_{3}^{FT0A} #upoint Q_{3}^{BTot};centrality FT0C (%);Q_{3}^{FT0A} #upoint Q_{3}^{BTot}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ3FT0AQ3FT0C_CentFT0C", "Q_{3}^{FT0A} #upoint Q_{3}^{FT0C};centrality FT0C (%);Q_{3}^{FT0A} #upoint Q_{3}^{FT0C}", kTProfile, {{110, 0, 110}}, false); // this is necessary for dimuons - } else if constexpr (nmod == 4) { // Q4 - fRegistry->add("Event/before/hQ4xFT0M_CentFT0C", "hQ4xFT0M_CentFT0C;centrality FT0C (%);Q_{4,x}^{FT0M}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4yFT0M_CentFT0C", "hQ4yFT0M_CentFT0C;centrality FT0C (%);Q_{4,y}^{FT0M}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4xFT0A_CentFT0C", "hQ4xFT0A_CentFT0C;centrality FT0C (%);Q_{4,x}^{FT0A}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4yFT0A_CentFT0C", "hQ4yFT0A_CentFT0C;centrality FT0C (%);Q_{4,y}^{FT0A}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4xFT0C_CentFT0C", "hQ4xFT0C_CentFT0C;centrality FT0C (%);Q_{4,x}^{FT0C}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4yFT0C_CentFT0C", "hQ4yFT0C_CentFT0C;centrality FT0C (%);Q_{4,y}^{FT0C}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4xBPos_CentFT0C", "hQ4xBPos_CentFT0C;centrality FT0C (%);Q_{4,x}^{BPos}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4yBPos_CentFT0C", "hQ4yBPos_CentFT0C;centrality FT0C (%);Q_{4,y}^{BPos}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4xBNeg_CentFT0C", "hQ4xBNeg_CentFT0C;centrality FT0C (%);Q_{4,x}^{BNeg}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4yBNeg_CentFT0C", "hQ4yBNeg_CentFT0C;centrality FT0C (%);Q_{4,y}^{BNeg}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4xBTot_CentFT0C", "hQ4xBTot_CentFT0C;centrality FT0C (%);Q_{4,x}^{BTot}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hQ4yBTot_CentFT0C", "hQ4yBTot_CentFT0C;centrality FT0C (%);Q_{4,y}^{BTot}", kTH2F, {{110, 0, 110}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hEP2FT0M_CentFT0C", "2nd harmonics event plane FT0M;centrality FT0C (%);#Psi_{2}^{FT0M} (rad.)", kTH2D, {{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.)", kTH2D, {{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.)", kTH2D, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP2FV0A_CentFT0C", "2nd harmonics event plane FV0A;centrality FT0C (%);#Psi_{2}^{FV0A} (rad.)", kTH2D, {{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.)", kTH2D, {{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.)", kTH2D, {{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.)", kTH2D, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); - fRegistry->add("Event/before/hEP4FT0M_CentFT0C", "4rd harmonics event plane FT0M;centrality FT0C (%);#Psi_{4}^{FT0M} (rad.)", kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); - fRegistry->add("Event/before/hEP4FT0A_CentFT0C", "4rd harmonics event plane FT0A;centrality FT0C (%);#Psi_{4}^{FT0A} (rad.)", kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); - fRegistry->add("Event/before/hEP4FT0C_CentFT0C", "4rd harmonics event plane FT0C;centrality FT0C (%);#Psi_{4}^{FT0C} (rad.)", kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); - fRegistry->add("Event/before/hEP4BPos_CentFT0C", "4rd harmonics event plane BPos;centrality FT0C (%);#Psi_{4}^{BPos} (rad.)", kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); - fRegistry->add("Event/before/hEP4BNeg_CentFT0C", "4rd harmonics event plane BNeg;centrality FT0C (%);#Psi_{4}^{BNeg} (rad.)", kTH2F, {{110, 0, 110}, {180, -M_PI_2, +M_PI_2}}, false); - fRegistry->add("Event/before/hEP4BTot_CentFT0C", "4rd harmonics event plane BTot;centrality FT0C (%);#Psi_{4}^{BTot} (rad.)", kTH2F, {{110, 0, 110}, {180, -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 + fRegistry->add("Event/before/hPrfQ2FV0AQ2BPos_CentFT0C", "Q_{2}^{FV0A} #upoint Q_{2}^{BPos};centrality FT0C (%);Q_{2}^{FV0A} #upoint Q_{2}^{BPos}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FV0AQ2BNeg_CentFT0C", "Q_{2}^{FV0A} #upoint Q_{2}^{BNeg};centrality FT0C (%);Q_{2}^{FV0A} #upoint Q_{2}^{BNeg}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FV0AQ2BTot_CentFT0C", "Q_{2}^{FV0A} #upoint Q_{2}^{BTot};centrality FT0C (%);Q_{2}^{FV0A} #upoint Q_{2}^{BTot}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ2FV0AQ2FT0C_CentFT0C", "Q_{2}^{FV0A} #upoint Q_{2}^{FT0C};centrality FT0C (%);Q_{2}^{FV0A} #upoint Q_{2}^{FT0C}", kTProfile, {{100, 0, 100}}, false); // this is necessary for dimuons + } else if constexpr (nmod == 3) { + fRegistry->add("Event/before/hQ3xFT0M_CentFT0C", "hQ3xFT0M_CentFT0C;centrality FT0C (%);Q_{3,x}^{FT0M}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yFT0M_CentFT0C", "hQ3yFT0M_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0M}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xFT0A_CentFT0C", "hQ3xFT0A_CentFT0C;centrality FT0C (%);Q_{3,x}^{FT0A}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yFT0A_CentFT0C", "hQ3yFT0A_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0A}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xFT0C_CentFT0C", "hQ3xFT0C_CentFT0C;centrality FT0C (%);Q_{3,x}^{FT0C}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yFT0C_CentFT0C", "hQ3yFT0C_CentFT0C;centrality FT0C (%);Q_{3,y}^{FT0C}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xFV0A_CentFT0C", "hQ3xFV0A_CentFT0C;centrality FT0C (%);Q_{3,x}^{FV0A}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yFV0A_CentFT0C", "hQ3yFV0A_CentFT0C;centrality FT0C (%);Q_{3,y}^{FV0A}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xBPos_CentFT0C", "hQ3xBPos_CentFT0C;centrality FT0C (%);Q_{3,x}^{BPos}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yBPos_CentFT0C", "hQ3yBPos_CentFT0C;centrality FT0C (%);Q_{3,y}^{BPos}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xBNeg_CentFT0C", "hQ3xBNeg_CentFT0C;centrality FT0C (%);Q_{3,x}^{BNeg}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yBNeg_CentFT0C", "hQ3yBNeg_CentFT0C;centrality FT0C (%);Q_{3,y}^{BNeg}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3xBTot_CentFT0C", "hQ3xBTot_CentFT0C;centrality FT0C (%);Q_{3,x}^{BTot}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); + fRegistry->add("Event/before/hQ3yBTot_CentFT0C", "hQ3yBTot_CentFT0C;centrality FT0C (%);Q_{3,y}^{BTot}", kTH2D, {{100, 0, 100}, {200, -10, +10}}, false); - fRegistry->add("Event/before/hPrfQ4FT0MQ4BPos_CentFT0C", "Q_{4}^{FT0M} #upoint Q_{4}^{BPos};centrality FT0C (%);Q_{4}^{FT0M} #upoint Q_{4}^{BPos}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ4FT0MQ4BNeg_CentFT0C", "Q_{4}^{FT0M} #upoint Q_{4}^{BNeg};centrality FT0C (%);Q_{4}^{FT0M} #upoint Q_{4}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ4BPosQ4BNeg_CentFT0C", "Q_{4}^{BPos} #upoint Q_{4}^{BNeg};centrality FT0C (%);Q_{4}^{BPos} #upoint Q_{4}^{BNeg}", kTProfile, {{110, 0, 110}}, false); // this is common for FT0M, FT0A, FT0C, FV0A resolution. - fRegistry->add("Event/before/hPrfQ4FT0CQ4BPos_CentFT0C", "Q_{4}^{FT0C} #upoint Q_{4}^{BPos};centrality FT0C (%);Q_{4}^{FT0C} #upoint Q_{4}^{BPos}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ4FT0CQ4BNeg_CentFT0C", "Q_{4}^{FT0C} #upoint Q_{4}^{BNeg};centrality FT0C (%);Q_{4}^{FT0C} #upoint Q_{4}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ4FT0CQ4BTot_CentFT0C", "Q_{4}^{FT0C} #upoint Q_{4}^{BTot};centrality FT0C (%);Q_{4}^{FT0C} #upoint Q_{4}^{BTot}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ4FT0AQ4BPos_CentFT0C", "Q_{4}^{FT0A} #upoint Q_{4}^{BPos};centrality FT0C (%);Q_{4}^{FT0A} #upoint Q_{4}^{BPos}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ4FT0AQ4BNeg_CentFT0C", "Q_{4}^{FT0A} #upoint Q_{4}^{BNeg};centrality FT0C (%);Q_{4}^{FT0A} #upoint Q_{4}^{BNeg}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ4FT0AQ4BTot_CentFT0C", "Q_{4}^{FT0A} #upoint Q_{4}^{BTot};centrality FT0C (%);Q_{4}^{FT0A} #upoint Q_{4}^{BTot}", kTProfile, {{110, 0, 110}}, false); - fRegistry->add("Event/before/hPrfQ4FT0AQ4FT0C_CentFT0C", "Q_{4}^{FT0A} #upoint Q_{4}^{FT0C};centrality FT0C (%);Q_{4}^{FT0A} #upoint Q_{4}^{FT0C}", kTProfile, {{110, 0, 110}}, false); // this is necessary for dimuons + fRegistry->add("Event/before/hEP3FT0M_CentFT0C", "3rd harmonics event plane FT0M;centrality FT0C (%);#Psi_{3}^{FT0M} (rad.)", kTH2D, {{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.)", kTH2D, {{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.)", kTH2D, {{100, 0, 100}, {36, -M_PI_2, +M_PI_2}}, false); + fRegistry->add("Event/before/hEP3FV0A_CentFT0C", "3rd harmonics event plane FV0A;centrality FT0C (%);#Psi_{3}^{FV0A} (rad.)", kTH2D, {{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.)", kTH2D, {{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.)", kTH2D, {{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.)", kTH2D, {{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->add("Event/before/hPrfQ3FV0AQ3BPos_CentFT0C", "Q_{3}^{FV0A} #upoint Q_{3}^{BPos};centrality FT0C (%);Q_{3}^{FV0A} #upoint Q_{3}^{BPos}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FV0AQ3BNeg_CentFT0C", "Q_{3}^{FV0A} #upoint Q_{3}^{BNeg};centrality FT0C (%);Q_{3}^{FV0A} #upoint Q_{3}^{BNeg}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FV0AQ3BTot_CentFT0C", "Q_{3}^{FV0A} #upoint Q_{3}^{BTot};centrality FT0C (%);Q_{3}^{FV0A} #upoint Q_{3}^{BTot}", kTProfile, {{100, 0, 100}}, false); + fRegistry->add("Event/before/hPrfQ3FV0AQ3FT0C_CentFT0C", "Q_{3}^{FV0A} #upoint Q_{3}^{FT0C};centrality FT0C (%);Q_{3}^{FV0A} #upoint Q_{3}^{FT0C}", kTProfile, {{100, 0, 100}}, false); // this is necessary for dimuons } fRegistry->addClone("Event/before/", "Event/after/"); } @@ -185,6 +198,30 @@ void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, co 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()); @@ -193,17 +230,17 @@ void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, co 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 + if constexpr (nmod == 2) { 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 q2bpos = {collision.q2xbpos(), collision.q2ybpos()}; std::array q2bneg = {collision.q2xbneg(), collision.q2ybneg()}; std::array q2btot = {collision.q2xbtot(), collision.q2ybtot()}; @@ -214,6 +251,8 @@ void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, co 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("hQ2xFV0A_CentFT0C"), collision.centFT0C(), collision.q2xfv0a()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ2yFV0A_CentFT0C"), collision.centFT0C(), collision.q2yfv0a()); 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()); @@ -224,6 +263,7 @@ void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, co 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("hEP2FV0A_CentFT0C"), collision.centFT0C(), collision.ep2fv0a()); 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()); @@ -231,17 +271,22 @@ void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, co 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("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("hPrfQ2FT0AQ2FT0C_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2ft0a, q2ft0c)); - } else if constexpr (nmod == 3) { // Q3 + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FV0AQ2BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2fv0a, q2bpos)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FV0AQ2BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2fv0a, q2bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FV0AQ2BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2fv0a, q2btot)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ2FV0AQ2FT0C_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q2fv0a, q2ft0c)); + } else if constexpr (nmod == 3) { std::array q3ft0m = {collision.q3xft0m(), collision.q3yft0m()}; std::array q3ft0a = {collision.q3xft0a(), collision.q3yft0a()}; std::array q3ft0c = {collision.q3xft0c(), collision.q3yft0c()}; + std::array q3fv0a = {collision.q3xfv0a(), collision.q3yfv0a()}; std::array q3bpos = {collision.q3xbpos(), collision.q3ybpos()}; std::array q3bneg = {collision.q3xbneg(), collision.q3ybneg()}; std::array q3btot = {collision.q3xbtot(), collision.q3ybtot()}; @@ -252,6 +297,8 @@ void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, co 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("hQ3xFV0A_CentFT0C"), collision.centFT0C(), collision.q3xfv0a()); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ3yFV0A_CentFT0C"), collision.centFT0C(), collision.q3yfv0a()); 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()); @@ -262,6 +309,7 @@ void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, co 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("hEP3FV0A_CentFT0C"), collision.centFT0C(), collision.ep3ft0a()); 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()); @@ -269,54 +317,18 @@ void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision, co 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)); - } else if constexpr (nmod == 4) { // Q4 - std::array q4ft0m = {collision.q4xft0m(), collision.q4yft0m()}; - std::array q4ft0a = {collision.q4xft0a(), collision.q4yft0a()}; - std::array q4ft0c = {collision.q4xft0c(), collision.q4yft0c()}; - std::array q4bpos = {collision.q4xbpos(), collision.q4ybpos()}; - std::array q4bneg = {collision.q4xbneg(), collision.q4ybneg()}; - std::array q4btot = {collision.q4xbtot(), collision.q4ybtot()}; - - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4xFT0M_CentFT0C"), collision.centFT0C(), collision.q4xft0m()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4yFT0M_CentFT0C"), collision.centFT0C(), collision.q4yft0m()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4xFT0A_CentFT0C"), collision.centFT0C(), collision.q4xft0a()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4yFT0A_CentFT0C"), collision.centFT0C(), collision.q4yft0a()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4xFT0C_CentFT0C"), collision.centFT0C(), collision.q4xft0c()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4yFT0C_CentFT0C"), collision.centFT0C(), collision.q4yft0c()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4xBPos_CentFT0C"), collision.centFT0C(), collision.q4xbpos()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4yBPos_CentFT0C"), collision.centFT0C(), collision.q4ybpos()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4xBNeg_CentFT0C"), collision.centFT0C(), collision.q4xbneg()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4yBNeg_CentFT0C"), collision.centFT0C(), collision.q4ybneg()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4xBTot_CentFT0C"), collision.centFT0C(), collision.q4xbtot()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hQ4yBTot_CentFT0C"), collision.centFT0C(), collision.q4ybtot()); - - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP4FT0M_CentFT0C"), collision.centFT0C(), collision.ep4ft0m()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP4FT0A_CentFT0C"), collision.centFT0C(), collision.ep4ft0a()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP4FT0C_CentFT0C"), collision.centFT0C(), collision.ep4ft0c()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP4BPos_CentFT0C"), collision.centFT0C(), collision.ep4bpos()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP4BNeg_CentFT0C"), collision.centFT0C(), collision.ep4bneg()); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hEP4BTot_CentFT0C"), collision.centFT0C(), collision.ep4btot()); - - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0MQ4BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0m, q4bpos)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0MQ4BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0m, q4bneg)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4BPosQ4BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4bpos, q4bneg)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0AQ4BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0a, q4bpos)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0AQ4BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0a, q4bneg)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0AQ4BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0a, q4btot)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0CQ4BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0c, q4bpos)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0CQ4BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0c, q4bneg)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0CQ4BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0c, q4btot)); - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ4FT0AQ4FT0C_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q4ft0a, q4ft0c)); + 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("hPrfQ3FV0AQ3FT0C_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3fv0a, q3ft0c)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FV0AQ3BPos_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3fv0a, q3bpos)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FV0AQ3BNeg_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3fv0a, q3bneg)); + fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hPrfQ3FV0AQ3BTot_CentFT0C"), collision.centFT0C(), RecoDecay::dotProd(q3fv0a, q3btot)); } } - } // 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 index 1fa83c60240..20b38399979 100644 --- a/PWGEM/Dilepton/Utils/EventMixingHandler.h +++ b/PWGEM/Dilepton/Utils/EventMixingHandler.h @@ -47,6 +47,11 @@ class EventMixingHandler void SetNdepth(int ndepth) { fNdepth = ndepth; } + void ReserveNTracksPerCollision(U key_df_collision, int ntrack) + { + fMap_Tracks_per_collision[key_df_collision].reserve(ntrack); + } + void AddTrackToEventPool(U key_df_collision, V obj) { fMap_Tracks_per_collision[key_df_collision].emplace_back(obj); diff --git a/PWGEM/Dilepton/Utils/MCUtilities.h b/PWGEM/Dilepton/Utils/MCUtilities.h index 668f1056e75..c75ea5d7f9e 100644 --- a/PWGEM/Dilepton/Utils/MCUtilities.h +++ b/PWGEM/Dilepton/Utils/MCUtilities.h @@ -15,9 +15,12 @@ #ifndef PWGEM_DILEPTON_UTILS_MCUTILITIES_H_ #define PWGEM_DILEPTON_UTILS_MCUTILITIES_H_ +#include "Framework/AnalysisDataModel.h" +#include "Framework/Logger.h" + +#include #include #include -#include //_______________________________________________________________________ namespace o2::aod::pwgem::dilepton::utils::mcutil @@ -31,6 +34,163 @@ 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 +bool isCharmonia(T const& track) +{ + if (std::abs(track.pdgCode()) < 100) { + return false; + } + + std::string pdgStr = std::to_string(std::abs(track.pdgCode())); + int n = pdgStr.length(); + int pdg3 = std::stoi(pdgStr.substr(n - 3, 3)); + + if (pdg3 == 441 || pdg3 == 443 || pdg3 == 445 || pdg3 == 447) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isCharmMeson(T const& track) +{ + if (isCharmonia(track)) { + return false; + } + + if (400 < std::abs(track.pdgCode()) && std::abs(track.pdgCode()) < 500) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isCharmBaryon(T const& track) +{ + if (4000 < std::abs(track.pdgCode()) && std::abs(track.pdgCode()) < 5000) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isBottomonia(T const& track) +{ + if (std::abs(track.pdgCode()) < 100) { + return false; + } + + std::string pdgStr = std::to_string(std::abs(track.pdgCode())); + int n = pdgStr.length(); + int pdg3 = std::stoi(pdgStr.substr(n - 3, 3)); + + if (pdg3 == 551 || pdg3 == 553 || pdg3 == 555 || pdg3 == 557) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isBeautyMeson(T const& track) +{ + if (isBottomonia(track)) { + return false; + } + + if (500 < std::abs(track.pdgCode()) && std::abs(track.pdgCode()) < 600) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isBeautyBaryon(T const& track) +{ + if (5000 < std::abs(track.pdgCode()) && std::abs(track.pdgCode()) < 6000) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isWeakDecayFromCharmHadron(T const& mcParticle, U const& mcParticles) +{ + // require that the direct mother is charm hadron via semileptonic. e.g. hc->e, not hc->X->pi0->eegamma + if (!mcParticle.has_mothers()) { + return false; + } + // if (mcParticle.getProcess() != 4) { // weak decay + // return false; + // } + auto mp = mcParticles.iteratorAt(mcParticle.mothersIds()[0]); + if (isCharmMeson(mp) || isCharmBaryon(mp)) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool isWeakDecayFromBeautyHadron(T const& mcParticle, U const& mcParticles) +{ + // require that the direct mother is beauty hadron via semileptonice decay. e.g. hb->e, not hb->X->pi0->eegamma + if (!mcParticle.has_mothers()) { + return false; + } + // if (mcParticle.getProcess() != 4) { // weak decay + // return false; + // } + auto mp = mcParticles.iteratorAt(mcParticle.mothersIds()[0]); + if (isBeautyMeson(mp) || isBeautyBaryon(mp)) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ //_______________________________________________________________________ template int FindCommonMotherFrom2ProngsWithoutPDG(TMCParticle1 const& p1, TMCParticle2 const& p2) @@ -186,6 +346,14 @@ int FindCommonMotherFrom3Prongs(TMCParticle1 const& p1, TMCParticle2 const& p2, } //_______________________________________________________________________ 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) { if (!p.has_mothers()) { @@ -194,14 +362,14 @@ 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) { + if (std::abs(mp_tmp.pdgCode()) < 1e+9 && (std::to_string(std::abs(mp_tmp.pdgCode()))[std::to_string(std::abs(mp_tmp.pdgCode())).length() - 2] == '5' && std::to_string(std::abs(mp_tmp.pdgCode()))[std::to_string(std::abs(mp_tmp.pdgCode())).length() - 3] == '5') && std::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); - if (abs(mp.pdgCode()) < 1e+9 && (std::to_string(abs(mp.pdgCode()))[std::to_string(abs(mp.pdgCode())).length() - 3] == '5' || std::to_string(abs(mp.pdgCode()))[std::to_string(abs(mp.pdgCode())).length() - 4] == '5')) { + if (std::abs(mp.pdgCode()) < 1e+9 && (std::to_string(std::abs(mp.pdgCode()))[std::to_string(std::abs(mp.pdgCode())).length() - 3] == '5' || std::to_string(std::abs(mp.pdgCode()))[std::to_string(std::abs(mp.pdgCode())).length() - 4] == '5')) { return motherid; } if (mp.has_mothers()) { @@ -217,6 +385,7 @@ int IsFromBeauty(TMCParticle const& p, TMCParticles const& mcparticles) return -999; } +//_______________________________________________________________________ template int IsFromCharm(TMCParticle const& p, TMCParticles const& mcparticles) { @@ -226,13 +395,13 @@ 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) { + if (std::abs(mp_tmp.pdgCode()) < 1e+9 && (std::to_string(std::abs(mp_tmp.pdgCode()))[std::to_string(std::abs(mp_tmp.pdgCode())).length() - 2] == '4' && std::to_string(std::abs(mp_tmp.pdgCode()))[std::to_string(std::abs(mp_tmp.pdgCode())).length() - 3] == '4') && std::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); - if (abs(mp.pdgCode()) < 1e+9 && (std::to_string(abs(mp.pdgCode()))[std::to_string(abs(mp.pdgCode())).length() - 3] == '4' || std::to_string(abs(mp.pdgCode()))[std::to_string(abs(mp.pdgCode())).length() - 4] == '4')) { + if (std::abs(mp.pdgCode()) < 1e+9 && (std::to_string(std::abs(mp.pdgCode()))[std::to_string(std::abs(mp.pdgCode())).length() - 3] == '4' || std::to_string(std::abs(mp.pdgCode()))[std::to_string(std::abs(mp.pdgCode())).length() - 4] == '4')) { return motherid; } if (mp.has_mothers()) { @@ -247,7 +416,97 @@ int IsFromCharm(TMCParticle const& p, TMCParticles const& mcparticles) return -999; } +//_______________________________________________________________________ +template +bool isFlavorOscillationB(TMCParticle const& mcParticle) +{ + if ((std::abs(mcParticle.pdgCode()) == 511 || std::abs(mcParticle.pdgCode()) == 531) && mcParticle.getGenStatusCode() == 92) { + return true; + } else { + return false; + } +} +//_______________________________________________________________________ +template +bool findFlavorOscillationB(TMCParticle const& mcParticle, TMCParticles const& mcParticles) +{ + // B0 or B0s can oscillate. + if (!mcParticle.has_mothers()) { + return false; + } + // store all mother1 relation + int motherid1 = mcParticle.mothersIds()[0]; // first mother index + while (motherid1 > -1) { + if (motherid1 < mcParticles.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcParticles.iteratorAt(motherid1); + if (isFlavorOscillationB(mp)) { + return true; + } + + if (mp.has_mothers()) { + motherid1 = mp.mothersIds()[0]; + } else { + motherid1 = -999; + } + } else { + LOGF(info, "Mother label(%d) exceeds the McParticles size(%d)", motherid1, mcParticles.size()); + } + } + return false; +} +//_______________________________________________________________________ +template +int find1stHadron(TMCParticle const& mcParticle, TMCParticles const& mcParticles) +{ + // find 1st hadron in decay chain except beam. + if (!mcParticle.has_mothers()) { + return -1; + } + + // store all mother1 relation + std::vector mothers_id; + std::vector mothers_pdg; + + int motherid1 = mcParticle.mothersIds()[0]; // first mother index + while (motherid1 > -1) { + if (motherid1 < mcParticles.size()) { // protect against bad mother indices. why is this needed? + auto mp = mcParticles.iteratorAt(motherid1); + mothers_id.emplace_back(motherid1); + mothers_pdg.emplace_back(mp.pdgCode()); + + if (mp.has_mothers()) { + motherid1 = mp.mothersIds()[0]; + } else { + motherid1 = -999; + } + } else { + LOGF(info, "Mother label(%d) exceeds the McParticles size(%d)", motherid1, mcParticles.size()); + } + } + + int counter = 0; + for (const auto& pdg : mothers_pdg) { + if (std::abs(pdg) <= 6 || std::abs(pdg) == 21 || (std::abs(pdg) == 2212 && counter == static_cast(mothers_pdg.size() - 1)) || (std::abs(pdg) > 1e+9 && counter == static_cast(mothers_pdg.size() - 1))) { // quarks or gluon or proton or ion beam + break; + } + counter++; + } + + int hadronId = -1; + if (counter == 0) { // particle directly from beam // only for protection. + hadronId = mcParticle.globalIndex(); + } else { + hadronId = mothers_id[counter - 1]; + } + + mothers_id.clear(); + mothers_id.shrink_to_fit(); + mothers_pdg.clear(); + mothers_pdg.shrink_to_fit(); + return hadronId; +} +//_______________________________________________________________________ template int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcparticles) { @@ -268,6 +527,7 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp auto mp = mcparticles.iteratorAt(motherid1); mothers_id1.emplace_back(motherid1); mothers_pdg1.emplace_back(mp.pdgCode()); + // LOGF(info, "mp1.globalIndex() = %d, mp1.pdgCode() = %d, mp1.getGenStatusCode() = %d", mp.globalIndex(), mp.pdgCode(), mp.getGenStatusCode()); if (mp.has_mothers()) { motherid1 = mp.mothersIds()[0]; @@ -288,6 +548,7 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp auto mp = mcparticles.iteratorAt(motherid2); mothers_id2.emplace_back(motherid2); mothers_pdg2.emplace_back(mp.pdgCode()); + // LOGF(info, "mp2.globalIndex() = %d, mp2.pdgCode() = %d, mp2.getGenStatusCode() = %d", mp.globalIndex(), mp.pdgCode(), mp.getGenStatusCode()); if (mp.has_mothers()) { motherid2 = mp.mothersIds()[0]; @@ -299,14 +560,21 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp } } - 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; + // require correlation between q-qbar. (not q-q) // need statusCode - if (is_direct_from_b1 && is_direct_from_b2 && p1.pdgCode() * p2.pdgCode() < 0) { + auto mpfh1 = mcparticles.iteratorAt(find1stHadron(p1, mcparticles)); + auto mpfh2 = mcparticles.iteratorAt(find1stHadron(p2, mcparticles)); + bool isFOat1stDecay1 = isFlavorOscillationB(mpfh1); // oscillation occured at 1st hb decay. + bool isFOat1stDecay2 = isFlavorOscillationB(mpfh2); // oscillation occured at 1st hb decay. + + bool is_direct_from_b1 = isWeakDecayFromBeautyHadron(p1, mcparticles); + bool is_direct_from_b2 = isWeakDecayFromBeautyHadron(p2, mcparticles); + bool is_prompt_c1 = isWeakDecayFromCharmHadron(p1, mcparticles) && IsFromBeauty(p1, mcparticles) < 0; + bool is_prompt_c2 = isWeakDecayFromCharmHadron(p2, mcparticles) && IsFromBeauty(p2, mcparticles) < 0; + bool is_c_from_b1 = isWeakDecayFromCharmHadron(p1, mcparticles) && IsFromBeauty(p1, mcparticles) > 0; + bool is_c_from_b2 = isWeakDecayFromCharmHadron(p2, mcparticles) && IsFromBeauty(p2, mcparticles) > 0; + + if (is_prompt_c1 && is_prompt_c2 && mpfh1.pdgCode() * mpfh2.pdgCode() < 0) { // charmed mesons never oscillate. Be careful with D(2007)*0 -> D0 e+ e- mothers_id1.clear(); mothers_pdg1.clear(); mothers_id2.clear(); @@ -315,9 +583,14 @@ 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 + return static_cast(EM_HFeeType::kCe_Ce); // cc->ee, decay type = 0 } - if (is_prompt_c1 && is_prompt_c2 && p1.pdgCode() * p2.pdgCode() < 0) { + + bool b2l_b2l_case0 = is_direct_from_b1 && is_direct_from_b2 && mpfh1.pdgCode() * mpfh2.pdgCode() < 0 && !isFOat1stDecay1 && !isFOat1stDecay2; // bbbar -> ll ULS + bool b2l_b2l_case1 = is_direct_from_b1 && is_direct_from_b2 && mpfh1.pdgCode() * mpfh2.pdgCode() > 0 && static_cast(isFOat1stDecay1 ^ isFOat1stDecay2); // bbbar -> ll LS + bool b2l_b2l_case2 = is_direct_from_b1 && is_direct_from_b2 && mpfh1.pdgCode() * mpfh2.pdgCode() < 0 && isFOat1stDecay1 && isFOat1stDecay2; // bbbar -> ll ULS + + if (b2l_b2l_case0 || b2l_b2l_case1 || b2l_b2l_case2) { mothers_id1.clear(); mothers_pdg1.clear(); mothers_id2.clear(); @@ -326,9 +599,14 @@ 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 + return static_cast(EM_HFeeType::kBe_Be); // bb->ee, decay type = 2 } - if (is_c_from_b1 && is_c_from_b2 && p1.pdgCode() * p2.pdgCode() < 0) { + + bool b2c2l_b2c2l_case0 = is_c_from_b1 && is_c_from_b2 && mpfh1.pdgCode() * mpfh2.pdgCode() < 0 && !isFOat1stDecay1 && !isFOat1stDecay2; // bbbar -> ll ULS + bool b2c2l_b2c2l_case1 = is_c_from_b1 && is_c_from_b2 && mpfh1.pdgCode() * mpfh2.pdgCode() > 0 && static_cast(isFOat1stDecay1 ^ isFOat1stDecay2); // bbbar -> ll LS + bool b2c2l_b2c2l_case2 = is_c_from_b1 && is_c_from_b2 && mpfh1.pdgCode() * mpfh2.pdgCode() < 0 && isFOat1stDecay1 && isFOat1stDecay2; // bbbar -> ll ULS + + if (b2c2l_b2c2l_case0 || b2c2l_b2c2l_case1 || b2c2l_b2c2l_case2) { mothers_id1.clear(); mothers_pdg1.clear(); mothers_id2.clear(); @@ -339,53 +617,44 @@ int IsHF(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcp mothers_pdg2.shrink_to_fit(); return static_cast(EM_HFeeType::kBCe_BCe); // b->c->e and b->c->e, decay type = 1 } + 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(); - 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(); - mothers_pdg2.clear(); - mothers_id1.shrink_to_fit(); - mothers_pdg1.shrink_to_fit(); - mothers_id2.shrink_to_fit(); - mothers_pdg2.shrink_to_fit(); - return static_cast(EM_HFeeType::kBCe_Be_SameB); // b->c->e and b->e, decay type = 3. this should happen only in ULS. - } + // No pair sign oscillation due to B0(s) oscillation for the same mother. + for (const auto& mid1 : mothers_id1) { + for (const auto& mid2 : mothers_id2) { + if (mid1 == mid2) { + auto common_mp = mcparticles.iteratorAt(mid1); + int mp_pdg = common_mp.pdgCode(); + bool is_mp_diquark = (1100 < std::abs(mp_pdg) && std::abs(mp_pdg) < 5600) && std::to_string(mp_pdg)[std::to_string(mp_pdg).length() - 2] == '0'; + if (!is_mp_diquark && std::abs(mp_pdg) < 1e+9 && (std::to_string(std::abs(mp_pdg))[std::to_string(std::abs(mp_pdg)).length() - 3] == '5' || std::to_string(std::abs(mp_pdg))[std::to_string(std::abs(mp_pdg)).length() - 4] == '5')) { + mothers_id1.clear(); + mothers_pdg1.clear(); + mothers_id2.clear(); + mothers_pdg2.clear(); + mothers_id1.shrink_to_fit(); + mothers_pdg1.shrink_to_fit(); + mothers_id2.shrink_to_fit(); + mothers_pdg2.shrink_to_fit(); + return static_cast(EM_HFeeType::kBCe_Be_SameB); // b->c->e and b->e, decay type = 3 } - } // end of motherid2 - } // end of motherid1 - } else { // LS - bool is_same_mother_found = false; - 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(); - 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 - if (!is_same_mother_found) { - mothers_id1.clear(); - mothers_pdg1.clear(); - mothers_id2.clear(); - mothers_pdg2.clear(); - mothers_id1.shrink_to_fit(); - mothers_pdg1.shrink_to_fit(); - mothers_id2.shrink_to_fit(); - mothers_pdg2.shrink_to_fit(); - return static_cast(EM_HFeeType::kBCe_Be_DiffB); // b->c->e and b->e, decay type = 4. this should happen only in LS. But, this may happen, when ele/pos is reconstructed as pos/ele wrongly. and create LS pair - } + } + } // end of motherid2 + } // end of motherid1 + + bool b2c2l_b2l_diffb_case0 = mpfh1.pdgCode() * mpfh2.pdgCode() < 0 && !isFOat1stDecay1 && !isFOat1stDecay2; // bbbar -> ll LS + bool b2c2l_b2l_diffb_case1 = mpfh1.pdgCode() * mpfh2.pdgCode() > 0 && static_cast(isFOat1stDecay1 ^ isFOat1stDecay2); // bbbar -> ll ULS + bool b2c2l_b2l_diffb_case2 = mpfh1.pdgCode() * mpfh2.pdgCode() < 0 && isFOat1stDecay1 && isFOat1stDecay2; // bbbar -> ll LS + + if (b2c2l_b2l_diffb_case0 || b2c2l_b2l_diffb_case1 || b2c2l_b2l_diffb_case2) { + mothers_id1.clear(); + mothers_pdg1.clear(); + mothers_id2.clear(); + mothers_pdg2.clear(); + mothers_id1.shrink_to_fit(); + mothers_pdg1.shrink_to_fit(); + mothers_id2.shrink_to_fit(); + mothers_pdg2.shrink_to_fit(); + return static_cast(EM_HFeeType::kBCe_Be_DiffB); // b->c->e and b->e, decay type = 4 } } @@ -399,7 +668,7 @@ 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 @@ -416,7 +685,7 @@ int searchMothers(T& p, U& mcParticles, int pdg, bool equal) } 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! + } else if ((80 < std::abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) && std::abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) < 90) || (100 < std::abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) && std::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); } @@ -434,14 +703,16 @@ int searchMothers(T& p, U& mcParticles, int pdg, bool equal) 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 + // if (std::abs(mpdg) == pdg && mpdg * p.pdgCode() > 0) { // check for quark + if (std::abs(mpdg) == pdg) { // check for quark to allow for beauty and charm + oscillation + 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 + //} else if ((static_cast(std::abs(mpdg) / 100) == pdg || static_cast(std::abs(mpdg) / 1000) == pdg) && mpdg * p.pdgCode() > 0) { // check for other mothers with flavour content + } else if ((static_cast(std::abs(mpdg) / 100) == pdg || static_cast(std::abs(mpdg) / 1000) == pdg)) { // check for other mothers with flavour content to allow for beauty and charm + 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; } @@ -460,7 +731,7 @@ int searchMothers(T& p, U& mcParticles, int pdg, bool equal) int quark_id = -1; for (int i : allmothersids) { auto mother = mcParticles.iteratorAt(i); - int mpdg = abs(mother.pdgCode()); + int mpdg = std::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."; @@ -479,6 +750,7 @@ int searchMothers(T& p, U& mcParticles, int pdg, bool equal) return -1; } +//_______________________________________________________________________ template int findHFOrigin(T& p, U& mcParticles, int pdg) { @@ -490,7 +762,7 @@ int findHFOrigin(T& p, U& mcParticles, int pdg) 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 @@ -499,45 +771,6 @@ bool checkFromSameQuarkPair(T& p1, T& p2, U& mcParticles, int 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::utils::mcutil 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..5ec9756b5a9 100644 --- a/PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h +++ b/PWGEM/Dilepton/Utils/MlResponseDielectronSingleTrack.h @@ -17,40 +17,85 @@ #ifndef PWGEM_DILEPTON_UTILS_MLRESPONSEDIELECTRONSINGLETRACK_H_ #define PWGEM_DILEPTON_UTILS_MLRESPONSEDIELECTRONSINGLETRACK_H_ +#include "Tools/ML/MlResponse.h" + #include #include #include -#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_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 GETTER1 and GETTER2 from track. +#define CHECK_AND_FILL_DIELECTRON_SINGLE_TRACK_RELDIFF(FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesDielectronSingleTrack::FEATURE): { \ + inputFeature = (track.GETTER2() - track.GETTER1()) / track.GETTER1(); \ + 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,24 +109,104 @@ enum class InputFeaturesDielectronSingleTrack : uint8_t { dcaResXY, dcaResZ, tpcNClsFindable, - tpcNClsFound, - tpcNClsCrossedRows, + tpcNClsFindableMinusFound, + tpcNClsFindableMinusCrossedRows, + tpcNClsShared, tpcChi2NCl, tpcInnerParam, + reldiffp, tpcSignal, tpcNSigmaEl, - tpcNSigmaMu, + // tpcNSigmaMu, tpcNSigmaPi, tpcNSigmaKa, tpcNSigmaPr, beta, tofNSigmaEl, - tofNSigmaMu, + // tofNSigmaMu, tofNSigmaPi, tofNSigmaKa, tofNSigmaPr, + tpctofNSigmaEl, + // tpctofNSigmaMu, + tpctofNSigmaPi, + tpctofNSigmaKa, + tpctofNSigmaPr, + itsClusterSizes, + itsChi2NCl, + tofChi2, + detectorMap, + x, + alpha, + y, + z, + snp, + tgl, + isAssociatedToMPC, + tpcNClsFound, + tpcNClsPID, + 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 +218,155 @@ 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_RELDIFF(reldiffp, p, 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(tpcNClsPID); + 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,31 +381,117 @@ 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(reldiffp), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcSignal), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNSigmaEl), - FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNSigmaMu), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNSigmaMu), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNSigmaPi), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNSigmaKa), FILL_MAP_DIELECTRON_SINGLE_TRACK(tpcNSigmaPr), FILL_MAP_DIELECTRON_SINGLE_TRACK(beta), FILL_MAP_DIELECTRON_SINGLE_TRACK(tofNSigmaEl), - FILL_MAP_DIELECTRON_SINGLE_TRACK(tofNSigmaMu), + // FILL_MAP_DIELECTRON_SINGLE_TRACK(tofNSigmaMu), 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(tpcNClsPID), + 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_SINGLE_TRACK_RELDIFF +#undef CHECK_AND_FILL_DIELECTRON_COLLISION #endif // PWGEM_DILEPTON_UTILS_MLRESPONSEDIELECTRONSINGLETRACK_H_ diff --git a/PWGEM/Dilepton/Utils/MlResponseO2Track.h b/PWGEM/Dilepton/Utils/MlResponseO2Track.h new file mode 100644 index 00000000000..d898d9da5f6 --- /dev/null +++ b/PWGEM/Dilepton/Utils/MlResponseO2Track.h @@ -0,0 +1,339 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MlResponseO2Track.h +/// \brief Class to compute the ML response for dielectron analyses at the single track level +/// \author Daniel Samitz , SMI Vienna +/// Elisa Meninno, , SMI Vienna + +#ifndef PWGEM_DILEPTON_UTILS_MLRESPONSEO2TRACK_H_ +#define PWGEM_DILEPTON_UTILS_MLRESPONSEO2TRACK_H_ + +#include "Tools/ML/MlResponse.h" + +#include +#include +#include + +// 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_O2_TRACK(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesO2Track::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_O2_TRACK(GETTER) \ + case static_cast(InputFeaturesO2Track::GETTER): { \ + inputFeature = 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 GETTER=FEATURE from track +#define CHECK_AND_FILL_O2_TRACKPARCOV(FEATURE, GETTER) \ + case static_cast(InputFeaturesO2Track::FEATURE): { \ + inputFeature = trackParCov.GETTER(); \ + break; \ + } + +// mean ITS cluster size +#define CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE(FEATURE, v1, v2) \ + case static_cast(InputFeaturesO2Track::FEATURE): { \ + int nsize = 0; \ + int ncls = 0; \ + for (int il = v1; il < v2; il++) { \ + nsize += track.itsClsSizeInLayer(il); \ + if (nsize > 0) { \ + ncls++; \ + } \ + } \ + inputFeature = static_cast(nsize) / static_cast(ncls); \ + break; \ + } + +// mean ITS cluster size x cos(lambda) +#define CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE_COS(FEATURE, v1, v2) \ + case static_cast(InputFeaturesO2Track::FEATURE): { \ + int nsize = 0; \ + int ncls = 0; \ + for (int il = v1; il < v2; il++) { \ + nsize += track.itsClsSizeInLayer(il); \ + if (nsize > 0) { \ + ncls++; \ + } \ + } \ + inputFeature = static_cast(nsize) / static_cast(ncls) * std::cos(std::atan(trackParCov.getTgl())); \ + break; \ + } + +// TPC+TOF combined nSigma +#define CHECK_AND_FILL_O2_TRACK_TPCTOF(FEATURE, GETTER1, GETTER2, GETTER3) \ + case static_cast(InputFeaturesO2Track::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 from track and applying a sqrt +#define CHECK_AND_FILL_O2_TRACK_SQRT(FEATURE, GETTER) \ + case static_cast(InputFeaturesO2Track::FEATURE): { \ + 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_O2_TRACK_COS(FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesO2Track::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 GETTER1 and GETTER2 from track. +#define CHECK_AND_FILL_O2_TRACK_RELDIFF(FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesO2Track::FEATURE): { \ + inputFeature = (track.GETTER2() - trackParCov.GETTER1()) / trackParCov.GETTER1(); \ + 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(InputFeaturesO2Track::GETTER): { \ + inputFeature = collision.GETTER(); \ + break; \ + } + +namespace o2::analysis +{ +// possible input features for ML +enum class InputFeaturesO2Track : uint8_t { + tpcInnerParam, + reldiffp, + tpcSignal, + tpcNSigmaEl, + // tpcNSigmaMu, + tpcNSigmaPi, + tpcNSigmaKa, + tpcNSigmaPr, + beta, + tofNSigmaEl, + // tofNSigmaMu, + tofNSigmaPi, + tofNSigmaKa, + tofNSigmaPr, + tpctofNSigmaEl, + // tpctofNSigmaMu, + tpctofNSigmaPi, + tpctofNSigmaKa, + tpctofNSigmaPr, + tpcNClsFound, + tpcNClsPID, + tpcNClsCrossedRows, + tpcChi2NCl, + hasITS, + hasTPC, + hasTRD, + hasTOF, + tgl, + p, + itsClusterSizes, + meanClusterSizeITS, + meanClusterSizeITSib, + meanClusterSizeITSob, + meanClusterSizeITSCos, + meanClusterSizeITSibCos, + meanClusterSizeITSobCos, + posZ, + numContrib, + trackOccupancyInTimeRange, + ft0cOccupancyInTimeRange, +}; + +template +class MlResponseO2Track : public MlResponse +{ + public: + /// Default constructor + MlResponseO2Track() = default; + /// Default destructor + virtual ~MlResponseO2Track() = default; + + template + float return_feature(uint8_t idx, T const& track, U const& trackParCov, V const& collision) + { + float inputFeature = 0.; + switch (idx) { + CHECK_AND_FILL_O2_TRACK(tpcInnerParam); + CHECK_AND_FILL_O2_TRACK_RELDIFF(reldiffp, getP, tpcInnerParam); + CHECK_AND_FILL_O2_TRACK(tpcSignal); + CHECK_AND_FILL_O2_TRACK(tpcNSigmaEl); + // CHECK_AND_FILL_O2_TRACK(tpcNSigmaMu); + CHECK_AND_FILL_O2_TRACK(tpcNSigmaPi); + CHECK_AND_FILL_O2_TRACK(tpcNSigmaKa); + CHECK_AND_FILL_O2_TRACK(tpcNSigmaPr); + CHECK_AND_FILL_O2_TRACK(beta); + CHECK_AND_FILL_O2_TRACK(tofNSigmaEl); + // CHECK_AND_FILL_O2_TRACK(tofNSigmaMu); + CHECK_AND_FILL_O2_TRACK(tofNSigmaPi); + CHECK_AND_FILL_O2_TRACK(tofNSigmaKa); + CHECK_AND_FILL_O2_TRACK(tofNSigmaPr); + CHECK_AND_FILL_O2_TRACK_TPCTOF(tpctofNSigmaEl, tpcNSigmaEl, tofNSigmaEl, hasTOF); + // CHECK_AND_FILL_O2_TRACK_TPCTOF(tpctofNSigmaMu, tpcNSigmaMu, tofNSigmaMu, hasTOF); + CHECK_AND_FILL_O2_TRACK_TPCTOF(tpctofNSigmaPi, tpcNSigmaPi, tofNSigmaPi, hasTOF); + CHECK_AND_FILL_O2_TRACK_TPCTOF(tpctofNSigmaKa, tpcNSigmaKa, tofNSigmaKa, hasTOF); + CHECK_AND_FILL_O2_TRACK_TPCTOF(tpctofNSigmaPr, tpcNSigmaPr, tofNSigmaPr, hasTOF); + CHECK_AND_FILL_O2_TRACK(tpcNClsFound); + CHECK_AND_FILL_O2_TRACK(tpcNClsPID); + CHECK_AND_FILL_O2_TRACK(tpcNClsCrossedRows); + CHECK_AND_FILL_O2_TRACK(tpcChi2NCl); + CHECK_AND_FILL_O2_TRACK(hasITS); + CHECK_AND_FILL_O2_TRACK(hasTPC); + CHECK_AND_FILL_O2_TRACK(hasTRD); + CHECK_AND_FILL_O2_TRACK(hasTOF); + CHECK_AND_FILL_O2_TRACKPARCOV(tgl, getTgl); + CHECK_AND_FILL_O2_TRACKPARCOV(p, getP); + CHECK_AND_FILL_O2_TRACK(itsClusterSizes); + CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE(meanClusterSizeITS, 0, 7); + CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE(meanClusterSizeITSib, 0, 3); + CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE(meanClusterSizeITSob, 3, 7); + CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE_COS(meanClusterSizeITSCos, 0, 7); + CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE_COS(meanClusterSizeITSibCos, 0, 3); + CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE_COS(meanClusterSizeITSobCos, 3, 7); + CHECK_AND_FILL_DIELECTRON_COLLISION(posZ); + CHECK_AND_FILL_DIELECTRON_COLLISION(numContrib); + CHECK_AND_FILL_DIELECTRON_COLLISION(trackOccupancyInTimeRange); + CHECK_AND_FILL_DIELECTRON_COLLISION(ft0cOccupancyInTimeRange); + } + return inputFeature; + } + + /// Method to get the input features vector needed for ML inference + /// \param track is the single track, \param collision is the collision + /// \return inputFeatures vector + template + std::vector getInputFeatures(T const& track, U const& trackParCov, V const& collision) + { + std::vector inputFeatures; + for (const auto& idx : MlResponse::mCachedIndices) { + float inputFeature = return_feature(idx, track, trackParCov, 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& trackParCov, V const& collision) + { + return return_feature(mCachedIndexBinning, track, trackParCov, 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() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_O2_TRACK(tpcInnerParam), + FILL_MAP_O2_TRACK(reldiffp), + FILL_MAP_O2_TRACK(tpcSignal), + FILL_MAP_O2_TRACK(tpcNSigmaEl), + // FILL_MAP_O2_TRACK(tpcNSigmaMu), + FILL_MAP_O2_TRACK(tpcNSigmaPi), + FILL_MAP_O2_TRACK(tpcNSigmaKa), + FILL_MAP_O2_TRACK(tpcNSigmaPr), + FILL_MAP_O2_TRACK(beta), + FILL_MAP_O2_TRACK(tofNSigmaEl), + // FILL_MAP_O2_TRACK(tofNSigmaMu), + FILL_MAP_O2_TRACK(tofNSigmaPi), + FILL_MAP_O2_TRACK(tofNSigmaKa), + FILL_MAP_O2_TRACK(tofNSigmaPr), + FILL_MAP_O2_TRACK(tpctofNSigmaEl), + // FILL_MAP_O2_TRACK(tpctofNSigmaMu), + FILL_MAP_O2_TRACK(tpctofNSigmaPi), + FILL_MAP_O2_TRACK(tpctofNSigmaKa), + FILL_MAP_O2_TRACK(tpctofNSigmaPr), + FILL_MAP_O2_TRACK(tpcNClsFound), + FILL_MAP_O2_TRACK(tpcNClsPID), + FILL_MAP_O2_TRACK(tpcNClsCrossedRows), + FILL_MAP_O2_TRACK(tpcChi2NCl), + FILL_MAP_O2_TRACK(hasITS), + FILL_MAP_O2_TRACK(hasTPC), + FILL_MAP_O2_TRACK(hasTRD), + FILL_MAP_O2_TRACK(hasTOF), + FILL_MAP_O2_TRACK(tgl), + FILL_MAP_O2_TRACK(p), + FILL_MAP_O2_TRACK(itsClusterSizes), + FILL_MAP_O2_TRACK(meanClusterSizeITS), + FILL_MAP_O2_TRACK(meanClusterSizeITSib), + FILL_MAP_O2_TRACK(meanClusterSizeITSob), + FILL_MAP_O2_TRACK(meanClusterSizeITSCos), + FILL_MAP_O2_TRACK(meanClusterSizeITSibCos), + FILL_MAP_O2_TRACK(meanClusterSizeITSobCos), + FILL_MAP_O2_TRACK(posZ), + FILL_MAP_O2_TRACK(numContrib), + FILL_MAP_O2_TRACK(trackOccupancyInTimeRange), + FILL_MAP_O2_TRACK(ft0cOccupancyInTimeRange)}; + } + + uint8_t mCachedIndexBinning; // index correspondance between configurable and available input features +}; + +} // namespace o2::analysis + +#undef FILL_MAP_O2_TRACK +#undef CHECK_AND_FILL_O2_TRACK +#undef CHECK_AND_FILL_O2_TRACKPARCOV +#undef CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE +#undef CHECK_AND_FILL_O2_TRACK_MEAN_ITSCLUSTER_SIZE_COS +#undef CHECK_AND_FILL_O2_TRACK_SQRT +#undef CHECK_AND_FILL_O2_TRACK_COS +#undef CHECK_AND_FILL_O2_TRACK_TPCTOF +#undef CHECK_AND_FILL_O2_TRACK_RELDIFF +#undef CHECK_AND_FILL_DIELECTRON_COLLISION + +#endif // PWGEM_DILEPTON_UTILS_MLRESPONSEO2TRACK_H_ diff --git a/PWGEM/Dilepton/Utils/MomentumSmearer.h b/PWGEM/Dilepton/Utils/MomentumSmearer.h index 002e7d6d247..d0e73ee971f 100644 --- a/PWGEM/Dilepton/Utils/MomentumSmearer.h +++ b/PWGEM/Dilepton/Utils/MomentumSmearer.h @@ -15,17 +15,27 @@ #ifndef PWGEM_DILEPTON_UTILS_MOMENTUMSMEARER_H_ #define PWGEM_DILEPTON_UTILS_MOMENTUMSMEARER_H_ -#include -#include -#include +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Logger.h" +#include "Framework/runDataProcessing.h" + #include +#include +#include +#include +#include +#include #include -#include +#include + #include -#include "Framework/Logger.h" -using namespace o2::framework; using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; class MomentumSmearer { @@ -48,6 +58,23 @@ class MomentumSmearer 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) { @@ -106,19 +133,64 @@ class MomentumSmearer } } - void fillVecReso(TH2F* fReso, std::vector& fVecReso) + void fillVecReso(TH2F* fReso, std::vector& fVecReso, const char* suffix) { - TAxis* axisPt = fReso->GetXaxis(); + TAxis* axisPt = fReso->GetXaxis(); // be careful! This works only for variable bin width. int nBinsPt = axisPt->GetNbins(); - for (int i = 1; i <= nBinsPt; i++) { - fVecReso.push_back(reinterpret_cast(fReso->ProjectionY("", i, i))); + fVecReso.resize(nBinsPt); + for (int i = 0; i < nBinsPt; i++) { + auto h1 = reinterpret_cast(fReso->ProjectionY(Form("h1reso%s_pt%d", suffix, i), i + 1, i + 1)); + h1->Scale(1.f, "width"); // convert ntrack to probability density + fVecReso[i] = h1; } } + 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://") || fEffFileName.BeginsWith("alien://") || fDCAFileName.BeginsWith("alien://")) && (!fFromCcdb)) { TGrid::Connect("alien://"); @@ -156,34 +228,48 @@ class MomentumSmearer fFile->Close(); } } - 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()); - } + LOGF(info, "Apply ND-correlated smearing: fDoNDSmearing = %d , fResNDHistName = %s", fDoNDSmearing, fResNDHistName.Data()); - fResoPhi_Pos = reinterpret_cast(listRes->FindObject(fResPhiPosHistName)); - if (!fResoPhi_Pos) { - LOGP(fatal, "Could not open {} from file {}", fResPhiPosHistName.Data(), fResFileName.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 { + if (fResType != 0) { + fResoPt = reinterpret_cast(listRes->FindObject(fResPtHistName)); + if (!fResoPt) { + LOGP(fatal, "Could not open {} from file {}", fResPtHistName.Data(), fResFileName.Data()); + } - fResoPhi_Neg = reinterpret_cast(listRes->FindObject(fResPhiNegHistName)); - if (!fResoPhi_Neg) { - LOGP(fatal, "Could not open {} from file {}", fResPhiNegHistName.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, "_reldpt"); + fillVecReso(fResoEta, fVecResoEta, "_deta"); + fillVecReso(fResoPhi_Pos, fVecResoPhi_Pos, "_dphi_pos"); + fillVecReso(fResoPhi_Neg, fVecResoPhi_Neg, "_dphi_neg"); } - fillVecReso(fResoPt, fVecResoPt); - fillVecReso(fResoEta, fVecResoEta); - fillVecReso(fResoPhi_Pos, fVecResoPhi_Pos); - fillVecReso(fResoPhi_Neg, fVecResoPhi_Neg); } - if (!fFromCcdb) + if (!fFromCcdb) { delete listRes; + } LOGP(info, "Set efficiency histos"); TList* listEff = new TList(); @@ -237,8 +323,9 @@ class MomentumSmearer } } - if (!fFromCcdb) + if (!fFromCcdb) { delete listEff; + } LOGP(info, "Set DCA histos"); TList* listDCA = new TList(); @@ -277,20 +364,22 @@ class MomentumSmearer if (!fDCA) { LOGP(fatal, "Could not open {} from file {}", fDCAHistName.Data(), fDCAFileName.Data()); } - fillVecReso(fDCA, fVecDCA); + fillVecReso(fDCA, fVecDCA, "_dca"); } - if (!fFromCcdb) + if (!fFromCcdb) { delete listDCA; + } fInitialized = true; } - void applySmearing(float ptgen, float vargen, float multiply, float& varsmeared, TH2F* fReso, std::vector& fVecReso) + void applySmearing(const float ptgen, const float vargen, const float multiply, float& varsmeared, TH2F* fReso, std::vector& fVecReso) { + float ptgen_tmp = ptgen > fMinPtGen ? ptgen : fMinPtGen; TAxis* axisPt = fReso->GetXaxis(); int nBinsPt = axisPt->GetNbins(); - int ptbin = axisPt->FindBin(ptgen); + int ptbin = axisPt->FindBin(ptgen_tmp); if (ptbin < 1) { ptbin = 1; } @@ -304,7 +393,7 @@ class MomentumSmearer varsmeared = vargen - smearing; } - void applySmearing(const int ch, const float ptgen, const float etagen, const float phigen, float& ptsmeared, float& etasmeared, float& phismeared) + 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; @@ -312,13 +401,78 @@ class MomentumSmearer phismeared = phigen; return; } - 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); + + if (fDoNDSmearing) { + if (centrality < 0) { + ptsmeared = ptgen; + etasmeared = etagen; + phismeared = phigen; + return; + } + applySmearingND(centrality, ch, ptgen, etagen, phigen, ptsmeared, etasmeared, phismeared); } else { - applySmearing(ptgen, phigen, 1., phismeared, fResoPhi_Neg, fVecResoPhi_Neg); + 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; + } + + // protection + if (etabin < 1) { + etabin = 1; + } else if (etabin > fNEtaBins) { + etabin = fNEtaBins; + } + + // protection + if (phibin < 1) { + phibin = 1; + } else if (phibin > fNPhiBins) { + phibin = fNPhiBins; + } + + // 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) @@ -408,7 +562,9 @@ class MomentumSmearer } // 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; } @@ -426,9 +582,12 @@ class MomentumSmearer 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; } @@ -445,10 +604,13 @@ class MomentumSmearer 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; @@ -463,10 +625,17 @@ class MomentumSmearer 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; @@ -477,6 +646,7 @@ class MomentumSmearer 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 index 77496d185c2..0758289bbee 100644 --- a/PWGEM/Dilepton/Utils/PairUtilities.h +++ b/PWGEM/Dilepton/Utils/PairUtilities.h @@ -15,14 +15,18 @@ #ifndef PWGEM_DILEPTON_UTILS_PAIRUTILITIES_H_ #define PWGEM_DILEPTON_UTILS_PAIRUTILITIES_H_ -#include -#include +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include "ReconstructionDataFormats/TrackFwd.h" + +#include "Math/GenVector/Boost.h" #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" + +#include +#include //_______________________________________________________________________ namespace o2::aod::pwgem::dilepton::utils::pairutil @@ -38,88 +42,117 @@ enum class DileptonAnalysisType : int { kFlowV2 = 2, kFlowV3 = 3, kPolarization = 4, - kVM = 5, - kHFll = 6, + kHFll = 5, +}; + +enum class DileptonHadronAnalysisType : int { + kAzimuthalCorrelation = 0, + kCumulant = 1, +}; + +enum class DileptonPrefilterBit : int { + kElFromPC = 0, // electron from photon conversion + kElFromPi0_20MeV = 1, // electron from pi0 dalitz decay in mee < 20 MeV/c2 + kElFromPi0_40MeV = 2, // electron from pi0 dalitz decay in mee < 40 MeV/c2 + kElFromPi0_60MeV = 3, // electron from pi0 dalitz decay in mee < 60 MeV/c2 + kElFromPi0_80MeV = 4, // electron from pi0 dalitz decay in mee < 80 MeV/c2 + kElFromPi0_100MeV = 5, // electron from pi0 dalitz decay in mee < 100 MeV/c2 + kElFromPi0_120MeV = 6, // electron from pi0 dalitz decay in mee < 120 MeV/c2 + kElFromPi0_140MeV = 7, // electron from pi0 dalitz decay in mee < 140 MeV/c2 +}; + +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) +template +void getAngleHX(std::array const& tM, std::array const& tD, 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; + // tM is mother momentum. tD is daugher momentum. Boost daugher to mother's rest frame. + ROOT::Math::PxPyPzEVector vM(tM[0], tM[1], tM[2], std::sqrt(std::pow(tM[0], 2) + std::pow(tM[1], 2) + std::pow(tM[2], 2) + std::pow(tM[3], 2))); + ROOT::Math::PxPyPzEVector vD(tD[0], tD[1], tD[2], std::sqrt(std::pow(tD[0], 2) + std::pow(tD[1], 2) + std::pow(tD[2], 2) + std::pow(tD[3], 2))); 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) + // Boost to pair rest frame + ROOT::Math::Boost boostvM{vM.BoostToCM()}; + ROOT::Math::XYZVectorF vD_PRF{(boostvM(vD).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam1_PRF{(boostvM(Beam1).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_PRF{(boostvM(Beam2).Vect()).Unit()}; // Helicity frame - ROOT::Math::XYZVectorF zaxis_HX{(v12.Vect()).Unit()}; - ROOT::Math::XYZVectorF yaxis_HX{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF zaxis_HX{(vM.Vect()).Unit()}; + ROOT::Math::XYZVectorF yaxis_HX{(Beam1_PRF.Cross(Beam2_PRF)).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)); - } + cos_thetaHX = zaxis_HX.Dot(vD_PRF); + phiHX = std::atan2(yaxis_HX.Dot(vD_PRF), xaxis_HX.Dot(vD_PRF)); } - -//_______________________________________________________________________ //_______________________________________________________________________ -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) +template +void getAngleCS(std::array const& tM, std::array const& tD, 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; + // tM is mother momentum. tD is daugher momentum. Boost daugher to mother's rest frame. + ROOT::Math::PxPyPzEVector vM(tM[0], tM[1], tM[2], std::sqrt(std::pow(tM[0], 2) + std::pow(tM[1], 2) + std::pow(tM[2], 2) + std::pow(tM[3], 2))); + ROOT::Math::PxPyPzEVector vD(tD[0], tD[1], tD[2], std::sqrt(std::pow(tD[0], 2) + std::pow(tD[1], 2) + std::pow(tD[2], 2) + std::pow(tD[3], 2))); 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) + // Boost to pair rest frame + ROOT::Math::Boost boostvM{vM.BoostToCM()}; + ROOT::Math::XYZVectorF vD_PRF{(boostvM(vD).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam1_PRF{(boostvM(Beam1).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_PRF{(boostvM(Beam2).Vect()).Unit()}; // 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 zaxis_CS{((Beam1_PRF.Unit() - Beam2_PRF.Unit()).Unit())}; + ROOT::Math::XYZVectorF yaxis_CS{(Beam1_PRF.Cross(Beam2_PRF)).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. + cos_thetaCS = zaxis_CS.Dot(vD_PRF); + phiCS = std::atan2(yaxis_CS.Dot(vD_PRF), xaxis_CS.Dot(vD_PRF)); +} +//_______________________________________________________________________ +template +void getAngleHX(std::array const& t1, std::array const& t2, const float beamE1, const float beamE2, const float beamP1, const float beamP2, const int8_t c1, float& cos_thetaHX, float& phiHX) +{ + // t1[0] = px, t1[1] = py, t1[2] = pz, t1[3] = mass; + ROOT::Math::PxPyPzEVector v1(t1[0], t1[1], t1[2], std::sqrt(std::pow(t1[0], 2) + std::pow(t1[1], 2) + std::pow(t1[2], 2) + std::pow(t1[3], 2))); + ROOT::Math::PxPyPzEVector v2(t2[0], t2[1], t2[2], std::sqrt(std::pow(t2[0], 2) + std::pow(t2[1], 2) + std::pow(t2[2], 2) + std::pow(t2[3], 2))); + ROOT::Math::PxPyPzEVector v12 = v1 + v2; + std::array arrM{static_cast(v12.Px()), static_cast(v12.Py()), static_cast(v12.Pz()), static_cast(v12.M())}; - 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)); + if (c1 > 0) { + getAngleHX(arrM, t1, beamE1, beamE2, beamP1, beamP2, cos_thetaHX, phiHX); } 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)); + getAngleHX(arrM, t2, beamE1, beamE2, beamP1, beamP2, cos_thetaHX, phiHX); } } +//_______________________________________________________________________ +template +void getAngleCS(std::array const& t1, std::array const& t2, const float beamE1, const float beamE2, const float beamP1, const float beamP2, const int8_t c1, float& cos_thetaCS, float& phiCS) +{ + // t1[0] = px, t1[1] = py, t1[2] = pz, t1[3] = mass; + ROOT::Math::PxPyPzEVector v1(t1[0], t1[1], t1[2], std::sqrt(std::pow(t1[0], 2) + std::pow(t1[1], 2) + std::pow(t1[2], 2) + std::pow(t1[3], 2))); + ROOT::Math::PxPyPzEVector v2(t2[0], t2[1], t2[2], std::sqrt(std::pow(t2[0], 2) + std::pow(t2[1], 2) + std::pow(t2[2], 2) + std::pow(t2[3], 2))); + ROOT::Math::PxPyPzEVector v12 = v1 + v2; + std::array arrM{static_cast(v12.Px()), static_cast(v12.Py()), static_cast(v12.Pz()), static_cast(v12.M())}; + if (c1 > 0) { + getAngleCS(arrM, t1, beamE1, beamE2, beamP1, beamP2, cos_thetaCS, phiCS); + } else { + getAngleCS(arrM, t2, beamE1, beamE2, beamP1, beamP2, cos_thetaCS, phiCS); + } +} //_______________________________________________________________________ template bool isSVFound(TDCAFitter fitter, TCollision const& collision, TTrack const& t1, TTrack const& t2, float& pca, float& lxy, float& cosPA) @@ -154,7 +187,6 @@ bool isSVFound(TDCAFitter fitter, TCollision const& collision, TTrack const& t1, return false; } } - //_______________________________________________________________________ // function call without cosPA template @@ -215,7 +247,7 @@ bool isSVFoundFwd(TFwdDCAFitter fitter, TCollision const& collision, TTrack cons } } //_______________________________________________________________________ -inline float getPhivPair(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg, int cpos, int cneg, float bz) +inline float getPhivPair(const float pxpos, const float pypos, const float pzpos, const float pxneg, const float pyneg, const float pzneg, const int8_t cpos, const int8_t cneg, const float bz) { // cos(phiv) = w*a /|w||a| // with w = u x v @@ -231,16 +263,20 @@ inline float getPhivPair(float pxpos, float pypos, float pzpos, float pxneg, flo 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 > 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 > 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); @@ -248,13 +284,15 @@ inline float getPhivPair(float pxpos, float pypos, float pzpos, float pxneg, flo } } else { // Unlike Sign if (bz > 0) { - if (cpos > 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 > 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); @@ -297,7 +335,7 @@ inline float getPhivPair(float pxpos, float pypos, float pzpos, float pxneg, flo 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) +inline float getPsiPair(const float pxpos, const float pypos, const float pzpos, const float pxneg, const float pyneg, const 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); @@ -308,7 +346,7 @@ inline float getPsiPair(float pxpos, float pypos, float pzpos, float pxneg, floa return std::asin(clipToPM1(argsin)); } //_______________________________________________________________________ -inline float getOpeningAngle(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +inline float getOpeningAngle(const float pxpos, const float pypos, const float pzpos, const float pxneg, const float pyneg, const 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); @@ -316,5 +354,15 @@ inline float getOpeningAngle(float pxpos, float pypos, float pzpos, float pxneg, 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 int8_t charge1, const int8_t 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/CutsLibrary.cxx b/PWGEM/PhotonMeson/Core/CutsLibrary.cxx index c2f313e6e62..aaf16551ba6 100644 --- a/PWGEM/PhotonMeson/Core/CutsLibrary.cxx +++ b/PWGEM/PhotonMeson/Core/CutsLibrary.cxx @@ -9,12 +9,28 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// Contact: daiki.sekihata@cern.ch -// +/// \file CutsLibrary.cxx +/// \brief Source of class for EM photon selection. +/// \author daiki.sekihata@cern.ch + +#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" + +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/PairCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" + +#include + +#include + +#include +#include +#include #include #include -#include -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" //_______________________________________________ int customAtoi(const std::string& str) @@ -132,7 +148,7 @@ 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->SetIsWithinBeamPipe(true); // for v0 cut->SetMinCosPA(0.99); cut->SetMaxPCA(3.0); @@ -201,7 +217,7 @@ 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->SetIsWithinBeamPipe(true); // for v0 cut->SetMinCosPA(0.995); cut->SetMaxPCA(0.5); @@ -216,7 +232,7 @@ 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->SetIsWithinBeamPipe(true); cut->SetRequireITSTPC(true); // for v0 cut->SetMinCosPA(0.99); @@ -232,7 +248,7 @@ 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->SetIsWithinBeamPipe(true); // for v0 cut->SetMinCosPA(0.99); cut->SetMaxPCA(3.0); @@ -249,7 +265,7 @@ 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(false); + // cut->SetIsWithinBeamPipe(false); // for v0 cut->SetMinCosPA(0.95); cut->SetMaxPCA(3.0); @@ -265,7 +281,7 @@ 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(false); + // cut->SetIsWithinBeamPipe(false); // for v0 cut->SetMinCosPA(0.95); cut->SetMaxPCA(3.0); @@ -511,12 +527,10 @@ EMCPhotonCut* o2::aod::pwgem::photon::emccuts::GetCut(const char* cutName) cut->SetM02Range(0.1f, 0.7f); cut->SetTimeRange(-20.f, 25.f); - cut->SetTrackMatchingEta([](float pT) { - return 0.01f + pow(pT + 4.07f, -2.5f); - }); - cut->SetTrackMatchingPhi([](float pT) { - return 0.015f + pow(pT + 3.65f, -2.f); - }); + cut->SetTrackMatchingEtaParams(0.01f, 4.07f, -2.5f); + cut->SetTrackMatchingPhiParams(0.015f, 3.65f, -2.0f); + cut->SetSecTrackMatchingEtaParams(0.01f, 4.07f, -2.5f); + cut->SetSecTrackMatchingPhiParams(0.015f, 3.65f, -2.0f); cut->SetMinEoverP(1.75f); cut->SetUseExoticCut(true); return cut; @@ -527,12 +541,10 @@ EMCPhotonCut* o2::aod::pwgem::photon::emccuts::GetCut(const char* cutName) cut->SetM02Range(0.0f, 1000.f); cut->SetTimeRange(-500.f, 500.f); - cut->SetTrackMatchingEta([](float /*pT*/) { - return -1.f; - }); - cut->SetTrackMatchingPhi([](float /*pT*/) { - return -1.f; - }); + cut->SetTrackMatchingEtaParams(-1.f, 0.f, 0.f); + cut->SetTrackMatchingPhiParams(-1.f, 0.f, 0.f); + cut->SetSecTrackMatchingEtaParams(-1.f, 0.f, 0.f); + cut->SetSecTrackMatchingPhiParams(-1.f, 0.f, 0.f); cut->SetMinEoverP(0.f); cut->SetUseExoticCut(false); return cut; @@ -543,12 +555,10 @@ EMCPhotonCut* o2::aod::pwgem::photon::emccuts::GetCut(const char* cutName) cut->SetM02Range(0.1f, 0.7f); cut->SetTimeRange(-20.f, 25.f); - cut->SetTrackMatchingEta([](float pT) { - return 0.01f + pow(pT + 4.07f, -2.5f); - }); - cut->SetTrackMatchingPhi([](float pT) { - return 0.015f + pow(pT + 3.65f, -2.f); - }); + cut->SetTrackMatchingEtaParams(0.01f, 4.07f, -2.5f); + cut->SetTrackMatchingPhiParams(0.015f, 3.65f, -2.0f); + cut->SetSecTrackMatchingEtaParams(0.01f, 4.07f, -2.5f); + cut->SetSecTrackMatchingPhiParams(0.015f, 3.65f, -2.0f); cut->SetMinEoverP(1.75f); cut->SetUseExoticCut(true); return cut; diff --git a/PWGEM/PhotonMeson/Core/DalitzEECut.cxx b/PWGEM/PhotonMeson/Core/DalitzEECut.cxx index b82b7460dfc..df6418474a1 100644 --- a/PWGEM/PhotonMeson/Core/DalitzEECut.cxx +++ b/PWGEM/PhotonMeson/Core/DalitzEECut.cxx @@ -13,9 +13,13 @@ // Class for dilepton Cut // -#include "Framework/Logger.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "Framework/Logger.h" + +#include +#include + ClassImp(DalitzEECut); // 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"}; @@ -78,6 +82,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; @@ -103,6 +112,12 @@ void DalitzEECut::SetMeanClusterSizeITS(float min, float max) mMaxMeanClusterSizeITS = max; LOG(info) << "DalitzEE Cut, set mean cluster size ITS range: " << mMinMeanClusterSizeITS << " - " << mMaxMeanClusterSizeITS; } +void DalitzEECut::SetTrackDca3DRange(float min, float max) +{ + mMinDca3D = min; + mMaxDca3D = max; + LOG(info) << "DalitzEE Cut, set DCA 3D range in sigma: " << mMinDca3D << " - " << mMaxDca3D; +} void DalitzEECut::SetMaxDcaXY(float maxDcaXY) { mMaxDcaXY = maxDcaXY; @@ -138,6 +153,12 @@ void DalitzEECut::SetTPCNsigmaPiRange(float min, float max) LOG(info) << "DalitzEE Cut, set TPC n sigma Pi range: " << mMinTPCNsigmaPi << " - " << mMaxTPCNsigmaPi; } +void DalitzEECut::SetTOFNsigmaElRange(float min, float max) +{ + mMinTOFNsigmaEl = min; + mMaxTOFNsigmaEl = max; + LOG(info) << "DalitzEE Cut, set TOF n sigma El range: " << mMinTOFNsigmaEl << " - " << mMaxTOFNsigmaEl; +} void DalitzEECut::RequireITSibAny(bool flag) { mRequireITSibAny = flag; @@ -148,43 +169,20 @@ void DalitzEECut::RequireITSib1st(bool flag) mRequireITSib1st = flag; LOG(info) << "DalitzEE Cut, require ITS ib 1st: " << mRequireITSib1st; } +void DalitzEECut::SetChi2TOF(float min, float max) +{ + mMinChi2TOF = min; + mMaxChi2TOF = max; + LOG(info) << "Dielectron Cut, set chi2 TOF range: " << mMinChi2TOF << " - " << mMaxChi2TOF; +} void DalitzEECut::SetPIDScheme(int scheme) { mPIDScheme = scheme; LOG(info) << "DalitzEE Cut, PID scheme: " << static_cast(mPIDScheme); } - -// void DalitzEECut::print() const -//{ -// 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!"; -// } -// } -// } +void DalitzEECut::IncludeITSsa(bool flag, float max) +{ + mIncludeITSsa = flag; + mMaxPtITSsa = max; + LOG(info) << "DalitzEE Cut, include ITSsa tracks: " << mIncludeITSsa << ", mMaxPtITSsa = " << mMaxPtITSsa; +} diff --git a/PWGEM/PhotonMeson/Core/DalitzEECut.h b/PWGEM/PhotonMeson/Core/DalitzEECut.h index 5ac38396976..ddc1da18340 100644 --- a/PWGEM/PhotonMeson/Core/DalitzEECut.h +++ b/PWGEM/PhotonMeson/Core/DalitzEECut.h @@ -16,22 +16,24 @@ #ifndef PWGEM_PHOTONMESON_CORE_DALITZEECUT_H_ #define PWGEM_PHOTONMESON_CORE_DALITZEECUT_H_ -#include -#include -#include -#include -#include -#include "TNamed.h" -#include "Math/Vector4D.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "Tools/ML/MlResponse.h" #include "Tools/ML/model.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" +#include "Framework/DataTypes.h" +#include "Framework/Logger.h" + +#include "Math/Vector4D.h" +#include "TNamed.h" + +#include +#include +#include +#include +#include using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; @@ -53,21 +55,23 @@ class DalitzEECut : public TNamed kTPCNCls, kTPCCrossedRows, kTPCCrossedRowsOverNCls, + kTPCFracSharedClusters, kTPCChi2NDF, kTPCNsigmaEl, kTPCNsigmaPi, + kDCA3Dsigma, kDCAxy, kDCAz, kITSNCls, kITSChi2NDF, - kITSCluserSize, kNCuts }; static const char* mCutNames[static_cast(DalitzEECuts::kNCuts)]; enum class PIDSchemes : int { kUnDef = -1, - kTPConly = 0, + kTOFif = 0, + kTPConly = 1, }; template @@ -113,7 +117,7 @@ class DalitzEECut : public TNamed template bool IsSelectedTrack(TTrack const& track, TCollision const& = 0) const { - if (!track.hasITS() || !track.hasTPC()) { // track has to be ITS-TPC matched track + if (!track.hasITS()) { return false; } @@ -123,6 +127,9 @@ class DalitzEECut : public TNamed if (!IsSelectedTrack(track, DalitzEECuts::kTrackEtaRange)) { return false; } + if (!IsSelectedTrack(track, DalitzEECuts::kDCA3Dsigma)) { + return false; + } if (!IsSelectedTrack(track, DalitzEECuts::kDCAxy)) { return false; } @@ -137,9 +144,6 @@ class DalitzEECut : public TNamed if (!IsSelectedTrack(track, DalitzEECuts::kITSChi2NDF)) { return false; } - if (!IsSelectedTrack(track, DalitzEECuts::kITSCluserSize)) { - 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); }); @@ -155,25 +159,44 @@ class DalitzEECut : public TNamed } } - // TPC cuts - if (!IsSelectedTrack(track, DalitzEECuts::kTPCNCls)) { - return false; - } - if (!IsSelectedTrack(track, DalitzEECuts::kTPCCrossedRows)) { + if (!mIncludeITSsa && (!track.hasITS() || !track.hasTPC())) { // track has to be ITS-TPC matched track return false; } - if (!IsSelectedTrack(track, DalitzEECuts::kTPCCrossedRowsOverNCls)) { + + if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && track.pt() > mMaxPtITSsa) { // ITSsa return false; } - if (!IsSelectedTrack(track, DalitzEECuts::kTPCChi2NDF)) { - return false; + + // TPC cuts + if (track.hasTPC()) { + if (!IsSelectedTrack(track, DalitzEECuts::kTPCNCls)) { + return false; + } + if (!IsSelectedTrack(track, DalitzEECuts::kTPCCrossedRows)) { + return false; + } + if (!IsSelectedTrack(track, DalitzEECuts::kTPCCrossedRowsOverNCls)) { + return false; + } + if (!IsSelectedTrack(track, DalitzEECuts::kTPCFracSharedClusters)) { + return false; + } + if (!IsSelectedTrack(track, DalitzEECuts::kTPCChi2NDF)) { + return false; + } } // PID cuts - if (!PassPID(track)) { - return false; + if (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) { // ITSsa + float meanClusterSizeITS = track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())); + if (meanClusterSizeITS < mMinMeanClusterSizeITS || mMaxMeanClusterSizeITS < meanClusterSizeITS) { + return false; + } + } else { + if (!PassPID(track)) { + return false; + } } - return true; } @@ -184,6 +207,9 @@ class DalitzEECut : public TNamed case static_cast(PIDSchemes::kTPConly): return PassTPConly(track); + case static_cast(PIDSchemes::kTOFif): + return PassTOFif(track); + case static_cast(PIDSchemes::kUnDef): return true; @@ -200,15 +226,24 @@ class DalitzEECut : public TNamed return is_el_included_TPC && is_pi_excluded_TPC; } + template + bool PassTOFif(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 = 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 bool IsSelectedTrack(T const& track, const DalitzEECuts& cut) const { switch (cut) { case DalitzEECuts::kTrackPtRange: - return track.pt() >= mMinTrackPt && track.pt() <= mMaxTrackPt; + return track.pt() > mMinTrackPt && track.pt() < mMaxTrackPt; case DalitzEECuts::kTrackEtaRange: - return track.eta() >= mMinTrackEta && track.eta() <= mMaxTrackEta; + return track.eta() > mMinTrackEta && track.eta() < mMaxTrackEta; case DalitzEECuts::kTPCNCls: return track.tpcNClsFound() >= mMinNClustersTPC; @@ -219,14 +254,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 < 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; @@ -234,9 +275,6 @@ class DalitzEECut : public TNamed case DalitzEECuts::kITSChi2NDF: return mMinChi2PerClusterITS < track.itsChi2NCl() && track.itsChi2NCl() < mMaxChi2PerClusterITS; - case DalitzEECuts::kITSCluserSize: - return mMinMeanClusterSizeITS < track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) && track.meanClusterSizeITS() * std::cos(std::atan(track.tgl())) < mMaxMeanClusterSizeITS; - default: return false; } @@ -245,7 +283,7 @@ class DalitzEECut : public TNamed // Setters void SetPairPtRange(float minPt = 0.f, float maxPt = 1e10f); void SetPairYRange(float minY = -1e10f, float maxY = 1e10f); - void SetMeeRange(float min = 0.f, float max = 0.5); + void SetMeeRange(float min = 0.f, float max = 0.04); void SetMaxPhivPairMeeDep(std::function meeDepCut); void SelectPhotonConversion(bool flag); @@ -254,29 +292,31 @@ 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 SetMeanClusterSizeITS(float min, float max); + void SetChi2TOF(float min, float max); void SetPIDScheme(int scheme); - void SetTPCNsigmaElRange(float min = -1e+10, float max = 1e+10); - void SetTPCNsigmaPiRange(float min = -1e+10, float max = 1e+10); + 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 SetMaxDcaXY(float maxDcaXY); // in cm - void SetMaxDcaZ(float maxDcaZ); // in cm + 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); + void IncludeITSsa(bool flag, float maxpt); // 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; @@ -297,24 +337,29 @@ 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 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}; - float mMinMeanClusterSizeITS{-1e10f}, mMaxMeanClusterSizeITS{1e10f}; // max x cos(Lmabda) + float mMinMeanClusterSizeITS{-1e10f}, mMaxMeanClusterSizeITS{1e10f}; // x cos(lmabda) + float mMinChi2TOF{-1e10f}, mMaxChi2TOF{1e10f}; // max tof chi2 per + bool mIncludeITSsa{false}; + float mMaxPtITSsa{0.15}; // pid cuts int mPIDScheme{-1}; float mMinTPCNsigmaEl{-1e+10}, mMaxTPCNsigmaEl{+1e+10}; - float mMinTPCNsigmaPi{-1e+10}, mMaxTPCNsigmaPi{+1e+10}; - - o2::ml::OnnxModel* mPIDModel{nullptr}; + float mMinTPCNsigmaPi{0}, mMaxTPCNsigmaPi{0}; + float mMinTOFNsigmaEl{-1e+10}, mMaxTOFNsigmaEl{+1e+10}; ClassDef(DalitzEECut, 1); }; diff --git a/PWGEM/PhotonMeson/Core/DiphotonHadronMPC.h b/PWGEM/PhotonMeson/Core/DiphotonHadronMPC.h new file mode 100644 index 00000000000..49d405e0dd1 --- /dev/null +++ b/PWGEM/PhotonMeson/Core/DiphotonHadronMPC.h @@ -0,0 +1,986 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// ======================== +// +/// \file DiphotonHadronMPC.h +/// \brief This code is to analyze diphoton-hadron correlation. Keep in mind that cumulant method does not require event mixing. +/// +/// \author D. Sekihata, daiki.sekihata@cern.ch + +#ifndef PWGEM_PHOTONMESON_CORE_DIPHOTONHADRONMPC_H_ +#define PWGEM_PHOTONMESON_CORE_DIPHOTONHADRONMPC_H_ + +#include "PWGEM/Dilepton/Core/EMTrackCut.h" +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/NMHistograms.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/RecoDecay.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 MyCollisionsWithSWT = soa::Join; +using MyCollisionWithSWT = MyCollisionsWithSWT::iterator; + +using MyV0Photons = soa::Filtered>; +using MyV0Photon = MyV0Photons::iterator; + +using MyPrimaryElectrons = soa::Filtered>; +using MyPrimaryElectron = MyPrimaryElectrons::iterator; + +template +struct DiphotonHadronMPC { + + 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 cfg_swt_name{"cfg_swt_name", "fHighTrackMult", "desired software trigger name"}; // 1 trigger name per 1 task. fHighTrackMult, fHighFt0Mult + + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + Configurable maxY{"maxY", 0.8, "maximum rapidity for diphoton"}; + Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + Configurable ndepth_photon{"ndepth_photon", 100, "depth for event mixing between photon-photon"}; + Configurable ndepth_hadron{"ndepth_hadron", 2, "depth for event mixing between hadron-hadron"}; + Configurable ndiff_bc_mix{"ndiff_bc_mix", 594, "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, 0.1, 1, 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 ConfOccupancyBins{"ConfOccupancyBins", {VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; + + ConfigurableAxis ConfMggBins{"ConfMggBins", {200, 0.0, 0.8}, "mgg bins for output histograms"}; + ConfigurableAxis ConfPtggBins{"ConfPtggBins", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 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.00}, "pTgg bins for output histograms"}; + + ConfigurableAxis ConfPtHadronBins{"ConfPtHadronBins", {VARIABLE_WIDTH, 0.00, 0.15, 0.2, 0.3, 0.4, 0.50, 1.00, 2.00, 3.00, 4.00, 5.00}, "pT,h bins for output histograms"}; + ConfigurableAxis ConfDEtaBins{"ConfDEtaBins", {120, -6, 6}, "deta bins for output histograms"}; + Configurable cfgNbinsDPhi{"cfgNbinsDPhi", 36, "nbins in dphi for output histograms"}; + // Configurable cfgNbinsCosNDPhi{"cfgNbinsCosNDPhi", 100, "nbins in cos(n(dphi)) for output histograms"}; + // Configurable cfgNmod{"cfgNmod", 2, "n-th harmonics"}; + + EMPhotonEventCut 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 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"}; + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadronPID] 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; + + 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_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", 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", 36.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.04, "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", 2.0, "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", 36.0, "max chi2/NclsITS"}; + 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.1, "max dca Z for single track in cm"}; + Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1e+10, "max DCA 3D in sigma"}; + Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 0.7, "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; + + EMTrackCut fEMTrackCut; + struct : ConfigurableGroup { + std::string prefix = "trackcut_group"; + Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.2, "min pT for ref. track"}; + Configurable cfg_max_pt_track{"cfg_max_pt_track", 3.0, "max pT for ref. track"}; + Configurable cfg_min_eta_track{"cfg_min_eta_track", -0.8, "min eta for ref. track"}; + Configurable cfg_max_eta_track{"cfg_max_eta_track", +0.8, "max eta for ref. track"}; + // Configurable cfg_min_phi_track{"cfg_min_phi_track", 0.0, "min phi for ref. track"}; + // Configurable cfg_max_phi_track{"cfg_max_phi_track", 6.3, "max phi for ref. track"}; + // Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.5, "max dca XY for single track in cm"}; + // Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.5, "max dca Z for single track in cm"}; + Configurable cfg_track_bits{"cfg_track_bits", 645, "required track bits"}; // default:645, loose:0, tight:778 + } trackcuts; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + 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 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()); + + 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_photon); + emh2 = new MyEMH(ndepth_photon); + emh_diphoton = new MyEMH_track(ndepth_photon); + emh_ref = new MyEMH_track(ndepth_hadron); + + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); + addHistograms(); + + DefineEMEventCut(); + DefineEMTrackCut(); + DefinePCMCut(); + DefineDileptonCut(); + + fRegistry.add("Diphoton/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); + } + + 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); + } + + 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()); + } + } + + ~DiphotonHadronMPC() + { + delete emh1; + emh1 = 0x0; + delete emh2; + emh2 = 0x0; + delete emh_diphoton; + emh_diphoton = 0x0; + delete emh_ref; + emh_ref = 0x0; + + used_photonIds_per_col.clear(); + used_photonIds_per_col.shrink_to_fit(); + used_dileptonIds_per_col.clear(); + used_dileptonIds_per_col.shrink_to_fit(); + used_diphotonIds_per_col.clear(); + used_diphotonIds_per_col.shrink_to_fit(); + + map_mixed_eventId_to_globalBC.clear(); + } + + void addHistograms() + { + std::string mass_axis_title = "m_{#gamma#gamma} (GeV/c^{2})"; + std::string pair_pt_axis_title = "p_{T,#gamma#gamma} (GeV/c)"; + std::string deta_axis_title = "#Delta#eta = #eta_{#gamma#gamma} - #eta_{h}"; + std::string dphi_axis_title = "#Delta#varphi = #varphi_{#gamma#gamma} - #varphi_{h} (rad.)"; + // std::string cosndphi_axis_title = std::format("cos({0:d}(#varphi_{{#gamma#gamma}} - #varphi_{{h}}))", cfgNmod.value); + + if constexpr (pairtype == PairType::kPCMDalitzEE) { + mass_axis_title = "m_{ee#gamma} (GeV/c^{2})"; + pair_pt_axis_title = "p_{T,ee#gamma} (GeV/c)"; + deta_axis_title = "#Delta#eta = #eta_{ee#gamma} - #eta_{h}"; + dphi_axis_title = "#Delta#varphi = #varphi_{ee#gamma} - #varphi_{h} (rad.)"; + // cosndphi_axis_title = std::format("cos({0:d}(#varphi_{{ee#gamma}} - #varphi_{{h}}))", cfgNmod.value); + } + + // diphoton info + const AxisSpec axis_mass{ConfMggBins, mass_axis_title}; + const AxisSpec axis_pt{ConfPtggBins, pair_pt_axis_title}; + + // diphoton-hadron info + const AxisSpec axis_deta{ConfDEtaBins, deta_axis_title}; + const AxisSpec axis_dphi{cfgNbinsDPhi, -M_PI / 2, +3 * M_PI / 2, dphi_axis_title}; + + const AxisSpec axis_pt_hadron{ConfPtHadronBins, "p_{T,h} (GeV/c)"}; + const AxisSpec axis_eta_hadron{40, -2, +2, "#eta_{h}"}; + const AxisSpec axis_phi_hadron{36, 0, 2 * M_PI, "#varphi_{h} (rad.)"}; + + fRegistry.add("Hadron/hs", "hadron", kTHnSparseD, {axis_pt_hadron, axis_eta_hadron, axis_phi_hadron}, false); + fRegistry.add("Hadron/hTrackBit", "track bit", kTH1D, {{65536, -0.5, 65535.5}}, false); + + fRegistry.add("Diphoton/same/hs", "diphoton", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry.addClone("Diphoton/same/", "Diphoton/mix/"); + + fRegistry.add("DiphotonHadron/same/hs", "diphoton-hadron 2PC", kTHnSparseD, {axis_mass, axis_pt, axis_deta, axis_dphi}, true); + fRegistry.addClone("DiphotonHadron/same/", "DiphotonHadron/mix/"); + + // hadron-hadron + const AxisSpec axis_deta_hh{60, -3, +3, "#Delta#eta = #eta_{h}^{ref1} - #eta_{h}^{ref2}"}; + const AxisSpec axis_dphi_hh{90, -M_PI / 2, +3 * M_PI / 2, "#Delta#varphi = #varphi_{h}^{ref1} - #varphi_{h}^{ref2} (rad.)"}; + // const AxisSpec axis_cosndphi_hh{cfgNbinsCosNDPhi, -1, +1, std::format("cos({0:d}(#varphi_{{h}}^{{ref1}} - #varphi_{{h}}^{{ref2}}))", cfgNmod.value)}; + fRegistry.add("HadronHadron/same/hDEtaDPhi", "hadron-hadron 2PC", kTH2D, {axis_dphi_hh, axis_deta_hh}, true); + fRegistry.addClone("HadronHadron/same/", "HadronHadron/mix/"); + } + + void DefineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("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.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.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + 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 + fDileptonCut.IncludeITSsa(false, 0.15); + + // 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 DefineEMTrackCut() + { + fEMTrackCut = EMTrackCut("fEMTrackCut", "fEMTrackCut"); + fEMTrackCut.SetTrackPtRange(trackcuts.cfg_min_pt_track, trackcuts.cfg_max_pt_track); + fEMTrackCut.SetTrackEtaRange(trackcuts.cfg_min_eta_track, trackcuts.cfg_max_eta_track); + // fEMTrackCut.SetTrackPhiRange(trackcuts.cfg_min_phi_track, trackcuts.cfg_max_phi_track); + // fEMTrackCut.SetTrackMaxDcaXY(trackcuts.cfg_max_dcaxy); + // fEMTrackCut.SetTrackMaxDcaZ(trackcuts.cfg_max_dcaz); + fEMTrackCut.SetTrackBit(trackcuts.cfg_track_bits); + } + + SliceCache cache; + Preslice perCollision_pcm = aod::v0photonkf::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 RefTracks = soa::Join; + using RefTrack = RefTracks::iterator; + Preslice perCollision_track = aod::emprimarytrack::emeventId; + Filter refTrackFilter = trackcuts.cfg_min_pt_track < 1 / nabs(o2::aod::emprimarytrack::signed1Pt) && 1 / nabs(o2::aod::emprimarytrack::signed1Pt) < trackcuts.cfg_max_pt_track && trackcuts.cfg_min_eta_track < o2::aod::emprimarytrack::eta && o2::aod::emprimarytrack::eta < trackcuts.cfg_max_eta_track; + using FilteredRefTracks = soa::Filtered; + using FilteredRefTrack = FilteredRefTracks::iterator; + + using MyEMH = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMTrack>; + MyEMH* emh1 = nullptr; + MyEMH* emh2 = nullptr; + using MyEMH_track = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, EMTrack>; // for charged track + MyEMH_track* emh_diphoton = nullptr; + MyEMH_track* emh_ref = nullptr; + + std::vector used_photonIds_per_col; // + std::vector> used_dileptonIds_per_col; // + std::vector> used_diphotonIds_per_col; // + std::map, uint64_t> map_mixed_eventId_to_globalBC; + + template + void run2PC(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, + TRefTracks const& refTracks) + { + for (const 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; + } + } + + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, 1.f); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + if (eventcuts.cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + continue; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, 1.f); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, 1.f); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, 1.f); // 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; + } + + int epbin = 0; + + 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); + + auto refTracks_per_collision = refTracks.sliceBy(perCollision_track, collision.globalIndex()); + + 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) { // 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; + } + fRegistry.fill(HIST("Diphoton/same/hs"), v12.M(), v12.Pt()); + auto pos1 = g1.template posTrack_as(); + auto ele1 = g1.template negTrack_as(); + auto pos2 = g2.template posTrack_as(); + auto ele2 = g2.template negTrack_as(); + + int npair = 0; // the number of diphoton-h pairs + for (const auto& track : refTracks_per_collision) { + if (pos1.trackId() == track.trackId() || ele1.trackId() == track.trackId()) { + continue; + } + if (pos2.trackId() == track.trackId() || ele2.trackId() == track.trackId()) { + continue; + } + + if (fEMTrackCut.IsSelected(track)) { + ROOT::Math::PtEtaPhiMVector v3(track.pt(), track.eta(), track.phi(), 0.139); + float deta = v12.Eta() - v3.Eta(); + float dphi = v12.Phi() - v3.Phi(); + // o2::math_utils::bringTo02Pi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI / 2, 1U); + fRegistry.fill(HIST("DiphotonHadron/same/hs"), v12.M(), v12.Pt(), deta, dphi); + npair++; + } + } // end of ref track loop + + if (npair > 0) { + std::tuple tuple_tmp_diphoton = std::make_tuple(g1.globalIndex(), g2.globalIndex(), -1); + if (std::find(used_diphotonIds_per_col.begin(), used_diphotonIds_per_col.end(), tuple_tmp_diphoton) == used_diphotonIds_per_col.end()) { + emh_diphoton->AddTrackToEventPool(key_df_collision, EMTrack(v12.Pt(), v12.Eta(), v12.Phi(), v12.M())); + used_diphotonIds_per_col.emplace_back(tuple_tmp_diphoton); + } + } + + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds_per_col.emplace_back(g1.globalIndex()); + } + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g2.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(g2.pt(), g2.eta(), g2.phi(), 0)); + used_photonIds_per_col.emplace_back(g2.globalIndex()); + } + 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("Diphoton/same/hs"), veeg.M(), veeg.Pt()); + + int npair = 0; // the number of diphoton-h pairs + for (const auto& track : refTracks_per_collision) { + if (pos1.trackId() == track.trackId() || ele1.trackId() == track.trackId()) { + continue; + } + if (pos2.trackId() == track.trackId() || ele2.trackId() == track.trackId()) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v3(track.pt(), track.eta(), track.phi(), 0.139); + float deta = veeg.Eta() - v3.Eta(); + float dphi = veeg.Phi() - v3.Phi(); + // o2::math_utils::bringTo02Pi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI / 2, 1U); + fRegistry.fill(HIST("DiphotonHadron/same/hs"), veeg.M(), veeg.Pt(), deta, dphi); + npair++; + + } // end of ref track loop + + if (npair > 0) { + std::tuple tuple_tmp_diphoton = std::make_tuple(g1.globalIndex(), pos2.trackId(), ele2.trackId()); + if (std::find(used_diphotonIds_per_col.begin(), used_diphotonIds_per_col.end(), tuple_tmp_diphoton) == used_diphotonIds_per_col.end()) { + emh_diphoton->AddTrackToEventPool(key_df_collision, EMTrack(veeg.Pt(), veeg.Eta(), veeg.Phi(), veeg.M())); + used_diphotonIds_per_col.emplace_back(tuple_tmp_diphoton); + } + } + + std::pair tuple_tmp_id2 = std::make_pair(pos2.trackId(), ele2.trackId()); + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds_per_col.emplace_back(g1.globalIndex()); + } + if (std::find(used_dileptonIds_per_col.begin(), used_dileptonIds_per_col.end(), tuple_tmp_id2) == used_dileptonIds_per_col.end()) { + emh2->AddTrackToEventPool(key_df_collision, EMTrack(v_ee.Pt(), v_ee.Eta(), v_ee.Phi(), v_ee.M())); + used_dileptonIds_per_col.emplace_back(tuple_tmp_id2); + } + ndiphoton++; + } // end of dielectron loop + } // end of g1 loop + } // end of pairing in same event + + used_photonIds_per_col.clear(); + used_photonIds_per_col.shrink_to_fit(); + used_dileptonIds_per_col.clear(); + used_dileptonIds_per_col.shrink_to_fit(); + used_diphotonIds_per_col.clear(); + used_diphotonIds_per_col.shrink_to_fit(); + + if (ndiphoton > 0) { + emh_ref->ReserveNTracksPerCollision(key_df_collision, refTracks_per_collision.size()); + for (const auto& track : refTracks_per_collision) { + if (fEMTrackCut.IsSelected(track)) { + fRegistry.fill(HIST("Hadron/hs"), track.pt(), track.eta(), track.phi()); + fRegistry.fill(HIST("Hadron/hTrackBit"), track.trackBit()); + emh_ref->AddTrackToEventPool(key_df_collision, EMTrack(track.pt(), track.eta(), track.phi(), 0.139)); + } + } + + for (const auto& [ref1, ref2] : combinations(CombinationsStrictlyUpperIndexPolicy(refTracks_per_collision, refTracks_per_collision))) { + if (fEMTrackCut.IsSelected(ref1) && fEMTrackCut.IsSelected(ref2)) { + float deta = ref1.eta() - ref2.eta(); + float dphi = ref1.phi() - ref2.phi(); + // o2::math_utils::bringTo02Pi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI / 2, 1U); + fRegistry.fill(HIST("HadronHadron/same/hDEtaDPhi"), dphi, deta); + } + } + } + + // 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 selected_refTracks_in_this_event = emh_ref->GetTracksPerCollision(key_df_collision); + auto selected_diphotons_in_this_event = emh_diphoton->GetTracksPerCollision(key_df_collision); + + auto collisionIds1_in_mixing_pool = emh1->GetCollisionIdsFromEventPool(key_bin); + auto collisionIds2_in_mixing_pool = emh2->GetCollisionIdsFromEventPool(key_bin); + auto collisionIdsRef_in_mixing_pool = emh_ref->GetCollisionIdsFromEventPool(key_bin); + auto collisionIdsDiphoton_in_mixing_pool = emh_diphoton->GetCollisionIdsFromEventPool(key_bin); + + if constexpr (pairtype == PairType::kPCMPCM) { // 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("Diphoton/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("Diphoton/mix/hs"), v12.M(), v12.Pt(), 1.f); + } + } + } // end of loop over mixed event pool between photon-photon + + for (const auto& mix_dfId_collisionId : collisionIdsRef_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); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto refTracks_from_event_pool = emh_ref->GetTracksPerCollision(mix_dfId_collisionId); + for (const auto& trg : selected_diphotons_in_this_event) { + for (const auto& ref : refTracks_from_event_pool) { + float deta = trg.eta() - ref.eta(); + float dphi = trg.phi() - ref.phi(); + // o2::math_utils::bringTo02Pi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI / 2, 1U); + fRegistry.fill(HIST("DiphotonHadron/mix/hs"), trg.mass(), trg.pt(), deta, dphi); + } + } + } // end of loop over mixed event pool between diphoton-hadron + + } 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("Diphoton/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("Diphoton/mix/hs"), v12.M(), v12.Pt(), 1.f); + } + } + } // end of loop over mixed event pool between photon-photon + + 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("Diphoton/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("Diphoton/mix/hs"), v12.M(), v12.Pt(), 1.f); + } + } + } // end of loop over mixed event pool between photon-photon + + for (const auto& mix_dfId_collisionId : collisionIdsRef_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); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto refTracks_from_event_pool = emh_ref->GetTracksPerCollision(mix_dfId_collisionId); + for (const auto& trg : selected_diphotons_in_this_event) { + for (const auto& ref : refTracks_from_event_pool) { + float deta = trg.eta() - ref.eta(); + float dphi = trg.phi() - ref.phi(); + // o2::math_utils::bringTo02Pi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI / 2, 1U); + fRegistry.fill(HIST("DiphotonHadron/mix/hs"), trg.mass(), trg.pt(), deta, dphi); + } + } + } // end of loop over mixed event pool between diphoton-hadron + } + + // hadron-hadron mixed event + for (const auto& mix_dfId_collisionId : collisionIdsRef_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); + if (diffBC < ndiff_bc_mix) { + continue; + } + + auto refTracks_from_event_pool = emh_ref->GetTracksPerCollision(mix_dfId_collisionId); + for (const auto& ref1 : selected_refTracks_in_this_event) { + for (const auto& ref2 : refTracks_from_event_pool) { + float deta = ref1.eta() - ref2.eta(); + float dphi = ref1.phi() - ref2.phi(); + // o2::math_utils::bringTo02Pi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI / 2, 1U); + fRegistry.fill(HIST("HadronHadron/mix/hDEtaDPhi"), dphi, deta); + } + } + } // end of loop over mixed event pool between hadron-hadron + + if (ndiphoton > 0) { + emh1->AddCollisionIdAtLast(key_bin, key_df_collision); + emh2->AddCollisionIdAtLast(key_bin, key_df_collision); + emh_diphoton->AddCollisionIdAtLast(key_bin, key_df_collision); + emh_ref->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, FilteredRefTracks const& refTracks, 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...)); + run2PC(collisions, v0photons, v0photons, v0legs, v0legs, perCollision_pcm, perCollision_pcm, fV0PhotonCut, fV0PhotonCut, refTracks); + } 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()); + run2PC(collisions, v0photons, emprimaryelectrons, v0legs, emprimaryelectrons, perCollision_pcm, perCollision_electron, fV0PhotonCut, fDileptonCut, refTracks); + } + ndf++; + } + PROCESS_SWITCH(DiphotonHadronMPC, processAnalysis, "process pair analysis", true); + + // using FilteredMyCollisionsWithSWT = soa::Filtered; + void processTriggerAnalysis(MyCollisionsWithSWT const& collisions, FilteredRefTracks const& refTracks, 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...)); + run2PC(collisions, v0photons, v0photons, v0legs, v0legs, perCollision_pcm, perCollision_pcm, fV0PhotonCut, fV0PhotonCut, refTracks); + } 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()); + run2PC(collisions, v0photons, emprimaryelectrons, v0legs, emprimaryelectrons, perCollision_pcm, perCollision_electron, fV0PhotonCut, fDileptonCut, refTracks); + } + ndf++; + } + PROCESS_SWITCH(DiphotonHadronMPC, processTriggerAnalysis, "process pair analysis with software trigger", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(DiphotonHadronMPC, processDummy, "Dummy function", false); +}; +#endif // PWGEM_PHOTONMESON_CORE_DIPHOTONHADRONMPC_H_ diff --git a/PWGEM/PhotonMeson/Core/EMCPhotonCut.cxx b/PWGEM/PhotonMeson/Core/EMCPhotonCut.cxx index 502e5b283a1..1ccca2a2be7 100644 --- a/PWGEM/PhotonMeson/Core/EMCPhotonCut.cxx +++ b/PWGEM/PhotonMeson/Core/EMCPhotonCut.cxx @@ -9,64 +9,87 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// -// Class for EMCal cluster selection -// +/// \file EMCPhotonCut.cxx +/// \brief source of class for emcal photon selection. +/// \author M. Hemmer, marvin.hemmer@cern.ch; N. Strangmann, nicolas.strangmann@cern.ch -#include "Framework/Logger.h" #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +// +#include "PWGJE/DataModel/EMCALClusters.h" + +#include + +#include + +#include 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", "SecTrackMatching", "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; LOG(info) << "EMCal Photon Cut, set minimum cluster energy: " << mMinE; } + void EMCPhotonCut::SetMinNCell(int min) { mMinNCell = min; LOG(info) << "EMCal Photon Cut, set minimum number of cells per cluster: " << mMinNCell; } + void EMCPhotonCut::SetM02Range(float min, float max) { mMinM02 = min; mMaxM02 = max; LOG(info) << "EMCal Photon Cut, set minimum and maximum M02: " << mMinM02 << " <= M02 <= " << mMaxM02; } + void EMCPhotonCut::SetTimeRange(float min, float max) { mMinTime = min; mMaxTime = max; LOG(info) << "EMCal Photon Cut, set cluster time range in ns: " << mMinTime << " <= t <= " << mMaxTime; } -void EMCPhotonCut::SetTrackMatchingEta(std::function funcTM) -{ - mTrackMatchingEta = funcTM; - LOG(info) << "EMCal Photon Cut, set max dEta for TM (e.g. track pT == 1.4 GeV): " << mTrackMatchingEta(1.4); -} -void EMCPhotonCut::SetTrackMatchingPhi(std::function funcTM) -{ - mTrackMatchingPhi = funcTM; - LOG(info) << "EMCal Photon Cut, set max dPhi for TM (e.g. track pT == 1.4 GeV): " << mTrackMatchingPhi(1.4); -} + void EMCPhotonCut::SetMinEoverP(float min) { mMinEoverP = min; } + 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::SetUseSecondaryTM(bool flag) +{ + mUseSecondaryTM = flag; + LOG(info) << "EM Photon Cluster Cut, using secondary 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; @@ -79,7 +102,7 @@ void EMCPhotonCut::print() const case EMCPhotonCuts::kTiming: LOG(info) << mCutNames[i] << " in [" << mMinTime << ", " << mMaxTime << "]"; break; - // currently unsure how to do this in a nice way + // TODO: find a nice way to print TM cuts // case EMCPhotonCuts::kTM: // LOG(info) << mCutNames[i] << " > " << mMinNCrossedRowsOverFindableClustersTPC; // break; diff --git a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h index 1a2e0f28b48..e7becec48b5 100644 --- a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h +++ b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h @@ -9,22 +9,25 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// -// Class for emcal photon selection -// +/// \file EMCPhotonCut.h +/// \brief Header of class for emcal photon selection. +/// \author M. Hemmer, marvin.hemmer@cern.ch; N. Strangmann, nicolas.strangmann@cern.ch #ifndef PWGEM_PHOTONMESON_CORE_EMCPHOTONCUT_H_ #define PWGEM_PHOTONMESON_CORE_EMCPHOTONCUT_H_ -#include -#include -#include +#include + +#include + +#include #include -#include -#include "Framework/Logger.h" -#include "Framework/DataTypes.h" -#include "Rtypes.h" -#include "TNamed.h" + +struct TrackMatchingParams { + float a{0.01f}; + float b{4.07f}; + float c{-2.5f}; +}; class EMCPhotonCut : public TNamed { @@ -34,50 +37,63 @@ class EMCPhotonCut : public TNamed enum class EMCPhotonCuts : int { // cluster cut - kEnergy = 0, + kDefinition = 0, + kEnergy, kNCell, kM02, kTiming, kTM, + kSecondaryTM, kExotic, kNCuts }; static const char* mCutNames[static_cast(EMCPhotonCuts::kNCuts)]; - // Temporary function to check if cluster passes selection criteria. To be replaced by framework filters. + /// \brief check if given cluster survives all cuts + /// \param cluster cluster to check + /// \return true if cluster survives all cuts else false 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 (mUseSecondaryTM && (!IsSelectedEMCal(EMCPhotonCuts::kSecondaryTM, 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 + /// \brief check if given cluster survives a given cut + /// \param cut enum of the cluster cut to check + /// \param cluster cluster to check + /// \return true if cluster survives cut else false + 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; @@ -91,21 +107,37 @@ class EMCPhotonCut : public TNamed return mMinTime <= cluster.time() && cluster.time() <= mMaxTime; case EMCPhotonCuts::kTM: { - auto trackseta = cluster.tracketa(); // std:vector - auto tracksphi = cluster.trackphi(); // std:vector - auto trackspt = cluster.trackpt(); // std:vector - auto tracksp = cluster.trackp(); // std:vector + auto dEtas = cluster.deltaEta(); // std:vector + auto dPhis = cluster.deltaPhi(); // std:vector + auto trackspt = cluster.trackpt(); // std:vector + auto tracksp = cluster.trackp(); // std:vector int ntrack = tracksp.size(); for (int itr = 0; itr < ntrack; itr++) { - float dEta = fabs(trackseta[itr] - cluster.eta()); - float dPhi = fabs(tracksphi[itr] - cluster.phi()); - bool result = (dEta > mTrackMatchingEta(trackspt[itr])) || (dPhi > mTrackMatchingPhi(trackspt[itr])) || (cluster.e() / tracksp[itr] >= mMinEoverP); + float dEta = std::fabs(dEtas[itr]); + float dPhi = std::fabs(dPhis[itr]); + bool result = (dEta > GetTrackMatchingEta(trackspt[itr])) || (dPhi > GetTrackMatchingPhi(trackspt[itr])) || (cluster.e() / tracksp[itr] >= mMinEoverP); if (!result) { return false; } } return true; // when we don't have any tracks the cluster should always survive the TM cut! } + case EMCPhotonCuts::kSecondaryTM: { + auto dEtas = cluster.deltaEtaSec(); // std:vector + auto dPhis = cluster.deltaPhiSec(); // std:vector + auto trackspt = cluster.trackptSec(); // std:vector + auto tracksp = cluster.trackpSec(); // std:vector + int ntrack = tracksp.size(); + for (int itr = 0; itr < ntrack; itr++) { + float dEta = std::fabs(dEtas[itr]); + float dPhi = std::fabs(dPhis[itr]); + bool result = (dEta > GetSecTrackMatchingEta(trackspt[itr])) || (dPhi > GetSecTrackMatchingPhi(trackspt[itr])); + if (!result) { + return false; + } + } + return true; // when we don't have any secondary tracks the cluster should always survive the secondary TM cut! + } case EMCPhotonCuts::kExotic: return mUseExoticCut ? !cluster.isExotic() : true; @@ -116,33 +148,131 @@ class EMCPhotonCut : public TNamed } // Setters + /// \brief Set clusterizer + /// \param clusterDefinitionString name of the clusterizer + void SetClusterizer(std::string clusterDefinitionString = "kV3Default"); + + /// \brief Set minimum cluster energy + /// \param min minimum cluster energy void SetMinE(float min = 0.7f); + + /// \brief Set minimum number of cells per cluster + /// \param min minimum number of cells per cluster void SetMinNCell(int min = 1); + + /// \brief Set cluster M02 range to select + /// \param min minimum allowed cluster M02 + /// \param max maximum allowed cluster M02 void SetM02Range(float min = 0.1f, float max = 0.7f); + + /// \brief Set cluster time range to select + /// \param min minimum allowed cluster time + /// \param max maximum allowed cluster time void SetTimeRange(float min = -20.f, float max = 25.f); - void SetTrackMatchingEta(std::function funcTM); - void SetTrackMatchingPhi(std::function funcTM); + + /// \brief Set minimum cluster E over track momentum for track matching + /// \param min minimum allowed E/p void SetMinEoverP(float min = 0.7f); + + /// \brief Set flag to reject exotic cluster + /// \param flag flag to reject exotic cluster void SetUseExoticCut(bool flag = true); - /// @brief Print the cluster selection + /// \brief Set flag to use track matching + /// \param flag flag to use track matching + void SetUseTM(bool flag = true); + + /// \brief Set flag to use secondary track matching + /// \param flag flag to use secondary track matching + void SetUseSecondaryTM(bool flag = false); + + /// \brief Set parameters for track matching delta eta = a + (pT + b)^c + /// \param a a in a + (pT + b)^c + /// \param b b in a + (pT + b)^c + /// \param c c in a + (pT + b)^c + void SetTrackMatchingEtaParams(float a, float b, float c) + { + mTrackMatchingEtaParams = {a, b, c}; + } + + /// \brief Set parameters for track matching delta phi = a + (pT + b)^c + /// \param a a in a + (pT + b)^c + /// \param b b in a + (pT + b)^c + /// \param c c in a + (pT + b)^c + void SetTrackMatchingPhiParams(float a, float b, float c) + { + mTrackMatchingPhiParams = {a, b, c}; + } + + /// \brief Set parameters for secondary track matching delta eta = a + (pT + b)^c + /// \param a a in a + (pT + b)^c + /// \param b b in a + (pT + b)^c + /// \param c c in a + (pT + b)^c + void SetSecTrackMatchingEtaParams(float a, float b, float c) + { + mSecTrackMatchingEtaParams = {a, b, c}; + } + + /// \brief Set parameters for secondary track matching delta phi = a + (pT + b)^c + /// \param a a in a + (pT + b)^c + /// \param b b in a + (pT + b)^c + /// \param c c in a + (pT + b)^c + void SetSecTrackMatchingPhiParams(float a, float b, float c) + { + mSecTrackMatchingPhiParams = {a, b, c}; + } + + /// \brief calculate delta eta for track matching at given track pT + /// \param pT track pT + float GetTrackMatchingEta(float pT) const + { + return mTrackMatchingEtaParams.a + std::pow(pT + mTrackMatchingEtaParams.b, mTrackMatchingEtaParams.c); + } + + /// \brief calculate delta phi for track matching at given track pT + /// \param pT track pT + float GetTrackMatchingPhi(float pT) const + { + return mTrackMatchingPhiParams.a + std::pow(pT + mTrackMatchingPhiParams.b, mTrackMatchingPhiParams.c); + } + + /// \brief calculate delta eta for secondary track matching at given track pT + /// \param pT track pT + float GetSecTrackMatchingEta(float pT) const + { + return mSecTrackMatchingEtaParams.a + std::pow(pT + mSecTrackMatchingEtaParams.b, mSecTrackMatchingEtaParams.c); + } + + /// \brief calculate delta phi for secondary track matching at given track pT + /// \param pT track pT + float GetSecTrackMatchingPhi(float pT) const + { + return mSecTrackMatchingPhiParams.a + std::pow(pT + mSecTrackMatchingPhiParams.b, mSecTrackMatchingPhiParams.c); + } + + /// \brief Print the cluster selection void print() const; private: // EMCal cluster cuts - float mMinE{0.7f}; ///< minimum energy - int mMinNCell{1}; ///< minimum number of cells per cluster - float mMinM02{0.1f}; ///< minimum M02 for a cluster - float mMaxM02{0.7f}; ///< maximum M02 for a cluster - float mMinTime{-20.f}; ///< minimum cluster timing - 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 - - 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 - - ClassDef(EMCPhotonCut, 1); + 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 + float mMaxM02{0.7f}; ///< maximum M02 for a cluster + float mMinTime{-20.f}; ///< minimum cluster timing + 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 + bool mUseSecondaryTM{false}; ///< flag to decide if seconary track matching cut is to be checek or not + + TrackMatchingParams mTrackMatchingEtaParams = {-1.f, 0.f, 0.f}; + TrackMatchingParams mTrackMatchingPhiParams = {-1.f, 0.f, 0.f}; + TrackMatchingParams mSecTrackMatchingEtaParams = {-1.f, 0.f, 0.f}; + TrackMatchingParams mSecTrackMatchingPhiParams = {-1.f, 0.f, 0.f}; + + ClassDef(EMCPhotonCut, 2); }; #endif // PWGEM_PHOTONMESON_CORE_EMCPHOTONCUT_H_ diff --git a/PWGEM/PhotonMeson/Core/HistogramsLibrary.cxx b/PWGEM/PhotonMeson/Core/HistogramsLibrary.cxx index 50174ab9e08..e54a462e9dc 100644 --- a/PWGEM/PhotonMeson/Core/HistogramsLibrary.cxx +++ b/PWGEM/PhotonMeson/Core/HistogramsLibrary.cxx @@ -9,28 +9,25 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// Contact: daiki.sekihata@cern.ch -// -#include -#include -#include -using namespace std; +/// \file HistogramsLibrary.cxx +/// \brief Small histogram library for photon and meson analysis. +/// \author D. Sekihata, daiki.sekihata@cern.ch + +#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" + +#include -#include -#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include "Framework/Logger.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include + +#include + +#include + +using namespace std; void o2::aod::pwgem::photon::histogram::DefineHistograms(THashList* list, const char* histClass, const char* subGroup) { @@ -184,7 +181,7 @@ void o2::aod::pwgem::photon::histogram::DefineHistograms(THashList* list, const list->Add(new TH2F("hEtaRec_DeltaEta", "photon #eta resolution;#eta^{rec} of conversion point;#eta^{rec} - #eta^{gen}", 400, -2, +2, 400, -1.0f, 1.0f)); list->Add(new TH2F("hEtaRec_DeltaPhi", "photon #varphi resolution;#eta^{rec} of conversion point;#varphi^{rec} - #varphi^{gen} (rad.)", 400, -2, +2, 400, -1.0f, 1.0f)); } // end of mc - } // end of V0 + } // end of V0 if (TString(histClass).Contains("Dalitz")) { THnSparseF* hs_dilepton_uls_same = nullptr; @@ -576,7 +573,7 @@ void o2::aod::pwgem::photon::histogram::DefineHistograms(THashList* list, const hs_conv_point_mix->Sumw2(); list->Add(hs_conv_point_mix); } // end of pair - } // end of material budget study + } // end of material budget study if (TString(histClass) == "Generated") { list->Add(new TH1F("hCollisionCounter", "hCollisionCounter", 5, 0.5f, 5.5f)); diff --git a/PWGEM/PhotonMeson/Core/HistogramsLibrary.h b/PWGEM/PhotonMeson/Core/HistogramsLibrary.h index 324718a663e..368acef59ce 100644 --- a/PWGEM/PhotonMeson/Core/HistogramsLibrary.h +++ b/PWGEM/PhotonMeson/Core/HistogramsLibrary.h @@ -8,34 +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. -// -// Contact: daiki.sekihata@cern.ch -// + +/// \file HistogramsLibrary.h +/// \brief Small histogram library for photon and meson analysis. +/// \author D. Sekihata, daiki.sekihata@cern.ch #ifndef PWGEM_PHOTONMESON_CORE_HISTOGRAMSLIBRARY_H_ #define PWGEM_PHOTONMESON_CORE_HISTOGRAMSLIBRARY_H_ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/RecoDecay.h" +#include +#include +#include + +#include +#include +#include + enum EMHistType { kEvent = 0, kEvent_Cent = 1, @@ -48,6 +39,8 @@ enum EMHistType { kEMCCluster = 8, }; +const float maxZ = 10.f; + namespace o2::aod { namespace pwgem::photon::histogram @@ -81,7 +74,7 @@ void FillHistClass(THashList* list, const char* subGroup, T1 const& obj1 /*, con if (obj1.sel8()) { reinterpret_cast(list->FindObject("hCollisionCounter"))->Fill("sel8", 1.f); } - if (abs(obj1.posZ()) < 10.0) { + if (std::abs(obj1.posZ()) < maxZ) { reinterpret_cast(list->FindObject("hCollisionCounter"))->Fill("|Z_{vtx}| < 10 cm", 1.f); } @@ -176,9 +169,9 @@ void FillHistClass(THashList* list, const char* subGroup, T1 const& obj1 /*, con reinterpret_cast(list->FindObject("hQoverPt"))->Fill(obj1.sign() / obj1.pt()); reinterpret_cast(list->FindObject("hEtaPhi"))->Fill(obj1.phi(), obj1.eta()); reinterpret_cast(list->FindObject("hDCAxyz"))->Fill(obj1.dcaXY(), obj1.dcaZ()); - reinterpret_cast(list->FindObject("hDCAxyzSigma"))->Fill(obj1.dcaXY() / sqrt(obj1.cYY()), obj1.dcaZ() / sqrt(obj1.cZZ())); - reinterpret_cast(list->FindObject("hDCAxyRes_Pt"))->Fill(obj1.pt(), sqrt(obj1.cYY()) * 1e+4); // convert cm to um - reinterpret_cast(list->FindObject("hDCAzRes_Pt"))->Fill(obj1.pt(), sqrt(obj1.cZZ()) * 1e+4); // convert cm to um + reinterpret_cast(list->FindObject("hDCAxyzSigma"))->Fill(obj1.dcaXY() / std::sqrt(obj1.cYY()), obj1.dcaZ() / std::sqrt(obj1.cZZ())); + reinterpret_cast(list->FindObject("hDCAxyRes_Pt"))->Fill(obj1.pt(), std::sqrt(obj1.cYY()) * 1e+4); // convert cm to um + reinterpret_cast(list->FindObject("hDCAzRes_Pt"))->Fill(obj1.pt(), std::sqrt(obj1.cZZ()) * 1e+4); // convert cm to um reinterpret_cast(list->FindObject("hNclsITS"))->Fill(obj1.itsNCls()); reinterpret_cast(list->FindObject("hNclsTPC"))->Fill(obj1.tpcNClsFound()); reinterpret_cast(list->FindObject("hNcrTPC"))->Fill(obj1.tpcNClsCrossedRows()); @@ -225,8 +218,8 @@ void FillHistClass(THashList* list, const char* subGroup, T1 const& obj1 /*, con reinterpret_cast(list->FindObject("hPt"))->Fill(obj1.pt()); reinterpret_cast(list->FindObject("hE"))->Fill(obj1.e()); reinterpret_cast(list->FindObject("hEtaPhi"))->Fill(obj1.phi(), obj1.eta()); - for (size_t itrack = 0; itrack < obj1.tracketa().size(); itrack++) { // Fill TrackEtaPhi histogram with delta phi and delta eta of all tracks saved in the vectors in skimmerGammaCalo.cxx - reinterpret_cast(list->FindObject("hTrackEtaPhi"))->Fill(obj1.trackphi()[itrack] - obj1.phi(), obj1.tracketa()[itrack] - obj1.eta()); + for (size_t itrack = 0; itrack < obj1.deltaEta().size(); itrack++) { // Fill TrackEtaPhi histogram with delta phi and delta eta of all tracks saved in the vectors in skimmerGammaCalo.cxx + reinterpret_cast(list->FindObject("hTrackEtaPhi"))->Fill(obj1.deltaPhi()[itrack], obj1.deltaEta()[itrack]); } } } diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h index a01fd1bbfd4..7b845f5399c 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h @@ -9,196 +9,200 @@ // 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 +/// \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 "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/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/NMHistograms.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +// Dilepton headers #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::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 = MyEMCClusters::iterator; +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include // IWYU pragma: keep +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include -template +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 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{"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"}; + o2::framework::Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + o2::framework::Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + o2::framework::Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + o2::framework::Configurable ndiff_bc_mix{"ndiff_bc_mix", 594, "difference in global BC required in mixed events"}; + + o2::framework::Configurable cfgQvecEstimator{"cfgQvecEstimator", 0, "FT0M:0, FT0A:1, FT0C:2"}; + o2::framework::Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + o2::framework::Configurable cfgOccupancyEstimator{"cfgOccupancyEstimator", 0, "FT0C:0, Track:1"}; + o2::framework::Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; + o2::framework::Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + o2::framework::Configurable maxY{"maxY", 0.8, "maximum rapidity for reconstructed particles"}; + o2::framework::Configurable cfgDoMix{"cfgDoMix", true, "flag for event mixing"}; + o2::framework::Configurable ndepth{"ndepth", 10, "depth for event mixing"}; + o2::framework::ConfigurableAxis ConfVtxBins{"ConfVtxBins", {o2::framework::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"}; + o2::framework::ConfigurableAxis ConfCentBins{"ConfCentBins", {o2::framework::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"}; + o2::framework::ConfigurableAxis ConfEPBins{"ConfEPBins", {o2::framework::VARIABLE_WIDTH, -o2::constants::math::PIHalf, -o2::constants::math::PIQuarter, 0.0f, +o2::constants::math::PIQuarter, +o2::constants::math::PIHalf}, "Mixing bins - event plane angle"}; + o2::framework::ConfigurableAxis ConfOccupancyBins{"ConfOccupancyBins", {o2::framework::VARIABLE_WIDTH, -1, 1e+10}, "Mixing bins - occupancy"}; EMPhotonEventCut fEMEventCut; - struct : ConfigurableGroup { + struct : o2::framework::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"}; + o2::framework::Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + o2::framework::Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + o2::framework::Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + o2::framework::Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + o2::framework::Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + o2::framework::Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + o2::framework::Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + o2::framework::Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + o2::framework::Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + o2::framework::Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", false, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + o2::framework::Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + o2::framework::Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + o2::framework::Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + o2::framework::Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + o2::framework::Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + o2::framework::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 { + struct : o2::framework::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_require_v0_on_wwire_ib{"cfg_require_v0_on_wwire_ib", false, "flag to select V0s on W wires ITSib"}; - 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_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_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"}; + o2::framework::Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + o2::framework::Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + o2::framework::Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + o2::framework::Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + o2::framework::Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + o2::framework::Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; + o2::framework::Configurable cfg_max_eta_v0{"cfg_max_eta_v0", 0.8, "max eta for v0 photons at PV"}; + o2::framework::Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + o2::framework::Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + o2::framework::Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + o2::framework::Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + o2::framework::Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "min V0 CosPA"}; + o2::framework::Configurable cfg_max_pca{"cfg_max_pca", 1.5, "max distance btween 2 legs"}; + o2::framework::Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + o2::framework::Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + o2::framework::Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter to V0"}; + + o2::framework::Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + o2::framework::Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + o2::framework::Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + o2::framework::Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + o2::framework::Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.0, "max chi2/NclsITS"}; + o2::framework::Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + o2::framework::Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + o2::framework::Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + o2::framework::Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; } pcmcuts; DalitzEECut fDileptonCut; - struct : ConfigurableGroup { + struct : o2::framework::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_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.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", 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_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTPConly), "pid scheme [kTPConly : 0]"}; - 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", -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"}; + o2::framework::Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + o2::framework::Configurable cfg_max_mass{"cfg_max_mass", 0.1, "max mass"}; + o2::framework::Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + o2::framework::Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + o2::framework::Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + o2::framework::Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + o2::framework::Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + o2::framework::Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + o2::framework::Configurable cfg_max_eta_track{"cfg_max_eta_track", 0.8, "max eta for single track"}; + o2::framework::Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + o2::framework::Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + o2::framework::Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 70, "min ncrossed rows"}; + o2::framework::Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + o2::framework::Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.0, "max chi2/NclsITS"}; + o2::framework::Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.05, "max dca XY for single track in cm"}; + o2::framework::Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.05, "max dca Z for single track in cm"}; + o2::framework::Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + o2::framework::Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + o2::framework::Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter to electron"}; + o2::framework::Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + o2::framework::Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + o2::framework::Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + o2::framework::Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + o2::framework::Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + o2::framework::Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + o2::framework::Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + o2::framework::Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + o2::framework::Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; } dileptoncuts; EMCPhotonCut fEMCCut; - struct : ConfigurableGroup { + struct : o2::framework::ConfigurableGroup { std::string prefix = "emccut_group"; - 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"}; + o2::framework::Configurable clusterDefinition{"clusterDefinition", "kV3Default", "Clusterizer to be selected, e.g. V3Default"}; + o2::framework::Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; + o2::framework::Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; + o2::framework::Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; + o2::framework::Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + o2::framework::Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + o2::framework::Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + o2::framework::Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + o2::framework::Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + o2::framework::Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + o2::framework::Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + o2::framework::Configurable EMC_UseExoticCut{"EMC_UseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + o2::framework::Configurable cfgDistanceToEdge{"cfgDistanceToEdge", 1, "Distance to edge in cells required for rotated cluster to be accepted"}; } emccuts; PHOSPhotonCut fPHOSCut; - struct : ConfigurableGroup { + struct : o2::framework::ConfigurableGroup { std::string prefix = "phoscut_group"; - Configurable cfg_min_Ecluster{"cfg_min_Ecluster", 0.3, "Minimum cluster energy for PHOS in GeV"}; + o2::framework::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/"}; + o2::framework::HistogramRegistry fRegistry{"output", {}, o2::framework::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; @@ -206,11 +210,12 @@ struct Pi0EtaToGammaGamma { std::vector occ_bin_edges; o2::ccdb::CcdbApi ccdbApi; - Service ccdb; + o2::framework::Service ccdb; int mRunNumber; float d_bz; + o2::emcal::Geometry* emcalGeom; - void init(InitContext&) + void init(o2::framework::InitContext&) { zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); zvtx_bin_edges.erase(zvtx_bin_edges.begin()); @@ -221,17 +226,16 @@ struct Pi0EtaToGammaGamma { 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); + emh1 = new o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, o2::aod::pwgem::dilepton::utils::EMTrack>(ndepth); + emh2 = new o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, o2::aod::pwgem::dilepton::utils::EMTrack>(ndepth); o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); - if constexpr (pairtype == PairType::kPCMDalitzEE) { + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMDalitzEE) { o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, false, "ee#gamma"); - } else if constexpr (pairtype == PairType::kPCMDalitzMuMu) { - o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, false, "#mu#mu#gamma"); } else { o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, false, "#gamma#gamma"); } @@ -241,10 +245,11 @@ struct Pi0EtaToGammaGamma { DefineEMCCut(); DefinePHOSCut(); - if constexpr (pairtype == kEMCEMC) { + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kEMCEMC) { fRegistry.addClone("Pair/same/", "Pair/rotation/"); - o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + emcalGeom = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); } + fRegistry.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current} - BC_{mixed}|", o2::framework::kTH1D, {{10001, -0.5, 10000.5}}, true); mRunNumber = 0; d_bz = 0; @@ -266,7 +271,7 @@ struct Pi0EtaToGammaGamma { 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)); } mRunNumber = collision.runNumber(); @@ -301,10 +306,11 @@ struct Pi0EtaToGammaGamma { delete emh2; emh2 = 0x0; - used_photonIds.clear(); - used_photonIds.shrink_to_fit(); - used_dileptonIds.clear(); - used_dileptonIds.shrink_to_fit(); + used_photonIds_per_col.clear(); + used_photonIds_per_col.shrink_to_fit(); + used_dileptonIds_per_col.clear(); + used_dileptonIds_per_col.shrink_to_fit(); + map_mixed_eventId_to_globalBC.clear(); } void DefineEMEventCut() @@ -312,7 +318,7 @@ struct Pi0EtaToGammaGamma { fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); - fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); @@ -320,7 +326,6 @@ struct Pi0EtaToGammaGamma { fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); } void DefinePCMCut() @@ -328,52 +333,30 @@ struct Pi0EtaToGammaGamma { 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.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.SetTrackPtRange(pcmcuts.cfg_min_pt_v0 * 0.5, 1e+10f); - fV0PhotonCut.SetTrackEtaRange(-pcmcuts.cfg_max_eta_v0, +pcmcuts.cfg_max_eta_v0); 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); - if (pcmcuts.cfg_reject_v0_on_itsib) { - fV0PhotonCut.SetNClustersITS(2, 4); - } else { - fV0PhotonCut.SetNClustersITS(0, 7); - } + fV0PhotonCut.SetNClustersITS(0, 7); fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); - fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); - - if (pcmcuts.cfg_require_v0_with_itstpc) { - fV0PhotonCut.SetRequireITSTPC(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 40); - } - if (pcmcuts.cfg_require_v0_with_itsonly) { - fV0PhotonCut.SetRequireITSonly(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 24); - } - if (pcmcuts.cfg_require_v0_with_tpconly) { - fV0PhotonCut.SetRequireTPConly(true); - fV0PhotonCut.SetMaxPCA(3.0); - fV0PhotonCut.SetRxyRange(36, 90); - } - if (pcmcuts.cfg_require_v0_on_wwire_ib) { - fV0PhotonCut.SetMaxPCA(0.3); - fV0PhotonCut.SetOnWwireIB(true); - fV0PhotonCut.SetOnWwireOB(false); - fV0PhotonCut.SetRxyRange(7, 14); - } + 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() @@ -393,36 +376,34 @@ struct Pi0EtaToGammaGamma { 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 + fDileptonCut.IncludeITSsa(dileptoncuts.includeITSsa, dileptoncuts.cfg_max_pt_track_ITSsa); // 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 + pow(pT + b, c); }); - fEMCCut.SetTrackMatchingPhi([&d, &e, &f](float pT) { return d + pow(pT + e, f); }); + fEMCCut.SetTrackMatchingEtaParams(emccuts.EMC_TM_Eta->at(0), emccuts.EMC_TM_Eta->at(1), emccuts.EMC_TM_Eta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.EMC_TM_Phi->at(0), emccuts.EMC_TM_Phi->at(1), emccuts.EMC_TM_Phi->at(2)); fEMCCut.SetMinEoverP(emccuts.EMC_Eoverp); fEMCCut.SetUseExoticCut(emccuts.EMC_UseExoticCut); @@ -433,25 +414,87 @@ struct Pi0EtaToGammaGamma { 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) + 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 + const float rotationAngle = o2::constants::math::PIHalf; // rotaion angle 90 degree ROOT::Math::AxisAngle rotationAxis(meson.Vect(), rotationAngle); ROOT::Math::Rotation3D rotationMatrix(rotationAxis); photon1 = rotationMatrix * photon1; photon2 = rotationMatrix * photon2; - for (auto& photon : photons_coll) { + 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::iterator>(photon))) { + continue; + } ROOT::Math::PtEtaPhiMVector photon3(photon.pt(), photon.eta(), photon.phi(), 0.); ROOT::Math::PtEtaPhiMVector mother1 = photon1 + photon3; @@ -460,43 +503,30 @@ struct Pi0EtaToGammaGamma { 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())); - int iCellID_photon1 = 0; - int iCellID_photon2 = 0; - - try { - iCellID_photon1 = o2::emcal::Geometry::GetInstance()->GetAbsCellIdFromEtaPhi(photon1.Eta(), photon1.Phi()); - } catch (o2::emcal::InvalidPositionException& e) { - iCellID_photon1 = -1; - } - try { - iCellID_photon2 = o2::emcal::Geometry::GetInstance()->GetAbsCellIdFromEtaPhi(photon2.Eta(), photon2.Phi()); - } catch (o2::emcal::InvalidPositionException& e) { - iCellID_photon2 = -1; - } - - if (openingAngle1 > emccuts.minOpenAngle && abs(mother1.Rapidity()) < maxY && iCellID_photon1 > 0) { - fRegistry.fill(HIST("Pair/rotation/hs"), mother1.M(), mother1.Pt()); + 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 && abs(mother2.Rapidity()) < maxY && iCellID_photon2 > 0) { - fRegistry.fill(HIST("Pair/rotation/hs"), mother2.M(), mother2.Pt()); + 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; + o2::framework::SliceCache cache; + o2::framework::Preslice>> perCollision_pcm = o2::aod::v0photonkf::emeventId; + o2::framework::Preslice> perCollision_emc = o2::aod::emccluster::emeventId; + o2::framework::Preslice> perCollision_phos = o2::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); + o2::framework::Preslice>> perCollision_electron = o2::aod::emprimaryelectron::emeventId; + o2::framework::Partition>> positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && dileptoncuts.cfg_min_pt_track < o2::aod::track::pt&& nabs(o2::aod::track::eta) < dileptoncuts.cfg_max_eta_track; + o2::framework::Partition>> electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && dileptoncuts.cfg_min_pt_track < o2::aod::track::pt && nabs(o2::aod::track::eta) < dileptoncuts.cfg_max_eta_track; - 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; // + o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, o2::aod::pwgem::dilepton::utils::EMTrack>* emh1 = nullptr; + o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, o2::aod::pwgem::dilepton::utils::EMTrack>* emh2 = nullptr; + std::vector used_photonIds_per_col; // + std::vector> used_dileptonIds_per_col; // + std::map, uint64_t> map_mixed_eventId_to_globalBC; template void runPairing(TCollisions const& collisions, @@ -505,10 +535,19 @@ struct Pi0EtaToGammaGamma { TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCut1 const& cut1, TCut2 const& cut2) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { initCCDB(collision); int ndiphoton = 0; - if ((pairtype == PairType::kPHOSPHOS || pairtype == PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { + if ((pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPHOSPHOS || pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { + continue; + } + + float weight = 1.f; + if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { + weight = collision.weight(); + } + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(weight - 1.f) < 1E-10) { continue; } @@ -517,13 +556,13 @@ struct Pi0EtaToGammaGamma { continue; } - o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision); + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, weight); if (!fEMEventCut.IsSelected(collision)) { 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 + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, weight); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, weight); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, weight); // accepted int zbin = lower_bound(zvtx_bin_edges.begin(), zvtx_bin_edges.end(), collision.posZ()) - zvtx_bin_edges.begin() - 1; if (zbin < 0) { @@ -548,7 +587,15 @@ struct Pi0EtaToGammaGamma { epbin = static_cast(ep_bin_edges.size()) - 2; } - int occbin = lower_bound(occ_bin_edges.begin(), occ_bin_edges.end(), collision.trackOccupancyInTimeRange()) - occ_bin_edges.begin() - 1; + 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) { @@ -560,11 +607,11 @@ struct Pi0EtaToGammaGamma { 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 + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM || pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPHOSPHOS || pairtype == o2::aod::pwgem::photonmeson::photonpair::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))) { + for (const auto& [g1, g2] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(photons1_per_collision, photons2_per_collision))) { if (!cut1.template IsSelected(g1) || !cut2.template IsSelected(g2)) { continue; } @@ -572,35 +619,39 @@ struct Pi0EtaToGammaGamma { 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) { + if (std::fabs(v12.Rapidity()) > maxY) { continue; } - fRegistry.fill(HIST("Pair/same/hs"), v12.M(), v12.Pt()); - - if constexpr (pairtype == PairType::kEMCEMC) { - RotationBackground(v12, v1, v2, photons2_per_collision, g1.globalIndex(), g2.globalIndex()); + if (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kEMCEMC) { + float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); + if (openingAngle < emccuts.minOpenAngle) { + continue; + } } - std::pair pair_tmp_id1 = std::make_pair(ndf, g1.globalIndex()); - std::pair pair_tmp_id2 = std::make_pair(ndf, g2.globalIndex()); + fRegistry.fill(HIST("Pair/same/hs"), v12.M(), v12.Pt(), weight); - if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id1) == used_photonIds.end()) { - emh1->AddTrackToEventPool(key_df_collision, EMTrack(g1.globalIndex(), collision.globalIndex(), g1.globalIndex(), g1.pt(), g1.eta(), g1.phi(), 0)); - used_photonIds.emplace_back(pair_tmp_id1); + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kEMCEMC) { + RotationBackground>(v12, v1, v2, photons2_per_collision, g1.globalIndex(), g2.globalIndex(), weight); } - if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id2) == used_photonIds.end()) { - emh1->AddTrackToEventPool(key_df_collision, EMTrack(g2.globalIndex(), collision.globalIndex(), g2.globalIndex(), g2.pt(), g2.eta(), g2.phi(), 0)); - used_photonIds.emplace_back(pair_tmp_id2); + + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, o2::aod::pwgem::dilepton::utils::EMTrack(g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds_per_col.emplace_back(g1.globalIndex()); + } + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g2.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, o2::aod::pwgem::dilepton::utils::EMTrack(g2.pt(), g2.eta(), g2.phi(), 0)); + used_photonIds_per_col.emplace_back(g2.globalIndex()); } ndiphoton++; } // end of pairing loop - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + for (const auto& g1 : photons1_per_collision) { if (!cut1.template IsSelected(g1)) { continue; } @@ -608,7 +659,7 @@ struct Pi0EtaToGammaGamma { auto ele1 = g1.template negTrack_as(); ROOT::Math::PtEtaPhiMVector v_gamma(g1.pt(), g1.eta(), g1.phi(), 0.); - for (auto& [pos2, ele2] : combinations(CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { + for (const auto& [pos2, ele2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(positrons_per_collision, electrons_per_collision))) { if (pos2.trackId() == ele2.trackId()) { // this is protection against pairing identical 2 tracks. continue; @@ -629,56 +680,57 @@ struct Pi0EtaToGammaGamma { 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 (abs(veeg.Rapidity()) > maxY) { + if (std::fabs(veeg.Rapidity()) > maxY) { continue; } - fRegistry.fill(HIST("Pair/same/hs"), veeg.M(), veeg.Pt()); + fRegistry.fill(HIST("Pair/same/hs"), veeg.M(), veeg.Pt(), 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(g1.globalIndex(), collision.globalIndex(), -1, g1.pt(), g1.eta(), g1.phi(), 0)); - used_photonIds.emplace_back(pair_tmp_id1); + std::pair tuple_tmp_id2 = std::make_pair(pos2.trackId(), ele2.trackId()); + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, o2::aod::pwgem::dilepton::utils::EMTrack(g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds_per_col.emplace_back(g1.globalIndex()); } - if (std::find(used_dileptonIds.begin(), used_dileptonIds.end(), tuple_tmp_id2) == used_dileptonIds.end()) { - emh2->AddTrackToEventPool(key_df_collision, EMTrack(-1, collision.globalIndex(), -1, v_ee.Pt(), v_ee.Eta(), v_ee.Phi(), v_ee.M())); - used_dileptonIds.emplace_back(tuple_tmp_id2); + if (std::find(used_dileptonIds_per_col.begin(), used_dileptonIds_per_col.end(), tuple_tmp_id2) == used_dileptonIds_per_col.end()) { + emh2->AddTrackToEventPool(key_df_collision, o2::aod::pwgem::dilepton::utils::EMTrack(v_ee.Pt(), v_ee.Eta(), v_ee.Phi(), v_ee.M())); + used_dileptonIds_per_col.emplace_back(tuple_tmp_id2); } ndiphoton++; - } // end of dielectron loop - } // end of g1 loop + } // 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 (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_collision, photons2_per_collision))) { + for (const auto& [g1, g2] : o2::soa::combinations(o2::soa::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 (abs(v12.Rapidity()) > maxY) { + if (std::fabs(v12.Rapidity()) > maxY) { continue; } - fRegistry.fill(HIST("Pair/same/hs"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/same/hs"), v12.M(), v12.Pt(), 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(g1.globalIndex(), collision.globalIndex(), -1, g1.pt(), g1.eta(), g1.phi(), 0)); - used_photonIds.emplace_back(pair_tmp_id1); + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, o2::aod::pwgem::dilepton::utils::EMTrack(g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds_per_col.emplace_back(g1.globalIndex()); } - if (std::find(used_photonIds.begin(), used_photonIds.end(), pair_tmp_id2) == used_photonIds.end()) { - emh2->AddTrackToEventPool(key_df_collision, EMTrack(g2.globalIndex(), collision.globalIndex(), -1, g2.pt(), g2.eta(), g2.phi(), 0)); - used_photonIds.emplace_back(pair_tmp_id2); + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g2.globalIndex()) == used_photonIds_per_col.end()) { + emh2->AddTrackToEventPool(key_df_collision, o2::aod::pwgem::dilepton::utils::EMTrack(g2.pt(), g2.eta(), g2.phi(), 0)); + used_photonIds_per_col.emplace_back(g2.globalIndex()); } ndiphoton++; } // end of pairing loop - } // end of pairing in same event + } // end of pairing in same event + + used_photonIds_per_col.clear(); + used_photonIds_per_col.shrink_to_fit(); + used_dileptonIds_per_col.clear(); + used_dileptonIds_per_col.shrink_to_fit(); // event mixing if (!cfgDoMix || !(ndiphoton > 0)) { @@ -692,8 +744,8 @@ struct Pi0EtaToGammaGamma { 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 (auto& mix_dfId_collisionId : collisionIds1_in_mixing_pool) { + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM || pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPHOSPHOS || pairtype == o2::aod::pwgem::photonmeson::photonpair::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; @@ -701,25 +753,32 @@ struct Pi0EtaToGammaGamma { 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) { + 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 (abs(v12.Rapidity()) > maxY) { + if (std::fabs(v12.Rapidity()) > maxY) { continue; } - fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt(), weight); } } } // end of loop over mixed event pool } else { // [photon1 from event1, photon2 from event2] and [photon1 from event2, photon2 from event1] - for (auto& mix_dfId_collisionId : collisionIds2_in_mixing_pool) { + 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; @@ -727,25 +786,32 @@ struct Pi0EtaToGammaGamma { 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) { - for (auto& g2 : photons2_from_event_pool) { + 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 || pairtype == PairType::kPCMDalitzMuMu) { //[photon from event1, dilepton from event2] and [photon from event2, dilepton from event1] + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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 (abs(v12.Rapidity()) > maxY) { + if (std::fabs(v12.Rapidity()) > maxY) { continue; } - fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt(), weight); } } } // end of loop over mixed event pool - for (auto& mix_dfId_collisionId : collisionIds1_in_mixing_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; @@ -753,21 +819,28 @@ struct Pi0EtaToGammaGamma { 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) { - for (auto& g2 : photons1_from_event_pool) { + 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 || pairtype == PairType::kPCMDalitzMuMu) { //[photon from event1, dilepton from event2] and [photon from event2, dilepton from event1] + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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 (abs(v12.Rapidity()) > maxY) { + if (std::fabs(v12.Rapidity()) > maxY) { continue; } - fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/mix/hs"), v12.M(), v12.Pt(), weight); } } } // end of loop over mixed event pool @@ -776,32 +849,75 @@ struct Pi0EtaToGammaGamma { 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_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; + o2::framework::expressions::Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + o2::framework::expressions::Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + o2::framework::expressions::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 = o2::soa::Filtered>; + + o2::framework::expressions::Filter prefilter_pcm = ifnode(pcmcuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::v0photonkf::pfbderived == static_cast(0), true); + o2::framework::expressions::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) + void processAnalysis(o2::soa::Filtered> const& collisions, Types const&... args) + { + // LOGF(info, "ndf = %d", ndf); + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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 == o2::aod::pwgem::photonmeson::photonpair::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 == o2::aod::pwgem::photonmeson::photonpair::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 == o2::aod::pwgem::photonmeson::photonpair::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", true); + + // using FilteredMyCollisionsWithJJMC = o2::soa::Filtered, o2::aod::EMEventsWeight>>; + void processAnalysisJJMC(o2::soa::Filtered, o2::aod::EMEventsWeight>> const& collisions, Types const&... args) { // LOGF(info, "ndf = %d", ndf); - if constexpr (pairtype == PairType::kPCMPCM) { + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPHOSPHOS) { auto phosclusters = std::get<0>(std::tie(args...)); runPairing(collisions, phosclusters, phosclusters, nullptr, nullptr, perCollision_phos, perCollision_phos, fPHOSCut, fPHOSCut); } @@ -819,9 +935,9 @@ struct Pi0EtaToGammaGamma { // } ndf++; } - PROCESS_SWITCH(Pi0EtaToGammaGamma, processAnalysis, "process pair analysis", false); + PROCESS_SWITCH(Pi0EtaToGammaGamma, processAnalysisJJMC, "process pair analysis", false); - void processDummy(MyCollisions const&) {} - PROCESS_SWITCH(Pi0EtaToGammaGamma, processDummy, "Dummy function", true); + void processDummy(o2::aod::EMEvents const&) {} + PROCESS_SWITCH(Pi0EtaToGammaGamma, processDummy, "Dummy function", false); }; #endif // PWGEM_PHOTONMESON_CORE_PI0ETATOGAMMAGAMMA_H_ diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h index be80a774247..df416caf9d4 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h @@ -9,205 +9,205 @@ // 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 +/// \file Pi0EtaToGammaGammaMC.h +/// \brief This code loops over photons and makes pairs for neutral mesons analyses with MC true info. +/// \author D. Sekihata, 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/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/NMHistograms.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" +// Dilepton headers #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; +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // IWYU pragma: keep +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include -template +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"}; + o2::framework::Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + o2::framework::Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + o2::framework::Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; + + o2::framework::Configurable cfgQvecEstimator{"cfgQvecEstimator", 0, "FT0M:0, FT0A:1, FT0C:2"}; + o2::framework::Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + o2::framework::Configurable cfgCentMin{"cfgCentMin", -1, "min. centrality"}; + o2::framework::Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + o2::framework::Configurable maxY_rec{"maxY_rec", 0.9, "maximum rapidity for reconstructed particles"}; + o2::framework::Configurable fd_k0s_to_pi0{"fd_k0s_pi0", "1.0", "feed down correction to pi0"}; + o2::framework::Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association"}; EMPhotonEventCut fEMEventCut; - struct : ConfigurableGroup { + struct : o2::framework::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"}; + o2::framework::Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + o2::framework::Configurable cfgZvtxMax{"cfgZvtxMax", +10.f, "max. Zvtx"}; + o2::framework::Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 in event cut"}; + o2::framework::Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + o2::framework::Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border in event cut"}; + o2::framework::Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + o2::framework::Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + o2::framework::Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + o2::framework::Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + o2::framework::Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", false, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + o2::framework::Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + o2::framework::Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. occupancy"}; + o2::framework::Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. occupancy"}; + o2::framework::Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. FT0C occupancy"}; + o2::framework::Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + o2::framework::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 { + struct : o2::framework::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_require_v0_on_wwire_ib{"cfg_require_v0_on_wwire_ib", false, "flag to select V0s on W wires ITSib"}; - 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_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_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"}; + o2::framework::Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; + o2::framework::Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; + o2::framework::Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; + o2::framework::Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + o2::framework::Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; + o2::framework::Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; + o2::framework::Configurable cfg_max_eta_v0{"cfg_max_eta_v0", 0.8, "max eta for v0 photons at PV"}; + o2::framework::Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; + o2::framework::Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; + o2::framework::Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; + o2::framework::Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; + o2::framework::Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "min V0 CosPA"}; + o2::framework::Configurable cfg_max_pca{"cfg_max_pca", 1.5, "max distance btween 2 legs"}; + o2::framework::Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; + o2::framework::Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; + o2::framework::Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter to V0"}; + + o2::framework::Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + o2::framework::Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; + o2::framework::Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + o2::framework::Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.0, "max chi2/NclsITS"}; + o2::framework::Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + o2::framework::Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + o2::framework::Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + o2::framework::Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; + o2::framework::Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; } pcmcuts; DalitzEECut fDileptonCut; - struct : ConfigurableGroup { + struct : o2::framework::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_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.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", 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_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTPConly), "pid scheme [kTPConly : 0]"}; - 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", -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"}; + o2::framework::Configurable cfg_min_mass{"cfg_min_mass", 0.0, "min mass"}; + o2::framework::Configurable cfg_max_mass{"cfg_max_mass", 0.1, "max mass"}; + o2::framework::Configurable cfg_apply_phiv{"cfg_apply_phiv", true, "flag to apply phiv cut"}; + o2::framework::Configurable cfg_require_itsib_any{"cfg_require_itsib_any", false, "flag to require ITS ib any hits"}; + o2::framework::Configurable cfg_require_itsib_1st{"cfg_require_itsib_1st", true, "flag to require ITS ib 1st hit"}; + o2::framework::Configurable cfg_phiv_slope{"cfg_phiv_slope", 0.0185, "slope for m vs. phiv"}; + o2::framework::Configurable cfg_phiv_intercept{"cfg_phiv_intercept", -0.0280, "intercept for m vs. phiv"}; + + o2::framework::Configurable cfg_min_pt_track{"cfg_min_pt_track", 0.1, "min pT for single track"}; + o2::framework::Configurable cfg_max_eta_track{"cfg_max_eta_track", 0.8, "max eta for single track"}; + o2::framework::Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; + o2::framework::Configurable cfg_min_ncluster_its{"cfg_min_ncluster_its", 5, "min ncluster its"}; + o2::framework::Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 70, "min ncrossed rows"}; + o2::framework::Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + o2::framework::Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; + o2::framework::Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.0, "max chi2/NclsITS"}; + o2::framework::Configurable cfg_max_dcaxy{"cfg_max_dcaxy", 0.05, "max dca XY for single track in cm"}; + o2::framework::Configurable cfg_max_dcaz{"cfg_max_dcaz", 0.05, "max dca Z for single track in cm"}; + o2::framework::Configurable cfg_max_dca3dsigma_track{"cfg_max_dca3dsigma_track", 1.5, "max DCA 3D in sigma"}; + o2::framework::Configurable cfg_apply_cuts_from_prefilter_derived{"cfg_apply_cuts_from_prefilter_derived", false, "flag to apply prefilter to electron"}; + o2::framework::Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + o2::framework::Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; + + o2::framework::Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + o2::framework::Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + o2::framework::Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + o2::framework::Configurable cfg_min_TPCNsigmaPi{"cfg_min_TPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + o2::framework::Configurable cfg_max_TPCNsigmaPi{"cfg_max_TPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + o2::framework::Configurable cfg_min_TOFNsigmaEl{"cfg_min_TOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + o2::framework::Configurable cfg_max_TOFNsigmaEl{"cfg_max_TOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; } dileptoncuts; EMCPhotonCut fEMCCut; - struct : ConfigurableGroup { + struct : o2::framework::ConfigurableGroup { std::string prefix = "emccut_group"; - 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"}; + o2::framework::Configurable clusterDefinition{"clusterDefinition", "kV3Default", "Clusterizer to be selected, e.g. V3Default"}; + o2::framework::Configurable minOpenAngle{"minOpenAngle", 0.0202, "apply min opening angle"}; + o2::framework::Configurable EMC_minTime{"EMC_minTime", -20., "Minimum cluster time for EMCal time cut"}; + o2::framework::Configurable EMC_maxTime{"EMC_maxTime", +25., "Maximum cluster time for EMCal time cut"}; + o2::framework::Configurable EMC_minM02{"EMC_minM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + o2::framework::Configurable EMC_maxM02{"EMC_maxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + o2::framework::Configurable EMC_minE{"EMC_minE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + o2::framework::Configurable EMC_minNCell{"EMC_minNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + o2::framework::Configurable> EMC_TM_Eta{"EMC_TM_Eta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + o2::framework::Configurable> EMC_TM_Phi{"EMC_TM_Phi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + o2::framework::Configurable EMC_Eoverp{"EMC_Eoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + o2::framework::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"}; + o2::framework::Configurable maxY_gen{"maxY_gen", 0.9, "maximum rapidity for generated particles"}; // for PCM and dielectron + o2::framework::Configurable maxRgen{"maxRgen", 90.f, "maximum radius for generated particles"}; + o2::framework::Configurable margin_z_mc{"margin_z_mc", 7.0, "margin for z cut in cm for MC"}; PHOSPhotonCut fPHOSCut; - struct : ConfigurableGroup { + struct : o2::framework::ConfigurableGroup { std::string prefix = "phoscut_group"; - Configurable cfg_min_Ecluster{"cfg_min_Ecluster", 0.3, "Minimum cluster energy for PHOS in GeV"}; + o2::framework::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::framework::HistogramRegistry fRegistry{"output", {}, o2::framework::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 kParnames[2] = {"Pi0/", "Eta/"}; o2::ccdb::CcdbApi ccdbApi; - Service ccdb; + o2::framework::Service ccdb; int mRunNumber; float d_bz; - void init(InitContext&) + void init(o2::framework::InitContext&) { o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); - if constexpr (pairtype == PairType::kPCMDalitzEE) { + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMDalitzEE) { o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, true, "ee#gamma"); - } else if constexpr (pairtype == PairType::kPCMDalitzMuMu) { - o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, true, "#mu#mu#gamma"); } else { o2::aod::pwgem::photonmeson::utils::nmhistogram::addNMHistograms(&fRegistry, true, "#gamma#gamma"); } @@ -219,7 +219,7 @@ struct Pi0EtaToGammaGammaMC { 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); + fRegistry.add("Event/hNrecPerMCCollision", "Nrec per mc collision;N_{rec} collisions per MC collision", o2::framework::kTH1F, {{21, -0.5f, 20.5f}}, false); mRunNumber = 0; d_bz = 0; @@ -241,7 +241,7 @@ struct Pi0EtaToGammaGammaMC { 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)); } mRunNumber = collision.runNumber(); @@ -280,7 +280,7 @@ struct Pi0EtaToGammaGammaMC { fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); - fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetZvtxRange(eventcuts.cfgZvtxMin, eventcuts.cfgZvtxMax); fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); @@ -288,7 +288,6 @@ struct Pi0EtaToGammaGammaMC { fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); } void DefinePCMCut() @@ -296,51 +295,30 @@ struct Pi0EtaToGammaGammaMC { 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.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.SetTrackPtRange(pcmcuts.cfg_min_pt_v0 * 0.4, 1e+10f); - fV0PhotonCut.SetTrackEtaRange(-pcmcuts.cfg_max_eta_v0, +pcmcuts.cfg_max_eta_v0); + 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); - if (pcmcuts.cfg_reject_v0_on_itsib) { - fV0PhotonCut.SetNClustersITS(2, 4); - } else { - fV0PhotonCut.SetNClustersITS(0, 7); - } + fV0PhotonCut.SetNClustersITS(0, 7); fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); - fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); - - if (pcmcuts.cfg_require_v0_with_itstpc) { - fV0PhotonCut.SetRequireITSTPC(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 40); - } - if (pcmcuts.cfg_require_v0_with_itsonly) { - fV0PhotonCut.SetRequireITSonly(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 24); - } - if (pcmcuts.cfg_require_v0_with_tpconly) { - fV0PhotonCut.SetRequireTPConly(true); - fV0PhotonCut.SetMaxPCA(3.0); - fV0PhotonCut.SetRxyRange(36, 90); - } - if (pcmcuts.cfg_require_v0_on_wwire_ib) { - fV0PhotonCut.SetMaxPCA(0.3); - fV0PhotonCut.SetOnWwireIB(true); - fV0PhotonCut.SetOnWwireOB(false); - fV0PhotonCut.SetRxyRange(7, 14); - } + 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() @@ -360,36 +338,34 @@ struct Pi0EtaToGammaGammaMC { 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 + fDileptonCut.IncludeITSsa(dileptoncuts.includeITSsa, dileptoncuts.cfg_max_pt_track_ITSsa); // 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 + pow(pT + b, c); }); - fEMCCut.SetTrackMatchingPhi([&d, &e, &f](float pT) { return d + pow(pT + e, f); }); + fEMCCut.SetTrackMatchingEtaParams(emccuts.EMC_TM_Eta->at(0), emccuts.EMC_TM_Eta->at(1), emccuts.EMC_TM_Eta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.EMC_TM_Phi->at(0), emccuts.EMC_TM_Phi->at(1), emccuts.EMC_TM_Phi->at(2)); fEMCCut.SetMinEoverP(emccuts.EMC_Eoverp); fEMCCut.SetUseExoticCut(emccuts.EMC_UseExoticCut); @@ -400,18 +376,14 @@ struct Pi0EtaToGammaGammaMC { 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); + o2::framework::SliceCache cache; + o2::framework::Preslice>> perCollision_pcm = o2::aod::v0photonkf::emeventId; + o2::framework::Preslice> perCollision_emc = o2::aod::emccluster::emeventId; + o2::framework::Preslice> perCollision_phos = o2::aod::phoscluster::emeventId; - // Preslice perCollision_muon = aod::emprimarymuon::emeventId; - // Partition muons_pos = o2::aod::emprimarymuon::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_TPCNsigmaMu) < o2::aod::pidtpc::tpcNSigmaMu&& o2::aod::pidtpc::tpcNSigmaMu < static_cast(dileptoncuts.cfg_max_TPCNsigmaMu); - // Partition muons_neg = o2::aod::emprimarymuon::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_TPCNsigmaMu) < o2::aod::pidtpc::tpcNSigmaMu && o2::aod::pidtpc::tpcNSigmaMu < static_cast(dileptoncuts.cfg_max_TPCNsigmaMu); + o2::framework::Preslice>> perCollision_electron = o2::aod::emprimaryelectron::emeventId; + o2::framework::Partition>> positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && dileptoncuts.cfg_min_pt_track < o2::aod::track::pt&& nabs(o2::aod::track::eta) < dileptoncuts.cfg_max_eta_track; + o2::framework::Partition>> electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && dileptoncuts.cfg_min_pt_track < o2::aod::track::pt && nabs(o2::aod::track::eta) < dileptoncuts.cfg_max_eta_track; template void runTruePairing(TCollisions const& collisions, @@ -424,7 +396,16 @@ struct Pi0EtaToGammaGammaMC { for (auto& collision : collisions) { initCCDB(collision); - if ((pairtype == PairType::kPHOSPHOS || pairtype == PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { + if ((pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPHOSPHOS || pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { + continue; + } + + float weight = 1.f; + if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { + weight = collision.weight(); + } + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(weight - 1.0) < 1e-10) { continue; } @@ -433,25 +414,25 @@ struct Pi0EtaToGammaGammaMC { continue; } - o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision); + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, weight); if (!fEMEventCut.IsSelected(collision)) { 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 + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, weight); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, weight); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, 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 + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM || pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPHOSPHOS || pairtype == o2::aod::pwgem::photonmeson::photonpair::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))) { + for (auto& [g1, g2] : o2::soa::combinations(o2::soa::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 + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM) { // check 2 legs auto pos1 = g1.template posTrack_as(); auto ele1 = g1.template negTrack_as(); auto pos2 = g2.template posTrack_as(); @@ -462,14 +443,14 @@ struct Pi0EtaToGammaGammaMC { 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) { + photonid1 = o2::aod::pwgem::dilepton::utils::mcutil::FindCommonMotherFrom2Prongs(pos1mc, ele1mc, -11, 11, 22, mcparticles); + photonid2 = o2::aod::pwgem::dilepton::utils::mcutil::FindCommonMotherFrom2Prongs(pos2mc, ele2mc, -11, 11, 22, mcparticles); + } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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}); + photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(cluster1mcparticle, mcparticles, std::vector{111, 221}); + photonid2 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(cluster2mcparticle, mcparticles, std::vector{111, 221}); } else { photonid1 = -1; photonid2 = -1; @@ -481,35 +462,56 @@ struct Pi0EtaToGammaGammaMC { 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)) { + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::PairType::kPCMPCM) { + if (!o2::aod::pwgem::photonmeson::utils::mcutil::IsConversionPointInAcceptance(g1mc, maxRgen, maxY_gen, margin_z_mc, mcparticles) || !o2::aod::pwgem::photonmeson::utils::mcutil::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); + pi0id = o2::aod::pwgem::dilepton::utils::mcutil::FindCommonMotherFrom2Prongs(g1mc, g2mc, 22, 22, 111, mcparticles); + etaid = o2::aod::pwgem::dilepton::utils::mcutil::FindCommonMotherFrom2Prongs(g1mc, g2mc, 22, 22, 221, mcparticles); - if (pi0id < 0 && etaid < 0) { + 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 (abs(v12.Rapidity()) > maxY_rec) { + if (std::fabs(v12.Rapidity()) > maxY_rec) { + continue; + } + + if (pairtype == o2::aod::pwgem::photonmeson::photonpair::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 (o2::aod::pwgem::dilepton::utils::mcutil::getMotherPDGCode(g1mc, mcparticles) == 111) + fRegistry.fill(HIST("Pair/Pi0/hs_FromSameGamma"), v12.M(), v12.Pt(), weight); + else if (o2::aod::pwgem::dilepton::utils::mcutil::getMotherPDGCode(g1mc, mcparticles) == 221) + fRegistry.fill(HIST("Pair/Eta/hs_FromSameGamma"), v12.M(), v12.Pt(), weight); 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); + if (cfgRequireTrueAssociation && (pi0mc.emmceventId() != collision.emmceventId())) { + continue; + } + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, 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); + if (cfgRequireTrueAssociation && (etamc.emmceventId() != collision.emmceventId())) { + continue; + } + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0, weight); } } // end of pairing loop - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { + } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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); @@ -522,18 +524,18 @@ struct Pi0EtaToGammaGammaMC { 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); + photonid1 = o2::aod::pwgem::dilepton::utils::mcutil::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)) { + if (!o2::aod::pwgem::photonmeson::utils::mcutil::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. + for (auto& [pos2, ele2] : o2::soa::combinations(o2::soa::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()) { @@ -544,64 +546,70 @@ struct Pi0EtaToGammaGammaMC { continue; } - if (!cut2.template IsSelectedPair(pos2, ele2, d_bz)) { + 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); + pi0id = o2::aod::pwgem::dilepton::utils::mcutil::FindCommonMotherFrom3Prongs(g1mc, pos2mc, ele2mc, 22, -11, 11, 111, mcparticles); + etaid = o2::aod::pwgem::dilepton::utils::mcutil::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 (abs(veeg.Rapidity()) > maxY_rec) { + if (std::fabs(veeg.Rapidity()) > maxY_rec) { continue; } if (pi0id > 0) { auto pi0mc = mcparticles.iteratorAt(pi0id); - o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, veeg, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0); + if (cfgRequireTrueAssociation && (pi0mc.emmceventId() != collision.emmceventId())) { + continue; + } + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, veeg, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, weight); } else if (etaid > 0) { auto etamc = mcparticles.iteratorAt(etaid); - o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, veeg, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0); + if (cfgRequireTrueAssociation && (etamc.emmceventId() != collision.emmceventId())) { + continue; + } + o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, veeg, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0, weight); } - } // end of dielectron loop - } // end of pcm loop + } // 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))) { + for (auto& [g1, g2] : o2::soa::combinations(o2::soa::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 (abs(v12.Rapidity()) > maxY_rec) { + 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); + // o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, pi0mc, mcparticles, mccollisions, f1fd_k0s_to_pi0, 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); + // o2::aod::pwgem::photonmeson::utils::nmhistogram::fillTruePairInfo(&fRegistry, v12, etamc, mcparticles, mccollisions, f1fd_k0s_to_pi0, weight); // } } // end of pairing loop - } // end of pairing in same event - } // end of collision 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 + auto hPtY = fRegistry.get(HIST("Generated/") + HIST(kParnames[par_id]) + HIST("hPtY")); // 2D + auto hPt = fRegistry.get(HIST("Generated/") + HIST(kParnames[par_id]) + HIST("hPt")); // 1D for (int ibin = 0; ibin < hPtY->GetNcells(); ibin++) { int nentry = binned_data[ibin]; @@ -619,8 +627,8 @@ struct Pi0EtaToGammaGammaMC { } } - PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; - PresliceUnsorted rec_perMcCollision = aod::emmceventlabel::emmceventId; + o2::framework::PresliceUnsorted perMcCollision = o2::aod::emmcparticle::emmceventId; + o2::framework::PresliceUnsorted> rec_perMcCollision = o2::aod::emmceventlabel::emmceventId; template void runGenInfo(TCollisions const& collisions, TMCCollisions const& mccollisions, TMCParticles const& /*mcparticles*/) @@ -635,10 +643,19 @@ struct Pi0EtaToGammaGammaMC { } for (auto& collision : collisions) { - if ((pairtype == kPHOSPHOS || pairtype == kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { + if ((pairtype == o2::aod::pwgem::photonmeson::photonpair::kPHOSPHOS || pairtype == o2::aod::pwgem::photonmeson::photonpair::kPCMPHOS) && !collision.alias_bit(triggerAliases::kTVXinPHOS)) { continue; // I don't know why this is necessary in simulation. } + float weight = 1.f; + if constexpr (std::is_same_v, o2::soa::Filtered, o2::aod::EMEventsWeight>>>) { + weight = collision.weight(); + } + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(weight - 1.0) < 1e-10) { + continue; + } + float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; @@ -651,54 +668,99 @@ struct Pi0EtaToGammaGammaMC { 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, 1.f); - fillBinnedData<1>(binned_data_eta_gen, 1.f); + fillBinnedData<0>(binned_data_pi0_gen, weight); + fillBinnedData<1>(binned_data_eta_gen, weight); } // end of collision loop } - 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; + o2::framework::expressions::Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; + o2::framework::expressions::Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; + o2::framework::expressions::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 = o2::soa::Filtered>; + + o2::framework::expressions::Filter prefilter_pcm = ifnode(pcmcuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::v0photonkf::pfbderived == static_cast(0), true); + o2::framework::expressions::Filter prefilter_primaryelectron = ifnode(dileptoncuts.cfg_apply_cuts_from_prefilter_derived.node(), o2::aod::emprimaryelectron::pfbderived == static_cast(0), true); + + void processAnalysis(o2::soa::Filtered> const& collisions, o2::soa::Join const& mccollisions, o2::aod::EMMCParticles const& mcparticles, Types const&... args) + { + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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 == o2::aod::pwgem::photonmeson::photonpair::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 == o2::aod::pwgem::photonmeson::photonpair::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 == o2::aod::pwgem::photonmeson::photonpair::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 == o2::aod::pwgem::photonmeson::photonpair::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 == o2::aod::pwgem::photonmeson::photonpair::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", true); - void processAnalysis(FilteredMyCollisions const& collisions, MyMCCollisions const& mccollisions, aod::EMMCParticles const& mcparticles, Types const&... args) + // using FilteredMyCollisionsWithJJMC = o2::soa::Filtered, aod::EMEventsWeight>>; + void processAnalysisJJMC(o2::soa::Filtered, o2::aod::EMEventsWeight>> const& collisions, o2::soa::Join const& mccollisions, o2::aod::EMMCParticles const& mcparticles, Types const&... args) { - if constexpr (pairtype == PairType::kPCMPCM) { + if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + // else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + // else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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) { + // } else if constexpr (pairtype == o2::aod::pwgem::photonmeson::photonpair::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); + PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processAnalysisJJMC, "process pair analysis", false); - void processDummy(MyCollisions const&) {} - PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processDummy, "Dummy function", true); + void processDummy(o2::aod::EMEvents const&) {} + PROCESS_SWITCH(Pi0EtaToGammaGammaMC, processDummy, "Dummy function", false); }; #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..e374a21b26b --- /dev/null +++ b/PWGEM/PhotonMeson/Core/TaggingPi0.h @@ -0,0 +1,731 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // IWYU pragma: keep +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 MyCollisionsWithJJMC = soa::Join; +using MyCollisionWithJJMC = MyCollisionsWithJJMC::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", 594, "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, -o2::constants::math::PIHalf, -o2::constants::math::PIQuarter, 0.0f, +o2::constants::math::PIQuarter, +o2::constants::math::PIHalf}, "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_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_per_col.clear(); + used_photonIds_per_col.shrink_to_fit(); + used_dileptonIds_per_col.clear(); + used_dileptonIds_per_col.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, o2::constants::math::TwoPI}, {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.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() + { + 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.SetTrackMatchingEtaParams(emccuts.EMC_TM_Eta->at(0), emccuts.EMC_TM_Eta->at(1), emccuts.EMC_TM_Eta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.EMC_TM_Phi->at(0), emccuts.EMC_TM_Phi->at(1), emccuts.EMC_TM_Phi->at(2)); + + 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_per_col; // + std::vector> used_dileptonIds_per_col; // + std::map, uint64_t> map_mixed_eventId_to_globalBC; + + 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 (const auto& collision : collisions) { + initCCDB(collision); + int ndiphoton = 0; + + float weight = 1.f; + if constexpr (std::is_same_v, FilteredMyCollisionsWithJJMC>) { + weight = collision.weight(); + } + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(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, weight); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, weight); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, weight); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, 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(), weight); + fRegistry.fill(HIST("Photon/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + o2::constants::math::TwoPI, v_gamma.Eta(), 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(), weight); + + std::pair tuple_tmp_id2 = std::make_pair(pos2.trackId(), ele2.trackId()); + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds_per_col.emplace_back(g1.globalIndex()); + } + if (std::find(used_dileptonIds_per_col.begin(), used_dileptonIds_per_col.end(), tuple_tmp_id2) == used_dileptonIds_per_col.end()) { + emh2->AddTrackToEventPool(key_df_collision, EMTrack(v_ee.Pt(), v_ee.Eta(), v_ee.Phi(), v_ee.M())); + used_dileptonIds_per_col.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(), weight); + + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g1.globalIndex()) == used_photonIds_per_col.end()) { + emh1->AddTrackToEventPool(key_df_collision, EMTrack(g1.pt(), g1.eta(), g1.phi(), 0)); + used_photonIds_per_col.emplace_back(g1.globalIndex()); + } + if (std::find(used_photonIds_per_col.begin(), used_photonIds_per_col.end(), g2.globalIndex()) == used_photonIds_per_col.end()) { + emh2->AddTrackToEventPool(key_df_collision, EMTrack(g2.pt(), g2.eta(), g2.phi(), 0)); + used_photonIds_per_col.emplace_back(g2.globalIndex()); + } + ndiphoton++; + } // end of pairing loop + } // end of pairing in same event + + used_photonIds_per_col.clear(); + used_photonIds_per_col.shrink_to_fit(); + used_dileptonIds_per_col.clear(); + used_dileptonIds_per_col.shrink_to_fit(); + + // 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(), 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", true); + + using FilteredMyCollisionsWithJJMC = soa::Filtered; + void processAnalysisJJMC(FilteredMyCollisionsWithJJMC 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, processAnalysisJJMC, "process pair analysis", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(TaggingPi0, processDummy, "Dummy function", false); +}; +#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..c13b531bfdc --- /dev/null +++ b/PWGEM/PhotonMeson/Core/TaggingPi0MC.h @@ -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 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 "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // IWYU pragma: keep +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 MyCollisionsWithJJMC = soa::Join; +using MyCollisionWithJJMC = MyCollisionsWithJJMC::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", -1, "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 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 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_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, o2::constants::math::TwoPI}, {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, o2::constants::math::TwoPI}, {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.cfgZvtxMin, 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.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() + { + 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.SetTrackMatchingEtaParams(emccuts.EMC_TM_Eta->at(0), emccuts.EMC_TM_Eta->at(1), emccuts.EMC_TM_Eta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.EMC_TM_Phi->at(0), emccuts.EMC_TM_Phi->at(1), emccuts.EMC_TM_Phi->at(2)); + + 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); + + float weight = 1.f; + if constexpr (std::is_same_v, FilteredMyCollisionsWithJJMC>) { + weight = collision.weight(); + } + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(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, weight); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&fRegistry, collision, weight); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 12.0, weight); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 12.0, 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(), weight); + fRegistry.fill(HIST("Photon/candidate/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + o2::constants::math::TwoPI, v_gamma.Eta(), 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(), weight); + fRegistry.fill(HIST("Photon/primary/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + o2::constants::math::TwoPI, v_gamma.Eta(), 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(), weight); + fRegistry.fill(HIST("Photon/fromPi0/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + o2::constants::math::TwoPI, v_gamma.Eta(), 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(), weight * weight); + fRegistry.fill(HIST("Photon/fromWD/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + o2::constants::math::TwoPI, v_gamma.Eta(), weight * weight); + } else { + fRegistry.fill(HIST("Photon/fromHS/hPt"), v_gamma.Pt(), weight); + fRegistry.fill(HIST("Photon/fromHS/hEtaPhi"), v_gamma.Phi() > 0 ? v_gamma.Phi() : v_gamma.Phi() + o2::constants::math::TwoPI, v_gamma.Eta(), 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(), 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(), weight * weight); + } else { + fRegistry.fill(HIST("Pair/fromHS/hMvsPt"), veeg.M(), v_gamma.Pt(), 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, 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", true); + + using FilteredMyCollisionsWithJJMC = soa::Filtered; + void processAnalysisJJMC(FilteredMyCollisionsWithJJMC 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, processAnalysisJJMC, "process pair analysis", false); + + void processDummy(MyCollisions const&) {} + PROCESS_SWITCH(TaggingPi0MC, processDummy, "Dummy function", false); +}; +#endif // PWGEM_PHOTONMESON_CORE_TAGGINGPI0MC_H_ diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx b/PWGEM/PhotonMeson/Core/V0PhotonCut.cxx index bceee717d76..4c149b7fd20 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; @@ -182,12 +193,6 @@ void V0PhotonCut::SetMeanClusterSizeITSob(float min, float max) LOG(info) << "V0 Photon Cut, set mean cluster size ITS range: " << mMinMeanClusterSizeITS << " - " << mMaxMeanClusterSizeITS; } -void V0PhotonCut::SetIsWithinBeamPipe(bool flag) -{ - mIsWithinBP = flag; - LOG(info) << "V0 Photon Cut, propagated to within beam pipe: " << mIsWithinBP; -} - void V0PhotonCut::SetRequireITSTPC(bool flag) { mRequireITSTPC = flag; @@ -218,49 +223,14 @@ void V0PhotonCut::SetRequireTPCTOF(bool flag) LOG(info) << "V0 Photon Cut, require TPC-TOF track: " << mRequireTPCTOF; } -void V0PhotonCut::SetRequireTPCTRDTOF(bool flag) -{ - mRequireTPCTRDTOF = flag; - LOG(info) << "V0 Photon Cut, require TPC-TOF track: " << mRequireTPCTRDTOF; -} - void V0PhotonCut::SetDisableITSonly(bool flag) { 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 3f0e2ede17d..dcd9cd2c5ce 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.h @@ -16,16 +16,18 @@ #ifndef PWGEM_PHOTONMESON_CORE_V0PHOTONCUT_H_ #define PWGEM_PHOTONMESON_CORE_V0PHOTONCUT_H_ -#include -#include -#include -#include -#include #include "Rtypes.h" -#include "TNamed.h" -#include "TMath.h" #include "PWGEM/PhotonMeson/Utils/TrackSelection.h" + +#include "TMath.h" +#include "TNamed.h" + +#include +#include +#include +#include +#include using namespace o2::pwgem::photonmeson; class V0PhotonCut : public TNamed @@ -45,6 +47,7 @@ class V0PhotonCut : public TNamed kRxy, kCosPA, kPCA, + kChi2KF, kRZLine, kOnWwireIB, kOnWwireOB, @@ -54,6 +57,7 @@ class V0PhotonCut : public TNamed kTPCNCls, kTPCCrossedRows, kTPCCrossedRowsOverNCls, + kTPCFracSharedClusters, kTPCChi2NDF, kTPCNsigmaEl, kTPCNsigmaPi, @@ -61,19 +65,15 @@ class V0PhotonCut : public TNamed kDCAz, kITSNCls, kITSChi2NDF, - kITSCluserSize, - kIsWithinBeamPipe, + kITSClusterSize, kRequireITSTPC, kRequireITSonly, kRequireTPConly, kRequireTPCTRD, kRequireTPCTOF, - kRequireTPCTRDTOF, kNCuts }; - static const char* mCutNames[static_cast(V0PhotonCuts::kNCuts)]; - template bool IsSelected(TV0 const& v0) const { @@ -104,6 +104,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; } @@ -138,15 +141,15 @@ class V0PhotonCut : public TNamed if (!IsSelectedTrack(track, V0PhotonCuts::kDCAz)) { return false; } - if (mIsWithinBP && !IsSelectedTrack(track, V0PhotonCuts::kIsWithinBeamPipe)) { - return false; - } if (!track.hasITS() && !track.hasTPC()) { // track has to be ITSonly or TPConly or ITS-TPC return false; } if (mDisableITSonly && isITSonlyTrack(track)) { return false; } + 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); }); @@ -192,9 +195,6 @@ class V0PhotonCut : public TNamed if (mRequireTPCTOF && !IsSelectedTrack(track, V0PhotonCuts::kRequireTPCTOF)) { return false; } - if (mRequireTPCTRDTOF && !IsSelectedTrack(track, V0PhotonCuts::kRequireTPCTRDTOF)) { - return false; - } } return true; } @@ -208,7 +208,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; @@ -226,6 +226,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; } @@ -238,31 +241,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 { @@ -289,11 +267,6 @@ class V0PhotonCut : public TNamed if (v0.v0radius() < mMinRxy || mMaxRxy < v0.v0radius()) { return false; } - if (mRejectITSib) { - if (v0.v0radius() < 4.f || v0.pca() < -0.05 * v0.v0radius() + 0.3) { - return false; - } - } return true; } @@ -303,8 +276,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 @@ -313,9 +289,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) { @@ -327,7 +303,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: { @@ -360,10 +336,10 @@ class V0PhotonCut : public TNamed { switch (cut) { case V0PhotonCuts::kTrackPtRange: - return track.pt() >= mMinTrackPt && track.pt() <= mMaxTrackPt; + return track.pt() > mMinTrackPt && track.pt() < mMaxTrackPt; case V0PhotonCuts::kTrackEtaRange: - return track.eta() >= mMinTrackEta && track.eta() <= mMaxTrackEta; + return track.eta() > mMinTrackEta && track.eta() < mMaxTrackEta; case V0PhotonCuts::kTPCNCls: return track.tpcNClsFound() >= mMinNClustersTPC; @@ -374,20 +350,23 @@ 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; case V0PhotonCuts::kTPCNsigmaEl: - return track.tpcNSigmaEl() >= mMinTPCNsigmaEl && track.tpcNSigmaEl() <= mMaxTPCNsigmaEl; + return track.tpcNSigmaEl() > mMinTPCNsigmaEl && track.tpcNSigmaEl() < mMaxTPCNsigmaEl; case V0PhotonCuts::kTPCNsigmaPi: - return track.tpcNSigmaPi() >= mMinTPCNsigmaPi && track.tpcNSigmaPi() <= mMaxTPCNsigmaPi; + 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; @@ -395,35 +374,13 @@ 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; } return mMinMeanClusterSizeITS < track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl())) && track.meanClusterSizeITSob() * std::cos(std::atan(track.tgl())) < mMaxMeanClusterSizeITS; } - case V0PhotonCuts::kIsWithinBeamPipe: { - if (!isTPConlyTrack(track)) { // TPC-TRD, TPC-TOF, TPC-TRD-TOF are constrained. - return true; - } - - // 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) { - return false; - } - if (track.x() > 82.9 && abs(track.y()) > abs(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) { - return false; - } - return true; - // const float slope = TMath::Tan(2 * TMath::ATan(TMath::Exp(-0.5))); - // return !(track.x() > 82.9 && abs(track.y()) < 15.f && abs(abs(track.z()) - track.x() / slope) < 3.f && 15.f < abs(track.dcaXY())); - //// return !(track.x() > 82.9 && abs(track.y()) < 40.f && abs(abs(track.z()) - 47.f) < 3.f && 15.f < abs(track.dcaXY())); - } case V0PhotonCuts::kRequireITSTPC: return isITSTPCTrack(track); @@ -439,9 +396,6 @@ class V0PhotonCut : public TNamed case V0PhotonCuts::kRequireTPCTOF: return isTPCTOFTrack(track); - case V0PhotonCuts::kRequireTPCTRDTOF: - return isTPCTRDTOFTrack(track); - default: return false; } @@ -457,6 +411,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); @@ -468,6 +423,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); @@ -485,11 +441,8 @@ class V0PhotonCut : public TNamed void SetRequireTPConly(bool flag); void SetRequireTPCTRD(bool flag); void SetRequireTPCTOF(bool flag); - void SetRequireTPCTRDTOF(bool flag); void SetDisableITSonly(bool flag); - - /// @brief Print the track selection - void print() const; + void SetDisableTPConly(bool flag); private: static const std::pair> its_ib_Requirement; @@ -505,6 +458,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}; @@ -524,6 +478,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,14 +486,13 @@ class V0PhotonCut : public TNamed float mMaxDcaXY{1e10f}; // max dca in xy plane float mMaxDcaZ{1e10f}; // max dca in z direction std::function mMaxDcaXYPtDep{}; // max dca in xy plane as function of pT - bool mIsWithinBP{false}; bool mRequireITSTPC{false}; bool mRequireITSonly{false}; 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..efd3f9a2007 --- /dev/null +++ b/PWGEM/PhotonMeson/DataModel/bcWiseTables.h @@ -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. +/// +/// \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" + +#include + +namespace o2::aod +{ + +namespace emdownscaling +{ +enum Observable { + kDefinition, + kEnergy, + kEta, + kPhi, + kNCells, + kM02, + kTime, + kCent, + kZVtx, + kFT0Amp, + kpT, + kMu, + kTimeSinceSOF, + 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, // FT0 centrality + 1E3, // Z-vertex position + 1E-1, // FT0M amplitude + 1E3, // MC pi0 pt + 1E5, // Mu + 5E-1}; // Time since start of fill (since ADJUST decleration) +} // 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(StoredFT0CCentrality, storedFt0CCentrality, uint8_t); //! FT0C centrality (0-100) (x2) +DECLARE_SOA_COLUMN(StoredFT0MCentrality, storedFT0MCentrality, uint8_t); //! FT0M centrality (0-100) (x2) +DECLARE_SOA_COLUMN(StoredFT0MAmplitude, storedFT0MAmplitude, uint16_t); //! ft0a+c amplitude +DECLARE_SOA_COLUMN(StoredMu, storedMu, uint16_t); //! probability of TVX collision per BC (x1000) +DECLARE_SOA_COLUMN(StoredTimeSinceSOF, storedTimeSinceSOF, uint16_t); //! time since decreation of ADJUST in seconds (x2) + +DECLARE_SOA_DYNAMIC_COLUMN(FT0CCentrality, ft0cCentrality, [](uint8_t storedft0ccentrality) -> float { return std::nextafter(storedft0ccentrality / emdownscaling::downscalingFactors[emdownscaling::kCent], std::numeric_limits::infinity()); }); //! Centrality (0-100) +DECLARE_SOA_DYNAMIC_COLUMN(FT0MCentrality, ft0mCentrality, [](uint8_t storedft0mcentrality) -> float { return std::nextafter(storedft0mcentrality / emdownscaling::downscalingFactors[emdownscaling::kCent], std::numeric_limits::infinity()); }); //! Centrality (0-100) +DECLARE_SOA_DYNAMIC_COLUMN(FT0MAmplitude, ft0Amplitude, [](uint16_t storedFT0MAmplitude) -> float { return std::nextafter(storedFT0MAmplitude / emdownscaling::downscalingFactors[emdownscaling::kFT0Amp], std::numeric_limits::infinity()); }); //! FT0M amplitude +DECLARE_SOA_DYNAMIC_COLUMN(Mu, mu, [](uint16_t storedMu) -> float { return std::nextafter(storedMu / emdownscaling::downscalingFactors[emdownscaling::kMu], std::numeric_limits::infinity()); }); //! probability of TVX collision per BC +DECLARE_SOA_DYNAMIC_COLUMN(TimeSinceSOF, timeSinceSOF, [](uint16_t storedTimeSinceSOF) -> float { return std::nextafter(storedTimeSinceSOF / emdownscaling::downscalingFactors[emdownscaling::kTimeSinceSOF], std::numeric_limits::infinity()); }); //! probability of TVX collision per BC +} // namespace bcwisebc +DECLARE_SOA_TABLE(BCWiseBCs, "AOD", "BCWISEBC", //! table of bc wise centrality estimation and event selection input + o2::soa::Index<>, bcwisebc::HasFT0, bcwisebc::HasTVX, bcwisebc::HaskTVXinEMC, bcwisebc::HasEMCCell, bcwisebc::StoredFT0CCentrality, bcwisebc::StoredFT0MCentrality, + bcwisebc::StoredFT0MAmplitude, bcwisebc::StoredMu, bcwisebc::StoredTimeSinceSOF, bcwisebc::FT0CCentrality, bcwisebc::FT0MCentrality, bcwisebc::FT0MAmplitude, bcwisebc::Mu, bcwisebc::TimeSinceSOF); + +DECLARE_SOA_INDEX_COLUMN(BCWiseBC, bcWiseBC); //! bunch crossing ID used as index + +namespace bcwisecollision +{ +DECLARE_SOA_COLUMN(StoredZVtx, storedZVtx, int16_t); //! Z-vertex position (x1000) + +DECLARE_SOA_DYNAMIC_COLUMN(ZVtx, zVtx, [](int16_t storedzvtx) -> float { return storedzvtx / emdownscaling::downscalingFactors[emdownscaling::kZVtx]; }); //! Z-Vertex +} // namespace bcwisecollision +DECLARE_SOA_TABLE(BCWiseCollisions, "AOD", "BCWISECOLL", //! table of skimmed EMCal clusters + o2::soa::Index<>, BCWiseBCId, bcwisecollision::StoredZVtx, bcwisecollision::ZVtx); + +namespace bcwisecluster +{ +DECLARE_SOA_COLUMN(StoredDefinition, storedDefinition, int8_t); //! cluster definition, see EMCALClusterDefinition.h +DECLARE_SOA_COLUMN(StoredE, storedE, int16_t); //! cluster energy (1 MeV -> Maximum cluster energy of ~32 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, int8_t); //! number of cells in cluster +DECLARE_SOA_COLUMN(StoredM02, storedM02, int16_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, [](int8_t storedDefinition) -> int8_t { return storedDefinition; }); //! cluster definition, see EMCALClusterDefinition.h +DECLARE_SOA_DYNAMIC_COLUMN(E, e, [](int16_t storedE) -> float { return std::nextafter(storedE / emdownscaling::downscalingFactors[emdownscaling::kEnergy], std::numeric_limits::infinity()); }); //! cluster energy (GeV) +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](int16_t storedEta) -> float { return std::nextafter(storedEta / emdownscaling::downscalingFactors[emdownscaling::kEta], std::numeric_limits::infinity()); }); //! cluster pseudorapidity +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](uint16_t storedPhi) -> float { return std::nextafter(storedPhi / emdownscaling::downscalingFactors[emdownscaling::kPhi], std::numeric_limits::infinity()); }); //! cluster azimuthal angle (0 to 2pi) +DECLARE_SOA_DYNAMIC_COLUMN(NCells, nCells, [](int16_t storedNCells) -> int16_t { return storedNCells; }); //! number of cells in cluster +DECLARE_SOA_DYNAMIC_COLUMN(M02, m02, [](int16_t storedM02) -> float { return std::nextafter(storedM02 / emdownscaling::downscalingFactors[emdownscaling::kM02], std::numeric_limits::infinity()); }); //! shower shape long axis +DECLARE_SOA_DYNAMIC_COLUMN(Time, time, [](int16_t storedTime) -> float { return std::nextafter(storedTime / emdownscaling::downscalingFactors[emdownscaling::kTime], std::numeric_limits::infinity()); }); //! 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", "BCWISECLUSTER", //! 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 bcwisemcmesons +{ +DECLARE_SOA_COLUMN(StoredPt, storedPt, uint16_t); //! Transverse momentum of generated pi0 (1 MeV -> Maximum pi0 pT of ~65 GeV) +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 std::nextafter(storedpt / emdownscaling::downscalingFactors[emdownscaling::kpT], std::numeric_limits::infinity()); }); //! pT of pi0 (GeV) +} // namespace bcwisemcmesons + +DECLARE_SOA_TABLE(BCWiseMCPi0s, "AOD", "BCWISEMCPI0", //! table of pi0s on MC level + o2::soa::Index<>, BCWiseBCId, bcwisemcmesons::StoredPt, bcwisemcmesons::IsAccepted, bcwisemcmesons::IsPrimary, bcwisemcmesons::IsFromWD, + bcwisemcmesons::Pt); +DECLARE_SOA_TABLE(BCWiseMCEtas, "AOD", "BCWISEMCETA", //! table of eta mesons on MC level + o2::soa::Index<>, BCWiseBCId, bcwisemcmesons::StoredPt, bcwisemcmesons::IsAccepted, bcwisemcmesons::IsPrimary, bcwisemcmesons::IsFromWD, + bcwisemcmesons::Pt); + +namespace bcwisemccluster +{ +DECLARE_SOA_COLUMN(MesonID, mesonID, int32_t); //! Index of the mother mesom (-1 if not from a pi0 or eta) +DECLARE_SOA_COLUMN(IsEta, isEta, bool); //! Boolean flag to indicate if the cluster is from an eta meson, otherwise it is from a pi0 +DECLARE_SOA_COLUMN(StoredTrueE, storedTrueE, uint16_t); //! energy of cluster inducing particle (1 MeV -> Maximum cluster energy of ~65 GeV) + +DECLARE_SOA_DYNAMIC_COLUMN(TrueE, trueE, [](uint16_t storedTrueE) -> float { return std::nextafter(storedTrueE / emdownscaling::downscalingFactors[emdownscaling::kEnergy], std::numeric_limits::infinity()); }); //! 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::MesonID, bcwisemccluster::IsEta, bcwisemccluster::StoredTrueE, + bcwisemccluster::TrueE); + +} // namespace o2::aod + +#endif // PWGEM_PHOTONMESON_DATAMODEL_BCWISETABLES_H_ diff --git a/PWGEM/PhotonMeson/DataModel/gammaTables.h b/PWGEM/PhotonMeson/DataModel/gammaTables.h index d4f638ed28a..a151e3762c6 100644 --- a/PWGEM/PhotonMeson/DataModel/gammaTables.h +++ b/PWGEM/PhotonMeson/DataModel/gammaTables.h @@ -9,22 +9,21 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" #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 "Common/DataModel/CaloClusters.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include +#include -#include "PWGJE/DataModel/EMCALClusters.h" +#include +#include +#include +#include #ifndef PWGEM_PHOTONMESON_DATAMODEL_GAMMATABLES_H_ #define PWGEM_PHOTONMESON_DATAMODEL_GAMMATABLES_H_ @@ -120,13 +119,16 @@ 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 + DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz); }); 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(Tgl, tgl, [](float px, float py, float pz) -> float { return std::tan(M_PI_2 - 2 * std::atan(std::exp(-RecoDecay::eta(std::array{px, py, pz})))); }); 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++) { @@ -173,11 +175,11 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32 } }); } // namespace v0leg -DECLARE_SOA_TABLE(V0Legs, "AOD", "V0LEG", //! +DECLARE_SOA_TABLE(V0Legs_000, "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, @@ -192,20 +194,72 @@ 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, + track::HasITS, track::HasTPC, track::HasTRD, track::HasTOF, v0leg::MeanClusterSizeITS, v0leg::MeanClusterSizeITSib, v0leg::MeanClusterSizeITSob); +DECLARE_SOA_TABLE_VERSIONED(V0Legs_001, "AOD", "V0LEG", 1, //! + 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::TPCNClsShared, + track::TPCChi2NCl, track::TPCInnerParam, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, + track::ITSClusterSizes, track::ITSChi2NCl, track::DetectorMap, + + // dynamic column + v0leg::P, + v0leg::Pt, + v0leg::Eta, + v0leg::Phi, + v0leg::Tgl, + + 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, + v0leg::MeanClusterSizeITS, + v0leg::MeanClusterSizeITSib, + v0leg::MeanClusterSizeITSob); + +using V0Legs = V0Legs_001; // iterators using V0Leg = V0Legs::iterator; +DECLARE_SOA_TABLE_VERSIONED(V0LegsXYZ_000, "AOD", "V0LEGXYZ", 0, track::X, track::Y, track::Z); +using V0LegsXYZ = V0LegsXYZ_000; +// iterators +using V0LegXYZ = V0LegsXYZ::iterator; + +DECLARE_SOA_TABLE_VERSIONED(V0LegsDeDxMC_000, "AOD", "V0LEGDEDXMC", 0, mcpidtpc::DeDxTunedMc, o2::soa::Marker<2>); +using V0LegsDeDxMC = V0LegsDeDxMC_000; +// iterators +using V0LegDeDxMC = V0LegsDeDxMC::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 @@ -214,14 +268,25 @@ DECLARE_SOA_COLUMN(Vz, vz, float); //! seco DECLARE_SOA_COLUMN(Px, px, float); //! px for photon kf DECLARE_SOA_COLUMN(Py, py, float); //! py for photon kf DECLARE_SOA_COLUMN(Pz, pz, float); //! pz for photon kf -DECLARE_SOA_COLUMN(MGamma, mGamma, float); //! invariant mass of dielectron at SV -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(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(MGamma, mGamma, float); //! invariant mass of dielectron at SV +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(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); }); @@ -230,13 +295,13 @@ DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) -> float { return Re DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz); }); 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, +DECLARE_SOA_TABLE(V0PhotonsKF_000, "AOD", "V0PHOTONKF", //! + 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, @@ -247,6 +312,27 @@ DECLARE_SOA_TABLE(V0PhotonsKF, "AOD", "V0PHOTONKF", //! v0photonkf::Phi, v0photonkf::P, v0photonkf::V0Radius); + +DECLARE_SOA_TABLE_VERSIONED(V0PhotonsKF_001, "AOD", "V0PHOTONKF", 1, //! + 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::CosPAXY, v0photonkf::CosPARZ, v0photonkf::PCA, + v0photonkf::Alpha, v0photonkf::QtArm, + v0photonkf::ChiSquareNDF, + + // dynamic column + v0photonkf::E, + v0photonkf::Pt, + v0photonkf::Eta, + v0photonkf::Phi, + v0photonkf::P, + v0photonkf::V0Radius); + +using V0PhotonsKF = V0PhotonsKF_001; + // iterators using V0PhotonKF = V0PhotonsKF::iterator; @@ -254,14 +340,24 @@ DECLARE_SOA_TABLE(V0KFEMEventIds, "AOD", "V0KFEMEVENTID", v0photonkf::EMEventId) // iterators using V0KFEMEventId = V0KFEMEventIds::iterator; -DECLARE_SOA_TABLE(EMPrimaryElectronsFromDalitz, "AOD", "EMPRIMARYELDA", //! +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_000, "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::TPCNSigmaPi, - track::ITSClusterSizes, track::ITSChi2NCl, track::DetectorMap, track::Tgl, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, pidtof::TOFNSigmaPi, + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, track::Tgl, // dynamic column track::TPCNClsFound, @@ -269,6 +365,7 @@ DECLARE_SOA_TABLE(EMPrimaryElectronsFromDalitz, "AOD", "EMPRIMARYELDA", //! 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, @@ -279,9 +376,51 @@ DECLARE_SOA_TABLE(EMPrimaryElectronsFromDalitz, "AOD", "EMPRIMARYELDA", //! emprimaryelectron::MeanClusterSizeITS, emprimaryelectron::MeanClusterSizeITSib, emprimaryelectron::MeanClusterSizeITSob); + +DECLARE_SOA_TABLE_VERSIONED(EMPrimaryElectronsFromDalitz_001, "AOD", "EMPRIMARYELDA", 1, //! + o2::soa::Index<>, emprimaryelectron::CollisionId, + emprimaryelectron::TrackId, emprimaryelectron::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, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, + + // dynamic column + track::TPCNClsFound, + track::TPCNClsCrossedRows, + 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::Tgl, + emprimaryelectron::MeanClusterSizeITS, + emprimaryelectron::MeanClusterSizeITSib, + emprimaryelectron::MeanClusterSizeITSob); + +using EMPrimaryElectronsFromDalitz = EMPrimaryElectronsFromDalitz_001; + // iterators using EMPrimaryElectronFromDalitz = EMPrimaryElectronsFromDalitz::iterator; +namespace v0photonsphiv +{ +DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! +DECLARE_SOA_COLUMN(PhiV, phiv, float); //! +} // namespace v0photonsphiv +DECLARE_SOA_TABLE(V0PhotonsPhiV, "AOD", "V0PHOTONPHIV", //! + o2::soa::Index<>, v0photonsphiv::PhiV); +// iterators +using V0PhotonsPhiV = V0PhotonsPhiV; + namespace dalitzee { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! @@ -433,17 +572,48 @@ DECLARE_SOA_COLUMN(Time, time, float); DECLARE_SOA_COLUMN(IsExotic, isExotic, bool); //! flag to mark cluster as exotic DECLARE_SOA_COLUMN(Definition, definition, int); //! cluster definition, see EMCALClusterDefinition.h DECLARE_SOA_ARRAY_INDEX_COLUMN(Track, track); //! TrackIds -DECLARE_SOA_COLUMN(TrackEta, tracketa, std::vector); //! eta values of the matched tracks -DECLARE_SOA_COLUMN(TrackPhi, trackphi, std::vector); //! phi values of the matched tracks +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, std::vector); //! phi values of the matched tracks +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, std::vector); //! eta values of the matched tracks DECLARE_SOA_COLUMN(TrackP, trackp, std::vector); //! momentum values of the matched tracks DECLARE_SOA_COLUMN(TrackPt, trackpt, std::vector); //! pt values of the matched tracks +DECLARE_SOA_COLUMN(DeltaPhiSec, deltaPhiSec, std::vector); //! phi values of the matched secondary tracks +DECLARE_SOA_COLUMN(DeltaEtaSec, deltaEtaSec, std::vector); //! eta values of the matched secondary tracks +DECLARE_SOA_COLUMN(TrackPSec, trackpSec, std::vector); //! momentum values of the matched secondary tracks +DECLARE_SOA_COLUMN(TrackPtSec, trackptSec, std::vector); //! pt values of the matched secondary tracks 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::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_VERSIONED(SkimEMCClusters_000, "AOD", "SKIMEMCCLUSTER", 0, //! table of skimmed EMCal clusters + o2::soa::Index<>, skimmedcluster::CollisionId, emccluster::Definition, skimmedcluster::E, skimmedcluster::Eta, skimmedcluster::Phi, + skimmedcluster::M02, skimmedcluster::NCells, skimmedcluster::Time, emccluster::IsExotic, emccluster::DeltaPhi, + emccluster::DeltaEta, emccluster::TrackP, emccluster::TrackPt, emccluster::Pt); + +DECLARE_SOA_TABLE_VERSIONED(SkimEMCClusters_001, "AOD", "SKIMEMCCLUSTER", 1, //! table of skimmed EMCal clusters version 002 - including secondary matched tracks + o2::soa::Index<>, skimmedcluster::CollisionId, emccluster::Definition, skimmedcluster::E, skimmedcluster::Eta, skimmedcluster::Phi, + skimmedcluster::M02, skimmedcluster::NCells, skimmedcluster::Time, emccluster::IsExotic, + emccluster::DeltaPhi, emccluster::DeltaEta, emccluster::TrackP, emccluster::TrackPt, + emccluster::DeltaPhiSec, emccluster::DeltaEtaSec, emccluster::TrackPSec, emccluster::TrackPtSec, + emccluster::Pt); + +using SkimEMCClusters = SkimEMCClusters_001; +using SkimEMCCluster = SkimEMCClusters_001::iterator; + +// DECLARE_SOA_TABLE_VERSIONED(EmEmcClusters_000, "AOD", "EMEMCCLUSTER", 0, //! table of skimmed EMCal clusters +// o2::soa::Index<>, skimmedcluster::CollisionId, emccluster::Definition, skimmedcluster::E, skimmedcluster::Eta, skimmedcluster::Phi, +// skimmedcluster::M02, skimmedcluster::NCells, skimmedcluster::Time, emccluster::IsExotic, emccluster::Pt); + +// using EmEmcClusters = EmEmcClusters_000; +// using EmEmcCluster = EmEmcClusters_000::iterator; + +// namespace trackmatching +// { +// DECLARE_SOA_INDEX_COLUMN(EmEmcCluster, emEmcCluster); //! +// } // namespace trackmatching + +// DECLARE_SOA_TABLE(EmEmcMTracks, "AOD", "EMEMCMTRACK", //! +// o2::soa::Index<>, trackmatching::EmEmcClusterId, emccluster::DeltaPhi, emccluster::DeltaEta, emccluster::TrackP, emccluster::TrackPt); + +// DECLARE_SOA_TABLE(EmEmcMSTracks, "AOD", "EMEMCMSTRACK", //! +// o2::soa::Index<>, trackmatching::EmEmcClusterId, emccluster::DeltaPhiSec, emccluster::DeltaEtaSec, emccluster::TrackPSec, emccluster::TrackPtSec); DECLARE_SOA_TABLE(EMCEMEventIds, "AOD", "EMCEMEVENTID", emccluster::EMEventId); // To be joined with SkimEMCClusters table at analysis level. // iterators @@ -494,42 +664,11 @@ namespace caloextra { DECLARE_SOA_INDEX_COLUMN_FULL(Cluster, cluster, int, SkimEMCClusters, ""); //! reference to the gamma in the skimmed EMCal table DECLARE_SOA_INDEX_COLUMN_FULL(Cell, cell, int, Calos, ""); //! reference to the gamma in the skimmed EMCal table -// DECLARE_SOA_INDEX_COLUMN(Track, track); //! TrackID -DECLARE_SOA_COLUMN(TrackEta, tracketa, float); //! eta of the matched track -DECLARE_SOA_COLUMN(TrackPhi, trackphi, float); //! phi of the matched track -DECLARE_SOA_COLUMN(TrackP, trackp, float); //! momentum of the matched track -DECLARE_SOA_COLUMN(TrackPt, trackpt, float); //! pt of the matched track } // namespace caloextra DECLARE_SOA_TABLE(SkimEMCCells, "AOD", "SKIMEMCCELLS", //! table of link between skimmed EMCal clusters and their cells o2::soa::Index<>, caloextra::ClusterId, caloextra::CellId); //! using SkimEMCCell = SkimEMCCells::iterator; - -DECLARE_SOA_TABLE(SkimEMCMTs, "AOD", "SKIMEMCMTS", //! table of link between skimmed EMCal clusters and their matched tracks - o2::soa::Index<>, caloextra::ClusterId, caloextra::TrackEta, - caloextra::TrackPhi, caloextra::TrackP, caloextra::TrackPt); -using SkimEMCMT = SkimEMCMTs::iterator; - -namespace gammareco -{ -DECLARE_SOA_COLUMN(Method, method, int); //! cut bit for PCM photon candidates -DECLARE_SOA_INDEX_COLUMN_FULL(SkimmedPCM, skimmedPCM, int, V0PhotonsKF, ""); //! reference to the gamma in the skimmed PCM table -DECLARE_SOA_INDEX_COLUMN_FULL(SkimmedPHOS, skimmedPHOS, int, PHOSClusters, ""); //! reference to the gamma in the skimmed PHOS table -DECLARE_SOA_INDEX_COLUMN_FULL(SkimmedEMC, skimmedEMC, int, SkimEMCClusters, ""); //! reference to the gamma in the skimmed EMCal table -DECLARE_SOA_COLUMN(PCMCutBit, pcmcutbit, uint64_t); //! cut bit for PCM photon candidates -DECLARE_SOA_COLUMN(PHOSCutBit, phoscutbit, uint64_t); //! cut bit for PHOS photon candidates -DECLARE_SOA_COLUMN(EMCCutBit, emccutbit, uint64_t); //! cut bit for EMCal photon candidates -} // namespace gammareco -DECLARE_SOA_TABLE(SkimGammas, "AOD", "SKIMGAMMAS", //! table of all gamma candidates (PCM, EMCal and PHOS) after cuts - o2::soa::Index<>, skimmedcluster::CollisionId, gammareco::Method, - skimmedcluster::E, skimmedcluster::Eta, skimmedcluster::Phi, - gammareco::SkimmedEMCId, gammareco::SkimmedPHOSId); -DECLARE_SOA_TABLE(SkimPCMCuts, "AOD", "SKIMPCMCUTS", //! table of link between skimmed PCM photon candidates and their cuts - o2::soa::Index<>, gammareco::SkimmedPCMId, gammareco::PCMCutBit); //! -DECLARE_SOA_TABLE(SkimPHOSCuts, "AOD", "SKIMPHOSCUTS", //! table of link between skimmed PHOS photon candidates and their cuts - o2::soa::Index<>, gammareco::SkimmedPHOSId, gammareco::PHOSCutBit); //! -DECLARE_SOA_TABLE(SkimEMCCuts, "AOD", "SKIMEMCCUTS", //! table of link between skimmed EMCal photon candidates and their cuts - o2::soa::Index<>, gammareco::SkimmedEMCId, gammareco::EMCCutBit); //! } // namespace o2::aod #endif // PWGEM_PHOTONMESON_DATAMODEL_GAMMATABLES_H_ diff --git a/PWGEM/PhotonMeson/DataModel/mesonTables.h b/PWGEM/PhotonMeson/DataModel/mesonTables.h deleted file mode 100644 index 54daaa3a512..00000000000 --- a/PWGEM/PhotonMeson/DataModel/mesonTables.h +++ /dev/null @@ -1,46 +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/AnalysisDataModel.h" - -#ifndef PWGEM_PHOTONMESON_DATAMODEL_MESONTABLES_H_ -#define PWGEM_PHOTONMESON_DATAMODEL_MESONTABLES_H_ - -namespace o2::aod -{ -namespace calomeson -{ -DECLARE_SOA_INDEX_COLUMN(Collision, - collision); //! Collision to which this meson belongs -DECLARE_SOA_INDEX_COLUMN_FULL(DaugtherPhotonOne, daugtherPhotonOne, int, - SkimEMCClusters, - "_One"); //! 1st daughter if this meson -DECLARE_SOA_INDEX_COLUMN_FULL(DaugtherPhotonTwo, daugtherPhotonTwo, int, - SkimEMCClusters, - "_Two"); //! 2nd daughter of this meson -DECLARE_SOA_COLUMN(Oa, oa, float); //! opening angle between the two daugthers -DECLARE_SOA_COLUMN(Px, px, float); //! px -DECLARE_SOA_COLUMN(Py, py, float); //! py -DECLARE_SOA_COLUMN(Pz, pz, float); //! pz -DECLARE_SOA_COLUMN(E, e, float); //! E -DECLARE_SOA_COLUMN(Alpha, - alpha, float); //! energy asymmertry of the two daughter particles -DECLARE_SOA_COLUMN(Minv, minv, float); //! invariant mass of the meson -DECLARE_SOA_COLUMN(Eta, eta, float); //! pseudorapidity of the meson -DECLARE_SOA_COLUMN(Phi, phi, float); //! phi angle of the meson -DECLARE_SOA_COLUMN(Pt, pt, float); //! pT of the meson -} // namespace calomeson -DECLARE_SOA_TABLE(CaloMeson, "AOD", "CALOMESON", //! - o2::soa::Index<>, calomeson::CollisionId, calomeson::DaugtherPhotonOneId, calomeson::DaugtherPhotonTwoId, - calomeson::Oa, calomeson::Px, calomeson::Py, calomeson::Pz, calomeson::E, calomeson::Alpha, - calomeson::Minv, calomeson::Eta, calomeson::Phi, calomeson::Pt); -} // namespace o2::aod -#endif // PWGEM_PHOTONMESON_DATAMODEL_MESONTABLES_H_ diff --git a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt index 4ddadeea3f5..a4cf2e6b566 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 O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore KFParticle::KFParticle O2Physics::TPCDriftManager COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(create-pcm @@ -31,7 +31,7 @@ o2physics_add_dpl_workflow(create-pcm o2physics_add_dpl_workflow(create-emevent-photon SOURCES createEMEventPhoton.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGJECore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(associate-mc-info-photon @@ -44,6 +44,11 @@ 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::AnalysisCCDB O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(skimmer-phos SOURCES skimmerPHOS.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::PHOSBase @@ -58,13 +63,3 @@ o2physics_add_dpl_workflow(skimmer-dalitz-ee SOURCES skimmerDalitzEE.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 - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(produce-meson-calo - SOURCES produceMesonCalo.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore - COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx index 975367c14c2..885a2e85a38 100644 --- a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx @@ -8,27 +8,33 @@ // In applying this license CERN does 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 +/// +/// \file associateMCinfoPhoton.cxx +/// +/// \brief This code produces reduced events for photon analyses +/// +/// \author Daiki Sekihata (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" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include + 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 MyCollisionsMC = soa::Join; using TracksMC = soa::Join; using FwdTracksMC = soa::Join; using MyEMCClusters = soa::Join; @@ -48,18 +54,18 @@ struct AssociateMCInfoPhoton { Produces emprimaryelectronmclabels; Produces ememcclustermclabels; - Produces binned_gen_pt; + Produces binnedGenPt; - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; 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", kTH1I, {{6, 0.5f, 6.5f}}); + auto hEventCounter = registry.add("hEventCounter", "hEventCounter", kTH1F, {{6, 0.5f, 6.5f}}); hEventCounter->GetXaxis()->SetBinLabel(1, "all"); hEventCounter->GetXaxis()->SetBinLabel(2, "has mc collision"); @@ -77,15 +83,15 @@ struct AssociateMCInfoPhoton { 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} (GeV/c)"}; - const AxisSpec axis_rapidity{{0.0, +0.8, +0.9}, "rapidity |y|"}; + const AxisSpec axisPt{ptbins, "p_{T} (GeV/c)"}; + const AxisSpec axisRapidity{{0.0, +0.8, +0.9}, "rapidity |y|"}; - static constexpr std::string_view parnames[9] = { + 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", parnames[i].data()), Form("Generated %s", parnames[i].data()), kTH2F, {axis_pt, axis_rapidity}, true); + 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 @@ -97,17 +103,17 @@ struct AssociateMCInfoPhoton { } Preslice perMcCollision = aod::mcparticle::mcCollisionId; - Preslice perCollision_pcm = aod::v0photonkf::collisionId; - Preslice perCollision_el = aod::emprimaryelectron::collisionId; - Preslice perCollision_phos = aod::skimmedcluster::collisionId; - Preslice perCollision_emc = aod::skimmedcluster::collisionId; + 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& mcTracks, TTracks const& o2tracks, TFwdTracks const&, TPCMs const& v0photons, TPCMLegs const& /*v0legs*/, TPHOSs const& /*phosclusters*/, TEMCs const& emcclusters, TEMPrimaryElectrons const& emprimaryelectrons) + 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; @@ -118,7 +124,7 @@ struct AssociateMCInfoPhoton { int fCounters[2] = {0, 0}; //! [0] - particle counter, [1] - event counter auto hBinFinder = registry.get(HIST("Generated/h2PtY_Gamma")); - for (auto& collision : collisions) { + for (const auto& collision : collisions) { registry.fill(HIST("hEventCounter"), 1); // TODO: investigate the collisions without corresponding mcCollision @@ -126,7 +132,7 @@ struct AssociateMCInfoPhoton { continue; } - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { continue; } @@ -138,22 +144,26 @@ struct AssociateMCInfoPhoton { auto mcCollision = collision.mcCollision(); // store mc particles - auto groupedMcTracks = mcTracks.sliceBy(perMcCollision, mcCollision.globalIndex()); + auto groupedMcParticles = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); - for (auto& mctrack : groupedMcTracks) { // store necessary information for denominator of efficiency - if ((mctrack.isPhysicalPrimary() || mctrack.producedByGenerator()) && abs(mctrack.y()) < 0.9f && mctrack.pt() < 20.f) { - auto binNumber = hBinFinder->FindBin(mctrack.pt(), abs(mctrack.y())); // caution: pack - switch (abs(mctrack.pdgCode())) { + 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"), mctrack.pt(), abs(mctrack.y())); + registry.fill(HIST("Generated/h2PtY_Gamma"), mcParticle.pt(), std::fabs(mcParticle.y())); genGamma[binNumber]++; break; case 111: - registry.fill(HIST("Generated/h2PtY_Pi0"), mctrack.pt(), abs(mctrack.y())); + if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + continue; + registry.fill(HIST("Generated/h2PtY_Pi0"), mcParticle.pt(), std::fabs(mcParticle.y())); genPi0[binNumber]++; break; case 221: - registry.fill(HIST("Generated/h2PtY_Eta"), mctrack.pt(), abs(mctrack.y())); + if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + continue; + registry.fill(HIST("Generated/h2PtY_Eta"), mcParticle.pt(), std::fabs(mcParticle.y())); genEta[binNumber]++; break; default: @@ -164,41 +174,42 @@ struct AssociateMCInfoPhoton { // 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()); + mcevents(mcCollision.globalIndex(), mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.impactParameter(), mcCollision.eventPlaneAngle()); fEventLabels[mcCollision.globalIndex()] = fCounters[1]; fCounters[1]++; - binned_gen_pt(genGamma, genPi0, genEta); + 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 (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) { + 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 = mctrack.pdgCode(); - if (abs(pdg) > 1e+9) { + 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", mctrack.index(), mctrack.pdgCode(), mctrack.producedByGenerator(), mctrack.isPhysicalPrimary()); + // LOGF(info,"index = %d , mc track pdg = %d , producedByGenerator = %d , isPhysicalPrimary = %d", mcParticle.index(), mcParticle.pdgCode(), mcParticle.producedByGenerator(), mcParticle.isPhysicalPrimary()); - if (abs(pdg) == 11 && mctrack.has_mothers() && !(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { // secondary electrons. i.e. ele/pos from photon conversions. - int motherid = mctrack.mothersIds()[0]; // first mother index - auto mp = mcTracks.iteratorAt(motherid); + 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 (sqrt(pow(mctrack.vx(), 2) + pow(mctrack.vy(), 2)) < abs(mctrack.vz()) * std::tan(2 * std::atan(std::exp(-max_eta_gen_secondary))) - margin_z_gen) { + 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()) && abs(mp.eta()) < max_eta_gen_secondary) { + 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(mctrack.globalIndex()) != fNewLabels.end())) { // store electron information. !!Not photon!! - fNewLabels[mctrack.globalIndex()] = fCounters[0]; - fNewLabelsReversed[fCounters[0]] = mctrack.globalIndex(); - // fMCFlags[mctrack.globalIndex()] = mcflags; - fEventIdx[mctrack.globalIndex()] = fEventLabels.find(mcCollision.globalIndex())->second; + 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]++; } @@ -217,53 +228,53 @@ struct AssociateMCInfoPhoton { } // end of rec. collision loop if constexpr (static_cast(system & kPCM)) { - for (auto& v0 : v0photons) { - auto collision_from_v0 = collisions.iteratorAt(v0.collisionId()); - if (!collision_from_v0.has_mcCollision()) { + for (const auto& v0 : v0photons) { + auto collisionFromV0 = collisions.iteratorAt(v0.collisionId()); + if (!collisionFromV0.has_mcCollision()) { continue; } - auto mcCollision_from_v0 = collision_from_v0.mcCollision(); + auto mcCollisionFromV0 = collisionFromV0.mcCollision(); 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()); + auto o2TrackEle = o2tracks.iteratorAt(pos.trackId()); + auto o2TrackPos = o2tracks.iteratorAt(ele.trackId()); - if (!o2track_ele.has_mcParticle() || !o2track_pos.has_mcParticle()) { + if (!o2TrackEle.has_mcParticle() || !o2TrackPos.has_mcParticle()) { continue; // If no MC particle is found, skip the v0 } - for (auto& leg : {pos, ele}) { // be carefull of order {pos, ele}! + 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. + 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(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_v0.globalIndex())->second; + 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(mctrack.index())->second, o2track.mcMask()); + v0legmclabels(fNewLabels.find(mcParticle.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 + if (mcParticle.has_mothers()) { + motherid = mcParticle.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 (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(mcCollision_from_v0.globalIndex())->second; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollisionFromV0.globalIndex())->second; fCounters[0]++; } @@ -276,50 +287,50 @@ struct AssociateMCInfoPhoton { motherid = -999; } } // end of mother chain loop - } // end of leg loop - } // end of v0 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 (auto& emprimaryelectron : emprimaryelectrons) { - auto collision_from_el = collisions.iteratorAt(emprimaryelectron.collisionId()); - if (!collision_from_el.has_mcCollision()) { + // 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 mcCollision_from_el = collision_from_el.mcCollision(); + 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 mctrack = o2track.template mcParticle_as(); + 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(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; + 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(mctrack.index())->second, o2track.mcMask()); + emprimaryelectronmclabels(fNewLabels.find(mcParticle.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 + if (mcParticle.has_mothers()) { + motherid = mcParticle.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 (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(mcCollision_from_el.globalIndex())->second; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollisionFromEl.globalIndex())->second; fCounters[0]++; } @@ -337,21 +348,21 @@ struct AssociateMCInfoPhoton { } if constexpr (static_cast(system & kEMC)) { // for emc photons - // auto ememcclusters_coll = emcclusters.sliceBy(perCollision_emc, collision.globalIndex()); - for (auto& emccluster : emcclusters) { - auto collision_from_emc = collisions.iteratorAt(emccluster.collisionId()); - if (!collision_from_emc.has_mcCollision()) { + // 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 mcCollision_from_emc = collision_from_emc.mcCollision(); + auto mcCollisionFromEMC = collisionFromEMC.mcCollision(); - auto mcphoton = mcTracks.iteratorAt(emccluster.emmcparticleIds()[0]); + 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(mcCollision_from_emc.globalIndex())->second; + fEventIdx[mcphoton.globalIndex()] = fEventLabels.find(mcCollisionFromEMC.globalIndex())->second; fCounters[0]++; } ememcclustermclabels(fNewLabels.find(mcphoton.index())->second); @@ -362,14 +373,14 @@ struct AssociateMCInfoPhoton { 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 (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(mcCollision_from_emc.globalIndex())->second; + fEventIdx[mp.globalIndex()] = fEventLabels.find(mcCollisionFromEMC.globalIndex())->second; fCounters[0]++; } @@ -388,46 +399,46 @@ struct AssociateMCInfoPhoton { // 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); + auto mcParticle = mcParticles.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 (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 { - std::cout << "Mother label (" << m << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; - std::cout << " Check the MC generator" << std::endl; + 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 (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) { + 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 < mcTracks.size()) { // protect against bad daughter indices - // auto dau_tmp = mcTracks.iteratorAt(d); + 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 { - std::cout << "Daughter label (" << d << ") exceeds the McParticles size (" << mcTracks.size() << ")" << std::endl; - std::cout << " Check the MC generator" << std::endl; + LOG(info) << "Daughter label (" << d << ") exceeds the McParticles size (" << mcParticles.size() << ")"; + LOG(info) << " Check the MC generator"; } } } - emmcparticles(fEventIdx.find(oldLabel)->second, mctrack.pdgCode(), mctrack.flags(), + emmcparticles(fEventIdx.find(oldLabel)->second, mcParticle.pdgCode(), mcParticle.flags(), mcParticle.statusCode(), mothers, daughters, - mctrack.px(), mctrack.py(), mctrack.pz(), mctrack.e(), - mctrack.vx(), mctrack.vy(), mctrack.vz()); + mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e(), + mcParticle.vx(), mcParticle.vy(), mcParticle.vz()); } // end loop over labels fNewLabels.clear(); @@ -437,80 +448,90 @@ struct AssociateMCInfoPhoton { fEventLabels.clear(); fCounters[0] = 0; fCounters[1] = 0; - } // end of skimmingMC + } // 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) + 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, mcTracks, o2tracks, nullptr, v0photons, v0legs, nullptr, nullptr, nullptr); + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, nullptr, nullptr, nullptr); } - void processMC_PCM_Electron(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::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + 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, mcTracks, o2tracks, nullptr, v0photons, v0legs, nullptr, nullptr, emprimaryelectrons); + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, nullptr, nullptr, emprimaryelectrons); } - void processMC_Electron(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, TracksMC const& o2tracks, aod::EMPrimaryElectronsFromDalitz const& 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, mcTracks, o2tracks, nullptr, nullptr, nullptr, nullptr, nullptr, emprimaryelectrons); + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, nullptr, nullptr, nullptr, nullptr, emprimaryelectrons); } - void processMC_PHOS(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, aod::PHOSClusters const& phosclusters) + 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, mcTracks, nullptr, nullptr, nullptr, nullptr, phosclusters, nullptr, nullptr); + skimmingMC(collisions, bcs, mccollisions, mcParticles, nullptr, nullptr, nullptr, nullptr, phosclusters, nullptr, nullptr); } - void processMC_EMC(MyCollisionsMC const& collisions, aod::BCs const& bcs, aod::McCollisions const& mccollisions, aod::McParticles const& mcTracks, MyEMCClusters const& emcclusters) + 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, mcTracks, nullptr, nullptr, nullptr, nullptr, nullptr, emcclusters, nullptr); + skimmingMC(collisions, bcs, mccollisions, mcParticles, nullptr, nullptr, nullptr, nullptr, nullptr, emcclusters, 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) + 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, mcTracks, o2tracks, nullptr, v0photons, v0legs, phosclusters, nullptr, nullptr); + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, phosclusters, nullptr, nullptr); } - void processMC_PCM_PHOS_Electron(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::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + 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, mcTracks, o2tracks, nullptr, v0photons, v0legs, phosclusters, nullptr, emprimaryelectrons); + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, phosclusters, nullptr, emprimaryelectrons); } - 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) + 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, mcTracks, o2tracks, nullptr, v0photons, v0legs, nullptr, emcclusters, nullptr); + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, nullptr, emcclusters, nullptr); } - void processMC_PCM_EMC_Electron(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::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + 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, mcTracks, o2tracks, nullptr, v0photons, v0legs, nullptr, emcclusters, emprimaryelectrons); + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, nullptr, emcclusters, emprimaryelectrons); } - 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) + 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, mcTracks, nullptr, nullptr, nullptr, nullptr, phosclusters, emcclusters, nullptr); + skimmingMC(collisions, bcs, mccollisions, mcParticles, nullptr, nullptr, nullptr, nullptr, phosclusters, emcclusters, 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) + 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, mcTracks, o2tracks, nullptr, v0photons, v0legs, phosclusters, emcclusters, nullptr); + skimmingMC(collisions, bcs, mccollisions, mcParticles, o2tracks, nullptr, v0photons, v0legs, phosclusters, emcclusters, nullptr); } - void processMC_PCM_PHOS_EMC_Electron(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::EMPrimaryElectronsFromDalitz const& emprimaryelectrons) + 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, mcTracks, o2tracks, nullptr, v0photons, v0legs, phosclusters, emcclusters, emprimaryelectrons); + 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, processMC_PCM, "create em mc event table for PCM", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_Electron, "create em mc event table for PCM, Electron", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_Electron, "create em mc event table for Electron", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PHOS, "create em mc event table for PHOS", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_EMC, "create em mc event table for EMCal", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_PHOS, "create em mc event table for PCM, PHOS", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_PHOS_Electron, "create em mc event table for PCM, PHOS, Electron", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_EMC, "create em mc event table for PCM, EMCal", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_EMC_Electron, "create em mc event table for PCM, EMCal, Electron", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PHOS_EMC, "create em mc event table for PHOS, EMCal", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_PHOS_EMC, "create em mc event table for PCM, PHOS, EMCal", false); - PROCESS_SWITCH(AssociateMCInfoPhoton, processMC_PCM_PHOS_EMC_Electron, "create em mc event table for PCM, PHOS, EMCal, Electron", false); PROCESS_SWITCH(AssociateMCInfoPhoton, processDummy, "processDummy", true); }; diff --git a/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx b/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx new file mode 100644 index 00000000000..b193c642175 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx @@ -0,0 +1,404 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGEM/PhotonMeson/DataModel/bcWiseTables.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DetectorsBase/GeometryManager.h" +#include "EMCALBase/Geometry.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod::emdownscaling; +using namespace o2::framework; +using namespace o2::framework::expressions; + +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 mcetaTable; + 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 cfgMaxClusterEnergy{"cfgMaxClusterEnergy", 30., "Maximum 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"}; + Configurable cfgMinPtGen{"cfgMinPtGen", 0., "Minimum pT for stored generated mesons (reduce disk space of derived data)"}; + + Configurable cfgRequirekTVXinEMC{"cfgRequirekTVXinEMC", false, "Only store kTVXinEMC triggered BCs"}; + Configurable cfgRequireGoodRCTQuality{"cfgRequireGoodRCTQuality", false, "Only store BCs with good quality of T0 and EMC in RCT"}; + Configurable cfgStoreMu{"cfgStoreMu", false, "Calculate and store mu (probablity of a TVX collision in the BC) per BC. Otherwise fill with 0"}; + Configurable cfgStoreTime{"cfgStoreTime", false, "Calculate and store time since the start of fill. Otherwise fill with 0"}; + ConfigurableAxis cfgMultiplicityBinning{"cfgMultiplicityBinning", {1000, 0, 10000}, "Binning used for the binning of the number of particles in the event"}; + + aod::rctsel::RCTFlagsChecker isFT0EMCGoodRCTChecker{aod::rctsel::kFT0Bad, aod::rctsel::kEMCBad}; + parameters::GRPLHCIFData* mLHCIFdata = nullptr; + int mRunNumber = -1; + ctpRateFetcher mRateFetcher; + + Filter energyFilter = (aod::emcalcluster::energy > cfgMinClusterEnergy && aod::emcalcluster::energy < cfgMaxClusterEnergy); + Filter m02Filter = (aod::emcalcluster::nCells == 1 || (aod::emcalcluster::m02 > cfgMinM02 && aod::emcalcluster::m02 < cfgMaxM02)); + Filter timeFilter = (aod::emcalcluster::time > cfgMinTime && aod::emcalcluster::time < cfgMaxTime); + Filter emccellFilter = aod::calo::caloType == 1; + + HistogramRegistry mHistManager{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + std::map fMapPi0Index; // Map to connect the MC index of the pi0 to the one saved in the derived table + std::map fMapEtaIndex; // Map to connect the MC index of the eta to the one saved in the derived table + + void init(o2::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", "HasMCColl"}; + for (int iBin = 0; iBin < nEventBins; iBin++) + mHistManager.get(HIST("nBCs"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin]); + + mHistManager.add("CentralityVsGenMultiplicity", "Centrality vs number of generated MC particles;Centrality;#bf{#it{N}_{gen}}", HistType::kTH2F, {{102, 0., 102}, cfgMultiplicityBinning}); + mHistManager.add("CentralityFT0CVsM", "Centrality of FT0C vs FT0M;FT0C Cent;FT0M Cent", HistType::kTH2F, {{102, 0., 102}, {102, 0., 102}}); + mHistManager.add("BCCentVsCollCent", "Centrality of the BC vs Centrality of the collision;BC Centrality;Collision Centrality", HistType::kTH2F, {{102, 0., 102}, {102, 0., 102}}); + mHistManager.add("BCHasFT0FoundFT0", "BCHasFT0FoundFT0;BC has FT0;BC has found FT0", HistType::kTH2F, {{1000, -2., 50000}, {1000, -2., 50000}}); + mHistManager.add("BCFoundFT0Diff", "BCFoundFT0Diff;BC_{ID}^{found FT0} - BC_{ID}^{FT0}", HistType::kTH1F, {{200001, -100000.5, 100000.5}}); + mHistManager.add("BCIDOfMCColl", "BCIDOfMCColl;BCID", HistType::kTH1F, {{4001, -0.5, 4000.5}}); + mHistManager.add("BCIDOfMCCollButNoFT0", "BCIDOfMCCollButNoFT0;BCID", HistType::kTH1F, {{4001, -0.5, 4000.5}}); + + mHistManager.add("MCZVtx", "Vertex position of MC collision;#bf{z_{vtx}^{MC} (cm)};#bf{#it{N}_{BCs}}", HistType::kTH1F, {{2000, -100, 100}}); + mHistManager.add("MCZVtx_TVX", "Vertex position of MC collision;#bf{z_{vtx}^{MC} (cm)};#bf{#it{N}_{BCs}}", HistType::kTH1F, {{2000, -100, 100}}); + + LOG(info) << "BC wise cluster skimmer cuts:"; + LOG(info) << "------------------------------------"; + LOG(info) << "| Timing cut: " << cfgMinTime << " < t < " << cfgMaxTime; + LOG(info) << "| Shape cut: " << cfgMinM02 << " < M02 < " << cfgMaxM02; + LOG(info) << "| Energy cut: " << cfgMinClusterEnergy << " < E < " << cfgMaxClusterEnergy; + LOG(info) << "| Rapidity cut: |y| < " << cfgRapidityCut; + LOG(info) << "| Min gen pt: pT > " << cfgMinPtGen; + + o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + if (cfgRequireGoodRCTQuality) + isFT0EMCGoodRCTChecker.init({aod::rctsel::kFT0Bad, aod::rctsel::kEMCBad}); + } + + /// \brief Process EMCAL clusters (either ambigous or unique) + template + OutputType convertForStorage(InputType const& valueIn, Observable 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.; + int32_t mesonMCIndex = -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, 221}); + if (daughterId > 0) { + mesonMCIndex = mcParticles.iteratorAt(daughterId).mothersIds()[0]; + if (mcParticles.iteratorAt(mesonMCIndex).pt() < cfgMinPtGen) + mesonMCIndex = -1; + } + } + bool isEta = false; + if (mesonMCIndex >= 0) { + if (mcParticles.iteratorAt(mesonMCIndex).pdgCode() == 111) { + if (fMapPi0Index.find(mesonMCIndex) != fMapPi0Index.end()) // Some pi0s might not be found (not gg decay or too large y) + mesonMCIndex = fMapPi0Index[mesonMCIndex]; // If pi0 was stored in table, change index from the MC index to the pi0 index from this task + else // If pi0 was not stored, treat photon as if not from pi0 + mesonMCIndex = -1; + } else if (mcParticles.iteratorAt(mesonMCIndex).pdgCode() == 221) { + isEta = true; + if (fMapEtaIndex.find(mesonMCIndex) != fMapEtaIndex.end()) // Some etas might not be found (not gg decay or too large y) + mesonMCIndex = fMapEtaIndex[mesonMCIndex]; // If eta was stored in table, change index from the MC index to the eta index from this task + else // If eta was not stored, treat photon as if not from eta + mesonMCIndex = -1; + } else { + mesonMCIndex = -1; // Not a pi0 or eta + } + } + mcclusterTable(bcID, mesonMCIndex, isEta, convertForStorage(clusterInducerEnergy, kEnergy)); + } + } + + bool isBCSelected(const auto& bc) + { + if (cfgRequirekTVXinEMC && !bc.alias_bit(kTVXinEMC)) + return false; + if (cfgRequireGoodRCTQuality && !isFT0EMCGoodRCTChecker(bc)) + return false; + return true; + } + + void setLHCIFData(const auto& bc) + { + if (mRunNumber == bc.runNumber()) + return; + + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + uint64_t timeStamp = bc.timestamp(); + + std::map metadata; + mLHCIFdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); + if (mLHCIFdata == nullptr) + LOG(fatal) << "GRPLHCIFData not in database, timestamp:" << timeStamp; + mRunNumber = bc.runNumber(); + LOG(info) << "LHCIF data fetched for run " << mRunNumber << " and timestamp " << timeStamp; + + return; + } + + double calculateMu(const auto& bc) + { + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + uint64_t timeStamp = bc.timestamp(); + + auto bfilling = mLHCIFdata->getBunchFilling(); + double nbc = bfilling.getFilledBCs().size(); + double tvxRate = mRateFetcher.fetch(&ccdbMgr, timeStamp, bc.runNumber(), "T0VTX"); + double nTriggersPerFilledBC = tvxRate / nbc / o2::constants::lhc::LHCRevFreq; + double mu = -std::log(1 - nTriggersPerFilledBC); + + // LOG(info) << "Time stamp: " << timeStamp << " Run number: " << bc.runNumber() << " Number of filled BCs: " << nbc << " Trigger rate: " << tvxRate << " Mu: " << mu; + + return mu; + } + + void processEventProperties(const auto& bc, const auto& collisionsInBC, const auto& cellsInBC, const bool hasMCCollision = false) + { + bool hasFT0 = bc.has_ft0(); + bool hasFoundFT0 = bc.has_foundFT0(); + int foundFT0ID = hasFoundFT0 ? bc.foundFT0().bcId() : -1; + int FT0ID = hasFT0 ? bc.ft0().bcId() : -1; + mHistManager.fill(HIST("BCHasFT0FoundFT0"), static_cast(FT0ID), static_cast(foundFT0ID)); + mHistManager.fill(HIST("BCFoundFT0Diff"), static_cast(foundFT0ID - FT0ID)); + + auto bcIDInOrbit = bc.globalBC() % 3564; + + if (hasMCCollision) { + mHistManager.fill(HIST("BCIDOfMCColl"), static_cast(bcIDInOrbit)); + if (!hasFoundFT0) { + mHistManager.fill(HIST("BCIDOfMCCollButNoFT0"), static_cast(bcIDInOrbit)); + } + } + + bool hasTVX = bc.selection_bit(aod::evsel::kIsTriggerTVX); + bool haskTVXinEMC = bc.alias_bit(kTVXinEMC); + bool hasEMCCell = cellsInBC.size() > 0; + mHistManager.fill(HIST("nBCs"), 0); + if (hasFoundFT0) + 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 (hasMCCollision) + mHistManager.fill(HIST("nBCs"), 5); + + if (cfgStoreMu || cfgStoreTime) + setLHCIFData(bc); + double mu = cfgStoreMu ? calculateMu(bc) : 0.; + float timeSinceSOF = cfgStoreTime ? (bc.timestamp() - mLHCIFdata->getFillNumberTime()) / 1e3 : 0.; // Convert to seconds + float ft0Amp = hasFoundFT0 ? bc.foundFT0().sumAmpA() + bc.foundFT0().sumAmpC() : 0.; + double centralityOfCollision = 101.5; + if (collisionsInBC.size() > 0) + centralityOfCollision = collisionsInBC.iteratorAt(0).centFT0C(); + double centralityOfBC = bc.centFT0C(); + + mHistManager.fill(HIST("BCCentVsCollCent"), centralityOfBC, centralityOfCollision); + mHistManager.fill(HIST("CentralityFT0CVsM"), centralityOfBC, bc.centFT0M()); + + bcTable(hasFoundFT0, hasTVX, haskTVXinEMC, hasEMCCell, convertForStorage(centralityOfBC, kCent), convertForStorage(bc.centFT0M(), kCent), convertForStorage(ft0Amp, kFT0Amp), convertForStorage(mu, kMu), convertForStorage(timeSinceSOF, kTimeSinceSOF)); + + for (const auto& collision : collisionsInBC) + collisionTable(bcTable.lastIndex(), convertForStorage(collision.posZ(), kZVtx)); + } + + 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) { + if (!isBCSelected(bc)) + continue; + 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) { + if (!isBCSelected(bc)) + continue; + auto collisionsInBC = collisions.sliceBy(perFoundBC, bc.globalIndex()); + auto cellsInBC = cells.sliceBy(cellsPerBC, bc.globalIndex()); + + auto mcCollisionsBC = mcCollisions.sliceBy(mcCollperBC, bc.globalIndex()); + + processEventProperties(bc, collisionsInBC, cellsInBC, mcCollisionsBC.size() > 0); + + for (const auto& mcCollision : mcCollisionsBC) { + mHistManager.fill(HIST("MCZVtx"), mcCollision.posZ()); + if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) + mHistManager.fill(HIST("MCZVtx_TVX"), mcCollision.posZ()); + auto mcParticlesInColl = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); + mHistManager.fill(HIST("CentralityVsGenMultiplicity"), bc.centFT0M(), mcParticlesInColl.size()); + for (const auto& mcParticle : mcParticlesInColl) { + if (std::abs(mcParticle.y()) > cfgRapidityCut || !isGammaGammaDecay(mcParticle, mcParticles) || mcParticle.pt() < cfgMinPtGen) + continue; + bool isPrimary = mcParticle.isPhysicalPrimary() || mcParticle.producedByGenerator(); + bool isFromWD = (aod::pwgem::photonmeson::utils::mcutil::IsFromWD(mcCollision, mcParticle, mcParticles)) > 0; + + if (mcParticle.pdgCode() == 111) { + mcpi0Table(bc.globalIndex(), convertForStorage(mcParticle.pt(), kpT), isAccepted(mcParticle, mcParticles), isPrimary, isFromWD); + fMapPi0Index[mcParticle.globalIndex()] = static_cast(mcpi0Table.lastIndex()); + } else if (mcParticle.pdgCode() == 221) { + mcetaTable(bc.globalIndex(), convertForStorage(mcParticle.pt(), kpT), isAccepted(mcParticle, mcParticles), isPrimary, isFromWD); + fMapEtaIndex[mcParticle.globalIndex()] = static_cast(mcetaTable.lastIndex()); + } + } + } + + if (collisionsInBC.size() == 1) { + auto clustersInBC = uClusters.sliceBy(perCol, collisionsInBC.begin().globalIndex()); + processClusters(clustersInBC, bcTable.lastIndex()); + processClusterMCInfo(clustersInBC, bcTable.lastIndex(), mcParticles); + } else { + auto clustersInBC = aClusters.sliceBy(perBC, bc.globalIndex()); + processClusters(clustersInBC, bcTable.lastIndex()); + processClusterMCInfo(clustersInBC, bcTable.lastIndex(), mcParticles); + } + fMapPi0Index.clear(); + fMapEtaIndex.clear(); + } + } + PROCESS_SWITCH(bcWiseClusterSkimmer, processMC, "Run skimming for MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx index fa6b7f9ce25..5fbd30a30e2 100644 --- a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx @@ -8,24 +8,41 @@ // In applying this license CERN does 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 "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" +/// \file createEMEventPhoton.cxx +/// \brief This code produces reduced events for photon analyses. +/// \author Daiki Sekihata, daiki.sekihata@cern.ch #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +// +#include "PWGJE/DataModel/Jet.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Qvectors.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -33,27 +50,37 @@ using namespace o2::framework::expressions; using namespace o2::soa; using MyBCs = soa::Join; -using MyQvectors = 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 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; +using MyCollisionsMCCent = soa::Join; // centrality table has dependency on multiplicity table. +using MyCollisionsMCCentQvec = soa::Join; -struct CreateEMEvent { +struct CreateEMEventPhoton { + // Produces embc; Produces event; - Produces eventcov; - Produces event_mult; - Produces event_cent; - Produces event_qvec; + Produces eventalias; + // Produces eventCov; + Produces eventMult; + Produces eventCent; + Produces eventQvec; + Produces emswtbit; + Produces event_norm_info; + Produces eventWeights; enum class EMEventType : int { kEvent = 0, kEvent_Cent = 1, kEvent_Cent_Qvec = 2, + kEvent_JJ = 3, }; // CCDB options @@ -61,8 +88,11 @@ struct CreateEMEvent { 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"}; - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; + 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&) @@ -70,10 +100,14 @@ struct CreateEMEvent { 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 d_bz; + float dBz; Service ccdb; template @@ -84,51 +118,47 @@ struct CreateEMEvent { } // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { - d_bz = d_bz_input; + if (dBzInput > -990) { + dBz = dBzInput; o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + if (std::fabs(dBz) > 1e-5) { + grpmag.setL3Current(30000.f / (dBz / 5.0f)); } mRunNumber = bc.runNumber(); return; } - auto run3grp_timestamp = bc.timestamp(); + auto run3GRPTimestamp = bc.timestamp(); o2::parameters::GRPObject* grpo = 0x0; o2::parameters::GRPMagField* grpmag = 0x0; if (!skipGRPOquery) - grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + grpo = ccdb->getForTimeStamp(grpPath, run3GRPTimestamp); 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"; + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3GRPTimestamp << " with magnetic field of " << dBz << " kZG"; } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + 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 " << run3grp_timestamp; + 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 - 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"; + 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(); } - PresliceUnsorted preslice_collisions_per_bc = o2::aod::evsel::foundBCId; - std::unordered_map map_ncolls_per_bc; - - template - void skimEvent(TCollisions const& collisions, TBCs const& bcs) + template + void skimEvent(TCollisions const& collisions, TBCs const&) { - // 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 (const auto& bc : bcs) { + // if (bc.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + // embc(bc.selection_raw(), bc.rct_raw()); // TVX is fired. + // } + // } // end of bc loop - for (auto& collision : collisions) { + for (const auto& collision : collisions) { if constexpr (isMC) { if (!collision.has_mcCollision()) { continue; @@ -138,159 +168,247 @@ struct CreateEMEvent { auto bc = collision.template foundBC_as(); initCCDB(bc); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (needEMCTrigger && !collision.alias_bit(kTVXinEMC)) { continue; } + if (needPHSTrigger && !collision.alias_bit(kTVXinPHOS)) { + continue; + } + + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + int16_t posZint16 = static_cast(collision.posZ() * 100.f); + if (posZint16 == 0.f) { + if (collision.posZ() < 0) { + posZint16 = -1; + } else { + posZint16 = +1; + } + } + if constexpr (eventtype == EMEventType::kEvent) { + event_norm_info(collision.selection_raw(), collision.rct_raw(), posZint16, static_cast(105.f * 500.f)); + } else if constexpr (eventtype == EMEventType::kEvent_Cent || eventtype == EMEventType::kEvent_Cent_Qvec) { + event_norm_info(collision.selection_raw(), collision.rct_raw(), posZint16, static_cast(collision.centFT0C() * 500.f)); + } else { + event_norm_info(collision.selection_raw(), collision.rct_raw(), posZint16, static_cast(105.f * 500.f)); + } + } + + if (!collision.isSelected()) { + continue; + } + + if (!collision.isEoI()) { // events with at least 1 photon for data reduction. + continue; + } + + if constexpr (isTriggerAnalysis) { + if (collision.swtaliastmp_raw() == 0) { + continue; + } else { + emswtbit(collision.swtaliastmp_raw()); + } + } + + const float qDefault = 999.f; // default value for q vectors if not obtained - // 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.runNumber(), bc.globalBC(), collision.alias_raw(), collision.selection_raw(), bc.timestamp(), - collision.posX(), collision.posY(), collision.posZ(), - collision.numContrib(), collision.trackOccupancyInTimeRange()); - - eventcov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); - - event_mult(collision.multFT0A(), collision.multFT0C(), collision.multTPC(), collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf()); - - 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; - float q4xft0m = 999.f, q4yft0m = 999.f, q4xft0a = 999.f, q4yft0a = 999.f, q4xft0c = 999.f, q4yft0c = 999.f, q4xbpos = 999.f, q4ybpos = 999.f, q4xbneg = 999.f, q4ybneg = 999.f, q4xbtot = 999.f, q4ybtot = 999.f; - - if constexpr (eventype == EMEventType::kEvent) { - event_cent(105.f, 105.f, 105.f, 105.f); - 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, - q4xft0m, q4yft0m, q4xft0a, q4yft0a, q4xft0c, q4yft0c, q4xbpos, q4ybpos, q4xbneg, q4ybneg, q4xbtot, q4ybtot); - } else if constexpr (eventype == EMEventType::kEvent_Cent) { - event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); - 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, - q4xft0m, q4yft0m, q4xft0a, q4yft0a, q4xft0c, q4yft0c, q4xbpos, q4ybpos, q4xbneg, q4ybneg, q4xbtot, q4ybtot); - } else if constexpr (eventype == EMEventType::kEvent_Cent_Qvec) { - event_cent(collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()); - - if (collision.qvecFT0CReVec().size() >= 3) { // harmonics 2,3,4 - 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]; - q4xft0m = collision.qvecFT0MReVec()[2], q4xft0a = collision.qvecFT0AReVec()[2], q4xft0c = collision.qvecFT0CReVec()[2], q4xbpos = collision.qvecBPosReVec()[2], q4xbneg = collision.qvecBNegReVec()[2], q4xbtot = collision.qvecBTotReVec()[2]; - q4yft0m = collision.qvecFT0MImVec()[2], q4yft0a = collision.qvecFT0AImVec()[2], q4yft0c = collision.qvecFT0CImVec()[2], q4ybpos = collision.qvecBPosImVec()[2], q4ybneg = collision.qvecBNegImVec()[2], q4ybtot = collision.qvecBTotImVec()[2]; - } else 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(collision.globalIndex(), bc.runNumber(), bc.globalBC(), collision.selection_raw(), collision.rct_raw(), bc.timestamp(), + collision.posZ(), + collision.numContrib(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + eventalias(collision.alias_raw()); + + // 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 (eventtype != EMEventType::kEvent_JJ) { + eventWeights(1.f); + } + + if constexpr (eventtype == 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, qDefault, qDefault, qDefault, qDefault); + } else if constexpr (eventtype == EMEventType::kEvent_Cent) { + 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, qDefault, qDefault, qDefault, qDefault); + } else if constexpr (eventtype == EMEventType::kEvent_Cent_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.qvecFV0AReVec()[0], collision.qvecFV0AImVec()[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.qvecFV0AReVec()[1], collision.qvecFV0AImVec()[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.qvecFV0AReVec()[0], collision.qvecFV0AImVec()[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, qDefault, qDefault); } - 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, - q4xft0m, q4yft0m, q4xft0a, q4yft0a, q4xft0c, q4yft0c, q4xbpos, q4ybpos, q4xbneg, q4ybneg, q4xbtot, q4ybtot); } else { - event_cent(105.f, 105.f, 105.f, 105.f); - 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, - q4xft0m, q4yft0m, q4xft0a, q4yft0a, q4xft0c, q4yft0c, q4xbpos, q4ybpos, q4xbneg, q4ybneg, q4xbtot, q4ybtot); + 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, qDefault, qDefault, qDefault, qDefault); } } // end of collision loop - map_ncolls_per_bc.clear(); + } // 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); + } + } + + // for data void processEvent(MyCollisions const& collisions, MyBCs const& bcs) { - skimEvent(collisions, bcs); + skimEvent(collisions, bcs); } - PROCESS_SWITCH(CreateEMEvent, processEvent, "process event info", false); + PROCESS_SWITCH(CreateEMEventPhoton, processEvent, "process event info", false); - void processEventMC(MyCollisionsMC const& collisions, MyBCs const& bcs) + void processEvent_Cent(MyCollisionsCent const& collisions, MyBCs const& bcs) { - skimEvent(collisions, bcs); + skimEvent(collisions, bcs); } - PROCESS_SWITCH(CreateEMEvent, processEventMC, "process event info", false); + PROCESS_SWITCH(CreateEMEventPhoton, processEvent_Cent, "process event info", false); - void processEvent_Cent(MyCollisions_Cent const& collisions, MyBCs const& bcs) + void processEvent_Cent_Qvec(MyCollisionsCentQvec const& collisions, MyBCs const& bcs) { - skimEvent(collisions, bcs); + skimEvent(collisions, bcs); } - PROCESS_SWITCH(CreateEMEvent, processEvent_Cent, "process event info", false); + PROCESS_SWITCH(CreateEMEventPhoton, processEvent_Cent_Qvec, "process event info", false); - void processEvent_Cent_Qvec(MyCollisions_Cent_Qvec const& collisions, MyBCs const& bcs) + void processEvent_SWT(MyCollisionsWithSWT const& collisions, MyBCs const& bcs) { - skimEvent(collisions, bcs); + skimEvent(collisions, bcs); } - PROCESS_SWITCH(CreateEMEvent, processEvent_Cent_Qvec, "process event info", false); + PROCESS_SWITCH(CreateEMEventPhoton, processEvent_SWT, "process event info", false); - void processEventMC_Cent(MyCollisionsMC_Cent const& collisions, MyBCs const& bcs) + void processEvent_SWT_Cent(MyCollisionsWithSWT_Cent const& collisions, MyBCs const& bcs) { - skimEvent(collisions, bcs); + skimEvent(collisions, bcs); } - PROCESS_SWITCH(CreateEMEvent, processEventMC_Cent, "process event info", false); + PROCESS_SWITCH(CreateEMEventPhoton, processEvent_SWT_Cent, "process event info", false); - void processEventMC_Cent_Qvec(MyCollisionsMC_Cent_Qvec const& collisions, MyBCs const& bcs) + void processEvent_SWT_Cent_Qvec(MyCollisionsWithSWT_Cent_Qvec const& collisions, MyBCs const& bcs) { - skimEvent(collisions, bcs); + skimEvent(collisions, bcs); } - PROCESS_SWITCH(CreateEMEvent, processEventMC_Cent_Qvec, "process event info", false); + PROCESS_SWITCH(CreateEMEventPhoton, processEvent_SWT_Cent_Qvec, "process event info", false); + + // for MC + 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 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(CreateEMEvent, processDummy, "processDummy", true); + PROCESS_SWITCH(CreateEMEventPhoton, processDummy, "processDummy", true); }; struct AssociatePhotonToEMEvent { Produces v0kfeventid; Produces prmeleventid; - Produces prmmueventid; Produces phoseventid; Produces emceventid; + Produces prmtrackeventid; - 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; + Preslice perCollisionPCM = aod::v0photonkf::collisionId; + PresliceUnsorted perCollisionEl = aod::emprimaryelectron::collisionId; + Preslice perCollisionPHOS = aod::skimmedcluster::collisionId; + Preslice perCollisionEMC = aod::skimmedcluster::collisionId; + Preslice perCollision_track = aod::emprimarytrack::collisionId; void init(o2::framework::InitContext&) {} 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 (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 + } // 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. + // 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, perCollision_pcm); + fillEventId(collisions, photons, v0kfeventid, perCollisionPCM); } void processElectronFromDalitz(aod::EMEvents const& collisions, aod::EMPrimaryElectronsFromDalitz const& tracks) { - fillEventId(collisions, tracks, prmeleventid, perCollision_el); + fillEventId(collisions, tracks, prmeleventid, perCollisionEl); } void processPHOS(aod::EMEvents const& collisions, aod::PHOSClusters const& photons) { - fillEventId(collisions, photons, phoseventid, perCollision_phos); + fillEventId(collisions, photons, phoseventid, perCollisionPHOS); } void processEMC(aod::EMEvents const& collisions, aod::SkimEMCClusters const& photons) { - fillEventId(collisions, photons, emceventid, perCollision_emc); + fillEventId(collisions, photons, emceventid, perCollisionEMC); + } + + void processChargedTrack(aod::EMEvents const& collisions, aod::EMPrimaryTracks const& tracks) + { + fillEventId(collisions, tracks, prmtrackeventid, perCollision_track); } void processDummy(aod::EMEvents const&) {} @@ -299,12 +417,13 @@ struct AssociatePhotonToEMEvent { 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, processChargedTrack, "process indexing for charged tracks", false); PROCESS_SWITCH(AssociatePhotonToEMEvent, processDummy, "process dummy", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"create-emevent-photon"}), + 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 f8ba87d2cbc..4ca74633e1b 100644 --- a/PWGEM/PhotonMeson/TableProducer/createPCM.cxx +++ b/PWGEM/PhotonMeson/TableProducer/createPCM.cxx @@ -554,15 +554,8 @@ struct createPCM { PROCESS_SWITCH(createPCM, processTrkCollAsso, "create V0s with track-to-collision associator", false); }; -// Extends the v0data table with expression columns -struct v0Initializer { - Spawns v0cores; - void init(InitContext const&) {} -}; - WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"v0-finder"}), - adaptAnalysisTask(cfgc, TaskName{"v0-initializer"})}; + adaptAnalysisTask(cfgc, TaskName{"v0-finder"})}; } diff --git a/PWGEM/PhotonMeson/TableProducer/gammaSelection.cxx b/PWGEM/PhotonMeson/TableProducer/gammaSelection.cxx deleted file mode 100644 index 7a3708d480b..00000000000 --- a/PWGEM/PhotonMeson/TableProducer/gammaSelection.cxx +++ /dev/null @@ -1,193 +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 skim cluster information to write photon cluster table in AO2D.root -/// dependencies: skimmergammacalo, skimmergammaconversions, skimmer-phos -/// \author marvin.hemmer@cern.ch - -// TODO: add PCM table -#include - -#include "PWGEM/PhotonMeson/Utils/gammaSelectionCuts.h" - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -// includes for the R recalculation -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "CCDB/BasicCCDBManager.h" - -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct gammaSelection { - - uint64_t EMC_CutModeBit; - - Preslice perEMCClusterMT = o2::aod::caloextra::clusterId; - - Produces tableGammaReco; - Produces tableEMCCuts; - - // Configurable for filter/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_CutMode{"EMC_CutMode", "0", "Cut Mode that is run. Each bit is a different setting. The first bit will use the cuts from the configurables."}; - - Configurable PHOS_minTime{"PHOS_minTime", -30., "Minimum cluster time for PHOS time cut"}; - Configurable PHOS_maxTime{"PHOS_maxTime", +30., "Maximum cluster time for PHOS time cut"}; - Configurable PHOS_minM02{"PHOS_minM02", 0.1, "Minimum M02 for PHOS M02 cut"}; - Configurable PHOS_minE{"PHOS_minE", 0.3, "Minimum cluster energy for PHOS energy cut"}; - Configurable PHOS_minENCell{"PHOS_minENCell", 0.1, "Threshold cluster energy for switch for PHOS NCell and M02 cut"}; - Configurable PHOS_minNCell{"PHOS_minNCell", 1, "Minimum number of cells per cluster for PHOS NCell cut"}; - Configurable PHOS_TM_Eta{"PHOS_TM_Eta", 0.02f, "|eta| <= value for PHOS track matching"}; - Configurable PHOS_TM_Phi{"PHOS_TM_Phi", 0.08f, "|phi| <= value for PHOS track matching"}; - - Configurable PHOS_QA{"PHOS_QA", 0b0, "Flag to enable PHOS related QA plots. 1st bit for TM QA."}; - - HistogramRegistry EMCHistos{ - "EMCHistos", - {}, - OutputObjHandlingPolicy::QAObject, - true, - true}; - - HistogramRegistry PHOSHistos{ - "PHOSHistos", - {}, - OutputObjHandlingPolicy::QAObject, - true, - true}; - - void init(o2::framework::InitContext&) - { - EMC_CutModeBit = stoi(EMC_CutMode, 0, 2); - std::bitset<64> EMC_CutModeBitSet(EMC_CutModeBit); - // EMCal - EMCHistos.add("hClusterEIn", "hClusterEIn", gHistoSpec_clusterECuts); - EMCHistos.add("hClusterEOut", "hClusterEOut", gHistoSpec_clusterECuts); - auto hCaloCuts_EMC = EMCHistos.add("hCaloCuts_EMC", "hCaloCuts_EMC", kTH2I, {{7, -0.5, 6.5}, {64, -0.5, 63.5}}); - hCaloCuts_EMC->GetXaxis()->SetBinLabel(1, "in"); - hCaloCuts_EMC->GetXaxis()->SetBinLabel(2, "#it{t}_{cluster} cut"); - hCaloCuts_EMC->GetXaxis()->SetBinLabel(3, "#it{M}_{02} cut"); - hCaloCuts_EMC->GetXaxis()->SetBinLabel(4, "#it{E} cut"); - hCaloCuts_EMC->GetXaxis()->SetBinLabel(5, "#it{N}_{cell} cut"); - hCaloCuts_EMC->GetXaxis()->SetBinLabel(6, "TM"); - hCaloCuts_EMC->GetXaxis()->SetBinLabel(7, "out"); - - LOG(info) << "| ECMal cluster cut settings:"; - LOG(info) << "|\t Timing cut: " << EMC_minTime << " < t < " << EMC_maxTime; - LOG(info) << "|\t M02 cut: " << EMC_minM02 << " < M02 < " << EMC_maxM02; - LOG(info) << "|\t E_min cut: E_cluster > " << EMC_minE; - LOG(info) << "|\t N_cell cut: N_cell > " << EMC_minNCell; - LOG(info) << "|\t TM |eta|: |eta| <= " << EMC_TM_Eta->at(0) << " + (pT + " << EMC_TM_Eta->at(1) << ")^" << EMC_TM_Eta->at(2); - LOG(info) << "|\t TM |phi|: |phi| <= " << EMC_TM_Phi->at(0) << " + (pT + " << EMC_TM_Phi->at(1) << ")^" << EMC_TM_Phi->at(2); - LOG(info) << "|\t TM E/p: E/p < " << EMC_Eoverp; - LOG(info) << "|\t Cut bit is set to: " << EMC_CutModeBitSet << std::endl; - - gatherCutsEMC(EMC_minTime, EMC_maxTime, EMC_minM02, EMC_maxM02, EMC_minE, EMC_minNCell, EMC_TM_Eta, EMC_TM_Phi, EMC_Eoverp); - - // PHOS - PHOSHistos.add("hClusterEIn", "hClusterEIn", gHistoSpec_clusterECuts); - PHOSHistos.add("hClusterEOut", "hClusterEOut", gHistoSpec_clusterECuts); - auto hCaloCuts_PHOS = PHOSHistos.add("hCaloCuts_PHOS", "hCaloCuts_PHOS", kTH1I, {{7, -0.5, 6.5}}); - hCaloCuts_PHOS->GetXaxis()->SetBinLabel(1, "in"); - hCaloCuts_PHOS->GetXaxis()->SetBinLabel(2, "#it{t}_{cluster} cut"); - hCaloCuts_PHOS->GetXaxis()->SetBinLabel(3, "#it{M}_{02} cut"); - hCaloCuts_PHOS->GetXaxis()->SetBinLabel(4, "#it{E} cut"); - hCaloCuts_PHOS->GetXaxis()->SetBinLabel(5, "#it{N}_{cell} cut"); - hCaloCuts_PHOS->GetXaxis()->SetBinLabel(6, "TM"); - hCaloCuts_PHOS->GetXaxis()->SetBinLabel(7, "out"); - if (PHOS_QA & 0b1) { - PHOSHistos.add("clusterTM_dEtadPhi", "cluster trackmatching dEta/dPhi;d#it{#eta};d#it{#varphi} (rad)", kTH2F, {{100, -0.2, 0.2}, {100, -0.2, 0.2}}); // dEta dPhi map of matched tracks - } - - LOG(info) << "| PHOS cluster cut settings:"; - LOG(info) << "|\t Timing cut: " << PHOS_minTime << " < t < " << PHOS_maxTime; - LOG(info) << "|\t NCell cut: " << PHOS_minNCell << " <= NCell for E >= " << PHOS_minENCell; - LOG(info) << "|\t M02 cut: " << PHOS_minM02 << " < M02 for E >= " << PHOS_minENCell; - LOG(info) << "|\t E_min cut: E_cluster > " << PHOS_minE; - LOG(info) << "|\t TM |eta|: |eta| <= " << PHOS_TM_Eta; - LOG(info) << "|\t TM |phi|: |phi| <= " << PHOS_TM_Phi << std::endl; - } - - void processRec(aod::EMEvents const&, aod::SkimEMCClusters const& emcclusters, aod::SkimEMCMTs const& matchedtracks, aod::PHOSClusters const& phosclusters) - { - for (const auto& emccluster : emcclusters) { // loop of EMC clusters - uint64_t EMC_CutBit = doPhotonCutsEMC(EMC_CutModeBit, emccluster, matchedtracks, perEMCClusterMT, EMCHistos); - tableEMCCuts(emccluster.globalIndex(), EMC_CutBit); - } // end loop of EMC clusters - - for (const auto& phoscluster : phosclusters) { // loop over PHOS clusters - PHOSHistos.fill(HIST("hClusterEIn"), phoscluster.e(), 0); - PHOSHistos.fill(HIST("hCaloCuts_PHOS"), 0); - - if (phoscluster.time() > PHOS_maxTime || phoscluster.time() < PHOS_minTime) { - PHOSHistos.fill(HIST("hCaloCuts_PHOS"), 1); - continue; - } - if (!(phoscluster.e() >= PHOS_minENCell && phoscluster.m02() > PHOS_minM02)) { - PHOSHistos.fill(HIST("hCaloCuts_PHOS"), 2); - continue; - } - if (phoscluster.e() <= PHOS_minE) { - PHOSHistos.fill(HIST("hCaloCuts_PHOS"), 3); - continue; - } - if (!(phoscluster.e() >= PHOS_minENCell && phoscluster.nCells() > PHOS_minNCell)) { - PHOSHistos.fill(HIST("hCaloCuts_PHOS"), 4); - continue; - } - - // TODO: add track matching for PHOS when available! - // track matching - bool hasMatchedTrack_PHOS = false; - // double dEta_PHOS, dPhi_PHOS; - // // only consider closest match - // dEta_PHOS = phoscluster.tracketa() - phoscluster.eta(); - // dPhi_PHOS = phoscluster.trackphi() - phoscluster.phi(); - // if ((fabs(dEta_PHOS) < PHOS_TM_Eta) && (fabs(dPhi_PHOS) < PHOS_TM_Phi)) { - // hasMatchedTrack_PHOS = true; - // if (PHOS_QA & 0b1) { - // EMCHistos.fill(HIST("clusterTM_dEtadPhi"), dEta_PHOS, dPhi_PHOS); - // } - // } - if (hasMatchedTrack_PHOS) { - PHOSHistos.fill(HIST("hCaloCuts_PHOS"), 5); - } else { - PHOSHistos.fill(HIST("hClusterEOut"), phoscluster.e(), 0); - PHOSHistos.fill(HIST("hCaloCuts_PHOS"), 6); - tableGammaReco(phoscluster.collisionId(), 2, - phoscluster.e(), phoscluster.eta(), phoscluster.phi(), 0, phoscluster.globalIndex()); - } - } // end loop of PHOS clusters - } - PROCESS_SWITCH(gammaSelection, processRec, "process only reconstructed info", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; - return workflow; -} diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index 6684618483a..f84f260bc46 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2023 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. // @@ -9,44 +9,60 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// ======================== -// \file photonconversionbuilder.cxx -// \brief this task produces photon data table with KFParticle. -// -// \author Daiki Sekihata , Tokyo -#include -#include -#include -#include -#include -#include +/// \file photonconversionbuilder.cxx +/// \brief this task produces photon data table with KFParticle. +/// \author Daiki Sekihata , Tokyo -#include "Math/Vector4D.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGEM/PhotonMeson/Utils/TrackSelection.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.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/TPCVDriftManager.h" #include "Common/Core/trackUtilities.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 "Common/Core/TableHelper.h" -#include "EventFiltering/Zorro.h" - +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Tools/KFparticle/KFUtilities.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" -#include "PWGEM/PhotonMeson/Utils/TrackSelection.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // IWYU pragma: keep +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::soa; @@ -56,15 +72,27 @@ using namespace o2::constants::physics; using namespace o2::pwgem::photonmeson; using std::array; -using MyCollisions = Join; +using MyCollisions = soa::Join; +using MyCollisionsWithSWT = soa::Join; using MyCollisionsMC = soa::Join; -using MyTracksIU = soa::Join; -using MyTracksIUMC = soa::Join; +using MyTracksIU = soa::Join; +using MyTracksIUMC = soa::Join; + +enum MatCorrType { + None = 0, + TGeo = 1, + LUT = 2 +}; struct PhotonConversionBuilder { Produces v0photonskf; Produces v0legs; + Produces v0legsXYZ; + Produces v0legsDeDxMC; + Produces v0photonsphiv; + // Produces v0photonskfcov; + // Produces events_ngpcm; // CCDB options Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -73,28 +101,27 @@ struct PhotonConversionBuilder { 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 inherit_from_emevent_dilepton{"inherit_from_emevent_dilepton", false, "flag to inherit task options from emevent-dilepton"}; - Configurable inherit_from_emevent_photon{"inherit_from_emevent_photon", false, "flag to inherit task options from emevent-photon"}; - Configurable enable_swt{"enable_swt", false, "flag to process skimmed data (swt triggered)"}; - Configurable cfg_swt_names{"cfg_swt_names", "", "comma-separated software trigger names"}; // Operation and minimisation criteria Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; // 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 requireITShit{"requireITShit", false, "require ITS hit to 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_at_sv{"min_pt_leg_at_sv", 0.0, "min pT for v0 legs at SV"}; // this is obsolete. - 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. @@ -106,6 +133,7 @@ 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"}; @@ -117,13 +145,12 @@ struct PhotonConversionBuilder { 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"}; - Zorro zorro; int mRunNumber; float d_bz; float maxSnp; // max sine phi for propagation @@ -131,6 +158,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", @@ -140,14 +168,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, o2::constants::math::TwoPI}, {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}}}}, @@ -156,15 +184,17 @@ struct PhotonConversionBuilder { {"V0/hRxy_minX_ITSTPC_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/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}}}}, + {"V0/hPhiV", "#phi_{V}; #phi_{V} (rad.)", {HistType::kTH1F, {{500, 0.0f, 2 * M_PI}}}}, {"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, o2::constants::math::TwoPI}, {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& initContext) + void init(InitContext&) { mRunNumber = 0; d_bz = 0; @@ -176,27 +206,23 @@ struct PhotonConversionBuilder { ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); - if (inherit_from_emevent_dilepton) { - getTaskOptionValue(initContext, "create-emevent-dilepton", "applyEveSel_at_skimming", applyEveSel_at_skimming.value, true); // for EM users. - getTaskOptionValue(initContext, "create-emevent-dilepton", "enable_swt", enable_swt.value, true); // for EM users. - getTaskOptionValue(initContext, "create-emevent-dilepton", "cfg_swt_names", cfg_swt_names.value, true); // for EM users. - } - - if (useMatCorrType == 1) { + if (useMatCorrType == MatCorrType::TGeo) { LOGF(info, "TGeo correction requested, loading geometry"); if (!o2::base::GeometryManager::isGeometryLoaded()) { ccdb->get(geoPath); } } - if (useMatCorrType == 2) { + if (useMatCorrType == MatCorrType::LUT) { LOGF(info, "LUT correction requested, loading LUT"); lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); } - if (useMatCorrType == 1) + if (useMatCorrType == MatCorrType::TGeo) { matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - if (useMatCorrType == 2) + } + if (useMatCorrType == MatCorrType::LUT) { matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + } } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -205,15 +231,11 @@ struct PhotonConversionBuilder { return; } - if (enable_swt) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfg_swt_names.value); - } - // 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) { + if (std::fabs(d_bz) > 1e-5) { grpmag.setL3Current(30000.f / (d_bz / 5.0f)); } o2::base::Propagator::initFieldFromGRP(&grpmag); @@ -222,18 +244,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); @@ -248,8 +271,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. @@ -262,6 +294,18 @@ struct PhotonConversionBuilder { } } + if (disableITSonlyTracks && isITSonlyTrack(track)) { + return false; + } + + if (disableTPConlyTracks && isTPConlyTrack(track)) { + return false; + } + + if (requireITShit && !track.hasITS()) { + return false; + } + if (track.x() > maxX) { return false; } @@ -281,6 +325,9 @@ struct PhotonConversionBuilder { if (track.tpcNClsCrossedRows() < mincrossedrows || track.tpcChi2NCl() > maxchi2tpc) { return false; } + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { return false; } @@ -298,21 +345,6 @@ struct PhotonConversionBuilder { 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) { - return false; - } - } } return true; @@ -326,10 +358,10 @@ struct PhotonConversionBuilder { float px = kfp.GetPx(); float py = kfp.GetPy(); float cospaXY = RecoDecay::dotProd(std::array{lx, ly}, std::array{px, py}) / (RecoDecay::sqrtSumOfSquares(lx, ly) * RecoDecay::sqrtSumOfSquares(px, py)); - if (cospaXY < -1.) { - return -1.; - } else if (cospaXY > 1.) { - return 1.; + if (cospaXY < -1.f) { + return -1.f; + } else if (cospaXY > 1.f) { + return 1.f; } return cospaXY; } @@ -345,33 +377,39 @@ struct PhotonConversionBuilder { float pz = kfp.GetPz(); float cospaRZ = RecoDecay::dotProd(std::array{lt, lz}, std::array{pt, pz}) / (RecoDecay::sqrtSumOfSquares(lt, lz) * RecoDecay::sqrtSumOfSquares(pt, pz)); - if (cospaRZ < -1.) { - return -1.; - } else if (cospaRZ > 1.) { - return 1.; + if (cospaRZ < -1.f) { + return -1.f; + } else if (cospaRZ > 1.f) { + return 1.f; } 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()); + track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap()); + + v0legsXYZ(shiftedtrack.getX(), shiftedtrack.getY(), shiftedtrack.getZ()); + + if constexpr (isMC) { + v0legsDeDxMC(track.mcTunedTPCSignal()); + } } - 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; @@ -388,6 +426,7 @@ struct PhotonConversionBuilder { if (isITSonlyTrack(pos) && !ele.hasITS()) { return; } + if (isITSonlyTrack(ele) && !pos.hasITS()) { return; } @@ -395,41 +434,57 @@ 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; + std::array dcaInfo; auto pTrack = getTrackParCov(pos); - pTrack.setPID(o2::track::PID::Electron); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrack, 2.f, matCorr, &dcaInfo); + 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 = getTrackParCov(ele); - nTrack.setPID(o2::track::PID::Electron); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrack, 2.f, matCorr, &dcaInfo); + 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); - KFParticle kfp_pos(kfp_track_pos, -11); - KFParticle kfp_ele(kfp_track_ele, 11); + 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, kPositron); + KFParticle kfp_ele(kfp_track_ele, kElectron); const KFParticle* GammaDaughters[2] = {&kfp_pos, &kfp_ele}; KFParticle gammaKF; @@ -460,39 +515,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 @@ -514,7 +569,7 @@ struct PhotonConversionBuilder { gammaKF_PV.SetProductionVertex(KFPV); float v0pt = RecoDecay::sqrtSumOfSquares(gammaKF_PV.GetPx(), gammaKF_PV.GetPy()); float v0eta = RecoDecay::eta(std::array{gammaKF_PV.GetPx(), gammaKF_PV.GetPy(), gammaKF_PV.GetPz()}); - float v0phi = RecoDecay::phi(gammaKF_PV.GetPx(), gammaKF_PV.GetPy()) > 0.f ? RecoDecay::phi(gammaKF_PV.GetPx(), gammaKF_PV.GetPy()) : RecoDecay::phi(gammaKF_PV.GetPx(), gammaKF_PV.GetPy()) + TMath::TwoPi(); + float v0phi = RecoDecay::constrainAngle(RecoDecay::phi(gammaKF_PV.GetPx(), gammaKF_PV.GetPy())); // KFParticle gammaKF_DecayVtx2 = gammaKF; // gammaKF_DecayVtx2.SetProductionVertex(KFPV); @@ -523,7 +578,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; } @@ -561,9 +616,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_at_sv || ele_pt < min_pt_leg_at_sv) { - return; - } if (isITSonlyTrack(pos) && pos_pt > maxpt_itsonly) { return; @@ -573,6 +625,11 @@ struct PhotonConversionBuilder { return; } + float chi2kf = gammaKF_DecayVtx.GetChi2() / gammaKF_DecayVtx.GetNDF(); + if (chi2kf > 6e+3) { // protection for uint16. + return; + } + // calculate DCAxy,z to PV float v0mom = RecoDecay::sqrtSumOfSquares(gammaKF_DecayVtx.GetPx(), gammaKF_DecayVtx.GetPy(), gammaKF_DecayVtx.GetPz()); float length = RecoDecay::sqrtSumOfSquares(gammaKF_DecayVtx.GetX() - collision.posX(), gammaKF_DecayVtx.GetY() - collision.posY(), gammaKF_DecayVtx.GetZ() - collision.posZ()); @@ -581,7 +638,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; } @@ -593,6 +650,8 @@ struct PhotonConversionBuilder { pca_map[std::make_tuple(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex())] = pca_kf; cospa_map[std::make_tuple(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex())] = cospa_kf; + 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 (filltable) { registry.fill(HIST("V0/hAP"), alpha, qt); registry.fill(HIST("V0/hConversionPointXY"), gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY()); @@ -605,7 +664,8 @@ 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 + registry.fill(HIST("V0/hPhiV"), phiv); float cospaXY_kf = cospaXY_KF(gammaKF_DecayVtx, KFPV); float cospaRZ_kf = cospaRZ_KF(gammaKF_DecayVtx, KFPV); @@ -613,19 +673,20 @@ struct PhotonConversionBuilder { registry.fill(HIST("V0/hCosPAXY_Rxy"), rxy, cospaXY_kf); registry.fill(HIST("V0/hCosPARZ_Rxy"), rxy, cospaRZ_kf); - float chi2kf = gammaKF_DecayVtx.GetChi2() / gammaKF_DecayVtx.GetNDF(); - - for (auto& leg : {kfp_pos_DecayVtx, kfp_ele_DecayVtx}) { + for (const auto& leg : {kfp_pos_DecayVtx, kfp_ele_DecayVtx}) { float legpt = RecoDecay::sqrtSumOfSquares(leg.GetPx(), leg.GetPy()); float legeta = RecoDecay::eta(std::array{leg.GetPx(), leg.GetPy(), leg.GetPz()}); - float legphi = RecoDecay::phi(leg.GetPx(), leg.GetPy()) > 0.f ? RecoDecay::phi(leg.GetPx(), leg.GetPy()) : RecoDecay::phi(leg.GetPx(), leg.GetPy()) + TMath::TwoPi(); + float legphi = RecoDecay::constrainAngle(RecoDecay::phi(leg.GetPx(), leg.GetPy())); registry.fill(HIST("V0Leg/hPt"), legpt); registry.fill(HIST("V0Leg/hEtaPhi"), legphi, legeta); } // end of leg loop - for (auto& leg : {pos, ele}) { + for (const auto& leg : {pos, ele}) { registry.fill(HIST("V0Leg/hdEdx_Pin"), leg.tpcInnerParam(), leg.tpcSignal()); registry.fill(HIST("V0Leg/hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); - registry.fill(HIST("V0Leg/hXZ"), leg.z(), leg.x()); + } // end of leg loop + for (const 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); @@ -635,52 +696,66 @@ 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); + v0photonsphiv(phiv); + + // 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 foundBC_as(); - initCCDB(bc); - registry.fill(HIST("hCollisionCounter"), 1); - - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { continue; } - if (enable_swt && !zorro.isSelected(bc.globalBC())) { - continue; + + if constexpr (isTriggerAnalysis) { + if (collision.swtaliastmp_raw() == 0) { + continue; + } } - auto v0s_per_coll = v0s.sliceBy(perCollision, collision.globalIndex()); + nv0_map[collision.globalIndex()] = 0; + + const auto& bc = collision.template foundBC_as(); + initCCDB(bc); + registry.fill(HIST("hCollisionCounter"), 1); + + 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) { @@ -720,20 +795,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 (const 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 (const 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. @@ -742,15 +852,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/produceMesonCalo.cxx b/PWGEM/PhotonMeson/TableProducer/produceMesonCalo.cxx deleted file mode 100644 index 7fd19416d3d..00000000000 --- a/PWGEM/PhotonMeson/TableProducer/produceMesonCalo.cxx +++ /dev/null @@ -1,151 +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 perform calo photon analysis on calo photons from skimmergammacalo task -/// dependencies: skimmergammacalo -/// \author marvin.hemmer@cern.ch - -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/DataModel/mesonTables.h" - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -// includes for the R recalculation -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsBase/GeometryManager.h" -#include "CCDB/BasicCCDBManager.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct produceMesonCalo { - - Produces tableCaloMeson; - - HistogramRegistry spectra = { - "spectra", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - // Configurable for histograms - Configurable nBinsMinv{"nBinsMinv", 800, "N bins for minv axis"}; - Configurable minMinv{"minMinv", 0.0, "Minimum value for minv axis"}; - Configurable maxMinv{"maxMinv", 0.8, "Maximum value for minv axis"}; - Configurable nBinsPt{"nBinsPt", 180, "N bins for pT axis"}; - Configurable minPt{"minPt", 0., "Minimum value for pT axis"}; - Configurable maxPt{"maxPt", 60., "Maximum value for pT axis"}; - - void init(o2::framework::InitContext&) - { - std::vector ptBinning(nBinsPt, 0); - - for (int i = 0; i < nBinsPt; i++) { - if (i < 100) { - ptBinning.at(i) = 0.10 * i; - } else if (i < 140) { - ptBinning.at(i) = 10. + 0.25 * (i - 100); - } else if (i < 180) { - ptBinning.at(i) = 20. + 1.00 * (i - 140); - } else { - ptBinning.at(i) = maxPt; - } - } - - AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec minvAxis = {nBinsMinv, minMinv, maxMinv, - "#it{m}_{inv} (GeV/#it{c}^{2})"}; - AxisSpec etaAxis = {100, -0.8, 0.8, "#eta"}; - AxisSpec phiAxis = {360, 0, 2 * M_PI, "#varphi (rad)"}; - AxisSpec alphaAxis = {200, -1, +1, "#alpha"}; - AxisSpec oaAxis = {180, 0, M_PI, "#vartheta_{#gamma#gamma} (rad)"}; - - HistogramConfigSpec defaultPtMinvHist( - {HistType::kTH2F, {minvAxis, ptAxis}}); - - HistogramConfigSpec defaultEtaPhiHist( - {HistType::kTH2F, {etaAxis, phiAxis}}); - - HistogramConfigSpec defaultPtMotherPtGammaHist( - {HistType::kTH2F, {ptAxis, ptAxis}}); - - HistogramConfigSpec defaultPtAlpha( - {HistType::kTH2F, {ptAxis, alphaAxis}}); - - HistogramConfigSpec defaultPtOA( - {HistType::kTH2F, {ptAxis, oaAxis}}); - - spectra.add("SameEvent_Minv_Pt", "SameEvent_Minv_Pt", defaultPtMinvHist, true); - spectra.add("SameEvent_Eta_Phi", "SameEvent_Eta_Phi", defaultEtaPhiHist, true); - spectra.add("SameEvent_Pt_Alpha", "SameEvent_Pt_Alpha", defaultPtAlpha, true); - spectra.add("SameEvent_Pt_OA", "SameEvent_Pt_OA", defaultPtOA, true); - spectra.add("SameEvent_PtMother_PtGamma", "SameEvent_PtMother_PtGamma", defaultPtMotherPtGammaHist, true); - - spectra.add("Photon_Eta_Phi", "Photon_Eta_Phi", defaultEtaPhiHist, true); - } - - void - processRec(aod::Collision const&, - aod::SkimGammas const& skimgammas) - { - for (auto& [gamma0, gamma1] : // EMC-EMC - combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(skimgammas, - skimgammas))) { - float openingAngle = acos((cos(gamma0.phi() - gamma1.phi()) + - sinh(gamma0.eta()) * sinh(gamma1.eta())) / - (cosh(gamma0.eta()) * cosh(gamma1.eta()))); - float E = gamma0.e() + gamma1.e(); - float pt0 = gamma0.e() / cosh(gamma0.eta()); - float pt1 = gamma1.e() / cosh(gamma1.eta()); - float px = - pt0 * cos(gamma0.phi()) + pt1 * cos(gamma1.phi()); - float py = - pt0 * sin(gamma0.phi()) + pt1 * sin(gamma1.phi()); - float pz = - pt0 * sinh(gamma0.eta()) + pt1 * sinh(gamma1.eta()); - float alpha = (gamma0.e() - gamma1.e()) != 0. - ? (gamma0.e() - gamma1.e()) / (gamma0.e() + gamma1.e()) - : 0.; - float Pt = sqrt(pt0 * pt0 + pt1 * pt1 + - 2. * pt0 * pt1 * - cos(gamma0.phi() - gamma1.phi())); - float minv = - sqrt(2. * gamma0.e() * gamma1.e() * (1. - cos(openingAngle))); - float eta = asinh(pz / Pt); - float phi = atan2(py, px); - phi = (phi < 0) ? phi + 2. * M_PI : phi; - tableCaloMeson(gamma0.collisionId(), gamma0.globalIndex(), gamma1.globalIndex(), - openingAngle, px, py, pz, E, alpha, minv, eta, phi, - Pt); - spectra.get(HIST("SameEvent_Minv_Pt"))->Fill(minv, Pt); - spectra.get(HIST("SameEvent_Eta_Phi"))->Fill(eta, phi); - spectra.get(HIST("SameEvent_Pt_Alpha"))->Fill(Pt, alpha); - spectra.get(HIST("SameEvent_Pt_OA"))->Fill(Pt, openingAngle); - spectra.get(HIST("SameEvent_PtMother_PtGamma"))->Fill(Pt, pt0); - spectra.get(HIST("SameEvent_PtMother_PtGamma"))->Fill(Pt, pt1); - - spectra.get(HIST("Photon_Eta_Phi"))->Fill(gamma0.eta(), gamma0.phi()); - spectra.get(HIST("Photon_Eta_Phi"))->Fill(gamma1.eta(), gamma1.phi()); - } - } - PROCESS_SWITCH(produceMesonCalo, processRec, - "process only reconstructed info", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; - return workflow; -} diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx index 5eb1bfeb069..c27bd6e64ab 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEE.cxx @@ -12,19 +12,24 @@ /// \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 "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" +#include +#include +#include +#include +#include +#include +#include +#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "CommonConstants/PhysicsConstants.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include // IWYU pragma: keep + +#include +#include +#include +#include using namespace o2; using namespace o2::soa; @@ -235,13 +240,13 @@ struct skimmerDalitzEE { if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { return false; } - if (applyPiRej_TPC && abs(track.tpcNSigmaPi()) < maxTPCNsigmaPi) { + if (applyPiRej_TPC && std::abs(track.tpcNSigmaPi()) < maxTPCNsigmaPi) { return false; } - if (applyKaRej_TPC && abs(track.tpcNSigmaKa()) < maxTPCNsigmaKa) { + if (applyKaRej_TPC && std::abs(track.tpcNSigmaKa()) < maxTPCNsigmaKa) { return false; } - if (applyPrRej_TPC && abs(track.tpcNSigmaPr()) < maxTPCNsigmaPr) { + if (applyPrRej_TPC && std::abs(track.tpcNSigmaPr()) < maxTPCNsigmaPr) { return false; } @@ -251,10 +256,10 @@ struct skimmerDalitzEE { template bool isElectron_TOFrequire(TTrack const& track) { - if (applyPiRej_TPC && abs(track.tpcNSigmaPi()) < maxTPCNsigmaPi) { + if (applyPiRej_TPC && std::abs(track.tpcNSigmaPi()) < maxTPCNsigmaPi) { return false; } - return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && abs(track.tofNSigmaEl()) < maxTOFNsigmaEl; + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::abs(track.tofNSigmaEl()) < maxTOFNsigmaEl; } template @@ -290,7 +295,7 @@ struct skimmerDalitzEE { fRegistry.fill(HIST("hNpairs"), static_cast(pairtype)); npair++; - } // end of pairing loop + } // end of pairing loop } else { // LS for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks1, tracks2))) { if (!checkTrack(t1) || !checkTrack(t2)) { diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx index b3d19edae96..b7cefc4045e 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx @@ -9,35 +9,49 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \brief skim cluster information to write photon cluster table in AO2D.root -/// dependencies: emcal-correction-task +/// \file skimmerGammaCalo.cxx +/// \brief skim cluster information to write photon cluster table into derived AO2D.root /// \author marvin.hemmer@cern.ch - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" - -// includes for the R recalculation -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "CCDB/BasicCCDBManager.h" +/// dependencies: emcal-correction-task #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h" +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" + +#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 skimmerGammaCalo { +struct SkimmerGammaCalo { - Preslice CellperCluster = o2::aod::emcalclustercell::emcalclusterId; - Preslice MTperCluster = o2::aod::emcalclustercell::emcalclusterId; + Preslice psCellperCluster = o2::aod::emcalclustercell::emcalclusterId; + Preslice psMTperCluster = o2::aod::emcalclustercell::emcalclusterId; + Preslice psMSperCluster = o2::aod::emcalclustercell::emcalclusterId; - Produces tableGammaEMCReco; + Produces tableGammaEMCReco; Produces tableEMCClusterMCLabels; Produces tableCellEMCReco; - Produces tableTrackEMCReco; // Configurable for filter/cuts Configurable minTime{"minTime", -200., "Minimum cluster time for time cut"}; @@ -45,102 +59,220 @@ struct skimmerGammaCalo { Configurable minM02{"minM02", 0.0, "Minimum M02 for M02 cut"}; Configurable maxM02{"maxM02", 1.0, "Maximum M02 for M02 cut"}; Configurable minE{"minE", 0.5, "Minimum energy for energy cut"}; - Configurable hasPropagatedTracks{"hasPropagatedTracks", false, "temporary flag, only set to true when running over data which has the tracks propagated to EMCal/PHOS!"}; + Configurable removeExotic{"removeExotic", false, "Flag to enable the removal of exotic clusters."}; + 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"}; + Configurable maxEoverP{"maxEoverP", 1.5, "Set a maximum for cluster E / track p for track matching."}; + Configurable maxdEtaSec{"maxdEtaSec", 0.1, "Set a maximum difference in eta for secondary tracks and cluster to still count as matched"}; + Configurable maxdPhiSec{"maxdPhiSec", 0.1, "Set a maximum difference in phi for secondary tracks and cluster to still count as matched"}; + Configurable needEMCTrigger{"needEMCTrigger", false, "flag to only save events which have kTVXinEMC trigger bit. To reduce PbPb derived data size"}; 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_clusterTM_dEtadPhi); - auto hCaloClusterFilter = historeg.add("hCaloClusterFilter", "hCaloClusterFilter", kTH1I, {{5, 0, 5}}); + 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", gHistoSpecClusterE); + historeg.add("EOut", "Energy of clusters after cuts", gHistoSpecClusterE); + historeg.add("MTEtaPhiBeforeTM", "Eta phi of matched tracks before TM cuts", gHistoSpecClusterTMdEtadPhi); + historeg.add("MTEtaPhiAfterTM", "Eta phi of matched tracks after TM cuts", gHistoSpecClusterTMdEtadPhi); + historeg.add("MSTEtaPhiBeforeTM", "Eta phi of matched secondary tracks before TM cuts", gHistoSpecClusterTMdEtadPhi); + historeg.add("MSTEtaPhiAfterTM", "Eta phi of matched secondary tracks after TM cuts", gHistoSpecClusterTMdEtadPhi); + historeg.add("Eoverp", "E/p for cluster E and track p", gHistoSpecTMEoverP); + 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, {{7, 0, 7}}); hCaloClusterFilter->GetXaxis()->SetBinLabel(1, "in"); - hCaloClusterFilter->GetXaxis()->SetBinLabel(2, "E cut"); - hCaloClusterFilter->GetXaxis()->SetBinLabel(3, "time cut"); - hCaloClusterFilter->GetXaxis()->SetBinLabel(4, "M02 cut"); - hCaloClusterFilter->GetXaxis()->SetBinLabel(5, "out"); - - LOG(info) << "| Timing cut: " << minTime << " < t < " << maxTime << std::endl; - LOG(info) << "| M02 cut: " << minM02 << " < M02 < " << maxM02 << std::endl; - LOG(info) << "| E cut: E > " << minE << 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, "exotic cut"); + hCaloClusterFilter->GetXaxis()->SetBinLabel(7, "out"); + + auto hCaloTrackFilter = historeg.add("hCaloTrackFilter", "hCaloTrackFilter", kTH1I, {{4, 0, 4}}); + hCaloTrackFilter->GetXaxis()->SetBinLabel(1, "in"); + hCaloTrackFilter->GetXaxis()->SetBinLabel(2, "#Delta#eta #Delta#varphi"); + hCaloTrackFilter->GetXaxis()->SetBinLabel(3, "E/p cut"); + hCaloTrackFilter->GetXaxis()->SetBinLabel(4, "out"); + + auto hCaloSecondaryTrackFilter = historeg.add("hCaloSecondaryTrackFilter", "hCaloSecondaryTrackFilter", kTH1I, {{4, 0, 4}}); + hCaloSecondaryTrackFilter->GetXaxis()->SetBinLabel(1, "in"); + hCaloSecondaryTrackFilter->GetXaxis()->SetBinLabel(2, "#Delta#eta #Delta#varphi"); + hCaloSecondaryTrackFilter->GetXaxis()->SetBinLabel(3, "E/p cut"); + hCaloSecondaryTrackFilter->GetXaxis()->SetBinLabel(4, "out"); + + LOG(info) << "| EMCal cluster cuts for skimming:"; + LOG(info) << "| Timing cut: " << minTime << " < t < " << maxTime; + LOG(info) << "| M02 cut: " << minM02 << " < M02 < " << maxM02; + LOG(info) << "| E cut: E > " << minE; + LOG(info) << "| TM - dPhi cut: dPhi < " << maxdPhi; + LOG(info) << "| TM - dEta cut: dEta < " << maxdEta; + LOG(info) << "| TM - E/p cut: E/p < " << maxEoverP; } - void processRec(aod::Collision const&, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const&) + template + static constexpr bool HasSecondaries = !std::is_same_v; + + template + void runAnalysis(TCollision const& collision, TClusters const& emcclusters, TClusterCells const& emcclustercells, TMatchedTracks const& emcmatchedtracks, TTracks const& /*tracks*/, TMatchedSecondaries const& secondaries = nullptr) { + const size_t NMaxMatchedTracks = 10; + // Skimmed matched tracks table + std::vector vEta; + std::vector vPhi; + std::vector vP; + std::vector vPt; + vEta.reserve(NMaxMatchedTracks); + vPhi.reserve(NMaxMatchedTracks); + vP.reserve(NMaxMatchedTracks); + vPt.reserve(NMaxMatchedTracks); + + std::vector vEtaSecondaries = {}; + std::vector vPhiSecondaries = {}; + std::vector vPSecondaries = {}; + std::vector vPtSecondaries = {}; + vEtaSecondaries.reserve(NMaxMatchedTracks); + vPhiSecondaries.reserve(NMaxMatchedTracks); + vPSecondaries.reserve(NMaxMatchedTracks); + vPtSecondaries.reserve(NMaxMatchedTracks); + + if (!collision.isSelected()) { + return; + } + if (needEMCTrigger.value && !collision.alias_bit(kTVXinEMC)) { + 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("M02In"), emccluster.m02()); + historeg.fill(HIST("TimeIn"), emccluster.time()); + historeg.fill(HIST("EIn"), emccluster.energy()); + + // Definition cut + if (!(std::find(clusterDefinitions.value.begin(), clusterDefinitions.value.end(), emccluster.definition()) != clusterDefinitions.value.end())) { + historeg.fill(HIST("hCaloClusterFilter"), 1); + continue; + } // Energy cut if (emccluster.energy() < minE) { - historeg.fill(HIST("hCaloClusterFilter"), 1); + historeg.fill(HIST("hCaloClusterFilter"), 2); continue; } // timing cut if (emccluster.time() > maxTime || emccluster.time() < minTime) { - historeg.fill(HIST("hCaloClusterFilter"), 2); + historeg.fill(HIST("hCaloClusterFilter"), 3); continue; } // M02 cut if (emccluster.nCells() > 1 && (emccluster.m02() > maxM02 || emccluster.m02() < minM02)) { - historeg.fill(HIST("hCaloClusterFilter"), 3); + historeg.fill(HIST("hCaloClusterFilter"), 4); continue; } + if (removeExotic.value && emccluster.isExotic()) { + historeg.fill(HIST("hCaloClusterFilter"), 5); + continue; + } + historeg.fill(HIST("hCaloClusterFilter"), 6); // Skimmed cell table - auto groupedCells = emcclustercells.sliceBy(CellperCluster, emccluster.globalIndex()); + auto groupedCells = emcclustercells.sliceBy(psCellperCluster, emccluster.globalIndex()); for (const auto& emcclustercell : groupedCells) { tableCellEMCReco(emcclustercell.emcalclusterId(), emcclustercell.caloId()); } - - // Skimmed matched tracks table - std::vector vTrackIds; - std::vector vEta; - std::vector vPhi; - std::vector vP; - std::vector vPt; - auto groupedMTs = emcmatchedtracks.sliceBy(MTperCluster, emccluster.globalIndex()); - vTrackIds.reserve(groupedMTs.size()); - vEta.reserve(groupedMTs.size()); - vPhi.reserve(groupedMTs.size()); - vP.reserve(groupedMTs.size()); - vPt.reserve(groupedMTs.size()); + auto groupedMTs = emcmatchedtracks.sliceBy(psMTperCluster, emccluster.globalIndex()); 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()); + historeg.fill(HIST("hCaloTrackFilter"), 0); + historeg.fill(HIST("MTEtaPhiBeforeTM"), emcmatchedtrack.deltaEta(), emcmatchedtrack.deltaPhi()); + if (std::abs(emcmatchedtrack.deltaEta()) >= maxdEta || std::abs(emcmatchedtrack.deltaPhi()) >= maxdPhi) { + historeg.fill(HIST("hCaloTrackFilter"), 1); + continue; + } + historeg.fill(HIST("Eoverp"), emccluster.energy(), emccluster.energy() / emcmatchedtrack.template track_as().p()); + if (emccluster.energy() / emcmatchedtrack.template track_as().p() > maxEoverP) { + historeg.fill(HIST("hCaloTrackFilter"), 2); + continue; + } + historeg.fill(HIST("hCaloTrackFilter"), 3); + historeg.fill(HIST("MTEtaPhiAfterTM"), emcmatchedtrack.deltaEta(), emcmatchedtrack.deltaPhi()); + vEta.emplace_back(emcmatchedtrack.deltaEta()); + vPhi.emplace_back(emcmatchedtrack.deltaPhi()); + vP.emplace_back(emcmatchedtrack.template track_as().p()); + vPt.emplace_back(emcmatchedtrack.template track_as().pt()); + } + + if constexpr (HasSecondaries) { + auto groupedMatchedSecondaries = secondaries.sliceBy(psMSperCluster, emccluster.globalIndex()); + for (const auto& emcMatchedSecondary : groupedMatchedSecondaries) { + historeg.fill(HIST("hCaloSecondaryTrackFilter"), 0); + historeg.fill(HIST("MSTEtaPhiBeforeTM"), emcMatchedSecondary.deltaEta(), emcMatchedSecondary.deltaPhi()); + if (std::abs(emcMatchedSecondary.deltaEta()) >= maxdEtaSec || std::abs(emcMatchedSecondary.deltaPhi()) >= maxdPhiSec) { + historeg.fill(HIST("hCaloSecondaryTrackFilter"), 1); + continue; + } + historeg.fill(HIST("hCaloSecondaryTrackFilter"), 3); + historeg.fill(HIST("MSTEtaPhiAfterTM"), emcMatchedSecondary.deltaEta(), emcMatchedSecondary.deltaPhi()); + vEtaSecondaries.emplace_back(emcMatchedSecondary.deltaEta()); + vPhiSecondaries.emplace_back(emcMatchedSecondary.deltaPhi()); + vPSecondaries.emplace_back(emcMatchedSecondary.template track_as().p()); + vPtSecondaries.emplace_back(emcMatchedSecondary.template track_as().pt()); } } - historeg.fill(HIST("hCaloClusterEOut"), emccluster.energy()); - historeg.fill(HIST("hCaloClusterFilter"), 4); + historeg.fill(HIST("DefinitionOut"), emccluster.definition()); + historeg.fill(HIST("EOut"), emccluster.energy()); + historeg.fill(HIST("M02Out"), emccluster.m02()); + historeg.fill(HIST("TimeOut"), emccluster.time()); - tableGammaEMCReco(emccluster.collisionId(), emccluster.energy(), emccluster.eta(), emccluster.phi(), emccluster.m02(), - emccluster.nCells(), emccluster.time(), emccluster.isExotic(), vEta, vPhi, vP, vPt); + tableGammaEMCReco(emccluster.collisionId(), emccluster.definition(), emccluster.energy(), emccluster.eta(), emccluster.phi(), emccluster.m02(), + emccluster.nCells(), emccluster.time(), emccluster.isExotic(), vPhi, vEta, vP, vPt, vPhiSecondaries, vEtaSecondaries, vPSecondaries, vPtSecondaries); + vEta.clear(); + vPhi.clear(); + vP.clear(); + vPt.clear(); + vPhiSecondaries.clear(); + vEtaSecondaries.clear(); + vPSecondaries.clear(); + vPtSecondaries.clear(); } } - void processMC(aod::Collision const&, soa::Join const& emcclusters, aod::McParticles const&) + + void processRec(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks) + { + runAnalysis(collision, emcclusters, emcclustercells, emcmatchedtracks, tracks); + } + PROCESS_SWITCH(SkimmerGammaCalo, processRec, "process only reconstructed info", true); + + void processRecWithSecondaries(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks, aod::EMCMatchSecs const& emcmatchedsecondaries) + { + runAnalysis(collision, emcclusters, emcclustercells, emcmatchedtracks, tracks, emcmatchedsecondaries); + } + PROCESS_SWITCH(SkimmerGammaCalo, processRecWithSecondaries, "process reconstructed info with secondary track matching.", false); + + void processMC(soa::Join::iterator const& collision, soa::Join const& emcclusters, aod::McParticles const&) { + if (!collision.isSelected()) { + return; + } + + if (needEMCTrigger.value && !collision.alias_bit(kTVXinEMC)) { + 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; @@ -165,18 +297,17 @@ struct skimmerGammaCalo { mcLabels.clear(); } } - PROCESS_SWITCH(skimmerGammaCalo, processRec, "process only reconstructed info", true); - PROCESS_SWITCH(skimmerGammaCalo, processMC, "process MC info", false); // Run this in addition to processRec for MCs to copy the cluster mc labels from the EMCALMCClusters to the skimmed EMCClusterMCLabels table + PROCESS_SWITCH(SkimmerGammaCalo, processMC, "process MC info", false); // Run this in addition to processRec for MCs to copy the cluster mc labels from the EMCALMCClusters to the skimmed EMCClusterMCLabels table void processDummy(aod::Collision const&) { // do nothing } - PROCESS_SWITCH(skimmerGammaCalo, processDummy, "Dummy function", false); + PROCESS_SWITCH(SkimmerGammaCalo, processDummy, "Dummy function", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow{adaptAnalysisTask(cfgc, TaskName{"skimmer-gamma-calo"})}; + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx index 40334a036c0..0ebf6f374c8 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaConversion.cxx @@ -23,33 +23,37 @@ // 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" #include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h" #include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" // includes for the R recalculation -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" - -#include "DCAFitter/HelixHelper.h" -#include "ReconstructionDataFormats/TrackFwd.h" #include "Common/Core/trackUtilities.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" +#include "ReconstructionDataFormats/HelixHelper.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "ReconstructionDataFormats/TrackFwd.h" +#include "Math/Vector4D.h" #include #include -#include "Math/Vector4D.h" - -#include "Tools/KFparticle/KFUtilities.h" using namespace o2; using namespace o2::framework; @@ -181,11 +185,10 @@ 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(), - theTrack.x(), theTrack.y(), theTrack.z(), theTrack.tgl()); + theTrack.itsClusterSizes(), theTrack.itsChi2NCl(), theTrack.detectorMap()); } template @@ -304,11 +307,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 +345,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/skimmerPrimaryElectronFromDalitzEE.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx index a42f00e0374..cb3452dc177 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx @@ -12,22 +12,29 @@ /// \brief write relevant information about primary electrons. /// \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/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/TrackSelection.h" +#include "Common/Core/trackUtilities.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" + +#include +#include +#include +#include + using namespace o2; using namespace o2::soa; using namespace o2::framework; @@ -35,16 +42,21 @@ using namespace o2::framework::expressions; using namespace o2::constants::physics; using namespace o2::pwgem::photonmeson; -using MyTracks = soa::Join; +using MyCollisions = soa::Join; +using MyCollisionsWithSWT = soa::Join; + +using MyCollisionsMC = soa::Join; +using MyTracks = soa::Join; using MyTrack = MyTracks::iterator; -using MyTracksMC = soa::Join; +using MyTracksMC = soa::Join; using MyTrackMC = MyTracksMC::iterator; struct skimmerPrimaryElectronFromDalitzEE { - SliceCache cache; Preslice perCol = o2::aod::track::collisionId; + Preslice perCol_pcm = o2::aod::v0photonkf::collisionId; Produces emprimaryelectrons; + Produces emprimaryelectronsDeDxMC; // Configurables Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -53,28 +65,36 @@ struct skimmerPrimaryElectronFromDalitzEE { Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; // Operation and minimisation criteria - Configurable applyEveSel_at_skimming{"applyEveSel_at_skimming", false, "flag to apply minimal event selection at the skimming level"}; 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 minitsncls{"minitsncls", 4, "min. number of ITS clusters"}; + 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.8, "eta acceptance"}; - Configurable dca_xy_max{"dca_xy_max", 0.1, "max DCAxy in cm"}; - Configurable dca_z_max{"dca_z_max", 0.1, "max DCAz in cm"}; + Configurable maxchi2its{"maxchi2its", 36.0, "max. chi2/NclsITS"}; + Configurable minpt{"minpt", 0.05, "min pt for ITS-TPC 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", 2.5, "max. TPC n sigma for pion exclusion"}; - Configurable minTPCNsigmaPi{"minTPCNsigmaPi", -1e+10, "min. TPC n sigma for pion exclusion"}; - Configurable maxMee_lowPtee{"maxMee_lowPtee", 0.02, "max. mee to store dalitz ee pairs for recovery"}; - Configurable maxMee_highPtee{"maxMee_highPtee", 0.04, "max. mee to store dalitz ee pairs for recovery"}; + 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"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; + Configurable maxpt_itssa{"maxpt_itssa", 0.15, "max pt for ITSsa track"}; + Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; + Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; + Configurable intercept{"intercept", -0.0380, "intercept for m vs. phiv"}; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - - std::pair> itsRequirement = {1, {0, 1, 2}}; // any hits on 3 ITS ib layers. + static constexpr std::string_view dileptonSigns[3] = {"uls/", "lspp/", "lsmm/"}; int mRunNumber; float d_bz; @@ -83,6 +103,10 @@ struct skimmerPrimaryElectronFromDalitzEE { void init(InitContext&) { + if (doprocessRec && doprocessRec_SWT) { + LOGF(fatal, "Cannot enable doprocessRec and doprocessRec_SWT at the same time. Please choose one."); + } + mRunNumber = 0; d_bz = 0; @@ -92,23 +116,47 @@ struct skimmerPrimaryElectronFromDalitzEE { 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/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {20, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hRelDeltaPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", kTH2F, {{1000, 0, 10}, {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/hDCAxy_Pt", "DCA_{xy} vs. pT;p_{T} (GeV/c);DCA_{xy} (cm)", kTH2F, {{1000, 0, 10}, {200, -1, 1}}, false); - fRegistry.add("Track/hDCAz_Pt", "DCA_{z} vs. pT;p_{T} (GeV/c);DCA_{z} (cm)", kTH2F, {{1000, 0, 10}, {200, -1, 1}}, 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/hTPCdEdxMC", "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); + + // 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/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{400, 0, 40}}, false); fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); - fRegistry.add("Pair/hMeePtee_ULS", "mee vs. pTee for dalitz ee ULS;m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {100, 0, 10}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hMeanClusterSizeITSib", "mean cluster size ITSib;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hMeanClusterSizeITSob", "mean cluster size ITSob;p_{pv} (GeV/c); #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) @@ -121,7 +169,7 @@ struct skimmerPrimaryElectronFromDalitzEE { 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); @@ -161,43 +209,70 @@ struct skimmerPrimaryElectronFromDalitzEE { } } - if (track.tpcChi2NCl() > maxchi2tpc) { + if (!track.hasITS()) { return false; } - if (track.itsChi2NCl() > maxchi2its) { + if (track.itsChi2NCl() < 0.f || maxchi2its < track.itsChi2NCl()) { return false; } - if (!track.hasITS() || !track.hasTPC()) { + if (track.itsNCls() < min_ncluster_its) { return false; } - if (track.itsNCls() < minitsncls) { + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { return false; } - auto hits = std::count_if(itsRequirement.second.begin(), itsRequirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - if (hits < itsRequirement.first) { + if (!includeITSsa && (!track.hasITS() || !track.hasTPC())) { return false; } - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; + if (track.hasTPC()) { + if (track.tpcChi2NCl() < 0.f || maxchi2tpc < track.tpcChi2NCl()) { + 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.tpcNClsCrossedRows() < mincrossedrows) { + if (std::fabs(track.dcaXY()) > dca_xy_max || std::fabs(track.dcaZ()) > dca_z_max) { return false; } - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + 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 (abs(track.dcaXY()) > dca_xy_max || abs(track.dcaZ()) > dca_z_max) { + if (std::fabs(track.eta()) > maxeta) { return false; } - - if (track.pt() < minpt || abs(track.eta()) > maxeta) { + if ((track.hasITS() && track.hasTPC()) && track.pt() < minpt) { + return false; + } + if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && maxpt_itssa < track.pt()) { return false; } @@ -207,53 +282,126 @@ struct skimmerPrimaryElectronFromDalitzEE { template bool isElectron(TTrack const& track) { + if (includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) { + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + if (maxMeanITSClusterSize > static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))) { + return true; + } else { + return false; + } + } + 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 + 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.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), - track.tpcChi2NCl(), track.tpcInnerParam(), - track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), - track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap(), track.tgl()); - - 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/hDCAxy_Pt"), track.pt(), track.dcaXY()); - fRegistry.fill(HIST("Track/hDCAz_Pt"), track.pt(), 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/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); - fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); - fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); - - stored_trackIds.emplace_back(std::make_pair(collision.globalIndex(), track.globalIndex())); + 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.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap()); + + if constexpr (isMC) { + emprimaryelectronsDeDxMC(track.mcTunedTPCSignal()); + } + } + + template + void fillTrackHistograms(TTrack const& track) + { + float mcTunedTPCSignal = 0.f; + if constexpr (isMC) { + mcTunedTPCSignal = track.mcTunedTPCSignal(); + } + + 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/hTPCdEdxMC"), track.tpcInnerParam(), mcTunedTPCSignal); + 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 total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + int total_cluster_size_ib = 0, nl_ib = 0; + for (unsigned int layer = 0; layer < 3; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl_ib++; + } + total_cluster_size_ib += cluster_size_per_layer; } + + int total_cluster_size_ob = 0, nl_ob = 0; + for (unsigned int layer = 3; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl_ob++; + } + total_cluster_size_ob += cluster_size_per_layer; + } + 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/hMeanClusterSizeITSib"), track.p(), static_cast(total_cluster_size_ib) / static_cast(nl_ib) * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hMeanClusterSizeITSob"), track.p(), static_cast(total_cluster_size_ob) / static_cast(nl_ob) * std::cos(std::atan(track.tgl()))); } - template + template void fillPairInfo(TCollision const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) { - for (auto& t1 : tracks1) { - for (auto& t2 : tracks2) { + if constexpr (pairtype == 0) { // ULS + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { continue; } @@ -264,77 +412,212 @@ struct skimmerPrimaryElectronFromDalitzEE { 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; + } + + if (v12.M() < slope * phiv + intercept) { + continue; + } + + if (t1.sign() > 0) { // for positron + if (std::find(acceptedPosTrackIds_per_collision.begin(), acceptedPosTrackIds_per_collision.end(), t1.globalIndex()) == acceptedPosTrackIds_per_collision.end()) { + fillTrackHistograms(t1); + acceptedPosTrackIds_per_collision.emplace_back(t1.globalIndex()); + } + } else { // for electron + if (std::find(acceptedNegTrackIds_per_collision.begin(), acceptedNegTrackIds_per_collision.end(), t1.globalIndex()) == acceptedNegTrackIds_per_collision.end()) { + fillTrackHistograms(t1); + acceptedNegTrackIds_per_collision.emplace_back(t1.globalIndex()); + } + } - if (v12.Pt() < 1.0) { // don't store - if (v12.M() > maxMee_lowPtee) { // don't store - continue; + if (t2.sign() > 0) { // for positron + if (std::find(acceptedPosTrackIds_per_collision.begin(), acceptedPosTrackIds_per_collision.end(), t2.globalIndex()) == acceptedPosTrackIds_per_collision.end()) { + fillTrackHistograms(t2); + acceptedPosTrackIds_per_collision.emplace_back(t2.globalIndex()); } - } else { - if (v12.M() > maxMee_highPtee) { // don't store - continue; + } else { // for electron + if (std::find(acceptedNegTrackIds_per_collision.begin(), acceptedNegTrackIds_per_collision.end(), t2.globalIndex()) == acceptedNegTrackIds_per_collision.end()) { + fillTrackHistograms(t2); + acceptedNegTrackIds_per_collision.emplace_back(t2.globalIndex()); } } - fRegistry.fill(HIST("Pair/hMeePtee_ULS"), v12.M(), v12.Pt()); - fillTrackTable(collision, t1); - fillTrackTable(collision, t2); - } // end of t2 - } // end of t1 + } // end of ULS 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 LS 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; - Filter pidFilter = minTPCNsigmaEl < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < maxTPCNsigmaEl; + std::vector acceptedPosTrackIds_per_collision; + std::vector acceptedNegTrackIds_per_collision; + std::vector> stored_trackIds; + Filter trackFilter = minpt < o2::aod::track::pt && nabs(o2::aod::track::eta) < maxeta && o2::aod::track::itsChi2NCl < maxchi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && nabs(o2::aod::track::dcaXY) < dca_xy_max && nabs(o2::aod::track::dcaZ) < dca_z_max; using MyFilteredTracks = soa::Filtered; Partition posTracks = o2::aod::track::signed1Pt > 0.f; Partition negTracks = o2::aod::track::signed1Pt < 0.f; // ---------- for data ---------- - void processRec(Join const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks) + void processRec(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks, aod::V0PhotonsKF const& v0photons) { stored_trackIds.reserve(tracks.size()); - for (auto& collision : collisions) { - auto bc = collision.bc_as(); + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); initCCDB(bc); - - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { 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); + const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); + + 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-- + } + + if ((v0photons_per_coll.size() >= 1 && acceptedPosTrackIds_per_collision.size() >= 1 && acceptedNegTrackIds_per_collision.size() >= 1) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { + // LOGF(info, "v0photons_per_coll.size() = %d, acceptedPosTrackIds_per_collision.size() = %d, acceptedNegTrackIds_per_collision.size() = %d", v0photons_per_coll.size(), acceptedPosTrackIds_per_collision.size(), acceptedNegTrackIds_per_collision.size()); + for (const auto& posId : acceptedPosTrackIds_per_collision) { + const auto& pos = tracks.rawIteratorAt(posId); + fillTrackTable(collision, pos); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + const auto& ele = tracks.rawIteratorAt(eleId); + fillTrackTable(collision, ele); + } + } - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - } // end of collision loop + acceptedPosTrackIds_per_collision.clear(); + acceptedPosTrackIds_per_collision.shrink_to_fit(); + acceptedNegTrackIds_per_collision.clear(); + acceptedNegTrackIds_per_collision.shrink_to_fit(); + } // end of collision loop stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); } PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec, "process reconstructed info only", true); // standalone + void processRec_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyFilteredTracks const& tracks, aod::V0PhotonsKF const& v0photons) + { + 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; + } + + const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); + + 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-- + } + + if ((v0photons_per_coll.size() >= 1 && acceptedPosTrackIds_per_collision.size() >= 1 && acceptedNegTrackIds_per_collision.size() >= 1) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { + // LOGF(info, "v0photons_per_coll.size() = %d, acceptedPosTrackIds_per_collision.size() = %d, acceptedNegTrackIds_per_collision.size() = %d", v0photons_per_coll.size(), acceptedPosTrackIds_per_collision.size(), acceptedNegTrackIds_per_collision.size()); + for (const auto& posId : acceptedPosTrackIds_per_collision) { + const auto& pos = tracks.rawIteratorAt(posId); + fillTrackTable(collision, pos); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + const auto& ele = tracks.rawIteratorAt(eleId); + fillTrackTable(collision, ele); + } + } + + acceptedPosTrackIds_per_collision.clear(); + acceptedPosTrackIds_per_collision.shrink_to_fit(); + acceptedNegTrackIds_per_collision.clear(); + acceptedNegTrackIds_per_collision.shrink_to_fit(); + } // end of collision loop + + stored_trackIds.clear(); + stored_trackIds.shrink_to_fit(); + } + PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec_SWT, "process reconstructed info with CEFP", false); // with cefp + using MyFilteredTracksMC = soa::Filtered; Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; // ---------- for MC ---------- - void processMC(soa::Join const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks) + void processMC(MyCollisionsMC const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyFilteredTracksMC const& tracks, aod::V0PhotonsKF const& v0photons) { stored_trackIds.reserve(tracks.size()); - for (auto& collision : collisions) { + for (const auto& collision : collisions) { + auto bc = collision.template foundBC_as(); + initCCDB(bc); if (!collision.has_mcCollision()) { continue; } - auto bc = collision.bc_as(); - initCCDB(bc); - if (applyEveSel_at_skimming && (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + if (!collision.isSelected()) { 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); + const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + const auto& posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - } // end of collision loop + 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-- + } + if ((v0photons_per_coll.size() >= 1 && acceptedPosTrackIds_per_collision.size() >= 1 && acceptedNegTrackIds_per_collision.size() >= 1) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { + // LOGF(info, "v0photons_per_coll.size() = %d, acceptedPosTrackIds_per_collision.size() = %d, acceptedNegTrackIds_per_collision.size() = %d", v0photons_per_coll.size(), acceptedPosTrackIds_per_collision.size(), acceptedNegTrackIds_per_collision.size()); + for (const auto& posId : acceptedPosTrackIds_per_collision) { + const auto& pos = tracks.rawIteratorAt(posId); + fillTrackTable(collision, pos); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + const auto& ele = tracks.rawIteratorAt(eleId); + fillTrackTable(collision, ele); + } + } + + acceptedPosTrackIds_per_collision.clear(); + acceptedPosTrackIds_per_collision.shrink_to_fit(); + acceptedNegTrackIds_per_collision.clear(); + acceptedNegTrackIds_per_collision.shrink_to_fit(); + } // end of collision loop stored_trackIds.clear(); stored_trackIds.shrink_to_fit(); @@ -342,34 +625,7 @@ struct skimmerPrimaryElectronFromDalitzEE { PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processMC, "process reconstructed and MC info ", false); }; -// 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& amp_ele : electrons_with_same_trackId) { -// if (amp_ele.globalIndex() == electron.globalIndex()) { // don't store myself. -// continue; -// } -// ambele_self_Ids.emplace_back(amp_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-from-dalitzee"}), - // adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-electron"}) - }; + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-electron-from-dalitzee"})}; } diff --git a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt index 187e3a1bc36..0f52d0ae9df 100644 --- a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Tasks/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(gammaconversions SOURCES gammaConversions.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore @@ -19,11 +21,21 @@ o2physics_add_dpl_workflow(gammaconversionstruthonlymc PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(emc-pi0-qc - SOURCES emcalPi0QC.cxx +o2physics_add_dpl_workflow(emcal-pi0-qc + SOURCES emcalPi0Qc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(emc-bc-wise-gammagamma + SOURCES emcalBcWiseGammaGamma.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(mc-generator-studies + SOURCES mcGeneratorStudies.cxx + PUBLIC_LINK_LIBRARIES O2::Framework 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 @@ -49,6 +61,16 @@ 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(omega-meson-emc + SOURCES OmegaMesonEMC.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 @@ -94,16 +116,6 @@ o2physics_add_dpl_workflow(pi0eta-to-gammagamma-mc-emcemc PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(tagging-pi0 - SOURCES TaggingPi0.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore - 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::MLCore - 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 O2Physics::MLCore @@ -124,3 +136,43 @@ 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) + +o2physics_add_dpl_workflow(diphoton-hadron-mpc-pcmpcm + SOURCES diphotonHadronMPCPCMPCM.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + + +o2physics_add_dpl_workflow(compconvbuilder + SOURCES compconvbuilder.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(diphoton-hadron-mpc-pcmdalitzee + SOURCES diphotonHadronMPCPCMDalitzEE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(calib-task-emc + SOURCES calibTaskEmc.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::EMCALBase O2::EMCALCalib O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/Tasks/CheckMCV0.cxx b/PWGEM/PhotonMeson/Tasks/CheckMCV0.cxx index 912e2ffc07a..5002de0a133 100644 --- a/PWGEM/PhotonMeson/Tasks/CheckMCV0.cxx +++ b/PWGEM/PhotonMeson/Tasks/CheckMCV0.cxx @@ -9,27 +9,34 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file CheckMCV0.cxx /// \brief check the v0 phase-space -/// \dependencies: o2-analysis-lf-lambdakzeromcfinder /// \author daiki.sekihata@cern.ch felix.schlepper@cern.ch +/// \dependencies: o2-analysis-lf-lambdakzeromcfinder -#include "TDatabasePDG.h" -#include "TMath.h" - -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" -#include "ReconstructionDataFormats/Track.h" -#include "DetectorsBase/Propagator.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGEM/PhotonMeson/DataModel/mcV0Tables.h" #include "PWGEM/PhotonMeson/Utils/TrackSelection.h" +// #include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGEM/PhotonMeson/DataModel/mcV0Tables.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" -#include "CommonConstants/LHCConstants.h" + +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; @@ -343,7 +350,7 @@ struct CheckMCV0 { return; } } else if constexpr (idxCut == 2) { - if (!(abs(pos.z()) > 38.f && abs(pos.z()) < 46.f) && !(abs(ele.z()) > 38.f && abs(ele.z()) < 46.f)) { + if (!(std::abs(pos.z()) > 38.f && std::abs(pos.z()) < 46.f) && !(std::abs(ele.z()) > 38.f && std::abs(ele.z()) < 46.f)) { return; } } @@ -419,15 +426,15 @@ struct CheckMCV0 { registry.fill(HIST("CheckV0Leg"), checkV0legEnum::PTMAX); return false; } - if (abs(track.eta()) > maxeta) { + if (std::abs(track.eta()) > maxeta) { registry.fill(HIST("CheckV0Leg"), checkV0legEnum::MAXETA); return false; } - if (abs(track.dcaXY()) < dcamin) { + if (std::abs(track.dcaXY()) < dcamin) { registry.fill(HIST("CheckV0Leg"), checkV0legEnum::DCAMIN); return false; } - if (abs(track.dcaXY()) > dcamax) { + if (std::abs(track.dcaXY()) > dcamax) { registry.fill(HIST("CheckV0Leg"), checkV0legEnum::DCAMAX); return false; } diff --git a/PWGEM/PhotonMeson/Tasks/Converters/CMakeLists.txt b/PWGEM/PhotonMeson/Tasks/Converters/CMakeLists.txt new file mode 100644 index 00000000000..b7fcf739373 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Converters/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(pcm-converter1 + SOURCES pcmConverter1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(electron-from-dalitz-converter1 + SOURCES electronFromDalitzConverter1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(skim-emc-cluste-converter + SOURCES skimEmcClusterConverter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/Tasks/Converters/electronFromDalitzConverter1.cxx b/PWGEM/PhotonMeson/Tasks/Converters/electronFromDalitzConverter1.cxx new file mode 100644 index 00000000000..961f8b0dfe7 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Converters/electronFromDalitzConverter1.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. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct electronFromDalitzConverter1 { + Produces electron_001; + + void process(aod::EMPrimaryElectronsFromDalitz_000 const& tracks) + { + for (const auto& track : tracks) { + electron_001(track.collisionId(), + track.trackId(), + 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.itsClusterSizes(), + track.itsChi2NCl(), + track.tofChi2(), + track.detectorMap()); + + } // end of track loop + } // end of process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"electronFromDalitz-converter1"})}; +} diff --git a/PWGEM/PhotonMeson/Tasks/Converters/pcmConverter1.cxx b/PWGEM/PhotonMeson/Tasks/Converters/pcmConverter1.cxx new file mode 100644 index 00000000000..1607c30b94a --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Converters/pcmConverter1.cxx @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// ======================== +// +// This code runs loop over ULS ee pars for virtual photon QC. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct pcmConverter1 { + Produces v0photon_001; + Produces v0leg_001; + + void process(aod::V0PhotonsKF_000 const& v0s, aod::V0Legs_000 const& v0legs) + { + for (auto& v0 : v0s) { + v0photon_001( + v0.collisionId(), + v0.v0Id(), + v0.posTrackId(), + v0.negTrackId(), + v0.vx(), + v0.vy(), + v0.vz(), + v0.px(), + v0.py(), + v0.pz(), + v0.mGamma(), + v0.dcaXYtopv(), + v0.dcaZtopv(), + v0.cospa(), + v0.cospaXY(), + v0.cospaRZ(), + v0.pca(), + v0.alpha(), + v0.qtarm(), + v0.chiSquareNDF()); + } // end of v0 loop + + for (auto& v0leg : v0legs) { + v0leg_001( + v0leg.collisionId(), + v0leg.trackId(), + v0leg.sign(), + v0leg.px(), + v0leg.py(), + v0leg.pz(), + v0leg.dcaXY(), + v0leg.dcaZ(), + v0leg.tpcNClsFindable(), + v0leg.tpcNClsFindableMinusFound(), + v0leg.tpcNClsFindableMinusCrossedRows(), + v0leg.tpcNClsShared(), + v0leg.tpcChi2NCl(), + v0leg.tpcInnerParam(), + v0leg.tpcSignal(), + v0leg.tpcNSigmaEl(), + v0leg.tpcNSigmaPi(), + v0leg.itsClusterSizes(), + v0leg.itsChi2NCl(), + v0leg.detectorMap()); + } // end of v0leg loop + } // end of process +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"pcm-converter1"})}; +} diff --git a/PWGEM/PhotonMeson/Tasks/Converters/skimEmcClusterConverter.cxx b/PWGEM/PhotonMeson/Tasks/Converters/skimEmcClusterConverter.cxx new file mode 100644 index 00000000000..d1809162bbc --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/Converters/skimEmcClusterConverter.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. + +/// \file skimEmcClusterConverter.cxx +/// \brief Converter task to convert SkimEMCClusters +/// \author M. Hemmer, marvin.hemmer@cern.ch + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +void convertSpanToVector(std::vector& destData, const gsl::span& srcData) +{ + destData.reserve(srcData.size()); + std::copy(srcData.begin(), srcData.end(), destData.begin()); +} + +// Converts SkimEMCClusters_000 into SkimEMCClusters_001 +struct SkimEmcClusterConverter { + Produces tableGammaEMCReco001; + + void process(aod::SkimEMCClusters_000 const& emcClusters) + { + std::vector vDummy = {}; + std::vector vPhi, vEta, vPt, vP; + for (const auto& emcCluster : emcClusters) { + // using convertSpanToVector is just a temporal solution, since right now tables return gsl::span + // while filling a table needs std::span which can not be transformed. So going over std::vector + // as a middle point is the current solution + convertSpanToVector(vPhi, emcCluster.deltaPhi()); + convertSpanToVector(vEta, emcCluster.deltaEta()); + convertSpanToVector(vP, emcCluster.trackp()); + convertSpanToVector(vPt, emcCluster.trackpt()); + tableGammaEMCReco001(emcCluster.collisionId(), emcCluster.definition(), emcCluster.e(), emcCluster.eta(), emcCluster.phi(), emcCluster.m02(), emcCluster.nCells(), emcCluster.time(), emcCluster.isExotic(), vPhi, vEta, vP, vPt, vDummy, vDummy, vDummy, vDummy); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/HeavyNeutralMeson.cxx b/PWGEM/PhotonMeson/Tasks/HeavyNeutralMeson.cxx new file mode 100644 index 00000000000..4e345a26c02 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/HeavyNeutralMeson.cxx @@ -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. +/// +/// \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 "PWGEM/PhotonMeson/Utils/HNMUtilities.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.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/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" +#include "TMath.h" +#include "TRandom3.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include + +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 cfgMaxMultiplicity{"cfgMaxMultiplicity", 5000, "Maximum number of tracks in a collision (can be used to increase the S/B -> Very experimental)"}; + 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; + } + if (col.multNTracksPV() > cfgMaxMultiplicity) { + 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 b5c1a5d8fde..e648dfe8fca 100644 --- a/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx +++ b/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx @@ -8,33 +8,54 @@ // In applying this license CERN does 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 for studying material budget. -// Please write to: daiki.sekihata@cern.ch -#include -#include +/// \file MaterialBudget.cxx +/// \brief Task to analyse and calculate the material budget weights +/// \author S. Mrozinski, smrozins@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 "ReconstructionDataFormats/Track.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/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PairCut.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Core/PairCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TPCVDriftManager.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -43,366 +64,1231 @@ 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::mcutil; +using namespace o2::aod::pwgem::dilepton::utils; +using o2::constants::math::TwoPI; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; +using MyCollisionsMC = soa::Join; +using MyCollisionMC = MyCollisionsMC::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + using MyV0Photons = soa::Join; using MyV0Photon = MyV0Photons::iterator; +using MyPrimaryElectrons = soa::Filtered>; +using MyPrimaryElectron = MyPrimaryElectrons::iterator; + +using MyMCV0Legs = soa::Join; +using MyMCV0Leg = MyMCV0Legs::iterator; + +using MyTracks = soa::Join; struct MaterialBudget { Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; - Configurable cfgCentMax{"cfgCentMax", 999, "max. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; - Configurable fConfigTagCuts{"cfgTagCuts", "qc", "Comma separated list of V0 photon cuts for tag"}; - Configurable fConfigProbeCuts{"cfgProbeCuts", "qc,wwire_ib", "Comma separated list of V0 photon cuts for probe"}; - Configurable fConfigPairCuts{"cfgPairCuts", "nocut", "Comma separated list of pair cuts"}; - Configurable fDoMixing{"DoMixing", false, "do event mixing"}; + struct SimplePhoton { + float pt; + float eta; + float phi; + float vz; + float r; + }; + + static constexpr int MaxMixEvents = 5; + std::map, std::deque>> mixingPools; + + std::vector centBinEdges = {0, 10, 30, 50, 90, 200}; + std::vector zvtxBinEdges = {-10, -5, 0, 5, 10}; + + std::tuple getPoolBin(float cent, float zvtx) + { + int centbin = std::lower_bound(centBinEdges.begin(), centBinEdges.end(), cent) - centBinEdges.begin() - 1; + centbin = std::max(0, std::min(centbin, static_cast(centBinEdges.size()) - 2)); + + int zbin = std::lower_bound(zvtxBinEdges.begin(), zvtxBinEdges.end(), zvtx) - zvtxBinEdges.begin() - 1; + zbin = std::max(0, std::min(zbin, static_cast(zvtxBinEdges.size()) - 2)); + return {centbin, zbin}; + } + + HistogramRegistry registry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + static constexpr std::string_view ItsClsNames[] = { + "ITSCls0", "ITSCls1", "ITSCls2", "ITSCls3", + "ITSCls4", "ITSCls5", "ITSCls6", "ITSCls7"}; + + static constexpr std::string_view EventTypes[2] = {"before/", "after/"}; + + Configurable cfgPlotBremsstrahlung{"cfgPlotBremsstrahlung", false, "produce plots to study Bremsstrahlung"}; + Configurable cfgPlotResolution{"cfgPlotResolution", false, "produce plots to study resolution"}; + Configurable cfgPlotPurity{"cfgPlotPurity", false, "produce plots to study purity"}; + Configurable cfgPlotMBDetailed{"cfgPlotMBDetailed", false, "produce plots to study material distribution distribution"}; + Configurable cfgPlotMBGeneral{"cfgPlotMBGeneral", true, "produce plots to study material distribution"}; + Configurable cfgPlotMBCollisions{"cfgPlotMBCollisions", false, "produce plots to study material distribution if collision association is wrong"}; + + 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}, ""}; + const AxisSpec axisPt{binsPt, "#it{p}_{T} [GeV/c]"}; - Configurable fConfigEMEventCut{"cfgEMEventCut", "minbias", "em event cut"}; // only 1 event cut per wagon EMPhotonEventCut fEMEventCut; - static constexpr std::string_view event_types[2] = {"before", "after"}; + 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; - OutputObj fOutputEvent{"Event"}; - OutputObj fOutputV0{"V0"}; - OutputObj fOutputPair{"Pair"}; // 2-photon pair - THashList* fMainList = new THashList(); + DalitzEECut fDileptonCut; + struct : ConfigurableGroup { + std::string prefix = "dileptoncut_group"; + Configurable cfgMinMass{"cfgMinMass", 0.0, "min mass"}; + Configurable cfgMaxMass{"cfgMaxMass", 0.1, "max mass"}; + Configurable cfgApplyPhiv{"cfgApplyPhiv", true, "flag to apply phiv cut"}; + Configurable cfgRequireItsibAny{"cfgRequireItsibAny", false, "flag to require ITS ib any hits"}; + Configurable cfgRequireItsib1st{"cfgRequireItsib1st", true, "flag to require ITS ib 1st hit"}; + Configurable cfgPhivSlope{"cfgPhivSlope", 0.0185, "slope for m vs. phiv"}; + Configurable cfgPhivIntercept{"cfgPhivIntercept", -0.0280, "intercept for m vs. phiv"}; - std::vector fTagCuts; - std::vector fProbeCuts; - std::vector fPairCuts; + Configurable cfgMinPtTrack{"cfgMinPtTrack", 0.1, "min pT for single track"}; + Configurable cfgMaxEtaTrack{"cfgMaxEtaTrack", 0.8, "max eta for single track"}; + Configurable cfgMinnclusterTPC{"cfgMinnclusterTPC", 0, "min ncluster tpc"}; + Configurable cfgMinnclusterITS{"cfgMinnclusterITS", 5, "min ncluster its"}; + Configurable cfgMinncrossedrows{"cfgMinncrossedrows", 70, "min ncrossed rows"}; + Configurable cfgMaxchi2TPC{"cfgMaxchi2TPC", 4.0, "max chi2/NclsTPC"}; + Configurable cfgMaxchi2ITS{"cfgMaxchi2ITS", 36.0, "max chi2/NclsITS"}; + Configurable cfgMaxDCAxy{"cfgMaxDCAxy", 0.05, "max dca XY for single track in cm"}; + Configurable cfgMaxDCAz{"cfgMaxDCAz", 0.05, "max dca Z for single track in cm"}; + Configurable cfgMaxDCA3dsigmaTrack{"cfgMaxDCA3dsigmaTrack", 1.5, "max DCA 3D in sigma"}; + Configurable cfgMaxFracSharedClustersTPC{"cfgMaxFracSharedClustersTPC", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfgApplyCutsFromPrefilterDerived{"cfgApplyCutsFromPrefilterDerived", false, "flag to apply prefilter to electron"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfgMaxpttrackITSsa{"cfgMaxpttrackITSsa", 0.15, "max pt for ITSsa tracks"}; - std::vector fPairNames; - void init(InitContext& context) + Configurable cfgPIDscheme{"cfgPIDscheme", static_cast(DalitzEECut::PIDSchemes::kTOFif), "pid scheme [kTOFif : 0, kTPConly : 1]"}; + Configurable cfgMinTPCNsigmaEl{"cfgMinTPCNsigmaEl", -2.0, "min. TPC n sigma for electron inclusion"}; + Configurable cfgMaxTPCNsigmaEl{"cfgMaxTPCNsigmaEl", +3.0, "max. TPC n sigma for electron inclusion"}; + Configurable cfgMinTPCNsigmaPi{"cfgMinTPCNsigmaPi", -0.0, "min. TPC n sigma for pion exclusion"}; + Configurable cfgMaxTPCNsigmaPi{"cfgMaxTPCNsigmaPi", +0.0, "max. TPC n sigma for pion exclusion"}; + Configurable cfgMinTOFNsigmaEl{"cfgMinTOFNsigmaEl", -3.0, "min. TOF n sigma for electron inclusion"}; + Configurable cfgMaxTOFNsigmaEl{"cfgMaxTOFNsigmaEl", +3.0, "max. TOF n sigma for electron inclusion"}; + } dileptoncuts; + + V0PhotonCut fV0PhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcut_group"; + Configurable cfgRequireV0WithITSTPC{"cfgRequireV0WithITSTPC", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfgRequireV0WithITSOnly{"cfgRequireV0WithITSOnly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfgRequireV0WithTPCOnly{"cfgRequireV0WithTPCOnly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfgMinPtV0{"cfgMinPtV0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfgMaxPtV0{"cfgMaxPtV0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfgMinEtaV0{"cfgMinEtaV0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfgMaxEtaV0{"cfgMaxEtaV0", +0.8, "max eta for v0 photons at PV"}; + Configurable cfgMinV0Radius{"cfgMinV0Radius", 4.0, "min v0 radius"}; + Configurable cfgMaxV0Radius{"cfgMaxV0Radius", 90.0, "max v0 radius"}; + Configurable cfgMaxAlphaAp{"cfgMaxAlphaAp", 0.95, "max alpha for AP cut"}; + Configurable cfgMaxQtAp{"cfgMaxQtAp", 0.01, "max qT for AP cut"}; + Configurable cfgMinCospa{"cfgMinCospa", 0.999, "min V0 CosPA"}; + Configurable cfgMaxPca{"cfgMaxPca", 1.5, "max distance btween 2 legs"}; + Configurable cfgMaxChi2kf{"cfgMaxChi2kf", 1e+10, "max chi2/ndf with KF"}; + Configurable cfgRejectV0OnITSib{"cfgRejectV0OnITSib", true, "flag to reject V0s on ITSib"}; + Configurable cfgMinNclusterTPC{"cfgMinNclusterTPC", 0, "min ncluster tpc"}; + Configurable cfgMinNcrossedrows{"cfgMinNcrossedrows", 40, "min ncrossed rows"}; + Configurable cfgMaxFracSharedClustersTPC{"cfgMaxFracSharedClustersTPC", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfgMaxChi2TPC{"cfgMaxChi2TPC", 4.0, "max chi2/NclsTPC"}; + Configurable cfgMaxChi2ITS{"cfgMaxChi2ITS", 36.0, "max chi2/NclsITS"}; + Configurable cfgMinTPCNsigmaEl{"cfgMinTPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfgMaxTPCNsigmaEl{"cfgMaxTPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfgDisableITSonlytrack{"cfgDisableITSonlytrack", false, "flag to disable ITSonly tracks"}; + Configurable cfgDisableTPCOnlytrack{"cfgDisableTPCOnlytrack", false, "flag to disable TPConly tracks"}; + } pcmcuts; + + void init(InitContext&) { - if (context.mOptions.get("processMB")) { - fPairNames.push_back("PCMPCM"); - } - DefineTagCuts(); - DefineProbeCuts(); - DefinePairCuts(); + defineEMEventCut(); + defineDileptonCut(); + definePCMCut(); addhistograms(); - TString ev_cut_name = fConfigEMEventCut.value; - fEMEventCut = *eventcuts::GetCut(ev_cut_name.Data()); + } + + 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 defineDileptonCut() + { + fDileptonCut = DalitzEECut("fDileptonCut", "fDileptonCut"); + + // for pair + fDileptonCut.SetMeeRange(dileptoncuts.cfgMinMass, dileptoncuts.cfgMaxMass); + fDileptonCut.SetMaxPhivPairMeeDep([&](float mll) { return (mll - dileptoncuts.cfgPhivIntercept) / dileptoncuts.cfgPhivSlope; }); + fDileptonCut.ApplyPhiV(dileptoncuts.cfgApplyPhiv); + fDileptonCut.RequireITSibAny(dileptoncuts.cfgRequireItsibAny); + fDileptonCut.RequireITSib1st(dileptoncuts.cfgRequireItsib1st); - fOutputEvent.setObject(reinterpret_cast(fMainList->FindObject("Event"))); - fOutputV0.setObject(reinterpret_cast(fMainList->FindObject("V0"))); - fOutputPair.setObject(reinterpret_cast(fMainList->FindObject("Pair"))); + // for tracks + fDileptonCut.SetTrackPtRange(dileptoncuts.cfgMinPtTrack, 1e+10f); + fDileptonCut.SetTrackEtaRange(-dileptoncuts.cfgMaxEtaTrack, +dileptoncuts.cfgMaxEtaTrack); + fDileptonCut.SetMinNClustersTPC(dileptoncuts.cfgMinnclusterTPC); + fDileptonCut.SetMinNCrossedRowsTPC(dileptoncuts.cfgMinncrossedrows); + fDileptonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fDileptonCut.SetMaxFracSharedClustersTPC(dileptoncuts.cfgMaxFracSharedClustersTPC); + fDileptonCut.SetChi2PerClusterTPC(0.0, dileptoncuts.cfgMaxchi2TPC); + fDileptonCut.SetChi2PerClusterITS(0.0, dileptoncuts.cfgMaxchi2ITS); + fDileptonCut.SetNClustersITS(dileptoncuts.cfgMinnclusterITS, 7); + fDileptonCut.SetMaxDcaXY(dileptoncuts.cfgMaxDCAxy); + fDileptonCut.SetMaxDcaZ(dileptoncuts.cfgMaxDCAz); + fDileptonCut.SetTrackDca3DRange(0.f, dileptoncuts.cfgMaxDCA3dsigmaTrack); // in sigma + fDileptonCut.IncludeITSsa(dileptoncuts.includeITSsa, dileptoncuts.cfgMaxpttrackITSsa); + + // for eID + fDileptonCut.SetPIDScheme(dileptoncuts.cfgPIDscheme); + fDileptonCut.SetTPCNsigmaElRange(dileptoncuts.cfgMinTPCNsigmaEl, dileptoncuts.cfgMaxTPCNsigmaEl); + fDileptonCut.SetTPCNsigmaPiRange(dileptoncuts.cfgMinTPCNsigmaPi, dileptoncuts.cfgMaxTPCNsigmaPi); + fDileptonCut.SetTOFNsigmaElRange(dileptoncuts.cfgMinTOFNsigmaEl, dileptoncuts.cfgMaxTOFNsigmaEl); } - template - void add_pair_histograms(THashList* list_pair, const std::string pairname, TCuts1 const& tagcuts, TCuts2 const& probecuts, TCuts3 const& cuts3) + void definePCMCut() { - for (auto& cut1 : tagcuts) { - for (auto& cut2 : probecuts) { - std::string cutname1 = cut1.GetName(); - std::string cutname2 = cut2.GetName(); - - 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, "material_budget_study", "Pair"); - } // end of cut3 loop pair cut - } // end of cut2 loop - } // end of cut1 loop + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.cfgMinPtV0, pcmcuts.cfgMaxPtV0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.cfgMinEtaV0, pcmcuts.cfgMaxEtaV0); + fV0PhotonCut.SetMinCosPA(pcmcuts.cfgMinCospa); + fV0PhotonCut.SetMaxPCA(pcmcuts.cfgMaxPca); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfgMaxChi2kf); + fV0PhotonCut.SetRxyRange(pcmcuts.cfgMinV0Radius, pcmcuts.cfgMaxV0Radius); + fV0PhotonCut.SetAPRange(pcmcuts.cfgMaxAlphaAp, pcmcuts.cfgMaxQtAp); + fV0PhotonCut.RejectITSib(pcmcuts.cfgRejectV0OnITSib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfgMinNclusterTPC); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfgMinNcrossedrows); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfgMaxFracSharedClustersTPC); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfgMaxChi2TPC); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfgMinTPCNsigmaEl, pcmcuts.cfgMaxTPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfgMaxChi2ITS); + fV0PhotonCut.SetNClustersITS(0, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fV0PhotonCut.SetDisableITSonly(pcmcuts.cfgDisableITSonlytrack); + fV0PhotonCut.SetDisableTPConly(pcmcuts.cfgDisableTPCOnlytrack); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfgRequireV0WithITSTPC); + fV0PhotonCut.SetRequireITSonly(pcmcuts.cfgRequireV0WithITSOnly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.cfgRequireV0WithTPCOnly); } - 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")); + auto hCollisionCounter = registry.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"); + + registry.add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + registry.add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + registry.add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + registry.add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2F, {{300, 0, 6000}, {300, 0, 6000}}, false); + registry.add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); + registry.add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); + registry.add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + registry.add("Event/before/hCentFT0MvsMultNTracksPV", "hCentFT0MvsMultNTracksPV;centrality FT0M (%);N_{track} to PV", kTH2F, {{110, 0, 110}, {600, 0, 6000}}, false); + registry.add("Event/before/hMultFT0MvsMultNTracksPV", "hMultFT0MvsMultNTracksPV;mult. FT0M;N_{track} to PV", kTH2F, {{600, 0, 6000}, {600, 0, 6000}}, false); + registry.addClone("Event/before/", "Event/after/"); - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "Pair"); - THashList* list_pair = reinterpret_cast(fMainList->FindObject("Pair")); + if (cfgPlotMBGeneral) { - o2::aod::pwgem::photon::histogram::AddHistClass(fMainList, "V0"); - THashList* list_v0 = reinterpret_cast(fMainList->FindObject("V0")); + registry.add("MBGeneral", ";z_{conv} (cm); R_{conv} (cm); #eta; #varphi (rad); p_{T}", kTHnSparseF, + {{200, -100.f, 100.f}, + {100, 0.f, 100.f}, + {80, -2, +2}, + {90, 0, o2::constants::math::TwoPI}, + {1000, 0, 10}}, // pT 5 + true); - // for V0s - for (const auto& cut : fProbeCuts) { - const char* cutname = cut.GetName(); - THashList* list_v0_cut = o2::aod::pwgem::photon::histogram::AddHistClass(list_v0, cutname); - o2::aod::pwgem::photon::histogram::DefineHistograms(list_v0_cut, "material_budget_study", "V0"); + registry.add("Pi0/Same", + "Pi0; m_{#gamma#gamma}; #it{p}_{T}; R_{conv} (cm); R_{conv} (cm)", + kTHnSparseF, + {{400, 0.f, 0.3}, // x 0 + {500, 0, 10}, // pT 1 + {100, 0.f, 100.f}, // R of photon 1 + {100, 0.f, 100.f}}, + true); + + registry.add("Dalitz/Same", + "Dalitz; m_{eeγ}; p_{T}; R_{γ} (cm); R_{e+}; R_{e-}", + kTHnSparseF, + {{400, 0.f, 0.5f}, + {500, 0.f, 10.f}, + {100, 0.f, 100.f}}, + true); + + registry.add("Pi0/Mix", "Pi0 mixed-event;m_{#gamma#gamma};p_{T}", kTHnSparseF, + {{400, 0, 0.3}, {500, 0, 10}, {100, 0, 100}, {100, 0, 100}}, true); } - for (auto& pairname : fPairNames) { - LOGF(info, "Enabled pairs = %s", pairname.data()); + if (cfgPlotMBDetailed) { - 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()); - } + registry.add("MBStudiesWireLeft", + "photon characteristics for MB studies; x (cm); y (cm); z (cm); #varphi (rad.); R_{conv} (cm)", + kTHnSparseF, + { + {200, -20.f, 20.f}, // x 0 + {200, -20.f, 20.f}, // y 1 + {80, -20.f, 20.f}, // z 2 + {40, 3.15, 3.4}, // phi 3 + {80, 0.f, 20.f}, // conversion radius 4 + {1000, 0, 10} // pT 5 + }, + true); - o2::aod::pwgem::photon::histogram::AddHistClass(list_pair, pairname.data()); + registry.add("MBStudiesWireRight", + "photon characteristics for MB studies; x (cm); y (cm); z (cm); #varphi (rad.); R_{conv} (cm)", + kTHnSparseF, + { + {200, -20.f, 20.f}, // x 0 + {200, -20.f, 20.f}, // y 1 + {80, -20.f, 20.f}, // z 2 + {40, 6.00, 6.15}, // phi 3 + {80, 0.f, 20.f}, // conversion radius 4 + {1000, 0, 10} // pT 5 + }, + true); - if (pairname == "PCMPCM") { - add_pair_histograms(list_pair, pairname, fTagCuts, fProbeCuts, fPairCuts); + registry.add("MBStudiesWireITS", + "photon characteristics for MB studies; x (cm); y (cm); z (cm); #varphi (rad.); R_{conv} (cm)", + kTHnSparseF, + { + {160, -40.f, 40.f}, // x 0 + {160, -40.f, 40.f}, // y 1 + {80, -40.f, 40.f}, // z 2 + {90, 0, TwoPI}, // phi 3 + {150, 0.f, 60.f}, // conversion radius 4 + {1000, 0, 10} // pT 5 + }, + true); + + registry.add("MBStudiesMFT", + "photon characteristics for MB studies; x (cm); y (cm); z (cm); #varphi (rad.); R_{conv} (cm)", + kTHnSparseF, + { + {160, -80.f, 80.f}, // x 0 + {160, -80.f, 80.f}, // y 1 + {40, -40.f, 40.f}, // z 2 + {90, 0, TwoPI}, // phi 3 + {40, 40.f, 60.f}, // conversion radius 4 + {500, 0, 10} // pT 5 + }, + true); + + registry.add("MBStudiesTPC", + "photon characteristics for MB studies; x (cm); y (cm); z (cm); #varphi (rad.); R_{conv} (cm)", + kTHnSparseF, + { + {160, -90.f, 90.f}, // x 0 + {160, -90.f, 90.f}, // y 1 + {80, -40.f, 40.f}, // z 2 + {90, 0, TwoPI}, // phi 3 + {80, 60.f, 80.f}, // conversion radius 4 + {1000, 0, 10} // pT 5 + }, + true); + + for (int nCls = 0; nCls <= 7; nCls++) { // o2-linter: disable=magic-number (just numbers for ITS cluster) + registry.add(Form("ITSHits/Neg/ITSCls%d", nCls), + Form("Conversion radius NEG legs with %d ITS clusters;R_{conv} (cm);Entries", nCls), + HistType::kTH1F, + {AxisSpec{100, 0.f, 100.f}}); + + registry.add(Form("ITSHits/Pos/ITSCls%d", nCls), + Form("Conversion radius POS legs with %d ITS clusters;R_{conv} (cm);Entries", nCls), + HistType::kTH1F, + {AxisSpec{100, 0.f, 100.f}}); } + } + + if (cfgPlotResolution) { + + registry.add("ResolutionGen/Z_res", + "Z resolution (gen ref);z_gen (cm);R_gen (cm);phi_gen;eta_gen;pT_gen;Δz (cm)", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {120, -30, 30}}, false); + + registry.add("ResolutionGen/R_res", + "R resolution (gen ref);z_gen (cm);R_gen (cm);phi_gen;eta_gen;pT_gen;ΔR (cm)", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {120, -30, 30}}, false); + + registry.add("ResolutionGen/Phi_res", + "Phi resolution (gen ref);z_gen (cm);R_gen (cm);phi_gen;eta_gen;pT_gen;Δφ", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {100, -0.2f, 0.2f}}, false); + + registry.add("ResolutionGen/Pt_res", + "pT resolution (gen ref);z_gen (cm);R_gen (cm);phi_gen;eta_gen;pT_gen;ΔpT/pT_gen", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {200, -1.0f, 1.0f}}, false); + + registry.add("ResolutionGen/Eta_res", + "Eta resolution (gen ref);z_gen (cm);R_gen (cm);phi_gen;eta_gen;pT_gen;Δη", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {100, -0.5f, 0.5f}}, false); + + registry.add("ResolutionRec/Z_res", + "Z resolution (rec ref);z_rec (cm);R_rec (cm);phi_rec;eta_rec;pT_rec;Δz (cm)", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {120, -30, 30}}, false); + + registry.add("ResolutionRec/R_res", + "R resolution (rec ref);z_rec (cm);R_rec (cm);phi_rec;eta_rec;pT_rec;ΔR (cm)", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {120, -30, 30}}, false); + + registry.add("ResolutionRec/Phi_res", + "Phi resolution (rec ref);z_rec (cm);R_rec (cm);phi_rec;eta_rec;pT_rec;Δφ", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {100, -0.2f, 0.2f}}, false); + + registry.add("ResolutionRec/Pt_res", + "pT resolution (rec ref);z_rec (cm);R_rec (cm);phi_rec;eta_rec;pT_rec;ΔpT/pT_gen", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {200, -1.0f, 1.0f}}, false); + + registry.add("ResolutionRec/Eta_res", + "Eta resolution (rec ref);z_rec (cm);R_rec (cm);phi_rec;eta_rec;pT_rec;Δη", + kTHnSparseF, + {{200, -100, 100}, {200, 0, 100}, {90, 0, TwoPI}, {200, -1.0f, 1.0f}, {500, 0, 10}, {100, -0.5f, 0.5f}}, false); + } + + if (cfgPlotPurity) { + + registry.add("PhotonPurity", + "Photon purity classification;p_{T} (GeV/c);R_{conv} (cm);#eta;#varphi;category", + kTHnSparseF, + { + {500, 0, 10}, // pT + {200, 0, 100}, // R + {100, -1.0, 1.0}, // eta + {90, 0, o2::constants::math::TwoPI}, // phi + {12, 0.5, 12.5} // purity categories + }, + true); + + auto hPurity = registry.get(HIST("PhotonPurity")); + + auto axis = hPurity->GetAxis(4); + + axis->SetBinLabel(1, "e^{+}e^{-}"); + axis->SetBinLabel(2, "e^{-} + #pi^{+}"); + axis->SetBinLabel(3, "#pi^{-} + e^{+}"); + axis->SetBinLabel(4, "K^{-} + e^{+}"); + axis->SetBinLabel(5, "e^{-} + K^{+}"); + axis->SetBinLabel(6, "#bar{p} + p"); + axis->SetBinLabel(7, "K^{-} + K^{+}"); + axis->SetBinLabel(8, "#pi^{-} + p"); + axis->SetBinLabel(9, "#bar{p} + #pi^{+}"); + axis->SetBinLabel(10, "#mu^{-} + #mu^{+}"); + } + + if (cfgPlotBremsstrahlung) { + + registry.add("Bremsstrahlung/EnergyLossVsR", ";R (cm);E_{loss} (GeV)", + kTH2F, {{50, 0, 100}, {100, 0, 5}}); + registry.add("Bremsstrahlung/EnergyLossXY", ";X (cm);Y (cm)", + kTH2F, {{100, -100, 100}, {100, -100, 100}}); + registry.add("Bremsstrahlung/EnergyLossXYWeigh", ";X (cm);Y (cm)", + kTH2F, {{100, -100, 100}, {100, -100, 100}}); + registry.add("Bremsstrahlung/EnergyLossVsZ", ";Z (cm);E_{loss} (GeV)", + kTH2F, {{100, -100, 100}, {200, 0, 5}}); + + registry.add("Bremsstrahlung/NBrem", ";N_{Brem} per e^{-};Counts", + kTH1I, {{10, 0, 10}}); + + registry.add("Bremsstrahlung/DeltaPoverPvsR", ";R (cm);(p_{Reco}-p_{MC})/p_{MC}", + kTH2F, {{50, 0, 100}, {200, -1, 1}}); + registry.add("Bremsstrahlung/DeltaPtvsR", ";R (cm);(p_{T,Reco}-p_{T,MC})/p_{T,MC}", + kTH2F, {{50, 0, 100}, {300, -2, 2}}); + registry.add("Bremsstrahlung/DeltaPhivsR", ";R (cm);#Delta#varphi (rad)", + kTH2F, {{50, 0, 100}, {200, -0.1, 0.1}}); + registry.add("Bremsstrahlung/DeltaEtavsR", ";R (cm);#Delta#eta", + kTH2F, {{50, 0, 100}, {200, -0.1, 0.1}}); + + registry.add("Bremsstrahlung/Sigma1PtVsR", ";R (cm);#sigma(1/p_{T}) [c/GeV]", + kTH2F, {{50, 0, 100}, {100, 0, 0.1}}); - } // end of pair name loop + registry.add("Bremsstrahlung/SigmaYVsR", ";R (cm);#sigma(y) [cm]", + kTH2F, {{50, 0, 100}, {100, 0, 0.5}}); + registry.add("Bremsstrahlung/SigmaZVsR", ";R (cm);#sigma(z) [cm]", + kTH2F, {{50, 0, 100}, {100, 0, 1.0}}); + + registry.add("Bremsstrahlung/relativeResoPtWBrems", + "relative #it{p}_{T} resolution; #it{p}_{T}; #sigma(#it{p}_{T})/#it{p}_{T}", + kTProfile, + {axisPt}); + + registry.add("Bremsstrahlung/relativeResoPtWOBrems", + "relative #it{p}_{T} resolution; #it{p}_{T}; #sigma(#it{p}_{T})/#it{p}_{T}", + kTProfile, + {axisPt}); + } + + if (cfgPlotMBCollisions) { + + registry.add("RightCollisions/SparseDeltaCol", + "RightCollisions;R_{rec} (cm);#it{p}_{T} (GeV/c);#Delta #it{p}_{T}/#it{p}_{T,gen};#Delta z (cm);#Delta R (cm);#Delta col ID", + kTHnSparseF, + { + {100, 0.f, 100.f}, // R_rec + {200, 0.f, 10.f}, // pT + {200, -1.f, 1.f}, // ΔpT/pT + {200, -20.f, 20.f}, // Δz + {200, -8.f, 8.f}, // ΔR + {21, -10.5, 10.5} // ΔCollisionID + }, + true); + + registry.add("WrongCollisions/SparseDeltaCol", + "WrongCollisions;R_{rec} (cm);#it{p}_{T} (GeV/c);#Delta #it{p}_{T}/#it{p}_{T,gen};#Delta z (cm);#Delta R (cm);#Delta col ID", + kTHnSparseF, + {{100, 0.f, 100.f}, + {200, 0.f, 10.f}, + {200, -1.f, 1.f}, + {200, -20.f, 20.f}, + {200, -8.f, 8.f}, + {21, -10.5, 10.5}}, + true); + } } - void DefineTagCuts() + template + void fillITSClsNeg(HistogramRegistry& reg, float value) { - TString cutNamesStr = fConfigTagCuts.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); - fTagCuts.push_back(*pcmcuts::GetCut(cutname)); + if constexpr (N == 0) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Neg/ITSCls0"), value); + if constexpr (N == 1) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Neg/ITSCls1"), value); + if constexpr (N == 2) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Neg/ITSCls2"), value); + if constexpr (N == 3) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Neg/ITSCls3"), value); + if constexpr (N == 4) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Neg/ITSCls4"), value); + if constexpr (N == 5) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Neg/ITSCls5"), value); + if constexpr (N == 6) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Neg/ITSCls6"), value); + if constexpr (N == 7) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Neg/ITSCls7"), value); + } + + template + void fillITSClsPos(HistogramRegistry& reg, float value) + { + if constexpr (N == 0) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Pos/ITSCls0"), value); + if constexpr (N == 1) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Pos/ITSCls1"), value); + if constexpr (N == 2) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Pos/ITSCls2"), value); + if constexpr (N == 3) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Pos/ITSCls3"), value); + if constexpr (N == 4) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Pos/ITSCls4"), value); + if constexpr (N == 5) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Pos/ITSCls5"), value); + if constexpr (N == 6) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Pos/ITSCls6"), value); + if constexpr (N == 7) // o2-linter: disable=magic-number (just numbers for ITS cluster) + reg.fill(HIST("ITSHits/Pos/ITSCls7"), value); + } + + template + void reconstructMesons(const TV0s& v0s) + { + for (auto i = 0; i < v0s.size(); i++) { + auto g1 = v0s.iteratorAt(i); + + for (auto j = i + 1; j < v0s.size(); j++) { + auto g2 = v0s.iteratorAt(j); + + 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; + + registry.fill(HIST("Pi0/Same"), v12.M(), v12.Pt(), + g1.v0radius(), g2.v0radius()); } } - LOGF(info, "Number of Tag cuts = %d", fTagCuts.size()); } - void DefineProbeCuts() + void fillClusterNeg(HistogramRegistry& reg, int nCls, float value) { - TString cutNamesStr = fConfigProbeCuts.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); - fProbeCuts.push_back(*pcmcuts::GetCut(cutname)); - } + switch (nCls) { + case 0: // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillITSClsNeg<0>(reg, value); + break; + case 1: // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillITSClsNeg<1>(reg, value); + break; + case 2: // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillITSClsNeg<2>(reg, value); + break; + case 3: // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillITSClsNeg<3>(reg, value); + break; + case 4: // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillITSClsNeg<4>(reg, value); + break; + case 5: // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillITSClsNeg<5>(reg, value); + break; + case 6: // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillITSClsNeg<6>(reg, value); + break; + case 7: // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillITSClsNeg<7>(reg, value); + break; + default: + break; } - LOGF(info, "Number of Probe cuts = %d", fProbeCuts.size()); } - void DefinePairCuts() + void fillClusterPos(HistogramRegistry& reg, int nCls, float value) { - 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)); - } + switch (nCls) { + case 0: + fillITSClsPos<0>(reg, value); + break; + case 1: + fillITSClsPos<1>(reg, value); + break; + case 2: + fillITSClsPos<2>(reg, value); + break; + case 3: + fillITSClsPos<3>(reg, value); + break; + case 4: + fillITSClsPos<4>(reg, value); + break; + case 5: + fillITSClsPos<5>(reg, value); + break; + case 6: + fillITSClsPos<6>(reg, value); + break; + case 7: + fillITSClsPos<7>(reg, value); + break; + default: + break; } - LOGF(info, "Number of Pair cuts = %d", fPairCuts.size()); } + template + void fillEventInfo(TCollision const& collision, const float /*weight*/ = 1.f) + { + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 1.0); + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 6.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 7.0); + } + if (collision.sel8()) { + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 8.0); + } + if (std::fabs(collision.posZ()) < 10.0) { // o2-linter: disable=magic-number (vertex position) + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCollisionCounter"), 9.0); + } - Preslice perCollision_pcm = aod::v0photonkf::emeventId; + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hZvtx"), collision.posZ()); - template - bool IsSelectedPair(TG1 const& g1, TG2 const& g2, TCut1 const& cut1, TCut2 const& cut2) + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hMultNTracksPV"), collision.multNTracksPV()); + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hMultNTracksPVeta1"), collision.multNTracksPVeta1()); + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hMultFT0"), collision.multFT0A(), collision.multFT0C()); + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCentFT0A"), collision.centFT0A()); + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCentFT0C"), collision.centFT0C()); + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCentFT0M"), collision.centFT0M()); + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hCentFT0MvsMultNTracksPV"), collision.centFT0M(), collision.multNTracksPV()); + registry.fill(HIST("Event/") + HIST(EventTypes[evID]) + HIST("hMultFT0MvsMultNTracksPV"), collision.multFT0A() + collision.multFT0C(), collision.multNTracksPV()); + } + template + void reconstructMesonsMixed(const TV0s& current, + const std::deque>& pool) + { + for (const auto& prev : pool) { + for (const auto& g1 : current) { + if (!fV0PhotonCut.IsSelected(g1)) { + continue; + } + for (const auto& g2 : prev) { + 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; + + registry.fill(HIST("Pi0/Mix"), v12.M(), v12.Pt(), + g1.v0radius(), g2.r); + } + } + } + } + + template + void reconstructDalitz(const TV0s& v0s, + const TPositrons& positronsPerCollision, + const TElectrons& electronsPerCollision, + MyCollision const& collision) { - return o2::aod::pwgem::photonmeson::photonpair::IsSelectedPair(g1, g2, cut1, cut2); + + for (const auto& g1 : v0s) { + if (!fV0PhotonCut.IsSelected(g1)) { + continue; + } + ROOT::Math::PtEtaPhiMVector vGamma(g1.pt(), g1.eta(), g1.phi(), 0.); + + for (const auto& [pos, ele] : + combinations(CombinationsFullIndexPolicy(positronsPerCollision, + electronsPerCollision))) { + + if (pos.trackId() == ele.trackId()) { + continue; + } + + if (!fDileptonCut.template IsSelectedTrack(pos, collision) || + !fDileptonCut.template IsSelectedTrack(ele, collision)) { + continue; // Track-Cuts + } + + ROOT::Math::PtEtaPhiMVector vPos(pos.pt(), pos.eta(), pos.phi(), + o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector vEle(ele.pt(), ele.eta(), ele.phi(), + o2::constants::physics::MassElectron); + + auto vee = vPos + vEle; + auto veGamma = vGamma + vee; + + registry.fill(HIST("Dalitz/Same"), + veGamma.M(), vee.Pt(), + g1.v0radius()); + } + } } - template - void fillsinglephoton(TEvents const& collisions, TPhotons const& photons, TPreslice const& perCollision, TCuts const& cuts, TLegs const& /*legs*/) + SliceCache cache; + Preslice perCollision = aod::v0photonkf::emeventId; + Preslice perCollisionElectron = aod::emprimaryelectron::emeventId; + + Partition positrons = o2::aod::emprimaryelectron::sign > int8_t(0) && dileptoncuts.cfgMinPtTrack < o2::aod::track::pt&& nabs(o2::aod::track::eta) < dileptoncuts.cfgMaxEtaTrack; + Partition electrons = o2::aod::emprimaryelectron::sign < int8_t(0) && dileptoncuts.cfgMinPtTrack < o2::aod::track::pt && nabs(o2::aod::track::eta) < dileptoncuts.cfgMaxEtaTrack; + + Filter prefilterPrimaryelectron = ifnode(dileptoncuts.cfgApplyCutsFromPrefilterDerived.node(), o2::aod::emprimaryelectron::pfbderived == static_cast(0), true); + + void processRec(MyCollisions const& collisions, + MyV0Photons const& v0photons, + aod::V0Legs const&, + MyPrimaryElectrons const& electrons) { - 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_v0 = static_cast(fMainList->FindObject("V0")); - double value[4] = {0.f}; - for (auto& collision : collisions) { + for (const 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_pair_before, "", collision); + fillEventInfo<0>(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 photons_coll = photons.sliceBy(perCollision, collision.globalIndex()); - for (auto& cut : cuts) { - for (auto& photon : photons_coll) { - if (!cut.template IsSelected(photon)) { - continue; - } - - float phi_cp = atan2(photon.vy(), photon.vx()); - float eta_cp = std::atanh(photon.vz() / sqrt(pow(photon.vx(), 2) + pow(photon.vy(), 2) + pow(photon.vz(), 2))); - value[0] = photon.pt(); - value[1] = photon.v0radius(); - value[2] = phi_cp > 0 ? phi_cp : phi_cp + TMath::TwoPi(); - value[3] = eta_cp; - reinterpret_cast(list_v0->FindObject(cut.GetName())->FindObject("hs_conv_point"))->Fill(value); - - } // end of photon loop - } // end of cut loop - - } // end of collision loop + fillEventInfo<1>(collision); + registry.fill(HIST("Event/before/hCollisionCounter"), 10.0); // accepted + registry.fill(HIST("Event/after/hCollisionCounter"), 10.0); // accepted + + auto v0sThisCollision = v0photons.sliceBy(perCollision, collision.globalIndex()); + + for (const auto& v0 : v0sThisCollision) { + + if (!fV0PhotonCut.IsSelected(v0)) { + continue; + } + + auto negLeg = v0.template negTrack_as(); + auto posLeg = v0.template posTrack_as(); + + int nClsNeg = 0; + int nClsPos = 0; + + if constexpr (requires { negLeg.itsNCls(); }) { + nClsNeg = negLeg.itsNCls(); + nClsPos = posLeg.itsNCls(); + } else if constexpr (requires { negLeg.itsClusterMap(); }) { + auto countBits = [](uint8_t map) { + return std::bitset<8>(map).count(); + }; + nClsNeg = countBits(negLeg.itsClusterMap()); + nClsPos = countBits(posLeg.itsClusterMap()); + } + if (nClsNeg >= 0 && nClsNeg <= 7) { // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillClusterNeg(registry, nClsNeg, v0.v0radius()); + } + if (nClsPos >= 0 && nClsPos <= 7) { // o2-linter: disable=magic-number (just numbers for ITS cluster) + fillClusterPos(registry, nClsPos, v0.v0radius()); + } + + if (cfgPlotMBGeneral) { + + registry.fill( + HIST("MBGeneral"), + v0.vz(), // 0 + v0.v0radius(), // 1 + v0.eta(), // 2 + v0.phi(), // 3 + v0.pt()); // 4 + } + + if (cfgPlotMBDetailed) { + + registry.fill( + HIST("MBStudiesWireLeft"), + v0.vx(), // 0 + v0.vy(), // 1 + v0.vz(), // 2 + v0.phi(), // 3 + v0.v0radius(), // 4 + v0.pt()); // 5 + + registry.fill( + HIST("MBStudiesWireRight"), + v0.vx(), // 0 + v0.vy(), // 1 + v0.vz(), // 2 + v0.phi(), // 3 + v0.v0radius(), // 4 + v0.pt()); // 5 + + registry.fill( + HIST("MBStudiesWireITS"), + v0.vx(), // 0 + v0.vy(), // 1 + v0.vz(), // 2 + v0.phi(), // 3 + v0.v0radius(), // 4 + v0.pt()); // 5 + + registry.fill( + HIST("MBStudiesMFT"), + v0.vx(), // 0 + v0.vy(), // 1 + v0.vz(), // 2 + v0.phi(), // 3 + v0.v0radius(), // 4 + v0.pt()); // 5 + + registry.fill( + HIST("MBStudiesTPC"), + v0.vx(), // 0 + v0.vy(), // 1 + v0.vz(), // 2 + v0.phi(), // 3 + v0.v0radius(), // 4 + v0.pt()); // 5 + } + } + + reconstructMesons(v0sThisCollision); + + auto electronsPerCollision = electrons.sliceBy(perCollisionElectron, collision.globalIndex()); + auto positronsPerCollision = positrons.sliceBy(perCollisionElectron, collision.globalIndex()); + + reconstructDalitz(v0sThisCollision, positronsPerCollision, electronsPerCollision, collision); + + auto key = getPoolBin(centralities[cfgCentEstimator], collision.posZ()); + auto& pool = mixingPools[key]; + reconstructMesonsMixed(v0sThisCollision, pool); + + std::vector eventCopy; + eventCopy.reserve(v0sThisCollision.size()); + for (const auto& v0 : v0sThisCollision) { + if (!fV0PhotonCut.IsSelected(v0)) { + continue; + } + eventCopy.push_back({v0.pt(), v0.eta(), v0.phi(), v0.vz(), v0.v0radius()}); + } + pool.emplace_back(std::move(eventCopy)); + + if (pool.size() > MaxMixEvents) { + pool.pop_front(); + } + } } - template - void SameEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TCuts1 const& tagcuts, TCuts2 const& probecuts, TPairCuts const& paircuts, TLegs const& /*legs*/) + int classifyPurity(int pdgNeg, int pdgPos) { - THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); + if (pdgNeg == kElectron && pdgPos == kPositron) { + return 1; + } + if (pdgNeg == kElectron && pdgPos == kPiPlus) + return 2; + if (pdgNeg == kPiMinus && pdgPos == kPositron) + return 3; + if (pdgNeg == kKMinus && pdgPos == kPositron) + return 4; + if (pdgNeg == kElectron && pdgPos == kKPlus) + return 5; + if (pdgNeg == kProtonBar && pdgPos == kProton) + return 6; + if (pdgNeg == kKMinus && pdgPos == kKPlus) + return 7; + if (pdgNeg == kPiMinus && pdgPos == kProton) + return 8; + if (pdgNeg == kProtonBar && pdgPos == kPiPlus) + return 9; + if (pdgNeg == kMuonMinus && pdgPos == kMuonPlus) + return 10; + return 11; + } - for (auto& collision : collisions) { - const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; - if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + Partition groupedCollisions = cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax; // this goes to same event. + Filter collisionFilterCommon = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > static_cast(0) && o2::aod::evsel::sel8 == true; // o2-linter: disable=magic-number (vertex position) + Filter collisionFilterCentrality = (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 MyFilteredCollisions = soa::Filtered; // this goes to same event pairing. + + void processTrue(MyCollisions const&, MyFilteredCollisions const& filteredCollisions, + MyV0Photons const& v0photons, + MyMCV0Legs const&, + aod::EMMCParticles const& mcparticles, + aod::EMMCEvents const&) + { + for (const auto& collision : filteredCollisions) { + + const float centralities[3] = { + collision.centFT0M(), + collision.centFT0A(), + collision.centFT0C()}; + + if (centralities[cfgCentEstimator] < cfgCentMin || + cfgCentMax < centralities[cfgCentEstimator]) { continue; } + fillEventInfo<0>(collision); if (!fEMEventCut.IsSelected(collision)) { continue; } - auto photons1_coll = photons1.sliceBy(perCollision1, collision.globalIndex()); - auto photons2_coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - - double value[6] = {0.f}; - float phi_cp2 = 0.f, eta_cp2 = 0.f; - for (auto& tagcut : tagcuts) { - for (auto& probecut : probecuts) { - for (auto& g1 : photons1_coll) { - for (auto& g2 : photons2_coll) { - if (g1.globalIndex() == g2.globalIndex()) { - continue; - } - if (!IsSelectedPair(g1, g2, tagcut, probecut)) { - continue; - } - for (auto& paircut : paircuts) { - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); // tag - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); // probe - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - phi_cp2 = atan2(g2.vy(), g2.vx()); - eta_cp2 = std::atanh(g2.vz() / sqrt(pow(g2.vx(), 2) + pow(g2.vy(), 2) + pow(g2.vz(), 2))); - value[0] = v12.M(); - value[1] = g1.pt(); - value[2] = g2.pt(); - value[3] = g2.v0radius(); - value[4] = phi_cp2 > 0.f ? phi_cp2 : phi_cp2 + TMath::TwoPi(); - value[5] = eta_cp2; - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", tagcut.GetName(), probecut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_conv_point_same"))->Fill(value); - } // end of pair cut loop - } // end of g2 loop - } // end of g1 loop - } // end of probecut loop - } // end of tagcut loop - } // end of collision loop + fillEventInfo<1>(collision); + + registry.fill(HIST("Event/before/hCollisionCounter"), 10.0); + registry.fill(HIST("Event/after/hCollisionCounter"), 10.0); + + auto v0PhotonsColl = v0photons.sliceBy(perCollision, collision.globalIndex()); + + for (const auto& v0 : v0PhotonsColl) { + + auto pos = v0.posTrack_as(); + auto ele = v0.negTrack_as(); + + auto posmc = pos.template emmcparticle_as(); + auto elemc = ele.template emmcparticle_as(); + + if (!fV0PhotonCut.IsSelected(v0)) { + continue; + } + + int purityCat = 12; // default: unmatched + + purityCat = classifyPurity(elemc.pdgCode(), posmc.pdgCode()); + + float rConv = v0.v0radius(); + registry.fill(HIST("PhotonPurity"), + v0.pt(), rConv, v0.eta(), v0.phi(), purityCat); + + int photonid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles); + if (photonid < 0) { + continue; + } + + auto mcphoton = mcparticles.iteratorAt(photonid); + + float rRec = v0.v0radius(); + float rGen = std::sqrt(mcphoton.vx() * mcphoton.vx() + + mcphoton.vy() * mcphoton.vy()); + float deltaR = rRec - rGen; + float deltaZ = v0.vz() - mcphoton.vz(); + float deltaPhi = v0.phi() - mcphoton.phi(); + float deltaEta = v0.eta() - mcphoton.eta(); + float deltaPt = v0.pt() - mcphoton.pt(); + + registry.fill(HIST("ResolutionGen/Z_res"), + mcphoton.vz(), rGen, mcphoton.phi(), + mcphoton.eta(), mcphoton.pt(), deltaZ); + + registry.fill(HIST("ResolutionGen/R_res"), + mcphoton.vz(), rGen, mcphoton.phi(), + mcphoton.eta(), mcphoton.pt(), deltaR); + + registry.fill(HIST("ResolutionGen/Phi_res"), + mcphoton.vz(), rGen, mcphoton.phi(), + mcphoton.eta(), mcphoton.pt(), deltaPhi); + + registry.fill(HIST("ResolutionGen/Eta_res"), + mcphoton.vz(), rGen, mcphoton.phi(), + mcphoton.eta(), mcphoton.pt(), deltaEta); + + registry.fill(HIST("ResolutionGen/Pt_res"), + mcphoton.vz(), rGen, mcphoton.phi(), + mcphoton.eta(), mcphoton.pt(), + deltaPt / mcphoton.pt()); + + registry.fill(HIST("ResolutionRec/Z_res"), + v0.vz(), rRec, v0.phi(), v0.eta(), + v0.pt(), deltaZ); + + registry.fill(HIST("ResolutionRec/R_res"), + v0.vz(), rRec, v0.phi(), v0.eta(), + v0.pt(), deltaR); + + registry.fill(HIST("ResolutionRec/Phi_res"), + v0.vz(), rRec, v0.phi(), v0.eta(), + v0.pt(), deltaPhi); + + registry.fill(HIST("ResolutionRec/Eta_res"), + v0.vz(), rRec, v0.phi(), v0.eta(), + v0.pt(), deltaEta); + + registry.fill(HIST("ResolutionRec/Pt_res"), + v0.vz(), rRec, v0.phi(), v0.eta(), + v0.pt(), deltaPt / mcphoton.pt()); + } + } } - 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& tagcuts, TCuts2 const& probecuts, TPairCuts const& paircuts, TLegs const& /*legs*/, TMixedBinning const& colBinning) + void processCollAssoc(MyCollisionsMC const& collisions, + MyMCCollisions const&, + aod::EMMCParticles const& mcparticles, + MyV0Photons const& v0photons, + MyMCV0Legs const&) { - 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. + for (auto const& col : collisions) { + + auto mccollision = col.emmcevent_as(); + + auto v0s = v0photons.sliceBy(perCollision, col.globalIndex()); + + int mcColIdDerived = mccollision.globalIndex(); // MC event (derived) global index + + for (auto const& v0 : v0s) { + + if (!fV0PhotonCut.IsSelected(v0)) { + continue; + } + + auto negLeg = v0.negTrack_as(); + auto posLeg = v0.posTrack_as(); - const float centralities1[3] = {collision1.centFT0M(), collision1.centFT0A(), collision1.centFT0C()}; - const float centralities2[3] = {collision2.centFT0M(), collision2.centFT0A(), collision2.centFT0C()}; + auto negMC = negLeg.template emmcparticle_as(); + auto posMC = posLeg.template emmcparticle_as(); - if (centralities1[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities1[cfgCentEstimator]) { + // find the photon mother in MC + int photonId = FindCommonMotherFrom2Prongs(posMC, negMC, -11, 11, 22, mcparticles); + if (photonId < 0) { + continue; + } + + auto mcPhoton = mcparticles.iteratorAt(photonId); + auto trueMcCol = mcPhoton.emmcevent_as(); // MC event where the photon was generated + int trueMcColIndex = trueMcCol.globalIndex(); + + int deltaCol = mcColIdDerived - trueMcColIndex; + + float rRec = v0.v0radius(); + float rGen = std::sqrt(mcPhoton.vx() * mcPhoton.vx() + mcPhoton.vy() * mcPhoton.vy()); + float deltaR = rRec - rGen; + float deltaZ = v0.vz() - mcPhoton.vz(); + float deltaPt = v0.pt() - mcPhoton.pt(); + float relPtRes = (mcPhoton.pt() > 0.f) ? deltaPt / mcPhoton.pt() : 0.f; + + // Fill base debug + registry.fill(HIST("DeltaRecDerived"), deltaCol); + registry.fill(HIST("AllR"), rRec); + + if (deltaCol == 0) { + registry.fill(HIST("RightCollisions/SparseDeltaCol"), + rRec, + v0.pt(), + relPtRes, + deltaZ, + deltaR, + deltaCol); + } else { + registry.fill(HIST("WrongCollisions/SparseDeltaCol"), + rRec, + v0.pt(), + relPtRes, + deltaZ, + deltaR, + deltaCol); + } + + if (deltaCol == 0) { + registry.fill(HIST("RightCollisions/DeltaColvsZ"), v0.vz()); + registry.fill(HIST("RightCollisions/DeltaColvsR"), rRec); + registry.fill(HIST("RightCollisions/DeltaColvspT"), v0.pt()); + registry.fill(HIST("RightCollisions/DeltaColvsZRes"), deltaZ); + registry.fill(HIST("RightCollisions/DeltaColvsRRes"), deltaR); + registry.fill(HIST("RightCollisions/DeltaColvspTRes"), relPtRes); + } else { + registry.fill(HIST("WrongCollisions/DeltaColvsZ"), v0.vz()); + registry.fill(HIST("WrongCollisions/DeltaColvsR"), rRec); + registry.fill(HIST("WrongCollisions/DeltaColvspT"), v0.pt()); + registry.fill(HIST("WrongCollisions/DeltaColvsZRes"), deltaZ); + registry.fill(HIST("WrongCollisions/DeltaColvsRRes"), deltaR); + registry.fill(HIST("WrongCollisions/DeltaColvspTRes"), relPtRes); + } + } + } + } + + void processBremsstrahlung(MyTracks const& tracks, aod::McParticles const& mcparticles) + { + + for (const auto& trk : tracks) { + if (!trk.has_mcParticle()) { continue; } - if (centralities2[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities2[cfgCentEstimator]) { + auto mc = trk.mcParticle(); + if (std::abs(mc.pdgCode()) != kElectron) { continue; } - if (!fEMEventCut.IsSelected(collision1) || !fEMEventCut.IsSelected(collision2)) { + + if (trk.pt() < dileptoncuts.cfgMinPtTrack) { 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()); - - double value[6] = {0.f}; - float phi_cp2 = 0.f, eta_cp2 = 0.f; - for (auto& tagcut : tagcuts) { - for (auto& probecut : probecuts) { - for (auto& g1 : photons_coll1) { - for (auto& g2 : photons_coll2) { - if (!IsSelectedPair(g1, g2, tagcut, probecut)) { - continue; - } - // 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()); - - for (auto& paircut : paircuts) { - if (!paircut.IsSelected(g1, g2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); // tag - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); // probe - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - phi_cp2 = atan2(g2.vy(), g2.vx()); - eta_cp2 = std::atanh(g2.vz() / sqrt(pow(g2.vx(), 2) + pow(g2.vy(), 2) + pow(g2.vz(), 2))); - value[0] = v12.M(); - value[1] = g1.pt(); - value[2] = g2.pt(); - value[3] = g2.v0radius(); - value[4] = phi_cp2 > 0.f ? phi_cp2 : phi_cp2 + TMath::TwoPi(); - value[5] = eta_cp2; - reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", tagcut.GetName(), probecut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_conv_point_mix"))->Fill(value); - - } // end of pair cut loop - } // end of g2 loop - } // end of g1 loop - } // end of probecut loop - } // end of tagcut loop - } // end of different collision combinations - } + double pMC = mc.p(); + double ptMC = mc.pt(); + double phiMC = mc.phi(); + double etaMC = mc.eta(); - 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); - using MyFilteredCollisions = soa::Filtered; // this goes to mixed event. + double pReco = trk.p(); + double ptReco = trk.pt(); + double phiReco = trk.phi(); + double etaReco = trk.eta(); - void processMB(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, MyV0Photons const& v0photons, aod::V0Legs const& legs) - { - fillsinglephoton(grouped_collisions, v0photons, perCollision_pcm, fProbeCuts, legs); - SameEventPairing(filtered_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fTagCuts, fProbeCuts, fPairCuts, legs); - if (fDoMixing) { - if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fTagCuts, fProbeCuts, fPairCuts, legs, colBinning_M); - } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fTagCuts, fProbeCuts, fPairCuts, legs, colBinning_A); - } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision_pcm, perCollision_pcm, fTagCuts, fProbeCuts, fPairCuts, legs, colBinning_C); + int nBrem = 0; // o2-linter: disable=magic-number + + registry.fill(HIST("Bremsstrahlung/relativeResoPtWOBrems"), trk.pt(), trk.pt() * std::sqrt(trk.c1Pt21Pt2())); + + bool isFirst = true; + for (const auto& dId : mc.daughtersIds()) { + if (dId < 0 || dId >= mcparticles.size()) { + continue; + } + auto daughter = mcparticles.iteratorAt(dId); + if (daughter.getProcess() != kPBrem) { + continue; + } + + if (std::abs(daughter.eta()) > pcmcuts.cfgMaxEtaV0) { + continue; + } + + double r = std::hypot(daughter.vx(), daughter.vy()); + double z = daughter.vz(); + + nBrem++; + + registry.fill(HIST("Bremsstrahlung/EnergyLossVsR"), r, daughter.e()); + registry.fill(HIST("Bremsstrahlung/EnergyLossVsZ"), z, daughter.e()); + registry.fill(HIST("Bremsstrahlung/EnergyLossXY"), daughter.vx(), daughter.vy()); + registry.fill(HIST("Bremsstrahlung/EnergyLossXYWeigh"), daughter.vx(), daughter.vy(), daughter.e()); + + if (isFirst) { + registry.fill(HIST("Bremsstrahlung/relativeResoPtWBrems"), trk.pt(), trk.pt() * std::sqrt(trk.c1Pt21Pt2())); + } + + registry.fill(HIST("Bremsstrahlung/Sigma1PtVsR"), r, trk.sigma1Pt()); + + registry.fill(HIST("Bremsstrahlung/SigmaYVsR"), r, trk.sigmaY()); + registry.fill(HIST("Bremsstrahlung/SigmaZVsR"), r, trk.sigmaZ()); + + if (pMC > 0) { + registry.fill(HIST("Bremsstrahlung/DeltaPoverPvsR"), r, (pReco - pMC) / pMC); + } + if (ptMC > 0) { + registry.fill(HIST("Bremsstrahlung/DeltaPtvsR"), r, (ptReco - ptMC) / ptMC); + } + registry.fill(HIST("Bremsstrahlung/DeltaPhivsR"), r, phiReco - phiMC); + registry.fill(HIST("Bremsstrahlung/DeltaEtavsR"), r, etaReco - etaMC); } + + registry.fill(HIST("Bremsstrahlung/NBrem"), nBrem); + isFirst = false; } } - void processDummy(MyCollisions::iterator const&) {} - - PROCESS_SWITCH(MaterialBudget, processMB, "process material budget", false); - PROCESS_SWITCH(MaterialBudget, processDummy, "Dummy function", true); + PROCESS_SWITCH(MaterialBudget, processRec, "process material budget", true); + PROCESS_SWITCH(MaterialBudget, processTrue, "process material budget", false); + PROCESS_SWITCH(MaterialBudget, processCollAssoc, "process material budget", false); + PROCESS_SWITCH(MaterialBudget, processBremsstrahlung, "process material budget", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"material-budget"})}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx b/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx index 3fe51c1ff7c..2c0a33d32ec 100644 --- a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx @@ -14,29 +14,34 @@ // This code loops over v0 photons for studying material budget. // Please write to: daiki.sekihata@cern.ch -#include -#include +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" +#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Core/PairCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.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/PairUtilities.h" -#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PairCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" -#include "PWGEM/Dilepton/Utils/MCUtilities.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -48,7 +53,7 @@ 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; @@ -127,8 +132,8 @@ struct MaterialBudgetMC { 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, "material_budget_study", "Pair"); } // end of cut3 loop pair cut - } // end of probecut loop - } // end of tagcut loop + } // end of probecut loop + } // end of tagcut loop } static constexpr std::string_view pairnames[9] = {"PCMPCM", "PHOSPHOS", "EMCEMC", "PCMPHOS", "PCMEMC", "PCMDalitzEE", "PCMDalitzMuMu", "PHOSEMC", "DalitzEEDalitzEE"}; @@ -280,7 +285,7 @@ struct MaterialBudgetMC { reinterpret_cast(list_v0->FindObject(cut.GetName())->FindObject("hs_conv_point"))->Fill(value); } // end of photon loop - } // end of cut loop + } // end of cut loop } // end of collision loop } @@ -372,11 +377,11 @@ struct MaterialBudgetMC { value[5] = eta_cp2; reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", tagcut.GetName(), probecut.GetName()))->FindObject(paircut.GetName())->FindObject("hs_conv_point_same"))->Fill(value); } // end of pair cut loop - } // end of g2 loop - } // end of g1 loop - } // end of probecut loop - } // end of tagcut loop - } // end of collision loop + } // end of g2 loop + } // end of g1 loop + } // end of probecut loop + } // end of tagcut loop + } // end of collision loop } Partition grouped_collisions = cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax; // this goes to same event. diff --git a/PWGEM/PhotonMeson/Tasks/OmegaMesonEMC.cxx b/PWGEM/PhotonMeson/Tasks/OmegaMesonEMC.cxx new file mode 100644 index 00000000000..556aa96bd6c --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/OmegaMesonEMC.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 OmegaMesonEMC.cxx +/// +/// \brief This code loops over collisions to reconstruct heavy mesons (omega or eta') using EMCal clusters +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt +/// + +#include "PWGEM/PhotonMeson/Utils/HNMUtilities.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.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/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector4D.h" +#include "TMath.h" +#include "TRandom3.h" + +#include "fairlogger/Logger.h" + +#include +#include +#include + +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::Filtered>; +using MyCollision = MyCollisions::iterator; +using SelectedTracks = soa::Filtered>; +} // namespace o2::aod + +namespace hnm +{ + +enum TrackCuts { kpT, + kEta, + kTPCSigma, + kTrackCuts +}; + +const std::vector chargedPionMinMaxName{"Min", "Max"}; +const std::vector chargedPionCutsName{"pT", "eta", "TPC sigma"}; +const float chargedPionCutsTable[kTrackCuts][2]{{0.35f, 20.f}, {-.8f, .8f}, {-4.f, 4.f}}; + +} // namespace hnm + +struct OmegaMesonEMC { + + // --------------------------------> 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", true, "Evt sel: check for sel8 trigger bit"}; + Configurable confEvtRequirekTVXinEMC{"confEvtRequirekTVXinEMC", false, "Evt sel: check for EMCal MB trigger kTVXinEMC"}; + Configurable confEvtRequireL0{"confEvtRequireL0", false, "Evt sel: check for EMCal L0 trigger"}; + Configurable confEvtRequireGoodZVertex{"confEvtRequireGoodZVertex", false, "Evt sel: check for EMCal good z-vertex"}; + Configurable confEvtRequireNoSameBunchPileUp{"confEvtRequireNoSameBunchPileUp", false, "Evt sel: check for no same bunch pile-up"}; + + // ---> Track selection + Configurable> cfgChargedPionCuts{"cfgChargedPionCuts", {hnm::chargedPionCutsTable[0], 3, 2, hnm::chargedPionCutsName, hnm::chargedPionMinMaxName}, "Charged pion track cuts"}; + Configurable cfgTPCNClustersMin{"cfgTPCNClustersMin", 80, "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", 4, "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 + + // ---> 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] = {0.11, 0.16}; + Configurable> cfgMassWindowPi0{"cfgMassWindowPi0", {DefaultMassWindows, 2, {"min", "max"}}, "Mass window for selected decay pi0"}; + + Configurable cfgMaxMultiplicity{"cfgMaxMultiplicity", 5000, "Maximum number of tracks in a collision (can be used to increase the S/B -> Very experimental)"}; + 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)"}; + + Filter collisionZVtxFilter = nabs(aod::collision::posZ) < confEvtZvtx; + Filter collisionMultFilter = (o2::aod::mult::multNTracksPV <= cfgMaxMultiplicity); + + Filter trackPtFilter = (o2::aod::track::pt > cfgChargedPionCuts->get(hnm::kpT, "Min")) && (o2::aod::track::pt < cfgChargedPionCuts->get(hnm::kpT, "Max")); + Filter trackEtaFilter = (o2::aod::track::eta > cfgChargedPionCuts->get(hnm::kEta, "Min")) && (o2::aod::track::eta < cfgChargedPionCuts->get(hnm::kEta, "Max")); + Filter trackDCAXYFilter = nabs(o2::aod::track::dcaXY) < cfgTrkDCAxyMax; + Filter trackDCAZFilter = nabs(o2::aod::track::dcaZ) < cfgTrkDCAzMax; + + Filter trackTPCChi2Filter = o2::aod::track::tpcChi2NCl < cfgTrkMaxChi2PerClusterTPC; + Filter trackITSChi2Filter = o2::aod::track::itsChi2NCl < cfgTrkMaxChi2PerClusterITS; + + Filter trackTPCSigmaFilterTPC = (o2::aod::pidtpc::tpcNSigmaPi > cfgChargedPionCuts->get(hnm::kTPCSigma, "Min")) && (o2::aod::pidtpc::tpcNSigmaPi < cfgChargedPionCuts->get(hnm::kTPCSigma, "Max")); + + template + bool isSelectedTrack(T const& track) + { + if (track.tpcNClsFound() < cfgTPCNClustersMin) + return false; + if (track.tpcCrossedRowsOverFindableCls() < cfgTrkTPCfCls) + return false; + if (track.tpcNClsCrossedRows() < cfgTrkTPCcRowsMin) + return false; + if (track.tpcFractionSharedCls() > cfgTrkTPCsClsSharedFrac) + return false; + if (track.itsNCls() < cfgTrkITSnclsMin) + return false; + return true; + } + + HistogramRegistry mHistManager{"HeavyNeutralMesonHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Prepare vectors for different species + std::vector vGGs; + std::vector vHNMs; + std::vector pion, antipion; + + Preslice perCollisionEMC = aod::skimmedcluster::collisionId; + + void init(InitContext const&) + { + 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/fMultiplicity", "Multiplicity after event cuts;#bf{#it{N}_{tracks}};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{500, 0, 500}}); + mHistManager.add("Event/fZvtx", "Zvtx after event cuts;#bf{z_{vtx} (cm)};#bf{#it{N}_{collisions}}", HistType::kTH1F, {{300, -15, 15}}); + + mHistManager.add("GG/invMassVsPt", "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_selected", "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.}}); + + 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/%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/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/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/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 + // Properties of the pi+pi- pair + mHistManager.add("Omega/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("Omega/Before/PiPlPiMi/fEta", "Pseudorapidity of HMNCand;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add("Omega/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"}) { + mHistManager.add(Form("Omega/%s/fInvMassVsPt", BeforeAfterString), "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, {{800, 0.4, 1.2}, {250, 0., 25.}}); + mHistManager.add(Form("Omega/%s/fEta", BeforeAfterString), "Pseudorapidity of HNM candidate;#eta;#bf{#it{N}^{#pi^{+}#pi^{-}#gamma#gamma}}", HistType::kTH1F, {{500, -2, 2}}); + mHistManager.add(Form("Omega/%s/fPhi", BeforeAfterString), "Azimuthal angle of HNM candidate;#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::SelectedTracks const& tracks) + { + // clean vecs + pion.clear(); + antipion.clear(); + vHNMs.clear(); + + // ---------------------------------> EMCal event QA <---------------------------------- + // - Fill Event/nEMCalEvents histogram for EMCal event QA + // ------------------------------------------------------------------------------------- + bool bcHasEMCCells = collision.isemcreadout(); + auto foundBC = collision.foundBC_as(); + bool iskTVXinEMC = foundBC.alias_bit(kTVXinEMC); + bool isL0Triggered = foundBC.alias_bit(kEMC7) || foundBC.alias_bit(kDMC7) || foundBC.alias_bit(kEG1) || foundBC.alias_bit(kEG2); + + if (confEvtRequireSel8 && !collision.sel8()) + return; // Skip this collision if sel8 trigger bit is not set + if (confEvtRequirekTVXinEMC && !iskTVXinEMC) + return; // Skip this collision if kTVXinEMC trigger bit is not set + if (confEvtRequireL0 && !isL0Triggered) + return; // Skip this collision if L0 trigger bit is not set + if (confEvtRequireGoodZVertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; // Skip this collision if good z-vertex condition is not met + if (confEvtRequireNoSameBunchPileUp && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; // Skip this collision if no same bunch pileup condition is not met + + 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); + + mHistManager.fill(HIST("Event/fMultiplicity"), collision.multNTracksPV()); + mHistManager.fill(HIST("Event/fZvtx"), collision.posZ()); + + // --------------------------------> 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 clustersInThisCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + + std::vector vGammas; + hnmutilities::storeGammasInVector(clustersInThisCollision, vGammas, emcEtaShift, emcPhiShift); + hnmutilities::reconstructGGs(vGammas, vGGs); + vGammas.clear(); + + for (unsigned int iGG = 0; iGG < vGGs.size(); iGG++) { + auto lightMeson = &vGGs.at(iGG); + + mHistManager.fill(HIST("GG/invMassVsPt"), lightMeson->m(), lightMeson->pT()); + + if (lightMeson->m() > cfgMassWindowPi0->get("min") && lightMeson->m() < cfgMassWindowPi0->get("max")) { + lightMeson->isPi0 = true; + mHistManager.fill(HIST("GG/invMassVsPt_selected"), lightMeson->m(), lightMeson->pT()); + } else { + vGGs.erase(vGGs.begin() + iGG); + iGG--; + } + } + + // ------------------------------> Loop over all tracks <------------------------------- + // - Fill QA histograms for all tracks and per particle species + // ------------------------------------------------------------------------------------- + for (const auto& track : tracks) { + if (!isSelectedTrack(track)) + continue; // Skip tracks that do not pass the selection criteria + if (track.sign() > 0) { // Positive charge -> Particles + pion.emplace_back(track.pt(), track.eta(), track.phi(), constants::physics::MassPionCharged); + + mHistManager.fill(HIST("TrackCuts/Pion/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/Pion/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/Pion/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/Pion/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaPi()); + + 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 + antipion.emplace_back(track.pt(), track.eta(), track.phi(), constants::physics::MassPionCharged); + + mHistManager.fill(HIST("TrackCuts/AntiPion/fPt"), track.pt()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fEta"), track.eta()); + mHistManager.fill(HIST("TrackCuts/AntiPion/fPhi"), track.phi()); + + mHistManager.fill(HIST("TrackCuts/AntiPion/fNsigmaTPCvsP"), track.p(), track.tpcNSigmaPi()); + + 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("Omega/Before/PiPlPiMi/fInvMassVsPt"), vecPiPlPiMi.M(), vecPiPlPiMi.pt()); + mHistManager.fill(HIST("Omega/Before/PiPlPiMi/fEta"), vecPiPlPiMi.eta()); + mHistManager.fill(HIST("Omega/Before/PiPlPiMi/fPhi"), RecoDecay::constrainAngle(vecPiPlPiMi.phi())); + } + } + + // ---------------------------> Process HNM candidates <-------------------------------- + // - Fill invMassVsPt histograms separated into HNM types (based on GG mass) and gamma reco method + // ------------------------------------------------------------------------------------- + for (unsigned int iHNM = 0; iHNM < vHNMs.size(); iHNM++) { + auto heavyNeutralMeson = vHNMs.at(iHNM); + float massHNM = heavyNeutralMeson.m(cfgHNMMassCorrection); + + mHistManager.fill(HIST("Omega/Before/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("Omega/Before/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("Omega/Before/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + + if (heavyNeutralMeson.gg->pT() / heavyNeutralMeson.pT() > cfgMinGGPtOverHNMPt) { + mHistManager.fill(HIST("Omega/After/fInvMassVsPt"), massHNM, heavyNeutralMeson.pT()); + mHistManager.fill(HIST("Omega/After/fEta"), heavyNeutralMeson.eta()); + mHistManager.fill(HIST("Omega/After/fPhi"), RecoDecay::constrainAngle(heavyNeutralMeson.phi())); + } + } + } +}; + +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"omega-meson-emc"})}; } diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaEMCEMC.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaEMCEMC.cxx index 3b7893f7373..b1b657f8a1f 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaEMCEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaEMCEMC.cxx @@ -9,25 +9,24 @@ // 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" +/// \file Pi0EtaToGammaGammaEMCEMC.cxx +/// \brief This code loops over photons and makes pairs for neutral mesons analyses for EMC-EMC. +/// \author D. Sekihata, daiki.sekihata@cern.ch +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" + +#include +#include +#include using namespace o2; using namespace o2::aod; +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::photonpair; using MyEMCClusters = soa::Join; -using MyEMCCluster = MyEMCClusters::iterator; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx index 7cd7ba3c492..982eba314e1 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx @@ -9,25 +9,24 @@ // 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" +/// \file Pi0EtaToGammaGammaMCEMCEMC.cxx +/// \brief This code loops over photons and makes pairs for neutral mesons analyses in MC for EMC-EMC. +/// \author D. Sekihata, daiki.sekihata@cern.ch +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" + +#include +#include +#include using namespace o2; using namespace o2::aod; +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::photonpair; using MyEMCClusters = soa::Join; -using MyEMCCluster = MyEMCClusters::iterator; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMDalitzEE.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMDalitzEE.cxx index 2d929f1a82a..e36da8a2556 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMDalitzEE.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMDalitzEE.cxx @@ -9,31 +9,26 @@ // 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" +/// \file Pi0EtaToGammaGammaMCPCMDalitzEE.cxx +/// \brief This code loops over photons and makes pairs for neutral mesons analyses in MC for PCM-Dalitz. +/// \author D. Sekihata, daiki.sekihata@cern.ch +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" + +#include +#include +#include using namespace o2; using namespace o2::aod; +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::photonpair; -// using MyV0Photons = soa::Join; -// using MyV0Photon = MyV0Photons::iterator; -// -// using MyMCV0Legs = soa::Join; -// using MyMCV0Leg = MyMCV0Legs::iterator; -// -// using MyMCElectrons = soa::Join; -// using MyMCElectron = MyMCElectrons::iterator; +using MyV0Photons = soa::Filtered>; +using MyMCV0Legs = soa::Join; +using MyMCElectrons = soa::Filtered>; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx index df8877d3ae8..62c57593fd0 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCPCMPCM.cxx @@ -9,28 +9,25 @@ // 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" +/// \file Pi0EtaToGammaGammaMCPCMPCM.cxx +/// \brief This code loops over photons and makes pairs for neutral mesons analyses in MC for PCM-PCM. +/// \author D. Sekihata, daiki.sekihata@cern.ch +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h" + +#include +#include +#include using namespace o2; using namespace o2::aod; +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::photonpair; -using MyV0Photons = soa::Join; -using MyV0Photon = MyV0Photons::iterator; - +using MyV0Photons = o2::soa::Filtered>; using MyMCV0Legs = soa::Join; -using MyMCV0Leg = MyMCV0Legs::iterator; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMDalitzEE.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMDalitzEE.cxx index 15ccbe72bd4..b2c39f2093a 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMDalitzEE.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMDalitzEE.cxx @@ -9,23 +9,25 @@ // 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" +/// \file Pi0EtaToGammaGammaPCMDalitzEE.cxx +/// \brief This code loops over photons and makes pairs for neutral mesons analyses for PCM-Dalitz. +/// \author D. Sekihata, daiki.sekihata@cern.ch -#include "Common/Core/RecoDecay.h" +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" + +#include +#include +#include using namespace o2; using namespace o2::aod; +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::photonpair; + +using MyV0Photons = o2::soa::Filtered>; +using MyPrimaryElectrons = o2::soa::Filtered>; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx index 24557c828a7..6272af75da6 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaPCMPCM.cxx @@ -9,25 +9,24 @@ // 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" +/// \file Pi0EtaToGammaGammaPCMPCM.cxx +/// \brief This code loops over photons and makes pairs for neutral mesons analyses for PCM-PCM. +/// \author D. Sekihata, daiki.sekihata@cern.ch +#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h" + +#include +#include +#include using namespace o2; using namespace o2::aod; +using namespace o2::framework; +using namespace o2::aod::pwgem::photonmeson::photonpair; -// using MyV0Photons = soa::Join; -// using MyV0Photon = MyV0Photons::iterator; +using MyV0Photons = o2::soa::Filtered>; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx b/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx index ddf61e9765e..cbb87e23b37 100644 --- a/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx +++ b/PWGEM/PhotonMeson/Tasks/SinglePhoton.cxx @@ -14,29 +14,37 @@ // This code loops over photon candidate and fill histograms // 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 "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/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "EMPhotonEventCut.h" + #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -45,7 +53,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -206,15 +214,6 @@ struct SinglePhoton { 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(",")); @@ -228,12 +227,8 @@ struct SinglePhoton { 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->SetTrackMatchingEtaParams(EMC_TM_Eta->at(0), EMC_TM_Eta->at(1), EMC_TM_Eta->at(2)); + custom_cut->SetTrackMatchingPhiParams(EMC_TM_Phi->at(0), EMC_TM_Phi->at(1), EMC_TM_Phi->at(2)); custom_cut->SetMinEoverP(EMC_Eoverp); custom_cut->SetUseExoticCut(EMC_UseExoticCut); @@ -266,8 +261,8 @@ struct SinglePhoton { return is_selected; } - template - void FillPhoton(TEvents const& collisions, TPhotons1 const& photons1, TPreslice1 const& perCollision1, TCuts1 const& cuts1, TV0Legs const&, TEMCMatchedTracks const&) + template + void FillPhoton(TEvents const& collisions, TPhotons1 const& photons1, TPreslice1 const& perCollision1, TCuts1 const& cuts1, TV0Legs const&) { THashList* list_ev_before = static_cast(fMainList->FindObject("Event")->FindObject(detnames[photontype].data())->FindObject(event_types[0].data())); THashList* list_ev_after = static_cast(fMainList->FindObject("Event")->FindObject(detnames[photontype].data())->FindObject(event_types[1].data())); @@ -331,25 +326,25 @@ 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. void processPCM(MyCollisions const&, MyV0Photons const& v0photons, aod::V0Legs const& legs) { - FillPhoton(grouped_collisions, v0photons, perCollision, fPCMCuts, legs, nullptr); + FillPhoton(grouped_collisions, v0photons, perCollision, fPCMCuts, legs); } // void processPHOS(MyCollisions const& collisions, aod::PHOSClusters const& phosclusters) // { - // FillPhoton(grouped_collisions, phosclusters, perCollision_phos, fPHOSCuts, nullptr, nullptr); + // FillPhoton(grouped_collisions, phosclusters, perCollision_phos, fPHOSCuts, nullptr); // } - // void processEMC(MyCollisions const& collisions, aod::SkimEMCClusters const& emcclusters, aod::SkimEMCMTs const& emcmatchedtracks) + // void processEMC(MyCollisions const& collisions, aod::SkimEMCClusters const& emcclusters) // { - // FillPhoton(grouped_collisions, emcclusters, perCollision_emc, fEMCCuts, nullptr, emcmatchedtracks); + // FillPhoton(grouped_collisions, emcclusters, perCollision_emc, fEMCCuts, nullptr); // } void processDummy(MyCollisions::iterator const&) {} diff --git a/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx b/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx index ccb33db7f3a..7a5b3e42120 100644 --- a/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx @@ -14,32 +14,35 @@ // This code loops over photon candidate and fill histograms // Please write to: daiki.sekihata@cern.ch -#include -#include - -#include "TString.h" -#include "TMath.h" -#include "Math/Vector4D.h" -#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/MCUtilities.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "EMPhotonEventCut.h" + +#include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" -#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -50,7 +53,7 @@ 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; @@ -212,14 +215,6 @@ struct SinglePhotonMC { // // 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()) { @@ -234,12 +229,8 @@ struct SinglePhotonMC { // 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->SetTrackMatchingEtaParams(EMC_TM_Eta->at(0), EMC_TM_Eta->at(1), EMC_TM_Eta->at(2)); + // custom_cut->SetTrackMatchingPhiParams(EMC_TM_Phi->at(0), EMC_TM_Phi->at(1), EMC_TM_Phi->at(2)); // // custom_cut->SetMinEoverP(EMC_Eoverp); // custom_cut->SetUseExoticCut(EMC_UseExoticCut); @@ -272,8 +263,8 @@ struct SinglePhotonMC { return is_selected; } - template - void FillTruePhoton(TEvents const& collisions, TPhotons1 const& photons1, TPreslice1 const& perCollision1, TCuts1 const& cuts1, TV0Legs const&, TEMCMatchedTracks const&, TMCParticles const& mcparticles, TMCEvents const&) + template + void FillTruePhoton(TEvents const& collisions, TPhotons1 const& photons1, TPreslice1 const& perCollision1, TCuts1 const& cuts1, TV0Legs const&, TMCParticles const& mcparticles, TMCEvents const&) { THashList* list_ev_before = static_cast(fMainList->FindObject("Event")->FindObject(detnames[photontype].data())->FindObject(event_types[0].data())); THashList* list_ev_after = static_cast(fMainList->FindObject("Event")->FindObject(detnames[photontype].data())->FindObject(event_types[1].data())); @@ -351,25 +342,25 @@ struct SinglePhotonMC { } } // 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. void processPCM(MyCollisions const&, MyV0Photons const& v0photons, MyMCV0Legs const& legs, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const& mccollisions) { - FillTruePhoton(grouped_collisions, v0photons, perCollision, fPCMCuts, legs, nullptr, mcparticles, mccollisions); + FillTruePhoton(grouped_collisions, v0photons, perCollision, fPCMCuts, legs, mcparticles, mccollisions); } // void processPHOS(MyCollisions const& collisions, aod::PHOSClusters const& phosclusters, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const& mccollisions) // { - // FillTruePhoton(grouped_collisions, phosclusters, perCollision_phos, fPHOSCuts, nullptr, nullptr, mcparticles, mccollisions); + // FillTruePhoton(grouped_collisions, phosclusters, perCollision_phos, fPHOSCuts, nullptr, mcparticles, mccollisions); // } - // void processEMC(MyCollisions const& collisions, aod::SkimEMCClusters const& emcclusters, aod::SkimEMCMTs const& emcmatchedtracks, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const& mccollisions) + // void processEMC(MyCollisions const& collisions, aod::SkimEMCClusters const& emcclusters, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const& mccollisions) // { - // FillTruePhoton(grouped_collisions, emcclusters, perCollision_emc, fEMCCuts, nullptr, emcmatchedtracks, mcparticles, mccollisions); + // FillTruePhoton(grouped_collisions, emcclusters, perCollision_emc, fEMCCuts, nullptr, mcparticles, mccollisions); // } PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; diff --git a/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx b/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx index 2f91a62dc43..2def85ae4d2 100644 --- a/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx +++ b/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx @@ -14,28 +14,47 @@ // This code is for data-driven efficiency for photon analyses. tag and probe method // 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/PHOSPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/PairCut.h" +#include "EMPhotonEventCut.h" + #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/PairCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::aod; @@ -45,7 +64,7 @@ using namespace o2::soa; 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; @@ -126,7 +145,7 @@ struct TagAndProbe { 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, "tag_and_probe", pairname.data()); } // end of cut3 loop pair cut - } // end of cut2 loop + } // end of cut2 loop } static constexpr std::string_view pairnames[6] = {"PCMPCM", "PHOSPHOS", "EMCEMC", "PCMPHOS", "PCMEMC", "PHOSEMC"}; @@ -232,8 +251,8 @@ struct TagAndProbe { Preslice perCollision_phos = aod::skimmedcluster::collisionId; Preslice perCollision_emc = aod::skimmedcluster::collisionId; - template - void SameEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TTagCut const& tagcut, TProbeCuts const& probecuts, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMCMTs const& emcmatchedtracks) + template + void SameEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TTagCut const& tagcut, TProbeCuts const& probecuts, TPairCuts const& paircuts, TLegs const& /*legs*/) { 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())); @@ -315,13 +334,13 @@ struct TagAndProbe { reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", tagcut.GetName(), probecut.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_PassingProbe_Same"))->Fill(v12.M(), v2.Pt()); if constexpr (pairtype == PairType::kEMCEMC) { - RotationBackground(v12, v1, v2, photons2_coll, g1.globalIndex(), g2.globalIndex(), probecut, paircut, emcmatchedtracks); + RotationBackground(v12, v1, v2, photons2_coll, g1.globalIndex(), g2.globalIndex(), probecut, paircut); } } // end of probe cut loop - } // end of pair cut loop - } // end of g2 loop - } // end of g1 loop - } // end of collision loop + } // end of pair cut loop + } // end of g2 loop + } // end of g1 loop + } // end of collision loop } Configurable ndepth{"ndepth", 10, "depth for event mixing"}; @@ -334,8 +353,8 @@ struct TagAndProbe { 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, TTagCut const& tagcut, TProbeCuts const& probecuts, TPairCuts const& paircuts, TLegs const& /*legs*/, TEMCMTs const& /*emcmatchedtracks*/, TMixedBinning const& colBinning) + template + void MixedEventPairing(TEvents const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPreslice1 const& perCollision1, TPreslice2 const& perCollision2, TTagCut const& tagcut, TProbeCuts const& probecuts, TPairCuts const& paircuts, TLegs const& /*legs*/, TMixedBinning const& colBinning) { THashList* list_pair_ss = static_cast(fMainList->FindObject("Pair")->FindObject(pairnames[pairtype].data())); @@ -406,15 +425,15 @@ struct TagAndProbe { reinterpret_cast(list_pair_ss->FindObject(Form("%s_%s", tagcut.GetName(), probecut.GetName()))->FindObject(paircut.GetName())->FindObject("hMggPt_PassingProbe_Mixed"))->Fill(v12.M(), v2.Pt()); } // end of probe cut loop - } // end of pair cut loop - } // end of g2 loop - } // end of g1 loop - } // end of different collision combinations + } // end of pair cut loop + } // end of g2 loop + } // end of g1 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*/) + 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) { // if less than 3 clusters are present skip event since we need at least 3 clusters if (photons_coll.size() < 3) { @@ -442,7 +461,7 @@ struct TagAndProbe { // only combine rotated photons with other photons continue; } - if (!cut.template IsSelected(photon)) { + if (!cut.template IsSelected(photon)) { continue; } @@ -474,32 +493,32 @@ 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_common = nabs(o2::aod::collision::posZ) < 10.f && o2::aod::collision::numContrib > static_cast(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); 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, fTagPCMCut, fProbePCMCuts, fPairCuts, legs, nullptr); + SameEventPairing(grouped_collisions, v0photons, v0photons, perCollision, perCollision, fTagPCMCut, fProbePCMCuts, fPairCuts, legs); if (cfgCentEstimator == 0) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fTagPCMCut, fProbePCMCuts, fPairCuts, legs, nullptr, colBinning_M); + MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fTagPCMCut, fProbePCMCuts, fPairCuts, legs, colBinning_M); } else if (cfgCentEstimator == 1) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fTagPCMCut, fProbePCMCuts, fPairCuts, legs, nullptr, colBinning_A); + MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fTagPCMCut, fProbePCMCuts, fPairCuts, legs, colBinning_A); } else if (cfgCentEstimator == 2) { - MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fTagPCMCut, fProbePCMCuts, fPairCuts, legs, nullptr, colBinning_C); + MixedEventPairing(filtered_collisions, v0photons, v0photons, perCollision, perCollision, fTagPCMCut, fProbePCMCuts, fPairCuts, legs, colBinning_C); } } void processPHOSPHOS(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, aod::PHOSClusters const& phosclusters) { - SameEventPairing(grouped_collisions, phosclusters, phosclusters, perCollision_phos, perCollision_phos, fTagPHOSCut, fProbePHOSCuts, fPairCuts, nullptr, nullptr); - MixedEventPairing(filtered_collisions, phosclusters, phosclusters, perCollision_phos, perCollision_phos, fTagPHOSCut, fProbePHOSCuts, fPairCuts, nullptr, nullptr, colBinning_C); + SameEventPairing(grouped_collisions, phosclusters, phosclusters, perCollision_phos, perCollision_phos, fTagPHOSCut, fProbePHOSCuts, fPairCuts, nullptr); + MixedEventPairing(filtered_collisions, phosclusters, phosclusters, perCollision_phos, perCollision_phos, fTagPHOSCut, fProbePHOSCuts, fPairCuts, nullptr, colBinning_C); } - void processEMCEMC(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, aod::SkimEMCClusters const& emcclusters, aod::SkimEMCMTs const& emcmatchedtracks) + void processEMCEMC(MyCollisions const&, MyFilteredCollisions const& filtered_collisions, aod::SkimEMCClusters const& emcclusters) { - SameEventPairing(grouped_collisions, emcclusters, emcclusters, perCollision_emc, perCollision_emc, fTagEMCCut, fProbeEMCCuts, fPairCuts, nullptr, emcmatchedtracks); - MixedEventPairing(filtered_collisions, emcclusters, emcclusters, perCollision_emc, perCollision_emc, fTagEMCCut, fProbeEMCCuts, fPairCuts, nullptr, emcmatchedtracks, colBinning_C); + SameEventPairing(grouped_collisions, emcclusters, emcclusters, perCollision_emc, perCollision_emc, fTagEMCCut, fProbeEMCCuts, fPairCuts, nullptr); + MixedEventPairing(filtered_collisions, emcclusters, emcclusters, perCollision_emc, perCollision_emc, fTagEMCCut, fProbeEMCCuts, fPairCuts, nullptr, colBinning_C); } void processDummy(MyCollisions const&) {} diff --git a/PWGEM/PhotonMeson/Tasks/TaggingPi0.cxx b/PWGEM/PhotonMeson/Tasks/TaggingPi0.cxx deleted file mode 100644 index f12cf270290..00000000000 --- a/PWGEM/PhotonMeson/Tasks/TaggingPi0.cxx +++ /dev/null @@ -1,585 +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 "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.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::pwgem::photonmeson::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 { - - // 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, "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 - EMPhotonEventCut 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; - - Service ccdb; - int mRunNumber; - float d_bz; - - 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"))); - - 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(); - } - - 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::pwgem::photonmeson::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMEMC) { - is_selected_pair = o2::aod::pwgem::photonmeson::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { - is_selected_pair = o2::aod::pwgem::photonmeson::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) { - initCCDB(collision); - 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 constexpr (pairtype == PairType::kPCMDalitzEE) { - auto pos_pv = g2.template posTrack_as(); - auto ele_pv = g2.template negTrack_as(); - std::tuple pair2 = std::make_tuple(pos_pv, ele_pv, d_bz); - if (!IsSelectedPair(g1, pair2, cut1, cut2)) { - continue; - } - } else { - 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::pwgem::photonmeson::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.2) || o2::aod::pwgem::photonmeson::photonpair::DoesV0LegMatchWithCluster(ele, g2, 0.02, 0.4, 0.2)) { - continue; - } - } else if constexpr (pairtype == PairType::kPCMEMC) { - if (o2::aod::pwgem::photonmeson::photonpair::DoesV0LegMatchWithCluster(pos, g2, 0.02, 0.4, 0.5) || o2::aod::pwgem::photonmeson::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. - - 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 constexpr (pairtype == PairType::kPCMDalitzEE) { - auto pos_pv = g2.template posTrack_as(); - auto ele_pv = g2.template negTrack_as(); - std::tuple pair2 = std::make_tuple(pos_pv, ele_pv, d_bz); - if (!IsSelectedPair(g1, pair2, cut1, cut2)) { - continue; - } - } else { - 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); - 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 3cf8a46a2b0..00000000000 --- a/PWGEM/PhotonMeson/Tasks/TaggingPi0MC.cxx +++ /dev/null @@ -1,589 +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 "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.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" -#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 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; - using MyMCTrack = MyMCTracks::iterator; - - // 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, "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 - EMPhotonEventCut 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; - - Service ccdb; - int mRunNumber; - float d_bz; - - 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"))); - - 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(); - } - - 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::pwgem::photonmeson::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMEMC) { - is_selected_pair = o2::aod::pwgem::photonmeson::photonpair::IsSelectedPair(g1, g2, cut1, cut2); - } else if constexpr (pairtype == PairType::kPCMDalitzEE) { - is_selected_pair = o2::aod::pwgem::photonmeson::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) { - initCCDB(collision); - 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) > 0) { - 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 constexpr (pairtype == PairType::kPCMDalitzEE) { - auto pos_pv = g2.template posTrack_as(); - auto ele_pv = g2.template negTrack_as(); - std::tuple pair2 = std::make_tuple(pos_pv, ele_pv, d_bz); - if (!IsSelectedPair(g1, pair2, cut1, cut2)) { - continue; - } - } else { - if (!IsSelectedPair(g1, g2, cut1, cut2)) { - continue; - } - } - - if (!paircut.IsSelected(g1, g2)) { - 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::pwgem::photonmeson::photonpair::DoesV0LegMatchWithCluster(pos1, g2, 0.02, 0.4, 0.2) || o2::aod::pwgem::photonmeson::photonpair::DoesV0LegMatchWithCluster(ele1, g2, 0.02, 0.4, 0.2)) { - continue; - } - } else if constexpr (pairtype == PairType::kPCMEMC) { - if (o2::aod::pwgem::photonmeson::photonpair::DoesV0LegMatchWithCluster(pos1, g2, 0.02, 0.4, 0.5) || o2::aod::pwgem::photonmeson::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/calibTaskEmc.cxx b/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx new file mode 100644 index 00000000000..607a562601d --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx @@ -0,0 +1,1059 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file calibTaskEmc.cxx +/// \brief Task to produce calibration values for EMCal +/// \author M. Hemmer, marvin.hemmer@cern.ch + +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h" +// +#include "PWGEM/Dilepton/Utils/EMTrack.h" +#include "PWGEM/Dilepton/Utils/EventMixingHandler.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include // IWYU pragma: keep +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +enum CentralityEstimator { + None = 0, + CFT0A = 1, + CFT0C, + CFT0M, + NCentralityEstimators +}; + +enum Harmonics { + kNone = 0, + kDirect = 1, + kElliptic = 2, + kTriangluar = 3, + kQuadrangular = 4, + kPentagonal = 5, + kHexagonal = 6, + kHeptagonal = 7, + kOctagonal = 8 +}; + +struct CalibTaskEmc { + static constexpr float MinEnergy = 0.7f; + + // configurable for flow + Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3)"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgDoRotation{"cfgDoRotation", false, "Flag to enable rotation background method"}; + Configurable cfgDownsampling{"cfgDownsampling", 1, "Calculate rotation background only for every collision"}; + Configurable cfgEMCalMapLevelBackground{"cfgEMCalMapLevelBackground", 4, "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", 4, "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 cfgMaxAsymmetry{"cfgMaxAsymmetry", 0.1f, "Maximum allowed asymmetry for photon pairs used in calibration when using EMC-EMC."}; + + // configurable axis + ConfigurableAxis thnConfigAxisInvMass{"thnConfigAxisInvMass", {400, 0.0, 0.8}, ""}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {100, 0., 20.}, ""}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {20, 0., 100.}, ""}; + ConfigurableAxis thnConfigAxisEnergyCalib{"thnConfigAxisEnergyCalib", {200, 0., 20.}, ""}; + + 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> emcSecTMEta{"emcSecTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> emcSecTMPhi{"emcSecTMPhi", {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", true, "flag to use EMCal track matching cut or not"}; + Configurable emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"}; + Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + } emccuts; + + V0PhotonCut fPCMPhotonCut; + struct : ConfigurableGroup { + std::string prefix = "pcmcuts"; + Configurable cfgRequireV0WithITSTPC{"cfgRequireV0WithITSTPC", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfgRequireV0WithITSonly{"cfgRequireV0WithITSonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfgRequireV0WithTPConly{"cfgRequireV0WithTPConly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfgMinPtV0{"cfgMinPtV0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfgMaxPtV0{"cfgMaxPtV0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfgMinEtaV0{"cfgMinEtaV0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfgMaxEtaV0{"cfgMaxEtaV0", 0.8, "max eta for v0 photons at PV"}; + Configurable cfgMinV0Radius{"cfgMinV0Radius", 4.0, "min v0 radius"}; + Configurable cfgMaxV0Radius{"cfgMaxV0Radius", 90.0, "max v0 radius"}; + Configurable cfgMaxAlphaAP{"cfgMaxAlphaAP", 0.95, "max alpha for AP cut"}; + Configurable cfgMaxQtAP{"cfgMaxQtAP", 0.01, "max qT for AP cut"}; + Configurable cfgMinCosPA{"cfgMinCosPA", 0.999, "min V0 CosPA"}; + Configurable cfgMaxPCA{"cfgMaxPCA", 1.5, "max distance btween 2 legs"}; + Configurable cfgMaxChi2KF{"cfgMaxChi2KF", 1e+10, "max chi2/ndf with KF"}; + Configurable cfgRejectV0OnITSib{"cfgRejectV0OnITSib", true, "flag to reject V0s on ITSib"}; + + Configurable cfgMinNClusterTPC{"cfgMinNClusterTPC", 0, "min ncluster tpc"}; + Configurable cfgMinNCrossedRows{"cfgMinNCrossedRows", 40, "min ncrossed rows"}; + Configurable cfgMaxFracSharedClusterTPC{"cfgMaxFracSharedClusterTPC", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfgMaxChi2TPC{"cfgMaxChi2TPC", 4.0, "max chi2/NclsTPC"}; + Configurable cfgMaxChi2ITS{"cfgMaxChi2ITS", 36.0, "max chi2/NclsITS"}; + Configurable cfgMinTPCNSigmaEl{"cfgMinTPCNSigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfgMaxTPCNSigmaEl{"cfgMaxTPCNSigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfgDisableITSOnly{"cfgDisableITSOnly", false, "flag to disable ITSonly tracks"}; + Configurable cfgDisableTPCOnly{"cfgDisableTPCOnly", false, "flag to disable TPConly tracks"}; + } pcmcuts; + + 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 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, -9.0f, -8.f, -7.0f, -6.f, -5.0f, -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 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"}; + Configurable cfgMixingDepth{"cfgMixingDepth", 2, "Mixing depth"}; + } mixingConfig; + + SliceCache cache; + 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 PCMPhotons = soa::Join; + using Colls = soa::Join; + + // for event mixing + using MyEMH = o2::aod::pwgem::dilepton::utils::EventMixingHandler, std::pair, o2::aod::pwgem::dilepton::utils::EMTrack>; + MyEMH* emh1 = nullptr; + MyEMH* emh2 = nullptr; + + Preslice perCollisionEMC = aod::emccluster::emeventId; + Preslice perCollisionPCM = aod::v0photonkf::emeventId; + + using BinningType = ColumnBinningPolicy; + BinningType binningOnPositions{{mixingConfig.cfgVtxBins, mixingConfig.cfgCentBins}, true}; + Pair pairPCMEMC{binningOnPositions, mixingConfig.cfgMixingDepth, -1, &cache}; // indicates that mixingConfig.cfgMixingDepth events should be mixed and under/overflow (-1) to be ignored + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + o2::emcal::Geometry* emcalGeom; + o2::emcal::BadChannelMap* mBadChannels; + // 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; + + // static constexpr + static constexpr int64_t NMinPhotonRotBkg = 3; + static constexpr int64_t NMinPhotonRotBkgMixed = 2; + + // Usage when cfgEnableNonLin is enabled + std::unique_ptr fEMCalCorrectionFactor; // ("fEMCalCorrectionFactor","(1 + [0]/x + [1]/x^2) / (1 + [2]/x)", 0.3, 100.); + + // 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"); + fEMCCut.SetTrackMatchingEtaParams(emccuts.cfgEMCTMEta->at(0), emccuts.cfgEMCTMEta->at(1), emccuts.cfgEMCTMEta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.cfgEMCTMPhi->at(0), emccuts.cfgEMCTMPhi->at(1), emccuts.cfgEMCTMPhi->at(2)); + + fEMCCut.SetSecTrackMatchingEtaParams(emccuts.emcSecTMEta->at(0), emccuts.emcSecTMEta->at(1), emccuts.emcSecTMEta->at(2)); + fEMCCut.SetSecTrackMatchingPhiParams(emccuts.emcSecTMPhi->at(0), emccuts.emcSecTMPhi->at(1), emccuts.emcSecTMPhi->at(2)); + 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); + fEMCCut.SetUseTM(emccuts.cfgEMCUseTM.value); // disables or enables TM + fEMCCut.SetUseSecondaryTM(emccuts.emcUseSecondaryTM.value); // disables or enables secondary TM + } + + void DefinePCMCut() + { + fPCMPhotonCut = V0PhotonCut("fPCMPhotonCut", "fPCMPhotonCut"); + + // for v0 + fPCMPhotonCut.SetV0PtRange(pcmcuts.cfgMinPtV0, pcmcuts.cfgMaxPtV0); + fPCMPhotonCut.SetV0EtaRange(pcmcuts.cfgMinEtaV0, pcmcuts.cfgMaxEtaV0); + fPCMPhotonCut.SetMinCosPA(pcmcuts.cfgMinCosPA); + fPCMPhotonCut.SetMaxPCA(pcmcuts.cfgMaxPCA); + fPCMPhotonCut.SetMaxChi2KF(pcmcuts.cfgMaxChi2KF); + fPCMPhotonCut.SetRxyRange(pcmcuts.cfgMinV0Radius, pcmcuts.cfgMaxV0Radius); + fPCMPhotonCut.SetAPRange(pcmcuts.cfgMaxAlphaAP, pcmcuts.cfgMaxQtAP); + fPCMPhotonCut.RejectITSib(pcmcuts.cfgRejectV0OnITSib); + + // for track + fPCMPhotonCut.SetMinNClustersTPC(pcmcuts.cfgMinNClusterTPC); + fPCMPhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfgMinNCrossedRows); + fPCMPhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); + fPCMPhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfgMaxFracSharedClusterTPC); + fPCMPhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfgMaxChi2TPC); + fPCMPhotonCut.SetTPCNsigmaElRange(pcmcuts.cfgMinTPCNSigmaEl, pcmcuts.cfgMaxTPCNSigmaEl); + fPCMPhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfgMaxChi2ITS); + fPCMPhotonCut.SetNClustersITS(0, 7); + fPCMPhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); + fPCMPhotonCut.SetDisableITSonly(pcmcuts.cfgDisableITSOnly); + fPCMPhotonCut.SetDisableTPConly(pcmcuts.cfgDisableTPCOnly); + fPCMPhotonCut.SetRequireITSTPC(pcmcuts.cfgRequireV0WithITSTPC); + fPCMPhotonCut.SetRequireITSonly(pcmcuts.cfgRequireV0WithITSonly); + fPCMPhotonCut.SetRequireTPConly(pcmcuts.cfgRequireV0WithTPConly); + } + + void init(InitContext&) + { + defineEMEventCut(); + defineEMCCut(); + 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 thAxisTanThetaPhi{mesonConfig.thConfigAxisTanThetaPhi, "atan(#Delta#theta/#Delta#varphi)"}; + const AxisSpec thAxisClusterEnergy{thnConfigAxisPt, "#it{E} (GeV)"}; + const AxisSpec thAxisEnergyCalib{thnConfigAxisEnergyCalib, "#it{E}_{clus} (GeV)"}; + const AxisSpec thAxisAlpha{100, -1., +1, "#alpha"}; + const AxisSpec thAxisEnergy{1000, 0., 100., "#it{E}_{clus} (GeV)"}; + + 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}); + + 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 (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("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}); + } + + 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(); + + fEMCalCorrectionFactor = std::make_unique("fEMCalCorrectionFactor", "(1 + [0]/x + [1]/x^2) / (1 + [2]/x)", 0.3, 100.); + fEMCalCorrectionFactor->SetParameters(-5.33426e-01, 1.40144e-02, -5.24434e-01); + }; // 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; + } + + /// Get the centrality + /// \param collision is the collision with the centrality information + template + float getCentrality(TCollision 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; + } + + 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 + } + } + } + } + + /// \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, TCollision const& collision) + { + // if less than 3 clusters are present skip event since we need at least 3 clusters + if (photons_coll.size() < NMinPhotonRotBkg) { + 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; + } + float energyCorrectionFactor = 1.f; + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(photon.e() > MinEnergy ? photon.e() : MinEnergy); + ROOT::Math::PtEtaPhiMVector photon3(energyCorrectionFactor * photon.pt(), photon.eta(), photon.phi(), 0.); + if (iCellIDPhoton1 >= 0) { + if (std::fabs((photon1.E() - photon3.E()) / (photon1.E() + photon3.E()) < cfgMaxAsymmetry)) { // 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()) < cfgMaxAsymmetry)) { // 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; + } + + /// \brief Calculate background using rotation background method for calib + /// \param meson mother particle from photon1 & photon2 which defines rotation axis + /// \param photon1 first photon (EMC) which will be rotated + /// \param photon2 second photon (PCM) which will be rotated + /// \param photonsEMC sub table of EMC photons of current event which will be combined with rotated photon2 + /// \param photonsPCM sub table of PCM photons of current event which will be combined with rotated photon1 + /// \param ig1 index of photon1 + /// \param ig2 index of photon2 + /// \param cent current collisions centrality + template + void rotationBackgroundCalibEMCPCM(const ROOT::Math::PtEtaPhiMVector& meson, ROOT::Math::PtEtaPhiMVector photon1, ROOT::Math::PtEtaPhiMVector photon2, TPhotonEMC const& photonsEMC, TPhotonPCM const& photonsPCM, unsigned int ig1, unsigned int ig2, float cent) + { + // we need at least 2 clusters or 2 pcm photons for rotation + if (photonsEMC.size() < NMinPhotonRotBkgMixed || photonsPCM.size() < NMinPhotonRotBkgMixed) { + return; + } + 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 (iCellIDPhoton1 == -1 && iCellIDPhoton2 == -1) { + return; + } + // Combining with EMCal photons from event + if (photonsEMC.size() >= NMinPhotonRotBkgMixed) { + for (const auto& photon : photonsEMC) { + if (photon.globalIndex() == ig1) { + continue; + } + if (!(fEMCCut.IsSelected(photon))) { + continue; + } + if (checkEtaPhi1D(photon.eta(), RecoDecay::constrainAngle(photon.phi())) >= cfgEMCalMapLevelBackground.value) { + continue; + } + float energyCorrectionFactor = 1.f; + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(photon.e() > MinEnergy ? photon.e() : MinEnergy); + ROOT::Math::PtEtaPhiMVector photon3(energyCorrectionFactor * photon.pt(), photon.eta(), photon.phi(), 0.); + if (iCellIDPhoton2 >= 0) { + ROOT::Math::PtEtaPhiMVector mother = photon2 + photon3; + float openingAngle2 = std::acos(photon2.Vect().Dot(photon3.Vect()) / (photon2.P() * photon3.P())); + + if (openingAngle2 > mesonConfig.minOpenAngle && thnConfigAxisInvMass.value[1] <= mother.M() && thnConfigAxisInvMass.value.back() >= mother.M() && thnConfigAxisPt.value[1] <= mother.Pt() && thnConfigAxisPt.value.back() >= mother.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"), mother.M(), mother.E() / 2., cent); + } + } else { + registry.fill(HIST("hSparseCalibBack"), mother.M(), mother.E() / 2., cent); + } + } + } + } // end of loop over third photon + } // check that we have at least 2 clusters + + // Combining with PCM photons from event + if (photonsPCM.size() >= NMinPhotonRotBkgMixed) { + for (const auto& photon : photonsPCM) { + if (photon.globalIndex() == ig2) { + continue; + } + if (!(fPCMPhotonCut.IsSelected(photon))) { + continue; + } + ROOT::Math::PtEtaPhiMVector photon3(photon.pt(), photon.eta(), photon.phi(), 0.); + if (iCellIDPhoton1 >= 0) { + ROOT::Math::PtEtaPhiMVector mother = photon1 + photon3; + float openingAngle2 = std::acos(photon1.Vect().Dot(photon3.Vect()) / (photon1.P() * photon3.P())); + + if (openingAngle2 > mesonConfig.minOpenAngle && thnConfigAxisInvMass.value[1] <= mother.M() && thnConfigAxisInvMass.value.back() >= mother.M() && thnConfigAxisPt.value[1] <= mother.Pt() && thnConfigAxisPt.value.back() >= mother.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"), mother.M(), mother.E() / 2., cent); + } + } else { + registry.fill(HIST("hSparseCalibBack"), mother.M(), mother.E() / 2., cent); + } + } + } + } // end of loop over third photon + } // check that we have at least 2 clusters + return; + } + + // EMCal calibration same event + void processEMCalCalib(Colls const& collisions, EMCalPhotons const& clusters, PCMPhotons const&) + { + float energyCorrectionFactor = 1.f; + 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; + } + 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; + } + } + + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g2.e() > MinEnergy ? g2.e() : MinEnergy); + ROOT::Math::PtEtaPhiMVector v2(energyCorrectionFactor * g2.pt(), g2.eta(), g2.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()) < cfgMaxAsymmetry)) { // 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(CalibTaskEmc, processEMCalCalib, "Process EMCal calibration same event", true); + + // EMCal calibration + void processEMCalPCMCalib(Colls const& collisions, EMCalPhotons const& clusters, PCMPhotons const& photons, aod::V0Legs const&) + { + float energyCorrectionFactor = 1.f; + int nColl = 1; + for (const auto& collision : collisions) { + 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; + } + 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 + + auto photonsEMCPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + auto photonsPCMPerCollision = photons.sliceBy(perCollisionPCM, collision.globalIndex()); + + if (emccuts.cfgEnableQA) { + for (const auto& photon : photonsEMCPerCollision) { + 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(CombinationsFullIndexPolicy(photonsEMCPerCollision, photonsPCMPerCollision))) { + if (!(fEMCCut.IsSelected(g1)) || !(fPCMPhotonCut.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; + } + } + + // EMCal photon v1 + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + // PCM photon v2s + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.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) { + rotationBackgroundCalibEMCPCM(vMeson, v1, v2, photonsEMCPerCollision, photonsPCMPerCollision, g1.globalIndex(), g2.globalIndex(), cent); + } + } + 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("hSparseCalibSE"), vMeson.M(), vMeson.E() / 2., getCentrality(collision)); + } + if (cfgDoRotation) { + if (nColl % cfgDownsampling.value == 0) { + nColl = 1; // reset counter + } else { + nColl++; + } + } + } + } + PROCESS_SWITCH(CalibTaskEmc, processEMCalPCMCalib, "Process EMCal calibration using PCM-EMC same event", true); + + // EMCal calibration mixed event + void processEMCalCalibMixed(Colls const&, EMCalPhotons const&, PCMPhotons const&) + { + float energyCorrectionFactor = 1.f; + + SameKindPair pair{binningOnPositions, mixingConfig.cfgMixingDepth, -1, &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; + } + runNow = c1.runNumber(); + if (runNow != runBefore) { + initCCDB(c1); + runBefore = runNow; + } + 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; + } + } + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g2.e() > MinEnergy ? g2.e() : MinEnergy); + ROOT::Math::PtEtaPhiMVector v2(energyCorrectionFactor * g2.pt(), g2.eta(), g2.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; + } + if (std::fabs((v1.E() - v2.E()) / (v1.E() + v2.E()) < cfgMaxAsymmetry)) { // only use symmetric decays + registry.fill(HIST("hClusterCutsMixed"), 6); + registry.fill(HIST("hSparseCalibBack"), vMeson.M(), vMeson.E() / 2., getCentrality(c1)); + } + } + } + } + PROCESS_SWITCH(CalibTaskEmc, processEMCalCalibMixed, "Process EMCal calibration mixed event", false); + + // EMCal calibration + void processEMCalPCMCalibMixed(Colls const&, EMCalPhotons const&, PCMPhotons const&, aod::V0Legs const&) + { + float energyCorrectionFactor = 1.f; + + LOG(info) << "Beginning of processEMCalPCMCalibMixed"; + + for (const auto& [c1, photonEMC, c2, photonPCM] : pairPCMEMC) { + 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; + } + runNow = c1.runNumber(); + if (runNow != runBefore) { + initCCDB(c1); + runBefore = runNow; + } + for (const auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photonEMC, photonPCM))) { + if (!(fEMCCut.IsSelected(g1)) || !(fPCMPhotonCut.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; + } + } + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.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("hSparseCalibBack"), vMeson.M(), vMeson.E() / 2., getCentrality(c1)); + } + } + } + PROCESS_SWITCH(CalibTaskEmc, processEMCalPCMCalibMixed, "Process EMCal calibration with PCM-EMC mixed event", false); + +}; // End struct CalibTaskEmc + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx b/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx new file mode 100644 index 00000000000..3a080016299 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/compconvbuilder.cxx @@ -0,0 +1,876 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file compconvbuilder.cxx +/// \brief QA task for photons in the EM and LF builder +/// \author S. Mrozinski, smrozins@cern.ch + +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#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::aod; +using namespace o2::soa; +using namespace o2::constants; + +using namespace o2::aod::pwgem::dilepton::utils::mcutil; + +using MyV0Photons = soa::Join; +using MyMCV0Legs = soa::Join; +using MyMCV0Leg = MyMCV0Legs::iterator; + +using MyCollisions = soa::Join; +using MyCollision = MyCollisions::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + +using MyStraCollisions = soa::Join; +using MyStraCollision = MyStraCollisions::iterator; + +using MyTracksIUMC = soa::Join; + +using V0DerivedMCDatas = soa::Join; + +using DauTracks = soa::Join; + +struct Compconvbuilder { + HistogramRegistry registry{"Compconvbuilder"}; + + enum ConversionBuilderID { + EMBuilder = 0, + LFBuilder = 1, + EMOnly = 2, + LFOnly = 3, + Common = 4, + NConversionBuilder + }; + + static constexpr std::string_view kConversionBuilder[NConversionBuilder] = {"EMBuilder/", "LFBuilder/", "EMOnly/", "LFOnly/", "Common/"}; + static constexpr std::string_view kEventTypes[2] = {"before/", "after/"}; + + 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; + + 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); + } + + // Link V0-photons to their collision + Preslice perV0PhotonCollision = aod::v0photonkf::emeventId; + + void init(InitContext const& /*ctx*/) + { + + defineEMEventCut(); + + for (int i = 0; i < NConversionBuilder; ++i) { + + registry.add(string(kConversionBuilder[i]) + "hPt", ";p_{T} (GeV/c); Counts", kTH1F, {{1000, 0., 10.}}); + registry.add(string(kConversionBuilder[i]) + "hR", ";R_{conv} (cm); Counts", kTH1F, {{100, 0., 100.}}); + + registry.add(string(kConversionBuilder[i]) + "hEta", ";#eta; Counts", kTH1F, {{200, -1.0f, 1.0f}}); + + registry.add(string(kConversionBuilder[i]) + "hcosPA", ";R_{conv} (cm); Counts", kTH1F, {{100, 0.99f, 1.0f}}); + + registry.add(string(kConversionBuilder[i]) + "MatchedDeltaRec", ";#Delta colID_{rec};Counts", kTH1F, {{21, -10.5, 10.5}}); + + registry.add(string(kConversionBuilder[i]) + "hZ", ";z (cm);Counts", kTH1F, {{200, -100, 100}}); + + registry.add(string(kConversionBuilder[i]) + "hZR", "conversion point in RZ;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100, 100}, {200, 0.0f, 100.0f}}); + + registry.add(string(kConversionBuilder[i]) + "hAP", "AP plot;#alpha;q_{T} (GeV/c)", kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}); + + registry.add(string(kConversionBuilder[i]) + "ResolutionGen/Z_res", "Conversion radius resolution;z_{conv, gen} (cm);R_{conv, gen} (cm);#varphi_{gen} (rad.);#eta_{gen};p_{T, gen};z_{conv, rec} - z_{conv, gen} (cm);", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {120, -30, 30} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionGen/R_res", "Conversion radius resolution;z_{conv, gen} (cm);R_{conv, gen} (cm);#varphi_{gen} (rad.);#eta_{gen};p_{T, gen};R_{conv, rec} - R_{conv, gen} (cm);", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {120, -30, 30} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionGen/Phi_res", "#varphi resolution;z_{conv, gen} (cm);R_{conv, gen} (cm);#varphi_{gen} (rad.);#eta_{gen};p_{T, gen};#varphi_{conv, rec} - #varphi_{conv, gen} (cm);", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {100, -0.2f, 0.2f} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionGen/Pt_res", "Conversion radius resolution;z_{conv, gen} (cm);R_{conv, gen} (cm);#varphi_{gen} (rad.);#eta_{gen};p_{T, gen};p_{T, rec} - p_{T, gen}/p_{T, gen};", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {200, -1.0f, 1.0f} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionGen/Eta_res", "Conversion radius resolution;z_{conv, gen} (cm);R_{conv, gen} (cm);#varphi_{gen} (rad.);#eta_{gen};p_{T, gen};#eta_{conv, rec} - #eta_{conv, gen} (cm);", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {100, -0.5f, 0.5f} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionRec/Z_res", "Conversion radius resolution;z_{conv, rec} (cm);R_{conv, rec} (cm);#varphi_{rec} (rad.);#eta_{rec};p_{T, rec};z_{conv, rec} - z_{conv, gen} (cm);", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {120, -30, 30} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionRec/R_res", "Conversion radius resolution;z_{conv, rec} (cm);R_{conv, rec} (cm);#varphi_{rec} (rad.);#eta_{rec};p_{T, rec};R_{conv, rec} - R_{conv, gen} (cm);", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {120, -30, 30} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionRec/Phi_res", "#varphi resolution;z_{conv, rec} (cm);R_{conv, rec} (cm);#varphi_{rec} (rad.);#eta_{rec};p_{T, rec};#varphi_{conv, rec} - #varphi_{conv, gen} (cm);", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {100, -0.2f, 0.2f} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionRec/Pt_res", "Conversion radius resolution;z_{conv, rec} (cm);R_{conv, rec} (cm);#varphi_{rec} (rad.);#eta_{rec};p_{T, rec};p_{T, rec} - p_{T, gen}/p_{T, gen};", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {200, -1.0f, 1.0f} + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "ResolutionRec/Eta_res", "Conversion radius resolution;z_{conv, rec} (cm);R_{conv, rec} (cm);#varphi_{rec} (rad.);#eta_{rec};p_{T, rec};#eta_{conv, rec} - #eta_{conv, gen} (cm);", + kTHnSparseF, + {{200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + {100, -0.5f, 0.5f} + + }, + false); + registry.add(string(kConversionBuilder[i]) + "ConvInfo", "Conversion radius resolution;x_{conv} (cm);y_{conv} (cm);z_{conv} (cm);R_{conv} (cm);#varphi (rad.);#eta;p_{T, gen};", + kTHnSparseF, + { + {200, -100, 100}, + {200, -100, 100}, + {200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}, + + }, + false); + + registry.add(string(kConversionBuilder[i]) + "V0Leg/Asymmetry", "", kTH1F, {{100, 0, 1}}); + + auto hCollisionCounter = registry.add(string(kConversionBuilder[i]) + "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"); + + registry.add(string(kConversionBuilder[i]) + "Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); + registry.add(string(kConversionBuilder[i]) + "Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + registry.add(string(kConversionBuilder[i]) + "Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", kTH1F, {{6001, -0.5, 6000.5}}, false); + registry.add(string(kConversionBuilder[i]) + "Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", kTH2F, {{300, 0, 6000}, {300, 0, 6000}}, false); + registry.add(string(kConversionBuilder[i]) + "Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", kTH1F, {{110, 0, 110}}, false); + registry.add(string(kConversionBuilder[i]) + "Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", kTH1F, {{110, 0, 110}}, false); + registry.add(string(kConversionBuilder[i]) + "Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", kTH1F, {{110, 0, 110}}, false); + registry.add(string(kConversionBuilder[i]) + "Event/before/hCentFT0MvsMultNTracksPV", "hCentFT0MvsMultNTracksPV;centrality FT0M (%);N_{track} to PV", kTH2F, {{110, 0, 110}, {600, 0, 6000}}, false); + registry.add(string(kConversionBuilder[i]) + "Event/before/hMultFT0MvsMultNTracksPV", "hMultFT0MvsMultNTracksPV;mult. FT0M;N_{track} to PV", kTH2F, {{600, 0, 6000}, {600, 0, 6000}}, false); + registry.addClone(string(kConversionBuilder[i]) + "Event/before/", string(kConversionBuilder[i]) + "Event/after/"); + } + + registry.add("truePhotons/hPt_Converted", "Converted Photons; p_{T} (GeV/c); Counts", kTH1F, {{100, 0., 10.}}); + registry.add("truePhotons/hR_Converted", "Converted Photons; R (cm); Counts", kTH1F, {{100, 0., 100.}}); + + registry.add("truePhotons/Sparse_Converted", "Conversion radius resolution;x_{conv} (cm);z_{conv} (cm);y_{conv} (cm);R_{conv} (cm);#varphi (rad.);#eta;p_{T, gen};", + kTHnSparseF, + {{200, -100, 100}, + {200, -100, 100}, + {200, -100, 100}, + {200, 0, 100}, + {90, 0, math::TwoPI}, + {200, -1.0f, 1.0f}, + {500, 0, 10}}, + false); + + auto h = registry.add("EMBuilder/hV0SignType", "Crosscheck", kTH1F, {{3, 0.5, 4.5}}, false); + h->GetXaxis()->SetBinLabel(1, "Same-sign"); + h->GetXaxis()->SetBinLabel(2, "Opposite-sign"); + h->GetXaxis()->SetBinLabel(3, "Zero-sign"); + + auto h2 = registry.add("EMBuilder/hV0ElectronPositronTrue", "pair in MC truth;;counts", kTH1F, {{2, -0.5, 1.5}}); + h2->GetXaxis()->SetBinLabel(1, "Mismatch"); + h2->GetXaxis()->SetBinLabel(2, "Good"); + } + + template + void fillEventInfo(TCollision const& collision, const float /*weight*/ = 1.f) + { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 1.0); + + if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 2.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 3.0); + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 4.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 5.0); + } + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 6.0); + } + + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 7.0); + } + + if (collision.sel8()) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 8.0); + } + if (std::fabs(collision.posZ()) < eventcuts.cfgZvtxMax) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 9.0); + } + + registry.fill(HIST(kConversionBuilder[type]) + HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hMultNTracksPVeta1"), collision.multNTracksPVeta1()); + } + + template + void fillLegInfo(auto& v0, auto& posleg, auto& negleg) + { + if constexpr (type == 0) { + + float ptPos = posleg.pt(); + float ptNeg = negleg.pt(); + float asym = (ptPos - ptNeg) / (ptPos + ptNeg); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("V0Leg/Asymmetry"), asym); + + } else { + + float ptPos = v0.postrackpt(); + float ptNeg = negleg.negtrackpt(); + float asym = (ptPos - ptNeg) / (ptPos + ptNeg); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("V0Leg/Asymmetry"), asym); + } + } + + template + void fillV0Info(auto& v0, auto& v0MC, auto& mcleg) + { + registry.fill(HIST(kConversionBuilder[type]) + HIST("hPt"), v0.pt()); + registry.fill(HIST(kConversionBuilder[type]) + HIST("hEta"), v0.eta()); + registry.fill(HIST(kConversionBuilder[type]) + HIST("hAP"), v0.alpha(), v0.qtarm()); + + if constexpr (type == EMBuilder || type == EMOnly) { + registry.fill(HIST(kConversionBuilder[type]) + HIST("hZ"), v0.vz()); + registry.fill(HIST(kConversionBuilder[type]) + HIST("hcosPA"), v0.cospa()); + registry.fill(HIST(kConversionBuilder[type]) + HIST("hZR"), v0.vz(), v0.v0radius()); + + float deltapT = v0.pt() - v0MC.pt(); + float deltaZ = v0.vz() - mcleg.vz(); + float deltaPhi = v0.phi() - v0MC.phi(); + float deltaEta = v0.eta() - v0MC.eta(); + float deltaR = v0.v0radius() - std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/Z_res"), + mcleg.vz(), + std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), + v0MC.phi(), + v0MC.eta(), + v0MC.pt(), + deltaZ); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/R_res"), + mcleg.vz(), + std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), + v0MC.phi(), + v0MC.eta(), + v0MC.pt(), + deltaR); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/Phi_res"), + mcleg.vz(), + std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), + v0MC.phi(), + v0MC.eta(), + v0MC.pt(), + deltaPhi); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/Pt_res"), + mcleg.vz(), + std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), + v0MC.phi(), + v0MC.eta(), + v0MC.pt(), + deltapT); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/Eta_res"), + mcleg.vz(), + std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), + v0MC.phi(), + v0MC.eta(), + v0MC.pt(), + deltaEta); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/Z_res"), + v0.vz(), + v0.v0radius(), + v0.phi(), + v0.eta(), + v0.pt(), + deltaZ); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/R_res"), + v0.vz(), + v0.v0radius(), + v0.phi(), + v0.eta(), + v0.pt(), + deltaR); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/Phi_res"), + v0.vz(), + v0.v0radius(), + v0.phi(), + v0.eta(), + v0.pt(), + deltaPhi); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/Pt_res"), + v0.vz(), + v0.v0radius(), + v0.phi(), + v0.eta(), + v0.pt(), + deltapT); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/Eta_res"), + v0.vz(), + v0.v0radius(), + v0.phi(), + v0.eta(), + v0.pt(), + deltaEta); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ConvInfo"), + v0.vx(), // 0 + v0.vy(), // 1 + v0.vz(), // 2 + v0.v0radius(), // 3 + v0.phi(), // 4 + v0.eta(), // 5 + v0.pt()); // 6 + + } else { + registry.fill(HIST(kConversionBuilder[type]) + HIST("hZ"), v0.z()); + registry.fill(HIST(kConversionBuilder[type]) + HIST("hcosPA"), v0.v0cosPA()); + registry.fill(HIST(kConversionBuilder[type]) + HIST("hZR"), v0.z(), v0.v0radius()); + + float deltaR = v0.v0radius() - std::hypot(v0MC.xMC(), v0MC.yMC()); + + float phiRec = v0.phi(); + RecoDecay::constrainAngle(phiRec); + + float phiMC = std::atan2(v0MC.pyMC(), v0MC.pxMC()); + RecoDecay::constrainAngle(phiMC); + + float deltaPhi = phiRec - phiMC; + RecoDecay::constrainAngle(deltaPhi); + + float etaGen = 0.5f * std::log((std::hypot(v0MC.pxMC(), v0MC.pyMC(), v0MC.pzMC()) + v0MC.pzMC()) / (std::hypot(v0MC.pxMC(), v0MC.pyMC(), v0MC.pzMC()) - v0MC.pzMC())); + + float etaRec = 0.5f * std::log((std::hypot(v0.px(), v0.py(), v0.pz()) + v0.pz()) / (std::hypot(v0.px(), v0.py(), v0.pz()) - v0.pz())); + + float deltapT = v0.pt() - v0MC.ptMC(); + float deltaEta = etaRec - etaGen; + float deltaZ = v0.z() - v0MC.zMC(); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/Z_res"), + v0MC.zMC(), + std::hypot(v0MC.xMC(), v0MC.yMC()), + phiMC, + etaGen, + v0MC.ptMC(), + deltaZ); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/R_res"), + v0MC.zMC(), + std::hypot(v0MC.xMC(), v0MC.yMC()), + phiMC, + etaGen, + v0MC.ptMC(), + deltaR); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/Phi_res"), + v0MC.zMC(), + std::hypot(v0MC.xMC(), v0MC.yMC()), + phiMC, + etaGen, + v0MC.ptMC(), + deltaPhi); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/Pt_res"), + v0MC.zMC(), + std::hypot(v0MC.xMC(), v0MC.yMC()), + phiMC, + etaGen, + v0MC.ptMC(), + deltapT); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionGen/Eta_res"), + v0MC.zMC(), + std::hypot(v0MC.xMC(), v0MC.yMC()), + phiMC, + etaGen, + v0MC.ptMC(), + deltaEta); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/Z_res"), + v0.z(), + v0.v0radius(), + phiRec, + v0.eta(), + v0.pt(), + deltaZ); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/R_res"), + v0.z(), + v0.v0radius(), + phiRec, + v0.eta(), + v0.pt(), + deltaR); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/Phi_res"), + v0.z(), + v0.v0radius(), + phiRec, + v0.eta(), + v0.pt(), + deltaPhi); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/Eta_res"), + v0.z(), + v0.v0radius(), + phiRec, + v0.eta(), + v0.pt(), + deltaEta); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ResolutionRec/Pt_res"), + v0.z(), + v0.v0radius(), + phiRec, + v0.eta(), + v0.pt(), + deltapT); + + registry.fill(HIST(kConversionBuilder[type]) + HIST("ConvInfo"), + v0.x(), + v0.y(), + v0.z(), + v0.v0radius(), + phiRec, + v0.eta(), + v0.pt()); + } + + registry.fill(HIST(kConversionBuilder[type]) + HIST("hR"), v0.v0radius()); + } + + Preslice perCollisionMCDerived = o2::aod::v0data::straCollisionId; + + void processLFV0sMC(MyStraCollisions const& stracollisions, + soa::Join const&, + V0DerivedMCDatas const& strangeV0s, + DauTracks const&) + { + + for (const auto& collision : stracollisions) { + + fillEventInfo<0, LFBuilder>(collision); + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + fillEventInfo<1, LFBuilder>(collision); + + registry.fill(HIST((kConversionBuilder[1])) + HIST("Event/before/hCollisionCounter"), 10.0); + registry.fill(HIST((kConversionBuilder[1])) + HIST("Event/after/hCollisionCounter"), 10.0); // accepted + + auto myV0s = strangeV0s.sliceBy(perCollisionMCDerived, collision.globalIndex()); + + for (auto const& v0 : myV0s) { + if (!v0.has_v0MCCore()) { + continue; + } + + auto v0MC = v0.v0MCCore_as>(); + + if (v0MC.pdgCode() != kGamma || !v0MC.isPhysicalPrimary()) { + continue; + } + + auto posTrack = v0.template posTrackExtra_as(); + + fillV0Info(v0, v0MC, posTrack); + } + } + } + + Preslice perCollision = aod::v0photonkf::emeventId; + + void processEMV0sMC(MyV0Photons const& v0s, aod::EMMCParticles const& mcparticles, MyMCV0Legs const&, MyCollisions const& collisions) + { + + for (const auto& collision : collisions) { + + fillEventInfo<0, EMBuilder>(collision); + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + fillEventInfo<1, EMBuilder>(collision); + + registry.fill(HIST((kConversionBuilder[0])) + HIST("Event/before/hCollisionCounter"), 10.0); // accepted + registry.fill(HIST((kConversionBuilder[0])) + HIST("Event/after/hCollisionCounter"), 10.0); // accepted + + auto v0PhotonsColl = v0s.sliceBy(perCollision, collision.globalIndex()); + + for (auto const& v0 : v0PhotonsColl) { + + auto pos = v0.posTrack_as(); + auto ele = v0.negTrack_as(); + auto posmc = pos.template emmcparticle_as(); + auto elemc = ele.template emmcparticle_as(); + + int photonid = FindCommonMotherFrom2Prongs(posmc, elemc, kPositron, kElectron, kGamma, mcparticles); + + auto mcphoton = mcparticles.iteratorAt(photonid); + + if (mcphoton.isPhysicalPrimary()) { + + fillV0Info(v0, mcphoton, elemc); + } + + if (pos.sign() * ele.sign() > 0) { + registry.fill(HIST("EMBuilder/hV0SignType"), 1); // same-sign + } else if (pos.sign() * ele.sign() < 0) { + registry.fill(HIST("EMBuilder/hV0SignType"), 2); // opposite-sign + } else { + registry.fill(HIST("EMBuilder/hV0SignType"), 3); // zero or undefined + } + + if ((posmc.pdgCode() == kElectron && elemc.pdgCode() == kPositron) || (posmc.pdgCode() == kPositron && elemc.pdgCode() == kElectron)) { + registry.fill(HIST("EMBuilder/hV0ElectronPositronTrue"), 1); // good + } else { + registry.fill(HIST("EMBuilder/hV0ElectronPositronTrue"), 0); // mismatch + } + } + } + } + + PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; + + void processConvV0s(MyCollisions const& collisions, + MyMCCollisions const&, + aod::EMMCParticles const& mcparticles, + MyTracksIUMC const& tracks) + { + for (const auto& collision : collisions) { + + const float minR = 5.0f; + const float maxR = 90.f; + + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + auto mccollision = collision.template emmcevent_as(); + + auto mcstack = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); + auto mcTracksColl = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); + + std::unordered_map mc2trk; + for (const auto& trk : tracks) { + if (trk.mcParticleId() >= 0) { + mc2trk[trk.mcParticleId()] = trk.globalIndex(); + } + } + + for (const auto& mc : mcTracksColl) { + if (mc.pdgCode() != kGamma || !mc.isPhysicalPrimary()) { + continue; + } + + auto daughters = mc.daughtersIds(); + if (daughters.size() != 2) { // o2-linter: disable=magic-number (this is pretty clear and not magic) + continue; + } + + auto d1 = mcparticles.iteratorAt(daughters[0]); + auto d2 = mcparticles.iteratorAt(daughters[1]); + + if (std::abs(d1.pdgCode()) != kElectron || std::abs(d2.pdgCode()) != kElectron) { + continue; + } + + float r = std::hypot(d1.vx(), d1.vy()); + if (r < minR || r > maxR) { + continue; + } + + registry.fill(HIST("truePhotons/hPt_Converted"), mc.pt()); + registry.fill(HIST("truePhotons/hR_Converted"), r); + + registry.fill(HIST("truePhotons/Sparse_Converted"), d1.vx(), mc.y(), d1.vz(), r, mc.phi(), mc.eta(), mc.pt()); + + int id1 = mc2trk.count(d1.globalIndex()) ? mc2trk[d1.globalIndex()] : -1; + int id2 = mc2trk.count(d2.globalIndex()) ? mc2trk[d2.globalIndex()] : -1; + if (id1 < 0 || id2 < 0) { + continue; + } + } + } + } + + void processMatchCategories( + MyCollisions const& collisions, + aod::EMMCEvents const&, + MyTracksIUMC const& tracksgen, + MyV0Photons const& emV0s, + soa::Join const&, + V0DerivedMCDatas const& lfV0s, + MyMCV0Legs const&, + aod::EMMCParticles const&, + aod::McParticles const& mcparticles, + DauTracks const&) + { + std::unordered_map trackToMcLabel; + for (auto const& t : tracksgen) { + int label = t.mcParticleId(); + if (label >= 0) { + trackToMcLabel[t.globalIndex()] = label; + } + } + + for (const auto& collision : collisions) { + if (!fEMEventCut.IsSelected(collision)) + continue; + + fillEventInfo<1, EMBuilder>(collision); + + auto emSlice = emV0s.sliceBy(perCollision, collision.globalIndex()); + auto lfSlice = lfV0s.sliceBy(perCollisionMCDerived, collision.globalIndex()); + + using EMIt = decltype(emSlice.begin()); + using LFIt = decltype(lfSlice.begin()); + struct Entry { + std::optional emIt; + std::optional lfIt; + }; + std::unordered_map table; + + for (EMIt it = emSlice.begin(); it != emSlice.end(); ++it) { + auto posmc = it.posTrack_as() + .emmcparticle_as(); + auto negmc = it.negTrack_as() + .emmcparticle_as(); + int pid = FindCommonMotherFrom2Prongs(posmc, negmc, + kPositron, kElectron, kGamma, mcparticles); + if (pid >= 0) + table[pid].emIt = it; + } + + for (LFIt it = lfSlice.begin(); it != lfSlice.end(); ++it) { + int posTrackIndex = it.posTrackId(); + auto negTrackIndex = it.negTrackId(); + + if (!trackToMcLabel.count(posTrackIndex) || !trackToMcLabel.count(negTrackIndex)) + continue; + auto posmc = mcparticles.iteratorAt(trackToMcLabel[posTrackIndex]); + auto negmc = mcparticles.iteratorAt(trackToMcLabel[negTrackIndex]); + int pid = FindCommonMotherFrom2Prongs(posmc, negmc, + kPositron, kElectron, kGamma, mcparticles); + if (pid >= 0) + table[pid].lfIt = it; + } + + for (auto const& [pid, entry] : table) { + auto mcphoton = mcparticles.iteratorAt(pid); + + if (entry.emIt.has_value() && entry.lfIt.has_value()) { + // --- Common V0 --- + auto& lfV0 = *entry.lfIt.value(); + auto v0MC = lfV0.template v0MCCore_as< + soa::Join>(); + auto posTrack = lfV0.template posTrackExtra_as(); + fillV0Info(lfV0, v0MC, posTrack); + + } else if (entry.emIt.has_value()) { + // --- EM-only V0 --- + auto& emV0 = *entry.emIt.value(); + auto negmc = emV0.negTrack_as() + .emmcparticle_as(); + fillV0Info(emV0, mcphoton, negmc); + + } else if (entry.lfIt.has_value()) { + // --- LF-only V0 --- + auto& lfV0 = *entry.lfIt.value(); + auto v0MC = lfV0.template v0MCCore_as< + soa::Join>(); + auto posTrack = lfV0.template posTrackExtra_as(); + fillV0Info(lfV0, v0MC, posTrack); + } + } + } + } + + PROCESS_SWITCH(Compconvbuilder, processMatchCategories, "Process V0s matched via MC photon", false); + PROCESS_SWITCH(Compconvbuilder, processLFV0sMC, "Process LF Builder V0s", true); + PROCESS_SWITCH(Compconvbuilder, processEMV0sMC, "Process EM Builder V0s", false); + PROCESS_SWITCH(Compconvbuilder, processConvV0s, "Process generated converted V0s", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +{ + return WorkflowSpec{adaptAnalysisTask(cfg)}; +} diff --git a/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx index e20116bc99f..a0c6deb047d 100644 --- a/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/dalitzEEQC.cxx @@ -14,23 +14,27 @@ // This code runs loop over dalitz ee table for dalitz QC. // Please write to: daiki.sekihata@cern.ch -#include "TString.h" -#include "Math/Vector4D.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" + #include "Common/Core/RecoDecay.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" #include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" -#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include using namespace o2; using namespace o2::aod; @@ -39,7 +43,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyTracks = soa::Join; @@ -77,9 +81,8 @@ struct DalitzEEQC { 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.5, "max 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_apply_pf{"cfg_apply_pf", false, "flag to apply phiv prefilter"}; 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"}; @@ -90,16 +93,22 @@ struct DalitzEEQC { 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 includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; - Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTPConly), "pid scheme [kTPConly : 0]"}; + 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", -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_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; @@ -136,7 +145,7 @@ struct DalitzEEQC { 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)); } mRunNumber = collision.runNumber(); @@ -172,21 +181,8 @@ struct DalitzEEQC { o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&fRegistry); // pair info - 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)"}; + 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); @@ -194,18 +190,29 @@ struct DalitzEEQC { 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/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/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/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); } void DefineEMEventCut() @@ -219,7 +226,6 @@ struct DalitzEEQC { fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); } void DefineDileptonCut() @@ -239,16 +245,20 @@ struct DalitzEEQC { 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 + fDileptonCut.IncludeITSsa(dileptoncuts.includeITSsa, dileptoncuts.cfg_max_pt_track_ITSsa); // 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 @@ -269,7 +279,7 @@ struct DalitzEEQC { 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) { + 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); @@ -279,27 +289,13 @@ struct DalitzEEQC { fRegistry.fill(HIST("Pair/same/hMvsPhiV"), phiv, v12.M()); } - 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 (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(), t2.globalIndex()) == used_trackIds.end()) { - used_trackIds.emplace_back(t2.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); - } + if (std::find(used_trackIds.begin(), used_trackIds.end(), t2.globalIndex()) == used_trackIds.end()) { + used_trackIds.emplace_back(t2.globalIndex()); + fillTrackInfo(t2); } return true; } @@ -311,17 +307,25 @@ struct DalitzEEQC { 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/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); @@ -329,8 +333,8 @@ struct DalitzEEQC { SliceCache cache; Preslice perCollision_track = aod::emprimaryelectron::emeventId; - Filter trackFilter = static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt && nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && o2::aod::track::tpcChi2NCl < static_cast(dileptoncuts.cfg_max_chi2tpc) && o2::aod::track::itsChi2NCl < static_cast(dileptoncuts.cfg_max_chi2its) && nabs(o2::aod::track::dcaXY) < static_cast(dileptoncuts.cfg_max_dcaxy) && nabs(o2::aod::track::dcaZ) < static_cast(dileptoncuts.cfg_max_dcaz); - Filter pidFilter = (static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl)) && (o2::aod::pidtpc::tpcNSigmaPi < static_cast(dileptoncuts.cfg_min_TPCNsigmaPi) || static_cast(dileptoncuts.cfg_max_TPCNsigmaPi) < o2::aod::pidtpc::tpcNSigmaPi); + 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); @@ -349,6 +353,9 @@ struct DalitzEEQC { 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 diff --git a/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx b/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx index afa1bca2bd7..6b6ca3f6649 100644 --- a/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/dalitzEEQCMC.cxx @@ -14,25 +14,29 @@ // This code runs loop over dalitz ee table for dalitz QC. // Please write to: daiki.sekihata@cern.ch -#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/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" #include "PWGEM/PhotonMeson/Core/DalitzEECut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" -#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" -#include "PWGEM/Dilepton/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" + +#include "Common/Core/RecoDecay.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TString.h" + +#include +#include using namespace o2; using namespace o2::aod; @@ -42,7 +46,7 @@ using namespace o2::soa; 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 MyMCTracks = soa::Join; @@ -61,6 +65,7 @@ struct DalitzEEQCMC { Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; 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 { @@ -81,9 +86,8 @@ struct DalitzEEQCMC { 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", 1e+10, "max 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_apply_pf{"cfg_apply_pf", false, "flag to apply phiv prefilter"}; 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"}; @@ -94,16 +98,22 @@ struct DalitzEEQCMC { 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 includeITSsa{"includeITSsa", false, "Flag to enable ITSsa tracks"}; + Configurable cfg_max_pt_track_ITSsa{"cfg_max_pt_track_ITSsa", 0.15, "max pt for ITSsa tracks"}; - Configurable cfg_pid_scheme{"cfg_pid_scheme", static_cast(DalitzEECut::PIDSchemes::kTPConly), "pid scheme [kTPConly : 0]"}; + 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", -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_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; @@ -120,6 +130,7 @@ struct DalitzEEQCMC { 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() {} @@ -128,21 +139,8 @@ struct DalitzEEQCMC { // event info o2::aod::pwgem::photonmeson::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)"}; + 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); @@ -163,22 +161,36 @@ struct DalitzEEQCMC { 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); + 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/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/"); } void init(InitContext&) @@ -207,7 +219,7 @@ struct DalitzEEQCMC { 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)); } mRunNumber = collision.runNumber(); @@ -246,7 +258,6 @@ struct DalitzEEQCMC { fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); } void DefineDileptonCut() @@ -266,16 +277,20 @@ struct DalitzEEQCMC { 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 + fDileptonCut.IncludeITSsa(dileptoncuts.includeITSsa, dileptoncuts.cfg_max_pt_track_ITSsa); // 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 @@ -299,7 +314,7 @@ struct DalitzEEQCMC { template bool isInAcceptance(T const& t1) { - if ((mctrackcuts.min_mcPt < t1.pt() && t1.pt() < mctrackcuts.max_mcPt) && abs(t1.eta()) < mctrackcuts.max_mcEta) { + if ((mctrackcuts.min_mcPt < t1.pt() && t1.pt() < mctrackcuts.max_mcPt) && std::fabs(t1.eta()) < mctrackcuts.max_mcEta) { return true; } else { return false; @@ -307,7 +322,7 @@ struct DalitzEEQCMC { } template - bool fillTruePairInfo(TCollision const&, TTrack1 const& t1, TTrack2 const& t2, TMCParticles const& mcparticles) + bool fillTruePairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TMCParticles const& mcparticles) { if (!fDileptonCut.IsSelectedTrack(t1) || !fDileptonCut.IsSelectedTrack(t2)) { return false; @@ -321,116 +336,160 @@ struct DalitzEEQCMC { 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) { + 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 (abs(v12.Rapidity()) > maxY) { + 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); if (mother_id > -1 && t1mc.pdgCode() * t2mc.pdgCode() < 0) { auto mcmother = mcparticles.iteratorAt(mother_id); + if (cfgRequireTrueAssociation && (mcmother.emmceventId() != collision.emmceventId())) { + return false; + } + if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { if ((t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && (t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { - switch (abs(mcmother.pdgCode())) { + 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); + } + 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 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); + } + 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); + } + 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 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; } } else if (!(t1mc.isPhysicalPrimary() || t1mc.producedByGenerator()) && !(t2mc.isPhysicalPrimary() || t2mc.producedByGenerator())) { - switch (abs(mcmother.pdgCode())) { + 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 - } - - // 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); - } + } // end of primary selection for same mother } - return true; } - template + 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()); + 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("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()); } std::vector used_trackIds; SliceCache cache; Preslice perCollision_track = aod::emprimaryelectron::emeventId; - Filter trackFilter = static_cast(dileptoncuts.cfg_min_pt_track) < o2::aod::track::pt && nabs(o2::aod::track::eta) < static_cast(dileptoncuts.cfg_max_eta_track) && o2::aod::track::tpcChi2NCl < static_cast(dileptoncuts.cfg_max_chi2tpc) && o2::aod::track::itsChi2NCl < static_cast(dileptoncuts.cfg_max_chi2its) && nabs(o2::aod::track::dcaXY) < static_cast(dileptoncuts.cfg_max_dcaxy) && nabs(o2::aod::track::dcaZ) < static_cast(dileptoncuts.cfg_max_dcaz); - Filter pidFilter = (static_cast(dileptoncuts.cfg_min_TPCNsigmaEl) < o2::aod::pidtpc::tpcNSigmaEl && o2::aod::pidtpc::tpcNSigmaEl < static_cast(dileptoncuts.cfg_max_TPCNsigmaEl)) && (o2::aod::pidtpc::tpcNSigmaPi < static_cast(dileptoncuts.cfg_min_TPCNsigmaPi) || static_cast(dileptoncuts.cfg_max_TPCNsigmaPi) < o2::aod::pidtpc::tpcNSigmaPi); + 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); @@ -454,6 +513,9 @@ struct DalitzEEQCMC { 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 @@ -490,6 +552,9 @@ struct DalitzEEQCMC { 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); @@ -510,15 +575,14 @@ 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 (abs(v12.Rapidity()) > maxY) { + if (std::fabs(v12.Rapidity()) > maxY) { continue; } @@ -526,7 +590,7 @@ struct DalitzEEQCMC { auto mcmother = mcparticles.iteratorAt(mother_id); if (mcmother.isPhysicalPrimary() || mcmother.producedByGenerator()) { - switch (abs(mcmother.pdgCode())) { + switch (std::abs(mcmother.pdgCode())) { case 111: fRegistry.fill(HIST("Generated/sm/Pi0/hMvsPt"), v12.M(), v12.Pt()); break; @@ -551,7 +615,7 @@ struct DalitzEEQCMC { } } } // end of true ULS pair loop - } // end of collision loop + } // end of collision loop } PROCESS_SWITCH(DalitzEEQCMC, processGen, "run genrated info", true); diff --git a/PWGEM/PhotonMeson/Tasks/diphotonHadronMPCPCMDalitzEE.cxx b/PWGEM/PhotonMeson/Tasks/diphotonHadronMPCPCMDalitzEE.cxx new file mode 100644 index 00000000000..a3a7b548894 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/diphotonHadronMPCPCMDalitzEE.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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/PhotonMeson/Core/DiphotonHadronMPC.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Common/Core/RecoDecay.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"diphoton-hadron-mpc-pcmdalitzee"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/diphotonHadronMPCPCMPCM.cxx b/PWGEM/PhotonMeson/Tasks/diphotonHadronMPCPCMPCM.cxx new file mode 100644 index 00000000000..6f0dfff7c2f --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/diphotonHadronMPCPCMPCM.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. +// +// ======================== +// +// This code loops over photons and makes pairs for neutral mesons analyses. +// Please write to: daiki.sekihata@cern.ch + +#include "PWGEM/PhotonMeson/Core/DiphotonHadronMPC.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::aod; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask>(cfgc, TaskName{"diphoton-hadron-mpc-pcmpcm"}), + }; +} diff --git a/PWGEM/PhotonMeson/Tasks/emcalBcWiseGammaGamma.cxx b/PWGEM/PhotonMeson/Tasks/emcalBcWiseGammaGamma.cxx new file mode 100644 index 00000000000..efbc38d799c --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/emcalBcWiseGammaGamma.cxx @@ -0,0 +1,377 @@ +// 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 emcalBcWiseGammaGamma.cxx +/// +/// \brief Task that extracts pi0s and eta mesons from BC wise derived data of EMCal clusters +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) Goethe University Frankfurt +/// + +#include "PWGEM/PhotonMeson/DataModel/bcWiseTables.h" + +#include "CommonConstants/MathConstants.h" +#include "EMCALBase/Geometry.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include "Math/AxisAngle.h" +#include "Math/LorentzRotation.h" +#include "Math/Rotation3D.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TString.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using SelectedClusters = soa::Filtered; +using SelectedMCClusters = soa::Filtered>; + +struct EmcalBcWiseGammaGamma { + HistogramRegistry mHistManager{"EmcalGammaGammaBcWiseHistograms"}; + + Configurable cfgRequirekTVXinEMC{"cfgRequirekTVXinEMC", true, "Reconstruct mesons only in kTVXinEMC triggered BCs"}; + Configurable cfgRequireEMCCell{"cfgRequireEMCCell", true, "Reconstruct mesons only in BCs containing at least one EMCal cell (workaround for kTVXinEMC trigger)"}; + Configurable cfgSelectOnlyUniqueAmbiguous{"cfgSelectOnlyUniqueAmbiguous", 0, "0: all clusters, 1: only unique clusters, 2: only ambiguous clusters"}; + Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 0, "0: FT0C, 1: FT0M"}; + + Configurable cfgClusterDefinition{"cfgClusterDefinition", 13, "Clusterizer to be selected, e.g. 13 for kV3MostSplitLowSeed"}; + Configurable cfgMinClusterEnergy{"cfgMinClusterEnergy", 700, "Minimum energy of selected clusters (MeV)"}; + Configurable cfgMinM02{"cfgMinM02", 1000, "Minimum M02 of selected clusters (x1000)"}; + Configurable cfgMaxM02{"cfgMaxM02", 7000, "Maximum M02 of selected clusters (x1000)"}; + Configurable cfgMinTime{"cfgMinTime", -1500, "Minimum time of selected clusters (10 ps)"}; + Configurable cfgMaxTime{"cfgMaxTime", 1500, "Maximum time of selected clusters (10 ps)"}; + 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)"}; + Configurable cfgMinTimeSinceSOF{"cfgMinTimeSinceSOF", -1, "Only analyze events with a time since start of fill larger than this value (in minutes)"}; + Configurable cfgMaxTimeSinceSOF{"cfgMaxTimeSinceSOF", 100000, "Only analyze events with a time since start of fill smaller than this value (in minutes)"}; + + ConfigurableAxis cfgCentralityBinning{"cfgCentralityBinning", {VARIABLE_WIDTH, 0.f, 5.f, 10.f, 20.f, 30.f, 40.f, 50.f, 60.f, 70.f, 80.f, 90.f, 100.f, 101.f, 102.f}, "FT0M centrality (%)"}; + + Configurable cfgIsMC{"cfgIsMC", false, "Flag to indicate if the task is running on MC data and should fill MC histograms"}; + + Filter clusterDefinitionFilter = aod::bcwisecluster::storedDefinition == cfgClusterDefinition; + Filter energyFilter = aod::bcwisecluster::storedE > cfgMinClusterEnergy; + Filter m02Filter = (aod::bcwisecluster::storedNCells == 1 || (aod::bcwisecluster::storedM02 > cfgMinM02 && aod::bcwisecluster::storedM02 < cfgMaxM02)); + Filter timeFilter = (aod::bcwisecluster::storedTime > cfgMinTime && aod::bcwisecluster::storedTime < cfgMaxTime); + + emcal::Geometry* emcalGeom; + + void init(InitContext const&) + { + emcalGeom = emcal::Geometry::GetInstanceFromRunNumber(300000); + const int nEventBins = 6; + mHistManager.add("Event/nBCs", "Number of BCs;;#bf{FT0M centrality (%)};#bf{#it{N}_{BC}}", HistType::kTH2F, {{nEventBins, -0.5, 5.5}, cfgCentralityBinning}); + mHistManager.add("Event/nCollisions", "Number of Collisions (BCs x P(mu));;#bf{FT0M centrality (%)};#bf{#it{N}_{coll}}", HistType::kTH2F, {{nEventBins, -0.5, 5.5}, cfgCentralityBinning}); + const TString binLabels[nEventBins] = {"All", "FT0", "TVX", "kTVXinEMC", "Cell", "Cluster"}; + for (int iBin = 0; iBin < nEventBins; iBin++) { + mHistManager.get(HIST("Event/nBCs"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin]); + mHistManager.get(HIST("Event/nCollisions"))->GetXaxis()->SetBinLabel(iBin + 1, binLabels[iBin]); + } + + mHistManager.add("Event/nCollPerBC", "Number of collisions per BC;#bf{#it{N}_{coll}};#bf{FT0M centrality (%)};#bf{#it{N}_{BC}}", HistType::kTH2F, {{5, -0.5, 4.5}, cfgCentralityBinning}); + mHistManager.add("Event/Z1VsZ2", "Z vertex positions for BCs with two collisions;#bf{#it{z}_{vtx}^{1} (cm)};#bf{#it{z}_{vtx}^{2} (cm)}", HistType::kTH2F, {{150, -15, 15}, {150, -15, 15}}); + mHistManager.add("Event/dZ", "Distance between vertices for BCs with two collisions;#bf{#Delta #it{z}_{vtx} (cm)};#bf{#it{N}_{BC}}", HistType::kTH1F, {{600, -30, 30}}); + mHistManager.add("Event/Mu", "Probablity of a collision in the BC;#bf{#mu};#bf{#it{N}_{BC}}", HistType::kTH1F, {{2000, 0., 0.4}}); + mHistManager.add("Event/TimeSinceSOF", "Time of BC since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1F, {{2400, 0., 1200}}); + + mHistManager.add("Event/Centrality", "FT0M centrality;FT0M centrality (%);#bf{#it{N}_{BC}}", HistType::kTH1F, {cfgCentralityBinning}); + mHistManager.add("Event/CentralityVsAmplitude", "FT0M AmplitudeVsCentrality;FT0M Centrality;FT0M Amplitude", HistType::kTH2F, {cfgCentralityBinning, {600, 0, 300000}}); + + mHistManager.add("Cluster/E", "Energy of cluster;#bf{#it{E} (GeV)};#bf{FT0M centrality (%)};#bf{#it{N}_{clusters}}", HistType::kTH2F, {{200, 0, 20}, cfgCentralityBinning}); + mHistManager.add("Cluster/M02", "Shape of cluster;#bf{#it{M}_{02}};#bf{FT0M centrality (%)};#bf{#it{N}_{clusters}}", HistType::kTH2F, {{200, 0, 2}, cfgCentralityBinning}); + mHistManager.add("Cluster/Time", "Time of cluster;#bf{#it{t} (ns)};#bf{FT0M centrality (%)};#bf{#it{N}_{clusters}}", HistType::kTH2F, {{200, -100, 100}, cfgCentralityBinning}); + mHistManager.add("Cluster/NCells", "Number of cells per cluster;#bf{#it{N}_{cells}};#bf{FT0M centrality (%)};#bf{#it{N}_{clusters}}", HistType::kTH2F, {{51, 0., 50.5}, cfgCentralityBinning}); + mHistManager.add("Cluster/Exotic", "Is cluster exotic?;#bf{Exotic?};#bf{FT0M centrality (%)};#bf{#it{N}_{clusters}}", HistType::kTH2F, {{2, -0.5, 1.5}, cfgCentralityBinning}); + mHistManager.add("Cluster/EtaPhi", "Eta/Phi distribution of clusters;#eta;#phi;#bf{FT0M centrality (%)};#bf{#it{N}_{clusters}}", HistType::kTH3F, {{400, -0.8, 0.8}, {400, 0, constants::math::TwoPI}, cfgCentralityBinning}); + + mHistManager.add("GG/invMassVsPt", "Invariant mass and pT of meson candidates;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{400, 0., 0.8}, {300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("GG/invMassVsPtBackground", "Invariant mass and pT of background meson candidates;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{400, 0., 0.8}, {300, 0, 30}, cfgCentralityBinning}); + + if (cfgIsMC) { + mHistManager.add("True/clusterERecVsETrue", "True vs reconstructed energy of cluster inducing particle;#bf{#it{E}_{rec} (GeV)};#bf{#it{E}_{true}^{cls inducing part} (GeV)};#bf{FT0M centrality (%)}", HistType::kTH3F, {{200, 0, 20}, {200, 0, 20}, cfgCentralityBinning}); + mHistManager.add("True/pi0_PtRecVsPtTrue", "True vs reconstructed pT of true pi0s;#bf{#it{p}_{T}^{rec} (GeV/#it{c})};#bf{#it{p}_{T}^{true} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{300, 0, 30}, {300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("True/pi0_invMassVsPt_Primary", "Reconstructed validated primary pi0;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{400, 0., 0.8}, {300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("True/pi0_invMassVsPt_Secondary", "Reconstructed validated pi0 from secondary decay;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{400, 0., 0.8}, {300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("True/pi0_invMassVsPt_HadronicShower", "Reconstructed validated pi0 from hadronic shower;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{400, 0., 0.8}, {300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("True/eta_PtRecVsPtTrue", "True vs reconstructed pT of true eta meson;#bf{#it{p}_{T}^{rec} (GeV/#it{c})};#bf{#it{p}_{T}^{true} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{300, 0, 30}, {300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("True/eta_invMassVsPt_Primary", "Reconstructed validated primary eta meson;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{400, 0., 0.8}, {300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("True/eta_invMassVsPt_Secondary", "Reconstructed validated eta meson from secondary decay;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{400, 0., 0.8}, {300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("True/eta_invMassVsPt_HadronicShower", "Reconstructed validated eta meson from hadronic shower;#bf{#it{M}^{#gamma#gamma} (GeV/#it{c}^{2})};#bf{#it{p}_{T}^{#gamma#gamma} (GeV/#it{c})};#bf{FT0M centrality (%)}", HistType::kTH3F, {{400, 0., 0.8}, {300, 0, 30}, cfgCentralityBinning}); + + mHistManager.add("Generated/pi0_AllBCs", "pT spectrum of generated pi0s in all BCs;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#pi^{0}}^{gen}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Generated/pi0_FT0", "pT spectrum of generated pi0s in BCs with found FT0;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#pi^{0}}^{gen}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Generated/pi0_TVX", "pT spectrum of generated pi0s in TVX triggered BCs;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#pi^{0}}^{gen}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Generated/pi0_kTVXinEMC", "pT spectrum of generated pi0s in kTVXinEMC triggered BCs;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#pi^{0}}^{gen}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Accepted/pi0_kTVXinEMC", "pT spectrum of accepted pi0s in kTVXinEMC triggered BCs;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#pi^{0}}^{acc}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Generated/eta_AllBCs", "pT spectrum of generated eta mesons in all BCs;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#eta}^{gen}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Generated/eta_FT0", "pT spectrum of generated eta mesons in BCs with found FT0;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#eta}^{gen}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Generated/eta_TVX", "pT spectrum of generated eta mesons in TVX triggered BCs;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#eta}^{gen}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Generated/eta_kTVXinEMC", "pT spectrum of generated eta mesons in kTVXinEMC triggered BCs;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#eta}^{gen}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + mHistManager.add("Accepted/eta_kTVXinEMC", "pT spectrum of accepted eta mesons in kTVXinEMC triggered BCs;#bf{#it{p}_{T} (GeV/#it{c})};#bf{FT0M centrality (%)};#bf{#it{N}_{#eta}^{acc}}", HistType::kTH2F, {{300, 0, 30}, cfgCentralityBinning}); + } + } + + float getCentrality(const auto& bc) + { + if (cfgCentralityEstimator == 0) + return bc.ft0cCentrality(); + else if (cfgCentralityEstimator == 1) + return bc.ft0mCentrality(); + else + throw std::runtime_error("Unknown centrality estimator selected"); + } + + /// \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("Event/nBCs"), 0, getCentrality(bc)); + float mu = bc.mu(); + mHistManager.fill(HIST("Event/Mu"), mu); + mHistManager.fill(HIST("Event/TimeSinceSOF"), bc.timeSinceSOF() / 60.); + double p = mu > 0.001 ? mu / (1 - std::exp(-mu)) : 1.; // No pile-up for small mu (protection against division by zero) + mHistManager.fill(HIST("Event/nCollisions"), 0, getCentrality(bc), p); + if (bc.hasFT0()) { + mHistManager.fill(HIST("Event/nBCs"), 1, getCentrality(bc)); + mHistManager.fill(HIST("Event/nCollisions"), 1, getCentrality(bc), p); + } + if (bc.hasTVX()) { + mHistManager.fill(HIST("Event/nBCs"), 2, getCentrality(bc)); + mHistManager.fill(HIST("Event/nCollisions"), 2, getCentrality(bc), p); + } + if (bc.haskTVXinEMC()) { + mHistManager.fill(HIST("Event/nBCs"), 3, getCentrality(bc)); + mHistManager.fill(HIST("Event/nCollisions"), 3, getCentrality(bc), p); + } + if (bc.hasEMCCell()) { + mHistManager.fill(HIST("Event/nBCs"), 4, getCentrality(bc)); + mHistManager.fill(HIST("Event/nCollisions"), 4, getCentrality(bc), p); + } + if (clusters.size() > 0) { + mHistManager.fill(HIST("Event/nBCs"), 5, getCentrality(bc)); + mHistManager.fill(HIST("Event/nCollisions"), 5, getCentrality(bc), p); + } + + mHistManager.fill(HIST("Event/Centrality"), getCentrality(bc)); + mHistManager.fill(HIST("Event/CentralityVsAmplitude"), getCentrality(bc), bc.ft0Amplitude()); + + mHistManager.fill(HIST("Event/nCollPerBC"), collisions.size(), getCentrality(bc)); + if (collisions.size() == 2) { + mHistManager.fill(HIST("Event/Z1VsZ2"), collisions.iteratorAt(0).zVtx(), collisions.iteratorAt(1).zVtx()); + mHistManager.fill(HIST("Event/dZ"), collisions.iteratorAt(0).zVtx() - collisions.iteratorAt(1).zVtx()); + } + } + + void fillClusterHists(const auto& clusters, float centrality) + { + for (const auto& cluster : clusters) { + mHistManager.fill(HIST("Cluster/E"), cluster.e(), centrality); + mHistManager.fill(HIST("Cluster/M02"), cluster.m02(), centrality); + mHistManager.fill(HIST("Cluster/Time"), cluster.time(), centrality); + mHistManager.fill(HIST("Cluster/NCells"), cluster.nCells(), centrality); + mHistManager.fill(HIST("Cluster/EtaPhi"), cluster.eta(), cluster.phi(), centrality); + mHistManager.fill(HIST("Cluster/Exotic"), cluster.isExotic(), centrality); + } + } + + void reconstructMesons(const auto& clusters, const auto& bc) + { + 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("GG/invMassVsPt"), v12.M(), v12.Pt(), getCentrality(bc)); + + if (clusters.size() < 3) + continue; + + if (bc.globalIndex() % 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("GG/invMassVsPtBackground"), vBG.M(), vBG.Pt(), getCentrality(bc)); + } + } + } + } + void reconstructTrueMesons(const auto& clusters, const auto& mcPi0s, const auto& mcEtas, const auto& bc) + { + for (const auto& [g1, g2] : soa::combinations(soa::CombinationsStrictlyUpperIndexPolicy(clusters, clusters))) { + if (g1.mesonID() != g2.mesonID() || g1.mesonID() == -1) + 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()) > cfgRapidityCut) + continue; + + float openingAngle12 = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); + if (openingAngle12 < cfgMinOpenAngle) + continue; + + if (!g1.isEta()) { + const auto& mcPi0 = mcPi0s.iteratorAt(g1.mesonID() - mcPi0s.offset()); + + mHistManager.fill(HIST("True/pi0_PtRecVsPtTrue"), v12.Pt(), mcPi0.pt(), getCentrality(bc)); + + if (mcPi0.isPrimary()) + mHistManager.fill(HIST("True/pi0_invMassVsPt_Primary"), v12.M(), v12.Pt(), getCentrality(bc)); + else if (mcPi0.isFromWD()) + mHistManager.fill(HIST("True/pi0_invMassVsPt_Secondary"), v12.M(), v12.Pt(), getCentrality(bc)); + else + mHistManager.fill(HIST("True/pi0_invMassVsPt_HadronicShower"), v12.M(), v12.Pt(), getCentrality(bc)); + } else { + const auto& mcEta = mcEtas.iteratorAt(g1.mesonID() - mcEtas.offset()); + + mHistManager.fill(HIST("True/eta_PtRecVsPtTrue"), v12.Pt(), mcEta.pt(), getCentrality(bc)); + + if (mcEta.isPrimary()) + mHistManager.fill(HIST("True/eta_invMassVsPt_Primary"), v12.M(), v12.Pt(), getCentrality(bc)); + else if (mcEta.isFromWD()) + mHistManager.fill(HIST("True/eta_invMassVsPt_Secondary"), v12.M(), v12.Pt(), getCentrality(bc)); + else + mHistManager.fill(HIST("True/eta_invMassVsPt_HadronicShower"), v12.M(), v12.Pt(), getCentrality(bc)); + } + } + } + + bool isBCSelected(const auto& bc, const auto& collisions) + { + if (cfgRequirekTVXinEMC && !bc.haskTVXinEMC()) + return false; + if (cfgRequireEMCCell && !bc.hasEMCCell()) + return false; + if (cfgSelectOnlyUniqueAmbiguous == 1 && collisions.size() != 1) + return false; + if (cfgSelectOnlyUniqueAmbiguous == 2 && collisions.size() == 1) + return false; + if (cfgMinTimeSinceSOF > bc.timeSinceSOF() / 60 || cfgMaxTimeSinceSOF < bc.timeSinceSOF() / 60) + return false; + return true; + } + + void fillGeneratedMesonHists(const auto& mcPi0s, const auto& mcEtas, const auto& bc) + { + for (const auto& mcPi0 : mcPi0s) { + if (mcPi0.isPrimary()) { + mHistManager.fill(HIST("Generated/pi0_AllBCs"), mcPi0.pt(), getCentrality(bc)); + if (bc.hasFT0()) + mHistManager.fill(HIST("Generated/pi0_FT0"), mcPi0.pt(), getCentrality(bc)); + if (bc.hasTVX()) + mHistManager.fill(HIST("Generated/pi0_TVX"), mcPi0.pt(), getCentrality(bc)); + if (bc.haskTVXinEMC()) + mHistManager.fill(HIST("Generated/pi0_kTVXinEMC"), mcPi0.pt(), getCentrality(bc)); + if (mcPi0.isAccepted() && bc.haskTVXinEMC()) + mHistManager.fill(HIST("Accepted/pi0_kTVXinEMC"), mcPi0.pt(), getCentrality(bc)); + } + } + for (const auto& mcEta : mcEtas) { + if (mcEta.isPrimary()) { + mHistManager.fill(HIST("Generated/eta_AllBCs"), mcEta.pt(), getCentrality(bc)); + if (bc.hasFT0()) + mHistManager.fill(HIST("Generated/eta_FT0"), mcEta.pt(), getCentrality(bc)); + if (bc.hasTVX()) + mHistManager.fill(HIST("Generated/eta_TVX"), mcEta.pt(), getCentrality(bc)); + if (bc.haskTVXinEMC()) + mHistManager.fill(HIST("Generated/eta_kTVXinEMC"), mcEta.pt(), getCentrality(bc)); + if (mcEta.isAccepted() && bc.haskTVXinEMC()) + mHistManager.fill(HIST("Accepted/eta_kTVXinEMC"), mcEta.pt(), getCentrality(bc)); + } + } + } + + void process(aod::BCWiseBCs::iterator const& bc, aod::BCWiseCollisions const& collisions, SelectedClusters const& clusters) + { + if (!isBCSelected(bc, collisions)) + return; + + fillEventHists(bc, collisions, clusters); + + fillClusterHists(clusters, getCentrality(bc)); + + reconstructMesons(clusters, bc); + } + + void processMCInfo(aod::BCWiseBCs::iterator const& bc, aod::BCWiseCollisions const& collisions, SelectedMCClusters const& clusters, aod::BCWiseMCPi0s const& mcPi0s, aod::BCWiseMCEtas const& mcEtas) + { + if (!cfgIsMC) + LOG(fatal) << "MC processing is not enabled, but the task is running on MC data. Please set cfgIsMC to true."; + + fillGeneratedMesonHists(mcPi0s, mcEtas, bc); // Fill before BC selection to also store pi0s and eta mesons in BCs that were not triggered + + if (!isBCSelected(bc, collisions)) + return; + + for (const auto& cluster : clusters) + mHistManager.fill(HIST("True/clusterERecVsETrue"), cluster.e(), cluster.trueE(), getCentrality(bc)); + + reconstructTrueMesons(clusters, mcPi0s, mcEtas, bc); + } + PROCESS_SWITCH(EmcalBcWiseGammaGamma, processMCInfo, "Run true and gen", false); +}; + +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 similarity index 66% rename from PWGEM/PhotonMeson/Tasks/emcalPi0QC.cxx rename to PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx index 509e74402b5..f2aa922ec90 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPi0QC.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx @@ -9,39 +9,10 @@ // 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 "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 "EMCALBase/Geometry.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGJE/DataModel/EMCALMatchedCollisions.h" -#include "DataFormatsEMCAL/Cell.h" -#include "DataFormatsEMCAL/Constants.h" -#include "DataFormatsEMCAL/AnalysisCluster.h" - -#include "CommonDataFormat/InteractionRecord.h" - -#include "TLorentzVector.h" -#include "TVector3.h" - -// \struct Pi0QCTask +/// \file emcalPi0Qc.cxx /// \brief Simple monitoring task for EMCal clusters /// \author Joshua Koenig , Goethe University Frankfurt +/// \struct EmcalPi0Qc /// \since 25.05.2022 /// /// This task is meant to be used for QC for the emcal using properties of the pi0 @@ -50,15 +21,48 @@ /// For pilot beam data, instead of relying on the event selection, one can veto specific BC IDS using the flag /// fDoVetoBCID. +#include "PWGJE/DataModel/EMCALClusterDefinition.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + using namespace o2::framework; using namespace o2::framework::expressions; -using collisionEvSelIt = o2::aod::Collision; -using selectedClusters = o2::soa::Filtered; +using SelectedClusters = o2::soa::Filtered; using MyCollisions = o2::soa::Join; using MyBCs = o2::soa::Join; -using selectedCluster = o2::soa::Filtered; -using selectedAmbiguousClusters = o2::soa::Filtered; -using selectedAmbiguousCluster = o2::soa::Filtered; +using SelectedAmbiguousClusters = o2::soa::Filtered; struct Photon { Photon(float eta_tmp, float phi_tmp, float energy_tmp, int clusid = 0) @@ -106,7 +110,7 @@ struct Meson { struct EventMixVec { - void AddEvent(std::vector vecGamma) + void addEvent(std::vector vecGamma) { if (vecEvtMix.size() < nEVtMixSize) { vecEvtMix.push_back(vecGamma); @@ -115,20 +119,12 @@ struct EventMixVec { vecEvtMix.push_back(vecGamma); } } - Photon* getPhoton(unsigned int iEvt, unsigned int iGamma) - { - if (vecEvtMix.size() >= iEvt) - return nullptr; - if (vecEvtMix[iEvt].size() >= iGamma) - return nullptr; - return &vecEvtMix[iEvt][iGamma]; - } std::vector> vecEvtMix; unsigned int nEVtMixSize = 20; }; -struct Pi0QCTask { +struct EmcalPi0Qc { HistogramRegistry mHistManager{"NeutralMesonHistograms"}; o2::emcal::Geometry* mGeometry = nullptr; @@ -136,21 +132,21 @@ 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"}; - Configurable mTimeMin{"TimeMinCut", -600, "apply min timing cut (in ns)"}; - Configurable mTimeMax{"TimeMaxCut", 900, "apply min timing cut (in ns)"}; - Configurable mClusterMinM02Cut{"MinM02Cut", 0.1, "apply min M02 cut"}; - Configurable mClusterMaxM02Cut{"MaxM02Cut", 0.7, "apply max M02 cut"}; - 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 mSplitEMCalDCal{"SplitEMCalDCal", 0, "Create and fill inv mass histograms for photons on EMCal and DCal individually"}; + Configurable mDoEventSel{"mDoEventSel", 0, "demand kINT7"}; + Configurable mRequireCaloReadout{"mRequireCaloReadout", 0, "require kTVXinEMC"}; + Configurable mRequireEMCalCells{"mRequireEMCalCells", 0, "require at least one EMC cell in each collision"}; + Configurable mVetoBCID{"mVetoBCID", "", "BC ID(s) to be excluded, this should be used as an alternative to the event selection"}; + Configurable mSelectBCID{"mSelectBCID", "all", "BC ID(s) to be included, this should be used as an alternative to the event selection"}; + Configurable mVertexCut{"mVertexCut", -1, "apply z-vertex cut with value in cm"}; + Configurable mTimeMin{"mTimeMin", -600, "apply min timing cut (in ns)"}; + Configurable mTimeMax{"mTimeMax", 900, "apply min timing cut (in ns)"}; + Configurable mClusterMinM02Cut{"mClusterMinM02Cut", 0.1, "apply min M02 cut"}; + Configurable mClusterMaxM02Cut{"mClusterMaxM02Cut", 0.7, "apply max M02 cut"}; + Configurable mMinEnergyCut{"mMinEnergyCut", 0.7, "apply min cluster energy cut"}; + Configurable mMinNCellsCut{"mMinNCellsCut", 1, "apply min cluster number of cell cut"}; + Configurable mMinOpenAngleCut{"mMinOpenAngleCut", 0.0202, "apply min opening angle cut"}; + Configurable mClusterDefinition{"mClusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"}; + Configurable mSplitEMCalDCal{"mSplitEMCalDCal", 0, "Create and fill inv mass histograms for photons on EMCal and DCal individually"}; std::vector mVetoBCIDs; std::vector mSelectBCIDs; @@ -172,19 +168,15 @@ struct Pi0QCTask { /// \brief Create output histograms and initialize geometry void init(InitContext const&) { - // create histograms - using o2HistType = HistType; - using o2Axis = AxisSpec; - // load geometry just in case we need it mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); // create common axes LOG(info) << "Creating histograms"; - const o2Axis bcAxis{3501, -0.5, 3500.5}; - const o2Axis energyAxis{makeClusterBinning(), "#it{E} (GeV)"}; + const AxisSpec bcAxis{3501, -0.5, 3500.5}; + const AxisSpec energyAxis{makeClusterBinning(), "#it{E} (GeV)"}; - mHistManager.add("events", "events;;#it{count}", o2HistType::kTH1F, {{6, 0.5, 6.5}}); + mHistManager.add("events", "events;;#it{count}", HistType::kTH1F, {{6, 0.5, 6.5}}); auto heventType = mHistManager.get(HIST("events")); heventType->GetXaxis()->SetBinLabel(1, "All events"); heventType->GetXaxis()->SetBinLabel(2, "sel8 + readout"); @@ -192,37 +184,37 @@ struct Pi0QCTask { heventType->GetXaxis()->SetBinLabel(4, "z<10cm"); heventType->GetXaxis()->SetBinLabel(5, "unique col"); heventType->GetXaxis()->SetBinLabel(6, "EMCAL cell>0"); - mHistManager.add("eventBCAll", "Bunch crossing ID of event (all events)", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("eventBCSelected", "Bunch crossing ID of event (selected events)", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("eventVertexZAll", "z-vertex of event (all events)", o2HistType::kTH1F, {{200, -20, 20}}); - mHistManager.add("eventVertexZSelected", "z-vertex of event (selected events)", o2HistType::kTH1F, {{200, -20, 20}}); + mHistManager.add("eventBCAll", "Bunch crossing ID of event (all events)", HistType::kTH1F, {bcAxis}); + mHistManager.add("eventBCSelected", "Bunch crossing ID of event (selected events)", HistType::kTH1F, {bcAxis}); + mHistManager.add("eventVertexZAll", "z-vertex of event (all events)", HistType::kTH1F, {{200, -20, 20}}); + mHistManager.add("eventVertexZSelected", "z-vertex of event (selected events)", HistType::kTH1F, {{200, -20, 20}}); // cluster properties - for (bool iBeforeCuts : {false, true}) { - const char* ClusterDirectory = iBeforeCuts ? "ClustersBeforeCuts" : "ClustersAfterCuts"; - mHistManager.add(Form("%s/clusterE", ClusterDirectory), "Energy of cluster", o2HistType::kTH1F, {energyAxis}); - mHistManager.add(Form("%s/clusterE_SimpleBinning", ClusterDirectory), "Energy of cluster", o2HistType::kTH1F, {{400, 0, 100, "#it{E} (GeV)"}}); - mHistManager.add(Form("%s/clusterTime", ClusterDirectory), "Time of cluster", o2HistType::kTH1F, {{500, -250, 250, "#it{t}_{cls} (ns)"}}); - mHistManager.add(Form("%s/clusterEtaPhi", ClusterDirectory), "Eta and phi of cluster", o2HistType::kTH2F, {{100, -1, 1, "#eta"}, {100, 0, 2 * TMath::Pi(), "#phi"}}); - mHistManager.add(Form("%s/clusterM02", ClusterDirectory), "M02 of cluster", o2HistType::kTH1F, {{400, 0, 5, "#it{M}_{02}"}}); - mHistManager.add(Form("%s/clusterM20", ClusterDirectory), "M20 of cluster", o2HistType::kTH1F, {{400, 0, 2.5, "#it{M}_{20}"}}); - mHistManager.add(Form("%s/clusterNLM", ClusterDirectory), "Number of local maxima of cluster", o2HistType::kTH1I, {{10, 0, 10, "#it{N}_{local maxima}"}}); - mHistManager.add(Form("%s/clusterNCells", ClusterDirectory), "Number of cells in cluster", o2HistType::kTH1I, {{50, 0, 50, "#it{N}_{cells}"}}); - mHistManager.add(Form("%s/clusterDistanceToBadChannel", ClusterDirectory), "Distance to bad channel", o2HistType::kTH1F, {{100, 0, 100, "#it{d}"}}); + for (const bool& iBeforeCuts : {false, true}) { + const char* clusterDirectory = iBeforeCuts ? "ClustersBeforeCuts" : "ClustersAfterCuts"; + mHistManager.add(Form("%s/clusterE", clusterDirectory), "Energy of cluster", HistType::kTH1F, {energyAxis}); + mHistManager.add(Form("%s/clusterE_SimpleBinning", clusterDirectory), "Energy of cluster", HistType::kTH1F, {{400, 0, 100, "#it{E} (GeV)"}}); + mHistManager.add(Form("%s/clusterTime", clusterDirectory), "Time of cluster", HistType::kTH1F, {{500, -250, 250, "#it{t}_{cls} (ns)"}}); + mHistManager.add(Form("%s/clusterEtaPhi", clusterDirectory), "Eta and phi of cluster", HistType::kTH2F, {{100, -1, 1, "#eta"}, {100, 0, o2::constants::math::TwoPI, "#phi"}}); + mHistManager.add(Form("%s/clusterM02", clusterDirectory), "M02 of cluster", HistType::kTH1F, {{400, 0, 5, "#it{M}_{02}"}}); + mHistManager.add(Form("%s/clusterM20", clusterDirectory), "M20 of cluster", HistType::kTH1F, {{400, 0, 2.5, "#it{M}_{20}"}}); + mHistManager.add(Form("%s/clusterNLM", clusterDirectory), "Number of local maxima of cluster", HistType::kTH1I, {{10, 0, 10, "#it{N}_{local maxima}"}}); + mHistManager.add(Form("%s/clusterNCells", clusterDirectory), "Number of cells in cluster", HistType::kTH1I, {{50, 0, 50, "#it{N}_{cells}"}}); + mHistManager.add(Form("%s/clusterDistanceToBadChannel", clusterDirectory), "Distance to bad channel", HistType::kTH1F, {{100, 0, 100, "#it{d}"}}); } // meson related histograms - mHistManager.add("invMassVsPt", "invariant mass and pT of meson candidates", o2HistType::kTH2F, {invmassBinning, pTBinning}); - mHistManager.add("invMassVsPtBackground", "invariant mass and pT of background meson candidates", o2HistType::kTH2F, {invmassBinning, pTBinning}); - mHistManager.add("invMassVsPtMixedBackground", "invariant mass and pT of mixed background meson candidates", o2HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPt", "invariant mass and pT of meson candidates", HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPtBackground", "invariant mass and pT of background meson candidates", HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPtMixedBackground", "invariant mass and pT of mixed background meson candidates", HistType::kTH2F, {invmassBinning, pTBinning}); if (mSplitEMCalDCal) { - mHistManager.add("invMassVsPt_EMCal", "invariant mass and pT of meson candidates with both clusters on EMCal", o2HistType::kTH2F, {invmassBinning, pTBinning}); - mHistManager.add("invMassVsPtBackground_EMCal", "invariant mass and pT of background meson candidates with both clusters on EMCal", o2HistType::kTH2F, {invmassBinning, pTBinning}); - mHistManager.add("invMassVsPtMixedBackground_EMCal", "invariant mass and pT of mixed background meson candidates with both clusters on EMCal", o2HistType::kTH2F, {invmassBinning, pTBinning}); - mHistManager.add("invMassVsPt_DCal", "invariant mass and pT of meson candidates with both clusters on DCal", o2HistType::kTH2F, {invmassBinning, pTBinning}); - mHistManager.add("invMassVsPtBackground_DCal", "invariant mass and pT of background meson candidates with both clusters on DCal", o2HistType::kTH2F, {invmassBinning, pTBinning}); - mHistManager.add("invMassVsPtMixedBackground_DCal", "invariant mass and pT of mixed background meson candidates with both clusters on DCal", o2HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPt_EMCal", "invariant mass and pT of meson candidates with both clusters on EMCal", HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPtBackground_EMCal", "invariant mass and pT of background meson candidates with both clusters on EMCal", HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPtMixedBackground_EMCal", "invariant mass and pT of mixed background meson candidates with both clusters on EMCal", HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPt_DCal", "invariant mass and pT of meson candidates with both clusters on DCal", HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPtBackground_DCal", "invariant mass and pT of background meson candidates with both clusters on DCal", HistType::kTH2F, {invmassBinning, pTBinning}); + mHistManager.add("invMassVsPtMixedBackground_DCal", "invariant mass and pT of mixed background meson candidates with both clusters on DCal", HistType::kTH2F, {invmassBinning, pTBinning}); } if (mVetoBCID->length()) { @@ -247,10 +239,10 @@ struct Pi0QCTask { } } - PresliceUnsorted perCollision = o2::aod::emcalcluster::collisionId; + PresliceUnsorted perCollision = o2::aod::emcalcluster::collisionId; /// \brief Process EMCAL clusters that are matched to a collisions - void processCollision(MyBCs const&, MyCollisions const& collisions, selectedClusters const& clusters, o2::soa::Filtered const& cells) + void processCollision(MyBCs const&, MyCollisions const& collisions, SelectedClusters const& clusters, o2::soa::Filtered const& cells) { std::unordered_map cellGlobalBCs; // Build map of number of cells for corrected BCs using global BCs @@ -265,7 +257,7 @@ struct Pi0QCTask { } } - for (auto& collision : collisions) { + for (const auto& collision : collisions) { mHistManager.fill(HIST("events"), 1); // Fill "All events" bin of event histogram if (mDoEventSel && (!collision.sel8() || (mRequireCaloReadout && !collision.alias_bit(kTVXinEMC)))) { // Check sel8 and whether EMC was read out @@ -298,16 +290,16 @@ struct Pi0QCTask { } mHistManager.fill(HIST("events"), 6); // Fill at least one non0 cell in EMCal of event histogram (Selected) - auto clusters_per_coll = clusters.sliceBy(perCollision, collision.collisionId()); - ProcessClusters(clusters_per_coll); - ProcessMesons(); + auto clustersPerColl = clusters.sliceBy(perCollision, collision.collisionId()); + processClusters(clustersPerColl); + processMesons(); } } - PROCESS_SWITCH(Pi0QCTask, processCollision, "Process clusters from collision", false); + PROCESS_SWITCH(EmcalPi0Qc, processCollision, "Process clusters from collision", false); /// \brief Process EMCAL clusters that are not matched to a collision /// This is not needed for most users - void processAmbiguous(o2::aod::BCs::iterator const& bc, selectedAmbiguousClusters const& clusters) + void processAmbiguous(o2::aod::BCs::iterator const& bc, SelectedAmbiguousClusters const& clusters) { LOG(debug) << "processAmbiguous"; // TODO: remove this loop and put it in separate process function that only takes care of ambiguous clusters @@ -323,16 +315,16 @@ struct Pi0QCTask { } mHistManager.fill(HIST("eventBCSelected"), eventIR.bc); - ProcessAmbiguousClusters(clusters); - ProcessMesons(); + processAmbiguousClusters(clusters); + processMesons(); } - PROCESS_SWITCH(Pi0QCTask, processAmbiguous, "Process Ambiguous clusters", false); + PROCESS_SWITCH(EmcalPi0Qc, processAmbiguous, "Process Ambiguous clusters", false); /// \brief Process EMCAL clusters that are matched to a collisions template - void ProcessClusters(Clusters const& clusters) + void processClusters(Clusters const& clusters) { - LOG(debug) << "ProcessClusters"; + LOG(debug) << "processClusters"; // clear photon vector mPhotons.clear(); @@ -351,12 +343,12 @@ struct Pi0QCTask { LOG(info) << "Something went wrong with the collision ID"; } - FillClusterQAHistos(cluster); + fillClusterQAHistos(cluster); - if (ClusterRejectedByCut(cluster)) + if (clusterRejectedByCut(cluster)) continue; - FillClusterQAHistos(cluster); + fillClusterQAHistos(cluster); // put clusters in photon vector mPhotons.push_back(Photon(cluster.eta(), cluster.phi(), cluster.energy(), cluster.id())); @@ -365,21 +357,21 @@ struct Pi0QCTask { /// \brief Process EMCAL clusters that are not matched to a collisions template - void ProcessAmbiguousClusters(Clusters const& clusters) + void processAmbiguousClusters(Clusters const& clusters) { - LOG(debug) << "ProcessClusters"; + LOG(debug) << "processClusters"; // clear photon vector mPhotons.clear(); // loop over all clusters from accepted collision for (const auto& cluster : clusters) { - FillClusterQAHistos(cluster); + fillClusterQAHistos(cluster); - if (ClusterRejectedByCut(cluster)) + if (clusterRejectedByCut(cluster)) continue; - FillClusterQAHistos(cluster); + fillClusterQAHistos(cluster); // put clusters in photon vector mPhotons.push_back(Photon(cluster.eta(), cluster.phi(), cluster.energy(), cluster.id())); @@ -388,33 +380,33 @@ struct Pi0QCTask { /// \brief Fills the standard QA histograms for a given cluster template - void FillClusterQAHistos(Cluster const& cluster) + void fillClusterQAHistos(Cluster const& cluster) { // In this implementation the cluster properties are directly loaded from the flat table, // in the future one should consider using the AnalysisCluster object to work with after loading. - static constexpr std::string_view clusterQAHistEnergy[2] = {"ClustersBeforeCuts/clusterE", "ClustersAfterCuts/clusterE"}; - static constexpr std::string_view clusterQAHistEnergySimpleBinning[2] = {"ClustersBeforeCuts/clusterE_SimpleBinning", "ClustersAfterCuts/clusterE_SimpleBinning"}; - static constexpr std::string_view clusterQAHistTime[2] = {"ClustersBeforeCuts/clusterTime", "ClustersAfterCuts/clusterTime"}; - static constexpr std::string_view clusterQAHistEtaPhi[2] = {"ClustersBeforeCuts/clusterEtaPhi", "ClustersAfterCuts/clusterEtaPhi"}; - static constexpr std::string_view clusterQAHistM02[2] = {"ClustersBeforeCuts/clusterM02", "ClustersAfterCuts/clusterM02"}; - static constexpr std::string_view clusterQAHistM20[2] = {"ClustersBeforeCuts/clusterM20", "ClustersAfterCuts/clusterM20"}; - static constexpr std::string_view clusterQAHistNLM[2] = {"ClustersBeforeCuts/clusterNLM", "ClustersAfterCuts/clusterNLM"}; - static constexpr std::string_view clusterQAHistNCells[2] = {"ClustersBeforeCuts/clusterNCells", "ClustersAfterCuts/clusterNCells"}; - static constexpr std::string_view clusterQAHistDistanceToBadChannel[2] = {"ClustersBeforeCuts/clusterDistanceToBadChannel", "ClustersAfterCuts/clusterDistanceToBadChannel"}; - mHistManager.fill(HIST(clusterQAHistEnergy[BeforeCuts]), cluster.energy()); - mHistManager.fill(HIST(clusterQAHistEnergySimpleBinning[BeforeCuts]), cluster.energy()); - mHistManager.fill(HIST(clusterQAHistTime[BeforeCuts]), cluster.time()); - mHistManager.fill(HIST(clusterQAHistEtaPhi[BeforeCuts]), cluster.eta(), cluster.phi()); - mHistManager.fill(HIST(clusterQAHistM02[BeforeCuts]), cluster.m02()); - mHistManager.fill(HIST(clusterQAHistM20[BeforeCuts]), cluster.m20()); - mHistManager.fill(HIST(clusterQAHistNLM[BeforeCuts]), cluster.nlm()); - mHistManager.fill(HIST(clusterQAHistNCells[BeforeCuts]), cluster.nCells()); - mHistManager.fill(HIST(clusterQAHistDistanceToBadChannel[BeforeCuts]), cluster.distanceToBadChannel()); + static constexpr std::string_view kClusterQAHistEnergy[2] = {"ClustersBeforeCuts/clusterE", "ClustersAfterCuts/clusterE"}; + static constexpr std::string_view kClusterQAHistEnergySimpleBinning[2] = {"ClustersBeforeCuts/clusterE_SimpleBinning", "ClustersAfterCuts/clusterE_SimpleBinning"}; + static constexpr std::string_view kClusterQAHistTime[2] = {"ClustersBeforeCuts/clusterTime", "ClustersAfterCuts/clusterTime"}; + static constexpr std::string_view kClusterQAHistEtaPhi[2] = {"ClustersBeforeCuts/clusterEtaPhi", "ClustersAfterCuts/clusterEtaPhi"}; + static constexpr std::string_view kClusterQAHistM02[2] = {"ClustersBeforeCuts/clusterM02", "ClustersAfterCuts/clusterM02"}; + static constexpr std::string_view kClusterQAHistM20[2] = {"ClustersBeforeCuts/clusterM20", "ClustersAfterCuts/clusterM20"}; + static constexpr std::string_view kClusterQAHistNLM[2] = {"ClustersBeforeCuts/clusterNLM", "ClustersAfterCuts/clusterNLM"}; + static constexpr std::string_view kClusterQAHistNCells[2] = {"ClustersBeforeCuts/clusterNCells", "ClustersAfterCuts/clusterNCells"}; + static constexpr std::string_view kClusterQAHistDistanceToBadChannel[2] = {"ClustersBeforeCuts/clusterDistanceToBadChannel", "ClustersAfterCuts/clusterDistanceToBadChannel"}; + mHistManager.fill(HIST(kClusterQAHistEnergy[BeforeCuts]), cluster.energy()); + mHistManager.fill(HIST(kClusterQAHistEnergySimpleBinning[BeforeCuts]), cluster.energy()); + mHistManager.fill(HIST(kClusterQAHistTime[BeforeCuts]), cluster.time()); + mHistManager.fill(HIST(kClusterQAHistEtaPhi[BeforeCuts]), cluster.eta(), cluster.phi()); + mHistManager.fill(HIST(kClusterQAHistM02[BeforeCuts]), cluster.m02()); + mHistManager.fill(HIST(kClusterQAHistM20[BeforeCuts]), cluster.m20()); + mHistManager.fill(HIST(kClusterQAHistNLM[BeforeCuts]), cluster.nlm()); + mHistManager.fill(HIST(kClusterQAHistNCells[BeforeCuts]), cluster.nCells()); + mHistManager.fill(HIST(kClusterQAHistDistanceToBadChannel[BeforeCuts]), cluster.distanceToBadChannel()); } /// \brief Return a boolean that states, whether a cluster should be rejected by the applied cluster cuts template - bool ClusterRejectedByCut(Cluster const& cluster) + bool clusterRejectedByCut(Cluster const& cluster) { // apply basic cluster cuts if (cluster.energy() < mMinEnergyCut) { @@ -440,9 +432,9 @@ struct Pi0QCTask { } /// \brief Process meson candidates, calculate invariant mass and pT and fill histograms - void ProcessMesons() + void processMesons() { - LOG(debug) << "ProcessMesons " << mPhotons.size(); + LOG(debug) << "processMesons " << mPhotons.size(); // if less then 2 clusters are found, skip event if (mPhotons.size() < 2) @@ -467,22 +459,22 @@ struct Pi0QCTask { } // calculate background candidates (rotation background) - CalculateBackground(meson, ig1, ig2); + calculateBackground(meson, ig1, ig2); } - CalculateMixedBack(mPhotons[ig1]); + calculateMixedBack(mPhotons[ig1]); } - evtMix.AddEvent(mPhotons); + evtMix.addEvent(mPhotons); } /// \brief Calculate background (using rotation background method) - void CalculateBackground(const Meson& meson, unsigned int ig1, unsigned int ig2) + void calculateBackground(const Meson& meson, unsigned int ig1, unsigned int ig2) { // if less than 3 clusters are present, skip event if (mPhotons.size() < 3) { return; } - const double rotationAngle = M_PI / 2.0; // 0.78539816339; // rotaion angle 90° + const double rotationAngle = o2::constants::math::PIHalf; // 0.78539816339; // rotaion angle 90° TLorentzVector lvRotationPhoton1; // photon candidates which get rotated TLorentzVector lvRotationPhoton2; // photon candidates which get rotated @@ -535,7 +527,7 @@ struct Pi0QCTask { } } - void CalculateMixedBack(Photon gamma) + void calculateMixedBack(Photon gamma) { for (unsigned int i = 0; i < evtMix.vecEvtMix.size(); ++i) { for (unsigned int ig1 = 0; ig1 < evtMix.vecEvtMix[i].size(); ++ig1) { @@ -562,7 +554,7 @@ struct Pi0QCTask { std::vector result; int nBinsPt = 179; double maxPt = 60; - for (Int_t i = 0; i < nBinsPt + 1; i++) { + for (int i = 0; i < nBinsPt + 1; i++) { if (i < 100) { result.emplace_back(0.10 * i); } else if (i < 140) { @@ -580,7 +572,7 @@ struct Pi0QCTask { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc, TaskName{"EMCPi0QCTask"}, SetDefaultProcesses{{{"processCollision", true}, {"processAmbiguous", false}}}), - adaptAnalysisTask(cfgc, TaskName{"EMCPi0QCTaskAmbiguous"}, SetDefaultProcesses{{{"processCollision", false}, {"processAmbiguous", true}}})}; + adaptAnalysisTask(cfgc, TaskName{"EmcalPi0QcAssociate"}, SetDefaultProcesses{{{"processCollision", true}, {"processAmbiguous", false}}}), // o2-linter: disable=name/o2-task (adapted multiple times) + adaptAnalysisTask(cfgc, TaskName{"EmcalPi0QcAmbiguous"}, SetDefaultProcesses{{{"processCollision", false}, {"processAmbiguous", true}}})}; // o2-linter: disable=name/o2-task (adapted multiple times) return workflow; } diff --git a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx index 99516a2aafd..6c3ef79b152 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx @@ -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. // @@ -8,32 +8,36 @@ // In applying this license CERN does 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 EMCal clusters for EMCal QC. -// Please write to: nicolas.strangmann@cern.ch - -#include -#include "TString.h" -#include "THashList.h" -#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" + +/// \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 "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" -#include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/ClusterHistograms.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -42,16 +46,16 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyEMCClusters = soa::Join; using MyEMCCluster = MyEMCClusters::iterator; -struct emcalQC { +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"}; + 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 { @@ -68,25 +72,27 @@ struct emcalQC { 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 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 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() + void defineEMEventCut() { fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); @@ -99,72 +105,98 @@ struct emcalQC { fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); } - void DefineEMCCut() + 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); + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetMinE(emccuts.minClusterE); + fEMCCut.SetMinNCell(emccuts.minNCell); + fEMCCut.SetM02Range(emccuts.minM02, emccuts.maxM02); + fEMCCut.SetTimeRange(emccuts.minClusterTime, emccuts.maxClusterTime); - 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.SetTrackMatchingEtaParams(emccuts.tmEta->at(0), emccuts.tmEta->at(1), emccuts.tmEta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.tmPhi->at(0), emccuts.tmPhi->at(1), emccuts.tmPhi->at(2)); - 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 + pow(pT + b, c); }); - fEMCCut.SetTrackMatchingPhi([&d, &e, &f](float pT) { return d + pow(pT + e, f); }); - - fEMCCut.SetMinEoverP(emccuts.EMC_Eoverp); - fEMCCut.SetUseExoticCut(emccuts.EMC_UseExoticCut); + fEMCCut.SetMinEoverP(emccuts.tmEoverP); + fEMCCut.SetUseExoticCut(emccuts.useExoticCut); } HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - std::vector zvtx_bin_edges; + std::vector zVtxBinEdges; void init(InitContext&) { - zvtx_bin_edges = std::vector(ConfVtxBins.value.begin(), ConfVtxBins.value.end()); - zvtx_bin_edges.erase(zvtx_bin_edges.begin()); + zVtxBinEdges = std::vector(confVtxBins.value.begin(), confVtxBins.value.end()); + zVtxBinEdges.erase(zVtxBinEdges.begin()); - DefineEMCCut(); - DefineEMEventCut(); + 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) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { + + if (eventcuts.onlyKeepWeightedEvents && std::fabs(collision.weight() - 1.) < 1E-10) { + continue; + } - o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision); + 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()); + } + } + } + } + } + + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&fRegistry, collision, collision.weight()); 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 + 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 clusters_per_coll = clusters.sliceBy(perCollision, collision.collisionId()); - fRegistry.fill(HIST("Cluster/before/hNgamma"), clusters_per_coll.size()); - int ng = 0; - for (auto& cluster : clusters_per_coll) { + 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 - o2::aod::pwgem::photonmeson::utils::clusterhistogram::fillClusterHistograms<0>(&fRegistry, cluster, cfgDo2DQA); + 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()); - auto track = nullptr; + 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 @@ -172,8 +204,8 @@ struct emcalQC { for (int icut = 0; icut < static_cast(EMCPhotonCut::EMCPhotonCuts::kNCuts); icut++) { // Loop through different cut observables EMCPhotonCut::EMCPhotonCuts specificcut = static_cast(icut); - if (!fEMCCut.IsSelectedEMCal(specificcut, cluster, track)) { // Check whether cluster passes this cluster requirement, if not, fill why in the next row - fRegistry.fill(HIST("Cluster/hClusterQualityCuts"), icut + 1, cluster.e()); + 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 + 1, cluster.e(), collision.weight()); survivesIsSelectedEMCalCuts = false; } } @@ -183,23 +215,22 @@ struct emcalQC { } if (survivesIsSelectedCuts) { - o2::aod::pwgem::photonmeson::utils::clusterhistogram::fillClusterHistograms<1>(&fRegistry, cluster, cfgDo2DQA); - fRegistry.fill(HIST("Cluster/hClusterQualityCuts"), 7., cluster.e()); - ng++; + o2::aod::pwgem::photonmeson::utils::clusterhistogram::fillClusterHistograms<1>(&fRegistry, cluster, cfgDo2DQA, collision.weight()); + fRegistry.fill(HIST("Cluster/hClusterQualityCuts"), static_cast(EMCPhotonCut::EMCPhotonCuts::kNCuts) + 1., cluster.e(), collision.weight()); + ngAfter++; } } - fRegistry.fill(HIST("Cluster/after/hNgamma"), ng); + fRegistry.fill(HIST("Cluster/after/hNgamma"), ngAfter, collision.weight()); } // end of collision loop - } // end of process + } // 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/mcGeneratorStudies.cxx b/PWGEM/PhotonMeson/Tasks/mcGeneratorStudies.cxx new file mode 100644 index 00000000000..889858359ed --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/mcGeneratorStudies.cxx @@ -0,0 +1,55 @@ +// 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 mcGeneratorStudies.cxx +/// +/// \brief Task that produces the generated pT spectrum of a given particle for MC studies based on on the fly MC simulations +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt +/// + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" + +#include "TDatabasePDG.h" + +using namespace o2; +using namespace o2::framework; + +struct MCGeneratorStudies { + HistogramRegistry mHistManager{"MCGeneratorStudyHistograms"}; + Configurable cfgSelectedParticleCode{"cfgSelectedParticleCode", 111, "PDG code of the particle to be investigated"}; + Configurable cfgMaxZVertex{"cfgMaxZVertex", 10, "Maximum absolute z-vertex distance (cm)"}; + Configurable cfgRapidityCut{"cfgRapidityCut", 0.8, "Maximum absolute rapditity of selected generated particles"}; + ConfigurableAxis cfgMultiplicityBinning{"cfgMultiplicityBinning", {1000, 0, 10000}, "Binning used for the binning of the number of particles in the event"}; + expressions::Filter zVertexFilter = aod::mccollision::posZ < cfgMaxZVertex && aod::mccollision::posZ > -cfgMaxZVertex; + + void init(InitContext const&) + { + mHistManager.add("Multiplicity", "Number of generated particles per MC collision;#bf{#it{N} (Multiplicity)};#bf{#it{N}_{MC collisions}}", HistType::kTH1F, {cfgMultiplicityBinning}); + mHistManager.add("YieldVsMultiplicity", "pT of selected particles in all MC collisions vs number of all generated particles in event;#bf{#it{p}_{T} (GeV/#it{c})};#bf{#it{N} (Multiplicity)};#bf{#it{N}}", HistType::kTH2F, {{200, 0, 20}, cfgMultiplicityBinning}); + } + + void process(soa::Filtered::iterator const&, aod::McParticles const& mcParticles) + { + int nParticles = mcParticles.size(); + mHistManager.fill(HIST("Multiplicity"), nParticles); + for (auto& mcParticle : mcParticles) { + if (mcParticle.pdgCode() == cfgSelectedParticleCode && std::abs(mcParticle.y()) < cfgRapidityCut) + mHistManager.fill(HIST("YieldVsMultiplicity"), mcParticle.pt(), nParticles); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"mc-generator-studies"})}; } diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 47c73a3e68c..a2a06a832e9 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -14,15 +14,18 @@ // This code runs loop over v0 photons for PCM QC. // Please write to: daiki.sekihata@cern.ch -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" + #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" -#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include +#include using namespace o2; using namespace o2::aod; @@ -31,7 +34,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -53,8 +56,15 @@ struct PCMQC { 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"}; + 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; @@ -63,24 +73,27 @@ struct PCMQC { 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_require_v0_on_wwire_ib{"cfg_require_v0_on_wwire_ib", false, "flag to select V0s on W wires ITSib"}; 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_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_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "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_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_max_chi2its{"cfg_max_chi2its", 36.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; static constexpr std::string_view event_types[2] = {"before/", "after/"}; @@ -121,28 +134,29 @@ struct PCMQC { // 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, {{36, 0, 2 * M_PI}, {20, -1.0f, 1.0f}}, false); - fRegistry.add("V0/hRadius", "V0Radius; radius in Z (cm);radius in XY (cm)", kTH2F, {{200, -100, 100}, {200, 0.0f, 100.0f}}, false); - fRegistry.add("V0/hCosPA", "V0CosPA;cosine pointing angle", kTH1F, {{100, 0.9f, 1.0f}}, false); - fRegistry.add("V0/hCosPA_Rxy", "cos PA vs. R_{xy};R_{xy} (cm);cosine pointing angle", kTH2F, {{200, 0.f, 100.f}, {100, 0.9f, 1.0f}}, 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/hPCA_Rxy", "distance between 2 legs vs. R_{xy};R_{xy} (cm);PCA (cm)", kTH2F, {{200, 0.f, 100.f}, {500, 0.0f, 5.0f}}, false); - fRegistry.add("V0/hPCA_CosPA", "distance between 2 legs vs. cosPA;cosine of pointing angle;PCA (cm)", kTH2F, {{100, 0.9f, 1.f}, {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/hGammaRxy", "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/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/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}}); // 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, {{180, 0, 2 * M_PI}, {40, -2.0f, 2.0f}}, 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); @@ -152,13 +166,14 @@ struct PCMQC { 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)", kTH1F, {{32, 0, 16}}, false); - fRegistry.add("V0Leg/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {100, -50, 50}}, 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}, {100, -50, 50}}, 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); } void DefineEMEventCut() @@ -172,7 +187,11 @@ struct PCMQC { fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); } void DefinePCMCut() @@ -180,54 +199,30 @@ struct PCMQC { 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.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.SetTrackPtRange(pcmcuts.cfg_min_pt_v0 * 0.4, 1e+10f); - fV0PhotonCut.SetTrackEtaRange(-pcmcuts.cfg_max_eta_v0, +pcmcuts.cfg_max_eta_v0); 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); - - if (pcmcuts.cfg_reject_v0_on_itsib) { - fV0PhotonCut.SetNClustersITS(2, 4); - } else { - fV0PhotonCut.SetNClustersITS(0, 7); - } + fV0PhotonCut.SetNClustersITS(0, 7); fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); - fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); - - if (pcmcuts.cfg_require_v0_with_itstpc) { - fV0PhotonCut.SetRequireITSTPC(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 40); - } - if (pcmcuts.cfg_require_v0_with_itsonly) { - fV0PhotonCut.SetRequireITSonly(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 24); - } - if (pcmcuts.cfg_require_v0_with_tpconly) { - fV0PhotonCut.SetRequireTPConly(true); - fV0PhotonCut.SetMaxPCA(3.0); - fV0PhotonCut.SetRxyRange(36, 90); - } - if (pcmcuts.cfg_require_v0_on_wwire_ib) { - fV0PhotonCut.SetMaxPCA(0.3); - fV0PhotonCut.SetOnWwireIB(true); - fV0PhotonCut.SetOnWwireOB(false); - fV0PhotonCut.SetRxyRange(7, 14); - } + 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); } template @@ -255,7 +250,7 @@ struct PCMQC { if (collision.sel8()) { fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); } - if (abs(collision.posZ()) < 10.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()); @@ -275,21 +270,26 @@ struct PCMQC { { fRegistry.fill(HIST("V0/hPt"), v0.pt()); fRegistry.fill(HIST("V0/hEtaPhi"), v0.phi(), v0.eta()); - fRegistry.fill(HIST("V0/hRadius"), v0.vz(), v0.v0radius()); + 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/hCosPA_Rxy"), v0.v0radius(), 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/hPCA_CosPA"), v0.cospa(), v0.pca()); - fRegistry.fill(HIST("V0/hPCA_Rxy"), v0.v0radius(), 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/hGammaRxy"), v0.vx(), v0.vy()); 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()); + + 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 @@ -304,20 +304,25 @@ struct PCMQC { 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()); - fRegistry.fill(HIST("V0Leg/hMeanClusterSizeITS"), leg.meanClusterSizeITS() * std::cos(std::atan(leg.tgl()))); + 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()); + // 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; 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(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, aod::V0Legs const&) @@ -341,6 +346,7 @@ struct PCMQC { for (auto& v0 : v0photons_coll) { auto pos = v0.posTrack_as(); auto ele = v0.negTrack_as(); + if (!fV0PhotonCut.IsSelected(v0)) { continue; } @@ -352,7 +358,7 @@ struct PCMQC { } // end of v0 loop fRegistry.fill(HIST("V0/hNgamma"), nv0); } // end of collision loop - } // end of process + } // end of process void processDummy(MyCollisions const&) {} diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx index e5d698f1aa4..359f7811795 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx @@ -14,17 +14,20 @@ // This code runs loop over v0 photons for PCM QC. // 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/PCMUtilities.h" -#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" #include "PWGEM/Dilepton/Utils/MCUtilities.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include using namespace o2; using namespace o2::aod; @@ -35,7 +38,7 @@ 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 MyMCCollisions = soa::Join; @@ -49,12 +52,13 @@ using MyMCV0Leg = MyMCV0Legs::iterator; struct PCMQCMC { - Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2, NTPV:3"}; + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; 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"}; EMPhotonEventCut fEMEventCut; struct : ConfigurableGroup { @@ -67,8 +71,15 @@ struct PCMQCMC { 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"}; + 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; @@ -77,29 +88,32 @@ struct PCMQCMC { 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_require_v0_on_wwire_ib{"cfg_require_v0_on_wwire_ib", false, "flag to select V0s on W wires ITSib"}; 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_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_min_cospa{"cfg_min_cospa", 0.999, "min V0 CosPA"}; Configurable cfg_max_pca{"cfg_max_pca", 3.0, "max distance btween 2 legs"}; - Configurable cfg_require_v0_with_correct_xz{"cfg_require_v0_with_correct_xz", true, "flag to select V0s with correct xz"}; + Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; 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_max_chi2its{"cfg_max_chi2its", 36.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[3] = {"primary/", "fromWD/", "fromHS/"}; + static constexpr std::string_view mcphoton_types[5] = {"primary/", "fromWD/", "fromHS/", "fromPi0Dalitz/", "fromEtaDalitz/"}; void init(InitContext&) { @@ -129,12 +143,13 @@ struct PCMQCMC { 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_ConvertedPhoton", "converted photon pT;p_{T} (GeV/c)", kTH1F, {axis_pt}, true); - fRegistry.add("Generated/hY_ConvertedPhoton", "converted photon y;rapidity y", kTH1F, {{40, -2.0f, 2.0f}}, true); - fRegistry.add("Generated/hPhi_ConvertedPhoton", "converted photon #varphi;#varphi (rad.)", kTH1F, {{180, 0, 2 * M_PI}}, true); - fRegistry.add("Generated/hPhotonRxy", "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/hPhotonRZ", "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/hPhotonPhivsRxy", "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/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); } // event info @@ -163,38 +178,47 @@ struct PCMQCMC { // 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, {{36, 0, 2 * M_PI}, {20, -1.0f, 1.0f}}, false); - fRegistry.add("V0/primary/hRadius", "V0Radius; radius in Z (cm);radius in XY (cm)", kTH2F, {{200, -100, 100}, {200, 0.0f, 100.0f}}, false); - fRegistry.add("V0/primary/hCosPA", "V0CosPA;cosine pointing angle", kTH1F, {{100, 0.9f, 1.0f}}, false); - fRegistry.add("V0/primary/hCosPA_Rxy", "cos PA vs. R_{xy};R_{xy} (cm);cosine pointing angle", kTH2F, {{200, 0.f, 100.f}, {100, 0.9f, 1.0f}}, 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/hPCA_Rxy", "distance between 2 legs vs. R_{xy};R_{xy} (cm);PCA (cm)", kTH2F, {{200, 0.f, 100.f}, {500, 0.0f, 5.0f}}, false); - fRegistry.add("V0/primary/hPCA_CosPA", "distance between 2 legs vs. cosPA;cosine of pointing angle;PCA (cm)", kTH2F, {{100, 0.9f, 1.f}, {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/hGammaRxy", "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/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/hNgamma", "Number of true #gamma per collision", kTH1F, {{101, -0.5f, 100.5f}}); + 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}, {400, -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}, {400, -1.0f, 1.0f}}, true); - fRegistry.add("V0/primary/hPtGen_DeltaPhi", "photon #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{1000, 0, 10}, {400, -1.0f, 1.0f}}, true); - fRegistry.add("V0/primary/hXY_Photon_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_Photon_MC", "R vs. Z of true photon conversion point;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100.0f, +100}, {200, 0, 100}}, true); - fRegistry.addClone("V0/primary/", "V0/fromWD/"); // from weak decay - fRegistry.addClone("V0/primary/", "V0/fromHS/"); // from hadronic shower in detector materials + 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/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/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, {{180, 0, 2 * M_PI}, {40, -2.0f, 2.0f}}, 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); @@ -204,18 +228,29 @@ struct PCMQCMC { 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)", kTH1F, {{32, 0, 16}}, false); - fRegistry.add("V0Leg/primary/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {100, -50, 50}}, 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}, {100, -50, 50}}, 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}, {400, -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}, {400, -1.0f, 1.0f}}, true); - fRegistry.add("V0Leg/primary/hPtGen_DeltaPhi", "electron #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{1000, 0, 10}, {400, -1.0f, 1.0f}}, true); - fRegistry.addClone("V0Leg/primary/", "V0Leg/fromWD/"); // from weak decay - fRegistry.addClone("V0Leg/primary/", "V0Leg/fromHS/"); // from hadronic shower in detector materials + 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); + 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); + + 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 + + fRegistry.addClone("V0Leg/primary/hPt", "V0Leg/candidate/hPt"); // only for purity + fRegistry.addClone("V0Leg/primary/hEtaPhi", "V0Leg/candidate/hEtaPhi"); // only for purity } void DefineEMEventCut() @@ -229,7 +264,11 @@ struct PCMQCMC { fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); - fEMEventCut.SetOccupancyRange(eventcuts.cfgOccupancyMin, eventcuts.cfgOccupancyMax); + fEMEventCut.SetRequireNoCollInTimeRangeStandard(eventcuts.cfgRequireNoCollInTimeRangeStandard); + fEMEventCut.SetRequireNoCollInTimeRangeStrict(eventcuts.cfgRequireNoCollInTimeRangeStrict); + fEMEventCut.SetRequireNoCollInITSROFStandard(eventcuts.cfgRequireNoCollInITSROFStandard); + fEMEventCut.SetRequireNoCollInITSROFStrict(eventcuts.cfgRequireNoCollInITSROFStrict); + fEMEventCut.SetRequireNoHighMultCollInPrevRof(eventcuts.cfgRequireNoHighMultCollInPrevRof); } void DefinePCMCut() @@ -237,54 +276,30 @@ struct PCMQCMC { 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.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.SetTrackPtRange(pcmcuts.cfg_min_pt_v0 * 0.4, 1e+10f); - fV0PhotonCut.SetTrackEtaRange(-pcmcuts.cfg_max_eta_v0, +pcmcuts.cfg_max_eta_v0); 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); - - if (pcmcuts.cfg_reject_v0_on_itsib) { - fV0PhotonCut.SetNClustersITS(2, 4); - } else { - fV0PhotonCut.SetNClustersITS(0, 7); - } + fV0PhotonCut.SetNClustersITS(0, 7); fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); - fV0PhotonCut.SetIsWithinBeamPipe(pcmcuts.cfg_require_v0_with_correct_xz); - - if (pcmcuts.cfg_require_v0_with_itstpc) { - fV0PhotonCut.SetRequireITSTPC(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 40); - } - if (pcmcuts.cfg_require_v0_with_itsonly) { - fV0PhotonCut.SetRequireITSonly(true); - fV0PhotonCut.SetMaxPCA(1.0); - fV0PhotonCut.SetRxyRange(4, 24); - } - if (pcmcuts.cfg_require_v0_with_tpconly) { - fV0PhotonCut.SetRequireTPConly(true); - fV0PhotonCut.SetMaxPCA(3.0); - fV0PhotonCut.SetRxyRange(36, 90); - } - if (pcmcuts.cfg_require_v0_on_wwire_ib) { - fV0PhotonCut.SetMaxPCA(0.3); - fV0PhotonCut.SetOnWwireIB(true); - fV0PhotonCut.SetOnWwireOB(false); - fV0PhotonCut.SetRxyRange(7, 14); - } + 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); } template @@ -312,9 +327,10 @@ struct PCMQCMC { if (collision.sel8()) { fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); } - if (abs(collision.posZ()) < 10.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()); @@ -332,16 +348,16 @@ struct PCMQCMC { { 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("hRadius"), v0.vz(), v0.v0radius()); + 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("hCosPA_Rxy"), v0.v0radius(), 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("hPCA_CosPA"), v0.cospa(), v0.pca()); - fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPCA_Rxy"), v0.v0radius(), 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("hGammaRxy"), v0.vx(), v0.vy()); 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("hKFChi2vsX"), v0.vx(), v0.chiSquareNDF()); @@ -350,11 +366,20 @@ struct PCMQCMC { 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()); + 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_Photon_MC"), mcleg.vx(), mcleg.vy()); - fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRZ_Photon_MC"), mcleg.vz(), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2))); + 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); } template @@ -369,30 +394,38 @@ struct PCMQCMC { 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()); - fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hMeanClusterSizeITS"), leg.meanClusterSizeITS() * std::cos(std::atan(leg.tgl()))); + 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()); + // 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()); + 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()); } 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(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, MyMCV0Legs const&, aod::EMMCParticles const& mcparticles, aod::EMMCEvents const&) { for (auto& collision : collisions) { - const float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -406,7 +439,7 @@ struct PCMQCMC { fRegistry.fill(HIST("Event/after/hCollisionCounter"), 10.0); // accepted auto V0Photons_coll = v0photons.sliceBy(perCollision, collision.globalIndex()); - int ng_primary = 0, ng_wd = 0, ng_hs = 0; + 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(); @@ -418,38 +451,80 @@ struct PCMQCMC { 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); - if (photonid < 0) { + 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; } - auto mcphoton = mcparticles.iteratorAt(photonid); - if (mcphoton.isPhysicalPrimary() || mcphoton.producedByGenerator()) { - fillV0Info<0>(v0, mcphoton, elemc); - for (auto& leg : {pos, ele}) { - fillV0LegInfo<0>(leg); + 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); + } + 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); + } + 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++; } - 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); + } else if (etaid > 0) { + auto mceta = mcparticles.iteratorAt(etaid); + if (cfgRequireTrueAssociation && (mceta.emmceventId() != collision.emmceventId())) { + continue; } - ng_wd++; - } else { - fillV0Info<2>(v0, mcphoton, elemc); - for (auto& leg : {pos, ele}) { - fillV0LegInfo<2>(leg); + if (mceta.isPhysicalPrimary() || mceta.producedByGenerator()) { + fillV0Info<4>(v0, mceta, elemc); + for (auto& leg : {pos, ele}) { + fillV0LegInfo<4>(leg); + } + nee_eta++; } - ng_hs++; - // LOGF(info, "mcphoton.vx() = %f, mcphoton.vy() = %f, mcphoton.vz() = %f, mother_pdg = %d", mcphoton.vx(), mcphoton.vy(), mcphoton.vz(), mother_pdg); } } // 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 + } // end of process template void fillBinnedData(TBinnedData const& binned_data, const float weight = 1.f) @@ -482,7 +557,7 @@ struct PCMQCMC { // all MC tracks which belong to the MC event corresponding to the current reconstructed event for (auto& collision : collisions) { - const float centralities[4] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C(), collision.centNTPV()}; + const float centralities[3] = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { continue; } @@ -498,22 +573,34 @@ struct PCMQCMC { auto mctracks_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); for (auto& mctrack : mctracks_coll) { - if (abs(mctrack.y()) > pcmcuts.cfg_max_eta_v0) { + if (std::fabs(mctrack.y()) > pcmcuts.cfg_max_eta_v0) { continue; } - if (abs(mctrack.pdgCode()) == 22 && (mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { - fRegistry.fill(HIST("Generated/hPt_ConvertedPhoton"), mctrack.pt()); - fRegistry.fill(HIST("Generated/hY_ConvertedPhoton"), mctrack.y()); - fRegistry.fill(HIST("Generated/hPhi_ConvertedPhoton"), 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 = sqrt(pow(daughter.vx(), 2) + pow(daughter.vy(), 2)); - fRegistry.fill(HIST("Generated/hPhotonRZ"), daughter.vz(), rxy_gen_e); - fRegistry.fill(HIST("Generated/hPhotonRxy"), daughter.vx(), daughter.vy()); - fRegistry.fill(HIST("Generated/hPhotonPhivsRxy"), daughter.phi(), rxy_gen_e); + 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))); + + if (rxy_gen_e < std::fabs(daughter.vz()) * std::tan(2 * std::atan(std::exp(-pcmcuts.cfg_max_eta_v0))) - margin_z_mc) { + continue; + } + 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&) {} diff --git a/PWGEM/PhotonMeson/Tasks/phosQC.cxx b/PWGEM/PhotonMeson/Tasks/phosQC.cxx index e7009b94f05..5f42145883e 100644 --- a/PWGEM/PhotonMeson/Tasks/phosQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/phosQC.cxx @@ -14,25 +14,31 @@ // This code runs loop over PHOS clusters for PHOS QC. // Please write to: daiki.sekihata@cern.ch -#include -#include "TString.h" -#include "THashList.h" -#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/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" +#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.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/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "THashList.h" +#include "TString.h" + +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -42,7 +48,7 @@ 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 phosQC { @@ -148,8 +154,8 @@ struct phosQC { } // end of v0 loop reinterpret_cast(fMainList->FindObject("Cluster")->FindObject(cut.GetName())->FindObject("hNgamma"))->Fill(ng); } // end of cut loop - } // end of collision loop - } // end of process + } // end of collision loop + } // end of process void processDummy(MyCollisions const&) {} diff --git a/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx b/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx new file mode 100644 index 00000000000..972c805f340 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/prefilterPhoton.cxx @@ -0,0 +1,636 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +// #include "Common/Core/RecoDecay.h" +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/DalitzEECut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include "Common/Core/trackUtilities.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.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_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); + } + + 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..729759af7b2 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -0,0 +1,1508 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +enum QvecEstimator { + FT0M = 0, + FT0A = 1, + FT0C, + TPCPos, + TPCNeg, + TPCTot, + FV0A +}; + +enum CentralityEstimator { + None = 0, + CFT0A = 1, + CFT0C, + CFT0M, + NCentralityEstimators +}; + +enum Harmonics { + kNone = 0, + kDirect = 1, + kElliptic = 2, + kTriangluar = 3, + kQuadrangular = 4, + kPentagonal = 5, + kHexagonal = 6, + kHeptagonal = 7, + kOctagonal = 8 +}; + +enum class MapLevel { + kGood = 1, + kNoBad = 2, + kInEMC = 3, + kAll = 4 +}; + +struct TaskPi0FlowEMC { + static constexpr float MinEnergy = 0.7f; + + // 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, FV0A: 6)"}; + 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, FV0A: 6)"}; + 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, FV0A: 6)"}; + 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 cfgMaxQVector{"cfgMaxQVector", 20.f, "Maximum allowed absolute QVector value."}; + Configurable cfgMaxAsymmetry{"cfgMaxAsymmetry", 0.1f, "Maximum allowed asymmetry for photon pairs used in calibration."}; + + // configurable axis + ConfigurableAxis thnConfigAxisInvMass{"thnConfigAxisInvMass", {400, 0.0, 0.8}, "invariant mass axis for the neutral meson"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {100, 0., 20.}, "pT axis for the neutral meson"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {20, 0., 100.}, "centrality axis for the current event"}; + ConfigurableAxis thnConfigAxisCosNPhi{"thnConfigAxisCosNPhi", {100, -1., 1.}, "cos(n*phi) axis for the current event"}; + ConfigurableAxis thnConfigAxisCosDeltaPhi{"thnConfigAxisCosDeltaPhi", {8, -1., 1.}, "cos(delta phi) axis for the current event"}; + ConfigurableAxis thnConfigAxisM02{"thnConfigAxisM02", {200, 0., 5.}, "M02 axis for the EMCal cluster"}; + ConfigurableAxis thnConfigAxisEnergyCalib{"thnConfigAxisEnergyCalib", {200, 0., 20.}, "energy axis for the emcal clusters for the calibration process"}; + + 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)"}; + } 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> emcSecTMEta{"emcSecTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> emcSecTMPhi{"emcSecTMPhi", {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 emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary 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"}; + Configurable cfgEnableNonLin{"cfgEnableNonLin", false, "flag to turn extra non linear energy calibration on/off"}; + } 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 && aod::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; + using Colls = 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 for the look up table + static constexpr double EtaMin = -0.75, etaMax = 0.75; + static constexpr int NBinsEta = 150; // 150 bins for eta + + static constexpr double PhiMin = 1.35, phiMax = 5.75; + static constexpr int NBinsPhi = 440; // (440 bins = 0.01 step size covering most regions) + + std::array lookupTable1D; + float epsilon = 1.e-8; + + // static constexpr + static constexpr int64_t NMinPhotonRotBkg = 3; + + // Usage when cfgEnableNonLin is enabled + std::unique_ptr fEMCalCorrectionFactor; // ("fEMCalCorrectionFactor","(1 + [0]/x + [1]/x^2) / (1 + [2]/x)", 0.3, 100.); + + // 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"); + + fEMCCut.SetTrackMatchingEtaParams(emccuts.cfgEMCTMEta->at(0), emccuts.cfgEMCTMEta->at(1), emccuts.cfgEMCTMEta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.cfgEMCTMPhi->at(0), emccuts.cfgEMCTMPhi->at(1), emccuts.cfgEMCTMPhi->at(2)); + + fEMCCut.SetSecTrackMatchingEtaParams(emccuts.emcSecTMEta->at(0), emccuts.emcSecTMEta->at(1), emccuts.emcSecTMEta->at(2)); + fEMCCut.SetSecTrackMatchingPhiParams(emccuts.emcSecTMPhi->at(0), emccuts.emcSecTMPhi->at(1), emccuts.emcSecTMPhi->at(2)); + 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); + fEMCCut.SetUseTM(emccuts.cfgEMCUseTM.value); // disables or enables TM + fEMCCut.SetUseSecondaryTM(emccuts.emcUseSecondaryTM.value); // disables or enables secondary TM + } + + void init(InitContext&) + { + if (harmonic != kElliptic && harmonic != kTriangluar) { + LOG(info) << "Harmonic was set to " << harmonic << " but can only be 2 or 3!"; + } + + defineEMEventCut(); + defineEMCCut(); + 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 thnAxisM02{thnConfigAxisM02, "M_{02}"}; + const AxisSpec thAxisTanThetaPhi{mesonConfig.thConfigAxisTanThetaPhi, "atan(#Delta#theta/#Delta#varphi)"}; + const AxisSpec thAxisClusterEnergy{thnConfigAxisPt, "#it{E} (GeV)"}; + const AxisSpec thAxisEnergyCalib{thnConfigAxisEnergyCalib, "#it{E}_{clus} (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 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 thAxisAzimuth{360, -o2::constants::math::PI, o2::constants::math::PI, "#it{#varphi} (rad)"}; + + 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", " vs m_{inv} vs p_T vs cent for same event", HistType::kTProfile3D, {thnAxisInvMass, thnAxisPt, thnAxisCent}); + registry.add("hSparsePi0", "m_{inv} vs p_T vs cent for same event", HistType::kTH3D, {thnAxisInvMass, thnAxisPt, thnAxisCent}); + + registry.add("hSparseBkgMixFlow", " vs m_{inv} vs p_T vs cent for mixed event", HistType::kTProfile3D, {thnAxisInvMass, thnAxisPt, thnAxisCent}); + registry.add("hSparseBkgMix", "m_{inv} vs p_T vs cent for mixed event", HistType::kTH3D, {thnAxisInvMass, thnAxisPt, thnAxisCent}); + + if (cfgDoRotation.value) { + registry.add("hSparseBkgRotFlow", " vs m_{inv} vs p_T vs cent for rotation background", HistType::kTProfile3D, {thnAxisInvMass, thnAxisPt, thnAxisCent}); + registry.add("hSparseBkgRot", "m_{inv} vs p_T vs cent for rotation background", HistType::kTH3D, {thnAxisInvMass, thnAxisPt, thnAxisCent}); + } + + 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.value) { + registry.add("spReso/hSpResoFT0cFT0a", "hSpResoFT0cFT0a; centrality; Q_{FT0c} #bullet Q_{FT0a}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0cTPCpos", "hSpResoFT0cTPCpos; centrality; Q_{FT0c} #bullet Q_{TPCpos}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0cTPCneg", "hSpResoFT0cTPCneg; centrality; Q_{FT0c} #bullet Q_{TPCneg}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0cTPCtot", "hSpResoFT0cTPCtot; centrality; Q_{FT0c} #bullet Q_{TPCtot}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0aTPCpos", "hSpResoFT0aTPCpos; centrality; Q_{FT0a} #bullet Q_{TPCpos}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0aTPCneg", "hSpResoFT0aTPCneg; centrality; Q_{FT0a} #bullet Q_{TPCneg}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0aTPCtot", "hSpResoFT0aTPCtot; centrality; Q_{FT0m} #bullet Q_{TPCtot}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0mTPCpos", "hSpResoFT0mTPCpos; centrality; Q_{FT0m} #bullet Q_{TPCpos}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0mTPCneg", "hSpResoFT0mTPCneg; centrality; Q_{FT0m} #bullet Q_{TPCneg}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFT0mTPCtot", "hSpResoFT0mTPCtot; centrality; Q_{FT0m} #bullet Q_{TPCtot}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoTPCposTPCneg", "hSpResoTPCposTPCneg; centrality; Q_{TPCpos} #bullet Q_{TPCneg}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFV0aFT0c", "hSpResoFV0aFT0c; centrality; Q_{FV0a} #bullet Q_{FT0c}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFV0aTPCpos", "hSpResoFV0aTPCpos; centrality; Q_{FV0a} #bullet Q_{TPCpos}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFV0aTPCneg", "hSpResoFV0aTPCneg; centrality; Q_{FV0a} #bullet Q_{TPCneg}", HistType::kTProfile, {thnAxisCent}); + registry.add("spReso/hSpResoFV0aTPCtot", "hSpResoFV0aTPCtot; centrality; Q_{FV0a} #bullet Q_{TPCtot}", HistType::kTProfile, {thnAxisCent}); + } + + if (saveEpResoHisto.value) { + registry.add("hEventPlaneAngleFT0C", "hEventPlaneAngleFT0C", HistType::kTH2D, {thnAxisCent, thAxisPsi}); + registry.add("hEventPlaneAngleFT0A", "hEventPlaneAngleFT0A", HistType::kTH2D, {thnAxisCent, thAxisPsi}); + registry.add("hEventPlaneAngleFT0M", "hEventPlaneAngleFT0M", HistType::kTH2D, {thnAxisCent, thAxisPsi}); + registry.add("hEventPlaneAngleFV0A", "hEventPlaneAngleFV0A", 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/hEpResoFV0aFT0c", "hEpResoFV0aFT0c; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFV0aTPCpos", "hEpResoFV0aTPCpos; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFV0aTPCneg", "hEpResoFV0aTPCneg; centrality; #Delta#Psi_{sub}", HistType::kTH2D, {thnAxisCent, thnAxisCosNPhi}); + registry.add("epReso/hEpResoFV0aTPCtot", "hEpResoFV0aTPCtot; 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/hEpCosCoefficientsFV0a", "hEpCosCoefficientsFV0a; centrality; c_{n}", HistType::kTProfile2D, {thnAxisCent, thAxisCN}); + registry.add("epReso/hEpSinCoefficientsFV0a", "hEpSinCoefficientsFV0a; 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}); + registry.add("QVector/hQVecMeanRVsPhiFT0a", "hQVecMeanRVsPhiFT0a; centrality; #it{#varphi} (rad), <#it{r}> (a.u.)", HistType::kTProfile2D, {thnAxisCent, thAxisAzimuth}); + registry.add("QVector/hQVecMeanRVsPhiFT0c", "hQVecMeanRVsPhiFT0c; centrality; #it{#varphi} (rad), <#it{r}> (a.u.)", HistType::kTProfile2D, {thnAxisCent, thAxisAzimuth}); + registry.add("QVector/hQVecMeanRVsPhiFT0m", "hQVecMeanRVsPhiFT0m; centrality; #it{#varphi} (rad), <#it{r}> (a.u.)", HistType::kTProfile2D, {thnAxisCent, thAxisAzimuth}); + registry.add("QVector/hQVecMeanRVsPhiFV0a", "hQVecMeanRVsPhiFV0a; centrality; #it{#varphi} (rad), <#it{r}> (a.u.)", HistType::kTProfile2D, {thnAxisCent, thAxisAzimuth}); + registry.add("QVector/hQVecMeanRVsPhiTPCpos", "hQVecMeanRVsPhiTPCpos; centrality; #it{#varphi} (rad), <#it{r}> (a.u.)", HistType::kTProfile2D, {thnAxisCent, thAxisAzimuth}); + registry.add("QVector/hQVecMeanRVsPhiTPCneg", "hQVecMeanRVsPhiTPCneg; centrality; #it{#varphi} (rad), <#it{r}> (a.u.)", HistType::kTProfile2D, {thnAxisCent, thAxisAzimuth}); + registry.add("QVector/hQVecMeanRVsPhiTPCTot", "hQVecMeanRVsPhiTPCTot; centrality; #it{#varphi} (rad), <#it{r}> (a.u.)", HistType::kTProfile2D, {thnAxisCent, thAxisAzimuth}); + } + + if (emccuts.cfgEnableQA.value) { + registry.add("clusterQA/hEClusterBefore", "Histo for cluster energy before cuts", HistType::kTH1D, {thAxisClusterEnergy}); + registry.add("clusterQA/hEClusterAfter", "Histo for cluster energy after cuts", HistType::kTH1D, {thAxisClusterEnergy}); + registry.add("clusterQA/hClusterEtaPhiBefore", "hClusterEtaPhiBefore", HistType::kTH2D, {thAxisPhi, thAxisEta}); + registry.add("clusterQA/hClusterEtaPhiAfter", "hClusterEtaPhiAfter", HistType::kTH2D, {thAxisPhi, thAxisEta}); + if (cfgDoRotation.value) { + registry.add("clusterQA/hClusterBackEtaPhiBefore", "hClusterBackEtaPhiBefore", HistType::kTH2D, {thAxisPhi, thAxisEta}); + registry.add("clusterQA/hClusterBackEtaPhiAfter", "hClusterBackEtaPhiAfter", HistType::kTH2D, {thAxisPhi, thAxisEta}); + } + } + + if (mesonConfig.cfgEnableQA.value) { + registry.add("mesonQA/hInvMassPt", "Histo for inv pair mass vs pt", HistType::kTH2D, {thnAxisInvMass, thnAxisPt}); + registry.add("mesonQA/hTanThetaPhi", "Histo for identification of conversion cluster", HistType::kTH2D, {thnAxisInvMass, thAxisTanThetaPhi}); + registry.add("mesonQA/hAlphaPt", "Histo of meson asymmetry vs pT", HistType::kTH2D, {thAxisAlpha, thnAxisPt}); + registry.add("mesonQA/hInvMassPtMixed", "Histo for inv pair mass vs pt for mixed event", HistType::kTH2D, {thnAxisInvMass, thnAxisPt}); + registry.add("mesonQA/hTanThetaPhiMixed", "Histo for identification of conversion cluster for mixed event", HistType::kTH2D, {thnAxisInvMass, thAxisTanThetaPhi}); + registry.add("mesonQA/hAlphaPtMixed", "Histo of meson asymmetry vs pT for mixed event", HistType::kTH2D, {thAxisAlpha, thnAxisPt}); + } + + if (correctionConfig.doEMCalCalib.value) { + 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("p3DM02Flow", " vs M_{02} vs p_T vs cent", HistType::kTProfile3D, {thnAxisM02, thnAxisPt, thnAxisCent}); + registry.add("h3DSparsePi0", "M_{02} vs p_T vs cent", HistType::kTH3D, {thnAxisM02, thnAxisPt, thnAxisCent}); + } + + 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(); + + fEMCalCorrectionFactor = std::make_unique("fEMCalCorrectionFactor", "(1 + [0]/x + [1]/x^2) / (1 + [2]/x)", 0.3, 100.); + fEMCalCorrectionFactor->SetParameters(-5.33426e-01, 1.40144e-02, -5.24434e-01); + }; // 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(const float mass, const float pt, const float cent, const float sp) + { + static constexpr std::string_view FlowHistTypes[3] = {"hSparsePi0Flow", "hSparseBkgRotFlow", "hSparseBkgMixFlow"}; + static constexpr std::string_view HistTypes[3] = {"hSparsePi0", "hSparseBkgRot", "hSparseBkgMix"}; + registry.fill(HIST(FlowHistTypes[histType]), mass, pt, cent, sp); + registry.fill(HIST(HistTypes[histType]), mass, pt, cent); + } + + /// Get the centrality + /// \param collision is the collision with the centrality information + template + float getCentrality(TCollision 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 + template + std::vector getAllQvec(TCollision 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 + template + std::pair getQvec(TCollision const& collision, int detector) + { + float xQVec = -999.f; + float yQVec = -999.f; + + switch (detector) { + case QvecEstimator::FT0M: + if (harmonic == kElliptic) { + xQVec = collision.q2xft0m(); + yQVec = collision.q2yft0m(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xft0m(); + yQVec = collision.q3yft0m(); + } + break; + case QvecEstimator::FT0A: + if (harmonic == kElliptic) { + xQVec = collision.q2xft0a(); + yQVec = collision.q2yft0a(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xft0a(); + yQVec = collision.q3yft0a(); + } + break; + case QvecEstimator::FT0C: + if (harmonic == kElliptic) { + xQVec = collision.q2xft0c(); + yQVec = collision.q2yft0c(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xft0c(); + yQVec = collision.q3yft0c(); + } + break; + case QvecEstimator::TPCPos: + if (harmonic == kElliptic) { + xQVec = collision.q2xbpos(); + yQVec = collision.q2ybpos(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xbpos(); + yQVec = collision.q3ybpos(); + } + break; + case QvecEstimator::TPCNeg: + if (harmonic == kElliptic) { + xQVec = collision.q2xbneg(); + yQVec = collision.q2ybneg(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xbneg(); + yQVec = collision.q3ybneg(); + } + break; + case QvecEstimator::TPCTot: + if (harmonic == kElliptic) { + xQVec = collision.q2xbtot(); + yQVec = collision.q2ybtot(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xbtot(); + yQVec = collision.q3ybtot(); + } + break; + case QvecEstimator::FV0A: + if (harmonic == kElliptic) { + xQVec = collision.q2xfv0a(); + yQVec = collision.q2yfv0a(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xfv0a(); + yQVec = collision.q3yfv0a(); + } + break; + default: + LOG(warning) << "Q vector estimator not valid. Falling back to FT0M"; + if (harmonic == kElliptic) { + xQVec = collision.q2xft0m(); + yQVec = collision.q2yft0m(); + } else if (harmonic == kTriangluar) { + 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) > cfgMaxQVector) { + 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.fill(-1); + double binWidthEta = (etaMax - EtaMin) / NBinsEta; + double binWidthPhi = (phiMax - PhiMin) / NBinsPhi; + + if (cfgEMCalMapLevelBackground.value >= static_cast(MapLevel::kAll) && cfgEMCalMapLevelSameEvent >= static_cast(MapLevel::kAll)) { + // in this case we do not want to check the clusters, so just say thery are all good. + lookupTable1D.fill(0); // good + } else { + 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, TCollision const& collision) + { + // if less than 3 clusters are present skip event since we need at least 3 clusters + if (photons_coll.size() < NMinPhotonRotBkg) { + 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.value) { + registry.fill(HIST("clusterQA/hClusterBackEtaPhiBefore"), RecoDecay::constrainAngle(photon1.Phi()), photon1.Eta()); // before check but after rotation + registry.fill(HIST("clusterQA/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.value) { + registry.fill(HIST("clusterQA/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.value) { + registry.fill(HIST("clusterQA/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; + } + float energyCorrectionFactor = 1.f; + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(photon.e() > MinEnergy ? photon.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector photon3(energyCorrectionFactor * 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); + registry.fill(HIST("hSparseBkgRot"), mother1.M(), mother1.Pt(), cent); + } + } else { + registry.fill(HIST("hSparseBkgRotFlow"), mother1.M(), mother1.Pt(), cent, scalprodCand1); + registry.fill(HIST("hSparseBkgRot"), mother1.M(), mother1.Pt(), cent); + } + } + } + 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); + registry.fill(HIST("hSparseBkgRot"), mother2.M(), mother2.Pt(), cent); + } + } else { + registry.fill(HIST("hSparseBkgRotFlow"), mother2.M(), mother2.Pt(), cent, scalprodCand2); + registry.fill(HIST("hSparseBkgRot"), mother2.M(), mother2.Pt(), cent); + } + } + } + } // 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, TCollision const& collision) + { + // if less than 3 clusters are present skip event since we need at least 3 clusters + if (photons_coll.size() < NMinPhotonRotBkg) { + 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; + } + float energyCorrectionFactor = 1.f; + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(photon.e() > MinEnergy ? photon.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector photon3(energyCorrectionFactor * photon.pt(), photon.eta(), photon.phi(), 0.); + if (iCellIDPhoton1 >= 0) { + if (std::fabs((photon1.E() - photon3.E()) / (photon1.E() + photon3.E()) < cfgMaxAsymmetry)) { // 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()) < cfgMaxAsymmetry)) { // 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(TCollision 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; + float energyCorrectionFactor = 1.f; + if (cfgDoReverseScaling.value) { + energyCorrectionFactor = 1.0505f; + } + 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.value) { + for (const auto& photon : photonsPerCollision) { + registry.fill(HIST("clusterQA/hEClusterBefore"), photon.e()); // before cuts + registry.fill(HIST("clusterQA/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("clusterQA/hEClusterAfter"), photon.e()); // accepted after cuts + registry.fill(HIST("clusterQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // 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; + } + } + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g2.e() > MinEnergy ? g2.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v2(energyCorrectionFactor * g2.pt(), g2.eta(), g2.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.value) { + registry.fill(HIST("mesonQA/hInvMassPt"), vMeson.M(), vMeson.Pt()); + registry.fill(HIST("mesonQA/hTanThetaPhi"), vMeson.M(), getAngleDegree(std::atan(dTheta / dPhi))); + registry.fill(HIST("mesonQA/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) + { + float energyCorrectionFactor = 1.f; + if (cfgDoReverseScaling.value) { + energyCorrectionFactor = 1.0505f; + } + 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; + } + } + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g2.e() > MinEnergy ? g2.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v2(energyCorrectionFactor * g2.pt(), g2.eta(), g2.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.value) { + registry.fill(HIST("mesonQA/hInvMassPtMixed"), vMeson.M(), vMeson.Pt()); + registry.fill(HIST("mesonQA/hTanThetaPhiMixed"), vMeson.M(), getAngleDegree(std::atan(dTheta / dPhi))); + registry.fill(HIST("mesonQA/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; + float xQVecFV0a = -999.f; + float yQVecFV0a = -999.f; + if (harmonic == kElliptic) { + 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(); + xQVecFV0a = collision.q2xfv0a(); + yQVecFV0a = collision.q2yfv0a(); + } else if (harmonic == kTriangluar) { + 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(); + xQVecFV0a = collision.q3xfv0a(); + yQVecFV0a = collision.q3yfv0a(); + } + + 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); + registry.fill(HIST("spReso/hSpResoFV0aFT0c"), centrality, xQVecFV0a * xQVecFT0c + yQVecFV0a * yQVecFT0c); + 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); + } + + 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); + float epFV0a = epHelper.GetEventPlane(xQVecFV0a, yQVecFV0a, harmonic); + + registry.fill(HIST("hEventPlaneAngleFT0M"), centrality, epFT0m); + registry.fill(HIST("hEventPlaneAngleFT0A"), centrality, epFT0c); + registry.fill(HIST("hEventPlaneAngleFT0C"), centrality, epFT0a); + registry.fill(HIST("hEventPlaneAngleTPCpos"), centrality, epBPoss); + registry.fill(HIST("hEventPlaneAngleTPCneg"), centrality, epBNegs); + registry.fill(HIST("hEventPlaneAngleFV0A"), centrality, epFV0a); + + registry.fill(HIST("QVector/hQVecMeanRVsPhiFT0a"), centrality, std::atan2(yQVecFT0a, xQVecFT0a), std::hypot(xQVecFT0a, yQVecFT0a)); + registry.fill(HIST("QVector/hQVecMeanRVsPhiFT0c"), centrality, std::atan2(yQVecFT0c, xQVecFT0c), std::hypot(xQVecFT0c, yQVecFT0c)); + registry.fill(HIST("QVector/hQVecMeanRVsPhiFT0m"), centrality, std::atan2(yQVecFT0m, xQVecFT0m), std::hypot(xQVecFT0m, yQVecFT0m)); + registry.fill(HIST("QVector/hQVecMeanRVsPhiTPCpos"), centrality, std::atan2(yQVecBPos, xQVecBPos), std::hypot(xQVecBPos, yQVecBPos)); + registry.fill(HIST("QVector/hQVecMeanRVsPhiTPCneg"), centrality, std::atan2(yQVecBNeg, xQVecBNeg), std::hypot(xQVecBNeg, yQVecBNeg)); + registry.fill(HIST("QVector/hQVecMeanRVsPhiTPCTot"), centrality, std::atan2(yQVecBTot, xQVecBTot), std::hypot(xQVecBTot, yQVecBTot)); + registry.fill(HIST("QVector/hQVecMeanRVsPhiFV0a"), centrality, std::atan2(yQVecFV0a, xQVecFV0a), std::hypot(xQVecFV0a, yQVecFV0a)); + + 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))); + registry.fill(HIST("epReso/hEpResoFV0aFT0c"), centrality, std::cos(harmonic * getDeltaPsiInRange(epFV0a, epFT0c))); + 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))); + for (int n = 1; n <= kOctagonal; n++) { + registry.fill(HIST("epReso/hEpCosCoefficientsFT0c"), centrality, n, std::cos(n * harmonic * epFT0c)); + registry.fill(HIST("epReso/hEpSinCoefficientsFT0c"), centrality, n, std::sin(n * harmonic * epFT0c)); + registry.fill(HIST("epReso/hEpCosCoefficientsFT0a"), centrality, n, std::cos(n * harmonic * epFT0a)); + registry.fill(HIST("epReso/hEpSinCoefficientsFT0a"), centrality, n, std::sin(n * harmonic * epFT0a)); + registry.fill(HIST("epReso/hEpCosCoefficientsFT0m"), centrality, n, std::cos(n * harmonic * epFT0m)); + registry.fill(HIST("epReso/hEpSinCoefficientsFT0m"), centrality, n, std::sin(n * harmonic * epFT0m)); + registry.fill(HIST("epReso/hEpCosCoefficientsTPCpos"), centrality, n, std::cos(n * harmonic * epBPoss)); + registry.fill(HIST("epReso/hEpSinCoefficientsTPCpos"), centrality, n, std::sin(n * harmonic * epBPoss)); + registry.fill(HIST("epReso/hEpCosCoefficientsTPCneg"), centrality, n, std::cos(n * harmonic * epBNegs)); + registry.fill(HIST("epReso/hEpSinCoefficientsTPCneg"), centrality, n, std::sin(n * harmonic * epBNegs)); + registry.fill(HIST("epReso/hEpCosCoefficientsTPCTots"), centrality, n, std::cos(n * harmonic * epBTots)); + registry.fill(HIST("epReso/hEpSinCoefficientsTPCTots"), centrality, n, std::sin(n * harmonic * epBTots)); + registry.fill(HIST("epReso/hEpCosCoefficientsFV0a"), centrality, n, std::cos(n * harmonic * epFV0a)); + registry.fill(HIST("epReso/hEpSinCoefficientsFV0a"), centrality, n, std::sin(n * harmonic * epFV0a)); + } + } + } + PROCESS_SWITCH(TaskPi0FlowEMC, processResolution, "Process resolution", false); + + // EMCal calibration + void processEMCalCalib(Colls const& collisions, EMCalPhotons const& clusters) + { + float energyCorrectionFactor = 1.f; + 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; + } + 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.value) { + for (const auto& photon : photonsPerCollision) { + registry.fill(HIST("clusterQA/hEClusterBefore"), photon.e()); // before cuts + if (!(fEMCCut.IsSelected(photon))) { + continue; + } + registry.fill(HIST("clusterQA/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; + } + } + + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g2.e() > MinEnergy ? g2.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v2(energyCorrectionFactor * g2.pt(), g2.eta(), g2.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.value) { + registry.fill(HIST("mesonQA/hInvMassPt"), vMeson.M(), vMeson.Pt()); + registry.fill(HIST("mesonQA/hTanThetaPhi"), vMeson.M(), getAngleDegree(std::atan(dTheta / dPhi))); + registry.fill(HIST("mesonQA/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()) < cfgMaxAsymmetry)) { // 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 mixed event", false); + + // Pi0 from EMCal + void processM02(CollsWithQvecs const& collisions, EMCalPhotons const& clusters) + { + 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 + + for (const auto& photon : photonsPerCollision) { + if (emccuts.cfgEnableQA.value) { + registry.fill(HIST("clusterQA/hEClusterBefore"), photon.e()); // before cuts + registry.fill(HIST("clusterQA/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 (emccuts.cfgEnableQA.value) { + registry.fill(HIST("clusterQA/hEClusterAfter"), photon.e()); // accepted after cuts + registry.fill(HIST("clusterQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // after 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("p3DM02Flow"), photon.m02(), photon.pt(), cent, scalprodCand); + registry.fill(HIST("h3DSparsePi0"), photon.m02(), photon.pt(), cent); + } + 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 index 143570fcd97..d4826f80ccb 100644 --- a/PWGEM/PhotonMeson/Utils/ClusterHistograms.h +++ b/PWGEM/PhotonMeson/Utils/ClusterHistograms.h @@ -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. // @@ -9,67 +9,91 @@ // 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 +/// \file ClusterHistograms.h +/// \brief Header file for histograms used in EMC cluster QA +/// \author N. Strangmann, nicolas.strangmann@cern.ch #ifndef PWGEM_PHOTONMESON_UTILS_CLUSTERHISTOGRAMS_H_ #define PWGEM_PHOTONMESON_UTILS_CLUSTERHISTOGRAMS_H_ -using namespace o2::framework; +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" + +#include +#include +#include + +#include + +#include +#include namespace o2::aod::pwgem::photonmeson::utils::clusterhistogram { -void addClusterHistograms(HistogramRegistry* fRegistry, bool do2DQA) +inline void addClusterHistograms(o2::framework::HistogramRegistry* fRegistry, bool do2DQA) { - fRegistry->add("Cluster/before/hE", "E_{cluster};#it{E}_{cluster} (GeV);#it{N}_{cluster}", kTH1F, {{500, 0, 50}}, true); - fRegistry->add("Cluster/before/hPt", "Transverse momenta of clusters;#it{p}_{T} (GeV/c);#it{N}_{cluster}", kTH1F, {{1000, 0.0f, 20}}, true); - fRegistry->add("Cluster/before/hNgamma", "Number of #gamma candidates per collision;#it{N}_{#gamma} per collision;#it{N}_{collisions}", kTH1F, {{101, -0.5f, 100.5f}}, true); - fRegistry->add("Cluster/before/hEtaPhi", "#eta vs #varphi;#eta;#varphi (rad.)", kTH2F, {{200, -1.0f, 1.0f}, {180, 0, 2 * M_PI}}, true); - fRegistry->add("Cluster/before/hTrackEtaPhi", "d#eta vs. d#varphi of matched tracks;d#eta;d#varphi (rad.)", kTH2F, {{100, -0.5, 0.5}, {100, -0.5, 0.5}}, true); + fRegistry->add("Cluster/before/hE", "E_{cluster};#it{E}_{cluster} (GeV);#it{N}_{cluster}", o2::framework::kTH1F, {{500, 0.0f, 50}}, true); + fRegistry->add("Cluster/before/hPt", "Transverse momenta of clusters;#it{p}_{T} (GeV/c);#it{N}_{cluster}", o2::framework::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}", o2::framework::kTH1F, {{51, -0.5f, 50.5f}}, true); + fRegistry->add("Cluster/before/hEtaPhi", "#eta vs #varphi;#eta;#varphi (rad.)", o2::framework::kTH2F, {{280, -0.7f, 0.7f}, {180, 0, o2::constants::math::TwoPI}}, true); + fRegistry->add("Cluster/before/hNTracks", "Number of tracks considered for TM;#it{N}_{tracks};#it{N}_{cluster}", o2::framework::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.)", o2::framework::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, {{51, -0.5, 50.5}, {200, 0, 20}}, true); - fRegistry->add("Cluster/before/hM02", "Long ellipse axis;#it{M}_{02} (cm);#it{E}_{cluster} (GeV)", kTH2F, {{500, 0, 5}, {200, 0, 20}}, true); - fRegistry->add("Cluster/before/hTime", "Cluster time;#it{t}_{cls} (ns);#it{E}_{cluster} (GeV)", kTH2F, {{100, -250, 250}, {200, 0, 20}}, true); - fRegistry->add("Cluster/before/hCellTime", "Cell time;#it{t}_{cell} (ns);#it{E}_{cluster} (GeV)", kTH2F, {{100, -250, 250}, {200, 0, 20}}, true); + fRegistry->add("Cluster/before/hNCell", "#it{N}_{cells};N_{cells} (GeV);#it{E}_{cluster} (GeV)", o2::framework::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)", o2::framework::kTH2F, {{200, 0, 2}, {200, 0, 20}}, true); + fRegistry->add("Cluster/before/hTime", "Cluster time;#it{t}_{cls} (ns);#it{E}_{cluster} (GeV)", o2::framework::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)", o2::framework::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)", o2::framework::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)", o2::framework::kTH2F, {{200, 0., 5.}, {200, 0, 20}}, true); } else { - fRegistry->add("Cluster/before/hNCell", "#it{N}_{cells};N_{cells} (GeV);#it{N}_{cluster}", kTH1F, {{51, -0.5, 50.5}}, true); - fRegistry->add("Cluster/before/hM02", "Long ellipse axis;#it{M}_{02} (cm);#it{N}_{cluster}", kTH1F, {{500, 0, 5}}, true); - fRegistry->add("Cluster/before/hTime", "Cluster time;#it{t}_{cls} (ns);#it{N}_{cluster}", kTH1F, {{500, -250, 250}}, true); - fRegistry->add("Cluster/before/hCellTime", "Cluster time;#it{t}_{cell} (ns);#it{N}_{cluster}", kTH1F, {{500, -250, 250}}, true); + fRegistry->add("Cluster/before/hNCell", "#it{N}_{cells};N_{cells} (GeV);#it{N}_{cluster}", o2::framework::kTH1F, {{26, -0.5, 25.5}}, true); + fRegistry->add("Cluster/before/hM02", "Long ellipse axis;#it{M}_{02} (cm);#it{N}_{cluster}", o2::framework::kTH1F, {{400, 0, 2}}, true); + fRegistry->add("Cluster/before/hTime", "Cluster time;#it{t}_{cls} (ns);#it{N}_{cluster}", o2::framework::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})", o2::framework::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); + auto hClusterQualityCuts = fRegistry->add("Cluster/hClusterQualityCuts", "Energy at which clusters are removed by a given cut;;#it{E} (GeV)", o2::framework::kTH2F, {{static_cast(EMCPhotonCut::EMCPhotonCuts::kNCuts) + 2, -0.5, static_cast(EMCPhotonCut::EMCPhotonCuts::kNCuts) + 1.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"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(2, "Definition"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(3, "Energy"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(4, "NCell"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(5, "M02"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(6, "Timing"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(7, "TM"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(8, "Sec. TM"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(9, "Exotic"); + hClusterQualityCuts->GetXaxis()->SetBinLabel(10, "Out"); fRegistry->addClone("Cluster/before/", "Cluster/after/"); } -template -void fillClusterHistograms(HistogramRegistry* fRegistry, SkimEMCCluster cluster, bool do2DQA) +template +inline void fillClusterHistograms(o2::framework::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.pt()); - fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hPt"), cluster.e()); - fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hEtaPhi"), cluster.eta(), cluster.phi()); - 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("hTrackEtaPhi"), cluster.tracketa()[itrack] - cluster.eta(), cluster.trackphi()[itrack] - cluster.phi()); + static constexpr std::string_view kClusterTypes[2] = {"before/", "after/"}; + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hE"), cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hPt"), cluster.pt(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hEtaPhi"), cluster.eta(), cluster.phi(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hNTracks"), cluster.deltaEta().size(), weight); + for (size_t itrack = 0; itrack < cluster.deltaEta().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(kClusterTypes[cls_id]) + HIST("hTrackdEtadPhi"), cluster.deltaEta()[itrack], cluster.deltaPhi()[itrack], weight); } if (do2DQA) { - fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hNCell"), cluster.nCells(), cluster.e()); - fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hM02"), cluster.m02(), cluster.e()); - fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTime"), cluster.time(), cluster.e()); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hNCell"), cluster.nCells(), cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hM02"), cluster.m02(), cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hTime"), cluster.time(), cluster.e(), weight); + for (size_t itrack = 0; itrack < cluster.deltaEta().size(); itrack++) { + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hTrackEOverP"), cluster.e() / cluster.trackp()[itrack], cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hTrackdEta"), cluster.deltaEta()[itrack], cluster.e(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hTrackdPhi"), cluster.deltaPhi()[itrack], cluster.e(), weight); + } } else { - fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hNCell"), cluster.nCells()); - fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hM02"), cluster.m02()); - fRegistry->fill(HIST("Cluster/") + HIST(cluster_types[cls_id]) + HIST("hTime"), cluster.time()); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hNCell"), cluster.nCells(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hM02"), cluster.m02(), weight); + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hTime"), cluster.time(), weight); + for (size_t itrack = 0; itrack < cluster.deltaEta().size(); itrack++) { + fRegistry->fill(HIST("Cluster/") + HIST(kClusterTypes[cls_id]) + HIST("hTrackEOverP"), cluster.e() / cluster.trackp()[itrack], weight); + } } } diff --git a/PWGEM/PhotonMeson/Utils/EventHistograms.h b/PWGEM/PhotonMeson/Utils/EventHistograms.h index fd6f6f31f7f..5a00d9b6da9 100644 --- a/PWGEM/PhotonMeson/Utils/EventHistograms.h +++ b/PWGEM/PhotonMeson/Utils/EventHistograms.h @@ -9,19 +9,29 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \header file for histograms +/// \file EventHistograms.h +/// \brief header file for event histograms /// \author daiki.sekihata@cern.ch #ifndef PWGEM_PHOTONMESON_UTILS_EVENTHISTOGRAMS_H_ #define PWGEM_PHOTONMESON_UTILS_EVENTHISTOGRAMS_H_ -using namespace o2::framework; + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" + +#include +#include + +#include + +#include namespace o2::aod::pwgem::photonmeson::utils::eventhistogram { -void addEventHistograms(HistogramRegistry* fRegistry) +inline void addEventHistograms(o2::framework::HistogramRegistry* fRegistry) { // event info - auto hCollisionCounter = fRegistry->add("Event/before/hCollisionCounter", "collision counter;;Number of events", kTH1F, {{12, 0.5, 12.5}}, false); + auto hCollisionCounter = fRegistry->add("Event/before/hCollisionCounter", "collision counter;;Number of events", o2::framework::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"); @@ -35,65 +45,87 @@ void addEventHistograms(HistogramRegistry* fRegistry) 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); + const o2::framework::AxisSpec axis_cent_ft0m{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 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, 102, 103, 104, 105, 106, 107, 108, 109, 110}, + "centrality FT0M (%)"}; + + const o2::framework::AxisSpec axis_cent_ft0a{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 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, 102, 103, 104, 105, 106, 107, 108, 109, 110}, + "centrality FT0A (%)"}; + + const o2::framework::AxisSpec axis_cent_ft0c{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 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, 102, 103, 104, 105, 106, 107, 108, 109, 110}, + "centrality FT0C (%)"}; + + fRegistry->add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", o2::framework::kTH1F, {{100, -50, +50}}, false); + fRegistry->add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", o2::framework::kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry->add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", o2::framework::kTH1F, {{6001, -0.5, 6000.5}}, false); + fRegistry->add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", o2::framework::kTH2F, {{200, 0, 200000}, {60, 0, 60000}}, false); + fRegistry->add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", o2::framework::kTH1F, {{axis_cent_ft0a}}, false); + fRegistry->add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", o2::framework::kTH1F, {{axis_cent_ft0c}}, false); + fRegistry->add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", o2::framework::kTH1F, {{axis_cent_ft0m}}, false); + fRegistry->add("Event/before/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", o2::framework::kTH2F, {{110, 0, 110}, {500, 0, 5000}}, false); + fRegistry->add("Event/before/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", o2::framework::kTH2F, {{60, 0, 60000}, {500, 0, 5000}}, false); + fRegistry->add("Event/before/hMultFT0CvsOccupancy", "hMultFT0CvsOccupancy;mult. FT0C;N_{track} in time range", o2::framework::kTH2F, {{60, 0, 60000}, {2000, 0, 20000}}, false); fRegistry->addClone("Event/before/", "Event/after/"); } template -void fillEventInfo(HistogramRegistry* fRegistry, TCollision const& collision) +void fillEventInfo(o2::framework::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); + const float maxZ = 10.f; + static constexpr std::string_view kEventTypes[2] = {"before/", "after/"}; + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[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); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[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); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[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); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[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); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[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); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[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); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 7.0, weight); } if (collision.sel8()) { - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 8.0, weight); } - if (abs(collision.posZ()) < 10.0) { - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 9.0); + if (std::abs(collision.posZ()) < maxZ) { + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 9.0, weight); } - fRegistry->fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hZvtx"), collision.posZ()); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[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); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[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); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCollisionCounter"), 11.0, weight); } - 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("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(kEventTypes[ev_id]) + HIST("hMultNTracksPV"), collision.multNTracksPV(), weight); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hMultNTracksPVeta1"), collision.multNTracksPVeta1(), weight); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hMultFT0"), collision.multFT0A(), collision.multFT0C(), weight); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCentFT0A"), collision.centFT0A(), weight); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCentFT0C"), collision.centFT0C(), weight); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCentFT0M"), collision.centFT0M(), weight); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hCentFT0CvsMultNTracksPV"), collision.centFT0C(), collision.multNTracksPV(), weight); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hMultFT0CvsMultNTracksPV"), collision.multFT0C(), collision.multNTracksPV(), weight); + fRegistry->fill(HIST("Event/") + HIST(kEventTypes[ev_id]) + HIST("hMultFT0CvsOccupancy"), collision.multFT0C(), collision.trackOccupancyInTimeRange(), weight); } } // namespace o2::aod::pwgem::photonmeson::utils::eventhistogram diff --git a/PWGEM/PhotonMeson/Utils/HNMUtilities.h b/PWGEM/PhotonMeson/Utils/HNMUtilities.h new file mode 100644 index 00000000000..9a3c7494c07 --- /dev/null +++ b/PWGEM/PhotonMeson/Utils/HNMUtilities.h @@ -0,0 +1,207 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PairUtilities.h" + +#include +#include + +#include // IWYU pragma: keep +#include + +#include + +#include +#include +#include +#include + +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 = photonpair::kNpair; + 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; +inline float smPhiEdges[nSMEdges] = {1.75, 2.1, 2.45, 2.8, 3.14, 4., 4.89, 5.24, 5.58}; + +inline 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 Store photons from EMC clusters in a vector and possibly add a eta and phi offset for alignment of EMCal clusters +template +void storeGammasInVector(C clusters, 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())); + } +} + +/// \brief Reconstruct light neutral mesons from photons and fill them into the vGGs vector +inline 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 +inline 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 0d9fe36920c..8164d846c02 100644 --- a/PWGEM/PhotonMeson/Utils/MCUtilities.h +++ b/PWGEM/PhotonMeson/Utils/MCUtilities.h @@ -9,15 +9,19 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \commonly used for MC analysis. +/// \file MCUtilities.h +/// \brief commonly used for MC analysis. /// \author daiki.sekihata@cern.ch #ifndef PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ #define PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ -#include +#include + #include -#include "Framework/AnalysisTask.h" +#include +#include +#include //_______________________________________________________________________ namespace o2::aod::pwgem::photonmeson::utils::mcutil @@ -48,7 +52,7 @@ int IsFromWD(TCollision const&, T const& mctrack, TMCs const& mcTracks) if (motherid < mcTracks.size()) { // protect against bad mother indices. why is this needed? auto mp = mcTracks.iteratorAt(motherid); int pdg_mother = mp.pdgCode(); - if (abs(pdg_mother) == 310 || abs(pdg_mother) == 130 || abs(pdg_mother) == 3122) { + if (std::abs(pdg_mother) == kK0Short || std::abs(pdg_mother) == kK0Long || std::abs(pdg_mother) == kLambda0) { // LOGF(info, "mctrack.globalIndex() = %d, mp.globalIndex() = %d , pdg_mother = %d", mctrack.globalIndex(), mp.globalIndex(), pdg_mother); return motherid; } @@ -88,32 +92,36 @@ int IsXFromY(T const& mctrack, TMCs const& mcTracks, const int pdgX, const int p // Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return this mothers daughter // E.g. Find the gamma that was created in a pi0 or eta decay template -int FindMotherInChain(T const& mcparticle, TMCs const& mcparticles, TTargetPDGs const& motherpdgs, const int Depth = 50) +int FindMotherInChain(T const& mcparticle, TMCs const& mcparticles, TTargetPDGs const& motherpdgs, const int Depth = 50) // o2-linter: disable=pdg/explicit-code (false positive) { - if (!mcparticle.has_mothers() || Depth < 1) + if (!mcparticle.has_mothers() || Depth < 1) { return -1; + } int motherid = mcparticle.mothersIds()[0]; auto mother = mcparticles.iteratorAt(motherid); - if (std::find(motherpdgs.begin(), motherpdgs.end(), mother.pdgCode()) != motherpdgs.end()) + if (std::find(motherpdgs.begin(), motherpdgs.end(), mother.pdgCode()) != motherpdgs.end()) { return mcparticle.globalIndex(); // The mother has the required pdg code, so return its daughters global mc particle code. - else + } else { return FindMotherInChain(mother, mcparticles, motherpdgs, Depth - 1); + } } //_______________________________________________________________________ template int IsEleFromPC(T const& mctrack, TMCs const& mcTracks) { // is election from photon conversion? returns index of mother photon - if (abs(mctrack.pdgCode()) != 11) + if (std::abs(mctrack.pdgCode()) != kElectron) { return -1; - if (mctrack.producedByGenerator()) + } + if (mctrack.producedByGenerator()) { return -1; + } if (mctrack.has_mothers()) { int motherid = mctrack.mothersIds()[0]; // first mother auto mp = mcTracks.iteratorAt(motherid); int pdg_mother = mp.pdgCode(); - if (pdg_mother == 22) { + if (pdg_mother == kGamma) { return motherid; } } else { @@ -189,7 +197,7 @@ bool IsInAcceptance(TMCParticle const& mcparticle, TMCParticles const& mcparticl } std::vector pdgs; pdgs.reserve(target_pdgs.size()); - for (auto& daughterId : daughtersIds) { + for (const auto& daughterId : daughtersIds) { if (daughterId < 0) { pdgs.clear(); pdgs.shrink_to_fit(); @@ -224,21 +232,21 @@ 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()) != kGamma) { return false; } auto daughtersIds = mcphoton.daughtersIds(); - if (daughtersIds.size() != 2) { + if (daughtersIds.size() != 2) { // o2-linter: disable=magic-number (2 is not that magic in this context) return false; } - for (auto& daughterId : daughtersIds) { + for (const auto& daughterId : daughtersIds) { if (daughterId < 0) { return false; } auto daughter = mcparticles.iteratorAt(daughterId); - if (abs(daughter.pdgCode()) != 11) { + if (std::abs(daughter.pdgCode()) != kElectron) { return false; } @@ -246,9 +254,9 @@ 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) + std::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) { + if (rxy_gen_e > max_r_gen || rxy_gen_e < std::abs(daughter.vz()) * std::tan(2 * std::atan(std::exp(-max_eta_gen))) - margin_z_mc) { return false; } } // end of daughter loop @@ -256,6 +264,21 @@ bool IsConversionPointInAcceptance(TMCPhoton const& mcphoton, const float max_r_ return true; } //_______________________________________________________________________ +template +bool isGammaGammaDecay(TMCParticle mcParticle, TMCParticles mcParticles) +{ + auto daughtersIds = mcParticle.daughtersIds(); + if (daughtersIds.size() != 2) { // o2-linter: disable=magic-number (2 is not that magic in this context) + return false; + } + for (const auto& daughterId : daughtersIds) { + if (mcParticles.iteratorAt(daughterId).pdgCode() != kGamma) { + return false; + } + } + return true; +} +//_______________________________________________________________________ } // namespace o2::aod::pwgem::photonmeson::utils::mcutil //_______________________________________________________________________ //_______________________________________________________________________ diff --git a/PWGEM/PhotonMeson/Utils/NMHistograms.h b/PWGEM/PhotonMeson/Utils/NMHistograms.h index 0bd205d3bd8..b04b8a67878 100644 --- a/PWGEM/PhotonMeson/Utils/NMHistograms.h +++ b/PWGEM/PhotonMeson/Utils/NMHistograms.h @@ -9,50 +9,59 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \header file for histograms +/// \file NMHistograms.h +/// \brief utility for mass vs pT histograms mainly /// \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; +#include +#include + +#include +#include +#include +#include + +#include namespace o2::aod::pwgem::photonmeson::utils::nmhistogram { -void addNMHistograms(HistogramRegistry* fRegistry, bool isMC, const char* pairname = "#gamma#gamma") +inline void addNMHistograms(o2::framework::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++) { + for (int i = 0; i < 2; i++) { // o2-linter: disable=magic-number (just numbers for binning) 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++) { + for (int i = 2; i < 51; i++) { // o2-linter: disable=magic-number (just numbers for binning) 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++) { + for (int i = 51; i < 61; i++) { // o2-linter: disable=magic-number (just numbers for binning) 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++) { + for (int i = 61; i < 72; i++) { // o2-linter: disable=magic-number (just numbers for binning) 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)}; + const o2::framework::AxisSpec axis_pt{ptbins, Form("p_{T,%s} (GeV/c)", pairname)}; + const o2::framework::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/Eta/hs_Primary", "rec. true eta", kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Pi0/hs_Primary", "rec. true pi0", o2::framework::kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Pi0/hs_FromWD", "rec. true pi0 from weak decay", o2::framework::kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Pi0/hs_FromHS", "rec. true pi0 from hadronic shower in material", o2::framework::kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Pi0/hs_FromSameGamma", "Two clusters from same gamma that is a pi0 daughter (conversion)", o2::framework::kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Eta/hs_Primary", "rec. true eta", o2::framework::kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Eta/hs_FromWD", "rec. true eta from weak decay", o2::framework::kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Eta/hs_FromHS", "rec. true eta from hadronic shower in material", o2::framework::kTHnSparseD, {axis_mass, axis_pt}, true); + fRegistry->add("Pair/Eta/hs_FromSameGamma", "Two clusters from same gamma that is a eta daughter (conversion)", o2::framework::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); + const o2::framework::AxisSpec axis_rapidity{{0.0, +0.8, +0.9}, "rapidity |y|"}; + fRegistry->add("Generated/Pi0/hPt", "pT;p_{T} (GeV/c)", o2::framework::kTH1F, {axis_pt}, true); + fRegistry->add("Generated/Pi0/hPtY", "Generated info", o2::framework::kTH2F, {axis_pt, axis_rapidity}, true); fRegistry->addClone("Generated/Pi0/", "Generated/Eta/"); fRegistry->get(HIST("Generated/Pi0/hPt"))->SetXTitle("p_{T} (GeV/c)"); @@ -62,36 +71,39 @@ void addNMHistograms(HistogramRegistry* fRegistry, bool isMC, const char* pairna 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->add("Pair/same/hs", "diphoton", o2::framework::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) +void fillTruePairInfo(o2::framework::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 = abs(mcparticle.pdgCode()); + int pdg = std::abs(mcparticle.pdgCode()); + float weight = eventWeight; + int motherid_strhad = o2::aod::pwgem::photonmeson::utils::mcutil::IsFromWD(mcparticle.template emmcevent_as(), mcparticle, mcparticles); switch (pdg) { - case 111: { - int motherid_strhad = IsFromWD(mcparticle.template emmcevent_as(), mcparticle, mcparticles); + case kPi0: { if (mcparticle.isPhysicalPrimary() || mcparticle.producedByGenerator()) { - fRegistry->fill(HIST("Pair/Pi0/hs_Primary"), v12.M(), v12.Pt()); + fRegistry->fill(HIST("Pair/Pi0/hs_Primary"), v12.M(), v12.Pt(), weight); } else if (motherid_strhad > 0) { - float weight = 1.f; auto str_had = mcparticles.iteratorAt(motherid_strhad); - if (abs(str_had.pdgCode()) == 310 && f1fd_k0s_to_pi0 != nullptr) { - weight = f1fd_k0s_to_pi0->Eval(str_had.pt()); + if (std::abs(str_had.pdgCode()) == kK0Short && 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 { - float weight = 1.f; 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()); + 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; } diff --git a/PWGEM/PhotonMeson/Utils/PCMUtilities.h b/PWGEM/PhotonMeson/Utils/PCMUtilities.h index 38492dae9e6..269db4f46fb 100644 --- a/PWGEM/PhotonMeson/Utils/PCMUtilities.h +++ b/PWGEM/PhotonMeson/Utils/PCMUtilities.h @@ -9,22 +9,32 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \commonly used for PCM analyses. +/// \file PCMUtilities.h +/// \brief helper functions commonly used for PCM analyses. /// \author daiki.sekihata@cern.ch #ifndef PWGEM_PHOTONMESON_UTILS_PCMUTILITIES_H_ #define PWGEM_PHOTONMESON_UTILS_PCMUTILITIES_H_ -#include -#include "DCAFitter/HelixHelper.h" -#include "DetectorsBase/Propagator.h" -#include "Common/Core/trackUtilities.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include //_______________________________________________________________________ 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 { @@ -47,18 +57,11 @@ inline float v0_qt(float pxpos, float pypos, float pzpos, float pxneg, float pyn return std::sqrt(RecoDecay::p2(pxneg, pyneg, pzneg) - dp * dp / momTot); // qt of v0 } //_______________________________________________________________________ -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) +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 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) @@ -66,15 +69,13 @@ inline void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrac 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 = 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 alphaPos = o2::constants::math::PI + std::atan2(-(xyz[1] - helixPos.yC), -(xyz[0] - helixPos.xC)); + float alphaNeg = o2::constants::math::PI + std::atan2(-(xyz[1] - helixNeg.yC), -(xyz[0] - helixNeg.xC)); float vertexXPos = helixPos.xC + helixPos.rC * std::cos(alphaPos); float vertexYPos = helixPos.yC + helixPos.rC * std::sin(alphaPos); @@ -104,5 +105,89 @@ inline void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrac xyz[2] = (trackPosInformationCopy.getZ() * helixNeg.rC + trackNegInformationCopy.getZ() * helixPos.rC) / (helixPos.rC + helixNeg.rC); } //_______________________________________________________________________ +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) +{ + // 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) + + Vtx_recalculationParCov(prop, trackPosInformation, trackNegInformation, xyz, matCorr); +} +//_______________________________________________________________________ +// template +// float getPtResolution(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 * 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); +// } +// //_______________________________________________________________________ +// template +// float getThetaResolution(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(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 2277caea505..02b6b548dca 100644 --- a/PWGEM/PhotonMeson/Utils/PairUtilities.h +++ b/PWGEM/PhotonMeson/Utils/PairUtilities.h @@ -15,9 +15,23 @@ #ifndef PWGEM_PHOTONMESON_UTILS_PAIRUTILITIES_H_ #define PWGEM_PHOTONMESON_UTILS_PAIRUTILITIES_H_ -#include +#include "Common/Core/RecoDecay.h" + +#include + #include +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 { @@ -47,10 +61,10 @@ template bool DoesV0LegMatchWithCluster(TV0Leg const& v0leg, TCluster const& cluster, const float max_deta, const float max_dphi, const float max_Ep_width) { float deta = v0leg.eta() - cluster.eta(); - float dphi = TVector2::Phi_mpi_pi(TVector2::Phi_0_2pi(v0leg.phi()) - TVector2::Phi_0_2pi(cluster.phi())); + float dphi = RecoDecay::constrainAngle(RecoDecay::constrainAngle(v0leg.phi()) - RecoDecay::constrainAngle(cluster.phi()), -o2::constants::math::PI); // float dR = sqrt(deta * deta + dphi * dphi); float Ep = cluster.e() / v0leg.p(); - return (pow(deta / max_deta, 2) + pow(dphi / max_dphi, 2) < 1) && (abs(Ep - 1) < max_Ep_width); + return (std::pow(deta / max_deta, 2.f) + std::pow(dphi / max_dphi, 2.f) < 1.f) && (std::abs(Ep - 1.f) < max_Ep_width); } } // namespace o2::aod::pwgem::photonmeson::photonpair diff --git a/PWGEM/PhotonMeson/Utils/TrackSelection.h b/PWGEM/PhotonMeson/Utils/TrackSelection.h index d7c4df97d2c..81803c9cee7 100644 --- a/PWGEM/PhotonMeson/Utils/TrackSelection.h +++ b/PWGEM/PhotonMeson/Utils/TrackSelection.h @@ -9,13 +9,16 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file TrackSelection.h /// \brief helper functions for pair track selection /// \author felix.schlepper@cern.ch #ifndef PWGEM_PHOTONMESON_UTILS_TRACKSELECTION_H_ #define PWGEM_PHOTONMESON_UTILS_TRACKSELECTION_H_ -#include "TPDGCode.h" +#include + +#include namespace o2::pwgem::photonmeson { @@ -43,7 +46,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 +59,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 +218,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/PhotonMeson/Utils/emcalHistoDefinitions.h b/PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h index 6ce678e9c35..0fc655d8858 100644 --- a/PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h +++ b/PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h @@ -9,42 +9,43 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \brief commonly used histogram (axis) definitions for emcal in PWGEM +/// \file emcalHistoDefinitions.h +/// \brief commonly used histograms and axes definitions for emcal in PWGEM /// \author marvin.hemmer@cern.ch -#include +#include -#include "Framework/AnalysisTask.h" +#include #ifndef PWGEM_PHOTONMESON_UTILS_EMCALHISTODEFINITIONS_H_ #define PWGEM_PHOTONMESON_UTILS_EMCALHISTODEFINITIONS_H_ -using namespace o2::framework; - -AxisSpec const gAxis_dEta{100, -0.2f, 0.2f, "#Delta#it{#eta}"}; -AxisSpec const gAxis_dPhi{100, -0.2f, 0.2f, "#Delta#it{#varphi} (rad)"}; -AxisSpec const gAxis_dR{100, 0.0f, 0.2f, "#Delta#it{R}"}; -AxisSpec const gAxis_MatchedTrack{10, 0.5f, 10.5f, "matched track"}; -AxisSpec const gAxis_Eta{160, -0.8f, 0.8f, "#it{#eta}"}; -AxisSpec const gAxis_Phi{144, 0.f, 2 * 3.14159, "#it{#varphi} (rad)"}; - -std::vector EClusBins = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, - 1, 1.2, 1.4, 1.6, 1.8, 2, 2.2, 2.4, 2.6, 2.8, - 3, 3.2, 3.4, 3.6, 3.8, 4, 4.2, 4.4, 4.6, 4.8, - 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 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, 55, 60, 65, 70, 75, 80, 85, 90, 95, - 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200}; -AxisSpec gAxis_EClus = {EClusBins, "#it{E}_{clus} (GeV)"}; - -HistogramConfigSpec gHistoSpec_clusterTM_dEtadPhi({HistType::kTH2F, {gAxis_dEta, gAxis_dPhi}}); -HistogramConfigSpec gHistoSpec_clusterTM_dEtaMT({HistType::kTH2F, {gAxis_dEta, {10, 0.5, 10.5}}}); -HistogramConfigSpec gHistoSpec_clusterTM_dPhiMT({HistType::kTH2F, {gAxis_dPhi, {10, 0.5, 10.5}}}); -HistogramConfigSpec gHistoSpec_clusterTM_dRMT({HistType::kTH2F, {gAxis_dR, {10, 0.5, 10.5}}}); -HistogramConfigSpec gHistoSpec_EtaPhi({HistType::kTH2F, {gAxis_Eta, gAxis_Phi}}); -HistogramConfigSpec gHistoSpec_clusterE({HistType::kTH1F, {gAxis_EClus}}); -HistogramConfigSpec gHistoSpec_clusterECuts({HistType::kTH2F, {gAxis_EClus, {64, -0.5, 63.5}}}); +o2::framework::AxisSpec const gAxisdEta{200, -0.1f, 0.1f, "#Delta#it{#eta}"}; +o2::framework::AxisSpec const gAxisdPhi{200, -0.1f, 0.1f, "#Delta#it{#varphi} (rad)"}; +o2::framework::AxisSpec const gAxisdR{100, 0.0f, 0.2f, "#Delta#it{R}"}; +o2::framework::AxisSpec const gAxisMatchedTrack{10, 0.5f, 10.5f, "matched track"}; +o2::framework::AxisSpec const gAxisEta{160, -0.8f, 0.8f, "#it{#eta}"}; +o2::framework::AxisSpec const gAxisPhi{144, 0.f, 2 * 3.14159, "#it{#varphi} (rad)"}; +o2::framework::AxisSpec const gAxisEoverP{250, 0.f, 2.5f, "#it{E}_{clus.}/#it{p}_{track} (#it{c})"}; + +const std::vector eClusBins = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, + 1, 1.2, 1.4, 1.6, 1.8, 2, 2.2, 2.4, 2.6, 2.8, + 3, 3.2, 3.4, 3.6, 3.8, 4, 4.2, 4.4, 4.6, 4.8, + 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 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, 55, 60, 65, 70, 75, 80, 85, 90, 95, + 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200}; +o2::framework::AxisSpec const gAxisEClus = {eClusBins, "#it{E}_{clus} (GeV)"}; + +o2::framework::HistogramConfigSpec const gHistoSpecClusterTMdEtadPhi({o2::framework::HistType::kTH2F, {gAxisdEta, gAxisdPhi}}); +o2::framework::HistogramConfigSpec const gHistoSpecClusterTMdEtaMT({o2::framework::HistType::kTH2F, {gAxisdEta, {10, 0.5, 10.5}}}); +o2::framework::HistogramConfigSpec const gHistoSpecClusterTMdPhiMT({o2::framework::HistType::kTH2F, {gAxisdPhi, {10, 0.5, 10.5}}}); +o2::framework::HistogramConfigSpec const gHistoSpecClusterTMdRMT({o2::framework::HistType::kTH2F, {gAxisdR, {10, 0.5, 10.5}}}); +o2::framework::HistogramConfigSpec const gHistoSpecEtaPhi({o2::framework::HistType::kTH2F, {gAxisEta, gAxisPhi}}); +o2::framework::HistogramConfigSpec const gHistoSpecClusterE({o2::framework::HistType::kTH1F, {gAxisEClus}}); +o2::framework::HistogramConfigSpec const gHistoSpecClusterECuts({o2::framework::HistType::kTH2F, {gAxisEClus, {64, -0.5, 63.5}}}); +o2::framework::HistogramConfigSpec const gHistoSpecTMEoverP({o2::framework::HistType::kTH2D, {gAxisEClus, gAxisEoverP}}); #endif // PWGEM_PHOTONMESON_UTILS_EMCALHISTODEFINITIONS_H_ diff --git a/PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h b/PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h index a9257d90ee4..2eb11525278 100644 --- a/PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h +++ b/PWGEM/PhotonMeson/Utils/gammaConvDefinitions.h @@ -9,13 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file gammaConvDefinitions.h /// \brief commonly used definitions for gammaConv tasks /// \author stephan.friedrich.stiefelmaier@cern.ch #ifndef PWGEM_PHOTONMESON_UTILS_GAMMACONVDEFINITIONS_H_ #define PWGEM_PHOTONMESON_UTILS_GAMMACONVDEFINITIONS_H_ -#include "Framework/AnalysisTask.h" +#include +#include using namespace o2::framework; diff --git a/PWGEM/PhotonMeson/Utils/gammaSelectionCuts.h b/PWGEM/PhotonMeson/Utils/gammaSelectionCuts.h deleted file mode 100644 index 341a6c95e38..00000000000 --- a/PWGEM/PhotonMeson/Utils/gammaSelectionCuts.h +++ /dev/null @@ -1,165 +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 cut selection and cut functions for photon candidates -/// \author marvin.hemmer@cern.ch - -#include - -#include "Framework/AnalysisTask.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" - -#ifndef PWGEM_PHOTONMESON_UTILS_GAMMASELECTIONCUTS_H_ -#define PWGEM_PHOTONMESON_UTILS_GAMMASELECTIONCUTS_H_ - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -namespace emccuts -{ -// set the standard cuts -std::vector EMC_minTime = {-20.f}; -std::vector EMC_maxTime = {+25.f}; -std::vector EMC_minM02 = {0.1f}; -std::vector EMC_maxM02 = {0.7f}; -std::vector EMC_minE = {0.7f}; -std::vector EMC_minNCell = {1}; -std::vector> EMC_TM_Eta = {{0.01f, 4.07f, -2.5f}}; -std::vector> EMC_TM_Phi = {{0.015f, 3.65f, -2.f}}; -std::vector EMC_Eoverp = {1.75f}; -} // namespace emccuts -void gatherCutsEMC(float minTime, float maxTime, float minM02, float maxM02, float minE, int minNCell, std::vector TM_Eta, std::vector TM_Phi, float Eoverp) -{ - // insert the configurable values in first position - emccuts::EMC_minTime.insert(emccuts::EMC_minTime.begin(), minTime); - emccuts::EMC_maxTime.insert(emccuts::EMC_maxTime.begin(), maxTime); - emccuts::EMC_minM02.insert(emccuts::EMC_minM02.begin(), minM02); - emccuts::EMC_maxM02.insert(emccuts::EMC_maxM02.begin(), maxM02); - emccuts::EMC_minE.insert(emccuts::EMC_minE.begin(), minE); - emccuts::EMC_minNCell.insert(emccuts::EMC_minNCell.begin(), minNCell); - emccuts::EMC_TM_Eta.insert(emccuts::EMC_TM_Eta.begin(), TM_Eta); - emccuts::EMC_TM_Phi.insert(emccuts::EMC_TM_Phi.begin(), TM_Phi); - emccuts::EMC_Eoverp.insert(emccuts::EMC_Eoverp.begin(), Eoverp); - - // fill up the rest of the vectors to size 64 to ensure no crashes can happen - emccuts::EMC_minTime.resize(64, 0); - emccuts::EMC_maxTime.resize(64, 0); - emccuts::EMC_minM02.resize(64, 0); - emccuts::EMC_maxM02.resize(64, 0); - emccuts::EMC_minE.resize(64, 0); - emccuts::EMC_minNCell.resize(64, 0); - emccuts::EMC_TM_Eta.resize(64, {0, 0, 0}); - emccuts::EMC_TM_Phi.resize(64, {0, 0, 0}); - emccuts::EMC_Eoverp.resize(64, 0); -} - -uint64_t doTimeCutEMC(int iCut, uint64_t cutbit, aod::SkimEMCCluster const& cluster, HistogramRegistry& registry) -{ - uint64_t cut_return = 0; - if (cutbit & ((uint64_t)1 << (uint64_t)iCut)) { // check if current cut should be applied - if (cluster.time() <= emccuts::EMC_maxTime.at(iCut) && cluster.time() >= emccuts::EMC_minTime.at(iCut)) { // check cut itself - cut_return |= (1 << iCut); // set bit of current cut to 1 for passing the cut - } else { - registry.fill(HIST("hCaloCuts_EMC"), 1, iCut); - } - } - return cut_return; -} - -uint64_t doM02CutEMC(int iCut, uint64_t cutbit, aod::SkimEMCCluster const& cluster, HistogramRegistry& registry) -{ - uint64_t cut_return = 0; - if (cutbit & ((uint64_t)1 << (uint64_t)iCut)) { // check if current cut should be applied - if (cluster.m02() <= emccuts::EMC_maxM02.at(iCut) && cluster.m02() >= emccuts::EMC_minM02.at(iCut)) { // check cut itself - cut_return |= (1 << iCut); // set bit of current cut to 1 for passing the cut - } else { - registry.fill(HIST("hCaloCuts_EMC"), 2, iCut); - } - } - return cut_return; -} - -uint64_t doMinECutEMC(int iCut, uint64_t cutbit, aod::SkimEMCCluster const& cluster, HistogramRegistry& registry) -{ - uint64_t cut_return = 0; - if (cutbit & ((uint64_t)1 << (uint64_t)iCut)) { // check if current cut should be applied - if (cluster.e() > emccuts::EMC_minE.at(iCut)) { // check cut itself - cut_return |= (1 << iCut); // set bit of current cut to 1 for passing the cut - } else { - registry.fill(HIST("hCaloCuts_EMC"), 3, iCut); - } - } - return cut_return; -} - -uint64_t doNCellCutEMC(int iCut, uint64_t cutbit, aod::SkimEMCCluster const& cluster, HistogramRegistry& registry) -{ - uint64_t cut_return = 0; - if (cutbit & ((uint64_t)1 << (uint64_t)iCut)) { // check if current cut should be applied - if (cluster.nCells() >= emccuts::EMC_minNCell.at(iCut)) { // check cut itself - cut_return |= (1 << iCut); // set bit of current cut to 1 for passing the cut - } else { - registry.fill(HIST("hCaloCuts_EMC"), 4, iCut); - } - } - return cut_return; -} - -uint64_t doTrackMatchingEMC(int iCut, uint64_t cutbit, aod::SkimEMCCluster const& cluster, aod::SkimEMCMTs const& tracks, HistogramRegistry& registry) -{ - uint64_t cut_return = 0; - double dEta, dPhi; - if (cutbit & ((uint64_t)1 << (uint64_t)iCut)) { // check if current cut should be applied - bool hasMatchedTrack_EMC = false; - for (const auto& track : tracks) { - dEta = track.tracketa() - cluster.eta(); - dPhi = track.trackphi() - cluster.phi(); - if ((fabs(dEta) <= emccuts::EMC_TM_Eta.at(iCut).at(0) + pow(track.trackpt() + emccuts::EMC_TM_Eta.at(iCut).at(1), emccuts::EMC_TM_Eta.at(iCut).at(2))) && - (fabs(dPhi) <= emccuts::EMC_TM_Phi.at(iCut).at(0) + pow(track.trackpt() + emccuts::EMC_TM_Phi.at(iCut).at(1), emccuts::EMC_TM_Phi.at(iCut).at(2))) && - cluster.e() / track.trackp() < emccuts::EMC_Eoverp.at(iCut)) { // check cut itself - hasMatchedTrack_EMC = true; // set bit of current cut to 1 for passing the cut - } - } - if (hasMatchedTrack_EMC) { - registry.fill(HIST("hCaloCuts_EMC"), 5, iCut); - } else { - cut_return |= (1 << iCut); - } - } - return cut_return; -} - -uint64_t doPhotonCutsEMC(uint64_t cutbit, aod::SkimEMCCluster const& cluster, aod::SkimEMCMTs const& tracks, Preslice perEMCClusterMT, HistogramRegistry& registry) -{ - uint64_t cut_return = 0; - auto tracksMatchedEMC = tracks.sliceBy(perEMCClusterMT, cluster.globalIndex()); - for (int iCut = 0; iCut < 64; iCut++) { // loop over max number of cut settings - if (cutbit & ((uint64_t)1 << (uint64_t)iCut)) { // check each cut setting if it is selected - registry.fill(HIST("hClusterEIn"), cluster.e(), iCut); - cut_return = doTimeCutEMC(iCut, cutbit, cluster, registry); - // use cut_return instead of cutbit from here on to only check cut settings that we want to look at - // where the cluster did not fail in the previous cut(s) - cut_return = doM02CutEMC(iCut, cut_return, cluster, registry); - cut_return = doMinECutEMC(iCut, cut_return, cluster, registry); - cut_return = doNCellCutEMC(iCut, cut_return, cluster, registry); - cut_return = doTrackMatchingEMC(iCut, cut_return, cluster, tracksMatchedEMC, registry); - - registry.fill(HIST("hCaloCuts_EMC"), 0, iCut); - if (cut_return & ((uint64_t)1 << (uint64_t)iCut)) { - registry.fill(HIST("hClusterEOut"), cluster.e(), iCut); - registry.fill(HIST("hCaloCuts_EMC"), 6, iCut); - } - } - } - return cut_return; -} - -#endif // PWGEM_PHOTONMESON_UTILS_GAMMASELECTIONCUTS_H_ 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 d63d77b84e5..5e5856518af 100644 --- a/PWGEM/Tasks/phosAlign.cxx +++ b/PWGEM/Tasks/phosAlign.cxx @@ -9,35 +9,35 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include -#include -#include -#include -#include "Common/Core/trackUtilities.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/CaloClusters.h" -#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "ReconstructionDataFormats/TrackParametrization.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/Propagator.h" #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ConfigParamSpec.h" #include "Framework/HistogramRegistry.h" - +#include "Framework/runDataProcessing.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" +#include "ReconstructionDataFormats/TrackParametrization.h" + +#include +#include +#include +#include +#include /// \struct PHOS pi0 analysis /// \brief Monitoring task for PHOS related quantities 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 3899075fe04..062bbb6271b 100644 --- a/PWGEM/Tasks/phosElId.cxx +++ b/PWGEM/Tasks/phosElId.cxx @@ -9,238 +9,334 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include -#include -#include -#include -#include "Common/Core/trackUtilities.h" +/// \file phosElId.cxx +/// \struct PHOS electron id analysis +/// \brief Task for calculating electron identification parameters +/// +/// \author Yeghishe Hambardzumyan, MIPT +/// \since Apr, 2024 + #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/CaloClusters.h" -#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "ReconstructionDataFormats/TrackParametrization.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/Propagator.h" #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ConfigParamSpec.h" #include "Framework/HistogramRegistry.h" - +#include "Framework/runDataProcessing.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" +#include "ReconstructionDataFormats/TrackParametrization.h" #include "TF1.h" +#include "TPDGCode.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 +#include +#include +#include +#include +#include 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 - using SelCollisions = soa::Join; - using tracks = soa::Join; +DECLARE_SOA_TABLE(PHOSMatchindexTable, "AOD", "PHSMTCH", //! + o2::soa::Index<>, phos_match::CollisionId, phos_match::CaloClusterId, phos_match::TrackId); //! + +} // namespace o2::aod - Configurable mMinCluE{"mMinCluE", 0.3, "Minimum cluster energy for analysis"}; - Configurable mMinCluTime{"minCluTime", -25.e-9, "Min. cluster time"}; - Configurable mMaxCluTime{"mMaxCluTime", 25.e-9, "Max. cluster time"}; - Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}; - Configurable mMinCluNcell{"minCluNcell", 3, "min cells in cluster"}; +// globalized estimator names for centrality +enum CentEstimators { FV0A, + FT0M, + FT0A, + FT0C, + FDDM, + NTPV }; - Configurable nBinsDeltaX{"nBinsDeltaX", 500, "N bins for track and cluster coordinate delta"}; - Configurable mDeltaXmin{"mDeltaXmin", -100., "Min for track and cluster coordinate delta"}; - Configurable mDeltaXmax{"mDeltaXmax", 100., "Max for track and cluster coordinate delta"}; +bool testLambda(float pt, float l1, float l2, float cutThreshold, bool useNegativeCrossTerm) +{ + float l2Mean = 1.53126f + 9.50835e+06f / (1.f + 1.08728e+07f * pt + 1.73420e+06f * pt * pt); + float l1Mean = 1.12365f + 0.123770f * std::exp(-pt * 0.246551f) + 5.30000e-03f * pt; + float l2Sigma = 6.48260e-02f + 7.60261e+10f / (1.f + 1.53012e+11f * pt + 5.01265e+05f * pt * pt) + 9.00000e-03f * pt; + float l1Sigma = 4.44719e-04f + 6.99839e-01f / (1.f + 1.22497e+00f * pt + 6.78604e-07f * pt * pt) + 9.00000e-03f * pt; + float c = -0.35f - 0.550f * std::exp(-0.390730f * pt); + if (l1Sigma == 0.f || l2Sigma == 0.f) + return false; + + float term1 = 0.5f * (l1 - l1Mean) * (l1 - l1Mean) / (l1Sigma * l1Sigma); + float term2 = 0.5f * (l2 - l2Mean) * (l2 - l2Mean) / (l2Sigma * l2Sigma); + float crossTerm = 0.5f * c * (l1 - l1Mean) * (l2 - l2Mean) / (l1Sigma * l2Sigma); + + float rSquared; + if (useNegativeCrossTerm) { + rSquared = term1 + term2 - crossTerm; + } else { + rSquared = term1 + term2 + crossTerm; + } - Configurable nBinsDeltaZ{"nBinsDeltaZ", 500, "N bins for track and cluster coordinate delta"}; - Configurable mDeltaZmin{"mDeltaZmin", -100., "Min for track and cluster coordinate delta"}; - Configurable mDeltaZmax{"mDeltaZmax", 100., "Max for track and cluster coordinate delta"}; + return rSquared < cutThreshold; +} + +struct PhosElId { - 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"}; + Produces phosMatch; + + using SelCollisions = soa::Join; + using MyTracks = soa::Join; + Configurable isMC{"isMC", true, "Enable MC analysis"}, + isSel8{"isSel8", 1, "check if event is Single Event Latch-up 8"}, + mSwapM20M02ForTestLambda{"mSwapM20M02ForTestLambda", false, "Swap m20 and m02 arguments for testLambda (false for note's correct order, true for swapped/original incorrect order)"}, + mUseNegativeCrossTerm{"mUseNegativeCrossTerm", true, "Use negative sign for the cross-term in testLambda (true for analysis note version, false for old version)"}, + mFillSingleLoopHistos{"mFillSingleLoopHistos", false, "Fill single loop histograms"}; - Configurable> pSigma_dz{"pSigma_dz", {20., 0.76, 6.6, 3.6, 0.1}, "parameters for sigma dz function"}; - Configurable> pSigma_dx{"pSigma_dx", {3, 2.3, 3.1}, "parameters for sigma dx function"}; + Configurable mColMaxZ{"mColMaxZ", 10.f, "maximum z accepted in analysis"}, + 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"}, + EtaMax{"EtaMax", {0.8f}, "eta ranges"}, + PtMin{"PtMin", {0.2f}, "pt min"}, + PtMax{"PtMax", {20.f}, "pt max"}, + DCAxyMax{"DCAxyMax", {3.f}, "dcaxy max"}, + DCAzMax{"DCAzMax", {3.f}, "dcaz max"}, + ITSchi2Max{"ITSchi2Max", {5.f}, "its chi2 max"}, + ITSnclsMin{"ITSnclsMin", {4.5f}, "min number of ITS clusters"}, + ITSnclsMax{"ITSnclsMax", {7.5f}, "max number of ITS clusters"}, + TPCchi2Max{"TPCchi2Max", {4.f}, "tpc chi2 max"}, + TPCnclsMin{"TPCnclsMin", {90.f}, "min number of TPC clusters"}, + TPCnclsMax{"TPCnclsMax", {170.f}, "max number of TPC clusters"}, + TPCnclsCRMin{"TPCnclsCRMin", {80.f}, "min number of TPC crossed rows"}, + TPCnclsCRMax{"TPCnclsCRMax", {161.f}, "max number of TPC crossed rows"}, + TPCNSigmaElMin{"TPCNSigmaElMin", {-3.f}, "min TPC nsigma e for inclusion"}, + TPCNSigmaElMax{"TPCNSigmaElMax", {2.f}, "max TPC nsigma e for inclusion"}, + TPCNSigmaPiMin{"TPCNSigmaPiMin", {-3.f}, "min TPC nsigma pion for exclusion"}, + TPCNSigmaPiMax{"TPCNSigmaPiMax", {3.5f}, "max TPC nsigma pion for exclusion"}, + TPCNSigmaPrMin{"TPCNSigmaPrMin", {-3.f}, "min TPC nsigma proton for exclusion"}, + TPCNSigmaPrMax{"TPCNSigmaPrMax", {4.f}, "max TPC nsigma proton for exclusion"}, + TPCNSigmaKaMin{"TPCNSigmaKaMin", {-3.f}, "min TPC nsigma kaon for exclusion"}, + TPCNSigmaKaMax{"TPCNSigmaKaMax", {4.f}, "max TPC nsigma kaon for exclusion"}, + TOFNSigmaElMin{"TOFNSigmaElMin", {-3.f}, "min TOF nsigma e for inclusion"}, + TOFNSigmaElMax{"TOFNSigmaElMax", {3.f}, "max TOF nsigma e for inclusion"}, + NsigmaTrackMatch{"NsigmaTrackMatch", {2.f}, "PHOS Track Matching Nsigma for inclusion"}, + mShowerShapeCutValue{"mShowerShapeCutValue", 4.f, "Cut threshold for testLambda shower shape"}; - Configurable> pPhosShiftZ{"pPhosShiftZ", {4.5, 3., 2., 2.}, "Phos coordinate centering Z per module"}; - Configurable> pPhosShiftX{"pPhosShiftX", {1.99, -0.63, -1.55, -1.63}, "Phos coordinate centering X per module"}; + Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}, + mAmountOfModules{"mAmountOfModules", 4, "amount of modules for PHOS"}, + 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> pMean_dx_pos_mod1{"pMean_dx_pos_mod1", {-9.57, -0.47, 1.04}, "parameters for mean dx function on module 1 for positive tracks"}; - Configurable> pMean_dx_pos_mod2{"pMean_dx_pos_mod2", {-12.24, -0.18, 1.59}, "parameters for mean dx function on module 2 for positive tracks"}; - Configurable> pMean_dx_pos_mod3{"pMean_dx_pos_mod3", {-5.73, -0.58, 1.13}, "parameters for mean dx function on module 3 for positive tracks"}; - Configurable> pMean_dx_pos_mod4{"pMean_dx_pos_mod4", {-5.14, -0.67, 1.05}, "parameters for mean dx function on module 4 for positive tracks"}; + 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"}, + pMeandXPosMod{"pMeandXPosMod", {-10.57, -0.42, 1.06, -8.1, -0.42, 1.14, -8.34, -0.42, 1.04, -7.38, -0.42, 1.17}, "parameters for mean dx function for positive tracks"}, + pMeandXNegMod{"pMeandXNegMod", {9.92, -0.42, 1.29, 7.82, -0.4, 1.34, 8.45, -0.33, 1.5, 7.5, -0.42, 1.25}, "parameters for mean dx function for negative tracks"}; - Configurable> pMean_dx_neg_mod1{"pMean_dx_neg_mod1", {10.29, -0.42, 1.12}, "parameters for mean dx function on module 1 for negative tracks"}; - Configurable> pMean_dx_neg_mod2{"pMean_dx_neg_mod2", {8.24, -0.42, 1.31}, "parameters for mean dx function on module 2 for negative tracks"}; - Configurable> pMean_dx_neg_mod3{"pMean_dx_neg_mod3", {11.83, -0.17, 1.71}, "parameters for mean dx function on module 3 for negative tracks"}; - Configurable> pMean_dx_neg_mod4{"pMean_dx_neg_mod4", {84.96, 0.79, 2.83}, "parameters for mean dx function on module 4 for negative tracks"}; + Filter ptFilter = (aod::track::pt > PtMin) && (aod::track::pt < PtMax), + etafilter = nabs(aod::track::eta) < EtaMax, + dcaxyfilter = nabs(aod::track::dcaXY) < DCAxyMax, + dcazfilter = nabs(aod::track::dcaZ) < DCAzMax, + itschi2filter = aod::track::itsChi2NCl < ITSchi2Max, + tpcchi2filter = aod::track::tpcChi2NCl < TPCchi2Max, + 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* fMean_dx_pos_mod1; - TF1* fMean_dx_neg_mod1; - TF1* fMean_dx_pos_mod2; - TF1* fMean_dx_neg_mod2; - TF1* fMean_dx_pos_mod3; - TF1* fMean_dx_neg_mod3; - TF1* fMean_dx_pos_mod4; - TF1* fMean_dx_neg_mod4; + std::array fMeandXPosMod, fMeandXNegMod; 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.}; - std::vector parameters_sigma_dz = pSigma_dz; - std::vector parameters_sigma_dx = pSigma_dx; - std::vector vPhosShiftX = pPhosShiftX; - std::vector vPhosShiftZ = pPhosShiftZ; - std::vector Mean_dx_pos_mod1 = pMean_dx_pos_mod1; - std::vector Mean_dx_pos_mod2 = pMean_dx_pos_mod2; - std::vector Mean_dx_pos_mod3 = pMean_dx_pos_mod3; - std::vector Mean_dx_pos_mod4 = pMean_dx_pos_mod4; - std::vector Mean_dx_neg_mod1 = pMean_dx_neg_mod1; - std::vector Mean_dx_neg_mod2 = pMean_dx_neg_mod2; - std::vector Mean_dx_neg_mod3 = pMean_dx_neg_mod3; - std::vector Mean_dx_neg_mod4 = pMean_dx_neg_mod4; - - 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{momentum_binning, "p (GeV/c)"}, - axisPt{momentum_binning, "p_{T} (GeV/c)"}, + 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{3, 0, +3, ""}, + 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{100, 2e9 * mMinCluTime, 2e9 * mMaxCluTime, "time (ns)", "time (nanoseconds)"}, + 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)"}, 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)"}, // make 3 different histo + 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)"}, // make 3 different histo + 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("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("hCluE_v_p", "Cluster energy vs p", HistType::kTH3F, {axisE, axisP, axisModes}); - mHistManager.add("hCluE_v_p_disp", "Cluster energy vs p | OK dispersion", HistType::kTH3F, {axisE, axisP, axisModes}); - mHistManager.add("hCluE_v_p_1sigma", "Cluster energy vs p within trackmatch 1sigma", HistType::kTH3F, {axisE, axisP, axisModes}); - mHistManager.add("hCluE_v_p_1sigma_disp", "Cluster energy vs p within trackmatch 1sigma | OK dispersion", HistType::kTH3F, {axisE, axisP, axisModes}); - mHistManager.add("hCluE_v_p_2sigma", "Cluster energy vs p within trackmatch 2sigma", HistType::kTH3F, {axisE, axisP, axisModes}); - mHistManager.add("hCluE_v_p_2sigma_disp", "Cluster energy vs p within trackmatch 2sigma | OK dispersion", HistType::kTH3F, {axisE, axisP, axisModes}); - - mHistManager.add("hEp_v_p_disp", "E/p ratio vs p | OK dispersion", HistType::kTH3F, {axisEp, axisP, axisModes}); - mHistManager.add("hEp_v_p_1sigma", "E/p ratio vs p within trackmatch 1sigma", HistType::kTH3F, {axisEp, axisP, axisModes}); - mHistManager.add("hEp_v_p_1sigma_disp", "E/p ratio vs p within trackmatch 1sigma | OK dispersion", HistType::kTH3F, {axisEp, axisP, axisModes}); - mHistManager.add("hEp_v_p_2sigma", "E/p ratio vs p within trackmatch 2sigma", HistType::kTH3F, {axisEp, axisP, axisModes}); - mHistManager.add("hEp_v_p_2sigma_disp", "E/p ratio vs p within trackmatch 2sigma | OK dispersion", HistType::kTH3F, {axisEp, axisP, axisModes}); - - mHistManager.add("hdZpmod", "dz,p_{tr},module", HistType::kTH3F, {axisdZ, axisP, axisModes}); - mHistManager.add("hdZpmod_pos", "dz,p_{tr},module positive tracks", HistType::kTH3F, {axisdZ, axisP, axisModes}); - mHistManager.add("hdZpmod_neg", "dz,p_{tr},module negative tracks", 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("tracks/hTrackPtEtaPhi", "Track pt vs eta vs phi", HistType::kTH3F, {axisPt, axisEta, axisPhi}); + mHistManager.add("tracks/hTrackPtEtaPhi_Phos", "Track pt vs eta vs phi on Phos surface", HistType::kTH3F, {axisPt, axisEta, axisPhi}); + mHistManager.add("tracks/hTrackDCA", "Track DCA info", HistType::kTH2F, {axisDCATrackXY, axisDCATrackZ}); + mHistManager.add("tracks/hTrackVX", "Track vertex coordinate X", HistType::kTH1F, {axisVTrackX}); + mHistManager.add("tracks/hTrackVY", "Track vertex coordinate Y", HistType::kTH1F, {axisVTrackY}); + mHistManager.add("tracks/hTrackVZ", "Track vertex coordinate Z", HistType::kTH1F, {axisVTrackZ}); + mHistManager.add("collision/hColVX", "Collision vertex coordinate X", HistType::kTH1F, {axisVColX}); + mHistManager.add("collision/hColVY", "Collision vertex coordinate Y", HistType::kTH1F, {axisVColY}); + mHistManager.add("collision/hColVZ", "Collision vertex coordinate Z", HistType::kTH1F, {axisVColZ}); + mHistManager.add("tracks/hTrackPhosProjMod", "Track projection coordinates on PHOS modules", HistType::kTH3F, {axisX, axisZ, axisModes}); + + mHistManager.add("clusterSpectra/hCluE_v_mod_v_time", "Cluster energy spectrum (E > 0.3 GeV) vs time per module", HistType::kTH3F, {axisE, axisTime, axisModes}); + mHistManager.add("clusterSpectra/hCluE_mod_energy_cut", "Cluster energy spectrum (E > 0.3 GeV) per module", HistType::kTH2F, {axisE, axisModes}); + mHistManager.add("clusterSpectra/hCluE_mod_time_cut", "Cluster energy spectrum (E > 0.3 GeV)(time +-25 ns) per module", HistType::kTH2F, {axisE, axisModes}); + mHistManager.add("clusterSpectra/hCluE_mod_cell_cut", "Cluster energy spectrum (E > 0.3 GeV)(time +-25 ns)(ncells > 3) per module", HistType::kTH2F, {axisE, axisModes}); + mHistManager.add("clusterSpectra/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("clusterSpectra/hCluE_ncells_mod", "Cluster energy spectrum vs cell ammount per module", HistType::kTH3F, {axisE, axisCells, axisModes}); + + mHistManager.add("coordinateMatching/hCluXZ_mod", "Local cluster X Z per module", HistType::kTH3F, {axisX, axisZ, axisModes}); + mHistManager.add("coordinateMatching/hdZpmod", "dz,p_{tr},module", HistType::kTH3F, {axisdZ, axisPt, axisModes}); + mHistManager.add("coordinateMatching/hdZpmod_pos", "dz,p_{tr},module positive tracks", HistType::kTH3F, {axisdZ, axisPt, axisModes}); + mHistManager.add("coordinateMatching/hdZpmod_neg", "dz,p_{tr},module negative tracks", HistType::kTH3F, {axisdZ, axisPt, axisModes}); + mHistManager.add("coordinateMatching/hdXpmod", "dx,p_{tr},module", HistType::kTH3F, {axisdX, axisPt, axisModes}); + mHistManager.add("coordinateMatching/hdXpmod_pos", "dx,p_{tr},module positive tracks", HistType::kTH3F, {axisdX, axisPt, axisModes}); + mHistManager.add("coordinateMatching/hdXpmod_neg", "dx,p_{tr},module negative tracks", HistType::kTH3F, {axisdX, axisPt, axisModes}); + + mHistManager.add("clusterSpectra/hCluE_v_pt_disp", "Cluster energy vs p | OK dispersion", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("clusterSpectra/hCluE_v_pt_Nsigma", "Cluster energy vs p within trackmatch Nsigma", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("clusterSpectra/hCluE_v_pt_Nsigma_disp", "Cluster energy vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisE, axisPt, axisModes}); + + mHistManager.add("energyMomentumRatio/hEp_v_pt_disp", "E/p ratio vs p | OK dispersion", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("energyMomentumRatio/hEp_v_pt_Nsigma", "E/p ratio vs p within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("energyMomentumRatio/hEp_v_pt_Nsigma_disp", "E/p ratio vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisPt, axisModes}); + + mHistManager.add("energyMomentumRatio/hEp_v_E_disp", "E/p ratio vs cluster E | OK dispersion", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("energyMomentumRatio/hEp_v_E_Nsigma", "E/p ratio vs cluster E within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("energyMomentumRatio/hEp_v_E_Nsigma_disp", "E/p ratio vs cluster E within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisE, axisModes}); + + mHistManager.add("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma", "Cluster energy vs p within trackmatch Nsigma", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp", "Cluster energy vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_TPCel", "Cluster energy vs p within trackmatch Nsigma", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp_TPCel", "Cluster energy vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisE, axisPt, axisModes}); + mHistManager.add("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma", "E/p ratio vs p within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp", "E/p ratio vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_TPCel", "E/p ratio vs p within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp_TPCel", "E/p ratio vs p within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisPt, axisModes}); + mHistManager.add("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma", "E/p ratio vs cluster E within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp", "E/p ratio vs cluster E within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_TPCel", "E/p ratio vs cluster E within trackmatch Nsigma", HistType::kTH3F, {axisEp, axisE, axisModes}); + mHistManager.add("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp_TPCel", "E/p ratio vs cluster E within trackmatch Nsigma | OK dispersion", HistType::kTH3F, {axisEp, axisE, axisModes}); + + const char* commonHistos[][2] = { + {"hCluE_v_pt_disp", "Cluster energy vs p | OK dispersion"}, + {"hCluE_v_pt_Nsigma", "Cluster energy vs p within trackmatch Nsigma"}, + {"hCluE_v_pt_Nsigma_disp", "Cluster energy vs p within trackmatch Nsigma | OK dispersion"}, + {"hEp_v_pt_disp", "E/p ratio vs p | OK dispersion"}, + {"hEp_v_pt_Nsigma", "E/p ratio vs p within trackmatch Nsigma"}, + {"hEp_v_pt_Nsigma_disp", "E/p ratio vs p within trackmatch Nsigma | OK dispersion"}, + {"hEp_v_E_disp", "E/p ratio vs cluster E | OK dispersion"}, + {"hEp_v_E_Nsigma", "E/p ratio vs cluster E within trackmatch Nsigma"}, + {"hEp_v_E_Nsigma_disp", "E/p ratio vs cluster E within trackmatch Nsigma | OK dispersion"}}; + + for (auto const& histo : commonHistos) { + AxisSpec axis1 = (TString(histo[0]).Contains("hCluE")) ? axisE : axisEp; + AxisSpec axis2 = (TString(histo[0]).Contains("_v_E_")) ? axisE : axisPt; + const char* subdir = (TString(histo[0]).Contains("hCluE")) ? "clusterSpectra" : "energyMomentumRatio"; + // Histograms for TPC/TOF identified particles + mHistManager.add(Form("PID/%s/%s_TPCel", subdir, histo[0]), Form("%s | TPCel", histo[1]), HistType::kTH3F, {axis1, axis2, axisModes}); + } + + if (isMC) { + mHistManager.add("TrueEl/hTrueElInPhos", "True electrons in PHOS acceptance", HistType::kTH2F, {axisPt, axisModes}); + mHistManager.add("TrueEl/hTrueElWithCluster", "True electrons with a cluster", HistType::kTH2F, {axisPt, axisModes}); + + for (auto const& histo : commonHistos) { + AxisSpec axis1 = (TString(histo[0]).Contains("hCluE")) ? axisE : axisEp; + AxisSpec axis2 = (TString(histo[0]).Contains("_v_E_")) ? axisE : axisPt; + const char* subdir = (TString(histo[0]).Contains("hCluE")) ? "clusterSpectra" : "energyMomentumRatio"; + + // Histograms for all true electrons + mHistManager.add(Form("TrueEl/%s/%s", subdir, histo[0]), Form("%s | TrueEl", histo[1]), HistType::kTH3F, {axis1, axis2, axisModes}); + + // Histograms for true electrons that also pass TPC/TOF PID + mHistManager.add(Form("TrueEl_after_PID/%s/%s_TPCel", subdir, histo[0]), Form("%s | TrueEl+TPCel", histo[1]), HistType::kTH3F, {axis1, axis2, axisModes}); + } + } geomPHOS = std::make_unique("PHOS"); - fSigma_dz = new TF1("func", "[0]/(x+[1])^[2]+pol1(3)", 0.3, 10); - fSigma_dz->SetParameters(parameters_sigma_dz.at(0), parameters_sigma_dz.at(1), parameters_sigma_dz.at(2), parameters_sigma_dz.at(3), parameters_sigma_dz.at(4)); - - fSigma_dx = new TF1("fSigma_dz_dx", "[0]/x^[1]+[2]", 0.1, 10); - fSigma_dx->SetParameters(parameters_sigma_dx.at(0), parameters_sigma_dx.at(1), parameters_sigma_dx.at(2)); - - fMean_dx_pos_mod1 = new TF1("funcMeandx_pos_mod1", "[0]/(x+[1])^[2]", 0.1, 10); - fMean_dx_neg_mod1 = new TF1("funcMeandx_neg_mod1", "[0]/(x+[1])^[2]", 0.1, 10); - fMean_dx_pos_mod2 = new TF1("funcMeandx_pos_mod2", "[0]/(x+[1])^[2]", 0.1, 10); - fMean_dx_neg_mod2 = new TF1("funcMeandx_neg_mod2", "[0]/(x+[1])^[2]", 0.1, 10); - fMean_dx_pos_mod3 = new TF1("funcMeandx_pos_mod3", "[0]/(x+[1])^[2]", 0.1, 10); - fMean_dx_neg_mod3 = new TF1("funcMeandx_neg_mod3", "[0]/(x+[1])^[2]", 0.1, 10); - fMean_dx_pos_mod4 = new TF1("funcMeandx_pos_mod4", "[0]/(x+[1])^[2]", 0.1, 10); - fMean_dx_neg_mod4 = new TF1("funcMeandx_neg_mod4", "[0]/(x+[1])^[2]", 0.1, 10); - - fMean_dx_pos_mod1->SetParameters(Mean_dx_pos_mod1.at(0), Mean_dx_pos_mod1.at(1), Mean_dx_pos_mod1.at(2)); - fMean_dx_pos_mod2->SetParameters(Mean_dx_pos_mod2.at(0), Mean_dx_pos_mod2.at(1), Mean_dx_pos_mod2.at(2)); - fMean_dx_pos_mod3->SetParameters(Mean_dx_pos_mod3.at(0), Mean_dx_pos_mod3.at(1), Mean_dx_pos_mod3.at(2)); - fMean_dx_pos_mod4->SetParameters(Mean_dx_pos_mod4.at(0), Mean_dx_pos_mod4.at(1), Mean_dx_pos_mod4.at(2)); - - fMean_dx_neg_mod1->SetParameters(Mean_dx_neg_mod1.at(0), Mean_dx_neg_mod1.at(1), Mean_dx_neg_mod1.at(2)); - fMean_dx_neg_mod2->SetParameters(Mean_dx_neg_mod2.at(0), Mean_dx_neg_mod2.at(1), Mean_dx_neg_mod2.at(2)); - fMean_dx_neg_mod3->SetParameters(Mean_dx_neg_mod3.at(0), Mean_dx_neg_mod3.at(1), Mean_dx_neg_mod3.at(2)); - fMean_dx_neg_mod4->SetParameters(Mean_dx_neg_mod4.at(0), Mean_dx_neg_mod4.at(1), Mean_dx_neg_mod4.at(2)); + + fSigma_dz = new TF1("fSigma_dz", "[0]/(x+[1])^[2]+pol1(3)", 0.3, 10); + fSigma_dz->SetParameters(((std::vector)pSigmadZ).at(0), ((std::vector)pSigmadZ).at(1), ((std::vector)pSigmadZ).at(2), ((std::vector)pSigmadZ).at(3), ((std::vector)pSigmadZ).at(4)); + + fSigma_dx = new TF1("fSigma_dx", "[0]/x^[1]+[2]", 0.1, 10); + fSigma_dx->SetParameters(((std::vector)pSigmadX).at(0), ((std::vector)pSigmadX).at(1), ((std::vector)pSigmadX).at(2)); + + for (int i = 0; i < mAmountOfModules; i++) { + fMeandXPosMod[i] = new TF1(Form("funcMeandx_pos_mod%i", i + 1), "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXPosMod[i]->SetParameters(pMeandXPosMod->at(3 * i), pMeandXPosMod->at(3 * i + 1), pMeandXPosMod->at(3 * i + 2)); + + fMeandXNegMod[i] = new TF1(Form("funcMeandx_neg_mod%i", i + 1), "[0]/(x+[1])^[2]", 0.1, 10); + fMeandXNegMod[i]->SetParameters(pMeandXNegMod->at(3 * i), pMeandXNegMod->at(3 * i + 1), pMeandXNegMod->at(3 * i + 2)); + } } - void process(soa::Join::iterator const& collision, - aod::CaloClusters& clusters, - tracks& tracks, - aod::BCsWithTimestamps const&) + + void processData(SelCollisions::iterator const& collision, + aod::CaloClusters const& clusters, + soa::Filtered const& tracks, + aod::BCsWithTimestamps const&) { auto bc = collision.bc_as(); if (runNumber != bc.runNumber()) { @@ -254,30 +350,38 @@ struct phosElId { LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; runNumber = bc.runNumber(); } + if (std::fabs(collision.posZ()) > mColMaxZ) + return; mHistManager.fill(HIST("eventCounter"), 0.5); - if (!collision.alias_bit(mEvSelTrig)) + if (isMC && !collision.alias_bit(mEvSelTrig)) return; - mHistManager.fill(HIST("TVXinPHOSCounter"), 0.5); - + mHistManager.fill(HIST("eventCounter"), 1.5); + if (isSel8) { + if (!collision.sel8()) + return; + mHistManager.fill(HIST("eventCounter"), 2.5); + } if (clusters.size() == 0) return; // Nothing to process + mHistManager.fill(HIST("collision/hColVX"), collision.posX()); + mHistManager.fill(HIST("collision/hColVY"), collision.posY()); + mHistManager.fill(HIST("collision/hColVZ"), collision.posZ()); for (auto const& track : tracks) { - if (!track.has_collision()) + if (!track.has_collision() || !track.hasTPC()) continue; - mHistManager.fill(HIST("hTrackVX"), track.x()); - mHistManager.fill(HIST("hTrackVY"), track.y()); - mHistManager.fill(HIST("hTrackVZ"), track.z()); - mHistManager.fill(HIST("hColVX"), collision.posX()); - mHistManager.fill(HIST("hColVY"), collision.posY()); - mHistManager.fill(HIST("hColVZ"), collision.posZ()); - if (std::abs(track.collision_as().posZ()) > 10.f) + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax || !((track.itsClusterMap() & uint8_t(1)) > 0)) continue; - - // calculate coordinate in PHOS plane - if (std::abs(track.eta()) > 0.3) + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + continue; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) continue; + + mHistManager.fill(HIST("tracks/hTrackVX"), track.x()); + mHistManager.fill(HIST("tracks/hTrackVY"), track.y()); + mHistManager.fill(HIST("tracks/hTrackVZ"), track.z()); + int16_t module; float trackX = 999., trackZ = 999.; @@ -286,133 +390,517 @@ struct phosElId { continue; float trackMom = track.p(); - bool posTrack = (track.sign() > 0 && bz > 0) || (track.sign() < 0 && bz < 0); - for (const auto& clu : clusters) { + float trackPT = track.pt(); + + bool isElectron = false; + if (track.hasTPC()) { + float nsigmaTPCEl = track.tpcNSigmaEl(); + float nsigmaTOFEl = track.tofNSigmaEl(); + bool isTPCElectron = nsigmaTPCEl > TPCNSigmaElMin && nsigmaTPCEl < TPCNSigmaElMax; + bool isTOFElectron = nsigmaTOFEl > TOFNSigmaElMin && nsigmaTOFEl < TOFNSigmaElMax; + isElectron = isTPCElectron || isTOFElectron; + + float nsigmaTPCPi = track.tpcNSigmaPi(); + float nsigmaTPCKa = track.tpcNSigmaKa(); + float nsigmaTPCPr = track.tpcNSigmaPr(); + bool isPion = nsigmaTPCPi > TPCNSigmaPiMin && nsigmaTPCPi < TPCNSigmaPiMax; + bool isKaon = nsigmaTPCKa > TPCNSigmaKaMin && nsigmaTPCKa < TPCNSigmaKaMax; + bool isProton = nsigmaTPCPr > TPCNSigmaPrMin && nsigmaTPCPr < TPCNSigmaPrMax; + if (isElectron && !(isPion || isKaon || isProton)) + isElectron = true; + } + + bool posTrack = track.sign() * bz > 0; + for (auto const& clu : clusters) { if (module != clu.mod()) continue; double cluE = clu.e(); - mHistManager.fill(HIST("hCluE_ncells_mod"), cluE, clu.ncell(), module); if (cluE < mMinCluE || clu.ncell() < mMinCluNcell || clu.time() > mMaxCluTime || clu.time() < mMinCluTime) continue; - bool isDispOK = testLambda(cluE, clu.m02(), clu.m20()); + bool isDispOK = false; + if (mSwapM20M02ForTestLambda) + isDispOK = testLambda(cluE, clu.m02(), clu.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOK = testLambda(cluE, clu.m20(), clu.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); float posX = clu.x(), posZ = clu.z(), dX = trackX - posX, dZ = trackZ - posZ, Ep = cluE / trackMom; - mHistManager.fill(HIST("hCluXZ_mod"), posX, posZ, module); - - mHistManager.fill(HIST("hdZpmod"), dZ, trackMom, module); - mHistManager.fill(HIST("hdXpmod"), dX, trackMom, module); + mHistManager.fill(HIST("coordinateMatching/hdZpmod"), dZ, trackPT, module); + mHistManager.fill(HIST("coordinateMatching/hdXpmod"), dX, trackPT, module); if (posTrack) { - mHistManager.fill(HIST("hdZpmod_pos"), dZ, trackMom, module); - mHistManager.fill(HIST("hdXpmod_pos"), dX, trackMom, module); + mHistManager.fill(HIST("coordinateMatching/hdZpmod_pos"), dZ, trackPT, module); + mHistManager.fill(HIST("coordinateMatching/hdXpmod_pos"), dX, trackPT, module); } else { - mHistManager.fill(HIST("hdZpmod_neg"), dZ, trackMom, module); - mHistManager.fill(HIST("hdXpmod_neg"), dX, trackMom, module); + mHistManager.fill(HIST("coordinateMatching/hdZpmod_neg"), dZ, trackPT, module); + mHistManager.fill(HIST("coordinateMatching/hdXpmod_neg"), dX, trackPT, module); } - mHistManager.fill(HIST("hCluE_v_p"), cluE, trackMom, module); if (isDispOK) { - mHistManager.fill(HIST("hCluE_v_p_disp"), cluE, trackMom, module); - mHistManager.fill(HIST("hEp_v_p_disp"), Ep, trackMom, module); + mHistManager.fill(HIST("clusterSpectra/hCluE_v_pt_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_pt_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_E_disp"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("PID/clusterSpectra/hCluE_v_pt_disp_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_pt_disp_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_E_disp_TPCel"), Ep, cluE, module); + } + } + if (clu.trackdist() < NsigmaTrackMatch) { + mHistManager.fill(HIST("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma"), cluE, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma"), Ep, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_TPCel"), Ep, cluE, module); + } + if (isDispOK) { + mHistManager.fill(HIST("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp_TPCel"), Ep, cluE, module); + } + } } - if (!isWithin2Sigma(module, trackMom, dZ, dX)) + if (!isWithinNSigma(module, trackPT, dZ, dX, posTrack)) continue; - mHistManager.fill(HIST("hCluE_v_p_2sigma"), cluE, trackMom, module); - mHistManager.fill(HIST("hEp_v_p_2sigma"), Ep, trackMom, module); - if (isDispOK) { - mHistManager.fill(HIST("hCluE_v_p_2sigma_disp"), cluE, trackMom, module); - mHistManager.fill(HIST("hEp_v_p_2sigma_disp"), Ep, trackMom, module); + mHistManager.fill(HIST("clusterSpectra/hCluE_v_pt_Nsigma"), cluE, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_pt_Nsigma"), Ep, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_E_Nsigma"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("PID/clusterSpectra/hCluE_v_pt_Nsigma_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_pt_Nsigma_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_E_Nsigma_TPCel"), Ep, cluE, module); } - if (isWithin1Sigma(module, trackMom, dZ, dX)) { - mHistManager.fill(HIST("hCluE_v_p_1sigma"), cluE, trackMom, module); - mHistManager.fill(HIST("hEp_v_p_1sigma"), Ep, trackMom, module); - if (isDispOK) { - mHistManager.fill(HIST("hCluE_v_p_1sigma_disp"), cluE, trackMom, module); - mHistManager.fill(HIST("hEp_v_p_1sigma_disp"), Ep, trackMom, module); + if (isDispOK) { + mHistManager.fill(HIST("clusterSpectra/hCluE_v_pt_Nsigma_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_pt_Nsigma_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_E_Nsigma_disp"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("PID/clusterSpectra/hCluE_v_pt_Nsigma_disp_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_pt_Nsigma_disp_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_E_Nsigma_disp_TPCel"), 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); + mHistManager.fill(HIST("tracks/hTrackPtEtaPhi"), track.pt(), track.eta(), track.phi() * TMath::RadToDeg()); + mHistManager.fill(HIST("tracks/hTrackPtEtaPhi_Phos"), track.pt(), track.trackEtaEmcal(), track.trackPhiEmcal() * TMath::RadToDeg()); + mHistManager.fill(HIST("tracks/hTrackDCA"), track.dcaXY(), track.dcaZ()); + mHistManager.fill(HIST("tracks/hTrackPhosProjMod"), trackX, trackZ, module); } // end of double loop - for (const auto& clu : clusters) { + for (auto const& clu : clusters) { double cluE = clu.e(), cluTime = clu.time(); int mod = clu.mod(); + bool isDispOK = false; + if (mSwapM20M02ForTestLambda) + isDispOK = testLambda(cluE, clu.m02(), clu.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOK = testLambda(cluE, clu.m20(), clu.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); if (cluE > mMinCluE) { - mHistManager.fill(HIST("hCluE_mod_energy_cut"), cluE, mod); - mHistManager.fill(HIST("hCluE_v_mod_v_time"), cluE, cluTime * 1e9, mod); + mHistManager.fill(HIST("clusterSpectra/hCluE_mod_energy_cut"), cluE, mod); + mHistManager.fill(HIST("clusterSpectra/hCluE_v_mod_v_time"), cluE, cluTime * 1e9, mod); if (cluTime < mMaxCluTime && cluTime > mMinCluTime) { - mHistManager.fill(HIST("hCluE_mod_time_cut"), cluE, mod); + mHistManager.fill(HIST("clusterSpectra/hCluE_mod_time_cut"), cluE, mod); if (clu.ncell() >= mMinCluNcell) { - mHistManager.fill(HIST("hCluE_mod_cell_cut"), cluE, mod); - if (testLambda(cluE, clu.m02(), clu.m20())) - mHistManager.fill(HIST("hCluE_mod_disp"), cluE, mod); + mHistManager.fill(HIST("clusterSpectra/hCluE_mod_cell_cut"), cluE, mod); + mHistManager.fill(HIST("coordinateMatching/hCluXZ_mod"), clu.x(), clu.z(), mod); + mHistManager.fill(HIST("clusterSpectra/hCluE_ncells_mod"), cluE, clu.ncell(), mod); + if (isDispOK) + mHistManager.fill(HIST("clusterSpectra/hCluE_mod_disp"), cluE, mod); + } + } + } + + if (cluE < mMinCluE || + clu.ncell() < mMinCluNcell || + clu.time() > mMaxCluTime || clu.time() < mMinCluTime) + continue; + + // The following block is disabled by default as it appears to be broken as of now. + if (mFillSingleLoopHistos) { + if (clu.trackdist() > NsigmaTrackMatch) + continue; + if (clu.trackIndex() == UCHAR_MAX) { + continue; + } + auto matchedTrack = tracks.iteratorAt(clu.trackIndex()); + if (!matchedTrack.has_collision() || !matchedTrack.hasTPC()) + continue; + + if (matchedTrack.itsNCls() < ITSnclsMin || matchedTrack.itsNCls() > ITSnclsMax || !((matchedTrack.itsClusterMap() & uint8_t(1)) > 0)) + continue; + if (matchedTrack.tpcNClsFound() < TPCnclsMin || matchedTrack.tpcNClsFound() > TPCnclsMax) + continue; + if (matchedTrack.tpcNClsCrossedRows() < TPCnclsCRMin || matchedTrack.tpcNClsCrossedRows() > TPCnclsCRMax) + continue; + + mHistManager.fill(HIST("singleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma"), cluE, matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma"), cluE / matchedTrack.p(), matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma"), cluE / matchedTrack.p(), cluE, mod); + if (isDispOK) { + mHistManager.fill(HIST("singleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp"), cluE, matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp"), cluE / matchedTrack.p(), matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp"), cluE / matchedTrack.p(), cluE, mod); + } + bool isElectron = false; + if (matchedTrack.hasTPC()) { + float nsigmaTPCEl = matchedTrack.tpcNSigmaEl(); + float nsigmaTOFEl = matchedTrack.tofNSigmaEl(); + bool isTPCElectron = nsigmaTPCEl > TPCNSigmaElMin && nsigmaTPCEl < TPCNSigmaElMax; + bool isTOFElectron = nsigmaTOFEl > TOFNSigmaElMin && nsigmaTOFEl < TOFNSigmaElMax; + isElectron = isTPCElectron || isTOFElectron; + + float nsigmaTPCPi = matchedTrack.tpcNSigmaPi(); + float nsigmaTPCKa = matchedTrack.tpcNSigmaKa(); + float nsigmaTPCPr = matchedTrack.tpcNSigmaPr(); + bool isPion = nsigmaTPCPi > TPCNSigmaPiMin && nsigmaTPCPi < TPCNSigmaPiMax; + bool isKaon = nsigmaTPCKa > TPCNSigmaKaMin && nsigmaTPCKa < TPCNSigmaKaMax; + bool isProton = nsigmaTPCPr > TPCNSigmaPrMin && nsigmaTPCPr < TPCNSigmaPrMax; + if (isElectron && !(isPion || isKaon || isProton)) + isElectron = true; + } + if (isElectron) { + mHistManager.fill(HIST("singleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_TPCel"), cluE, matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_TPCel"), cluE / matchedTrack.p(), matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_TPCel"), cluE / matchedTrack.p(), cluE, mod); + if (isDispOK) { + mHistManager.fill(HIST("singleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp_TPCel"), cluE, matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp_TPCel"), cluE / matchedTrack.p(), matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp_TPCel"), cluE / matchedTrack.p(), cluE, mod); } } } } // end of cluster loop } + PROCESS_SWITCH(PhosElId, processData, "process data", false); - bool isWithin2Sigma(int16_t& mod, float p, float deltaZ, float deltaX) + void processMC(SelCollisions::iterator const& collision, + aod::CaloClusters const& clusters, + soa::Join, aod::McTrackLabels> const& tracks, + aod::McParticles const& mcParticles, + aod::BCsWithTimestamps const&) { - if (mod == 1) { - if (fabs(deltaZ - PhosShiftZ[0]) > 2 * fSigma_dz->Eval(p)) - return false; - if (fabs(deltaX - fMean_dx_pos_mod1->Eval(p) + PhosShiftX[0]) > 2 * fSigma_dx->Eval(p)) - return false; - } else if (mod == 2) { - if (fabs(deltaZ - PhosShiftZ[1]) > 2 * fSigma_dz->Eval(p)) - return false; - if (fabs(deltaX - fMean_dx_pos_mod2->Eval(p) + PhosShiftX[1]) > 2 * fSigma_dx->Eval(p)) - return false; - } else if (mod == 3) { - if (fabs(deltaZ - PhosShiftZ[2]) > 2 * fSigma_dz->Eval(p)) - return false; - if (fabs(deltaX - fMean_dx_pos_mod3->Eval(p) + PhosShiftX[2]) > 2 * fSigma_dx->Eval(p)) - return false; - } else if (mod == 4) { - if (fabs(deltaZ - PhosShiftZ[3]) > 2 * fSigma_dz->Eval(p)) - return false; - if (fabs(deltaX - fMean_dx_pos_mod4->Eval(p) + PhosShiftX[3]) > 2 * fSigma_dx->Eval(p)) - return false; + 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(); } - return true; + if (std::fabs(collision.posZ()) > mColMaxZ) + return; + mHistManager.fill(HIST("eventCounter"), 0.5); + if (!isMC && !collision.alias_bit(mEvSelTrig)) + return; + mHistManager.fill(HIST("eventCounter"), 1.5); + if (isSel8) { + if (!collision.sel8()) + return; + mHistManager.fill(HIST("eventCounter"), 2.5); + } + if (clusters.size() == 0) + return; // Nothing to process + mHistManager.fill(HIST("collision/hColVX"), collision.posX()); + mHistManager.fill(HIST("collision/hColVY"), collision.posY()); + mHistManager.fill(HIST("collision/hColVZ"), collision.posZ()); + + for (auto const& track : tracks) { + + if (!track.has_collision() || !track.hasTPC()) + continue; + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax || !((track.itsClusterMap() & uint8_t(1)) > 0)) + continue; + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + continue; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) + continue; + + mHistManager.fill(HIST("tracks/hTrackVX"), track.x()); + mHistManager.fill(HIST("tracks/hTrackVY"), track.y()); + mHistManager.fill(HIST("tracks/hTrackVZ"), track.z()); + + int16_t module; + float trackX = 999., trackZ = 999.; + + auto trackPar = getTrackPar(track); + if (!impactOnPHOS(trackPar, track.trackEtaEmcal(), track.trackPhiEmcal(), track.collision_as().posZ(), module, trackX, trackZ)) + continue; + + float trackMom = track.p(); + float trackPT = track.pt(); + + bool isElectron = false; + if (track.hasTPC()) { + float nsigmaTPCEl = track.tpcNSigmaEl(); + float nsigmaTOFEl = track.tofNSigmaEl(); + bool isTPCElectron = nsigmaTPCEl > TPCNSigmaElMin && nsigmaTPCEl < TPCNSigmaElMax; + bool isTOFElectron = nsigmaTOFEl > TOFNSigmaElMin && nsigmaTOFEl < TOFNSigmaElMax; + isElectron = isTPCElectron || isTOFElectron; + + float nsigmaTPCPi = track.tpcNSigmaPi(); + float nsigmaTPCKa = track.tpcNSigmaKa(); + float nsigmaTPCPr = track.tpcNSigmaPr(); + bool isPion = nsigmaTPCPi > TPCNSigmaPiMin && nsigmaTPCPi < TPCNSigmaPiMax; + bool isKaon = nsigmaTPCKa > TPCNSigmaKaMin && nsigmaTPCKa < TPCNSigmaKaMax; + bool isProton = nsigmaTPCPr > TPCNSigmaPrMin && nsigmaTPCPr < TPCNSigmaPrMax; + if (isElectron && !(isPion || isKaon || isProton)) + isElectron = true; + } + + bool isTrueElectron = false; + auto mcLabel = track.mcParticleId(); + if (mcLabel > -1 && mcLabel < mcParticles.size()) { + auto mcpart = mcParticles.iteratorAt(mcLabel); + if (std::abs(mcpart.pdgCode()) == PDG_t::kElectron) { + isTrueElectron = true; + } + } + + if (isTrueElectron) { + mHistManager.fill(HIST("TrueEl/hTrueElInPhos"), trackPT, module); + } + + bool posTrack = track.sign() * bz > 0; + for (auto const& clu : clusters) { + if (module != clu.mod()) + continue; + double cluE = clu.e(); + + if (cluE < mMinCluE || + clu.ncell() < mMinCluNcell || + clu.time() > mMaxCluTime || clu.time() < mMinCluTime) + continue; + + if (isTrueElectron) { + mHistManager.fill(HIST("TrueEl/hTrueElWithCluster"), trackPT, module); + } + + bool isDispOK = false; + if (mSwapM20M02ForTestLambda) + isDispOK = testLambda(cluE, clu.m02(), clu.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOK = testLambda(cluE, clu.m20(), clu.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); + float posX = clu.x(), posZ = clu.z(), dX = trackX - posX, dZ = trackZ - posZ, Ep = cluE / trackMom; + + mHistManager.fill(HIST("coordinateMatching/hdZpmod"), dZ, trackPT, module); + mHistManager.fill(HIST("coordinateMatching/hdXpmod"), dX, trackPT, module); + if (posTrack) { + mHistManager.fill(HIST("coordinateMatching/hdZpmod_pos"), dZ, trackPT, module); + mHistManager.fill(HIST("coordinateMatching/hdXpmod_pos"), dX, trackPT, module); + } else { + mHistManager.fill(HIST("coordinateMatching/hdZpmod_neg"), dZ, trackPT, module); + mHistManager.fill(HIST("coordinateMatching/hdXpmod_neg"), dX, trackPT, module); + } + + if (isDispOK) { + mHistManager.fill(HIST("clusterSpectra/hCluE_v_pt_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_pt_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_E_disp"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("PID/clusterSpectra/hCluE_v_pt_disp_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_pt_disp_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_E_disp_TPCel"), Ep, cluE, module); + if (isTrueElectron) { + mHistManager.fill(HIST("TrueEl_after_PID/clusterSpectra/hCluE_v_pt_disp_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("TrueEl_after_PID/energyMomentumRatio/hEp_v_pt_disp_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("TrueEl_after_PID/energyMomentumRatio/hEp_v_E_disp_TPCel"), Ep, cluE, module); + } + } + if (isTrueElectron) { + mHistManager.fill(HIST("TrueEl/clusterSpectra/hCluE_v_pt_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("TrueEl/energyMomentumRatio/hEp_v_pt_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("TrueEl/energyMomentumRatio/hEp_v_E_disp"), Ep, cluE, module); + } + } + if (clu.trackdist() < NsigmaTrackMatch) { + mHistManager.fill(HIST("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma"), cluE, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma"), Ep, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_TPCel"), Ep, cluE, module); + } + if (isDispOK) { + mHistManager.fill(HIST("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("doubleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("doubleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp_TPCel"), Ep, cluE, module); + } + } + } + if (!isWithinNSigma(module, trackPT, dZ, dX, posTrack)) + continue; + mHistManager.fill(HIST("clusterSpectra/hCluE_v_pt_Nsigma"), cluE, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_pt_Nsigma"), Ep, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_E_Nsigma"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("PID/clusterSpectra/hCluE_v_pt_Nsigma_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_pt_Nsigma_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_E_Nsigma_TPCel"), Ep, cluE, module); + if (isTrueElectron) { + mHistManager.fill(HIST("TrueEl_after_PID/clusterSpectra/hCluE_v_pt_Nsigma_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("TrueEl_after_PID/energyMomentumRatio/hEp_v_pt_Nsigma_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("TrueEl_after_PID/energyMomentumRatio/hEp_v_E_Nsigma_TPCel"), Ep, cluE, module); + } + } + if (isTrueElectron) { + mHistManager.fill(HIST("TrueEl/clusterSpectra/hCluE_v_pt_Nsigma"), cluE, trackPT, module); + mHistManager.fill(HIST("TrueEl/energyMomentumRatio/hEp_v_pt_Nsigma"), Ep, trackPT, module); + mHistManager.fill(HIST("TrueEl/energyMomentumRatio/hEp_v_E_Nsigma"), Ep, cluE, module); + } + if (isDispOK) { + mHistManager.fill(HIST("clusterSpectra/hCluE_v_pt_Nsigma_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_pt_Nsigma_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("energyMomentumRatio/hEp_v_E_Nsigma_disp"), Ep, cluE, module); + if (isElectron) { + mHistManager.fill(HIST("PID/clusterSpectra/hCluE_v_pt_Nsigma_disp_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_pt_Nsigma_disp_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("PID/energyMomentumRatio/hEp_v_E_Nsigma_disp_TPCel"), Ep, cluE, module); + if (isTrueElectron) { + mHistManager.fill(HIST("TrueEl_after_PID/clusterSpectra/hCluE_v_pt_Nsigma_disp_TPCel"), cluE, trackPT, module); + mHistManager.fill(HIST("TrueEl_after_PID/energyMomentumRatio/hEp_v_pt_Nsigma_disp_TPCel"), Ep, trackPT, module); + mHistManager.fill(HIST("TrueEl_after_PID/energyMomentumRatio/hEp_v_E_Nsigma_disp_TPCel"), Ep, cluE, module); + } + } + if (isTrueElectron) { + mHistManager.fill(HIST("TrueEl/clusterSpectra/hCluE_v_pt_Nsigma_disp"), cluE, trackPT, module); + mHistManager.fill(HIST("TrueEl/energyMomentumRatio/hEp_v_pt_Nsigma_disp"), Ep, trackPT, module); + mHistManager.fill(HIST("TrueEl/energyMomentumRatio/hEp_v_E_Nsigma_disp"), Ep, cluE, module); + } + phosMatch(collision.index(), clu.index(), track.index()); + } + } + + mHistManager.fill(HIST("tracks/hTrackPtEtaPhi"), track.pt(), track.eta(), track.phi() * TMath::RadToDeg()); + mHistManager.fill(HIST("tracks/hTrackPtEtaPhi_Phos"), track.pt(), track.trackEtaEmcal(), track.trackPhiEmcal() * TMath::RadToDeg()); + mHistManager.fill(HIST("tracks/hTrackDCA"), track.dcaXY(), track.dcaZ()); + mHistManager.fill(HIST("tracks/hTrackPhosProjMod"), trackX, trackZ, module); + } // end of double loop + + for (auto const& clu : clusters) { + double cluE = clu.e(), cluTime = clu.time(); + int mod = clu.mod(); + bool isDispOK = false; + if (mSwapM20M02ForTestLambda) + isDispOK = testLambda(cluE, clu.m02(), clu.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOK = testLambda(cluE, clu.m20(), clu.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); + if (cluE > mMinCluE) { + mHistManager.fill(HIST("clusterSpectra/hCluE_mod_energy_cut"), cluE, mod); + mHistManager.fill(HIST("clusterSpectra/hCluE_v_mod_v_time"), cluE, cluTime * 1e9, mod); + if (cluTime < mMaxCluTime && cluTime > mMinCluTime) { + mHistManager.fill(HIST("clusterSpectra/hCluE_mod_time_cut"), cluE, mod); + if (clu.ncell() >= mMinCluNcell) { + mHistManager.fill(HIST("clusterSpectra/hCluE_mod_cell_cut"), cluE, mod); + mHistManager.fill(HIST("coordinateMatching/hCluXZ_mod"), clu.x(), clu.z(), mod); + mHistManager.fill(HIST("clusterSpectra/hCluE_ncells_mod"), cluE, clu.ncell(), mod); + if (isDispOK) + mHistManager.fill(HIST("clusterSpectra/hCluE_mod_disp"), cluE, mod); + } + } + } + + if (cluE < mMinCluE || + clu.ncell() < mMinCluNcell || + clu.time() > mMaxCluTime || clu.time() < mMinCluTime) + continue; + + // The following block is disabled by default because the track and cluster labels are not consistent, causing crashes when trying to access tracks using cluster information. + if (mFillSingleLoopHistos) { + if (clu.trackdist() > NsigmaTrackMatch) + continue; + if (clu.trackIndex() == UCHAR_MAX) { + continue; + } + auto matchedTrack = tracks.iteratorAt(clu.trackIndex()); + + if (!matchedTrack.has_collision() || !matchedTrack.hasTPC()) + continue; + + if (matchedTrack.itsNCls() < ITSnclsMin || matchedTrack.itsNCls() > ITSnclsMax || !((matchedTrack.itsClusterMap() & uint8_t(1)) > 0)) + continue; + if (matchedTrack.tpcNClsFound() < TPCnclsMin || matchedTrack.tpcNClsFound() > TPCnclsMax) + continue; + if (matchedTrack.tpcNClsCrossedRows() < TPCnclsCRMin || matchedTrack.tpcNClsCrossedRows() > TPCnclsCRMax) + continue; + + mHistManager.fill(HIST("singleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma"), cluE, matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma"), cluE / matchedTrack.p(), matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma"), cluE / matchedTrack.p(), cluE, mod); + if (isDispOK) { + mHistManager.fill(HIST("singleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp"), cluE, matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp"), cluE / matchedTrack.p(), matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp"), cluE / matchedTrack.p(), cluE, mod); + } + bool isElectron = false; + if (matchedTrack.hasTPC()) { + float nsigmaTPCEl = matchedTrack.tpcNSigmaEl(); + float nsigmaTOFEl = matchedTrack.tofNSigmaEl(); + bool isTPCElectron = nsigmaTPCEl > TPCNSigmaElMin && nsigmaTPCEl < TPCNSigmaElMax; + bool isTOFElectron = nsigmaTOFEl > TOFNSigmaElMin && nsigmaTOFEl < TOFNSigmaElMax; + isElectron = isTPCElectron || isTOFElectron; + + float nsigmaTPCPi = matchedTrack.tpcNSigmaPi(); + float nsigmaTPCKa = matchedTrack.tpcNSigmaKa(); + float nsigmaTPCPr = matchedTrack.tpcNSigmaPr(); + bool isPion = nsigmaTPCPi > TPCNSigmaPiMin && nsigmaTPCPi < TPCNSigmaPiMax; + bool isKaon = nsigmaTPCKa > TPCNSigmaKaMin && nsigmaTPCKa < TPCNSigmaKaMax; + bool isProton = nsigmaTPCPr > TPCNSigmaPrMin && nsigmaTPCPr < TPCNSigmaPrMax; + if (isElectron && !(isPion || isKaon || isProton)) + isElectron = true; + } + if (isElectron) { + mHistManager.fill(HIST("singleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_TPCel"), cluE, matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_TPCel"), cluE / matchedTrack.p(), matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_TPCel"), cluE / matchedTrack.p(), cluE, mod); + if (isDispOK) { + mHistManager.fill(HIST("singleLoop/trackdist/clusterSpectra/hCluE_v_pt_Nsigma_disp_TPCel"), cluE, matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_pt_Nsigma_disp_TPCel"), cluE / matchedTrack.p(), matchedTrack.pt(), mod); + mHistManager.fill(HIST("singleLoop/trackdist/energyMomentumRatio/hEp_v_E_Nsigma_disp_TPCel"), cluE / matchedTrack.p(), cluE, mod); + } + } + } + } // end of cluster loop } + PROCESS_SWITCH(PhosElId, processMC, "process mc", false); + + void processDummy(SelCollisions::iterator const&) {} + PROCESS_SWITCH(PhosElId, processDummy, "Dummy process", true); - bool isWithin1Sigma(int16_t& mod, float p, float deltaZ, float deltaX) + bool isWithinNSigma(int16_t& mod, float p, float deltaZ, float deltaX, bool positiveCharge) { - if (mod == 1) { - if (fabs(deltaZ - PhosShiftZ[0]) > fSigma_dz->Eval(p)) - return false; - if (fabs(deltaX - fMean_dx_pos_mod1->Eval(p) + PhosShiftX[0]) > fSigma_dx->Eval(p)) - return false; - } else if (mod == 2) { - if (fabs(deltaZ - PhosShiftZ[1]) > fSigma_dz->Eval(p)) - return false; - if (fabs(deltaX - fMean_dx_pos_mod2->Eval(p) + PhosShiftX[1]) > fSigma_dx->Eval(p)) - return false; - } else if (mod == 3) { - if (fabs(deltaZ - PhosShiftZ[2]) > fSigma_dz->Eval(p)) - return false; - if (fabs(deltaX - fMean_dx_pos_mod3->Eval(p) + PhosShiftX[2]) > fSigma_dx->Eval(p)) - return false; - } else if (mod == 4) { - if (fabs(deltaZ - PhosShiftZ[3]) > fSigma_dz->Eval(p)) + int modMinus1 = mod - 1; + if (std::fabs(deltaZ - ((std::vector)pPhosShiftZ).at(modMinus1)) > NsigmaTrackMatch * fSigma_dz->Eval(p)) + return false; + if (positiveCharge) { + if (std::fabs(deltaX - fMeandXPosMod[modMinus1]->Eval(p) - ((std::vector)pPhosShiftX).at(modMinus1)) > NsigmaTrackMatch * fSigma_dx->Eval(p)) return false; - if (fabs(deltaX - fMean_dx_pos_mod4->Eval(p) + PhosShiftX[3]) > fSigma_dx->Eval(p)) + } else { + if (std::fabs(deltaX - fMeandXNegMod[modMinus1]->Eval(p) - ((std::vector)pPhosShiftX).at(modMinus1)) > NsigmaTrackMatch * fSigma_dx->Eval(p)) return false; } return true; } - - /////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////// taken from PHOSAlign bool impactOnPHOS(o2::track::TrackParametrization& trackPar, float trackEta, float trackPhi, float /*zvtx*/, int16_t& module, float& trackX, float& trackZ) { // eta,phi was calculated at EMCAL radius. @@ -421,31 +909,26 @@ 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(); - } + trackPhi = RecoDecay::constrainAngle(trackPhi); + module = 1 + static_cast((trackPhi - phiMin) / dphi); if (module < 1) { module = 1; } - if (module > 4) { - module = 4; + if (module > mAmountOfModules) { // > 4 + module = mAmountOfModules; // = 4 } // 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 @@ -470,7 +953,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(); @@ -480,26 +963,1360 @@ struct phosElId { trackZ = posL[1]; return true; } - //_____________________________________________________________________________ - bool testLambda(float pt, float l1, float l2) +}; + +struct MassSpectra { + + using SelCollisions = soa::Join; + using MyTracks = soa::Join; + Configurable isMC{"isMC", false, "Enable MC analysis"}, + isSel8{"isSel8", 1, "check if event is Single Event Latch-up 8"}; + Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}, + MassBinning{"MassBinning", 1000, "Binning for mass"}, + EnergyBinning{"EnergyBinning", 100, "Binning for energy"}, + EpRatioBinning{"EpRatioBinning", 200, "Binning for energy to momentum ratio"}, + CentBinning{"CentBinning", 10, "Binning for centrality"}, + CentEst{"CentEst", 1, "Centrality estimator, 0: FV0A, 1: FT0M, 2: FT0A, 3: FT0C, 4: FDDM, 5: NTPV"}; + + Configurable mColMaxZ{"mColMaxZ", 10.f, "maximum z accepted in analysis"}, + fEtaMax{"fEtaMax", {0.8f}, "eta ranges"}, + fEtaMaxPhos{"fEtaMaxPhos", {0.15f}, "eta ranges of phos"}, + fPtMin{"fPtMin", {0.2f}, "pt min"}, + fPtMax{"fPtMax", {20.f}, "pt max"}, + fMassSpectraMin{"fMassSpectraMin", {2.5f}, "mass spectra min for e+e-"}, + fMassSpectraMax{"fMassSpectraMax", {3.5f}, "mass spcetra max for e+e-"}, + fDCAxyMax{"fDCAxyMax", {3.f}, "dcaxy max"}, + fDCAzMax{"fDCAzMax", {3.f}, "dcaz max"}, + fITSchi2Max{"fITSchi2Max", {5.f}, "its chi2 max"}, + fITSnclsMin{"fITSnclsMin", {4.5f}, "min number of ITS clusters"}, + fITSnclsMax{"fITSnclsMax", {7.5f}, "max number of ITS clusters"}, + fTPCchi2Max{"fTPCchi2Max", {4.f}, "tpc chi2 max"}, + fTPCnclsMin{"fTPCnclsMin", {90.f}, "min number of TPC clusters"}, + fTPCnclsMax{"fTPCnclsMax", {170.f}, "max number of TPC clusters"}, + fTPCnclsCRMin{"fTPCnclsCRMin", {80.f}, "min number of TPC crossed rows"}, + fTPCnclsCRMax{"fTPCnclsCRMax", {161.f}, "max number of TPC crossed rows"}, + fTPCNSigmaElMin{"fTPCNSigmaElMin", {-3.f}, "min TPC nsigma e for inclusion"}, + fTPCNSigmaElMax{"fTPCNSigmaElMax", {2.f}, "max TPC nsigma e for inclusion"}, + fTPCNSigmaPiMin{"fTPCNSigmaPiMin", {-3.f}, "min TPC nsigma pion for exclusion"}, + fTPCNSigmaPiMax{"fTPCNSigmaPiMax", {3.5f}, "max TPC nsigma pion for exclusion"}, + fTPCNSigmaPrMin{"fTPCNSigmaPrMin", {-3.f}, "min TPC nsigma proton for exclusion"}, + fTPCNSigmaPrMax{"fTPCNSigmaPrMax", {4.f}, "max TPC nsigma proton for exclusion"}, + fTPCNSigmaKaMin{"fTPCNSigmaKaMin", {-3.f}, "min TPC nsigma kaon for exclusion"}, + fTPCNSigmaKaMax{"fTPCNSigmaKaMax", {4.f}, "max TPC nsigma kaon for exclusion"}, + fTOFNSigmaElMin{"fTOFNSigmaElMin", {-3.f}, "min TOF nsigma e for inclusion"}, + fTOFNSigmaElMax{"fTOFNSigmaElMax", {3.f}, "max TOF nsigma e for inclusion"}, + fShiftEp{"fShiftEp", {0.055f}, "PHOS E/p shift for electrons"}, + fNsigmaEp{"fNsigmaEp", {2.f}, "PHOS E/p nsigma for inclusion"}; + + Configurable> fEpSigmaPars{"fEpSigmaPars", {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{3, 0, +3, ""}, + axisCent{CentBinning, 0, 100, "centrality percentage"}, + axisPt{momentumBinning, "p_{T} (GeV/c)"}, + axisEp{EpRatioBinning, 0., 2., "E/p", "E_{cluster}/p_{track}"}, + axisE{EnergyBinning, 0, 10, "E (GeV)", "E (GeV)"}, + axisMassSpectrum{MassBinning, fMassSpectraMin, fMassSpectraMax, "M (GeV/c^{2})", "Mass e^{+}e^{-} (GeV/c^{2})"}; + + mHistManager.add("eventCounter", "eventCounter", 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 = fEpSigmaPars; + 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()) > mColMaxZ) + return; + mHistManager.fill(HIST("eventCounter"), 0.5); + if (!isMC && !collision.alias_bit(mEvSelTrig)) + return; + mHistManager.fill(HIST("eventCounter"), 1.5); + if (isSel8) { + if (!collision.sel8()) + return; + mHistManager.fill(HIST("eventCounter"), 2.5); + } + + if (clusters.size() == 0) + return; // Nothing to process + + float cent = -1.; + switch (CentEst) { + 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()) > fDCAxyMax || std::fabs(TPCel.dcaZ()) > fDCAzMax || !TPCel.hasTPC() || std::fabs(TPCel.eta()) > fEtaMaxPhos) + continue; + if (TPCel.pt() < fPtMin || TPCel.pt() > fPtMax) + continue; + if (TPCel.itsChi2NCl() > fITSchi2Max) + continue; + if (TPCel.itsNCls() < fITSnclsMin || TPCel.itsNCls() > fITSnclsMax || !((TPCel.itsClusterMap() & uint8_t(1)) > 0)) + continue; + if (TPCel.tpcChi2NCl() > fTPCchi2Max) + continue; + if (TPCel.tpcNClsFound() < fTPCnclsMin || TPCel.tpcNClsFound() > fTPCnclsMax) + continue; + if (TPCel.tpcNClsCrossedRows() < fTPCnclsCRMin || TPCel.tpcNClsCrossedRows() > fTPCnclsCRMax) + continue; + + bool isElectron = false; + float nsigmaTPCEl = TPCel.tpcNSigmaEl(); + float nsigmaTOFEl = TPCel.tofNSigmaEl(); + bool isTPCElectron = nsigmaTPCEl > fTPCNSigmaElMin && nsigmaTPCEl < fTPCNSigmaElMax; + bool isTOFElectron = nsigmaTOFEl > fTOFNSigmaElMin && nsigmaTOFEl < fTOFNSigmaElMax; + isElectron = isTPCElectron || isTOFElectron; + + float nsigmaTPCPi = TPCel.tpcNSigmaPi(); + float nsigmaTPCKa = TPCel.tpcNSigmaKa(); + float nsigmaTPCPr = TPCel.tpcNSigmaPr(); + bool isPion = nsigmaTPCPi > fTPCNSigmaPiMin && nsigmaTPCPi < fTPCNSigmaPiMax; + bool isKaon = nsigmaTPCKa > fTPCNSigmaKaMin && nsigmaTPCKa < fTPCNSigmaKaMax; + bool isProton = nsigmaTPCPr > fTPCNSigmaPrMin && nsigmaTPCPr < fTPCNSigmaPrMax; + 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, momProbeTrack = track2.pt(), cluE = clust2.e(); + ROOT::Math::LorentzVector> fourVectorP1, fourVectorP2; + fourVectorP1.SetPxPyPzE(TPCel.px(), TPCel.py(), TPCel.pz(), TPCel.energy(0)); + fourVectorP2.SetPxPyPzE(track2.px(), track2.py(), track2.pz(), track2.energy(0)); + mass2Tracks = (fourVectorP1 + fourVectorP2).M(); + bool elCandidate = (std::fabs(cluE / track2.p() - fShiftEp - 1) < fNsigmaEp * fEpSigmaPhos->Eval(cluE)); + + if (TPCel.sign() == track2.sign()) { + if (posTrack) { + mHistManager.fill(HIST("h_eh_pp_mass_spectra_v_pt_v_cent"), mass2Tracks, momProbeTrack, 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, momProbeTrack, 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, momProbeTrack, 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, momProbeTrack, 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, momProbeTrack, 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, momProbeTrack, 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 - fShiftEp - 1) < fNsigmaEp * fEpSigmaPhos->Eval(cluE)); + if (elCandidate) + mHistManager.fill(HIST("hEp_v_E_v_cent_cutEp"), epRatio, cluE, cent); + } + } + PROCESS_SWITCH(MassSpectra, process, "process", false); + + void processDummy(SelCollisions::iterator const&) {} + PROCESS_SWITCH(MassSpectra, processDummy, "Dummy process", true); +}; + +struct TpcElIdMassSpectrum { + + using SelCollisions = soa::Join; + using MyTracks = soa::Join; + Configurable isSel8{"isSel8", 1, "check if event is Single Event Latch-up 8"}, + mSwapM20M02ForTestLambda{"mSwapM20M02ForTestLambda", false, "Swap m20 and m02 arguments for testLambda (false for note's correct order, true for swapped/original incorrect order)"}, + mUseNegativeCrossTerm{"mUseNegativeCrossTerm", true, "Use negative sign for the cross-term in testLambda (true for analysis note version, false for old version)"}; + + Configurable isMC{"isMC", true, "Enable MC analysis"}; + Configurable mColMaxZ{"mColMaxZ", 10.f, "maximum z accepted in analysis"}, + 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"}, + EtaMax{"EtaMax", {0.8f}, "eta ranges"}, + PtMin{"PtMin", {0.2f}, "pt min"}, + PtMax{"PtMax", {20.f}, "pt max"}, + MassSpectraJpsiMin{"MassSpectraJpsiMin", {0.5f}, "mass spectra min for Jpsi region"}, + MassSpectraJpsiMax{"MassSpectraJpsiMax", {3.5f}, "mass spcetra max for Jpsi region"}, + MassSpectraChicMin{"MassSpectraChicMin", {3.f}, "mass spectra min Chic region"}, + MassSpectraChicMax{"MassSpectraChicMax", {4.f}, "mass spcetra max Chic region"}, + DCAxyMax{"DCAxyMax", {3.f}, "dcaxy max"}, + DCAzMax{"DCAzMax", {3.f}, "dcaz max"}, + ITSchi2Max{"ITSchi2Max", {5.f}, "its chi2 max"}, + ITSnclsMin{"ITSnclsMin", {4.5f}, "min number of ITS clusters"}, + ITSnclsMax{"ITSnclsMax", {7.5f}, "max number of ITS clusters"}, + TPCchi2Max{"TPCchi2Max", {4.f}, "tpc chi2 max"}, + TPCnclsMin{"TPCnclsMin", {90.f}, "min number of TPC clusters"}, + TPCnclsMax{"TPCnclsMax", {170.f}, "max number of TPC clusters"}, + TPCnclsCRMin{"TPCnclsCRMin", {80.f}, "min number of TPC crossed rows"}, + TPCnclsCRMax{"TPCnclsCRMax", {161.f}, "max number of TPC crossed rows"}, + TPCNSigmaElMin{"TPCNSigmaElMin", {-3.f}, "min TPC nsigma e for inclusion"}, + TPCNSigmaElMax{"TPCNSigmaElMax", {2.f}, "max TPC nsigma e for inclusion"}, + TPCNSigmaPiMin{"TPCNSigmaPiMin", {-3.f}, "min TPC nsigma pion for exclusion"}, + TPCNSigmaPiMax{"TPCNSigmaPiMax", {3.5f}, "max TPC nsigma pion for exclusion"}, + TPCNSigmaPrMin{"TPCNSigmaPrMin", {-3.f}, "min TPC nsigma proton for exclusion"}, + TPCNSigmaPrMax{"TPCNSigmaPrMax", {4.f}, "max TPC nsigma proton for exclusion"}, + TPCNSigmaKaMin{"TPCNSigmaKaMin", {-3.f}, "min TPC nsigma kaon for exclusion"}, + TPCNSigmaKaMax{"TPCNSigmaKaMax", {4.f}, "max TPC nsigma kaon for exclusion"}, + TOFNSigmaElMin{"TOFNSigmaElMin", {-3.f}, "min TOF nsigma e for inclusion"}, + TOFNSigmaElMax{"TOFNSigmaElMax", {3.f}, "max TOF nsigma e for inclusion"}, + PhosRangeEta{"PhosRangeEta", {0.12f}, "Phos range definition plus minus eta"}, + PhosRangePhiMin{"PhosRangePhiMin", {230.f}, "Phos range angle phi min"}, + PhosRangePhiMax{"PhosRangePhiMax", {330.f}, "Phos range angle phi max"}, + eeMassMin{"eeMassMin", {2.9f}, "J/psi(e+e-) Mass corridor lower limit (for Chic selection)"}, + eeMassMax{"eeMassMax", {3.3f}, "J/psi(e+e-) Mass corridor upper limit (for Chic selection)"}, + JpsiMass{"JpsiMass", {3.097f}, "J/psi Mass constant"}, + mMassSpectrumLowerCutoff{"mMassSpectrumLowerCutoff", {0.01f}, "Used to exclude 0+0 masses"}, + mShowerShapeCutValue{"mShowerShapeCutValue", 4.f, "Cut threshold for testLambda shower shape"}; + + Configurable mEvSelTrig{"mEvSelTrig", kTVXinPHOS, "Select events with this trigger"}, + CentBinning{"CentBinning", 10, "Binning for centrality"}, + CentEst{"CentEst", 1, "Centrality estimator, 0: FV0A, 1: FT0M, 2: FT0A, 3: FT0C, 4: FDDM, 5: NTPV"}, + MassBinning{"MassBinning", 1000, "Binning for mass"}, + EnergyBinning{"EnergyBinning", 100, "Binning for energy"}, + mMinCluNcell{"minCluNcell", 3, "min cells in cluster"}; + + Service ccdb; + double bz{0.}; + 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{3, 0, +3, ""}, + axisCent{CentBinning, 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{EnergyBinning, 0, 10, "E (GeV)", "E (GeV)"}, + axisMassSpectrum{MassBinning, MassSpectraJpsiMin, MassSpectraJpsiMax, "M (GeV/c^{2})", "Mass e^{+}e^{-} (GeV/c^{2})"}, + axisMassSpectrumChiC{MassBinning, MassSpectraChicMin, MassSpectraChicMax, "M (GeV/c^{2})", "Mass e^{+}e^{-}#gamma (GeV/c^{2})"}, + axisMassSpectrumChiCNoJpsiErrors{MassBinning, MassSpectraChicMin, MassSpectraChicMax, "M (GeV/c^{2})", "Mass e^{+}e^{-}#gamma - Mass e^{+}e^{-} + Mass J/#psi (GeV/c^{2})"}, + axisMassSpectrumgammagamma{MassBinning, 0, 0.3, "M (GeV/c^{2})", "Mass #gamma#gamma (GeV/c^{2})"}, + axisTPC{1000, 0, 200, "TPC signal (dE/dx)"}, + axisTOF{1000, 0, 50000, "TOF signal (ps)"}, + axisPt{momentumBinning, "p_{T} (GeV/c)"}, + axisPtProbe{momentumBinning, "Probe 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("centCounter", "centCounter", kTH1F, {axisCent}); + + mHistManager.add("PID_collection/h_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("PID_collection/h_MS_mm_v_pt_v_cent", "Mass e^{-}e^{-} vs momentum e^{-}e^{-} (from TPC candidates)", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("PID_collection/h_MS_pp_v_pt_v_cent", "Mass e^{+}e^{+} vs momentum e^{+}e^{+} (from TPC candidates)", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + + mHistManager.add("PID_collection/h_MS_mp_kTVXinPHOS_v_pt_v_cent", "TVXinPHOS | Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp} (from TPC candidates)", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("PID_collection/h_MS_mm_kTVXinPHOS_v_pt_v_cent", "TVXinPHOS | Mass e^{-}e^{-} vs momentum e^{-}e^{-} (from TPC candidates)", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("PID_collection/h_MS_pp_kTVXinPHOS_v_pt_v_cent", "TVXinPHOS | Mass e^{+}e^{+} vs momentum e^{+}e^{+} (from TPC candidates)", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + + mHistManager.add("PID_collection/h_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("PID_collection/h_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("PID_collection/h_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("PID_collection/h_MS_mp_phosRange_kTVXinPHOS_v_pt_v_cent", "TVXinPHOS | 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("PID_collection/h_MS_mm_phosRange_kTVXinPHOS_v_pt_v_cent", "TVXinPHOS | Mass e^{-}e^{-} vs momentum e^{-}e^{-} (from TPC candidates) with one e in phos acceptance range", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add("PID_collection/h_MS_pp_phosRange_kTVXinPHOS_v_pt_v_cent", "TVXinPHOS | Mass e^{+}e^{+} vs momentum e^{+}e^{+} (from TPC candidates) with one e in phos acceptance range", HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + + mHistManager.add("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_MS_v_cluE_v_cent", "Mass e^{#pm}e^{#mp}#gamma vs cluster Energy left by the photon", HistType::kTH3F, {axisMassSpectrumChiC, axisE, axisCent}); + + mHistManager.add("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_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("TPCeePhosGamma/h_minusee_MS_v_cluE_v_cent", "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("twoPhoton/MS_noCuts", "Mass vs Transverse Momentum for #gamma#gamma", HistType::kTH3F, {axisMassSpectrumgammagamma, axisPt, axisCent}); + mHistManager.add("twoPhoton/MS_noMatches", "Mass vs Transverse Momentum for #gamma#gamma excluding trackmatched clusters", HistType::kTH3F, {axisMassSpectrumgammagamma, axisPt, axisCent}); + + mHistManager.add("TPCeff/h_eh_pp_mass_spectra_v_pt_v_cent", "Mass e^{+}h^{+} vs momentum e^{+}h^{+}", HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add("TPCeff/h_ee_pp_mass_spectra_v_pt_v_cent", "Mass e^{+}e^{+} vs momentum e^{+}e^{+}", HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add("TPCeff/h_eh_mm_mass_spectra_v_pt_v_cent", "Mass e^{-}h^{-} vs momentum e^{-}h^{-}", HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add("TPCeff/h_ee_mm_mass_spectra_v_pt_v_cent", "Mass e^{-}e^{-} vs momentum e^{-}e^{-}", HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add("TPCeff/h_eh_mp_mass_spectra_v_pt_v_cent", "Mass e^{#pm}h^{#mp} vs momentum e^{#pm}h^{#mp}", HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add("TPCeff/h_ee_mp_mass_spectra_v_pt_v_cent", "Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp}", HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + + mHistManager.add("PID_crosscheck/hTPCspectra_TOFcut", "TPC spectra after TOF cut", HistType::kTH2F, {axisPt, axisTPC}); + mHistManager.add("PID_crosscheck/hTOFspectra_TPCcut", "TOF spectra after TPC cut", HistType::kTH2F, {axisPt, axisTOF}); + mHistManager.add("PID_crosscheck/hTPCspectra_TOFcutOnly", "TPC spectra after TOF cut (no hadron rejection)", HistType::kTH2F, {axisPt, axisTPC}); + mHistManager.add("PID_crosscheck/hTOFspectra_TPCcutOnly", "TOF spectra after TPC cut (no hadron rejection)", HistType::kTH2F, {axisPt, axisTOF}); + const char* categories[] = {"Inclusive", "PID", "True", "PID_and_True"}; + const char* titles[] = {"Inclusive", "PID selected", "True electron", "PID and True"}; + const int nDataCategories = 2; // "Inclusive" and "PID" for data and MC + for (int i = 0; i < nDataCategories; ++i) { + mHistManager.add(Form("%s/hTrackPt", categories[i]), Form("%s Track pt", titles[i]), HistType::kTH1F, {axisPtBig}); + mHistManager.add(Form("%s/hTPCspectra", categories[i]), Form("%s TPC dE/dx spectra", titles[i]), HistType::kTH2F, {axisPt, axisTPC}); + mHistManager.add(Form("%s/hTOFspectra", categories[i]), Form("%s TOF signal spectra", titles[i]), HistType::kTH2F, {axisPt, axisTOF}); + + mHistManager.add(Form("%s/h_MS_mp_v_pt_v_cent", categories[i]), Form("%s Mass e^{#pm}e^{#mp} vs momentum", titles[i]), HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add(Form("%s/h_MS_mm_v_pt_v_cent", categories[i]), Form("%s Mass e^{-}e^{-} vs momentum", titles[i]), HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add(Form("%s/h_MS_pp_v_pt_v_cent", categories[i]), Form("%s Mass e^{+}e^{+} vs momentum", titles[i]), HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + } + if (isMC) { + for (std::size_t i = nDataCategories; i < std::size(categories); ++i) { // "True" and "PID_and_True" for MC only + mHistManager.add(Form("%s/hTrackPt", categories[i]), Form("%s Track pt", titles[i]), HistType::kTH1F, {axisPtBig}); + mHistManager.add(Form("%s/hTPCspectra", categories[i]), Form("%s TPC dE/dx spectra", titles[i]), HistType::kTH2F, {axisPt, axisTPC}); + mHistManager.add(Form("%s/hTOFspectra", categories[i]), Form("%s TOF signal spectra", titles[i]), HistType::kTH2F, {axisPt, axisTOF}); + + mHistManager.add(Form("%s/h_MS_mp_v_pt_v_cent", categories[i]), Form("%s Mass e^{#pm}e^{#mp} vs momentum", titles[i]), HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add(Form("%s/h_MS_mm_v_pt_v_cent", categories[i]), Form("%s Mass e^{-}e^{-} vs momentum", titles[i]), HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + mHistManager.add(Form("%s/h_MS_pp_v_pt_v_cent", categories[i]), Form("%s Mass e^{+}e^{+} vs momentum", titles[i]), HistType::kTH3F, {axisMassSpectrum, axisPt, axisCent}); + } + mHistManager.add("PID_crosscheck/hTPCspectra_TOFcut_True", "TPC spectra after TOF cut (True Electrons)", HistType::kTH2F, {axisPt, axisTPC}); + mHistManager.add("PID_crosscheck/hTOFspectra_TPCcut_True", "TOF spectra after TPC cut (True Electrons)", HistType::kTH2F, {axisPt, axisTOF}); + mHistManager.add("PID_crosscheck/hTPCspectra_TOFcutOnly_True", "TPC spectra after TOF cut (no hadron rejection, True El)", HistType::kTH2F, {axisPt, axisTPC}); + mHistManager.add("PID_crosscheck/hTOFspectra_TPCcutOnly_True", "TOF spectra after TPC cut (no hadron rejection, True El)", HistType::kTH2F, {axisPt, axisTOF}); + + const char* effCategories[] = {"PID", "True", "PID_and_True"}; + const char* effTitles[] = {"PID Tag", "True Tag", "PID and True Tag"}; + + for (std::size_t i = 0; i < std::size(effCategories); ++i) { + mHistManager.add(Form("TPCeff/%s/h_eh_pp_mass_spectra_v_pt_v_cent", effCategories[i]), Form("Mass e^{+}h^{+} vs momentum e^{+}h^{+} (%s)", effTitles[i]), HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add(Form("TPCeff/%s/h_ee_pp_mass_spectra_v_pt_v_cent", effCategories[i]), Form("Mass e^{+}e^{+} vs momentum e^{+}e^{+} (%s)", effTitles[i]), HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add(Form("TPCeff/%s/h_eh_mm_mass_spectra_v_pt_v_cent", effCategories[i]), Form("Mass e^{-}h^{-} vs momentum e^{-}h^{-} (%s)", effTitles[i]), HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add(Form("TPCeff/%s/h_ee_mm_mass_spectra_v_pt_v_cent", effCategories[i]), Form("Mass e^{-}e^{-} vs momentum e^{-}e^{-} (%s)", effTitles[i]), HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add(Form("TPCeff/%s/h_eh_mp_mass_spectra_v_pt_v_cent", effCategories[i]), Form("Mass e^{#pm}h^{#mp} vs momentum e^{#pm}h^{#mp} (%s)", effTitles[i]), HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + mHistManager.add(Form("TPCeff/%s/h_ee_mp_mass_spectra_v_pt_v_cent", effCategories[i]), Form("Mass e^{#pm}e^{#mp} vs momentum e^{#pm}e^{#mp} (%s)", effTitles[i]), HistType::kTH3F, {axisMassSpectrum, axisPtProbe, axisCent}); + } + } + } + + void processData(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()) > mColMaxZ) + return; + + float cent = -1.; + switch (CentEst) { + 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; + } + mHistManager.fill(HIST("eventCounter"), 0.5); + mHistManager.fill(HIST("centCounter"), cent); + if ((isMC || collision.alias_bit(mEvSelTrig))) { + mHistManager.fill(HIST("eventCounter"), 1.5); + } + if (isSel8) { + if (!collision.sel8()) + return; + mHistManager.fill(HIST("eventCounter"), 2.5); + } + + auto isGoodForReconstruction = [&](auto const& track) -> bool { + if (!track.has_collision() || !track.hasTPC()) + return false; + if (track.pt() <= PtMin || track.pt() >= PtMax) + return false; + if (std::fabs(track.eta()) >= EtaMax) + return false; + if (std::fabs(track.dcaXY()) >= DCAxyMax) + return false; + if (std::fabs(track.dcaZ()) >= DCAzMax) + return false; + if (track.itsChi2NCl() >= ITSchi2Max) + return false; + if (track.tpcChi2NCl() >= TPCchi2Max) + return false; + if (!((track.itsClusterMap() & uint8_t(1)) > 0)) + return false; + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax) + return false; + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + return false; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) + return false; + return true; + }; + + auto isGoodElectronPID = [&](auto const& track) -> bool { + bool isTPCElectron = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool isTOFElectron = track.hasTOF() && (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + if (!isTPCElectron && !isTOFElectron) + return false; + + bool isPion = (track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax); + bool isKaon = (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax); + bool isProton = (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax); + if (isPion || isKaon || isProton) + return false; + return true; + }; + + for (auto const& track : tracks) { + if (!isGoodForReconstruction(track)) { + continue; + } + + mHistManager.fill(HIST("Inclusive/hTrackPt"), track.pt()); + mHistManager.fill(HIST("Inclusive/hTPCspectra"), track.pt(), track.tpcSignal()); + if (track.hasTOF()) { + mHistManager.fill(HIST("Inclusive/hTOFspectra"), track.pt(), track.tofSignal()); + } + if (isGoodElectronPID(track)) { + mHistManager.fill(HIST("PID/hTrackPt"), track.pt()); + mHistManager.fill(HIST("PID/hTPCspectra"), track.pt(), track.tpcSignal()); + if (track.hasTOF()) { + mHistManager.fill(HIST("PID/hTOFspectra"), track.pt(), track.tofSignal()); + } + } + + // Logic for PID cross-check histograms + bool tpcE = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool tofE = track.hasTOF() && (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + bool noHadrons = !((track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax) || (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax) || (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax)); + + if (tofE) { + mHistManager.fill(HIST("PID_crosscheck/hTPCspectra_TOFcutOnly"), track.pt(), track.tpcSignal()); + if (noHadrons) { + mHistManager.fill(HIST("PID_crosscheck/hTPCspectra_TOFcut"), track.pt(), track.tpcSignal()); + } + } + + if (tpcE) { + if (track.hasTOF()) { + mHistManager.fill(HIST("PID_crosscheck/hTOFspectra_TPCcutOnly"), track.pt(), track.tofSignal()); + if (noHadrons) { + mHistManager.fill(HIST("PID_crosscheck/hTOFspectra_TPCcut"), track.pt(), track.tofSignal()); + } + } + } + } + + auto isGoodElectronForSignal = [&](const MyTracks::iterator& track) -> bool { + if (!track.has_collision() || !track.hasTPC()) + return false; + if (track.pt() <= PtMin || track.pt() >= PtMax) + return false; + if (std::fabs(track.eta()) >= EtaMax) + return false; + if (std::fabs(track.dcaXY()) >= DCAxyMax) + return false; + if (std::fabs(track.dcaZ()) >= DCAzMax) + return false; + if (track.itsChi2NCl() >= ITSchi2Max) + return false; + if (track.tpcChi2NCl() >= TPCchi2Max) + return false; + if (!((track.itsClusterMap() & uint8_t(1)) > 0)) + return false; + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax) + return false; + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + return false; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) + return false; + + bool isTPCElectron = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool isTOFElectron = (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + if (!isTPCElectron && !isTOFElectron) + return false; + + bool isPion = (track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax); + bool isKaon = (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax); + bool isProton = (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax); + if (isPion || isKaon || isProton) + return false; + return true; + }; + + auto isGoodTagElectron = [&](const MyTracks::iterator& track) -> bool { + if (!track.has_collision() || !track.hasTPC()) + return false; + if (!((track.itsClusterMap() & uint8_t(1)) > 0)) + return false; + if (track.itsChi2NCl() > ITSchi2Max || track.tpcChi2NCl() > TPCchi2Max) + return false; + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax) + return false; + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + return false; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) + return false; + if (std::fabs(track.eta()) >= EtaMax) + return false; + if (std::fabs(track.dcaXY()) >= DCAxyMax) + return false; + if (std::fabs(track.dcaZ()) >= DCAzMax) + return false; + + bool isTPCElectron = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool isTOFElectron = (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + if (!isTPCElectron && !isTOFElectron) + return false; + + bool isPionSignal = (track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax); + bool isKaonSignal = (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax); + bool isProtonSignal = (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax); + if (isPionSignal || isKaonSignal || isProtonSignal) + return false; + return true; + }; + + auto isGoodProbeBaseTrack = [&](const MyTracks::iterator& track) -> bool { + if (!track.has_collision() || !track.hasTPC()) + return false; + if (!((track.itsClusterMap() & uint8_t(1)) > 0)) + return false; + if (track.itsChi2NCl() > ITSchi2Max || track.tpcChi2NCl() > TPCchi2Max) + return false; + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax) + return false; + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + return false; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) + return false; + if (std::fabs(track.dcaXY()) > DCAxyMax || std::fabs(track.dcaZ()) > DCAzMax) + return false; + if (std::fabs(track.eta()) >= EtaMax) + return false; + return true; + }; + + auto isProbeIdentifiedAsElectron = [&](const MyTracks::iterator& track) -> bool { + if (!track.hasTPC()) + return false; + bool isTPCElectron = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool isTOFElectron = (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + if (!isTPCElectron && !isTOFElectron) + return false; + + bool isPionSignal = (track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax); + bool isKaonSignal = (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax); + bool isProtonSignal = (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax); + if (isPionSignal || isKaonSignal || isProtonSignal) + return false; + return true; + }; + + for (auto const& [track1_iterator, track2_iterator] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + if (track1_iterator.collisionId() != track2_iterator.collisionId()) { + continue; + } + + bool track1IsSignalE = isGoodElectronForSignal(track1_iterator); + bool track2IsSignalE = isGoodElectronForSignal(track2_iterator); + + if (track1IsSignalE && track2IsSignalE) { + ROOT::Math::LorentzVector> fourVectorP1, fourVectorP2; + fourVectorP1.SetPxPyPzE(track1_iterator.px(), track1_iterator.py(), track1_iterator.pz(), track1_iterator.energy(0)); + fourVectorP2.SetPxPyPzE(track2_iterator.px(), track2_iterator.py(), track2_iterator.pz(), track2_iterator.energy(0)); + + bool inPhosEtaRange1 = std::fabs(track1_iterator.eta()) < PhosRangeEta; + bool inPhosEtaRange2 = std::fabs(track2_iterator.eta()) < PhosRangeEta; + bool inPhosPhiRange1 = (track1_iterator.phi() * TMath::RadToDeg() > PhosRangePhiMin && track1_iterator.phi() * TMath::RadToDeg() < PhosRangePhiMax); + bool inPhosPhiRange2 = (track2_iterator.phi() * TMath::RadToDeg() > PhosRangePhiMin && track2_iterator.phi() * TMath::RadToDeg() < PhosRangePhiMax); + bool inPhosRange = (inPhosEtaRange1 && inPhosPhiRange1) || (inPhosEtaRange2 && inPhosPhiRange2); + + double pairMass = (fourVectorP1 + fourVectorP2).M(), pairPt = (fourVectorP1 + fourVectorP2).Pt(); + + if (track1_iterator.sign() == track2_iterator.sign()) { + bool track1IsPositive = track1_iterator.sign() * bz > 0; + if (track1IsPositive) { + mHistManager.fill(HIST("PID_collection/h_MS_pp_v_pt_v_cent"), pairMass, pairPt, cent); + if ((isMC || collision.alias_bit(mEvSelTrig))) + mHistManager.fill(HIST("PID_collection/h_MS_pp_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + if (inPhosRange) { + mHistManager.fill(HIST("PID_collection/h_MS_pp_phosRange_v_pt_v_cent"), pairMass, pairPt, cent); + if ((isMC || collision.alias_bit(mEvSelTrig))) + mHistManager.fill(HIST("PID_collection/h_MS_pp_phosRange_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + } + } else { + mHistManager.fill(HIST("PID_collection/h_MS_mm_v_pt_v_cent"), pairMass, pairPt, cent); + if ((isMC || collision.alias_bit(mEvSelTrig))) + mHistManager.fill(HIST("PID_collection/h_MS_mm_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + if (inPhosRange) { + mHistManager.fill(HIST("PID_collection/h_MS_mm_phosRange_v_pt_v_cent"), pairMass, pairPt, cent); + if ((isMC || collision.alias_bit(mEvSelTrig))) + mHistManager.fill(HIST("PID_collection/h_MS_mm_phosRange_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + } + } + } else { + mHistManager.fill(HIST("PID_collection/h_MS_mp_v_pt_v_cent"), pairMass, pairPt, cent); + if ((isMC || collision.alias_bit(mEvSelTrig))) + mHistManager.fill(HIST("PID_collection/h_MS_mp_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + if (inPhosRange) { + mHistManager.fill(HIST("PID_collection/h_MS_mp_phosRange_v_pt_v_cent"), pairMass, pairPt, cent); + if ((isMC || collision.alias_bit(mEvSelTrig))) + mHistManager.fill(HIST("PID_collection/h_MS_mp_phosRange_kTVXinPHOS_v_pt_v_cent"), pairMass, pairPt, cent); + } + + if ((isMC || 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 = false; + bool isJpsi = (pairMass > eeMassMin && pairMass < eeMassMax); + bool isDispOK = false; + if (mSwapM20M02ForTestLambda) + isDispOK = testLambda(cluE, gamma.m02(), gamma.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOK = testLambda(cluE, gamma.m20(), gamma.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); + for (auto const& match : matches) { + if (gamma.index() == match.caloClusterId()) { + matchFlag = true; + break; + } + } + ROOT::Math::LorentzVector> fourVectorP3; + fourVectorP3.SetPxPyPzE(gamma.px(), gamma.py(), gamma.pz(), cluE); + double tripletMass = (fourVectorP1 + fourVectorP2 + fourVectorP3).M(); + double tripletPt = (fourVectorP1 + fourVectorP2 + fourVectorP3).Pt(); + double tripletMinusPairPlusJpsiMass = tripletMass - pairMass + JpsiMass; + + mHistManager.fill(HIST("TPCeePhosGamma/h_MS_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_minusee_MS_v_3pt_v_cent"), tripletMinusPairPlusJpsiMass, tripletPt, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_MS_v_cluE_v_cent"), tripletMass, cluE, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_minusee_MS_v_cluE_v_cent"), tripletMinusPairPlusJpsiMass, cluE, cent); + + if (!matchFlag) { + mHistManager.fill(HIST("TPCeePhosGamma/h_MS_noMatches_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_minusee_MS_noMatches_v_3pt_v_cent"), tripletMinusPairPlusJpsiMass, tripletPt, cent); + if (isJpsi) { + mHistManager.fill(HIST("TPCeePhosGamma/h_MS_noMatches_aroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_minusee_MS_noMatches_aroundJpsi_v_3pt_v_cent"), tripletMinusPairPlusJpsiMass, tripletPt, cent); + if (isDispOK) { + mHistManager.fill(HIST("TPCeePhosGamma/h_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_minusee_MS_noMatches_aroundJpsi_DispOK_v_3pt_v_cent"), tripletMinusPairPlusJpsiMass, tripletPt, cent); + } + } + if (isDispOK) { + mHistManager.fill(HIST("TPCeePhosGamma/h_MS_noMatches_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_minusee_MS_noMatches_DispOK_v_3pt_v_cent"), tripletMinusPairPlusJpsiMass, tripletPt, cent); + } + } + if (isJpsi) { + mHistManager.fill(HIST("TPCeePhosGamma/h_MS_aroundJpsi_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_minusee_MS_aroundJpsi_v_3pt_v_cent"), tripletMinusPairPlusJpsiMass, tripletPt, cent); + } + if (isDispOK) { + mHistManager.fill(HIST("TPCeePhosGamma/h_MS_DispOK_v_3pt_v_cent"), tripletMass, tripletPt, cent); + mHistManager.fill(HIST("TPCeePhosGamma/h_minusee_MS_DispOK_v_3pt_v_cent"), tripletMinusPairPlusJpsiMass, tripletPt, cent); + } + } + } + } + } + + if (isGoodTagElectron(track1_iterator) && isGoodProbeBaseTrack(track2_iterator)) { + ROOT::Math::LorentzVector> pTag1, pProbe2; + pTag1.SetPxPyPzE(track1_iterator.px(), track1_iterator.py(), track1_iterator.pz(), track1_iterator.energy(0)); + pProbe2.SetPxPyPzE(track2_iterator.px(), track2_iterator.py(), track2_iterator.pz(), track2_iterator.energy(0)); + float massTag1Probe2 = (pTag1 + pProbe2).M(); + float ptProbe2 = track2_iterator.pt(); + bool tag1IsPositive = track1_iterator.sign() * bz > 0; + + if (track1_iterator.sign() == track2_iterator.sign()) { + if (tag1IsPositive) { + mHistManager.fill(HIST("TPCeff/h_eh_pp_mass_spectra_v_pt_v_cent"), massTag1Probe2, ptProbe2, cent); + } else { + mHistManager.fill(HIST("TPCeff/h_eh_mm_mass_spectra_v_pt_v_cent"), massTag1Probe2, ptProbe2, cent); + } + } else { + mHistManager.fill(HIST("TPCeff/h_eh_mp_mass_spectra_v_pt_v_cent"), massTag1Probe2, ptProbe2, cent); + } + if (isProbeIdentifiedAsElectron(track2_iterator)) { + if (track1_iterator.sign() == track2_iterator.sign()) { + if (tag1IsPositive) { + mHistManager.fill(HIST("TPCeff/h_ee_pp_mass_spectra_v_pt_v_cent"), massTag1Probe2, ptProbe2, cent); + } else { + mHistManager.fill(HIST("TPCeff/h_ee_mm_mass_spectra_v_pt_v_cent"), massTag1Probe2, ptProbe2, cent); + } + } else { + mHistManager.fill(HIST("TPCeff/h_ee_mp_mass_spectra_v_pt_v_cent"), massTag1Probe2, ptProbe2, cent); + } + } + } + + if (isGoodTagElectron(track2_iterator) && isGoodProbeBaseTrack(track1_iterator)) { + ROOT::Math::LorentzVector> pTag2, pProbe1; + pTag2.SetPxPyPzE(track2_iterator.px(), track2_iterator.py(), track2_iterator.pz(), track2_iterator.energy(0)); + pProbe1.SetPxPyPzE(track1_iterator.px(), track1_iterator.py(), track1_iterator.pz(), track1_iterator.energy(0)); + float massTag2Probe1 = (pTag2 + pProbe1).M(); + float ptProbe1 = track1_iterator.pt(); + bool tag2IsPositive = track2_iterator.sign() * bz > 0; + + if (track2_iterator.sign() == track1_iterator.sign()) { + if (tag2IsPositive) { + mHistManager.fill(HIST("TPCeff/h_eh_pp_mass_spectra_v_pt_v_cent"), massTag2Probe1, ptProbe1, cent); + } else { + mHistManager.fill(HIST("TPCeff/h_eh_mm_mass_spectra_v_pt_v_cent"), massTag2Probe1, ptProbe1, cent); + } + } else { + mHistManager.fill(HIST("TPCeff/h_eh_mp_mass_spectra_v_pt_v_cent"), massTag2Probe1, ptProbe1, cent); + } + if (isProbeIdentifiedAsElectron(track1_iterator)) { + if (track2_iterator.sign() == track1_iterator.sign()) { + if (tag2IsPositive) { + mHistManager.fill(HIST("TPCeff/h_ee_pp_mass_spectra_v_pt_v_cent"), massTag2Probe1, ptProbe1, cent); + } else { + mHistManager.fill(HIST("TPCeff/h_ee_mm_mass_spectra_v_pt_v_cent"), massTag2Probe1, ptProbe1, cent); + } + } else { + mHistManager.fill(HIST("TPCeff/h_ee_mp_mass_spectra_v_pt_v_cent"), massTag2Probe1, ptProbe1, cent); + } + } + } + } + + for (auto const& gamma1 : clusters) { + float cluE1 = gamma1.e(); + if (cluE1 < mMinCluE || gamma1.ncell() < mMinCluNcell || gamma1.time() > mMaxCluTime || gamma1.time() < mMinCluTime) + continue; + bool matchFlag1 = false; + + bool isDispOKClu1 = false; + if (mSwapM20M02ForTestLambda) + isDispOKClu1 = testLambda(cluE1, gamma1.m02(), gamma1.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOKClu1 = testLambda(cluE1, gamma1.m20(), gamma1.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); + if (!isDispOKClu1) + continue; + for (auto const& match : matches) { + if (gamma1.index() == match.caloClusterId()) { + matchFlag1 = true; + break; + } + } + for (auto const& gamma2 : clusters) { + if (gamma1.index() >= gamma2.index()) + continue; + float cluE2 = gamma2.e(); + if (cluE2 < mMinCluE || gamma2.ncell() < mMinCluNcell || gamma2.time() > mMaxCluTime || gamma2.time() < mMinCluTime) + continue; + bool isDispOKClu2 = false; + if (mSwapM20M02ForTestLambda) + isDispOKClu2 = testLambda(cluE2, gamma2.m02(), gamma2.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOKClu2 = testLambda(cluE2, gamma2.m20(), gamma2.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); + if (!isDispOKClu2) + continue; + bool matchFlag2 = false; + for (auto const& match : matches) { + if (gamma2.index() == match.caloClusterId()) { + matchFlag2 = true; + break; + } + } + ROOT::Math::LorentzVector> fourVectorG1, fourVectorG2; + fourVectorG1.SetPxPyPzE(gamma1.px(), gamma1.py(), gamma1.pz(), cluE1); + fourVectorG2.SetPxPyPzE(gamma2.px(), gamma2.py(), gamma2.pz(), cluE2); + double pairMassGG = (fourVectorG1 + fourVectorG2).M(); + double pairPtGG = (fourVectorG1 + fourVectorG2).Pt(); + + if (pairMassGG < mMassSpectrumLowerCutoff) + continue; + + mHistManager.fill(HIST("twoPhoton/MS_noCuts"), pairMassGG, pairPtGG, cent); + if (matchFlag1 || matchFlag2) + continue; + mHistManager.fill(HIST("twoPhoton/MS_noMatches"), pairMassGG, pairPtGG, cent); + } + } + } + PROCESS_SWITCH(TpcElIdMassSpectrum, processData, "process data", false); + + void processMC(SelCollisions::iterator const& collision, + aod::CaloClusters const& clusters, + soa::Join const& tracks, + o2::aod::PHOSMatchindexTable const& matches, + aod::McParticles const& mcParticles, + 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()) > mColMaxZ) + return; + + float cent = -1.; + switch (CentEst) { + 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; + } + mHistManager.fill(HIST("eventCounter"), 0.5); + mHistManager.fill(HIST("centCounter"), cent); + if ((isMC || collision.alias_bit(mEvSelTrig))) { + mHistManager.fill(HIST("eventCounter"), 1.5); + } + if (isSel8) { + if (!collision.sel8()) + return; + mHistManager.fill(HIST("eventCounter"), 2.5); + } + + auto isGoodForReconstruction = [&](auto const& track) -> bool { + if (!track.has_collision() || !track.hasTPC()) + return false; + if (track.pt() <= PtMin || track.pt() >= PtMax) + return false; + if (std::fabs(track.eta()) >= EtaMax) + return false; + if (std::fabs(track.dcaXY()) >= DCAxyMax) + return false; + if (std::fabs(track.dcaZ()) >= DCAzMax) + return false; + if (track.itsChi2NCl() >= ITSchi2Max) + return false; + if (track.tpcChi2NCl() >= TPCchi2Max) + return false; + if (!((track.itsClusterMap() & uint8_t(1)) > 0)) + return false; + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax) + return false; + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + return false; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) + return false; + return true; + }; + + auto isGoodElectronPID = [&](auto const& track) -> bool { + bool isTPCElectron = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool isTOFElectron = track.hasTOF() && (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + if (!isTPCElectron && !isTOFElectron) + return false; + + bool isPion = (track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax); + bool isKaon = (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax); + bool isProton = (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax); + if (isPion || isKaon || isProton) + return false; + return true; + }; + + auto isTrueElectron = [&](auto const& track) -> bool { + auto mcLabel = track.mcParticleId(); + if (mcLabel > -1 && mcLabel < mcParticles.size()) { + auto mcpart = mcParticles.iteratorAt(mcLabel); + if (std::abs(mcpart.pdgCode()) == PDG_t::kElectron) { + return true; + } + } + return false; + }; + + auto isGoodTagElectron = [&](auto const& track) -> bool { + if (!track.has_collision() || !track.hasTPC()) + return false; + if (!((track.itsClusterMap() & uint8_t(1)) > 0)) + return false; + if (track.itsChi2NCl() > ITSchi2Max || track.tpcChi2NCl() > TPCchi2Max) + return false; + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax) + return false; + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + return false; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) + return false; + if (std::fabs(track.eta()) >= EtaMax) + return false; + if (std::fabs(track.dcaXY()) >= DCAxyMax) + return false; + if (std::fabs(track.dcaZ()) >= DCAzMax) + return false; + + bool isTPCElectron = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool isTOFElectron = (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + if (!isTPCElectron && !isTOFElectron) + return false; + + bool isPionSignal = (track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax); + bool isKaonSignal = (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax); + bool isProtonSignal = (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax); + if (isPionSignal || isKaonSignal || isProtonSignal) + return false; + return true; + }; + + auto isGoodProbeBaseTrack = [&](auto const& track) -> bool { + if (!track.has_collision() || !track.hasTPC()) + return false; + if (!((track.itsClusterMap() & uint8_t(1)) > 0)) + return false; + if (track.itsChi2NCl() > ITSchi2Max || track.tpcChi2NCl() > TPCchi2Max) + return false; + if (track.itsNCls() < ITSnclsMin || track.itsNCls() > ITSnclsMax) + return false; + if (track.tpcNClsFound() < TPCnclsMin || track.tpcNClsFound() > TPCnclsMax) + return false; + if (track.tpcNClsCrossedRows() < TPCnclsCRMin || track.tpcNClsCrossedRows() > TPCnclsCRMax) + return false; + if (std::fabs(track.dcaXY()) > DCAxyMax || std::fabs(track.dcaZ()) > DCAzMax) + return false; + if (std::fabs(track.eta()) >= EtaMax) + return false; + return true; + }; + + auto isProbeIdentifiedAsElectron = [&](auto const& track) -> bool { + if (!track.hasTPC()) + return false; + bool isTPCElectron = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool isTOFElectron = track.hasTOF() && (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + if (!isTPCElectron && !isTOFElectron) + return false; + + bool isPionSignal = (track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax); + bool isKaonSignal = (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax); + bool isProtonSignal = (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax); + if (isPionSignal || isKaonSignal || isProtonSignal) + return false; + return true; + }; + + for (auto const& track : tracks) { + if (!isGoodForReconstruction(track)) { + continue; + } + bool pid = isGoodElectronPID(track); + bool trueE = isTrueElectron(track); + + mHistManager.fill(HIST("Inclusive/hTrackPt"), track.pt()); + mHistManager.fill(HIST("Inclusive/hTPCspectra"), track.pt(), track.tpcSignal()); + if (track.hasTOF()) { + mHistManager.fill(HIST("Inclusive/hTOFspectra"), track.pt(), track.tofSignal()); + } + + if (pid) { + mHistManager.fill(HIST("PID/hTrackPt"), track.pt()); + mHistManager.fill(HIST("PID/hTPCspectra"), track.pt(), track.tpcSignal()); + if (track.hasTOF()) { + mHistManager.fill(HIST("PID/hTOFspectra"), track.pt(), track.tofSignal()); + } + } + + if (trueE) { + mHistManager.fill(HIST("True/hTrackPt"), track.pt()); + mHistManager.fill(HIST("True/hTPCspectra"), track.pt(), track.tpcSignal()); + if (track.hasTOF()) { + mHistManager.fill(HIST("True/hTOFspectra"), track.pt(), track.tofSignal()); + } + } + + if (pid && trueE) { + mHistManager.fill(HIST("PID_and_True/hTrackPt"), track.pt()); + mHistManager.fill(HIST("PID_and_True/hTPCspectra"), track.pt(), track.tpcSignal()); + if (track.hasTOF()) { + mHistManager.fill(HIST("PID_and_True/hTOFspectra"), track.pt(), track.tofSignal()); + } + } + + // Logic for PID cross-check histograms + bool tpcE = (track.tpcNSigmaEl() > TPCNSigmaElMin) && (track.tpcNSigmaEl() < TPCNSigmaElMax); + bool tofE = track.hasTOF() && (track.tofNSigmaEl() > TOFNSigmaElMin) && (track.tofNSigmaEl() < TOFNSigmaElMax); + bool noHadrons = !((track.tpcNSigmaPi() >= TPCNSigmaPiMin && track.tpcNSigmaPi() <= TPCNSigmaPiMax) || (track.tpcNSigmaKa() >= TPCNSigmaKaMin && track.tpcNSigmaKa() <= TPCNSigmaKaMax) || (track.tpcNSigmaPr() >= TPCNSigmaPrMin && track.tpcNSigmaPr() <= TPCNSigmaPrMax)); + + if (tofE) { + mHistManager.fill(HIST("PID_crosscheck/hTPCspectra_TOFcutOnly"), track.pt(), track.tpcSignal()); + if (trueE) { + mHistManager.fill(HIST("PID_crosscheck/hTPCspectra_TOFcutOnly_True"), track.pt(), track.tpcSignal()); + } + if (noHadrons) { + mHistManager.fill(HIST("PID_crosscheck/hTPCspectra_TOFcut"), track.pt(), track.tpcSignal()); + if (trueE) { + mHistManager.fill(HIST("PID_crosscheck/hTPCspectra_TOFcut_True"), track.pt(), track.tpcSignal()); + } + } + } + + if (tpcE) { + if (track.hasTOF()) { + mHistManager.fill(HIST("PID_crosscheck/hTOFspectra_TPCcutOnly"), track.pt(), track.tofSignal()); + if (trueE) { + mHistManager.fill(HIST("PID_crosscheck/hTOFspectra_TPCcutOnly_True"), track.pt(), track.tofSignal()); + } + if (noHadrons) { + mHistManager.fill(HIST("PID_crosscheck/hTOFspectra_TPCcut"), track.pt(), track.tofSignal()); + if (trueE) { + mHistManager.fill(HIST("PID_crosscheck/hTOFspectra_TPCcut_True"), track.pt(), track.tofSignal()); + } + } + } + } + } + + for (auto const& [track1_iterator, track2_iterator] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + if (track1_iterator.collisionId() != track2_iterator.collisionId()) { + continue; + } + + bool isInclusive1 = isGoodForReconstruction(track1_iterator); + bool isInclusive2 = isGoodForReconstruction(track2_iterator); + bool pid1 = isGoodElectronPID(track1_iterator); + bool pid2 = isGoodElectronPID(track2_iterator); + bool true1 = isTrueElectron(track1_iterator); + bool true2 = isTrueElectron(track2_iterator); + + ROOT::Math::LorentzVector> p1, p2; + p1.SetPxPyPzE(track1_iterator.px(), track1_iterator.py(), track1_iterator.pz(), track1_iterator.energy(0)); + p2.SetPxPyPzE(track2_iterator.px(), track2_iterator.py(), track2_iterator.pz(), track2_iterator.energy(0)); + double pairMass = (p1 + p2).M(); + double pairPt = (p1 + p2).Pt(); + + if (isInclusive1 && isInclusive2) { + if (track1_iterator.sign() != track2_iterator.sign()) { + mHistManager.fill(HIST("Inclusive/h_MS_mp_v_pt_v_cent"), pairMass, pairPt, cent); + } else if (track1_iterator.sign() * bz > 0) { + mHistManager.fill(HIST("Inclusive/h_MS_pp_v_pt_v_cent"), pairMass, pairPt, cent); + } else { + mHistManager.fill(HIST("Inclusive/h_MS_mm_v_pt_v_cent"), pairMass, pairPt, cent); + } + } + + if (isInclusive1 && isInclusive2 && pid1 && pid2) { + if (track1_iterator.sign() != track2_iterator.sign()) { + mHistManager.fill(HIST("PID/h_MS_mp_v_pt_v_cent"), pairMass, pairPt, cent); + } else if (track1_iterator.sign() * bz > 0) { + mHistManager.fill(HIST("PID/h_MS_pp_v_pt_v_cent"), pairMass, pairPt, cent); + } else { + mHistManager.fill(HIST("PID/h_MS_mm_v_pt_v_cent"), pairMass, pairPt, cent); + } + } + + if (isInclusive1 && isInclusive2 && true1 && true2) { + if (track1_iterator.sign() != track2_iterator.sign()) { + mHistManager.fill(HIST("True/h_MS_mp_v_pt_v_cent"), pairMass, pairPt, cent); + } else if (track1_iterator.sign() * bz > 0) { + mHistManager.fill(HIST("True/h_MS_pp_v_pt_v_cent"), pairMass, pairPt, cent); + } else { + mHistManager.fill(HIST("True/h_MS_mm_v_pt_v_cent"), pairMass, pairPt, cent); + } + } + + if (isInclusive1 && isInclusive2 && pid1 && pid2 && true1 && true2) { + if (track1_iterator.sign() != track2_iterator.sign()) { + mHistManager.fill(HIST("PID_and_True/h_MS_mp_v_pt_v_cent"), pairMass, pairPt, cent); + } else if (track1_iterator.sign() * bz > 0) { + mHistManager.fill(HIST("PID_and_True/h_MS_pp_v_pt_v_cent"), pairMass, pairPt, cent); + } else { + mHistManager.fill(HIST("PID_and_True/h_MS_mm_v_pt_v_cent"), pairMass, pairPt, cent); + } + } + + // Tag and probe logic + auto isTagPID = isGoodTagElectron; + auto isTagTrue = [&](auto const& track) { return isTrueElectron(track) && isGoodProbeBaseTrack(track); }; + auto isTagPIDandTrue = [&](auto const& track) { return isGoodTagElectron(track) && isTrueElectron(track); }; + + bool tag1IsPositive = track1_iterator.sign() * bz > 0; + bool tag2IsPositive = track2_iterator.sign() * bz > 0; + + // Symmetric tag and probe + const int nTagProbeSymmetries = 2; + for (int i = 0; i < nTagProbeSymmetries; ++i) { + auto& tag = (i == 0) ? track1_iterator : track2_iterator; + auto& probe = (i == 0) ? track2_iterator : track1_iterator; + bool tagIsPositive = (i == 0) ? tag1IsPositive : tag2IsPositive; + + float mass = (p1 + p2).M(); + float pt = probe.pt(); + + // --- PID tag --- + if (isTagPID(tag) && isGoodProbeBaseTrack(probe)) { + if (tag.sign() == probe.sign()) { + if (tagIsPositive) { + mHistManager.fill(HIST("TPCeff/PID/h_eh_pp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/PID/h_ee_pp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } else { + mHistManager.fill(HIST("TPCeff/PID/h_eh_mm_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/PID/h_ee_mm_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } + } else { + mHistManager.fill(HIST("TPCeff/PID/h_eh_mp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/PID/h_ee_mp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } + } + + // --- True tag --- + if (isTagTrue(tag) && isGoodProbeBaseTrack(probe)) { + if (tag.sign() == probe.sign()) { + if (tagIsPositive) { + mHistManager.fill(HIST("TPCeff/True/h_eh_pp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/True/h_ee_pp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } else { + mHistManager.fill(HIST("TPCeff/True/h_eh_mm_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/True/h_ee_mm_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } + } else { + mHistManager.fill(HIST("TPCeff/True/h_eh_mp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/True/h_ee_mp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } + } + + // --- PID and True tag --- + if (isTagPIDandTrue(tag) && isGoodProbeBaseTrack(probe)) { + if (tag.sign() == probe.sign()) { + if (tagIsPositive) { + mHistManager.fill(HIST("TPCeff/PID_and_True/h_eh_pp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/PID_and_True/h_ee_pp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } else { + mHistManager.fill(HIST("TPCeff/PID_and_True/h_eh_mm_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/PID_and_True/h_ee_mm_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } + } else { + mHistManager.fill(HIST("TPCeff/PID_and_True/h_eh_mp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + if (isProbeIdentifiedAsElectron(probe)) + mHistManager.fill(HIST("TPCeff/PID_and_True/h_ee_mp_mass_spectra_v_pt_v_cent"), mass, pt, cent); + } + } + } + } + + for (auto const& gamma1 : clusters) { + float cluE1 = gamma1.e(); + if (cluE1 < mMinCluE || gamma1.ncell() < mMinCluNcell || gamma1.time() > mMaxCluTime || gamma1.time() < mMinCluTime) + continue; + bool matchFlag1 = false; + + bool isDispOKClu1 = false; + if (mSwapM20M02ForTestLambda) + isDispOKClu1 = testLambda(cluE1, gamma1.m02(), gamma1.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOKClu1 = testLambda(cluE1, gamma1.m20(), gamma1.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); + if (!isDispOKClu1) + continue; + for (auto const& match : matches) { + if (gamma1.index() == match.caloClusterId()) { + matchFlag1 = true; + break; + } + } + for (auto const& gamma2 : clusters) { + if (gamma1.index() >= gamma2.index()) + continue; + float cluE2 = gamma2.e(); + if (cluE2 < mMinCluE || gamma2.ncell() < mMinCluNcell || gamma2.time() > mMaxCluTime || gamma2.time() < mMinCluTime) + continue; + bool isDispOKClu2 = false; + if (mSwapM20M02ForTestLambda) + isDispOKClu2 = testLambda(cluE2, gamma2.m02(), gamma2.m20(), mShowerShapeCutValue, mUseNegativeCrossTerm); + else + isDispOKClu2 = testLambda(cluE2, gamma2.m20(), gamma2.m02(), mShowerShapeCutValue, mUseNegativeCrossTerm); + if (!isDispOKClu2) + continue; + bool matchFlag2 = false; + for (auto const& match : matches) { + if (gamma2.index() == match.caloClusterId()) { + matchFlag2 = true; + break; + } + } + ROOT::Math::LorentzVector> fourVectorG1, fourVectorG2; + fourVectorG1.SetPxPyPzE(gamma1.px(), gamma1.py(), gamma1.pz(), cluE1); + fourVectorG2.SetPxPyPzE(gamma2.px(), gamma2.py(), gamma2.pz(), cluE2); + double pairMassGG = (fourVectorG1 + fourVectorG2).M(); + double pairPtGG = (fourVectorG1 + fourVectorG2).Pt(); + + if (pairMassGG < mMassSpectrumLowerCutoff) + continue; + + mHistManager.fill(HIST("twoPhoton/MS_noCuts"), pairMassGG, pairPtGG, cent); + if (matchFlag1 || matchFlag2) + continue; + mHistManager.fill(HIST("twoPhoton/MS_noMatches"), pairMassGG, pairPtGG, cent); + } + } + } + + PROCESS_SWITCH(TpcElIdMassSpectrum, processMC, "process mc", false); + void processDummy(SelCollisions::iterator const&) { - // 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 * TMath::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); - - 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.; } + PROCESS_SWITCH(TpcElIdMassSpectrum, processDummy, "Dummy process", true); }; 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 7cd2e4387a7..51610ec9639 100644 --- a/PWGEM/Tasks/phosNbar.cxx +++ b/PWGEM/Tasks/phosNbar.cxx @@ -8,30 +8,30 @@ // In applying this license CERN does 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 "TRandom.h" - #include "Common/Core/trackUtilities.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/HistogramRegistry.h" -#include "CommonUtils/NameConf.h" +#include "Common/DataModel/CaloClusters.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "CommonUtils/NameConf.h" #include "DataFormatsParameters/GRPLHCIFData.h" #include "DataFormatsParameters/GRPMagField.h" #include "DetectorsBase/Propagator.h" - +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "PHOSBase/Geometry.h" #include "ReconstructionDataFormats/Track.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/CaloClusters.h" -#include "PHOSBase/Geometry.h" -#include "CommonDataFormat/InteractionRecord.h" +#include "TRandom.h" + +#include /// \struct phosNbar /// \brief account Nbar who's clusters appeared within PHOS diff --git a/PWGEM/Tasks/phosNonlin.cxx b/PWGEM/Tasks/phosNonlin.cxx index 9115fa432c8..dd3ea3003fb 100644 --- a/PWGEM/Tasks/phosNonlin.cxx +++ b/PWGEM/Tasks/phosNonlin.cxx @@ -9,52 +9,57 @@ // 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 +/// \file phosNonlin.cxx +/// \brief task to calculate PHOS non-lienarity based on pi0 peak position +/// \author Dmitri Peresunko +/// + +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" #include "Common/DataModel/CaloClusters.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsParameters/GRPLHCIFData.h" #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ConfigParamSpec.h" #include "Framework/HistogramRegistry.h" - +#include "Framework/runDataProcessing.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 -/// +#include + +#include +#include +#include +#include +#include +#include +#include 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 mParamType{"mParamType", 0, "Functional form 0: a-la data, 1: a-la MC"}; - 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"}; @@ -82,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, @@ -116,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(); } } @@ -141,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); // } } } @@ -202,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); } @@ -225,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(); } } @@ -240,33 +269,33 @@ 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.; - if (mParamType == 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); + 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 (mParamType == 1) { - 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); - return a + b / TMath::Sqrt(en) + c / en + d / (en * TMath::Sqrt(en)) + e / (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.; } @@ -275,5 +304,5 @@ struct phosNonlin { 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 fe248dbeaa6..74536648380 100644 --- a/PWGEM/Tasks/phosPi0.cxx +++ b/PWGEM/Tasks/phosPi0.cxx @@ -9,114 +9,140 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include -#include -#include -#include +/// \file phosPi0.cxx +/// \brief PHOS pi0/eta analysis +/// \author Dmitri Peresunko +/// + +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" #include "Common/DataModel/CaloClusters.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsParameters/GRPLHCIFData.h" #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ConfigParamSpec.h" #include "Framework/HistogramRegistry.h" - +#include "Framework/runDataProcessing.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 -/// +#include + +#include +#include +#include +#include +#include +#include +#include +#include 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", kTVXinPHOS, "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 kMixBinsZ = 20; + static constexpr int kMixBinsPhi = 6; + static constexpr int kMaxMixBins = kMixBinsZ * kMixBinsPhi + 1; // maximal number of bins of events for mixing: vtx*event plane + hard + static constexpr double kEmixCut = 10.; // minimal clu energy for special hard mixing bin + static constexpr int kHardMixBin = kMaxMixBins - 1; // special hard mixing bin + + 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; + TH3 *hReMod, *hMiMod, *hReAsym, *hMiAsym; 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)"}, @@ -127,15 +153,16 @@ struct phosPi0 { centAxis{10, 0., 10.}, centralityAxis{100, 0., 100., "centrality", "centrality"}; - hColl = std::get>(mHistManager.add("eventsCol", "Number of events", HistType::kTH1F, {{9, 0., 9.}})).get(); + hColl = std::get>(mHistManager.add("eventsCol", "Number of events", HistType::kTH1F, {{10, 0., 10.}})).get(); hColl->GetXaxis()->SetBinLabel(1, "All"); - hColl->GetXaxis()->SetBinLabel(2, "T0a||T0c"); - hColl->GetXaxis()->SetBinLabel(3, "T0a&&T0c"); - hColl->GetXaxis()->SetBinLabel(4, "kTVXinPHOS"); - hColl->GetXaxis()->SetBinLabel(5, "kIsTriggerTVX"); - hColl->GetXaxis()->SetBinLabel(6, "PHOSClu"); - hColl->GetXaxis()->SetBinLabel(7, "PHOSClu&&kTVXinPHOS"); - hColl->GetXaxis()->SetBinLabel(8, "Accepted"); + 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, "kPHOS"); + hColl->GetXaxis()->SetBinLabel(8, "kPHOS&&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"); @@ -150,14 +177,14 @@ struct phosPi0 { mHistManager.add("contributors", "Contributors per collision", HistType::kTH2F, {{10, 0., 10.}, {10, 0., 100.}}); 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}); @@ -165,6 +192,7 @@ struct phosPi0 { mHistManager.add("cluCPVOcc", "Cluster with CPV occupancy", HistType::kTH3F, {phiAxis, zAxis, modAxis}); mHistManager.add("cluDispOcc", "Cluster with Disp occupancy", HistType::kTH3F, {phiAxis, zAxis, modAxis}); mHistManager.add("cluBothOcc", "Cluster with Both occupancy", HistType::kTH3F, {phiAxis, zAxis, modAxis}); + mHistManager.add("qvec", "qvector", HistType::kTH2F, {{10, 0, o2::constants::math::PI, "#phi", "#phi (rad)"}, {10, 0., 1., "|q|", "|q|"}}); } hReMod = std::get>(mHistManager.add("mggReModComb", "inv mass per module", @@ -182,8 +210,36 @@ struct phosPi0 { hReBoth = std::get>(mHistManager.add("mggReBoth", "inv mass for centrality", HistType::kTH2F, {mggAxis, ptAxis})) .get(); - - if (mIsMC) { + hReAsym = std::get>(mHistManager.add("mggReAsym", "inv mass vs pt vs asym", + HistType::kTH3F, {mggAxis, ptAxis, {10, 0., 1., "asym", "a"}})) + .get(); + 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(); @@ -216,82 +272,149 @@ struct phosPi0 { hMiBoth = std::get>(mHistManager.add("mggMiBoth", "inv mass for centrality", HistType::kTH2F, {mggAxis, ptAxis})) .get(); - if (mIsMC) { + hMiAsym = std::get>(mHistManager.add("mggMiAsym", "inv mass vs pt vs asym", + HistType::kTH3F, {mggAxis, ptAxis, {10, 0., 1., "asym", "a"}})) + .get(); + 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., "R (cm)"}, {100, -TMath::Pi(), TMath::Pi(), "#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::FullTracks const& tracks, + aod::BCsWithTimestamps const&) { aod::McParticles const* mcPart = nullptr; - scanAll(col, clusters, mcPart); + scanAll(col, clusters, tracks, mcPart); } - PROCESS_SWITCH(phosPi0, processData, "processData", true); + PROCESS_SWITCH(PhosPi0, processData, "processData", true); void processMC(SelCollisionsMC::iterator const& col, - mcClusters const& clusters, + McClusters const& clusters, + aod::FullTracks const& tracks, aod::McParticles const& mcPart, - aod::McCollisions const& /*mcCol*/) + aod::McCollisions const& /*mcCol*/, + aod::BCsWithTimestamps const&) { - scanAll(col, clusters, &mcPart); + scanAll(col, clusters, tracks, &mcPart); } - PROCESS_SWITCH(phosPi0, processMC, "processMC", false); + PROCESS_SWITCH(PhosPi0, processMC, "processMC", false); template void scanAll(TCollision& col, TClusters& clusters, + aod::FullTracks const& tracks, aod::McParticles const* mcPart) { - bool isColSelected = false; mixedEventBin = 0; - hColl->Fill(0.5); - if (col.selection_bit(kIsBBT0A) || col.selection_bit(kIsBBT0C)) { - hColl->Fill(1.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.alias_bit(evSelTrig)) { + return; + } } - if (col.selection_bit(kIsBBT0A) && col.selection_bit(kIsBBT0C)) { + + hColl->Fill(1.5); + const double vtxCut = 10.; + double vtxZ = col.posZ(); + mHistManager.fill(HIST("vertex"), vtxZ); + bool isColSelected = col.alias_bit(evSelTrig) && std::abs(vtxZ) < vtxCut; + ; + // if constexpr (isMC) { + // isColSelected = (col.selection_bit(kIsTriggerTVX) && (clusters.size() > 0)); + // } else { + // isColSelected = col.alias_bit(evSelTrig) && std::abs(vtxZ) < vtxCut; // + // // collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + // } + + if (col.selection_bit(kIsBBT0A) || col.selection_bit(kIsBBT0C)) { hColl->Fill(2.5); } - if (col.alias_bit(kTVXinPHOS)) { + if (col.selection_bit(kIsBBT0A) && col.selection_bit(kIsBBT0C)) { hColl->Fill(3.5); } - if (col.selection_bit(kIsTriggerTVX)) { + if (col.alias_bit(kTVXinPHOS)) { hColl->Fill(4.5); } - if (clusters.size() > 0) { + if (col.alias_bit(kIsTriggerTVX)) { hColl->Fill(5.5); + } + if (col.alias_bit(kPHOS)) { + hColl->Fill(6.5); if (col.alias_bit(kTVXinPHOS)) { - hColl->Fill(6.5); + hColl->Fill(7.5); } } - isColSelected = false; - if constexpr (isMC) { - isColSelected = (col.selection_bit(kIsTriggerTVX) && (clusters.size() > 0)); - } else { - isColSelected = col.alias_bit(mEvSelTrig); - } - double vtxZ = col.posZ(); - mHistManager.fill(HIST("vertex"), vtxZ); - int mult = 1.; // multiplicity TODO!!! - mixedEventBin = findMixedEventBin(vtxZ, mult); if (!isColSelected) { return; } - hColl->Fill(7.5); + hColl->Fill(8.5); + + int mult = 1.; // multiplicity TODO!!! + std::pair q = evalQvec(tracks); + + // find proper event for mixing + // note, that if one find hard cluster in PHOS later, it will change bin to special one + mixedEventBin = findMixedEventBin(vtxZ, mult, q); // Fill MC distributions // pion rapidity, pt, phi // secondary pi0s + const double rMax = 0.5; // consider pi0s within this radius as primary + const double yMax = 0.5; // rapidity range if constexpr (isMC) { // check current collision Id for clusters int cluMcBCId = -1; - for (auto clu : clusters) { + 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 @@ -309,20 +432,20 @@ struct phosPi0 { 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) { - if (part.mcCollision().bcId() != cluMcBCId) { + for (const auto& part : *mcPart) { + if (part.mcCollision().bcId() != col.bcId()) { continue; } - if (part.pdgCode() == 111) { - double r = sqrt(pow(part.vx(), 2) + pow(part.vy(), 2)); - if (r < 0.5) { + if (part.pdgCode() == PDG_t::kPi0) { + double r = std::sqrt(std::pow(part.vx(), 2) + std::pow(part.vy(), 2)); + if (r < rMax) { mHistManager.fill(HIST("hMCPi0RapPrim"), part.y()); } - if (abs(part.y()) < .5) { + if (std::abs(part.y()) < yMax) { double pt = part.pt(); mHistManager.fill(HIST("hMCPi0SpAll"), pt); - double phiVtx = atan2(part.vy(), part.vx()); - if (r > 0.5) { + double phiVtx = std::atan2(part.vy(), part.vx()); + if (r > rMax) { mHistManager.fill(HIST("hMCPi0SecVtx"), r, phiVtx); } else { mHistManager.fill(HIST("hMCPi0SpPrim"), pt); @@ -339,31 +462,34 @@ 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 (clu.e() > kEmixCut) { + mixedEventBin = kHardMixBin; + } + 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.) { + if (clu.trackdist() > cpvCut) { 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()); } @@ -377,46 +503,109 @@ 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); + hReAsym->Fill(m, pt, std::abs((ph1.e - ph2.e) / (ph1.e + ph2.e)), 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 + const double tofCut1 = 12.5e-9; + const double tofCut2 = 30.e-9; + const double tofCut3 = 50.e-9; + const double tofCut4 = 100.e-9; + if (std::abs(ph1.time - timeOffset) < tofCut1) { // strict cut on first photon + if (std::abs(ph2.time - timeOffset) < tofCut4) { + hReTime100->Fill(m, ph2.pt()); + if (std::abs(ph2.time - timeOffset) < tofCut3) { + hReTime50->Fill(m, ph2.pt()); + if (std::abs(ph2.time - timeOffset) < tofCut2) { + hReTime30->Fill(m, ph2.pt()); + if (std::abs(ph2.time - timeOffset) < tofCut1) { + hReTime12->Fill(m, ph2.pt()); + } + } + } + } + } + if (std::abs(ph2.time - timeOffset) < tofCut1) { // strict cut on first photon + if (std::abs(ph1.time - timeOffset) < tofCut4) { + hReTime100->Fill(m, ph1.pt()); + if (std::abs(ph1.time - timeOffset) < tofCut3) { + hReTime50->Fill(m, ph1.pt()); + if (std::abs(ph1.time - timeOffset) < tofCut2) { + hReTime30->Fill(m, ph1.pt()); + if (std::abs(ph1.time - timeOffset) < tofCut1) { + 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); - if (cp == 111) { + hSignalAll->Fill(m, pt, w); + if (cp == PDG_t::kPi0) { 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); } } } @@ -427,26 +616,51 @@ struct phosPi0 { } // 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 = 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); + hMiAsym->Fill(m, pt, std::abs((ph1.e - ph2.e) / (ph1.e + ph2.e)), 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); + } } - double pt = sqrt(pow(ph1.px + ph2.px, 2) + - 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()) { - hMiCPV->Fill(m, pt); + hMiCPV->Fill(m, pt, w); } if (ph1.isDispOK() && ph2.isDispOK()) { - hMiDisp->Fill(m, pt); + hMiDisp->Fill(m, pt, w); if (ph1.isCPVOK() && ph2.isCPVOK()) { - hMiBoth->Fill(m, pt); + hMiBoth->Fill(m, pt, w); } } } @@ -456,7 +670,7 @@ 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(); } } @@ -468,9 +682,10 @@ struct phosPi0 { mixedEventBin = 0; mHistManager.fill(HIST("eventsBC"), 0.); - double vtxZ = 0; // no vtx info - int mult = 1.; // multiplicity TODO!!! - mixedEventBin = findMixedEventBin(vtxZ, mult); + double vtxZ = 0; // no vtx info + int mult = 1.; // multiplicity TODO!!! + std::pair q{0, 0}; // fake q-vector as no tracks + mixedEventBin = findMixedEventBin(vtxZ, mult, q); if (!isSelected) { return; @@ -480,31 +695,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.) { + if (clu.trackdist() > cpvCut) { 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()); } @@ -512,17 +727,22 @@ struct phosPi0 { } int mcLabel = -1; - 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 (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); + 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); @@ -542,17 +762,17 @@ struct phosPi0 { } // 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()) { @@ -571,41 +791,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); + 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); + if (d == 2) { // o2-linter: disable=magic-number (algoritm value) + 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 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 l2Mean = 1.53126 + 9.50835e+06 / (1. + 1.08728e+07 * pt + 1.73420e+06 * pt * pt); // o2-linter: disable=magic-number (fixed parameterization) + float l1Mean = 1.12365 + 0.123770 * std::exp(-pt * 0.246551) + 5.30000e-03 * pt; // o2-linter: disable=magic-number (fixed parameterization) + float l2Sigma = 6.48260e-02 + 7.60261e+10 / (1. + 1.53012e+11 * pt + 5.01265e+05 * pt * pt) + 9.00000e-03 * pt; // o2-linter: disable=magic-number (fixed parameterization) + float l1Sigma = 4.44719e-04 + 6.99839e-01 / (1. + 1.22497e+00 * pt + 6.78604e-07 * pt * pt) + 9.00000e-03 * pt; // o2-linter: disable=magic-number (fixed parameterization) + float c = -0.35 - 0.550 * std::exp(-0.390730 * pt); // o2-linter: disable=magic-number (fixed parameterization) return 0.5 * (l1 - l1Mean) * (l1 - l1Mean) / l1Sigma / l1Sigma + 0.5 * (l2 - l2Mean) * (l2 - l2Mean) / l2Sigma / l2Sigma + @@ -613,17 +833,27 @@ struct phosPi0 { 4.; } //_____________________________________________________________________________ - int findMixedEventBin(double vtxZ, double /*mult */) + int findMixedEventBin(double vtxZ, double /*mult*/, std::pair& q) { // calculate index for event mixing const double zwidth = 1.; // Width of zvtx bin - int res = static_cast((vtxZ + 10.) / zwidth); - - if (res < 0) - return 0; - if (res >= nMaxMixBins) - return nMaxMixBins - 1; - return res; + int iz = static_cast((vtxZ + 10.) / zwidth); + + if (iz < 0) + iz = 0; + if (iz >= kMixBinsZ) + iz = kMixBinsZ - 1; + + // event plane orientation + double phi = 0.5 * std::atan2(q.second, q.first); // 1/2 due to second order flow harmonic + while (phi < 0) + phi += o2::constants::math::PI; + while (phi > o2::constants::math::PI) + phi -= o2::constants::math::PI; + int iphi = static_cast(kMixBinsPhi * phi / o2::constants::math::PI); + mHistManager.fill(HIST("qvec"), phi, std::sqrt(q.first * q.first + q.second * q.second)); + + return iz * iphi; } //---------------------------------------- int commonParentPDG(int lab1, int lab2, aod::McParticles const* mcParticles) @@ -639,23 +869,87 @@ 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 + // no parents, parent not quark/gluon, strings + if (parent2.mothersIds().size() == 0 || parent2.pdgCode() == 21 || // o2-linter: disable=pdg/explicit-code (no code) o2-linter: disable=magic-number (pdg value) + std::abs(parent2.pdgCode()) < 11 || std::abs(parent2.pdgCode()) > 5000) { // o2-linter: disable=pdg/explicit-code (no code) o2-linter: disable=magic-number (pdg value) 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 + // 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) { // o2-linter: disable=pdg/explicit-code (no code) o2-linter: disable=magic-number (pdg value) 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 //o2-linter: disable=magic-number (local parameterization) + // parameterization 01.08.2020 + if (en > 1.1) // o2-linter: disable=magic-number (local parameterization) + en = 1.1; + if (en < 0.11) // o2-linter: disable=magic-number (local parameterization) + en = 0.11; + return std::exp((-1.15295e+05 + 2.26754e+05 * en - 1.26063e+05 * en * en + en * en * en) / // o2-linter: disable=magic-number (local parameterization) + (1. - 3.16443e+05 * en + 3.68044e+06 * en * en + en * en * en)); // o2-linter: disable=magic-number (local parameterization) + } + if (tofEffParam == 2) { // Run2 30 ns //o2-linter: disable=magic-number (kind of TOF parameterization) + if (en > 1.6) // o2-linter: disable=magic-number (local parameterization) + 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 - // o2-linter: disable=magic-number (local parameterization) + 1.43777e+03 * en * en * en * en) / // o2-linter: disable=magic-number (local parameterization) + (1. - 1.23667e+02 * en + 1.07255e+03 * en * en + 5.87221e+02 * en * en * en))); // o2-linter: disable=magic-number (local parameterization) + } + if (tofEffParam == 3) { // Run2 12.5 ns //o2-linter: disable=magic-number (local parameterization) + if (en < 4.6) { // o2-linter: disable=magic-number (local parameterization) + 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.; + } + //_____________________________________________________________________________ + std::pair evalQvec(aod::FullTracks const& tracks) + { + // calculate approximate q-vector for event + const int ord = 2; // flow order + std::pair q{0, 0}; + int ntr = 0; + for (const auto& track : tracks) { + if (!track.has_collision()) { // ignore orphan tracks without collision + continue; + } + // if (!track.isGlobalTrack()) { // only global tracks + // continue; + // } + q.first += std::cos(ord * track.phi()); + q.second += std::sin(ord * track.phi()); + ntr++; + } + if (ntr > 0) { + q.first /= ntr; + q.second /= ntr; + } + return q; + } }; 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/Core/DecayChannelsLegacy.h b/PWGHF/ALICE3/Core/DecayChannelsLegacy.h new file mode 100644 index 00000000000..7b95df102f1 --- /dev/null +++ b/PWGHF/ALICE3/Core/DecayChannelsLegacy.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 DecayChannelsLegacy.h +/// \brief Legacy definitions of constants for MC flagging of HF decay channels. +/// \author Vít Kučera , Inha University + +#ifndef PWGHF_ALICE3_CORE_DECAYCHANNELSLEGACY_H_ +#define PWGHF_ALICE3_CORE_DECAYCHANNELSLEGACY_H_ + +namespace o2::aod +{ +namespace hf_cand_x +{ +enum DecayType { + XToJpsiToEEPiPi = 0, + XToJpsiToMuMuPiPi +}; +} // namespace hf_cand_x + +namespace hf_cand_xicc +{ +enum DecayType { + XiccToXicPi = 0 +}; +} // namespace hf_cand_xicc + +namespace hf_cand_chic +{ +enum DecayType { + ChicToJpsiToEEGamma = 0, + ChicToJpsiToMuMuGamma +}; +} // namespace hf_cand_chic + +} // namespace o2::aod + +#endif // PWGHF_ALICE3_CORE_DECAYCHANNELSLEGACY_H_ diff --git a/PWGHF/ALICE3/TableProducer/candidateCreatorChic.cxx b/PWGHF/ALICE3/TableProducer/candidateCreatorChic.cxx index af643fe92e9..117fc633098 100644 --- a/PWGHF/ALICE3/TableProducer/candidateCreatorChic.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateCreatorChic.cxx @@ -15,18 +15,21 @@ /// /// \author Alessandro De Falco , Cagliari University +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "ALICE3/DataModel/ECAL.h" +#include "Common/Core/trackUtilities.h" + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/V0.h" -#include "ALICE3/DataModel/ECAL.h" -#include "Common/Core/trackUtilities.h" - -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include using namespace o2; using namespace o2::analysis; @@ -64,7 +67,6 @@ struct HfCandidateCreatorChic { Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter (to rebuild Jpsi vertex) - HfHelper hfHelper; double massJpsi{0.}; double massJpsiGamma{0.}; @@ -106,14 +108,14 @@ struct HfCandidateCreatorChic { if (!(jpsiCand.hfflag() & 1 << hf_cand_2prong::DecayType::JpsiToEE) && !(jpsiCand.hfflag() & 1 << hf_cand_2prong::DecayType::JpsiToMuMu)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yJpsi(jpsiCand)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yJpsi(jpsiCand)) > yCandMax) { continue; } if (jpsiCand.isSelJpsiToEE() > 0) { - hMassJpsiToEE->Fill(hfHelper.invMassJpsiToEE(jpsiCand)); + hMassJpsiToEE->Fill(HfHelper::invMassJpsiToEE(jpsiCand)); } if (jpsiCand.isSelJpsiToMuMu() > 0) { - hMassJpsiToMuMu->Fill(hfHelper.invMassJpsiToMuMu(jpsiCand)); + hMassJpsiToMuMu->Fill(HfHelper::invMassJpsiToMuMu(jpsiCand)); } hPtJpsi->Fill(jpsiCand.pt()); hCPAJpsi->Fill(jpsiCand.cpa()); @@ -186,7 +188,7 @@ struct HfCandidateCreatorChic { impactParameter0.getY(), 0.f, // impactParameter1.getY(), std::sqrt(impactParameter0.getSigmaY2()), 0.f, // std::sqrt(impactParameter1.getSigmaY2()), jpsiCand.globalIndex(), ecal.globalIndex(), - hfFlag, hfHelper.invMassJpsiToMuMu(jpsiCand)); + hfFlag, HfHelper::invMassJpsiToMuMu(jpsiCand)); // calculate invariant mass auto arrayMomenta = std::array{pvecJpsi, pvecGamma}; @@ -198,9 +200,9 @@ struct HfCandidateCreatorChic { hMassChicToJpsiToMuMuGamma->Fill(massJpsiGamma); } } // ecal loop - } // Jpsi loop - } // process -}; // struct + } // Jpsi loop + } // process +}; // struct /// Extends the base table with expression columns. struct HfCandidateCreatorChicExpressions { @@ -214,8 +216,6 @@ struct HfCandidateCreatorChicMc { Produces rowMcMatchRec; Produces rowMcMatchGen; - HfHelper hfHelper; - OutputObj hMassJpsiToMuMuMatched{TH1F("hMassChicToJpsiToMuMuMatched", "2-prong candidates;inv. mass (J/#psi (#rightarrow #mu+ #mu-)) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; OutputObj hMassEMatched{TH1F("hMassEMatched", "2-prong candidates;inv. mass (J/#psi (#rightarrow #mu+ #mu-)) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; OutputObj hEphotonMatched{TH1F("hEphotonMatched", "2-prong candidates;inv. mass (J/#psi (#rightarrow #mu+ #mu-)) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; @@ -246,7 +246,7 @@ struct HfCandidateCreatorChicMc { // chi_c → J/ψ gamma indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayJpsiDaughters, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true); if (indexRec > -1) { - hMassJpsiToMuMuMatched->Fill(hfHelper.invMassJpsiToMuMu(candidate.prong0())); + hMassJpsiToMuMuMatched->Fill(HfHelper::invMassJpsiToMuMu(candidate.prong0())); int indexMother = RecoDecay::getMother(mcParticles, mcParticles.rawIteratorAt(indexRec), Pdg::kChiC1); int indexMotherGamma = RecoDecay::getMother(mcParticles, mcParticles.rawIteratorAt(candidate.prong1().mcparticleId()), Pdg::kChiC1); @@ -259,7 +259,7 @@ struct HfCandidateCreatorChicMc { RecoDecay::getDaughters(particleMother, &arrAllDaughtersIndex, std::array{static_cast(kGamma), static_cast(Pdg::kJPsi)}, 1); if (arrAllDaughtersIndex.size() == 2) { flag = 1 << hf_cand_chic::DecayType::ChicToJpsiToMuMuGamma; - hMassChicToJpsiToMuMuGammaMatched->Fill(hfHelper.invMassChicToJpsiGamma(candidate)); + hMassChicToJpsiToMuMuGammaMatched->Fill(HfHelper::invMassChicToJpsiGamma(candidate)); } } } @@ -296,8 +296,8 @@ struct HfCandidateCreatorChicMc { rowMcMatchGen(flag, origin, channel); } // candidate loop - } // process -}; // struct + } // process +}; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGHF/ALICE3/TableProducer/candidateCreatorX.cxx b/PWGHF/ALICE3/TableProducer/candidateCreatorX.cxx index 9f58eb93a75..ee6317aaa27 100644 --- a/PWGHF/ALICE3/TableProducer/candidateCreatorX.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateCreatorX.cxx @@ -16,17 +16,20 @@ /// \author Rik Spijkers , Utrecht University /// \author Luca Micheletti , INFN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "Common/Core/trackUtilities.h" + #include "CommonConstants/PhysicsConstants.h" #include "DCAFitter/DCAFitterN.h" #include "Framework/AnalysisTask.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/V0.h" -#include "Common/Core/trackUtilities.h" - -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include using namespace o2; using namespace o2::analysis; @@ -64,7 +67,6 @@ struct HfCandidateCreatorX { o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter (to rebuild Jpsi vertex) o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter - HfHelper hfHelper; double massPi{0.}; double massJpsi{0.}; @@ -116,20 +118,20 @@ struct HfCandidateCreatorX { if (!(jpsiCand.hfflag() & 1 << hf_cand_2prong::DecayType::JpsiToEE) && !(jpsiCand.hfflag() & 1 << hf_cand_2prong::DecayType::JpsiToMuMu)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yJpsi(jpsiCand)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yJpsi(jpsiCand)) > yCandMax) { continue; } if (jpsiCand.isSelJpsiToEE() > 0) { - if (std::abs(hfHelper.invMassJpsiToEE(jpsiCand) - massJpsi) > diffMassJpsiMax) { + if (std::abs(HfHelper::invMassJpsiToEE(jpsiCand) - massJpsi) > diffMassJpsiMax) { continue; } - hMassJpsiToEE->Fill(hfHelper.invMassJpsiToEE(jpsiCand)); + hMassJpsiToEE->Fill(HfHelper::invMassJpsiToEE(jpsiCand)); } if (jpsiCand.isSelJpsiToMuMu() > 0) { - if (std::abs(hfHelper.invMassJpsiToMuMu(jpsiCand) - massJpsi) > diffMassJpsiMax) { + if (std::abs(HfHelper::invMassJpsiToMuMu(jpsiCand) - massJpsi) > diffMassJpsiMax) { continue; } - hMassJpsiToMuMu->Fill(hfHelper.invMassJpsiToMuMu(jpsiCand)); + hMassJpsiToMuMu->Fill(HfHelper::invMassJpsiToMuMu(jpsiCand)); } hPtJpsi->Fill(jpsiCand.pt()); @@ -252,10 +254,10 @@ struct HfCandidateCreatorX { hMassXToJpsiToMuMuPiPi->Fill(massJpsiPiPi); } } // pi- loop - } // pi+ loop - } // Jpsi loop - } // process -}; // struct + } // pi+ loop + } // Jpsi loop + } // process +}; // struct /// Extends the base table with expression columns. struct HfCandidateCreatorXExpressions { @@ -360,8 +362,8 @@ struct HfCandidateCreatorXMc { rowMcMatchGen(flag, origin, channel); } // candidate loop - } // process -}; // struct + } // process +}; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorChicToJpsiGamma.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorChicToJpsiGamma.cxx index affa3a6df99..fab70fd5eb5 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorChicToJpsiGamma.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorChicToJpsiGamma.cxx @@ -15,15 +15,17 @@ /// /// \author Alessandro De Falco , Università/INFN Cagliari -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -46,9 +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"}; - - HfHelper hfHelper; + 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"}; /// Selection on goodness of daughter tracks /// \note should be applied at candidate selection @@ -78,7 +78,7 @@ struct HfCandidateSelectorChicToJpsiGamma { } auto mchic = o2::constants::physics::MassChiC1; // chi_c1(1p) - if (std::abs(hfHelper.invMassChicToJpsiGamma(hfCandChic) - mchic) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassChicToJpsiGamma(hfCandChic) - mchic) > cuts->get(pTBin, "m")) { // LOGF(debug, "Chic topol selection failed at mass diff check"); return false; // check that mass difference is within bounds } @@ -95,8 +95,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..0de3e010c44 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Barrel.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Barrel.cxx @@ -15,15 +15,18 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "ALICE3/DataModel/RICH.h" + #include "CommonConstants/PhysicsConstants.h" #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" +#include +#include using namespace o2; using namespace o2::analysis; @@ -65,9 +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"}; - - HfHelper hfHelper; + 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"}; using TracksSel = soa::Join; @@ -144,11 +145,11 @@ struct HfCandidateSelectorD0Alice3Barrel { // invariant-mass cut if (trackPion.sign() > 0) { - if (std::abs(hfHelper.invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { return false; } } else { - if (std::abs(hfHelper.invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { return false; } } @@ -165,11 +166,11 @@ struct HfCandidateSelectorD0Alice3Barrel { // cut on cos(theta*) if (trackPion.sign() > 0) { - if (std::abs(hfHelper.cosThetaStarD0(candidate)) > cuts->get(pTBin, "cos theta*")) { + if (std::abs(HfHelper::cosThetaStarD0(candidate)) > cuts->get(pTBin, "cos theta*")) { return false; } } else { - if (std::abs(hfHelper.cosThetaStarD0bar(candidate)) > cuts->get(pTBin, "cos theta*")) { + if (std::abs(HfHelper::cosThetaStarD0bar(candidate)) > cuts->get(pTBin, "cos theta*")) { return false; } } diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Forward.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Forward.cxx index 5dadba32b98..00ef9b7d673 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Forward.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorD0Alice3Forward.cxx @@ -15,15 +15,18 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "ALICE3/DataModel/RICH.h" + #include "CommonConstants/PhysicsConstants.h" #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" +#include +#include using namespace o2; using namespace o2::analysis; @@ -65,9 +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"}; - - HfHelper hfHelper; + 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"}; using TracksSel = soa::Join; @@ -144,11 +145,11 @@ struct HfCandidateSelectorD0Alice3Forward { // invariant-mass cut if (trackPion.sign() > 0) { - if (std::abs(hfHelper.invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { return false; } } else { - if (std::abs(hfHelper.invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { return false; } } @@ -165,11 +166,11 @@ struct HfCandidateSelectorD0Alice3Forward { // cut on cos(theta*) if (trackPion.sign() > 0) { - if (std::abs(hfHelper.cosThetaStarD0(candidate)) > cuts->get(pTBin, "cos theta*")) { + if (std::abs(HfHelper::cosThetaStarD0(candidate)) > cuts->get(pTBin, "cos theta*")) { return false; } } else { - if (std::abs(hfHelper.cosThetaStarD0bar(candidate)) > cuts->get(pTBin, "cos theta*")) { + if (std::abs(HfHelper::cosThetaStarD0bar(candidate)) > cuts->get(pTBin, "cos theta*")) { return false; } } diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorD0ParametrizedPid.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorD0ParametrizedPid.cxx index b429b08cf10..7a8d6111ee0 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorD0ParametrizedPid.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorD0ParametrizedPid.cxx @@ -15,15 +15,18 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "ALICE3/DataModel/RICH.h" + #include "CommonConstants/PhysicsConstants.h" #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" +#include +#include using namespace o2; using namespace o2::analysis; @@ -65,9 +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"}; - - HfHelper hfHelper; + 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"}; using TracksSel = soa::Join; @@ -144,11 +145,11 @@ struct HfCandidateSelectorD0ParametrizedPid { // invariant-mass cut if (trackPion.sign() > 0) { - if (std::abs(hfHelper.invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { return false; } } else { - if (std::abs(hfHelper.invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) > cuts->get(pTBin, "m")) { return false; } } @@ -165,11 +166,11 @@ struct HfCandidateSelectorD0ParametrizedPid { // cut on cos(theta*) if (trackPion.sign() > 0) { - if (std::abs(hfHelper.cosThetaStarD0(candidate)) > cuts->get(pTBin, "cos theta*")) { + if (std::abs(HfHelper::cosThetaStarD0(candidate)) > cuts->get(pTBin, "cos theta*")) { return false; } } else { - if (std::abs(hfHelper.cosThetaStarD0bar(candidate)) > cuts->get(pTBin, "cos theta*")) { + if (std::abs(HfHelper::cosThetaStarD0bar(candidate)) > cuts->get(pTBin, "cos theta*")) { return false; } } diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorJpsi.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorJpsi.cxx index 74690e954c3..5ca50181673 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorJpsi.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorJpsi.cxx @@ -16,16 +16,18 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "ALICE3/DataModel/MID.h" #include "ALICE3/DataModel/RICH.h" #include "Common/Core/TrackSelectorPID.h" -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" + +#include using namespace o2; using namespace o2::analysis; @@ -82,9 +84,8 @@ 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; TrackSelectorMu selectorMuon; @@ -124,12 +125,12 @@ struct HfCandidateSelectorJpsi { } // cut on e+ e− invariant mass - if (std::abs(hfHelper.invMassJpsiToEE(candidate) - o2::constants::physics::MassJPsi) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassJpsiToEE(candidate) - o2::constants::physics::MassJPsi) > cuts->get(pTBin, "m")) { selEE = 0; } // cut on μ+ μ− invariant mass - if (std::abs(hfHelper.invMassJpsiToMuMu(candidate) - o2::constants::physics::MassJPsi) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassJpsiToMuMu(candidate) - o2::constants::physics::MassJPsi) > cuts->get(pTBin, "m")) { selMuMu = 0; } diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorLcAlice3.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorLcAlice3.cxx index 8fae8fe6e6f..509ba9bb813 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorLcAlice3.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorLcAlice3.cxx @@ -16,15 +16,17 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "ALICE3/DataModel/RICH.h" + #include "CommonConstants/PhysicsConstants.h" #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" +#include using namespace o2; using namespace o2::analysis; @@ -67,9 +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"}; - - HfHelper hfHelper; + 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"}; using TracksSel = soa::Join; @@ -134,11 +134,11 @@ struct HfCandidateSelectorLcAlice3 { } if (trackProton.globalIndex() == candidate.prong0Id()) { - if (std::abs(hfHelper.invMassLcToPKPi(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassLcToPKPi(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { return false; } } else { - if (std::abs(hfHelper.invMassLcToPiKP(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassLcToPiKP(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { return false; } } diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorLcParametrizedPid.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorLcParametrizedPid.cxx index 491b15a04d2..6bcc7fc438c 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorLcParametrizedPid.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorLcParametrizedPid.cxx @@ -16,15 +16,17 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "ALICE3/DataModel/RICH.h" + #include "CommonConstants/PhysicsConstants.h" #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" +#include using namespace o2; using namespace o2::analysis; @@ -68,9 +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"}; - - HfHelper hfHelper; + 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"}; using TracksSel = soa::Join; @@ -135,11 +135,11 @@ struct HfCandidateSelectorLcParametrizedPid { } if (trackProton.globalIndex() == candidate.prong0Id()) { - if (std::abs(hfHelper.invMassLcToPKPi(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassLcToPKPi(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { return false; } } else { - if (std::abs(hfHelper.invMassLcToPiKP(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassLcToPiKP(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { return false; } } diff --git a/PWGHF/ALICE3/TableProducer/candidateSelectorXToJpsiPiPi.cxx b/PWGHF/ALICE3/TableProducer/candidateSelectorXToJpsiPiPi.cxx index 62a542d94f9..222d8261259 100644 --- a/PWGHF/ALICE3/TableProducer/candidateSelectorXToJpsiPiPi.cxx +++ b/PWGHF/ALICE3/TableProducer/candidateSelectorXToJpsiPiPi.cxx @@ -16,15 +16,17 @@ /// \author Rik Spijkers , Utrecht University /// \author Luca Micheletti , INFN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -47,9 +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"}; - - HfHelper hfHelper; + 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"}; using TracksSel = soa::Join; @@ -84,7 +84,7 @@ struct HfCandidateSelectorXToJpsiPiPi { return false; // check that the candidate pT is within the analysis range } - if (std::abs(hfHelper.invMassXToJpsiPiPi(hfCandX) - o2::constants::physics::MassX3872) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassXToJpsiPiPi(hfCandX) - o2::constants::physics::MassX3872) > cuts->get(pTBin, "m")) { // LOGF(debug, "X topol selection failed at mass diff check"); return false; // check that mass difference is within bounds } diff --git a/PWGHF/ALICE3/TableProducer/treeCreatorChicToJpsiGamma.cxx b/PWGHF/ALICE3/TableProducer/treeCreatorChicToJpsiGamma.cxx index 1b164a0fc0e..33af9544284 100644 --- a/PWGHF/ALICE3/TableProducer/treeCreatorChicToJpsiGamma.cxx +++ b/PWGHF/ALICE3/TableProducer/treeCreatorChicToJpsiGamma.cxx @@ -18,14 +18,14 @@ /// \author Alessandro De Falco , Università/INFN Cagliari /// \author Luca Micheletti , INFN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -122,8 +122,6 @@ struct HfTreeCreatorChicToJpsiGamma { Produces rowCandidateFullEvents; Produces rowCandidateFullParticles; - HfHelper hfHelper; - void init(InitContext const&) { } @@ -203,8 +201,8 @@ struct HfTreeCreatorChicToJpsiGamma { candidate.originMcRec()); } }; - fillTable(0, candidate.isSelChicToJpsiToMuMuGamma(), hfHelper.invMassChicToJpsiGamma(candidate), hfHelper.ctChic(candidate), hfHelper.yChic(candidate)); - // fillTable(1, candidate.isSelChicToJpsiToEEGamma(), hfHelper.invMassChicToJpsiGamma(candidate), hfHelper.ctChic(candidate), hfHelper.yChic(candidate)); + fillTable(0, candidate.isSelChicToJpsiToMuMuGamma(), HfHelper::invMassChicToJpsiGamma(candidate), HfHelper::ctChic(candidate), HfHelper::yChic(candidate)); + // fillTable(1, candidate.isSelChicToJpsiToEEGamma(), HfHelper::invMassChicToJpsiGamma(candidate), HfHelper::ctChic(candidate), HfHelper::yChic(candidate)); } // Filling particle properties diff --git a/PWGHF/ALICE3/TableProducer/treeCreatorXToJpsiPiPi.cxx b/PWGHF/ALICE3/TableProducer/treeCreatorXToJpsiPiPi.cxx index 7a981b35798..b4ebf84eac2 100644 --- a/PWGHF/ALICE3/TableProducer/treeCreatorXToJpsiPiPi.cxx +++ b/PWGHF/ALICE3/TableProducer/treeCreatorXToJpsiPiPi.cxx @@ -17,13 +17,13 @@ /// /// \author Luca Micheletti , INFN -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -144,8 +144,6 @@ struct HfTreeCreatorXToJpsiPiPi { Produces rowCandidateFullEvents; Produces rowCandidateFullParticles; - HfHelper hfHelper; - using TracksWPid = soa::Join; void init(InitContext const&) @@ -236,7 +234,7 @@ struct HfTreeCreatorXToJpsiPiPi { } }; - fillTable(0, candidate.isSelXToJpsiToMuMuPiPi(), hfHelper.invMassXToJpsiPiPi(candidate), hfHelper.ctX(candidate), hfHelper.yX(candidate), hfHelper.qX(candidate), hfHelper.dRX(candidate, 1), hfHelper.dRX(candidate, 2), hfHelper.balancePtPionsX(candidate)); + fillTable(0, candidate.isSelXToJpsiToMuMuPiPi(), HfHelper::invMassXToJpsiPiPi(candidate), HfHelper::ctX(candidate), HfHelper::yX(candidate), HfHelper::qX(candidate), HfHelper::dRX(candidate, 1), HfHelper::dRX(candidate, 2), HfHelper::balancePtPionsX(candidate)); } // Filling particle properties diff --git a/PWGHF/ALICE3/Tasks/taskChic.cxx b/PWGHF/ALICE3/Tasks/taskChic.cxx index 026f781f6f4..f7331b7d417 100644 --- a/PWGHF/ALICE3/Tasks/taskChic.cxx +++ b/PWGHF/ALICE3/Tasks/taskChic.cxx @@ -15,15 +15,17 @@ /// \author Gian Michele Innocenti , CERN /// \author Alessandro De Falco , Cagliari University -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" + +#include + using namespace o2; using namespace o2::aod; using namespace o2::analysis; @@ -45,8 +47,6 @@ struct HfTaskChic { Configurable modeChicToJpsiToMuMuGamma{"modeChicToJpsiToMuMuGamma", true, "Perform Jpsi to mu+mu- analysis"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_chic_to_jpsi_gamma::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_chic::isSelChicToJpsiToEEGamma >= selectionFlagChic || aod::hf_sel_candidate_chic::isSelChicToJpsiToMuMuGamma >= selectionFlagChic); HistogramRegistry registry{ @@ -78,12 +78,12 @@ struct HfTaskChic { if (!(candidate.hfflag() & 1 << decayMode)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yChic(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yChic(candidate)) > yCandMax) { continue; } - registry.fill(HIST("hMass"), hfHelper.invMassChicToJpsiGamma(candidate), candidate.pt()); - registry.fill(HIST("hDeltaMass"), hfHelper.invMassChicToJpsiGamma(candidate) - candidate.jpsiToMuMuMass() + o2::constants::physics::MassJPsi, candidate.pt()); + registry.fill(HIST("hMass"), HfHelper::invMassChicToJpsiGamma(candidate), candidate.pt()); + registry.fill(HIST("hDeltaMass"), HfHelper::invMassChicToJpsiGamma(candidate) - candidate.jpsiToMuMuMass() + o2::constants::physics::MassJPsi, candidate.pt()); registry.fill(HIST("hPtCand"), candidate.pt()); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); registry.fill(HIST("hPtProng1"), candidate.ptProng1()); @@ -99,8 +99,8 @@ struct HfTaskChic { registry.fill(HIST("hDecLenXYErr"), candidate.errorDecayLengthXY(), candidate.pt()); // registry.fill(HIST("hEGamma"), candidate.prong1().e()); } // candidate loop - } // process -}; // struct + } // process +}; // struct struct HfTaskChicMc { Configurable selectionFlagChic{"selectionFlagChic", 1, "Selection Flag for Chic"}; @@ -108,8 +108,6 @@ struct HfTaskChicMc { Configurable modeChicToJpsiToMuMuGamma{"modeChicToJpsiToMuMuGamma", true, "Perform Jpsi to mu+mu- analysis"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_chic_to_jpsi_gamma::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_chic::isSelChicToJpsiToEEGamma >= selectionFlagChic || aod::hf_sel_candidate_chic::isSelChicToJpsiToMuMuGamma >= selectionFlagChic); HistogramRegistry registry{ @@ -163,7 +161,7 @@ struct HfTaskChicMc { if (!(candidate.hfflag() & 1 << decayMode)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yChic(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yChic(candidate)) > yCandMax) { continue; } if (candidate.flagMcMatchRec() == 1 << decayMode) { @@ -175,29 +173,29 @@ struct HfTaskChicMc { registry.fill(HIST("hCPARecSig"), candidate.cpa(), candidate.pt()); registry.fill(HIST("hEtaRecSig"), candidate.eta(), candidate.pt()); registry.fill(HIST("hDecLengthRecSig"), candidate.decayLength(), candidate.pt()); - registry.fill(HIST("hDeltaMassRecSig"), hfHelper.invMassChicToJpsiGamma(candidate) - candidate.jpsiToMuMuMass() + o2::constants::physics::MassJPsi), candidate.pt(); - registry.fill(HIST("hMassRecSig"), hfHelper.invMassChicToJpsiGamma(candidate), candidate.pt()); + registry.fill(HIST("hDeltaMassRecSig"), HfHelper::invMassChicToJpsiGamma(candidate) - candidate.jpsiToMuMuMass() + o2::constants::physics::MassJPsi), candidate.pt(); + registry.fill(HIST("hMassRecSig"), HfHelper::invMassChicToJpsiGamma(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("hChi2PCARecSig"), candidate.chi2PCA(), candidate.pt()); - registry.fill(HIST("hCtRecSig"), hfHelper.ctChic(candidate), candidate.pt()); - registry.fill(HIST("hYRecSig"), hfHelper.yChic(candidate), candidate.pt()); + registry.fill(HIST("hCtRecSig"), HfHelper::ctChic(candidate), candidate.pt()); + registry.fill(HIST("hYRecSig"), HfHelper::yChic(candidate), candidate.pt()); } else { registry.fill(HIST("hPtRecBg"), candidate.pt()); registry.fill(HIST("hCPARecBg"), candidate.cpa(), candidate.pt()); registry.fill(HIST("hEtaRecBg"), candidate.eta(), candidate.pt()); registry.fill(HIST("hDecLengthRecBg"), candidate.decayLength(), candidate.pt()); - registry.fill(HIST("hDeltaMassRecBg"), hfHelper.invMassChicToJpsiGamma(candidate) - candidate.jpsiToMuMuMass() + o2::constants::physics::MassJPsi), candidate.pt(); - registry.fill(HIST("hMassRecBg"), hfHelper.invMassChicToJpsiGamma(candidate), candidate.pt()); + registry.fill(HIST("hDeltaMassRecBg"), HfHelper::invMassChicToJpsiGamma(candidate) - candidate.jpsiToMuMuMass() + o2::constants::physics::MassJPsi), candidate.pt(); + registry.fill(HIST("hMassRecBg"), HfHelper::invMassChicToJpsiGamma(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("hChi2PCARecBg"), candidate.chi2PCA(), candidate.pt()); - registry.fill(HIST("hCtRecBg"), hfHelper.ctChic(candidate), candidate.pt()); - registry.fill(HIST("hYRecBg"), hfHelper.yChic(candidate), candidate.pt()); + registry.fill(HIST("hCtRecBg"), HfHelper::ctChic(candidate), candidate.pt()); + registry.fill(HIST("hYRecBg"), HfHelper::yChic(candidate), candidate.pt()); } } // rec // MC gen. @@ -223,8 +221,8 @@ struct HfTaskChicMc { registry.fill(HIST("hPtProng1Gen"), ptProngs[1], particle.pt()); } } // gen - } // process -}; // struct + } // process +}; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGHF/ALICE3/Tasks/taskD0Alice3Barrel.cxx b/PWGHF/ALICE3/Tasks/taskD0Alice3Barrel.cxx index da86e77a06b..546d7946394 100644 --- a/PWGHF/ALICE3/Tasks/taskD0Alice3Barrel.cxx +++ b/PWGHF/ALICE3/Tasks/taskD0Alice3Barrel.cxx @@ -15,15 +15,15 @@ /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + #include "CommonConstants/PhysicsConstants.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" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -33,8 +33,6 @@ struct HfTaskD0Alice3Barrel { // Configurable centralitySelectionMin{"centralitySelectionMin", 0.0, "Lower boundary of centrality selection"}; // Configurable centralitySelectionMax{"centralitySelectionMax", 0.0, "Higher boundary of centrality selection"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_d0_alice3_barrel::isSelHfFlag >= 1); HistogramRegistry registry{ @@ -73,14 +71,14 @@ struct HfTaskD0Alice3Barrel { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (std::abs(hfHelper.yD0(candidate)) > 4.0) { + if (std::abs(HfHelper::yD0(candidate)) > 4.0) { continue; } - auto massD0 = hfHelper.invMassD0ToPiK(candidate); - auto massD0bar = hfHelper.invMassD0barToKPi(candidate); + auto massD0 = HfHelper::invMassD0ToPiK(candidate); + auto massD0bar = HfHelper::invMassD0barToKPi(candidate); auto ptCandidate = candidate.pt(); - auto rapidityCandidate = std::abs(hfHelper.yD0(candidate)); + auto rapidityCandidate = std::abs(HfHelper::yD0(candidate)); if (candidate.isSelD0NoPid() >= 1) { registry.fill(HIST("hMassSigBkgD0NoPid"), massD0, ptCandidate, rapidityCandidate); diff --git a/PWGHF/ALICE3/Tasks/taskD0Alice3Forward.cxx b/PWGHF/ALICE3/Tasks/taskD0Alice3Forward.cxx index dea53a20d70..a43dc94d436 100644 --- a/PWGHF/ALICE3/Tasks/taskD0Alice3Forward.cxx +++ b/PWGHF/ALICE3/Tasks/taskD0Alice3Forward.cxx @@ -15,15 +15,15 @@ /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + #include "CommonConstants/PhysicsConstants.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" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -32,8 +32,6 @@ using namespace o2::framework::expressions; struct HfTaskD0Alice3Forward { Filter filterSelectCandidates = (aod::hf_sel_candidate_d0_alice3_forward::isSelHfFlag >= 1); - HfHelper hfHelper; - HistogramRegistry registry{ "registry", {{"hMassGen", "2-prong candidates (generated); #it{p}_{T}; #it{y}", {HistType::kTH2F, {{150, 0., 30.}, {8, 0, 4.0}}}}, @@ -49,14 +47,14 @@ struct HfTaskD0Alice3Forward { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (std::abs(hfHelper.yD0(candidate)) > 4.0) { + if (std::abs(HfHelper::yD0(candidate)) > 4.0) { continue; } - auto massD0 = hfHelper.invMassD0ToPiK(candidate); - // auto massD0bar = hfHelper.invMassD0barToKPi(candidate); + auto massD0 = HfHelper::invMassD0ToPiK(candidate); + // auto massD0bar = HfHelper::invMassD0barToKPi(candidate); auto ptCandidate = candidate.pt(); - auto rapidityCandidate = std::abs(hfHelper.yD0(candidate)); + auto rapidityCandidate = std::abs(HfHelper::yD0(candidate)); if (candidate.isSelD0FRichPid() >= 1) { registry.fill(HIST("hMassSigBkgD0ForwardRICHPID"), massD0, ptCandidate, rapidityCandidate); diff --git a/PWGHF/ALICE3/Tasks/taskD0ParametrizedPid.cxx b/PWGHF/ALICE3/Tasks/taskD0ParametrizedPid.cxx index 3fe2487b2f3..46387f053a6 100644 --- a/PWGHF/ALICE3/Tasks/taskD0ParametrizedPid.cxx +++ b/PWGHF/ALICE3/Tasks/taskD0ParametrizedPid.cxx @@ -15,15 +15,15 @@ /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + #include "CommonConstants/PhysicsConstants.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" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -33,8 +33,6 @@ struct HfTaskD0ParametrizedPid { // Configurable centralitySelectionMin{"centralitySelectionMin", 0.0, "Lower boundary of centrality selection"}; // Configurable centralitySelectionMax{"centralitySelectionMax", 30000.0, "Higher boundary of centrality selection"}; - HfHelper hfHelper; - using McParticlesHf = soa::Join; Filter filterSelectCandidates = (aod::hf_sel_candidate_d0_parametrized_pid::isSelD0NoPid >= 1 || aod::hf_sel_candidate_d0_parametrized_pid::isSelD0barNoPid >= 1); @@ -71,14 +69,14 @@ struct HfTaskD0ParametrizedPid { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (std::abs(hfHelper.yD0(candidate)) > 4.0) { + if (std::abs(HfHelper::yD0(candidate)) > 4.0) { continue; } - auto massD0 = hfHelper.invMassD0ToPiK(candidate); - // auto massD0bar = hfHelper.invMassD0barToKPi(candidate); + auto massD0 = HfHelper::invMassD0ToPiK(candidate); + // auto massD0bar = HfHelper::invMassD0barToKPi(candidate); auto ptCandidate = candidate.pt(); - auto rapidityCandidate = std::abs(hfHelper.yD0(candidate)); + auto rapidityCandidate = std::abs(HfHelper::yD0(candidate)); if (candidate.isSelD0NoPid() >= 1) { registry.fill(HIST("hMassSigBkgD0NoPid"), massD0, ptCandidate, rapidityCandidate); diff --git a/PWGHF/ALICE3/Tasks/taskJpsi.cxx b/PWGHF/ALICE3/Tasks/taskJpsi.cxx index f3bcbd8dcb2..9a20f6f42e9 100644 --- a/PWGHF/ALICE3/Tasks/taskJpsi.cxx +++ b/PWGHF/ALICE3/Tasks/taskJpsi.cxx @@ -16,13 +16,15 @@ /// \author Vít Kučera , CERN /// \author Biao Zhang , CCNU +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include using namespace o2; using namespace o2::analysis; @@ -48,8 +50,6 @@ struct HfTaskJpsi { Configurable selectedMid{"selectedMid", false, "select MID for Jpsi to mu+mu-"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_jpsi_to_e_e::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_jpsi::isSelJpsiToEETopol >= selectionFlagJpsi || aod::hf_sel_candidate_jpsi::isSelJpsiToMuMuTopol >= selectionFlagJpsi); HistogramRegistry registry{ @@ -109,14 +109,14 @@ struct HfTaskJpsi { } } } - if (yCandMax >= 0. && std::abs(hfHelper.yJpsi(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yJpsi(candidate)) > yCandMax) { continue; } if (modeJpsiToMuMu) { - registry.fill(HIST("hMass"), hfHelper.invMassJpsiToMuMu(candidate), candidate.pt()); + registry.fill(HIST("hMass"), HfHelper::invMassJpsiToMuMu(candidate), candidate.pt()); } else { - registry.fill(HIST("hMass"), hfHelper.invMassJpsiToEE(candidate), candidate.pt()); + registry.fill(HIST("hMass"), HfHelper::invMassJpsiToEE(candidate), candidate.pt()); } registry.fill(HIST("hPtCand"), candidate.pt()); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); @@ -147,8 +147,6 @@ struct HfTaskJpsiMc { Configurable selectedMid{"selectedMid", false, "select MID for Jpsi to mu+mu-"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_jpsi_to_e_e::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - using McParticlesHf = soa::Join; Filter filterSelectCandidates = (aod::hf_sel_candidate_jpsi::isSelJpsiToEETopol >= selectionFlagJpsi || aod::hf_sel_candidate_jpsi::isSelJpsiToMuMuTopol >= selectionFlagJpsi); @@ -232,7 +230,7 @@ struct HfTaskJpsiMc { } } - if (yCandMax >= 0. && std::abs(hfHelper.yJpsi(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yJpsi(candidate)) > yCandMax) { continue; } if (candidate.flagMcMatchRec() == 1 << decayMode) { @@ -244,9 +242,9 @@ struct HfTaskJpsiMc { registry.fill(HIST("hCPARecSig"), candidate.cpa()); registry.fill(HIST("hEtaRecSig"), candidate.eta()); if (modeJpsiToMuMu) { - registry.fill(HIST("hMassSig"), hfHelper.invMassJpsiToMuMu(candidate), candidate.pt()); + registry.fill(HIST("hMassSig"), HfHelper::invMassJpsiToMuMu(candidate), candidate.pt()); } else { - registry.fill(HIST("hMassSig"), hfHelper.invMassJpsiToEE(candidate), candidate.pt()); + registry.fill(HIST("hMassSig"), HfHelper::invMassJpsiToEE(candidate), candidate.pt()); } registry.fill(HIST("hDecLengthSig"), candidate.decayLength(), candidate.pt()); registry.fill(HIST("hDecLengthXYSig"), candidate.decayLengthXY(), candidate.pt()); @@ -254,8 +252,8 @@ struct HfTaskJpsiMc { registry.fill(HIST("hd0Prong1Sig"), candidate.impactParameter1(), candidate.pt()); registry.fill(HIST("hd0d0Sig"), candidate.impactParameterProduct(), candidate.pt()); registry.fill(HIST("hChi2PCASig"), candidate.chi2PCA(), candidate.pt()); - registry.fill(HIST("hCtSig"), hfHelper.ctJpsi(candidate), candidate.pt()); - registry.fill(HIST("hYSig"), hfHelper.yJpsi(candidate), candidate.pt()); + registry.fill(HIST("hCtSig"), HfHelper::ctJpsi(candidate), candidate.pt()); + registry.fill(HIST("hYSig"), HfHelper::yJpsi(candidate), candidate.pt()); registry.fill(HIST("hYGenSig"), RecoDecay::y(particleMother.pVector(), o2::constants::physics::MassJPsi), particleMother.pt()); } else { @@ -263,9 +261,9 @@ struct HfTaskJpsiMc { registry.fill(HIST("hCPARecBg"), candidate.cpa()); registry.fill(HIST("hEtaRecBg"), candidate.eta()); if (modeJpsiToMuMu) { - registry.fill(HIST("hMassBg"), hfHelper.invMassJpsiToMuMu(candidate), candidate.pt()); + registry.fill(HIST("hMassBg"), HfHelper::invMassJpsiToMuMu(candidate), candidate.pt()); } else { - registry.fill(HIST("hMassBg"), hfHelper.invMassJpsiToEE(candidate), candidate.pt()); + registry.fill(HIST("hMassBg"), HfHelper::invMassJpsiToEE(candidate), candidate.pt()); } registry.fill(HIST("hDecLengthBg"), candidate.decayLength(), candidate.pt()); registry.fill(HIST("hDecLengthxyBg"), candidate.decayLengthXY(), candidate.pt()); @@ -273,8 +271,8 @@ struct HfTaskJpsiMc { registry.fill(HIST("hd0Prong1Bg"), candidate.impactParameter1(), candidate.pt()); registry.fill(HIST("hd0d0Bg"), candidate.impactParameterProduct(), candidate.pt()); registry.fill(HIST("hChi2PCABg"), candidate.chi2PCA(), candidate.pt()); - registry.fill(HIST("hCtBg"), hfHelper.ctJpsi(candidate), candidate.pt()); - registry.fill(HIST("hYBg"), hfHelper.yJpsi(candidate), candidate.pt()); + registry.fill(HIST("hCtBg"), HfHelper::ctJpsi(candidate), candidate.pt()); + registry.fill(HIST("hYBg"), HfHelper::yJpsi(candidate), candidate.pt()); } } // MC gen. diff --git a/PWGHF/ALICE3/Tasks/taskLcAlice3.cxx b/PWGHF/ALICE3/Tasks/taskLcAlice3.cxx index 9bbfdaf91e5..ec32c52976c 100644 --- a/PWGHF/ALICE3/Tasks/taskLcAlice3.cxx +++ b/PWGHF/ALICE3/Tasks/taskLcAlice3.cxx @@ -15,15 +15,15 @@ /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + #include "CommonConstants/PhysicsConstants.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" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -32,8 +32,6 @@ using namespace o2::framework::expressions; struct HfTaskLcAlice3 { Filter filterSelectCandidates = (aod::hf_sel_candidate_lc_alice3::isSelLcToPKPiNoPid == 1 || aod::hf_sel_candidate_lc_alice3::isSelLcToPiKPNoPid == 1); - HfHelper hfHelper; - HistogramRegistry registry{ "registry", {{"hMassGen", "3-prong candidates (generated); #it{p}_{T}; #it{y}", {HistType::kTH2F, {{150, 0., 30.}, {8, 0, 4.0}}}}, @@ -58,14 +56,14 @@ struct HfTaskLcAlice3 { if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { continue; } - if (std::abs(hfHelper.yLc(candidate)) > 4.0) { + if (std::abs(HfHelper::yLc(candidate)) > 4.0) { continue; } - auto massLc = hfHelper.invMassLcToPKPi(candidate); - auto massLcSwap = hfHelper.invMassLcToPiKP(candidate); + auto massLc = HfHelper::invMassLcToPKPi(candidate); + auto massLcSwap = HfHelper::invMassLcToPiKP(candidate); auto ptCandidate = candidate.pt(); - auto rapidityCandidate = std::abs(hfHelper.yLc(candidate)); + auto rapidityCandidate = std::abs(HfHelper::yLc(candidate)); if (candidate.isSelLcToPKPiNoPid() == 1) { registry.fill(HIST("hMassSigBkgLcNoPid"), massLc, ptCandidate, rapidityCandidate); diff --git a/PWGHF/ALICE3/Tasks/taskLcParametrizedPid.cxx b/PWGHF/ALICE3/Tasks/taskLcParametrizedPid.cxx index 8936c56e2c1..b22c531e621 100644 --- a/PWGHF/ALICE3/Tasks/taskLcParametrizedPid.cxx +++ b/PWGHF/ALICE3/Tasks/taskLcParametrizedPid.cxx @@ -15,22 +15,21 @@ /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + #include "CommonConstants/PhysicsConstants.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" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; /// Fills MC histograms. struct HfTaskLcParametrizedPid { - HfHelper hfHelper; Filter filterSelectCandidates = (aod::hf_sel_candidate_lc_parametrized_pid::isSelLcToPKPiNoPid == 1 || aod::hf_sel_candidate_lc_parametrized_pid::isSelLcToPiKPNoPid == 1); @@ -55,14 +54,14 @@ struct HfTaskLcParametrizedPid { if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { continue; } - if (std::abs(hfHelper.yLc(candidate)) > 4.0) { + if (std::abs(HfHelper::yLc(candidate)) > 4.0) { continue; } - auto massLc = hfHelper.invMassLcToPKPi(candidate); - auto massLcSwap = hfHelper.invMassLcToPiKP(candidate); + auto massLc = HfHelper::invMassLcToPKPi(candidate); + auto massLcSwap = HfHelper::invMassLcToPiKP(candidate); auto ptCandidate = candidate.pt(); - auto rapidityCandidate = std::abs(hfHelper.yLc(candidate)); + auto rapidityCandidate = std::abs(HfHelper::yLc(candidate)); if (candidate.isSelLcToPKPiNoPid() == 1) { registry.fill(HIST("hMassSigBkgLcNoPid"), massLc, ptCandidate, rapidityCandidate); 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..2be307e0f92 100644 --- a/PWGHF/ALICE3/Tasks/taskX.cxx +++ b/PWGHF/ALICE3/Tasks/taskX.cxx @@ -16,15 +16,17 @@ /// \author Rik Spijkers , Utrecht University /// \author Luca Micheletti , INFN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" + +#include + using namespace o2; using namespace o2::aod; using namespace o2::analysis; @@ -46,8 +48,6 @@ struct HfTaskX { Configurable modeXToJpsiToMuMuPiPi{"modeXToJpsiToMuMuPiPi", false, "Perform Jpsi to mu+mu- analysis"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_x_to_jpsi_pi_pi::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_x::isSelXToJpsiToEEPiPi >= selectionFlagX || aod::hf_sel_candidate_x::isSelXToJpsiToMuMuPiPi >= selectionFlagX); HistogramRegistry registry{ @@ -79,11 +79,11 @@ struct HfTaskX { if (!(candidate.hfflag() & 1 << decayMode)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yX(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yX(candidate)) > yCandMax) { continue; } - registry.fill(HIST("hMass"), hfHelper.invMassXToJpsiPiPi(candidate), candidate.pt()); + registry.fill(HIST("hMass"), HfHelper::invMassXToJpsiPiPi(candidate), candidate.pt()); registry.fill(HIST("hPtCand"), candidate.pt()); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); registry.fill(HIST("hPtProng1"), candidate.ptProng1()); @@ -100,8 +100,8 @@ struct HfTaskX { registry.fill(HIST("hDecLenErr"), candidate.errorDecayLength(), candidate.pt()); registry.fill(HIST("hDecLenXYErr"), candidate.errorDecayLengthXY(), candidate.pt()); } // candidate loop - } // process -}; // struct + } // process +}; // struct struct HfTaskXMc { Configurable selectionFlagX{"selectionFlagX", 1, "Selection Flag for X"}; @@ -109,8 +109,6 @@ struct HfTaskXMc { Configurable modeXToJpsiToMuMuPiPi{"modeXToJpsiToMuMuPiPi", false, "Perform Jpsi to mu+mu- analysis"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_x_to_jpsi_pi_pi::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_x::isSelXToJpsiToEEPiPi >= selectionFlagX || aod::hf_sel_candidate_x::isSelXToJpsiToMuMuPiPi >= selectionFlagX); HistogramRegistry registry{ @@ -167,7 +165,7 @@ struct HfTaskXMc { if (!(candidate.hfflag() & 1 << decayMode)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yX(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yX(candidate)) > yCandMax) { continue; } if (candidate.flagMcMatchRec() == 1 << decayMode) { @@ -179,7 +177,7 @@ struct HfTaskXMc { registry.fill(HIST("hEtaRecSig"), candidate.eta(), candidate.pt()); registry.fill(HIST("hDeclengthRecSig"), candidate.decayLength(), candidate.pt()); - registry.fill(HIST("hMassRecSig"), hfHelper.invMassXToJpsiPiPi(candidate), candidate.pt()); + registry.fill(HIST("hMassRecSig"), HfHelper::invMassXToJpsiPiPi(candidate), candidate.pt()); registry.fill(HIST("hd0Prong0RecSig"), candidate.impactParameter0(), candidate.pt()); registry.fill(HIST("hd0Prong1RecSig"), candidate.impactParameter1(), candidate.pt()); registry.fill(HIST("hd0Prong2RecSig"), candidate.impactParameter2(), candidate.pt()); @@ -187,15 +185,15 @@ struct HfTaskXMc { registry.fill(HIST("hPtProng1RecSig"), candidate.ptProng1(), candidate.pt()); registry.fill(HIST("hPtProng2RecSig"), candidate.ptProng2(), candidate.pt()); registry.fill(HIST("hChi2PCASig"), candidate.chi2PCA(), candidate.pt()); - registry.fill(HIST("hCtSig"), hfHelper.ctX(candidate), candidate.pt()); - registry.fill(HIST("hYSig"), hfHelper.yX(candidate), candidate.pt()); + registry.fill(HIST("hCtSig"), HfHelper::ctX(candidate), candidate.pt()); + registry.fill(HIST("hYSig"), HfHelper::yX(candidate), candidate.pt()); } else { registry.fill(HIST("hPtRecBg"), candidate.pt()); registry.fill(HIST("hCPARecBg"), candidate.cpa(), candidate.pt()); registry.fill(HIST("hEtaRecBg"), candidate.eta(), candidate.pt()); registry.fill(HIST("hDeclengthRecBg"), candidate.decayLength(), candidate.pt()); - registry.fill(HIST("hMassRecBg"), hfHelper.invMassXToJpsiPiPi(candidate), candidate.pt()); + registry.fill(HIST("hMassRecBg"), HfHelper::invMassXToJpsiPiPi(candidate), candidate.pt()); registry.fill(HIST("hd0Prong0RecBg"), candidate.impactParameter0(), candidate.pt()); registry.fill(HIST("hd0Prong1RecBg"), candidate.impactParameter1(), candidate.pt()); registry.fill(HIST("hd0Prong2RecBg"), candidate.impactParameter2(), candidate.pt()); @@ -203,8 +201,8 @@ struct HfTaskXMc { registry.fill(HIST("hPtProng1RecBg"), candidate.ptProng1(), candidate.pt()); registry.fill(HIST("hPtProng2RecBg"), candidate.ptProng2(), candidate.pt()); registry.fill(HIST("hChi2PCABg"), candidate.chi2PCA(), candidate.pt()); - registry.fill(HIST("hCtBg"), hfHelper.ctX(candidate), candidate.pt()); - registry.fill(HIST("hYBg"), hfHelper.yX(candidate), candidate.pt()); + registry.fill(HIST("hCtBg"), HfHelper::ctX(candidate), candidate.pt()); + registry.fill(HIST("hYBg"), HfHelper::yX(candidate), candidate.pt()); } } // rec // MC gen. @@ -228,8 +226,8 @@ struct HfTaskXMc { registry.fill(HIST("hPtGenProng2"), ptProngs[2], particle.pt()); } } // gen - } // process -}; // struct + } // process +}; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGHF/Core/CentralityEstimation.h b/PWGHF/Core/CentralityEstimation.h index 23fd5d6ebb7..71cdc0ebffd 100644 --- a/PWGHF/Core/CentralityEstimation.h +++ b/PWGHF/Core/CentralityEstimation.h @@ -16,6 +16,10 @@ #ifndef PWGHF_CORE_CENTRALITYESTIMATION_H_ #define PWGHF_CORE_CENTRALITYESTIMATION_H_ +#include + +#include + namespace o2::hf_centrality { // centrality selection estimators @@ -28,6 +32,162 @@ enum CentralityEstimator { 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 TCollision& 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 TCollision& 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 TCollision& 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 TCollision& 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 TCollision& 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 TCollision&) +{ + return -1.f; +} + +/// 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 TCollision& collision, const 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. See CentralityEstimator for valid values."; + break; + } + return -1.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(TCollisions const& collSlice) +{ + uint16_t multiplicity{}; // type of numContrib + float centrality{-1.f}; + for (const auto& collision : collSlice) { + const uint16_t 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(TCollisions const& collSlice, const int centEstimator) +{ + uint16_t multiplicity{}; // type of numContrib + float centrality{-1.f}; + for (const auto& collision : collSlice) { + const uint16_t 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/DecayChannels.h b/PWGHF/Core/DecayChannels.h new file mode 100644 index 00000000000..929079b9b9f --- /dev/null +++ b/PWGHF/Core/DecayChannels.h @@ -0,0 +1,281 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DecayChannels.h +/// \brief Definitions of constants for MC flagging of HF decay channels. +/// \author Vít Kučera , Inha University +/// \note DecayChannelMain enums define unique combinations of the mother and the daughters for main channels. +/// \note DecayChannelResonant enums define unique combinations of the mother and the daughters for resonant channels. +/// \note Value 0 is reserved to indicate no match. +/// \note Daughter ordering convention: (charm|strange|π±|K±|π0), (baryon|meson), (+|−) + +#ifndef PWGHF_CORE_DECAYCHANNELS_H_ +#define PWGHF_CORE_DECAYCHANNELS_H_ + +#include + +namespace o2::hf_decay +{ + +// TODO +// - HF cascades (Λc+ → p K0short) +// - HF cascades to LF cascades (Ωc0/Ξc0 → Ξ+ π−, Ξc+ → Ξ+ π− π+) +// - Σc + +using HfDecayChannel = int8_t; + +namespace hf_cand_2prong +{ +/// @brief 2-prong candidates: main channels +enum DecayChannelMain : HfDecayChannel { + // D0 + D0ToPiK = 1, // π+ K− + D0ToPiKPi0 = 2, // π+ K− π0 + D0ToPiPi = 3, // π+ π− + D0ToPiPiPi0 = 4, // π+ π− π0 + D0ToKK = 5, // K+ K− + // J/ψ + JpsiToEE = 6, // e+ e− + JpsiToMuMu = 7, // μ+ μ− + // + NChannelsMain = JpsiToMuMu // last channel +}; +/// @brief 2-prong candidates: resonant channels +enum DecayChannelResonant : HfDecayChannel { + // D0 + D0ToRhoplusPi = 1, // ρ+ π− + D0ToRhoplusK = 2, // ρ+ K− + D0ToKstar0Pi0 = 3, // anti-K*0 π0 + D0ToKstarPi = 4, // K*− π+ + // + NChannelsResonant = D0ToKstarPi // last channel +}; +} // namespace hf_cand_2prong + +namespace hf_cand_3prong +{ +/// @brief 3-prong candidates: main channels +enum DecayChannelMain : HfDecayChannel { + // D+ + DplusToPiKPi = 1, // π+ K− π+ + DplusToPiKPiPi0 = 2, // π+ K− π+ π0 + DplusToPiPiPi = 3, // π+ π− π+ + DplusToPiKK = 4, // π+ K− K+ + // Ds+ + DsToPiKK = 5, // π+ K− K+ + DsToPiKKPi0 = 6, // π+ K− K+ π0 + DsToPiPiK = 7, // π+ π− K+ + DsToPiPiPi = 8, // π+ π− π+ + DsToPiPiPiPi0 = 9, // π+ π− π+ π0 + // D*+ + DstarToPiKPi = 10, // π+ K− π+ (from [(D0 → π+ K−) π+]) + DstarToPiKPiPi0 = 11, // π+ K− π+ π0 + DstarToPiKPiPi0Pi0 = 12, // π+ K− π+ π0 π0 + DstarToPiKK = 13, // π+ K− K+ + DstarToPiKKPi0 = 14, // π+ K− K+ π0 + DstarToPiPiPi = 15, // π+ π− π+ + DstarToPiPiPiPi0 = 16, // π+ π− π+ π0 + // Λc+ + LcToPKPi = 17, // p K− π+ + LcToPKPiPi0 = 18, // p K− π+ π0 + LcToPPiPi = 19, // p π− π+ + LcToPKK = 20, // p K− K+ + // Ξc+ + XicToPKPi = 21, // p K− π+ + XicToPKK = 22, // p K− K+ + XicToSPiPi = 23, // Σ+ π− π+ + // + NChannelsMain = XicToSPiPi // last channel +}; +/// @brief 3-prong candidates: resonant channels +enum DecayChannelResonant : HfDecayChannel { + // D+ + DplusToPhiPi = 1, // φ π+ + DplusToKstar0K = 2, // anti-K*0 K+ + DplusToKstar1430_0K = 3, // anti-K*0(1430) K+ + DplusToRho0Pi = 4, // ρ0 π+ + DplusToF2_1270Pi = 5, // f2(1270) π+ + // Ds+ + DsToPhiPi = 6, // φ π+ + DsToPhiRhoplus = 7, // φ ρ+ + DsToKstar0K = 8, // anti-K*0 K+ + DsToKstar0Pi = 9, // anti-K*0 π+ + DsToRho0Pi = 10, // ρ0 π+ + DsToRho0K = 11, // ρ0 K+ + DsToF2_1270Pi = 12, // f2(1270) π+ + DsToF0_1370K = 13, // f0(1370) K+ + DsToEtaPi = 14, // η π+ + // D*+ + DstarToD0ToRhoplusPi = 15, // ρ+ π− + DstarToD0ToRhoplusK = 16, // ρ+ K− + DstarToD0ToKstar0Pi0 = 17, // anti-K*0 π0 + DstarToD0ToKstarPi = 18, // K*− π+ + DstarToDplusToPhiPi = 19, // φ π+ + DstarToDplusToKstar0K = 20, // anti-K*0 K+ + DstarToDplusToKstar1430_0K = 21, // anti-K*0(1430) K+ + DstarToDplusToRho0Pi = 22, // ρ0 π+ + DstarToDplusToF2_1270Pi = 23, // f2(1270) π+ + // Λc+ + LcToPKstar0 = 24, // p anti-K*0(892) + LcToDeltaplusplusK = 25, // Δ++ K− + LcToL1520Pi = 26, // Λ(1520) π+ + LcToPPhi = 29, // p φ + // Ξc+ + XicToPKstar0 = 27, // p anti-K*0(892) + XicToPPhi = 28, // p φ + // + NChannelsResonant = XicToPPhi // last channel +}; +} // namespace hf_cand_3prong + +namespace hf_cand_dstar +{ +/// @brief D*+ candidates: main channels +enum DecayChannelMain : HfDecayChannel { + // D*+ + DstarToPiKPi = 1, // π+ K− π+ (from [(D0 → π+ K−) π+]) + DstarToPiKPiPi0 = 2, // π+ K− π+ π0 (from [(D0 → π+ K− π0) π+] or [(D+ → π+ K− π+) π0]) + // + NChannelsMain = DstarToPiKPiPi0 // last channel +}; +} // namespace hf_cand_dstar + +namespace hf_cand_beauty +{ +/// @brief beauty candidates: main channels +enum DecayChannelMain : HfDecayChannel { + // B0 + B0ToDminusPi = 1, // D− π+ + B0ToDminusPiPi0 = 2, // D− π+ π0 + B0ToDminusPiGamma = 3, // D− π+ γ0 + B0ToDminusK = 4, // D− K+ + B0ToD0PiPi = 5, // anti-D0 π+ π− + B0ToDsPi = 19, // Ds− π+ + // Bs0 + BsToDsPi = 6, // Ds− π+ + BsToDsPiPi0 = 7, // Ds− π+ π0 + BsToDsPiGamma = 8, // Ds− π+ γ0 + BsToDsK = 9, // Ds− K+ + // Λb0 + LbToLcPi = 10, // Λc+ π− + LbToLcPiPi0 = 11, // Λc+ π− π0 + LbToLcPiGamma = 12, // Λc+ π− γ0 + LbToLcK = 13, // Λc+ K− + LbToLcKPi0 = 14, // Λc+ K− π0 + // B+ + BplusToD0Pi = 15, // anti-D0 π+ + BplusToD0PiPi0 = 16, // anti-D0 π+ π0 + BplusToD0PiGamma = 17, // anti-D0 π+ γ0 + BplusToD0K = 18, // anti-D0 K+ + // + NChannelsMain = B0ToDsPi // last channel +}; +/// @brief beauty candidates: resonant channels +enum DecayChannelResonant : HfDecayChannel { + // B0 + B0ToDminusRhoplus = 1, // D− ρ+ + B0ToDstarminusPi = 2, // D*− π+ + // Bs0 + BsToDsRhoplus = 3, // Ds− ρ+ + BsToDsstarPi = 4, // Ds*− π+ + // Λb0 + LbToLcRhoplus = 5, // Λc+ ρ− + LbToScPi = 6, // Σc+ π− + LbToScK = 7, // Σc+ K− + LbToSc0Pi0 = 8, // Σc0 π0 + // B+ + BplusToD0Rhoplus = 9, // anti-D0 ρ+ + BplusToDstar0Pi = 10, // anti-D*0 π+ + // + NChannelsResonant = BplusToDstar0Pi // last channel +}; +/// @brief beauty candidates: beauty to J/ψ decay channels +enum DecayChannelToJpsiMain : HfDecayChannel { + // B0 + B0ToJpsiPiK = 1, // J/ψ π− K+ + // Bs0 + BsToJpsiKK = 2, // J/ψ K+ K− + // Λb0 + LbToJpsiPK = 3, // J/ψ p K− + // B+ + BplusToJpsiK = 4, // J/ψ K+ + // Bc+ + BcToJpsiPi = 5, // J/ψ π+ + // + NChannelsToJpsiMain = BcToJpsiPi // last channel +}; +/// @brief beauty candidates: beauty to J/ψ resonant decay channels +enum DecayChannelToJpsiResonant : HfDecayChannel { + // B0 + B0ToJpsiKstar0 = 1, // J/ψ K*0(892) + // Bs0 + BsToJpsiPhi = 2, // J/ψ φ + // + NChannelsToJpsiResonant = BsToJpsiPhi // last channel +}; +} // namespace hf_cand_beauty + +namespace hf_cand_reso +{ +/// @brief resonance candidates: main channels +enum DecayChannelMain : HfDecayChannel { + // D1(2420)0 + D1zeroToDstarPi = 1, // D*+ π- + // D2*(2460)0 + D2starzeroToDplusPi = 2, // D+ π− + D2starzeroToDstarPi = 3, // D*+ π- + // D2*(2460)+ + D2starplusToD0Pi = 4, // D0 π+ + // Ds1(2536)+ + Ds1ToDstarK0s = 5, // D*+ K0s + // Ds2*(2573)+ + Ds2starToD0Kplus = 6, // D0 K+ + Ds2starToDplusK0s = 7, // D+ K0s + Ds2starToDstarK0s = 8, // D*+ K0s + // Ds1*(2700)+ + Ds1star2700ToDstarK0s = 9, // D*+ K0s + // Ds1*(2860)+ + Ds1star2860ToDstarK0s = 10, // D*+ K0s + // Ds3*(2860)+ + Ds3star2860ToDstarK0s = 11, // D*+ K0s + // Xic(3055)0 + Xic3055zeroToD0Lambda = 12, // D0 Λ + // Xic(3055)+ + Xic3055plusToDplusLambda = 13, // D+ Λ + // Xic(3080)0 + Xic3080zeroToD0Lambda = 14, // D0 Λ + // Xic(3080)+ + Xic3080plusToDplusLambda = 15, // D+ Λ + // D*+ + DstarToD0Pi = 16, // D0 π+ + NChannelsMain = DstarToD0Pi // last channel +}; +} // namespace hf_cand_reso + +/// @brief Sigmac candidates: main channels +namespace hf_cand_sigmac +{ +enum DecayChannelMain : HfDecayChannel { + // Σc0(2455) → Λc+ π- → p K- π+ π- + Sc0ToPKPiPi = 1, + // Σc++(2455) → Λc+ π+ → p K- π+ π+ + ScplusplusToPKPiPi = 2, + // Σc0(2520) → Λc+ π- → p K- π+ π- + ScStar0ToPKPiPi = 3, + // Σc++(2520) → Λc+ π+ → p K- π+ π+ + ScStarPlusPlusToPKPiPi = 4, + NChannelsMain = ScStarPlusPlusToPKPiPi // last channel +}; +} // namespace hf_cand_sigmac + +} // namespace o2::hf_decay + +#endif // PWGHF_CORE_DECAYCHANNELS_H_ diff --git a/PWGHF/Core/DecayChannelsLegacy.h b/PWGHF/Core/DecayChannelsLegacy.h new file mode 100644 index 00000000000..675417d975b --- /dev/null +++ b/PWGHF/Core/DecayChannelsLegacy.h @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DecayChannelsLegacy.h +/// \brief Legacy definitions of constants for MC flagging of HF decay channels. +/// \author Vít Kučera , Inha University +/// \note Should be replaced with corresponding constants in DecayChannels.h. + +#ifndef PWGHF_CORE_DECAYCHANNELSLEGACY_H_ +#define PWGHF_CORE_DECAYCHANNELSLEGACY_H_ + +namespace o2::aod +{ +namespace hf_cand_xic0_omegac0 +{ +enum DecayType { + XiczeroToXiPi = 0, + OmegaczeroToXiPi, + OmegaczeroToOmegaPi, + OmegaczeroToOmegaK, + OmegaczeroToOmegaPiOneMu +}; +} // namespace hf_cand_xic0_omegac0 + +namespace hf_cand_xic_to_xi_pi_pi +{ +enum DecayType { + XicToXiPiPi = 0, // Ξc± → Ξ∓ π± π± + XicToXiResPiToXiPiPi, // Ξc± → Ξ(1530) π± → Ξ∓ π± π± + NDecayType +}; +} // namespace hf_cand_xic_to_xi_pi_pi + +namespace hf_cand_dstar +{ +enum DecayType { + DstarToD0Pi = 0, + D0ToPiK, + DstarToD0PiPi0, + D0ToPiKPi0, + NDstarDecayType +}; +} // namespace hf_cand_dstar + +namespace hf_cand_b0 +{ +enum DecayType { + B0ToDPi = 0, + B0ToDstarPi +}; +} // namespace hf_cand_b0 + +namespace hf_cand_bplus +{ +enum DecayType { + BplusToD0Pi = 0 +}; +} // namespace hf_cand_bplus + +namespace hf_cand_bs +{ +enum DecayType { + BsToDsPi = 0 +}; +} // namespace hf_cand_bs + +namespace hf_cand_lb +{ +enum DecayType { + LbToLcPi +}; +} // namespace hf_cand_lb + +} // namespace o2::aod + +#endif // PWGHF_CORE_DECAYCHANNELSLEGACY_H_ diff --git a/PWGHF/Core/HfHelper.h b/PWGHF/Core/HfHelper.h index 018f5ea52f3..419360c00be 100644 --- a/PWGHF/Core/HfHelper.h +++ b/PWGHF/Core/HfHelper.h @@ -17,16 +17,26 @@ #ifndef PWGHF_CORE_HFHELPER_H_ #define PWGHF_CORE_HFHELPER_H_ -#include -#include -#include - -#include "CommonConstants/PhysicsConstants.h" +#include "PWGHF/Utils/utilsAnalysis.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelectorPID.h" -#include "PWGHF/Utils/utilsAnalysis.h" +#include +#include + +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include + +#include +#include +#include + +template +concept IsB0ToDstarPiChannel = requires(T candidate) { + candidate.prongD0Id(); +}; class HfHelper { @@ -42,43 +52,43 @@ class HfHelper // D0(bar) → π± K∓ template - auto ctD0(const T& candidate) + static auto ctD0(const T& candidate) { return candidate.ct(o2::constants::physics::MassD0); } template - auto yD0(const T& candidate) + static auto yD0(const T& candidate) { return candidate.y(o2::constants::physics::MassD0); } template - auto eD0(const T& candidate) + static auto eD0(const T& candidate) { return candidate.e(o2::constants::physics::MassD0); } template - auto invMassD0ToPiK(const T& candidate) + static auto invMassD0ToPiK(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}); } template - auto invMassD0barToKPi(const T& candidate) + static auto invMassD0barToKPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); } template - auto cosThetaStarD0(const T& candidate) + static auto cosThetaStarD0(const T& candidate) { return candidate.cosThetaStar(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}, o2::constants::physics::MassD0, 1); } template - auto cosThetaStarD0bar(const T& candidate) + static auto cosThetaStarD0bar(const T& candidate) { return candidate.cosThetaStar(std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}, o2::constants::physics::MassD0, 0); } @@ -86,33 +96,33 @@ class HfHelper // J/ψ template - auto ctJpsi(const T& candidate) + static auto ctJpsi(const T& candidate) { return candidate.ct(o2::constants::physics::MassJPsi); } template - auto yJpsi(const T& candidate) + static auto yJpsi(const T& candidate) { return candidate.y(o2::constants::physics::MassJPsi); } template - auto eJpsi(const T& candidate) + static auto eJpsi(const T& candidate) { return candidate.e(o2::constants::physics::MassJPsi); } // J/ψ → e+ e− template - auto invMassJpsiToEE(const T& candidate) + static auto invMassJpsiToEE(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); } // J/ψ → μ+ μ− template - auto invMassJpsiToMuMu(const T& candidate) + static auto invMassJpsiToMuMu(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassMuonPlus, o2::constants::physics::MassMuonMinus}); } @@ -120,25 +130,25 @@ class HfHelper // hf_cand_casc template - auto invMassLcToK0sP(const T& candidate) + static auto invMassLcToK0sP(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassProton, o2::constants::physics::MassK0Short}); // first daughter is bachelor } template - auto invMassGammaToEE(const T& candidate) + static auto invMassGammaToEE(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); } template - auto ctV0K0s(const T& candidate) + static auto ctV0K0s(const T& candidate) { return candidate.ctV0(o2::constants::physics::MassK0Short); } template - auto ctV0Lambda(const T& candidate) + static auto ctV0Lambda(const T& candidate) { return candidate.ctV0(o2::constants::physics::MassLambda0); } @@ -146,31 +156,37 @@ class HfHelper // B± → D0bar(D0) π± template - auto ctBplus(const T& candidate) + static auto ctBplus(const T& candidate) { return candidate.ct(o2::constants::physics::MassBPlus); } template - auto yBplus(const T& candidate) + static auto yBplus(const T& candidate) { return candidate.y(o2::constants::physics::MassBPlus); } template - auto eBplus(const T& candidate) + static auto eBplus(const T& candidate) { return candidate.e(o2::constants::physics::MassBPlus); } template - auto invMassBplusToD0Pi(const T& candidate) + static auto invMassBplusToD0Pi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassD0, o2::constants::physics::MassPiPlus}); } template - auto cosThetaStarBplus(const T& candidate) + static auto invMassBplusToJpsiK(const T& candidate) + { + return candidate.m(std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus}); + } + + template + static auto cosThetaStarBplus(const T& candidate) { return candidate.cosThetaStar(std::array{o2::constants::physics::MassD0, o2::constants::physics::MassPiPlus}, o2::constants::physics::MassBPlus, 1); } @@ -180,31 +196,31 @@ class HfHelper // D± → π± K∓ π± template - auto ctDplus(const T& candidate) + static auto ctDplus(const T& candidate) { return candidate.ct(o2::constants::physics::MassDPlus); } template - auto yDplus(const T& candidate) + static auto yDplus(const T& candidate) { return candidate.y(o2::constants::physics::MassDPlus); } template - auto eDplus(const T& candidate) + static auto eDplus(const T& candidate) { return candidate.e(o2::constants::physics::MassDPlus); } template - auto invMassDplusToPiKPi(const T& candidate) + static auto invMassDplusToPiKPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); } template - auto invMassDplusToPiKPi(const T& pVec0, const T& pVec1, const T& pVec2) + static auto invMassDplusToPiKPi(const T& pVec0, const T& pVec1, const T& pVec2) { return RecoDecay::m(std::array{pVec0, pVec1, pVec2}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); @@ -213,55 +229,55 @@ class HfHelper // Ds± → K± K∓ π± template - auto ctDs(const T& candidate) + static auto ctDs(const T& candidate) { return candidate.ct(o2::constants::physics::MassDS); } template - auto yDs(const T& candidate) + static auto yDs(const T& candidate) { return candidate.y(o2::constants::physics::MassDS); } template - auto eDs(const T& candidate) + static auto eDs(const T& candidate) { return candidate.e(o2::constants::physics::MassDS); } template - auto invMassDsToKKPi(const T& candidate) + static auto invMassDsToKKPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); } template - auto invMassDsToPiKK(const T& candidate) + static auto invMassDsToPiKK(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}); } template - auto massKKPairDsToKKPi(const T& candidate) + static auto massKKPairDsToKKPi(const T& candidate) { return RecoDecay::m(std::array{candidate.pVectorProng0(), candidate.pVectorProng1()}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}); } template - auto massKKPairDsToPiKK(const T& candidate) + static auto massKKPairDsToPiKK(const T& candidate) { return RecoDecay::m(std::array{candidate.pVectorProng1(), candidate.pVectorProng2()}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}); } template - auto deltaMassPhiDsToKKPi(const T& candidate) + static auto deltaMassPhiDsToKKPi(const T& candidate) { return std::abs(massKKPairDsToKKPi(candidate) - o2::constants::physics::MassPhi); } template - auto deltaMassPhiDsToPiKK(const T& candidate) + static auto deltaMassPhiDsToPiKK(const T& candidate) { return std::abs(massKKPairDsToPiKK(candidate) - o2::constants::physics::MassPhi); } @@ -271,12 +287,12 @@ class HfHelper /// \param option mass hypothesis considered: 0 = KKPi, 1 = PiKK /// \return cosine of pion-kaon angle in the phi rest frame template - auto cosPiKPhiRestFrame(const T& candidate, int option) + static auto cosPiKPhiRestFrame(const T& candidate, int option) { // Ported from AliAODRecoDecayHF3Prong::CosPiKPhiRFrame - std::array momPi; - std::array momK1; - std::array momK2; + std::array momPi{}; + std::array momK1{}; + std::array momK2{}; if (option == 0) { // KKPi momPi = candidate.pVectorProng2(); @@ -288,12 +304,12 @@ class HfHelper momK2 = candidate.pVectorProng2(); } - ROOT::Math::PxPyPzMVector vecPi(momPi[0], momPi[1], momPi[2], o2::constants::physics::MassPiPlus); - ROOT::Math::PxPyPzMVector vecK1(momK1[0], momK1[1], momK1[2], o2::constants::physics::MassKPlus); - ROOT::Math::PxPyPzMVector vecK2(momK2[0], momK2[1], momK2[2], o2::constants::physics::MassKPlus); - ROOT::Math::PxPyPzMVector vecPhi = vecK1 + vecK2; + ROOT::Math::PxPyPzMVector const vecPi(momPi[0], momPi[1], momPi[2], o2::constants::physics::MassPiPlus); + ROOT::Math::PxPyPzMVector const vecK1(momK1[0], momK1[1], momK1[2], o2::constants::physics::MassKPlus); + ROOT::Math::PxPyPzMVector const vecK2(momK2[0], momK2[1], momK2[2], o2::constants::physics::MassKPlus); + ROOT::Math::PxPyPzMVector const vecPhi = vecK1 + vecK2; - ROOT::Math::Boost boostToPhiRestFrame(vecPhi.BoostToCM()); + ROOT::Math::Boost const boostToPhiRestFrame(vecPhi.BoostToCM()); auto momPiPhiRestFrame = boostToPhiRestFrame(vecPi).Vect(); auto momK1PhiRestFrame = boostToPhiRestFrame(vecK1).Vect(); @@ -301,27 +317,27 @@ class HfHelper } template - auto cos3PiKDsToKKPi(const T& candidate) + static auto cos3PiKDsToKKPi(const T& candidate) { auto cosPiK = cosPiKPhiRestFrame(candidate, 0); return cosPiK * cosPiK * cosPiK; } template - auto absCos3PiKDsToKKPi(const T& candidate) + static auto absCos3PiKDsToKKPi(const T& candidate) { return std::abs(cos3PiKDsToKKPi(candidate)); } template - auto cos3PiKDsToPiKK(const T& candidate) + static auto cos3PiKDsToPiKK(const T& candidate) { auto cosPiK = cosPiKPhiRestFrame(candidate, 1); return cosPiK * cosPiK * cosPiK; } template - auto absCos3PiKDsToPiKK(const T& candidate) + static auto absCos3PiKDsToPiKK(const T& candidate) { return std::abs(cos3PiKDsToPiKK(candidate)); } @@ -329,75 +345,113 @@ class HfHelper // Λc± → p± K∓ π± template - auto ctLc(const T& candidate) + static auto ctLc(const T& candidate) { return candidate.ct(o2::constants::physics::MassLambdaCPlus); } template - auto yLc(const T& candidate) + static auto yLc(const T& candidate) { return candidate.y(o2::constants::physics::MassLambdaCPlus); } template - auto eLc(const T& candidate) + static auto eLc(const T& candidate) { return candidate.e(o2::constants::physics::MassLambdaCPlus); } template - auto invMassLcToPKPi(const T& candidate) + static auto invMassLcToPKPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); } template - auto invMassLcToPiKP(const T& candidate) + static auto invMassLcToPiKP(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassProton}); } template - auto invMassKPiPairLcToPKPi(const T& candidate) + static 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) + static 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 + static 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 + static 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 + static 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 + static auto invMassPPiPairLcToPiKP(const T& candidate) + { + return RecoDecay::m(std::array{candidate.pVectorProng2(), candidate.pVectorProng0()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiPlus}); + } + + // Cd± → De± K∓ π± + + template + static auto invMassCdToDeKPi(const T& candidate) + { + return candidate.m(std::array{o2::constants::physics::MassDeuteron, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } + + template + static auto invMassCdToPiKDe(const T& candidate) + { + return candidate.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassDeuteron}); + } + // Ξc± → p± K∓ π± template - auto ctXic(const T& candidate) + static auto ctXic(const T& candidate) { return candidate.ct(o2::constants::physics::MassXiCPlus); } template - auto yXic(const T& candidate) + static auto yXic(const T& candidate) { return candidate.y(o2::constants::physics::MassXiCPlus); } template - auto eXic(const T& candidate) + static auto eXic(const T& candidate) { return candidate.e(o2::constants::physics::MassXiCPlus); } template - auto invMassXicToPKPi(const T& candidate) + static auto invMassXicToPKPi(const T& candidate) { return invMassLcToPKPi(candidate); } template - auto invMassXicToPiKP(const T& candidate) + static auto invMassXicToPiKP(const T& candidate) { return invMassLcToPiKP(candidate); } @@ -405,13 +459,13 @@ class HfHelper // hf_cand_casc_lf_2prong template - auto invMassXiczeroToXiPi(const T& candidate) + static auto invMassXiczeroToXiPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassXiMinus, o2::constants::physics::MassPiPlus}); } template - auto invMassOmegaczeroToOmegaPi(const T& candidate) + static auto invMassOmegaczeroToOmegaPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassPiPlus}); } @@ -419,7 +473,7 @@ class HfHelper // hf_cand_casc_lf_3prong template - auto invMassXicplusToXiPiPi(const T& candidate) + static auto invMassXicplusToXiPiPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassXiMinus, o2::constants::physics::MassPiPlus, o2::constants::physics::MassPiPlus}); } @@ -428,32 +482,32 @@ class HfHelper // X → Jpsi π+ π- template - auto ctX(const T& candidate) + static auto ctX(const T& candidate) { return candidate.ct(o2::constants::physics::MassX3872); } template - auto yX(const T& candidate) + static auto yX(const T& candidate) { return candidate.y(o2::constants::physics::MassX3872); } template - auto eX(const T& candidate) + static auto eX(const T& candidate) { return candidate.e(o2::constants::physics::MassX3872); } template - auto invMassXToJpsiPiPi(const T& candidate) + static auto invMassXToJpsiPiPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassJPsi, o2::constants::physics::MassPiPlus, o2::constants::physics::MassPiPlus}); } /// Difference between the X mass and the sum of the J/psi and di-pion masses template - auto qX(const T& candidate) + static auto qX(const T& candidate) { auto piVec1 = std::array{candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()}; auto piVec2 = std::array{candidate.pxProng2(), candidate.pyProng2(), candidate.pzProng2()}; @@ -467,7 +521,7 @@ class HfHelper /// Angular difference between the J/psi and the pion template - auto dRX(const T& candidate, int numPi) + static auto dRX(const T& candidate, int numPi) { double etaJpsi = RecoDecay::eta(std::array{candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()}); double phiJpsi = RecoDecay::phi(candidate.pxProng0(), candidate.pyProng0()); @@ -482,15 +536,15 @@ class HfHelper phiPi = RecoDecay::phi(candidate.pxProng2(), candidate.pyProng2()); } - double deltaEta = etaJpsi - etaPi; - double deltaPhi = RecoDecay::constrainAngle(phiJpsi - phiPi, -o2::constants::math::PI); + double const deltaEta = etaJpsi - etaPi; + double const deltaPhi = RecoDecay::constrainAngle(phiJpsi - phiPi, -o2::constants::math::PI); return RecoDecay::sqrtSumOfSquares(deltaEta, deltaPhi); } /// Difference in pT between the two pions template - auto balancePtPionsX(const T& candidate) + static auto balancePtPionsX(const T& candidate) { double ptPi1 = RecoDecay::pt(candidate.pxProng1(), candidate.pyProng1()); double ptPi2 = RecoDecay::pt(candidate.pxProng2(), candidate.pyProng2()); @@ -500,25 +554,25 @@ class HfHelper // Ξcc±± → p± K∓ π± π± template - auto ctXicc(const T& candidate) + static auto ctXicc(const T& candidate) { return candidate.ct(o2::constants::physics::MassXiCCPlusPlus); } template - auto yXicc(const T& candidate) + static auto yXicc(const T& candidate) { return candidate.y(o2::constants::physics::MassXiCCPlusPlus); } template - auto eXicc(const T& candidate) + static auto eXicc(const T& candidate) { return candidate.e(o2::constants::physics::MassXiCCPlusPlus); } template - auto invMassXiccToXicPi(const T& candidate) + static auto invMassXiccToXicPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassXiCPlus, o2::constants::physics::MassPiPlus}); } @@ -526,24 +580,24 @@ class HfHelper // chic → Jpsi gamma template - auto ctChic(const T& candidate) + static auto ctChic(const T& candidate) { return candidate.ct(o2::constants::physics::MassChiC1); } template - auto yChic(const T& candidate) + static auto yChic(const T& candidate) { return candidate.y(o2::constants::physics::MassChiC1); } template - auto eChic(const T& candidate) + static auto eChic(const T& candidate) { return candidate.e(o2::constants::physics::MassChiC1); } template - auto invMassChicToJpsiGamma(const T& candidate) + static auto invMassChicToJpsiGamma(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassJPsi, 0.}); } @@ -551,24 +605,24 @@ class HfHelper // Λb → Λc+ π- → p K- π+ π- template - auto ctLb(const T& candidate) + static auto ctLb(const T& candidate) { return candidate.ct(o2::constants::physics::MassLambdaB0); } template - auto yLb(const T& candidate) + static auto yLb(const T& candidate) { return candidate.y(o2::constants::physics::MassLambdaB0); } template - auto eLb(const T& candidate) + static auto eLb(const T& candidate) { return candidate.e(o2::constants::physics::MassLambdaB0); } template - auto invMassLbToLcPi(const T& candidate) + static auto invMassLbToLcPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassLambdaCPlus, o2::constants::physics::MassPiPlus}); } @@ -576,31 +630,37 @@ class HfHelper // B0(B0bar) → D∓ π± template - auto ctB0(const T& candidate) + static auto ctB0(const T& candidate) { return candidate.ct(o2::constants::physics::MassB0); } template - auto yB0(const T& candidate) + static auto yB0(const T& candidate) { return candidate.y(o2::constants::physics::MassB0); } template - auto eB0(const T& candidate) + static auto eB0(const T& candidate) { return candidate.e(o2::constants::physics::MassB0); } template - auto invMassB0ToDPi(const T& candidate) + static auto invMassB0ToDPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassDMinus, o2::constants::physics::MassPiPlus}); } + template + static auto invMassB0ToDPi(const T& candidate) + { + return candidate.m(std::array{o2::constants::physics::MassD0, o2::constants::physics::MassPiPlus, o2::constants::physics::MassPiPlus}); + } + template - auto cosThetaStarB0(const T& candidate) + static auto cosThetaStarB0(const T& candidate) { return candidate.cosThetaStar(std::array{o2::constants::physics::MassDMinus, o2::constants::physics::MassPiPlus}, o2::constants::physics::MassB0, 1); } @@ -608,31 +668,37 @@ class HfHelper // Bs(bar) → Ds∓ π± template - auto ctBs(const T& candidate) + static auto ctBs(const T& candidate) { return candidate.ct(o2::constants::physics::MassBS); } template - auto yBs(const T& candidate) + static auto yBs(const T& candidate) { return candidate.y(o2::constants::physics::MassBS); } template - auto eBs(const T& candidate) + static auto eBs(const T& candidate) { return candidate.e(o2::constants::physics::MassBS); } template - auto invMassBsToDsPi(const T& candidate) + static auto invMassBsToDsPi(const T& candidate) { return candidate.m(std::array{o2::constants::physics::MassDSBar, o2::constants::physics::MassPiPlus}); } template - auto cosThetaStarBs(const T& candidate) + static auto invMassBsToJpsiPhi(const T& candidate) + { + return candidate.m(std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}); + } + + template + static auto cosThetaStarBs(const T& candidate) { return candidate.cosThetaStar(std::array{o2::constants::physics::MassDSBar, o2::constants::physics::MassPiPlus}, o2::constants::physics::MassBS, 1); } @@ -641,26 +707,26 @@ class HfHelper /// @brief Sc inv. mass using reco mass for Lc in pKpi and PDG mass for pion template - auto invMassScRecoLcToPKPi(const T& candidateSc, const U& candidateLc) + static auto invMassScRecoLcToPKPi(const T& candidateSc, const U& candidateLc) { return candidateSc.m(std::array{static_cast(invMassLcToPKPi(candidateLc)), o2::constants::physics::MassPiPlus}); } /// @brief Sc inv. mass using reco mass for Lc in piKp and PDG mass for pion template - auto invMassScRecoLcToPiKP(const T& candidateSc, const U& candidateLc) + static auto invMassScRecoLcToPiKP(const T& candidateSc, const U& candidateLc) { return candidateSc.m(std::array{static_cast(invMassLcToPiKP(candidateLc)), o2::constants::physics::MassPiPlus}); } template - auto ySc0(const T& candidate) + static auto ySc0(const T& candidate) { return candidate.y(o2::constants::physics::MassSigmaC0); } template - auto yScPlusPlus(const T& candidate) + static auto yScPlusPlus(const T& candidate) { return candidate.y(o2::constants::physics::MassSigmaCPlusPlus); } @@ -668,7 +734,7 @@ class HfHelper /// Σ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) + static auto invMassScRecoLcToK0sP(const T& candidateSc, const U& candidateLc) { return candidateSc.m(std::array{static_cast(invMassLcToK0sP(candidateLc)), o2::constants::physics::MassPiMinus}); } @@ -679,7 +745,7 @@ class HfHelper /// \param binsPt pT bin limits /// \return true if candidate passes all selections template - bool selectionB0ToDPiTopol(const T1& candB0, const T2& cuts, const T3& binsPt) + static bool selectionB0ToDPiTopol(const T1& candB0, const T2& cuts, const T3& binsPt) { auto ptCandB0 = candB0.pt(); auto ptD = RecoDecay::pt(candB0.pxProng0(), candB0.pyProng0()); @@ -756,8 +822,7 @@ class HfHelper /// \param pidTrackPi PID status of trackPi (prong1 of B0 candidate) /// \param acceptPIDNotApplicable switch to accept Status::NotApplicable /// \return true if prong1 of B0 candidate passes all selections - template - bool selectionB0ToDPiPid(const T1& pidTrackPi, const T2& acceptPIDNotApplicable) + static bool selectionB0ToDPiPid(const int pidTrackPi, const bool acceptPIDNotApplicable) { if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) { return false; @@ -775,12 +840,12 @@ class HfHelper /// \param binsPt pT bin limits /// \return true if candidate passes all selections template - bool selectionBplusToD0PiTopol(const T1& candBp, const T2& cuts, const T3& binsPt) + static bool selectionBplusToD0PiTopol(const T1& candBp, const T2& cuts, const T3& binsPt) { - auto ptcandBp = candBp.pt(); + auto ptCandBp = candBp.pt(); auto ptPi = RecoDecay::pt(candBp.pxProng1(), candBp.pyProng1()); - int pTBin = o2::analysis::findBin(binsPt, ptcandBp); + int pTBin = o2::analysis::findBin(binsPt, ptCandBp); if (pTBin == -1) { return false; } @@ -815,6 +880,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; } @@ -822,8 +897,7 @@ class HfHelper /// \param pidTrackPi PID status of trackPi (prong1 of B+ candidate) /// \param acceptPIDNotApplicable switch to accept Status::NotApplicable /// \return true if prong1 of B+ candidate passes all selections - template - bool selectionBplusToD0PiPid(const T1& pidTrackPi, const T2& acceptPIDNotApplicable) + static bool selectionBplusToD0PiPid(const int pidTrackPi, const bool acceptPIDNotApplicable) { if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) { return false; @@ -835,13 +909,112 @@ class HfHelper return true; } + // Apply topological cuts as defined in SelectorCuts.h + /// \param candBp B+ candidate + /// \param cuts B+ candidate selection per pT bin + /// \param binsPt pT bin limits + /// \return true if candidate passes all selections + template + static bool selectionBplusToJpsiKTopol(const T1& candBp, const T2& cuts, const T3& binsPt) + { + auto ptCandBp = candBp.pt(); + auto mCandBp = invMassBplusToJpsiK(candBp); + auto ptJpsi = RecoDecay::pt(candBp.pxProng0(), candBp.pyProng0()); + auto ptKa = RecoDecay::pt(candBp.pxProng1(), candBp.pyProng1()); + auto candJpsi = candBp.jpsi(); + float pseudoPropDecLen = candBp.decayLengthXY() * mCandBp / ptCandBp; + + int binPt = o2::analysis::findBin(binsPt, ptCandBp); + if (binPt == -1) { + return false; + } + + // B+ mass cut + if (std::abs(mCandBp - o2::constants::physics::MassBPlus) > cuts->get(binPt, "m")) { + return false; + } + + // kaon pt + if (ptKa < cuts->get(binPt, "pT K")) { + return false; + } + + // J/Psi pt + if (ptJpsi < cuts->get(binPt, "pT J/Psi")) { + return false; + } + + // J/Psi mass + if (std::abs(candJpsi.m() - o2::constants::physics::MassJPsi) < cuts->get(binPt, "DeltaM J/Psi")) { + return false; + } + + // d0(J/Psi)xd0(K) + if (candBp.impactParameterProduct() > cuts->get(binPt, "B Imp. Par. Product")) { + return false; + } + + // B+ Decay length + if (candBp.decayLength() < cuts->get(binPt, "B decLen")) { + return false; + } + + // B+ Decay length XY + if (candBp.decayLengthXY() < cuts->get(binPt, "B decLenXY")) { + return false; + } + + // B+ CPA cut + if (candBp.cpa() < cuts->get(binPt, "CPA")) { + return false; + } + + // B+ CPAXY cut + if (candBp.cpaXY() < cuts->get(binPt, "CPAXY")) { + return false; + } + + // d0 of K + if (std::abs(candBp.impactParameter1()) < cuts->get(binPt, "d0 K")) { + return false; + } + + // d0 of J/Psi + if (std::abs(candBp.impactParameter0()) < cuts->get(binPt, "d0 J/Psi")) { + return false; + } + + // B pseudoproper decay length + if (pseudoPropDecLen < cuts->get(binPt, "B pseudoprop. decLen")) { + return false; + } + + return true; + } + + /// Apply PID selection + /// \param pidTrackKa PID status of trackKa (prong1 of B+ candidate) + /// \param acceptPIDNotApplicable switch to accept Status::NotApplicable + /// \return true if prong1 of B+ candidate passes all selections + static bool selectionBplusToJpsiKPid(const int pidTrackKa, const bool acceptPIDNotApplicable) + { + if (!acceptPIDNotApplicable && pidTrackKa != TrackSelectorPID::Accepted) { + return false; + } + if (acceptPIDNotApplicable && pidTrackKa == TrackSelectorPID::Rejected) { + return false; + } + + return true; + } + /// Apply topological cuts as defined in SelectorCuts.h /// \param candBs Bs candidate /// \param cuts Bs candidate selections /// \param binsPt pT bin limits /// \return true if candidate passes all selections template - bool selectionBsToDsPiTopol(const T1& candBs, const T2& cuts, const T3& binsPt) + static bool selectionBsToDsPiTopol(const T1& candBs, const T2& cuts, const T3& binsPt) { auto ptCandBs = candBs.pt(); auto ptDs = RecoDecay::pt(candBs.pxProng0(), candBs.pyProng0()); @@ -909,8 +1082,196 @@ class HfHelper /// \param pidTrackPi PID status of trackPi (prong1 of Bs candidate) /// \param acceptPIDNotApplicable switch to accept Status::NotApplicable /// \return true if prong1 of Bs candidate passes all selections - template - bool selectionBsToDsPiPid(const T1& pidTrackPi, const T2& acceptPIDNotApplicable) + static bool selectionBsToDsPiPid(const int pidTrackPi, const bool acceptPIDNotApplicable) + { + if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) { + return false; + } + if (acceptPIDNotApplicable && pidTrackPi == TrackSelectorPID::Rejected) { + return false; + } + + return true; + } + + // Apply topological cuts as defined in SelectorCuts.h + /// \param candBs Bs candidate + /// \param candKa0 kaon candidate 0 (phi daughter) + /// \param candKa1 kaon candidate 1 (phi daughter) + /// \param cuts Bs candidate selection per pT bin + /// \param binsPt pT bin limits + /// \return true if candidate passes all selections + template + static bool selectionBsToJpsiPhiTopol(const T1& candBs, const T2& candKa0, const T3& candKa1, const T4& cuts, const T5& binsPt) + { + auto ptCandBs = candBs.pt(); + auto mCandBs = invMassBsToJpsiPhi(candBs); + std::array pVecKa0 = candKa0.pVector(); + std::array pVecKa1 = candKa1.pVector(); + auto mCandPhi = RecoDecay::m(std::array{pVecKa0, pVecKa1}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}); + auto ptJpsi = RecoDecay::pt(candBs.pxProng0(), candBs.pyProng0()); + auto candJpsi = candBs.jpsi(); + float pseudoPropDecLen = candBs.decayLengthXY() * mCandBs / ptCandBs; + + int binPt = o2::analysis::findBin(binsPt, ptCandBs); + if (binPt == -1) { + return false; + } + + // Bs mass cut + if (std::abs(mCandBs - o2::constants::physics::MassBPlus) > cuts->get(binPt, "m")) { + return false; + } + + // kaon pt + if (candKa0.pt() < cuts->get(binPt, "pT K") && + candKa1.pt() < cuts->get(binPt, "pT K")) { + return false; + } + + // J/Psi pt + if (ptJpsi < cuts->get(binPt, "pT J/Psi")) { + return false; + } + + // phi mass + if (std::abs(mCandPhi - o2::constants::physics::MassPhi) < cuts->get(binPt, "DeltaM phi")) { + return false; + } + + // J/Psi mass + if (std::abs(candJpsi.m() - o2::constants::physics::MassJPsi) < cuts->get(binPt, "DeltaM J/Psi")) { + return false; + } + + // d0(J/Psi)xd0(phi) + if (candBs.impactParameterProduct() > cuts->get(binPt, "B Imp. Par. Product")) { + return false; + } + + // Bs Decay length + if (candBs.decayLength() < cuts->get(binPt, "B decLen")) { + return false; + } + + // Bs Decay length XY + if (candBs.decayLengthXY() < cuts->get(binPt, "B decLenXY")) { + return false; + } + + // Bs CPA cut + if (candBs.cpa() < cuts->get(binPt, "CPA")) { + return false; + } + + // Bs CPAXY cut + if (candBs.cpaXY() < cuts->get(binPt, "CPAXY")) { + return false; + } + + // d0 of phi + if (std::abs(candBs.impactParameter1()) < cuts->get(binPt, "d0 phi")) { + return false; + } + + // d0 of J/Psi + if (std::abs(candBs.impactParameter0()) < cuts->get(binPt, "d0 J/Psi")) { + return false; + } + + // B pseudoproper decay length + if (pseudoPropDecLen < cuts->get(binPt, "B pseudoprop. decLen")) { + return false; + } + + return true; + } + + /// Apply PID selection + /// \param pidTrackKa PID status of trackKa (prong1 of B+ candidate) + /// \param acceptPIDNotApplicable switch to accept Status::NotApplicable + /// \return true if prong1 of B+ candidate passes all selections + static bool selectionBsToJpsiPhiPid(const int pidTrackKa, const bool acceptPIDNotApplicable) + { + if (!acceptPIDNotApplicable && pidTrackKa != TrackSelectorPID::Accepted) { + return false; + } + if (acceptPIDNotApplicable && pidTrackKa == TrackSelectorPID::Rejected) { + return false; + } + + return true; + } + + /// Apply topological cuts as defined in SelectorCuts.h + /// \param candLb Lb candidate + /// \param cuts Lb candidate selection per pT bin" + /// \param binsPt pT bin limits + /// \return true if candidate passes all selections + template + static bool selectionLbToLcPiTopol(const T1& candLb, const T2& cuts, const T3& binsPt) + { + auto ptCandLb = candLb.pt(); + auto ptLc = candLb.ptProng0(); + auto ptPi = candLb.ptProng1(); + + int pTBin = o2::analysis::findBin(binsPt, ptCandLb); + if (pTBin == -1) { + return false; + } + + // Lb mass cut + if (std::abs(invMassLbToLcPi(candLb) - o2::constants::physics::MassLambdaB0) > cuts->get(pTBin, "m")) { + return false; + } + + // pion pt + if (ptPi < cuts->get(pTBin, "pT Pi")) { + return false; + } + + // Lc pt + if (ptLc < cuts->get(pTBin, "pT Lc+")) { + return false; + } + + // Lb Decay length + if (candLb.decayLength() < cuts->get(pTBin, "Lb decLen")) { + return false; + } + + // Lb Decay length XY + if (candLb.decayLengthXY() < cuts->get(pTBin, "Lb decLenXY")) { + return false; + } + + // Lb chi2PCA cut + if (candLb.chi2PCA() > cuts->get(pTBin, "Chi2PCA")) { + return false; + } + + // Lb CPA cut + if (candLb.cpa() < cuts->get(pTBin, "CPA")) { + return false; + } + + // d0 of pi + if (std::abs(candLb.impactParameter1()) < cuts->get(pTBin, "d0 Pi")) { + return false; + } + + // d0 of Lc + if (std::abs(candLb.impactParameter0()) < cuts->get(pTBin, "d0 Lc+")) { + return false; + } + + return true; + } + + /// \param pidTrackPi PID status of trackPi (prong1 of Lb candidate) + /// \param acceptPIDNotApplicable switch to accept Status::NotApplicable + /// \return true if prong1 of Lb candidate passes all selections + static bool selectionLbToLcPiPid(const int pidTrackPi, const bool acceptPIDNotApplicable) { if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) { return false; @@ -923,35 +1284,58 @@ 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 + static bool applySelectionDmesMlScoresForB(const T1& cuts, const T2& binsPtC, float ptC, const 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; } - private: + /// 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 + static 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 + static 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); + } }; #endif // PWGHF_CORE_HFHELPER_H_ diff --git a/PWGHF/Core/HfMlResponseB0ToDPi.h b/PWGHF/Core/HfMlResponseB0ToDPi.h index 08853a21eac..4874b56543b 100644 --- a/PWGHF/Core/HfMlResponseB0ToDPi.h +++ b/PWGHF/Core/HfMlResponseB0ToDPi.h @@ -9,25 +9,28 @@ // 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 +/// \author Vít Kučera , Inha University #ifndef PWGHF_CORE_HFMLRESPONSEB0TODPI_H_ #define PWGHF_CORE_HFMLRESPONSEB0TODPI_H_ -#include -#include -#include - #include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include // 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,30 +61,13 @@ 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()); +// +// Make FEATURE from an element of VECTOR at INDEX. +#define CHECK_AND_FILL_VEC_B0_INDEX(FEATURE, VECTOR, INDEX) \ + case static_cast(InputFeaturesB0ToDPi::FEATURE): { \ + inputFeatures.emplace_back((VECTOR)[INDEX]); \ + break; \ } - return defaultNSigma; -} -} // namespace o2::pid_tpc_tof_utils namespace o2::analysis { @@ -89,9 +75,12 @@ namespace o2::analysis enum class InputFeaturesB0ToDPi : uint8_t { ptProng0 = 0, ptProng1, + ptProng2, impactParameter0, impactParameter1, + impactParameter2, impactParameterProduct, + impactParameterProngSqSum, chi2PCA, decayLength, decayLengthXY, @@ -105,10 +94,16 @@ enum class InputFeaturesB0ToDPi : uint8_t { prong0MlScoreNonprompt, tpcNSigmaPi1, tofNSigmaPi1, - tpcTofNSigmaPi1 + tpcTofNSigmaPi1, + tpcNSigmaPiBachPi, + tofNSigmaPiBachPi, + tpcTofNSigmaPiBachPi, + tpcNSigmaPiSoftPi, + tofNSigmaPiSoftPi, + tpcTofNSigmaPiSoftPi }; -template +template class HfMlResponseB0ToDPi : public HfMlResponse { public: @@ -123,57 +118,116 @@ class HfMlResponseB0ToDPi : public HfMlResponse /// \return inputFeatures vector template std::vector getInputFeatures(T1 const& candidate, - T2 const& prong1) + T2 const& prongBachPi, + const std::vector* mlScoresD = nullptr) { std::vector inputFeatures; for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + CHECK_AND_FILL_VEC_B0(ptProng0); + CHECK_AND_FILL_VEC_B0(ptProng1); + CHECK_AND_FILL_VEC_B0(impactParameter0); + CHECK_AND_FILL_VEC_B0(impactParameter1); + CHECK_AND_FILL_VEC_B0(impactParameterProduct); + CHECK_AND_FILL_VEC_B0(chi2PCA); + CHECK_AND_FILL_VEC_B0(decayLength); + CHECK_AND_FILL_VEC_B0(decayLengthXY); + CHECK_AND_FILL_VEC_B0(decayLengthNormalised); + CHECK_AND_FILL_VEC_B0(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_B0(cpa); + CHECK_AND_FILL_VEC_B0(cpaXY); + CHECK_AND_FILL_VEC_B0(maxNormalisedDeltaIP); + // TPC PID variable + CHECK_AND_FILL_VEC_B0_FULL(prongBachPi, tpcNSigmaPi1, tpcNSigmaPi); + // TOF PID variable + CHECK_AND_FILL_VEC_B0_FULL(prongBachPi, tofNSigmaPi1, tofNSigmaPi); + // Combined PID variables + CHECK_AND_FILL_VEC_B0_FUNC(prongBachPi, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } if constexpr (withDmesMl) { - switch (idx) { - CHECK_AND_FILL_VEC_B0(ptProng0); - CHECK_AND_FILL_VEC_B0(ptProng1); - CHECK_AND_FILL_VEC_B0(impactParameter0); - CHECK_AND_FILL_VEC_B0(impactParameter1); - CHECK_AND_FILL_VEC_B0(impactParameterProduct); - CHECK_AND_FILL_VEC_B0(chi2PCA); - CHECK_AND_FILL_VEC_B0(decayLength); - CHECK_AND_FILL_VEC_B0(decayLengthXY); - CHECK_AND_FILL_VEC_B0(decayLengthNormalised); - CHECK_AND_FILL_VEC_B0(decayLengthXYNormalised); - CHECK_AND_FILL_VEC_B0(cpa); - CHECK_AND_FILL_VEC_B0(cpaXY); - CHECK_AND_FILL_VEC_B0(maxNormalisedDeltaIP); - CHECK_AND_FILL_VEC_B0(prong0MlScoreBkg); - CHECK_AND_FILL_VEC_B0(prong0MlScorePrompt); - CHECK_AND_FILL_VEC_B0(prong0MlScoreNonprompt); - // TPC PID variable - CHECK_AND_FILL_VEC_B0_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); - // TOF PID variable - CHECK_AND_FILL_VEC_B0_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); - // Combined PID variables - CHECK_AND_FILL_VEC_B0_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + if constexpr (reduced) { + switch (idx) { + CHECK_AND_FILL_VEC_B0(prong0MlScoreBkg); + CHECK_AND_FILL_VEC_B0(prong0MlScorePrompt); + CHECK_AND_FILL_VEC_B0(prong0MlScoreNonprompt); + } + } else { + if (mlScoresD) { + switch (idx) { + CHECK_AND_FILL_VEC_B0_INDEX(prong0MlScoreBkg, *mlScoresD, 0); + CHECK_AND_FILL_VEC_B0_INDEX(prong0MlScorePrompt, *mlScoresD, 1); + CHECK_AND_FILL_VEC_B0_INDEX(prong0MlScoreNonprompt, *mlScoresD, 2); + } + } else { + LOG(fatal) << "ML scores of D not provided"; + } } - } else { - switch (idx) { - CHECK_AND_FILL_VEC_B0(ptProng0); - CHECK_AND_FILL_VEC_B0(ptProng1); - CHECK_AND_FILL_VEC_B0(impactParameter0); - CHECK_AND_FILL_VEC_B0(impactParameter1); - CHECK_AND_FILL_VEC_B0(impactParameterProduct); - CHECK_AND_FILL_VEC_B0(chi2PCA); - CHECK_AND_FILL_VEC_B0(decayLength); - CHECK_AND_FILL_VEC_B0(decayLengthXY); - CHECK_AND_FILL_VEC_B0(decayLengthNormalised); - CHECK_AND_FILL_VEC_B0(decayLengthXYNormalised); - CHECK_AND_FILL_VEC_B0(cpa); - CHECK_AND_FILL_VEC_B0(cpaXY); - CHECK_AND_FILL_VEC_B0(maxNormalisedDeltaIP); - // TPC PID variable - CHECK_AND_FILL_VEC_B0_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); - // TOF PID variable - CHECK_AND_FILL_VEC_B0_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); - // Combined PID variables - CHECK_AND_FILL_VEC_B0_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } + } + + return inputFeatures; + } + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the B0 candidate + /// \param prongBachPi is the candidate's bachelor pion prong + /// \param prongSoftPi is the candidate's soft pion prong + /// \param mlScoresD is the vector of ML scores for the D meson (if available) + /// \note this method is used for B0 → D*∓ π± candidates with D meson ML scores + /// \return inputFeatures vector + template + std::vector getInputFeaturesDStarPi(T1 const& candidate, + T2 const& prongBachPi, + T3 const& prongSoftPi, + const std::vector* mlScoresD = nullptr) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + CHECK_AND_FILL_VEC_B0(ptProng0); + CHECK_AND_FILL_VEC_B0(ptProng1); + CHECK_AND_FILL_VEC_B0(ptProng2); + CHECK_AND_FILL_VEC_B0(impactParameter0); + CHECK_AND_FILL_VEC_B0(impactParameter1); + CHECK_AND_FILL_VEC_B0(impactParameter2); + CHECK_AND_FILL_VEC_B0(impactParameterProngSqSum); + CHECK_AND_FILL_VEC_B0(chi2PCA); + CHECK_AND_FILL_VEC_B0(decayLength); + CHECK_AND_FILL_VEC_B0(decayLengthXY); + CHECK_AND_FILL_VEC_B0(decayLengthNormalised); + CHECK_AND_FILL_VEC_B0(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_B0(cpa); + CHECK_AND_FILL_VEC_B0(cpaXY); + CHECK_AND_FILL_VEC_B0(maxNormalisedDeltaIP); + // TPC PID variable + CHECK_AND_FILL_VEC_B0_FULL(prongBachPi, tpcNSigmaPiBachPi, tpcNSigmaPi); + CHECK_AND_FILL_VEC_B0_FULL(prongSoftPi, tpcNSigmaPiSoftPi, tpcNSigmaPiSoftPi); + // TOF PID variable + CHECK_AND_FILL_VEC_B0_FULL(prongBachPi, tofNSigmaPiBachPi, tofNSigmaPi); + CHECK_AND_FILL_VEC_B0_FULL(prongSoftPi, tofNSigmaPiSoftPi, tofNSigmaPiSoftPi); + // Combined PID variables + CHECK_AND_FILL_VEC_B0_FUNC(prongBachPi, tpcTofNSigmaPiBachPi, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + CHECK_AND_FILL_VEC_B0_FUNC(prongSoftPi, tpcTofNSigmaPiSoftPi, o2::pid_tpc_tof_utils::getTpcTofNSigmaSoftPi); + } + if constexpr (withDmesMl) { + if constexpr (reduced) { + switch (idx) { + CHECK_AND_FILL_VEC_B0(prong0MlScoreBkg); + CHECK_AND_FILL_VEC_B0(prong0MlScorePrompt); + CHECK_AND_FILL_VEC_B0(prong0MlScoreNonprompt); + } + } else { + if (mlScoresD) { + switch (idx) { + CHECK_AND_FILL_VEC_B0_INDEX(prong0MlScoreBkg, *mlScoresD, 0); + CHECK_AND_FILL_VEC_B0_INDEX(prong0MlScorePrompt, *mlScoresD, 1); + CHECK_AND_FILL_VEC_B0_INDEX(prong0MlScoreNonprompt, *mlScoresD, 2); + } + } else { + LOG(fatal) << "ML scores of D not provided"; + } } } } @@ -188,9 +242,12 @@ class HfMlResponseB0ToDPi : public HfMlResponse MlResponse::mAvailableInputFeatures = { FILL_MAP_B0(ptProng0), FILL_MAP_B0(ptProng1), + FILL_MAP_B0(ptProng2), FILL_MAP_B0(impactParameter0), FILL_MAP_B0(impactParameter1), + FILL_MAP_B0(impactParameter2), FILL_MAP_B0(impactParameterProduct), + FILL_MAP_B0(impactParameterProngSqSum), FILL_MAP_B0(chi2PCA), FILL_MAP_B0(decayLength), FILL_MAP_B0(decayLengthXY), @@ -204,10 +261,16 @@ class HfMlResponseB0ToDPi : public HfMlResponse FILL_MAP_B0(prong0MlScoreNonprompt), // TPC PID variable FILL_MAP_B0(tpcNSigmaPi1), + FILL_MAP_B0(tpcNSigmaPiSoftPi), + FILL_MAP_B0(tpcNSigmaPiBachPi), // TOF PID variable FILL_MAP_B0(tofNSigmaPi1), + FILL_MAP_B0(tofNSigmaPiSoftPi), + FILL_MAP_B0(tofNSigmaPiBachPi), // Combined PID variable - FILL_MAP_B0(tpcTofNSigmaPi1)}; + FILL_MAP_B0(tpcTofNSigmaPi1), + FILL_MAP_B0(tpcTofNSigmaPiSoftPi), + FILL_MAP_B0(tpcTofNSigmaPiBachPi)}; } }; diff --git a/PWGHF/Core/HfMlResponseBplusToD0Pi.h b/PWGHF/Core/HfMlResponseBplusToD0Pi.h index 8d47d4ade89..9593101719e 100644 --- a/PWGHF/Core/HfMlResponseBplusToD0Pi.h +++ b/PWGHF/Core/HfMlResponseBplusToD0Pi.h @@ -16,18 +16,22 @@ #ifndef PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PI_H_ #define PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PI_H_ -#include -#include -#include - #include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +#include "Tools/ML/MlResponse.h" + +#include + +#include +#include // 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 < uint8_t>(InputFeaturesBplusToD0Pi::FEATURE) \ +#define FILL_MAP_BPLUS(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesBplusToD0Pi::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -58,30 +62,16 @@ 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()); +// 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::Pdg::kD0) { \ + inputFeatures.emplace_back((candidateD0.GETTER1())[INDEX]); \ + } else { \ + inputFeatures.emplace_back((candidateD0.GETTER2())[INDEX]); \ + } \ + break; \ } - return defaultNSigma; -} -} // namespace o2::pid_tpc_tof_utils namespace o2::analysis { @@ -100,9 +90,9 @@ enum class InputFeaturesBplusToD0Pi : uint8_t { cpa, cpaXY, maxNormalisedDeltaIP, - prong0MlScoreBkg, - prong0MlScorePrompt, - prong0MlScoreNonprompt, + prong0MlProbBkg, + prong0MlProbPrompt, + prong0MlProbNonPrompt, tpcNSigmaPi1, tofNSigmaPi1, tpcTofNSigmaPi1 @@ -121,9 +111,11 @@ class HfMlResponseBplusToD0Pi : public HfMlResponse /// \param candidate is the B+ candidate /// \param prong1 is the candidate's prong1 /// \return inputFeatures vector - template + template std::vector getInputFeatures(T1 const& candidate, - T2 const& prong1) + T2 const& candidateD0, + int const& pdgCode, + T3 const& prong1) { std::vector inputFeatures; @@ -143,9 +135,9 @@ class HfMlResponseBplusToD0Pi : public HfMlResponse 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); + 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 @@ -199,9 +191,9 @@ class HfMlResponseBplusToD0Pi : public HfMlResponse FILL_MAP_BPLUS(cpa), FILL_MAP_BPLUS(cpaXY), FILL_MAP_BPLUS(maxNormalisedDeltaIP), - FILL_MAP_BPLUS(prong0MlScoreBkg), - FILL_MAP_BPLUS(prong0MlScorePrompt), - FILL_MAP_BPLUS(prong0MlScoreNonprompt), + FILL_MAP_BPLUS(prong0MlProbBkg), + FILL_MAP_BPLUS(prong0MlProbPrompt), + FILL_MAP_BPLUS(prong0MlProbNonPrompt), // TPC PID variable FILL_MAP_BPLUS(tpcNSigmaPi1), // TOF PID variable diff --git a/PWGHF/Core/HfMlResponseBplusToD0PiReduced.h b/PWGHF/Core/HfMlResponseBplusToD0PiReduced.h new file mode 100644 index 00000000000..93e2ea67eb4 --- /dev/null +++ b/PWGHF/Core/HfMlResponseBplusToD0PiReduced.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 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 "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include + +// 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/HfMlResponseBplusToJpsiKReduced.h b/PWGHF/Core/HfMlResponseBplusToJpsiKReduced.h new file mode 100644 index 00000000000..85830fcb55b --- /dev/null +++ b/PWGHF/Core/HfMlResponseBplusToJpsiKReduced.h @@ -0,0 +1,184 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file HfMlResponseBplusToJpsiKReduced.h +/// \brief Class to compute the ML response for B± → J/Psi K± analysis selections in the reduced format +/// \author Fabrizio Chinu , Università degli Studi and INFN Torino + +#ifndef PWGHF_CORE_HFMLRESPONSEBPLUSTOJPSIKREDUCED_H_ +#define PWGHF_CORE_HFMLRESPONSEBPLUSTOJPSIKREDUCED_H_ + +#include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +#include "Tools/ML/MlResponse.h" + +#include + +#include +#include + +// 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(InputFeaturesBplusToJpsiKReduced::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(InputFeaturesBplusToJpsiKReduced::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(InputFeaturesBplusToJpsiKReduced::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(InputFeaturesBplusToJpsiKReduced::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +// Specific case of CHECK_AND_FILL_VEC_BPLUS_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate, FEATURE = GETTER, and args are needed +#define CHECK_AND_FILL_VEC_BPLUS_WITH_ARGS(GETTER, ARGS...) \ + case static_cast(InputFeaturesBplusToJpsiKReduced::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER(ARGS)); \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesBplusToJpsiKReduced : uint8_t { + ptProng0 = 0, + ptProng1, + impactParameter0, + impactParameter1, + impactParameter2, + impactParameterProduct, + impactParameterProductJpsi, + chi2PCA, + decayLength, + decayLengthXY, + decayLengthNormalised, + decayLengthXYNormalised, + cpa, + cpaXY, + maxNormalisedDeltaIP, + ctXY, + tpcNSigmaKa1, + tofNSigmaKa1, + tpcTofNSigmaKa1 +}; + +template +class HfMlResponseBplusToJpsiKReduced : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseBplusToJpsiKReduced() = default; + /// Default destructor + virtual ~HfMlResponseBplusToJpsiKReduced() = 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) { + 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(impactParameter2); + CHECK_AND_FILL_VEC_BPLUS(impactParameterProduct); + CHECK_AND_FILL_VEC_BPLUS(impactParameterProductJpsi); + 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_WITH_ARGS(ctXY, std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus}); + // TPC PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tpcNSigmaKa1, tpcNSigmaKa); + // TOF PID variable + CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tofNSigmaKa1, tofNSigmaKa); + // Combined PID variables + CHECK_AND_FILL_VEC_BPLUS_FUNC(prong1, tpcTofNSigmaKa1, o2::pid_tpc_tof_utils::getTpcTofNSigmaKa1); + } + } + + 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(impactParameter2), + FILL_MAP_BPLUS(impactParameterProduct), + FILL_MAP_BPLUS(impactParameterProductJpsi), + 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(ctXY), + // TPC PID variable + FILL_MAP_BPLUS(tpcNSigmaKa1), + // TOF PID variable + FILL_MAP_BPLUS(tofNSigmaKa1), + // Combined PID variable + FILL_MAP_BPLUS(tpcTofNSigmaKa1)}; + } +}; + +} // 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_HFMLRESPONSEBPLUSTOJPSIKREDUCED_H_ diff --git a/PWGHF/Core/HfMlResponseBsToDsPi.h b/PWGHF/Core/HfMlResponseBsToDsPi.h new file mode 100644 index 00000000000..4c472034f71 --- /dev/null +++ b/PWGHF/Core/HfMlResponseBsToDsPi.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 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 "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include + +// 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/HfMlResponseBsToJpsiPhiReduced.h b/PWGHF/Core/HfMlResponseBsToJpsiPhiReduced.h new file mode 100644 index 00000000000..ee9fb5956c7 --- /dev/null +++ b/PWGHF/Core/HfMlResponseBsToJpsiPhiReduced.h @@ -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 HfMlResponseBsToJpsiPhiReduced.h +/// \brief Class to compute the ML response for Bs0 → J/Psi phi analysis selections in the reduced format +/// \author Fabrizio Chinu , Università degli Studi and INFN Torino + +#ifndef PWGHF_CORE_HFMLRESPONSEBSTOJPSIPHIREDUCED_H_ +#define PWGHF_CORE_HFMLRESPONSEBSTOJPSIPHIREDUCED_H_ + +#include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +#include "Tools/ML/MlResponse.h" + +#include + +#include +#include + +// 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(InputFeaturesBsToJpsiPhiReduced::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(InputFeaturesBsToJpsiPhiReduced::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(InputFeaturesBsToJpsiPhiReduced::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(InputFeaturesBsToJpsiPhiReduced::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +// Specific case of CHECK_AND_FILL_VEC_BPLUS_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE = GETTER and args are needed +#define CHECK_AND_FILL_VEC_BS_WITH_ARGS(GETTER, ARGS...) \ + case static_cast(InputFeaturesBsToJpsiPhiReduced::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER(ARGS)); \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesBsToJpsiPhiReduced : uint8_t { + ptProng0 = 0, + ptProng1, + impactParameter0, + impactParameter1, + impactParameter2, + impactParameter3, + impactParameterProduct, + impactParameterProductJpsi, + impactParameterProductPhi, + chi2PCA, + decayLength, + decayLengthXY, + decayLengthNormalised, + decayLengthXYNormalised, + cpa, + cpaXY, + maxNormalisedDeltaIP, + ctXY, + tpcNSigmaKa0, + tofNSigmaKa0, + tpcTofNSigmaKa0, + tpcNSigmaKa1, + tofNSigmaKa1, + tpcTofNSigmaKa1 +}; + +template +class HfMlResponseBsToJpsiPhiReduced : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseBsToJpsiPhiReduced() = default; + /// Default destructor + virtual ~HfMlResponseBsToJpsiPhiReduced() = 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, + T3 const& prong2) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + 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(impactParameter2); + CHECK_AND_FILL_VEC_BS(impactParameter3); + CHECK_AND_FILL_VEC_BS(impactParameterProduct); + CHECK_AND_FILL_VEC_BS(impactParameterProductJpsi); + CHECK_AND_FILL_VEC_BS(impactParameterProductPhi); + 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_WITH_ARGS(ctXY, std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}); + // TPC PID variable + CHECK_AND_FILL_VEC_BS_FULL(prong1, tpcNSigmaKa0, tpcNSigmaKa); + // TOF PID variable + CHECK_AND_FILL_VEC_BS_FULL(prong1, tofNSigmaKa0, tofNSigmaKa); + // Combined PID variables + CHECK_AND_FILL_VEC_BS_FUNC(prong1, tpcTofNSigmaKa0, o2::pid_tpc_tof_utils::getTpcTofNSigmaKa1); + // TPC PID variable + CHECK_AND_FILL_VEC_BS_FULL(prong2, tpcNSigmaKa1, tpcNSigmaKa); + // TOF PID variable + CHECK_AND_FILL_VEC_BS_FULL(prong2, tofNSigmaKa1, tofNSigmaKa); + // Combined PID variables + CHECK_AND_FILL_VEC_BS_FUNC(prong2, tpcTofNSigmaKa1, o2::pid_tpc_tof_utils::getTpcTofNSigmaKa1); + } + } + + 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(impactParameter2), + FILL_MAP_BS(impactParameter3), + FILL_MAP_BS(impactParameterProduct), + FILL_MAP_BS(impactParameterProductJpsi), + FILL_MAP_BS(impactParameterProductPhi), + 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(ctXY), + // TPC PID variable + FILL_MAP_BS(tpcNSigmaKa0), + // TOF PID variable + FILL_MAP_BS(tofNSigmaKa0), + // Combined PID variable + FILL_MAP_BS(tpcTofNSigmaKa0), + // TPC PID variable + FILL_MAP_BS(tpcNSigmaKa1), + // TOF PID variable + FILL_MAP_BS(tofNSigmaKa1), + // Combined PID variable + FILL_MAP_BS(tpcTofNSigmaKa1)}; + } +}; + +} // 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_HFMLRESPONSEBSTOJPSIPHIREDUCED_H_ diff --git a/PWGHF/Core/HfMlResponseD0ToKPi.h b/PWGHF/Core/HfMlResponseD0ToKPi.h index 91790751503..b0c6eaccdd3 100644 --- a/PWGHF/Core/HfMlResponseD0ToKPi.h +++ b/PWGHF/Core/HfMlResponseD0ToKPi.h @@ -17,21 +17,22 @@ #ifndef PWGHF_CORE_HFMLRESPONSED0TOKPI_H_ #define PWGHF_CORE_HFMLRESPONSED0TOKPI_H_ -#include -#include -#include - -#include "CommonConstants/PhysicsConstants.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponse.h" +#include "Tools/ML/MlResponse.h" + +#include + +#include +#include + // 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) @@ -53,26 +54,68 @@ } // Variation of CHECK_AND_FILL_VEC_D0_FULL(OBJECT, FEATURE, GETTER) -// where GETTER is a method of hfHelper +// where GETTER is a method of HfHelper #define CHECK_AND_FILL_VEC_D0_HFHELPER(OBJECT, FEATURE, GETTER) \ case static_cast(InputFeaturesD0ToKPi::FEATURE): { \ - inputFeatures.emplace_back(hfHelper.GETTER(OBJECT)); \ + inputFeatures.emplace_back(HfHelper::GETTER(OBJECT)); \ break; \ } // Variation of CHECK_AND_FILL_VEC_D0_HFHELPER(OBJECT, FEATURE, GETTER) -// where GETTER1 and GETTER2 are methods of hfHelper, and the variable +// 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_HFHELPER_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) \ case static_cast(InputFeaturesD0ToKPi::FEATURE): { \ if (pdgCode == o2::constants::physics::kD0) { \ - inputFeatures.emplace_back(hfHelper.GETTER1(OBJECT)); \ + inputFeatures.emplace_back(HfHelper::GETTER1(OBJECT)); \ } else { \ - inputFeatures.emplace_back(hfHelper.GETTER2(OBJECT)); \ + inputFeatures.emplace_back(HfHelper::GETTER2(OBJECT)); \ } \ 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 +143,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, @@ -117,16 +175,11 @@ class HfMlResponseD0ToKPi : public HfMlResponse /// Default destructor virtual ~HfMlResponseD0ToKPi() = default; - HfHelper hfHelper; - /// 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 +197,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 +261,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 +304,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/HfMlResponseDplusToPiKPi.h b/PWGHF/Core/HfMlResponseDplusToPiKPi.h index 292ddcccb95..fd6085b5ce9 100644 --- a/PWGHF/Core/HfMlResponseDplusToPiKPi.h +++ b/PWGHF/Core/HfMlResponseDplusToPiKPi.h @@ -16,18 +16,19 @@ #ifndef PWGHF_CORE_HFMLRESPONSEDPLUSTOPIKPI_H_ #define PWGHF_CORE_HFMLRESPONSEDPLUSTOPIKPI_H_ -#include -#include -#include - #include "PWGHF/Core/HfMlResponse.h" +#include "Tools/ML/MlResponse.h" + +#include +#include + // 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_DPLUS(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesDplusToPiKPi::FEATURE) \ +#define FILL_MAP_DPLUS(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesDplusToPiKPi::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -104,9 +105,8 @@ class HfMlResponseDplusToPiKPi : public HfMlResponse /// \param prong1 is the candidate's prong1 /// \param prong2 is the candidate's prong2 /// \return inputFeatures vector - template - std::vector getInputFeatures(T1 const& candidate, - T2 const& prong0, T2 const& prong1, T2 const& prong2) + template + std::vector getInputFeatures(T1 const& candidate) { std::vector inputFeatures; @@ -130,26 +130,26 @@ class HfMlResponseDplusToPiKPi : public HfMlResponse CHECK_AND_FILL_VEC_DPLUS(maxNormalisedDeltaIP); CHECK_AND_FILL_VEC_DPLUS(chi2PCA); // TPC PID variables - CHECK_AND_FILL_VEC_DPLUS_FULL(prong0, tpcNSigmaPi0, tpcNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong0, tpcNSigmaKa0, tpcNSigmaKa); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong1, tpcNSigmaKa1, tpcNSigmaKa); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong2, tpcNSigmaPi2, tpcNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong2, tpcNSigmaKa2, tpcNSigmaKa); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcNSigmaPi0, nSigTpcPi0); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcNSigmaKa0, nSigTpcKa0); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcNSigmaPi1, nSigTpcPi1); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcNSigmaKa1, nSigTpcKa1); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcNSigmaPi2, nSigTpcPi2); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcNSigmaKa2, nSigTpcKa2); // TOF PID variables - CHECK_AND_FILL_VEC_DPLUS_FULL(prong0, tofNSigmaPi0, tofNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong0, tofNSigmaKa0, tofNSigmaKa); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong1, tofNSigmaKa1, tofNSigmaKa); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong2, tofNSigmaPi2, tofNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong2, tofNSigmaKa2, tofNSigmaKa); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tofNSigmaPi0, nSigTofPi0); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tofNSigmaKa0, nSigTofKa0); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tofNSigmaPi1, nSigTofPi1); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tofNSigmaKa1, nSigTofKa1); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tofNSigmaPi2, nSigTofPi2); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tofNSigmaKa2, nSigTofKa2); // Combined PID variables - CHECK_AND_FILL_VEC_DPLUS_FULL(prong0, tpcTofNSigmaPi0, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong1, tpcTofNSigmaPi1, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong2, tpcTofNSigmaPi2, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong0, tpcTofNSigmaKa0, tpcTofNSigmaKa); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong1, tpcTofNSigmaKa1, tpcTofNSigmaKa); - CHECK_AND_FILL_VEC_DPLUS_FULL(prong2, tpcTofNSigmaKa2, tpcTofNSigmaKa); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcTofNSigmaPi0, tpcTofNSigmaPi0); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcTofNSigmaPi1, tpcTofNSigmaPi1); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcTofNSigmaPi2, tpcTofNSigmaPi2); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcTofNSigmaKa0, tpcTofNSigmaKa0); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcTofNSigmaKa1, tpcTofNSigmaKa1); + CHECK_AND_FILL_VEC_DPLUS_FULL(candidate, tpcTofNSigmaKa2, tpcTofNSigmaKa2); } } diff --git a/PWGHF/Core/HfMlResponseDsToKKPi.h b/PWGHF/Core/HfMlResponseDsToKKPi.h index 62e93882ddf..4d826944378 100644 --- a/PWGHF/Core/HfMlResponseDsToKKPi.h +++ b/PWGHF/Core/HfMlResponseDsToKKPi.h @@ -16,17 +16,20 @@ #ifndef PWGHF_CORE_HFMLRESPONSEDSTOKKPI_H_ #define PWGHF_CORE_HFMLRESPONSEDSTOKKPI_H_ -#include - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponse.h" +#include "Tools/ML/MlResponse.h" + +#include +#include + // 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_DS(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesDsToKKPi::FEATURE) \ +#define FILL_MAP_DS(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesDsToKKPi::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -48,26 +51,51 @@ } // Variation of CHECK_AND_FILL_VEC_DS_FULL(OBJECT, FEATURE, GETTER) -// where GETTER is a method of hfHelper +// where GETTER is a method of HfHelper #define CHECK_AND_FILL_VEC_DS_HFHELPER(OBJECT, FEATURE, GETTER) \ case static_cast(InputFeaturesDsToKKPi::FEATURE): { \ - inputFeatures.emplace_back(hfHelper.GETTER(OBJECT)); \ + inputFeatures.emplace_back(HfHelper::GETTER(OBJECT)); \ break; \ } // Variation of CHECK_AND_FILL_VEC_DS_HFHELPER(OBJECT, FEATURE, GETTER) -// where GETTER1 and GETTER2 are methods of hfHelper, and the variable +// where GETTER1 and GETTER2 are methods of HfHelper, and the variable // is filled depending on whether it is a DsToKKPi or a DsToPiKK #define CHECK_AND_FILL_VEC_DS_HFHELPER_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) \ case static_cast(InputFeaturesDsToKKPi::FEATURE): { \ if (caseDsToKKPi) { \ - inputFeatures.emplace_back(hfHelper.GETTER1(OBJECT)); \ + inputFeatures.emplace_back(HfHelper::GETTER1(OBJECT)); \ } else { \ - inputFeatures.emplace_back(hfHelper.GETTER2(OBJECT)); \ + inputFeatures.emplace_back(HfHelper::GETTER2(OBJECT)); \ } \ 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; \ + } + +// Variation of CHECK_AND_FILL_VEC_DS_OBJECT_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) +// where GETTER1 and GETTER2 are methods of the OBJECT +#define CHECK_AND_FILL_VEC_DS_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesDsToKKPi::FEATURE): { \ + if (caseDsToKKPi) { \ + inputFeatures.emplace_back(OBJECT.GETTER1()); \ + } else { \ + inputFeatures.emplace_back(OBJECT.GETTER2()); \ + } \ + break; \ + } + namespace o2::analysis { enum class InputFeaturesDsToKKPi : uint8_t { @@ -95,12 +123,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 }; @@ -114,8 +154,6 @@ class HfMlResponseDsToKKPi : public HfMlResponse /// Default destructor virtual ~HfMlResponseDsToKKPi() = default; - HfHelper hfHelper; - /// Method to get the input features vector needed for ML inference /// \param candidate is the Ds candidate /// \param prong0 is the candidate's prong0 @@ -123,9 +161,8 @@ class HfMlResponseDsToKKPi : public HfMlResponse /// \param prong2 is the candidate's prong2 /// \param caseDsToKKPi used to divide the case DsToKKPi from DsToPiKK /// \return inputFeatures vector - template - std::vector getInputFeatures(T1 const& candidate, - T2 const& prong0, T2 const& prong1, T2 const& prong2, bool const& caseDsToKKPi) + template + std::vector getInputFeatures(T1 const& candidate, bool const caseDsToKKPi) { std::vector inputFeatures; @@ -149,20 +186,33 @@ class HfMlResponseDsToKKPi : public HfMlResponse CHECK_AND_FILL_VEC_DS(impactParameterZ0); CHECK_AND_FILL_VEC_DS(impactParameterZ1); CHECK_AND_FILL_VEC_DS(impactParameterZ2); - // TPC PID variables - CHECK_AND_FILL_VEC_DS_FULL(prong0, nSigTpcPi0, tpcNSigmaPi); - CHECK_AND_FILL_VEC_DS_FULL(prong1, nSigTpcPi1, tpcNSigmaPi); - CHECK_AND_FILL_VEC_DS_FULL(prong2, nSigTpcPi2, tpcNSigmaPi); - 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); + // TPC and TOF PID variables + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcPi0, nSigTpcPi0); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcPi1, nSigTpcPi1); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcPi2, nSigTpcPi2); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcKa0, nSigTpcKa0); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcKa1, nSigTpcKa1); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcKa2, nSigTpcKa2); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTofPi0, nSigTofPi0); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTofPi1, nSigTofPi1); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTofPi2, nSigTofPi2); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTofKa0, nSigTofKa0); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTofKa1, nSigTofKa1); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTofKa2, nSigTofKa2); + CHECK_AND_FILL_VEC_DS_SIGNED(candidate, nSigTpcKaExpKa0, nSigTpcKa0, nSigTpcKa2); + CHECK_AND_FILL_VEC_DS_SIGNED(candidate, nSigTpcPiExpPi2, nSigTpcPi2, nSigTpcPi0); + CHECK_AND_FILL_VEC_DS_SIGNED(candidate, nSigTofKaExpKa0, nSigTofKa0, nSigTofKa2); + CHECK_AND_FILL_VEC_DS_SIGNED(candidate, nSigTofPiExpPi2, nSigTofPi2, nSigTofPi0); + // Combined PID variables - CHECK_AND_FILL_VEC_DS_FULL(prong0, nSigTpcTofPi0, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_DS_FULL(prong1, nSigTpcTofPi1, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_DS_FULL(prong2, nSigTpcTofPi2, tpcTofNSigmaPi); - 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_FULL(candidate, nSigTpcTofPi0, tpcTofNSigmaPi0); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcTofPi1, tpcTofNSigmaPi1); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcTofPi2, tpcTofNSigmaPi2); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcTofKa0, tpcTofNSigmaKa0); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcTofKa1, tpcTofNSigmaKa1); + CHECK_AND_FILL_VEC_DS_FULL(candidate, nSigTpcTofKa2, tpcTofNSigmaKa2); + CHECK_AND_FILL_VEC_DS_SIGNED(candidate, nSigTpcTofKaExpKa0, tpcTofNSigmaKa0, tpcTofNSigmaKa2); + CHECK_AND_FILL_VEC_DS_SIGNED(candidate, nSigTpcTofPiExpPi2, tpcTofNSigmaPi2, tpcTofNSigmaPi0); // Ds specific variables CHECK_AND_FILL_VEC_DS_HFHELPER_SIGNED(candidate, absCos3PiK, absCos3PiKDsToKKPi, absCos3PiKDsToPiKK); @@ -193,6 +243,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 +253,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 +270,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 +286,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 b583d93ed88..f83c9114feb 100644 --- a/PWGHF/Core/HfMlResponseDstarToD0Pi.h +++ b/PWGHF/Core/HfMlResponseDstarToD0Pi.h @@ -16,19 +16,21 @@ #ifndef PWGHF_CORE_HFMLRESPONSEDSTARTOD0PI_H_ #define PWGHF_CORE_HFMLRESPONSEDSTARTOD0PI_H_ -#include -#include -#include - #include "PWGHF/Core/HfMlResponse.h" -#include "CommonConstants/PhysicsConstants.h" + +#include "Tools/ML/MlResponse.h" + +#include + +#include +#include // 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_DSTAR(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesDstarToD0Pi::FEATURE) \ +#define FILL_MAP_DSTAR(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesDstarToD0Pi::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -49,16 +51,36 @@ break; \ } +// Specific case of CHECK_AND_FILL_VEC_DSTAR_FULL(OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE != GETTER +#define CHECK_AND_FILL_VEC_DSTAR_GETTER(FEATURE, GETTER) \ + case static_cast(InputFeaturesDstarToD0Pi::FEATURE): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + // Very specific case of CHECK_AND_FILL_VEC_DSTAR_FULL(OBJECT, FEATURE, GETTER) // Use for push back different value for D*+ or D*- candidate -#define CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(POSGETTER, NEGGETTER, FEATURENAME) \ - case static_cast(InputFeaturesDstarToD0Pi::FEATURENAME): { \ - if (candidate.signSoftPi() > 0) { \ - inputFeatures.emplace_back(candidate.POSGETTER()); \ - } else { \ - inputFeatures.emplace_back(candidate.NEGGETTER()); \ - } \ - break; \ +#define CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(POSGETTER, NEGGETTER, FEATURENAME, SWAP) \ + case static_cast(InputFeaturesDstarToD0Pi::FEATURENAME): { \ + if (candidate.signSoftPi() > 0 || !SWAP) { \ + inputFeatures.emplace_back(candidate.POSGETTER()); \ + } else { \ + inputFeatures.emplace_back(candidate.NEGGETTER()); \ + } \ + 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, SWAP) \ + case static_cast(InputFeaturesDstarToD0Pi::FEATURENAME): { \ + if (candidate.signSoftPi() > 0 || !SWAP) { \ + 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) @@ -91,6 +113,8 @@ enum class InputFeaturesDstarToD0Pi : uint8_t { ptSoftPi, impactParameter0, impactParameter1, + impactParameterXY0, + impactParameterXY1, impactParameterZ0, impactParameterZ1, impParamSoftPi, @@ -139,9 +163,8 @@ class HfMlResponseDstarToD0Pi : public HfMlResponse /// \param prong1 is the candidate's prong1 /// \param prongSoftPi is the candidate's prongSoftPi /// \return inputFeatures vector - template - std::vector getInputFeatures(T1 const& candidate, - T2 const& prong0, T2 const& prong1, T2 const& prongSoftPi) + template + std::vector getInputFeatures(T1 const& candidate, bool swapDzeroDaus = true) { std::vector inputFeatures; @@ -156,42 +179,42 @@ 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, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(ptProng1, ptProng0, ptProng1, swapDzeroDaus); CHECK_AND_FILL_VEC_DSTAR(ptSoftPi); - CHECK_AND_FILL_VEC_DSTAR(impactParameter0); - CHECK_AND_FILL_VEC_DSTAR(impactParameter1); - CHECK_AND_FILL_VEC_DSTAR(impactParameterZ0); - CHECK_AND_FILL_VEC_DSTAR(impactParameterZ1); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameter0, impactParameter1, impactParameter0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameter1, impactParameter0, impactParameter1, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterZ0, impactParameterZ1, impactParameterZ0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterZ1, impactParameterZ0, impactParameterZ1, swapDzeroDaus); CHECK_AND_FILL_VEC_DSTAR(impParamSoftPi); CHECK_AND_FILL_VEC_DSTAR(impParamZSoftPi); - CHECK_AND_FILL_VEC_DSTAR(impactParameterNormalised0); - CHECK_AND_FILL_VEC_DSTAR(impactParameterNormalised1); - CHECK_AND_FILL_VEC_DSTAR(impactParameterZNormalised0); - CHECK_AND_FILL_VEC_DSTAR(impactParameterZNormalised1); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterNormalised0, impactParameterNormalised1, impactParameterNormalised0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterNormalised1, impactParameterNormalised0, impactParameterNormalised1, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterZNormalised0, impactParameterZNormalised1, impactParameterZNormalised0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(impactParameterZNormalised1, impactParameterZNormalised0, impactParameterZNormalised1, swapDzeroDaus); 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_CHARGEBASE(cosThetaStarD0, cosThetaStarD0Bar, cosThetaStarD0, true); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(invMassD0, invMassD0Bar, massD0, true); 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_FULL(prongSoftPi, nSigmaTPCPiPrSoftPi, tpcNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prongSoftPi, nSigmaTPCKaPrSoftPi, tpcNSigmaKa); - CHECK_AND_FILL_VEC_DSTAR_FULL(prongSoftPi, nSigmaTOFPiPrSoftPi, tofNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prongSoftPi, nSigmaTOFKaPrSoftPi, tofNSigmaKa); - CHECK_AND_FILL_VEC_DSTAR_FULL(prongSoftPi, nSigmaTPCTOFPiPrSoftPi, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_DSTAR_FULL(prongSoftPi, nSigmaTPCTOFKaPrSoftPi, tpcTofNSigmaKa); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(nSigTpcPi0, nSigTpcPi1, nSigmaTPCPiPr0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(nSigTpcKa0, nSigTpcKa1, nSigmaTPCKaPr0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(nSigTofPi0, nSigTofPi1, nSigmaTOFPiPr0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(nSigTofKa0, nSigTofKa1, nSigmaTOFKaPr0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(tpcTofNSigmaPi0, tpcTofNSigmaPi1, nSigmaTPCTOFPiPr0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(tpcTofNSigmaKa0, tpcTofNSigmaKa1, nSigmaTPCTOFKaPr0, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(nSigTpcPi1, nSigTpcPi0, nSigmaTPCPiPr1, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(nSigTpcKa1, nSigTpcKa0, nSigmaTPCKaPr1, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(nSigTofPi1, nSigTofPi0, nSigmaTOFPiPr1, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(nSigTofKa1, nSigTofKa0, nSigmaTOFKaPr1, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(tpcTofNSigmaPi1, tpcTofNSigmaPi0, nSigmaTPCTOFPiPr1, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE(tpcTofNSigmaKa1, tpcTofNSigmaKa0, nSigmaTPCTOFKaPr1, swapDzeroDaus); + CHECK_AND_FILL_VEC_DSTAR_GETTER(nSigmaTPCPiPrSoftPi, nSigTpcPi2); + CHECK_AND_FILL_VEC_DSTAR_GETTER(nSigmaTPCKaPrSoftPi, nSigTpcKa2); + CHECK_AND_FILL_VEC_DSTAR_GETTER(nSigmaTOFPiPrSoftPi, nSigTofPi2); + CHECK_AND_FILL_VEC_DSTAR_GETTER(nSigmaTOFKaPrSoftPi, nSigTofKa2); + CHECK_AND_FILL_VEC_DSTAR_GETTER(nSigmaTPCTOFPiPrSoftPi, tpcTofNSigmaPi2); + CHECK_AND_FILL_VEC_DSTAR_GETTER(nSigmaTPCTOFKaPrSoftPi, tpcTofNSigmaKa2); } } @@ -217,6 +240,8 @@ class HfMlResponseDstarToD0Pi : public HfMlResponse FILL_MAP_DSTAR(ptSoftPi), FILL_MAP_DSTAR(impactParameter0), FILL_MAP_DSTAR(impactParameter1), + FILL_MAP_DSTAR(impactParameterXY0), + FILL_MAP_DSTAR(impactParameterXY1), FILL_MAP_DSTAR(impactParameterZ0), FILL_MAP_DSTAR(impactParameterZ1), FILL_MAP_DSTAR(impParamSoftPi), @@ -258,5 +283,6 @@ class HfMlResponseDstarToD0Pi : public HfMlResponse #undef CHECK_AND_FILL_VEC_DSTAR #undef CHECK_AND_FILL_VEC_DSTAR_CHARGEBASE #undef CHECK_AND_FILL_VEC_DSTAR_DELTA_MASS_D0 +#undef CHECK_AND_FILL_VEC_DSTAR_GETTER #endif // PWGHF_CORE_HFMLRESPONSEDSTARTOD0PI_H_ diff --git a/PWGHF/Core/HfMlResponseLbToLcPi.h b/PWGHF/Core/HfMlResponseLbToLcPi.h new file mode 100644 index 00000000000..8375e8cf5ea --- /dev/null +++ b/PWGHF/Core/HfMlResponseLbToLcPi.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 HfMlResponseLbToLcPi.h +/// \brief Class to compute the ML response for Lb → Lc∓ π± analysis selections +/// \author Biao Zhang , Heidelberg University + +#ifndef PWGHF_CORE_HFMLRESPONSELBTOLCPI_H_ +#define PWGHF_CORE_HFMLRESPONSELBTOLCPI_H_ + +#include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include + +// 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_LB(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesLbToLcPi::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_LB_FULL(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesLbToLcPi::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_LB_FUNC(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesLbToLcPi::FEATURE): { \ + inputFeatures.emplace_back(GETTER(OBJECT)); \ + break; \ + } + +// Specific case of (OBJECT, FEATURE, GETTER) +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_VEC_LB(GETTER) \ + case static_cast(InputFeaturesLbToLcPi::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesLbToLcPi : uint8_t { + ptProng0 = 0, + ptProng1, + impactParameter0, + impactParameter1, + impactParameterProduct, + chi2PCA, + decayLength, + decayLengthXY, + decayLengthNormalised, + decayLengthXYNormalised, + cpa, + cpaXY, + maxNormalisedDeltaIP, + prong0MlScoreBkg, + prong0MlScorePrompt, + prong0MlScoreNonprompt, + tpcNSigmaPi1, + tofNSigmaPi1, + tpcTofNSigmaPi1 +}; + +template +class HfMlResponseLbToLcPi : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseLbToLcPi() = default; + /// Default destructor + virtual ~HfMlResponseLbToLcPi() = default; + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the Lb 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_LB(ptProng0); + CHECK_AND_FILL_VEC_LB(ptProng1); + CHECK_AND_FILL_VEC_LB(impactParameter0); + CHECK_AND_FILL_VEC_LB(impactParameter1); + CHECK_AND_FILL_VEC_LB(impactParameterProduct); + CHECK_AND_FILL_VEC_LB(chi2PCA); + CHECK_AND_FILL_VEC_LB(decayLength); + CHECK_AND_FILL_VEC_LB(decayLengthXY); + CHECK_AND_FILL_VEC_LB(decayLengthNormalised); + CHECK_AND_FILL_VEC_LB(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_LB(cpa); + CHECK_AND_FILL_VEC_LB(cpaXY); + CHECK_AND_FILL_VEC_LB(maxNormalisedDeltaIP); + CHECK_AND_FILL_VEC_LB(prong0MlScoreBkg); + CHECK_AND_FILL_VEC_LB(prong0MlScorePrompt); + CHECK_AND_FILL_VEC_LB(prong0MlScoreNonprompt); + // TPC PID variable + CHECK_AND_FILL_VEC_LB_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); + // TOF PID variable + CHECK_AND_FILL_VEC_LB_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); + // Combined PID variables + CHECK_AND_FILL_VEC_LB_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1); + } + } else { + switch (idx) { + CHECK_AND_FILL_VEC_LB(ptProng0); + CHECK_AND_FILL_VEC_LB(ptProng1); + CHECK_AND_FILL_VEC_LB(impactParameter0); + CHECK_AND_FILL_VEC_LB(impactParameter1); + CHECK_AND_FILL_VEC_LB(impactParameterProduct); + CHECK_AND_FILL_VEC_LB(chi2PCA); + CHECK_AND_FILL_VEC_LB(decayLength); + CHECK_AND_FILL_VEC_LB(decayLengthXY); + CHECK_AND_FILL_VEC_LB(decayLengthNormalised); + CHECK_AND_FILL_VEC_LB(decayLengthXYNormalised); + CHECK_AND_FILL_VEC_LB(cpa); + CHECK_AND_FILL_VEC_LB(cpaXY); + CHECK_AND_FILL_VEC_LB(maxNormalisedDeltaIP); + // TPC PID variable + CHECK_AND_FILL_VEC_LB_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); + // TOF PID variable + CHECK_AND_FILL_VEC_LB_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); + // Combined PID variables + CHECK_AND_FILL_VEC_LB_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_LB(ptProng0), + FILL_MAP_LB(ptProng1), + FILL_MAP_LB(impactParameter0), + FILL_MAP_LB(impactParameter1), + FILL_MAP_LB(impactParameterProduct), + FILL_MAP_LB(chi2PCA), + FILL_MAP_LB(decayLength), + FILL_MAP_LB(decayLengthXY), + FILL_MAP_LB(decayLengthNormalised), + FILL_MAP_LB(decayLengthXYNormalised), + FILL_MAP_LB(cpa), + FILL_MAP_LB(cpaXY), + FILL_MAP_LB(maxNormalisedDeltaIP), + FILL_MAP_LB(prong0MlScoreBkg), + FILL_MAP_LB(prong0MlScorePrompt), + FILL_MAP_LB(prong0MlScoreNonprompt), + // TPC PID variable + FILL_MAP_LB(tpcNSigmaPi1), + // TOF PID variable + FILL_MAP_LB(tofNSigmaPi1), + // Combined PID variable + FILL_MAP_LB(tpcTofNSigmaPi1)}; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_LB +#undef CHECK_AND_FILL_VEC_LB_FULL +#undef CHECK_AND_FILL_VEC_LB_FUNC +#undef CHECK_AND_FILL_VEC_LB + +#endif // PWGHF_CORE_HFMLRESPONSELBTOLCPI_H_ diff --git a/PWGHF/Core/HfMlResponseLcToK0sP.h b/PWGHF/Core/HfMlResponseLcToK0sP.h index 2dc78cb19d1..4e6899bf3aa 100644 --- a/PWGHF/Core/HfMlResponseLcToK0sP.h +++ b/PWGHF/Core/HfMlResponseLcToK0sP.h @@ -17,19 +17,20 @@ #ifndef PWGHF_CORE_HFMLRESPONSELCTOK0SP_H_ #define PWGHF_CORE_HFMLRESPONSELCTOK0SP_H_ -#include -#include -#include - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponse.h" +#include "Tools/ML/MlResponse.h" + +#include +#include + // 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_LC(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesLcToK0sP::FEATURE) \ +#define FILL_MAP_LC(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesLcToK0sP::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -51,10 +52,10 @@ } // Variation of CHECK_AND_FILL_VEC_LC_FULL(OBJECT, FEATURE, GETTER) -// where GETTER is a method of hfHelper +// where GETTER is a method of HfHelper #define CHECK_AND_FILL_VEC_LC_HFHELPER(OBJECT, FEATURE, GETTER) \ case static_cast(InputFeaturesLcToK0sP::FEATURE): { \ - inputFeatures.emplace_back(hfHelper.GETTER(OBJECT)); \ + inputFeatures.emplace_back(HfHelper::GETTER(OBJECT)); \ break; \ } @@ -103,8 +104,6 @@ class HfMlResponseLcToK0sP : public HfMlResponse /// Default destructor virtual ~HfMlResponseLcToK0sP() = default; - HfHelper hfHelper; - /// Method to get the input features vector needed for ML inference /// \param candidate is the Lc candidate /// \param bach is the bachelor candidate (proton) diff --git a/PWGHF/Core/HfMlResponseLcToPKPi.h b/PWGHF/Core/HfMlResponseLcToPKPi.h index e011567c4d6..e9fe8ff2221 100644 --- a/PWGHF/Core/HfMlResponseLcToPKPi.h +++ b/PWGHF/Core/HfMlResponseLcToPKPi.h @@ -16,16 +16,22 @@ #ifndef PWGHF_CORE_HFMLRESPONSELCTOPKPI_H_ #define PWGHF_CORE_HFMLRESPONSELCTOPKPI_H_ -#include - #include "PWGHF/Core/HfMlResponse.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include +#include +#include // 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_LCTOPKPI(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesLcToPKPi::FEATURE) \ +#define FILL_MAP_LCTOPKPI(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesLcToPKPi::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -47,13 +53,38 @@ } // Variation of CHECK_AND_FILL_VEC_LCTOPKPI_FULL(OBJECT, FEATURE, GETTER) -// where GETTER is a method of hfHelper +// where GETTER is a method of HfHelper #define CHECK_AND_FILL_VEC_LCTOPKPI_HFHELPER(OBJECT, FEATURE, GETTER) \ case static_cast(InputFeaturesLcToPKPi::FEATURE): { \ - inputFeatures.emplace_back(hfHelper.GETTER(OBJECT)); \ + inputFeatures.emplace_back(HfHelper::GETTER(OBJECT)); \ 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; \ + } + +// Variation of CHECK_AND_FILL_VEC_LCTOPKPI_HFHELPER_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) +// where GETTER1 and GETTER2 are methods of the OBJECT +#define CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesLcToPKPi::FEATURE): { \ + if (caseLcToPKPi) { \ + inputFeatures.emplace_back(OBJECT.GETTER1()); \ + } else { \ + inputFeatures.emplace_back(OBJECT.GETTER2()); \ + } \ + break; \ + } + namespace o2::analysis { enum class InputFeaturesLcToPKPi : uint8_t { @@ -72,22 +103,22 @@ enum class InputFeaturesLcToPKPi : uint8_t { cpa, cpaXY, chi2PCA, - tpcNSigmaP0, // 0 + tpcNSigmaPr0, // 0 tpcNSigmaKa0, // 0 tpcNSigmaPi0, // 0 - tpcNSigmaP1, // 1 + tpcNSigmaPr1, // 1 tpcNSigmaKa1, // 1 tpcNSigmaPi1, // 1 - tpcNSigmaP2, // 2 + tpcNSigmaPr2, // 2 tpcNSigmaKa2, // 2 tpcNSigmaPi2, // 2 - tofNSigmaP0, // + tofNSigmaPr0, // tofNSigmaKa0, // tofNSigmaPi0, // - tofNSigmaP1, + tofNSigmaPr1, tofNSigmaKa1, tofNSigmaPi1, - tofNSigmaP2, + tofNSigmaPr2, tofNSigmaKa2, tofNSigmaPi2, tpcTofNSigmaPi0, @@ -98,10 +129,28 @@ enum class InputFeaturesLcToPKPi : uint8_t { tpcTofNSigmaKa2, tpcTofNSigmaPr0, tpcTofNSigmaPr1, - tpcTofNSigmaPr2 + tpcTofNSigmaPr2, + tpcNSigmaPrExpPr0, + tpcNSigmaPiExpPi2, + tofNSigmaPrExpPr0, + tofNSigmaPiExpPi2, + tpcTofNSigmaPrExpPr0, + tpcTofNSigmaPiExpPi2, + kfChi2PrimProton, + kfChi2PrimKaon, + kfChi2PrimPion, + kfChi2GeoKaonPion, + kfChi2GeoProtonPion, + kfChi2GeoProtonKaon, + kfDcaKaonPion, + kfDcaProtonPion, + kfDcaProtonKaon, + kfChi2Geo, + kfChi2Topo, + kfDecayLengthNormalised }; -template +template class HfMlResponseLcToPKPi : public HfMlResponse { public: @@ -116,9 +165,8 @@ class HfMlResponseLcToPKPi : public HfMlResponse /// \param prong1 is the candidate's prong1 /// \param prong2 is the candidate's prong2 /// \return inputFeatures vector - template - std::vector getInputFeatures(T1 const& candidate, - T2 const& prong0, T2 const& prong1, T2 const& prong2) + template + std::vector getInputFeatures(T1 const& candidate, bool const caseLcToPKPi) { std::vector inputFeatures; @@ -140,38 +188,62 @@ class HfMlResponseLcToPKPi : public HfMlResponse CHECK_AND_FILL_VEC_LCTOPKPI(cpaXY); CHECK_AND_FILL_VEC_LCTOPKPI(chi2PCA); // TPC PID variables - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tpcNSigmaP0, tpcNSigmaPr); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tpcNSigmaKa0, tpcNSigmaKa); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tpcNSigmaPi0, tpcNSigmaPi); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tpcNSigmaP1, tpcNSigmaPr); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tpcNSigmaKa1, tpcNSigmaKa); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); - 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_FULL(candidate, tpcNSigmaPr0, nSigTpcPr0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcNSigmaKa0, nSigTpcKa0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcNSigmaPi0, nSigTpcPi0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcNSigmaPr1, nSigTpcPr1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcNSigmaKa1, nSigTpcKa1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcNSigmaPi1, nSigTpcPi1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcNSigmaPr2, nSigTpcPr2); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcNSigmaKa2, nSigTpcKa2); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcNSigmaPi2, nSigTpcPi2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, tpcNSigmaPrExpPr0, nSigTpcPr0, nSigTpcPr2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, tpcNSigmaPiExpPi2, nSigTpcPi2, nSigTpcPi0); // TOF PID variables - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tofNSigmaP0, tofNSigmaPr); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tofNSigmaKa0, tofNSigmaKa); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tofNSigmaPi0, tofNSigmaPi); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tofNSigmaP1, tofNSigmaPr); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tofNSigmaKa1, tofNSigmaKa); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); - 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_FULL(candidate, tofNSigmaPr0, nSigTofPr0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tofNSigmaKa0, nSigTofKa0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tofNSigmaPi0, nSigTofPi0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tofNSigmaPr1, nSigTofPr1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tofNSigmaKa1, nSigTofKa1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tofNSigmaPi1, nSigTofPi1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tofNSigmaPr2, nSigTofPr2); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tofNSigmaKa2, nSigTofKa2); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tofNSigmaPi2, nSigTofPi2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, tofNSigmaPrExpPr0, nSigTofPr0, nSigTofPr2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, tofNSigmaPiExpPi2, nSigTofPi2, nSigTofPi0); // Combined PID variables - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tpcTofNSigmaPi0, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tpcTofNSigmaPi1, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tpcTofNSigmaPi2, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong0, tpcTofNSigmaKa0, tpcTofNSigmaKa); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong1, tpcTofNSigmaKa1, tpcTofNSigmaKa); - CHECK_AND_FILL_VEC_LCTOPKPI_FULL(prong2, tpcTofNSigmaKa2, tpcTofNSigmaKa); - 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_FULL(candidate, tpcTofNSigmaPi0, tpcTofNSigmaPi0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcTofNSigmaPi1, tpcTofNSigmaPi1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcTofNSigmaPi2, tpcTofNSigmaPi2); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcTofNSigmaKa0, tpcTofNSigmaKa0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcTofNSigmaKa1, tpcTofNSigmaKa1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcTofNSigmaKa2, tpcTofNSigmaKa2); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcTofNSigmaPr0, tpcTofNSigmaPr0); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcTofNSigmaPr1, tpcTofNSigmaPr1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, tpcTofNSigmaPr2, tpcTofNSigmaPr2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, tpcTofNSigmaPrExpPr0, tpcTofNSigmaPr0, tpcTofNSigmaPr2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, tpcTofNSigmaPiExpPi2, tpcTofNSigmaPi2, tpcTofNSigmaPi0); + } + if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + switch (idx) { + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, kfChi2PrimProton, kfChi2PrimProng0, kfChi2PrimProng2); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, kfChi2PrimKaon, kfChi2PrimProng1); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, kfChi2PrimPion, kfChi2PrimProng2, kfChi2PrimProng0); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, kfChi2GeoKaonPion, kfChi2GeoProng1Prong2, kfChi2GeoProng0Prong1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, kfChi2GeoProtonPion, kfChi2GeoProng0Prong2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, kfChi2GeoProtonKaon, kfChi2GeoProng0Prong1, kfChi2GeoProng1Prong2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, kfDcaKaonPion, kfDcaProng1Prong2, kfDcaProng0Prong1); + CHECK_AND_FILL_VEC_LCTOPKPI_FULL(candidate, kfDcaProtonPion, kfDcaProng0Prong2); + CHECK_AND_FILL_VEC_LCTOPKPI_SIGNED(candidate, kfDcaProtonKaon, kfDcaProng0Prong1, kfDcaProng1Prong2); + CHECK_AND_FILL_VEC_LCTOPKPI(kfChi2Geo); + CHECK_AND_FILL_VEC_LCTOPKPI(kfChi2Topo); + case static_cast(InputFeaturesLcToPKPi::kfDecayLengthNormalised): { + inputFeatures.emplace_back(candidate.kfDecayLength() / candidate.kfDecayLengthError()); + break; + } + } } } - return inputFeatures; } @@ -196,25 +268,29 @@ class HfMlResponseLcToPKPi : public HfMlResponse FILL_MAP_LCTOPKPI(cpaXY), FILL_MAP_LCTOPKPI(chi2PCA), // TPC PID variables - FILL_MAP_LCTOPKPI(tpcNSigmaP0), + FILL_MAP_LCTOPKPI(tpcNSigmaPr0), FILL_MAP_LCTOPKPI(tpcNSigmaKa0), FILL_MAP_LCTOPKPI(tpcNSigmaPi0), - FILL_MAP_LCTOPKPI(tpcNSigmaP1), + FILL_MAP_LCTOPKPI(tpcNSigmaPr1), FILL_MAP_LCTOPKPI(tpcNSigmaKa1), FILL_MAP_LCTOPKPI(tpcNSigmaPi1), - FILL_MAP_LCTOPKPI(tpcNSigmaP2), + FILL_MAP_LCTOPKPI(tpcNSigmaPr2), 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(tofNSigmaPr0), FILL_MAP_LCTOPKPI(tofNSigmaKa0), FILL_MAP_LCTOPKPI(tofNSigmaPi0), - FILL_MAP_LCTOPKPI(tofNSigmaP1), + FILL_MAP_LCTOPKPI(tofNSigmaPr1), FILL_MAP_LCTOPKPI(tofNSigmaKa1), FILL_MAP_LCTOPKPI(tofNSigmaPi1), - FILL_MAP_LCTOPKPI(tofNSigmaP2), + FILL_MAP_LCTOPKPI(tofNSigmaPr2), 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 +300,26 @@ 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)}; + if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + std::map mapKfFeatures{ + // KFParticle variables + FILL_MAP_LCTOPKPI(kfChi2PrimProton), + FILL_MAP_LCTOPKPI(kfChi2PrimKaon), + FILL_MAP_LCTOPKPI(kfChi2PrimPion), + FILL_MAP_LCTOPKPI(kfChi2GeoKaonPion), + FILL_MAP_LCTOPKPI(kfChi2GeoProtonPion), + FILL_MAP_LCTOPKPI(kfChi2GeoProtonKaon), + FILL_MAP_LCTOPKPI(kfDcaKaonPion), + FILL_MAP_LCTOPKPI(kfDcaProtonPion), + FILL_MAP_LCTOPKPI(kfDcaProtonKaon), + FILL_MAP_LCTOPKPI(kfChi2Geo), + FILL_MAP_LCTOPKPI(kfChi2Topo), + FILL_MAP_LCTOPKPI(kfDecayLengthNormalised)}; + MlResponse::mAvailableInputFeatures.insert(mapKfFeatures.begin(), mapKfFeatures.end()); + } } }; @@ -234,5 +329,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..ed78d100b07 --- /dev/null +++ b/PWGHF/Core/HfMlResponseOmegacToOmegaPi.h @@ -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. + +/// \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 "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponse.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include + +// 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, + chi2TopoPiFromOmegacToPv, + dcaCharmBaryonDau, + invMassCascade, + massCascChi2OverNdf, + kfDcaXYCascToPv, + cosPaCascToPv, + cosThetaStarPiFromOmegac, + chi2NdfTopoOmegacToPv, + ldlCasc, + dcaCascDau, + cosPaCascToOmegac, + decayLenXYCasc, + ldlOmegac, + chi2NdfTopoCascToOmegac, + chi2NdfTopoCascToPv, + chi2GeoOmegac, + chi2GeoCasc, + + nSigmaTPCPiFromV0, + nSigmaTPCPiFromOmegac, + nSigmaTPCKaFromCasc + +}; + +template +class HfMlResponseOmegacToOmegaPi : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseOmegacToOmegaPi() = default; + /// Default destructor + virtual ~HfMlResponseOmegacToOmegaPi() = default; + + /// 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_FULL(candidate, cosPaOmegacToPv, cosPACharmBaryon); + CHECK_AND_FILL_VEC_OMEGAC0(kfDcaXYPiFromOmegac); + 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, cosPaCascToPv, cosPACasc); + CHECK_AND_FILL_VEC_OMEGAC0(cosThetaStarPiFromOmegac); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(candidate, chi2NdfTopoOmegacToPv, chi2TopoOmegacToPv); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(candidate, ldlCasc, cascldl); + CHECK_AND_FILL_VEC_OMEGAC0(dcaCascDau); + CHECK_AND_FILL_VEC_OMEGAC0(cosPaCascToOmegac); + CHECK_AND_FILL_VEC_OMEGAC0(decayLenXYCasc); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(candidate, ldlOmegac, omegacldl); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(candidate, chi2NdfTopoCascToOmegac, chi2TopoCascToOmegac); + CHECK_AND_FILL_VEC_OMEGAC0_FULL(candidate, chi2NdfTopoCascToPv, chi2TopoCascToPv); + CHECK_AND_FILL_VEC_OMEGAC0(chi2GeoOmegac); + CHECK_AND_FILL_VEC_OMEGAC0(chi2GeoCasc); + + // 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(cosPaOmegacToPv), + FILL_MAP_OMEGAC0(kfDcaXYPiFromOmegac), + FILL_MAP_OMEGAC0(chi2TopoPiFromOmegacToPv), + FILL_MAP_OMEGAC0(dcaCharmBaryonDau), + FILL_MAP_OMEGAC0(invMassCascade), + FILL_MAP_OMEGAC0(massCascChi2OverNdf), + FILL_MAP_OMEGAC0(kfDcaXYCascToPv), + FILL_MAP_OMEGAC0(cosPaCascToPv), + FILL_MAP_OMEGAC0(cosThetaStarPiFromOmegac), + FILL_MAP_OMEGAC0(chi2NdfTopoOmegacToPv), + FILL_MAP_OMEGAC0(ldlCasc), + FILL_MAP_OMEGAC0(dcaCascDau), + FILL_MAP_OMEGAC0(cosPaCascToOmegac), + FILL_MAP_OMEGAC0(decayLenXYCasc), + FILL_MAP_OMEGAC0(ldlOmegac), + FILL_MAP_OMEGAC0(chi2NdfTopoCascToOmegac), + FILL_MAP_OMEGAC0(chi2NdfTopoCascToPv), + FILL_MAP_OMEGAC0(chi2GeoOmegac), + FILL_MAP_OMEGAC0(chi2GeoCasc), + + 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/HfMlResponseXic0ToXiPi.h b/PWGHF/Core/HfMlResponseXic0ToXiPi.h new file mode 100644 index 00000000000..88c402617f8 --- /dev/null +++ b/PWGHF/Core/HfMlResponseXic0ToXiPi.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. + +/// \file HfMlResponseXic0ToXiPi.h +/// \brief Class to compute the ML response for Ξc^0 → Ξ∓ π± analysis selections +/// \author Tao Fang , Central China Normal University + +#ifndef PWGHF_CORE_HFMLRESPONSEXIC0TOXIPI_H_ +#define PWGHF_CORE_HFMLRESPONSEXIC0TOXIPI_H_ + +#include "PWGHF/Core/HfMlResponse.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include + +// 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_XIC0TOXIPI(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesXic0ToXiPi::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_XIC0TOXIPI_FULL(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesXic0ToXiPi::FEATURE): { \ + inputFeatures.emplace_back(OBJECT.GETTER()); \ + break; \ + } + +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_VEC_XIC0TOXIPI(GETTER) \ + case static_cast(InputFeaturesXic0ToXiPi::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesXic0ToXiPi : uint8_t { + tpcNSigmaPiFromLambda, + tpcNSigmaPiFromCasc, + tpcNSigmaPiFromCharmBaryon, + dcaCascDau, + dcaCharmBaryonDau, + cosPACharmBaryon, + cosPACasc, + cosPAV0, + impactParBachFromCharmBaryonXY, + impactParCascXY +}; + +template +class HfMlResponseXic0ToXiPi : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseXic0ToXiPi() = default; + /// Default destructor + virtual ~HfMlResponseXic0ToXiPi() = default; + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the Xic0 candidate + /// \return inputFeatures vector + template + // std::vector getInputFeatures(T1 const& candidate) + std::vector getInputFeatures(T1 const& candidate, T2 const& lamProngPi, T2 const& cascProngPi, T3 const& charmBaryonProngPi) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + // PID variables + CHECK_AND_FILL_VEC_XIC0TOXIPI_FULL(lamProngPi, tpcNSigmaPiFromLambda, tpcNSigmaPi); + CHECK_AND_FILL_VEC_XIC0TOXIPI_FULL(cascProngPi, tpcNSigmaPiFromCasc, tpcNSigmaPi); + CHECK_AND_FILL_VEC_XIC0TOXIPI_FULL(charmBaryonProngPi, tpcNSigmaPiFromCharmBaryon, tpcNSigmaPi); + // DCA + CHECK_AND_FILL_VEC_XIC0TOXIPI(dcaCascDau); + CHECK_AND_FILL_VEC_XIC0TOXIPI(dcaCharmBaryonDau); + // CosPA + CHECK_AND_FILL_VEC_XIC0TOXIPI(cosPACharmBaryon); + CHECK_AND_FILL_VEC_XIC0TOXIPI(cosPACasc); + CHECK_AND_FILL_VEC_XIC0TOXIPI(cosPAV0); + // ImpactPar + CHECK_AND_FILL_VEC_XIC0TOXIPI(impactParBachFromCharmBaryonXY); + CHECK_AND_FILL_VEC_XIC0TOXIPI(impactParCascXY); + } + } + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_XIC0TOXIPI(tpcNSigmaPiFromLambda), + FILL_MAP_XIC0TOXIPI(tpcNSigmaPiFromCasc), + FILL_MAP_XIC0TOXIPI(tpcNSigmaPiFromCharmBaryon), + FILL_MAP_XIC0TOXIPI(dcaCascDau), + FILL_MAP_XIC0TOXIPI(dcaCharmBaryonDau), + FILL_MAP_XIC0TOXIPI(cosPACharmBaryon), + FILL_MAP_XIC0TOXIPI(cosPACasc), + FILL_MAP_XIC0TOXIPI(cosPAV0), + FILL_MAP_XIC0TOXIPI(impactParBachFromCharmBaryonXY), + FILL_MAP_XIC0TOXIPI(impactParCascXY)}; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_XIC0TOXIPI +#undef CHECK_AND_FILL_VEC_XIC0TOXIPI_FULL +#undef CHECK_AND_FILL_VEC_XIC0TOXIPI + +#endif // PWGHF_CORE_HFMLRESPONSEXIC0TOXIPI_H_ diff --git a/PWGHF/Core/HfMlResponseXic0ToXiPiKf.h b/PWGHF/Core/HfMlResponseXic0ToXiPiKf.h new file mode 100644 index 00000000000..3fbb6cf4052 --- /dev/null +++ b/PWGHF/Core/HfMlResponseXic0ToXiPiKf.h @@ -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. + +/// \file HfMlResponseXic0ToXiPiKf.h +/// \brief Class to compute the ML response for Ξc^0 → Ξ∓ π± kf analysis selections +/// \author Tao Fang , Central China Normal University + +#ifndef PWGHF_CORE_HFMLRESPONSEXIC0TOXIPIKF_H_ +#define PWGHF_CORE_HFMLRESPONSEXIC0TOXIPIKF_H_ + +#include "PWGHF/Core/HfMlResponse.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include + +// 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_XIC0TOXIPIKF(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesXic0ToXiPiKf::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_XIC0TOXIPIKF_FULL(OBJECT, FEATURE, GETTER) \ + case static_cast(InputFeaturesXic0ToXiPiKf::FEATURE): { \ + inputFeatures.emplace_back(OBJECT.GETTER()); \ + break; \ + } + +// where OBJECT is named candidate and FEATURE = GETTER +#define CHECK_AND_FILL_VEC_XIC0TOXIPIKF(GETTER) \ + case static_cast(InputFeaturesXic0ToXiPiKf::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +namespace o2::analysis +{ + +enum class InputFeaturesXic0ToXiPiKf : uint8_t { + tpcNSigmaPiFromLambda, + tpcNSigmaPiFromCasc, + tpcNSigmaPiFromCharmBaryon, + dcaCascDau, + dcaCharmBaryonDau, + kfDcaXYPiFromXic, + kfDcaXYCascToPv, + cascChi2OverNdf, + xicChi2OverNdf, + cascldl, + chi2TopoCascToPv, + chi2TopoCascToXic, + cosPaCascToXic, + decayLenXYCasc +}; + +template +class HfMlResponseXic0ToXiPiKf : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseXic0ToXiPiKf() = default; + /// Default destructor + virtual ~HfMlResponseXic0ToXiPiKf() = default; + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the Xic0 candidate + /// \return inputFeatures vector + template + // std::vector getInputFeatures(T1 const& candidate) + std::vector getInputFeatures(T1 const& candidate, T2 const& lamProngPi, T2 const& cascProngPi, T3 const& charmBaryonProngPi) + { + std::vector inputFeatures; + + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + // PID variables + CHECK_AND_FILL_VEC_XIC0TOXIPIKF_FULL(lamProngPi, tpcNSigmaPiFromLambda, tpcNSigmaPi); + CHECK_AND_FILL_VEC_XIC0TOXIPIKF_FULL(cascProngPi, tpcNSigmaPiFromCasc, tpcNSigmaPi); + CHECK_AND_FILL_VEC_XIC0TOXIPIKF_FULL(charmBaryonProngPi, tpcNSigmaPiFromCharmBaryon, tpcNSigmaPi); + // DCA + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(dcaCascDau); + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(dcaCharmBaryonDau); + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(kfDcaXYPiFromXic); + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(kfDcaXYCascToPv); + // Chi2Geo + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(cascChi2OverNdf); + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(xicChi2OverNdf); + // ldl + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(cascldl); + // Chi2Topo + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(chi2TopoCascToPv); + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(chi2TopoCascToXic); + // CosPa + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(cosPaCascToXic); + // Decay length + CHECK_AND_FILL_VEC_XIC0TOXIPIKF(decayLenXYCasc); + } + } + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_XIC0TOXIPIKF(tpcNSigmaPiFromLambda), + FILL_MAP_XIC0TOXIPIKF(tpcNSigmaPiFromCasc), + FILL_MAP_XIC0TOXIPIKF(tpcNSigmaPiFromCharmBaryon), + FILL_MAP_XIC0TOXIPIKF(dcaCascDau), + FILL_MAP_XIC0TOXIPIKF(dcaCharmBaryonDau), + FILL_MAP_XIC0TOXIPIKF(kfDcaXYPiFromXic), + FILL_MAP_XIC0TOXIPIKF(kfDcaXYCascToPv), + FILL_MAP_XIC0TOXIPIKF(cascChi2OverNdf), + FILL_MAP_XIC0TOXIPIKF(xicChi2OverNdf), + FILL_MAP_XIC0TOXIPIKF(cascldl), + FILL_MAP_XIC0TOXIPIKF(chi2TopoCascToPv), + FILL_MAP_XIC0TOXIPIKF(chi2TopoCascToXic), + FILL_MAP_XIC0TOXIPIKF(cosPaCascToXic), + FILL_MAP_XIC0TOXIPIKF(decayLenXYCasc), + }; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_XIC0TOXIPIKF +#undef CHECK_AND_FILL_VEC_XIC0TOXIPIKF_FULL +#undef CHECK_AND_FILL_VEC_XIC0TOXIPIKF + +#endif // PWGHF_CORE_HFMLRESPONSEXIC0TOXIPIKF_H_ diff --git a/PWGHF/Core/HfMlResponseXicToPKPi.h b/PWGHF/Core/HfMlResponseXicToPKPi.h index 398357a66d6..f433d29bd5d 100644 --- a/PWGHF/Core/HfMlResponseXicToPKPi.h +++ b/PWGHF/Core/HfMlResponseXicToPKPi.h @@ -16,18 +16,19 @@ #ifndef PWGHF_CORE_HFMLRESPONSEXICTOPKPI_H_ #define PWGHF_CORE_HFMLRESPONSEXICTOPKPI_H_ -#include -#include -#include - #include "PWGHF/Core/HfMlResponse.h" +#include "Tools/ML/MlResponse.h" + +#include +#include + // 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_XIC(FEATURE) \ - { \ -#FEATURE, static_cast < uint8_t>(InputFeaturesXicToPKPi::FEATURE) \ +#define FILL_MAP_XIC(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesXicToPKPi::FEATURE) \ } // Check if the index of mCachedIndices (index associated to a FEATURE) @@ -48,6 +49,32 @@ 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; \ + } + +// Variation of CHECK_AND_FILL_VEC_XIC_OBJECT_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) +// where GETTER1 and GETTER2 are methods of the OBJECT, and used +// depending on whether the candidate is a XicToPKPi or a XicToPiKP +#define CHECK_AND_FILL_VEC_XIC_SIGNED(OBJECT, FEATURE, GETTER1, GETTER2) \ + case static_cast(InputFeaturesXicToPKPi::FEATURE): { \ + if (caseXicToPKPi) { \ + inputFeatures.emplace_back(OBJECT.GETTER1()); \ + } else { \ + inputFeatures.emplace_back(OBJECT.GETTER2()); \ + } \ + break; \ + } + namespace o2::analysis { enum class InputFeaturesXicToPKPi : uint8_t { @@ -66,22 +93,22 @@ enum class InputFeaturesXicToPKPi : uint8_t { cpa, cpaXY, chi2PCA, - tpcNSigmaP0, // 0 + tpcNSigmaPr0, // 0 tpcNSigmaKa0, // 0 tpcNSigmaPi0, // 0 - tpcNSigmaP1, // 1 + tpcNSigmaPr1, // 1 tpcNSigmaKa1, // 1 tpcNSigmaPi1, // 1 - tpcNSigmaP2, // 2 + tpcNSigmaPr2, // 2 tpcNSigmaKa2, // 2 tpcNSigmaPi2, // 2 - tofNSigmaP0, // + tofNSigmaPr0, // tofNSigmaKa0, // tofNSigmaPi0, // - tofNSigmaP1, + tofNSigmaPr1, tofNSigmaKa1, tofNSigmaPi1, - tofNSigmaP2, + tofNSigmaPr2, tofNSigmaKa2, tofNSigmaPi2, tpcTofNSigmaPi0, @@ -92,8 +119,13 @@ enum class InputFeaturesXicToPKPi : uint8_t { tpcTofNSigmaKa2, tpcTofNSigmaPr0, tpcTofNSigmaPr1, - tpcTofNSigmaPr2 - + tpcTofNSigmaPr2, + tpcNSigmaPrExpPr0, + tpcNSigmaPiExpPi2, + tofNSigmaPrExpPr0, + tofNSigmaPiExpPi2, + tpcTofNSigmaPrExpPr0, + tpcTofNSigmaPiExpPi2 }; template @@ -111,9 +143,8 @@ class HfMlResponseXicToPKPi : public HfMlResponse /// \param prong1 is the candidate's prong1 /// \param prong2 is the candidate's prong2 /// \return inputFeatures vector - template - std::vector getInputFeatures(T1 const& candidate, - T2 const& prong0, T2 const& prong1, T2 const& prong2) + template + std::vector getInputFeatures(T1 const& candidate, bool const caseXicToPKPi) { std::vector inputFeatures; @@ -135,35 +166,41 @@ class HfMlResponseXicToPKPi : public HfMlResponse CHECK_AND_FILL_VEC_XIC(cpaXY); CHECK_AND_FILL_VEC_XIC(chi2PCA); // TPC PID variables - CHECK_AND_FILL_VEC_XIC_FULL(prong0, tpcNSigmaP0, tpcNSigmaPr); - CHECK_AND_FILL_VEC_XIC_FULL(prong0, tpcNSigmaKa0, tpcNSigmaKa); - CHECK_AND_FILL_VEC_XIC_FULL(prong0, tpcNSigmaPi0, tpcNSigmaPi); - CHECK_AND_FILL_VEC_XIC_FULL(prong1, tpcNSigmaP1, tpcNSigmaPr); - CHECK_AND_FILL_VEC_XIC_FULL(prong1, tpcNSigmaKa1, tpcNSigmaKa); - CHECK_AND_FILL_VEC_XIC_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi); - 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_FULL(candidate, tpcNSigmaPr0, nSigTpcPr0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcNSigmaKa0, nSigTpcKa0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcNSigmaPi0, nSigTpcPi0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcNSigmaPr1, nSigTpcPr1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcNSigmaKa1, nSigTpcKa1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcNSigmaPi1, nSigTpcPi1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcNSigmaPr2, nSigTpcPr2); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcNSigmaKa2, nSigTpcKa2); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcNSigmaPi2, nSigTpcPi2); + CHECK_AND_FILL_VEC_XIC_SIGNED(candidate, tpcNSigmaPrExpPr0, nSigTpcPr0, nSigTpcPr2); + CHECK_AND_FILL_VEC_XIC_SIGNED(candidate, tpcNSigmaPiExpPi2, nSigTpcPi2, nSigTpcPi0); // TOF PID variables - CHECK_AND_FILL_VEC_XIC_FULL(prong0, tofNSigmaP0, tofNSigmaPr); - CHECK_AND_FILL_VEC_XIC_FULL(prong0, tofNSigmaKa0, tofNSigmaKa); - CHECK_AND_FILL_VEC_XIC_FULL(prong0, tofNSigmaPi0, tofNSigmaPi); - CHECK_AND_FILL_VEC_XIC_FULL(prong1, tofNSigmaP1, tofNSigmaPr); - CHECK_AND_FILL_VEC_XIC_FULL(prong1, tofNSigmaKa1, tofNSigmaKa); - CHECK_AND_FILL_VEC_XIC_FULL(prong1, tofNSigmaPi1, tofNSigmaPi); - 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_FULL(candidate, tofNSigmaPr0, nSigTofPr0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tofNSigmaKa0, nSigTofKa0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tofNSigmaPi0, nSigTofPi0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tofNSigmaPr1, nSigTofPr1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tofNSigmaKa1, nSigTofKa1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tofNSigmaPi1, nSigTofPi1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tofNSigmaPr2, nSigTofPr2); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tofNSigmaKa2, nSigTofKa2); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tofNSigmaPi2, nSigTofPi2); + CHECK_AND_FILL_VEC_XIC_SIGNED(candidate, tofNSigmaPrExpPr0, nSigTofPr0, nSigTofPr2); + CHECK_AND_FILL_VEC_XIC_SIGNED(candidate, tofNSigmaPiExpPi2, nSigTofPi2, nSigTofPi0); // Combined PID variables - CHECK_AND_FILL_VEC_XIC_FULL(prong0, tpcTofNSigmaPi0, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_XIC_FULL(prong1, tpcTofNSigmaPi1, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_XIC_FULL(prong2, tpcTofNSigmaPi2, tpcTofNSigmaPi); - CHECK_AND_FILL_VEC_XIC_FULL(prong0, tpcTofNSigmaKa0, tpcTofNSigmaKa); - CHECK_AND_FILL_VEC_XIC_FULL(prong1, tpcTofNSigmaKa1, tpcTofNSigmaKa); - CHECK_AND_FILL_VEC_XIC_FULL(prong2, tpcTofNSigmaKa2, tpcTofNSigmaKa); - 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_FULL(candidate, tpcTofNSigmaPi0, tpcTofNSigmaPi0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcTofNSigmaPi1, tpcTofNSigmaPi1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcTofNSigmaPi2, tpcTofNSigmaPi2); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcTofNSigmaKa0, tpcTofNSigmaKa0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcTofNSigmaKa1, tpcTofNSigmaKa1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcTofNSigmaKa2, tpcTofNSigmaKa2); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcTofNSigmaPr0, tpcTofNSigmaPr0); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcTofNSigmaPr1, tpcTofNSigmaPr1); + CHECK_AND_FILL_VEC_XIC_FULL(candidate, tpcTofNSigmaPr2, tpcTofNSigmaPr2); + CHECK_AND_FILL_VEC_XIC_SIGNED(candidate, tpcTofNSigmaPrExpPr0, tpcTofNSigmaPr0, tpcTofNSigmaPr2); + CHECK_AND_FILL_VEC_XIC_SIGNED(candidate, tpcTofNSigmaPiExpPi2, tpcTofNSigmaPi2, tpcTofNSigmaPi0); } } @@ -191,25 +228,29 @@ class HfMlResponseXicToPKPi : public HfMlResponse FILL_MAP_XIC(cpaXY), FILL_MAP_XIC(chi2PCA), // TPC PID variables - FILL_MAP_XIC(tpcNSigmaP0), + FILL_MAP_XIC(tpcNSigmaPr0), FILL_MAP_XIC(tpcNSigmaKa0), FILL_MAP_XIC(tpcNSigmaPi0), - FILL_MAP_XIC(tpcNSigmaP1), + FILL_MAP_XIC(tpcNSigmaPr1), FILL_MAP_XIC(tpcNSigmaKa1), FILL_MAP_XIC(tpcNSigmaPi1), - FILL_MAP_XIC(tpcNSigmaP2), + FILL_MAP_XIC(tpcNSigmaPr2), 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(tofNSigmaPr0), FILL_MAP_XIC(tofNSigmaKa0), FILL_MAP_XIC(tofNSigmaPi0), - FILL_MAP_XIC(tofNSigmaP1), + FILL_MAP_XIC(tofNSigmaPr1), FILL_MAP_XIC(tofNSigmaKa1), FILL_MAP_XIC(tofNSigmaPi1), - FILL_MAP_XIC(tofNSigmaP2), + FILL_MAP_XIC(tofNSigmaPr2), 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 +260,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 +271,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..4bb4a4d023f --- /dev/null +++ b/PWGHF/Core/HfMlResponseXicToXiPiPi.h @@ -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 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 "PWGHF/Core/HfMlResponse.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include + +// 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, + cpaXi, + cpaXYXi, + cpaLambda, + cpaXYLambda, + 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(cpaXi); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cpaXYXi); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cpaLambda); + CHECK_AND_FILL_VEC_XICTOXIPIPI(cpaXYLambda); + 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(cpaXi), + FILL_MAP_XICTOXIPIPI(cpaXYXi), + FILL_MAP_XICTOXIPIPI(cpaLambda), + FILL_MAP_XICTOXIPIPI(cpaXYLambda), + 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 92f62d72cca..2a0917cdf97 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 = 4; +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,10 +40,10 @@ constexpr double binsPtTrack[nBinsPtTrack + 1] = { 2.0, 3.0, 1000.0}; -auto vecBinsPtTrack = std::vector{binsPtTrack, binsPtTrack + nBinsPtTrack + 1}; +const 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 */ +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 */ @@ -49,7 +51,7 @@ constexpr double cutsTrack[nBinsPtTrack][nCutVarsTrack] = {{0.0000, 10., 0.0000, {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 */ +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 */ @@ -66,28 +68,29 @@ static const std::vector labelsCutVarTrack = {"min_dcaxytoprimary", 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[5][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}, {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}}; static const std::vector labelsCutsPid = {"minPtTpc", "maxPtTpc", "nSigmaMaxTpc", "minPtTof", "maxPtTof", "nSigmaMaxTof"}; -static const std::vector labelsRowsPid = {"ProtonInLcToPKPi", "ProtonInXicToPKPi", "ProtonInLcToPK0S", "KaonIn3Prongs"}; +static const std::vector labelsRowsPid = {"ProtonInLcToPKPi", "ProtonInXicToPKPi", "ProtonInLcToPK0S", "KaonIn3Prongs", "DeuteronInCdToDeKPi"}; } // namespace hf_presel_pid 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}; +const 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 +118,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 +135,18 @@ constexpr double binsPt[nBinsPt + 1] = { 16., 24., 50.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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}; +const 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 +182,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}; +const 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 +206,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}; +const 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 +230,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}; +const 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 +253,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}; +const 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 +276,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 +307,10 @@ constexpr double binsPt[nBinsPt + 1] = { 36.0, 50.0, 100.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 +370,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 +401,7 @@ constexpr double binsPt[nBinsPt + 1] = { 36.0, 50.0, 100.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; // row labels static const std::vector labelsPt = { @@ -432,7 +435,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 +464,12 @@ 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 = 8; +static constexpr int NBinsPt = 10; +static constexpr int NCutVars = 11; +static constexpr int NCutKfVars = 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., 1., 2., @@ -477,19 +481,32 @@ 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., -1.}, /* 0 < pT < 1 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}, /* 1 < pT < 2 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}, /* 2 < pT < 3 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}, /* 3 < pT < 4 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}, /* 4 < pT < 5 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}, /* 5 < pT < 6 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}, /* 6 < pT < 8 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}, /* 8 < pT < 12 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}, /* 12 < pT < 24 */ - {0.400, 0.4, 0.4, 0.4, 0., 0.005, 0., -1.}}; /* 24 < pT < 36 */ +const 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 */ + +// default value for the cuts Chi2Prim Chi2Geo DCA, cm Chi2Geo Chi2Topo +// P K Pi KPi PPi PK KPi PPi PK ↓ LdL ↓ +constexpr double CutsKf[NBinsPt][NCutKfVars] = {{3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 0 < pT < 1 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 1 < pT < 2 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 2 < pT < 3 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 3 < pT < 4 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 4 < pT < 5 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 5 < pT < 6 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 6 < pT < 8 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 8 < pT < 12 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}, /* 12 < pT < 24 */ + {3., 3., 3., 3., 3., 3., 0.01, 0.01, 0.01, 3., 5., 5.}}; /* 24 < pT < 36 */ // row labels static const std::vector labelsPt = { @@ -505,16 +522,17 @@ 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", "mass (Kpi)"}; +static const std::vector labelsCutVar = {"m", "pT p", "pT K", "pT Pi", "Chi2PCA", "decay length", "cos pointing angle", "decLengthXY", "normDecLXY", "impParXY", "mass (Kpi)"}; +static const std::vector labelsCutKfVar = {"kfChi2PrimPr", "kfChi2PrimKa", "kfChi2PrimPi", "kfChi2GeoKaPi", "kfChi2GeoPrPi", "kfChi2GeoPrKa", "kfDcaKaPi", "kfDcaPrPi", "kfDcaPrKa", "kfChi2Geo", "kfLdL", "kfChi2Topo"}; } // 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 = 9; // 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,18 +542,18 @@ constexpr double binsPt[nBinsPt + 1] = { 8., 12., 24.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 - {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 - {0.013, 0.005, 0.1, 0.6, 0.4, 1.4, 0.06, 999999.}, // 5 < pt < 6 - {0.013, 0.005, 0.1, 0.9, 0.4, 1.6, 0.09, 999999.}, // 6 < pt < 8 - {0.016, 0.005, 0.1, 0.9, 0.4, 1.7, 0.10, 999999.}, // 8 < pt < 12 - {0.019, 0.005, 0.1, 1.0, 0.4, 1.9, 0.20, 999999.}}; // 12 < pt < 24 +// mLc(GeV) mK0s(GeV) mLambdas(GeV) mGammas(GeV) ptp ptK0sdau ptK0s d0p d0K0 +constexpr double Cuts[NBinsPt][NCutVars] = {{0.4, 0.008, 0.005, 0.1, 0.5, 0.3, 0.6, 0.05, 999999.}, // 1 < pt < 2 + {0.4, 0.008, 0.005, 0.1, 0.5, 0.4, 1.3, 0.05, 999999.}, // 2 < pt < 3 + {0.4, 0.009, 0.005, 0.1, 0.6, 0.4, 1.3, 0.05, 999999.}, // 3 < pt < 4 + {0.4, 0.011, 0.005, 0.1, 0.6, 0.4, 1.4, 0.05, 999999.}, // 4 < pt < 5 + {0.4, 0.013, 0.005, 0.1, 0.6, 0.4, 1.4, 0.06, 999999.}, // 5 < pt < 6 + {0.4, 0.013, 0.005, 0.1, 0.9, 0.4, 1.6, 0.09, 999999.}, // 6 < pt < 8 + {0.4, 0.016, 0.005, 0.1, 0.9, 0.4, 1.7, 0.10, 999999.}, // 8 < pt < 12 + {0.4, 0.019, 0.005, 0.1, 1.0, 0.4, 1.9, 0.20, 999999.}}; // 12 < pt < 24 // row labels static const std::vector labelsPt = { @@ -549,16 +567,16 @@ static const std::vector labelsPt = { "pT bin 7"}; // column labels -static const std::vector labelsCutVar = {"mK0s", "mLambda", "mGamma", "ptBach", "ptV0Dau", "ptV0", "d0Bach", "d0V0"}; +static const std::vector labelsCutVar = {"mLc", "mK0s", "mLambda", "mGamma", "ptBach", "ptV0Dau", "ptV0", "d0Bach", "d0V0"}; } // namespace hf_cuts_lc_to_k0s_p 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 +590,11 @@ constexpr double binsPt[nBinsPt + 1] = { 16., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 +628,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 +641,11 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 16., 24.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 +669,138 @@ 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}; + +const 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_omegacxic_to_omega_ka +{ +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}; + +const 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 Ka from Omegac"}; +} // namespace hf_cuts_omegacxic_to_omega_ka + +namespace hf_cuts_xic_to_xi_pi +{ +static constexpr int NBinsPt = 11; +static constexpr int NCutVars = 28; +// 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.0, + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 8.0, + 10.0, + 12.0, + 16.0, + 24.0}; + +const auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts +constexpr double Cuts[NBinsPt][NCutVars] = {{0.2, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 0 < pt < 1 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 1 < pt < 2 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 2 < pt < 3 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 3 < pt < 4 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 4 < pt < 5 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 5 < pt < 6 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 6 < pt < 8 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 8 < pt < 10 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 10 < pt < 12 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}, /* 12 < pt < 16 */ + {0.5, 0.99, 0.97, 0.99, 0.99, 0.1, 0.2, 1.0, 0.04, 0.06, 0.06, 0.05, 0.3, 70, 60, 100, 120, 250, 250, 0.4, 100, 300, 0., 0., 1.5, 0., 0., 0.4}}; /* 16 < pt < 24 */ + +// 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", + "pT bin 10"}; + +// column labels +static const std::vector labelsCutVar = {"ptPiFromCharmBaryon", "cosPACasc", "cosPAV0", "cosPaCascToXic", "cosPaV0ToCasc", + "dcaCharmBaryonDau", "dcaCascDau", "dcaV0Dau", "dcaXYToPvCascDau", "dcaXYToPvV0Dau0", "dcaXYToPvV0Dau1", "kfDcaXYPiFromXic", "kfDcaXYCascToPv", + "chi2GeoXic", "chi2GeoCasc", "chi2GeoV0", + "chi2TopoXicToPv", "chi2TopoPiFromXicToPv", "chi2TopoCascToPv", "chi2TopoV0ToPv", "chi2TopoV0ToCasc", "chi2TopoCascToXic", + "cascldl", "v0ldl", "decayLenXYXic", "decayLenXYCasc", "decayLenXYLambda", "cTauXic"}; +} // namespace hf_cuts_xic_to_xi_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 +812,10 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 */ @@ -702,11 +845,11 @@ static const std::vector labelsCutVar = {"m", "pT p", "pT K", "pT P namespace hf_cuts_xic_to_xi_pi_pi { -static const int nBinsPt = 10; -static const int nCutVars = 12; +static constexpr int NBinsPt = 13; +static constexpr int NCutVars = 13; // 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., @@ -714,23 +857,29 @@ constexpr double binsPt[nBinsPt + 1] = { 4., 5., 6., + 7., 8., + 9., + 10., + 11., 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 */ + 20.}; +const auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts m Y Eta EtaPi EtaXi pT Pi0 Pi1 Sum chi2SV dL dLXY invMass Xi-Pi pairs +constexpr double Cuts[NBinsPt][NCutVars] = {{0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 0 < pT < 1 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 1 < pT < 2 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 2 < pT < 3 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 3 < pT < 4 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 4 < pT < 5 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 5 < pT < 6 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 6 < pT < 7 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 7 < pT < 8 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 8 < pT < 9 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 9 < pT < 10 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 10 < pT < 11 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}, /* 11 < pT < 12 */ + {0.4, 0.8, 0.8, 0.8, 1.0, 0.1, 0.1, 0.2, 100, 0.0, 0.0, 2.4, 2.4}}; /* 12 < pT < 20 */ // row labels static const std::vector labelsPt = { @@ -743,19 +892,22 @@ static const std::vector labelsPt = { "pT bin 6", "pT bin 7", "pT bin 8", - "pT bin 9"}; + "pT bin 9", + "pT bin 10", + "pT bin 11", + "pT bin 12"}; // 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"}; +static const std::vector labelsCutVar = {"m", "y", "eta", "eta Pi from XicPlus", "eta Xi Daughters", "pT Pi0", "pT Pi1", "pT Pi0 + Pi1", "chi2SV", "min decay length", "min decay length XY", "max inv mass Xi-Pi0", "max inv mass Xi-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., @@ -767,10 +919,10 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 */ @@ -800,11 +952,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, @@ -816,10 +968,10 @@ constexpr double binsPt[nBinsPt + 1] = { 10.0, 15.0, }; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 */ @@ -845,13 +997,60 @@ static const std::vector labelsPt = { static const std::vector labelsCutVar = {"m", "DCA_xy", "DCA_z", "pT El", "chi2PCA"}; } // namespace hf_cuts_jpsi_to_e_e +namespace hf_cuts_jpsi_to_mu_mu +{ +static constexpr int NBinsPt = 9; +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] = { + 0, + 0.5, + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 10.0, + 16.0, +}; +const auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts +constexpr double Cuts[NBinsPt][NCutVars] = {{0.6, 1.0, 0.2, 0.2, 0.9, 0.9, 0., 0.}, /* 0 < pT < 0.5 */ + {0.6, 1.0, 0.2, 0.2, 0.9, 0.9, 0., 0.}, /* 0.5 < pT < 1 */ + {0.6, 1.0, 0.2, 0.2, 0.9, 0.9, 0., 0.}, /* 1 < pT < 2 */ + {0.6, 1.0, 0.2, 0.2, 0.9, 0.9, 0., 0.}, /* 2 < pT < 3 */ + {0.6, 1.0, 0.2, 0.2, 0.9, 0.9, 0., 0.}, /* 3 < pT < 4 */ + {0.6, 1.0, 0.2, 0.2, 0.9, 0.9, 0., 0.}, /* 4 < pT < 5 */ + {0.8, 1.0, 0.3, 0.3, 0.9, 0.9, 0., 0.}, /* 5 < pT < 6 */ + {0.8, 1.0, 0.3, 0.3, 0.9, 0.9, 1., 0.}, /* 6 < pT < 10 */ + {0.8, 1.0, 0.3, 0.3, 0.9, 0.9, 1., 0.}}; /* 10 < pT < 16 */ + +// 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"}; + +// column labels +static const std::vector labelsCutVar = {"m", "pT mu", "decay length", "decay length xy", "cpa", "cpa xy", "d0xd0", "pseudoprop. decay length"}; +} // namespace hf_cuts_jpsi_to_mu_mu + 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, @@ -866,11 +1065,11 @@ constexpr double binsPt[nBinsPt + 1] = { 20.0, 24.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 */ @@ -903,37 +1102,118 @@ 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}; +const 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"}; } // namespace hf_cuts_bs_to_ds_pi +namespace hf_cuts_bs_to_jpsi_phi +{ +static constexpr int NBinsPt = 12; +static constexpr int NCutVars = 13; +// 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, + 0.5, + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 7.0, + 10.0, + 13.0, + 16.0, + 20.0, + 24.0}; + +const auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts +// DeltaM CPA d0Jpsi d0K pTJpsi pTK BDecayLength BDecayLengthXY BIPProd DeltaMJpsi JpsiIPProd +constexpr double Cuts[NBinsPt][NCutVars] = {{1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 0 < pt < 0.5 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 0.5 < pt < 1 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 1 < pt < 2 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 2 < pt < 3 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 3 < pt < 4 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 4 < pt < 5 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 5 < pt < 7 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 7 < pt < 10 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 10 < pt < 13 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 13 < pt < 16 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}, /* 16 < pt < 20 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.02, 0.}}; /* 20 < pt < 24 */ +// 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", + "pT bin 10", + "pT bin 11"}; + +// column labels +static const std::vector labelsCutVar = {"m", "CPA", "CPAXY", "d0 J/Psi", "d0 phi", "pT J/Psi", "pT K", "B decLen", "B decLenXY", "B Imp. Par. Product", "DeltaM J/Psi", "DeltaM phi", "B pseudoprop. decLen"}; +} // namespace hf_cuts_bs_to_jpsi_phi + 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, @@ -948,11 +1228,11 @@ constexpr double binsPt[nBinsPt + 1] = { 20.0, 24.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 */ @@ -983,13 +1263,69 @@ static const std::vector labelsPt = { static const std::vector labelsCutVar = {"m", "CPA", "d0 D0", "d0 Pi", "pT D0", "pT Pi", "B decLen", "B decLenXY", "Imp. Par. Product", "DeltaMD0", "Cos ThetaStar"}; } // namespace hf_cuts_bplus_to_d0_pi +namespace hf_cuts_bplus_to_jpsi_k +{ +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] = { + 0, + 0.5, + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 7.0, + 10.0, + 13.0, + 16.0, + 20.0, + 24.0}; + +const auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts +// DeltaM CPA d0Jpsi d0K pTJpsi pTK BDecayLength BDecayLengthXY BIPProd DeltaMJpsi JpsiIPProd +constexpr double Cuts[NBinsPt][NCutVars] = {{1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 0 < pt < 0.5 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 0.5 < pt < 1 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 1 < pt < 2 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 2 < pt < 3 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 3 < pt < 4 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 4 < pt < 5 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 5 < pt < 7 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 7 < pt < 10 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 10 < pt < 13 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 13 < pt < 16 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}, /* 16 < pt < 20 */ + {1., 0.8, 0.8, 0.01, 0.01, 1.0, 0.15, 0.05, 0.05, 0., 0.1, 0.}}; /* 20 < pt < 24 */ +// 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", + "pT bin 10", + "pT bin 11"}; + +// column labels +static const std::vector labelsCutVar = {"m", "CPA", "CPAXY", "d0 J/Psi", "d0 K", "pT J/Psi", "pT K", "B decLen", "B decLenXY", "B Imp. Par. Product", "DeltaM J/Psi", "B pseudoprop. decLen"}; +} // namespace hf_cuts_bplus_to_jpsi_k + 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, @@ -1004,11 +1340,11 @@ constexpr double binsPt[nBinsPt + 1] = { 20.0, 24.0}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 */ @@ -1041,11 +1377,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, @@ -1057,11 +1393,11 @@ constexpr double binsPt[nBinsPt + 1] = { 10.0, 15.0, }; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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, @@ -1104,11 +1440,11 @@ constexpr double binsPt[nBinsPt + 1] = { 10.0, 15.0, }; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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., @@ -1150,10 +1486,10 @@ constexpr double binsPt[nBinsPt + 1] = { 12., 24., 36.}; -auto vecBinsPt = std::vector{binsPt, binsPt + nBinsPt + 1}; +const 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 */ @@ -1181,6 +1517,43 @@ static const std::vector labelsPt = { static const std::vector labelsCutVar = {"max pKpi mass Lc", "max piKp mass Lc"}; } // namespace hf_cuts_sigmac_to_p_k_pi +namespace hf_cuts_cd_to_de_k_pi +{ +static constexpr int NBinsPt = 6; +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] = { + 0., + 2., + 4., + 6., + 8., + 12., + 24.}; +const 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}, /* 0 < pT < 2 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 2 < pT < 4 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 4 < pT < 6 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 6 < pT < 8 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 8 < pT < 12 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}}; /* 12 < pT < 24 */ + +// 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"}; + +// column labels +static const std::vector labelsCutVar = {"m", "pT De", "pT K", "pT Pi", "Chi2PCA", "decay length", "cos pointing angle", "decLengthXY", "normDecLXY", "impParXY"}; +} // namespace hf_cuts_cd_to_de_k_pi + } // namespace o2::analysis #endif // PWGHF_CORE_SELECTORCUTS_H_ diff --git a/PWGHF/D2H/Core/SelectorCutsRedDataFormat.h b/PWGHF/D2H/Core/SelectorCutsRedDataFormat.h new file mode 100644 index 00000000000..c18fcf61290 --- /dev/null +++ b/PWGHF/D2H/Core/SelectorCutsRedDataFormat.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 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] = { + 0., + 2., + 4., + 6., + 8., + 12., + 24., + 1000.}; +const 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.}; +const 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 hf_cuts_track_daughter +{ +static constexpr int NCutVars = 7; +// default values for the cuts +constexpr double Cuts[1][NCutVars] = {{0.1, 3, 40, 4, 3, -1, -1}}; // nSigmaTpc, nSigmaTof, nSigmaCombined +// row labels +static const std::vector labelsCutVar = {"ptMin", "itsNClsMin", "tpcNCrossedRowsMin", "tpcChi2Max", "nSigmaTpc", "nSigmaTof", "nSigmaComb"}; +} // namespace hf_cuts_track_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 391043904d5..f3fcbc188d1 100644 --- a/PWGHF/D2H/DataModel/ReducedDataModel.h +++ b/PWGHF/D2H/DataModel/ReducedDataModel.h @@ -11,24 +11,39 @@ /// \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) +/// \author Biao Zhang , Heidelberg University +/// \author Fabrizio Chinu , Università degli Studi di Torino (UniTO) #ifndef PWGHF_D2H_DATAMODEL_REDUCEDDATAMODEL_H_ #define PWGHF_D2H_DATAMODEL_REDUCEDDATAMODEL_H_ -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/Vertex.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsPid.h" #include "Common/Core/RecoDecay.h" -#include "Common/DataModel/PIDResponse.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" + +#include +#include +#include +#include + +#include +#include +#include +#include namespace o2 { @@ -36,9 +51,10 @@ 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, o2::hf_evsel::HfCollisionRejectionMask); //! 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 @@ -51,16 +67,44 @@ 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; @@ -126,10 +170,109 @@ 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, int8_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(ItsChi2NCl, itsChi2NCl, float); //! ITS 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}); }); +DECLARE_SOA_DYNAMIC_COLUMN(PVector, pVector, //! 3-momentum vector + [](float px, float py, float pz) -> std::array { return {px, py, pz}; }); +} // namespace hf_track_vars_reduced + +namespace hf_b_to_jpsi_track_vars_reduced +{ +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! transverse momentum + [](float signed1Pt) -> float { return std::abs(signed1Pt) <= o2::constants::math::Almost0 ? o2::constants::math::VeryBig : 1.f / std::abs(signed1Pt); }); +} // namespace hf_b_to_jpsi_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(TPCNSigmaPrProng0, tpcNSigmaPrProng0, float); //! NsigmaTPCPr for prong0, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TPCNSigmaPrProng1, tpcNSigmaPrProng1, float); //! NsigmaTPCPr for prong1, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TPCNSigmaPrProng2, tpcNSigmaPrProng2, float); //! NsigmaTPCPr 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) +DECLARE_SOA_COLUMN(TOFNSigmaPrProng0, tofNSigmaPrProng0, float); //! NsigmaTOFPr for prong0, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaPrProng1, tofNSigmaPrProng1, float); //! NsigmaTOFPr for prong1, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaPrProng2, tofNSigmaPrProng2, float); //! NsigmaTOFPr 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); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPrProng0, tpcTofNSigmaPrProng0, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPr, float tofNSigmaPr) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr, tofNSigmaPr); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPrProng1, tpcTofNSigmaPrProng1, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPr, float tofNSigmaPr) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr, tofNSigmaPr); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPrProng2, tpcTofNSigmaPrProng2, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPr, float tofNSigmaPr) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr, tofNSigmaPr); }); +} // 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 @@ -137,33 +280,115 @@ 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, - aod::track::PVector); + aod::track::PVector, + o2::soa::Marker<1>); DECLARE_SOA_TABLE(HfRedTracksCov, "AOD", "HFREDTRACKCOV", //! Table with track covariance information for reduced workflow + soa::Index<>, + HFTRACKPARCOV_COLUMNS, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(HfRedTracksMom, "AOD", "HFREDTRACKMOM", //! Table with track momentum information for reduced workflow + soa::Index<>, + hf_track_vars_reduced::Px, + hf_track_vars_reduced::Py, + hf_track_vars_reduced::Pz, + hf_track_vars_reduced::Sign); + +// 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(HfRedBach0Bases, "AOD", "HFREDBACH0BASE", //! Table with track information for reduced workflow + soa::Index<>, + hf_track_index_reduced::TrackId, + hf_track_index_reduced::HfRedCollisionId, + HFTRACKPAR_COLUMNS, + hf_b_to_jpsi_track_vars_reduced::Pt, + hf_track_vars_reduced::ItsNCls, + hf_track_vars_reduced::TpcNClsCrossedRows, + hf_track_vars_reduced::TpcChi2NCl, + hf_track_vars_reduced::ItsChi2NCl, + hf_track_vars_reduced::HasTPC, + hf_track_vars_reduced::HasTOF, + pidtpc::TPCNSigmaPi, + pidtof::TOFNSigmaPi, + pidtpc::TPCNSigmaKa, + pidtof::TOFNSigmaKa, + pidtpc::TPCNSigmaPr, + pidtof::TOFNSigmaPr, + hf_track_pid_reduced::TPCTOFNSigmaPi, + hf_track_pid_reduced::TPCTOFNSigmaKa, + hf_track_pid_reduced::TPCTOFNSigmaPr, + aod::track::Px, + aod::track::Py, + aod::track::Pz, + aod::track::PVector); + +DECLARE_SOA_TABLE(HfRedBach0Cov, "AOD", "HFREDBACH0COV", //! Table with track covariance information for reduced workflow + soa::Index<>, + HFTRACKPARCOV_COLUMNS); + +// 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(HfRedBach1Bases, "AOD", "HFREDBACH1BASE", //! Table with track information for reduced workflow + soa::Index<>, + hf_track_index_reduced::TrackId, + hf_track_index_reduced::HfRedCollisionId, + HFTRACKPAR_COLUMNS, + hf_b_to_jpsi_track_vars_reduced::Pt, + hf_track_vars_reduced::ItsNCls, + hf_track_vars_reduced::TpcNClsCrossedRows, + hf_track_vars_reduced::TpcChi2NCl, + hf_track_vars_reduced::ItsChi2NCl, + hf_track_vars_reduced::HasTPC, + hf_track_vars_reduced::HasTOF, + pidtpc::TPCNSigmaPi, + pidtof::TOFNSigmaPi, + pidtpc::TPCNSigmaKa, + pidtof::TOFNSigmaKa, + pidtpc::TPCNSigmaPr, + pidtof::TOFNSigmaPr, + hf_track_pid_reduced::TPCTOFNSigmaPi, + hf_track_pid_reduced::TPCTOFNSigmaKa, + hf_track_pid_reduced::TPCTOFNSigmaPr, + aod::track::Px, + aod::track::Py, + aod::track::Pz, + aod::track::PVector); + +DECLARE_SOA_TABLE(HfRedBach1Cov, "AOD", "HFREDBACH1COV", //! Table with track covariance information for reduced workflow soa::Index<>, HFTRACKPARCOV_COLUMNS); // 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); +DECLARE_SOA_EXTENDED_TABLE_USER(HfRedBach0Ext, HfRedBach0Bases, "HFREDBACH0EXT", //! Track parameters at collision vertex + aod::track::Pt); +DECLARE_SOA_EXTENDED_TABLE_USER(HfRedBach1Ext, HfRedBach1Bases, "HFREDBACH1EXT", //! Track parameters at collision vertex + aod::track::Pt); using HfRedTracks = HfRedTracksExt; +using HfRedBach0Tracks = HfRedBach0Bases; +using HfRedBach1Tracks = HfRedBach1Bases; 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) @@ -172,6 +397,115 @@ DECLARE_SOA_COLUMN(MlScorePromptMassHypo1, mlScorePromptMassHypo1, float); DECLARE_SOA_COLUMN(MlScoreNonpromptMassHypo1, mlScoreNonpromptMassHypo1, float); //! ML score for non-prompt class (mass hypothesis 1) } // namespace hf_charm_cand_reduced +namespace hf_jpsi_cand_reduced +{ +DECLARE_SOA_COLUMN(ProngPosId, prongPosId, int); //! Original track index +DECLARE_SOA_COLUMN(ProngNegId, prongNegId, int); //! Original track index +DECLARE_SOA_COLUMN(HfRedCollisionId, hfRedCollisionId, int); //! Collision index +DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate in GeV/c2 + +DECLARE_SOA_COLUMN(ItsNClsDauPos, itsNClsDauPos, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsDauPos, tpcNClsCrossedRowsDauPos, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(TpcChi2NClDauPos, tpcChi2NClDauPos, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(ItsChi2NClDauPos, itsChi2NClDauPos, float); //! ITS chi2 / Number of clusters +DECLARE_SOA_COLUMN(ItsNClsDauNeg, itsNClsDauNeg, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsDauNeg, tpcNClsCrossedRowsDauNeg, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(TpcChi2NClDauNeg, tpcChi2NClDauNeg, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(ItsChi2NClDauNeg, itsChi2NClDauNeg, float); //! ITS chi2 / Number of clusters + +DECLARE_SOA_COLUMN(XDauPos, xDauPos, float); //! x +DECLARE_SOA_COLUMN(XDauNeg, xDauNeg, float); //! x +DECLARE_SOA_COLUMN(YDauPos, yDauPos, float); //! y +DECLARE_SOA_COLUMN(YDauNeg, yDauNeg, float); //! y +DECLARE_SOA_COLUMN(ZDauPos, zDauPos, float); //! z +DECLARE_SOA_COLUMN(ZDauNeg, zDauNeg, float); //! z +DECLARE_SOA_COLUMN(AlphaDauPos, alphaDauPos, float); //! alpha of the J/Psi positive decay daughter +DECLARE_SOA_COLUMN(AlphaDauNeg, alphaDauNeg, float); //! alpha of the J/Psi negative decay daughter +DECLARE_SOA_COLUMN(SnpDauPos, snpDauPos, float); //! snp of the J/Psi positive decay daughter +DECLARE_SOA_COLUMN(SnpDauNeg, snpDauNeg, float); //! snp of the J/Psi negative decay daughter +DECLARE_SOA_COLUMN(TglDauPos, tglDauPos, float); //! tgl of the J/Psi positive decay daughter +DECLARE_SOA_COLUMN(TglDauNeg, tglDauNeg, float); //! tgl of the J/Psi negative decay daughter +DECLARE_SOA_COLUMN(Signed1PtDauPos, signed1PtDauPos, float); //! signed1Pt of the J/Psi positive decay daughter +DECLARE_SOA_COLUMN(Signed1PtDauNeg, signed1PtDauNeg, float); //! signed1Pt of the J/Psi negative decay daughter + +DECLARE_SOA_DYNAMIC_COLUMN(PxDauPos, pxDauPos, //! Momentum in x-direction in GeV/c + [](float signed1Pt, float snp, float alpha) -> float { + auto pt = 1.f / std::abs(signed1Pt); + // FIXME: GCC & clang should optimize to sincosf + float cs = cosf(alpha), sn = sinf(alpha); + auto r = std::sqrt((1.f - snp) * (1.f + snp)); + return pt * (r * cs - snp * sn); + }); +DECLARE_SOA_DYNAMIC_COLUMN(PyDauPos, pyDauPos, //! Momentum in y-direction in GeV/c + [](float signed1Pt, float snp, float alpha) -> float { + auto pt = 1.f / std::abs(signed1Pt); + // FIXME: GCC & clang should optimize to sincosf + float cs = cosf(alpha), sn = sinf(alpha); + auto r = std::sqrt((1.f - snp) * (1.f + snp)); + return pt * (snp * cs + r * sn); + }); +DECLARE_SOA_DYNAMIC_COLUMN(PzDauPos, pzDauPos, //! Momentum in z-direction in GeV/c + [](float signed1Pt, float tgl) -> float { + auto pt = 1.f / std::abs(signed1Pt); + return pt * tgl; + }); +DECLARE_SOA_DYNAMIC_COLUMN(PxDauNeg, pxDauNeg, //! Momentum in x-direction in GeV/c + [](float signed1Pt, float snp, float alpha) -> float { + auto pt = 1.f / std::abs(signed1Pt); + // FIXME: GCC & clang should optimize to sincosf + float cs = cosf(alpha), sn = sinf(alpha); + auto r = std::sqrt((1.f - snp) * (1.f + snp)); + return pt * (r * cs - snp * sn); + }); +DECLARE_SOA_DYNAMIC_COLUMN(PyDauNeg, pyDauNeg, //! Momentum in y-direction in GeV/c + [](float signed1Pt, float snp, float alpha) -> float { + auto pt = 1.f / std::abs(signed1Pt); + // FIXME: GCC & clang should optimize to sincosf + float cs = cosf(alpha), sn = sinf(alpha); + auto r = std::sqrt((1.f - snp) * (1.f + snp)); + return pt * (snp * cs + r * sn); + }); +DECLARE_SOA_DYNAMIC_COLUMN(PzDauNeg, pzDauNeg, //! Momentum in z-direction in GeV/c + [](float signed1Pt, float tgl) -> float { + auto pt = 1.f / std::abs(signed1Pt); + return pt * tgl; + }); + +// Covariance matrix of the J/Psi positive decay daughter +DECLARE_SOA_COLUMN(CYYDauPos, cYYDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CZYDauPos, cZYDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CZZDauPos, cZZDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CSnpYDauPos, cSnpYDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CSnpZDauPos, cSnpZDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CSnpSnpDauPos, cSnpSnpDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CTglYDauPos, cTglYDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CTglZDauPos, cTglZDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CTglSnpDauPos, cTglSnpDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CTglTglDauPos, cTglTglDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1PtYDauPos, c1PtYDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1PtZDauPos, c1PtZDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1PtSnpDauPos, c1PtSnpDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1PtTglDauPos, c1PtTglDauPos, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1Pt21Pt2DauPos, c1Pt21Pt2DauPos, float); //! Covariance matrix + +// Covariance matrix of the J/Psi negative decay daughter +DECLARE_SOA_COLUMN(CYYDauNeg, cYYDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CZYDauNeg, cZYDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CZZDauNeg, cZZDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CSnpYDauNeg, cSnpYDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CSnpZDauNeg, cSnpZDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CSnpSnpDauNeg, cSnpSnpDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CTglYDauNeg, cTglYDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CTglZDauNeg, cTglZDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CTglSnpDauNeg, cTglSnpDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(CTglTglDauNeg, cTglTglDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1PtYDauNeg, c1PtYDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1PtZDauNeg, c1PtZDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1PtSnpDauNeg, c1PtSnpDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1PtTglDauNeg, c1PtTglDauNeg, float); //! Covariance matrix +DECLARE_SOA_COLUMN(C1Pt21Pt2DauNeg, c1Pt21Pt2DauNeg, float); //! Covariance matrix +} // namespace hf_jpsi_cand_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(HfRed2Prongs, "AOD", "HFRED2PRONG", //! Table with 2prong candidate information for reduced workflow @@ -180,7 +514,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, @@ -199,6 +535,39 @@ DECLARE_SOA_TABLE(HfRed2ProngsMl, "AOD", "HFRED2PRONGML", //! Table with 2prong hf_charm_cand_reduced::MlScorePromptMassHypo1, hf_charm_cand_reduced::MlScoreNonpromptMassHypo1); +// 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(HfRedSoftPiBases, "AOD", "HFREDSOFTPIBASE", //! Table with track information for reduced workflow + soa::Index<>, + 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, + aod::track::PVector); + +DECLARE_SOA_TABLE(HfRedSoftPiCov, "AOD", "HFREDSOFTPICOV", //! Table with track covariance information for reduced workflow + soa::Index<>, + HFTRACKPARCOV_COLUMNS, + o2::soa::Marker<2>); + +DECLARE_SOA_TABLE(HfRedSoftPiPid, "AOD", "HFREDSOFTPIPID", + soa::Index<>, + hf_cand_dstar::TPCNSigmaPiSoftPi, + hf_cand_dstar::TOFNSigmaPiSoftPi, + hf_track_vars_reduced::HasTOF, + hf_track_vars_reduced::HasTPC, + hf_cand_dstar::TPCTOFNSigmaPiSoftPi) + +namespace hf_track_index_reduced +{ +DECLARE_SOA_INDEX_COLUMN_FULL(SoftPi, softPi, int, HfRedSoftPiBases, ""); //! ReducedCollision index +}; // namespace hf_track_index_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(HfRed3Prongs, "AOD", "HFRED3PRONG", //! Table with 3prong candidate information for reduced workflow @@ -207,7 +576,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, @@ -218,24 +589,181 @@ 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(HfRedMomDDaugs, "AOD", "HFREDMOMDDAUGS", //! Table with 2prong candidate ML scores + 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); + +// 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(HfRedJpsis, "AOD", "HFREDJPSI", //! Table with J/Psi candidate information for reduced workflow + o2::soa::Index<>, + hf_jpsi_cand_reduced::ProngPosId, + hf_jpsi_cand_reduced::ProngNegId, + hf_track_index_reduced::HfRedCollisionId, + hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, + hf_jpsi_cand_reduced::M, + hf_jpsi_cand_reduced::ItsNClsDauPos, + hf_jpsi_cand_reduced::TpcNClsCrossedRowsDauPos, + hf_jpsi_cand_reduced::TpcChi2NClDauPos, + hf_jpsi_cand_reduced::ItsChi2NClDauPos, + hf_jpsi_cand_reduced::ItsNClsDauNeg, + hf_jpsi_cand_reduced::TpcNClsCrossedRowsDauNeg, + hf_jpsi_cand_reduced::TpcChi2NClDauNeg, + hf_jpsi_cand_reduced::ItsChi2NClDauNeg, + hf_jpsi_cand_reduced::XDauPos, hf_jpsi_cand_reduced::XDauNeg, + hf_jpsi_cand_reduced::YDauPos, hf_jpsi_cand_reduced::YDauNeg, + hf_jpsi_cand_reduced::ZDauPos, hf_jpsi_cand_reduced::ZDauNeg, + hf_jpsi_cand_reduced::AlphaDauPos, hf_jpsi_cand_reduced::AlphaDauNeg, + hf_jpsi_cand_reduced::SnpDauPos, hf_jpsi_cand_reduced::SnpDauNeg, + hf_jpsi_cand_reduced::TglDauPos, hf_jpsi_cand_reduced::TglDauNeg, + hf_jpsi_cand_reduced::Signed1PtDauPos, hf_jpsi_cand_reduced::Signed1PtDauNeg, + hf_jpsi_cand_reduced::PxDauPos, + hf_jpsi_cand_reduced::PxDauNeg, + hf_jpsi_cand_reduced::PyDauPos, + hf_jpsi_cand_reduced::PyDauNeg, + hf_jpsi_cand_reduced::PzDauPos, + hf_jpsi_cand_reduced::PzDauNeg); + +DECLARE_SOA_TABLE(HfRedJpsiCov, "AOD", "HFREDJPSICOV", //! Table with J/Psi candidate covariance for reduced workflow + o2::soa::Index<>, + hf_jpsi_cand_reduced::CYYDauPos, hf_jpsi_cand_reduced::CYYDauNeg, + hf_jpsi_cand_reduced::CZYDauPos, hf_jpsi_cand_reduced::CZYDauNeg, + hf_jpsi_cand_reduced::CZZDauPos, hf_jpsi_cand_reduced::CZZDauNeg, + hf_jpsi_cand_reduced::CSnpYDauPos, hf_jpsi_cand_reduced::CSnpYDauNeg, + hf_jpsi_cand_reduced::CSnpZDauPos, hf_jpsi_cand_reduced::CSnpZDauNeg, + hf_jpsi_cand_reduced::CSnpSnpDauPos, hf_jpsi_cand_reduced::CSnpSnpDauNeg, + hf_jpsi_cand_reduced::CTglYDauPos, hf_jpsi_cand_reduced::CTglYDauNeg, + hf_jpsi_cand_reduced::CTglZDauPos, hf_jpsi_cand_reduced::CTglZDauNeg, + hf_jpsi_cand_reduced::CTglSnpDauPos, hf_jpsi_cand_reduced::CTglSnpDauNeg, + hf_jpsi_cand_reduced::CTglTglDauPos, hf_jpsi_cand_reduced::CTglTglDauNeg, + hf_jpsi_cand_reduced::C1PtYDauPos, hf_jpsi_cand_reduced::C1PtYDauNeg, + hf_jpsi_cand_reduced::C1PtZDauPos, hf_jpsi_cand_reduced::C1PtZDauNeg, + hf_jpsi_cand_reduced::C1PtSnpDauPos, hf_jpsi_cand_reduced::C1PtSnpDauNeg, + hf_jpsi_cand_reduced::C1PtTglDauPos, hf_jpsi_cand_reduced::C1PtTglDauNeg, + hf_jpsi_cand_reduced::C1Pt21Pt2DauPos, hf_jpsi_cand_reduced::C1Pt21Pt2DauNeg); + +DECLARE_SOA_TABLE(HfRedPidDau0s_000, "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_000, "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_000, "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); + +DECLARE_SOA_TABLE_VERSIONED(HfRedPidDau0s_001, "AOD", "HFREDPIDDAU0", 1, //! + hf_track_pid_reduced::TPCNSigmaPiProng0, + hf_track_pid_reduced::TOFNSigmaPiProng0, + hf_track_pid_reduced::TPCNSigmaKaProng0, + hf_track_pid_reduced::TOFNSigmaKaProng0, + hf_track_pid_reduced::TPCNSigmaPrProng0, + hf_track_pid_reduced::TOFNSigmaPrProng0, + hf_track_vars_reduced::HasTOFProng0, + hf_track_vars_reduced::HasTPCProng0, + hf_track_pid_reduced::TPCTOFNSigmaPiProng0, + hf_track_pid_reduced::TPCTOFNSigmaKaProng0, + hf_track_pid_reduced::TPCTOFNSigmaPrProng0, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE_VERSIONED(HfRedPidDau1s_001, "AOD", "HFREDPIDDAU1", 1, //! + hf_track_pid_reduced::TPCNSigmaPiProng1, + hf_track_pid_reduced::TOFNSigmaPiProng1, + hf_track_pid_reduced::TPCNSigmaKaProng1, + hf_track_pid_reduced::TOFNSigmaKaProng1, + hf_track_pid_reduced::TPCNSigmaPrProng1, + hf_track_pid_reduced::TOFNSigmaPrProng1, + hf_track_vars_reduced::HasTOFProng1, + hf_track_vars_reduced::HasTPCProng1, + hf_track_pid_reduced::TPCTOFNSigmaPiProng1, + hf_track_pid_reduced::TPCTOFNSigmaKaProng1, + hf_track_pid_reduced::TPCTOFNSigmaPrProng1, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE_VERSIONED(HfRedPidDau2s_001, "AOD", "HFREDPIDDAU2", 1, //! + hf_track_pid_reduced::TPCNSigmaPiProng2, + hf_track_pid_reduced::TOFNSigmaPiProng2, + hf_track_pid_reduced::TPCNSigmaKaProng2, + hf_track_pid_reduced::TOFNSigmaKaProng2, + hf_track_pid_reduced::TPCNSigmaPrProng2, + hf_track_pid_reduced::TOFNSigmaPrProng2, + hf_track_vars_reduced::HasTOFProng2, + hf_track_vars_reduced::HasTPCProng2, + hf_track_pid_reduced::TPCTOFNSigmaPiProng2, + hf_track_pid_reduced::TPCTOFNSigmaKaProng2, + hf_track_pid_reduced::TPCTOFNSigmaPrProng2, + o2::soa::Marker<1>); + +using HfRedPidDau0s = HfRedPidDau0s_001; +using HfRedPidDau1s = HfRedPidDau1s_001; +using HfRedPidDau2s = HfRedPidDau2s_001; + +using HfRedPidDau0 = HfRedPidDau0s::iterator; +using HfRedPidDau1 = HfRedPidDau1s::iterator; +using HfRedPidDau2 = HfRedPidDau2s::iterator; + // Beauty candidates prongs namespace hf_cand_b0_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 +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_INDEX_COLUMN_FULL(ProngD0, prongD0, int, HfRed2Prongs, "_0"); //! ProngD0 index +DECLARE_SOA_INDEX_COLUMN_FULL(ProngBachPi, prongBachPi, int, HfRedTrackBases, "_1"); //! ProngBachPi index +DECLARE_SOA_INDEX_COLUMN_FULL(ProngSoftPi, prongSoftPi, int, HfRedSoftPiBases, "_2"); //! ProngSoftPi 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_b0_reduced DECLARE_SOA_TABLE(HfRedB0Prongs, "AOD", "HFREDB0PRONG", //! Table with B0 daughter indices hf_cand_b0_reduced::Prong0Id, hf_cand_b0_reduced::Prong1Id); +DECLARE_SOA_TABLE(HfRedB0ProngDStars, "AOD", "HFREDB0PRONGDST", //! Table with B0 daughter indices + hf_cand_b0_reduced::ProngD0Id, hf_cand_b0_reduced::ProngBachPiId, hf_cand_b0_reduced::ProngSoftPiId); + DECLARE_SOA_TABLE(HfRedB0DpMls, "AOD", "HFREDB0DPML", //! Table with ML scores for the D+ daughter hf_cand_b0_reduced::Prong0MlScoreBkg, hf_cand_b0_reduced::Prong0MlScorePrompt, @@ -243,11 +771,14 @@ DECLARE_SOA_TABLE(HfRedB0DpMls, "AOD", "HFREDB0DPML", //! Table with ML scores f o2::soa::Marker<1>); using HfRedCandB0 = soa::Join; +using HfRedCandB0DStar = soa::Join; 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_INDEX_COLUMN_FULL(Jpsi, jpsi, int, HfRedJpsis, "_0"); //! J/Psi index +DECLARE_SOA_INDEX_COLUMN_FULL(BachKa, bachKa, int, HfRedBach0Bases, "_0"); //! J/Psi 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 @@ -256,13 +787,64 @@ DECLARE_SOA_COLUMN(Prong0MlScoreNonprompt, prong0MlScoreNonprompt, float); //! N 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 D+ daughter +DECLARE_SOA_TABLE(HfRedBplus2JpsiDaus, "AOD", "HFREDBP2JPSIDAU", + hf_cand_bplus_reduced::JpsiId, hf_cand_bplus_reduced::BachKaId); + +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; +using HfRedCandBplusToJpsiK = 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_INDEX_COLUMN_FULL(Jpsi, jpsi, int, HfRedJpsis, "_0"); //! J/Psi index +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0Phi, prong0Phi, int, HfRedBach0Bases, "_0"); //! J/Psi index +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1Phi, prong1Phi, int, HfRedBach1Bases, "_0"); //! J/Psi 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(HfRedBs2JpsiDaus, "AOD", "HFREDBS2JPSIDAU", + hf_cand_bs_reduced::JpsiId, hf_cand_bs_reduced::Prong0PhiId, hf_cand_bs_reduced::Prong1PhiId); + +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; +using HfRedCandBsToJpsiPhi = soa::Join; + +namespace hf_cand_lb_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 Lc daughter +DECLARE_SOA_COLUMN(Prong0MlScorePrompt, prong0MlScorePrompt, float); //! Prompt ML score of the Lc daughter +DECLARE_SOA_COLUMN(Prong0MlScoreNonprompt, prong0MlScoreNonprompt, float); //! Nonprompt ML score of the Lc daughter +} // namespace hf_cand_lb_reduced + +DECLARE_SOA_TABLE(HfRedLbProngs, "AOD", "HFREDLBPRONG", //! Table with Lb daughter indices + hf_cand_lb_reduced::Prong0Id, hf_cand_lb_reduced::Prong1Id); + +DECLARE_SOA_TABLE(HfRedLbLcMls, "AOD", "HFREDLBLCML", //! Table with ML scores for the Lc daughter + hf_cand_lb_reduced::Prong0MlScoreBkg, + hf_cand_lb_reduced::Prong0MlScorePrompt, + hf_cand_lb_reduced::Prong0MlScoreNonprompt, + o2::soa::Marker<1>); + +using HfRedCandLb = soa::Join; namespace hf_b0_mc { @@ -292,6 +874,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); @@ -306,9 +889,20 @@ DECLARE_SOA_TABLE(HfMcCheckDpPis, "AOD", "HFMCCHECKDPPI", //! Table with reconst hf_b0_mc::PdgCodeProng3, o2::soa::Marker<1>); +// table with results of reconstruction level MC matching +DECLARE_SOA_TABLE(HfMcRecRedDStarPis, "AOD", "HFMCRECREDDSTPI", //! Table with reconstructed MC information on DStarPi pairs for reduced workflow + hf_cand_b0_reduced::ProngD0Id, + hf_cand_b0_reduced::ProngBachPiId, + hf_cand_b0::FlagMcMatchRec, + hf_cand_b0::FlagWrongCollision, + hf_cand_b0::DebugMcRec, + hf_b0_mc::PtMother); + // 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::FlagMcDecayChanRec, + hf_cand_b0::FlagWrongCollision, hf_cand_b0::DebugMcRec, hf_b0_mc::PtMother); @@ -323,6 +917,7 @@ DECLARE_SOA_TABLE(HfMcCheckB0s, "AOD", "HFMCCHECKB0", //! Table with reconstruct DECLARE_SOA_TABLE(HfMcGenRedB0s, "AOD", "HFMCGENREDB0", //! Generation-level MC information on B0 candidates for reduced workflow hf_cand_b0::FlagMcMatchGen, + hf_cand_b0::FlagMcDecayChanRec, hf_b0_mc::PtTrack, hf_b0_mc::YTrack, hf_b0_mc::EtaTrack, @@ -331,7 +926,10 @@ DECLARE_SOA_TABLE(HfMcGenRedB0s, "AOD", "HFMCGENREDB0", //! Generation-level MC hf_b0_mc::EtaProng0, hf_b0_mc::PtProng1, hf_b0_mc::YProng1, - hf_b0_mc::EtaProng1); + hf_b0_mc::EtaProng1, + hf_reduced_collision::HfCollisionRejectionMap, + cent::CentFT0C, + cent::CentFT0M); // store all configurables values used in the first part of the workflow // so we can use them in the B0 part @@ -361,6 +959,7 @@ DECLARE_SOA_COLUMN(YProng1, yProng1, float); //! Rapidity of the track's pro 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 @@ -371,12 +970,24 @@ 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); + +// table with results of reconstruction level MC matching +DECLARE_SOA_TABLE(HfMcRecRedJPKs, "AOD", "HFMCRECREDJPK", //! Table with reconstructed MC information on J/PsiK(<-B+) pairs for reduced workflow + hf_cand_bplus_reduced::JpsiId, + hf_cand_bplus_reduced::BachKaId, + hf_cand_bplus::FlagMcMatchRec, + hf_cand_bplus::FlagMcDecayChanRec, + 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, @@ -385,11 +996,14 @@ DECLARE_SOA_TABLE(HfMcCheckD0Pis, "AOD", "HFMCCHECKD0PI", //! Table with reconst // 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::FlagMcDecayChanRec, + 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, @@ -397,6 +1011,7 @@ DECLARE_SOA_TABLE(HfMcCheckBps, "AOD", "HFMCCHECKBP", //! Table with reconstruct DECLARE_SOA_TABLE(HfMcGenRedBps, "AOD", "HFMCGENREDBP", //! Generation-level MC information on B+ candidates for reduced workflow hf_cand_bplus::FlagMcMatchGen, + hf_cand_bplus::FlagMcDecayChanRec, hf_bplus_mc::PtTrack, hf_bplus_mc::YTrack, hf_bplus_mc::EtaTrack, @@ -405,7 +1020,10 @@ DECLARE_SOA_TABLE(HfMcGenRedBps, "AOD", "HFMCGENREDBP", //! Generation-level MC hf_bplus_mc::EtaProng0, hf_bplus_mc::PtProng1, hf_bplus_mc::YProng1, - hf_bplus_mc::EtaProng1); + hf_bplus_mc::EtaProng1, + hf_reduced_collision::HfCollisionRejectionMap, + cent::CentFT0C, + cent::CentFT0M); // store all configurables values used in the first part of the workflow // so we can use them in the Bplus part @@ -414,6 +1032,7 @@ namespace hf_cand_bplus_config DECLARE_SOA_COLUMN(MySelectionFlagD0, mySelectionFlagD0, int8_t); //! Flag to filter selected D0 mesons DECLARE_SOA_COLUMN(MySelectionFlagD0bar, mySelectionFlagD0bar, int8_t); //! Flag to filter selected D0 mesons DECLARE_SOA_COLUMN(MyInvMassWindowD0Pi, myInvMassWindowD0Pi, float); //! Half-width of the Bplus invariant-mass window in GeV/c2 +DECLARE_SOA_COLUMN(MyInvMassWindowJpsiK, myInvMassWindowJpsiK, float); //! Half-width of the Bplus invariant-mass window in GeV/c2 } // namespace hf_cand_bplus_config DECLARE_SOA_TABLE(HfCandBpConfigs, "AOD", "HFCANDBPCONFIG", //! Table with configurables information for reduced workflow @@ -421,25 +1040,203 @@ DECLARE_SOA_TABLE(HfCandBpConfigs, "AOD", "HFCANDBPCONFIG", //! Table with confi hf_cand_bplus_config::MySelectionFlagD0bar, hf_cand_bplus_config::MyInvMassWindowD0Pi); -// Charm resonances analysis -namespace hf_reso_cand_reduced +DECLARE_SOA_TABLE(HfCfgBpToJpsi, "AOD", "HFCFGBPTOJPSI", //! Table with configurables information for reduced workflow + hf_cand_bplus_config::MyInvMassWindowJpsiK); + +namespace hf_bs_mc { -DECLARE_SOA_COLUMN(InvMass, invMass, float); //! Invariant mass in GeV/c2 -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 +// 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 -namespace hf_reso_3_prong +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); + +// table with results of reconstruction level MC matching +DECLARE_SOA_TABLE(HfMcRecRedJPPhis, "AOD", "HFMCRECREDJPPHI", //! Table with reconstructed MC information on DsPi(<-Bs) pairs for reduced workflow + hf_cand_bs_reduced::JpsiId, + hf_cand_bs_reduced::Prong0PhiId, + hf_cand_bs_reduced::Prong1PhiId, + hf_cand_bs::FlagMcMatchRec, + hf_cand_bs::FlagMcDecayChanRec, + 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::FlagMcDecayChanRec, + 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_cand_bs::FlagMcDecayChanRec, + 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, + hf_reduced_collision::HfCollisionRejectionMap, + cent::CentFT0C, + cent::CentFT0M); + +// 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 +DECLARE_SOA_COLUMN(MyInvMassWindowJpsiPhi, myInvMassWindowJpsiPhi, 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); + +DECLARE_SOA_TABLE(HfCfgBsToJpsis, "AOD", "HFCFGBSTOJPSI", //! Table with configurables information for reduced workflow + hf_cand_bs_config::MyInvMassWindowJpsiPhi); +namespace hf_lb_mc { -DECLARE_SOA_COLUMN(DType, dType, int8_t); //! Integer with selected D candidate type: 1 = Dplus, -1 = Dminus, 2 = DstarPlus, -2 = DstarMinus +// 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_DYNAMIC_COLUMN(Px, px, //! +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_lb_mc + +// table with results of reconstruction level MC matching +DECLARE_SOA_TABLE(HfMcRecRedLcPis, "AOD", "HFMCRECREDLCPI", //! Table with reconstructed MC information on LcPi(<-Lb) pairs for reduced workflow + hf_cand_lb_reduced::Prong0Id, + hf_cand_lb_reduced::Prong1Id, + hf_cand_lb::FlagMcMatchRec, + hf_cand_lb::FlagWrongCollision, + hf_cand_lb::DebugMcRec, + hf_lb_mc::PtMother); + +DECLARE_SOA_TABLE(HfMcCheckLcPis, "AOD", "HFMCCHECKLCPI", //! Table with reconstructed MC information on LcPi(<-Lb) pairs for MC checks in reduced workflow + hf_lb_mc::PdgCodeBeautyMother, + hf_lb_mc::PdgCodeCharmMother, + hf_lb_mc::PdgCodeProng0, + hf_lb_mc::PdgCodeProng1, + hf_lb_mc::PdgCodeProng2, + hf_lb_mc::PdgCodeProng3, + o2::soa::Marker<1>); + +// Table with same size as HFCANDLc +DECLARE_SOA_TABLE(HfMcRecRedLbs, "AOD", "HFMCRECREDLB", //! Reconstruction-level MC information on Lb candidates for reduced workflow + hf_cand_lb::FlagMcMatchRec, + hf_cand_lb::FlagWrongCollision, + hf_cand_lb::DebugMcRec, + hf_lb_mc::PtMother); + +DECLARE_SOA_TABLE(HfMcCheckLbs, "AOD", "HFMCCHECKLB", //! Table with reconstructed MC information on Lb candidates for MC checks in reduced workflow + hf_lb_mc::PdgCodeBeautyMother, + hf_lb_mc::PdgCodeCharmMother, + hf_lb_mc::PdgCodeProng0, + hf_lb_mc::PdgCodeProng1, + hf_lb_mc::PdgCodeProng2, + hf_lb_mc::PdgCodeProng3, + o2::soa::Marker<2>); + +DECLARE_SOA_TABLE(HfMcGenRedLbs, "AOD", "HFMCGENREDLB", //! Generation-level MC information on Lb candidates for reduced workflow + hf_cand_lb::FlagMcMatchGen, + hf_lb_mc::PtTrack, + hf_lb_mc::YTrack, + hf_lb_mc::EtaTrack, + hf_lb_mc::PtProng0, + hf_lb_mc::YProng0, + hf_lb_mc::EtaProng0, + hf_lb_mc::PtProng1, + hf_lb_mc::YProng1, + hf_lb_mc::EtaProng1, + hf_reduced_collision::HfCollisionRejectionMap, + cent::CentFT0C, + cent::CentFT0M); + +// store all configurables values used in the first part of the workflow +// so we can use them in the B0 part +namespace hf_cand_lb_config +{ +DECLARE_SOA_COLUMN(MySelectionFlagLc, mySelectionFlagLc, int8_t); //! Flag to filter selected Lc baryons +DECLARE_SOA_COLUMN(MyInvMassWindowLcPi, myInvMassWindowLcPi, float); //! Half-width of the Lb invariant-mass window in GeV/c2 +} // namespace hf_cand_lb_config + +DECLARE_SOA_TABLE(HfCandLbConfigs, "AOD", "HFCANDLBCONFIG", //! Table with configurables information for reduced workflow + hf_cand_lb_config::MySelectionFlagLc, + hf_cand_lb_config::MyInvMassWindowLcPi); + +// Charm resonances analysis +namespace hf_reso_3_prong +{ +DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Integer with selected D candidate sign +DECLARE_SOA_COLUMN(ItsNClsSoftPi, itsNClsSoftPi, int); //! minimum value of number of ITS clusters for the decay daughter tracks +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsSoftPi, tpcNClsCrossedRowsSoftPi, int); //! minimum value of number of TPC crossed rows for the decay daughter tracks +DECLARE_SOA_COLUMN(TpcChi2NClSoftPi, tpcChi2NClSoftPi, float); //! maximum value of TPC chi2 for the decay daughter tracks +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; }); @@ -449,21 +1246,33 @@ 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(InvMassDstar, invMassDstar, - [](float pxSoftPi, float pySoftPi, float pzSoftPi, float pxProng0, float pyProng0, float pzProng0, float pxProng1, float pyProng1, float pzProng1) - -> float { return RecoDecay::m(std::array{std::array{pxSoftPi, pySoftPi, pzSoftPi}, std::array{pxProng0, pyProng0, pzProng0}, std::array{pxProng1, pyProng1, pzProng1}}, std::array{constants::physics::MassPiPlus, constants::physics::MassPiPlus, constants::physics::MassKPlus}) - RecoDecay::m(std::array{std::array{pxProng0, pyProng0, pzProng0}, std::array{pxProng1, pyProng1, pzProng1}}, std::array{constants::physics::MassPiPlus, constants::physics::MassKPlus}); }); -DECLARE_SOA_DYNAMIC_COLUMN(InvMassAntiDstar, invMassAntiDstar, - [](float pxSoftPi, float pySoftPi, float pzSoftPi, float pxProng0, float pyProng0, float pzProng0, float pxProng1, float pyProng1, float pzProng1) - -> float { return RecoDecay::m(std::array{std::array{pxSoftPi, pySoftPi, pzSoftPi}, std::array{pxProng0, pyProng0, pzProng0}, std::array{pxProng1, pyProng1, pzProng1}}, std::array{constants::physics::MassPiPlus, constants::physics::MassKPlus, constants::physics::MassPiPlus}) - RecoDecay::m(std::array{std::array{pxProng0, pyProng0, pzProng0}, std::array{pxProng1, pyProng1, pzProng1}}, std::array{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_2_prong +{ +DECLARE_SOA_COLUMN(SelFlagD0, selFlagD0, uint8_t); //! Integer with D0 selection flag: 1 = selected as D0, 2 = selected as D0bar, 3 = selected as D0 and D0bar +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(PVector, pVector, + [](float pxProng0, float pyProng0, float pzProng0, float pxProng1, float pyProng1, float pzProng1) -> std::array { return std::array{pxProng0 + pxProng1, pyProng0 + pyProng1, pzProng0 + 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)); }); +} // namespace hf_reso_2_prong + namespace hf_reso_v0 { 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_DYNAMIC_COLUMN(Px, px, //! + +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; }); @@ -471,7 +1280,7 @@ 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) +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}); }); @@ -479,30 +1288,10 @@ DECLARE_SOA_DYNAMIC_COLUMN(InvMassAntiLambda, invMassAntiLambda, //! mass under [](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 -namespace hf_reso_track -{ -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(NSigmaTpcPi, nSigmaTpcPi, float); //! TPC Nsigma for pion hypothesis -DECLARE_SOA_COLUMN(NSigmaTpcKa, nSigmaTpcKa, float); //! TPC Nsigma for kaon hypothesis -DECLARE_SOA_COLUMN(NSigmaTpcPr, nSigmaTpcPr, float); //! TPC Nsigma for proton hypothesis -DECLARE_SOA_COLUMN(NSigmaTofPi, nSigmaTofPi, float); //! TOF Nsigma for pion hypothesis -DECLARE_SOA_COLUMN(NSigmaTofKa, nSigmaTofKa, float); //! TOF Nsigma for kaon hypothesis -DECLARE_SOA_COLUMN(NSigmaTofPr, nSigmaTofPr, float); //! TOF Nsigma for proton hypothesis -DECLARE_SOA_COLUMN(HasTof, hasTof, bool); //! flag for presence of TOF -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! - [](float px, float py) -> float { return RecoDecay::pt(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! - [](float px, float py) -> float { return RecoDecay::phi(px, py); }); -DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! - [](float px, float py, float pz) -> float { return RecoDecay::eta(std::array{px, py, pz}); }); - -} // namespace hf_reso_track - DECLARE_SOA_TABLE(HfRedVzeros, "AOD", "HFREDVZERO", //! Table with V0 candidate information for resonances reduced workflow o2::soa::Index<>, // Indices @@ -512,39 +1301,55 @@ DECLARE_SOA_TABLE(HfRedVzeros, "AOD", "HFREDVZERO", //! Table with V0 candidate hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, 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_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_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::TrackId, hf_track_index_reduced::HfRedCollisionId, // Static - hf_reso_track::Px, - hf_reso_track::Py, - hf_reso_track::Pz, - hf_reso_track::Sign, - hf_reso_track::NSigmaTpcPi, - hf_reso_track::NSigmaTpcKa, - hf_reso_track::NSigmaTpcPr, - hf_reso_track::NSigmaTofPi, - hf_reso_track::NSigmaTofKa, - hf_reso_track::NSigmaTofPr, - hf_reso_track::HasTof, + 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_reso_track::Pt, - hf_reso_track::Eta, - hf_reso_track::Phi); + 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, + hf_track_vars_reduced::PVector); DECLARE_SOA_TABLE(HfRed3PrNoTrks, "AOD", "HFRED3PRNOTRK", //! Table with 3 prong candidate information for resonances reduced workflow o2::soa::Index<>, @@ -556,33 +1361,292 @@ DECLARE_SOA_TABLE(HfRed3PrNoTrks, "AOD", "HFRED3PRNOTRK", //! Table with 3 prong 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_reso_3_prong::DType, + hf_track_vars_reduced::ItsNClsProngMin, hf_track_vars_reduced::TpcNClsCrossedRowsProngMin, hf_track_vars_reduced::TpcChi2NClProngMax, + hf_reso_3_prong::Sign, // 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_reso_3_prong::InvMassDstar, - hf_reso_3_prong::InvMassAntiDstar, - hf_reso_3_prong::Pt); + hf_reso_3_prong::Pt, + hf_cand::PVectorProng0, + hf_cand::PVectorProng1, + hf_cand::PVectorProng2, + hf_reso_3_prong::PVector); -DECLARE_SOA_TABLE(HfCandCharmReso, "AOD", "HFCANDCHARMRESO", //! Table with Resonance candidate information for resonances reduced workflow +DECLARE_SOA_TABLE(HfRed2PrNoTrks, "AOD", "HFRED2PRNOTRK", //! Table with 2 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::HfRedCollisionId, + // Static + hf_cand::XSecondaryVertex, hf_cand::YSecondaryVertex, hf_cand::ZSecondaryVertex, + hf_cand::PxProng0, hf_cand::PyProng0, hf_cand::PzProng0, + hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, + hf_track_vars_reduced::ItsNClsProngMin, hf_track_vars_reduced::TpcNClsCrossedRowsProngMin, hf_track_vars_reduced::TpcChi2NClProngMax, + hf_reso_2_prong::SelFlagD0, + // Dynamic + hf_reso_2_prong::Px, + hf_reso_2_prong::Py, + hf_reso_2_prong::Pz, + hf_track_vars_reduced::PtProng0, + hf_track_vars_reduced::PtProng1, + hf_track_vars_reduced::EtaProng0, + hf_track_vars_reduced::EtaProng1, + hf_reso_2_prong::PVector, + hf_cand::PVectorProng0, + hf_cand::PVectorProng1, + hf_reso_2_prong::Pt, + // InvMasses + hf_cand_dstar::InvMassD0, + hf_cand_dstar::InvMassD0Bar); + +DECLARE_SOA_TABLE(HfRedDstarNoTrks, "AOD", "HFREDDSTARNOTRK", //! 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_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::ItsNClsSoftPi, hf_reso_3_prong::TpcNClsCrossedRowsSoftPi, hf_reso_3_prong::TpcChi2NClSoftPi, + hf_reso_3_prong::Sign, + // 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_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/Tr daughter in GeV/c +DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign of the Resonance candidate +DECLARE_SOA_COLUMN(IsWrongSign, isWrongSign, int8_t); //! Flag for wrong sign of the Resonance candidate, 1 = wrong sign, 0 = right sign + +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // flag for resonance decay channel classification reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchRecD, flagMcMatchRecD, int8_t); // flag for D meson bachelor decay channel classification reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchChanD, flagMcMatchChanD, int8_t); // flag for D meson resonant channel classification reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // flag for decay channel classification generator level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, uint16_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_COLUMN(PtGen, ptGen, float); // Pt at generation level in GeV/c +DECLARE_SOA_COLUMN(InvMassGen, invMassGen, float); //! Invariant mass at generation level in GeV/c2 +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); }); +} // namespace hf_reso_cand_reduced + +namespace hf_reso_3pr_v0 +{ +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) +} // namespace hf_reso_3pr_v0 +namespace hf_reso_dstar_v0 +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfRedDstarNoTrks, "_0"); //! Prong0 index (D daughter) +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, HfRedVzeros, "_1"); //! Prong1 index (V0 daughter) +} // namespace hf_reso_dstar_v0 +namespace hf_reso_2pr_v0 +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfRed2PrNoTrks, "_0"); //! Prong0 index (D daughter) +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, HfRedVzeros, "_1"); //! Prong1 index (V0 daughter) +} // namespace hf_reso_2pr_v0 +namespace hf_reso_3pr_trk +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfRed3PrNoTrks, "_0"); //! Prong0 index (D daughter) +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, HfRedTrkNoParams, "_1"); //! Prong1 index (Track daughter) +} // namespace hf_reso_3pr_trk +namespace hf_reso_dstar_trk +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfRedDstarNoTrks, "_0"); //! Prong0 index (D daughter) +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, HfRedTrkNoParams, "_1"); //! Prong1 index (Track daughter) +} // namespace hf_reso_dstar_trk +namespace hf_reso_2pr_trk +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfRed2PrNoTrks, "_0"); //! Prong0 index (D daughter) +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, HfRedTrkNoParams, "_1"); //! Prong1 index (Track daughter) +} // namespace hf_reso_2pr_trk + +DECLARE_SOA_TABLE(HfCandCharmReso, "AOD", "HFCANDCHARMRESO", //! Table with Resonance candidate information for resonances reduced workflow + o2::soa::Index<>, + // 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_v0::Cpa, - hf_reso_v0::Dca, - hf_reso_v0::Radius); - -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, + hf_reso_cand_reduced::Sign, + hf_reso_cand_reduced::IsWrongSign, + // 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); + +DECLARE_SOA_TABLE(Hf3PrV0Ids, "AOD", "HF3PRV0ID", + hf_track_index_reduced::HfRedCollisionId, + hf_reso_3pr_v0::Prong0Id, + hf_reso_3pr_v0::Prong1Id); +DECLARE_SOA_TABLE(HfDstarV0Ids, "AOD", "HFDSTARV0ID", + hf_track_index_reduced::HfRedCollisionId, + hf_reso_dstar_v0::Prong0Id, + hf_reso_dstar_v0::Prong1Id); +DECLARE_SOA_TABLE(Hf2PrV0Ids, "AOD", "HF2PRV0ID", + hf_track_index_reduced::HfRedCollisionId, + hf_reso_2pr_v0::Prong0Id, + hf_reso_2pr_v0::Prong1Id); +DECLARE_SOA_TABLE(Hf3PrTrkIds, "AOD", "HF3PRTRKID", + hf_track_index_reduced::HfRedCollisionId, + hf_reso_3pr_trk::Prong0Id, + hf_reso_3pr_trk::Prong1Id); +DECLARE_SOA_TABLE(HfDstarTrkIds, "AOD", "HFDSTARTRKID", + hf_track_index_reduced::HfRedCollisionId, + hf_reso_dstar_trk::Prong0Id, + hf_reso_dstar_trk::Prong1Id); +DECLARE_SOA_TABLE(Hf2PrTrkIds, "AOD", "HF2PRTRKID", + hf_track_index_reduced::HfRedCollisionId, + hf_reso_2pr_trk::Prong0Id, + hf_reso_2pr_trk::Prong1Id); + +// Tables for MC Resonance analysis +// table with results of reconstruction level MC matching +DECLARE_SOA_TABLE(Hf3PrV0McRec, "AOD", "HF3PRV0MCREC", + hf_reso_3pr_v0::Prong0Id, + hf_reso_3pr_v0::Prong1Id, + hf_reso_cand_reduced::FlagMcMatchRec, + hf_reso_cand_reduced::FlagMcMatchRecD, + hf_reso_cand_reduced::FlagMcMatchChanD, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_reso_cand_reduced::PtGen, + hf_reso_cand_reduced::InvMassGen, + hf_cand::NTracksDecayed, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(HfDstarV0McRec, "AOD", "HFDSTARV0MCREC", + hf_reso_dstar_v0::Prong0Id, + hf_reso_dstar_v0::Prong1Id, + hf_reso_cand_reduced::FlagMcMatchRec, + hf_reso_cand_reduced::FlagMcMatchRecD, + hf_reso_cand_reduced::FlagMcMatchChanD, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_reso_cand_reduced::PtGen, + hf_reso_cand_reduced::InvMassGen, + hf_cand::NTracksDecayed, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(Hf2PrV0McRec, "AOD", "HF2PRV0MCREC", + hf_reso_2pr_v0::Prong0Id, + hf_reso_2pr_v0::Prong1Id, + hf_reso_cand_reduced::FlagMcMatchRec, + hf_reso_cand_reduced::FlagMcMatchRecD, + hf_reso_cand_reduced::FlagMcMatchChanD, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_reso_cand_reduced::PtGen, + hf_reso_cand_reduced::InvMassGen, + hf_cand::NTracksDecayed, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(Hf3PrTrkMcRec, "AOD", "HF3PRTRKMCREC", + hf_reso_3pr_trk::Prong0Id, + hf_reso_3pr_trk::Prong1Id, + hf_reso_cand_reduced::FlagMcMatchRec, + hf_reso_cand_reduced::FlagMcMatchRecD, + hf_reso_cand_reduced::FlagMcMatchChanD, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_reso_cand_reduced::PtGen, + hf_reso_cand_reduced::InvMassGen, + hf_cand::NTracksDecayed, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(HfDstarTrkMcRec, "AOD", "HFDSTARTRKMCREC", + hf_reso_dstar_trk::Prong0Id, + hf_reso_dstar_trk::Prong1Id, + hf_reso_cand_reduced::FlagMcMatchRec, + hf_reso_cand_reduced::FlagMcMatchRecD, + hf_reso_cand_reduced::FlagMcMatchChanD, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_reso_cand_reduced::PtGen, + hf_reso_cand_reduced::InvMassGen, + hf_cand::NTracksDecayed, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(Hf2PrTrkMcRec, "AOD", "HF2PRTRKMCREC", + hf_reso_2pr_trk::Prong0Id, + hf_reso_2pr_trk::Prong1Id, + hf_reso_cand_reduced::FlagMcMatchRec, + hf_reso_cand_reduced::FlagMcMatchRecD, + hf_reso_cand_reduced::FlagMcMatchChanD, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_reso_cand_reduced::PtGen, + hf_reso_cand_reduced::InvMassGen, + hf_cand::NTracksDecayed, + 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, + hf_reso_cand_reduced::InvMassGen, + hf_reduced_collision::HfCollisionRejectionMap, + o2::soa::Marker<1>); + +// 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::FlagMcMatchRecD, + hf_reso_cand_reduced::FlagMcMatchChanD, + hf_reso_cand_reduced::DebugMcRec, + hf_reso_cand_reduced::Origin, + hf_reso_cand_reduced::PtGen, + hf_reso_cand_reduced::InvMassGen, + hf_cand::NTracksDecayed, o2::soa::Marker<1>); } // namespace aod diff --git a/PWGHF/D2H/Macros/CMakeLists_HFInvMassFitter.txt b/PWGHF/D2H/Macros/CMakeLists_HFInvMassFitter.txt new file mode 100644 index 00000000000..5a74cec1768 --- /dev/null +++ b/PWGHF/D2H/Macros/CMakeLists_HFInvMassFitter.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.10) + +project(HFInvMassFitter) + +set(HFFITTER_RAPIDJSON_INCLUDE_DIRS "" CACHE STRING "Location of rapidjson include directories") + +find_package(ROOT REQUIRED COMPONENTS RooFit RooFitCore) + +include_directories(${ROOT_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${HFFITTER_RAPIDJSON_INCLUDE_DIRS}) + +set(SOURCES + HFInvMassFitter.cxx + runMassFitter.C +) + +add_executable(runMassFitter ${SOURCES} "HFInvMassFitter.h") + +ROOT_GENERATE_DICTIONARY(G__HFInvMassFitter + HFInvMassFitter.h LINKDEF HFInvMassFitterLinkDef.h + MODULE runMassFitter +) + +target_link_libraries(runMassFitter PRIVATE ${ROOT_LIBRARIES} ROOT::EG ROOT::RooFit ROOT::RooFitCore) diff --git a/PWGHF/D2H/Macros/HFInvMassFitter.cxx b/PWGHF/D2H/Macros/HFInvMassFitter.cxx index 9b1ac55cd31..843712e2245 100644 --- a/PWGHF/D2H/Macros/HFInvMassFitter.cxx +++ b/PWGHF/D2H/Macros/HFInvMassFitter.cxx @@ -16,50 +16,70 @@ /// \author Mingyu Zhang /// \author Xinye Peng /// \author Biao Zhang +/// \author Oleksii Lubynets +/// \author Phil Stahlhut #include "HFInvMassFitter.h" -#include -#include -#include #include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include using namespace RooFit; -using namespace std; ClassImp(HFInvMassFitter); -HFInvMassFitter::HFInvMassFitter() : TNamed(), - mHistoInvMass(0x0), +HFInvMassFitter::HFInvMassFitter() : mHistoInvMass(nullptr), mFitOption("L,E"), mMinMass(0), mMaxMass(5), mTypeOfBkgPdf(Expo), - mMassParticle(1.864), mTypeOfSgnPdf(SingleGaus), mTypeOfReflPdf(1), + mMassParticle(TDatabasePDG::Instance()->GetParticle("D0")->Mass()), mMass(1.865), + mMassLowLimit(0), + mMassUpLimit(0), + mMassReflLowLimit(0), + mMassReflUpLimit(0), mSecMass(1.969), - mMassErr(0.), mSigmaSgn(0.012), mSecSigma(0.006), mNSigmaForSidebands(4.), mNSigmaForSgn(3.), mSigmaSgnErr(0.), - mSigmaSgnDoubleGaus(0.012), + mSigmaSgnDoubleGaus(0.025), mFixedMean(kFALSE), mBoundMean(kFALSE), mBoundReflMean(kFALSE), - mRooMeanSgn(0x0), - mRooSigmaSgn(0x0), - mMassLowLimit(0), - mMassUpLimit(0), - mMassReflLowLimit(0), - mMassReflUpLimit(0), mFixedSigma(kFALSE), mFixedSigmaDoubleGaus(kFALSE), mBoundSigma(kFALSE), @@ -74,97 +94,115 @@ HFInvMassFitter::HFInvMassFitter() : TNamed(), mEnableReflections(kFALSE), mRawYield(0), mRawYieldErr(0), + mRawYieldCounted(0), + mRawYieldCountedErr(0), mBkgYield(0), mBkgYieldErr(0), mSignificance(0), mSignificanceErr(0), - mChiSquareOverNdf(0), - mSgnPdf(0x0), - mBkgPdf(0x0), - mReflPdf(0x0), + mChiSquareOverNdfTotal(0), + mChiSquareOverNdfBkg(0), + mFixReflOverSgn(kFALSE), + mRooMeanSgn(nullptr), + mRooSigmaSgn(nullptr), + mRooSecSigmaSgn(nullptr), + mRooFracDoubleGaus(nullptr), + mSgnPdf(nullptr), + mBkgPdf(nullptr), + mReflPdf(nullptr), + mRooNSgn(nullptr), + mRooNBkg(nullptr), + mRooNRefl(nullptr), + mTotalPdf(nullptr), + mInvMassFrame(nullptr), + mReflFrame(nullptr), + mReflOnlyFrame(nullptr), + mResidualFrame(nullptr), + mResidualFrameForCalculation(nullptr), + mWorkspace(nullptr), mIntegralHisto(0), mIntegralBkg(0), mIntegralSgn(0), - mRooNSgn(0x0), - mRooNBkg(0x0), - mRooNRefl(0x0), - mTotalPdf(0x0), - mInvMassFrame(0x0), - mReflFrame(0x0), - mReflOnlyFrame(0x0), - mResidualFrame(0x0), - mWorkspace(0x0), - mHistoTemplateRefl(0x0) + mHistoTemplateRefl(nullptr), + mDrawBgPrefit(kFALSE), + mHighlightPeakRegion(kFALSE) { // default constructor } -HFInvMassFitter::HFInvMassFitter(const TH1F* histoToFit, Double_t minValue, Double_t maxValue, Int_t fitTypeBkg, Int_t fitTypeSgn) : TNamed(), - mHistoInvMass(0x0), - mFitOption("L,E"), - mMinMass(minValue), - mMaxMass(maxValue), - mTypeOfBkgPdf(fitTypeBkg), - mMassParticle(1.864), - mTypeOfSgnPdf(fitTypeSgn), - mTypeOfReflPdf(1), - mMass(1.865), - mSecMass(1.969), - mMassErr(0.), - mSigmaSgn(0.012), - mSecSigma(0.006), - mNSigmaForSidebands(3.), - mNSigmaForSgn(3.), - mSigmaSgnErr(0.), - mSigmaSgnDoubleGaus(0.012), - mFixedMean(kFALSE), - mBoundMean(kFALSE), - mBoundReflMean(kFALSE), - mRooMeanSgn(0x0), - mRooSigmaSgn(0x0), - mMassLowLimit(0), - mMassUpLimit(0), - mMassReflLowLimit(0), - mMassReflUpLimit(0), - mFixedSigma(kFALSE), - mFixedSigmaDoubleGaus(kFALSE), - mBoundSigma(kFALSE), - mSigmaValue(0.012), - mParamSgn(0.1), - mFracDoubleGaus(0.2), - mFixedRawYield(-1.), - mFixedFracDoubleGaus(kFALSE), - mRatioDoubleGausSigma(0.), - mFixedRatioDoubleGausSigma(kFALSE), - mReflOverSgn(0), - mEnableReflections(kFALSE), - mRawYield(0), - mRawYieldErr(0), - mBkgYield(0), - mBkgYieldErr(0), - mSignificance(0), - mSignificanceErr(0), - mChiSquareOverNdf(0), - mSgnPdf(0x0), - mBkgPdf(0x0), - mReflPdf(0x0), - mIntegralHisto(0), - mIntegralBkg(0), - mIntegralSgn(0), - mRooNSgn(0x0), - mRooNBkg(0x0), - mRooNRefl(0x0), - mTotalPdf(0x0), - mInvMassFrame(0x0), - mReflFrame(0x0), - mReflOnlyFrame(0x0), - mResidualFrame(0x0), - mWorkspace(0x0), - mHistoTemplateRefl(0x0) +HFInvMassFitter::HFInvMassFitter(const TH1* histoToFit, Double_t minValue, Double_t maxValue, Int_t fitTypeBkg, Int_t fitTypeSgn) : mHistoInvMass(nullptr), + mFitOption("L,E"), + mMinMass(minValue), + mMaxMass(maxValue), + mTypeOfBkgPdf(fitTypeBkg), + mTypeOfSgnPdf(fitTypeSgn), + mTypeOfReflPdf(1), + mMassParticle(TDatabasePDG::Instance()->GetParticle("D0")->Mass()), + mMass(1.865), + mMassLowLimit(0), + mMassUpLimit(0), + mMassReflLowLimit(0), + mMassReflUpLimit(0), + mSecMass(1.969), + mSigmaSgn(0.012), + mSecSigma(0.006), + mNSigmaForSidebands(3.), + mNSigmaForSgn(3.), + mSigmaSgnErr(0.), + mSigmaSgnDoubleGaus(0.025), + mFixedMean(kFALSE), + mBoundMean(kFALSE), + mBoundReflMean(kFALSE), + mFixedSigma(kFALSE), + mFixedSigmaDoubleGaus(kFALSE), + mBoundSigma(kFALSE), + mSigmaValue(0.012), + mParamSgn(0.1), + mFracDoubleGaus(0.2), + mFixedRawYield(-1.), + mFixedFracDoubleGaus(kFALSE), + mRatioDoubleGausSigma(0.), + mFixedRatioDoubleGausSigma(kFALSE), + mReflOverSgn(0), + mEnableReflections(kFALSE), + mRawYield(0), + mRawYieldErr(0), + mRawYieldCounted(0), + mRawYieldCountedErr(0), + mBkgYield(0), + mBkgYieldErr(0), + mSignificance(0), + mSignificanceErr(0), + mChiSquareOverNdfTotal(0), + mChiSquareOverNdfBkg(0), + mFixReflOverSgn(kFALSE), + mRooMeanSgn(nullptr), + mRooSigmaSgn(nullptr), + mRooSecSigmaSgn(nullptr), + mRooFracDoubleGaus(nullptr), + mSgnPdf(nullptr), + mBkgPdf(nullptr), + mReflPdf(nullptr), + mRooNSgn(nullptr), + mRooNBkg(nullptr), + mRooNRefl(nullptr), + mTotalPdf(nullptr), + mInvMassFrame(nullptr), + mReflFrame(nullptr), + mReflOnlyFrame(nullptr), + mResidualFrame(nullptr), + mResidualFrameForCalculation(nullptr), + mWorkspace(nullptr), + mIntegralHisto(0), + mIntegralBkg(0), + mIntegralSgn(0), + mHistoTemplateRefl(nullptr), + mDrawBgPrefit(kFALSE), + mHighlightPeakRegion(kFALSE) { // standard constructor - mHistoInvMass = reinterpret_cast(histoToFit->Clone(histoToFit->GetTitle())); - mHistoInvMass->SetDirectory(0); + mHistoInvMass = dynamic_cast(histoToFit->Clone(histoToFit->GetTitle())); + mHistoInvMass->SetDirectory(nullptr); } HFInvMassFitter::~HFInvMassFitter() @@ -175,6 +213,8 @@ HFInvMassFitter::~HFInvMassFitter() delete mHistoTemplateRefl; delete mRooMeanSgn; delete mRooSigmaSgn; + delete mRooSecSigmaSgn; + delete mRooFracDoubleGaus; delete mSgnPdf; delete mBkgPdf; delete mReflPdf; @@ -189,7 +229,7 @@ HFInvMassFitter::~HFInvMassFitter() delete mWorkspace; } -void HFInvMassFitter::doFit(Bool_t draw) +void HFInvMassFitter::doFit() { mIntegralHisto = mHistoInvMass->Integral(mHistoInvMass->FindBin(mMinMass), mHistoInvMass->FindBin(mMaxMass)); mWorkspace = new RooWorkspace("mWorkspace"); @@ -197,10 +237,10 @@ void HFInvMassFitter::doFit(Bool_t draw) RooRealVar* mass = mWorkspace->var("mass"); RooDataHist dataHistogram("dataHistogram", "data", *mass, Import(*mHistoInvMass)); - if (mTypeOfBkgPdf == 6) { // MC + if (mTypeOfBkgPdf == NoBkg) { // MC mass->setRange("signal", mMass - 3. * mSigmaSgn, mMass + 3. * mSigmaSgn); } else { - if (mTypeOfSgnPdf == 3) { // Second Peak fit range + if (mTypeOfSgnPdf == GausSec) { // Second Peak fit range mass->setRange("SBL", mMinMass, mMass - mNSigmaForSidebands * mSigmaSgn); mass->setRange("SBR", mMass + mNSigmaForSidebands * mSigmaSgn, mSecMass - mNSigmaForSidebands * mSecSigma); mass->setRange("SEC", mSecMass + mNSigmaForSidebands * mSecSigma, mMaxMass); @@ -221,41 +261,53 @@ void HFInvMassFitter::doFit(Bool_t draw) RooAbsPdf* bkgPdf = createBackgroundFitFunction(mWorkspace); // Create background pdf RooAbsPdf* sgnPdf = createSignalFitFunction(mWorkspace); // Create signal pdf - // fir MC or Data - if (mTypeOfBkgPdf == 6) { // MC + // fit MC or Data + if (mTypeOfBkgPdf == NoBkg) { // MC mRooNSgn = new RooRealVar("mRooNSig", "number of signal", 0.3 * mIntegralHisto, 0., 1.2 * mIntegralHisto); // signal yield mTotalPdf = new RooAddPdf("mMCFunc", "MC fit function", RooArgList(*sgnPdf), RooArgList(*mRooNSgn)); // create total pdf - if (!strcmp(mFitOption.Data(), "Chi2")) { + if (strcmp(mFitOption.Data(), "Chi2") == 0) { mTotalPdf->chi2FitTo(dataHistogram, Range("signal")); } else { mTotalPdf->fitTo(dataHistogram, Range("signal")); } - RooAbsReal* signalIntergralMc = mTotalPdf->createIntegral(*mass, NormSet(*mass), Range("signal")); // sig yield from fit - mIntegralSgn = signalIntergralMc->getValV(); + RooAbsReal* signalIntegralMc = mTotalPdf->createIntegral(*mass, NormSet(*mass), Range("signal")); // sig yield from fit + mIntegralSgn = signalIntegralMc->getValV(); calculateSignal(mRawYield, mRawYieldErr); // calculate signal and signal error mTotalPdf->plotOn(mInvMassFrame, Name("Tot_c")); // plot total function } else { // data mBkgPdf = new RooAddPdf("mBkgPdf", "background fit function", RooArgList(*bkgPdf), RooArgList(*mRooNBkg)); - if (mTypeOfSgnPdf == 3) { // two peak fit - if (!strcmp(mFitOption.Data(), "Chi2")) { + if (mTypeOfSgnPdf == GausSec) { // two peak fit + if (strcmp(mFitOption.Data(), "Chi2") == 0) { mBkgPdf->chi2FitTo(dataHistogram, Range("SBL,SBR,SEC"), Save()); } else { mBkgPdf->fitTo(dataHistogram, Range("SBL,SBR,SEC"), Save()); } } else { // single peak fit - if (!strcmp(mFitOption.Data(), "Chi2")) { + if (strcmp(mFitOption.Data(), "Chi2") == 0) { mBkgPdf->chi2FitTo(dataHistogram, Range("SBL,SBR"), Save()); } else { mBkgPdf->fitTo(dataHistogram, Range("SBL,SBR"), Save()); } } + // define the frame to evaluate background sidebands chi2 (bg pdf needs to be plotted within sideband ranges) + RooPlot* frameTemporary = mass->frame(Title(Form("%s_temp", mHistoInvMass->GetTitle()))); + dataHistogram.plotOn(frameTemporary, Name("data_for_bkgchi2")); + mBkgPdf->plotOn(frameTemporary, Range("SBL", true), Name("Bkg_sidebands")); + mChiSquareOverNdfBkg = frameTemporary->chiSquare("Bkg_sidebands", "data_for_bkgchi2"); // calculate reduced chi2 / NDF of background sidebands (pre-fit) + delete frameTemporary; + RooAbsPdf* mBkgPdfPrefit{nullptr}; + if (mDrawBgPrefit) { + mBkgPdfPrefit = dynamic_cast(mBkgPdf->Clone()); + mBkgPdfPrefit->plotOn(mInvMassFrame, Range("full"), Name("Bkg_c_prefit"), LineColor(kGray)); + delete mBkgPdfPrefit; + } // estimate signal yield RooAbsReal* bkgIntegral = mBkgPdf->createIntegral(*mass, NormSet(*mass), Range("bkg")); // bkg integral - mIntegralBkg = bkgIntegral->getValV(); + mIntegralBkg = bkgIntegral->getValV(); // fraction of BG's integral in "bkg" range out of that in "full" range (which is 1 by construction). Not an absolute value. Double_t estimatedSignal; - checkForSignal(estimatedSignal); - calculateBackground(mBkgYield, mBkgYieldErr); + checkForSignal(estimatedSignal); // SIG's absolute integral in "bkg" range + calculateBackground(mBkgYield, mBkgYieldErr); // BG's absolute integral in "bkg" range mRooNSgn = new RooRealVar("mNSgn", "number of signal", 0.3 * estimatedSignal, 0., 1.2 * estimatedSignal); // estimated signal yield if (mFixedRawYield > 0) { @@ -264,7 +316,7 @@ void HFInvMassFitter::doFit(Bool_t draw) } mSgnPdf = new RooAddPdf("mSgnPdf", "signal fit function", RooArgList(*sgnPdf), RooArgList(*mRooNSgn)); // create reflection template and fit to reflection - if (mHistoTemplateRefl) { + if (mHistoTemplateRefl != nullptr) { RooAbsPdf* reflPdf = createReflectionFitFunction(mWorkspace); // create reflection pdf RooDataHist reflHistogram("reflHistogram", "refl for fit", *mass, Import(*mHistoTemplateRefl)); mReflFrame = mass->frame(); @@ -272,7 +324,7 @@ void HFInvMassFitter::doFit(Bool_t draw) reflHistogram.plotOn(mReflOnlyFrame); mRooNRefl = new RooRealVar("mNRefl", "number of reflection", 0.5 * mHistoTemplateRefl->Integral(), 0, mHistoTemplateRefl->Integral()); RooAddPdf reflFuncTemp("reflFuncTemp", "template reflection fit function", RooArgList(*reflPdf), RooArgList(*mRooNRefl)); - if (!strcmp(mFitOption.Data(), "Chi2")) { + if (strcmp(mFitOption.Data(), "Chi2") == 0) { reflFuncTemp.chi2FitTo(reflHistogram); } else { reflFuncTemp.fitTo(reflHistogram); @@ -283,18 +335,18 @@ void HFInvMassFitter::doFit(Bool_t draw) mRooNRefl->setConstant(kTRUE); setReflFuncFixed(); // fix reflection pdf parameter mTotalPdf = new RooAddPdf("mTotalPdf", "background + signal + reflection fit function", RooArgList(*bkgPdf, *sgnPdf, *reflPdf), RooArgList(*mRooNBkg, *mRooNSgn, *mRooNRefl)); - if (!strcmp(mFitOption.Data(), "Chi2")) { + if (strcmp(mFitOption.Data(), "Chi2") == 0) { mTotalPdf->chi2FitTo(dataHistogram); } else { mTotalPdf->fitTo(dataHistogram); } mTotalPdf->plotOn(mInvMassFrame, Name("Tot_c")); mReflPdf = new RooAddPdf("mReflPdf", "reflection fit function", RooArgList(*reflPdf), RooArgList(*mRooNRefl)); - RooAddPdf reflBkgPdf("reflBkgPdf", "reflBkgPdf", RooArgList(*bkgPdf, *reflPdf), RooArgList(*mRooNBkg, *mRooNRefl)); + RooAddPdf const reflBkgPdf("reflBkgPdf", "reflBkgPdf", RooArgList(*bkgPdf, *reflPdf), RooArgList(*mRooNBkg, *mRooNRefl)); reflBkgPdf.plotOn(mInvMassFrame, Normalization(1.0, RooAbsReal::RelativeExpected), LineStyle(7), LineColor(kRed + 1), Name("ReflBkg_c")); - plotBkg(mTotalPdf); // plot bkg pdf in total pdf - plotRefl(mTotalPdf); // plot reflection in total pdf - mChiSquareOverNdf = mInvMassFrame->chiSquare("Tot_c", "data_c"); // calculate reduced chi2 / NDF + plotBkg(mTotalPdf); // plot bkg pdf in total pdf + plotRefl(mTotalPdf); // plot reflection in total pdf + mChiSquareOverNdfTotal = mInvMassFrame->chiSquare("Tot_c", "data_c"); // calculate reduced chi2 / NDF // plot residual distribution RooHist* residualHistogram = mInvMassFrame->residHist("data_c", "ReflBkg_c"); @@ -303,23 +355,23 @@ void HFInvMassFitter::doFit(Bool_t draw) mSgnPdf->plotOn(mResidualFrame, Normalization(1.0, RooAbsReal::RelativeExpected), LineColor(kBlue)); } else { mTotalPdf = new RooAddPdf("mTotalPdf", "background + signal pdf", RooArgList(*bkgPdf, *sgnPdf), RooArgList(*mRooNBkg, *mRooNSgn)); - if (!strcmp(mFitOption.Data(), "Chi2")) { + if (strcmp(mFitOption.Data(), "Chi2") == 0) { mTotalPdf->chi2FitTo(dataHistogram); } else { mTotalPdf->fitTo(dataHistogram); } plotBkg(mTotalPdf); - mTotalPdf->plotOn(mInvMassFrame, Components("mReflFuncDoubleGaus"), Name("refl_c"), LineColor(kGreen)); mTotalPdf->plotOn(mInvMassFrame, Name("Tot_c"), LineColor(kBlue)); - mChiSquareOverNdf = mInvMassFrame->chiSquare("Tot_c", "data_c"); // calculate refuced chi2 / DNF + mSgnPdf->plotOn(mInvMassFrame, Normalization(1.0, RooAbsReal::RelativeExpected), DrawOption("F"), FillColor(TColor::GetColorTransparent(kBlue, 0.2)), VLines()); + mChiSquareOverNdfTotal = mInvMassFrame->chiSquare("Tot_c", "data_c"); // calculate reduced chi2 / DNF + // plot residual distribution mResidualFrame = mass->frame(Title("Residual Distribution")); RooHist* residualHistogram = mInvMassFrame->residHist("data_c", "Bkg_c"); mResidualFrame->addPlotable(residualHistogram, "P"); mSgnPdf->plotOn(mResidualFrame, Normalization(1.0, RooAbsReal::RelativeExpected), LineColor(kBlue)); - mTotalPdf->plotOn(mResidualFrame, Components(*mSgnPdf), Normalization(1.0, RooAbsReal::RelativeExpected), LineColor(kBlue)); } - mass->setRange("bkgForSignificance", mRooMeanSgn->getVal() - mNSigmaForSgn * mRooSigmaSgn->getVal(), mRooMeanSgn->getVal() + mNSigmaForSgn * mRooSigmaSgn->getVal()); + mass->setRange("bkgForSignificance", mRooMeanSgn->getVal() - mNSigmaForSgn * mRooSecSigmaSgn->getVal(), mRooMeanSgn->getVal() + mNSigmaForSgn * mRooSecSigmaSgn->getVal()); bkgIntegral = mBkgPdf->createIntegral(*mass, NormSet(*mass), Range("bkgForSignificance")); mIntegralBkg = bkgIntegral->getValV(); calculateBackground(mBkgYield, mBkgYieldErr); @@ -327,51 +379,62 @@ void HFInvMassFitter::doFit(Bool_t draw) RooAbsReal* sgnIntegral = mSgnPdf->createIntegral(*mass, NormSet(*mass), Range("signal")); mIntegralSgn = sgnIntegral->getValV(); calculateSignal(mRawYield, mRawYieldErr); + countSignal(mRawYieldCounted, mRawYieldCountedErr); calculateSignificance(mSignificance, mSignificanceErr); + // Fit to data ratio + mRatioFrame = mass->frame(Title(Form("%s", mHistoInvMass->GetTitle()))); + calculateFitToDataRatio(); } } -void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) +void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) const { // Declare observable variable - RooRealVar mass("mass", "mass", mMinMass, mMaxMass, "GeV/c"); + RooRealVar mass("mass", "mass", mMinMass, mMaxMass, "GeV/c^{2}"); // bkg expo RooRealVar tau("tau", "tau", -1, -5., 5.); RooAbsPdf* bkgFuncExpo = new RooExponential("bkgFuncExpo", "background fit function", mass, tau); workspace.import(*bkgFuncExpo); + delete bkgFuncExpo; // bkg poly1 - RooRealVar PolyParam0("PolyParam0", "Parameter of Poly function", 0.5, -5., 5.); - RooRealVar PolyParam1("PolyParam1", "Parameter of Poly function", 0.2, -5., 5.); - RooAbsPdf* bkgFuncPoly1 = new RooPolynomial("bkgFuncPoly1", "background fit function", mass, RooArgSet(PolyParam0, PolyParam1)); + RooRealVar const polyParam0("polyParam0", "Parameter of Poly function", 0.5, -5., 5.); + RooRealVar const polyParam1("polyParam1", "Parameter of Poly function", 0.2, -5., 5.); + RooAbsPdf* bkgFuncPoly1 = new RooPolynomial("bkgFuncPoly1", "background fit function", mass, RooArgSet(polyParam0, polyParam1)); workspace.import(*bkgFuncPoly1); + delete bkgFuncPoly1; // bkg poly2 - RooRealVar PolyParam2("PolyParam2", "Parameter of Poly function", 0.2, -5., 5.); - RooAbsPdf* bkgFuncPoly2 = new RooPolynomial("bkgFuncPoly2", "background fit function", mass, RooArgSet(PolyParam0, PolyParam1, PolyParam2)); + RooRealVar const polyParam2("polyParam2", "Parameter of Poly function", 0.2, -5., 5.); + RooAbsPdf* bkgFuncPoly2 = new RooPolynomial("bkgFuncPoly2", "background fit function", mass, RooArgSet(polyParam0, polyParam1, polyParam2)); workspace.import(*bkgFuncPoly2); + delete bkgFuncPoly2; // bkg poly3 - RooRealVar PolyParam3("PolyParam3", "Parameter of Poly function", 0.2, -1., 1.); - RooAbsPdf* bkgFuncPoly3 = new RooPolynomial("bkgFuncPoly3", "background pdf", mass, RooArgSet(PolyParam0, PolyParam1, PolyParam2, PolyParam3)); + RooRealVar const polyParam3("polyParam3", "Parameter of Poly function", 0.2, -1., 1.); + RooAbsPdf* bkgFuncPoly3 = new RooPolynomial("bkgFuncPoly3", "background pdf", mass, RooArgSet(polyParam0, polyParam1, polyParam2, polyParam3)); workspace.import(*bkgFuncPoly3); + delete bkgFuncPoly3; // bkg power law - RooRealVar PowParam1("PowParam1", "Parameter of Pow function", 0.13957); - RooRealVar PowParam2("PowParam2", "Parameter of Pow function", 1., -10, 10); - RooAbsPdf* bkgFuncPow = new RooGenericPdf("bkgFuncPow", "bkgFuncPow", "(mass-PowParam1)^PowParam2", RooArgSet(mass, PowParam1, PowParam2)); + RooRealVar const powParam1("powParam1", "Parameter of Pow function", TDatabasePDG::Instance()->GetParticle("pi+")->Mass()); + RooRealVar const powParam2("powParam2", "Parameter of Pow function", 1., -10, 10); + RooAbsPdf* bkgFuncPow = new RooGenericPdf("bkgFuncPow", "bkgFuncPow", "(mass-powParam1)^powParam2", RooArgSet(mass, powParam1, powParam2)); workspace.import(*bkgFuncPow); + delete bkgFuncPow; // pow * exp - RooRealVar PowExpoParam1("PowExpoParam1", "Parameter of PowExpo function", 1 / 2); - RooRealVar PowExpoParam2("PowExpoParam2", "Parameter of PowExpo function", 1, -10, 10); - RooRealVar massPi("massPi", "mass of pion", 0.13957); - RooFormulaVar PowExpoParam3("PowExpoParam3", "PowExpoParam1 + 1", RooArgList(PowExpoParam1)); - RooFormulaVar PowExpoParam4("PowExpoParam4", "1./PowExpoParam2", RooArgList(PowExpoParam2)); - RooAbsPdf* bkgFuncPowExpo = new RooGamma("bkgFuncPowExpo", "background pdf", mass, PowExpoParam3, PowExpoParam4, massPi); + RooRealVar const powExpoParam1("powExpoParam1", "Parameter of PowExpo function", 1. / 2.); + RooRealVar const powExpoParam2("powExpoParam2", "Parameter of PowExpo function", 1, -10, 10); + RooRealVar massPi("massPi", "mass of pion", TDatabasePDG::Instance()->GetParticle("pi+")->Mass()); + RooFormulaVar powExpoParam3("powExpoParam3", "powExpoParam1 + 1", RooArgList(powExpoParam1)); + RooFormulaVar powExpoParam4("powExpoParam4", "1./powExpoParam2", RooArgList(powExpoParam2)); + RooAbsPdf* bkgFuncPowExpo = new RooGamma("bkgFuncPowExpo", "background pdf", mass, powExpoParam3, powExpoParam4, massPi); workspace.import(*bkgFuncPowExpo); + delete bkgFuncPowExpo; + // signal pdf - RooRealVar mean("mean", "mean for signal fit", mMass, 1.86, 1.87); + RooRealVar mean("mean", "mean for signal fit", mMass, 0, 5); if (mBoundMean) { mean.setMax(mMassUpLimit); mean.setMin(mMassLowLimit); } - // signal Guassian + // signal Gaussian if (mFixedMean) { mean.setVal(mMass); mean.setConstant(kTRUE); @@ -387,11 +450,12 @@ void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) } RooAbsPdf* sgnFuncGaus = new RooGaussian("sgnFuncGaus", "signal pdf", mass, mean, sigma); workspace.import(*sgnFuncGaus); - // signal double Gaussianaa - RooRealVar sigmaDoubleGaus("sigmaDoubleGaus", "sigma2Gaus", mSigmaSgn, mSigmaSgn - 0.01, mSigmaSgn + 0.01); + delete sgnFuncGaus; + // signal double Gaussian + RooRealVar sigmaDoubleGaus("sigmaDoubleGaus", "sigma2Gaus", mSigmaSgnDoubleGaus, mSigmaSgnDoubleGaus - 0.003, mSigmaSgnDoubleGaus + 0.003); if (mBoundSigma) { - sigmaDoubleGaus.setMax(mSigmaSgn * (1 + mParamSgn)); - sigmaDoubleGaus.setMin(mSigmaSgn * (1 - mParamSgn)); + sigmaDoubleGaus.setMax(mSigmaSgnDoubleGaus * (1 + mParamSgn)); + sigmaDoubleGaus.setMin(mSigmaSgnDoubleGaus * (1 - mParamSgn)); } if (mFixedSigma) { sigma.setVal(mSigmaSgn); @@ -401,8 +465,8 @@ void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) sigmaDoubleGaus.setVal(mSigmaSgnDoubleGaus); sigmaDoubleGaus.setConstant(kTRUE); } - RooGaussian gaus1("gaus1", "gaus1", mass, mean, sigma); - RooGaussian gaus2("gaus2", "gaus2", mass, mean, sigmaDoubleGaus); + RooGaussian const gaus1("gaus1", "gaus1", mass, mean, sigma); + RooGaussian const gaus2("gaus2", "gaus2", mass, mean, sigmaDoubleGaus); RooRealVar fracDoubleGaus("fracDoubleGaus", "frac of two gauss", mFracDoubleGaus, 0, 1.); if (mFixedFracDoubleGaus) { fracDoubleGaus.setVal(mFracDoubleGaus); @@ -410,6 +474,7 @@ void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) } RooAbsPdf* sgnFuncDoubleGaus = new RooAddPdf("sgnFuncDoubleGaus", "signal pdf", RooArgList(gaus1, gaus2), fracDoubleGaus); workspace.import(*sgnFuncDoubleGaus); + delete sgnFuncDoubleGaus; // double Gaussian ratio RooRealVar ratio("ratio", "ratio of sigma12", mRatioDoubleGausSigma, 0, 10); if (mFixedSigma) { @@ -425,8 +490,8 @@ void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) sigma.setMin(mSigmaSgn * (1 - mParamSgn)); } RooRealVar sigmaDoubleGausRatio("sigmaDoubleGausRatio", "sigmaDoubleGausRatio", sigma.getVal() * ratio.getVal()); - RooGaussian gausRatio1("gausRatio1", "gausratio1", mass, mean, sigma); - RooGaussian gausRatio2("gausRatio2", "gausratio2", mass, mean, sigmaDoubleGausRatio); + RooGaussian const gausRatio1("gausRatio1", "gausratio1", mass, mean, sigma); + RooGaussian const gausRatio2("gausRatio2", "gausratio2", mass, mean, sigmaDoubleGausRatio); RooRealVar fracDoubleGausRatio("fracDoubleGausRatio", "fraction of two gauss ratio", 0.5, 0, 1.); if (mFixedFracDoubleGaus) { fracDoubleGausRatio.setVal(mFracDoubleGaus); @@ -434,6 +499,7 @@ void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) } RooAbsPdf* sgnFuncGausRatio = new RooAddPdf("sgnFuncGausRatio", "signal pdf", RooArgList(gausRatio1, gausRatio2), fracDoubleGausRatio); workspace.import(*sgnFuncGausRatio); + delete sgnFuncGausRatio; // double peak for Ds RooRealVar meanSec("meanSec", "mean for second peak fit", mSecMass, mMinMass, mMaxMass); RooRealVar sigmaSec("sigmaSec", "sigmaSec", mSecSigma, mSecSigma - 0.005, mSecSigma + 0.01); @@ -453,11 +519,12 @@ void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) sigmaSec.setMax(mSecSigma * (1 + mParamSgn)); sigmaSec.setMin(mSecSigma * (1 - mParamSgn)); } - RooGaussian gausSec1("gausSec1", "gausSec1", mass, mean, sigmaSec); - RooGaussian gausSec2("gausSec2", "gausSec2", mass, meanSec, sigmaSec); - RooRealVar fracSec("fracSec", "frac of two peak", 0.5, 0, 1.); + RooGaussian const gausSec1("gausSec1", "gausSec1", mass, mean, sigmaSec); + RooGaussian const gausSec2("gausSec2", "gausSec2", mass, meanSec, sigmaSec); + RooRealVar const fracSec("fracSec", "frac of two peak", 0.5, 0, 1.); RooAbsPdf* sgnFuncDoublePeak = new RooAddPdf("sgnFuncDoublePeak", "signal pdf", RooArgList(gausSec1, gausSec2), fracSec); workspace.import(*sgnFuncDoublePeak); + delete sgnFuncDoublePeak; // reflection Gaussian RooRealVar meanRefl("meanRefl", "mean for reflection", mMass, 0.0, mMass + 0.05); if (mBoundReflMean) { @@ -467,6 +534,7 @@ void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) RooRealVar sigmaRefl("sigmaRefl", "sigma for reflection", 0.012, 0, 0.25); RooAbsPdf* reflFuncGaus = new RooGaussian("reflFuncGaus", "reflection pdf", mass, meanRefl, sigmaRefl); workspace.import(*reflFuncGaus); + delete reflFuncGaus; // reflection double Gaussian RooRealVar meanReflDoubleGaus("meanReflDoubleGaus", "mean for reflection double gaussian", mMass, 0.0, mMass + 0.05); if (mBoundReflMean) { @@ -474,89 +542,167 @@ void HFInvMassFitter::fillWorkspace(RooWorkspace& workspace) meanReflDoubleGaus.setMin(mMassReflLowLimit); } RooRealVar sigmaReflDoubleGaus("sigmaReflDoubleGaus", "sigmaReflDoubleGaus", 0.012, 0.0, 0.25); - RooGaussian gausRefl1("gausRefl1", "gausRefl1", mass, meanRefl, sigmaRefl); - RooGaussian gausRefl2("gausRefl2", "gausRefl2", mass, meanReflDoubleGaus, sigmaReflDoubleGaus); - RooRealVar fracRefl("fracRefl", "frac of two gauss", 0.5, 0, 1.); + RooGaussian const gausRefl1("gausRefl1", "gausRefl1", mass, meanRefl, sigmaRefl); + RooGaussian const gausRefl2("gausRefl2", "gausRefl2", mass, meanReflDoubleGaus, sigmaReflDoubleGaus); + RooRealVar const fracRefl("fracRefl", "frac of two gauss", 0.5, 0, 1.); RooAbsPdf* reflFuncDoubleGaus = new RooAddPdf("reflFuncDoubleGaus", "reflection pdf", RooArgList(gausRefl1, gausRefl2), fracRefl); workspace.import(*reflFuncDoubleGaus); + delete reflFuncDoubleGaus; // reflection poly3 - RooRealVar PolyReflParam0("PolyReflParam0", "PolyReflParam0", 0.5, -1., 1.); - RooRealVar PolyReflParam1("PolyReflParam1", "PolyReflParam1", 0.2, -1., 1.); - RooRealVar PolyReflParam2("PolyReflParam2", "PolyReflParam2", 0.2, -1., 1.); - RooRealVar PolyReflParam3("PolyReflParam3", "PolyReflParam3", 0.2, -1., 1.); - RooAbsPdf* reflFuncPoly3 = new RooPolynomial("reflFuncPoly3", "reflection PDF", mass, RooArgSet(PolyReflParam0, PolyReflParam1, PolyReflParam2, PolyReflParam3)); + RooRealVar const polyReflParam0("polyReflParam0", "polyReflParam0", 0.5, -1., 1.); + RooRealVar const polyReflParam1("polyReflParam1", "polyReflParam1", 0.2, -1., 1.); + RooRealVar const polyReflParam2("polyReflParam2", "polyReflParam2", 0.2, -1., 1.); + RooRealVar const polyReflParam3("polyReflParam3", "polyReflParam3", 0.2, -1., 1.); + RooAbsPdf* reflFuncPoly3 = new RooPolynomial("reflFuncPoly3", "reflection PDF", mass, RooArgSet(polyReflParam0, polyReflParam1, polyReflParam2, polyReflParam3)); workspace.import(*reflFuncPoly3); + delete reflFuncPoly3; // reflection poly6 - RooRealVar PolyReflParam4("PolyReflParam4", "PolyReflParam4", 0.2, -1., 1.); - RooRealVar PolyReflParam5("PolyReflParam5", "PolyReflParam5", 0.2, -1., 1.); - RooRealVar PolyReflParam6("PolyReflParam6", "PolyReflParam6", 0.2, -1., 1.); - RooAbsPdf* reflFuncPoly6 = new RooPolynomial("reflFuncPoly6", "reflection pdf", mass, RooArgSet(PolyReflParam0, PolyReflParam1, PolyReflParam2, PolyReflParam3, PolyReflParam4, PolyReflParam5, PolyReflParam6)); + RooRealVar const polyReflParam4("polyReflParam4", "polyReflParam4", 0.2, -1., 1.); + RooRealVar const polyReflParam5("polyReflParam5", "polyReflParam5", 0.2, -1., 1.); + RooRealVar const polyReflParam6("polyReflParam6", "polyReflParam6", 0.2, -1., 1.); + RooAbsPdf* reflFuncPoly6 = new RooPolynomial("reflFuncPoly6", "reflection pdf", mass, RooArgSet(polyReflParam0, polyReflParam1, polyReflParam2, polyReflParam3, polyReflParam4, polyReflParam5, polyReflParam6)); workspace.import(*reflFuncPoly6); + delete reflFuncPoly6; } + // draw fit output -void HFInvMassFitter::drawFit(TVirtualPad* pad, Int_t writeFitInfo) +void HFInvMassFitter::drawFit(TVirtualPad* pad, const std::vector& plotLabels, Bool_t writeParInfo) { gStyle->SetOptStat(0); gStyle->SetCanvasColor(0); gStyle->SetFrameFillColor(0); pad->cd(); - if (writeFitInfo > 0) { - TPaveText* textInfoLeft = new TPaveText(0.12, 0.65, 0.47, 0.89, "NDC"); - TPaveText* textInfoRight = new TPaveText(0.6, 0.7, 1., .87, "NDC"); - textInfoLeft->SetBorderSize(0); - textInfoLeft->SetFillStyle(0); - textInfoRight->SetBorderSize(0); - textInfoRight->SetFillStyle(0); - textInfoRight->SetTextColor(kBlue); - textInfoLeft->AddText(Form("S = %.0f #pm %.0f ", mRawYield, mRawYieldErr)); - if (mTypeOfBkgPdf != 6) { - textInfoLeft->AddText(Form("B (%d#sigma) = %.0f #pm %.0f", mNSigmaForSidebands, mBkgYield, mBkgYieldErr)); - textInfoLeft->AddText(Form("S/B (%d#sigma) = %.4g ", mNSigmaForSidebands, mRawYield / mBkgYield)); - } - if (mReflPdf) { - textInfoLeft->AddText(Form("Refl/Sig = %.3f #pm %.3f ", mReflOverSgn, 0.0)); - } - if (mTypeOfBkgPdf != 6) { - textInfoLeft->AddText(Form("Signif (%d#sigma) = %.1f #pm %.1f ", mNSigmaForSidebands, mSignificance, mSignificanceErr)); - textInfoLeft->AddText(Form("#chi^{2} / ndf = %.3f", mChiSquareOverNdf)); - } + // Fit metrics + auto* textFitMetrics = new TPaveText(0.65, 0.7, 0.9, 0.88, "NDC"); + textFitMetrics->SetBorderSize(0); + textFitMetrics->SetFillStyle(0); + textFitMetrics->SetTextSize(0.04); + textFitMetrics->SetTextAlign(33); + textFitMetrics->AddText(Form("S = %.0f #pm %.0f ", mRawYield, mRawYieldErr)); + textFitMetrics->AddText(Form("S_{count} = %.0f #pm %.0f ", mRawYieldCounted, mRawYieldCountedErr)); + if (mTypeOfBkgPdf != NoBkg) { + textFitMetrics->AddText(Form("B (%d#sigma) = %.0f #pm %.0f", mNSigmaForSidebands, mBkgYield, mBkgYieldErr)); + textFitMetrics->AddText(Form("S/B (%d#sigma) = %.4g ", mNSigmaForSidebands, mRawYield / mBkgYield)); + textFitMetrics->AddText(Form("Significance (%d#sigma) = %.1f #pm %.1f ", mNSigmaForSidebands, mSignificance, mSignificanceErr)); + textFitMetrics->AddText(Form("#chi^{2} / ndf = %.3f", mChiSquareOverNdfTotal)); + } + if (mReflPdf != nullptr) { + textFitMetrics->AddText(Form("Refl/Sig = %.3f #pm %.3f ", mReflOverSgn, 0.0)); + } + mInvMassFrame->addObject(textFitMetrics); + // Analysis information + auto* textAnalysisInfo = new TPaveText(0.18, 0.78, 0.35, 0.88, "NDC"); + textAnalysisInfo->SetBorderSize(0); + textAnalysisInfo->SetFillStyle(0); + textAnalysisInfo->SetTextSize(0.05); + textAnalysisInfo->SetTextAlign(13); + for (const auto& label : plotLabels) { + textAnalysisInfo->AddText(label.c_str()); + } + mInvMassFrame->addObject(textAnalysisInfo); + if (writeParInfo) { + // right text box + auto* textSignalPar = new TPaveText(0.18, 0.65, 0.4, 0.75, "NDC"); + textSignalPar->SetBorderSize(0); + textSignalPar->SetFillStyle(0); + textSignalPar->SetTextColor(kBlue); + textSignalPar->SetTextAlign(13); if (mFixedMean) { - textInfoRight->AddText(Form("mean(fixed) = %.3f #pm %.3f", mRooMeanSgn->getVal(), mRooMeanSgn->getError())); + textSignalPar->AddText(Form("mean(fixed) = %.3f #pm %.3f", mRooMeanSgn->getVal(), mRooMeanSgn->getError())); } else { - textInfoRight->AddText(Form("mean(free) = %.3f #pm %.3f", mRooMeanSgn->getVal(), mRooMeanSgn->getError())); + textSignalPar->AddText(Form("mean(free) = %.3f #pm %.3f", mRooMeanSgn->getVal(), mRooMeanSgn->getError())); } - if (mFixedSigma) { - textInfoRight->AddText(Form("sigma(fixed) = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); + if (mTypeOfSgnPdf == DoubleGaus) { + if (mFixedSigma) { + textSignalPar->AddText(Form("sigma(fixed) = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); + } else { + textSignalPar->AddText(Form("sigma(free) = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); + } + if (mFixedSigmaDoubleGaus) { + textSignalPar->AddText(Form("sigma 2(fixed) = %.3f #pm %.3f", mRooSecSigmaSgn->getVal(), mRooSecSigmaSgn->getError())); + } else { + textSignalPar->AddText(Form("sigma 2(free) = %.3f #pm %.3f", mRooSecSigmaSgn->getVal(), mRooSecSigmaSgn->getError())); + } + } else if (mFixedSigma) { + textSignalPar->AddText(Form("sigma(fixed) = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); } else { - textInfoRight->AddText(Form("sigma(free) = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); - } - mInvMassFrame->addObject(textInfoLeft); - mInvMassFrame->addObject(textInfoRight); - mInvMassFrame->GetYaxis()->SetTitleOffset(1.8); - gPad->SetLeftMargin(0.15); - mInvMassFrame->GetYaxis()->SetTitle(Form("%s", mHistoInvMass->GetYaxis()->GetTitle())); - mInvMassFrame->GetXaxis()->SetTitle(Form("%s", mHistoInvMass->GetXaxis()->GetTitle())); - mInvMassFrame->Draw(); - if (mHistoTemplateRefl) { - mReflFrame->Draw("same"); + textSignalPar->AddText(Form("sigma(free) = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); } + mInvMassFrame->addObject(textSignalPar); + } + mInvMassFrame->GetXaxis()->SetTitleOffset(1.2); + mInvMassFrame->GetYaxis()->SetTitleOffset(1.8); + gPad->SetLeftMargin(0.15); + mInvMassFrame->GetYaxis()->SetTitle(Form("%s", mHistoInvMass->GetYaxis()->GetTitle())); + mInvMassFrame->GetXaxis()->SetTitle(Form("%s", mHistoInvMass->GetXaxis()->GetTitle())); + mInvMassFrame->Draw(); + highlightPeakRegion(mInvMassFrame); + if (mHistoTemplateRefl) { + mReflFrame->Draw("same"); } } -// draw redisual distribution on canvas +// draw residual distribution on canvas void HFInvMassFitter::drawResidual(TVirtualPad* pad) { pad->cd(); mResidualFrame->GetYaxis()->SetTitle(""); - TPaveText* textInfo = new TPaveText(0.12, 0.65, 0.47, .89, "NDC"); + auto* textInfo = new TPaveText(0.12, 0.65, 0.47, .89, "NDC"); textInfo->SetBorderSize(0); textInfo->SetFillStyle(0); textInfo->SetTextColor(kBlue); textInfo->AddText(Form("S = %.0f #pm %.0f ", mRawYield, mRawYieldErr)); + textInfo->AddText(Form("S_{count} = %.0f #pm %.0f ", mRawYieldCounted, mRawYieldCountedErr)); textInfo->AddText(Form("mean = %.3f #pm %.3f", mRooMeanSgn->getVal(), mRooMeanSgn->getError())); - textInfo->AddText(Form("sigma = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); + if (mTypeOfSgnPdf == DoubleGaus) { + textInfo->AddText(Form("sigma = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); + textInfo->AddText(Form("sigma 2 = %.3f #pm %.3f", mRooSecSigmaSgn->getVal(), mRooSecSigmaSgn->getError())); + } else { + textInfo->AddText(Form("sigma = %.3f #pm %.3f", mRooSigmaSgn->getVal(), mRooSigmaSgn->getError())); + } mResidualFrame->addObject(textInfo); mResidualFrame->Draw(); + highlightPeakRegion(mResidualFrame); +} + +// draw ratio on canvas +void HFInvMassFitter::drawRatio(TVirtualPad* pad) +{ + pad->cd(); + mRatioFrame->GetXaxis()->SetTitleOffset(1.2); + mRatioFrame->GetYaxis()->SetTitleOffset(1.5); + mRatioFrame->GetYaxis()->SetTitle("Fit / Data"); + double xMin = mRatioFrame->GetXaxis()->GetXmin(); + double xMax = mRatioFrame->GetXaxis()->GetXmax(); + auto* line = new TLine(xMin, 1.0, xMax, 1.0); + line->SetLineColor(kGray); + line->SetLineStyle(2); + line->SetLineWidth(2); + mRatioFrame->addObject(line); + mRatioFrame->Draw(); + highlightPeakRegion(mRatioFrame); +} + +// draw peak region with vertical lines +void HFInvMassFitter::highlightPeakRegion(const RooPlot* plot, Color_t color, Width_t width, Style_t style) const +{ + if (!mHighlightPeakRegion) { + return; + } + double const yMin = plot->GetMinimum(); + double const yMax = plot->GetMaximum(); + const Double_t mean = mRooMeanSgn->getVal(); + const Double_t sigma = mRooSecSigmaSgn->getVal(); + const Double_t minForSgn = mean - mNSigmaForSidebands * sigma; + const Double_t maxForSgn = mean + mNSigmaForSidebands * sigma; + auto* leftLine = new TLine(minForSgn, yMin, minForSgn, yMax); + auto* rightLine = new TLine(maxForSgn, yMin, maxForSgn, yMax); + for (const auto& line : std::array{leftLine, rightLine}) { + line->SetLineColor(color); + line->SetLineWidth(width); + line->SetLineStyle(style); + line->Draw(); + } } // draw reflection distribution on canvas @@ -567,6 +713,34 @@ void HFInvMassFitter::drawReflection(TVirtualPad* pad) mReflOnlyFrame->Draw(); } +// calculate signal yield via bin counting +void HFInvMassFitter::countSignal(Double_t& signal, Double_t& signalErr) const +{ + const Double_t mean = mRooMeanSgn->getVal(); + const Double_t sigma = mRooSecSigmaSgn->getVal(); + const Double_t minForSgn = mean - mNSigmaForSidebands * sigma; + const Double_t maxForSgn = mean + mNSigmaForSidebands * sigma; + const Int_t binForMinSgn = mHistoInvMass->FindBin(minForSgn); + const Int_t binForMaxSgn = mHistoInvMass->FindBin(maxForSgn); + const Double_t binForMinSgnUpperEdge = mHistoInvMass->GetBinLowEdge(binForMinSgn + 1); + const Double_t binForMaxSgnLowerEdge = mHistoInvMass->GetBinLowEdge(binForMaxSgn); + const Double_t binForMinSgnFraction = (binForMinSgnUpperEdge - minForSgn) / mHistoInvMass->GetBinWidth(binForMinSgn); + const Double_t binForMaxSgnFraction = (maxForSgn - binForMaxSgnLowerEdge) / mHistoInvMass->GetBinWidth(binForMaxSgn); + + Double_t sum = 0; + sum += mHistoInvMass->GetBinContent(binForMinSgn) * binForMinSgnFraction; + for (Int_t iBin = binForMinSgn + 1; iBin <= binForMaxSgn - 1; iBin++) { + sum += mHistoInvMass->GetBinContent(iBin); + } + sum += mHistoInvMass->GetBinContent(binForMaxSgn) * binForMaxSgnFraction; + + Double_t bkg, errBkg; + calculateBackground(bkg, errBkg); + + signal = sum - bkg; + signalErr = std::sqrt(sum + errBkg * errBkg); // sum error squared is equal to sum +} + // calculate signal yield void HFInvMassFitter::calculateSignal(Double_t& signal, Double_t& errSignal) const { @@ -588,20 +762,20 @@ void HFInvMassFitter::calculateSignificance(Double_t& significance, Double_t& er calculateSignal(signal, errSignal); Double_t bkg, errBkg; calculateBackground(bkg, errBkg); - 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)); + Double_t const sgnErrSquare = errSignal * errSignal; + Double_t const bkgErrSquare = errBkg * errBkg; + Double_t const totalSgnBkg = signal + bkg; + significance = signal / std::sqrt(signal + bkg); + errSignificance = significance * std::sqrt((sgnErrSquare + bkgErrSquare) / (mNSigmaForSidebands * totalSgnBkg * totalSgnBkg) + (bkg / totalSgnBkg) * (sgnErrSquare / signal / signal)); } -// estimate Signnal +// estimate Signal void HFInvMassFitter::checkForSignal(Double_t& estimatedSignal) { - Double_t minForSgn = mMass - 4 * mSigmaSgn; - Double_t maxForSgn = mMass + 4 * mSigmaSgn; - Int_t binForMinSgn = mHistoInvMass->FindBin(minForSgn); - Int_t binForMaxSgn = mHistoInvMass->FindBin(maxForSgn); + Double_t const minForSgn = mMass - 4 * mSigmaSgn; + Double_t const maxForSgn = mMass + 4 * mSigmaSgn; + Int_t const binForMinSgn = mHistoInvMass->FindBin(minForSgn); + Int_t const binForMaxSgn = mHistoInvMass->FindBin(maxForSgn); Double_t sum = 0; for (Int_t i = binForMinSgn; i <= binForMaxSgn; i++) { @@ -613,61 +787,49 @@ void HFInvMassFitter::checkForSignal(Double_t& estimatedSignal) } // Create Background Fit Function -RooAbsPdf* HFInvMassFitter::createBackgroundFitFunction(RooWorkspace* workspace) +RooAbsPdf* HFInvMassFitter::createBackgroundFitFunction(RooWorkspace* workspace) const { - RooAbsPdf* bkgPdf; - switch (mTypeOfBkgPdf) { - case 0: // exponential - { - bkgPdf = workspace->pdf("bkgFuncExpo"); - } break; - case 1: // poly1 - { - bkgPdf = workspace->pdf("bkgFuncPoly1"); - } break; - case 2: { - bkgPdf = workspace->pdf("bkgFuncPoly2"); - } break; - case 3: { - bkgPdf = workspace->pdf("bkgFuncPow"); - } break; - case 4: { - bkgPdf = workspace->pdf("bkgFuncPowExpo"); - } break; - case 5: { - bkgPdf = workspace->pdf("bkgFuncPoly3"); - } break; - case 6: // MC - break; - default: - break; + RooAbsPdf* bkgPdf{nullptr}; + if (mTypeOfBkgPdf == NoBkg) { + return bkgPdf; } + if (mTypeOfBkgPdf < 0 || mTypeOfBkgPdf >= NTypesOfBkgPdf) { + throw std::runtime_error("createBackgroundFitFunction(): mTypeOfBkgPdf must be within [0; " + std::to_string(NTypesOfBkgPdf) + ") range"); + } + bkgPdf = workspace->pdf(namesOfBkgPdf.at(mTypeOfBkgPdf)); + return bkgPdf; } // Create Signal Fit Function RooAbsPdf* HFInvMassFitter::createSignalFitFunction(RooWorkspace* workspace) { - RooAbsPdf* sgnPdf; + RooAbsPdf* sgnPdf{nullptr}; switch (mTypeOfSgnPdf) { case 0: { sgnPdf = workspace->pdf("sgnFuncGaus"); mRooSigmaSgn = workspace->var("sigma"); + mRooSecSigmaSgn = workspace->var("sigma"); mRooMeanSgn = workspace->var("mean"); } break; case 1: { sgnPdf = workspace->pdf("sgnFuncDoubleGaus"); - mRooSigmaSgn = workspace->var("sigmaDoubleGaus"); + mRooSigmaSgn = workspace->var("sigma"); + mRooSecSigmaSgn = workspace->var("sigmaDoubleGaus"); mRooMeanSgn = workspace->var("mean"); + mRooFracDoubleGaus = workspace->var("fracDoubleGaus"); } break; case 2: { sgnPdf = workspace->pdf("sgnFuncGausRatio"); - mRooSigmaSgn = workspace->var("sigmaDoubleGausRatio"); + mRooSigmaSgn = workspace->var("sigma"); + mRooSecSigmaSgn = workspace->var("sigmaDoubleGausRatio"); mRooMeanSgn = workspace->var("mean"); + mRooFracDoubleGaus = workspace->var("fracDoubleGausRatio"); } break; case 3: { sgnPdf = workspace->pdf("sgnFuncDoublePeak"); - mRooSigmaSgn = workspace->var("sigmaSec"); + mRooSigmaSgn = workspace->var("sigma"); + mRooSecSigmaSgn = workspace->var("sigmaSec"); mRooMeanSgn = workspace->var("meanSec"); } break; default: @@ -677,76 +839,69 @@ RooAbsPdf* HFInvMassFitter::createSignalFitFunction(RooWorkspace* workspace) } // Create Reflection Fit Function -RooAbsPdf* HFInvMassFitter::createReflectionFitFunction(RooWorkspace* workspace) +RooAbsPdf* HFInvMassFitter::createReflectionFitFunction(RooWorkspace* workspace) const { - RooAbsPdf* reflPdf; - switch (mTypeOfReflPdf) { - case 0: { - reflPdf = workspace->pdf("reflFuncGaus"); - } break; - case 1: { - reflPdf = workspace->pdf("reflFuncDoubleGaus"); - } break; - case 2: { - reflPdf = workspace->pdf("reflFuncPoly3"); - } break; - case 3: { - reflPdf = workspace->pdf("reflFuncPoly6"); - } break; - default: - break; + if (mTypeOfReflPdf < 0 || mTypeOfReflPdf >= NTypesOfReflPdf) { + throw std::runtime_error("createReflectionFitFunction(): mTypeOfReflPdf must be within [0; " + std::to_string(NTypesOfReflPdf) + ") range"); } + RooAbsPdf* reflPdf = workspace->pdf(namesOfReflPdf.at(mTypeOfReflPdf)); + return reflPdf; } // Plot Bkg components of fTotFunction -void HFInvMassFitter::plotBkg(RooAbsPdf* pdf) +void HFInvMassFitter::plotBkg(RooAbsPdf* pdf, Color_t color) { - switch (mTypeOfBkgPdf) { - case 0: - pdf->plotOn(mInvMassFrame, Components("bkgFuncExpo"), Name("Bkg_c"), LineColor(kRed)); - break; - case 1: - pdf->plotOn(mInvMassFrame, Components("bkgFuncPoly1"), Name("Bkg_c"), LineColor(kRed)); - break; - case 2: - pdf->plotOn(mInvMassFrame, Components("bkgFuncPoly2"), Name("Bkg_c"), LineColor(kRed)); - break; - case 3: - pdf->plotOn(mInvMassFrame, Components("bkgFuncPow"), Name("Bkg_c"), LineColor(kRed)); - break; - case 4: - pdf->plotOn(mInvMassFrame, Components("bkgFuncPowExp"), Name("Bkg_c"), LineColor(kRed)); - break; - case 5: - pdf->plotOn(mInvMassFrame, Components("bkgFuncPoly3"), Name("Bkg_c"), LineColor(kRed)); - break; - case 6: - break; - default: - break; + if (mTypeOfBkgPdf == NoBkg) { + return; + } + if (mTypeOfBkgPdf < 0 || mTypeOfBkgPdf >= NTypesOfBkgPdf) { + throw std::runtime_error("plotBkg(): mTypeOfBkgPdf must be within [0; " + std::to_string(NTypesOfBkgPdf) + ") range"); } + pdf->plotOn(mInvMassFrame, Components(namesOfBkgPdf.at(mTypeOfBkgPdf).c_str()), Name("Bkg_c"), LineColor(color)); } // Plot Refl distribution on canvas void HFInvMassFitter::plotRefl(RooAbsPdf* pdf) { - switch (mTypeOfReflPdf) { - case 0: - pdf->plotOn(mInvMassFrame, Components("reflFuncGaus"), Name("Refl_c"), LineColor(kGreen)); - break; - case 1: - pdf->plotOn(mInvMassFrame, Components("reflFuncDoubleGaus"), Name("Refl_c"), LineColor(kGreen)); - break; - case 2: - pdf->plotOn(mInvMassFrame, Components("reflFuncPoly3"), Name("Refl_c"), LineColor(kGreen)); - break; - case 3: - pdf->plotOn(mInvMassFrame, Components("reflFuncPoly6"), Name("Refl_c"), LineColor(kGreen)); - break; - default: - break; + if (mTypeOfReflPdf < 0 || mTypeOfReflPdf >= NTypesOfReflPdf) { + throw std::runtime_error("plotRefl(): mTypeOfReflPdf must be within [0; " + std::to_string(NTypesOfReflPdf) + ") range"); + } + pdf->plotOn(mInvMassFrame, Components(namesOfReflPdf.at(mTypeOfReflPdf).c_str()), Name("Refl_c"), LineColor(kGreen)); +} + +// Calculate fit to data ratio +void HFInvMassFitter::calculateFitToDataRatio() const +{ + if (!mInvMassFrame) + return; + + // Get the data and fit curves from the frame + auto* dataHist = dynamic_cast(mInvMassFrame->findObject("data_c")); + auto* fitCurve = dynamic_cast(mInvMassFrame->findObject("Tot_c")); // or the relevant fit curve + + if (!dataHist || !fitCurve) + return; + + RooHist* ratioHist = new RooHist(); + + for (int i = 0; i < dataHist->GetN(); ++i) { + double x, dataY, dataErr; + dataHist->GetPoint(i, x, dataY); + dataErr = dataHist->GetErrorY(i); + + double fitY = fitCurve->Eval(x); + + double ratio = dataY != 0 ? fitY / dataY : 0; + double err = dataY != 0 ? ratio * dataErr / dataY : 0; + + ratioHist->SetPoint(i, x, ratio); + ratioHist->SetPointError(i, 0, 0, err, err); } + + mRatioFrame->addPlotable(ratioHist, "P"); + mRatioFrame->SetMinimum(0.5); + mRatioFrame->SetMaximum(1.5); } // Fix reflection pdf @@ -774,30 +929,30 @@ void HFInvMassFitter::setReflFuncFixed() fracRefl->setConstant(kTRUE); } break; case 2: { - RooRealVar* PolyReflParam0 = mWorkspace->var("PolyReflParam0"); - RooRealVar* PolyReflParam1 = mWorkspace->var("PolyReflParam1"); - RooRealVar* PolyReflParam2 = mWorkspace->var("PolyReflParam2"); - RooRealVar* PolyReflParam3 = mWorkspace->var("PolyReflParam3"); - PolyReflParam0->setConstant(kTRUE); - PolyReflParam1->setConstant(kTRUE); - PolyReflParam2->setConstant(kTRUE); - PolyReflParam3->setConstant(kTRUE); + RooRealVar* polyReflParam0 = mWorkspace->var("polyReflParam0"); + RooRealVar* polyReflParam1 = mWorkspace->var("polyReflParam1"); + RooRealVar* polyReflParam2 = mWorkspace->var("polyReflParam2"); + RooRealVar* polyReflParam3 = mWorkspace->var("polyReflParam3"); + polyReflParam0->setConstant(kTRUE); + polyReflParam1->setConstant(kTRUE); + polyReflParam2->setConstant(kTRUE); + polyReflParam3->setConstant(kTRUE); } break; case 3: { - RooRealVar* PolyReflParam0 = mWorkspace->var("PolyReflParam0"); - RooRealVar* PolyReflParam1 = mWorkspace->var("PolyReflParam1"); - RooRealVar* PolyReflParam2 = mWorkspace->var("PolyReflParam2"); - RooRealVar* PolyReflParam3 = mWorkspace->var("PolyReflParam3"); - RooRealVar* PolyReflParam4 = mWorkspace->var("PolyReflParam4"); - RooRealVar* PolyReflParam5 = mWorkspace->var("PolyReflParam5"); - RooRealVar* PolyReflParam6 = mWorkspace->var("PolyReflParam6"); - PolyReflParam0->setConstant(kTRUE); - PolyReflParam1->setConstant(kTRUE); - PolyReflParam2->setConstant(kTRUE); - PolyReflParam3->setConstant(kTRUE); - PolyReflParam4->setConstant(kTRUE); - PolyReflParam5->setConstant(kTRUE); - PolyReflParam6->setConstant(kTRUE); + RooRealVar* polyReflParam0 = mWorkspace->var("polyReflParam0"); + RooRealVar* polyReflParam1 = mWorkspace->var("polyReflParam1"); + RooRealVar* polyReflParam2 = mWorkspace->var("polyReflParam2"); + RooRealVar* polyReflParam3 = mWorkspace->var("polyReflParam3"); + RooRealVar* polyReflParam4 = mWorkspace->var("polyReflParam4"); + RooRealVar* polyReflParam5 = mWorkspace->var("polyReflParam5"); + RooRealVar* polyReflParam6 = mWorkspace->var("polyReflParam6"); + polyReflParam0->setConstant(kTRUE); + polyReflParam1->setConstant(kTRUE); + polyReflParam2->setConstant(kTRUE); + polyReflParam3->setConstant(kTRUE); + polyReflParam4->setConstant(kTRUE); + polyReflParam5->setConstant(kTRUE); + polyReflParam6->setConstant(kTRUE); } break; default: break; diff --git a/PWGHF/D2H/Macros/HFInvMassFitter.h b/PWGHF/D2H/Macros/HFInvMassFitter.h index 6ac9357c5c2..daa00ec0b09 100644 --- a/PWGHF/D2H/Macros/HFInvMassFitter.h +++ b/PWGHF/D2H/Macros/HFInvMassFitter.h @@ -16,29 +16,26 @@ /// \author Mingyu Zhang /// \author Xinye Peng /// \author Biao Zhang +/// \author Oleksii Lubynets +/// \author Phil Stahlhut #ifndef PWGHF_D2H_MACROS_HFINVMASSFITTER_H_ #define PWGHF_D2H_MACROS_HFINVMASSFITTER_H_ -#include // std::string - +#include +#include #include -#include -#include -#include #include -#include #include -#include #include -#include -#include -#include +#include -using namespace RooFit; +#include +#include -class TF1; -class TH1F; +#include +#include +#include class HFInvMassFitter : public TNamed { @@ -50,37 +47,42 @@ class HFInvMassFitter : public TNamed Pow = 3, PowExpo = 4, Poly3 = 5, - NoBkg = 6 + NoBkg = 6, + NTypesOfBkgPdf }; + std::vector namesOfBkgPdf{"bkgFuncExpo", "bkgFuncPoly1", "bkgFuncPoly2", "bkgFuncPow", "bkgFuncPowExpo", "bkgFuncPoly3"}; enum TypeOfSgnPdf { SingleGaus = 0, DoubleGaus = 1, DoubleGausSigmaRatioPar = 2, - GausSec = 3 + GausSec = 3, + NTypesOfSgnPdf }; enum TypeOfReflPdf { SingleGausRefl = 0, DoubleGausRefl = 1, Poly3Refl = 2, - Poly6Refl = 3 + Poly6Refl = 3, + NTypesOfReflPdf }; + std::vector namesOfReflPdf{"reflFuncGaus", "reflFuncDoubleGaus", "reflFuncPoly3", "reflFuncPoly6"}; HFInvMassFitter(); - HFInvMassFitter(const TH1F* histoToFit, Double_t minValue, Double_t maxValue, Int_t fitTypeBkg = Expo, Int_t fitTypeSgn = SingleGaus); - ~HFInvMassFitter(); - void setHistogramForFit(const TH1F* histoToFit) + HFInvMassFitter(const TH1* histoToFit, Double_t minValue, Double_t maxValue, Int_t fitTypeBkg = Expo, Int_t fitTypeSgn = SingleGaus); + ~HFInvMassFitter() override; + void setHistogramForFit(const TH1* histoToFit) { - if (mHistoInvMass) { - delete mHistoInvMass; - } - mHistoInvMass = reinterpret_cast(histoToFit->Clone("mHistoInvMass")); - mHistoInvMass->SetDirectory(0); + + delete mHistoInvMass; + + mHistoInvMass = dynamic_cast(histoToFit->Clone("mHistoInvMass")); + mHistoInvMass->SetDirectory(nullptr); } void setUseLikelihoodFit() { mFitOption = "L,E"; } void setUseChi2Fit() { mFitOption = "Chi2"; } void setFitOption(TString opt) { mFitOption = opt.Data(); } - RooAbsPdf* createBackgroundFitFunction(RooWorkspace* w1); + RooAbsPdf* createBackgroundFitFunction(RooWorkspace* w1) const; RooAbsPdf* createSignalFitFunction(RooWorkspace* w1); - RooAbsPdf* createReflectionFitFunction(RooWorkspace* w1); + RooAbsPdf* createReflectionFitFunction(RooWorkspace* w1) const; void setFitRange(Double_t minValue, Double_t maxValue) { @@ -98,7 +100,7 @@ class HFInvMassFitter : public TNamed mParamSgn = sigmaLimit; } void setParticlePdgMass(Double_t mass) { mMassParticle = mass; } - Double_t getParticlePdgMass() { return mMassParticle; } + [[nodiscard]] Double_t getParticlePdgMass() const { return mMassParticle; } void setInitialGaussianMean(Double_t mean) { mMass = mean; @@ -121,7 +123,7 @@ class HFInvMassFitter : public TNamed { if (mean < meanLowLimit || mean > meanUpLimit) { - cout << "Invalid Gaussian mean limmit!" << endl; + printf("Invalid Gaussian mean limit!\n"); } setInitialGaussianMean(mean); mMassLowLimit = meanLowLimit; @@ -132,7 +134,7 @@ class HFInvMassFitter : public TNamed { if (mean < meanLowLimit || mean > meanUpLimit) { - cout << "Invalid Gaussian mean limmit for reflection!" << endl; + printf("Invalid Gaussian mean limit for reflection!\n"); } setInitialGaussianMean(mean); mMassReflLowLimit = meanLowLimit; @@ -153,7 +155,7 @@ class HFInvMassFitter : public TNamed void setFixSecondGaussianSigma(Double_t sigma) { if (mTypeOfSgnPdf != DoubleGaus) { - cout << "Fit type should be 2Gaus!" << endl; + printf("Fit type should be 2Gaus!\n"); } setInitialSecondGaussianSigma(sigma); mFixedSigmaDoubleGaus = kTRUE; @@ -162,7 +164,7 @@ class HFInvMassFitter : public TNamed { if (mTypeOfSgnPdf != DoubleGaus && mTypeOfSgnPdf != DoubleGausSigmaRatioPar) { - cout << "Fit type should be 2Gaus or 2GausSigmaRatio!" << endl; + printf("Fit type should be 2Gaus or 2GausSigmaRatio!\n"); } setInitialFracDoubleGaus(frac); mFixedFracDoubleGaus = kTRUE; @@ -170,63 +172,77 @@ class HFInvMassFitter : public TNamed void setFixRatioToGausSigma(Double_t sigmaFrac) { if (mTypeOfSgnPdf != DoubleGausSigmaRatioPar) { - cout << "Fit type should be set to k2GausSigmaRatioPar!" << endl; + printf("Fit type should be set to k2GausSigmaRatioPar!\n"); } setInitialRatioDoubleGausSigma(sigmaFrac); mFixedRatioDoubleGausSigma = kTRUE; } void setFixSignalYield(Double_t yield) { mFixedRawYield = yield; } void setNumberOfSigmaForSidebands(Double_t numberOfSigma) { mNSigmaForSidebands = numberOfSigma; } - void plotBkg(RooAbsPdf* mFunc); + void plotBkg(RooAbsPdf* mFunc, Color_t color = kRed); void plotRefl(RooAbsPdf* mFunc); void setReflFuncFixed(); - void doFit(Bool_t draw = kTRUE); + void doFit(); void setInitialReflOverSgn(Double_t reflOverSgn) { mReflOverSgn = reflOverSgn; } void setFixReflOverSgn(Double_t reflOverSgn) { setInitialReflOverSgn(reflOverSgn); mFixReflOverSgn = kTRUE; } - void setTemplateReflections(const TH1* histoRefl, Int_t fitTypeRefl = DoubleGaus) + void setTemplateReflections(const TH1* histoRefl) { - if (!histoRefl) { + if (histoRefl == nullptr) { mEnableReflections = kFALSE; + return; } - mHistoTemplateRefl = reinterpret_cast(histoRefl->Clone("mHistoTemplateRefl")); + mHistoTemplateRefl = dynamic_cast(histoRefl->Clone("mHistoTemplateRefl")); } - Double_t getChiSquareOverNDF() const { return mChiSquareOverNdf; } - Double_t getRawYield() const { return mRawYield; } - Double_t getRawYieldError() const { return mRawYieldErr; } - Double_t getBkgYield() const { return mBkgYield; } - Double_t getBkgYieldError() const { return mBkgYieldErr; } - Double_t getSignificance() const { return mSignificance; } - Double_t getSignificanceError() const { return mSignificanceErr; } - Double_t getMean() const { return mRooMeanSgn->getVal(); } - Double_t getMeanUncertainty() const { return mRooMeanSgn->getError(); } - Double_t getSigma() const { return mRooSigmaSgn->getVal(); } - Double_t getSigmaUncertainty() const { return mRooSigmaSgn->getError(); } - Double_t getReflOverSig() const + void setDrawBgPrefit(Bool_t value = true) { mDrawBgPrefit = value; } + void setHighlightPeakRegion(Bool_t value = true) { mHighlightPeakRegion = value; } + [[nodiscard]] Double_t getChiSquareOverNDFTotal() const { return mChiSquareOverNdfTotal; } + [[nodiscard]] Double_t getChiSquareOverNDFBkg() const { return mChiSquareOverNdfBkg; } + [[nodiscard]] Double_t getRawYield() const { return mRawYield; } + [[nodiscard]] Double_t getRawYieldError() const { return mRawYieldErr; } + [[nodiscard]] Double_t getRawYieldCounted() const { return mRawYieldCounted; } + [[nodiscard]] Double_t getRawYieldCountedError() const { return mRawYieldCountedErr; } + [[nodiscard]] Double_t getBkgYield() const { return mBkgYield; } + [[nodiscard]] Double_t getBkgYieldError() const { return mBkgYieldErr; } + [[nodiscard]] Double_t getSignificance() const { return mSignificance; } + [[nodiscard]] Double_t getSignificanceError() const { return mSignificanceErr; } + [[nodiscard]] Double_t getMean() const { return mRooMeanSgn->getVal(); } + [[nodiscard]] Double_t getMeanUncertainty() const { return mRooMeanSgn->getError(); } + [[nodiscard]] Double_t getSigma() const { return mRooSigmaSgn->getVal(); } + [[nodiscard]] Double_t getSigmaUncertainty() const { return mRooSigmaSgn->getError(); } + [[nodiscard]] Double_t getSecSigma() const { return mRooSecSigmaSgn->getVal(); } + [[nodiscard]] Double_t getSecSigmaUncertainty() const { return mRooSecSigmaSgn->getError(); } + [[nodiscard]] Double_t getFracDoubleGaus() const { return mRooFracDoubleGaus->getVal(); } + [[nodiscard]] Double_t getFracDoubleGausUncertainty() const { return mRooFracDoubleGaus->getError(); } + [[nodiscard]] Double_t getReflOverSig() const + { - if (mReflPdf) { + if (mReflPdf != nullptr) { return mReflOverSgn; - } else { - return 0; } + return 0; } void calculateSignal(Double_t& signal, Double_t& signalErr) const; + void countSignal(Double_t& signal, Double_t& signalErr) const; void calculateBackground(Double_t& bkg, Double_t& bkgErr) const; void calculateSignificance(Double_t& significance, Double_t& significanceErr) const; void checkForSignal(Double_t& estimatedSignal); - void drawFit(TVirtualPad* c, Int_t writeFitInfo = 2); + void calculateFitToDataRatio() const; + void drawFit(TVirtualPad* c, const std::vector& plotLabels, Bool_t writeParInfo = true); void drawResidual(TVirtualPad* c); + void drawRatio(TVirtualPad* c); void drawReflection(TVirtualPad* c); private: HFInvMassFitter(const HFInvMassFitter& source); HFInvMassFitter& operator=(const HFInvMassFitter& source); - void fillWorkspace(RooWorkspace& w); + void fillWorkspace(RooWorkspace& w) const; + void highlightPeakRegion(const RooPlot* plot, Color_t color = kGray + 1, Width_t width = 1, Style_t style = 2) const; - TH1F* mHistoInvMass; // histogram to fit + TH1* mHistoInvMass; // histogram to fit TString mFitOption; Double_t mMinMass; // lower mass limit Double_t mMaxMass; // upper mass limit @@ -240,14 +256,13 @@ class HFInvMassFitter : public TNamed Double_t mMassReflLowLimit; /// lower limit of the allowed mass range for reflection Double_t mMassReflUpLimit; /// upper limit of the allowed mass range for reflection Double_t mSecMass; /// Second peak mean value - Double_t mMassErr; /// uncertainty on signal gaussian mean value Double_t mSigmaSgn; /// signal gaussian sigma Double_t mSecSigma; /// Second peak gaussian sigma Int_t mNSigmaForSidebands; /// number of sigmas to veto the signal peak Int_t mNSigmaForSgn; /// number of sigmas to veto the signal peak Double_t mSigmaSgnErr; /// uncertainty on signal gaussian sigma Double_t mSigmaSgnDoubleGaus; /// signal 2gaussian sigma - Double_t mFixedMean; /// switch for fix mean of gaussian + Bool_t mFixedMean; /// switch for fix mean of gaussian Bool_t mBoundMean; /// switch for bound mean of guassian Bool_t mBoundReflMean; /// switch for bound mean of guassian for reflection Bool_t mFixedSigma; /// fix sigma or not @@ -264,14 +279,19 @@ class HFInvMassFitter : public TNamed Bool_t mEnableReflections; /// flag use/not use reflections Double_t mRawYield; /// signal gaussian integral Double_t mRawYieldErr; /// err on signal gaussian integral + Double_t mRawYieldCounted; /// signal gaussian integral evaluated via bin counting + Double_t mRawYieldCountedErr; /// err on signal gaussian integral evaluated via bin counting Double_t mBkgYield; /// background Double_t mBkgYieldErr; /// err on background Double_t mSignificance; /// significance Double_t mSignificanceErr; /// err on significance - Double_t mChiSquareOverNdf; /// chi2/ndf + Double_t mChiSquareOverNdfTotal; /// chi2/ndf of the total fit + Double_t mChiSquareOverNdfBkg; /// chi2/ndf of the background (sidebands) pre-fit Bool_t mFixReflOverSgn; /// switch for fix refl/signal RooRealVar* mRooMeanSgn; /// mean for gaussian of signal RooRealVar* mRooSigmaSgn; /// sigma for gaussian of signal + RooRealVar* mRooSecSigmaSgn; /// second sigma for composite gaussian of signal + RooRealVar* mRooFracDoubleGaus; /// fraction of second gaussian for composite gaussian of signal RooAbsPdf* mSgnPdf; /// signal fit function RooAbsPdf* mBkgPdf; /// background fit function RooAbsPdf* mReflPdf; /// reflection fit function @@ -283,13 +303,15 @@ class HFInvMassFitter : public TNamed RooPlot* mReflFrame; /// reflection frame RooPlot* mReflOnlyFrame; /// reflection frame plot on reflection only RooPlot* mResidualFrame; /// residual frame - RooPlot* mResidualFrameForCalulation; - RooRealVar* mass; /// mass - RooWorkspace* mWorkspace; /// workspace - Double_t mIntegralHisto; /// integral of histogram to fit - Double_t mIntegralBkg; /// integral of background fit function - Double_t mIntegralSgn; /// integral of signal fit function - TH1F* mHistoTemplateRefl; /// reflection histogram + RooPlot* mRatioFrame; /// fit/data ratio frame + RooPlot* mResidualFrameForCalculation; + RooWorkspace* mWorkspace; /// workspace + Double_t mIntegralHisto; /// integral of histogram to fit + Double_t mIntegralBkg; /// integral of background fit function + Double_t mIntegralSgn; /// integral of signal fit function + TH1* mHistoTemplateRefl; /// reflection histogram + Bool_t mDrawBgPrefit; /// draw background after fitting the sidebands + Bool_t mHighlightPeakRegion; /// draw vertical lines showing the peak region (usually +- 3 sigma) ClassDef(HFInvMassFitter, 1); }; diff --git a/PWGHF/D2H/Macros/HFInvMassFitterLinkDef.h b/PWGHF/D2H/Macros/HFInvMassFitterLinkDef.h new file mode 100644 index 00000000000..cc755de478f --- /dev/null +++ b/PWGHF/D2H/Macros/HFInvMassFitterLinkDef.h @@ -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. + +/// \file HFInvMassFitterLinkDef.h +/// \brief HFInvMassFitter dictionary definition file +/// +/// \author Zhen Zhang +/// \author Mingyu Zhang +/// \author Xinye Peng +/// \author Biao Zhang +/// \author Oleksii Lubynets + +#ifndef PWGHF_D2H_MACROS_HFINVMASSFITTERLINKDEF_H_ +#define PWGHF_D2H_MACROS_HFINVMASSFITTERLINKDEF_H_ + +#ifdef __CINT__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ class HFInvMassFitter + ; +#endif + +#endif // PWGHF_D2H_MACROS_HFINVMASSFITTERLINKDEF_H_ diff --git a/PWGHF/D2H/Macros/README.md b/PWGHF/D2H/Macros/README.md new file mode 100644 index 00000000000..f65de110419 --- /dev/null +++ b/PWGHF/D2H/Macros/README.md @@ -0,0 +1,59 @@ +# Invariant-mass fitter +Invariant-mass fitter is implemented in the class `HFInvMassFitter` (`HFInvMassFitter.cxx/h` files), and its run is executed via `runMassFitter.C` macro. +Fitter is configured in `config_massfitter.json`.\ +The fitter is **not** a part of O2Physics source code. + +## Dependencies +1. ROOT +2. RapidJSON. Download the header-only (no compilation needed) RapidJSON library, see the link . + +If you have O2Physics compilation you do not need to fulfill these dependencies explicitly. + +## How to run +### As a ROOT macro +The `runMassFitter.C` can be compiled as ROOT macro. +```bash +cd path-to-o2physics-src/PWGHF/D2H/Macros +source path-to-root-install/bin/thisroot.sh +export ROOT_INCLUDE_PATH=$ROOT_INCLUDE_PATH:path-to-json-include +root -l -x -b -q "HFInvMassFitter.cxx" "runMassFitter.C(\"config_massfitter.json\")" +``` +If you have O2Physics compilation and enter into its environment there is no need to set environment variables (skip lines 2-3 above). + +### As a CMake project +It is also possible to compile the fitter as a CMake project or insert it into existing one if any. +Use the `CMakeLists_HFInvMassFitter.txt` (rename it into `CMakeLists.txt` before usage).\ +Compile the fitter with the following steps: +```bash +cd path-to-o2physics-src/PWGHF/D2H/Macros +mkdir build +cd build +source path-to-root-install/bin/thisroot.sh +cmake -DHFFITTER_RAPIDJSON_INCLUDE_DIRS=path-to-json-include ../ +make +``` +and run the fitter: +```bash +./runMassFitter ../config_massfitter.json +``` +### Directly from the terminal +Compile the fitter with the following steps: +```bash +cd path-to-o2physics-src/PWGHF/D2H/Macros +mkdir build +cd build +source path-to-root-install/bin/thisroot.sh + +# Generate ROOT dictionary: +rootcling -f G__HFInvMassFitter.cxx -c ../HFInvMassFitter.h ../HFInvMassFitterLinkDef.h + +# Compile source code: +g++ -fPIC -I$(root-config --incdir) -I path-to-json-include -c ../HFInvMassFitter.cxx ../runMassFitter.C G__HFInvMassFitter.cxx + +# Link the executable: +g++ -o runMassFitter HFInvMassFitter.o runMassFitter.o G__HFInvMassFitter.o $(root-config --libs) -lRooFit -lRooFitCore -lEG +``` +and run the fitter: +```bash +./runMassFitter ../config_massfitter.json +``` diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index 57182744893..35f751419fd 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -10,9 +10,11 @@ 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 @@ -25,6 +27,7 @@ def main(config): """ ROOT.gROOT.SetBatch(True) + ROOT.TH1.AddDirectory(False) with open(config, encoding="utf8") as fil: cfg = json.load(fil) @@ -32,22 +35,43 @@ def main(config): hist_rawy, hist_effp, hist_effnp = ([] for _ in range(3)) for filename_rawy, filename_eff in zip(cfg["rawyields"]["inputfiles"], cfg["efficiencies"]["inputfiles"]): infile_rawy = ROOT.TFile.Open(os.path.join(cfg["rawyields"]["inputdir"], filename_rawy)) - hist_rawy.append(infile_rawy.Get(cfg["rawyields"]["histoname"])) + hist_rawy_name = cfg["rawyields"]["histoname"] + hist_rawy.append(infile_rawy.Get(hist_rawy_name)) + if(hist_rawy[-1] is None): + sys.exit(f"Fatal error: Histogram with raw yield \"{hist_rawy_name}\" is absent. Exit.") hist_rawy[-1].SetDirectory(0) infile_rawy.Close() infile_eff = ROOT.TFile.Open(os.path.join(cfg["efficiencies"]["inputdir"], filename_eff)) - hist_effp.append(infile_eff.Get(cfg["efficiencies"]["histonames"]["prompt"])) - hist_effnp.append(infile_eff.Get(cfg["efficiencies"]["histonames"]["nonprompt"])) + hist_effp_name = cfg["efficiencies"]["histonames"]["prompt"] + hist_effnp_name = cfg["efficiencies"]["histonames"]["nonprompt"] + hist_effp.append(infile_eff.Get(hist_effp_name)) + hist_effnp.append(infile_eff.Get(hist_effnp_name)) + if(hist_effp[-1] is None): + sys.exit(f"Fatal error: Histogram with efficiency for prompt \"{hist_effp_name}\" is absent. Exit.") + if(hist_effnp[-1] is None): + sys.exit(f"Fatal error: Histogram with efficiency for nonprompt \"{hist_effnp}\" is absent. Exit.") hist_effp[-1].SetDirectory(0) hist_effnp[-1].SetDirectory(0) infile_eff.Close() + pt_bin_to_process = cfg.get("pt_bin_to_process", -1) + if not isinstance(pt_bin_to_process, int): + sys.exit("Fatal error: pt_bin_to_process must be an integer value. Exit.") + if (pt_bin_to_process != -1 and pt_bin_to_process < 1) or pt_bin_to_process > hist_rawy[0].GetNbinsX(): + sys.exit("Fatal error: pt_bin_to_process must be a positive value up to number of bins in raw yield histogram. Exit.") + if cfg["central_efficiency"]["computerawfrac"]: infile_name = os.path.join(cfg["central_efficiency"]["inputdir"], cfg["central_efficiency"]["inputfile"]) infile_central_eff = ROOT.TFile.Open(infile_name) - hist_central_effp = infile_central_eff.Get(cfg["central_efficiency"]["histonames"]["prompt"]) - hist_central_effnp = infile_central_eff.Get(cfg["central_efficiency"]["histonames"]["nonprompt"]) + hist_central_effp_name = cfg["central_efficiency"]["histonames"]["prompt"] + hist_central_effp = infile_central_eff.Get(hist_central_effp_name) + if(hist_central_effp is None): + sys.exit(f"Fatal error: Histogram with central efficiency for prompt \"{hist_central_effp_name}\" is absent. Exit.") + hist_central_effnp_name = cfg["central_efficiency"]["histonames"]["nonprompt"] + hist_central_effnp = infile_central_eff.Get(hist_central_effnp_name) + if(hist_central_effnp is None): + sys.exit(f"Fatal error: Histogram with central efficiency for nonprompt \"{hist_central_effnp_name}\" is absent. Exit.") hist_central_effp.SetDirectory(0) hist_central_effnp.SetDirectory(0) infile_central_eff.Close() @@ -59,12 +83,18 @@ def main(config): hist_corry_prompt = hist_rawy[0].Clone("hCorrYieldsPrompt") hist_corry_nonprompt = hist_rawy[0].Clone("hCorrYieldsNonPrompt") - hist_covariance = hist_rawy[0].Clone("hCovPromptNonPrompt") + hist_covariance_pnp = hist_rawy[0].Clone("hCovPromptNonPrompt") + hist_covariance_pp = hist_rawy[0].Clone("hCovPromptPrompt") + hist_covariance_npnp = hist_rawy[0].Clone("hCovNonPromptNonPrompt") hist_corrfrac_prompt = hist_rawy[0].Clone("hCorrFracPrompt") hist_corrfrac_nonprompt = hist_rawy[0].Clone("hCorrFracNonPrompt") + for histo in hist_corry_prompt, hist_corry_nonprompt, hist_covariance_pnp, hist_covariance_pp, hist_covariance_npnp, hist_corrfrac_prompt, hist_corrfrac_nonprompt: + histo.Reset() hist_corry_prompt.GetYaxis().SetTitle("corrected yields prompt") hist_corry_nonprompt.GetYaxis().SetTitle("corrected yields non-prompt") - hist_covariance.GetYaxis().SetTitle("#sigma(prompt, non-prompt)") + hist_covariance_pnp.GetYaxis().SetTitle("#sigma(prompt, non-prompt)") + hist_covariance_pp.GetYaxis().SetTitle("#sigma(prompt, prompt)") + hist_covariance_npnp.GetYaxis().SetTitle("#sigma(non-prompt, non-prompt)") hist_corrfrac_prompt.GetYaxis().SetTitle("corrected fraction prompt") hist_corrfrac_nonprompt.GetYaxis().SetTitle("corrected fraction non-prompt") set_object_style( @@ -79,7 +109,9 @@ def main(config): fillstyle=0, markerstyle=ROOT.kFullSquare, ) - set_object_style(hist_covariance) + set_object_style(hist_covariance_pnp) + set_object_style(hist_covariance_pp) + set_object_style(hist_covariance_npnp) set_object_style( hist_corrfrac_prompt, color=ROOT.kRed + 1, @@ -95,6 +127,8 @@ def main(config): if cfg["central_efficiency"]["computerawfrac"]: hist_frac_raw_prompt = hist_rawy[0].Clone("hRawFracPrompt") hist_frac_raw_nonprompt = hist_rawy[0].Clone("hRawFracNonPrompt") + for histo in hist_frac_raw_prompt, hist_frac_raw_nonprompt: + histo.Reset() hist_frac_raw_prompt.GetYaxis().SetTitle("raw fraction prompt") hist_frac_raw_nonprompt.GetYaxis().SetTitle("raw fraction non-prompt") set_object_style( @@ -111,94 +145,148 @@ def main(config): markerstyle=ROOT.kFullSquare, ) - output = ROOT.TFile(os.path.join(cfg["output"]["directory"], cfg["output"]["file"]), "recreate") + pt_bin_to_process_name_suffix = "" + if pt_bin_to_process != -1: + pt_bin_to_process_name_suffix = "_bin_" + str(pt_bin_to_process) + + output_name_template = cfg['output']['file'].replace(".root", "") + pt_bin_to_process_name_suffix + ".root" + output = ROOT.TFile(os.path.join(cfg["output"]["directory"], output_name_template), "recreate") n_sets = len(hist_rawy) + pt_axis_title = hist_rawy[0].GetXaxis().GetTitle() for ipt in range(hist_rawy[0].GetNbinsX()): + if pt_bin_to_process !=-1 and ipt+1 != pt_bin_to_process: + continue pt_min = hist_rawy[0].GetXaxis().GetBinLowEdge(ipt + 1) pt_max = hist_rawy[0].GetXaxis().GetBinUpEdge(ipt + 1) + print(f"\n\nINFO: processing pt range {ipt+1} from {pt_min} to {pt_max} {pt_axis_title}") rawy, effp, effnp, unc_rawy, unc_effp, unc_effnp = (np.zeros(n_sets) for _ in range(6)) for iset, (hrawy, heffp, heffnp) in enumerate(zip(hist_rawy, hist_effp, hist_effnp)): - rawy.itemset(iset, hrawy.GetBinContent(ipt + 1)) - effp.itemset(iset, heffp.GetBinContent(ipt + 1)) - effnp.itemset(iset, heffnp.GetBinContent(ipt + 1)) - unc_rawy.itemset(iset, hrawy.GetBinError(ipt + 1)) - unc_effp.itemset(iset, heffp.GetBinError(ipt + 1)) - unc_effnp.itemset(iset, heffnp.GetBinError(ipt + 1)) + rawy[iset] = hrawy.GetBinContent(ipt + 1) + effp[iset] = heffp.GetBinContent(ipt + 1) + effnp[iset] = heffnp.GetBinContent(ipt + 1) + unc_rawy[iset] = hrawy.GetBinError(ipt + 1) + unc_effp[iset] = heffp.GetBinError(ipt + 1) + unc_effnp[iset] = heffnp.GetBinError(ipt + 1) + + if cfg["minimisation"]["correlated"]: + if not (np.all(rawy[1:] > rawy[:-1]) or np.all(rawy[1:] < rawy[:-1])): + print("WARNING! main(): the raw yield vector is not monotonous. Check the input for stability.") + print(f"raw yield vector elements = {rawy}\n") + if not (np.all(unc_rawy[1:] > unc_rawy[:-1]) or np.all(unc_rawy[1:] < unc_rawy[:-1])): + print("WARNING! main(): the raw yield uncertainties vector is not monotonous. Check the input for stability.") + print(f"raw yield uncertainties vector elements = {unc_rawy}\n") minimiser = CutVarMinimiser(rawy, effp, effnp, unc_rawy, unc_effp, unc_effnp) - minimiser.minimise_system(cfg["minimisation"]["correlated"]) - - hist_corry_prompt.SetBinContent(ipt + 1, minimiser.get_prompt_yield_and_error()[0]) - hist_corry_prompt.SetBinError(ipt + 1, minimiser.get_prompt_yield_and_error()[1]) - hist_corry_nonprompt.SetBinContent(ipt + 1, minimiser.get_nonprompt_yield_and_error()[0]) - hist_corry_nonprompt.SetBinError(ipt + 1, minimiser.get_nonprompt_yield_and_error()[1]) - hist_covariance.SetBinContent(ipt + 1, minimiser.get_prompt_nonprompt_cov()) - hist_covariance.SetBinError(ipt + 1, 0) - corr_frac_prompt = minimiser.get_corr_prompt_fraction() - corr_frac_nonprompt = minimiser.get_corr_nonprompt_fraction() - hist_corrfrac_prompt.SetBinContent(ipt + 1, corr_frac_prompt[0]) - hist_corrfrac_prompt.SetBinError(ipt + 1, corr_frac_prompt[1]) - hist_corrfrac_nonprompt.SetBinContent(ipt + 1, corr_frac_nonprompt[0]) - hist_corrfrac_nonprompt.SetBinError(ipt + 1, corr_frac_nonprompt[1]) - if cfg["central_efficiency"]["computerawfrac"]: - raw_frac_prompt = minimiser.get_raw_prompt_fraction( - hist_central_effp.GetBinContent(ipt + 1), hist_central_effnp.GetBinContent(ipt + 1) - ) - raw_frac_nonprompt = minimiser.get_raw_nonprompt_fraction( - hist_central_effp.GetBinContent(ipt + 1), hist_central_effnp.GetBinContent(ipt + 1) - ) - hist_frac_raw_prompt.SetBinContent(ipt + 1, raw_frac_prompt[0]) - hist_frac_raw_prompt.SetBinError(ipt + 1, raw_frac_prompt[1]) - hist_frac_raw_nonprompt.SetBinContent(ipt + 1, raw_frac_nonprompt[0]) - hist_frac_raw_nonprompt.SetBinError(ipt + 1, raw_frac_nonprompt[1]) - - canv_rawy, histos_rawy, leg_r = minimiser.plot_result(f"_pt{pt_min:.0f}_{pt_max:.0f}") - output.cd() - canv_rawy.Write() - for _, hist in histos_rawy.items(): - hist.Write() - - canv_eff, histos_eff, leg_e = minimiser.plot_efficiencies(f"_pt{pt_min:.0f}_{pt_max:.0f}") - output.cd() - canv_eff.Write() - for _, hist in histos_eff.items(): - hist.Write() - - canv_frac, histos_frac, leg_f = minimiser.plot_fractions(f"_pt{pt_min:.0f}_{pt_max:.0f}") - output.cd() - canv_frac.Write() - for _, hist in histos_frac.items(): - hist.Write() - - canv_cov, histo_cov = minimiser.plot_cov_matrix(True, f"_pt{pt_min:.0f}_{pt_max:.0f}") - output.cd() - canv_cov.Write() - histo_cov.Write() - - 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')}" - 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_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)}") - 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)}]") + status = minimiser.minimise_system(cfg["minimisation"]["correlated"]) + + if status: + hist_corry_prompt.SetBinContent(ipt + 1, minimiser.get_prompt_yield_and_error()[0]) + hist_corry_prompt.SetBinError(ipt + 1, minimiser.get_prompt_yield_and_error()[1]) + hist_corry_nonprompt.SetBinContent(ipt + 1, minimiser.get_nonprompt_yield_and_error()[0]) + hist_corry_nonprompt.SetBinError(ipt + 1, minimiser.get_nonprompt_yield_and_error()[1]) + hist_covariance_pnp.SetBinContent(ipt + 1, minimiser.get_prompt_nonprompt_cov()) + hist_covariance_pnp.SetBinError(ipt + 1, 0) + hist_covariance_pp.SetBinContent(ipt + 1, minimiser.get_prompt_prompt_cov()) + hist_covariance_pp.SetBinError(ipt + 1, 0) + hist_covariance_npnp.SetBinContent(ipt + 1, minimiser.get_nonprompt_nonprompt_cov()) + hist_covariance_npnp.SetBinError(ipt + 1, 0) + corr_frac_prompt = minimiser.get_corr_prompt_fraction() + corr_frac_nonprompt = minimiser.get_corr_nonprompt_fraction() + hist_corrfrac_prompt.SetBinContent(ipt + 1, corr_frac_prompt[0]) + hist_corrfrac_prompt.SetBinError(ipt + 1, corr_frac_prompt[1]) + hist_corrfrac_nonprompt.SetBinContent(ipt + 1, corr_frac_nonprompt[0]) + hist_corrfrac_nonprompt.SetBinError(ipt + 1, corr_frac_nonprompt[1]) + if cfg["central_efficiency"]["computerawfrac"]: + raw_frac_prompt = minimiser.get_raw_prompt_fraction( + hist_central_effp.GetBinContent(ipt + 1), hist_central_effnp.GetBinContent(ipt + 1) + ) + raw_frac_nonprompt = minimiser.get_raw_nonprompt_fraction( + hist_central_effp.GetBinContent(ipt + 1), hist_central_effnp.GetBinContent(ipt + 1) + ) + hist_frac_raw_prompt.SetBinContent(ipt + 1, raw_frac_prompt[0]) + hist_frac_raw_prompt.SetBinError(ipt + 1, raw_frac_prompt[1]) + hist_frac_raw_nonprompt.SetBinContent(ipt + 1, raw_frac_nonprompt[0]) + hist_frac_raw_nonprompt.SetBinError(ipt + 1, raw_frac_nonprompt[1]) + + hist_bin_title = f"bin # {ipt+1}; {pt_axis_title}#in ({pt_min}; {pt_max})" + + canv_rawy, histos_rawy, leg_r = minimiser.plot_result(f"_pt{pt_min}_{pt_max}", hist_bin_title) + output.cd() + canv_rawy.Write() + for _, hist in histos_rawy.items(): + hist.Write() + + canv_unc, histos_unc, leg_unc = minimiser.plot_uncertainties(f"_pt{pt_min}_{pt_max}", hist_bin_title) + output.cd() + canv_unc.Write() + for _, hist in histos_unc.items(): + hist.Write() + + canv_eff, histos_eff, leg_e = minimiser.plot_efficiencies(f"_pt{pt_min}_{pt_max}", hist_bin_title) + output.cd() + canv_eff.Write() + for _, hist in histos_eff.items(): + hist.Write() + + canv_frac, histos_frac, leg_f = minimiser.plot_fractions(f"_pt{pt_min}_{pt_max}", hist_bin_title) + output.cd() + canv_frac.Write() + for _, hist in histos_frac.items(): + hist.Write() + + canv_cov, histo_cov = minimiser.plot_cov_matrix(True, f"_pt{pt_min}_{pt_max}", hist_bin_title) + output.cd() + canv_cov.Write() + histo_cov.Write() + else: + print(f"Minimization for pT {pt_min}, {pt_max} not successful") + canv_rawy = ROOT.TCanvas("c_rawy_minimization_error", "Minimization error", 500, 500) + canv_eff = ROOT.TCanvas("c_eff_minimization_error", "Minimization error", 500, 500) + canv_frac = ROOT.TCanvas("c_frac_minimization_error", "Minimization error", 500, 500) + canv_cov = ROOT.TCanvas("c_conv_minimization_error", "Minimization error", 500, 500) + + canv_combined = ROOT.TCanvas(f"canv_combined_{ipt}", "", 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_template = output_name_template.replace('.root', '.pdf') + + output_name_rawy_pdf = f"Distr_{output_name_template}" + output_name_eff_pdf = f"Eff_{output_name_template}" + output_name_frac_pdf = f"Frac_{output_name_template}" + output_name_covmat_pdf = f"CovMatrix_{output_name_template}" + output_name_unc_pdf = f"Unc_{output_name_template}" + output_name_pdf = f"{output_name_template}" + + if hist_rawy[0].GetNbinsX() == 1 or pt_bin_to_process != -1: + print_bracket = "" + elif ipt == 0: + print_bracket = "(" + elif ipt == hist_rawy[0].GetNbinsX() - 1: + print_bracket = ")" + else: + print_bracket = "" + canv_rawy.Print(f"{os.path.join(cfg['output']['directory'], output_name_rawy_pdf)}{print_bracket}") + canv_eff.Print(f"{os.path.join(cfg['output']['directory'], output_name_eff_pdf)}{print_bracket}") + canv_frac.Print(f"{os.path.join(cfg['output']['directory'], output_name_frac_pdf)}{print_bracket}") + canv_cov.Print(f"{os.path.join(cfg['output']['directory'], output_name_covmat_pdf)}{print_bracket}") + canv_combined.Print(f"{os.path.join(cfg['output']['directory'], output_name_pdf)}{print_bracket}") + canv_unc.Print(f"{os.path.join(cfg['output']['directory'], output_name_unc_pdf)}{print_bracket}") output.cd() hist_corry_prompt.Write() hist_corry_nonprompt.Write() - hist_covariance.Write() + hist_covariance_pnp.Write() + hist_covariance_pp.Write() + hist_covariance_npnp.Write() hist_corrfrac_prompt.Write() hist_corrfrac_nonprompt.Write() if cfg["central_efficiency"]["computerawfrac"]: diff --git a/PWGHF/D2H/Macros/config_cutvar_example.json b/PWGHF/D2H/Macros/config_cutvar_example.json index 6ac80c747ad..20466b37044 100644 --- a/PWGHF/D2H/Macros/config_cutvar_example.json +++ b/PWGHF/D2H/Macros/config_cutvar_example.json @@ -70,4 +70,4 @@ "directory": ".", "file": "CutVarDplus_pp13TeV_MB.root" } -} \ No newline at end of file +} diff --git a/PWGHF/D2H/Macros/config_massfitter.json b/PWGHF/D2H/Macros/config_massfitter.json index 34404095510..393fb8aa0f3 100644 --- a/PWGHF/D2H/Macros/config_massfitter.json +++ b/PWGHF/D2H/Macros/config_massfitter.json @@ -1,136 +1,162 @@ { - "IsMC": false, - "InFileName": "input file directory ", - "ReflFileName": "input reflection file directory", - "OutFileName": "output file directory", - "InputHistoName": [ - "name array of the input data histogram for fit", - "once the projection macro is ready", - "these names will no longer need to be input manually" - ], - "PromptHistoName": [ - "MC prompt histogram name array" - ], - "FDHistoName": [ - "MC FD histogram name array" - ], - "ReflHistoName": [ - "MC reflection histogram name array" - ], - "PromptSecPeakHistoName": [ - "MC prompt second peak histogram name array" - ], - "FDSecPeakHistoName": [ - "MC FD second peak histogram name array" - ], - "Particle": "D0", - "_Particles": [ - "Dplus", - "Ds", - "LcToPKPi", - "LcToPK0s", - "Dstar" - ], - "EnableRefl": true, - "FixSigma": false, - "SigmaFile": "", - "_SigmaFile": "fix sigma from file", - "FixSigmaManual": [ - 0.012, - 0.012, - 0.013, - 0.015, - 0.017, - 0.02 - ], - "_FixSigmaManual": "fix sigma mannually", - "FixMean": false, - "MeanFile": "", - "_MeanFile": "fix mean from file", - "PtMin": [ - 1.0, - 2.0, - 4.0, - 6.0, - 8.0, - 12.0 - ], - "PtMax": [ - 2.0, - 4.0, - 6.0, - 8.0, - 12.0, - 24.0 - ], - "MassMin": [ - 1.72, - 1.72, - 1.72, - 1.72, - 1.72, - 1.72 - ], - "MassMax": [ - 2.03, - 2.03, - 2.03, - 2.03, - 2.03, - 2.03 - ], - "Rebin": [ - 6, - 6, - 6, - 6, - 6, - 6 - ], - "InclSecPeak": false, - "SigmaSecPeak": "", - "SigmaFileSecPeak": "", - "SigmaMultFactorSecPeak": 1.0, - "FixSigmaToFirstPeak": false, - "UseLikelihood": true, - "_UseLikelihood": [ - "true: likelihood fit", - "false: chi2 fit" - ], - "BkgFunc": [ - 0, - 0, - 0, - 0, - 0, - 0 - ], - "_BkgFuncs": [ - "0 for Expo", - "1 for Poly1", - "2 for Poly2", - "3 for Pow", - "4 for PowEx", - "5 for Poly3", - "6 for NoBkg" - ], - "SgnFunc": [ - 0, - 0, - 0, - 0, - 0, - 0 - ], - "_SgnFuncs": [ - "0 for SingleGaus", - "1 for DoubleGaus", - "2 for DoubleGausSigmaRatioPar", - "3 for GausSec" - ], - "BoundMean": false, - "_BoundMean": [ - "false: Do not set limits on mean range", - "true: the mean is set to be between MassMin[i] and MassMax[i]" - ] + "IsMC": false, + "WriteSignalPar": true, + "_WriteSignalPar": "write signal parameter values on mass canvas", + "InFileName": "hMasses.root", + "_InFileName": "download example file here https://cernbox.cern.ch/s/uoWicuRAVGArDsV", + "ReflFileName": "", + "OutFileName": "mInvFits.root", + "InputHistoName": [ + "hMass_T_0.20_0.35", + "hMass_T_0.35_0.50", + "hMass_T_0.50_0.70", + "hMass_T_0.70_0.90", + "hMass_T_0.90_1.60" + ], + "PromptHistoName": [ + "MC prompt histogram name array" + ], + "FDHistoName": [ + "MC FD histogram name array" + ], + "ReflHistoName": [ + "MC reflection histogram name array" + ], + "PromptSecPeakHistoName": [ + "MC prompt second peak histogram name array" + ], + "FDSecPeakHistoName": [ + "MC FD second peak histogram name array" + ], + "Particle": "LcToPKPi", + "_Particles": [ + "Dplus", + "Ds", + "LcToPKPi", + "LcToPK0s", + "Dstar", + "XicToXiPiPi" + ], + "CollisionSystem": "pp #sqrt{#it{s}} = 13.6 TeV", + "_CollisionSystems": "Label for mass canvases", + "EnableRefl": false, + "FixSigma": false, + "SigmaFile": "", + "_SigmaFile": "fix sigma from file", + "FixSigmaManual": [ + 0, + 0, + 0, + 0, + 0 + ], + "_FixSigmaManual": "fix sigma manually", + "FixMean": false, + "MeanFile": "", + "_MeanFile": "fix mean from file", + "FixMeanManual": [ + 0, + 0, + 0, + 0, + 0 + ], + "_FixMeanManual": "fix mean manually", + "FixSecondSigma": false, + "SecondSigmaFile": "", + "_SecondSigmaFile": "fix second sigma for double gauss from file", + "FixSecondSigmaManual": [ + 0, + 0, + 0, + 0, + 0 + ], + "_FixSecondSigmaManual": "fix second sigma for double gauss manually", + "FixFracDoubleGaus": false, + "FracDoubleGausFile": "", + "_FracDoubleGausFile": "fix fraction of sigmas for double gauss from file", + "FixFracDoubleGausManual": [ + 0, + 0, + 0, + 0, + 0 + ], + "_FixFracDoubleGausManual": "fix fraction of sigmas for double gauss manually", + "SliceVarName": "T", + "SliceVarUnit": "ps", + "_SliceVarName, _SliceVarUnit": "e.g. pT, GeV/c or something else depending on user's needs", + "SliceVarMin": [ + 0.2, + 0.35, + 0.5, + 0.7, + 0.9 + ], + "SliceVarMax": [ + 0.35, + 0.5, + 0.7, + 0.9, + 1.6 + ], + "MassMin": [ + 2.12, + 2.12, + 2.12, + 2.12, + 2.12 + ], + "MassMax": [ + 2.42, + 2.42, + 2.42, + 2.42, + 2.42 + ], + "Rebin": [ + 4, + 4, + 4, + 4, + 4 + ], + "InclSecPeak": false, + "UseLikelihood": false, + "_UseLikelihood": [ + "true: likelihood fit", + "false: chi2 fit" + ], + "BkgFunc": [ + 2, + 2, + 2, + 2, + 2 + ], + "_BkgFuncs": [ + "0 for Expo", + "1 for Poly1", + "2 for Poly2", + "3 for Pow", + "4 for PowEx", + "5 for Poly3", + "6 for NoBkg" + ], + "SgnFunc": [ + 0, + 0, + 0, + 0, + 0 + ], + "_SgnFuncs": [ + "0 for SingleGaus", + "1 for DoubleGaus", + "2 for DoubleGausSigmaRatioPar", + "3 for GausSec" + ], + "drawBgPrefit": true, + "highlightPeakRegion": true } diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index 74292f5acd5..3d862589836 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -11,6 +11,7 @@ import numpy as np # pylint: disable=import-error import ROOT # pylint: disable=import-error +sys.path.insert(0, '..') from style_formatter import set_global_style, set_object_style @@ -109,9 +110,9 @@ def __initialise_objects(self): self.unc_frac_nonprompt = np.zeros(shape=self.n_sets) for i_set, (rawy, effp, effnp) in enumerate(zip(self.raw_yields, self.eff_prompt, self.eff_nonprompt)): - self.m_rawy.itemset(i_set, rawy) - self.m_eff.itemset((i_set, 0), effp) - self.m_eff.itemset((i_set, 1), effnp) + self.m_rawy[i_set] = rawy + self.m_eff[(i_set, 0)] = effp + self.m_eff[(i_set, 1)] = effnp # pylint: disable=too-many-locals def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100): @@ -135,7 +136,7 @@ def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100) self.m_eff = np.matrix(self.m_eff) m_corr_yields_old = np.zeros(shape=(2, 1)) - for _ in range(max_iterations): + for iteration in range(max_iterations): for i_row, (rw_unc_row, effp_unc_row, effnp_unc_row) in enumerate( zip(self.unc_raw_yields, self.unc_eff_prompt, self.unc_eff_nonprompt) ): @@ -164,15 +165,21 @@ def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100) else: rho = 0.0 cov_row_col = rho * unc_row * unc_col - self.m_cov_sets.itemset((i_row, i_col), cov_row_col) + self.m_cov_sets[i_row, i_col] = cov_row_col self.m_cov_sets = np.matrix(self.m_cov_sets) - self.m_weights = np.linalg.inv(np.linalg.cholesky(self.m_cov_sets)) + try: + self.m_weights = np.linalg.inv(np.linalg.cholesky(self.m_cov_sets)) + except np.linalg.LinAlgError: + return False self.m_weights = self.m_weights.T * self.m_weights m_eff_tr = self.m_eff.T self.m_covariance = (m_eff_tr * self.m_weights) * self.m_eff - self.m_covariance = np.linalg.inv(np.linalg.cholesky(self.m_covariance)) + try: + self.m_covariance = np.linalg.inv(np.linalg.cholesky(self.m_covariance)) + except np.linalg.LinAlgError: + return False self.m_covariance = self.m_covariance.T * self.m_covariance self.m_corr_yields = self.m_covariance * (m_eff_tr * self.m_weights) * self.m_rawy @@ -188,6 +195,13 @@ def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100) m_corr_yields_old = np.copy(self.m_corr_yields) + print(f"INFO: number of processed iterations = {iteration+1}\n") + if correlated: + m_cov_sets_diag = np.diag(self.m_cov_sets) + if not (np.all(m_cov_sets_diag[1:] > m_cov_sets_diag[:-1]) or np.all(m_cov_sets_diag[1:] < m_cov_sets_diag[:-1])): + print("WARNING! minimise_system(): the residual vector uncertainties elements are not monotonous. Check the input for stability.") + print(f"residual vector uncertainties elements = {np.sqrt(m_cov_sets_diag)}\n") + # chi2 self.chi_2 = float(np.transpose(self.m_res) * self.m_weights * self.m_res) @@ -210,10 +224,12 @@ def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100) + der_fnp_np**2 * self.m_covariance.item(1, 1) + 2 * der_fnp_p * der_fnp_np * self.m_covariance.item(1, 0) ) - self.frac_prompt.itemset(i_set, rawyp / (rawyp + rawynp)) - self.frac_nonprompt.itemset(i_set, rawynp / (rawyp + rawynp)) - self.unc_frac_prompt.itemset(i_set, unc_fp) - self.unc_frac_nonprompt.itemset(i_set, unc_fnp) + self.frac_prompt[i_set] = rawyp / (rawyp + rawynp) + self.frac_nonprompt[i_set] = rawynp / (rawyp + rawynp) + self.unc_frac_prompt[i_set] = unc_fp + self.unc_frac_nonprompt[i_set] = unc_fnp + + return True def get_red_chi2(self): """ @@ -263,6 +279,30 @@ def get_prompt_nonprompt_cov(self): return self.m_covariance.item(1, 0) + def get_prompt_prompt_cov(self): + """ + Helper function to get covariance between prompt and prompt corrected yields + + Returns + ----------------------------------------------------- + - cov_p_np: float + covariance between prompt and prompt corrected yields + """ + + return self.m_covariance.item(0, 0) + + def get_nonprompt_nonprompt_cov(self): + """ + Helper function to get covariance between non-prompt and non-prompt corrected yields + + Returns + ----------------------------------------------------- + - cov_p_np: float + covariance between non-prompt and non-prompt corrected yields + """ + + return self.m_covariance.item(1, 1) + def get_raw_prompt_fraction(self, effacc_p, effacc_np): """ Helper function to get the raw prompt fraction given the efficiencies @@ -295,6 +335,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 +401,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 @@ -345,7 +463,7 @@ def get_corr_nonprompt_fraction(self): return self.get_raw_nonprompt_fraction(1.0, 1.0) # pylint: disable=no-member - def plot_result(self, suffix=""): + def plot_result(self, suffix="", title=""): """ Helper function to plot minimisation result as a function of cut set @@ -353,6 +471,8 @@ def plot_result(self, suffix=""): ----------------------------------------------------- - suffix: str suffix to be added in the name of the output objects + - title: str + title to be written at the top margin of the output objects Returns ----------------------------------------------------- @@ -365,7 +485,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 +555,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) @@ -449,6 +569,9 @@ def plot_result(self, suffix=""): hist_raw_yield_prompt.Draw("histsame") hist_raw_yield_nonprompt.Draw("histsame") hist_raw_yield_sum.Draw("histsame") + tex = ROOT.TLatex() + tex.SetTextSize(0.04) + tex.DrawLatexNDC(0.05, 0.95, title) canvas.Modified() canvas.Update() @@ -461,7 +584,7 @@ def plot_result(self, suffix=""): return canvas, histos, leg - def plot_cov_matrix(self, correlated=True, suffix=""): + def plot_cov_matrix(self, correlated=True, suffix="", title=""): """ Helper function to plot covariance matrix @@ -471,6 +594,8 @@ def plot_cov_matrix(self, correlated=True, suffix=""): correlation between cut sets - suffix: str suffix to be added in the name of the output objects + - title: str + title to be written at the top margin of the output objects Returns ----------------------------------------------------- @@ -484,6 +609,7 @@ def plot_cov_matrix(self, correlated=True, suffix=""): padleftmargin=0.14, padbottommargin=0.12, padrightmargin=0.12, + padtopmargin = 0.075, palette=ROOT.kRainBow, ) @@ -513,12 +639,15 @@ def plot_cov_matrix(self, correlated=True, suffix=""): canvas = ROOT.TCanvas(f"cCorrMatrixCutSets{suffix}", "", 500, 500) hist_corr_matrix.Draw("colz") + tex = ROOT.TLatex() + tex.SetTextSize(0.04) + tex.DrawLatexNDC(0.05, 0.95, title) canvas.Modified() canvas.Update() return canvas, hist_corr_matrix - def plot_efficiencies(self, suffix=""): + def plot_efficiencies(self, suffix="", title=""): """ Helper function to plot efficiencies as a function of cut set @@ -526,6 +655,8 @@ def plot_efficiencies(self, suffix=""): ----------------------------------------------------- - suffix: str suffix to be added in the name of the output objects + - title: str + title to be written at the top margin of the output objects Returns ----------------------------------------------------- @@ -537,7 +668,7 @@ def plot_efficiencies(self, suffix=""): needed otherwise it is destroyed """ - set_global_style(padleftmargin=0.14, padbottommargin=0.12, titleoffset=1.2) + set_global_style(padleftmargin=0.14, padbottommargin=0.12, titleoffset=1.2, padtopmargin = 0.075) hist_eff_prompt = ROOT.TH1F( f"hEffPromptVsCut{suffix}", @@ -599,12 +730,15 @@ def plot_efficiencies(self, suffix=""): leg.AddEntry(hist_eff_prompt, "prompt", "pl") leg.AddEntry(hist_eff_nonprompt, "non-prompt", "pl") leg.Draw() + tex = ROOT.TLatex() + tex.SetTextSize(0.04) + tex.DrawLatexNDC(0.05, 0.95, title) canvas.Modified() canvas.Update() return canvas, histos, leg - def plot_fractions(self, suffix=""): + def plot_fractions(self, suffix="", title=""): """ Helper function to plot fractions as a function of cut set @@ -612,6 +746,8 @@ def plot_fractions(self, suffix=""): ----------------------------------------------------- - suffix: str suffix to be added in the name of the output objects + - title: str + title to be written at the top margin of the output objects Returns ----------------------------------------------------- @@ -623,7 +759,7 @@ def plot_fractions(self, suffix=""): needed otherwise it is destroyed """ - set_global_style(padleftmargin=0.14, padbottommargin=0.12, titleoffset=1.2) + set_global_style(padleftmargin=0.14, padbottommargin=0.12, titleoffset=1.2, padtopmargin = 0.075) hist_f_prompt = ROOT.TH1F( f"hFracPromptVsCut{suffix}", @@ -678,7 +814,91 @@ def plot_fractions(self, suffix=""): leg.AddEntry(hist_f_prompt, "prompt", "pl") leg.AddEntry(hist_f_nonprompt, "non-prompt", "pl") leg.Draw() + tex = ROOT.TLatex() + tex.SetTextSize(0.04) + tex.DrawLatexNDC(0.05, 0.95, title) canvas.Modified() canvas.Update() return canvas, histos, leg + + # pylint: disable=no-member + def plot_uncertainties(self, suffix="", title=""): + """ + Helper function to plot uncertainties as a function of cut set + + Parameters + ----------------------------------------------------- + - suffix: str + suffix to be added in the name of the output objects + - title: str + title to be written at the top margin of the output objects + + Returns + ----------------------------------------------------- + - canvas: ROOT.TCanvas + canvas with plot + - histos: dict + dictionary of ROOT.TH1F with uncertainties distributions for + raw yield and residual vector + - leg: ROOT.TLegend + needed otherwise it is destroyed + """ + + set_global_style(padleftmargin=0.16, padbottommargin=0.12, padtopmargin=0.075, titleoffsety=1.6) + + hist_raw_yield_unc = ROOT.TH1F( + f"hRawYieldUncVsCut{suffix}", + ";cut set;runc.", + self.n_sets, + -0.5, + self.n_sets - 0.5, + ) + + hist_residual_unc = ROOT.TH1F( + f"hResidualUncVsCut{suffix}", + ";cut set;unc.", + self.n_sets, + -0.5, + self.n_sets - 0.5, + ) + + m_cov_sets_diag = np.diag(self.m_cov_sets) + m_cov_sets_diag = np.sqrt(m_cov_sets_diag) + + for i_bin, (unc_rawy, unc_res) in enumerate(zip(self.unc_raw_yields, m_cov_sets_diag)): + hist_raw_yield_unc.SetBinContent(i_bin + 1, unc_rawy) + hist_residual_unc.SetBinContent(i_bin+1, unc_res) + + set_object_style(hist_raw_yield_unc, color=ROOT.kRed + 1, fillstyle=0) + set_object_style(hist_residual_unc, color=ROOT.kAzure + 4, fillstyle=0) + + canvas = ROOT.TCanvas(f"cUncVsCut{suffix}", "", 500, 500) + canvas.DrawFrame( + -0.5, + 0.0, + self.n_sets - 0.5, + hist_residual_unc.GetMaximum() * 1.2, + ";cut set;unc.", + ) + leg = ROOT.TLegend(0.6, 0.75, 0.8, 0.85) + leg.SetBorderSize(0) + leg.SetFillStyle(0) + leg.SetTextSize(0.04) + leg.AddEntry(hist_raw_yield_unc, "raw yield", "l") + leg.AddEntry(hist_residual_unc, "residual vector", "l") + leg.Draw() + hist_raw_yield_unc.Draw("histsame") + hist_residual_unc.Draw("histsame") + tex = ROOT.TLatex() + tex.SetTextSize(0.04) + tex.DrawLatexNDC(0.05, 0.95, title) + canvas.Modified() + canvas.Update() + + histos = { + "rawy": hist_raw_yield_unc, + "residual": hist_residual_unc, + } + + return canvas, histos, leg diff --git a/PWGHF/D2H/Macros/runMassFitter.C b/PWGHF/D2H/Macros/runMassFitter.C index 0c4c44f9ff7..e4baa2a856a 100644 --- a/PWGHF/D2H/Macros/runMassFitter.C +++ b/PWGHF/D2H/Macros/runMassFitter.C @@ -16,41 +16,55 @@ /// \author Mingyu Zhang /// \author Xinye Peng /// \author Biao Zhang +/// \author Oleksii Lubynets +/// \author Phil Stahlhut #if !defined(__CINT__) || defined(__CLING__) #include "HFInvMassFitter.h" -#include // std::cout -#include // std::string -#include // std::vector +#include +#include +#include +#include +#include +#include +#include -#include -#include - -// if .h file not found, please include your local rapidjson/document.h and rapidjson/filereadstream.h here -#include +#include // if .h file not found, please include your local rapidjson/document.h and rapidjson/filereadstream.h here #include +#include +#include + +#include +#include // for fclose +#include +#include +#include +#include // std::string +#include +#include +#include // std::vector + #endif -using namespace std; using namespace rapidjson; -int runMassFitter(TString configFileName = "config_massfitter.json"); +int runMassFitter(const 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++) { + for (const auto* it = jsonArray.Begin(); it != jsonArray.End(); it++) { auto value = it->template Get(); output.emplace_back(value); } } -void parseStringArray(const Value& jsonArray, vector& output) +void parseStringArray(const Value& jsonArray, std::vector& output) { - size_t arrayLength = jsonArray.Size(); + size_t const arrayLength = jsonArray.Size(); for (size_t i = 0; i < arrayLength; i++) { if (jsonArray[i].IsString()) { output.emplace_back(jsonArray[i].GetString()); @@ -58,16 +72,15 @@ void parseStringArray(const Value& jsonArray, vector& output) } } -void divideCanvas(TCanvas* c, int nPtBins); -void setHistoStyle(TH1* histo, int color = kBlack, double markerSize = 1.); +void divideCanvas(TCanvas* c, int nSliceVarBins); +void setHistoStyle(TH1* histo, Color_t color = kBlack, Size_t markerSize = 1); -int runMassFitter(TString configFileName) +int runMassFitter(const TString& configFileName) { // load config FILE* configFile = fopen(configFileName.Data(), "r"); - if (!configFile) { - cerr << "ERROR: Missing configuration json file: " << configFileName << endl; - return -1; + if (configFile == nullptr) { + throw std::runtime_error("ERROR: Missing configuration json file: " + configFileName); } Document config; @@ -76,26 +89,33 @@ int runMassFitter(TString configFileName) config.ParseStream(is); fclose(configFile); - Bool_t isMc = config["IsMC"].GetBool(); - TString inputFileName = config["InFileName"].GetString(); - TString reflFileName = config["ReflFileName"].GetString(); + Bool_t const isMc = config["IsMC"].GetBool(); + Bool_t const writeSignalPar = config["WriteSignalPar"].GetBool(); + TString const particleName = config["Particle"].GetString(); + TString const collisionSystem = config["CollisionSystem"].GetString(); + TString const inputFileName = config["InFileName"].GetString(); + TString const reflFileName = config["ReflFileName"].GetString(); TString outputFileName = config["OutFileName"].GetString(); - TString particleName = config["Particle"].GetString(); - - vector inputHistoName; - vector promptHistoName; - vector fdHistoName; - vector reflHistoName; - vector promptSecPeakHistoName; - vector fdSecPeakHistoName; - vector ptMin; - vector ptMax; - vector massMin; - vector massMax; - vector fixSigmaManual; - vector nRebin; - vector bkgFuncConfig; - vector sgnFuncConfig; + + std::vector inputHistoName; + std::vector promptHistoName; + std::vector fdHistoName; + std::vector reflHistoName; + std::vector promptSecPeakHistoName; + std::vector fdSecPeakHistoName; + TString sliceVarName; + TString sliceVarUnit; + std::vector sliceVarMin; + std::vector sliceVarMax; + std::vector massMin; + std::vector massMax; + std::vector fixMeanManual; + std::vector fixSigmaManual; + std::vector fixSecondSigmaManual; + std::vector fixFracDoubleGausManual; + std::vector nRebin; + std::vector bkgFuncConfig; + std::vector sgnFuncConfig; const Value& inputHistoNameValue = config["InputHistoName"]; parseStringArray(inputHistoNameValue, inputHistoName); @@ -113,23 +133,40 @@ int runMassFitter(TString configFileName) parseStringArray(promptSecPeakHistoNameValue, promptSecPeakHistoName); const Value& fdSecPeakHistoNameValue = config["FDSecPeakHistoName"]; - parseStringArray(promptSecPeakHistoNameValue, promptSecPeakHistoName); + parseStringArray(fdSecPeakHistoNameValue, fdSecPeakHistoName); - bool fixSigma = config["FixSigma"].GetBool(); - string sigmaFile = config["SigmaFile"].GetString(); - double sigmaMultFactor = - config["SigmaMultFactor"].GetDouble(); - bool fixMean = config["FixMean"].GetBool(); - string meanFile = config["MeanFile"].GetString(); + const bool fixMean = config["FixMean"].GetBool(); + const std::string meanFile = config["MeanFile"].GetString(); + + const Value& fixMeanManualValue = config["FixMeanManual"]; + readArray(fixMeanManualValue, fixMeanManual); + + const bool fixSigma = config["FixSigma"].GetBool(); + const std::string sigmaFile = config["SigmaFile"].GetString(); const Value& fixSigmaManualValue = config["FixSigmaManual"]; readArray(fixSigmaManualValue, fixSigmaManual); - const Value& ptMinValue = config["PtMin"]; - readArray(ptMinValue, ptMin); + const bool fixSecondSigma = config["FixSecondSigma"].GetBool(); + const std::string secondSigmaFile = config["SecondSigmaFile"].GetString(); + + const Value& fixSecondSigmaManualValue = config["FixSecondSigmaManual"]; + readArray(fixSecondSigmaManualValue, fixSecondSigmaManual); + + const bool fixFracDoubleGaus = config["FixFracDoubleGaus"].GetBool(); + const std::string fracDoubleGausFile = config["FracDoubleGausFile"].GetString(); + + const Value& fixFracDoubleGausManualValue = config["FixFracDoubleGausManual"]; + readArray(fixFracDoubleGausManualValue, fixFracDoubleGausManual); - const Value& ptMaxValue = config["PtMax"]; - readArray(ptMaxValue, ptMax); + sliceVarName = config["SliceVarName"].GetString(); + sliceVarUnit = config["SliceVarUnit"].GetString(); + + const Value& sliceVarMinValue = config["SliceVarMin"]; + readArray(sliceVarMinValue, sliceVarMin); + + const Value& sliceVarMaxValue = config["SliceVarMax"]; + readArray(sliceVarMaxValue, sliceVarMax); const Value& massMinValue = config["MassMin"]; readArray(massMinValue, massMin); @@ -140,15 +177,8 @@ int runMassFitter(TString configFileName) const Value& rebinValue = config["Rebin"]; readArray(rebinValue, nRebin); - bool includeSecPeak = config["InclSecPeak"].GetBool(); - string sigmaSecPeak = config["SigmaSecPeak"].GetString(); - string sigmaFileSecPeak = - config["SigmaFileSecPeak"].GetString(); - double sigmaMultFactorSecPeak = - config["SigmaMultFactorSecPeak"].GetDouble(); - bool fixSigmaToFirstPeak = - config["FixSigmaToFirstPeak"].GetBool(); - bool useLikelihood = config["UseLikelihood"].GetBool(); + bool const includeSecPeak = config["InclSecPeak"].GetBool(); + bool const useLikelihood = config["UseLikelihood"].GetBool(); const Value& bkgFuncValue = config["BkgFunc"]; readArray(bkgFuncValue, bkgFuncConfig); @@ -156,192 +186,112 @@ int runMassFitter(TString configFileName) const Value& sgnFuncValue = config["SgnFunc"]; readArray(sgnFuncValue, sgnFuncConfig); - bool fixSigmaRatio = config["FixSigmaRatio"].GetBool(); - TString sigmaRatioFile = config["SigmaRatioFile"].GetString(); - bool boundMean = config["BoundMean"].GetBool(); - bool enableRefl = config["EnableRefl"].GetBool(); - - const unsigned int nPtBins = ptMin.size(); - int bkgFunc[nPtBins], sgnFunc[nPtBins]; - double ptLimits[nPtBins + 1]; - - for (unsigned int iPt = 0; iPt < nPtBins; iPt++) { - ptLimits[iPt] = ptMin[iPt]; - ptLimits[iPt + 1] = ptMax[iPt]; - - if (bkgFuncConfig[iPt] == 0) { - bkgFunc[iPt] = HFInvMassFitter::Expo; - } else if (bkgFuncConfig[iPt] == 1) { - bkgFunc[iPt] = HFInvMassFitter::Poly1; - } else if (bkgFuncConfig[iPt] == 2) { - bkgFunc[iPt] = HFInvMassFitter::Poly2; - } else if (bkgFuncConfig[iPt] == 3) { - bkgFunc[iPt] = HFInvMassFitter::Pow; - } else if (bkgFuncConfig[iPt] == 4) { - bkgFunc[iPt] = HFInvMassFitter::PowExpo; - } else if (bkgFuncConfig[iPt] == 5) { - bkgFunc[iPt] = HFInvMassFitter::Poly3; - } else if (bkgFuncConfig[iPt] == 6) { - bkgFunc[iPt] = HFInvMassFitter::NoBkg; - } else { - cerr << "ERROR: only Expo, Poly1, Poly2, Pow and PowEx background " - "functions supported! Exit" - << endl; - return -1; + const bool enableRefl = config["EnableRefl"].GetBool(); + + const bool drawBgPrefit = config["drawBgPrefit"].GetBool(); + const bool highlightPeakRegion = config["highlightPeakRegion"].GetBool(); + + const unsigned int nSliceVarBins = sliceVarMin.size(); + std::vector bkgFunc(nSliceVarBins); + std::vector sgnFunc(nSliceVarBins); + std::vector sliceVarLimits(nSliceVarBins + 1); + + for (unsigned int iSliceVar = 0; iSliceVar < nSliceVarBins; iSliceVar++) { + sliceVarLimits[iSliceVar] = sliceVarMin[iSliceVar]; + sliceVarLimits[iSliceVar + 1] = sliceVarMax[iSliceVar]; + + if (bkgFuncConfig[iSliceVar] < 0 || bkgFuncConfig[iSliceVar] >= HFInvMassFitter::NTypesOfBkgPdf) { + throw std::runtime_error("ERROR: only Expo, Poly1, Poly2, Pow and PowEx background functions supported! Exit"); } + bkgFunc[iSliceVar] = bkgFuncConfig[iSliceVar]; - if (sgnFuncConfig[iPt] == 0) { - sgnFunc[iPt] = HFInvMassFitter::SingleGaus; - } else if (sgnFuncConfig[iPt] == 1) { - sgnFunc[iPt] = HFInvMassFitter::DoubleGaus; - } else if (sgnFuncConfig[iPt] == 2) { - sgnFunc[iPt] = HFInvMassFitter::DoubleGausSigmaRatioPar; - } else { - cerr << "ERROR: only SingleGaus, DoubleGaus and DoubleGausSigmaRatioPar signal " - "functions supported! Exit" - << endl; - return -1; + if (sgnFuncConfig[iSliceVar] < 0 || sgnFuncConfig[iSliceVar] >= HFInvMassFitter::NTypesOfSgnPdf) { + throw std::runtime_error("ERROR: only SingleGaus, DoubleGaus and DoubleGausSigmaRatioPar signal functions supported! Exit"); } + sgnFunc[iSliceVar] = sgnFuncConfig[iSliceVar]; } - TString massAxisTitle = ""; - if (particleName == "Dplus") { - massAxisTitle = "#it{M}(K#pi#pi) (GeV/#it{c}^{2})"; - } else if (particleName == "D0") { - massAxisTitle = "#it{M}(K#pi) (GeV/#it{c}^{2})"; - } else if (particleName == "Ds") { - massAxisTitle = "#it{M}(KK#pi) (GeV/#it{c}^{2})"; - } else if (particleName == "LcToPKPi") { - massAxisTitle = "#it{M}(pK#pi) (GeV/#it{c}^{2})"; - } else if (particleName == "LcToPK0s") { - massAxisTitle = "#it{M}(pK^{0}_{s}) (GeV/#it{c}^{2})"; - } else if (particleName == "Dstar") { - massAxisTitle = "#it{M}(pi^{+}) (GeV/#it{c}^{2})"; - } else { - cerr << "ERROR: only Dplus, D0, Ds, LcToPKPi, LcToPK0s and Dstar particles supported! Exit" << endl; - return -1; + std::map> particles{ + {"Dplus", {"K#pi#pi", "D+", "D^{+} #rightarrow K^{-}#pi^{+}#pi^{+} + c.c."}}, + {"D0", {"K#pi", "D0", "D^{0} #rightarrow K^{-}#pi^{+} + c.c."}}, + {"Ds", {"KK#pi", "D_s+", "D_{s}^{+} #rightarrow K^{-}K^{+}#pi^{+} + c.c."}}, + {"LcToPKPi", {"pK#pi", "Lambda_c+", "#Lambda_{c}^{+} #rightarrow pK^{-}#pi^{+} + c.c."}}, + {"LcToPK0s", {"pK^{0}_{s}", "Lambda_c+", "#Lambda_{c}^{+} #rightarrow pK^{0}_{s} + c.c."}}, + {"Dstar", {"D^{0}pi^{+}", "D*+", "D^{*+} #rightarrow D^{0}#pi^{+} + c.c."}}, + {"XicToXiPiPi", {"#Xi#pi#pi", "Xi_c+", "#Xi_{c}^{+} #rightarrow #Xi^{-}#pi^{+}#pi^{+} + c.c."}}}; + if (particles.find(particleName.Data()) == particles.end()) { + throw std::runtime_error("ERROR: only Dplus, D0, Ds, LcToPKPi, LcToPK0s, Dstar and XicToXiPiPi particles supported! Exit"); } + const auto& particleTuple = particles[particleName.Data()]; + const TString massAxisTitle = "#it{M}(" + std::get<0>(particleTuple) + ") (GeV/#it{c}^{2})"; + const double massPDG = TDatabasePDG::Instance()->GetParticle(std::get<1>(particleTuple).c_str())->Mass(); + const std::vector plotLabels = {std::get<2>(particleTuple), collisionSystem.Data()}; // load inv-mass histograms - auto inputFile = TFile::Open(inputFileName.Data()); - if (!inputFile || !inputFile->IsOpen()) { + auto* inputFile = TFile::Open(inputFileName.Data()); + if ((inputFile == nullptr) || !inputFile->IsOpen()) { return -1; } - TFile* inputFileRefl = NULL; + TFile* inputFileRefl = nullptr; if (enableRefl) { inputFileRefl = TFile::Open(reflFileName.Data()); - if (!inputFileRefl || !inputFileRefl->IsOpen()) { + if ((inputFileRefl == nullptr) || !inputFileRefl->IsOpen()) { return -1; } } - TH1F* hMassSgn[nPtBins]; - TH1F* hMassRefl[nPtBins]; - TH1F* hMass[nPtBins]; + std::vector hMassSgn(nSliceVarBins); + std::vector hMassRefl(nSliceVarBins); + std::vector hMass(nSliceVarBins); - for (unsigned int iPt = 0; iPt < nPtBins; iPt++) { + for (unsigned int iSliceVar = 0; iSliceVar < nSliceVarBins; iSliceVar++) { if (!isMc) { - hMass[iPt] = static_cast(inputFile->Get(inputHistoName[iPt].data())); + hMass[iSliceVar] = inputFile->Get(inputHistoName[iSliceVar].data()); if (enableRefl) { - hMassRefl[iPt] = static_cast(inputFileRefl->Get(reflHistoName[iPt].data())); - hMassSgn[iPt] = static_cast(inputFileRefl->Get(fdHistoName[iPt].data())); - hMassSgn[iPt]->Add(static_cast(inputFileRefl->Get(promptHistoName[iPt].data()))); - if (!hMassRefl[iPt]) { - cerr << "ERROR: MC reflection histogram not found! Exit!" << endl; - return -1; + hMassRefl[iSliceVar] = inputFileRefl->Get(reflHistoName[iSliceVar].data()); + if (hMassRefl[iSliceVar] == nullptr) { + throw std::runtime_error("ERROR: MC reflection histogram not found! Exit!"); } - if (!hMassSgn[iPt]) { - cerr << "ERROR: MC prompt or FD histogram not found! Exit!" << endl; - return -1; + hMassSgn[iSliceVar] = inputFileRefl->Get(fdHistoName[iSliceVar].data()); + if (hMassSgn[iSliceVar] == nullptr) { + throw std::runtime_error("ERROR: MC prompt or FD histogram not found! Exit!"); } + hMassSgn[iSliceVar]->Add(inputFileRefl->Get(promptHistoName[iSliceVar].data())); } } else { - hMass[iPt] = static_cast(inputFile->Get(promptHistoName[iPt].data())); - hMass[iPt]->Add(static_cast(inputFile->Get(fdHistoName[iPt].data()))); + hMass[iSliceVar] = inputFile->Get(promptHistoName[iSliceVar].data()); + hMass[iSliceVar]->Add(inputFile->Get(fdHistoName[iSliceVar].data())); if (includeSecPeak) { - hMass[iPt]->Add(static_cast(inputFile->Get(promptSecPeakHistoName[iPt].data()))); - hMass[iPt]->Add(static_cast(inputFile->Get(fdSecPeakHistoName[iPt].data()))); + hMass[iSliceVar]->Add(inputFile->Get(promptSecPeakHistoName[iSliceVar].data())); + hMass[iSliceVar]->Add(inputFile->Get(fdSecPeakHistoName[iSliceVar].data())); } } - if (!hMass[iPt]) { - cerr << "ERROR: input histogram for fit not found! Exit!" << endl; - return -1; + if (hMass[iSliceVar] == nullptr) { + throw std::runtime_error("ERROR: input histogram for fit not found! Exit!"); } - hMass[iPt]->SetDirectory(0); + hMass[iSliceVar]->SetDirectory(nullptr); } inputFile->Close(); // define output histos - auto hRawYields = new TH1D("hRawYields", ";#it{p}_{T} (GeV/#it{c});raw yield", - nPtBins, ptLimits); - auto hRawYieldsSigma = new TH1D( - "hRawYieldsSigma", ";#it{p}_{T} (GeV/#it{c});width (GeV/#it{c}^{2})", - nPtBins, ptLimits); - auto hRawYieldsSigmaRatio = new TH1D( - "hRawYieldsSigmaRatio", - ";#it{p}_{T} (GeV/#it{c});ratio #sigma_{1}/#sigma_{2}", nPtBins, ptLimits); - auto hRawYieldsSigma2 = new TH1D( - "hRawYieldsSigma2", ";#it{p}_{T} (GeV/#it{c});width (GeV/#it{c}^{2})", - nPtBins, ptLimits); - auto hRawYieldsMean = new TH1D( - "hRawYieldsMean", ";#it{p}_{T} (GeV/#it{c});mean (GeV/#it{c}^{2})", - nPtBins, ptLimits); - auto hRawYieldsFracGaus2 = new TH1D( - "hRawYieldsFracGaus2", - ";#it{p}_{T} (GeV/#it{c});second-gaussian fraction", nPtBins, ptLimits); - auto hRawYieldsSignificance = new TH1D( - "hRawYieldsSignificance", - ";#it{p}_{T} (GeV/#it{c});significance (3#sigma)", nPtBins, ptLimits); - auto hRawYieldsSgnOverBkg = - new TH1D("hRawYieldsSgnOverBkg", ";#it{p}_{T} (GeV/#it{c});S/B (3#sigma)", - nPtBins, ptLimits); - auto hRawYieldsSignal = - new TH1D("hRawYieldsSignal", ";#it{p}_{T} (GeV/#it{c});Signal (3#sigma)", - nPtBins, ptLimits); - auto hRawYieldsBkg = - new TH1D("hRawYieldsBkg", ";#it{p}_{T} (GeV/#it{c});Background (3#sigma)", - nPtBins, ptLimits); - auto hRawYieldsChiSquare = - new TH1D("hRawYieldsChiSquare", - ";#it{p}_{T} (GeV/#it{c});#chi^{2}/#it{ndf}", nPtBins, ptLimits); - auto hRawYieldsSecondPeak = new TH1D( - "hRawYieldsSecondPeak", ";#it{p}_{T} (GeV/#it{c});raw yield second peak", - nPtBins, ptLimits); - auto hRawYieldsMeanSecondPeak = - new TH1D("hRawYieldsMeanSecondPeak", - ";#it{p}_{T} (GeV/#it{c});mean second peak (GeV/#it{c}^{2})", - nPtBins, ptLimits); - auto hRawYieldsSigmaSecondPeak = - new TH1D("hRawYieldsSigmaSecondPeak", - ";#it{p}_{T} (GeV/#it{c});width second peak (GeV/#it{c}^{2})", - nPtBins, ptLimits); - auto hRawYieldsSignificanceSecondPeak = - new TH1D("hRawYieldsSignificanceSecondPeak", - ";#it{p}_{T} (GeV/#it{c});signficance second peak (3#sigma)", - nPtBins, ptLimits); - auto hRawYieldsSigmaRatioSecondFirstPeak = - new TH1D("hRawYieldsSigmaRatioSecondFirstPeak", - ";#it{p}_{T} (GeV/#it{c});width second peak / width first peak", - nPtBins, ptLimits); - auto hRawYieldsSoverBSecondPeak = new TH1D( - "hRawYieldsSoverBSecondPeak", - ";#it{p}_{T} (GeV/#it{c});S/B second peak (3#sigma)", nPtBins, ptLimits); - auto hRawYieldsSignalSecondPeak = new TH1D( - "hRawYieldsSignalSecondPeak", - ";#it{p}_{T} (GeV/#it{c});Signal second peak (3#sigma)", nPtBins, ptLimits); - auto hRawYieldsBkgSecondPeak = - new TH1D("hRawYieldsBkgSecondPeak", - ";#it{p}_{T} (GeV/#it{c});Background second peak (3#sigma)", - nPtBins, ptLimits); - auto hReflectionOverSignal = - new TH1D("hReflectionOverSignal", ";#it{p}_{T} (GeV/#it{c});Refl/Signal", - nPtBins, ptLimits); + auto* hRawYieldsSignal = new TH1D("hRawYieldsSignal", ";" + sliceVarName + "(" + sliceVarUnit + ");raw yield", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsSignalCounted = new TH1D("hRawYieldsSignalCounted", ";" + sliceVarName + "(" + sliceVarUnit + ");raw yield via bin count", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsBkg = new TH1D("hRawYieldsBkg", ";" + sliceVarName + "(" + sliceVarUnit + ");Background (3#sigma)", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsSgnOverBkg = new TH1D("hRawYieldsSgnOverBkg", ";" + sliceVarName + "(" + sliceVarUnit + ");S/B (3#sigma)", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsSignificance = new TH1D("hRawYieldsSignificance", ";" + sliceVarName + "(" + sliceVarUnit + ");significance (3#sigma)", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsChiSquareBkg = new TH1D("hRawYieldsChiSquareBkg", ";" + sliceVarName + "(" + sliceVarUnit + ");#chi^{2}/#it{ndf}", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsChiSquareTotal = new TH1D("hRawYieldsChiSquareTotal", ";" + sliceVarName + "(" + sliceVarUnit + ");#chi^{2}/#it{ndf}", nSliceVarBins, sliceVarLimits.data()); + auto* hReflectionOverSignal = new TH1D("hReflectionOverSignal", ";" + sliceVarName + "(" + sliceVarUnit + ");Refl/Signal", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsMean = new TH1D("hRawYieldsMean", ";" + sliceVarName + "(" + sliceVarUnit + ");mean (GeV/#it{c}^{2})", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsSigma = new TH1D("hRawYieldsSigma", ";" + sliceVarName + "(" + sliceVarUnit + ");width (GeV/#it{c}^{2})", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsSecSigma = new TH1D("hRawYieldsSecSigma", ";" + sliceVarName + "(" + sliceVarUnit + ");width (GeV/#it{c}^{2})", nSliceVarBins, sliceVarLimits.data()); + auto* hRawYieldsFracDoubleGaus = new TH1D("hRawYieldsFracDoubleGaus", ";" + sliceVarName + "(" + sliceVarUnit + ");fraction of double gaussian", nSliceVarBins, sliceVarLimits.data()); const Int_t nConfigsToSave = 6; - auto hFitConfig = new TH2F("hfitConfig", "Fit Configurations", nConfigsToSave, 0, 6, nPtBins, ptLimits); + auto* hFitConfig = new TH2F("hfitConfig", "Fit Configurations", nConfigsToSave, 0, 6, nSliceVarBins, sliceVarLimits.data()); const char* hFitConfigXLabel[nConfigsToSave] = {"mass min", "mass max", "rebin num", "fix sigma", "bkg func", "sgn func"}; - hFitConfig->SetStats(0); + hFitConfig->SetStats(false); hFitConfig->LabelsDeflate("X"); hFitConfig->LabelsDeflate("Y"); hFitConfig->LabelsOption("v"); @@ -349,73 +299,64 @@ int runMassFitter(TString configFileName) hFitConfig->GetXaxis()->SetBinLabel(i + 1, hFitConfigXLabel[i]); } - setHistoStyle(hRawYields); - setHistoStyle(hRawYieldsSigma); - setHistoStyle(hRawYieldsSigma2); - setHistoStyle(hRawYieldsMean); - setHistoStyle(hRawYieldsFracGaus2); - setHistoStyle(hRawYieldsSignificance); - setHistoStyle(hRawYieldsSgnOverBkg); setHistoStyle(hRawYieldsSignal); + setHistoStyle(hRawYieldsSignalCounted); setHistoStyle(hRawYieldsBkg); - setHistoStyle(hRawYieldsChiSquare); - setHistoStyle(hRawYieldsSecondPeak, kRed + 1); - setHistoStyle(hRawYieldsMeanSecondPeak, kRed + 1); - setHistoStyle(hRawYieldsSigmaSecondPeak, kRed + 1); - setHistoStyle(hRawYieldsSignificanceSecondPeak, kRed + 1); - setHistoStyle(hRawYieldsSigmaRatioSecondFirstPeak, kRed + 1); - setHistoStyle(hRawYieldsSoverBSecondPeak, kRed + 1); - setHistoStyle(hRawYieldsSignalSecondPeak, kRed + 1); - setHistoStyle(hRawYieldsBkgSecondPeak, kRed + 1); + setHistoStyle(hRawYieldsSgnOverBkg); + setHistoStyle(hRawYieldsSignificance); + setHistoStyle(hRawYieldsChiSquareBkg); + setHistoStyle(hRawYieldsChiSquareTotal); setHistoStyle(hReflectionOverSignal, kRed + 1); - - TH1D* hSigmaToFix = NULL; - if (fixSigma) { - if (fixSigmaManual.empty()) { - auto inputFileSigma = TFile::Open(sigmaFile.data()); - if (!inputFileSigma) { - return -2; - } - hSigmaToFix = static_cast(inputFileSigma->Get("hRawYieldsSigma")); - hSigmaToFix->SetDirectory(0); - if (static_cast(hSigmaToFix->GetNbinsX()) != nPtBins) { - cout << "WARNING: Different number of bins for this analysis and histo for fix sigma!" << endl; + setHistoStyle(hRawYieldsMean); + setHistoStyle(hRawYieldsSigma); + setHistoStyle(hRawYieldsSecSigma); + setHistoStyle(hRawYieldsFracDoubleGaus); + + auto getHistToFix = [&nSliceVarBins](bool const& isFix, std::vector const& fixManual, std::string const& fixFileName, std::string const& var) -> TH1* { + TH1* histToFix = nullptr; + if (isFix) { + if (fixManual.empty()) { + auto* fixInputFile = TFile::Open(fixFileName.data()); + if (fixInputFile == nullptr) { + throw std::runtime_error("Cannot open file for fixed " + var); + } + const std::string histName = "hRawYields" + var; + histToFix = fixInputFile->Get(histName.data()); + histToFix->SetDirectory(nullptr); + if (static_cast(histToFix->GetNbinsX()) != nSliceVarBins) { + throw std::runtime_error("Different number of bins for this analysis and histo for fixed " + var); + } + fixInputFile->Close(); } - inputFileSigma->Close(); } - } + return histToFix; + }; - TH1D* hMeanToFix = NULL; - if (fixMean) { - auto inputFileMean = TFile::Open(meanFile.data()); - if (!inputFileMean) { - return -3; - } - hMeanToFix = static_cast(inputFileMean->Get("hRawYieldsMean")); - hMeanToFix->SetDirectory(0); - if (static_cast(hMeanToFix->GetNbinsX()) != nPtBins) { - cout << "WARNING: Different number of bins for this analysis and histo for fix mean" << endl; - } - inputFileMean->Close(); - } + TH1* hSigmaToFix = getHistToFix(fixSigma, fixSigmaManual, sigmaFile, "Sigma"); + TH1* hMeanToFix = getHistToFix(fixMean, fixMeanManual, meanFile, "Mean"); + TH1* hSecondSigmaToFix = getHistToFix(fixSecondSigma, fixSecondSigmaManual, secondSigmaFile, "SecSigma"); + TH1* hFracDoubleGausToFix = getHistToFix(fixFracDoubleGaus, fixFracDoubleGausManual, fracDoubleGausFile, "FracDoubleGaus"); // fit histograms - TH1F* hMassForFit[nPtBins]; - TH1F* hMassForRefl[nPtBins]; - TH1F* hMassForSgn[nPtBins]; + std::vector hMassForFit(nSliceVarBins); + std::vector hMassForRefl(nSliceVarBins); + std::vector hMassForSgn(nSliceVarBins); Int_t canvasSize[2] = {1920, 1080}; - if (nPtBins == 1) { + if (nSliceVarBins == 1) { canvasSize[0] = 500; canvasSize[1] = 500; } - Int_t nCanvasesMax = 20; // do not put more than 20 bins per canvas to make them visible - const Int_t nCanvases = ceil((float)nPtBins / nCanvasesMax); - TCanvas *canvasMass[nCanvases], *canvasResiduals[nCanvases], *canvasRefl[nCanvases]; + Int_t const nCanvasesMax = 20; // do not put more than 20 bins per canvas to make them visible + const Int_t nCanvases = std::ceil(static_cast(nSliceVarBins) / nCanvasesMax); + std::vector canvasMass(nCanvases); + std::vector canvasResiduals(nCanvases); + std::vector canvasRatio(nCanvases); + std::vector canvasRefl(nCanvases); for (int iCanvas = 0; iCanvas < nCanvases; iCanvas++) { - int nPads = (nCanvases == 1) ? nPtBins : nCanvasesMax; + const int nPads = (nCanvases == 1) ? nSliceVarBins : nCanvasesMax; canvasMass[iCanvas] = new TCanvas(Form("canvasMass%d", iCanvas), Form("canvasMass%d", iCanvas), canvasSize[0], canvasSize[1]); divideCanvas(canvasMass[iCanvas], nPads); @@ -423,137 +364,184 @@ int runMassFitter(TString configFileName) canvasResiduals[iCanvas] = new TCanvas(Form("canvasResiduals%d", iCanvas), Form("canvasResiduals%d", iCanvas), canvasSize[0], canvasSize[1]); divideCanvas(canvasResiduals[iCanvas], nPads); - canvasRefl[iCanvas] = new TCanvas(Form("canvasRefl%d", iCanvas), Form("canvasRefl%d", iCanvas), - canvasSize[0], canvasSize[1]); - divideCanvas(canvasRefl[iCanvas], nPads); + + canvasRatio[iCanvas] = new TCanvas(Form("canvasRatio%d", iCanvas), Form("canvasRatio%d", iCanvas), + canvasSize[0], canvasSize[1]); + divideCanvas(canvasRatio[iCanvas], nPads); + + if (enableRefl) { + canvasRefl[iCanvas] = new TCanvas(Form("canvasRefl%d", iCanvas), Form("canvasRefl%d", iCanvas), + canvasSize[0], canvasSize[1]); + divideCanvas(canvasRefl[iCanvas], nPads); + } } - for (unsigned int iPt = 0; iPt < nPtBins; iPt++) { - Int_t iCanvas = floor((float)iPt / nCanvasesMax); + for (unsigned int iSliceVar = 0; iSliceVar < nSliceVarBins; iSliceVar++) { + const Int_t iCanvas = std::floor(static_cast(iSliceVar) / nCanvasesMax); - hMassForFit[iPt] = reinterpret_cast(hMass[iPt]->Rebin(nRebin[iPt])); - TString ptTitle = - Form("%0.1f < #it{p}_{T} < %0.1f GeV/#it{c}", ptMin[iPt], ptMax[iPt]); - hMassForFit[iPt]->SetTitle(Form("%s;%s;Counts per %0.f MeV/#it{c}^{2}", - ptTitle.Data(), massAxisTitle.Data(), - hMassForFit[iPt]->GetBinWidth(1) * 1000)); - hMassForFit[iPt]->SetName(Form("MassForFit%d", iPt)); + hMassForFit[iSliceVar] = hMass[iSliceVar]->Rebin(nRebin[iSliceVar]); + TString const ptTitle = + Form("%0.2f < " + sliceVarName + " < %0.2f " + sliceVarUnit, sliceVarMin[iSliceVar], sliceVarMax[iSliceVar]); + hMassForFit[iSliceVar]->SetTitle(Form("%s;%s;Counts per %0.1f MeV/#it{c}^{2}", + ptTitle.Data(), massAxisTitle.Data(), + hMassForFit[iSliceVar]->GetBinWidth(1) * 1000)); + hMassForFit[iSliceVar]->SetName(Form("MassForFit%d", iSliceVar)); if (enableRefl) { - hMassForRefl[iPt] = - reinterpret_cast(hMassRefl[iPt]->Rebin(nRebin[iPt])); - hMassForSgn[iPt] = - reinterpret_cast(hMassSgn[iPt]->Rebin(nRebin[iPt])); + hMassForRefl[iSliceVar] = hMassRefl[iSliceVar]->Rebin(nRebin[iSliceVar]); + hMassForSgn[iSliceVar] = hMassSgn[iSliceVar]->Rebin(nRebin[iSliceVar]); } Double_t reflOverSgn = 0; - double markerSize = 1.; - if (nPtBins > 15) { - markerSize = 0.5; - } if (isMc) { HFInvMassFitter* massFitter; - massFitter = new HFInvMassFitter(hMassForFit[iPt], massMin[iPt], massMax[iPt], HFInvMassFitter::NoBkg, sgnFunc[iPt]); - massFitter->doFit(false); - - if (nPtBins > 1) { - canvasMass[iCanvas]->cd(iPt - nCanvasesMax * iCanvas + 1); + massFitter = new HFInvMassFitter(hMassForFit[iSliceVar], massMin[iSliceVar], massMax[iSliceVar], HFInvMassFitter::NoBkg, sgnFunc[iSliceVar]); + massFitter->setDrawBgPrefit(drawBgPrefit); + massFitter->setHighlightPeakRegion(highlightPeakRegion); + massFitter->setInitialGaussianMean(massPDG); + massFitter->setParticlePdgMass(massPDG); + massFitter->setBoundGaussianMean(massPDG, 0.8 * massPDG, 1.2 * massPDG); + massFitter->doFit(); + + if (nSliceVarBins > 1) { + canvasMass[iCanvas]->cd(iSliceVar - nCanvasesMax * iCanvas + 1); } else { canvasMass[iCanvas]->cd(); } - massFitter->drawFit(gPad); - - Double_t rawYield = massFitter->getRawYield(); - Double_t rawYieldErr = massFitter->getRawYieldError(); - - Double_t sigma = massFitter->getSigma(); - Double_t sigmaErr = massFitter->getSigmaUncertainty(); - Double_t mean = massFitter->getMean(); - Double_t meanErr = massFitter->getMeanUncertainty(); - Double_t reducedChiSquare = massFitter->getChiSquareOverNDF(); - - hRawYields->SetBinContent(iPt + 1, rawYield); - hRawYields->SetBinError(iPt + 1, rawYieldErr); - hRawYieldsSigma->SetBinContent(iPt + 1, sigma); - hRawYieldsSigma->SetBinError(iPt + 1, sigmaErr); - hRawYieldsMean->SetBinContent(iPt + 1, mean); - hRawYieldsMean->SetBinError(iPt + 1, meanErr); - hRawYieldsChiSquare->SetBinContent(iPt + 1, reducedChiSquare); - hRawYieldsChiSquare->SetBinError(iPt + 1, 0.); + massFitter->drawFit(gPad, plotLabels, writeSignalPar); + + const Double_t rawYield = massFitter->getRawYield(); + const Double_t rawYieldErr = massFitter->getRawYieldError(); + const Double_t rawYieldCounted = massFitter->getRawYieldCounted(); + const Double_t rawYieldCountedErr = massFitter->getRawYieldCountedError(); + const Double_t reducedChiSquareBkg = massFitter->getChiSquareOverNDFBkg(); + const Double_t reducedChiSquareTotal = massFitter->getChiSquareOverNDFTotal(); + const Double_t mean = massFitter->getMean(); + const Double_t meanErr = massFitter->getMeanUncertainty(); + const Double_t sigma = massFitter->getSigma(); + const Double_t sigmaErr = massFitter->getSigmaUncertainty(); + + hRawYieldsSignal->SetBinContent(iSliceVar + 1, rawYield); + hRawYieldsSignal->SetBinError(iSliceVar + 1, rawYieldErr); + hRawYieldsSignalCounted->SetBinContent(iSliceVar + 1, rawYieldCounted); + hRawYieldsSignalCounted->SetBinError(iSliceVar + 1, rawYieldCountedErr); + hRawYieldsChiSquareBkg->SetBinContent(iSliceVar + 1, reducedChiSquareBkg); + hRawYieldsChiSquareBkg->SetBinError(iSliceVar + 1, 0.); + hRawYieldsChiSquareTotal->SetBinContent(iSliceVar + 1, reducedChiSquareTotal); + hRawYieldsChiSquareTotal->SetBinError(iSliceVar + 1, 0.); + hRawYieldsMean->SetBinContent(iSliceVar + 1, mean); + hRawYieldsMean->SetBinError(iSliceVar + 1, meanErr); + hRawYieldsSigma->SetBinContent(iSliceVar + 1, sigma); + hRawYieldsSigma->SetBinError(iSliceVar + 1, sigmaErr); + + if (sgnFunc[iSliceVar] != HFInvMassFitter::SingleGaus) { + const Double_t secSigma = massFitter->getSecSigma(); + const Double_t secSigmaErr = massFitter->getSecSigmaUncertainty(); + hRawYieldsSecSigma->SetBinContent(iSliceVar + 1, secSigma); + hRawYieldsSecSigma->SetBinError(iSliceVar + 1, secSigmaErr); + } + if (sgnFunc[iSliceVar] == HFInvMassFitter::DoubleGaus || sgnFunc[iSliceVar] == HFInvMassFitter::DoubleGausSigmaRatioPar) { + const Double_t fracDoubleGaus = massFitter->getFracDoubleGaus(); + const Double_t fracDoubleGausErr = massFitter->getFracDoubleGausUncertainty(); + hRawYieldsFracDoubleGaus->SetBinContent(iSliceVar + 1, fracDoubleGaus); + hRawYieldsFracDoubleGaus->SetBinError(iSliceVar + 1, fracDoubleGausErr); + } } else { HFInvMassFitter* massFitter; - massFitter = new HFInvMassFitter(hMassForFit[iPt], massMin[iPt], massMax[iPt], - bkgFunc[iPt], sgnFunc[iPt]); + massFitter = new HFInvMassFitter(hMassForFit[iSliceVar], massMin[iSliceVar], massMax[iSliceVar], + bkgFunc[iSliceVar], sgnFunc[iSliceVar]); + massFitter->setDrawBgPrefit(drawBgPrefit); + massFitter->setHighlightPeakRegion(highlightPeakRegion); + massFitter->setInitialGaussianMean(massPDG); + massFitter->setParticlePdgMass(massPDG); + massFitter->setBoundGaussianMean(massPDG, 0.8 * massPDG, 1.2 * massPDG); if (useLikelihood) { massFitter->setUseLikelihoodFit(); } - if (fixMean) { - massFitter->setFixGaussianMean(hMeanToFix->GetBinContent(iPt + 1)); - } - if (fixSigma) { - if (fixSigmaManual.empty()) { - massFitter->setFixGaussianSigma(hSigmaToFix->GetBinContent(iPt + 1)); - cout << "*****************************" - << "\n" - << "FIXED SIGMA: " << hSigmaToFix->GetBinContent(iPt + 1) << "\n" - << "*****************************" << endl; - } else if (!fixSigmaManual.empty()) { - massFitter->setFixGaussianSigma(fixSigmaManual[iPt]); - cout << "*****************************" - << "\n" - << "FIXED SIGMA: " << fixSigmaManual[iPt] << "\n" - << "*****************************" << endl; - } else { - cout << "WARNING: impossible to fix sigma! Wrong fix sigma file or value!" << endl; + + auto setFixedValue = [&iSliceVar](bool const& isFix, std::vector const& fixManual, const TH1* histToFix, std::function setFunc, std::string const& var) -> void { + if (isFix) { + if (fixManual.empty()) { + setFunc(histToFix->GetBinContent(iSliceVar + 1)); + printf("*****************************\n"); + printf("FIXED %s: %f\n", var.data(), histToFix->GetBinContent(iSliceVar + 1)); + printf("*****************************\n"); + } else { + setFunc(fixManual[iSliceVar]); + printf("*****************************\n"); + printf("FIXED %s: %f\n", var.data(), fixManual[iSliceVar]); + printf("*****************************\n"); + } } - } + }; + + setFixedValue(fixMean, fixMeanManual, hMeanToFix, std::bind(&HFInvMassFitter::setFixGaussianMean, massFitter, std::placeholders::_1), "MEAN"); + setFixedValue(fixSigma, fixSigmaManual, hSigmaToFix, std::bind(&HFInvMassFitter::setFixGaussianSigma, massFitter, std::placeholders::_1), "SIGMA"); + setFixedValue(fixSecondSigma, fixSecondSigmaManual, hSecondSigmaToFix, std::bind(&HFInvMassFitter::setFixSecondGaussianSigma, massFitter, std::placeholders::_1), "SECOND SIGMA"); + setFixedValue(fixFracDoubleGaus, fixFracDoubleGausManual, hFracDoubleGausToFix, std::bind(&HFInvMassFitter::setFixFrac2Gaus, massFitter, std::placeholders::_1), "FRAC DOUBLE GAUS"); if (enableRefl) { - reflOverSgn = hMassForSgn[iPt]->Integral(hMassForSgn[iPt]->FindBin(massMin[iPt] * 1.0001), hMassForSgn[iPt]->FindBin(massMax[iPt] * 0.999)); - reflOverSgn = hMassForRefl[iPt]->Integral(hMassForRefl[iPt]->FindBin(massMin[iPt] * 1.0001), hMassForRefl[iPt]->FindBin(massMax[iPt] * 0.999)) / reflOverSgn; + reflOverSgn = hMassForSgn[iSliceVar]->Integral(hMassForSgn[iSliceVar]->FindBin(massMin[iSliceVar] * 1.0001), hMassForSgn[iSliceVar]->FindBin(massMax[iSliceVar] * 0.999)); + reflOverSgn = hMassForRefl[iSliceVar]->Integral(hMassForRefl[iSliceVar]->FindBin(massMin[iSliceVar] * 1.0001), hMassForRefl[iSliceVar]->FindBin(massMax[iSliceVar] * 0.999)) / reflOverSgn; massFitter->setFixReflOverSgn(reflOverSgn); - massFitter->setTemplateReflections(hMassRefl[iPt], HFInvMassFitter::DoubleGaus); + massFitter->setTemplateReflections(hMassRefl[iSliceVar]); } - massFitter->doFit(false); - - double rawYield = massFitter->getRawYield(); - double rawYieldErr = massFitter->getRawYieldError(); - double sigma = massFitter->getSigma(); - double sigmaErr = massFitter->getSigmaUncertainty(); - double mean = massFitter->getMean(); - double meanErr = massFitter->getMeanUncertainty(); - double reducedChiSquare = massFitter->getChiSquareOverNDF(); - double significance = massFitter->getSignificance(); - double significanceErr = massFitter->getSignificanceError(); - double bkg = massFitter->getBkgYield(); - double bkgErr = massFitter->getBkgYieldError(); - - hRawYields->SetBinContent(iPt + 1, rawYield); - hRawYields->SetBinError(iPt + 1, rawYieldErr); - hRawYieldsSigma->SetBinContent(iPt + 1, sigma); - hRawYieldsSigma->SetBinError(iPt + 1, sigmaErr); - hRawYieldsMean->SetBinContent(iPt + 1, mean); - hRawYieldsMean->SetBinError(iPt + 1, meanErr); - hRawYieldsSignificance->SetBinContent(iPt + 1, significance); - hRawYieldsSignificance->SetBinError(iPt + 1, significanceErr); - hRawYieldsSgnOverBkg->SetBinContent(iPt + 1, rawYield / bkg); - hRawYieldsSgnOverBkg->SetBinError(iPt + 1, rawYield / bkg * std::sqrt(rawYieldErr / rawYield * rawYieldErr / rawYield + bkgErr / bkg * bkgErr / bkg)); - hRawYieldsSignal->SetBinContent(iPt + 1, rawYield); - hRawYieldsSignal->SetBinError(iPt + 1, rawYieldErr); - hRawYieldsBkg->SetBinContent(iPt + 1, bkg); - hRawYieldsBkg->SetBinError(iPt + 1, bkgErr); - hRawYieldsChiSquare->SetBinContent(iPt + 1, reducedChiSquare); - hRawYieldsChiSquare->SetBinError(iPt + 1, 1.e-20); - if (enableRefl) { - hReflectionOverSignal->SetBinContent(iPt + 1, reflOverSgn); + massFitter->doFit(); + + const double rawYield = massFitter->getRawYield(); + const double rawYieldErr = massFitter->getRawYieldError(); + const double rawYieldCounted = massFitter->getRawYieldCounted(); + const double rawYieldCountedErr = massFitter->getRawYieldCountedError(); + const double bkg = massFitter->getBkgYield(); + const double bkgErr = massFitter->getBkgYieldError(); + const double significance = massFitter->getSignificance(); + const double significanceErr = massFitter->getSignificanceError(); + const double reducedChiSquareBkg = massFitter->getChiSquareOverNDFBkg(); + const double reducedChiSquareTotal = massFitter->getChiSquareOverNDFTotal(); + const double mean = massFitter->getMean(); + const double meanErr = massFitter->getMeanUncertainty(); + const double sigma = massFitter->getSigma(); + const double sigmaErr = massFitter->getSigmaUncertainty(); + + hRawYieldsSignal->SetBinContent(iSliceVar + 1, rawYield); + hRawYieldsSignal->SetBinError(iSliceVar + 1, rawYieldErr); + hRawYieldsSignalCounted->SetBinContent(iSliceVar + 1, rawYieldCounted); + hRawYieldsSignalCounted->SetBinError(iSliceVar + 1, rawYieldCountedErr); + hRawYieldsBkg->SetBinContent(iSliceVar + 1, bkg); + hRawYieldsBkg->SetBinError(iSliceVar + 1, bkgErr); + hRawYieldsSgnOverBkg->SetBinContent(iSliceVar + 1, rawYield / bkg); + hRawYieldsSgnOverBkg->SetBinError(iSliceVar + 1, rawYield / bkg * std::sqrt(rawYieldErr / rawYield * rawYieldErr / rawYield + bkgErr / bkg * bkgErr / bkg)); + hRawYieldsSignificance->SetBinContent(iSliceVar + 1, significance); + hRawYieldsSignificance->SetBinError(iSliceVar + 1, significanceErr); + hRawYieldsChiSquareBkg->SetBinContent(iSliceVar + 1, reducedChiSquareBkg); + hRawYieldsChiSquareBkg->SetBinError(iSliceVar + 1, 1.e-20); + hRawYieldsChiSquareTotal->SetBinContent(iSliceVar + 1, reducedChiSquareTotal); + hRawYieldsChiSquareTotal->SetBinError(iSliceVar + 1, 1.e-20); + hRawYieldsMean->SetBinContent(iSliceVar + 1, mean); + hRawYieldsMean->SetBinError(iSliceVar + 1, meanErr); + hRawYieldsSigma->SetBinContent(iSliceVar + 1, sigma); + hRawYieldsSigma->SetBinError(iSliceVar + 1, sigmaErr); + + if (sgnFunc[iSliceVar] != HFInvMassFitter::SingleGaus) { + const double secSigma = massFitter->getSecSigma(); + const double secSigmaErr = massFitter->getSecSigmaUncertainty(); + hRawYieldsSecSigma->SetBinContent(iSliceVar + 1, secSigma); + hRawYieldsSecSigma->SetBinError(iSliceVar + 1, secSigmaErr); + } + if (sgnFunc[iSliceVar] == HFInvMassFitter::DoubleGaus || sgnFunc[iSliceVar] == HFInvMassFitter::DoubleGausSigmaRatioPar) { + const double fracDoubleGaus = massFitter->getFracDoubleGaus(); + const double fracDoubleGausErr = massFitter->getFracDoubleGausUncertainty(); + hRawYieldsFracDoubleGaus->SetBinContent(iSliceVar + 1, fracDoubleGaus); + hRawYieldsFracDoubleGaus->SetBinError(iSliceVar + 1, fracDoubleGausErr); } if (enableRefl) { - if (nPtBins > 1) { - canvasRefl[iCanvas]->cd(iPt - nCanvasesMax * iCanvas + 1); + hReflectionOverSignal->SetBinContent(iSliceVar + 1, reflOverSgn); + if (nSliceVarBins > 1) { + canvasRefl[iCanvas]->cd(iSliceVar - nCanvasesMax * iCanvas + 1); } else { canvasRefl[iCanvas]->cd(); } @@ -562,37 +550,48 @@ int runMassFitter(TString configFileName) canvasRefl[iCanvas]->Update(); } - if (nPtBins > 1) { - canvasMass[iCanvas]->cd(iPt - nCanvasesMax * iCanvas + 1); + if (nSliceVarBins > 1) { + canvasMass[iCanvas]->cd(iSliceVar - nCanvasesMax * iCanvas + 1); } else { canvasMass[iCanvas]->cd(); } - massFitter->drawFit(gPad); + massFitter->drawFit(gPad, plotLabels, writeSignalPar); canvasMass[iCanvas]->Modified(); canvasMass[iCanvas]->Update(); - if (nPtBins > 1) { - canvasResiduals[iCanvas]->cd(iPt - nCanvasesMax * iCanvas + 1); - } else { - canvasResiduals[iCanvas]->cd(); + if (bkgFunc[iSliceVar] != HFInvMassFitter::NoBkg) { + if (nSliceVarBins > 1) { + canvasResiduals[iCanvas]->cd(iSliceVar - nCanvasesMax * iCanvas + 1); + } else { + canvasResiduals[iCanvas]->cd(); + } + massFitter->drawResidual(gPad); + canvasResiduals[iCanvas]->Modified(); + canvasResiduals[iCanvas]->Update(); + + if (nSliceVarBins > 1) { + canvasRatio[iCanvas]->cd(iSliceVar - nCanvasesMax * iCanvas + 1); + } else { + canvasRatio[iCanvas]->cd(); + } + massFitter->drawRatio(gPad); + canvasRatio[iCanvas]->Modified(); + canvasRatio[iCanvas]->Update(); } - massFitter->drawResidual(gPad); - canvasResiduals[iCanvas]->Modified(); - canvasResiduals[iCanvas]->Update(); } - hFitConfig->SetBinContent(1, iPt + 1, massMin[iPt]); - hFitConfig->SetBinContent(2, iPt + 1, massMax[iPt]); - hFitConfig->SetBinContent(3, iPt + 1, nRebin[iPt]); + hFitConfig->SetBinContent(1, iSliceVar + 1, massMin[iSliceVar]); + hFitConfig->SetBinContent(2, iSliceVar + 1, massMax[iSliceVar]); + hFitConfig->SetBinContent(3, iSliceVar + 1, nRebin[iSliceVar]); if (fixSigma) { if (fixSigmaManual.empty()) { - hFitConfig->SetBinContent(4, iPt + 1, hSigmaToFix->GetBinContent(iPt + 1)); + hFitConfig->SetBinContent(4, iSliceVar + 1, hSigmaToFix->GetBinContent(iSliceVar + 1)); } else { - hFitConfig->SetBinContent(4, iPt + 1, fixSigmaManual[iPt]); + hFitConfig->SetBinContent(4, iSliceVar + 1, fixSigmaManual[iSliceVar]); } } - hFitConfig->SetBinContent(5, iPt + 1, bkgFuncConfig[iPt]); - hFitConfig->SetBinContent(6, iPt + 1, sgnFuncConfig[iPt]); + hFitConfig->SetBinContent(5, iSliceVar + 1, bkgFuncConfig[iSliceVar]); + hFitConfig->SetBinContent(6, iSliceVar + 1, sgnFuncConfig[iSliceVar]); } // save output histograms @@ -601,31 +600,30 @@ int runMassFitter(TString configFileName) canvasMass[iCanvas]->Write(); if (!isMc) { canvasResiduals[iCanvas]->Write(); - canvasRefl[iCanvas]->Write(); + canvasRatio[iCanvas]->Write(); + if (enableRefl) { + canvasRefl[iCanvas]->Write(); + } } } - for (unsigned int iPt = 0; iPt < nPtBins; iPt++) { - hMass[iPt]->Write(); + for (unsigned int iSliceVar = 0; iSliceVar < nSliceVarBins; iSliceVar++) { + hMass[iSliceVar]->Write(); } - hRawYields->Write(); - hRawYieldsSigma->Write(); - hRawYieldsMean->Write(); - hRawYieldsSignificance->Write(); - hRawYieldsSgnOverBkg->Write(); hRawYieldsSignal->Write(); + hRawYieldsSignalCounted->Write(); hRawYieldsBkg->Write(); - hRawYieldsChiSquare->Write(); - hRawYieldsSigma2->Write(); - hRawYieldsFracGaus2->Write(); - hRawYieldsSecondPeak->Write(); - hRawYieldsMeanSecondPeak->Write(); - hRawYieldsSigmaSecondPeak->Write(); - hRawYieldsSignificanceSecondPeak->Write(); - hRawYieldsSigmaRatioSecondFirstPeak->Write(); - hRawYieldsSoverBSecondPeak->Write(); - hRawYieldsSignalSecondPeak->Write(); - hRawYieldsBkgSecondPeak->Write(); + hRawYieldsSgnOverBkg->Write(); + hRawYieldsSignificance->Write(); + hRawYieldsChiSquareBkg->Write(); + hRawYieldsChiSquareTotal->Write(); + hRawYieldsMean->Write(); + hRawYieldsSigma->Write(); + hRawYieldsSecSigma->Write(); + hRawYieldsFracDoubleGaus->Write(); + if (enableRefl) { + hReflectionOverSignal->Write(); + } hFitConfig->Write(); outputFile.Close(); @@ -633,6 +631,8 @@ int runMassFitter(TString configFileName) outputFileName.ReplaceAll(".root", ".pdf"); TString outputFileNameResidual = outputFileName; outputFileNameResidual.ReplaceAll(".pdf", "_Residuals.pdf"); + TString outputFileRatio = outputFileName; + outputFileRatio.ReplaceAll(".pdf", "_Ratio.pdf"); for (int iCanvas = 0; iCanvas < nCanvases; iCanvas++) { if (iCanvas == 0 && nCanvases > 1) { canvasMass[iCanvas]->SaveAs(Form("%s[", outputFileName.Data())); @@ -642,6 +642,7 @@ int runMassFitter(TString configFileName) canvasMass[iCanvas]->SaveAs(Form("%s]", outputFileName.Data())); } if (!isMc) { + // residuals if (iCanvas == 0 && nCanvases > 1) { canvasResiduals[iCanvas]->SaveAs(Form("%s[", outputFileNameResidual.Data())); } @@ -649,12 +650,20 @@ int runMassFitter(TString configFileName) if (iCanvas == nCanvases - 1 && nCanvases > 1) { canvasResiduals[iCanvas]->SaveAs(Form("%s]", outputFileNameResidual.Data())); } + // ratio + if (iCanvas == 0 && nCanvases > 1) { + canvasRatio[iCanvas]->SaveAs(Form("%s[", outputFileRatio.Data())); + } + canvasRatio[iCanvas]->SaveAs(outputFileRatio.Data()); + if (iCanvas == nCanvases - 1 && nCanvases > 1) { + canvasRatio[iCanvas]->SaveAs(Form("%s]", outputFileRatio.Data())); + } } } return 0; } -void setHistoStyle(TH1* histo, int color, double markerSize) +void setHistoStyle(TH1* histo, Color_t color, Size_t markerSize) { histo->SetStats(kFALSE); histo->SetMarkerSize(markerSize); @@ -664,33 +673,22 @@ void setHistoStyle(TH1* histo, int color, double markerSize) histo->SetLineColor(color); } -void divideCanvas(TCanvas* canvas, int nPtBins) +void divideCanvas(TCanvas* canvas, int nSliceVarBins) +{ + int nCols = std::ceil(std::sqrt(nSliceVarBins)); + int nRows = std::ceil(static_cast(nSliceVarBins) / nCols); + canvas->Divide(nCols, nRows); +} + +int main(int argc, const char* argv[]) { - if (nPtBins < 2) { - canvas->cd(); - } else if (nPtBins == 2 || nPtBins == 3) { - canvas->Divide(nPtBins, 1); - } else if (nPtBins == 4 || nPtBins == 6 || nPtBins == 8) { - canvas->Divide(nPtBins / 2, 2); - } else if (nPtBins == 5 || nPtBins == 7) { - canvas->Divide((nPtBins + 1) / 2, 2); - } else if (nPtBins == 9 || nPtBins == 12 || nPtBins == 15) { - canvas->Divide(nPtBins / 3, 3); - } else if (nPtBins == 10 || nPtBins == 11) { - canvas->Divide(4, 3); - } else if (nPtBins == 13 || nPtBins == 14) { - canvas->Divide(5, 3); - } else if (nPtBins > 15 && nPtBins <= 20 && nPtBins % 4 == 0) { - canvas->Divide(nPtBins / 4, 4); - } else if (nPtBins > 15 && nPtBins <= 20 && nPtBins % 4 != 0) { - canvas->Divide(5, 4); - } else if (nPtBins == 21) { - canvas->Divide(7, 3); - } else if (nPtBins > 21 && nPtBins <= 25) { - canvas->Divide(5, 5); - } else if (nPtBins > 25 && nPtBins % 2 == 0) { - canvas->Divide(nPtBins / 2, 2); - } else { - canvas->Divide((nPtBins + 1) / 2, 2); + if (argc == 1) { + throw std::runtime_error("Not enough arguments. Please use\n./runMassFitter configFileName"); } + + const std::string configFileName = argv[1]; + + runMassFitter(configFileName); + + return 0; } diff --git a/PWGHF/D2H/TableProducer/CMakeLists.txt b/PWGHF/D2H/TableProducer/CMakeLists.txt index 3579b44cc6e..a60ab1d78ab 100644 --- a/PWGHF/D2H/TableProducer/CMakeLists.txt +++ b/PWGHF/D2H/TableProducer/CMakeLists.txt @@ -11,6 +11,11 @@ # Candidate creators +o2physics_add_dpl_workflow(candidate-creator-b-to-jpsi-reduced + SOURCES candidateCreatorBToJpsiReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(candidate-creator-b0-reduced SOURCES candidateCreatorB0Reduced.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter @@ -21,11 +26,21 @@ 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 COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(candidate-creator-lb-reduced + SOURCES candidateCreatorLbReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter + COMPONENT_NAME Analysis) + # Candidate selectors o2physics_add_dpl_workflow(candidate-selector-b0-to-d-pi-reduced @@ -38,6 +53,16 @@ o2physics_add_dpl_workflow(candidate-selector-bplus-to-d0-pi-reduced 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) + +o2physics_add_dpl_workflow(candidate-selector-lb-to-lc-pi-reduced + SOURCES candidateSelectorLbToLcPiReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + # Data creators o2physics_add_dpl_workflow(data-creator-charm-had-pi-reduced @@ -50,3 +75,19 @@ o2physics_add_dpl_workflow(data-creator-charm-reso-reduced PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(data-creator-jpsi-had-reduced + SOURCES dataCreatorJpsiHadReduced.cxx + 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) + + o2physics_add_dpl_workflow(converter-reduced-hadron-daus-pid + SOURCES converterReducedHadronDausPid.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGHF/D2H/TableProducer/candidateCreatorB0Reduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorB0Reduced.cxx index 383ca9c42b1..49cff73feea 100644 --- a/PWGHF/D2H/TableProducer/candidateCreatorB0Reduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateCreatorB0Reduced.cxx @@ -15,19 +15,33 @@ /// \author Alexandre Bigot , IPHC Strasbourg /// \author Fabrizio Grosa , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" +#include "Common/Core/RecoDecay.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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -37,9 +51,11 @@ using namespace o2::hf_trkcandsel; /// Reconstruction of B0 candidates struct HfCandidateCreatorB0Reduced { - Produces rowCandidateBase; // table defined in CandidateReconstructionTables.h - Produces rowCandidateProngs; // table defined in ReducedDataModel.h - Produces rowCandidateDmesMlScores; // table defined in ReducedDataModel.h + Produces rowCandidateBase; // table defined in CandidateReconstructionTables.h + Produces rowCandidateB0DStar; // table defined in CandidateReconstructionTables.h + Produces rowCandidateProngs; // table defined in ReducedDataModel.h + Produces rowCandidateProngsDStar; // table defined in ReducedDataModel.h + Produces rowCandidateDmesMlScores; // table defined in ReducedDataModel.h // vertexing Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -53,17 +69,18 @@ struct HfCandidateCreatorB0Reduced { Configurable invMassWindowDPiTolerance{"invMassWindowDPiTolerance", 0.01, "invariant-mass window tolerance for DPi pair preselections (GeV/c2)"}; float myInvMassWindowDPi{1.}; // variable that will store the value of invMassWindowDPi (defined in dataCreatorDplusPiReduced.cxx) - float massPi{0.}; - float massD{0.}; - float massB0{0.}; float bz{0.}; - o2::vertexing::DCAFitterN<2> df2; // fitter for B vertex (2-prong vertex fitter) + o2::vertexing::DCAFitterN<2> df2; // fitter for B vertex (2-prong vertex fitter for DpPi candidates) + o2::vertexing::DCAFitterN<3> df3; // fitter for B vertex (3-prong vertex fitter for DstarPi candidates) using HfRedCollisionsWithExtras = soa::Join; + using HfSoftPiWCovAndPid = soa::Join; - Preslice> candsDPerCollision = hf_track_index_reduced::hfRedCollisionId; - Preslice> candsDWithMlPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> candsDplusPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> candsDplusWithMlPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> candsDstarPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> candsDstarWithMlPerCollision = hf_track_index_reduced::hfRedCollisionId; Preslice> tracksPionPerCollision = hf_track_index_reduced::hfRedCollisionId; std::shared_ptr hCandidates; @@ -71,16 +88,11 @@ struct HfCandidateCreatorB0Reduced { void init(InitContext const&) { - std::array doprocess{doprocessData, doprocessDataWithDmesMl}; + std::array doprocess{doprocessDataDplusPi, doprocessDataDplusPiWithDmesMl, doprocessDataDstarPi, doprocessDataDstarPiWithDmesMl}; 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; - massD = o2::constants::physics::MassDMinus; - massB0 = o2::constants::physics::MassB0; - // Initialize fitter df2.setPropagateToPCA(propagateToPCA); df2.setMaxR(maxR); @@ -90,8 +102,20 @@ struct HfCandidateCreatorB0Reduced { 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); + // histograms - registry.add("hMassB0ToDPi", "2-prong candidates;inv. mass (B^{0} #rightarrow D^{#minus}#pi^{#plus} #rightarrow #pi^{#minus}K^{#plus}#pi^{#minus}#pi^{#plus}) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 3., 8.}}}); + if (doprocessDataDplusPi || doprocessDataDplusPiWithDmesMl) { + registry.add("hMassB0ToDPi", "2-prong candidates;inv. mass (B^{0} #rightarrow D^{#minus}#pi^{#plus} #rightarrow #pi^{#minus}K^{#plus}#pi^{#minus}#pi^{#plus}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 3., 8.}}}); + } else if (doprocessDataDstarPi || doprocessDataDstarPiWithDmesMl) { + registry.add("hMassB0ToDPi", "3-prong candidates;inv. mass (B^{0} #rightarrow D^{0}#pi^{#plus}#pi^{#plus} #rightarrow #pi^{#minus}K^{#plus}#pi^{#minus}#pi^{#plus}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{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}}); @@ -108,12 +132,124 @@ struct HfCandidateCreatorB0Reduced { /// \param tracksPionThisCollision pion tracks in this collision /// \param invMass2DPiMin minimum B0 invariant-mass /// \param invMass2DPiMax maximum B0 invariant-mass - template + template + void runCandidateCreationDStar(Coll const& collision, + Cands const& candsDThisColl, + SoftPions const& softPions, + 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(); + df3.setBz(bz); + + for (const auto& candD : candsDThisColl) { + auto trackParCovD = getTrackParCov(candD); + std::array pVecD0 = candD.pVector(); + auto trackSoftPion = softPions.rawIteratorAt(candD.globalIndex()); + std::array pVecSoftPion = trackSoftPion.pVector(); + auto trackParCovSoftPi = getTrackParCov(trackSoftPion); + + for (const auto& trackBachPion : tracksPionThisCollision) { + // this track is among daughters + if (trackBachPion.trackId() == candD.prong0Id() || trackBachPion.trackId() == candD.prong1Id() || trackBachPion.trackId() == trackSoftPion.trackId()) { + continue; + } + + auto trackParCovPi = getTrackParCov(trackBachPion); + std::array pVecBachPion = trackBachPion.pVector(); + + // compute invariant mass square and apply selection + auto invMass2DPi = RecoDecay::m2(std::array{pVecD0, pVecSoftPion, pVecBachPion}, std::array{o2::constants::physics::MassD0, o2::constants::physics::MassPiPlus, o2::constants::physics::MassPiPlus}); + if ((invMass2DPi < invMass2DPiMin) || (invMass2DPi > invMass2DPiMax)) { + continue; + } + + // --------------------------------- + // reconstruct the 3-prong B0 vertex + hCandidates->Fill(SVFitting::BeforeFit); + try { + if (df3.process(trackParCovD, trackParCovSoftPi, 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); + + // DPi passed B0 reconstruction + + // calculate relevant properties + const auto& secondaryVertexB0 = df3.getPCACandidate(); + auto chi2PCA = df3.getChi2AtPCACandidate(); + auto covMatrixPCA = df3.calcPCACovMatrixFlat(); + registry.fill(HIST("hCovSVXX"), covMatrixPCA[0]); + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + + // propagate D and Pi to the B0 vertex + df3.propagateTracksToVertex(); + // track.getPxPyPzGlo(pVec) modifies pVec of track + df3.getTrack(0).getPxPyPzGlo(pVecD0); // momentum of D at the B0 vertex + df3.getTrack(1).getPxPyPzGlo(pVecSoftPion); // momentum of SoftPi at the B0 vertex + df3.getTrack(2).getPxPyPzGlo(pVecBachPion); // momentum of Pi at the B0 vertex + + registry.fill(HIST("hMassB0ToDPi"), std::sqrt(invMass2DPi)); + + // compute impact parameters of D and Pi + o2::dataformats::DCA dcaD; + o2::dataformats::DCA dcaSoftPion; + o2::dataformats::DCA dcaBachPion; + trackParCovD.propagateToDCA(primaryVertex, bz, &dcaD); + trackParCovSoftPi.propagateToDCA(primaryVertex, bz, &dcaSoftPion); + trackParCovPi.propagateToDCA(primaryVertex, bz, &dcaBachPion); + + // get uncertainty of the decay length + float phi, theta; + // getPointDirection modifies phi and theta + getPointDirection(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertexB0, 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 B0 here: + rowCandidateB0DStar(collision.globalIndex(), + collision.posX(), collision.posY(), collision.posZ(), + secondaryVertexB0[0], secondaryVertexB0[1], secondaryVertexB0[2], + errorDecayLength, errorDecayLengthXY, + chi2PCA, + pVecD0[0], pVecD0[1], pVecD0[2], + pVecSoftPion[0], pVecSoftPion[1], pVecSoftPion[2], + pVecBachPion[0], pVecBachPion[1], pVecBachPion[2], + dcaD.getY(), dcaSoftPion.getY(), dcaBachPion.getY(), + std::sqrt(dcaD.getSigmaY2()), std::sqrt(dcaSoftPion.getSigmaY2()), std::sqrt(dcaBachPion.getSigmaY2())); + + rowCandidateProngsDStar(candD.globalIndex(), trackBachPion.globalIndex(), trackSoftPion.globalIndex()); + + if constexpr (WithDmesMl) { + rowCandidateDmesMlScores(candD.mlScoreBkgMassHypo0(), candD.mlScorePromptMassHypo0(), candD.mlScoreNonpromptMassHypo0()); + } + } // pi loop + } // D loop + } + + /// Main function to perform B0 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 collision the collision + /// \param candsDThisColl B0 candidates in this collision + /// \param tracksPionThisCollision pion tracks in this collision + /// \param invMass2DPiMin minimum B0 invariant-mass + /// \param invMass2DPiMax maximum B0 invariant-mass + template void runCandidateCreation(Coll const& collision, Cands const& candsDThisColl, Pions const& tracksPionThisCollision, - const float& invMass2DPiMin, - const float& invMass2DPiMax) + const float invMass2DPiMin, + const float invMass2DPiMax) { auto primaryVertex = getPrimaryVertex(collision); auto covMatrixPV = primaryVertex.getCov(); @@ -136,7 +272,7 @@ struct HfCandidateCreatorB0Reduced { std::array pVecPion = trackPion.pVector(); // compute invariant mass square and apply selection - auto invMass2DPi = RecoDecay::m2(std::array{pVecD, pVecPion}, std::array{massD, massPi}); + auto invMass2DPi = RecoDecay::m2(std::array{pVecD, pVecPion}, std::array{o2::constants::physics::MassDMinus, o2::constants::physics::MassPiPlus}); if ((invMass2DPi < invMass2DPiMin) || (invMass2DPi > invMass2DPiMax)) { continue; } @@ -197,18 +333,18 @@ struct HfCandidateCreatorB0Reduced { rowCandidateProngs(candD.globalIndex(), trackPion.globalIndex()); - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { rowCandidateDmesMlScores(candD.mlScoreBkgMassHypo0(), candD.mlScorePromptMassHypo0(), candD.mlScoreNonpromptMassHypo0()); } } // pi loop - } // D loop + } // D loop } - void processData(HfRedCollisionsWithExtras const& collisions, - soa::Join const& candsD, - soa::Join const& tracksPion, - aod::HfOrigColCounts const& collisionsCounter, - aod::HfCandB0Configs const& configs) + void processDataDplusPi(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsD, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandB0Configs const& configs) { // DPi invariant-mass window cut for (const auto& config : configs) { @@ -216,8 +352,8 @@ struct HfCandidateCreatorB0Reduced { } // invMassWindowDPiTolerance is used to apply a slightly tighter cut than in DPi pair preselection // to avoid accepting DPi pairs that were not formed in DPi pair creator - float invMass2DPiMin = (massB0 - myInvMassWindowDPi + invMassWindowDPiTolerance) * (massB0 - myInvMassWindowDPi + invMassWindowDPiTolerance); - float invMass2DPiMax = (massB0 + myInvMassWindowDPi - invMassWindowDPiTolerance) * (massB0 + myInvMassWindowDPi - invMassWindowDPiTolerance); + float const invMass2DPiMin = (o2::constants::physics::MassB0 - myInvMassWindowDPi + invMassWindowDPiTolerance) * (o2::constants::physics::MassB0 - myInvMassWindowDPi + invMassWindowDPiTolerance); + float const invMass2DPiMax = (o2::constants::physics::MassB0 + myInvMassWindowDPi - invMassWindowDPiTolerance) * (o2::constants::physics::MassB0 + myInvMassWindowDPi - invMassWindowDPiTolerance); for (const auto& collisionCounter : collisionsCounter) { registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); @@ -226,7 +362,7 @@ struct HfCandidateCreatorB0Reduced { static int ncol = 0; for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); - auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto candsDThisColl = candsD.sliceBy(candsDplusPerCollision, thisCollId); auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); runCandidateCreation(collision, candsDThisColl, tracksPionThisCollision, invMass2DPiMin, invMass2DPiMax); if (ncol % 10000 == 0) { @@ -234,15 +370,15 @@ struct HfCandidateCreatorB0Reduced { } ncol++; } - } // processData + } // processDataDplusPi - PROCESS_SWITCH(HfCandidateCreatorB0Reduced, processData, "Process data without any ML score", true); + PROCESS_SWITCH(HfCandidateCreatorB0Reduced, processDataDplusPi, "Process data D-pi without any ML score", true); - void processDataWithDmesMl(HfRedCollisionsWithExtras const& collisions, - soa::Join const& candsD, - soa::Join const& tracksPion, - aod::HfOrigColCounts const& collisionsCounter, - aod::HfCandB0Configs const& configs) + void processDataDplusPiWithDmesMl(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsD, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandB0Configs const& configs) { // DPi invariant-mass window cut for (const auto& config : configs) { @@ -250,8 +386,8 @@ struct HfCandidateCreatorB0Reduced { } // invMassWindowDPiTolerance is used to apply a slightly tighter cut than in DPi pair preselection // to avoid accepting DPi pairs that were not formed in DPi pair creator - float invMass2DPiMin = (massB0 - myInvMassWindowDPi + invMassWindowDPiTolerance) * (massB0 - myInvMassWindowDPi + invMassWindowDPiTolerance); - float invMass2DPiMax = (massB0 + myInvMassWindowDPi - invMassWindowDPiTolerance) * (massB0 + myInvMassWindowDPi - invMassWindowDPiTolerance); + float const invMass2DPiMin = (o2::constants::physics::MassB0 - myInvMassWindowDPi + invMassWindowDPiTolerance) * (o2::constants::physics::MassB0 - myInvMassWindowDPi + invMassWindowDPiTolerance); + float const invMass2DPiMax = (o2::constants::physics::MassB0 + myInvMassWindowDPi - invMassWindowDPiTolerance) * (o2::constants::physics::MassB0 + myInvMassWindowDPi - invMassWindowDPiTolerance); for (const auto& collisionCounter : collisionsCounter) { registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); @@ -260,7 +396,7 @@ struct HfCandidateCreatorB0Reduced { static int ncol = 0; for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); - auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); + auto candsDThisColl = candsD.sliceBy(candsDplusPerCollision, thisCollId); auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); runCandidateCreation(collision, candsDThisColl, tracksPionThisCollision, invMass2DPiMin, invMass2DPiMax); if (ncol % 10000 == 0) { @@ -268,14 +404,86 @@ struct HfCandidateCreatorB0Reduced { } ncol++; } - } // processDataWithDmesMl + } // processDataDplusPiWithDmesMl + + PROCESS_SWITCH(HfCandidateCreatorB0Reduced, processDataDplusPiWithDmesMl, "Process data D-pi with ML scores of D mesons", false); + + void processDataDstarPi(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsD, + HfSoftPiWCovAndPid const& softPions, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandB0Configs 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 DPi pair preselection + // to avoid accepting DPi pairs that were not formed in DPi pair creator + float const invMass2DPiMin = (o2::constants::physics::MassB0 - myInvMassWindowDPi + invMassWindowDPiTolerance) * (o2::constants::physics::MassB0 - myInvMassWindowDPi + invMassWindowDPiTolerance); + float const invMass2DPiMax = (o2::constants::physics::MassB0 + myInvMassWindowDPi - invMassWindowDPiTolerance) * (o2::constants::physics::MassB0 + 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(candsDstarPerCollision, thisCollId); + auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); + runCandidateCreationDStar(collision, candsDThisColl, softPions, tracksPionThisCollision, invMass2DPiMin, invMass2DPiMax); + if (ncol % 10000 == 0) { + LOGP(debug, "collisions parsed {}", ncol); + } + ncol++; + } + } // processDataDstarPi + + PROCESS_SWITCH(HfCandidateCreatorB0Reduced, processDataDstarPi, "Process data D*pi without any ML score", false); + + void processDataDstarPiWithDmesMl(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsD, + HfSoftPiWCovAndPid const& softPions, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandB0Configs 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 DPi pair preselection + // to avoid accepting DPi pairs that were not formed in DPi pair creator + float const invMass2DPiMin = (o2::constants::physics::MassB0 - myInvMassWindowDPi + invMassWindowDPiTolerance) * (o2::constants::physics::MassB0 - myInvMassWindowDPi + invMassWindowDPiTolerance); + float const invMass2DPiMax = (o2::constants::physics::MassB0 + myInvMassWindowDPi - invMassWindowDPiTolerance) * (o2::constants::physics::MassB0 + 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(candsDstarWithMlPerCollision, thisCollId); + auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); + runCandidateCreationDStar(collision, candsDThisColl, softPions, tracksPionThisCollision, invMass2DPiMin, invMass2DPiMax); + if (ncol % 10000 == 0) { + LOGP(debug, "collisions parsed {}", ncol); + } + ncol++; + } + } // processDataDstarPiWithDmesMl + + PROCESS_SWITCH(HfCandidateCreatorB0Reduced, processDataDstarPiWithDmesMl, "Process data D*pi with ML scores of D mesons", false); - PROCESS_SWITCH(HfCandidateCreatorB0Reduced, processDataWithDmesMl, "Process data with ML scores of D mesons", false); }; // struct /// Extends the table base with expression columns and performs MC matching. struct HfCandidateCreatorB0ReducedExpressions { Spawns rowCandidateB0; + Spawns rowCandidateB0DSt; Spawns rowTracksExt; Produces rowB0McRec; Produces rowB0McCheck; @@ -284,18 +492,24 @@ struct HfCandidateCreatorB0ReducedExpressions { /// \param checkDecayTypeMc /// \param rowsDPiMcRec MC reco information on DPi pairs /// \param candsB0 prong global indices of B0 candidates - template - void fillB0McRec(McRec const& rowsDPiMcRec, HfRedB0Prongs const& candsB0) + template + void fillB0McRec(McRec const& rowsDPiMcRec, B0Prongs const& candsB0) { for (const auto& candB0 : candsB0) { bool filledMcInfo{false}; for (const auto& rowDPiMcRec : rowsDPiMcRec) { - if ((rowDPiMcRec.prong0Id() != candB0.prong0Id()) || (rowDPiMcRec.prong1Id() != candB0.prong1Id())) { - continue; + if constexpr (std::is_same_v) { + if ((rowDPiMcRec.prong0Id() != candB0.prong0Id()) || (rowDPiMcRec.prong1Id() != candB0.prong1Id())) { + continue; + } + } else if constexpr (std::is_same_v) { // No need to check ID of soft pion, it is the same as D0 + if ((rowDPiMcRec.prongD0Id() != candB0.prongD0Id()) || (rowDPiMcRec.prongBachPiId() != candB0.prongBachPiId())) { + continue; + } } - rowB0McRec(rowDPiMcRec.flagMcMatchRec(), rowDPiMcRec.debugMcRec(), rowDPiMcRec.ptMother()); + rowB0McRec(rowDPiMcRec.flagMcMatchRec(), -1 /*channel*/, rowDPiMcRec.flagWrongCollision(), rowDPiMcRec.debugMcRec(), rowDPiMcRec.ptMother()); filledMcInfo = true; - if constexpr (checkDecayTypeMc) { + if constexpr (CheckDecayTypeMc) { rowB0McCheck(rowDPiMcRec.pdgCodeBeautyMother(), rowDPiMcRec.pdgCodeCharmMother(), rowDPiMcRec.pdgCodeProng0(), @@ -306,25 +520,37 @@ 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); - if constexpr (checkDecayTypeMc) { + rowB0McRec(0, -1, -1, -1, -1.f); + if constexpr (CheckDecayTypeMc) { rowB0McCheck(-1, -1, -1, -1, -1, -1); } } } } - void processMc(HfMcRecRedDpPis const& rowsDPiMcRec, HfRedB0Prongs const& candsB0) + void processMcDplusPi(HfMcRecRedDpPis const& rowsDPiMcRec, HfRedB0Prongs const& candsB0) + { + fillB0McRec(rowsDPiMcRec, candsB0); + } + PROCESS_SWITCH(HfCandidateCreatorB0ReducedExpressions, processMcDplusPi, "Process MC for DplusPi", false); + + void processMcDplusPiWithDecayTypeCheck(soa::Join const& rowsDPiMcRec, HfRedB0Prongs const& candsB0) + { + fillB0McRec(rowsDPiMcRec, candsB0); + } + PROCESS_SWITCH(HfCandidateCreatorB0ReducedExpressions, processMcDplusPiWithDecayTypeCheck, "Process MC with decay type checks for DplusPi", false); + + void processMcDstarPi(HfMcRecRedDStarPis const& rowsDPiMcRec, HfRedB0ProngDStars const& candsB0) { fillB0McRec(rowsDPiMcRec, candsB0); } - PROCESS_SWITCH(HfCandidateCreatorB0ReducedExpressions, processMc, "Process MC", false); + PROCESS_SWITCH(HfCandidateCreatorB0ReducedExpressions, processMcDstarPi, "Process MC for DstarPi", false); - void processMcWithDecayTypeCheck(soa::Join const& rowsDPiMcRec, HfRedB0Prongs const& candsB0) + void processMcDstarPiWithDecayTypeCheck(soa::Join const& rowsDPiMcRec, HfRedB0ProngDStars const& candsB0) { fillB0McRec(rowsDPiMcRec, candsB0); } - PROCESS_SWITCH(HfCandidateCreatorB0ReducedExpressions, processMcWithDecayTypeCheck, "Process MC with decay type checks", false); + PROCESS_SWITCH(HfCandidateCreatorB0ReducedExpressions, processMcDstarPiWithDecayTypeCheck, "Process MC with decay type checks for DstarPi", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/TableProducer/candidateCreatorBToJpsiReduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorBToJpsiReduced.cxx new file mode 100644 index 00000000000..444ee4b1afe --- /dev/null +++ b/PWGHF/D2H/TableProducer/candidateCreatorBToJpsiReduced.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. + +/// \file candidateCreatorBToJpsiReduced.cxx +/// \brief Reconstruction of B->J/Psi hadron candidates +/// +/// \author Fabrizio Chinu , Università degli Studi and INFN Torino +/// \author Fabrizio Grosa , CERN + +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_trkcandsel; + +enum DecayChannel : uint8_t { + B0ToJpsiK0Star = 0, + BplusToJpsiK, + BsToJpsiPhi +}; + +/// Reconstruction of B+ candidates +struct HfCandidateCreatorBToJpsiReduced { + Produces rowCandidateBpBase; // table defined in CandidateReconstructionTables.h + Produces rowCandidateBpProngs; // table defined in ReducedDataModel.h + Produces rowCandidateBsBase; // table defined in CandidateReconstructionTables.h + Produces rowCandidateBsProngs; // 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 B+ is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + + Configurable runJpsiToee{"runJpsiToee", false, "Run analysis for J/Psi to ee (debug)"}; + // selection + Configurable invMassWindowJpsiHadTolerance{"invMassWindowJpsiHadTolerance", 0.01, "invariant-mass window tolerance for J/Psi K pair preselections (GeV/c2)"}; + + float myInvMassWindowJpsiK{1.}, myInvMassWindowJpsiPhi{1.}; // variable that will store the value of invMassWindowJpsiK (defined in dataCreatorJpsiKReduced.cxx) + double massBplus{0.}, massBs{0.}; + double bz{0.}; + o2::vertexing::DCAFitterN<2> df2; // fitter for B vertex (2-prong vertex fitter) + o2::vertexing::DCAFitterN<3> df3; // fitter for B vertex (3-prong vertex fitter) + o2::vertexing::DCAFitterN<4> df4; // fitter for B vertex (4-prong vertex fitter) + + using HfRedCollisionsWithExtras = soa::Join; + + Preslice> candsJpsiPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> tracksLf0PerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice> tracksLf1PerCollision = hf_track_index_reduced::hfRedCollisionId; + + std::shared_ptr hCandidatesB, hCandidatesPhi; + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + // invariant-mass window cut + massBplus = o2::constants::physics::MassBPlus; + massBs = o2::constants::physics::MassBS; + + // Initialize fitters + df2.setPropagateToPCA(propagateToPCA); + df2.setMaxR(maxR); + df2.setMaxDZIni(maxDZIni); + df2.setMinParamChange(minParamChange); + df2.setMinRelChi2Change(minRelChi2Change); + df2.setUseAbsDCA(useAbsDCA); + df2.setWeightedFinalPCA(useWeightedFinalPCA); + df2.setMatCorrType(noMatCorr); + + df3.setPropagateToPCA(propagateToPCA); + df3.setMaxR(maxR); + df3.setMaxDZIni(maxDZIni); + df3.setMinParamChange(minParamChange); + df3.setMinRelChi2Change(minRelChi2Change); + df3.setUseAbsDCA(useAbsDCA); + df3.setWeightedFinalPCA(useWeightedFinalPCA); + df3.setMatCorrType(noMatCorr); + + df4.setPropagateToPCA(propagateToPCA); + df4.setMaxR(maxR); + df4.setMaxDZIni(maxDZIni); + df4.setMinParamChange(minParamChange); + df4.setMinRelChi2Change(minRelChi2Change); + df4.setUseAbsDCA(useAbsDCA); + df4.setWeightedFinalPCA(useWeightedFinalPCA); + df4.setMatCorrType(noMatCorr); + + // histograms + registry.add("hMassJpsi", "J/Psi mass;#it{M}_{#mu#mu} (GeV/#it{c}^{2});Counts", {HistType::kTH1F, {{600, 2.5, 3.7, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hMassBplusToJpsiK", "2-prong candidates;inv. mass (B^{+} #rightarrow #overline{D^{0}}#pi^{#plus} #rightarrow #pi^{#minus}K^{#plus}#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 + hCandidatesB = registry.add("hFitCandidatesJpsi", "candidates counter", {HistType::kTH1D, {axisCands}}); + hCandidatesPhi = registry.add("hFitCandidatesPhi", "candidates counter", {HistType::kTH1D, {axisCands}}); + setLabelHistoCands(hCandidatesB); + setLabelHistoCands(hCandidatesPhi); + } + + /// Main function to perform B+ candidate creation + /// \param collision the collision + /// \param candsJpsiThisColl J/Psi candidates in this collision + /// \param tracksLfThisCollisionArr LF tracks in this collision + /// \param invMass2JpsiHadMin minimum B invariant-mass + /// \param invMass2JpsiHadMax maximum B invariant-mass + template + void runCandidateCreation(Coll const& collision, + Cands const& candsJpsiThisColl, + TTracks0 const& tracksLfDau0ThisCollision, + TTracks1 const& tracksLfDau1ThisCollision, + const float invMass2JpsiHadMin, + const float invMass2JpsiHadMax) + { + auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + + // Set the magnetic field from ccdb + bz = collision.bz(); + df2.setBz(bz); + df3.setBz(bz); + df4.setBz(bz); + + for (const auto& candJpsi : candsJpsiThisColl) { + o2::track::TrackParametrizationWithError trackPosParCov( + candJpsi.xDauPos(), candJpsi.alphaDauPos(), {candJpsi.yDauPos(), candJpsi.zDauPos(), candJpsi.snpDauPos(), candJpsi.tglDauPos(), candJpsi.signed1PtDauPos()}, 1 /*Charge*/, 1 /*Muon*/); + o2::track::TrackParametrizationWithError trackNegParCov( + candJpsi.xDauNeg(), candJpsi.alphaDauNeg(), {candJpsi.yDauNeg(), candJpsi.zDauNeg(), candJpsi.snpDauNeg(), candJpsi.tglDauNeg(), candJpsi.signed1PtDauNeg()}, -1 /*Charge*/, 1 /*Muon*/); + + // --------------------------------- + // reconstruct J/Psi candidate + o2::track::TrackParCov trackParCovJpsi{}; + std::array pVecJpsi{}; + registry.fill(HIST("hFitCandidatesJpsi"), SVFitting::BeforeFit); + try { + if (df2.process(trackPosParCov, trackNegParCov) == 0) { + LOG(info) << "DCAFitterN failed to reconstruct J/Psi candidate, skipping the candidate."; + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + registry.fill(HIST("hFitCandidatesJpsi"), SVFitting::Fail); + continue; + } + registry.fill(HIST("hFitCandidatesJpsi"), SVFitting::FitOk); + + std::array pVecDauPos{candJpsi.pxDauPos(), candJpsi.pyDauPos(), candJpsi.pzDauPos()}; + std::array pVecDauNeg{candJpsi.pxDauNeg(), candJpsi.pyDauNeg(), candJpsi.pzDauNeg()}; + + df2.getTrack(0).getPxPyPzGlo(pVecDauPos); + df2.getTrack(1).getPxPyPzGlo(pVecDauNeg); + pVecJpsi = RecoDecay::pVec(pVecDauPos, pVecDauNeg); + trackParCovJpsi = df2.createParentTrackParCov(); + trackParCovJpsi.setAbsCharge(0); // to be sure + + float invMassJpsi{0.f}; + if (runJpsiToee) { + invMassJpsi = RecoDecay::m2(std::array{pVecDauPos, pVecDauNeg}, std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + } else { + invMassJpsi = RecoDecay::m2(std::array{pVecDauPos, pVecDauNeg}, std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon}); + } + invMassJpsi = std::sqrt(invMassJpsi); + registry.fill(HIST("hMassJpsi"), invMassJpsi); + + for (const auto& trackLf0 : tracksLfDau0ThisCollision) { + // this track is among daughters + if (trackLf0.trackId() == candJpsi.prongPosId() || trackLf0.trackId() == candJpsi.prongNegId()) { + continue; + } + auto trackParCovLf0 = getTrackParCov(trackLf0); + std::array pVecTrackLf0{}; + if constexpr (DecChannel == DecayChannel::BplusToJpsiK) { + // --------------------------------- + // reconstruct the 3-prong B+ vertex + hCandidatesB->Fill(SVFitting::BeforeFit); + try { + if (df3.process(trackPosParCov, trackNegParCov, trackParCovLf0) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + hCandidatesB->Fill(SVFitting::Fail); + continue; + } + hCandidatesB->Fill(SVFitting::FitOk); + // JpsiK passed B+ reconstruction + + // calculate relevant properties + const auto& secondaryVertexBplus = df3.getPCACandidate(); + auto chi2PCA = df3.getChi2AtPCACandidate(); + auto covMatrixPCA = df3.calcPCACovMatrixFlat(); + registry.fill(HIST("hCovSVXX"), covMatrixPCA[0]); + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + + // propagate Jpsi daugthers and K to the B+ vertex + df3.propagateTracksToVertex(); + // track.getPxPyPzGlo(pVec) modifies pVec of track + df3.getTrack(0).getPxPyPzGlo(pVecDauPos); // momentum of positive Jpsi daughter at the B+ vertex + df3.getTrack(1).getPxPyPzGlo(pVecDauNeg); // momentum of negative Jpsi daughter at the B+ vertex + df3.getTrack(2).getPxPyPzGlo(pVecTrackLf0); // momentum of K at the B+ vertex + + // compute invariant mass square and apply selection + auto invMass2JpsiK = RecoDecay::m2(std::array{pVecDauPos, pVecDauNeg, pVecTrackLf0}, std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus}); + if ((invMass2JpsiK < invMass2JpsiHadMin) || (invMass2JpsiK > invMass2JpsiHadMax)) { + continue; + } + registry.fill(HIST("hMassBplusToJpsiK"), std::sqrt(invMass2JpsiK)); + + // compute impact parameters of Jpsi and K + o2::dataformats::DCA dcaDauPos, dcaDauNeg, dcaKaon; + trackPosParCov.propagateToDCA(primaryVertex, bz, &dcaDauPos); + trackNegParCov.propagateToDCA(primaryVertex, bz, &dcaDauNeg); + trackParCovLf0.propagateToDCA(primaryVertex, bz, &dcaKaon); + + // 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: + rowCandidateBpBase(collision.globalIndex(), + collision.posX(), collision.posY(), collision.posZ(), + secondaryVertexBplus[0], secondaryVertexBplus[1], secondaryVertexBplus[2], + errorDecayLength, errorDecayLengthXY, + chi2PCA, + pVecDauPos[0], pVecDauPos[1], pVecDauPos[2], + pVecDauNeg[0], pVecDauNeg[1], pVecDauNeg[2], + pVecTrackLf0[0], pVecTrackLf0[1], pVecTrackLf0[2], + dcaDauPos.getY(), dcaDauNeg.getY(), dcaKaon.getY(), + std::sqrt(dcaDauPos.getSigmaY2()), std::sqrt(dcaDauNeg.getSigmaY2()), std::sqrt(dcaKaon.getSigmaY2())); + + rowCandidateBpProngs(candJpsi.globalIndex(), trackLf0.globalIndex()); + } else if constexpr (DecChannel == DecayChannel::BsToJpsiPhi) { + for (const auto& trackLf1 : tracksLfDau1ThisCollision) { + // this track is among daughters + if (trackLf1.trackId() == candJpsi.prongPosId() || trackLf1.trackId() == candJpsi.prongNegId()) { + continue; + } + auto trackParCovLf1 = getTrackParCov(trackLf1); + std::array pVecTrackLf1 = trackLf1.pVector(); + + // --------------------------------- + // reconstruct the 4-prong Bs vertex + hCandidatesB->Fill(SVFitting::BeforeFit); + try { + if (df4.process(trackPosParCov, trackNegParCov, trackParCovLf0, trackParCovLf1) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + hCandidatesB->Fill(SVFitting::Fail); + continue; + } + hCandidatesB->Fill(SVFitting::FitOk); + // passed Bs reconstruction + + // calculate relevant properties + const auto& secondaryVertexBs = df4.getPCACandidate(); + auto chi2PCA = df4.getChi2AtPCACandidate(); + auto covMatrixPCA = df4.calcPCACovMatrixFlat(); + registry.fill(HIST("hCovSVXX"), covMatrixPCA[0]); + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + + // propagate Jpsi and phi to the Bs vertex + df4.propagateTracksToVertex(); + // track.getPxPyPzGlo(pVec) modifies pVec of track + df4.getTrack(0).getPxPyPzGlo(pVecDauPos); // momentum of Jpsi at the B+ vertex + df4.getTrack(1).getPxPyPzGlo(pVecDauNeg); // momentum of Jpsi at the B+ vertex + df4.getTrack(2).getPxPyPzGlo(pVecTrackLf0); // momentum of K at the B+ vertex + df4.getTrack(3).getPxPyPzGlo(pVecTrackLf1); // momentum of K at the B+ vertex + + // compute invariant mass square and apply selection + auto invMass2JpsiPhi = RecoDecay::m2(std::array{pVecDauPos, pVecDauNeg, pVecTrackLf0, pVecTrackLf1}, std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}); + if ((invMass2JpsiPhi < invMass2JpsiHadMin) || (invMass2JpsiPhi > invMass2JpsiHadMax)) { + continue; + } + registry.fill(HIST("hMassBplusToJpsiK"), std::sqrt(invMass2JpsiPhi)); + + // compute impact parameters of Jpsi and K + o2::dataformats::DCA dcaDauPos, dcaDauNeg, dcaTrackLf0, dcaTrackLf1; + trackPosParCov.propagateToDCA(primaryVertex, bz, &dcaDauPos); + trackNegParCov.propagateToDCA(primaryVertex, bz, &dcaDauNeg); + trackParCovLf0.propagateToDCA(primaryVertex, bz, &dcaTrackLf0); + trackParCovLf1.propagateToDCA(primaryVertex, bz, &dcaTrackLf1); + + // get uncertainty of the decay length + double phi, theta; + // getPointDirection modifies phi and theta + getPointDirection(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertexBs, 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: + rowCandidateBsBase(collision.globalIndex(), + collision.posX(), collision.posY(), collision.posZ(), + secondaryVertexBs[0], secondaryVertexBs[1], secondaryVertexBs[2], + errorDecayLength, errorDecayLengthXY, + chi2PCA, + pVecDauPos[0], pVecDauPos[1], pVecDauPos[2], + pVecDauNeg[0], pVecDauNeg[1], pVecDauPos[2], + pVecTrackLf0[0], pVecTrackLf0[1], pVecTrackLf0[2], + pVecTrackLf1[0], pVecTrackLf1[1], pVecTrackLf0[2], + dcaDauPos.getY(), dcaDauNeg.getY(), dcaTrackLf0.getY(), dcaTrackLf1.getY(), + std::sqrt(dcaDauPos.getSigmaY2()), std::sqrt(dcaDauNeg.getSigmaY2()), std::sqrt(dcaTrackLf0.getSigmaY2()), std::sqrt(dcaTrackLf1.getSigmaY2())); + rowCandidateBsProngs(candJpsi.globalIndex(), trackLf0.globalIndex(), trackLf1.globalIndex()); + } + } + } // TrackLf0 loop + } // J/Psi loop + } // end runCandidateCreation + + void processDataBplus(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsJpsi, + soa::Join const& tracksKaon, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCfgBpToJpsi const& configs) + { + // Jpsi K invariant-mass window cut + for (const auto& config : configs) { + myInvMassWindowJpsiK = config.myInvMassWindowJpsiK(); + } + // invMassWindowJpsiHadTolerance is used to apply a slightly tighter cut than in JpsiK pair preselection + // to avoid accepting JpsiK pairs that were not formed in JpsiK pair creator + double const invMass2JpsiKMin = (massBplus - myInvMassWindowJpsiK + invMassWindowJpsiHadTolerance) * (massBplus - myInvMassWindowJpsiK + invMassWindowJpsiHadTolerance); + double const invMass2JpsiKMax = (massBplus + myInvMassWindowJpsiK - invMassWindowJpsiHadTolerance) * (massBplus + myInvMassWindowJpsiK - invMassWindowJpsiHadTolerance); + + for (const auto& collisionCounter : collisionsCounter) { + registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); + } + + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsJpsiThisColl = candsJpsi.sliceBy(candsJpsiPerCollision, thisCollId); + auto tracksKaonThisCollision = tracksKaon.sliceBy(tracksLf0PerCollision, thisCollId); + runCandidateCreation(collision, candsJpsiThisColl, tracksKaonThisCollision, tracksKaonThisCollision, invMass2JpsiKMin, invMass2JpsiKMax); + } + } // processDataBplus + PROCESS_SWITCH(HfCandidateCreatorBToJpsiReduced, processDataBplus, "Process data for B+", true); + + void processDataBs(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsJpsi, + soa::Join const& tracksLfDau0, + soa::Join const& tracksLfDau1, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCfgBsToJpsis const& configs) + { + // Jpsi K invariant-mass window cut + for (const auto& config : configs) { + myInvMassWindowJpsiPhi = config.myInvMassWindowJpsiPhi(); + } + // invMassWindowJpsiHadTolerance is used to apply a slightly tighter cut than in JpsiK pair preselection + // to avoid accepting JpsiK pairs that were not formed in JpsiK pair creator + double const invMass2JpsiKMin = (massBs - myInvMassWindowJpsiPhi + invMassWindowJpsiHadTolerance) * (massBs - myInvMassWindowJpsiPhi + invMassWindowJpsiHadTolerance); + double const invMass2JpsiKMax = (massBs + myInvMassWindowJpsiPhi - invMassWindowJpsiHadTolerance) * (massBs + myInvMassWindowJpsiPhi - invMassWindowJpsiHadTolerance); + + for (const auto& collisionCounter : collisionsCounter) { + registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); + } + + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsJpsiThisColl = candsJpsi.sliceBy(candsJpsiPerCollision, thisCollId); + auto tracksLf0ThisCollision = tracksLfDau0.sliceBy(tracksLf0PerCollision, thisCollId); + auto tracksLf1ThisCollision = tracksLfDau1.sliceBy(tracksLf1PerCollision, thisCollId); + runCandidateCreation(collision, candsJpsiThisColl, tracksLf0ThisCollision, tracksLf1ThisCollision, invMass2JpsiKMin, invMass2JpsiKMax); + } + } // processDataBs + PROCESS_SWITCH(HfCandidateCreatorBToJpsiReduced, processDataBs, "Process data for Bs", false); +}; // struct + +/// Extends the table base with expression columns and performs MC matching. +struct HfCandidateCreatorBToJpsiReducedExpressions { + Spawns rowCandidateBPlus; + Spawns rowCandidateBs; + Produces rowBplusMcRec; + Produces rowBsMcRec; + + /// Fill candidate information at MC reconstruction level + /// \param rowsJpsiHadMcRec MC reco information on Jpsi hadron pairs + /// \param candsBIds prong global indices of B candidates + template + void fillMcRec(McRec const& rowsJpsiHadMcRec, CCands const& candsBIds) + { + for (const auto& candB : candsBIds) { + bool filledMcInfo{false}; + if constexpr (DecChannel == DecayChannel::BplusToJpsiK) { + for (const auto& rowJpsiHadMcRec : rowsJpsiHadMcRec) { + if ((rowJpsiHadMcRec.jpsiId() != candB.jpsiId()) || (rowJpsiHadMcRec.bachKaId() != candB.bachKaId())) { + continue; + } + rowBplusMcRec(rowJpsiHadMcRec.flagMcMatchRec(), rowJpsiHadMcRec.flagMcDecayChanRec(), rowJpsiHadMcRec.flagWrongCollision(), rowJpsiHadMcRec.debugMcRec(), rowJpsiHadMcRec.ptMother()); + filledMcInfo = true; + break; + } + if (!filledMcInfo) { // protection to get same size tables in case something went wrong: we created a candidate that was not preselected in the Jpsi-K creator + rowBplusMcRec(0, -1, -1, -1, -1.f); + } + } else if constexpr (DecChannel == DecayChannel::BsToJpsiPhi) { + for (const auto& rowJpsiHadMcRec : rowsJpsiHadMcRec) { + if ((rowJpsiHadMcRec.jpsiId() != candB.jpsiId()) || (rowJpsiHadMcRec.prong0PhiId() != candB.prong0PhiId()) || (rowJpsiHadMcRec.prong1PhiId() != candB.prong1PhiId())) { + continue; + } + rowBsMcRec(rowJpsiHadMcRec.flagMcMatchRec(), rowJpsiHadMcRec.flagMcDecayChanRec(), rowJpsiHadMcRec.flagWrongCollision(), rowJpsiHadMcRec.debugMcRec(), rowJpsiHadMcRec.ptMother()); + filledMcInfo = true; + break; + } + if (!filledMcInfo) { // protection to get same size tables in case something went wrong: we created a candidate that was not preselected in the Jpsi-K creator + rowBsMcRec(0, -1, -1, -1, -1.f); + } + } + } + } + + void processMcBPlus(HfMcRecRedJPKs const& rowsJpsiKMcRec, HfRedBplus2JpsiDaus const& candsBplus) + { + fillMcRec(rowsJpsiKMcRec, candsBplus); + } + PROCESS_SWITCH(HfCandidateCreatorBToJpsiReducedExpressions, processMcBPlus, "Process MC", false); + + void processMcBs(HfMcRecRedJPPhis const& rowsJpsiPhiMcRec, HfRedBs2JpsiDaus const& bs) + { + fillMcRec(rowsJpsiPhiMcRec, bs); + } + PROCESS_SWITCH(HfCandidateCreatorBToJpsiReducedExpressions, processMcBs, "Process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/TableProducer/candidateCreatorBplusReduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorBplusReduced.cxx index d47ac5f3d4d..a5f5ba5779b 100644 --- a/PWGHF/D2H/TableProducer/candidateCreatorBplusReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateCreatorBplusReduced.cxx @@ -14,20 +14,33 @@ /// /// \author Antonio Palasciano , Università degli Studi di Bari -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/V0.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" +#include "Common/Core/RecoDecay.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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -107,7 +120,7 @@ struct HfCandidateCreatorBplusReduced { /// \param tracksPionThisCollision pion tracks in this collision /// \param invMass2D0PiMin minimum B+ invariant-mass /// \param invMass2D0PiMax maximum B+ invariant-mass - template + template void runCandidateCreation(Coll const& collision, Cands const& candsDThisColl, Pions const& tracksPionThisCollision, @@ -190,7 +203,7 @@ struct HfCandidateCreatorBplusReduced { rowCandidateProngs(candD0.globalIndex(), trackPion.globalIndex()); - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { if (trackPion.signed1Pt() < 0) { rowCandidateDmesMlScores(candD0.mlScoreBkgMassHypo0(), candD0.mlScorePromptMassHypo0(), candD0.mlScoreNonpromptMassHypo0()); } else { @@ -198,8 +211,8 @@ struct HfCandidateCreatorBplusReduced { } } } // pi loop - } // D0 loop - } // end runCandidateCreation + } // D0 loop + } // end runCandidateCreation void processData(HfRedCollisionsWithExtras const& collisions, soa::Join const& candsD, @@ -213,8 +226,8 @@ struct HfCandidateCreatorBplusReduced { } // 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 - double invMass2D0PiMin = (massBplus - myInvMassWindowD0Pi + invMassWindowD0PiTolerance) * (massBplus - myInvMassWindowD0Pi + invMassWindowD0PiTolerance); - double invMass2D0PiMax = (massBplus + myInvMassWindowD0Pi - invMassWindowD0PiTolerance) * (massBplus + myInvMassWindowD0Pi - invMassWindowD0PiTolerance); + double const invMass2D0PiMin = (massBplus - myInvMassWindowD0Pi + invMassWindowD0PiTolerance) * (massBplus - myInvMassWindowD0Pi + invMassWindowD0PiTolerance); + double const invMass2D0PiMax = (massBplus + myInvMassWindowD0Pi - invMassWindowD0PiTolerance) * (massBplus + myInvMassWindowD0Pi - invMassWindowD0PiTolerance); for (const auto& collisionCounter : collisionsCounter) { registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); @@ -248,8 +261,8 @@ struct HfCandidateCreatorBplusReduced { } // 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); + float const invMass2D0PiMin = (massBplus - myInvMassWindowD0Pi + invMassWindowD0PiTolerance) * (massBplus - myInvMassWindowD0Pi + invMassWindowD0PiTolerance); + float const invMass2D0PiMax = (massBplus + myInvMassWindowD0Pi - invMassWindowD0PiTolerance) * (massBplus + myInvMassWindowD0Pi - invMassWindowD0PiTolerance); for (const auto& collisionCounter : collisionsCounter) { registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); @@ -282,7 +295,7 @@ struct HfCandidateCreatorBplusReducedExpressions { /// \param checkDecayTypeMc /// \param rowsD0PiMcRec MC reco information on D0Pi pairs /// \param candsBplus prong global indices of B+ candidates - template + template void fillBplusMcRec(McRec const& rowsD0PiMcRec, HfRedBplusProngs const& candsBplus) { for (const auto& candBplus : candsBplus) { @@ -291,10 +304,11 @@ struct HfCandidateCreatorBplusReducedExpressions { if ((rowD0PiMcRec.prong0Id() != candBplus.prong0Id()) || (rowD0PiMcRec.prong1Id() != candBplus.prong1Id())) { continue; } - rowBplusMcRec(rowD0PiMcRec.flagMcMatchRec(), rowD0PiMcRec.debugMcRec(), rowD0PiMcRec.ptMother()); + rowBplusMcRec(rowD0PiMcRec.flagMcMatchRec(), -1 /*channel*/, rowD0PiMcRec.flagWrongCollision(), rowD0PiMcRec.debugMcRec(), rowD0PiMcRec.ptMother()); filledMcInfo = true; - if constexpr (checkDecayTypeMc) { + if constexpr (CheckDecayTypeMc) { rowBplusMcCheck(rowD0PiMcRec.pdgCodeBeautyMother(), + rowD0PiMcRec.pdgCodeCharmMother(), rowD0PiMcRec.pdgCodeProng0(), rowD0PiMcRec.pdgCodeProng1(), rowD0PiMcRec.pdgCodeProng2()); @@ -302,9 +316,9 @@ struct HfCandidateCreatorBplusReducedExpressions { break; } 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.f); - if constexpr (checkDecayTypeMc) { - rowBplusMcCheck(-1, -1, -1, -1); + rowBplusMcRec(0, -1, -1, -1, -1.f); + if constexpr (CheckDecayTypeMc) { + rowBplusMcCheck(-1, -1, -1, -1, -1); } } } diff --git a/PWGHF/D2H/TableProducer/candidateCreatorBsReduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorBsReduced.cxx new file mode 100644 index 00000000000..3317b7383fa --- /dev/null +++ b/PWGHF/D2H/TableProducer/candidateCreatorBsReduced.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 candidateCreatorBsReduced.cxx +/// \brief Reconstruction of Bs candidates +/// +/// \author Fabio Catalano , CERN + +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +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 const invMass2DPiMin = (massB - myInvMassWindowDPi + invMassWindowDPiTolerance) * (massB - myInvMassWindowDPi + invMassWindowDPiTolerance); + float const 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 const invMass2DPiMin = (massB - myInvMassWindowDPi + invMassWindowDPiTolerance) * (massB - myInvMassWindowDPi + invMassWindowDPiTolerance); + float const 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(), -1 /*channel*/, 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, -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 79b6c92311e..46fd5998702 100644 --- a/PWGHF/D2H/TableProducer/candidateCreatorCharmResoReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateCreatorCharmResoReduced.cxx @@ -13,385 +13,1023 @@ /// \brief Reconstruction of Resonance candidates /// /// \author Luca Aglietta , Università degli Studi di Torino +/// \author Antonio Palasciano , INFN Bari -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/V0.h" +#include "PWGHF/D2H/Core/SelectorCutsRedDataFormat.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/Utils/utilsMcMatching.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/Core/RecoDecay.h" -#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include 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, + BachSel, NSelSteps }; -enum DecayChannel : uint8_t { - Ds1ToDstarK0s = 0, - Ds2StarToDplusK0s, - XcToDplusLambda, - LambdaDminus + +enum D0Sel : uint8_t { + SelectedD0 = 0, + SelectedD0Bar +}; + +enum DMesonType : uint8_t { + Dplus = 1, + Dstar, + D0 +}; + +enum BachelorType : uint8_t { + V0 = 1, + Track }; + enum V0Type : uint8_t { K0s = 0, Lambda, AntiLambda }; -const int nBins = 7; -constexpr double binsPt[nBins + 1] = { - 1., - 2., - 4., - 6., - 8., - 12., - 24., - 50.}; -auto vecBins = std::vector{binsPt, binsPt + nBins + 1}; + +enum TrackType : uint8_t { + Pion = 0, + Kaon, + Proton +}; struct HfCandidateCreatorCharmResoReduced { // Produces: Tables with resonance info Produces rowCandidateReso; - // Optional D daughter ML scores table - Produces mlScores; - - // 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"}; - // QA switch - Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; - // Hist Axis - Configurable> binsPt{"binsPt", std::vector{vecBins}, "pT bin limits"}; - - using reducedDWithMl = soa::Join; - - // Partition of V0 candidates based on v0Type - 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; + // Tables with bachelors indices for MC matching and Task + Produces rowCandidateResoIndices3PrV0s; + Produces rowCandidateResoIndicesDstarV0s; + Produces rowCandidateResoIndices2PrV0s; + Produces rowCandidateResoIndices3PrTrks; + Produces rowCandidateResoIndicesDstarTrks; + Produces rowCandidateResoIndices2PrTrks; + // D Configurables + struct : ConfigurableGroup { + std::string prefix = "dmesonsCuts"; + Configurable> binsPtD{"binsPtD", std::vector{hf_cuts_d_daughter::vecBinsPt}, "pT bin limits for D daughter cuts"}; + Configurable> cutsD{"cutsD", {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 keepSideBands{"keepSideBands", false, "flag to keep events from D meson sidebands for backgorund estimation"}; + } cfgDmesCuts; + // V0 cuts configurables + struct : ConfigurableGroup { + std::string prefix = "v0Cuts"; + Configurable> cutsV0{"cutsV0", {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"}; + Configurable v0Type{"v0Type", 0, "V0 type to be selected (0: K0s, 1: Lambda"}; + } cfgV0Cuts; + // Track cuts configurables + struct : ConfigurableGroup { + std::string prefix = "trackCuts"; + Configurable> cutsTrk{"cutsTrk", {hf_cuts_track_daughter::Cuts[0], hf_cuts_track_daughter::NCutVars, hf_cuts_track_daughter::labelsCutVar}, "Track daughter selections, set to -1 to disable cuts"}; + Configurable massHypo{"massHypo", 1, "Mass Hypothesis for the track daughters (0: pion, 1: kaon, 2: proton)"}; + } cfgTrackCuts; + // Mixed Event configurables + struct : ConfigurableGroup { + std::string prefix = "mixedEvent"; + 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"}; + } cfgMixedEvent; + struct : ConfigurableGroup { + std::string prefix = "trackRotation"; + Configurable enable{"enable", false, "enable rotation of track/V0 for background estimation"}; + Configurable numRotations{"numRotations", 12, "number of track/V0 rotations"}; + 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"}; + } cfgTrackRotation; + // Histogram axes configurables + struct : ConfigurableGroup { + std::string prefix = "histAxes"; + ConfigurableAxis axisPtD{"axisPtD", {100, 0., 50}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisPtV0{"axisPtV0", {100, 0., 50}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisPtReso{"axisPtReso", {100, 0., 50}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisMassD{"axisMassD", {100, 1.7f, 2.1f}, "inv. mass (D) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisMassV0{"axisMassV0", {100, 0.45f, 0.55f}, "inv. mass (V_{0}) (GeV/#it{c}^{2})"}; + ConfigurableAxis axisMassDsj{"axisMassDsj", {400, 0.49f, 0.89f}, "inv. mass (DV_{0}) (GeV/#it{c}^{2})"}; + } cfgHistAxes; + // Other Configurables + Configurable rejectPairsWithCommonDaughter{"rejectPairsWithCommonDaughter", true, "flag to reject the pairs that share a daughter track if not done in the derived data creation"}; + Configurable useDeltaMass{"useDeltaMass", true, "Use Delta Mass for resonance invariant Mass calculation"}; + SliceCache cache; Preslice candsV0PerCollision = aod::hf_track_index_reduced::hfRedCollisionId; - Preslice candsDPerCollision = hf_track_index_reduced::hfRedCollisionId; - // aod::HfRedVzeros - // Useful constants - double massK0{0.}; - double massLambda{0.}; - double massDplus{0.}; - double massDstar{0.}; - double massD0{0.}; - - // Histogram registry: if task make it with a THNsparse with all variables you want to save + Preslice candsTrackPerCollision = aod::hf_track_index_reduced::hfRedCollisionId; + Preslice cands3PrPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice candsDstarPerCollision = hf_track_index_reduced::hfRedCollisionId; + Preslice cands2PrPerCollision = hf_track_index_reduced::hfRedCollisionId; + HistogramRegistry registry{"registry"}; + float bkgRotationAngleStep{0.f}; void init(InitContext const&) { - // check that only one process function is enabled - std::array doprocess{doprocessDs2StarToDplusK0s, doprocessDs2StarToDplusK0sWithMl, doprocessDs1ToDstarK0s, doprocessDs1ToDstarK0sWithMl, doprocessXcToDplusLambda, doprocessXcToDplusLambdaWithMl, doprocessLambdaDminus, doprocessLambdaDminusWithMl}; - 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})"}}}); - 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"; - 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()); - } + registry.add("hMassDmesDauVsPt", "D daughter candidates inv. mass", {HistType::kTH2F, {cfgHistAxes.axisMassD, cfgHistAxes.axisPtD}}); + registry.add("hMassV0DauVsPt", "V0 daughter candidates inv. mass", {HistType::kTH2F, {cfgHistAxes.axisMassV0, cfgHistAxes.axisPtV0}}); + registry.add("hMassResoVsPt", "Resonance candidates inv. mass", {HistType::kTH2F, {cfgHistAxes.axisMassDsj, cfgHistAxes.axisPtReso}}); + 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.}}}); + constexpr int kNBinsSelections = Selections::NSelSteps; + std::string labels[kNBinsSelections]; + labels[Selections::NoSel] = "No selection"; + labels[Selections::DSel] = "D Candidates Selection"; + labels[Selections::BachSel] = "D & other bach. 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; - massD0 = o2::constants::physics::MassD0; + bkgRotationAngleStep = (cfgTrackRotation.numRotations > 1) ? (cfgTrackRotation.maxRotAngleMultByPi - cfgTrackRotation.minRotAngleMultByPi) * constants::math::PI / (cfgTrackRotation.numRotations - 1) : 0.; } + + bool isInMassInterval(float invMass, int ptBin) + { + if (!cfgDmesCuts.keepSideBands) { + return (invMass >= cfgDmesCuts.cutsD->get(ptBin, "invMassSignalLow") && invMass <= cfgDmesCuts.cutsD->get(ptBin, "invMassSignalHigh")); + } + return ((invMass >= cfgDmesCuts.cutsD->get(ptBin, "invMassLeftSBLow") && invMass <= cfgDmesCuts.cutsD->get(ptBin, "invMassLeftSBHigh")) || + (invMass >= cfgDmesCuts.cutsD->get(ptBin, "invMassRightSBLow") && invMass <= cfgDmesCuts.cutsD->get(ptBin, "invMassRightSBHigh")) || + (invMass >= cfgDmesCuts.cutsD->get(ptBin, "invMassSignalLow") && invMass <= cfgDmesCuts.cutsD->get(ptBin, "invMassSignalHigh"))); + } + /// 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) + template + uint8_t selctionFlagBachD(DRedTable const& candD) { - float massD{0.}; + uint8_t selection = {BIT(D0Sel::SelectedD0) | BIT(D0Sel::SelectedD0Bar)}; float invMassD{0.}; - // slection on D candidate mass - if (channel == DecayChannel::Ds2StarToDplusK0s || channel == DecayChannel::XcToDplusLambda || channel == DecayChannel::LambdaDminus) { - massD = massDplus; + float const ptD = candD.pt(); + int const ptBin = findBin(cfgDmesCuts.binsPtD, ptD); + if (ptBin == -1) { + return 0; + } + if constexpr (DType == DMesonType::Dplus) { invMassD = candD.invMassDplus(); - } else if (channel == DecayChannel::Ds1ToDstarK0s) { - massD = massDstar - massD0; - if (candD.dType() > 0) - invMassD = candD.invMassDstar(); - else - invMassD = candD.invMassAntiDstar(); + if (!isInMassInterval(invMassD, ptBin)) { + return 0; + } + } else if constexpr (DType == DMesonType::Dstar) { + if (candD.sign() > 0) { + invMassD = candD.invMassDstar() - candD.invMassD0(); + } else { + invMassD = candD.invMassAntiDstar() - candD.invMassD0Bar(); + } + if (!isInMassInterval(invMassD, ptBin)) { + return 0; + } + } else if constexpr (DType == DMesonType::D0) { + if (TESTBIT(candD.selFlagD0(), D0Sel::SelectedD0)) { + invMassD = candD.invMassD0(); + if (!isInMassInterval(invMassD, ptBin)) { + CLRBIT(selection, D0Sel::SelectedD0); + } + } else { + CLRBIT(selection, D0Sel::SelectedD0); + } + if (TESTBIT(candD.selFlagD0(), D0Sel::SelectedD0Bar)) { + invMassD = candD.invMassD0Bar(); + if (!isInMassInterval(invMassD, ptBin)) { + CLRBIT(selection, D0Sel::SelectedD0Bar); + } + } else { + CLRBIT(selection, D0Sel::SelectedD0Bar); + } } - if (std::fabs(invMassD - massD) > invMassWindowD) { + return selection; + } + + /// Basic selection of V0 and track candidates + /// \param candV0 is the reduced V0 candidate + /// \return true if selections are passed + template + bool isV0Selected(V0RedTable const& candV0) + { + int const ptBin = findBin(cfgV0Cuts.binsPtV0, candV0.pt()); + const float invMassLow = cfgV0Cuts.cutsV0->get(ptBin, "invMassLow"); + const float invMassHigh = cfgV0Cuts.cutsV0->get(ptBin, "invMassHigh"); + if (ptBin == -1) { + return false; + } + if (cfgV0Cuts.v0Type == V0Type::K0s) { // K0s + if (!TESTBIT(candV0.v0Type(), V0Type::K0s)) { + return false; + } + if (candV0.invMassK0s() < invMassLow || candV0.invMassK0s() > invMassHigh) { + return false; + } + } else if (cfgV0Cuts.v0Type == V0Type::Lambda) { // Lambda + if (!TESTBIT(candV0.v0Type(), V0Type::Lambda) && !TESTBIT(candV0.v0Type(), V0Type::AntiLambda)) { + return false; + } + + if (TESTBIT(candV0.v0Type(), V0Type::Lambda)) { + if (candV0.invMassLambda() < invMassLow || candV0.invMassLambda() > invMassHigh) { + return false; + } + } + + if (TESTBIT(candV0.v0Type(), V0Type::AntiLambda)) { + if (candV0.invMassAntiLambda() < invMassLow || candV0.invMassAntiLambda() > invMassHigh) { + return false; + } + } + } else { + LOG(error) << "Unsupported V0 type for selection: " << cfgV0Cuts.v0Type; + return false; + } + // selection on kinematics and topology + if (candV0.dca() > cfgV0Cuts.cutsV0->get(ptBin, "dcaMax") || candV0.cpa() < cfgV0Cuts.cutsV0->get(ptBin, "cpaMin") || candV0.v0Radius() < cfgV0Cuts.cutsV0->get(ptBin, "radiusMin")) { return false; } return true; } - /// Basic selection of V0 candidates - /// \param candV0 is the reduced V0 candidate - /// \param candD is the reduced D meson candidate + // Basic selection of track candidates + /// \param candTr is the reduced track candidate /// \return true if selections are passed - template - bool isV0Selected(V0RedTable const& candV0, DRedTable const& candD) + template + bool isTrackSelected(TrkRedTable const& candTr) { - float massV0{0.}; - float invMassV0{0.}; - if (channel == DecayChannel::Ds2StarToDplusK0s || channel == DecayChannel::Ds1ToDstarK0s) { - massV0 = massK0; - invMassV0 = candV0.invMassK0s(); - } else if (channel == DecayChannel::XcToDplusLambda || channel == DecayChannel::LambdaDminus) { - massV0 = massLambda; - int wsFact{1}; - if (channel == DecayChannel::LambdaDminus) - wsFact = -1; - uint8_t targetV0Type{0}; - if (wsFact * candD.dType() > 0) { - invMassV0 = candV0.invMassLambda(); - targetV0Type = V0Type::Lambda; - } else { - invMassV0 = candV0.invMassAntiLambda(); - targetV0Type = V0Type::AntiLambda; + // pT selection + if (cfgTrackCuts.cutsTrk->get("ptMin") > 0 && candTr.pt() < cfgTrackCuts.cutsTrk->get("ptMin")) { + return false; + } + // ITS quality selection + if (cfgTrackCuts.cutsTrk->get("itsNClsMin") > 0 && candTr.itsNCls() < cfgTrackCuts.cutsTrk->get("itsNClsMin")) { + return false; + } + // TPC quality selection + if (cfgTrackCuts.cutsTrk->get("tpcNCrossedRowsMin") > 0 && candTr.tpcNClsCrossedRows() < cfgTrackCuts.cutsTrk->get("tpcNCrossedRowsMin")) { + return false; + } + if (cfgTrackCuts.cutsTrk->get("tpcChi2Max") > 0 && candTr.tpcChi2NCl() > cfgTrackCuts.cutsTrk->get("tpcChi2Max")) { + return false; + } + // PID selection + if (cfgTrackCuts.massHypo == TrackType::Pion) { // Pion + if (cfgTrackCuts.cutsTrk->get("nSigmaTpc") > 0 && candTr.tpcNSigmaPi() > cfgTrackCuts.cutsTrk->get("nSigmaTpc")) { + return false; } - if (!TESTBIT(candV0.v0Type(), targetV0Type)) { + if (cfgTrackCuts.cutsTrk->get("nSigmaTof") > 0 && candTr.tofNSigmaPi() > cfgTrackCuts.cutsTrk->get("nSigmaTof")) { return false; } - } - // slection on V0 candidate mass - if (std::fabs(invMassV0 - massV0) > invMassWindowV0) { + if (cfgTrackCuts.cutsTrk->get("nSigmaComb") > 0 && candTr.tpcTofNSigmaPi() > cfgTrackCuts.cutsTrk->get("nSigmaComb")) { + return false; + } + } else if (cfgTrackCuts.massHypo == TrackType::Kaon) { // Kaon + if (cfgTrackCuts.cutsTrk->get("nSigmaTpc") > 0 && candTr.tpcNSigmaKa() > cfgTrackCuts.cutsTrk->get("nSigmaTpc")) { + return false; + } + if (cfgTrackCuts.cutsTrk->get("nSigmaTof") > 0 && candTr.tofNSigmaKa() > cfgTrackCuts.cutsTrk->get("nSigmaTof")) { + return false; + } + if (cfgTrackCuts.cutsTrk->get("nSigmaComb") > 0 && candTr.tpcTofNSigmaKa() > cfgTrackCuts.cutsTrk->get("nSigmaComb")) { + return false; + } + } else if (cfgTrackCuts.massHypo == TrackType::Proton) { // Proton + if (cfgTrackCuts.cutsTrk->get("nSigmaTpc") > 0 && candTr.tpcNSigmaPr() > cfgTrackCuts.cutsTrk->get("nSigmaTpc")) { + return false; + } + if (cfgTrackCuts.cutsTrk->get("nSigmaTof") > 0 && candTr.tofNSigmaPr() > cfgTrackCuts.cutsTrk->get("nSigmaTof")) { + return false; + } + if (cfgTrackCuts.cutsTrk->get("nSigmaComb") > 0 && candTr.tpcTofNSigmaPr() > cfgTrackCuts.cutsTrk->get("nSigmaComb")) { + return false; + } + } else { + LOG(error) << "Unsupported mass hypothesis for track selection: " << cfgTrackCuts.massHypo; return false; } return true; } - template + /// Fill the output tables with the resonance candidates + /// \param collision is the collision information + /// \param candD is the reduced D meson candidate + /// \param candV0Tr is the reduced V0 or track candidate + /// \tparam dType is the type of D meson (Dplus, Dstar, D0) + /// \tparam bachType is the type of bachelor (V0 or Track) + template + void fillOutputTables(Coll const& collision, + DRedTable const& candD, + V0TrRedTable const& candV0Tr, + int selectionFlag) + { + std::vector> pVectorCharmProngs = {candD.pVectorProng0(), candD.pVectorProng1()}; + std::array pVecD = candD.pVector(); + + int const numFills = (cfgTrackRotation.enable) ? cfgTrackRotation.numRotations : 1; // number of times we fil the tables: default 1, but more in case of track rotation + + for (int iFill{0}; iFill < numFills; ++iFill) { + + std::array pVecV0Tr = candV0Tr.pVector(); + if (cfgTrackRotation.enable) { // let's rotate + float const bkgRotAngle = cfgTrackRotation.minRotAngleMultByPi * constants::math::PI + bkgRotationAngleStep * iFill; + pVecV0Tr = std::array{candV0Tr.px() * std::cos(bkgRotAngle) - candV0Tr.py() * std::sin(bkgRotAngle), candV0Tr.px() * std::sin(bkgRotAngle) + candV0Tr.py() * std::cos(bkgRotAngle), candV0Tr.pz()}; + } + + float invMassReso{-1}, invMassV0Tr{-1}, invMassD{-1}; + int8_t signReso{0}, isWrongSign{0}; + double const ptReso = RecoDecay::pt(RecoDecay::sumOfVec(pVecV0Tr, pVecD)); + + if constexpr (DType == DMesonType::Dplus) { + invMassD = candD.invMassDplus(); + pVectorCharmProngs.push_back(candD.pVectorProng2()); + if constexpr (BachType == BachelorType::V0) { + if (cfgV0Cuts.v0Type == V0Type::K0s) { // K0s + invMassV0Tr = candV0Tr.invMassK0s(); + signReso = candD.sign(); + if (useDeltaMass) { + 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{pVecD, pVecV0Tr}, std::array{MassDPlus, MassK0Short}); + } + } else if (cfgV0Cuts.v0Type == V0Type::Lambda) { // Lambda + if (TESTBIT(candV0Tr.v0Type(), V0Type::Lambda)) { + invMassV0Tr = candV0Tr.invMassLambda(); + signReso = candD.sign(); + isWrongSign = candD.sign() < 0 ? 1 : 0; + } else if (TESTBIT(candV0Tr.v0Type(), V0Type::AntiLambda)) { + invMassV0Tr = candV0Tr.invMassAntiLambda(); + signReso = candD.sign(); + isWrongSign = candD.sign() > 0 ? 1 : 0; + } + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDPlus, MassLambda}); + } + } + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD, + invMassV0Tr, + signReso, + isWrongSign); + rowCandidateResoIndices3PrV0s(collision.globalIndex(), candD.globalIndex(), candV0Tr.globalIndex()); + registry.fill(HIST("hMassResoVsPt"), invMassReso, ptReso); + registry.fill(HIST("hMassDmesDauVsPt"), invMassD, candD.pt()); + registry.fill(HIST("hMassV0DauVsPt"), invMassV0Tr, candV0Tr.pt()); + } else if constexpr (BachType == BachelorType::Track) { + signReso = candD.sign() + candV0Tr.sign(); + isWrongSign = candD.sign() * candV0Tr.sign() > 0 ? 1 : 0; + if (cfgTrackCuts.massHypo == TrackType::Pion) { // Pion + invMassV0Tr = MassPiPlus; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassPiPlus}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDPlus, MassPiPlus}); + } + } else if (cfgTrackCuts.massHypo == TrackType::Kaon) { // Kaon + invMassV0Tr = MassKPlus; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassKPlus}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDPlus, MassKPlus}); + } + } else if (cfgTrackCuts.massHypo == TrackType::Proton) { // Proton + invMassV0Tr = MassProton; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDPlus, MassProton}); + } + } + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD, + invMassV0Tr, + signReso, + isWrongSign); + rowCandidateResoIndices3PrTrks(collision.globalIndex(), candD.globalIndex(), candV0Tr.globalIndex()); + registry.fill(HIST("hMassResoVsPt"), invMassReso, ptReso); + registry.fill(HIST("hMassDmesDauVsPt"), invMassD, candD.pt()); + registry.fill(HIST("hMassV0DauVsPt"), invMassV0Tr, candV0Tr.pt()); + } + } else if constexpr (DType == DMesonType::Dstar) { + float invMassD0; + if (candD.sign() > 0) { + invMassD = candD.invMassDstar(); + invMassD0 = candD.invMassD0(); + } else { + invMassD = candD.invMassAntiDstar(); + invMassD0 = candD.invMassD0Bar(); + } + pVectorCharmProngs.push_back(candD.pVectorProng2()); + if constexpr (BachType == BachelorType::V0) { + signReso = candD.sign(); + if (cfgV0Cuts.v0Type == V0Type::K0s) { // K0s + invMassV0Tr = candV0Tr.invMassK0s(); + if (useDeltaMass) { + if (candD.sign() > 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; + } + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDStar, MassK0Short}); + } + } else if (cfgV0Cuts.v0Type == V0Type::Lambda) { // Lambda + if (TESTBIT(candV0Tr.v0Type(), V0Type::Lambda)) { + invMassV0Tr = candV0Tr.invMassLambda(); + } else if (TESTBIT(candV0Tr.v0Type(), V0Type::AntiLambda)) { + invMassV0Tr = candV0Tr.invMassAntiLambda(); + isWrongSign = 1; + } + if (useDeltaMass) { + if (candD.sign() > 0) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[1], pVectorCharmProngs[0], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda}) - invMassD; + } + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDStar, MassLambda}); + } + } + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD - invMassD0, + invMassV0Tr, + signReso, + isWrongSign); + rowCandidateResoIndicesDstarV0s(collision.globalIndex(), candD.globalIndex(), candV0Tr.globalIndex()); + registry.fill(HIST("hMassResoVsPt"), invMassReso, ptReso); + registry.fill(HIST("hMassDmesDauVsPt"), invMassD - invMassD0, candD.pt()); + registry.fill(HIST("hMassV0DauVsPt"), invMassV0Tr, candV0Tr.pt()); + } else if constexpr (BachType == BachelorType::Track) { + signReso = candD.sign() + candV0Tr.sign(); + isWrongSign = candD.sign() * candV0Tr.sign() > 0 ? 1 : 0; + if (cfgTrackCuts.massHypo == TrackType::Pion) { // Pion + invMassV0Tr = MassPiPlus; + if (useDeltaMass) { + if (candD.sign() > 0) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassPiPlus}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[1], pVectorCharmProngs[0], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassPiPlus}) - invMassD; + } + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDStar, MassPiPlus}); + } + } else if (cfgTrackCuts.massHypo == TrackType::Kaon) { // Kaon + invMassV0Tr = MassKPlus; + if (useDeltaMass) { + if (candD.sign() > 0) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassKPlus}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[1], pVectorCharmProngs[0], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassKPlus}) - invMassD; + } + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDStar, MassKPlus}); + } + } else if (cfgTrackCuts.massHypo == TrackType::Proton) { // Proton + invMassV0Tr = MassProton; + if (useDeltaMass) { + if (candD.sign() > 0) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[1], pVectorCharmProngs[0], pVectorCharmProngs[2], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}) - invMassD; + } + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassDStar, MassProton}); + } + } + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD - invMassD0, + invMassV0Tr, + signReso, + isWrongSign); + rowCandidateResoIndicesDstarTrks(collision.globalIndex(), candD.globalIndex(), candV0Tr.globalIndex()); + registry.fill(HIST("hMassResoVsPt"), invMassReso, ptReso); + registry.fill(HIST("hMassDmesDauVsPt"), invMassD, candD.pt()); + registry.fill(HIST("hMassV0DauVsPt"), invMassV0Tr, candV0Tr.pt()); + } + } else if constexpr (DType == DMesonType::D0) { + // D0 + if (TESTBIT(selectionFlag, D0Sel::SelectedD0)) { + invMassD = candD.invMassD0(); + if constexpr (BachType == BachelorType::V0) { + signReso = 0; + if (cfgV0Cuts.v0Type == V0Type::K0s) { // K0s + invMassV0Tr = candV0Tr.invMassK0s(); + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassK0Short}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0, MassK0Short}); + } + } else if (cfgV0Cuts.v0Type == V0Type::Lambda) { // Lambda + if (TESTBIT(candV0Tr.v0Type(), V0Type::Lambda)) { + invMassV0Tr = candV0Tr.invMassLambda(); + } else if (TESTBIT(candV0Tr.v0Type(), V0Type::AntiLambda)) { + invMassV0Tr = candV0Tr.invMassAntiLambda(); + isWrongSign = 1; + } + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassLambda}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0, MassLambda}); + } + } + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD, + invMassV0Tr, + signReso, + isWrongSign); + rowCandidateResoIndices2PrV0s(collision.globalIndex(), candD.globalIndex(), candV0Tr.globalIndex()); + registry.fill(HIST("hMassResoVsPt"), invMassReso, ptReso); + registry.fill(HIST("hMassDmesDauVsPt"), invMassD, candD.pt()); + registry.fill(HIST("hMassV0DauVsPt"), invMassV0Tr, candV0Tr.pt()); + } else if constexpr (BachType == BachelorType::Track) { + signReso = candV0Tr.sign(); + isWrongSign = candV0Tr.sign() > 0 ? 0 : 1; + if (cfgTrackCuts.massHypo == TrackType::Pion) { // Pion + invMassV0Tr = MassPiPlus; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassPiPlus}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0, MassPiPlus}); + } + } else if (cfgTrackCuts.massHypo == TrackType::Kaon) { // Kaon + invMassV0Tr = MassKPlus; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassKPlus}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0, MassKPlus}); + } + } else if (cfgTrackCuts.massHypo == TrackType::Proton) { // Proton + invMassV0Tr = MassProton; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassPiPlus, MassKPlus, MassProton}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0, MassProton}); + } + } + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD, + invMassV0Tr, + signReso, + isWrongSign); + rowCandidateResoIndices2PrTrks(collision.globalIndex(), candD.globalIndex(), candV0Tr.globalIndex()); + registry.fill(HIST("hMassResoVsPt"), invMassReso, ptReso); + registry.fill(HIST("hMassDmesDauVsPt"), invMassD, candD.pt()); + registry.fill(HIST("hMassV0DauVsPt"), invMassV0Tr, candV0Tr.pt()); + } + } + // D0bar + if (TESTBIT(selectionFlag, D0Sel::SelectedD0Bar)) { + invMassD = candD.invMassD0Bar(); + if constexpr (BachType == BachelorType::V0) { + signReso = 0; + if (cfgV0Cuts.v0Type == V0Type::K0s) { // K0s + invMassV0Tr = candV0Tr.invMassK0s(); + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassKPlus, MassPiPlus, MassK0Short}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0Bar, MassK0Short}); + } + } else if (cfgV0Cuts.v0Type == V0Type::Lambda) { // Lambda + if (TESTBIT(candV0Tr.v0Type(), V0Type::Lambda)) { + invMassV0Tr = candV0Tr.invMassLambda(); + isWrongSign = 1; + } else if (TESTBIT(candV0Tr.v0Type(), V0Type::AntiLambda)) { + invMassV0Tr = candV0Tr.invMassAntiLambda(); + } + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassKPlus, MassPiPlus, MassLambda}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0Bar, MassLambda}); + } + } + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD, + invMassV0Tr, + signReso, + isWrongSign); + rowCandidateResoIndices2PrV0s(collision.globalIndex(), candD.globalIndex(), candV0Tr.globalIndex()); + registry.fill(HIST("hMassResoVsPt"), invMassReso, ptReso); + registry.fill(HIST("hMassDmesDauVsPt"), invMassD, candD.pt()); + registry.fill(HIST("hMassV0DauVsPt"), invMassV0Tr, candV0Tr.pt()); + } else if constexpr (BachType == BachelorType::Track) { + signReso = candV0Tr.sign(); + isWrongSign = candV0Tr.sign() > 0 ? 1 : 0; + if (cfgTrackCuts.massHypo == TrackType::Pion) { // Pion + invMassV0Tr = MassPiPlus; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassKPlus, MassPiPlus, MassPiPlus}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0Bar, MassPiPlus}); + } + } else if (cfgTrackCuts.massHypo == TrackType::Kaon) { // Kaon + invMassV0Tr = MassKPlus; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassKPlus, MassPiPlus, MassKPlus}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0Bar, MassKPlus}); + } + } else if (cfgTrackCuts.massHypo == TrackType::Proton) { // Proton + invMassV0Tr = MassProton; + if (useDeltaMass) { + invMassReso = RecoDecay::m(std::array{pVectorCharmProngs[0], pVectorCharmProngs[1], pVecV0Tr}, std::array{MassKPlus, MassPiPlus, MassProton}) - invMassD; + } else { + invMassReso = RecoDecay::m(std::array{pVecD, pVecV0Tr}, std::array{MassD0Bar, MassProton}); + } + } + rowCandidateReso(pVecD[0], pVecD[1], pVecD[2], + pVecV0Tr[0], pVecV0Tr[1], pVecV0Tr[2], + invMassReso, + invMassD, + invMassV0Tr, + signReso, + isWrongSign); + rowCandidateResoIndices2PrTrks(collision.globalIndex(), candD.globalIndex(), candV0Tr.globalIndex()); + registry.fill(HIST("hMassResoVsPt"), invMassReso, ptReso); + registry.fill(HIST("hMassDmesDauVsPt"), invMassD, candD.pt()); + registry.fill(HIST("hMassV0DauVsPt"), invMassV0Tr, candV0Tr.pt()); + } + } + } + } + } + + template void runCandidateCreation(Coll const& collision, DRedTable const& candsD, - V0RedTable const& candsV0) + V0TrRedTable const& candsV0Tr) { // loop on D candidates + // LOG(info) << "Number of D candidates: " << candsD.size() << ", Number of V0/Track candidates: " << candsV0Tr.size(); for (const auto& candD : candsD) { // selection of D candidates - if (activateQA) { - registry.fill(HIST("hSelections"), 1); - } - if (!isDSelected(candD)) { + registry.fill(HIST("hSelections"), 1); + uint8_t const selFlagD = selctionFlagBachD(candD); + if (selFlagD == 0) { continue; } - if (activateQA) { - registry.fill(HIST("hSelections"), 1 + Selections::DSel); + registry.fill(HIST("hSelections"), 1 + Selections::DSel); + std::vector dDaughtersIDs = {candD.prong0Id(), candD.prong1Id()}; + if constexpr (DType == DMesonType::Dstar || DType == DMesonType::Dplus) { + dDaughtersIDs.push_back(candD.prong2Id()); } - float invMassD{0.}; - if (std::abs(candD.dType()) == 1) - invMassD = candD.invMassDplus(); - if (candD.dType() == 2) - invMassD = candD.invMassDstar(); - if (candD.dType() == -2) - invMassD = candD.invMassAntiDstar(); - std::array pVecD = {candD.px(), candD.py(), candD.pz()}; - float ptD = RecoDecay::pt(pVecD); - ; - // loop on V0 candidates + // loop on V0 or track candidates bool alreadyCounted{false}; - for (const auto& candV0 : candsV0) { - if (rejectDV0PairsWithCommonDaughter) { - const std::array dDaughtersIDs = {candD.prong0Id(), candD.prong1Id(), candD.prong2Id()}; - if (std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), candV0.prong0Id()) != dDaughtersIDs.end() || std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), candV0.prong1Id()) != dDaughtersIDs.end()) { + for (const auto& candV0Tr : candsV0Tr) { + if constexpr (BachType == BachelorType::V0) { // Case: V0 + if (rejectPairsWithCommonDaughter && (std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), candV0Tr.prong0Id()) != dDaughtersIDs.end() || std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), candV0Tr.prong1Id()) != dDaughtersIDs.end())) { continue; } + if (!isV0Selected(candV0Tr)) { + continue; + } + if (!alreadyCounted) { + registry.fill(HIST("hSelections"), 1 + Selections::BachSel); + alreadyCounted = true; + } + } else if constexpr (BachType == BachelorType::Track) { // Case: Track + if (rejectPairsWithCommonDaughter && std::find(dDaughtersIDs.begin(), dDaughtersIDs.end(), candV0Tr.trackId()) != dDaughtersIDs.end()) { + continue; + } + if (!isTrackSelected(candV0Tr)) { + continue; + } + if (!alreadyCounted) { + registry.fill(HIST("hSelections"), 1 + Selections::BachSel); + alreadyCounted = true; + } } + // Filling of tables and histograms + fillOutputTables(collision, candD, candV0Tr, selFlagD); + } // end of loop on V0/Track candidates + } // end of loop on D candidates + } // end of function - if (!isV0Selected(candV0, candD)) { + // 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 const corrBinning{{cfgMixedEvent.zPoolBins, cfgMixedEvent.multPoolBins}, true}; + auto bachTuple = std::make_tuple(candsD, candsV0Tr); + Pair const pairs{corrBinning, cfgMixedEvent.numberEventsMixed, cfgMixedEvent.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 + uint8_t const selFlagD = selctionFlagBachD(bachD); + if (selFlagD == 0) { continue; } - if (activateQA && !alreadyCounted) { - registry.fill(HIST("hSelections"), 1 + Selections::V0Sel); - alreadyCounted = true; - } - float invMassReso{0.}; - float invMassV0{0.}; - std::array pVecV0 = {candV0.px(), candV0.py(), candV0.pz()}; - float ptV0 = RecoDecay::pt(pVecV0); - float ptReso = RecoDecay::pt(RecoDecay::sumOfVec(pVecV0, pVecD)); - switch (channel) { - case DecayChannel::Ds1ToDstarK0s: - invMassV0 = candV0.invMassK0s(); - invMassReso = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massDstar, massK0}); - registry.fill(HIST("hMassDs1"), invMassReso, ptReso); - break; - case DecayChannel::Ds2StarToDplusK0s: - invMassV0 = candV0.invMassK0s(); - invMassReso = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massDplus, massK0}); - registry.fill(HIST("hMassDs2Star"), invMassReso, ptReso); - break; - case DecayChannel::XcToDplusLambda: - if (candD.dType() > 0) { - invMassV0 = candV0.invMassLambda(); - } else { - invMassV0 = candV0.invMassAntiLambda(); - } - invMassReso = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massDplus, massLambda}); - registry.fill(HIST("hMassXcRes"), invMassReso, ptReso); - break; - case DecayChannel::LambdaDminus: - if (candD.dType() < 0) { - invMassV0 = candV0.invMassLambda(); - } else { - invMassV0 = candV0.invMassAntiLambda(); - } - invMassReso = RecoDecay::m(std::array{pVecD, pVecV0}, std::array{massDplus, massLambda}); - registry.fill(HIST("hMassLambdaDminus"), invMassReso, ptReso); - break; - default: - break; - } - // Filling Output table - rowCandidateReso(collision.globalIndex(), - invMassReso, - ptReso, - invMassD, - ptD, - invMassV0, - ptV0, - candV0.cpa(), - candV0.dca(), - candV0.v0radius()); - if constexpr (fillMl) { - mlScores(candD.mlScoreBkgMassHypo0(), candD.mlScorePromptMassHypo0(), candD.mlScoreNonpromptMassHypo0()); + if constexpr (BachType == BachelorType::V0) { + if (!isV0Selected(bachV0Tr)) { + continue; + } + } else if constexpr (BachType == BachelorType::Track) { + if (!isTrackSelected(bachV0Tr)) { + continue; + } } + fillOutputTables(collision1, bachD, bachV0Tr, selFlagD); } } - } // main function + } // runCandidateCreationMixedEvent - void processDs2StarToDplusK0s(aod::HfRedCollisions const& collisions, - aod::HfRed3PrNoTrks const& candsD, - aod::HfRedVzeros const&) + // List of Process Functions + void process3ProngV0s(aod::HfRedCollisions const& collisions, + aod::HfRed3PrNoTrks const& candsD, + aod::HfRedVzeros const& candsV0) { 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); + auto candsDThisColl = candsD.sliceBy(cands3PrPerCollision, thisCollId); + auto v0sThisColl = candsV0.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, v0sThisColl); } } - PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs2StarToDplusK0s, "Process Ds2* candidates without ML info", true); + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, process3ProngV0s, "Process resonances decaying in a 3 prong D meson and a V0", true); - void processDs2StarToDplusK0sWithMl(aod::HfRedCollisions const& collisions, - soa::Join const& candsD, - aod::HfRedVzeros const&) + void processDstarV0s(aod::HfRedCollisions const& collisions, + aod::HfRedDstarNoTrks const& candsD, + aod::HfRedVzeros const& candsV0) { 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); + auto candsDThisColl = candsD.sliceBy(candsDstarPerCollision, thisCollId); + auto v0sThisColl = candsV0.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, v0sThisColl); } } - PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs2StarToDplusK0sWithMl, "Process Ds2* candidates with Ml info", false); + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDstarV0s, "Process resonances decaying in a Dstar meson and a V0", false); - void processDs1ToDstarK0s(aod::HfRedCollisions const& collisions, - aod::HfRed3PrNoTrks const& candsD, - aod::HfRedVzeros const&) + void process2PrV0s(aod::HfRedCollisions const& collisions, + aod::HfRed2PrNoTrks const& candsD, + aod::HfRedVzeros const& candsV0) { 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); + auto candsDThisColl = candsD.sliceBy(cands2PrPerCollision, thisCollId); + auto v0sThisColl = candsV0.sliceBy(candsV0PerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, v0sThisColl); } } - PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs1ToDstarK0s, "Process Ds1 candidates without Ml info", false); + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, process2PrV0s, "Process resonances decaying in a 2 prong D meson and a V0", false); - void processDs1ToDstarK0sWithMl(aod::HfRedCollisions const& collisions, - reducedDWithMl const& candsD, - aod::HfRedVzeros const&) + void process3ProngTracks(aod::HfRedCollisions const& collisions, + aod::HfRed3PrNoTrks const& candsD, + HfRedTrkNoParams const& candsTr) { 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); + auto candsDThisColl = candsD.sliceBy(cands3PrPerCollision, thisCollId); + auto trksThisColl = candsTr.sliceBy(candsTrackPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, trksThisColl); } } - PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDs1ToDstarK0sWithMl, "Process Ds1 candidates with Ml info", false); + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, process3ProngTracks, "Process resonances decaying in a 3 prong D meson and a Track", false); - void processXcToDplusLambda(aod::HfRedCollisions const& collisions, - aod::HfRed3PrNoTrks const& candsD, - aod::HfRedVzeros const&) + void processDstarTracks(aod::HfRedCollisions const& collisions, + aod::HfRedDstarNoTrks const& candsD, + HfRedTrkNoParams const& candsTr) { 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); + auto candsDThisColl = candsD.sliceBy(candsDstarPerCollision, thisCollId); + auto trksThisColl = candsTr.sliceBy(candsTrackPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, trksThisColl); } } - PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processXcToDplusLambda, "Process Xc candidates without Ml info", false); + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDstarTracks, "Process resonances decaying in a Dstar meson and a Track", false); - void processXcToDplusLambdaWithMl(aod::HfRedCollisions const& collisions, - soa::Join const& candsD, - aod::HfRedVzeros const&) + void process2PrTracks(aod::HfRedCollisions const& collisions, + aod::HfRed2PrNoTrks const& candsD, + HfRedTrkNoParams const& candsTr) { 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); + auto candsDThisColl = candsD.sliceBy(cands2PrPerCollision, thisCollId); + auto trksThisColl = candsTr.sliceBy(candsTrackPerCollision, thisCollId); + runCandidateCreation(collision, candsDThisColl, trksThisColl); } } - PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processXcToDplusLambdaWithMl, "Process Xc candidates with Ml info", false); + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, process2PrTracks, "Process resonances decaying in a 2 prong D meson and a Track", false); - void processLambdaDminus(aod::HfRedCollisions const& collisions, - aod::HfRed3PrNoTrks const& candsD, - aod::HfRedVzeros const&) + // Mixed Event Process Functions + void process3ProngV0sMixedEvent(aod::HfRedCollisions const& collisions, + aod::HfRed3PrNoTrks const& candsD, + aod::HfRedVzeros const& candsV0) { - 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); - } + runCandidateCreationMixedEvent(collisions, candsD, candsV0); } - PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processLambdaDminus, "Process LambdaDminus candidates without Ml info", false); + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, process3ProngV0sMixedEvent, "Process mixed events for resonances decaying in a 3 prong D meson and a V0", false); - void processLambdaDminusWithMl(aod::HfRedCollisions const& collisions, - soa::Join const& candsD, - aod::HfRedVzeros const&) + void processDstarV0sMixedEvent(aod::HfRedCollisions const& collisions, + aod::HfRedDstarNoTrks const& candsD, + aod::HfRedVzeros const& candsV0) { - 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); + runCandidateCreationMixedEvent(collisions, candsD, candsV0); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDstarV0sMixedEvent, "Process mixed events for resonances decaying in a Dstar meson and a V0", false); + + void process2PrV0sMixedEvent(aod::HfRedCollisions const& collisions, + aod::HfRed2PrNoTrks const& candsD, + aod::HfRedVzeros const& candsV0) + { + runCandidateCreationMixedEvent(collisions, candsD, candsV0); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, process2PrV0sMixedEvent, "Process mixed events for resonances decaying in a 2 prong D meson and a V0", false); + + void process3ProngTracksMixedEvent(aod::HfRedCollisions const& collisions, + aod::HfRed3PrNoTrks const& candsD, + HfRedTrkNoParams const& candsTr) + { + runCandidateCreationMixedEvent(collisions, candsD, candsTr); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, process3ProngTracksMixedEvent, "Process mixed events for resonances decaying in a 3 prong D meson and a Track", false); + + void processDstarTracksMixedEvent(aod::HfRedCollisions const& collisions, + aod::HfRedDstarNoTrks const& candsD, + HfRedTrkNoParams const& candsTr) + { + runCandidateCreationMixedEvent(collisions, candsD, candsTr); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processDstarTracksMixedEvent, "Process mixed events for resonances decaying in a Dstar meson and a Track", false); + + void process2PrTracksMixedEvent(aod::HfRedCollisions const& collisions, + aod::HfRed2PrNoTrks const& candsD, + HfRedTrkNoParams const& candsTr) + { + runCandidateCreationMixedEvent(collisions, candsD, candsTr); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, process2PrTracksMixedEvent, "Process mixed events for resonances decaying in a 2 prong D meson and a Track", false); + +}; // struct HfCandidateCreatorCharmResoReduced + +struct HfCandidateCreatorCharmResoReducedExpressions { + + Produces rowResoMcRec; + + using CandResoWithIndices2PrV0s = soa::Join; + using CandResoWithIndices2PrTrks = soa::Join; + using CandResoWithIndices3PrV0s = soa::Join; + using CandResoWithIndices3PrTrks = soa::Join; + using CandResoWithIndicesDstarV0s = soa::Join; + using CandResoWithIndicesDstarTrks = 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 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}}); + } + + /// Fill candidate information at MC reconstruction level + /// \param rowsMcRec MC reco information on DPi pairs + /// \param candsReso prong global indices of B0 candidates + template + void fillResoMcRec(McRec const& rowsMcRec, CandResoWithIndices const& candsReso) + { + for (const auto& candReso : candsReso) { + bool filledMcInfo{false}; + for (const auto& rowMcRec : rowsMcRec) { + if ((rowMcRec.prong0Id() != candReso.prong0Id()) || (rowMcRec.prong1Id() != candReso.prong1Id())) { + continue; + } + rowResoMcRec(rowMcRec.flagMcMatchRec(), + rowMcRec.flagMcMatchRecD(), + rowMcRec.flagMcMatchChanD(), + rowMcRec.debugMcRec(), + rowMcRec.origin(), + rowMcRec.ptGen(), + rowMcRec.invMassGen(), + rowMcRec.nTracksDecayed()); + filledMcInfo = true; + if (std::abs(rowMcRec.flagMcMatchRec()) > 0 && + !TESTBIT(rowMcRec.debugMcRec(), hf_decay::hf_cand_reso::PartialMatchMc::ResoPartlyMatched)) { + registry.fill(HIST("hMassMcMatched"), candReso.invMass(), candReso.pt()); + } else if (std::abs(rowMcRec.flagMcMatchRec()) > 0 && + TESTBIT(rowMcRec.debugMcRec(), hf_decay::hf_cand_reso::PartialMatchMc::ResoPartlyMatched)) { + registry.fill(HIST("hMassMcMatchedIncomplete"), candReso.invMass(), candReso.pt()); + } else { + registry.fill(HIST("hMassMcUnmatched"), candReso.invMass(), candReso.pt()); + } + 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, 0, 0, 0, 0, -1.f, -1.f, 0); + registry.fill(HIST("hMassMcNoEntry"), candReso.invMass(), candReso.pt()); + } } } - PROCESS_SWITCH(HfCandidateCreatorCharmResoReduced, processLambdaDminusWithMl, "Process LambdaDminus candidates with Ml info", false); -}; // struct + void processDstarV0Mc(aod::HfDstarV0McRec const& rowsMcRec, CandResoWithIndicesDstarV0s const& candsReso) + { + fillResoMcRec(rowsMcRec, candsReso); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReducedExpressions, processDstarV0Mc, "Process resonances to Dstar V0 MC", false); + + void processDstarTrackMc(aod::HfDstarTrkMcRec const& rowsMcRec, CandResoWithIndicesDstarTrks const& candsReso) + { + fillResoMcRec(rowsMcRec, candsReso); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReducedExpressions, processDstarTrackMc, "Process resonances to Dstar track MC", false); + + void process2PrV0Mc(aod::Hf2PrV0McRec const& rowsMcRec, CandResoWithIndices2PrV0s const& candsReso) + { + fillResoMcRec(rowsMcRec, candsReso); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReducedExpressions, process2PrV0Mc, "Process resonances to D0 V0 MC", false); + + void process2PrTrackMc(aod::Hf2PrTrkMcRec const& rowsMcRec, CandResoWithIndices2PrTrks const& candsReso) + { + fillResoMcRec(rowsMcRec, candsReso); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReducedExpressions, process2PrTrackMc, "Process resonances to D0 track MC", false); + + void process3PrV0Mc(aod::Hf3PrV0McRec const& rowsMcRec, CandResoWithIndices3PrV0s const& candsReso) + { + fillResoMcRec(rowsMcRec, candsReso); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReducedExpressions, process3PrV0Mc, "Process resonances to Dplus V0 MC", false); + + void process3PrTrackMc(aod::Hf3PrTrkMcRec const& rowsMcRec, CandResoWithIndices3PrTrks const& candsReso) + { + fillResoMcRec(rowsMcRec, candsReso); + } + PROCESS_SWITCH(HfCandidateCreatorCharmResoReducedExpressions, process3PrTrackMc, "Process resonances to Dplus track MC", false); + + void processDummy(aod::HfCandCharmReso 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/candidateCreatorLbReduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorLbReduced.cxx new file mode 100644 index 00000000000..77b9457ecb2 --- /dev/null +++ b/PWGHF/D2H/TableProducer/candidateCreatorLbReduced.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 candidateCreatorLbReduced.cxx +/// \brief Reconstruction of Lb candidates +/// +/// \author Biao Zhang , Heidelberg University + +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::constants::physics; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_trkcandsel; + +/// Reconstruction of Lb candidates +struct HfCandidateCreatorLbReduced { + Produces rowCandidateBase; // table defined in CandidateReconstructionTables.h + Produces rowCandidateProngs; // table defined in ReducedDataModel.h + Produces rowCandidateLcMlScores; // 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 Lb is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + // selection + Configurable invMassWindowLcPiTolerance{"invMassWindowLcPiTolerance", 0.01, "invariant-mass window tolerance for LcPi pair preselections (GeV/c2)"}; + + float myInvMassWindowLcPi{1.}; // variable that will store the value of invMassWindowLcPi + float bz{0.}; + + o2::vertexing::DCAFitterN<2> df2; // fitter for B vertex (2-prong vertex fitter) + + using HfRedCollisionsWithExtras = soa::Join; + + Preslice> candsLcPerCollision = 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, doprocessDataWithLcMl}; + 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("hMassLambdaB0ToLcPi", "2-prong candidates;inv. mass (#Lambda_{b}^{0} #rightarrow #Lambda_{c}^{#plus}#pi^{#minus} #rightarrow pK^{#minus}#pi^{#plus}#pi^{#minus}) (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); + } + + template + std::pair computeInvMass2LcPiWindow(Config const& configs, + float invMassWindowLcPiTolerance) + { + + myInvMassWindowLcPi = 0.0f; + for (const auto& config : configs) { + myInvMassWindowLcPi = config.myInvMassWindowLcPi(); + } + + float const deltaMin = MassLambdaB0 - myInvMassWindowLcPi + invMassWindowLcPiTolerance; + float const deltaMax = MassLambdaB0 + myInvMassWindowLcPi - invMassWindowLcPiTolerance; + + float const invMass2LcPiMin = deltaMin * deltaMin; + float const invMass2LcPiMax = deltaMax * deltaMax; + + return {invMass2LcPiMin, invMass2LcPiMax}; + } + + /// Main function to perform Lb candidate creation + /// \param withLcMl is the flag to use the table with ML scores for the Lc daughter (only possible if present in the derived data) + /// \param collision the collision + /// \param candsLcThisColl Lc candidates in this collision + /// \param tracksPionThisCollision pion tracks in this collision + /// \param invMass2LcPiMin minimum Lb invariant-mass + /// \param invMass2LcPiMax maximum Lb invariant-mass + template + void runCandidateCreation(Coll const& collision, + Cands const& candsLcThisColl, + Pions const& tracksPionThisCollision, + float invMass2LcPiMin, + float invMass2LcPiMax) + { + auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + + // Set the magnetic field from ccdb + bz = collision.bz(); + df2.setBz(bz); + + for (const auto& candLc : candsLcThisColl) { + auto trackParCovD = getTrackParCov(candLc); + std::array pVecLc = candLc.pVector(); + + for (const auto& trackPion : tracksPionThisCollision) { + // this track is among daughters + if (trackPion.trackId() == candLc.prong0Id() || trackPion.trackId() == candLc.prong1Id() || trackPion.trackId() == candLc.prong2Id()) { + continue; + } + + auto trackParCovPi = getTrackParCov(trackPion); + std::array pVecPion = trackPion.pVector(); + + // compute invariant mass square and apply selection + auto invMass2LcPi = RecoDecay::m2(std::array{pVecLc, pVecPion}, std::array{MassLambdaCPlus, MassPiPlus}); + if ((invMass2LcPi < invMass2LcPiMin) || (invMass2LcPi > invMass2LcPiMax)) { + continue; + } + // --------------------------------- + // reconstruct the 2-prong Lb 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); + + // LcPi passed Lb reconstruction + + // calculate relevant properties + const auto& secondaryVertexLb = df2.getPCACandidate(); + auto chi2PCA = df2.getChi2AtPCACandidate(); + auto covMatrixPCA = df2.calcPCACovMatrixFlat(); + registry.fill(HIST("hCovSVXX"), covMatrixPCA[0]); + registry.fill(HIST("hCovPVXX"), covMatrixPV[0]); + + // propagate Lc and Pi to the Lb vertex + df2.propagateTracksToVertex(); + // track.getPxPyPzGlo(pVec) modifies pVec of track + df2.getTrack(0).getPxPyPzGlo(pVecLc); // momentum of Lc at the Lb vertex + df2.getTrack(1).getPxPyPzGlo(pVecPion); // momentum of Pi at the Lb vertex + + registry.fill(HIST("hMassLambdaB0ToLcPi"), std::sqrt(invMass2LcPi)); + + // compute impact parameters of D and Pi + o2::dataformats::DCA dcaLc; + o2::dataformats::DCA dcaPion; + trackParCovD.propagateToDCA(primaryVertex, bz, &dcaLc); + 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()}, secondaryVertexLb, 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 Lb here: + rowCandidateBase(collision.globalIndex(), + collision.posX(), collision.posY(), collision.posZ(), + secondaryVertexLb[0], secondaryVertexLb[1], secondaryVertexLb[2], + errorDecayLength, errorDecayLengthXY, + chi2PCA, + pVecLc[0], pVecLc[1], pVecLc[2], + pVecPion[0], pVecPion[1], pVecPion[2], + dcaLc.getY(), dcaPion.getY(), + std::sqrt(dcaLc.getSigmaY2()), std::sqrt(dcaPion.getSigmaY2())); + + rowCandidateProngs(candLc.globalIndex(), trackPion.globalIndex()); + + if constexpr (WithLcMl) { + if (candLc.invMassHypo0() > 0) { + rowCandidateLcMlScores(candLc.mlScoreBkgMassHypo0(), candLc.mlScorePromptMassHypo0(), candLc.mlScoreNonpromptMassHypo0()); + } else { + rowCandidateLcMlScores(candLc.mlScoreBkgMassHypo1(), candLc.mlScorePromptMassHypo1(), candLc.mlScoreNonpromptMassHypo1()); + } + } // pi loop + } // Lc loop + } + } + + void processData(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsLc, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandLbConfigs const& configs) + { + // LcPi invariant-mass window cut + // invMassWindowLcPiTolerance is used to apply a slightly tighter cut than in LcPi pair preselection + // to avoid accepting LcPi pairs that were not formed in LcPi pair creator + auto [invMass2LcPiMin, invMass2LcPiMax] = computeInvMass2LcPiWindow(configs, invMassWindowLcPiTolerance); + + for (const auto& collisionCounter : collisionsCounter) { + registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); + } + + static int ncol = 0; + static constexpr int PrintFrequency = 10000; + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsLcThisColl = candsLc.sliceBy(candsLcPerCollision, thisCollId); + auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); + runCandidateCreation(collision, candsLcThisColl, tracksPionThisCollision, invMass2LcPiMin, invMass2LcPiMax); + if (ncol % PrintFrequency == 0) { + LOGP(debug, "collisions parsed {}", ncol); + } + ncol++; + } + } // processData + + PROCESS_SWITCH(HfCandidateCreatorLbReduced, processData, "Process data without any ML score", true); + + void processDataWithLcMl(HfRedCollisionsWithExtras const& collisions, + soa::Join const& candsLc, + soa::Join const& tracksPion, + aod::HfOrigColCounts const& collisionsCounter, + aod::HfCandLbConfigs const& configs) + { + // LcPi invariant-mass window cut + // invMassWindowLcPiTolerance is used to apply a slightly tighter cut than in LcPi pair preselection + // to avoid accepting LcPi pairs that were not formed in LcPi pair creator + auto [invMass2LcPiMin, invMass2LcPiMax] = computeInvMass2LcPiWindow(configs, invMassWindowLcPiTolerance); + + for (const auto& collisionCounter : collisionsCounter) { + registry.fill(HIST("hEvents"), 1, collisionCounter.originalCollisionCount()); + } + + static int ncol = 0; + static constexpr int PrintFrequency = 10000; + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsLcThisColl = candsLc.sliceBy(candsLcPerCollision, thisCollId); + auto tracksPionThisCollision = tracksPion.sliceBy(tracksPionPerCollision, thisCollId); + runCandidateCreation(collision, candsLcThisColl, tracksPionThisCollision, invMass2LcPiMin, invMass2LcPiMax); + if (ncol % PrintFrequency == 0) { + LOGP(debug, "collisions parsed {}", ncol); + } + ncol++; + } + } // processDataWithLcMl + + PROCESS_SWITCH(HfCandidateCreatorLbReduced, processDataWithLcMl, "Process data with ML scores of Lc", false); +}; // struct + +/// Extends the table base with expression columns and performs MC matching. +struct HfCandidateCreatorLbReducedExpressions { + Spawns rowCandidateLb; + Spawns rowTracksExt; + Produces rowLbMcRec; + Produces rowLbMcCheck; + + /// Fill candidate information at MC reconstruction level + /// \param checkDecayTypeMc + /// \param rowsLcPiMcRec MC reco information on LcPi pairs + /// \param candsLb prong global indices of Lb candidates + template + void fillLbMcRec(McRec const& rowsLcPiMcRec, HfRedLbProngs const& candsLb) + { + for (const auto& candLb : candsLb) { + bool filledMcInfo{false}; + for (const auto& rowLcPiMcRec : rowsLcPiMcRec) { + if ((rowLcPiMcRec.prong0Id() != candLb.prong0Id()) || (rowLcPiMcRec.prong1Id() != candLb.prong1Id())) { + continue; + } + rowLbMcRec(rowLcPiMcRec.flagMcMatchRec(), rowLcPiMcRec.flagWrongCollision(), rowLcPiMcRec.debugMcRec(), rowLcPiMcRec.ptMother()); + filledMcInfo = true; + if constexpr (CheckDecayTypeMc) { + rowLbMcCheck(rowLcPiMcRec.pdgCodeBeautyMother(), + rowLcPiMcRec.pdgCodeCharmMother(), + rowLcPiMcRec.pdgCodeProng0(), + rowLcPiMcRec.pdgCodeProng1(), + rowLcPiMcRec.pdgCodeProng2(), + rowLcPiMcRec.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 LcPi creator + rowLbMcRec(0, -1, -1, -1.f); + if constexpr (CheckDecayTypeMc) { + rowLbMcCheck(-1, -1, -1, -1, -1, -1); + } + } + } + } + + void processMc(HfMcRecRedLcPis const& rowsLcPiMcRec, HfRedLbProngs const& candsLb) + { + fillLbMcRec(rowsLcPiMcRec, candsLb); + } + PROCESS_SWITCH(HfCandidateCreatorLbReducedExpressions, processMc, "Process MC", false); + + void processMcWithDecayTypeCheck(soa::Join const& rowsLcPiMcRec, HfRedLbProngs const& candsLb) + { + fillLbMcRec(rowsLcPiMcRec, candsLb); + } + PROCESS_SWITCH(HfCandidateCreatorLbReducedExpressions, 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/candidateSelectorB0ToDPiReduced.cxx b/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx index 5bf352517e4..3913e7f0fca 100644 --- a/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx @@ -15,22 +15,42 @@ /// \author Alexandre Bigot , IPHC Strasbourg /// \author Fabrizio Grosa , CERN -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -#include "Common/Core/TrackSelectorPID.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponseB0ToDPi.h" #include "PWGHF/Core/SelectorCuts.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::analysis; +using namespace o2::aod::pid_tpc_tof_utils; struct HfCandidateSelectorB0ToDPiReduced { Produces hfSelB0ToDPiCandidate; // table defined in CandidateSelectionTables.h @@ -39,7 +59,7 @@ struct HfCandidateSelectorB0ToDPiReduced { 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 pionPidMethod{"pionPidMethod", PidMethod::TpcOrTof, "PID selection method for the bachelor pion (PidMethod::NoPid: none, PidMethod::TpcOrTof: TPC or TOF, PidMethod::TpcAndTof: 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 +73,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"}; @@ -75,30 +95,30 @@ struct HfCandidateSelectorB0ToDPiReduced { // variable that will store the value of selectionFlagD (defined in dataCreatorDplusPiReduced.cxx) int mySelectionFlagD = -1; - o2::analysis::HfMlResponseB0ToDPi hfMlResponse; + o2::analysis::HfMlResponseB0ToDPi hfMlResponse; float outputMlNotPreselected = -1.; - std::vector outputMl = {}; + std::vector outputMl; o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; - HfHelper hfHelper; - using TracksPion = soa::Join; + using TracksBachPion = soa::Join; + using TracksSoftPions = soa::Join; HistogramRegistry registry{"registry"}; void init(InitContext const&) { - std::array doprocess{doprocessSelection, doprocessSelectionWithDmesMl}; + std::array doprocess{doprocessSelectionDplusPi, doprocessSelectionDplusPiWithDmesMl, doprocessSelectionDstarPi, doprocessSelectionDstarPiWithDmesMl}; 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) { + if (pionPidMethod < 0 || pionPidMethod >= PidMethod::NPidMethods) { LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); } - if (pionPidMethod) { + if (pionPidMethod != PidMethod::NoPid) { selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); @@ -114,6 +134,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) { @@ -134,14 +155,63 @@ struct HfCandidateSelectorB0ToDPiReduced { } } + /// Utility function to retrieve the bach pion track + /// from the B0 candidate in the D*-pi decay channel + /// \param candidate is the B0 candidate + /// \return bach pion track + template + auto getTrackBachPi(const T1& candidate) + { + return candidate.template prongBachPi_as(); + } + + /// Method to get the input features vector needed for ML inference + /// \param candidate is the B0 candidate + /// \param prongBachPi is the candidate's bachelor pion prong + /// \note this method is used for B0 → D*- π+ candidates with D meson ML scores + template + auto getMlInputFeatures(const T1& candB0, const T2& prongBachPi) + { + auto prongSoftPi = candB0.template prongSoftPi_as(); + if constexpr (WithDmesMl) { + return hfMlResponse.getInputFeaturesDStarPi(candB0, prongBachPi, prongSoftPi); + } else { + return hfMlResponse.getInputFeaturesDStarPi(candB0, prongBachPi, prongSoftPi); + } + } + + /// Utility function to retrieve the bach pion track + /// from the B0 candidate in the D-pi decay channel + /// \param candidate is the B0 candidate + /// \return bach pion track + template + auto getTrackBachPi(const T1& candidate) + { + return candidate.template prong1_as(); + } + + /// Method to get the input features vector needed for ML inference + /// \param candB0 is the B0 candidate + /// \param prongBachPi is the candidate's bachelor pion prong + /// \note this method is used for B0 → D- π+ candidates with D meson ML scores + template + auto getMlInputFeatures(const T1& candB0, const T2& prongBachPi) + { + if constexpr (WithDmesMl) { + return hfMlResponse.getInputFeatures(candB0, prongBachPi); + } else { + return hfMlResponse.getInputFeatures(candB0, prongBachPi); + } + } + /// Main function to perform B0 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 hfCandsB0 B0 candidates /// \param pionTracks pion tracks /// \param configs config inherited from the Dpi data creator - template + template void runSelection(Cands const& hfCandsB0, - TracksPion const&, + TracksBachPion const&, HfCandB0Configs const& configs) { // get DplusPi creator configurable @@ -159,7 +229,7 @@ struct HfCandidateSelectorB0ToDPiReduced { } // topological cuts - if (!hfHelper.selectionB0ToDPiTopol(hfCandB0, cuts, binsPt)) { + if (!HfHelper::selectionB0ToDPiTopol(hfCandB0, cuts, binsPt)) { hfSelB0ToDPiCandidate(statusB0ToDPi); if (applyB0Ml) { hfMlB0ToDPiCandidate(outputMlNotPreselected); @@ -168,8 +238,8 @@ struct HfCandidateSelectorB0ToDPiReduced { continue; } - if constexpr (withDmesMl) { // we include it in the topological selections - if (!hfHelper.selectionDmesMlScoresForB(hfCandB0, cutsDmesMl, binsPtDmesMl)) { + if constexpr (WithDmesMl) { // we include it in the topological selections + if (!HfHelper::selectionDmesMlScoresForBReduced(hfCandB0, cutsDmesMl, binsPtDmesMl)) { hfSelB0ToDPiCandidate(statusB0ToDPi); if (applyB0Ml) { hfMlB0ToDPiCandidate(outputMlNotPreselected); @@ -184,16 +254,15 @@ struct HfCandidateSelectorB0ToDPiReduced { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoTopol, ptCandB0); } - // track-level PID selection - auto trackPi = hfCandB0.template prong1_as(); - if (pionPidMethod) { - int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; - if (pionPidMethod == 1) { - pidTrackPi = selectorPion.statusTpcOrTof(trackPi); - } else { - pidTrackPi = selectorPion.statusTpcAndTof(trackPi); + auto trackBachPi = getTrackBachPi(hfCandB0); + if (pionPidMethod == PidMethod::TpcOrTof || pionPidMethod == PidMethod::TpcAndTof) { + int pidTrackBachPi{TrackSelectorPID::Status::NotApplicable}; + if (pionPidMethod == PidMethod::TpcOrTof) { + pidTrackBachPi = selectorPion.statusTpcOrTof(trackBachPi); + } else if (pionPidMethod == PidMethod::TpcAndTof) { + pidTrackBachPi = selectorPion.statusTpcAndTof(trackBachPi); } - if (!hfHelper.selectionB0ToDPiPid(pidTrackPi, acceptPIDNotApplicable.value)) { + if (!HfHelper::selectionB0ToDPiPid(pidTrackBachPi, acceptPIDNotApplicable.value)) { // LOGF(info, "B0 candidate selection failed at PID selection"); hfSelB0ToDPiCandidate(statusB0ToDPi); if (applyB0Ml) { @@ -206,11 +275,10 @@ struct HfCandidateSelectorB0ToDPiReduced { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandB0); } } - if (applyB0Ml) { // B0 ML selections - std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandB0, trackPi); - bool isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandB0, outputMl); + std::vector inputFeatures = getMlInputFeatures(hfCandB0, trackBachPi); + bool const isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandB0, outputMl); hfMlB0ToDPiCandidate(outputMl[1]); // storing ML score for signal class if (!isSelectedMl) { @@ -228,23 +296,43 @@ struct HfCandidateSelectorB0ToDPiReduced { } } - void processSelection(HfRedCandB0 const& hfCandsB0, - TracksPion const& pionTracks, - HfCandB0Configs const& configs) + void processSelectionDplusPi(HfRedCandB0 const& hfCandsB0, + TracksBachPion const& pionTracks, + HfCandB0Configs const& configs) + { + runSelection(hfCandsB0, pionTracks, configs); + } // processSelectionDplusPi + + PROCESS_SWITCH(HfCandidateSelectorB0ToDPiReduced, processSelectionDplusPi, "Process selection DplusPi without ML scores of D mesons", true); + + void processSelectionDplusPiWithDmesMl(soa::Join const& hfCandsB0, + TracksBachPion const& pionTracks, + HfCandB0Configs const& configs) + { + runSelection(hfCandsB0, pionTracks, configs); + } // processSelectionDplusPiWithDmesMl + + PROCESS_SWITCH(HfCandidateSelectorB0ToDPiReduced, processSelectionDplusPiWithDmesMl, "Process selection DplusPi with ML scores of D mesons", false); + + void processSelectionDstarPi(HfRedCandB0DStar const& hfCandsB0, + TracksBachPion const& pionTracks, + HfCandB0Configs const& configs, + TracksSoftPions const& /*softPions*/) { runSelection(hfCandsB0, pionTracks, configs); - } // processSelection + } // processSelectionDstarPi - PROCESS_SWITCH(HfCandidateSelectorB0ToDPiReduced, processSelection, "Process selection without ML scores of D mesons", true); + PROCESS_SWITCH(HfCandidateSelectorB0ToDPiReduced, processSelectionDstarPi, "Process selection DstarPi without ML scores of D mesons", false); - void processSelectionWithDmesMl(soa::Join const& hfCandsB0, - TracksPion const& pionTracks, - HfCandB0Configs const& configs) + void processSelectionDstarPiWithDmesMl(soa::Join const& hfCandsB0, + TracksBachPion const& pionTracks, + HfCandB0Configs const& configs, + TracksSoftPions const& /*softPions*/) { runSelection(hfCandsB0, pionTracks, configs); - } // processSelectionWithDmesMl + } // processSelectionDstarPiWithDmesMl - PROCESS_SWITCH(HfCandidateSelectorB0ToDPiReduced, processSelectionWithDmesMl, "Process selection with ML scores of D mesons", false); + PROCESS_SWITCH(HfCandidateSelectorB0ToDPiReduced, processSelectionDstarPiWithDmesMl, "Process selection DstarPi with ML scores of D mesons", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx b/PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx index b10dfe22752..e9088c68e93 100644 --- a/PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx @@ -14,22 +14,42 @@ /// /// \author Antonio Palasciano , Università degli Studi di Bari -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -#include "Common/Core/TrackSelectorPID.h" - #include "PWGHF/Core/HfHelper.h" -#include "PWGHF/Core/HfMlResponseBplusToD0Pi.h" +#include "PWGHF/Core/HfMlResponseBplusToD0PiReduced.h" #include "PWGHF/Core/SelectorCuts.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::analysis; +using namespace o2::aod::pid_tpc_tof_utils; struct HfCandidateSelectorBplusToD0PiReduced { Produces hfSelBplusToD0PiCandidate; // table defined in CandidateSelectionTables.h @@ -38,7 +58,7 @@ struct HfCandidateSelectorBplusToD0PiReduced { 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 pionPidMethod{"pionPidMethod", PidMethod::TpcOrTof, "PID selection method for the bachelor pion (PidMethod::NoPid: none, PidMethod::TpcOrTof: TPC or TOF, PidMethod::TpcAndTof: 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"}; @@ -52,18 +72,18 @@ 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"}; + 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", (int8_t)hf_cuts_ml::nCutScores, "Number of classes in ML model"}; + 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"}; @@ -75,18 +95,17 @@ struct HfCandidateSelectorBplusToD0PiReduced { int mySelectionFlagD0 = -1; int mySelectionFlagD0bar = -1; - o2::analysis::HfMlResponseBplusToD0Pi hfMlResponse; + o2::analysis::HfMlResponseBplusToD0PiReduced hfMlResponse; float outputMlNotPreselected = -1.; - std::vector outputMl = {}; + std::vector outputMl; o2::ccdb::CcdbApi ccdbApi; - HfHelper hfHelper; TrackSelectorPi selectorPion; - HistogramRegistry registry{"registry"}; - using TracksPion = soa::Join; + HistogramRegistry registry{"registry"}; + void init(InitContext const&) { std::array doprocess{doprocessSelection, doprocessSelectionWithDmesMl}; @@ -94,11 +113,11 @@ struct HfCandidateSelectorBplusToD0PiReduced { LOGP(fatal, "Only one process function for data should be enabled at a time."); } - if (pionPidMethod < 0 || pionPidMethod > 2) { + if (pionPidMethod < 0 || pionPidMethod >= PidMethod::NPidMethods) { LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); } - if (pionPidMethod) { + if (pionPidMethod != PidMethod::NoPid) { selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); @@ -114,6 +133,7 @@ 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) { @@ -139,7 +159,7 @@ struct HfCandidateSelectorBplusToD0PiReduced { /// \param hfCandsBp B+ candidates /// \param pionTracks pion tracks /// \param configs config inherited from the D0pi data creator - template + template void runSelection(Cands const& hfCandsBp, TracksPion const& /*pionTracks*/, HfCandBpConfigs const& configs) @@ -160,7 +180,7 @@ struct HfCandidateSelectorBplusToD0PiReduced { } // topological cuts - if (!hfHelper.selectionBplusToD0PiTopol(hfCandBp, cuts, binsPt)) { + if (!HfHelper::selectionBplusToD0PiTopol(hfCandBp, cuts, binsPt)) { hfSelBplusToD0PiCandidate(statusBplus); if (applyBplusMl) { hfMlBplusToD0PiCandidate(outputMlNotPreselected); @@ -169,8 +189,8 @@ struct HfCandidateSelectorBplusToD0PiReduced { continue; } - if constexpr (withDmesMl) { // we include it in the topological selections - if (!hfHelper.selectionDmesMlScoresForB(hfCandBp, cutsDmesMl, binsPtDmesMl)) { + if constexpr (WithDmesMl) { // we include it in the topological selections + if (!HfHelper::selectionDmesMlScoresForBReduced(hfCandBp, cutsDmesMl, binsPtDmesMl)) { hfSelBplusToD0PiCandidate(statusBplus); if (applyBplusMl) { hfMlBplusToD0PiCandidate(outputMlNotPreselected); @@ -187,14 +207,14 @@ struct HfCandidateSelectorBplusToD0PiReduced { // track-level PID selection auto trackPi = hfCandBp.template prong1_as(); - if (pionPidMethod) { + if (pionPidMethod == PidMethod::TpcOrTof || pionPidMethod == PidMethod::TpcAndTof) { int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; - if (pionPidMethod == 1) { + if (pionPidMethod == PidMethod::TpcOrTof) { pidTrackPi = selectorPion.statusTpcOrTof(trackPi); - } else { + } else if (pionPidMethod == PidMethod::TpcAndTof) { pidTrackPi = selectorPion.statusTpcAndTof(trackPi); } - if (!hfHelper.selectionBplusToD0PiPid(pidTrackPi, acceptPIDNotApplicable.value)) { + if (!HfHelper::selectionBplusToD0PiPid(pidTrackPi, acceptPIDNotApplicable.value)) { // LOGF(info, "B+ candidate selection failed at PID selection"); hfSelBplusToD0PiCandidate(statusBplus); if (applyBplusMl) { @@ -209,8 +229,8 @@ struct HfCandidateSelectorBplusToD0PiReduced { } if (applyBplusMl) { // B+ ML selections - std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandBp, trackPi); - bool isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandBplus, outputMl); + std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandBp, trackPi); + bool const isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandBplus, outputMl); hfMlBplusToD0PiCandidate(outputMl[1]); // storing ML score for signal class if (!isSelectedMl) { diff --git a/PWGHF/D2H/TableProducer/candidateSelectorBsToDsPiReduced.cxx b/PWGHF/D2H/TableProducer/candidateSelectorBsToDsPiReduced.cxx new file mode 100644 index 00000000000..988df046c06 --- /dev/null +++ b/PWGHF/D2H/TableProducer/candidateSelectorBsToDsPiReduced.cxx @@ -0,0 +1,261 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseBsToDsPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::analysis; +using namespace o2::aod::pid_tpc_tof_utils; + +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", PidMethod::TpcOrTof, "PID selection method for the bachelor pion (PidMethod::NoPid: none, PidMethod::TpcOrTof: TPC or TOF, PidMethod::TpcAndTof: 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; + + 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 >= PidMethod::NPidMethods) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (pionPidMethod != PidMethod::NoPid) { + 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 == PidMethod::TpcOrTof || pionPidMethod == PidMethod::TpcAndTof) { + int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; + if (pionPidMethod == PidMethod::TpcOrTof) { + pidTrackPi = selectorPion.statusTpcOrTof(trackPi); + } else if (pionPidMethod == PidMethod::TpcAndTof) { + 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 const 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/candidateSelectorLbToLcPiReduced.cxx b/PWGHF/D2H/TableProducer/candidateSelectorLbToLcPiReduced.cxx new file mode 100644 index 00000000000..705f23ae97e --- /dev/null +++ b/PWGHF/D2H/TableProducer/candidateSelectorLbToLcPiReduced.cxx @@ -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 candidateSelectorLbToLcPiReduced.cxx +/// \brief Lb → Lc+ π- candidate selector +/// +/// \author Biao Zhang , Heidelberg University + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseLbToLcPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::analysis; +using namespace o2::aod::pid_tpc_tof_utils; + +struct HfCandidateSelectorLbToLcPiReduced { + Produces hfSelLbToLcPiCandidate; // table defined in CandidateSelectionTables.h + Produces hfMlLbToLcPiCandidate; // 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", PidMethod::TpcOrTof, "PID selection method for the bachelor pion (PidMethod::NoPid: none, PidMethod::TpcOrTof: TPC or TOF, PidMethod::TpcAndTof: 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_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}, "Lb candidate selection per pT bin"}; + // Lc ML cuts + Configurable> binsPtLcMl{"binsPtLcMl", std::vector{hf_cuts_ml::vecBinsPt}, "Lc pT bin limits for ML cuts"}; + Configurable> cutsLcMl{"cutsLcMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsDmesCutScore}, "Lc ML cuts per pT bin"}; + // QA switch + Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; + // Lb ML inference + Configurable applyLbMl{"applyLbMl", false, "Flag to apply ML selections"}; + Configurable> binsPtLbMl{"binsPtLbMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; + Configurable> cutDirLbMl{"cutDirLbMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cutsLbMl{"cutsLbMl", {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 nClassesLbMl{"nClassesLbMl", 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_Lb/"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_LbToLcPi.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::HfMlResponseLbToLcPi hfMlResponse; + float outputMlNotPreselected = -1.; + std::vector outputMl; + o2::ccdb::CcdbApi ccdbApi; + + TrackSelectorPi selectorPion; + + using TracksPion = soa::Join; + + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + std::array doprocess{doprocessSelection, doprocessSelectionWithLcMl}; + 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 >= PidMethod::NPidMethods) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (pionPidMethod != PidMethod::NoPid) { + 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 (applyLbMl) { + hfMlResponse.configure(binsPtLbMl, cutsLbMl, cutDirLbMl, nClassesLbMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponse.setModelPathsLocal(onnxFileNames); + } + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); + } + } + + /// Main function to perform Lb candidate selection + /// \param withLcMl is the flag to use the table with ML scores for the Ds- daughter (only possible if present in the derived data) + /// \param hfCandsLb Lb candidates + /// \param pionTracks pion tracks + /// \param configs config inherited from the charm-hadron data creator + template + void runSelection(Cands const& hfCandsLb, + TracksPion const&, + HfCandLbConfigs const&) + { + for (const auto& hfCandLb : hfCandsLb) { + int statusLbToLcPi = 0; + outputMl.clear(); + auto ptCandLb = hfCandLb.pt(); + + SETBIT(statusLbToLcPi, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusLbToLcPi = 1 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandLb); + } + + // topological cuts + if (!HfHelper::selectionLbToLcPiTopol(hfCandLb, cuts, binsPt)) { + hfSelLbToLcPiCandidate(statusLbToLcPi); + if (applyLbMl) { + hfMlLbToLcPiCandidate(outputMlNotPreselected); + } + continue; + } + + if constexpr (WithLcMl) { // we include it in the topological selections + if (!HfHelper::selectionDmesMlScoresForBReduced(hfCandLb, cutsLcMl, binsPtLcMl)) { + hfSelLbToLcPiCandidate(statusLbToLcPi); + if (applyLbMl) { + hfMlLbToLcPiCandidate(outputMlNotPreselected); + } + continue; + } + } + + SETBIT(statusLbToLcPi, SelectionStep::RecoTopol); // RecoTopol = 1 --> statusLbToLcPi = 3 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoTopol, ptCandLb); + } + + // track-level PID selection + auto trackPi = hfCandLb.template prong1_as(); + if (pionPidMethod == PidMethod::TpcOrTof || pionPidMethod == PidMethod::TpcAndTof) { + int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; + if (pionPidMethod == PidMethod::TpcOrTof) { + pidTrackPi = selectorPion.statusTpcOrTof(trackPi); + } else if (pionPidMethod == PidMethod::TpcAndTof) { + pidTrackPi = selectorPion.statusTpcAndTof(trackPi); + } + if (!HfHelper::selectionLbToLcPiPid(pidTrackPi, acceptPIDNotApplicable.value)) { + hfSelLbToLcPiCandidate(statusLbToLcPi); + if (applyLbMl) { + hfMlLbToLcPiCandidate(outputMlNotPreselected); + } + continue; + } + SETBIT(statusLbToLcPi, SelectionStep::RecoPID); // RecoPID = 2 --> statusLbToLcPi = 7 + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandLb); + } + } + + if (applyLbMl) { + // Lb ML selections + std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandLb, trackPi); + bool const isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandLb, outputMl); + hfMlLbToLcPiCandidate(outputMl[1]); + + if (!isSelectedMl) { + hfSelLbToLcPiCandidate(statusLbToLcPi); + continue; + } + SETBIT(statusLbToLcPi, SelectionStep::RecoMl); // RecoML = 3 --> statusLbToLcPi = 15 if PidMethod, 11 otherwise + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoMl, ptCandLb); + } + } + + hfSelLbToLcPiCandidate(statusLbToLcPi); + } + } + + void processSelection(HfRedCandLb const& hfCandsLb, + TracksPion const& pionTracks, + HfCandLbConfigs const& configs) + { + runSelection(hfCandsLb, pionTracks, configs); + } // processSelection + + PROCESS_SWITCH(HfCandidateSelectorLbToLcPiReduced, processSelection, "Process selection without ML scores of Lc", true); + + void processSelectionWithLcMl(soa::Join const& hfCandsLb, + TracksPion const& pionTracks, + HfCandLbConfigs const& configs) + { + runSelection(hfCandsLb, pionTracks, configs); + } // processSelectionwithLcMl + + PROCESS_SWITCH(HfCandidateSelectorLbToLcPiReduced, processSelectionWithLcMl, "Process selection with ML scores of Lc", 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..90360a29cc0 --- /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 "PWGHF/D2H/DataModel/ReducedDataModel.h" + +#include +#include +#include + +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/converterReducedHadronDausPid.cxx b/PWGHF/D2H/TableProducer/converterReducedHadronDausPid.cxx new file mode 100644 index 00000000000..d1bf2d4e47c --- /dev/null +++ b/PWGHF/D2H/TableProducer/converterReducedHadronDausPid.cxx @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file converterReducedHadronDausPid.cxx +/// \brief Task for conversion of daughters pid to version 001 +/// +/// \author Biao Zhang , Heidelberg University + +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +struct HfConverterReducedHadronDausPid { + Produces hfRedPidDau0s; + Produces hfRedPidDau1s; + Produces hfRedPidDau2s; + + using HfRedPidDaus2Prong = soa::Join; + using HfRedPidDaus3Prong = soa::Join; + + void process2Prongs(HfRedPidDaus2Prong::iterator const& hfCandPidProngs) + { + hfRedPidDau0s(hfCandPidProngs.tpcNSigmaPiProng0(), hfCandPidProngs.tofNSigmaPiProng0(), hfCandPidProngs.tpcNSigmaKaProng0(), hfCandPidProngs.tofNSigmaKaProng0(), -999.f, -999.f, hfCandPidProngs.hasTOFProng0(), hfCandPidProngs.hasTPCProng0()); + hfRedPidDau1s(hfCandPidProngs.tpcNSigmaPiProng1(), hfCandPidProngs.tofNSigmaPiProng1(), hfCandPidProngs.tpcNSigmaKaProng1(), hfCandPidProngs.tofNSigmaKaProng1(), -999.f, -999.f, hfCandPidProngs.hasTOFProng1(), hfCandPidProngs.hasTPCProng1()); + } + PROCESS_SWITCH(HfConverterReducedHadronDausPid, process2Prongs, "Produce PID tables for 2-prong candidates", false); + + void process3Prongs(HfRedPidDaus3Prong::iterator const& hfCandPidProngs) + { + hfRedPidDau0s(hfCandPidProngs.tpcNSigmaPiProng0(), hfCandPidProngs.tofNSigmaPiProng0(), hfCandPidProngs.tpcNSigmaKaProng0(), hfCandPidProngs.tofNSigmaKaProng0(), -999.f, -999.f, hfCandPidProngs.hasTOFProng0(), hfCandPidProngs.hasTPCProng0()); + hfRedPidDau1s(hfCandPidProngs.tpcNSigmaPiProng1(), hfCandPidProngs.tofNSigmaPiProng1(), hfCandPidProngs.tpcNSigmaKaProng1(), hfCandPidProngs.tofNSigmaKaProng1(), -999.f, -999.f, hfCandPidProngs.hasTOFProng1(), hfCandPidProngs.hasTPCProng1()); + hfRedPidDau2s(hfCandPidProngs.tpcNSigmaPiProng2(), hfCandPidProngs.tofNSigmaPiProng2(), hfCandPidProngs.tpcNSigmaKaProng2(), hfCandPidProngs.tofNSigmaKaProng2(), -999.f, -999.f, hfCandPidProngs.hasTOFProng2(), hfCandPidProngs.hasTPCProng2()); + } + PROCESS_SWITCH(HfConverterReducedHadronDausPid, process3Prongs, "Produce PID tables for 3-prong candidates", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx index da170115da2..a9d569cb32c 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx @@ -15,27 +15,71 @@ /// \author Alexandre Bigot , IPHC Strasbourg /// \author Antonio Palasciano , Università degli Studi di Bari /// \author Fabrizio Grosa , CERN +/// \author Fabio Catalano , CERN +/// \author Biao Zhang , Heidelberg University -#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/DataModel/CollisionAssociationTables.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsEvSelHf.h" -#include "PWGHF/D2H/DataModel/ReducedDataModel.h" #include "PWGHF/Utils/utilsTrkCandHf.h" -#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -55,150 +99,242 @@ enum Event : uint8_t { enum DecayChannel : uint8_t { B0ToDminusPi = 0, BplusToD0barPi, + BsToDsminusPi, + LbToLcplusPi, + B0ToDstarPi +}; + +enum WrongCollisionType : uint8_t { + None = 0, + WrongAssociation, + SplitCollision, }; /// Creation of CharmHad-Pi pairs for Beauty hadrons struct HfDataCreatorCharmHadPiReduced { // Produces AOD tables to store track information // collision related tables - Produces hfReducedCollision; - Produces hfReducedCollExtra; - Produces hfCollisionCounter; - // Pi bachelor related tables - Produces hfTrackPion; - Produces hfTrackCovPion; - Produces hfTrackPidPion; - // charm hadron related tables - Produces hfCand2Prong; - Produces hfCand2ProngCov; - Produces hfCand2ProngMl; - Produces hfCand3Prong; - Produces hfCand3ProngCov; - Produces hfCand3ProngMl; - // B-hadron config and MC related tables - Produces rowCandidateConfigB0; - Produces rowHfDPiMcRecReduced; - Produces rowHfDPiMcCheckReduced; - Produces rowHfB0McGenReduced; - - Produces rowCandidateConfigBplus; - Produces rowHfD0PiMcRecReduced; - Produces rowHfD0PiMcCheckReduced; - Produces rowHfBpMcGenReduced; - + struct : ProducesGroup { + Produces hfReducedCollision; + Produces hfReducedCollCentrality; + Produces hfReducedQvector; + Produces hfReducedCollExtra; + Produces hfCollisionCounter; + // Pi bachelor related tables + Produces hfTrackPion; + Produces hfTrackCovPion; + Produces hfTrackPidPion; + Produces hfTrackMomPion; + // charm hadron related tables + Produces hfCand2Prong; + Produces hfCand2ProngCov; + Produces hfCand2ProngMl; + Produces hfCand3Prong; + Produces hfCand3ProngCov; + Produces hfCand3ProngMl; + Produces hfMomDMesDaugs; + // D* related tables + Produces hfTrackSoftPion; + Produces hfTrackCovSoftPion; + Produces hfTrackPidSoftPion; + // 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; + Produces rowHfDPiMcCheckReduced; + Produces rowHfDStarPiMcRecReduced; + Produces rowHfB0McGenReduced; + + Produces rowCandidateConfigBplus; + Produces rowHfD0PiMcRecReduced; + Produces rowHfD0PiMcCheckReduced; + Produces rowHfBpMcGenReduced; + + Produces rowCandidateConfigBs; + Produces rowHfDsPiMcRecReduced; + Produces rowHfDsPiMcCheckReduced; + Produces rowHfBsMcGenReduced; + + Produces rowCandidateConfigLb; + Produces rowHfLcPiMcRecReduced; + Produces rowHfLcPiMcCheckReduced; + Produces rowHfLbMcGenReduced; + } tables; + + // generic configurables + struct : o2::framework::ConfigurableGroup { + // event selection + Configurable skipRejectedCollisions{"skipRejectedCollisions", true, "skips collisions rejected by the event selection, instead of flagging only"}; + // magnetic field setting from CCDB + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + // pair selection + Configurable invMassWindowCharmHadPi{"invMassWindowCharmHadPi", 0.3, "invariant-mass window for CharmHad-Pi pair preselections (GeV/c2)"}; + // MC extra + Configurable checkDecayTypeMc{"checkDecayTypeMc", false, "flag to enable MC checks on decay type"}; + } configs; // vertexing - // Configurable bz{"bz", 5., "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 B0 is smaller than this"}; - Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + struct : o2::framework::ConfigurableGroup { + 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 B0 is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + } vertexConfigurations; // 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> 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 invMassWindowCharmHadPi{"invMassWindowCharmHadPi", 0.3, "invariant-mass window for CharmHad-Pi pair preselections (GeV/c2)"}; - Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for D+"}; - Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; - Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; - - // magnetic field setting from CCDB - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; - - // MC extra - Configurable checkDecayTypeMc{"checkDecayTypeMc", false, "flag to enable MC checks on decay type"}; - - HfHelper hfHelper; + struct : o2::framework::ConfigurableGroup { + Configurable usePionIsGlobalTrackWoDCA{"usePionIsGlobalTrackWoDCA", true, "check isGlobalTrackWoDCA status for pions, for Run3 studies"}; + Configurable ptPionMin{"ptPionMin", 0.5, "minimum pion pT threshold (GeV/c)"}; + Configurable etaPionMax{"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"}; + } trackPionConfigurations; + // HF flags + struct : o2::framework::ConfigurableGroup { + 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"}; + Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; + Configurable selectionFlagDstar{"selectionFlagDstar", true, "Selection Flag for D* decay to D0 Pi"}; + } hfflagConfigurations; + o2::hf_evsel::HfEventSelection hfEvSel; + o2::hf_evsel::HfEventSelectionMc hfEvSelMc; // CCDB service Service ccdb; o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - int runNumber; + int runNumber{}; // O2DatabasePDG service Service pdg; - double massPi{0.}; double massC{0.}; double massB{0.}; double invMass2ChHadPiMin{0.}; double invMass2ChHadPiMax{0.}; double bz{0.}; - + static constexpr std::size_t NDaughtersDs{2u}; + static constexpr std::size_t NDaughtersDstar{2u}; bool isHfCandBhadConfigFilled = false; // Fitter to redo D-vertex to get extrapolated daughter tracks (2/3-prong vertex filter) 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>; - - Filter filterSelectDplusCandidates = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus); - 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 candsD0PerCollision = aod::track_association::collisionId; - Preslice candsD0PerCollisionWithMl = aod::track_association::collisionId; - Preslice trackIndicesPerCollision = aod::track_association::collisionId; - - std::shared_ptr hCandidatesD0, hCandidatesDPlus; + using CandsDplusFiltered = soa::Filtered>; + using CandsDplusFilteredWithMl = soa::Filtered>; + using CandsDsFiltered = soa::Filtered>; + using CandsDsFilteredWithMl = soa::Filtered>; + using CandsD0Filtered = soa::Filtered>; + using CandsD0FilteredWithMl = soa::Filtered>; + using CandsLcFiltered = soa::Filtered>; + using CandsLcFilteredWithMl = soa::Filtered>; + using CandsDstarFiltered = soa::Filtered>; + using CandsDstarFilteredWithMl = soa::Filtered>; + + using CollisionsWCent = soa::Join; + using CollisionsWCentAndMcLabels = soa::Join; + using CollisionsWCentAndQvectors = soa::Join; + using BCsInfo = soa::Join; + + Filter filterSelectDplusCandidates = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= hfflagConfigurations.selectionFlagDplus); + Filter filterSelectDsCandidates = (aod::hf_sel_candidate_ds::isSelDsToKKPi >= hfflagConfigurations.selectionFlagDs || aod::hf_sel_candidate_ds::isSelDsToPiKK >= hfflagConfigurations.selectionFlagDs); + Filter filterSelectDzeroCandidates = (aod::hf_sel_candidate_d0::isSelD0 >= hfflagConfigurations.selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= hfflagConfigurations.selectionFlagD0bar); + Filter filterSelectLcCandidates = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= hfflagConfigurations.selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= hfflagConfigurations.selectionFlagLc); + Filter filterSelectDstarCandidates = (aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == hfflagConfigurations.selectionFlagDstar); + + struct : PresliceGroup { + 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 candsLcPerCollision = aod::track_association::collisionId; + Preslice candsLcPerCollisionWithMl = aod::track_association::collisionId; + Preslice candsDstarPerCollision = aod::track_association::collisionId; + Preslice candsDstarPerCollisionWithMl = aod::track_association::collisionId; + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + } preslices; + + std::shared_ptr hCandidatesD0, hCandidatesDPlus, hCandidatesDs, hCandidatesLc, hCandidatesD0FromDstar; HistogramRegistry registry{"registry"}; + OutputObj zorroSummary{"zorroSummary"}; - void init(InitContext const&) + 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& initContext) { - std::array doProcess = {doprocessDplusPiData, doprocessDplusPiDataWithMl, doprocessDplusPiMc, doprocessDplusPiMcWithMl, doprocessD0PiData, doprocessD0PiDataWithMl, doprocessD0PiMc, doprocessD0PiMcWithMl}; + std::array doProcess = {doprocessDplusPiData, doprocessDplusPiDataWithMl, doprocessDplusPiDataWithQvec, doprocessDplusPiDataWithMlAndQvec, doprocessDplusPiMc, doprocessDplusPiMcWithMl, + doprocessDsPiData, doprocessDsPiDataWithMl, doprocessDsPiDataWithQvec, doprocessDsPiDataWithMlAndQvec, doprocessDsPiMc, doprocessDsPiMcWithMl, + doprocessD0PiData, doprocessD0PiDataWithMl, doprocessD0PiDataWithQvec, doprocessD0PiDataWithMlAndQvec, doprocessD0PiMc, doprocessD0PiMcWithMl, + doprocessLcPiData, doprocessLcPiDataWithMl, doprocessLcPiMc, doprocessLcPiMcWithMl, + doprocessDstarPiData, doprocessDstarPiDataWithMl, doprocessDstarPiDataWithQvec, doprocessDstarPiDataWithMlAndQvec, doprocessDstarPiMc, doprocessDstarPiMcWithMl}; 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!"); } // invariant-mass window cut - massPi = MassPiPlus; - if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiMc || doprocessDplusPiMcWithMl) { + if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiDataWithQvec || doprocessDplusPiDataWithMlAndQvec || doprocessDplusPiMc || doprocessDplusPiMcWithMl) { massC = MassDMinus; massB = MassB0; - } else if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiMc || doprocessD0PiMcWithMl) { + } else if (doprocessDsPiData || doprocessDsPiDataWithMl || doprocessDsPiDataWithQvec || doprocessDsPiDataWithMlAndQvec || doprocessDsPiMc || doprocessDsPiMcWithMl) { + massC = MassDS; + massB = MassBS; + } else if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiDataWithQvec || doprocessD0PiDataWithMlAndQvec || doprocessD0PiMc || doprocessD0PiMcWithMl) { massC = MassD0; massB = MassBPlus; + } else if (doprocessLcPiData || doprocessLcPiDataWithMl || doprocessLcPiMc || doprocessLcPiMcWithMl) { + massC = MassLambdaCPlus; + massB = MassLambdaB0; + } else if (doprocessDstarPiData || doprocessDstarPiDataWithMl || doprocessDstarPiDataWithQvec || doprocessDstarPiDataWithMlAndQvec || doprocessDstarPiMc || doprocessDstarPiMcWithMl) { + massC = MassDStar; + massB = MassB0; } - invMass2ChHadPiMin = (massB - invMassWindowCharmHadPi) * (massB - invMassWindowCharmHadPi); - invMass2ChHadPiMax = (massB + invMassWindowCharmHadPi) * (massB + invMassWindowCharmHadPi); + invMass2ChHadPiMin = (massB - configs.invMassWindowCharmHadPi) * (massB - configs.invMassWindowCharmHadPi); + invMass2ChHadPiMax = (massB + configs.invMassWindowCharmHadPi) * (massB + configs.invMassWindowCharmHadPi); // Initialize fitter - if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiMc || doprocessDplusPiMcWithMl) { - df3.setPropagateToPCA(propagateToPCA); - df3.setMaxR(maxR); - df3.setMaxDZIni(maxDZIni); - df3.setMinParamChange(minParamChange); - df3.setMinRelChi2Change(minRelChi2Change); - df3.setUseAbsDCA(useAbsDCA); - df3.setWeightedFinalPCA(useWeightedFinalPCA); + if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiDataWithQvec || doprocessDplusPiDataWithMlAndQvec || doprocessDplusPiMc || doprocessDplusPiMcWithMl || + doprocessDsPiData || doprocessDsPiDataWithMl || doprocessDsPiDataWithQvec || doprocessDsPiDataWithMlAndQvec || doprocessDsPiMc || doprocessDsPiMcWithMl || + doprocessLcPiData || doprocessLcPiDataWithMl || doprocessLcPiMc || doprocessLcPiMcWithMl) { + df3.setPropagateToPCA(vertexConfigurations.propagateToPCA); + df3.setMaxR(vertexConfigurations.maxR); + df3.setMaxDZIni(vertexConfigurations.maxDZIni); + df3.setMinParamChange(vertexConfigurations.minParamChange); + df3.setMinRelChi2Change(vertexConfigurations.minRelChi2Change); + df3.setUseAbsDCA(vertexConfigurations.useAbsDCA); + df3.setWeightedFinalPCA(vertexConfigurations.useWeightedFinalPCA); df3.setMatCorrType(noMatCorr); - } else if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiMc || doprocessD0PiMcWithMl) { - df2.setPropagateToPCA(propagateToPCA); - df2.setMaxR(maxR); - df2.setMaxDZIni(maxDZIni); - df2.setMinParamChange(minParamChange); - df2.setMinRelChi2Change(minRelChi2Change); - df2.setUseAbsDCA(useAbsDCA); - df2.setWeightedFinalPCA(useWeightedFinalPCA); + } else if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiDataWithQvec || doprocessD0PiDataWithMlAndQvec || doprocessD0PiMc || doprocessD0PiMcWithMl || + doprocessDstarPiData || doprocessDstarPiDataWithMl || doprocessDstarPiDataWithQvec || doprocessDstarPiDataWithMlAndQvec || doprocessDstarPiMc || doprocessDstarPiMcWithMl) { + df2.setPropagateToPCA(vertexConfigurations.propagateToPCA); + df2.setMaxR(vertexConfigurations.maxR); + df2.setMaxDZIni(vertexConfigurations.maxDZIni); + df2.setMinParamChange(vertexConfigurations.minParamChange); + df2.setMinRelChi2Change(vertexConfigurations.minRelChi2Change); + df2.setUseAbsDCA(vertexConfigurations.useAbsDCA); + df2.setWeightedFinalPCA(vertexConfigurations.useWeightedFinalPCA); df2.setMatCorrType(noMatCorr); } // Configure CCDB access - ccdb->setURL(ccdbUrl); + ccdb->setURL(configs.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); runNumber = 0; @@ -215,36 +351,66 @@ 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 = ""; - if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiMc || doprocessDplusPiMcWithMl) { - charmHadTitle0 = "D^{#plus}"; - histMassTitle0 = "Dplus"; - charmHadInvMassTitle = "#it{M}(K#pi#pi)"; - } else if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiMc || doprocessD0PiMcWithMl) { - charmHadTitle0 = "D^{0}"; - charmHadTitle1 = "#overline{D}^{0}"; - histMassTitle0 = "D0"; - histMassTitle1 = "D0bar"; - charmHadInvMassTitle = "#it{M}(K#pi)"; + std::string charmHadTitle; + std::string histMassTitle; + if (doprocessDplusPiData || doprocessDplusPiDataWithMl || doprocessDplusPiDataWithQvec || doprocessDplusPiDataWithMlAndQvec || doprocessDplusPiMc || doprocessDplusPiMcWithMl) { + charmHadTitle = "D^{#plus}"; + histMassTitle = "Dplus"; + registry.add("hMassDplus", "D^{#plus} candidates; #it{M}(K#pi#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + } else if (doprocessDsPiData || doprocessDsPiDataWithMl || doprocessDsPiDataWithQvec || doprocessDsPiDataWithMlAndQvec || 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::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassDsToPiKK", "D_{s}^{#plus} to piKK candidates; #it{M}(KK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + } else if (doprocessD0PiData || doprocessD0PiDataWithMl || doprocessD0PiDataWithQvec || doprocessD0PiDataWithMlAndQvec || doprocessD0PiMc || doprocessD0PiMcWithMl) { + charmHadTitle = "D^{0}"; + histMassTitle = "D0"; + registry.add("hMassD0", "D^{0} candidates; #it{M}(K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassD0bar", "#overline{D}^{0} candidates; #it{M}(K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + } else if (doprocessLcPiData || doprocessLcPiDataWithMl || doprocessLcPiMc || doprocessLcPiMcWithMl) { + charmHadTitle = "#Lambda_{c}^{+}"; + histMassTitle = "Lc"; + registry.add("hMassLcToPKPi", "#Lambda_{c}^{+} to KKpi candidates; #it{M}(pK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassLcToPiKP", "#Lambda_{c}^{+} to piKK candidates; #it{M}(#piKp) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + } else if (doprocessDstarPiData || doprocessDstarPiDataWithMl || doprocessDstarPiDataWithQvec || doprocessDstarPiDataWithMlAndQvec || doprocessDstarPiMc || doprocessDstarPiMcWithMl) { + charmHadTitle = "D^{*}"; + histMassTitle = "Dstar"; + registry.add("hMassDstarToD0Pi", "D^{*} candidates; #it{M}(K#pi#pi) - #it{M}(K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 1.}}}); } - 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("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("hPt%s", histMassTitle.data()), Form("%s candidates candidates;%s candidate #it{p}_{T} (GeV/#it{c});entries", charmHadTitle.data(), charmHadTitle.data()), {HistType::kTH1D, {{100, 0., 10.}}}); + registry.add("hPtPion", "#pi^{#plus} candidates;#pi^{#plus} candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {{100, 0., 10.}}}); + registry.add(Form("hCpa%s", histMassTitle.data()), Form("%s candidates;%s cosine of pointing angle;entries", charmHadTitle.data(), charmHadTitle.data()), {HistType::kTH1D, {{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}}); + hCandidatesLc = registry.add("hCandidatesLc", "Lc candidate counter", {HistType::kTH1D, {axisCands}}); + hCandidatesD0FromDstar = registry.add("hCandidatesD0FromDstar", "D0 from D* candidate counter", {HistType::kTH1D, {axisCands}}); + setLabelHistoCands(hCandidatesD0); setLabelHistoCands(hCandidatesDPlus); + setLabelHistoCands(hCandidatesDs); + setLabelHistoCands(hCandidatesLc); + setLabelHistoCands(hCandidatesD0FromDstar); + + // init HF event selection helper + hfEvSel.init(registry, zorroSummary); + if (doprocessDplusPiMc || doprocessDplusPiMcWithMl || + doprocessDsPiMc || doprocessDsPiMcWithMl || + doprocessD0PiMc || doprocessD0PiMcWithMl || + doprocessLcPiMc || doprocessLcPiMcWithMl || + doprocessDstarPiMc || doprocessDstarPiMcWithMl) { + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name == "hf-data-creator-charm-had-pi-reduced") { + // init HF event selection helper + hfEvSelMc.init(device, registry); + break; + } + } + } } /// Pion selection (D Pi <-- B0) @@ -257,11 +423,11 @@ struct HfDataCreatorCharmHadPiReduced { bool isPionSelected(const T1& trackPion, const T2& trackParCovPion, const T3& dcaPion, const std::vector& charmDautracks) { // check isGlobalTrackWoDCA status for pions if wanted - if (usePionIsGlobalTrackWoDCA && !trackPion.isGlobalTrackWoDCA()) { + if (trackPionConfigurations.usePionIsGlobalTrackWoDCA && !trackPion.isGlobalTrackWoDCA()) { return false; } - // minimum pT selection - if (trackParCovPion.getPt() < ptPionMin || !isSelectedTrackDCA(trackParCovPion, dcaPion)) { + // minimum pT and eta selection + if (trackParCovPion.getPt() < trackPionConfigurations.ptPionMin || std::abs(trackParCovPion.getEta()) > trackPionConfigurations.etaPionMax || !isSelectedTrackDCA(trackParCovPion, dcaPion, trackPionConfigurations.binsPtPion, trackPionConfigurations.cutsTrackPionDCA)) { return false; } // reject pions that are charm-hadron daughters @@ -274,25 +440,42 @@ struct HfDataCreatorCharmHadPiReduced { return true; } - /// Single-track cuts for pions on dcaXY - /// \param trackPar is the track parametrisation - /// \param dca is the 2-D array with track DCAs - /// \return true if track passes all cuts - template - bool isSelectedTrackDCA(const T1& trackPar, const T2& dca) + /// 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) { - auto pTBinTrack = findBin(binsPtPion, trackPar.getPt()); - if (pTBinTrack == -1) { - return false; + unsigned maxNumContrib = 0; + int64_t indexCollisionMaxNumContrib = -1; + for (const auto& collision : collisions) { + if (collision.numContrib() > maxNumContrib) { + maxNumContrib = collision.numContrib(); + indexCollisionMaxNumContrib = collision.globalIndex(); + } } + return indexCollisionMaxNumContrib; + } - if (std::abs(dca[0]) < cutsTrackPionDCA->get(pTBinTrack, "min_dcaxytoprimary")) { - return false; // minimum DCAxy - } - if (std::abs(dca[0]) > cutsTrackPionDCA->get(pTBinTrack, "max_dcaxytoprimary")) { - return false; // maximum DCAxy + /// 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; + } } - return true; } /// Function for filling MC reco information in the tables @@ -300,16 +483,20 @@ struct HfDataCreatorCharmHadPiReduced { /// \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 signD{0}; int8_t flag{0}; + int8_t flagWrongCollision{WrongCollisionType::None}; int8_t debug{0}; int pdgCodeBeautyMother{-1}; int pdgCodeCharmMother{-1}; @@ -319,13 +506,13 @@ struct HfDataCreatorCharmHadPiReduced { int pdgCodeProng3{0}; float motherPt{-1.f}; - if constexpr (decChannel == DecayChannel::B0ToDminusPi) { + 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 { @@ -337,22 +524,45 @@ struct HfDataCreatorCharmHadPiReduced { if (indexMother >= 0) { auto particleMother = particlesMc.rawIteratorAt(indexMother); motherPt = particleMother.pt(); + checkWrongCollision(particleMother, collision, indexCollisionMaxNumContrib, flagWrongCollision); } } // additional checks for correlated backgrounds - if (checkDecayTypeMc) { + if (configs.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); + } + } + } + // B0 → D- K+ → (π- K+ π-) K+ + if (!flag) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kB0, std::array{-kPiPlus, +kKPlus, -kPiPlus, +kKPlus}, true, &sign, 3); + if (indexRec > -1) { + // D- → π- K+ π- + 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::B0ToDplusKToPiKPiK); + } + } + } // 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) { @@ -361,15 +571,15 @@ struct HfDataCreatorCharmHadPiReduced { auto particleProng2 = vecDaughtersB[2].mcParticle(); auto particleProng3 = vecDaughtersB[3].mcParticle(); // b-hadron hypothesis - std::array bHadronMotherHypos = {Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; + std::array const bHadronMotherHypos = {Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; // c-hadron hypothesis - std::array cHadronMotherHypos = {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar}; + std::array const cHadronMotherHypos = {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, 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); + int const index0Mother = RecoDecay::getMother(particlesMc, particleProng0, bHadronMotherHypo, true); + int const index1Mother = RecoDecay::getMother(particlesMc, particleProng1, bHadronMotherHypo, true); + int const index2Mother = RecoDecay::getMother(particlesMc, particleProng2, bHadronMotherHypo, true); + int const index3Mother = RecoDecay::getMother(particlesMc, particleProng3, bHadronMotherHypo, true); // look for common b-hadron ancestor if (index0Mother > -1 && index1Mother > -1 && index2Mother > -1 && index3Mother > -1) { @@ -387,9 +597,9 @@ struct HfDataCreatorCharmHadPiReduced { if (cHadronMotherHypo == Pdg::kDStar) { // to include D* -> D π0/γ and D* -> D0 π 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); + int const index0CharmMother = RecoDecay::getMother(particlesMc, particleProng0, cHadronMotherHypo, true, &sign, depthMax); + int const index1CharmMother = RecoDecay::getMother(particlesMc, particleProng1, cHadronMotherHypo, true, &sign, depthMax); + int const index2CharmMother = RecoDecay::getMother(particlesMc, particleProng2, cHadronMotherHypo, true, &sign, depthMax); if (index0CharmMother > -1 && index1CharmMother > -1 && index2CharmMother > -1) { if (index0CharmMother == index1CharmMother && index1CharmMother == index2CharmMother) { // pdgCodeCharmMother = @@ -397,6 +607,162 @@ 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()); + } + } + } + break; + } + } + } + } + tables.rowHfDPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); + } + tables.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() == NDaughtersDs) { + 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 (configs.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() == NDaughtersDs) { + 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); + } + } + } + } + } + // Bs → Ds- K+ → (K- 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, +kKPlus}, 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() == NDaughtersDs) { + 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::BsToDsKToPhiPiKToKKPiK); + } 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::BsToDsKToK0starKKToKKPiK); + } + } + } 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); + } + } + } + // 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 const bHadronMotherHypos = {Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; + // c-hadron hypothesis + std::array const cHadronMotherHypos = {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, Pdg::kDSStar, Pdg::kLambdaCPlus}; + + for (const auto& bHadronMotherHypo : bHadronMotherHypos) { + int const index0Mother = RecoDecay::getMother(particlesMc, particleProng0, bHadronMotherHypo, true); + int const index1Mother = RecoDecay::getMother(particlesMc, particleProng1, bHadronMotherHypo, true); + int const index2Mother = RecoDecay::getMother(particlesMc, particleProng2, bHadronMotherHypo, true); + int const 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 const index0CharmMother = RecoDecay::getMother(particlesMc, particleProng0, cHadronMotherHypo, true, &sign, depthMax); + int const index1CharmMother = RecoDecay::getMother(particlesMc, particleProng1, cHadronMotherHypo, true, &sign, depthMax); + int const 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()); } } @@ -406,17 +772,17 @@ struct HfDataCreatorCharmHadPiReduced { } } } - rowHfDPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); + tables.rowHfDsPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); } - rowHfDPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, debug, motherPt); - } else if constexpr (decChannel == DecayChannel::BplusToD0barPi) { + tables.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) { - // 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); + flag = sign * BIT(hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi); } else { debug = 1; LOGF(debug, "B+ decays in the expected final state but the condition on the intermediate state is not fulfilled"); @@ -426,12 +792,32 @@ struct HfDataCreatorCharmHadPiReduced { if (indexMother >= 0) { auto particleMother = particlesMc.rawIteratorAt(indexMother); motherPt = particleMother.pt(); + checkWrongCollision(particleMother, collision, indexCollisionMaxNumContrib, flagWrongCollision); } } - rowHfD0PiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, debug, motherPt); - // additional checks for correlated backgrounds - if (checkDecayTypeMc) { + if (configs.checkDecayTypeMc) { + if (!flag) { + // B+ → D0(bar) K+ → (K+ π-) K+ + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kBPlus, std::array{+kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2); + if (indexRec > -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::DecayTypeMc::BplusToD0KToKPiK); + } else { + debug = 1; + 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); + } + } + } // Partly reconstructed decays, i.e. the 3 prongs have a common b-hadron ancestor // convention: final state particles are prong0,1,2 if (!flag) { @@ -439,12 +825,14 @@ struct HfDataCreatorCharmHadPiReduced { auto particleProng1 = vecDaughtersB[1].mcParticle(); auto particleProng2 = vecDaughtersB[2].mcParticle(); // b-hadron hypothesis - std::array bHadronMotherHypos = {Pdg::kBPlus, Pdg::kB0, Pdg::kBS}; + std::array const bHadronMotherHypos = {Pdg::kBPlus, Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; + // c-hadron hypothesis + std::array const 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); + int const index0Mother = RecoDecay::getMother(particlesMc, particleProng0, bHadronMotherHypo, true); + int const index1Mother = RecoDecay::getMother(particlesMc, particleProng1, bHadronMotherHypo, true); + int const index2Mother = RecoDecay::getMother(particlesMc, particleProng2, bHadronMotherHypo, true); // look for common b-hadron ancestor if (index0Mother > -1 && index1Mother > -1 && index2Mother > -1) { @@ -455,26 +843,197 @@ struct HfDataCreatorCharmHadPiReduced { 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 == Pdg::kDStar0 || cHadronMotherHypo == Pdg::kDSStar) { // to include D* -> D π0/γ, D* -> D0 π, and Ds* -> Ds π0/γ + depthMax += 1; + } + int const index0CharmMother = RecoDecay::getMother(particlesMc, particleProng0, cHadronMotherHypo, true, &sign, depthMax); + int const 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, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2); + tables.rowHfD0PiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2); + } + tables.rowHfD0PiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); + } else if constexpr (DecChannel == DecayChannel::LbToLcplusPi) { + // Lb → Lc+ π- → (p K- π+) π- + auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kLambdaB0, std::array{+kProton, -kKPlus, +kPiPlus, -kPiPlus}, true, &sign, 3); + if (indexRec > -1) { + // Lc+ → p K- π+ + // Printf("Checking Lc+ → p K- π+"); + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + if (indexRec > -1) { + flag = sign * BIT(hf_cand_lb::DecayTypeMc::LbToLcPiToPKPiPi); + } else { + debug = 1; + LOGF(debug, "Lb 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::kLambdaB0, true); + if (indexMother >= 0) { + auto particleMother = particlesMc.rawIteratorAt(indexMother); + motherPt = particleMother.pt(); + checkWrongCollision(particleMother, collision, indexCollisionMaxNumContrib, flagWrongCollision); + } + } + + // additional checks for correlated backgrounds + if (configs.checkDecayTypeMc) { + // Lb → Lc+ K- → (p K- π+) K- + if (!flag) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kLambdaB0, std::array{+kProton, -kKPlus, +kPiPlus, -kKPlus}, true, &sign, 3); + if (indexRec > -1) { + // Lc+ → p K- π+ + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + if (indexRec > -1) { + flag = sign * BIT(hf_cand_lb::DecayTypeMc::LbToLcKToPKPiK); + } + } + } + // B0 → D- π+ → (π- K+ π-) π+ + if (!flag) { + 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+ π- + 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_lb::DecayTypeMc::B0ToDplusPiToPiKPiPi); + } + } + } + + // 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 const bHadronMotherHypos = {Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; + // c-hadron hypothesis + std::array const cHadronMotherHypos = {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, Pdg::kLambdaCPlus}; + + for (const auto& bHadronMotherHypo : bHadronMotherHypos) { + int const index0Mother = RecoDecay::getMother(particlesMc, particleProng0, bHadronMotherHypo, true); + int const index1Mother = RecoDecay::getMother(particlesMc, particleProng1, bHadronMotherHypo, true); + int const index2Mother = RecoDecay::getMother(particlesMc, particleProng2, bHadronMotherHypo, true); + int const 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_b0::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) { // to include D* -> D π0/γ and D* -> D0 π + depthMax += 1; + } + int const index0CharmMother = RecoDecay::getMother(particlesMc, particleProng0, cHadronMotherHypo, true, &sign, depthMax); + int const index1CharmMother = RecoDecay::getMother(particlesMc, particleProng1, cHadronMotherHypo, true, &sign, depthMax); + int const 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) + // Pdg::kLambdaCPlus (if Λc+ is the mother) + pdgCodeCharmMother += std::abs(particlesMc.rawIteratorAt(index0CharmMother).pdgCode()); + } + } + } + break; // Early exit: found a valid decay chain with common b-hadron mother + } + } + } + } + tables.rowHfLcPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); + } + tables.rowHfLcPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); + } else if constexpr (DecChannel == DecayChannel::B0ToDstarPi) { + // B0 → D*+ π- → (D0 π+) π- → (K- π+ π+) π- + auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kB0, std::array{+kKPlus, -kPiPlus, -kPiPlus, +kPiPlus}, true, &sign, 4); + if (indexRec > -1) { + // D*+ → (D0 π+) → K- π+ π+ + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, +Pdg::kDStar, std::array{-kKPlus, +kPiPlus, +kPiPlus}, true, &signD, 3); + if (indexRec > -1) { + std::vector arrDaughDstarIndex; + RecoDecay::getDaughters(particlesMc.rawIteratorAt(indexRec), &arrDaughDstarIndex, std::array{0}, 1); + if (arrDaughDstarIndex.size() == NDaughtersDstar) { + bool matchD0{false}; + for (const int iProng : arrDaughDstarIndex) { + auto daughI = particlesMc.rawIteratorAt(iProng); + if (std::abs(daughI.pdgCode()) == Pdg::kD0) { + matchD0 = RecoDecay::isMatchedMCGen(particlesMc, daughI, +Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &signD, 2); + } + } + if (matchD0) { + flag = sign * BIT(hf_cand_b0::DecayTypeMc::B0ToDstarPiToD0PiPiToKPiPiPi); + } else { + debug = 1; + LOGF(debug, "B0 decays in the expected final state but the condition on D* intermediate state is not fulfilled"); + } + } + } else { + debug = 1; + LOGF(debug, "B0 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::kB0, true); + if (indexMother >= 0) { + auto particleMother = particlesMc.rawIteratorAt(indexMother); + motherPt = particleMother.pt(); + checkWrongCollision(particleMother, collision, indexCollisionMaxNumContrib, flagWrongCollision); + } } + tables.rowHfDStarPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); } } - template + template void runDataCreation(Coll const& collision, CCharmCands const& candsC, aod::TrackAssoc const& trackIndices, TTracks const&, PParticles const& particlesMc, - aod::BCsWithTimestamps const&) + uint64_t const& indexCollisionMaxNumContrib, + BBCs const&) { + registry.fill(HIST("hEvents"), 1 + Event::Processed); + float centrality = -1.f; + const auto hfRejMap = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + if (configs.skipRejectedCollisions && hfRejMap != 0) { + return; + } + // helpers for ReducedTables filling - int indexHfReducedCollision = hfReducedCollision.lastIndex() + 1; + int const indexHfReducedCollision = tables.hfReducedCollision.lastIndex() + 1; // std::map where the key is the track.globalIndex() and // the value is the track index in the table of the selected pions std::map selectedTracksPion; @@ -485,10 +1044,10 @@ 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.template 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()); + auto* grpo = ccdb->getForTimeStamp(configs.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()); } @@ -497,32 +1056,66 @@ struct HfDataCreatorCharmHadPiReduced { LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; runNumber = bc.runNumber(); } + df2.setBz(bz); df3.setBz(bz); auto thisCollId = collision.globalIndex(); for (const auto& candC : candsC) { int indexHfCandCharm{-1}; float invMassC0{-1.f}, invMassC1{-1.f}; - if constexpr (decChannel == DecayChannel::B0ToDminusPi) { - indexHfCandCharm = hfCand3Prong.lastIndex() + 1; - invMassC0 = hfHelper.invMassDplusToPiKPi(candC); + if constexpr (DecChannel == DecayChannel::B0ToDminusPi) { + indexHfCandCharm = tables.hfCand3Prong.lastIndex() + 1; + invMassC0 = HfHelper::invMassDplusToPiKPi(candC); registry.fill(HIST("hMassDplus"), invMassC0); registry.fill(HIST("hPtDplus"), candC.pt()); registry.fill(HIST("hCpaDplus"), candC.cpa()); - } else if constexpr (decChannel == DecayChannel::BplusToD0barPi) { - indexHfCandCharm = hfCand2Prong.lastIndex() + 1; - if (candC.isSelD0() >= selectionFlagD0) { - invMassC0 = hfHelper.invMassD0ToPiK(candC); + } else if constexpr (DecChannel == DecayChannel::BsToDsminusPi) { + indexHfCandCharm = tables.hfCand3Prong.lastIndex() + 1; + if (candC.isSelDsToKKPi() >= hfflagConfigurations.selectionFlagDs) { + invMassC0 = HfHelper::invMassDsToKKPi(candC); + registry.fill(HIST("hMassDsToKKPi"), invMassC0); + } + if (candC.isSelDsToPiKK() >= hfflagConfigurations.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 = tables.hfCand2Prong.lastIndex() + 1; + if (candC.isSelD0() >= hfflagConfigurations.selectionFlagD0) { + invMassC0 = HfHelper::invMassD0ToPiK(candC); registry.fill(HIST("hMassD0"), invMassC0); } - if (candC.isSelD0bar() >= selectionFlagD0bar) { - invMassC1 = hfHelper.invMassD0barToKPi(candC); + if (candC.isSelD0bar() >= hfflagConfigurations.selectionFlagD0bar) { + invMassC1 = HfHelper::invMassD0barToKPi(candC); registry.fill(HIST("hMassD0bar"), invMassC1); } registry.fill(HIST("hPtD0"), candC.pt()); registry.fill(HIST("hCpaD0"), candC.cpa()); + } else if constexpr (DecChannel == DecayChannel::LbToLcplusPi) { + indexHfCandCharm = tables.hfCand3Prong.lastIndex() + 1; + if (candC.isSelLcToPKPi() >= hfflagConfigurations.selectionFlagLc) { + invMassC0 = HfHelper::invMassLcToPKPi(candC); + registry.fill(HIST("hMassLcToPKPi"), invMassC0); + } + if (candC.isSelLcToPiKP() >= hfflagConfigurations.selectionFlagLc) { + invMassC1 = HfHelper::invMassLcToPiKP(candC); + registry.fill(HIST("hMassLcToPiKP"), invMassC1); + } + registry.fill(HIST("hPtLc"), candC.pt()); + registry.fill(HIST("hCpaLc"), candC.cpa()); + } else if constexpr (DecChannel == DecayChannel::B0ToDstarPi) { + indexHfCandCharm = tables.hfCand2Prong.lastIndex() + 1; + if (candC.signSoftPi() > 0) { + invMassC0 = candC.invMassDstar() - candC.invMassD0(); + } else { + invMassC0 = candC.invMassAntiDstar() - candC.invMassD0Bar(); + } + registry.fill(HIST("hMassDstarToD0Pi"), invMassC0); + registry.fill(HIST("hPtDstar"), candC.pt()); + registry.fill(HIST("hCpaDstar"), candC.cpaD0()); } - bool fillHfCandCharm = false; std::vector charmHadDauTracks{candC.template prong0_as(), candC.template prong1_as()}; @@ -547,8 +1140,12 @@ struct HfDataCreatorCharmHadPiReduced { } // third track, if it's a 3-prong - if constexpr (decChannel == DecayChannel::B0ToDminusPi) { - charmHadDauTracks.push_back(candC.template prong2_as()); + if constexpr (DecChannel == DecayChannel::B0ToDminusPi || DecChannel == DecayChannel::BsToDsminusPi || DecChannel == DecayChannel::LbToLcplusPi || DecChannel == DecayChannel::B0ToDstarPi) { + if constexpr (DecChannel == DecayChannel::B0ToDstarPi) { + charmHadDauTracks.push_back(candC.template prongPi_as()); // Soft pion from D* decay + } else { + charmHadDauTracks.push_back(candC.template prong2_as()); + } trackParCov2 = getTrackParCov(charmHadDauTracks[2]); pVec2 = charmHadDauTracks[2].pVector(); auto dca2 = o2::dataformats::DCA(charmHadDauTracks[2].dcaXY(), charmHadDauTracks[2].dcaZ(), charmHadDauTracks[2].cYY(), charmHadDauTracks[2].cZY(), charmHadDauTracks[2].cZZ()); @@ -562,19 +1159,38 @@ 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 || DecChannel == DecayChannel::LbToLcplusPi) { // D∓ → π∓ K± π∓ and Ds∓ → K∓ K± π∓ and Lc∓ → p∓ K± π∓ + + if constexpr (DecChannel == DecayChannel::B0ToDminusPi) { + hCandidatesDPlus->Fill(SVFitting::BeforeFit); + } else if constexpr (DecChannel == DecayChannel::BsToDsminusPi) { + hCandidatesDs->Fill(SVFitting::BeforeFit); + } else if constexpr (DecChannel == DecayChannel::LbToLcplusPi) { + hCandidatesLc->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() << ". DCAFitterN cannot work, skipping the candidate."; - hCandidatesDPlus->Fill(SVFitting::Fail); + if constexpr (DecChannel == DecayChannel::B0ToDminusPi) { + hCandidatesDPlus->Fill(SVFitting::Fail); + } else if constexpr (DecChannel == DecayChannel::BsToDsminusPi) { + hCandidatesDs->Fill(SVFitting::Fail); + } else if constexpr (DecChannel == DecayChannel::LbToLcplusPi) { + hCandidatesLc->Fill(SVFitting::Fail); + } continue; } - hCandidatesDPlus->Fill(SVFitting::FitOk); + if constexpr (DecChannel == DecayChannel::B0ToDminusPi) { + hCandidatesDPlus->Fill(SVFitting::FitOk); + } else if constexpr (DecChannel == DecayChannel::BsToDsminusPi) { + hCandidatesDs->Fill(SVFitting::FitOk); + } else if constexpr (DecChannel == DecayChannel::LbToLcplusPi) { + hCandidatesLc->Fill(SVFitting::FitOk); + } auto secondaryVertexCharm = df3.getPCACandidate(); trackParCov0.propagateTo(secondaryVertexCharm[0], bz); @@ -586,7 +1202,7 @@ struct HfDataCreatorCharmHadPiReduced { pVecCharm = RecoDecay::pVec(pVec0, pVec1, pVec2); trackParCovCharmHad = df3.createParentTrackParCov(); trackParCovCharmHad.setAbsCharge(charmHadDauTracks[1].sign()); // to be sure - } else if constexpr (decChannel == DecayChannel::BplusToD0barPi) { // D0(bar) → K± π∓ + } else if constexpr (DecChannel == DecayChannel::BplusToD0barPi) { // D0(bar) → K± π∓ hCandidatesD0->Fill(SVFitting::BeforeFit); try { @@ -608,6 +1224,48 @@ struct HfDataCreatorCharmHadPiReduced { pVecCharm = RecoDecay::pVec(pVec0, pVec1); trackParCovCharmHad = df2.createParentTrackParCov(); trackParCovCharmHad.setAbsCharge(0); // to be sure + } else if constexpr (DecChannel == DecayChannel::B0ToDstarPi) { + + hCandidatesD0FromDstar->Fill(SVFitting::BeforeFit); + try { + // D0 vertex + if (df2.process(trackParCov0, trackParCov1) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + hCandidatesD0FromDstar->Fill(SVFitting::Fail); + continue; + } + hCandidatesD0FromDstar->Fill(SVFitting::FitOk); + auto secondaryVertexCharm = df2.getPCACandidate(); + trackParCov0.propagateTo(secondaryVertexCharm[0], bz); + trackParCov1.propagateTo(secondaryVertexCharm[0], bz); + df2.getTrack(0).getPxPyPzGlo(pVec0); + df2.getTrack(1).getPxPyPzGlo(pVec1); + pVecCharm = RecoDecay::pVec(pVec0, pVec1, pVec2); + trackParCovCharmHad = df2.createParentTrackParCov(); + 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) { @@ -615,7 +1273,7 @@ struct HfDataCreatorCharmHadPiReduced { // apply selections on pion tracks auto trackParCovPion = getTrackParCov(trackPion); - o2::gpu::gpustd::array dcaPion{trackPion.dcaXY(), trackPion.dcaZ()}; + std::array dcaPion{trackPion.dcaXY(), trackPion.dcaZ()}; std::array pVecPion = trackPion.pVector(); if (trackPion.collisionId() != thisCollId) { o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovPion, 2.f, noMatCorr, &dcaPion); @@ -623,12 +1281,16 @@ 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 || DecChannel == DecayChannel::LbToLcplusPi) { // D∓ → π∓ K± π∓ and Ds∓ → K∓ K± π∓ and Lc∓ → p∓ K± π∓ if (trackPion.sign() * charmHadDauTracks[0].sign() > 0) { continue; } - } else if constexpr (decChannel == DecayChannel::BplusToD0barPi) { // D0(bar) → K± π∓ - if (!((candC.isSelD0() >= selectionFlagD0 && trackPion.sign() < 0) || (candC.isSelD0bar() >= selectionFlagD0bar && trackPion.sign() > 0))) { + } else if constexpr (DecChannel == DecayChannel::BplusToD0barPi) { // D0(bar) → K± π∓ + if (!((candC.isSelD0() >= hfflagConfigurations.selectionFlagD0 && trackPion.sign() < 0) || (candC.isSelD0bar() >= hfflagConfigurations.selectionFlagD0bar && trackPion.sign() > 0))) { + continue; + } + } else if constexpr (DecChannel == DecayChannel::B0ToDstarPi) { // D*+ → D0 π+ + if (trackPion.sign() * charmHadDauTracks.back().sign() > 0) { continue; } } @@ -640,7 +1302,7 @@ struct HfDataCreatorCharmHadPiReduced { registry.fill(HIST("hPtPion"), trackParCovPion.getPt()); // compute invariant mass square and apply selection - auto invMass2DPi = RecoDecay::m2(std::array{pVecCharm, pVecPion}, std::array{massC, massPi}); + auto invMass2DPi = RecoDecay::m2(std::array{pVecCharm, pVecPion}, std::array{massC, MassPiPlus}); if ((invMass2DPi < invMass2ChHadPiMin) || (invMass2DPi > invMass2ChHadPiMax)) { continue; } @@ -648,101 +1310,225 @@ struct HfDataCreatorCharmHadPiReduced { // fill Pion tracks table // if information on track already stored, go to next track if (!selectedTracksPion.count(trackPion.globalIndex())) { - hfTrackPion(trackPion.globalIndex(), indexHfReducedCollision, - trackParCovPion.getX(), trackParCovPion.getAlpha(), - trackParCovPion.getY(), trackParCovPion.getZ(), trackParCovPion.getSnp(), - trackParCovPion.getTgl(), trackParCovPion.getQ2Pt()); - hfTrackCovPion(trackParCovPion.getSigmaY2(), trackParCovPion.getSigmaZY(), trackParCovPion.getSigmaZ2(), - trackParCovPion.getSigmaSnpY(), trackParCovPion.getSigmaSnpZ(), - trackParCovPion.getSigmaSnp2(), trackParCovPion.getSigmaTglY(), trackParCovPion.getSigmaTglZ(), - trackParCovPion.getSigmaTglSnp(), trackParCovPion.getSigmaTgl2(), - trackParCovPion.getSigma1PtY(), trackParCovPion.getSigma1PtZ(), trackParCovPion.getSigma1PtSnp(), - trackParCovPion.getSigma1PtTgl(), trackParCovPion.getSigma1Pt2()); - hfTrackPidPion(trackPion.hasTPC(), trackPion.hasTOF(), - trackPion.tpcNSigmaPi(), trackPion.tofNSigmaPi()); + tables.hfTrackPion(trackPion.globalIndex(), indexHfReducedCollision, + trackParCovPion.getX(), trackParCovPion.getAlpha(), + trackParCovPion.getY(), trackParCovPion.getZ(), trackParCovPion.getSnp(), + trackParCovPion.getTgl(), trackParCovPion.getQ2Pt(), + trackPion.itsNCls(), trackPion.tpcNClsCrossedRows(), trackPion.tpcChi2NCl()); + tables.hfTrackCovPion(trackParCovPion.getSigmaY2(), trackParCovPion.getSigmaZY(), trackParCovPion.getSigmaZ2(), + trackParCovPion.getSigmaSnpY(), trackParCovPion.getSigmaSnpZ(), + trackParCovPion.getSigmaSnp2(), trackParCovPion.getSigmaTglY(), trackParCovPion.getSigmaTglZ(), + trackParCovPion.getSigmaTglSnp(), trackParCovPion.getSigmaTgl2(), + trackParCovPion.getSigma1PtY(), trackParCovPion.getSigma1PtZ(), trackParCovPion.getSigma1PtSnp(), + trackParCovPion.getSigma1PtTgl(), trackParCovPion.getSigma1Pt2()); + tables.hfTrackPidPion(trackPion.hasTPC(), trackPion.hasTOF(), + trackPion.tpcNSigmaPi(), trackPion.tofNSigmaPi()); + tables.hfTrackMomPion(pVecPion[0], pVecPion[1], pVecPion[2], trackPion.sign()); // add trackPion.globalIndex() to a list // to keep memory of the pions filled in the table and avoid refilling them if they are paired to another D candidate - // and keep track of their index in hfTrackPion for McRec purposes - selectedTracksPion[trackPion.globalIndex()] = hfTrackPion.lastIndex(); + // and keep track of their index in tables.hfTrackPion for McRec purposes + selectedTracksPion[trackPion.globalIndex()] = tables.hfTrackPion.lastIndex(); } - if constexpr (doMc) { + if constexpr (DoMc) { std::vector beautyHadDauTracks{}; + beautyHadDauTracks.reserve(charmHadDauTracks.size()); for (const auto& track : charmHadDauTracks) { 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± π∓ - 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); - 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()); - if constexpr (withMl) { - hfCand3ProngMl(candC.mlProbDplusToPiKPi()[0], candC.mlProbDplusToPiKPi()[1], candC.mlProbDplusToPiKPi()[2]); + } // pion loop + if (fillHfCandCharm) { // fill candCplus table only once per D candidate + constexpr std::size_t NSizeMLScore{3u}; + if constexpr (DecChannel == DecayChannel::B0ToDminusPi || DecChannel == DecayChannel::BsToDsminusPi || DecChannel == DecayChannel::LbToLcplusPi) { // D∓ → π∓ K± π∓ and Ds∓ → K∓ K± π∓ and Lc∓ → p∓ K± π∓ + tables.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, invMassC1, + ptDauMin, etaDauMin, nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax); + tables.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()); + float nSigmaTpcPr0{-999.f}, nSigmaTpcPr1{-999.f}, nSigmaTpcPr2{-999.f}; + float nSigmaTofPr0{-999.f}, nSigmaTofPr1{-999.f}, nSigmaTofPr2{-999.f}; + if constexpr (DecChannel == DecayChannel::LbToLcplusPi) { + /// assign non-dummy values only for Lb->LcPi analysis + nSigmaTpcPr0 = candC.nSigTpcPr0(); + nSigmaTpcPr1 = candC.nSigTpcPr1(); + nSigmaTpcPr2 = candC.nSigTpcPr2(); + nSigmaTofPr0 = candC.nSigTofPr0(); + nSigmaTofPr1 = candC.nSigTofPr1(); + nSigmaTofPr2 = candC.nSigTofPr2(); + } + tables.hfCandPidProng0(candC.nSigTpcPi0(), candC.nSigTofPi0(), candC.nSigTpcKa0(), candC.nSigTofKa0(), nSigmaTpcPr0, nSigmaTofPr0, charmHadDauTracks[0].hasTOF(), charmHadDauTracks[0].hasTPC()); + tables.hfCandPidProng1(candC.nSigTpcPi1(), candC.nSigTofPi1(), candC.nSigTpcKa1(), candC.nSigTofKa1(), nSigmaTpcPr1, nSigmaTofPr1, charmHadDauTracks[1].hasTOF(), charmHadDauTracks[1].hasTPC()); + tables.hfCandPidProng2(candC.nSigTpcPi2(), candC.nSigTofPi2(), candC.nSigTpcKa2(), candC.nSigTofKa2(), nSigmaTpcPr2, nSigmaTofPr2, charmHadDauTracks[2].hasTOF(), charmHadDauTracks[2].hasTPC()); + if constexpr (WithMl) { + std::array mlScores = {-1.f, -1.f, -1.f, -1.f, -1.f, -1.f}; + if constexpr (DecChannel == DecayChannel::B0ToDminusPi) { + tables.hfCand3ProngMl(candC.mlProbDplusToPiKPi()[0], candC.mlProbDplusToPiKPi()[1], candC.mlProbDplusToPiKPi()[2], -1., -1., -1.); + } else if constexpr (DecChannel == DecayChannel::BsToDsminusPi) { + if (candC.mlProbDsToKKPi().size() == NSizeMLScore) { + std::copy(candC.mlProbDsToKKPi().begin(), candC.mlProbDsToKKPi().end(), mlScores.begin()); + } + if (candC.mlProbDsToPiKK().size() == NSizeMLScore) { + std::copy(candC.mlProbDsToPiKK().begin(), candC.mlProbDsToPiKK().end(), mlScores.begin() + 3); + } + tables.hfCand3ProngMl(mlScores[0], mlScores[1], mlScores[2], mlScores[3], mlScores[4], mlScores[5]); + } else if constexpr (DecChannel == DecayChannel::LbToLcplusPi) { + if (candC.mlProbLcToPKPi().size() == NSizeMLScore) { + std::copy(candC.mlProbLcToPKPi().begin(), candC.mlProbLcToPKPi().end(), mlScores.begin()); + } + if (candC.mlProbLcToPiKP().size() == NSizeMLScore) { + std::copy(candC.mlProbLcToPiKP().begin(), candC.mlProbLcToPiKP().end(), mlScores.begin() + 3); + } + tables.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(), - indexHfReducedCollision, - trackParCovCharmHad.getX(), trackParCovCharmHad.getAlpha(), - trackParCovCharmHad.getY(), trackParCovCharmHad.getZ(), trackParCovCharmHad.getSnp(), - trackParCovCharmHad.getTgl(), trackParCovCharmHad.getQ2Pt(), - candC.xSecondaryVertex(), candC.ySecondaryVertex(), candC.zSecondaryVertex(), invMassC0, invMassC1); - 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()); - if constexpr (withMl) { - std::array bdtScores = {-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()); + } else if constexpr (DecChannel == DecayChannel::BplusToD0barPi) { // D0(bar) → K± π∓ + tables.hfCand2Prong(charmHadDauTracks[0].globalIndex(), charmHadDauTracks[1].globalIndex(), + indexHfReducedCollision, + trackParCovCharmHad.getX(), trackParCovCharmHad.getAlpha(), + trackParCovCharmHad.getY(), trackParCovCharmHad.getZ(), trackParCovCharmHad.getSnp(), + trackParCovCharmHad.getTgl(), trackParCovCharmHad.getQ2Pt(), + candC.xSecondaryVertex(), candC.ySecondaryVertex(), candC.zSecondaryVertex(), invMassC0, invMassC1, + ptDauMin, etaDauMin, nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax); + tables.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()); + tables.hfCandPidProng0(candC.nSigTpcPi0(), candC.nSigTofPi0(), candC.nSigTpcKa0(), candC.nSigTofKa0(), 0., 0., charmHadDauTracks[0].hasTOF(), charmHadDauTracks[0].hasTPC()); + tables.hfCandPidProng1(candC.nSigTpcPi1(), candC.nSigTofPi1(), candC.nSigTpcKa1(), candC.nSigTofKa1(), 0., 0., charmHadDauTracks[1].hasTOF(), charmHadDauTracks[1].hasTPC()); + if constexpr (WithMl) { + std::array mlScores = {-1.f, -1.f, -1.f, -1.f, -1.f, -1.f}; + if (candC.mlProbD0().size() == NSizeMLScore) { + 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); + if (candC.mlProbD0bar().size() == NSizeMLScore) { + std::copy(candC.mlProbD0bar().begin(), candC.mlProbD0bar().end(), mlScores.begin() + 3); } - - hfCand2ProngMl(bdtScores[0], bdtScores[1], bdtScores[2], bdtScores[3], bdtScores[4], bdtScores[5]); + tables.hfCand2ProngMl(mlScores[0], mlScores[1], mlScores[2], mlScores[3], mlScores[4], mlScores[5]); + } + } else if constexpr (DecChannel == DecayChannel::B0ToDstarPi) { + tables.hfCand2Prong(charmHadDauTracks[0].globalIndex(), charmHadDauTracks[1].globalIndex(), + indexHfReducedCollision, + trackParCovCharmHad.getX(), trackParCovCharmHad.getAlpha(), + trackParCovCharmHad.getY(), trackParCovCharmHad.getZ(), trackParCovCharmHad.getSnp(), + trackParCovCharmHad.getTgl(), trackParCovCharmHad.getQ2Pt(), + candC.xSecondaryVertexD0(), candC.ySecondaryVertexD0(), candC.zSecondaryVertexD0(), invMassC0, invMassC1, + ptDauMin, etaDauMin, nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax); + tables.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()); + float nSigmaTpcPr0{-999.f}, nSigmaTpcPr1{-999.f}; + float nSigmaTofPr0{-999.f}, nSigmaTofPr1{-999.f}; + tables.hfCandPidProng0(candC.nSigTpcPi0(), candC.nSigTofPi0(), candC.nSigTpcKa0(), candC.nSigTofKa0(), nSigmaTpcPr0, nSigmaTofPr0, charmHadDauTracks[0].hasTOF(), charmHadDauTracks[0].hasTPC()); + tables.hfCandPidProng1(candC.nSigTpcPi1(), candC.nSigTofPi1(), candC.nSigTpcKa1(), candC.nSigTofKa1(), nSigmaTpcPr1, nSigmaTofPr1, charmHadDauTracks[1].hasTOF(), charmHadDauTracks[1].hasTPC()); + + // Soft pion tables + auto trackSoftPion = charmHadDauTracks.back(); + auto trackParCovSoftPion = getTrackParCov(trackSoftPion); + std::array dcaSoftPion{trackSoftPion.dcaXY(), trackSoftPion.dcaZ()}; + std::array pVecSoftPion = trackSoftPion.pVector(); + if (trackSoftPion.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovSoftPion, 2.f, noMatCorr, &dcaSoftPion); + getPxPyPz(trackParCovSoftPion, pVecSoftPion); } + tables.hfTrackSoftPion(trackSoftPion.globalIndex(), indexHfReducedCollision, + trackParCovSoftPion.getX(), trackParCovSoftPion.getAlpha(), + trackParCovSoftPion.getY(), trackParCovSoftPion.getZ(), trackParCovSoftPion.getSnp(), + trackParCovSoftPion.getTgl(), trackParCovSoftPion.getQ2Pt(), + trackSoftPion.itsNCls(), trackSoftPion.tpcNClsCrossedRows(), trackSoftPion.tpcChi2NCl()); + tables.hfTrackCovSoftPion(trackParCovSoftPion.getSigmaY2(), trackParCovSoftPion.getSigmaZY(), trackParCovSoftPion.getSigmaZ2(), + trackParCovSoftPion.getSigmaSnpY(), trackParCovSoftPion.getSigmaSnpZ(), + trackParCovSoftPion.getSigmaSnp2(), trackParCovSoftPion.getSigmaTglY(), trackParCovSoftPion.getSigmaTglZ(), + trackParCovSoftPion.getSigmaTglSnp(), trackParCovSoftPion.getSigmaTgl2(), + trackParCovSoftPion.getSigma1PtY(), trackParCovSoftPion.getSigma1PtZ(), trackParCovSoftPion.getSigma1PtSnp(), + trackParCovSoftPion.getSigma1PtTgl(), trackParCovSoftPion.getSigma1Pt2()); + tables.hfTrackPidSoftPion(candC.nSigTpcPi2(), candC.nSigTofPi2(), charmHadDauTracks[2].hasTOF(), charmHadDauTracks[2].hasTPC()); + if constexpr (WithMl) { + std::array mlScores = {-1.f, -1.f, -1.f, -1.f, -1.f, -1.f}; + if (candC.mlProbDstarToD0Pi().size() == NSizeMLScore) { + std::copy(candC.mlProbDstarToD0Pi().begin(), candC.mlProbDstarToD0Pi().end(), mlScores.begin()); + } + tables.hfCand3ProngMl(mlScores[0], mlScores[1], mlScores[2], mlScores[3], mlScores[4], mlScores[5]); + } + + tables.hfMomDMesDaugs(pVec0[0], pVec0[1], pVec0[2], + pVec1[0], pVec1[1], pVec1[2], + pVecSoftPion[0], pVecSoftPion[1], pVecSoftPion[2]); } fillHfReducedCollision = true; } } // candsC loop - registry.fill(HIST("hEvents"), 1 + Event::Processed); if (!fillHfReducedCollision) { registry.fill(HIST("hEvents"), 1 + Event::NoCharmHadPiSelected); return; } registry.fill(HIST("hEvents"), 1 + Event::CharmHadPiSelected); + // fill collision table if it contains a DPi pair a minima - hfReducedCollision(collision.posX(), collision.posY(), collision.posZ()); - hfReducedCollExtra(collision.covXX(), collision.covXY(), collision.covYY(), - collision.covXZ(), collision.covYZ(), collision.covZZ(), - bz); + tables.hfReducedCollision(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), hfRejMap, bz); + tables.hfReducedCollExtra(collision.covXX(), collision.covXY(), collision.covYY(), + collision.covXZ(), collision.covYZ(), collision.covZZ()); + tables.hfReducedCollCentrality(collision.centFT0C(), collision.centFT0M(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + if constexpr (WithQvec) { + tables.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 - void runMcGen(aod::McParticles const& particlesMc) + template + void runMcGen(aod::McCollision const& mcCollision, + aod::McParticles const& particlesMc, + CollisionsWCentAndMcLabels const& collisions, + BCsInfo const&) { + // Check event selection + float centDummy{-1.f}, centFT0C{-1.f}, centFT0M{-1.f}; + const auto collSlice = collisions.sliceBy(preslices.colPerMcCollision, mcCollision.globalIndex()); + const auto hfRejMap = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centDummy); + if (configs.skipRejectedCollisions && hfRejMap != 0) { + return; + } + + // get centrality + using TMult = uint16_t; // type of numContrib + TMult multiplicity{}; + for (const auto& collision : collSlice) { + const TMult collMult = collision.numContrib(); + if (collMult > multiplicity) { + centFT0C = collision.centFT0C(); + centFT0M = collision.centFT0M(); + multiplicity = collMult; + } + } + + const auto mcParticlesPerMcColl = particlesMc.sliceBy(preslices.mcParticlesPerMcCollision, mcCollision.globalIndex()); + // Match generated particles. - for (const auto& particle : particlesMc) { + for (const auto& particle : mcParticlesPerMcColl) { int8_t sign{0}; int8_t flag{0}; - if constexpr (decayChannel == DecayChannel::B0ToDminusPi) { + if constexpr (DecayChannel == DecayChannel::B0ToDminusPi) { // B0 → D- π+ if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kB0, std::array{-static_cast(Pdg::kDPlus), +kPiPlus}, true)) { // Match D- -> π- K+ π- @@ -762,9 +1548,84 @@ struct HfDataCreatorCharmHadPiReduced { auto yParticle = RecoDecay::y(particle.pVector(), massB); auto etaParticle = particle.eta(); - std::array ptProngs; - std::array yProngs; - std::array etaProngs; + 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++; + } + tables.rowHfB0McGenReduced(flag, -1 /*channel*/, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1], hfRejMap, centFT0C, centFT0M); + } 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() == NDaughtersDs) { + 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 (configs.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() == NDaughtersDs) { + 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(); @@ -772,12 +1633,12 @@ struct HfDataCreatorCharmHadPiReduced { yProngs[counter] = RecoDecay::y(daught.pVector(), pdg->Mass(daught.pdgCode())); counter++; } - rowHfB0McGenReduced(flag, ptParticle, yParticle, etaParticle, - ptProngs[0], yProngs[0], etaProngs[0], - ptProngs[1], yProngs[1], etaProngs[1]); - } else if constexpr (decayChannel == DecayChannel::BplusToD0barPi) { + tables.rowHfBsMcGenReduced(flag, -1 /*channel*/, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1], hfRejMap, centFT0C, centFT0M); + } 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+"); @@ -795,9 +1656,42 @@ struct HfDataCreatorCharmHadPiReduced { auto yParticle = RecoDecay::y(particle.pVector(), massB); auto etaParticle = particle.eta(); - std::array ptProngs; - std::array yProngs; - std::array etaProngs; + 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++; + } + tables.rowHfBpMcGenReduced(flag, -1 /*channel*/, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1], hfRejMap, centFT0C, centFT0M); + } else if constexpr (DecayChannel == DecayChannel::LbToLcplusPi) { + // Lb → Lc+ π- + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kLambdaB0, std::array{static_cast(Pdg::kLambdaCPlus), -kPiPlus}, true)) { + // Match Lc+ → p K- π+ + auto candCMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + // Printf("Checking Lc+ → p K- π+"); + if (RecoDecay::isMatchedMCGen(particlesMc, candCMC, static_cast(Pdg::kLambdaCPlus), std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + flag = sign * BIT(hf_cand_lb::DecayType::LbToLcPi); + } + } + + // save information for Lc task + if (!TESTBIT(std::abs(flag), hf_cand_lb::DecayType::LbToLcPi)) { + 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(); @@ -805,9 +1699,42 @@ struct HfDataCreatorCharmHadPiReduced { yProngs[counter] = RecoDecay::y(daught.pVector(), pdg->Mass(daught.pdgCode())); counter++; } - rowHfBpMcGenReduced(flag, ptParticle, yParticle, etaParticle, - ptProngs[0], yProngs[0], etaProngs[0], - ptProngs[1], yProngs[1], etaProngs[1]); + tables.rowHfLbMcGenReduced(flag, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1], hfRejMap, centFT0C, centFT0M); + } else if constexpr (DecayChannel == DecayChannel::B0ToDstarPi) { + // B0 → D* π+ + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kB0, std::array{-static_cast(Pdg::kDStar), +kPiPlus}, true)) { + // Match D- -> π- K+ π- + auto candCMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + // Printf("Checking D- -> π- K+ π-"); + if (RecoDecay::isMatchedMCGen(particlesMc, candCMC, +static_cast(Pdg::kDStar), std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 3)) { + flag = sign * BIT(hf_cand_b0::DecayType::B0ToDstarPi); + } + } + + // save information for B0 task + if (!TESTBIT(std::abs(flag), hf_cand_b0::DecayType::B0ToDstarPi)) { + 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++; + } + tables.rowHfB0McGenReduced(flag, -1 /*channel*/, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1], hfRejMap, centFT0C, centFT0M); } } // gen } @@ -815,7 +1742,7 @@ struct HfDataCreatorCharmHadPiReduced { //////////////////////////////////////////////////////////////////////////////////////////////////// // PROCESS FUNCTIONS FOR DATA - void processDplusPiData(soa::Join const& collisions, + void processDplusPiData(CollisionsWCent const& collisions, CandsDplusFiltered const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, @@ -823,7 +1750,7 @@ struct HfDataCreatorCharmHadPiReduced { { // store configurables needed for B0 workflow if (!isHfCandBhadConfigFilled) { - rowCandidateConfigB0(selectionFlagDplus.value, invMassWindowCharmHadPi.value); + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDplus.value, configs.invMassWindowCharmHadPi.value); isHfCandBhadConfigFilled = true; } @@ -836,16 +1763,16 @@ struct HfDataCreatorCharmHadPiReduced { 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); + auto candsCThisColl = candsC.sliceBy(preslices.candsDplusPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.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); + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiData, "Process DplusPi without MC info and without ML info", true); - void processDplusPiDataWithMl(soa::Join const& collisions, + void processDplusPiDataWithMl(CollisionsWCent const& collisions, CandsDplusFilteredWithMl const& candsC, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, @@ -853,7 +1780,7 @@ struct HfDataCreatorCharmHadPiReduced { { // store configurables needed for B0 workflow if (!isHfCandBhadConfigFilled) { - rowCandidateConfigB0(selectionFlagDplus.value, invMassWindowCharmHadPi.value); + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDplus.value, configs.invMassWindowCharmHadPi.value); isHfCandBhadConfigFilled = true; } @@ -866,24 +1793,24 @@ struct HfDataCreatorCharmHadPiReduced { 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); + auto candsCThisColl = candsC.sliceBy(preslices.candsDplusPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.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); + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiDataWithMl, "Process DplusPi without MC info and with ML info", false); - void processD0PiData(soa::Join const& collisions, - CandsD0Filtered const& candsC, - aod::TrackAssoc const& trackIndices, - TracksPidWithSel const& tracks, - aod::BCsWithTimestamps const& bcs) + void processDplusPiDataWithQvec(CollisionsWCentAndQvectors const& collisions, + CandsDplusFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) { - // store configurables needed for B+ workflow + // store configurables needed for B0 workflow if (!isHfCandBhadConfigFilled) { - rowCandidateConfigBplus(selectionFlagD0.value, selectionFlagD0bar.value, invMassWindowCharmHadPi.value); + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDplus.value, configs.invMassWindowCharmHadPi.value); isHfCandBhadConfigFilled = true; } @@ -896,24 +1823,24 @@ struct HfDataCreatorCharmHadPiReduced { 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); + auto candsCThisColl = candsC.sliceBy(preslices.candsDplusPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.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); + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiData, "Process D0Pi without MC info and without ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiDataWithQvec, "Process DplusPi without MC info, without ML info and with Q-vectors", false); - void processD0PiDataWithMl(soa::Join const& collisions, - CandsD0FilteredWithMl const& candsC, - aod::TrackAssoc const& trackIndices, - TracksPidWithSel const& tracks, - aod::BCsWithTimestamps const& bcs) + void processDplusPiDataWithMlAndQvec(CollisionsWCentAndQvectors const& collisions, + CandsDplusFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) { - // store configurables needed for B+ workflow + // store configurables needed for B0 workflow if (!isHfCandBhadConfigFilled) { - rowCandidateConfigBplus(selectionFlagD0.value, selectionFlagD0bar.value, invMassWindowCharmHadPi.value); + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDplus.value, configs.invMassWindowCharmHadPi.value); isHfCandBhadConfigFilled = true; } @@ -926,28 +1853,56 @@ struct HfDataCreatorCharmHadPiReduced { 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); + auto candsCThisColl = candsC.sliceBy(preslices.candsDplusPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.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); + tables.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, processDplusPiDataWithMlAndQvec, "Process DplusPi without MC info, with ML info and with Q-vectors", false); - //////////////////////////////////////////////////////////////////////////////////////////////////// - // PROCESS FUNCTIONS FOR MC + void processDstarPiData(CollisionsWCent const& collisions, + CandsDstarFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs, + aod::Hf2Prongs const&) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDstar.value, configs.invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } - void processDplusPiMc(soa::Join const& collisions, - CandsDplusFiltered const& candsC, - aod::TrackAssoc const& trackIndices, - TracksPidWithSelAndMc 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 candsCThisColl = candsC.sliceBy(preslices.candsDstarPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDstarPiData, "Process DstarPi without MC info and without ML info", false); + + void processDstarPiDataWithMl(CollisionsWCent const& collisions, + CandsDstarFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs, + aod::Hf2Prongs const&) { // store configurables needed for B0 workflow if (!isHfCandBhadConfigFilled) { - rowCandidateConfigB0(selectionFlagDplus.value, invMassWindowCharmHadPi.value); + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDstar.value, configs.invMassWindowCharmHadPi.value); isHfCandBhadConfigFilled = true; } @@ -960,26 +1915,56 @@ struct HfDataCreatorCharmHadPiReduced { 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 candsCThisColl = candsC.sliceBy(preslices.candsDstarPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.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); - runMcGen(particlesMc); + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiMc, "Process DplusPi with MC info and without ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDstarPiDataWithMl, "Process DstarPi without MC info and with ML info", false); + + void processDstarPiDataWithQvec(CollisionsWCentAndQvectors const& collisions, + CandsDstarFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs, + aod::Hf2Prongs const&) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDstar.value, configs.invMassWindowCharmHadPi.value); + isHfCandBhadConfigFilled = true; + } - void processDplusPiMcWithMl(soa::Join const& collisions, - CandsDplusFilteredWithMl const& candsC, - aod::TrackAssoc const& trackIndices, - TracksPidWithSelAndMc 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 candsCThisColl = candsC.sliceBy(preslices.candsDstarPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDstarPiDataWithQvec, "Process DstarPi without MC info, without ML info and with Q-vectors", false); + + void processDstarPiDataWithMlAndQvec(CollisionsWCentAndQvectors const& collisions, + CandsDstarFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs, + aod::Hf2Prongs const&) { // store configurables needed for B0 workflow if (!isHfCandBhadConfigFilled) { - rowCandidateConfigB0(selectionFlagDplus.value, invMassWindowCharmHadPi.value); + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDstar.value, configs.invMassWindowCharmHadPi.value); isHfCandBhadConfigFilled = true; } @@ -992,26 +1977,24 @@ struct HfDataCreatorCharmHadPiReduced { 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 candsCThisColl = candsC.sliceBy(preslices.candsDstarPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.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); - runMcGen(particlesMc); + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiMcWithMl, "Process DplusPi with MC info and with ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDstarPiDataWithMlAndQvec, "Process DstarPi without MC info, with ML info and with Q-vectors", false); - void processD0PiMc(soa::Join const& collisions, - CandsD0Filtered const& candsC, - aod::TrackAssoc const& trackIndices, - TracksPidWithSelAndMc const& tracks, - aod::McParticles const& particlesMc, - aod::BCsWithTimestamps const& bcs) + void processDsPiData(CollisionsWCent const& collisions, + CandsDsFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) { - // store configurables needed for B+ workflow + // store configurables needed for Bs workflow if (!isHfCandBhadConfigFilled) { - rowCandidateConfigBplus(selectionFlagD0.value, selectionFlagD0bar.value, invMassWindowCharmHadPi.value); + tables.rowCandidateConfigBs(hfflagConfigurations.selectionFlagDs.value, configs.invMassWindowCharmHadPi.value); isHfCandBhadConfigFilled = true; } @@ -1024,26 +2007,114 @@ struct HfDataCreatorCharmHadPiReduced { 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 candsCThisColl = candsC.sliceBy(preslices.candsDsPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.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); - runMcGen(particlesMc); + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiMc, "Process D0Pi with MC info and without ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDsPiData, "Process DsPi without MC info and without ML info", false); - void processD0PiMcWithMl(soa::Join const& collisions, - CandsD0FilteredWithMl const& candsC, - aod::TrackAssoc const& trackIndices, - TracksPidWithSelAndMc const& tracks, - aod::McParticles const& particlesMc, - aod::BCsWithTimestamps const& bcs) + 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) { + tables.rowCandidateConfigBs(hfflagConfigurations.selectionFlagDs.value, configs.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(preslices.candsDsPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.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) { + tables.rowCandidateConfigBs(hfflagConfigurations.selectionFlagDs.value, configs.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(preslices.candsDsPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDsPiDataWithQvec, "Process DsPi without MC info, without ML info and with Q-vectors", false); + + 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) { + tables.rowCandidateConfigBs(hfflagConfigurations.selectionFlagDs.value, configs.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(preslices.candsDsPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.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, + aod::BCsWithTimestamps const& bcs) { // store configurables needed for B+ workflow if (!isHfCandBhadConfigFilled) { - rowCandidateConfigBplus(selectionFlagD0.value, selectionFlagD0bar.value, invMassWindowCharmHadPi.value); + tables.rowCandidateConfigBplus(hfflagConfigurations.selectionFlagD0.value, hfflagConfigurations.selectionFlagD0bar.value, configs.invMassWindowCharmHadPi.value); isHfCandBhadConfigFilled = true; } @@ -1056,15 +2127,540 @@ struct HfDataCreatorCharmHadPiReduced { 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 candsCThisColl = candsC.sliceBy(preslices.candsD0PerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.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); - runMcGen(particlesMc); + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiData, "Process D0Pi without MC info and without ML info", false); + + void processD0PiDataWithMl(CollisionsWCent const& collisions, + CandsD0FilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for B+ workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigBplus(hfflagConfigurations.selectionFlagD0.value, hfflagConfigurations.selectionFlagD0bar.value, configs.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(preslices.candsD0PerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.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) { + tables.rowCandidateConfigBplus(hfflagConfigurations.selectionFlagD0.value, hfflagConfigurations.selectionFlagD0bar.value, configs.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(preslices.candsD0PerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.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) { + tables.rowCandidateConfigBplus(hfflagConfigurations.selectionFlagD0.value, hfflagConfigurations.selectionFlagD0bar.value, configs.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(preslices.candsD0PerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiDataWithMlAndQvec, "Process D0Pi without MC info, with ML info, and with Q-vectors", false); + + void processLcPiData(CollisionsWCent const& collisions, + CandsLcFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for Lb workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigLb(hfflagConfigurations.selectionFlagLc.value, configs.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(preslices.candsLcPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processLcPiData, "Process LcPi without MC info and without ML info", false); + + void processLcPiDataWithMl(CollisionsWCent const& collisions, + CandsLcFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for Lb workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigLb(hfflagConfigurations.selectionFlagLc.value, configs.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(preslices.candsLcPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processLcPiDataWithMl, "Process LcPi without MC info and with ML info", false); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // PROCESS FUNCTIONS FOR MC + + void processDplusPiMc(CollisionsWCentAndMcLabels const& collisions, + CandsDplusFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDplus.value, configs.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(preslices.candsDplusPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiMc, "Process DplusPi with MC info and without ML info", false); + + void processDplusPiMcWithMl(CollisionsWCentAndMcLabels const& collisions, + CandsDplusFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDplus.value, configs.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(preslices.candsDplusPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDplusPiMcWithMl, "Process DplusPi with MC info and with ML info", false); + + void processDstarPiMc(CollisionsWCentAndMcLabels const& collisions, + CandsDstarFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions, + aod::Hf2Prongs const&) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDstar.value, configs.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(preslices.candsDstarPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDstarPiMc, "Process DstarPi with MC info and without ML info", false); + + void processDstarPiMcWithMl(CollisionsWCentAndMcLabels const& collisions, + CandsDstarFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions, + aod::Hf2Prongs const&) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigB0(hfflagConfigurations.selectionFlagDstar.value, configs.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(preslices.candsDstarPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processDstarPiMcWithMl, "Process DstarPi with MC info and with ML info", false); + + void processDsPiMc(CollisionsWCentAndMcLabels const& collisions, + CandsDsFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for Bs workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigBs(hfflagConfigurations.selectionFlagDs.value, configs.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(preslices.candsDsPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + 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, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for Bs workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigBs(hfflagConfigurations.selectionFlagDs.value, configs.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(preslices.candsDsPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + 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, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for B+ workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigBplus(hfflagConfigurations.selectionFlagD0.value, hfflagConfigurations.selectionFlagD0bar.value, configs.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(preslices.candsD0PerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiMc, "Process D0Pi with MC info and without ML info", false); + + void processD0PiMcWithMl(CollisionsWCentAndMcLabels const& collisions, + CandsD0FilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for B+ workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigBplus(hfflagConfigurations.selectionFlagD0.value, hfflagConfigurations.selectionFlagD0bar.value, configs.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(preslices.candsD0PerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } } PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processD0PiMcWithMl, "Process D0Pi with MC info and with ML info", false); + + void processLcPiMc(CollisionsWCentAndMcLabels const& collisions, + CandsLcFiltered const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for Lb workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigLb(hfflagConfigurations.selectionFlagDplus.value, configs.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(preslices.candsLcPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processLcPiMc, "Process LcPi with MC info and without ML info", false); + + void processLcPiMcWithMl(CollisionsWCentAndMcLabels const& collisions, + CandsLcFilteredWithMl const& candsC, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for Lb workflow + if (!isHfCandBhadConfigFilled) { + tables.rowCandidateConfigLb(hfflagConfigurations.selectionFlagLc.value, configs.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(preslices.candsLcPerCollisionWithMl, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(preslices.trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(preslices.colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsCThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + tables.hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorCharmHadPiReduced, processLcPiMcWithMl, "Process LcPi with MC info and with ML info", false); + }; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmResoReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmResoReduced.cxx index 5d6f3f2c4c5..5dd72be0c9e 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmResoReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmResoReduced.cxx @@ -15,30 +15,61 @@ /// \author Luca Aglietta , UniTO Turin /// \author Fabrizio Grosa , CERN -#include -#include - -#include "DetectorsBase/Propagator.h" -#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 "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsMcMatching.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#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" +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -46,7 +77,6 @@ using namespace o2::aod; using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; - // event types enum Event : uint8_t { Processed = 0, @@ -55,12 +85,6 @@ enum Event : uint8_t { kNEvent }; -enum DecayChannel : uint8_t { - DstarV0 = 0, - DplusV0, - DstarTrack -}; - enum BachelorType : uint8_t { K0s = 0, Lambda, @@ -70,54 +94,77 @@ enum BachelorType : uint8_t { enum DType : uint8_t { Dplus = 1, - Dstar + Dstar, + D0 +}; + +enum PairingType : uint8_t { + V0Only, + TrackOnly, + V0AndTrack +}; + +enum D0Sel : uint8_t { + SelectedD0 = 0, + SelectedD0Bar }; /// 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 // tracks, V0 and D candidates reduced tables - Produces hfCandV0; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + 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 + Produces hfCandD3Pr; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + Produces hfCandD2Pr; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + Produces hfCandDstar; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h // ML optional Tables - Produces hfCandDMl; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h - - // CCDB configuration - o2::ccdb::CcdbApi ccdbApi; - Service ccdb; - 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"}; + Produces hfCandD3PrMl; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + Produces hfCandD2PrMl; // Defined in PWGHF/D2H/DataModel/ReducedDataModel.h + // MC Tables + Produces rowHfResoMcGenReduced; + Produces rowHf3PrV0McRecReduced; + Produces rowHfDstarV0McRecReduced; + Produces rowHf2PrV0McRecReduced; + Produces rowHf3PrTrkMcRecReduced; + Produces rowHfDstarTrkMcRecReduced; + Produces rowHf2PrTrkMcRecReduced; - int runNumber{0}; // needed to detect if the run changed and trigger update of calibrations etc. // selection D 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"}; + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; + Configurable selectionFlagD0Bar{"selectionFlagD0Bar", 1, "Selection Flag for D0bar"}; } cfgDmesCuts; // selection V0 struct : ConfigurableGroup { std::string prefix = "v0s"; - 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"}; + 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 trackFracMaxindableTpcCls{"trackFracMaxindableTpcCls", 0.8f, "Maximum fraction of findable 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"; + std::string prefix = "singleTracks"; 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"}; @@ -126,36 +173,120 @@ struct HfDataCreatorCharmResoReduced { Configurable maxNsigmaTpcPr{"maxNsigmaTpcPr", 3., "maximum proton NSigma in TPC for single tracks to be paired with D mesons; set negative to reject"}; } cfgSingleTrackCuts; + // QA histograms + struct : ConfigurableGroup { + std::string prefix = "qaPlots"; + Configurable applyCutsForQaHistograms{"applyCutsForQaHistograms", true, "flag to apply cuts to QA histograms"}; + Configurable cutMassDstarMin{"cutMassDstarMin", 0.143, "minimum mass for Dstar candidates"}; + Configurable cutMassDstarMax{"cutMassDstarMax", 0.155, "maximum mass for Dstar candidates"}; + Configurable cutMassDMin{"cutMassDMin", 1.83, "minimum mass for D0 and Dplus candidates"}; + Configurable cutMassDMax{"cutMassDMax", 1.92, "maximum mass for D0 and Dplus candidates"}; + Configurable cutMassK0sMin{"cutMassK0sMin", 0.485, "minimum mass for K0s candidates"}; + Configurable cutMassK0sMax{"cutMassK0sMax", 0.509, "maximum mass for K0s candidates"}; + Configurable cutMassLambdaMin{"cutMassLambdaMin", 1.11, "minimum mass for Lambda candidates"}; + Configurable cutMassLambdaMax{"cutMassLambdaMax", 1.12, "maximum mass for Lambda candidates"}; + } cfgQaPlots; // other configurables + Configurable ccdbUrl{"ccdbUrl", "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"}; Configurable rejectPairsWithCommonDaughter{"rejectPairsWithCommonDaughter", true, "flag to reject already at this stage the pairs that share a daughter track"}; + Configurable rejectCollisionsWithBadEvSel{"rejectCollisionsWithBadEvSel", true, "flag to reject collisions with bad event selection"}; + + o2::hf_evsel::HfEventSelection hfEvSel; + o2::hf_evsel::HfEventSelectionMc hfEvSelMc; + + // CCDB service + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + double bz{0.}; + int runNumber{0}; // needed to detect if the run changed and trigger update of calibrations etc. // material correction for track propagation - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - HfHelper hfHelper; - o2::hf_evsel::HfEventSelection hfEvSel; - bool isHfCandResoConfigFilled = false; + // O2DatabasePDG service + Service pdg; + // vertex fitter + o2::vertexing::DCAFitterN<2> fitter; + + // 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 invMassD0; + float invMassD0Bar; + float invMassReso; + float ptReso; + int8_t signD; + std::array pVectorProng0; + std::array pVectorProng1; + std::array pVectorProng2; + } varUtils{}; + + // Dplus using CandsDplusFiltered = soa::Filtered>; using CandsDplusFilteredWithMl = soa::Filtered>; - using CandDstarFiltered = soa::Filtered>; - using CandDstarFilteredWithMl = soa::Filtered>; + using CandsDplusFilteredWithMc = soa::Filtered>; + using CandsDplusFilteredWithMlAndMc = soa::Filtered>; + // Dstar + using CandsDstarFiltered = soa::Filtered>; + using CandsDstarFilteredWithMl = soa::Filtered>; + using CandsDstarFilteredWithMc = soa::Filtered>; + using CandsDstarFilteredWithMlAndMc = soa::Filtered>; + // D0 + using CandsD0Filtered = soa::Filtered>; + using CandsD0FilteredWithMl = soa::Filtered>; + using CandsD0FilteredWithMc = soa::Filtered>; + using CandsD0FilteredWithMlAndMc = soa::Filtered>; + // Tracks using TracksWithPID = soa::Join; + using TracksWithPIDAndMC = soa::Join; + using TracksIUWithPID = soa::Join; + using TracksIUWithPIDAndMC = soa::Join; + // Collisions MC + using BCsInfo = soa::Join; + using McCollisionsNoCents = soa::Join; Filter filterSelectDplus = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= cfgDmesCuts.selectionFlagDplus); Filter filterSelectedCandDstar = (aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == cfgDmesCuts.selectionFlagDstarToD0Pi); + Filter filterSelectD0Candidates = (aod::hf_sel_candidate_d0::isSelD0 >= cfgDmesCuts.selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= cfgDmesCuts.selectionFlagD0Bar); 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::v0data::collisionId; + Preslice candsDstarPerCollision = aod::hf_cand::collisionId; + Preslice candsDstarPerCollisionWithMl = aod::hf_cand::collisionId; + Preslice candsD0PerCollision = aod::hf_cand::collisionId; + Preslice candsD0PerCollisionWithMl = aod::hf_cand::collisionId; + Preslice candsV0PerCollision = aod::v0::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; HistogramRegistry registry{"registry"}; + OutputObj zorroSummary{"zorroSummary"}; - void init(InitContext const&) + void init(InitContext& initContext) { // histograms constexpr int kNBinsEvents = kNEvent; @@ -164,96 +295,272 @@ struct HfDataCreatorCharmResoReduced { labels[Event::NoDV0Selected] = "without DV0 pairs"; labels[Event::DV0Selected] = "with DV0 pairs"; static const AxisSpec axisEvents = {kNBinsEvents, 0.5, kNBinsEvents + 0.5, ""}; - registry.add("hEvents", "Events;;entries", HistType::kTH1F, {axisEvents}); + registry.add("hEvents", "Events;;entries", HistType::kTH1D, {axisEvents}); for (int iBin = 0; iBin < kNBinsEvents; iBin++) { registry.get(HIST("hEvents"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } - const AxisSpec axisPt{50, 0.f, 50.f, ""}; - const AxisSpec axisP{100, 0.f, 10.f, ""}; + const AxisSpec axisPt{50, 0.f, 50.f, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisP{100, 0.f, 10.f, "#it{p} (GeV/#it{c})"}; 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, ""}; - - 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, {{400, 0.49, 0.89}}}); - registry.add("hMassDsStar2", "Ds^{*}2 candidates; Ds^{*}2 - m_{D^{#plus}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{400, 0.49, 0.89}}}); - 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("hV0Type", "V0 selection flag", {HistType::kTH1F, {{8, -0.5, 7.5}}}); - registry.add("hDType", "D selection flag", {HistType::kTH1F, {{5, -2.5, 2.5}}}); + const AxisSpec axisMassD0{200, 1.7f, 2.1f, "inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisMassDplus{200, 1.7f, 2.1f, "inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisMassDstar{200, 0.139f, 0.179f, "delta inv. mass (GeV/#it{c}^{2})"}; // o2-linter: disable=pdg/explicit-mass (false positive) + const AxisSpec axisMassLambda{100, 1.05f, 1.35f, "inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisMassKzero{100, 0.35f, 0.65f, "inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisDeltaMassToK{500, 0.49, 1.49, "inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisDeltaMassToPi{500, 0.13, 1.13, "inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisDeltaMassToPr{500, 0.93, 1.93, "inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisDeltaMassToLambda{500, 1.05, 2.05, "inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisMassDsj{400, 0.49f, 0.89f, ""}; // Ds1 and Ds2Star legacy + registry.add("hMassVsPtK0s", "K0^{s} candidates;#it{p}_{T} (GeV/#it{c});inv. mass (#pi^{#plus}#pi^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisMassKzero}}); + registry.add("hMassVsPtLambda", "Lambda candidates;#it{p}_{T} (GeV/#it{c});inv. mass (p #pi^{#minus}) (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisMassLambda}}); + registry.add("hdEdxVsP", "Tracks;#it{p} (GeV/#it{c});d#it{E}/d#it{x};entries", {HistType::kTH2D, {axisP, axisDeDx}}); + if (doprocessD0V0 || doprocessD0Track || doprocessD0V0AndTrack || doprocessD0V0WithMl || doprocessD0TrackWithMl || doprocessD0V0AndTrackWithMl || + doprocessD0V0MC || doprocessD0TrackMC || doprocessD0V0AndTrackMC || doprocessD0V0MCWithMl || doprocessD0TrackMCWithMl || doprocessD0V0AndTrackMCWithMl) { + registry.add("hMassVsPtD0All", "D0 candidates (all, regardless the pairing with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisMassD0}}); + registry.add("hMassVsPtD0BarAll", "D0bar candidates (all, regardless the pairing with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisMassD0}}); + registry.add("hMassVsPtD0Paired", "D0 candidates (paired with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisMassD0}}); + registry.add("hMassVsPtD0BarPaired", "D0 candidates (paired with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisMassD0}}); + registry.add("hMassD0Pi", "D0Pi candidates; m_{D^{0}#pi^{+}} - m_{D^{0}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToPi}}); + registry.add("hMassD0K", "D0Kplus candidates; m_{D^{0}K^{+}} - m_{D^{0}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToK}}); + registry.add("hMassD0Proton", "D0Proton candidates; m_{D^{0}p} - m_{D^{0}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToPr}}); + registry.add("hMassD0Lambda", "D0Lambda candidates; m_{D^{0}#Lambda} - m_{D^{0}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToLambda}}); + } + if (doprocessDstarV0 || doprocessDstarTrack || doprocessDstarV0AndTrack || doprocessDstarV0WithMl || doprocessDstarTrackWithMl || doprocessDstarV0AndTrackWithMl || + doprocessDstarV0MC || doprocessDstarTrackMC || doprocessDstarV0AndTrackMC || doprocessDstarV0MCWithMl || doprocessDstarTrackMCWithMl || doprocessDstarV0AndTrackMCWithMl) { + 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::kTH2D, {axisPt, axisMassDstar}}); + registry.add("hMassVsPtDstarPaired", "Dstar candidates (paired with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisMassDstar}}); + registry.add("hMassDstarPi", "DstarPi candidates; m_{D^{*+}#pi^{-}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToPi}}); + registry.add("hMassDstarK", "DstarK candidates; m_{D^{*+}#pi^{-}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToK}}); + registry.add("hMassDstarProton", "DstarProton candidates; m_{D^{*}p} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToPr}}); + registry.add("hMassDstarK0s", "DstarK0s candidates; m_{D^{*}K^{0}_{S}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToK}}); + registry.add("hMassDstarLambda", "DstarLambda candidates; m_{D^{*}#Lambda} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToLambda}}); + } + if (doprocessDplusV0 || doprocessDplusTrack || doprocessDplusV0AndTrack || doprocessDplusV0WithMl || doprocessDplusTrackWithMl || doprocessDplusV0AndTrackWithMl || + doprocessDplusV0MC || doprocessDplusTrackMC || doprocessDplusV0AndTrackMC || doprocessDplusV0MCWithMl || doprocessDplusTrackMCWithMl || doprocessDplusV0AndTrackMCWithMl) { + 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::kTH2D, {axisPt, axisMassDplus}}); + registry.add("hMassVsPtDplusPaired", "Dplus candidates (paired with V0s);#it{p}_{T} (GeV/#it{c});inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisMassDplus}}); + registry.add("hMassDplusK0s", "DplusK0s candidates; m_{D^{+}K^{0}_{S}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToK}}); + registry.add("hMassDplusPi", "DplusPi candidates; m_{D^{+}#pi^{-}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToPi}}); + registry.add("hMassDplusK", "DplusK candidates; m_{D^{+}#pi^{-}} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToK}}); + registry.add("hMassDplusProton", "DplusProton candidates; m_{D^{+}p} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToPr}}); + registry.add("hMassDplusLambda", "DplusLambda candidates; m_{D^{+}#Lambda} (GeV/#it{c}^{2});entries", {HistType::kTH2D, {axisPt, axisDeltaMassToLambda}}); + } + if (doprocessD0V0MC || doprocessD0TrackMC || doprocessD0V0AndTrackMC || doprocessD0V0MCWithMl || doprocessD0TrackMCWithMl || doprocessD0V0AndTrackMCWithMl || + doprocessDstarV0MC || doprocessDstarTrackMC || doprocessDstarV0AndTrackMC || doprocessDstarV0MCWithMl || doprocessDstarTrackMCWithMl || doprocessDstarV0AndTrackMCWithMl || + doprocessDplusV0MC || doprocessDplusTrackMC || doprocessDplusV0AndTrackMC || doprocessDplusV0MCWithMl || doprocessDplusTrackMCWithMl || doprocessDplusV0AndTrackMCWithMl) { + // MC Rec + int const nChannels = hf_decay::hf_cand_reso::DecayChannelMain::NChannelsMain; + registry.add("hMCRecCounter", "Number of Reconstructed MC Matched candidates per channel", {HistType::kTH1D, {{2 * nChannels + 1, -(nChannels + 0.5), nChannels + 0.5}}}); + registry.add("hMCRecDebug", "Debug of MC Reco", {HistType::kTH1D, {{551, -0.5, 550.5}}}); + registry.add("hMCRecOrigin", "Origin of Matched particles", {HistType::kTH1D, {{3, -0.5, 2.5}}}); + registry.add("hMCRecMassGen", "Generated inv. mass of resoncances", {HistType::kTH1D, {{2000, 1.8, 3.8}}}); + registry.add("hMCRecCharmDau", "Charm daughter flag", {HistType::kTH1D, {{57, -28.5, 28.5}}}); + // MC Gen + registry.add("hMCGenCounter", "Number of Generated particles; Decay Channel Flag; pT [GeV/c]", {HistType::kTH2D, {{17, -8.5, 8.5}, {100, 0, 50}}}); + registry.add("hMCGenOrigin", "Origin of Generated particles", {HistType::kTH1D, {{3, -0.5, 2.5}}}); + } // Configure CCDB access - ccdb->setURL(url.value); + ccdb->setURL(ccdbUrl.value); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); - ccdbApi.init(url); + ccdbApi.init(ccdbUrl); 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); + + // init HF event selection helper + hfEvSel.init(registry, zorroSummary); + + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name == "hf-data-creator-charm-reso-reduced") { + // init HF event selection helper + hfEvSelMc.init(device, registry); + break; + } + } + } + + /// 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() < cfgV0Cuts.trackFracMaxindableTpcCls * 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 const momTot = std::sqrt(std::pow(momA[0], 2.) + std::pow(momA[1], 2.) + std::pow(momA[2], 2.)); + float const lQlPos = (momB[0] * momA[0] + momB[1] * momA[1] + momB[2] * momA[2]) / momTot; + float const 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 /// \return a bitmap with mass hypotesis if passes all cuts - template - 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 (rejectPairsWithCommonDaughter && (std::find(dDaughtersIds.begin(), dDaughtersIds.end(), v0.posTrackId()) != dDaughtersIds.end() || std::find(dDaughtersIds.begin(), dDaughtersIds.end(), v0.negTrackId()) != dDaughtersIds.end())) { - return 0; + const auto& trackPos = dauTracks[0]; + const auto& trackNeg = dauTracks[1]; + // single-tracks selection + if (!selectV0Daughter(trackPos, dDaughtersIds) || !selectV0Daughter(trackNeg, dDaughtersIds)) { + return false; + } + // daughters DCA to V0's collision primary vertex + std::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 (...) { + 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); + + candidateV0.mom = RecoDecay::pVec(candidateV0.momPos, candidateV0.momNeg); + + 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()) > cfgV0Cuts.minV0dauEta || std::fabs(v0.positiveeta()) > cfgV0Cuts.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() < cfgV0Cuts.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 < cfgV0Cuts.minK0sLambdaCosinePa) { - return 0; + std::copy(vtx.begin(), vtx.end(), candidateV0.pos.begin()); + + // 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; } - // DCA V0 and V0 daughters to select for primary V0s - if (v0.dcav0topv() > cfgV0Cuts.maxV0DCA || v0.dcaV0daughters() > cfgV0Cuts.maxV0dauDCA || std::fabs(v0.dcapostopv()) < cfgV0Cuts.minV0dauDCA || std::fabs(v0.dcanegtopv()) < cfgV0Cuts.minV0dauDCA) { - return 0; + // v0 cosine of pointing angle + std::array const 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(BachelorType::K0s) | BIT(BachelorType::Lambda) | BIT(BachelorType::AntiLambda)}; + // for lambda hypotesys define if its lambda or anti-lambda + candidateV0.alpha = alphaAP(candidateV0.mom, candidateV0.momPos, candidateV0.momNeg); + bool const matter = candidateV0.alpha > 0; + CLRBIT(candidateV0.v0Type, matter ? BachelorType::AntiLambda : BachelorType::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) > cfgV0Cuts.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, BachelorType::K0s); } - if (std::fabs(v0.mLambda() - MassLambda0) > cfgV0Cuts.deltaMassLambda) { - CLRBIT(selMap, Lambda); + if (std::fabs(candidateV0.mLambda - MassLambda0) > cfgV0Cuts.deltaMassLambda) { + CLRBIT(candidateV0.v0Type, BachelorType::Lambda); + CLRBIT(candidateV0.v0Type, BachelorType::AntiLambda); } - if (std::fabs(v0.mAntiLambda() - MassLambda0) > cfgV0Cuts.deltaMassLambda) { - CLRBIT(selMap, AntiLambda); + // PID + if (TESTBIT(candidateV0.v0Type, BachelorType::K0s)) { + if ((trackPos.hasTPC() && std::fabs(trackPos.tpcNSigmaPi()) > cfgV0Cuts.nSigmaTpc) || + (trackNeg.hasTPC() && std::fabs(trackNeg.tpcNSigmaPi()) > cfgV0Cuts.nSigmaTpc)) { + CLRBIT(candidateV0.v0Type, BachelorType::K0s); + } + } + if (TESTBIT(candidateV0.v0Type, BachelorType::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, BachelorType::Lambda); + } } - // 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]) > cfgV0Cuts.maxNsigmaPrForLambda) || (dauTracks[0].hasTOF() && std::fabs(nSigmaPrTof[0]) > cfgV0Cuts.maxNsigmaPrForLambda))) { - CLRBIT(selMap, Lambda); + if (TESTBIT(candidateV0.v0Type, BachelorType::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, BachelorType::AntiLambda); + } } - if (TESTBIT(selMap, AntiLambda) && ((dauTracks[1].hasTPC() && std::fabs(nSigmaPrTpc[1]) > cfgV0Cuts.maxNsigmaPrForLambda) || (dauTracks[1].hasTOF() && std::fabs(nSigmaPrTof[1]) > cfgV0Cuts.maxNsigmaPrForLambda))) { - CLRBIT(selMap, AntiLambda); + if (candidateV0.v0Type == 0) { + return false; } - return selMap; + return true; } /// Basic selection of tracks @@ -263,11 +570,9 @@ struct HfDataCreatorCharmResoReduced { template bool isTrackSelected(const Tr& track, const std::array& dDaughtersIds) { - if (rejectPairsWithCommonDaughter && std::find(dDaughtersIds.begin(), dDaughtersIds.end(), track.globalIndex()) != dDaughtersIds.end()) { return false; } - switch (cfgSingleTrackCuts.setTrackSelections) { case 1: if (!track.isGlobalTrackWoDCA()) { @@ -285,231 +590,989 @@ struct HfDataCreatorCharmResoReduced { } break; } - if (track.pt() < cfgSingleTrackCuts.minPt) { return false; } - if (std::abs(track.eta()) > cfgSingleTrackCuts.maxEta) { return false; } - if (!track.hasTPC()) { return false; } + bool const isPion = std::abs(track.tpcNSigmaPi()) < cfgSingleTrackCuts.maxNsigmaTpcPi; + bool const isKaon = std::abs(track.tpcNSigmaKa()) < cfgSingleTrackCuts.maxNsigmaTpcKa; + bool const isProton = std::abs(track.tpcNSigmaPr()) < cfgSingleTrackCuts.maxNsigmaTpcPr; + return (isPion || isKaon || isProton); // we keep the track if is it compatible with at least one of the PID hypotheses selected + } + + template + int8_t getMatchingFlagV0(PParticles const& particlesMc, const std::array& arrDaughtersV0) + { + int8_t signV0{0}; + int indexRec{-1}; + int flagV0{0}; + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersV0, kK0, std::array{+kPiPlus, -kPiPlus}, true, &signV0, 2); + if (indexRec > -1) { + flagV0 = hf_decay::hf_cand_reso::PartialMatchMc::K0Matched; + } else { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersV0, kLambda0, std::array{+kProton, -kPiPlus}, true, &signV0, 2); + if (indexRec > -1) { + flagV0 = signV0 * hf_decay::hf_cand_reso::PartialMatchMc::LambdaMatched; + } + } + return flagV0; // Placeholder, should return the actual flag based on matching logic + } - bool isPion = std::abs(track.tpcNSigmaPi()) < cfgSingleTrackCuts.maxNsigmaTpcPi; - bool isKaon = std::abs(track.tpcNSigmaKa()) < cfgSingleTrackCuts.maxNsigmaTpcKa; - bool isProton = std::abs(track.tpcNSigmaPr()) < cfgSingleTrackCuts.maxNsigmaTpcPr; + template + float computeInvMassGen(PParticles const& particlesMc, int indexRec) + { + auto particleReso = particlesMc.iteratorAt(indexRec); + auto dau1 = particlesMc.iteratorAt(particleReso.daughtersIds().front()); + auto dau2 = particlesMc.iteratorAt(particleReso.daughtersIds().back()); + std::array, 2> pArr = {{{dau1.px(), dau1.py(), dau1.pz()}, {dau2.px(), dau2.py(), dau2.pz()}}}; + std::array mArr = {static_cast(pdg->Mass(dau1.pdgCode())), static_cast(pdg->Mass(dau2.pdgCode()))}; + return static_cast(RecoDecay::m(pArr, mArr)); + } - if (!isPion && !isKaon && !isProton) { // we keep the track if is it compatible with at least one of the PID hypotheses selected - return false; + /// Function for filling MC reco information of DV0 candidates in the tables + /// \tparam dType is the D meson type (Dstar, Dplus or D0) + /// \param particlesMc is the table with MC particles + /// \param candCharmBach is the D meson candidate + /// \param bachelorV0 is the V0 candidate + /// \param tracks is the table with tracks + /// \param indexHfCandCharm is the index of the charm-hadron bachelor in the reduced table + /// \param indexCandV0TrBach is the index of the v0 bachelor in the reduced table + template + void fillMcRecoInfoDV0(PParticles const& particlesMc, + CCand const& candCharmBach, + BBachV0 const& bachelorV0, + Tr const& tracks, + int& indexHfCandCharm, + int64_t& indexCandV0Bach) + { + std::vector vecDaughtersReso{}; + int8_t sign{0}, nKinkedTracks{0}, origin{0}, flagCharmBach{0}, flagCharmBachInterm{0}, flagV0{0}, flagReso{0}; + int indexRec{-1}, debugMcRec{0}; + float ptGen{-1.f}, invMassGen{-1.f}; + if constexpr (DType == DType::Dstar) { + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong0Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong1Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prongPiId())); + // Check if D* is matched + flagCharmBach = candCharmBach.flagMcMatchRec(); + if (flagCharmBach != 0) { + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::DstarMatched); + origin = candCharmBach.originMcRec(); + } + // Check if D0 is matched + flagCharmBachInterm = candCharmBach.flagMcMatchRecD0(); + if (flagCharmBachInterm != 0) { + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::D0Matched); + } + // Check if V0 is matched + vecDaughtersReso.push_back(tracks.rawIteratorAt(bachelorV0.posTrackId())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(bachelorV0.negTrackId())); + flagV0 = getMatchingFlagV0(particlesMc, std::array{vecDaughtersReso[3], vecDaughtersReso[4]}); + if (flagV0 != 0) { + SETBIT(debugMcRec, std::abs(flagV0)); + } + // If both D* and K0s are matched, try to match resonance + if (flagCharmBach != 0 && flagV0 == hf_decay::hf_cand_reso::PartialMatchMc::K0Matched) { + std::array const pdgCodesDaughters = {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}; + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], vecDaughtersReso[3], vecDaughtersReso[4]}; + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDstarK0s) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + break; + } + } + } else if (flagCharmBachInterm != 0 && flagV0 == hf_decay::hf_cand_reso::PartialMatchMc::K0Matched) { + std::array const pdgCodesDaughters = {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}; + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[3], vecDaughtersReso[4]}; + // Peaking background of D0K0s <- Ds* with spurious soft pion + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDstarK0s) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::ResoPartlyMatched); + break; + } + } + } + // No physical channel expected in D*Lambda + if (indexRec > -1) { + auto particleReso = particlesMc.iteratorAt(indexRec); + ptGen = particleReso.pt(); + invMassGen = computeInvMassGen(particlesMc, indexRec); + } + rowHfDstarV0McRecReduced(indexHfCandCharm, indexCandV0Bach, + flagReso, flagCharmBach, + flagCharmBachInterm, debugMcRec, + origin, ptGen, invMassGen, + nKinkedTracks); + } else if constexpr (DType == DType::Dplus) { + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong0Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong1Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong2Id())); + // Check if D+ is matched + flagCharmBach = candCharmBach.flagMcMatchRec(); + flagCharmBachInterm = candCharmBach.flagMcDecayChanRec(); + if (flagCharmBach != 0) { + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::DplusMatched); + origin = candCharmBach.originMcRec(); + } + // Check if V0 is matched + vecDaughtersReso.push_back(tracks.rawIteratorAt(bachelorV0.posTrackId())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(bachelorV0.negTrackId())); + flagV0 = getMatchingFlagV0(particlesMc, std::array{vecDaughtersReso[3], vecDaughtersReso[4]}); + if (flagV0 != 0) { + SETBIT(debugMcRec, std::abs(flagV0)); + } + // If both D+ and K0s are matched, try to match resonance + if (hf_decay::hf_cand_3prong::daughtersDplusMain.contains(static_cast(std::abs(flagCharmBach))) && flagV0 == hf_decay::hf_cand_reso::PartialMatchMc::K0Matched) { + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], vecDaughtersReso[3], vecDaughtersReso[4]}; + auto pdgCodesDplusDaughters = hf_decay::hf_cand_3prong::daughtersDplusMain.at(static_cast(std::abs(flagCharmBach))); + auto pdgCodesDaughters = std::array{pdgCodesDplusDaughters[0], pdgCodesDplusDaughters[1], pdgCodesDplusDaughters[2], +kPiPlus, -kPiPlus}; + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDplusK0s) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + break; + } + } + // Partial matching of Dsj -> D*K0s -> (D+ pi0) (K0s) with missing neutral + if (indexRec < 0) { + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDstarK0s) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::ResoPartlyMatched); + break; + } + } + } + + } else if (hf_decay::hf_cand_3prong::daughtersDplusMain.contains(static_cast(std::abs(flagCharmBach))) && std::abs(flagV0) == hf_decay::hf_cand_reso::PartialMatchMc::LambdaMatched) { + // Peaking background of D+Lambda <- Ds* with spurious soft pion + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], vecDaughtersReso[3], vecDaughtersReso[4]}; + auto pdgCodesDplusDaughters = hf_decay::hf_cand_3prong::daughtersDplusMain.at(static_cast(std::abs(flagCharmBach))); + auto pdgCodesDaughters = std::array{pdgCodesDplusDaughters[0], pdgCodesDplusDaughters[1], pdgCodesDplusDaughters[2], +kProton, -kPiPlus}; + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDplusLambda) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + break; + } + } + } + if (indexRec > -1) { + auto particleReso = particlesMc.iteratorAt(indexRec); + ptGen = particleReso.pt(); + invMassGen = computeInvMassGen(particlesMc, indexRec); + } + rowHf3PrV0McRecReduced(indexHfCandCharm, indexCandV0Bach, + flagReso, flagCharmBach, + flagCharmBachInterm, debugMcRec, + origin, ptGen, invMassGen, + nKinkedTracks); + } else if constexpr (DType == DType::D0) { + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong0Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong1Id())); + // Check if D0 is matched + flagCharmBach = candCharmBach.flagMcMatchRec(); + flagCharmBachInterm = candCharmBach.flagMcDecayChanRec(); + if (flagCharmBach != 0) { + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::D0Matched); + origin = candCharmBach.originMcRec(); + } + // Check if V0 is matched + vecDaughtersReso.push_back(tracks.rawIteratorAt(bachelorV0.posTrackId())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(bachelorV0.negTrackId())); + flagV0 = getMatchingFlagV0(particlesMc, std::array{vecDaughtersReso[2], vecDaughtersReso[3]}); + if (flagV0 != 0) { + SETBIT(debugMcRec, std::abs(flagV0)); + } + // No physical channel expected in D0 K0s + // If both D0 and Lambda are matched, try to match resonance + if (hf_decay::hf_cand_2prong::daughtersD0Main.contains(static_cast(std::abs(flagCharmBach))) && std::abs(flagV0) == hf_decay::hf_cand_reso::PartialMatchMc::LambdaMatched) { + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], vecDaughtersReso[3]}; + auto pdgCodesDzeroDaughters = hf_decay::hf_cand_2prong::daughtersD0Main.at(static_cast(std::abs(flagCharmBach))); + auto pdgCodesDaughters = std::array{pdgCodesDzeroDaughters[0], pdgCodesDzeroDaughters[1], +kProton, -kPiPlus}; + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToD0Lambda) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + break; + } + } + } + if (indexRec > -1) { + auto particleReso = particlesMc.iteratorAt(indexRec); + ptGen = particleReso.pt(); + invMassGen = computeInvMassGen(particlesMc, indexRec); + } + rowHf2PrV0McRecReduced(indexHfCandCharm, indexCandV0Bach, + flagReso, flagCharmBach, + flagCharmBachInterm, debugMcRec, + origin, ptGen, invMassGen, + nKinkedTracks); } + registry.fill(HIST("hMCRecDebug"), debugMcRec); + if (indexRec > -1) { + registry.fill(HIST("hMCRecCounter"), flagReso); + registry.fill(HIST("hMCRecOrigin"), origin); + registry.fill(HIST("hMCRecMassGen"), invMassGen); + } + if (flagCharmBach != 0) { + registry.fill(HIST("hMCRecCharmDau"), flagCharmBach); + } + } - return true; + template + int8_t getMatchingFlagTrack(Tr const& bachTrack) + { + auto particle = bachTrack.mcParticle(); + auto pdgCode = std::abs(particle.pdgCode()); + if (pdgCode == kPiPlus) { + return hf_decay::hf_cand_reso::PartialMatchMc::PionMatched; + } + if (pdgCode == kKPlus) { + return hf_decay::hf_cand_reso::PartialMatchMc::KaonMatched; + } + if (pdgCode == kProton) { + return hf_decay::hf_cand_reso::PartialMatchMc::ProtonMatched; + } + return 0; } + // Function for filling MC reco information of D Track candidates in the tables + /// \tparam dType is the D meson type (Dstar, Dplus or D0) + /// \param particlesMc is the table with MC particles + /// \param candCharmBach is the D meson candidate + /// \param bachelorTrack is the bachelor track + /// \param tracks is the table with tracks + /// \param indexHfCandCharm is the index of the charm-hadron bachelor in the reduced table + /// \param indexCandTrBach is the index of the v0 bachelor in the reduced table + template + void fillMcRecoInfoDTrack(PParticles const& particlesMc, + CCand const& candCharmBach, + BBachTr const& bachelorTrack, + Tr const& tracks, + const int64_t indexHfCandCharm, + const int64_t indexCandTrBach) + { + std::vector vecDaughtersReso{}; + int8_t sign{0}, nKinkedTracks{0}, origin{0}, flagCharmBach{0}, flagCharmBachInterm{0}, flagTrack{0}, flagReso{0}; + int indexRec{-1}; + uint16_t debugMcRec{0}; + float ptGen{-1.f}, invMassGen{-1.f}; + if constexpr (DType == DType::Dstar) { + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong0Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong1Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prongPiId())); + // Check if D* is matched + flagCharmBach = candCharmBach.flagMcMatchRec(); + if (flagCharmBach != 0) { + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::DstarMatched); + origin = candCharmBach.originMcRec(); + } + // Check if D0 is matched + flagCharmBachInterm = candCharmBach.flagMcMatchRecD0(); + if (flagCharmBachInterm != 0) { + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::D0Matched); + } + // Check if Track is matched + flagTrack = getMatchingFlagTrack(bachelorTrack); + if (flagTrack != 0) { + SETBIT(debugMcRec, flagTrack); + } + // If both D* and Track are matched, try to match resonance + if (flagCharmBach != 0 && flagTrack == hf_decay::hf_cand_reso::PartialMatchMc::PionMatched) { + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], bachelorTrack}; + auto pdgCodesDaughters = std::array{+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}; + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDstarPi) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + break; + } + } + } + // No channels in D*K+ or D*Pr + if (indexRec > -1) { + auto particleReso = particlesMc.iteratorAt(indexRec); + ptGen = particleReso.pt(); + invMassGen = computeInvMassGen(particlesMc, indexRec); + } + rowHfDstarTrkMcRecReduced(indexHfCandCharm, indexCandTrBach, + flagReso, flagCharmBach, + flagCharmBachInterm, debugMcRec, + origin, ptGen, invMassGen, + nKinkedTracks); + } else if constexpr (DType == DType::Dplus) { + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong0Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong1Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong2Id())); + // Check if D+ is matched + flagCharmBach = candCharmBach.flagMcMatchRec(); + flagCharmBachInterm = candCharmBach.flagMcDecayChanRec(); + if (flagCharmBach != 0) { + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::DplusMatched); + origin = candCharmBach.originMcRec(); + } + // Check if Track is matched + flagTrack = getMatchingFlagTrack(bachelorTrack); + if (flagTrack != 0) { + SETBIT(debugMcRec, flagTrack); + } + // If both D+ and Track are matched, try to match resonance + if (hf_decay::hf_cand_3prong::daughtersDplusMain.contains(static_cast(std::abs(flagCharmBach))) && flagTrack == hf_decay::hf_cand_reso::PartialMatchMc::PionMatched) { + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], vecDaughtersReso[2], bachelorTrack}; + auto pdgCodesDplusDaughters = hf_decay::hf_cand_3prong::daughtersDplusMain.at(static_cast(std::abs(flagCharmBach))); + auto pdgCodesDaughters = std::array{pdgCodesDplusDaughters[0], pdgCodesDplusDaughters[1], pdgCodesDplusDaughters[2], -kPiPlus}; + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDplusPi) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + break; + } + } + // Partial matching of Dj -> D*Pi -> (D+ pi0) (pi) with missing neutral + if (indexRec < 0) { + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDstarPi) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::ResoPartlyMatched); + break; + } + } + } + } + // No channels in D+K+ or D+Pr + if (indexRec > -1) { + auto particleReso = particlesMc.iteratorAt(indexRec); + ptGen = particleReso.pt(); + invMassGen = computeInvMassGen(particlesMc, indexRec); + } + rowHf3PrTrkMcRecReduced(indexHfCandCharm, indexCandTrBach, + flagReso, flagCharmBach, + flagCharmBachInterm, debugMcRec, + origin, ptGen, invMassGen, + nKinkedTracks); + } else if constexpr (DType == DType::D0) { + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong0Id())); + vecDaughtersReso.push_back(tracks.rawIteratorAt(candCharmBach.prong1Id())); + // Check if D0 is matched + flagCharmBach = candCharmBach.flagMcMatchRec(); + flagCharmBachInterm = candCharmBach.flagMcDecayChanRec(); + if (flagCharmBach != 0) { + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::D0Matched); + origin = candCharmBach.originMcRec(); + } + flagTrack = getMatchingFlagTrack(bachelorTrack); + if (flagTrack != 0) { + SETBIT(debugMcRec, flagTrack); + } + if (hf_decay::hf_cand_2prong::daughtersD0Main.contains(static_cast(std::abs(flagCharmBach))) && flagTrack == hf_decay::hf_cand_reso::PartialMatchMc::PionMatched) { + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], bachelorTrack}; + auto pdgCodesDzeroDaughters = hf_decay::hf_cand_2prong::daughtersD0Main.at(static_cast(std::abs(flagCharmBach))); + auto pdgCodesDaughters = std::array{pdgCodesDzeroDaughters[0], pdgCodesDzeroDaughters[1], +kPiPlus}; + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToD0Pi) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + break; + } + } + // Partial matching of Dj -> D*Pi -> (D0 pi) (pi) with missing pion + if (indexRec < 0) { + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDstarPi) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + SETBIT(debugMcRec, hf_decay::hf_cand_reso::PartialMatchMc::ResoPartlyMatched); + break; + } + } + } + } else if (hf_decay::hf_cand_2prong::daughtersD0Main.contains(static_cast(std::abs(flagCharmBach))) && flagTrack == hf_decay::hf_cand_reso::PartialMatchMc::KaonMatched) { + auto arrDaughtersReso = std::array{vecDaughtersReso[0], vecDaughtersReso[1], bachelorTrack}; + auto pdgCodesDzeroDaughters = hf_decay::hf_cand_2prong::daughtersD0Main.at(static_cast(std::abs(flagCharmBach))); + auto pdgCodesDaughters = std::array{pdgCodesDzeroDaughters[0], pdgCodesDzeroDaughters[1], +kKPlus}; + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToD0Kplus) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, arrDaughtersReso, pdgCodeReso, pdgCodesDaughters, true, &sign, 3, &nKinkedTracks); + if (indexRec > -1) { + flagReso = sign * decayChannelFlag; + break; + } + } + } + if (indexRec > -1) { + auto particleReso = particlesMc.iteratorAt(indexRec); + ptGen = particleReso.pt(); + invMassGen = computeInvMassGen(particlesMc, indexRec); + } + rowHf2PrTrkMcRecReduced(indexHfCandCharm, indexCandTrBach, + flagReso, flagCharmBach, + flagCharmBachInterm, debugMcRec, + origin, ptGen, invMassGen, + nKinkedTracks); + } + registry.fill(HIST("hMCRecDebug"), debugMcRec); + if (indexRec > -1) { + registry.fill(HIST("hMCRecCounter"), flagReso); + registry.fill(HIST("hMCRecOrigin"), origin); + registry.fill(HIST("hMCRecMassGen"), invMassGen); + } + if (flagCharmBach != 0) { + registry.fill(HIST("hMCRecCharmDau"), flagCharmBach); + } + } // fillMcRecoInfoDTrack - template + template void runDataCreation(Coll const& collision, CCands const& candsD, - BBach const& bachelors, - TracksWithPID const&, - aod::BCsWithTimestamps const&) + BBachV0s const& bachelorV0s, + BBachTracks const& bachelorTrks, + Tr const& tracks, + TrIU const& tracksIU, + PParticles const& particlesMc, + BCs const&) { // helpers for ReducedTables filling - int indexHfReducedCollision = hfReducedCollision.lastIndex() + 1; + float centrality = -1.f; + const auto hfRejMap = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + if (rejectCollisionsWithBadEvSel && hfRejMap != 0) { + return; + } + int const indexHfReducedCollision = hfReducedCollision.lastIndex() + 1; // 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.template bc_as(); - initCCDB(bc, runNumber, ccdb, ccdbPathGrpMag, lut, false); + constexpr bool DoTracks = PairingType == PairingType::TrackOnly || PairingType == PairingType::V0AndTrack; + constexpr bool DoV0s = PairingType == PairingType::V0Only || PairingType == PairingType::V0AndTrack; + 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 + // initialize variables depending on D meson type bool fillHfCandD = false; - float invMassD{0.f}, invMassDdau{0.f}; - 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 || DecayChannel == DecayChannel::DstarTrack) { - if (candD.signSoftPi() > 0) { - invMassD = candD.invMassDstar(); - invMassDdau = candD.invMassD0(); + std::array secondaryVertexD{}; + std::array prongIdsD{}; + std::array bdtScores = {-1.f, -1.f, -1.f, -1.f, -1.f, -1.f}; + std::vector> charmHadDauTracks{}; + varUtils.ptD = candD.pt(); + if constexpr (DType == DType::Dstar) { + varUtils.signD = candD.signSoftPi(); + if (varUtils.signD > 0) { + varUtils.invMassD = candD.invMassDstar(); + varUtils.invMassD0 = candD.invMassD0(); } else { - invMassD = candD.invMassAntiDstar(); - invMassDdau = candD.invMassD0Bar(); + varUtils.invMassD = candD.invMassAntiDstar(); + varUtils.invMassD0 = candD.invMassD0Bar(); } - pVecD = candD.pVector(); secondaryVertexD[0] = candD.xSecondaryVertexD0(); secondaryVertexD[1] = candD.ySecondaryVertexD0(); secondaryVertexD[2] = candD.zSecondaryVertexD0(); prongIdsD[0] = candD.prong0Id(); prongIdsD[1] = candD.prong1Id(); prongIdsD[2] = candD.prongPiId(); - pVecProng2 = candD.pVecSoftPi(); - - dtype = candD.signSoftPi() * DType::Dstar; - if constexpr (withMl) { + varUtils.pVectorProng0 = candD.pVectorProng0(); + varUtils.pVectorProng1 = candD.pVectorProng1(); + varUtils.pVectorProng2 = candD.pVecSoftPi(); + charmHadDauTracks.push_back(tracksIU.rawIteratorAt(candD.prong0Id())); + charmHadDauTracks.push_back(tracksIU.rawIteratorAt(candD.prong1Id())); + if constexpr (WithMl) { std::copy(candD.mlProbDstarToD0Pi().begin(), candD.mlProbDstarToD0Pi().end(), bdtScores.begin()); } - registry.fill(HIST("hMassVsPtDstarAll"), candD.pt(), invMassD - invMassDdau); - } else if constexpr (DecayChannel == DecayChannel::DplusV0) { - auto prong0 = candD.template prong0_as(); - invMassD = hfHelper.invMassDplusToPiKPi(candD); - pVecD = candD.pVector(); + registry.fill(HIST("hMassVsPtDstarAll"), varUtils.ptD, varUtils.invMassD - varUtils.invMassD0); + } else if constexpr (DType == DType::Dplus) { + auto prong0 = tracksIU.rawIteratorAt(candD.prong0Id()); + varUtils.invMassD = HfHelper::invMassDplusToPiKPi(candD); secondaryVertexD[0] = candD.xSecondaryVertex(); secondaryVertexD[1] = candD.ySecondaryVertex(); secondaryVertexD[2] = candD.zSecondaryVertex(); prongIdsD[0] = candD.prong0Id(); prongIdsD[1] = candD.prong1Id(); prongIdsD[2] = candD.prong2Id(); - pVecProng2 = candD.pVectorProng2(); - dtype = static_cast(prong0.sign() * DType::Dplus); - if constexpr (withMl) { + varUtils.signD = prong0.sign(); + varUtils.pVectorProng0 = candD.pVectorProng0(); + varUtils.pVectorProng1 = candD.pVectorProng1(); + varUtils.pVectorProng2 = candD.pVectorProng2(); + charmHadDauTracks.push_back(tracksIU.rawIteratorAt(candD.prong0Id())); + charmHadDauTracks.push_back(tracksIU.rawIteratorAt(candD.prong1Id())); + charmHadDauTracks.push_back(tracksIU.rawIteratorAt(candD.prong2Id())); + if constexpr (WithMl) { std::copy(candD.mlProbDplusToPiKPi().begin(), candD.mlProbDplusToPiKPi().end(), bdtScores.begin()); } - registry.fill(HIST("hMassVsPtDplusAll"), candD.pt(), invMassD); - } // else if - - if constexpr (DecayChannel == DecayChannel::DplusV0 || DecayChannel == DecayChannel::DstarV0) { - // Loop on V0 candidates - for (const auto& v0 : bachelors) { - auto posTrack = v0.template posTrack_as(); - auto negTrack = v0.template negTrack_as(); + registry.fill(HIST("hMassVsPtDplusAll"), varUtils.ptD, varUtils.invMassD); + } else if constexpr (DType == DType::D0) { + varUtils.invMassD0 = HfHelper::invMassD0ToPiK(candD); + varUtils.invMassD0Bar = HfHelper::invMassD0barToKPi(candD); + secondaryVertexD[0] = candD.xSecondaryVertex(); + secondaryVertexD[1] = candD.ySecondaryVertex(); + secondaryVertexD[2] = candD.zSecondaryVertex(); + prongIdsD[0] = candD.prong0Id(); + prongIdsD[1] = candD.prong1Id(); + prongIdsD[2] = -1; // D0 does not have a third prong + charmHadDauTracks.push_back(tracksIU.rawIteratorAt(candD.prong0Id())); + charmHadDauTracks.push_back(tracksIU.rawIteratorAt(candD.prong1Id())); + varUtils.pVectorProng0 = candD.pVectorProng0(); + varUtils.pVectorProng1 = candD.pVectorProng1(); + varUtils.pVectorProng2 = {0.f, 0.f, 0.f}; // D0 does not have a third prong + if constexpr (WithMl) { + std::copy(candD.mlProbD0().begin(), candD.mlProbD0().end(), bdtScores.begin()); + std::copy(candD.mlProbD0bar().begin(), candD.mlProbD0bar().end(), bdtScores.begin() + 3); + } + if (candD.isSelD0() >= cfgDmesCuts.selectionFlagD0) { + registry.fill(HIST("hMassVsPtD0All"), varUtils.ptD, varUtils.invMassD0); + } + if (candD.isSelD0bar() >= cfgDmesCuts.selectionFlagD0Bar) { + registry.fill(HIST("hMassVsPtD0BarAll"), varUtils.ptD, varUtils.invMassD0Bar); + } + } // end of dType switch + + // Get single track variables + float chi2TpcDauMax = -1.f; + int nItsClsDauMin = 8, nTpcCrossRowsDauMin = 200; + float chi2TpcSoftPi = -1.f; + int nItsClsSoftPi = 8, nTpcCrossRowsSoftPi = 200; + for (const auto& charmHadTrack : charmHadDauTracks) { + if (charmHadTrack.itsNCls() < nItsClsDauMin) { + nItsClsDauMin = charmHadTrack.itsNCls(); + } + if (charmHadTrack.tpcNClsCrossedRows() < nTpcCrossRowsDauMin) { + nTpcCrossRowsDauMin = charmHadTrack.tpcNClsCrossedRows(); + } + if (charmHadTrack.tpcChi2NCl() > chi2TpcDauMax) { + chi2TpcDauMax = charmHadTrack.tpcChi2NCl(); + } + } + if constexpr (DType == DType::Dstar) { + auto softPi = tracksIU.rawIteratorAt(candD.prongPiId()); + nItsClsSoftPi = softPi.itsNCls(); + nTpcCrossRowsSoftPi = softPi.tpcNClsCrossedRows(); + chi2TpcSoftPi = softPi.tpcChi2NCl(); + charmHadDauTracks.push_back(softPi); + } + // Loop on the bachelor V0s + if constexpr (DoV0s) { + for (const auto& v0 : bachelorV0s) { + auto trackPos = tracksIU.rawIteratorAt(v0.posTrackId()); + auto trackNeg = tracksIU.rawIteratorAt(v0.negTrackId()); // Apply selsection - v0type = getSelectionMapV0(v0, collision, std::array{posTrack, negTrack}, prongIdsD); - if (v0type == 0) { + auto v0DauTracks = std::array{trackPos, trackNeg}; + if (!buildAndSelectV0(collision, prongIdsD, v0DauTracks)) { continue; } + // 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(); + } + } // 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); + std::array const pVecV0Orig = {candidateV0.mom[0], candidateV0.mom[1], candidateV0.mom[2]}; + std::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, pVecV0); - } - float ptV0 = RecoDecay::pt(pVecV0); // fill histos - float invMassKPiPiV0{0.f}; - if (TESTBIT(v0type, K0s)) { - if constexpr (DecayChannel == DecayChannel::DplusV0) { - invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVectorProng2(), pVecV0}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); - } else if (DecayChannel == DecayChannel::DstarV0) { - if (candD.signSoftPi() > 0) { - invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVecSoftPi(), pVecV0}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); - } else { - invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng1(), candD.pVectorProng0(), candD.pVecSoftPi(), pVecV0}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); - } - } - - registry.fill(HIST("hMassVsPtK0s"), ptV0, v0.mK0Short()); - if constexpr (DecayChannel == DecayChannel::DstarV0) { - registry.fill(HIST("hMassDs1"), invMassKPiPiV0 - invMassD); - } else if constexpr (DecayChannel == DecayChannel::DplusV0) { - registry.fill(HIST("hMassDsStar2"), invMassKPiPiV0 - invMassD); - } + getPxPyPz(trackParK0, candidateV0.mom); } - bool isLambda = TESTBIT(v0type, Lambda); - bool isAntiLambda = TESTBIT(v0type, AntiLambda); + // compute resonance invariant mass and filling of QA histograms + if (TESTBIT(candidateV0.v0Type, BachelorType::K0s)) { + registry.fill(HIST("hMassVsPtK0s"), candidateV0.pT, candidateV0.mK0Short); + switch (DType) { + case DType::Dstar: + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, candidateV0.mom)); + if (varUtils.signD > 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + } else { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, varUtils.pVectorProng2, candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + } + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD - varUtils.invMassD0 > cfgQaPlots.cutMassDstarMin && + varUtils.invMassD - varUtils.invMassD0 < cfgQaPlots.cutMassDstarMax && + candidateV0.mK0Short > cfgQaPlots.cutMassK0sMin && + candidateV0.mK0Short < cfgQaPlots.cutMassK0sMax)) { + registry.fill(HIST("hMassDstarK0s"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + break; + case DType::Dplus: + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassK0}); + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, candidateV0.mom)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD > cfgQaPlots.cutMassDMin && + varUtils.invMassD < cfgQaPlots.cutMassDMax && + candidateV0.mK0Short > cfgQaPlots.cutMassK0sMin && + candidateV0.mK0Short < cfgQaPlots.cutMassK0sMax)) { + registry.fill(HIST("hMassDplusK0s"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + break; + default: + break; // no other D meson types expected + } // end of dType switch + } // matched with K0s + bool const isLambda = TESTBIT(candidateV0.v0Type, BachelorType::Lambda); + bool const isAntiLambda = TESTBIT(candidateV0.v0Type, BachelorType::AntiLambda); if (isLambda || isAntiLambda) { - if constexpr (DecayChannel == DecayChannel::DplusV0) { - invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVectorProng2(), pVecV0}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda0}); - } else if (DecayChannel == DecayChannel::DstarV0) { - if (candD.signSoftPi() > 0) { - invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng0(), candD.pVectorProng1(), candD.pVecSoftPi(), pVecV0}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda0}); - } else { - invMassKPiPiV0 = RecoDecay::m(std::array{candD.pVectorProng1(), candD.pVectorProng0(), candD.pVecSoftPi(), pVecV0}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda0}); - } - } - if (isLambda) { - registry.fill(HIST("hMassVsPtLambda"), ptV0, v0.mLambda()); - } - if (isAntiLambda) { - registry.fill(HIST("hMassVsPtLambda"), ptV0, v0.mAntiLambda()); - } - if constexpr (DecayChannel == DecayChannel::DplusV0) { - registry.fill(HIST("hMassXcRes"), invMassKPiPiV0 - invMassD); - } - } + registry.fill(HIST("hMassVsPtLambda"), candidateV0.pT, candidateV0.mLambda); + switch (DType) { + case DType::Dstar: + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, candidateV0.mom)); + if (varUtils.signD > 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda}); + } else { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, varUtils.pVectorProng2, candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda}); + } + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD - varUtils.invMassD0 > cfgQaPlots.cutMassDstarMin && + varUtils.invMassD - varUtils.invMassD0 < cfgQaPlots.cutMassDstarMax && + candidateV0.mLambda > cfgQaPlots.cutMassLambdaMin && + candidateV0.mLambda < cfgQaPlots.cutMassLambdaMax)) { + registry.fill(HIST("hMassDstarLambda"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + break; + case DType::Dplus: + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassLambda}); + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, candidateV0.mom)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD > cfgQaPlots.cutMassDMin && + varUtils.invMassD < cfgQaPlots.cutMassDMax && + candidateV0.mLambda > cfgQaPlots.cutMassLambdaMin && + candidateV0.mLambda < cfgQaPlots.cutMassLambdaMax)) { + registry.fill(HIST("hMassDplusLambda"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + break; + case DType::D0: + if (isLambda) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassLambda}); + } else { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, candidateV0.mom}, std::array{MassPiPlus, MassKPlus, MassLambda}); + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, candidateV0.mom)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (((varUtils.invMassD0 > cfgQaPlots.cutMassDMin && varUtils.invMassD0 < cfgQaPlots.cutMassDMax) || + (varUtils.invMassD0Bar > cfgQaPlots.cutMassDMin && varUtils.invMassD0Bar < cfgQaPlots.cutMassDMax)) && + candidateV0.mLambda > cfgQaPlots.cutMassLambdaMin && + candidateV0.mLambda < cfgQaPlots.cutMassLambdaMax)) { + if (isLambda) { + registry.fill(HIST("hMassD0Lambda"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0); + } else { + registry.fill(HIST("hMassD0Lambda"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0Bar); + } + } + break; + default: + break; + } // end of dType switch + } // matched with Lambda or AntiLambda // fill V0 table // if information on V0 already stored, go to next V0 if (!selectedV0s.count(v0.globalIndex())) { - hfCandV0(v0.posTrackId(), v0.negTrackId(), + hfCandV0(trackPos.globalIndex(), trackNeg.globalIndex(), indexHfReducedCollision, - v0.x(), v0.y(), v0.z(), - v0.pxpos(), v0.pypos(), v0.pzpos(), - v0.pxneg(), v0.pyneg(), v0.pzneg(), - v0.v0cosPA(), - v0.dcav0topv(), - v0type); + 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; - } // V0 loop - } else if constexpr (DecayChannel == DecayChannel::DstarTrack) { - for (const auto& trackIndex : bachelors) { - auto track = trackIndex.template track_as(); + // Optional filling of MC Rec table, for now only implemented for Ds1->D*K0s and Ds2*->D+K0s + if constexpr (DoMc) { + int indexHfCandCharm{-1}; + if constexpr (DType == DType::Dstar) { + indexHfCandCharm = hfCandDstar.lastIndex() + 1; + } else if constexpr (DType == DType::Dplus) { + indexHfCandCharm = hfCandD3Pr.lastIndex() + 1; + } else if constexpr (DType == DType::D0) { + indexHfCandCharm = hfCandD2Pr.lastIndex() + 1; + } + fillMcRecoInfoDV0(particlesMc, candD, v0, tracksIU, indexHfCandCharm, selectedV0s[v0.globalIndex()]); + } + } // end of loop on V0 candidates + } // end of do V0s + // Loop on the bachelor tracks + if constexpr (DoTracks) { + for (const auto& trackIndex : bachelorTrks) { + auto track = tracks.rawIteratorAt(trackIndex.trackId()); 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 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 - invMassD); + // compute invariant mass and filling of QA histograms + switch (DType) { + case DType::Dstar: + // D* pi + if (std::abs(track.tpcNSigmaPi()) < cfgSingleTrackCuts.maxNsigmaTpcPi) { + if (varUtils.signD > 0 && track.sign() < 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassPiPlus}); + } else if (varUtils.signD < 0 && track.sign() > 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassPiPlus}); + } else { + varUtils.invMassReso = -1.f; // invalid case + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD - varUtils.invMassD0 > cfgQaPlots.cutMassDstarMin && + varUtils.invMassD - varUtils.invMassD0 < cfgQaPlots.cutMassDstarMax)) { + registry.fill(HIST("hMassDstarPi"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + } + if (std::abs(track.tpcNSigmaKa()) < cfgSingleTrackCuts.maxNsigmaTpcKa) { + if (varUtils.signD > 0 && track.sign() < 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassKPlus}); + } else if (varUtils.signD < 0 && track.sign() > 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassKPlus}); + } else { + varUtils.invMassReso = -1.f; // invalid case + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD - varUtils.invMassD0 > cfgQaPlots.cutMassDstarMin && + varUtils.invMassD - varUtils.invMassD0 < cfgQaPlots.cutMassDstarMax)) { + registry.fill(HIST("hMassDstarK"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + } + // D* p + if (std::abs(track.tpcNSigmaPr()) < cfgSingleTrackCuts.maxNsigmaTpcPr) { + if (varUtils.signD > 0 && track.sign() > 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}); + } else if (varUtils.signD < 0 && track.sign() < 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}); + } else { + varUtils.invMassReso = -1.f; // invalid case + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD - varUtils.invMassD0 > cfgQaPlots.cutMassDstarMin && + varUtils.invMassD - varUtils.invMassD0 < cfgQaPlots.cutMassDstarMax)) { + registry.fill(HIST("hMassDstarProton"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + } + break; + case DType::Dplus: + // D+ pi + if (std::abs(track.tpcNSigmaPi()) < cfgSingleTrackCuts.maxNsigmaTpcPi) { + if (varUtils.signD * track.sign() < 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassPiPlus}); + } else { + varUtils.invMassReso = -1.f; // invalid case + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD > cfgQaPlots.cutMassDMin && + varUtils.invMassD < cfgQaPlots.cutMassDMax)) { + registry.fill(HIST("hMassDplusPi"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + } + // D+ K + if (std::abs(track.tpcNSigmaKa()) < cfgSingleTrackCuts.maxNsigmaTpcKa) { + if (varUtils.signD * track.sign() < 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassKPlus}); + } else { + varUtils.invMassReso = -1.f; // invalid case + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD > cfgQaPlots.cutMassDMin && + varUtils.invMassD < cfgQaPlots.cutMassDMax)) { + registry.fill(HIST("hMassDplusK"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + } + // D+ pr + if (std::abs(track.tpcNSigmaPr()) < cfgSingleTrackCuts.maxNsigmaTpcPr) { + if (varUtils.signD * track.sign() < 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus, MassProton}); + } else { + varUtils.invMassReso = -1.f; // invalid case + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, varUtils.pVectorProng2, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + (varUtils.invMassD > cfgQaPlots.cutMassDMin && + varUtils.invMassD < cfgQaPlots.cutMassDMax)) { + registry.fill(HIST("hMassDplusProton"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD); + } + } + break; + case DType::D0: + // D0 pi + if (std::abs(track.tpcNSigmaPi()) < cfgSingleTrackCuts.maxNsigmaTpcPi) { + if (track.sign() > 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus}); + } else { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassPiPlus}); + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + ((varUtils.invMassD0 > cfgQaPlots.cutMassDMin && + varUtils.invMassD0 < cfgQaPlots.cutMassDMax) || + (varUtils.invMassD0Bar > cfgQaPlots.cutMassDMin && + varUtils.invMassD0Bar < cfgQaPlots.cutMassDMax))) { + if (track.sign() > 0) { + registry.fill(HIST("hMassD0Pi"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0); + } else { + registry.fill(HIST("hMassD0Pi"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0Bar); + } + } + } + // D0 K + if (std::abs(track.tpcNSigmaKa()) < cfgSingleTrackCuts.maxNsigmaTpcKa) { + if (track.sign() > 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassKPlus}); + } else { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassKPlus}); + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + ((varUtils.invMassD0 > cfgQaPlots.cutMassDMin && + varUtils.invMassD0 < cfgQaPlots.cutMassDMax) || + (varUtils.invMassD0Bar > cfgQaPlots.cutMassDMin && + varUtils.invMassD0Bar < cfgQaPlots.cutMassDMax))) { + if (track.sign() > 0) { + registry.fill(HIST("hMassD0K"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0); + } else { + registry.fill(HIST("hMassD0K"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0Bar); + } + } + } + // D0 p + if (std::abs(track.tpcNSigmaPr()) < cfgSingleTrackCuts.maxNsigmaTpcPr) { + if (track.sign() > 0) { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng0, varUtils.pVectorProng1, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassProton}); + } else { + varUtils.invMassReso = RecoDecay::m(std::array{varUtils.pVectorProng1, varUtils.pVectorProng0, pVecTrack}, std::array{MassPiPlus, MassKPlus, MassProton}); + } + varUtils.ptReso = RecoDecay::pt(RecoDecay::sumOfVec(varUtils.pVectorProng0, varUtils.pVectorProng1, pVecTrack)); + if (!cfgQaPlots.applyCutsForQaHistograms || + ((varUtils.invMassD0 > cfgQaPlots.cutMassDMin && + varUtils.invMassD0 < cfgQaPlots.cutMassDMax) || + (varUtils.invMassD0Bar > cfgQaPlots.cutMassDMin && + varUtils.invMassD0Bar < cfgQaPlots.cutMassDMax))) { + if (track.sign() > 0) { + registry.fill(HIST("hMassD0Proton"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0); + } else { + registry.fill(HIST("hMassD0Proton"), varUtils.ptReso, varUtils.invMassReso - varUtils.invMassD0Bar); + } + } + } + break; + default: + break; // no other D meson types expected + } // end of DType switch + // fill track table if (!selectedTracks.count(track.globalIndex())) { - hfTrackNoParam(indexHfReducedCollision, + hfTrackNoParam(track.globalIndex(), + indexHfReducedCollision, track.px(), track.py(), track.pz(), track.sign(), track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr(), - track.hasTOF()); + track.hasTOF(), track.hasTPC(), track.itsNCls(), track.tpcNClsCrossedRows(), track.tpcChi2NCl()); selectedTracks[track.globalIndex()] = hfTrackNoParam.lastIndex(); } fillHfCandD = true; - } // track loop - } - + if constexpr (DoMc) { + int indexHfCandCharm{-1}; + if constexpr (DType == DType::Dstar) { + indexHfCandCharm = hfCandDstar.lastIndex() + 1; + } else if constexpr (DType == DType::Dplus) { + indexHfCandCharm = hfCandD3Pr.lastIndex() + 1; + } else if constexpr (DType == DType::D0) { + indexHfCandCharm = hfCandD2Pr.lastIndex() + 1; + } + fillMcRecoInfoDTrack(particlesMc, candD, track, tracks, indexHfCandCharm, selectedTracks[track.globalIndex()]); + } + } // end of loop on bachelor tracks + } // end of do tracks + // fill D candidate table 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], - candD.pxProng0(), candD.pyProng0(), candD.pzProng0(), - candD.pxProng1(), candD.pyProng1(), candD.pzProng1(), - pVecProng2[0], pVecProng2[1], pVecProng2[2], - dtype); - if constexpr (withMl) { - hfCandDMl(bdtScores[0], bdtScores[1], bdtScores[2]); + if constexpr (DType == DType::Dplus) { + hfCandD3Pr(prongIdsD[0], prongIdsD[1], prongIdsD[2], + indexHfReducedCollision, + secondaryVertexD[0], secondaryVertexD[1], secondaryVertexD[2], + candD.pxProng0(), candD.pyProng0(), candD.pzProng0(), + candD.pxProng1(), candD.pyProng1(), candD.pzProng1(), + varUtils.pVectorProng2[0], varUtils.pVectorProng2[1], varUtils.pVectorProng2[2], + nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax, varUtils.signD); + if constexpr (WithMl) { + hfCandD3PrMl(bdtScores[0], bdtScores[1], bdtScores[2], bdtScores[3], bdtScores[4], bdtScores[5]); + } + } else if constexpr (DType == DType::D0) { + uint8_t selFlagD0 = {BIT(D0Sel::SelectedD0) | BIT(D0Sel::SelectedD0Bar)}; + if (candD.isSelD0() < cfgDmesCuts.selectionFlagD0) { + CLRBIT(selFlagD0, D0Sel::SelectedD0); + } + if (candD.isSelD0bar() < cfgDmesCuts.selectionFlagD0Bar) { + CLRBIT(selFlagD0, D0Sel::SelectedD0Bar); + } + hfCandD2Pr(prongIdsD[0], prongIdsD[1], + indexHfReducedCollision, + secondaryVertexD[0], secondaryVertexD[1], secondaryVertexD[2], + candD.pxProng0(), candD.pyProng0(), candD.pzProng0(), + candD.pxProng1(), candD.pyProng1(), candD.pzProng1(), + nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax, + selFlagD0); + if constexpr (WithMl) { + hfCandD2PrMl(bdtScores[0], bdtScores[1], bdtScores[2], bdtScores[3], bdtScores[4], bdtScores[5]); + } + } else if constexpr (DType == DType::Dstar) { + hfCandDstar(prongIdsD[0], prongIdsD[1], prongIdsD[2], + indexHfReducedCollision, + secondaryVertexD[0], secondaryVertexD[1], secondaryVertexD[2], + candD.pxProng0(), candD.pyProng0(), candD.pzProng0(), + candD.pxProng1(), candD.pyProng1(), candD.pzProng1(), + varUtils.pVectorProng2[0], varUtils.pVectorProng2[1], varUtils.pVectorProng2[2], + nItsClsDauMin, nTpcCrossRowsDauMin, chi2TpcDauMax, + nItsClsSoftPi, nTpcCrossRowsSoftPi, chi2TpcSoftPi, + varUtils.signD); + if constexpr (WithMl) { + hfCandD3PrMl(bdtScores[0], bdtScores[1], bdtScores[2], bdtScores[3], bdtScores[4], bdtScores[5]); + } } fillHfReducedCollision = true; - if constexpr (DecayChannel == DecayChannel::DstarV0 || DecayChannel == DecayChannel::DstarTrack) { - registry.fill(HIST("hMassVsPtDstarPaired"), candD.pt(), invMassD - invMassDdau); - } else if constexpr (DecayChannel == DecayChannel::DplusV0) { - registry.fill(HIST("hMassVsPtDplusPaired"), candD.pt(), invMassD); + if constexpr (DType == DType::Dstar) { + registry.fill(HIST("hMassVsPtDstarPaired"), candD.pt(), varUtils.invMassD - varUtils.invMassD0); + } else if constexpr (DType == DType::Dplus) { + registry.fill(HIST("hMassVsPtDplusPaired"), candD.pt(), varUtils.invMassD); + } else if constexpr (DType == DType::D0) { + if (candD.isSelD0() >= cfgDmesCuts.selectionFlagD0) { + registry.fill(HIST("hMassVsPtD0Paired"), varUtils.ptD, varUtils.invMassD0); + } + if (candD.isSelD0bar() >= cfgDmesCuts.selectionFlagD0Bar) { + registry.fill(HIST("hMassVsPtD0BarPaired"), varUtils.ptD, varUtils.invMassD0Bar); + } } - registry.fill(HIST("hDType"), dtype); } } // candsD loop registry.fill(HIST("hEvents"), 1 + Event::Processed); @@ -519,37 +1582,188 @@ struct HfDataCreatorCharmResoReduced { } registry.fill(HIST("hEvents"), 1 + Event::DV0Selected); // fill collision table if it contains a DPi pair a minima - hfReducedCollision(collision.posX(), collision.posY(), collision.posZ()); - } // run data creation + hfReducedCollision(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), hfRejMap, bz); + } // end of runDataCreation function - void processDplusV0(soa::Join const& collisions, - CandsDplusFiltered const& candsDplus, - aod::V0Datas const& V0s, - TracksWithPID const& tracks, - aod::BCsWithTimestamps const& bcs) + template + void runMcGen(McParticles const& mcParticles, + CCs const& collInfos, + McCollisions const& mcCollisions, + BCsInfo const&) { - 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); - } - // handle normalization by the right number of collisions - 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); + bool const doV0s = (PairingType == PairingType::V0Only || PairingType == PairingType::V0AndTrack); + bool const doTracks = (PairingType == PairingType::TrackOnly || PairingType == PairingType::V0AndTrack); + 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}; + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + int const nSplitColl = 0; + const auto collSlice = collInfos.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + hfEvSelMc.fillHistograms(mcCollision, rejectionMask, nSplitColl); + if (rejectCollisionsWithBadEvSel && rejectionMask != 0) { + // at least one event selection not satisfied --> reject all gen particles from this collision + continue; + } + for (const auto& particle : mcParticlesPerMcColl) { + int8_t sign{0}; + int8_t flag{0}; + int8_t signD{0}; + int8_t signBach{0}; + int8_t origin{0}; + bool matchedReso{false}, matchedD{false}, matchedV0Tr{false}; + std::vector idxBhadMothers{}; + if constexpr (DType == DType::Dstar) { + if (doV0s) { + // D* K0s + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDstarK0s) { + matchedReso = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, particle, pdgCodeReso, std::array{static_cast(Pdg::kDStar), +kK0}, true, &sign, 1); + if (matchedReso) { + flag = sign * decayChannelFlag; + auto candV0MC = mcParticles.rawIteratorAt(particle.daughtersIds().back()); + matchedV0Tr = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, candV0MC, kK0, std::array{+kPiPlus, -kPiPlus}, true, &signBach, 2); + break; + } + } + } + if (doTracks && !matchedReso) { + // D*+ pi- + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDstarPi) { + matchedReso = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, particle, pdgCodeReso, std::array{static_cast(Pdg::kDStar), -static_cast(kPiPlus)}, true, &sign, 1); + if (matchedReso) { + flag = sign * decayChannelFlag; + matchedV0Tr = true; + break; + } + } + } + if (matchedReso && matchedV0Tr) { + auto candDstarMC = mcParticles.rawIteratorAt(particle.daughtersIds().front()); + matchedD = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, candDstarMC, Pdg::kDStar, std::array{static_cast(Pdg::kD0), +static_cast(kPiPlus)}, true, &signD, 1); + if (matchedD) { + auto candD0MC = mcParticles.rawIteratorAt(candDstarMC.daughtersIds().front()); + matchedD = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, candD0MC, Pdg::kD0, std::array{-kKPlus, +kPiPlus}, true, &signD, 2); + } + } + } else if constexpr (DType == DType::Dplus) { + if (doV0s) { + // D+ K0s + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDplusK0s) { + matchedReso = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, particle, pdgCodeReso, std::array{static_cast(Pdg::kDPlus), +kK0}, true, &sign, 1); + if (matchedReso) { + flag = sign * decayChannelFlag; + auto candV0MC = mcParticles.rawIteratorAt(particle.daughtersIds().back()); + matchedV0Tr = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, candV0MC, kK0, std::array{+kPiPlus, -kPiPlus}, true, &signBach, 2); + break; + } + } + if (!matchedReso) { + // D+ lambda + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDplusLambda) { + matchedReso = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, particle, pdgCodeReso, std::array{static_cast(Pdg::kDPlus), +kLambda0}, true, &sign, 1); + if (matchedReso) { + flag = sign * decayChannelFlag; + auto candV0MC = mcParticles.rawIteratorAt(particle.daughtersIds().back()); + matchedV0Tr = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, candV0MC, kLambda0, std::array{+kProton, -kPiPlus}, true, &signBach, 1); + break; + } + } + } + } + if (doTracks && !matchedReso) { + // D+ pi- + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToDplusPi) { + matchedReso = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, particle, pdgCodeReso, std::array{static_cast(Pdg::kDPlus), -static_cast(kPiPlus)}, true, &sign, 1); + if (matchedReso) { + flag = sign * decayChannelFlag; + matchedV0Tr = true; + break; + } + } + } + if (matchedReso && matchedV0Tr) { + auto candDplusMC = mcParticles.rawIteratorAt(particle.daughtersIds().front()); + matchedD = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, candDplusMC, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &signD, 2); + } + } else if constexpr (DType == DType::D0) { + if (doV0s) { + // D0 Lambda + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToD0Lambda) { + matchedReso = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, particle, pdgCodeReso, std::array{static_cast(Pdg::kD0), +kLambda0}, true, &sign, 1); + if (matchedReso) { + flag = sign * decayChannelFlag; + auto candV0MC = mcParticles.rawIteratorAt(particle.daughtersIds().back()); + matchedV0Tr = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, candV0MC, kLambda0, std::array{+kProton, -kPiPlus}, true, &signBach, 1); + break; + } + } + } + if (doTracks && !matchedReso) { + // D0 pi+ + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToD0Pi) { + matchedReso = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, particle, pdgCodeReso, std::array{static_cast(Pdg::kD0), +static_cast(kPiPlus)}, true, &sign, 1); + if (matchedReso) { + flag = sign * decayChannelFlag; + matchedV0Tr = true; + break; + } + } + // D0 K+ + if (!matchedReso) { + for (const auto& [decayChannelFlag, pdgCodeReso] : hf_decay::hf_cand_reso::particlesToD0Kplus) { + matchedReso = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, particle, pdgCodeReso, std::array{static_cast(Pdg::kD0), +static_cast(kKPlus)}, true, &sign, 1); + if (matchedReso) { + flag = sign * decayChannelFlag; + matchedV0Tr = true; + break; + } + } + } + } + if (matchedReso && matchedV0Tr) { + auto candD0MC = mcParticles.rawIteratorAt(particle.daughtersIds().front()); + matchedD = RecoDecay::isMatchedMCGen(mcParticlesPerMcColl, candD0MC, Pdg::kD0, std::array{-kKPlus, +kPiPlus}, true, &signD, 2); + } + } + if (matchedReso && matchedD && matchedV0Tr) { + origin = RecoDecay::getCharmHadronOrigin(mcParticlesPerMcColl, particle, false, &idxBhadMothers); + registry.fill(HIST("hMCGenOrigin"), origin); + auto ptParticle = particle.pt(); + auto invMassGen = computeInvMassGen(mcParticles, particle.globalIndex()); + auto yParticle = RecoDecay::y(particle.pVector(), invMassGen); + auto etaParticle = particle.eta(); - void processDplusV0WithMl(soa::Join const& collisions, - CandsDplusFilteredWithMl const& candsDplus, - aod::V0Datas const& V0s, - TracksWithPID const& tracks, - aod::BCsWithTimestamps const& bcs) + std::array ptProngs{}; + std::array yProngs{}; + std::array etaProngs{}; + int counter = 0; + for (const auto& daught : particle.template 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], + invMassGen, rejectionMask); + } + } + } + } + + // Process functions + // No ML + // Data + // D* + void processDstarV0(soa::Join const& collisions, + CandsDstarFiltered const& candsDstar, + aod::V0s const& v0s, + TracksIUWithPID const& tracksIU, + aod::BCsWithTimestamps const& bcs) { int zvtxColl{0}; int sel8Coll{0}; @@ -559,20 +1773,20 @@ struct HfDataCreatorCharmResoReduced { 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, bcs); + auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, bcs); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0WithMl, "Process Dplus candidates paired with V0s with ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0, "Process Dstar candidates paired with V0s", true); - void processDstarV0(soa::Join const& collisions, - CandDstarFiltered const& candsDstar, - aod::V0Datas const& V0s, - TracksWithPID const& tracks, - aod::BCsWithTimestamps const& bcs) + void processDstarTrack(soa::Join const& collisions, + CandsDstarFiltered const& candsDstar, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + aod::BCsWithTimestamps const& bcs) { int zvtxColl{0}; int sel8Coll{0}; @@ -581,21 +1795,24 @@ struct HfDataCreatorCharmResoReduced { 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, bcs); } // handle normalization by the right number of collisions 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); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarTrack, "Process Dstar candidates paired with Tracks", false); - void processDstarV0WithMl(soa::Join const& collisions, - CandDstarFilteredWithMl const& candsDstar, - aod::V0Datas const& V0s, - TracksWithPID const& tracks, - aod::BCsWithTimestamps const& bcs) + void processDstarV0AndTrack(soa::Join const& collisions, + CandsDstarFiltered const& candsDstar, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + TracksIUWithPID const& tracksIU, + aod::BCsWithTimestamps const& bcs) { int zvtxColl{0}; int sel8Coll{0}; @@ -604,19 +1821,43 @@ struct HfDataCreatorCharmResoReduced { 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, tracks, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0AndTrack, "Process Dstar candidates paired with V0s and Tracks", false); + // Dplus + void processDplusV0(soa::Join const& collisions, + CandsDplusFiltered const& candsDplus, + aod::V0s const& v0s, + TracksIUWithPID const& tracksIU, + 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, bcs); + auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, bcs); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } - PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0WithMl, "Process DStar candidates paired with V0s with ML info", false); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0, "Process Dplus candidates paired with V0s", false); - void processDstarTrack(soa::Join const& collisions, - CandDstarFiltered const& candsDstar, + void processDplusTrack(soa::Join const& collisions, + CandsDplusFiltered const& candsDplus, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, aod::BCsWithTimestamps const& bcs) @@ -628,18 +1869,145 @@ struct HfDataCreatorCharmResoReduced { 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 candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusTrack, "Process Dplus candidates paired with Tracks", false); + + void processDplusV0AndTrack(soa::Join const& collisions, + CandsDplusFiltered const& candsDplus, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + TracksIUWithPID const& tracksIU, + 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, tracks, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0AndTrack, "Process Dplus candidates paired with V0s and Tracks", false); + + // D0 + void processD0V0(soa::Join const& collisions, + CandsD0Filtered const& candsD0, + aod::V0s const& v0s, + TracksIUWithPID const& tracksIU, + 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 = candsD0.sliceBy(candsD0PerCollision, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0V0, "Process D0 candidates paired with V0s", false); + + void processD0Track(soa::Join const& collisions, + CandsD0Filtered const& candsD0, + 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 = candsD0.sliceBy(candsD0PerCollision, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0Track, "Process D0 candidates paired with Tracks", false); + + void processD0V0AndTrack(soa::Join const& collisions, + CandsD0Filtered const& candsD0, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + TracksIUWithPID const& tracksIU, + 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 = candsD0.sliceBy(candsD0PerCollision, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, trackIdsThisColl, tracks, bcs); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, tracks, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0V0AndTrack, "Process D0 candidates paired with V0s and Tracks", false); + + // ML + // Data + // D* + void processDstarV0WithMl(soa::Join const& collisions, + CandsDstarFilteredWithMl const& candsDstar, + aod::V0s const& v0s, + TracksIUWithPID const& tracksIU, + 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, nullptr, tracksIU, tracksIU, nullptr, 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); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0WithMl, "Process Dstar candidates paired with V0s with ML info", false); void processDstarTrackWithMl(soa::Join const& collisions, - CandDstarFilteredWithMl const& candsDstar, + CandsDstarFilteredWithMl const& candsDstar, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, aod::BCsWithTimestamps const& bcs) @@ -655,13 +2023,698 @@ struct HfDataCreatorCharmResoReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation(collision, candsDThisColl, trackIdsThisColl, tracks, bcs); + runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, 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); + + void processDstarV0AndTrackWithMl(soa::Join const& collisions, + CandsDstarFilteredWithMl const& candsDstar, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + TracksIUWithPID const& tracksIU, + 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, tracks, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0AndTrackWithMl, "Process Dstar candidates paired with V0s and Tracks with ML info", false); + + // Dplus + void processDplusV0WithMl(soa::Join const& collisions, + CandsDplusFilteredWithMl const& candsDplus, + aod::V0s const& v0s, + TracksIUWithPID const& tracksIU, + 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, nullptr, tracksIU, tracksIU, nullptr, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0WithMl, "Process Dplus candidates paired with V0s with ML info", false); + + void processDplusTrackWithMl(soa::Join const& collisions, + CandsDplusFilteredWithMl const& candsDplus, + 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 = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusTrackWithMl, "Process Dplus candidates paired with Tracks with ML info", false); + + void processDplusV0AndTrackWithMl(soa::Join const& collisions, + CandsDplusFilteredWithMl const& candsDplus, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + TracksIUWithPID const& tracksIU, + 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, tracks, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0AndTrackWithMl, "Process Dplus candidates paired with V0s and Tracks with ML info", false); + + // D0 + void processD0V0WithMl(soa::Join const& collisions, + CandsD0FilteredWithMl const& candsD0, + aod::V0s const& v0s, + TracksIUWithPID const& tracksIU, + 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 = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, 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); + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0V0WithMl, "Process D0 candidates paired with V0s with ML info", false); + + void processD0TrackWithMl(soa::Join const& collisions, + CandsD0FilteredWithMl const& candsD0, + 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 = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0TrackWithMl, "Process D0 candidates paired with Tracks with ML info", false); + + void processD0V0AndTrackWithMl(soa::Join const& collisions, + CandsD0FilteredWithMl const& candsD0, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPID const& tracks, + TracksIUWithPID const& tracksIU, + 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 = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, tracks, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0V0AndTrackWithMl, "Process D0 candidates paired with V0s and Tracks with ML info", false); + + // MC + // No ML + // D* + void processDstarV0MC(soa::Join const& collisions, + CandsDstarFilteredWithMc const& candsDstar, + aod::V0s const& v0s, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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, v0sThisColl, tracksIU, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0MC, "Process Dstar candidates paired with V0s with MC matching", false); + + void processDstarTrackMC(soa::Join const& collisions, + CandsDstarFilteredWithMc const& candsDstar, + TracksWithPIDAndMC const& tracks, + aod::TrackAssoc const& trackIndices, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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, trackIdsThisColl, tracks, tracks, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarTrackMC, "Process Dstar candidates paired with tracks with MC matching", false); + + void processDstarV0AndTrackMC(soa::Join const& collisions, + CandsDstarFilteredWithMc const& candsDstar, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPIDAndMC const& tracks, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0AndTrackMC, "Process Dstar candidates paired with V0s and tracks with MC matching", false); + + // Dplus + void processDplusV0MC(soa::Join const& collisions, + CandsDplusFilteredWithMc const& candsDplus, + aod::V0s const& v0s, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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, v0sThisColl, tracksIU, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0MC, "Process Dstar candidates paired with V0s with MC matching", false); + + void processDplusTrackMC(soa::Join const& collisions, + CandsDplusFilteredWithMc const& candsDplus, + TracksWithPIDAndMC const& tracks, + aod::TrackAssoc const& trackIndices, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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 trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, trackIdsThisColl, trackIdsThisColl, tracks, tracks, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusTrackMC, "Process Dplus candidates paired with tracks with MC matching", false); + + void processDplusV0AndTrackMC(soa::Join const& collisions, + CandsDplusFilteredWithMc const& candsDplus, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPIDAndMC const& tracks, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0AndTrackMC, "Process Dplus candidates paired with V0s and tracks with MC matching", false); + + // D0 + void processD0V0MC(soa::Join const& collisions, + CandsD0FilteredWithMc const& candsD0, + aod::V0s const& v0s, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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 = candsD0.sliceBy(candsD0PerCollision, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, v0sThisColl, tracksIU, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0V0MC, "Process D0 candidates paired with V0s with MC matching", false); + + void processD0TrackMC(soa::Join const& collisions, + CandsD0FilteredWithMc const& candsD0, + TracksWithPIDAndMC const& tracks, + aod::TrackAssoc const& trackIndices, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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 = candsD0.sliceBy(candsD0PerCollision, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, trackIdsThisColl, trackIdsThisColl, tracks, tracks, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0TrackMC, "Process D0 candidates paired with tracks with MC matching", false); + + void processD0V0AndTrackMC(soa::Join const& collisions, + CandsD0FilteredWithMc const& candsD0, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPIDAndMC const& tracks, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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 = candsD0.sliceBy(candsD0PerCollision, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0V0AndTrackMC, "Process D0 candidates paired with V0s and tracks with MC matching", false); + // ML + // D* + void processDstarV0MCWithMl(soa::Join const& collisions, + CandsDstarFilteredWithMlAndMc const& candsDstar, + aod::V0s const& v0s, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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, nullptr, tracksIU, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0MCWithMl, "Process Dstar candidates paired with V0s with MC matching and with ML info", false); + + void processDstarTrackMCWithMl(soa::Join const& collisions, + CandsDstarFilteredWithMlAndMc const& candsDstar, + TracksWithPIDAndMC const& tracks, + aod::TrackAssoc const& trackIndices, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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, trackIdsThisColl, tracks, tracks, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarTrackMCWithMl, "Process Dstar candidates paired with tracks with MC matching and with ML info", false); + + void processDstarV0AndTrackMCWithMl(soa::Join const& collisions, + CandsDstarFilteredWithMlAndMc const& candsDstar, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPIDAndMC const& tracks, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDstarV0AndTrackMCWithMl, "Process Dstar candidates paired with V0s and tracks with MC matching and with ML info", false); + + // Dplus + void processDplusV0MCWithMl(soa::Join const& collisions, + CandsDplusFilteredWithMlAndMc const& candsDplus, + aod::V0s const& v0s, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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, nullptr, tracksIU, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0MCWithMl, "Process Dplus candidates paired with V0s with MC matching and with ML info", false); + + void processDplusTrackMCWithMl(soa::Join const& collisions, + CandsDplusFilteredWithMlAndMc const& candsDplus, + TracksWithPIDAndMC const& tracks, + aod::TrackAssoc const& trackIndices, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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 trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, trackIdsThisColl, trackIdsThisColl, tracks, tracks, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusTrackMCWithMl, "Process Dplus candidates paired with tracks with MC matching and with ML info", false); + + void processDplusV0AndTrackMCWithMl(soa::Join const& collisions, + CandsDplusFilteredWithMlAndMc const& candsDplus, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPIDAndMC const& tracks, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processDplusV0AndTrackMCWithMl, "Process Dplus candidates paired with V0s and tracks with MC matching and with ML info", false); + + // D0 + void processD0V0MCWithMl(soa::Join const& collisions, + CandsD0FilteredWithMlAndMc const& candsD0, + aod::V0s const& v0s, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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 = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0V0MCWithMl, "Process D0 candidates paired with V0s with MC matching and with ML info", false); + + void processD0TrackMCWithMl(soa::Join const& collisions, + CandsD0FilteredWithMlAndMc const& candsD0, + TracksWithPIDAndMC const& tracks, + aod::TrackAssoc const& trackIndices, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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 = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, trackIdsThisColl, trackIdsThisColl, tracks, tracks, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0TrackMCWithMl, "Process D0 candidates paired with tracks with MC matching and with ML info", false); + + void processD0V0AndTrackMCWithMl(soa::Join const& collisions, + CandsD0FilteredWithMlAndMc const& candsD0, + aod::V0s const& v0s, + aod::TrackAssoc const& trackIndices, + TracksWithPIDAndMC const& tracks, + TracksIUWithPIDAndMC const& tracksIU, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisionsNoCents const& collInfos, + aod::McCollisions const& mcCollisions) + { + 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 = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); + auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); + auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, bcs); + } + runMcGen(particlesMc, collInfos, mcCollisions, bcs); + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorCharmResoReduced, processD0V0AndTrackMCWithMl, "Process D0 candidates paired with V0s and tracks with MC matching and with ML info", false); }; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx new file mode 100644 index 00000000000..8a2b53b9380 --- /dev/null +++ b/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx @@ -0,0 +1,1248 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file dataCreatorJpsiHadReduced.cxx +/// \brief Creation of J/Psi-LF hadron pairs for Beauty hadron analyses +/// +/// \author Fabrizio Chinu , Università degli Studi and INFN Torino +/// \author Fabrizio Grosa , CERN + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/D2H/Utils/utilsRedDataFormat.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelectorPID.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::aod; +using namespace o2::constants::physics; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_trkcandsel; + +enum Event : uint8_t { // TODO: check if needed + Processed = 0, + NoCharmHadPiSelected, + CharmHadPiSelected, + NEvent +}; + +enum DecayChannel : uint8_t { + B0ToJpsiK0Star = 0, + BplusToJpsiK, + BsToJpsiPhi +}; + +enum WrongCollisionType : uint8_t { + None = 0, + WrongAssociation, + SplitCollision, +}; + +/// Creation of Jpsi-Had pairs for Beauty hadrons +struct HfDataCreatorJpsiHadReduced { + // Produces AOD tables to store track information + // collision related tables + Produces hfReducedCollision; + Produces hfReducedCollCentrality; + Produces hfReducedQvector; + Produces hfReducedCollExtra; + Produces hfCollisionCounter; + // J/Psi related tables + Produces hfJpsi; + Produces hfRedJpsiCov; + // Ka bachelor related tables + Produces hfTrackLfDau0; + Produces hfTrackCovLfDau0; + Produces hfTrackLfDau1; + Produces hfTrackCovLfDau1; + // MC related tables + Produces rowHfJpsiKMcRecReduced; + Produces rowHfJpsiPhiMcRecReduced; + Produces rowHfBpMcGenReduced; + Produces rowHfBsMcGenReduced; + + Produces rowCandidateConfigBplus; + Produces rowCandidateConfigBs; + + Configurable skipRejectedCollisions{"skipRejectedCollisions", true, "skips collisions rejected by the event selection, instead of flagging only"}; + 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 B0 is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations is chi2/chi2old > this"}; + + Configurable runJpsiToee{"runJpsiToee", false, "Run analysis for J/Psi to ee (debug)"}; + struct : o2::framework::ConfigurableGroup { + // 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 nSigmaTpcElMax{"nSigmaTpcElMax", 4., "Electron nsigma cut on TPC only"}; + Configurable nSigmaTpcPiMin{"nSigmaTpcPiMin", 2.5, "Pion nsigma cut on TPC only"}; + Configurable nSigmaTpcPiMax{"nSigmaTpcPiMax", 99., "Pion nsigma cut on TPC only"}; + Configurable nSigmaTpcPrMin{"nSigmaTpcPrMin", -99., "Proton nsigma cut on TPC only"}; + Configurable nSigmaTpcPrMax{"nSigmaTpcPrMax", 99, "Proton nsigma cut on TPC only"}; + Configurable nSigmaTpcElCombinedMax{"nSigmaTpcElCombinedMax", 4., "Electron Nsigma cut on TPC combined with TOF"}; + Configurable nSigmaTpcPiCombinedMin{"nSigmaTpcPiCombinedMin", 2.5, "Pion Nsigma cut on TPC combined with TOF"}; + Configurable nSigmaTpcPiCombinedMax{"nSigmaTpcPiCombinedMax", 99., "Pion Nsigma cut on TPC combined with TOF"}; + Configurable nSigmaTpcPrCombinedMin{"nSigmaTpcPrCombinedMin", -99., "Proton Nsigma cut on TPC combined with TOF"}; + Configurable nSigmaTpcPrCombinedMax{"nSigmaTpcPrCombinedMax", 99, "Proton 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", 5., "Upper bound of track pT for TOF PID"}; + Configurable nSigmaTofElMax{"nSigmaTofElMax", 4., "Electron nsigma cut on TPC only"}; + Configurable nSigmaTofPiMin{"nSigmaTofPiMin", -99, "Pion nsigma cut on TPC only"}; + Configurable nSigmaTofPiMax{"nSigmaTofPiMax", 99., "Pion nsigma cut on TPC only"}; + Configurable nSigmaTofPrMin{"nSigmaTofPrMin", -99, "Proton nsigma cut on TPC only"}; + Configurable nSigmaTofPrMax{"nSigmaTofPrMax", 99., "Proton nsigma cut on TPC only"}; + Configurable nSigmaTofElCombinedMax{"nSigmaTofElCombinedMax", 4., "Electron Nsigma cut on TOF combined with TPC"}; + Configurable nSigmaTofPiCombinedMin{"nSigmaTofPiCombinedMin", 2.5, "Pion Nsigma cut on TOF combined with TPC"}; + Configurable nSigmaTofPiCombinedMax{"nSigmaTofPiCombinedMax", 99., "Pion Nsigma cut on TOF combined with TPC"}; + Configurable nSigmaTofPrCombinedMin{"nSigmaTofPrCombinedMin", -99., "Proton Nsigma cut on TOF combined with TPC"}; + Configurable nSigmaTofPrCombinedMax{"nSigmaTofPrCombinedMax", 99, "Proton Nsigma cut on TOF combined with TPC"}; + // AND logic for TOF+TPC PID (as in Run2) + Configurable usePidTpcAndTof{"usePidTpcAndTof", true, "Use AND logic for TPC and TOF PID"}; + } selectionsPid; + Configurable ptJpsiMin{"ptJpsiMin", 0., "Lower bound of J/Psi pT"}; + Configurable ptJpsiMax{"ptJpsiMax", 50., "Upper bound of J/Psi pT"}; + Configurable useTrackIsGlobalTrackWoDCA{"useTrackIsGlobalTrackWoDCA", true, "check isGlobalTrackWoDCA status for the bachelor tracks"}; + Configurable ptTrackMin{"ptTrackMin", 0.5, "minimum bachelor track pT threshold (GeV/c)"}; + Configurable absEtaTrackMax{"absEtaTrackMax", 0.8, "maximum bachelor track absolute eta threshold"}; + Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for bachelor track DCA XY pT-dependent cut"}; + Configurable> cutsTrackDCA{"cutsTrackDCA", {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 bachelor track"}; + // topological/kinematic cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_jpsi_to_mu_mu::vecBinsPt}, "J/Psi pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_jpsi_to_mu_mu::Cuts[0], hf_cuts_jpsi_to_mu_mu::NBinsPt, hf_cuts_jpsi_to_mu_mu::NCutVars, hf_cuts_jpsi_to_mu_mu::labelsPt, hf_cuts_jpsi_to_mu_mu::labelsCutVar}, "J/Psi candidate selection per pT bin"}; + Configurable invMassWindowJpsiHad{"invMassWindowJpsiHad", 0.3, "invariant-mass window for Jpsi-Had pair preselections (GeV/c2)"}; + Configurable deltaMPhiMax{"deltaMPhiMax", 0.02, "invariant-mass window for phi preselections (GeV/c2) (only for Bs->J/PsiPhi)"}; + Configurable cpaMin{"cpaMin", 0., "Minimum cosine of pointing angle for B candidates"}; + Configurable decLenMin{"decLenMin", 0., "Minimum decay length for B candidates"}; + + // magnetic field setting from CCDB + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + + TrackSelectorPi selectorPion; + TrackSelectorPr selectorProton; + TrackSelectorEl selectorElectron; + + // CCDB service + Service ccdb; + // O2DatabasePDG service + Service pdg; + + using TracksPid = soa::Join; + using TracksPidWithSel = soa::Join; + using TracksPidWithSelAndMc = soa::Join; + using CollisionsWCMcLabels = soa::Join; + using BCsInfo = soa::Join; + + Preslice candsJpsiPerCollision = aod::track_association::collisionId; + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + int runNumber{}; + double bz{0.}; + double invMass2JpsiHadMin{}, invMass2JpsiHadMax{}; + bool isHfCandBhadConfigFilled = false; + + o2::hf_evsel::HfEventSelection hfEvSel; + o2::hf_evsel::HfEventSelectionMc hfEvSelMc; + + o2::vertexing::DCAFitterN<2> df2; + o2::vertexing::DCAFitterN<3> df3; + o2::vertexing::DCAFitterN<4> df4; + + HistogramRegistry registry{"registry"}; + OutputObj zorroSummary{"zorroSummary"}; + + void init(InitContext& initContext) + { + selectorPion.setRangePtTpc(selectionsPid.ptPidTpcMin, selectionsPid.ptPidTpcMax); + selectorPion.setRangeNSigmaTpc(-selectionsPid.nSigmaTpcPiMax, selectionsPid.nSigmaTpcPiMax); + selectorPion.setRangeNSigmaTpcCondTof(-selectionsPid.nSigmaTpcPiCombinedMax, selectionsPid.nSigmaTpcPiCombinedMax); + selectorPion.setRangePtTof(selectionsPid.ptPidTofMin, selectionsPid.ptPidTofMax); + selectorPion.setRangeNSigmaTof(-selectionsPid.nSigmaTofPiMax, selectionsPid.nSigmaTofPiMax); + selectorPion.setRangeNSigmaTofCondTpc(-selectionsPid.nSigmaTofPiCombinedMax, selectionsPid.nSigmaTofPiCombinedMax); + + selectorProton.setRangePtTpc(selectionsPid.ptPidTpcMin, selectionsPid.ptPidTpcMax); + selectorProton.setRangeNSigmaTpc(-selectionsPid.nSigmaTpcPrMax, selectionsPid.nSigmaTpcPrMax); + selectorProton.setRangeNSigmaTpcCondTof(-selectionsPid.nSigmaTpcPrCombinedMax, selectionsPid.nSigmaTpcPrCombinedMax); + selectorProton.setRangePtTof(selectionsPid.ptPidTofMin, selectionsPid.ptPidTofMax); + selectorProton.setRangeNSigmaTof(-selectionsPid.nSigmaTofPrMax, selectionsPid.nSigmaTofPrMax); + selectorProton.setRangeNSigmaTofCondTpc(-selectionsPid.nSigmaTofPrCombinedMax, selectionsPid.nSigmaTofPrCombinedMax); + + selectorElectron.setRangePtTpc(selectionsPid.ptPidTpcMin, selectionsPid.ptPidTpcMax); + selectorElectron.setRangeNSigmaTpc(-selectionsPid.nSigmaTpcElMax, selectionsPid.nSigmaTpcElMax); + selectorElectron.setRangeNSigmaTpcCondTof(-selectionsPid.nSigmaTofElCombinedMax, selectionsPid.nSigmaTofElCombinedMax); + selectorElectron.setRangePtTof(selectionsPid.ptPidTofMin, selectionsPid.ptPidTofMax); + selectorElectron.setRangeNSigmaTof(-selectionsPid.nSigmaTofElMax, selectionsPid.nSigmaTofElMax); + selectorElectron.setRangeNSigmaTofCondTpc(-selectionsPid.nSigmaTofElCombinedMax, selectionsPid.nSigmaTofElCombinedMax); + + std::array doProcess = {doprocessJpsiKData, doprocessJpsiKMc, doprocessJpsiPhiData, doprocessJpsiPhiMc}; + 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!"); + } + + // Set up the histogram registry + constexpr int kNBinsSelections = 2 + aod::SelectionStep::RecoPID; + 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"; + static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; + registry.add("hSelectionsJpsi", "J/Psi selection;;#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("hSelectionsJpsi"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + } + + constexpr int kNBinsEvents = NEvent; + std::string labelsEvents[kNBinsEvents]; + labelsEvents[Event::Processed] = "processed"; + labelsEvents[Event::NoCharmHadPiSelected] = "without CharmHad-Pi pairs"; + labelsEvents[Event::CharmHadPiSelected] = "with CharmHad-Pi pairs"; + static const AxisSpec axisEvents = {kNBinsEvents, 0.5, kNBinsEvents + 0.5, ""}; + registry.add("hEvents", "Events;;entries", HistType::kTH1F, {axisEvents}); + for (int iBin = 0; iBin < kNBinsEvents; iBin++) { + registry.get(HIST("hEvents"))->GetXaxis()->SetBinLabel(iBin + 1, labelsEvents[iBin].data()); + } + + registry.add("hMassJpsi", "J/Psi mass;#it{M}_{#mu#mu} (GeV/#it{c}^{2});Counts", {HistType::kTH1F, {{600, 2.8, 3.4, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hPtJpsi", "J/Psi #it{p}_{T};#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {{(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("hCpaJpsi", "J/Psi cos#theta_{p};J/Psi cos#theta_{p};Counts", {HistType::kTH1F, {{200, -1., 1, "J/Psi cos#theta_{p}"}}}); + std::shared_ptr hFitCandidatesJpsi = registry.add("hFitCandidatesJpsi", "Jpsi candidate counter", {HistType::kTH1D, {axisCands}}); + std::shared_ptr hFitCandidatesBPlus = registry.add("hFitCandidatesBPlus", "hFitCandidatesBPlus candidate counter", {HistType::kTH1D, {axisCands}}); + std::shared_ptr hFitCandidatesBS = registry.add("hFitCandidatesBS", "hFitCandidatesBS candidate counter", {HistType::kTH1D, {axisCands}}); + setLabelHistoCands(hFitCandidatesJpsi); + setLabelHistoCands(hFitCandidatesBPlus); + setLabelHistoCands(hFitCandidatesBS); + if (doprocessJpsiKData || doprocessJpsiKMc) { + registry.add("hPtKaon", "Kaon #it{p}_{T};#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("hMassJpsiKaon", "J/Psi Kaon mass;#it{M}_{J/#PsiK} (GeV/#it{c}^{2});Counts", {HistType::kTH1F, {{800, 4.9, 5.7}}}); + } else if (doprocessJpsiPhiData || doprocessJpsiPhiMc) { + registry.add("hPtPhi", "Phi #it{p}_{T};#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("hMassPhi", "Phi mass;#it{M}_{KK} (GeV/#it{c}^{2});Counts", {HistType::kTH1F, {{200, 0.9, 1.2}}}); + registry.add("hMassJpsiPhi", "J/Psi Phi mass;#it{M}_{J/#Psi#phi} (GeV/#it{c}^{2});Counts", {HistType::kTH1F, {{800, 4.9, 5.7}}}); + std::shared_ptr hFitCandidatesPhi = registry.add("hFitCandidatesPhi", "Phi candidate counter", {HistType::kTH1D, {axisCands}}); + setLabelHistoCands(hFitCandidatesPhi); + } + + df2.setPropagateToPCA(propagateToPCA); + df2.setMaxR(maxR); + df2.setMaxDZIni(maxDZIni); + df2.setMinParamChange(minParamChange); + df2.setMinRelChi2Change(minRelChi2Change); + df2.setUseAbsDCA(useAbsDCA); + df2.setWeightedFinalPCA(useWeightedFinalPCA); + df2.setMatCorrType(noMatCorr); + + df3.setPropagateToPCA(propagateToPCA); + df3.setMaxR(maxR); + df3.setMaxDZIni(maxDZIni); + df3.setMinParamChange(minParamChange); + df3.setMinRelChi2Change(minRelChi2Change); + df3.setUseAbsDCA(useAbsDCA); + df3.setWeightedFinalPCA(useWeightedFinalPCA); + df3.setMatCorrType(noMatCorr); + + df4.setPropagateToPCA(propagateToPCA); + df4.setMaxR(maxR); + df4.setMaxDZIni(maxDZIni); + df4.setMinParamChange(minParamChange); + df4.setMinRelChi2Change(minRelChi2Change); + df4.setUseAbsDCA(useAbsDCA); + df4.setWeightedFinalPCA(useWeightedFinalPCA); + df4.setMatCorrType(noMatCorr); + + // Configure CCDB access + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + runNumber = 0; + + if (doprocessJpsiKData || doprocessJpsiKMc) { + invMass2JpsiHadMin = (MassBPlus - invMassWindowJpsiHad) * (MassBPlus - invMassWindowJpsiHad); + invMass2JpsiHadMax = (MassBPlus + invMassWindowJpsiHad) * (MassBPlus + invMassWindowJpsiHad); + } else if (doprocessJpsiPhiData || doprocessJpsiPhiMc) { + invMass2JpsiHadMin = (MassBS - invMassWindowJpsiHad) * (MassBS - invMassWindowJpsiHad); + invMass2JpsiHadMax = (MassBS + invMassWindowJpsiHad) * (MassBS + invMassWindowJpsiHad); + } + + // init HF event selection helper + hfEvSel.init(registry, zorroSummary); + if (doprocessJpsiKMc || doprocessJpsiPhiMc) { + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name == "hf-data-creator-jpsi-had-reduced") { + // init HF event selection helper + hfEvSelMc.init(device, registry); + break; + } + } + } + } + + /// Topological cuts + /// \param candidate is candidate + /// \param trackPos is the positive track + /// \param trackNeg is the negative track + /// \return true if candidate passes all cuts + template + bool selectionTopol(const T1& candidate, const T2& trackPos, const T2& trackNeg) + { + auto candpT = candidate.pt(); + auto candInvMass = runJpsiToee ? HfHelper::invMassJpsiToEE(candidate) : HfHelper::invMassJpsiToMuMu(candidate); + auto pseudoPropDecLen = candidate.decayLengthXY() * candInvMass / candpT; + auto pTBin = findBin(binsPt, candpT); + if (pTBin == -1) { + return false; + } + + // check that the candidate pT is within the analysis range + if (candpT < ptJpsiMin || candpT >= ptJpsiMax) { + return false; + } + + // cut on μ+ μ− (e+e−) invariant mass + if (std::abs(candInvMass - o2::constants::physics::MassJPsi) > cuts->get(pTBin, "m")) { + return false; + } + + // cut on daughter pT (same cut used for both channels) + if (trackNeg.pt() < cuts->get(pTBin, "pT mu") || trackPos.pt() < cuts->get(pTBin, "pT mu")) { + return false; + } + + // decay length + if (candidate.decayLength() < cuts->get(pTBin, "decay length")) { + return false; + } + + // decay length in XY plane + if (candidate.decayLengthXY() < cuts->get(pTBin, "decay length xy")) { + return false; + } + + // cosine of pointing angle + if (candidate.cpa() < cuts->get(pTBin, "cpa")) { + return false; + } + + // cosine of pointing angle XY + if (candidate.cpaXY() < cuts->get(pTBin, "cpa xy")) { + return false; + } + + // product of daughter impact parameters + if (candidate.impactParameterProduct() > cuts->get(pTBin, "d0xd0")) { + return false; + } + + // pseudoproper decay length + if (pseudoPropDecLen < cuts->get(pTBin, "pseudoprop. decay length")) { + return false; + } + + return true; + } + + /// Kaon selection (J/Psi K+ <-- B+) + /// \param track is the considered track + /// \param trackParCov is the track parametrisation + /// \param dca is the 2-D array with track DCAs + /// \param jPsiDautracks J/Psi daughter tracks + /// \return true if track passes all cuts + template + bool isTrackSelected(const T1& track, const T2& trackParCov, const T3& dca, const std::vector& jPsiDautracks) + { + // check isGlobalTrackWoDCA status for kaons if wanted + if (useTrackIsGlobalTrackWoDCA && !track.isGlobalTrackWoDCA()) { + return false; + } + // minimum pT, eta, and DCA selection + if (trackParCov.getPt() < ptTrackMin || std::abs(trackParCov.getEta()) > absEtaTrackMax || !isSelectedTrackDCA(trackParCov, dca, binsPtTrack, cutsTrackDCA)) { + return false; + } + // reject kaons that are J/Psi daughters + for (const auto& trackJpsi : jPsiDautracks) { + if (track.globalIndex() == trackJpsi.globalIndex()) { + return false; + } + } + + return true; + } + + template + bool isSelectedJpsiDauPid(const T1& track) + { + int pidPion = -1; + int pidProton = -1; + int pidElectron = -1; + + if (selectionsPid.usePidTpcAndTof) { + pidPion = selectorPion.statusTpcAndTof(track, track.tpcNSigmaPi(), track.tofNSigmaPi()); + pidProton = selectorProton.statusTpcAndTof(track, track.tpcNSigmaPr(), track.tofNSigmaPr()); + pidElectron = selectorElectron.statusTpcAndTof(track, track.tpcNSigmaEl(), track.tofNSigmaEl()); + } else { + pidPion = selectorPion.statusTpcOrTof(track, track.tpcNSigmaPi(), track.tofNSigmaPi()); + pidProton = selectorProton.statusTpcOrTof(track, track.tpcNSigmaPr(), track.tofNSigmaPr()); + pidElectron = selectorElectron.statusTpcOrTof(track, track.tpcNSigmaEl(), track.tofNSigmaEl()); + } + + if (pidPion == TrackSelectorPID::Rejected || + pidProton == TrackSelectorPID::Rejected || + pidElectron == TrackSelectorPID::Rejected) { + return false; + } + return true; + } + + /// B meson preselections + /// \param momentum is the B meson momentum + /// \param secondaryVertex is the reconstructed secondary vertex + /// \param collision is the reconstructed collision + template + bool isBSelected(const T1& momentum, const T2& secondaryVertex, const T3& collision) + { + // B candidate CPA + if (RecoDecay::cpa(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex, momentum) < cpaMin) { + return false; + } + + // B candidate decay length + if (RecoDecay::distance(std::array{collision.posX(), collision.posY(), collision.posZ()}, secondaryVertex) < decLenMin) { + return false; + } + + return true; + } + + /// 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 (Jpsi daughters in first position) + /// \param indexHfCandJpsi is the index of the Jpsi candidate + /// \param selectedTracksBach is the map with the indices of selected bachelor pion tracks + template + void fillMcRecoInfo(CColl const& collision, + PParticles const& particlesMc, + std::vector const& vecDaughtersB, + const int64_t indexHfCandJpsi, + std::array, 2> selectedTracksBach, + const int64_t indexCollisionMaxNumContrib) + { + + // we check the MC matching to be stored + int8_t sign{0}, flag{0}, channel{0}; + int8_t flagWrongCollision{WrongCollisionType::None}; + int8_t debug{0}; + float motherPt{-1.f}; + + if constexpr (DecChannel == DecayChannel::BplusToJpsiK) { + // B+ → J/Psi K+ → (µ+µ-) K+ + int indexRec = -1; + if (!runJpsiToee) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kBPlus, std::array{-kMuonMinus, +kMuonMinus, +kKPlus}, true, &sign, 3); + } else { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kBPlus, std::array{-kElectron, +kElectron, +kKPlus}, true, &sign, 3); + } + if (indexRec > -1) { + // J/Psi → µ+µ- + if (!runJpsiToee) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1]}, Pdg::kJPsi, std::array{-kMuonMinus, +kMuonMinus}, true); + } else { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1]}, Pdg::kJPsi, std::array{-kElectron, +kElectron}, true); + } + if (indexRec > -1) { + flag = sign * o2::hf_decay::hf_cand_beauty::BplusToJpsiK; + } else { + debug = 1; + 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); + } + } + rowHfJpsiKMcRecReduced(indexHfCandJpsi, selectedTracksBach[0][vecDaughtersB.back().globalIndex()], flag, channel, flagWrongCollision, debug, motherPt); + } else if constexpr (DecChannel == DecayChannel::BsToJpsiPhi) { + // Bs → J/Psi phi → (µ+µ-) (K+K-) + int indexRec = -1; + if (!runJpsiToee) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kBS, std::array{-kMuonMinus, +kMuonMinus, +kKPlus, -kKPlus}, true, &sign, 4); + } else { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kBS, std::array{-kElectron, +kElectron, +kKPlus, -kKPlus}, true, &sign, 4); + } + if (indexRec > -1) { + // J/Psi → µ+µ- + if (!runJpsiToee) { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1]}, Pdg::kJPsi, std::array{-kMuonMinus, +kMuonMinus}, true, &sign, 1); + } else { + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1]}, Pdg::kJPsi, std::array{-kElectron, +kElectron}, true, &sign, 1); + } + if (indexRec > -1) { + flag = sign * o2::hf_decay::hf_cand_beauty::BsToJpsiKK; + indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kPhi, std::array{-kKPlus, +kKPlus}, true, &sign, 1); + if (indexRec > -1) { + channel = o2::hf_decay::hf_cand_beauty::BsToJpsiPhi; + } else { + debug = 1; + LOGF(debug, "Bs decays in the expected final state but the condition on the phi intermediate state is not fulfilled"); + } + } else { + debug = 1; + LOGF(debug, "Bs decays in the expected final state but the condition on the J/Psi 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); + } + } + rowHfJpsiPhiMcRecReduced(indexHfCandJpsi, selectedTracksBach[0][vecDaughtersB.back().globalIndex()], selectedTracksBach[1][vecDaughtersB.back().globalIndex()], flag, channel, flagWrongCollision, debug, motherPt); + } + } + + /// 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; + } + + template + void runMcGen(aod::McCollision const& mcCollision, + aod::McParticles const& particlesMc, + CollisionsWCMcLabels const& collisions, + BCsInfo const&) + { + // Check event selection + float centDummy{-1.f}, centFT0C{-1.f}, centFT0M{-1.f}; + const auto collSlice = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + auto hfRejMap = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centDummy); + if (skipRejectedCollisions && hfRejMap != 0) { + return; + } + + const auto mcParticlesPerMcColl = particlesMc.sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + + // Match generated particles. + for (const auto& particle : mcParticlesPerMcColl) { + int8_t sign{0}, flag{0}, channel{0}; + if constexpr (DecChannel == DecayChannel::BplusToJpsiK) { + // B+ → J/Psi K+ → (µ+µ-) K+ + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kBPlus, std::array{static_cast(Pdg::kJPsi), +kKPlus}, true, &sign)) { + // Match J/Psi -> µ+µ- + auto candJpsiMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + // Printf("Checking J/Psi -> µ+µ-"); + if (!runJpsiToee) { + if (RecoDecay::isMatchedMCGen(particlesMc, candJpsiMC, static_cast(Pdg::kJPsi), std::array{-kMuonMinus, +kMuonMinus}, true)) { + flag = sign * o2::hf_decay::hf_cand_beauty::BplusToJpsiK; + } + } else { // debug + // Printf("Checking J/Psi -> e+e-"); + if (RecoDecay::isMatchedMCGen(particlesMc, candJpsiMC, static_cast(Pdg::kJPsi), std::array{-kElectron, +kElectron}, true)) { + flag = sign * o2::hf_decay::hf_cand_beauty::BplusToJpsiK; + } + } + } + + // save information for B+ task + if (std::abs(flag) != o2::hf_decay::hf_cand_beauty::BplusToJpsiK) { + continue; + } + + auto ptParticle = particle.pt(); + auto yParticle = RecoDecay::y(particle.pVector(), MassBPlus); + 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++; + } + rowHfBpMcGenReduced(flag, channel, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1], hfRejMap, centFT0C, centFT0M); + } else if constexpr (DecChannel == DecayChannel::BsToJpsiPhi) { + // Bs → J/Psi phi → (µ+µ-) (K+K-) + if (RecoDecay::isMatchedMCGen(particlesMc, particle, Pdg::kBS, std::array{static_cast(Pdg::kJPsi), +kKPlus, -kKPlus}, true, &sign, 2)) { + // Match J/Psi -> µ+µ- and phi -> K+K- + auto candJpsiMC = particlesMc.rawIteratorAt(particle.daughtersIds().front()); + auto candPhiMC = particlesMc.rawIteratorAt(particle.daughtersIds().back()); + // Printf("Checking J/Psi -> µ+µ- and phi -> K+K-"); + if (runJpsiToee && RecoDecay::isMatchedMCGen(particlesMc, candJpsiMC, static_cast(Pdg::kJPsi), std::array{-kElectron, +kElectron}, true)) { + flag = sign * o2::hf_decay::hf_cand_beauty::BsToJpsiKK; + } else if (!runJpsiToee && RecoDecay::isMatchedMCGen(particlesMc, candJpsiMC, static_cast(Pdg::kJPsi), std::array{-kMuonMinus, +kMuonMinus}, true)) { + flag = sign * o2::hf_decay::hf_cand_beauty::BsToJpsiKK; + } + // Check phi -> K+K- + if (RecoDecay::isMatchedMCGen(particlesMc, candPhiMC, static_cast(Pdg::kPhi), std::array{-kKPlus, +kKPlus}, true)) { + channel = o2::hf_decay::hf_cand_beauty::BsToJpsiPhi; + } + } + + // save information for Bs task + if (std::abs(flag) != o2::hf_decay::hf_cand_beauty::BsToJpsiKK) { + continue; + } + + auto ptParticle = particle.pt(); + auto yParticle = RecoDecay::y(particle.pVector(), MassBPlus); + 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, channel, ptParticle, yParticle, etaParticle, + ptProngs[0], yProngs[0], etaProngs[0], + ptProngs[1], yProngs[1], etaProngs[1], hfRejMap, centFT0C, centFT0M); + } + } // gen + } + + // Jpsi candidate selection + template + void runDataCreation(Coll const& collision, + JpsiCands const& candsJpsi, + aod::TrackAssoc const& trackIndices, + TTracks const&, + PParticles const& particlesMc, + uint64_t const& indexCollisionMaxNumContrib, + BBCs const&) + { + + registry.fill(HIST("hEvents"), 1 + Event::Processed); + float centrality = -1.f; + const auto hfRejMap = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + if (skipRejectedCollisions && hfRejMap != 0) { + return; + } + + // helpers for ReducedTables filling + int const indexHfReducedCollision = hfReducedCollision.lastIndex() + 1; + // std::map where the key is the track.globalIndex() and + // the value is the track index in the table of the selected tracks + std::map selectedTracksBach; + std::map selectedTracksBach2; // for the second daughter (for B0 and Bs) + + bool fillHfReducedCollision = false; + + auto primaryVertex = getPrimaryVertex(collision); + + // 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; + auto* 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(); + LOG(info) << ">>>>>>>>>>>> Magnetic field: " << bz; + runNumber = bc.runNumber(); + } + df2.setBz(bz); + df3.setBz(bz); + df4.setBz(bz); + + auto thisCollId = collision.globalIndex(); + // looping over 2-prong candidates + for (const auto& candidate : candsJpsi) { + + // Apply the selections on the J/Psi candidates + registry.fill(HIST("hSelectionsJpsi"), 1, candidate.pt()); + + if (!(candidate.hfflag() & (1 << (runJpsiToee ? aod::hf_cand_2prong::DecayType::JpsiToEE : aod::hf_cand_2prong::DecayType::JpsiToMuMu)))) { + continue; + } + registry.fill(HIST("hSelectionsJpsi"), 2 + aod::SelectionStep::RecoSkims, candidate.pt()); + + auto trackPos = candidate.template prong0_as(); // positive daughter + auto trackNeg = candidate.template prong1_as(); // negative daughter + + auto trackPosParCov = getTrackParCov(trackPos); + auto trackNegParCov = getTrackParCov(trackNeg); + + std::vector jPsiDauTracks{trackPos, trackNeg}; + + auto dca0 = o2::dataformats::DCA(jPsiDauTracks[0].dcaXY(), jPsiDauTracks[0].dcaZ(), jPsiDauTracks[0].cYY(), jPsiDauTracks[0].cZY(), jPsiDauTracks[0].cZZ()); + auto dca1 = o2::dataformats::DCA(jPsiDauTracks[1].dcaXY(), jPsiDauTracks[1].dcaZ(), jPsiDauTracks[1].cYY(), jPsiDauTracks[1].cZY(), jPsiDauTracks[1].cZZ()); + + // repropagate tracks to this collision if needed + if (jPsiDauTracks[0].collisionId() != thisCollId) { + trackPosParCov.propagateToDCA(primaryVertex, bz, &dca0); + } + + if (jPsiDauTracks[1].collisionId() != thisCollId) { + trackNegParCov.propagateToDCA(primaryVertex, bz, &dca1); + } + + // --------------------------------- + // reconstruct J/Psi candidate secondary vertex + o2::track::TrackParCov const trackParCovJpsi{}; // FIXME: unused + std::array const pVecJpsi{}; // FIXME: unused + registry.fill(HIST("hFitCandidatesJpsi"), SVFitting::BeforeFit); + try { + if (df2.process(trackPosParCov, trackNegParCov) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + registry.fill(HIST("hFitCandidatesJpsi"), SVFitting::Fail); + continue; + } + registry.fill(HIST("hFitCandidatesJpsi"), SVFitting::FitOk); + + // topological selection + if (!selectionTopol(candidate, trackPos, trackNeg)) { + continue; + } + registry.fill(HIST("hSelectionsJpsi"), 2 + aod::SelectionStep::RecoTopol, candidate.pt()); + + // PID selection + if (!isSelectedJpsiDauPid(trackPos) || !isSelectedJpsiDauPid(trackNeg)) { + continue; + } + registry.fill(HIST("hSelectionsJpsi"), 2 + aod::SelectionStep::RecoPID, candidate.pt()); + + int const indexHfCandJpsi = hfJpsi.lastIndex() + 1; + float const invMassJpsi = runJpsiToee ? HfHelper::invMassJpsiToEE(candidate) : HfHelper::invMassJpsiToMuMu(candidate); + registry.fill(HIST("hMassJpsi"), invMassJpsi); + registry.fill(HIST("hPtJpsi"), candidate.pt()); + registry.fill(HIST("hCpaJpsi"), candidate.cpa()); + + bool fillHfCandJpsi = false; + + // TODO: add single track information (min eta, min ITS/TPC clusters, etc.) + double invMass2JpsiHad{0.}; + for (const auto& trackId : trackIndices) { + auto trackBach = trackId.template track_as(); + + // apply selections on bachelor tracks + auto trackParCovBach = getTrackParCov(trackBach); + std::array dcaBach{trackBach.dcaXY(), trackBach.dcaZ()}; + std::array pVecBach = trackBach.pVector(); + if (trackBach.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParCovBach, 2.f, noMatCorr, &dcaBach); + getPxPyPz(trackParCovBach, pVecBach); + } + + // apply selections on bachelor tracks + if (!isTrackSelected(trackBach, trackParCovBach, dcaBach, jPsiDauTracks)) { + continue; + } + + if constexpr (DecChannel == DecayChannel::BplusToJpsiK) { + registry.fill(HIST("hPtKaon"), trackParCovBach.getPt()); + // compute invariant mass square and apply selection + invMass2JpsiHad = RecoDecay::m2(std::array{pVecJpsi, pVecBach}, std::array{MassJPsi, MassKPlus}); + if ((invMass2JpsiHad < invMass2JpsiHadMin) || (invMass2JpsiHad > invMass2JpsiHadMax)) { + continue; + } + registry.fill(HIST("hMassJpsiKaon"), std::sqrt(invMass2JpsiHad)); + + registry.fill(HIST("hFitCandidatesBPlus"), SVFitting::BeforeFit); + try { + if (df3.process(trackPosParCov, trackNegParCov, trackParCovBach) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + registry.fill(HIST("hFitCandidatesBPlus"), SVFitting::Fail); + continue; + } + registry.fill(HIST("hFitCandidatesBPlus"), SVFitting::FitOk); + + o2::track::TrackParCov trackParCovBPlus{}; + std::array pVecBPlus{}, pVec0{}, pVec1{}, pVec2{}; + + auto secondaryVertexBPlus = df3.getPCACandidate(); + df3.propagateTracksToVertex(); + df3.getTrack(0).getPxPyPzGlo(pVec0); + df3.getTrack(1).getPxPyPzGlo(pVec1); + df3.getTrack(2).getPxPyPzGlo(pVec2); + pVecBPlus = RecoDecay::pVec(pVec0, pVec1, pVec2); + trackParCovBPlus = df3.createParentTrackParCov(); + trackParCovBPlus.setAbsCharge(0); // to be sure + + if (!isBSelected(pVecBPlus, secondaryVertexBPlus, collision)) { + continue; + } + + // fill Kaon tracks table + // if information on track already stored, go to next track + if (!selectedTracksBach.count(trackBach.globalIndex())) { + hfTrackLfDau0(trackBach.globalIndex(), indexHfReducedCollision, + trackParCovBach.getX(), trackParCovBach.getAlpha(), + trackParCovBach.getY(), trackParCovBach.getZ(), trackParCovBach.getSnp(), + trackParCovBach.getTgl(), trackParCovBach.getQ2Pt(), + trackBach.itsNCls(), trackBach.tpcNClsCrossedRows(), trackBach.tpcChi2NCl(), trackBach.itsChi2NCl(), + trackBach.hasTPC(), trackBach.hasTOF(), + trackBach.tpcNSigmaPi(), trackBach.tofNSigmaPi(), + trackBach.tpcNSigmaKa(), trackBach.tofNSigmaKa(), + trackBach.tpcNSigmaPr(), trackBach.tofNSigmaPr()); + hfTrackCovLfDau0(trackParCovBach.getSigmaY2(), trackParCovBach.getSigmaZY(), trackParCovBach.getSigmaZ2(), + trackParCovBach.getSigmaSnpY(), trackParCovBach.getSigmaSnpZ(), + trackParCovBach.getSigmaSnp2(), trackParCovBach.getSigmaTglY(), trackParCovBach.getSigmaTglZ(), + trackParCovBach.getSigmaTglSnp(), trackParCovBach.getSigmaTgl2(), + trackParCovBach.getSigma1PtY(), trackParCovBach.getSigma1PtZ(), trackParCovBach.getSigma1PtSnp(), + trackParCovBach.getSigma1PtTgl(), trackParCovBach.getSigma1Pt2()); + // add trackBach.globalIndex() to a list + // to keep memory of the pions filled in the table and avoid refilling them if they are paired to another Jpsi candidate + // and keep track of their index in hfTrackLfDau0 for McRec purposes + selectedTracksBach[trackBach.globalIndex()] = hfTrackLfDau0.lastIndex(); + } + + if constexpr (DoMc) { + std::vector beautyHadDauTracks{}; + beautyHadDauTracks.reserve(jPsiDauTracks.size()); + for (const auto& track : jPsiDauTracks) { + beautyHadDauTracks.push_back(track); + } + beautyHadDauTracks.push_back(trackBach); + fillMcRecoInfo(collision, particlesMc, beautyHadDauTracks, indexHfCandJpsi, std::array, 2>{selectedTracksBach}, indexCollisionMaxNumContrib); + } + fillHfCandJpsi = true; + } else if constexpr (DecChannel == DecayChannel::BsToJpsiPhi) { + for (auto trackBachId2 = trackId + 1; trackBachId2 != trackIndices.end(); ++trackBachId2) { + auto trackBach2 = trackBachId2.template track_as(); + auto trackBach2ParCov = getTrackParCov(trackBach2); + + std::array dcaBach2{trackBach2.dcaXY(), trackBach2.dcaZ()}; + std::array pVecBach2 = trackBach2.pVector(); + if (trackBach2.collisionId() != thisCollId) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackBach2ParCov, 2.f, noMatCorr, &dcaBach2); + getPxPyPz(trackBach2ParCov, pVecBach2); + } + + // apply selections on bachelor tracks + if (!isTrackSelected(trackBach2, trackBach2ParCov, dcaBach2, jPsiDauTracks)) { + continue; + } + std::array pVec2{trackBach.pVector()}, pVec3{trackBach2.pVector()}; + auto invMassPhi = RecoDecay::m(std::array{pVec2, pVec3}, std::array{MassKPlus, MassKPlus}); + + if (std::abs(invMassPhi - MassPhi) > deltaMPhiMax) { + continue; + } + + // --------------------------------- + // reconstruct Bs candidate secondary vertex + + registry.fill(HIST("hFitCandidatesBS"), SVFitting::BeforeFit); + try { + if (df4.process(trackPosParCov, trackNegParCov, trackParCovBach, trackBach2ParCov) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; + registry.fill(HIST("hFitCandidatesBS"), SVFitting::Fail); + continue; + } + registry.fill(HIST("hFitCandidatesBS"), SVFitting::FitOk); + + o2::track::TrackParCov trackParCovBS{}; + std::array pVecBS{}, pVec0{}, pVec1{}, pVecPhi{}; + + auto secondaryVertexBS = df4.getPCACandidate(); + df4.propagateTracksToVertex(); + df4.getTrack(0).getPxPyPzGlo(pVec0); + df4.getTrack(1).getPxPyPzGlo(pVec1); + df4.getTrack(2).getPxPyPzGlo(pVec2); + df4.getTrack(3).getPxPyPzGlo(pVec3); + pVecBS = RecoDecay::pVec(pVec0, pVec1, pVec2, pVec3); + pVecPhi = RecoDecay::pVec(pVec2, pVec3); + trackParCovBS = df4.createParentTrackParCov(); + trackParCovBS.setAbsCharge(0); // to be sure + + if (!isBSelected(pVecBS, secondaryVertexBS, collision)) { + continue; + } + + registry.fill(HIST("hPtPhi"), RecoDecay::pt(pVecBach, pVecBach2)); + registry.fill(HIST("hMassPhi"), RecoDecay::m(std::array{pVecBach, pVecBach2}, std::array{MassKPlus, MassKPlus})); + invMass2JpsiHad = RecoDecay::m2(std::array{pVecJpsi, pVecPhi}, std::array{MassJPsi, MassPhi}); + if ((invMass2JpsiHad < invMass2JpsiHadMin) || (invMass2JpsiHad > invMass2JpsiHadMax)) { + continue; + } + registry.fill(HIST("hMassJpsiPhi"), std::sqrt(invMass2JpsiHad)); + + // fill daughter tracks table + // if information on track already stored, go to next track + if (!selectedTracksBach.count(trackBach.globalIndex())) { + hfTrackLfDau0(trackBach.globalIndex(), indexHfReducedCollision, + trackParCovBach.getX(), trackParCovBach.getAlpha(), + trackParCovBach.getY(), trackParCovBach.getZ(), trackParCovBach.getSnp(), + trackParCovBach.getTgl(), trackParCovBach.getQ2Pt(), + trackBach.itsNCls(), trackBach.tpcNClsCrossedRows(), trackBach.tpcChi2NCl(), trackBach.itsChi2NCl(), + trackBach.hasTPC(), trackBach.hasTOF(), + trackBach.tpcNSigmaPi(), trackBach.tofNSigmaPi(), + trackBach.tpcNSigmaKa(), trackBach.tofNSigmaKa(), + trackBach.tpcNSigmaPr(), trackBach.tofNSigmaPr()); + hfTrackCovLfDau0(trackParCovBach.getSigmaY2(), trackParCovBach.getSigmaZY(), trackParCovBach.getSigmaZ2(), + trackParCovBach.getSigmaSnpY(), trackParCovBach.getSigmaSnpZ(), + trackParCovBach.getSigmaSnp2(), trackParCovBach.getSigmaTglY(), trackParCovBach.getSigmaTglZ(), + trackParCovBach.getSigmaTglSnp(), trackParCovBach.getSigmaTgl2(), + trackParCovBach.getSigma1PtY(), trackParCovBach.getSigma1PtZ(), trackParCovBach.getSigma1PtSnp(), + trackParCovBach.getSigma1PtTgl(), trackParCovBach.getSigma1Pt2()); + // add trackBach.globalIndex() to a list + // to keep memory of the pions filled in the table and avoid refilling them if they are paired to another Jpsi candidate + // and keep track of their index in hfTrackLfDau0 for McRec purposes + selectedTracksBach[trackBach.globalIndex()] = hfTrackLfDau0.lastIndex(); + } + + // fill daughter tracks table + // if information on track already stored, go to next track + if (!selectedTracksBach2.count(trackBach2.globalIndex())) { + hfTrackLfDau1(trackBach2.globalIndex(), indexHfReducedCollision, + trackBach2ParCov.getX(), trackBach2ParCov.getAlpha(), + trackBach2ParCov.getY(), trackBach2ParCov.getZ(), trackBach2ParCov.getSnp(), + trackBach2ParCov.getTgl(), trackBach2ParCov.getQ2Pt(), + trackBach2.itsNCls(), trackBach2.tpcNClsCrossedRows(), trackBach2.tpcChi2NCl(), trackBach2.itsChi2NCl(), + trackBach2.hasTPC(), trackBach2.hasTOF(), + trackBach2.tpcNSigmaPi(), trackBach2.tofNSigmaPi(), + trackBach2.tpcNSigmaKa(), trackBach2.tofNSigmaKa(), + trackBach2.tpcNSigmaPr(), trackBach2.tofNSigmaPr()); + hfTrackCovLfDau1(trackBach2ParCov.getSigmaY2(), trackBach2ParCov.getSigmaZY(), trackBach2ParCov.getSigmaZ2(), + trackBach2ParCov.getSigmaSnpY(), trackBach2ParCov.getSigmaSnpZ(), + trackBach2ParCov.getSigmaSnp2(), trackBach2ParCov.getSigmaTglY(), trackBach2ParCov.getSigmaTglZ(), + trackBach2ParCov.getSigmaTglSnp(), trackBach2ParCov.getSigmaTgl2(), + trackBach2ParCov.getSigma1PtY(), trackBach2ParCov.getSigma1PtZ(), trackBach2ParCov.getSigma1PtSnp(), + trackBach2ParCov.getSigma1PtTgl(), trackBach2ParCov.getSigma1Pt2()); + // add trackBach2.globalIndex() to a list + // to keep memory of the pions filled in the table and avoid refilling them if they are paired to another Jpsi candidate + // and keep track of their index in hfTrackLfDau1 for McRec purposes + selectedTracksBach2[trackBach2.globalIndex()] = hfTrackLfDau1.lastIndex(); + } + + if constexpr (DoMc) { + std::vector beautyHadDauTracks{}; + beautyHadDauTracks.reserve(jPsiDauTracks.size()); + for (const auto& track : jPsiDauTracks) { + beautyHadDauTracks.push_back(track); + } + beautyHadDauTracks.push_back(trackBach); + fillMcRecoInfo(collision, particlesMc, beautyHadDauTracks, indexHfCandJpsi, std::array, 2>{selectedTracksBach, selectedTracksBach2}, indexCollisionMaxNumContrib); + } + fillHfCandJpsi = true; + } + } + } // kaon loop + if (fillHfCandJpsi) { // fill Jpsi table only once per Jpsi candidate + double invMassJpsi{0.}; + if (runJpsiToee) { + invMassJpsi = HfHelper::invMassJpsiToEE(candidate); + } else { + invMassJpsi = HfHelper::invMassJpsiToMuMu(candidate); + } + hfJpsi(trackPos.globalIndex(), trackNeg.globalIndex(), + indexHfReducedCollision, + candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), + invMassJpsi, + trackPos.itsNCls(), trackPos.tpcNClsCrossedRows(), trackPos.tpcChi2NCl(), trackPos.itsChi2NCl(), + trackNeg.itsNCls(), trackNeg.tpcNClsCrossedRows(), trackNeg.tpcChi2NCl(), trackNeg.itsChi2NCl(), + trackPosParCov.getX(), trackNegParCov.getX(), + trackPosParCov.getY(), trackNegParCov.getY(), + trackPosParCov.getZ(), trackNegParCov.getZ(), + trackPosParCov.getAlpha(), trackNegParCov.getAlpha(), + trackPosParCov.getSnp(), trackNegParCov.getSnp(), + trackPosParCov.getTgl(), trackNegParCov.getTgl(), + trackPosParCov.getQ2Pt(), trackNegParCov.getQ2Pt()); // Q/pT + hfRedJpsiCov(trackPosParCov.getSigmaY2(), trackNegParCov.getSigmaY2(), + trackPosParCov.getSigmaZY(), trackNegParCov.getSigmaZY(), + trackPosParCov.getSigmaZ2(), trackNegParCov.getSigmaZ2(), + trackPosParCov.getSigmaSnpY(), trackNegParCov.getSigmaSnpY(), + trackPosParCov.getSigmaSnpZ(), trackNegParCov.getSigmaSnpZ(), + trackPosParCov.getSigmaSnp2(), trackNegParCov.getSigmaSnp2(), + trackPosParCov.getSigmaTglY(), trackNegParCov.getSigmaTglY(), + trackPosParCov.getSigmaTglZ(), trackNegParCov.getSigmaTglZ(), + trackPosParCov.getSigmaTglSnp(), trackNegParCov.getSigmaTglSnp(), + trackPosParCov.getSigmaTgl2(), trackNegParCov.getSigmaTgl2(), + trackPosParCov.getSigma1PtY(), trackNegParCov.getSigma1PtY(), + trackPosParCov.getSigma1PtZ(), trackNegParCov.getSigma1PtZ(), + trackPosParCov.getSigma1PtSnp(), trackNegParCov.getSigma1PtSnp(), + trackPosParCov.getSigma1PtTgl(), trackNegParCov.getSigma1PtTgl(), + trackPosParCov.getSigma1Pt2(), trackNegParCov.getSigma1Pt2()); + fillHfReducedCollision = true; + } + } // candsJpsi loop + + if (!fillHfReducedCollision) { + registry.fill(HIST("hEvents"), 1 + Event::NoCharmHadPiSelected); + return; + } + registry.fill(HIST("hEvents"), 1 + Event::CharmHadPiSelected); + // fill collision table if it contains a J/Psi K pair at minimum + hfReducedCollision(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), hfRejMap, bz); + hfReducedCollExtra(collision.covXX(), collision.covXY(), collision.covYY(), + collision.covXZ(), collision.covYZ(), collision.covZZ()); + // hfReducedCollCentrality(collision.centFT0C(), collision.centFT0M(), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); // TODO: add + // 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()); + // } + } + + void processJpsiKData(soa::Join const& collisions, + aod::HfCand2ProngWPid const& candsJpsi, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBplus(invMassWindowJpsiHad.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 candsJpsiThisColl = candsJpsi.sliceBy(candsJpsiPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsJpsiThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorJpsiHadReduced, processJpsiKData, "Process J/Psi K without MC info", true); + + void processJpsiPhiData(soa::Join const& collisions, + aod::HfCand2ProngWPid const& candsJpsi, + aod::TrackAssoc const& trackIndices, + TracksPidWithSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + // store configurables needed for B0 workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBs(invMassWindowJpsiHad.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 candsJpsiThisColl = candsJpsi.sliceBy(candsJpsiPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + runDataCreation(collision, candsJpsiThisColl, trackIdsThisCollision, tracks, tracks, -1, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + } + PROCESS_SWITCH(HfDataCreatorJpsiHadReduced, processJpsiPhiData, "Process J/Psi phi without MC info", false); + + void processJpsiKMc(CollisionsWCMcLabels const& collisions, + aod::HfCand2ProngWPid const& candsJpsi, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for B+ workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBplus(invMassWindowJpsiHad.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 candsJpsiThisColl = candsJpsi.sliceBy(candsJpsiPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsJpsiThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorJpsiHadReduced, processJpsiKMc, "Process J/Psi K with MC info", false); + + void processJpsiPhiMc(CollisionsWCMcLabels const& collisions, + aod::HfCand2ProngWPid const& candsJpsi, + aod::TrackAssoc const& trackIndices, + TracksPidWithSelAndMc const& tracks, + aod::McParticles const& particlesMc, + BCsInfo const& bcs, + McCollisions const& mcCollisions) + { + // store configurables needed for B+ workflow + if (!isHfCandBhadConfigFilled) { + rowCandidateConfigBs(invMassWindowJpsiHad.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 candsJpsiThisColl = candsJpsi.sliceBy(candsJpsiPerCollision, thisCollId); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + auto collsSameMcCollision = collisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + int64_t const indexCollisionMaxNumContrib = getIndexCollisionMaxNumContrib(collsSameMcCollision); + runDataCreation(collision, candsJpsiThisColl, trackIdsThisCollision, tracks, particlesMc, indexCollisionMaxNumContrib, bcs); + } + // handle normalization by the right number of collisions + hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); + for (const auto& mcCollision : mcCollisions) { + runMcGen(mcCollision, particlesMc, collisions, bcs); + } + } + PROCESS_SWITCH(HfDataCreatorJpsiHadReduced, processJpsiPhiMc, "Process J/Psi phi with MC info", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index d9f203b5f2d..acaedd2911c 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -29,29 +29,64 @@ o2physics_add_dpl_workflow(task-bplus-reduced PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-bplus-to-jpsi-k-reduced + SOURCES taskBplusToJpsiKReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + 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-to-jpsi-phi-reduced + SOURCES taskBsToJpsiPhiReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + 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-cd + SOURCES taskCd.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-to-d-v0-reduced + SOURCES taskCharmResoToDV0Reduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-charm-reso-to-d-trk-reduced + SOURCES taskCharmResoToDTrkReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + 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 + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-ds SOURCES taskDs.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-dstar-to-d0-pi @@ -61,7 +96,7 @@ o2physics_add_dpl_workflow(task-dstar-to-d0-pi o2physics_add_dpl_workflow(task-flow-charm-hadrons SOURCES taskFlowCharmHadrons.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-lb @@ -69,9 +104,14 @@ o2physics_add_dpl_workflow(task-lb PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-lb-reduced + SOURCES taskLbReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-lc SOURCES taskLc.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-lc-to-k0s-p @@ -79,6 +119,11 @@ 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 @@ -103,3 +148,8 @@ o2physics_add_dpl_workflow(task-xicc SOURCES taskXicc.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-xic0-to-xi-pi + SOURCES taskXic0ToXiPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGHF/D2H/Tasks/taskB0.cxx b/PWGHF/D2H/Tasks/taskB0.cxx index 43025a47f6b..4fe85452d27 100644 --- a/PWGHF/D2H/Tasks/taskB0.cxx +++ b/PWGHF/D2H/Tasks/taskB0.cxx @@ -14,22 +14,43 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_decay::hf_cand_beauty; /// B0 analysis task struct HfTaskB0 { @@ -44,7 +65,6 @@ struct HfTaskB0 { // O2DatabasePDG service Service pdg; - HfHelper hfHelper; using TracksWithSel = soa::Join; @@ -128,15 +148,15 @@ struct HfTaskB0 { registry.add("hPtGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}); if (checkDecayTypeMc) { - constexpr uint8_t kNBinsDecayTypeMc = hf_cand_b0::DecayTypeMc::NDecayTypeMc; - TString labels[kNBinsDecayTypeMc]; + constexpr uint8_t NBinsDecayTypeMc = hf_cand_b0::DecayTypeMc::NDecayTypeMc; // FIXME + TString labels[NBinsDecayTypeMc]; labels[hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi] = "B^{0} #rightarrow (D^{#minus} #rightarrow #pi^{#minus} K^{#plus} #pi^{#minus}) #pi^{#plus}"; labels[hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi] = "B^{0} #rightarrow (D^{#minus}_{s} #rightarrow K^{#minus} K^{#plus} #pi^{#minus}) #pi^{#plus}"; labels[hf_cand_b0::DecayTypeMc::PartlyRecoDecay] = "Partly reconstructed decay channel"; labels[hf_cand_b0::DecayTypeMc::OtherDecay] = "Other decays"; - static const AxisSpec axisDecayType = {kNBinsDecayTypeMc, 0.5, kNBinsDecayTypeMc + 0.5, ""}; + static const AxisSpec axisDecayType = {NBinsDecayTypeMc, 0.5, NBinsDecayTypeMc + 0.5, ""}; registry.add("hDecayTypeMc", "DecayType", {HistType::kTH3F, {axisDecayType, axisMassB0, axisPt}}); - for (uint8_t iBin = 0; iBin < kNBinsDecayTypeMc; ++iBin) { + for (uint8_t iBin = 0; iBin < NBinsDecayTypeMc; ++iBin) { registry.get(HIST("hDecayTypeMc"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin]); } } @@ -157,7 +177,7 @@ struct HfTaskB0 { TracksWithSel const&) { for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } @@ -166,7 +186,7 @@ struct HfTaskB0 { auto ptCandB0 = candidate.pt(); - registry.fill(HIST("hMass"), hfHelper.invMassB0ToDPi(candidate), ptCandB0); + registry.fill(HIST("hMass"), HfHelper::invMassB0ToDPi(candidate), ptCandB0); registry.fill(HIST("hPtCand"), ptCandB0); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); registry.fill(HIST("hPtProng1"), candidate.ptProng1()); @@ -177,14 +197,14 @@ struct HfTaskB0 { registry.fill(HIST("hd0Prong1"), candidate.impactParameter1(), ptCandB0); registry.fill(HIST("hCPA"), candidate.cpa(), ptCandB0); registry.fill(HIST("hEta"), candidate.eta(), ptCandB0); - registry.fill(HIST("hRapidity"), hfHelper.yB0(candidate), ptCandB0); + registry.fill(HIST("hRapidity"), HfHelper::yB0(candidate), ptCandB0); registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter0(), ptCandB0); registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter1(), ptCandB0); registry.fill(HIST("hDecLenErr"), candidate.errorDecayLength(), ptCandB0); registry.fill(HIST("hDecLenXYErr"), candidate.errorDecayLengthXY(), ptCandB0); - registry.fill(HIST("hInvMassD"), hfHelper.invMassDplusToPiKPi(candD), ptCandB0); + registry.fill(HIST("hInvMassD"), HfHelper::invMassDplusToPiKPi(candD), ptCandB0); } // candidate loop - } // process + } // process /// B0 MC analysis and fill histograms void processMc(soa::Filtered> const& candidates, @@ -194,16 +214,16 @@ struct HfTaskB0 { { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } auto ptCandB0 = candidate.pt(); auto candD = candidate.prong0_as>(); - auto invMassCandB0 = hfHelper.invMassB0ToDPi(candidate); - int flagMcMatchRecB0 = std::abs(candidate.flagMcMatchRec()); + auto invMassCandB0 = HfHelper::invMassB0ToDPi(candidate); + auto flagMcMatchRecB0 = std::abs(candidate.flagMcMatchRec()); - if (TESTBIT(flagMcMatchRecB0, hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi)) { + if (flagMcMatchRecB0 == DecayChannelMain::B0ToDminusPi) { auto indexMother = RecoDecay::getMother(mcParticles, candidate.prong1_as().mcParticle_as>(), o2::constants::physics::Pdg::kB0, true); auto particleMother = mcParticles.rawIteratorAt(indexMother); @@ -212,10 +232,10 @@ struct HfTaskB0 { registry.fill(HIST("hCPARecSig"), candidate.cpa(), ptCandB0); registry.fill(HIST("hCPAxyRecSig"), candidate.cpaXY(), ptCandB0); registry.fill(HIST("hEtaRecSig"), candidate.eta(), ptCandB0); - registry.fill(HIST("hRapidityRecSig"), hfHelper.yB0(candidate), ptCandB0); + registry.fill(HIST("hRapidityRecSig"), HfHelper::yB0(candidate), ptCandB0); registry.fill(HIST("hDecLengthRecSig"), candidate.decayLength(), ptCandB0); registry.fill(HIST("hDecLengthXYRecSig"), candidate.decayLengthXY(), ptCandB0); - registry.fill(HIST("hMassRecSig"), hfHelper.invMassB0ToDPi(candidate), ptCandB0); + registry.fill(HIST("hMassRecSig"), HfHelper::invMassB0ToDPi(candidate), ptCandB0); registry.fill(HIST("hd0Prong0RecSig"), candidate.impactParameter0(), ptCandB0); registry.fill(HIST("hd0Prong1RecSig"), candidate.impactParameter1(), ptCandB0); registry.fill(HIST("hPtProng0RecSig"), candidate.ptProng0(), ptCandB0); @@ -234,10 +254,10 @@ struct HfTaskB0 { registry.fill(HIST("hCPARecBg"), candidate.cpa(), ptCandB0); registry.fill(HIST("hCPAxyRecBg"), candidate.cpaXY(), ptCandB0); registry.fill(HIST("hEtaRecBg"), candidate.eta(), ptCandB0); - registry.fill(HIST("hRapidityRecBg"), hfHelper.yB0(candidate), ptCandB0); + registry.fill(HIST("hRapidityRecBg"), HfHelper::yB0(candidate), ptCandB0); registry.fill(HIST("hDecLengthRecBg"), candidate.decayLength(), ptCandB0); registry.fill(HIST("hDecLengthXYRecBg"), candidate.decayLengthXY(), ptCandB0); - registry.fill(HIST("hMassRecBg"), hfHelper.invMassB0ToDPi(candidate), ptCandB0); + registry.fill(HIST("hMassRecBg"), HfHelper::invMassB0ToDPi(candidate), ptCandB0); registry.fill(HIST("hd0Prong0RecBg"), candidate.impactParameter0(), ptCandB0); registry.fill(HIST("hd0Prong1RecBg"), candidate.impactParameter1(), ptCandB0); registry.fill(HIST("hPtProng0RecBg"), candidate.ptProng0(), ptCandB0); @@ -249,9 +269,9 @@ struct HfTaskB0 { registry.fill(HIST("hChi2PCARecBg"), candidate.chi2PCA(), ptCandB0); if (checkDecayTypeMc) { - if (TESTBIT(flagMcMatchRecB0, hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi)) { // B0 → Ds- π+ → (K- K+ π-) π+ + if (flagMcMatchRecB0 == DecayChannelMain::B0ToDsPi) { // B0 → Ds- π+ → (K- K+ π-) π+ registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi, invMassCandB0, ptCandB0); - } else if (TESTBIT(flagMcMatchRecB0, hf_cand_b0::DecayTypeMc::PartlyRecoDecay)) { // Partly reconstructed decay channel + } else if (flagMcMatchRecB0 == hf_cand_b0::DecayTypeMc::PartlyRecoDecay) { // FIXME, Partly reconstructed decay channel registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_b0::DecayTypeMc::PartlyRecoDecay, invMassCandB0, ptCandB0); } else { registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_b0::DecayTypeMc::OtherDecay, invMassCandB0, ptCandB0); @@ -262,7 +282,7 @@ struct HfTaskB0 { // MC gen. level for (const auto& particle : mcParticles) { - if (TESTBIT(std::abs(particle.flagMcMatchGen()), hf_cand_b0::DecayType::B0ToDPi)) { + if (std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::B0ToDminusPi) { auto ptParticle = particle.pt(); auto yParticle = RecoDecay::y(particle.pVector(), o2::constants::physics::MassB0); @@ -270,9 +290,9 @@ struct HfTaskB0 { continue; } - std::array ptProngs; - std::array yProngs; - std::array etaProngs; + std::array ptProngs{}; + std::array yProngs{}; + std::array etaProngs{}; int counter = 0; for (const auto& daught : particle.daughters_as()) { ptProngs[counter] = daught.pt(); @@ -306,7 +326,7 @@ struct HfTaskB0 { registry.fill(HIST("hEtaGenWithProngsInAcceptance"), particle.eta(), ptParticle); } } // gen - } // process + } // process PROCESS_SWITCH(HfTaskB0, processMc, "Process MC", false); }; // struct diff --git a/PWGHF/D2H/Tasks/taskB0Reduced.cxx b/PWGHF/D2H/Tasks/taskB0Reduced.cxx index 5e38055f589..5e146308c45 100644 --- a/PWGHF/D2H/Tasks/taskB0Reduced.cxx +++ b/PWGHF/D2H/Tasks/taskB0Reduced.cxx @@ -15,16 +15,32 @@ /// \author Alexandre Bigot , IPHC Strasbourg /// \author Fabrizio Grosa , 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/D2H/DataModel/ReducedDataModel.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/D2H/DataModel/ReducedDataModel.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -36,65 +52,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, 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(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::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, @@ -123,33 +190,32 @@ struct HfTaskB0Reduced { 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 TracksBachPions = soa::Join; + using CandsDplus = soa::Join; + using CandsDstar = soa::Join; + using TracksSoftPions = soa::Join; Filter filterSelectCandidates = (aod::hf_sel_candidate_b0::isSelB0ToDPi >= selectionFlagB0); HistogramRegistry registry{"registry"}; - using TracksPion = soa::Join; - void init(InitContext&) { - std::array processFuncData{doprocessData, doprocessDataWithDmesMl, doprocessDataWithB0Ml}; + std::array processFuncData{doprocessDataDplusPi, doprocessDataDplusPiWithDmesMl, doprocessDataDplusPiWithB0Ml, + doprocessDataDstarPi, doprocessDataDstarPiWithDmesMl}; 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{doprocessMcDplusPi, doprocessMcDplusPiWithDecayTypeCheck, doprocessMcDplusPiWithDmesMl, doprocessMcDplusPiWithDmesMlAndDecayTypeCheck, doprocessMcDplusPiWithB0Ml, doprocessMcDplusPiWithB0MlAndDecayTypeCheck, + doprocessMcDstarPi, doprocessMcDstarPiWithDmesMl}; 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}; + const AxisSpec axisMassDeltaMassDStar{300, 0.05f, 0.3f}; const AxisSpec axisDecayLength{200, 0.f, 0.4f}; const AxisSpec axisNormDecayLength{100, 0.f, 50.f}; const AxisSpec axisDca{100, -0.05f, 0.05f}; @@ -157,63 +223,94 @@ struct HfTaskB0Reduced { 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 axisImpParProngSqSum{100, 0, 1.e-3}; const AxisSpec axisPtB0{100, 0.f, 50.f}; const AxisSpec axisPtDminus{100, 0.f, 50.f}; const AxisSpec axisPtPi{100, 0.f, 10.f}; + const AxisSpec axisPtSoftPi{100, 0.f, 1.f}; + + std::array processFuncDplusPi = {doprocessDataDplusPi, doprocessDataDplusPiWithDmesMl, doprocessDataDplusPiWithB0Ml, + doprocessMcDplusPi, doprocessMcDplusPiWithDecayTypeCheck, doprocessMcDplusPiWithDmesMl, + doprocessMcDplusPiWithDmesMlAndDecayTypeCheck, doprocessMcDplusPiWithB0Ml, + doprocessMcDplusPiWithB0MlAndDecayTypeCheck}; + const AxisSpec axisMass = ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) ? axisMassDminus : axisMassDeltaMassDStar; + std::string dMesSpecie; + if ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) { + dMesSpecie += "D^{#minus}"; + } else { + dMesSpecie += "D^{0}#pi^{#minus}"; + } - if (doprocessData || doprocessDataWithDmesMl || doprocessDataWithB0Ml) { + if (doprocessDataDplusPi || doprocessDataDplusPiWithDmesMl || doprocessDataDplusPiWithB0Ml || doprocessDataDstarPi || doprocessDataDstarPiWithDmesMl) { if (fillHistograms) { registry.add("hMass", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{M} (D#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtB0, axisMassB0}}); registry.add("hDecLength", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtB0, axisDecayLength}}); registry.add("hDecLengthXy", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtB0, axisDecayLength}}); registry.add("hNormDecLengthXy", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtB0, axisNormDecayLength}}); - registry.add("hDcaProng0", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});prong 0 (D^{#minus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); + registry.add("hDcaProng0", Form("B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});prong 0 (%s) DCAxy to prim. vertex (cm);entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisDca}}); registry.add("hDcaProng1", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});prong 1 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); - registry.add("hPtProng0", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(D^{#minus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtDminus}}); - registry.add("hPtProng1", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); registry.add("hCosp", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtB0, axisCosp}}); registry.add("hCospXy", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtB0, axisCosp}}); registry.add("hEta", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtB0, axisEta}}); registry.add("hRapidity", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate #it{y};entries", {HistType::kTH2F, {axisPtB0, axisEta}}); - registry.add("hImpParProd", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtB0, axisImpParProd}}); - registry.add("hInvMassD", "B^{0} candidates;#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, #it{M}(K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtDminus, axisMassDminus}}); - registry.add("hDecLengthD", "B^{0} candidates;#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); - registry.add("hDecLengthXyD", "B^{0} candidates;#it{p}_{T}(D^{#minus}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); - registry.add("hCospD", "B^{0} candidates;#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtDminus, axisCosp}}); - registry.add("hCospXyD", "B^{0} candidates;#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtDminus, axisCosp}}); + registry.add("hInvMassD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});prong0, #it{M}(K#pi) (GeV/#it{c}^{2});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMass}}); + registry.add("hDecLengthD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});%s candidate decay length (cm);entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); + registry.add("hDecLengthXyD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});decay length XY (cm);entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); + registry.add("hCospD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});%s candidate cos(#vartheta_{P});entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisCosp}}); + registry.add("hCospXyD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});%s candidate cos(#vartheta_{P}^{XY});entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisCosp}}); + if ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) { + registry.add("hImpParProd", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtB0, axisImpParProd}}); + registry.add("hPtProng0", Form("B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(%s) (GeV/#it{c});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisPtDminus}}); + registry.add("hPtProng1", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); + } else { + registry.add("hImpParProngSqSum", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter sum;entries", {HistType::kTH2F, {axisPtB0, axisImpParProngSqSum}}); + registry.add("hPtProngD0", Form("B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(%s) (GeV/#it{c});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisPtDminus}}); + registry.add("hPtProngSoftPi", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtSoftPi}}); + registry.add("hPtProngBachPi", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); + registry.add("hDcaProng2", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});prong 2 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); + } // ML scores of D- daughter - if (doprocessDataWithDmesMl) { - registry.add("hMlScoreBkgD", "B^{0} candidates;#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML background score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); - registry.add("hMlScorePromptD", "B^{0} candidates;#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML prompt score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); - registry.add("hMlScoreNonPromptD", "B^{0} candidates;#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML nonprompt score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + if (doprocessDataDplusPiWithDmesMl || doprocessDataDstarPiWithDmesMl) { + registry.add("hMlScoreBkgD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML background score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + registry.add("hMlScorePromptD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML prompt score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + registry.add("hMlScoreNonPromptD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML nonprompt score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); } // ML scores of B0 candidate - if (doprocessDataWithB0Ml) { + if (doprocessDataDplusPiWithB0Ml) { registry.add("hMlScoreSigB0", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});prong0, B^{0} ML signal score;entries", {HistType::kTH2F, {axisPtB0, axisMlScore}}); } } if (fillSparses) { - if (!(doprocessDataWithDmesMl || doprocessDataWithB0Ml)) { - registry.add("hMassPtCutVars", "B^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate decay length (cm);D^{#minus} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDminus, axisPtDminus, axisDecayLength, axisCosp}}); + if (!(doprocessDataDplusPiWithDmesMl || doprocessDataDplusPiWithB0Ml || doprocessDataDstarPiWithDmesMl)) { + if ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) { + registry.add("hMassPtCutVars", "B^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate decay length (cm);%s candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMass, axisPtDminus, axisDecayLength, axisCosp}}); + } else { + registry.add("hMassPtCutVars", "B^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate decay length (cm);%s candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProngSqSum, axisCosp, axisMass, axisPtDminus, axisDecayLength, axisCosp}}); + } } else { - registry.add("hMassPtCutVars", "B^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate ML score bkg;D^{#minus} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDminus, axisPtDminus, axisMlScore, axisMlScore}}); + if ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) { + registry.add("hMassPtCutVars", "B^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate ML score bkg;%s candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMass, axisPtDminus, axisMlScore, axisMlScore}}); + } else { + registry.add("hMassPtCutVars", "B^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate ML score bkg;%s candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProngSqSum, axisCosp, axisMass, axisPtDminus, axisMlScore, axisMlScore}}); + } } } } - if (doprocessMc || doprocessMcWithDecayTypeCheck || doprocessMcWithDmesMl || doprocessMcWithB0Ml || doprocessMcWithB0MlAndDecayTypeCheck) { + if (doprocessMcDplusPi || doprocessMcDplusPiWithDecayTypeCheck || doprocessMcDplusPiWithDmesMl || doprocessMcDplusPiWithDmesMlAndDecayTypeCheck || doprocessMcDplusPiWithB0Ml || doprocessMcDplusPiWithB0MlAndDecayTypeCheck || + doprocessMcDstarPi || doprocessMcDstarPiWithDmesMl) { 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}}); registry.add("hYGen", "B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{y}^{gen}(B^{0});entries", {HistType::kTH2F, {axisPtB0, axisEta}}); registry.add("hYGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{y}^{gen}(B^{0});entries", {HistType::kTH2F, {axisPtB0, axisEta}}); - registry.add("hPtProng0Gen", "B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{p}_{T}^{gen}(D^{#minus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtDminus}}); + registry.add("hPtProng0Gen", Form("B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{p}_{T}^{gen}(%s) (GeV/#it{c});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisPtDminus}}); registry.add("hPtProng1Gen", "B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{p}_{T}^{gen}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); - registry.add("hYProng0Gen", "B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{y}^{gen}(D^{#minus});entries", {HistType::kTH2F, {axisPtB0, axisEta}}); + registry.add("hYProng0Gen", Form("B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{y}^{gen}(%s);entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisEta}}); registry.add("hYProng1Gen", "B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{y}^{gen}(#pi^{#plus});entries", {HistType::kTH2F, {axisPtB0, axisEta}}); - registry.add("hEtaProng0Gen", "B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{#eta}^{gen}(D^{#minus});entries", {HistType::kTH2F, {axisPtB0, axisEta}}); + registry.add("hEtaProng0Gen", Form("B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{#eta}^{gen}(%s);entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisEta}}); registry.add("hEtaProng1Gen", "B^{0} particles (generated);#it{p}_{T}^{gen}(B^{0}) (GeV/#it{c});#it{#eta}^{gen}(#pi^{#plus});entries", {HistType::kTH2F, {axisPtB0, axisEta}}); // reco histos @@ -222,47 +319,68 @@ struct HfTaskB0Reduced { registry.add("hDecLengthRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtB0, axisDecayLength}}); registry.add("hDecLengthXyRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtB0, axisDecayLength}}); registry.add("hNormDecLengthXyRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtB0, axisNormDecayLength}}); - registry.add("hDcaProng0RecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong 0 (D^{#minus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); + registry.add("hDcaProng0RecSig", Form("B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong 0 (%s) DCAxy to prim. vertex (cm);entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisDca}}); registry.add("hDcaProng1RecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong 1 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); - registry.add("hPtProng0RecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(D^{#minus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtDminus}}); - registry.add("hPtProng1RecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); registry.add("hCospRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtB0, axisCosp}}); registry.add("hCospXyRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtB0, axisCosp}}); registry.add("hEtaRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtB0, axisEta}}); registry.add("hRapidityRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate #it{y};entries", {HistType::kTH2F, {axisPtB0, axisEta}}); - registry.add("hImpParProdRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtB0, axisImpParProd}}); - registry.add("hInvMassDRecSig", "B^{0} candidates (matched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, #it{M}(K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtDminus, axisMassDminus}}); - registry.add("hDecLengthDRecSig", "B^{0} candidates (matched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); - registry.add("hDecLengthXyDRecSig", "B^{0} candidates (matched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); - registry.add("hCospDRecSig", "B^{0} candidates (matched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtDminus, axisCosp}}); - registry.add("hCospXyDRecSig", "B^{0} candidates (matched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtDminus, axisCosp}}); + registry.add("hInvMassDRecSig", Form("B^{0} candidates (matched);#it{p}_{T}(%s) (GeV/#it{c});prong0, #it{M}(K#pi) (GeV/#it{c}^{2});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMass}}); + registry.add("hDecLengthDRecSig", Form("B^{0} candidates (matched);#it{p}_{T}(%s) (GeV/#it{c});%s candidate decay length (cm);entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); + registry.add("hDecLengthXyDRecSig", Form("B^{0} candidates (matched);#it{p}_{T}(%s) (GeV/#it{c});decay length XY (cm);entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); + registry.add("hCospDRecSig", Form("B^{0} candidates (matched);#it{p}_{T}(%s) (GeV/#it{c});%s candidate cos(#vartheta_{P});entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisCosp}}); + registry.add("hCospXyDRecSig", Form("B^{0} candidates (matched);#it{p}_{T}(%s) (GeV/#it{c});%s candidate cos(#vartheta_{P}^{XY});entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisCosp}}); + + if ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) { + registry.add("hPtProng0RecSig", Form("B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(%s) (GeV/#it{c});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisPtDminus}}); + registry.add("hPtProng1RecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); + registry.add("hImpParProdRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtB0, axisImpParProd}}); + } else { + registry.add("hPtProngD0RecSig", Form("B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(%s) (GeV/#it{c});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisPtDminus}}); + registry.add("hPtProngSoftPiRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtSoftPi}}); + registry.add("hPtProngBachPiRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); + registry.add("hDcaProng2RecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong 2 (#pi^{#minus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); + registry.add("hImpParProngSqSumRecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtB0, axisImpParProngSqSum}}); + } + // background if (fillBackground) { registry.add("hMassRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{M} (D#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtB0, axisMassB0}}); registry.add("hDecLengthRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtB0, axisDecayLength}}); registry.add("hDecLengthXyRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtB0, axisDecayLength}}); registry.add("hNormDecLengthXyRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtB0, axisNormDecayLength}}); - registry.add("hDcaProng0RecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong 0 (D^{#minus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); + registry.add("hDcaProng0RecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong 0 (%s) DCAxy to prim. vertex (cm);entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisDca}}); registry.add("hDcaProng1RecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong 1 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); - registry.add("hPtProng0RecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(D^{#minus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtDminus}}); - registry.add("hPtProng1RecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); registry.add("hCospRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtB0, axisCosp}}); registry.add("hCospXyRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtB0, axisCosp}}); registry.add("hEtaRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtB0, axisEta}}); registry.add("hRapidityRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate #it{y};entries", {HistType::kTH2F, {axisPtB0, axisEta}}); - registry.add("hImpParProdRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtB0, axisImpParProd}}); - registry.add("hInvMassDRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, #it{M}(K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtDminus, axisMassDminus}}); - registry.add("hDecLengthDRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); - registry.add("hDecLengthXyDRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); - registry.add("hCospDRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtDminus, axisCosp}}); - 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}}); + registry.add("hInvMassDRecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(%s) (GeV/#it{c});prong0, #it{M}(K#pi) (GeV/#it{c}^{2});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMass}}); + registry.add("hDecLengthDRecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(%s) (GeV/#it{c});%s candidate decay length (cm);entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); + registry.add("hDecLengthXyDRecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(%s) (GeV/#it{c});decay length XY (cm);entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisDecayLength}}); + registry.add("hCospDRecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(%s) (GeV/#it{c});%s candidate cos(#vartheta_{P});entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisCosp}}); + registry.add("hCospXyDRecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(%s) (GeV/#it{c});%s candidate cos(#vartheta_{P}^{XY});entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisCosp}}); + + if ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) { + registry.add("hPtProng0RecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(%s) (GeV/#it{c});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisPtDminus}}); + registry.add("hPtProng1RecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); + registry.add("hImpParProdRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtB0, axisImpParProd}}); + } else { + registry.add("hPtProngD0RecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(%s) (GeV/#it{c});entries", dMesSpecie.c_str()), {HistType::kTH2F, {axisPtB0, axisPtDminus}}); + registry.add("hPtProngSoftPiRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtSoftPi}}); + registry.add("hPtProngBachPiRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtB0, axisPtPi}}); + registry.add("hImpParProngSqSumRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtB0, axisImpParProngSqSum}}); + registry.add("hDcaProng2RecBg", "B^{0} candidates (unmatched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong 2 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); + } } // MC checks - if (doprocessMcWithDecayTypeCheck || doprocessMcWithB0MlAndDecayTypeCheck) { + if (doprocessMcDplusPiWithDecayTypeCheck || doprocessMcDplusPiWithB0MlAndDecayTypeCheck || doprocessMcDplusPiWithDmesMlAndDecayTypeCheck) { 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}"; - labels[hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi] = "B^{0} #rightarrow (D^{#minus}_{s} #rightarrow K^{#minus} K^{#plus} #pi^{#minus}) #pi^{#plus}"; + labels[hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi] = Form("B^{0} #rightarrow (%s #rightarrow #pi^{#minus} K^{#plus} #pi^{#minus}) #pi^{#plus}", dMesSpecie.c_str()); + labels[hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi] = Form("B^{0} #rightarrow (%s_{s} #rightarrow K^{#minus} K^{#plus} #pi^{#minus}) #pi^{#plus}", dMesSpecie.c_str()); + labels[hf_cand_b0::DecayTypeMc::BsToDsPiToKKPiPi] = Form("B_{s}^{0} #rightarrow (%s_{s} #rightarrow K^{#minus} K^{#plus} #pi^{#minus}) #pi^{#plus}", dMesSpecie.c_str()); + labels[hf_cand_b0::DecayTypeMc::B0ToDplusKToPiKPiK] = Form("B^{0} #rightarrow (%s #rightarrow #pi^{#minus} K^{#plus} #pi^{#minus}) K^{#plus}", dMesSpecie.c_str()); labels[hf_cand_b0::DecayTypeMc::PartlyRecoDecay] = "Partly reconstructed decay channel"; labels[hf_cand_b0::DecayTypeMc::OtherDecay] = "Other decays"; static const AxisSpec axisDecayType = {kNBinsDecayTypeMc, 0.5, kNBinsDecayTypeMc + 0.5, ""}; @@ -272,18 +390,18 @@ struct HfTaskB0Reduced { } } // ML scores of D- daughter - if (doprocessMcWithDmesMl) { + if (doprocessMcDplusPiWithDmesMl || doprocessMcDplusPiWithDmesMlAndDecayTypeCheck || doprocessMcDstarPiWithDmesMl) { // 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}}); - registry.add("hMlScoreNonPromptDRecSig", "B^{0} candidates (matched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML nonprompt score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + registry.add("hMlScoreBkgDRecSig", Form("B^{0} candidates (matched);#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML background score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + registry.add("hMlScorePromptDRecSig", Form("B^{0} candidates (matched);#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML prompt score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + registry.add("hMlScoreNonPromptDRecSig", Form("B^{0} candidates (matched);#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML nonprompt score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); // background - registry.add("hMlScoreBkgDRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML background score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); - registry.add("hMlScorePromptDRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML prompt score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); - registry.add("hMlScoreNonPromptDRecBg", "B^{0} candidates (unmatched);#it{p}_{T}(D^{#minus}) (GeV/#it{c});prong0, D^{#minus} ML nonprompt score;entries", {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + registry.add("hMlScoreBkgDRecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML background score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + registry.add("hMlScorePromptDRecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML prompt score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); + registry.add("hMlScoreNonPromptDRecBg", Form("B^{0} candidates (unmatched);#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML nonprompt score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); } // ML scores of B0 candidate - if (doprocessMcWithB0Ml || doprocessMcWithB0MlAndDecayTypeCheck) { + if (doprocessMcDplusPiWithB0Ml || doprocessMcDplusPiWithB0MlAndDecayTypeCheck) { // signal registry.add("hMlScoreSigB0RecSig", "B^{0} candidates (matched);#it{p}_{T}(B^{0}) (GeV/#it{c});prong0, B^{0} ML signal score;entries", {HistType::kTH2F, {axisPtB0, axisMlScore}}); // background @@ -296,15 +414,15 @@ struct HfTaskB0Reduced { registry.add("hPtYWithProngsInAccepanceGenSig", "B^{0} particles (generated-daughters in acceptance);#it{p}_{T}(B^{0}) (GeV/#it{c});#it{y}(B^{0})", {HistType::kTHnSparseF, {axisPtB0, axisEta}}); // reco sparses - if (!(doprocessDataWithDmesMl || doprocessDataWithB0Ml)) { - registry.add("hMassPtCutVarsRecSig", "B^{0} candidates (matched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate decay length (cm);D^{#minus} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDminus, axisPtDminus, axisDecayLength, axisCosp}}); + if (!(doprocessDataDplusPiWithDmesMl || doprocessDataDplusPiWithB0Ml || doprocessDataDstarPiWithDmesMl)) { + registry.add("hMassPtCutVarsRecSig", Form("B^{0} candidates (matched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate decay length (cm);%s candidate cos(#vartheta_{P})", dMesSpecie.c_str(), dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMass, axisPtDminus, axisDecayLength, axisCosp}}); if (fillBackground) { - registry.add("hMassPtCutVarsRecBg", "B^{0} candidates (unmatched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate decay length (cm);D^{#minus} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDminus, axisPtDminus, axisDecayLength, axisCosp}}); + registry.add("hMassPtCutVarsRecBg", Form("B^{0} candidates (unmatched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate decay length (cm);%s candidate cos(#vartheta_{P})", dMesSpecie.c_str(), dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMass, axisPtDminus, axisDecayLength, axisCosp}}); } } else { - registry.add("hMassPtCutVarsRecSig", "B^{0} candidates (matched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate ML score bkg;D^{#minus} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDminus, axisPtDminus, axisMlScore, axisMlScore}}); + registry.add("hMassPtCutVarsRecSig", Form("B^{0} candidates (matched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate ML score bkg;%s candidate ML score nonprompt", dMesSpecie.c_str(), dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMass, axisPtDminus, axisMlScore, axisMlScore}}); if (fillBackground) { - registry.add("hMassPtCutVarsRecBg", "B^{0} candidates (unmatched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(D^{#minus}) (GeV/#it{c});D^{#minus} candidate ML score bkg;D^{#minus} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassDminus, axisPtDminus, axisMlScore, axisMlScore}}); + registry.add("hMassPtCutVarsRecBg", Form("B^{0} candidates (unmatched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate ML score bkg;%s candidate ML score nonprompt", dMesSpecie.c_str(), dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMass, axisPtDminus, axisMlScore, axisMlScore}}); } } } @@ -328,34 +446,274 @@ 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 fillCandDStarPi(Cand const& candidate, + SoftPions const& softPions, + CandsDmes const&) + { + auto ptCandB0 = candidate.pt(); + auto invMassB0 = HfHelper::invMassB0ToDPi(candidate); + auto candD = candidate.template prongD0_as(); + auto ptD = candidate.ptProng0(); + auto invMassD = candD.invMassHypo0(); + auto softPi = softPions.rawIteratorAt(candD.globalIndex()); + std::array const posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; + std::array const posSvD{candD.xSecondaryVertex(), candD.ySecondaryVertex(), candD.zSecondaryVertex()}; + std::array const momD{candD.pVector()}; + auto cospD = RecoDecay::cpa(posPv, posSvD, momD); + auto cospXyD = RecoDecay::cpaXY(posPv, posSvD, momD); + auto decLenD = RecoDecay::distance(posPv, posSvD); + 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::B0ToDstarPiToD0PiPiToKPiPiPi); + } + + if (fillHistograms) { + if constexpr (DoMc) { + if (isSignal) { + registry.fill(HIST("hMassRecSig"), ptCandB0, HfHelper::invMassB0ToDPi(candidate)); + registry.fill(HIST("hPtProngD0RecSig"), ptCandB0, candidate.ptProng0()); + registry.fill(HIST("hPtProngSoftPiRecSig"), ptCandB0, candidate.ptProng1()); + registry.fill(HIST("hPtProngBachPiRecSig"), ptCandB0, candidate.ptProng2()); + registry.fill(HIST("hImpParProngSqSumRecSig"), ptCandB0, candidate.impactParameterProngSqSum()); + registry.fill(HIST("hDecLengthRecSig"), ptCandB0, candidate.decayLength()); + registry.fill(HIST("hDecLengthXyRecSig"), ptCandB0, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXyRecSig"), ptCandB0, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hDcaProng0RecSig"), ptCandB0, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1RecSig"), ptCandB0, candidate.impactParameter1()); + registry.fill(HIST("hDcaProng2RecSig"), ptCandB0, candidate.impactParameter2()); + registry.fill(HIST("hCospRecSig"), ptCandB0, candidate.cpa()); + registry.fill(HIST("hCospXyRecSig"), ptCandB0, candidate.cpaXY()); + registry.fill(HIST("hEtaRecSig"), ptCandB0, candidate.eta()); + registry.fill(HIST("hRapidityRecSig"), ptCandB0, HfHelper::yB0(candidate)); + registry.fill(HIST("hInvMassDRecSig"), ptD, invMassD); + registry.fill(HIST("hDecLengthDRecSig"), ptD, decLenD); + registry.fill(HIST("hDecLengthXyDRecSig"), ptD, decLenXyD); + registry.fill(HIST("hCospDRecSig"), ptD, cospD); + registry.fill(HIST("hCospXyDRecSig"), ptD, cospXyD); + if constexpr (WithDmesMl) { + registry.fill(HIST("hMlScoreBkgDRecSig"), ptD, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptDRecSig"), ptD, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptDRecSig"), ptD, candidate.prong0MlScoreNonprompt()); + } + } else if (fillBackground) { + registry.fill(HIST("hMassRecBg"), ptCandB0, HfHelper::invMassB0ToDPi(candidate)); + registry.fill(HIST("hPtProngD0RecBg"), ptCandB0, candidate.ptProng0()); + registry.fill(HIST("hPtProngSoftPiRecBg"), ptCandB0, candidate.ptProng1()); + registry.fill(HIST("hPtProngBachPiRecBg"), ptCandB0, candidate.ptProng2()); + registry.fill(HIST("hImpParProngSqSumRecBg"), ptCandB0, candidate.impactParameterProngSqSum()); + registry.fill(HIST("hDecLengthRecBg"), ptCandB0, candidate.decayLength()); + registry.fill(HIST("hDecLengthXyRecBg"), ptCandB0, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXyRecBg"), ptCandB0, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hDcaProng0RecBg"), ptCandB0, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1RecBg"), ptCandB0, candidate.impactParameter1()); + registry.fill(HIST("hDcaProng2RecBg"), ptCandB0, candidate.impactParameter2()); + registry.fill(HIST("hCospRecBg"), ptCandB0, candidate.cpa()); + registry.fill(HIST("hCospXyRecBg"), ptCandB0, candidate.cpaXY()); + registry.fill(HIST("hEtaRecBg"), ptCandB0, candidate.eta()); + registry.fill(HIST("hRapidityRecBg"), ptCandB0, HfHelper::yB0(candidate)); + registry.fill(HIST("hInvMassDRecBg"), ptD, invMassD); + registry.fill(HIST("hDecLengthDRecBg"), ptD, decLenD); + registry.fill(HIST("hDecLengthXyDRecBg"), ptD, decLenXyD); + registry.fill(HIST("hCospDRecBg"), ptD, cospD); + registry.fill(HIST("hCospXyDRecBg"), ptD, cospXyD); + if constexpr (WithDmesMl) { + registry.fill(HIST("hMlScoreBkgDRecBg"), ptD, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptDRecBg"), ptD, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptDRecBg"), ptD, candidate.prong0MlScoreNonprompt()); + } + } + } else { + registry.fill(HIST("hMass"), ptCandB0, invMassB0); + registry.fill(HIST("hPtProngD0"), ptCandB0, candidate.ptProng0()); + registry.fill(HIST("hPtProngSoftPi"), ptCandB0, candidate.ptProng1()); + registry.fill(HIST("hPtProngBachPi"), ptCandB0, candidate.ptProng2()); + registry.fill(HIST("hDecLength"), ptCandB0, candidate.decayLength()); + registry.fill(HIST("hDecLengthXy"), ptCandB0, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXy"), ptCandB0, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hImpParProngSqSum"), ptCandB0, candidate.impactParameterProngSqSum()); + registry.fill(HIST("hDcaProng0"), ptCandB0, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1"), ptCandB0, candidate.impactParameter1()); + registry.fill(HIST("hDcaProng2"), ptCandB0, candidate.impactParameter2()); + registry.fill(HIST("hCosp"), ptCandB0, candidate.cpa()); + registry.fill(HIST("hCospXy"), ptCandB0, candidate.cpaXY()); + registry.fill(HIST("hEta"), ptCandB0, candidate.eta()); + registry.fill(HIST("hRapidity"), ptCandB0, HfHelper::yB0(candidate)); + registry.fill(HIST("hInvMassD"), ptD, invMassD); + registry.fill(HIST("hDecLengthD"), ptD, decLenD); + registry.fill(HIST("hDecLengthXyD"), ptD, decLenXyD); + registry.fill(HIST("hCospD"), ptD, cospD); + registry.fill(HIST("hCospXyD"), ptD, cospXyD); + + if constexpr (WithDmesMl) { + registry.fill(HIST("hMlScoreBkgD"), ptD, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptD"), ptD, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptD"), ptD, candidate.prong0MlScoreNonprompt()); + } + } + } + if (fillSparses) { + if constexpr (DoMc) { + if (isSignal) { + if constexpr (WithDmesMl) { + registry.fill(HIST("hMassPtCutVarsRecSig"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProngSqSum(), candidate.cpa(), invMassD, ptD, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVarsRecSig"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProngSqSum(), candidate.cpa(), invMassD, ptD, decLenD, cospD); + } + } else if (fillBackground) { + if constexpr (WithDmesMl) { + registry.fill(HIST("hMassPtCutVarsRecBg"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProngSqSum(), candidate.cpa(), invMassD, ptD, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVarsRecBg"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProngSqSum(), candidate.cpa(), invMassD, ptD, decLenD, cospD); + } + } + } else { + if constexpr (WithDmesMl) { + registry.fill(HIST("hMassPtCutVars"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProngSqSum(), candidate.cpa(), invMassD, ptD, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVars"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProngSqSum(), candidate.cpa(), invMassD, ptD, decLenD, cospD); + } + } + } + if (fillTree) { + float const pseudoRndm = ptD * 1000. - static_cast(ptD * 1000); + if (flagMcMatchRec != 0 || (((DoMc && fillBackground) || !DoMc) && (ptCandB0 >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor))) { + float prong0MlScoreBkg = -1.; + float prong0MlScorePrompt = -1.; + float prong0MlScoreNonprompt = -1.; + float const candidateMlScoreSig = -1; + if constexpr (WithDmesMl) { + prong0MlScoreBkg = candidate.prong0MlScoreBkg(); + prong0MlScorePrompt = candidate.prong0MlScorePrompt(); + prong0MlScoreNonprompt = candidate.prong0MlScoreNonprompt(); + } + auto prongBachPi = candidate.template prongBachPi_as(); + + float ptMother = -1.; + if constexpr (DoMc) { + ptMother = candidate.ptMother(); + } + + 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, + decLenD, + decLenXyD, + candidate.impactParameter0(), + candD.ptProngMin(), + candD.absEtaProngMin(), + candD.itsNClsProngMin(), + candD.tpcNClsCrossedRowsProngMin(), + candD.tpcChi2NClProngMax(), + candD.tpcNSigmaPiProng0(), + candD.tofNSigmaPiProng0(), + candD.tpcTofNSigmaPiProng0(), + candD.tpcNSigmaKaProng1(), + candD.tofNSigmaKaProng1(), + candD.tpcTofNSigmaKaProng1(), + softPi.tpcNSigmaPiSoftPi(), + softPi.tofNSigmaPiSoftPi(), + softPi.tpcTofNSigmaPiSoftPi(), + prong0MlScoreBkg, + prong0MlScorePrompt, + prong0MlScoreNonprompt, + // pion features + candidate.ptProng2(), + std::abs(RecoDecay::eta(prongBachPi.pVector())), + prongBachPi.itsNCls(), + prongBachPi.tpcNClsCrossedRows(), + prongBachPi.tpcChi2NCl(), + candidate.impactParameter2(), + prongBachPi.tpcNSigmaPi(), + prongBachPi.tofNSigmaPi(), + prongBachPi.tpcTofNSigmaPi(), + // MC truth + flagMcMatchRec, + isSignal, + flagWrongCollision, + ptMother); + + if constexpr (WithDecayTypeCheck) { + hfRedB0McCheck( + flagMcMatchRec, + flagWrongCollision, + invMassD, + ptD, + invMassB0, + ptCandB0, + candidateMlScoreSig, + candidate.pdgCodeBeautyMother(), + candidate.pdgCodeCharmMother(), + candidate.pdgCodeProng0(), + candidate.pdgCodeProng1(), + candidate.pdgCodeProng2(), + candidate.pdgCodeProng3()); + } + } + } + } + + /// 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 D- daughter + /// \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 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 invMassB0 = HfHelper::invMassB0ToDPi(candidate); + auto candD = candidate.template prong0_as(); auto ptD = candidate.ptProng0(); - auto invMassD = candD.invMass(); - std::array posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; - std::array posSvD{candD.xSecondaryVertex(), candD.ySecondaryVertex(), candD.zSecondaryVertex()}; - std::array momD{candD.pVector()}; + auto invMassD = candD.invMassHypo0(); + std::array const posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; + std::array const posSvD{candD.xSecondaryVertex(), candD.ySecondaryVertex(), candD.zSecondaryVertex()}; + std::array const momD{candD.pVector()}; auto cospD = RecoDecay::cpa(posPv, posSvD, momD); auto cospXyD = RecoDecay::cpaXY(posPv, posSvD, momD); auto decLenD = RecoDecay::distance(posPv, posSvD); auto decLenXyD = RecoDecay::distanceXY(posPv, posSvD); int8_t flagMcMatchRec = 0; + int8_t flagWrongCollision = 0; bool isSignal = false; - if constexpr (doMc) { + if constexpr (DoMc) { flagMcMatchRec = candidate.flagMcMatchRec(); + flagWrongCollision = candidate.flagWrongCollision(); isSignal = TESTBIT(std::abs(flagMcMatchRec), hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi); } if (fillHistograms) { - if constexpr (doMc) { + if constexpr (DoMc) { if (isSignal) { - registry.fill(HIST("hMassRecSig"), ptCandB0, hfHelper.invMassB0ToDPi(candidate)); + registry.fill(HIST("hMassRecSig"), ptCandB0, HfHelper::invMassB0ToDPi(candidate)); registry.fill(HIST("hPtProng0RecSig"), ptCandB0, candidate.ptProng0()); registry.fill(HIST("hPtProng1RecSig"), ptCandB0, candidate.ptProng1()); registry.fill(HIST("hImpParProdRecSig"), ptCandB0, candidate.impactParameterProduct()); @@ -367,25 +725,25 @@ struct HfTaskB0Reduced { registry.fill(HIST("hCospRecSig"), ptCandB0, candidate.cpa()); registry.fill(HIST("hCospXyRecSig"), ptCandB0, candidate.cpaXY()); registry.fill(HIST("hEtaRecSig"), ptCandB0, candidate.eta()); - registry.fill(HIST("hRapidityRecSig"), ptCandB0, hfHelper.yB0(candidate)); + registry.fill(HIST("hRapidityRecSig"), ptCandB0, HfHelper::yB0(candidate)); registry.fill(HIST("hInvMassDRecSig"), ptD, invMassD); registry.fill(HIST("hDecLengthDRecSig"), ptD, decLenD); registry.fill(HIST("hDecLengthXyDRecSig"), ptD, decLenXyD); registry.fill(HIST("hCospDRecSig"), ptD, cospD); registry.fill(HIST("hCospXyDRecSig"), ptD, cospXyD); - if constexpr (withDecayTypeCheck) { + if constexpr (WithDecayTypeCheck) { registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi, invMassB0, ptCandB0); } - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { registry.fill(HIST("hMlScoreBkgDRecSig"), ptD, candidate.prong0MlScoreBkg()); registry.fill(HIST("hMlScorePromptDRecSig"), ptD, candidate.prong0MlScorePrompt()); registry.fill(HIST("hMlScoreNonPromptDRecSig"), ptD, candidate.prong0MlScoreNonprompt()); } - if constexpr (withB0Ml) { + if constexpr (WithB0Ml) { registry.fill(HIST("hMlScoreSigB0RecSig"), ptCandB0, candidate.mlProbB0ToDPi()); } } else if (fillBackground) { - registry.fill(HIST("hMassRecBg"), ptCandB0, hfHelper.invMassB0ToDPi(candidate)); + registry.fill(HIST("hMassRecBg"), ptCandB0, HfHelper::invMassB0ToDPi(candidate)); registry.fill(HIST("hPtProng0RecBg"), ptCandB0, candidate.ptProng0()); registry.fill(HIST("hPtProng1RecBg"), ptCandB0, candidate.ptProng1()); registry.fill(HIST("hImpParProdRecBg"), ptCandB0, candidate.impactParameterProduct()); @@ -397,23 +755,27 @@ struct HfTaskB0Reduced { registry.fill(HIST("hCospRecBg"), ptCandB0, candidate.cpa()); registry.fill(HIST("hCospXyRecBg"), ptCandB0, candidate.cpaXY()); registry.fill(HIST("hEtaRecBg"), ptCandB0, candidate.eta()); - registry.fill(HIST("hRapidityRecBg"), ptCandB0, hfHelper.yB0(candidate)); + registry.fill(HIST("hRapidityRecBg"), ptCandB0, HfHelper::yB0(candidate)); registry.fill(HIST("hInvMassDRecBg"), ptD, invMassD); registry.fill(HIST("hDecLengthDRecBg"), ptD, decLenD); registry.fill(HIST("hDecLengthXyDRecBg"), ptD, decLenXyD); registry.fill(HIST("hCospDRecBg"), ptD, cospD); registry.fill(HIST("hCospXyDRecBg"), ptD, cospXyD); - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { registry.fill(HIST("hMlScoreBkgDRecBg"), ptD, candidate.prong0MlScoreBkg()); registry.fill(HIST("hMlScorePromptDRecBg"), ptD, candidate.prong0MlScorePrompt()); registry.fill(HIST("hMlScoreNonPromptDRecBg"), ptD, candidate.prong0MlScoreNonprompt()); } - if constexpr (withB0Ml) { + if constexpr (WithB0Ml) { registry.fill(HIST("hMlScoreSigB0RecBg"), ptCandB0, candidate.mlProbB0ToDPi()); } - } else if constexpr (withDecayTypeCheck) { + } else if constexpr (WithDecayTypeCheck) { if (TESTBIT(flagMcMatchRec, hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi)) { // B0 → Ds- π+ → (K- K+ π-) π+ registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi, invMassB0, ptCandB0); + } else if (TESTBIT(flagMcMatchRec, hf_cand_b0::DecayTypeMc::BsToDsPiToKKPiPi)) { // B0s → Ds- π+ → (K- K+ π-) π+ + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_b0::DecayTypeMc::BsToDsPiToKKPiPi, invMassB0, ptCandB0); + } else if (TESTBIT(flagMcMatchRec, hf_cand_b0::DecayTypeMc::B0ToDplusKToPiKPiK)) { // B0 → D- K+ → (π- K+ π-) K+ + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_b0::DecayTypeMc::B0ToDplusKToPiKPiK, invMassB0, ptCandB0); } else if (TESTBIT(flagMcMatchRec, hf_cand_b0::DecayTypeMc::PartlyRecoDecay)) { // Partly reconstructed decay channel registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_b0::DecayTypeMc::PartlyRecoDecay, invMassB0, ptCandB0); } else { @@ -433,40 +795,40 @@ struct HfTaskB0Reduced { registry.fill(HIST("hCosp"), ptCandB0, candidate.cpa()); registry.fill(HIST("hCospXy"), ptCandB0, candidate.cpaXY()); registry.fill(HIST("hEta"), ptCandB0, candidate.eta()); - registry.fill(HIST("hRapidity"), ptCandB0, hfHelper.yB0(candidate)); + registry.fill(HIST("hRapidity"), ptCandB0, HfHelper::yB0(candidate)); registry.fill(HIST("hInvMassD"), ptD, invMassD); registry.fill(HIST("hDecLengthD"), ptD, decLenD); registry.fill(HIST("hDecLengthXyD"), ptD, decLenXyD); registry.fill(HIST("hCospD"), ptD, cospD); registry.fill(HIST("hCospXyD"), ptD, cospXyD); - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { registry.fill(HIST("hMlScoreBkgD"), ptD, candidate.prong0MlScoreBkg()); registry.fill(HIST("hMlScorePromptD"), ptD, candidate.prong0MlScorePrompt()); registry.fill(HIST("hMlScoreNonPromptD"), ptD, candidate.prong0MlScoreNonprompt()); } - if constexpr (withB0Ml) { + if constexpr (WithB0Ml) { registry.fill(HIST("hMlScoreSigB0"), ptCandB0, candidate.mlProbB0ToDPi()); } } } if (fillSparses) { - if constexpr (withDmesMl) { + if constexpr (DoMc) { if (isSignal) { - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { registry.fill(HIST("hMassPtCutVarsRecSig"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD, ptD, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); } else { registry.fill(HIST("hMassPtCutVarsRecSig"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD, ptD, decLenD, cospD); } } else if (fillBackground) { - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { registry.fill(HIST("hMassPtCutVarsRecBg"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD, ptD, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); } else { registry.fill(HIST("hMassPtCutVarsRecBg"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD, ptD, decLenD, cospD); } } } else { - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { registry.fill(HIST("hMassPtCutVars"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD, ptD, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); } else { registry.fill(HIST("hMassPtCutVars"), invMassB0, ptCandB0, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassD, ptD, decLenD, cospD); @@ -474,76 +836,100 @@ struct HfTaskB0Reduced { } } if (fillTree) { - float pseudoRndm = ptD * 1000. - (int64_t)(ptD * 1000); - if (flagMcMatchRec != 0 || (((doMc && fillBackground) || !doMc) && (ptCandB0 >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor))) { + float const pseudoRndm = ptD * 1000. - static_cast(ptD * 1000); + if (flagMcMatchRec != 0 || (((DoMc && fillBackground) || !DoMc) && (ptCandB0 >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor))) { float prong0MlScoreBkg = -1.; float prong0MlScorePrompt = -1.; float prong0MlScoreNonprompt = -1.; float candidateMlScoreSig = -1; - if constexpr (withDmesMl) { + if constexpr (WithDmesMl) { prong0MlScoreBkg = candidate.prong0MlScoreBkg(); prong0MlScorePrompt = candidate.prong0MlScorePrompt(); prong0MlScoreNonprompt = candidate.prong0MlScoreNonprompt(); } - if constexpr (withB0Ml) { + if constexpr (WithB0Ml) { candidateMlScoreSig = candidate.mlProbB0ToDPi(); } - auto prong1 = candidate.template prong1_as(); + auto prong1 = candidate.template prong1_as(); float ptMother = -1.; - if constexpr (doMc) { + if constexpr (DoMc) { ptMother = candidate.ptMother(); } 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()); } } } @@ -560,7 +946,7 @@ struct HfTaskB0Reduced { 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]); + bool const prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); if (fillHistograms) { registry.fill(HIST("hPtProng0Gen"), ptParticle, ptProngs[0]); @@ -587,53 +973,82 @@ struct HfTaskB0Reduced { } // Process functions - void processData(soa::Filtered> const& candidates, - aod::HfRed3Prongs const& candidatesD, - TracksPion const&) + void processDataDplusPi(soa::Filtered> const& candidates, + CandsDplus const& candidatesD, + TracksBachPions const&) { for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); } // candidate loop - } // processData - PROCESS_SWITCH(HfTaskB0Reduced, processData, "Process data without ML scores for B0 and D daughter", true); + } // processDataDplusPi + PROCESS_SWITCH(HfTaskB0Reduced, processDataDplusPi, "Process data without ML scores for B0 and Dplus daughter", true); - void processDataWithDmesMl(soa::Filtered> const& candidates, - aod::HfRed3Prongs const& candidatesD, - TracksPion const&) + void processDataDplusPiWithDmesMl(soa::Filtered> const& candidates, + CandsDplus const& candidatesD, + TracksBachPions const&) { for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); } // candidate loop - } // processDataWithDmesMl - PROCESS_SWITCH(HfTaskB0Reduced, processDataWithDmesMl, "Process data with(out) ML scores for D daughter (B0)", false); + } // processDataDplusPiWithDmesMl + PROCESS_SWITCH(HfTaskB0Reduced, processDataDplusPiWithDmesMl, "Process data with(out) ML scores for Dplus daughter (B0)", false); - void processDataWithB0Ml(soa::Filtered> const& candidates, - aod::HfRed3Prongs const& candidatesD, - TracksPion const&) + void processDataDplusPiWithB0Ml(soa::Filtered> const& candidates, + CandsDplus const& candidatesD, + TracksBachPions const&) { for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); } // candidate loop - } // processDataWithB0Ml - PROCESS_SWITCH(HfTaskB0Reduced, processDataWithB0Ml, "Process data with(out) ML scores for B0 (D daughter)", false); + } // processDataDplusPiWithB0Ml + PROCESS_SWITCH(HfTaskB0Reduced, processDataDplusPiWithB0Ml, "Process data with(out) ML scores for B0 (Dplus daughter)", false); + + // Process functions + void processDataDstarPi(soa::Filtered> const& candidates, + CandsDstar const& candidatesD, + TracksSoftPions const& softPions, + TracksBachPions const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { + continue; + } + fillCandDStarPi(candidate, softPions, candidatesD); + } // candidate loop + } // processDataDstarPi + PROCESS_SWITCH(HfTaskB0Reduced, processDataDstarPi, "Process data without ML scores for B0 and Dstar daughter", false); - void processMc(soa::Filtered> const& candidates, - aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, - TracksPion const&) + void processDataDstarPiWithDmesMl(soa::Filtered> const& candidates, + CandsDstar const& candidatesD, + TracksSoftPions const& softPions, + TracksBachPions const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { + continue; + } + fillCandDStarPi(candidate, softPions, candidatesD); + } // candidate loop + } // processDataDstarPiWithDmesMl + PROCESS_SWITCH(HfTaskB0Reduced, processDataDstarPiWithDmesMl, "Process data with(out) ML scores for Dstar daughter (B0)", false); + + void processMcDplusPi(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDplus const& candidatesD, + TracksBachPions const&) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); @@ -643,17 +1058,17 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc - PROCESS_SWITCH(HfTaskB0Reduced, processMc, "Process MC without ML scores for B0 and D daughter", false); + } // processMcDplusPi + PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPi, "Process MC without ML scores for B0 and Dplus daughter", false); - void processMcWithDecayTypeCheck(soa::Filtered> const& candidates, - aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, - TracksPion const&) + void processMcDplusPiWithDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDplus const& candidatesD, + TracksBachPions const&) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); @@ -663,17 +1078,17 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc - PROCESS_SWITCH(HfTaskB0Reduced, processMcWithDecayTypeCheck, "Process MC with decay type check and without ML scores for B0 and D daughter", false); + } // processMcDplusPi + PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithDecayTypeCheck, "Process MC with decay type check and without ML scores for B0 and Dplus daughter", false); - void processMcWithDmesMl(soa::Filtered> const& candidates, - aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, - TracksPion const&) + void processMcDplusPiWithDmesMl(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDplus const& candidatesD, + TracksBachPions const&) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); @@ -683,17 +1098,37 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMcWithDmesMl - PROCESS_SWITCH(HfTaskB0Reduced, processMcWithDmesMl, "Process MC with(out) ML scores for D daughter (B0)", false); + } // processMcDplusPiWithDmesMl + PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithDmesMl, "Process MC with(out) ML scores for Dplus daughter (B0)", false); + + void processMcDplusPiWithDmesMlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDplus const& candidatesD, + TracksBachPions 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 + } // processMcDplusPi + PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithDmesMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B0 (Dplus daughter)", false); - void processMcWithB0Ml(soa::Filtered> const& candidates, - aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, - TracksPion const&) + void processMcDplusPiWithB0Ml(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDplus const& candidatesD, + TracksBachPions const&) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); @@ -703,17 +1138,17 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMcWithB0Ml - PROCESS_SWITCH(HfTaskB0Reduced, processMcWithB0Ml, "Process MC with(out) ML scores for B0 (D daughter)", false); + } // processMcDplusPiWithB0Ml + PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithB0Ml, "Process MC with(out) ML scores for B0 (Dplus daughter)", false); - void processMcWithB0MlAndDecayTypeCheck(soa::Filtered> const& candidates, - aod::HfMcGenRedB0s const& mcParticles, - aod::HfRed3Prongs const& candidatesD, - TracksPion const&) + void processMcDplusPiWithB0MlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDplus const& candidatesD, + TracksBachPions const&) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yB0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } fillCand(candidate, candidatesD); @@ -723,8 +1158,51 @@ struct HfTaskB0Reduced { for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc - PROCESS_SWITCH(HfTaskB0Reduced, processMcWithB0MlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B0 (D daughter)", false); + } // processMcDplusPi + PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithB0MlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B0 (Dplus daughter)", false); + + void processMcDstarPi(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDstar const& candidatesD, + TracksSoftPions const& softPions, + TracksBachPions const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { + continue; + } + fillCandDStarPi(candidate, softPions, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcDstarPi + PROCESS_SWITCH(HfTaskB0Reduced, processMcDstarPi, "Process MC without ML scores for B0 and Dstar daughter", false); + + void processMcDstarPiWithDmesMl(soa::Filtered> const& candidates, + aod::HfMcGenRedB0s const& mcParticles, + CandsDstar const& candidatesD, + TracksSoftPions const& softPions, + TracksBachPions const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { + continue; + } + fillCandDStarPi(candidate, softPions, candidatesD); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcDstarPiWithDmesMl + PROCESS_SWITCH(HfTaskB0Reduced, processMcDstarPiWithDmesMl, "Process MC with(out) ML scores for Dstar daughter (B0)", false); + }; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/Tasks/taskBplus.cxx b/PWGHF/D2H/Tasks/taskBplus.cxx index 9586ebaa424..75712e018f0 100644 --- a/PWGHF/D2H/Tasks/taskBplus.cxx +++ b/PWGHF/D2H/Tasks/taskBplus.cxx @@ -18,22 +18,39 @@ /// \author Antonio Palasciano , Università degli Studi di Bari & INFN, Sezione di Bari /// \author Deepa Thomas , UT Austin -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + using namespace o2; using namespace o2::aod; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_decay::hf_cand_beauty; // string definitions, used for histogram axis labels const TString stringPt = "#it{p}_{T} (GeV/#it{c})"; @@ -54,7 +71,6 @@ struct HfTaskBplus { // O2DatabasePDG service Service pdg; - HfHelper hfHelper; Partition> selectedBPlusCandidates = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= selectionFlagBplus; Partition> selectedBPlusCandidatesMC = aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= selectionFlagBplus; @@ -164,14 +180,14 @@ struct HfTaskBplus { { for (const auto& candidate : selectedBPlusCandidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } auto ptCandBplus = candidate.pt(); auto candD0 = candidate.prong0_as>(); auto candPi = candidate.prong1(); - registry.fill(HIST("hMass"), hfHelper.invMassBplusToD0Pi(candidate), ptCandBplus); + 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()); @@ -183,20 +199,20 @@ struct HfTaskBplus { 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("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); if (candPi.sign() > 0) { - registry.fill(HIST("hInvMassD0"), hfHelper.invMassD0barToKPi(candD0), ptCandBplus); + registry.fill(HIST("hInvMassD0"), HfHelper::invMassD0barToKPi(candD0), ptCandBplus); } else { - registry.fill(HIST("hInvMassD0"), hfHelper.invMassD0ToPiK(candD0), ptCandBplus); + registry.fill(HIST("hInvMassD0"), HfHelper::invMassD0ToPiK(candD0), ptCandBplus); } registry.fill(HIST("hCPAFinerBinning"), candidate.cpa(), ptCandBplus); registry.fill(HIST("hCPAxyFinerBinning"), candidate.cpaXY(), ptCandBplus); } // candidate loop - } // process + } // process void processMc(soa::Join const&, soa::Join const& mcParticles, @@ -205,12 +221,12 @@ struct HfTaskBplus { { // MC rec for (const auto& candidate : selectedBPlusCandidatesMC) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } auto ptCandBplus = candidate.pt(); // auto candD0 = candidate.prong0_as(); - if (TESTBIT(std::abs(candidate.flagMcMatchRec()), hf_cand_bplus::DecayType::BplusToD0Pi)) { + if (std::abs(candidate.flagMcMatchRec()) == DecayChannelMain::BplusToD0Pi) { auto indexMother = RecoDecay::getMother(mcParticles, candidate.prong1_as().mcParticle_as>(), o2::constants::physics::Pdg::kBPlus, true); auto particleMother = mcParticles.rawIteratorAt(indexMother); @@ -221,10 +237,10 @@ struct HfTaskBplus { 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("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("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); @@ -238,10 +254,10 @@ struct HfTaskBplus { 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("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("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); @@ -253,7 +269,7 @@ struct HfTaskBplus { // MC gen. level for (const auto& particle : mcParticles) { - if (TESTBIT(std::abs(particle.flagMcMatchGen()), hf_cand_bplus::DecayType::BplusToD0Pi)) { + if (std::abs(particle.flagMcMatchGen()) == DecayChannelMain::BplusToD0Pi) { auto ptParticle = particle.pt(); auto yParticle = RecoDecay::y(particle.pVector(), o2::constants::physics::MassBPlus); @@ -263,7 +279,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())); @@ -297,7 +313,7 @@ struct HfTaskBplus { registry.fill(HIST("hEtaGenWithProngsInAcceptance"), particle.eta(), ptParticle); } } // gen - } // processMc + } // processMc PROCESS_SWITCH(HfTaskBplus, processMc, "Process MC", false); }; diff --git a/PWGHF/D2H/Tasks/taskBplusReduced.cxx b/PWGHF/D2H/Tasks/taskBplusReduced.cxx index 5b56d523944..bca08dbf154 100644 --- a/PWGHF/D2H/Tasks/taskBplusReduced.cxx +++ b/PWGHF/D2H/Tasks/taskBplusReduced.cxx @@ -14,16 +14,33 @@ /// /// \author Antonio Palasciano , Università degli Studi di Bari & INFN, Sezione di Bari -#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/D2H/DataModel/ReducedDataModel.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/D2H/DataModel/ReducedDataModel.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -35,69 +52,118 @@ namespace o2::aod { namespace hf_cand_bplus_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 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::MProng0, - hf_cand_bplus_lite::PtProng0, - hf_cand_bplus_lite::PtProng1, - hf_cand::ImpactParameter0, - hf_cand::ImpactParameter1, hf_cand_bplus_lite::ImpactParameterProduct, - hf_cand_bplus_lite::NSigTpcPi1, - hf_cand_bplus_lite::NSigTofPi1, + 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, - hf_cand_bplus_lite::MlScoreSig, - hf_sel_candidate_bplus::IsSelBplusToD0Pi, - hf_cand_bplus_lite::M, - hf_cand_bplus_lite::Pt, - hf_cand_bplus_lite::Cpa, - hf_cand_bplus_lite::CpaXY, - hf_cand_bplus_lite::MaxNormalisedDeltaIP, - hf_cand_bplus_lite::Eta, - hf_cand_bplus_lite::Phi, - hf_cand_bplus_lite::Y, + // 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_3prong::FlagMcMatchRec, - hf_cand_bplus_lite::MProng0, - hf_cand_bplus_lite::PtProng0, + 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); @@ -130,34 +196,29 @@ struct HfTaskBplusReduced { 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"}; - using TracksPion = soa::Join; - void init(InitContext&) { - std::array processFuncData{doprocessData, doprocessDataWithDmesMl}; + 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, doprocessMcWithDmesMl}; + 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."); } - 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 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}; @@ -186,10 +247,10 @@ struct HfTaskBplusReduced { 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("hDecLengthD", bPlusCandTitle + "#it{p}_{T}(D^{0}) (GeV/#it{c});D^{0} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtD0, axisDecLength}}); - registry.add("hDecLengthXyD", bPlusCandTitle + "#it{p}_{T}(D^{0}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtD0, axisDecLength}}); - registry.add("hCpaD", bPlusCandTitle + "#it{p}_{T}(D^{0}) (GeV/#it{c});D^{0} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtD0, axisCpa}}); - registry.add("hCpaXyD", bPlusCandTitle + "#it{p}_{T}(D^{0}) (GeV/#it{c});D^{0} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtD0, axisCpa}}); + 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) { @@ -213,7 +274,7 @@ struct HfTaskBplusReduced { } // histograms processMC - if (doprocessMc || doprocessMcWithDecayTypeCheck || doprocessMcWithDmesMl || doprocessMcWithBplusMl || doprocessMcWithBplusMlAndDecayTypeCheck) { + if (doprocessMc || doprocessMcWithDecayTypeCheck || doprocessMcWithDmesMl || doprocessMcWithDmesMlAndDecayTypeCheck || doprocessMcWithBplusMl || doprocessMcWithBplusMlAndDecayTypeCheck) { if (fillHistograms) { // Gen Level registry.add("hEtaGen", mcParticleMatched + "candidate #it{#eta}^{gen};" + stringPt, {HistType::kTH2F, {axisEta, axisPtB}}); @@ -270,10 +331,11 @@ struct HfTaskBplusReduced { 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 || doprocessMcWithBplusMlAndDecayTypeCheck) { + 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::BplusToD0KToKPiK] = "B^{+} #rightarrow (#overline{D^{0}} #rightarrow K^{#plus} #pi^{#minus}) #K^{#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, ""}; @@ -283,7 +345,7 @@ struct HfTaskBplusReduced { } } // ML scores of D0 daughter - if (doprocessMcWithDmesMl) { + 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}}); @@ -338,33 +400,36 @@ struct HfTaskBplusReduced { /// \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 + template void fillCand(Cand const& candidate, - aod::HfRed2Prongs const& /*candidatesD*/) + 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 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.invMassD0() : candD0.invMassD0Bar(); - std::array posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; - std::array posSvD{candD0.xSecondaryVertex(), candD0.ySecondaryVertex(), candD0.zSecondaryVertex()}; - std::array momD{candD0.pVector()}; + auto invMassD0 = (candPi.signed1Pt() < 0) ? candD0.invMassHypo0() : candD0.invMassHypo1(); + std::array const posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; + std::array const posSvD{candD0.xSecondaryVertex(), candD0.ySecondaryVertex(), candD0.zSecondaryVertex()}; + std::array const 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) { + 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 constexpr (DoMc) { if (isSignal) { registry.fill(HIST("hMassRecSig"), invMassBplus, ptCandBplus); registry.fill(HIST("hPtRecSig"), ptCandBplus); @@ -373,7 +438,7 @@ struct HfTaskBplusReduced { 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("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); @@ -386,15 +451,15 @@ struct HfTaskBplusReduced { registry.fill(HIST("hDecLengthXyD0RecSig"), decLenXyD0, ptD0); registry.fill(HIST("hCpaD0RecSig"), cpaD0, ptD0); registry.fill(HIST("hCpaXyD0RecSig"), cpaXyD0, ptD0); - if constexpr (withDecayTypeCheck) { + if constexpr (WithDecayTypeCheck) { registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi, invMassBplus, ptCandBplus); } - if constexpr (withDmesMl) { + 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) { + if constexpr (WithBplusMl) { registry.fill(HIST("hMlScoreSigBplusRecSig"), ptCandBplus, candidate.mlProbBplusToD0Pi()); } } else if (fillBackground) { @@ -405,7 +470,7 @@ struct HfTaskBplusReduced { 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("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); @@ -418,16 +483,18 @@ struct HfTaskBplusReduced { registry.fill(HIST("hDecLengthXyDRecBg"), decLenXyD0, ptD0); registry.fill(HIST("hCpaDRecBg"), cpaD0, ptD0); registry.fill(HIST("hCpaXyDRecBg"), cpaXyD0, ptD0); - if constexpr (withDmesMl) { + 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) { + 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 + } else if constexpr (WithDecayTypeCheck) { + if (TESTBIT(flagMcMatchRec, hf_cand_bplus::DecayTypeMc::BplusToD0KToKPiK)) { // Partly reconstructed decay channel + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bplus::DecayTypeMc::BplusToD0KToKPiK, invMassBplus, ptCandBplus); + } else 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); @@ -447,39 +514,39 @@ struct HfTaskBplusReduced { 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("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) { + 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) { + if constexpr (WithBplusMl) { registry.fill(HIST("hMlScoreSigBplus"), ptCandBplus, candidate.mlProbBplusToD0Pi()); } } } if (fillSparses) { - if constexpr (doMc) { + if constexpr (DoMc) { if (isSignal) { - if constexpr (withDmesMl) { + 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) { + 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) { + 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); @@ -487,74 +554,114 @@ struct HfTaskBplusReduced { } } if (fillTree) { - float pseudoRndm = ptD0 * 1000. - (int64_t)(ptD0 * 1000); + float const 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) { + if constexpr (WithDmesMl) { prong0MlScoreBkg = candidate.prong0MlScoreBkg(); prong0MlScorePrompt = candidate.prong0MlScorePrompt(); prong0MlScoreNonprompt = candidate.prong0MlScoreNonprompt(); } - if constexpr (withBplusMl) { + 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) { + 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, - candidate.ptProng1(), + decLenD0, + decLenXyD0, candidate.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameterProduct(), - prong1.tpcNSigmaPi(), - prong1.tofNSigmaPi(), + cpaD0, + cpaXyD0, + candD0.ptProngMin(), + candD0.absEtaProngMin(), + candD0.itsNClsProngMin(), + candD0.tpcNClsCrossedRowsProngMin(), + candD0.tpcChi2NClProngMax(), + tpcNSigmaPi, + tofNSigmaPi, + tpcTofNSigmaPi, + tpcNSigmaKa, + tofNSigmaKa, + tpcTofNSigmaKa, prong0MlScoreBkg, prong0MlScorePrompt, prong0MlScoreNonprompt, - candidateMlScoreSig, - candidate.isSelBplusToD0Pi(), - invMassBplus, - ptCandBplus, - candidate.cpa(), - candidate.cpaXY(), - candidate.maxNormalisedDeltaIP(), - candidate.eta(), - candidate.phi(), - hfHelper.yBplus(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 (withBplusMl) { - candidateMlScoreSig = candidate.mlProbBplusToD0Pi(); + + if constexpr (WithDecayTypeCheck) { + hfRedBpMcCheck( + flagMcMatchRec, + flagWrongCollision, + invMassD0, + ptD0, + invMassBplus, + ptCandBplus, + candidateMlScoreSig, + candidate.pdgCodeBeautyMother(), + candidate.pdgCodeCharmMother(), + candidate.pdgCodeProng0(), + candidate.pdgCodeProng1(), + candidate.pdgCodeProng2()); } - hfRedBpMcCheck( - flagMcMatchRec, - invMassD0, - ptD0, - invMassBplus, - ptCandBplus, - candidateMlScoreSig, - candidate.pdgCodeBeautyMother(), - candidate.pdgCodeProng0(), - candidate.pdgCodeProng1(), - candidate.pdgCodeProng2()); } } } @@ -571,7 +678,7 @@ struct HfTaskBplusReduced { 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]); + bool const prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); if (fillHistograms) { registry.fill(HIST("hPtProng0Gen"), ptParticle, ptProngs[0]); @@ -599,142 +706,162 @@ struct HfTaskBplusReduced { // Process functions void processData(soa::Filtered> const& candidates, - aod::HfRed2Prongs const& candidatesD, - TracksPion const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(candidate, candidatesD, pionTracks); } // candidate loop - } // processData + } // processData PROCESS_SWITCH(HfTaskBplusReduced, processData, "Process data without ML scores for D0 daughter", true); void processDataWithDmesMl(soa::Filtered> const& candidates, - aod::HfRed2Prongs const& candidatesD, - TracksPion const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(candidate, candidatesD, pionTracks); } // candidate loop - } // processDataWithDmesMl + } // processDataWithDmesMl PROCESS_SWITCH(HfTaskBplusReduced, processDataWithDmesMl, "Process data with ML scores for D0 daughter", false); void processDataWithBplusMl(soa::Filtered> const& candidates, - aod::HfRed2Prongs const& candidatesD, - TracksPion const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(candidate, candidatesD, pionTracks); } // candidate loop - } // processDataWithBplusMl + } // processDataWithBplusMl PROCESS_SWITCH(HfTaskBplusReduced, processDataWithBplusMl, "Process data with(out) ML scores for B+ (D0 daughter)", false); - void processMc(soa::Join const& candidates, + void processMc(soa::Filtered> const& candidates, aod::HfMcGenRedBps const& mcParticles, - aod::HfRed2Prongs const& candidatesD, - TracksPion const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(candidate, candidatesD, pionTracks); } // rec // MC gen. level for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc + } // 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, - aod::HfRed2Prongs const& candidatesD, - TracksPion const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(candidate, candidatesD, pionTracks); } // rec // MC gen. level for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc + } // processMc PROCESS_SWITCH(HfTaskBplusReduced, processMcWithDecayTypeCheck, "Process MC with decay type check and without ML scores for B+ and D daughter", false); - void processMcWithDmesMl(soa::Join const& candidates, + void processMcWithDmesMl(soa::Filtered> const& candidates, aod::HfMcGenRedBps const& mcParticles, - aod::HfRed2Prongs const& candidatesD, - TracksPion const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(candidate, candidatesD, pionTracks); } // rec // MC gen. level for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMcWithDmesMl + } // 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 + + // 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, - aod::HfRed2Prongs const& candidatesD, - TracksPion const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(candidate, candidatesD, pionTracks); } // rec // MC gen. level for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMcWithBplusMl + } // 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, - aod::HfRed2Prongs const& candidatesD, - TracksPion const&) + CandsD0 const& candidatesD, + TracksPion const& pionTracks) { // MC rec for (const auto& candidate : candidates) { - if (yCandRecoMax >= 0. && std::abs(hfHelper.yBplus(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(candidate, candidatesD, pionTracks); } // rec // MC gen. level for (const auto& particle : mcParticles) { fillCandMcGen(particle); } // gen - } // processMc + } // processMc PROCESS_SWITCH(HfTaskBplusReduced, processMcWithBplusMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B+ (D0 daughter)", false); }; // struct diff --git a/PWGHF/D2H/Tasks/taskBplusToJpsiKReduced.cxx b/PWGHF/D2H/Tasks/taskBplusToJpsiKReduced.cxx new file mode 100644 index 00000000000..aa0ff931938 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskBplusToJpsiKReduced.cxx @@ -0,0 +1,562 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file taskBplusToJpsiKReduced.cxx +/// \brief B+ → Jpsi K+ → (µ+ µ-) K+ analysis task +/// +/// \author Fabrizio Chinu , Università degli Studi and INFN Torino +/// \author Fabrizio Grosa , CERN + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseBplusToJpsiKReduced.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::pid_tpc_tof_utils; + +namespace o2::aod +{ +namespace hf_cand_bplustojpsik_lite +{ +DECLARE_SOA_COLUMN(PtJpsi, ptJpsi, float); //! Transverse momentum of Jpsi daughter candidate (GeV/c) +DECLARE_SOA_COLUMN(PtBach, ptBach, float); //! Transverse momentum of bachelor kaon (GeV/c) +DECLARE_SOA_COLUMN(ItsNClsJpsiDauPos, itsNClsJpsiDauPos, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsJpsiDauPos, tpcNClsCrossedRowsJpsiDauPos, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(ItsChi2NClJpsiDauPos, itsChi2NClJpsiDauPos, float); //! ITS chi2 / Number of clusters +DECLARE_SOA_COLUMN(TpcChi2NClJpsiDauPos, tpcChi2NClJpsiDauPos, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(AbsEtaJpsiDauPos, absEtaJpsiDauPos, float); //! |eta| +DECLARE_SOA_COLUMN(ItsNClsJpsiDauNeg, itsNClsJpsiDauNeg, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsJpsiDauNeg, tpcNClsCrossedRowsJpsiDauNeg, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(ItsChi2NClJpsiDauNeg, itsChi2NClJpsiDauNeg, float); //! ITS chi2 / Number of clusters +DECLARE_SOA_COLUMN(TpcChi2NClJpsiDauNeg, tpcChi2NClJpsiDauNeg, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(AbsEtaJpsiDauNeg, absEtaJpsiDauNeg, float); //! |eta| +DECLARE_SOA_COLUMN(ItsNClsLfTrack0, itsNClsLfTrack0, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsLfTrack0, tpcNClsCrossedRowsLfTrack0, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(ItsChi2NClLfTrack0, itsChi2NClLfTrack0, float); //! ITS chi2 / Number of clusters +DECLARE_SOA_COLUMN(TpcChi2NClLfTrack0, tpcChi2NClLfTrack0, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(AbsEtaLfTrack0, absEtaLfTrack0, float); //! |eta| +DECLARE_SOA_COLUMN(MJpsi, mJpsi, float); //! Invariant mass of Jpsi 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(NSigTpcKaBachelor, nSigTpcKaBachelor, float); //! TPC Nsigma separation for bachelor with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofKaBachelor, nSigTofKaBachelor, float); //! TOF Nsigma separation for bachelor with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofKaBachelor, nSigTpcTofKaBachelor, float); //! Combined TPC and TOF Nsigma separation for bachelor with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcMuJpsiDauPos, nSigTpcMuJpsiDauPos, float); //! TPC Nsigma separation for Jpsi DauPos with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofMuJpsiDauPos, nSigTofMuJpsiDauPos, float); //! TOF Nsigma separation for Jpsi DauPos with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofMuJpsiDauPos, nSigTpcTofMuJpsiDauPos, float); //! Combined TPC and TOF Nsigma separation for Jpsi prong0 with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcMuJpsiDauNeg, nSigTpcMuJpsiDauNeg, float); //! TPC Nsigma separation for Jpsi DauNeg with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofMuJpsiDauNeg, nSigTofMuJpsiDauNeg, float); //! TOF Nsigma separation for Jpsi DauNeg with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofMuJpsiDauNeg, nSigTpcTofMuJpsiDauNeg, float); //! Combined TPC and TOF Nsigma separation for Jpsi prong1 with muon 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(CtXY, ctXY, float); //! Pseudo-proper decay length of candidate +DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! Impact parameter product of B daughters +DECLARE_SOA_COLUMN(ImpactParameterProductJpsi, impactParameterProductJpsi, float); //! Impact parameter product of Jpsi daughters +DECLARE_SOA_COLUMN(ImpactParameterJpsiDauPos, impactParameterJpsiDauPos, float); //! Impact parameter of Jpsi daughter candidate +DECLARE_SOA_COLUMN(ImpactParameterJpsiDauNeg, impactParameterJpsiDauNeg, float); //! Impact parameter of Jpsi daughter candidate +DECLARE_SOA_COLUMN(ImpactParameterLfTrack0, impactParameterLfTrack0, float); //! Impact parameter of Phi daughter 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(CpaJpsi, cpaJpsi, float); //! Cosine pointing angle of Jpsi daughter candidate +DECLARE_SOA_COLUMN(CpaXYJpsi, cpaXYJpsi, float); //! Cosine pointing angle in transverse plane of Jpsi 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_bplustojpsik_lite + +DECLARE_SOA_TABLE(HfRedCandBpLites, "AOD", "HFREDCANDBPLITE", //! Table with some B+ properties + hf_cand_bplustojpsik_lite::M, + hf_cand_bplustojpsik_lite::Pt, + hf_cand_bplustojpsik_lite::Eta, + hf_cand_bplustojpsik_lite::Phi, + hf_cand_bplustojpsik_lite::Y, + hf_cand_bplustojpsik_lite::Cpa, + hf_cand_bplustojpsik_lite::CpaXY, + hf_cand::Chi2PCA, + hf_cand_bplustojpsik_lite::DecayLength, + hf_cand_bplustojpsik_lite::DecayLengthXY, + hf_cand_bplustojpsik_lite::DecayLengthNormalised, + hf_cand_bplustojpsik_lite::DecayLengthXYNormalised, + hf_cand_bplustojpsik_lite::CtXY, + hf_cand_bplustojpsik_lite::ImpactParameterProduct, + hf_cand_bplustojpsik_lite::ImpactParameterProductJpsi, + hf_cand_bplustojpsik_lite::MaxNormalisedDeltaIP, + hf_cand_bplustojpsik_lite::MlScoreSig, + // hf_sel_candidate_bplus::IsSelBplusToJpsiPi, + // Jpsi meson features + hf_cand_bplustojpsik_lite::MJpsi, + hf_cand_bplustojpsik_lite::PtJpsi, + hf_cand_bplustojpsik_lite::ImpactParameterJpsiDauPos, + hf_cand_bplustojpsik_lite::ImpactParameterJpsiDauNeg, + hf_cand_bplustojpsik_lite::ImpactParameterLfTrack0, + // Jpsi daughter features + hf_cand_bplustojpsik_lite::ItsNClsJpsiDauPos, + hf_cand_bplustojpsik_lite::TpcNClsCrossedRowsJpsiDauPos, + hf_cand_bplustojpsik_lite::ItsChi2NClJpsiDauPos, + hf_cand_bplustojpsik_lite::TpcChi2NClJpsiDauPos, + hf_cand_bplustojpsik_lite::AbsEtaJpsiDauPos, + hf_cand_bplustojpsik_lite::ItsNClsJpsiDauNeg, + hf_cand_bplustojpsik_lite::TpcNClsCrossedRowsJpsiDauNeg, + hf_cand_bplustojpsik_lite::ItsChi2NClJpsiDauNeg, + hf_cand_bplustojpsik_lite::TpcChi2NClJpsiDauNeg, + hf_cand_bplustojpsik_lite::AbsEtaJpsiDauNeg, + // kaon features + hf_cand_bplustojpsik_lite::PtBach, + hf_cand_bplustojpsik_lite::ItsNClsLfTrack0, + hf_cand_bplustojpsik_lite::TpcNClsCrossedRowsLfTrack0, + hf_cand_bplustojpsik_lite::ItsChi2NClLfTrack0, + hf_cand_bplustojpsik_lite::TpcChi2NClLfTrack0, + hf_cand_bplustojpsik_lite::AbsEtaLfTrack0, + hf_cand_bplustojpsik_lite::NSigTpcKaBachelor, + hf_cand_bplustojpsik_lite::NSigTofKaBachelor, + hf_cand_bplustojpsik_lite::NSigTpcTofKaBachelor, + // MC truth + hf_cand_bplus::FlagMcMatchRec, + hf_cand_bplus::FlagMcDecayChanRec, + hf_cand_bplus::OriginMcRec, + hf_cand_bplustojpsik_lite::FlagWrongCollision, + hf_cand_bplustojpsik_lite::PtGen); + +// DECLARE_SOA_TABLE(HfRedBpMcCheck, "AOD", "HFREDBPMCCHECK", //! Table with MC decay type check +// hf_cand_2prong::FlagMcMatchRec, +// hf_cand_bplustojpsik_lite::FlagWrongCollision, +// hf_cand_bplustojpsik_lite::MJpsi, +// hf_cand_bplustojpsik_lite::PtJpsi, +// hf_cand_bplustojpsik_lite::M, +// hf_cand_bplustojpsik_lite::Pt, +// // hf_cand_bplustojpsik_lite::MlScoreSig, +// hf_bplus_mc::PdgCodeBeautyMother, +// hf_bplus_mc::PdgCodeCharmMother, +// hf_bplus_mc::PdgCodeDauPos, +// hf_bplus_mc::PdgCodeDauNeg, +// 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 stringPtJpsi = "#it{p}_{T}(Jpsi) (GeV/#it{c});"; +const TString bPlusCandTitle = "B+ candidates;"; +const TString entries = "entries"; +const TString bPlusCandMatch = "B+ candidates (matched);"; +const TString bPlusCandUnmatch = "B+ candidates (unmatched);"; +const TString mcParticleMatched = "MC particles (matched);"; + +/// B+ analysis task +struct HfTaskBplusToJpsiKReduced { + 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 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"}; + // topological cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_bplus_to_jpsi_k::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_bplus_to_jpsi_k::Cuts[0], hf_cuts_bplus_to_jpsi_k::NBinsPt, hf_cuts_bplus_to_jpsi_k::NCutVars, hf_cuts_bplus_to_jpsi_k::labelsPt, hf_cuts_bplus_to_jpsi_k::labelsCutVar}, "B+ candidate selection per pT bin"}; + // Enable PID + Configurable kaonPidMethod{"kaonPidMethod", PidMethod::TpcOrTof, "PID selection method for the bachelor kaon (PidMethod::NoPid: none, PidMethod::TpcOrTof: TPC or TOF, PidMethod::TpcAndTof: 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"}; + // B+ ML inference + 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_BPLUSToJPSIK.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"}; + + TrackSelectorKa selectorKaon; + o2::analysis::HfMlResponseBplusToJpsiKReduced hfMlResponse; + o2::ccdb::CcdbApi ccdbApi; + + using TracksKaon = soa::Join; + std::vector outputMl; + + // Filter filterSelectCandidates = (aod::hf_sel_candidate_bplus::isSelBplusToJpsiPi >= selectionFlagBplus); + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + std::array processFuncData{doprocessData, 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, doprocessMcWithBplusMl}; + if ((std::accumulate(processFuncMc.begin(), processFuncMc.end(), 0)) > 1) { + LOGP(fatal, "Only one process function for MC can be enabled at a time."); + } + + if (kaonPidMethod < 0 || kaonPidMethod >= PidMethod::NPidMethods) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (kaonPidMethod != PidMethod::NoPid) { + selectorKaon.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); + selectorKaon.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); + selectorKaon.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); + selectorKaon.setRangePtTof(ptPidTofMin, ptPidTofMax); + selectorKaon.setRangeNSigmaTof(-nSigmaTofMax, nSigmaTofMax); + selectorKaon.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedMax, nSigmaTofCombinedMax); + } + + const AxisSpec axisMassBplus{150, 4.5, 6.0}; + const AxisSpec axisMassJpsi{600, 2.8f, 3.4f}; + const AxisSpec axisPtProng{100, 0., 10.}; + const AxisSpec axisImpactPar{200, -0.05, 0.05}; + const AxisSpec axisPtJpsi{100, 0., 50.}; + const AxisSpec axisRapidity{100, -2., 2.}; + const AxisSpec axisPtB{(std::vector)binsPt, "#it{p}_{T}^{B^{+}} (GeV/#it{c})"}; + const AxisSpec axisPtKa{100, 0.f, 10.f}; + + registry.add("hMass", bPlusCandTitle + "inv. mass J/#Psi K^{+} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassBplus, axisPtB}}); + registry.add("hMassJpsi", bPlusCandTitle + "inv. mass #mu^{+}#mu^{#minus} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassJpsi, axisPtJpsi}}); + registry.add("hd0K", bPlusCandTitle + "Kaon DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisImpactPar, axisPtKa}}); + + // histograms processMC + if (doprocessMc || doprocessMcWithBplusMl) { + registry.add("hPtJpsiGen", mcParticleMatched + "J/#Psi #it{p}_{T}^{gen} (GeV/#it{c}); B^{+} " + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hPtKGen", mcParticleMatched + "Kaon #it{p}_{T}^{gen} (GeV/#it{c}); B^{+} " + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hYGenWithProngsInAcceptance", mcParticleMatched + "B^{+} #it{p}_{T}^{gen} (GeV/#it{c}); B^{+} #it{y}", {HistType::kTH2F, {axisPtProng, axisRapidity}}); + registry.add("hMassRecSig", bPlusCandMatch + "inv. mass J/#Psi K^{+} (GeV/#it{c}^{2}); B^{+} " + stringPt, {HistType::kTH2F, {axisMassBplus, axisPtB}}); + registry.add("hMassJpsiRecSig", bPlusCandMatch + "inv. mass #mu^{+}#mu^{#minus} (GeV/#it{c}^{2}); J/#Psi " + stringPt, {HistType::kTH2F, {axisMassJpsi, axisPtJpsi}}); + registry.add("hd0KRecSig", bPlusCandMatch + "Kaon DCAxy to prim. vertex (cm); K^{+} " + stringPt, {HistType::kTH2F, {axisImpactPar, axisPtKa}}); + registry.add("hMassRecBg", bPlusCandUnmatch + "inv. mass J/#Psi K^{+} (GeV/#it{c}^{2}); B^{+} " + stringPt, {HistType::kTH2F, {axisMassBplus, axisPtB}}); + registry.add("hMassJpsiRecBg", bPlusCandUnmatch + "inv. mass #mu^{+}#mu^{#minus} (GeV/#it{c}^{2}); J/#Psi " + stringPt, {HistType::kTH2F, {axisMassJpsi, axisPtJpsi}}); + registry.add("hd0KRecBg", bPlusCandMatch + "Kaon DCAxy to prim. vertex (cm); K^{+} " + stringPt, {HistType::kTH2F, {axisImpactPar, axisPtKa}}); + } + + if (doprocessDataWithBplusMl || doprocessMcWithBplusMl) { + 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(); + } + } + + /// Selection of B+ daughter in geometrical acceptance + /// \param etaProng is the pseudorapidity of B+ prong + /// \param ptProng is the pT of B+ 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; + } + + /// Calculate pseudorapidity from track tan(lambda) + /// \param tgl is the track tangent of the dip angle + /// \return pseudorapidity + float absEta(float tgl) + { + return std::abs(std::log(std::tan(o2::constants::math::PIQuarter - 0.5f * std::atan(tgl)))); + } + + /// Fill candidate information at reconstruction level + /// \param doMc is the flag to enable the filling with MC information + /// \param withBplusMl is the flag to enable the filling with ML scores for the B+ candidate + /// \param candidate is the B+ candidate + /// \param candidatesJpsi is the table with Jpsi candidates + template + void fillCand(Cand const& candidate, + aod::HfRedJpsis const& /*candidatesJpsi*/, + aod::HfRedBach0Tracks const&) + { + auto ptCandBplus = candidate.pt(); + auto invMassBplus = HfHelper::invMassBplusToJpsiK(candidate); + auto candJpsi = candidate.template jpsi_as(); + auto candKa = candidate.template bachKa_as(); + auto ptJpsi = candidate.ptProng0(); + auto invMassJpsi = candJpsi.m(); + uint8_t statusBplus = 0; + + int8_t flagMcMatchRec{0}, flagMcDecayChanRec{0}, flagWrongCollision{0}; + bool isSignal = false; + if constexpr (DoMc) { + flagMcMatchRec = candidate.flagMcMatchRec(); + flagMcDecayChanRec = candidate.flagMcDecayChanRec(); + flagWrongCollision = candidate.flagWrongCollision(); + isSignal = std::abs(flagMcMatchRec) == o2::hf_decay::hf_cand_beauty::BplusToJpsiK; + } + + SETBIT(statusBplus, SelectionStep::RecoSkims); + if (HfHelper::selectionBplusToJpsiKTopol(candidate, cuts, binsPt)) { + SETBIT(statusBplus, SelectionStep::RecoTopol); + } else if (selectionFlagBplus >= BIT(SelectionStep::RecoTopol) * 2 - 1) { + return; + } + // track-level PID selection + // auto trackKa = candidate.template prong1_as(); + if (kaonPidMethod == PidMethod::TpcOrTof || kaonPidMethod == PidMethod::TpcAndTof) { + int pidTrackKa{TrackSelectorPID::Status::NotApplicable}; + if (kaonPidMethod == PidMethod::TpcOrTof) { + pidTrackKa = selectorKaon.statusTpcOrTof(candKa); + } else if (kaonPidMethod == PidMethod::TpcAndTof) { + pidTrackKa = selectorKaon.statusTpcAndTof(candKa); + } + if (HfHelper::selectionBplusToJpsiKPid(pidTrackKa, acceptPIDNotApplicable.value)) { + // LOGF(info, "B+ candidate selection failed at PID selection"); + SETBIT(statusBplus, SelectionStep::RecoPID); + } else if (selectionFlagBplus >= BIT(SelectionStep::RecoPID) * 2 - 1) { + return; + } + } + + float candidateMlScoreSig = -1; + if constexpr (WithBplusMl) { + // B+ ML selections + std::vector inputFeatures = hfMlResponse.getInputFeatures(candidate, candKa); + if (hfMlResponse.isSelectedMl(inputFeatures, ptCandBplus, outputMl)) { + SETBIT(statusBplus, SelectionStep::RecoMl); + } else if (selectionFlagBplus >= BIT(SelectionStep::RecoMl) * 2 - 1) { + return; + } + candidateMlScoreSig = outputMl[1]; + } + + registry.fill(HIST("hMass"), invMassBplus, ptCandBplus); + registry.fill(HIST("hMassJpsi"), invMassJpsi, candidate.ptProng0()); + registry.fill(HIST("hd0K"), candidate.impactParameter1(), candidate.ptProng1()); + if constexpr (DoMc) { + if (isSignal) { + registry.fill(HIST("hMassRecSig"), invMassBplus, ptCandBplus); + registry.fill(HIST("hMassJpsiRecSig"), invMassJpsi, candidate.ptProng0()); + registry.fill(HIST("hd0KRecSig"), candidate.impactParameter1(), candidate.ptProng1()); + } else if (fillBackground) { + registry.fill(HIST("hMassRecBg"), invMassBplus, ptCandBplus); + registry.fill(HIST("hMassJpsiRecBg"), invMassJpsi, candidate.ptProng0()); + registry.fill(HIST("hd0KRecBg"), candidate.impactParameter1(), candidate.ptProng1()); + } + } + + float const pseudoRndm = ptJpsi * 1000. - static_cast(ptJpsi * 1000); + if (ptCandBplus >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor) { + 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.ctXY(std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus}), + candidate.impactParameterProduct(), + candidate.impactParameterProductJpsi(), + candidate.maxNormalisedDeltaIP(), + candidateMlScoreSig, + // J/Psi features + invMassJpsi, + ptJpsi, + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameter2(), + candJpsi.itsNClsDauPos(), + candJpsi.tpcNClsCrossedRowsDauPos(), + candJpsi.itsChi2NClDauPos(), + candJpsi.tpcChi2NClDauPos(), + absEta(candJpsi.tglDauPos()), + candJpsi.itsNClsDauNeg(), + candJpsi.tpcNClsCrossedRowsDauNeg(), + candJpsi.itsChi2NClDauNeg(), + candJpsi.tpcChi2NClDauNeg(), + absEta(candJpsi.tglDauNeg()), + // kaon features + candidate.ptProng1(), + candKa.itsNCls(), + candKa.tpcNClsCrossedRows(), + candKa.itsChi2NCl(), + candKa.tpcChi2NCl(), + absEta(candKa.tgl()), + candKa.tpcNSigmaKa(), + candKa.tofNSigmaKa(), + candKa.tpcTofNSigmaKa(), + // MC truth + flagMcMatchRec, + flagMcDecayChanRec, + isSignal, + flagWrongCollision, + ptMother); + } + } + + /// Fill particle histograms (gen MC truth) + void fillCandMcGen(aod::HfMcGenRedBps::iterator const& particle) + { + auto ptParticle = particle.ptTrack(); + auto yParticle = particle.yTrack(); + if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + return; + } + std::array ptProngs = {particle.ptProng0(), particle.ptProng1()}; + std::array etaProngs = {particle.etaProng0(), particle.etaProng1()}; + bool const prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); + + registry.fill(HIST("hPtJpsiGen"), ptProngs[0], ptParticle); + registry.fill(HIST("hPtKGen"), ptProngs[1], ptParticle); + + // generated B+ with daughters in geometrical acceptance + if (prongsInAcc) { + registry.fill(HIST("hYGenWithProngsInAcceptance"), ptParticle, yParticle); + } + } + + // Process functions + void processData(aod::HfRedCandBplusToJpsiK const& candidates, + aod::HfRedJpsis const& candidatesJpsi, + aod::HfRedBach0Tracks const& kaonTracks) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesJpsi, kaonTracks); + } // candidate loop + } // processData + PROCESS_SWITCH(HfTaskBplusToJpsiKReduced, processData, "Process data without ML for B+", true); + + void processDataWithBplusMl(aod::HfRedCandBplusToJpsiK const& candidates, + aod::HfRedJpsis const& candidatesJpsi, + aod::HfRedBach0Tracks const& kaonTracks) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesJpsi, kaonTracks); + } // candidate loop + } // processDataWithBplusMl + PROCESS_SWITCH(HfTaskBplusToJpsiKReduced, processDataWithBplusMl, "Process data with ML for B+", false); + + void processMc(soa::Join const& candidates, + aod::HfMcGenRedBps const& mcParticles, + aod::HfRedJpsis const& candidatesJpsi, + aod::HfRedBach0Tracks const& kaonTracks) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesJpsi, kaonTracks); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBplusToJpsiKReduced, processMc, "Process MC without ML for B+", false); + + void processMcWithBplusMl(soa::Join const& candidates, + aod::HfMcGenRedBps const& mcParticles, + aod::HfRedJpsis const& candidatesJpsi, + aod::HfRedBach0Tracks const& kaonTracks) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBplus(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesJpsi, kaonTracks); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcWithBplusMl + PROCESS_SWITCH(HfTaskBplusToJpsiKReduced, processMcWithBplusMl, "Process MC with ML for B+", false); + +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskBs.cxx b/PWGHF/D2H/Tasks/taskBs.cxx index 29c424f869b..b6beb8844ee 100644 --- a/PWGHF/D2H/Tasks/taskBs.cxx +++ b/PWGHF/D2H/Tasks/taskBs.cxx @@ -15,22 +15,43 @@ /// /// \author Phil Stahlhut -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_decay::hf_cand_beauty; /// Bs analysis task struct HfTaskBs { @@ -44,7 +65,6 @@ struct HfTaskBs { Configurable checkDecayTypeMc{"checkDecayTypeMc", false, "Flag to enable DecayType histogram"}; Service pdg; - HfHelper hfHelper; using TracksWithSel = soa::Join; @@ -126,15 +146,15 @@ struct HfTaskBs { registry.add("hYGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);B^{0}_{s} candidate #it{y}^{gen};entries", {HistType::kTH2F, {{100, -2., 2.}, axisPt}}); 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}"; + constexpr uint8_t NBinsDecayTypeMc = hf_cand_bs::DecayTypeMc::NDecayTypeMc + 1; + TString labels[NBinsDecayTypeMc]; + 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, ""}; + static const AxisSpec axisDecayType = {NBinsDecayTypeMc, 0.5, NBinsDecayTypeMc + 0.5, ""}; registry.add("hDecayTypeMc", "DecayType", {HistType::kTH3F, {axisDecayType, axisMassBs, axisPt}}); - for (uint8_t iBin = 0; iBin < kNBinsDecayTypeMc; ++iBin) { + for (uint8_t iBin = 0; iBin < NBinsDecayTypeMc; ++iBin) { registry.get(HIST("hDecayTypeMc"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin]); } } @@ -155,10 +175,7 @@ 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) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBs(candidate)) > yCandRecoMax) { continue; } @@ -170,9 +187,9 @@ struct HfTaskBs { registry.fill(HIST("hPtProng1"), candidate.ptProng1()); registry.fill(HIST("hPtCand"), ptCandBs); registry.fill(HIST("hEta"), candidate.eta(), ptCandBs); - registry.fill(HIST("hRapidity"), hfHelper.yBs(candidate), ptCandBs); + registry.fill(HIST("hRapidity"), HfHelper::yBs(candidate), ptCandBs); registry.fill(HIST("hCPA"), candidate.cpa(), ptCandBs); - registry.fill(HIST("hMass"), hfHelper.invMassBsToDsPi(candidate), ptCandBs); + registry.fill(HIST("hMass"), HfHelper::invMassBsToDsPi(candidate), ptCandBs); registry.fill(HIST("hDecLength"), candidate.decayLength(), ptCandBs); registry.fill(HIST("hDecLenErr"), candidate.errorDecayLength(), ptCandBs); registry.fill(HIST("hDecLengthXY"), candidate.decayLengthXY(), ptCandBs); @@ -182,9 +199,9 @@ struct HfTaskBs { registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter0(), ptCandBs); registry.fill(HIST("hImpParErr"), candidate.errorImpactParameter1(), ptCandBs); registry.fill(HIST("hIPProd"), candidate.impactParameterProduct(), ptCandBs); - registry.fill(HIST("hInvMassDs"), hfHelper.invMassDsToKKPi(candDs), ptCandBs); + registry.fill(HIST("hInvMassDs"), HfHelper::invMassDsToKKPi(candDs), ptCandBs); } // candidate loop - } // process + } // process /// Bs MC analysis and fill histograms void processMc(soa::Filtered> const& candidates, @@ -194,29 +211,26 @@ 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) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBs(candidate)) > yCandRecoMax) { continue; } auto ptCandBs = candidate.pt(); auto candDs = candidate.prong0_as>(); - auto invMassCandBs = hfHelper.invMassBsToDsPi(candidate); - int flagMcMatchRecBs = std::abs(candidate.flagMcMatchRec()); + auto invMassCandBs = HfHelper::invMassBsToDsPi(candidate); + auto flagMcMatchRecBs = std::abs(candidate.flagMcMatchRec()); - if (TESTBIT(flagMcMatchRecBs, hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi)) { + if (flagMcMatchRecBs == DecayChannelMain::BsToDsPi) { auto indexMother = RecoDecay::getMother(mcParticles, candidate.prong1_as().mcParticle_as>(), o2::constants::physics::Pdg::kBS, true); auto particleMother = mcParticles.rawIteratorAt(indexMother); registry.fill(HIST("hPtGenSig"), particleMother.pt()); registry.fill(HIST("hPtRecSig"), ptCandBs); registry.fill(HIST("hEtaRecSig"), candidate.eta(), ptCandBs); - registry.fill(HIST("hRapidityRecSig"), hfHelper.yBs(candidate), ptCandBs); + registry.fill(HIST("hRapidityRecSig"), HfHelper::yBs(candidate), ptCandBs); registry.fill(HIST("hCPARecSig"), candidate.cpa(), ptCandBs); registry.fill(HIST("hCPAxyRecSig"), candidate.cpaXY(), ptCandBs); - registry.fill(HIST("hMassRecSig"), hfHelper.invMassBsToDsPi(candidate), ptCandBs); + registry.fill(HIST("hMassRecSig"), HfHelper::invMassBsToDsPi(candidate), ptCandBs); registry.fill(HIST("hDecLengthRecSig"), candidate.decayLength(), ptCandBs); registry.fill(HIST("hDecLengthXYRecSig"), candidate.decayLengthXY(), ptCandBs); registry.fill(HIST("hDecLengthNormRecSig"), candidate.decayLengthXYNormalised(), ptCandBs); @@ -230,15 +244,15 @@ 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); registry.fill(HIST("hEtaRecBg"), candidate.eta(), ptCandBs); - registry.fill(HIST("hRapidityRecBg"), hfHelper.yBs(candidate), ptCandBs); + registry.fill(HIST("hRapidityRecBg"), HfHelper::yBs(candidate), ptCandBs); registry.fill(HIST("hCPARecBg"), candidate.cpa(), ptCandBs); registry.fill(HIST("hCPAxyRecBg"), candidate.cpaXY(), ptCandBs); - registry.fill(HIST("hMassRecBg"), hfHelper.invMassBsToDsPi(candidate), ptCandBs); + registry.fill(HIST("hMassRecBg"), HfHelper::invMassBsToDsPi(candidate), ptCandBs); registry.fill(HIST("hDecLengthRecBg"), candidate.decayLength(), ptCandBs); registry.fill(HIST("hDecLengthXYRecBg"), candidate.decayLengthXY(), ptCandBs); registry.fill(HIST("hDecLengthNormRecBg"), candidate.decayLengthXYNormalised(), ptCandBs); @@ -252,9 +266,9 @@ 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); - } else if (TESTBIT(flagMcMatchRecBs, hf_cand_bs::DecayTypeMc::PartlyRecoDecay)) { // Partly reconstructed decay channel + if (flagMcMatchRecBs == DecayChannelMain::B0ToDsPi) { // B0(bar) → Ds± π∓ → (K- K+ π±) π∓ + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::B0ToDsPiToPhiPiPiToKKPiPi, invMassCandBs, ptCandBs); + } else if (flagMcMatchRecBs == hf_cand_bs::DecayTypeMc::PartlyRecoDecay) { // FIXME, Partly reconstructed decay channel registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::PartlyRecoDecay, invMassCandBs, ptCandBs); } else { registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_bs::DecayTypeMc::NDecayTypeMc, invMassCandBs, ptCandBs); @@ -265,7 +279,7 @@ struct HfTaskBs { // MC gen. level for (const auto& particle : mcParticles) { - if (TESTBIT(std::abs(particle.flagMcMatchGen()), hf_cand_bs::DecayTypeMc::BsToDsPiToKKPiPi)) { + if (std::abs(particle.flagMcMatchGen()) == DecayChannelMain::BsToDsPi) { auto ptParticle = particle.pt(); auto yParticle = RecoDecay::y(particle.pVector(), o2::constants::physics::MassBS); @@ -273,9 +287,9 @@ struct HfTaskBs { continue; } - std::array ptProngs; - std::array yProngs; - std::array etaProngs; + std::array ptProngs{}; + std::array yProngs{}; + std::array etaProngs{}; int counter = 0; for (const auto& daught : particle.daughters_as()) { ptProngs[counter] = daught.pt(); @@ -308,7 +322,7 @@ struct HfTaskBs { registry.fill(HIST("hYGenWithProngsInAcceptance"), yParticle, ptParticle); } } // gen - } // process + } // process PROCESS_SWITCH(HfTaskBs, processMc, "Process MC", false); }; // struct diff --git a/PWGHF/D2H/Tasks/taskBsReduced.cxx b/PWGHF/D2H/Tasks/taskBsReduced.cxx new file mode 100644 index 00000000000..93b4485228a --- /dev/null +++ b/PWGHF/D2H/Tasks/taskBsReduced.cxx @@ -0,0 +1,854 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/Core/HfHelper.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +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 +{ +// B meson features +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(Eta, eta, float); //! Pseudorapidity of candidate +DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity 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(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(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 +// D meson features +DECLARE_SOA_COLUMN(MProng0, mProng0, float); //! Invariant mass of prong0 (GeV/c) +DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! Transverse momentum of prong0 (GeV/c) +DECLARE_SOA_COLUMN(DecayLength0, decayLength0, float); //! Decay length of D-meson daughter candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXY0, decayLengthXY0, float); //! Transverse decay length of D-meson daughter candidate (cm) +DECLARE_SOA_COLUMN(ImpactParameter0, impactParameter0, float); //! Impact parameter product of D-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(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 +// pion features +DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Transverse momentum of prong1 (GeV/c) +DECLARE_SOA_COLUMN(AbsEtaProng1, absEtaProng1, float); //! Absolute pseudorapidity of Prong1 +DECLARE_SOA_COLUMN(ItsNClsProng1, itsNClsProng1, int); //! Number of ITS clusters of Prong1 +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsProng1, tpcNClsCrossedRowsProng1, int); //! Number of TPC crossed rows of prongs of Prong1 +DECLARE_SOA_COLUMN(TpcChi2NClProng1, tpcChi2NClProng1, float); //! Maximum TPC chi2 of prongs of D-meson daughter candidate +DECLARE_SOA_COLUMN(ImpactParameterProng1, impactParameterProng1, float); //! Impact parameter product of bachelor pion +DECLARE_SOA_COLUMN(NSigTpcPiProng1, nSigTpcPiProng1, float); //! TPC Nsigma separation for prong1 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPiProng1, nSigTofPiProng1, float); //! TOF Nsigma separation for prong1 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPiProng1, nSigTpcTofPiProng1, float); //! Combined TPC and TOF Nsigma separation for prong1 with pion mass hypothesis +// MC truth +DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); //! Flag for association with wrong collision +DECLARE_SOA_COLUMN(PtGen, ptGen, float); //! Transverse momentum of candidate (GeV/c) +// General vars (unused for now) +DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c) +DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV) +} // namespace hf_cand_bs_lite + +DECLARE_SOA_TABLE(HfRedCandBsLites, "AOD", "HFREDCANDBSLITE", //! Table with some Bs properties + // B meson features + hf_cand_bs_lite::M, + hf_cand_bs_lite::Pt, + hf_cand_bs_lite::Eta, + hf_cand_bs_lite::Phi, + hf_cand_bs_lite::Y, + hf_cand_bs_lite::Cpa, + hf_cand_bs_lite::CpaXY, + 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::ImpactParameterProduct, + hf_cand_bs_lite::MaxNormalisedDeltaIP, + hf_cand_bs_lite::MlScoreSig, + hf_sel_candidate_bs::IsSelBsToDsPi, + // D meson features + hf_cand_bs_lite::MProng0, + hf_cand_bs_lite::PtProng0, + hf_cand_bs_lite::DecayLength0, + hf_cand_bs_lite::DecayLengthXY0, + hf_cand_bs_lite::ImpactParameter0, + hf_cand_bs_lite::PtDmesProngMin, + hf_cand_bs_lite::AbsEtaDmesProngMin, + hf_cand_bs_lite::ItsNClsDmesProngMin, + hf_cand_bs_lite::TpcNClsCrossedRowsDmesProngMin, + hf_cand_bs_lite::TpcChi2NClDmesProngMax, + hf_cand_bs_lite::NSigTpcPiDmesProng0, + hf_cand_bs_lite::NSigTofPiDmesProng0, + hf_cand_bs_lite::NSigTpcTofPiDmesProng0, + hf_cand_bs_lite::NSigTpcKaDmesProng1, + hf_cand_bs_lite::NSigTofKaDmesProng1, + hf_cand_bs_lite::NSigTpcTofKaDmesProng1, + hf_cand_bs_lite::NSigTpcPiDmesProng2, + hf_cand_bs_lite::NSigTofPiDmesProng2, + hf_cand_bs_lite::NSigTpcTofPiDmesProng2, + hf_cand_bs_reduced::Prong0MlScoreBkg, + hf_cand_bs_reduced::Prong0MlScorePrompt, + hf_cand_bs_reduced::Prong0MlScoreNonprompt, + // pion features + hf_cand_bs_lite::PtProng1, + hf_cand_bs_lite::AbsEtaProng1, + hf_cand_bs_lite::ItsNClsProng1, + hf_cand_bs_lite::TpcNClsCrossedRowsProng1, + hf_cand_bs_lite::TpcChi2NClProng1, + hf_cand_bs_lite::ImpactParameterProng1, + hf_cand_bs_lite::NSigTpcPiProng1, + hf_cand_bs_lite::NSigTofPiProng1, + hf_cand_bs_lite::NSigTpcTofPiProng1, + // MC truth + 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"}; + + using TracksPion = soa::Join; + using CandsDS = soa::Join; + + Filter filterSelectCandidates = (aod::hf_sel_candidate_bs::isSelBsToDsPi >= selectionFlagBs); + + HistogramRegistry registry{"registry"}; + + 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::BsToDsKToPhiPiKToKKPiK] = "B^{0}_{s} #rightarrow (D_{s} #rightarrow #Phi#pi #rightarrow KK#pi) K"; + labels[hf_cand_bs::DecayTypeMc::BsToDsKToK0starKKToKKPiK] = "B^{0}_{s} #rightarrow (D_{s} #rightarrow K^{0*}K #rightarrow KK#pi) K"; + 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, + CandsDmes 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 const posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; + std::array const posSvDs{candDs.xSecondaryVertex(), candDs.ySecondaryVertex(), candDs.zSecondaryVertex()}; + std::array const 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 (DoMc) { + 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 const 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( + // B meson features + invMassBs, + ptCandBs, + candidate.eta(), + candidate.phi(), + HfHelper::yBs(candidate), + candidate.cpa(), + candidate.cpaXY(), + candidate.chi2PCA(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.impactParameterProduct(), + candidate.maxNormalisedDeltaIP(), + candidateMlScoreSig, + candidate.isSelBsToDsPi(), + // D meson features + invMassDs, + ptDs, + decLenDs, + decLenXyDs, + candidate.impactParameter0(), + candDs.ptProngMin(), + candDs.absEtaProngMin(), + candDs.itsNClsProngMin(), + candDs.tpcNClsCrossedRowsProngMin(), + candDs.tpcChi2NClProngMax(), + candDs.tpcNSigmaPiProng0(), + candDs.tofNSigmaPiProng0(), + candDs.tpcTofNSigmaPiProng0(), + candDs.tpcNSigmaKaProng1(), + candDs.tofNSigmaKaProng1(), + candDs.tpcTofNSigmaKaProng1(), + candDs.tpcNSigmaKaProng2(), + candDs.tofNSigmaKaProng2(), + candDs.tpcTofNSigmaKaProng2(), + 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) { + 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 const 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, + CandsDS 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, + CandsDS 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, + CandsDS 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, + CandsDS 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, + CandsDS 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, + CandsDS 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, + CandsDS 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, + CandsDS 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, + CandsDS 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/taskBsToJpsiPhiReduced.cxx b/PWGHF/D2H/Tasks/taskBsToJpsiPhiReduced.cxx new file mode 100644 index 00000000000..2ff8dbe84e2 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskBsToJpsiPhiReduced.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 taskBsToJpsiPhiReduced.cxx +/// \brief Bs → Jpsi phi → (µ+ µ-) (K+K-) analysis task +/// +/// \author Fabrizio Chinu , Università degli Studi and INFN Torino +/// \author Fabrizio Grosa , CERN + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseBsToJpsiPhiReduced.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::pid_tpc_tof_utils; + +namespace o2::aod +{ +namespace hf_cand_bstojpsiphi_lite +{ +DECLARE_SOA_COLUMN(PtJpsi, ptJpsi, float); //! Transverse momentum of Jpsi daughter candidate (GeV/c) +DECLARE_SOA_COLUMN(PtBach0, ptBach0, float); //! Transverse momentum of bachelor kaon(<- phi) (GeV/c) +DECLARE_SOA_COLUMN(PtBach1, ptBach1, float); //! Transverse momentum of bachelor kaon(<- phi) (GeV/c) +DECLARE_SOA_COLUMN(ItsNClsJpsiDauPos, itsNClsJpsiDauPos, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsJpsiDauPos, tpcNClsCrossedRowsJpsiDauPos, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(ItsChi2NClJpsiDauPos, itsChi2NClJpsiDauPos, float); //! ITS chi2 / Number of clusters +DECLARE_SOA_COLUMN(TpcChi2NClJpsiDauPos, tpcChi2NClJpsiDauPos, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(AbsEtaJpsiDauPos, absEtaJpsiDauPos, float); //! |eta| +DECLARE_SOA_COLUMN(ItsNClsJpsiDauNeg, itsNClsJpsiDauNeg, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsJpsiDauNeg, tpcNClsCrossedRowsJpsiDauNeg, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(ItsChi2NClJpsiDauNeg, itsChi2NClJpsiDauNeg, float); //! ITS chi2 / Number of clusters +DECLARE_SOA_COLUMN(TpcChi2NClJpsiDauNeg, tpcChi2NClJpsiDauNeg, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(AbsEtaJpsiDauNeg, absEtaJpsiDauNeg, float); //! |eta| +DECLARE_SOA_COLUMN(ItsNClsLfTrack0, itsNClsLfTrack0, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsLfTrack0, tpcNClsCrossedRowsLfTrack0, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(ItsChi2NClLfTrack0, itsChi2NClLfTrack0, float); //! ITS chi2 / Number of clusters +DECLARE_SOA_COLUMN(TpcChi2NClLfTrack0, tpcChi2NClLfTrack0, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(AbsEtaLfTrack0, absEtaLfTrack0, float); //! |eta| +DECLARE_SOA_COLUMN(ItsNClsLfTrack1, itsNClsLfTrack1, int); //! Number of clusters in ITS +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsLfTrack1, tpcNClsCrossedRowsLfTrack1, int); //! Number of TPC crossed rows +DECLARE_SOA_COLUMN(ItsChi2NClLfTrack1, itsChi2NClLfTrack1, float); //! ITS chi2 / Number of clusters +DECLARE_SOA_COLUMN(TpcChi2NClLfTrack1, tpcChi2NClLfTrack1, float); //! TPC chi2 / Number of clusters +DECLARE_SOA_COLUMN(AbsEtaLfTrack1, absEtaLfTrack1, float); //! |eta| +DECLARE_SOA_COLUMN(MJpsi, mJpsi, float); //! Invariant mass of Jpsi daughter candidates (GeV/c) +DECLARE_SOA_COLUMN(MPhi, mPhi, float); //! Invariant mass of phi 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(NSigTpcKaBachelor0, nSigTpcKaBachelor0, float); //! TPC Nsigma separation for bachelor 0 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofKaBachelor0, nSigTofKaBachelor0, float); //! TOF Nsigma separation for bachelor 0 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofKaBachelor0, nSigTpcTofKaBachelor0, float); //! Combined TPC and TOF Nsigma separation for bachelor 0 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcKaBachelor1, nSigTpcKaBachelor1, float); //! TPC Nsigma separation for bachelor 1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofKaBachelor1, nSigTofKaBachelor1, float); //! TOF Nsigma separation for bachelor 1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofKaBachelor1, nSigTpcTofKaBachelor1, float); //! Combined TPC and TOF Nsigma separation for bachelor 1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcMuJpsiDauPos, nSigTpcMuJpsiDauPos, float); //! TPC Nsigma separation for Jpsi DauPos with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofMuJpsiDauPos, nSigTofMuJpsiDauPos, float); //! TOF Nsigma separation for Jpsi DauPos with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofMuJpsiDauPos, nSigTpcTofMuJpsiDauPos, float); //! Combined TPC and TOF Nsigma separation for Jpsi prong0 with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcMuJpsiDauNeg, nSigTpcMuJpsiDauNeg, float); //! TPC Nsigma separation for Jpsi DauNeg with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofMuJpsiDauNeg, nSigTofMuJpsiDauNeg, float); //! TOF Nsigma separation for Jpsi DauNeg with muon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofMuJpsiDauNeg, nSigTpcTofMuJpsiDauNeg, float); //! Combined TPC and TOF Nsigma separation for Jpsi prong1 with muon 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(CtXY, ctXY, float); //! Pseudo-proper decay length of candidate +DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! Impact parameter product of B daughters +DECLARE_SOA_COLUMN(ImpactParameterProductJpsi, impactParameterProductJpsi, float); //! Impact parameter product of Jpsi daughters +DECLARE_SOA_COLUMN(ImpactParameterProductPhi, impactParameterProductPhi, float); //! Impact parameter product of Phi daughters +DECLARE_SOA_COLUMN(ImpactParameterJpsiDauPos, impactParameterJpsiDauPos, float); //! Impact parameter of Jpsi daughter candidate +DECLARE_SOA_COLUMN(ImpactParameterJpsiDauNeg, impactParameterJpsiDauNeg, float); //! Impact parameter of Jpsi daughter candidate +DECLARE_SOA_COLUMN(ImpactParameterLfTrack0, impactParameterLfTrack0, float); //! Impact parameter of Phi daughter candidate +DECLARE_SOA_COLUMN(ImpactParameterLfTrack1, impactParameterLfTrack1, float); //! Impact parameter of Phi daughter 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(CpaJpsi, cpaJpsi, float); //! Cosine pointing angle of Jpsi daughter candidate +DECLARE_SOA_COLUMN(CpaXYJpsi, cpaXYJpsi, float); //! Cosine pointing angle in transverse plane of Jpsi 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_bstojpsiphi_lite + +DECLARE_SOA_TABLE(HfRedCandBsLites, "AOD", "HFREDCANDBSLITE", //! Table with some Bs properties + hf_cand_bstojpsiphi_lite::M, + hf_cand_bstojpsiphi_lite::Pt, + hf_cand_bstojpsiphi_lite::Eta, + hf_cand_bstojpsiphi_lite::Phi, + hf_cand_bstojpsiphi_lite::Y, + hf_cand_bstojpsiphi_lite::Cpa, + hf_cand_bstojpsiphi_lite::CpaXY, + hf_cand::Chi2PCA, + hf_cand_bstojpsiphi_lite::DecayLength, + hf_cand_bstojpsiphi_lite::DecayLengthXY, + hf_cand_bstojpsiphi_lite::DecayLengthNormalised, + hf_cand_bstojpsiphi_lite::DecayLengthXYNormalised, + hf_cand_bstojpsiphi_lite::CtXY, + hf_cand_bstojpsiphi_lite::ImpactParameterProduct, + hf_cand_bstojpsiphi_lite::ImpactParameterProductJpsi, + hf_cand_bstojpsiphi_lite::ImpactParameterProductPhi, + hf_cand_bstojpsiphi_lite::MaxNormalisedDeltaIP, + hf_cand_bstojpsiphi_lite::MlScoreSig, + // hf_sel_candidate_bplus::IsSelBsToJpsiPi, + // Jpsi meson features + hf_cand_bstojpsiphi_lite::MJpsi, + hf_cand_bstojpsiphi_lite::PtJpsi, + hf_cand_bstojpsiphi_lite::MPhi, + hf_cand_bstojpsiphi_lite::ImpactParameterJpsiDauPos, + hf_cand_bstojpsiphi_lite::ImpactParameterJpsiDauNeg, + hf_cand_bstojpsiphi_lite::ImpactParameterLfTrack0, + hf_cand_bstojpsiphi_lite::ImpactParameterLfTrack1, + // Jpsi daughter features + hf_cand_bstojpsiphi_lite::ItsNClsJpsiDauPos, + hf_cand_bstojpsiphi_lite::TpcNClsCrossedRowsJpsiDauPos, + hf_cand_bstojpsiphi_lite::ItsChi2NClJpsiDauPos, + hf_cand_bstojpsiphi_lite::TpcChi2NClJpsiDauPos, + hf_cand_bstojpsiphi_lite::AbsEtaJpsiDauPos, + hf_cand_bstojpsiphi_lite::ItsNClsJpsiDauNeg, + hf_cand_bstojpsiphi_lite::TpcNClsCrossedRowsJpsiDauNeg, + hf_cand_bstojpsiphi_lite::ItsChi2NClJpsiDauNeg, + hf_cand_bstojpsiphi_lite::TpcChi2NClJpsiDauNeg, + hf_cand_bstojpsiphi_lite::AbsEtaJpsiDauNeg, + // kaon features + hf_cand_bstojpsiphi_lite::PtBach0, + hf_cand_bstojpsiphi_lite::ItsNClsLfTrack0, + hf_cand_bstojpsiphi_lite::TpcNClsCrossedRowsLfTrack0, + hf_cand_bstojpsiphi_lite::ItsChi2NClLfTrack0, + hf_cand_bstojpsiphi_lite::TpcChi2NClLfTrack0, + hf_cand_bstojpsiphi_lite::AbsEtaLfTrack0, + hf_cand_bstojpsiphi_lite::NSigTpcKaBachelor0, + hf_cand_bstojpsiphi_lite::NSigTofKaBachelor0, + hf_cand_bstojpsiphi_lite::NSigTpcTofKaBachelor0, + hf_cand_bstojpsiphi_lite::PtBach1, + hf_cand_bstojpsiphi_lite::ItsNClsLfTrack1, + hf_cand_bstojpsiphi_lite::TpcNClsCrossedRowsLfTrack1, + hf_cand_bstojpsiphi_lite::ItsChi2NClLfTrack1, + hf_cand_bstojpsiphi_lite::TpcChi2NClLfTrack1, + hf_cand_bstojpsiphi_lite::AbsEtaLfTrack1, + hf_cand_bstojpsiphi_lite::NSigTpcKaBachelor1, + hf_cand_bstojpsiphi_lite::NSigTofKaBachelor1, + hf_cand_bstojpsiphi_lite::NSigTpcTofKaBachelor1, + // MC truth + hf_cand_bs::FlagMcMatchRec, + hf_cand_bs::FlagMcDecayChanRec, + hf_cand_bs::OriginMcRec, + hf_cand_bstojpsiphi_lite::FlagWrongCollision, + hf_cand_bstojpsiphi_lite::PtGen); + +// DECLARE_SOA_TABLE(HfRedBsMcCheck, "AOD", "HFREDBPMCCHECK", //! Table with MC decay type check +// hf_cand_2prong::FlagMcMatchRec, +// hf_cand_bstojpsiphi_lite::FlagWrongCollision, +// hf_cand_bstojpsiphi_lite::MJpsi, +// hf_cand_bstojpsiphi_lite::PtJpsi, +// hf_cand_bstojpsiphi_lite::M, +// hf_cand_bstojpsiphi_lite::Pt, +// // hf_cand_bstojpsiphi_lite::MlScoreSig, +// hf_bplus_mc::PdgCodeBeautyMother, +// hf_bplus_mc::PdgCodeCharmMother, +// hf_bplus_mc::PdgCodeDauPos, +// hf_bplus_mc::PdgCodeDauNeg, +// 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 stringPtJpsi = "#it{p}_{T}(Jpsi) (GeV/#it{c});"; +const TString bSCandTitle = "B_{s}^{0} candidates;"; +const TString entries = "entries"; +const TString bSCandMatch = "B_{s}^{0} candidates (matched);"; +const TString bSCandUnmatch = "B_{s}^{0} candidates (unmatched);"; +const TString mcParticleMatched = "MC particles (matched);"; + +/// Bs analysis task +struct HfTaskBsToJpsiPhiReduced { + 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"}; + Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track transverse momentum"}; + 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"}; + // topological cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_bs_to_jpsi_phi::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_bs_to_jpsi_phi::Cuts[0], hf_cuts_bs_to_jpsi_phi::NBinsPt, hf_cuts_bs_to_jpsi_phi::NCutVars, hf_cuts_bs_to_jpsi_phi::labelsPt, hf_cuts_bs_to_jpsi_phi::labelsCutVar}, "Bs candidate selection per pT bin"}; + // Enable PID + Configurable kaonPidMethod{"kaonPidMethod", PidMethod::TpcOrTof, "PID selection method for the bachelor kaon (PidMethod::NoPid: none, PidMethod::TpcOrTof: TPC or TOF, PidMethod::TpcAndTof: 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"}; + // Bs ML inference + 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_BSToJpsiPhi.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"}; + + TrackSelectorKa selectorKaon; + o2::analysis::HfMlResponseBsToJpsiPhiReduced hfMlResponse; + o2::ccdb::CcdbApi ccdbApi; + + using TracksKaon = soa::Join; + std::vector outputMl; + + // Filter filterSelectCandidates = (aod::hf_sel_candidate_bplus::isSelBsToJpsiPi >= selectionFlagBs); + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + std::array processFuncData{doprocessData, 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, doprocessMcWithBsMl}; + if ((std::accumulate(processFuncMc.begin(), processFuncMc.end(), 0)) > 1) { + LOGP(fatal, "Only one process function for MC can be enabled at a time."); + } + + if (kaonPidMethod < 0 || kaonPidMethod >= PidMethod::NPidMethods) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (kaonPidMethod != PidMethod::NoPid) { + selectorKaon.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); + selectorKaon.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); + selectorKaon.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); + selectorKaon.setRangePtTof(ptPidTofMin, ptPidTofMax); + selectorKaon.setRangeNSigmaTof(-nSigmaTofMax, nSigmaTofMax); + selectorKaon.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedMax, nSigmaTofCombinedMax); + } + + const AxisSpec axisMassBs{150, 4.5, 6.0}; + const AxisSpec axisMassJpsi{600, 2.8f, 3.4f}; + const AxisSpec axisMassPhi{200, 0.9f, 1.1f}; + const AxisSpec axisPtProng{100, 0., 10.}; + const AxisSpec axisImpactPar{200, -0.05, 0.05}; + const AxisSpec axisPtJpsi{100, 0., 50.}; + const AxisSpec axisRapidity{100, -2., 2.}; + const AxisSpec axisPtB{(std::vector)binsPt, "#it{p}_{T}^{B_{s}^{0}} (GeV/#it{c})"}; + const AxisSpec axisPtKa{100, 0.f, 10.f}; + const AxisSpec axisPtPhi{100, 0.f, 10.f}; + + registry.add("hMass", bSCandTitle + "inv. mass J/#Psi K^{+} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassBs, axisPtB}}); + registry.add("hMassJpsi", bSCandTitle + "inv. mass #mu^{+}#mu^{#minus} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassJpsi, axisPtJpsi}}); + registry.add("hMassPhi", bSCandTitle + "inv. mass K^{+}K^{#minus} (GeV/#it{c}^{2});" + stringPt, {HistType::kTH2F, {axisMassPhi, axisPtPhi}}); + registry.add("hd0K", bSCandTitle + "Kaon DCAxy to prim. vertex (cm);" + stringPt, {HistType::kTH2F, {axisImpactPar, axisPtKa}}); + + // histograms processMC + if (doprocessMc || doprocessMcWithBsMl) { + registry.add("hPtJpsiGen", mcParticleMatched + "J/#Psi #it{p}_{T}^{gen} (GeV/#it{c}); B_{s}^{0} " + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hPtPhiGen", mcParticleMatched + "#phi #it{p}_{T}^{gen} (GeV/#it{c}); B_{s}^{0} " + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hPtKGen", mcParticleMatched + "Kaon #it{p}_{T}^{gen} (GeV/#it{c}); B_{s}^{0} " + stringPt, {HistType::kTH2F, {axisPtProng, axisPtB}}); + registry.add("hYGenWithProngsInAcceptance", mcParticleMatched + "B_{s}^{0} #it{p}_{T}^{gen} (GeV/#it{c}); B_{s}^{0} #it{y}", {HistType::kTH2F, {axisPtProng, axisRapidity}}); + registry.add("hMassRecSig", bSCandMatch + "inv. mass J/#Psi K^{+} (GeV/#it{c}^{2}); B_{s}^{0} " + stringPt, {HistType::kTH2F, {axisMassBs, axisPtB}}); + registry.add("hMassJpsiRecSig", bSCandMatch + "inv. mass #mu^{+}#mu^{#minus} (GeV/#it{c}^{2}); J/#Psi " + stringPt, {HistType::kTH2F, {axisMassJpsi, axisPtJpsi}}); + registry.add("hMassPhiRecSig", bSCandMatch + "inv. mass K^{+}K^{#minus} (GeV/#it{c}^{2}); #phi " + stringPt, {HistType::kTH2F, {axisMassPhi, axisPtPhi}}); + registry.add("hd0KRecSig", bSCandMatch + "Kaon DCAxy to prim. vertex (cm); K^{+} " + stringPt, {HistType::kTH2F, {axisImpactPar, axisPtKa}}); + registry.add("hMassRecBg", bSCandUnmatch + "inv. mass J/#Psi K^{+} (GeV/#it{c}^{2}); B_{s}^{0} " + stringPt, {HistType::kTH2F, {axisMassBs, axisPtB}}); + registry.add("hMassJpsiRecBg", bSCandUnmatch + "inv. mass #mu^{+}#mu^{#minus} (GeV/#it{c}^{2}); J/#Psi " + stringPt, {HistType::kTH2F, {axisMassJpsi, axisPtJpsi}}); + registry.add("hMassPhiRecBg", bSCandMatch + "inv. mass K^{+}K^{#minus} (GeV/#it{c}^{2}); #phi " + stringPt, {HistType::kTH2F, {axisMassPhi, axisPtPhi}}); + registry.add("hd0KRecBg", bSCandMatch + "Kaon DCAxy to prim. vertex (cm); K^{+} " + stringPt, {HistType::kTH2F, {axisImpactPar, axisPtKa}}); + } + + if (doprocessDataWithBsMl || doprocessMcWithBsMl) { + 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(); + } + } + + /// 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; + } + + /// Calculate pseudorapidity from track tan(lambda) + /// \param tgl is the track tangent of the dip angle + /// \return pseudorapidity + float absEta(float tgl) + { + return std::abs(std::log(std::tan(o2::constants::math::PIQuarter - 0.5f * std::atan(tgl)))); + } + + /// Fill candidate information at reconstruction level + /// \param doMc is the flag to enable the filling with MC information + /// \param withBsMl is the flag to enable the filling with ML scores for the Bs candidate + /// \param candidate is the Bs candidate + /// \param candidatesJpsi is the table with Jpsi candidates + template + void fillCand(Cand const& candidate, + aod::HfRedJpsis const& /*candidatesJpsi*/, + aod::HfRedBach0Tracks const&, + aod::HfRedBach1Tracks const&) + { + auto ptCandBs = candidate.pt(); + auto invMassBs = HfHelper::invMassBsToJpsiPhi(candidate); + auto candJpsi = candidate.template jpsi_as(); + auto candKa0 = candidate.template prong0Phi_as(); + auto candKa1 = candidate.template prong1Phi_as(); + std::array const pVecKa0 = {candKa0.px(), candKa0.py(), candKa0.pz()}; + std::array const pVecKa1 = {candKa1.px(), candKa1.py(), candKa1.pz()}; + auto ptJpsi = candidate.ptProng0(); + auto invMassJpsi = candJpsi.m(); + auto invMassPhi = RecoDecay::m(std::array{pVecKa0, pVecKa1}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}); + uint8_t statusBs = 0; + + int8_t flagMcMatchRec{0}, flagMcDecayChanRec{0}, flagWrongCollision{0}; + bool isSignal = false; + if constexpr (DoMc) { + flagMcMatchRec = candidate.flagMcMatchRec(); + flagMcDecayChanRec = candidate.flagMcDecayChanRec(); + flagWrongCollision = candidate.flagWrongCollision(); + isSignal = flagMcMatchRec == o2::hf_decay::hf_cand_beauty::BsToJpsiKK && + flagMcDecayChanRec == o2::hf_decay::hf_cand_beauty::BsToJpsiPhi; + } + + SETBIT(statusBs, SelectionStep::RecoSkims); + if (HfHelper::selectionBsToJpsiPhiTopol(candidate, candKa0, candKa1, cuts, binsPt)) { + SETBIT(statusBs, SelectionStep::RecoTopol); + } else if (selectionFlagBs >= BIT(SelectionStep::RecoTopol) * 2 - 1) { + return; + } + // track-level PID selection + // auto trackKa = candidate.template prong1_as(); + if (kaonPidMethod == PidMethod::TpcOrTof || kaonPidMethod == PidMethod::TpcAndTof) { + int pidTrackKa0{TrackSelectorPID::Status::NotApplicable}; + int pidTrackKa1{TrackSelectorPID::Status::NotApplicable}; + if (kaonPidMethod == PidMethod::TpcOrTof) { + pidTrackKa0 = selectorKaon.statusTpcOrTof(candKa0); + pidTrackKa1 = selectorKaon.statusTpcOrTof(candKa1); + } else if (kaonPidMethod == PidMethod::TpcAndTof) { + pidTrackKa0 = selectorKaon.statusTpcAndTof(candKa0); + pidTrackKa1 = selectorKaon.statusTpcAndTof(candKa1); + } + if (HfHelper::selectionBsToJpsiPhiPid(pidTrackKa0, acceptPIDNotApplicable.value) && + HfHelper::selectionBsToJpsiPhiPid(pidTrackKa1, acceptPIDNotApplicable.value)) { + // LOGF(info, "Bs candidate selection failed at PID selection"); + SETBIT(statusBs, SelectionStep::RecoPID); + } else if (selectionFlagBs >= BIT(SelectionStep::RecoPID) * 2 - 1) { + return; + } + } + + float candidateMlScoreSig = -1; + if constexpr (WithBsMl) { + // Bs ML selections + std::vector inputFeatures = hfMlResponse.getInputFeatures(candidate, candKa0, candKa1); + if (hfMlResponse.isSelectedMl(inputFeatures, ptCandBs, outputMl)) { + SETBIT(statusBs, SelectionStep::RecoMl); + } else if (selectionFlagBs >= BIT(SelectionStep::RecoMl) * 2 - 1) { + return; + } + candidateMlScoreSig = outputMl[1]; + } + + registry.fill(HIST("hMass"), invMassBs, ptCandBs); + registry.fill(HIST("hMassJpsi"), invMassJpsi, candidate.ptProng0()); + registry.fill(HIST("hMassPhi"), invMassPhi, candidate.ptProng0()); + registry.fill(HIST("hd0K"), candidate.impactParameter1(), candidate.ptProng1()); + if constexpr (DoMc) { + if (isSignal) { + registry.fill(HIST("hMassRecSig"), invMassBs, ptCandBs); + registry.fill(HIST("hMassJpsiRecSig"), invMassJpsi, candidate.ptProng0()); + registry.fill(HIST("hd0KRecSig"), candidate.impactParameter1(), candidate.ptProng1()); + } else if (fillBackground) { + registry.fill(HIST("hMassRecBg"), invMassBs, ptCandBs); + registry.fill(HIST("hMassJpsiRecBg"), invMassJpsi, candidate.ptProng0()); + registry.fill(HIST("hd0KRecBg"), candidate.impactParameter1(), candidate.ptProng1()); + } + } + + float const pseudoRndm = ptJpsi * 1000. - static_cast(ptJpsi * 1000); + if (ptCandBs >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor) { + float ptMother = -1.; + if constexpr (DoMc) { + ptMother = candidate.ptMother(); + } + + hfRedCandBsLite( + // Bs - meson features + invMassBs, + ptCandBs, + candidate.eta(), + candidate.phi(), + HfHelper::yBs(candidate), + candidate.cpa(), + candidate.cpaXY(), + candidate.chi2PCA(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.ctXY(std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus}), + candidate.impactParameterProduct(), + candidate.impactParameterProductJpsi(), + candidate.impactParameterProductPhi(), + candidate.maxNormalisedDeltaIP(), + candidateMlScoreSig, + // J/Psi features + invMassJpsi, + ptJpsi, + invMassPhi, + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameter2(), + candidate.impactParameter3(), + candJpsi.itsNClsDauPos(), + candJpsi.tpcNClsCrossedRowsDauPos(), + candJpsi.itsChi2NClDauPos(), + candJpsi.tpcChi2NClDauPos(), + absEta(candJpsi.tglDauPos()), + candJpsi.itsNClsDauNeg(), + candJpsi.tpcNClsCrossedRowsDauNeg(), + candJpsi.itsChi2NClDauNeg(), + candJpsi.tpcChi2NClDauNeg(), + absEta(candJpsi.tglDauNeg()), + // kaon features + candKa0.pt(), + candKa0.itsNCls(), + candKa0.tpcNClsCrossedRows(), + candKa0.itsChi2NCl(), + candKa0.tpcChi2NCl(), + absEta(candKa0.tgl()), + // candKa.absEtaBach(candKa.tgl()), + candKa0.tpcNSigmaKa(), + candKa0.tofNSigmaKa(), + candKa0.tpcTofNSigmaKa(), + candKa1.pt(), + candKa1.itsNCls(), + candKa1.tpcNClsCrossedRows(), + candKa1.itsChi2NCl(), + candKa1.tpcChi2NCl(), + absEta(candKa1.tgl()), + candKa1.tpcNSigmaKa(), + candKa1.tofNSigmaKa(), + candKa1.tpcTofNSigmaKa(), + // MC truth + flagMcMatchRec, + flagMcDecayChanRec, + isSignal, + flagWrongCollision, + ptMother); + } + } + + /// Fill particle histograms (gen MC truth) + void fillCandMcGen(aod::HfMcGenRedBss::iterator const& particle) + { + auto ptParticle = particle.ptTrack(); + auto yParticle = particle.yTrack(); + if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + return; + } + std::array ptProngs = {particle.ptProng0(), particle.ptProng1()}; + std::array etaProngs = {particle.etaProng0(), particle.etaProng1()}; + bool const prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); + + registry.fill(HIST("hPtJpsiGen"), ptProngs[0], ptParticle); + registry.fill(HIST("hPtKGen"), ptProngs[1], ptParticle); + + // generated Bs with daughters in geometrical acceptance + if (prongsInAcc) { + registry.fill(HIST("hYGenWithProngsInAcceptance"), ptParticle, yParticle); + } + } + + // Process functions + void processData(aod::HfRedCandBsToJpsiPhi const& candidates, + aod::HfRedJpsis const& candidatesJpsi, + aod::HfRedBach0Tracks const& kaon0Tracks, + aod::HfRedBach1Tracks const& kaon1Tracks) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesJpsi, kaon0Tracks, kaon1Tracks); + } // candidate loop + } // processData + PROCESS_SWITCH(HfTaskBsToJpsiPhiReduced, processData, "Process data without ML for Bs", true); + + void processDataWithBsMl(aod::HfRedCandBsToJpsiPhi const& candidates, + aod::HfRedJpsis const& candidatesJpsi, + aod::HfRedBach0Tracks const& kaon0Tracks, + aod::HfRedBach1Tracks const& kaon1Tracks) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesJpsi, kaon0Tracks, kaon1Tracks); + } // candidate loop + } // processDataWithBsMl + PROCESS_SWITCH(HfTaskBsToJpsiPhiReduced, processDataWithBsMl, "Process data with ML for Bs", false); + + void processMc(soa::Join const& candidates, + aod::HfMcGenRedBss const& mcParticles, + aod::HfRedJpsis const& candidatesJpsi, + aod::HfRedBach0Tracks const& kaon0Tracks, + aod::HfRedBach1Tracks const& kaon1Tracks) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesJpsi, kaon0Tracks, kaon1Tracks); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskBsToJpsiPhiReduced, processMc, "Process MC without ML for Bs", false); + + void processMcWithBsMl(soa::Join const& candidates, + aod::HfMcGenRedBss const& mcParticles, + aod::HfRedJpsis const& candidatesJpsi, + aod::HfRedBach0Tracks const& kaon0Tracks, + aod::HfRedBach1Tracks const& kaon1Tracks) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yBs(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesJpsi, kaon0Tracks, kaon1Tracks); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcWithBsMl + PROCESS_SWITCH(HfTaskBsToJpsiPhiReduced, processMcWithBsMl, "Process MC with ML for Bs", false); + +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskCd.cxx b/PWGHF/D2H/Tasks/taskCd.cxx new file mode 100644 index 00000000000..0e43e6dd990 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskCd.cxx @@ -0,0 +1,277 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file taskCd.cxx +/// \brief Cd± → d± K∓ π± analysis task +/// \author Biao Zhang , Heidelberg Universiity + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include // std::vector + +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; +using namespace o2::hf_evsel; + +struct HfTaskCd { + Configurable selectionFlagCd{"selectionFlagCd", 1, "Selection Flag for Cd"}; + Configurable> binsPt{"binsPt", std::vector{hf_cuts_cd_to_de_k_pi::vecBinsPt}, "pT bin limits"}; + Configurable fillTHn{"fillTHn", false, "fill THn"}; + + SliceCache cache; + + using CollisionsWEvSel = soa::Join; + using CollisionsWithEvSelFT0C = soa::Join; + using CollisionsWithEvSelFT0M = soa::Join; + + using CdCandidates = soa::Filtered>; + + Filter filterSelectCandidates = aod::hf_sel_candidate_cd::isSelCdToDeKPi >= selectionFlagCd; + Preslice candCdPerCollision = aod::hf_cand::collisionId; + + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {72, 0, 36}, ""}; + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {400, 2.4, 4.4}, ""}; + ConfigurableAxis thnConfigAxisPtProng{"thnConfigAxisPtProng", {100, 0, 20}, ""}; + ConfigurableAxis thnConfigAxisChi2PCA{"thnConfigAxisChi2PCA", {100, 0, 20}, ""}; + ConfigurableAxis thnConfigAxisDecLength{"thnConfigAxisDecLength", {10, 0, 0.05}, ""}; + ConfigurableAxis thnConfigAxisCPA{"thnConfigAxisCPA", {20, 0.8, 1}, ""}; + ConfigurableAxis thnConfigAxisCentrality{"thnConfigAxisCentrality", {100, 0, 100}, ""}; + + HistogramRegistry registry{ + "registry", + {/// mass candidate + {"Data/hMass", "3-prong candidates;inv. mass (de K #pi) (GeV/#it{c}^{2})", {HistType::kTH1F, {{400, 2.4, 4.4}}}}, + /// pT + {"Data/hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, + {"Data/hPtProng0", "3-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, + {"Data/hPtProng1", "3-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, + {"Data/hPtProng2", "3-prong candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, + /// 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}}}}, + {"Data/hd0Prong1", "3-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, + {"Data/hd0Prong2", "3-prong candidates;prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, + /// decay length candidate + {"Data/hDecLength", "3-prong candidates;decay length (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, + /// decay length xy candidate + {"Data/hDecLengthxy", "3-prong candidates;decay length xy (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, + /// cosine of pointing angle + {"Data/hCPA", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, + /// cosine of pointing angle xy + {"Data/hCPAxy", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, + /// Chi 2 PCA to sec. vertex + {"Data/hDca2", "3-prong candidates;prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH1F, {{400, 0., 20.}}}}, + /// eta + {"Data/hEta", "3-prong candidates;#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + /// phi + {"Data/hPhi", "3-prong candidates;#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}}}; + + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + std::array doprocess{doprocessDataStd, doprocessDataStdWithFT0C, doprocessDataStdWithFT0M}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "no or more than one process function enabled! Please check your configuration!"); + } + /// mass candidate + registry.add("Data/hMassVsPtVsNPvContributors", "3-prong candidates;inv. mass (de K #pi) (GeV/#it{c}^{2}); p_{T}; Number of PV contributors", {HistType::kTH3F, {{400, 2.4, 4.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}, {500, 0., 5000.}}}); + registry.add("Data/hMassVsPt", "3-prong candidates;inv. mass (de K #pi) (GeV/#it{c}^{2}); p_{T}", {HistType::kTH2F, {{400, 2.4, 4.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// DCAxy to prim. vertex prongs + registry.add("Data/hd0VsPtProng0", "3-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/hd0VsPtProng1", "3-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/hd0VsPtProng2", "3-prong candidates;prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// decay length candidate + registry.add("Data/hDecLengthVsPt", "3-prong candidates;decay length (cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// decay length xy candidate + registry.add("Data/hDecLengthxyVsPt", "3-prong candidates;decay length xy(cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// cosine of pointing angle + registry.add("Data/hCPAVsPt", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// cosine of pointing angle xy + registry.add("Data/hCPAxyVsPt", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// Chi 2 PCA to sec. vertex + registry.add("Data/hDca2VsPt", "3-prong candidates;prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH2F, {{400, 0., 20.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// eta + registry.add("Data/hEtaVsPt", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// phi + registry.add("Data/hPhiVsPt", "3-prong candidates;candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// selection status + registry.add("hSelectionStatus", "3-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// impact parameter error + registry.add("Data/hImpParErrProng0", "3-prong candidates;prong 0 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/hImpParErrProng1", "3-prong candidates;prong 1 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/hImpParErrProng2", "3-prong candidates;prong 2 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + + if (fillTHn) { + const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (de K #pi) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T}(C_{d}^{+}) (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 thnAxisChi2PCA{thnConfigAxisChi2PCA, "Chi2PCA to sec. vertex (cm)"}; + const AxisSpec thnAxisDecLength{thnConfigAxisDecLength, "decay length (cm)"}; + const AxisSpec thnAxisCPA{thnConfigAxisCPA, "cosine of pointing angle"}; + const AxisSpec thnAxisCentrality{thnConfigAxisCentrality, "centrality (FT0C)"}; + + std::vector axesStd{thnAxisMass, thnAxisPt, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisCentrality}; + registry.add("hnCdVars", "THn for Reconstructed Cd candidates for data", HistType::kTHnSparseF, axesStd); + } + } + + /// Fill histograms for real data + template + void fillHistosData(CollType const& collision, CandType const& candidates) + { + auto thisCollId = collision.globalIndex(); + auto groupedCdCandidates = candidates.sliceBy(candCdPerCollision, thisCollId); + auto numPvContributors = collision.numContrib(); + + for (const auto& candidate : groupedCdCandidates) { + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::CdToDeKPi)) { + continue; + } + + const auto pt = candidate.pt(); + const auto ptProng0 = candidate.ptProng0(); + const auto ptProng1 = candidate.ptProng1(); + const auto ptProng2 = candidate.ptProng2(); + const auto decayLength = candidate.decayLength(); + const auto decayLengthXY = candidate.decayLengthXY(); + const auto chi2PCA = candidate.chi2PCA(); + const auto cpa = candidate.cpa(); + const auto cpaXY = candidate.cpaXY(); + + if (candidate.isSelCdToDeKPi() >= selectionFlagCd) { + registry.fill(HIST("Data/hMass"), HfHelper::invMassCdToDeKPi(candidate)); + registry.fill(HIST("Data/hMassVsPtVsNPvContributors"), HfHelper::invMassCdToDeKPi(candidate), pt, numPvContributors); + registry.fill(HIST("Data/hMassVsPt"), HfHelper::invMassCdToDeKPi(candidate), pt); + } + if (candidate.isSelCdToPiKDe() >= selectionFlagCd) { + registry.fill(HIST("Data/hMass"), HfHelper::invMassCdToPiKDe(candidate)); + registry.fill(HIST("Data/hMassVsPtVsNPvContributors"), HfHelper::invMassCdToPiKDe(candidate), pt, numPvContributors); + registry.fill(HIST("Data/hMassVsPt"), HfHelper::invMassCdToPiKDe(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/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.isSelCdToDeKPi(), pt); + registry.fill(HIST("hSelectionStatus"), candidate.isSelCdToPiKDe(), 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); + + if (fillTHn) { + float const cent = o2::hf_centrality::getCentralityColl(collision); + double massCd(-1); + if (candidate.isSelCdToDeKPi() >= selectionFlagCd) { + massCd = HfHelper::invMassCdToDeKPi(candidate); + std::vector valuesToFill{massCd, pt, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, cent}; + registry.get(HIST("hnCdVars"))->Fill(valuesToFill.data()); + } + if (candidate.isSelCdToPiKDe() >= selectionFlagCd) { + massCd = HfHelper::invMassCdToPiKDe(candidate); + std::vector valuesToFill{massCd, pt, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, cent}; + registry.get(HIST("hnCdVars"))->Fill(valuesToFill.data()); + } + } + } + } + /// Run the analysis on real data + template + void runAnalysisPerCollisionData(CollType const& collisions, + CandType const& candidates) + { + + for (const auto& collision : collisions) { + fillHistosData(collision, candidates); + } + } + + void processDataStd(CollisionsWEvSel const& collisions, + CdCandidates const& selectedCdCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedCdCandidates); + } + PROCESS_SWITCH(HfTaskCd, processDataStd, "Process Data with the standard method", true); + + void processDataStdWithFT0C(CollisionsWithEvSelFT0C const& collisions, + CdCandidates const& selectedCdCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedCdCandidates); + } + PROCESS_SWITCH(HfTaskCd, processDataStdWithFT0C, "Process real data with the standard method and with FT0C centrality", false); + + void processDataStdWithFT0M(CollisionsWithEvSelFT0M const& collisions, + CdCandidates const& selectedCdCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedCdCandidates); + } + PROCESS_SWITCH(HfTaskCd, processDataStdWithFT0M, "Process real data with the standard method and with FT0M centrality", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx b/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx index 0e001bf50fb..0795d6361a2 100644 --- a/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx +++ b/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx @@ -15,22 +15,48 @@ /// \author F. Grosa (CERN) fabrizio.grosa@cern.ch /// \author S. Kundu (CERN) sourav.kundu@cern.ch /// \author M. Faggin (CERN) mattia.faggin@cern.ch +/// \author M. Li (CCNU) mingze.li@cern.ch -#include "TRandom3.h" -#include "Math/Vector3D.h" -#include "Math/Vector4D.h" -#include "Math/GenVector/Boost.h" - -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - -// #include "Common/Core/EventPlaneHelper.h" -// #include "Common/DataModel/Qvectors.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include // IWYU pragma: keep (do not replace with Math/Vector3Dfwd.h) +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -46,6 +72,7 @@ enum CosThetaStarType : uint8_t { Production, Beam, Random, + EP, NTypes }; enum DecayChannel : uint8_t { @@ -59,6 +86,11 @@ enum MassHyposLcToPKPi : uint8_t { PiKP, NMassHypoLcToPKPi }; +enum QvecEstimator : uint8_t { + FV0A = 0, + FT0M, + FT0C, +}; /// columns for table to study the Lc->PKPi background DECLARE_SOA_COLUMN(MassLc, massLc, float); @@ -72,9 +104,12 @@ 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 @@ -91,13 +126,16 @@ DECLARE_SOA_TABLE(HfLcPolBkg, "AOD", "HFLCPOLBKG", charm_polarisation::MassKProton, charm_polarisation::MassPiProton, charm_polarisation::BdtBkgScore, + charm_polarisation::BdtNonPromptScore, charm_polarisation::IsRealPKPi, charm_polarisation::IsRealLcPKPi, - charm_polarisation::IsReflected); + charm_polarisation::IsReflected, + charm_polarisation::Charge, + charm_polarisation::Origin); } // namespace o2::aod -struct TaskPolarisationCharmHadrons { +struct HfTaskCharmPolarisation { Produces rowCandLcBkg; float massPi{0.f}; @@ -112,24 +150,11 @@ struct TaskPolarisationCharmHadrons { Configurable selectionFlagDstarToD0Pi{"selectionFlagDstarToD0Pi", true, "Selection Flag for D* decay to D0 Pi"}; Configurable selectionFlagLcToPKPi{"selectionFlagLcToPKPi", 1, "Selection Flag for Lc decay to P K Pi"}; - 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 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 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}"}; + // Configurable harmonic{"harmonic", 2, "harmonic number"}; + Configurable qVecDetector{"qVecDetector", 2, "Detector for Q vector estimation (FV0A: 0, FT0M: 1, FT0C: 2)"}; + Configurable centEstimator{"centEstimator", 2, "Centrality estimator ((None: 0, FT0C: 2, FT0M: 3))"}; + Configurable centralityMin{"centralityMin", 30, "Minimum centrality (0-100) to be considered in the analysis"}; + Configurable centralityMax{"centralityMax", 50, "Maximum centrality (0-100) to be considered in the analysis"}; /// activate rotational background Configurable nBkgRotations{"nBkgRotations", 0, "Number of rotated copies (background) per each original candidate"}; @@ -144,16 +169,56 @@ struct TaskPolarisationCharmHadrons { 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 activateTHnSparseCosThStarEP{"activateTHnSparseCosThStarEP", false, "Activate the THnSparse with cosThStar w.r.t. reaction plane 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)"}; - 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); + /// 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{"configThnAxisInvMass2KPiLcMonitoring", {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)"}; + + /// Application of rapidity cut for reconstructed candidates + Configurable rapidityCut{"rapidityCut", 999.f, "Max. value of reconstructed candidate rapidity (abs. value)"}; + + SliceCache cache; + EventPlaneHelper epHelper; using CollisionsWithMcLabels = soa::SmallGroups>; + using CollisionsWithMcLabelsAndCent = soa::SmallGroups>; + using CollsWithQVecs = soa::Join; using TracksWithMcLabels = soa::Join; using TracksWithExtra = soa::Join; @@ -173,7 +238,9 @@ struct TaskPolarisationCharmHadrons { using FilteredCandLcToPKPiWSelFlagAndMc = soa::Filtered>; using FilteredCandLcToPKPiWSelFlagAndMcAndMl = soa::Filtered>; - SliceCache cache; + 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); + Preslice dstarPerCollision = aod::hf_cand::collisionId; Preslice dstarWithMlPerCollision = aod::hf_cand::collisionId; Preslice dstarWithMcPerCollision = aod::hf_cand::collisionId; @@ -184,13 +251,37 @@ struct TaskPolarisationCharmHadrons { Preslice lcToPKPiWithMcPerCollision = aod::hf_cand::collisionId; Preslice lcToPKPiWithMcAndMlPerCollision = aod::hf_cand::collisionId; - HfHelper hfHelper; + PresliceUnsorted colPerMcCollision = aod::mcparticle::mcCollisionId; + + ConfigurableAxis configTHnAxisEulerPhi{"configTHnAxisEulerPhi", {24, -o2::constants::math::PI, o2::constants::math::PI}, "Euler polar angle #phi"}; + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {200, 0.139f, 0.179f}, "#it{M} (GeV/#it{c}^{2})"}; // o2-linter: disable=pdg/explicit-mass (false positive) + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.f, 100.f}, "#it{p}_{T} (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 configThnAxisCosThetaStarEP{"configThnAxisCosThetaStarEP", {20, -1.f, 1.f}, "cos(#vartheta_{EP})"}; + 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 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{"configThnAxisAbsEtaTrackMin", {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"}; + ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {100, 0.f, 100.f}, "centrality (%)"}; + HistogramRegistry registry{"registry", {}}; void init(InitContext&) { /// check process functions - std::array processes = {doprocessDstar, doprocessDstarWithMl, doprocessLcToPKPi, doprocessLcToPKPiWithMl, doprocessDstarMc, doprocessDstarMcWithMl, doprocessLcToPKPiMc, doprocessLcToPKPiMcWithMl, doprocessLcToPKPiBackgroundMcWithMl}; + std::array processes = {doprocessDstar, doprocessDstarWithMl, doprocessLcToPKPi, doprocessLcToPKPiWithMl, doprocessDstarMc, doprocessDstarMcWithMl, doprocessLcToPKPiMc, doprocessLcToPKPiMcWithMl, doprocessLcToPKPiBackgroundMcWithMl, doprocessDstarInPbPb, doprocessDstarWithMlInPbPb, doprocessDstarMcInPbPb, doprocessDstarMcWithMlInPbPb}; 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"); @@ -199,7 +290,7 @@ struct TaskPolarisationCharmHadrons { } /// check output THnSparses - std::array sparses = {activateTHnSparseCosThStarHelicity, activateTHnSparseCosThStarProduction, activateTHnSparseCosThStarBeam, activateTHnSparseCosThStarRandom}; + std::array sparses = {activateTHnSparseCosThStarHelicity, activateTHnSparseCosThStarProduction, activateTHnSparseCosThStarBeam, activateTHnSparseCosThStarRandom, activateTHnSparseCosThStarEP}; if (std::accumulate(sparses.begin(), sparses.end(), 0) == 0) { LOGP(fatal, "No output THnSparses enabled"); } else { @@ -215,10 +306,17 @@ struct TaskPolarisationCharmHadrons { if (activateTHnSparseCosThStarRandom) { LOGP(info, "THnSparse with cosThStar w.r.t. random axis active."); } + if (activateTHnSparseCosThStarEP) { + LOGP(info, "THnSparse with cosThStar w.r.t. event plane axis active."); + } + } + + if (activatePartRecoDstar && !(doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb)) { + 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 || doprocessLcToPKPiBackgroundMcWithMl)) { + if (nBkgRotations > 0 && (doprocessDstarMc || doprocessDstarMcWithMl || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb)) { LOGP(fatal, "No background rotation supported for MC."); } @@ -238,16 +336,24 @@ struct TaskPolarisationCharmHadrons { const AxisSpec thnAxisCosThetaStarProduction{configThnAxisCosThetaStarProduction, "cos(#vartheta_{production})"}; const AxisSpec thnAxisCosThetaStarRandom{configThnAxisCosThetaStarRandom, "cos(#vartheta_{random})"}; const AxisSpec thnAxisCosThetaStarBeam{configThnAxisCosThetaStarBeam, "cos(#vartheta_{beam})"}; + const AxisSpec thnAxisCosThetaStarEP{configThnAxisCosThetaStarEP, "cos(#vartheta_{EP})"}; // reaction plane 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"}; + const AxisSpec thnAxisCentrality{configThnAxisCentrality, "centrality (%)"}; auto invMassBins = thnAxisInvMass.binEdges; minInvMass = invMassBins.front(); @@ -256,159 +362,311 @@ struct TaskPolarisationCharmHadrons { 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 (doprocessDstarInPbPb || doprocessDstarMcInPbPb || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + registry.add("hCentrality", "Centrality distribution for D*+ candidates;centrality (%); counts", HistType::kTH1D, {thnAxisCentrality}); + } - 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, 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, 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, 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, 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); - 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, thnAxisPtB}); + if (activateTHnSparseCosThStarHelicity) { + std::vector hHelicityaxes = {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY}; + if (doprocessDstar || doprocessDstarMc || doprocessDstarWithMl || doprocessDstarMcWithMl || doprocessDstarInPbPb || doprocessDstarMcInPbPb || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + hHelicityaxes.insert(hHelicityaxes.end(), {thnAxisInvMassD0, thnAxisCosThetaStarHelicity}); + if (doprocessDstarWithMl || doprocessDstarMcWithMl || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + hHelicityaxes.insert(hHelicityaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); + } + if (activateTrackingSys) { + hHelicityaxes.insert(hHelicityaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); + } + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + std::vector hRecoPromptHelicityAxes(hHelicityaxes); + hRecoPromptHelicityAxes.insert(hRecoPromptHelicityAxes.end(), {thnAxisDauToMuons}); + std::vector hRecoNonPromptHelicityAxes(hHelicityaxes); + hRecoNonPromptHelicityAxes.insert(hRecoNonPromptHelicityAxes.end(), {thnAxisDauToMuons, thnAxisPtB}); + registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptHelicityAxes); + registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptHelicityAxes); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for partially reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptHelicityAxes); + registry.add("hPartRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for partially reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptHelicityAxes); + } + } else { + if (nBkgRotations > 0) { + hHelicityaxes.push_back(thnAxisIsRotatedCandidate); + } + registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores", HistType::kTHnSparseF, hHelicityaxes); } - 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); - 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, thnAxisPtB}); + } else if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPi || doprocessLcToPKPiMc) { // Lc->pKpi + hHelicityaxes.insert(hHelicityaxes.end(), {thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity}); + if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { // Lc->pKpi with ML + hHelicityaxes.insert(hHelicityaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); } - 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); - 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, thnAxisPtB}); + if (doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { // Lc->pKpi MC + std::vector hRecoHelicityAxes(hHelicityaxes); + if (doprocessLcToPKPiMc) { // Lc->pKpi MC without ML, have one more axis for rotated candidates + hRecoHelicityAxes.insert(hRecoHelicityAxes.end(), {thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + } else { + hRecoHelicityAxes.insert(hRecoHelicityAxes.end(), {thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + } + registry.add("hRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for reconstructed prompt Lc+ candidates", HistType::kTHnSparseF, hRecoHelicityAxes); + registry.add("hRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for reconstructed non-prompt Lc+ candidates", HistType::kTHnSparseF, hRecoHelicityAxes); } - 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); - 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, thnAxisPtB}); + hHelicityaxes.insert(hHelicityaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + registry.add("hHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores", HistType::kTHnSparseF, hHelicityaxes); + + if (activateTHnEulerPhiMonitor) { + std::vector hEulerPhiAxes = {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi}; + if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + hEulerPhiAxes.insert(hEulerPhiAxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); + } + if (doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPiMc) { + hEulerPhiAxes.insert(hEulerPhiAxes.end(), {thnAxisResoChannelLc}); + } + hEulerPhiAxes.push_back(thnAxisCharge); + if (doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPiMc) { + registry.add("hRecPromptEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, hEulerPhiAxes); + registry.add("hRecNonPromptEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, hEulerPhiAxes); + } else { + registry.add("hEulerPhiHelicity", "THn for polarisation studies with Euler phi w.r.t. helicity axis", HistType::kTHnSparseF, hEulerPhiAxes); + } } } - } 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); - 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}); - } - 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarProduction, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); - 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}); - } - 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarBeam, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc}); - 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}); - } - 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarRandom, thnAxisMlBkg, thnAxisMlNonPrompt, thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); - 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}); + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + std::vector const hgenPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + std::vector const hgenNonPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + registry.add("hGenPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); + registry.add("hGenNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); + if (activatePartRecoDstar) { + registry.add("hGenPartRecoPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for partially reconstructed generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); + registry.add("hGenPartRecoNonPromptHelicity", "THn for polarisation studies with cosThStar w.r.t. helicity axis and BDT scores for partially reconstructed generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); } } - } 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, 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassD0, thnAxisCosThetaStarProduction, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); + } + + if (activateTHnSparseCosThStarProduction) { + std::vector hProductionaxes = {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY}; + if (doprocessDstar || doprocessDstarMc || doprocessDstarWithMl || doprocessDstarMcWithMl || doprocessDstarInPbPb || doprocessDstarMcInPbPb || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + + hProductionaxes.insert(hProductionaxes.end(), {thnAxisInvMassD0, thnAxisCosThetaStarProduction}); + if (doprocessDstarWithMl || doprocessDstarMcWithMl || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + hProductionaxes.insert(hProductionaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); + } + if (activateTrackingSys) { + hProductionaxes.insert(hProductionaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); + } + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + std::vector hRecoPromptProductionAxes(hProductionaxes); + hRecoPromptProductionAxes.insert(hRecoPromptProductionAxes.end(), {thnAxisDauToMuons}); + std::vector hRecoNonPromptProductionAxes(hProductionaxes); + hRecoNonPromptProductionAxes.insert(hRecoNonPromptProductionAxes.end(), {thnAxisDauToMuons, thnAxisPtB}); + registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptProductionAxes); + registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptProductionAxes); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for partially reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptProductionAxes); + registry.add("hPartRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for partially reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptProductionAxes); + } + } else { + if (nBkgRotations > 0) { + hProductionaxes.push_back(thnAxisIsRotatedCandidate); + } + registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores", HistType::kTHnSparseF, hProductionaxes); } - if (activateTHnSparseCosThStarBeam) { - 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}); + } else if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPi || doprocessLcToPKPiMc) { + hProductionaxes.insert(hProductionaxes.end(), {thnAxisInvMassKPiLc, thnAxisCosThetaStarProduction}); + if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + hProductionaxes.insert(hProductionaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); } - if (activateTHnSparseCosThStarRandom) { - 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}); + if (doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + std::vector hRecoProductionAxes(hProductionaxes); + if (doprocessLcToPKPiMc) { + hRecoProductionAxes.insert(hRecoProductionAxes.end(), {thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + } else { + hRecoProductionAxes.insert(hRecoProductionAxes.end(), {thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + } + registry.add("hRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for reconstructed prompt Lc+ candidates", HistType::kTHnSparseF, hRecoProductionAxes); + registry.add("hRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for reconstructed non-prompt Lc+ candidates", HistType::kTHnSparseF, hRecoProductionAxes); + } + hProductionaxes.insert(hProductionaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + registry.add("hProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores", HistType::kTHnSparseF, hProductionaxes); + if (activateTHnEulerPhiMonitor) { + std::vector hEulerPhiAxes = {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi}; + if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + hEulerPhiAxes.insert(hEulerPhiAxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); + } + if (doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPiMc) { + hEulerPhiAxes.insert(hEulerPhiAxes.end(), {thnAxisResoChannelLc}); + } + hEulerPhiAxes.push_back(thnAxisCharge); + if (doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPiMc) { + registry.add("hRecPromptEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. production axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, hEulerPhiAxes); + registry.add("hRecNonPromptEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. production axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, hEulerPhiAxes); + } else { + registry.add("hEulerPhiProduction", "THn for polarisation studies with Euler phi w.r.t. production axis", HistType::kTHnSparseF, hEulerPhiAxes); + } } - } else { - if (activateTHnSparseCosThStarHelicity) { - 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}); - 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, thnAxisPtB}); + } + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + std::vector const hgenPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarProduction, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + std::vector const hgenNonPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarProduction, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + registry.add("hGenPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); + registry.add("hGenNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); + if (activatePartRecoDstar) { + registry.add("hGenPartRecoPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for partially reconstructed generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); + registry.add("hGenPartRecoNonPromptProduction", "THn for polarisation studies with cosThStar w.r.t. production axis and BDT scores for partially reconstructed generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); } - if (activateTHnSparseCosThStarProduction) { - 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}); - 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, thnAxisPtB}); + } + } + + if (activateTHnSparseCosThStarBeam) { + std::vector hBeamaxes = {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY}; + if (doprocessDstar || doprocessDstarMc || doprocessDstarWithMl || doprocessDstarMcWithMl || doprocessDstarInPbPb || doprocessDstarMcInPbPb || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + hBeamaxes.insert(hBeamaxes.end(), {thnAxisInvMassD0, thnAxisCosThetaStarBeam}); + if (doprocessDstarWithMl || doprocessDstarMcWithMl || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + hBeamaxes.insert(hBeamaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); + } + if (activateTrackingSys) { + hBeamaxes.insert(hBeamaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); + } + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + std::vector hRecoPromptBeamAxes(hBeamaxes); + hRecoPromptBeamAxes.insert(hRecoPromptBeamAxes.end(), {thnAxisDauToMuons}); + std::vector hRecoNonPromptBeamAxes(hBeamaxes); + hRecoNonPromptBeamAxes.insert(hRecoNonPromptBeamAxes.end(), {thnAxisDauToMuons, thnAxisPtB}); + registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptBeamAxes); + registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptBeamAxes); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for partially reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptBeamAxes); + registry.add("hPartRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for partially reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptBeamAxes); + } + } else { + if (nBkgRotations > 0) { + hBeamaxes.push_back(thnAxisIsRotatedCandidate); + } + registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores", HistType::kTHnSparseF, hBeamaxes); } - if (activateTHnSparseCosThStarBeam) { - 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}); - 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, thnAxisPtB}); + } else if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPi || doprocessLcToPKPiMc) { + hBeamaxes.insert(hBeamaxes.end(), {thnAxisInvMassKPiLc, thnAxisCosThetaStarBeam}); + if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + hBeamaxes.insert(hBeamaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); } - if (activateTHnSparseCosThStarRandom) { - 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}); - 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, thnAxisPtB}); + if (doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + std::vector hRecoBeamAxes(hBeamaxes); + if (doprocessLcToPKPiMc) { + hRecoBeamAxes.insert(hRecoBeamAxes.end(), {thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + } else { + hRecoBeamAxes.insert(hRecoBeamAxes.end(), {thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + } + registry.add("hRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for reconstructed prompt Lc+ candidates", HistType::kTHnSparseF, hRecoBeamAxes); + registry.add("hRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for reconstructed non-prompt Lc+ candidates", HistType::kTHnSparseF, hRecoBeamAxes); + } + hBeamaxes.insert(hBeamaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + registry.add("hBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores", HistType::kTHnSparseF, hBeamaxes); + if (activateTHnEulerPhiMonitor) { + std::vector hEulerPhiAxes = {thnAxisInvMass, thnAxisPt, thnAxisInvMassKPiLc, thnAxisTHnAxisEulerPhi}; + if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + hEulerPhiAxes.insert(hEulerPhiAxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); + } + if (doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPiMc) { + hEulerPhiAxes.insert(hEulerPhiAxes.end(), {thnAxisResoChannelLc}); + } + hEulerPhiAxes.push_back(thnAxisCharge); + if (doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPiMc) { + registry.add("hRecPromptEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis and BDT scores -- reco prompt signal", HistType::kTHnSparseF, hEulerPhiAxes); + registry.add("hRecNonPromptEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis and BDT scores -- reco non-prompt signal", HistType::kTHnSparseF, hEulerPhiAxes); + } else { + registry.add("hEulerPhiBeam", "THn for polarisation studies with Euler phi w.r.t. beam axis", HistType::kTHnSparseF, hEulerPhiAxes); + } } } - } 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, thnAxisNumPvContributors, thnAxisY, thnAxisInvMassKPiLc, thnAxisCosThetaStarHelicity, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate}); + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + std::vector const hgenPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarBeam, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + std::vector const hgenNonPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarBeam, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + registry.add("hGenPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); + registry.add("hGenNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); + if (activatePartRecoDstar) { + registry.add("hGenPartRecoPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for partially reconstructed generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); + registry.add("hGenPartRecoNonPromptBeam", "THn for polarisation studies with cosThStar w.r.t. beam axis and BDT scores for partially reconstructed generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); } - if (activateTHnSparseCosThStarProduction) { - 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}); + } + } + + if (activateTHnSparseCosThStarRandom) { + std::vector hRandomaxes = {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY}; + if (doprocessDstar || doprocessDstarMc || doprocessDstarWithMl || doprocessDstarMcWithMl || doprocessDstarInPbPb || doprocessDstarMcInPbPb || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + + hRandomaxes.insert(hRandomaxes.end(), {thnAxisInvMassD0, thnAxisCosThetaStarRandom}); + if (doprocessDstarWithMl || doprocessDstarMcWithMl || doprocessDstarWithMlInPbPb || doprocessDstarMcWithMlInPbPb) { + hRandomaxes.insert(hRandomaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); + } + if (activateTrackingSys) { + hRandomaxes.insert(hRandomaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); + } + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb) { + std::vector hRecoPromptRandomAxes(hRandomaxes); + hRecoPromptRandomAxes.insert(hRecoPromptRandomAxes.end(), {thnAxisDauToMuons}); + std::vector hRecoNonPromptRandomAxes(hRandomaxes); + hRecoNonPromptRandomAxes.insert(hRecoNonPromptRandomAxes.end(), {thnAxisDauToMuons, thnAxisPtB}); + registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptRandomAxes); + registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptRandomAxes); + if (activatePartRecoDstar) { + registry.add("hPartRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for partially reconstructed prompt D*+ candidates", HistType::kTHnSparseF, hRecoPromptRandomAxes); + registry.add("hPartRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for partially reconstructed non-prompt D*+ candidates", HistType::kTHnSparseF, hRecoNonPromptRandomAxes); + } + } else { + if (nBkgRotations > 0) { + hRandomaxes.push_back(thnAxisIsRotatedCandidate); + } + registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores", HistType::kTHnSparseF, hRandomaxes); } - if (activateTHnSparseCosThStarBeam) { - 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}); + } else if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl || doprocessLcToPKPi || doprocessLcToPKPiMc) { + hRandomaxes.insert(hRandomaxes.end(), {thnAxisInvMassKPiLc, thnAxisCosThetaStarRandom}); + if (doprocessLcToPKPiWithMl || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + hRandomaxes.insert(hRandomaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); } - if (activateTHnSparseCosThStarRandom) { - 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}); + if (doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + std::vector hRecoRandomAxes(hRandomaxes); + if (doprocessLcToPKPiMc) { + hRecoRandomAxes.insert(hRecoRandomAxes.end(), {thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + } else { + hRecoRandomAxes.insert(hRecoRandomAxes.end(), {thnAxisResoChannelLc, thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisCharge}); + } + registry.add("hRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for reconstructed prompt Lc+ candidates", HistType::kTHnSparseF, hRecoRandomAxes); + registry.add("hRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for reconstructed non-prompt Lc+ candidates", HistType::kTHnSparseF, hRecoRandomAxes); } - } else { - if (activateTHnSparseCosThStarHelicity) { - 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}); - 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}); + hRandomaxes.insert(hRandomaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin, thnAxisIsRotatedCandidate, thnAxisCharge}); + registry.add("hRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores", HistType::kTHnSparseF, hRandomaxes); + } + if (doprocessDstarMc || doprocessDstarMcWithMl || doprocessDstarMcInPbPb || doprocessDstarMcWithMlInPbPb || doprocessLcToPKPiMc || doprocessLcToPKPiMcWithMl || doprocessLcToPKPiBackgroundMcWithMl) { + std::vector const hgenPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + std::vector const hgenNonPromptAxes = {thnAxisPt, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarRandom, thnAxisPtB, thnAxisDausAcc, thnAxisResoChannelLc, thnAxisCharge}; + registry.add("hGenPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); + registry.add("hGenNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); + if (activatePartRecoDstar) { + registry.add("hGenPartRecoPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for partially reconstructed generated prompt D*+ candidates", HistType::kTHnSparseF, hgenPromptAxes); + registry.add("hGenPartRecoNonPromptRandom", "THn for polarisation studies with cosThStar w.r.t. random axis and BDT scores for partially reconstructed generated non-prompt D*+ candidates", HistType::kTHnSparseF, hgenNonPromptAxes); } - if (activateTHnSparseCosThStarProduction) { - 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}); - 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}); + } + } + + if (activateTHnSparseCosThStarEP && !(doprocessDstarInPbPb || doprocessDstarWithMlInPbPb)) { + LOGP(fatal, "THnSparse with cosThStar w.r.t. event plane axis is not supported for pp analysis, please check the configuration!"); + } else if (activateTHnSparseCosThStarEP) { + std::vector hEPaxes = {thnAxisInvMass, thnAxisPt, thnAxisNumPvContributors, thnAxisY}; + if (doprocessDstarInPbPb || doprocessDstarWithMlInPbPb) { + hEPaxes.insert(hEPaxes.end(), {thnAxisInvMassD0, thnAxisCosThetaStarEP}); + if (doprocessDstarWithMlInPbPb) { + hEPaxes.insert(hEPaxes.end(), {thnAxisMlBkg, thnAxisMlNonPrompt}); } - if (activateTHnSparseCosThStarBeam) { - 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}); - 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}); + if (activateTrackingSys) { + hEPaxes.insert(hEPaxes.end(), {thnAxisAbsEtaTrackMin, thnAxisNumItsClsMin, thnAxisNumTpcClsMin}); } - if (activateTHnSparseCosThStarRandom) { - 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}); - 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}); + if (nBkgRotations > 0) { + hEPaxes.push_back(thnAxisIsRotatedCandidate); } + registry.add("hEP", "THn for polarisation studies with cosThStar w.r.t. event plane axis and BDT scores", HistType::kTHnSparseF, hEPaxes); } } - // MC Gen histos - 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, thnAxisNumPvContributors, thnAxisY, thnAxisCosThetaStarHelicity, thnAxisDausAcc, thnAxisResoChannelLc}); - 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}); - } - if (activateTHnSparseCosThStarProduction) { - 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}); - 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}); - } - if (activateTHnSparseCosThStarBeam) { - 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}); - 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}); - } - if (activateTHnSparseCosThStarRandom) { - 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}); - 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}); - } + /// 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 @@ -428,6 +686,8 @@ struct TaskPolarisationCharmHadrons { /// \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 @@ -437,189 +697,590 @@ struct TaskPolarisationCharmHadrons { /// \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 - template - void fillRecoHistos(float invMassCharmHad, float ptCharmHad, int numPvContributors, float rapCharmHad, float invMassD0, float invMassKPiLc, float cosThetaStar, std::array outputMl, int isRotatedCandidate, int8_t origin, float ptBhadMother, int8_t resoChannelLc, float absEtaMin, int numItsClsMin, int numTpcClsMin) + /// \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, 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, numPvContributors, 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, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Helicity) { // Helicity + if constexpr (!DoMc) { // data + if constexpr (WithMl) { // with ML + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + } else { + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, isRotatedCandidate); + } else { + registry.fill(HIST("hHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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 constexpr (WithMl) { // with ML if (origin == RecoDecay::OriginType::Prompt) { // prompt - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } else { + registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, ptBhadMother); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, ptBhadMother); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptHelicity"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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); + } } } } } - } else if constexpr (cosThetaStarType == charm_polarisation::CosThetaStarType::Production) { // Production - if constexpr (!doMc) { // data - if constexpr (withMl) { // with ML - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, 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, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Production) { // Production + if constexpr (!DoMc) { // data + if constexpr (WithMl) { // with ML + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + } else { + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, isRotatedCandidate); + } else { + registry.fill(HIST("hProduction"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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 constexpr (WithMl) { // with ML if (origin == RecoDecay::OriginType::Prompt) { // prompt - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } else { + registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, ptBhadMother); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, ptBhadMother); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptProduction"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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); + } } } } } - } else if constexpr (cosThetaStarType == charm_polarisation::CosThetaStarType::Beam) { // Beam - if constexpr (!doMc) { // data - if constexpr (withMl) { // with ML - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, 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, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Beam) { // Beam + if constexpr (!DoMc) { // data + if constexpr (WithMl) { // with ML + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + } else { + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, isRotatedCandidate); + } else { + registry.fill(HIST("hBeam"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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 constexpr (WithMl) { // with ML if (origin == RecoDecay::OriginType::Prompt) { // prompt - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } else { + registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, ptBhadMother); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, ptBhadMother); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptBeam"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, nMuons, ptBhadMother); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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); + } } } } } - } else if constexpr (cosThetaStarType == charm_polarisation::CosThetaStarType::Random) { // Random - if constexpr (!doMc) { // data - if constexpr (withMl) { // with ML - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, 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, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Random) { // Random + if constexpr (!DoMc) { // data + if constexpr (WithMl) { // with ML + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + } else { + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, isRotatedCandidate); + } else { + registry.fill(HIST("hRandom"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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 constexpr (WithMl) { // with ML if (origin == RecoDecay::OriginType::Prompt) { // prompt - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } else { + registry.fill(HIST("hPartRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, ptBhadMother); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + 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 (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } + } + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ + 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + 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, 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, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, ptBhadMother); - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ - registry.fill(HIST("hRecoNonPromptRandom"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin); + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + 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, numPvContributors, rapCharmHad, invMassKPiLc, cosThetaStar, resoChannelLc, absEtaMin, numItsClsMin, numTpcClsMin, charge); + } + } + } + } + } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::EP) { // EP + if constexpr (!DoMc) { // data + if constexpr (WithMl) { // with ML + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], isRotatedCandidate); + } else { + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2]); + } + } + } + } else { + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (nBkgRotations > 0) { + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin, isRotatedCandidate); + } else { + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, absEtaMin, numItsClsMin, numTpcClsMin); + } + } else { + if (nBkgRotations > 0) { + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar, isRotatedCandidate); + } else { + registry.fill(HIST("hEP"), invMassCharmHad, ptCharmHad, numPvContributors, std::abs(rapCharmHad), invMassD0, cosThetaStar); + } + } + } + } + } else { + if constexpr (WithMl) { // with ML + if (origin == RecoDecay::OriginType::Prompt) { // prompt + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } else { + registry.fill(HIST("hPartRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons); + } + } else { + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } else { + registry.fill(HIST("hPartRecoPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons); + } + } + } + } else { // non-prompt + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + if (activateTrackingSys) { + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], absEtaMin, numItsClsMin, numTpcClsMin, nMuons, ptBhadMother); + } + } else { + if (!isPartRecoDstar) { + registry.fill(HIST("hRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } else { + registry.fill(HIST("hPartRecoNonPromptEP"), invMassCharmHad, ptCharmHad, numPvContributors, rapCharmHad, invMassD0, cosThetaStar, outputMl[0], /*outputMl[1],*/ outputMl[2], nMuons, ptBhadMother); + } + } } } } @@ -635,32 +1296,79 @@ struct TaskPolarisationCharmHadrons { /// \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) - template - void fillGenHistos(float ptCharmHad, int numPvContributors, float rapCharmHad, float cosThetaStar, int8_t origin, float ptBhadMother, bool areDausInAcc, uint8_t resoChannelLc) + /// \param isPartRecoDstar is a flag indicating if it is a partly reconstructed Dstar->D0pi->Kpipipi0 meson (MC only) + template + 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 constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Helicity) { // Helicity if (origin == RecoDecay::OriginType::Prompt) { // prompt - registry.fill(HIST("hGenPromptHelicity"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc); + 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, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc); + 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 + } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Production) { // Production if (origin == RecoDecay::OriginType::Prompt) { // prompt - registry.fill(HIST("hGenPromptProduction"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc); + 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, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc); + 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 + } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Beam) { // Beam if (origin == RecoDecay::OriginType::Prompt) { // prompt - registry.fill(HIST("hGenPromptBeam"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc); + 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, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc); + 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 + } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::Random) { // Random if (origin == RecoDecay::OriginType::Prompt) { // prompt - registry.fill(HIST("hGenPromptRandom"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc); + 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, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc); + 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); + } + } + } else if constexpr (CosThetaStarType == charm_polarisation::CosThetaStarType::EP) { // EP + if (origin == RecoDecay::OriginType::Prompt) { // prompt + if (!isPartRecoDstar) { + registry.fill(HIST("hGenPromptEP"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoPromptEP"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, areDausInAcc, resoChannelLc, charge); + } + } else { // non-prompt + if (!isPartRecoDstar) { + registry.fill(HIST("hGenNonPromptEP"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } else { + registry.fill(HIST("hGenPartRecoNonPromptEP"), ptCharmHad, numPvContributors, rapCharmHad, cosThetaStar, ptBhadMother, areDausInAcc, resoChannelLc, charge); + } } } } @@ -681,15 +1389,21 @@ struct TaskPolarisationCharmHadrons { /// \param invMass is the invariant mass /// \return true if candidate in signal region - template + template bool isInSignalRegion(float invMass) { - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ - if (0.142f < invMass && invMass < 0.15f) { + float invMassMin; + float invMassMax; + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // D*+ + invMassMin = 0.142f; + invMassMax = 0.15f; + if (invMassMin < invMass && invMass < invMassMax) { return true; } - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ (to be tuned!) - if (2.25f < invMass && invMass < 2.35f) { + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc+ (to be tuned!) + invMassMin = 2.25f; + invMassMax = 2.35f; + if (invMassMin < invMass && invMass < invMassMax) { return true; } } @@ -760,35 +1474,75 @@ struct TaskPolarisationCharmHadrons { } } + /// Get the Q vector + /// \param collision is the collision with the Q vector information + template + std::vector getQVec(Coll const& collision) + { + float xQVec = -999.; + float yQVec = -999.; + float const amplQVec = -999.; + switch (qVecDetector) { + case charm_polarisation::QvecEstimator::FV0A: + xQVec = collision.qvecFV0ARe(); + yQVec = collision.qvecFV0AIm(); + break; + case charm_polarisation::QvecEstimator::FT0M: + xQVec = collision.qvecFT0MRe(); + yQVec = collision.qvecFT0MIm(); + break; + case charm_polarisation::QvecEstimator::FT0C: + xQVec = collision.qvecFT0CRe(); + yQVec = collision.qvecFT0CIm(); + 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(); + yQVec = collision.qvecFV0AIm(); + break; + } + return {xQVec, yQVec, amplQVec}; + } + /// \param candidates are the selected candidates /// \param bkgRotationId is the id for the background rotation /// \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*/) + template + bool runPolarisationAnalysis(Cand const& candidate, int bkgRotationId, int numPvContributors, Part const& particles, Trk const& /*tracks*/, QVecs const* qVecs = nullptr) { + if constexpr (WithEp) { + assert(qVecs && "EP analysis requested but qVecs == nullptr"); + } + + constexpr std::size_t NScores{3u}; + bool isCandidateInSignalRegion{false}; int8_t origin{RecoDecay::OriginType::None}; int8_t massHypoMcTruth{-1}; float ptBhadMother{-1.f}; int8_t resoChannelLc = -1; - 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 + int8_t charge = -99; + bool partRecoDstar{false}; + if constexpr (DoMc) { + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { + partRecoDstar = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPiPi0 && std::abs(candidate.flagMcMatchRecD0()) == hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiKPi0; + bool const signalDstar = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi && std::abs(candidate.flagMcMatchRecD0()) == hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; + if (!signalDstar && (!partRecoDstar || !activatePartRecoDstar)) { // this candidate is not signal and not partially reconstructed signal, skip return isCandidateInSignalRegion; } origin = candidate.originMcRec(); ptBhadMother = candidate.ptBhadMotherPart(); - int pdgBhadMother = candidate.pdgBhadMotherPart(); + int const 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)) { + 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 == 557)) { // o2-linter: disable=pdg/explicit-code, magic-number (constants not in the PDG header) return isCandidateInSignalRegion; } - } 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 + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { + if constexpr (!StudyLcPkPiBkgMc) { // skip this if studyLcPKPiBkgMc is true, since we are interested in background + if (std::abs(candidate.flagMcMatchRec()) != hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { // this candidate is not signal, skip return isCandidateInSignalRegion; } origin = candidate.originMcRec(); @@ -799,6 +1553,19 @@ struct TaskPolarisationCharmHadrons { } 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 const 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()); } } @@ -808,12 +1575,12 @@ 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}, invMassKPiLc{0.f}; + double massDau{0.}, invMassCharmHad{0.}, invMassCharmHadForSparse{0.}, invMassD0{0.}, invMassKPiLc{0.}, invMassPKLc{0.}, invMassPPiLc{0.}; float rapidity{-999.f}; std::array outputMl{-1.f, -1.f, -1.f}; int isRotatedCandidate = 0; // currently meaningful only for Lc->pKpi - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { // Dstar analysis // polarization measured from the soft-pion daughter (*) @@ -858,16 +1625,16 @@ struct TaskPolarisationCharmHadrons { } invMassCharmHadForSparse = invMassCharmHad - invMassD0; - if constexpr (withMl) { + if constexpr (WithMl) { outputMl[0] = candidate.mlProbDstarToD0Pi()[0]; outputMl[1] = candidate.mlProbDstarToD0Pi()[1]; outputMl[2] = candidate.mlProbDstarToD0Pi()[2]; } - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { // Lc->pKpi analysis // polarization measured from the proton daughter (*) - if constexpr (doMc) { // we keep only the good hypo in the MC + if constexpr (DoMc) { // we keep only the good hypo in the MC if ((iMass == charm_polarisation::MassHyposLcToPKPi::PiKP && massHypoMcTruth == charm_polarisation::MassHyposLcToPKPi::PKPi) || (iMass == charm_polarisation::MassHyposLcToPKPi::PKPi && massHypoMcTruth == charm_polarisation::MassHyposLcToPKPi::PiKP)) { continue; } @@ -898,6 +1665,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(); @@ -909,11 +1679,11 @@ struct TaskPolarisationCharmHadrons { invMassCharmHadForSparse = invMassCharmHad; } else { /// original candidate (kaon track not rotated) - invMassCharmHad = hfHelper.invMassLcToPKPi(candidate); - invMassCharmHadForSparse = hfHelper.invMassLcToPKPi(candidate); + invMassCharmHad = HfHelper::invMassLcToPKPi(candidate); + invMassCharmHadForSparse = HfHelper::invMassLcToPKPi(candidate); } - if constexpr (withMl) { - if (candidate.mlProbLcToPKPi().size() == 3) { + if constexpr (WithMl) { + if (candidate.mlProbLcToPKPi().size() == NScores) { // protect from empty vectors // the BDT output score might be empty if no preselections were enabled (selectionFlag null) // !!! NB: each rotated candidates inherits the BDT scores of the original candidate, even if the candidate pt changed after the rotation of the kaon-track pt !!! @@ -923,7 +1693,15 @@ struct TaskPolarisationCharmHadrons { } } // invariant mass of the KPi pair - invMassKPiLc = hfHelper.invMassKPiPairLcToPKPi(candidate); + 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(); @@ -935,11 +1713,11 @@ struct TaskPolarisationCharmHadrons { invMassCharmHadForSparse = invMassCharmHad; } else { /// original candidate (kaon track not rotated) - invMassCharmHad = hfHelper.invMassLcToPiKP(candidate); - invMassCharmHadForSparse = hfHelper.invMassLcToPiKP(candidate); + invMassCharmHad = HfHelper::invMassLcToPiKP(candidate); + invMassCharmHadForSparse = HfHelper::invMassLcToPiKP(candidate); } - if constexpr (withMl) { - if (candidate.mlProbLcToPiKP().size() == 3) { + if constexpr (WithMl) { + if (candidate.mlProbLcToPiKP().size() == NScores) { // protect from empty vectors // the BDT output score might be empty if no preselections were enabled (selectionFlag null) // !!! NB: each rotated candidates inherits the BDT scores of the original candidate, even if the candidate pt changed after the rotation of the kaon-track pt !!! @@ -949,7 +1727,15 @@ struct TaskPolarisationCharmHadrons { } } // invariant mass of the KPi pair - invMassKPiLc = hfHelper.invMassKPiPairLcToPiKP(candidate); + 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! @@ -957,24 +1743,54 @@ 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 const invMass2KPiLc = invMassKPiLc * invMassKPiLc; + double const invMass2PKLc = invMassPKLc * invMassPKLc; + double const 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; } - 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); - ROOT::Math::PxPyPzMVector fourVecMother = ROOT::Math::PxPyPzMVector(pxCharmHad, pyCharmHad, pzCharmHad, invMassCharmHad); - ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; - ROOT::Math::PxPyPzMVector fourVecDauCM = boost(fourVecDau); - ROOT::Math::XYZVector threeVecDauCM = fourVecDauCM.Vect(); + /// apply rapidity selection on the reconstructed candidate + if (std::abs(rapidity) > rapidityCut) { + continue; + } - float ptCharmHad = std::sqrt(pxCharmHad * pxCharmHad + pyCharmHad * pyCharmHad); // this definition is valid for both rotated and original candidates + float const phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + float const thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + ROOT::Math::PxPyPzMVector const fourVecDau = ROOT::Math::PxPyPzMVector(pxDau, pyDau, pzDau, massDau); + ROOT::Math::PxPyPzMVector const fourVecMother = ROOT::Math::PxPyPzMVector(pxCharmHad, pyCharmHad, pzCharmHad, invMassCharmHad); + ROOT::Math::Boost const boost{fourVecMother.BoostToCM()}; + ROOT::Math::PxPyPzMVector const fourVecDauCM = boost(fourVecDau); + ROOT::Math::XYZVector const threeVecDauCM = fourVecDauCM.Vect(); + + float const 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); + isCandidateInSignalRegion = isInSignalRegion(invMassCharmHadForSparse); } float absEtaTrackMin{-1.f}; @@ -983,44 +1799,78 @@ struct TaskPolarisationCharmHadrons { if (activateTrackingSys) { auto trackProng0 = candidate.template prong0_as(); auto trackProng1 = candidate.template prong1_as(); - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { + 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) { + } 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 const helicityVec = fourVecMother.Vect(); float cosThetaStarHelicity = -10.f; + float phiHelicity = -10.f; + // production + ROOT::Math::XYZVector const normalVec = ROOT::Math::XYZVector(pyCharmHad, -pxCharmHad, 0.f); float cosThetaStarProduction = -10.f; + float phiProduction = -10.f; + // beam + ROOT::Math::XYZVector const 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 constexpr (WithEp && !DoMc) { + /// EP analysis + float const xQvec = (*qVecs).at(0); + float const yQvec = (*qVecs).at(1); + ROOT::Math::XYZVector const qVecNorm = ROOT::Math::XYZVector(yQvec, -xQvec, 0.f); + float const phiEP = -99.f; + + if (activateTHnSparseCosThStarEP) { + // EP + float cosThetaStarEP = qVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(qVecNorm.Mag2()); + fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarEP, phiEP, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin, charge, nMuons, partRecoDstar); + } + } + if (activateTHnSparseCosThStarHelicity) { - ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); + // helicity cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(helicityVec.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarHelicity, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin); + 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); + // production cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(normalVec.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarProduction, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin); + 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); + // beam cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarBeam, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin); + 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) { - ROOT::Math::XYZVector randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + // random + ROOT::Math::XYZVector const randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); - fillRecoHistos(invMassCharmHadForSparse, ptCharmHad, numPvContributors, rapidity, invMassD0, invMassKPiLc, cosThetaStarRandom, outputMl, isRotatedCandidate, origin, ptBhadMother, resoChannelLc, absEtaTrackMin, numItsClsMin, numTpcClsMin); + 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) { + 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: @@ -1045,23 +1895,32 @@ struct TaskPolarisationCharmHadrons { 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; @@ -1076,9 +1935,29 @@ struct TaskPolarisationCharmHadrons { 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 const idBMotherProng0 = idxBhadMothersProng0.at(0); + int const idBMotherProng1 = idxBhadMothersProng1.at(0); + int const 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)) { + if (isRealPKPi && (std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi)) { isRealLcPKPi = 1; } @@ -1095,31 +1974,33 @@ struct TaskPolarisationCharmHadrons { int pdgMotherProng0 = -1; int pdgMotherProng1 = -1; int pdgMotherProng2 = -1; - if (idMothersProng0.size() > 0 && idMothersProng1.size() > 0 && idMothersProng0.at(0) == idMothersProng1.at(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 - pdgMotherProng1 = pdgMotherProng0; - } - if (idMothersProng1.size() > 0 && idMothersProng2.size() > 0 && idMothersProng1.at(0) == idMothersProng2.at(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 - pdgMotherProng2 = pdgMotherProng1; - } - if (idMothersProng0.size() > 0 && idMothersProng2.size() > 0 && idMothersProng0.at(0) == idMothersProng2.at(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 - pdgMotherProng2 = pdgMotherProng0; + bool const atLeast2ProngsFromSameMother = (!idMothersProng0.empty() && !idMothersProng1.empty() && idMothersProng0.at(0) == idMothersProng1.at(0)) || + (!idMothersProng1.empty() && !idMothersProng2.empty() && idMothersProng1.at(0) == idMothersProng2.at(0)) || + (!idMothersProng0.empty() && !idMothersProng2.empty() && idMothersProng0.at(0) == idMothersProng2.at(0)); + if (atLeast2ProngsFromSameMother) { + if (!idMothersProng0.empty()) { + /// 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.empty()) { + /// 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.empty()) { + /// 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 const pVecKaon = candidate.pVectorProng1(); std::array pVecProton = {}; if (iMass == charm_polarisation::MassHyposLcToPKPi::PKPi && candidate.isSelLcToPKPi() >= selectionFlagLcToPKPi) { pVecProton = candidate.pVectorProng0(); @@ -1156,10 +2037,11 @@ struct TaskPolarisationCharmHadrons { cosThetaStarForTable, pdgMotherProng0, pdgMotherProng1, pdgMotherProng2, massKPi, massKProton, massPiProton, - outputMl.at(0), - isRealPKPi, isRealLcPKPi, isReflected); + outputMl.at(0), outputMl.at(2), + isRealPKPi, isRealLcPKPi, isReflected, + charge, originTriplet); } // end studyLcPKPiBkgMc - } // end table for Lc->pKpi background studies + } // end table for Lc->pKpi background studies } /// end loop over mass hypotheses @@ -1169,60 +2051,78 @@ struct TaskPolarisationCharmHadrons { /// \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, int numPvContributors) + template + void runMcGenPolarisationAnalysis(Part const& mcParticle, Particles const& mcParticles, int numPvContributors, Cent const* centrality = nullptr) { + if constexpr (WithCent) { + assert(qVecs && "Centrality analysis requested but Cent == nullptr"); + } + if constexpr (WithCent) { + if (*centrality < centralityMin || *centrality > centralityMax) { + return; // skip this collision if outside of the centrality range + } + } + 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; - 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 + int8_t charge = -99; + bool partRecoDstar{false}; + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { + partRecoDstar = (std::abs(mcParticle.flagMcMatchGen()) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPiPi0) && (std::abs(mcParticle.flagMcMatchGenD0()) == hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiKPi0); + bool const signalDstar = (std::abs(mcParticle.flagMcMatchGen()) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) && (std::abs(mcParticle.flagMcMatchGenD0()) == hf_decay::hf_cand_2prong::DecayChannelMain::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()); + int const 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) { + if (pdgBhadMother == 5101 || pdgBhadMother == 5103 || pdgBhadMother == 5201 || pdgBhadMother == 5203 || pdgBhadMother == 5301 || pdgBhadMother == 5303 || pdgBhadMother == 5401 || pdgBhadMother == 5403 || pdgBhadMother == 5503 || pdgBhadMother == 553 || pdgBhadMother == 555 || pdgBhadMother == 557) { // o2-linter: disable=pdg/explicit-code, magic-number (constants not in the PDG header) return; } ptBhadMother = bHadMother.pt(); } - std::array dauPdgs = {kPiPlus, o2::constants::physics::Pdg::kD0}; + std::array const dauPdgs = {kPiPlus, o2::constants::physics::Pdg::kD0}; RecoDecay::getDaughters(mcParticle, &listDaughters, dauPdgs, 1); massDau = massPi; massCharmHad = massDstar; - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { - if (!TESTBIT(std::abs(mcParticle.flagMcMatchGen()), aod::hf_cand_3prong::DecayType::LcToPKPi)) { // this particle is not signal, skip + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { + if (std::abs(mcParticle.flagMcMatchGen()) != hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { // this particle is not signal, skip return; } origin = mcParticle.originMcGen(); resoChannelLc = mcParticle.flagMcDecayChanGen(); - std::array dauPdgs = {kProton, -kKPlus, kPiPlus}; + std::array const dauPdgs = {kProton, -kKPlus, kPiPlus}; RecoDecay::getDaughters(mcParticle, &listDaughters, dauPdgs, 2); massDau = massProton; massCharmHad = massLc; + + /// electric charge from PDG code + int const pdgCode = mcParticle.pdgCode(); + charge = static_cast(pdgCode / std::abs(pdgCode)); } - float rapidity = mcParticle.y(); + float const rapidity = mcParticle.y(); if (std::abs(rapidity) > 1.f) { // we do not keep particles with |y| > 1 return; } - float pxCharmHad = mcParticle.px(); - float pyCharmHad = mcParticle.py(); - float pzCharmHad = mcParticle.pz(); - float ptCharmHad = mcParticle.pt(); + float const pxCharmHad = mcParticle.px(); + float const pyCharmHad = mcParticle.py(); + float const pzCharmHad = mcParticle.pz(); + float const ptCharmHad = mcParticle.pt(); float pxDau{-1000.f}, pyDau{-1000.f}, pzDau{-1000.f}; for (const auto& dauIdx : listDaughters) { auto dauPart = mcParticles.rawIteratorAt(dauIdx - mcParticles.offset()); - if constexpr (channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { + if constexpr (Channel == charm_polarisation::DecayChannel::DstarToDzeroPi) { if (std::abs(dauPart.pdgCode()) == kPiPlus) { pxDau = dauPart.px(); pyDau = dauPart.py(); @@ -1232,16 +2132,14 @@ struct TaskPolarisationCharmHadrons { } } else if (areDauInAcc) { // check also D0 daughters std::vector listDaughtersD0{}; - std::array dauPdgsD0 = {kPiPlus, -kKPlus}; + std::array const 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); - } + areDauInAcc = isDaughterInAcceptance(dauPartD0, 0.3, 0.8); } } - } else if constexpr (channel == charm_polarisation::DecayChannel::LcToPKPi) { + } else if constexpr (Channel == charm_polarisation::DecayChannel::LcToPKPi) { if (std::abs(dauPart.pdgCode()) == kProton) { pxDau = dauPart.px(); pyDau = dauPart.py(); @@ -1253,33 +2151,33 @@ struct TaskPolarisationCharmHadrons { } } - 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); - ROOT::Math::PxPyPzMVector fourVecMother = ROOT::Math::PxPyPzMVector(pxCharmHad, pyCharmHad, pzCharmHad, massCharmHad); - ROOT::Math::Boost boost{fourVecMother.BoostToCM()}; - ROOT::Math::PxPyPzMVector fourVecDauCM = boost(fourVecDau); - ROOT::Math::XYZVector threeVecDauCM = fourVecDauCM.Vect(); + float const phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); + float const thetaRandom = gRandom->Uniform(0.f, constants::math::PI); + ROOT::Math::PxPyPzMVector const fourVecDau = ROOT::Math::PxPyPzMVector(pxDau, pyDau, pzDau, massDau); + ROOT::Math::PxPyPzMVector const fourVecMother = ROOT::Math::PxPyPzMVector(pxCharmHad, pyCharmHad, pzCharmHad, massCharmHad); + ROOT::Math::Boost const boost{fourVecMother.BoostToCM()}; + ROOT::Math::PxPyPzMVector const fourVecDauCM = boost(fourVecDau); + ROOT::Math::XYZVector const threeVecDauCM = fourVecDauCM.Vect(); if (activateTHnSparseCosThStarHelicity) { - ROOT::Math::XYZVector helicityVec = fourVecMother.Vect(); - float cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(helicityVec.Mag2()); - fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarHelicity, origin, ptBhadMother, areDauInAcc, resoChannelLc); + ROOT::Math::XYZVector const helicityVec = fourVecMother.Vect(); + float const cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(helicityVec.Mag2()); + 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, numPvContributors, rapidity, cosThetaStarProduction, origin, ptBhadMother, areDauInAcc, resoChannelLc); + ROOT::Math::XYZVector const normalVec = ROOT::Math::XYZVector(pyCharmHad, -pxCharmHad, 0.f); + float const cosThetaStarProduction = normalVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(normalVec.Mag2()); + 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, numPvContributors, rapidity, cosThetaStarBeam, origin, ptBhadMother, areDauInAcc, resoChannelLc); + ROOT::Math::XYZVector const beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + float const cosThetaStarBeam = beamVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + 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, numPvContributors, rapidity, cosThetaStarRandom, origin, ptBhadMother, areDauInAcc, resoChannelLc); + ROOT::Math::XYZVector const randomVec = ROOT::Math::XYZVector(std::sin(thetaRandom) * std::cos(phiRandom), std::sin(thetaRandom) * std::sin(phiRandom), std::cos(thetaRandom)); + float const cosThetaStarRandom = randomVec.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()); + fillGenHistos(ptCharmHad, numPvContributors, rapidity, cosThetaStarRandom, origin, ptBhadMother, areDauInAcc, resoChannelLc, charge, partRecoDstar); } } @@ -1294,7 +2192,7 @@ struct TaskPolarisationCharmHadrons { { for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); - int numPvContributors = collision.numContrib(); + int const numPvContributors = collision.numContrib(); auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarPerCollision, thisCollId); int nCands{0}, nCandsInSignalRegion{0}; @@ -1311,7 +2209,7 @@ struct TaskPolarisationCharmHadrons { fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processDstar, "Process Dstar candidates without ML", true); + PROCESS_SWITCH(HfTaskCharmPolarisation, processDstar, "Process Dstar candidates without ML", true); // Dstar with ML cuts void processDstarWithMl(aod::Collisions const& collisions, @@ -1320,7 +2218,7 @@ struct TaskPolarisationCharmHadrons { { for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); - int numPvContributors = collision.numContrib(); + int const numPvContributors = collision.numContrib(); auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarWithMlPerCollision, thisCollId); int nCands{0}, nCandsInSignalRegion{0}; @@ -1337,7 +2235,7 @@ struct TaskPolarisationCharmHadrons { fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processDstarWithMl, "Process Dstar candidates with ML", false); + PROCESS_SWITCH(HfTaskCharmPolarisation, processDstarWithMl, "Process Dstar candidates with ML", false); // Dstar in MC with rectangular cuts void processDstarMc(aod::McCollisions::iterator const&, @@ -1349,7 +2247,7 @@ struct TaskPolarisationCharmHadrons { 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(); + int const numPvContributors = collision.numContrib(); auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarWithMcPerCollision, thisCollId); int nCands{0}, nCandsInSignalRegion{0}; @@ -1370,7 +2268,7 @@ struct TaskPolarisationCharmHadrons { runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processDstarMc, "Process Dstar candidates in MC without ML", false); + PROCESS_SWITCH(HfTaskCharmPolarisation, processDstarMc, "Process Dstar candidates in MC without ML", false); // Dstar in MC with ML cuts void processDstarMcWithMl(aod::McCollisions::iterator const&, @@ -1382,7 +2280,7 @@ struct TaskPolarisationCharmHadrons { 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(); + int const numPvContributors = collision.numContrib(); auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarWithMcAndMlPerCollision, thisCollId); int nCands{0}, nCandsInSignalRegion{0}; @@ -1403,7 +2301,145 @@ struct TaskPolarisationCharmHadrons { runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processDstarMcWithMl, "Process Dstar candidates in MC with ML", false); + PROCESS_SWITCH(HfTaskCharmPolarisation, processDstarMcWithMl, "Process Dstar candidates in MC with ML", false); + + void processDstarInPbPb(CollsWithQVecs const& collisions, + FilteredCandDstarWSelFlag const& dstarCandidates, + TracksWithExtra const& tracks) + { + for (const auto& collision : collisions) { + const auto centrality = o2::hf_centrality::getCentralityColl(collision, centEstimator); + if (centrality < centralityMin || centrality > centralityMax) { + continue; // skip this collision if outside of the centrality range + } + registry.fill(HIST("hCentrality"), centrality); + + auto thisCollId = collision.globalIndex(); + int const numPvContributors = collision.numContrib(); + auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + std::vector const qVecs = getQVec(collision); + + for (const auto& dstarCandidate : groupedDstarCandidates) { + nCands++; + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks, &qVecs)) { + nCandsInSignalRegion++; + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); + } + } + PROCESS_SWITCH(HfTaskCharmPolarisation, processDstarInPbPb, "Process Dstar candidates in PbPb collisions", false); + + void processDstarWithMlInPbPb(CollsWithQVecs const& collisions, + FilteredCandDstarWSelFlagAndMl const& dstarCandidates, + TracksWithExtra const& tracks) + { + for (const auto& collision : collisions) { + const auto centrality = o2::hf_centrality::getCentralityColl(collision, centEstimator); + if (centrality < centralityMin || centrality > centralityMax) { + continue; // skip this collision if outside of the centrality range + } + registry.fill(HIST("hCentrality"), centrality); + + auto thisCollId = collision.globalIndex(); + int const numPvContributors = collision.numContrib(); + auto groupedDstarCandidates = dstarCandidates.sliceBy(dstarWithMlPerCollision, thisCollId); + int nCands{0}, nCandsInSignalRegion{0}; + + std::vector const qVecs = getQVec(collision); + + for (const auto& dstarCandidate : groupedDstarCandidates) { + nCands++; + if (runPolarisationAnalysis(dstarCandidate, 0, numPvContributors, -1 /*MC particles*/, tracks, &qVecs)) { + nCandsInSignalRegion++; + } + } + fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); + } + } + PROCESS_SWITCH(HfTaskCharmPolarisation, processDstarWithMlInPbPb, "Process Dstar candidates with ML in PbPb collisions", false); + + void processDstarMcInPbPb(aod::McCollisions::iterator const&, + McParticlesDstarMatched const& mcParticles, + CollisionsWithMcLabelsAndCent const& collisions, // this is grouped with SmallGroupsCollisionsWithMcLabels const& collisions, + FilteredCandDstarWSelFlagAndMc const& dstarCandidates, + TracksWithExtra const& tracks) + { + int numPvContributorsGen{0}; + + for (const auto& collision : collisions) { // loop over reco collisions associated to this gen collision + const auto centrality = o2::hf_centrality::getCentralityColl(collision, centEstimator); + if (centrality < centralityMin || centrality > centralityMax) { + continue; // skip this collision if outside of the centrality range + } + registry.fill(HIST("hCentrality"), centrality); + + auto thisCollId = collision.globalIndex(); + int const 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) { + const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, mcParticle.mcCollision().globalIndex()); + const auto cent = o2::hf_centrality::getCentralityGenColl(recoCollsPerMcColl, centEstimator); + runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen, ¢); + } + } + PROCESS_SWITCH(HfTaskCharmPolarisation, processDstarMcInPbPb, "Process Dstar candidates in PbPb MC without ML", false); + + void processDstarMcWithMlInPbPb(aod::McCollisions::iterator const&, + McParticlesDstarMatched const& mcParticles, + CollisionsWithMcLabelsAndCent const& collisions, // this is grouped with SmallGroupsCollisionsWithMcLabels const& collisions, + FilteredCandDstarWSelFlagAndMcAndMl const& dstarCandidates, + TracksWithExtra const& tracks) + { + int numPvContributorsGen{0}; + + for (const auto& collision : collisions) { // loop over reco collisions associated to this gen collision + const auto centrality = o2::hf_centrality::getCentralityColl(collision, centEstimator); + if (centrality < centralityMin || centrality > centralityMax) { + continue; // skip this collision if outside of the centrality range + } + registry.fill(HIST("hCentrality"), centrality); + + auto thisCollId = collision.globalIndex(); + int const 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) { + const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, mcParticle.mcCollision().globalIndex()); + const auto cent = o2::hf_centrality::getCentralityGenColl(recoCollsPerMcColl, centEstimator); + runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen, ¢); + } + } + PROCESS_SWITCH(HfTaskCharmPolarisation, processDstarMcWithMlInPbPb, "Process Dstar candidates in PbPb MC with ML", false); //////////////////////////// // Lc->pKpi analysis /// @@ -1416,7 +2452,7 @@ struct TaskPolarisationCharmHadrons { { for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); - int numPvContributors = collision.numContrib(); + int const numPvContributors = collision.numContrib(); auto groupedLcCandidates = lcCandidates.sliceBy(lcToPKPiPerCollision, thisCollId); int nCands{0}, nCandsInSignalRegion{0}; @@ -1434,7 +2470,7 @@ struct TaskPolarisationCharmHadrons { fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPi, "Process Lc candidates without ML", false); + PROCESS_SWITCH(HfTaskCharmPolarisation, processLcToPKPi, "Process Lc candidates without ML", false); // Lc->pKpi with ML cuts void processLcToPKPiWithMl(aod::Collisions const& collisions, @@ -1443,7 +2479,7 @@ struct TaskPolarisationCharmHadrons { { for (const auto& collision : collisions) { auto thisCollId = collision.globalIndex(); - int numPvContributors = collision.numContrib(); + int const numPvContributors = collision.numContrib(); auto groupedLcCandidates = lcCandidates.sliceBy(lcToPKPiWithMlPerCollision, thisCollId); int nCands{0}, nCandsInSignalRegion{0}; @@ -1461,7 +2497,7 @@ struct TaskPolarisationCharmHadrons { fillMultHistos(numPvContributors, nCands, nCandsInSignalRegion); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPiWithMl, "Process Lc candidates with ML", false); + PROCESS_SWITCH(HfTaskCharmPolarisation, processLcToPKPiWithMl, "Process Lc candidates with ML", false); // Lc->pKpi in MC with rectangular cuts void processLcToPKPiMc(aod::McCollisions::iterator const&, @@ -1473,7 +2509,7 @@ struct TaskPolarisationCharmHadrons { 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(); + int const numPvContributors = collision.numContrib(); auto groupedLcCandidates = lcCandidates.sliceBy(lcToPKPiWithMcAndMlPerCollision, thisCollId); int nCands{0}, nCandsInSignalRegion{0}; @@ -1494,7 +2530,7 @@ struct TaskPolarisationCharmHadrons { runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPiMc, "Process Lc candidates in MC without ML", false); + PROCESS_SWITCH(HfTaskCharmPolarisation, processLcToPKPiMc, "Process Lc candidates in MC without ML", false); // Lc->pKpi in MC with ML cuts void processLcToPKPiMcWithMl(aod::McCollisions::iterator const&, @@ -1506,7 +2542,7 @@ struct TaskPolarisationCharmHadrons { 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(); + int const numPvContributors = collision.numContrib(); auto groupedLcCandidates = lcCandidates.sliceBy(lcToPKPiWithMcAndMlPerCollision, thisCollId); int nCands{0}, nCandsInSignalRegion{0}; @@ -1527,7 +2563,7 @@ struct TaskPolarisationCharmHadrons { runMcGenPolarisationAnalysis(mcParticle, mcParticles, numPvContributorsGen); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPiMcWithMl, "Process Lc candidates in MC with ML", false); + PROCESS_SWITCH(HfTaskCharmPolarisation, 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, @@ -1542,10 +2578,10 @@ struct TaskPolarisationCharmHadrons { runMcGenPolarisationAnalysis(mcParticle, mcParticles, /*numPvContributorsGen*/ -1); } } - PROCESS_SWITCH(TaskPolarisationCharmHadrons, processLcToPKPiBackgroundMcWithMl, "Process Lc candidates in MC with ML w/o mcCollision grouping", false); + PROCESS_SWITCH(HfTaskCharmPolarisation, processLcToPKPiBackgroundMcWithMl, "Process Lc candidates in MC with ML w/o mcCollision grouping", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGHF/D2H/Tasks/taskCharmResoToDTrkReduced.cxx b/PWGHF/D2H/Tasks/taskCharmResoToDTrkReduced.cxx new file mode 100644 index 00000000000..860825fdb75 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskCharmResoToDTrkReduced.cxx @@ -0,0 +1,482 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file taskCharmResoToDTrkReduced.cxx +/// \brief Charmed Resonances decaying in a D meson and a Track analysis task +/// +/// \author Luca Aglietta , University and INFN Torino + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/Utils/utilsMcMatching.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +enum BachelorType : uint8_t { + K0s = 0, + Lambda, + AntiLambda +}; + +namespace o2::aod +{ +namespace hf_cand_reso_to_trk_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(ItsNClsBach1, itsNClsBach1, int); //! minimum value of number of ITS clusters for the decay daughter tracks of bachelor 1 +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsBach1, tpcNClsCrossedRowsBach1, int); //! minimum value of number of TPC crossed rows for the decay daughter tracks of bachelor 1 +DECLARE_SOA_COLUMN(TpcChi2NClBach1, tpcChi2NClBach1, float); //! maximum value of TPC chi2 for the decay daughter tracks of bachelor 1 +DECLARE_SOA_COLUMN(TpcNSigmaBach1, tpcNSigmaBach1, float); //! NsigmaTPC for Bach1 for its mass hypothesis +DECLARE_SOA_COLUMN(TofNSigmaBach1, tofNSigmaBach1, float); //! NsigmaTOF for Bach1 for its mass hypothesis +DECLARE_SOA_COLUMN(TpcTofNSigmaBach1, tpcTofNSigmaBach1, float); //! Combined NsigmaTPC-TOF for Bach1 for its mass hypothesis +DECLARE_SOA_COLUMN(FlagMcMatch, flagMcMatch, int8_t); //! flag for decay channel classification reconstruction level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int); //! 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(InvMassGen, invMassGen, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(FlagCharmBach, flagCharmBach, int8_t); //! Flag for charm bachelor classification +DECLARE_SOA_COLUMN(FlagCharmBachInterm, flagCharmBachInterm, int8_t); //! Flag for charm bachelor classification intermediate +DECLARE_SOA_COLUMN(NKinkedTracks, nKinkedTracks, int8_t); //! Number of kinked tracks found in MC matching +} // namespace hf_cand_reso_to_trk_lite + +DECLARE_SOA_TABLE(HfCandDTrkLites, "AOD", "HFCANDDTRKLITE", //! Table with some B0 properties + // Candidate Properties + hf_cand_reso_to_trk_lite::M, + hf_cand_reso_to_trk_lite::Pt, + hf_cand_reso_to_trk_lite::P, + hf_cand_reso_to_trk_lite::Y, + hf_cand_reso_to_trk_lite::Eta, + hf_cand_reso_to_trk_lite::Phi, + hf_cand_reso_to_trk_lite::E, + hf_cand_reso_to_trk_lite::CosThetaStar, + hf_cand_reso_to_trk_lite::Sign, + // Bachelors Properties + hf_cand_reso_to_trk_lite::MBach0, + hf_cand_reso_to_trk_lite::PtBach0, + hf_cand_reso_to_trk_lite::MlScoreBkgBach0, + hf_cand_reso_to_trk_lite::MlScorePromptBach0, + hf_cand_reso_to_trk_lite::MlScoreNonPromptBach0, + hf_cand_reso_to_trk_lite::ItsNClsProngMinBach0, + hf_cand_reso_to_trk_lite::TpcNClsCrossedRowsProngMinBach0, + hf_cand_reso_to_trk_lite::TpcChi2NClProngMaxBach0, + hf_cand_reso_to_trk_lite::PtBach1, + hf_cand_reso_to_trk_lite::ItsNClsBach1, + hf_cand_reso_to_trk_lite::TpcNClsCrossedRowsBach1, + hf_cand_reso_to_trk_lite::TpcChi2NClBach1, + hf_cand_reso_to_trk_lite::TpcNSigmaBach1, + hf_cand_reso_to_trk_lite::TofNSigmaBach1, + hf_cand_reso_to_trk_lite::TpcTofNSigmaBach1, + // MC + hf_cand_reso_to_trk_lite::FlagMcMatch, + hf_cand_reso_to_trk_lite::DebugMcRec, + hf_cand_reso_to_trk_lite::Origin, + hf_cand_reso_to_trk_lite::PtGen, + hf_cand_reso_to_trk_lite::InvMassGen, + hf_cand_reso_to_trk_lite::FlagCharmBach, + hf_cand_reso_to_trk_lite::FlagCharmBachInterm, + hf_cand_reso_to_trk_lite::NKinkedTracks); + +DECLARE_SOA_TABLE(HfGenResoLites, "AOD", "HFGENRESOLITE", //! Table with some B0 properties + hf_cand_reso_to_trk_lite::Pt, + hf_cand_reso_to_trk_lite::Y, + hf_cand_reso_to_trk_lite::Origin, + hf_cand_reso_to_trk_lite::FlagMcMatch); + +} // namespace o2::aod + +enum DecayChannel : uint8_t { + D0Kplus = 0 +}; + +struct HfTaskCharmResoToDTrkReduced { + Produces hfCandResoLite; + Produces hfGenResoLite; + + Configurable doWrongSign{"doWrongSign", false, "Flag to enable wrong sign candidates"}; + 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.2, "min. mass of resonance"}; + Configurable massResoMax{"massResoMax", 1.29, "max. mass of resonance"}; + + using ReducedReso2PrTrk = soa::Join; + using ReducedReso2PrTrkMC = soa::Join; + + // 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 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"}; + + // Histogram Registry + HistogramRegistry registry; + + // init + void init(InitContext&) + { + registry.add("hMass", "Charm resonance candidates inv. mass", {HistType::kTH1D, {axisInvMassReso}}); + registry.add("hMassProng0", "D daughters inv. mass", {HistType::kTH1D, {axisInvMassProng0}}); + registry.add("hPt", "Charm resonance candidates pT", {HistType::kTH1D, {axisPt}}); + registry.add("hPtProng0", "D daughters pT", {HistType::kTH1D, {axisPtProng0}}); + registry.add("hPtProng1", "Track daughter pT", {HistType::kTH1D, {axisPtProng1}}); + registry.add("hNPvCont", "Collision number of PV contributors ; N contrib ; entries", {HistType::kTH1D, {{125, -0.5, 249.5}}}); + registry.add("hZvert", "Collision Z Vtx ; z PV [cm] ; entries", {HistType::kTH1D, {{120, -12., 12.}}}); + registry.add("hBz", "Collision Bz ; Bz [T] ; entries", {HistType::kTH1D, {{20, -10., 10.}}}); + registry.add("hSparse", "THn for production studies with cosThStar and BDT scores", HistType::kTHnSparseF, {axisPt, axisPtProng0, axisPtProng1, axisInvMassReso, axisInvMassProng0, axisCosThetaStar, axisBkgBdtScore, axisNonPromptBdtScore}); + + if (doprocessD0KplusMC || doprocessD0KplusMCWithMl) { + // gen histos + registry.add("hYRecPrompt", "Charm resonance candidates pT", {HistType::kTH2D, {axisPt, axisEta}}); + registry.add("hYRecNonPrompt", "Charm resonance candidates pT", {HistType::kTH2D, {axisPt, axisEta}}); + registry.add("hYGenAll", "Prompt {D_{S}}^j particles (generated);#it{p}_{T}^{gen}({D_{S}}^j) (GeV/#it{c});#it{y}^{gen}({D_{S}}^j);entries", {HistType::kTH2D, {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::kTH2D, {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::kTH2D, {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::kTH2D, {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::kTH2D, {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 TrkBach& bach1) + { + // Base + float massReso{0}, cosThetaStar{0}; + int8_t sign{0}; + float tpcNSigmaBach1{0}, tofNSigmaBach1{0}, tpcTofNSigmaBach1{0}; + if constexpr (Channel == DecayChannel::D0Kplus) { + massReso = useDeltaMass ? candidate.invMass() + MassD0 : candidate.invMass(); + cosThetaStar = RecoDecay::cosThetaStar(std::array{bach0.pVector(), bach1.pVector()}, std::array{MassD0, MassKPlus}, massReso, 0); + tpcNSigmaBach1 = bach1.tpcNSigmaKa(); + tofNSigmaBach1 = bach1.tofNSigmaKa(); + tpcTofNSigmaBach1 = bach1.tpcTofNSigmaKa(); + sign = bach1.sign(); + } + float y = RecoDecay::y(std::array{candidate.px(), candidate.py(), candidate.pz()}, massReso); + 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()}, massReso); + + // MC Rec + float ptGen{-1.}, invMassGen{-1}; + int8_t origin{0}, flagMcMatchRec{0}, flagCharmBach{0}, flagCharmBachInterm{0}, nKinkedTracks{0}; + int debugMcRec{-1}; + if constexpr (DoMc) { + ptGen = candidate.ptGen(); + origin = candidate.origin(); + flagMcMatchRec = candidate.flagMcMatchRec(); + debugMcRec = candidate.debugMcRec(); + invMassGen = candidate.invMassGen(); + flagCharmBach = candidate.flagMcMatchRecD(); + flagCharmBachInterm = candidate.flagMcMatchChanD(); + nKinkedTracks = candidate.nTracksDecayed(); + if (fillOnlySignal) { + if (Channel == DecayChannel::D0Kplus && + !hf_decay::hf_cand_reso::particlesToD0Kplus.contains(static_cast(std::abs(flagMcMatchRec)))) { + return; + } + } + if (origin == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hYRecPrompt"), candidate.pt(), y); + } else if (origin == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hYRecNonPrompt"), candidate.pt(), y); + } + } + + // Ml + float mlScoreBkg{-1.}, mlScorePrompt{-1.}, mlScoreNonPrompt{-1.}; + if constexpr (WithMl) { + if constexpr (Channel == DecayChannel::D0Kplus) { + if (bach1.sign() > 0 && !doWrongSign) { + mlScoreBkg = bach0.mlScoreBkgMassHypo0(); + mlScorePrompt = bach0.mlScorePromptMassHypo0(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo0(); + } else if (bach1.sign() < 0 && !doWrongSign) { + mlScoreBkg = bach0.mlScoreBkgMassHypo1(); + mlScorePrompt = bach0.mlScorePromptMassHypo1(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo1(); + } else if (bach1.sign() > 0 && doWrongSign) { + mlScoreBkg = bach0.mlScoreBkgMassHypo1(); + mlScorePrompt = bach0.mlScorePromptMassHypo1(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo1(); + } else if (bach1.sign() < 0 && doWrongSign) { + mlScoreBkg = bach0.mlScoreBkgMassHypo0(); + mlScorePrompt = bach0.mlScorePromptMassHypo0(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo0(); + } + } else { + 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"), candidate.invMass()); + registry.fill(HIST("hMassProng0"), candidate.invMassProng0()); + 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(), candidate.invMass(), candidate.invMassProng0(), cosThetaStar, mlScoreBkg, mlScoreNonPrompt); + } + if (fillTrees) { + hfCandResoLite( + candidate.invMass(), + candidate.pt(), + p, + y, + eta, + phi, + e, + cosThetaStar, + sign, + // Bachelors Properties + candidate.invMassProng0(), + bach0.pt(), + mlScoreBkg, + mlScorePrompt, + mlScoreNonPrompt, + bach0.itsNClsProngMin(), + bach0.tpcNClsCrossedRowsProngMin(), + bach0.tpcChi2NClProngMax(), + bach1.pt(), + bach1.itsNCls(), + bach1.tpcNClsCrossedRows(), + bach1.tpcChi2NCl(), + tpcNSigmaBach1, + tofNSigmaBach1, + tpcTofNSigmaBach1, + // MC + flagMcMatchRec, + debugMcRec, + origin, + ptGen, + invMassGen, + flagCharmBach, + flagCharmBachInterm, + nKinkedTracks); + } + } // 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 TrkBach is the reduced v0 table + /// \param Cand is the candidates table + template + void processData(Coll const&, Candidates const& candidates, CharmBach const&, aod::HfRedTrkNoParams const&) + { + for (const auto& cand : candidates) { + if (ptMinReso >= 0 && cand.pt() < ptMinReso) { + continue; + } + if ((massResoMin >= 0 && cand.invMass() < massResoMin) || + (massResoMax >= 0 && cand.invMass() > massResoMax)) { + continue; + } + if (doWrongSign && cand.isWrongSign() == 0) { + continue; + } + if (!doWrongSign && cand.isWrongSign() != 0) { + continue; + } + + float massReso{0}; + if (useDeltaMass) { + switch (Channel) { + case DecayChannel::D0Kplus: + massReso = cand.invMass() + MassD0; + break; + default: + break; + } + } else { + massReso = cand.invMass(); + } + if (yCandRecoMax >= 0. && std::abs(RecoDecay::y(std::array{cand.px(), cand.py(), cand.pz()}, massReso)) > 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(); + std::array ptProngs = {particle.ptProng0(), particle.ptProng1()}; + std::array etaProngs = {particle.etaProng0(), particle.etaProng1()}; + bool const prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); + if (Channel == DecayChannel::D0Kplus && + !hf_decay::hf_cand_reso::particlesToD0Kplus.contains(static_cast(std::abs(flag)))) { + continue; + } + registry.fill(HIST("hYGenAll"), ptParticle, yParticle); + if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + continue; + } + if (originParticle == RecoDecay::OriginType::Prompt) { // prompt particles + registry.fill(HIST("hYGenPrompt"), ptParticle, yParticle); + if (prongsInAcc) { + registry.fill(HIST("hYGenPromptWithProngsInAcceptance"), ptParticle, yParticle); + } + } else if (originParticle == RecoDecay::OriginType::NonPrompt) { + 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, flag); + } + } + } // fillCandMcGen + + // process functions + void processD0KplusData(aod::HfRedCollisions const& collisions, + ReducedReso2PrTrk const& candidates, + aod::HfRed2PrNoTrks const& charmBachs, + aod::HfRedTrkNoParams const& trkBachs) + { + processData(collisions, candidates, charmBachs, trkBachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDTrkReduced, processD0KplusData, "Process data for D0Kplus analysis", true); + + // Process data with ML + void processD0KplusDataWithMl(aod::HfRedCollisions const& collisions, + ReducedReso2PrTrk const& candidates, + soa::Join const& charmBachs, + aod::HfRedTrkNoParams const& trkBachs) + { + processData(collisions, candidates, charmBachs, trkBachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDTrkReduced, processD0KplusDataWithMl, "Process data for D0Kplus analysis with Ml", false); + + // MC + void processD0KplusMC(aod::HfRedCollisions const& collisions, + ReducedReso2PrTrkMC const& candidates, + aod::HfRed2PrNoTrks const& charmBachs, + aod::HfRedTrkNoParams const& trkBachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, trkBachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDTrkReduced, processD0KplusMC, "Process MC for D0Kplus analysis", false); + + // MC with Ml + void processD0KplusMCWithMl(aod::HfRedCollisions const& collisions, + ReducedReso2PrTrkMC const& candidates, + soa::Join const& charmBachs, + aod::HfRedTrkNoParams const& trkBachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, trkBachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDTrkReduced, processD0KplusMCWithMl, "Process MC for D0Kplus analysis with Ml", false); + +}; // struct HfTaskCharmResoToDTrkReduced +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskCharmResoToDV0Reduced.cxx b/PWGHF/D2H/Tasks/taskCharmResoToDV0Reduced.cxx new file mode 100644 index 00000000000..84ef61e84ba --- /dev/null +++ b/PWGHF/D2H/Tasks/taskCharmResoToDV0Reduced.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 taskCharmResoToDV0Reduced.cxx +/// \brief Charmed Resonances decaying in a D meson and a V0 analysis task +/// +/// \author Luca Aglietta , University and INFN Torino + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/Utils/utilsMcMatching.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::soa; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +enum BachelorType : uint8_t { + K0s = 0, + Lambda, + AntiLambda +}; + +namespace o2::aod +{ +namespace hf_cand_reso_to_v0_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(ItsNClsSoftPi, itsNClsSoftPi, int); //! minimum value of number of ITS clusters for the decay daughter tracks of bachelor 0 +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsSoftPi, tpcNClsCrossedRowsSoftPi, int); //! minimum value of number of TPC crossed rows for the decay daughter tracks of bachelor 0 +DECLARE_SOA_COLUMN(TpcChi2NClSoftPi, tpcChi2NClSoftPi, 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(FlagMcMatch, flagMcMatch, int8_t); //! flag for decay channel classification reconstruction level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int); //! 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(InvMassGen, invMassGen, float); //! Invariant mass of candidate (GeV/c2) +DECLARE_SOA_COLUMN(FlagCharmBach, flagCharmBach, int8_t); //! Flag for charm bachelor classification +DECLARE_SOA_COLUMN(FlagCharmBachInterm, flagCharmBachInterm, int8_t); //! Flag for charm bachelor classification intermediate +DECLARE_SOA_COLUMN(NKinkedTracks, nKinkedTracks, int8_t); //! Number of kinked tracks found in MC matching +} // namespace hf_cand_reso_to_v0_lite + +DECLARE_SOA_TABLE(HfCandDV0Lites, "AOD", "HFCANDDV0LITE", //! Table with some Resonances properties + // Candidate Properties + hf_cand_reso_to_v0_lite::M, + hf_cand_reso_to_v0_lite::Pt, + hf_cand_reso_to_v0_lite::P, + hf_cand_reso_to_v0_lite::Y, + hf_cand_reso_to_v0_lite::Eta, + hf_cand_reso_to_v0_lite::Phi, + hf_cand_reso_to_v0_lite::E, + hf_cand_reso_to_v0_lite::CosThetaStar, + hf_cand_reso_to_v0_lite::Sign, + // Bachelors Properties + hf_cand_reso_to_v0_lite::MBach0, + hf_cand_reso_to_v0_lite::PtBach0, + hf_cand_reso_to_v0_lite::MlScoreBkgBach0, + hf_cand_reso_to_v0_lite::MlScorePromptBach0, + hf_cand_reso_to_v0_lite::MlScoreNonPromptBach0, + hf_cand_reso_to_v0_lite::ItsNClsProngMinBach0, + hf_cand_reso_to_v0_lite::TpcNClsCrossedRowsProngMinBach0, + hf_cand_reso_to_v0_lite::TpcChi2NClProngMaxBach0, + hf_cand_reso_to_v0_lite::ItsNClsSoftPi, + hf_cand_reso_to_v0_lite::TpcNClsCrossedRowsSoftPi, + hf_cand_reso_to_v0_lite::TpcChi2NClSoftPi, + hf_cand_reso_to_v0_lite::MBach1, + hf_cand_reso_to_v0_lite::PtBach1, + hf_cand_reso_to_v0_lite::CpaBach1, + hf_cand_reso_to_v0_lite::DcaBach1, + hf_cand_reso_to_v0_lite::RadiusBach1, + hf_cand_reso_to_v0_lite::ItsNClsProngMinBach1, + hf_cand_reso_to_v0_lite::TpcNClsCrossedRowsProngMinBach1, + hf_cand_reso_to_v0_lite::TpcChi2NClProngMaxBach1, + // MC + hf_cand_reso_to_v0_lite::FlagMcMatch, + hf_cand_reso_to_v0_lite::DebugMcRec, + hf_cand_reso_to_v0_lite::Origin, + hf_cand_reso_to_v0_lite::PtGen, + hf_cand_reso_to_v0_lite::InvMassGen, + hf_cand_reso_to_v0_lite::FlagCharmBach, + hf_cand_reso_to_v0_lite::FlagCharmBachInterm, + hf_cand_reso_to_v0_lite::NKinkedTracks); + +DECLARE_SOA_TABLE(HfGenResoLites, "AOD", "HFGENRESOLITE", //! Table with some B0 properties + hf_cand_reso_to_v0_lite::Pt, + hf_cand_reso_to_v0_lite::Y, + hf_cand_reso_to_v0_lite::Origin, + hf_cand_reso_to_v0_lite::FlagMcMatch); + +} // namespace o2::aod + +enum DecayChannel : uint8_t { + DstarK0s = 0, + DplusK0s, + DplusLambda, + D0Lambda +}; + +struct HfTaskCharmResoToDV0Reduced { + Produces hfCandResoLite; + Produces hfGenResoLite; + + Configurable doWrongSign{"doWrongSign", false, "Flag to enable wrong sign candidates"}; + 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"}; + + using ReducedReso3PrV0 = soa::Join; + using ReducedResoDstarV0 = soa::Join; + using ReducedReso2PrV0 = soa::Join; + using ReducedReso3PrV0MC = soa::Join; + using ReducedResoDstarV0MC = soa::Join; + using ReducedReso2PrV0MC = soa::Join; + + // 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"}; + + // Histogram Registry + HistogramRegistry registry; + + // init + void init(InitContext&) + { + registry.add("hMass", "Charm resonance candidates inv. mass", {HistType::kTH1D, {axisInvMassReso}}); + registry.add("hMassProng0", "D daughters inv. mass", {HistType::kTH1D, {axisInvMassProng0}}); + registry.add("hMassProng1", "V0 daughter inv. mass", {HistType::kTH1D, {axisInvMassProng1}}); + registry.add("hPt", "Charm resonance candidates pT", {HistType::kTH1D, {axisPt}}); + registry.add("hPtProng0", "D daughters pT", {HistType::kTH1D, {axisPtProng0}}); + registry.add("hPtProng1", "V0 daughter pT", {HistType::kTH1D, {axisPtProng1}}); + registry.add("hNPvCont", "Collision number of PV contributors ; N contrib ; entries", {HistType::kTH1D, {{125, -0.5, 249.5}}}); + registry.add("hZvert", "Collision Z Vtx ; z PV [cm] ; entries", {HistType::kTH1D, {{120, -12., 12.}}}); + registry.add("hBz", "Collision Bz ; Bz [T] ; entries", {HistType::kTH1D, {{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 (doprocessDstarK0sMC || doprocessDplusK0sMC || doprocessDstarK0sMCWithMl || doprocessDplusK0sMCWithMl || + doprocessDplusLambdaMC || doprocessD0LambdaMC || doprocessDplusLambdaMCWithMl || doprocessD0LambdaMCWithMl) { + // gen histos + registry.add("hYRecPrompt", "Charm resonance candidates pT", {HistType::kTH2D, {axisPt, axisEta}}); + registry.add("hYRecNonPrompt", "Charm resonance candidates pT", {HistType::kTH2D, {axisPt, axisEta}}); + registry.add("hYGenAll", "Prompt {D_{S}}^j particles (generated);#it{p}_{T}^{gen}({D_{S}}^j) (GeV/#it{c});#it{y}^{gen}({D_{S}}^j);entries", {HistType::kTH2D, {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::kTH2D, {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::kTH2D, {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::kTH2D, {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::kTH2D, {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) + { + // Base + float massReso{0}, cosThetaStar{0}; + int8_t sign{0}; + int itsNClsSoftPi{0}, tpcNClsCrossedRowsSoftPi{0}; + float tpcChi2NClSoftPi{0.}; + if constexpr (Channel == DecayChannel::DstarK0s) { + sign = bach0.sign(); + massReso = useDeltaMass ? candidate.invMass() + MassDStar : candidate.invMass(); + cosThetaStar = RecoDecay::cosThetaStar(std::array{bach0.pVector(), bach1.pVector()}, std::array{MassDStar, MassK0}, massReso, 0); + itsNClsSoftPi = bach0.itsNClsSoftPi(); + tpcNClsCrossedRowsSoftPi = bach0.tpcNClsCrossedRowsSoftPi(); + tpcChi2NClSoftPi = bach0.tpcChi2NClSoftPi(); + } else if constexpr (Channel == DecayChannel::DplusK0s) { + sign = bach0.sign(); + massReso = useDeltaMass ? candidate.invMass() + MassDPlus : candidate.invMass(); + cosThetaStar = RecoDecay::cosThetaStar(std::array{bach0.pVector(), bach1.pVector()}, std::array{MassDPlus, MassK0}, massReso, 0); + } else if constexpr (Channel == DecayChannel::DplusLambda) { + sign = bach0.sign(); + massReso = useDeltaMass ? candidate.invMass() + MassDPlus : candidate.invMass(); + cosThetaStar = RecoDecay::cosThetaStar(std::array{bach0.pVector(), bach1.pVector()}, std::array{MassDPlus, MassLambda0}, massReso, 0); + } else if constexpr (Channel == DecayChannel::D0Lambda) { + massReso = useDeltaMass ? candidate.invMass() + MassD0 : candidate.invMass(); + cosThetaStar = RecoDecay::cosThetaStar(std::array{bach0.pVector(), bach1.pVector()}, std::array{MassD0, MassLambda0}, massReso, 0); + } + float y = RecoDecay::y(std::array{candidate.px(), candidate.py(), candidate.pz()}, massReso); + 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()}, massReso); + + // MC Rec + float ptGen{-1.}, invMassGen{-1}; + int8_t origin{0}, flagMcMatchRec{0}, flagCharmBach{0}, flagCharmBachInterm{0}, nKinkedTracks{0}; + int debugMcRec{-1}; + if constexpr (DoMc) { + ptGen = candidate.ptGen(); + origin = candidate.origin(); + flagMcMatchRec = candidate.flagMcMatchRec(); + debugMcRec = candidate.debugMcRec(); + invMassGen = candidate.invMassGen(); + flagCharmBach = candidate.flagMcMatchRecD(); + flagCharmBachInterm = candidate.flagMcMatchChanD(); + nKinkedTracks = candidate.nTracksDecayed(); + if (fillOnlySignal) { + if (Channel == DecayChannel::DstarK0s && + !hf_decay::hf_cand_reso::particlesToDstarK0s.contains(static_cast(std::abs(flagMcMatchRec)))) { + return; + } + if (Channel == DecayChannel::DplusK0s && + !hf_decay::hf_cand_reso::particlesToDplusK0s.contains(static_cast(std::abs(flagMcMatchRec)))) { + return; + } + if (Channel == DecayChannel::DplusLambda && + !hf_decay::hf_cand_reso::particlesToDplusLambda.contains(static_cast(std::abs(flagMcMatchRec)))) { + return; + } + if (Channel == DecayChannel::D0Lambda && + !hf_decay::hf_cand_reso::particlesToD0Lambda.contains(static_cast(std::abs(flagMcMatchRec)))) { + return; + } + } + if (origin == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hYRecPrompt"), candidate.pt(), y); + } else if (origin == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hYRecNonPrompt"), candidate.pt(), y); + } + } + + // Ml + float mlScoreBkg{-1.}, mlScorePrompt{-1.}, mlScoreNonPrompt{-1.}; + if constexpr (WithMl) { + if constexpr (Channel == DecayChannel::D0Lambda) { + if (TESTBIT(bach1.v0Type(), BachelorType::Lambda) && !doWrongSign) { + mlScoreBkg = bach0.mlScoreBkgMassHypo0(); + mlScorePrompt = bach0.mlScorePromptMassHypo0(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo0(); + } else if (TESTBIT(bach1.v0Type(), BachelorType::AntiLambda) && !doWrongSign) { + mlScoreBkg = bach0.mlScoreBkgMassHypo1(); + mlScorePrompt = bach0.mlScorePromptMassHypo1(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo1(); + } else if (TESTBIT(bach1.v0Type(), BachelorType::Lambda) && doWrongSign) { + mlScoreBkg = bach0.mlScoreBkgMassHypo1(); + mlScorePrompt = bach0.mlScorePromptMassHypo1(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo1(); + } else if (TESTBIT(bach1.v0Type(), BachelorType::AntiLambda) && doWrongSign) { + mlScoreBkg = bach0.mlScoreBkgMassHypo0(); + mlScorePrompt = bach0.mlScorePromptMassHypo0(); + mlScoreNonPrompt = bach0.mlScoreNonpromptMassHypo0(); + } + } else { + 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"), candidate.invMass()); + registry.fill(HIST("hMassProng0"), candidate.invMassProng0()); + registry.fill(HIST("hMassProng1"), candidate.invMassProng1()); + 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(), candidate.invMass(), candidate.invMassProng0(), candidate.invMassProng1(), cosThetaStar, mlScoreBkg, mlScoreNonPrompt); + } + if (fillTrees) { + hfCandResoLite( + candidate.invMass(), + candidate.pt(), + p, + y, + eta, + phi, + e, + cosThetaStar, + sign, + // Bachelors Properties + candidate.invMassProng0(), + bach0.pt(), + mlScoreBkg, + mlScorePrompt, + mlScoreNonPrompt, + bach0.itsNClsProngMin(), + bach0.tpcNClsCrossedRowsProngMin(), + bach0.tpcChi2NClProngMax(), + itsNClsSoftPi, + tpcNClsCrossedRowsSoftPi, + tpcChi2NClSoftPi, + candidate.invMassProng1(), + bach1.pt(), + bach1.cpa(), + bach1.dca(), + bach1.v0Radius(), + bach1.itsNClsProngMin(), + bach1.tpcNClsCrossedRowsProngMin(), + bach1.tpcChi2NClProngMax(), + // MC + flagMcMatchRec, + debugMcRec, + origin, + ptGen, + invMassGen, + flagCharmBach, + flagCharmBachInterm, + nKinkedTracks); + } + } // 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; + } + if ((massResoMin >= 0 && cand.invMass() < massResoMin) || + (massResoMax >= 0 && cand.invMass() > massResoMax)) { + continue; + } + if (doWrongSign && cand.isWrongSign() == 0) { + continue; + } + if (!doWrongSign && cand.isWrongSign() != 0) { + continue; + } + + float massReso{0}; + if (useDeltaMass) { + switch (Channel) { + case DecayChannel::DstarK0s: + massReso = cand.invMass() + MassDStar; + break; + case DecayChannel::DplusK0s: + massReso = cand.invMass() + MassDPlus; + break; + case DecayChannel::DplusLambda: + massReso = cand.invMass() + MassDPlus; + break; + case DecayChannel::D0Lambda: + massReso = cand.invMass() + MassD0; + break; + default: + break; + } + } else { + massReso = cand.invMass(); + } + if (yCandRecoMax >= 0. && std::abs(RecoDecay::y(std::array{cand.px(), cand.py(), cand.pz()}, massReso)) > 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(); + std::array ptProngs = {particle.ptProng0(), particle.ptProng1()}; + std::array etaProngs = {particle.etaProng0(), particle.etaProng1()}; + bool const prongsInAcc = isProngInAcceptance(etaProngs[0], ptProngs[0]) && isProngInAcceptance(etaProngs[1], ptProngs[1]); + if (Channel == DecayChannel::DstarK0s && + !hf_decay::hf_cand_reso::particlesToDstarK0s.contains(static_cast(std::abs(flag)))) { + continue; + } + if (Channel == DecayChannel::DplusK0s && + !hf_decay::hf_cand_reso::particlesToDplusK0s.contains(static_cast(std::abs(flag)))) { + continue; + } + if (Channel == DecayChannel::DplusLambda && + !hf_decay::hf_cand_reso::particlesToDplusLambda.contains(static_cast(std::abs(flag)))) { + continue; + } + if (Channel == DecayChannel::D0Lambda && + !hf_decay::hf_cand_reso::particlesToD0Lambda.contains(static_cast(std::abs(flag)))) { + continue; + } + registry.fill(HIST("hYGenAll"), ptParticle, yParticle); + if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { + continue; + } + if (originParticle == RecoDecay::OriginType::Prompt) { // prompt particles + registry.fill(HIST("hYGenPrompt"), ptParticle, yParticle); + if (prongsInAcc) { + registry.fill(HIST("hYGenPromptWithProngsInAcceptance"), ptParticle, yParticle); + } + } else if (originParticle == RecoDecay::OriginType::NonPrompt) { + 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, flag); + } + } + } // fillCandMcGen + + // process functions + void processDstarK0sData(aod::HfRedCollisions const& collisions, + ReducedResoDstarV0 const& candidates, + aod::HfRedDstarNoTrks const& charmBachs, + aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDstarK0sData, "Process data for DstarK0s analysis", true); + + void processDplusK0sData(aod::HfRedCollisions const& collisions, + ReducedReso3PrV0 const& candidates, + aod::HfRed3PrNoTrks const& charmBachs, + aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDplusK0sData, "Process data for DplusK0s analysis", false); + + void processDplusLambdaData(aod::HfRedCollisions const& collisions, + ReducedReso3PrV0 const& candidates, + aod::HfRed3PrNoTrks const& charmBachs, + aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDplusLambdaData, "Process data for DplusLambda analysis", false); + + void processD0LambdaData(aod::HfRedCollisions const& collisions, + ReducedReso2PrV0 const& candidates, + aod::HfRed2PrNoTrks const& charmBachs, + aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processD0LambdaData, "Process data for D0Lambda analysis", false); + + // Process data with ML + void processDstarK0sDataWithMl(aod::HfRedCollisions const& collisions, + ReducedResoDstarV0 const& candidates, + soa::Join const& charmBachs, + aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDstarK0sDataWithMl, "Process data for DstarK0s analysis with Ml", false); + + void processDplusK0sDataWithMl(aod::HfRedCollisions const& collisions, + ReducedReso3PrV0 const& candidates, + soa::Join const& charmBachs, + aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDplusK0sDataWithMl, "Process data for DplusK0s analysis with Ml", false); + + void processDplusLambdaDataWithMl(aod::HfRedCollisions const& collisions, + ReducedReso3PrV0 const& candidates, + soa::Join const& charmBachs, + aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDplusLambdaDataWithMl, "Process data for DplusLambda analysis with Ml", false); + + void processD0LambdaDataWithMl(aod::HfRedCollisions const& collisions, + ReducedReso2PrV0 const& candidates, + soa::Join const& charmBachs, + aod::HfRedVzeros const& v0Bachs) + { + processData(collisions, candidates, charmBachs, v0Bachs); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processD0LambdaDataWithMl, "Process data for D0Lambda analysis with Ml", false); + + // MC + void processDstarK0sMC(aod::HfRedCollisions const& collisions, + ReducedResoDstarV0MC const& candidates, + aod::HfRedDstarNoTrks const& charmBachs, + aod::HfRedVzeros const& v0Bachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDstarK0sMC, "Process MC for DstarK0s analysis", false); + + void processDplusK0sMC(aod::HfRedCollisions const& collisions, + ReducedReso3PrV0MC const& candidates, + aod::HfRed3PrNoTrks const& charmBachs, + aod::HfRedVzeros const& v0Bachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDplusK0sMC, "Process MC for DplusK0s analysis", false); + + void processDplusLambdaMC(aod::HfRedCollisions const& collisions, + ReducedReso3PrV0MC const& candidates, + aod::HfRed3PrNoTrks const& charmBachs, + aod::HfRedVzeros const& v0Bachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDplusLambdaMC, "Process MC for DplusLambda analysis", false); + + void processD0LambdaMC(aod::HfRedCollisions const& collisions, + ReducedReso2PrV0MC const& candidates, + aod::HfRed2PrNoTrks const& charmBachs, + aod::HfRedVzeros const& v0Bachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processD0LambdaMC, "Process MC for D0Lambda analysis", false); + + // MC with Ml + void processDstarK0sMCWithMl(aod::HfRedCollisions const& collisions, + ReducedResoDstarV0MC const& candidates, + soa::Join const& charmBachs, + aod::HfRedVzeros const& v0Bachs, + aod::HfMcGenRedResos const& charmBachsMc) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(charmBachsMc); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDstarK0sMCWithMl, "Process MC for DstarK0s analysis with Ml", false); + + void processDplusK0sMCWithMl(aod::HfRedCollisions const& collisions, + ReducedReso3PrV0MC const& candidates, + soa::Join const& charmBachs, + aod::HfRedVzeros const& v0Bachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDplusK0sMCWithMl, "Process MC for DplusK0s analysis with Ml", false); + + void processDplusLambdaMCWithMl(aod::HfRedCollisions const& collisions, + ReducedReso3PrV0MC const& candidates, + soa::Join const& charmBachs, + aod::HfRedVzeros const& v0Bachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processDplusLambdaMCWithMl, "Process MC for DplusLambda analysis with Ml", false); + + void processD0LambdaMCWithMl(aod::HfRedCollisions const& collisions, + ReducedReso2PrV0MC const& candidates, + soa::Join const& charmBachs, + aod::HfRedVzeros const& v0Bachs, + aod::HfMcGenRedResos const& mcParticles) + { + processData(collisions, candidates, charmBachs, v0Bachs); + fillCandMcGen(mcParticles); + } + PROCESS_SWITCH(HfTaskCharmResoToDV0Reduced, processD0LambdaMCWithMl, "Process MC for D0Lambda analysis with Ml", false); + +}; // struct HfTaskCharmResoToDV0Reduced +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index e778ae64a9e..45e20eea651 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -14,29 +14,66 @@ /// /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN +/// \author Minjung Kim , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsUpcHf.h" +#include "PWGUD/Core/UPCHelpers.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include // std::min +#include +#include +#include +#include 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; +using namespace o2::hf_evsel; +using namespace o2::analysis::hf_upc; /// 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,32 +86,44 @@ 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 storeOccupancyAndIR{"storeOccupancyAndIR", false, "Flag to store occupancy information and interaction rate"}; + Configurable storeTrackQuality{"storeTrackQuality", false, "Flag to store track quality information"}; // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - // 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 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", {4, -0.5, 3.5}, "D0 type"}; - ConfigurableAxis thnConfigAxisGenPtD{"thnConfigAxisGenPtD", {500, 0, 50}, "Gen Pt D"}; - ConfigurableAxis thnConfigAxisGenPtB{"thnConfigAxisGenPtB", {1000, 0, 100}, "Gen Pt B"}; + HfEventSelection hfEvSel; // event selection and monitoring + HfUpcGapThresholds upcThresholds; // UPC gap determination thresholds + ctpRateFetcher mRateFetcher; + + SliceCache cache; + Service ccdb; + + using D0Candidates = soa::Filtered>; + using D0CandidatesMc = soa::Filtered>; + using D0CandidatesKF = soa::Filtered>; + using D0CandidatesMcKF = soa::Filtered>; - HfHelper hfHelper; + using D0CandidatesMl = soa::Filtered>; + using D0CandidatesMlMc = soa::Filtered>; + using D0CandidatesMlKF = soa::Filtered>; + using D0CandidatesMlMcKF = soa::Filtered>; - using D0Candidates = soa::Join; - using D0CandidatesMc = soa::Join; - using D0CandidatesKF = soa::Join; - using D0CandidatesMcKF = soa::Join; + using Collisions = soa::Join; + using CollisionsCent = soa::Join; + using CollisionsWithMcLabels = soa::Join; + using CollisionsWithMcLabelsCent = soa::Join; + using TracksSelQuality = soa::Join; - using D0CandidatesMl = soa::Join; - using D0CandidatesMlMc = soa::Join; - using D0CandidatesMlKF = soa::Join; - using D0CandidatesMlMcKF = soa::Join; + Filter filterD0Flag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK))) != static_cast(0); + + Preslice candD0PerCollision = aod::hf_cand::collisionId; + 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; @@ -86,6 +135,30 @@ 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"}; + ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (see TrueGap enum in o2::aod::sgselector)"}; + ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisZN{"thnConfigAxisZN", {510, -1.5, 49.5}, "axis for ZN energy (a.u.)"}; + HistogramRegistry registry{ "registry", {{"hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, @@ -164,14 +237,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, doprocessDataWithDCAFitterNWithUpc, doprocessDataWithDCAFitterNMlWithUpc}; 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 || storeOccupancyAndIR) && !(doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMlCent || doprocessDataWithDCAFitterNWithUpc || doprocessDataWithDCAFitterNMlWithUpc)) { + LOGP(fatal, "Can't enable the storeCentrality and storeOccupancu without cent process or UPC 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}}}); @@ -211,44 +286,128 @@ 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"}; + const AxisSpec thnAxisIR{thnConfigAxisIR, "Interaction rate"}; + const AxisSpec thnAxisGapType{thnConfigAxisGapType, "Gap type"}; + const AxisSpec thnAxisFT0A{thnConfigAxisFT0, "FT0-A amplitude"}; + const AxisSpec thnAxisFT0C{thnConfigAxisFT0, "FT0-C amplitude"}; + const AxisSpec thnAxisFV0A{thnConfigAxisFV0A, "FV0-A amplitude"}; + const AxisSpec thnAxisFDDA{thnConfigAxisFDD, "FDD-A amplitude"}; + const AxisSpec thnAxisFDDC{thnConfigAxisFDD, "FDD-C amplitude"}; + const AxisSpec thnAxisZNA{thnConfigAxisZN, "ZNA energy"}; + const AxisSpec thnAxisZNC{thnConfigAxisZN, "ZNC energy"}; + + if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { + std::vector axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr}; + + if (storeCentrality) { + axesAcc.push_back(thnAxisCent); + } + // interaction rate only store in Data and MC Reco. Level + if (storeOccupancyAndIR) { + 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 (storeOccupancyAndIR) { + axes.push_back(thnAxisOccupancy); + axes.push_back(thnAxisIR); + } + 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 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})"}; - - registry.add("hSparseAcc", "Thn for generated D0 from charm and beauty", HistType::kTHnSparseD, {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin}); - registry.get(HIST("hSparseAcc"))->Sumw2(); + const AxisSpec thnAxisPromptScore{thnConfigAxisPromptScore, "BDT score prompt."}; + + // Insert ML scores after pt (position 2) to match taskDplus structure: [mass, pt, mlScores, ...] + if (doprocessDataWithDCAFitterNMlWithUpc) { + axes.insert(axes.begin() + 2, thnAxisPromptScore); + axes.insert(axes.begin() + 2, thnAxisNonPromptScore); + axes.insert(axes.begin() + 2, thnAxisBkgScore); + } else { + axes.insert(axes.begin(), thnAxisPromptScore); + axes.insert(axes.begin(), thnAxisNonPromptScore); + axes.insert(axes.begin(), thnAxisBkgScore); + } + } + if (doprocessDataWithDCAFitterNMlWithUpc || doprocessDataWithDCAFitterNWithUpc) { + axes.push_back(thnAxisGapType); + axes.push_back(thnAxisFT0A); + axes.push_back(thnAxisFT0C); + axes.push_back(thnAxisFV0A); + axes.push_back(thnAxisFDDA); + axes.push_back(thnAxisFDDC); + axes.push_back(thnAxisZNA); + axes.push_back(thnAxisZNC); + } - registry.add("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type", "Thn for D0 candidates with BDT scores", HistType::kTHnSparseD, {thnAxisBkgScore, thnAxisNonPromptScore, thnAxisMass, thnAxisPt, thnAxisPtB, thnAxisY, thnAxisOrigin, thnAxisCandType}); + if (applyMl) { + 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(); } + + registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); + registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap type;Counts", {HistType::kTH1F, {{7, -1.5, 5.5}}}); + + hfEvSel.addHistograms(registry); + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); } - template - void processData(CandType const& candidates) + template + void processData(CandType const& candidates, + CollType const&, + aod::TracksWExtra const&, + BCsType const&) { for (const auto& candidate : candidates) { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (yCandRecoMax >= 0. && std::abs(hfHelper.yD0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > yCandRecoMax) { continue; } float massD0, massD0bar; - if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { massD0 = candidate.kfGeoMassD0(); massD0bar = candidate.kfGeoMassD0bar(); } else { - massD0 = hfHelper.invMassD0ToPiK(candidate); - massD0bar = hfHelper.invMassD0barToKPi(candidate); + massD0 = HfHelper::invMassD0ToPiK(candidate); + massD0bar = HfHelper::invMassD0barToKPi(candidate); } auto ptCandidate = candidate.pt(); @@ -276,8 +435,8 @@ struct HfTaskD0 { registry.fill(HIST("hd0ErrProng0"), candidate.errorImpactParameter0(), ptCandidate); registry.fill(HIST("hd0ErrProng1"), candidate.errorImpactParameter1(), ptCandidate); registry.fill(HIST("hd0d0"), candidate.impactParameterProduct(), ptCandidate); - registry.fill(HIST("hCTS"), hfHelper.cosThetaStarD0(candidate), ptCandidate); - registry.fill(HIST("hCt"), hfHelper.ctD0(candidate), ptCandidate); + registry.fill(HIST("hCTS"), HfHelper::cosThetaStarD0(candidate), ptCandidate); + registry.fill(HIST("hCt"), HfHelper::ctD0(candidate), ptCandidate); registry.fill(HIST("hCPA"), candidate.cpa(), ptCandidate); registry.fill(HIST("hEta"), candidate.eta(), ptCandidate); registry.fill(HIST("hSelectionStatus"), candidate.isSelD0() + (candidate.isSelD0bar() * 2), ptCandidate); @@ -286,75 +445,347 @@ struct HfTaskD0 { registry.fill(HIST("hd0Prong0FinerBinning"), candidate.impactParameter0(), ptCandidate); registry.fill(HIST("hd0Prong1FinerBinning"), candidate.impactParameter1(), ptCandidate); registry.fill(HIST("hd0d0FinerBinning"), candidate.impactParameterProduct(), ptCandidate); - registry.fill(HIST("hCTSFinerBinning"), hfHelper.cosThetaStarD0(candidate), ptCandidate); - registry.fill(HIST("hCtFinerBinning"), hfHelper.ctD0(candidate), ptCandidate); + registry.fill(HIST("hCTSFinerBinning"), HfHelper::cosThetaStarD0(candidate), ptCandidate); + registry.fill(HIST("hCtFinerBinning"), HfHelper::ctD0(candidate), ptCandidate); registry.fill(HIST("hCPAFinerBinning"), candidate.cpa(), ptCandidate); registry.fill(HIST("hCPAXYFinerBinning"), candidate.cpaXY(), ptCandidate); - if constexpr (applyMl) { + float cent{-1.f}; + float occ{-1.f}; + float ir{-1.f}; + if (storeCentrality || storeOccupancyAndIR) { + auto collision = candidate.template collision_as(); + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(collision, centEstimator); + } + if (storeOccupancyAndIR && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + auto bc = collision.template foundBC_as(); + ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz + } + } + + auto trackPos = candidate.template prong0_as(); // positive daughter + auto trackNeg = candidate.template prong1_as(); // negative daughter + int const minItsClustersOfProngs = std::min(trackPos.itsNCls(), trackNeg.itsNCls()); + int const minTpcCrossedRowsOfProngs = std::min(trackPos.tpcNClsCrossedRows(), trackNeg.tpcNClsCrossedRows()); + if constexpr (ApplyMl) { + if (storeCentrality && storeOccupancyAndIR) { + 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, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, cent, occ, ir); + } + 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, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, cent, occ, ir); + } + } else if (storeCentrality && !storeOccupancyAndIR) { + 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 && storeOccupancyAndIR) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, occ, ir); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, occ, ir); + } + } 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); + } + } + } else { + if (storeCentrality && storeOccupancyAndIR) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, cent, occ, ir); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, cent, occ, ir); + } + } else if (storeCentrality && !storeOccupancyAndIR) { + 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 && storeOccupancyAndIR) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, occ, ir); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, occ, ir); + } + } 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); + } + } + } + } + } + + template + void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, + CandType const& candidates, + BCsType const& bcs, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds) + { + for (const auto& collision : collisions) { + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); + if (rejectionMask != 0) { + continue; + } + const auto& bc = collision.template bc_as(); + + // Determine gap type using SGSelector with BC range checking + const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); + const int gap = gapResult.value; + + // Use the BC with FIT activity if available from SGSelector + auto bcForUPC = bc; + if (gapResult.bc) { + bcForUPC = *(gapResult.bc); + } + + // Get FIT information from the UPC BC + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bcForUPC, bcs, ft0s, fv0as, fdds); + + // Get ZDC energies if available (extract once and reuse) + const bool hasZdc = bcForUPC.has_zdc(); + float zdcEnergyZNA = -1.f; + float zdcEnergyZNC = -1.f; + if (hasZdc) { + const auto& zdc = bcForUPC.zdc(); + zdcEnergyZNA = zdc.energyCommonZNA(); + zdcEnergyZNC = zdc.energyCommonZNC(); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); + } + + registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + registry.fill(HIST("Data/hUpcGapAfterSelection"), gap); + + const auto thisCollId = collision.globalIndex(); + const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); + + // Calculate occupancy and interaction rate if needed + float occ{-1.f}; + float ir{-1.f}; + if (storeOccupancyAndIR && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz + } + + for (const auto& candidate : groupedD0Candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > yCandRecoMax) { + continue; + } + + const float massD0 = HfHelper::invMassD0ToPiK(candidate); + const float massD0bar = HfHelper::invMassD0barToKPi(candidate); + const auto ptCandidate = candidate.pt(); + if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], massD0, ptCandidate, -1, hfHelper.yD0(candidate), 0, SigD0); + registry.fill(HIST("hMass"), massD0, ptCandidate); + registry.fill(HIST("hMassFinerBinning"), massD0, ptCandidate); + registry.fill(HIST("hMassVsPhi"), massD0, ptCandidate, candidate.phi()); } if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], massD0bar, ptCandidate, -1, hfHelper.yD0(candidate), 0, SigD0bar); + registry.fill(HIST("hMass"), massD0bar, ptCandidate); + registry.fill(HIST("hMassFinerBinning"), massD0bar, ptCandidate); + registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); + } + + // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC] + auto fillTHnData = [&](float mass, int d0Type) { + // Pre-calculate vector size to avoid reallocations + constexpr int NAxesBase = 12; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC + constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality + int const nAxesOccIR = storeOccupancyAndIR ? 2 : 0; // occupancy and IR if storeOccupancyAndIR + int const nAxesTotal = NAxesBase + NAxesMl + nAxesCent + nAxesOccIR; + + std::vector valuesToFill; + valuesToFill.reserve(nAxesTotal); + + // Fill values in order matching histogram axes + valuesToFill.push_back(static_cast(mass)); + valuesToFill.push_back(static_cast(ptCandidate)); + if constexpr (FillMl) { + valuesToFill.push_back(candidate.mlProbD0()[0]); + valuesToFill.push_back(candidate.mlProbD0()[1]); + valuesToFill.push_back(candidate.mlProbD0()[2]); + } + valuesToFill.push_back(static_cast(HfHelper::yD0(candidate))); + valuesToFill.push_back(static_cast(d0Type)); + if (storeCentrality) { + valuesToFill.push_back(centrality); + } + if (storeOccupancyAndIR) { + valuesToFill.push_back(occ); + valuesToFill.push_back(ir); + } + valuesToFill.push_back(static_cast(gap)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + valuesToFill.push_back(static_cast(fitInfo.ampFV0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDA)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); + valuesToFill.push_back(static_cast(zdcEnergyZNA)); + valuesToFill.push_back(static_cast(zdcEnergyZNC)); + + if constexpr (FillMl) { + registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); + } else { + registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); + } + }; + + if (candidate.isSelD0() >= selectionFlagD0) { + fillTHnData(massD0, SigD0); + fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + fillTHnData(massD0bar, SigD0bar); + fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); } } } } - void processDataWithDCAFitterN(D0Candidates const&) + + void processDataWithDCAFitterN(D0Candidates const&, Collisions const& collisions, aod::TracksWExtra const& tracks, aod::BcFullInfos const& bcs) { - processData(selectedD0Candidates); + processData(selectedD0Candidates, collisions, tracks, bcs); } PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterN, "process taskD0 with DCAFitterN", true); - void processDataWithKFParticle(D0CandidatesKF const&) + void processDataWithDCAFitterNCent(D0Candidates const&, CollisionsCent const& collisions, aod::TracksWExtra const& tracks, aod::BcFullInfos const& bcs) { - processData(selectedD0CandidatesKF); + processData(selectedD0Candidates, collisions, tracks, bcs); + } + PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNCent, "process taskD0 with DCAFitterN and centrality", false); + + void processDataWithKFParticle(D0CandidatesKF const&, Collisions const& collisions, aod::TracksWExtra const& tracks, aod::BcFullInfos const& bcs) + { + processData(selectedD0CandidatesKF, collisions, tracks, bcs); } 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, aod::BcFullInfos const& bcs) { - processData(selectedD0CandidatesMl); + processData(selectedD0CandidatesMl, collisions, tracks, bcs); } 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, aod::BcFullInfos const& bcs) + { + processData(selectedD0CandidatesMl, collisions, tracks, bcs); + } + 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, aod::BcFullInfos const& bcs) { - processData(selectedD0CandidatesMlKF); + processData(selectedD0CandidatesMlKF, collisions, tracks, bcs); } 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&, + BCsType const&) { // MC rec. for (const auto& candidate : candidates) { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (yCandRecoMax >= 0. && std::abs(hfHelper.yD0(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > yCandRecoMax) { continue; } + + float cent{-1.f}; + float occ{-1.f}; + float ir{-1.f}; + auto collision = candidate.template collision_as(); + auto numPvContributors = collision.numContrib(); + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(collision, centEstimator); + } + if (storeOccupancyAndIR && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + auto bc = collision.template foundBC_as(); + ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz + } float massD0, massD0bar; - if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { massD0 = candidate.kfGeoMassD0(); massD0bar = candidate.kfGeoMassD0bar(); } else { - massD0 = hfHelper.invMassD0ToPiK(candidate); - massD0bar = hfHelper.invMassD0barToKPi(candidate); + massD0 = HfHelper::invMassD0ToPiK(candidate); + massD0bar = HfHelper::invMassD0barToKPi(candidate); } - if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + auto trackPos = candidate.template prong0_as(); // positive daughter + auto trackNeg = candidate.template prong1_as(); // negative daughter + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::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 ptRec = candidate.pt(); - auto yRec = hfHelper.yD0(candidate); + auto yRec = HfHelper::yD0(candidate); if (candidate.isRecoHfFlag() >= selectionFlagHf) { registry.fill(HIST("hPtVsYRecSigRecoHFFlag"), ptRec, yRec); registry.fill(HIST("hPtGenVsPtRecSig"), ptGen, ptRec); @@ -424,7 +855,7 @@ struct HfTaskD0 { auto ptCandidate = candidate.pt(); auto ptProng0 = candidate.ptProng0(); auto ptProng1 = candidate.ptProng1(); - auto rapidityCandidate = hfHelper.yD0(candidate); + auto rapidityCandidate = HfHelper::yD0(candidate); auto declengthCandidate = candidate.decayLength(); auto declengthxyCandidate = candidate.decayLengthXY(); auto normaliseddeclengthCandidate = candidate.decayLengthNormalised(); @@ -432,13 +863,15 @@ struct HfTaskD0 { auto d0Prong0 = candidate.impactParameter0(); auto d0Prong1 = candidate.impactParameter1(); auto d0d0Candidate = candidate.impactParameterProduct(); - auto ctsCandidate = hfHelper.cosThetaStarD0(candidate); - auto ctCandidate = hfHelper.ctD0(candidate); + auto ctsCandidate = HfHelper::cosThetaStarD0(candidate); + auto ctCandidate = HfHelper::ctD0(candidate); auto cpaCandidate = candidate.cpa(); auto cpaxyCandidate = candidate.cpaXY(); + int const minItsClustersOfProngs = std::min(trackPos.itsNCls(), trackNeg.itsNCls()); + int const 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)) { + if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { registry.fill(HIST("hPtProng0Sig"), ptProng0, rapidityCandidate); registry.fill(HIST("hPtProng1Sig"), ptProng1, rapidityCandidate); registry.fill(HIST("hDecLengthSig"), declengthCandidate, rapidityCandidate); @@ -462,8 +895,30 @@ struct HfTaskD0 { registry.fill(HIST("hDecLengthVsPtSig"), declengthCandidate, ptCandidate); registry.fill(HIST("hDecLengthxyVsPtSig"), declengthxyCandidate, ptCandidate); registry.fill(HIST("hMassSigD0"), massD0, ptCandidate, rapidityCandidate); - if constexpr (applyMl) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], massD0, ptCandidate, candidate.ptBhadMotherPart(), rapidityCandidate, candidate.originMcRec(), SigD0); + if constexpr (ApplyMl) { + if (storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + } else if (storeCentrality && !storeOccupancyAndIR) { + 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 && storeOccupancyAndIR) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + } 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 && storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + } else if (storeCentrality && !storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + } 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); @@ -480,27 +935,93 @@ struct HfTaskD0 { registry.fill(HIST("hCPABkg"), cpaCandidate, rapidityCandidate); registry.fill(HIST("hCPAxyBkg"), cpaxyCandidate, rapidityCandidate); registry.fill(HIST("hMassBkgD0"), massD0, ptCandidate, rapidityCandidate); - if (candidate.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { registry.fill(HIST("hMassReflBkgD0"), massD0, ptCandidate, rapidityCandidate); - if constexpr (applyMl) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], massD0, ptCandidate, candidate.ptBhadMotherPart(), rapidityCandidate, candidate.originMcRec(), ReflectedD0); + if constexpr (ApplyMl) { + if (storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + } else if (storeCentrality && !storeOccupancyAndIR) { + 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 && storeOccupancyAndIR) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + } 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 && storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + } else if (storeCentrality && !storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + } 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); + } } } } } if (candidate.isSelD0bar() >= selectionFlagD0bar) { registry.fill(HIST("hMassSigBkgD0bar"), massD0bar, ptCandidate, rapidityCandidate); - if (candidate.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { registry.fill(HIST("hMassSigD0bar"), massD0bar, ptCandidate, rapidityCandidate); - if constexpr (applyMl) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], massD0bar, ptCandidate, candidate.ptBhadMotherPart(), rapidityCandidate, candidate.originMcRec(), SigD0bar); + if constexpr (ApplyMl) { + if (storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + } else if (storeCentrality && !storeOccupancyAndIR) { + 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 && storeOccupancyAndIR) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + } 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 && storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + } else if (storeCentrality && !storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + } 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)) { + if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { registry.fill(HIST("hMassReflBkgD0bar"), massD0bar, ptCandidate, rapidityCandidate); - if constexpr (applyMl) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], massD0bar, ptCandidate, candidate.ptBhadMotherPart(), rapidityCandidate, candidate.originMcRec(), ReflectedD0bar); + if constexpr (ApplyMl) { + if (storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + } else if (storeCentrality && !storeOccupancyAndIR) { + 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 && storeOccupancyAndIR) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + } 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 && storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + } else if (storeCentrality && !storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + } else if (!storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + } 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); + } } } } @@ -508,7 +1029,7 @@ struct HfTaskD0 { } // MC gen. for (const auto& particle : mcParticles) { - if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + if (std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { if (yCandGenMax >= 0. && std::abs(RecoDecay::y(particle.pVector(), o2::constants::physics::MassD0)) > yCandGenMax) { continue; } @@ -518,20 +1039,53 @@ struct HfTaskD0 { 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 (storeOccupancyAndIR && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::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 constexpr (applyMl) { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1); + if (storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib, cent, occ); + } else if (storeCentrality && !storeOccupancyAndIR) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib, cent); + } else if (!storeCentrality && storeOccupancyAndIR) { + 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 constexpr (applyMl) { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2); + if (storeCentrality && storeOccupancyAndIR) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib, cent, occ); + } else if (storeCentrality && !storeOccupancyAndIR) { + registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib, cent); + } else if (!storeCentrality && storeOccupancyAndIR) { + 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()); @@ -541,35 +1095,97 @@ struct HfTaskD0 { void processMcWithDCAFitterN(D0CandidatesMc const&, soa::Join const& mcParticles, - aod::TracksWMc const& tracks) + TracksSelQuality const& tracks, + CollisionsWithMcLabels const& collisions, + aod::McCollisions const& mcCollisions, + aod::BcFullInfos const& bcs) { - processMc(selectedD0CandidatesMc, mcParticles, tracks); + processMc(selectedD0CandidatesMc, mcParticles, tracks, collisions, mcCollisions, bcs); } 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, + aod::BcFullInfos const& bcs) + { + processMc(selectedD0CandidatesMc, mcParticles, tracks, collisions, mcCollisions, bcs); + } + 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, + aod::BcFullInfos const& bcs) { - processMc(selectedD0CandidatesMcKF, mcParticles, tracks); + processMc(selectedD0CandidatesMcKF, mcParticles, tracks, collisions, mcCollisions, bcs); } 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, + aod::BcFullInfos const& bcs) { - processMc(selectedD0CandidatesMlMc, mcParticles, tracks); + processMc(selectedD0CandidatesMlMc, mcParticles, tracks, collisions, mcCollisions, bcs); } 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, + aod::BcFullInfos const& bcs) + { + processMc(selectedD0CandidatesMlMc, mcParticles, tracks, collisions, mcCollisions, bcs); + } + 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, + aod::BcFullInfos const& bcs) { - processMc(selectedD0CandidatesMlMcKF, mcParticles, tracks); + processMc(selectedD0CandidatesMlMcKF, mcParticles, tracks, collisions, mcCollisions, bcs); } PROCESS_SWITCH(HfTaskD0, processMcWithKFParticleMl, "Process MC with KFParticle and ML selections", false); + // TODO: add the processMcWithKFParticleMlCent + + void processDataWithDCAFitterNWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + D0Candidates const&, + aod::TracksWExtra const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedD0Candidates, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNWithUpc, "Process real data with DCAFitterN w/o ML with UPC", false); + + void processDataWithDCAFitterNMlWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + D0CandidatesMl const&, + aod::TracksWExtra const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedD0CandidatesMl, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNMlWithUpc, "Process real data with DCAFitterN and ML with UPC", false); }; 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..4826a11ded2 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskDirectedFlowCharmHadrons.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 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 "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 "PWGLF/DataModel/SPCalibrationTables.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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."}; + + 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("hpQxtQxpvscentpteta", "hpQxtQxpvscentpteta", HistType::kTHnSparseF, axes, true); + registry.add("hpQytQypvscentpteta", "hpQytQypvscentpteta", HistType::kTHnSparseF, axes, 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 const 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 const ptCand = candidate.pt(); + double etaCand = candidate.eta(); + double const phiCand = candidate.phi(); + double const cosNPhi = std::cos(phiCand); + double const 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("hpQxtQxpvscentpteta"), massCand, cent, ptCand, etaCand, qxtQxp, sign, outputMl[0], outputMl[1]); + registry.fill(HIST("hpQytQypvscentpteta"), massCand, cent, ptCand, etaCand, qytQyp, 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..ef5b677962e 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -16,55 +16,125 @@ /// \author Fabio Catalano , Politecnico and INFN Torino /// \author Vít Kučera , CERN /// \author Luca Aglietta , University and INFN Torino +/// \author Minjung Kim , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsUpcHf.h" +#include "PWGUD/Core/UPCHelpers.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include 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; +using namespace o2::hf_evsel; +using namespace o2::analysis::hf_upc; /// 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 storeIR{"storeIR", false, "Flag to store interaction rate information"}; + Configurable storePvContributors{"storePvContributors", false, "Flag to store number of PV contributors information"}; + Configurable fillMcBkgHistos{"fillMcBkgHistos", false, "Flag to fill and store histograms for MC background"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + HfEventSelection hfEvSel; // event selection and monitoring + HfUpcGapThresholds upcThresholds; // UPC gap determination thresholds + ctpRateFetcher mRateFetcher; // interaction rate fetcher - HfHelper hfHelper; + Service ccdb; using CandDplusData = soa::Filtered>; 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 candDplusPerCollision = aod::hf_cand::collisionId; + 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; // Matched MC - Partition recoDPlusCandidates = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - Partition recoDPlusCandidatesWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi)) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + Partition recoDPlusCandidates = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + Partition recoDPlusCandidatesWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; // MC Bkg - 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; + Partition recoBkgCandidates = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; + Partition recoBkgCandidatesWithMl = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagDplus; - // Generated particles + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {600, 1.67, 2.27}, "Cand. mass bins"}; + ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {40, -1, 1}, "Cand. rapidity bins"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {110, 0., 110.}, "axis for centrality"}; + ConfigurableAxis thnConfigAxisOccupancy{"thnConfigAxisOccupancy", {14, 0, 14000}, "axis for occupancy"}; + ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; + ConfigurableAxis thnConfigAxisPvContributors{"thnConfigAxisPvContributors", {100, 0., 100.}, "axis for PV contributors"}; + 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"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (see TrueGap enum in o2::aod::sgselector)"}; + ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisZN{"thnConfigAxisZN", {510, -1.5, 49.5}, "axis for ZN energy (a.u.)"}; HistogramRegistry registry{ "registry", @@ -80,13 +150,32 @@ struct HfTaskDplus { void init(InitContext&) { - std::array doprocess{doprocessData, doprocessDataWithMl, doprocessMc, doprocessMcWithMl}; + std::array doprocess{doprocessData, doprocessDataWithMl, doprocessMc, doprocessMcWithMl, doprocessDataWithUpc, doprocessDataWithMlWithUpc}; 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 const thnAxisPt = {vbins, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const thnAxisMass = {thnConfigAxisMass, "inv. mass (K#pi#pi) (GeV/#it{c}^{2})"}; + AxisSpec const thnAxisY = {thnConfigAxisY, "y"}; + AxisSpec const thnAxisMlScore0 = {thnConfigAxisMlScore0, "Score 0"}; + AxisSpec const thnAxisMlScore1 = {thnConfigAxisMlScore1, "Score 1"}; + AxisSpec const thnAxisMlScore2 = {thnConfigAxisMlScore2, "Score 2"}; + AxisSpec const thnAxisPtBHad{thnConfigAxisPtBHad, "#it{p}_{T,B} (GeV/#it{c})"}; + AxisSpec const thnAxisFlagBHad{thnConfigAxisFlagBHad, "B Hadron flag"}; + AxisSpec const thnAxisCent{thnConfigAxisCent, "Centrality"}; + AxisSpec const thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; + AxisSpec const thnAxisIR{thnConfigAxisIR, "Interaction rate (kHz)"}; + AxisSpec const thnAxisPvContributors{thnConfigAxisPvContributors, "PV contributors"}; + AxisSpec const thnAxisGapType{thnConfigAxisGapType, "Gap type"}; + AxisSpec const thnAxisFT0A{thnConfigAxisFT0, "FT0-A amplitude"}; + AxisSpec const thnAxisFT0C{thnConfigAxisFT0, "FT0-C amplitude"}; + AxisSpec const thnAxisFV0A{thnConfigAxisFV0A, "FV0-A amplitude"}; + AxisSpec const thnAxisFDDA{thnConfigAxisFDD, "FDD-A amplitude"}; + AxisSpec const thnAxisFDDC{thnConfigAxisFDD, "FDD-C amplitude"}; + AxisSpec const thnAxisZNA{thnConfigAxisZN, "ZNA energy"}; + AxisSpec const thnAxisZNC{thnConfigAxisZN, "ZNC energy"}; + 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,14 +213,90 @@ 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 || doprocessDataWithMlWithUpc || doprocessDataWithUpc) { + std::vector axes = {thnAxisMass, thnAxisPt}; + + if (doprocessDataWithMl || doprocessDataWithMlWithUpc) { + axes.push_back(thnAxisMlScore0); + axes.push_back(thnAxisMlScore1); + axes.push_back(thnAxisMlScore2); + } + if (storeCentrality) { + axes.push_back(thnAxisCent); + } + if (storeOccupancy) { + axes.push_back(thnAxisOccupancy); + } + if (storeIR) { + axes.push_back(thnAxisIR); + } + if (doprocessDataWithMlWithUpc || doprocessDataWithUpc) { + axes.push_back(thnAxisGapType); + axes.push_back(thnAxisFT0A); + axes.push_back(thnAxisFT0C); + axes.push_back(thnAxisFV0A); + axes.push_back(thnAxisFDDA); + axes.push_back(thnAxisFDDC); + axes.push_back(thnAxisZNA); + axes.push_back(thnAxisZNC); + } + + 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.push_back(thnAxisCent); + axesFD.push_back(thnAxisCent); + axesGenPrompt.push_back(thnAxisCent); + axesGenFD.push_back(thnAxisCent); + } + if (storeOccupancy) { + axes.push_back(thnAxisOccupancy); + axesFD.push_back(thnAxisOccupancy); + axesGenPrompt.push_back(thnAxisOccupancy); + axesGenFD.push_back(thnAxisOccupancy); + } + if (storePvContributors) { + axes.push_back(thnAxisPvContributors); + axesFD.push_back(thnAxisPvContributors); + axesGenPrompt.push_back(thnAxisPvContributors); + axesGenFD.push_back(thnAxisPvContributors); + } + + axesFD.push_back(thnAxisPtBHad); + axesFD.push_back(thnAxisFlagBHad); + axesGenFD.push_back(thnAxisPtBHad); + axesGenFD.push_back(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); } + + registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); + registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap type;Counts", {HistType::kTH1F, {{7, -1.5, 5.5}}}); + + hfEvSel.addHistograms(registry); // collision monitoring + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); } // Fill histograms of quantities for the reconstructed Dplus candidates @@ -139,11 +304,11 @@ struct HfTaskDplus { template void fillHisto(const T1& candidate) { - float pt = candidate.pt(); - registry.fill(HIST("hMass"), hfHelper.invMassDplusToPiKPi(candidate), pt); + float const pt = candidate.pt(); + registry.fill(HIST("hMass"), HfHelper::invMassDplusToPiKPi(candidate), pt); registry.fill(HIST("hPt"), pt); registry.fill(HIST("hEta"), candidate.eta(), pt); - registry.fill(HIST("hCt"), hfHelper.ctDplus(candidate), pt); + registry.fill(HIST("hCt"), HfHelper::ctDplus(candidate), pt); registry.fill(HIST("hDecayLength"), candidate.decayLength(), pt); registry.fill(HIST("hDecayLengthXY"), candidate.decayLengthXY(), pt); registry.fill(HIST("hNormalisedDecayLengthXY"), candidate.decayLengthXYNormalised(), pt); @@ -167,36 +332,104 @@ struct HfTaskDplus { // Fill THnSparses for the ML analysis /// \param candidate is a particle candidate - template - void fillSparseML(const T1& 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 + /// \param numPvContributors contributors to the PV + template + void fillSparseML(const T1& candidate, + float ptbhad, + int flagBHad, + float centrality, + float occupancy, + float numPvContributors) { 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 if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMassPrompt"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors); + } 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 if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMassFD"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors, 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 if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMassBkg"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors); + } 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 if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMassNotMatched"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors); + } 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 if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors); + } 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]); } } // Fill histograms of quantities for the reconstructed Dplus candidates with MC matching /// \param candidate is candidate - template + template void fillHistoMCRec(const T1& candidate) { - if constexpr (isMatched) { + if constexpr (IsMatched) { auto ptRec = candidate.pt(); - auto yRec = hfHelper.yDplus(candidate); + auto yRec = HfHelper::yDplus(candidate); registry.fill(HIST("hPtVsYRecSig_RecoSkim"), ptRec, yRec); if (TESTBIT(candidate.isSelDplusToPiKPi(), aod::SelectionStep::RecoTopol)) { registry.fill(HIST("hPtVsYRecSigRecoTopol"), ptRec, yRec); @@ -258,104 +491,389 @@ 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 + /// \param numPvContributors contributors to the PV + template + void fillSparseMcGen(const T1& particle, + float ptGenB, + int flagGenB, + float centrality, + float occupancy, + float numPvContributors) + { + 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 if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMassGenPrompt"), particle.pt(), yGen, numPvContributors); + } 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 if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMassGenFD"), particle.pt(), yGen, numPvContributors, 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*/) + template + void runDataAnalysis(const T1& /*candidates*/, CollisionsCent const& /*colls*/) { - if constexpr (!fillMl) { + float cent{-1.f}; + float occ{-1.f}; + float numPvContr{-1.f}; + float ptBhad{-1.f}; + int const flagBHad{-1}; + if constexpr (!FillMl) { for (const auto& candidate : selectedDPlusCandidates) { - if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { + if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { continue; } fillHisto(candidate); } } else { for (const auto& candidate : selectedDPlusCandidatesWithMl) { - if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { + 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 = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } + if (storePvContributors) { + numPvContr = collision.numContrib(); + } + } + fillHisto(candidate); - fillSparseML(candidate); + fillSparseML(candidate, ptBhad, flagBHad, cent, occ, numPvContr); } } } + // 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 numPvContr{-1}; + float ptBhad{-1}; + int flagBHad{-1}; + // MC rec. w/o Ml - if constexpr (!fillMl) { + if constexpr (!FillMl) { for (const auto& candidate : recoDPlusCandidates) { - if ((yCandRecoMax >= 0. && std::abs(hfHelper.yDplus(candidate)) > yCandRecoMax)) { + if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { continue; } fillHisto(candidate); 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)) { + if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { continue; } + ptBhad = candidate.ptBhadMotherPart(); + flagBHad = getBHadMotherFlag(candidate.pdgBhadMotherPart()); + auto collision = candidate.template collision_as(); + if (storeCentrality || storeOccupancy) { + if (storeCentrality && centEstimator != CentralityEstimator::None) { + cent = getCentralityColl(collision, centEstimator); + } + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } + } + if (storePvContributors) { + numPvContr = collision.numContrib(); + } fillHisto(candidate); fillHistoMCRec(candidate); - fillSparseML(candidate); + fillSparseML(candidate, ptBhad, flagBHad, cent, occ, numPvContr); } // 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 = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } + if (storePvContributors) { + numPvContr = collision.numContrib(); + } + fillHistoMCRec(candidate); + fillSparseML(candidate, ptBhad, flagBHad, cent, occ, numPvContr); } - 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)) { + float cent{-1.}; + float occ{-1.}; + float numPvContr{-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 = o2::hf_occupancy::getOccupancyGenColl(recoCollsPerGenMcColl, occEstimator); + } + + for (const auto& particle : mcParticlesPerGenMcColl) { + ptGenB = -1; + flagGenB = -1; + numPvContr = -1; + auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassDPlus); + if ((yCandGenMax >= 0. && std::abs(yGen) > yCandGenMax) || (std::abs(particle.flagMcMatchGen()) != hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) { + continue; + } + if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcGenParticles.rawIteratorAt(particle.idxBhadMotherPart() - mcGenParticles.offset()); + flagGenB = getBHadMotherFlag(bHadMother.pdgCode()); + ptGenB = bHadMother.pt(); + } + for (const auto& recCol : recoCollsPerGenMcColl) { + numPvContr = std::max(numPvContr, recCol.numContrib()); + } + fillHistoMCGen(particle); + if constexpr (FillMl) { + fillSparseMcGen(particle, ptGenB, flagGenB, cent, occ, numPvContr); + } + } + } + } + + template + void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, + CandType const& candidates, + BCsType const& bcs, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds) + { + for (const auto& collision : collisions) { + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject the candidate continue; } - fillHistoMCGen(particle); + const auto& bc = collision.template bc_as(); + + // Determine gap type using SGSelector with BC range checking + const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); + const int gap = gapResult.value; + + // Use the BC with FIT activity if available from SGSelector + auto bcForUPC = bc; + if (gapResult.bc) { + bcForUPC = *(gapResult.bc); + } + + // Get FIT information from the UPC BC + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bcForUPC, bcs, ft0s, fv0as, fdds); + + // Get ZDC energies if available (extract once and reuse) + const bool hasZdc = bcForUPC.has_zdc(); + float zdcEnergyZNA = -1.f; + float zdcEnergyZNC = -1.f; + if (hasZdc) { + const auto& zdc = bcForUPC.zdc(); + zdcEnergyZNA = zdc.energyCommonZNA(); + zdcEnergyZNC = zdc.energyCommonZNC(); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); + } + registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + registry.fill(HIST("Data/hUpcGapAfterSelection"), gap); + + const auto thisCollId = collision.globalIndex(); + const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); + + float cent{-1.f}; + float occ{-1.f}; + float ir{-1.f}; + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } + if (storeIR) { + ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz + } + static constexpr auto HSparseMass = HIST("hSparseMass"); + // Lambda function to fill THn - handles both ML and non-ML cases + auto fillTHnData = [&](const auto& candidate) { + // Pre-calculate vector size to avoid reallocations + constexpr int NAxesBase = 10; // mass, pt, gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC + constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality + int const nAxesOcc = storeOccupancy ? 1 : 0; // occupancy if storeOccupancy + int const nAxesIR = storeIR ? 1 : 0; // IR if storeIR + int const nAxesTotal = NAxesBase + NAxesMl + nAxesCent + nAxesOcc + nAxesIR; + + std::vector valuesToFill; + valuesToFill.reserve(nAxesTotal); + + // Fill values in order matching histogram axes + valuesToFill.push_back(HfHelper::invMassDplusToPiKPi(candidate)); + valuesToFill.push_back(static_cast(candidate.pt())); + if constexpr (FillMl) { + std::vector outputMl = {-999., -999., -999.}; + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; + } + valuesToFill.push_back(outputMl[0]); + valuesToFill.push_back(outputMl[1]); + valuesToFill.push_back(outputMl[2]); + } + if (storeCentrality) { + valuesToFill.push_back(cent); + } + if (storeOccupancy) { + valuesToFill.push_back(occ); + } + if (storeIR) { + valuesToFill.push_back(ir); + } + valuesToFill.push_back(static_cast(gap)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + valuesToFill.push_back(static_cast(fitInfo.ampFV0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDA)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); + valuesToFill.push_back(static_cast(zdcEnergyZNA)); + valuesToFill.push_back(static_cast(zdcEnergyZNC)); + registry.get(HSparseMass)->Fill(valuesToFill.data()); + }; + + for (const auto& candidate : groupedDplusCandidates) { + if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { + continue; + } + fillHisto(candidate); + fillTHnData(candidate); + } } } // 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); + + void processDataWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + CandDplusData const& selectedDplusCandidates, + aod::Tracks const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedDplusCandidates, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskDplus, processDataWithUpc, "Process real data w/o ML with UPC", false); + + void processDataWithMlWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + CandDplusDataWithMl const& selectedDplusCandidatesMl, + aod::Tracks const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedDplusCandidatesMl, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskDplus, processDataWithMlWithUpc, "Process real data with the ML method with UPC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/D2H/Tasks/taskDs.cxx b/PWGHF/D2H/Tasks/taskDs.cxx index 2c45ba0d846..1c991fd802f 100644 --- a/PWGHF/D2H/Tasks/taskDs.cxx +++ b/PWGHF/D2H/Tasks/taskDs.cxx @@ -17,21 +17,59 @@ /// \author Stefano Politanò , Politecnico & INFN Torino /// \author Fabrizio Chinu , Universita and INFN Torino -#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/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include "Common/Core/MetadataHelper.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +o2::common::core::MetadataHelper metadataInfo; // Metadata helper + enum FinalState { KKPi = 0, PiKK }; @@ -41,86 +79,114 @@ enum DataType { Data = 0, McDplusPrompt, McDplusNonPrompt, McDplusBkg, + McLcBkg, McBkg, kDataTypes }; -enum SpeciesAndDecay { DsToKKPi = 0, - DplusToKKPi, - DplusToPiKPi, - kSpeciesAndDecay }; +enum Mother : int8_t { + Ds, + Dplus +}; + +enum ResonantChannel : int8_t { + PhiPi = 1, + Kstar0K = 2 +}; + +static std::unordered_map> channelsResonant = {{{Mother::Ds, {{ResonantChannel::PhiPi, hf_decay::hf_cand_3prong::DecayChannelResonant::DsToPhiPi}, {ResonantChannel::Kstar0K, hf_decay::hf_cand_3prong::DecayChannelResonant::DsToKstar0K}}}, + {Mother::Dplus, {{ResonantChannel::PhiPi, hf_decay::hf_cand_3prong::DecayChannelResonant::DplusToPhiPi}, {ResonantChannel::Kstar0K, hf_decay::hf_cand_3prong::DecayChannelResonant::DplusToKstar0K}}}}}; + +template +concept HasDsMlInfo = requires(T candidate) { + candidate.mlProbDsToKKPi(); + candidate.mlProbDsToPiKK(); +}; /// Ds± analysis task struct HfTaskDs { - Configurable decayChannel{"decayChannel", 1, "Switch between decay channels: 1 for Ds/Dplus->PhiPi->KKpi, 2 for Ds/Dplus->K0*K->KKPi"}; + Configurable decayChannel{"decayChannel", 1, "Switch between resonant decay channels: 1 for Ds/Dplus->PhiPi->KKpi, 2 for Ds/Dplus->K0*K->KKPi"}; 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; + + SliceCache cache; + Service ccdb; + + 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; - HfHelper hfHelper; - - using CentralityEstimator = o2::hf_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 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, 100}, "axis for centrality/multiplicity"}; + ConfigurableAxis axisOccupancy{"axisOccupancy", {14, 0., 14000.}, "axis for occupancy"}; + + 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,23 +199,69 @@ struct HfTaskDs { LOGP(fatal, "No process function enabled"); } - AxisSpec ptbins{axisPt, "#it{p}_{T} (GeV/#it{c})"}; + if (decayChannel != ResonantChannel::PhiPi && decayChannel != ResonantChannel::Kstar0K) { + LOGP(fatal, "Invalid value of decayChannel"); + } + + AxisSpec const ptbins{axisPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const ptBHad{axisPtBHad, "#it{p}_{T}(B) (GeV/#it{c})"}; + AxisSpec const 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 const massbins = {600, 1.67, 2.27, "inv. mass (KK#pi) (GeV/#it{c}^{2})"}; + AxisSpec const centralitybins = {axisCentrality, "Centrality"}; + AxisSpec const npvcontributorsbins = {axisNPvContributors, "NPvContributors"}; + AxisSpec const mlscore0bins = {axisMlScore0, "Score 0"}; + AxisSpec const mlscore1bins = {axisMlScore1, "Score 1"}; + AxisSpec const mlscore2bins = {axisMlScore2, "Score 2"}; + AxisSpec const 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.}}}); @@ -181,35 +293,141 @@ 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(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && candidate.flagMcDecayChanRec() == channelsResonant[Mother::Ds][decayChannel] && candidate.originMcRec() == RecoDecay::OriginType::Prompt; + } + + template + bool isDplusPrompt(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && candidate.flagMcDecayChanRec() == channelsResonant[Mother::Dplus][decayChannel] && candidate.originMcRec() == RecoDecay::OriginType::Prompt; + } + + template + bool isDsNonPrompt(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && candidate.flagMcDecayChanRec() == channelsResonant[Mother::Ds][decayChannel] && candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + } + + template + bool isDplusNonPrompt(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && candidate.flagMcDecayChanRec() == channelsResonant[Mother::Dplus][decayChannel] && candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + } + + template + bool isDplusBkg(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + } + + template + bool isLcBkg(const CandDs& candidate) + { + return std::abs(candidate.flagMcMatchRec()) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::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 const isKKPi = candidate.isSelDsToKKPi() >= selectionFlagDs; + float const 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 const multZeqFT0A = hVtxZFT0A->Interpolate(0.0) * multFT0A / hVtxZFT0A->Interpolate(collision.posZ()); + float const 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 const 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); + } + 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); + } + 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 @@ -219,346 +437,315 @@ 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); - - return; + 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); } - /// 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]); - } else { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToKKPi(candidate), pt, 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 { - if constexpr (centDetector != CentralityEstimator::None) { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToKKPi(candidate), pt, evaluateCentrality(candidate)); - } else { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToKKPi(candidate), pt); + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), outputMl[0], outputMl[1], outputMl[2]); + return; + } + 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; + } + 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; + } + 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; } + 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 (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; } - if constexpr (centDetector != CentralityEstimator::None) { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToPiKK(candidate), pt, evaluateCentrality(candidate), outputMl[0], outputMl[1], outputMl[2]); - } 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; + } + 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; + } + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), candidate.template collision_as().numContrib(), candidate.ptBhadMotherPart(), getBHadMotherFlag(candidate.pdgBhadMotherPart())); + return; } - } else { - if constexpr (centDetector != CentralityEstimator::None) { - std::get(histosPtr[dataType]["hSparseMass"])->Fill(hfHelper.invMassDsToPiKK(candidate), pt, evaluateCentrality(candidate)); - } 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; } + std::get(histosPtr[dataType]["hSparseMass"])->Fill(mass, pt, evaluateCentralityCand(candidate), candidate.template collision_as().numContrib()); + return; } + } + + /// 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.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); + 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); + } + + /// 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); - 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 MC histograms at reconstruction level /// \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; + if (dataType == DataType::McDplusPrompt || dataType == DataType::McDplusNonPrompt || dataType == DataType::McDplusBkg) { + id = o2::constants::physics::Pdg::kDPlus; + } else if (dataType == DataType::McLcBkg) { + id = o2::constants::physics::Pdg::kLambdaCPlus; + } + 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) { - 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) { - - double 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 + auto yCand = candidate.y(HfHelper::invMassDsToKKPi(candidate)); + if (yCandRecoMax >= 0. && std::abs(yCand) > yCandRecoMax) { + return; } + 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) { - double 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 + auto yCand = candidate.y(HfHelper::invMassDsToPiKK(candidate)); + if (yCandRecoMax >= 0. && std::abs(yCand) > yCandRecoMax) { + return; } + fillHisto(candidate, dataType); + fillHistoPiKK(candidate, dataType); - return; - } // end D+→ K± K∓ π± - - // D+→ π± K∓ π± - if (whichSpeciesDecay == SpeciesAndDecay::DplusToPiKPi) { - double 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); + } + } } } - 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 (candidate.isSelDsToKKPi() >= selectionFlagDs) { // KKPi + if (yCandRecoMax >= 0. && std::abs(candidate.y(HfHelper::invMassDsToKKPi(candidate))) > yCandRecoMax) { + return; } 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 + if (yCandRecoMax >= 0. && std::abs(candidate.y(HfHelper::invMassDsToPiKK(candidate))) > yCandRecoMax) { + return; } + 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 (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) + if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) { + if (candidate.isSelDsToKKPi() >= selectionFlagDs) { // KKPi + if (yCandRecoMax >= 0. && std::abs(candidate.y(HfHelper::invMassDsToKKPi(candidate))) > yCandRecoMax) { + return; + } 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 + if (yCandRecoMax >= 0. && std::abs(candidate.y(HfHelper::invMassDsToPiKK(candidate))) > yCandRecoMax) { + return; + } 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) { - if (particle.flagMcDecayChanGen() == decayChannel || (fillDplusMc && particle.flagMcDecayChanGen() == (decayChannel + offsetDplusDecayChannel))) { + + if (std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK || std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) { + const auto& recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, particle.mcCollision().globalIndex()); + if (particle.flagMcDecayChanGen() == channelsResonant[Mother::Ds][decayChannel] || (fillDplusMc && particle.flagMcDecayChanGen() == channelsResonant[Mother::Dplus][decayChannel])) { auto pt = particle.pt(); double y{0.f}; - if (particle.flagMcDecayChanGen() == decayChannel) { + unsigned maxNumContrib = 0; + for (const auto& recCol : recoCollsPerMcColl) { + maxNumContrib = recCol.numContrib() > maxNumContrib ? recCol.numContrib() : maxNumContrib; + } + float const 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() == channelsResonant[Mother::Ds][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 const flagGenB = getBHadMotherFlag(bHadMother.pdgCode()); + float const 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); @@ -566,14 +753,25 @@ 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 const flagGenB = getBHadMotherFlag(bHadMother.pdgCode()); + float const 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); + } } } } @@ -581,160 +779,353 @@ struct HfTaskDs { } } - void processDataWithCentFT0C(CollisionsWithFT0C const&, - CandDsData const&) + template + void fillNPvContribHisto(const Coll& collision, + std::array& nCandsPerType, + std::array& nCandsInSignalRegionDsPerType, + std::array& nCandsInSignalRegionDplusPerType) + { + int const numPvContributors = collision.numContrib(); + float const 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.empty()) { + 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 = dynamic_cast(lCalibObjects->FindObject("hVtxZFT0A")); + hVtxZFT0C = dynamic_cast(lCalibObjects->FindObject("hVtxZFT0C")); + hVtxZNTracks = dynamic_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.empty()) { + 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 = dynamic_cast(lCalibObjects->FindObject("hVtxZFT0A")); + hVtxZFT0C = dynamic_cast(lCalibObjects->FindObject("hVtxZFT0C")); + hVtxZNTracks = dynamic_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& 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 35a6ce4c74b..6c5a2fee257 100644 --- a/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx +++ b/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx @@ -15,15 +15,40 @@ /// \author Deependra Sharma , IITB /// \author Fabrizio Grosa , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/runDataProcessing.h" +/// \brief Dstar production analysis task (With and Without ML) +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::framework; @@ -33,313 +58,696 @@ using namespace o2::soa; /// Dstar analysis task struct HfTaskDstarToD0Pi { Configurable selectionFlagDstarToD0Pi{"selectionFlagDstarToD0Pi", true, "Selection Flag for D* decay to D0 & Pi"}; + Configurable isCentStudy{"isCentStudy", true, "Flag to select centrality study"}; + Configurable qaEnabled{"qaEnabled", true, "Flag to enable QA histograms"}; + Configurable studyD0ToPiKPi0{"studyD0ToPiKPi0", false, "Flag to study D*->D0(piKpi0)pi channel"}; + + // CCDB configuration + Configurable useWeight{"useWeight", true, "Flag to use weights from CCDB"}; + Configurable nWeights{"nWeights", 6, "Number of weights to be used from CCDB"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathForWeight{"ccdbPathForWeight", "Users/d/desharma/weights", "CCDB path for PVContrib weights"}; + Configurable timestampCCDB{"timestampCCDB", -1, "CCDB timestamp for the weights"}; + Configurable weightFileName{"weightFileName", "Weights.root", "Name of the weight file to be used for PVContrib"}; + Configurable> centRangesForWeights{"centRangesForWeights", {0.0, 5.0, 10.0, 30.0, 50.0, 70.0, 100.0}, "Centrality ranges for weights. Size of ranges should be equal to nWeights + 1"}; + Configurable yCandDstarRecoMax{"yCandDstarRecoMax", 0.8, "max. candidate Dstar rapidity"}; Configurable yCandDstarGenMax{"yCandDstarGenMax", 0.5, "max. rapidity of Generator level Particle"}; 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"}; + Configurable deltaMassMin{"deltaMassMin", 0.142, "Lower bound of the signal region for Delta Invariant MassDstar"}; + Configurable deltaMassMax{"deltaMassMax", 0.15, "Upper bound of the signal region for Delta Invariant MassDstar"}; + + o2::ccdb::CcdbApi ccdbApi; + SliceCache cache; + std::vector hWeights; + std::vector axesPtVsCentVsBDTVsPvContrib; + std::vector axesPtVsCentVsPvContrib; + std::vector axesPtVsBDT; 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; 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; - SliceCache cache; - Partition rowsSelectedCandDstar = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstarToD0Pi; 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, 10.0, 20.0, 30.0, 60.0, 100.0}, "centrality binning"}; - - HistogramRegistry registry{ - "registry", - {{"QA/hPtDstar", "Dstar Candidates; Dstar candidate #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"QA/hPtD0", "D0 Candiades; D0 Candidate #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"QA/hPtProng0D0", "Prong0 of D0 Candidates; Prong0 #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"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/hDeltaCentGen", "#{Delta}Cent % distribution of Collisions having same MC Collision;FT0M #{Delta}Cent %; Counts", {HistType::kTH1F, {{100, 0.0, 100.0}}}}}}; + ConfigurableAxis binningCentrality{"binningCentrality", {VARIABLE_WIDTH, 0.0, 1.0, 10.0, 30.0, 50.0, 70.0, 100.0}, "centrality binning"}; + ConfigurableAxis binningD0Mass{"binningD0Mass", {500, 1.0, 3.0}, "Bins of InvMass of D0"}; + 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"}; + ConfigurableAxis binningPvContrib{"binningPvContrib", {100, 0.0f, 300.0f}, "Bins for PVContrib"}; + + HistogramRegistry registry{"registry", {}}; 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 const axisImpactParam = {binningImpactParam, "impact parameter (cm)"}; + AxisSpec const axisDecayLength = {binningDecayLength, " decay length (cm)"}; + AxisSpec const axisNormDecayLength = {binningNormDecayLength, "normalised decay length (cm)"}; AxisSpec axisCentrality = {binningCentrality, "centrality (%)"}; + AxisSpec axisDeltaInvMass = {binningDeltaInvMass, "#Delta #it{M}_{inv} D*"}; + AxisSpec axisD0Mass = {binningD0Mass, "InvMass of D0 (GeV/#it{c}^{2})"}; + 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"}; + AxisSpec axisPvContrib = {binningPvContrib, "PV Contribution"}; + AxisSpec const axisPt = {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}; + + axesPtVsCentVsBDTVsPvContrib = {axisPt, axisCentrality, axisBDTScoreBackground, axisBDTScorePrompt, axisBDTScoreNonPrompt, axisPvContrib}; + axesPtVsCentVsPvContrib = {axisPt, axisCentrality, axisPvContrib}; + axesPtVsBDT = {axisPt, axisBDTScoreBackground, axisBDTScorePrompt, axisBDTScoreNonPrompt}; + + if (qaEnabled) { + // only QA + registry.add("QA/hPtDstar", "Dstar Candidates; Dstar candidate #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}); + registry.add("QA/hPtD0", "D0 Candiades; D0 Candidate #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}); + registry.add("QA/hPtProng0D0", "Prong0 of D0 Candidates; Prong0 #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}); + registry.add("QA/hPtProng1D0", "Prong1 of D0 Candidates; Prong1 #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}); + registry.add("QA/hPtProng0D0Bar", "Prong0 of D0Bar Candidates; Prong0 #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}); + registry.add("QA/hPtProng1D0Bar", "Prong1 of D0Bar Candidates; Prong1 #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{360, 0., 36.}}}); + registry.add("QA/hPtSoftPi", "Soft Pi ; Soft Pi #it{p}_{T} (GeV/#it{c}); entries", {HistType::kTH1F, {{100, 0., 1.}}}); + registry.add("QA/hDeltaCentGen", "#{Delta}Cent % distribution of Collisions having same MC Collision;FT0M #{Delta}Cent %; Counts", {HistType::kTH1F, {{100, 0.0, 100.0}}}); + + registry.add("QA/hEtaDstar", "D* Candidate; D* Candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hCtD0", "D0 Candidate; D0 Candidate's proper life time #it{c}#tau (cm) ; entries ", {HistType::kTH2F, {{1000, -0.1, 14.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hDecayLengthD0", "D0 Candidate; D0 Candidate's decay length (cm); entries", {HistType::kTH2F, {axisDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hDecayLengthXYD0", "D0 Candidate; D0 Candidate's decay length xy (cm); entries", {HistType::kTH2F, {axisDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hDecayLengthNormalisedD0", "D0 Candidates;Do Candidate's normalised decay length (cm); entries", {HistType::kTH2F, {axisNormDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hDecayLengthXYNormalisedD0", "D0 candidate; D0 Candidate's normalised decay length xy (cm); entries", {HistType::kTH2F, {axisNormDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hCPAD0", "D0 Candidates; D0 Candidate's cosine pointing angle; entries", {HistType::kTH2F, {{110, -1., 1.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hCPAxyD0", "D0 candidates; D0 Candidate's cosine of pointing angle xy; entries", {HistType::kTH2F, {{110, -1., 1.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hImpactParameterXYD0", "D0 Candidates; D0 Candidate's reconstructed impact parameter xy (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hDeltaIPMaxNormalisedD0", "D0 Candidate; D0 Candidate's Norm. Delta IP; entries", {HistType::kTH2F, {{1000, -20., 20.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hSqSumProngsImpactParameterD0", "D0 Candidates; Sqr Sum of Impact params of D0 Prongs; entries ", {HistType::kTH2F, {{1000, 0., 0.25}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hDecayLengthErrorD0", "D0 Candidates; D0 Candidate's Decay Length Error (cm); entries", {HistType::kTH2F, {axisDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hDecayLengthXYErrorD0", "D0 Candidates; D0 Candidate's Decay Length Error XY (cm); entries", {HistType::kTH2F, {axisDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hImpactParameterError", "D0 Prongs; Impact param error of different D0 Prongs (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hd0Prong0", "Prong0; DCAxy of Prong0 (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hd0Prong1", "Prong1; DCAxy of Prong1 (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hd0ProngSoftPi", "ProngSoftPi; DCAxy of Prong Soft Pi (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + + // MC Matching at Reconstruction Level Successful + registry.add("QA/hCPASkimD0RecSig", "MC Matched Skimed D* Candidates at Reconstruction Level; cosine of pointing angle", {HistType::kTH1F, {{110, -1.1, 1.1}}}); + 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})"}}}, true); + registry.add("QA/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})"}}}); + + // 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.}}}); + registry.add("QA/hPtVsYRecoPidPromptDstarRecSig", "MC Matched RecoPid 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/hPtFullRecoPromptDstarRecSig", "MC Matched FullReco 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})"}}}); + // Only Non-Prompt RecSig + 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/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.}}}); + registry.add("QA/hEtaSkimDstarRecBg", "MC UnMatched Skimmed D* Candidates at Reconstruction Level; #it{#eta} of D* Candidate", {HistType::kTH1F, {{100, -2., 2.}}}); + // registry.add("QA/hPtSkimD0RecBg", "MC UnMatched Skimmed D0 Candidates at Reconstruction Level; #it{p}_{T} of D0", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("QA/hPtSkimDstarRecBg", "MC UnMatched Skimmed D* Candidates at Reconstruction Level; #it{p}_{T} of D*", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); + + // 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("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, {{100, 0.13, 0.16}, {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, {{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/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 - registry.add("QA/hEtaDstar", "D* Candidate; D* Candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hCtD0", "D0 Candidate; D0 Candidate's proper life time #it{c}#tau (cm) ; entries ", {HistType::kTH2F, {{1000, -0.1, 14.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hDecayLengthD0", "D0 Candidate; D0 Candidate's decay length (cm); entries", {HistType::kTH2F, {axisDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hDecayLengthXYD0", "D0 Candidate; D0 Candidate's decay length xy (cm); entries", {HistType::kTH2F, {axisDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hDecayLengthNormalisedD0", "D0 Candidates;Do Candidate's normalised decay length (cm); entries", {HistType::kTH2F, {axisNormDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hDecayLengthXYNormalisedD0", "D0 candidate; D0 Candidate's normalised decay length xy (cm); entries", {HistType::kTH2F, {axisNormDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hCPAD0", "D0 Candidates; D0 Candidate's cosine pointing angle; entries", {HistType::kTH2F, {{110, -1., 1.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hCPAxyD0", "D0 candidates; D0 Candidate's cosine of pointing angle xy; entries", {HistType::kTH2F, {{110, -1., 1.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hImpactParameterXYD0", "D0 Candidates; D0 Candidate's reconstructed impact parameter xy (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hDeltaIPMaxNormalisedD0", "D0 Candidate; D0 Candidate's Norm. Delta IP; entries", {HistType::kTH2F, {{1000, -20., 20.}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hSqSumProngsImpactParameterD0", "D0 Candidates; Sqr Sum of Impact params of D0 Prongs; entries ", {HistType::kTH2F, {{1000, 0., 0.25}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hDecayLengthErrorD0", "D0 Candidates; D0 Candidate's Decay Length Error (cm); entries", {HistType::kTH2F, {axisDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hDecayLengthXYErrorD0", "D0 Candidates; D0 Candidate's Decay Length Error XY (cm); entries", {HistType::kTH2F, {axisDecayLength, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hImpactParameterError", "D0 Prongs; Impact param error of different D0 Prongs (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hd0Prong0", "Prong0; DCAxy of Prong0 (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hd0Prong1", "Prong1; DCAxy of Prong1 (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hd0ProngSoftPi", "ProngSoftPi; DCAxy of Prong Soft Pi (cm); entries", {HistType::kTH2F, {axisImpactParam, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - // MC Matching at Reconstruction Level Successful - registry.add("QA/hCPASkimD0RecSig", "MC Matched Skimed D* Candidates at Reconstruction Level; cosine of pointing angle", {HistType::kTH1F, {{110, -1.1, 1.1}}}); - 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.}}}); + + // 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}, {axisD0Mass}}}, true); + } else if (doprocessDataWoML) { + 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/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); + } + // 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})"}}}, 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})"}}}); - // 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.}}}); - registry.add("QA/hPtVsYRecoPidPromptDstarRecSig", "MC Matched RecoPid 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/hPtFullRecoPromptDstarRecSig", "MC Matched FullReco 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})"}}}); - // Only Non-Prompt RecSig - 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/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.}}}); - registry.add("QA/hEtaSkimDstarRecBg", "MC UnMatched Skimmed D* Candidates at Reconstruction Level; #it{#eta} of D* Candidate", {HistType::kTH1F, {{100, -2., 2.}}}); - registry.add("QA/hPtSkimD0RecBg", "MC UnMatched Skimmed D0 Candidates at Reconstruction Level; #it{p}_{T} of D0", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("QA/hPtSkimDstarRecBg", "MC UnMatched Skimmed D* Candidates at Reconstruction Level; #it{p}_{T} of D*", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}); - // 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.}}}); + registry.add("Efficiency/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.}}}, true); // 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})"}}}); - registry.add("QA/hPtVsYPromptDstarGen", "MC Matched 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.}}}); + registry.add("Efficiency/hPtVsYPromptDstarGen", "MC Matched 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.}}}, true); // 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.}}}); - } + registry.add("Efficiency/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.}}}, true); - void process(CollisionsWCent const&, CandDstarWSelFlag const&) - { - for (const auto& candDstar : rowsSelectedCandDstar) { - auto yDstar = candDstar.y(constants::physics::MassDStar); - if (yCandDstarRecoMax >= 0. && std::abs(yDstar) > yCandDstarRecoMax) { - continue; + // Checking PV contributors from Data as well MC rec for calculation weights offline + if (isCentStudy) { + registry.add("Efficiency/hNumPvContributorsAll", "PV Contributors; PV Contributor; FT0M Centrality", {HistType::kTH2F, {{axisPvContrib}, {axisCentrality}}}, true); + registry.add("Efficiency/hNumPvContributorsCand", "PV Contributors; PV Contributor; FT0M Centrality", {HistType::kTH2F, {{axisPvContrib}, {axisCentrality}}}, true); + registry.add("Efficiency/hNumPvContributorsCandInMass", "PV Contributors; PV Contributor; FT0M Centrality", {HistType::kTH2F, {{axisPvContrib}, {axisCentrality}}}, true); + } + + // Hists at Reco level W/O ML usefull for efficiency calculation + if (doprocessMcWoMl && isCentStudy) { + registry.add("Efficiency/hPtVsCentVsPvContribRecSig", "Pt Vs Cent Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsPvContrib}, true); + registry.add("Efficiency/hPtPromptVsCentVsPvContribRecSig", "Pt Vs Cent Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsPvContrib}, true); + registry.add("Efficiency/hPtNonPromptVsCentVsPvContribRecSig", "Pt Vs Cent Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsPvContrib}, true); + } else if (doprocessMcWoMl && !isCentStudy) { + registry.add("Efficiency/hPtVsPvContribRecSig", "Pt Vs PvContrib", {HistType::kTHnSparseF, axesPtVsBDT}, true); + registry.add("Efficiency/hPtPromptVsPvContribRecSig", "Pt Vs PvContrib", {HistType::kTHnSparseF, axesPtVsBDT}, true); + registry.add("Efficiency/hPtNonPromptVsPvContribRecSig", "Pt Vs PvContrib", {HistType::kTHnSparseF, axesPtVsBDT}, true); + } + + // Hists at Reco level W/ ML usefull for efficiency calculation + if (doprocessMcWML && isCentStudy) { + registry.add("Efficiency/hPtVsCentVsBDTScoreVsPvContribRecSig", "Pt Vs Cent Vs BDTScore Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsBDTVsPvContrib}, true); + registry.add("Efficiency/hPtPromptVsCentVsBDTScorePvContribRecSig", "Pt Vs Cent Vs BDTScore Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsBDTVsPvContrib}, true); + registry.add("Efficiency/hPtNonPrompRectVsCentVsBDTScorePvContribRecSig", "Pt Vs Cent Vs BDTScore", {HistType::kTHnSparseF, axesPtVsCentVsBDTVsPvContrib}, true); + // registry.add("Efficiency/hPtBkgVsCentVsBDTScore", "Pt Vs Cent Vs BDTScore", {HistType::kTHnSparseF, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}}}); + } else if (doprocessMcWML && !isCentStudy) { + registry.add("Efficiency/hPtVsBDTScoreRecSig", "Pt Vs BDTScore", {HistType::kTHnSparseF, axesPtVsBDT}, true); + registry.add("Efficiency/hPtPromptVsBDTScoreRecSig", "Pt Vs BDTScore", {HistType::kTHnSparseF, axesPtVsBDT}, true); + registry.add("Efficiency/hPtNonPromptVsBDTScoreRecSig", "Pt Vs BDTScore", {HistType::kTHnSparseF, axesPtVsBDT}, true); + } + + // Hists at Gen level usefull for efficiency calculation + if (doprocessMcWoMl || doprocessMcWML) { + if (isCentStudy) { + registry.add("SignalLoss/hPtVsCentVsPvContribGenWRecEve", "Pt Vs Cent Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsPvContrib}, true); + registry.add("Efficiency/hPtVsCentVsPvContribGen", "Pt Vs Cent Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsPvContrib}, true); + registry.add("Efficiency/hPtPromptVsCentVsPvContribGen", "Pt Vs Cent Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsPvContrib}, true); + registry.add("Efficiency/hPtNonPromptVsCentVsPvContribGen", "Pt Vs Cent Vs PvContrib", {HistType::kTHnSparseF, axesPtVsCentVsPvContrib}, true); + } else { + registry.add("Efficiency/hPtGen", "MC Matched D* Candidates at Generator Level", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}, true); + registry.add("Efficiency/hPtPromptVsGen", "MC Matched Prompt D* Candidates at Generator Level", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}, true); + registry.add("Efficiency/hPtNonPromptVsGen", "MC Matched Non-Prompt D* Candidates at Generator Level", {HistType::kTH1F, {{vecPtBins, "#it{p}_{T} (GeV/#it{c})"}}}, true); + } + } + + if (studyD0ToPiKPi0) { + // inclusive D0ToPiKPi0 study + if (doprocessMcWML && isCentStudy) { + registry.add("D0ToPiKPi0/hDeltaInvMassVsPtVsCentVsBDTScore", "#Delta #it{M}_{inv} Vs Pt Vs Cent Vs BDTScore for D0ToPiKPi0", {HistType::kTHnSparseF, {{axisDeltaInvMass}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisCentrality}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}, {axisD0Mass}}}, true); + } else if (doprocessMcWoMl && isCentStudy) { + registry.add("D0ToPiKPi0/hDeltaInvMassDstar3D", "#Delta #it{M}_{inv} D* Candidate for D0ToPiKPi0; 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); + } else if (doprocessMcWML && !isCentStudy) { + registry.add("D0ToPiKPi0/hDeltaInvMassVsPtVsBDTScore", "#Delta #it{M}_{inv} Vs Pt Vs BDTScore for D0ToPiKPi0", {HistType::kTHnSparseF, {{axisDeltaInvMass}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}, {axisD0Mass}}}, true); + } else if (doprocessMcWoMl && !isCentStudy) { + registry.add("D0ToPiKPi0/hDeltaInvMassDstar2D", "#Delta #it{M}_{inv} D* Candidate for D0ToPiKPi0; 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); + } + + // differential (prompt/Non-prompt) D0ToPiKPi0 study + if (doprocessMcWML) { + registry.add("D0ToPiKPi0/hPromptDeltaInvMassVsPtVsBDTScore", "Prompt #Delta #it{M}_{inv} Vs Pt Vs BDTScore for D0ToPiKPi0", {HistType::kTHnSparseF, {{axisDeltaInvMass}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}, {axisD0Mass}}}, true); + registry.add("D0ToPiKPi0/hNonPromptDeltaInvMassVsPtVsBDTScore", "Non-Prompt #Delta #it{M}_{inv} Vs Pt Vs BDTScore for D0ToPiKPi0", {HistType::kTHnSparseF, {{axisDeltaInvMass}, {vecPtBins, "#it{p}_{T} (GeV/#it{c})"}, {axisBDTScoreBackground}, {axisBDTScorePrompt}, {axisBDTScoreNonPrompt}, {axisD0Mass}}}, true); + } else if (doprocessMcWoMl) { + registry.add("D0ToPiKPi0/hPromptDeltaInvMassDstar2D", "Prompt #Delta #it{M}_{inv} D* Candidate for D0ToPiKPi0; 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("D0ToPiKPi0/hNonPromptDeltaInvMassDstar2D", "Non-Prompt #Delta #it{M}_{inv} D* Candidate for D0ToPiKPi0; 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); + } + } + + // if weights to be applied + if (useWeight) { + ccdbApi.init(ccdbUrl); + std::map const metadata; + // Retrieve the file from CCDB + bool const isFileAvailable = ccdbApi.retrieveBlob(ccdbPathForWeight, ".", metadata, timestampCCDB, false, weightFileName); + if (!isFileAvailable) { + LOGF(fatal, "Failed to retrieve weight file from CCDB: %s", ccdbPathForWeight.value.c_str()); + return; } - 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 collision = candDstar.collision_as(); - auto centrality = collision.centFT0M(); // 0-100% - - auto signDstar = candDstar.signSoftPi(); - if (signDstar > 0) { - registry.fill(HIST("Yield/hDeltaInvMassDstar3D"), (invDstar - invD0), candDstar.pt(), centrality); - 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/hDeltaInvMassDstar3D"), (invAntiDstar - invD0Bar), candDstar.pt(), centrality); - 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()); + + if (isCentStudy) { + // Open the ROOT file + TFile* weightFile = TFile::Open(weightFileName.value.c_str(), "READ"); + if ((weightFile != nullptr) && !weightFile->IsZombie()) { + // Ensure hWeights is properly sized + hWeights.resize(nWeights); + for (int ithWeight = 0; ithWeight < nWeights; ++ithWeight) { + std::string const histName = "hMult" + std::to_string(ithWeight + 1) + "_Weight"; + hWeights[ithWeight] = reinterpret_cast(weightFile->Get(histName.c_str())); + if (hWeights[ithWeight] == nullptr) { + LOGF(fatal, "Histogram %s not found in weight file!", histName.c_str()); + return; + } + hWeights[ithWeight]->SetDirectory(nullptr); + hWeights[ithWeight]->SetName(("hWeight" + std::to_string(ithWeight + 1)).c_str()); + } + weightFile->Close(); + delete weightFile; + } else { + LOGF(fatal, "Failed to open weight file from CCDB: %s", weightFileName.value.c_str()); + return; + } } } } - void processMC(aod::McCollisions const&, CollisionsWCentMcLabel const& collisions, CandDstarWSelFlagMcRec const&, - CandDstarMcGen const& rowsMcPartilces, - aod::TracksWMc 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) + { + 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) { - rowsSelectedCandDstarMcRec.bindExternalIndices(&collisions); + 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) { + registry.fill(HIST("Efficiency/hNumPvContributorsCand"), nPVContributors, centrality); + } + + int nCandsSignalRegion = 0; + for (const auto& candDstar : selectedCandsCurrentCol) { + auto yDstar = candDstar.y(constants::physics::MassDStar); + if (yCandDstarRecoMax >= 0. && std::abs(yDstar) > yCandDstarRecoMax) { + continue; + } + + if (qaEnabled) { + 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 (deltaMassMin < deltaMDstar && deltaMDstar < deltaMassMax) { + nCandsSignalRegion++; + } + + if constexpr (ApplyMl) { + auto mlBdtScore = candDstar.mlProbDstarToD0Pi(); + registry.fill(HIST("Yield/hDeltaInvMassVsPtVsCentVsBDTScore"), deltaMDstar, candDstar.pt(), centrality, mlBdtScore[0], mlBdtScore[1], mlBdtScore[2], invD0); + } + + if (doprocessDataWoML) { + 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 + if (qaEnabled) { + 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 (deltaMassMin < deltaMAntiDstar && deltaMAntiDstar < deltaMassMax) { + nCandsSignalRegion++; + } + + if constexpr (ApplyMl) { + auto mlBdtScore = candDstar.mlProbDstarToD0Pi(); + registry.fill(HIST("Yield/hDeltaInvMassVsPtVsCentVsBDTScore"), deltaMAntiDstar, candDstar.pt(), centrality, mlBdtScore[0], mlBdtScore[1], mlBdtScore[2], invD0Bar); + } + + if (doprocessDataWoML) { + 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 + if (qaEnabled) { + 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 + } + /// @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) + { int8_t signDstar = 0; // MC at Reconstruction level - for (const auto& candDstarMcRec : rowsSelectedCandDstarMcRec) { + for (const auto& candDstarMcRec : candsMcRecSel) { auto ptDstarRecSig = candDstarMcRec.pt(); auto yDstarRecSig = candDstarMcRec.y(constants::physics::MassDStar); if (yCandDstarRecoMax >= 0. && std::abs(yDstarRecSig) > yCandDstarRecoMax) { continue; } - auto collision = candDstarMcRec.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 + auto collision = candDstarMcRec.template collision_as(); + auto centrality = collision.centFT0M(); // 0-100% + auto nPVContributors = collision.numContrib(); // number of PV contributors + if (std::abs(candDstarMcRec.flagMcMatchRec()) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { // if MC matching is successful at Reconstruction Level // 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/hPtSkimDstarGenSig"), particleMother.pt()); // generator level pt - registry.fill(HIST("Efficiency/hPtVsCentSkimDstarGenSig"), particleMother.pt(), centrality); - - // auto recCollision = candDstarMcRec.collision_as(); - // float centFT0M = recCollision.centFT0M(); - // LOGF(info, "centFT0M: %f", centFT0M); - - registry.fill(HIST("QA/hPtVsYSkimDstarRecSig"), ptDstarRecSig, yDstarRecSig); // Skimed at level of trackIndexSkimCreator - if (candDstarMcRec.isRecoTopol()) { // if Topological selection are passed - registry.fill(HIST("QA/hPtVsYRecoTopolDstarRecSig"), ptDstarRecSig, yDstarRecSig); - } - if (candDstarMcRec.isRecoPid()) { // if PID selection is passed - registry.fill(HIST("QA/hPtVsYRecoPidDstarRecSig"), ptDstarRecSig, yDstarRecSig); - } - if (candDstarMcRec.isRecoCand()) { // if all selection passed - registry.fill(HIST("QA/hPtFullRecoDstarRecSig"), ptDstarRecSig); - } - registry.fill(HIST("QA/hCPASkimD0RecSig"), candDstarMcRec.cpaD0()); - registry.fill(HIST("QA/hEtaSkimD0RecSig"), candDstarMcRec.etaD0()); - registry.fill(HIST("QA/hEtaSkimDstarRecSig"), candDstarMcRec.eta()); - - // only prompt signal at reconstruction level - if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::Prompt) { - registry.fill(HIST("QA/hPtVsYSkimPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); // Skimed at level of trackIndexSkimCreator - if (candDstarMcRec.isRecoTopol()) { // if Topological selection are passed - registry.fill(HIST("QA/hPtVsYRecoTopolPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); + 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? + if (qaEnabled) { + registry.fill(HIST("QA/hPtSkimDstarGenSig"), particleMother.pt()); // generator level pt + registry.fill(HIST("QA/hPtVsCentSkimDstarGenSig"), particleMother.pt(), centrality); + registry.fill(HIST("QA/hPtVsYSkimDstarRecSig"), ptDstarRecSig, yDstarRecSig); // Skimed at level of trackIndexSkimCreator + if (candDstarMcRec.isRecoTopol()) { // if Topological selection are passed + registry.fill(HIST("QA/hPtVsYRecoTopolDstarRecSig"), ptDstarRecSig, yDstarRecSig); } if (candDstarMcRec.isRecoPid()) { // if PID selection is passed - registry.fill(HIST("QA/hPtVsYRecoPidPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); + registry.fill(HIST("QA/hPtVsYRecoPidDstarRecSig"), ptDstarRecSig, yDstarRecSig); + } + } + + if (candDstarMcRec.isSelDstarToD0Pi()) { // if all selection passed + float weightValue = 1.0; + if (useWeight && (hWeights.empty() || hWeights[0] == nullptr)) { + LOGF(fatal, "Weight histograms are not initialized or empty. Check CCDB path or weight file."); + return; } - if (candDstarMcRec.isRecoCand()) { // if all selection passed - registry.fill(HIST("QA/hPtFullRecoPromptDstarRecSig"), ptDstarRecSig); + if (useWeight && isCentStudy) { + for (int ithWeight = 0; ithWeight < nWeights; ++ithWeight) { + if (centrality > centRangesForWeights.value[ithWeight] && centrality <= centRangesForWeights.value[ithWeight + 1]) { + weightValue = hWeights[ithWeight]->GetBinContent(hWeights[ithWeight]->FindBin(nPVContributors)); + break; + } + } + } + if (qaEnabled) { + registry.fill(HIST("QA/hPtFullRecoDstarRecSig"), ptDstarRecSig); } - } 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 constexpr (ApplyMl) { // All efficiency histograms at reconstruction level w/ ml + if (isCentStudy) { + auto bdtScore = candDstarMcRec.mlProbDstarToD0Pi(); + registry.fill(HIST("Efficiency/hPtVsCentVsBDTScoreVsPvContribRecSig"), ptDstarRecSig, centrality, bdtScore[0], bdtScore[1], bdtScore[2], nPVContributors, weightValue); + if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("Efficiency/hPtPromptVsCentVsBDTScorePvContribRecSig"), ptDstarRecSig, centrality, bdtScore[0], bdtScore[1], bdtScore[2], nPVContributors, weightValue); + } else if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtNonPrompRectVsCentVsBDTScorePvContribRecSig"), ptDstarRecSig, centrality, bdtScore[0], bdtScore[1], bdtScore[2], nPVContributors, weightValue); + } + } else { + auto bdtScore = candDstarMcRec.mlProbDstarToD0Pi(); + registry.fill(HIST("Efficiency/hPtVsBDTScoreRecSig"), ptDstarRecSig, bdtScore[0], bdtScore[1], bdtScore[2], weightValue); + if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("Efficiency/hPtPromptVsBDTScoreRecSig"), ptDstarRecSig, bdtScore[0], bdtScore[1], bdtScore[2], weightValue); + } else if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtNonPromptVsBDTScoreRecSig"), ptDstarRecSig, bdtScore[0], bdtScore[1], bdtScore[2], weightValue); + } + } + } else { // All efficiency histograms at reconstruction level w/o ml + if (isCentStudy) { + registry.fill(HIST("Efficiency/hPtVsCentVsPvContribRecSig"), ptDstarRecSig, centrality, nPVContributors, weightValue); + if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("Efficiency/hPtPromptVsCentVsPvContribRecSig"), ptDstarRecSig, centrality, nPVContributors, weightValue); + } else if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtNonPromptVsCentVsPvContribRecSig"), ptDstarRecSig, centrality, nPVContributors, weightValue); + } + } else { + registry.fill(HIST("Efficiency/hPtVsPvContribRecSig"), ptDstarRecSig, nPVContributors, weightValue); + if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("Efficiency/hPtPromptVsPvContribRecSig"), ptDstarRecSig, nPVContributors, weightValue); + } else if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtNonPromptVsPvContribRecSig"), ptDstarRecSig, nPVContributors, weightValue); + } + } + } + } + if (qaEnabled) { + registry.fill(HIST("QA/hCPASkimD0RecSig"), candDstarMcRec.cpaD0()); + registry.fill(HIST("QA/hEtaSkimD0RecSig"), candDstarMcRec.etaD0()); + registry.fill(HIST("QA/hEtaSkimDstarRecSig"), candDstarMcRec.eta()); + + // only prompt signal at reconstruction level + if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("QA/hPtVsYSkimPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); // Skimed at level of trackIndexSkimCreator + if (candDstarMcRec.isRecoTopol()) { // if Topological selection are passed + registry.fill(HIST("QA/hPtVsYRecoTopolPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); + } + if (candDstarMcRec.isRecoPid()) { // if PID selection is passed + registry.fill(HIST("QA/hPtVsYRecoPidPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); + } + if (candDstarMcRec.isSelDstarToD0Pi()) { // if all selection passed + registry.fill(HIST("QA/hPtFullRecoPromptDstarRecSig"), ptDstarRecSig); + } + } 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()) { // if PID selection is passed + registry.fill(HIST("QA/hPtVsYRecoPidNonPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); + } + if (candDstarMcRec.isSelDstarToD0Pi()) { // if all selection passed + registry.fill(HIST("QA/hPtFullRecoNonPromptDstarRecSig"), ptDstarRecSig); + } } - if (candDstarMcRec.isRecoPid()) { - registry.fill(HIST("QA/hPtVsYRecoPidNonPromptDstarRecSig"), ptDstarRecSig, yDstarRecSig); + } + } else if (studyD0ToPiKPi0 && candDstarMcRec.isSelDstarToD0Pi() && (std::abs(candDstarMcRec.flagMcMatchRec()) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPiPi0) && (std::abs(candDstarMcRec.flagMcMatchRecD0()) == hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiKPi0)) { + // Aplly all selection to study D*->D0(piKpi0)pi channel same as signal channel + // MC Matched but to D*->D0(piKpi0)pi channel + double deltaMDstar = -999.; + double invD0Mass = -999.; + if (candDstarMcRec.signSoftPi() < 0) { + deltaMDstar = candDstarMcRec.invMassAntiDstar() - candDstarMcRec.invMassD0Bar(); + invD0Mass = candDstarMcRec.invMassD0Bar(); + } else { + deltaMDstar = candDstarMcRec.invMassDstar() - candDstarMcRec.invMassD0(); + invD0Mass = candDstarMcRec.invMassD0(); + } + if constexpr (ApplyMl) { + auto bdtScore = candDstarMcRec.mlProbDstarToD0Pi(); + // inclusive study + if (isCentStudy) { + registry.fill(HIST("D0ToPiKPi0/hDeltaInvMassVsPtVsCentVsBDTScore"), deltaMDstar, candDstarMcRec.pt(), centrality, bdtScore[0], bdtScore[1], bdtScore[2], invD0Mass); + } else { + registry.fill(HIST("D0ToPiKPi0/hDeltaInvMassVsPtVsBDTScore"), deltaMDstar, candDstarMcRec.pt(), bdtScore[0], bdtScore[1], bdtScore[2], invD0Mass); + } + // differential (prompt/Non-prompt) study + if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("D0ToPiKPi0/hPromptDeltaInvMassVsPtVsBDTScore"), deltaMDstar, candDstarMcRec.pt(), bdtScore[0], bdtScore[1], bdtScore[2], invD0Mass); + } else if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("D0ToPiKPi0/hNonPromptDeltaInvMassVsPtVsBDTScore"), deltaMDstar, candDstarMcRec.pt(), bdtScore[0], bdtScore[1], bdtScore[2], invD0Mass); } - if (candDstarMcRec.isRecoCand()) { - registry.fill(HIST("QA/hPtFullRecoNonPromptDstarRecSig"), ptDstarRecSig); + } else { // without ML + // inclusive study + if (isCentStudy) { + registry.fill(HIST("D0ToPiKPi0/hDeltaInvMassDstar3D"), deltaMDstar, candDstarMcRec.pt(), centrality); + } else { + registry.fill(HIST("D0ToPiKPi0/hDeltaInvMassDstar2D"), deltaMDstar, candDstarMcRec.pt()); + } + // differential (prompt/Non-prompt) study + if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("D0ToPiKPi0/hPromptDeltaInvMassDstar2D"), deltaMDstar, candDstarMcRec.pt()); + } else if (candDstarMcRec.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("D0ToPiKPi0/hNonPromptDeltaInvMassDstar2D"), deltaMDstar, candDstarMcRec.pt()); } } } 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 (qaEnabled) { + registry.fill(HIST("QA/hCPASkimD0RecBg"), candDstarMcRec.cpaD0()); + registry.fill(HIST("QA/hEtaSkimD0RecBg"), candDstarMcRec.etaD0()); + registry.fill(HIST("QA/hEtaSkimDstarRecBg"), candDstarMcRec.eta()); + if (candDstarMcRec.isSelDstarToD0Pi()) { + registry.fill(HIST("QA/hPtSkimDstarRecBg"), candDstarMcRec.pt()); + } + } } - } - - // MC at Generator Level - for (const auto& mcParticle : rowsMcPartilces) { - if (TESTBIT(std::abs(mcParticle.flagMcMatchGen()), aod::hf_cand_dstar::DecayType::DstarToD0Pi)) { // MC Matching is successful at Generator Level + } // candidate loop ends + } + /// @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 (std::abs(mcParticle.flagMcMatchGen()) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { // 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.mcCollision_as(); + auto mcCollision = mcParticle.template mcCollision_as(); auto recCollisions = collisions.sliceBy(colsPerMcCollision, mcCollision.globalIndex()); - // auto recCollisions = collisions.sliceByCached(aod::mccollisionlabel::mcCollisionId, mcCollision.globalIndex(), cache); - // auto recCollisions = collisions.sliceByCachedUnsorted(aod::mccollisionlabel::mcCollisionId, mcCollision.globalIndex(), cache); - - // 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 = abs(c1.centFT0M() - c2.centFT0M()); - registry.fill(HIST("QA/hDeltaCentGen"), deltaCent); + if (qaEnabled) { + registry.fill(HIST("QA/hEtaDstarGen"), mcParticle.eta()); + registry.fill(HIST("QA/hPtDstarGen"), ptGen); + + // 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; + float pvContributors; // assigning centrality to MC Collision using max FT0M amplitute from Reconstructed collisions - if (recCollisions.size()) { + if (recCollisions.size() != 0) { std::vector::iterator, int>> tempRecCols; - for (const auto& recCol : recCollisions) { - // if(recCollisions.size()>1) LOGF(info, "cuurent cent: %f",recCol.centFT0M()); - tempRecCols.push_back(std::make_pair(recCol, recCol.numContrib())); + tempRecCols.emplace_back(recCol, recCol.numContrib()); } std::sort(tempRecCols.begin(), tempRecCols.end(), compare); centFT0MGen = tempRecCols.at(0).first.centFT0M(); - // if(recCollisions.size()>1) LOGF(info, "assigned cent: %f",centFT0MGen); + pvContributors = tempRecCols.at(0).second; } else { centFT0MGen = -999.; + pvContributors = -999.; + } + + float weightValue = 1.0; + if (useWeight && (hWeights.empty() || hWeights[0] == nullptr)) { + LOGF(fatal, "Weight histograms are not initialized or empty. Check CCDB path or weight file."); + return; + } + if (useWeight && isCentStudy) { + for (int ithWeight = 0; ithWeight < nWeights; ++ithWeight) { + if (centFT0MGen > centRangesForWeights.value[ithWeight] && centFT0MGen <= centRangesForWeights.value[ithWeight + 1]) { + weightValue = hWeights[ithWeight]->GetBinContent(hWeights[ithWeight]->FindBin(centFT0MGen, pvContributors)); + break; + } + } } - 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); + registry.fill(HIST("Efficiency/hPtVsYDstarGen"), ptGen, yGen, weightValue); + if (isCentStudy) { + if (recCollisions.size() != 0) { + registry.fill(HIST("SignalLoss/hPtVsCentVsPvContribGenWRecEve"), ptGen, centFT0MGen, pvContributors, weightValue); + } + registry.fill(HIST("Efficiency/hPtVsCentVsPvContribGen"), ptGen, centFT0MGen, pvContributors, weightValue); + } else { + registry.fill(HIST("Efficiency/hPtGen"), ptGen, weightValue); + } - // only promt Dstar candidate at Generator level + // Prompt if (mcParticle.originMcGen() == RecoDecay::OriginType::Prompt) { - registry.fill(HIST("QA/hPtPromptDstarGen"), ptGen); - registry.fill(HIST("QA/hPtVsYPromptDstarGen"), ptGen, yGen); - } else if (mcParticle.originMcGen() == RecoDecay::OriginType::NonPrompt) { // only non-prompt Dstar candidate at Generator level - registry.fill(HIST("QA/hPtNonPromptDstarGen"), ptGen); - registry.fill(HIST("QA/hPtVsYNonPromptDstarGen"), ptGen, yGen); + registry.fill(HIST("Efficiency/hPtVsYPromptDstarGen"), ptGen, yGen, weightValue); + if (isCentStudy) { + registry.fill(HIST("Efficiency/hPtPromptVsCentVsPvContribGen"), ptGen, centFT0MGen, pvContributors, weightValue); + } else { + registry.fill(HIST("Efficiency/hPtPromptVsGen"), ptGen, weightValue); + } + // Non-Prompt + } else if (mcParticle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("Efficiency/hPtVsYNonPromptDstarGen"), ptGen, yGen, weightValue); + if (isCentStudy) { + registry.fill(HIST("Efficiency/hPtNonPromptVsCentVsPvContribGen"), ptGen, centFT0MGen, pvContributors, weightValue); + + } else { + registry.fill(HIST("Efficiency/hPtNonPromptVsGen"), ptGen, weightValue); + } } } - } + } // MC Particle loop ends } - PROCESS_SWITCH(HfTaskDstarToD0Pi, processMC, "Process MC Data", false); - // 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) + // process data function without susing ML + void processDataWoML(CollisionsWCent const& cols, soa::Filtered const& selectedCands) { - return a.second > b.second; + 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, 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 4b808f5dfb1..a42089754dc 100644 --- a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx +++ b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx @@ -14,24 +14,77 @@ /// /// \author S. Politanò, INFN Torino, Italy /// \author Wu Chuntai, CUG, China +/// \author Ran Tu, Fudan University, China +/// \author Marcello Di Costanzo , Polytechnic University of Turin and INFN -#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 "Common/Core/EventPlaneHelper.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include 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_occupancy; +using namespace o2::hf_evsel; + +namespace o2::aod +{ +namespace full +{ +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(MlScore0, mlScore0, float); //! ML score of the first configured index +DECLARE_SOA_COLUMN(MlScore1, mlScore1, float); //! ML score of the second configured index +DECLARE_SOA_COLUMN(ScalarProd, scalarProd, float); //! Scalar product +DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality +} // namespace full +DECLARE_SOA_TABLE(HfCandMPtInfos, "AOD", "HFCANDMPTINFO", + full::M, + full::Pt, + full::MlScore0, + full::MlScore1); + +DECLARE_SOA_TABLE(HfCandFlowInfos, "AOD", "HFCANDFLOWINFO", + full::M, + full::Pt, + full::MlScore0, + full::MlScore1, + full::ScalarProd, + full::Cent); +} // namespace o2::aod enum DecayChannel { DplusToPiKPi = 0, DsToKKPi, @@ -39,33 +92,48 @@ enum DecayChannel { DplusToPiKPi = 0, D0ToPiK, D0ToKPi, LcToPKPi, - LcToPiKP }; + LcToPiKP, + XicToPKPi, + XicToPiKP, + Xic0ToXiPi +}; enum QvecEstimator { FV0A = 0, FT0M, FT0A, FT0C, TPCPos, - TPCNeg }; + TPCNeg, + TPCTot }; struct HfTaskFlowCharmHadrons { - Configurable zVtxMax{"zVtxMax", 10., "Max vertex coordinate z"}; + Produces rowCandMassPtMl; + Produces rowCandMassPtMlSpCent; + 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 fillMassPtMlTree{"fillMassPtMlTree", false, "Flag to fill mass, pt and ML scores tree"}; + Configurable fillMassPtMlSpCentTree{"fillMassPtMlSpCentTree", false, "Flag to fill mass, pt, ML scores, SP and centrality tree"}; + Configurable fillSparse{"fillSparse", true, "Flag to fill sparse"}; + Configurable downSampleFactor{"downSampleFactor", 1., "Fraction of candidates to keep in TTree"}; + Configurable ptDownSampleMax{"ptDownSampleMax", 10., "Maximum pt for the application of the downsampling factor"}; + 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 thnConfigAxisCosDeltaPhi{"thnConfigAxisCosDeltaPhi", {100, -1., 1.}, ""}; - ConfigurableAxis thnConfigAxisScalarProd{"thnConfigAxisScalarProd", {100, 0., 1.}, ""}; - ConfigurableAxis thnConfigAxisMlOne{"thnConfigAxisMlOne", {1000, 0., 1.}, ""}; - ConfigurableAxis thnConfigAxisMlTwo{"thnConfigAxisMlTwo", {1000, 0., 1.}, ""}; + EventPlaneHelper epHelper; + HfEventSelection hfEvSel; // event selection and monitoring + o2::framework::Service ccdb; + SliceCache cache; using CandDsDataWMl = soa::Filtered>; using CandDsData = soa::Filtered>; @@ -73,14 +141,20 @@ struct HfTaskFlowCharmHadrons { using CandDplusData = soa::Filtered>; using CandLcData = soa::Filtered>; using CandLcDataWMl = soa::Filtered>; + using CandXicData = soa::Filtered>; + using CandXicDataWMl = soa::Filtered>; + using CandXic0Data = soa::Filtered>; + using CandXic0DataWMl = 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; + Filter filterSelectXic0Candidates = aod::hf_sel_toxipi::resultSelections == true; Partition selectedDsToKKPi = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlag; Partition selectedDsToPiKK = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlag; @@ -94,57 +168,143 @@ 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; + Partition selectedXic0 = aod::hf_sel_toxipi::resultSelections == true; + Partition selectedXic0WMl = aod::hf_sel_toxipi::resultSelections == true; - SliceCache cache; - HfHelper hfHelper; - EventPlaneHelper epHelper; + 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, 0, constants::math::TwoPI}, ""}; + 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}, ""}; 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 axesReso = {thnAxisCent, thnAxisResoFT0cFV0a, thnAxisResoFT0cTPCtot, thnAxisResoFV0aTPCtot}; + if (occEstimator == 1) { + axesReso.insert(axesReso.end(), {thnAxisOccupancyITS, thnAxisNoSameBunchPileup, thnAxisOccupancy, + thnAxisNoCollInTimeRangeNarrow, thnAxisNoCollInTimeRangeStandard, thnAxisNoCollInRofStandard}); + } else { + axesReso.insert(axesReso.end(), {thnAxisOccupancyFT0C, thnAxisNoSameBunchPileup, thnAxisOccupancy, + thnAxisNoCollInTimeRangeNarrow, thnAxisNoCollInTimeRangeStandard, thnAxisNoCollInRofStandard}); + } + registry.add("spReso/hSparseReso", "THn for resolution with occupancy", HistType::kTHnSparseF, axesReso); + } + + hfEvSel.addHistograms(registry); // collision monitoring + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); } }; // end init @@ -153,37 +313,75 @@ struct HfTaskFlowCharmHadrons { /// \param tracksQx is the X component of the Q vector for the tracks /// \param tracksQy is the Y component of the Q vector for the tracks /// \param channel is the decay channel - template - void getQvecDtracks(const T1& cand, + template + void getQvecDtracks(T1 const& cand, std::vector& tracksQx, std::vector& tracksQy, - float& ampl) + const float ampl) { // TODO: add possibility to consider different weights for the tracks, at the moment only pT is considered; - float pXTrack0 = cand.pxProng0(); - float pYTrack0 = cand.pyProng0(); - float pTTrack0 = cand.ptProng0(); - float phiTrack0 = std::atan2(pYTrack0, pXTrack0); - float pXTrack1 = cand.pxProng1(); - float pYTrack1 = cand.pyProng1(); - float pTTrack1 = cand.ptProng1(); - float phiTrack1 = std::atan2(pYTrack1, pXTrack1); + float const pXTrack0 = cand.pxProng0(); + float const pYTrack0 = cand.pyProng0(); + float const pTTrack0 = cand.ptProng0(); + float const phiTrack0 = std::atan2(pYTrack0, pXTrack0); + float const pXTrack1 = cand.pxProng1(); + float const pYTrack1 = cand.pyProng1(); + float const pTTrack1 = cand.ptProng1(); + float const phiTrack1 = std::atan2(pYTrack1, pXTrack1); tracksQx.push_back(std::cos(harmonic * phiTrack0) * pTTrack0 / ampl); tracksQy.push_back(std::sin(harmonic * phiTrack0) * pTTrack0 / ampl); tracksQx.push_back(std::cos(harmonic * phiTrack1) * pTTrack1 / ampl); tracksQy.push_back(std::sin(harmonic * phiTrack1) * pTTrack1 / ampl); - if constexpr (channel != DecayChannel::D0ToPiK && channel != DecayChannel::D0ToKPi) { - float pXTrack2 = cand.pxProng2(); - float pYTrack2 = cand.pyProng2(); - float pTTrack2 = cand.ptProng2(); - float phiTrack2 = std::atan2(pYTrack2, pXTrack2); + if constexpr (Channel != DecayChannel::D0ToPiK && Channel != DecayChannel::D0ToKPi) { + float const pXTrack2 = cand.pxProng2(); + float const pYTrack2 = cand.pyProng2(); + float const pTTrack2 = cand.ptProng2(); + float const phiTrack2 = std::atan2(pYTrack2, pXTrack2); tracksQx.push_back(std::cos(harmonic * phiTrack2) * pTTrack2 / ampl); tracksQy.push_back(std::sin(harmonic * phiTrack2) * pTTrack2 / ampl); } } + /// Compute the Q vector for the candidate's tracks + /// \param cand is the candidate + /// \param tracksQx is the X component of the Q vector for the tracks + /// \param tracksQy is the Y component of the Q vector for the tracks + /// \param channel is the decay channel + template + void getQvecXic0Tracks(const T1& cand, + std::vector& tracksQx, + std::vector& tracksQy, + float ampl) + { + // add possibility to consider different weights for the tracks, at the moment only pT is considered; + float const pXTrack0 = cand.pxPosV0Dau(); + float const pYTrack0 = cand.pyPosV0Dau(); + float const pTTrack0 = std::hypot(pXTrack0, pYTrack0); + float const phiTrack0 = std::atan2(pXTrack0, pYTrack0); + float const pXTrack1 = cand.pxNegV0Dau(); + float const pYTrack1 = cand.pyNegV0Dau(); + float const pTTrack1 = std::hypot(pXTrack1, pYTrack1); + float const phiTrack1 = std::atan2(pXTrack1, pYTrack1); + float const pYTrack2 = cand.pxBachFromCasc(); + float const pXTrack2 = cand.pyBachFromCasc(); + float const pTTrack2 = std::hypot(pXTrack2, pYTrack2); + float const phiTrack2 = std::atan2(pXTrack2, pYTrack2); + float const pXTrack3 = cand.pxBachFromCharmBaryon(); + float const pYTrack3 = cand.pyBachFromCharmBaryon(); + float const pTTrack3 = std::hypot(pXTrack3, pYTrack3); + float const phiTrack3 = std::atan2(pXTrack3, pYTrack3); + + tracksQx.push_back(std::cos(harmonic * phiTrack0) * pTTrack0 / ampl); + tracksQy.push_back(std::sin(harmonic * phiTrack0) * pTTrack0 / ampl); + tracksQx.push_back(std::cos(harmonic * phiTrack1) * pTTrack1 / ampl); + tracksQy.push_back(std::sin(harmonic * phiTrack1) * pTTrack1 / ampl); + tracksQx.push_back(std::cos(harmonic * phiTrack2) * pTTrack2 / ampl); + tracksQy.push_back(std::sin(harmonic * phiTrack2) * pTTrack2 / ampl); + tracksQx.push_back(std::cos(harmonic * phiTrack3) * pTTrack3 / ampl); + tracksQy.push_back(std::sin(harmonic * phiTrack3) * pTTrack3 / ampl); + } /// Compute the delta psi in the range [0, pi/harmonic] /// \param psi1 is the first angle /// \param psi2 is the second angle @@ -191,62 +389,98 @@ struct HfTaskFlowCharmHadrons { float getDeltaPsiInRange(float psi1, float psi2) { float deltaPsi = psi1 - psi2; - if (std::abs(deltaPsi) > constants::math::PI / harmonic) { - if (deltaPsi > 0.) - deltaPsi -= constants::math::TwoPI / harmonic; - else - deltaPsi += constants::math::TwoPI / harmonic; - } + deltaPsi = RecoDecay::constrainAngle(deltaPsi, -o2::constants::math::PI / harmonic, harmonic); return deltaPsi; } + /// Get the event selection flags + /// \param hfevselflag is the event selection flag + std::vector getEventSelectionFlags(const o2::hf_evsel::HfCollisionRejectionMask 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 - void fillThn(float& mass, - float& pt, - float& cent, - float& cosNPhi, - float& cosDeltaPhi, - float& sp, - std::vector& outputMl) + /// \param occupancy is the occupancy of the collision using the track estimator + /// \param hfevselflag flag of the collision associated to utilsEvSelHf.h + void fillThn(const float mass, + const float pt, + const float cent, + const float cosNPhi, + const float sinNPhi, + const float cosDeltaPhi, + const float sp, + const std::vector& outputMl, + const float occupancy, + const o2::hf_evsel::HfCollisionRejectionMask 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; + const auto occupancy = o2::hf_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 @@ -283,6 +517,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(); @@ -295,16 +534,27 @@ struct HfTaskFlowCharmHadrons { /// Compute the scalar product /// \param collision is the collision with the Q vector information and event plane /// \param candidates are the selected candidates - template + template 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.; + o2::hf_evsel::HfCollisionRejectionMask hfevflag{}; + if (occEstimator != 0) { + occupancy = o2::hf_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); + float const amplQVec = qVecs[2]; + float const evtPl = epHelper.GetEventPlane(xQVec, yQVec, harmonic); int nProngs = 3; for (const auto& candidate : candidates) { @@ -312,93 +562,156 @@ struct HfTaskFlowCharmHadrons { std::vector outputMl = {-999., -999.}; if constexpr (std::is_same_v || std::is_same_v) { - switch (channel) { + switch (Channel) { case DecayChannel::DsToKKPi: - massCand = hfHelper.invMassDsToKKPi(candidate); + massCand = HfHelper::invMassDsToKKPi(candidate); if constexpr (std::is_same_v) { - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; + } } break; case DecayChannel::DsToPiKK: - massCand = hfHelper.invMassDsToPiKK(candidate); + massCand = HfHelper::invMassDsToPiKK(candidate); if constexpr (std::is_same_v) { - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; + } } break; default: break; } } else if constexpr (std::is_same_v || std::is_same_v) { - massCand = hfHelper.invMassDplusToPiKPi(candidate); + massCand = HfHelper::invMassDplusToPiKPi(candidate); if constexpr (std::is_same_v) { - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + 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) { nProngs = 2; - switch (channel) { + switch (Channel) { case DecayChannel::D0ToPiK: - massCand = hfHelper.invMassD0ToPiK(candidate); + massCand = HfHelper::invMassD0ToPiK(candidate); if constexpr (std::is_same_v) { - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; + } } break; case DecayChannel::D0ToKPi: - massCand = hfHelper.invMassD0barToKPi(candidate); + massCand = HfHelper::invMassD0barToKPi(candidate); if constexpr (std::is_same_v) { - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + 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) { - switch (channel) { + switch (Channel) { case DecayChannel::LcToPKPi: - massCand = hfHelper.invMassLcToPKPi(candidate); + massCand = HfHelper::invMassLcToPKPi(candidate); if constexpr (std::is_same_v) { - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbLcToPKPi()[classMl->at(iclass)]; + } } break; case DecayChannel::LcToPiKP: - massCand = hfHelper.invMassLcToPiKP(candidate); + massCand = HfHelper::invMassLcToPiKP(candidate); if constexpr (std::is_same_v) { - for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbLcToPiKP()[classMl->at(iclass)]; + } } break; 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; + } + } else if constexpr (std::is_same_v || std::is_same_v) { + massCand = candidate.invMassCharmBaryon(); + if constexpr (std::is_same_v) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbToXiPi()[classMl->at(iclass)]; + } + } } - float ptCand = candidate.pt(); - float phiCand = candidate.phi(); + float ptCand = 0.; + float phiCand = 0.; + + if constexpr (std::is_same_v || std::is_same_v) { + ptCand = RecoDecay::sqrtSumOfSquares(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()); + phiCand = std::atan2(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()); + } else { + ptCand = candidate.pt(); + phiCand = candidate.phi(); + } // If TPC is used for the SP estimation, the tracks of the hadron candidate must be removed from the TPC Q vector to avoid double counting if (qvecDetector == QvecEstimator::TPCNeg || qvecDetector == QvecEstimator::TPCPos) { - float ampl = amplQVec - static_cast(nProngs); + float const ampl = amplQVec - static_cast(nProngs); std::vector tracksQx = {}; std::vector tracksQy = {}; - - getQvecDtracks(candidate, tracksQx, tracksQy, ampl); + if constexpr (std::is_same_v || std::is_same_v) { + // std::cout<(candidate, tracksQx, tracksQy, ampl); + } for (auto iTrack{0u}; iTrack < tracksQx.size(); ++iTrack) { xQVec -= tracksQx[iTrack]; yQVec -= tracksQy[iTrack]; } } - float cosNPhi = std::cos(harmonic * phiCand); - float sinNPhi = std::sin(harmonic * phiCand); - float scalprodCand = cosNPhi * xQVec + sinNPhi * yQVec; - float cosDeltaPhi = std::cos(harmonic * (phiCand - evtPl)); - - fillThn(massCand, ptCand, cent, cosNPhi, cosDeltaPhi, scalprodCand, outputMl); + float const cosNPhi = std::cos(harmonic * phiCand); + float const sinNPhi = std::sin(harmonic * phiCand); + float const scalprodCand = cosNPhi * xQVec + sinNPhi * yQVec; + float const cosDeltaPhi = std::cos(harmonic * (phiCand - evtPl)); + + if (fillMassPtMlTree || fillMassPtMlSpCentTree) { + if (downSampleFactor < 1.) { + float const pseudoRndm = ptCand * 1000. - static_cast(ptCand * 1000); + if (ptCand < ptDownSampleMax && pseudoRndm >= downSampleFactor) { + continue; + } + } + if (fillMassPtMlTree) { + rowCandMassPtMl(massCand, ptCand, outputMl[0], outputMl[1]); + } + if (fillMassPtMlSpCentTree) { + rowCandMassPtMlSpCent(massCand, ptCand, outputMl[0], outputMl[1], scalprodCand, cent); + } + } + if (fillSparse) { + fillThn(massCand, ptCand, cent, cosNPhi, sinNPhi, cosDeltaPhi, scalprodCand, outputMl, occupancy, hfevflag); + } } } @@ -484,64 +797,135 @@ struct HfTaskFlowCharmHadrons { } PROCESS_SWITCH(HfTaskFlowCharmHadrons, processLc, "Process Lc candidates", false); + // 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); + + // 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); + + // Xic0 with ML + void processXic0Ml(CollsWithQvecs::iterator const& collision, + CandXic0DataWMl const&) + { + auto candsXic0WMl = selectedXic0WMl->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + runFlowAnalysis(collision, candsXic0WMl); + } + PROCESS_SWITCH(HfTaskFlowCharmHadrons, processXic0Ml, "Process Xic0 candidates with ML", false); + + // Xic0 + void processXic0(CollsWithQvecs::iterator const& collision, + CandXic0Data const&) + { + auto candsXic0 = selectedXic0->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + runFlowAnalysis(collision, candsXic0); + } + PROCESS_SWITCH(HfTaskFlowCharmHadrons, processXic0, "Process Xic0 candidates", false); + // Resolution - void processResolution(CollsWithQvecs::iterator const& collision) + void processResolution(CollsWithQvecs::iterator const& collision, + aod::BCsWithTimestamps const& bcs) { + float centrality{-1.f}; + float const xQVecFT0a = collision.qvecFT0ARe(); + float const yQVecFT0a = collision.qvecFT0AIm(); + float const xQVecFT0c = collision.qvecFT0CRe(); + float const yQVecFT0c = collision.qvecFT0CIm(); + float const xQVecFT0m = collision.qvecFT0MRe(); + float const yQVecFT0m = collision.qvecFT0MIm(); + float const xQVecFV0a = collision.qvecFV0ARe(); + float const yQVecFV0a = collision.qvecFV0AIm(); + float const xQVecBPos = collision.qvecBPosRe(); + float const yQVecBPos = collision.qvecBPosIm(); + float const xQVecBNeg = collision.qvecBNegRe(); + float const yQVecBNeg = collision.qvecBNegIm(); + float const xQVecBTot = collision.qvecBTotRe(); + float const yQVecBTot = collision.qvecBTotIm(); + + centrality = o2::hf_centrality::getCentralityColl(collision, o2::hf_centrality::CentralityEstimator::FT0C); + if (storeResoOccu) { + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + registry.fill(HIST("trackOccVsFT0COcc"), collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange()); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + std::vector evtSelFlags = getEventSelectionFlags(rejectionMask); + 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 (!collision.sel8() || std::abs(collision.posZ()) > zVtxMax) { + if (!isCollSelected(collision, bcs, centrality)) { + // no selection on the centrality is applied, but on event selection flags return; } - float centrality = getCentrality(collision); - float xQVecFT0a = collision.qvecFT0ARe(); - float yQVecFT0a = collision.qvecFT0AIm(); - float xQVecFT0c = collision.qvecFT0CRe(); - float yQVecFT0c = collision.qvecFT0CIm(); - float xQVecFT0m = collision.qvecFT0MRe(); - float yQVecFT0m = collision.qvecFT0MIm(); - float xQVecFV0a = collision.qvecFV0ARe(); - float yQVecFV0a = collision.qvecFV0AIm(); - float xQVecBPos = collision.qvecBPosRe(); - float yQVecBPos = collision.qvecBPosIm(); - float xQVecBNeg = collision.qvecBNegRe(); - float yQVecBNeg = collision.qvecBNegIm(); - 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) { - float epFT0a = epHelper.GetEventPlane(xQVecFT0a, yQVecFT0a, harmonic); - float epFT0c = epHelper.GetEventPlane(xQVecFT0c, yQVecFT0c, harmonic); - float epFT0m = epHelper.GetEventPlane(xQVecFT0m, yQVecFT0m, harmonic); - float epFV0a = epHelper.GetEventPlane(xQVecFV0a, yQVecFV0a, harmonic); - float epBPoss = epHelper.GetEventPlane(xQVecBPos, yQVecBPos, harmonic); - float epBNegs = epHelper.GetEventPlane(xQVecBNeg, yQVecBNeg, harmonic); + float const epFT0a = epHelper.GetEventPlane(xQVecFT0a, yQVecFT0a, harmonic); + float const epFT0c = epHelper.GetEventPlane(xQVecFT0c, yQVecFT0c, harmonic); + float const epFT0m = epHelper.GetEventPlane(xQVecFT0m, yQVecFT0m, harmonic); + float const epFV0a = epHelper.GetEventPlane(xQVecFV0a, yQVecFV0a, harmonic); + float const epBPoss = epHelper.GetEventPlane(xQVecBPos, yQVecBPos, harmonic); + float const epBNegs = epHelper.GetEventPlane(xQVecBNeg, yQVecBNeg, harmonic); + float const 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 025c525b35c..ecf0e8f6022 100644 --- a/PWGHF/D2H/Tasks/taskLb.cxx +++ b/PWGHF/D2H/Tasks/taskLb.cxx @@ -15,32 +15,52 @@ /// \author Panos Christakoglou , Nikhef /// \author Martin Voelkl , University of Birmingham -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" - -#include "Common/DataModel/Centrality.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; - -#include "Framework/runDataProcessing.h" +using namespace o2::hf_decay::hf_cand_beauty; /// Λb0 analysis task struct HfTaskLb { 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 lengthDCAParameter{"lengthDCAParameter", 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"}; @@ -52,27 +72,26 @@ struct HfTaskLb { 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; + Filter filterSelectCandidates = (aod::hf_sel_candidate_lb::isSelLbToLcPi >= selectionFlagLb); + + PresliceUnsorted mcPartID = aod::mctracklabel::mcParticleId; bool passesImpactParameterResolution(float pT, float d0Resolution) { - float expectedResolution(0.001 + 0.0052 * exp(-0.655 * pT)); + float const 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) + 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 + float const numerator = 1. / lengthParameter * std::exp(-dca / lengthParameter); + float const 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 @@ -168,83 +187,112 @@ struct HfTaskLb { soa::Join const& candidatesLc, TracksWExt const&) { - float massKStar892 = 0.892; - float massDelta1232 = 1.232; + float const massKStar892 = 0.892; + float const massDelta1232 = 1.232; + std::array dca = {0.f, 0.f, 0.f}; + std::array dcaResolution = {0.f, 0.f, 0.f}; for (const auto& candidateLc : candidatesLc) { - if (!candidateLc.isSelLcToPKPi() && !candidateLc.isSelLcToPiKP()) + if ((candidateLc.isSelLcToPKPi() == 0) && (candidateLc.isSelLcToPiKP() == 0)) { 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(); + float const reso0 = candidateLc.errorImpactParameter0(); // 0.0023166 *pow(track0.pt(), -0.788); + float const reso1 = candidateLc.errorImpactParameter1(); + float const 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)) + if (!passesImpactParameterResolution(track0.pt(), reso0)) { continue; - if (!passesImpactParameterResolution(track1.pt(), reso1)) + } + if (!passesImpactParameterResolution(track1.pt(), reso1)) { continue; - if (!passesImpactParameterResolution(track2.pt(), reso2)) + } + 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) + } + + dca = { + candidateLc.impactParameter0(), + candidateLc.impactParameter1(), + candidateLc.impactParameter2()}; + + bool const exceedsMaxDca = std::any_of(dca.begin(), dca.end(), [&](float val) { + return val > maximumImpactParameterForLambdaCCrossChecks; + }); + + if (exceedsMaxDca) { continue; - float likelihoodRatio = logLikelihoodRatioSingleTrackDCA(DCA0, reso0, DCALengthParameter) + logLikelihoodRatioSingleTrackDCA(DCA1, reso1, DCALengthParameter) + logLikelihoodRatioSingleTrackDCA(DCA2, reso2, DCALengthParameter); + } + dcaResolution = {reso0, reso1, reso2}; + + float likelihoodRatio = 0.0f; + for (size_t i = 0; i < dca.size(); ++i) { + likelihoodRatio += logLikelihoodRatioSingleTrackDCA(dca[i], dcaResolution[i], lengthDCAParameter); + } + registry.get(HIST("hPtlogLikelihood"))->Fill(candidateLc.pt(), likelihoodRatio); - if (likelihoodRatio < minLikelihoodRatioLc) + 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) { + if (candidateLc.isSelLcToPKPi() != 0) { + registry.get(HIST("hPtinvMassLc"))->Fill(candidateLc.pt(), HfHelper::invMassLcToPKPi(candidateLc)); + float const mRecoKstar = RecoDecay::m(std::array{track1.pVector(), track2.pVector()}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + float const mRecoDelta1232 = RecoDecay::m(std::array{track0.pVector(), track2.pVector()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiPlus}); + float const mRecoLambda1520 = RecoDecay::m(std::array{track0.pVector(), track1.pVector()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus}); + float const mDiffKStar892 = std::abs(mRecoKstar - massKStar892); + float const mDiffDelta1232 = std::abs(mRecoDelta1232 - massDelta1232); + float const 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) { + if (candidateLc.isSelLcToPiKP() != 0) { + registry.get(HIST("hPtinvMassLc"))->Fill(candidateLc.pt(), HfHelper::invMassLcToPiKP(candidateLc)); + float const mRecoKstar = RecoDecay::m(std::array{track1.pVector(), track0.pVector()}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + float const mRecoDelta1232 = RecoDecay::m(std::array{track2.pVector(), track0.pVector()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiPlus}); + float const mRecoLambda1520 = RecoDecay::m(std::array{track2.pVector(), track1.pVector()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus}); + float const mDiffKStar892 = std::abs(mRecoKstar - massKStar892); + float const mDiffDelta1232 = std::abs(mRecoDelta1232 - massDelta1232); + float const 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); @@ -253,28 +301,35 @@ struct HfTaskLb { } // Lambda_c candidates loop for cross checks for (const auto& candidate : candidates) { - 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) { + + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { continue; } registry.get(HIST("hZVertex"))->Fill(collision.posZ()); auto candLc = candidate.prong0_as>(); - 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) + dca = { + candLc.impactParameter0(), + candLc.impactParameter1(), + candLc.impactParameter2()}; + + dcaResolution = { + candLc.errorImpactParameter0(), + candLc.errorImpactParameter1(), + candLc.errorImpactParameter2()}; + + float likelihoodRatio = 0.0f; + for (size_t i = 0; i < dca.size(); ++i) { + likelihoodRatio += logLikelihoodRatioSingleTrackDCA(dca[i], dcaResolution[i], lengthDCAParameter); + } + + if (likelihoodRatio < minLikelihoodRatio) { continue; // Larger likelihood means more likely to be signal - float lbMass = hfHelper.invMassLbToLcPi(candidate); + } + float const lbMass = HfHelper::invMassLbToLcPi(candidate); registry.get(HIST("hPtinvMassLb"))->Fill(candidate.pt(), lbMass); - registry.fill(HIST("hMass"), hfHelper.invMassLbToLcPi(candidate), candidate.pt()); + 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()); @@ -285,7 +340,7 @@ struct HfTaskLb { registry.fill(HIST("hd0Prong1"), candidate.impactParameter1(), candidate.pt()); registry.fill(HIST("hCPA"), candidate.cpa(), candidate.pt()); registry.fill(HIST("hEta"), candidate.eta(), candidate.pt()); - registry.fill(HIST("hRapidity"), hfHelper.yLb(candidate), candidate.pt()); + registry.fill(HIST("hRapidity"), HfHelper::yLb(candidate), 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()); @@ -302,15 +357,14 @@ struct HfTaskLb { { // MC rec for (const auto& candidate : candidates) { - if (!(candidate.hfflag() & 1 << hf_cand_lb::DecayType::LbToLcPi)) { - continue; - } - if (yCandRecoMax >= 0. && std::abs(hfHelper.yLb(candidate)) > yCandRecoMax) { + + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { continue; } - auto candLc = candidate.prong0_as(); + auto candLc = candidate.prong0_as>(); + auto flagMcMatchRecLb = std::abs(candidate.flagMcMatchRec()); - if (std::abs(candidate.flagMcMatchRec()) == 1 << hf_cand_lb::DecayType::LbToLcPi) { + if (flagMcMatchRecLb == DecayChannelMain::LbToLcPi) { auto indexMother = RecoDecay::getMother(mcParticles, candidate.prong1_as().mcParticle_as>(), o2::constants::physics::Pdg::kLambdaB0, true); auto particleMother = mcParticles.rawIteratorAt(indexMother); @@ -319,10 +373,10 @@ struct HfTaskLb { 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/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/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()); @@ -338,10 +392,10 @@ struct HfTaskLb { 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/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/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()); @@ -357,7 +411,7 @@ struct HfTaskLb { // MC gen. level for (const auto& particle : mcParticles) { - if (std::abs(particle.flagMcMatchGen()) == 1 << hf_cand_lb::DecayType::LbToLcPi) { + if (std::abs(particle.flagMcMatchGen()) == DecayChannelMain::LbToLcPi) { auto yParticle = RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaB0); if (yCandGenMax >= 0. && std::abs(yParticle) > yCandGenMax) { diff --git a/PWGHF/D2H/Tasks/taskLbReduced.cxx b/PWGHF/D2H/Tasks/taskLbReduced.cxx new file mode 100644 index 00000000000..b8ba64cb42a --- /dev/null +++ b/PWGHF/D2H/Tasks/taskLbReduced.cxx @@ -0,0 +1,840 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file taskLbReduced.cxx +/// \brief Lb → Lc+ π- → (pK- π+) π- analysis task +/// +/// \author Biao Zhang , Heidelberg University + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +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_lb_lite +{ +DECLARE_SOA_COLUMN(PtLc, ptLc, float); //! Transverse momentum of Lc-baryon 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 Lc-baryon daughter candidate +DECLARE_SOA_COLUMN(PtLcProngMin, ptLcProngMin, float); //! Minimum pT of prongs of Lc-baryon daughter candidate (GeV/c) +DECLARE_SOA_COLUMN(EtaLcProngMin, etaLcProngMin, float); //! Minimum absolute pseudorapidity of prongs of Lc-baryon daughter candidate +DECLARE_SOA_COLUMN(ItsNClsLcProngMin, itsNClsLcProngMin, int); //! Minimum number of ITS clusters of prongs of Lc-baryon daughter candidate +DECLARE_SOA_COLUMN(TpcNClsCrossedRowsLcProngMin, tpcNClsCrossedRowsLcProngMin, int); //! Minimum number of TPC crossed rows of prongs of Lc-baryon daughter candidate +DECLARE_SOA_COLUMN(TpcChi2NClLcProngMax, tpcChi2NClLcProngMax, float); //! Maximum TPC chi2 of prongs of Lc-baryon daughter candidate +DECLARE_SOA_COLUMN(MLc, mLc, float); //! Invariant mass of Lc-baryon 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(NSigTpcPrLcProng0, nSigTpcPrLcProng0, float); //! TPC Nsigma separation for Lc-baryon prong0 with proton mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPrLcProng0, nSigTofPrLcProng0, float); //! TOF Nsigma separation for Lc-baryon prong0 with proton mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPrLcProng0, nSigTpcTofPrLcProng0, float); //! Combined TPC and TOF Nsigma separation for Lc-baryon prong0 with proton mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcKaLcProng1, nSigTpcKaLcProng1, float); //! TPC Nsigma separation for Lc-baryon prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofKaLcProng1, nSigTofKaLcProng1, float); //! TOF Nsigma separation for Lc-baryon prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofKaLcProng1, nSigTpcTofKaLcProng1, float); //! Combined TPC and TOF Nsigma separation for Lc-baryon prong1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcPiLcProng2, nSigTpcPiLcProng2, float); //! TPC Nsigma separation for Lc-baryon prong2 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPiLcProng2, nSigTofPiLcProng2, float); //! TOF Nsigma separation for Lc-baryon prong2 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPiLcProng2, nSigTpcTofPiLcProng2, float); //! Combined TPC and TOF Nsigma separation for Lc-baryon 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(DecayLengthLc, decayLengthLc, float); //! Decay length of Lc-baryon daughter candidate (cm) +DECLARE_SOA_COLUMN(DecayLengthXYLc, decayLengthXYLc, float); //! Transverse decay length of Lc-baryon daughter candidate (cm) +DECLARE_SOA_COLUMN(ImpactParameterLc, impactParameterLc, float); //! Impact parameter product of Lc-baryon 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_lb_lite + +DECLARE_SOA_TABLE(HfRedCandLbLites, "AOD", "HFREDCANDLBLITE", //! Table with some Lb properties + // B meson features hf_cand_lb_lite::M, + hf_cand_lb_lite::M, + hf_cand_lb_lite::Pt, + hf_cand_lb_lite::Eta, + hf_cand_lb_lite::Phi, + hf_cand_lb_lite::Y, + hf_cand_lb_lite::Cpa, + hf_cand_lb_lite::CpaXY, + hf_cand::Chi2PCA, + hf_cand_lb_lite::DecayLength, + hf_cand_lb_lite::DecayLengthXY, + hf_cand_lb_lite::DecayLengthNormalised, + hf_cand_lb_lite::DecayLengthXYNormalised, + hf_cand_lb_lite::ImpactParameterProduct, + hf_cand_lb_lite::MaxNormalisedDeltaIP, + hf_cand_lb_lite::MlScoreSig, + hf_sel_candidate_lb::IsSelLbToLcPi, + // Lc baryon features + hf_cand_lb_lite::MLc, + hf_cand_lb_lite::PtLc, + hf_cand_lb_lite::DecayLengthLc, + hf_cand_lb_lite::DecayLengthXYLc, + hf_cand_lb_lite::ImpactParameterLc, + hf_cand_lb_lite::PtLcProngMin, + hf_cand_lb_lite::EtaLcProngMin, + hf_cand_lb_lite::ItsNClsLcProngMin, + hf_cand_lb_lite::TpcNClsCrossedRowsLcProngMin, + hf_cand_lb_lite::TpcChi2NClLcProngMax, + hf_cand_lb_lite::NSigTpcPrLcProng0, + hf_cand_lb_lite::NSigTofPrLcProng0, + hf_cand_lb_lite::NSigTpcTofPrLcProng0, + hf_cand_lb_lite::NSigTpcKaLcProng1, + hf_cand_lb_lite::NSigTofKaLcProng1, + hf_cand_lb_lite::NSigTpcTofKaLcProng1, + hf_cand_lb_lite::NSigTpcPiLcProng2, + hf_cand_lb_lite::NSigTofPiLcProng2, + hf_cand_lb_lite::NSigTpcTofPiLcProng2, + hf_cand_lb_reduced::Prong0MlScoreBkg, + hf_cand_lb_reduced::Prong0MlScorePrompt, + hf_cand_lb_reduced::Prong0MlScoreNonprompt, + // pion features + hf_cand_lb_lite::PtBach, + hf_cand_lb_lite::AbsEtaBach, + hf_cand_lb_lite::ItsNClsBach, + hf_cand_lb_lite::TpcNClsCrossedRowsBach, + hf_cand_lb_lite::TpcChi2NClBach, + hf_cand_lb_lite::ImpactParameterBach, + hf_cand_lb_lite::NSigTpcPiBachelor, + hf_cand_lb_lite::NSigTofPiBachelor, + hf_cand_lb_lite::NSigTpcTofPiBachelor, + // MC truth + hf_cand_3prong::FlagMcMatchRec, + hf_cand_3prong::OriginMcRec, + hf_cand_lb_lite::FlagWrongCollision, + hf_cand_lb_lite::PtGen); + +DECLARE_SOA_TABLE(HfRedLbMcCheck, "AOD", "HFREDLBMCCHECK", //! Table with MC decay type check + hf_cand_3prong::FlagMcMatchRec, + hf_cand_lb_lite::FlagWrongCollision, + hf_cand_lb_lite::MLc, + hf_cand_lb_lite::PtLc, + hf_cand_lb_lite::M, + hf_cand_lb_lite::Pt, + hf_cand_lb_lite::MlScoreSig, + hf_lb_mc::PdgCodeBeautyMother, + hf_lb_mc::PdgCodeCharmMother, + hf_lb_mc::PdgCodeProng0, + hf_lb_mc::PdgCodeProng1, + hf_lb_mc::PdgCodeProng2, + hf_lb_mc::PdgCodeProng3); +} // namespace o2::aod + +/// Lb analysis task +struct HfTaskLbReduced { + Produces hfRedCandLbLite; + Produces hfRedLbMcCheck; + + 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 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 candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + + using TracksPion = soa::Join; + using CandsLc = soa::Join; + Filter filterSelectCandidates = (aod::hf_sel_candidate_lb::isSelLbToLcPi >= selectionFlagLb); + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + std::array processFuncData{doprocessData, doprocessDataWithLcMl, doprocessDataWithLbMl}; + 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, doprocessMcWithLcMl, doprocessMcWithLcMlAndDecayTypeCheck, doprocessMcWithLbMl, doprocessMcWithLbMlAndDecayTypeCheck}; + 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 axisMassLb{300, 4.5f, 6.0f}; + const AxisSpec axisMassLc{300, 2.15f, 2.45f}; + 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 axisPtLb{100, 0.f, 50.f}; + const AxisSpec axisPtLc{100, 0.f, 50.f}; + const AxisSpec axisPtPi{100, 0.f, 10.f}; + + if (doprocessData || doprocessDataWithLcMl || doprocessDataWithLbMl) { + if (fillHistograms) { + registry.add("hMass", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{M} (D#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtLb, axisMassLb}}); + registry.add("hDecLength", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtLb, axisDecayLength}}); + registry.add("hDecLengthXy", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtLb, axisDecayLength}}); + registry.add("hNormDecLengthXy", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtLb, axisNormDecayLength}}); + registry.add("hDcaProng0", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong 0 (#Lambda_{c}^{+}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtLb, axisDca}}); + registry.add("hDcaProng1", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong 1 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtLb, axisDca}}); + registry.add("hPtProng0", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtLb, axisPtLc}}); + registry.add("hPtProng1", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtLb, axisPtPi}}); + registry.add("hCosp", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtLb, axisCosp}}); + registry.add("hCospXy", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtLb, axisCosp}}); + registry.add("hEta", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hRapidity", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate #it{y};entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hImpParProd", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtLb, axisImpParProd}}); + registry.add("hinvMassLc", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #it{M}(pK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtLc, axisMassLc}}); + registry.add("hDecLengthLc", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtLc, axisDecayLength}}); + registry.add("hDecLengthXyLc", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtLc, axisDecayLength}}); + registry.add("hCospLc", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtLc, axisCosp}}); + registry.add("hCospXyLc", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtLc, axisCosp}}); + + // ML scores of Lc daughter + if (doprocessDataWithLcMl) { + registry.add("hMlScoreBkgLc", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML background score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + registry.add("hMlScorePromptLc", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML prompt score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + registry.add("hMlScoreNonPromptLc", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML nonprompt score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + } + + // ML scores of Lb candidate + if (doprocessDataWithLbMl) { + registry.add("hMlScoreSigLb", "#Lambda_{b}^{0} candidates;#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong0, #Lambda_{b}^{0} ML signal score;entries", {HistType::kTH2F, {axisPtLb, axisMlScore}}); + } + } + if (fillSparses) { + if (!(doprocessDataWithLcMl || doprocessDataWithLbMl)) { + registry.add("hMassPtCutVars", "#Lambda_{b}^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);#Lambda_{b}^{0} candidate norm. decay length XY (cm);#Lambda_{b}^{0} candidate impact parameter product (cm);#Lambda_{b}^{0} candidate cos(#vartheta_{P});#it{M} (pK#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate decay length (cm);#Lambda_{c}^{+} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassLb, axisPtLb, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassLc, axisPtLc, axisDecayLength, axisCosp}}); + } else { + registry.add("hMassPtCutVars", "#Lambda_{b}^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);#Lambda_{b}^{0} candidate norm. decay length XY (cm);#Lambda_{b}^{0} candidate impact parameter product (cm);#Lambda_{b}^{0} candidate cos(#vartheta_{P});#it{M} (pK#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate ML score bkg;#Lambda_{c}^{+} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassLb, axisPtLb, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassLc, axisPtLc, axisMlScore, axisMlScore}}); + } + } + } + + if (doprocessMc || doprocessMcWithDecayTypeCheck || doprocessMcWithLcMl || doprocessMcWithLcMlAndDecayTypeCheck || doprocessMcWithLbMl || doprocessMcWithLbMlAndDecayTypeCheck) { + if (fillHistograms) { + // gen histos + registry.add("hEtaGen", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{#eta}^{gen}(#Lambda_{b}^{0});entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hYGen", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{y}^{gen}(#Lambda_{b}^{0});entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hYGenWithProngsInAcceptance", "MC particles (generated-daughters in acceptance);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{y}^{gen}(#Lambda_{b}^{0});entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hPtProng0Gen", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{p}_{T}^{gen}(#Lambda_{c}^{+}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtLb, axisPtLc}}); + registry.add("hPtProng1Gen", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{p}_{T}^{gen}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtLb, axisPtPi}}); + registry.add("hYProng0Gen", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{y}^{gen}(#Lambda_{c}^{+});entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hYProng1Gen", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{y}^{gen}(#pi^{#plus});entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hEtaProng0Gen", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{#eta}^{gen}(#Lambda_{c}^{+});entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hEtaProng1Gen", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}^{gen}(#Lambda_{b}^{0}) (GeV/#it{c});#it{#eta}^{gen}(#pi^{#plus});entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + + // reco histos + // signal + registry.add("hMassRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{M} (D#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtLb, axisMassLb}}); + registry.add("hDecLengthRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtLb, axisDecayLength}}); + registry.add("hDecLengthXyRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtLb, axisDecayLength}}); + registry.add("hNormDecLengthXyRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtLb, axisNormDecayLength}}); + registry.add("hDcaProng0RecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong 0 (#Lambda_{c}^{+}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtLb, axisDca}}); + registry.add("hDcaProng1RecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong 1 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtLb, axisDca}}); + registry.add("hPtProng0RecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtLb, axisPtLc}}); + registry.add("hPtProng1RecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtLb, axisPtPi}}); + registry.add("hCospRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtLb, axisCosp}}); + registry.add("hCospXyRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtLb, axisCosp}}); + registry.add("hEtaRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hRapidityRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate #it{y};entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hImpParProdRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtLb, axisImpParProd}}); + registry.add("hinvMassLcRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #it{M}(pK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtLc, axisMassLc}}); + registry.add("hDecLengthLcRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtLc, axisDecayLength}}); + registry.add("hDecLengthXyLcRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtLc, axisDecayLength}}); + registry.add("hCospLcRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtLc, axisCosp}}); + registry.add("hCospXyLcRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtLc, axisCosp}}); + // background + if (fillBackground) { + registry.add("hMassRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{M} (D#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtLb, axisMassLb}}); + registry.add("hDecLengthRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtLb, axisDecayLength}}); + registry.add("hDecLengthXyRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtLb, axisDecayLength}}); + registry.add("hNormDecLengthXyRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate norm. decay length XY (cm);entries", {HistType::kTH2F, {axisPtLb, axisNormDecayLength}}); + registry.add("hDcaProng0RecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong 0 (#Lambda_{c}^{+}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtLb, axisDca}}); + registry.add("hDcaProng1RecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong 1 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtLb, axisDca}}); + registry.add("hPtProng0RecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtLb, axisPtLc}}); + registry.add("hPtProng1RecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{p}_{T}(#pi^{#plus}) (GeV/#it{c});entries", {HistType::kTH2F, {axisPtLb, axisPtPi}}); + registry.add("hCospRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtLb, axisCosp}}); + registry.add("hCospXyRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtLb, axisCosp}}); + registry.add("hEtaRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate #it{#eta};entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hRapidityRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate #it{y};entries", {HistType::kTH2F, {axisPtLb, axisEta}}); + registry.add("hImpParProdRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate impact parameter product;entries", {HistType::kTH2F, {axisPtLb, axisImpParProd}}); + registry.add("hinvMassLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #it{M}(pK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtLc, axisMassLc}}); + registry.add("hDecLengthLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtLc, axisDecayLength}}); + registry.add("hDecLengthXyLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});decay length XY (cm);entries", {HistType::kTH2F, {axisPtLc, axisDecayLength}}); + registry.add("hCospLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate cos(#vartheta_{P});entries", {HistType::kTH2F, {axisPtLc, axisCosp}}); + registry.add("hCospXyLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate cos(#vartheta_{P}^{XY});entries", {HistType::kTH2F, {axisPtLc, axisCosp}}); + } + // MC checks + if (doprocessMcWithDecayTypeCheck || doprocessMcWithLbMlAndDecayTypeCheck || doprocessMcWithLcMlAndDecayTypeCheck) { + constexpr uint8_t kNBinsDecayTypeMc = hf_cand_lb::DecayTypeMc::NDecayTypeMc; + TString labels[kNBinsDecayTypeMc]; + labels[hf_cand_lb::DecayTypeMc::LbToLcPiToPKPiPi] = "#Lambda_{b}^{0} #rightarrow (#Lambda_{c}^{#plus} #rightarrow p K^{#minus} #pi^{#plus}) #pi^{#minus}"; + labels[hf_cand_lb::DecayTypeMc::B0ToDplusPiToPiKPiPi] = "B^{0} #rightarrow (D^{#minus} #rightarrow #pi^{#minus} K^{#plus} #pi^{#minus}) #pi^{#plus}"; + labels[hf_cand_lb::DecayTypeMc::LbToLcKToPKPiK] = "#Lambda_{b}^{0} #rightarrow (#Lambda_{c}^{#plus} #rightarrow p K^{#minus} #pi^{#plus}) K^{#minus}"; + labels[hf_cand_lb::DecayTypeMc::PartlyRecoDecay] = "Partly reconstructed decay channel"; + labels[hf_cand_lb::DecayTypeMc::OtherDecay] = "Other decays"; + static const AxisSpec axisDecayType = {kNBinsDecayTypeMc, 0.5, kNBinsDecayTypeMc + 0.5, ""}; + registry.add("hDecayTypeMc", "DecayType", {HistType::kTH3F, {axisDecayType, axisMassLb, axisPtLb}}); + for (uint8_t iBin = 0; iBin < kNBinsDecayTypeMc; ++iBin) { + registry.get(HIST("hDecayTypeMc"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin]); + } + } + // ML scores of Lc daughter + if (doprocessMcWithLcMl || doprocessMcWithLcMlAndDecayTypeCheck) { + // signal + registry.add("hMlScoreBkgLcRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML background score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + registry.add("hMlScorePromptLcRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML prompt score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + registry.add("hMlScoreNonPromptLcRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML nonprompt score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + // background + registry.add("hMlScoreBkgLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML background score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + registry.add("hMlScorePromptLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML prompt score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + registry.add("hMlScoreNonPromptLcRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});prong0, #Lambda_{c}^{+} ML nonprompt score;entries", {HistType::kTH2F, {axisPtLc, axisMlScore}}); + } + // ML scores of Lb candidate + if (doprocessMcWithLbMl || doprocessMcWithLbMlAndDecayTypeCheck) { + // signal + registry.add("hMlScoreSigLbRecSig", "#Lambda_{b}^{0} candidates (matched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong0, #Lambda_{b}^{0} ML signal score;entries", {HistType::kTH2F, {axisPtLb, axisMlScore}}); + // background + registry.add("hMlScoreSigLbRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});prong0, #Lambda_{b}^{0} ML signal score;entries", {HistType::kTH2F, {axisPtLb, axisMlScore}}); + } + } + if (fillSparses) { + // gen sparses + registry.add("hPtYGenSig", "#Lambda_{b}^{0} particles (generated);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{y}(#Lambda_{b}^{0})", {HistType::kTHnSparseF, {axisPtLb, axisEta}}); + registry.add("hPtYWithProngsInAccepanceGenSig", "#Lambda_{b}^{0} particles (generated-daughters in acceptance);#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#it{y}(#Lambda_{b}^{0})", {HistType::kTHnSparseF, {axisPtLb, axisEta}}); + + // reco sparses + if (!(doprocessDataWithLcMl || doprocessDataWithLbMl)) { + registry.add("hMassPtCutVarsRecSig", "#Lambda_{b}^{0} candidates (matched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);#Lambda_{b}^{0} candidate norm. decay length XY (cm);#Lambda_{b}^{0} candidate impact parameter product (cm);#Lambda_{b}^{0} candidate cos(#vartheta_{P});#it{M} (pK#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate decay length (cm);#Lambda_{c}^{+} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassLb, axisPtLb, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassLc, axisPtLc, axisDecayLength, axisCosp}}); + if (fillBackground) { + registry.add("hMassPtCutVarsRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);#Lambda_{b}^{0} candidate norm. decay length XY (cm);#Lambda_{b}^{0} candidate impact parameter product (cm);#Lambda_{b}^{0} candidate cos(#vartheta_{P});#it{M} (pK#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate decay length (cm);#Lambda_{c}^{+} candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassLb, axisPtLb, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassLc, axisPtLc, axisDecayLength, axisCosp}}); + } + } else { + registry.add("hMassPtCutVarsRecSig", "#Lambda_{b}^{0} candidates (matched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);#Lambda_{b}^{0} candidate norm. decay length XY (cm);#Lambda_{b}^{0} candidate impact parameter product (cm);#Lambda_{b}^{0} candidate cos(#vartheta_{P});#it{M} (pK#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate ML score bkg;#Lambda_{c}^{+} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassLb, axisPtLb, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassLc, axisPtLc, axisMlScore, axisMlScore}}); + if (fillBackground) { + registry.add("hMassPtCutVarsRecBg", "#Lambda_{b}^{0} candidates (unmatched);#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{b}^{0}) (GeV/#it{c});#Lambda_{b}^{0} candidate decay length (cm);#Lambda_{b}^{0} candidate norm. decay length XY (cm);#Lambda_{b}^{0} candidate impact parameter product (cm);#Lambda_{b}^{0} candidate cos(#vartheta_{P});#it{M} (pK#pi) (GeV/#it{c}^{2});#it{p}_{T}(#Lambda_{c}^{#plus}) (GeV/#it{c});#Lambda_{c}^{+} candidate ML score bkg;#Lambda_{c}^{+} candidate ML score nonprompt", {HistType::kTHnSparseF, {axisMassLb, axisPtLb, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMassLc, axisPtLc, axisMlScore, axisMlScore}}); + } + } + } + } + } + + /// Selection of Lb daughter in geometrical acceptance + /// \param etaProng is the pseudorapidity of Lb prong + /// \param ptProng is the pT of Lb 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 withLcMl is the flag to enable the filling with ML scores for the Lc daughter + /// \param withLbMl is the flag to enable the filling with ML scores for the Lb candidate + /// \param candidate is the Lb candidate + /// \param candidatesLc is the table with Lc candidates + template + void fillCand(Cand const& candidate, + CandsLc const&) + { + auto ptCandLb = candidate.pt(); + auto invMassLb = HfHelper::invMassLbToLcPi(candidate); + auto candLc = candidate.template prong0_as(); + auto ptLc = candidate.ptProng0(); + auto invMassLc = candLc.invMassHypo0() > 0 ? candLc.invMassHypo0() : candLc.invMassHypo1(); + // TODO: here we are assuming that only one of the two hypotheses is filled, to be checked + std::array const posPv{candidate.posX(), candidate.posY(), candidate.posZ()}; + std::array const posSvLc{candLc.xSecondaryVertex(), candLc.ySecondaryVertex(), candLc.zSecondaryVertex()}; + std::array const momLc{candLc.pVector()}; + auto cospLc = RecoDecay::cpa(posPv, posSvLc, momLc); + auto cospXyLc = RecoDecay::cpaXY(posPv, posSvLc, momLc); + auto decLenLc = RecoDecay::distance(posPv, posSvLc); + auto decLenXyLc = RecoDecay::distanceXY(posPv, posSvLc); + + 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_lb::DecayTypeMc::LbToLcPiToPKPiPi); + } + + if (fillHistograms) { + if constexpr (DoMc) { + if (isSignal) { + registry.fill(HIST("hMassRecSig"), ptCandLb, HfHelper::invMassLbToLcPi(candidate)); + registry.fill(HIST("hPtProng0RecSig"), ptCandLb, candidate.ptProng0()); + registry.fill(HIST("hPtProng1RecSig"), ptCandLb, candidate.ptProng1()); + registry.fill(HIST("hImpParProdRecSig"), ptCandLb, candidate.impactParameterProduct()); + registry.fill(HIST("hDecLengthRecSig"), ptCandLb, candidate.decayLength()); + registry.fill(HIST("hDecLengthXyRecSig"), ptCandLb, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXyRecSig"), ptCandLb, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hDcaProng0RecSig"), ptCandLb, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1RecSig"), ptCandLb, candidate.impactParameter1()); + registry.fill(HIST("hCospRecSig"), ptCandLb, candidate.cpa()); + registry.fill(HIST("hCospXyRecSig"), ptCandLb, candidate.cpaXY()); + registry.fill(HIST("hEtaRecSig"), ptCandLb, candidate.eta()); + registry.fill(HIST("hRapidityRecSig"), ptCandLb, HfHelper::yLb(candidate)); + registry.fill(HIST("hinvMassLcRecSig"), ptLc, invMassLc); + registry.fill(HIST("hDecLengthLcRecSig"), ptLc, decLenLc); + registry.fill(HIST("hDecLengthXyLcRecSig"), ptLc, decLenXyLc); + registry.fill(HIST("hCospLcRecSig"), ptLc, cospLc); + registry.fill(HIST("hCospXyLcRecSig"), ptLc, cospXyLc); + if constexpr (WithDecayTypeCheck) { + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_lb::DecayTypeMc::LbToLcPiToPKPiPi, invMassLb, ptCandLb); + } + if constexpr (WithLcMl) { + registry.fill(HIST("hMlScoreBkgLcRecSig"), ptLc, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptLcRecSig"), ptLc, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptLcRecSig"), ptLc, candidate.prong0MlScoreNonprompt()); + } + if constexpr (WithLbMl) { + registry.fill(HIST("hMlScoreSigLbRecSig"), ptCandLb, candidate.mlProbLbToLcPi()); + } + } else if (fillBackground) { + registry.fill(HIST("hMassRecBg"), ptCandLb, HfHelper::invMassLbToLcPi(candidate)); + registry.fill(HIST("hPtProng0RecBg"), ptCandLb, candidate.ptProng0()); + registry.fill(HIST("hPtProng1RecBg"), ptCandLb, candidate.ptProng1()); + registry.fill(HIST("hImpParProdRecBg"), ptCandLb, candidate.impactParameterProduct()); + registry.fill(HIST("hDecLengthRecBg"), ptCandLb, candidate.decayLength()); + registry.fill(HIST("hDecLengthXyRecBg"), ptCandLb, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXyRecBg"), ptCandLb, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hDcaProng0RecBg"), ptCandLb, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1RecBg"), ptCandLb, candidate.impactParameter1()); + registry.fill(HIST("hCospRecBg"), ptCandLb, candidate.cpa()); + registry.fill(HIST("hCospXyRecBg"), ptCandLb, candidate.cpaXY()); + registry.fill(HIST("hEtaRecBg"), ptCandLb, candidate.eta()); + registry.fill(HIST("hRapidityRecBg"), ptCandLb, HfHelper::yLb(candidate)); + registry.fill(HIST("hinvMassLcRecBg"), ptLc, invMassLc); + registry.fill(HIST("hDecLengthLcRecBg"), ptLc, decLenLc); + registry.fill(HIST("hDecLengthXyLcRecBg"), ptLc, decLenXyLc); + registry.fill(HIST("hCospLcRecBg"), ptLc, cospLc); + registry.fill(HIST("hCospXyLcRecBg"), ptLc, cospXyLc); + if constexpr (WithLcMl) { + registry.fill(HIST("hMlScoreBkgLcRecBg"), ptLc, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptLcRecBg"), ptLc, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptLcRecBg"), ptLc, candidate.prong0MlScoreNonprompt()); + } + if constexpr (WithLbMl) { + registry.fill(HIST("hMlScoreSigLbRecBg"), ptCandLb, candidate.mlProbLbToLcPi()); + } + } else if constexpr (WithDecayTypeCheck) { + if (TESTBIT(flagMcMatchRec, hf_cand_lb::DecayTypeMc::LbToLcKToPKPiK)) { // Lb → Lc+ K- → (pK-π+) K- + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_lb::DecayTypeMc::LbToLcKToPKPiK, invMassLb, ptCandLb); + } else if (TESTBIT(flagMcMatchRec, hf_cand_lb::DecayTypeMc::B0ToDplusPiToPiKPiPi)) { // // B0 → D- π+ → (π- K+ π-) π+ + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_lb::DecayTypeMc::B0ToDplusPiToPiKPiPi, invMassLb, ptCandLb); + } else if (TESTBIT(flagMcMatchRec, hf_cand_lb::DecayTypeMc::PartlyRecoDecay)) { // Partly reconstructed decay channel + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_lb::DecayTypeMc::PartlyRecoDecay, invMassLb, ptCandLb); + } else { + registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_lb::DecayTypeMc::OtherDecay, invMassLb, ptCandLb); + } + } + } else { + registry.fill(HIST("hMass"), ptCandLb, invMassLb); + registry.fill(HIST("hPtProng0"), ptCandLb, candidate.ptProng0()); + registry.fill(HIST("hPtProng1"), ptCandLb, candidate.ptProng1()); + registry.fill(HIST("hImpParProd"), ptCandLb, candidate.impactParameterProduct()); + registry.fill(HIST("hDecLength"), ptCandLb, candidate.decayLength()); + registry.fill(HIST("hDecLengthXy"), ptCandLb, candidate.decayLengthXY()); + registry.fill(HIST("hNormDecLengthXy"), ptCandLb, candidate.decayLengthXY() / candidate.errorDecayLengthXY()); + registry.fill(HIST("hDcaProng0"), ptCandLb, candidate.impactParameter0()); + registry.fill(HIST("hDcaProng1"), ptCandLb, candidate.impactParameter1()); + registry.fill(HIST("hCosp"), ptCandLb, candidate.cpa()); + registry.fill(HIST("hCospXy"), ptCandLb, candidate.cpaXY()); + registry.fill(HIST("hEta"), ptCandLb, candidate.eta()); + registry.fill(HIST("hRapidity"), ptCandLb, HfHelper::yLb(candidate)); + registry.fill(HIST("hinvMassLc"), ptLc, invMassLc); + registry.fill(HIST("hDecLengthLc"), ptLc, decLenLc); + registry.fill(HIST("hDecLengthXyLc"), ptLc, decLenXyLc); + registry.fill(HIST("hCospLc"), ptLc, cospLc); + registry.fill(HIST("hCospXyLc"), ptLc, cospXyLc); + + if constexpr (WithLcMl) { + registry.fill(HIST("hMlScoreBkgLc"), ptLc, candidate.prong0MlScoreBkg()); + registry.fill(HIST("hMlScorePromptLc"), ptLc, candidate.prong0MlScorePrompt()); + registry.fill(HIST("hMlScoreNonPromptLc"), ptLc, candidate.prong0MlScoreNonprompt()); + } + if constexpr (WithLbMl) { + registry.fill(HIST("hMlScoreSigLb"), ptCandLb, candidate.mlProbLbToLcPi()); + } + } + } + if (fillSparses) { + if constexpr (WithLcMl) { + if (isSignal) { + if constexpr (WithLcMl) { + registry.fill(HIST("hMassPtCutVarsRecSig"), invMassLb, ptCandLb, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassLc, ptLc, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVarsRecSig"), invMassLb, ptCandLb, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassLc, ptLc, decLenLc, cospLc); + } + } else if (fillBackground) { + if constexpr (WithLcMl) { + registry.fill(HIST("hMassPtCutVarsRecBg"), invMassLb, ptCandLb, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassLc, ptLc, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVarsRecBg"), invMassLb, ptCandLb, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassLc, ptLc, decLenLc, cospLc); + } + } + } else { + if constexpr (WithLcMl) { + registry.fill(HIST("hMassPtCutVars"), invMassLb, ptCandLb, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassLc, ptLc, candidate.prong0MlScoreBkg(), candidate.prong0MlScoreNonprompt()); + } else { + registry.fill(HIST("hMassPtCutVars"), invMassLb, ptCandLb, candidate.decayLength(), candidate.decayLengthXY() / candidate.errorDecayLengthXY(), candidate.impactParameterProduct(), candidate.cpa(), invMassLc, ptLc, decLenLc, cospLc); + } + } + } + if (fillTree) { + float const pseudoRndm = ptLc * 1000. - static_cast(ptLc * 1000); + if (flagMcMatchRec != 0 || (((DoMc && fillBackground) || !DoMc) && (ptCandLb >= ptMaxForDownSample || pseudoRndm < downSampleBkgFactor))) { + float prong0MlScoreBkg = -1.; + float prong0MlScorePrompt = -1.; + float prong0MlScoreNonprompt = -1.; + float candidateMlScoreSig = -1; + if constexpr (WithLcMl) { + prong0MlScoreBkg = candidate.prong0MlScoreBkg(); + prong0MlScorePrompt = candidate.prong0MlScorePrompt(); + prong0MlScoreNonprompt = candidate.prong0MlScoreNonprompt(); + } + if constexpr (WithLbMl) { + candidateMlScoreSig = candidate.mlProbLbToLcPi(); + } + auto prong1 = candidate.template prong1_as(); + + float ptMother = -1.; + if constexpr (DoMc) { + ptMother = candidate.ptMother(); + } + + hfRedCandLbLite( + // Lb features + invMassLb, + ptCandLb, + candidate.eta(), + candidate.phi(), + HfHelper::yLb(candidate), + candidate.cpa(), + candidate.cpaXY(), + candidate.chi2PCA(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.impactParameterProduct(), + candidate.maxNormalisedDeltaIP(), + candidateMlScoreSig, + candidate.isSelLbToLcPi(), + // Lc-baryon features + invMassLc, + ptLc, + decLenLc, + decLenXyLc, + candidate.impactParameter0(), + candLc.ptProngMin(), + candLc.absEtaProngMin(), + candLc.itsNClsProngMin(), + candLc.tpcNClsCrossedRowsProngMin(), + candLc.tpcChi2NClProngMax(), + candLc.tpcNSigmaPrProng0(), + candLc.tofNSigmaPrProng0(), + candLc.tpcTofNSigmaPrProng0(), + candLc.tpcNSigmaKaProng1(), + candLc.tofNSigmaKaProng1(), + candLc.tpcTofNSigmaKaProng1(), + candLc.tpcNSigmaPiProng2(), + candLc.tofNSigmaPiProng2(), + candLc.tpcTofNSigmaPiProng2(), + 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) { + hfRedLbMcCheck( + flagMcMatchRec, + flagWrongCollision, + invMassLc, + ptLc, + invMassLb, + ptCandLb, + candidateMlScoreSig, + candidate.pdgCodeBeautyMother(), + candidate.pdgCodeCharmMother(), + candidate.pdgCodeProng0(), + candidate.pdgCodeProng1(), + candidate.pdgCodeProng2(), + candidate.pdgCodeProng3()); + } + } + } + } + + /// Fill particle histograms (gen MC truth) + void fillCandMcGen(aod::HfMcGenRedLbs::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 const 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 Lb 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, + CandsLc const& candidatesLc, + TracksPion const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // candidate loop + } // processData + PROCESS_SWITCH(HfTaskLbReduced, processData, "Process data without ML scores for Lb and Lc daughter", true); + + void processDataWithLcMl(soa::Filtered> const& candidates, + CandsLc const& candidatesLc, + TracksPion const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // candidate loop + } // processDataWithLcMl + PROCESS_SWITCH(HfTaskLbReduced, processDataWithLcMl, "Process data with(out) ML scores for Lc daughter (Lb)", false); + + void processDataWithLbMl(soa::Filtered> const& candidates, + CandsLc const& candidatesLc, + TracksPion const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // candidate loop + } // processDataWithLbMl + PROCESS_SWITCH(HfTaskLbReduced, processDataWithLbMl, "Process data with(out) ML scores for Lb (Lc daughter)", false); + + void processMc(soa::Filtered> const& candidates, + aod::HfMcGenRedLbs const& mcParticles, + CandsLc const& candidatesLc, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskLbReduced, processMc, "Process MC without ML scores for Lb and Lc daughter", false); + + void processMcWithDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedLbs const& mcParticles, + CandsLc const& candidatesLc, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskLbReduced, processMcWithDecayTypeCheck, "Process MC with decay type check and without ML scores for Lb and D daughter", false); + + void processMcWithLcMl(soa::Filtered> const& candidates, + aod::HfMcGenRedLbs const& mcParticles, + CandsLc const& candidatesLc, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcWithLcMl + PROCESS_SWITCH(HfTaskLbReduced, processMcWithLcMl, "Process MC with(out) ML scores for Lc daughter (Lb)", false); + + void processMcWithLcMlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedLbs const& mcParticles, + CandsLc const& candidatesLc, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskLbReduced, processMcWithLcMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for Lb (Lc daughter)", false); + + void processMcWithLbMl(soa::Filtered> const& candidates, + aod::HfMcGenRedLbs const& mcParticles, + CandsLc const& candidatesLc, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMcWithLbMl + PROCESS_SWITCH(HfTaskLbReduced, processMcWithLbMl, "Process MC with(out) ML scores for Lb (Lc daughter)", false); + + void processMcWithLbMlAndDecayTypeCheck(soa::Filtered> const& candidates, + aod::HfMcGenRedLbs const& mcParticles, + CandsLc const& candidatesLc, + TracksPion const&) + { + // MC rec + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLb(candidate)) > yCandRecoMax) { + continue; + } + fillCand(candidate, candidatesLc); + } // rec + + // MC gen. level + for (const auto& particle : mcParticles) { + fillCandMcGen(particle); + } // gen + } // processMc + PROCESS_SWITCH(HfTaskLbReduced, processMcWithLbMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for Lb (Lc daughter)", false); +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskLc.cxx b/PWGHF/D2H/Tasks/taskLc.cxx index 842c4b18e11..9550eb95a0d 100644 --- a/PWGHF/D2H/Tasks/taskLc.cxx +++ b/PWGHF/D2H/Tasks/taskLc.cxx @@ -17,20 +17,58 @@ /// \author Vít Kučera , CERN /// \author Annalena Kalteyer , GSI Darmstadt /// \author Biao Zhang , Heidelberg University +/// \author Ran Tu , Fudan University +/// \author Oleksii Lubynets , Heidelberg University, GSI Darmstadt -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsUpcHf.h" +#include "PWGUD/Core/UPCHelpers.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include // std::vector 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; +using namespace o2::hf_evsel; +using namespace o2::analysis::hf_upc; /// Λc± → p± K∓ π± analysis task struct HfTaskLc { @@ -39,233 +77,204 @@ 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)"}; + Configurable storeProperLifetime{"storeProperLifetime", false, "Flag to store proper lifetime"}; + // CCDB configuration + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + 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 + HfUpcGapThresholds upcThresholds; // UPC gap determination thresholds + SliceCache cache; + Service ccdb; + + 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>; - - HistogramRegistry registry{ - "registry", - {/// mass candidate - {"Data/hMass", "3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1F, {{600, 1.98, 2.58}}}}, - {"MC/reconstructed/signal/hMassRecSig", "3-prong candidates (matched);inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1F, {{600, 1.98, 2.58}}}}, - {"MC/reconstructed/prompt/hMassRecSigPrompt", "3-prong candidates (matched, prompt);inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1F, {{600, 1.98, 2.58}}}}, - {"MC/reconstructed/nonprompt/hMassRecSigNonPrompt", "3-prong candidates (matched, non-prompt);inv. mass (p K #pi) (GeV/#it{c}^{2})", {HistType::kTH1F, {{600, 1.98, 2.58}}}}, - /// pT - {"Data/hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/signal/hPtRecSig", "3-prong candidates (matched);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/prompt/hPtRecSigPrompt", "3-prong candidates (matched, prompt);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/nonprompt/hPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);#it{p}_{T}^{rec.} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/generated/signal/hPtGen", "MC particles (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/generated/prompt/hPtGenPrompt", "MC particles (matched, prompt);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/generated/nonprompt/hPtGenNonPrompt", "MC particles (matched, non-prompt);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/generated/signal/hPtGenSig", "3-prong candidates (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"Data/hPtProng0", "3-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/signal/hPtRecProng0Sig", "3-prong candidates (matched);prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/prompt/hPtRecProng0SigPrompt", "3-prong candidates (matched, prompt);prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/nonprompt/hPtRecProng0SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"Data/hPtProng1", "3-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/signal/hPtRecProng1Sig", "3-prong candidates (matched);prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/prompt/hPtRecProng1SigPrompt", "3-prong candidates (matched, prompt);prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"MC/reconstructed/nonprompt/hPtRecProng1SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"Data/hPtProng2", "3-prong candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, - {"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}}}}, - {"MC/reconstructed/prompt/hd0RecProng0SigPrompt", "3-prong candidates (matched, prompt);prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"MC/reconstructed/nonprompt/hd0RecProng0SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"Data/hd0Prong1", "3-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"MC/reconstructed/signal/hd0RecProng1Sig", "3-prong candidates (matched);prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"MC/reconstructed/prompt/hd0RecProng1SigPrompt", "3-prong candidates (matched, prompt);prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"MC/reconstructed/nonprompt/hd0RecProng1SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"Data/hd0Prong2", "3-prong candidates;prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"MC/reconstructed/signal/hd0RecProng2Sig", "3-prong candidates (matched);prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"MC/reconstructed/prompt/hd0RecProng2SigPrompt", "3-prong candidates (matched, prompt);prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - {"MC/reconstructed/nonprompt/hd0RecProng2SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, - /// decay length candidate - {"Data/hDecLength", "3-prong candidates;decay length (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, - {"MC/reconstructed/signal/hDecLengthRecSig", "3-prong candidates (matched);decay length (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, - {"MC/reconstructed/prompt/hDecLengthRecSigPrompt", "3-prong candidates (matched, prompt);decay length (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, - {"MC/reconstructed/nonprompt/hDecLengthRecSigNonPrompt", "3-prong candidates (matched, non-prompt);decay length (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, - /// decay length xy candidate - {"Data/hDecLengthxy", "3-prong candidates;decay length xy (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, - {"MC/reconstructed/signal/hDecLengthxyRecSig", "3-prong candidates (matched);decay length xy (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, - {"MC/reconstructed/prompt/hDecLengthxyRecSigPrompt", "3-prong candidates (matched, prompt);decay length xy (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, - {"MC/reconstructed/nonprompt/hDecLengthxyRecSigNonPrompt", "3-prong candidates (matched, non-prompt);decay length xy (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, - /// proper lifetime - {"Data/hCt", "3-prong candidates;proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH1F, {{100, 0., 0.2}}}}, - {"MC/reconstructed/signal/hCtRecSig", "3-prong candidates (matched);proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH1F, {{100, 0., 0.2}}}}, - {"MC/reconstructed/prompt/hCtRecSigPrompt", "3-prong candidates (matched, prompt);proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH1F, {{100, 0., 0.2}}}}, - {"MC/reconstructed/nonprompt/hCtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH1F, {{100, 0., 0.2}}}}, - /// cosine of pointing angle - {"Data/hCPA", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"MC/reconstructed/signal/hCPARecSig", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"MC/reconstructed/prompt/hCPARecSigPrompt", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"MC/reconstructed/nonprompt/hCPARecSigNonPrompt", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - /// cosine of pointing angle xy - {"Data/hCPAxy", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"MC/reconstructed/signal/hCPAxyRecSig", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"MC/reconstructed/prompt/hCPAxyRecSigPrompt", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - {"MC/reconstructed/nonprompt/hCPAxyRecSigNonPrompt", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, - /// Chi 2 PCA to sec. vertex - {"Data/hDca2", "3-prong candidates;prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH1F, {{400, 0., 20.}}}}, - {"MC/reconstructed/signal/hDca2RecSig", "3-prong candidates (matched);prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH1F, {{400, 0., 20.}}}}, - {"MC/reconstructed/prompt/hDca2RecSigPrompt", "3-prong candidates (matched);prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH1F, {{400, 0., 20.}}}}, - {"MC/reconstructed/nonprompt/hDca2RecSigNonPrompt", "3-prong candidates (matched);prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH1F, {{400, 0., 20.}}}}, - /// eta - {"Data/hEta", "3-prong candidates;#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/reconstructed/signal/hEtaRecSig", "3-prong candidates (matched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/reconstructed/prompt/hEtaRecSigPrompt", "3-prong candidates (matched, prompt);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/reconstructed/nonprompt/hEtaRecSigNonPrompt", "3-prong candidates (matched, non-prompt);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/generated/signal/hEtaGen", "MC particles (matched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/generated/prompt/hEtaGenPrompt", "MC particles (matched, prompt);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/generated/nonprompt/hEtaGenNonPrompt", "MC particles (matched, non-prompt);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/generated/signal/hYGen", "MC particles (matched);#it{y};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/generated/prompt/hYGenPrompt", "MC particles (matched, prompt);#it{y};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - {"MC/generated/nonprompt/hYGenNonPrompt", "MC particles (matched, non-prompt);#it{y};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, - /// phi - {"Data/hPhi", "3-prong candidates;#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}, - {"MC/reconstructed/signal/hPhiRecSig", "3-prong candidates (matched);#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}, - {"MC/reconstructed/prompt/hPhiRecSigPrompt", "3-prong candidates (matched, prompt);#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}, - {"MC/reconstructed/nonprompt/hPhiRecSigNonPrompt", "3-prong candidates (matched, non-prompt);#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}, - {"MC/generated/signal/hPhiGen", "MC particles (matched);#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}, - {"MC/generated/prompt/hPhiGenPrompt", "MC particles (matched, prompt);#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}, - {"MC/generated/nonprompt/hPhiGenNonPrompt", "MC particles (matched, non-prompt);#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}}}; + 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"}; + ConfigurableAxis thnConfigAxisProperLifetime{"thnConfigAxisProperLifetime", {200, 0, 2}, "Proper lifetime, ps"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (see TrueGap enum in o2::aod::sgselector)"}; + ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisZN{"thnConfigAxisZN", {510, -1.5, 49.5}, "axis for ZN energy (a.u.)"}; + HistogramRegistry registry{"registry", {}}; + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Factors for conversion between units + constexpr static float CtToProperLifetimePs = 1.f / o2::constants::physics::LightSpeedCm2PS; + constexpr static float NanoToPico = 1000.f; + // Names of folders and suffixes for MC signal histograms + constexpr static std::string_view SignalFolders[] = {"signal", "prompt", "nonprompt"}; + constexpr static std::string_view SignalSuffixes[] = {"", "Prompt", "NonPrompt"}; + + enum MlClasses : int { + MlClassBackground = 0, + MlClassPrompt, + MlClassNonPrompt, + NumberOfMlClasses + }; + + enum SignalClasses : int { + Signal = 0, + Prompt, + NonPrompt + }; void init(InitContext&) { - std::array doprocess{doprocessDataStd, doprocessDataWithMl, doprocessMcStd, doprocessMcWithMl}; + const std::array doprocess{doprocessDataStd, doprocessDataStdWithFT0C, doprocessDataStdWithFT0M, doprocessDataWithMl, doprocessDataWithMlWithFT0C, doprocessDataWithMlWithFT0M, doprocessDataWithMlWithUpc, doprocessMcStd, doprocessMcStdWithFT0C, doprocessMcStdWithFT0M, doprocessMcWithMl, doprocessMcWithMlWithFT0C, doprocessMcWithMlWithFT0M, doprocessDataStdWithUpc}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { LOGP(fatal, "no or more than one process function enabled! Please check your configuration!"); } + const bool isData = doprocessDataStd || doprocessDataStdWithFT0C || doprocessDataStdWithFT0M || doprocessDataWithMl || doprocessDataWithMlWithFT0C || doprocessDataWithMlWithFT0M || doprocessDataWithMlWithUpc; + const bool isUpc = doprocessDataWithMlWithUpc || doprocessDataStdWithUpc; + + auto addHistogramsRec = [&](const std::string& histoName, const std::string& xAxisTitle, const std::string& yAxisTitle, const HistogramConfigSpec& configSpec) { + if (isData) { + registry.add(("Data/" + histoName).c_str(), ("3-prong candidates;" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + } else { + registry.add(("MC/reconstructed/signal/" + histoName + "RecSig").c_str(), ("3-prong candidates (matched);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + registry.add(("MC/reconstructed/prompt/" + histoName + "RecSigPrompt").c_str(), ("3-prong candidates (matched, prompt);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + registry.add(("MC/reconstructed/nonprompt/" + histoName + "RecSigNonPrompt").c_str(), ("3-prong candidates (matched, non-prompt);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + } + }; + + auto addHistogramsGen = [&](const std::string& histoName, const std::string& xAxisTitle, const std::string& yAxisTitle, const HistogramConfigSpec& configSpec) { + if (!isData) { + registry.add(("MC/generated/signal/" + histoName + "Gen").c_str(), ("MC particles (matched);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + registry.add(("MC/generated/prompt/" + histoName + "GenPrompt").c_str(), ("MC particles (matched, prompt);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + registry.add(("MC/generated/nonprompt/" + histoName + "GenNonPrompt").c_str(), ("MC particles (matched, non-prompt);" + xAxisTitle + ";" + yAxisTitle).c_str(), configSpec); + } + }; + + /// mass candidate + addHistogramsRec("hMass", "inv. mass (p K #pi) (GeV/#it{c}^{2})", "", {HistType::kTH1F, {{600, 1.98, 2.58}}}); + /// pT + addHistogramsRec("hPt", "#it{p}_{T}^{rec.} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + addHistogramsGen("hPt", "#it{p}_{T}^{gen.} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + if (!isData) { + registry.add("MC/generated/signal/hPtGenSig", "3-prong candidates (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}); + } + addHistogramsRec("hPtProng0", "prong 0 #it{p}_{T} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + addHistogramsRec("hPtProng1", "prong 1 #it{p}_{T} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + addHistogramsRec("hPtProng2", "prong 2 #it{p}_{T} (GeV/#it{c})", "entries", {HistType::kTH1F, {{360, 0., 36.}}}); + /// DCAxy to prim. vertex prongs + addHistogramsRec("hd0Prong0", "prong 0 DCAxy to prim. vertex (cm)", "entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}); + addHistogramsRec("hd0Prong1", "prong 1 DCAxy to prim. vertex (cm)", "entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}); + addHistogramsRec("hd0Prong2", "prong 2 DCAxy to prim. vertex (cm)", "entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}); + /// decay length candidate + addHistogramsRec("hDecLength", "decay length (cm)", "entries", {HistType::kTH1F, {{400, 0., 1.}}}); + /// decay length xy candidate + addHistogramsRec("hDecLengthxy", "decay length xy (cm)", "entries", {HistType::kTH1F, {{400, 0., 1.}}}); + /// proper lifetime + addHistogramsRec("hCt", "proper lifetime (#Lambda_{c}) * #it{c} (cm)", "entries", {HistType::kTH1F, {{100, 0., 0.2}}}); + /// cosine of pointing angle + addHistogramsRec("hCPA", "cosine of pointing angle", "entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}); + /// cosine of pointing angle xy + addHistogramsRec("hCPAxy", "cosine of pointing angle xy", "entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}); + /// Chi 2 PCA to sec. vertex + addHistogramsRec("hDca2", "prong Chi2PCA to sec. vertex (cm)", "entries", {HistType::kTH1F, {{400, 0., 20.}}}); + /// eta + addHistogramsRec("hEta", "#it{#eta}", "entries", {HistType::kTH1F, {{100, -2., 2.}}}); + addHistogramsGen("hEta", "#it{#eta}", "entries", {HistType::kTH1F, {{100, -2., 2.}}}); + addHistogramsGen("hY", "#it{y}", "entries", {HistType::kTH1F, {{100, -2., 2.}}}); + /// phi + addHistogramsRec("hPhi", "#it{#Phi}", "entries", {HistType::kTH1F, {{100, 0., 6.3}}}); + addHistogramsGen("hPhi", "#it{#Phi}", "entries", {HistType::kTH1F, {{100, 0., 6.3}}}); + 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/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})"}}}); - 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, 1.98, 2.58}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + if (isData) { + 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.}}}); + } + addHistogramsRec("hMassVsPt", "inv. mass (p K #pi) (GeV/#it{c}^{2})", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{600, 1.98, 2.58}, {vbins}}}); /// DCAxy to prim. vertex prongs - registry.add("Data/hd0VsPtProng0", "3-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hd0VsPtRecProng0Sig", "3-prong candidates (matched);prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hd0VsPtRecProng0SigPrompt", "3-prong candidates (matched, prompt);prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hd0VsPtRecProng0SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/hd0VsPtProng1", "3-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hd0VsPtRecProng1Sig", "3-prong candidates (matched);prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hd0VsPtRecProng1SigPrompt", "3-prong candidates (matched, prompt);prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hd0VsPtRecProng1SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/hd0VsPtProng2", "3-prong candidates;prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hd0VsPtRecProng2Sig", "3-prong candidates (matched);prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hd0VsPtRecProng2SigPrompt", "3-prong candidates (matched, prompt);prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hd0VsPtRecProng2SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hd0VsPtProng0", "prong 0 DCAxy to prim. vertex (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins}}}); + addHistogramsRec("hd0VsPtProng1", "prong 1 DCAxy to prim. vertex (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins}}}); + addHistogramsRec("hd0VsPtProng2", "prong 2 DCAxy to prim. vertex (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{600, -0.4, 0.4}, {vbins}}}); /// decay length candidate - registry.add("Data/hDecLengthVsPt", "3-prong candidates;decay length (cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hDecLengthVsPtRecSig", "3-prong candidates (matched);decay length (cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hDecLengthVsPtRecSigPrompt", "3-prong candidates (matched, prompt);decay length (cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hDecLengthVsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);decay length (cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hDecLengthVsPt", "decay length (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 1.}, {vbins}}}); /// decay length xy candidate - registry.add("Data/hDecLengthxyVsPt", "3-prong candidates;decay length xy(cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hDecLengthxyVsPtRecSig", "3-prong candidates (matched);decay length xy(cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hDecLengthxyVsPtRecSigPrompt", "3-prong candidates (matched, prompt);decay length xy(cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hDecLengthxyVsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);decay length xy(cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hDecLengthxyVsPt", "decay length xy (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 1.}, {vbins}}}); /// proper lifetime - registry.add("Data/hCtVsPt", "3-prong candidates;proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH2F, {{100, 0., 0.2}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hCtVsPtRecSig", "3-prong candidates (matched);proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH2F, {{100, 0., 0.2}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hCtVsPtRecSigPrompt", "3-prong candidates (matched, prompt);proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH2F, {{100, 0., 0.2}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hCtVsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);proper lifetime (#Lambda_{c}) * #it{c} (cm);entries", {HistType::kTH2F, {{100, 0., 0.2}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hCtVsPt", "proper lifetime (#Lambda_{c}) * #it{c} (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 0.2}, {vbins}}}); /// cosine of pointing angle - registry.add("Data/hCPAVsPt", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hCPAVsPtRecSig", "3-prong candidates (matched);cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hCPAVsPtRecSigPrompt", "3-prong candidates (matched, prompt);cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hCPAVsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hCPAVsPt", "cosine of pointing angle", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins}}}); /// cosine of pointing angle xy - registry.add("Data/hCPAxyVsPt", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hCPAxyVsPtRecSig", "3-prong candidates (matched);cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hCPAxyVsPtRecSigPrompt", "3-prong candidates (matched, prompt);cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hCPAxyVsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hCPAxyVsPt", "cosine of pointing angle xy", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins}}}); /// Chi 2 PCA to sec. vertex - registry.add("Data/hDca2VsPt", "3-prong candidates;prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH2F, {{400, 0., 20.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hDca2VsPtRecSig", "3-prong candidates (matched);prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH2F, {{400, 0., 20.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hDca2VsPtRecSigPrompt", "3-prong candidates (matched, prompt);prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH2F, {{400, 0., 20.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hDca2VsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH2F, {{400, 0., 20.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hDca2VsPt", "prong Chi2PCA to sec. vertex (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 20.}, {vbins}}}); /// eta - registry.add("Data/hEtaVsPt", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {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})"}}}); + addHistogramsRec("hEtaVsPt", "candidate #it{#eta}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -2., 2.}, {vbins}}}); + addHistogramsGen("hEtaVsPt", "#it{#eta}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -2., 2.}, {vbins}}}); /// y - 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})"}}}); + addHistogramsGen("hYVsPt", "#it{y}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -2., 2.}, {vbins}}}); /// phi - registry.add("Data/hPhiVsPt", "3-prong candidates;candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hPhiVsPtRecSig", "3-prong candidates (matched);candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hPhiVsPtRecSigPrompt", "3-prong candidates (matched, prompt);candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hPhiVsPtRecSigNonPrompt", "3-prong candidates (matched, non-prompt);candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/generated/signal/hPhiVsPtGenSig", "3-prong candidates (matched);candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/generated/prompt/hPhiVsPtGenSigPrompt", "3-prong candidates (matched, prompt);candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/generated/nonprompt/hPhiVsPtGenSigNonPrompt", "3-prong candidates (matched, non-prompt);candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hPhiVsPt", "candidate #it{#Phi}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 6.3}, {vbins}}}); + addHistogramsGen("hPhiVsPt", "#it{#Phi}", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 6.3}, {vbins}}}); /// selection status registry.add("hSelectionStatus", "3-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); /// impact parameter error - registry.add("Data/hImpParErrProng0", "3-prong candidates;prong 0 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/hImpParErrProng1", "3-prong candidates;prong 1 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/hImpParErrProng2", "3-prong candidates;prong 2 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hImpParErrProng0Sig", "3-prong candidates (matched);prong 0 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hImpParErrProng0SigPrompt", "3-prong candidates (matched, prompt);prong 0 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hImpParErrProng0SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 0 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hImpParErrProng1Sig", "3-prong candidates (matched);prong 1 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hImpParErrProng1SigPrompt", "3-prong candidates (matched, prompt);prong 1 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hImpParErrProng1SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 1 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hImpParErrProng2Sig", "3-prong candidates (matched);prong 2 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/prompt/hImpParErrProng2SigPrompt", "3-prong candidates (matched, prompt);prong 2 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/nonprompt/hImpParErrProng2SigNonPrompt", "3-prong candidates (matched, non-prompt);prong 2 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); + addHistogramsRec("hImpParErrProng0VsPt", "prong 0 impact parameter error (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1., 1.}, {vbins}}}); + addHistogramsRec("hImpParErrProng1VsPt", "prong 1 impact parameter error (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1., 1.}, {vbins}}}); + addHistogramsRec("hImpParErrProng2VsPt", "prong 2 impact parameter error (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1., 1.}, {vbins}}}); /// decay length error - registry.add("Data/hDecLenErr", "3-prong candidates;decay length error (cm);entries", {HistType::kTH2F, {{100, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("MC/reconstructed/signal/hDecLenErrSig", "3-prong candidates (matched);decay length error (cm);entries", {HistType::kTH2F, {{100, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - 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})"}}}); + addHistogramsRec("hDecLenErrVsPt", "decay length error (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 1.}, {vbins}}}); - if (enableTHn) { + if (isUpc) { + qaRegistry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{1500, 0., 1500}, {1500, 0., 1500}}}); + qaRegistry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + qaRegistry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{7, -1.5, 5.5}}}); + } + 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,60 +282,356 @@ 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"}; + const AxisSpec thnAxisProperLifetime{thnConfigAxisProperLifetime, "T_{proper} (ps)"}; + const AxisSpec thnAxisGapType{thnConfigAxisGapType, "Gap type"}; + const AxisSpec thnAxisFT0A{thnConfigAxisFT0, "FT0-A amplitude"}; + const AxisSpec thnAxisFT0C{thnConfigAxisFT0, "FT0-C amplitude"}; + const AxisSpec thnAxisFV0A{thnConfigAxisFV0A, "FV0-A amplitude"}; + const AxisSpec thnAxisFDDA{thnConfigAxisFDD, "FDD-A amplitude"}; + const AxisSpec thnAxisFDDC{thnConfigAxisFDD, "FDD-C amplitude"}; + const AxisSpec thnAxisZNA{thnConfigAxisZN, "ZNA energy"}; + const AxisSpec thnAxisZNC{thnConfigAxisZN, "ZNC energy"}; + + bool const isDataWithMl = doprocessDataWithMl || doprocessDataWithMlWithFT0C || doprocessDataWithMlWithFT0M || doprocessDataWithMlWithUpc; + bool const isMcWithMl = doprocessMcWithMl || doprocessMcWithMlWithFT0C || doprocessMcWithMlWithFT0M; + bool const isDataStd = doprocessDataStd || doprocessDataStdWithFT0C || doprocessDataStdWithFT0M || doprocessDataStdWithUpc; + bool const isMcStd = doprocessMcStd || doprocessMcStdWithFT0C || doprocessMcStdWithFT0M; + + std::vector axesStd, axesWithBdt, axesGen, axesUpc, axesUpcWithBdt; + + if (isDataStd && !isUpc) { + axesStd = {thnAxisMass, thnAxisPt, thnAxisCentrality, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisTracklets}; + } + if (isDataStd && isUpc) { + axesUpc = {thnAxisMass, thnAxisPt, thnAxisRapidity, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisTracklets, thnAxisGapType, thnAxisFT0A, thnAxisFT0C, thnAxisFV0A, thnAxisFDDA, thnAxisFDDC, thnAxisZNA, thnAxisZNC}; + } + if (isMcStd) { + axesStd = {thnAxisMass, thnAxisPt, thnAxisCentrality, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisTracklets, thnAxisPtB, thnAxisCanType}; + } + if (isMcStd || isMcWithMl) { + axesGen = {thnAxisPt, thnAxisCentrality, thnAxisY, thnAxisTracklets, thnAxisPtB, thnAxisCanType}; + } + if (isDataWithMl && !isUpc) { + axesWithBdt = {thnAxisMass, thnAxisPt, thnAxisCentrality, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcPrompt, thnAxisBdtScoreLcNonPrompt, thnAxisTracklets}; + } + if (isDataWithMl && isUpc) { + axesUpcWithBdt = {thnAxisMass, thnAxisPt, thnAxisRapidity, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcPrompt, thnAxisBdtScoreLcNonPrompt, thnAxisTracklets, thnAxisGapType, thnAxisFT0A, thnAxisFT0C, thnAxisFV0A, thnAxisFDDA, thnAxisFDDC, thnAxisZNA, thnAxisZNC}; + } + if (isMcWithMl) { + axesWithBdt = {thnAxisMass, thnAxisPt, thnAxisCentrality, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcPrompt, thnAxisBdtScoreLcNonPrompt, thnAxisTracklets, thnAxisPtB, thnAxisCanType}; + } - if (doprocessDataWithMl || doprocessMcWithMl) { - registry.add("hnLcVarsWithBdt", "THn for Lambdac candidates with BDT scores", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisMultiplicity, thnAxisBdtScoreLcBkg, thnAxisBdtScoreLcPrompt, thnAxisBdtScoreLcNonPrompt, thnAxisCanType}); + if (storeOccupancy) { + for (const auto& axes : std::array*, 3>{&axesWithBdt, &axesStd, &axesGen}) { + if (!axes->empty()) { + axes->push_back(thnAxisOccupancy); + } + } + } + if (storeProperLifetime) { + for (const auto& axes : std::array*, 3>{&axesWithBdt, &axesStd, &axesGen}) { + if (!axes->empty()) { + axes->push_back(thnAxisProperLifetime); + } + } + } + if (isUpc) { + if (isDataStd) { + registry.add("hnLcUpcVars", "THn for Lambdac candidates for Data in UPC", HistType::kTHnSparseF, axesUpc); + } else if (isDataWithMl) { + registry.add("hnLcUpcVarsWithBdt", "THn for Lambdac candidates with BDT scores for data in UPC", HistType::kTHnSparseF, axesUpcWithBdt); + } + } else 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 Lambdac candidates", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisMultiplicity, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisCanType}); + 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); } } + + if (isUpc) { + hfEvSel.addHistograms(qaRegistry); // collision monitoring + } + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); } - template - void processData(aod::Collision const& collision, - CandType const& candidates, - aod::TracksWDca const& tracks) + /// Evaluate centrality/multiplicity percentile (centrality estimator is automatically selected based on the used table) + /// \param collision is collision + /// \return centrality/multiplicity percentile of the collision + template + float evaluateCentralityColl(const Coll& collision) { - int nTracks = 0; - if (collision.numContrib() > 1) { - for (const auto& track : tracks) { - if (std::abs(track.eta()) > 4.0) { - continue; + return o2::hf_centrality::getCentralityColl(collision); + } + + /// Helper function for filling MC reconstructed histograms for prompt, nonpromt and common (signal) + /// \param candidate is a reconstructed candidate + /// \tparam SignalType is an enum defining which histogram in which folder (signal, prompt or nonpromt) to fill + template + void fillHistogramsRecSig(CandidateType const& candidate) + { + const auto& mcParticleProng0 = candidate.template prong0_as().template mcParticle_as>(); + const auto pdgCodeProng0 = std::abs(mcParticleProng0.pdgCode()); + if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hMassRecSig") + HIST(SignalSuffixes[SignalType]), HfHelper::invMassLcToPKPi(candidate)); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hMassVsPtRecSig") + HIST(SignalSuffixes[SignalType]), HfHelper::invMassLcToPKPi(candidate), candidate.pt()); + } + if ((candidate.isSelLcToPiKP() >= selectionFlagLc) && pdgCodeProng0 == kPiPlus) { + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hMassRecSig") + HIST(SignalSuffixes[SignalType]), HfHelper::invMassLcToPiKP(candidate)); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hMassVsPtRecSig") + HIST(SignalSuffixes[SignalType]), HfHelper::invMassLcToPiKP(candidate), candidate.pt()); + } + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hPtProng0RecSig") + HIST(SignalSuffixes[SignalType]), candidate.ptProng0()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hPtProng1RecSig") + HIST(SignalSuffixes[SignalType]), candidate.ptProng1()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hPtProng2RecSig") + HIST(SignalSuffixes[SignalType]), candidate.ptProng2()); + + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hd0Prong0RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameter0()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hd0Prong1RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameter1()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hd0Prong2RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameter2()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hd0VsPtProng0RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameter0(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hd0VsPtProng1RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameter1(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hd0VsPtProng2RecSig") + HIST(SignalSuffixes[SignalType]), candidate.impactParameter2(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLengthRecSig") + HIST(SignalSuffixes[SignalType]), candidate.decayLength()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLengthVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.decayLength(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLengthxyRecSig") + HIST(SignalSuffixes[SignalType]), candidate.decayLengthXY()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLengthxyVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.decayLengthXY(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hCtRecSig") + HIST(SignalSuffixes[SignalType]), HfHelper::ctLc(candidate)); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hCtVsPtRecSig") + HIST(SignalSuffixes[SignalType]), HfHelper::ctLc(candidate), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hCPARecSig") + HIST(SignalSuffixes[SignalType]), candidate.cpa()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hCPAVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.cpa(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hCPAxyRecSig") + HIST(SignalSuffixes[SignalType]), candidate.cpaXY()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hCPAxyVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.cpaXY(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hDca2RecSig") + HIST(SignalSuffixes[SignalType]), candidate.chi2PCA()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hDca2VsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.chi2PCA(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaRecSig") + HIST(SignalSuffixes[SignalType]), candidate.eta()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.eta(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hPhiRecSig") + HIST(SignalSuffixes[SignalType]), candidate.phi()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hPhiVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.phi(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hImpParErrProng0VsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.errorImpactParameter0(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hImpParErrProng1VsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.errorImpactParameter1(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hImpParErrProng2VsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.errorImpactParameter2(), candidate.pt()); + registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hDecLenErrVsPtRecSig") + HIST(SignalSuffixes[SignalType]), candidate.errorDecayLength(), candidate.pt()); + } + + /// 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) + { + const auto thisCollId = collision.globalIndex(); + const auto& groupedLcCandidates = candidates.sliceBy(candLcPerCollision, thisCollId); + + for (const auto& candidate : groupedLcCandidates) { + /// Select Lc + if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + continue; + } + /// rapidity selection + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLc(candidate)) > yCandRecoMax) { + continue; + } + + if (std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + // Get the corresponding MC particle. + const auto& mcParticleProng0 = candidate.template prong0_as().template mcParticle_as>(); + const auto pdgCodeProng0 = std::abs(mcParticleProng0.pdgCode()); + const auto indexMother = RecoDecay::getMother(mcParticles, mcParticleProng0, o2::constants::physics::Pdg::kLambdaCPlus, true); + const auto particleMother = mcParticles.rawIteratorAt(indexMother); + registry.fill(HIST("MC/generated/signal/hPtGenSig"), particleMother.pt()); // gen. level pT + + const auto pt = candidate.pt(); + const auto ptProng0 = candidate.ptProng0(); + const auto ptProng1 = candidate.ptProng1(); + const auto ptProng2 = candidate.ptProng2(); + const auto decayLength = candidate.decayLength(); + const auto chi2PCA = candidate.chi2PCA(); + const auto cpa = candidate.cpa(); + const auto originType = candidate.originMcRec(); + const auto numPvContributors = collision.numContrib(); + const auto ptRecB = candidate.ptBhadMotherPart(); + + /// MC reconstructed signal + fillHistogramsRecSig(candidate); + + /// reconstructed signal prompt + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { + fillHistogramsRecSig(candidate); + /// reconstructed signal nonprompt + } else if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { + fillHistogramsRecSig(candidate); + } + + if (fillTHn) { + float const cent = evaluateCentralityColl(collision); + float occ{-1.}; + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } + double outputBkg(-1), outputPrompt(-1), outputFD(-1); + const float properLifetime = HfHelper::ctLc(candidate) * CtToProperLifetimePs; + + auto fillTHnRecSig = [&](bool isPKPi) { + const auto massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); + + std::vector valuesToFill; + if constexpr (FillMl) { + const auto& mlProb = isPKPi ? candidate.mlProbLcToPKPi() : candidate.mlProbLcToPiKP(); + if (mlProb.size() == NumberOfMlClasses) { + outputBkg = mlProb[MlClassBackground]; /// bkg score + outputPrompt = mlProb[MlClassPrompt]; /// prompt score + outputFD = mlProb[MlClassNonPrompt]; /// non-prompt score + } + /// Fill the ML outputScores and variables of candidate + valuesToFill.reserve(registry.get(HIST("hnLcVarsWithBdt"))->GetNdimensions()); + valuesToFill.insert(valuesToFill.end(), {massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast(numPvContributors), ptRecB, static_cast(originType)}); + } else { + valuesToFill.reserve(registry.get(HIST("hnLcVars"))->GetNdimensions()); + valuesToFill.insert(valuesToFill.end(), {massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast(numPvContributors), ptRecB, static_cast(originType)}); + } + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + valuesToFill.push_back(occ); + } + if (storeProperLifetime) { + valuesToFill.push_back(properLifetime); + } + if constexpr (FillMl) { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(valuesToFill.data()); + } else { + registry.get(HIST("hnLcVars"))->Fill(valuesToFill.data()); + } + }; + + if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { + fillTHnRecSig(true); + } + if ((candidate.isSelLcToPiKP() >= selectionFlagLc) && pdgCodeProng0 == kPiPlus) { + fillTHnRecSig(false); + } } - if (std::abs(track.dcaXY()) > 0.0025 || std::abs(track.dcaZ()) > 0.0025) { + } + } + } + + /// Helper function for filling MC generated histograms for prompt, nonpromt and common (signal) + /// \param particle is a generated particle + /// \tparam SignalType is an enum defining which histogram in which folder (signal, prompt or nonpromt) to fill + template + void fillHistogramsGen(ParticleType const& particle) + { + registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hPtGen") + HIST(SignalSuffixes[SignalType]), particle.pt()); + registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaGen") + HIST(SignalSuffixes[SignalType]), particle.eta()); + registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hYGen") + HIST(SignalSuffixes[SignalType]), RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus)); + registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hPhiGen") + HIST(SignalSuffixes[SignalType]), particle.phi()); + registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaVsPtGen") + HIST(SignalSuffixes[SignalType]), particle.eta(), particle.pt()); + registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hYVsPtGen") + HIST(SignalSuffixes[SignalType]), RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus), particle.pt()); + registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hPhiVsPtGen") + HIST(SignalSuffixes[SignalType]), particle.phi(), particle.pt()); + } + + /// Fill MC histograms at generated level + template + void fillHistosMcGen(CandLcMcGen const& mcParticles, Coll const& recoCollisions) + { + // MC gen. + for (const auto& particle : mcParticles) { + if (std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus); + if (yCandGenMax >= 0. && std::abs(yGen) > yCandGenMax) { continue; } - nTracks++; + const auto ptGen = particle.pt(); + const 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 const cent = o2::hf_centrality::getCentralityGenColl(recoCollsPerMcColl); + float occ{-1.}; + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyGenColl(recoCollsPerMcColl, occEstimator); + } + + const auto& mcDaughter0 = particle.template daughters_as>().begin(); + const float p2m = particle.p() / o2::constants::physics::MassLambdaCPlus; + const float gamma = std::sqrt(1 + p2m * p2m); // mother's particle Lorentz factor + const float properLifetime = mcDaughter0.vt() * NanoToPico / gamma; // from ns to ps * from lab time to proper time + + fillHistogramsGen(particle); + + auto fillTHnGen = [&](bool isPrompt) { + ptGenB = isPrompt ? -1. : mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + + if (fillTHn) { + std::vector valuesToFill{ptGen, cent, yGen, static_cast(numPvContributors), ptGenB, static_cast(originType)}; + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + valuesToFill.push_back(occ); + } + if (storeProperLifetime) { + valuesToFill.push_back(properLifetime); + } + registry.get(HIST("hnLcVarsGen"))->Fill(valuesToFill.data()); + } + }; + + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + fillTHnGen(true); + fillHistogramsGen(particle); + } else if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + fillTHnGen(false); + fillHistogramsGen(particle); + } } } - registry.fill(HIST("Data/hMultiplicity"), nTracks); + } + + /// Fill histograms for real data + /// \tparam FillMl switch to fill ML histograms + template + void fillHistosData(CollType const& collision, CandType const& candidates) + { + const auto thisCollId = collision.globalIndex(); + const auto& groupedLcCandidates = candidates.sliceBy(candLcPerCollision, thisCollId); + const auto numPvContributors = collision.numContrib(); - for (const auto& candidate : candidates) { + 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) { + 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(); + const auto pt = candidate.pt(); + const auto ptProng0 = candidate.ptProng0(); + const auto ptProng1 = candidate.ptProng1(); + const auto ptProng2 = candidate.ptProng2(); + const auto decayLength = candidate.decayLength(); + const auto decayLengthXY = candidate.decayLengthXY(); + const auto chi2PCA = candidate.chi2PCA(); + const auto cpa = candidate.cpa(); + const 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); + 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/hMassVsPtVsMult"), hfHelper.invMassLcToPiKP(candidate), pt, nTracks); - registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassLcToPiKP(candidate), pt); + 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); @@ -342,8 +647,8 @@ struct HfTaskLc { 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/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); @@ -356,317 +661,318 @@ struct HfTaskLc { 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); + registry.fill(HIST("Data/hImpParErrProng0VsPt"), candidate.errorImpactParameter0(), pt); + registry.fill(HIST("Data/hImpParErrProng1VsPt"), candidate.errorImpactParameter1(), pt); + registry.fill(HIST("Data/hImpParErrProng2VsPt"), candidate.errorImpactParameter2(), pt); + registry.fill(HIST("Data/hDecLenErrVsPt"), candidate.errorDecayLength(), pt); + + if (fillTHn) { + float const cent = evaluateCentralityColl(collision); + float occ{-1.}; + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } 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 + const float properLifetime = HfHelper::ctLc(candidate) * CtToProperLifetimePs; + + auto fillTHnData = [&](bool isPKPi) { + const auto massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); + + std::vector valuesToFill; + if constexpr (FillMl) { + const auto& mlProb = isPKPi ? candidate.mlProbLcToPKPi() : candidate.mlProbLcToPiKP(); + if (mlProb.size() == NumberOfMlClasses) { + outputBkg = mlProb[MlClassBackground]; /// bkg score + outputPrompt = mlProb[MlClassPrompt]; /// prompt score + outputFD = mlProb[MlClassNonPrompt]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate - registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, nTracks, outputBkg, outputPrompt, outputFD, 0); + valuesToFill.reserve(registry.get(HIST("hnLcVarsWithBdt"))->GetNdimensions()); + valuesToFill.insert(valuesToFill.end(), {massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast(numPvContributors)}); } else { - registry.get(HIST("hnLcVars"))->Fill(massLc, pt, nTracks, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, 0); + valuesToFill.reserve(registry.get(HIST("hnLcVars"))->GetNdimensions()); + valuesToFill.insert(valuesToFill.end(), {massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast(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 - registry.get(HIST("hnLcVarsWithBdt"))->Fill(massLc, pt, nTracks, outputBkg, outputPrompt, outputFD, 0); + if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { + valuesToFill.push_back(occ); + } + if (storeProperLifetime) { + valuesToFill.push_back(properLifetime); + } + if constexpr (FillMl) { + registry.get(HIST("hnLcVarsWithBdt"))->Fill(valuesToFill.data()); } else { - registry.get(HIST("hnLcVars"))->Fill(massLc, pt, nTracks, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, 0); + registry.get(HIST("hnLcVars"))->Fill(valuesToFill.data()); } + }; + + if (candidate.isSelLcToPKPi() >= selectionFlagLc) { + fillTHnData(true); + } + if (candidate.isSelLcToPiKP() >= selectionFlagLc) { + fillTHnData(false); } } } } - - void processDataStd(aod::Collision const& collision, - LcCandidates const& selectedLcCandidates, - aod::TracksWDca const& tracks) + /// Run the analysis on real data + /// \tparam FillMl switch to fill ML histograms + template + void runAnalysisPerCollisionData(CollType const& collisions, + CandType const& candidates) { - processData(collision, selectedLcCandidates, tracks); - } - PROCESS_SWITCH(HfTaskLc, processDataStd, "Process Data with the standard method", true); - void processDataWithMl(aod::Collision const& collision, - LcCandidatesMl const& selectedLcCandidatesMl, - aod::TracksWDca const& tracks) - { - processData(collision, selectedLcCandidatesMl, tracks); + for (const auto& collision : collisions) { + fillHistosData(collision, candidates); + } } - 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&) + template + void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, + CandType const& candidates, + BCsType const& bcs, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds + + ) { - for (const auto& candidate : candidates) { - /// Select Lc - if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + for (const auto& collision : collisions) { + float centrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, qaRegistry, bcs); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject the candidate continue; } - /// rapidity selection - if (yCandRecoMax >= 0. && std::abs(hfHelper.yLc(candidate)) > yCandRecoMax) { - continue; + const auto thisCollId = collision.globalIndex(); + const auto& groupedLcCandidates = candidates.sliceBy(candLcPerCollision, thisCollId); + const auto numPvContributors = collision.numContrib(); + const auto& bc = collision.template bc_as(); + + // Determine gap type using SGSelector with BC range checking + const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); + const int gap = gapResult.value; + + // Use the BC with FIT activity if available from SGSelector + auto bcForUPC = bc; + if (gapResult.bc) { + bcForUPC = *(gapResult.bc); } - if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { - // Get the corresponding MC particle. - auto mcParticleProng0 = candidate.template prong0_as().template mcParticle_as>(); - auto pdgCodeProng0 = std::abs(mcParticleProng0.pdgCode()); - auto indexMother = RecoDecay::getMother(mcParticles, mcParticleProng0, o2::constants::physics::Pdg::kLambdaCPlus, true); - auto particleMother = mcParticles.rawIteratorAt(indexMother); - registry.fill(HIST("MC/generated/signal/hPtGenSig"), particleMother.pt()); // gen. level pT - - 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(); - auto originType = candidate.originMcRec(); - /// MC reconstructed signal - if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { - registry.fill(HIST("MC/reconstructed/signal/hMassRecSig"), hfHelper.invMassLcToPKPi(candidate)); - registry.fill(HIST("MC/reconstructed/signal/hMassVsPtRecSig"), hfHelper.invMassLcToPKPi(candidate), pt); - } - if ((candidate.isSelLcToPiKP() >= selectionFlagLc) && pdgCodeProng0 == kPiPlus) { - registry.fill(HIST("MC/reconstructed/signal/hMassRecSig"), hfHelper.invMassLcToPiKP(candidate)); - registry.fill(HIST("MC/reconstructed/signal/hMassVsPtRecSig"), hfHelper.invMassLcToPiKP(candidate), pt); + // Get FIT information from the UPC BC + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bcForUPC, bcs, ft0s, fv0as, fdds); + + // Get ZDC energies if available (extract once and reuse) + const bool hasZdc = bcForUPC.has_zdc(); + float zdcEnergyZNA = -1.f; + float zdcEnergyZNC = -1.f; + + if (hasZdc) { + const auto zdc = bcForUPC.zdc(); + zdcEnergyZNA = zdc.energyCommonZNA(); + zdcEnergyZNC = zdc.energyCommonZNC(); + qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); + qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast(gap)); + } + for (const auto& candidate : groupedLcCandidates) { + if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + continue; } - registry.fill(HIST("MC/reconstructed/signal/hPtRecSig"), pt); - registry.fill(HIST("MC/reconstructed/signal/hPtRecProng0Sig"), ptProng0); - registry.fill(HIST("MC/reconstructed/signal/hPtRecProng1Sig"), ptProng1); - registry.fill(HIST("MC/reconstructed/signal/hPtRecProng2Sig"), ptProng2); - - registry.fill(HIST("MC/reconstructed/signal/hd0RecProng0Sig"), candidate.impactParameter0()); - registry.fill(HIST("MC/reconstructed/signal/hd0RecProng1Sig"), candidate.impactParameter1()); - registry.fill(HIST("MC/reconstructed/signal/hd0RecProng2Sig"), candidate.impactParameter2()); - registry.fill(HIST("MC/reconstructed/signal/hd0VsPtRecProng0Sig"), candidate.impactParameter0(), pt); - registry.fill(HIST("MC/reconstructed/signal/hd0VsPtRecProng1Sig"), candidate.impactParameter1(), pt); - registry.fill(HIST("MC/reconstructed/signal/hd0VsPtRecProng2Sig"), candidate.impactParameter2(), pt); - registry.fill(HIST("MC/reconstructed/signal/hDecLengthRecSig"), decayLength); - registry.fill(HIST("MC/reconstructed/signal/hDecLengthVsPtRecSig"), decayLength, pt); - registry.fill(HIST("MC/reconstructed/signal/hDecLengthxyRecSig"), decayLengthXY); - registry.fill(HIST("MC/reconstructed/signal/hDecLengthxyVsPtRecSig"), decayLengthXY, pt); - registry.fill(HIST("MC/reconstructed/signal/hCtRecSig"), hfHelper.ctLc(candidate)); - registry.fill(HIST("MC/reconstructed/signal/hCtVsPtRecSig"), hfHelper.ctLc(candidate), pt); - registry.fill(HIST("MC/reconstructed/signal/hCPARecSig"), cpa); - registry.fill(HIST("MC/reconstructed/signal/hCPAVsPtRecSig"), cpa, pt); - registry.fill(HIST("MC/reconstructed/signal/hCPAxyRecSig"), cpaXY); - registry.fill(HIST("MC/reconstructed/signal/hCPAxyVsPtRecSig"), cpaXY, pt); - registry.fill(HIST("MC/reconstructed/signal/hDca2RecSig"), chi2PCA); - registry.fill(HIST("MC/reconstructed/signal/hDca2VsPtRecSig"), chi2PCA, pt); - registry.fill(HIST("MC/reconstructed/signal/hEtaRecSig"), candidate.eta()); - registry.fill(HIST("MC/reconstructed/signal/hEtaVsPtRecSig"), candidate.eta(), pt); - registry.fill(HIST("MC/reconstructed/signal/hPhiRecSig"), candidate.phi()); - registry.fill(HIST("MC/reconstructed/signal/hPhiVsPtRecSig"), candidate.phi(), pt); - registry.fill(HIST("MC/reconstructed/signal/hImpParErrProng0Sig"), candidate.errorImpactParameter0(), pt); - registry.fill(HIST("MC/reconstructed/signal/hImpParErrProng1Sig"), candidate.errorImpactParameter1(), pt); - registry.fill(HIST("MC/reconstructed/signal/hImpParErrProng2Sig"), candidate.errorImpactParameter2(), pt); - registry.fill(HIST("MC/reconstructed/signal/hDecLenErrSig"), candidate.errorDecayLength(), pt); - - /// reconstructed signal prompt - if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { - if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { - registry.fill(HIST("MC/reconstructed/prompt/hMassRecSigPrompt"), hfHelper.invMassLcToPKPi(candidate)); - registry.fill(HIST("MC/reconstructed/prompt/hMassVsPtRecSigPrompt"), hfHelper.invMassLcToPKPi(candidate), pt); - } - if ((candidate.isSelLcToPiKP() >= selectionFlagLc) && pdgCodeProng0 == kPiPlus) { - registry.fill(HIST("MC/reconstructed/prompt/hMassRecSigPrompt"), hfHelper.invMassLcToPiKP(candidate)); - registry.fill(HIST("MC/reconstructed/prompt/hMassVsPtRecSigPrompt"), hfHelper.invMassLcToPiKP(candidate), pt); - } - registry.fill(HIST("MC/reconstructed/prompt/hPtRecSigPrompt"), pt); - registry.fill(HIST("MC/reconstructed/prompt/hPtRecProng0SigPrompt"), ptProng0); - registry.fill(HIST("MC/reconstructed/prompt/hPtRecProng1SigPrompt"), ptProng1); - registry.fill(HIST("MC/reconstructed/prompt/hPtRecProng2SigPrompt"), ptProng2); - registry.fill(HIST("MC/reconstructed/prompt/hd0RecProng0SigPrompt"), candidate.impactParameter0()); - registry.fill(HIST("MC/reconstructed/prompt/hd0RecProng1SigPrompt"), candidate.impactParameter1()); - registry.fill(HIST("MC/reconstructed/prompt/hd0RecProng2SigPrompt"), candidate.impactParameter2()); - registry.fill(HIST("MC/reconstructed/prompt/hd0VsPtRecProng0SigPrompt"), candidate.impactParameter0(), pt); - registry.fill(HIST("MC/reconstructed/prompt/hd0VsPtRecProng1SigPrompt"), candidate.impactParameter1(), pt); - registry.fill(HIST("MC/reconstructed/prompt/hd0VsPtRecProng2SigPrompt"), candidate.impactParameter2(), pt); - registry.fill(HIST("MC/reconstructed/prompt/hDecLengthRecSigPrompt"), decayLength); - registry.fill(HIST("MC/reconstructed/prompt/hDecLengthVsPtRecSigPrompt"), decayLength, pt); - registry.fill(HIST("MC/reconstructed/prompt/hDecLengthxyRecSigPrompt"), decayLengthXY); - registry.fill(HIST("MC/reconstructed/prompt/hDecLengthxyVsPtRecSigPrompt"), decayLengthXY, pt); - registry.fill(HIST("MC/reconstructed/prompt/hCtRecSigPrompt"), hfHelper.ctLc(candidate)); - registry.fill(HIST("MC/reconstructed/prompt/hCtVsPtRecSigPrompt"), hfHelper.ctLc(candidate), pt); - registry.fill(HIST("MC/reconstructed/prompt/hCPARecSigPrompt"), cpa); - registry.fill(HIST("MC/reconstructed/prompt/hCPAVsPtRecSigPrompt"), cpa, pt); - registry.fill(HIST("MC/reconstructed/prompt/hCPAxyRecSigPrompt"), cpaXY); - registry.fill(HIST("MC/reconstructed/prompt/hCPAxyVsPtRecSigPrompt"), cpaXY, pt); - registry.fill(HIST("MC/reconstructed/prompt/hDca2RecSigPrompt"), chi2PCA); - registry.fill(HIST("MC/reconstructed/prompt/hDca2VsPtRecSigPrompt"), chi2PCA, pt); - registry.fill(HIST("MC/reconstructed/prompt/hEtaRecSigPrompt"), candidate.eta()); - registry.fill(HIST("MC/reconstructed/prompt/hEtaVsPtRecSigPrompt"), candidate.eta(), pt); - registry.fill(HIST("MC/reconstructed/prompt/hPhiRecSigPrompt"), candidate.phi()); - registry.fill(HIST("MC/reconstructed/prompt/hPhiVsPtRecSigPrompt"), candidate.phi(), pt); - registry.fill(HIST("MC/reconstructed/prompt/hImpParErrProng0SigPrompt"), candidate.errorImpactParameter0(), pt); - registry.fill(HIST("MC/reconstructed/prompt/hImpParErrProng1SigPrompt"), candidate.errorImpactParameter1(), pt); - registry.fill(HIST("MC/reconstructed/prompt/hImpParErrProng2SigPrompt"), candidate.errorImpactParameter2(), pt); - registry.fill(HIST("MC/reconstructed/prompt/hDecLenErrSigPrompt"), candidate.errorDecayLength(), pt); - } else { - if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { - registry.fill(HIST("MC/reconstructed/nonprompt/hMassRecSigNonPrompt"), hfHelper.invMassLcToPKPi(candidate)); - registry.fill(HIST("MC/reconstructed/nonprompt/hMassVsPtRecSigNonPrompt"), hfHelper.invMassLcToPKPi(candidate), pt); - } - if ((candidate.isSelLcToPiKP() >= selectionFlagLc) && pdgCodeProng0 == kPiPlus) { - registry.fill(HIST("MC/reconstructed/nonprompt/hMassRecSigNonPrompt"), hfHelper.invMassLcToPiKP(candidate)); - registry.fill(HIST("MC/reconstructed/nonprompt/hMassVsPtRecSigNonPrompt"), hfHelper.invMassLcToPiKP(candidate), pt); - } - registry.fill(HIST("MC/reconstructed/nonprompt/hPtRecSigNonPrompt"), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hPtRecProng0SigNonPrompt"), ptProng0); - registry.fill(HIST("MC/reconstructed/nonprompt/hPtRecProng1SigNonPrompt"), ptProng1); - registry.fill(HIST("MC/reconstructed/nonprompt/hPtRecProng2SigNonPrompt"), ptProng2); - registry.fill(HIST("MC/reconstructed/nonprompt/hd0RecProng0SigNonPrompt"), candidate.impactParameter0()); - registry.fill(HIST("MC/reconstructed/nonprompt/hd0RecProng1SigNonPrompt"), candidate.impactParameter1()); - registry.fill(HIST("MC/reconstructed/nonprompt/hd0RecProng2SigNonPrompt"), candidate.impactParameter2()); - registry.fill(HIST("MC/reconstructed/nonprompt/hd0VsPtRecProng0SigNonPrompt"), candidate.impactParameter0(), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hd0VsPtRecProng1SigNonPrompt"), candidate.impactParameter1(), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hd0VsPtRecProng2SigNonPrompt"), candidate.impactParameter2(), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hDecLengthRecSigNonPrompt"), decayLength); - registry.fill(HIST("MC/reconstructed/nonprompt/hDecLengthVsPtRecSigNonPrompt"), decayLength, pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hDecLengthxyRecSigNonPrompt"), decayLengthXY); - registry.fill(HIST("MC/reconstructed/nonprompt/hDecLengthxyVsPtRecSigNonPrompt"), decayLengthXY, pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hCtRecSigNonPrompt"), hfHelper.ctLc(candidate)); - registry.fill(HIST("MC/reconstructed/nonprompt/hCtVsPtRecSigNonPrompt"), hfHelper.ctLc(candidate), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hCPARecSigNonPrompt"), cpa); - registry.fill(HIST("MC/reconstructed/nonprompt/hCPAVsPtRecSigNonPrompt"), cpa, pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hCPAxyRecSigNonPrompt"), cpaXY); - registry.fill(HIST("MC/reconstructed/nonprompt/hCPAxyVsPtRecSigNonPrompt"), cpaXY, pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hDca2RecSigNonPrompt"), chi2PCA); - registry.fill(HIST("MC/reconstructed/nonprompt/hDca2VsPtRecSigNonPrompt"), chi2PCA, pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hEtaRecSigNonPrompt"), candidate.eta()); - registry.fill(HIST("MC/reconstructed/nonprompt/hEtaVsPtRecSigNonPrompt"), candidate.eta(), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hPhiRecSigNonPrompt"), candidate.phi()); - registry.fill(HIST("MC/reconstructed/nonprompt/hPhiVsPtRecSigNonPrompt"), candidate.phi(), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hImpParErrProng0SigNonPrompt"), candidate.errorImpactParameter0(), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hImpParErrProng1SigNonPrompt"), candidate.errorImpactParameter1(), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hImpParErrProng2SigNonPrompt"), candidate.errorImpactParameter2(), pt); - registry.fill(HIST("MC/reconstructed/nonprompt/hDecLenErrSigNonPrompt"), candidate.errorDecayLength(), pt); + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLc(candidate)) > yCandRecoMax) { + continue; } - if (enableTHn) { - double massLc(-1); + const auto pt = candidate.pt(); + const auto ptProng0 = candidate.ptProng0(); + const auto ptProng1 = candidate.ptProng1(); + const auto ptProng2 = candidate.ptProng2(); + const auto decayLength = candidate.decayLength(); + const auto chi2PCA = candidate.chi2PCA(); + const auto cpa = candidate.cpa(); + const auto rapidity = std::abs(HfHelper::yLc(candidate)); + + if (fillTHn) { double outputBkg(-1), outputPrompt(-1), outputFD(-1); - if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { - massLc = hfHelper.invMassLcToPKPi(candidate); - if constexpr (fillMl) { + auto fillTHnData = [&](bool isPKPi) { + const auto massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); - if (candidate.mlProbLcToPKPi().size() == 3) { - - outputBkg = candidate.mlProbLcToPKPi()[0]; /// bkg score - outputPrompt = candidate.mlProbLcToPKPi()[1]; /// prompt score - outputFD = candidate.mlProbLcToPKPi()[2]; /// non-prompt score + if constexpr (FillMl) { + const auto& mlProb = isPKPi ? candidate.mlProbLcToPKPi() : candidate.mlProbLcToPiKP(); + if (mlProb.size() == NumberOfMlClasses) { + outputBkg = mlProb[MlClassBackground]; /// bkg score + outputPrompt = mlProb[MlClassPrompt]; /// prompt score + outputFD = mlProb[MlClassNonPrompt]; /// 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 + std::vector valuesToFill{massLc, pt, rapidity, outputBkg, outputPrompt, outputFD, static_cast(numPvContributors), static_cast(gap), static_cast(fitInfo.ampFT0A), static_cast(fitInfo.ampFT0C), static_cast(fitInfo.ampFV0A), static_cast(fitInfo.ampFDDA), static_cast(fitInfo.ampFDDC), static_cast(zdcEnergyZNA), static_cast(zdcEnergyZNC)}; + registry.get(HIST("hnLcUpcVarsWithBdt"))->Fill(valuesToFill.data()); } else { - registry.get(HIST("hnLcVars"))->Fill(massLc, pt, 0, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, originType); + std::vector valuesToFill{massLc, pt, rapidity, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast(numPvContributors), static_cast(gap), static_cast(fitInfo.ampFT0A), static_cast(fitInfo.ampFT0C), static_cast(fitInfo.ampFV0A), static_cast(fitInfo.ampFDDA), static_cast(fitInfo.ampFDDC), static_cast(zdcEnergyZNA), static_cast(zdcEnergyZNC)}; + registry.get(HIST("hnLcUpcVars"))->Fill(valuesToFill.data()); } - } - 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); - } else { - registry.get(HIST("hnLcVars"))->Fill(massLc, pt, 0, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, originType); - } + if (candidate.isSelLcToPKPi() >= selectionFlagLc) { + fillTHnData(true); + } + if (candidate.isSelLcToPiKP() >= selectionFlagLc) { + fillTHnData(false); } } } } + } + /// 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. - for (const auto& particle : mcParticles) { - if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { - auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus); - if (yCandGenMax >= 0. && std::abs(yGen) > yCandGenMax) { - continue; - } - 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/hPhiGen"), particle.phi()); - registry.fill(HIST("MC/generated/signal/hEtaVsPtGenSig"), particle.eta(), ptGen); - registry.fill(HIST("MC/generated/signal/hYVsPtGenSig"), yGen, ptGen); - registry.fill(HIST("MC/generated/signal/hPhiVsPtGenSig"), particle.phi(), ptGen); + fillHistosMcGen(mcParticles, collisions); + } - 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/hPhiGenPrompt"), particle.phi()); - registry.fill(HIST("MC/generated/prompt/hEtaVsPtGenSigPrompt"), particle.eta(), ptGen); - registry.fill(HIST("MC/generated/prompt/hYVsPtGenSigPrompt"), yGen, ptGen); - registry.fill(HIST("MC/generated/prompt/hPhiVsPtGenSigPrompt"), particle.phi(), ptGen); - } - 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/hPhiGenNonPrompt"), particle.phi()); - registry.fill(HIST("MC/generated/nonprompt/hEtaVsPtGenSigNonPrompt"), particle.eta(), ptGen); - registry.fill(HIST("MC/generated/nonprompt/hYVsPtGenSigNonPrompt"), yGen, ptGen); - registry.fill(HIST("MC/generated/nonprompt/hPhiVsPtGenSigNonPrompt"), particle.phi(), ptGen); - } - } - } + 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 processMcStd(LcCandidatesMc const& selectedLcCandidatesMc, - soa::Join const& mcParticles, - aod::TracksWMc const& tracksWithMc) + void processDataWithMlWithFT0C(CollisionsWithFT0C const& collisions, + LcCandidatesMl const& selectedLcCandidatesMl, + aod::Tracks const&) { - processMc(selectedLcCandidatesMc, mcParticles, tracksWithMc); + 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 processDataWithMlWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + LcCandidatesMl const& selectedLcCandidatesMl, + aod::Tracks const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedLcCandidatesMl, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskLc, processDataWithMlWithUpc, "Process real data with the ML method with UPC", false); + + void processDataStdWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + LcCandidatesMl const& selectedLcCandidatesMl, + aod::Tracks const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedLcCandidatesMl, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskLc, processDataStdWithUpc, "Process real data with the standard method with UPC", 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..78fd2c5174a 100644 --- a/PWGHF/D2H/Tasks/taskLcToK0sP.cxx +++ b/PWGHF/D2H/Tasks/taskLcToK0sP.cxx @@ -17,14 +17,27 @@ /// /// \note based on taskD0.cxx, taskLc.cxx -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::framework; @@ -35,38 +48,38 @@ struct HfTaskLcToK0sP { Configurable selectionFlagLcToK0sP{"selectionFlagLcToK0sP", 1, "Selection Flag for Lc"}; Configurable selectionFlagLcbarToK0sP{"selectionFlagLcbarToK0sP", 1, "Selection Flag for Lcbar"}; Configurable etaCandMax{"etaCandMax", -1., "max. cand. pseudorapidity"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_k0s_p::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; + using TracksWPid = soa::Join; Filter filterSelectCandidates = (aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= selectionFlagLcToK0sP || aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= selectionFlagLcbarToK0sP); - using TracksWPid = soa::Join; - HistogramRegistry registry{"registry"}; void init(InitContext& context) { // 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})"}; + AxisSpec const axisBinsPt = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisPt = {300, 0.0f, 30.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisEta = {500, -2.0f, 2.0f, "#it{#eta}"}; + AxisSpec const axisPhi = {100, 0.f, 6.3f, "#it{#phi}"}; + AxisSpec const axisMassCand = {600, 1.98f, 2.58f, "inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec const axisd0 = {500, -0.5f, 0.5f, "DCAxy (cm)"}; + AxisSpec const axisd0V0Daughters = {1000, -5.0f, 5.0f, "DCAxy (cm)"}; + AxisSpec const axisV0CPA = {500, 0.98f, 1.0001f, "v0 cos pointing angle"}; + AxisSpec const axisV0Radius = {1000, 0.f, 40.f, "V0 radius (cm)"}; + AxisSpec const axisV0DCADaughters = {200, 0.f, 2.f, "DCA (cm)"}; + AxisSpec const axisMassK0Short = {500, 0.4f, 0.6f, "#it{m}(K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec const axisMassLambda = {500, 1.0f, 1.2f, "#it{m}(#Lambda) (GeV/#it{c}^{2})"}; + AxisSpec const axisMassGamma = {500, 0.0f, 0.4f, "#it{m}(#gamma) (GeV/#it{c}^{2})"}; + AxisSpec const axisCPACand = {110, -1.1f, 1.1f, "candiate cos pointing angle"}; + AxisSpec const axisDecLength = {200, 0.f, 2.0f, "decay length (cm)"}; + AxisSpec const axisProperLifetime = {100, 0.f, 0.2f, "#it{c#tau} (cm)"}; + AxisSpec const axisProperLifetimeV0 = {1000, 0.f, 80.f, "#it{c#tau} (cm)"}; + AxisSpec const axisNSigma = {100, -6.f, 6.f, "n#it{#sigma}_{p}"}; + AxisSpec const axisPidP = {100, 0.f, 10.0f, "#it{p} (GeV/#it{c})"}; // data registry.add("hPtCand", "cascade candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); registry.add("hEtaCand", "cascade candidates;candidate #it{#eta};entries", {HistType::kTH1F, {axisEta}}); @@ -127,6 +140,8 @@ struct HfTaskLcToK0sP { // add MC histograms if (context.mOptions.get("processMc")) { registry.add("MC/Rec/hPtCandRecSig", "cascade candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("MC/Rec/hPtCandRecSigPrompt", "cascade candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("MC/Rec/hPtCandRecSigNonPrompt", "cascade candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); registry.add("MC/Rec/hPtCandRecBg", "cascade candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); registry.add("MC/Rec/hEtaCandRecSig", "cascade candidates;candidate #it{#eta};entries", {HistType::kTH1F, {axisEta}}); registry.add("MC/Rec/hEtaCandVsPtCandRecSig", "cascade candidates;candidate #it{#eta};p_{T}", {HistType::kTH2F, {axisEta, axisBinsPt}}); @@ -137,6 +152,8 @@ struct HfTaskLcToK0sP { registry.add("MC/Rec/hPhiCandRecBg", "cascade candidates;candidate #it{#phi};entries", {HistType::kTH1F, {axisPhi}}); registry.add("MC/Rec/hPhiCandVsPtCandRecBg", "cascade candidates;candidate #it{#phi};p_{T}", {HistType::kTH2F, {axisPhi, axisBinsPt}}); registry.add("MC/Gen/hPtCandGen", "cascade candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("MC/Gen/hPtCandGenPrompt", "cascade candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("MC/Gen/hPtCandGenNonPrompt", "cascade candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); registry.add("MC/Gen/hEtaCandGen", "cascade candidates;candidate #it{#eta};entries", {HistType::kTH1F, {axisEta}}); registry.add("MC/Gen/hEtaCandVsPtCandGen", "cascade candidates;candidate #it{#eta};p_{T}", {HistType::kTH2F, {axisEta, axisBinsPt}}); registry.add("MC/Gen/hPhiCandGen", "cascade candidates;candidate #it{#phi};entries", {HistType::kTH1F, {axisPhi}}); @@ -248,21 +265,17 @@ struct HfTaskLcToK0sP { TracksWPid const&) { for (const auto& candidate : candidates) { - /* - // no such selection for LcK0sp for now - it is the only cascade - if (!(candidate.hfflag() & 1 << D0ToPiK)) { + if (etaCandMax >= 0. && std::abs(candidate.eta()) > etaCandMax) { continue; } - */ - - if (etaCandMax >= 0. && std::abs(candidate.eta()) > etaCandMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLc(candidate)) > yCandRecoMax) { continue; } auto ptCand = candidate.pt(); auto eta = candidate.eta(); auto phi = candidate.phi(); - auto invMassLcToK0sP = hfHelper.invMassLcToK0sP(candidate); + auto invMassLcToK0sP = HfHelper::invMassLcToK0sP(candidate); auto ptProng0 = candidate.ptProng0(); auto ptProng1 = candidate.ptProng1(); auto impactParameter0 = candidate.impactParameter0(); @@ -278,13 +291,13 @@ struct HfTaskLcToK0sP { auto mLambda = candidate.mLambda(); auto mAntiLambda = candidate.mAntiLambda(); auto mGamma = candidate.mGamma(); - auto ctV0K0Short = hfHelper.ctV0K0s(candidate); - auto ctV0Lambda = hfHelper.ctV0Lambda(candidate); + auto ctV0K0Short = HfHelper::ctV0K0s(candidate); + auto ctV0Lambda = HfHelper::ctV0Lambda(candidate); auto cpa = candidate.cpa(); auto cpaXY = candidate.cpaXY(); auto decayLength = candidate.decayLength(); auto decayLengthXY = candidate.decayLengthXY(); - auto ctLc = hfHelper.ctLc(candidate); + auto ctLc = HfHelper::ctLc(candidate); registry.fill(HIST("hPtCand"), ptCand); registry.fill(HIST("hEtaCand"), eta); @@ -362,10 +375,14 @@ struct HfTaskLcToK0sP { continue; } + if (yCandRecoMax >= 0. && std::abs(HfHelper::yLc(candidate)) > yCandRecoMax) { + continue; + } + auto ptCand = candidate.pt(); auto eta = candidate.eta(); auto phi = candidate.phi(); - auto invMassLcToK0sP = hfHelper.invMassLcToK0sP(candidate); + auto invMassLcToK0sP = HfHelper::invMassLcToK0sP(candidate); auto ptProng0 = candidate.ptProng0(); auto ptProng1 = candidate.ptProng1(); auto impactParameter0 = candidate.impactParameter0(); @@ -381,19 +398,24 @@ struct HfTaskLcToK0sP { auto mLambda = candidate.mLambda(); auto mAntiLambda = candidate.mAntiLambda(); auto mGamma = candidate.mGamma(); - auto ctV0K0Short = hfHelper.ctV0K0s(candidate); - auto ctV0Lambda = hfHelper.ctV0Lambda(candidate); + auto ctV0K0Short = HfHelper::ctV0K0s(candidate); + auto ctV0Lambda = HfHelper::ctV0Lambda(candidate); auto cpa = candidate.cpa(); auto cpaXY = candidate.cpaXY(); auto decayLength = candidate.decayLength(); auto decayLengthXY = candidate.decayLengthXY(); - auto ctLc = hfHelper.ctLc(candidate); + auto ctLc = HfHelper::ctLc(candidate); const auto& bach = candidate.prong0_as(); // bachelor track auto tpcNSigmaPr = bach.tpcNSigmaPr(); auto pBach = bach.p(); if (std::abs(candidate.flagMcMatchRec()) == 1) { + if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("MC/Rec/hPtCandRecSigPrompt"), ptCand); + } else if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("MC/Rec/hPtCandRecSigNonPrompt"), ptCand); + } registry.fill(HIST("MC/Rec/hPtCandRecSig"), ptCand); registry.fill(HIST("MC/Rec/hEtaCandRecSig"), eta); registry.fill(HIST("MC/Rec/hEtaCandVsPtCandRecSig"), eta, ptCand); @@ -520,6 +542,11 @@ struct HfTaskLcToK0sP { } if (std::abs(particle.flagMcMatchGen()) == 1) { + + auto yGen = RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus); + if (yCandGenMax >= 0. && std::abs(yGen) > yCandGenMax) { + continue; + } auto ptCand = particle.pt(); auto eta = particle.eta(); auto phi = particle.phi(); @@ -528,6 +555,12 @@ struct HfTaskLcToK0sP { registry.fill(HIST("MC/Gen/hEtaCandVsPtCandGen"), eta, ptCand); registry.fill(HIST("MC/Gen/hPhiCandGen"), phi); registry.fill(HIST("MC/Gen/hPhiCandVsPtCandGen"), phi, ptCand); + + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("MC/Gen/hPtCandGenPrompt"), ptCand); + } else if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("MC/Gen/hPtCandGenNonPrompt"), ptCand); + } } } } diff --git a/PWGHF/D2H/Tasks/taskOmegac0ToOmegaPi.cxx b/PWGHF/D2H/Tasks/taskOmegac0ToOmegaPi.cxx new file mode 100644 index 00000000000..ec9bfc9820c --- /dev/null +++ b/PWGHF/D2H/Tasks/taskOmegac0ToOmegaPi.cxx @@ -0,0 +1,403 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace ml +{ +DECLARE_SOA_COLUMN(InvMassCharmBaryon, invMassCharmBaryon, float); +DECLARE_SOA_COLUMN(KfptOmegac, kfptOmegac, float); +DECLARE_SOA_COLUMN(KfptPiFromOmegac, kfptPiFromOmegac, float); +DECLARE_SOA_COLUMN(MlProbOmegac, mlProbOmegac, float); +DECLARE_SOA_COLUMN(Cent, cent, float); +} // namespace ml +DECLARE_SOA_TABLE(HfKfOmegacML, "AOD", "HFKFOMEGACML", + ml::InvMassCharmBaryon, ml::KfptOmegac, ml::KfptPiFromOmegac, ml::MlProbOmegac, ml::Cent); +} // namespace o2::aod + +/// Omegac0 analysis task +struct HfTaskOmegac0ToOmegaPi { + Produces kfCandMl; + + Configurable selectionFlagOmegac0{"selectionFlagOmegac0", true, "Select Omegac0 candidates"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "Max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "Max. cand. rapidity"}; + Configurable fillTree{"fillTree", false, "Fill tree for local analysis (enabled only with ML)"}; + + SliceCache cache; + + 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 CollisionsWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + using CollisionsWithMcLabels = soa::Join; + + using McCollisionsWithFT0M = 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)); + + Preslice candOmegacKFPerCollision = aod::hf_cand_xic0_omegac0::collisionId; + Preslice candOmegacKFMlPerCollision = aod::hf_cand_xic0_omegac0::collisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {700, 2.4, 3.1}, "Cand. inv. mass"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {500, 0, 50}, "Cand. pT"}; + ConfigurableAxis thnConfigAxisPtB{"thnConfigAxisPtB", {500, 0, 50}, "Cand. beauty mother pT"}; + ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {20, -1, 1}, "Cand. rapidity"}; + ConfigurableAxis thnConfigAxisOrigin{"thnConfigAxisOrigin", {3, -0.5, 2.5}, "Cand. origin"}; + ConfigurableAxis thnConfigAxisMatchFlag{"thnConfigAxisMatchFlag", {15, -7.5, 7.5}, "Cand. MC match flag"}; + ConfigurableAxis thnConfigAxisNumPvContr{"thnConfigAxisNumPvContr", {200, -0.5, 199.5}, "Coll. num. PV contributors"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {100, 0, 100}, "Coll. centrality precentile"}; + ConfigurableAxis thnConfigAxisPromptScore{"thnConfigAxisPromptScore", {100, 0, 1}, "Prompt score"}; + HistogramRegistry registry{"registry", {}}; + + void init(InitContext&) + { + std::array doprocess{doprocessDataKFParticle, doprocessDataKFParticleMl, doprocessDataKFParticleFT0C, doprocessDataKFParticleMlFT0C, + doprocessDataKFParticleFT0M, doprocessDataKFParticleMlFT0M, doprocessMcKFParticle, doprocessMcKFParticleMl, + doprocessMcKFParticleFT0M, doprocessMcKFParticleMlFT0M}; + 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, "MC match flag"}; + const AxisSpec thnAxisNumPvContr{thnConfigAxisNumPvContr, "Number of primary vtx. contributors"}; + const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality percentile"}; + const AxisSpec thnAxisCentMc{thnConfigAxisCent, "Centrality percentile (from gen. MC info)"}; + const AxisSpec thnAxisPromptScore{thnConfigAxisPromptScore, "BDT score prompt"}; + + std::vector axes = {thnAxisMass, thnAxisPt, thnAxisY}; + std::vector axesMcGen = {thnAxisPt, thnAxisPtB, thnAxisY, thnAxisOrigin}; + + if (doprocessDataKFParticleFT0C || doprocessDataKFParticleMlFT0C || doprocessDataKFParticleFT0M || doprocessDataKFParticleMlFT0M) { + axes.push_back(thnAxisCent); + axes.emplace_back(thnConfigAxisNumPvContr); + } + + if (doprocessMcKFParticleFT0M || doprocessMcKFParticleMlFT0M) { + axes.push_back(thnAxisCentMc); + axes.emplace_back(thnConfigAxisNumPvContr); + axesMcGen.push_back(thnAxisCentMc); + axesMcGen.emplace_back(thnConfigAxisNumPvContr); + } + + if (doprocessMcKFParticle || doprocessMcKFParticleMl || doprocessMcKFParticleFT0M || doprocessMcKFParticleMlFT0M) { + registry.add("hMcGen", "Gen. #Omega_{c}^{0} from charm and beauty", HistType::kTHnSparseD, axesMcGen); + registry.get(HIST("hMcGen"))->Sumw2(); + + if (doprocessMcKFParticleFT0M || doprocessMcKFParticleMlFT0M) { + registry.add("hMcGenWithRecoColl", "Gen. #Omega_{c}^{0} from charm and beauty (associated to a reco collision)", HistType::kTHnSparseD, axesMcGen); + registry.add("hNumRecoCollPerMcColl", "Number of reco collisions associated to a mc collision;Num. reco. coll. per Mc coll.;", {HistType::kTH1D, {{10, -0.5, 9.5}}}); + registry.get(HIST("hMcGenWithRecoColl"))->Sumw2(); + } + + axes.push_back(thnAxisPtB); + axes.push_back(thnAxisOrigin); + axes.push_back(thnAxisMatchFlag); + } + + if (doprocessDataKFParticleMl || doprocessDataKFParticleMlFT0C || doprocessDataKFParticleMlFT0M || doprocessMcKFParticleMl || doprocessMcKFParticleMlFT0M) { + axes.push_back(thnAxisPromptScore); + } + + registry.add("hReco", "Reco. #Omega_{c}^{0} candidates", HistType::kTHnSparseD, axes); + registry.get(HIST("hReco"))->Sumw2(); + } + + template + void processData(const CandType& candidates) + { + 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("hReco"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), candidate.mlProbOmegac()[0]); + } else { + registry.fill(HIST("hReco"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac()); + } + } + } + + template + void processDataCent(const CandType& candidates, CollType const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedOmegacCandidates = ApplyMl ? candidates.sliceBy(candOmegacKFMlPerCollision, thisCollId) : candidates.sliceBy(candOmegacKFPerCollision, thisCollId); + auto numPvContributors = collision.numContrib(); + + for (const auto& candidate : groupedOmegacCandidates) { + if (!(candidate.resultSelections() == true || (candidate.resultSelections() == false && !selectionFlagOmegac0))) { + continue; + } + + if (yCandRecoMax >= 0. && std::abs(candidate.kfRapOmegac()) > yCandRecoMax) { + continue; + } + + float const cent = o2::hf_centrality::getCentralityColl(collision); + + if constexpr (ApplyMl) { + registry.fill(HIST("hReco"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), + cent, numPvContributors, candidate.mlProbOmegac()[0]); + if (fillTree) { + kfCandMl(candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfptPiFromOmegac(), candidate.mlProbOmegac()[0], cent); + } + } else { + registry.fill(HIST("hReco"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), + cent, numPvContributors); + } + } + } + } + + template + void processMc(const CandType& candidates, Omegac0Gen const& mcParticles) + { + // 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; + } + + if constexpr (ApplyMl) { + registry.fill(HIST("hReco"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), candidate.ptBhadMotherPart(), candidate.originMcRec(), candidate.flagMcMatchRec(), candidate.mlProbOmegac()[0]); + + } else { + registry.fill(HIST("hReco"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), candidate.ptBhadMotherPart(), candidate.originMcRec(), candidate.flagMcMatchRec()); + } + } + + // MC gen. + for (const auto& particle : mcParticles) { + if (yCandGenMax >= 0. && std::abs(particle.rapidityCharmBaryonGen()) > yCandGenMax) { + continue; + } + + auto ptGen = particle.pt(); + auto yGen = particle.rapidityCharmBaryonGen(); + + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hMcGen"), ptGen, -1., yGen, RecoDecay::OriginType::Prompt); + } else { + float const ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("hMcGen"), ptGen, ptGenB, yGen, RecoDecay::OriginType::NonPrompt); + } + } + } + + template + void processMcCent(const CandType& candidates, Omegac0Gen const& mcParticles, + CollisionsWithMcLabels const& collisions, McCollisionWithCents 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 collision = candidate.template collision_as(); + uint16_t const numPvContributors = collision.numContrib(); + float const mcCent = o2::hf_centrality::getCentralityColl(collision.template mcCollision_as()); + + if constexpr (ApplyMl) { + registry.fill(HIST("hReco"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), mcCent, numPvContributors, candidate.ptBhadMotherPart(), candidate.originMcRec(), candidate.flagMcMatchRec(), candidate.mlProbOmegac()[0]); + + } else { + registry.fill(HIST("hReco"), candidate.invMassCharmBaryon(), candidate.ptCharmBaryon(), candidate.kfRapOmegac(), mcCent, numPvContributors, candidate.ptBhadMotherPart(), candidate.originMcRec(), candidate.flagMcMatchRec()); + } + } + + // MC gen. + for (const auto& particle : mcParticles) { + if (yCandGenMax >= 0. && std::abs(particle.rapidityCharmBaryonGen()) > yCandGenMax) { + continue; + } + + auto ptGen = particle.pt(); + auto yGen = particle.rapidityCharmBaryonGen(); + auto mcCollision = particle.template mcCollision_as(); + + int maxNumContrib = 0; + const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + for (const auto& recCol : recoCollsPerMcColl) { + maxNumContrib = recCol.numContrib() > maxNumContrib ? recCol.numContrib() : maxNumContrib; + } + + float const mcCent = o2::hf_centrality::getCentralityColl(mcCollision); + + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hMcGen"), ptGen, -1., yGen, RecoDecay::OriginType::Prompt, mcCent, maxNumContrib); + } else { + float const ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("hMcGen"), ptGen, ptGenB, yGen, RecoDecay::OriginType::NonPrompt, mcCent, maxNumContrib); + } + + registry.fill(HIST("hNumRecoCollPerMcColl"), recoCollsPerMcColl.size()); + + // fill sparse only for gen particles associated to a reconstructed collision + if (recoCollsPerMcColl.size() >= 1) { + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hMcGenWithRecoColl"), ptGen, -1., yGen, RecoDecay::OriginType::Prompt, mcCent, maxNumContrib); + } else { + float const ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("hMcGenWithRecoColl"), ptGen, ptGenB, yGen, RecoDecay::OriginType::NonPrompt, mcCent, maxNumContrib); + } + } + } + } + + void processDataKFParticle(Omegac0CandsKF const& candidates) + { + processData(candidates); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processDataKFParticle, "process data with KFParticle", false); + + void processDataKFParticleMl(Omegac0CandsMlKF const& candidates) + { + processData(candidates); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processDataKFParticleMl, "process data with KFParticle, ML selections", false); + + void processDataKFParticleFT0C(Omegac0CandsKF const& candidates, + CollisionsWithFT0C const& collisions) + { + processDataCent(candidates, collisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processDataKFParticleFT0C, "process data with KFParticle, FT0C centrality", false); + + void processDataKFParticleMlFT0C(Omegac0CandsMlKF const& candidates, + CollisionsWithFT0C const& collisions) + { + processDataCent(candidates, collisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processDataKFParticleMlFT0C, "process data with KFParticle, ML selections, FT0C centrality", false); + + void processDataKFParticleFT0M(Omegac0CandsKF const& candidates, + CollisionsWithFT0M const& collisions) + { + processDataCent(candidates, collisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processDataKFParticleFT0M, "process data with KFParticle, FT0M centrality", false); + + void processDataKFParticleMlFT0M(Omegac0CandsMlKF const& candidates, + CollisionsWithFT0M const& collisions) + { + processDataCent(candidates, collisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processDataKFParticleMlFT0M, "process data with KFParticle, ML selections, FT0M centrality", false); + + void processMcKFParticle(OmegaC0CandsMcKF const& omegaC0CandidatesMcKF, + Omegac0Gen const& mcParticles) + { + processMc(omegaC0CandidatesMcKF, mcParticles); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processMcKFParticle, "Process MC with KFParticle", false); + + void processMcKFParticleMl(Omegac0CandsMlMcKF const& omegac0CandidatesMlMcKF, + Omegac0Gen const& mcParticles) + { + processMc(omegac0CandidatesMlMcKF, mcParticles); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processMcKFParticleMl, "Process MC with KFParticle, ML selections", false); + + void processMcKFParticleFT0M(OmegaC0CandsMcKF const& omegaC0CandidatesMcKF, + Omegac0Gen const& mcParticles, + CollisionsWithMcLabels const& collisions, + McCollisionsWithFT0M const& mcCollisions) + { + processMcCent(omegaC0CandidatesMcKF, mcParticles, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processMcKFParticleFT0M, "Process MC with KFParticle, FT0M centrality (from MC)", false); + + void processMcKFParticleMlFT0M(Omegac0CandsMlMcKF const& omegac0CandidatesMlMcKF, + Omegac0Gen const& mcParticles, + CollisionsWithMcLabels const& collisions, + McCollisionsWithFT0M const& mcCollisions) + { + processMcCent(omegac0CandidatesMlMcKF, mcParticles, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskOmegac0ToOmegaPi, processMcKFParticleMlFT0M, "Process MC with KFParticle, ML selections, FT0M centrality (from MC)", 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..b4f6c7d2e60 100644 --- a/PWGHF/D2H/Tasks/taskSigmac.cxx +++ b/PWGHF/D2H/Tasks/taskSigmac.cxx @@ -15,15 +15,38 @@ /// /// \author Mattia Faggin , University and INFN PADOVA -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/D2H/Utils/utilsSigmac.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::framework; @@ -37,11 +60,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,++"}; + Configurable addSoftPiDcaToSigmacSparse{"addSoftPiDcaToSigmacSparse", false, "enable the filling of sof-pion dcaXY, dcaZ in the Σc0,++ THnSparse"}; + + 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 +82,7 @@ struct HfTaskSigmac { ConfigurableAxis configAxisDeltaMassSigmaC{"configAxisDeltaMassSigmaC", {200, 0.13, 0.23}, ""}; ConfigurableAxis thnConfigAxisBdtScoreLcBkg{"thnConfigAxisBdtScoreLcBkg", {100, 0., 1.}, ""}; ConfigurableAxis thnConfigAxisBdtScoreLcNonPrompt{"thnConfigAxisBdtScoreLcNonPrompt", {100, 0., 1.}, ""}; - - HfHelper hfHelper; + ConfigurableAxis thnConfigAxisSoftPiAbsDca{"thnConfigAxisSoftPiAbsDca", {14, 0., 0.07}, ""}; /// analysis histograms HistogramRegistry registry{ @@ -96,10 +127,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&) @@ -125,12 +152,28 @@ struct HfTaskSigmac { } /// establish if the analysis is done on Data or MC - if (doprocessMcWoMl || doprocessMcWithMl) { - isMc = true; - } else { - isMc = false; - } - + isMc = doprocessMcWoMl || doprocessMcWithMl; + + 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 thnAxisSoftPiAbsDcaXY{thnConfigAxisSoftPiAbsDca, "|dca_{xy}|(#pi^{-,+} #leftarrow #Sigma_{c}^{0,++}) (cm)"}; + const AxisSpec thnAxisSoftPiAbsDcaZ{thnConfigAxisSoftPiAbsDca, "|dca_{z}|(#pi^{-,+} #leftarrow #Sigma_{c}^{0,++}) (cm)"}; + 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)"}; + const AxisSpec thnAxisSigmaCParticleAntiparticle = {o2::aod::hf_cand_sigmac::Conjugated::NConjugated, -0.5f, +o2::aod::hf_cand_sigmac::Conjugated::NConjugated - 0.5f, "bin 1: particle, bin 2: antiparticle"}; const AxisSpec axisDeltaMassSigmaC{configAxisDeltaMassSigmaC, "#it{M}(pK#pi#pi) - #it{M}(pK#pi) (GeV/#it{c}^{2})"}; registry.add("Data/hDeltaMassSc0", "#Sigma_{c}^{0} candidates; #it{M}(pK#pi#pi) - #it{M}(pK#pi) (GeV/#it{c}^{2}); #it{p}_{T}(#Sigma_{c}^{0}) (GeV/#it{c});", {HistType::kTH2D, {axisDeltaMassSigmaC, {36, 0., 36.}}}); registry.add("Data/hDeltaMassScPlusPlus", "#Sigma_{c}^{++} candidates; #it{M}(pK#pi#pi) - #it{M}(pK#pi) (GeV/#it{c}^{2}); #it{p}_{T}(#Sigma_{c}^{++}) (GeV/#it{c});", {HistType::kTH2D, {axisDeltaMassSigmaC, {36, 0., 36.}}}); @@ -243,54 +286,61 @@ 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, thnAxisSigmaCParticleAntiparticle}); + if (doprocessMcWithMl) { + axesLambdaCWithMl.push_back(thnAxisGenPtLambdaCBMother); + axesSigmaCWithMl.push_back(thnAxisGenPtSigmaCBMother); + axesSigmaCWithMl.push_back(thnAxisGenSigmaCSpecies); + axesSigmaCWithMl.push_back(thnAxisSigmaCParticleAntiparticle); + if (addSoftPiDcaToSigmacSparse) { + axesSigmaCWithMl.push_back(thnAxisSoftPiAbsDcaXY); + axesSigmaCWithMl.push_back(thnAxisSoftPiAbsDcaZ); + } + 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); + axesSigmaCWoMl.push_back(thnAxisSigmaCParticleAntiparticle); + if (addSoftPiDcaToSigmacSparse) { + axesSigmaCWoMl.push_back(thnAxisSoftPiAbsDcaXY); + axesSigmaCWoMl.push_back(thnAxisSoftPiAbsDcaZ); + } + 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) { + if (addSoftPiDcaToSigmacSparse) { + axesSigmaCWithMl.push_back(thnAxisSoftPiAbsDcaXY); + axesSigmaCWithMl.push_back(thnAxisSoftPiAbsDcaZ); + } + registry.add("hnLambdaC", "THn for Lambdac", HistType::kTHnSparseF, axesLambdaCWithMl); + registry.add("hnSigmaC", "THn for Sigmac", HistType::kTHnSparseF, axesSigmaCWithMl); + } else { + if (addSoftPiDcaToSigmacSparse) { + axesSigmaCWoMl.push_back(thnAxisSoftPiAbsDcaXY); + axesSigmaCWoMl.push_back(thnAxisSoftPiAbsDcaZ); + } + registry.add("hnLambdaC", "THn for Lambdac", HistType::kTHnSparseF, axesLambdaCWoMl); + registry.add("hnSigmaC", "THn for Sigmac", HistType::kTHnSparseF, axesSigmaCWoMl); + } } } }; /// end init - /// @brief Function to determine if the reconstructed candidate Σc0,++ decays into Λc+ → pK-π+, Λc+ → π+K-p or both - /// @tparam L template for Lc daughter of Sc candidate - /// @tparam S template for Sc candidate - /// @param candidateLc Lc daughter of Sc candidate - /// @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) - { - int channel = 0; - if ((candidateLc.isSelLcToPKPi() >= 1) && candSc.statusSpreadLcMinvPKPiFromPDG()) { - // Λc+ → pK-π+ and within the requested mass to build the Σc0,++ - channel += 1; - } - if ((candidateLc.isSelLcToPiKP() >= 1) && candSc.statusSpreadLcMinvPiKPFromPDG()) { - // Λc+ → π+K-p and within the requested mass to build the Σc0,++ - channel += 2; - } - return channel; /// 0: none; 1: pK-π+ only; 2: π+K-p only; 3: both possible - } - /// @brief function to fill the histograms needed in analysis (data) /// @param candidatesSc are the reconstructed candidate Σc0,++ /// @param - template + template void fillHistosData(aod::HfCandSc const& candidatesSc, CandsLc const& candidatesLc, aod::Tracks const&) @@ -299,6 +349,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 +362,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 = hf_sigmac_utils::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 +371,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) { - massSc = hfHelper.invMassScRecoLcToPKPi(candSc, candidateLc); - massLc = hfHelper.invMassLcToPKPi(candidateLc); + 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); @@ -371,7 +427,9 @@ struct HfTaskSigmac { if (enableTHn) { if (!isMc) { /// fill it only if no MC operations are enabled, otherwise fill it in the processMC with the right origin and channel! - if constexpr (useMl) { + const float softPiAbsDcaXY = std::abs(candSc.softPiDcaXY()); + const float softPiAbsDcaZ = std::abs(candSc.softPiDcaZ()); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -379,21 +437,29 @@ 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), 0, 0, ptSc, std::abs(chargeSc)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), 0, 0, ptSc, std::abs(chargeSc), softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), 0, 0, ptSc, std::abs(chargeSc)); + } } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, 0, 0, ptSc, std::abs(chargeSc)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, 0, 0, ptSc, std::abs(chargeSc), softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, 0, 0, ptSc, std::abs(chargeSc)); + } } } } } /// 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) { - massSc = hfHelper.invMassScRecoLcToPiKP(candSc, candidateLc); - massLc = hfHelper.invMassLcToPiKP(candidateLc); + 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); @@ -444,7 +510,9 @@ struct HfTaskSigmac { if (enableTHn) { if (!isMc) { /// fill it only if no MC operations are enabled, otherwise fill it in the processMC with the right origin and channel! - if constexpr (useMl) { + const float softPiAbsDcaXY = std::abs(candSc.softPiDcaXY()); + const float softPiAbsDcaZ = std::abs(candSc.softPiDcaZ()); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -452,15 +520,23 @@ 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), 0, 0, ptSc, std::abs(chargeSc)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), 0, 0, ptSc, std::abs(chargeSc), softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), 0, 0, ptSc, std::abs(chargeSc)); + } } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, 0, 0, ptSc, std::abs(chargeSc)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, 0, 0, ptSc, std::abs(chargeSc), softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, 0, 0, ptSc, std::abs(chargeSc)); + } } } } } /// 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) { @@ -469,12 +545,12 @@ struct HfTaskSigmac { /// loop over Λc+ candidates w/o Σc0,++ mass-window cut for (const auto& candidateLc : candidatesLc) { double massLc(-1.); - double ptLc(candidateLc.pt()); + double const ptLc(candidateLc.pt()); double decLengthLc(candidateLc.decayLength()), decLengthXYLc(candidateLc.decayLengthXY()); double cpaLc(candidateLc.cpa()), cpaXYLc(candidateLc.cpaXY()); if (candidateLc.isSelLcToPKPi() >= 1) { - massLc = hfHelper.invMassLcToPKPi(candidateLc); - if constexpr (useMl) { + massLc = HfHelper::invMassLcToPKPi(candidateLc); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -489,8 +565,8 @@ struct HfTaskSigmac { } } if (candidateLc.isSelLcToPiKP() >= 1) { - massLc = hfHelper.invMassLcToPiKP(candidateLc); - if constexpr (useMl) { + massLc = HfHelper::invMassLcToPiKP(candidateLc); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -507,13 +583,13 @@ 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 /// @param mcParticles are the generated particles with flags wheter they are Σc0,++ or not /// @param - template + template void fillHistosMc(soa::Join const& candidatesSc, soa::Join const& mcParticlesSc, soa::Join const& mcParticlesLc, @@ -522,14 +598,17 @@ 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 const isSc0Gen = (std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::Sc0ToPKPiPi); + bool const isScStar0Gen = (std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStar0ToPKPiPi); + bool const isScPlusPlusGen = (std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScplusplusToPKPiPi); + bool const isScStarPlusPlusGen = (std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStarPlusPlusToPKPiPi); + if (!isSc0Gen && !isScPlusPlusGen && !isScStar0Gen && !isScStarPlusPlusGen) { continue; + } /// look for generated particles in acceptance /* @@ -542,16 +621,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 +653,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 +666,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 +681,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 +708,21 @@ 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) { + int8_t const particleAntiparticle = particle.particleAntiparticle(); + if (origin == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("MC/generated/hnSigmaCGen"), ptGenSc, ptGenScBMother, origin, channel, ptGenLc, 0, sigmacSpecies, particleAntiparticle); + } else { + ptGenScBMother = mcParticlesSc.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("MC/generated/hnSigmaCGen"), ptGenSc, ptGenScBMother, origin, channel, ptGenLc, 0, sigmacSpecies, particleAntiparticle); + } + + // 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 +743,48 @@ 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 + int8_t const particleAntiparticle = particle.particleAntiparticle(); + if (origin == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("MC/generated/hnSigmaCGen"), ptGenSc, ptGenScBMother, origin, channel, ptGenLc, 2, sigmacSpecies, particleAntiparticle); + } else { + ptGenScBMother = mcParticlesSc.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("MC/generated/hnSigmaCGen"), ptGenSc, ptGenScBMother, origin, channel, ptGenLc, 2, sigmacSpecies, particleAntiparticle); + } + + // 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()) != hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + continue; + } + if (yCandGenMax >= 0. && std::abs(RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus)) > yCandGenMax) { + continue; + } + double ptGenLc(particle.pt()), ptGenLcBMother(-1.); + int const origin = particle.originMcGen(); + int const 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)) { - 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,19 +794,33 @@ 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 = hf_sigmac_utils::isDecayToPKPiToPiKP(candidateLc, candSc); // candidateLc.flagMcDecayChanRec(); - /// Reconstructed Σc0 signal - if (std::abs(candSc.flagMcMatchRec()) == 1 << aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi && (chargeSc == 0)) { + bool const isTrueSc0Reco = std::abs(candSc.flagMcMatchRec()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::Sc0ToPKPiPi; + bool const isTrueScStar0Reco = std::abs(candSc.flagMcMatchRec()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStar0ToPKPiPi; + bool const isTrueScPlusPlusReco = std::abs(candSc.flagMcMatchRec()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScplusplusToPKPiPi; + bool const isTrueScStarPlusPlusReco = std::abs(candSc.flagMcMatchRec()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::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()}; int8_t sign = 0; - int indexMcLcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersLc, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + int const indexMcLcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersLc, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); auto particleLc = mcParticles.rawIteratorAt(indexMcLcRec); // Get the corresponding MC particle for soft pion auto particleSoftPi = candSc.prong1_as().mcParticle(); @@ -679,13 +835,13 @@ struct HfTaskSigmac { double ptGenSc(particleSc.pt()), ptGenLc(particleLc.pt()), ptGenSoftPi(particleSoftPi.pt()); double decLengthLc(candidateLc.decayLength()), decLengthXYLc(candidateLc.decayLengthXY()); double cpaLc(candidateLc.cpa()), cpaXYLc(candidateLc.cpaXY()); - int origin = candSc.originMcRec(); + int const origin = candSc.originMcRec(); 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) { - massSc = hfHelper.invMassScRecoLcToPKPi(candSc, candidateLc); - massLc = hfHelper.invMassLcToPKPi(candidateLc); + 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; /// Fill the histograms for reconstructed Σc0 signal @@ -740,7 +896,10 @@ struct HfTaskSigmac { /// THn for candidate Σc0,++ cut variation if (enableTHn) { - if constexpr (useMl) { + int8_t const particleAntiparticle = candSc.particleAntiparticle(); + const float softPiAbsDcaXY = std::abs(candSc.softPiDcaXY()); + const float softPiAbsDcaZ = std::abs(candSc.softPiDcaZ()); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -748,18 +907,26 @@ 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)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle, softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle); + } } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle, softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle); + } } } } /// 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) { - massSc = hfHelper.invMassScRecoLcToPiKP(candSc, candidateLc); - massLc = hfHelper.invMassLcToPiKP(candidateLc); + 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; /// Fill the histograms for reconstructed Σc0 signal @@ -814,7 +981,10 @@ struct HfTaskSigmac { /// THn for candidate Σc0,++ cut variation if (enableTHn) { - if constexpr (useMl) { + int8_t const particleAntiparticle = candSc.particleAntiparticle(); + const float softPiAbsDcaXY = std::abs(candSc.softPiDcaXY()); + const float softPiAbsDcaZ = std::abs(candSc.softPiDcaZ()); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -822,24 +992,41 @@ 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)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle, softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle); + } } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle, softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle); + } } } } /// 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()}; int8_t sign = 0; - int indexMcLcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersLc, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + int const indexMcLcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersLc, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); auto particleLc = mcParticles.rawIteratorAt(indexMcLcRec); // Get the corresponding MC particle for soft pion auto particleSoftPi = candSc.prong1_as().mcParticle(); @@ -854,13 +1041,13 @@ struct HfTaskSigmac { double ptGenSc(particleSc.pt()), ptGenLc(particleLc.pt()), ptGenSoftPi(particleSoftPi.pt()); double decLengthLc(candidateLc.decayLength()), decLengthXYLc(candidateLc.decayLengthXY()); double cpaLc(candidateLc.cpa()), cpaXYLc(candidateLc.cpaXY()); - int origin = candSc.originMcRec(); - auto channel = candidateLc.flagMcDecayChanRec(); /// 0: direct; 1: Λc± → p± K*; 2: Λc± → Δ(1232)±± K∓; 3: Λc± → Λ(1520) π± + int const origin = candSc.originMcRec(); + auto channel = candidateLc.flagMcDecayChanRec(); /// 0: direct; 1: Λc± → p± K*; 2: Λc± → Δ(1232)±± K∓; 3: Λc± → Λ(1520) π±; FIXME: DecayChannelResonant /// 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) { - massSc = hfHelper.invMassScRecoLcToPKPi(candSc, candidateLc); - massLc = hfHelper.invMassLcToPKPi(candidateLc); + 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; /// Fill the histograms for reconstructed Σc++ signal @@ -915,7 +1102,10 @@ struct HfTaskSigmac { /// THn for candidate Σc0,++ cut variation if (enableTHn) { - if constexpr (useMl) { + int8_t const particleAntiparticle = candSc.particleAntiparticle(); + const float softPiAbsDcaXY = std::abs(candSc.softPiDcaXY()); + const float softPiAbsDcaZ = std::abs(candSc.softPiDcaZ()); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -923,18 +1113,26 @@ 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)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle, softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle); + } } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle, softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle); + } } } } /// 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) { - massSc = hfHelper.invMassScRecoLcToPiKP(candSc, candidateLc); - massLc = hfHelper.invMassLcToPiKP(candidateLc); + 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; /// Fill the histograms for reconstructed Σc++ signal @@ -987,7 +1185,10 @@ struct HfTaskSigmac { /// THn for candidate Σc0,++ cut variation if (enableTHn) { - if constexpr (useMl) { + int8_t const particleAntiparticle = candSc.particleAntiparticle(); + const float softPiAbsDcaXY = std::abs(candSc.softPiDcaXY()); + const float softPiAbsDcaZ = std::abs(candSc.softPiDcaZ()); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -995,15 +1196,23 @@ 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)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle, softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, outputMl.at(0), outputMl.at(1), origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle); + } } else { /// fill w/o BDT information - registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc)); + if (addSoftPiDcaToSigmacSparse) { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle, softPiAbsDcaXY, softPiAbsDcaZ); + } else { + registry.get(HIST("hnSigmaC"))->Fill(ptLc, deltaMass, decLengthLc, decLengthXYLc, cpaLc, cpaXYLc, origin, channel, ptSc, std::abs(chargeSc), candSc.ptBhadMotherPart(), sigmacSpecies, particleAntiparticle); + } } } } /// end candidate Λc+ → π+K-p (and charge conjugate) - } /// end reconstructed Σc++ signal + } /// end reconstructed Σc++ signal } /// end loop on reconstructed Σc0,++ @@ -1011,22 +1220,22 @@ struct HfTaskSigmac { if (enableTHn) { /// loop over Λc+ candidates w/o Σc0,++ mass-window cut for (const auto& candidateLc : candidatesLc) { - if (!TESTBIT(std::abs(candidateLc.flagMcMatchRec()), aod::hf_cand_3prong::DecayType::LcToPKPi)) { + if (std::abs(candidateLc.flagMcMatchRec()) != hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { continue; } double massLc(-1.); - double ptLc(candidateLc.pt()); + double const ptLc(candidateLc.pt()); double decLengthLc(candidateLc.decayLength()), decLengthXYLc(candidateLc.decayLengthXY()); double cpaLc(candidateLc.cpa()), cpaXYLc(candidateLc.cpaXY()); - int origin = candidateLc.originMcRec(); + int const origin = candidateLc.originMcRec(); auto channel = candidateLc.flagMcDecayChanRec(); /// 0: direct; 1: Λc± → p± K*; 2: Λc± → Δ(1232)±± K∓; 3: Λc± → Λ(1520) π± int pdgAbs = -1; if (candidateLc.template prong0_as().has_mcParticle()) { pdgAbs = std::abs(candidateLc.template prong0_as().mcParticle().pdgCode()); } if (candidateLc.isSelLcToPKPi() >= 1 && pdgAbs == kProton) { - massLc = hfHelper.invMassLcToPKPi(candidateLc); - if constexpr (useMl) { + massLc = HfHelper::invMassLcToPKPi(candidateLc); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -1034,15 +1243,15 @@ 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) { - massLc = hfHelper.invMassLcToPiKP(candidateLc); - if constexpr (useMl) { + massLc = HfHelper::invMassLcToPiKP(candidateLc); + if constexpr (UseMl) { /// fill with ML information /// BDT index 0: bkg score; BDT index 2: non-prompt score std::array outputMl{-1., -1.}; @@ -1050,10 +1259,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 index 821379003d7..79f8d3c7a60 100644 --- a/PWGHF/D2H/Tasks/taskSigmacToCascade.cxx +++ b/PWGHF/D2H/Tasks/taskSigmacToCascade.cxx @@ -15,18 +15,24 @@ /// \author Rutuparna Rath , INFN BOLOGNA and GSI Darmstadt /// In collaboration with Andrea Alici , INFN BOLOGNA -#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/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + using namespace o2; using namespace o2::analysis; using namespace o2::framework; @@ -56,31 +62,30 @@ struct HfTaskSigmacToCascade { 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})"}; + AxisSpec const axisBinsPt = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisPt = {300, 0.0f, 30.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisEta = {500, -2.0f, 2.0f, "#it{#eta}"}; + AxisSpec const axisY = {500, -2.0f, 2.0f, "y"}; + AxisSpec const axisPhi = {100, 0.f, 6.3f, "#it{#phi}"}; + AxisSpec const axisMassCand = {600, 1.98f, 2.58f, "inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec const axisd0 = {500, -0.5f, 0.5f, "DCAxy (cm)"}; + AxisSpec const axisd0V0Daughters = {1000, -5.0f, 5.0f, "DCAxy (cm)"}; + AxisSpec const axisV0CPA = {500, 0.98f, 1.0001f, "v0 cos pointing angle"}; + AxisSpec const axisV0Radius = {1000, 0.f, 40.f, "V0 radius (cm)"}; + AxisSpec const axisV0DCADaughters = {200, 0.f, 2.f, "DCA (cm)"}; + AxisSpec const axisMassK0Short = {500, 0.4f, 0.6f, "#it{m}(K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec const axisMassLambda = {500, 1.0f, 1.2f, "#it{m}(#Lambda) (GeV/#it{c}^{2})"}; + AxisSpec const axisMassGamma = {500, 0.0f, 0.4f, "#it{m}(#gamma) (GeV/#it{c}^{2})"}; + AxisSpec const axisCPACand = {110, -1.1f, 1.1f, "candiate cos pointing angle"}; + AxisSpec const axisDecLength = {200, 0.f, 2.0f, "decay length (cm)"}; + AxisSpec const axisProperLifetime = {100, 0.f, 0.2f, "#it{c#tau} (cm)"}; + AxisSpec const axisProperLifetimeV0 = {1000, 0.f, 80.f, "#it{c#tau} (cm)"}; + AxisSpec const axisNSigma = {100, -6.f, 6.f, "n#it{#sigma}_{p}"}; + AxisSpec const 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 @@ -134,22 +139,21 @@ struct HfTaskSigmacToCascade { { 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 const etaSc(candSc.eta()) /*, etaLc(candidateLc.eta())*/; + float const 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; + auto massLc = HfHelper::invMassLcToK0sP(candidateLc); + auto massSc = HfHelper::invMassScRecoLcToK0sP(candSc, candidateLc); + auto deltaMass = massSc - massLc; if (candSc.charge() == 0) { - y = hfHelper.ySc0(candSc); + y = HfHelper::ySc0(candSc); } else if (candSc.charge() == 2) { - y = hfHelper.yScPlusPlus(candSc); + 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 diff --git a/PWGHF/D2H/Tasks/taskXic.cxx b/PWGHF/D2H/Tasks/taskXic.cxx index df164fb9a77..b45ba158bf0 100644 --- a/PWGHF/D2H/Tasks/taskXic.cxx +++ b/PWGHF/D2H/Tasks/taskXic.cxx @@ -19,15 +19,36 @@ /// \author Himanshu Sharma , University and INFN Padova /// \author Cristina Terrevoli , INFN Bari -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -45,8 +66,12 @@ struct HfTaskXic { Configurable dcaZTrackMax{"dcaZTrackMax", 0.0025, "max. DCAz for track"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_xic_to_p_k_pi::vecBinsPt}, "pT bin limits"}; - // THnSparse for ML outputScores and Vars Configurable enableTHn{"enableTHn", false, "enable THn for Xic"}; + Service pdg; + + Filter filterSelectCandidates = (aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlagXic || aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlagXic); + + // THnSparse for ML outputScores and Vars ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {36, 0, 36}, ""}; ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {300, 1.98, 2.58}, ""}; ConfigurableAxis thnConfigAxisPtProng{"thnConfigAxisPtProng", {100, 0, 20}, ""}; @@ -58,36 +83,35 @@ struct HfTaskXic { ConfigurableAxis thnConfigAxisBdtScoreSignal{"thnConfigAxisBdtScoreSignal", {100, 0., 1.}, ""}; ConfigurableAxis thnConfigAxisYMC{"thnConfigAxisYMC", {100, -2., 2.}, ""}; // - Service pdg; - HfHelper hfHelper; float etaMaxAcceptance = 0.8; float ptMinAcceptance = 0.1; - using TracksWPid = soa::Join; - - Filter filterSelectCandidates = (aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlagXic || aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlagXic); - - Partition> selectedMCXicCandidates = (aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlagXic || aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlagXic); - 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&) { @@ -96,10 +120,10 @@ struct HfTaskXic { LOGP(fatal, "no or more than one process function enabled! Please check your configuration!"); } - AxisSpec axisPPid = {100, 0.f, 10.0f, "#it{p} (GeV/#it{c})"}; - AxisSpec axisNSigmaPr = {100, -6.f, 6.f, "n#it{#sigma}_{p}"}; - AxisSpec axisNSigmaPi = {100, -6.f, 6.f, "n#it{#sigma}_{#pi}"}; - AxisSpec axisNSigmaKa = {100, -6.f, 6.f, "n#it{#sigma}_{K}"}; + AxisSpec const axisPPid = {100, 0.f, 10.0f, "#it{p} (GeV/#it{c})"}; + AxisSpec const axisNSigmaPr = {100, -6.f, 6.f, "n#it{#sigma}_{p}"}; + AxisSpec const axisNSigmaPi = {100, -6.f, 6.f, "n#it{#sigma}_{#pi}"}; + AxisSpec const axisNSigmaKa = {100, -6.f, 6.f, "n#it{#sigma}_{K}"}; auto vbins = (std::vector)binsPt; // histo in pt bins registry.add("Data/hMassVsPt", "3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});;entries", {HistType::kTH2F, {{500, 2., 3.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -174,6 +198,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})"}}}); @@ -211,9 +251,9 @@ struct HfTaskXic { 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, thnAxisPtMC, thnAxisYMC, thnAxisMCAllProngAccepted}); + registry.add("hnXicVarsWithBdt", "THn for Xic candidates with BDT scores", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisBdtScoreXicBkg, thnAxisBdtScoreXicPrompt, thnAxisBdtScoreXicNonPrompt, thnAxisMcOrigin}); } else { - registry.add("hnXicVars", "THn for Xic candidates", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisChi2PCA, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisMcOrigin, thnAxisPtMC, thnAxisYMC, thnAxisMCAllProngAccepted}); + registry.add("hnXicVars", "THn for Xic candidates", HistType::kTHnSparseF, {thnAxisMass, thnAxisPt, thnAxisChi2PCA, thnAxisDecLength, thnAxisDecLengthXY, thnAxisCPA, thnAxisMcOrigin}); } } } // end init @@ -227,10 +267,10 @@ struct HfTaskXic { { return std::abs(etaProng) <= etaMaxAcceptance && ptProng >= ptMinAcceptance; } - template + template void analysisData(aod::Collision const& collision, Cands const& candidates, - TracksWPid const& tracks) + aod::TracksWDca const& tracks) { int nTracks = 0; @@ -252,18 +292,18 @@ struct HfTaskXic { if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::XicToPKPi)) { continue; } - if (yCandRecoMax >= 0. && std::abs(hfHelper.yXic(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yXic(candidate)) > yCandRecoMax) { continue; } auto ptCandidate = candidate.pt(); if (candidate.isSelXicToPKPi() >= selectionFlagXic) { // pKpi - registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassXicToPKPi(candidate), ptCandidate); - registry.fill(HIST("Data/hMass"), hfHelper.invMassXicToPKPi(candidate)); + registry.fill(HIST("Data/hMassVsPt"), HfHelper::invMassXicToPKPi(candidate), ptCandidate); + registry.fill(HIST("Data/hMass"), HfHelper::invMassXicToPKPi(candidate)); } if (candidate.isSelXicToPiKP() >= selectionFlagXic) { // piKp - registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassXicToPiKP(candidate), ptCandidate); - registry.fill(HIST("Data/hMass"), hfHelper.invMassXicToPiKP(candidate)); + registry.fill(HIST("Data/hMassVsPt"), HfHelper::invMassXicToPiKP(candidate), ptCandidate); + registry.fill(HIST("Data/hMass"), HfHelper::invMassXicToPiKP(candidate)); } registry.fill(HIST("Data/hPt"), ptCandidate); registry.fill(HIST("Data/hEta"), candidate.eta()); @@ -278,7 +318,7 @@ struct HfTaskXic { registry.fill(HIST("Data/hd0Prong0"), candidate.impactParameter0(), ptCandidate); registry.fill(HIST("Data/hd0Prong1"), candidate.impactParameter1(), ptCandidate); registry.fill(HIST("Data/hd0Prong2"), candidate.impactParameter2(), ptCandidate); - registry.fill(HIST("Data/hCt"), hfHelper.ctXic(candidate), ptCandidate); + registry.fill(HIST("Data/hCt"), HfHelper::ctXic(candidate), ptCandidate); registry.fill(HIST("Data/hCPA"), candidate.cpa(), ptCandidate); registry.fill(HIST("Data/hCPAXY"), candidate.cpaXY(), ptCandidate); registry.fill(HIST("Data/hEtaVsPt"), candidate.eta(), ptCandidate); @@ -290,93 +330,94 @@ struct HfTaskXic { registry.fill(HIST("Data/hChi2PCA"), candidate.chi2PCA(), ptCandidate); // PID histos - auto trackProng0 = candidate.template prong0_as(); - auto trackProng1 = candidate.template prong1_as(); - auto trackProng2 = candidate.template prong2_as(); + auto trackProng0 = candidate.template prong0_as(); + auto trackProng1 = candidate.template prong1_as(); + auto trackProng2 = candidate.template prong2_as(); auto momentumProng0 = trackProng0.p(); auto momentumProng1 = trackProng1.p(); auto momentumProng2 = trackProng2.p(); // TPC nSigma histograms - registry.fill(HIST("Data/hPVsTPCNSigmaPr_Prong0"), momentumProng0, trackProng0.tpcNSigmaPr()); - registry.fill(HIST("Data/hPVsTPCNSigmaPi_Prong0"), momentumProng0, trackProng0.tpcNSigmaPi()); - registry.fill(HIST("Data/hPVsTPCNSigmaKa_Prong0"), momentumProng0, trackProng0.tpcNSigmaKa()); + registry.fill(HIST("Data/hPVsTPCNSigmaPr_Prong0"), momentumProng0, candidate.nSigTpcPr0()); + registry.fill(HIST("Data/hPVsTPCNSigmaPi_Prong0"), momentumProng0, candidate.nSigTpcPi0()); + registry.fill(HIST("Data/hPVsTPCNSigmaKa_Prong0"), momentumProng0, candidate.nSigTpcKa0()); - registry.fill(HIST("Data/hPVsTPCNSigmaPr_Prong1"), momentumProng1, trackProng1.tpcNSigmaPr()); - registry.fill(HIST("Data/hPVsTPCNSigmaPi_Prong1"), momentumProng1, trackProng1.tpcNSigmaPi()); - registry.fill(HIST("Data/hPVsTPCNSigmaKa_Prong1"), momentumProng1, trackProng1.tpcNSigmaKa()); + registry.fill(HIST("Data/hPVsTPCNSigmaPr_Prong1"), momentumProng1, candidate.nSigTpcPr1()); + registry.fill(HIST("Data/hPVsTPCNSigmaPi_Prong1"), momentumProng1, candidate.nSigTpcPi1()); + registry.fill(HIST("Data/hPVsTPCNSigmaKa_Prong1"), momentumProng1, candidate.nSigTpcKa1()); - registry.fill(HIST("Data/hPVsTPCNSigmaPr_Prong2"), momentumProng2, trackProng2.tpcNSigmaPr()); - registry.fill(HIST("Data/hPVsTPCNSigmaPi_Prong2"), momentumProng2, trackProng2.tpcNSigmaPi()); - registry.fill(HIST("Data/hPVsTPCNSigmaKa_Prong2"), momentumProng2, trackProng2.tpcNSigmaKa()); + registry.fill(HIST("Data/hPVsTPCNSigmaPr_Prong2"), momentumProng2, candidate.nSigTpcPr2()); + registry.fill(HIST("Data/hPVsTPCNSigmaPi_Prong2"), momentumProng2, candidate.nSigTpcPi2()); + registry.fill(HIST("Data/hPVsTPCNSigmaKa_Prong2"), momentumProng2, candidate.nSigTpcKa2()); // TOF nSigma histograms - registry.fill(HIST("Data/hPVsTOFNSigmaPr_Prong0"), momentumProng0, trackProng0.tofNSigmaPr()); - registry.fill(HIST("Data/hPVsTOFNSigmaPi_Prong0"), momentumProng0, trackProng0.tofNSigmaPi()); - registry.fill(HIST("Data/hPVsTOFNSigmaKa_Prong0"), momentumProng0, trackProng0.tofNSigmaKa()); + registry.fill(HIST("Data/hPVsTOFNSigmaPr_Prong0"), momentumProng0, candidate.nSigTofPr0()); + registry.fill(HIST("Data/hPVsTOFNSigmaPi_Prong0"), momentumProng0, candidate.nSigTofPi0()); + registry.fill(HIST("Data/hPVsTOFNSigmaKa_Prong0"), momentumProng0, candidate.nSigTofKa0()); - registry.fill(HIST("Data/hPVsTOFNSigmaPr_Prong1"), momentumProng1, trackProng1.tofNSigmaPr()); - registry.fill(HIST("Data/hPVsTOFNSigmaPi_Prong1"), momentumProng1, trackProng1.tofNSigmaPi()); - registry.fill(HIST("Data/hPVsTOFNSigmaKa_Prong1"), momentumProng1, trackProng1.tofNSigmaKa()); + registry.fill(HIST("Data/hPVsTOFNSigmaPr_Prong1"), momentumProng1, candidate.nSigTofPr1()); + registry.fill(HIST("Data/hPVsTOFNSigmaPi_Prong1"), momentumProng1, candidate.nSigTofPi1()); + registry.fill(HIST("Data/hPVsTOFNSigmaKa_Prong1"), momentumProng1, candidate.nSigTofKa1()); - registry.fill(HIST("Data/hPVsTOFNSigmaPr_Prong2"), momentumProng2, trackProng2.tofNSigmaPr()); - registry.fill(HIST("Data/hPVsTOFNSigmaPi_Prong2"), momentumProng2, trackProng2.tofNSigmaPi()); - registry.fill(HIST("Data/hPVsTOFNSigmaKa_Prong2"), momentumProng2, trackProng2.tofNSigmaKa()); + registry.fill(HIST("Data/hPVsTOFNSigmaPr_Prong2"), momentumProng2, candidate.nSigTofPr2()); + registry.fill(HIST("Data/hPVsTOFNSigmaPi_Prong2"), momentumProng2, candidate.nSigTofPi2()); + registry.fill(HIST("Data/hPVsTOFNSigmaKa_Prong2"), momentumProng2, candidate.nSigTofKa2()); // THnSparse if (enableTHn) { double massXic(-1); double outputBkg(-1), outputPrompt(-1), outputFD(-1); + const int ternaryCl = 3; if (candidate.isSelXicToPKPi() >= selectionFlagXic) { - massXic = hfHelper.invMassXicToPKPi(candidate); - if constexpr (useMl) { - if (candidate.mlProbXicToPKPi().size() == 3) { + massXic = HfHelper::invMassXicToPKPi(candidate); + if constexpr (UseMl) { + if (candidate.mlProbXicToPKPi().size() == ternaryCl) { outputBkg = candidate.mlProbXicToPKPi()[0]; /// bkg score outputPrompt = candidate.mlProbXicToPKPi()[1]; /// prompt score 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, 0.0, 0.0, false); + registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, false); } else { - registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), 0, 0.0, 0.0, false); + registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), false); } } if (candidate.isSelXicToPiKP() >= selectionFlagXic) { - massXic = hfHelper.invMassXicToPiKP(candidate); - if constexpr (useMl) { - if (candidate.mlProbXicToPiKP().size() == 3) { + massXic = HfHelper::invMassXicToPiKP(candidate); + if constexpr (UseMl) { + if (candidate.mlProbXicToPiKP().size() == ternaryCl) { outputBkg = candidate.mlProbXicToPiKP()[0]; /// bkg score outputPrompt = candidate.mlProbXicToPiKP()[1]; /// prompt score 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, 0.0, 0.0, false); + registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXic, ptCandidate, outputBkg, outputPrompt, outputFD, false); } else { - registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), 0, 0.0, 0.0, false); + registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), false); } } } // thn for Xic - } // loop candidates - } // end process data + } // loop candidates + } // end process data void processDataStd(aod::Collision const& collision, - soa::Filtered> const& candidates, - TracksWPid const& tracks) + soa::Filtered> const& candidates, + aod::TracksWDca const& tracks) { analysisData(collision, candidates, tracks); } PROCESS_SWITCH(HfTaskXic, processDataStd, "Process Data with the standard method", true); void processDataWithMl(aod::Collision const& collision, - soa::Filtered> const& candidatesMl, TracksWPid const& tracks) + soa::Filtered> const& candidatesMl, aod::TracksWDca const& tracks) { analysisData(collision, candidatesMl, tracks); } PROCESS_SWITCH(HfTaskXic, processDataWithMl, "Process Data with the ML method", false); // Fill MC histograms - template + template void analysisMc(Cands const& candidates, soa::Join const& mcParticles, aod::TracksWMc const&) @@ -388,7 +429,7 @@ struct HfTaskXic { if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::XicToPKPi)) { continue; } - if (yCandRecoMax >= 0. && std::abs(hfHelper.yXic(candidate)) > yCandRecoMax) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yXic(candidate)) > yCandRecoMax) { continue; } @@ -396,29 +437,27 @@ struct HfTaskXic { auto massXicToPiKP = 0.; if (candidate.isSelXicToPKPi() >= selectionFlagXic) { - massXicToPKPi = hfHelper.invMassXicToPKPi(candidate); + massXicToPKPi = HfHelper::invMassXicToPKPi(candidate); } if (candidate.isSelXicToPiKP() >= selectionFlagXic) { - massXicToPiKP = hfHelper.invMassXicToPiKP(candidate); // mass conjugate + massXicToPiKP = HfHelper::invMassXicToPiKP(candidate); // mass conjugate } - if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::XicToPKPi) { + if (std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi) { // 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); @@ -429,59 +468,69 @@ struct HfTaskXic { registry.fill(HIST("MC/reconstructed/signal/hd0Prong0RecSig"), candidate.impactParameter0(), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hd0Prong1RecSig"), candidate.impactParameter1(), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hd0Prong2RecSig"), candidate.impactParameter2(), ptCandidate); - registry.fill(HIST("MC/reconstructed/signal/hCtRecSig"), hfHelper.ctXic(candidate), ptCandidate); + registry.fill(HIST("MC/reconstructed/signal/hCtRecSig"), HfHelper::ctXic(candidate), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hCPARecSig"), candidate.cpa(), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hCPAXYRecSig"), candidate.cpaXY(), ptCandidate); registry.fill(HIST("MC/reconstructed/signal/hEtaRecSig"), candidate.eta(), ptCandidate); 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 + int const origin = candidate.originMcRec(); + if (origin == 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; + const int ternaryCl = 3; 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) { + if constexpr (UseMl) { + if (candidate.mlProbXicToPKPi().size() == ternaryCl) { outputBkg = candidate.mlProbXicToPKPi()[0]; /// bkg score outputPrompt = candidate.mlProbXicToPKPi()[1]; /// prompt score 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(), mcParticleProng0.pt(), yProng0, allProngsInAcceptance); + registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXicToPKPi, ptCandidate, outputBkg, outputPrompt, outputFD, origin); } else { - registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), candidate.originMcRec(), mcParticleProng0.pt(), yProng0, allProngsInAcceptance); + registry.get(HIST("hnXicVars"))->Fill(massXicToPKPi, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), origin); } } 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) { + if constexpr (UseMl) { + if (candidate.mlProbXicToPiKP().size() == ternaryCl) { outputBkg = candidate.mlProbXicToPiKP()[0]; /// bkg score outputPrompt = candidate.mlProbXicToPiKP()[1]; /// prompt score outputFD = candidate.mlProbXicToPiKP()[2]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate (todo: add multiplicity) // 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); + registry.get(HIST("hnXicVarsWithBdt"))->Fill(massXicToPiKP, ptCandidate, outputBkg, outputPrompt, outputFD, origin); } else { - registry.get(HIST("hnXicVars"))->Fill(massXic, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), candidate.originMcRec(), mcParticleProng0.pt(), yProng0, allProngsInAcceptance); + registry.get(HIST("hnXicVars"))->Fill(massXicToPiKP, ptCandidate, candidate.chi2PCA(), candidate.decayLength(), candidate.decayLengthXY(), candidate.cpa(), origin); } } } // enable THn @@ -506,7 +555,7 @@ struct HfTaskXic { registry.fill(HIST("MC/reconstructed/background/hd0Prong0RecBg"), candidate.impactParameter0(), ptCandidate); registry.fill(HIST("MC/reconstructed/background/hd0Prong1RecBg"), candidate.impactParameter1(), ptCandidate); registry.fill(HIST("MC/reconstructed/background/hd0Prong2RecBg"), candidate.impactParameter2(), ptCandidate); - registry.fill(HIST("MC/reconstructed/background/hCtRecBg"), hfHelper.ctXic(candidate), ptCandidate); + registry.fill(HIST("MC/reconstructed/background/hCtRecBg"), HfHelper::ctXic(candidate), ptCandidate); registry.fill(HIST("MC/reconstructed/background/hCPARecBg"), candidate.cpa(), ptCandidate); registry.fill(HIST("MC/reconstructed/background/hCPAXYRecBg"), candidate.cpaXY(), ptCandidate); registry.fill(HIST("MC/reconstructed/background/hEtaRecBg"), candidate.eta(), ptCandidate); @@ -514,40 +563,40 @@ struct HfTaskXic { registry.fill(HIST("MC/reconstructed/background/hDecLenErrBg"), candidate.errorDecayLength(), ptCandidate); registry.fill(HIST("MC/reconstructed/background/hChi2PCARecBg"), candidate.chi2PCA(), ptCandidate); } // Xic background - } // candidate loop + } // candidate loop // 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) { + if (std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi) { + 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, + void processMcStd(soa::Filtered> const& selectedCandidatesMc, soa::Join const& mcParticles, aod::TracksWMc const& tracksWithMc) { @@ -555,7 +604,7 @@ struct HfTaskXic { } PROCESS_SWITCH(HfTaskXic, processMcStd, "Process MC with the standard method", false); - void processMcWithMl(soa::Filtered> const& selectedCandidatesMlMc, + void processMcWithMl(soa::Filtered> const& selectedCandidatesMlMc, soa::Join const& mcParticles, aod::TracksWMc const& tracksWithMc) { diff --git a/PWGHF/D2H/Tasks/taskXic0ToXiPi.cxx b/PWGHF/D2H/Tasks/taskXic0ToXiPi.cxx new file mode 100644 index 00000000000..4cfbbed96fe --- /dev/null +++ b/PWGHF/D2H/Tasks/taskXic0ToXiPi.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 taskXic0ToXiPi.cxx +/// \brief Task for Ξc^0 → Ξ∓ π± analysis +/// \author Tao Fang , Central China Normal University +/// \author Ran Tu , Fudan University + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Xic0 analysis task + +struct HfTaskXic0ToXiPi { + // ML inference + Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; + Configurable fillCent{"fillCent", false, "Flag to fill centrality information"}; + Configurable yCandGenMax{"yCandGenMax", 0.8, "max. gen particle rapidity"}; + Configurable yCandRecMax{"yCandRecMax", 0.8, "max. cand. rapidity"}; + + SliceCache cache; + + using TracksMc = soa::Join; + + using Xic0Cands = soa::Filtered>; + using Xic0CandsKF = soa::Filtered>; + using Xic0CandsMc = soa::Filtered>; + using Xic0CandsMcKF = soa::Filtered>; + + using Xic0CandsMl = soa::Filtered>; + using Xic0CandsMlKF = soa::Filtered>; + using Xic0CandsMlMc = soa::Filtered>; + using Xic0CandsMlMcKF = soa::Filtered>; + + using Xic0Gen = soa::Filtered>; + + using CollisionsWithEvSels = soa::Join; + using CollisionsWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + using CollisionsWithMcLabels = soa::Join; + + using McCollisionsCentFT0Ms = soa::Join; + + Filter filterSelectXic0Candidates = aod::hf_sel_toxipi::resultSelections == true; + Filter filterXicMatchedRec = nabs(aod::hf_cand_xic0_omegac0::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi)); + Filter filterXicMatchedGen = nabs(aod::hf_cand_xic0_omegac0::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi)); + Preslice candXicPerCollision = aod::hf_cand_xic0_omegac0::collisionId; + Preslice candXicKFPerCollision = aod::hf_cand_xic0_omegac0::collisionId; + Preslice candXicMlPerCollision = aod::hf_cand_xic0_omegac0::collisionId; + Preslice candXicKFMlPerCollision = aod::hf_cand_xic0_omegac0::collisionId; + + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + // ThnSparse for ML outputScores and Vars + ConfigurableAxis thnConfigAxisPromptScore{"thnConfigAxisPromptScore", {100, 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 thnConfigAxisCent{"thnConfigAxisCent", {100, 0, 100}, "Centrality bins"}; + ConfigurableAxis thnConfigAxisPtPion{"thnConfigAxisPtPion", {100, 0, 10}, "PtPion from Xic0 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{doprocessDataWithDCAFitter, doprocessDataWithDCAFitterMl, doprocessDataWithDCAFitterFT0C, doprocessDataWithDCAFitterFT0M, doprocessDataWithDCAFitterMlFT0C, doprocessDataWithDCAFitterMlFT0M, + doprocessDataWithKFParticle, doprocessDataWithKFParticleMl, doprocessDataWithKFParticleFT0C, doprocessDataWithKFParticleFT0M, doprocessDataWithKFParticleMlFT0C, doprocessDataWithKFParticleMlFT0M, + doprocessMcWithKFParticle, doprocessMcWithKFParticleMl, doprocessMcWithDCAFitter, doprocessMcWithDCAFitterMl}; + 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 (#Xi#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"}; + const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality percentile"}; + + if (doprocessMcWithKFParticle || doprocessMcWithKFParticleMl || doprocessMcWithDCAFitter || doprocessMcWithDCAFitterMl) { + std::vector const axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisCent, thnAxisNumPvContr}; + registry.add("hSparseAcc", "Thn for generated Xic0 from charm and beauty", HistType::kTHnSparseD, axesAcc); + registry.get(HIST("hSparseAcc"))->Sumw2(); + + registry.add("hSparseAccWithRecoColl", "Gen. Xic0 from charm and beauty (associated to a reco collision)", HistType::kTHnSparseD, axesAcc); + registry.get(HIST("hSparseAccWithRecoColl"))->Sumw2(); + + registry.add("hNumRecoCollPerMcColl", "Number of reco collisions associated to a mc collision;Num. reco. coll. per Mc coll.;", {HistType::kTH1D, {{10, -0.5, 9.5}}}); + } + + std::vector axes = {thnAxisMass, thnAxisPt, thnAxisY}; + if (doprocessMcWithKFParticle || doprocessMcWithKFParticleMl || doprocessMcWithDCAFitter || doprocessMcWithDCAFitterMl) { + axes.push_back(thnAxisPtB); + axes.push_back(thnAxisOrigin); + axes.push_back(thnAxisMatchFlag); + axes.push_back(thnAxisCent); + axes.push_back(thnAxisNumPvContr); + } + if (applyMl) { + const AxisSpec thnAxisPromptScore{thnConfigAxisPromptScore, "BDT score prompt."}; + axes.insert(axes.begin(), thnAxisPromptScore); + registry.add("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsXic0Type", "Thn for Xic0 candidates", HistType::kTHnSparseD, axes); + registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsXic0Type"))->Sumw2(); + } else { + registry.add("hMassVsPtVsPtBVsYVsOriginVsXic0Type", "Thn for Xic0 candidates", HistType::kTHnSparseF, axes); + registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsXic0Type"))->Sumw2(); + } + if (fillCent) { + const AxisSpec thnAxisPromptScore{thnConfigAxisPromptScore, "BDT score prompt."}; + const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality."}; + const AxisSpec thnAxisPtPion{thnConfigAxisPtPion, "Pt of Pion from Xic0."}; + std::vector const axesWithBdtCent = {thnAxisPromptScore, thnAxisMass, thnAxisPt, thnAxisY, thnAxisCent, thnAxisPtPion, thnConfigAxisNumPvContr}; + std::vector const axesWithCent = {thnAxisMass, thnAxisPt, thnAxisY, thnAxisCent, thnAxisPtPion, thnConfigAxisNumPvContr}; + registry.add("hBdtScoreVsMassVsPtVsYVsCentVsPtPion", "Thn for Xic0 candidates with BDT&Cent&pTpi", HistType::kTHnSparseD, axesWithBdtCent); + registry.add("hMassVsPtVsYVsCentVsPtPion", "Thn for Xic0 candidates with Cent&pTpi", HistType::kTHnSparseD, axesWithCent); + registry.get(HIST("hBdtScoreVsMassVsPtVsYVsCentVsPtPion"))->Sumw2(); + registry.get(HIST("hMassVsPtVsYVsCentVsPtPion"))->Sumw2(); + } + } + + template + void processDataCent(const CandType& candidate, CollType const& collision) + { + if (candidate.resultSelections() != true) { + return; + } + double yCharmBaryon; + if constexpr (UseKfParticle) { + yCharmBaryon = candidate.kfRapXic(); + } else { + yCharmBaryon = candidate.y(o2::constants::physics::MassXiC0); + } + if (yCandRecMax >= 0. && std::abs(yCharmBaryon) > yCandRecMax) { + return; + } + + auto numPvContributors = collision.numContrib(); + float centrality = -999.f; + if constexpr (UseCentrality) { + centrality = o2::hf_centrality::getCentralityColl(collision); + } + double const ptXic = RecoDecay::pt(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()); + double const ptPiFromXic = RecoDecay::pt(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); + if constexpr (ApplyMl) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsYVsCentVsPtPion"), + candidate.mlProbToXiPi()[0], + candidate.invMassCharmBaryon(), + ptXic, + yCharmBaryon, + centrality, + ptPiFromXic, + numPvContributors); + } else { + registry.fill(HIST("hMassVsPtVsYVsCentVsPtPion"), + candidate.invMassCharmBaryon(), + ptXic, + yCharmBaryon, + centrality, + ptPiFromXic, + numPvContributors); + } + } + + template + void processMc(const CandType& candidates, + Xic0Gen const& mcParticles, + TracksMc const&, + CollType const& collisions, + McCollisionWithCents const&) + { + // MC rec. + for (const auto& candidate : candidates) { + if (candidate.resultSelections() != true) { + continue; + } + double yCharmBaryon; + if constexpr (UseKfParticle) { + yCharmBaryon = candidate.kfRapXic(); + } else { + yCharmBaryon = candidate.y(o2::constants::physics::MassXiC0); + } + if (yCandRecMax >= 0. && std::abs(yCharmBaryon) > yCandRecMax) { + continue; + } + + auto collision = candidate.template collision_as(); + float const mcCent = o2::hf_centrality::getCentralityColl(collision.template mcCollision_as()); + auto numPvContributors = candidate.template collision_as().numContrib(); + double const ptXic = RecoDecay::pt(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()); + if constexpr (ApplyMl) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsXic0Type"), + candidate.mlProbToXiPi()[0], + candidate.invMassCharmBaryon(), + ptXic, + yCharmBaryon, + candidate.ptBhadMotherPart(), + candidate.originMcRec(), + candidate.flagMcMatchRec(), + mcCent, + numPvContributors); + } else { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsXic0Type"), + candidate.invMassCharmBaryon(), + ptXic, + yCharmBaryon, + candidate.ptBhadMotherPart(), + candidate.originMcRec(), + candidate.flagMcMatchRec(), + mcCent, + 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(); + + float const mcCent = o2::hf_centrality::getCentralityColl(particle.template mcCollision_as()); + 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.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hSparseAcc"), + ptGen, + -1., + yGen, + RecoDecay::OriginType::Prompt, + mcCent, + maxNumContrib); + } else { + float const ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("hSparseAcc"), + ptGen, + ptGenB, + yGen, + RecoDecay::OriginType::NonPrompt, + mcCent, + maxNumContrib); + } + + registry.fill(HIST("hNumRecoCollPerMcColl"), recoCollsPerMcColl.size()); + + // fill sparse only for gen particles associated to a reconstructed collision + if (recoCollsPerMcColl.size() >= 1) { + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hSparseAccWithRecoColl"), + ptGen, + -1., + yGen, + RecoDecay::OriginType::Prompt, + mcCent, + maxNumContrib); + } else { + float const ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + registry.fill(HIST("hSparseAccWithRecoColl"), + ptGen, + ptGenB, + yGen, + RecoDecay::OriginType::NonPrompt, + mcCent, + maxNumContrib); + } + } + } + } + + void processDataWithDCAFitter(Xic0Cands const& candidates, + CollisionsWithEvSels const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithDCAFitter, "process HfTaskXic0ToXiPi with DCAFitter", true); + + void processDataWithKFParticle(Xic0CandsKF const& candidates, + CollisionsWithEvSels const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicKFPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithKFParticle, "process HfTaskXic0ToXiPi with KFParticle", true); + + void processDataWithDCAFitterMl(Xic0CandsMl const& candidates, + CollisionsWithEvSels const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicMlPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithDCAFitterMl, "process HfTaskXic0ToXiPi with DCAFitter and ML selections", false); + + void processDataWithKFParticleMl(Xic0CandsMlKF const& candidates, + CollisionsWithEvSels const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicKFMlPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithKFParticleMl, "process HfTaskXic0ToXiPi with KFParticle and ML selections", false); + + void processDataWithDCAFitterFT0C(Xic0Cands const& candidates, + CollisionsWithFT0C const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithDCAFitterFT0C, "process HfTaskXic0ToXiPi with DCAFitter and with FT0C centrality", false); + + void processDataWithKFParticleFT0C(Xic0CandsKF const& candidates, + CollisionsWithFT0C const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicKFPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithKFParticleFT0C, "process HfTaskXic0ToXiPi with KFParticle and with FT0C centrality", false); + + void processDataWithDCAFitterFT0M(Xic0Cands const& candidates, + CollisionsWithFT0M const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithDCAFitterFT0M, "process HfTaskXic0ToXiPi with DCAFitter and with FT0M centrality", false); + + void processDataWithKFParticleFT0M(Xic0CandsKF const& candidates, + CollisionsWithFT0M const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicKFPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithKFParticleFT0M, "process HfTaskXic0ToXiPi with KFParticle and with FT0M centrality", false); + + void processDataWithDCAFitterMlFT0C(Xic0CandsMl const& candidates, + CollisionsWithFT0C const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicMlPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithDCAFitterMlFT0C, "process HfTaskXic0ToXiPi with DCAFitter and ML selections and with FT0C centrality", false); + + void processDataWithKFParticleMlFT0C(Xic0CandsMlKF const& candidates, + CollisionsWithFT0C const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicKFMlPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithKFParticleMlFT0C, "process HfTaskXic0ToXiPi with KFParticle and ML selections and with FT0C centrality", false); + + void processDataWithDCAFitterMlFT0M(Xic0CandsMl const& candidates, + CollisionsWithFT0M const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicMlPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithDCAFitterMlFT0M, "process HfTaskXic0ToXiPi with DCAFitter and ML selections and with FT0M centrality", false); + + void processDataWithKFParticleMlFT0M(Xic0CandsMlKF const& candidates, + CollisionsWithFT0M const& collisions) + { + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto groupedXicCandidates = candidates.sliceBy(candXicKFMlPerCollision, thisCollId); + for (const auto& candidate : groupedXicCandidates) { + processDataCent(candidate, collision); + } + } + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processDataWithKFParticleMlFT0M, "process HfTaskXic0ToXiPi with KFParticle and ML selections and with FT0M centrality", false); + + void processMcWithDCAFitter(Xic0CandsMc const& xic0CandidatesMc, + Xic0Gen const& mcParticles, + TracksMc const& tracks, + CollisionsWithMcLabels const& collisions, + McCollisionsCentFT0Ms const& mcCollisions) + { + processMc(xic0CandidatesMc, mcParticles, tracks, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processMcWithDCAFitter, "Process MC with KFParticle", false); + + void processMcWithKFParticle(Xic0CandsMcKF const& xic0CandidatesMcKf, + Xic0Gen const& mcParticles, + TracksMc const& tracks, + CollisionsWithMcLabels const& collisions, + McCollisionsCentFT0Ms const& mcCollisions) + { + processMc(xic0CandidatesMcKf, mcParticles, tracks, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processMcWithKFParticle, "Process MC with KFParticle", false); + + void processMcWithDCAFitterMl(Xic0CandsMlMc const& xic0CandidatesMlMc, + Xic0Gen const& mcParticles, + TracksMc const& tracks, + CollisionsWithMcLabels const& collisions, + McCollisionsCentFT0Ms const& mcCollisions) + { + processMc(xic0CandidatesMlMc, mcParticles, tracks, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processMcWithDCAFitterMl, "Process MC with KFParticle and ML selections", false); + + void processMcWithKFParticleMl(Xic0CandsMlMcKF const& xic0CandidatesMlMcKf, + Xic0Gen const& mcParticles, + TracksMc const& tracks, + CollisionsWithMcLabels const& collisions, + McCollisionsCentFT0Ms const& mcCollisions) + { + processMc(xic0CandidatesMlMcKf, mcParticles, tracks, collisions, mcCollisions); + } + PROCESS_SWITCH(HfTaskXic0ToXiPi, processMcWithKFParticleMl, "Process MC with KFParticle and ML selections", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/D2H/Tasks/taskXicToXiPiPi.cxx b/PWGHF/D2H/Tasks/taskXicToXiPiPi.cxx index 4c07f89f70f..256fd600a69 100644 --- a/PWGHF/D2H/Tasks/taskXicToXiPiPi.cxx +++ b/PWGHF/D2H/Tasks/taskXicToXiPiPi.cxx @@ -13,18 +13,43 @@ /// \brief Ξc± → (Ξ∓ → (Λ → p π∓) π∓) π± π± analysis task /// \note adapted from taskBs.cxx /// -/// \author Phil Stahlhut - -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" +/// \author Phil Lennart Stahlhut , Heidelberg University +/// \author Carolina Reetz , Heidelberg University +/// \author Jaeyoon Cho , Inha University +#include "PWGHF/Core/DecayChannelsLegacy.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::analysis; @@ -41,8 +66,26 @@ struct HfTaskXicToXiPiPi { 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"}; + + static constexpr int NVarsMultiClass{3}; + + 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}, ""}; @@ -50,21 +93,23 @@ struct HfTaskXicToXiPiPi { ConfigurableAxis binsSV{"binsSV", {200, -5., 5.}, ""}; ConfigurableAxis binsChi2{"binsChi2", {200, 0., 0.1}, ""}; - Service pdg; - - Filter filterSelectCandidates = (aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= selectionFlagXic); - - HistogramRegistry registry{ - "registry", - {{"hPtCand", "#Xi^{#plus}_{c} candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{400, 0., 40.}}}}, - {"hPtProng0", "#Xi^{#plus}_{c} candidates;prong 0 (#Xi^{#minus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{300, 0., 30.}}}}, - {"hPtProng1", "#Xi^{#plus}_{c} candidates;prong 1 (#pi^{#plus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 20.}}}}, - {"hPtProng2", "#Xi^{#plus}_{c} candidates;prong 2 (#pi^{#plus}) #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 20.}}}}}}; + 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.0, 2.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}; @@ -73,41 +118,48 @@ struct HfTaskXicToXiPiPi { static const AxisSpec axisSV = {binsSV}; static const AxisSpec axisChi2 = {binsChi2}; - // candidate - registry.add("hPt", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 20.}}}); - 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}}); - registry.add("hChi2topoToPV", "#Xi^{#plus}_{c} candidates;#Xi^{#plus}_{c} candidate #chi^{2}_{topo} to PV;entries", {HistType::kTH2F, {axisChi2, axisPt}}); - // daughters - 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("hPtProng0vsPt", "#Xi^{#plus}_{c} candidates;#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("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}}); - 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("hChi2topoXiToXicPlus", "#Xi^{#plus}_{c} candidates;#Xi^{#mp} candidate #chi^{2}_{topo} to #Xi^{#plus}_{c};entries", {HistType::kTH2F, {axisChi2, axisPt}}); - - if (doprocessMc) { + 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;#chi^{2}_{geo} (#Xi^{#mp});entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2GeoLam", "#Xi^{#plus}_{c} candidates;#chi^{2}_{geo} (#Lambda);entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2TopoXicPlusToPV", "#Xi^{#plus}_{c} candidates;#chi^{2}_{topo} (#Xi^{#plus}_{c} #rightarrow PV);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.}}}); @@ -158,14 +210,6 @@ struct HfTaskXicToXiPiPi { 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("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}}); 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}}); @@ -178,6 +222,15 @@ struct HfTaskXicToXiPiPi { 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("hChi2GeoXiRecSig", "#Xi^{#plus}_{c} candidates (matched);#chi^{2}_{geo} (#Xi^{#mp});entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2GeoXiRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#chi^{2}_{geo} (#Xi^{#mp});entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2GeoLamRecSig", "#Xi^{#plus}_{c} candidates (matched);#chi^{2}_{geo} (#Lambda);entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2GeoLamRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#chi^{2}_{geo} (#Lambda);entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2TopoXicPlusToPVRecSig", "#Xi^{#plus}_{c} candidates (matched);#chi^{2}_{topo} (#Xi^{#plus}_{c} #rightarrow PV);entries", {HistType::kTH2F, {axisChi2, axisPt}}); + registry.add("hChi2TopoXicPlusToPVRecBg", "#Xi^{#plus}_{c} candidates (unmatched);#chi^{2}_{topo} (#Xi^{#plus}_{c} #rightarrow PV);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}}); @@ -211,6 +264,55 @@ struct HfTaskXicToXiPiPi { 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 const scoreSize = candidate.mlProbXicToXiPiPi().size(); + if (scoreSize > 0) { + outputBkg = candidate.mlProbXicToXiPiPi()[0]; + outputPrompt = candidate.mlProbXicToXiPiPi()[1]; + if (scoreSize == NVarsMultiClass) { + 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 @@ -223,7 +325,9 @@ struct HfTaskXicToXiPiPi { return std::abs(etaProng) <= etaTrackMax && ptProng >= ptTrackMin; } - void process(soa::Filtered> const& candidates) + /// Function to fill histograms + template + void fillHistograms(TCanTable const& candidates) { for (const auto& candidate : candidates) { auto yCandXic = candidate.y(o2::constants::physics::MassXiCPlus); @@ -233,7 +337,7 @@ struct HfTaskXicToXiPiPi { auto ptCandXic = candidate.pt(); - registry.fill(HIST("hPtCand"), ptCandXic); + registry.fill(HIST("hPt"), ptCandXic); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); registry.fill(HIST("hPtProng1"), candidate.ptProng1()); registry.fill(HIST("hPtProng2"), candidate.ptProng2()); @@ -241,7 +345,7 @@ struct HfTaskXicToXiPiPi { 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.invMassXic(), 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); @@ -249,8 +353,6 @@ struct HfTaskXicToXiPiPi { registry.fill(HIST("hSVx"), candidate.xSecondaryVertex(), ptCandXic); registry.fill(HIST("hSVy"), candidate.ySecondaryVertex(), ptCandXic); registry.fill(HIST("hSVz"), candidate.zSecondaryVertex(), ptCandXic); - registry.fill(HIST("hChi2topoToPV"), candidate.chi2TopoXicPlusToPV(), ptCandXic); - registry.fill(HIST("hChi2topoXiToXicPlus"), candidate.chi2TopoXiToXicPlus(), ptCandXic); registry.fill(HIST("hPtProng0vsPt"), candidate.ptProng0(), ptCandXic); registry.fill(HIST("hPtProng1vsPt"), candidate.ptProng1(), ptCandXic); registry.fill(HIST("hPtProng2vsPt"), candidate.ptProng2(), ptCandXic); @@ -261,21 +363,36 @@ struct HfTaskXicToXiPiPi { 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("hCPAXi"), candidate.cpaXi(), ptCandXic); + registry.fill(HIST("hCPAxyXi"), candidate.cpaXYXi(), ptCandXic); + registry.fill(HIST("hCPALambda"), candidate.cpaLambda(), ptCandXic); + registry.fill(HIST("hCPAxyLambda"), candidate.cpaLambda(), ptCandXic); registry.fill(HIST("hMassXiPi1"), candidate.invMassXiPi0(), ptCandXic); registry.fill(HIST("hMassXiPi2"), candidate.invMassXiPi1(), ptCandXic); - registry.fill(HIST("hChi2geoXi"), candidate.kfCascadeChi2(), ptCandXic); - registry.fill(HIST("hChi2geoLam"), candidate.kfV0Chi2(), ptCandXic); + + // fill KFParticle specific histograms + if constexpr (UseKfParticle) { + registry.fill(HIST("hChi2GeoXi"), candidate.kfCascadeChi2(), ptCandXic); + registry.fill(HIST("hChi2GeoLam"), candidate.kfV0Chi2(), ptCandXic); + registry.fill(HIST("hChi2TopoXicPlusToPV"), candidate.chi2TopoXicPlusToPV(), ptCandXic); + } + + // fill THnSparse + if (enableTHn) { + if constexpr (UseMl) { + fillTHnSparse(candidate); + } else { + fillTHnSparse(candidate); + } + } } // candidate loop - } // process + } - /// MC analysis and fill histograms - void processMc(soa::Filtered> const& candidates, - soa::Join const& mcParticles, - aod::TracksWMc const&) + /// Function for MC analysis and histogram filling + template + void fillHistogramsMc(TCandTable const& candidates, + soa::Join const& mcParticles, + aod::TracksWMc const&) { std::vector arrDaughIndex; @@ -287,10 +404,10 @@ struct HfTaskXicToXiPiPi { } auto ptCandXic = candidate.pt(); - int flagMcMatchRecXic = std::abs(candidate.flagMcMatchRec()); + auto 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.pi0_as().mcParticle_as>(), o2::constants::physics::Pdg::kXiCPlus, true); + 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()); @@ -308,7 +425,7 @@ struct HfTaskXicToXiPiPi { 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.invMassXic(), 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); @@ -320,14 +437,17 @@ struct HfTaskXicToXiPiPi { registry.fill(HIST("hImpParErrRecSig"), candidate.errorImpactParameter1(), ptCandXic); registry.fill(HIST("hImpParErrRecSig"), candidate.errorImpactParameter2(), ptCandXic); registry.fill(HIST("hChi2PCARecSig"), candidate.chi2PCA(), ptCandXic); - 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); - 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); + registry.fill(HIST("hCPAXiRecSig"), candidate.cpaXi(), ptCandXic); + registry.fill(HIST("hCPAxyXiRecSig"), candidate.cpaXYXi(), ptCandXic); + registry.fill(HIST("hCPALambdaRecSig"), candidate.cpaLambda(), ptCandXic); + registry.fill(HIST("hCPAxyLambdaRecSig"), candidate.cpaLambda(), ptCandXic); + + // fill KFParticle specific histograms + if constexpr (UseKfParticle) { + registry.fill(HIST("hChi2geoXiRecSig"), candidate.kfCascadeChi2(), ptCandXic); + registry.fill(HIST("hChi2geoLamRecSig"), candidate.kfV0Chi2(), ptCandXic); + registry.fill(HIST("hChi2TopoXicPlusToPVRecSig"), candidate.chi2TopoXicPlusToPV(), ptCandXic); + } } else { registry.fill(HIST("hPtRecBg"), ptCandXic); registry.fill(HIST("hPtProng0RecBg"), candidate.ptProng0()); @@ -343,7 +463,7 @@ struct HfTaskXicToXiPiPi { 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.invMassXic(), 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); @@ -355,25 +475,37 @@ struct HfTaskXicToXiPiPi { registry.fill(HIST("hImpParErrRecBg"), candidate.errorImpactParameter1(), ptCandXic); registry.fill(HIST("hImpParErrRecBg"), candidate.errorImpactParameter2(), ptCandXic); registry.fill(HIST("hChi2PCARecBg"), candidate.chi2PCA(), ptCandXic); - 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); - 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); + registry.fill(HIST("hCPAXiRecBg"), candidate.cpaXi(), ptCandXic); + registry.fill(HIST("hCPAxyXiRecBg"), candidate.cpaXYXi(), ptCandXic); + registry.fill(HIST("hCPALambdaRecBg"), candidate.cpaLambda(), ptCandXic); + registry.fill(HIST("hCPAxyLambdaRecBg"), candidate.cpaLambda(), ptCandXic); + + // fill KFParticle specific histograms + if constexpr (UseKfParticle) { + registry.fill(HIST("hChi2geoXiRecBg"), candidate.kfCascadeChi2(), ptCandXic); + registry.fill(HIST("hChi2geoLamRecBg"), candidate.kfV0Chi2(), ptCandXic); + registry.fill(HIST("hChi2TopoXicPlusToPVRecBg"), candidate.chi2TopoXicPlusToPV(), 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.invMassXic(), ptCandXic); + 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.invMassXic(), ptCandXic); + 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 { - registry.fill(HIST("hDecayTypeMc"), 1 + hf_cand_xic_to_xi_pi_pi::DecayType::NDecayType, candidate.invMassXic(), ptCandXic); + fillTHnSparse(candidate); } } + } // rec // MC gen. level @@ -388,16 +520,16 @@ struct HfTaskXicToXiPiPi { } // get kinematic variables of Ξ π π - std::array ptProngs; - std::array yProngs; - std::array etaProngs; - std::array prodVtxXProngs; - std::array prodVtxYProngs; - std::array prodVtxZProngs; + 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]); + for (const int iProng : arrDaughIndex) { + auto daughI = mcParticles.rawIteratorAt(iProng); ptProngs[counter] = daughI.pt(); etaProngs[counter] = daughI.eta(); yProngs[counter] = RecoDecay::y(daughI.pVector(), pdg->Mass(daughI.pdgCode())); @@ -432,8 +564,69 @@ struct HfTaskXicToXiPiPi { registry.fill(HIST("hYGenWithProngsInAcceptance"), yParticle, ptParticle); } } // gen - } // process - PROCESS_SWITCH(HfTaskXicToXiPiPi, processMc, "Process MC", false); + } + + /// 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) diff --git a/PWGHF/D2H/Tasks/taskXicc.cxx b/PWGHF/D2H/Tasks/taskXicc.cxx index 0e3f116081a..f75ca850c81 100644 --- a/PWGHF/D2H/Tasks/taskXicc.cxx +++ b/PWGHF/D2H/Tasks/taskXicc.cxx @@ -16,14 +16,28 @@ /// \author Gian Michele Innocenti , CERN /// \author Jinjoo Seo , Inha University -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" - +#include "PWGHF/ALICE3/Core/DecayChannelsLegacy.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::framework; @@ -31,11 +45,11 @@ using namespace o2::framework::expressions; void customize(std::vector& workflowOptions) { - ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, true, {"Fill MC histograms."}}; + ConfigParamSpec const optionDoMC{"doMC", VariantType::Bool, true, {"Fill MC histograms."}}; workflowOptions.push_back(optionDoMC); } -#include "Framework/runDataProcessing.h" +#include /// Ξcc±± analysis task struct HfTaskXicc { @@ -43,8 +57,6 @@ struct HfTaskXicc { Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_xicc_to_p_k_pi_pi::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_xicc::isSelXiccToPKPiPi >= selectionFlagXicc); HistogramRegistry registry{ @@ -75,13 +87,13 @@ struct HfTaskXicc { void process(soa::Filtered> const& candidates) { for (const auto& candidate : candidates) { - if (!(candidate.hfflag() & 1 << aod::hf_cand_xicc::DecayType::XiccToXicPi)) { + if ((candidate.hfflag() & 1 << aod::hf_cand_xicc::DecayType::XiccToXicPi) == 0) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yXicc(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yXicc(candidate)) > yCandMax) { continue; } - registry.fill(HIST("hMass"), hfHelper.invMassXiccToXicPi(candidate), candidate.pt()); // FIXME need to consider the two mass hp + registry.fill(HIST("hMass"), HfHelper::invMassXiccToXicPi(candidate), candidate.pt()); // FIXME need to consider the two mass hp registry.fill(HIST("hPtCand"), candidate.pt()); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); registry.fill(HIST("hPtProng1"), candidate.ptProng1()); @@ -90,10 +102,10 @@ struct HfTaskXicc { registry.fill(HIST("hChi2PCA"), candidate.chi2PCA(), candidate.pt()); registry.fill(HIST("hd0Prong0"), candidate.impactParameter0(), candidate.pt()); registry.fill(HIST("hd0Prong1"), candidate.impactParameter1(), candidate.pt()); - registry.fill(HIST("hCt"), hfHelper.ctXicc(candidate), candidate.pt()); + registry.fill(HIST("hCt"), HfHelper::ctXicc(candidate), candidate.pt()); registry.fill(HIST("hCPA"), candidate.cpa(), candidate.pt()); registry.fill(HIST("hEta"), candidate.eta(), candidate.pt()); - registry.fill(HIST("hY"), hfHelper.yXicc(candidate), candidate.pt()); + registry.fill(HIST("hY"), HfHelper::yXicc(candidate), candidate.pt()); registry.fill(HIST("hSelectionStatus"), candidate.isSelXiccToPKPiPi(), candidate.pt()); registry.fill(HIST("hImpParErr0"), candidate.errorImpactParameter0(), candidate.pt()); registry.fill(HIST("hImpParErr1"), candidate.errorImpactParameter1(), candidate.pt()); @@ -108,8 +120,6 @@ struct HfTaskXiccMc { Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_xicc_to_p_k_pi_pi::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_xicc::isSelXiccToPKPiPi >= selectionFlagXicc); HistogramRegistry registry{ @@ -183,10 +193,10 @@ struct HfTaskXiccMc { { // MC rec. for (const auto& candidate : candidates) { - if (!(candidate.hfflag() & 1 << aod::hf_cand_xicc::DecayType::XiccToXicPi)) { + if ((candidate.hfflag() & 1 << aod::hf_cand_xicc::DecayType::XiccToXicPi) == 0) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yXicc(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yXicc(candidate)) > yCandMax) { continue; } if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_xicc::DecayType::XiccToXicPi) { @@ -209,17 +219,17 @@ struct HfTaskXiccMc { registry.fill(HIST("hPtGenSig"), particleXicc.pt()); // gen. level pT registry.fill(HIST("hPtRecSig"), candidate.pt()); // rec. level pT registry.fill(HIST("hEtaRecSig"), candidate.eta()); - registry.fill(HIST("hYRecSig"), hfHelper.yXicc(candidate)); - registry.fill(HIST("hMassVsPtRecSig"), hfHelper.invMassXiccToXicPi(candidate), candidate.pt()); // FIXME need to consider the two mass hp + registry.fill(HIST("hYRecSig"), HfHelper::yXicc(candidate)); + registry.fill(HIST("hMassVsPtRecSig"), HfHelper::invMassXiccToXicPi(candidate), candidate.pt()); // FIXME need to consider the two mass hp registry.fill(HIST("hDecLengthVsPtRecSig"), candidate.decayLength(), candidate.pt()); registry.fill(HIST("hChi2PCAVsPtRecSig"), candidate.chi2PCA(), candidate.pt()); registry.fill(HIST("hCPAVsPtRecSig"), candidate.cpa(), candidate.pt()); registry.fill(HIST("hd0Prong0VsPtRecSig"), candidate.impactParameter0(), candidate.pt()); registry.fill(HIST("hd0Prong1VsPtRecSig"), candidate.impactParameter1(), candidate.pt()); registry.fill(HIST("hd0d0VsPtRecSig"), candidate.impactParameterProduct(), candidate.pt()); - registry.fill(HIST("hCtVsPtRecSig"), hfHelper.ctXicc(candidate), candidate.pt()); + registry.fill(HIST("hCtVsPtRecSig"), HfHelper::ctXicc(candidate), candidate.pt()); registry.fill(HIST("hEtaVsPtRecSig"), candidate.eta(), candidate.pt()); - registry.fill(HIST("hYVsPtRecSig"), hfHelper.yXicc(candidate), candidate.pt()); + registry.fill(HIST("hYVsPtRecSig"), HfHelper::yXicc(candidate), candidate.pt()); registry.fill(HIST("hImpParErr0VsPtRecSig"), candidate.errorImpactParameter0(), candidate.pt()); registry.fill(HIST("hImpParErr1VsPtRecSig"), candidate.errorImpactParameter1(), candidate.pt()); registry.fill(HIST("hXSecVtxPosRecGenDiffSig"), candidate.xSecondaryVertex() - particleXic.vx(), candidate.pt()); @@ -227,38 +237,38 @@ struct HfTaskXiccMc { registry.fill(HIST("hZSecVtxPosRecGenDiffSig"), candidate.zSecondaryVertex() - particleXic.vz(), candidate.pt()); registry.fill(HIST("hPtRecGenDiffSig"), candidate.pt() - particleXicc.pt(), candidate.pt()); // Check Y dependence (To be removed) - registry.fill(HIST("hMassVsPtVsYRecSig"), hfHelper.invMassXiccToXicPi(candidate), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hDecLengthVsPtVsYRecSig"), candidate.decayLength(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hChi2PCAVsPtVsYRecSig"), candidate.chi2PCA(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hCPAVsPtVsYRecSig"), candidate.cpa(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hd0Prong0VsPtVsYRecSig"), candidate.impactParameter0(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hd0Prong1VsPtVsYRecSig"), candidate.impactParameter1(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hCtVsPtVsYRecSig"), hfHelper.ctXicc(candidate), candidate.pt(), hfHelper.yXicc(candidate)); + registry.fill(HIST("hMassVsPtVsYRecSig"), HfHelper::invMassXiccToXicPi(candidate), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hDecLengthVsPtVsYRecSig"), candidate.decayLength(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hChi2PCAVsPtVsYRecSig"), candidate.chi2PCA(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hCPAVsPtVsYRecSig"), candidate.cpa(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hd0Prong0VsPtVsYRecSig"), candidate.impactParameter0(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hd0Prong1VsPtVsYRecSig"), candidate.impactParameter1(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hCtVsPtVsYRecSig"), HfHelper::ctXicc(candidate), candidate.pt(), HfHelper::yXicc(candidate)); } else { registry.fill(HIST("hPtRecBg"), candidate.pt()); registry.fill(HIST("hEtaRecBg"), candidate.eta()); - registry.fill(HIST("hYRecBg"), hfHelper.yXicc(candidate)); - registry.fill(HIST("hMassVsPtRecBg"), hfHelper.invMassXiccToXicPi(candidate), candidate.pt()); // FIXME need to consider the two mass hp + registry.fill(HIST("hYRecBg"), HfHelper::yXicc(candidate)); + registry.fill(HIST("hMassVsPtRecBg"), HfHelper::invMassXiccToXicPi(candidate), candidate.pt()); // FIXME need to consider the two mass hp registry.fill(HIST("hDecLengthVsPtRecBg"), candidate.decayLength(), candidate.pt()); registry.fill(HIST("hChi2PCAVsPtRecBg"), candidate.chi2PCA(), candidate.pt()); registry.fill(HIST("hCPAVsPtRecBg"), candidate.cpa(), candidate.pt()); registry.fill(HIST("hd0Prong0VsPtRecBg"), candidate.impactParameter0(), candidate.pt()); registry.fill(HIST("hd0Prong1VsPtRecBg"), candidate.impactParameter1(), candidate.pt()); registry.fill(HIST("hd0d0VsPtRecBg"), candidate.impactParameterProduct(), candidate.pt()); - registry.fill(HIST("hCtVsPtRecBg"), hfHelper.ctXicc(candidate), candidate.pt()); + registry.fill(HIST("hCtVsPtRecBg"), HfHelper::ctXicc(candidate), candidate.pt()); registry.fill(HIST("hEtaVsPtRecBg"), candidate.eta(), candidate.pt()); - registry.fill(HIST("hYVsPtRecBg"), hfHelper.yXicc(candidate), candidate.pt()); + registry.fill(HIST("hYVsPtRecBg"), HfHelper::yXicc(candidate), candidate.pt()); registry.fill(HIST("hImpParErr0VsPtRecBg"), candidate.errorImpactParameter0(), candidate.pt()); registry.fill(HIST("hImpParErr1VsPtRecBg"), candidate.errorImpactParameter1(), candidate.pt()); registry.fill(HIST("hDebugMCmatching"), candidate.debugMcRec(), candidate.pt()); // Check Y dependence (To be removed) - registry.fill(HIST("hMassVsPtVsYRecBg"), hfHelper.invMassXiccToXicPi(candidate), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hDecLengthVsPtVsYRecBg"), candidate.decayLength(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hChi2PCAVsPtVsYRecBg"), candidate.chi2PCA(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hCPAVsPtVsYRecBg"), candidate.cpa(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hd0Prong0VsPtVsYRecBg"), candidate.impactParameter0(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hd0Prong1VsPtVsYRecBg"), candidate.impactParameter1(), candidate.pt(), hfHelper.yXicc(candidate)); - registry.fill(HIST("hCtVsPtVsYRecBg"), hfHelper.ctXicc(candidate), candidate.pt(), hfHelper.yXicc(candidate)); + registry.fill(HIST("hMassVsPtVsYRecBg"), HfHelper::invMassXiccToXicPi(candidate), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hDecLengthVsPtVsYRecBg"), candidate.decayLength(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hChi2PCAVsPtVsYRecBg"), candidate.chi2PCA(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hCPAVsPtVsYRecBg"), candidate.cpa(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hd0Prong0VsPtVsYRecBg"), candidate.impactParameter0(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hd0Prong1VsPtVsYRecBg"), candidate.impactParameter1(), candidate.pt(), HfHelper::yXicc(candidate)); + registry.fill(HIST("hCtVsPtVsYRecBg"), HfHelper::ctXicc(candidate), candidate.pt(), HfHelper::yXicc(candidate)); } } // end of loop over reconstructed candidates // MC gen. @@ -273,8 +283,8 @@ struct HfTaskXiccMc { registry.fill(HIST("hPtvsEtavsYGen"), particle.pt(), particle.eta(), RecoDecay::y(particle.pVector(), o2::constants::physics::MassXiCCPlusPlus)); } } // end of loop of MC particles - } // end of process function -}; // end of struct + } // end of process function +}; // end of struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGHF/D2H/Utils/utilsRedDataFormat.h b/PWGHF/D2H/Utils/utilsRedDataFormat.h index 2d99105e474..b188bee7645 100644 --- a/PWGHF/D2H/Utils/utilsRedDataFormat.h +++ b/PWGHF/D2H/Utils/utilsRedDataFormat.h @@ -10,29 +10,34 @@ // or submit itself to any jurisdiction. /// \file utilsRedDataFormat.h -/// \brief Event selection utilities for reduced data format analyses +/// \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" +#include +#include +#include + +#include + +#include + 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 +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); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (!TESTBIT(rejectionMask, o2::hf_evsel::EventRejection::Trigger)) { sel8Coll++; } @@ -51,4 +56,80 @@ void checkEvSel(Coll const& collision, o2::hf_evsel::HfEventSelection& hfEvSel, } } // 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 const 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; +} + +/// Helper function to retrive PID information of bachelor pion from b-hadron decay +/// \param prongSoftPi soft pion track +template +float getTpcTofNSigmaSoftPi(const T1& prongSoftPi) +{ + float const defaultNSigma = -999.f; // -999.f is the default value set in TPCPIDResponse.h and PIDTOF.h + + bool hasTpc = prongSoftPi.hasTPC(); + bool hasTof = prongSoftPi.hasTOF(); + + if (hasTpc && hasTof) { + float tpcNSigma = prongSoftPi.tpcNSigmaPiSoftPi(); + float tofNSigma = prongSoftPi.tofNSigmaPiSoftPi(); + return std::sqrt(.5f * tpcNSigma * tpcNSigma + .5f * tofNSigma * tofNSigma); + } + if (hasTpc) { + return std::abs(prongSoftPi.tpcNSigmaPiSoftPi()); + } + if (hasTof) { + return std::abs(prongSoftPi.tofNSigmaPiSoftPi()); + } + return defaultNSigma; +} + +/// Helper function to retrive PID information of bachelor kaon from b-hadron decay +/// \param prong1 kaon track from reduced data format, aod::HfRedBachProng0Tracks +/// \return the combined TPC and TOF n-sigma for kaon +template +float getTpcTofNSigmaKa1(const T1& prong1) +{ + float const 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.tpcNSigmaKa(); + float tofNSigma = prong1.tofNSigmaKa(); + return std::sqrt(.5f * tpcNSigma * tpcNSigma + .5f * tofNSigma * tofNSigma); + } + if (hasTpc) { + return std::abs(prong1.tpcNSigmaKa()); + } + if (hasTof) { + return std::abs(prong1.tofNSigmaKa()); + } + return defaultNSigma; +} +} // namespace o2::pid_tpc_tof_utils + #endif // PWGHF_D2H_UTILS_UTILSREDDATAFORMAT_H_ diff --git a/PWGHF/D2H/Utils/utilsSigmac.h b/PWGHF/D2H/Utils/utilsSigmac.h new file mode 100644 index 00000000000..4777235ee6a --- /dev/null +++ b/PWGHF/D2H/Utils/utilsSigmac.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. + +/// \file utilsSigmac.h +/// \brief Utilities for Sigmac analysis +/// \author Mattia Faggin , INFN Padova + +#ifndef PWGHF_D2H_UTILS_UTILSSIGMAC_H_ +#define PWGHF_D2H_UTILS_UTILSSIGMAC_H_ + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" + +#include + +#include + +namespace o2::hf_sigmac_utils +{ +/// @brief Function to determine if the reconstructed candidate Σc0,++ decays into Λc+ → pK-π+, Λc+ → π+K-p or both +/// @tparam L template for Lc daughter of Sc candidate +/// @tparam S template for Sc candidate +/// @param candidateLc Lc daughter of Sc candidate +/// @param candSc Sc candidate +/// @return 0: none; 1: only Λc+ → pK-π+ possible; 2: Λc+ → π+K-p possible; 3: both possible +template +int8_t isDecayToPKPiToPiKP(L& candidateLc, S& candSc) +{ + int8_t channel = 0; + if ((candidateLc.isSelLcToPKPi() >= 1) && candSc.statusSpreadLcMinvPKPiFromPDG()) { + // Λc+ → pK-π+ and within the requested mass to build the Σc0,++ + 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,++ + SETBIT(channel, o2::aod::hf_cand_sigmac::Decays::PiKP); + } + return channel; /// 0: none; 1: pK-π+ only; 2: π+K-p only; 3: both possible +} +} // namespace o2::hf_sigmac_utils + +#endif // PWGHF_D2H_UTILS_UTILSSIGMAC_H_ diff --git a/PWGHF/DataModel/AliasTables.h b/PWGHF/DataModel/AliasTables.h new file mode 100644 index 00000000000..37e396770db --- /dev/null +++ b/PWGHF/DataModel/AliasTables.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 AliasTables.h +/// \brief Table aliases +/// +/// \author Gian Michele Innocenti , CERN +/// \author Vít Kučera , CERN + +#ifndef PWGHF_DATAMODEL_ALIASTABLES_H_ +#define PWGHF_DATAMODEL_ALIASTABLES_H_ + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include + +namespace o2::aod +{ +using BcFullInfos = soa::Join; + +using TracksWCov = soa::Join; +using TracksWDca = soa::Join; +using TracksWExtra = soa::Join; +using TracksWCovDca = soa::Join; +using TracksWCovExtra = soa::Join; +using TracksWDcaExtra = soa::Join; +using TracksWCovDcaExtra = soa::Join; + +using TracksWMc = soa::Join; + +using TracksPidEl = soa::Join; +using TracksPidMu = soa::Join; +using TracksPidPi = soa::Join; +using TracksPidKa = soa::Join; +using TracksPidPr = soa::Join; +using TracksPidDe = soa::Join; + +using TracksPidTinyEl = soa::Join; +using TracksPidTinyMu = soa::Join; +using TracksPidTinyPi = soa::Join; +using TracksPidTinyKa = soa::Join; +using TracksPidTinyPr = soa::Join; +using TracksPidTinyDe = soa::Join; +} // namespace o2::aod + +#endif // PWGHF_DATAMODEL_ALIASTABLES_H_ diff --git a/PWGHF/DataModel/CandidateReconstructionTables.h b/PWGHF/DataModel/CandidateReconstructionTables.h index 27716aee943..5bc4cc45c1c 100644 --- a/PWGHF/DataModel/CandidateReconstructionTables.h +++ b/PWGHF/DataModel/CandidateReconstructionTables.h @@ -18,132 +18,23 @@ #ifndef PWGHF_DATAMODEL_CANDIDATERECONSTRUCTIONTABLES_H_ #define PWGHF_DATAMODEL_CANDIDATERECONSTRUCTIONTABLES_H_ -#include - -#include "Math/GenVector/Boost.h" -#include "Math/Vector4D.h" - -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsPid.h" +// +#include "PWGLF/DataModel/LFStrangenessTables.h" #include "ALICE3/DataModel/ECAL.h" #include "Common/Core/RecoDecay.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include +#include +#include -#include "PWGHF/Core/SelectorCuts.h" +#include +#include namespace o2::aod { -// Table aliases - -using TracksWCov = soa::Join; -using TracksWDca = soa::Join; -using TracksWExtra = soa::Join; -using TracksWCovDca = soa::Join; -using TracksWCovExtra = soa::Join; -using TracksWDcaExtra = soa::Join; -using TracksWCovDcaExtra = soa::Join; - -using TracksWMc = soa::Join; - -using TracksPidEl = soa::Join; -using TracksPidMu = soa::Join; -using TracksPidPi = soa::Join; -using TracksPidKa = soa::Join; -using TracksPidPr = soa::Join; - -using TracksPidTinyEl = soa::Join; -using TracksPidTinyMu = soa::Join; -using TracksPidTinyPi = soa::Join; -using TracksPidTinyKa = soa::Join; -using TracksPidTinyPr = soa::Join; - -// namespace pid_tpc_tof_utils -// { -// /// Function to combine TPC and TOF NSigma (for ML purposes) -// /// \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 Node containing the combined NSigma of TPC and TOF -// template -// o2::framework::expressions::Node combineNSigma(const T1& tpcNSigma, const T1& tofNSigma) -// { -// float defaultNSigmaTolerance = .1f; -// float defaultNSigma = -999.f + defaultNSigmaTolerance; // -999.f is the default value set in TPCPIDResponse.h and PIDTOF.h - -// if constexpr (tiny) { -// auto tpcBinWidth = 1.f * pidtpc_tiny::binning::bin_width; -// auto tofBinWidth = 1.f * pidtof_tiny::binning::bin_width; - -// return o2::framework::expressions::ifnode((tpcNSigma * tpcBinWidth > defaultNSigma) && (tofNSigma * tofBinWidth > defaultNSigma), o2::framework::expressions::nsqrt(.5f * tpcNSigma * tpcNSigma * tpcBinWidth * tpcBinWidth + .5f * tofNSigma * tofNSigma * tofBinWidth * tofBinWidth), // TPC and TOF -// o2::framework::expressions::ifnode(tpcNSigma * tpcBinWidth > defaultNSigma, o2::framework::expressions::nabs(tpcNSigma * tpcBinWidth), // only TPC -// o2::framework::expressions::ifnode(tofNSigma * tofBinWidth > defaultNSigma, o2::framework::expressions::nabs(tofNSigma * tofBinWidth), // only TOF -// 1.f * tofNSigma * tofBinWidth))); // no TPC nor TOF -// } - -// return o2::framework::expressions::ifnode((tpcNSigma > defaultNSigma) && (tofNSigma > defaultNSigma), o2::framework::expressions::nsqrt(.5f * tpcNSigma * tpcNSigma + .5f * tofNSigma * tofNSigma), // TPC and TOF -// o2::framework::expressions::ifnode(tpcNSigma > defaultNSigma, o2::framework::expressions::nabs(tpcNSigma), // only TPC -// o2::framework::expressions::ifnode(tofNSigma > defaultNSigma, o2::framework::expressions::nabs(tofNSigma), // only TOF -// 1.f * tofNSigma))); // no TPC nor TOF -// } -// } // namespace pid_tpc_tof_utils - -// namespace pid_tpc_tof_full -// { -// // Combined TPC and TOF NSigma -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaEl, tpcTofNSigmaEl, //! Combined NSigma separation with the TPC & TOF detectors for electron -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc::tpcNSigmaEl, o2::aod::pidtof::tofNSigmaEl)); -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaMu, tpcTofNSigmaMu, //! Combined NSigma separation with the TPC & TOF detectors for muon -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc::tpcNSigmaMu, o2::aod::pidtof::tofNSigmaMu)); -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaPi, tpcTofNSigmaPi, //! Combined NSigma separation with the TPC & TOF detectors for pion -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc::tpcNSigmaPi, o2::aod::pidtof::tofNSigmaPi)); -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaKa, tpcTofNSigmaKa, //! Combined NSigma separation with the TPC & TOF detectors for kaon -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc::tpcNSigmaKa, o2::aod::pidtof::tofNSigmaKa)); -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaPr, tpcTofNSigmaPr, //! Combined NSigma separation with the TPC & TOF detectors for proton -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc::tpcNSigmaPr, o2::aod::pidtof::tofNSigmaPr)); -// } // namespace pid_tpc_tof_full - -// namespace pid_tpc_tof_tiny -// { -// // Combined binned TPC and TOF NSigma -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaEl, tpcTofNSigmaEl, //! Combined binned NSigma separation with the TPC & TOF detectors for electron -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc_tiny::tpcNSigmaStoreEl, o2::aod::pidtof_tiny::tofNSigmaStoreEl)); -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaMu, tpcTofNSigmaMu, //! Combined binned NSigma separation with the TPC & TOF detectors for muon -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc_tiny::tpcNSigmaStoreMu, o2::aod::pidtof_tiny::tofNSigmaStoreMu)); -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaPi, tpcTofNSigmaPi, //! Combined binned NSigma separation with the TPC & TOF detectors for pion -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc_tiny::tpcNSigmaStorePi, o2::aod::pidtof_tiny::tofNSigmaStorePi)); -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaKa, tpcTofNSigmaKa, //! Combined binned NSigma separation with the TPC & TOF detectors for kaon -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc_tiny::tpcNSigmaStoreKa, o2::aod::pidtof_tiny::tofNSigmaStoreKa)); -// DECLARE_SOA_EXPRESSION_COLUMN(TpcTofNSigmaPr, tpcTofNSigmaPr, //! Combined binned NSigma separation with the TPC & TOF detectors for proton -// float, pid_tpc_tof_utils::combineNSigma(o2::aod::pidtpc_tiny::tpcNSigmaStorePr, o2::aod::pidtof_tiny::tofNSigmaStorePr)); -// } // namespace pid_tpc_tof_tiny - -// // Extension of per particle tables -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidElExt, TracksPidEl, "PIDELEXT", //! Table of the TPC & TOF Combined NSigma for electron -// pid_tpc_tof_full::TpcTofNSigmaEl); -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidMuExt, TracksPidMu, "PIDMUEXT", //! Table of the TPC & TOF Combined NSigma for muon -// pid_tpc_tof_full::TpcTofNSigmaMu); -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidPiExt, TracksPidPi, "PIDPIEXT", //! Table of the TPC & TOF Combined NSigma for pion -// pid_tpc_tof_full::TpcTofNSigmaPi); -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidKaExt, TracksPidKa, "PIDKAEXT", //! Table of the TPC & TOF Combined NSigma for kaon -// pid_tpc_tof_full::TpcTofNSigmaKa); -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidPrExt, TracksPidPr, "PIDPREXT", //! Table of the TPC & TOF Combined NSigma for proton -// pid_tpc_tof_full::TpcTofNSigmaPr); - -// // Extension of tiny size tables -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidTinyElExt, TracksPidTinyEl, "PIDTINYELEXT", //! Table of the TPC & TOF combined binned NSigma for electron -// pid_tpc_tof_tiny::TpcTofNSigmaEl); -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidTinyMuExt, TracksPidTinyMu, "PIDTINYMUEXT", //! Table of the TPC & TOF combined binned NSigma for muon -// pid_tpc_tof_tiny::TpcTofNSigmaMu); -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidTinyPiExt, TracksPidTinyPi, "PIDTINYPIEXT", //! Table of the TPC & TOF combined binned NSigma for pion -// pid_tpc_tof_tiny::TpcTofNSigmaPi); -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidTinyKaExt, TracksPidTinyKa, "PIDTINYKAEXT", //! Table of the TPC & TOF combined binned NSigma for kaon -// pid_tpc_tof_tiny::TpcTofNSigmaKa); -// DECLARE_SOA_EXTENDED_TABLE_USER(TracksPidTinyPrExt, TracksPidTinyPr, "PIDTINYPREXT", //! Table of the TPC & TOF combined binned NSigma for proton -// pid_tpc_tof_tiny::TpcTofNSigmaPr); - namespace pid_tpc_tof_static_full { // Combined TPC and TOF NSigma @@ -152,6 +43,7 @@ DECLARE_SOA_COLUMN(TpcTofNSigmaMu, tpcTofNSigmaMu, float); //! Combined NSigma s DECLARE_SOA_COLUMN(TpcTofNSigmaPi, tpcTofNSigmaPi, float); //! Combined NSigma separation with the TPC & TOF detectors for pion DECLARE_SOA_COLUMN(TpcTofNSigmaKa, tpcTofNSigmaKa, float); //! Combined NSigma separation with the TPC & TOF detectors for kaon DECLARE_SOA_COLUMN(TpcTofNSigmaPr, tpcTofNSigmaPr, float); //! Combined NSigma separation with the TPC & TOF detectors for proton +DECLARE_SOA_COLUMN(TpcTofNSigmaDe, tpcTofNSigmaDe, float); //! Combined NSigma separation with the TPC & TOF detectors for deuteron } // namespace pid_tpc_tof_static_full namespace pid_tpc_tof_static_tiny @@ -162,6 +54,7 @@ DECLARE_SOA_COLUMN(TpcTofNSigmaMu, tpcTofNSigmaMu, float); //! Combined NSigma s DECLARE_SOA_COLUMN(TpcTofNSigmaPi, tpcTofNSigmaPi, float); //! Combined NSigma separation with the TPC & TOF detectors for pion DECLARE_SOA_COLUMN(TpcTofNSigmaKa, tpcTofNSigmaKa, float); //! Combined NSigma separation with the TPC & TOF detectors for kaon DECLARE_SOA_COLUMN(TpcTofNSigmaPr, tpcTofNSigmaPr, float); //! Combined NSigma separation with the TPC & TOF detectors for proton +DECLARE_SOA_COLUMN(TpcTofNSigmaDe, tpcTofNSigmaDe, float); //! Combined NSigma separation with the TPC & TOF detectors for deuteron } // namespace pid_tpc_tof_static_tiny // Extension of per particle tables @@ -175,6 +68,8 @@ DECLARE_SOA_TABLE(PidTpcTofFullKa, "AOD", "PIDTPCTOFFULLKA", //! Table of the TP pid_tpc_tof_static_full::TpcTofNSigmaKa); DECLARE_SOA_TABLE(PidTpcTofFullPr, "AOD", "PIDTPCTOFFULLPR", //! Table of the TPC & TOF Combined NSigma for proton pid_tpc_tof_static_full::TpcTofNSigmaPr); +DECLARE_SOA_TABLE(PidTpcTofFullDe, "AOD", "PIDTPCTOFFULLDe", //! Table of the TPC & TOF Combined NSigma for deuteron + pid_tpc_tof_static_full::TpcTofNSigmaDe); // Extension of per particle tables DECLARE_SOA_TABLE(PidTpcTofTinyEl, "AOD", "PIDTPCTOFTINYEL", //! Table of the TPC & TOF Combined NSigma for electron @@ -187,236 +82,8 @@ DECLARE_SOA_TABLE(PidTpcTofTinyKa, "AOD", "PIDTPCTOFTINYKA", //! Table of the TP pid_tpc_tof_static_tiny::TpcTofNSigmaKa); DECLARE_SOA_TABLE(PidTpcTofTinyPr, "AOD", "PIDTPCTOFTINYPR", //! Table of the TPC & TOF Combined NSigma for proton pid_tpc_tof_static_tiny::TpcTofNSigmaPr); - -namespace hf_sel_collision -{ -DECLARE_SOA_COLUMN(WhyRejectColl, whyRejectColl, uint16_t); //! -} // namespace hf_sel_collision - -DECLARE_SOA_TABLE(HfSelCollision, "AOD", "HFSELCOLLISION", //! - hf_sel_collision::WhyRejectColl); - -namespace hf_sel_track -{ -DECLARE_SOA_COLUMN(IsSelProng, isSelProng, uint32_t); //! -DECLARE_SOA_COLUMN(IsIdentifiedPid, isIdentifiedPid, uint32_t); //! -DECLARE_SOA_COLUMN(IsPositive, isPositive, bool); //! -} // namespace hf_sel_track - -DECLARE_SOA_TABLE(HfSelTrack, "AOD", "HFSELTRACK", //! - hf_sel_track::IsSelProng, - hf_sel_track::IsIdentifiedPid, - hf_sel_track::IsPositive); - -namespace hf_pv_refit_track -{ -DECLARE_SOA_COLUMN(PvRefitX, pvRefitX, float); //! -DECLARE_SOA_COLUMN(PvRefitY, pvRefitY, float); //! -DECLARE_SOA_COLUMN(PvRefitZ, pvRefitZ, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaX2, pvRefitSigmaX2, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaXY, pvRefitSigmaXY, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaY2, pvRefitSigmaY2, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaXZ, pvRefitSigmaXZ, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaYZ, pvRefitSigmaYZ, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaZ2, pvRefitSigmaZ2, float); //! -DECLARE_SOA_COLUMN(PvRefitDcaXY, pvRefitDcaXY, float); //! -DECLARE_SOA_COLUMN(PvRefitDcaZ, pvRefitDcaZ, float); //! -} // namespace hf_pv_refit_track - -DECLARE_SOA_TABLE(HfPvRefitTrack, "AOD", "HFPVREFITTRACK", //! - hf_pv_refit_track::PvRefitX, - hf_pv_refit_track::PvRefitY, - hf_pv_refit_track::PvRefitZ, - hf_pv_refit_track::PvRefitSigmaX2, - hf_pv_refit_track::PvRefitSigmaXY, - hf_pv_refit_track::PvRefitSigmaY2, - hf_pv_refit_track::PvRefitSigmaXZ, - hf_pv_refit_track::PvRefitSigmaYZ, - hf_pv_refit_track::PvRefitSigmaZ2, - hf_pv_refit_track::PvRefitDcaXY, - hf_pv_refit_track::PvRefitDcaZ); - -namespace hf_track_index -{ -DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision index -DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, Tracks, "_0"); //! Index to first prong -DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, Tracks, "_1"); //! Index to second prong -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(FlagD0ToKPi, flagD0ToKPi, uint8_t); //! -DECLARE_SOA_COLUMN(FlagJpsiToEE, flagJpsiToEE, uint8_t); //! -DECLARE_SOA_COLUMN(FlagJpsiToMuMu, flagJpsiToMuMu, uint8_t); //! - -DECLARE_SOA_COLUMN(FlagDplusToPiKPi, flagDplusToPiKPi, uint8_t); //! -DECLARE_SOA_COLUMN(FlagLcToPKPi, flagLcToPKPi, uint8_t); //! -DECLARE_SOA_COLUMN(FlagDsToKKPi, flagDsToKKPi, uint8_t); //! -DECLARE_SOA_COLUMN(FlagXicToPKPi, flagXicToPKPi, uint8_t); //! - -DECLARE_SOA_COLUMN(FlagDstarToD0Pi, flagDstarToD0Pi, uint8_t); //! - -DECLARE_SOA_COLUMN(MlProbSkimD0ToKPi, mlProbSkimD0ToKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for D0->Kpi -DECLARE_SOA_COLUMN(MlProbSkimDplusToPiKPi, mlProbSkimDplusToPiKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for D+->Kpipi -DECLARE_SOA_COLUMN(MlProbSkimDsToKKPi, mlProbSkimDsToKKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for Ds->KKpi -DECLARE_SOA_COLUMN(MlProbSkimLcToPKPi, mlProbSkimLcToPKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for Lc->pKpi -DECLARE_SOA_COLUMN(MlProbSkimXicToPKPi, mlProbSkimXicToPKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for Xic->pKpi -} // namespace hf_track_index - -DECLARE_SOA_TABLE(Hf2Prongs_000, "AOD", "HF2PRONG", //! Table for HF 2 prong candidates (Run 2 converted format) - o2::soa::Index<>, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - hf_track_index::HFflag); - -DECLARE_SOA_TABLE_VERSIONED(Hf2Prongs_001, "AOD", "HF2PRONG", 1, //! Table for HF 2 prong candidates (Run 3 format) - o2::soa::Index<>, - hf_track_index::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - hf_track_index::HFflag); - -using Hf2Prongs = Hf2Prongs_001; -using Hf2Prong = Hf2Prongs::iterator; - -DECLARE_SOA_TABLE(HfCascades_000, "AOD", "HFCASCADE", //! Table for HF candidates with a V0 (Run 2 converted format) - o2::soa::Index<>, - hf_track_index::Prong0Id, - hf_track_index::V0Id); - -DECLARE_SOA_TABLE_VERSIONED(HfCascades_001, "AOD", "HFCASCADE", 1, //! Table for HF candidates with a V0 (Run 3 format) - o2::soa::Index<>, - hf_track_index::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::V0Id); - -using HfCascades = HfCascades_001; -using HfCascade = HfCascades::iterator; - -DECLARE_SOA_TABLE(Hf3Prongs_000, "AOD", "HF3PRONG", //! Table for HF 3 prong candidates (Run 2 converted format) - o2::soa::Index<>, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - hf_track_index::Prong2Id, - hf_track_index::HFflag); - -DECLARE_SOA_TABLE_VERSIONED(Hf3Prongs_001, "AOD", "HF3PRONG", 1, //! Table for HF 3 prong candidates (Run 3 format) - o2::soa::Index<>, - hf_track_index::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - hf_track_index::Prong2Id, - hf_track_index::HFflag); - -using Hf3Prongs = Hf3Prongs_001; -using Hf3Prong = Hf3Prongs::iterator; - -DECLARE_SOA_TABLE(HfCascLf2Prongs, "AOD", "HFCASCLF2PRONG", //! Table for HF 2 prong candidates with a Cascade - o2::soa::Index<>, - hf_track_index::CollisionId, - hf_track_index::CascadeId, - hf_track_index::Prong0Id, - hf_track_index::HFflag); -using HfCascLf2Prong = HfCascLf2Prongs::iterator; - -DECLARE_SOA_TABLE(HfCascLf3Prongs, "AOD", "HFCASCLF3PRONG", //! Table for HF 3 prong candidates with a Cascade - o2::soa::Index<>, - hf_track_index::CollisionId, - hf_track_index::CascadeId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id); -using HfCascLf3Prong = HfCascLf3Prongs::iterator; - -namespace hf_track_index -{ -DECLARE_SOA_INDEX_COLUMN_FULL(ProngD0, prongD0, int, Hf2Prongs, ""); //! Index to a D0 prong -} // namespace hf_track_index - -DECLARE_SOA_TABLE(HfDstars_000, "AOD", "HFDSTAR", //! D* -> D0pi candidates (Run 2 converted format) - o2::soa::Index<>, - 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); - -using HfDstars = HfDstars_001; -using HfDstar = HfDstars::iterator; - -DECLARE_SOA_TABLE(HfCutStatus2Prong, "AOD", "HFCUTSTATUS2P", //! - hf_track_index::FlagD0ToKPi, - hf_track_index::FlagJpsiToEE, - hf_track_index::FlagJpsiToMuMu); - -DECLARE_SOA_TABLE(HfCutStatus3Prong, "AOD", "HFCUTSTATUS3P", //! - hf_track_index::FlagDplusToPiKPi, - hf_track_index::FlagLcToPKPi, - hf_track_index::FlagDsToKKPi, - hf_track_index::FlagXicToPKPi); - -DECLARE_SOA_TABLE(HfCutStatusDstar, "AOD", "HFCUTSTATUSDST", //! - hf_track_index::FlagDstarToD0Pi); - -DECLARE_SOA_TABLE(Hf2ProngMlProbs, "AOD", "HF2PRONGMLPROB", //! Table for ML scores of HF 2 prong candidates - hf_track_index::MlProbSkimD0ToKPi); - -DECLARE_SOA_TABLE(Hf3ProngMlProbs, "AOD", "HF3PRONGMLPROB", //! Table for ML scores of HF 3 prong candidates - hf_track_index::MlProbSkimDplusToPiKPi, - hf_track_index::MlProbSkimLcToPKPi, - hf_track_index::MlProbSkimDsToKKPi, - hf_track_index::MlProbSkimXicToPKPi); - -namespace hf_pv_refit -{ -DECLARE_SOA_COLUMN(PvRefitX, pvRefitX, float); //! -DECLARE_SOA_COLUMN(PvRefitY, pvRefitY, float); //! -DECLARE_SOA_COLUMN(PvRefitZ, pvRefitZ, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaX2, pvRefitSigmaX2, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaXY, pvRefitSigmaXY, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaY2, pvRefitSigmaY2, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaXZ, pvRefitSigmaXZ, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaYZ, pvRefitSigmaYZ, float); //! -DECLARE_SOA_COLUMN(PvRefitSigmaZ2, pvRefitSigmaZ2, float); //! -} // namespace hf_pv_refit - -DECLARE_SOA_TABLE(HfPvRefit2Prong, "AOD", "HFPVREFIT2PRONG", //! - hf_pv_refit::PvRefitX, - hf_pv_refit::PvRefitY, - hf_pv_refit::PvRefitZ, - hf_pv_refit::PvRefitSigmaX2, - hf_pv_refit::PvRefitSigmaXY, - hf_pv_refit::PvRefitSigmaY2, - hf_pv_refit::PvRefitSigmaXZ, - hf_pv_refit::PvRefitSigmaYZ, - hf_pv_refit::PvRefitSigmaZ2); - -DECLARE_SOA_TABLE(HfPvRefit3Prong, "AOD", "HFPVREFIT3PRONG", //! - hf_pv_refit::PvRefitX, - hf_pv_refit::PvRefitY, - hf_pv_refit::PvRefitZ, - hf_pv_refit::PvRefitSigmaX2, - hf_pv_refit::PvRefitSigmaXY, - hf_pv_refit::PvRefitSigmaY2, - hf_pv_refit::PvRefitSigmaXZ, - hf_pv_refit::PvRefitSigmaYZ, - hf_pv_refit::PvRefitSigmaZ2, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(HfPvRefitDstar, "AOD", "HFPVREFITDSTAR", //! - hf_pv_refit::PvRefitX, - hf_pv_refit::PvRefitY, - hf_pv_refit::PvRefitZ, - hf_pv_refit::PvRefitSigmaX2, - hf_pv_refit::PvRefitSigmaXY, - hf_pv_refit::PvRefitSigmaY2, - hf_pv_refit::PvRefitSigmaXZ, - hf_pv_refit::PvRefitSigmaYZ, - hf_pv_refit::PvRefitSigmaZ2, - o2::soa::Marker<2>); +DECLARE_SOA_TABLE(PidTpcTofTinyDe, "AOD", "PIDTPCTOFTINYDE", //! Table of the TPC & TOF Combined NSigma for deuteron + pid_tpc_tof_static_tiny::TpcTofNSigmaDe); // general decay properties namespace hf_cand @@ -482,7 +149,95 @@ 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 +DECLARE_SOA_COLUMN(PxProng3, pxProng3, float); //! +DECLARE_SOA_COLUMN(PyProng3, pyProng3, float); //! +DECLARE_SOA_COLUMN(PzProng3, pzProng3, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(PtProng3, ptProng3, //! + [](float px, float py) -> float { return RecoDecay::pt(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt2Prong3, pt2Prong3, //! + [](float px, float py) -> float { return RecoDecay::pt2(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(PVectorProng3, pVectorProng3, //! + [](float px, float py, float pz) -> std::array { return std::array{px, py, pz}; }); +DECLARE_SOA_COLUMN(ImpactParameter3, impactParameter3, float); //! +DECLARE_SOA_COLUMN(ErrorImpactParameter3, errorImpactParameter3, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterNormalised3, impactParameterNormalised3, //! + [](float dca, float err) -> float { return dca / err; }); +DECLARE_SOA_COLUMN(ImpactParameterZ3, impactParameterZ3, float); //! +DECLARE_SOA_COLUMN(ErrorImpactParameterZ3, errorImpactParameterZ3, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterZNormalised3, impactParameterZNormalised3, //! + [](float dca, float err) -> float { return dca / err; }); +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 +/// prong PID nsigma +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(NSigTpcDe0, nSigTpcDe0, float); //! TPC nSigma for deuteron hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTpcDe1, nSigTpcDe1, float); //! TPC nSigma for deuteron hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTpcDe2, nSigTpcDe2, float); //! TPC nSigma for deuteron 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_COLUMN(NSigTofDe0, nSigTofDe0, float); //! TOF nSigma for deuteron hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTofDe1, nSigTofDe1, float); //! TOF nSigma for deuteron hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTofDe2, nSigTofDe2, float); //! TOF nSigma for deuteron 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); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaDe0, tpcTofNSigmaDe0, //! Combined NSigma separation with the TPC & TOF detectors for deuteron - prong 0 + [](float tpcNSigmaDe0, float tofNSigmaDe0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaDe0, tofNSigmaDe0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaDe1, tpcTofNSigmaDe1, //! Combined NSigma separation with the TPC & TOF detectors for deuteron - prong 1 + [](float tpcNSigmaDe1, float tofNSigmaDe1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaDe1, tofNSigmaDe1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaDe2, tpcTofNSigmaDe2, //! Combined NSigma separation with the TPC & TOF detectors for deuteron - prong 2 + [](float tpcNSigmaDe2, float tofNSigmaDe2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaDe2, tofNSigmaDe2); }); + +// 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); }); @@ -514,9 +269,9 @@ 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); }); @@ -527,6 +282,9 @@ DECLARE_SOA_COLUMN(KfTopolChi2OverNdf, kfTopolChi2OverNdf, float); //! chi2overn 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, @@ -554,21 +312,20 @@ DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProngSqSum, impactParameterProngSqSum, [](float impParProng0, float impParProng1) -> float { return RecoDecay::sumOfSquares(impParProng0, impParProng1); }); DECLARE_SOA_DYNAMIC_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, //! [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float errDlxy, float pxM, float pyM, float ip0, float errIp0, float ip1, float errIp1, float px0, float py0, float px1, float py1) -> float { return RecoDecay::maxNormalisedDeltaIP(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, errDlxy, std::array{pxM, pyM}, std::array{ip0, ip1}, std::array{errIp0, errIp1}, std::array{std::array{px0, py0}, std::array{px1, py1}}); }); +DECLARE_SOA_DYNAMIC_COLUMN(CtXY, ctXY, //! + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float xVtxP, float yVtxP, float xVtxS, float yVtxS, const std::array& m) -> float { return RecoDecay::ctXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}}, m); }); // 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(OriginMcRec, originMcRec, int8_t); //! particle origin, reconstruction level +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! particle origin, generator level +DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); //! resonant decay channel flag, reconstruction level +DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); //! resonant decay channel flag, reconstruction level + // KF related properties DECLARE_SOA_COLUMN(KfGeoMassD0, kfGeoMassD0, float); //! mass of the D0 candidate from the KFParticle geometric fit DECLARE_SOA_COLUMN(KfGeoMassD0bar, kfGeoMassD0bar, float); //! mass of the D0bar candidate from the KFParticle geometric fit -// mapping of decay types -enum DecayType { D0ToPiK = 0, - JpsiToEE, - JpsiToMuMu, - N2ProngDecays }; // always keep N2ProngDecays at the end - } // namespace hf_cand_2prong // general columns @@ -604,7 +361,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, @@ -618,8 +375,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, @@ -633,7 +390,21 @@ 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(HfCand2Prong0PidPi, "AOD", "HFCAND2P0PIDPI", //! + hf_cand::NSigTpcPi0, hf_cand::NSigTofPi0, + hf_cand::TpcTofNSigmaPi0); +DECLARE_SOA_TABLE(HfCand2Prong1PidPi, "AOD", "HFCAND2P1PIDPI", //! + hf_cand::NSigTpcPi1, hf_cand::NSigTofPi1, + hf_cand::TpcTofNSigmaPi1); +DECLARE_SOA_TABLE(HfCand2Prong0PidKa, "AOD", "HFCAND2P0PIDKA", //! + hf_cand::NSigTpcKa0, hf_cand::NSigTofKa0, + hf_cand::TpcTofNSigmaKa0); +DECLARE_SOA_TABLE(HfCand2Prong1PidKa, "AOD", "HFCAND2P1PIDKA", //! + hf_cand::NSigTpcKa1, hf_cand::NSigTofKa1, + hf_cand::TpcTofNSigmaKa1); + using HfCand2Prong = HfCand2ProngExt; +using HfCand2ProngWPid = soa::Join; DECLARE_SOA_TABLE(HfCand2ProngKF, "AOD", "HFCAND2PKF", hf_cand::KfTopolChi2OverNdf, @@ -643,13 +414,17 @@ DECLARE_SOA_TABLE(HfCand2ProngKF, "AOD", "HFCAND2PKF", DECLARE_SOA_TABLE(HfCand2ProngMcRec, "AOD", "HFCAND2PMCREC", //! hf_cand_2prong::FlagMcMatchRec, hf_cand_2prong::OriginMcRec, + hf_cand_2prong::FlagMcDecayChanRec, hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart); + 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::FlagMcDecayChanGen, hf_cand::IdxBhadMotherPart); // cascade decay candidate table @@ -673,9 +448,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", //! @@ -708,8 +483,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, @@ -722,9 +497,9 @@ DECLARE_SOA_TABLE(HfCandCascBase, "AOD", "HFCANDCASCBASE", //! hf_cand_casc::PtV0Pos, // pT of positive V0 daughter hf_cand_casc::PtV0Neg, // pT of negative V0 daughter v0data::V0Radius, - v0data::MLambda, - v0data::MAntiLambda, - v0data::MK0Short, + v0data::legacy::MLambda, + v0data::legacy::MAntiLambda, + v0data::legacy::MK0Short, v0data::MGamma, hf_cand_casc::CtV0); // , @@ -756,18 +531,29 @@ 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 - -enum DecayType { BplusToD0Pi = 0 }; +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // main decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // main decay channel, generator level +DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel, 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(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProduct, impactParameterProduct, // Impact parameter product for B+ -> J/Psi K + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS, float impParK) -> float { return impParK * RecoDecay::impParXY(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, RecoDecay::pVec(std::array{px0, py0, pz0}, std::array{px1, py1, pz1})); }); +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProductJpsi, impactParameterProductJpsi, // J/Psi impact parameter for B+ -> J/Psi K + [](float dcaDauPos, float dcaDauNeg) -> float { return dcaDauPos * dcaDauNeg; }); enum DecayTypeMc : uint8_t { BplusToD0PiToKPiPi = 0, + BplusToD0KToKPiK, PartlyRecoDecay, OtherDecay, NDecayTypeMc }; + +enum class DecayTypeBToJpsiMc : uint8_t { BplusToJpsiKToMuMuK = 0, + PartlyRecoDecay, + OtherDecay, + NDecayTypeMc }; } // namespace hf_cand_bplus // declare dedicated BPlus decay candidate table @@ -792,8 +578,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, @@ -801,7 +587,8 @@ DECLARE_SOA_TABLE(HfCandBplusBase, "AOD", "HFCANDBPLUSBASE", hf_cand::Phi, hf_cand::Y, hf_cand::E, - hf_cand::E2); + hf_cand::E2, + hf_cand_2prong::CtXY); // extended table with expression columns that can be used as arguments of dynamic columns DECLARE_SOA_EXTENDED_TABLE_USER(HfCandBplusExt, HfCandBplusBase, "HFCANDBPLUSEXT", @@ -815,11 +602,13 @@ using HfCandBplus = soa::Join; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandBplusMcRec, "AOD", "HFCANDBPMCREC", hf_cand_bplus::FlagMcMatchRec, + hf_cand_bplus::FlagMcDecayChanRec, hf_cand_bplus::OriginMcRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandBplusMcGen, "AOD", "HFCANDBPMCGEN", hf_cand_bplus::FlagMcMatchGen, + hf_cand_bplus::FlagMcDecayChanGen, hf_cand_bplus::OriginMcGen); // specific 3-prong decay properties @@ -839,6 +628,10 @@ DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProngSqSum, impactParameterProngSqSum, [](float impParProng0, float impParProng1, float impParProng2) -> float { return RecoDecay::sumOfSquares(impParProng0, impParProng1, impParProng2); }); DECLARE_SOA_DYNAMIC_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, //! [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float errDlxy, float pxM, float pyM, float ip0, float errIp0, float ip1, float errIp1, float ip2, float errIp2, float px0, float py0, float px1, float py1, float px2, float py2) -> float { return RecoDecay::maxNormalisedDeltaIP(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, errDlxy, std::array{pxM, pyM}, std::array{ip0, ip1, ip2}, std::array{errIp0, errIp1, errIp2}, std::array{std::array{px0, py0}, std::array{px1, py1}, std::array{px2, py2}}); }); +DECLARE_SOA_DYNAMIC_COLUMN(CtXY, ctXY, //! + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2, float xVtxP, float yVtxP, float xVtxS, float yVtxS, const std::array& m) -> float { + return RecoDecay::ctXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}, std::array{px2, py2, pz2}}, m); + }); // MC matching result: DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); //! reconstruction level DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); //! generator level @@ -848,13 +641,6 @@ DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); //! swapping 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 -// mapping of decay types -enum DecayType { DplusToPiKPi = 0, - LcToPKPi, - DsToKKPi, - XicToPKPi, - N3ProngDecays }; // always keep N3ProngDecays at the end - // Ds± → K± K∓ π± or D± → K± K∓ π± enum DecayChannelDToKKPi { @@ -864,6 +650,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 +699,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 +716,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, @@ -911,7 +731,58 @@ DECLARE_SOA_TABLE(HfCand3ProngBase, "AOD", "HFCAND3PBASE", //! DECLARE_SOA_EXTENDED_TABLE_USER(HfCand3ProngExt, HfCand3ProngBase, "HFCAND3PEXT", //! hf_cand_3prong::Px, hf_cand_3prong::Py, hf_cand_3prong::Pz); +DECLARE_SOA_TABLE(HfCand3Prong0PidPi, "AOD", "HFCAND3P0PIDPI", //! + hf_cand::NSigTpcPi0, hf_cand::NSigTofPi0, + hf_cand::TpcTofNSigmaPi0); +DECLARE_SOA_TABLE(HfCand3Prong1PidPi, "AOD", "HFCAND3P1PIDPI", //! + hf_cand::NSigTpcPi1, hf_cand::NSigTofPi1, + hf_cand::TpcTofNSigmaPi1); +DECLARE_SOA_TABLE(HfCand3Prong2PidPi, "AOD", "HFCAND3P2PIDPI", //! + hf_cand::NSigTpcPi2, hf_cand::NSigTofPi2, + hf_cand::TpcTofNSigmaPi2); +DECLARE_SOA_TABLE(HfCand3Prong0PidKa, "AOD", "HFCAND3P0PIDKA", //! + hf_cand::NSigTpcKa0, hf_cand::NSigTofKa0, + hf_cand::TpcTofNSigmaKa0); +DECLARE_SOA_TABLE(HfCand3Prong1PidKa, "AOD", "HFCAND3P1PIDKA", //! + hf_cand::NSigTpcKa1, hf_cand::NSigTofKa1, + hf_cand::TpcTofNSigmaKa1); +DECLARE_SOA_TABLE(HfCand3Prong2PidKa, "AOD", "HFCAND3P2PIDKA", //! + hf_cand::NSigTpcKa2, hf_cand::NSigTofKa2, + hf_cand::TpcTofNSigmaKa2); +DECLARE_SOA_TABLE(HfCand3Prong0PidPr, "AOD", "HFCAND3P0PIDPR", //! + hf_cand::NSigTpcPr0, hf_cand::NSigTofPr0, + hf_cand::TpcTofNSigmaPr0); +DECLARE_SOA_TABLE(HfCand3Prong1PidPr, "AOD", "HFCAND3P1PIDPR", //! + hf_cand::NSigTpcPr1, hf_cand::NSigTofPr1, + hf_cand::TpcTofNSigmaPr1); +DECLARE_SOA_TABLE(HfCand3Prong2PidPr, "AOD", "HFCAND3P2PIDPR", //! + hf_cand::NSigTpcPr2, hf_cand::NSigTofPr2, + hf_cand::TpcTofNSigmaPr2); +DECLARE_SOA_TABLE(HfCand3Prong0PidDe, "AOD", "HFCAND3P0PIDDE", //! + hf_cand::NSigTpcDe0, hf_cand::NSigTofDe0, + hf_cand::TpcTofNSigmaDe0); +DECLARE_SOA_TABLE(HfCand3Prong1PidDe, "AOD", "HFCAND3P1PIDDE", //! + hf_cand::NSigTpcDe1, hf_cand::NSigTofDe1, + hf_cand::TpcTofNSigmaDe1); +DECLARE_SOA_TABLE(HfCand3Prong2PidDe, "AOD", "HFCAND3P2PIDDE", //! + hf_cand::NSigTpcDe2, hf_cand::NSigTofDe2, + hf_cand::TpcTofNSigmaDe2); + using HfCand3Prong = HfCand3ProngExt; +using HfCand3ProngWPidPiKaPr = soa::Join; +using HfCand3ProngWPidPiKa = soa::Join; +using HfCand3ProngWPidPiKaDe = soa::Join; + +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", //! @@ -920,7 +791,9 @@ DECLARE_SOA_TABLE(HfCand3ProngMcRec, "AOD", "HFCAND3PMCREC", //! hf_cand_3prong::IsCandidateSwapped, hf_cand_3prong::FlagMcDecayChanRec, hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart); + hf_cand::PdgBhadMotherPart, + hf_cand::NTracksDecayed, + hf_cand::NInteractionsWithMaterial); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCand3ProngMcGen, "AOD", "HFCAND3PMCGEN", //! @@ -929,17 +802,60 @@ DECLARE_SOA_TABLE(HfCand3ProngMcGen, "AOD", "HFCAND3PMCGEN", //! hf_cand_3prong::FlagMcDecayChanGen, hf_cand::IdxBhadMotherPart); +// declare dedicated BPlus -> J/Psi K decay candidate table +// convention: prongs 0 and 1 should be J/Psi decay products +DECLARE_SOA_TABLE(HfCandBpJPBase, "AOD", "HFCANDBPJPBASE", + // general columns + HFCAND_COLUMNS, + /* prong 2 */ hf_cand::ImpactParameterNormalised2, + hf_cand::PtProng2, + hf_cand::Pt2Prong2, + hf_cand::PVectorProng2, + // 3-prong specific columns + o2::soa::Index<>, + 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, + /* dynamic columns */ + hf_cand_3prong::M, + hf_cand_3prong::M2, + hf_cand_3prong::ImpactParameterProngSqSum, + hf_cand_bplus::ImpactParameterProduct, + hf_cand_bplus::ImpactParameterProductJpsi, + /* dynamic columns that use candidate momentum components */ + hf_cand::Pt, + hf_cand::Pt2, + hf_cand::P, + hf_cand::P2, + 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, + hf_cand::E, + hf_cand::E2, + hf_cand_3prong::CtXY); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(HfCandBpJPExt, HfCandBpJPBase, "HFCANDBPJPEXT", + hf_cand_3prong::Px, hf_cand_3prong::Py, hf_cand_3prong::Pz); + +DECLARE_SOA_TABLE(HfCandBpJPDaus, "AOD", "HFCANDBPJPDAUS", + hf_track_index::Prong0Id, hf_track_index::Prong1Id, hf_track_index::Prong2Id); + +using HfCandBplusToJpsi = soa::Join; + namespace hf_cand_casc_lf { -// mapping of decay types -enum DecayType2Prong { XiczeroOmegaczeroToXiPi = 0, - OmegaczeroToOmegaPi, - OmegaczeroToOmegaK, - N2ProngDecays }; // always keep N2ProngDecays at the end - -// mapping of decay types -enum DecayType3Prong { XicplusToXiPiPi = 0, - N3ProngDecays }; // always keep N3ProngDecays at the end +// mapping of construct method +enum ConstructMethod { DcaFitter = 0, + KfParticle }; } // namespace hf_cand_casc_lf namespace hf_cand_x @@ -953,9 +869,6 @@ DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle 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 -// mapping of decay types -enum DecayType { XToJpsiToEEPiPi = 0, - XToJpsiToMuMuPiPi }; // move this to a dedicated cascade namespace in the future? } // namespace hf_cand_x // declare dedicated X candidate table @@ -983,8 +896,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, @@ -1022,8 +935,6 @@ 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 { XiccToXicPi = 0 }; // move this to a dedicated cascade namespace in the future? } // namespace hf_cand_xicc // declare dedicated Xicc candidate table @@ -1047,8 +958,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, @@ -1138,10 +1049,10 @@ 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(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); @@ -1165,46 +1076,157 @@ DECLARE_SOA_COLUMN(ErrorDecayLengthCharmBaryon, errorDecayLengthCharmBaryon, flo DECLARE_SOA_COLUMN(ErrorDecayLengthXYCharmBaryon, errorDecayLengthXYCharmBaryon, float); // KFParticle results +DECLARE_SOA_COLUMN(XPvKf, xPvKf, float); +DECLARE_SOA_COLUMN(YPvKf, yPvKf, float); +DECLARE_SOA_COLUMN(ZPvKf, zPvKf, float); +DECLARE_SOA_COLUMN(XDecayVtxV0Kf, xDecayVtxV0Kf, float); +DECLARE_SOA_COLUMN(YDecayVtxV0Kf, yDecayVtxV0Kf, float); +DECLARE_SOA_COLUMN(ZDecayVtxV0Kf, zDecayVtxV0Kf, float); +DECLARE_SOA_COLUMN(XDecayVtxCascadeKf, xDecayVtxCascadeKf, float); +DECLARE_SOA_COLUMN(YDecayVtxCascadeKf, yDecayVtxCascadeKf, float); +DECLARE_SOA_COLUMN(ZDecayVtxCascadeKf, zDecayVtxCascadeKf, float); +DECLARE_SOA_COLUMN(PxLambdaKf, pxLambdaKf, float); +DECLARE_SOA_COLUMN(PyLambdaKf, pyLambdaKf, float); +DECLARE_SOA_COLUMN(PzLambdaKf, pzLambdaKf, float); +DECLARE_SOA_COLUMN(PxCascKf, pxCascKf, float); +DECLARE_SOA_COLUMN(PyCascKf, pyCascKf, float); +DECLARE_SOA_COLUMN(PzCascKf, pzCascKf, float); +DECLARE_SOA_COLUMN(XDecayVtxOmegaKaKf, xDecayVtxOmegaKaKf, float); +DECLARE_SOA_COLUMN(YDecayVtxOmegaKaKf, yDecayVtxOmegaKaKf, float); +DECLARE_SOA_COLUMN(ZDecayVtxOmegaKaKf, zDecayVtxOmegaKaKf, float); +DECLARE_SOA_COLUMN(PxOmegaKaKf, pxOmegaKaKf, float); +DECLARE_SOA_COLUMN(PyOmegaKaKf, pyOmegaKaKf, float); +DECLARE_SOA_COLUMN(PzOmegaKaKf, pzOmegaKaKf, float); +DECLARE_SOA_COLUMN(EtaV0DauPr, etaV0DauPr, float); +DECLARE_SOA_COLUMN(EtaV0DauPi, etaV0DauPi, float); +DECLARE_SOA_COLUMN(InvMassCascadeRej, invMassCascadeRej, float); +DECLARE_SOA_COLUMN(InvMassLambdaErr, invMassLambdaErr, float); +DECLARE_SOA_COLUMN(InvMassCascadeErr, invMassCascadeErr, float); +DECLARE_SOA_COLUMN(InvMassCascadeRejErr, invMassCascadeRejErr, float); +DECLARE_SOA_COLUMN(InvMassCharmBaryonErr, invMassCharmBaryonErr, float); +DECLARE_SOA_COLUMN(CTauOmegaKa, cTauOmegaKa, float); +DECLARE_SOA_COLUMN(Chi2GeoOmegaKa, chi2GeoOmegaKa, float); +DECLARE_SOA_COLUMN(OmegaKaldl, omegaKaldl, float); +DECLARE_SOA_COLUMN(Chi2TopoKaFromOmegaKaToPv, chi2TopoKaFromOmegaKaToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoOmegaKaToPv, chi2TopoOmegaKaToPv, float); +DECLARE_SOA_COLUMN(Chi2TopoKaToCasc, chi2TopoKaToCasc, float); +DECLARE_SOA_COLUMN(Chi2TopoCascToOmegaKa, chi2TopoCascToOmegaKa, float); +DECLARE_SOA_COLUMN(Chi2TopoKaToOmegaKa, chi2TopoKaToOmegaKa, float); +DECLARE_SOA_COLUMN(CosPaCascToOmegaKa, cosPaCascToOmegaKa, float); +DECLARE_SOA_COLUMN(CosPaXYCascToOmegaKa, cosPaXYCascToOmegaKa, float); +DECLARE_SOA_COLUMN(KfRapOmegaKa, kfRapOmegaKa, float); +DECLARE_SOA_COLUMN(KfPtKaFromOmegaKa, kfPtKaFromOmegaKa, float); +DECLARE_SOA_COLUMN(KfPtOmega, kfPtOmega, float); +DECLARE_SOA_COLUMN(KfPtOmegaKa, kfPtOmegaKa, float); +DECLARE_SOA_COLUMN(CosThetaStarKaFromOmegac, cosThetaStarKaFromOmegac, float); +DECLARE_SOA_COLUMN(CosThetaStarKaFromXic, cosThetaStarKaFromXic, float); 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(KfptOmegac, kfptOmegac, 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); + +// Kf QA results: +DECLARE_SOA_COLUMN(InvMassV0Err, invMassV0Err, float); +DECLARE_SOA_COLUMN(InvMassXiErr, invMassXiErr, float); +DECLARE_SOA_COLUMN(InvMassXic0Err, invMassXic0Err, float); +DECLARE_SOA_COLUMN(V0DauPosX, v0DauPosX, float); +DECLARE_SOA_COLUMN(V0DauPosY, v0DauPosY, float); +DECLARE_SOA_COLUMN(V0DauPosZ, v0DauPosZ, float); +DECLARE_SOA_COLUMN(V0DauPosXError, v0DauPosXError, float); +DECLARE_SOA_COLUMN(V0DauPosYError, v0DauPosYError, float); +DECLARE_SOA_COLUMN(V0DauPosZError, v0DauPosZError, float); +DECLARE_SOA_COLUMN(V0DauPosPt, v0DauPosPt, float); +DECLARE_SOA_COLUMN(V0DauNegX, v0DauNegX, float); +DECLARE_SOA_COLUMN(V0DauNegY, v0DauNegY, float); +DECLARE_SOA_COLUMN(V0DauNegZ, v0DauNegZ, float); +DECLARE_SOA_COLUMN(V0DauNegXError, v0DauNegXError, float); +DECLARE_SOA_COLUMN(V0DauNegYError, v0DauNegYError, float); +DECLARE_SOA_COLUMN(V0DauNegZError, v0DauNegZError, float); +DECLARE_SOA_COLUMN(V0DauNegPt, v0DauNegPt, float); + +DECLARE_SOA_COLUMN(V0VtxX, v0VtxX, float); +DECLARE_SOA_COLUMN(V0VtxY, v0VtxY, float); +DECLARE_SOA_COLUMN(V0VtxZ, v0VtxZ, float); +DECLARE_SOA_COLUMN(V0XError, v0XError, float); +DECLARE_SOA_COLUMN(V0YError, v0YError, float); +DECLARE_SOA_COLUMN(V0ZError, v0ZError, float); +DECLARE_SOA_COLUMN(V0Pt, v0Pt, float); +DECLARE_SOA_COLUMN(XiBachelorX, xiBachelorX, float); +DECLARE_SOA_COLUMN(XiBachelorY, xiBachelorY, float); +DECLARE_SOA_COLUMN(XiBachelorZ, xiBachelorZ, float); +DECLARE_SOA_COLUMN(XiBachelorPt, xiBachelorPt, float); +DECLARE_SOA_COLUMN(XiBachelorXError, xiBachelorXError, float); +DECLARE_SOA_COLUMN(XiBachelorYError, xiBachelorYError, float); +DECLARE_SOA_COLUMN(XiBachelorZError, xiBachelorZError, float); +DECLARE_SOA_COLUMN(XiX, xiX, float); +DECLARE_SOA_COLUMN(XiY, xiY, float); +DECLARE_SOA_COLUMN(XiZ, xiZ, float); +DECLARE_SOA_COLUMN(XiXError, xiXError, float); +DECLARE_SOA_COLUMN(XiYError, xiYError, float); +DECLARE_SOA_COLUMN(XiZError, xiZError, float); +DECLARE_SOA_COLUMN(XiPt, xiPt, float); +DECLARE_SOA_COLUMN(Xic0BachelorX, xic0BachelorX, float); +DECLARE_SOA_COLUMN(Xic0BachelorY, xic0BachelorY, float); +DECLARE_SOA_COLUMN(Xic0BachelorZ, xic0BachelorZ, float); +DECLARE_SOA_COLUMN(Xic0BachelorPt, xic0BachelorPt, float); +DECLARE_SOA_COLUMN(Xic0BachelorXError, xic0BachelorXError, float); +DECLARE_SOA_COLUMN(Xic0BachelorYError, xic0BachelorYError, float); +DECLARE_SOA_COLUMN(Xic0BachelorZError, xic0BachelorZError, float); +DECLARE_SOA_COLUMN(Xic0Pt, xic0Pt, float); +DECLARE_SOA_COLUMN(Xic0XError, xic0XError, float); +DECLARE_SOA_COLUMN(Xic0YError, xic0YError, float); +DECLARE_SOA_COLUMN(Xic0ZError, xic0ZError, float); // MC matching result: DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // reconstruction level @@ -1214,8 +1236,8 @@ DECLARE_SOA_COLUMN(CollisionMatched, collisionMatched, bool); DECLARE_SOA_COLUMN(DebugGenCharmBar, debugGenCharmBar, 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(OriginMcRec, originMcRec, int8_t); +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); DECLARE_SOA_COLUMN(PtCharmBaryonGen, ptCharmBaryonGen, float); DECLARE_SOA_COLUMN(RapidityCharmBaryonGen, rapidityCharmBaryonGen, float); @@ -1231,12 +1253,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(PtPiFromCharmBaryon, ptPiFromCharmBaryon, DECLARE_SOA_DYNAMIC_COLUMN(PtKaFromCasc, ptKaFromCasc, [](float px, float py) -> float { return RecoDecay::pt(px, py); }); -// mapping of decay types -enum DecayType { XiczeroToXiPi = 0, - OmegaczeroToXiPi, - OmegaczeroToOmegaPi, - OmegaczeroToOmegaK }; - } // end of namespace hf_cand_xic0_omegac0 // declare dedicated Omegac and Xic to Xi Pi candidate table @@ -1266,7 +1282,9 @@ DECLARE_SOA_TABLE(HfCandToXiPi, "AOD", "HFCANDTOXIPI", 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::DecLenCharmBaryon, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::ErrorDecayLengthCharmBaryon, hf_cand_xic0_omegac0::ErrorDecayLengthXYCharmBaryon, + // dynamic + hf_cand::Y); DECLARE_SOA_TABLE(HfCandToOmegaPi, "AOD", "HFCANDTOOMEGAPI", o2::soa::Index<>, @@ -1301,7 +1319,7 @@ DECLARE_SOA_TABLE(HfCandToOmegaPi, "AOD", "HFCANDTOOMEGAPI", 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::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", @@ -1339,7 +1357,7 @@ DECLARE_SOA_TABLE(HfOmegacKf, "AOD", "HFOMEGACKF", //! 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::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, @@ -1349,13 +1367,95 @@ DECLARE_SOA_TABLE(HfOmegacKf, "AOD", "HFOMEGACKF", //! 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); + +// OmegaKa reconstruct by KFParticle +DECLARE_SOA_TABLE(HfCandToOmegaKaKf, "AOD", "HFCANDTOOMEGAKAKF", + 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::XPvKf, hf_cand_xic0_omegac0::YPvKf, hf_cand_xic0_omegac0::ZPvKf, + hf_cand_xic0_omegac0::XDecayVtxV0, hf_cand_xic0_omegac0::YDecayVtxV0, hf_cand_xic0_omegac0::ZDecayVtxV0, + hf_cand_xic0_omegac0::PxLambda, hf_cand_xic0_omegac0::PyLambda, hf_cand_xic0_omegac0::PzLambda, + hf_cand_xic0_omegac0::XDecayVtxCascade, hf_cand_xic0_omegac0::YDecayVtxCascade, hf_cand_xic0_omegac0::ZDecayVtxCascade, + hf_cand_xic0_omegac0::PxCasc, hf_cand_xic0_omegac0::PyCasc, hf_cand_xic0_omegac0::PzCasc, + hf_cand_xic0_omegac0::XDecayVtxV0Kf, hf_cand_xic0_omegac0::YDecayVtxV0Kf, hf_cand_xic0_omegac0::ZDecayVtxV0Kf, + hf_cand_xic0_omegac0::PxLambdaKf, hf_cand_xic0_omegac0::PyLambdaKf, hf_cand_xic0_omegac0::PzLambdaKf, + hf_cand_xic0_omegac0::XDecayVtxCascadeKf, hf_cand_xic0_omegac0::YDecayVtxCascadeKf, hf_cand_xic0_omegac0::ZDecayVtxCascadeKf, + hf_cand_xic0_omegac0::PxCascKf, hf_cand_xic0_omegac0::PyCascKf, hf_cand_xic0_omegac0::PzCascKf, + hf_cand_xic0_omegac0::XDecayVtxOmegaKaKf, hf_cand_xic0_omegac0::YDecayVtxOmegaKaKf, hf_cand_xic0_omegac0::ZDecayVtxOmegaKaKf, + hf_cand_xic0_omegac0::PxOmegaKaKf, hf_cand_xic0_omegac0::PyOmegaKaKf, hf_cand_xic0_omegac0::PzOmegaKaKf, + hf_cand_xic0_omegac0::SignDecay, hf_cand_xic0_omegac0::EtaV0DauPr, hf_cand_xic0_omegac0::EtaV0DauPi, hf_cand_xic0_omegac0::EtaBachFromCasc, + hf_cand_xic0_omegac0::EtaBachFromCharmBaryon, hf_cand_xic0_omegac0::EtaV0, hf_cand_xic0_omegac0::EtaCascade, hf_cand_xic0_omegac0::EtaCharmBaryon, + hf_cand_xic0_omegac0::KfRapOmegaKa, hf_cand_xic0_omegac0::ImpactParBachFromCharmBaryonXY, hf_cand_xic0_omegac0::ErrImpactParBachFromCharmBaryonXY, hf_cand_xic0_omegac0::ImpactParCascXY, hf_cand_xic0_omegac0::ErrImpactParCascXY, + hf_cand_xic0_omegac0::DcaV0Dau, hf_cand_xic0_omegac0::DcaCascDau, hf_cand_xic0_omegac0::DcaCharmBaryonDau, + hf_cand_xic0_omegac0::CosPAV0, hf_cand_xic0_omegac0::CosPACasc, hf_cand_xic0_omegac0::CosPACharmBaryon, hf_cand_xic0_omegac0::CosPAXYV0, hf_cand_xic0_omegac0::CosPAXYCasc, hf_cand_xic0_omegac0::CosPAXYCharmBaryon, + hf_cand_xic0_omegac0::CosPaV0ToCasc, hf_cand_xic0_omegac0::CosPaCascToOmegaKa, hf_cand_xic0_omegac0::CosPaXYV0ToCasc, hf_cand_xic0_omegac0::CosPaXYCascToOmegaKa, + hf_cand_xic0_omegac0::Chi2GeoV0, hf_cand_xic0_omegac0::Chi2GeoCasc, hf_cand_xic0_omegac0::Chi2GeoOmegaKa, + hf_cand_xic0_omegac0::MassV0Chi2OverNdf, hf_cand_xic0_omegac0::MassCascChi2OverNdf, + hf_cand_xic0_omegac0::Chi2TopoV0ToCasc, hf_cand_xic0_omegac0::Chi2TopoKaToCasc, hf_cand_xic0_omegac0::Chi2TopoKaToOmegaKa, hf_cand_xic0_omegac0::Chi2TopoCascToOmegaKa, + hf_cand_xic0_omegac0::Chi2TopoV0ToPv, hf_cand_xic0_omegac0::Chi2TopoCascToPv, hf_cand_xic0_omegac0::Chi2TopoKaFromOmegaKaToPv, hf_cand_xic0_omegac0::Chi2TopoOmegaKaToPv, + hf_cand_xic0_omegac0::V0ldl, hf_cand_xic0_omegac0::Cascldl, hf_cand_xic0_omegac0::OmegaKaldl, + hf_cand_xic0_omegac0::DecLenV0, hf_cand_xic0_omegac0::DecLenCascade, hf_cand_xic0_omegac0::DecLenCharmBaryon, + hf_cand_xic0_omegac0::InvMassLambda, hf_cand_xic0_omegac0::InvMassLambdaErr, hf_cand_xic0_omegac0::InvMassCascade, hf_cand_xic0_omegac0::InvMassCascadeErr, hf_cand_xic0_omegac0::InvMassCascadeRej, hf_cand_xic0_omegac0::InvMassCascadeRejErr, hf_cand_xic0_omegac0::InvMassCharmBaryon, hf_cand_xic0_omegac0::InvMassCharmBaryonErr, + hf_cand_xic0_omegac0::KfPtOmegaKa, hf_cand_xic0_omegac0::KfPtKaFromOmegaKa, hf_cand_xic0_omegac0::KfPtOmega, + hf_cand_xic0_omegac0::CosThetaStarKaFromOmegac, hf_cand_xic0_omegac0::CosThetaStarKaFromXic, hf_cand_xic0_omegac0::CTauV0, hf_cand_xic0_omegac0::CTauCascade, hf_cand_xic0_omegac0::CTauOmegaKa, + hf_cand_xic0_omegac0::V0Id, v0data::PosTrackId, v0data::NegTrackId, hf_cand_xic0_omegac0::CascadeId, cascdata::BachelorId, hf_cand_xic0_omegac0::BachelorFromCharmBaryonId); + +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::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::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::CosPACasc, + 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::DcaCascDau, hf_cand_xic0_omegac0::DcaV0Dau, hf_cand_xic0_omegac0::DcaCharmBaryonDau, + 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::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::KfRapXic, + 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); +DECLARE_SOA_TABLE(HfCandToXiPiKfQa, "AOD", "HFCANDTOXIPIKFQA", + o2::soa::Index<>, + hf_cand_xic0_omegac0::InvMassLambda, hf_cand_xic0_omegac0::InvMassCascade, hf_cand_xic0_omegac0::InvMassCharmBaryon, hf_cand_xic0_omegac0::InvMassV0Err, hf_cand_xic0_omegac0::InvMassXiErr, hf_cand_xic0_omegac0::InvMassXic0Err, + hf_cand_xic0_omegac0::CollisionId, hf_track_index::V0Id, v0data::PosTrackId, v0data::NegTrackId, hf_cand_xic0_omegac0::CascadeId, hf_cand_xic0_omegac0::BachelorFromCharmBaryonId, cascdata::BachelorId, + hf_cand_xic0_omegac0::V0DauPosX, hf_cand_xic0_omegac0::V0DauPosY, hf_cand_xic0_omegac0::V0DauPosZ, hf_cand_xic0_omegac0::V0DauPosXError, hf_cand_xic0_omegac0::V0DauPosYError, hf_cand_xic0_omegac0::V0DauPosZError, hf_cand_xic0_omegac0::V0DauPosPt, + hf_cand_xic0_omegac0::V0DauNegX, hf_cand_xic0_omegac0::V0DauNegY, hf_cand_xic0_omegac0::V0DauNegZ, hf_cand_xic0_omegac0::V0DauNegXError, hf_cand_xic0_omegac0::V0DauNegYError, hf_cand_xic0_omegac0::V0DauNegZError, hf_cand_xic0_omegac0::V0DauNegPt, + hf_cand_xic0_omegac0::V0VtxX, hf_cand_xic0_omegac0::V0VtxY, hf_cand_xic0_omegac0::V0VtxZ, hf_cand_xic0_omegac0::V0XError, hf_cand_xic0_omegac0::V0YError, hf_cand_xic0_omegac0::V0ZError, hf_cand_xic0_omegac0::V0Pt, + hf_cand_xic0_omegac0::XiBachelorX, hf_cand_xic0_omegac0::XiBachelorY, hf_cand_xic0_omegac0::XiBachelorZ, hf_cand_xic0_omegac0::XiBachelorXError, hf_cand_xic0_omegac0::XiBachelorYError, hf_cand_xic0_omegac0::XiBachelorZError, hf_cand_xic0_omegac0::XiBachelorPt, + hf_cand_xic0_omegac0::XiX, hf_cand_xic0_omegac0::XiY, hf_cand_xic0_omegac0::XiZ, hf_cand_xic0_omegac0::XiXError, hf_cand_xic0_omegac0::XiYError, hf_cand_xic0_omegac0::XiZError, hf_cand_xic0_omegac0::XiPt, + hf_cand_xic0_omegac0::Xic0BachelorX, hf_cand_xic0_omegac0::Xic0BachelorY, hf_cand_xic0_omegac0::Xic0BachelorZ, hf_cand_xic0_omegac0::Xic0BachelorXError, hf_cand_xic0_omegac0::Xic0BachelorYError, hf_cand_xic0_omegac0::Xic0BachelorZError, hf_cand_xic0_omegac0::Xic0BachelorPt, + hf_cand_xic0_omegac0::XDecayVtxCharmBaryon, hf_cand_xic0_omegac0::YDecayVtxCharmBaryon, hf_cand_xic0_omegac0::ZDecayVtxCharmBaryon, hf_cand_xic0_omegac0::Xic0XError, hf_cand_xic0_omegac0::Xic0YError, hf_cand_xic0_omegac0::Xic0ZError, hf_cand_xic0_omegac0::Xic0Pt, + hf_cand_casc::V0X, hf_cand_casc::V0Y, hf_cand_casc::V0Z, hf_cand_xic0_omegac0::XDecayVtxCascade, hf_cand_xic0_omegac0::YDecayVtxCascade, hf_cand_xic0_omegac0::ZDecayVtxCascade); + // table with results of reconstruction level MC matching 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::OriginMcRec, hf_cand_xic0_omegac0::CollisionMatched, hf_cand::PtBhadMotherPart, hf_cand::PdgBhadMotherPart, @@ -1363,7 +1463,7 @@ DECLARE_SOA_TABLE(HfXicToXiPiMCRec, "AOD", "HFXICXIPIMCREC", //! 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::OriginMcRec, hf_cand_xic0_omegac0::CollisionMatched, hf_cand::PtBhadMotherPart, hf_cand::PdgBhadMotherPart, @@ -1371,7 +1471,7 @@ DECLARE_SOA_TABLE(HfOmegacToXiPiMCRec, "AOD", "HFOMCXIPIMCREC", //! 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::OriginMcRec, hf_cand_xic0_omegac0::CollisionMatched, hf_cand::PtBhadMotherPart, hf_cand::PdgBhadMotherPart, @@ -1379,7 +1479,7 @@ DECLARE_SOA_TABLE(HfToOmegaPiMCRec, "AOD", "HFTOOMEPIMCREC", //! 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::OriginMcRec, hf_cand_xic0_omegac0::CollisionMatched, hf_cand::PtBhadMotherPart, hf_cand::PdgBhadMotherPart, @@ -1388,63 +1488,109 @@ DECLARE_SOA_TABLE(HfToOmegaKMCRec, "AOD", "HFTOOMEKMCREC", //! // table with results of generator level MC matching 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>); + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginMcGen, 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>); + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginMcGen, 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>); + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginMcGen, 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>); + hf_cand_xic0_omegac0::PtCharmBaryonGen, hf_cand_xic0_omegac0::RapidityCharmBaryonGen, hf_cand_xic0_omegac0::OriginMcGen, 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(Sign, sign, int8_t); +DECLARE_SOA_COLUMN(InvMassXicPlus, invMassXicPlus, 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(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(XDecayVtxXi, xDecayVtxXi, float); -DECLARE_SOA_COLUMN(YDecayVtxXi, yDecayVtxXi, float); -DECLARE_SOA_COLUMN(ZDecayVtxXi, zDecayVtxXi, float); -DECLARE_SOA_COLUMN(XDecayVtxLambda, xDecayVtxLambda, float); -DECLARE_SOA_COLUMN(YDecayVtxLambda, yDecayVtxLambda, float); -DECLARE_SOA_COLUMN(ZDecayVtxLambda, zDecayVtxLambda, 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(InvMassXic, invMassXic, float); -DECLARE_SOA_COLUMN(Sign, sign, float); -DECLARE_SOA_COLUMN(InvMassXiPi0, invMassXiPi0, float); -DECLARE_SOA_COLUMN(InvMassXiPi1, invMassXiPi1, float); +DECLARE_SOA_COLUMN(CpaXi, cpaXi, float); +DECLARE_SOA_COLUMN(CpaXYXi, cpaXYXi, float); +DECLARE_SOA_COLUMN(CpaLambda, cpaLambda, float); +DECLARE_SOA_COLUMN(CpaXYLambda, cpaXYLambda, float); +DECLARE_SOA_COLUMN(CpaLambdaToXi, cpaLambdaToXi, float); +DECLARE_SOA_COLUMN(CpaXYLambdaToXi, cpaXYLambdaToXi, 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(Chi2TopoXicPlusToPV, chi2TopoXicPlusToPV, float); +DECLARE_SOA_COLUMN(Chi2TopoXicPlusToPVBefConst, chi2TopoXicPlusToPVBefConst, float); +DECLARE_SOA_COLUMN(Chi2PrimXi, chi2PrimXi, float); +DECLARE_SOA_COLUMN(Chi2PrimPi0, chi2PrimPi0, float); +DECLARE_SOA_COLUMN(Chi2PrimPi1, chi2PrimPi1, float); +DECLARE_SOA_COLUMN(Chi2DevPi0Pi1, chi2DevPi0Pi1, float); +DECLARE_SOA_COLUMN(Chi2DevPi0Xi, chi2DevPi0Xi, float); +DECLARE_SOA_COLUMN(Chi2DevPi1Xi, chi2DevPi1Xi, 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(Chi2TopoXiToXicPlus, chi2TopoXiToXicPlus, float); +DECLARE_SOA_COLUMN(DcaXYPi0Pi1, dcaXYPi0Pi1, float); +DECLARE_SOA_COLUMN(DcaXYPi0Xi, dcaXYPi0Xi, float); +DECLARE_SOA_COLUMN(DcaXYPi1Xi, dcaXYPi1Xi, 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); - -// mapping of decay types -enum DecayType { XicToXiPiPi = 0, // Ξc± → Ξ∓ π± π± - XicToXiResPiToXiPiPi, // Ξc± → Ξ(1530) π± → Ξ∓ π± π± - NDecayType }; +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); +DECLARE_SOA_COLUMN(DecayLengthMcGen, decayLengthMcGen, 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); +// 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); }); + } // end of namespace hf_cand_xic_to_xi_pi_pi // declare dedicated Xic to Xi Pi Pi candidate table @@ -1458,19 +1604,22 @@ DECLARE_SOA_TABLE(HfCandXicBase, "AOD", "HFCANDXICBASE", 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::InvMassXic, hf_cand_xic_to_xi_pi_pi::Sign, + 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::XDecayVtxXi, hf_cand_xic_to_xi_pi_pi::YDecayVtxXi, hf_cand_xic_to_xi_pi_pi::ZDecayVtxXi, - hf_cand_xic_to_xi_pi_pi::XDecayVtxLambda, hf_cand_xic_to_xi_pi_pi::YDecayVtxLambda, hf_cand_xic_to_xi_pi_pi::ZDecayVtxLambda, - 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::InvMassXiPi0, hf_cand_xic_to_xi_pi_pi::InvMassXiPi1, + 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::CpaXi, hf_cand_xic_to_xi_pi_pi::CpaXYXi, hf_cand_xic_to_xi_pi_pi::CpaLambda, hf_cand_xic_to_xi_pi_pi::CpaXYLambda, hf_cand_xic_to_xi_pi_pi::CpaLambdaToXi, hf_cand_xic_to_xi_pi_pi::CpaXYLambdaToXi, + 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::RSecondaryVertex, hf_cand::DecayLength, hf_cand::DecayLengthXY, hf_cand::DecayLengthNormalised, @@ -1479,46 +1628,69 @@ DECLARE_SOA_TABLE(HfCandXicBase, "AOD", "HFCANDXICBASE", 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::Cpa, + hf_cand::CpaXY, hf_cand::Ct, hf_cand::ImpactParameterXY, hf_cand_3prong::MaxNormalisedDeltaIP, hf_cand::Eta, hf_cand::Phi, - hf_cand::Y, - hf_cand::E); + 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; +// table with KF-specific variables DECLARE_SOA_TABLE(HfCandXicKF, "AOD", "HFCANDXICKF", - cascdata::KFCascadeChi2, cascdata::KFV0Chi2, hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPV, 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::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, + cascdata::KFCascadeChi2, cascdata::KFV0Chi2, + hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPVBefConst, hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPV, + hf_cand_xic_to_xi_pi_pi::Chi2PrimXi, hf_cand_xic_to_xi_pi_pi::Chi2PrimPi0, hf_cand_xic_to_xi_pi_pi::Chi2PrimPi1, + hf_cand_xic_to_xi_pi_pi::Chi2DevPi0Pi1, hf_cand_xic_to_xi_pi_pi::Chi2DevPi0Xi, hf_cand_xic_to_xi_pi_pi::Chi2DevPi1Xi, hf_cand_xic_to_xi_pi_pi::DcaPi0Pi1, hf_cand_xic_to_xi_pi_pi::DcaPi0Xi, hf_cand_xic_to_xi_pi_pi::DcaPi1Xi, - cascdata::DCACascDaughters); + hf_cand_xic_to_xi_pi_pi::DcaXYPi0Pi1, hf_cand_xic_to_xi_pi_pi::DcaXYPi0Xi, hf_cand_xic_to_xi_pi_pi::DcaXYPi1Xi); // table with results of reconstruction level MC matching -DECLARE_SOA_TABLE(HfCandXicMcRec, "AOD", "HFCANDXICMCREC", //! +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); + hf_cand_xic_to_xi_pi_pi::OriginMcRec); // table with results of generator level MC matching -DECLARE_SOA_TABLE(HfCandXicMcGen, "AOD", "HFCANDXICMCGEN", //! +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); + hf_cand_xic_to_xi_pi_pi::OriginMcGen, + hf_cand::PdgBhadMotherPart, + hf_cand_xic_to_xi_pi_pi::DecayLengthMcGen); + +// table with residuals and pulls of PV +DECLARE_SOA_TABLE(HfCandXicResid, "AOD", "HFCANDXICRESID", + hf_cand_xic_to_xi_pi_pi::OriginMcGen, + hf_cand_xic_to_xi_pi_pi::PResidual, + hf_cand_xic_to_xi_pi_pi::PtResidual, + hf_cand_xic_to_xi_pi_pi::XPvResidual, + hf_cand_xic_to_xi_pi_pi::YPvResidual, + hf_cand_xic_to_xi_pi_pi::ZPvResidual, + hf_cand_xic_to_xi_pi_pi::XPvPull, + hf_cand_xic_to_xi_pi_pi::YPvPull, + hf_cand_xic_to_xi_pi_pi::ZPvPull, + hf_cand_xic_to_xi_pi_pi::XSvResidual, + hf_cand_xic_to_xi_pi_pi::YSvResidual, + hf_cand_xic_to_xi_pi_pi::ZSvResidual, + hf_cand_xic_to_xi_pi_pi::XSvPull, + hf_cand_xic_to_xi_pi_pi::YSvPull, + hf_cand_xic_to_xi_pi_pi::ZSvPull); // specific chic candidate properties namespace hf_cand_chic @@ -1533,9 +1705,6 @@ DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // particle 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(JpsiToMuMuMass, jpsiToMuMuMass, float); // Jpsi mass -// mapping of decay types -enum DecayType { ChicToJpsiToEEGamma = 0, - ChicToJpsiToMuMuGamma }; // move this to a dedicated cascade namespace in the future? } // namespace hf_cand_chic // declare dedicated chi_c candidate table @@ -1562,8 +1731,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, @@ -1596,13 +1765,21 @@ namespace hf_cand_lb { DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_0"); // Lb 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 -// mapping of decay types -enum DecayType { LbToLcPi }; // move this to a dedicated cascade namespace in the future? +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // main decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // main decay channel, generator level +DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel, 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(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level + +enum DecayTypeMc : uint8_t { LbToLcPiToPKPiPi = 0, + LbToLcKToPKPiK, + B0ToDplusPiToPiKPiPi, + PartlyRecoDecay, + OtherDecay, + NDecayTypeMc }; } // namespace hf_cand_lb // declare dedicated Lb candidate table @@ -1614,8 +1791,6 @@ DECLARE_SOA_TABLE(HfCandLbBase, "AOD", "HFCANDLBBASE", hf_cand::PxProng1, hf_cand::PyProng1, hf_cand::PzProng1, hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, - hf_cand_lb::Prong0Id, hf_track_index::Prong1Id, - hf_track_index::HFflag, /* dynamic columns */ hf_cand_2prong::M, hf_cand_2prong::M2, @@ -1626,8 +1801,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, @@ -1641,17 +1816,22 @@ DECLARE_SOA_TABLE(HfCandLbBase, "AOD", "HFCANDLBBASE", DECLARE_SOA_EXTENDED_TABLE_USER(HfCandLbExt, HfCandLbBase, "HFCANDLBEXT", hf_cand_2prong::Px, hf_cand_2prong::Py, hf_cand_2prong::Pz); -using HfCandLb = HfCandLbExt; +DECLARE_SOA_TABLE(HfCandLbProngs, "AOD", "HFCANDLBPRONGS", + hf_cand_lb::Prong0Id, hf_track_index::Prong1Id); + +using HfCandLb = soa::Join; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandLbMcRec, "AOD", "HFCANDLBMCREC", //! hf_cand_lb::FlagMcMatchRec, + hf_cand_lb::FlagMcDecayChanRec, hf_cand_lb::OriginMcRec, hf_cand_lb::DebugMcRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandLbMcGen, "AOD", "HFCANDLBMCGEN", //! hf_cand_lb::FlagMcMatchGen, + hf_cand_lb::FlagMcDecayChanGen, hf_cand_lb::OriginMcGen); // specific B0 candidate properties @@ -1659,17 +1839,20 @@ 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 - -// mapping of decay types -enum DecayType { B0ToDPi }; +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // main decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // main decay channel, generator level +DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel, 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(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level enum DecayTypeMc : uint8_t { B0ToDplusPiToPiKPiPi = 0, B0ToDsPiToKKPiPi, + BsToDsPiToKKPiPi, + B0ToDplusKToPiKPiK, + B0ToDstarPiToD0PiPiToKPiPiPi, PartlyRecoDecay, OtherDecay, NDecayTypeMc }; @@ -1696,8 +1879,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, @@ -1707,6 +1890,42 @@ DECLARE_SOA_TABLE(HfCandB0Base, "AOD", "HFCANDB0BASE", hf_cand::E, hf_cand::E2); +DECLARE_SOA_TABLE(HfCandB0DStar, "AOD", "HFCANDB0DSTAR", + // general columns + HFCAND_COLUMNS, + /* prong 2 */ + hf_cand::ImpactParameterNormalised2, + hf_cand::PtProng2, + hf_cand::Pt2Prong2, + hf_cand::PVectorProng2, + // 3-prong specific columns + 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, + /* dynamic columns */ + hf_cand_3prong::M, + hf_cand_3prong::M2, + hf_cand_2prong::ImpactParameterProduct, + hf_cand_3prong::ImpactParameterProngSqSum, + /* dynamic columns that use candidate momentum components */ + hf_cand::Pt, + hf_cand::Pt2, + hf_cand::P, + hf_cand::P2, + 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, + 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(HfCandB0Ext, HfCandB0Base, "HFCANDB0EXT", hf_cand_2prong::Px, hf_cand_2prong::Py, hf_cand_2prong::Pz); @@ -1716,15 +1935,21 @@ DECLARE_SOA_TABLE(HfCandB0Prongs, "AOD", "HFCANDB0PRONGS", using HfCandB0 = soa::Join; +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(HfCandB0DStExt, HfCandB0DStar, "HFCANDB0DSTEXT", + hf_cand_3prong::Px, hf_cand_3prong::Py, hf_cand_3prong::Pz); + // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandB0McRec, "AOD", "HFCANDB0MCREC", hf_cand_b0::FlagMcMatchRec, + hf_cand_b0::FlagMcDecayChanRec, hf_cand_b0::OriginMcRec, hf_cand_b0::DebugMcRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandB0McGen, "AOD", "HFCANDB0MCGEN", hf_cand_b0::FlagMcMatchGen, + hf_cand_b0::FlagMcDecayChanGen, hf_cand_b0::OriginMcGen); // specific Bs candidate properties @@ -1732,16 +1957,39 @@ 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 - -// mapping of decay types -enum DecayType { BsToDsPi }; +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); // main decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcMatchGen, flagMcMatchGen, int8_t); // main decay channel, generator level +DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); // resonant decay channel, reconstruction level +DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); // resonant decay channel, 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(FlagWrongCollision, flagWrongCollision, int8_t); // reconstruction level +DECLARE_SOA_COLUMN(DebugMcRec, debugMcRec, int8_t); // debug flag for mis-association reconstruction level +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProduct, impactParameterProduct, // Impact parameter product for Bs -> J/Psi phi + [](float pxJpsiDauPos, float pyJpsiDauPos, float pzJpsiDauPos, float pxJpsiDauNeg, float pyJpsiDauNeg, float pzJpsiDauNeg, float pxLfTrack0, float pyLfTrack0, float pzLfTrack0, float pxLfTrack1, float pyLfTrack1, float pzLfTrack1, float xVtxP, float yVtxP, float zVtxP, float xVtxS, float yVtxS, float zVtxS) -> float { + float impParJpsi = RecoDecay::impParXY(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, RecoDecay::pVec(std::array{pxJpsiDauPos, pyJpsiDauPos, pzJpsiDauPos}, std::array{pxJpsiDauNeg, pyJpsiDauNeg, pzJpsiDauNeg})); + float impParPhi = RecoDecay::impParXY(std::array{xVtxP, yVtxP, zVtxP}, std::array{xVtxS, yVtxS, zVtxS}, RecoDecay::pVec(std::array{pxLfTrack0, pyLfTrack0, pzLfTrack0}, std::array{pxLfTrack1, pyLfTrack1, pzLfTrack1})); + return impParJpsi * impParPhi; + }); +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProductJpsi, impactParameterProductJpsi, // J/Psi impact parameter for Bs -> J/Psi phi + [](float dcaDauPos, float dcaDauNeg) -> float { return dcaDauPos * dcaDauNeg; }); +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProductPhi, impactParameterProductPhi, // J/Psi impact parameter for Bs -> J/Psi phi + [](float dcaLfTrack0, float dcaLfTrack1) -> float { return dcaLfTrack0 * dcaLfTrack1; }); + +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+ π±) π∓ + BsToDsKToPhiPiKToKKPiK, // Bs(bar) → Ds± K∓ → (Phi π∓) K∓ → (K- K+ π±) K∓ + BsToDsKToK0starKKToKKPiK, // Bs(bar) → Ds± K∓ → (K0* K±) K∓ → (K- K+ π±) K∓ + PartlyRecoDecay, // 4 final state particles have another common b-hadron ancestor + OtherDecay, + NDecayTypeMc }; // counter of differentiated MC decay types -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 class DecayTypeBToJpsiMc : uint8_t { BsToJpsiPhiToMuMuKK = 0, // Bs(bar) → J/Psi Phi → (µ+ µ-) (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 @@ -1754,8 +2002,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, @@ -1768,8 +2014,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, @@ -1777,21 +2023,104 @@ DECLARE_SOA_TABLE(HfCandBsBase, "AOD", "HFCANDBSBASE", hf_cand::Phi, hf_cand::Y, hf_cand::E, - hf_cand::E2); + hf_cand::E2, + hf_cand_2prong::CtXY, + 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", - hf_cand_bs::FlagMcMatchRec); + hf_cand_bs::FlagMcMatchRec, + hf_cand_bs::FlagMcDecayChanRec); // table with results of generator level MC matching DECLARE_SOA_TABLE(HfCandBsMcGen, "AOD", "HFCANDBSMCGEN", - hf_cand_bs::FlagMcMatchGen); + hf_cand_bs::FlagMcMatchGen, + hf_cand_bs::FlagMcDecayChanGen); + +namespace hf_cand_4prong +{ +DECLARE_SOA_EXPRESSION_COLUMN(Px, px, //! + float, 1.f * aod::hf_cand::pxProng0 + 1.f * aod::hf_cand::pxProng1 + 1.f * aod::hf_cand::pxProng2 + 1.f * aod::hf_cand::pxProng3); +DECLARE_SOA_EXPRESSION_COLUMN(Py, py, //! + float, 1.f * aod::hf_cand::pyProng0 + 1.f * aod::hf_cand::pyProng1 + 1.f * aod::hf_cand::pyProng2 + 1.f * aod::hf_cand::pyProng3); +DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, //! + float, 1.f * aod::hf_cand::pzProng0 + 1.f * aod::hf_cand::pzProng1 + 1.f * aod::hf_cand::pzProng2 + 1.f * aod::hf_cand::pzProng3); +DECLARE_SOA_DYNAMIC_COLUMN(M, m, //! + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2, float px3, float py3, float pz3, const std::array& m) -> float { return RecoDecay::m(std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}, std::array{px2, py2, pz2}, std::array{px3, py3, pz3}}, m); }); +DECLARE_SOA_DYNAMIC_COLUMN(M2, m2, //! + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2, float px3, float py3, float pz3, const std::array& m) -> float { return RecoDecay::m2(std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}, std::array{px2, py2, pz2}, std::array{px3, py3, pz3}}, m); }); +DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterProngSqSum, impactParameterProngSqSum, //! + [](float impParProng0, float impParProng1, float impParProng2, float impParProng3) -> float { return RecoDecay::sumOfSquares(impParProng0, impParProng1, impParProng2, impParProng3); }); +DECLARE_SOA_DYNAMIC_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, //! + [](float xVtxP, float yVtxP, float xVtxS, float yVtxS, float errDlxy, float pxM, float pyM, float ip0, float errIp0, float ip1, float errIp1, float ip2, float errIp2, float ip3, float errIp3, float px0, float py0, float px1, float py1, float px2, float py2, float px3, float py3) -> float { return RecoDecay::maxNormalisedDeltaIP(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, errDlxy, std::array{pxM, pyM}, std::array{ip0, ip1, ip2, ip3}, std::array{errIp0, errIp1, errIp2, errIp3}, std::array{std::array{px0, py0}, std::array{px1, py1}, std::array{px2, py2}, std::array{px3, py3}}); }); +DECLARE_SOA_DYNAMIC_COLUMN(CtXY, ctXY, //! + [](float px0, float py0, float pz0, float px1, float py1, float pz1, float px2, float py2, float pz2, float px3, float py3, float pz3, float xVtxP, float yVtxP, float xVtxS, float yVtxS, const std::array& m) -> float { return RecoDecay::ctXY(std::array{xVtxP, yVtxP}, std::array{xVtxS, yVtxS}, std::array{std::array{px0, py0, pz0}, std::array{px1, py1, pz1}, std::array{px2, py2, pz2}, std::array{px3, py3, pz3}}, m); }); +} // namespace hf_cand_4prong + +// declare dedicated Bs -> J/Psi phi decay candidate table +// convention: prongs 0 and 1 should be J/Psi decay products, 2 and 3 should be phi decay products +DECLARE_SOA_TABLE(HfCandBsJPBase, "AOD", "HFCANDBSJPBASE", + // general columns + HFCAND_COLUMNS, + /* prong 2 */ hf_cand::ImpactParameterNormalised2, + hf_cand::PtProng2, + hf_cand::Pt2Prong2, + hf_cand::PVectorProng2, + /* prong 3 */ hf_cand::ImpactParameterNormalised3, + hf_cand::PtProng3, + hf_cand::Pt2Prong3, + hf_cand::PVectorProng3, + // 4-prong specific columns + o2::soa::Index<>, + 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::PxProng3, hf_cand::PyProng3, hf_cand::PzProng3, + hf_cand::ImpactParameter0, hf_cand::ImpactParameter1, hf_cand::ImpactParameter2, hf_cand::ImpactParameter3, + hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, hf_cand::ErrorImpactParameter2, hf_cand::ErrorImpactParameter3, + /* dynamic columns */ + hf_cand_4prong::M, + hf_cand_4prong::M2, + hf_cand_4prong::ImpactParameterProngSqSum, + hf_cand_bs::ImpactParameterProduct, + hf_cand_bs::ImpactParameterProductJpsi, + hf_cand_bs::ImpactParameterProductPhi, + /* dynamic columns that use candidate momentum components */ + hf_cand::Pt, + hf_cand::Pt2, + hf_cand::P, + hf_cand::P2, + hf_cand::PVector, + hf_cand::Cpa, + hf_cand::CpaXY, + hf_cand::Ct, + hf_cand::ImpactParameterXY, + hf_cand_4prong::MaxNormalisedDeltaIP, + hf_cand::Eta, + hf_cand::Phi, + hf_cand::Y, + hf_cand::E, + hf_cand::E2, + hf_cand_4prong::CtXY, + o2::soa::Marker<1>); + +// extended table with expression columns that can be used as arguments of dynamic columns +DECLARE_SOA_EXTENDED_TABLE_USER(HfCandBsJPExt, HfCandBsJPBase, "HFCANDBSJPEXT", + hf_cand_4prong::Px, hf_cand_4prong::Py, hf_cand_4prong::Pz); + +DECLARE_SOA_TABLE(HfCandBsJPDaus, "AOD", "HFCANDBSJPDAUS", + hf_cand_bs::Prong0Id, hf_track_index::Prong1Id, hf_track_index::Prong2Id, hf_track_index::Prong3Id); + +using HfCandBsToJpsi = soa::Join; // specific Σc0,++ candidate properties namespace hf_cand_sigmac @@ -1800,16 +2129,27 @@ DECLARE_SOA_INDEX_COLUMN_FULL(ProngLc, prongLc, int, HfCand3Prong, ""); DECLARE_SOA_COLUMN(Charge, charge, int8_t); //! // Σc charge(either 0 or ++) DECLARE_SOA_COLUMN(StatusSpreadLcMinvPKPiFromPDG, statusSpreadLcMinvPKPiFromPDG, int); //! // Λc Minv(pKpi) spread from PDG Λc mass DECLARE_SOA_COLUMN(StatusSpreadLcMinvPiKPFromPDG, statusSpreadLcMinvPiKPFromPDG, int); //! // Λc Minv(piKp) spread from PDG Λc mass +DECLARE_SOA_COLUMN(SoftPiDcaXY, softPiDcaXY, float); //! soft-pion impact parameter in xy +DECLARE_SOA_COLUMN(SoftPiDcaZ, softPiDcaZ, float); //! soft-pion impact parameter in z DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, HfCand3Prong, "_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 - -// mapping of decay types -enum DecayType { Sc0ToPKPiPi = 0, - ScplusplusToPKPiPi }; +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(ParticleAntiparticle, particleAntiparticle, int8_t); //! particle or antiparticle + +enum Species : int { Sc2455 = 0, + Sc2520, + NSpecies }; +enum Decays : int { PKPi = 0, + PiKP, + NDecays }; +enum Conjugated : int { Particle = 0, + Antiparticle, + NConjugated }; +constexpr int ChargeNull = 0; +constexpr int ChargePlusPlus = 2; } // namespace hf_cand_sigmac // declare dedicated Σc0,++ decay candidate table @@ -1829,6 +2169,7 @@ DECLARE_SOA_TABLE(HfCandScBase, "AOD", "HFCANDSCBASE", /* Σc0,++ specific columns */ hf_cand_sigmac::Charge, hf_cand_sigmac::StatusSpreadLcMinvPKPiFromPDG, hf_cand_sigmac::StatusSpreadLcMinvPiKPFromPDG, + hf_cand_sigmac::SoftPiDcaXY, hf_cand_sigmac::SoftPiDcaZ, /* prong 0 */ // hf_cand::ImpactParameterNormalised0, hf_cand::PtProng0, @@ -1864,21 +2205,23 @@ DECLARE_SOA_TABLE(HfCandScMcRec, "AOD", "HFCANDSCMCREC", //! hf_cand_sigmac::FlagMcMatchRec, hf_cand_sigmac::OriginMcRec, hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart); + hf_cand::PdgBhadMotherPart, + hf_cand_sigmac::ParticleAntiparticle); // table with results of generation level MC matching DECLARE_SOA_TABLE(HfCandScMcGen, "AOD", "HFCANDSCMCGEN", //! hf_cand_sigmac::FlagMcMatchGen, hf_cand_sigmac::OriginMcGen, - hf_cand::IdxBhadMotherPart); + hf_cand::IdxBhadMotherPart, + hf_cand_sigmac::ParticleAntiparticle); // 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(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: @@ -1996,9 +2339,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); }); @@ -2020,7 +2363,11 @@ DECLARE_SOA_DYNAMIC_COLUMN(NormalisedImpParamZSoftPi, normalisedImpParamZSoftPi, DECLARE_SOA_COLUMN(PxSoftPi, pxSoftPi, float); DECLARE_SOA_COLUMN(PySoftPi, pySoftPi, float); DECLARE_SOA_COLUMN(PzSoftPi, pzSoftPi, float); +DECLARE_SOA_COLUMN(DcaYSoftPi, dcaYSoftPi, float); +DECLARE_SOA_COLUMN(SigmaYSoftPi, sigmaYSoftPi, float); DECLARE_SOA_COLUMN(SignSoftPi, signSoftPi, int8_t); +DECLARE_SOA_COLUMN(TPCNSigmaPiSoftPi, tpcNSigmaPiSoftPi, float); //! NsigmaTPCPi for soft pi, o2-linter: disable=name/o2-column (written to disk) +DECLARE_SOA_COLUMN(TOFNSigmaPiSoftPi, tofNSigmaPiSoftPi, float); //! NsigmaTOFPi for soft pi, o2-linter: disable=name/o2-column (written to disk) // Dstar momenta DECLARE_SOA_EXPRESSION_COLUMN(PxDstar, pxDstar, float, 1.f * aod::hf_cand::pxProng0 + 1.f * aod::hf_cand::pxProng1 + 1.f * aod::hf_cand_dstar::pxSoftPi); DECLARE_SOA_EXPRESSION_COLUMN(PyDstar, pyDstar, float, 1.f * aod::hf_cand::pyProng0 + 1.f * aod::hf_cand::pyProng1 + 1.f * aod::hf_cand_dstar::pySoftPi); @@ -2036,20 +2383,17 @@ DECLARE_SOA_DYNAMIC_COLUMN(InvMassAntiDstar, invMassAntiDstar, DECLARE_SOA_DYNAMIC_COLUMN(PtSoftPi, ptSoftPi, [](float pxSoftPi, float pySoftPi) -> float { return RecoDecay::pt(pxSoftPi, pySoftPi); }); DECLARE_SOA_DYNAMIC_COLUMN(PVecSoftPi, pVecSoftPi, [](float px, float py, float pz) -> std::array { return std::array{px, py, pz}; }); - +DECLARE_SOA_DYNAMIC_COLUMN(TPCTOFNSigmaPiSoftPi, tpcTofNSigmaPiSoftPi, //! Combination of NsigmaTPC and NsigmaTOF, o2-linter: disable=name/o2-column (written to disk) + [](float tpcNSigmaPiSoftPi, float TOFNSigmaPiSoftPi) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPiSoftPi, TOFNSigmaPiSoftPi); }); // 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(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, - NDstarDecayType -}; - } // namespace hf_cand_dstar /// D0 (table) from DStar @@ -2090,8 +2434,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, @@ -2105,7 +2449,27 @@ DECLARE_SOA_TABLE(HfD0FromDstarBase, "AOD", "HFD0FRMDSTR", DECLARE_SOA_EXTENDED_TABLE_USER(HfD0FromDstarExt, HfD0FromDstarBase, "HFD0FRMDSTREXT", hf_cand_dstar::PxD0, hf_cand_dstar::PyD0, hf_cand_dstar::PzD0); +DECLARE_SOA_TABLE(HfCandDstarProng0PidPi, "AOD", "HFDSTRP0PIDPI", //! + hf_cand::NSigTpcPi0, hf_cand::NSigTofPi0, + hf_cand::TpcTofNSigmaPi0); +DECLARE_SOA_TABLE(HfCandDstarProng1PidPi, "AOD", "HFDSTRP1PIDPI", //! + hf_cand::NSigTpcPi1, hf_cand::NSigTofPi1, + hf_cand::TpcTofNSigmaPi1); +DECLARE_SOA_TABLE(HfCandDstarProng2PidPi, "AOD", "HFDSTRP2PIDPI", //! + hf_cand::NSigTpcPi2, hf_cand::NSigTofPi2, + hf_cand::TpcTofNSigmaPi2); +DECLARE_SOA_TABLE(HfCandDstarProng0PidKa, "AOD", "HFDSTRP0PIDKA", //! + hf_cand::NSigTpcKa0, hf_cand::NSigTofKa0, + hf_cand::TpcTofNSigmaKa0); +DECLARE_SOA_TABLE(HfCandDstarProng1PidKa, "AOD", "HFDSTRP1PIDKA", //! + hf_cand::NSigTpcKa1, hf_cand::NSigTofKa1, + hf_cand::TpcTofNSigmaKa1); +DECLARE_SOA_TABLE(HfCandDstarProng2PidKa, "AOD", "HFDSTRP2PIDKA", //! + hf_cand::NSigTpcKa2, hf_cand::NSigTofKa2, + hf_cand::TpcTofNSigmaKa2); + using HfD0FromDstar = HfD0FromDstarExt; +using HfD0FromDstarWPid = soa::Join; DECLARE_SOA_TABLE(HfCandDstarBase, "AOD", "HFCANDDSTRBASE", o2::soa::Index<>, @@ -2156,17 +2520,22 @@ DECLARE_SOA_EXTENDED_TABLE_USER(HfCandDstarExt, HfCandDstarBase, "HFCANDDSTREXT" using HfCandDstars = HfCandDstarExt; using HfCandDstar = HfCandDstars::iterator; +using HfCandDstarsWPid = soa::Join; // table with results of reconstruction level MC matching DECLARE_SOA_TABLE(HfCandDstarMcRec, "AOD", "HFCANDDSTRMCREC", hf_cand_dstar::FlagMcMatchRec, + hf_cand_dstar::FlagMcMatchRecD0, hf_cand_dstar::OriginMcRec, hf_cand::PtBhadMotherPart, - hf_cand::PdgBhadMotherPart); + 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::FlagMcMatchGenD0, hf_cand_dstar::OriginMcGen, hf_cand::IdxBhadMotherPart); diff --git a/PWGHF/DataModel/CandidateSelectionTables.h b/PWGHF/DataModel/CandidateSelectionTables.h index 071ad7c0431..839c289d6f5 100644 --- a/PWGHF/DataModel/CandidateSelectionTables.h +++ b/PWGHF/DataModel/CandidateSelectionTables.h @@ -11,17 +11,15 @@ /// \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_ -#include - -#include "Common/Core/RecoDecay.h" -#include "Common/Core/TrackSelectorPID.h" +#include -#include "PWGHF/Core/SelectorCuts.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include namespace o2::aod { @@ -136,11 +134,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 @@ -166,6 +164,14 @@ DECLARE_SOA_TABLE(HfSelLc, "AOD", "HFSELLC", //! DECLARE_SOA_TABLE(HfMlLcToPKPi, "AOD", "HFMLLc", //! hf_sel_candidate_lc::MlProbLcToPKPi, hf_sel_candidate_lc::MlProbLcToPiKP); +namespace hf_sel_candidate_cd +{ +DECLARE_SOA_COLUMN(IsSelCdToDeKPi, isSelCdToDeKPi, int); //! +DECLARE_SOA_COLUMN(IsSelCdToPiKDe, isSelCdToPiKDe, int); //! +} // namespace hf_sel_candidate_cd +DECLARE_SOA_TABLE(HfSelCd, "AOD", "HFSELCD", //! + hf_sel_candidate_cd::IsSelCdToDeKPi, hf_sel_candidate_cd::IsSelCdToPiKDe); + namespace hf_sel_candidate_lc_alice3 { DECLARE_SOA_COLUMN(IsSelLcToPKPiNoPid, isSelLcToPKPiNoPid, int); //! @@ -233,10 +239,12 @@ DECLARE_SOA_TABLE(HfSelJpsi, "AOD", "HFSELJPSI", //! namespace hf_sel_candidate_lc_to_k0s_p { DECLARE_SOA_COLUMN(IsSelLcToK0sP, isSelLcToK0sP, int); +DECLARE_SOA_COLUMN(MlProbLcToK0sP, mlProbLcToK0sP, std::vector); //! } // namespace hf_sel_candidate_lc_to_k0s_p - DECLARE_SOA_TABLE(HfSelLcToK0sP, "AOD", "HFSELLCK0SP", //! hf_sel_candidate_lc_to_k0s_p::IsSelLcToK0sP); +DECLARE_SOA_TABLE(HfMlLcToK0sP, "AOD", "HFMLLcK0sP", //! + hf_sel_candidate_lc_to_k0s_p::MlProbLcToK0sP); namespace hf_sel_candidate_b0 { @@ -252,19 +260,23 @@ DECLARE_SOA_TABLE(HfMlB0ToDPi, "AOD", "HFMLB0", //! namespace hf_sel_candidate_bs { -DECLARE_SOA_COLUMN(IsSelBsToDsPi, isSelBsToDsPi, int); //! -DECLARE_SOA_COLUMN(MlProbBsToDsPi, mlProbBsToDsPi, std::vector); //! +DECLARE_SOA_COLUMN(IsSelBsToDsPi, isSelBsToDsPi, int); //! +DECLARE_SOA_COLUMN(MlProbBsToDsPi, mlProbBsToDsPi, std::vector); //! +DECLARE_SOA_COLUMN(MlProbBsToJpsiPhi, mlProbBsToJpsiPhi, std::vector); //! } // namespace hf_sel_candidate_bs DECLARE_SOA_TABLE(HfSelBsToDsPi, "AOD", "HFSELBS", //! hf_sel_candidate_bs::IsSelBsToDsPi); DECLARE_SOA_TABLE(HfMlBsToDsPi, "AOD", "HFMLBS", //! hf_sel_candidate_bs::MlProbBsToDsPi); +DECLARE_SOA_TABLE(HfMlBsToJpsiPhi, "AOD", "HFMLBSTOJPSIPHI", //! + hf_sel_candidate_bs::MlProbBsToDsPi); namespace hf_sel_candidate_bplus { -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 +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 +DECLARE_SOA_COLUMN(MlProbBplusToJpsiK, mlProbBplusToJpsiK, float); //! ML score of B+ candidate for signal class } // namespace hf_sel_candidate_bplus DECLARE_SOA_TABLE(HfSelBplusToD0Pi, "AOD", "HFSELBPLUS", //! @@ -273,13 +285,19 @@ DECLARE_SOA_TABLE(HfSelBplusToD0Pi, "AOD", "HFSELBPLUS", //! DECLARE_SOA_TABLE(HfMlBplusToD0Pi, "AOD", "HFMLBPLUS", //! hf_sel_candidate_bplus::MlProbBplusToD0Pi); +DECLARE_SOA_TABLE(HfMlBplusToJpsiK, "AOD", "HFMLBPLUSTOJPSIK", //! + hf_sel_candidate_bplus::MlProbBplusToJpsiK); namespace hf_sel_candidate_lb { -DECLARE_SOA_COLUMN(IsSelLbToLcPi, isSelLbToLcPi, int); //! +DECLARE_SOA_COLUMN(IsSelLbToLcPi, isSelLbToLcPi, int); //! selection flag on Lb candidate +DECLARE_SOA_COLUMN(MlProbLbToLcPi, mlProbLbToLcPi, float); //! ML score of Lb candidate for signal class + } // namespace hf_sel_candidate_lb DECLARE_SOA_TABLE(HfSelLbToLcPi, "AOD", "HFSELLB", //! hf_sel_candidate_lb::IsSelLbToLcPi); +DECLARE_SOA_TABLE(HfMlLbToLcPi, "AOD", "HFMLLB", //! + hf_sel_candidate_lb::MlProbLbToLcPi); namespace hf_sel_candidate_x { @@ -307,7 +325,16 @@ 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(IsSelXicToXiPiPi, isSelXicToXiPiPi, int); //! +DECLARE_SOA_COLUMN(MlProbXicToXiPiPi, mlProbXicToXiPiPi, std::vector); //! +enum XicToXiPiPiSelectionStep { + RecoTotal = 0, + RecoKinTopol, + RecoTrackQuality, + RecoPID, + RecoMl, + NSelectionSteps +}; } // namespace hf_sel_candidate_xic DECLARE_SOA_TABLE(HfSelXicToPKPi, "AOD", "HFSELXIC", //! @@ -317,6 +344,8 @@ DECLARE_SOA_TABLE(HfMlXicToPKPi, "AOD", "HFMLXIC", //! // 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 { @@ -345,6 +374,7 @@ DECLARE_SOA_COLUMN(TofNSigmaPiFromLambda, tofNSigmaPiFromLambda, float); DECLARE_SOA_COLUMN(TofNSigmaPrFromLambda, tofNSigmaPrFromLambda, float); DECLARE_SOA_COLUMN(PidTpcInfoStored, pidTpcInfoStored, int); DECLARE_SOA_COLUMN(PidTofInfoStored, pidTofInfoStored, int); +DECLARE_SOA_COLUMN(MlProbToXiPi, mlProbToXiPi, std::vector); } // namespace hf_sel_toxipi DECLARE_SOA_TABLE(HfSelToXiPi, "AOD", "HFSELTOXIPI", @@ -354,6 +384,14 @@ 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::ResultSelections, + 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(HfMlToXiPi, "AOD", "HFMLSELTOXIPI", + hf_sel_toxipi::MlProbToXiPi); + namespace hf_sel_toomegapi { DECLARE_SOA_COLUMN(StatusPidLambda, statusPidLambda, bool); @@ -364,12 +402,12 @@ 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(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(TofNSigmaKaFromCharmBaryon, tofNSigmaKaFromCharmBaryon, float); DECLARE_SOA_COLUMN(TofNSigmaKaFromCasc, tofNSigmaKaFromCasc, float); DECLARE_SOA_COLUMN(TofNSigmaPiFromLambda, tofNSigmaPiFromLambda, float); DECLARE_SOA_COLUMN(TofNSigmaPrFromLambda, tofNSigmaPrFromLambda, float); @@ -377,7 +415,6 @@ 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", @@ -387,8 +424,15 @@ DECLARE_SOA_TABLE(HfSelToOmegaPi, "AOD", "HFSELTOOMEPI", 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(HfSelToOmegaKaKf, "AOD", "HFSELTOOMEGAKAKF", + 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::TpcNSigmaKaFromCharmBaryon, hf_sel_toomegapi::TpcNSigmaKaFromCasc, hf_sel_toomegapi::TpcNSigmaPiFromLambda, hf_sel_toomegapi::TpcNSigmaPrFromLambda, + hf_sel_toomegapi::TofNSigmaKaFromCharmBaryon, hf_sel_toomegapi::TofNSigmaKaFromCasc, hf_sel_toomegapi::TofNSigmaPiFromLambda, hf_sel_toomegapi::TofNSigmaPrFromLambda); + DECLARE_SOA_TABLE(HfMlSelOmegacToOmegaPi, "AOD", "HFMLOMEGAC", //! - hf_sel_toomegapi::MlProbOmegac, hf_sel_toomegapi::MlProbOmegacBar); + hf_sel_toomegapi::MlProbOmegac); namespace hf_sel_toomegaka { DECLARE_SOA_COLUMN(StatusPidLambda, statusPidLambda, bool); diff --git a/PWGHF/DataModel/DerivedTables.h b/PWGHF/DataModel/DerivedTables.h index 9fb45596145..3e9b374898a 100644 --- a/PWGHF/DataModel/DerivedTables.h +++ b/PWGHF/DataModel/DerivedTables.h @@ -16,21 +16,33 @@ #ifndef PWGHF_DATAMODEL_DERIVEDTABLES_H_ #define PWGHF_DATAMODEL_DERIVEDTABLES_H_ -#include - -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include + +#include + +#include +#include namespace o2::aod { -constexpr uint MarkerD0 = 1; -constexpr uint Marker3P = 2; +// basic species: +// D0 → K− π+ +// Λc → p K− π+ +// D+ → K− π+ π+ +// Ds+ → K− K+ π+ + +// composite species +// B0 → D− π+ +// B+ → D0 π+ +// D*+ → D0 π+ +// Ξc± → (Ξ∓ → (Λ → p π∓) π∓) π± π± // ================ // Collision tables @@ -39,131 +51,76 @@ constexpr uint Marker3P = 2; // 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, - soa::Marker); - -using HfD0CollBase = HfD0CollBases::iterator; - -DECLARE_SOA_TABLE(HfD0CollIds, "AOD", "HFD0COLLID", //! Table with original global indices of collisions - hf_cand::CollisionId, - soa::Marker); - -// 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); - -using Hf3PCollBase = Hf3PCollBases::iterator; - -DECLARE_SOA_TABLE(Hf3PCollIds, "AOD", "HF3PCOLLID", //! Table with original global indices of collisions - hf_cand::CollisionId, - soa::Marker); - -// =================== -// MC collision tables -// =================== - -// MC collision columns namespace hf_mc_coll { DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); //! original global index of the MC collision -namespace der_d0 -{ -DECLARE_SOA_ARRAY_INDEX_COLUMN(HfD0CollBase, hfCollBases); //! collision index array pointing to the derived reconstructed collisions for D0 candidates -} -namespace der_3p -{ -DECLARE_SOA_ARRAY_INDEX_COLUMN(Hf3PCollBase, hfCollBases); //! collision index array pointing to the derived reconstructed collisions for 3-prong candidates -} } // namespace hf_mc_coll -// DO - -DECLARE_SOA_TABLE(HfD0McCollBases, "AOD", "HFD0MCCOLLBASE", //! Table with basic MC collision info - o2::soa::Index<>, - mccollision::PosX, - mccollision::PosY, - mccollision::PosZ, - soa::Marker); - -using HfD0McCollBase = HfD0McCollBases::iterator; - -DECLARE_SOA_TABLE(HfD0McCollIds, "AOD", "HFD0MCCOLLID", //! Table with original global indices of MC collisions - hf_mc_coll::McCollisionId, - soa::Marker); - -DECLARE_SOA_TABLE(HfD0McRCollIds, "AOD", "HFD0MCRCOLLID", //! Table with indices pointing to the derived reconstructed-collision table - hf_mc_coll::der_d0::HfD0CollBaseIds); - -// 3-prong decays - -DECLARE_SOA_TABLE(Hf3PMcCollBases, "AOD", "HF3PMCCOLLBASE", //! Table with basic MC collision info - o2::soa::Index<>, - mccollision::PosX, - mccollision::PosY, - mccollision::PosZ, - soa::Marker); +// 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); -using Hf3PMcCollBase = Hf3PMcCollBases::iterator; - -DECLARE_SOA_TABLE(Hf3PMcCollIds, "AOD", "HF3PMCCOLLID", //! Table with original global indices of MC collisions - hf_mc_coll::McCollisionId, - soa::Marker); - -DECLARE_SOA_TABLE(Hf3PMcRCollIds, "AOD", "HF3PMCRCOLLID", //! Table with indices pointing to the derived reconstructed-collision table - hf_mc_coll::der_3p::Hf3PCollBaseIds); +// 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"); /* o2-linter: disable=name/o2-column (unified getter) */ \ + } \ + } \ + 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 // ================ -// Basic candidate properties namespace hf_cand_base { -namespace der_d0 -{ -DECLARE_SOA_INDEX_COLUMN(HfD0CollBase, hfCollBase); //! collision index pointing to the derived collision table for D0 candidates -} -namespace der_3p -{ -DECLARE_SOA_INDEX_COLUMN(Hf3PCollBase, hfCollBase); //! collision index pointing to the derived collision table for 3-prong candidates -} DECLARE_SOA_COLUMN(Eta, eta, float); //! pseudorapidity DECLARE_SOA_COLUMN(M, m, float); //! invariant mass DECLARE_SOA_COLUMN(Phi, phi, float); //! azimuth @@ -179,36 +136,238 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! momentum [](float pt, float eta) -> float { return RecoDecayPtEtaPhi::p(pt, eta); }); } // namespace hf_cand_base +// Candidate selection flags +namespace hf_cand_sel +{ +DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); //! bitmap of the selected candidate type +} + +// Candidate MC columns +namespace hf_cand_mc +{ +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 hf_mc_particle +{ +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"); /* o2-linter: disable=name/o2-column (unified getter) */ \ + } \ + } \ + \ + 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 global indices for 4-prong candidates (Ids). +#define DECLARE_TABLE_CAND_ID_4P(_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, \ + hf_track_index::Prong3Id, \ + o2::soa::Marker); + +// Declares the table with global indices for 5-prong candidates (Ids). +#define DECLARE_TABLE_CAND_ID_5P(_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, \ + hf_track_index::Prong3Id, \ + hf_track_index::Prong4Id, \ + 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"); /* o2-linter: disable=name/o2-column (unified getter) */ \ + } \ + } \ + 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_) + +#define DECLARE_TABLES_4P(_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_4P(_hf_type_, _hf_description_) + +#define DECLARE_TABLES_5P(_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_5P(_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(Ds, "DS", ds, 9); +DECLARE_TABLES_3P(Bplus, "BP", bplus, 5); +DECLARE_TABLES_3P(Dstar, "DST", dstar, 6); +// Workaround for the existing B0 macro in termios.h +#pragma push_macro("B0") +#undef B0 +DECLARE_TABLES_4P(B0, "B0", b0, 7); +#pragma pop_macro("B0") +DECLARE_TABLES_5P(XicToXiPiPi, "XICXPP", xic_to_xi_pi_pi, 8); + +// ================ +// Additional species-specific candidate tables +// ================ + // Candidate properties used for selection namespace hf_cand_par { -DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float); //! cosine of theta star -DECLARE_SOA_COLUMN(Cpa, cpa, float); //! cosine of pointing angle -DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! cosine of pointing angle in the transverse plane -DECLARE_SOA_COLUMN(Ct, ct, float); //! proper lifetime times c -DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! decay length -DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! decay length divided by its uncertainty -DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! decay length in the transverse plane -DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! decay length in the transverse plane divided by its uncertainty -DECLARE_SOA_COLUMN(ImpactParameterNormalised0, impactParameterNormalised0, float); //! impact parameter of prong 0 divided by its uncertainty -DECLARE_SOA_COLUMN(ImpactParameterNormalised1, impactParameterNormalised1, float); //! impact parameter of prong 1 divided by its uncertainty -DECLARE_SOA_COLUMN(ImpactParameterNormalised2, impactParameterNormalised2, float); //! impact parameter of prong 2 divided by its uncertainty -DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! product of impact parameters of prong 0 and prong 1 -DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! see RecoDecay::maxNormalisedDeltaIP -DECLARE_SOA_COLUMN(PProng0, pProng0, float); //! momentum magnitude of prong 0 -DECLARE_SOA_COLUMN(PProng1, pProng1, float); //! momentum magnitude of prong 1 -DECLARE_SOA_COLUMN(PProng2, pProng2, float); //! momentum magnitude of prong 2 -DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! transverse momentum of prong 0 -DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! transverse momentum of prong 1 -DECLARE_SOA_COLUMN(PtProng2, ptProng2, float); //! transverse momentum of prong 2 -DECLARE_SOA_COLUMN(RSecondaryVertex, rSecondaryVertex, float); //! distance of the secondary vertex from the z axis +DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float); //! cosine of theta star +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! cosine of pointing angle +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! cosine of pointing angle in the transverse plane +DECLARE_SOA_COLUMN(Ct, ct, float); //! proper lifetime times c +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! decay length +DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! decay length divided by its uncertainty +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! decay length in the transverse plane +DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! decay length in the transverse plane divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterXi, impactParameterXi, float); //! impact parameter of the Xi prong +DECLARE_SOA_COLUMN(ImpactParameterPi0, impactParameterPi0, float); //! impact parameter of the first pion prong +DECLARE_SOA_COLUMN(ImpactParameterPi1, impactParameterPi1, float); //! impact parameter of the second pion prong +DECLARE_SOA_COLUMN(ImpactParameterNormalised0, impactParameterNormalised0, float); //! impact parameter of prong 0 divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterNormalised1, impactParameterNormalised1, float); //! impact parameter of prong 1 divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterNormalised2, impactParameterNormalised2, float); //! impact parameter of prong 2 divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterNormalisedXi, impactParameterNormalisedXi, float); //! impact parameter of the Xi prong divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterNormalisedPi0, impactParameterNormalisedPi0, float); //! impact parameter of the first pion prong divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterNormalisedPi1, impactParameterNormalisedPi1, float); //! impact parameter of the second pion prong divided by its uncertainty +DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! product of impact parameters of prong 0 and prong 1 +DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! see RecoDecay::maxNormalisedDeltaIP +DECLARE_SOA_COLUMN(PProng0, pProng0, float); //! momentum magnitude of prong 0 +DECLARE_SOA_COLUMN(PProng1, pProng1, float); //! momentum magnitude of prong 1 +DECLARE_SOA_COLUMN(PProng2, pProng2, float); //! momentum magnitude of prong 2 +DECLARE_SOA_COLUMN(PProngPi0, pProngPi0, float); //! momentum magnitude of the first pion prong +DECLARE_SOA_COLUMN(PProngPi1, pProngPi1, float); //! momentum magnitude of the second pion prong +DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! transverse momentum of prong 0 +DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! transverse momentum of prong 1 +DECLARE_SOA_COLUMN(PtProng2, ptProng2, float); //! transverse momentum of prong 2 +DECLARE_SOA_COLUMN(PtProngXi, ptProngXi, float); //! transverse momentum of the Xi prong +DECLARE_SOA_COLUMN(PtProngPi0, ptProngPi0, float); //! transverse momentum of the first pion prong +DECLARE_SOA_COLUMN(PtProngPi1, ptProngPi1, float); //! transverse momentum of the second pion prong +DECLARE_SOA_COLUMN(RSecondaryVertex, rSecondaryVertex, float); //! distance of the secondary vertex from the z axis +// D*± → D0(bar) π± +DECLARE_SOA_COLUMN(SignProng1, signProng1, int8_t); // TOF 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); @@ -216,9 +375,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); @@ -226,290 +389,698 @@ 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 -} +DECLARE_SOA_COLUMN(Chi2PCACharm, chi2PCACharm, float); //! sum of (non-weighted) distances of the secondary vertex to its prongs +DECLARE_SOA_COLUMN(NProngsContributorsPVCharm, nProngsContributorsPVCharm, uint8_t); //! number of prongs contributing to the primary-vertex reconstruction +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(ImpactParameter2Charm, impactParameter2Charm, float); //! impact parameter of prong 2 +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(PxProng0Charm, pxProng0Charm, float); //! x-component of momentum of prong 0 +DECLARE_SOA_COLUMN(PyProng0Charm, pyProng0Charm, float); //! y-component of momentum of prong 0 +DECLARE_SOA_COLUMN(PzProng0Charm, pzProng0Charm, float); //! z-component of momentum of prong 0 +DECLARE_SOA_COLUMN(PxProng1Charm, pxProng1Charm, float); //! x-component of momentum of prong 1 +DECLARE_SOA_COLUMN(PyProng1Charm, pyProng1Charm, float); //! y-component of momentum of prong 1 +DECLARE_SOA_COLUMN(PzProng1Charm, pzProng1Charm, float); //! z-component of momentum of prong 1 +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 +DECLARE_SOA_COLUMN(InvMassCharm, invMassCharm, float); //! mass of the charm daughter +// 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 -namespace hf_cand_mc +// 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(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(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::der_d0::HfD0CollBaseId, - 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, - soa::Marker); +// ---------------- // 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, - soa::Marker); - -DECLARE_SOA_TABLE(HfD0ParEs, "AOD", "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, - soa::Marker); - -DECLARE_SOA_TABLE(HfD0Sels, "AOD", "HFD0SEL", //! Table with candidate selection flags - hf_cand_sel::CandidateSelFlag, - soa::Marker); - -DECLARE_SOA_TABLE(HfD0Mls, "AOD", "HFD0ML", //! Table with candidate selection ML scores - hf_cand_mc::MlScores, - soa::Marker); - -DECLARE_SOA_TABLE(HfD0Ids, "AOD", "HFD0ID", //! Table with original global indices for candidates - hf_cand::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - soa::Marker); - -DECLARE_SOA_TABLE(HfD0Mcs, "AOD", "HFD0MC", //! Table with MC candidate info - hf_cand_mc::FlagMcMatchRec, - hf_cand_mc::OriginMcRec, - soa::Marker); - -// 3-prong decays - -DECLARE_SOA_TABLE(Hf3PBases, "AOD", "HF3PBASE", //! Table with basic candidate properties used in the analyses - o2::soa::Index<>, - hf_cand_base::der_3p::Hf3PCollBaseId, - 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, - soa::Marker); +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); -// 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, - soa::Marker); - -DECLARE_SOA_TABLE(Hf3PParEs, "AOD", "HF3PPARE", //! 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, - soa::Marker); - -DECLARE_SOA_TABLE(Hf3PSels, "AOD", "HF3PSEL", //! Table with candidate selection flags - hf_cand_sel::CandidateSelFlag, - soa::Marker); - -DECLARE_SOA_TABLE(Hf3PMls, "AOD", "HF3PML", //! Table with candidate selection ML scores - hf_cand_mc::MlScores, - soa::Marker); - -DECLARE_SOA_TABLE(Hf3PIds, "AOD", "HF3PID", //! Table with original global indices for candidates - hf_cand::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - hf_track_index::Prong2Id, - soa::Marker); - -DECLARE_SOA_TABLE(Hf3PMcs, "AOD", "HF3PMC", //! Table with MC candidate info - hf_cand_mc::FlagMcMatchRec, - hf_cand_mc::OriginMcRec, - hf_cand_mc::IsCandidateSwapped, - soa::Marker); - -// ================== -// MC particle tables -// ================== +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); -// MC particle columns -namespace hf_mc_particle -{ -DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); //! MC collision of this particle -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle -namespace der_d0 -{ -DECLARE_SOA_INDEX_COLUMN(HfD0McCollBase, hfMcCollBase); //! collision index pointing to the derived MC collision table for D0 candidates -} -namespace der_3p -{ -DECLARE_SOA_INDEX_COLUMN(Hf3PMcCollBase, hfMcCollBase); //! collision index pointing to the derived MC collision table for 3-prong candidates -} -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 +DECLARE_SOA_TABLE_STAGED(HfD0Mls, "HFD0ML", //! Table with candidate selection ML scores + hf_cand_mc::MlScores, + o2::soa::Marker); -// D0 +DECLARE_SOA_TABLE_STAGED(HfD0Mcs, "HFD0MC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + o2::soa::Marker); + +// ---------------- +// B+ +// ---------------- + +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); + +// ---------------- +// B0 +// ---------------- + +DECLARE_SOA_TABLE_STAGED(HfB0Pars, "HFB0PAR", //! 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(HfB0ParDpluss, "HFB0PARDP", //! Table with D+ candidate properties used for selection of B0 + hf_cand_par_charm::Chi2PCACharm, + hf_cand_par_charm::NProngsContributorsPVCharm, + hf_cand_par_charm::CpaCharm, + hf_cand_par_charm::CpaXYCharm, + hf_cand_par_charm::DecayLengthCharm, + hf_cand_par_charm::DecayLengthXYCharm, + hf_cand_par_charm::DecayLengthNormalisedCharm, + hf_cand_par_charm::DecayLengthXYNormalisedCharm, + hf_cand_par_charm::PtProng0Charm, + hf_cand_par_charm::PtProng1Charm, + hf_cand_par_charm::PtProng2Charm, + hf_cand_par_charm::ImpactParameter0Charm, + hf_cand_par_charm::ImpactParameter1Charm, + hf_cand_par_charm::ImpactParameter2Charm, + hf_cand_par_charm::ImpactParameterNormalised0Charm, + hf_cand_par_charm::ImpactParameterNormalised1Charm, + hf_cand_par_charm::ImpactParameterNormalised2Charm, + hf_cand_par_charm::NSigTpcPi0Charm, + hf_cand_par_charm::NSigTofPi0Charm, + hf_cand_par_charm::NSigTpcTofPi0Charm, + hf_cand_par_charm::NSigTpcKa1Charm, + hf_cand_par_charm::NSigTofKa1Charm, + hf_cand_par_charm::NSigTpcTofKa1Charm, + hf_cand_par_charm::NSigTpcPi2Charm, + hf_cand_par_charm::NSigTofPi2Charm, + hf_cand_par_charm::NSigTpcTofPi2Charm, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfB0ParEs, "HFB0PARE", //! 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(HfB0Mls, "HFB0ML", //! Table with candidate selection ML scores + hf_cand_mc::MlScoreSig, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfB0MlDpluss, "HFB0MLDP", //! Table with D+ candidate selection ML scores + hf_cand_mc_charm::MlScoresCharm, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfB0Mcs, "HFB0MC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + o2::soa::Marker); + +// ---------------- +// Lc +// ---------------- + +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+ +// ---------------- + +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); + +// ---------------- +// Ds+ +// ---------------- + +DECLARE_SOA_TABLE_STAGED(HfDsPars, "HFDSPAR", //! 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::NSigTpcKa0, + hf_cand_par::NSigTofPi0, + hf_cand_par::NSigTofKa0, + hf_cand_par::NSigTpcTofPi0, + hf_cand_par::NSigTpcTofKa0, + hf_cand_par::NSigTpcKa1, + hf_cand_par::NSigTofKa1, + hf_cand_par::NSigTpcTofKa1, + hf_cand_par::NSigTpcPi2, + hf_cand_par::NSigTpcKa2, + hf_cand_par::NSigTofPi2, + hf_cand_par::NSigTofKa2, + hf_cand_par::NSigTpcTofPi2, + hf_cand_par::NSigTpcTofKa2, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfDsParEs, "HFDSPARE", //! 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(HfDsMls, "HFDSML", //! Table with candidate selection ML scores + hf_cand_mc::MlScores, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfDsMcs, "HFDSMC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + hf_cand_mc::IsCandidateSwapped, + hf_cand_mc::FlagMcDecayChanRec, + o2::soa::Marker); + +// ---------------- +// D*+ +// ---------------- + +DECLARE_SOA_TABLE_STAGED(HfDstarPars, "HFDSTPAR", //! Table with candidate properties used for selection + hf_cand::PxProng0, // Prong0 is the D0 + hf_cand::PyProng0, + hf_cand::PzProng0, + hf_cand::PxProng1, // Prong1 is the soft pion + hf_cand::PyProng1, + hf_cand::PzProng1, + hf_cand::PtProng1, + hf_cand_par::SignProng1, + hf_cand::PtProng0, + hf_cand::ImpactParameter1, + hf_cand_par::ImpactParameterNormalised1, + hf_cand_par::NSigTpcPi1, + hf_cand_par::NSigTofPi1, + hf_cand_par::NSigTpcTofPi1, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfDstarParD0s, "HFDSTPARD0", //! Table with candidate properties used for selection + hf_cand_par_charm::Chi2PCACharm, + hf_cand_par_charm::CpaCharm, + hf_cand_par_charm::CpaXYCharm, + hf_cand_par_charm::DecayLengthCharm, + hf_cand_par_charm::DecayLengthXYCharm, + hf_cand_par_charm::DecayLengthNormalisedCharm, + hf_cand_par_charm::DecayLengthXYNormalisedCharm, + hf_cand_par_charm::PxProng0Charm, // prong0 is the first D0 daughter + hf_cand_par_charm::PyProng0Charm, + hf_cand_par_charm::PzProng0Charm, + hf_cand_par_charm::PxProng1Charm, // prong 1 is the second D0 daughter + hf_cand_par_charm::PyProng1Charm, + hf_cand_par_charm::PzProng1Charm, + hf_cand_par_charm::InvMassCharm, + hf_cand_par_charm::ImpactParameter0Charm, + hf_cand_par_charm::ImpactParameter1Charm, + hf_cand_par_charm::ImpactParameterNormalised0Charm, + hf_cand_par_charm::ImpactParameterNormalised1Charm, + hf_cand_par_charm::NSigTpcPi0Charm, + hf_cand_par_charm::NSigTofPi0Charm, + hf_cand_par_charm::NSigTpcTofPi0Charm, + hf_cand_par_charm::NSigTpcKa0Charm, + hf_cand_par_charm::NSigTofKa0Charm, + hf_cand_par_charm::NSigTpcTofKa0Charm, + hf_cand_par_charm::NSigTpcPi1Charm, + hf_cand_par_charm::NSigTofPi1Charm, + hf_cand_par_charm::NSigTpcTofPi1Charm, + hf_cand_par_charm::NSigTpcKa1Charm, + hf_cand_par_charm::NSigTofKa1Charm, + hf_cand_par_charm::NSigTpcTofKa1Charm, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfDstarMls, "HFDSTML", //! Table with candidate selection ML scores + hf_cand_mc::MlScores, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfDstarMcs, "HFDSTMC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc_charm::FlagMcMatchRecCharm, + hf_cand_mc::OriginMcRec, + hf_cand::PtBhadMotherPart, + hf_cand::PdgBhadMotherPart, + hf_cand::NTracksDecayed, + o2::soa::Marker); + +// ---------------- +// Ξc± → (Ξ∓ → (Λ → p π∓) π∓) π± π± +// ---------------- + +DECLARE_SOA_TABLE_STAGED(HfXicToXiPiPiPars, "HFXICXPPPAR", //! Table with candidate properties used for selection + hf_cand_xic_to_xi_pi_pi::Sign, + hf_cand_par::PtProngXi, + hf_cand_par::PtProngPi0, + hf_cand_par::PtProngPi1, + 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, + hf_cand::Chi2PCA, + hf_cand_par::Ct, + hf_cand_par::DecayLength, + hf_cand_par::DecayLengthNormalised, + hf_cand_par::DecayLengthXY, + hf_cand_par::DecayLengthXYNormalised, + hf_cand_par::Cpa, + hf_cand_par::CpaXY, + hf_cand_xic_to_xi_pi_pi::CpaXi, + hf_cand_xic_to_xi_pi_pi::CpaXYXi, + hf_cand_xic_to_xi_pi_pi::CpaLambda, + hf_cand_xic_to_xi_pi_pi::CpaXYLambda, + hf_cand_par::ImpactParameterXi, + hf_cand_par::ImpactParameterNormalisedXi, + hf_cand_par::ImpactParameterPi0, + hf_cand_par::ImpactParameterNormalisedPi0, + hf_cand_par::ImpactParameterPi1, + hf_cand_par::ImpactParameterNormalisedPi1, + hf_cand_par::MaxNormalisedDeltaIP, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfXicToXiPiPiParEs, "HFXICXPPPARE", //! Table with additional candidate properties used for selection + hf_cand_xic_to_xi_pi_pi::CpaLambdaToXi, + hf_cand_xic_to_xi_pi_pi::CpaXYLambdaToXi, + hf_cand_par::PProngPi0, + hf_cand_par::PProngPi1, + 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::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, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(HfXicToXiPiPiMls, "HFXICXPPML", //! Table with candidate selection ML scores + hf_cand_mc::MlScores, + o2::soa::Marker); -DECLARE_SOA_TABLE(HfD0PBases, "AOD", "HFD0PBASE", //! Table with MC particle info - o2::soa::Index<>, - hf_mc_particle::der_d0::HfD0McCollBaseId, - 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, - soa::Marker); - -DECLARE_SOA_TABLE(HfD0PIds, "AOD", "HFD0PID", //! Table with original global indices for MC particles - hf_mc_particle::McCollisionId, - hf_mc_particle::McParticleId, - soa::Marker); - -// 3-prong decays - -DECLARE_SOA_TABLE(Hf3PPBases, "AOD", "HF3PPBASE", //! Table with MC particle info - o2::soa::Index<>, - hf_mc_particle::der_3p::Hf3PMcCollBaseId, - 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, - soa::Marker); - -DECLARE_SOA_TABLE(Hf3PPIds, "AOD", "HF3PPID", //! Table with original global indices for MC particles - hf_mc_particle::McCollisionId, - hf_mc_particle::McParticleId, - soa::Marker); +DECLARE_SOA_TABLE_STAGED(HfXicToXiPiPiMcs, "HFXICXPPMC", //! Table with MC candidate info + hf_cand_mc::FlagMcMatchRec, + hf_cand_mc::OriginMcRec, + o2::soa::Marker); } // namespace o2::aod #endif // PWGHF_DATAMODEL_DERIVEDTABLES_H_ diff --git a/PWGHF/DataModel/DerivedTablesStored.h b/PWGHF/DataModel/DerivedTablesStored.h deleted file mode 100644 index 95d5cc0438f..00000000000 --- a/PWGHF/DataModel/DerivedTablesStored.h +++ /dev/null @@ -1,371 +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 DerivedTablesStored.h -/// \brief Definitions of stored versions of derived tables produced by derived-data creators (defined in DerivedTables.h) -/// \author Vít Kučera , Inha University -/// \note Things to check when comparing with DerivedTables.h: -/// - Prefix "Stored" in table definitions -/// - Prefix "Stored" in names of index columns pointing to derived tables -/// - Suffix "Stored" in Marker name -/// - Prefix "der_stored_" in namespace names (if needed to avoid redefinitions in "der_") -/// - Origin AOD1 - -#ifndef PWGHF_DATAMODEL_DERIVEDTABLESSTORED_H_ -#define PWGHF_DATAMODEL_DERIVEDTABLESSTORED_H_ - -#include "PWGHF/DataModel/DerivedTables.h" - -namespace o2::aod -{ -constexpr uint MarkerD0Stored = 10; -constexpr uint Marker3PStored = 20; - -// ================ -// Collision tables -// ================ - -// D0 - -DECLARE_SOA_TABLE(StoredHfD0CollBases, "AOD1", "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, - soa::Marker); - -using StoredHfD0CollBase = StoredHfD0CollBases::iterator; - -DECLARE_SOA_TABLE(StoredHfD0CollIds, "AOD1", "HFD0COLLID", //! Table with original global indices of collisions - hf_cand::CollisionId, - soa::Marker); - -// 3-prong decays - -DECLARE_SOA_TABLE(StoredHf3PCollBases, "AOD1", "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); - -using StoredHf3PCollBase = StoredHf3PCollBases::iterator; - -DECLARE_SOA_TABLE(StoredHf3PCollIds, "AOD1", "HF3PCOLLID", //! Table with original global indices of collisions - hf_cand::CollisionId, - soa::Marker); - -// =================== -// MC collision tables -// =================== - -// DO - -DECLARE_SOA_TABLE(StoredHfD0McCollBases, "AOD1", "HFD0MCCOLLBASE", //! Table with basic MC collision info - o2::soa::Index<>, - mccollision::PosX, - mccollision::PosY, - mccollision::PosZ, - soa::Marker); - -using StoredHfD0McCollBase = StoredHfD0McCollBases::iterator; - -DECLARE_SOA_TABLE(StoredHfD0McCollIds, "AOD1", "HFD0MCCOLLID", //! Table with original global indices of MC collisions - hf_mc_coll::McCollisionId, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHfD0McRCollIds, "AOD1", "HFD0MCRCOLLID", //! Table with indices pointing to the derived reconstructed-collision table - hf_mc_coll::der_d0::HfD0CollBaseIds, - soa::Marker); - -// 3-prong decays - -DECLARE_SOA_TABLE(StoredHf3PMcCollBases, "AOD1", "HF3PMCCOLLBASE", //! Table with basic MC collision info - o2::soa::Index<>, - mccollision::PosX, - mccollision::PosY, - mccollision::PosZ, - soa::Marker); - -using StoredHf3PMcCollBase = StoredHf3PMcCollBases::iterator; - -DECLARE_SOA_TABLE(StoredHf3PMcCollIds, "AOD1", "HF3PMCCOLLID", //! Table with original global indices of MC collisions - hf_mc_coll::McCollisionId, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHf3PMcRCollIds, "AOD1", "HF3PMCRCOLLID", //! Table with indices pointing to the derived reconstructed-collision table - hf_mc_coll::der_3p::Hf3PCollBaseIds, - soa::Marker); - -// ================ -// Candidate tables -// ================ - -// Basic candidate properties - -// D0 - -DECLARE_SOA_TABLE(StoredHfD0Bases, "AOD1", "HFD0BASE", //! Table with basic candidate properties used in the analyses - o2::soa::Index<>, - hf_cand_base::der_d0::HfD0CollBaseId, - 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, - soa::Marker); - -// 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(StoredHfD0Pars, "AOD1", "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, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHfD0ParEs, "AOD1", "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, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHfD0Sels, "AOD1", "HFD0SEL", //! Table with candidate selection flags - hf_cand_sel::CandidateSelFlag, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHfD0Mls, "AOD1", "HFD0ML", //! Table with candidate selection ML scores - hf_cand_mc::MlScores, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHfD0Ids, "AOD1", "HFD0ID", //! Table with original global indices for candidates - hf_cand::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHfD0Mcs, "AOD1", "HFD0MC", //! Table with MC candidate info - hf_cand_mc::FlagMcMatchRec, - hf_cand_mc::OriginMcRec, - soa::Marker); - -// 3-prong decays - -DECLARE_SOA_TABLE(StoredHf3PBases, "AOD1", "HF3PBASE", //! Table with basic candidate properties used in the analyses - o2::soa::Index<>, - hf_cand_base::der_3p::Hf3PCollBaseId, - 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, - soa::Marker); - -// 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(StoredHf3PPars, "AOD1", "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, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHf3PParEs, "AOD1", "HF3PPARE", //! 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, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHf3PSels, "AOD1", "HF3PSEL", //! Table with candidate selection flags - hf_cand_sel::CandidateSelFlag, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHf3PMls, "AOD1", "HF3PML", //! Table with candidate selection ML scores - hf_cand_mc::MlScores, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHf3PIds, "AOD1", "HF3PID", //! Table with original global indices for candidates - hf_cand::CollisionId, - hf_track_index::Prong0Id, - hf_track_index::Prong1Id, - hf_track_index::Prong2Id, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHf3PMcs, "AOD1", "HF3PMC", //! Table with MC candidate info - hf_cand_mc::FlagMcMatchRec, - hf_cand_mc::OriginMcRec, - hf_cand_mc::IsCandidateSwapped, - soa::Marker); - -// ================== -// MC particle tables -// ================== - -// D0 - -DECLARE_SOA_TABLE(StoredHfD0PBases, "AOD1", "HFD0PBASE", //! Table with MC particle info - o2::soa::Index<>, - hf_mc_particle::der_d0::HfD0McCollBaseId, - 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, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHfD0PIds, "AOD1", "HFD0PID", //! Table with original global indices for MC particles - hf_mc_particle::McCollisionId, - hf_mc_particle::McParticleId, - soa::Marker); - -// 3-prong decays - -DECLARE_SOA_TABLE(StoredHf3PPBases, "AOD1", "HF3PPBASE", //! Table with MC particle info - o2::soa::Index<>, - hf_mc_particle::der_3p::Hf3PMcCollBaseId, - 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, - soa::Marker); - -DECLARE_SOA_TABLE(StoredHf3PPIds, "AOD1", "HF3PPID", //! Table with original global indices for MC particles - hf_mc_particle::McCollisionId, - hf_mc_particle::McParticleId, - soa::Marker); -} // namespace o2::aod - -#endif // PWGHF_DATAMODEL_DERIVEDTABLESSTORED_H_ diff --git a/PWGHF/DataModel/TrackIndexSkimmingTables.h b/PWGHF/DataModel/TrackIndexSkimmingTables.h new file mode 100644 index 00000000000..6408c636f8e --- /dev/null +++ b/PWGHF/DataModel/TrackIndexSkimmingTables.h @@ -0,0 +1,323 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TrackIndexSkimmingTables.h +/// \brief Definitions of tables produced by the candidate skimming +/// +/// \author Gian Michele Innocenti , CERN +/// \author Vít Kučera , CERN + +#ifndef PWGHF_DATAMODEL_TRACKINDEXSKIMMINGTABLES_H_ +#define PWGHF_DATAMODEL_TRACKINDEXSKIMMINGTABLES_H_ + +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include +#include + +#include +#include + +namespace o2::aod +{ +namespace hf_sel_collision +{ + +// ================ +// Collision selection table +// ================ + +DECLARE_SOA_COLUMN(WhyRejectColl, whyRejectColl, o2::hf_evsel::HfCollisionRejectionMask); //! +} // namespace hf_sel_collision + +DECLARE_SOA_TABLE(HfSelCollision, "AOD", "HFSELCOLLISION", //! + hf_sel_collision::WhyRejectColl); + +// ================ +// Track selection tables +// ================ + +namespace hf_sel_track +{ +DECLARE_SOA_COLUMN(IsSelProng, isSelProng, uint32_t); //! +DECLARE_SOA_COLUMN(IsIdentifiedPid, isIdentifiedPid, uint32_t); //! +DECLARE_SOA_COLUMN(IsPositive, isPositive, bool); //! +} // namespace hf_sel_track + +DECLARE_SOA_TABLE(HfSelTrack, "AOD", "HFSELTRACK", //! + hf_sel_track::IsSelProng, + hf_sel_track::IsIdentifiedPid, + hf_sel_track::IsPositive); + +namespace hf_pv_refit_track +{ +DECLARE_SOA_COLUMN(PvRefitX, pvRefitX, float); //! +DECLARE_SOA_COLUMN(PvRefitY, pvRefitY, float); //! +DECLARE_SOA_COLUMN(PvRefitZ, pvRefitZ, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaX2, pvRefitSigmaX2, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaXY, pvRefitSigmaXY, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaY2, pvRefitSigmaY2, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaXZ, pvRefitSigmaXZ, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaYZ, pvRefitSigmaYZ, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaZ2, pvRefitSigmaZ2, float); //! +DECLARE_SOA_COLUMN(PvRefitDcaXY, pvRefitDcaXY, float); //! +DECLARE_SOA_COLUMN(PvRefitDcaZ, pvRefitDcaZ, float); //! +} // namespace hf_pv_refit_track + +DECLARE_SOA_TABLE(HfPvRefitTrack, "AOD", "HFPVREFITTRACK", //! + hf_pv_refit_track::PvRefitX, + hf_pv_refit_track::PvRefitY, + hf_pv_refit_track::PvRefitZ, + hf_pv_refit_track::PvRefitSigmaX2, + hf_pv_refit_track::PvRefitSigmaXY, + hf_pv_refit_track::PvRefitSigmaY2, + hf_pv_refit_track::PvRefitSigmaXZ, + hf_pv_refit_track::PvRefitSigmaYZ, + hf_pv_refit_track::PvRefitSigmaZ2, + hf_pv_refit_track::PvRefitDcaXY, + hf_pv_refit_track::PvRefitDcaZ); + +// ================ +// Track index skim tables +// ================ + +namespace hf_track_index +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! Collision index +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, Tracks, "_0"); //! Index to first prong +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, Tracks, "_1"); //! Index to second prong +DECLARE_SOA_INDEX_COLUMN_FULL(Prong2, prong2, int, Tracks, "_2"); //! Index to third prong +DECLARE_SOA_INDEX_COLUMN_FULL(Prong3, prong3, int, Tracks, "_3"); //! Index to fourth prong +DECLARE_SOA_INDEX_COLUMN_FULL(Prong4, prong4, int, Tracks, "_4"); //! Index to fifth 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); //! 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); //! +DECLARE_SOA_COLUMN(FlagJpsiToMuMu, flagJpsiToMuMu, uint8_t); //! +DECLARE_SOA_COLUMN(FlagDplusToPiKPi, flagDplusToPiKPi, uint8_t); //! +DECLARE_SOA_COLUMN(FlagLcToPKPi, flagLcToPKPi, uint8_t); //! +DECLARE_SOA_COLUMN(FlagDsToKKPi, flagDsToKKPi, uint8_t); //! +DECLARE_SOA_COLUMN(FlagXicToPKPi, flagXicToPKPi, uint8_t); //! +DECLARE_SOA_COLUMN(FlagDstarToD0Pi, flagDstarToD0Pi, uint8_t); //! + +DECLARE_SOA_COLUMN(MlProbSkimD0ToKPi, mlProbSkimD0ToKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for D0->Kpi +DECLARE_SOA_COLUMN(MlProbSkimDplusToPiKPi, mlProbSkimDplusToPiKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for D+->Kpipi +DECLARE_SOA_COLUMN(MlProbSkimDsToKKPi, mlProbSkimDsToKKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for Ds->KKpi +DECLARE_SOA_COLUMN(MlProbSkimLcToPKPi, mlProbSkimLcToPKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for Lc->pKpi +DECLARE_SOA_COLUMN(MlProbSkimXicToPKPi, mlProbSkimXicToPKPi, std::vector); //! ML probabilities (background, prompt, non-prompt) for Xic->pKpi +} // namespace hf_track_index + +DECLARE_SOA_TABLE(Hf2Prongs_000, "AOD", "HF2PRONG", //! Table for HF 2 prong candidates (Run 2 converted format) + o2::soa::Index<>, + hf_track_index::Prong0Id, + hf_track_index::Prong1Id, + hf_track_index::HFflag); + +DECLARE_SOA_TABLE_VERSIONED(Hf2Prongs_001, "AOD", "HF2PRONG", 1, //! Table for HF 2 prong candidates (Run 3 format) + o2::soa::Index<>, + hf_track_index::CollisionId, + hf_track_index::Prong0Id, + hf_track_index::Prong1Id, + hf_track_index::HFflag); + +using Hf2Prongs = Hf2Prongs_001; +using Hf2Prong = Hf2Prongs::iterator; + +DECLARE_SOA_TABLE(HfCascades_000, "AOD", "HFCASCADE", //! Table for HF candidates with a V0 (Run 2 converted format) + o2::soa::Index<>, + hf_track_index::Prong0Id, + hf_track_index::V0Id); + +DECLARE_SOA_TABLE_VERSIONED(HfCascades_001, "AOD", "HFCASCADE", 1, //! Table for HF candidates with a V0 (Run 3 format) + o2::soa::Index<>, + hf_track_index::CollisionId, + hf_track_index::Prong0Id, + hf_track_index::V0Id); + +using HfCascades = HfCascades_001; +using HfCascade = HfCascades::iterator; + +DECLARE_SOA_TABLE(Hf3Prongs_000, "AOD", "HF3PRONG", //! Table for HF 3 prong candidates (Run 2 converted format) + o2::soa::Index<>, + hf_track_index::Prong0Id, + hf_track_index::Prong1Id, + hf_track_index::Prong2Id, + hf_track_index::HFflag); + +DECLARE_SOA_TABLE_VERSIONED(Hf3Prongs_001, "AOD", "HF3PRONG", 1, //! Table for HF 3 prong candidates (Run 3 format) + o2::soa::Index<>, + hf_track_index::CollisionId, + hf_track_index::Prong0Id, + hf_track_index::Prong1Id, + hf_track_index::Prong2Id, + hf_track_index::HFflag); + +using Hf3Prongs = Hf3Prongs_001; +using Hf3Prong = Hf3Prongs::iterator; + +DECLARE_SOA_TABLE(HfCascLf2Prongs, "AOD", "HFCASCLF2PRONG", //! Table for HF 2 prong candidates with a Cascade + o2::soa::Index<>, + hf_track_index::CollisionId, + hf_track_index::CascadeId, + hf_track_index::Prong0Id, + hf_track_index::HFflag); + +using HfCascLf2Prong = HfCascLf2Prongs::iterator; + +DECLARE_SOA_TABLE(HfCascLf3Prongs, "AOD", "HFCASCLF3PRONG", //! Table for HF 3 prong candidates with a Cascade + o2::soa::Index<>, + hf_track_index::CollisionId, + hf_track_index::CascadeId, + hf_track_index::Prong0Id, + hf_track_index::Prong1Id); + +using HfCascLf3Prong = HfCascLf3Prongs::iterator; + +namespace hf_track_index +{ +DECLARE_SOA_INDEX_COLUMN_FULL(ProngD0, prongD0, int, Hf2Prongs, ""); //! Index to a D0 prong +} // namespace hf_track_index + +DECLARE_SOA_TABLE(HfDstars_000, "AOD", "HFDSTAR", //! D* -> D0pi candidates (Run 2 converted format) + o2::soa::Index<>, + 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; + +DECLARE_SOA_TABLE(HfCutStatus2Prong, "AOD", "HFCUTSTATUS2P", //! + hf_track_index::FlagD0ToKPi, + hf_track_index::FlagJpsiToEE, + hf_track_index::FlagJpsiToMuMu); + +DECLARE_SOA_TABLE(HfCutStatus3Prong, "AOD", "HFCUTSTATUS3P", //! + hf_track_index::FlagDplusToPiKPi, + hf_track_index::FlagLcToPKPi, + hf_track_index::FlagDsToKKPi, + hf_track_index::FlagXicToPKPi); + +DECLARE_SOA_TABLE(HfCutStatusDstar, "AOD", "HFCUTSTATUSDST", //! + hf_track_index::FlagDstarToD0Pi); + +DECLARE_SOA_TABLE(Hf2ProngMlProbs, "AOD", "HF2PRONGMLPROB", //! Table for ML scores of HF 2 prong candidates + hf_track_index::MlProbSkimD0ToKPi); + +DECLARE_SOA_TABLE(Hf3ProngMlProbs, "AOD", "HF3PRONGMLPROB", //! Table for ML scores of HF 3 prong candidates + hf_track_index::MlProbSkimDplusToPiKPi, + hf_track_index::MlProbSkimLcToPKPi, + hf_track_index::MlProbSkimDsToKKPi, + hf_track_index::MlProbSkimXicToPKPi); + +// ================ +// Primary-vertex refit tables +// ================ + +namespace hf_pv_refit +{ +DECLARE_SOA_COLUMN(PvRefitX, pvRefitX, float); //! +DECLARE_SOA_COLUMN(PvRefitY, pvRefitY, float); //! +DECLARE_SOA_COLUMN(PvRefitZ, pvRefitZ, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaX2, pvRefitSigmaX2, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaXY, pvRefitSigmaXY, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaY2, pvRefitSigmaY2, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaXZ, pvRefitSigmaXZ, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaYZ, pvRefitSigmaYZ, float); //! +DECLARE_SOA_COLUMN(PvRefitSigmaZ2, pvRefitSigmaZ2, float); //! +} // namespace hf_pv_refit + +DECLARE_SOA_TABLE(HfPvRefit2Prong, "AOD", "HFPVREFIT2PRONG", //! + hf_pv_refit::PvRefitX, + hf_pv_refit::PvRefitY, + hf_pv_refit::PvRefitZ, + hf_pv_refit::PvRefitSigmaX2, + hf_pv_refit::PvRefitSigmaXY, + hf_pv_refit::PvRefitSigmaY2, + hf_pv_refit::PvRefitSigmaXZ, + hf_pv_refit::PvRefitSigmaYZ, + hf_pv_refit::PvRefitSigmaZ2); + +DECLARE_SOA_TABLE(HfPvRefit3Prong, "AOD", "HFPVREFIT3PRONG", //! + hf_pv_refit::PvRefitX, + hf_pv_refit::PvRefitY, + hf_pv_refit::PvRefitZ, + hf_pv_refit::PvRefitSigmaX2, + hf_pv_refit::PvRefitSigmaXY, + hf_pv_refit::PvRefitSigmaY2, + hf_pv_refit::PvRefitSigmaXZ, + hf_pv_refit::PvRefitSigmaYZ, + hf_pv_refit::PvRefitSigmaZ2, + o2::soa::Marker<1>); + +DECLARE_SOA_TABLE(HfPvRefitDstar, "AOD", "HFPVREFITDSTAR", //! + hf_pv_refit::PvRefitX, + hf_pv_refit::PvRefitY, + hf_pv_refit::PvRefitZ, + hf_pv_refit::PvRefitSigmaX2, + hf_pv_refit::PvRefitSigmaXY, + hf_pv_refit::PvRefitSigmaY2, + hf_pv_refit::PvRefitSigmaXZ, + hf_pv_refit::PvRefitSigmaYZ, + hf_pv_refit::PvRefitSigmaZ2, + o2::soa::Marker<2>); + +// ================ +// Decay types stored in HFflag +// ================ + +namespace hf_cand_2prong +{ +enum DecayType { + D0ToPiK = 0, + JpsiToEE, + JpsiToMuMu, + N2ProngDecays +}; +} // namespace hf_cand_2prong + +namespace hf_cand_3prong +{ +enum DecayType { + DplusToPiKPi = 0, + LcToPKPi, + DsToKKPi, + XicToPKPi, + CdToDeKPi, + N3ProngDecays +}; +} // namespace hf_cand_3prong + +namespace hf_cand_casc_lf +{ +enum DecayType2Prong { + XiczeroOmegaczeroToXiPi = 0, + OmegaczeroToOmegaPi, + OmegaczeroToOmegaK, + N2ProngDecays +}; + +enum DecayType3Prong { + XicplusToXiPiPi = 0, + N3ProngDecays +}; +} // namespace hf_cand_casc_lf + +} // namespace o2::aod + +#endif // PWGHF_DATAMODEL_TRACKINDEXSKIMMINGTABLES_H_ diff --git a/PWGHF/HFC/DataModel/CorrelationTables.h b/PWGHF/HFC/DataModel/CorrelationTables.h index a613d58eaaa..69860d9d178 100644 --- a/PWGHF/HFC/DataModel/CorrelationTables.h +++ b/PWGHF/HFC/DataModel/CorrelationTables.h @@ -16,12 +16,15 @@ #ifndef PWGHF_HFC_DATAMODEL_CORRELATIONTABLES_H_ #define PWGHF_HFC_DATAMODEL_CORRELATIONTABLES_H_ -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" // IWYU pragma: keep #include "Common/Core/RecoDecay.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include +#include +#include + +#include namespace o2::aod { @@ -51,15 +54,28 @@ 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(IsAutoCorrelated, isAutoCorrelated, bool); //! Correlation Status +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(Cent, cent, float); //! Centrality of Collision +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 @@ -81,29 +97,79 @@ 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::IsAutoCorrelated); + aod::hf_correlation_d0_hadron::IsAutoCorrelated, + aod::hf_correlation_d0_hadron::Cent); -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(ChargeCand, chargeCand, int); //! store charge of Lc and Sc +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(Cent, cent, float); //! Centrality of Collision +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 @@ -111,25 +177,72 @@ 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, + aod::hf_correlation_lc_hadron::Cent); 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", + aod::hf_correlation_lc_hadron::DeltaY); +DECLARE_SOA_TABLE(CandChargePair, "AOD", "CANDCHARGEPAIR", + aod::hf_correlation_lc_hadron::ChargeCand); +DECLARE_SOA_TABLE(CandCharge, "AOD", "CANDCHARGE", + aod::hf_correlation_lc_hadron::ChargeCand); // definition of columns and tables for Ds-Hadron correlation pairs namespace hf_correlation_ds_hadron { DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between Ds and Hadrons DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between Ds and Hadrons -DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of Ds -DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! Transverse momentum of Hadron +DECLARE_SOA_COLUMN(SignedPtD, signedPtD, float); //! Transverse momentum of Ds +DECLARE_SOA_COLUMN(SignedPtHadron, signedPtHadron, float); //! Transverse momentum of Hadron DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of Ds DECLARE_SOA_COLUMN(MlScoreBkg, mlScoreBkg, float); //! ML background score for Ds selection DECLARE_SOA_COLUMN(MlScorePrompt, mlScorePrompt, float); //! ML prompt score for Ds selection 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(PoolBin, poolBin, int); //! Pool Bin for the MixedEvent +DECLARE_SOA_COLUMN(NumPvContrib, numPvContrib, uint16_t); //! number PV contributors 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 @@ -141,9 +254,10 @@ DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); //! U DECLARE_SOA_TABLE(DsHadronPair, "AOD", "DSHPAIR", //! Ds-Hadrons pairs Information aod::hf_correlation_ds_hadron::DeltaPhi, aod::hf_correlation_ds_hadron::DeltaEta, - aod::hf_correlation_ds_hadron::PtD, - aod::hf_correlation_ds_hadron::PtHadron, - aod::hf_correlation_ds_hadron::PoolBin); + aod::hf_correlation_ds_hadron::SignedPtD, + aod::hf_correlation_ds_hadron::SignedPtHadron, + aod::hf_correlation_ds_hadron::PoolBin, + aod::hf_correlation_ds_hadron::NumPvContrib); DECLARE_SOA_TABLE(DsHadronRecoInfo, "AOD", "DSHRECOINFO", //! Ds-Hadrons pairs Reconstructed Information aod::hf_correlation_ds_hadron::MD, @@ -161,9 +275,10 @@ DECLARE_SOA_TABLE(DsHadronMlInfo, "AOD", "DSHMLINFO", //! Ds-Hadrons pairs Machi DECLARE_SOA_TABLE(DsCandRecoInfo, "AOD", "DSCANDRECOINFO", //! Ds candidates Reconstructed Information aod::hf_correlation_ds_hadron::MD, - aod::hf_correlation_ds_hadron::PtD, + aod::hf_correlation_ds_hadron::SignedPtD, aod::hf_correlation_ds_hadron::MlScorePrompt, - aod::hf_correlation_ds_hadron::MlScoreBkg); + aod::hf_correlation_ds_hadron::MlScoreBkg, + aod::hf_correlation_ds_hadron::NumPvContrib); DECLARE_SOA_TABLE(DsCandGenInfo, "AOD", "DSCANDGENOINFO", //! Ds candidates Generated Information aod::hf_correlation_ds_hadron::IsPrompt); @@ -173,6 +288,27 @@ DECLARE_SOA_TABLE(TrackRecoInfo, "AOD", "TRACKRECOINFO", //! Tracks Reconstructe 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 { @@ -223,6 +359,7 @@ DECLARE_SOA_COLUMN(PtHadron, ptHadron, float); //! T 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(MlScoreNonPrompt, mlScoreNonPrompt, float); //! ML non-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 @@ -253,13 +390,15 @@ DECLARE_SOA_TABLE(DplusHadronGenInfo, "AOD", "DPLUSHGENINFO", //! Ds-Hadrons pai DECLARE_SOA_TABLE(DplusHadronMlInfo, "AOD", "DPLUSHMLINFO", //! D+-Hadrons pairs Machine Learning Information aod::hf_correlation_dplus_hadron::MlScoreBkg, - aod::hf_correlation_dplus_hadron::MlScorePrompt); + aod::hf_correlation_dplus_hadron::MlScorePrompt, + aod::hf_correlation_dplus_hadron::MlScoreNonPrompt); 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); + aod::hf_correlation_dplus_hadron::MlScorePrompt, + aod::hf_correlation_dplus_hadron::MlScoreNonPrompt); DECLARE_SOA_TABLE(DplusGenInfo, "AOD", "DPLUSGENOINFO", //! D+ candidates Generated Information aod::hf_correlation_dplus_hadron::IsPrompt); @@ -272,9 +411,11 @@ DECLARE_SOA_TABLE(TrkRecInfoDplus, "AOD", "TRKRECINFODPLUS", //! Tracks Reconstr // 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); @@ -319,9 +460,9 @@ DECLARE_SOA_TABLE(DstarHadronPair, "AOD", "DSTRHPAIR", // D* Hadrons pairs Infor hf_correlation_dstar_hadron::DeltaM); DECLARE_SOA_TABLE(Dstar, "AOD", "DSTAR", // Only Dstar properties - hf_correlation_dstar_hadron::CollisionId, + hf_correlation_dstar_hadron::CollisionIdx, // D* only properties - hf_correlation_dstar_hadron::HfCandDstarId, + hf_correlation_dstar_hadron::HfCandDstarIdx, hf_correlation_dstar_hadron::PhiDstar, hf_correlation_dstar_hadron::EtaDstar, hf_correlation_dstar_hadron::PtDstar, @@ -333,7 +474,7 @@ DECLARE_SOA_TABLE(Dstar, "AOD", "DSTAR", // Only Dstar properties // Note: Table for selection of Lc in a collision namespace hf_selection_lc_collision { -DECLARE_SOA_COLUMN(LcSel, lcSel, int); //! Selection flag for Lc in a collision +DECLARE_SOA_COLUMN(LcSel, lcSel, bool); //! Selection flag for Lc in a collision } // namespace hf_selection_lc_collision DECLARE_SOA_TABLE(LcSelection, "AOD", "LCINCOLL", // Selection of Lc in collisions @@ -347,6 +488,68 @@ 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_electron +{ +DECLARE_SOA_COLUMN(PhiElectron, phiElectron, float); //! Phi of electron +DECLARE_SOA_COLUMN(EtaElectron, etaElectron, float); //! Eta of electron +DECLARE_SOA_COLUMN(PtElectron, ptElectron, float); //! Transverse momentum of electron +DECLARE_SOA_COLUMN(NElectronsLS, nElectronsLS, int); //! number of like-sign +DECLARE_SOA_COLUMN(NElectronsUS, nElectronsUS, int); //! number of Unlike-sign +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin of event defined using zvtx and multiplicit +DECLARE_SOA_COLUMN(GIndexCol, gIndexCol, int); //! Global index for the collision +DECLARE_SOA_COLUMN(TimeStamp, timeStamp, int64_t); //! Timestamp for the collision + +} // namespace hf_electron + +DECLARE_SOA_TABLE(HfElectron, "AOD", "HFELECTRON", //! Hf Electron properties + aod::hf_electron::PhiElectron, + aod::hf_electron::EtaElectron, + aod::hf_electron::PtElectron, + aod::hf_electron::NElectronsLS, + aod::hf_electron::NElectronsUS, + aod::hf_electron::PoolBin, + aod::hf_electron::GIndexCol, + aod::hf_electron::TimeStamp); + +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(NPairsLS, nPairsLS, int); //! number of like-sign electron-hadron pairs +DECLARE_SOA_COLUMN(NPairsUS, nPairsUS, int); //! number of unlike-sign electron-hadron pairs +} // 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::NPairsLS, + hf_correlation_electron_hadron::NPairsUS); + +// 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..35e12760919 100644 --- a/PWGHF/HFC/DataModel/DMesonPairsTables.h +++ b/PWGHF/HFC/DataModel/DMesonPairsTables.h @@ -17,7 +17,10 @@ #ifndef PWGHF_HFC_DATAMODEL_DMESONPAIRSTABLES_H_ #define PWGHF_HFC_DATAMODEL_DMESONPAIRSTABLES_H_ -#include "Framework/AnalysisDataModel.h" +#include + +#include +#include namespace o2::aod { @@ -25,10 +28,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 +47,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 +61,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 +77,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..555d86f34c8 --- /dev/null +++ b/PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h @@ -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 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 + +namespace o2::aod +{ +namespace hf_collisions_reduced +{ +DECLARE_SOA_COLUMN(NumPvContrib, numPvContrib, int); //! Event multiplicity from PV contributors +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); //! Event multiplicity +DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Event centrality +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::NumPvContrib, + aod::hf_collisions_reduced::PosZ); + +DECLARE_SOA_TABLE(HfcRedCorrColls, "AOD", "HFCREDCORRCOLL", //! Table with collision info + soa::Index<>, + aod::hf_collisions_reduced::Multiplicity, + aod::hf_collisions_reduced::NumPvContrib, + aod::hf_collisions_reduced::Centrality, + aod::hf_collisions_reduced::PosZ); + +using HfcRedCollision = HfcRedCollisions::iterator; + +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 background 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); + +// definition of columns and tables for Charm-Hadron and Hadron-Hadron correlation pairs +namespace hf_correl_charm_had_reduced +{ +// Correlation columns +DECLARE_SOA_INDEX_COLUMN(HfcRedCorrColl, hfcRedCorrColl); //! ReducedCollision index +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DeltaPhi between charm hadron and Hadrons +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! DeltaEta between charm hadron and Hadrons +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin for the MixedEvent +// General trigger particle columns +DECLARE_SOA_COLUMN(PhiTrig, phiTrig, float); //! Phi of the trigger candidate +DECLARE_SOA_COLUMN(EtaTrig, etaTrig, float); //! Eta of the trigger candidate +DECLARE_SOA_COLUMN(PtTrig, ptTrig, float); //! Pt of the trigger candidate +// Charm trigger particle selection columns +DECLARE_SOA_COLUMN(InvMassTrig, invMassTrig, float); //! Invariant mass of Charm trigger candidate +DECLARE_SOA_COLUMN(BdtScore0Trig, bdtScore0Trig, float); //! First BDT output score +DECLARE_SOA_COLUMN(BdtScore1Trig, bdtScore1Trig, float); //! Second BDT output score +// Hadron trigger particle selection columns +DECLARE_SOA_COLUMN(NTpcCrossedRowsTrig, nTpcCrossedRowsTrig, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(ItsClsMapTrig, itsClsMapTrig, int); //! ITS cluster map, one bit per a layer, starting from the innermost +DECLARE_SOA_COLUMN(ItsNClsTrig, itsNClsTrig, int); //! Number of ITS clusters +DECLARE_SOA_COLUMN(DcaXYTrig, dcaXYTrig, float); //! Impact parameter in XY of the track to the primary vertex +DECLARE_SOA_COLUMN(DcaZTrig, dcaZTrig, float); //! Impact parameter in Z of the track to the primary vertex +// General associated particle columns +DECLARE_SOA_COLUMN(EtaAssoc, etaAssoc, float); //! Eta of the associated candidate +DECLARE_SOA_COLUMN(PhiAssoc, phiAssoc, float); //! Phi of the associated candidate +DECLARE_SOA_COLUMN(PtAssoc, ptAssoc, float); //! Pt of the associated candidate +// Hadron associated particle selection columns +DECLARE_SOA_COLUMN(NTpcCrossedRowsAssoc, nTpcCrossedRowsAssoc, int); //! Number of crossed TPC Rows +DECLARE_SOA_COLUMN(ItsClsMapAssoc, itsClsMapAssoc, int); //! ITS cluster map, one bit per a layer, starting from the innermost +DECLARE_SOA_COLUMN(ItsNClsAssoc, itsNClsAssoc, int); //! Number of ITS clusters +DECLARE_SOA_COLUMN(DcaXYAssoc, dcaXYAssoc, float); //! Impact parameter in XY of the track to the primary vertex +DECLARE_SOA_COLUMN(DcaZAssoc, dcaZAssoc, float); //! Impact parameter in Z of the track to the primary vertex +} // namespace hf_correl_charm_had_reduced + +DECLARE_SOA_TABLE(HfcRedTrigBases, "AOD", "HFCREDTRIGBASE", //! Table with trigger candidate base info + soa::Index<>, + aod::hf_correl_charm_had_reduced::PhiTrig, + aod::hf_correl_charm_had_reduced::EtaTrig); + +DECLARE_SOA_TABLE(HfcRedTrigCharms, "AOD", "HFCREDTRIGCHARM", //! Table with Same Event Charm-Hadron pairs information + aod::hf_correl_charm_had_reduced::HfcRedCorrCollId, + aod::hf_correl_charm_had_reduced::PtTrig, + aod::hf_correl_charm_had_reduced::InvMassTrig, + aod::hf_correl_charm_had_reduced::BdtScore0Trig, + aod::hf_correl_charm_had_reduced::BdtScore1Trig); + +DECLARE_SOA_TABLE(HfcRedTrigTracks, "AOD", "HFCREDTRIGTRACK", //! Table with Same Event Charm-Hadron pairs information + aod::hf_correl_charm_had_reduced::HfcRedCorrCollId, + aod::hf_correl_charm_had_reduced::PtTrig, + aod::hf_correl_charm_had_reduced::NTpcCrossedRowsTrig, + aod::hf_correl_charm_had_reduced::ItsClsMapTrig, + aod::hf_correl_charm_had_reduced::ItsNClsTrig, + aod::hf_correl_charm_had_reduced::DcaXYTrig, + aod::hf_correl_charm_had_reduced::DcaZTrig); + +namespace hf_correl_charm_had_reduced +{ +DECLARE_SOA_INDEX_COLUMN(HfcRedTrigCharm, hfcRedTrigCharm); //! Same Event pair index +DECLARE_SOA_INDEX_COLUMN(HfcRedTrigTrack, hfcRedTrigTrack); //! Same Event pair index +} // namespace hf_correl_charm_had_reduced + +DECLARE_SOA_TABLE(HfcRedSEChBases, "AOD", "HFCREDSECHBASE", //! Table with Same Event Trig-Assoc pairs + aod::hf_correl_charm_had_reduced::HfcRedCorrCollId, + aod::hf_correl_charm_had_reduced::HfcRedTrigCharmId, + aod::hf_correl_charm_had_reduced::PtAssoc, + aod::hf_correl_charm_had_reduced::DeltaEta, + aod::hf_correl_charm_had_reduced::DeltaPhi); + +DECLARE_SOA_TABLE(HfcRedSEHadBases, "AOD", "HFCREDSEHADBASE", //! Table with Same Event Trig-Assoc pairs + aod::hf_correl_charm_had_reduced::HfcRedCorrCollId, + aod::hf_correl_charm_had_reduced::HfcRedTrigTrackId, + aod::hf_correl_charm_had_reduced::PtAssoc, + aod::hf_correl_charm_had_reduced::DeltaEta, + aod::hf_correl_charm_had_reduced::DeltaPhi); + +DECLARE_SOA_TABLE(HfcRedAssBases, "AOD", "HFCREDASSBASE", //! Table with associated candidate base info + soa::Index<>, + aod::hf_correl_charm_had_reduced::HfcRedCorrCollId, + aod::hf_correl_charm_had_reduced::PhiAssoc, + aod::hf_correl_charm_had_reduced::EtaAssoc, + aod::hf_correl_charm_had_reduced::PtAssoc); + +DECLARE_SOA_TABLE(HfcRedAssTracks, "AOD", "HFCREDASSTRACK", //! Table with Same Event Track Selections information + aod::hf_correl_charm_had_reduced::NTpcCrossedRowsAssoc, + aod::hf_correl_charm_had_reduced::ItsClsMapAssoc, + aod::hf_correl_charm_had_reduced::ItsNClsAssoc, + aod::hf_correl_charm_had_reduced::DcaXYAssoc, + aod::hf_correl_charm_had_reduced::DcaZAssoc); + +DECLARE_SOA_TABLE(HfcRedSEChHads, "AOD", "HFCREDSECHHAD", //! Correlation pairs information Same Event + aod::hf_correl_charm_had_reduced::PoolBin, + aod::hf_correl_charm_had_reduced::PtTrig, + aod::hf_correl_charm_had_reduced::PtAssoc, + aod::hf_correl_charm_had_reduced::DeltaEta, + aod::hf_correl_charm_had_reduced::DeltaPhi, + aod::hf_correl_charm_had_reduced::InvMassTrig, + aod::hf_correl_charm_had_reduced::BdtScore0Trig, + aod::hf_correl_charm_had_reduced::BdtScore1Trig, + aod::hf_correl_charm_had_reduced::NTpcCrossedRowsAssoc, + aod::hf_correl_charm_had_reduced::ItsClsMapAssoc, + aod::hf_correl_charm_had_reduced::ItsNClsAssoc, + aod::hf_correl_charm_had_reduced::DcaXYAssoc, + aod::hf_correl_charm_had_reduced::DcaZAssoc, + soa::Marker<1>); + +DECLARE_SOA_TABLE(HfcRedMEChHads, "AOD", "HFCREDMECHHAD", //! Correlation pairs information Same Event + aod::hf_correl_charm_had_reduced::PoolBin, + aod::hf_correl_charm_had_reduced::PtTrig, + aod::hf_correl_charm_had_reduced::PtAssoc, + aod::hf_correl_charm_had_reduced::DeltaEta, + aod::hf_correl_charm_had_reduced::DeltaPhi, + aod::hf_correl_charm_had_reduced::InvMassTrig, + aod::hf_correl_charm_had_reduced::BdtScore0Trig, + aod::hf_correl_charm_had_reduced::BdtScore1Trig, + aod::hf_correl_charm_had_reduced::NTpcCrossedRowsAssoc, + aod::hf_correl_charm_had_reduced::ItsClsMapAssoc, + aod::hf_correl_charm_had_reduced::ItsNClsAssoc, + aod::hf_correl_charm_had_reduced::DcaXYAssoc, + aod::hf_correl_charm_had_reduced::DcaZAssoc, + soa::Marker<2>); + +DECLARE_SOA_TABLE(HfcRedSEHadHads, "AOD", "HFCREDSEHADHAD", //! Correlation pairs information Same Event + aod::hf_correl_charm_had_reduced::PoolBin, + aod::hf_correl_charm_had_reduced::PtTrig, + aod::hf_correl_charm_had_reduced::PtAssoc, + aod::hf_correl_charm_had_reduced::DeltaEta, + aod::hf_correl_charm_had_reduced::DeltaPhi, + aod::hf_correl_charm_had_reduced::NTpcCrossedRowsTrig, + aod::hf_correl_charm_had_reduced::ItsClsMapTrig, + aod::hf_correl_charm_had_reduced::ItsNClsTrig, + aod::hf_correl_charm_had_reduced::DcaXYTrig, + aod::hf_correl_charm_had_reduced::DcaZTrig, + aod::hf_correl_charm_had_reduced::NTpcCrossedRowsAssoc, + aod::hf_correl_charm_had_reduced::ItsClsMapAssoc, + aod::hf_correl_charm_had_reduced::ItsNClsAssoc, + aod::hf_correl_charm_had_reduced::DcaXYAssoc, + aod::hf_correl_charm_had_reduced::DcaZAssoc, + soa::Marker<1>); + +DECLARE_SOA_TABLE(HfcRedMEHadHads, "AOD", "HFCREDMEHADHAD", //! Correlation pairs information Same Event + aod::hf_correl_charm_had_reduced::PoolBin, + aod::hf_correl_charm_had_reduced::PtTrig, + aod::hf_correl_charm_had_reduced::PtAssoc, + aod::hf_correl_charm_had_reduced::DeltaEta, + aod::hf_correl_charm_had_reduced::DeltaPhi, + aod::hf_correl_charm_had_reduced::NTpcCrossedRowsTrig, + aod::hf_correl_charm_had_reduced::ItsClsMapTrig, + aod::hf_correl_charm_had_reduced::ItsNClsTrig, + aod::hf_correl_charm_had_reduced::DcaXYTrig, + aod::hf_correl_charm_had_reduced::DcaZTrig, + aod::hf_correl_charm_had_reduced::NTpcCrossedRowsAssoc, + aod::hf_correl_charm_had_reduced::ItsClsMapAssoc, + aod::hf_correl_charm_had_reduced::ItsNClsAssoc, + aod::hf_correl_charm_had_reduced::DcaXYAssoc, + aod::hf_correl_charm_had_reduced::DcaZAssoc, + soa::Marker<2>); + +DECLARE_SOA_TABLE(HfcRedCollInfos, "AOD", "HFCREDCOLLINFO", //! Table with collision info + aod::hf_collisions_reduced::Multiplicity, + aod::hf_collisions_reduced::NumPvContrib, + aod::hf_collisions_reduced::Centrality); +} // 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..f2566f4f9a6 100644 --- a/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx +++ b/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx @@ -10,44 +10,100 @@ // or submit itself to any jurisdiction. /// \file DhCorrelationExtraction.cxx -/// \brief Class for D-h correlation extraction +/// \brief class for D-h correlation extraction /// \author Samuele Cattaruzzi /// \author Swapnesh Santosh Khade #include "DhCorrelationExtraction.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + DhCorrelationExtraction::DhCorrelationExtraction() : // default constructor - fFileMass(0x0), - fFileSE(0x0), - fFileME(0x0), - fDirMass(0x0), - fDirSE(0x0), - fDirME(0x0), - fCorrectedCorrHisto(0x0), + fFileMass(nullptr), + fFileSE(nullptr), + fFileME(nullptr), + fFileFDTemplate(nullptr), + fFileFDPromptFrac(nullptr), + fFileSecPart(nullptr), + fFilePromptMc(nullptr), + fFileNonPromptMc(nullptr), + fDirMass(nullptr), + fDirSE(nullptr), + fDirME(nullptr), + fDirSecPart(nullptr), + fCorrectedCorrHisto(nullptr), + fCorrectedCorrHistoBaselineSubtr(nullptr), + fCorrectedCorrHistoReflected(nullptr), + fCorrectedCorrHistoReflectedBaselineSubtr(nullptr), fDmesonSpecies(kDsToKKPi), fDmesonLabel("Ds"), - fNpools(9), - fDeltaEtaMin(-1.), - fDeltaEtaMax(1.), - fCorrectPoolsSeparately(kTRUE), - fSubtractSoftPiME(kFALSE), fFileNameSE(""), fFileNameME(""), + fFileSecPartName(""), + fFileFDTemplateName(""), + fFileFDPromptFracName(""), + fFilePromptMcRecName(""), + fFileNonPromptMcRecName(""), fDirNameSE(""), fDirNameME(""), + fDirSecPartName(""), fMassHistoNameSgn(""), fMassHistoNameBkg(""), fMassHistoNameSBs(""), fSECorrelSignalRegionName(""), fSECorrelSidebandsName(""), + fSECorrelSidebandLeftName(""), + fSECorrelSidebandRightName(""), fMECorrelSignalRegionName(""), fMECorrelSidebandsName(""), - fBkgScaleFactor(1.), - fSgnYieldNorm(1.), - fRebin2Dhisto(kFALSE), + fMECorrelSidebandLeftName(""), + fMECorrelSidebandRightName(""), + fHistoFDTemplatePromptName(""), + fHistoFDTemplateNonPromptName(""), + fHistoFDPromptFracName(""), + fHistoPrimaryPartName(""), + fHistoAllPartName(""), + fNpools(9), fRebinAxisDeltaEta(1), fRebinAxisDeltaPhi(1), - fDebug(0) + fDebug(0), + fBinPtCand(0), + fBinPtHad(0), + fDeltaEtaMin(-1.), + fDeltaEtaMax(1.), + fBkgScaleFactor(1.), + fSgnYieldNorm(1.), + fBkgYield(1.), + fCorrectPoolsSeparately(kTRUE), + fSubtractSoftPiME(kFALSE), + fRebinAngCorr(kFALSE), + fRebinFDCorr(kFALSE), + fRebinSecPart(kFALSE), + fSidebandDivided(kFALSE), + fUseSidebLeft(kFALSE), + fUseSidebRight(kFALSE), + fFDsubtraction(false), + fSecPartContamination(false), + fCorrBiasBtoD(false) { } @@ -55,49 +111,84 @@ DhCorrelationExtraction::DhCorrelationExtraction(const DhCorrelationExtraction& fFileMass(source.fFileMass), fFileSE(source.fFileSE), fFileME(source.fFileME), + fFileFDTemplate(source.fFileFDTemplate), + fFileFDPromptFrac(source.fFileFDPromptFrac), + fFileSecPart(source.fFileSecPart), + fFilePromptMc(source.fFilePromptMc), + fFileNonPromptMc(source.fFileNonPromptMc), fDirMass(source.fDirMass), fDirSE(source.fDirSE), fDirME(source.fDirME), + fDirSecPart(source.fDirSecPart), fCorrectedCorrHisto(source.fCorrectedCorrHisto), + fCorrectedCorrHistoBaselineSubtr(source.fCorrectedCorrHistoBaselineSubtr), + fCorrectedCorrHistoReflected(source.fCorrectedCorrHistoReflected), + fCorrectedCorrHistoReflectedBaselineSubtr(source.fCorrectedCorrHistoReflectedBaselineSubtr), fDmesonSpecies(source.fDmesonSpecies), fDmesonLabel(source.fDmesonLabel), - fNpools(source.fNpools), - fDeltaEtaMin(source.fDeltaEtaMin), - fDeltaEtaMax(source.fDeltaEtaMax), - fCorrectPoolsSeparately(source.fCorrectPoolsSeparately), - fSubtractSoftPiME(source.fSubtractSoftPiME), fFileNameSE(source.fFileNameSE), fFileNameME(source.fFileNameME), + fFileSecPartName(source.fFileSecPartName), + fFileFDTemplateName(source.fFileFDTemplateName), + fFileFDPromptFracName(source.fFileFDPromptFracName), + fFilePromptMcRecName(source.fFilePromptMcRecName), + fFileNonPromptMcRecName(source.fFileNonPromptMcRecName), fDirNameSE(source.fDirNameSE), fDirNameME(source.fDirNameME), + fDirSecPartName(source.fDirSecPartName), fMassHistoNameSgn(source.fMassHistoNameSgn), fMassHistoNameBkg(source.fMassHistoNameBkg), fMassHistoNameSBs(source.fMassHistoNameSBs), fSECorrelSignalRegionName(source.fSECorrelSignalRegionName), fSECorrelSidebandsName(source.fSECorrelSidebandsName), + fSECorrelSidebandLeftName(source.fSECorrelSidebandLeftName), + fSECorrelSidebandRightName(source.fSECorrelSidebandRightName), fMECorrelSignalRegionName(source.fMECorrelSignalRegionName), fMECorrelSidebandsName(source.fMECorrelSidebandsName), - fBkgScaleFactor(source.fBkgScaleFactor), - fSgnYieldNorm(source.fSgnYieldNorm), - fRebin2Dhisto(source.fRebin2Dhisto), + fMECorrelSidebandLeftName(source.fMECorrelSidebandLeftName), + fMECorrelSidebandRightName(source.fMECorrelSidebandRightName), + fHistoFDTemplatePromptName(source.fHistoFDTemplatePromptName), + fHistoFDTemplateNonPromptName(source.fHistoFDTemplateNonPromptName), + fHistoFDPromptFracName(source.fHistoFDPromptFracName), + fHistoPrimaryPartName(source.fHistoPrimaryPartName), + fHistoAllPartName(source.fHistoAllPartName), + fNpools(source.fNpools), fRebinAxisDeltaEta(source.fRebinAxisDeltaEta), fRebinAxisDeltaPhi(source.fRebinAxisDeltaPhi), - fDebug(source.fDebug) + fDebug(source.fDebug), + fBinPtCand(source.fBinPtCand), + fBinPtHad(source.fBinPtHad), + fDeltaEtaMin(source.fDeltaEtaMin), + fDeltaEtaMax(source.fDeltaEtaMax), + fBkgScaleFactor(source.fBkgScaleFactor), + fSgnYieldNorm(source.fSgnYieldNorm), + fBkgYield(source.fBkgYield), + fCorrectPoolsSeparately(source.fCorrectPoolsSeparately), + fSubtractSoftPiME(source.fSubtractSoftPiME), + fRebinAngCorr(source.fRebinAngCorr), + fRebinFDCorr(source.fRebinFDCorr), + fRebinSecPart(source.fRebinSecPart), + fSidebandDivided(source.fSidebandDivided), + fUseSidebLeft(source.fUseSidebLeft), + fUseSidebRight(source.fUseSidebRight), + fFDsubtraction(source.fFDsubtraction), + fSecPartContamination(source.fSecPartContamination), + fCorrBiasBtoD(source.fCorrBiasBtoD) { } DhCorrelationExtraction::~DhCorrelationExtraction() -// destructor -{ -} + // destructor + = default; -Bool_t DhCorrelationExtraction::SetDmesonSpecie(DmesonSpecie k) +Bool_t DhCorrelationExtraction::setDmesonSpecie(DmesonSpecie k) { if (k < 0 || k > 3) { printf("[ERROR] D meson specie not correctly set!\n"); return kFALSE; - } else if (k == 0) { + } + if (k == 0) { fDmesonLabel = "Dzero"; } else if (k == 1) { fDmesonLabel = "Dplus"; @@ -106,241 +197,658 @@ Bool_t DhCorrelationExtraction::SetDmesonSpecie(DmesonSpecie k) } else { fDmesonLabel = "Dstar"; } - fDmesonSpecies = k; return kTRUE; } -Bool_t DhCorrelationExtraction::ExtractCorrelations(Double_t PtCandMin, Double_t PtCandMax, Double_t PtHadMin, Double_t PtHadMax, TString codeName) +Bool_t DhCorrelationExtraction::extractCorrelations(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax, TString codeName) { if (fSubtractSoftPiME) { printf("[INFO] Fake softPi subtraction in ME via extraction code is enabled!\n"); } - if (!fCorrectPoolsSeparately) + if (!fCorrectPoolsSeparately) { fNpools = 1; // single histogram with integrated pools + } // Histograms definition - TH2D* hSE_Sign[fNpools]; - TH2D* hME_Sign[fNpools]; - TH2D* hME_Sign_SoftPi[fNpools]; - TH2D* hSE_Sideb[fNpools]; - TH2D* hME_Sideb[fNpools]; - TH2D* hME_Sideb_SoftPi[fNpools]; - - TH2D* hCorr_Sign[fNpools]; - TH2D* hCorr_Sideb[fNpools]; - - TH2D* h2D_Sign; - TH2D* h2D_Sideb; - TH2D* h2D_Subtr; - - TH1D* h1D_Sign; - TH1D* h1D_Sideb; - TH1D* h1D_Subtr; - TH1D* h1D_SubtrNorm; + TH2D* hSeSign[fNpools]; + TH2D* hMeSign[fNpools]; + TH2D* hMeSignSoftPi[fNpools]; + TH2D* hSeSideb[fNpools]; + TH2D* hMeSideb[fNpools]; + TH2D* hMeSidebSoftPi[fNpools]; + + TH2D* hCorrSign[fNpools]; + TH2D* hCorrSideb[fNpools]; + + TH2D* h2DSign; + TH2D* h2DSideb; + TH2D* h2DSubtr; + + TH2D* h2DFdTemplatePrompt; + TH2D* h2DFdTemplateNonPrompt; + + TH1D* h1DSign; + TH1D* h1DSideb; + TH1D* h1DSubtr; + TH1D* h1DSignNorm; + TH1D* h1DSidebNorm; + TH1D* h1DSubtrNorm; + TH1D* h1DFdTemplatePrompt; + TH1D* h1DFdTemplateNonPrompt; + TH1D* h1DTemplateTotal; + TH1D* h1DSubtrFdNorm; + TH1D* h1DPrimaryPartCorr; + TH1D* h1DAllPartCorr; + TH1D* h1DSecPartFrac; + TH1D* h1DSubtrNormSecPart; + TH1D* h1DBaselineSubtr; + TH1D* h1DReflCorr; + TH1D* h1DReflCorrBaselineSubtr; + TH1D* hModul; + TH1D* hBeforeModulCorr; + + Double_t fdPromptFrac; // if (fIntegratePtBins && iBinPtHad>0) continue; for (int iPool = 0; iPool < fNpools; iPool++) { - // Retrieve 2D plots for SE and ME, signal and bkg regions, for each pTbin and pool - hSE_Sign[iPool] = GetCorrelHisto(kSE, kSign, iPool, PtCandMin, PtCandMax, PtHadMin, PtHadMax); - hME_Sign[iPool] = GetCorrelHisto(kME, kSign, iPool, PtCandMin, PtCandMax, PtHadMin, PtHadMax); - hSE_Sideb[iPool] = GetCorrelHisto(kSE, kSideb, iPool, PtCandMin, PtCandMax, PtHadMin, PtHadMax); - hME_Sideb[iPool] = GetCorrelHisto(kME, kSideb, iPool, PtCandMin, PtCandMax, PtHadMin, PtHadMax); - - hSE_Sign[iPool]->Sumw2(); - hME_Sign[iPool]->Sumw2(); - hSE_Sideb[iPool]->Sumw2(); - hME_Sideb[iPool]->Sumw2(); + hSeSign[iPool] = getCorrelHisto(kSE, kSign, iPool, ptCandMin, ptCandMax, ptHadMin, ptHadMax); + std::cout << "Got SE histogram signal region" << std::endl; + hMeSign[iPool] = getCorrelHisto(kME, kSign, iPool, ptCandMin, ptCandMax, ptHadMin, ptHadMax); + std::cout << "Got ME histogram signal region" << std::endl; + hSeSideb[iPool] = getCorrelHisto(kSE, kSideb, iPool, ptCandMin, ptCandMax, ptHadMin, ptHadMax); + std::cout << "Got SE histogram sdeband region" << std::endl; + hMeSideb[iPool] = getCorrelHisto(kME, kSideb, iPool, ptCandMin, ptCandMax, ptHadMin, ptHadMax); + std::cout << "Got ME histogram sdeband region" << std::endl; + + hSeSign[iPool]->Sumw2(); + hMeSign[iPool]->Sumw2(); + hSeSideb[iPool]->Sumw2(); + hMeSideb[iPool]->Sumw2(); // rebin axes deltaEta and deltaPhi - if (fRebin2Dhisto) { - hSE_Sign[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); // Xaxis: deltaEta, Yaxis: deltaPhi - hSE_Sideb[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); - hME_Sign[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); - hME_Sideb[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); + if (fRebinAngCorr) { + hSeSign[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); // Xaxis: deltaEta, Yaxis: deltaPhi + hSeSideb[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); + hMeSign[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); + hMeSideb[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); if (fSubtractSoftPiME) { - hME_Sideb_SoftPi[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); + hMeSidebSoftPi[iPool]->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); } + std::cout << "SE and ME histograms rebinned" << std::endl; } if (fDebug >= 1) { - TCanvas* c = new TCanvas(Form("cSEME_Original_%d_%1.1fto%1.1f", iPool, PtHadMin, PtHadMax), Form("cSEME_Original_%s_pool%d_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), iPool, PtCandMin, PtCandMax, PtHadMin, PtHadMax), 100, 100, 1600, 900); - c->Divide(2, 2); + auto* c = new TCanvas(Form("cSE_Original_%d_%1.1fto%1.1f", iPool, ptHadMin, ptHadMax), Form("cSE_Original_%s_pool%d_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), iPool, ptCandMin, ptCandMax, ptHadMin, ptHadMax), 100, 100, 1600, 900); + c->Divide(2, 1); c->cd(1); - hSE_Sign[iPool]->SetMinimum(0); - hSE_Sign[iPool]->Draw("lego2"); + hSeSign[iPool]->SetMinimum(0); + hSeSign[iPool]->Draw("lego2"); c->cd(2); - hME_Sign[iPool]->SetMinimum(0); - hME_Sign[iPool]->Draw("lego2"); - c->cd(3); - hSE_Sideb[iPool]->SetMinimum(0); - hSE_Sideb[iPool]->Draw("lego2"); - c->cd(4); - hME_Sideb[iPool]->SetMinimum(0); - hME_Sideb[iPool]->Draw("lego2"); - c->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrSEandME_Original_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); - c->SaveAs(Form("Output_CorrelationExtraction_%s_Root/CorrSEandME_Original_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); + hSeSideb[iPool]->SetMinimum(0); + hSeSideb[iPool]->Draw("lego2"); + c->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrSE_Original_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c->SaveAs(Form("Output_CorrelationExtraction_%s_Root/CorrSE_Original_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } + + if (fDebug >= 1) { + auto* c = new TCanvas(Form("cME_Original_%d_%1.1fto%1.1f", iPool, ptHadMin, ptHadMax), Form("cME_Original_%s_pool%d_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), iPool, ptCandMin, ptCandMax, ptHadMin, ptHadMax), 100, 100, 1600, 900); + c->Divide(2, 1); + c->cd(1); + hMeSign[iPool]->SetMinimum(0); + hMeSign[iPool]->Draw("lego2"); + c->cd(2); + hMeSideb[iPool]->SetMinimum(0); + hMeSideb[iPool]->Draw("lego2"); + c->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrME_Original_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c->SaveAs(Form("Output_CorrelationExtraction_%s_Root/CorrME_Original_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); } // Scale bkg plots by ratio of signal region/sidebands - hSE_Sideb[iPool]->Scale(fBkgScaleFactor); - hME_Sideb[iPool]->Scale(fBkgScaleFactor); - hSE_Sideb[iPool]->SetEntries(hSE_Sideb[iPool]->GetEntries() * fBkgScaleFactor); - hME_Sideb[iPool]->SetEntries(hME_Sideb[iPool]->GetEntries() * fBkgScaleFactor); + hSeSideb[iPool]->Scale(fBkgScaleFactor); + hMeSideb[iPool]->Scale(fBkgScaleFactor); // when normalised this factor should cancel out + std::cout << "[INFO] fBkgScaleFactor = " << fBkgScaleFactor << std::endl; + hSeSideb[iPool]->SetEntries(hSeSideb[iPool]->GetEntries() * fBkgScaleFactor); + hMeSideb[iPool]->SetEntries(hMeSideb[iPool]->GetEntries() * fBkgScaleFactor); if (fSubtractSoftPiME) { - hME_Sideb_SoftPi[iPool]->Scale(fBkgScaleFactor); - hME_Sideb_SoftPi[iPool]->SetEntries(hME_Sideb_SoftPi[iPool]->GetEntries() * fBkgScaleFactor); + hMeSidebSoftPi[iPool]->Scale(fBkgScaleFactor); + hMeSidebSoftPi[iPool]->SetEntries(hMeSidebSoftPi[iPool]->GetEntries() * fBkgScaleFactor); } // Normalize ME plots for the entries in (deltaEta, deltaPhi) = (0, 0) - NormalizeMEplot(hME_Sign[iPool], hME_Sign_SoftPi[iPool]); - NormalizeMEplot(hME_Sideb[iPool], hME_Sideb_SoftPi[iPool]); + normalizeMePlot(hMeSign[iPool], hMeSignSoftPi[iPool]); + normalizeMePlot(hMeSideb[iPool], hMeSidebSoftPi[iPool]); // Apply Event Mixing Correction - hCorr_Sign[iPool] = reinterpret_cast(hSE_Sign[iPool]->Clone(Form("hCorr_Sign_Pool%d", iPool))); - hCorr_Sign[iPool]->Sumw2(); - hCorr_Sign[iPool]->Divide(hME_Sign[iPool]); - - hCorr_Sideb[iPool] = reinterpret_cast(hSE_Sideb[iPool]->Clone(Form("hCorr_Sideb_Pool%d", iPool))); - hCorr_Sideb[iPool]->Sumw2(); - hCorr_Sideb[iPool]->Divide(hME_Sideb[iPool]); - - Double_t N_SEsign = 0, N_SEsideb = 0, N_sign = 0, N_sideb = 0; - for (int i = 1; i <= hCorr_Sign[iPool]->GetXaxis()->GetNbins(); i++) { - for (int j = 1; j <= hCorr_Sign[iPool]->GetYaxis()->GetNbins(); j++) { - N_SEsign += hSE_Sign[iPool]->GetBinContent(i, j); - N_SEsideb += hSE_Sideb[iPool]->GetBinContent(i, j); - N_sign += hCorr_Sign[iPool]->GetBinContent(i, j); - N_sideb += hCorr_Sideb[iPool]->GetBinContent(i, j); + hCorrSign[iPool] = reinterpret_cast(hSeSign[iPool]->Clone(Form("hCorr_Sign_Pool%d", iPool))); + hCorrSign[iPool]->Sumw2(); + hCorrSign[iPool]->Divide(hMeSign[iPool]); + + hCorrSideb[iPool] = reinterpret_cast(hSeSideb[iPool]->Clone(Form("hCorr_Sideb_Pool%d", iPool))); + hCorrSideb[iPool]->Sumw2(); + hCorrSideb[iPool]->Divide(hMeSideb[iPool]); + + Double_t nSEsign = 0, nSEsideb = 0, nSign = 0, nSideb = 0; + for (int i = 1; i <= hCorrSign[iPool]->GetXaxis()->GetNbins(); i++) { + for (int j = 1; j <= hCorrSign[iPool]->GetYaxis()->GetNbins(); j++) { + nSEsign += hSeSign[iPool]->GetBinContent(i, j); + nSEsideb += hSeSideb[iPool]->GetBinContent(i, j); + nSign += hCorrSign[iPool]->GetBinContent(i, j); + nSideb += hCorrSideb[iPool]->GetBinContent(i, j); } } - hSE_Sign[iPool]->SetEntries(N_SEsign); - hSE_Sideb[iPool]->SetEntries(N_SEsideb); - hCorr_Sign[iPool]->SetEntries(N_sign); - hCorr_Sideb[iPool]->SetEntries(N_sideb); + hSeSign[iPool]->SetEntries(nSEsign); + hSeSideb[iPool]->SetEntries(nSEsideb); + hCorrSign[iPool]->SetEntries(nSign); + hCorrSideb[iPool]->SetEntries(nSideb); if (fDebug >= 1) { - TCanvas* c = new TCanvas(Form("cSEME_%d_%1.1fto%1.1f", iPool, PtHadMin, PtHadMax), Form("cSEME_%s_pool%d_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), iPool, PtCandMin, PtCandMax, PtHadMin, PtHadMax), 100, 100, 1600, 900); + auto* c = new TCanvas(Form("cSEME_%d_%1.1fto%1.1f", iPool, ptHadMin, ptHadMax), Form("cSEME_%s_pool%d_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), iPool, ptCandMin, ptCandMax, ptHadMin, ptHadMax), 100, 100, 1600, 900); c->Divide(3, 2); c->cd(1); - hSE_Sign[iPool]->SetMinimum(0); - hSE_Sign[iPool]->Draw("lego2"); + hSeSign[iPool]->SetMinimum(0); + hSeSign[iPool]->Draw("lego2"); c->cd(2); - hME_Sign[iPool]->SetMinimum(0); - hME_Sign[iPool]->Draw("lego2"); + hMeSign[iPool]->SetMinimum(0); + hMeSign[iPool]->Draw("lego2"); c->cd(3); - hCorr_Sign[iPool]->SetMinimum(0); - hCorr_Sign[iPool]->Draw("lego2"); + hCorrSign[iPool]->SetMinimum(0); + hCorrSign[iPool]->Draw("lego2"); c->cd(4); - hSE_Sideb[iPool]->SetMinimum(0); - hSE_Sideb[iPool]->Draw("lego2"); + hSeSideb[iPool]->SetMinimum(0); + hSeSideb[iPool]->Draw("lego2"); c->cd(5); - hME_Sideb[iPool]->SetMinimum(0); - hME_Sideb[iPool]->Draw("lego2"); + hMeSideb[iPool]->SetMinimum(0); + hMeSideb[iPool]->Draw("lego2"); c->cd(6); - hCorr_Sideb[iPool]->SetMinimum(0); - hCorr_Sideb[iPool]->Draw("lego2"); - c->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrSEandME_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); - c->SaveAs(Form("Output_CorrelationExtraction_%s_Root/CorrSEandME_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); + hCorrSideb[iPool]->SetMinimum(0); + hCorrSideb[iPool]->Draw("lego2"); + c->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrSEandME_%s_Canvas_PtCand%.0fto%.0f_Pool%d_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, iPool, ptHadMin, ptHadMax)); + c->SaveAs(Form("Output_CorrelationExtraction_%s_Root/CorrSEandME_%s_Canvas_PtCand%.0fto%.0f_Pool%d_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, iPool, ptHadMin, ptHadMax)); } // Pools integration if (iPool == 0) { - h2D_Sign = reinterpret_cast(hCorr_Sign[0]->Clone("h2D_Sign")); - h2D_Sideb = reinterpret_cast(hCorr_Sideb[0]->Clone("h2D_Sideb")); - h2D_Sign->Sumw2(); - h2D_Sideb->Sumw2(); + h2DSign = reinterpret_cast(hCorrSign[0]->Clone("h2D_Sign")); + h2DSideb = reinterpret_cast(hCorrSideb[0]->Clone("h2D_Sideb")); + h2DSign->Sumw2(); + h2DSideb->Sumw2(); } else { - h2D_Sign->Add(hCorr_Sign[iPool]); - h2D_Sideb->Add(hCorr_Sideb[iPool]); + h2DSign->Add(hCorrSign[iPool]); + h2DSideb->Add(hCorrSideb[iPool]); } } // end pool loop // Draw 2D plots (Signal region and Sidebands) - TCanvas* c2D = new TCanvas(Form("c2D_IntPools_PtHad%.0fto%.0f", PtHadMin, PtHadMax), Form("c2D_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), PtHadMin, PtHadMax), 100, 100, 1500, 800); - SetTH2HistoStyle(h2D_Sign, Form("Signal region, %.0f < p^{%s}_{T} < %.0f GeV/c, %.0f < p^{assoc}_{T} < %.0f GeV/c", PtCandMin, fDmesonLabel.Data(), PtCandMax, PtHadMin, PtHadMax), "#Delta#eta", "#Delta#phi [rad]", "entries", 1.6, 1.6, 1.6, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04); - SetTH2HistoStyle(h2D_Sideb, Form("Sideband region, %.0f < p^{%s}_{T} < %.0f GeV/c, %.0f < p^{assoc}_{T} < %.0f GeV/c", PtCandMin, fDmesonLabel.Data(), PtCandMax, PtHadMin, PtHadMax), "#Delta#eta", "#Delta#phi [rad]", "#frac{Y_{Bkg}}{Y_{SB}} entries", 1.6, 1.6, 1.6, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04); + auto* c2D = new TCanvas(Form("c2D_IntPools_PtHad%.0fto%.0f", ptHadMin, ptHadMax), Form("c2D_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax), 100, 100, 1500, 800); + setTH2HistoStyle(h2DSign, Form("Signal region, %.0f < p^{%s}_{T} < %.0f GeV/c, %.0f < p^{assoc}_{T} < %.0f GeV/c", ptCandMin, fDmesonLabel.Data(), ptCandMax, ptHadMin, ptHadMax), "#Delta#eta", "#Delta#phi [rad]", "entries", 1.6, 1.6, 1.6, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04); + setTH2HistoStyle(h2DSideb, Form("Sideband region, %.0f < p^{%s}_{T} < %.0f GeV/c, %.0f < p^{assoc}_{T} < %.0f GeV/c", ptCandMin, fDmesonLabel.Data(), ptCandMax, ptHadMin, ptHadMax), "#Delta#eta", "#Delta#phi [rad]", "#frac{Y_{Bkg}}{Y_{SB}} entries", 1.6, 1.6, 1.6, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04); c2D->Divide(2, 1); c2D->cd(1); - h2D_Sign->SetMinimum(0); - h2D_Sign->Draw("lego2"); + h2DSign->SetMinimum(0); + h2DSign->Draw("lego2"); c2D->cd(2); - h2D_Sideb->SetMinimum(0); - h2D_Sideb->Draw("lego2"); - c2D->SaveAs(Form("Output_CorrelationExtraction_%s_png/h2D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); - c2D->SaveAs(Form("Output_CorrelationExtraction_%s_Root/h2D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); + h2DSideb->SetMinimum(0); + h2DSideb->Draw("lego2"); + c2D->SaveAs(Form("Output_CorrelationExtraction_%s_png/h2D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c2D->SaveAs(Form("Output_CorrelationExtraction_%s_Root/h2D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + // Get FD correlations for FD subtraction + if (fFDsubtraction) { + h2DFdTemplatePrompt = getFdTemplateHisto(kPrompt, ptCandMin, ptCandMax, ptHadMin, ptHadMax); + h2DFdTemplateNonPrompt = getFdTemplateHisto(kFD, ptCandMin, ptCandMax, ptHadMin, ptHadMax); + // h1D_BaselineSubtr + fdPromptFrac = getFdPromptFrac(ptCandMin, ptCandMax, ptHadMin, ptHadMax); + + if (fRebinFDCorr) { + h2DFdTemplatePrompt->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); + h2DFdTemplateNonPrompt->Rebin2D(fRebinAxisDeltaEta, fRebinAxisDeltaPhi); + } + + if (fDebug >= 1) { + auto* c = new TCanvas(Form("cFDTemplate_PtCand%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax), Form("cFDTemplate_%s_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c->Divide(2, 1); + c->cd(1); + h2DFdTemplatePrompt->SetMinimum(0); + h2DFdTemplatePrompt->Draw("lego2"); + c->cd(2); + h2DFdTemplateNonPrompt->SetMinimum(0); + h2DFdTemplateNonPrompt->Draw("lego2"); + c->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrFDTemplate_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } + } // Bkg subtraction (2D plot) - TCanvas* c2D_Sub = new TCanvas(Form("c2D_Subtr_IntPools_PtHAd%.0fto%.0f", PtHadMin, PtHadMax), Form("c2D_%s_Subtr_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), PtHadMin, PtHadMax), 100, 100, 1500, 800); - h2D_Subtr = reinterpret_cast(h2D_Sign->Clone("h2D_Subtr")); - h2D_Subtr->Sumw2(); - h2D_Subtr->Add(h2D_Sideb, -1); - h2D_Subtr->SetEntries(h2D_Sign->GetEntries() - h2D_Sideb->GetEntries()); - h2D_Subtr->SetTitle("Signal region after sideb. subt. corr. - 2D"); - h2D_Subtr->Draw("lego2"); - c2D_Sub->SaveAs(Form("Output_CorrelationExtraction_%s_png/h2D_%s_Subtr_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); - c2D_Sub->SaveAs(Form("Output_CorrelationExtraction_%s_Root/h2D_%s_Subtr_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); + auto* c2DSub = new TCanvas(Form("c2D_Subtr_IntPools_PtHAd%.0fto%.0f", ptHadMin, ptHadMax), Form("c2D_%s_Subtr_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax), 100, 100, 1500, 800); + h2DSubtr = reinterpret_cast(h2DSign->Clone("h2D_Subtr")); + h2DSubtr->Sumw2(); + h2DSubtr->Add(h2DSideb, -1); + h2DSubtr->SetEntries(h2DSign->GetEntries() - h2DSideb->GetEntries()); + h2DSubtr->SetTitle("Signal region after sideb. subt. corr. - 2D"); + h2DSubtr->Draw("lego2"); + c2DSub->SaveAs(Form("Output_CorrelationExtraction_%s_png/h2D_%s_Subtr_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c2DSub->SaveAs(Form("Output_CorrelationExtraction_%s_Root/h2D_%s_Subtr_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); // 1D projection - h1D_Sign = reinterpret_cast(h2D_Sign->ProjectionY("h1D_Sign")); // projection on deltaPhi axis - h1D_Sideb = reinterpret_cast(h2D_Sideb->ProjectionY("h1D_Sideb")); - h1D_Sign->SetTitle("Signal region correlations"); - h1D_Sideb->SetTitle("Sidebands correlations"); - h1D_Sign->Scale(1. / h1D_Sign->GetXaxis()->GetBinWidth(1)); - h1D_Sideb->Scale(1. / h1D_Sideb->GetXaxis()->GetBinWidth(1)); + h1DSign = h2DSign->ProjectionY("h1D_Sign"); // projection on deltaPhi axis + h1DSideb = h2DSideb->ProjectionY("h1D_Sideb"); + h1DSign->SetTitle("Signal region correlations"); + h1DSideb->SetTitle("Sidebands correlations"); + h1DSign->Scale(1. / h1DSign->GetXaxis()->GetBinWidth(1)); + h1DSideb->Scale(1. / h1DSideb->GetXaxis()->GetBinWidth(1)); // Bkg subtraction (1D plot) - h1D_Subtr = reinterpret_cast(h1D_Sign->Clone("h1D_Subtr")); - h1D_Subtr->Sumw2(); - h1D_Subtr->Add(h1D_Sideb, -1); - h1D_Subtr->SetEntries(h1D_Sign->GetEntries() - h1D_Sideb->GetEntries()); - h1D_Subtr->SetTitle("Signal region after sideb. subt. corr."); + h1DSubtr = reinterpret_cast(h1DSign->Clone("h1D_Subtr")); + h1DSubtr->Sumw2(); + h1DSubtr->Add(h1DSideb, -1); + h1DSubtr->SetEntries(h1DSign->GetEntries() - h1DSideb->GetEntries()); + h1DSubtr->SetTitle("Signal region after sideb. subt. corr."); // Draw 1D plots (Signal region, Sidebands, S-SB (subtr.)) - TCanvas* c1D = new TCanvas(Form("c1D_IntPools_%.0fto%.0f", PtHadMin, PtHadMax), Form("c1D_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), PtHadMin, PtHadMax), 100, 100, 1600, 500); + auto* c1D = new TCanvas(Form("c1D_IntPools_PtCand%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax), Form("c1D_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax), 100, 100, 1600, 500); c1D->Divide(3, 1); c1D->cd(1); - h1D_Sign->Draw(); + h1DSign->Draw(); c1D->cd(2); - h1D_Sideb->Draw(); + h1DSideb->Draw(); c1D->cd(3); - h1D_Subtr->Draw(); - c1D->SaveAs(Form("Output_CorrelationExtraction_%s_png/h1D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); - c1D->SaveAs(Form("Output_CorrelationExtraction_%s_Root/h1D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); - + h1DSubtr->Draw(); + c1D->SaveAs(Form("Output_CorrelationExtraction_%s_png/h1D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c1D->SaveAs(Form("Output_CorrelationExtraction_%s_Root/h1D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + if (fDebug >= 1) { + h1DSignNorm = reinterpret_cast(h1DSign->Clone("h1D_Sign_Norm")); + h1DSidebNorm = reinterpret_cast(h1DSideb->Clone("h1D_Sideb_Norm")); + h1DSignNorm->Scale(1. / (fSgnYieldNorm + fBkgYield)); + // h1D_SidebNorm -> Scale(1./fBkgYield); + h1DSidebNorm->Scale(1. / fBkgScaleFactor); + h1DSidebNorm->Scale(1. / fSBYield); + h1DSignNorm->SetMarkerStyle(kFullCircle); + h1DSignNorm->SetMarkerSize(1.2); + h1DSignNorm->SetLineColor(kRed); + h1DSignNorm->SetMarkerColor(kRed); + h1DSignNorm->SetLineWidth(2); + h1DSidebNorm->SetMinimum(0); + h1DSidebNorm->SetMarkerStyle(kFullSquare); + h1DSidebNorm->SetMarkerSize(1.2); + h1DSidebNorm->SetLineColor(kBlue); + h1DSidebNorm->SetMarkerColor(kBlue); + h1DSidebNorm->SetLineWidth(2); + h1DSidebNorm->SetTitle(Form("%.0f < p_{T} < %.0f", ptCandMin, ptCandMax)); + auto* c = new TCanvas(Form("c_IntPools_PtCand%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax), ""); + c->cd(); + h1DSidebNorm->Draw(); + h1DSignNorm->Draw("same"); + c->SaveAs(Form("Output_CorrelationExtraction_%s_png/ComparisonSignalSidebCorr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c->SaveAs(Form("Output_CorrelationExtraction_%s_Root/ComparisonSignalSidebCorr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } // Apply normalization to number of triggers - h1D_SubtrNorm = reinterpret_cast(h1D_Subtr->Clone("h1D_SubtrNorm")); - h1D_SubtrNorm->Sumw2(); - h1D_SubtrNorm->Scale(1. / fSgnYieldNorm); - h1D_SubtrNorm->SetTitle("Signal region after sideb. subt. corr. - Normalized to # of triggers"); + h1DSubtrNorm = reinterpret_cast(h1DSubtr->Clone("h1D_SubtrNorm")); + h1DSubtrNorm->Sumw2(); + h1DSubtrNorm->Scale(1. / fSgnYieldNorm); + h1DSubtrNorm->SetTitle("Signal region after sideb. subt. corr. - Normalized to # of triggers"); + + // Correction for bias B to D topologies + if (fCorrBiasBtoD) { + hModul = evaluateMcClosModulations(ptCandMin, ptCandMax, ptHadMin, ptHadMax); + auto* c1DCorrBbias = new TCanvas(Form("c1D_corrBbias_IntPools_PtCand%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax), Form("c1D_corrBbias_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax), 100, 100, 1600, 500); + c1DCorrBbias->cd(); + hBeforeModulCorr = reinterpret_cast(h1DSubtrNorm->Clone("hBeforeModulCorr")); + hBeforeModulCorr->SetLineColor(kViolet - 3); + hBeforeModulCorr->GetYaxis()->SetRangeUser(0., 5.); + hBeforeModulCorr->Draw(); + h1DSubtrNorm->Multiply(hModul); + h1DSubtrNorm->Draw("same"); + c1DCorrBbias->SaveAs(Form("Output_CorrelationExtraction_%s_png/ComparisonCorrBiasBtoD_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c1DCorrBbias->SaveAs(Form("Output_CorrelationExtraction_%s_Root/ComparisonCorrBiasBtoD_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + auto* file = new TFile(Form("Output_CorrelationExtraction_%s_Root/SystematicCorrBiasBtoD_%s_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax), "RECREATE"); // Open file in write mode + TH1D* h1DSubtrNormClone = reinterpret_cast(h1DSubtrNorm->Clone("h1D_SubtrNorm_Clone")); + h1DSubtrNormClone = reflectCorrHistogram(h1DSubtrNormClone); + hBeforeModulCorr = reflectCorrHistogram(hBeforeModulCorr); + TH1D* hSystematicCorrBiasBtoD = reinterpret_cast(h1DSubtrNormClone->Clone("hSystematicCorrBiasBtoD")); + hSystematicCorrBiasBtoD->Add(h1DSubtrNormClone, hBeforeModulCorr, 1, -1); + // Set bin contents to absolute values + for (int i = 1; i <= hSystematicCorrBiasBtoD->GetNbinsX(); ++i) { + hSystematicCorrBiasBtoD->SetBinContent(i, std::abs(hSystematicCorrBiasBtoD->GetBinContent(i)) / TMath::Sqrt(12)); + hSystematicCorrBiasBtoD->SetBinError(i, 0.); + } + hSystematicCorrBiasBtoD->Write(); + file->Close(); + } + + // Secondary particle contamination + if (fSecPartContamination) { + h1DPrimaryPartCorr = getCorrelHistoSecondaryPart(kPrimaryPart, ptCandMin, ptCandMax, ptHadMin, ptHadMax); + h1DAllPartCorr = getCorrelHistoSecondaryPart(kAllPart, ptCandMin, ptCandMax, ptHadMin, ptHadMax); + h1DPrimaryPartCorr->Sumw2(); + h1DAllPartCorr->Sumw2(); + if (fRebinSecPart) { + h1DPrimaryPartCorr->RebinX(fRebinAxisDeltaPhi); // Xaxis: deltaPhi + h1DAllPartCorr->RebinX(fRebinAxisDeltaPhi); + std::cout << "Secondary particle histogram rebinned" << std::endl; + } + h1DSecPartFrac = reinterpret_cast(h1DPrimaryPartCorr->Clone(Form("hCorrRatio_PtD%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax))); + h1DSecPartFrac->Sumw2(); + h1DSecPartFrac->Divide(h1DPrimaryPartCorr, h1DAllPartCorr, 1., 1., "B"); + + auto* c1D = new TCanvas(Form("c1D_CorrPrimaryPart_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax), Form("c1D_%s_CorrPrimaryPart_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax)); + c1D->cd(); + setTH1HistoStyle(h1DSecPartFrac, Form("%.0f < p_{T} < %.0f GeV/c", ptCandMin, ptCandMax), "#Delta#phi [rad]", "#frac{primary part.}{part. selected}"); + h1DSecPartFrac->Draw(); + c1D->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrPrimaryPartRatio_%s_Canvas_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c1D->SaveAs(Form("Output_CorrelationExtraction_%s_Root/CorrPrimaryPartRatio_%s_Canvas_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + h1DSubtrNormSecPart = reinterpret_cast(h1DSubtrNorm->Clone("h1D_SubtrNorm_SecPart")); + h1DSubtrNormSecPart->Sumw2(); + Int_t const nBinsPhi = h1DSubtrNormSecPart->GetNbinsX(); + if (nBinsPhi != h1DSecPartFrac->GetNbinsX()) { + std::cout << "[ERROR]: nBinsPhi different between h1D_SubtrNorm and h1D_SecPartFrac" << std::endl; + return kFALSE; + } + h1DSubtrNormSecPart->Multiply(h1DSecPartFrac); + } + + // FD Subtraction + if (fFDsubtraction) { + h1DFdTemplatePrompt = h2DFdTemplatePrompt->ProjectionY("h1D_FDTemplatePrompt"); + h1DFdTemplateNonPrompt = h2DFdTemplateNonPrompt->ProjectionY("h1D_FDTemplateNonPrompt"); + + h1DFdTemplatePrompt->Scale(1. / h1DFdTemplatePrompt->GetXaxis()->GetBinWidth(1)); + h1DFdTemplateNonPrompt->Scale(1. / h1DFdTemplateNonPrompt->GetXaxis()->GetBinWidth(1)); + + h1DTemplateTotal = reinterpret_cast(h1DFdTemplatePrompt->Clone("h1D_TemplateTotal")); + h1DTemplateTotal->Sumw2(); + h1DTemplateTotal->Scale(fdPromptFrac); + h1DTemplateTotal->Add(h1DFdTemplateNonPrompt, 1 - fdPromptFrac); - fCorrectedCorrHisto = reinterpret_cast(h1D_SubtrNorm->Clone(Form("hCorrectedCorr_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", PtCandMin, PtCandMax, PtHadMin, PtHadMax))); + if (fDebug >= 1) { + auto* c = new TCanvas(Form("cFDTemplate_1D_%1.1fto%1.1f", ptHadMin, ptHadMax), Form("cFDTemplate_%s_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c->cd(); + h1DTemplateTotal->SetMinimum(0); + h1DFdTemplateNonPrompt->SetMinimum(0); + h1DTemplateTotal->SetMarkerColor(kGreen); + h1DTemplateTotal->SetLineColor(kGreen); + h1DTemplateTotal->SetLineWidth(2); + h1DTemplateTotal->SetMarkerStyle(kFullCircle); + h1DFdTemplatePrompt->SetMarkerColor(kRed); + h1DFdTemplatePrompt->SetLineColor(kRed); + h1DFdTemplatePrompt->SetLineWidth(2); + h1DFdTemplatePrompt->SetMarkerStyle(kFullCircle); + h1DFdTemplateNonPrompt->SetMarkerColor(kBlue); + h1DFdTemplateNonPrompt->SetLineColor(kBlue); + h1DFdTemplateNonPrompt->SetLineWidth(2); + h1DFdTemplateNonPrompt->SetMarkerStyle(kFullCircle); + h1DFdTemplateNonPrompt->Draw(); + h1DFdTemplatePrompt->Draw("same"); + h1DTemplateTotal->Draw("same"); + auto* lFD = new TLegend(); + lFD->AddEntry(h1DTemplateTotal, "Total template"); + lFD->AddEntry(h1DFdTemplatePrompt, "Prompt Template"); + lFD->AddEntry(h1DFdTemplateNonPrompt, "Non prompt template"); + lFD->Draw("same"); + c->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrFDTemplate_1D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c->SaveAs(Form("Output_CorrelationExtraction_%s_Root/CorrFDTemplate_1D_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } + + Double_t const baselineFd = calculateBaseline(h1DTemplateTotal, kTRUE); + Double_t baselineData; + if (fSecPartContamination) { + baselineData = calculateBaseline(h1DSubtrNormSecPart, kTRUE); + } else { + baselineData = calculateBaseline(h1DSubtrNorm, kTRUE); + } + + std::cout << "===================== " << std::endl; + std::cout << "Baseline FD: " << baselineFd << std::endl; + std::cout << "Baseline Data: " << baselineData << std::endl; + std::cout << "===================== " << std::endl; + std::cout << " " << std::endl; + + Double_t const baselinediff = baselineData - baselineFd; + TH1D* hBaselineDiff = reinterpret_cast(h1DFdTemplateNonPrompt->Clone("hBaselineDiff")); + for (int iBin = 0; iBin < hBaselineDiff->GetNbinsX(); iBin++) { + hBaselineDiff->SetBinContent(iBin + 1, baselinediff); + } + h1DFdTemplateNonPrompt->Add(hBaselineDiff); + h1DTemplateTotal->Add(hBaselineDiff); + if (fSecPartContamination) { + h1DSubtrFdNorm = reinterpret_cast(h1DSubtrNormSecPart->Clone("h1D_SubtrFDNorm")); + } else { + h1DSubtrFdNorm = reinterpret_cast(h1DSubtrNorm->Clone("h1D_SubtrFDNorm")); + } + h1DFdTemplateNonPrompt->Scale(1 - fdPromptFrac); + h1DSubtrFdNorm->Add(h1DFdTemplateNonPrompt, -1); + h1DSubtrFdNorm->Scale(1. / fdPromptFrac); + + if (fDebug >= 1) { + auto* c1 = new TCanvas(Form("cFDTemplateSubtr_%1.1fto%1.1f", ptHadMin, ptHadMax), Form("cFDTemplateSubtr_%s_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax), 100, 100, 1600, 900); + c1->cd(); + h1DSubtrNorm->SetLineColor(kRed); + h1DSubtrNormSecPart->SetLineColor(kOrange); + h1DFdTemplateNonPrompt->SetLineColor(kBlue); + h1DSubtrFdNorm->SetLineColor(kGreen); + h1DTemplateTotal->SetLineColor(kMagenta); + h1DSubtrNorm->SetMinimum(0); + h1DSubtrNormSecPart->SetMinimum(0); + h1DFdTemplateNonPrompt->SetMinimum(0); + h1DSubtrFdNorm->SetMinimum(0); + // h1D_SubtrNorm -> GetYaxis() -> SetRangeUser(0., 8.); + h1DSubtrNorm->SetMarkerStyle(kFullCircle); + h1DSubtrNorm->SetMarkerSize(1.2); + h1DSubtrNorm->SetMarkerColor(kRed); + h1DSubtrNorm->SetLineWidth(2); + h1DSubtrNormSecPart->SetMarkerStyle(kFullCircle); + h1DSubtrNormSecPart->SetMarkerSize(1.2); + h1DSubtrNormSecPart->SetMarkerColor(kOrange); + h1DSubtrNormSecPart->SetLineWidth(2); + h1DSubtrFdNorm->SetMarkerStyle(kFullCircle); + h1DSubtrFdNorm->SetMarkerSize(1.2); + h1DSubtrFdNorm->SetMarkerColor(kGreen); + h1DSubtrFdNorm->SetLineWidth(2); + h1DSubtrNorm->GetYaxis()->SetTitle("#frac{1}{N_{D}} #frac{dN^{assoc. part}}{d#Delta#phi}"); + h1DSubtrNormSecPart->GetYaxis()->SetTitle("#frac{1}{N_{D}} #frac{dN^{assoc. part}}{d#Delta#phi}"); + if (fSecPartContamination) { + h1DSubtrNormSecPart->Draw(); + } else { + h1DSubtrNorm->Draw(); + } + // h1D_FDTemplateNonPrompt -> Draw("same"); + h1DSubtrFdNorm->Draw("same"); + h1DTemplateTotal->Draw("same"); + c1->SaveAs(Form("Output_CorrelationExtraction_%s_png/CorrFDTemplateSubtr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + c1->SaveAs(Form("Output_CorrelationExtraction_%s_Root/CorrFDTemplateSubtr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } + } + + if (fFDsubtraction) { + fCorrectedCorrHisto = reinterpret_cast(h1DSubtrFdNorm->Clone(Form("hCorrectedCorr_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax))); + } else if (fSecPartContamination) { + fCorrectedCorrHisto = reinterpret_cast(h1DSubtrNormSecPart->Clone(Form("hCorrectedCorr_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax))); + } else { + fCorrectedCorrHisto = reinterpret_cast(h1DSubtrNorm->Clone(Form("hCorrectedCorr_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax))); + } + + std::cout << "Analysis steps completed - baseline subtraction missing" << std::endl; // Draw 1D plots (Signal region, normalized) - TCanvas* cFinal = new TCanvas(Form("cFinal_%.0fto%.0f", PtHadMin, PtHadMax), Form("cFinal_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), PtHadMin, PtHadMax), 100, 100, 1200, 700); - h1D_SubtrNorm->Draw(); - cFinal->SaveAs(Form("Output_CorrelationExtraction_%s_png/AzimCorrDistr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); - cFinal->SaveAs(Form("Output_CorrelationExtraction_%s_Root/AzimCorrDistr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), PtCandMin, PtCandMax, PtHadMin, PtHadMax)); + auto* cFinal = new TCanvas(Form("cFinal_%.0fto%.0f", ptHadMin, ptHadMax), Form("cFinal_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax), 100, 100, 1200, 700); + h1DSubtrNorm->SetLineColor(kBlue + 1); + h1DSubtrNorm->SetMarkerColor(kBlue + 1); + h1DSubtrNorm->SetMarkerStyle(kFullCircle); + h1DSubtrNorm->SetMinimum(0); + h1DSubtrNorm->Draw(); + if (fSecPartContamination) { + h1DSubtrNormSecPart->SetLineColor(kRed + 1); + h1DSubtrNormSecPart->SetMarkerColor(kRed + 1); + h1DSubtrNormSecPart->SetMarkerStyle(kFullCircle); + h1DSubtrNormSecPart->Draw("same"); + } + if (fFDsubtraction) { + h1DSubtrFdNorm->SetLineColor(kGreen + 2); + h1DSubtrFdNorm->SetMarkerColor(kGreen + 2); + h1DSubtrFdNorm->SetMarkerStyle(kFullCircle); + h1DSubtrFdNorm->Draw("same"); + } + if (fFDsubtraction) { + h1DTemplateTotal->Draw("same"); + } + auto* lFinal = new TLegend(); + lFinal->AddEntry(h1DSubtrNorm, "Corr. after bkg subtr."); + if (fFDsubtraction) { + lFinal->AddEntry(h1DTemplateTotal, "CR Mode 2 total template"); + } + if (fSecPartContamination) { + lFinal->AddEntry(h1DSubtrNormSecPart, "Corr. after sec. part. correction"); + } + if (fFDsubtraction) { + lFinal->AddEntry(h1DSubtrFdNorm, "Corr. FD subtr."); + } + lFinal->Draw("same"); + cFinal->SaveAs(Form("Output_CorrelationExtraction_%s_png/AzimCorrDistr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + cFinal->SaveAs(Form("Output_CorrelationExtraction_%s_Root/AzimCorrDistr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + // Baseline subtraction + Double_t baselineData, baselineDataErr; + TH1D* hBaseline = reinterpret_cast(h1DSubtrNorm->Clone("hBaseline")); + hBaseline->Sumw2(); + if (fFDsubtraction) { + baselineData = calculateBaseline(h1DSubtrFdNorm, kTRUE, kFALSE); // introduced kFALSE + baselineDataErr = calculateBaselineError(h1DSubtrFdNorm, kTRUE, kFALSE); + for (int iBin = 0; iBin < hBaseline->GetNbinsX(); iBin++) { + hBaseline->SetBinContent(iBin + 1, baselineData); + hBaseline->SetBinError(iBin + 1, baselineDataErr); + } + h1DBaselineSubtr = reinterpret_cast(h1DSubtrFdNorm->Clone("h1D_BaselineSubtr")); + h1DBaselineSubtr->Add(hBaseline, -1.); + } else if (fSecPartContamination) { + baselineData = calculateBaseline(h1DSubtrNormSecPart, kTRUE, kFALSE); + baselineDataErr = calculateBaselineError(h1DSubtrNormSecPart, kTRUE, kFALSE); + for (int iBin = 0; iBin < hBaseline->GetNbinsX(); iBin++) { + hBaseline->SetBinContent(iBin + 1, baselineData); + hBaseline->SetBinError(iBin + 1, baselineDataErr); + } + h1DBaselineSubtr = reinterpret_cast(h1DSubtrNormSecPart->Clone("h1D_BaselineSubtr")); + h1DBaselineSubtr->Add(hBaseline, -1.); + } else { + baselineData = calculateBaseline(h1DSubtrNorm, kTRUE, kFALSE); + baselineDataErr = calculateBaselineError(h1DSubtrNorm, kTRUE, kFALSE); + for (int iBin = 0; iBin < hBaseline->GetNbinsX(); iBin++) { + hBaseline->SetBinContent(iBin + 1, baselineData); + hBaseline->SetBinError(iBin + 1, baselineDataErr); + } + h1DBaselineSubtr = reinterpret_cast(h1DSubtrNorm->Clone("h1D_BaselineSubtr")); + h1DBaselineSubtr->Add(hBaseline, -1.); + } + + fCorrectedCorrHistoBaselineSubtr = reinterpret_cast(h1DBaselineSubtr->Clone(Form("hCorrectedCorrBaselineSubtr_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax))); + + auto* cFinalBaselineSubtr = new TCanvas(Form("cFinal_BaselineSubtr_%.0fto%.0f", ptHadMin, ptHadMax), Form("cFinal_BaselineSubtr_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax), 100, 100, 1200, 700); + h1DBaselineSubtr->SetMarkerColor(kOrange + 8); + h1DBaselineSubtr->SetLineColor(kOrange + 8); + h1DBaselineSubtr->GetYaxis()->SetRangeUser(-0.2, 8.); + h1DBaselineSubtr->Draw(); + if (fFDsubtraction) { + h1DSubtrFdNorm->Draw("same"); + } else if (fSecPartContamination) { + h1DSubtrNormSecPart->Draw("same"); + } else { + h1DSubtrNorm->Draw("same"); + } + hBaseline->SetMarkerColor(kPink - 6); + hBaseline->SetMarkerStyle(kFullSquare); + hBaseline->SetLineColor(kPink - 6); + hBaseline->Draw("same"); + + cFinalBaselineSubtr->SaveAs(Form("Output_CorrelationExtraction_%s_png/AzimCorrDistr_BaselineSubtr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + cFinalBaselineSubtr->SaveAs(Form("Output_CorrelationExtraction_%s_Root/AzimCorrDistr_BaselineSubtr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + // Reflected histograms + if (fFDsubtraction) { + h1DReflCorr = reflectCorrHistogram(h1DSubtrFdNorm); + } else if (fSecPartContamination) { + h1DReflCorr = reflectCorrHistogram(h1DSubtrNormSecPart); + } else { + h1DReflCorr = reflectCorrHistogram(h1DSubtrNorm); + } + + /* used as control using Run2 reflection function + if (fFDsubtraction) { + h1D_ReflCorr = ReflectHistoRun2(h1D_SubtrFDNorm, 0.5); + } else if (fSecPartContamination) { + h1D_ReflCorr = ReflectHistoRun2(h1D_SubtrNorm_SecPart, 0.5); + } else { + h1D_ReflCorr = ReflectHistoRun2(h1D_SubtrNorm, 0.5); + }*/ + + auto* cFinalReflected = new TCanvas(Form("cFinal_Reflected_%.0fto%.0f", ptHadMin, ptHadMax), Form("cFinal_Reflected_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax), 100, 100, 1200, 700); + cFinalReflected->cd(); + setTH1HistoStyle(h1DReflCorr, Form("%.0f < p_{T} < %.0f GeV/c", ptCandMin, ptCandMax), "#Delta#phi [rad]", "#frac{1}{N_{D}}#frac{dN^{assoc}}{d#Delta#phi} [rad^{-1}]", kFullCircle, kOrange + 8, 1.6, kOrange + 8, 3); + h1DReflCorr->SetMinimum(0); + h1DReflCorr->Draw(); + cFinalReflected->SaveAs(Form("Output_CorrelationExtraction_%s_png/AzimCorrDistr_Reflected_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + cFinalReflected->SaveAs(Form("Output_CorrelationExtraction_%s_Root/AzimCorrDistr_Reflected_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + // Reflected histograms baseline subtracted + TH1D* hBaselineRefl = reinterpret_cast(h1DReflCorr->Clone("hBaseline_Refl")); + hBaselineRefl->Sumw2(); + baselineData = calculateBaseline(h1DReflCorr, kFALSE, kTRUE); + baselineDataErr = calculateBaselineError(h1DReflCorr, kFALSE, kTRUE); + + for (int iBin = 0; iBin < hBaselineRefl->GetNbinsX(); iBin++) { + hBaselineRefl->SetBinContent(iBin + 1, baselineData); + hBaselineRefl->SetBinError(iBin + 1, baselineDataErr); + } + h1DReflCorrBaselineSubtr = reinterpret_cast(h1DReflCorr->Clone("h1D_ReflCorr_BaselineSubtr")); + h1DReflCorrBaselineSubtr->Sumw2(); + h1DReflCorrBaselineSubtr->Add(hBaselineRefl, -1.); + + TF1* fConstZero = new TF1("fConstZero", "[0]", 0., TMath::Pi()); + fConstZero->SetParameter(0, 0.); + fConstZero->SetLineColor(kMagenta); + fConstZero->SetLineStyle(9); + fConstZero->SetLineWidth(4); + fConstZero->SetTitle(""); + + auto* cFinalReflectedBaselineSubtr = new TCanvas(Form("cFinal_Reflected_BaselineSubtr_%.0fto%.0f", ptHadMin, ptHadMax), Form("cFinal_Reflected_BaselineSubtr_%s_IntPools_PtAssoc%.0fto%.0f", fDmesonLabel.Data(), ptHadMin, ptHadMax), 100, 100, 1200, 700); + setTH1HistoStyle(h1DReflCorrBaselineSubtr, Form("%.0f < p_{T} < %.0f GeV/c", ptCandMin, ptCandMax), "#Delta#phi [rad]", "#frac{1}{N_{D}}#frac{dN^{assoc}}{d#Delta#phi} [rad^{-1}]", kFullCircle, kRed + 1, 1.6, kRed + 1, 3); + hBaselineRefl->SetMarkerColor(kOrange); + hBaselineRefl->SetMarkerStyle(kFullSquare); + hBaselineRefl->SetLineColor(kOrange); + cFinalReflectedBaselineSubtr->cd(); + h1DReflCorr->SetMinimum(-0.8); + h1DReflCorr->SetStats(false); + hBaselineRefl->SetStats(false); + h1DReflCorr->Draw(); + hBaselineRefl->Draw("same"); + h1DReflCorrBaselineSubtr->SetStats(false); + h1DReflCorrBaselineSubtr->Draw("same"); // then keep just this + fConstZero->Draw("same"); + cFinalReflectedBaselineSubtr->SaveAs(Form("Output_CorrelationExtraction_%s_png/AzimCorrDistr_Reflected_BaselineSubtr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + cFinalReflectedBaselineSubtr->SaveAs(Form("Output_CorrelationExtraction_%s_Root/AzimCorrDistr_Reflected_BaselineSubtr_%s_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.root", codeName.Data(), fDmesonLabel.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + fCorrectedCorrHistoReflected = reinterpret_cast(h1DReflCorr->Clone(Form("hCorrectedCorrReflected_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax))); + fCorrectedCorrHistoReflectedBaselineSubtr = reinterpret_cast(h1DReflCorrBaselineSubtr->Clone(Form("hCorrectedCorrReflected_BaselineSubtr_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax))); return kTRUE; } -Bool_t DhCorrelationExtraction::ReadInputSEandME() +Bool_t DhCorrelationExtraction::readInputSeAndMe() { fFileSE = TFile::Open(fFileNameSE.Data()); - if (!fFileSE) { + if (fFileSE == nullptr) { std::cout << "[ERROR] File " << fFileNameSE << " cannot be opened! check your file path!"; return kFALSE; } fFileME = TFile::Open(fFileNameME.Data()); - if (!fFileME) { + if (fFileME == nullptr) { std::cout << "[ERROR] File " << fFileNameME << " cannot be opened! check your file path!"; return kFALSE; } @@ -360,11 +868,11 @@ Bool_t DhCorrelationExtraction::ReadInputSEandME() return kTRUE; } -Bool_t DhCorrelationExtraction::ReadInputInvMass() +Bool_t DhCorrelationExtraction::readInputInvMass() { fFileMass = TFile::Open(fFileNameMass.Data()); - if (!fFileMass) { + if (fFileMass == nullptr) { std::cout << "[ERROR] File " << fFileNameMass << " cannot be opened! check your file path!"; return kFALSE; } @@ -381,107 +889,468 @@ Bool_t DhCorrelationExtraction::ReadInputInvMass() return kTRUE; } -TH2D* DhCorrelationExtraction::GetCorrelHisto(Int_t SEorME, Int_t SorSB, Int_t pool, Double_t PtCandMin, Double_t PtCandMax, Double_t PtHadMin, Double_t PtHadMax) +Bool_t DhCorrelationExtraction::readInputFdSubtr() { - // TODO: Subtraction of softpion - TH2D* h2D = new TH2D(); // pointer to be returned - THnSparseD* hSparse = 0x0; + fFileFDTemplate = TFile::Open(fFileFDTemplateName.Data()); + fFileFDPromptFrac = TFile::Open(fFileFDPromptFracName.Data()); + if (fFileFDTemplate == nullptr) { + std::cout << "[ERROR] File " << fFileFDTemplateName << " cannot be opened! check your file path!" << std::endl; + return kFALSE; + } + if (fFileFDPromptFrac == nullptr) { + std::cout << "[ERROR] File " << fFileFDPromptFracName << " cannot be opened! check your file path!" << std::endl; + return kFALSE; + } + + std::cout << "===================== " << std::endl; + std::cout << "Read inputs FD template" << std::endl; + std::cout << "TFile FD template = " << fFileFDTemplateName << std::endl; + std::cout << "TFile FD Prompt Frac = " << fFileFDPromptFracName << std::endl; + std::cout << "Histo FD template Prompt = " << fHistoFDTemplatePromptName << std::endl; + std::cout << "Histo FD template Non Prompt = " << fHistoFDTemplateNonPromptName << std::endl; + std::cout << "Histo FD Prompt Frac = " << fHistoFDPromptFracName << std::endl; + std::cout << "===================== " << std::endl; + std::cout << " " << std::endl; - if (SEorME == kSE) { // Same Event - if (SorSB == kSign) { - hSparse = reinterpret_cast(fDirSE->Get(fSECorrelSignalRegionName.Data())); + return kTRUE; +} + +Bool_t DhCorrelationExtraction::readInputSecondaryPartContamination() +{ + + fFileSecPart = TFile::Open(fFileSecPartName.Data()); + if (fFileSecPart == nullptr) { + std::cout << "[ERROR] File " << fFileSecPartName << " cannot be opened! check your file path!" << std::endl; + return kFALSE; + } + + fDirSecPart = reinterpret_cast(fFileSecPart->Get(fDirSecPartName.Data())); + + if (fDirSecPart == nullptr) { + std::cout << "[ERROR] Directory " << fDirSecPart << " cannot be opened! check your file path!" << std::endl; + return kFALSE; + } + + std::cout << "===================== " << std::endl; + std::cout << "Read inputs SE and ME" << std::endl; + std::cout << "TFile Sec. part. = " << fFileSecPartName << std::endl; + std::cout << "TDir Sec. part. = " << fDirSecPartName << std::endl; + std::cout << "===================== " << std::endl; + std::cout << " " << std::endl; + + return kTRUE; +} + +TH1D* DhCorrelationExtraction::evaluateMcClosModulations(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax) +{ + + TH1D* hModul = nullptr; + + fFilePromptMc = TFile::Open(fFilePromptMcRecName.Data()); + if (fFilePromptMc == nullptr) { + throw std::runtime_error("[ERROR] File prompt MC rec cannot be opened! check your file path!"); + } + fFileNonPromptMc = TFile::Open(fFileNonPromptMcRecName.Data()); + if (fFileNonPromptMc == nullptr) { + throw std::runtime_error("[ERROR] File non-prompt MC rec cannot be opened! check your file path!"); + } + + // TODO: generalise this part + TH1D* hRecPrompt = reinterpret_cast(fFilePromptMc->Get(Form("h1D_Rec_iPtD%d_iPtAssoc%d", fBinPtCand, fBinPtHad))); + TH1D* hRecNonPrompt = reinterpret_cast(fFileNonPromptMc->Get(Form("h1D_Rec_iPtD%d_iPtAssoc%d", fBinPtCand, fBinPtHad))); + TH1D* hGenPrompt = reinterpret_cast(fFilePromptMc->Get(Form("h1D_Gen_iPtD%d_iPtAssoc%d", fBinPtCand, fBinPtHad))); + TH1D* hGenNonPrompt = reinterpret_cast(fFileNonPromptMc->Get(Form("h1D_Gen_iPtD%d_iPtAssoc%d", fBinPtCand, fBinPtHad))); + + printf("[INFO] Bin cand %d - Bin had %d \n", fBinPtCand, fBinPtHad); + + // hRecPrompt = reflectCorrHistogram(hRecPrompt); + // hRecNonPrompt = reflectCorrHistogram(hRecNonPrompt); + // hGenPrompt = reflectCorrHistogram(hGenPrompt); + // hGenNonPrompt = reflectCorrHistogram(hGenNonPrompt); + + hRecNonPrompt->Sumw2(); + hRecNonPrompt->Sumw2(); + hGenPrompt->Sumw2(); + hGenNonPrompt->Sumw2(); + + TH1D* hRatioNonPrompt = reinterpret_cast(hRecNonPrompt->Clone("hRatioNonPrompt")); + hRatioNonPrompt->Sumw2(); + hRatioNonPrompt->Divide(hRecNonPrompt, hGenNonPrompt, 1., 1., "B"); + hModul = reinterpret_cast(hRatioNonPrompt->Clone("hModul")); + + TF1* funFit = new TF1("funFit", "[0]", TMath::Pi() * 3. / 8., TMath::Pi() * 3 / 2); + hRatioNonPrompt->Fit(funFit, "R"); + Double_t const fitVal = funFit->GetParameter(0); + + auto* cRatioMcClosure = new TCanvas(Form("cRatio_MCClosure_PtCand%.0fto%.0f_Pthad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax), Form("cRatio_MCClosure_PtCand%.0fto%.0f_Pthad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax), 100, 100, 1200, 700); + cRatioMcClosure->cd(); + hRatioNonPrompt->GetYaxis()->SetRangeUser(0.2, 1.8); + hRatioNonPrompt->Draw(); + + Double_t const fPrompt = getFdPromptFrac(ptCandMin, ptCandMax, ptHadMin, ptHadMax); + Double_t relAmplC[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + Double_t relAmplB[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + Double_t recoKineVal[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + Double_t modul[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + for (int iBin = 0; iBin < hRatioNonPrompt->GetNbinsX(); iBin++) { + if (iBin > 1 && iBin < 13) { + recoKineVal[iBin - 2] = hRatioNonPrompt->GetBinContent(iBin + 1) - (fitVal - 1); + relAmplC[iBin - 2] = hRecPrompt->GetBinContent(iBin + 1) / (hRecPrompt->GetBinContent(iBin + 1) * fPrompt + hRecNonPrompt->GetBinContent(iBin + 1) * (1 - fPrompt)); + relAmplB[iBin - 2] = hRecNonPrompt->GetBinContent(iBin + 1) / (hRecPrompt->GetBinContent(iBin + 1) * fPrompt + hRecNonPrompt->GetBinContent(iBin + 1) * (1 - fPrompt)); + modul[iBin - 2] = relAmplC[iBin - 2] * fPrompt + relAmplB[iBin - 2] * (1 - fPrompt) / recoKineVal[iBin - 2]; + hModul->SetBinContent(iBin + 1, modul[iBin - 2]); + hModul->SetBinError(iBin + 1, 0.); + + printf("[INFO] Bin%d MODUL = %1.5f\t (Reco/Kine-fitVal = %1.4f, FPrompt = %1.3f, Ampl_ratio C,B = %1.4f, %1.4f)\n", iBin + 1, modul[iBin - 2], recoKineVal[iBin - 2], fPrompt, relAmplC[iBin - 2], relAmplB[iBin - 2]); } else { + hModul->SetBinContent(iBin + 1, 1.); + hModul->SetBinError(iBin + 1, 0.); + } + } + + hModul->SetLineColor(kMagenta); + hModul->Draw("same"); + + cRatioMcClosure->SaveAs(Form("Output_CorrelationExtraction_Thin2023_FullAnalysis_CentralPoints_png/Ratio_MCClosure_Canvas_PtCand%.0fto%.0f_PoolInt_PtAssoc%.0fto%.0f.png", ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + + return hModul; +} + +TH2D* DhCorrelationExtraction::getCorrelHisto(Int_t sEorMe, Int_t sorSb, Int_t pool, Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax) +{ + // TODO: Subtraction of softpion + TH2D* h2D = nullptr; // pointer to be returned + + THnSparseD* hSparse = nullptr; + if (sEorMe == kSE) { // Same Event + if (sorSb == kSign) { + hSparse = reinterpret_cast(fDirSE->Get(fSECorrelSignalRegionName.Data())); + } else if (!fSidebandDivided) { hSparse = reinterpret_cast(fDirSE->Get(fSECorrelSidebandsName.Data())); + } else { + if (fUseSidebLeft && !fUseSidebRight) { + hSparse = reinterpret_cast(fDirSE->Get(fSECorrelSidebandLeftName.Data())); + } else if (!fUseSidebLeft && fUseSidebRight) { + hSparse = reinterpret_cast(fDirSE->Get(fSECorrelSidebandRightName.Data())); + } else if (fUseSidebLeft && fUseSidebRight) { + hSparse = reinterpret_cast(fDirSE->Get(fSECorrelSidebandLeftName.Data())); + hSparse->SetName("hSparse"); + auto* hSparseRightSideb = reinterpret_cast(fDirSE->Get(fSECorrelSidebandRightName.Data())); + hSparse->Add(hSparseRightSideb, 1.); + } } } else { // Mixed Event - if (SorSB == kSign) { + if (sorSb == kSign) { hSparse = reinterpret_cast(fDirME->Get(fMECorrelSignalRegionName.Data())); - } else { + } else if (!fSidebandDivided) { hSparse = reinterpret_cast(fDirME->Get(fMECorrelSidebandsName.Data())); + } else { + if (fUseSidebLeft && !fUseSidebRight) { + hSparse = reinterpret_cast(fDirME->Get(fMECorrelSidebandLeftName.Data())); + } else if (!fUseSidebLeft && fUseSidebRight) { + hSparse = reinterpret_cast(fDirME->Get(fMECorrelSidebandRightName.Data())); + } else if (fUseSidebLeft && fUseSidebRight) { + hSparse = reinterpret_cast(fDirME->Get(fMECorrelSidebandLeftName.Data())); + hSparse->SetName("hSparse"); + auto* hSparseRightSideb = reinterpret_cast(fDirME->Get(fMECorrelSidebandRightName.Data())); + hSparse->Add(hSparseRightSideb, 1.); + } } } - Int_t binExtPtCandMin = (Int_t)hSparse->GetAxis(2)->FindBin(PtCandMin + 0.01); // axis2: ptCand, the 0.01 to avoid bin edges! - Int_t binExtPtCandMax = (Int_t)hSparse->GetAxis(2)->FindBin(PtCandMax - 0.01); - Int_t binExtPtHadMin = (Int_t)hSparse->GetAxis(3)->FindBin(PtHadMin + 0.01); // axis3: ptHad - Int_t binExtPtHadMax = (Int_t)hSparse->GetAxis(3)->FindBin(PtHadMax - 0.01); + /*else if (fSidebandDivided) { // Mixed Event + if (SorSB == kSign) { hSparse = reinterpret_cast fDirME -> Get(fMECorrelSignalRegionName.Data()); + } else if (!fSidebandDivided) { hSparse = reinterpret_cast fDirME -> Get(fMECorrelSidebandsName.Data()); + } else { + if (fUseSidebLeft && !fUseSidebRight) { + hSparse = reinterpret_cast fDirME -> Get(fMECorrelSidebandLeftName.Data()); + } else if (!fUseSidebLeft && fUseSidebRight) { + hSparse = reinterpret_cast fDirME -> Get(fMECorrelSidebandRightName.Data()); + } else if (fUseSidebLeft && fUseSidebRight) { + hSparse = reinterpret_cast fDirME -> Get(fMECorrelSidebandLeftName.Data()); + hSparse -> SetName("hSparse"); + THnSparseD *hSparseRightSideb = reinterpret_cast fDirME -> Get(fMECorrelSidebandRightName.Data()); + hSparse -> Add(hSparseRightSideb, 1.); + } + } + }*/ + + Int_t const binExtPtCandMin = hSparse->GetAxis(2)->FindBin(ptCandMin + 0.01); // axis2: ptCand, the 0.01 to avoid bin edges! + Int_t const binExtPtCandMax = hSparse->GetAxis(2)->FindBin(ptCandMax - 0.01); + Int_t const binExtPtHadMin = hSparse->GetAxis(3)->FindBin(ptHadMin + 0.01); // axis3: ptHad + Int_t const binExtPtHadMax = hSparse->GetAxis(3)->FindBin(ptHadMax - 0.01); Int_t binExtPoolMin; Int_t binExtPoolMax; if (fCorrectPoolsSeparately) { - binExtPoolMin = (Int_t)hSparse->GetAxis(4)->FindBin(pool + 1.01); // axis4: pool bin - binExtPoolMax = (Int_t)hSparse->GetAxis(4)->FindBin(pool + 1.99); + binExtPoolMin = hSparse->GetAxis(4)->FindBin(pool + 0.01); // axis4: pool bin + binExtPoolMax = hSparse->GetAxis(4)->FindBin(pool + 0.99); } else { // merge all pools in one binExtPoolMin = 1; - binExtPoolMax = (Int_t)hSparse->GetAxis(4)->GetNbins(); - // cout << "binExtPoolMax:" << binExtPoolMax <GetAxis(4)->GetNbins(); } // possibility to select a certain eta region - Int_t binExtEtaMin = (Int_t)hSparse->GetAxis(1)->FindBin(fDeltaEtaMin + 0.0001); - Int_t binExtEtaMax = (Int_t)hSparse->GetAxis(1)->FindBin(fDeltaEtaMax - 0.0001); - if (binExtEtaMax > hSparse->GetAxis(1)->GetNbins()) + Int_t binExtEtaMin = hSparse->GetAxis(1)->FindBin(fDeltaEtaMin + 0.0001); + Int_t binExtEtaMax = hSparse->GetAxis(1)->FindBin(fDeltaEtaMax - 0.0001); + if (binExtEtaMax > hSparse->GetAxis(1)->GetNbins()) { binExtEtaMax = hSparse->GetAxis(1)->GetNbins(); - if (binExtEtaMin < 1) + } + if (binExtEtaMin < 1) { binExtEtaMin = 1; - + } hSparse->GetAxis(1)->SetRange(binExtEtaMin, binExtEtaMax); // axis1: deltaEta hSparse->GetAxis(2)->SetRange(binExtPtCandMin, binExtPtCandMax); // axis2: ptCand hSparse->GetAxis(3)->SetRange(binExtPtHadMin, binExtPtHadMax); // axis3: ptHad - // hSparse -> GetAxis(4) -> SetRange(binExtPoolMin, binExtPoolMax); // axis4: pool bin - - h2D = reinterpret_cast(hSparse->Projection(0, 1)); // axis0: deltaPhi, axis1: deltaEta - if (SEorME == kSE) { // Same Event - if (SorSB == kSign) { + hSparse->GetAxis(4)->SetRange(binExtPoolMin, binExtPoolMax); // axis4: pool bin + h2D = hSparse->Projection(0, 1); // axis0: deltaPhi, axis1: deltaEta + if (sEorMe == kSE) { // Same Event + if (sorSb == kSign) { h2D->SetName(Form("hCorr_SE_Sig_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); - } else { + } else if (!fSidebandDivided) { h2D->SetName(Form("hCorr_SE_Sideb_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + } else { + if (fUseSidebLeft && !fUseSidebRight) { + h2D->SetName(Form("hCorr_SE_Sideb_Left_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + } else if (!fUseSidebLeft && fUseSidebRight) { + h2D->SetName(Form("hCorr_SE_Sideb_Right_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + } else if (fUseSidebLeft && fUseSidebRight) { + h2D->SetName(Form("hCorr_SE_Sideb_LeftAndRight_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + } } } else { // Mixed Event - if (SorSB == kSign) { + if (sorSb == kSign) { h2D->SetName(Form("hCorr_ME_Sig_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + } else if (!fSidebandDivided) { + h2D->SetName(Form("hCorr_SE_Sideb_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); } else { - h2D->SetName(Form("hCorr_ME_Sideb_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + if (fUseSidebLeft && !fUseSidebRight) { + h2D->SetName(Form("hCorr_ME_Sideb_Left_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + } else if (!fUseSidebLeft && fUseSidebRight) { + h2D->SetName(Form("hCorr_ME_Sideb_Right_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + } else if (fUseSidebLeft && fUseSidebRight) { + h2D->SetName(Form("hCorr_ME_Sideb_LeftAndRight_2D_PtCandBin%d_PtHadBin%d_iPool%d", binExtPtCandMin, binExtPtHadMin, pool)); + } } } return h2D; } -void DhCorrelationExtraction::GetSignalAndBackgroundForNorm(Double_t PtCandMin, Double_t PtCandMax) +void DhCorrelationExtraction::getSignalAndBackgroundForNorm(Double_t ptCandMin, Double_t ptCandMax) { // using results obtained from HFInvariantMassFitter.cxx class TH1F* hMassFitSgnYield = reinterpret_cast(fFileMass->Get(fMassHistoNameSgn.Data())); TH1F* hMassFitBkgYield = reinterpret_cast(fFileMass->Get(fMassHistoNameBkg.Data())); TH1F* hMassFitSBsYield = reinterpret_cast(fFileMass->Get(fMassHistoNameSBs.Data())); + TH1F* hMassFitSBLYield = reinterpret_cast(fFileMass->Get("hBackgroundSidebandLeft")); + TH1F* hMassFitSBRYield = reinterpret_cast(fFileMass->Get("hBackgroundSidebandRight")); - Int_t PtCandBin = hMassFitSgnYield->FindBin(PtCandMin + 0.01); - if (PtCandBin != hMassFitSgnYield->FindBin(PtCandMax - 0.01)) + Int_t const ptCandBin = hMassFitSgnYield->FindBin(ptCandMin + 0.01); + if (ptCandBin != hMassFitSgnYield->FindBin(ptCandMax - 0.01)) { std::cout << "[ERROR] Pt bin in invariant mass histogram not univocally defined " << std::endl; + } - Float_t SgnYield = hMassFitSgnYield->GetBinContent(PtCandBin); - Float_t BkgYield = hMassFitBkgYield->GetBinContent(PtCandBin); - Float_t SBsYield = hMassFitSBsYield->GetBinContent(PtCandBin); + Float_t const sgnYield = hMassFitSgnYield->GetBinContent(ptCandBin); + Float_t const bkgYield = hMassFitBkgYield->GetBinContent(ptCandBin); + Float_t const sBsYield = hMassFitSBsYield->GetBinContent(ptCandBin); + Float_t const sblYield = hMassFitSBLYield->GetBinContent(ptCandBin); + Float_t const sbrYield = hMassFitSBRYield->GetBinContent(ptCandBin); std::cout << "================================= " << std::endl; std::cout << "Getting invariant mass parameters " << std::endl; - std::cout << "Pt cand " << PtCandMin << " - " << PtCandMax << std::endl; - std::cout << "Signal yield = " << SgnYield << std::endl; - std::cout << "Bkg yield = " << BkgYield << std::endl; - std::cout << "Sideband yield = " << SBsYield << std::endl; + std::cout << "Pt cand " << ptCandMin << " - " << ptCandMax << std::endl; + std::cout << "Signal yield = " << sgnYield << std::endl; + std::cout << "Bkg yield = " << bkgYield << std::endl; + std::cout << "Sideband yield = " << sBsYield << std::endl; + std::cout << "Sideband left yield = " << sblYield << std::endl; + std::cout << "Sideband right yield = " << sbrYield << std::endl; std::cout << "================================= " << std::endl; std::cout << " " << std::endl; - SetSignalYieldforNorm(SgnYield); - SetBkgScaleFactor(BkgYield / SBsYield); + setSignalYieldforNorm(sgnYield); + setBkgYield(bkgYield); + if (fUseSidebLeft && fUseSidebRight) { + setBkgScaleFactor(bkgYield / sBsYield); + setSbYield(sBsYield); + } else if (fUseSidebLeft && !fUseSidebRight) { + setBkgScaleFactor(bkgYield / sblYield); + setSbYield(sblYield); + } else if (!fUseSidebLeft && fUseSidebRight) { + setBkgScaleFactor(bkgYield / sbrYield); + setSbYield(sbrYield); + } +} + +TH2D* DhCorrelationExtraction::getFdTemplateHisto(Int_t promptOrFd, Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax) +{ + + TH2D* h2D = nullptr; // pointer to be returned + + if (promptOrFd == kPrompt) { + h2D = reinterpret_cast(fFileFDTemplate->Get(Form("%s%.0f_%.0f_ptassoc%.0f_%.0f", fHistoFDTemplatePromptName.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax))); + } else { + h2D = reinterpret_cast(fFileFDTemplate->Get(Form("%s%.0f_%.0f_ptassoc%.0f_%.0f", fHistoFDTemplateNonPromptName.Data(), ptCandMin, ptCandMax, ptHadMin, ptHadMax))); + } + + Int_t binExtEtaMin = h2D->GetXaxis()->FindBin(fDeltaEtaMin + 0.000001); + Int_t binExtEtaMax = h2D->GetXaxis()->FindBin(fDeltaEtaMax - 0.000001); + if (binExtEtaMax > h2D->GetXaxis()->GetNbins()) { + binExtEtaMax = h2D->GetXaxis()->GetNbins(); + } + if (binExtEtaMin < 1) { + binExtEtaMin = 1; + } + + h2D->GetXaxis()->SetRange(binExtEtaMin, binExtEtaMax); + if (promptOrFd == kPrompt) { + h2D->SetName(Form("hFDTemplatePrompt_2D_PtCand%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } else { + h2D->SetName(Form("hFDTemplateNonPrompt_2D_PtCand%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } + h2D->GetYaxis()->SetTitle("#Delta#phi (rad)"); + h2D->GetXaxis()->SetTitle("#Delta#eta"); + + return h2D; +} + +TH1D* DhCorrelationExtraction::getCorrelHistoSecondaryPart(Int_t partType, Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax) +{ + + TH1D* h1D = nullptr; // pointer to be returned + + THnSparseD* hSparse = nullptr; + + if (partType == kPrimaryPart) { // primary particles + hSparse = reinterpret_cast(fDirSecPart->Get(fHistoPrimaryPartName.Data())); + } else { // all selected particles + hSparse = reinterpret_cast(fDirSecPart->Get(fHistoAllPartName.Data())); + } + Int_t const binExtPtCandMin = hSparse->GetAxis(2)->FindBin(ptCandMin + 0.01); // axis2: ptCand, the 0.01 to avoid bin edges! + Int_t const binExtPtCandMax = hSparse->GetAxis(2)->FindBin(ptCandMax - 0.01); + Int_t const binExtPtHadMin = hSparse->GetAxis(3)->FindBin(ptHadMin + 0.01); // axis3: ptHad + Int_t const binExtPtHadMax = hSparse->GetAxis(3)->FindBin(ptHadMax - 0.01); + Int_t binExtPoolMin; + Int_t binExtPoolMax; + if (partType == kAllPart) { + binExtPoolMin = 1; + binExtPoolMax = hSparse->GetAxis(4)->GetNbins(); + } + // possibility to select a certain eta region + Int_t binExtEtaMin = hSparse->GetAxis(1)->FindBin(fDeltaEtaMin + 0.0001); + Int_t binExtEtaMax = hSparse->GetAxis(1)->FindBin(fDeltaEtaMax - 0.0001); + if (binExtEtaMax > hSparse->GetAxis(1)->GetNbins()) { + binExtEtaMax = hSparse->GetAxis(1)->GetNbins(); + } + if (binExtEtaMin < 1) { + binExtEtaMin = 1; + } + + hSparse->GetAxis(1)->SetRange(binExtEtaMin, binExtEtaMax); // axis1: deltaEta + hSparse->GetAxis(2)->SetRange(binExtPtCandMin, binExtPtCandMax); // axis2: ptCand + hSparse->GetAxis(3)->SetRange(binExtPtHadMin, binExtPtHadMax); // axis3: ptHad + if (partType == kAllPart) { + hSparse->GetAxis(4)->SetRange(binExtPoolMin, binExtPoolMax); // axis4: pool bin + } + + h1D = hSparse->Projection(0); // axis0: deltaPhi + if (partType == kPrimaryPart) { // primary particles + h1D->SetName(Form("hPrimaryPartCorr_PtD%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } else { // all selected particles + h1D->SetName(Form("hAllPartCorr_PtD%.0fto%.0f_PtHad%.0fto%.0f", ptCandMin, ptCandMax, ptHadMin, ptHadMax)); + } + + return h1D; +} + +TH1D* DhCorrelationExtraction::reflectCorrHistogram(TH1D*& histo) +{ + + // nBinsPhi must be a multple of 4 in order to reflect correcty the histogram + Int_t const nBinsPhi = histo->GetNbinsX(); + Int_t const nBinsPhiRefl = nBinsPhi / 2; + Int_t const bin0Phi = nBinsPhi / 4 + 1; + Int_t const binPiPhi = 3 * nBinsPhi / 4; + + TH1D* h1D = new TH1D("h1D_Reflected", "", nBinsPhiRefl, 0., TMath::Pi()); // pointer to be returned + h1D->Sumw2(); + // TH1D* h1D = reinterpret_cast histo -> Clone("h1D_Reflected"); + // h1D -> GetXaxis() -> SetRange(bin0Phi, binPiPhi); + + // reflection + Double_t reflectedContent, reflectedContentError; + for (int iBin = 0; iBin < nBinsPhiRefl / 2; iBin++) { + reflectedContent = (histo->GetBinContent(bin0Phi - iBin - 1) + histo->GetBinContent(bin0Phi + iBin)) / 2; + std::cout << "[INFO] Paired bins for reflection: " << bin0Phi - iBin - 1 << " - " << bin0Phi + iBin << std::endl; + std::cout << "[INFO] Bin filled: " << iBin + 1 << std::endl; + reflectedContentError = 0.5 * TMath::Sqrt(TMath::Power(histo->GetBinError(iBin + 1), 2) + TMath::Power(histo->GetBinError(bin0Phi + iBin), 2)); + h1D->SetBinContent(iBin + 1, reflectedContent); + h1D->SetBinError(iBin + 1, reflectedContentError); + } + for (int iBin = nBinsPhiRefl / 2; iBin < nBinsPhiRefl; iBin++) { + reflectedContent = (histo->GetBinContent(bin0Phi + iBin) + histo->GetBinContent(binPiPhi + 2 * bin0Phi - iBin - 2)) / 2; + reflectedContentError = 0.5 * TMath::Sqrt(TMath::Power(histo->GetBinError(bin0Phi + iBin), 2) + TMath::Power(histo->GetBinError(binPiPhi + 2 * bin0Phi - iBin - 2), 2)); + std::cout << "[INFO] Paired bins for reflection: " << bin0Phi + iBin << " - " << binPiPhi + 2 * bin0Phi - iBin - 2 << std::endl; + std::cout << "[INFO] Bin filled: " << iBin + 1 << std::endl; + h1D->SetBinContent(iBin + 1, reflectedContent); + h1D->SetBinError(iBin + 1, reflectedContentError); + } + + return h1D; +} + +TH1D* DhCorrelationExtraction::reflectHistoRun2(TH1D* h, Double_t scale) +{ + + TH1D* h2 = new TH1D(Form("%sReflected", h->GetName()), Form("%sReflected", h->GetName()), h->GetNbinsX() / 2., 0., TMath::Pi()); + for (Int_t j = 1; j <= h->GetNbinsX(); j++) { + Double_t const x = h->GetBinCenter(j); + Double_t const y0 = h->GetBinContent(j); + Double_t const ey0 = h->GetBinError(j); + Int_t j2; + if (x > 0 && x < TMath::Pi()) { + j2 = h2->FindBin(x); + } else if (x < 0) { + j2 = h2->FindBin(-1. * x); + } else if (x > TMath::Pi()) { + j2 = h2->FindBin(2. * TMath::Pi() - x); + } else { + printf("Point %d excluded \n", j); + continue; + } + Double_t const y = h2->GetBinContent(j2); + Double_t const ey = h2->GetBinError(j2); + h2->SetBinContent(j2, (y + y0)); + h2->SetBinError(j2, TMath::Sqrt(ey0 * ey0 + ey * ey)); + } + h2->Scale(scale); + + return h2; +} + +Double_t DhCorrelationExtraction::getFdPromptFrac(Double_t ptCandMin, Double_t ptCandMax, Double_t /*ptHadMin*/, Double_t /*ptHadMax*/) +{ + + TH1D* h1D = reinterpret_cast(fFileFDPromptFrac->Get(fHistoFDPromptFracName.Data())); - return; + Int_t const binPtCandMin = h1D->GetXaxis()->FindBin(ptCandMin + 0.01); + Int_t const binPtCandMax = h1D->GetXaxis()->FindBin(ptCandMax - 0.01); + Double_t promptFraction; + if (binPtCandMin == binPtCandMax) { + promptFraction = h1D->GetBinContent(binPtCandMin); + } else { + std::cout << "[ERROR] Different bin obtained from PtCandMin and PtCandMax"; + return 0.; + } + + return promptFraction; } -void DhCorrelationExtraction::NormalizeMEplot(TH2D*& histoME, TH2D*& histoMEsoftPi) +void DhCorrelationExtraction::normalizeMePlot(TH2D*& histoME, TH2D*& histoMEsoftPi) const { - Double_t bin0phi = histoME->GetYaxis()->FindBin(0.); - Double_t bin0eta = histoME->GetXaxis()->FindBin(0.); + Int_t const bin0phi = histoME->GetYaxis()->FindBin(0.); + Int_t const bin0eta = histoME->GetXaxis()->FindBin(0.); // evaluate the normalization (from ALL tracks, including possible fake softpions) -> **histoME indeed includes bin1+bin2 of THnSparse, i.e. all the tracks** Double_t factorNorm = 0; @@ -493,17 +1362,158 @@ void DhCorrelationExtraction::NormalizeMEplot(TH2D*& histoME, TH2D*& histoMEsoft } factorNorm /= 4.; + std::cout << "bin 0 phi: " << bin0phi << std::endl; + std::cout << "bin 0 eta: " << bin0eta << std::endl; + std::cout << "Factor norm. ME: " << factorNorm << std::endl; + std::cout << "Bin content (0,0) ME: " << histoME->GetBinContent(bin0eta, bin0phi) << std::endl; + if (fSubtractSoftPiME) { histoME->Add(histoMEsoftPi, -1); // remove the tracks compatible with soft pion (if requested) } // apply the normalization histoME->Scale(1. / factorNorm); +} + +Double_t DhCorrelationExtraction::calculateBaseline(TH1D*& histo, Bool_t totalRange, Bool_t reflected) +{ + + // total range = 2*Pi + // half range = Pi , for histogram reflected under symmetric assumption + + Double_t baseline; + Int_t const nBinsPhi = histo->GetNbinsX(); + Int_t const binPhiHalf = nBinsPhi / 2; + Int_t const binPhiHalfMinus1 = nBinsPhi / 2 - 1; + Int_t const binPhiHalfPlus1 = nBinsPhi / 2 + 1; + Int_t const binPhiHalfPlus2 = nBinsPhi / 2 + 1; + + if (totalRange) { + // baseline evaluated considering: the two first points, the last two points and four points in the middle (corresponding to the outer points) + if (nBinsPhi >= 32) { + baseline = + ((histo->GetBinContent(1)) * (1. / TMath::Power(histo->GetBinError(1), 2)) + + (histo->GetBinContent(2)) * (1. / TMath::Power(histo->GetBinError(2), 2)) + + (histo->GetBinContent(binPhiHalfMinus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (histo->GetBinContent(binPhiHalfPlus2)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2)) + + (histo->GetBinContent(nBinsPhi - 1)) * (1. / TMath::Power(histo->GetBinError(nBinsPhi - 1), 2)) + + (histo->GetBinContent(nBinsPhi)) * (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))) / + ((1. / TMath::Power(histo->GetBinError(1), 2)) + + (1. / TMath::Power(histo->GetBinError(2), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi - 1), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))); + } else { + baseline = + ((histo->GetBinContent(1)) * (1. / TMath::Power(histo->GetBinError(1), 2)) + + (histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (histo->GetBinContent(nBinsPhi)) * (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))) / + ((1. / TMath::Power(histo->GetBinError(1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))); + } + } else { + if (reflected) { + baseline = + ((histo->GetBinContent(binPhiHalfMinus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (histo->GetBinContent(binPhiHalfPlus2)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))) / + ((1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))); + } else { + // baseline evaluated using the 4 middle points in the transverese region + if (nBinsPhi >= 32) { + baseline = + ((histo->GetBinContent(binPhiHalfMinus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (histo->GetBinContent(binPhiHalfPlus2)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))) / + ((1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))); + } else { + baseline = + ((histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2))) / + ((1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2))); + } + } + } + + return baseline; +} + +Double_t DhCorrelationExtraction::calculateBaselineError(TH1D*& histo, Bool_t totalRange, Bool_t reflected) +{ + + // total range = 2*Pi + // half range = Pi , for histogram reflected under symmetric assumption + + Double_t errBaseline; + Int_t const nBinsPhi = histo->GetNbinsX(); + Int_t const binPhiHalf = nBinsPhi / 2; + Int_t const binPhiHalfMinus1 = nBinsPhi / 2 - 1; + Int_t const binPhiHalfPlus1 = nBinsPhi / 2 + 1; + Int_t const binPhiHalfPlus2 = nBinsPhi / 2 + 1; + + if (totalRange) { + // baseline evaluated considering: the two first points, the last two points and four points in the middle (corresponding to the outer points) + if (nBinsPhi >= 32) { + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(1), 2)) + + (1. / TMath::Power(histo->GetBinError(2), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi - 1), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))); + } else { // fon nBinsPhi = 16 (rebin 4) + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))); + } + } else { + // baseline evaluated using the 4 middle points in the transverese region + if (reflected) { + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))); + } else { + if (nBinsPhi >= 32) { + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))); + } else { + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2))); + } + } + } - return; + return errBaseline; } -void DhCorrelationExtraction::SetTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, +void DhCorrelationExtraction::setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, Style_t markerStyle, Color_t markerColor, Double_t markerSize, Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset, Float_t hTitleYaxisOffset, Float_t hTitleXaxisSize, Float_t hTitleYaxisSize, Float_t hLabelXaxisSize, Float_t hLabelYaxisSize, @@ -526,11 +1536,9 @@ void DhCorrelationExtraction::SetTH1HistoStyle(TH1D*& histo, TString hTitle, TSt histo->GetYaxis()->SetLabelSize(hLabelYaxisSize); histo->GetXaxis()->CenterTitle(centerXaxisTitle); histo->GetYaxis()->CenterTitle(centerYaxisTitle); - - return; } -void DhCorrelationExtraction::SetTH2HistoStyle(TH2D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, TString hZaxisTitle, +void DhCorrelationExtraction::setTH2HistoStyle(TH2D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, TString hZaxisTitle, Float_t hTitleXaxisOffset, Float_t hTitleYaxisOffset, Float_t hTitleZaxisOffset, Float_t hTitleXaxisSize, Float_t hTitleYaxisSize, Float_t hTitleZaxisSize, Float_t hLabelXaxisSize, Float_t hLabelYaxisSize, Float_t hLabelZaxisSize, @@ -552,6 +1560,4 @@ void DhCorrelationExtraction::SetTH2HistoStyle(TH2D*& histo, TString hTitle, TSt histo->GetZaxis()->SetLabelSize(hLabelZaxisSize); histo->GetXaxis()->CenterTitle(centerXaxisTitle); histo->GetYaxis()->CenterTitle(centerYaxisTitle); - - return; } diff --git a/PWGHF/HFC/Macros/DhCorrelationExtraction.h b/PWGHF/HFC/Macros/DhCorrelationExtraction.h index a659724594b..aa3f2a52874 100644 --- a/PWGHF/HFC/Macros/DhCorrelationExtraction.h +++ b/PWGHF/HFC/Macros/DhCorrelationExtraction.h @@ -17,22 +17,17 @@ #ifndef PWGHF_HFC_MACROS_DHCORRELATIONEXTRACTION_H_ #define PWGHF_HFC_MACROS_DHCORRELATIONEXTRACTION_H_ -#include -#include "TObject.h" -#include "TMath.h" -#include "TFile.h" -#include "TDirectoryFile.h" -#include "TList.h" -#include "TCanvas.h" -#include "TPaveText.h" -#include "TLegend.h" -#include "TSystem.h" -#include "TH1D.h" -#include "TH2D.h" -#include "TH3D.h" -#include "TF1.h" -#include "THnSparse.h" -#include "TVector.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include class DhCorrelationExtraction : public TObject { @@ -42,102 +37,197 @@ class DhCorrelationExtraction : public TObject kDplusKpipi, kDsToKKPi, kDStarD0pi }; - enum selectAnalysisType { kSE, + enum SelectAnalysisType { kSE, kME }; - enum selectInvMassRegion { kSign, + enum SelectInvMassRegion { kSign, kSideb }; + enum SelectDmesonOrigin { kPrompt, + kFD }; + enum SelectParticleType { kPrimaryPart, + kAllPart }; DhCorrelationExtraction(); // default constructor DhCorrelationExtraction(const DhCorrelationExtraction& source); - virtual ~DhCorrelationExtraction(); + ~DhCorrelationExtraction() override; /// Methods to set the input configuration // Input files, directories and histograms - Bool_t SetDmesonSpecie(DmesonSpecie k); - void SetInputFilenameMass(TString filenameMass) { fFileNameMass = filenameMass; } - void SetInputFilenameSE(TString filenameSE) { fFileNameSE = filenameSE; } - void SetInputFilenameME(TString filenameME) { fFileNameME = filenameME; } - void SetDirNameSE(TString dirNameSE) { fDirNameSE = dirNameSE; } - void SetDirNameME(TString dirNameME) { fDirNameME = dirNameME; } - void SetMassHistoNameSgn(TString massHistoNameSgn) { fMassHistoNameSgn = massHistoNameSgn; } - void SetMassHistoNameBkg(TString massHistoNameBkg) { fMassHistoNameBkg = massHistoNameBkg; } - void SetMassHistoNameSBs(TString massHistoNameSBs) { fMassHistoNameSBs = massHistoNameSBs; } - void SetSECorrelHistoSignalName(TString correlNameSigSE) { fSECorrelSignalRegionName = correlNameSigSE; } - void SetSECorrelHistoSidebandName(TString correlNameSbSE) { fSECorrelSidebandsName = correlNameSbSE; } - void SetMECorrelHistoSignalName(TString correlNameSigME) { fMECorrelSignalRegionName = correlNameSigME; } - void SetMECorrelHistoSidebandName(TString correlNameSbME) { fMECorrelSidebandsName = correlNameSbME; } + Bool_t setDmesonSpecie(DmesonSpecie k); + void setInputFilenameMass(TString filenameMass) { fFileNameMass = filenameMass; } + void setInputFilenameSe(TString filenameSE) { fFileNameSE = filenameSE; } + void setInputFilenameMe(TString filenameME) { fFileNameME = filenameME; } + void setInputFilenameSecPart(TString filenameSecPart) { fFileSecPartName = filenameSecPart; } + void setInputFilenameBiasBtoD(TString filenamePromptMcRec, TString filenameNonPromptMcRec) + { + fFilePromptMcRecName = filenamePromptMcRec; + fFileNonPromptMcRecName = filenameNonPromptMcRec; + } + void setDirNameSe(TString dirNameSE) { fDirNameSE = dirNameSE; } + void setDirNameMe(TString dirNameME) { fDirNameME = dirNameME; } + void setDirNameSecPart(TString dirNameSecPart) { fDirSecPartName = dirNameSecPart; } + void setMassHistoNameSgn(TString massHistoNameSgn) { fMassHistoNameSgn = massHistoNameSgn; } + void setMassHistoNameBkg(TString massHistoNameBkg) { fMassHistoNameBkg = massHistoNameBkg; } + void setMassHistoNameSBs(TString massHistoNameSBs) { fMassHistoNameSBs = massHistoNameSBs; } + void setSeCorrelHistoSignalName(TString correlNameSigSE) { fSECorrelSignalRegionName = correlNameSigSE; } + void setSeCorrelHistoSidebandName(TString correlNameSbSE) { fSECorrelSidebandsName = correlNameSbSE; } + void setSeCorrelHistoSidebandLeftName(TString correlNameSbSE) { fSECorrelSidebandLeftName = correlNameSbSE; } + void setSeCorrelHistoSidebandRightName(TString correlNameSbSE) { fSECorrelSidebandRightName = correlNameSbSE; } + void setMeCorrelHistoSignalName(TString correlNameSigME) { fMECorrelSignalRegionName = correlNameSigME; } + void setMeCorrelHistoSidebandName(TString correlNameSbME) { fMECorrelSidebandsName = correlNameSbME; } + void setMeCorrelHistoSidebandLeftName(TString correlNameSbME) { fMECorrelSidebandLeftName = correlNameSbME; } + void setMeCorrelHistoSidebandRightName(TString correlNameSbME) { fMECorrelSidebandRightName = correlNameSbME; } + void setHistoSecPartName(TString histoPrimaryPartName, TString histoAllPartName) + { + fHistoPrimaryPartName = histoPrimaryPartName; + fHistoAllPartName = histoAllPartName; + } + void setInputFilenameFdTemplate(TString filenameFDTemplate) { fFileFDTemplateName = filenameFDTemplate; } + void setInputFilenameFdPromptFrac(TString filenameFDPromptFrac) { fFileFDPromptFracName = filenameFDPromptFrac; } + void setInputHistoNameFdTemplatePrompt(TString hNameFDTemplatePrompt) { fHistoFDTemplatePromptName = hNameFDTemplatePrompt; } + void setInputHistoNameFdTemplateNonPrompt(TString hNameFDTemplateNonPrompt) { fHistoFDTemplateNonPromptName = hNameFDTemplateNonPrompt; } + void setInputHistoNameFdPromptFrac(TString hNameFDPromptFrac) { fHistoFDPromptFracName = hNameFDPromptFrac; } // Input conditions: PtCand, PtHad, PoolBins - void SetNpools(Int_t npools) { fNpools = npools; } - void SetCorrectPoolsSeparately(Bool_t usePools) { fCorrectPoolsSeparately = usePools; } - void SetDeltaEtaRange(Double_t etaLow = -1., Double_t etaHigh = 1) + void setNpools(Int_t npools) { fNpools = npools; } + void setCorrectPoolsSeparately(Bool_t usePools) { fCorrectPoolsSeparately = usePools; } + void setDeltaEtaRange(Double_t etaLow = -1., Double_t etaHigh = 1) { fDeltaEtaMin = etaLow; fDeltaEtaMax = etaHigh; } - void SetSubtractSoftPiInMEdistr(Bool_t subtractSoftPiME) { fSubtractSoftPiME = subtractSoftPiME; } - void SetBkgScaleFactor(Double_t scaleFactor) { fBkgScaleFactor = scaleFactor; } - void SetSignalYieldforNorm(Double_t sgnYield) { fSgnYieldNorm = sgnYield; } - void SetRebin2DcorrelHisto(Int_t rebinDeltaEta, Int_t rebinDeltaPhi) + void setSubtractSoftPiInMEdistr(Bool_t subtractSoftPiME) { fSubtractSoftPiME = subtractSoftPiME; } + void setBkgScaleFactor(Double_t scaleFactor) { fBkgScaleFactor = scaleFactor; } + void setSignalYieldforNorm(Double_t sgnYield) { fSgnYieldNorm = sgnYield; } + void setBkgYield(Double_t bkgYield) { fBkgYield = bkgYield; } + void setSbYield(Double_t sbYield) { fSBYield = sbYield; } + void setRebin2DcorrelHisto(Int_t rebinDeltaEta, Int_t rebinDeltaPhi) { - fRebin2Dhisto = kTRUE; fRebinAxisDeltaEta = rebinDeltaEta; fRebinAxisDeltaPhi = rebinDeltaPhi; } - void GetSignalAndBackgroundForNorm(Double_t PtCandMin, Double_t PtCandMax); - void NormalizeMEplot(TH2D*& histoME, TH2D*& histoMEsoftPi); - void SetDebugLevel(Int_t debug) { fDebug = debug; } + void setRebinOptions(Bool_t rebinAngCorr, Bool_t rebinFDCorr, Bool_t rebinSecPart) + { + fRebinAngCorr = rebinAngCorr; + fRebinFDCorr = rebinFDCorr; + fRebinSecPart = rebinSecPart; + } + void getSignalAndBackgroundForNorm(Double_t ptCandMin, Double_t ptCandMax); + void normalizeMePlot(TH2D*& histoME, TH2D*& histoMEsoftPi) const; + void setDebugLevel(Int_t debug) { fDebug = debug; } + void setDividedSidebands(Bool_t dividedSideb, Bool_t useSidebLeft, Bool_t useSidebRight) + { + fSidebandDivided = dividedSideb; + fUseSidebLeft = useSidebLeft; + fUseSidebRight = useSidebRight; + } + void setFdSubtraction(Bool_t subtractFD) { fFDsubtraction = subtractFD; } + void setSecPartContamination(Bool_t secPartContamination) { fSecPartContamination = secPartContamination; } + void setCorrBiasBtoD(Bool_t corrbiasBtoD) { fCorrBiasBtoD = corrbiasBtoD; } + void setBinCandAndHad(Int_t binCand, Int_t binHad) + { + fBinPtCand = binCand; + fBinPtHad = binHad; + } /// Analysis methods - TH2D* GetCorrelHisto(Int_t SEorME, Int_t SorSB, Int_t pool, Double_t PtCandMin, Double_t PtCandMax, Double_t PtHadMin, Double_t PtHadMax); - Bool_t ReadInputSEandME(); - Bool_t ReadInputInvMass(); - Bool_t ExtractCorrelations(Double_t PtCandMin, Double_t PtCandMax, Double_t PtHadMin, Double_t PtHadMax, TString codeName); - TH1D* GetCorrectedCorrHisto() { return fCorrectedCorrHisto; } + TH2D* getCorrelHisto(Int_t sEorMe, Int_t sorSb, Int_t pool, Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax); + TH2D* getFdTemplateHisto(Int_t promptOrFd, Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax); + TH1D* getCorrelHistoSecondaryPart(Int_t primaryPart, Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax); + TH1D* reflectCorrHistogram(TH1D*& histo); + TH1D* reflectHistoRun2(TH1D* h, Double_t scale); + TH1D* evaluateMcClosModulations(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax); + Double_t getFdPromptFrac(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax); + Double_t calculateBaseline(TH1D*& histo, Bool_t totalRange = kTRUE, Bool_t reflected = kFALSE); + Double_t calculateBaselineError(TH1D*& histo, Bool_t totalRange = kTRUE, Bool_t reflected = kFALSE); + Bool_t readInputSeAndMe(); + Bool_t readInputInvMass(); + Bool_t readInputFdSubtr(); + Bool_t readInputSecondaryPartContamination(); + Bool_t extractCorrelations(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax, TString codeName); + TH1D* getCorrectedCorrHisto() { return fCorrectedCorrHisto; } + TH1D* getCorrectedCorrHistoBaselineSubtr() { return fCorrectedCorrHistoBaselineSubtr; } + TH1D* getCorrectedCorrHistoReflected() { return fCorrectedCorrHistoReflected; } + TH1D* getCorrectedCorrHistoReflectedBaselineSubtr() { return fCorrectedCorrHistoReflectedBaselineSubtr; } /// Histogram style - void SetTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, Style_t markerStyle = kFullCircle, Color_t markerColor = kRed + 1, Double_t markerSize = 1.4, Color_t lineColor = kRed + 1, Int_t lineWidth = 3, Float_t hTitleXaxisOffset = 1.0, Float_t hTitleYaxisOffset = 1.0, Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, Bool_t centerXaxisTitle = false, Bool_t centerYaxisTitle = false); - void SetTH2HistoStyle(TH2D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, TString hZaxisTitle, Float_t hTitleXaxisOffset = 1.8, Float_t hTitleYaxisOffset = 1.8, Float_t hTitleZaxisOffset = 1.2, Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hTitleZaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, Float_t hLabelZaxisSize = 0.060, Bool_t centerXaxisTitle = true, Bool_t centerYaxisTitle = true); + void setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, Style_t markerStyle = kFullCircle, Color_t markerColor = kRed + 1, Double_t markerSize = 1.4, Color_t lineColor = kRed + 1, Int_t lineWidth = 3, Float_t hTitleXaxisOffset = 1.0, Float_t hTitleYaxisOffset = 1.0, Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, Bool_t centerXaxisTitle = false, Bool_t centerYaxisTitle = false); + void setTH2HistoStyle(TH2D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, TString hZaxisTitle, Float_t hTitleXaxisOffset = 1.8, Float_t hTitleYaxisOffset = 1.8, Float_t hTitleZaxisOffset = 1.2, Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hTitleZaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, Float_t hLabelZaxisSize = 0.060, Bool_t centerXaxisTitle = true, Bool_t centerYaxisTitle = true); private: - TFile* fFileMass; // file containing the mass histograms - TFile* fFileSE; // file containing the Same Event (SE) output - TFile* fFileME; // file containing the Mixed Event (ME) output - - TDirectoryFile* fDirMass; // TDirectory for mass histos - TDirectoryFile* fDirSE; // TDirectory for SE info - TDirectoryFile* fDirME; // TDirectory for ME info - - TH1D* fCorrectedCorrHisto; // Corrected correlation histogram - - DmesonSpecie fDmesonSpecies; // D meson specie - TString fDmesonLabel; // D meson label - TString fFileNameMass; // File cntaining inv. mass histograms - TString fFileNameSE; // File contaning Same Event (SE) output - TString fFileNameME; // File contaning Mixed Event (ME) output - TString fDirNameSE; // Directory in the file containing SE output - TString fDirNameME; // Directory in the file containing ME output - TString fMassHistoNameSgn; // Inv. mass histo name signal yield - TString fMassHistoNameBkg; // Inv. mass histo name background yield - TString fMassHistoNameSBs; // Inv. mass histo name sideband yield - TString fSECorrelSignalRegionName; // THnSparse name containing SE output for signal region - TString fSECorrelSidebandsName; // THnSparse name containing SE output for sideband region - TString fMECorrelSignalRegionName; // THnSparse name containing ME output for signal region - TString fMECorrelSidebandsName; // THnSparse name containing ME output for sideband region - - Int_t fNpools; // number of pools used for the ME correction - Int_t fRebinAxisDeltaEta; // rebin deltaEta axis - Int_t fRebinAxisDeltaPhi; // rebin deltaPhi axis - Int_t fDebug; // debug level - - Double_t fDeltaEtaMin; // deltaEta min value - Double_t fDeltaEtaMax; // deltaEta max value + TFile* fFileMass; // File containing the mass histograms + TFile* fFileSE; // File containing the Same Event (SE) output + TFile* fFileME; // File containing the Mixed Event (ME) output + TFile* fFileFDTemplate; // File containing FD angular correlation templates + TFile* fFileFDPromptFrac; // File containing prompt fraction (used fo FD subtraction) + TFile* fFileSecPart; // File containing secondary particle contaminaion teplates + TFile* fFilePromptMc; // File containing prompt ratio taken from MC Closure test study (to use for B to D bias correction) + TFile* fFileNonPromptMc; // File containing non-prompt ratio taken from MC Closure test study (to use for B to D bias correction) + + TDirectoryFile* fDirMass; // TDirectory for mass histos + TDirectoryFile* fDirSE; // TDirectory for SE info + TDirectoryFile* fDirME; // TDirectory for ME info + TDirectoryFile* fDirSecPart; // TDirectory for seondary particle correction + + TH1D* fCorrectedCorrHisto; // Corrected correlation histogram + TH1D* fCorrectedCorrHistoBaselineSubtr; // Corrected correlation histogram with baseline subtracion + TH1D* fCorrectedCorrHistoReflected; // Corrected correlation histogram relected in azimuth + TH1D* fCorrectedCorrHistoReflectedBaselineSubtr; // Corrected correlation histogram reflected in azimuth with baseline subtraction + + DmesonSpecie fDmesonSpecies; // D meson specie + TString fDmesonLabel; // D meson label + TString fFileNameMass; // File name containing inv. mass histograms + TString fFileNameSE; // File name contaning Same Event (SE) output + TString fFileNameME; // File name contaning Mixed Event (ME) output + TString fFileSecPartName; // File name contaning secondary particle correction output + TString fFileFDTemplateName; // File name contaning FD angular correlation templates + TString fFileFDPromptFracName; // File name contaning prompt fraction (used for FD subtraction) + TString fFilePromptMcRecName; // File name contaning prompt angular correlation (used for B to d bias correction) + TString fFileNonPromptMcRecName; // File name contaning non-prompt angular correlation (used for B to d bias correction) + TString fDirNameSE; // Directory in the file containing SE output + TString fDirNameME; // Directory in the file containing ME output + TString fDirSecPartName; // Directory in the file containing secondary particle correction output + TString fMassHistoNameSgn; // Inv. mass histo name signal yield + TString fMassHistoNameBkg; // Inv. mass histo name background yield + TString fMassHistoNameSBs; // Inv. mass histo name sideband yield + TString fSECorrelSignalRegionName; // THnSparse name containing SE output for signal region + TString fSECorrelSidebandsName; // THnSparse name containing SE output for sideband region + TString fSECorrelSidebandLeftName; // THnSparse name containing SE output for sideband left region + TString fSECorrelSidebandRightName; // THnSparse name containing SE output for sideband right region + TString fMECorrelSignalRegionName; // THnSparse name containing ME output for signal region + TString fMECorrelSidebandsName; // THnSparse name containing ME output for sideband regions + TString fMECorrelSidebandLeftName; // THnSparse name containing ME output for sideband left region + TString fMECorrelSidebandRightName; // THnSparse name containing ME output for sideband right region + TString fHistoFDTemplatePromptName; // Prompt angular correlation histogram name + TString fHistoFDTemplateNonPromptName; // FD angular correlation histogram name + TString fHistoFDPromptFracName; // Prompt fraction histogram name + TString fHistoPrimaryPartName; // Primary particle histogram (to be used for secondary particle contamination correction) + TString fHistoAllPartName; // All particle histogram (to be used for secondary particle contamination correction) + + Int_t fNpools; // Number of pools used for the ME correction + Int_t fRebinAxisDeltaEta; // Rebin deltaEta axis value + Int_t fRebinAxisDeltaPhi; // Rebin deltaPhi axis value + Int_t fDebug; // Debug level + Int_t fBinPtCand; // Pt bin of the candidate + Int_t fBinPtHad; // Pt bin of the hadron + + Double_t fDeltaEtaMin; // DeltaEta min value + Double_t fDeltaEtaMax; // DeltaEta max value Double_t fBkgScaleFactor; // Bkg/SB factor to scale correlation plots obtained in the sideband region Double_t fSgnYieldNorm; // Signal yield (used for normalize correlation plots after bkg subtraction) + Double_t fBkgYield; // Bkg yield under signal peak region + Double_t fSBYield; // Sideband yield Bool_t fCorrectPoolsSeparately; // Possibility to do the ME correction pool-by-pool (kTRUE) or merging all pools (kFALSE) Bool_t fSubtractSoftPiME; // Soft pion subtraction (for D0 case) - Bool_t fRebin2Dhisto; // Flag to rebin the 2D correlation plots + Bool_t fRebinAngCorr; // Rebin angular correlaion distributons (SE and ME) + Bool_t fRebinFDCorr; // Rebin angular correlaion distributon templates used for FD correction (theory driven) + Bool_t fRebinSecPart; // Rebin angular correlaion distributon templates used for secodary particle contamination correction + Bool_t fSidebandDivided; // To be set to TRUE if two sideband corrlaion histograms are passed inteh config file + Bool_t fUseSidebLeft; // To be set to TRUE if only sideband left is used for the bkg correction + Bool_t fUseSidebRight; // To be set to TRUE if only sideband right is used for the bkg correction + Bool_t fFDsubtraction; // Enable feed-down (FD) correction + Bool_t fSecPartContamination; // Enable seconday particle contamination correction + Bool_t fCorrBiasBtoD; // Enable bias B to D correction (perfrmed with angular correlaion templates taken from MC simulaions) }; #endif // PWGHF_HFC_MACROS_DHCORRELATIONEXTRACTION_H_ diff --git a/PWGHF/HFC/Macros/DhCorrelationFitter.cxx b/PWGHF/HFC/Macros/DhCorrelationFitter.cxx index d203c6ee63f..594f58f8843 100644 --- a/PWGHF/HFC/Macros/DhCorrelationFitter.cxx +++ b/PWGHF/HFC/Macros/DhCorrelationFitter.cxx @@ -10,163 +10,142 @@ // or submit itself to any jurisdiction. /// \file DhCorrelationFitter.cxx -/// \brief Class to perform the azimuthal correlation fit +/// \brief class for for performing the fit of azimuthal correlations /// \author Samuele Cattaruzzi /// \author Swapnesh Santosh Khade -#include -#include -#include -#include +#include "DhCorrelationFitter.h" + +#include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include +#include +#include // IWYU pragma: keep (do not replace with TMatrixDfwd.h) +#include #include -#include "DhCorrelationFitter.h" +#include +#include +#include +#include + +#include +#include + +#include +#include DhCorrelationFitter::DhCorrelationFitter() : // default constructor + fHist(nullptr), + fFit(nullptr), + fGausNS(nullptr), + fGausAS(nullptr), + fPed(nullptr), + fBaseTransvReg(nullptr), fIsReflected(kFALSE), + fUseExternalPars(kFALSE), + fShiftBaselineUp(kFALSE), + fShiftBaselineDown(kFALSE), + fIsTotal(kTRUE), fTypeOfFitFunc(kConstwoGaus), fFixBase(0), fFixMean(0), - fMinCandPt(0.), - fMaxCandPt(99.), - fMinAssoPt(0.), - fMaxAssoPt(99.), fNpars(0), - fExtParsVals(0x0), - fExtParsLowBounds(0x0), - fExtParsUppBounds(0x0), - fUseExternalPars(kFALSE), fNbasleinePoints(0), - fBinsBaseline(0x0), - fHist(0x0), + fBinsBaseline(nullptr), fMinCorr(0), fMaxCorr(0), + fMinCandPt(0.), + fMaxCandPt(99.), + fMinAssoPt(0.), + fMaxAssoPt(99.), fBaseline(0.), fErrBaseline(0.), - fFit(0x0), - fGausNS(0x0), - fGausAS(0x0), - fPed(0x0), fNSyieldBinCount(0.), fErrNSyieldBinCount(0.), fASyieldBinCount(0.), - fErrASyieldBinCount(0.) + fErrASyieldBinCount(0.), + fv2AssocPart(0.), + fv2Dmeson(0.), + fExtParsVals(nullptr), + fExtParsLowBounds(nullptr), + fExtParsUppBounds(nullptr) { } DhCorrelationFitter::DhCorrelationFitter(TH1F* histoToFit, Double_t min, Double_t max) : // standard constructor + fHist(histoToFit), + fFit(nullptr), + fGausNS(nullptr), + fGausAS(nullptr), + fPed(nullptr), + fBaseTransvReg(nullptr), fIsReflected(kFALSE), + fUseExternalPars(kFALSE), + fShiftBaselineUp(kFALSE), + fShiftBaselineDown(kFALSE), + fIsTotal(kTRUE), fTypeOfFitFunc(kConstwoGaus), fFixBase(0), fFixMean(0), + fNpars(0), + fNbasleinePoints(0), + fBinsBaseline(nullptr), + fMinCorr(min), + fMaxCorr(max), fMinCandPt(0.), fMaxCandPt(99.), fMinAssoPt(0.), fMaxAssoPt(99.), - fNpars(0), - fExtParsVals(0x0), - fExtParsLowBounds(0x0), - fExtParsUppBounds(0x0), - fUseExternalPars(kFALSE), - fNbasleinePoints(0), - fBinsBaseline(0x0), - fHist(0x0), - fMinCorr(0.), - fMaxCorr(0.), fBaseline(0.), fErrBaseline(0.), - fFit(0x0), - fGausNS(0x0), - fGausAS(0x0), - fPed(0x0), fNSyieldBinCount(0.), fErrNSyieldBinCount(0.), fASyieldBinCount(0.), - fErrASyieldBinCount(0.) + fErrASyieldBinCount(0.), + fv2AssocPart(0.), + fv2Dmeson(0.), + fExtParsVals(nullptr), + fExtParsLowBounds(nullptr), + fExtParsUppBounds(nullptr) { - fHist = histoToFit; - fMinCorr = min; - fMaxCorr = max; } -DhCorrelationFitter::DhCorrelationFitter(const DhCorrelationFitter& source) : // copy constructor - fIsReflected(source.fIsReflected), - fTypeOfFitFunc(source.fTypeOfFitFunc), - fFixBase(source.fFixBase), - fFixMean(source.fFixMean), - fMinCandPt(source.fMinCandPt), - fMaxCandPt(source.fMaxCandPt), - fMinAssoPt(source.fMinAssoPt), - fMaxAssoPt(source.fMaxAssoPt), - fNpars(source.fNpars), - fExtParsVals(source.fExtParsVals), - fExtParsLowBounds(source.fExtParsLowBounds), - fExtParsUppBounds(source.fExtParsUppBounds), - fUseExternalPars(source.fUseExternalPars), - fNbasleinePoints(source.fNbasleinePoints), - fBinsBaseline(source.fBinsBaseline), - fHist(source.fHist), - fMinCorr(source.fMinCorr), - fMaxCorr(source.fMaxCorr), - fBaseline(source.fBaseline), - fErrBaseline(source.fErrBaseline), - fFit(source.fFit), - fGausNS(source.fGausNS), - fGausAS(source.fGausAS), - fPed(source.fPed), - fNSyieldBinCount(source.fNSyieldBinCount), - fErrNSyieldBinCount(source.fErrNSyieldBinCount), - fASyieldBinCount(source.fASyieldBinCount), - fErrASyieldBinCount(source.fErrASyieldBinCount) -{ -} +DhCorrelationFitter::DhCorrelationFitter(const DhCorrelationFitter& source) + + = default; DhCorrelationFitter::~DhCorrelationFitter() // destructor { Info("DhCorrelationFitter.cxx", "Destructor is calling"); - if (fHist) { + if (fHist != nullptr) { delete fHist; - fHist = 0; + fHist = nullptr; } - if (fFit) { + if (fFit != nullptr) { delete fFit; - fFit = 0; + fFit = nullptr; } - if (fGausNS) { + if (fGausNS != nullptr) { delete fGausNS; - fGausNS = 0; + fGausNS = nullptr; } // if (fGausNS2) {delete fGausNS2; fGausNS2 = 0;} - if (fPed) { + if (fPed != nullptr) { delete fPed; - fPed = 0; + fPed = nullptr; } } DhCorrelationFitter& DhCorrelationFitter::operator=(const DhCorrelationFitter& cfit) // assignment operator { - if (&cfit == this) + if (&cfit == this) { return *this; + } fIsReflected = cfit.fIsReflected; fTypeOfFitFunc = cfit.fTypeOfFitFunc; @@ -181,6 +160,9 @@ DhCorrelationFitter& DhCorrelationFitter::operator=(const DhCorrelationFitter& c fExtParsLowBounds = cfit.fExtParsLowBounds; fExtParsUppBounds = cfit.fExtParsUppBounds; fUseExternalPars = cfit.fUseExternalPars; + fShiftBaselineUp = cfit.fShiftBaselineUp; + fShiftBaselineDown = cfit.fShiftBaselineDown; + fIsTotal = cfit.fIsTotal; fNbasleinePoints = cfit.fNbasleinePoints; fBinsBaseline = cfit.fBinsBaseline; fHist = cfit.fHist; @@ -192,6 +174,9 @@ DhCorrelationFitter& DhCorrelationFitter::operator=(const DhCorrelationFitter& c fGausNS = cfit.fGausNS; fGausAS = cfit.fGausAS; fPed = cfit.fPed; + fBaseTransvReg = cfit.fBaseTransvReg; + fv2AssocPart = cfit.fv2AssocPart; + fv2Dmeson = cfit.fv2Dmeson; fNSyieldBinCount = cfit.fNSyieldBinCount; fErrNSyieldBinCount = cfit.fErrNSyieldBinCount; fASyieldBinCount = cfit.fASyieldBinCount; @@ -200,7 +185,7 @@ DhCorrelationFitter& DhCorrelationFitter::operator=(const DhCorrelationFitter& c return *this; } -void DhCorrelationFitter::SetExternalValsAndBounds(Int_t nPars, Double_t* vals, Double_t* lowBounds, Double_t* uppBounds) +void DhCorrelationFitter::setExternalValsAndBounds(Int_t nPars, const Double_t* vals, const Double_t* lowBounds, const Double_t* uppBounds) { fNpars = nPars; @@ -214,32 +199,40 @@ void DhCorrelationFitter::SetExternalValsAndBounds(Int_t nPars, Double_t* vals, fExtParsLowBounds[i] = lowBounds[i]; fExtParsUppBounds[i] = uppBounds[i]; } - - return; } -void DhCorrelationFitter::Fitting(Bool_t drawSplitTerm, Bool_t useExternalPars) +void DhCorrelationFitter::fitting(Bool_t drawSplitTerm, Bool_t useExternalPars) { // -> fFixBase = 0 : baseline free // = 1 : fix the baseline to the minimum of the histogram // < 0 : fix the baseline to the weighted average of the abs(fFixBaseline) lower points // = 2 : zyam at pi/2. Fix the baseline averaging the 2 points around +-pi/2 value // = 3 : fix the baseline to the weighted average of the points passed through the function SetPointsForBaseline() + // = 4 : fix the baseline to the weighted average of the points in the transverse region in default configuration (i.e. for 32 bins the first 2, the last 2 and the 4 middle ones) // // -> fFixMean = 0 : NS & AS mean free // = 1 : NS mean fixed to 0, AS mean free // = 2 : AS mean fixed to pi, NS mean free // = 3 : NS mean fixed to 0, AS mean to pi - if (useExternalPars) + if (useExternalPars) { fUseExternalPars = kTRUE; + } if (fFixBase != 0 && fFixBase != 6) { Printf("[INFO] DhCorrelationFitter::Fitting, Finding baseline"); - FindBaseline(); + findBaseline(); + } + if (fFixBase == 0) { + // set initial value of the fBaseline + fBaseline = calculateBaseline(fHist, fIsTotal); } Printf("[INFO] DhCorrelationFitter::Fitting, Setting Function"); - SetFitFunction(); + if (fTypeOfFitFunc == 7) { // case for v2 modulation + fitBaselineWv2(); // to contrain the B parameter in the fit function for the pedestal + Printf("[INFO] B parameter for v2 fit: %.3f", fBaseline); + } + setFitFunction(); if (fFixBase != 0) { fFit->FixParameter(0, fBaseline); @@ -248,14 +241,19 @@ void DhCorrelationFitter::Fitting(Bool_t drawSplitTerm, Bool_t useExternalPars) fFit->FixParameter(2, 0.); } if (fFixMean == 2 || fFixMean == 3) { - if (fTypeOfFitFunc != 0) + if (fTypeOfFitFunc != 0 && fTypeOfFitFunc != 3) { fFit->FixParameter(5, TMath::Pi()); + } + if (fTypeOfFitFunc == 3 || fTypeOfFitFunc == 6) { + fFit->FixParameter(2, TMath::Pi()); + } } + Printf("[INFO] DhCorrelationFitter::Fitting, Fitting"); TVirtualFitter::SetMaxIterations(20000); - TFitResultPtr fitptr = fHist->Fit(fFit, "RIMES", "", fMinCorr, fMaxCorr); - TMatrixD cor = fitptr->GetCorrelationMatrix(); - TMatrixD cov = fitptr->GetCovarianceMatrix(); + TFitResultPtr const fitptr = fHist->Fit(fFit, "RIMES", "", fMinCorr, fMaxCorr); + TMatrixD const cor = fitptr->GetCorrelationMatrix(); + TMatrixD const cov = fitptr->GetCovarianceMatrix(); printf("[INFO] Correlation Matrix - The final one! \n"); cor.Print(); gMinuit->mnmatu(1); @@ -266,25 +264,45 @@ void DhCorrelationFitter::Fitting(Bool_t drawSplitTerm, Bool_t useExternalPars) fErrBaseline = fFit->GetParError(0); } Printf("[INFO] DhCorrelationFitter::Fitting, Calculating yields with BC"); - CalculateYieldsAboveBaseline(); + calculateYieldsAboveBaseline(); fHist->SetTitle(";#Delta#varphi (rad); #frac{1}{N_{D}}#frac{dN^{assoc}}{d#Delta#varphi} (rad^{-1})"); Printf("[INFO] DhCorrelationFitter::Fitting, Now drawing, if requested"); - SetSingleTermsForDrawing(drawSplitTerm); + setSingleTermsForDrawing(drawSplitTerm); + + // NS yield from bin counting + double fNSyield = 0.; + double fNSyieldErr = 0.; + double baselinBinCount = 0; + for (int iBin = 1; iBin <= 6; iBin++) { // first six bins + fNSyield += 2 * (fHist->GetBinContent(iBin) - fBaseline) * fHist->GetBinWidth(iBin); // x2 due to the fatct the histogram is reflected + fNSyieldErr += 4 * (TMath::Power(fHist->GetBinError(iBin), 2) + TMath::Power(fErrBaseline, 2)) * (fHist->GetBinWidth(iBin) * fHist->GetBinWidth(iBin)); + baselinBinCount += fBaseline * fHist->GetBinWidth(iBin); + } + fNSyieldErr = TMath::Sqrt(fNSyieldErr); + + // AS yield from bin counting + double fASyield = 0.; + double fASyieldErr = 0.; + for (int iBin = 11; iBin <= 16; iBin++) { // last six bins + fASyield += 2 * (fHist->GetBinContent(iBin) - fBaseline) * fHist->GetBinWidth(iBin); + fASyieldErr += 4 * (TMath::Power(fHist->GetBinError(iBin), 2) + TMath::Power(fErrBaseline, 2)) * (fHist->GetBinWidth(iBin) * fHist->GetBinWidth(iBin)); + } + fASyieldErr = TMath::Sqrt(fASyieldErr); + + printf("[RESULT MINE] Bin counting results: NS Yield = %.3f +- %.3f \n[RESULT MINE] Bin counting results: AS Yield: %.3f +- %.3f \n[RESULT MINE] baseline = %.3f \n", fNSyield, fNSyieldErr, fASyield, fASyieldErr, baselinBinCount); } -void DhCorrelationFitter::SetFitFunction() +void DhCorrelationFitter::setFitFunction() { - // -> fitFunc = 1: const+ G NS + G AS (w/o periodicity) - // = 2: const+ G NS + G AS (w/ periodicity) - // = 3: const+ yieldNS*[fact*(G NS)+(1- fact)*(G2 NS)] + yieldAS*(G AS) (w/ periodicity) - // = 4: const +yieldNS*(G NS) + yieldAS*[fact*(G AS)+(1- fact)*(G2 AS)] (w/ periodicity) - // = 5: v2 modulation (no gaussian terms) - // = 6: v2 modulation + G NS + G AS (w/ periodicity) - // = 7: const+ GenG NS + G AS (w/ periodicity) - // = 8: const+ GenG fixBeta NS + G AS (w/ periodicity) - // = 9: const+ GenG constrBeta NS + G AS (w/ periodicity) - - if (fFit) { + // -> fitFunc = 1: const + G NS + G AS (w/o periodicity) + // = 2: const + G NS + G AS (w/ periodicity) + // = 3: const + G AS + // = 4: const + GenG NS + G AS (w/ periodicity) + // = 5: const + VonMises NS + VonMises AS (w/periodicity) + // = 6: const + VonMises AS + // = 7: baseline w v2 modulation + G NS + G AS (w/ periodicity) + + if (fFit != nullptr) { delete fFit; delete fGausNS; // delete fGausNS2; @@ -372,10 +390,184 @@ void DhCorrelationFitter::SetFitFunction() fFit->SetParName(6, "AS #sigma"); break; + + case 3: + fFit = new TF1("OneGausPeriodicity", "[0]+[1]/TMath::Sqrt(2.*TMath::Pi())/[3]*TMath::Exp(-(x-[2])*(x-[2])/2./([3]*[3]))+[1]/TMath::Sqrt(2.*TMath::Pi())/[3]*TMath::Exp(-(x+2.*TMath::Pi()-[2])*(x+2.*TMath::Pi()-[2])/2./([3]*[3]))+[1]/TMath::Sqrt(2.*TMath::Pi())/[3]*TMath::Exp(-(x-2.*TMath::Pi()-[2])*(x-2.*TMath::Pi()-[2])/2./([3]*[3]))", fMinCorr, fMaxCorr); + fGausAS = new TF1("fGausASper", "[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x-[1])*(x-[1])/2./([2]*[2]))+[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x-2.*TMath::Pi()-[1])*(x-2.*TMath::Pi()-[1])/2./([2]*[2]))+[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x+2.*TMath::Pi()-[1])*(x+2.*TMath::Pi()-[1])/2./([2]*[2]))", fMinCorr, fMaxCorr); + fPed = new TF1("fPed", "[0]", fMinCorr, fMaxCorr); + + // TODO: add possibility to use external parameters + // if(!fUseExternalPars) { + fFit->SetParLimits(0, 0, 9999.); + fFit->SetParLimits(1, 0, 999.); + fFit->SetParLimits(2, 2., 4.); + fFit->SetParLimits(3, 0, 3.14 / 2.); + + fFit->SetParameter(0, 3); + fFit->SetParameter(1, 2); + fFit->SetParameter(2, 3.14); + fFit->SetParameter(3, 0.3); + + /*} else { + for(int i=0; i SetParameter(i, fExtParsVals[i]); + fFit -> SetParLimits(i, fExtParsLowBounds[i], fExtParsUppBounds[i]); + } + } */ + + fFit->SetParName(0, "ped"); + fFit->SetParName(1, "AS Y"); + fFit->SetParName(2, "AS mean"); + fFit->SetParName(3, "AS #sigma"); + + break; + + case 4: + fFit = new TF1("kModifNSGausPeriodicity", "[0]+[1]*([7]*TMath::Sqrt(TMath::Gamma(3./[7]))/(2.*[3]*TMath::Power(TMath::Gamma(1./[7]),3./2.))*TMath::Exp(-TMath::Power(TMath::Abs(x-[2])*TMath::Sqrt(TMath::Gamma(3./[7]))/([3]*TMath::Sqrt(TMath::Gamma(1./[7]))),[7])))+[4]/TMath::Sqrt(2.*TMath::Pi())/[6]*TMath::Exp(-(x-[5])*(x-[5])/2./([6]*[6]))+[1]*([7]*TMath::Sqrt(TMath::Gamma(3./[7]))/(2.*[3]*TMath::Power(TMath::Gamma(1./[7]),3./2.))*TMath::Exp(-TMath::Power(TMath::Abs(x-2*TMath::Pi()-[2])*TMath::Sqrt(TMath::Gamma(3./[7]))/([3]*TMath::Sqrt(TMath::Gamma(1./[7]))),[7])))+[1]*([7]*TMath::Sqrt(TMath::Gamma(3./[7]))/(2.*[3]*TMath::Power(TMath::Gamma(1./[7]),3./2.))*TMath::Exp(-TMath::Power(TMath::Abs(x+2*TMath::Pi()-[2])*TMath::Sqrt(TMath::Gamma(3./[7]))/([3]*TMath::Sqrt(TMath::Gamma(1./[7]))),[7])))+[4]/TMath::Sqrt(2.*TMath::Pi())/[6]*TMath::Exp(-(x-2.*TMath::Pi()-[5])*(x-2.*TMath::Pi()-[5])/2./([6]*[6]))+[4]/TMath::Sqrt(2.*TMath::Pi())/[6]*TMath::Exp(-(x+2.*TMath::Pi()-[5])*(x+2.*TMath::Pi()-[5])/2./([6]*[6]))", fMinCorr, fMaxCorr); + fGausNS = new TF1("fModGausNSper", "[0]*([3]*TMath::Sqrt(TMath::Gamma(3./[3]))/(2.*[2]*TMath::Power(TMath::Gamma(1./[3]),3./2.))*TMath::Exp(-TMath::Power(TMath::Abs(x-[1])*TMath::Sqrt(TMath::Gamma(3./[3]))/([2]*TMath::Sqrt(TMath::Gamma(1./[3]))),[3])))+[0]*([3]*TMath::Sqrt(TMath::Gamma(3./[3]))/(2.*[2]*TMath::Power(TMath::Gamma(1./[3]),3./2.))*TMath::Exp(-TMath::Power(TMath::Abs(x-2*TMath::Pi()-[1])*TMath::Sqrt(TMath::Gamma(3./[3]))/([2]*TMath::Sqrt(TMath::Gamma(1./[3]))),[3])))+[0]*([3]*TMath::Sqrt(TMath::Gamma(3./[3]))/(2.*[2]*TMath::Power(TMath::Gamma(1./[3]),3./2.))*TMath::Exp(-TMath::Power(TMath::Abs(x+2*TMath::Pi()-[1])*TMath::Sqrt(TMath::Gamma(3./[3]))/([2]*TMath::Sqrt(TMath::Gamma(1./[3]))),[3])))", fMinCorr, fMaxCorr); + fGausAS = new TF1("fGausASper", "[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x-[1])*(x-[1])/2./([2]*[2]))+[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x-2.*TMath::Pi()-[1])*(x-2.*TMath::Pi()-[1])/2./([2]*[2]))+[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x+2.*TMath::Pi()-[1])*(x+2.*TMath::Pi()-[1])/2./([2]*[2]))", fMinCorr, fMaxCorr); + fPed = new TF1("fPed", "[0]", fMinCorr, fMaxCorr); + + fFit->SetParLimits(0, 0., 999.); + fFit->SetParLimits(1, 0.005, 25.); + fFit->SetParLimits(2, -0.55, 0.55); + fFit->SetParLimits(3, 0, 0.8); + fFit->SetParLimits(4, 0.005, 25.); + fFit->SetParLimits(5, 2.85, 3.55); + fFit->SetParLimits(6, 0.05, 3.14 / 2.); + fFit->SetParLimits(7, 0.5, 3.5); + + // default starting pars + fFit->SetParameter(0, 1.); + fFit->SetParameter(1, 1.); + fFit->SetParameter(2, 0.); + fFit->SetParameter(3, 0.3); + fFit->SetParameter(4, 0.25); + fFit->SetParameter(5, TMath::Pi()); + fFit->SetParameter(6, 0.3); + fFit->SetParameter(7, 2); + + fFit->SetParName(0, "ped"); + fFit->SetParName(1, "NS Y"); + fFit->SetParName(2, "NS mean"); + fFit->SetParName(3, "NS #sigma"); + fFit->SetParName(4, "AS Y"); + fFit->SetParName(5, "AS mean"); + fFit->SetParName(6, "AS #sigma"); + fFit->SetParName(7, "NS shape par"); // beta of the gen. gaussian + break; + + case 5: + fFit = new TF1("kVonMises", "[0] +[1]/(2*TMath::Pi()*TMath::BesselI0([3]))*TMath::Exp([3]*TMath::Cos(x- 2*TMath::Pi() - [2])) + [4]/(2*TMath::Pi()*TMath::BesselI0([6]))*TMath::Exp([6]*TMath::Cos(x- 2*TMath::Pi()-[5]))", fMinCorr, fMaxCorr); + fGausNS = new TF1("fVonMisesNS", "[0]/(2*TMath::Pi()*TMath::BesselI0([2]))*TMath::Exp([2]*TMath::Cos(x- 2*TMath::Pi() - [1]))", fMinCorr, fMaxCorr); + fGausAS = new TF1("fVonMisesAS", "[0]/(2*TMath::Pi()*TMath::BesselI0([2]))*TMath::Exp([2]*TMath::Cos(x- 2*TMath::Pi()-[1]))", fMinCorr, fMaxCorr); + fPed = new TF1("fPed", "[0]", fMinCorr, fMaxCorr); + + fFit->SetParLimits(0, 0., 999.); + fFit->SetParLimits(1, 0.005, 25.); + fFit->SetParLimits(2, -0.55, 0.55); + fFit->SetParLimits(3, 0, 15.); + fFit->SetParLimits(4, 0.005, 25.); + fFit->SetParLimits(5, 2.85, 3.55); + fFit->SetParLimits(6, 0., 15.); + + // default starting pars + fFit->SetParameter(0, 3.5); + fFit->SetParameter(1, 0.8); + fFit->SetParameter(2, 0.); + fFit->SetParameter(3, 1.); + fFit->SetParameter(4, 1.5); + fFit->SetParameter(5, TMath::Pi()); + fFit->SetParameter(6, 1.); + + fFit->SetParName(0, "ped"); + fFit->SetParName(1, "NS Y"); + fFit->SetParName(2, "NS mean"); + fFit->SetParName(3, "NS #sigma"); + fFit->SetParName(4, "AS Y"); + fFit->SetParName(5, "AS mean"); + fFit->SetParName(6, "AS #sigma"); + + break; + + case 6: + fFit = new TF1("kSingleVonMises", "[0] +[1]/(2*TMath::Pi()*TMath::BesselI0([3]))*TMath::Exp([3]*TMath::Cos(x- 2*TMath::Pi() - [2]))", fMinCorr, fMaxCorr); + fGausAS = new TF1("fVonMisesAS", "[0]/(2*TMath::Pi()*TMath::BesselI0([2]))*TMath::Exp([2]*TMath::Cos(x- 2*TMath::Pi()-[1]))", fMinCorr, fMaxCorr); + fPed = new TF1("fPed", "[0]", fMinCorr, fMaxCorr); + + fFit->SetParLimits(0, 0., 999.); + fFit->SetParLimits(1, 0.005, 25.); + fFit->SetParLimits(2, 2.85, 3.55); + fFit->SetParLimits(3, 0., 15.); + + // default starting pars + fFit->SetParameter(0, 3.5); + fFit->SetParameter(1, 1.5); + fFit->SetParameter(2, TMath::Pi()); + fFit->SetParameter(3, 1.); + + fFit->SetParName(0, "ped"); + fFit->SetParName(1, "AS Y"); + fFit->SetParName(2, "AS mean"); + fFit->SetParName(3, "AS #sigma"); + + break; + + case 7: // case 2 Gaus w periodicity + v2 modulation + + fFit = new TF1("kTwoGausPeriodicityPlusV2modulation", "[1]/TMath::Sqrt(2.*TMath::Pi())/[3]*TMath::Exp(-(x-[2])*(x-[2])/2./([3]*[3]))+[4]/TMath::Sqrt(2.*TMath::Pi())/[6]*TMath::Exp(-(x-[5])*(x-[5])/2./([6]*[6]))+[1]/TMath::Sqrt(2.*TMath::Pi())/[3]*TMath::Exp(-(x-2.*TMath::Pi()-[2])*(x-2.*TMath::Pi()-[2])/2./([3]*[3]))+[1]/TMath::Sqrt(2.*TMath::Pi())/[3]*TMath::Exp(-(x+2.*TMath::Pi()-[2])*(x+2.*TMath::Pi()-[2])/2./([3]*[3]))+[4]/TMath::Sqrt(2.*TMath::Pi())/[6]*TMath::Exp(-(x+2.*TMath::Pi()-[5])*(x+2.*TMath::Pi()-[5])/2./([6]*[6]))+[4]/TMath::Sqrt(2.*TMath::Pi())/[6]*TMath::Exp(-(x-2.*TMath::Pi()-[5])*(x-2.*TMath::Pi()-[5])/2./([6]*[6]))+[0]*(1+2*[7]*[8]*TMath::Cos(2*x))", fMinCorr, fMaxCorr); + fGausNS = new TF1("fGausNSper", "[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x-[1])*(x-[1])/2./([2]*[2]))+[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x-2.*TMath::Pi()-[1])*(x-2.*TMath::Pi()-[1])/2./([2]*[2]))+[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x+2.*TMath::Pi()-[1])*(x+2.*TMath::Pi()-[1])/2./([2]*[2]))", fMinCorr, fMaxCorr); + fGausAS = new TF1("fGausASper", "[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x-[1])*(x-[1])/2./([2]*[2]))+[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x-2.*TMath::Pi()-[1])*(x-2.*TMath::Pi()-[1])/2./([2]*[2]))+[0]/TMath::Sqrt(2.*TMath::Pi())/[2]*TMath::Exp(-(x+2.*TMath::Pi()-[1])*(x+2.*TMath::Pi()-[1])/2./([2]*[2]))", fMinCorr, fMaxCorr); + fPed = new TF1("fPedv2Mod", "[0]*(1+2*[1]*[2]*TMath::Cos(2*x))", fMinCorr, fMaxCorr); + + fFit->SetParLimits(0, 0., 999.); + fFit->SetParLimits(1, 0, 999.); + fFit->SetParLimits(2, -0.55, 0.55); + fFit->SetParLimits(3, 0, 3.14 / 3.); + fFit->SetParLimits(4, 0, 999.); + fFit->SetParLimits(5, 2.85, 3.55); + fFit->SetParLimits(6, 0, 3.14 / 2.); + fFit->SetParLimits(7, -1, 1); + fFit->SetParLimits(8, -1, 1); + + fFit->FixParameter(0, fBaseline); + fFit->SetParameter(1, 3); + fFit->SetParameter(2, 0.); + fFit->SetParameter(3, 0.3); + fFit->SetParameter(4, 2); + fFit->SetParameter(5, TMath::Pi()); + fFit->SetParameter(6, 0.3); + fFit->SetParameter(7, 0); + fFit->SetParameter(8, 0); + + if (fUseExternalPars) { // overwrites previous configuration + for (int i = 0; i < fNpars; i++) { + fFit->SetParameter(i, fExtParsVals[i]); + fFit->SetParLimits(i, fExtParsLowBounds[i], fExtParsUppBounds[i]); + } + } + + fFit->FixParameter(7, fv2AssocPart); + fFit->FixParameter(8, fv2Dmeson); + + fPed->FixParameter(0, fBaseline); + fPed->FixParameter(1, fv2AssocPart); + fPed->FixParameter(2, fv2Dmeson); + + fFit->SetParName(0, "ped"); + fFit->SetParName(1, "NS Y"); + fFit->SetParName(2, "NS mean"); + fFit->SetParName(3, "NS #sigma"); + fFit->SetParName(4, "AS Y"); + fFit->SetParName(5, "AS mean"); + fFit->SetParName(6, "AS #sigma"); + fFit->SetParName(7, "v_{2} hadron"); + fFit->SetParName(8, "v_{2} D meson"); + break; } } -void DhCorrelationFitter::SetPointsForBaseline(Int_t nBaselinePoints, Int_t* binsBaseline) +void DhCorrelationFitter::setPointsForBaseline(Int_t nBaselinePoints, const Int_t* binsBaseline) { fNbasleinePoints = nBaselinePoints; @@ -385,17 +577,15 @@ void DhCorrelationFitter::SetPointsForBaseline(Int_t nBaselinePoints, Int_t* bin for (int i = 0; i < fNbasleinePoints; i++) { fBinsBaseline[i] = binsBaseline[i]; } - - return; } -Double_t DhCorrelationFitter::FindBaseline() +Double_t DhCorrelationFitter::findBaseline() { // baseline free if (fFixBase == 0) { Printf("[INFO] DhCorrelationFitter::FindBasline(). The baseline option is set to free baseline: now the full fit will be done. Beware!"); - Fitting(); // TODO: not sure + fitting(); // TODO: not sure return fBaseline; } @@ -412,19 +602,30 @@ Double_t DhCorrelationFitter::FindBaseline() fBaseline = min; fErrBaseline = fHist->GetBinError(iBin); + if (fShiftBaselineUp) { + fBaseline += fErrBaseline; + printf("[INFO] Shift baseline up of its statistical uncertainty"); + } + + if (fShiftBaselineDown) { + fBaseline -= fErrBaseline; + printf("[INFO] Shift baseline down of its statistical uncertainty"); + } + return fBaseline; } // fix the baseline to the weighted average of the abs(fFixBaseline) lower points if (fFixBase < 0) { Int_t npointsAv = TMath::Abs(fFixBase); - Int_t* ind = new Int_t[fHist->GetNbinsX()]; - Float_t* hval = new Float_t[fHist->GetNbinsX()]; + auto* ind = new Int_t[fHist->GetNbinsX()]; + auto* hval = new Float_t[fHist->GetNbinsX()]; for (Int_t k = 1; k <= fHist->GetNbinsX(); k++) { hval[k - 1] = fHist->GetBinContent(k); } - Double_t errAv = 0., Av = 0.; + Double_t errAv = 0., av = 0.; TMath::Sort(fHist->GetNbinsX(), hval, ind, kFALSE); // KFALSE -> increasing order + delete[] hval; // Average of abs(fFixBase) lower points for (Int_t k = 0; k < npointsAv; k++) { if (fHist->GetBinError(ind[k] + 1) == 0.) // in case of null entries which induce a crash. Could bias the basline in upward direction! @@ -433,38 +634,61 @@ Double_t DhCorrelationFitter::FindBaseline() npointsAv++; continue; } - Av += fHist->GetBinContent(ind[k] + 1) / (fHist->GetBinError(ind[k] + 1) * fHist->GetBinError(ind[k] + 1)); + av += fHist->GetBinContent(ind[k] + 1) / (fHist->GetBinError(ind[k] + 1) * fHist->GetBinError(ind[k] + 1)); errAv += 1. / (fHist->GetBinError(ind[k] + 1) * fHist->GetBinError(ind[k] + 1)); } - Av /= errAv; + delete[] ind; + av /= errAv; errAv = TMath::Sqrt(1. / errAv); - printf("[RESULT] Average fBaseline: %.3f +- %.3f", Av, errAv); - fBaseline = Av; + printf("[RESULT] Average fBaseline: %.3f +- %.3f", av, errAv); + fBaseline = av; fErrBaseline = errAv; + + if (fShiftBaselineUp) { + fBaseline += fErrBaseline; + printf("[INFO] Shift baseline up of its statistical uncertainty"); + } + + if (fShiftBaselineDown) { + fBaseline -= fErrBaseline; + printf("[INFO] Shift baseline down of its statistical uncertainty"); + } + return fBaseline; } // zyam at pi/2. Fix the baseline averaging the 2 points around +-pi/2 value if (fFixBase == 2) { - Double_t errAv = 0., Av = 0.; + Double_t errAv = 0., av = 0.; Int_t binPhi = fHist->FindBin(TMath::Pi() / 2.); - Av += fHist->GetBinContent(binPhi) / (fHist->GetBinError(binPhi) * fHist->GetBinError(binPhi)); + av += fHist->GetBinContent(binPhi) / (fHist->GetBinError(binPhi) * fHist->GetBinError(binPhi)); errAv += 1. / (fHist->GetBinError(binPhi) * fHist->GetBinError(binPhi)); if (!fIsReflected) { binPhi = fHist->FindBin(-TMath::Pi() / 2.); - if (binPhi < 1) + if (binPhi < 1) { binPhi = 1; - Av += fHist->GetBinContent(binPhi) / (fHist->GetBinError(binPhi) * fHist->GetBinError(binPhi)); + } + av += fHist->GetBinContent(binPhi) / (fHist->GetBinError(binPhi) * fHist->GetBinError(binPhi)); errAv += 1. / (fHist->GetBinError(binPhi) * fHist->GetBinError(binPhi)); } else { printf("[INFO] Reflected histo: only the point at +pi/2 used to evaluate baseline"); } - Av /= errAv; + av /= errAv; errAv = TMath::Sqrt(1. / errAv); - printf("[RESULT] Average fBaseline: %.3f +- %.3f \n", Av, errAv); - fBaseline = Av; + printf("[RESULT] Average fBaseline: %.3f +- %.3f \n", av, errAv); + fBaseline = av; fErrBaseline = errAv; + if (fShiftBaselineUp) { + fBaseline += fErrBaseline; + printf("[INFO] Shift baseline up of its statistical uncertainty"); + } + + if (fShiftBaselineDown) { + fBaseline -= fErrBaseline; + printf("[INFO] Shift baseline down of its statistical uncertainty"); + } + return fBaseline; } @@ -474,17 +698,44 @@ Double_t DhCorrelationFitter::FindBaseline() printf("[ERROR] No baseline points set for the baseline evaluation, SetPointsForBaseline(Int_t nBaselinePoints, Double_t* valsBaseline). Returning -1"); return -1; } - Double_t errAv = 0., Av = 0.; + Double_t errAv = 0., av = 0.; for (int i = 0; i < fNbasleinePoints; i++) { - Av += fHist->GetBinContent(fBinsBaseline[i]) / (fHist->GetBinError(fBinsBaseline[i]) * fHist->GetBinError(fBinsBaseline[i])); + av += fHist->GetBinContent(fBinsBaseline[i]) / (fHist->GetBinError(fBinsBaseline[i]) * fHist->GetBinError(fBinsBaseline[i])); errAv += 1. / (fHist->GetBinError(fBinsBaseline[i]) * fHist->GetBinError(fBinsBaseline[i])); } - Av /= errAv; + av /= errAv; errAv = TMath::Sqrt(1. / errAv); - printf("[RESULT] Average fBaseline: %.3f +- %.3f \n", Av, errAv); - fBaseline = Av; + printf("[RESULT] Average fBaseline: %.3f +- %.3f \n", av, errAv); + fBaseline = av; fErrBaseline = errAv; + if (fShiftBaselineUp) { + fBaseline += fErrBaseline; + printf("[INFO] Shift baseline up of its statistical uncertainty \n"); + } + + if (fShiftBaselineDown) { + fBaseline -= fErrBaseline; + printf("[INFO] Shift baseline down of its statistical uncertainty \n"); + } + + return fBaseline; + } + + if (fFixBase == 4) { + fBaseline = calculateBaseline(fHist, fIsTotal); // TODO: add the option for total range/ reflected range to pass in input + fErrBaseline = calculateBaselineError(fHist, fIsTotal); + + if (fShiftBaselineUp) { + fBaseline += fErrBaseline; + printf("[INFO] Shift baseline up of its statistical uncertainty \n"); + } + + if (fShiftBaselineDown) { + fBaseline -= fErrBaseline; + printf("[INFO] Shift baseline down of its statistical uncertainty \n"); + } + return fBaseline; } @@ -492,90 +743,381 @@ Double_t DhCorrelationFitter::FindBaseline() return -1.; } -void DhCorrelationFitter::CalculateYieldsAboveBaseline() +void DhCorrelationFitter::fitBaselineWv2() +{ + + fBaseTransvReg = new TF1("fBaseTransvReg", [](const double* x, const double* p) { + double const xx = x[0]; // x value + if ((xx >= -TMath::Pi()/2 && xx <= -3*TMath::Pi()/8) || (xx >= 3*TMath::Pi()/8 && xx <= 5*TMath::Pi()/8) || (xx >= 11*TMath::Pi()/8 && xx <= 3*TMath::Pi()/2)) { + // Gaussian example: p[0] = amplitude, p[1] = mean, p[2] = sigma + return p[0]*(1+2*p[1]*p[2]*TMath::Cos(2*xx)); + } + return 0.; }, -TMath::Pi() / 2, 3 * TMath::Pi() / 2, 3); // Function valid for [0,10], with 3 parameters + + fBaseTransvReg->FixParameter(1, fv2AssocPart); + fBaseTransvReg->FixParameter(2, fv2Dmeson); + + TFitResultPtr const rFit = fHist->Fit(fBaseTransvReg, "RIMES", "", fMinCorr, fMaxCorr); + fBaseline = fBaseTransvReg->GetParameter(0); +} + +void DhCorrelationFitter::calculateYieldsAboveBaseline() { fNSyieldBinCount = 0; fErrNSyieldBinCount = 0; fASyieldBinCount = 0; fErrASyieldBinCount = 0; - cout << "[RESULT] Baseline: " << fBaseline << " +- " << fErrBaseline << endl; + std::cout << "[RESULT] Baseline: " << fBaseline << " +- " << fErrBaseline << std::endl; Int_t binMinNS = fHist->FindBin(-1.5); // slightly more than -pi/2 - if (binMinNS < 1) - binMinNS = 1; // with this, it is ok even in the case of a reflected fHist (range 0 - pi) - Int_t binMaxNS = fHist->FindBin(1.5); // slightly less than +pi/2 - Int_t binMinAS = fHist->FindBin(1.6); // slightly more than +pi/2 - Int_t binMaxAS = fHist->FindBin(3.14 + 1.5); // slightly less than +3pi/2 - if (binMaxAS > fHist->GetNbinsX()) - binMaxNS = fHist->GetNbinsX(); // with this, it is ok even in the case of a reflected fHist (range 0 - pi) TODO: maybe binMaxAS + if (binMinNS < 1) { + binMinNS = 1; // with this, it is ok even in the case of a reflected fHist (range 0 - pi) + } + Int_t const binMaxNS = 6; // fHist -> FindBin(1.5); // slightly less than +pi/2 + Int_t const binMinAS = 11; // fHist -> FindBin(1.6); // slightly more than +pi/2 + Int_t binMaxAS = 16; // fHist -> FindBin(3.14+1.5); // slightly less than +3pi/2 + if (binMaxAS > fHist->GetNbinsX()) { + binMaxAS = fHist->GetNbinsX(); // with this, it is ok even in the case of a reflected fHist (range 0 - pi) + } + std::cout << "N bins : " << fHist->GetNbinsX() << std::endl; + std::cout << "binMinNS : " << binMinNS << std::endl; + std::cout << "binMaxNS : " << binMaxNS << std::endl; + std::cout << "binMinAS : " << binMinAS << std::endl; + std::cout << "binMaxAS : " << binMaxAS << std::endl; // Near Side Yield from bin counting for (Int_t bmNS = binMinNS; bmNS <= binMaxNS; bmNS++) { - fNSyieldBinCount += (fHist->GetBinContent(bmNS) - fBaseline) * fHist->GetBinWidth(bmNS); - fErrNSyieldBinCount += (fHist->GetBinError(bmNS) * fHist->GetBinError(bmNS)) * fHist->GetBinWidth(bmNS) * fHist->GetBinWidth(bmNS); + fNSyieldBinCount += 2 * (fHist->GetBinContent(bmNS) - fBaseline) * fHist->GetBinWidth(bmNS); + fErrNSyieldBinCount += 4 * (fHist->GetBinError(bmNS) * fHist->GetBinError(bmNS)) * fHist->GetBinWidth(bmNS) * fHist->GetBinWidth(bmNS); } fErrNSyieldBinCount = TMath::Sqrt(fErrNSyieldBinCount); // Away Side Yield from bin counting for (Int_t bmAS = binMinAS; bmAS <= binMaxAS; bmAS++) { - fASyieldBinCount += (fHist->GetBinContent(bmAS) - fBaseline) * fHist->GetBinWidth(bmAS); - fErrASyieldBinCount += (fHist->GetBinError(bmAS) * fHist->GetBinError(bmAS)) * fHist->GetBinWidth(bmAS) * fHist->GetBinWidth(bmAS); + fASyieldBinCount += 2 * (fHist->GetBinContent(bmAS) - fBaseline) * fHist->GetBinWidth(bmAS); + fErrASyieldBinCount += 4 * (fHist->GetBinError(bmAS) * fHist->GetBinError(bmAS)) * fHist->GetBinWidth(bmAS) * fHist->GetBinWidth(bmAS); } fErrASyieldBinCount = TMath::Sqrt(fErrASyieldBinCount); printf("[RESULT] Bin counting results: NS Yield = %.3f +- %.3f \n[RESULT] Bin counting results: AS Yield: %.3f +- %.3f \n", fNSyieldBinCount, fErrNSyieldBinCount, fASyieldBinCount, fErrASyieldBinCount); +} - return; +Double_t DhCorrelationFitter::calculateBaseline(TH1F*& histo, Bool_t totalRange) +{ + + // total range = 2*Pi + // half range = Pi , for histogram reflected under symmetric assumption + + Double_t baseline; + Int_t const nBinsPhi = histo->GetNbinsX(); + Int_t const binPhiHalf = nBinsPhi / 2; + Int_t const binPhiHalfMinus1 = nBinsPhi / 2 - 1; + Int_t const binPhiHalfPlus1 = nBinsPhi / 2 + 1; + Int_t const binPhiHalfPlus2 = nBinsPhi / 2 + 1; + + if (totalRange) { + printf("[INFO] Using total deltaPhi range \n"); + // baseline evaluated considering: the two first points, the last two points and four points in the middle (corresponding to the outer points) + if (nBinsPhi >= 32) { + printf("[INFO] nBinsPhi >= 32 \n"); + baseline = + ((histo->GetBinContent(1)) * (1. / TMath::Power(histo->GetBinError(1), 2)) + + (histo->GetBinContent(2)) * (1. / TMath::Power(histo->GetBinError(2), 2)) + + (histo->GetBinContent(binPhiHalfMinus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (histo->GetBinContent(binPhiHalfPlus2)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2)) + + (histo->GetBinContent(nBinsPhi - 1)) * (1. / TMath::Power(histo->GetBinError(nBinsPhi - 1), 2)) + + (histo->GetBinContent(nBinsPhi)) * (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))) / + ((1. / TMath::Power(histo->GetBinError(1), 2)) + + (1. / TMath::Power(histo->GetBinError(2), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi - 1), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))); + } else { + printf("[INFO] nBinsPhi < 32 \n"); + baseline = + ((histo->GetBinContent(1)) * (1. / TMath::Power(histo->GetBinError(1), 2)) + + (histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (histo->GetBinContent(nBinsPhi)) * (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))) / + ((1. / TMath::Power(histo->GetBinError(1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))); + } + } else { + printf("[INFO] Using reflected deltaPhi range \n"); + // baseline evaluated using the 4 middle points in the transverese region + if (nBinsPhi >= 16) { + printf("[INFO] 4 central points in the transverse region for baseline \n"); + baseline = + ((histo->GetBinContent(binPhiHalfMinus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (histo->GetBinContent(binPhiHalfPlus2)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))) / + ((1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))); + } else { + baseline = + ((histo->GetBinContent(binPhiHalf)) * (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (histo->GetBinContent(binPhiHalfPlus1)) * (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2))) / + ((1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2))); + } + } + + return baseline; } -void DhCorrelationFitter::SetSingleTermsForDrawing(Bool_t draw) +Double_t DhCorrelationFitter::calculateBaselineError(TH1F*& histo, Bool_t totalRange) { - Double_t* par = 0; - if (fTypeOfFitFunc == 1 || fTypeOfFitFunc == 2) { + + // total range = 2*Pi + // half range = Pi , for histogram reflected under symmetric assumption + + Double_t errBaseline; + Int_t const nBinsPhi = histo->GetNbinsX(); + Int_t const binPhiHalf = nBinsPhi / 2; + Int_t const binPhiHalfMinus1 = nBinsPhi / 2 - 1; + Int_t const binPhiHalfPlus1 = nBinsPhi / 2 + 1; + Int_t const binPhiHalfPlus2 = nBinsPhi / 2 + 1; + + if (totalRange) { + // baseline evaluated considering: the two first points, the last two points and four points in the middle (corresponding to the outer points) + if (nBinsPhi >= 32) { + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(1), 2)) + + (1. / TMath::Power(histo->GetBinError(2), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi - 1), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))); + } else { // fon nBinsPhi = 16 (rebin 4) + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(nBinsPhi), 2))); + } + } else { + // baseline evaluated using the 4 middle points in the transverese region + if (nBinsPhi >= 32) { + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(binPhiHalfMinus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus2), 2))); + } else { + errBaseline = 1. / + TMath::Sqrt((1. / TMath::Power(histo->GetBinError(binPhiHalf), 2)) + + (1. / TMath::Power(histo->GetBinError(binPhiHalfPlus1), 2))); + } + } + + return errBaseline; +} + +void DhCorrelationFitter::setSingleTermsForDrawing(Bool_t draw) +{ + Double_t* par = nullptr; + if (fTypeOfFitFunc == 1 || fTypeOfFitFunc == 2 || fTypeOfFitFunc == 5) { par = new Double_t[7]; + } else if (fTypeOfFitFunc == 3 || fTypeOfFitFunc == 6) { + par = new Double_t[4]; + } else if (fTypeOfFitFunc == 4) { + par = new Double_t[8]; + } else if (fTypeOfFitFunc == 7) { + par = new Double_t[9]; } else { Printf("[ERROR] DhCorrelationFitter::SetSingleTermsForDrawing, wrong type of function"); return; } - fFit->GetParameters(par); - fFit->SetLineWidth(4); - - fPed->SetParameter(0, par[0]); - fPed->SetLineColor(6); // pink - fPed->SetLineStyle(9); - fPed->SetLineWidth(4); - - fGausNS->SetParameter(0, par[1]); - fGausNS->SetParameter(1, par[2]); - fGausNS->SetParameter(2, par[3]); - fGausAS->SetParameter(0, par[4]); - fGausAS->SetParameter(1, par[5]); - fGausAS->SetParameter(2, par[6]); - - fGausNS->SetLineStyle(9); - fGausNS->SetLineColor(kBlue); - fGausAS->SetLineStyle(9); - fGausAS->SetLineColor(kGreen); - fGausNS->SetLineWidth(4); - fGausAS->SetLineWidth(4); - - TPaveText* pvStatTests1 = new TPaveText(0.51, 0.58, 0.85, 0.90, "NDC"); - pvStatTests1->SetFillStyle(0); - pvStatTests1->SetTextSize(0.035); - pvStatTests1->SetBorderSize(0); - TText *t0, *t1, *t2, *t3, *t4, *t5, *t6; - t0 = pvStatTests1->AddText(0., 1.00, Form("#chi^{2}/ndf = %.1f/%d ", fFit->GetChisquare(), fFit->GetNDF())); - t1 = pvStatTests1->AddText(0., 0.80, Form("Ped = %.3f#pm%.3f ", fBaseline, fErrBaseline)); - t2 = pvStatTests1->AddText(0., 0.65, Form("NS Y = %.3f#pm%.3f ", fFit->GetParameter("NS Y"), fFit->GetParError(fFit->GetParNumber("NS Y")))); - t3 = pvStatTests1->AddText(0., 0.50, Form("NS #sigma = %.3f#pm%.3f ", fFit->GetParameter("NS #sigma"), fFit->GetParError(fFit->GetParNumber("NS #sigma")))); - t4 = pvStatTests1->AddText(0., 0.35, Form("AS Y = %.3f#pm%.3f ", fFit->GetParameter("AS Y"), fFit->GetParError(fFit->GetParNumber("AS Y")))); - t5 = pvStatTests1->AddText(0., 0.20, Form("AS #sigma = %.3f#pm%.3f ", fFit->GetParameter("AS #sigma"), fFit->GetParError(fFit->GetParNumber("AS #sigma")))); - - if (draw) { - fFit->Draw("same"); - fPed->Draw("same"); - fGausAS->Draw("same"); - fGausNS->Draw("same"); - pvStatTests1->Draw("same"); + if (fTypeOfFitFunc == 3 || fTypeOfFitFunc == 6) { + fFit->GetParameters(par); + fFit->SetLineWidth(4); + + fPed->SetParameter(0, par[0]); + fPed->SetLineColor(6); // pink + fPed->SetLineStyle(9); + fPed->SetLineWidth(4); + + fGausAS->SetParameter(0, par[1]); + fGausAS->SetParameter(1, par[2]); + fGausAS->SetParameter(2, par[3]); + + fGausAS->SetLineStyle(9); + fGausAS->SetLineColor(kGreen); + fGausAS->SetLineWidth(4); + + auto* pvStatTests1 = new TPaveText(0.51, 0.58, 0.85, 0.90, "NDC"); + pvStatTests1->SetFillStyle(0); + pvStatTests1->SetTextSize(0.045); + pvStatTests1->SetBorderSize(0); + // TText *t0, *t1, *t2, *t3; + // t0 = pvStatTests1->AddText(0., 1.00, Form("#chi^{2}/ndf = %.1f/%d ", fFit->GetChisquare(), fFit->GetNDF())); + // t1 = pvStatTests1->AddText(0., 0.80, Form("Ped = %.3f#pm%.3f ", fBaseline, fErrBaseline)); + // t2 = pvStatTests1->AddText(0., 0.65, Form("AS Y = %.3f#pm%.3f ", fFit->GetParameter("AS Y"), fFit->GetParError(fFit->GetParNumber("AS Y")))); + // t3 = pvStatTests1->AddText(0., 0.50, Form("AS #sigma = %.3f#pm%.3f ", fFit->GetParameter("AS #sigma"), fFit->GetParError(fFit->GetParNumber("AS #sigma")))); + + if (draw) { + fFit->Draw("same"); + fPed->Draw("same"); + fGausAS->Draw("same"); + pvStatTests1->Draw("same"); + } + } else if (fTypeOfFitFunc == 4) { + fFit->GetParameters(par); + fFit->SetLineWidth(4); + + fPed->SetParameter(0, par[0]); + fPed->SetLineColor(6); // pink + fPed->SetLineStyle(9); + fPed->SetLineWidth(4); + + fGausNS->SetParameter(0, par[1]); + fGausNS->SetParameter(1, par[2]); + fGausNS->SetParameter(2, par[3]); + fGausNS->SetParameter(3, par[7]); + fGausAS->SetParameter(0, par[4]); + fGausAS->SetParameter(1, par[5]); + fGausAS->SetParameter(2, par[6]); + + fGausNS->SetLineStyle(9); + fGausNS->SetLineColor(kBlue); + fGausAS->SetLineStyle(9); + fGausAS->SetLineColor(kGreen); + fGausNS->SetLineWidth(4); + fGausAS->SetLineWidth(4); + + auto* pvStatTests1 = new TPaveText(0.51, 0.58, 0.85, 0.90, "NDC"); + pvStatTests1->SetFillStyle(0); + pvStatTests1->SetTextSize(0.045); + pvStatTests1->SetBorderSize(0); + // TText *t0, *t1, *t2, *t3, *t4, *t5, *t6; + // t0 = pvStatTests1->AddText(0., 1.00, Form("#chi^{2}/ndf = %.1f/%d ", fFit->GetChisquare(), fFit->GetNDF())); + // t1 = pvStatTests1->AddText(0., 0.80, Form("Ped = %.3f#pm%.3f ", fBaseline, fErrBaseline)); + // t2 = pvStatTests1->AddText(0., 0.65, Form("NS Y = %.3f#pm%.3f ", fFit->GetParameter("NS Y"), fFit->GetParError(fFit->GetParNumber("NS Y")))); + // t3 = pvStatTests1->AddText(0., 0.50, Form("NS #sigma = %.3f#pm%.3f ", fFit->GetParameter("NS #sigma"), fFit->GetParError(fFit->GetParNumber("NS #sigma")))); + // t4 = pvStatTests1->AddText(0., 0.35, Form("AS Y = %.3f#pm%.3f ", fFit->GetParameter("AS Y"), fFit->GetParError(fFit->GetParNumber("AS Y")))); + // t5 = pvStatTests1->AddText(0., 0.20, Form("AS #sigma = %.3f#pm%.3f ", fFit->GetParameter("AS #sigma"), fFit->GetParError(fFit->GetParNumber("AS #sigma")))); + // t6 = pvStatTests1->AddText(0., 0.05, Form("#beta = %.3f#pm%.3f ", fFit->GetParameter("NS shape par"), fFit->GetParError(fFit->GetParNumber("NS shape par")))); + + if (draw) { + fFit->Draw("same"); + fPed->Draw("same"); + fGausAS->Draw("same"); + fGausNS->Draw("same"); + pvStatTests1->Draw("same"); + } + } else if (fTypeOfFitFunc == 7) { + fFit->GetParameters(par); + fFit->SetLineWidth(4); + + fBaseTransvReg->SetLineColor(15); + fBaseTransvReg->SetLineStyle(9); + fBaseTransvReg->SetLineWidth(4); + + fPed->SetParameter(0, par[0]); + fPed->SetParameter(1, par[7]); + fPed->SetParameter(2, par[8]); + fPed->SetLineColor(6); // pink + fPed->SetLineStyle(9); + fPed->SetLineWidth(4); + + fGausNS->SetParameter(0, par[1]); + fGausNS->SetParameter(1, par[2]); + fGausNS->SetParameter(2, par[3]); + // fGausNS -> SetParameter(3, par[7]); + fGausAS->SetParameter(0, par[4]); + fGausAS->SetParameter(1, par[5]); + fGausAS->SetParameter(2, par[6]); + + fGausNS->SetLineStyle(9); + fGausNS->SetLineColor(kBlue); + fGausAS->SetLineStyle(9); + fGausAS->SetLineColor(kGreen); + fGausNS->SetLineWidth(4); + fGausAS->SetLineWidth(4); + + auto* pvStatTests1 = new TPaveText(0.51, 0.58, 0.85, 0.90, "NDC"); + pvStatTests1->SetFillStyle(0); + pvStatTests1->SetTextSize(0.045); + pvStatTests1->SetBorderSize(0); + // TText *t0, *t1, *t2, *t3, *t4, *t5, *t6, *t7, *t8; + // t0 = pvStatTests1->AddText(0., 1.00, Form("#chi^{2}/ndf = %.1f/%d ", fFit->GetChisquare(), fFit->GetNDF())); + // t2 = pvStatTests1->AddText(0., 0.80, Form("NS Y = %.3f#pm%.3f ", fFit->GetParameter("NS Y"), fFit->GetParError(fFit->GetParNumber("NS Y")))); + // t3 = pvStatTests1->AddText(0., 0.65, Form("NS #sigma = %.3f#pm%.3f ", fFit->GetParameter("NS #sigma"), fFit->GetParError(fFit->GetParNumber("NS #sigma")))); + // t4 = pvStatTests1->AddText(0., 0.50, Form("AS Y = %.3f#pm%.3f ", fFit->GetParameter("AS Y"), fFit->GetParError(fFit->GetParNumber("AS Y")))); + // t5 = pvStatTests1->AddText(0., 0.35, Form("AS #sigma = %.3f#pm%.3f ", fFit->GetParameter("AS #sigma"), fFit->GetParError(fFit->GetParNumber("AS #sigma")))); + // t6 = pvStatTests1 -> AddText(0., 0.20, Form("#beta = %.3f#pm%.3f ", fFit -> GetParameter("NS shape par"), fFit -> GetParError(fFit->GetParNumber("NS shape par")))); + + auto* pvStatTests2 = new TPaveText(0.51, 0.28, 0.85, 0.60, "NDC"); + pvStatTests2->SetFillStyle(0); + pvStatTests2->SetTextSize(0.045); + pvStatTests2->SetBorderSize(0); + // t1 = pvStatTests2->AddText(0., 1.00, Form("Ped = %.3f#pm%.3f ", fFit->GetParameter("ped"), fErrBaseline /*fFit -> GetParError(fFit->GetParNumber("ped")*/)); + // t7 = pvStatTests2->AddText(0., 0.65, Form("v_{2}^{hadron} = %.3f#pm%.3f ", fFit->GetParameter("v_{2} hadron"), fFit->GetParError(fFit->GetParNumber("v_{2} hadron")))); + // t8 = pvStatTests2->AddText(0., 0.35, Form("v_{2}^{D} = %.3f#pm%.3f ", fFit->GetParameter("v_{2} D meson"), fFit->GetParError(fFit->GetParNumber("v_{2} D meson")))); + + if (draw) { + fFit->Draw("same"); + fPed->Draw("same"); + fBaseTransvReg->Draw("same"); + fGausAS->Draw("same"); + fGausNS->Draw("same"); + pvStatTests1->Draw("same"); + pvStatTests2->Draw("same"); + } + } else { + fFit->GetParameters(par); + fFit->SetLineWidth(4); + + fPed->SetParameter(0, par[0]); + fPed->SetLineColor(6); // pink + fPed->SetLineStyle(9); + fPed->SetLineWidth(4); + + fGausNS->SetParameter(0, par[1]); + fGausNS->SetParameter(1, par[2]); + fGausNS->SetParameter(2, par[3]); + fGausAS->SetParameter(0, par[4]); + fGausAS->SetParameter(1, par[5]); + fGausAS->SetParameter(2, par[6]); + + fGausNS->SetLineStyle(9); + fGausNS->SetLineColor(kBlue); + fGausAS->SetLineStyle(9); + fGausAS->SetLineColor(kGreen); + fGausNS->SetLineWidth(4); + fGausAS->SetLineWidth(4); + + auto* pvStatTests1 = new TPaveText(0.51, 0.58, 0.85, 0.90, "NDC"); + pvStatTests1->SetFillStyle(0); + pvStatTests1->SetTextSize(0.045); + pvStatTests1->SetBorderSize(0); + // TText *t0, *t1, *t2, *t3, *t4, *t5, *t6; + // t0 = pvStatTests1->AddText(0., 1.00, Form("#chi^{2}/ndf = %.1f/%d ", fFit->GetChisquare(), fFit->GetNDF())); + // t1 = pvStatTests1->AddText(0., 0.80, Form("Ped = %.3f#pm%.3f ", fBaseline, fErrBaseline)); + // t2 = pvStatTests1->AddText(0., 0.65, Form("NS Y = %.3f#pm%.3f ", fFit->GetParameter("NS Y"), fFit->GetParError(fFit->GetParNumber("NS Y")))); + // t3 = pvStatTests1->AddText(0., 0.50, Form("NS #sigma = %.3f#pm%.3f ", fFit->GetParameter("NS #sigma"), fFit->GetParError(fFit->GetParNumber("NS #sigma")))); + // t4 = pvStatTests1->AddText(0., 0.35, Form("AS Y = %.3f#pm%.3f ", fFit->GetParameter("AS Y"), fFit->GetParError(fFit->GetParNumber("AS Y")))); + // t5 = pvStatTests1->AddText(0., 0.20, Form("AS #sigma = %.3f#pm%.3f ", fFit->GetParameter("AS #sigma"), fFit->GetParError(fFit->GetParNumber("AS #sigma")))); + + if (draw) { + fFit->Draw("same"); + fPed->Draw("same"); + fGausAS->Draw("same"); + fGausNS->Draw("same"); + pvStatTests1->Draw("same"); + } } + delete[] par; } diff --git a/PWGHF/HFC/Macros/DhCorrelationFitter.h b/PWGHF/HFC/Macros/DhCorrelationFitter.h index 83734f44257..692ff6a0ad5 100644 --- a/PWGHF/HFC/Macros/DhCorrelationFitter.h +++ b/PWGHF/HFC/Macros/DhCorrelationFitter.h @@ -17,17 +17,24 @@ #ifndef PWGHF_HFC_MACROS_DHCORRELATIONFITTER_H_ #define PWGHF_HFC_MACROS_DHCORRELATIONFITTER_H_ -#include -#include -#include -#include +#include +#include + +#include + +#include class DhCorrelationFitter { public: enum FunctionType { kConstwoGaus = 1, - kTwoGausPeriodicity = 2 }; + kTwoGausPeriodicity = 2, + kSingleGaus = 3, + kGenGaus = 4, + kVonMises = 5, + kSingleVonMises = 6, + kTwoGausPeriodicityPlusV2modulation = 7 }; /// Constructors DhCorrelationFitter(); @@ -37,53 +44,67 @@ class DhCorrelationFitter DhCorrelationFitter& operator=(const DhCorrelationFitter& cfit); /// Setters - void SetHistoIsReflected(Bool_t isrefl) { fIsReflected = isrefl; } - void SetFuncType(FunctionType fitType) { fTypeOfFitFunc = fitType; } - void SetFixBaseline(Int_t fixBase) { fFixBase = fixBase; } - void SetFixMean(Int_t fixMean) { fFixMean = fixMean; } - void SetPtRanges(Double_t PtCandMin, Double_t PtCandMax, Double_t PtAssocMin, Double_t PtAssocMax) + void setHistoIsReflected(Bool_t isrefl) { fIsReflected = isrefl; } + void setFuncType(FunctionType fitType) { fTypeOfFitFunc = fitType; } + void setFixBaseline(Int_t fixBase) { fFixBase = fixBase; } + void setFixMean(Int_t fixMean) { fFixMean = fixMean; } + void setPtRanges(Double_t ptCandMin, Double_t ptCandMax, Double_t ptAssocMin, Double_t ptAssocMax) + { + fMinCandPt = ptCandMin; + fMaxCandPt = ptCandMax; + fMinAssoPt = ptAssocMin; + fMaxAssoPt = ptAssocMax; + } + void setExternalValsAndBounds(Int_t nPars, const Double_t* vals, const Double_t* lowBounds, const Double_t* uppBounds); + void setPointsForBaseline(Int_t nBaselinePoints, const Int_t* binsBaseline); + void setReflectedCorrHisto(Bool_t isReflected) { fIsTotal = !isReflected; } + void setBaselineUpOrDown(Bool_t baseUp, Bool_t baseDown) + { + fShiftBaselineUp = baseUp; + fShiftBaselineDown = baseDown; + } + void setv2(Double_t v2AssocPart, Double_t v2Dmeson) { - fMinCandPt = PtCandMin; - fMaxCandPt = PtCandMax; - fMinAssoPt = PtAssocMin; - fMaxAssoPt = PtAssocMax; + fv2AssocPart = v2AssocPart; + fv2Dmeson = v2Dmeson; } - void SetExternalValsAndBounds(Int_t nPars, Double_t* vals, Double_t* lowBounds, Double_t* uppBounds); - void SetPointsForBaseline(Int_t nBaselinePoints, Int_t* binsBaseline); /// Functions for fitting - void Fitting(Bool_t drawSplitTerm = kTRUE, Bool_t useExternalPars = kFALSE); - void SetFitFunction(); - void CalculateYieldsAboveBaseline(); - void SetSingleTermsForDrawing(Bool_t draw); - Double_t FindBaseline(); + void fitting(Bool_t drawSplitTerm = kTRUE, Bool_t useExternalPars = kFALSE); + void setFitFunction(); + void calculateYieldsAboveBaseline(); + void fitBaselineWv2(); + Double_t calculateBaseline(TH1F*& histo, Bool_t totalRange = kTRUE); + Double_t calculateBaselineError(TH1F*& histo, Bool_t totalRange = kTRUE); + void setSingleTermsForDrawing(Bool_t draw); + Double_t findBaseline(); /// Getters - Double_t GetNSSigma() { return fFit->GetParameter("NS #sigma"); } // TODO: case kConstThreeGausPeriodicity - Double_t GetASSigma() { return fFit->GetParameter("AS #sigma"); } // TODO: case kConstThreeGausPeriodicity - Double_t GetNSYield() { return fFit->GetParameter("NS Y"); } - Double_t GetASYield() { return fFit->GetParameter("AS Y"); } - Double_t GetBeta() { return fFit->GetParameter(7); } - Double_t GetPedestal() { return fBaseline; } - Double_t Getv2hadron() { return fFit->GetParameter("v_{2} hadron"); } - Double_t Getv2Dmeson() { return fFit->GetParameter("v_{2} D meson"); } - Double_t GetNSSigmaError() { return fFit->GetParError(fFit->GetParNumber("NS #sigma")); } // TODO: case kConstThreeGausPeriodicity - Double_t GetASSigmaError() { return fFit->GetParError(fFit->GetParNumber("AS #sigma")); } // TODO: case kConstThreeGausPeriodicityAS - Double_t GetNSYieldError() { return fFit->GetParError(fFit->GetParNumber("NS Y")); } - Double_t GetASYieldError() { return fFit->GetParError(fFit->GetParNumber("AS Y")); } - Double_t GetBetaError() { return fFit->GetParError(7); } - Double_t GetPedestalError() { return fErrBaseline; } - Double_t Getv2hadronError() { return fFit->GetParError(fFit->GetParNumber("v_{2} hadron")); } - Double_t Getv2DmesonError() { return fFit->GetParError(fFit->GetParNumber("v_{2} D meson")); } - Double_t GetBinCountingNSYield() { return fNSyieldBinCount; } - Double_t GetBinCountingASYield() { return fASyieldBinCount; } - Double_t GetBinCountingNSYieldErr() { return fErrNSyieldBinCount; } - Double_t GetBinCountingASYieldErr() { return fErrASyieldBinCount; } - TF1* GetFitFunction() + Double_t getNsSigma() { return fFit->GetParameter("NS #sigma"); } // TODO: case kConstThreeGausPeriodicity + Double_t getAsSigma() { return fFit->GetParameter("AS #sigma"); } // TODO: case kConstThreeGausPeriodicity + Double_t getNsYield() { return fFit->GetParameter("NS Y"); } + Double_t getAsYield() { return fFit->GetParameter("AS Y"); } + Double_t getBeta() { return fFit->GetParameter(7); } + [[nodiscard]] Double_t getPedestal() const { return fBaseline; } + Double_t getv2hadron() { return fFit->GetParameter("v_{2} hadron"); } + Double_t getv2Dmeson() { return fFit->GetParameter("v_{2} D meson"); } + Double_t getNsSigmaError() { return fFit->GetParError(fFit->GetParNumber("NS #sigma")); } // TODO: case kConstThreeGausPeriodicity + Double_t getAsSigmaError() { return fFit->GetParError(fFit->GetParNumber("AS #sigma")); } // TODO: case kConstThreeGausPeriodicityAS + Double_t getNsYieldError() { return fFit->GetParError(fFit->GetParNumber("NS Y")); } + Double_t getAsYieldError() { return fFit->GetParError(fFit->GetParNumber("AS Y")); } + Double_t getBetaError() { return fFit->GetParError(7); } + [[nodiscard]] Double_t getPedestalError() const { return fErrBaseline; } + Double_t getv2hadronError() { return fFit->GetParError(fFit->GetParNumber("v_{2} hadron")); } + Double_t getv2DmesonError() { return fFit->GetParError(fFit->GetParNumber("v_{2} D meson")); } + [[nodiscard]] Double_t getBinCountingNsYield() const { return fNSyieldBinCount; } + [[nodiscard]] Double_t getBinCountingAsYield() const { return fASyieldBinCount; } + [[nodiscard]] Double_t getBinCountingNsYieldErr() const { return fErrNSyieldBinCount; } + [[nodiscard]] Double_t getBinCountingAsYieldErr() const { return fErrASyieldBinCount; } + TF1* getFitFunction() { - if (!fFit) { + if (fFit == nullptr) { printf("[ERROR] DhCorrelationFitter::GetFitFunction, No fit function"); - return NULL; + return nullptr; } return fFit; } @@ -91,13 +112,17 @@ class DhCorrelationFitter private: TH1F* fHist; // 1D azimuthal correlation histogram - TF1* fFit; // Total fit function - TF1* fGausNS; // Near-Side (NS) Gaussian - TF1* fGausAS; // Away-Side (AS) Gaussian - TF1* fPed; // Baseline function + TF1* fFit; // Total fit function + TF1* fGausNS; // Near-Side (NS) Gaussian + TF1* fGausAS; // Away-Side (AS) Gaussian + TF1* fPed; // Baseline function + TF1* fBaseTransvReg; // Baseline function with v2 - Bool_t fIsReflected; - Bool_t fUseExternalPars; // To use external fit parameters initial values and bounds + Bool_t fIsReflected; // To use if reflected azimuthal correlation are given as input + Bool_t fUseExternalPars; // To use external fit parameters initial values and bounds + Bool_t fShiftBaselineUp; // To shift the baseline up of its statistical uncertainty + Bool_t fShiftBaselineDown; // To shift baseline down of its statistical uncertainty + Bool_t fIsTotal; // Total range of 2*pi in the azimuthal correlation distribution FunctionType fTypeOfFitFunc; // Type of fit function @@ -120,6 +145,8 @@ class DhCorrelationFitter Double_t fErrNSyieldBinCount; // NS Yield error from bin counting Double_t fASyieldBinCount; // AS Yield from bin counting Double_t fErrASyieldBinCount; // AS Yield error from bin counting + Double_t fv2AssocPart; // v2 associated particles + Double_t fv2Dmeson; // v2 of D mesons Double_t* fExtParsVals; // Fit parameters initial values Double_t* fExtParsLowBounds; // Fit parameters lower bounds diff --git a/PWGHF/HFC/Macros/ExtractOutputCorrel.C b/PWGHF/HFC/Macros/ExtractOutputCorrel.C index f13116bffd6..db8dc9158d5 100644 --- a/PWGHF/HFC/Macros/ExtractOutputCorrel.C +++ b/PWGHF/HFC/Macros/ExtractOutputCorrel.C @@ -9,34 +9,45 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file ExtractOutputCorrel.C -/// \brief Macro to perform the correlation extraction +/// \file DhCorrelationExtraction.cxx +/// \brief class for D-h correlation extraction /// \usage .L DhCorrelationExtraction.cxx+ /// \usage .x ExtractOutputCorrel.C("config-file-name") /// \author Samuele Cattaruzzi /// \author Swapnesh Santosh Khade -#include "Riostream.h" +#include "DhCorrelationExtraction.h" + +#include #include +#include #include +#include + #include #include -#include "DhCorrelationExtraction.h" + +#include + +#include +#include +#include +#include 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++) { + for (const auto* it = jsonArray.Begin(); it != jsonArray.End(); it++) { auto value = it->template Get(); output.emplace_back(value); } } -void parseStringArray(const Value& jsonArray, vector& output) +void parseStringArray(const Value& jsonArray, std::vector& output) { - size_t arrayLength = jsonArray.Size(); + size_t const arrayLength = jsonArray.Size(); for (size_t i = 0; i < arrayLength; i++) { if (jsonArray[i].IsString()) { output.emplace_back(jsonArray[i].GetString()); @@ -44,10 +55,13 @@ 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 setInputCorrelNames(DhCorrelationExtraction* plotter, TString pathFileSE, TString pathFileME, TString dirSE, TString dirME, TString histoNameCorrSignal, TString histoNameCorrSideba, TString histoNameCorrSidebaLeft, TString histoNameCorrSidebaRight); +void setInputHistoInvMassNames(DhCorrelationExtraction* plotter, TString pathFileMass, std::vector inputMassNames); +void setInputHistoFdSubtraction(DhCorrelationExtraction* plotter, TString pathFileFDTemplate, TString pathFileFDPromptFrac, TString histoNameFDTemplatePrompt, TString histoNameFDTemplateNonPrompt, TString histoNameRawFracPrompt); +void setInputHistoSecPart(DhCorrelationExtraction* plotter, TString pathFileSecPart, TString dirSecPartName, TString histoNamePrimaryPart, TString histoNameAllPart); +void setInputHistoBiasBtoD(DhCorrelationExtraction* plotter, TString pathfFilePromptMcRec, TString pathfFileNonPromptMcRec); -void ExtractOutputCorrel(TString cfgFileName = "config_CorrAnalysis.json") +void extractOutputCorrelDs(const TString cfgFileName = "config_CorrAnalysis.json") { // gStyle -> SetOptStat(0); gStyle->SetPadLeftMargin(0.15); @@ -65,47 +79,75 @@ void ExtractOutputCorrel(TString cfgFileName = "config_CorrAnalysis.json") config.ParseStream(is); fclose(configFile); - string CodeNameAnalysis = config["CodeName"].GetString(); - gSystem->Exec(Form("rm -rf Output_CorrelationExtraction_%s_Root/ Output_CorrelationExtraction_%s_png/", CodeNameAnalysis.data(), CodeNameAnalysis.data())); - gSystem->Exec(Form("mkdir Output_CorrelationExtraction_%s_Root/ Output_CorrelationExtraction_%s_png/", CodeNameAnalysis.data(), CodeNameAnalysis.data())); - - string pathFileSE = config["pathFileSE"].GetString(); - string pathFileME = config["pathFileME"].GetString(); - string pathFileMass = config["pathFileMass"].GetString(); - - string dirSE = config["InputDirSE"].GetString(); - string dirME = config["InputDirME"].GetString(); - string histoNameCorrSignal = config["InputHistoCorrSignalName"].GetString(); - string histoNameCorrSideba = config["InputHistoCorrSidebaName"].GetString(); - - vector InputHistoMassName; + std::string codeNameAnalysis = config["CodeName"].GetString(); + gSystem->Exec(Form("rm -rf Output_CorrelationExtraction_%s_Root/ Output_CorrelationExtraction_%s_png/", codeNameAnalysis.data(), codeNameAnalysis.data())); + gSystem->Exec(Form("mkdir Output_CorrelationExtraction_%s_Root/ Output_CorrelationExtraction_%s_png/", codeNameAnalysis.data(), codeNameAnalysis.data())); + + std::string const pathFileSE = config["pathFileSE"].GetString(); + std::string const pathFileME = config["pathFileME"].GetString(); + std::string const pathFileMass = config["pathFileMass"].GetString(); + std::string const pathFileFDTemplate = config["pathFileFDTemplate"].GetString(); + std::string const pathFileFDPromptFrac = config["pathFileFDPromptFrac"].GetString(); + std::string const pathFileSecPart = config["pathFileSecPart"].GetString(); + std::string const pathfFilePromptMcRec = config["pathfFilePromptMcRec"].GetString(); + std::string const pathfFileNonPromptMcRec = config["pathfFileNonPromptMcRec"].GetString(); + + std::string const dirSE = config["InputDirSE"].GetString(); + std::string const dirME = config["InputDirME"].GetString(); + std::string const dirSecPart = config["InputDirSecPart"].GetString(); + std::string const histoNameCorrSignal = config["InputHistoCorrSignalName"].GetString(); + std::string const histoNameCorrSideba = config["InputHistoCorrSidebaName"].GetString(); + std::string const histoNameCorrSidebaLeft = config["InputHistoCorrSidebaLeftName"].GetString(); + std::string const histoNameCorrSidebaRight = config["InputHistoCorrSidebaRightName"].GetString(); + std::string const histoNameFDTemplatePrompt = config["InputHistoFDTemplatePrompt"].GetString(); + std::string const histoNameFDTemplateNonPrompt = config["InputHistoFDTemplateNonPrompt"].GetString(); + std::string const histoNameRawFracPrompt = config["InputHistoFDPromptFrac"].GetString(); + std::string const histoNamePrimaryPart = config["InputHistoPrimaryPart"].GetString(); + std::string const histoNameAllPart = config["InputHistoAllPart"].GetString(); + + std::vector inputHistoMassName; const Value& inputMassNames = config["InputHistoMassName"]; - parseStringArray(inputMassNames, InputHistoMassName); + parseStringArray(inputMassNames, inputHistoMassName); - cout << InputHistoMassName[0].data() << endl; - cout << InputHistoMassName[1].data() << endl; - cout << InputHistoMassName[2].data() << endl; + std::cout << inputHistoMassName[0].data() << std::endl; + std::cout << inputHistoMassName[1].data() << std::endl; + std::cout << inputHistoMassName[2].data() << std::endl; - vector binsPtCandIntervals; - vector binsPtHadIntervals; - vector deltaEtaInterval; + std::vector binsPtCandIntervals; + std::vector binsPtHadIntervals; + std::vector deltaEtaInterval; - const Value& PtCandValue = config["binsPtCandIntervals"]; - readArray(PtCandValue, binsPtCandIntervals); + const Value& ptCandValue = config["binsPtCandIntervals"]; + readArray(ptCandValue, binsPtCandIntervals); - const Value& PtHadValue = config["binsPtHadIntervals"]; - readArray(PtHadValue, binsPtHadIntervals); + const Value& ptHadValue = config["binsPtHadIntervals"]; + readArray(ptHadValue, binsPtHadIntervals); const Value& deltaEtaValue = config["deltaEtaInterval"]; readArray(deltaEtaValue, deltaEtaInterval); - double deltaEtaMin = deltaEtaInterval[0]; - double deltaEtaMax = deltaEtaInterval[1]; - - int specie = config["DmesonSpecie"].GetInt(); - - int npools = config["NumberOfPools"].GetInt(); - bool poolByPool = config["CorrectPoolsSeparately"].GetBool(); + double const deltaEtaMin = deltaEtaInterval[0]; + double const deltaEtaMax = deltaEtaInterval[1]; + + int const specie = config["DmesonSpecie"].GetInt(); + bool const rebinAngCorr = config["RebinAngCorr"].GetBool(); + bool const rebinFDCorr = config["RebinFDCorr"].GetBool(); + bool const rebinSecPart = config["RebinSecPart"].GetBool(); + int const rebinDeltaPhi = config["nRebinDeltaPhi"].GetInt(); + int const rebinDeltaEta = config["nRebinDeltaEta"].GetInt(); + + int const npools = config["NumberOfPools"].GetInt(); + bool const poolByPool = config["CorrectPoolsSeparately"].GetBool(); + bool const applySecPartCorr = config["ApplySecPartCorr"].GetBool(); + bool const applyBiasBtoDCorr = config["ApplyBiasBtoDCorr"].GetBool(); + bool const applyFDCorr = config["ApplyFDCorr"].GetBool(); + bool const isDividedSideb = config["IsDividedSideb"].GetBool(); + bool const useSidebLeft = config["UseSidebLeft"].GetBool(); + bool const useSidebRight = config["UseSidebRight"].GetBool(); + + if (useSidebLeft && useSidebRight) { + std::cout << "Using left and right" << std::endl; + } std::cout << "=========================== " << std::endl; std::cout << "Input variables from config" << std::endl; @@ -121,42 +163,78 @@ void ExtractOutputCorrel(TString cfgFileName = "config_CorrAnalysis.json") const int nBinsPtHad = binsPtHadIntervals.size() - 1; TH1D* hCorrectedCorrel[nBinsPtCand][nBinsPtHad]; + TH1D* hCorrectedCorrelBaselineSubtr[nBinsPtCand][nBinsPtHad]; + TH1D* hCorrectedCorrelReflected[nBinsPtCand][nBinsPtHad]; + TH1D* hCorrectedCorrelReflectedBaselineSubtr[nBinsPtCand][nBinsPtHad]; // Create and set the correlation plotter class - DhCorrelationExtraction* plotter = new DhCorrelationExtraction(); - - Bool_t flagSpecie = plotter->SetDmesonSpecie(static_cast(specie)); - plotter->SetNpools(npools); - plotter->SetCorrectPoolsSeparately(poolByPool); // kTRUE = pool.by-pool extraction and correction; kFALSE = merged ME pools - plotter->SetDeltaEtaRange(deltaEtaMin, deltaEtaMax); - plotter->SetSubtractSoftPiInMEdistr(kFALSE); - plotter->SetRebin2DcorrelHisto(2, 2); // Xaxis: deltaEta, Yaxis: deltaPhi - plotter->SetDebugLevel(1); - - if (!flagSpecie) - cout << "[ERROR] Wrong D meson flag" << endl; + auto* plotter = new DhCorrelationExtraction(); + + Bool_t const flagSpecie = plotter->setDmesonSpecie(static_cast(specie)); + plotter->setNpools(npools); + plotter->setCorrectPoolsSeparately(poolByPool); // kTRUE = pool.by-pool extraction and correction; kFALSE = merged ME pools + plotter->setFdSubtraction(applyFDCorr); + plotter->setSecPartContamination(applySecPartCorr); + plotter->setDeltaEtaRange(deltaEtaMin, deltaEtaMax); + plotter->setSubtractSoftPiInMEdistr(kFALSE); + plotter->setRebinOptions(rebinAngCorr, rebinFDCorr, rebinSecPart); + plotter->setRebin2DcorrelHisto(rebinDeltaEta, rebinDeltaPhi); // Xaxis: deltaEta, Yaxis: deltaPhi + plotter->setCorrBiasBtoD(applyBiasBtoDCorr); + plotter->setDebugLevel(1); + + if (!flagSpecie) { + std::cout << "[ERROR] Wrong D meson flag" << std::endl; + } // Set the input file config - SetInputCorrelNames(plotter, pathFileMass, pathFileSE, pathFileME, dirSE, dirME, histoNameCorrSignal, histoNameCorrSideba); - SetInputHistoInvMassNames(plotter, InputHistoMassName); - Bool_t readSEandME = plotter->ReadInputSEandME(); - Bool_t readInvMass = plotter->ReadInputInvMass(); - if (readSEandME) - cout << "Files SE and ME read correctly" << endl; - if (readInvMass) - cout << "Files inv. mass read correctly" << endl; + setInputCorrelNames(plotter, pathFileSE, pathFileME, dirSE, dirME, histoNameCorrSignal, histoNameCorrSideba, histoNameCorrSidebaLeft, histoNameCorrSidebaRight); + setInputHistoInvMassNames(plotter, pathFileMass, inputHistoMassName); + if (applyFDCorr) { + setInputHistoFdSubtraction(plotter, pathFileFDTemplate, pathFileFDPromptFrac, histoNameFDTemplatePrompt, histoNameFDTemplateNonPrompt, histoNameRawFracPrompt); + } + if (applySecPartCorr) { + setInputHistoSecPart(plotter, pathFileSecPart, dirSecPart, histoNamePrimaryPart, histoNameAllPart); + } + if (applyBiasBtoDCorr) { + setInputHistoBiasBtoD(plotter, pathfFilePromptMcRec, pathfFileNonPromptMcRec); + } + Bool_t const readSEandME = plotter->readInputSeAndMe(); + if (readSEandME) { + std::cout << "Files SE and ME read correctly" << std::endl; + } + Bool_t const readInvMass = plotter->readInputInvMass(); + if (readInvMass) { + std::cout << "Files inv. mass read correctly" << std::endl; + } + if (applyFDCorr) { + Bool_t const readFDSubtr = plotter->readInputFdSubtr(); + if (readFDSubtr) { + std::cout << "Files for FD subtr. read correctly" << std::endl; + } + } + if (applySecPartCorr) { + Bool_t const readSecPart = plotter->readInputSecondaryPartContamination(); + if (readSecPart) { + std::cout << "Files for secondary part. contamination read correctly" << std::endl; + } + } // Loop over candidate pt and assoc. particle pt for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { - plotter->GetSignalAndBackgroundForNorm(binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1]); + plotter->setDividedSidebands(isDividedSideb, useSidebLeft, useSidebRight); + plotter->getSignalAndBackgroundForNorm(binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1]); for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { - plotter->ExtractCorrelations(binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1], binsPtHadIntervals[iBinPtHad], binsPtHadIntervals[iBinPtHad + 1], CodeNameAnalysis); - hCorrectedCorrel[iBinPtCand][iBinPtHad] = reinterpret_cast(plotter->GetCorrectedCorrHisto()); + plotter->setBinCandAndHad(iBinPtCand + 1, iBinPtHad + 1); + plotter->extractCorrelations(binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1], binsPtHadIntervals[iBinPtHad], binsPtHadIntervals[iBinPtHad + 1], codeNameAnalysis); + hCorrectedCorrel[iBinPtCand][iBinPtHad] = plotter->getCorrectedCorrHisto(); + hCorrectedCorrelBaselineSubtr[iBinPtCand][iBinPtHad] = plotter->getCorrectedCorrHistoBaselineSubtr(); + hCorrectedCorrelReflected[iBinPtCand][iBinPtHad] = plotter->getCorrectedCorrHistoReflected(); + hCorrectedCorrelReflectedBaselineSubtr[iBinPtCand][iBinPtHad] = plotter->getCorrectedCorrHistoReflectedBaselineSubtr(); } } // output file - TFile* outFile = new TFile(Form("Output_CorrelationExtraction_%s_Root/ExtractCorrelationsResults.root", CodeNameAnalysis.data()), "RECREATE"); + auto* outFile = new TFile(Form("Output_CorrelationExtraction_%s_Root/ExtractCorrelationsResults.root", codeNameAnalysis.data()), "RECREATE"); outFile->cd(); for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { @@ -165,32 +243,84 @@ void ExtractOutputCorrel(TString cfgFileName = "config_CorrAnalysis.json") } outFile->Close(); - return; + // output file baseline subtr. + auto* outFileBaselineSubtr = new TFile(Form("Output_CorrelationExtraction_%s_Root/ExtractCorrelationsResults_BaselineSubtr.root", codeNameAnalysis.data()), "RECREATE"); + outFileBaselineSubtr->cd(); + for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { + for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { + hCorrectedCorrelBaselineSubtr[iBinPtCand][iBinPtHad]->Write(); + } + } + outFileBaselineSubtr->Close(); + + // output file reflected + auto* outFileReflected = new TFile(Form("Output_CorrelationExtraction_%s_Root/ExtractCorrelationsResults_Reflected.root", codeNameAnalysis.data()), "RECREATE"); + outFileReflected->cd(); + for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { + for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { + hCorrectedCorrelReflected[iBinPtCand][iBinPtHad]->Write(); + } + } + outFileReflected->Close(); + + // output file reflected baseline subtr. + auto* outFileReflectedBaselineSubtr = new TFile(Form("Output_CorrelationExtraction_%s_Root/ExtractCorrelationsResults_Reflected_BaselineSubtr.root", codeNameAnalysis.data()), "RECREATE"); + outFileReflectedBaselineSubtr->cd(); + for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { + for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { + hCorrectedCorrelReflectedBaselineSubtr[iBinPtCand][iBinPtHad]->Write(); + } + } + outFileReflectedBaselineSubtr->Close(); } -void SetInputCorrelNames(DhCorrelationExtraction* plotter, TString pathFileMass, TString pathFileSE, TString pathFileME, TString dirSE, TString dirME, TString histoNameCorrSignal, TString histoNameCorrSideba) +void setInputCorrelNames(DhCorrelationExtraction* plotter, TString pathFileSE, TString pathFileME, TString dirSE, TString dirME, TString histoNameCorrSignal, TString histoNameCorrSideba, TString histoNameCorrSidebaLeft, TString histoNameCorrSidebaRight) { - // paths - plotter->SetInputFilenameMass(pathFileMass.Data()); - plotter->SetInputFilenameSE(pathFileSE.Data()); - plotter->SetInputFilenameME(pathFileME.Data()); - plotter->SetDirNameSE(dirSE.Data()); - plotter->SetDirNameME(dirME.Data()); - plotter->SetSECorrelHistoSignalName(histoNameCorrSignal.Data()); - plotter->SetSECorrelHistoSidebandName(histoNameCorrSideba.Data()); - plotter->SetMECorrelHistoSignalName(histoNameCorrSignal.Data()); - plotter->SetMECorrelHistoSidebandName(histoNameCorrSideba.Data()); - - return; + // Ds paths + plotter->setInputFilenameSe(pathFileSE.Data()); + plotter->setInputFilenameMe(pathFileME.Data()); + plotter->setDirNameSe(dirSE.Data()); + plotter->setDirNameMe(dirME.Data()); + plotter->setSeCorrelHistoSignalName(histoNameCorrSignal.Data()); + plotter->setSeCorrelHistoSidebandName(histoNameCorrSideba.Data()); + plotter->setMeCorrelHistoSignalName(histoNameCorrSignal.Data()); + plotter->setMeCorrelHistoSidebandName(histoNameCorrSideba.Data()); + plotter->setSeCorrelHistoSidebandLeftName(histoNameCorrSidebaLeft.Data()); + plotter->setMeCorrelHistoSidebandLeftName(histoNameCorrSidebaLeft.Data()); + plotter->setSeCorrelHistoSidebandRightName(histoNameCorrSidebaRight.Data()); + plotter->setMeCorrelHistoSidebandRightName(histoNameCorrSidebaRight.Data()); } -void SetInputHistoInvMassNames(DhCorrelationExtraction* plotter, vector inputMassNames) +void setInputHistoInvMassNames(DhCorrelationExtraction* plotter, TString pathFileMass, std::vector inputMassNames) { // to use if sgn and bkg extraction is done apart - plotter->SetMassHistoNameSgn(inputMassNames[0].data()); - plotter->SetMassHistoNameBkg(inputMassNames[1].data()); - plotter->SetMassHistoNameSBs(inputMassNames[2].data()); + plotter->setInputFilenameMass(pathFileMass.Data()); + plotter->setMassHistoNameSgn(inputMassNames[0].data()); + plotter->setMassHistoNameBkg(inputMassNames[1].data()); + plotter->setMassHistoNameSBs(inputMassNames[2].data()); +} + +void setInputHistoFdSubtraction(DhCorrelationExtraction* plotter, TString pathFileFDTemplate, TString pathFileFDPromptFrac, TString histoNameFDTemplatePrompt, TString histoNameFDTemplateNonPrompt, TString histoNameRawFracPrompt) +{ + + plotter->setInputFilenameFdTemplate(pathFileFDTemplate.Data()); + plotter->setInputFilenameFdPromptFrac(pathFileFDPromptFrac.Data()); + plotter->setInputHistoNameFdTemplatePrompt(histoNameFDTemplatePrompt.Data()); + plotter->setInputHistoNameFdTemplateNonPrompt(histoNameFDTemplateNonPrompt.Data()); + plotter->setInputHistoNameFdPromptFrac(histoNameRawFracPrompt.Data()); +} + +void setInputHistoSecPart(DhCorrelationExtraction* plotter, TString pathFileSecPart, TString dirSecPartName, TString histoNamePrimaryPart, TString histoNameAllPart) +{ + + plotter->setInputFilenameSecPart(pathFileSecPart.Data()); + plotter->setDirNameSecPart(dirSecPartName.Data()); + plotter->setHistoSecPartName(histoNamePrimaryPart.Data(), histoNameAllPart.Data()); +} + +void setInputHistoBiasBtoD(DhCorrelationExtraction* plotter, TString pathfFilePromptMcRec, TString pathfFileNonPromptMcRec) +{ - return; + plotter->setInputFilenameBiasBtoD(pathfFilePromptMcRec.Data(), pathfFileNonPromptMcRec.Data()); } diff --git a/PWGHF/HFC/Macros/FitCorrel.C b/PWGHF/HFC/Macros/FitCorrel.C index 591933112c6..72461f06dc3 100644 --- a/PWGHF/HFC/Macros/FitCorrel.C +++ b/PWGHF/HFC/Macros/FitCorrel.C @@ -9,47 +9,68 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FitCorrel.C -/// \brief Macro to perform the azimuthal correlation fit -/// \usage .L DhCorrelationFitter.cxx+ -/// \usage .x FitCorrel.C("config-file-name") +/// \file DhCorrelationExtraction.cxx +/// \brief class for D-h correlation extraction /// \author Samuele Cattaruzzi /// \author Swapnesh Santosh Khade -#include "Riostream.h" -#include +#include "DhCorrelationFitter.h" + +#include +#include #include -#include +#include +#include #include #include -#include +#include +#include #include +#include +#include + #include #include -#include "DhCorrelationFitter.h" +#include +#include + +#include +#include +#include +#include + +using namespace std; using namespace rapidjson; +bool removeNSPeakLowPt = false; + template void readArray(const Value& jsonArray, vector& output) { - for (auto it = jsonArray.Begin(); it != jsonArray.End(); it++) { + for (const auto* it = jsonArray.Begin(); it != jsonArray.End(); it++) { auto value = it->template Get(); output.emplace_back(value); } } -void SetTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, +void setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, + Style_t markerStyle, Color_t markerColor, Double_t markerSize, + Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset = 1.3, Float_t hTitleYaxisOffset = 1.3, + Float_t hTitleXaxisSize = 0.045, Float_t hTitleYaxisSize = 0.045, Float_t hLabelXaxisSize = 0.045, Float_t hLabelYaxisSize = 0.045, + Bool_t centerXaxisTitle = false, Bool_t centerYaxisTitle = false); +void setTH1HistoStyle(TH1F*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, Style_t markerStyle, Color_t markerColor, Double_t markerSize, - Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset = 1., Float_t hTitleYaxisOffset = 1., - Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, + Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset = 1.3, Float_t hTitleYaxisOffset = 1.3, + Float_t hTitleXaxisSize = 0.045, Float_t hTitleYaxisSize = 0.045, Float_t hLabelXaxisSize = 0.045, Float_t hLabelYaxisSize = 0.045, Bool_t centerXaxisTitle = false, Bool_t centerYaxisTitle = false); -void FitCorrel(TString cfgFileName = "config_CorrAnalysis.json") +void fitCorrelDs(const TString cfgFileName = "config_CorrAnalysis.json") { gStyle->SetOptStat(0); - gStyle->SetPadLeftMargin(0.15); - gStyle->SetPadBottomMargin(0.15); + gStyle->SetPadLeftMargin(0.2); + gStyle->SetPadRightMargin(0.005); + gStyle->SetPadBottomMargin(0.2); gStyle->SetFrameLineWidth(2); gStyle->SetLineWidth(2); gStyle->SetCanvasDefH(1126); @@ -63,116 +84,379 @@ void FitCorrel(TString cfgFileName = "config_CorrAnalysis.json") config.ParseStream(is); fclose(configFile); - string CodeNameAnalysis = config["CodeName"].GetString(); - gSystem->Exec(Form("rm -rf Output_CorrelationFitting_%s_Root/ Output_CorrelationFitting_%s_png/", CodeNameAnalysis.data(), CodeNameAnalysis.data())); - gSystem->Exec(Form("mkdir Output_CorrelationFitting_%s_Root/ Output_CorrelationFitting_%s_png/", CodeNameAnalysis.data(), CodeNameAnalysis.data())); + string codeNameAnalysis = config["CodeName"].GetString(); + gSystem->Exec(Form("rm -rf Output_CorrelationFitting_%s_Root/ Output_CorrelationFitting_%s_png/", codeNameAnalysis.data(), codeNameAnalysis.data())); + gSystem->Exec(Form("mkdir Output_CorrelationFitting_%s_Root/ Output_CorrelationFitting_%s_png/", codeNameAnalysis.data(), codeNameAnalysis.data())); + + string inputFileNameFit = config["InputFileNameFitCorr"].GetString(); + const TString inFileName = Form("Output_CorrelationExtraction_%s_Root/%s", codeNameAnalysis.data(), inputFileNameFit.data()); - const TString inFileName = Form("Output_CorrelationExtraction_%s_Root/ExtractCorrelationsResults.root", CodeNameAnalysis.data()); + bool const isReflected = config["IsRiflected"].GetBool(); + bool const drawSystematicErrors = config["DrawSystematics"].GetBool(); + bool const sameSystematics = config["SameSystematics"].GetBool(); + bool const shiftBaseUp = config["ShiftBaseUp"].GetBool(); + bool const shiftBaseDown = config["ShiftBaseDown"].GetBool(); - vector binsPtCandIntervals; - vector binsPtHadIntervals; + std::vector binsPtCandIntervalsVec; + std::vector binsPtHadIntervals; + std::vector fitFunc; - const Value& PtCandValue = config["binsPtCandIntervals"]; - readArray(PtCandValue, binsPtCandIntervals); + const Value& ptCandValue = config["binsPtCandIntervals"]; + readArray(ptCandValue, binsPtCandIntervalsVec); - const Value& PtHadValue = config["binsPtHadIntervals"]; - readArray(PtHadValue, binsPtHadIntervals); + const Value& ptHadValue = config["binsPtHadIntervals"]; + readArray(ptHadValue, binsPtHadIntervals); - int fitFunc = config["FitFunction"].GetInt(); - int fixBase = config["FixBaseline"].GetInt(); - int fixMean = config["FixMean"].GetInt(); + const int nBinsPtCand = binsPtCandIntervalsVec.size() - 1; + const int nBinsPtHad = binsPtHadIntervals.size() - 1; + + double binsPtCandIntervals[nBinsPtCand + 1]; + for (int i = 0; i < nBinsPtCand + 1; i++) { + binsPtCandIntervals[i] = binsPtCandIntervalsVec[i]; + } + + const Value& fitFuncValue = config["FitFunction"]; + readArray(fitFuncValue, fitFunc); + + int const fixBase = config["FixBaseline"].GetInt(); + int const fixMean = config["FixMean"].GetInt(); + + int const nBaselinePoints = config["nBaselinePoints"].GetInt(); + vector pointsForBaselineVec; + const Value& pointsForBaselineValue = config["binsForBaseline"]; + readArray(pointsForBaselineValue, pointsForBaselineVec); + if (pointsForBaselineVec.size() != nBaselinePoints) { + cout << "ERROR: size of the vector pointsForBaseline is different from the number of nBaselinePoints" << endl; + return; + } + int pointsForBaseline[nBaselinePoints]; + for (int i = 0; i < nBaselinePoints; i++) { + pointsForBaseline[i] = pointsForBaselineVec[i]; + } std::cout << "=========================== " << std::endl; std::cout << "Input variables from config" << std::endl; - std::cout << "FitFunction = " << fitFunc << std::endl; + for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { + std::cout << "iPt = " << iBinPtCand + 1 << " FitFunction = " << fitFunc[iBinPtCand] << std::endl; + } std::cout << "FixBaseline = " << fixBase << std::endl; std::cout << "FixMean = " << fixMean << std::endl; std::cout << "=========================== " << std::endl; std::cout << " " << std::endl; // TODO: reflections - bool refl = false; - - const int nBinsPtCand = binsPtCandIntervals.size() - 1; - const int nBinsPtHad = binsPtHadIntervals.size() - 1; + bool const refl = false; // Input file - TFile* inFile = new TFile(inFileName.Data()); + auto* inFile = new TFile(inFileName.Data()); + auto* inFileSystematicErrors = new TFile("OutputSystematicUncertainties/SystematicUncertaintesAngCorrMerged.root"); + auto* inFileFitSystematicErrors = new TFile("OutputSystematicUncertainties/SystematicUncertaintesFitPhysObsMerged.root"); // Canvas - TCanvas* CanvasCorrPhi[nBinsPtHad]; + TCanvas* canvasCorrPhi[nBinsPtHad]; // Histograms TH1D* hCorrPhi[nBinsPtCand][nBinsPtHad]; + TH1F* hSystematicErrors[nBinsPtCand][nBinsPtHad]; + TH1D* hSystematicErrorsPlot[nBinsPtCand][nBinsPtHad]; - int nBinsPhi; - double baselineFromThreePoints[nBinsPtCand][nBinsPtHad], baselineFromThreePointsError[nBinsPtCand][nBinsPtHad]; + const int nBinsPtD = 5; + if (nBinsPtD != nBinsPtCand) { + std::cout << "[ERROR]: nBinsPtD != nBinsPtCand" << std::endl; + return; + } + double const systUncCorrelatedDs[nBinsPtD] = {20, 20, 20, 10}; // % (just the MC Closure uncertainty to put in the plot) // DhCorrelationFitter const double fMin{-0.5 * TMath::Pi()}, fMax{1.5 * TMath::Pi()}; // limits for the fitting function DhCorrelationFitter* corrFitter[nBinsPtHad][nBinsPtCand]; // Input parameters for fitting - const int npars{8}; // PED NSY NSM NSW ASY ASM ASW BETA - Double_t vals[npars] = {3., 2., 0., 0.5, 2., 3.14, 0.3, 2.}; - Double_t lowBounds[npars] = {0., 0., -1., 0., 0., 2., 0., 0.5}; - Double_t uppBounds[npars] = {9999., 999., 1., 3.14 / 3., 999., 4., 3.14 / 2., 3.5}; - - const int nBaselinePoints{8}; - Int_t pointsForBaseline[nBaselinePoints] = {1, 2, 13, 14, 15, 16, 31, 32}; + const int npars{10}; // PED NSY NSM NSW ASY ASM ASW BETA v2D v2h + const Double_t vals[npars] = {3., 2., 0., 0.5, 2., 3.14, 0.3, 2., 0.1, 0.1}; + const Double_t lowBounds[npars] = {0., 0., -1., 0., 0., 2., 0., 0.5, 0., 0.}; + const Double_t uppBounds[npars] = {9999., 999., 1., 3.14 / 3., 999., 4., 3.14 / 2., 3.5, 0.5, 0.5}; + const Double_t v2AssocPart[nBinsPtD] = {0.15, 0.15, 0.15, 0.15}; + const Double_t v2Dmeson[nBinsPtD] = {0.175, 0.09, 0.04, 0.04}; + + // Output histograms + TH1D* hBaselin[nBinsPtHad]; + TH1D* hNSYield[nBinsPtHad]; + TH1D* hNSSigma[nBinsPtHad]; + TH1D* hASYield[nBinsPtHad]; + TH1D* hASSigma[nBinsPtHad]; + TH1D* hBeta[nBinsPtHad]; + TH1D* hNSYieldBinCount[nBinsPtHad]; + TH1D* hASYieldBinCount[nBinsPtHad]; // extract TH1D and prepare fit for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { - hCorrPhi[iBinPtCand][iBinPtHad] = reinterpret_cast(inFile->Get(Form("hCorrectedCorr_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1], binsPtHadIntervals[iBinPtHad], binsPtHadIntervals[iBinPtHad + 1]))); - - corrFitter[iBinPtHad][iBinPtCand] = new DhCorrelationFitter(reinterpret_cast(hCorrPhi[iBinPtCand][iBinPtHad], fMin, fMax)); - corrFitter[iBinPtHad][iBinPtCand]->SetHistoIsReflected(refl); - corrFitter[iBinPtHad][iBinPtCand]->SetFuncType(static_cast(fitFunc)); - corrFitter[iBinPtHad][iBinPtCand]->SetFixBaseline(fixBase); - corrFitter[iBinPtHad][iBinPtCand]->SetPointsForBaseline(nBaselinePoints, pointsForBaseline); - - corrFitter[iBinPtHad][iBinPtCand]->SetFixMean(fixMean); - corrFitter[iBinPtHad][iBinPtCand]->SetPtRanges(binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1], binsPtHadIntervals[iBinPtHad], binsPtHadIntervals[iBinPtHad + 1]); - corrFitter[iBinPtHad][iBinPtCand]->SetExternalValsAndBounds(npars, vals, lowBounds, uppBounds); // these are starting points and limits... + if (isReflected) { + hCorrPhi[iBinPtCand][iBinPtHad] = reinterpret_cast(inFile->Get(Form("hCorrectedCorrReflected_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1], binsPtHadIntervals[iBinPtHad], binsPtHadIntervals[iBinPtHad + 1]))); + } else { + hCorrPhi[iBinPtCand][iBinPtHad] = reinterpret_cast(inFile->Get(Form("hCorrectedCorr_PtCand%.0fto%.0f_PtAssoc%.0fto%.0f", binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1], binsPtHadIntervals[iBinPtHad], binsPtHadIntervals[iBinPtHad + 1]))); + } + + corrFitter[iBinPtHad][iBinPtCand] = new DhCorrelationFitter(reinterpret_cast(hCorrPhi[iBinPtCand][iBinPtHad]), fMin, fMax); + corrFitter[iBinPtHad][iBinPtCand]->setHistoIsReflected(refl); + corrFitter[iBinPtHad][iBinPtCand]->setFixBaseline(fixBase); + corrFitter[iBinPtHad][iBinPtCand]->setBaselineUpOrDown(shiftBaseUp, shiftBaseDown); + corrFitter[iBinPtHad][iBinPtCand]->setPointsForBaseline(nBaselinePoints, pointsForBaseline); + corrFitter[iBinPtHad][iBinPtCand]->setv2(v2AssocPart[iBinPtCand], v2Dmeson[iBinPtCand]); + corrFitter[iBinPtHad][iBinPtCand]->setReflectedCorrHisto(isReflected); + + corrFitter[iBinPtHad][iBinPtCand]->setFixMean(fixMean); + corrFitter[iBinPtHad][iBinPtCand]->setPtRanges(binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1], binsPtHadIntervals[iBinPtHad], binsPtHadIntervals[iBinPtHad + 1]); + corrFitter[iBinPtHad][iBinPtCand]->setExternalValsAndBounds(npars, vals, lowBounds, uppBounds); // these are starting points and limits... } } // Plots and fit for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { - CanvasCorrPhi[iBinPtHad] = new TCanvas(Form("CanvasCorrPhi_PtBinAssoc%d", iBinPtHad + 1), Form("CorrPhiDs_PtBinAssoc%d", iBinPtHad + 1)); + canvasCorrPhi[iBinPtHad] = new TCanvas(Form("CanvasCorrPhi_PtBinAssoc%d", iBinPtHad + 1), Form("CorrPhiDs_PtBinAssoc%d", iBinPtHad + 1)); if (nBinsPtCand <= 4) { - CanvasCorrPhi[iBinPtHad]->Divide(2, 2); + canvasCorrPhi[iBinPtHad]->Divide(2, 2); } if (nBinsPtCand > 4 && nBinsPtCand <= 6) { - CanvasCorrPhi[iBinPtHad]->Divide(2, 3); + canvasCorrPhi[iBinPtHad]->Divide(3, 2); } - for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { - SetTH1HistoStyle(hCorrPhi[iBinPtCand][iBinPtHad], "", "#Delta#phi [rad]", "#frac{1}{N_{D_{s}}}#frac{dN^{assoc}}{d#Delta#phi} [rad^{-1}]", kFullCircle, kRed + 1, 1.4, kRed + 1, 3); + // histograms with fir parameters + hBaselin[iBinPtHad] = new TH1D(Form("hBaselin_PtBinAssoc%d", iBinPtHad + 1), "", nBinsPtCand, binsPtCandIntervals); + hNSYield[iBinPtHad] = new TH1D(Form("hNSYield_PtBinAssoc%d", iBinPtHad + 1), "", nBinsPtCand, binsPtCandIntervals); + hNSSigma[iBinPtHad] = new TH1D(Form("hNSSigma_PtBinAssoc%d", iBinPtHad + 1), "", nBinsPtCand, binsPtCandIntervals); + hASYield[iBinPtHad] = new TH1D(Form("hASYield_PtBinAssoc%d", iBinPtHad + 1), "", nBinsPtCand, binsPtCandIntervals); + hASSigma[iBinPtHad] = new TH1D(Form("hASSigma_PtBinAssoc%d", iBinPtHad + 1), "", nBinsPtCand, binsPtCandIntervals); + hBeta[iBinPtHad] = new TH1D(Form("hBeta_PtBinAssoc%d", iBinPtHad + 1), "", nBinsPtCand, binsPtCandIntervals); + hNSYieldBinCount[iBinPtHad] = new TH1D(Form("hNSYieldBinCount_PtBinAssoc%d", iBinPtHad + 1), "", nBinsPtCand, binsPtCandIntervals); + hASYieldBinCount[iBinPtHad] = new TH1D(Form("hASYieldBinCount_PtBinAssoc%d", iBinPtHad + 1), "", nBinsPtCand, binsPtCandIntervals); - CanvasCorrPhi[iBinPtHad]->cd(iBinPtCand + 1); - hCorrPhi[iBinPtCand][iBinPtHad]->Draw(); + for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { + setTH1HistoStyle(hCorrPhi[iBinPtCand][iBinPtHad], "", "#Delta#phi [rad]", "#frac{1}{N_{D_{s}}}#frac{dN^{assoc}}{d#Delta#phi} [rad^{-1}]", kFullCircle, kRed + 1, 1.4, kRed + 1, 3); + + canvasCorrPhi[iBinPtHad]->cd(iBinPtCand + 1); + canvasCorrPhi[iBinPtHad]->SetTickx(); + canvasCorrPhi[iBinPtHad]->SetTicky(); + hCorrPhi[iBinPtCand][iBinPtHad]->SetStats(false); + hCorrPhi[iBinPtCand][iBinPtHad]->SetMinimum(0); + // hCorrPhi[iBinPtCand][iBinPtHad] -> Draw(); + + // draw systematic errors + int const nBinsPhi = hCorrPhi[iBinPtCand][iBinPtHad]->GetNbinsX(); + if (drawSystematicErrors) { + hSystematicErrors[iBinPtCand][iBinPtHad] = reinterpret_cast(inFileSystematicErrors->Get(Form("hSystematicErrorsMerged_PtBin%d_PtBinAssoc%d", iBinPtCand + 1, iBinPtHad + 1))); + hSystematicErrorsPlot[iBinPtCand][iBinPtHad] = reinterpret_cast(hCorrPhi[iBinPtCand][iBinPtHad]->Clone(Form("hSystematicErrorsPlot_PtBin%d_PtBinAssoc%d", iBinPtCand + 1, iBinPtHad + 1))); + for (int iPhi = 0; iPhi < nBinsPhi; iPhi++) { + if (sameSystematics) { + hSystematicErrorsPlot[iBinPtCand][iBinPtHad]->SetBinError(iPhi + 1, hSystematicErrors[iBinPtCand][iBinPtHad]->GetBinContent(1) * hCorrPhi[iBinPtCand][iBinPtHad]->GetBinContent(iPhi + 1)); + } else { + hSystematicErrorsPlot[iBinPtCand][iBinPtHad]->SetBinError(iPhi + 1, hSystematicErrors[iBinPtCand][iBinPtHad]->GetBinContent(iPhi + 1) * hCorrPhi[iBinPtCand][iBinPtHad]->GetBinContent(iPhi + 1)); + } + hSystematicErrorsPlot[iBinPtCand][iBinPtHad]->SetBinContent(iPhi + 1, hCorrPhi[iBinPtCand][iBinPtHad]->GetBinContent(iPhi + 1)); + } + setTH1HistoStyle(hSystematicErrorsPlot[iBinPtCand][iBinPtHad], "", "#Delta#phi [rad]", "#frac{1}{N_{D_{s}}}#frac{dN^{assoc}}{d#Delta#phi} [rad^{-1}]", kFullCircle, kRed + 1, 1.4, kRed + 1, 2); + hSystematicErrorsPlot[iBinPtCand][iBinPtHad]->SetLineColor(kRed - 4); + hSystematicErrorsPlot[iBinPtCand][iBinPtHad]->SetFillStyle(0); + // hSystematicErrorsPlot[iBinPtCand][iBinPtHad] -> Draw("E2same"); + } + // hCorrPhi[iBinPtCand][iBinPtHad] -> Draw("same"); // Fit - corrFitter[iBinPtHad][iBinPtCand]->Fitting(kTRUE, kTRUE); // the first term is for drawing the fit functions, the second argument is useExternalParams + corrFitter[iBinPtHad][iBinPtCand]->setFuncType(static_cast(fitFunc[iBinPtCand])); + corrFitter[iBinPtHad][iBinPtCand]->fitting(kTRUE, kTRUE); // the first term is for drawing the fit functions, the second argument is useExternalParams - TF1* fFit = corrFitter[iBinPtHad][iBinPtCand]->GetFitFunction(); + TF1* fFit = corrFitter[iBinPtHad][iBinPtCand]->getFitFunction(); // Title of the histogram - TPaveText* pttext = new TPaveText(0.15, 0.9, 0.85, 0.95, "NDC"); + auto* pttext = new TPaveText(0.15, 0.9, 0.85, 0.95, "NDC"); pttext->SetFillStyle(0); pttext->SetBorderSize(0); - TText* tpT = pttext->AddText(0., 0.8, Form("%.0f < p_{T}^{D_{s}} < %.0f GeV/c, p_{T}^{assoc} > 0.3 GeV/c", binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1])); + TText* tpT = pttext->AddText(0., 0.8, Form("%.0f < p_{T}^{D_{s}} < %.0f GeV/c, p_{T}^{assoc} > %.1f GeV/c", binsPtCandIntervals[iBinPtCand], binsPtCandIntervals[iBinPtCand + 1], binsPtHadIntervals[iBinPtHad])); + // pttext -> Draw("same"); + + // Fill the histograms with the fit parameters + hBaselin[iBinPtHad]->SetBinContent(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getPedestal()); + hBaselin[iBinPtHad]->SetBinError(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getPedestalError()); + if (iBinPtCand == 0 && removeNSPeakLowPt) { + hNSYield[iBinPtHad]->SetBinContent(iBinPtCand + 1, -1); + hNSYield[iBinPtHad]->SetBinError(iBinPtCand + 1, 0); + + hNSSigma[iBinPtHad]->SetBinContent(iBinPtCand + 1, -1); + hNSSigma[iBinPtHad]->SetBinError(iBinPtCand + 1, 0); + + hBeta[iBinPtHad]->SetBinContent(iBinPtCand + 1, -1); + hBeta[iBinPtHad]->SetBinError(iBinPtCand + 1, 0); + } else { + hNSYield[iBinPtHad]->SetBinContent(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getNsYield()); + hNSYield[iBinPtHad]->SetBinError(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getNsYieldError()); + + if (fitFunc[iBinPtCand] != 5 && fitFunc[iBinPtCand] != 6) { + hNSSigma[iBinPtHad]->SetBinContent(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getNsSigma()); + hNSSigma[iBinPtHad]->SetBinError(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getNsSigmaError()); + } else { + hNSSigma[iBinPtHad]->SetBinContent(iBinPtCand + 1, TMath::Sqrt(1. / corrFitter[iBinPtHad][iBinPtCand]->getNsSigma())); + Double_t const errrel = corrFitter[iBinPtHad][iBinPtCand]->getNsSigmaError() / corrFitter[iBinPtHad][iBinPtCand]->getNsSigma() / 2.; + hNSSigma[iBinPtHad]->SetBinError(iBinPtCand + 1, errrel * TMath::Sqrt(1. / corrFitter[iBinPtHad][iBinPtCand]->getNsSigma())); + } + } + hNSYieldBinCount[iBinPtHad]->SetBinContent(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getBinCountingNsYield()); + hNSYieldBinCount[iBinPtHad]->SetBinError(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getBinCountingNsYieldErr()); + + hASYield[iBinPtHad]->SetBinContent(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getAsYield()); + hASYield[iBinPtHad]->SetBinError(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getAsYieldError()); + + hASYieldBinCount[iBinPtHad]->SetBinContent(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getBinCountingAsYield()); + hASYieldBinCount[iBinPtHad]->SetBinError(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getBinCountingAsYieldErr()); + if (fitFunc[iBinPtCand] != 5 && fitFunc[iBinPtCand] != 6) { + hASSigma[iBinPtHad]->SetBinContent(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getAsSigma()); + hASSigma[iBinPtHad]->SetBinError(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getAsSigmaError()); + } else { + hASSigma[iBinPtHad]->SetBinContent(iBinPtCand + 1, TMath::Sqrt(1. / corrFitter[iBinPtHad][iBinPtCand]->getAsSigma())); + Double_t const errrel = corrFitter[iBinPtHad][iBinPtCand]->getAsSigmaError() / corrFitter[iBinPtHad][iBinPtCand]->getAsSigma() / 2.; + hASSigma[iBinPtHad]->SetBinError(iBinPtCand + 1, errrel * TMath::Sqrt(1. / corrFitter[iBinPtHad][iBinPtCand]->getAsSigma())); + } + if (fitFunc[iBinPtCand] == 4) { // param beta for gen. gauss + hBeta[iBinPtHad]->SetBinContent(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getBeta()); + hBeta[iBinPtHad]->SetBinError(iBinPtCand + 1, corrFitter[iBinPtHad][iBinPtCand]->getBetaError()); + } + + // Draw + auto* tCorrUncDs = new TPaveText(0.413, 0.311, 0.877, 0.392, "NDC"); + tCorrUncDs->SetFillStyle(0); + tCorrUncDs->SetBorderSize(0); + tCorrUncDs->SetTextSize(0.05); + tCorrUncDs->SetTextFont(42); + tCorrUncDs->SetTextAlign(13); + tCorrUncDs->SetTextColor(kRed + 1); + tCorrUncDs->AddText(0., 0., Form("#splitline{+%.0f%%}{#minus%.0f%%}", systUncCorrelatedDs[iBinPtCand], systUncCorrelatedDs[iBinPtCand])); + + auto* tScaleUnc = new TPaveText(0.501, 0.292, 0.968, 0.372, "NDC"); + tScaleUnc->SetFillStyle(0); + tScaleUnc->SetBorderSize(0); + tScaleUnc->SetTextSize(0.05); + tScaleUnc->SetTextFont(42); + tScaleUnc->SetTextAlign(13); + tScaleUnc->SetTextColor(kBlack); + tScaleUnc->AddText(0., 0., "corr. unc."); + + if (drawSystematicErrors) { + hSystematicErrorsPlot[iBinPtCand][iBinPtHad]->Draw("E2same"); + } + hCorrPhi[iBinPtCand][iBinPtHad]->Draw("same"); pttext->Draw("same"); + if (drawSystematicErrors) { + tCorrUncDs->Draw("same"); + tScaleUnc->Draw("same"); + } } - CanvasCorrPhi[iBinPtHad]->SaveAs(Form("Output_CorrelationFitting_%s_png/CorrPhi_PtBinAssoc%d.png", CodeNameAnalysis.data(), iBinPtHad + 1)); - CanvasCorrPhi[iBinPtHad]->SaveAs(Form("Output_CorrelationFitting_%s_Root/CorrPhi_PtBinAssoc%d.root", CodeNameAnalysis.data(), iBinPtHad + 1)); + canvasCorrPhi[iBinPtHad]->SaveAs(Form("Output_CorrelationFitting_%s_png/CorrPhiDs_PtBinAssoc%d.png", codeNameAnalysis.data(), iBinPtHad + 1)); + canvasCorrPhi[iBinPtHad]->SaveAs(Form("Output_CorrelationFitting_%s_Root/CorrPhiDs_PtBinAssoc%d.root", codeNameAnalysis.data(), iBinPtHad + 1)); + } + + // histogram with fit parameter and errors + auto* outFile = new TFile(Form("Output_CorrelationFitting_%s_Root/CorrPhiDs_FinalPlots.root", codeNameAnalysis.data()), "RECREATE"); + outFile->cd(); + for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { + hBaselin[iBinPtHad]->Write(); + hNSYield[iBinPtHad]->Write(); + hNSSigma[iBinPtHad]->Write(); + hASYield[iBinPtHad]->Write(); + hASSigma[iBinPtHad]->Write(); + hBeta[iBinPtHad]->Write(); + hNSYieldBinCount[iBinPtHad]->Write(); + hASYieldBinCount[iBinPtHad]->Write(); } + outFile->Close(); - return; + // Draw plots + for (int iBinPtHad = 0; iBinPtHad < nBinsPtHad; iBinPtHad++) { + auto* c1 = new TCanvas(Form("NS_yield_PtAssoc%d", iBinPtHad + 1), Form("NS_yield_PtAssoc%d", iBinPtHad + 1)); + auto* c2 = new TCanvas(Form("AS_yield_PtAssoc%d", iBinPtHad + 1), Form("AS_yield_PtAssoc%d", iBinPtHad + 1)); + auto* c3 = new TCanvas(Form("NS_sigma_PtAssoc%d", iBinPtHad + 1), Form("AS_sigma_PtAssoc%d", iBinPtHad + 1)); + auto* c4 = new TCanvas(Form("AS_sigma_PtAssoc%d", iBinPtHad + 1), Form("AS_sigma_PtAssoc%d", iBinPtHad + 1)); + auto* c5 = new TCanvas(Form("Baseline_PtAssoc%d", iBinPtHad + 1), Form("Baseline_PtAssoc%d", iBinPtHad + 1)); + setTH1HistoStyle(hBaselin[iBinPtHad], Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "Baseline", kFullSquare, kBlue, 1.8, kBlue, 2); + setTH1HistoStyle(hNSYield[iBinPtHad], Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "Y^{NS}", kFullSquare, kRed, 1.8, kRed, 2); + setTH1HistoStyle(hASYield[iBinPtHad], Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "Y^{AS}", kFullSquare, kMagenta, 1.8, kMagenta, 2); + setTH1HistoStyle(hNSSigma[iBinPtHad], Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "#sigma_{NS}", kFullSquare, kOrange + 8, 1.8, kOrange + 8, 2); + setTH1HistoStyle(hASSigma[iBinPtHad], Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "#sigma_{AS}", kFullSquare, kViolet - 5, 1.8, kViolet - 5, 2); + c1->cd(); + hNSYield[iBinPtHad]->SetMinimum(0); + hNSYield[iBinPtHad]->Draw(); + c2->cd(); + hASYield[iBinPtHad]->SetMinimum(0); + hASYield[iBinPtHad]->Draw(); + c3->cd(); + hNSSigma[iBinPtHad]->SetMinimum(0); + hNSSigma[iBinPtHad]->Draw(); + c4->cd(); + hASSigma[iBinPtHad]->SetMinimum(0); + hASSigma[iBinPtHad]->Draw(); + c5->cd(); + hBaselin[iBinPtHad]->SetMinimum(0); + hBaselin[iBinPtHad]->Draw(); + + if (drawSystematicErrors) { + TH1F* hBaselinSyst = reinterpret_cast(inFileFitSystematicErrors->Get(Form("hSystematicErrorsBaselinMerged_PtBinAssoc%d", iBinPtHad + 1))); + TH1F* hNSYieldSyst = reinterpret_cast(inFileFitSystematicErrors->Get(Form("hSystematicErrorsNSYieldMerged_PtBinAssoc%d", iBinPtHad + 1))); + TH1F* hNSSigmaSyst = reinterpret_cast(inFileFitSystematicErrors->Get(Form("hSystematicErrorsNSSigmaMerged_PtBinAssoc%d", iBinPtHad + 1))); + TH1F* hASYieldSyst = reinterpret_cast(inFileFitSystematicErrors->Get(Form("hSystematicErrorsASYieldMerged_PtBinAssoc%d", iBinPtHad + 1))); + TH1F* hASSigmaSyst = reinterpret_cast(inFileFitSystematicErrors->Get(Form("hSystematicErrorsASSigmaMerged_PtBinAssoc%d", iBinPtHad + 1))); + + for (int iBinPtCand = 0; iBinPtCand < nBinsPtCand; iBinPtCand++) { + hBaselinSyst->SetBinError(iBinPtCand + 1, hBaselinSyst->GetBinContent(iBinPtCand + 1) * hBaselin[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + hNSYieldSyst->SetBinError(iBinPtCand + 1, hNSYieldSyst->GetBinContent(iBinPtCand + 1) * hNSYield[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + hNSSigmaSyst->SetBinError(iBinPtCand + 1, hNSSigmaSyst->GetBinContent(iBinPtCand + 1) * hNSSigma[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + hASYieldSyst->SetBinError(iBinPtCand + 1, hASYieldSyst->GetBinContent(iBinPtCand + 1) * hASYield[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + hASSigmaSyst->SetBinError(iBinPtCand + 1, hASSigmaSyst->GetBinContent(iBinPtCand + 1) * hASSigma[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + + hBaselinSyst->SetBinContent(iBinPtCand + 1, hBaselin[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + hNSYieldSyst->SetBinContent(iBinPtCand + 1, hNSYield[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + hNSSigmaSyst->SetBinContent(iBinPtCand + 1, hNSSigma[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + hASYieldSyst->SetBinContent(iBinPtCand + 1, hASYield[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + hASSigmaSyst->SetBinContent(iBinPtCand + 1, hASSigma[iBinPtHad]->GetBinContent(iBinPtCand + 1)); + } + + c1->cd(); + setTH1HistoStyle(hNSYieldSyst, Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "Y^{NS}", kFullSquare, kRed, 1.8, kRed, 2); + hNSYieldSyst->SetFillStyle(0); + hNSYieldSyst->Draw("E2same"); + + c2->cd(); + setTH1HistoStyle(hASYieldSyst, Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "Y^{AS}", kFullSquare, kMagenta, 1.8, kMagenta, 2); + hASYieldSyst->SetFillStyle(0); + hASYieldSyst->Draw("E2same"); + + c3->cd(); + setTH1HistoStyle(hNSSigmaSyst, Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "#sigma_{NS}", kFullSquare, kOrange + 8, 1.8, kOrange + 8, 2); + hNSSigmaSyst->SetFillStyle(0); + hNSSigmaSyst->Draw("E2same"); + + c4->cd(); + setTH1HistoStyle(hASSigmaSyst, Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "#sigma_{AS}", kFullSquare, kViolet - 5, 1.8, kViolet - 5, 2); + hASSigmaSyst->SetFillStyle(0); + hASSigmaSyst->Draw("E2same"); + + c5->cd(); + setTH1HistoStyle(hBaselinSyst, Form("p_{T}^{assoc} > %.1f GeV/c", binsPtHadIntervals[iBinPtHad]), "p_{T} (GeV/c)", "Baseline", kFullSquare, kBlue, 1.8, kBlue, 2); + hBaselinSyst->SetFillStyle(0); + hBaselinSyst->Draw("E2same"); + } + + c1->SaveAs(Form("Output_CorrelationFitting_%s_png/NearSideYield_PtAssoc%d.png", codeNameAnalysis.data(), iBinPtHad + 1)); + c2->SaveAs(Form("Output_CorrelationFitting_%s_png/AwaySideYield_PtAssoc%d.png", codeNameAnalysis.data(), iBinPtHad + 1)); + c3->SaveAs(Form("Output_CorrelationFitting_%s_png/NearSideSigma_PtAssoc%d.png", codeNameAnalysis.data(), iBinPtHad + 1)); + c4->SaveAs(Form("Output_CorrelationFitting_%s_png/AwaySideSigma_PtAssoc%d.png", codeNameAnalysis.data(), iBinPtHad + 1)); + c5->SaveAs(Form("Output_CorrelationFitting_%s_png/Baseline_PtAssoc%d.png", codeNameAnalysis.data(), iBinPtHad + 1)); + c1->SaveAs(Form("Output_CorrelationFitting_%s_Root/NearSideYield_PtBinAssoc%d.root", codeNameAnalysis.data(), iBinPtHad + 1)); + c2->SaveAs(Form("Output_CorrelationFitting_%s_Root/AwaySideYield_PtBinAssoc%d.root", codeNameAnalysis.data(), iBinPtHad + 1)); + c3->SaveAs(Form("Output_CorrelationFitting_%s_Root/NearSideSigma_PtBinAssoc%d.root", codeNameAnalysis.data(), iBinPtHad + 1)); + c4->SaveAs(Form("Output_CorrelationFitting_%s_Root/AwaySideSigma_PtBinAssoc%d.root", codeNameAnalysis.data(), iBinPtHad + 1)); + c5->SaveAs(Form("Output_CorrelationFitting_%s_Root/Baseline_PtBinAssoc%d.root", codeNameAnalysis.data(), iBinPtHad + 1)); + } } -void SetTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, +void setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, Style_t markerStyle, Color_t markerColor, Double_t markerSize, Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset, Float_t hTitleYaxisOffset, Float_t hTitleXaxisSize, Float_t hTitleYaxisSize, Float_t hLabelXaxisSize, Float_t hLabelYaxisSize, @@ -195,6 +479,29 @@ void SetTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString histo->GetYaxis()->SetLabelSize(hLabelYaxisSize); histo->GetXaxis()->CenterTitle(centerXaxisTitle); histo->GetYaxis()->CenterTitle(centerYaxisTitle); +} + +void setTH1HistoStyle(TH1F*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, + Style_t markerStyle, Color_t markerColor, Double_t markerSize, + Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset, Float_t hTitleYaxisOffset, + Float_t hTitleXaxisSize, Float_t hTitleYaxisSize, Float_t hLabelXaxisSize, Float_t hLabelYaxisSize, + Bool_t centerXaxisTitle, Bool_t centerYaxisTitle) +{ - return; + histo->SetTitle(hTitle.Data()); + histo->GetXaxis()->SetTitle(hXaxisTitle.Data()); + histo->GetYaxis()->SetTitle(hYaxisTitle.Data()); + histo->SetMarkerStyle(markerStyle); + histo->SetMarkerColor(markerColor); + histo->SetMarkerSize(markerSize); + histo->SetLineColor(lineColor); + histo->SetLineWidth(lineWidth); + histo->GetXaxis()->SetTitleOffset(hTitleXaxisOffset); + histo->GetYaxis()->SetTitleOffset(hTitleYaxisOffset); + histo->GetXaxis()->SetTitleSize(hTitleXaxisSize); + histo->GetYaxis()->SetTitleSize(hTitleYaxisSize); + histo->GetXaxis()->SetLabelSize(hLabelXaxisSize); + histo->GetYaxis()->SetLabelSize(hLabelYaxisSize); + histo->GetXaxis()->CenterTitle(centerXaxisTitle); + histo->GetYaxis()->CenterTitle(centerYaxisTitle); } diff --git a/PWGHF/HFC/Macros/config_CorrAnalysis_DsToKKPi.json b/PWGHF/HFC/Macros/config_CorrAnalysis_DsToKKPi.json index 27e71b97514..5866d619f87 100644 --- a/PWGHF/HFC/Macros/config_CorrAnalysis_DsToKKPi.json +++ b/PWGHF/HFC/Macros/config_CorrAnalysis_DsToKKPi.json @@ -1,13 +1,23 @@ { - "CodeName": "Default", - "_CodeName": "Name to identify the analysis", - "pathFileSE": "~/cernbox/DsCorrelationAnalysis/MasterDegreeAnalysis/AnalysisResultsFinal.root", - "pathFileME": "~/cernbox/DsCorrelationAnalysis/MasterDegreeAnalysis/AnalysisResultsFinalME.root", - "pathFileMass": "/data/dataalice/scattar/RawYieldsDs.root", + "CodeName": "Test_example", + "_CodeName": "Name to identify the analysis: pass7_Full_ptAssoc0p3, Thin2023_Full_ptAssoc0p3", + "pathFileSE": "~/cernbox/AnalysisResults_SE_pp_Thin2023_FullAnalysis.root", + "_pathFileSE": "Name SE file", + "pathFileME": "~/cernbox/AnalysisResults_ME_derived_Thinned2023.root", + "_pathFileME": "Name ME file", + "pathFileMass": "~/cernbox/DsCorrelationAnalysis/ClassesForAnalysis/InvMassFitter/InvMass_pp_Thin2023_Final_Default.root", + "_pathFileMass": "Name mass file", + "pathFileFDTemplate": "~/cernbox/TemplatesCRMode2_ptAssocInt.root", + "pathFileFDPromptFrac": "~/cernbox/CutVarDs_FDVarDefaultBkg.root", + "pathFileSecPart": "~/cernbox/AnalysisResults_MC_Anchored_Thin2023_SecPart.root", + "_pathFileSecPart": "Path file for secondary particle contamination correction", "InputDirSE": "hf-task-correlation-ds-hadrons", "InputDirME": "hf-task-correlation-ds-hadrons", + "InputDirSecPart": "hf-task-correlation-ds-hadrons", "InputHistoCorrSignalName": "hCorrel2DVsPtSignalRegion", "InputHistoCorrSidebaName": "hCorrel2DVsPtSidebands", + "InputHistoCorrSidebaLeftName": "hCorrel2DVsPtSidebandLeft", + "InputHistoCorrSidebaRightName": "hCorrel2DVsPtSidebandRight", "InputHistoMassName": [ "hRawYieldsSignal", "hRawYieldsBkg", @@ -18,21 +28,34 @@ "Bkg yield vs pt", "SBs yield vs pt" ], + "InputHistoFDTemplatePrompt": "EtaPhiPromptNorm_pt", + "InputHistoFDTemplateNonPrompt": "EtaPhiNonPromptNorm_pt", + "InputHistoFDPromptFrac": "hRawFracPrompt", + "InputHistoPrimaryPart": "hCorrel2DVsPtPhysicalPrimaryMcRec", + "InputHistoAllPart": "hCorrel2DVsPtSignalRegionMcRec", + "IsDividedSideb": true, + "UseSidebLeft": true, + "UseSidebRight": false, + "ApplySecPartCorr": true, + "ApplyFDCorr": true, + "ApplyBiasBtoDCorr": true, + "pathfFilePromptMcRec": "~/cernbox/DsCorrelationAnalysis/ClassesForAnalysis/MonteCarloClosureTest/MonteCarloClosureTest_Prompt_All.root", + "pathfFileNonPromptMcRec": "~/cernbox/DsCorrelationAnalysis/ClassesForAnalysis/MonteCarloClosureTest/MonteCarloClosureTest_NonPrompt_All.root", "binsPtCandIntervals": [ - 2.0, + 1.0, 3.0, - 4.0, 5.0, 8.0, - 16.0 + 16.0, + 36.0 ], "binsPtHadIntervals": [ - 0.0, - 11.0 + 0.3, + 50.0 ], "deltaEtaInterval": [ - -0.8, - 0.8 + -1.0, + 1.0 ], "DmesonSpecie": 2, "_DmesonSpecie": [ @@ -45,7 +68,36 @@ "_NumberOfPools": "Number of pools for the event mixing", "CorrectPoolsSeparately": false, "_CorrectPoolsSeparately": "true = pool-by-pool ME correction; false = merged-pools ME correction", - "FitFunction": 1, - "FixBaseline": 0, - "FixMean": 3 + "RebinAngCorr": false, + "RebinFDCorr": true, + "RebinSecPart": false, + "nRebinDeltaPhi": 2, + "nRebinDeltaEta": 2, + "InputFileNameFitCorr": "ExtractCorrelationsResults_Reflected.root", + "_InputFileNameFitCorr": "ExtractCorrelationsResults_Reflected.root - ExtractCorrelationsResults.root", + "IsRiflected": true, + "DrawSystematics": false, + "SameSystematics": false, + "_SameSystematics": "true: systematic take from the first delta phi bin, false: systematic applied bin per bin", + "FitFunction": [ + 2, + 2, + 2, + 2, + 2 + ], + "_FitFunction": "1 : const + G NS + G AS (w/o periodicity), 2 : const + G NS + G AS (w/ periodicity), 3 : const + G AS, 4 : const + GenG NS + G AS (w/ periodicity), 5 : const + VonMises NS + VonMises AS (w/periodicity), 6 : const + VonMises AS", + "FixBaseline": 4, + "_FixBaseline": "0 : baseline free, = 1 : fix the baseline to the minimum of the histogram, < 0 : fix the baseline to the weighted average of the abs(fFixBaseline) lower points, = 3 : fix the baseline to the weighted average of the points passed through the function SetPointsForBaseline(), 4 : fix the baseline to the weighted average of default transverse region points", + "FixMean": 3, + "_FixMean": "= 0 : NS & AS mean free, = 1 : NS mean fixed to 0, AS mean free, = 2 : AS mean fixed to pi, NS mean free, = 3 : NS mean fixed to 0, AS mean to pi", + "ShiftBaseUp": false, + "ShiftBaseDown": false, + "nBaselinePoints": 4, + "binsForBaseline": [ + 6, + 7, + 8, + 9 + ] } diff --git a/PWGHF/HFC/TableProducer/CMakeLists.txt b/PWGHF/HFC/TableProducer/CMakeLists.txt index 1a888dfc1d7..4b5d698a393 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,17 +44,42 @@ o2physics_add_dpl_workflow(correlator-ds-hadrons PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(derived-data-creator-correlations-reduced + SOURCES derivedDataCreatorCorrelationsReduced.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(correlator-flow-charm-hadrons-reduced + SOURCES correlatorFlowCharmHadronsReduced.cxx + 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(correlator-lc-sc-hadrons + SOURCES correlatorLcScHadrons.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femto-dream-producer SOURCES femtoDreamProducer.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) diff --git a/PWGHF/HFC/TableProducer/correlatorD0D0bar.cxx b/PWGHF/HFC/TableProducer/correlatorD0D0bar.cxx index d51ded0baa4..dbef6c1ee60 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0D0bar.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0D0bar.cxx @@ -14,18 +14,34 @@ /// /// \author Fabio Colamaria , INFN Bari -#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 "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include using namespace o2; using namespace o2::analysis; @@ -48,9 +64,9 @@ 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}; +const auto efficiencyDmesonV = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsMassAndEfficiency}; // histogram binning definition const int massAxisBins = 120; @@ -82,9 +98,7 @@ struct HfCorrelatorD0D0bar { Configurable multMin{"multMin", 0., "minimum multiplicity accepted"}; Configurable multMax{"multMax", 10000., "maximum multiplicity accepted"}; Configurable> binsPt{"binsPt", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots and efficiency"}; - Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmeson_v}, "Efficiency values for D0 meson"}; - - HfHelper hfHelper; + Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmesonV}, "Efficiency values for D0 meson"}; 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; @@ -161,37 +175,37 @@ struct HfCorrelatorD0D0bar { 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) { + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candidate1)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { continue; } // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if ((candidate1.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) == 0) { continue; } double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); } // fill invariant mass plots and generic info from all D0/D0bar candidates if (candidate1.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMassD0"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMass"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } if (candidate1.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hMass"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMassD0bar"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMass"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0bar"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); } 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("hY"), HfHelper::yD0(candidate1)); registry.fill(HIST("hSelectionStatus"), candidate1.isSelD0bar() + (candidate1.isSelD0() * 2)); // D-Dbar correlation dedicated section @@ -200,14 +214,14 @@ struct HfCorrelatorD0D0bar { continue; } for (const auto& candidate2 : selectedD0CandidatesGrouped) { - if (!(candidate2.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { // check decay channel flag for candidate2 + if ((candidate2.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) == 0) { // check decay channel flag for candidate2 continue; } if (candidate2.isSelD0bar() < selectionFlagD0bar) { // keep only D0bar candidates passing the selection continue; } // kinematic selection on D0bar candidates - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate2)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candidate2)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { @@ -221,8 +235,8 @@ struct HfCorrelatorD0D0bar { candidate2.eta() - candidate1.eta(), candidate1.pt(), candidate2.pt()); - entryD0D0barRecoInfo(hfHelper.invMassD0ToPiK(candidate1), - hfHelper.invMassD0barToKPi(candidate2), + entryD0D0barRecoInfo(HfHelper::invMassD0ToPiK(candidate1), + HfHelper::invMassD0barToKPi(candidate2), 0); double etaCut = 0.; double ptCut = 0.; @@ -278,10 +292,10 @@ struct HfCorrelatorD0D0bar { bool flagD0barReflection = false; for (const auto& candidate1 : selectedD0CandidatesGroupedMC) { // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if ((candidate1.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) == 0) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate1)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candidate1)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { @@ -289,37 +303,37 @@ struct HfCorrelatorD0D0bar { } double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); } - if (std::abs(candidate1.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + if (std::abs(candidate1.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // fill per-candidate distributions from D0/D0bar true candidates registry.fill(HIST("hPtCandMCRec"), candidate1.pt()); registry.fill(HIST("hPtProng0MCRec"), candidate1.ptProng0()); registry.fill(HIST("hPtProng1MCRec"), candidate1.ptProng1()); registry.fill(HIST("hEtaMCRec"), candidate1.eta()); registry.fill(HIST("hPhiMCRec"), candidate1.phi()); - registry.fill(HIST("hYMCRec"), hfHelper.yD0(candidate1)); + registry.fill(HIST("hYMCRec"), HfHelper::yD0(candidate1)); 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.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)) { - registry.fill(HIST("hMassD0MCRecRefl"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + if (candidate1.isSelD0() >= selectionFlagD0) { // only reco as D0 + if (candidate1.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0 + registry.fill(HIST("hMassD0MCRecSig"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + } else if (candidate1.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMassD0MCRecRefl"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMassD0MCRecBkg"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0MCRecBkg"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } } - 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) { - registry.fill(HIST("hMassD0barMCRecRefl"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + if (candidate1.isSelD0bar() >= selectionFlagD0bar) { // only reco as D0bar + if (candidate1.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0bar + registry.fill(HIST("hMassD0barMCRecSig"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + } else if (candidate1.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMassD0barMCRecRefl"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMassD0barMCRecBkg"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0barMCRecBkg"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); } } @@ -328,18 +342,18 @@ struct HfCorrelatorD0D0bar { if (candidate1.isSelD0() < selectionFlagD0) { // discard candidates not selected as D0 in outer loop continue; } - flagD0Signal = candidate1.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK; // flagD0Signal 'true' if candidate1 matched to D0 (particle) - flagD0Reflection = candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Reflection 'true' if candidate1, selected as D0 (particle), is matched to D0bar (antiparticle) + flagD0Signal = candidate1.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0Signal 'true' if candidate1 matched to D0 (particle) + flagD0Reflection = candidate1.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0Reflection 'true' if candidate1, selected as D0 (particle), is matched to D0bar (antiparticle) for (const auto& candidate2 : selectedD0CandidatesGroupedMC) { - if (!(candidate2.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { // check decay channel flag for candidate2 + if ((candidate2.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) == 0) { // check decay channel flag for candidate2 continue; } if (candidate2.isSelD0bar() < selectionFlagD0bar) { // discard candidates not selected as D0bar in inner loop continue; } - flagD0barSignal = candidate2.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0barSignal 'true' if candidate2 matched to D0bar (antiparticle) - flagD0barReflection = candidate2.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK; // flagD0barReflection 'true' if candidate2, selected as D0bar (antiparticle), is matched to D0 (particle) - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate2)) > yCandMax) { + flagD0barSignal = candidate2.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0barSignal 'true' if candidate2 matched to D0bar (antiparticle) + flagD0barReflection = candidate2.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0barReflection 'true' if candidate2, selected as D0bar (antiparticle), is matched to D0 (particle) + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candidate2)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { @@ -367,8 +381,8 @@ struct HfCorrelatorD0D0bar { candidate2.eta() - candidate1.eta(), candidate1.pt(), candidate2.pt()); - entryD0D0barRecoInfo(hfHelper.invMassD0ToPiK(candidate1), - hfHelper.invMassD0barToKPi(candidate2), + entryD0D0barRecoInfo(HfHelper::invMassD0ToPiK(candidate1), + HfHelper::invMassD0barToKPi(candidate2), pairSignalStatus); double etaCut = 0.; double ptCut = 0.; @@ -401,7 +415,7 @@ struct HfCorrelatorD0D0bar { if (std::abs(particle1.pdgCode()) != Pdg::kD0) { continue; } - double yD = RecoDecay::y(particle1.pVector(), MassD0); + double const yD = RecoDecay::y(particle1.pVector(), MassD0); if (yCandMax >= 0. && std::abs(yD) > yCandMax) { continue; } @@ -442,7 +456,7 @@ struct HfCorrelatorD0D0bar { // fill pairs vs etaCut plot bool rightDecayChannels = false; - if ((std::abs(particle1.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) && (std::abs(particle2.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if ((std::abs(particle1.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) && (std::abs(particle2.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK)) { rightDecayChannels = true; } do { @@ -475,7 +489,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); } @@ -493,13 +507,13 @@ struct HfCorrelatorD0D0bar { if (std::abs(particle1.pdgCode()) != PDG_t::kCharm) { // search c or cbar particles continue; } - int partMothPDG = particle1.mothers_as().front().pdgCode(); + int const partMothPDG = particle1.mothers_as().front().pdgCode(); // check whether mothers of quark c/cbar are still '4'/'-4' particles - in that case the c/cbar quark comes from its own fragmentation, skip it if (partMothPDG == particle1.pdgCode()) { continue; } counterCCbarBeforeEtasel++; // count c or cbar (before kinematic selection) - double yC = RecoDecay::y(particle1.pVector(), MassCharm); + double const yC = RecoDecay::y(particle1.pVector(), MassCharm); if (yCandMax >= 0. && std::abs(yC) > yCandMax) { continue; } @@ -540,8 +554,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..a7efa82e7bd 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0D0barBarrelFullPid.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0D0barBarrelFullPid.cxx @@ -9,23 +9,39 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file HFCorrelatorD0D0barBarrelFullPid.cxx +/// \file correlatorD0D0barBarrelFullPid.cxx /// \brief Temporary D0-D0bar correlator task with full barrel PID implementation - data-like, MC-reco and MC-kine analyses. For ULS and LS pairs /// /// \author Fabio Colamaria , INFN Bari -#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 "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include using namespace o2; using namespace o2::analysis; @@ -48,9 +64,9 @@ 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}; +const auto efficiencyDmesonV = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsMassAndEfficiency}; // histogram binning definition const int massAxisBins = 120; @@ -83,9 +99,7 @@ struct HfCorrelatorD0D0barBarrelFullPid { Configurable multMin{"multMin", 0., "minimum multiplicity accepted"}; Configurable multMax{"multMax", 10000., "maximum multiplicity accepted"}; Configurable> binsPt{"binsPt", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots and efficiency"}; - Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmeson_v}, "Efficiency values for D0 meson"}; - - HfHelper hfHelper; + Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmesonV}, "Efficiency values for D0 meson"}; Partition> selectedD0candidates = (aod::hf_sel_candidate_d0_alice3_barrel::isSelD0TofPlusRichPid >= selectionFlagD0 || aod::hf_sel_candidate_d0_alice3_barrel::isSelD0barTofPlusRichPid >= selectionFlagD0bar); Partition> selectedD0candidatesMC = (aod::hf_sel_candidate_d0_alice3_barrel::isSelD0TofPlusRichPid >= selectionFlagD0 || aod::hf_sel_candidate_d0_alice3_barrel::isSelD0barTofPlusRichPid >= selectionFlagD0bar); @@ -162,37 +176,37 @@ struct HfCorrelatorD0D0barBarrelFullPid { 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) { + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candidate1)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { continue; } // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if ((candidate1.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) == 0) { continue; } double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); } // fill invariant mass plots and generic info from all D0/D0bar candidates if (candidate1.isSelD0TofPlusRichPid() >= selectionFlagD0) { - registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMassD0"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMass"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } if (candidate1.isSelD0barTofPlusRichPid() >= selectionFlagD0bar) { - registry.fill(HIST("hMass"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMassD0bar"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMass"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0bar"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); } 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("hY"), HfHelper::yD0(candidate1)); registry.fill(HIST("hSelectionStatus"), candidate1.isSelD0barTofPlusRichPid() + (candidate1.isSelD0TofPlusRichPid() * 2)); // D-Dbar correlation dedicated section @@ -201,14 +215,14 @@ struct HfCorrelatorD0D0barBarrelFullPid { continue; } for (const auto& candidate2 : selectedD0candidatesGrouped) { - if (!(candidate2.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { // check decay channel flag for candidate2 + if ((candidate2.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) == 0) { // check decay channel flag for candidate2 continue; } if (candidate2.isSelD0barTofPlusRichPid() < selectionFlagD0bar) { // keep only D0bar candidates passing the selection continue; } // kinematic selection on D0bar candidates - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate2)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candidate2)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { @@ -222,8 +236,8 @@ struct HfCorrelatorD0D0barBarrelFullPid { candidate2.eta() - candidate1.eta(), candidate1.pt(), candidate2.pt()); - entryD0D0barRecoInfo(hfHelper.invMassD0ToPiK(candidate1), - hfHelper.invMassD0barToKPi(candidate2), + entryD0D0barRecoInfo(HfHelper::invMassD0ToPiK(candidate1), + HfHelper::invMassD0barToKPi(candidate2), 0); double etaCut = 0.; double ptCut = 0.; @@ -279,10 +293,10 @@ struct HfCorrelatorD0D0barBarrelFullPid { bool flagD0barReflection = false; for (const auto& candidate1 : selectedD0candidatesGroupedMC) { // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if ((candidate1.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) == 0) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate1)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candidate1)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { @@ -290,37 +304,37 @@ struct HfCorrelatorD0D0barBarrelFullPid { } double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); } - if (std::abs(candidate1.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + if (std::abs(candidate1.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // fill per-candidate distributions from D0/D0bar true candidates registry.fill(HIST("hPtCandMCRec"), candidate1.pt()); registry.fill(HIST("hPtProng0MCRec"), candidate1.ptProng0()); registry.fill(HIST("hPtProng1MCRec"), candidate1.ptProng1()); registry.fill(HIST("hEtaMCRec"), candidate1.eta()); registry.fill(HIST("hPhiMCRec"), candidate1.phi()); - registry.fill(HIST("hYMCRec"), hfHelper.yD0(candidate1)); + registry.fill(HIST("hYMCRec"), HfHelper::yD0(candidate1)); 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.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)) { - registry.fill(HIST("hMassD0MCRecRefl"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + if (candidate1.isSelD0TofPlusRichPid() >= selectionFlagD0) { // only reco as D0 + if (candidate1.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0 + registry.fill(HIST("hMassD0MCRecSig"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + } else if (candidate1.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMassD0MCRecRefl"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMassD0MCRecBkg"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0MCRecBkg"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); } } - 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) { - registry.fill(HIST("hMassD0barMCRecRefl"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + if (candidate1.isSelD0barTofPlusRichPid() >= selectionFlagD0bar) { // only reco as D0bar + if (candidate1.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0bar + registry.fill(HIST("hMassD0barMCRecSig"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + } else if (candidate1.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMassD0barMCRecRefl"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMassD0barMCRecBkg"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0barMCRecBkg"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); } } @@ -329,18 +343,18 @@ struct HfCorrelatorD0D0barBarrelFullPid { if (candidate1.isSelD0TofPlusRichPid() < selectionFlagD0) { // discard candidates not selected as D0 in outer loop continue; } - flagD0Signal = candidate1.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK; // flagD0Signal 'true' if candidate1 matched to D0 (particle) - flagD0Reflection = candidate1.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0Reflection 'true' if candidate1, selected as D0 (particle), is matched to D0bar (antiparticle) + flagD0Signal = candidate1.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0Signal 'true' if candidate1 matched to D0 (particle) + flagD0Reflection = candidate1.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0Reflection 'true' if candidate1, selected as D0 (particle), is matched to D0bar (antiparticle) for (const auto& candidate2 : selectedD0candidatesGroupedMC) { - if (!(candidate2.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { // check decay channel flag for candidate2 + if ((candidate2.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) == 0) { // check decay channel flag for candidate2 continue; } if (candidate2.isSelD0barTofPlusRichPid() < selectionFlagD0bar) { // discard candidates not selected as D0bar in inner loop continue; } - flagD0barSignal = candidate2.flagMcMatchRec() == -(1 << aod::hf_cand_2prong::DecayType::D0ToPiK); // flagD0barSignal 'true' if candidate2 matched to D0bar (antiparticle) - flagD0barReflection = candidate2.flagMcMatchRec() == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK; // flagD0barReflection 'true' if candidate2, selected as D0bar (antiparticle), is matched to D0 (particle) - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate2)) > yCandMax) { + flagD0barSignal = candidate2.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0barSignal 'true' if candidate2 matched to D0bar (antiparticle) + flagD0barReflection = candidate2.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0barReflection 'true' if candidate2, selected as D0bar (antiparticle), is matched to D0 (particle) + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candidate2)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { @@ -368,8 +382,8 @@ struct HfCorrelatorD0D0barBarrelFullPid { candidate2.eta() - candidate1.eta(), candidate1.pt(), candidate2.pt()); - entryD0D0barRecoInfo(hfHelper.invMassD0ToPiK(candidate1), - hfHelper.invMassD0barToKPi(candidate2), + entryD0D0barRecoInfo(HfHelper::invMassD0ToPiK(candidate1), + HfHelper::invMassD0barToKPi(candidate2), pairSignalStatus); double etaCut = 0.; double ptCut = 0.; @@ -402,7 +416,7 @@ struct HfCorrelatorD0D0barBarrelFullPid { if (std::abs(particle1.pdgCode()) != Pdg::kD0) { continue; } - double yD = RecoDecay::y(particle1.pVector(), MassD0); + double const yD = RecoDecay::y(particle1.pVector(), MassD0); if (yCandMax >= 0. && std::abs(yD) > yCandMax) { continue; } @@ -443,7 +457,7 @@ struct HfCorrelatorD0D0barBarrelFullPid { // fill pairs vs etaCut plot bool rightDecayChannels = false; - if ((std::abs(particle1.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) && (std::abs(particle2.flagMcMatchGen()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if ((std::abs(particle1.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) && (std::abs(particle2.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK)) { rightDecayChannels = true; } do { @@ -476,7 +490,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); } @@ -494,13 +508,13 @@ struct HfCorrelatorD0D0barBarrelFullPid { if (std::abs(particle1.pdgCode()) != PDG_t::kCharm) { // search c or cbar particles continue; } - int partMothPDG = particle1.mothers_as().front().pdgCode(); + int const partMothPDG = particle1.mothers_as().front().pdgCode(); // check whether mothers of quark c/cbar are still '4'/'-4' particles - in that case the c/cbar quark comes from its own fragmentation, skip it if (partMothPDG == particle1.pdgCode()) { continue; } counterCCbarBeforeEtasel++; // count c or cbar (before kinematic selection) - double yC = RecoDecay::y(particle1.pVector(), MassCharm); + double const yC = RecoDecay::y(particle1.pVector(), MassCharm); if (yCandMax >= 0. && std::abs(yC) > yCandMax) { continue; } @@ -541,8 +555,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 3fc2a915496..157c230d72c 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx @@ -15,27 +15,56 @@ /// \author Samrangy Sadhu , INFN Bari /// \author Swapnesh Santosh Khade , IIT Indore -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" +#include "PWGHF/Utils/utilsAnalysis.h" -#include "Common/Core/TrackSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include 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 @@ -45,122 +74,146 @@ 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.; - // Types using BinningType = ColumnBinningPolicy>; -using SelectedCollisions = soa::Filtered>; +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 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"}; + Configurable centMin{"centMin", 0., "Minimum Centrality"}; + Configurable centMax{"centMax", 100., "Maximum Centrality"}; + Configurable useCentrality{"useCentrality", false, "Flag for centrality dependent analyses"}; + + SliceCache cache; - HfHelper hfHelper; + 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; + bool isCentInRange = false; if (selectedD0Candidates.size() > 0) { auto selectedD0CandidatesGrouped = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); 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 (std::abs(hfHelper.yD0(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + if (std::abs(HfHelper::yD0(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + isD0Found = false; continue; } - isD0Found = 1; + isD0Found = true; break; } } - d0Sel(isD0Found); + float cent = 0.; + if (useCentrality) { + cent = collision.centFT0M(); + } + if (useSel8) { + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + } + isCentInRange = (cent >= centMin && cent <= centMax); + isSelColl = isD0Found && isSel8 && isNosameBunchPileUp && isCentInRange; + 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& candidate : selectedD0CandidatesGroupedMc) { // check decay channel flag for candidate if (!TESTBIT(candidate.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + isD0Found = false; continue; } - if (std::abs(hfHelper.yD0(candidate)) > yCandMax || candidate.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 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = 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; + bool isD0Found = false; for (const auto& particle : mcParticles) { if (std::abs(particle.pdgCode()) != Pdg::kD0) { continue; } - double yD = RecoDecay::y(particle.pVector(), MassD0); + double const 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"}; @@ -171,21 +224,19 @@ struct HfCorrelatorD0Hadrons { Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; Configurable ptTrackMax{"ptTrackMax", 99., "max. 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> 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"}; + 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"}; - 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 - - HfHelper hfHelper; - BinningType corrBinning{{zPoolBins, multPoolBins}, true}; + Configurable useCentrality{"useCentrality", false, "Flag for centrality dependent analyses"}; int leadingIndex = 0; double massD0{0.}; @@ -193,10 +244,7 @@ struct HfCorrelatorD0Hadrons { 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; + SliceCache cache; Filter collisionFilter = aod::hf_selection_dmeson_collision::dmesonSel == true; 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); @@ -204,39 +252,25 @@ struct HfCorrelatorD0Hadrons { 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.}}}}, - {"hMultFT0M", "Multiplicity FT0M", {HistType::kTH1F, {{10000, 0., 10000.}}}}, - {"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; + Preslice perCollisionID = aod::track::collisionId; + Preslice perTrueCollision = o2::aod::mcparticle::mcCollisionId; + + 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"}; + ConfigurableAxis binsCentFt0m{"binsCentFt0m", {100, 0., 100.}, "Centrality percentile (FT0M)"}; + + BinningType corrBinning{{zPoolBins, multPoolBins}, true}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { @@ -244,59 +278,112 @@ 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 candidates - 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 - 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 - 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 candidates - 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 - 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 - 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 const axisEta = {binsEta, "#it{#eta}"}; + AxisSpec const axisPhi = {binsPhi, "#it{#varphi}"}; + AxisSpec const 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 const axisMultiplicity = {binsMultiplicity, "Multiplicity"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec const axisPosZ = {binsPosZ, "PosZ"}; + AxisSpec const axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec const axisStatus = {4, -0.5, 3.5, "Selection status"}; + AxisSpec const axisSignalStatus = {200, 0., 200., "Signal status"}; + AxisSpec axisEvtCount = {1, -0.5, 0.5}; + AxisSpec const axisTrkCount = {5, 0., 5.}; + AxisSpec axisBdtScoreBkg = {100, 0., 1., "Bdt score background"}; + AxisSpec axisBdtScorePrompt = {100, 0., 1., "Bdt score prompt"}; + AxisSpec axisBdtScoreNonPrompt = {100, 0., 1., "Bdt score Nonprompt"}; + AxisSpec axisOrigin = {10, 0., 10., "Candidate origin"}; + AxisSpec axisCent = {binsCentFt0m, "Centrality"}; + + // 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("hCentFT0M", "Centrality FT0M;centrality;entries", {HistType::kTH1F, {{100, 0., 100.}}}); + 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("hMassD0VsPtVsCent", "D0 candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCent}}}); + registry.add("hMLScoresVsMassVsPtVsEtaVsOrigin", "D0, D0bar candidates BkgVspromptVsNonPromptVsMassVsPtVsEtaVsOrigin", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisBdtScoreNonPrompt}, {axisMassD}, {axisPtD}, {axisEta}, {axisOrigin}}}); + // 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", "D0,Hadron candidates Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtVsMLScoresVsEtaRecSigPrompt", "Prompt D0-D0bar signal candidates MLVsPtVsEta - MC reco", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisBdtScoreNonPrompt}, {axisPtD}, {axisEta}}}); + registry.add("hPtCandRecSigNonPrompt", "D0,Hadron candidates Non Prompt - MC Reco", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtVsMLScoresVsEtaRecSigNonPrompt", "NonPrompt D0-D0bar signal candidates MLVsPtVsEta - MC reco", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisBdtScoreNonPrompt}, {axisPtD}, {axisEta}}}); + 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("hPtVsEtaCandGenSigPrompt", "D0,Hadron candidates PtvsEta - MC Gen prompt", {HistType::kTH2F, {{axisPtD}, {axisEta}}}); + registry.add("hPtCandGenNonPrompt", "D0, D0bar candidates - MC gen non prompt", {HistType::kTH1F, {axisPtD}}); + registry.add("hPtVsEtaCandGenSigNonPrompt", "D0,Hadron candidates PtvsEta - MC Gen non-prompt", {HistType::kTH2F, {{axisPtD}, {axisEta}}}); + 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}}); } - // Find Leading Particle - template - int findLeadingParticle(TTracks const& tracks) - { - auto leadingParticle = tracks.begin(); - for (auto const& track : tracks) { - if (std::abs(track.dcaXY()) >= 1. || std::abs(track.dcaZ()) >= 1.) { - continue; - } - if (track.pt() > leadingParticle.pt()) { - leadingParticle = track; - } - } - int leadingIndex = leadingParticle.globalIndex(); - return leadingIndex; - } // ======= 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(SelectedCollisions::iterator const& collision, SelectedTracks const& tracks, - soa::Join const&) + SelectedCandidatesDataMl const& candidates) { - // protection against empty tables to be sliced - if (selectedD0Candidates.size() == 0) { - return; - } // find leading particle if (correlateD0WithLeadingParticle) { - leadingIndex = findLeadingParticle(tracks); + leadingIndex = findLeadingParticle(tracks, etaTrackMax.value); + } + float cent = 0.; + if (useCentrality) { + cent = collision.centFT0M(); } 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) { @@ -310,98 +397,110 @@ struct HfCorrelatorD0Hadrons { } } registry.fill(HIST("hMultiplicityPreSelection"), nTracks); - registry.fill(HIST("hZvtx"), collision.posZ()); - registry.fill(HIST("hMultFT0M"), collision.multFT0M()); + 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 (std::abs(hfHelper.yD0(candidate1)) >= yCandMax || candidate1.pt() <= ptCandMin || candidate1.pt() >= ptTrackMax) { + for (const auto& candidate : candidates) { + if (std::abs(HfHelper::yD0(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptTrackMax) { 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())); + if (applyEfficiency != 0) { + efficiencyWeight = 1. / efficiencyDmeson->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())); } + + // Invariant mass of D0 and D0bar + const auto invMassD0 = HfHelper::invMassD0ToPiK(candidate); + const auto invMassD0bar = HfHelper::invMassD0barToKPi(candidate); + // ========================== 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"), invMassD0, candidate.pt(), efficiencyWeight); + registry.fill(HIST("hMass1D"), invMassD0, efficiencyWeight); + registry.fill(HIST("hMassD01D"), invMassD0, efficiencyWeight); + registry.fill(HIST("hMassD0VsPtVsCent"), invMassD0, candidate.pt(), cent, efficiencyWeight); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; + } + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOrigin"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), (candidate.isSelD0bar() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0Only); } - 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"), invMassD0bar, candidate.pt(), efficiencyWeight); + registry.fill(HIST("hMass1D"), invMassD0bar, efficiencyWeight); + registry.fill(HIST("hMassD0bar1D"), invMassD0bar, efficiencyWeight); + registry.fill(HIST("hMassD0VsPtVsCent"), invMassD0bar, candidate.pt(), cent, efficiencyWeight); + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; + } + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOrigin"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), (candidate.isSelD0() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0barOnly); } + entryD0CandRecoInfo(invMassD0, invMassD0bar, 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 bool correlationStatus = false; - if ((candidate1.prong0Id() == track.globalIndex()) || (candidate1.prong1Id() == track.globalIndex())) { + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex())) { if (!storeAutoCorrelationFlag) { continue; } correlationStatus = true; } - - 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) { - isSoftPiD0 = true; + if (candidate.isSelD0() >= selectionFlagD0) { + if ((std::abs(invMassDstar1 - invMassD0) - softPiMass) < ptSoftPionMax) { continue; } } - if (candidate1.isSelD0bar() >= selectionFlagD0bar) { - if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(candidate1)) - softPiMass) < ptSoftPionMax) { - isSoftPiD0bar = true; + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + if ((std::abs(invMassDstar2 - invMassD0bar) - softPiMass) < ptSoftPionMax) { 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) { signalStatus += aod::hf_correlation_d0_hadron::ParticleTypeData::D0Only; } - if ((candidate1.isSelD0bar() >= selectionFlagD0bar) && !isSoftPiD0bar) { + if (candidate.isSelD0bar() >= selectionFlagD0bar) { signalStatus += aod::hf_correlation_d0_hadron::ParticleTypeData::D0barOnly; } @@ -409,15 +508,20 @@ struct HfCorrelatorD0Hadrons { if (track.globalIndex() != leadingIndex) { continue; } - registry.fill(HIST("hTrackCounter"), 4); // fill no. of tracks have leading particle + registry.fill(HIST("hTrackCounter"), 3); // fill no. of tracks have leading particle } - 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, - correlationStatus); - entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(candidate1), hfHelper.invMassD0barToKPi(candidate1), signalStatus); + correlationStatus, + cent); + entryD0HadronRecoInfo(invMassD0, invMassD0bar, 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()); + registry.fill(HIST("hCentFT0M"), cent); } // end inner loop (tracks) @@ -429,17 +533,18 @@ struct HfCorrelatorD0Hadrons { void processMcRec(SelectedCollisions::iterator const& collision, SelectedTracksMcRec const& tracks, - soa::Join const&) + 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); + leadingIndex = findLeadingParticle(tracks, etaTrackMax.value); } 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) { @@ -458,223 +563,299 @@ 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)) { + std::vector outputMlD0 = {-1., -1., -1.}; + std::vector outputMlD0bar = {-1., -1., -1.}; + + for (const auto& candidate : candidates) { + bool isD0Prompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + bool isD0NonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + // check decay channel flag for candidate + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (std::abs(hfHelper.yD0(candidate1)) >= yCandMax || candidate1.pt() <= ptCandMin || candidate1.pt() >= ptTrackMax) { + 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())); + if (applyEfficiency != 0) { + efficiencyWeight = 1. / efficiencyDmeson->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())); } - if (std::abs(candidate1.flagMcMatchRec()) == 1 << aod::hf_cand_2prong::DecayType::D0ToPiK) { + const auto invMassD0 = HfHelper::invMassD0ToPiK(candidate); + const auto invMassD0bar = HfHelper::invMassD0barToKPi(candidate); + + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::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() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0 + registry.fill(HIST("hMassD0RecSig"), invMassD0, candidate.pt(), efficiencyWeight); + if (isD0Prompt) { + registry.fill(HIST("hPtCandRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityRecPrompt"), candidate.pt(), collision.multFT0M()); + registry.fill(HIST("hPtVsMLScoreVsEtasRecSigPrompt"), outputMlD0[0], outputMlD0[1], outputMlD0[2], candidate.pt(), candidate.eta()); + } else if (isD0NonPrompt) { + registry.fill(HIST("hPtCandRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityRecNonPrompt"), candidate.pt(), collision.multFT0M()); + registry.fill(HIST("hPtVsMLScoresVsEtaRecSigNonPrompt"), outputMlD0[0], outputMlD0[1], outputMlD0[2], candidate.pt(), candidate.eta()); + } + } else if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMassD0RecRef"), invMassD0, candidate.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMassD0RecBg"), hfHelper.invMassD0ToPiK(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0RecBg"), invMassD0, candidate.pt(), efficiencyWeight); + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; } + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOrigin"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), isD0Prompt); } - 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() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0bar + registry.fill(HIST("hMassD0barRecSig"), invMassD0bar, candidate.pt(), efficiencyWeight); + if (isD0Prompt) { + registry.fill(HIST("hPtCandRecSigPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityRecPrompt"), candidate.pt(), collision.multFT0M()); + registry.fill(HIST("hPtVsMLScoresVsEtaRecSigPrompt"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], candidate.pt(), candidate.eta()); + } else if (isD0NonPrompt) { + registry.fill(HIST("hPtCandRecSigNonPrompt"), candidate.pt()); + registry.fill(HIST("hPtVsMultiplicityRecNonPrompt"), candidate.pt(), collision.multFT0M()); + registry.fill(HIST("hPtVsMLScoresVsEtaRecSigNonPrompt"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], candidate.pt(), candidate.eta()); + } + } else if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMassD0barRecRef"), invMassD0bar, candidate.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMassD0barRecBg"), hfHelper.invMassD0barToKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassD0barRecBg"), invMassD0bar, candidate.pt(), efficiencyWeight); + } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; } + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOrigin"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), isD0Prompt); } + entryD0CandRecoInfo(invMassD0, invMassD0bar, 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() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0Signal 'true' if candidate matched to D0 (particle) + flagD0bar = candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0Reflection 'true' if candidate, selected as D0 (particle), is matched to D0bar (antiparticle) + float cent = 100.0; // Centrality Placeholder: will be updated later // ========== track loop starts here ======================== for (const auto& track : tracks) { - registry.fill(HIST("hTrackCounterRec"), 1); // fill total no. of tracks - + registry.fill(HIST("hTrackCounter"), 0); // fill total no. of tracks + if (!track.isGlobalTrackWoDCA()) { + continue; + } // Removing D0 daughters by checking track indices bool correlationStatus = false; - if ((candidate1.prong0Id() == track.globalIndex()) || (candidate1.prong1Id() == track.globalIndex())) { + 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; // ===== 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) { - isSoftPiD0 = true; + if (candidate.isSelD0() >= selectionFlagD0) { + if ((std::abs(invMassDstar1 - invMassD0) - softPiMass) < ptSoftPionMax) { continue; } } - if (candidate1.isSelD0bar() >= selectionFlagD0bar) { - if ((std::abs(invMassDstar2 - hfHelper.invMassD0barToKPi(candidate1)) - softPiMass) < ptSoftPionMax) { - isSoftPiD0bar = true; + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + if ((std::abs(invMassDstar2 - invMassD0bar) - softPiMass) < ptSoftPionMax) { 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"), 4); // fill no. of tracks have leading particle + 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, - correlationStatus); - entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(candidate1), hfHelper.invMassD0barToKPi(candidate1), signalStatus); + correlationStatus, + cent); + entryD0HadronRecoInfo(invMassD0, invMassD0bar, 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(); + auto 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.multFT0M()); + } // 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 const 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; + float cent = 100.; // Centrality Placeholder: will be updated later - 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) { + if (std::abs(particleTrigg.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + double const yD = RecoDecay::y(particleTrigg.pVector(), MassD0); + if (yCandMax >= 0. && std::abs(yD) > yCandMax) { continue; } - if (particle2.pt() < ptTrackMin) { - 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()); + registry.fill(HIST("hPtVsEtaCandGenSigPrompt"), particleTrigg.pt(), particleTrigg.eta()); + } else if (isD0NonPrompt) { + registry.fill(HIST("hPtCandGenNonPrompt"), particleTrigg.pt()); + registry.fill(HIST("hPtVsEtaCandGenSigNonPrompt"), particleTrigg.pt(), particleTrigg.eta()); + } - 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}, {zPoolBins, multPoolBinsMcGen}, true}; - int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), getTracksSize(mcCollision))); - - bool correlationStatus = false; - entryD0HadronPair(getDeltaPhi(particle2.phi(), particle1.phi()), - particle2.eta() - particle1.eta(), - particle1.pt(), - particle2.pt(), - poolBin, - correlationStatus); - 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, + cent); + 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); @@ -682,7 +863,7 @@ 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) { @@ -691,47 +872,64 @@ struct HfCorrelatorD0Hadrons { } auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair const pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairData) { + 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())); - for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + int const 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(t1)) >= yCandMax) { + 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); + const auto invMassD0 = HfHelper::invMassD0ToPiK(candidate); + const auto invMassD0bar = HfHelper::invMassD0barToKPi(candidate); + 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.}; + float cent = 100.; // Centrality Placeholder: will be updated later - if (t1.isSelD0() >= selectionFlagD0) { - if ((std::abs(invMassDstar1 - hfHelper.invMassD0ToPiK(t1)) - softPiMass) < ptSoftPionMax) { + if (candidate.isSelD0() >= selectionFlagD0) { + if ((std::abs(invMassDstar1 - invMassD0) - 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 - invMassD0bar) - 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 { @@ -739,8 +937,11 @@ struct HfCorrelatorD0Hadrons { } } bool correlationStatus = false; - entryD0HadronPair(getDeltaPhi(t1.phi(), t2.phi()), t1.eta() - t2.eta(), t1.pt(), t2.pt(), poolBin, correlationStatus); - entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(t1), hfHelper.invMassD0barToKPi(t1), signalStatus); + entryD0HadronPair(getDeltaPhi(candidate.phi(), particleAssoc.phi()), candidate.eta() - particleAssoc.eta(), candidate.pt(), particleAssoc.pt(), poolBin, correlationStatus, cent); + entryD0HadronRecoInfo(invMassD0, invMassD0bar, 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()); } } } @@ -749,49 +950,81 @@ struct HfCorrelatorD0Hadrons { // ====================== Implement Event mixing on McRec =================================== void processMcRecMixedEvent(SelectedCollisions const& collisions, - SelectedCandidatesMcRec const& candidates, - SelectedTracksMcRec const& tracks) + SelectedCandidatesMcRecMl const& candidates, + SelectedTracksMcRec const& tracks, + aod::McParticles const& mcParticles) { auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair const 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.multFT0M())); + int const 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()); + float cent = 100.; // Centrality Placeholder: will be updated later - 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 (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); + const auto invMassD0 = HfHelper::invMassD0ToPiK(candidate); + const auto invMassD0bar = HfHelper::invMassD0barToKPi(candidate); + 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 - invMassD0) - 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 - invMassD0bar) - 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() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK; // flagD0Signal 'true' if candidate matched to D0 (particle) + flagD0bar = candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::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 { @@ -799,7 +1032,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 { @@ -807,7 +1040,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 { @@ -815,7 +1048,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 { @@ -823,7 +1056,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 { @@ -831,7 +1064,7 @@ 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 { @@ -840,8 +1073,11 @@ struct HfCorrelatorD0Hadrons { } // background case D0bar registry.fill(HIST("hSignalStatusMERec"), signalStatus); bool correlationStatus = false; - entryD0HadronPair(getDeltaPhi(t1.phi(), t2.phi()), t1.eta() - t2.eta(), t1.pt(), t2.pt(), poolBin, correlationStatus); - entryD0HadronRecoInfo(hfHelper.invMassD0ToPiK(t1), hfHelper.invMassD0barToKPi(t1), signalStatus); + entryD0HadronPair(getDeltaPhi(candidate.phi(), particleAssoc.phi()), candidate.eta() - particleAssoc.eta(), candidate.pt(), particleAssoc.pt(), poolBin, correlationStatus, cent); + entryD0HadronRecoInfo(invMassD0, invMassD0bar, 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()); } } } @@ -852,55 +1088,44 @@ struct HfCorrelatorD0Hadrons { void processMcGenMixedEvent(SelectedCollisionsMcGen const& collisions, 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}, {zPoolBins, multPoolBinsMcGen}, true}; - + BinningTypeMcGen const corrBinningMcGen{{zPoolBins, multPoolBinsMcGen}, true}; auto tracksTuple = std::make_tuple(mcParticles, mcParticles); - Pair pairMcGen{corrBinningMcGen, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair const 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 (std::abs(yD) >= yCandMax || t1.pt() <= ptCandMin || std::abs(t2.eta()) >= etaTrackMax || t2.pt() <= ptTrackMin) { - continue; - } - if ((std::abs(t2.pdgCode()) != kElectron) && (std::abs(t2.pdgCode()) != kMuonMinus) && (std::abs(t2.pdgCode()) != kPiPlus) && (std::abs(t2.pdgCode()) != kKPlus) && (std::abs(t2.pdgCode()) != kProton)) { - continue; - } - if (!t2.isPhysicalPrimary()) { + 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()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + double const 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; + } + float cent = 100.; // Centrality Placeholder: will be updated later + 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, cent); + entryD0HadronRecoInfo(massD0, massD0, 0); // dummy info + entryD0HadronGenInfo(isD0Prompt, particleAssoc.isPhysicalPrimary(), trackOrigin); } - int poolBin = corrBinningMcGen.getBin(std::make_tuple(c2.posZ(), getTracksSize(c2))); - bool correlationStatus = false; - entryD0HadronPair(getDeltaPhi(t2.phi(), t1.phi()), t2.eta() - t1.eta(), t1.pt(), t2.pt(), poolBin, correlationStatus); - entryD0HadronRecoInfo(massD0, massD0, 0); // dummy info } } } diff --git a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx index 6288d7388b5..7c14da3fe30 100644 --- a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx @@ -14,18 +14,39 @@ /// /// \author Andrea Tavira García , IJCLab Orsay -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseD0ToKPi.h" +#include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/HFC/DataModel/DMesonPairsTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::constants::physics; @@ -52,10 +73,9 @@ 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; @@ -69,18 +89,57 @@ struct HfCorrelatorDMesonPairs { 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"}; + Configurable ptMaxRemoveAmbiguous{"ptMaxRemoveAmbiguous", 5.0, "Max. pT to remove the 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"}; + + SliceCache cache; + Preslice perCol2Prong = aod::hf_cand::collisionId; + + o2::analysis::HfMlResponseD0ToKPi hfMlResponse; + o2::ccdb::CcdbApi ccdbApi; - HfHelper hfHelper; + std::vector outputMlD0Cand1; + std::vector outputMlD0barCand1; - using TracksWPid = soa::Join; + std::vector outputMlD0Cand2; + std::vector outputMlD0barCand2; - 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; + // 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::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", @@ -91,11 +150,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}, @@ -106,6 +175,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]; @@ -140,7 +222,7 @@ struct HfCorrelatorDMesonPairs { labels[23] = "# of True D+Dbar Pairs"; labels[24] = "# of True Dbar+D Pairs"; - AxisSpec axisSelStatus = {kNBinsSelStatus, 0.5, kNBinsSelStatus + 0.5, ""}; + AxisSpec const axisSelStatus = {kNBinsSelStatus, 0.5, kNBinsSelStatus + 0.5, ""}; registry.add("hSelectionStatus", "D Meson candidates;selection status;entries", HistType::kTH1F, {axisSelStatus}); registry.add("hSelectionStatusMcGen", "D Meson candidates MC Gen;selection status;entries", HistType::kTH1F, {axisSelStatus}); @@ -162,7 +244,7 @@ struct HfCorrelatorDMesonPairs { labelsMatching[6] = "# of matched Dbar Cand 2"; labelsMatching[7] = "# of unmatched Cand 2"; - AxisSpec axisMatching = {kNBinsMatching, 0.5, kNBinsMatching + 0.5, ""}; + AxisSpec const axisMatching = {kNBinsMatching, 0.5, kNBinsMatching + 0.5, ""}; registry.add("hMatchingMcRec", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisMatching}); registry.add("hMatchingMcGen", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisMatching}); @@ -181,7 +263,7 @@ struct HfCorrelatorDMesonPairs { labelsSinglePart[4] = "# of true D"; labelsSinglePart[5] = "# of true Dbar"; - AxisSpec axisSinglePart = {kNBinsSinglePart, 0.5, kNBinsSinglePart + 0.5, ""}; + AxisSpec const axisSinglePart = {kNBinsSinglePart, 0.5, kNBinsSinglePart + 0.5, ""}; registry.add("hStatusSinglePart", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisSinglePart}); registry.add("hStatusSinglePartMcGen", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisSinglePart}); @@ -190,7 +272,7 @@ struct HfCorrelatorDMesonPairs { registry.get(HIST("hStatusSinglePartMcGen"))->GetXaxis()->SetBinLabel(iBin + 1, labelsSinglePart[iBin].data()); } - AxisSpec axisInputD0 = {200, -0.5, 199.5}; + AxisSpec const axisInputD0 = {200, -0.5, 199.5}; registry.add("hInputCheckD0", "Check on input D0 meson candidates/event", {HistType::kTH1F, {axisInputD0}}); registry.add("hInputCheckD0bar", "Check on input D0bar meson candidates/event", {HistType::kTH1F, {axisInputD0}}); registry.add("hInputCheckD0AndD0bar", "Check on input D0 & D0bar meson candidates/event", {HistType::kTH1F, {axisInputD0}}); @@ -202,13 +284,38 @@ 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 /// SelectedD and SelectedDbar bits look at whether the candidate passed the selection flags. /// \param candidate is candidate /// \return bitmap with type of candidate - template + template uint8_t assignCandidateTypeD0(const T& candidate) { uint8_t candidateType(0); @@ -218,11 +325,11 @@ struct HfCorrelatorDMesonPairs { if (candidate.isSelD0bar() >= selectionFlagD0bar) { SETBIT(candidateType, SelectedDbar); } - if constexpr (isMcRec) { - if (candidate.flagMcMatchRec() == 1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK) { // matched as D0 + if constexpr (IsMcRec) { + if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // matched as D0 SETBIT(candidateType, TrueD); } - if (candidate.flagMcMatchRec() == -(1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK)) { // matched as D0bar + if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // matched as D0bar SETBIT(candidateType, TrueDbar); } } @@ -280,59 +387,50 @@ 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) { // Get counters per event - bool isSignalD0 = std::abs(hfHelper.invMassD0ToPiK(candidate) - MassD0) < massCut; - bool isSignalD0bar = std::abs(hfHelper.invMassD0barToKPi(candidate) - MassD0Bar) < massCut; + bool const isSignalD0 = std::abs(HfHelper::invMassD0ToPiK(candidate) - MassD0) < massCut; + bool const isSignalD0bar = std::abs(HfHelper::invMassD0barToKPi(candidate) - MassD0Bar) < massCut; if (selectSignalRegionOnly && !(isSignalD0 || isSignalD0bar)) { continue; } 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); + bool const isDCand1 = isD(candidateType1); + bool const isDbarCand1 = isDbar(candidateType1); if (isDCand1) { nDevent++; } @@ -372,7 +470,7 @@ struct HfCorrelatorDMesonPairs { /// Fill selection status histogram 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, + 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) { @@ -427,144 +525,355 @@ struct HfCorrelatorDMesonPairs { } } - entryD0Pair(ptCand1, ptCand2, 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 == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMatchingMcRec"), 2); + } else if (matchedRec1 == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + 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 == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMatchingMcRec"), 6); + } else if (matchedRec2 == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + registry.fill(HIST("hMatchingMcRec"), 7); + } else if (matchedRec2 == 0) { + registry.fill(HIST("hMatchingMcRec"), 8); + } + // Fill True info + if (isTrueDCand1 != 0) { + registry.fill(HIST("hSelectionStatus"), 6); + } else if (isTrueDbarCand1 != 0) { + registry.fill(HIST("hSelectionStatus"), 7); + } + if (isTrueDCand2 != 0) { + registry.fill(HIST("hSelectionStatus"), 12); + } else if (isTrueDbarCand2 != 0) { + registry.fill(HIST("hSelectionStatus"), 13); + } + if ((isTrueDCand1 != 0) && (isTrueDCand2 != 0)) { + registry.fill(HIST("hSelectionStatus"), 22); + } else if ((isTrueDbarCand1 != 0) && (isTrueDbarCand2 != 0)) { + registry.fill(HIST("hSelectionStatus"), 23); + } else if ((isTrueDCand1 != 0) && (isTrueDbarCand2 != 0)) { + registry.fill(HIST("hSelectionStatus"), 24); + } else if ((isTrueDbarCand1 != 0) && (isTrueDCand2 != 0)) { + 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; + bool const isSignalD0Cand1 = std::abs(HfHelper::invMassD0ToPiK(candidate1) - MassD0) < massCut; + bool const isSignalD0barCand1 = std::abs(HfHelper::invMassD0barToKPi(candidate1) - MassD0Bar) < massCut; if (selectSignalRegionOnly && !(isSignalD0Cand1 || isSignalD0barCand1)) { continue; } auto candidateType1 = assignCandidateTypeD0(candidate1); // Candidate type attribution - bool isDCand1 = isD(candidateType1); - bool isDbarCand1 = isDbar(candidateType1); + bool const isDCand1 = isD(candidateType1); + bool const 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) && candidate1.pt() < ptMaxRemoveAmbiguous) { + 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; } - bool isSignalD0Cand2 = std::abs(hfHelper.invMassD0ToPiK(candidate2) - MassD0) < massCut; - bool isSignalD0barCand2 = std::abs(hfHelper.invMassD0barToKPi(candidate2) - MassD0Bar) < massCut; + bool const isSignalD0Cand2 = std::abs(HfHelper::invMassD0ToPiK(candidate2) - MassD0) < massCut; + bool const isSignalD0barCand2 = std::abs(HfHelper::invMassD0barToKPi(candidate2) - MassD0Bar) < massCut; if (selectSignalRegionOnly && !(isSignalD0Cand2 || isSignalD0barCand2)) { continue; } auto candidateType2 = assignCandidateTypeD0(candidate2); // Candidate type attribution - bool isDCand2 = isD(candidateType2); - bool isDbarCand2 = isDbar(candidateType2); - - fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, hfHelper.yD0(candidate1), hfHelper.yD0(candidate2), - candidate1.pt(), candidate2.pt(), hfHelper.invMassD0ToPiK(candidate1), hfHelper.invMassD0barToKPi(candidate1), - hfHelper.invMassD0ToPiK(candidate2), hfHelper.invMassD0barToKPi(candidate2)); + bool const isDCand2 = isD(candidateType2); + bool const isDbarCand2 = isDbar(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) && candidate2.pt() < ptMaxRemoveAmbiguous) { + 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) { - auto ptCandidate1 = candidate1.pt(); - auto yCandidate1 = hfHelper.yD0(candidate1); - float massD0Cand1 = hfHelper.invMassD0ToPiK(candidate1); - float massD0barCand1 = hfHelper.invMassD0barToKPi(candidate1); - auto prong0Cand1 = candidate1.template prong0_as(); - auto prong1Cand1 = candidate1.template prong1_as(); - if (abs(hfHelper.yD0(candidate1)) > yCandMax) { + outputMlD0Cand1.clear(); + outputMlD0barCand1.clear(); + + auto ptCandidate1 = candidate1.pt(); + auto yCandidate1 = HfHelper::yD0(candidate1); + auto phiCandidate1 = candidate1.phi(); + float const massD0Cand1 = HfHelper::invMassD0ToPiK(candidate1); + float const 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; } - bool isSignalD0Cand1 = std::abs(massD0Cand1 - MassD0) < massCut; - bool isSignalD0barCand1 = std::abs(massD0barCand1 - MassD0Bar) < massCut; + bool const isSignalD0Cand1 = std::abs(massD0Cand1 - MassD0) < massCut; + bool const isSignalD0barCand1 = std::abs(massD0barCand1 - MassD0Bar) < massCut; if (selectSignalRegionOnly && !(isSignalD0Cand1 || isSignalD0barCand1)) { continue; } - if (!(candidate1.isSelD0() >= selectionFlagD0 || candidate1.isSelD0bar() >= selectionFlagD0bar)) { + if (candidate1.isSelD0() < selectionFlagD0 && candidate1.isSelD0bar() < selectionFlagD0bar) { continue; } auto candidateType1 = assignCandidateTypeD0(candidate1); // Candidate type attribution - bool isDCand1 = isD(candidateType1); - bool isDbarCand1 = isDbar(candidateType1); - bool isTrueDCand1 = isTrueD(candidateType1); - bool isTrueDbarCand1 = isTrueDbar(candidateType1); + bool const isDCand1 = isD(candidateType1); + bool const isDbarCand1 = isDbar(candidateType1); + bool const isTrueDCand1 = isTrueD(candidateType1); + bool const isTrueDbarCand1 = isTrueDbar(candidateType1); 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) && candidate1.pt() < ptMaxRemoveAmbiguous) { + 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 == RecoDecay::Prompt) { + registry.fill(HIST("hMassMcRecPrompt"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt()); + registry.fill(HIST("hPtVsYVsNContribMcRecPrompt"), candidate1.pt(), HfHelper::yD0(candidate1), collision.numContrib()); + } else if (originRec1 == RecoDecay::NonPrompt) { + 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 == RecoDecay::Prompt) { + registry.fill(HIST("hMassMcRecPrompt"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt()); + } else if (originRec1 == RecoDecay::NonPrompt) { + 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) { - auto ptCandidate2 = candidate2.pt(); - auto yCandidate2 = hfHelper.yD0(candidate2); - float massD0Cand2 = hfHelper.invMassD0ToPiK(candidate2); - float massD0barCand2 = hfHelper.invMassD0barToKPi(candidate2); - auto prong0Cand2 = candidate2.template prong0_as(); - auto prong1Cand2 = candidate2.template prong1_as(); - if (abs(hfHelper.yD0(candidate2)) > yCandMax) { + outputMlD0Cand2.clear(); + outputMlD0barCand2.clear(); + + auto ptCandidate2 = candidate2.pt(); + auto yCandidate2 = HfHelper::yD0(candidate2); + auto phiCandidate2 = candidate2.phi(); + float const massD0Cand2 = HfHelper::invMassD0ToPiK(candidate2); + float const 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; } - bool isSignalD0Cand2 = std::abs(massD0Cand2 - MassD0) < massCut; - bool isSignalD0barCand2 = std::abs(massD0barCand2 - MassD0Bar) < massCut; + bool const isSignalD0Cand2 = std::abs(massD0Cand2 - MassD0) < massCut; + bool const isSignalD0barCand2 = std::abs(massD0barCand2 - MassD0Bar) < massCut; if (selectSignalRegionOnly && !(isSignalD0Cand2 || isSignalD0barCand2)) { continue; } - if (!(candidate2.isSelD0() >= selectionFlagD0 || candidate2.isSelD0bar() >= selectionFlagD0bar)) { + if (candidate2.isSelD0() < selectionFlagD0 && candidate2.isSelD0bar() < selectionFlagD0bar) { continue; } if (daughterTracksCutFlag && ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2))) { @@ -572,63 +881,67 @@ struct HfCorrelatorDMesonPairs { } auto candidateType2 = assignCandidateTypeD0(candidate2); // Candidate type attribution - bool isDCand2 = isD(candidateType2); - bool isDbarCand2 = isDbar(candidateType2); - bool isTrueDCand2 = isTrueD(candidateType2); - bool isTrueDbarCand2 = isTrueDbar(candidateType2); + bool const isDCand2 = isD(candidateType2); + bool const isDbarCand2 = isDbar(candidateType2); + bool const isTrueDCand2 = isTrueD(candidateType2); + bool const isTrueDbarCand2 = isTrueDbar(candidateType2); 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) && candidate2.pt() < ptMaxRemoveAmbiguous) { + continue; + } + + // Fill tables + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, phiCandidate1, phiCandidate2, + ptCandidate1, ptCandidate2, massD0Cand1, massD0barCand1, massD0Cand2, massD0barCand2); + fillMcHistos(matchedRec1, matchedRec2, static_cast(isTrueDCand1), static_cast(isTrueDbarCand1), static_cast(isTrueDCand2), static_cast(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, static_cast(isTrueDCand1), static_cast(isTrueDbarCand1), static_cast(isTrueDCand2), static_cast(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(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, - ptCandidate1, ptCandidate2, massD0Cand1, massD0barCand1, massD0Cand2, massD0barCand2); - 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 const 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) { @@ -636,15 +949,15 @@ 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) { continue; } auto particleType = assignParticleTypeD0Gen(particle); // Candidate type attribution - bool isDParticle = isTrueD(particleType); - bool isDbarParticle = isTrueDbar(particleType); + bool const isDParticle = isTrueD(particleType); + bool const isDbarParticle = isTrueDbar(particleType); if (isDParticle) { nDevent++; } @@ -681,7 +994,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) { @@ -692,8 +1005,8 @@ struct HfCorrelatorDMesonPairs { registry.fill(HIST("hPtCandAfterCutMcGen"), particle1.pt()); auto particleType1 = assignParticleTypeD0Gen(particle1); // Candidate sign attribution - bool isDParticle1 = isTrueD(particleType1); - bool isDbarParticle1 = isTrueDbar(particleType1); + bool const isDParticle1 = isTrueD(particleType1); + bool const isDbarParticle1 = isTrueDbar(particleType1); // check if it's MC matched int8_t matchedGen1 = particle1.flagMcMatchGen(); @@ -712,12 +1025,21 @@ struct HfCorrelatorDMesonPairs { registry.fill(HIST("hStatusSinglePartMcGen"), 4); } + registry.fill(HIST("hPtVsYVsNContribMcGen"), particle1.pt(), particle1.y(), numPvContributorsGen); + if (originGen1 == RecoDecay::Prompt) { + registry.fill(HIST("hPtVsYVsNContribMcGenPrompt"), particle1.pt(), particle1.y(), numPvContributorsGen); + } + if (originGen1 == RecoDecay::NonPrompt) { + 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) { @@ -725,8 +1047,8 @@ struct HfCorrelatorDMesonPairs { } // Candidate sign attribution. auto particleType2 = assignParticleTypeD0Gen(particle2); - bool isDParticle2 = isTrueD(particleType2); - bool isDbarParticle2 = isTrueDbar(particleType2); + bool const isDParticle2 = isTrueD(particleType2); + bool const isDbarParticle2 = isTrueDbar(particleType2); // check if it's MC matched int8_t matchedGen2 = particle2.flagMcMatchGen(); @@ -735,18 +1057,18 @@ struct HfCorrelatorDMesonPairs { // Fill hMatchingMcGen - Cand 1 registry.fill(HIST("hMatchingMcGen"), 1); - if (matchedGen1 == 1) { + if (matchedGen1 == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { registry.fill(HIST("hMatchingMcGen"), 2); - } else if (matchedGen1 == -1) { + } else if (matchedGen1 == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { registry.fill(HIST("hMatchingMcGen"), 3); } else if (matchedGen1 == 0) { registry.fill(HIST("hMatchingMcGen"), 4); } // Fill hMatchingMcRec - Cand 2 registry.fill(HIST("hMatchingMcGen"), 5); - if (matchedGen2 == 1) { + if (matchedGen2 == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { registry.fill(HIST("hMatchingMcGen"), 6); - } else if (matchedGen2 == -1) { + } else if (matchedGen2 == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { registry.fill(HIST("hMatchingMcGen"), 7); } else if (matchedGen2 == 0) { registry.fill(HIST("hMatchingMcGen"), 8); @@ -790,11 +1112,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..14eed44af7f 100644 --- a/PWGHF/HFC/TableProducer/correlatorDplusDminus.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDplusDminus.cxx @@ -9,23 +9,39 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file HfCorrelatorDplusDminus.cxx +/// \file correlatorDplusDminus.cxx /// \brief Dplus-Dminus correlator task - data-like, MC-reco and MC-kine analyses. For ULS and LS pairs /// /// \author Fabio Colamaria , INFN Bari -#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 "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include using namespace o2; using namespace o2::analysis; @@ -48,9 +64,9 @@ 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}; +const auto efficiencyDmesonV = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsMassAndEfficiency}; // histogram binning definition const int massAxisBins = 120; @@ -80,9 +96,8 @@ struct HfCorrelatorDplusDminus { 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_v}, "Efficiency values for Dplus meson"}; + Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmesonV}, "Efficiency values for Dplus meson"}; - HfHelper hfHelper; SliceCache cache; Preslice perCol = aod::hf_cand::collisionId; @@ -162,19 +177,19 @@ struct HfCorrelatorDplusDminus { auto selectedDPlusCandidatesGrouped = selectedDPlusCandidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); for (const auto& candidate1 : selectedDPlusCandidatesGrouped) { - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(candidate1)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yDplus(candidate1)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { continue; } // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { // probably dummy since already selected? not sure... + if ((candidate1.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) == 0) { // probably dummy since already selected? not sure... continue; } double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); } @@ -186,11 +201,11 @@ struct HfCorrelatorDplusDminus { // fill invariant mass plots and generic info from all Dplus/Dminus candidates if (outerParticleSign == 1) { - registry.fill(HIST("hMass"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMassDplus"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMass"), HfHelper::invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassDplus"), HfHelper::invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); } else { - registry.fill(HIST("hMass"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); - registry.fill(HIST("hMassDminus"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMass"), HfHelper::invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassDminus"), HfHelper::invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); } registry.fill(HIST("hPtCand"), candidate1.pt()); registry.fill(HIST("hPtProng0"), candidate1.ptProng0()); @@ -198,7 +213,7 @@ struct HfCorrelatorDplusDminus { registry.fill(HIST("hPtProng2"), candidate1.ptProng2()); registry.fill(HIST("hEta"), candidate1.eta()); registry.fill(HIST("hPhi"), candidate1.phi()); - registry.fill(HIST("hY"), hfHelper.yDplus(candidate1)); + registry.fill(HIST("hY"), HfHelper::yDplus(candidate1)); registry.fill(HIST("hSelectionStatus"), candidate1.isSelDplusToPiKPi()); // D-Dbar correlation dedicated section @@ -208,14 +223,14 @@ struct HfCorrelatorDplusDminus { } for (const auto& candidate2 : selectedDPlusCandidatesGrouped) { // check decay channel flag for candidate2 - if (!(candidate2.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { // probably dummy since already selected? not sure... + if ((candidate2.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) == 0) { // probably dummy since already selected? not sure... continue; } auto innerSecondTrack = candidate2.prong1_as(); if (innerSecondTrack.sign() != 1) { // keep only Dminus (with second daughter track positive) continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(candidate2)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yDplus(candidate2)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { @@ -225,8 +240,8 @@ struct HfCorrelatorDplusDminus { candidate2.eta() - candidate1.eta(), candidate1.pt(), candidate2.pt()); - entryDplusDminusRecoInfo(hfHelper.invMassDplusToPiKPi(candidate1), - hfHelper.invMassDplusToPiKPi(candidate2), + entryDplusDminusRecoInfo(HfHelper::invMassDplusToPiKPi(candidate1), + HfHelper::invMassDplusToPiKPi(candidate2), 0); double etaCut = 0.; double ptCut = 0.; @@ -241,7 +256,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); @@ -275,10 +290,10 @@ struct HfCorrelatorDplusDminus { bool flagDminusSignal = false; for (const auto& candidate1 : selectedDPlusCandidatesGroupedMC) { // check decay channel flag for candidate1 - if (!(candidate1.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { + if ((candidate1.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) == 0) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(candidate1)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yDplus(candidate1)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { @@ -286,7 +301,7 @@ struct HfCorrelatorDplusDminus { } double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { efficiencyWeight = 1. / efficiencyD->at(o2::analysis::findBin(binsPt, candidate1.pt())); } @@ -295,12 +310,12 @@ struct HfCorrelatorDplusDminus { if (outerSecondTrack.sign() == 1) { outerParticleSign = -1; // Dminus (second daughter track is positive) } - if (std::abs(candidate1.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) { + if (std::abs(candidate1.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { // fill invariant mass plots and per-candidate distributions from Dplus/Dminus signal candidates if (outerParticleSign == 1) { // reco and matched as Dplus - registry.fill(HIST("hMassDplusMCRecSig"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassDplusMCRecSig"), HfHelper::invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); } else { // reco and matched as Dminus - registry.fill(HIST("hMassDminusMCRecSig"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassDminusMCRecSig"), HfHelper::invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); } registry.fill(HIST("hPtCandMCRec"), candidate1.pt()); registry.fill(HIST("hPtProng0MCRec"), candidate1.ptProng0()); @@ -308,14 +323,14 @@ struct HfCorrelatorDplusDminus { registry.fill(HIST("hPtProng2MCRec"), candidate1.ptProng2()); registry.fill(HIST("hEtaMCRec"), candidate1.eta()); registry.fill(HIST("hPhiMCRec"), candidate1.phi()); - registry.fill(HIST("hYMCRec"), hfHelper.yDplus(candidate1)); + registry.fill(HIST("hYMCRec"), HfHelper::yDplus(candidate1)); registry.fill(HIST("hSelectionStatusMCRec"), candidate1.isSelDplusToPiKPi()); } else { // fill invariant mass plots from Dplus/Dminus background candidates if (outerParticleSign == 1) { // reco as Dplus - registry.fill(HIST("hMassDplusMCRecBkg"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassDplusMCRecBkg"), HfHelper::invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); } else { // matched as Dminus - registry.fill(HIST("hMassDminusMCRecBkg"), hfHelper.invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); + registry.fill(HIST("hMassDminusMCRecBkg"), HfHelper::invMassDplusToPiKPi(candidate1), candidate1.pt(), efficiencyWeight); } } @@ -323,17 +338,17 @@ struct HfCorrelatorDplusDminus { if (outerParticleSign == -1) { continue; // reject Dminus in outer loop } - flagDplusSignal = std::abs(candidate1.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi; // flagDplusSignal 'true' if candidate1 matched to Dplus + flagDplusSignal = std::abs(candidate1.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi; // flagDplusSignal 'true' if candidate1 matched to Dplus for (const auto& candidate2 : selectedDPlusCandidatesGroupedMC) { - if (!(candidate2.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { // check decay channel flag for candidate2 + if ((candidate2.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) == 0) { // check decay channel flag for candidate2 continue; } auto innerSecondTrack = candidate2.prong1_as(); if (innerSecondTrack.sign() != 1) { // keep only Dminus (with second daughter track positive) continue; } - flagDminusSignal = std::abs(candidate2.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi; // flagDminusSignal 'true' if candidate2 matched to Dminus - if (yCandMax >= 0. && std::abs(hfHelper.yDplus(candidate2)) > yCandMax) { + flagDminusSignal = std::abs(candidate2.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi; // flagDminusSignal 'true' if candidate2 matched to Dminus + if (yCandMax >= 0. && std::abs(HfHelper::yDplus(candidate2)) > yCandMax) { continue; } if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { @@ -351,8 +366,8 @@ struct HfCorrelatorDplusDminus { candidate2.eta() - candidate1.eta(), candidate1.pt(), candidate2.pt()); - entryDplusDminusRecoInfo(hfHelper.invMassDplusToPiKPi(candidate1), - hfHelper.invMassDplusToPiKPi(candidate2), + entryDplusDminusRecoInfo(HfHelper::invMassDplusToPiKPi(candidate1), + HfHelper::invMassDplusToPiKPi(candidate2), pairSignalStatus); double etaCut = 0.; double ptCut = 0.; @@ -384,7 +399,7 @@ struct HfCorrelatorDplusDminus { if (std::abs(particle1.pdgCode()) != Pdg::kDPlus) { continue; } - double yD = RecoDecay::y(particle1.pVector(), MassDPlus); + double const yD = RecoDecay::y(particle1.pVector(), MassDPlus); if (yCandMax >= 0. && std::abs(yD) > yCandMax) { continue; } @@ -425,7 +440,7 @@ struct HfCorrelatorDplusDminus { // fill pairs vs etaCut plot bool rightDecayChannels = false; - if ((std::abs(particle1.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) && (std::abs(particle2.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi)) { + if ((std::abs(particle1.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) && (std::abs(particle2.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) { rightDecayChannels = true; } do { @@ -458,7 +473,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); @@ -475,13 +490,13 @@ struct HfCorrelatorDplusDminus { if (std::abs(particle1.pdgCode()) != PDG_t::kCharm) { // search c or cbar particles continue; } - int partMothPDG = particle1.mothers_as().front().pdgCode(); + int const partMothPDG = particle1.mothers_as().front().pdgCode(); // check whether mothers of quark c/cbar are still '4'/'-4' particles - in that case the c/cbar quark comes from its own fragmentation, skip it if (partMothPDG == particle1.pdgCode()) { continue; } counterCCbarBeforeEtasel++; // count c or cbar (before kinematic selection) - double yC = RecoDecay::y(particle1.pVector(), MassCharm); + double const yC = RecoDecay::y(particle1.pVector(), MassCharm); if (yCandMax >= 0. && std::abs(yC) > yCandMax) { continue; } @@ -522,8 +537,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 b254504ff60..37fdb8acea8 100644 --- a/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx @@ -10,23 +10,46 @@ // or submit itself to any jurisdiction. /// \file correlatorDplusHadrons.cxx +/// \brief D+-Hadrons correlator task - data-like, MC-reco and MC-Gen analyses /// \author Shyam Kumar -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/Centrality.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -43,8 +66,8 @@ 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; -std::vector efficiencyDmeson(npTBinsMassAndEfficiency + 1); +const int npTBinsMassAndEfficiency = o2::analysis::hf_cuts_dplus_to_pi_k_pi::NBinsPt; +const std::vector efficiencyDmeson(npTBinsMassAndEfficiency + 1); // definition of ME variables using BinningType = ColumnBinningPolicy>; @@ -61,7 +84,6 @@ struct HfCorrelatorDplusHadronsDplusSelection { Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; - HfHelper hfHelper; SliceCache cache; using SelCollisions = soa::Join; @@ -81,7 +103,7 @@ struct HfCorrelatorDplusHadronsDplusSelection { bool isNosameBunchPileUp = true; if (doSelDplusCollision) { for (const auto& candidate : candidates) { - if (std::abs(hfHelper.yDplus(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + if (std::abs(HfHelper::yDplus(candidate)) > yCandMax || candidate.pt() < ptCandMin) { isDplusFound = false; continue; } @@ -93,7 +115,7 @@ struct HfCorrelatorDplusHadronsDplusSelection { isSel8 = collision.sel8(); } if (selNoSameBunchPileUpColl) { - isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + isNosameBunchPileUp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); } isSelColl = isDplusFound && isSel8 && isNosameBunchPileUp; dplusSel(isSelColl); @@ -109,10 +131,10 @@ struct HfCorrelatorDplusHadronsDplusSelection { bool isNosameBunchPileUp = true; if (doSelDplusCollision) { for (const auto& candidate : candidates) { - if (std::abs(hfHelper.yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin) { + if (std::abs(HfHelper::yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin) { continue; } - isDplusFound = 1; + isDplusFound = true; break; } } @@ -120,7 +142,7 @@ struct HfCorrelatorDplusHadronsDplusSelection { isSel8 = collision.sel8(); } if (selNoSameBunchPileUpColl) { - isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + isNosameBunchPileUp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); } isSelColl = isDplusFound && isSel8 && isNosameBunchPileUp; dplusSel(isSelColl); @@ -131,16 +153,16 @@ struct HfCorrelatorDplusHadronsDplusSelection { void processDplusSelectionMcGen(aod::McCollision const&, CandDplusMcGen const& mcParticles) { - bool isDplusFound = 0; + bool isDplusFound = false; for (const auto& particle1 : mcParticles) { if (std::abs(particle1.pdgCode()) != Pdg::kDPlus) { continue; } - double yD = RecoDecay::y(particle1.pVector(), MassDPlus); + double const yD = RecoDecay::y(particle1.pVector(), MassDPlus); if (std::abs(yD) >= yCandMax || particle1.pt() <= ptCandMin) { continue; } - isDplusFound = 1; + isDplusFound = true; break; } dplusSel(isDplusFound); @@ -159,10 +181,13 @@ struct HfCorrelatorDplusHadrons { Produces entryTrackRecoInfo; Produces entryDplus; Produces entryHadron; + static constexpr std::size_t NDaughters{3u}; + static constexpr float EtaDaughtersMax = 0.8f; // Eta cut on daughters of D+ meson as Run2 Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for Dplus"}; // 7 corresponds to topo+PID cuts Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; - Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying D-meson efficiency weights"}; + 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"}; @@ -179,19 +204,8 @@ struct HfCorrelatorDplusHadrons { 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>; @@ -212,25 +226,32 @@ struct HfCorrelatorDplusHadrons { 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 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; - + 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})"}; + BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { AxisSpec axisMassD = {binsMassD, "inv. mass (pi^{+}K^{-}#pi^{+}) (GeV/#it{c}^{2})"}; - AxisSpec axisEta = {binsEta, "#it{#eta}"}; - AxisSpec axisPhi = {binsPhi, "#it{#varphi}"}; + AxisSpec const axisEta = {binsEta, "#it{#eta}"}; + AxisSpec const 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 const 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"}; + AxisSpec const axisPosZ = {binsZVtx, "PosZ"}; + AxisSpec const axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec const axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec const axisStatus = {15, 0.5, 15.5, "Selection status"}; + AxisSpec const 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}}); @@ -318,31 +339,31 @@ struct HfCorrelatorDplusHadrons { int cntDplus = 0; std::vector outputMl = {-1., -1., -1.}; for (const auto& candidate : candidates) { - if (std::abs(hfHelper.yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptCandMax) { + if (std::abs(HfHelper::yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptCandMax) { continue; } - int effBinD = o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()); + int const effBinD = o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()); double efficiencyWeightD = 1.; if (applyEfficiency) { efficiencyWeightD = 1. / efficiencyD->at(effBinD); } // fill invariant mass plots and generic info from all Dplus candidates - registry.fill(HIST("hMassDplus_2D"), hfHelper.invMassDplusToPiKPi(candidate), candidate.pt(), efficiencyWeightD); - registry.fill(HIST("hMassDplusData"), hfHelper.invMassDplusToPiKPi(candidate), efficiencyWeightD); + 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("hY"), HfHelper::yDplus(candidate)); registry.fill(HIST("hSelectionStatus"), candidate.isSelDplusToPiKPi()); registry.fill(HIST("hDplusBin"), poolBin); 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); + entryDplusCandRecoInfo(HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); // 0: BkgBDTScore, 1:PromptBDTScore, 2: FDScore + 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 @@ -352,16 +373,18 @@ struct HfCorrelatorDplusHadrons { continue; } // Removing Dplus daughters by checking track indices - if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { - continue; + if (removeDaughters) { + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { + continue; + } } entryDplusHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), candidate.pt(), track.pt(), poolBin); - entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(candidate), false); + entryDplusHadronRecoInfo(HfHelper::invMassDplusToPiKPi(candidate), false); entryDplusHadronGenInfo(false, false, 0); - entryDplusHadronMlInfo(outputMl[0], outputMl[1]); + entryDplusHadronMlInfo(outputMl[0], outputMl[1], outputMl[2]); entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); if (cntDplus == 0) { entryHadron(track.phi(), track.eta(), track.pt(), poolBin, gCollisionId, timeStamp); @@ -399,45 +422,49 @@ struct HfCorrelatorDplusHadrons { } registry.fill(HIST("hMultiplicity"), nTracks); - float multiplicityFT0M = collision.multFT0M(); + float const multiplicityFT0M = collision.multFT0M(); // MC reco level - bool isDplusPrompt = false; - bool isDplusNonPrompt = false; - bool flagDplusSignal = false; for (const auto& candidate : candidates) { // rapidity and pT selections - if (std::abs(hfHelper.yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptCandMax) { + if (std::abs(HfHelper::yDplus(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptCandMax) { + continue; + } + // Remove D+ candidates for which at least one daughter has |eta| > 0.8 + double etaDaugh1 = RecoDecay::eta(std::array{candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()}); + double etaDaugh2 = RecoDecay::eta(std::array{candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()}); + double etaDaugh3 = RecoDecay::eta(std::array{candidate.pxProng2(), candidate.pyProng2(), candidate.pzProng2()}); + if (std::abs(etaDaugh1) >= EtaDaughtersMax || std::abs(etaDaugh2) >= EtaDaughtersMax || std::abs(etaDaugh3) >= EtaDaughtersMax) { continue; } // efficiency weight determination - int effBinD = o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()); + int const effBinD = o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()); double efficiencyWeightD = 1.; if (applyEfficiency) { efficiencyWeightD = 1. / efficiencyD->at(effBinD); } // Dplus flag - flagDplusSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi; + bool isDplusSignal = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi; // prompt and non-prompt division - isDplusPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; - isDplusNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + bool isDplusPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + bool isDplusNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; std::vector outputMl = {-1., -1., -1.}; // fill invariant mass plots from Dplus signal and background candidates - registry.fill(HIST("hMassDplusMcRec"), hfHelper.invMassDplusToPiKPi(candidate), efficiencyWeightD); + registry.fill(HIST("hMassDplusMcRec"), HfHelper::invMassDplusToPiKPi(candidate), efficiencyWeightD); registry.fill(HIST("hDplusBin"), poolBin); - if (flagDplusSignal) { + 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("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("hYMCRecSig"), HfHelper::yDplus(candidate)); registry.fill(HIST("hPhiMcRecSig"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); // prompt and non-prompt division @@ -452,14 +479,14 @@ struct HfCorrelatorDplusHadrons { 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]); + registry.fill(HIST("hMassDplusMcRecSig"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), efficiencyWeightD); + entryDplusCandRecoInfo(HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); entryDplusCandGenInfo(isDplusPrompt); } else { 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("hMassDplusMcRecBkg"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), efficiencyWeightD); } // Dplus-Hadron correlation dedicated section @@ -472,15 +499,17 @@ struct HfCorrelatorDplusHadrons { continue; } // Removing Dplus daughters by checking track indices - if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { - continue; + if (removeDaughters) { + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { + continue; + } } entryDplusHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), candidate.pt(), track.pt(), poolBin); - entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(candidate), flagDplusSignal); - entryDplusHadronMlInfo(outputMl[0], outputMl[1]); + entryDplusHadronRecoInfo(HfHelper::invMassDplusToPiKPi(candidate), isDplusSignal); + entryDplusHadronMlInfo(outputMl[0], outputMl[1], outputMl[2]); if (track.has_mcParticle()) { auto mcParticle = track.template mcParticle_as(); isPhysicalPrimary = mcParticle.isPhysicalPrimary(); @@ -512,50 +541,60 @@ struct HfCorrelatorDplusHadrons { int counterDplusHadron = 0; registry.fill(HIST("hMCEvtCount"), 0); - BinningTypeMcGen corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; + BinningTypeMcGen const corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); - registry.fill(HIST("hCollisionPoolBin"), poolBin); registry.fill(HIST("hMultFT0AMcGen"), mcCollision.multMCFT0A()); - bool isDplusPrompt = 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 (std::abs(particle1.flagMcMatchGen()) != hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { + continue; + } + double const yD = RecoDecay::y(particle1.pVector(), MassDPlus); if (std::abs(yD) >= yCandMax || particle1.pt() <= ptCandMin) { continue; } + std::vector listDaughters{}; + std::array const arrDaughDplusPDG = {+kPiPlus, -kKPlus, kPiPlus}; + std::array prongsId{}; + listDaughters.clear(); + RecoDecay::getDaughters(particle1, &listDaughters, arrDaughDplusPDG, 2); + int counterDaughters = 0; + if (listDaughters.size() != NDaughters) + continue; + bool isDaughtersOk = true; + for (const auto& dauIdx : listDaughters) { + auto daughI = mcParticles.rawIteratorAt(dauIdx - mcParticles.offset()); + if (std::abs(daughI.eta()) >= EtaDaughtersMax) { + isDaughtersOk = false; + break; + } + counterDaughters += 1; + prongsId[counterDaughters - 1] = daughI.globalIndex(); + } + if (!isDaughtersOk) + continue; // Skip this D+ candidate if any daughter fails eta cut + counterDplusHadron++; + + 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(), -PIHalf)); registry.fill(HIST("hYMCGen"), yD); // prompt and non-prompt division - isDplusPrompt = particle1.originMcGen() == RecoDecay::OriginType::Prompt; + bool isDplusPrompt = particle1.originMcGen() == RecoDecay::OriginType::Prompt; + bool isDplusNonPrompt = particle1.originMcGen() == RecoDecay::OriginType::NonPrompt; if (isDplusPrompt) { registry.fill(HIST("hPtCandMcGenPrompt"), particle1.pt()); - } else { + } 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 registry.fill(HIST("hcountDplustriggersMCGen"), 0, particle1.pt()); // to count trigger Dplus for normalisation) @@ -563,8 +602,10 @@ struct HfCorrelatorDplusHadrons { 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 (removeDaughters) { + 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; @@ -583,7 +624,7 @@ struct HfCorrelatorDplusHadrons { entryDplusHadronRecoInfo(MassDPlus, true); entryDplusHadronGenInfo(isDplusPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); } // end associated loop - } // end trigger + } // end trigger registry.fill(HIST("hcountDplusHadronPerEvent"), counterDplusHadron); registry.fill(HIST("hZvtx"), mcCollision.posZ()); // registry.fill(HIST("hMultiplicity"), getTracksSize(mcCollision)); @@ -595,18 +636,18 @@ struct HfCorrelatorDplusHadrons { TracksData const& tracks) { auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairData{corrBinning, 5, -1, collisions, tracksTuple, &cache}; + Pair const 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 (!assocParticle.isGlobalTrackWoDCA() || std::abs(hfHelper.yDplus(trigDplus)) >= yCandMax) { + 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); - entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(trigDplus), 0); + entryDplusHadronRecoInfo(HfHelper::invMassDplusToPiKPi(trigDplus), 0); } } } @@ -617,17 +658,17 @@ struct HfCorrelatorDplusHadrons { TracksWithMc const& tracks, aod::McParticles const& mcParticles) { - BinningType corrBinning{{binsZVtx, binsMultiplicityMc}, true}; + BinningType const corrBinning{{binsZVtx, binsMultiplicityMc}, true}; for (const auto& candidate : candidates) { - if (std::abs(hfHelper.yDplus(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + if (std::abs(HfHelper::yDplus(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } // Dplus flag - bool flagDplusSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi; + bool const isDplusSignal = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi; // prompt and non-prompt division - bool isDplusPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; - bool isDplusNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; - if (flagDplusSignal) { + bool const isDplusPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + bool const isDplusNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + if (isDplusSignal) { if (isDplusPrompt) { registry.fill(HIST("hPtCandMcRecSigPrompt"), candidate.pt()); registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), candidate.pt(), 0); @@ -642,17 +683,17 @@ struct HfCorrelatorDplusHadrons { } } auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair const 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())); - int poolBinDplus = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())); + int const 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) { + if (std::abs(HfHelper::yDplus(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } if (!pAssoc.isGlobalTrackWoDCA()) { @@ -661,7 +702,7 @@ struct HfCorrelatorDplusHadrons { std::vector outputMl = {-1., -1., -1.}; bool isPhysicalPrimary = false; int trackOrigin = -1; - bool flagDplusSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi; + bool isDplusSignal = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi; // prompt and non-prompt division bool isDplusPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; if (pAssoc.has_mcParticle()) { @@ -676,12 +717,12 @@ struct HfCorrelatorDplusHadrons { candidate.pt(), pAssoc.pt(), poolBin); - entryDplusHadronRecoInfo(hfHelper.invMassDplusToPiKPi(candidate), flagDplusSignal); + 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]); + entryDplusHadronMlInfo(outputMl[0], outputMl[1], outputMl[2]); entryTrackRecoInfo(pAssoc.dcaXY(), pAssoc.dcaZ(), pAssoc.tpcNClsCrossedRows()); } } @@ -691,16 +732,16 @@ struct HfCorrelatorDplusHadrons { void processMcGenMixedEvent(SelCollisionsWithDplusMc const& collisions, CandDplusMcGen const& mcParticles) { - BinningTypeMcGen corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; + BinningTypeMcGen const corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; auto tracksTuple = std::make_tuple(mcParticles, mcParticles); - Pair pairMcGen{corrBinningMcGen, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair const 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.pdgCode()) != Pdg::kDPlus) { continue; } - double yD = RecoDecay::y(candidate.pVector(), MassDPlus); + double const yD = RecoDecay::y(candidate.pVector(), MassDPlus); if (std::abs(yD) > yCandGenMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } diff --git a/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx index 016c672f50e..8d224319170 100644 --- a/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx @@ -14,21 +14,49 @@ /// \author Grazia Luparello /// \author Samuele Cattaruzzi -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" +#include "PWGHF/Utils/utilsAnalysis.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/Centrality.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -36,6 +64,14 @@ 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; + +enum ResonantChannel : int8_t { + PhiPi = 1, + Kstar0K = 2 +}; + +static std::unordered_map channelsResonant = {{{ResonantChannel::PhiPi, hf_decay::hf_cand_3prong::DecayChannelResonant::DsToPhiPi}, {ResonantChannel::Kstar0K, hf_decay::hf_cand_3prong::DecayChannelResonant::DsToKstar0K}}}; /// Returns deltaPhi value in range [-pi/2., 3.*pi/2], typically used for correlation studies double getDeltaPhi(double phiHadron, double phiD) @@ -59,7 +95,6 @@ struct HfCorrelatorDsHadronsSelCollision { Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; SliceCache cache; - HfHelper hfHelper; using SelCollisions = soa::Join; using CandDsData = soa::Filtered>; @@ -76,8 +111,9 @@ struct HfCorrelatorDsHadronsSelCollision { 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) { + if (std::abs(HfHelper::yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin) { isDsFound = false; continue; } @@ -89,7 +125,7 @@ struct HfCorrelatorDsHadronsSelCollision { isSel8 = collision.sel8(); } if (selNoSameBunchPileUpColl) { - isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + isNosameBunchPileUp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); } isSelColl = isDsFound && isSel8 && isNosameBunchPileUp; collisionsWithSelDs(isSelColl); @@ -106,7 +142,7 @@ struct HfCorrelatorDsHadronsSelCollision { 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) { + if (std::abs(HfHelper::yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin) { isDsFound = false; continue; } @@ -118,7 +154,7 @@ struct HfCorrelatorDsHadronsSelCollision { isSel8 = collision.sel8(); } if (selNoSameBunchPileUpColl) { - isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + isNosameBunchPileUp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); } isSelColl = isDsFound && isSel8 && isNosameBunchPileUp; collisionsWithSelDs(isSelColl); @@ -135,16 +171,23 @@ struct HfCorrelatorDsHadrons { Produces entryDsCandRecoInfo; Produces entryDsCandGenInfo; Produces entryTrackRecoInfo; + 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"}; - Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; + 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 pidTrkApplied{"pidTrkApplied", false, "Apply PID selection for associated tracks"}; + Configurable forceTOF{"forceTOF", false, "force the TOF signal for the PID"}; 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 decayChannel{"decayChannel", 1, "Decay channels: 1 for Ds->PhiPi->KKpi, 2 for Ds->K0*K->KKPi"}; + Configurable decayChannel{"decayChannel", 1, "Resonant 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"}; @@ -155,37 +198,51 @@ struct HfCorrelatorDsHadrons { Configurable ptCandMax{"ptCandMax", 50., "max. cand pT"}; Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; Configurable ptTrackMax{"ptTrackMax", 50., "max. track pT"}; + Configurable zVtxMax{"zVtxMax", 10., "max. position-z of the reconstructed collision"}; + Configurable tofPIDThreshold{"tofPIDThreshold", 0.75, "minimum pT after which TOF PID is applicable"}; Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; + 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> binsPtD{"binsPtD", std::vector{o2::analysis::hf_cuts_ds_to_k_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_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 binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; - HfHelper hfHelper; + int hfcReducedCollisionIndex = 0; + static constexpr std::size_t NDaughtersDs{3u}; + SliceCache cache; 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 - using MyTracksData = soa::Filtered>; // trackFilter applied - using TracksWithMc = soa::Filtered>; // trackFilter applied + using CandDsData = soa::Filtered>; // flagDsFilter applied + using CandDsMcReco = soa::Filtered>; // flagDsFilter applied + using CandDsMcGen = soa::Join; // flagDsFilter applied + using MyTracksData = soa::Filtered>; // trackFilter applied + using TracksWithMc = soa::Filtered>; // trackFilter applied Filter collisionFilter = aod::hf_selection_dmeson_collision::dmesonSel == true; 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&) @@ -195,13 +252,15 @@ struct HfCorrelatorDsHadrons { 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 const axisMultiplicity = {binsMultiplicity, "Multiplicity"}; AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; - AxisSpec axisPosZ = {binsPosZ, "PosZ"}; - AxisSpec axisPoolBin = {binsPoolBin, "PoolBin"}; - AxisSpec axisStatus = {15, 0.5, 15.5, "Selection status"}; + AxisSpec const axisPosZ = {binsPosZ, "PosZ"}; + AxisSpec const axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec const axisStatus = {15, 0.5, 15.5, "Selection status"}; + const AxisSpec axisPid{20, -10.f, 10.f, "n #sigma"}; // Histograms for data analysis + registry.add("hCollisionPoolBin", "Ds candidates collision pool bin", {HistType::kTH1F, {axisPoolBin}}); if (fillHistoData) { registry.add("hPtCand", "Ds candidates pt", {HistType::kTH1F, {axisPtD}}); registry.add("hSelectionStatusDsToKKPi", "Ds candidates selection", {HistType::kTH1F, {axisStatus}}); @@ -218,9 +277,22 @@ struct HfCorrelatorDsHadrons { 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}}); + if (pidTrkApplied) { + registry.add("hTpcTofNSigmaPreSelPidPion", "n sigma tpc and tof for pion hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPreSelPidKaon", "n sigma tpc and tof for kaon hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPreSelPidProton", "n sigma tpc and tof for proton hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPreSelPidPionM2", "n sigma tpc and tof for pion hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPreSelPidKaonM2", "n sigma tpc and tof for kaon hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPreSelPidProtonM2", "n sigma tpc and tof for proton hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPidPion", "n sigma tpc and tof for pion hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPidKaon", "n sigma tpc and tof for kaon hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPidProton", "n sigma tpc and tof for proton hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPidPionM2", "n sigma tpc and tof for pion hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPidKaonM2", "n sigma tpc and tof for kaon hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + registry.add("hTpcTofNSigmaPidProtonM2", "n sigma tpc and tof for proton hypothesis", {HistType::kTH3F, {{axisPid}, {axisPid}, {axisPtHadron}}}); + } } // Histograms for MC Reco analysis if (fillHistoMcRec) { @@ -255,6 +327,17 @@ struct HfCorrelatorDsHadrons { 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}}); + registry.add("hCorrAllPrimaryParticles", "Ds-ch. part. correlations MC Gen", {HistType::kTH3F, {{axisPhi}, {axisPtD}, {axisPtHadron}}}); + registry.add("hCorrAllPrimaryHadrons", "Ds-h correlations MC Gen", {HistType::kTH3F, {{axisPhi}, {axisPtD}, {axisPtHadron}}}); + registry.add("hCorrAllPrimaryPions", "Ds-pion correlations MC Gen", {HistType::kTH3F, {{axisPhi}, {axisPtD}, {axisPtHadron}}}); + registry.add("hCorrAllPrimaryKaons", "Ds-kaon correlations MC Gen", {HistType::kTH3F, {{axisPhi}, {axisPtD}, {axisPtHadron}}}); + registry.add("hCorrAllPrimaryProtons", "Ds-proton correlations MC Gen", {HistType::kTH3F, {{axisPhi}, {axisPtD}, {axisPtHadron}}}); + registry.add("hFakeCollision", "Fake collision counter", {HistType::kTH1F, {{1, -0.5, 0.5, "n fake coll"}}}); + if (pidTrkApplied) { + registry.add("hCorrKaonsLSPairs", "Ds-kaon correlations LS MC Gen", {HistType::kTH3F, {{axisPhi}, {axisPtD}, {axisPtHadron}}}); + registry.add("hCorrKaonsULSPairs", "Ds-kaon correlations ULS MC Gen", {HistType::kTH3F, {{axisPhi}, {axisPtD}, {axisPtHadron}}}); + registry.add("hDsWoKaons", "Collisions with Ds mesons without kaons", {HistType::kTH1F, {{1, -0.5, 0.5, "n coll w/o kaons"}}}); + } } } @@ -276,8 +359,8 @@ struct HfCorrelatorDsHadrons { template void fillHistoKKPi(const T1& candidate, double efficiencyWeight) { - registry.fill(HIST("hMassDsVsPt"), hfHelper.invMassDsToKKPi(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hMassDsData"), hfHelper.invMassDsToKKPi(candidate), efficiencyWeight); + registry.fill(HIST("hMassDsVsPt"), HfHelper::invMassDsToKKPi(candidate), candidate.pt(), efficiencyWeight); + registry.fill(HIST("hMassDsData"), HfHelper::invMassDsToKKPi(candidate), efficiencyWeight); registry.fill(HIST("hSelectionStatusDsToKKPi"), candidate.isSelDsToKKPi()); } @@ -287,8 +370,8 @@ struct HfCorrelatorDsHadrons { template void fillHistoPiKK(const T1& candidate, double efficiencyWeight) { - registry.fill(HIST("hMassDsVsPt"), hfHelper.invMassDsToPiKK(candidate), candidate.pt(), efficiencyWeight); - registry.fill(HIST("hMassDsData"), hfHelper.invMassDsToPiKK(candidate), efficiencyWeight); + registry.fill(HIST("hMassDsVsPt"), HfHelper::invMassDsToPiKK(candidate), candidate.pt(), efficiencyWeight); + registry.fill(HIST("hMassDsData"), HfHelper::invMassDsToPiKK(candidate), efficiencyWeight); registry.fill(HIST("hSelectionStatusDsToPiKK"), candidate.isSelDsToPiKK()); } @@ -344,23 +427,25 @@ struct HfCorrelatorDsHadrons { CandDsData const& candidates, MyTracksData const& tracks) { - BinningType corrBinning{{zPoolBins, multPoolBins}, true}; + BinningType const corrBinning{{zPoolBins, multPoolBins}, true}; registry.fill(HIST("hZVtx"), collision.posZ()); registry.fill(HIST("hMultFT0M"), collision.multFT0M()); int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); registry.fill(HIST("hCollisionPoolBin"), poolBin); - int nTracks = tracks.size(); + int const nTracks = tracks.size(); registry.fill(HIST("hMultiplicity"), nTracks); // Ds fill histograms and Ds-Hadron correlation for DsToKKPi for (const auto& candidate : candidates) { - if (std::abs(hfHelper.yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + if (std::abs(HfHelper::yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } double efficiencyWeightD = 1.; if (applyEfficiency) { efficiencyWeightD = 1. / efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())); } + auto prong0 = candidate.template prong0_as(); + int const chargeDs = prong0.sign(); std::vector outputMl = {-1., -1., -1.}; fillHisto(candidate); if (candidate.isSelDsToKKPi() >= selectionFlagDs) { @@ -368,13 +453,13 @@ struct HfCorrelatorDsHadrons { for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; } - entryDsCandRecoInfo(hfHelper.invMassDsToKKPi(candidate), candidate.pt(), outputMl[0], outputMl[2]); + entryDsCandRecoInfo(HfHelper::invMassDsToKKPi(candidate), candidate.pt() * chargeDs, outputMl[0], outputMl[2], collision.numContrib()); } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { fillHistoPiKK(candidate, efficiencyWeightD); for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; } - entryDsCandRecoInfo(hfHelper.invMassDsToPiKK(candidate), candidate.pt(), outputMl[0], outputMl[2]); + entryDsCandRecoInfo(HfHelper::invMassDsToPiKK(candidate), candidate.pt() * chargeDs, outputMl[0], outputMl[2], collision.numContrib()); } if (candidate.isSelDsToKKPi() >= selectionFlagDs && candidate.isSelDsToPiKK() >= selectionFlagDs) { registry.fill(HIST("hCountSelectionStatusDsToKKPiAndToPiKK"), 0.); @@ -395,26 +480,28 @@ struct HfCorrelatorDsHadrons { if (candidate.isSelDsToKKPi() >= selectionFlagDs) { entryDsHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), - candidate.pt(), - track.pt(), - poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(candidate), false, false); - entryDsHadronGenInfo(false, false, 0); + candidate.pt() * chargeDs, + track.pt() * track.sign(), + poolBin, + collision.numContrib()); + 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) { entryDsHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), - candidate.pt(), - track.pt(), - poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(candidate), false, false); - entryDsHadronGenInfo(false, false, 0); + candidate.pt() * chargeDs, + track.pt() * track.sign(), + poolBin, + collision.numContrib()); + 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); @@ -424,27 +511,24 @@ struct HfCorrelatorDsHadrons { TracksWithMc const& tracks, aod::McParticles const& mcParticles) { - BinningType corrBinning{{zPoolBins, multPoolBins}, true}; + BinningType const corrBinning{{zPoolBins, multPoolBins}, true}; registry.fill(HIST("hZVtx"), collision.posZ()); registry.fill(HIST("hMultFT0M"), collision.multFT0M()); int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); registry.fill(HIST("hCollisionPoolBin"), poolBin); // MC reco level - bool isDsPrompt = false; - bool isDsSignal = false; bool isCorrectInvMassHypo = false; - bool isDecayChan = false; bool isAlreadyFilledEvent = false; - float multiplicityFT0M = collision.multFT0M(); + float const multiplicityFT0M = collision.multFT0M(); for (const auto& candidate : candidates) { // prompt and non-prompt division - isDsPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + bool isDsPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; // Ds Signal - isDsSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi; - isDecayChan = candidate.flagMcDecayChanRec() == decayChannel; + bool isDsSignal = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK; + bool isDecayChan = candidate.flagMcDecayChanRec() == channelsResonant[decayChannel]; - if (std::abs(hfHelper.yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + if (std::abs(HfHelper::yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } @@ -457,6 +541,8 @@ struct HfCorrelatorDsHadrons { } std::vector outputMl = {-1., -1., -1.}; + auto prong0 = candidate.template prong0_as(); + int const chargeDs = prong0.sign(); if (isDsSignal && isDecayChan && isCorrectInvMassHypo) { fillHistoMcRecSig(candidate, multiplicityFT0M); @@ -464,21 +550,21 @@ struct HfCorrelatorDsHadrons { 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("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("hSelectionStatusDsToKKPiMcRec"), candidate.isSelDsToKKPi()); - entryDsCandRecoInfo(hfHelper.invMassDsToKKPi(candidate), candidate.pt(), outputMl[0], outputMl[2]); + entryDsCandRecoInfo(HfHelper::invMassDsToKKPi(candidate), candidate.pt() * chargeDs, outputMl[0], outputMl[2], collision.numContrib()); 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("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("hSelectionStatusDsToPiKKMcRec"), candidate.isSelDsToPiKK()); - entryDsCandRecoInfo(hfHelper.invMassDsToPiKK(candidate), candidate.pt(), outputMl[0], outputMl[2]); + entryDsCandRecoInfo(HfHelper::invMassDsToPiKK(candidate), candidate.pt() * chargeDs, outputMl[0], outputMl[2], collision.numContrib()); entryDsCandGenInfo(isDsPrompt); } } else { @@ -487,17 +573,17 @@ struct HfCorrelatorDsHadrons { 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("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("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()); } } @@ -513,20 +599,20 @@ struct HfCorrelatorDsHadrons { continue; } bool isPhysicalPrimary = false; - int trackOrigin = -1; // DsToKKPi and DsToPiKK division 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, isDecayChan); + candidate.pt() * chargeDs, + track.pt() * track.sign(), + poolBin, + collision.numContrib()); + entryDsHadronRecoInfo(HfHelper::invMassDsToKKPi(candidate), isDsSignal, isDecayChan); entryDsHadronMlInfo(outputMl[0], outputMl[2]); if (track.has_mcParticle()) { auto mcParticle = track.template mcParticle_as(); isPhysicalPrimary = mcParticle.isPhysicalPrimary(); - trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + auto trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary, trackOrigin); } else { entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary, 0); @@ -543,15 +629,16 @@ struct HfCorrelatorDsHadrons { } 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, isDecayChan); + candidate.pt() * chargeDs, + track.pt() * track.sign(), + poolBin, + collision.numContrib()); + entryDsHadronRecoInfo(HfHelper::invMassDsToPiKK(candidate), isDsSignal, isDecayChan); entryDsHadronMlInfo(outputMl[0], outputMl[2]); if (track.has_mcParticle()) { auto mcParticle = track.template mcParticle_as(); isPhysicalPrimary = mcParticle.isPhysicalPrimary(); - trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + auto trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); entryDsHadronGenInfo(isDsPrompt, isPhysicalPrimary, trackOrigin); } else { entryDsHadronGenInfo(isDsPrompt, false, 0); @@ -572,15 +659,12 @@ struct HfCorrelatorDsHadrons { } PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcRec, "Process MC Reco mode", false); - Preslice perCollisionCandMc = o2::aod::mcparticle::mcCollisionId; - PresliceUnsorted> collPerCollMc = o2::aod::mccollisionlabel::mcCollisionId; - /// 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) { - BinningTypeMcGen corrBinningMcGen{{zPoolBins, multPoolBins}, true}; + BinningTypeMcGen const corrBinningMcGen{{zPoolBins, multPoolBins}, true}; for (const auto& mcCollision : mcCollisions) { @@ -607,7 +691,7 @@ struct HfCorrelatorDsHadrons { if (useSel8 && !collision.sel8()) { continue; } - if (std::abs(collision.posZ()) > 10.) { + if (std::abs(collision.posZ()) > zVtxMax) { continue; } if (selNoSameBunchPileUpColl && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { @@ -625,29 +709,40 @@ struct HfCorrelatorDsHadrons { // 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(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && (particle.flagMcDecayChanGen() == channelsResonant[decayChannel])) { + double const 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; + isDecayChan = particle.flagMcDecayChanGen() == channelsResonant[decayChannel]; std::vector listDaughters{}; - std::array arrDaughDsPDG = {+kKPlus, -kKPlus, kPiPlus}; - std::array prongsId; + std::array const arrDaughDsPDG = {+kKPlus, -kKPlus, kPiPlus}; + std::array prongsId{}; listDaughters.clear(); RecoDecay::getDaughters(particle, &listDaughters, arrDaughDsPDG, 2); int counterDaughters = 0; - if (listDaughters.size() == 3) { + int chargeDs = 0; + if (listDaughters.size() == NDaughtersDs) { for (const auto& dauIdx : listDaughters) { // auto daughI = mcParticles.rawIteratorAt(dauIdx - mcParticles.offset()); auto daughI = groupedMcParticles.rawIteratorAt(dauIdx - groupedMcParticles.offset()); counterDaughters += 1; + if (counterDaughters == 1) { + if (daughI.pdgCode() == kKPlus) { + chargeDs = 1; + } else { + chargeDs = -1; + } + } prongsId[counterDaughters - 1] = daughI.globalIndex(); } } + + int numberOfCorrKaons = 0; + // Ds Hadron correlation dedicated section for (const auto& particleAssoc : groupedMcParticles) { if (std::abs(particleAssoc.eta()) > etaTrackMax || particleAssoc.pt() < ptTrackMin || particleAssoc.pt() > ptTrackMax) { @@ -662,6 +757,31 @@ struct HfCorrelatorDsHadrons { if (!particleAssoc.isPhysicalPrimary()) { continue; } + + if (isDsPrompt) { + registry.fill(HIST("hCorrAllPrimaryParticles"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + if (std::abs(particleAssoc.pdgCode()) == kPiPlus) { + registry.fill(HIST("hCorrAllPrimaryHadrons"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + registry.fill(HIST("hCorrAllPrimaryPions"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + } else if (std::abs(particleAssoc.pdgCode()) == kKPlus) { + registry.fill(HIST("hCorrAllPrimaryHadrons"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + registry.fill(HIST("hCorrAllPrimaryKaons"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + } else if (std::abs(particleAssoc.pdgCode()) == kProton) { + registry.fill(HIST("hCorrAllPrimaryHadrons"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + registry.fill(HIST("hCorrAllPrimaryProtons"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + } + if (pidTrkApplied) { + if (((chargeDs == 1) && (particleAssoc.pdgCode() == kKPlus)) || ((chargeDs == -1) && (particleAssoc.pdgCode() == kKMinus))) { // LS pairs + registry.fill(HIST("hCorrKaonsLSPairs"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + numberOfCorrKaons++; + } + if (((chargeDs == 1) && (particleAssoc.pdgCode() == kKMinus)) || ((chargeDs == -1) && (particleAssoc.pdgCode() == kKPlus))) { // ULS pairs + registry.fill(HIST("hCorrKaonsULSPairs"), getDeltaPhi(particleAssoc.phi(), particle.phi()), particle.pt(), particleAssoc.pt()); + numberOfCorrKaons++; + } + } + } + // trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); trackOrigin = RecoDecay::getCharmHadronOrigin(groupedMcParticles, particleAssoc, true); registry.fill(HIST("hPtParticleAssocMcGen"), particleAssoc.pt()); @@ -669,30 +789,99 @@ struct HfCorrelatorDsHadrons { particleAssoc.eta() - particle.eta(), particle.pt(), particleAssoc.pt(), - poolBin); + poolBin, + 0); entryDsHadronRecoInfo(MassDS, true, isDecayChan); entryDsHadronGenInfo(isDsPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + } // end loop generated particles + if (numberOfCorrKaons == 0) { + registry.fill(HIST("hDsWoKaons"), numberOfCorrKaons); } - } - } + } // if statement for Ds selection + } // end loop generated Ds } // end loop reconstructed collision - } // end loop generated collision + } // end loop generated collision } PROCESS_SWITCH(HfCorrelatorDsHadrons, processMcGen, "Process MC Gen mode", false); + void processDerivedDataDs(SelCollisionsWithDs const& collisions, + CandDsData const& candidates, + MyTracksData const& tracks) + { + + for (const auto& collision : collisions) { + auto thisCollId = collision.globalIndex(); + auto candsDsThisColl = candidates.sliceBy(candsDsPerCollision, thisCollId); + auto tracksThisColl = tracks.sliceBy(trackIndicesPerCollision, thisCollId); + + int indexHfcReducedCollision = collReduced.lastIndex() + 1; + + // Ds fill histograms and Ds candidates information stored + for (const auto& candidate : candsDsThisColl) { + std::vector outputMl = {-1., -1., -1.}; + auto prong0 = candidate.template prong0_as(); + int const chargeDs = prong0.sign(); + // candidate selected + if (candidate.isSelDsToKKPi() >= selectionFlagDs) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; + } + candReduced(indexHfcReducedCollision, candidate.phi(), candidate.eta(), candidate.pt() * chargeDs, 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)]; + } + candReduced(indexHfcReducedCollision, candidate.phi(), candidate.eta(), candidate.pt() * chargeDs, 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; + } + registry.fill(HIST("hTpcTofNSigmaPreSelPidPion"), track.tpcNSigmaPi(), track.tofNSigmaPi(), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPreSelPidKaon"), track.tpcNSigmaKa(), track.tofNSigmaKa(), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPreSelPidProton"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPreSelPidPionM2"), o2::aod::pidutils::tpcNSigma(o2::track::PID::Pion, track), o2::aod::pidutils::tofNSigma(o2::track::PID::Pion, track), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPreSelPidKaonM2"), o2::aod::pidutils::tpcNSigma(o2::track::PID::Kaon, track), o2::aod::pidutils::tofNSigma(o2::track::PID::Kaon, track), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPreSelPidProtonM2"), o2::aod::pidutils::tpcNSigma(o2::track::PID::Proton, track), o2::aod::pidutils::tofNSigma(o2::track::PID::Proton, track), track.pt()); + + if (pidTrkApplied) { + if (!passPIDSelection(track, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) { + continue; + } + registry.fill(HIST("hTpcTofNSigmaPidPion"), track.tpcNSigmaPi(), track.tofNSigmaPi(), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPidKaon"), track.tpcNSigmaKa(), track.tofNSigmaKa(), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPidProton"), track.tpcNSigmaPr(), track.tofNSigmaPr(), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPidPionM2"), o2::aod::pidutils::tpcNSigma(o2::track::PID::Pion, track), o2::aod::pidutils::tofNSigma(o2::track::PID::Pion, track), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPidKaonM2"), o2::aod::pidutils::tpcNSigma(o2::track::PID::Kaon, track), o2::aod::pidutils::tofNSigma(o2::track::PID::Kaon, track), track.pt()); + registry.fill(HIST("hTpcTofNSigmaPidProtonM2"), o2::aod::pidutils::tpcNSigma(o2::track::PID::Proton, track), o2::aod::pidutils::tofNSigma(o2::track::PID::Proton, track), track.pt()); + } + assocTrackReduced(indexHfcReducedCollision, track.globalIndex(), track.phi(), track.eta(), track.pt() * track.sign()); + assocTrackSelInfo(indexHfcReducedCollision, track.tpcNClsCrossedRows(), track.itsClusterMap(), track.itsNCls(), track.dcaXY(), track.dcaZ()); + } + + collReduced(collision.multFT0M(), collision.numContrib(), collision.posZ()); + } + } + PROCESS_SWITCH(HfCorrelatorDsHadrons, processDerivedDataDs, "Process derived data Ds", false); + // Event Mixing void processDataME(SelCollisionsWithDs const& collisions, CandDsData const& candidates, MyTracksData const& tracks) { - BinningType corrBinning{{zPoolBins, multPoolBins}, true}; + BinningType const corrBinning{{zPoolBins, multPoolBins}, true}; 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, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair const pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, tracks1, c2, tracks2] : pairData) { if (tracks1.size() == 0) { @@ -701,30 +890,33 @@ struct HfCorrelatorDsHadrons { // 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()))); int poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); - int poolBinDs = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())); + int const poolBinDs = corrBinning.getBin(std::make_tuple(c1.posZ(), c1.multFT0M())); registry.fill(HIST("hTracksPoolBin"), poolBin); // note that the selections here are not yet applied registry.fill(HIST("hDsPoolBin"), poolBinDs); // note that the selections here are not yet applied for (const auto& [cand, pAssoc] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (!(cand.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DsToKKPi)) { + if ((cand.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) == 0) { continue; } - if (std::abs(hfHelper.yDs(cand)) > yCandMax || cand.pt() < ptCandMin || cand.pt() > ptCandMax) { + if (std::abs(HfHelper::yDs(cand)) > yCandMax || cand.pt() < ptCandMin || cand.pt() > ptCandMax) { continue; } if (!pAssoc.isGlobalTrackWoDCA()) { continue; } + auto prong0 = cand.template prong0_as(); + int const chargeDs = prong0.sign(); std::vector outputMl = {-1., -1., -1.}; // DsToKKPi and DsToPiKK division if (cand.isSelDsToKKPi() >= selectionFlagDs) { // LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d), KKPi", cand.index(), pAssoc.index(), c1.index(), c2.index(), cand.collision().index(), pAssoc.collision().index()); entryDsHadronPair(getDeltaPhi(pAssoc.phi(), cand.phi()), pAssoc.eta() - cand.eta(), - cand.pt(), - pAssoc.pt(), - poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(cand), false, false); - entryDsHadronGenInfo(false, false, 0); + cand.pt() * chargeDs, + pAssoc.pt() * pAssoc.sign(), + poolBin, + c1.numContrib()); + 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)]; } @@ -734,11 +926,12 @@ struct HfCorrelatorDsHadrons { // LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d), PiKK", cand.index(), pAssoc.index(), c1.index(), c2.index(), cand.collision().index(), pAssoc.collision().index()); entryDsHadronPair(getDeltaPhi(pAssoc.phi(), cand.phi()), pAssoc.eta() - cand.eta(), - cand.pt(), - pAssoc.pt(), - poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToPiKK(cand), false, false); - entryDsHadronGenInfo(false, false, 0); + cand.pt() * chargeDs, + pAssoc.pt() * pAssoc.sign(), + poolBin, + c1.numContrib()); + 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)]; } @@ -755,16 +948,14 @@ struct HfCorrelatorDsHadrons { TracksWithMc const& tracks, aod::McParticles const& mcParticles) { - BinningType corrBinning{{zPoolBins, multPoolBins}, true}; + BinningType const corrBinning{{zPoolBins, multPoolBins}, true}; for (const auto& candidate : candidates) { - if (std::abs(hfHelper.yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + if (std::abs(HfHelper::yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } - if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) { + if (std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) { // DsToKKPi and DsToPiKK division - if (candidate.isSelDsToKKPi() >= selectionFlagDs) { - fillHistoMcRecSig(candidate, 0.); - } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { + if (candidate.isSelDsToKKPi() >= selectionFlagDs || candidate.isSelDsToPiKK() >= selectionFlagDs) { fillHistoMcRecSig(candidate, 0.); } } else { @@ -772,7 +963,7 @@ struct HfCorrelatorDsHadrons { } } auto tracksTuple = std::make_tuple(candidates, tracks); - Pair pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair const pairMcRec{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; bool isDsPrompt = false; bool isDsSignal = false; @@ -781,23 +972,25 @@ struct HfCorrelatorDsHadrons { 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())); + int const poolBinDs = 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("hDsPoolBin"), poolBinDs); // 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.yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { + if (std::abs(HfHelper::yDs(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } if (!pAssoc.isGlobalTrackWoDCA()) { continue; } + auto prong0 = candidate.template prong0_as(); + int const chargeDs = prong0.sign(); std::vector outputMl = {-1., -1., -1.}; // prompt and non-prompt division isDsPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; // Ds Signal - isDsSignal = std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DsToKKPi; + isDsSignal = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK; isDecayChan = candidate.flagMcDecayChanRec() == decayChannel; if (pAssoc.has_mcParticle()) { auto mcParticle = pAssoc.template mcParticle_as(); @@ -810,10 +1003,11 @@ struct HfCorrelatorDsHadrons { if (candidate.isSelDsToKKPi() >= selectionFlagDs) { entryDsHadronPair(getDeltaPhi(pAssoc.phi(), candidate.phi()), pAssoc.eta() - candidate.eta(), - candidate.pt(), - pAssoc.pt(), - poolBin); - entryDsHadronRecoInfo(hfHelper.invMassDsToKKPi(candidate), isDsSignal, isDecayChan); + candidate.pt() * chargeDs, + pAssoc.pt() * pAssoc.sign(), + poolBin, + c1.numContrib()); + 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)]; @@ -823,10 +1017,11 @@ struct HfCorrelatorDsHadrons { } 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, isDecayChan); + candidate.pt() * chargeDs, + pAssoc.pt() * pAssoc.sign(), + poolBin, + c1.numContrib()); + 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)]; @@ -842,14 +1037,14 @@ struct HfCorrelatorDsHadrons { void processMcGenME(SelCollisionsMc const& collisions, CandDsMcGen const& mcParticles) { - BinningTypeMcGen corrBinningMcGen{{zPoolBins, multPoolBins}, true}; + BinningTypeMcGen const corrBinningMcGen{{zPoolBins, multPoolBins}, true}; auto tracksTuple = std::make_tuple(mcParticles, mcParticles); - Pair pairMcGen{corrBinningMcGen, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair const 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(candidate.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && (candidate.flagMcDecayChanGen() == decayChannel)) { + double const yD = RecoDecay::y(candidate.pVector(), MassDS); if (std::abs(yD) > yCandGenMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } @@ -868,7 +1063,8 @@ struct HfCorrelatorDsHadrons { particleAssoc.eta() - candidate.eta(), candidate.pt(), particleAssoc.pt(), - poolBin); + poolBin, + 0); entryDsHadronRecoInfo(MassDS, true, true); entryDsHadronGenInfo(isDsPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); } diff --git a/PWGHF/HFC/TableProducer/correlatorDsHadronsReduced.cxx b/PWGHF/HFC/TableProducer/correlatorDsHadronsReduced.cxx new file mode 100644 index 00000000000..f7aa4fbc31b --- /dev/null +++ b/PWGHF/HFC/TableProducer/correlatorDsHadronsReduced.cxx @@ -0,0 +1,219 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +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 const axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec const axisPosZ = {binsPosZ, "PosZ"}; + AxisSpec const 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 const 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(), collision.numPvContrib()); + 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, + collision.numPvContrib()); + 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 const corrBinning{{zPoolBins, multPoolBins}, true}; + + for (const auto& collision : collisions) { + int const 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 const 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 const 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, + c1.numPvContrib()); + 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 ec40be09311..ff27fa3f3e9 100644 --- a/PWGHF/HFC/TableProducer/correlatorDstarHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDstarHadrons.cxx @@ -13,24 +13,60 @@ /// \author Deependra Sharma , IITB /// \author Fabrizio Grosa , CERN -// O2 -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +/// \brief Correlator for D* and hadrons. This task is used to produce table for D* and hadron pairs. -// O2Physics -#include "Common/DataModel/Multiplicity.h" - -// PWGHF +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#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; +const int nBinsPtCorrelation = 8; + +const double binsPtCorrelationsDefault[nBinsPtCorrelation + 1] = {0., 2., 4., 6., 8., 12., 16., 24., 100.}; +const 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}; +const 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}; +const 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}; +const 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}; +const auto vecSidebandRightOuterDefault = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + nBinsPtCorrelation}; + // flaging a collision if D* meson is found. struct HfCorrelatorDstarHadronsCollisionSelector { Produces collisionWDstar; @@ -39,19 +75,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,7 +109,7 @@ 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); }; @@ -102,13 +138,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; @@ -128,12 +171,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}}}}}}; @@ -145,7 +197,31 @@ struct HfCorrelatorDstarHadrons { LOGP(fatal, "One and only one process function must be enabled at a time."); } + AxisSpec const axisSpecMultFT0M{binsMultiplicity, "Multiplicity in FT0M", "multFT0M"}; + + invMassDstarParticle = -999.0; + invMassD0Particle = -999.0; + binNumber = -2; + binningScheme = {{binsZVtx, binsMultiplicity}, true}; + + registry.add("QA/hMultFT0M", "Multiplicity distribution in FT0M", {HistType::kTH1D, {axisSpecMultFT0M}}); + 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* @@ -153,20 +229,79 @@ 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); - if (candidatesPerCol.size() && tracksPerCol.size() == 0) { + if ((candidatesPerCol.size() != 0) && tracksPerCol.size() == 0) { continue; } // endif registry.fill(HIST("hTriggerColCandPairCounts"), 1); // counting number of trigger particle + registry.fill(HIST("QA/hMultFT0M"), collision.multFT0M()); + 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 const 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))) { @@ -176,7 +311,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) { @@ -188,12 +323,9 @@ struct HfCorrelatorDstarHadrons { } // endif registry.fill(HIST("hTriggerColCandPairCounts"), 2); // counting number of pairs - - auto binNumber = binningScheme.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); - - // Inv Mass of Dstar and D0 Candidate - float invMassDstarParticle = -999.; - float invMassD0Particle = -999.; + 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(); @@ -217,28 +349,7 @@ struct HfCorrelatorDstarHadrons { assocParticle.pt(), timestamp, binNumber); - - if (enableSeparateTables) { - rowsDstar(collision.globalIndex(), - gItriggerParticle, - triggerParticle.phi(), - triggerParticle.eta(), - triggerParticle.pt(), - invMassDstarParticle, - invMassD0Particle, - timestamp, - binNumber); - - rowsAssoTrack(assocParticle.phi(), - assocParticle.eta(), - assocParticle.pt(), - binNumber, - collision.globalIndex(), - timestamp); - } - } // D-H pair loop - } // collision loop } // processDataSameEvent @@ -251,28 +362,20 @@ struct HfCorrelatorDstarHadrons { { auto dstarHadronTuple = std::make_tuple(candidates, tracks); - Pair pairData{binningScheme, 5, -1, collisions, dstarHadronTuple, &cache}; + Pair const 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())); - - // Inv Mass of Dstar and D0 Candidate - float invMassDstarParticle = -999.; - float invMassD0Particle = -999.; + binNumber = binningScheme.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); if (triggerParticle.signSoftPi() > 0) { invMassDstarParticle = triggerParticle.invMassDstar(); diff --git a/PWGHF/HFC/TableProducer/correlatorFlowCharmHadronsReduced.cxx b/PWGHF/HFC/TableProducer/correlatorFlowCharmHadronsReduced.cxx new file mode 100644 index 00000000000..e6a55f8625b --- /dev/null +++ b/PWGHF/HFC/TableProducer/correlatorFlowCharmHadronsReduced.cxx @@ -0,0 +1,646 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file correlatorFlowCharmHadronsReduced.cxx +/// \brief CharmHadrons-Hadrons correlator tree creator for data analyses +/// \author Marcello Di Costanzo , Politecnico and INFN Torino + +#include "PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#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; + +using BinningCentPosZ = ColumnBinningPolicy; +using BinningMultPosZ = ColumnBinningPolicy; + +/// Get charm candidate or hadron track pT +/// \param track is the candidate +template +double getPt(const TTrack& track) +{ + if constexpr (requires { track.ptAssoc(); }) { + return track.ptAssoc(); + } else { + return track.ptTrig(); + } +} + +/// Get charm candidate or hadron track eta +/// \param track is the candidate +template +double getEta(const TTrack& track) +{ + if constexpr (requires { track.etaAssoc(); }) { + return track.etaAssoc(); + } else { + return track.etaTrig(); + } +} + +/// Get charm candidate or hadron track phi +/// \param track is the candidate +template +double getPhi(const TTrack& track) +{ + if constexpr (requires { track.phiAssoc(); }) { + return track.phiAssoc(); + } else { + return track.phiTrig(); + } +} + +struct HfCorrelatorFlowCharmHadronsReduced { + // Produces rowPairSECharmHads; //! Correlation pairs information Same Event + // Produces rowPairMECharmHads; //! Correlation pairs information Mixed Event + // Produces rowPairSEHadHads; //! Correlation pairs information Same Event + // Produces rowPairMEHadHads; //! Correlation pairs information Mixed Event + // Produces rowCollInfos; //! Collision info + + Configurable fillSparses{"fillSparses", true, "Fill sparse histograms"}; + Configurable fillTables{"fillTables", false, "Fill tables"}; + Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; + Configurable> binsPtTrig{"binsPtTrig", std::vector{0., 3., 5., 8., 16., 36.}, "pT bin limits for trigger candidates"}; + Configurable> bdtScore0PtMaxs{"bdtScore0PtMaxs", std::vector{0.1, 0.1, 0.1, 0.1, 0.1}, "pT-differential maximum score 0 for charm candidates"}; + Configurable> bdtScore1PtMins{"bdtScore1PtMins", std::vector{0.1, 0.1, 0.1, 0.1, 0.1}, "pT-differential minimum score 1 for charm candidates"}; + Configurable> binsPtAssoc{"binsPtAssoc", std::vector{0.3, 1., 2., 50.}, "pT bin limits for associated particles"}; + Configurable centralityMin{"centralityMin", 0, "min. centrality"}; + Configurable centralityMax{"centralityMax", 10., "max. centrality"}; + Configurable deltaEtaAbsMin{"deltaEtaAbsMin", 0.5, "min. pair delta eta"}; + Configurable deltaEtaAbsMax{"deltaEtaAbsMax", 2., "max. pair delta eta"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. track DCA XY"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. track DCA Z"}; + Configurable tpcCrossedRowsMin{"tpcCrossedRowsMin", 1, "min. TPC crossed rows"}; + Configurable itsNClsMin{"itsNClsMin", 1, "min. ITS clusters"}; + Configurable downSamplePairs{"downSamplePairs", 1., "Fraction of pairs to keep"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + Configurable centMaxForDownSample{"centMaxForDownSample", 10., "Maximum centrality for the application of the downsampling factor"}; + + SliceCache cache; + + int poolBins{0}; + + using SameEvtPairsChHad = soa::Filtered>; + using SameEvtPairsHadHad = soa::Filtered>; + using AssocTracks = soa::Filtered>; + using TrigCharmCands = soa::Join; + + Filter filterAssocTracks = (nabs(aod::hf_correl_charm_had_reduced::dcaXYAssoc) < dcaXYTrackMax) && (nabs(aod::hf_correl_charm_had_reduced::dcaZAssoc) < dcaZTrackMax) && (aod::hf_correl_charm_had_reduced::nTpcCrossedRowsAssoc > tpcCrossedRowsMin) && (aod::hf_correl_charm_had_reduced::itsNClsAssoc > itsNClsMin); + Filter filterTrigTracks = (nabs(aod::hf_correl_charm_had_reduced::dcaXYTrig) < dcaXYTrackMax) && (nabs(aod::hf_correl_charm_had_reduced::dcaZTrig) < dcaZTrackMax) && (aod::hf_correl_charm_had_reduced::nTpcCrossedRowsTrig > tpcCrossedRowsMin) && (aod::hf_correl_charm_had_reduced::itsNClsTrig > itsNClsMin); + Filter filterSameEvtPairs = (nabs(aod::hf_correl_charm_had_reduced::deltaEta) > deltaEtaAbsMin) && (nabs(aod::hf_correl_charm_had_reduced::deltaEta) < deltaEtaAbsMax); + + Preslice assocTracksPerCol = aod::hf_correl_charm_had_reduced::hfcRedCorrCollId; + Preslice trigCharmCandsPerCol = aod::hf_correl_charm_had_reduced::hfcRedCorrCollId; + + 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 centPoolBins{"centPoolBins", {VARIABLE_WIDTH, 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100}, "Event centrality pools"}; + ConfigurableAxis binsInvMass{"binsInvMass", {300, 1.6, 2.2}, "Invariant mass bins"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {100, 0., 10000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsCent{"binsCent", {100, 0., 100.}, "Centrality bins"}; + ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "Primary vertex z coordinate"}; + ConfigurableAxis binsEta{"binsEta", {50, -2., 2.}, "Eta bins"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, "Phi bins"}; + ConfigurableAxis binsDeltaEta{"binsDeltaEta", {100, -2., 2.}, "Delta Eta bins"}; + ConfigurableAxis binsDeltaPhi{"binsDeltaPhi", {64, -3., 3.}, "Delta Phi bins"}; + ConfigurableAxis binsMlOne{"binsMlOne", {100, 0., 1.}, "ML score index 1 bins"}; + ConfigurableAxis binsMlTwo{"binsMlTwo", {100, 0., 1.}, "ML score index 2 bins"}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + if ((doprocessSameEventCharmHadWCentMix && doprocessMixedEventCharmHadWMultMix) || + (doprocessSameEventCharmHadWMultMix && doprocessMixedEventCharmHadWCentMix) || + (doprocessSameEventHadHadWCentMix && doprocessMixedEventHadHadWMultMix) || + (doprocessSameEventHadHadWMultMix && doprocessMixedEventHadHadWCentMix)) { + LOGP(fatal, "You cannot mix centrality and multiplicity mixing in the same processing! Please check your configuration!"); + } + if (!fillSparses && !fillTables) { + LOGP(fatal, "At least one of fillSparses or fillTables must be true!"); + } + if ((binsPtTrig.value.size() != (bdtScore0PtMaxs.value.size() + 1) || binsPtTrig.value.size() != (bdtScore1PtMins.value.size() + 1))) { + LOGP(fatal, "The size of bdtScore0PtMaxs and bdtScore1PtMins must be the one of binsPtTrig minus one!"); + } + + if (doprocessSameEventCharmHadWCentMix || doprocessSameEventHadHadWCentMix || doprocessMixedEventCharmHadWCentMix || doprocessMixedEventHadHadWCentMix) { + poolBins = (centPoolBins->size() - 2) * (zPoolBins->size() - 2); + } else { + poolBins = (multPoolBins->size() - 2) * (zPoolBins->size() - 2); + } + + const AxisSpec axisInvMass{binsInvMass, "Inv. mass (GeV/#it{c}^{2})"}; + const AxisSpec axisCent = {binsCent, "Centrality"}; + const AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + const AxisSpec axisPosZ = {binsPosZ, "PosZ"}; + const AxisSpec axisPoolBin = {poolBins, 0., static_cast(poolBins), "PoolBin"}; + const AxisSpec axisDeltaEta = {binsDeltaEta, "#Delta#it{#eta}"}; + const AxisSpec axisDeltaPhi = {binsDeltaPhi, "#Delta#it{#varphi}"}; + const AxisSpec axisPtTrig = {(std::vector)binsPtTrig, "#it{p}_{T} Trig (GeV/#it{c})"}; + const AxisSpec axisPtAssoc = {(std::vector)binsPtAssoc, "#it{p}_{T} Assoc (GeV/#it{c})"}; + const AxisSpec axisMlOne{binsMlOne, "bdtScore0"}; + const AxisSpec axisMlTwo{binsMlTwo, "bdtScore1"}; + + // Histograms for data analysis + if (doprocessSameEventCharmHadWCentMix || doprocessSameEventHadHadWCentMix) { + registry.add("hCentPoolBinSE", "Centrality SE", {HistType::kTH2F, {{axisCent}, {axisPoolBin}}}); + } else if (doprocessSameEventCharmHadWMultMix || doprocessSameEventHadHadWMultMix) { + registry.add("hMultFT0MPoolBinSE", "Multiplicity FT0M SE", {HistType::kTH2F, {{axisMultFT0M}, {axisPoolBin}}}); + } else if (doprocessMixedEventCharmHadWCentMix || doprocessMixedEventHadHadWCentMix) { + registry.add("hCentPoolBinME", "Centrality ME", {HistType::kTH2F, {{axisCent}, {axisPoolBin}}}); + } else if (doprocessMixedEventCharmHadWMultMix || doprocessMixedEventHadHadWMultMix) { + registry.add("hMultFT0MPoolBinME", "Multiplicity FT0M ME", {HistType::kTH2F, {{axisMultFT0M}, {axisPoolBin}}}); + } + registry.add("hZVtxPoolBinSE", "z vertex SE", {HistType::kTH2F, {{axisPosZ}, {axisPoolBin}}}); + registry.add("hZVtxPoolBinME", "z vertex ME", {HistType::kTH2F, {{axisPosZ}, {axisPoolBin}}}); + registry.add("hPoolBinTrigSE", "Trigger candidates pool bin SE", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hPoolBinTrigME", "Trigger candidates pool bin ME", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hPoolBinAssocSE", "Associated particles pool bin SE", {HistType::kTH1F, {axisPoolBin}}); + registry.add("hPoolBinAssocME", "Associated particles pool bin ME", {HistType::kTH1F, {axisPoolBin}}); + if (fillSparses) { + std::vector axesTrigger = {axisInvMass, axisPtTrig, axisMlOne, axisMlTwo}; + std::vector axes = {axisPoolBin, axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}; + if (doprocessSameEventHadHadWCentMix || doprocessSameEventHadHadWMultMix) { + registry.add("hSparseCorrelationsSEHadHad", "THn for SE Had-Had correlations", HistType::kTHnSparseF, axes); + } else if (doprocessMixedEventHadHadWCentMix || doprocessMixedEventHadHadWMultMix) { + registry.add("hSparseCorrelationsMEHadHad", "THn for ME Had-Had correlations", HistType::kTHnSparseF, axes); + } else { + axes.insert(axes.end(), {axisInvMass}); + // axes.insert(axes.end(), {axisInvMass, axisMlOne, axisMlTwo}); + if (doprocessSameEventCharmHadWCentMix || doprocessSameEventCharmHadWMultMix || doprocessSameEventCharmHadWCentMixBase) { + registry.add("hSparseCorrelationsSECharmHad", "THn for SE Charm-Had correlations", HistType::kTHnSparseF, axes); + } else if (doprocessMixedEventCharmHadWCentMix || doprocessMixedEventCharmHadWMultMix || doprocessMixedEventCharmHadWCentMixBase) { + registry.add("hSparseCorrelationsMECharmHad", "THn for ME Charm-Had correlations", HistType::kTHnSparseF, axes); + } + if (doprocessCharmTriggers) { + registry.add("hSparseTrigCandsCharm", "THn for Charm trigger candidates", HistType::kTHnSparseF, axesTrigger); + } + } + } + } + + /// Get the binning pool associated to the collision + /// \param collision is the collision + /// \param binPolicy is the binning policy for the correlation + template + int getPoolBin(const TColl& collision, const TBinningType& binPolicy) + { + int poolBin{0}; + if constexpr (std::is_same_v) { + poolBin = binPolicy.getBin(std::make_tuple(collision.posZ(), collision.centrality())); + if constexpr (IsMixedEvent) { + registry.fill(HIST("hCentPoolBinME"), collision.centrality(), poolBin); + registry.fill(HIST("hZVtxPoolBinME"), collision.posZ(), poolBin); + } else { + registry.fill(HIST("hCentPoolBinSE"), collision.centrality(), poolBin); + registry.fill(HIST("hZVtxPoolBinSE"), collision.posZ(), poolBin); + } + } else if constexpr (std::is_same_v) { + poolBin = binPolicy.getBin(std::make_tuple(collision.posZ(), collision.multiplicity())); + if constexpr (IsMixedEvent) { + registry.fill(HIST("hMultFT0MPoolBinME"), collision.multiplicity(), poolBin); + registry.fill(HIST("hZVtxPoolBinME"), collision.posZ(), poolBin); + } else { + registry.fill(HIST("hMultFT0MPoolBinSE"), collision.multiplicity(), poolBin); + registry.fill(HIST("hZVtxPoolBinSE"), collision.posZ(), poolBin); + } + } + return poolBin; + } + + /// Apply pT-differential ML BDT bkg score cut + /// \param ptTrig is the pT of the charm candidate + template + bool isSelBdtScoreCut(TCand const& cand, + double ptTrig) + { + for (size_t iPt = 0; iPt < binsPtTrig.value.size() - 1; iPt++) { + if (ptTrig >= binsPtTrig.value[iPt] && ptTrig < binsPtTrig.value[iPt + 1]) { + return (cand.bdtScore0Trig() < bdtScore0PtMaxs.value[iPt]) && (cand.bdtScore1Trig() > bdtScore1PtMins.value[iPt]); + } + } + return false; + } + + /// Save info for Same Event pairs + /// \param collisions are the selected collisions + /// \param trigCands are the selected trigger candidates + /// \param assocTracks are the selected associated tracks + /// \param binPolicy is the binning policy for the correlation + template + void fillSameEvent(TPair const& pair, + TTrigCand const& trigCand, + TBinningType binPolicy) + { + auto collision = pair.template hfcRedCorrColl_as(); + if (collision.centrality() < centralityMin || collision.centrality() > centralityMax) { + return; + } + double const ptTrig = trigCand.ptTrig(); + if constexpr (requires { trigCand.bdtScore0Trig(); }) { // ML selection on bkg score for Charm-Had case + if (!isSelBdtScoreCut(trigCand, ptTrig)) { + return; + } + } + if (downSamplePairs < 1.) { + float const pseudoRndm = ptTrig * 1000. - static_cast(ptTrig * 1000); + if (ptTrig < ptMaxForDownSample && collision.centrality() < centMaxForDownSample && pseudoRndm >= downSamplePairs) { + return; + } + } + int const poolBin = getPoolBin(collision, binPolicy); + registry.fill(HIST("hPoolBinTrigSE"), poolBin); + registry.fill(HIST("hPoolBinAssocSE"), poolBin); + // if constexpr (FillTables) { + // if constexpr (requires { trigCand.bdtScore0Trig(); }) { // Separate Charm-Had and Had-Had cases + // rowPairSECharmHads(poolBin, ptTrig, pair.ptAssoc(), pair.deltaEta(), pair.deltaPhi(), + // trigCand.invMassTrig(), trigCand.bdtScore0Trig(), trigCand.bdtScore1Trig(), + // pair.nTpcCrossedRowsAssoc(), pair.itsClsMapAssoc(), pair.itsNClsAssoc(), pair.dcaXYAssoc(), pair.dcaZAssoc()); + // } else { + // rowPairSEHadHads(poolBin, ptTrig, pair.ptAssoc(), pair.deltaEta(), pair.deltaPhi(), + // trigCand.nTpcCrossedRowsTrig(), trigCand.itsClsMapTrig(), trigCand.itsNClsTrig(), trigCand.dcaXYTrig(), trigCand.dcaZTrig(), + // pair.nTpcCrossedRowsAssoc(), pair.itsClsMapAssoc(), pair.itsNClsAssoc(), pair.dcaXYAssoc(), pair.dcaZAssoc()); + // } + // rowCollInfos(collision.multiplicity(), collision.numPvContrib(), collision.centrality()); + // } + if constexpr (FillSparses) { + if constexpr (requires { trigCand.bdtScore0Trig(); }) { // Separate Charm-Had and Had-Had cases + registry.fill(HIST("hSparseCorrelationsSECharmHad"), poolBin, ptTrig, pair.ptAssoc(), pair.deltaEta(), + pair.deltaPhi(), trigCand.invMassTrig()); // , trigCand.bdtScore0Trig(), trigCand.bdtScore1Trig()); + } else { + registry.fill(HIST("hSparseCorrelationsSEHadHad"), poolBin, ptTrig, pair.ptAssoc(), pair.deltaEta(), pair.deltaPhi()); + } + } + } + + /// Save info for Mixed Event pairs + /// \param collisions are the selected collisions + /// \param pairs are the mixed event pairs of trigger candidates and associated tracks + /// \param binPolicy is the binning policy for the correlation + template + void fillMixedEvent(TPairs const& pairs, + TBinningType binPolicy) + { + for (const auto& [trigColl, trigCands, assocColl, assocTracks] : pairs) { + if (trigCands.size() == 0 || assocTracks.size() == 0) { + continue; + } + if (trigColl.centrality() < centralityMin || trigColl.centrality() > centralityMax || + assocColl.centrality() < centralityMin || assocColl.centrality() > centralityMax) { + continue; + } + int const poolBinTrig = getPoolBin(trigColl, binPolicy); + int const poolBinAssoc = getPoolBin(assocColl, binPolicy); + if (poolBinAssoc != poolBinTrig) { + LOGF(info, "Error, poolBins are different"); + continue; + } + registry.fill(HIST("hPoolBinTrigME"), poolBinTrig); + registry.fill(HIST("hPoolBinAssocME"), poolBinAssoc); + + for (const auto& [trigCand, assocTrack] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(trigCands, assocTracks))) { + // LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", trigCand.index(), assocTrack.index(), trigColl.index(), assocColl.index(), trigCand.hfcRedFlowCollId(), assocTrack.hfcRedFlowCollId()); + double const deltaEta = getEta(assocTrack) - getEta(trigCand); + if (std::abs(deltaEta) < deltaEtaAbsMin || std::abs(deltaEta) > deltaEtaAbsMax) { + continue; + } + double const ptTrig = getPt(trigCand); + if constexpr (requires { trigCand.bdtScore0Trig(); }) { // ML selection on bkg score for Charm-Had case + if (!isSelBdtScoreCut(trigCand, ptTrig)) { + continue; + } + } + double const ptAssoc = getPt(assocTrack); + if (downSamplePairs < 1.) { + float const pseudoRndm = ptAssoc * 1000. - static_cast(ptAssoc * 1000); + if (ptTrig < ptMaxForDownSample && trigColl.centrality() < centMaxForDownSample && + assocColl.centrality() < centMaxForDownSample && pseudoRndm >= downSamplePairs) { + continue; + } + } + double const deltaPhi = RecoDecay::constrainAngle(getPhi(assocTrack) - getPhi(trigCand), -o2::constants::math::PIHalf); + // if constexpr (FillTables) { + // if constexpr (requires { trigCand.bdtScore0Trig(); }) { // Separate Charm-Had and Had-Had cases + // rowPairMECharmHads(poolBinTrig, ptTrig, ptAssoc, deltaEta, deltaPhi, + // trigCand.invMassTrig(), trigCand.bdtScore0Trig(), trigCand.bdtScore1Trig(), + // assocTrack.nTpcCrossedRowsAssoc(), assocTrack.itsClsMapAssoc(), assocTrack.itsNClsAssoc(), assocTrack.dcaXYAssoc(), assocTrack.dcaZAssoc()); + // } else { + // rowPairMEHadHads(poolBinTrig, ptTrig, ptAssoc, deltaEta, deltaPhi, + // trigCand.nTpcCrossedRowsAssoc(), trigCand.itsClsMapAssoc(), trigCand.itsNClsAssoc(), trigCand.dcaXYAssoc(), trigCand.dcaZAssoc(), + // assocTrack.nTpcCrossedRowsAssoc(), assocTrack.itsClsMapAssoc(), assocTrack.itsNClsAssoc(), assocTrack.dcaXYAssoc(), assocTrack.dcaZAssoc()); + // } + // rowCollInfos(trigColl.multiplicity(), trigColl.numPvContrib(), trigColl.centrality()); + // } + if constexpr (FillSparses) { + if constexpr (requires { trigCand.bdtScore0Trig(); }) { // Separate Charm-Had and Had-Had cases + registry.fill(HIST("hSparseCorrelationsMECharmHad"), poolBinTrig, ptTrig, ptAssoc, deltaEta, + deltaPhi, trigCand.invMassTrig()); //, trigCand.bdtScore0Trig(), trigCand.bdtScore1Trig()); + } else { + registry.fill(HIST("hSparseCorrelationsMEHadHad"), poolBinTrig, ptTrig, ptAssoc, deltaEta, deltaPhi); + } + } + } + } + } + + /// Correlations for Same Event pairs + /// \param poolBin collision pool bin based on multiplicity and z-vertex position + /// \param trigCandsThisColl are the selected trigger candidates in the collision + /// \param assocTracksThisColl are the selected associated tracks in the collision + template + void doCorrelationsSameEvent(int poolBin, + const TTrigCand& trigCandsThisColl, + const TTrackAssoc& assocTracksThisColl) + { + for (const auto& trigCand : trigCandsThisColl) { + double const ptTrig = trigCand.ptTrig(); + if constexpr (requires { trigCand.bdtScore0Trig(); }) { // ML selection on bkg score for Charm-Had case + if (!isSelBdtScoreCut(trigCand, ptTrig)) { + continue; + } + } + + for (const auto& assTrk : assocTracksThisColl) { + // TODO: Remove Ds daughters + /*if (assTrk.originTrackId() == candidate.prong0Id() || + assTrk.originTrackId() == candidate.prong1Id() || + assTrk.originTrackId() == candidate.prong2Id()) { + continue; + }*/ + // TODO: DCA cut + double deltaPhi = RecoDecay::constrainAngle(assTrk.phiAssoc() - trigCand.phiTrig(), -o2::constants::math::PIHalf); + double deltaEta = assTrk.etaAssoc() - trigCand.etaTrig(); + if constexpr (FillSparses) { + if constexpr (requires { trigCand.bdtScore0Trig(); }) { // Separate Charm-Had and Had-Had cases + registry.fill(HIST("hSparseCorrelationsSECharmHad"), poolBin, ptTrig, assTrk.ptAssoc(), deltaEta, + deltaPhi, trigCand.invMassTrig()); + } else { + registry.fill(HIST("hSparseCorrelationsSEHadHad"), poolBin, ptTrig, assTrk.ptAssoc(), deltaEta, deltaPhi); + } + } + } + } + } + + /// Correlations for Mixed Event pairs + /// \param collisions are the selected collisions + /// \param trigCands are the trigger candidates + /// \param assocTracks are the associated tracks + /// \param binPolicy is the binning policy for the correlation + template + void doCorrelationsMixedEvent(const TCollision& collisions, + const TTrigCand& trigCands, + const TTrackAssoc& assocTracks, + TBinningType binPolicy) + { + auto tracksTuple = std::make_tuple(trigCands, assocTracks); + + Pair pairData{binPolicy, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + + for (const auto& [c1, tracks1, c2, tracks2] : pairData) { + if (tracks1.size() == 0) { + continue; + } + + int poolBin = binPolicy.getBin({c2.posZ(), c2.multiplicity()}); + int poolBinTrigCand = binPolicy.getBin({c1.posZ(), c1.multiplicity()}); + + if (poolBin != poolBinTrigCand) { + LOGF(info, "Error, poolBins are different"); + continue; + } + + for (const auto& [trigCand, assTrk] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!isSelBdtScoreCut(trigCand, trigCand.ptTrig())) { + continue; + } + LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", trigCand.index(), assTrk.index(), c1.index(), c2.index(), trigCand.hfcRedCorrCollId(), assTrk.hfcRedCorrCollId()); + + double deltaPhi = RecoDecay::constrainAngle(assTrk.phiAssoc() - trigCand.phiTrig(), -o2::constants::math::PIHalf); + double deltaEta = assTrk.etaAssoc() - trigCand.etaTrig(); + if constexpr (FillSparses) { + if constexpr (requires { trigCand.bdtScore0Trig(); }) { // Separate Charm-Had and Had-Had cases + registry.fill(HIST("hSparseCorrelationsMECharmHad"), poolBin, trigCand.ptTrig(), assTrk.ptAssoc(), deltaEta, + deltaPhi, trigCand.invMassTrig()); + } else { + registry.fill(HIST("hSparseCorrelationsMEHadHad"), poolBin, trigCand.ptTrig(), assTrk.ptAssoc(), deltaEta, deltaPhi); + } + } + } + } + } + + void processSameEventCharmHadWMultMix(SameEvtPairsChHad::iterator const& pair, + aod::HfcRedTrigCharms const&, + aod::HfcRedCorrColls const&) + { + BinningMultPosZ binPolicyPosZMult{{zPoolBins, multPoolBins}, true}; + auto trigCand = pair.template hfcRedTrigCharm_as(); + if (fillSparses && fillTables) { + fillSameEvent(pair, trigCand, binPolicyPosZMult); + } else if (fillSparses) { + fillSameEvent(pair, trigCand, binPolicyPosZMult); + } else if (fillTables) { + fillSameEvent(pair, trigCand, binPolicyPosZMult); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processSameEventCharmHadWMultMix, "Process Same Event for Charm-Had with multiplicity pools", true); + + void processSameEventHadHadWMultMix(SameEvtPairsHadHad::iterator const& pair, + aod::HfcRedTrigTracks const&, + aod::HfcRedCorrColls const&) + { + BinningMultPosZ binPolicyPosZMult{{zPoolBins, multPoolBins}, true}; + auto trigCand = pair.template hfcRedTrigTrack_as(); + if (fillSparses && fillTables) { + fillSameEvent(pair, trigCand, binPolicyPosZMult); + } else if (fillSparses) { + fillSameEvent(pair, trigCand, binPolicyPosZMult); + } else if (fillTables) { + fillSameEvent(pair, trigCand, binPolicyPosZMult); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processSameEventHadHadWMultMix, "Process Same Event for Had-Had with multiplicity pools", false); + + void processSameEventCharmHadWCentMix(SameEvtPairsChHad::iterator const& pair, + aod::HfcRedTrigCharms const&, + aod::HfcRedCorrColls const&) + { + BinningCentPosZ binPolicyPosZCent{{zPoolBins, centPoolBins}, true}; + auto trigCand = pair.template hfcRedTrigCharm_as(); + if (fillSparses && fillTables) { + fillSameEvent(pair, trigCand, binPolicyPosZCent); + } else if (fillSparses) { + fillSameEvent(pair, trigCand, binPolicyPosZCent); + } else if (fillTables) { + fillSameEvent(pair, trigCand, binPolicyPosZCent); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processSameEventCharmHadWCentMix, "Process Same Event for Charm-Had with centrality pools", true); + + void processSameEventHadHadWCentMix(SameEvtPairsHadHad::iterator const& pair, + aod::HfcRedTrigTracks const&, + aod::HfcRedCorrColls const&) + { + BinningCentPosZ binPolicyPosZCent{{zPoolBins, centPoolBins}, true}; + auto trigCand = pair.template hfcRedTrigTrack_as(); + if (fillSparses && fillTables) { + fillSameEvent(pair, trigCand, binPolicyPosZCent); + } else if (fillSparses) { + fillSameEvent(pair, trigCand, binPolicyPosZCent); + } else if (fillTables) { + fillSameEvent(pair, trigCand, binPolicyPosZCent); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processSameEventHadHadWCentMix, "Process Same Event for Had-Had with centrality pools", false); + + void processMixedEventCharmHadWCentMix(aod::HfcRedCorrColls const& collisions, + TrigCharmCands const& candidates, + AssocTracks const& tracks) + { + BinningCentPosZ binPolicyPosZCent{{zPoolBins, centPoolBins}, true}; + auto pairsTuple = std::make_tuple(candidates, tracks); + Pair const pairs{binPolicyPosZCent, numberEventsMixed, -1, collisions, pairsTuple, &cache}; + if (fillSparses && fillTables) { + fillMixedEvent(pairs, binPolicyPosZCent); + } else if (fillSparses) { + fillMixedEvent(pairs, binPolicyPosZCent); + } else if (fillTables) { + fillMixedEvent(pairs, binPolicyPosZCent); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processMixedEventCharmHadWCentMix, "Process Mixed Event for Charm-Had with centrality pools", false); + + void processMixedEventCharmHadWMultMix(aod::HfcRedCorrColls const& collisions, + TrigCharmCands const& candidates, + AssocTracks const& tracks) + { + BinningMultPosZ binPolicyPosZMult{{zPoolBins, multPoolBins}, true}; + auto pairsTuple = std::make_tuple(candidates, tracks); + Pair const pairs{binPolicyPosZMult, numberEventsMixed, -1, collisions, pairsTuple, &cache}; + if (fillSparses && fillTables) { + fillMixedEvent(pairs, binPolicyPosZMult); + } else if (fillSparses) { + fillMixedEvent(pairs, binPolicyPosZMult); + } else if (fillTables) { + fillMixedEvent(pairs, binPolicyPosZMult); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processMixedEventCharmHadWMultMix, "Process Mixed Event for Charm-Had with multiplicity pools", false); + + void processMixedEventHadHadWCentMix(aod::HfcRedCorrColls const& collisions, + AssocTracks const& tracks) + { + BinningCentPosZ binPolicyPosZCent{{zPoolBins, centPoolBins}, true}; + auto tracksTuple = std::make_tuple(tracks); + SameKindPair const pairs{binPolicyPosZCent, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + if (fillSparses && fillTables) { + fillMixedEvent(pairs, binPolicyPosZCent); + } else if (fillSparses) { + fillMixedEvent(pairs, binPolicyPosZCent); + } else if (fillTables) { + fillMixedEvent(pairs, binPolicyPosZCent); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processMixedEventHadHadWCentMix, "Process Mixed Event for Had-Had with centrality pools", false); + + void processMixedEventHadHadWMultMix(aod::HfcRedCorrColls const& collisions, + AssocTracks const& tracks) + { + BinningMultPosZ binPolicyPosZMult{{zPoolBins, multPoolBins}, true}; + auto tracksTuple = std::make_tuple(tracks); + SameKindPair const pairs{binPolicyPosZMult, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + if (fillSparses && fillTables) { + fillMixedEvent(pairs, binPolicyPosZMult); + } else if (fillSparses) { + fillMixedEvent(pairs, binPolicyPosZMult); + } else if (fillTables) { + fillMixedEvent(pairs, binPolicyPosZMult); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processMixedEventHadHadWMultMix, "Process Mixed Event for Had-Had with multiplicity pools", false); + + void processCharmTriggers(aod::HfcRedTrigCharms const& trigCands, + aod::HfcRedCorrColls const&) + { + for (const auto& trigCand : trigCands) { + auto collision = trigCand.template hfcRedCorrColl_as(); + if (collision.centrality() < centralityMin || collision.centrality() > centralityMax) { + continue; + } + if (!isSelBdtScoreCut(trigCand, trigCand.ptTrig())) { + continue; + } + registry.fill(HIST("hSparseTrigCandsCharm"), trigCand.invMassTrig(), trigCand.ptTrig(), trigCand.bdtScore0Trig(), trigCand.bdtScore1Trig()); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processCharmTriggers, "Process charm trigger info", false); + + void processSameEventCharmHadWCentMixBase(aod::HfcRedCorrColls const& collisions, + TrigCharmCands const& candidates, + aod::HfcRedAssBases const& tracks) + { + BinningCentPosZ binPolicyPosZCent{{zPoolBins, centPoolBins}, true}; + + for (const auto& collision : collisions) { + if (collision.centrality() < centralityMin || collision.centrality() > centralityMax) { + continue; + } + int poolBin = binPolicyPosZCent.getBin({collision.posZ(), collision.multiplicity()}); + + auto thisCollId = collision.globalIndex(); + auto candsThisColl = candidates.sliceBy(trigCharmCandsPerCol, thisCollId); + auto tracksThisColl = tracks.sliceBy(assocTracksPerCol, thisCollId); + + doCorrelationsSameEvent(poolBin, candsThisColl, tracksThisColl); + } + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processSameEventCharmHadWCentMixBase, "Process Same Event base", false); + + void processMixedEventCharmHadWCentMixBase(aod::HfcRedCorrColls const& collisions, + TrigCharmCands const& candidates, + aod::HfcRedAssBases const& tracks) + { + BinningCentPosZ binPolicyPosZCent{{zPoolBins, centPoolBins}, true}; + + doCorrelationsMixedEvent(collisions, candidates, tracks, binPolicyPosZCent); + } + PROCESS_SWITCH(HfCorrelatorFlowCharmHadronsReduced, processMixedEventCharmHadWCentMixBase, "Process Mixed Event base", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx new file mode 100644 index 00000000000..a9fb08a3d9a --- /dev/null +++ b/PWGHF/HFC/TableProducer/correlatorHfeHadrons.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 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 "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFL/DataModel/ElectronSelectionTable.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#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; +using namespace o2::soa; +using namespace o2::aod::hf_sel_electron; + +const std::vector zBins{VARIABLE_WIDTH, -10.0, -2.5, 2.5, 10.0}; +const std::vector multBins{VARIABLE_WIDTH, 0., 200., 500.0, 5000.}; +const std::vector multBinsMcGen{VARIABLE_WIDTH, 0., 20., 50.0, 500.}; // In MCGen multiplicity is defined by counting primaries +using BinningType = ColumnBinningPolicy>; +const BinningType corrBinning{{zBins, multBins}, true}; + +using BinningTypeMcGen = ColumnBinningPolicy; + +struct HfCorrelatorHfeHadrons { + Produces entryElectronHadronPair; + Produces entryElectronHadronPairmcGen; + Produces entryElectron; + Produces entryHadron; + // Configurables + // Event Selection + Configurable zPvPosMax{"zPvPosMax", 10., "Maximum z of the primary vertex (cm)"}; + Configurable isRun3{"isRun3", true, "Data is from Run3 or Run2"}; + + Configurable numberEventsMixed{"numberEventsMixed", 5, "number of events mixed in ME process"}; + Configurable invMassEEMax{"invMassEEMax", 0.14f, "max Invariant Mass for Photonic electron"}; + // 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"}; + Configurable requireEmcal{"requireEmcal", true, "Require electron to be in EMCal"}; + + // Sigma cut for non-EMCal electrons + Configurable tofNSigmaEl{"tofNSigmaEl", 3.0, "Sigma cut for electrons not in EMCal"}; + Configurable tpcNsigmaElectronMin{"tpcNsigmaElectronMin", -0.5f, "min Electron TPCnsigma"}; + Configurable tpcNsigmaElectronMax{"tpcNsigmaElectronMax", 3.0f, "max Electron TPCnsigma"}; + + // Electron hadron correlation condition + Configurable ptCondition{"ptCondition", true, "Electron pT should be greater than associate particle pT"}; + + Configurable eventFractionToAnalyze{"eventFractionToAnalyze", -1, "Fraction of events to analyze (use only for ME offline on very large samples)"}; + + TRandom3 rnd{0}; + + 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 binsPosZ{"binsPosZ", {100, -10., 10.}, "primary vertex z coordinate"}; + 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 binsPt{"binsPt", {50, 0.0, 50}, "#it{p_{T}}(GeV/#it{c})"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + ConfigurableAxis binsNSigma{"binsNSigma", {30, -15., 15.}, "#it{#sigma_{TPC}}"}; + ConfigurableAxis binsMass{"binsMass", {100, 0.0, 2.0}, "Mass (GeV/#it{c}^{2}); entries"}; + + HistogramRegistry registry{ + "registry", + {}}; + + void init(InitContext&) + { + AxisSpec const axisPosZ = {binsPosZ, "Pos Z"}; + AxisSpec axisDeltaEta = {binsDeltaEta, "#Delta #eta = #eta_{Electron}- #eta_{Hadron}"}; + AxisSpec axisDeltaPhi = {binsDeltaPhi, "#Delta #varphi = #varphi_{Electron}- #varphi_{Hadron}"}; + AxisSpec axisPt = {binsPt, "#it{p_{T}}(GeV/#it{c})"}; + AxisSpec axisMass = {binsMass, "Mass (GeV/#it{c}^{2}); entries"}; + + AxisSpec const axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec axisNSigma = {binsNSigma, "it{#sigma_{TPC}}"}; + + registry.add("hZvertex", "z vertex", {HistType::kTH1D, {axisPosZ}}); + registry.add("hNevents", "No of events", {HistType::kTH1D, {{3, 1, 4}}}); + registry.add("hLikeMass", "Like mass", {HistType::kTH1D, {{axisMass}}}); + registry.add("hUnLikeMass", "unLike mass", {HistType::kTH1D, {{axisMass}}}); + registry.add("hLikeSignPt", "Like sign Momentum ", {HistType::kTH1D, {{axisPt}}}); + registry.add("hUnLikeSignPt", "UnLike sign Momentum", {HistType::kTH1D, {{axisPt}}}); + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hTpcTofNSigmaVsPt", " TPC and TOF nSigma info vs pt; n#sigma; n#sigma;#it{pt} (GeV/#it{c});", {HistType::kTH3F, {{axisNSigma}, {axisNSigma}, {axisPt}}}); + + // After electron selection Information + registry.add("hTofNSigmaVsPt", " TOF nSigma info vs pt; n#sigma;#it{pt} (GeV/#it{c});", {HistType::kTH2F, {{axisNSigma}, {axisPt}}}); + registry.add("hTpcNSigmaVsPt", " TPC nSigma info vs pt; n#sigma;#it{pt} (GeV/#it{c});", {HistType::kTH2F, {{axisNSigma}, {axisPt}}}); + + registry.add("hMCgenNonHfEHCorrel", "Sparse for Delta phi and Delta eta for McGen Non Hf Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hptElectron", "hptElectron", {HistType::kTH1D, {axisPt}}); + registry.add("hptHadron", "hptHadron", {HistType::kTH1D, {axisPt}}); + registry.add("hMCgenptHadron", "hMCgenptHadron", {HistType::kTH1D, {axisPt}}); + registry.add("hMCgenptHadronprimary", "hMCgenptHadronprimary", {HistType::kTH1D, {axisPt}}); + + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hMixEventMcGenNonHfEHCorrl", "Sparse for mix event Delta phi and Delta eta Mc gen Non Hf Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hElectronBin", "Electron bin", {HistType::kTH1D, {axisPoolBin}}); + registry.add("hLSElectronBin", "Electron bin", {HistType::kTH1D, {axisPoolBin}}); + registry.add("hULSElectronBin", "Electron bin", {HistType::kTH1D, {axisPoolBin}}); + registry.add("hTracksBin", "Particles associated pool bin", {HistType::kTH1D, {axisPoolBin}}); + } + + // 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& electrons, TracksType const& tracks, BcType const&) + { + if (!(isRun3 ? collision.sel8() : (collision.sel7() && collision.alias_bit(kINT7)))) { + return; + } + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + auto bc = collision.template bc_as(); + int gCollisionId = collision.globalIndex(); + int64_t timeStamp = bc.timestamp(); + + bool skipEventTableFilling = false; + if (eventFractionToAnalyze > 0) { + if (rnd.Uniform(0, 1) > eventFractionToAnalyze) { + skipEventTableFilling = true; + } + } + + registry.fill(HIST("hNevents"), 1); + // Add hadron Table For Mix Event Electron Hadron correlation + if (!skipEventTableFilling) { + registry.fill(HIST("hZvertex"), collision.posZ()); + for (const auto& hTrack : tracks) { + if (!selAssoHadron(hTrack)) { + continue; + } + registry.fill(HIST("hTracksBin"), poolBin); + registry.fill(HIST("hptHadron"), hTrack.pt()); + entryHadron(hTrack.phi(), hTrack.eta(), hTrack.pt(), poolBin, gCollisionId, timeStamp); + } + } + + // Construct Deta Phi between electrons and hadrons + + double ptElectron = -999; + double phiElectron = -999; + double etaElectron = -999; + + for (const auto& eTrack : electrons) { + ptElectron = eTrack.ptTrack(); + phiElectron = eTrack.phiTrack(); + etaElectron = eTrack.etaTrack(); + bool acceptElectron = false; + + double deltaPhi = -999; + double deltaEta = -999; + double ptHadron = -999; + double etaHadron = -999; + double phiHadron = -999; + // EMCal electron + if (eTrack.isEmcal() && requireEmcal) { + acceptElectron = true; + } else if (!eTrack.isEmcal() && !requireEmcal) { + + registry.fill(HIST("hTpcTofNSigmaVsPt"), eTrack.tofNSigmaElTrack(), eTrack.tpcNSigmaElTrack(), eTrack.ptTrack()); + + // After electron selection Information + if (std::abs(eTrack.tofNSigmaElTrack()) < tofNSigmaEl && eTrack.tpcNSigmaElTrack() > tpcNsigmaElectronMin && + eTrack.tpcNSigmaElTrack() < tpcNsigmaElectronMax) { + + registry.fill(HIST("hTofNSigmaVsPt"), eTrack.tofNSigmaElTrack(), eTrack.ptTrack()); + registry.fill(HIST("hTpcNSigmaVsPt"), eTrack.tpcNSigmaElTrack(), eTrack.ptTrack()); + acceptElectron = true; + } + } + + if (!acceptElectron) { + continue; // skip electron if not passing criteria + } + + registry.fill(HIST("hptElectron"), ptElectron); + int nElectronLS = 0; + int nElectronUS = 0; + float massLike = 0; + float massUnLike = 0; + if (eTrack.nElPairLS() > 0) { + for (int i = 0; i < eTrack.nElPairLS(); ++i) { + massLike = eTrack.invariantMassEE(); + + registry.fill(HIST("hLSElectronBin"), poolBin); + registry.fill(HIST("hLikeMass"), massLike); + + if (massLike <= invMassEEMax) { + ++nElectronLS; + registry.fill(HIST("hLikeSignPt"), eTrack.ptTrack()); + } + } + } + if (eTrack.nElPairUS() > 0) { + for (int i = 0; i < eTrack.nElPairUS(); ++i) { + massUnLike = eTrack.invariantMassEE(); + + registry.fill(HIST("hULSElectronBin"), poolBin); + registry.fill(HIST("hUnLikeMass"), massUnLike); + + if (massUnLike <= invMassEEMax) { + ++nElectronUS; + registry.fill(HIST("hLikeSignPt"), eTrack.ptTrack()); + } + } + } + + if (!skipEventTableFilling) { + registry.fill(HIST("hElectronBin"), poolBin); + entryElectron(phiElectron, etaElectron, ptElectron, nElectronLS, nElectronUS, poolBin, gCollisionId, timeStamp); + } + + for (const auto& hTrack : tracks) { + // Apply Hadron cut + if (!selAssoHadron(hTrack)) { + continue; + } + ptHadron = hTrack.pt(); + phiHadron = hTrack.phi(); + etaHadron = hTrack.eta(); + if (hTrack.globalIndex() == eTrack.trackId()) { + continue; + } + + 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 nElHadLSCorr = 0; + int nElHadUSCorr = 0; + if (eTrack.nElPairLS() > 0) { + for (int i = 0; i < eTrack.nElPairLS(); ++i) { + if (eTrack.invariantMassEE() <= invMassEEMax) { + ++nElHadLSCorr; + registry.fill(HIST("hLSEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + } + } + } + if (eTrack.nElPairUS() > 0) { + for (int i = 0; i < eTrack.nElPairUS(); ++i) { + if (eTrack.invariantMassEE() <= invMassEEMax) { + registry.fill(HIST("hULSEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + ++nElHadUSCorr; + } + } + } + entryElectronHadronPair(deltaPhi, deltaEta, ptElectron, ptHadron, poolBin, nElHadLSCorr, nElHadUSCorr); + + } // end Hadron Track loop + + } // end Electron loop + } + + // 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.multFT0M())); + 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 nElHadLSCorr = 0; + int nElHadUSCorr = 0; + if (t1.nElPairLS() > 0) { + for (int i = 0; i < t1.nElPairLS(); ++i) { + + registry.fill(HIST("hMixEventLSEHCorrel"), ptElectronMix, ptHadronMix, deltaPhiMix, deltaEtaMix); + ++nElHadLSCorr; + } + } + if (t1.nElPairUS() > 0) { + for (int i = 0; i < t1.nElPairUS(); ++i) { + + registry.fill(HIST("hMixEventULSEHCorrel"), ptElectronMix, ptHadronMix, deltaPhiMix, deltaEtaMix); + ++nElHadUSCorr; + } + } + entryElectronHadronPair(deltaPhiMix, deltaEtaMix, ptElectronMix, ptHadronMix, poolBin, nElHadLSCorr, nElHadUSCorr); + } + } + + // ======= Process starts for Data, Same event ============ + + void processData(TableCollision const& collision, + aod::HfCorrSelEl const& electrons, + TableTracks const& tracks, + aod::BCsWithTimestamps const& bcs) + { + fillCorrelation(collision, electrons, tracks, bcs); + } + + PROCESS_SWITCH(HfCorrelatorHfeHadrons, processData, "Process for Data", true); + + // ======= Process starts for McRec, Same event ============ + + void processMcRec(McTableCollision const& mcCollision, + aod::HfCorrSelEl const& mcElectrons, + McTableTracks const& mcTracks, + aod::BCsWithTimestamps const& bcs) + { + fillCorrelation(mcCollision, mcElectrons, mcTracks, bcs); + } + + PROCESS_SWITCH(HfCorrelatorHfeHadrons, processMcRec, "Process MC Reco mode", false); + + void processMcGen(McGenTableCollision const& mcCollision, aod::McParticles const& mcParticles, aod::HfMcGenSelEl const& electrons) + { + + BinningTypeMcGen const corrBinningMcGen{{zBins, multBinsMcGen}, true}; + int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); + + for (const auto& particleMc : mcParticles) { + if (particleMc.eta() < etaTrackMin || particleMc.eta() > etaTrackMax) { + continue; + } + if (particleMc.pt() < ptTrackMin) { + continue; + } + + registry.fill(HIST("hMCgenptHadron"), particleMc.pt()); + if (particleMc.isPhysicalPrimary()) { + + registry.fill(HIST("hMCgenptHadronprimary"), particleMc.pt()); + } + } + + double ptElectron = 0; + double phiElectron = 0; + double etaElectron = 0; + + for (const auto& electronMc : electrons) { + 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", false); + // ====================== 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 const pair{corrBinning, numberEventsMixed, -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 const pairMcRec{corrBinning, numberEventsMixed, -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 const corrBinningMcGen{{zBins, multBinsMcGen}, true}; + + auto tracksTuple = std::make_tuple(electrons, mcParticles); + Pair const 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 141ad2e9b4c..62a8ee5bc8d 100644 --- a/PWGHF/HFC/TableProducer/correlatorLcHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorLcHadrons.cxx @@ -14,150 +14,177 @@ /// /// \author Marianna Mazzilli /// \author Zhen Zhang +/// \author Ravindra Singh -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" +#include "PWGHF/Utils/utilsAnalysis.h" -#include "Common/Core/TrackSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include 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 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"}; + Configurable centMin{"centMin", 0., "Minimum Centrality"}; + Configurable centMax{"centMax", 100., "Maximum Centrality"}; + Configurable useCentrality{"useCentrality", false, "Flag for centrality dependent analyses"}; - 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) { - int 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; + bool isCentInRange = false; + 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); + + float cent = 0.; + if (useCentrality) { + cent = collision.centFT0M(); + } + + if (useSel8) { + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + } + + isCentInRange = (cent >= centMin && cent < centMax); + isSelColl = isLcFound && isSel8 && isNosameBunchPileUp && isCentInRange; + 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) { - int 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 = 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) { - int 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) { + double const yL = RecoDecay::y(particle.pVector(), MassLambdaCPlus); + if (std::abs(yL) > yCandMax || particle.pt() < ptCandMin) { + isLcFound = false; continue; } - if (ptCandMin >= 0. && particle.pt() < ptCandMin) { - continue; - } - isLcFound = 1; + isLcFound = true; break; } lcSel(isLcFound); @@ -168,113 +195,212 @@ 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 filterFlagLc{"filterFlagLc", true, "Flag for applying Collision Filter with Lc"}; - Configurable filterFlagLcMc{"filterFlagLcMc", false, "Flag for applying Mc Collision Filter with Lc"}; - Configurable nEventForMixedEvent{"nEventForMixedEvent", 5, "number of event to be mixed"}; 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)"}; + Configurable useCentrality{"useCentrality", false, "Flag for centrality dependent analyses"}; - HfHelper hfHelper; SliceCache cache; - BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; + Service pdg; + int leadingIndex = 0; + bool correlationStatus = false; + static constexpr std::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 >= filterFlagLc; + 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 >= filterFlagLcMc; - 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.}}}}, - {"hMultT0M", "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 perCollisionID = aod::track::collisionId; + Preslice cand3ProngPerCol = aod::hf_cand::collisionId; + + // 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})"}; + ConfigurableAxis binsCentFt0m{"binsCentFt0m", {100, 0., 100.}, "Centrality percentile (FT0M)"}; + + 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 const axisEta = {binsEta, "#it{eta}"}; + AxisSpec const 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 const axisMultiplicity = {binsMultiplicity, "Multiplicity"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec const axisPosZ = {binsZVtx, "PosZ"}; + AxisSpec const axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec const axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec const axisRapidity = {100, -2, 2, "Rapidity"}; + AxisSpec axisSign = {2, -1, 1, "Sign"}; + AxisSpec axisCent = {binsCentFt0m, "Centrality"}; + + registry.add("hPtCand", "Lc,Hadron candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtProng0", "Lc,Hadron candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtProng1", "Lc,Hadron candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtProng2", "Lc,Hadron candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtLc}}); + registry.add("hSelectionStatusLcToPKPi", "Lc,Hadron candidates;selection status;entries", {HistType::kTH1D, {{8, -0.5, 7.5}}}); + registry.add("hSelectionStatusLcToPiKP", "Lc,Hadron candidates;selection status;entries", {HistType::kTH1D, {{8, -0.5, 7.5}}}); + registry.add("hEta", "Lc,Hadron candidates;candidate #it{#eta};entries", {HistType::kTH1D, {axisEta}}); + registry.add("hPhi", "Lc,Hadron candidates;candidate #it{#varphi};entries", {HistType::kTH1D, {axisPhi}}); + registry.add("hY", "Lc,Hadron candidates;candidate #it{#y};entries", {HistType::kTH1D, {axisRapidity}}); + registry.add("hCountLcHadronPerEvent", "Lc,Hadron particles - MC gen;Number per event;entries", {HistType::kTH1D, {{21, -0.5, 20.5}}}); + registry.add("hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1D, {{10000, 0., 10000.}}}); + registry.add("hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1D, {{10000, 0., 10000.}}}); + registry.add("hMultFT0M", "multiplicity;multiplicity;entries", {HistType::kTH1D, {{10000, 0., 10000.}}}); + registry.add("hZvtx", "z vertex;z vertex;entries", {HistType::kTH1D, {{200, -20., 20.}}}); + registry.add("hCentFT0M", "Centrality FT0M; Centrality;entries", {HistType::kTH1D, {{100, 0., 100.}}}); + registry.add("hLcBin", "Lc selected in pool Bin;pool Bin;entries", {HistType::kTH1D, {{9, 0., 9.}}}); + registry.add("hTracksBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1D, {{9, 0., 9.}}}); + registry.add("hMassLcVsPtVsCent", "Lc candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH3F, {{axisMassLc}, {axisPtLc}, {axisCent}}}); + registry.add("hMassLcData", "Lc candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{axisMassLc}}}); + registry.add("hLcPoolBin", "Lc candidates pool bin", {HistType::kTH1D, {axisPoolBin}}); + registry.add("hTracksPoolBin", "Particles associated pool bin", {HistType::kTH1D, {axisPoolBin}}); + // Histograms for MC Reco analysis + registry.add("hSelectionStatusLcToPKPiMcRec", "Lc,Hadron candidates - MC reco;selection status;entries", {HistType::kTH1D, {{8, -0.5, 7.5}}}); + registry.add("hSelectionStatusLcToPiKPMcRec", "Lc,Hadron candidates - MC reco;selection status;entries", {HistType::kTH1D, {{8, -0.5, 7.5}}}); + registry.add("hMcEvtCount", "Event counter - MC gen;;entries", {HistType::kTH1D, {{1, -0.5, 0.5}}}); + registry.add("hPtProng0McRec", "Lc,Hadron candidates - MC reco;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtProng1McRec", "Lc,Hadron candidates - MC reco;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtProng2McRec", "Lc,Hadron candidates - MC reco;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtLc}}); + registry.add("hMassLcMcRec", "Lc candidates;inv. mass (P K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{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::kTH1D, {axisPtLc}}); + registry.add("hPtCandMcRecSigPrompt", "Lc,Hadron candidates Prompt - MC Reco", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtCandMcRecSigNonPrompt", "Lc,Hadron candidates Non Prompt - MC Reco", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtCandMcRecBkg", "Lc,Hadron candidates - MC Reco", {HistType::kTH1D, {axisPtLc}}); + registry.add("hEtaMcRecSig", "Lc,Hadron candidates - MC Reco", {HistType::kTH1D, {axisEta}}); + registry.add("hPhiMcRecSig", "Lc,Hadron candidates - MC Reco", {HistType::kTH1D, {axisPhi}}); + registry.add("hYMcRecSig", "Lc,Hadron candidates - MC reco;candidate #it{#y};entries", {HistType::kTH1D, {axisRapidity}}); + registry.add("hEtaMcRecBkg", "Lc,Hadron candidates - MC Reco", {HistType::kTH1D, {axisEta}}); + registry.add("hPhiMcRecBkg", "Lc,Hadron candidates - MC Reco", {HistType::kTH1D, {axisPhi}}); + registry.add("hYMcRecBkg", "Lc,Hadron candidates - MC reco;candidate #it{#y};entries", {HistType::kTH1D, {axisRapidity}}); + registry.add("hFakeTracksMcRec", "Fake tracks - MC Rec", {HistType::kTH1D, {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::kTH1D, {axisPtLc}}); + registry.add("hYMcGen", "Lc,Hadron candidates - MC gen;candidate #it{#y};entries", {HistType::kTH1D, {axisRapidity}}); + registry.add("hPtCandMcGenPrompt", "Lc,Hadron particles - MC Gen Prompt", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtCandMcGenNonPrompt", "Lc,Hadron particles - MC Gen Non Prompt", {HistType::kTH1D, {axisPtLc}}); + registry.add("hPtParticleAssocMcGen", "Associated Particle - MC Gen", {HistType::kTH1D, {axisPtHadron}}); + registry.add("hEtaMcGen", "Lc,Hadron particles - MC Gen", {HistType::kTH1D, {axisEta}}); + registry.add("hPhiMcGen", "Lc,Hadron particles - MC Gen", {HistType::kTH1D, {axisPhi}}); + registry.add("hMultFT0AMcGen", "Lc,Hadron multiplicity FT0A - MC Gen", {HistType::kTH1D, {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; } + + 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(); + + float cent = 0.; + if (useCentrality) { + cent = collision.centFT0M(); + } 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); @@ -283,105 +409,153 @@ 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) { + for (const auto& candidate : candidates) { + if (std::abs(HfHelper::yLc(candidate)) > yCandMax || candidate.pt() < ptCandMin || candidate.pt() > ptCandMax) { continue; } - if (candidate.pt() > ptTrackMax) { - continue; - } - // check decay channel flag for candidate - if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::LcToPKPi)) { - continue; + double efficiencyWeightLc = 1.; + if (applyEfficiency != 0) { + efficiencyWeightLc = 1. / efficiencyLc->at(o2::analysis::findBin(binsPtEfficiencyLc, candidate.pt())); } + auto trackPos1 = candidate.template prong0_as(); // positive daughter (negative for the antiparticles) + int8_t const chargeLc = trackPos1.sign(); // charge of 1st prong will be the charge of Lc candidate - double efficiencyWeight = 1.; - if (applyEfficiency) { - efficiencyWeight = 1. / efficiencyLc->at(o2::analysis::findBin(binsPt, candidate.pt())); - } 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.yLc(candidate)); - registry.fill(HIST("hLcPoolBin"), poolBin); + registry.fill(HIST("hPhi"), RecoDecay::constrainAngle(candidate.phi(), -PIHalf)); + registry.fill(HIST("hY"), HfHelper::yLc(candidate)); + 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("hMassLcVsPtVsCent"), HfHelper::invMassLcToPKPi(candidate), candidate.pt(), cent, 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 + if (!skipMixedEventTableFilling) { + 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("hMassLcVsPtVsCent"), HfHelper::invMassLcToPiKP(candidate), candidate.pt(), cent, 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; + correlationStatus = false; + // 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); - entryLcHadronRecoInfo(hfHelper.invMassLcToPKPi(candidate), false); + candidate.pt() * chargeLc, + track.pt() * track.sign(), + poolBin, + correlationStatus, + cent); + entryLcHadronPairY(track.rapidity(MassProton) - HfHelper::yLc(candidate)); // only for proton as of now + 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); - entryLcHadronRecoInfo(hfHelper.invMassLcToPiKP(candidate), false); + candidate.pt() * chargeLc, + track.pt() * track.sign(), + poolBin, + correlationStatus, + cent); + entryLcHadronPairY(track.rapidity(MassProton) - HfHelper::yLc(candidate)); // only for proton as of now + 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("hMultT0M"), collision.multFT0M()); + registry.fill(HIST("hMultFT0M"), collision.multFT0M()); + registry.fill(HIST("hCentFT0M"), cent); } 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; } + + // 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); @@ -390,313 +564,611 @@ struct HfCorrelatorLcHadrons { } registry.fill(HIST("hMultiplicity"), nTracks); - auto selectedLcCandidatesGroupedMc = selectedLcCandidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); - + float const 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 efficiencyWeightLc = 1.; + if (applyEfficiency != 0) { + efficiencyWeightLc = 1. / efficiencyLc->at(o2::analysis::findBin(binsPtEfficiencyLc, candidate.pt())); } - double efficiencyWeight = 1.; - if (applyEfficiency) { - efficiencyWeight = 1. / efficiencyLc->at(o2::analysis::findBin(binsPt, 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 const chargeLc = trackPos1.sign(); // charge of 1st prong will be the charge of Lc candidate + isLcSignal = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::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))); + } + //} + } + float cent = 100.0; // will be updated later // 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) { + correlationStatus = false; + 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); - entryLcHadronRecoInfo(hfHelper.invMassLcToPKPi(candidate), isLcSignal); + candidate.pt() * chargeLc, + track.pt() * track.sign(), + poolBin, + correlationStatus, + cent); + entryLcHadronPairY(track.rapidity(MassProton) - HfHelper::yLc(candidate)); // only for proton as of now + 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); - entryLcHadronRecoInfo(hfHelper.invMassLcToPiKP(candidate), isLcSignal); + candidate.pt() * chargeLc, + track.pt() * track.sign(), + poolBin, + correlationStatus, + cent); + entryLcHadronPairY(track.rapidity(MassProton) - HfHelper::yLc(candidate)); // only for proton as of now + 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("hMultT0M"), collision.multFT0M()); + 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 const corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; + int poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); + registry.fill(HIST("hMultFT0AMcGen"), mcCollision.multMCFT0A()); - // Mc gen level + bool isLcPrompt = false; + bool isLcNonPrompt = false; + float cent = 100.0; // will be updated later + + // 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 (std::abs(particle.flagMcMatchGen()) != hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + continue; + } + double const 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 const 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) { + correlationStatus = false; + 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)) { + continue; + } + + if (pidTrkApplied && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; // proton PID + } + + if (!particleAssoc.isPhysicalPrimary()) { + continue; + } - 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 (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 const chargeLc = pdg->GetParticle(particle.pdgCode())->Charge(); // Retrieve charge + int8_t const 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, + cent); + 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, nEventForMixedEvent, -1, collisions, tracksTuple, &cache}; + Pair const 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.multFT0M())); - for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (!TESTBIT(t1.hfflag(), aod::hf_cand_3prong::DecayType::LcToPKPi)) { + 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 const chargeLc = trackPos1.sign(); // charge of 1st prong will be the charge of Lc candidate + + float cent = 100.0; // will be updated later + + 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, + cent); + 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, + cent); + 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 const 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 const isLcSignal = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi; + // prompt and non-prompt division + bool const isLcPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + bool const 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, nEventForMixedEvent, -1, collisions, tracksTuple, &cache}; + Pair const 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& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (yCandMax >= 0. && std::abs(hfHelper.yLc(t1)) > yCandMax) { + int const 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); + float cent = 100.0; // will be updated later + 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 (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 (!pAssoc.isGlobalTrackWoDCA()) { + continue; + } + std::vector outputMl = {-1., -1., -1.}; + bool isPhysicalPrimary = false; + int trackOrigin = -1; + bool isLcSignal = std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::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 const 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, + cent); + 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, + cent); + 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 const corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; auto tracksTuple = std::make_tuple(mcParticles, mcParticles); - Pair pairMcGen{corrBinningMcGen, nEventForMixedEvent, -1, collisions, tracksTuple, &cache}; - + Pair const 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 const 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 const chargeLc = pdg->GetParticle(candidate.pdgCode())->Charge(); // Retrieve charge + int8_t const chargeAssoc = pdg->GetParticle(particleAssoc.pdgCode())->Charge(); // Retrieve charge + float cent = 100.0; // will be updated later + + 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, + cent); + entryLcHadronPairY(particleAssoc.y() - yL); + entryLcHadronRecoInfo(MassLambdaCPlus, true); + entryLcHadronGenInfo(isLcPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); } } } diff --git a/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx new file mode 100644 index 00000000000..05092bab783 --- /dev/null +++ b/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx @@ -0,0 +1,1457 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file correlatorLcScHadrons.cxx +/// \brief Lc-Hadrons correlator task - data-like, Mc-Reco and Mc-Gen analyses +/// +/// \author Marianna Mazzilli +/// \author Zhen Zhang +/// \author Ravindra Singh + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" +#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +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, -PIHalf); +} + +// definition of ME variables +using BinningType = ColumnBinningPolicy>; +using BinningTypeMcGen = ColumnBinningPolicy; + +// Code to select collisions with at least one Lambda_c +struct HfCorrelatorLcScHadronsSelection { + Produces candSel; + + 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"}; + + 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 cfgV0LifeTime{"cfgV0LifeTime", 30., "maximum lambda lifetime"}; + Configurable cfgPV{"cfgPV", 10., "maximum z-vertex"}; + 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"}; + } cfgV0; + + SliceCache cache; + + using SelCollisions = soa::Join; + using CandsLcDataFiltered = soa::Filtered>; + using CandsLcMcRecFiltered = soa::Filtered>; + using CandsScMcRec = soa::Join; + using CandidatesLcMcGen = soa::Join; + using CandidatesScMcGen = soa::Join; + // 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); + + template + void selectionCollision(CollType const& collision, CandType const& candidates) + { + bool isSelColl = true; + bool isCandFound = false; + bool isSel8 = true; + bool isNosameBunchPileUp = true; + double yCand = -999.; + const int chargeZero = 0; + if (doSelLcCollision) { + for (const auto& candidate : candidates) { + + if constexpr (IsCandSc) { + int8_t const chargeCand = candidate.charge(); + + if (chargeCand == chargeZero) { + yCand = HfHelper::ySc0(candidate); + } else { + yCand = HfHelper::yScPlusPlus(candidate); + } + + } else { + yCand = HfHelper::yLc(candidate); + } + + if (std::abs(yCand) > yCandMax || candidate.pt() < ptCandMin) { + isCandFound = false; + continue; + } + isCandFound = true; + break; + } + } + if (useSel8) { + isSel8 = collision.sel8(); + } + if (selNoSameBunchPileUpColl) { + isNosameBunchPileUp = static_cast(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)); + } + isSelColl = isCandFound && isSel8 && isNosameBunchPileUp; + candSel(isSelColl); + } + + template + void selectionCollisionMcGen(CandType const& mcParticles) + { + bool isCandFound = false; + double massCand = -999.0; + for (const auto& particle : mcParticles) { + + isCandFound = matchCandAndMass(particle, massCand); + if (!isCandFound) { + continue; + } + + double const yCand = RecoDecay::y(particle.pVector(), massCand); + if (std::abs(yCand) > yCandMax || particle.pt() < ptCandMin) { + isCandFound = false; + continue; + } + + isCandFound = true; + break; + } + candSel(isCandFound); + } + + template + bool selectionV0(TCollision const& collision, V0 const& candidate) + { + if (candidate.v0radius() < cfgV0.cfgV0radiusMin) { + return false; + } + if (std::abs(candidate.dcapostopv()) < cfgV0.cfgDCAPosToPVMin) { + return false; + } + if (std::abs(candidate.dcanegtopv()) < cfgV0.cfgDCANegToPVMin) { + return false; + } + if (candidate.v0cosPA() < cfgV0.cfgV0CosPA) { + return false; + } + if (std::abs(candidate.dcaV0daughters()) > cfgV0.cfgDCAV0Dau) { + return false; + } + if (candidate.pt() < cfgV0.cfgV0PtMin) { + return false; + } + if (std::abs(candidate.yLambda()) > yCandMax) { + return false; + } + if (candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda > cfgV0.cfgV0LifeTime) { + return false; + } + + return true; + } + + template + bool eventSelV0(TCollision 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 (std::abs(collision.posZ()) > cfgV0.cfgPV) { + return 0; + } + if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + if (collision.trackOccupancyInTimeRange() > cfgV0.cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgV0.cfgMinOccupancy) { + return 0; + } + + return 1; + } // event selection V0 + + /// Code to select collisions with at least one Lc - for real data and data-like analysis + void processV0Selection(SelCollisions::iterator const& collision, + aod::V0Datas const& V0s) + { + bool isCandFound = false; + const int64_t kMinV0Candidates = 1; + + if (!eventSelV0(collision)) { + candSel(isCandFound); + return; + } + if (V0s.size() < kMinV0Candidates) { + candSel(isCandFound); + return; + } + for (const auto& v0 : V0s) { + if (selectionV0(collision, v0)) { + isCandFound = true; + break; + } + } + candSel(isCandFound); + } + PROCESS_SWITCH(HfCorrelatorLcScHadronsSelection, processV0Selection, "Process V0 Collision Selection for Data", true); + + void processLcSelection(SelCollisions::iterator const& collision, + CandsLcDataFiltered const& candidates) + { + selectionCollision(collision, candidates); + } + PROCESS_SWITCH(HfCorrelatorLcScHadronsSelection, processLcSelection, "Process Lc Collision Selection for Data and Mc", true); + + void processScSelection(SelCollisions::iterator const& collision, + aod::HfCandSc const& candidates) + { + selectionCollision(collision, candidates); + } + PROCESS_SWITCH(HfCorrelatorLcScHadronsSelection, processScSelection, "Process Sc Collision Selection for Data and Mc", false); + + void processLcSelectionMcRec(SelCollisions::iterator const& collision, + CandsLcMcRecFiltered const& candidates) + { + selectionCollision(collision, candidates); + } + PROCESS_SWITCH(HfCorrelatorLcScHadronsSelection, processLcSelectionMcRec, "Process Lc Selection McRec", false); + + void processScSelectionMcRec(SelCollisions::iterator const& collision, + CandsScMcRec const& candidates) + { + selectionCollision(collision, candidates); + } + PROCESS_SWITCH(HfCorrelatorLcScHadronsSelection, processScSelectionMcRec, "Process Sc Selection McRec", false); + + void processLcSelectionMcGen(aod::McCollision const&, + CandidatesLcMcGen const& mcParticles) + { + selectionCollisionMcGen(mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadronsSelection, processLcSelectionMcGen, "Process Lc Selection McGen", false); + + void processScSelectionMcGen(aod::McCollision const&, + CandidatesScMcGen const& mcParticles) + { + selectionCollisionMcGen(mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadronsSelection, processScSelectionMcGen, "Process Lc Selection McGen", false); +}; + +// Lc-Hadron correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via Mc truth) +struct HfCorrelatorLcScHadrons { + Produces entryCandHadronPair; + Produces entryCandHadronPairY; + Produces entryCandHadronPairTrkPID; + Produces entryCandHadronRecoInfo; + Produces entryCandHadronMlInfo; + Produces entryCandCandRecoInfo; + Produces entryCandHadronGenInfo; + Produces entryCandCandGenInfo; + Produces entryTrackRecoInfo; + Produces entryCand; + Produces entryHadron; + Produces entryTrkPID; + Produces entryPairCandCharge; + Produces entryCandCharge; + + 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", 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> 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 calEffEventWithCand{"calEffEventWithCand", 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)"}; + + struct : ConfigurableGroup { + Configurable cfgDaughPrPtMax{"cfgDaughPrPtMax", 5., "max. pT Daughter Proton"}; + Configurable cfgDaughPrPtMin{"cfgDaughPrPtMin", 0.3, "min. pT Daughter Proton"}; + Configurable cfgDaughPiPtMax{"cfgDaughPiPtMax", 10., "max. pT Daughter Pion"}; + Configurable cfgDaughPiPtMin{"cfgDaughPiPtMin", 0.3, "min. pT Daughter Pion"}; + Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 3., "max. TPCnSigma Proton"}; + Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 2., "max. TPCnSigma Pion"}; + Configurable cfgDaughPIDCutsTOFPi{"cfgDaughPIDCutsTOFPi", 2., "max. TOFnSigma Pion"}; + Configurable cfgHypMassWindow{"cfgHypMassWindow", 0.5, "single lambda mass selection"}; + } cfgV0; + + SliceCache cache; + Service pdg; + int8_t chargeCand = 3; + int8_t signSoftPion = 0; + int leadingIndex = 0; + int poolBin = 0; + int poolBinLc = 0; + bool correlationStatus = false; + bool isPrompt = false; + bool isNonPrompt = false; + bool isSignal = false; + static constexpr int8_t ChargeScPlusPlus{2}; + static constexpr int8_t ChargeZero{0}; + static constexpr int8_t AssignedChargeSc0{1}; // to distinguish sc0 from anti-sc0, charge set to +1 and -1 + + TRandom3* rnd = new TRandom3(0); + // std::vector outputMl = {-1., -1., -1.}; + std::vector outputMlPKPi = {-1., -1., -1.}; + std::vector outputMlPiKP = {-1., -1., -1.}; + + // Event Mixing for the Data Mode + // using SelCollisionsWithSc = soa::Join; + using SelCollisions = soa::Filtered>; + using SelCollisionsMc = soa::Filtered>; // collisionFilter applied + + using CandsLcData = soa::Join; + using CandsLcDataFiltered = soa::Filtered; + + // Event Mixing for the MCRec Mode + using CandsLcMcRec = soa::Join; + using CandsLcMcRecFiltered = soa::Filtered; + using CandidatesLcMcGen = soa::Join; // flagLcFilter applied + using CandsScMcRec = soa::Join; + using CandidatesScMcGen = soa::Join; + // 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); + + Preslice perTrueCollision = o2::aod::mcparticle::mcCollisionId; + Preslice perCollisionID = aod::track::collisionId; + Preslice cand3ProngPerCol = aod::hf_cand::collisionId; + Preslice csndScPerCol = aod::hf_cand::collisionId; + + // 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 binsCandMass{"binsCandMass", {200, 1.98, 2.58}, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; + ConfigurableAxis binsNSigmas{"binsNSigmas", {4000, -500., 500.}, "n#sigma"}; + + BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(InitContext&) + { + AxisSpec axisCandMass = {binsCandMass, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; + AxisSpec const axisEta = {binsEta, "#it{eta}"}; + AxisSpec const axisPhi = {binsPhi, "#it{#varphi}"}; + AxisSpec axisPtLc = {static_cast>(binsPtLc), "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPtHadron = {static_cast>(binsPtHadron), "#it{p}_{T} Hadron (GeV/#it{c})"}; + AxisSpec axisPtTrack = {500, 0, 50, "#it{p}_{T} Hadron (GeV/#it{c})"}; + AxisSpec const axisMultiplicity = {binsMultiplicity, "Multiplicity"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec const axisPosZ = {binsZVtx, "PosZ"}; + AxisSpec const axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec const axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec const axisRapidity = {100, -2, 2, "Rapidity"}; + AxisSpec const axisNSigma = {binsNSigmas, "n#sigma"}; + AxisSpec axisSign = {5, -2.5, 2.5, "Sign"}; + AxisSpec axisPtV0 = {500, 0., 50.0, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisMassV0 = {300, 1.05f, 1.2f, "inv. mass (p #pi) (GeV/#it{c}^{2})"}; + + 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("hcountCandHadronPerEvent", "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("hCandBin", "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, {{axisCandMass}, {axisPtLc}}}); + registry.add("hMassScVsPtVsSign", "Sc candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});sign;entries", {HistType::kTH3F, {{axisCandMass}, {axisPtLc}, {axisSign}}}); + registry.add("hMassLcData", "Lc candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{axisCandMass}}}); + 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("hMcEvtCount", "Event counter - MC gen;;entries", {HistType::kTH1F, {{1, -0.5, 0.5}}}); + registry.add("hMassLcMcRecBkg", "Lc background candidates - MC reco;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{axisCandMass}, {axisPtLc}}}); + registry.add("hPtCandSig", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtCandSigPrompt", "Lc,Hadron candidates Prompt - MC Reco", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtCandSigNonPrompt", "Lc,Hadron candidates Non Prompt - MC Reco", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtCandMcRecBkg", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPtLc}}); + registry.add("hEtaSig", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisEta}}); + registry.add("hPhiSig", "Lc,Hadron candidates - MC Reco", {HistType::kTH1F, {axisPhi}}); + registry.add("hY", "Lc,Hadron candidates;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + registry.add("hYSig", "Lc,Hadron candidates - MC reco;candidate #it{#y};entries", {HistType::kTH1F, {axisRapidity}}); + 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("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("hcountCandtriggersMcGen", "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("hPtCandVsChargeMcGenPrompt", "Charm Hadron particles - MC Gen Prompt", {HistType::kTH2F, {{axisPtLc}, {axisSign}}}); + registry.add("hPtCandMcGenNonPrompt", "Charm Hadron particles - MC Gen Non Prompt", {HistType::kTH1F, {axisPtLc}}); + registry.add("hPtCandVsChargeMcGenNonPrompt", "Lc,Hadron particles - MC Gen Non Prompt", {HistType::kTH2F, {{axisPtLc}, {axisSign}}}); + 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}}); + registry.add("hTOFnSigmaPr", "hTOFnSigmaPr", {HistType::kTH2F, {{axisPtHadron}, {axisNSigma}}}); + registry.add("hTPCnSigmaPr", "hTPCnSigmaPr", {HistType::kTH2F, {{axisPtHadron}, {axisNSigma}}}); + registry.add("hTOFnSigmaPrPiKRej", "hTOFnSigmaPrPiKRej", {HistType::kTH2F, {{axisPtHadron}, {axisNSigma}}}); + registry.add("hTPCnSigmaPrPiKRej", "hTPCnSigmaPrPiKRej", {HistType::kTH2F, {{axisPtHadron}, {axisNSigma}}}); + + // Lambda V0 histograms + registry.add("hEventLambdaV0", "Lambda, events", {HistType::kTH1F, {{2, 0, 2}}}); + registry.add("hV0Lambda", "V0 Lambda candidates;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0LambdaRefl", "V0 Lambda reflected candidates;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0LambdaPiKRej", "V0 Lambda candidates with #pi K rejection;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0LambdaReflPiKRej", "V0 Lambda reflected candidates with #pi K rejection;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0LambdaMcRec", "McRec V0 Lambda candidates;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0LambdaReflMcRec", "McRec V0 Lambda reflected candidates;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0LambdaPiKRejMcRec", "McRec V0 Lambda candidates with #pi K rejection;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0LambdaReflPiKRejMcRec", "McRec V0 Lambda reflected candidates with #pi K rejection;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + + corrBinning = {{binsZVtx, binsMultiplicity}, true}; + } + + template + void fillMlOutput(MlProbType const& mlProb, std::vector& outputMl) + { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = mlProb[classMl->at(iclass)]; + } + }; + + template + double estimateY(CandType const& candidate) + { + double y = -999.; + if constexpr (IsCandSc) { + int8_t const chargeCand = candidate.charge(); + + if (chargeCand == ChargeZero) { + y = HfHelper::ySc0(candidate); + } else { + y = HfHelper::yScPlusPlus(candidate); + } + + } else { + y = HfHelper::yLc(candidate); + } + return y; + } + + template + bool isSelectedV0Daughter(T const& track, int pid) + { + // if (!track.isGlobalTrackWoDCA()) + // return false; + if (std::abs(pid) == kProton && std::abs(track.tpcNSigmaPr()) > cfgV0.cfgDaughPIDCutsTPCPr) { + return false; + } + if (std::abs(pid) == kPiPlus && (std::abs(track.tpcNSigmaPi()) > cfgV0.cfgDaughPIDCutsTPCPi || std::abs(track.tofNSigmaPi()) > cfgV0.cfgDaughPIDCutsTOFPi)) { + return false; + } + if (std::abs(track.eta()) > etaTrackMax) { + return false; + } + if (std::abs(pid) == kProton && track.pt() > cfgV0.cfgDaughPrPtMax) { + return false; + } + if (std::abs(pid) == kProton && track.pt() < cfgV0.cfgDaughPrPtMin) { + return false; + } + if (std::abs(pid) == kPiPlus && track.pt() > cfgV0.cfgDaughPiPtMax) { + return false; + } + if (std::abs(pid) == kPiPlus && track.pt() < cfgV0.cfgDaughPiPtMin) { + return false; + } + + return true; + } + + template + void fillV0Histograms(V0 const& v0s, TrackType const&) + { + for (const auto& v0 : v0s) { + auto posTrackV0 = v0.template posTrack_as(); + auto negTrackV0 = v0.template negTrack_as(); + + if (isSelectedV0Daughter(posTrackV0, kProton) && isSelectedV0Daughter(negTrackV0, kPiPlus)) { + if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { + registry.fill(HIST("hV0Lambda"), v0.mLambda(), v0.pt(), posTrackV0.pt()); + registry.fill(HIST("hV0LambdaRefl"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); + + registry.fill(HIST("hTPCnSigmaPr"), posTrackV0.pt(), posTrackV0.tpcNSigmaPr()); + if (posTrackV0.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPr"), posTrackV0.pt(), posTrackV0.tofNSigmaPr()); + } + + if (passPIDSelection(posTrackV0, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRej"), v0.mLambda(), v0.pt(), posTrackV0.pt()); + registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); + + registry.fill(HIST("hTPCnSigmaPrPiKRej"), posTrackV0.pt(), posTrackV0.tpcNSigmaPr()); + if (posTrackV0.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPrPiKRej"), posTrackV0.pt(), posTrackV0.tofNSigmaPr()); + } + } + } + } + if (isSelectedV0Daughter(negTrackV0, kProton) && isSelectedV0Daughter(posTrackV0, kPiPlus)) { + if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { + registry.fill(HIST("hV0Lambda"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); + registry.fill(HIST("hV0LambdaRefl"), v0.mLambda(), v0.pt(), posTrackV0.pt()); + + registry.fill(HIST("hTPCnSigmaPr"), negTrackV0.pt(), negTrackV0.tpcNSigmaPr()); + if (negTrackV0.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPr"), negTrackV0.pt(), negTrackV0.tofNSigmaPr()); + } + if (passPIDSelection(negTrackV0, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRej"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); + registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mLambda(), v0.pt(), posTrackV0.pt()); + + registry.fill(HIST("hTPCnSigmaPrPiKRej"), negTrackV0.pt(), negTrackV0.tpcNSigmaPr()); + if (negTrackV0.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPrPiKRej"), negTrackV0.pt(), negTrackV0.tofNSigmaPr()); + } + } + } + } + if constexpr (IsMcRec) { + if (!v0.has_mcParticle() || !posTrackV0.has_mcParticle() || !negTrackV0.has_mcParticle()) { + continue; + } + auto v0Mc = v0.mcParticle(); + auto posTrack = posTrackV0.mcParticle(); + auto negTrack = negTrackV0.mcParticle(); + + if (std::abs(v0Mc.pdgCode()) == kLambda0) { + if (std::abs(posTrack.pdgCode()) == kProton) { + registry.fill(HIST("hV0LambdaMcRec"), v0.mLambda(), v0.pt(), posTrackV0.pt()); + registry.fill(HIST("hV0LambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); + + if (passPIDSelection(posTrackV0, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mLambda(), v0.pt(), posTrackV0.pt()); + registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); + } + } + if (std::abs(negTrack.pdgCode()) == kProton) { + registry.fill(HIST("hV0LambdaMcRec"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); + registry.fill(HIST("hV0LambdaReflMcRec"), v0.mLambda(), v0.pt(), posTrackV0.pt()); + + if (passPIDSelection(negTrackV0, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); + registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mLambda(), v0.pt(), posTrackV0.pt()); + } + } + } + } + } + } + + template + void calculateTrkEff(T1 const& trackPos1, T2 const& trackPos2, McPart const& mcParticles) + { + // genrated tracks + decltype(trackPos1.template 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 { + return; + } + 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 / (std::abs(chargeTrack))); + } + } + template + void fillCorrelationTable(bool trkPidFill, TrackType const& track, CandType const& candidate, + const std::vector& outMl, int binPool, int8_t correlStatus, + double yCand, int signCand, McPart const& mcParticles) + { + bool isPhysicalPrimary = false; + int trackOrigin = -1; + float const cent = 100.0; // will be updated later + + entryCandHadronPair(getDeltaPhi(track.phi(), candidate.phi()), + track.eta() - candidate.eta(), + candidate.pt(), + track.pt() * track.sign(), + binPool, + correlStatus, + cent); + entryCandHadronPairY(track.rapidity(MassProton) - yCand); + entryCandHadronMlInfo(outMl[0], outMl[1]); + entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); + entryPairCandCharge(signCand); + if (trkPidFill) { + entryCandHadronPairTrkPID(track.tpcNSigmaPr(), track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tofNSigmaPr(), track.tofNSigmaKa(), track.tofNSigmaPi()); + } + if constexpr (IsMcRec) { + if (track.has_mcParticle()) { + auto mcParticle = track.template mcParticle_as(); + isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); + entryCandHadronGenInfo(isPrompt, isPhysicalPrimary, trackOrigin); + } else { + entryCandHadronGenInfo(isPrompt, false, 0); + registry.fill(HIST("hFakeTracksMcRec"), track.pt()); + } + registry.fill(HIST("hPtParticleAssocVsCandMcRec"), track.pt(), candidate.pt()); + if (isPhysicalPrimary) { + registry.fill(HIST("hPtPrimaryParticleAssocVsCandMcRec"), track.pt(), candidate.pt()); + } + } + } + + template + void doSameEvent(CollisionType const& collision, + TrackType const& tracks, + CandType const& candidates, + aod::McParticles const* mcParticles = nullptr) + { + + int nTracks = 0; + int64_t timeStamp = 0; + bool skipMixedEventTableFilling = false; + float const multiplicityFT0M = collision.multFT0M(); + int gCollisionId = collision.globalIndex(); + if (candidates.size() == 0) { + return; + } + + if (eventFractionToAnalyze > 0) { + if (rnd->Uniform(0, 1) > eventFractionToAnalyze) { + skipMixedEventTableFilling = true; + } + } + + if constexpr (!IsMcRec) { + timeStamp = collision.template bc_as().timestamp(); + } + + poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), multiplicityFT0M)); + if (correlateLcWithLeadingParticle) { + leadingIndex = findLeadingParticle(tracks, etaTrackMax.value); + } + + // Count good tracks + if (collision.numContrib() > 1) { + for (const auto& track : tracks) { + if (std::abs(track.eta()) > etaTrackMax || std::abs(track.dcaXY()) > dcaXYTrackMax || std::abs(track.dcaZ()) > dcaZTrackMax) { + continue; + } + nTracks++; + } + } + + registry.fill(HIST("hMultiplicityPreSelection"), nTracks); + if (nTracks < multMin || nTracks > multMax) { + return; + } + registry.fill(HIST("hMultiplicity"), nTracks); + + int countCand = 1; + + for (const auto& candidate : candidates) { + double efficiencyWeightCand = 1.; + double yCand = -999.0; + double etaCand = -999.0; + double ptCandLc = -999.0; + double ptCand = -999.0; + double phiCand = -999.0; + double massCandPKPi = -999.0; + double massCandPiKP = -999.0; + bool selLcPKPi = false; + bool selLcPiKP = false; + + yCand = estimateY(candidate); + etaCand = candidate.eta(); + ptCand = candidate.pt(); + phiCand = RecoDecay::constrainAngle(candidate.phi(), -PIHalf); + + if ((std::abs(yCand) > yCandMax) || ptCand < ptCandMin || ptCand > ptCandMax) { + continue; + } + + registry.fill(HIST("hY"), yCand); + registry.fill(HIST("hPtCand"), ptCand); + registry.fill(HIST("hEta"), etaCand); + registry.fill(HIST("hPhi"), phiCand); + registry.fill(HIST("hCandBin"), poolBin); + + if (applyEfficiency) { + efficiencyWeightCand = 1. / efficiencyLc->at(o2::analysis::findBin(binsPtEfficiencyLc, ptCand)); + } + + if constexpr (IsMcRec) { + isPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + isNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + } + + if constexpr (IsCandSc) { + chargeCand = candidate.charge(); + const auto& candidateLc = candidate.template prongLc_as(); + ptCandLc = candidateLc.pt(); + selLcPKPi = (candidateLc.isSelLcToPKPi() >= selectionFlagLc) && (candidate.statusSpreadLcMinvPKPiFromPDG()); + selLcPiKP = (candidateLc.isSelLcToPiKP() >= selectionFlagLc) && (candidate.statusSpreadLcMinvPiKPFromPDG()); + if (selLcPKPi) { + const auto& probs = candidateLc.mlProbLcToPKPi(); + fillMlOutput(probs, outputMlPKPi); + massCandPKPi = std::abs(HfHelper::invMassScRecoLcToPKPi(candidate, candidateLc) - HfHelper::invMassLcToPKPi(candidateLc)); + } + if (selLcPiKP) { + const auto& probs = candidateLc.mlProbLcToPiKP(); + fillMlOutput(probs, outputMlPiKP); + massCandPiKP = std::abs(HfHelper::invMassScRecoLcToPiKP(candidate, candidateLc) - HfHelper::invMassLcToPiKP(candidateLc)); + } + if constexpr (IsMcRec) { + // isSignal = + // (TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi) && chargeCand == 0) || + // (TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi) && std::abs(chargeCand) == 2); + isSignal = + (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::Sc0ToPKPiPi && chargeCand == ChargeZero) || + (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScplusplusToPKPiPi && std::abs(chargeCand) == ChargeScPlusPlus); + + auto trackPos1 = candidateLc.template prong0_as(); + auto trackPos2 = candidateLc.template prong2_as(); + signSoftPion = candidate.template prong1_as().sign(); + if (calTrkEff && countCand == 1 && (isSignal || !calEffEventWithCand)) { + calculateTrkEff(trackPos1, trackPos2, *mcParticles); + } + registry.fill(HIST("hPtProng1"), candidate.template prong1_as().pt()); + } else { + signSoftPion = candidate.template prong1_as().sign(); + registry.fill(HIST("hPtProng1"), candidate.prong1().pt()); + } + registry.fill(HIST("hPtProng0"), ptCandLc); + + if (chargeCand == ChargeZero) { + chargeCand = (signSoftPion < ChargeZero) ? AssignedChargeSc0 : -AssignedChargeSc0; // to distingush sc0 from anti-sc0, charge set to +1 and -1 + } + + } else { + selLcPKPi = candidate.isSelLcToPKPi() >= selectionFlagLc; + selLcPiKP = candidate.isSelLcToPiKP() >= selectionFlagLc; + if (selLcPKPi) { + const auto& probs = candidate.mlProbLcToPKPi(); + fillMlOutput(probs, outputMlPKPi); + massCandPKPi = HfHelper::invMassLcToPKPi(candidate); + } + if (selLcPiKP) { + const auto& probs = candidate.mlProbLcToPiKP(); + fillMlOutput(probs, outputMlPiKP); + massCandPiKP = HfHelper::invMassLcToPiKP(candidate); + } + auto trackPos1 = candidate.template prong0_as(); + auto trackPos2 = candidate.template prong2_as(); + chargeCand = trackPos1.sign(); + if constexpr (IsMcRec) { + isSignal = std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi; + if (calTrkEff && countCand == 1 && (isSignal || !calEffEventWithCand)) { + calculateTrkEff(trackPos1, trackPos2, *mcParticles); + } + } + registry.fill(HIST("hPtProng0"), candidate.ptProng0()); + registry.fill(HIST("hPtProng1"), candidate.ptProng1()); + registry.fill(HIST("hPtProng2"), candidate.ptProng2()); + } + + if (isSignal) { + registry.fill(HIST("hPtCandSig"), ptCand); + registry.fill(HIST("hEtaSig"), ptCand); + registry.fill(HIST("hPhiSig"), phiCand); + registry.fill(HIST("hYSig"), yCand); + } + + if (selLcPKPi) { + registry.fill(HIST("hMassLcVsPt"), massCandPKPi, ptCand, efficiencyWeightCand); + registry.fill(HIST("hMassScVsPtVsSign"), massCandPKPi, ptCand, chargeCand, efficiencyWeightCand); + registry.fill(HIST("hMassLcData"), massCandPKPi, efficiencyWeightCand); + registry.fill(HIST("hSelectionStatusLcToPKPi"), selLcPKPi); + if (isPrompt) { + registry.fill(HIST("hPtCandSigPrompt"), ptCand); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), ptCand, multiplicityFT0M); + } else if (isNonPrompt) { + registry.fill(HIST("hPtCandSigNonPrompt"), ptCand); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), ptCand, multiplicityFT0M); + } + + entryCandCandRecoInfo(massCandPKPi, ptCand, outputMlPKPi[0], outputMlPKPi[1]); + entryCandCandGenInfo(isPrompt); + if (!skipMixedEventTableFilling) { + entryCand(candidate.phi(), etaCand, ptCand, massCandPKPi, poolBin, gCollisionId, timeStamp); + entryCandCharge(chargeCand); + } + } + + if (selLcPiKP) { + registry.fill(HIST("hMassLcVsPt"), massCandPiKP, ptCand, efficiencyWeightCand); + registry.fill(HIST("hMassScVsPtVsSign"), massCandPKPi, ptCand, chargeCand, efficiencyWeightCand); + registry.fill(HIST("hMassLcData"), massCandPiKP, efficiencyWeightCand); + registry.fill(HIST("hSelectionStatusLcToPiKP"), selLcPiKP); + if (isPrompt) { + registry.fill(HIST("hPtCandSigPrompt"), ptCand); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), ptCand, multiplicityFT0M); + } else if (isNonPrompt) { + registry.fill(HIST("hPtCandSigNonPrompt"), ptCand); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), ptCand, multiplicityFT0M); + } + entryCandCandRecoInfo(massCandPiKP, ptCand, outputMlPiKP[0], outputMlPiKP[1]); + entryCandCandGenInfo(isPrompt); + if (!skipMixedEventTableFilling) { + entryCand(candidate.phi(), etaCand, ptCand, massCandPiKP, poolBin, gCollisionId, timeStamp); + entryCandCharge(chargeCand); + } + } + + registry.fill(HIST("hCandBin"), poolBin); + // Correlation with hadrons + for (const auto& track : tracks) { + // Remove Lc daughters by checking track indices + if constexpr (!IsCandSc) { + if ((candidate.prong0Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex()) || (candidate.prong2Id() == track.globalIndex())) { + if (!storeAutoCorrelationFlag) { + continue; + } + correlationStatus = true; + } + } else { + const auto& candidateLc = candidate.template prongLc_as(); + if ((candidateLc.prong0Id() == track.globalIndex()) || (candidateLc.prong1Id() == track.globalIndex()) || (candidateLc.prong2Id() == track.globalIndex()) || (candidate.prong1Id() == track.globalIndex())) { + if (!storeAutoCorrelationFlag) { + continue; + } + correlationStatus = true; + } + } + if (!track.isGlobalTrackWoDCA()) { + continue; + } + if (pidTrkApplied) { + if (!passPIDSelection(track, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) { + continue; + } + } + if (correlateLcWithLeadingParticle) { + if (track.globalIndex() != leadingIndex) { + continue; + } + } + if constexpr (IsMcRec) { + if (calTrkEff && countCand == 1 && (isSignal || !calEffEventWithCand) && 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()); + if (std::abs(mcParticle.pdgCode()) == kProton) { + registry.fill(HIST("hPtTracksVsSignRecTrue"), track.pt(), track.sign()); + } + } + } + + if (selLcPKPi) { + fillCorrelationTable(fillTrkPID, track, candidate, outputMlPKPi, poolBin, correlationStatus, yCand, chargeCand, *mcParticles); + entryCandHadronRecoInfo(massCandPKPi, false); + } + if (selLcPiKP) { + fillCorrelationTable(fillTrkPID, track, candidate, outputMlPiKP, poolBin, correlationStatus, yCand, chargeCand, *mcParticles); + entryCandHadronRecoInfo(massCandPiKP, false); + } + + if (countCand == 1) { + 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); + } + } + } // end Hadron Tracks loop + countCand++; + } // end outer Lc loop + registry.fill(HIST("hZvtx"), collision.posZ()); + registry.fill(HIST("hMultFT0M"), multiplicityFT0M); + } + + template + void doMixEvent(CollisionType const& collisions, + TrackType const& tracks, + CandType const& candidates, + aod::McParticles const* mcParticles = nullptr) + { + + if (candidates.size() == 0) { + return; + } + + double yCand = -999.; + double ptCand = -999.; + int8_t chargeCand = 3; + double massCandPKPi = -999.0; + double massCandPiKP = -999.0; + bool selLcPKPi = false; + bool selLcPiKP = false; + + auto tracksTuple = std::make_tuple(candidates, tracks); + Pair const pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + + for (const auto& [c1, tracks1, c2, tracks2] : pairData) { + poolBin = corrBinning.getBin(std::make_tuple(c2.posZ(), c2.multFT0M())); + 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, assocParticle] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + yCand = estimateY(candidate); + ptCand = candidate.pt(); + if constexpr (IsMcRec) { + isPrompt = candidate.originMcRec() == RecoDecay::OriginType::Prompt; + isNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; + } + + if constexpr (IsCandSc) { + const auto& candidateLc = candidate.template prongLc_as(); + chargeCand = candidate.charge(); + + selLcPKPi = (candidateLc.isSelLcToPKPi() >= selectionFlagLc) && (candidate.statusSpreadLcMinvPKPiFromPDG()); + selLcPiKP = (candidateLc.isSelLcToPiKP() >= selectionFlagLc) && (candidate.statusSpreadLcMinvPiKPFromPDG()); + if (selLcPKPi) { + const auto& probs = candidateLc.mlProbLcToPKPi(); + fillMlOutput(probs, outputMlPKPi); + massCandPKPi = std::abs(HfHelper::invMassScRecoLcToPKPi(candidate, candidateLc) - HfHelper::invMassLcToPKPi(candidateLc)); + } + if (selLcPiKP) { + const auto& probs = candidateLc.mlProbLcToPiKP(); + fillMlOutput(probs, outputMlPiKP); + massCandPiKP = std::abs(HfHelper::invMassScRecoLcToPiKP(candidate, candidateLc) - HfHelper::invMassLcToPiKP(candidateLc)); + } + if constexpr (IsMcRec) { + isSignal = + ((std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::Sc0ToPKPiPi) && chargeCand == ChargeZero) || + ((std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScplusplusToPKPiPi) && std::abs(chargeCand) == ChargeScPlusPlus); + signSoftPion = candidate.template prong1_as().sign(); + } else { + signSoftPion = candidate.template prong1_as().sign(); + } + if (chargeCand == ChargeZero) { + chargeCand = (signSoftPion < ChargeZero) ? AssignedChargeSc0 : -AssignedChargeSc0; // to distingush sc0 from anti-sc0, charge set to +1 and -1 + } + } else { + selLcPKPi = candidate.isSelLcToPKPi() >= selectionFlagLc; + selLcPiKP = candidate.isSelLcToPiKP() >= selectionFlagLc; + if (selLcPKPi) { + const auto& probs = candidate.mlProbLcToPKPi(); + fillMlOutput(probs, outputMlPKPi); + massCandPKPi = HfHelper::invMassLcToPKPi(candidate); + } + if (selLcPiKP) { + const auto& probs = candidate.mlProbLcToPiKP(); + fillMlOutput(probs, outputMlPiKP); + massCandPiKP = HfHelper::invMassLcToPiKP(candidate); + } + auto trackPos1 = candidate.template prong0_as(); + chargeCand = trackPos1.sign(); + if constexpr (IsMcRec) { + isSignal = std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi; + } + } + + if (!assocParticle.isGlobalTrackWoDCA() || std::abs(yCand) > yCandMax) { + continue; + } + + if (pidTrkApplied) { + if (!passPIDSelection(assocParticle, trkPIDspecies, pidTPCMax, pidTOFMax, tofPIDThreshold, forceTOF)) { + continue; + } + } + + if (selLcPKPi) { + fillCorrelationTable(fillTrkPID, assocParticle, candidate, outputMlPKPi, poolBin, correlationStatus, yCand, chargeCand, *mcParticles); + entryCandHadronRecoInfo(massCandPKPi, false); + + if (isPrompt) { + registry.fill(HIST("hPtCandMcRecSigPrompt"), ptCand); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), ptCand, 0); + } else if (isNonPrompt) { + registry.fill(HIST("hPtCandMcRecSigNonPrompt"), ptCand); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), ptCand, 0); + } + } + + if (selLcPiKP) { + fillCorrelationTable(fillTrkPID, assocParticle, candidate, outputMlPiKP, poolBin, correlationStatus, yCand, chargeCand, *mcParticles); + entryCandHadronRecoInfo(massCandPiKP, false); + + if (isPrompt) { + registry.fill(HIST("hPtCandMcRecSigPrompt"), ptCand); + registry.fill(HIST("hPtVsMultiplicityMcRecPrompt"), ptCand, 0); + } else if (isNonPrompt) { + registry.fill(HIST("hPtCandMcRecSigNonPrompt"), ptCand); + registry.fill(HIST("hPtVsMultiplicityMcRecNonPrompt"), ptCand, 0); + } + } + } + } + } + + template + void doSameEventMcGen(CollisionType const& mcCollision, PartType const& mcParticles) + { + + int counterCharmCand = 0; + static constexpr std::size_t PDGChargeScale{3u}; + + registry.fill(HIST("hMcEvtCount"), 0); + BinningTypeMcGen const corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; + poolBin = corrBinningMcGen.getBin(std::make_tuple(mcCollision.posZ(), mcCollision.multMCFT0A())); + registry.fill(HIST("hMultFT0AMcGen"), mcCollision.multMCFT0A()); + + // find leading particle + if (correlateLcWithLeadingParticle) { + leadingIndex = findLeadingParticleMcGen(mcParticles, etaTrackMax.value, ptTrackMin.value); + } + // Mc Gen level + for (const auto& particle : mcParticles) { + + double massCand = -999.0; + bool const isCandFound = IsCandSc ? matchCandAndMass(particle, massCand) : matchCandAndMass(particle, massCand); + if (!isCandFound) { + continue; + } + double const yCand = RecoDecay::y(particle.pVector(), massCand); + + if (std::abs(yCand) > yCandGenMax || particle.pt() < ptCandMin) { + continue; + } + registry.fill(HIST("hCandBin"), 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"), yCand); + + int8_t chargeCand = pdg->GetParticle(particle.pdgCode())->Charge() / PDGChargeScale; // Retrieve charge + if (chargeCand == ChargeZero) { + chargeCand = (particle.pdgCode() > ChargeZero) ? AssignedChargeSc0 : -AssignedChargeSc0; // to distingush sc0 from anti-sc0, charge set to +1 and -1 + } + + isPrompt = particle.originMcGen() == RecoDecay::OriginType::Prompt; + isNonPrompt = particle.originMcGen() == RecoDecay::OriginType::NonPrompt; + if (isPrompt) { + registry.fill(HIST("hPtCandMcGenPrompt"), particle.pt()); + registry.fill(HIST("hPtCandVsChargeMcGenPrompt"), particle.pt(), chargeCand); + } else if (isNonPrompt) { + registry.fill(HIST("hPtCandMcGenNonPrompt"), particle.pt()); + registry.fill(HIST("hPtCandVsChargeMcGenNonPrompt"), particle.pt(), chargeCand); + } + + static constexpr std::size_t NDaughtersSc{4u}; + static constexpr std::size_t NDaughtersLc{3u}; + std::vector listDaughters{}; + listDaughters.clear(); + const std::size_t nDaughtersExpected = IsCandSc ? NDaughtersSc : NDaughtersLc; + + if (IsCandSc) { + if (massCand == o2::constants::physics::MassSigmaC0 || massCand == o2::constants::physics::MassSigmaCStar0) { + std::array const arrDaughSc0PDG = {kProton, -kKPlus, kPiPlus, kPiMinus}; + RecoDecay::getDaughters(particle, &listDaughters, arrDaughSc0PDG, 2); + } else { + std::array const arrDaughScPlusPDG = {kProton, -kKPlus, kPiPlus, kPiPlus}; + RecoDecay::getDaughters(particle, &listDaughters, arrDaughScPlusPDG, 2); + } + } else { + std::array const arrDaughLcPDG = {kProton, -kKPlus, kPiPlus}; + RecoDecay::getDaughters(particle, &listDaughters, arrDaughLcPDG, 2); + } + + int counterDaughters = 0; + std::vector prongsId(nDaughtersExpected); + if (listDaughters.size() == nDaughtersExpected) { + for (const auto& dauIdx : listDaughters) { + auto daughI = mcParticles.rawIteratorAt(dauIdx - mcParticles.offset()); + counterDaughters += 1; + prongsId[counterDaughters - 1] = daughI.globalIndex(); + } + } + counterCharmCand++; + + // Lc Hadron correlation dedicated section + // if it's a Lc particle, search for Hadron and evalutate correlations + registry.fill(HIST("hcountCandtriggersMcGen"), 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; + } + + if (std::find(prongsId.begin(), prongsId.end(), particleAssoc.globalIndex()) != prongsId.end()) { + 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)) { + continue; + } + + if (pidTrkApplied && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; // proton PID + } + + if (!particleAssoc.isPhysicalPrimary()) { + continue; + } + + if (correlateLcWithLeadingParticle) { + if (particleAssoc.globalIndex() != leadingIndex) { + continue; + } + } + + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + int8_t chargeAssoc = pdg->GetParticle(particleAssoc.pdgCode())->Charge(); // Retrieve charge + chargeAssoc = chargeAssoc / std::abs(chargeAssoc); + registry.fill(HIST("hPtParticleAssocMcGen"), particleAssoc.pt()); + float const cent = 100.0; // will be updated later + + entryCandHadronPair(getDeltaPhi(particleAssoc.phi(), particle.phi()), + particleAssoc.eta() - particle.eta(), + particle.pt(), + particleAssoc.pt() * chargeAssoc, + poolBin, + correlationStatus, + cent); + entryCandHadronPairY(particleAssoc.y() - yCand); + entryCandHadronRecoInfo(massCand, true); + entryCandHadronGenInfo(isPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + entryPairCandCharge(chargeCand); + } // end inner loop + } // end outer loop + registry.fill(HIST("hcountCandHadronPerEvent"), counterCharmCand); + registry.fill(HIST("hZvtx"), mcCollision.posZ()); + } + + //} + + /// Lc-hadron correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) + void processDataLc(SelCollisions::iterator const& collision, + TracksData const& tracks, + CandsLcDataFiltered const& candidates, + aod::BCsWithTimestamps const&) + { + doSameEvent(collision, tracks, candidates); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processDataLc, "Process data", true); + + void processDataSc(SelCollisions::iterator const& collision, + TracksData const& tracks, + aod::Tracks const&, + aod::HfCandSc const& candidates, + CandsLcData const&, + aod::BCsWithTimestamps const&) // MUST be last among index-compatible + { + doSameEvent(collision, tracks, candidates); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processDataSc, "Process data Sc", false); + + /// Lc-Hadron correlation process starts for McRec + void processMcRecLc(SelCollisions::iterator const& collision, + TracksWithMc const& tracks, + CandsLcMcRecFiltered const& candidates, + aod::McParticles const& mcParticles) + { + doSameEvent(collision, tracks, candidates, &mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcRecLc, "Process Mc Reco mode", false); + + /// Lc-Hadron correlation process starts for McRec + void processMcRecSc(SelCollisions::iterator const& collision, + TracksWithMc const& tracks, + aod::TracksWMc const&, + CandsScMcRec const& candidates, + CandsLcData const&, + aod::McParticles const& mcParticles) + { + doSameEvent(collision, tracks, candidates, &mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcRecSc, "Process Mc Reco mode", false); + + void processDataMixedEventSc(SelCollisions const& collisions, + TracksData const& tracks, + aod::Tracks const&, + aod::HfCandSc const& candidates, + CandsLcData const&) + { + doMixEvent(collisions, tracks, candidates); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processDataMixedEventSc, "Process Mixed Event Data", false); + + void processDataMixedEventLc(SelCollisions const& collisions, + CandsLcDataFiltered const& candidates, + TracksData const& tracks) + { + + doMixEvent(collisions, tracks, candidates); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processDataMixedEventLc, "Process Mixed Event Data", false); + + void processMcRecMixedEventSc(SelCollisions const& collisions, + TracksWithMc const& tracks, + aod::TracksWMc const&, + soa::Join const& candidates, + CandsLcData const&, + aod::McParticles const& mcParticles) + { + doMixEvent(collisions, tracks, candidates, &mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcRecMixedEventSc, "Process Mixed Event McRec", false); + + void processMcRecMixedEventLc(SelCollisions const& collisions, + CandsLcMcRecFiltered const& candidates, + TracksWithMc const& tracks, + aod::McParticles const& mcParticles) + { + doMixEvent(collisions, tracks, candidates, &mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcRecMixedEventLc, "Process Mixed Event McRec", false) + + /// Lc-Hadron correlation pair builder - for Mc Gen-level analysis + void processMcGenLc(SelCollisionsMc::iterator const& mcCollision, + CandidatesLcMcGen const& mcParticles) + { + doSameEventMcGen(mcCollision, mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcGenLc, "Process Mc Gen Lc mode", false); + + void processMcGenSc(SelCollisionsMc::iterator const& mcCollision, + CandidatesScMcGen const& mcParticles) + { + doSameEventMcGen(mcCollision, mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcGenSc, "Process Mc Gen Sc mode", false); + + void processMcGenMixedEvent(SelCollisionsMc const& collisions, + CandidatesLcMcGen const& mcParticles) + { + BinningTypeMcGen const corrBinningMcGen{{binsZVtx, binsMultiplicityMc}, true}; + auto tracksTuple = std::make_tuple(mcParticles, mcParticles); + Pair const pairMcGen{corrBinningMcGen, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + for (const auto& [c1, tracks1, c2, tracks2] : pairMcGen) { + 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 const yL = RecoDecay::y(candidate.pVector(), MassLambdaCPlus); + if (std::abs(yL) > 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; + } + if (pidTrkApplied && (std::abs(particleAssoc.pdgCode()) != kProton)) { + continue; // proton PID + } + int8_t const chargeLc = pdg->GetParticle(candidate.pdgCode())->Charge(); // Retrieve charge + int8_t const chargeAssoc = pdg->GetParticle(particleAssoc.pdgCode())->Charge(); // Retrieve charge + float cent = 100.0; // will be updated later + + int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, particleAssoc, true); + bool isPrompt = candidate.originMcGen() == RecoDecay::OriginType::Prompt; + entryCandHadronPair(getDeltaPhi(particleAssoc.phi(), candidate.phi()), + particleAssoc.eta() - candidate.eta(), + candidate.pt() * chargeLc / std::abs(chargeLc), + particleAssoc.pt() * chargeAssoc / std::abs(chargeAssoc), + poolBin, + correlationStatus, + cent); + entryCandHadronPairY(particleAssoc.y() - yL); + entryCandHadronRecoInfo(MassLambdaCPlus, true); + entryCandHadronGenInfo(isPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + } + } + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcGenMixedEvent, "Process Mixed Event McGen", false); + + void processDataLambdaV0(SelCollisions::iterator const&, + TracksData const& tracks, aod::V0Datas const& v0s) + { + fillV0Histograms(v0s, tracks); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processDataLambdaV0, "Data process for v0 lambda", false); + + void processMcLambdaV0(SelCollisions::iterator const&, + TracksWithMc const& tracks, soa::Join const& v0s, aod::McParticles const&) + { + fillV0Histograms(v0s, tracks); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcLambdaV0, "Mc process for v0 lambda", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx b/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx new file mode 100644 index 00000000000..f418af0e1fb --- /dev/null +++ b/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx @@ -0,0 +1,567 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file derivedDataCreatorCorrelationsReduced.cxx +/// \brief CharmHadrons-Hadrons correlator tree creator for data and MC-reco analyses +/// \author Marcello Di Costanzo , Politecnico and INFN Torino +/// \author Stefano Politanò , CERN +/// \author Wu Chuntai , CCNU, INFN Padova, and Padova University + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#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; +using namespace o2::hf_centrality; +using namespace o2::hf_evsel; + +enum CandidateType { + DplusToPiKPi = 0, + DsToKKPi, + DsToPiKK, + D0ToPiK, + D0ToKPi, + Hadron +}; + +/// Code to select collisions with at least one Ds meson +struct HfDerivedDataCreatorCorrelationsReduced { + Produces rowCollisions; // Table with reduced collision info + Produces rowSECharmHadPairs; // Table with same-event pairs info + Produces rowSEHadHadPairs; // Table with same-event pairs info + Produces rowAssocBases; // Table with associated candidate base info + Produces rowAssocTrkSels; // Table with associated track selection info + Produces rowTrigBases; // Table with base trigger candidate info + Produces rowTrigCharms; // Table with charm trigger candidate selection info + Produces rowTrigHads; // Table with hadron trigger candidate selection info + + Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3, FV0A: 4)"}; + Configurable selectionFlag{"selectionFlag", 15, "Selection Flag for hadron (ML score tables are required to run the task)"}; + Configurable forceCharmInCollision{"forceCharmInCollision", true, "Flag to force charm in collision"}; + 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."}; + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable ptCandMin{"ptCandMin", 0., "min. cand. pT"}; + Configurable ptCandMax{"ptCandMax", 24., "max. cand. pT"}; + Configurable tpcNClsCrossedRowsMin{"tpcNClsCrossedRowsMin", 70, "min. TPC crossed rows for associated tracks"}; + Configurable etaTrkMax{"etaTrkMax", 1., "max. track eta"}; + Configurable ptTrkMin{"ptTrkMin", 0.2, "min. track pT"}; + Configurable ptTrkMax{"ptTrkMax", 3., "max. track pT"}; + Configurable dcaXYTrkMax{"dcaXYTrkMax", 1., "max. track DCA XY"}; + Configurable dcaZTrkMax{"dcaZTrkMax", 1., "max. track DCA Z"}; + Configurable usePtDiffDcaXYCut{"usePtDiffDcaXYCut", false, "Use pt-differential DCAxy cut for associated tracks"}; + Configurable dcaXYTrkNSigmaMax{"dcaXYTrkNSigmaMax", 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"}; + Configurable dcaXYPtPrimTrkFunc{"dcaXYPtPrimTrkFunc", "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"}; + Configurable deltaEtaAbsMin{"deltaEtaAbsMin", 0.5, "min. pair delta eta"}; + Configurable deltaEtaAbsMax{"deltaEtaAbsMax", 2., "max. pair delta eta"}; + Configurable downSampleTrksFactor{"downSampleTrksFactor", 1., "Fraction of associated tracks to keep"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + Configurable centMaxForDownSample{"centMaxForDownSample", 101., "Maximum centrality for the application of the downsampling factor"}; + Configurable> binsPtTrig{"binsPtTrig", std::vector{0., 1., 2., 3., 5., 8., 12., 24., 36.}, "pT bin limits for trigger candidates"}; + Configurable> binsPtAssoc{"binsPtAssoc", std::vector{0.2, 1., 2., 50.}, "pT bin limits for associated particles"}; + + HfEventSelection hfEvSel; // event selection and monitoring + o2::framework::Service ccdb; + SliceCache cache; + + double massCharm{0.}; + TF1* funcDcaXYPtCutPrimTrk = nullptr; + + using CollsWithCentMult = soa::Join; + using CandDsData = soa::Filtered>; + using CandDplusData = soa::Filtered>; + using CandD0Data = soa::Filtered>; + using TracksData = soa::Filtered>; + + 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 filterSelectTrkData = (nabs(aod::track::eta) < etaTrkMax) && (aod::track::pt > ptTrkMin) && (aod::track::pt < ptTrkMax) && (nabs(aod::track::dcaXY) < dcaXYTrkMax) && (nabs(aod::track::dcaZ) < dcaZTrkMax); + + Preslice candsDsPerColl = aod::hf_cand::collisionId; + Preslice candsDplusPerColl = aod::hf_cand::collisionId; + Preslice candsD0PerColl = aod::hf_cand::collisionId; + Preslice trackIndicesPerColl = aod::track::collisionId; + + Partition selectedDsToKKPi = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlag; + Partition selectedDsToPiKK = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlag; + Partition selectedD0ToPiK = aod::hf_sel_candidate_d0::isSelD0 >= selectionFlag; + Partition selectedD0ToKPi = aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlag; + + ConfigurableAxis binsInvMass{"binsInvMass", {300, 1.6, 2.2}, ""}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {100, 0., 10000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsCent{"binsCent", {100, 0., 100.}, "Centrality bins"}; + ConfigurableAxis binsPosZ{"binsPosZ", {100, -10., 10.}, "Primary vertex z coordinate"}; + ConfigurableAxis binsEta{"binsEta", {50, -2., 2.}, "Eta bins"}; + ConfigurableAxis binsPhi{"binsPhi", {64, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}, "Phi bins"}; + ConfigurableAxis binsDeltaEta{"binsDeltaEta", {100, -2., 2.}, "Delta Eta bins"}; + ConfigurableAxis binsDeltaPhi{"binsDeltaPhi", {64, -3., 3.}, "Delta Phi bins"}; + ConfigurableAxis binsMlOne{"binsMlOne", {100, 0., 1.}, ""}; + ConfigurableAxis binsMlTwo{"binsMlTwo", {100, 0., 1.}, ""}; + ConfigurableAxis binsDca{"binsDca", {200, -1., 1.}, ""}; + + HistogramRegistry registry{"registry", {}}; + + void init(InitContext&) + { + if (doprocessDplusSameEvent || doprocessDplusMixedEvent) { + massCharm = o2::constants::physics::MassDPlus; + } else if (doprocessDsSameEvent || doprocessDsMixedEvent) { + massCharm = o2::constants::physics::MassDS; + } else if (doprocessD0SameEvent || doprocessD0MixedEvent) { + massCharm = o2::constants::physics::MassD0; + } else if (doprocessHadronHadronSameEvent || doprocessHadronHadronMixedEvent) { + LOG(info) << "Charm mass not set, processing Hadron-Hadron case"; + } else { + LOG(fatal) << "No decay channel selected to process"; + } + + hfEvSel.addHistograms(registry); // collision monitoring + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + const AxisSpec axisCent = {binsCent, "Centrality"}; + const AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + const AxisSpec axisPosZ = {binsPosZ, "PosZ"}; + const AxisSpec axisEta = {binsEta, "#it{#eta}"}; + const AxisSpec axisPhi = {binsPhi, "#it{#varphi}"}; + const AxisSpec axisPtTrig = {(std::vector)binsPtTrig, "#it{p}_{T} Trig (GeV/#it{c})"}; + const AxisSpec axisPtAssoc = {(std::vector)binsPtAssoc, "#it{p}_{T} Assoc (GeV/#it{c})"}; + const AxisSpec axisDcaXY = {binsDca, "DCA XY (cm)"}; + const AxisSpec axisDcaZ = {binsDca, "DCA Z (cm)"}; + + // Histograms for data analysis + registry.add("hPhiVsPtTrig", "Trigger candidates phiVsPt", {HistType::kTH2F, {{axisPhi}, {axisPtTrig}}}); + registry.add("hEtaVsPtTrig", "Trigger candidates etaVsPt", {HistType::kTH2F, {{axisEta}, {axisPtTrig}}}); + registry.add("hPhiVsPtTrigAssoc", "Associated particles phiVsPt", {HistType::kTH3F, {{axisPhi}, {axisPtTrig}, {axisPtAssoc}}}); + registry.add("hEtaVsPtTrigAssoc", "Associated particles etaVsPt", {HistType::kTH3F, {{axisEta}, {axisPtTrig}, {axisPtAssoc}}}); + registry.add("hPhiVsPtAssoc", "Associated particles phiVsPt", {HistType::kTH2F, {{axisPhi}, {axisPtAssoc}}}); + registry.add("hEtaVsPtAssoc", "Associated particles etaVsPt", {HistType::kTH2F, {{axisEta}, {axisPtAssoc}}}); + registry.add("hDcaXYVsPtAssoc", "Associated particles DCAxyVsPt", {HistType::kTH2F, {{axisDcaXY}, {axisPtAssoc}}}); + registry.add("hDcaZVsPtAssoc", "Associated particles DCAzVsPt", {HistType::kTH2F, {{axisDcaZ}, {axisPtAssoc}}}); + + // Setup pt-dependent DCAxy cut function + if (usePtDiffDcaXYCut) { + funcDcaXYPtCutPrimTrk = new TF1("funcDcaXYPtCutPrimTrk", Form("[0]*%s", dcaXYPtPrimTrkFunc.value.data()), 0.001, 100); + funcDcaXYPtCutPrimTrk->SetParameter(0, dcaXYTrkNSigmaMax); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", dcaXYPtPrimTrkFunc.value.data())); + } + }; // end init + + /// Get charm hadron candidate mass + /// \param candidate is the charm hadron candidate + template + double getCandMass(const TCand& candidate) + { + if constexpr (CandType == CandidateType::DsToKKPi) { + return HfHelper::invMassDsToKKPi(candidate); + } + if constexpr (CandType == CandidateType::DsToPiKK) { + return HfHelper::invMassDsToPiKK(candidate); + } + if constexpr (CandType == CandidateType::DplusToPiKPi) { + return HfHelper::invMassDplusToPiKPi(candidate); + } + if constexpr (CandType == CandidateType::D0ToPiK) { + return HfHelper::invMassD0ToPiK(candidate); + } + if constexpr (CandType == CandidateType::D0ToKPi) { + return HfHelper::invMassD0barToKPi(candidate); + } + return -1.; + } + + /// Get charm hadron bdt scores + /// \param candidate is the charm hadron candidate + template + std::array getCandMlScores(const TCand& candidate) + { + std::array outputMl{-999.f, -999.f}; + if constexpr (CandType == CandidateType::DsToKKPi) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; + } + } + if constexpr (CandType == CandidateType::DsToPiKK) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; + } + } + if constexpr (CandType == CandidateType::DplusToPiKPi) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; + } + } + if constexpr (CandType == CandidateType::D0ToPiK) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; + } + } + if constexpr (CandType == CandidateType::D0ToKPi) { + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; + } + } + return outputMl; + } + + /// Check event selections for collision and fill the collision table + /// \param collision is the collision + template + bool checkCollision(Coll const& collision, float& cent, float& mult) + { + o2::hf_evsel::HfCollisionRejectionMask collRejMask{}; + if (centEstimator == CentralityEstimator::FT0A) { + collRejMask = hfEvSel.getHfCollisionRejectionMask(collision, cent, ccdb, registry); + mult = collision.multFT0A(); + } else if (centEstimator == CentralityEstimator::FT0C) { + collRejMask = hfEvSel.getHfCollisionRejectionMask(collision, cent, ccdb, registry); + mult = collision.multFT0C(); + } else if (centEstimator == CentralityEstimator::FT0M) { + collRejMask = hfEvSel.getHfCollisionRejectionMask(collision, cent, ccdb, registry); + mult = collision.multFT0M(); + } else if (centEstimator == CentralityEstimator::FV0A) { + collRejMask = hfEvSel.getHfCollisionRejectionMask(collision, cent, ccdb, registry); + mult = collision.multFV0A(); + } else { + LOG(fatal) << "Centrality estimator not recognized for collision selection"; + std::abort(); + } + hfEvSel.fillHistograms(collision, collRejMask, cent); + return collRejMask == 0; + } + + /// Checks if the trigger cand-associated track pair can be accepted for SE correlation + /// \param assTrk is the associated track + /// \param cand is the trigger candidate + template + bool acceptSameEvtPair(TAssocTrk const& assTrk, TCand const& cand, double deltaEta) + { + if (std::abs(deltaEta) <= deltaEtaAbsMin || std::abs(deltaEta) > deltaEtaAbsMax) { + return false; + } + + if (!assTrk.isGlobalTrackWoDCA() || assTrk.tpcNClsCrossedRows() < tpcNClsCrossedRowsMin) { + return false; + } + + int const trackGlobalIndex = assTrk.globalIndex(); + if constexpr (CandType == CandidateType::Hadron) { + if (!cand.isGlobalTrackWoDCA() || cand.tpcNClsCrossedRows() < tpcNClsCrossedRowsMin) { + return false; + } + if (trackGlobalIndex <= cand.globalIndex()) { + return false; // skip self-correlation and avoid pair duplication for hadron-hadron + } + } else { // Remove Daughter-Cand pairs for charm-hadron correlations + if constexpr ((requires { cand.prong2Id(); })) { // Check 3-prong + if (trackGlobalIndex == cand.prong0Id() || trackGlobalIndex == cand.prong1Id() || trackGlobalIndex == cand.prong2Id()) { + return false; + } + } else { // Check 2-prong + if (trackGlobalIndex == cand.prong0Id() || trackGlobalIndex == cand.prong1Id()) { + return false; + } + } + } + return true; + } + + /// Fill histograms and tables for same-event correlations + /// \param trigCands are the trigger candidates + /// \param assTrks are the associated tracks + /// \param collCentrality is the collision centrality + template + void fillSameEvent(TTrigCands const& trigCands, + TAssocTrks const& assTrks, + const float collCentrality) + { + for (const auto& trigCand : trigCands) { + double trigCandPt = trigCand.pt(); + registry.fill(HIST("hPhiVsPtTrig"), RecoDecay::constrainAngle(trigCand.phi(), -o2::constants::math::PIHalf), trigCandPt); + registry.fill(HIST("hEtaVsPtTrig"), trigCand.eta(), trigCandPt); + if constexpr (CandType == CandidateType::Hadron) { + rowTrigHads(rowCollisions.lastIndex(), trigCandPt, trigCand.tpcNClsCrossedRows(), trigCand.itsClusterMap(), trigCand.itsNCls(), trigCand.dcaXY(), trigCand.dcaZ()); + } else { + std::array outputMl = getCandMlScores(trigCand); + rowTrigCharms(rowCollisions.lastIndex(), trigCandPt, getCandMass(trigCand), outputMl[0], outputMl[1]); + } + + for (const auto& assTrk : assTrks) { + double assTrkPt = assTrk.pt(); + if (usePtDiffDcaXYCut) { + float const dcaXYTrkCut = funcDcaXYPtCutPrimTrk->Eval(assTrkPt); + if (std::fabs(assTrk.dcaXY()) > dcaXYTrkCut) { + continue; + } + } + + double deltaEta = assTrk.eta() - trigCand.eta(); + if (!acceptSameEvtPair(assTrk, trigCand, deltaEta)) { + continue; + } + if (downSampleTrksFactor < 1.) { + float const pseudoRndm = assTrkPt * 1000. - static_cast(assTrkPt * 1000); + if (assTrkPt < ptMaxForDownSample && collCentrality < centMaxForDownSample && pseudoRndm >= downSampleTrksFactor) { + continue; + } + } + registry.fill(HIST("hPhiVsPtTrigAssoc"), RecoDecay::constrainAngle(assTrk.phi(), -o2::constants::math::PIHalf), trigCandPt, assTrkPt); + registry.fill(HIST("hEtaVsPtTrigAssoc"), assTrk.eta(), trigCandPt, assTrkPt); + registry.fill(HIST("hPhiVsPtAssoc"), RecoDecay::constrainAngle(assTrk.phi(), -o2::constants::math::PIHalf), assTrkPt); + registry.fill(HIST("hEtaVsPtAssoc"), assTrk.eta(), assTrkPt); + registry.fill(HIST("hDcaXYVsPtAssoc"), assTrk.dcaXY(), assTrkPt); + registry.fill(HIST("hDcaZVsPtAssoc"), assTrk.dcaZ(), assTrkPt); + + double deltaPhi = RecoDecay::constrainAngle(assTrk.phi() - trigCand.phi(), -o2::constants::math::PIHalf); + rowAssocTrkSels(assTrk.tpcNClsCrossedRows(), assTrk.itsClusterMap(), assTrk.itsNCls(), assTrk.dcaXY(), assTrk.dcaZ()); + if constexpr (CandType == CandidateType::Hadron) { + rowSEHadHadPairs(rowCollisions.lastIndex(), rowTrigHads.lastIndex(), assTrkPt, deltaEta, deltaPhi); + } else { + rowSECharmHadPairs(rowCollisions.lastIndex(), rowTrigCharms.lastIndex(), assTrkPt, deltaEta, deltaPhi); + } + } + } + } + + /// Fill charm hadron tables for mixed-event + /// \param trigCands are the charm trigger candidates + template + void fillCharmMixedEvent(TTrigCands const& trigCands) + { + for (const auto& trigCand : trigCands) { + registry.fill(HIST("hPhiVsPtTrig"), RecoDecay::constrainAngle(trigCand.phi(), -o2::constants::math::PIHalf), trigCand.pt()); + registry.fill(HIST("hEtaVsPtTrig"), trigCand.eta(), trigCand.pt()); + + std::array outputMl = getCandMlScores(trigCand); + rowTrigBases(trigCand.phi(), trigCand.eta()); + rowTrigCharms(rowCollisions.lastIndex(), trigCand.pt(), getCandMass(trigCand), outputMl[0], outputMl[1]); + } + } + + /// Fill track tables for mixed-event + /// \param assTrks are the associated tracks + /// \param collCentrality is the collision centrality + template + void fillTrkMixedEvent(TAssocTrks const& assTrks, + const float collCentrality) + { + bool first = true; + for (const auto& assTrk : assTrks) { + if (!assTrk.isGlobalTrackWoDCA() || assTrk.tpcNClsCrossedRows() < tpcNClsCrossedRowsMin) { + continue; + } + double assTrkPt = assTrk.pt(); + if (usePtDiffDcaXYCut) { + float const dcaXYTrkCut = funcDcaXYPtCutPrimTrk->Eval(assTrkPt); + if (std::fabs(assTrk.dcaXY()) > dcaXYTrkCut) { + continue; + } + } + if (!first && downSampleTrksFactor < 1.) { // skip downsampling for the first track to avoid empty tables + float const pseudoRndm = assTrkPt * 1000. - static_cast(assTrkPt * 1000); + if (assTrkPt < ptMaxForDownSample && collCentrality < centMaxForDownSample && pseudoRndm >= downSampleTrksFactor) { + continue; + } + } + first = false; + registry.fill(HIST("hPhiVsPtAssoc"), RecoDecay::constrainAngle(assTrk.phi(), -o2::constants::math::PIHalf), assTrkPt); + registry.fill(HIST("hEtaVsPtAssoc"), assTrk.eta(), assTrkPt); + registry.fill(HIST("hDcaXYVsPtAssoc"), assTrk.dcaXY(), assTrkPt); + registry.fill(HIST("hDcaZVsPtAssoc"), assTrk.dcaZ(), assTrkPt); + rowAssocBases(rowCollisions.lastIndex(), assTrk.phi(), assTrk.eta(), assTrkPt); + rowAssocTrkSels(assTrk.tpcNClsCrossedRows(), assTrk.itsClusterMap(), assTrk.itsNCls(), assTrk.dcaXY(), assTrk.dcaZ()); + } + } + + // Dplus with ML selections + void processDplusSameEvent(CollsWithCentMult::iterator const& coll, + CandDplusData const& candsDplus, + TracksData const& tracks) + { + if (forceCharmInCollision && candsDplus.size() < 1) { + return; + } + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillSameEvent(candsDplus, tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processDplusSameEvent, "Process Same Event for Dplus candidates", true); + + // Dplus with ML selections + void processDplusMixedEvent(CollsWithCentMult::iterator const& coll, + CandDplusData const& candsDplus, + TracksData const& tracks) + { + if (forceCharmInCollision && candsDplus.size() < 1) { + return; + } + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillCharmMixedEvent(candsDplus); + fillTrkMixedEvent(tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processDplusMixedEvent, "Process Mixed Event for Dplus candidates", false); + + // Ds with ML selections + void processDsSameEvent(CollsWithCentMult::iterator const& coll, + TracksData const& tracks, + CandDsData const&) + { + auto candsDsToPiKK = selectedDsToPiKK->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + auto candsDsToKKPi = selectedDsToKKPi->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + if (forceCharmInCollision && candsDsToPiKK.size() < 1 && candsDsToKKPi.size() < 1) { + return; + } + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillSameEvent(candsDsToPiKK, tracks, cent); + fillSameEvent(candsDsToKKPi, tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processDsSameEvent, "Process Same Event for Ds candidates", false); + + // Ds with ML selections + void processDsMixedEvent(CollsWithCentMult::iterator const& coll, + TracksData const& tracks, + CandDsData const&) + { + auto candsDsToPiKK = selectedDsToPiKK->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + auto candsDsToKKPi = selectedDsToKKPi->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + if (forceCharmInCollision && candsDsToPiKK.size() < 1 && candsDsToKKPi.size() < 1) { + return; + } + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillCharmMixedEvent(candsDsToPiKK); + fillCharmMixedEvent(candsDsToKKPi); + fillTrkMixedEvent(tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processDsMixedEvent, "Process Mixed Event for Ds candidates", false); + + // D0 with ML selections + void processD0SameEvent(CollsWithCentMult::iterator const& coll, + TracksData const& tracks, + CandD0Data const&) + { + auto candsD0ToPiK = selectedD0ToPiK->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + auto candsD0ToKPi = selectedD0ToKPi->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + if (forceCharmInCollision && candsD0ToPiK.size() < 1 && candsD0ToKPi.size() < 1) { + return; + } + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillSameEvent(candsD0ToPiK, tracks, cent); + fillSameEvent(candsD0ToKPi, tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processD0SameEvent, "Process Same Event for D0 candidates", false); + + // D0 with ML selections + void processD0MixedEvent(CollsWithCentMult::iterator const& coll, + TracksData const& tracks, + CandD0Data const&) + { + auto candsD0ToPiK = selectedD0ToPiK->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + auto candsD0ToKPi = selectedD0ToKPi->sliceByCached(aod::hf_cand::collisionId, coll.globalIndex(), cache); + if (forceCharmInCollision && candsD0ToPiK.size() < 1 && candsD0ToKPi.size() < 1) { + return; + } + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillCharmMixedEvent(candsD0ToPiK); + fillCharmMixedEvent(candsD0ToKPi); + fillTrkMixedEvent(tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processD0MixedEvent, "Process Mixed Event for D0 candidates", false); + + // Hadron Hadron Same Event + void processHadronHadronSameEvent(CollsWithCentMult::iterator const& coll, + TracksData const& tracks) + { + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillSameEvent(tracks, tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processHadronHadronSameEvent, "Process Same Event for hadron candidates", false); + + // Hadron Hadron Mixed Event + void processHadronHadronMixedEvent(CollsWithCentMult::iterator const& coll, + TracksData const& tracks) + { + float cent{-1.}, mult{-1.}; + if (!checkCollision(coll, cent, mult)) { + return; + } + rowCollisions(mult, coll.numContrib(), cent, coll.posZ()); + fillTrkMixedEvent(tracks, cent); + } + PROCESS_SWITCH(HfDerivedDataCreatorCorrelationsReduced, processHadronHadronMixedEvent, "Process Mixed Event for hadron candidates", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFC/TableProducer/femtoDreamProducer.cxx b/PWGHF/HFC/TableProducer/femtoDreamProducer.cxx index 3a2bd3434e8..6487d9c562a 100644 --- a/PWGHF/HFC/TableProducer/femtoDreamProducer.cxx +++ b/PWGHF/HFC/TableProducer/femtoDreamProducer.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -12,44 +12,98 @@ /// \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 +/// \author Yunfan Liu, Central China Normal University, yunfan.l@cern.ch -#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/DataModel/FemtoDerived.h" +#include "PWGCF/FemtoDream/Core/femtoDreamSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamTrackSelection.h" #include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseDplusToPiKPi.h" +#include "PWGHF/Core/HfMlResponseLcToPKPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#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::analysis; 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 { + All = 0, + RejEveSel, + RejNoTracksAndCharm, + TrackSelected, + CharmSelected, + PairSelected +}; + +// ml modes +enum MlMode : uint8_t { + NoMl = 0, + FillMlFromSelector, + FillMlFromNewBDT +}; + +// decay channels +enum DecayChannel { DplusToPiKPi = 0, + LcToPKPi +}; struct HfFemtoDreamProducer { Produces outputCollision; + Produces rowMasks; Produces rowCandCharmHad; Produces rowCandMcCharmHad; Produces rowCandCharmHadGen; Produces outputPartsIndex; + Produces outputPartsTime; Produces outputMcCollision; Produces outputCollsMcLabels; Produces outputParts; @@ -64,34 +118,26 @@ struct HfFemtoDreamProducer { 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)"}; - - /// Event selection - // Configurable evtZvtx{"evtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; - // Configurable evtTriggerCheck{"evtTriggerCheck", true, "Evt sel: check for trigger"}; - // Configurable evtTriggerSel{"evtTriggerSel", kINT7, "Evt sel: trigger"}; - // Configurable evtOfflineCheck{"evtOfflineCheck", false, "Evt sel: check for offline selection"}; - // Configurable evtAddOfflineCheck{"evtAddOfflineCheck", false, "Evt sel: additional checks for offline selection (not part of sel8 yet)"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"EventFiltering/PWGHF/BDTLc"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_LcToPKPi.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"}; - Configurable evtAddOfflineCheck{"evtAddOfflineCheck", false, "Evt sel: additional checks for offline selection (not part of sel8 yet)"}; - Configurable evtOfflineCheck{"evtOfflineCheck", false, "Evt sel: check for offline selection"}; - Configurable evtTriggerCheck{"evtTriggerCheck", true, "Evt sel: check for trigger"}; - Configurable evtTriggerSel{"evtTriggerSel", kINT7, "Evt sel: trigger"}; - Configurable evtZvtx{"evtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; + // 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"}; + /// Charm hadron table + Configurable selectionFlagHadron{"selectionFlagHadron", 1, "Selection Flag for Charm Hadron: 1 for Lc, 7 for Dplus (Topologic and PID cuts)"}; + Configurable useCent{"useCent", false, "Enable centrality for Charm Hadron"}; 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> trkPIDspecies{"trkPIDspecies", std::vector{o2::track::PID::Pion, o2::track::PID::Kaon, o2::track::PID::Proton, o2::track::PID::Deuteron}, "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"}; @@ -103,50 +149,77 @@ struct HfFemtoDreamProducer { 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: ")}; + // ML inference + Configurable applyMlMode{"applyMlMode", 1, "None: 0, BDT model from candidate selector: 1, New BDT model on Top of candidate selector: 2"}; + 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"}; - using CandidateLc = soa::Join; - using CandidateLcMc = soa::Join; + FemtoDreamTrackSelection trackCuts; + + o2::analysis::HfMlResponseLcToPKPi hfMlResponse; + o2::analysis::HfMlResponseDplusToPiKPi hfMlResponseDplus; + std::vector outputMlDplus; + std::vector outputMlPKPi; + std::vector outputMlPiKP; + o2::ccdb::CcdbApi ccdbApi; + o2::hf_evsel::HfEventSelection hfEvSel; + 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 + + float magField{}; + int runNumber{}; + using CandidateDplus = soa::Join; + using CandidateDplusMc = soa::Join; + 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 FemtoHFTracks = soa::Join; using FemtoHFTrack = FemtoHFTracks::iterator; using FemtoHFMcTracks = soa::Join; using FemtoHFMcTrack = FemtoHFMcTracks::iterator; using GeneratedMc = soa::Filtered>; - FemtoDreamCollisionSelection colCuts; - FemtoDreamTrackSelection trackCuts; - - Filter filterSelectCandidateLc = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc); + Filter filterSelectCandidateDplus = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagHadron || aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlagHadron); + Filter filterSelectCandidateLc = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagHadron || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagHadron); HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry TrackRegistry{"Tracks", {}, OutputObjHandlingPolicy::AnalysisObject}; - - HfHelper hfHelper; - - 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 + HistogramRegistry trackRegistry{"Tracks", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) { - std::array processes = {doprocessDataCharmHad, doprocessMcCharmHad, doprocessDataCharmHadWithML, doprocessMcCharmHadWithML, doprocessMcCharmHadGen}; + std::array processes = {doprocessDataDplusToPiKPi, doprocessMcDplusToPiKPi, doprocessDataDplusToPiKPiWithML, doprocessMcDplusToPiKPiWithML, doprocessMcDplusToPiKPiGen, + doprocessDataLcToPKPi, doprocessMcLcToPKPi, doprocessDataLcToPKPiWithML, doprocessMcLcToPKPiWithML, doprocessMcLcToPKPiGen}; 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}}); - - colCuts.setCuts(evtZvtx.value, evtTriggerCheck.value, evtTriggerSel.value, evtOfflineCheck.value, evtAddOfflineCheck.value, isRun3.value); - colCuts.init(&qaRegistry); + int const 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 = PairSelected + 1; + std::string labels[kEventTypes]; + labels[Event::All] = "All events"; + labels[Event::RejEveSel] = "rejected by event selection"; + labels[Event::RejNoTracksAndCharm] = "rejected by no tracks and charm"; + labels[Event::TrackSelected] = "with tracks "; + labels[Event::CharmSelected] = "with charm hadrons "; + labels[Event::PairSelected] = "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); @@ -163,7 +236,7 @@ struct HfFemtoDreamProducer { trackCuts.setSelection(trkPIDnSigmaMax, femtoDreamTrackSelection::kPIDnSigmaMax, femtoDreamSelection::kAbsUpperLimit); trackCuts.setPIDSpecies(trkPIDspecies); trackCuts.setnSigmaPIDOffset(trkPIDnSigmaOffsetTPC, trkPIDnSigmaOffsetTOF); - trackCuts.init(&qaRegistry, &TrackRegistry); + trackCuts.init(&qaRegistry, &trackRegistry); runNumber = 0; magField = 0.0; @@ -172,12 +245,26 @@ struct HfFemtoDreamProducer { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - int64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + hfEvSel.addHistograms(qaRegistry); // collision monitoring + + int64_t const now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); ccdb->setCreatedNotAfter(now); + + if (applyMlMode == FillMlFromNewBDT) { + 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(); + } } /// Function to retrieve the nominal magnetic field in kG (0.1T) and convert it directly to T - void getMagneticFieldTesla(aod::BCsWithTimestamps::iterator bc) + void getMagneticFieldTesla(const aod::BCsWithTimestamps::iterator& bc) { initCCDB(bc, runNumber, ccdb, !isRun3 ? ccdbPathGrp : ccdbPathGrpMag, lut, !isRun3); } @@ -196,13 +283,24 @@ struct HfFemtoDreamProducer { particle.dcaXY(), particle.dcaZ(), particle.tpcSignal(), + -999., particle.tpcNSigmaPi(), particle.tpcNSigmaKa(), particle.tpcNSigmaPr(), + particle.tpcNSigmaDe(), + -999., + -999., + -999., particle.tofNSigmaPi(), particle.tofNSigmaKa(), particle.tofNSigmaPr(), - -999., -999., -999., -999., -999., -999., -999., -999., -999., -999.); + 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 @@ -214,11 +312,12 @@ struct HfFemtoDreamProducer { auto pdgCode = particleMc.pdgCode(); int particleOrigin = 99; int pdgCodeMother = -1; + constexpr int GenFromTransport = -1; // -1 if a particle produced during transport // 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 (abs(pdgCode) == abs(trkPDGCode.value)) { + 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()) { @@ -230,7 +329,7 @@ struct HfFemtoDreamProducer { // 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()) { + } else if (particleMc.getProcess() == TMCProcess::kPDecay && particleMc.getGenStatusCode() == GenFromTransport && !motherparticlesMc.empty()) { // get direct mother auto motherparticleMc = motherparticlesMc.front(); pdgCodeMother = motherparticleMc.pdgCode(); @@ -238,7 +337,7 @@ struct HfFemtoDreamProducer { // 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) { + } else if (particleMc.getProcess() == TMCProcess::kPHInhelastic && particleMc.getGenStatusCode() == GenFromTransport) { particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kMaterial; // cross check to see if we missed a case } else { @@ -275,33 +374,32 @@ struct HfFemtoDreamProducer { } } - template - bool fillTracksForCharmHadron(CollisionType const& col, TrackType const& tracks, ProngType const& prong0, ProngType const& prong1, ProngType const& prong2, int candSize) + 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 const 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) { + 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 ((candSize == 1) && (track.globalIndex() == prong0.globalIndex() || track.globalIndex() == prong1.globalIndex() || track.globalIndex() == prong2.globalIndex())) - 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))); - + auto cutContainer = trackCuts.getCutContainer(track, track.pt(), track.eta(), sqrtf(powf(track.dcaXY(), 2.f) + powf(track.dcaZ(), 2.f))); + auto bc = col.template bc_as(); + int64_t timeStamp = bc.timestamp(); // track global index outputPartsIndex(track.globalIndex()); + outputPartsTime(timeStamp); // now the table is filled - outputParts(outputCollision.lastIndex() + 1, + outputParts(outputCollision.lastIndex(), track.pt(), track.eta(), track.phi(), @@ -315,22 +413,19 @@ struct HfFemtoDreamProducer { fillDebugParticle(track); } - if constexpr (isMc) { + if constexpr (IsMc) { fillMcParticle(col, track, o2::aod::femtodreamparticle::ParticleType::kTrack); } } return fIsTrackFilled; } - template + template void fillCharmHadronTable(CollisionType const& col, TrackType const& tracks, CandType const& candidates) { const auto vtxZ = col.posZ(); const auto sizeCand = candidates.size(); - if (sizeCand == 0) - return; - - const auto spher = colCuts.computeSphericity(col, tracks); + const auto spher = 2.; // dummy value for the moment float mult = 0; int multNtr = 0; if (isRun3) { @@ -345,113 +440,272 @@ struct HfFemtoDreamProducer { multNtr = col.multTracklets(); } - colCuts.fillQA(col, mult); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(col, mult, ccdb, qaRegistry); + + qaRegistry.fill(HIST("hEventQA"), 1 + Event::All); - // 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)) { + /// 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::RejEveSel); return; } - if (colCuts.isEmptyCollision(col, tracks, trackCuts)) { + if (isNoSelectedTracks(col, tracks, trackCuts) && sizeCand <= 0) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::RejNoTracksAndCharm); return; } + + outputCollision(vtxZ, mult, multNtr, spher, magField); + if constexpr (IsMc) { + fillMcCollision(col); + } + // Filling candidate properties rowCandCharmHad.reserve(sizeCand); bool isTrackFilled = false; + bool isSelectedMlLcToPKPi = true; + bool isSelectedMlLcToPiKP = true; + bool isSelectedMlDplusToPiKPi = true; 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 - } - } + outputMlDplus = {-1.0f, -1.0f, -1.0f}; + outputMlPKPi = {-1.0f, -1.0f, -1.0f}; + outputMlPiKP = {-1.0f, -1.0f, -1.0f}; 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){ - // Fill tracks if it is not filled for Lc Candidate in an event - if (!isTrackFilled) { - isTrackFilled = fillTracksForCharmHadron(col, tracks, trackPos1, trackNeg, trackPos2, sizeCand); - - // If track filling was successful, fill the collision table - if (isTrackFilled) { - outputCollision(vtxZ, mult, multNtr, spher, magField); - if constexpr (isMc) { - fillMcCollision(col); - } - } + auto bc = col.template bc_as(); + int64_t timeStamp = bc.timestamp(); + auto fillTable = [&](int candFlag, + int functionSelection, + float bdtScoreBkg, + float bdtScorePrompt, + float bdtScoreFd) { + if (functionSelection >= 1) { + rowCandCharmHad( + outputCollision.lastIndex(), + timeStamp, + 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()); + } + } + }; + + if constexpr (Channel == DecayChannel::DplusToPiKPi) { + if constexpr (UseCharmMl) { + /// fill with ML information + /// BDT index 0: bkg score; BDT index 1: prompt score; BDT index 2: non-prompt score + if (applyMlMode == FillMlFromSelector) { + if (candidate.mlProbDplusToPiKPi().size() > 0) { + outputMlDplus.at(0) = candidate.mlProbDplusToPiKPi()[0]; /// bkg score + outputMlDplus.at(1) = candidate.mlProbDplusToPiKPi()[1]; /// prompt score + outputMlDplus.at(2) = candidate.mlProbDplusToPiKPi()[2]; /// non-prompt score } - - // fill collision table if track table is filled, i.e., there is at least one Lc-p pair - if (isTrackFilled) { - // Row for candidate charm hadron - 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()); - } + } else if (applyMlMode == FillMlFromNewBDT) { + isSelectedMlDplusToPiKPi = false; + if (candidate.mlProbDplusToPiKPi().size() > 0) { + std::vector inputFeaturesDplusToPiKPi = hfMlResponseDplus.getInputFeatures(candidate); + isSelectedMlDplusToPiKPi = hfMlResponseDplus.isSelectedMl(inputFeaturesDplusToPiKPi, candidate.pt(), outputMlDplus); + } + if (!isSelectedMlDplusToPiKPi) { + continue; + } + } else { + LOGF(fatal, "Please check your Ml configuration!!"); + } + } + fillTable(2, candidate.isSelDplusToPiKPi(), outputMlDplus.at(0), outputMlDplus.at(1), outputMlDplus.at(2)); + + } else if constexpr (Channel == DecayChannel::LcToPKPi) { + if constexpr (UseCharmMl) { + /// fill with ML information + /// BDT index 0: bkg score; BDT index 1: prompt score; BDT index 2: non-prompt score + if (applyMlMode == FillMlFromSelector) { + 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 + } + } else if (applyMlMode == FillMlFromNewBDT) { + isSelectedMlLcToPKPi = false; + isSelectedMlLcToPiKP = false; + if (candidate.mlProbLcToPKPi().size() > 0) { + std::vector inputFeaturesLcToPKPi = hfMlResponse.getInputFeatures(candidate, true); + isSelectedMlLcToPKPi = hfMlResponse.isSelectedMl(inputFeaturesLcToPKPi, candidate.pt(), outputMlPKPi); + } + if (candidate.mlProbLcToPiKP().size() > 0) { + std::vector inputFeaturesLcToPiKP = hfMlResponse.getInputFeatures(candidate, false); + isSelectedMlLcToPiKP = hfMlResponse.isSelectedMl(inputFeaturesLcToPiKP, candidate.pt(), outputMlPKPi); } - } }; + if (!isSelectedMlLcToPKPi && !isSelectedMlLcToPiKP) { + continue; + } + } else { + LOGF(fatal, "Please check your Ml configuration!!"); + } + } + 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)); + } + } + isTrackFilled = fillTracksForCharmHadron(col, tracks); + + aod::femtodreamcollision::BitMaskType bitTrack = 0; + if (isTrackFilled) { + bitTrack |= 1 << 0; + qaRegistry.fill(HIST("hEventQA"), 1 + Event::TrackSelected); + } - 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)); + aod::femtodreamcollision::BitMaskType bitCand = 0; + if (sizeCand > 0) { + bitCand |= 1 << 0; + qaRegistry.fill(HIST("hEventQA"), 1 + Event::CharmSelected); } + + if (isTrackFilled && (sizeCand > 0)) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::PairSelected); + } + + rowMasks(bitTrack, + bitCand, + 0); } - template + // 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()); + if constexpr (Channel == DecayChannel::DplusToPiKPi) { + for (const auto& particle : particles) { + if (std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { + rowCandCharmHadGen( + particle.mcCollisionId(), + particle.flagMcMatchGen(), + particle.originMcGen()); + } + } + } else if constexpr (Channel == DecayChannel::LcToPKPi) { + for (const auto& particle : particles) { + if (std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + rowCandCharmHadGen( + particle.mcCollisionId(), + particle.flagMcMatchGen(), + particle.originMcGen()); + } } } } - void processDataCharmHad(FemtoFullCollision const& col, + /// DplusToPiKPi + void processDataDplusToPiKPi(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, processDataDplusToPiKPi, + "Provide experimental data for DplusToPiKPi femto", false); + + void processDataDplusToPiKPiWithML(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, processDataDplusToPiKPiWithML, + "Provide experimental data for DplusToPiKPi with ml", false); + + void processMcDplusToPiKPi(FemtoFullCollisionMc const& col, + aod::BCsWithTimestamps const&, + FemtoHFMcTracks const& tracks, + aod::McParticles const&, + CandidateDplusMc const& candidates) + { + // get magnetic field for run + getMagneticFieldTesla(col.bc_as()); + + fillCharmHadronTable(col, tracks, candidates); + } + PROCESS_SWITCH(HfFemtoDreamProducer, processMcDplusToPiKPi, "Provide Mc for DplusToPiKPi", false); + + void processMcDplusToPiKPiWithML(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, processMcDplusToPiKPiWithML, "Provide Mc for DplusToPiKPi with ml", false); + + void processMcDplusToPiKPiGen(GeneratedMc const& particles) + { + + fillCharmHadMcGen(particles); + } + PROCESS_SWITCH(HfFemtoDreamProducer, processMcDplusToPiKPiGen, "Provide Mc Generated DplusToPiKPi", false); + + /// LcToPKPi + void processDataLcToPKPi(FemtoFullCollision const& col, aod::BCsWithTimestamps const&, FemtoHFTracks const& tracks, soa::Filtered const& candidates) @@ -459,12 +713,12 @@ struct HfFemtoDreamProducer { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); - fillCharmHadronTable(col, tracks, candidates); + fillCharmHadronTable(col, tracks, candidates); } - PROCESS_SWITCH(HfFemtoDreamProducer, processDataCharmHad, - "Provide experimental data for charm hadron femto", false); + PROCESS_SWITCH(HfFemtoDreamProducer, processDataLcToPKPi, + "Provide experimental data for Lc(PKPi)-proton femto", false); - void processDataCharmHadWithML(FemtoFullCollision const& col, + void processDataLcToPKPiWithML(FemtoFullCollision const& col, aod::BCsWithTimestamps const&, FemtoHFTracks const& tracks, soa::Filtered()); - fillCharmHadronTable(col, tracks, candidates); + fillCharmHadronTable(col, tracks, candidates); } - PROCESS_SWITCH(HfFemtoDreamProducer, processDataCharmHadWithML, - "Provide experimental data for charm hadron femto with ml", false); + PROCESS_SWITCH(HfFemtoDreamProducer, processDataLcToPKPiWithML, + "Provide experimental data for Lc(PKPi)-proton femto with ml", false); - void processMcCharmHad(FemtoFullCollisionMc const& col, + void processMcLcToPKPi(FemtoFullCollisionMc const& col, aod::BCsWithTimestamps const&, FemtoHFMcTracks const& tracks, aod::McParticles const&, @@ -488,11 +742,11 @@ struct HfFemtoDreamProducer { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); - fillCharmHadronTable(col, tracks, candidates); + fillCharmHadronTable(col, tracks, candidates); } - PROCESS_SWITCH(HfFemtoDreamProducer, processMcCharmHad, "Provide Mc for charm hadron", false); + PROCESS_SWITCH(HfFemtoDreamProducer, processMcLcToPKPi, "Provide Mc for lctopkpi", false); - void processMcCharmHadWithML(FemtoFullCollisionMc const& col, + void processMcLcToPKPiWithML(FemtoFullCollisionMc const& col, aod::BCsWithTimestamps const&, FemtoHFMcTracks const& tracks, aod::McParticles const&, @@ -502,16 +756,16 @@ struct HfFemtoDreamProducer { // get magnetic field for run getMagneticFieldTesla(col.bc_as()); - fillCharmHadronTable(col, tracks, candidates); + fillCharmHadronTable(col, tracks, candidates); } - PROCESS_SWITCH(HfFemtoDreamProducer, processMcCharmHadWithML, "Provide Mc for charm hadron with ml", false); + PROCESS_SWITCH(HfFemtoDreamProducer, processMcLcToPKPiWithML, "Provide Mc for lctopkpi with ml", false); - void processMcCharmHadGen(GeneratedMc const& particles) + void processMcLcToPKPiGen(GeneratedMc const& particles) { - fillCharmHadMcGen(particles); + fillCharmHadMcGen(particles); } - PROCESS_SWITCH(HfFemtoDreamProducer, processMcCharmHadGen, "Provide Mc Generated charm hadron", false); + PROCESS_SWITCH(HfFemtoDreamProducer, processMcLcToPKPiGen, "Provide Mc Generated lctopkpi", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFC/Tasks/CMakeLists.txt b/PWGHF/HFC/Tasks/CMakeLists.txt index 2580d9ff75e..ec2e1779ebf 100644 --- a/PWGHF/HFC/Tasks/CMakeLists.txt +++ b/PWGHF/HFC/Tasks/CMakeLists.txt @@ -44,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 index 32cd888d109..40f907f5a29 100644 --- a/PWGHF/HFC/Tasks/taskCharmHadronsFemtoDream.cxx +++ b/PWGHF/HFC/Tasks/taskCharmHadronsFemtoDream.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2022 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. // @@ -9,27 +9,44 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file taskCharmHadronsFemtoDream.cxx.cxx +/// \file taskCharmHadronsFemtoDream.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 - -#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" +/// \author Biao Zhang, Heidelberg University, biao.zhang@cern.ch +/// \author Yunfan Liu, Central China Normal University, yunfan.l@cern.ch #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/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamMath.h" +#include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" +#include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" #include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" +#include "PWGHF/Core/DecayChannels.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -37,6 +54,13 @@ using namespace o2::soa; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::analysis::femtoDream; +using namespace o2::hf_decay; +using namespace o2::hf_decay::hf_cand_3prong; + +inline o2::framework::expressions::Node coshEta(o2::framework::expressions::Node&& eta) +{ + return (nexp(std::move(eta)) + nexp(0.0f - std::move(eta))) * 0.5f; +} struct HfTaskCharmHadronsFemtoDream { @@ -51,24 +75,21 @@ struct HfTaskCharmHadronsFemtoDream { 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", {300, 2.15, 2.45}, "InvMass binning"}; - 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 binpT{"binpT", {20, 0.5, 4.05}, "pT binning"}; - ConfigurableAxis binpTTrack{"binpTTrack", {50, 0.5, 10.05}, "pT binning of the pT vs. TempFitVar plot (Track)"}; - ConfigurableAxis binkT{"binkT", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis binkstar{"binkstar", {1500, 0., 6.}, "binning kstar"}; + constexpr static int OriginRecPrompt = 1; + constexpr static int OriginRecFD = 2; + constexpr static int CutBitChargePositive = 2; + + Produces rowFemtoResultPairs; + Produces rowFemtoResultCharm; + Produces rowFemtoResultTrk; + Produces rowFemtoResultColl; + + 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 charmHadCandSel{"charmHadCandSel", 1, "candidate selection for charm hadron"}; + Configurable charmHadMcSel{"charmHadMcSel", DecayChannelMain::LcToPKPi, "charm hadron selection for mc, DplusToPiKPi = 1, LcToPKPi = 17"}; 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)"}; @@ -89,15 +110,13 @@ struct HfTaskCharmHadronsFemtoDream { 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"}; + Configurable fillTableWithCharm{"fillTableWithCharm", true, "Write charm/tracks/collision table only if >=1 charm hadron in this collision"}; // Mixing configurables - ConfigurableAxis mixingBinMult{"mixingBinMult", {VARIABLE_WIDTH, 0.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 mixingPolicy{"mixingBinPolicy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; - + struct : ConfigurableGroup { + Configurable mixingBinPolicy{"mixingBinPolicy", 0, "Binning policy for mixing - 0: multiplicity, 1: multipliciy percentile, 2: both"}; + Configurable mixingDepth{"mixingDepth", 5, "Number of events for mixing"}; + } mixSetting; /// Event selection struct : ConfigurableGroup { std::string prefix = "eventSel"; @@ -108,7 +127,7 @@ struct HfTaskCharmHadronsFemtoDream { } eventSel; /// Particle 1 (track) - Configurable cutBitTrack1{"cutBitTrack1", 5542474, "Particle 1 (Track) - Selection bit from cutCulator"}; + Configurable cutBitTrack1{"cutBitTrack1", 8188, "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)"}; @@ -118,23 +137,7 @@ struct HfTaskCharmHadronsFemtoDream { 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 pairCloseRejection; - - 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 >= charmHadCandSel.value; - Filter hfMcSelFilter = nabs(aod::fdhf::flagMc) == 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); + SliceCache cache; using FilteredCharmCands = soa::Filtered; using FilteredCharmCand = FilteredCharmCands::iterator; @@ -142,53 +145,108 @@ struct HfTaskCharmHadronsFemtoDream { using FilteredCharmMcCands = soa::Filtered>; using FilteredCharmMcCand = FilteredCharmMcCands::iterator; - using FilteredColisions = FDCollisions; + using FilteredColisions = soa::Filtered>; using FilteredColision = FilteredColisions::iterator; - using FilteredMcColisions = soa::Filtered>; + using FilteredMcColisions = soa::Filtered>; using FilteredMcColision = FilteredMcColisions::iterator; - using FilteredFDMcParts = soa::Filtered>; + using FilteredFDMcParts = soa::Filtered>; using FilteredFDMcPart = FilteredFDMcParts::iterator; - using FilteredFDParticles = soa::Filtered>; + using FilteredFDParticles = soa::Filtered>; using FilteredFDParticle = FilteredFDParticles::iterator; - /// Histogramming for particle 1 - FemtoDreamParticleHisto trackHistoPartOne; - /// Histogramming for Event - FemtoDreamEventHisto eventHisto; - /// Histogram output - HistogramRegistry registry{"CorrelationsAndQA", {}, OutputObjHandlingPolicy::AnalysisObject}; + 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 >= charmHadCandSel; + Filter hfMcSelFilter = (nabs(aod::fdhf::flagMc) == charmHadMcSel); + 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); - /// Partition for particle 1 + Preslice perCol = aod::femtodreamparticle::fdCollisionId; + Preslice perHfByCol = aod::femtodreamparticle::fdCollisionId; - Partition partitionTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)); + /// Partition for particle 1 + Partition partitionTrk1 = (aod::femtodreamparticle::partType == uint8_t(aod::femtodreamparticle::ParticleType::kTrack)) && (ncheckbit(aod::femtodreamparticle::cut, cutBitTrack1)) && ifnode(aod::femtodreamparticle::pt * coshEta(aod::femtodreamparticle::eta) <= 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)); + ifnode(aod::femtodreamparticle::pt * coshEta(aod::femtodreamparticle::eta) <= 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; + Partition partitionMcCharmHadron = aod::fdhf::originMcRec == OriginRecPrompt || aod::fdhf::originMcRec == OriginRecFD; + + /// Axis configurables + ConfigurableAxis dummy{"dummy", {1, 0, 1}, "dummy axis"}; + /// 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, o2::constants::math::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"}; + // Mixing axis 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"}; + + 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; + + 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"}; 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); - trackHistoPartOne.init(®istry, binmultTempFit, dummy, binpTTrack, dummy, dummy, binTempFitVarTrack, dummy, dummy, dummy, dummy, dummy, isMc, pdgCodeTrack1); + 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, binpT, binkT, binmT, mixingBinMult, mixingBinMultPercentile, + binkstar, binpTTrack, binkT, binmT, mixingBinMult, mixingBinMultPercentile, bin4Dkstar, bin4DmT, bin4DMult, bin4DmultPercentile, isMc, use4D, extendedPlots, highkstarCut, @@ -196,59 +254,112 @@ struct HfTaskCharmHadronsFemtoDream { sameEventCont.setPDGCodes(pdgCodeTrack1, charmHadPDGCode); mixedEventCont.init(®istry, - binkstar, binpT, binkT, binmT, mixingBinMult, mixingBinMultPercentile, + 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) { - pairCloseRejection.init(®istry, ®istry, cprDeltaPhiMax.value, cprDeltaEtaMax.value, cprPlotPerRadii.value); + pairCloseRejectionSE.init(®istry, ®istry, cprDeltaPhiMax.value, cprDeltaEtaMax.value, cprPlotPerRadii.value, 1); + pairCloseRejectionME.init(®istry, ®istry, cprDeltaPhiMax.value, cprDeltaEtaMax.value, cprPlotPerRadii.value, 2); } } - /// 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) + template + void fillCollision(CollisionType const& col) { - processType = 1; // for same event - /// Histogramming same event - for (auto const& part : sliceTrk1) { + registryMixQa.fill(HIST("MixingQA/hSECollisionBins"), colBinningMult.getBin({col.posZ(), col.multNtr()})); + registryMixQa.fill(HIST("MixingQA/hSECollisionPool"), col.posZ(), col.multNtr()); + } - trackHistoPartOne.fillQA(part, aod::femtodreamparticle::kPt, col.multNtr(), col.multV0M()); + /// Compute the charm hadron candidates mass with the daughter masses + /// assumes the candidate is either a D+ or Λc+ + template + float getCharmHadronMass(const Candidate& cand) + { + float invMass = 0.0f; + if (charmHadPDGCode == o2::constants::physics::Pdg::kLambdaCPlus) { + if (cand.candidateSelFlag() == 1) { + invMass = cand.m(std::array{o2::constants::physics::MassProton, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + return invMass; + } + invMass = cand.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassProton}); + return invMass; } + // D+ → π K π (PDG: 411) + if (charmHadPDGCode == o2::constants::physics::Pdg::kDPlus) { + invMass = cand.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + return invMass; + } + // Add more channels as needed + return invMass; + } - for (auto const& [p1, p2] : combinations(CombinationsFullIndexPolicy(sliceTrk1, sliceCharmHad))) { - // proton track charge - float chargeTrack = 0.; - if ((p1.cut() & 1) == 1) { - chargeTrack = PositiveCharge; - } else { - chargeTrack = NegativeCharge; - } + template + float getCharmHadronTrackMass(const Candidate& cand, + const Track& trk, + double trackMassHyp = o2::constants::physics::MassProton) + { - int pairSign = 0; - if (chargeTrack == p2.charge()) { - pairSign = LikeSignPair; + auto pVecProng0 = RecoDecayPtEtaPhi::pVector(cand.prong0Pt(), cand.prong0Eta(), cand.prong0Phi()); + auto pVecProng1 = RecoDecayPtEtaPhi::pVector(cand.prong1Pt(), cand.prong1Eta(), cand.prong1Phi()); + auto pVecProng2 = RecoDecayPtEtaPhi::pVector(cand.prong2Pt(), cand.prong2Eta(), cand.prong2Phi()); + auto pVecTrack = RecoDecayPtEtaPhi::pVector(trk.pt(), trk.eta(), trk.phi()); + const auto pVecCharmTrk = std::array{pVecProng0, pVecProng1, pVecProng2, pVecTrack}; + + std::array massCharmTrk{}; + + if (charmHadPDGCode == o2::constants::physics::Pdg::kLambdaCPlus) { + // Λc⁺ → p K π + if (cand.candidateSelFlag() == 1) { + massCharmTrk = { + o2::constants::physics::MassProton, + o2::constants::physics::MassKPlus, + o2::constants::physics::MassPiPlus, + trackMassHyp}; } else { - pairSign = UnLikeSignPair; + // prong0=π, prong1=K, prong2=p + massCharmTrk = { + o2::constants::physics::MassPiPlus, + o2::constants::physics::MassKPlus, + o2::constants::physics::MassProton, + trackMassHyp}; } + } else if (charmHadPDGCode == o2::constants::physics::Pdg::kDPlus) { + // D⁺ → π K π + massCharmTrk = { + o2::constants::physics::MassPiPlus, + o2::constants::physics::MassKPlus, + o2::constants::physics::MassPiPlus, + trackMassHyp}; + } else { + return -1.f; + } + return static_cast(RecoDecay::m(pVecCharmTrk, massCharmTrk)); + } - float kstar = FemtoDreamMath::getkstar(p1, massOne, p2, massTwo); - if (kstar > highkstarCut) { + /// 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 (chargeTrack == 1) { - // partSign = 1; - // } else { - // partSign = 1 << 1; - // } - if (useCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, col.magField())) { + if (pairCloseRejectionSE.isClosePair(p1, p2, parts, col.magField())) { continue; } } @@ -257,12 +368,11 @@ struct HfTaskCharmHadronsFemtoDream { 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}); + float kstar = FemtoDreamMath::getkstar(p1, massOne, p2, massTwo); + if (kstar > highkstarCut) { + continue; } + float invMass = getCharmHadronMass(p2); if (invMass < charmHadMinInvMass || invMass > charmHadMaxInvMass) { continue; @@ -272,13 +382,33 @@ struct HfTaskCharmHadronsFemtoDream { continue; } + float deltaInvMassPair = getCharmHadronTrackMass(p2, p1, o2::constants::physics::MassProton) - invMass; + + // proton track charge + float chargeTrack = 0.; + if ((p1.cut() & CutBitChargePositive) == CutBitChargePositive) { + chargeTrack = PositiveCharge; + } else { + chargeTrack = NegativeCharge; + } + int pairSign = 0; + if (chargeTrack == p2.charge()) { + pairSign = LikeSignPair; + } else { + pairSign = UnLikeSignPair; + } + + /// 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) { + if constexpr (IsMc) { charmHadMc = p2.flagMc(); originType = p2.originMcRec(); } - fillFemtoResult( + + rowFemtoResultPairs( invMass, p2.pt(), p1.pt(), @@ -292,32 +422,72 @@ struct HfTaskCharmHadronsFemtoDream { col.multV0M(), p2.charge(), pairSign, + deltaInvMassPair, processType, charmHadMc, originType); - sameEventCont.setPair(p1, p2, col.multNtr(), col.multV0M(), use4D, extendedPlots, smearingByOrigin); + sameEventCont.setPair(p1, p2, col.multNtr(), col.multV0M(), use4D, extendedPlots, smearingByOrigin); } } - template + template void doMixedEvent(CollisionType const& cols, PartType const& parts, PartitionType1& part1, PartitionType2& part2, BinningType policy) { - processType = 1 << 1; // for mixed event + processType = 2; // for mixed event + // Mixed events that contain the pair of interest + Partition partitionMaskedCol1 = (aod::femtodreamcollision::bitmaskTrackOne & bitMask) == bitMask; + partitionMaskedCol1.bindTable(cols); - for (auto const& [collision1, collision2] : soa::selfCombinations(policy, mixingDepth.value, -1, cols, cols)) { + Partition partitionMaskedCol2 = (aod::femtodreamcollision::bitmaskTrackTwo & bitMask) == bitMask; + partitionMaskedCol2.bindTable(cols); + + for (auto const& [collision1, collision2] : combinations(soa::CombinationsBlockFullIndexPolicy(policy, mixSetting.mixingDepth, -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))) { + for (const 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 kstar = FemtoDreamMath::getkstar(p1, massOne, p2, massTwo); + if (kstar > highkstarCut) { + continue; + } + + float invMass = getCharmHadronMass(p2); + + if (invMass < charmHadMinInvMass || invMass > charmHadMaxInvMass) { + continue; + } + + if (p2.pt() < charmHadMinPt || p2.pt() > charmHadMaxPt) { + continue; + } + + float deltaInvMassPair = getCharmHadronTrackMass(p2, p1, o2::constants::physics::MassProton) - invMass; + + // proton track charge float chargeTrack = 0.; - if ((p1.cut() & 1) == 1) { + if ((p1.cut() & CutBitChargePositive) == CutBitChargePositive) { chargeTrack = PositiveCharge; } else { chargeTrack = NegativeCharge; } - int pairSign = 0; if (chargeTrack == p2.charge()) { pairSign = LikeSignPair; @@ -325,25 +495,14 @@ struct HfTaskCharmHadronsFemtoDream { 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}); - } - int charmHadMc = 0; int originType = 0; - if constexpr (isMc) { + if constexpr (IsMc) { charmHadMc = p2.flagMc(); originType = p2.originMcRec(); } - fillFemtoResult( + + rowFemtoResultPairs( invMass, p2.pt(), p1.pt(), @@ -357,20 +516,12 @@ struct HfTaskCharmHadronsFemtoDream { collision1.multV0M(), p2.charge(), pairSign, + deltaInvMassPair, processType, charmHadMc, originType); - if (useCPR.value) { - if (pairCloseRejection.isClosePair(p1, p2, parts, collision1.magField())) { - continue; - } - } - if (!pairCleaner.isCleanPair(p1, p2, parts)) { - continue; - } - // 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); + mixedEventCont.setPair(p1, p2, collision1.multNtr(), collision1.multV0M(), use4D, extendedPlots, smearingByOrigin); } } } @@ -382,6 +533,65 @@ struct HfTaskCharmHadronsFemtoDream { eventHisto.fillQA(col); auto sliceTrk1 = partitionTrk1->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); auto sliceCharmHad = partitionCharmHadron->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + if (fillTableWithCharm.value && sliceCharmHad.size() == 0) { + return; + } + + int64_t timeStamp = -999; + + for (auto const& part : sliceCharmHad) { + float invMass = getCharmHadronMass(part); + registryCharmHadronQa.fill(HIST("CharmHadronQA/hPtVsMass"), part.pt(), invMass); + timeStamp = part.timeStamp(); + rowFemtoResultCharm( + col.globalIndex(), + timeStamp, + invMass, + part.pt(), + part.eta(), + part.phi(), + part.prong0Id(), + part.prong1Id(), + part.prong2Id(), + part.charge(), + part.bdtBkg(), + part.bdtPrompt(), + part.bdtFD()); + } + + for (auto const& part : sliceTrk1) { + allTrackHisto.fillQA(part, + static_cast(confTempFitVarMomentum.value), + col.multNtr(), col.multV0M()); + + float chargeTrack = ((part.cut() & CutBitChargePositive) == CutBitChargePositive) + ? PositiveCharge + : NegativeCharge; + timeStamp = part.timeStamp(); + rowFemtoResultTrk( + col.globalIndex(), + timeStamp, + part.pt(), + part.eta(), + part.phi(), + part.trackId(), + chargeTrack, + part.tpcNClsFound(), + part.tpcNClsFindable(), + part.tpcNClsCrossedRows(), + part.tpcNSigmaPr(), + part.tofNSigmaPr()); + } + if (sliceCharmHad.size() > 0 || sliceTrk1.size() > 0) { + rowFemtoResultColl( + col.globalIndex(), + timeStamp, + col.posZ(), + col.multNtr()); + } else { + return; + } + doSameEvent(sliceTrk1, sliceCharmHad, parts, col); } PROCESS_SWITCH(HfTaskCharmHadronsFemtoDream, processSameEvent, "Enable processing same event", false); @@ -390,7 +600,7 @@ struct HfTaskCharmHadronsFemtoDream { FilteredFDParticles const& parts, FilteredCharmCands const&) { - switch (mixingPolicy.value) { + switch (mixSetting.mixingBinPolicy) { case femtodreamcollision::kMult: doMixedEvent(cols, parts, partitionTrk1, partitionCharmHadron, colBinningMult); break; @@ -413,14 +623,30 @@ struct HfTaskCharmHadronsFemtoDream { 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 (sliceMcCharmHad.size() > 0) { + for (auto const& part : sliceMcCharmHad) { + registryCharmHadronQa.fill(HIST("CharmHadronQA/hPtVsMass"), part.pt(), getCharmHadronMass(part)); + } + } 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); @@ -432,9 +658,10 @@ struct HfTaskCharmHadronsFemtoDream { void processMixedEventMc(FilteredMcColisions const& cols, FilteredFDMcParts const& parts, o2::aod::FDMCParticles const&, + o2::aod::FDExtMCParticles const&, FilteredCharmMcCands const&) { - switch (mixingPolicy.value) { + switch (mixSetting.mixingBinPolicy) { case femtodreamcollision::kMult: doMixedEvent(cols, parts, partitionMcTrk1, partitionMcCharmHadron, colBinningMult); break; diff --git a/PWGHF/HFC/Tasks/taskCorrelationD0Hadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationD0Hadrons.cxx index 9ac7c6ae3de..74c33e0868e 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationD0Hadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationD0Hadrons.cxx @@ -16,253 +16,354 @@ /// \author Samrangy Sadhu , INFN Bari /// \author Swapnesh Santosh Khade , IIT Indore -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.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" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include 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., ""}; -AxisSpec axisCorrelationState = {2, 0., 1., ""}; -ConfigurableAxis axisMass{"axisMass", {250, 1.65f, 2.15f}, ""}; +using namespace o2::analysis::hf_correlations; // definition of vectors for standard ptbin and invariant mass configurables const int nPtBinsCorrelations = 12; const double pTBinsCorrelations[nPtBinsCorrelations + 1] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 12., 16., 24., 99.}; -auto vecPtBinsCorrelations = std::vector{pTBinsCorrelations, pTBinsCorrelations + nPtBinsCorrelations + 1}; +const auto vecPtBinsCorrelations = std::vector{pTBinsCorrelations, pTBinsCorrelations + nPtBinsCorrelations + 1}; const double signalRegionLeftDefault[nPtBinsCorrelations] = {1.7948, 1.8198, 1.8198, 1.8148, 1.8148, 1.8048, 1.8048, 1.7948, 1.7948, 1.7898, 1.7848, 1.7598}; const double signalRegionRightDefault[nPtBinsCorrelations] = {1.9098, 1.8998, 1.9048, 1.9048, 1.9148, 1.9248, 1.9298, 1.9348, 1.9398, 1.9298, 1.9398, 1.9198}; const double sidebandLeftInnerDefault[nPtBinsCorrelations] = {1.7398, 1.7748, 1.7798, 1.7698, 1.7648, 1.7448, 1.7448, 1.7198, 1.7198, 1.7198, 1.7048, 1.6798}; const double sidebandLeftOuterDefault[nPtBinsCorrelations] = {1.6298, 1.6898, 1.6948, 1.6748, 1.6648, 1.6248, 1.6198, 1.5748, 1.5748, 1.5798, 1.5448, 1.5198}; const double sidebandRightInnerDefault[nPtBinsCorrelations] = {1.9648, 1.9448, 1.9448, 1.9548, 1.9648, 1.9848, 1.9948, 2.0098, 2.0148, 1.9998, 2.0248, 1.9998}; const double sidebandRightOuterDefault[nPtBinsCorrelations] = {2.0748, 2.0248, 2.0298, 2.0448, 2.0648, 2.1048, 2.1148, 2.1548, 2.1648, 2.1398, 2.1848, 2.1598}; -auto vecsignalRegionLeft = std::vector{signalRegionLeftDefault, signalRegionLeftDefault + nPtBinsCorrelations}; -auto vecsignalRegionRight = std::vector{signalRegionRightDefault, signalRegionRightDefault + nPtBinsCorrelations}; -auto vecSidebandLeftInner = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + nPtBinsCorrelations}; -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 auto vecsignalRegionLeft = std::vector{signalRegionLeftDefault, signalRegionLeftDefault + nPtBinsCorrelations}; +const auto vecsignalRegionRight = std::vector{signalRegionRightDefault, signalRegionRightDefault + nPtBinsCorrelations}; +const auto vecSidebandLeftInner = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + nPtBinsCorrelations}; +const auto vecSidebandLeftOuter = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + nPtBinsCorrelations}; +const auto vecSidebandRightInner = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + nPtBinsCorrelations}; +const auto vecSidebandRightOuter = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + nPtBinsCorrelations}; +const int nPtbinsPtEfficiencyD = o2::analysis::hf_cuts_d0_to_pi_k::NBinsPt; +const double efficiencyDmesonDefault[nPtbinsPtEfficiencyD] = {}; +const 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 useCentrality{"useCentrality", false, "Flag for centrality dependent analysis"}; 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 isTowardTransverseAway{"isTowardTransverseAway", false, "Divide into three regions: toward, transverse, and away"}; Configurable leadingParticlePtMin{"leadingParticlePtMin", 0., "Min for leading particle pt"}; - Configurable applyEfficiency{"efficiencyFlagD", 1, "Flag for applying efficiency weights"}; - - enum Region { - Default = 0, // 默认值 - Toward, - Away, - Transverse - }; - - 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}}}, - // Toward Transverse Away - {"hToward", "Toward invmass; ptD; correlationState;entries", {HistType::kTH3F, {{axisMass}, {axisPtD}, {axisCorrelationState}}}}, - {"hTransverse", "Transverse invmass; ptD; correlationState;entries", {HistType::kTH3F, {{axisMass}, {axisPtD}, {axisCorrelationState}}}}, - {"hAway", "Away invmass; ptD; correlationState;entries", {HistType::kTH3F, {{axisMass}, {axisPtD}, {axisCorrelationState}}}}}}; + + 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"}; + ConfigurableAxis binsCentFt0m{"binsCentFt0m", {100, 0., 100.}, "Centrality percentile (FT0M)"}; + + 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 const 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 const axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec const axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec const axisPosZ = {binsPosZ, "PosZ"}; + AxisSpec axisD0Prompt = {2, -0.5, 1.5, "Prompt D0"}; + AxisSpec axisCorrelationState = {2, 0., 2., "correlationState"}; + AxisSpec axisCentFT0M = {binsCentFt0m, "Centrality percentile (FT0M)"}; + + // 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}, {axisCentFT0M}}}); + 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}, {axisCentFT0M}}}); + 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}, {axisCentFT0M}}}); + 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}, {axisCentFT0M}}}); 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"); } - Region getRegion(double deltaPhi) - { - if (std::abs(deltaPhi) < o2::constants::math::PI / 3.) { - return Toward; - } else if (deltaPhi > 2. * o2::constants::math::PI / 3. && deltaPhi < 4. * o2::constants::math::PI / 3.) { - return Away; - } else { - return Transverse; - } - } /// 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 const ptD = candidate.ptD(); + float const bdtScorePromptD0 = candidate.mlScorePromptD0(); + float const bdtScoreBkgD0 = candidate.mlScoreBkgD0(); + float const bdtScorePromptD0bar = candidate.mlScorePromptD0bar(); + float const bdtScoreBkgD0bar = candidate.mlScoreBkgD0bar(); + int const 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) { + float cent = 0.; + if (useCentrality) { + cent = pairEntry.cent(); + } // define variables for widely used quantities - double deltaPhi = pairEntry.deltaPhi(); - double deltaEta = pairEntry.deltaEta(); - double ptD = pairEntry.ptD(); - double ptHadron = pairEntry.ptHadron(); - double massD = pairEntry.mD(); - double massDbar = pairEntry.mDbar(); - int signalStatus = pairEntry.signalStatus(); - int effBinD = o2::analysis::findBin(binsEfficiency, ptD); - int ptBinD = o2::analysis::findBin(binsCorrelations, ptD); - int poolBin = pairEntry.poolBin(); - bool isAutoCorrelated = pairEntry.isAutoCorrelated(); + double const deltaPhi = pairEntry.deltaPhi(); + double const deltaEta = pairEntry.deltaEta(); + double const ptD = pairEntry.ptD(); + double const ptHadron = pairEntry.ptHadron(); + double const massD = pairEntry.mD(); + double const massDbar = pairEntry.mDbar(); + int const signalStatus = pairEntry.signalStatus(); + int const effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + int const ptBinD = o2::analysis::findBin(binsCorrelations, ptD); + int const poolBin = pairEntry.poolBin(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + bool const isAutoCorrelated = pairEntry.isAutoCorrelated(); + float const bdtScorePromptD0 = pairEntry.mlScorePromptD0(); + float const bdtScoreBkgD0 = pairEntry.mlScoreBkgD0(); + float const bdtScorePromptD0bar = pairEntry.mlScorePromptD0bar(); + float const 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 ***** + if (applyEfficiency != 0) { + 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 @@ -274,58 +375,42 @@ struct HfTaskCorrelationD0Hadrons { if (ptHadron < leadingParticlePtMin) { continue; } - Region region = getRegion(deltaPhi); - if (signalStatus == ParticleTypeData::D0Only || signalStatus == ParticleTypeData::D0D0barBoth) { - 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; - } - } - if (signalStatus == ParticleTypeData::D0barOnly || signalStatus == ParticleTypeData::D0D0barBoth) { - 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; - } + Region const 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))) { + if ((massD > signalRegionLeft->at(ptBinD) && massD < signalRegionRight->at(ptBinD)) && (signalStatus == ParticleTypeData::D0Only)) { // in signal region - registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSignalRegion"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegion"), deltaPhi, efficiencyWeight); } - if ((massD > signalRegionLeft->at(ptBinD) && massD < signalRegionRight->at(ptBinD)) && ((signalStatus == ParticleTypeData::D0OnlySoftPi) || (signalStatus >= ParticleTypeData::D0D0barBothSoftPi))) { + if ((massD > signalRegionLeft->at(ptBinD) && massD < signalRegionRight->at(ptBinD)) && (signalStatus == ParticleTypeData::D0OnlySoftPi)) { // in signal region, fills for soft pion only in ME - registry.fill(HIST("hCorrel2DVsPtSignalRegionSoftPi"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegionSoftPi"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSignalRegionSoftPi"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegionSoftPi"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegionSoftPi"), deltaPhi, efficiencyWeight); } - if ((massDbar > signalRegionLeft->at(ptBinD) && massDbar < signalRegionRight->at(ptBinD)) && ((signalStatus == ParticleTypeData::D0barOnly) || (signalStatus == ParticleTypeData::D0D0barBoth))) { + if ((massDbar > signalRegionLeft->at(ptBinD) && massDbar < signalRegionRight->at(ptBinD)) && (signalStatus == ParticleTypeData::D0barOnly)) { // in signal region - registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSignalRegion"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegion"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegion"), deltaPhi, efficiencyWeight); @@ -333,7 +418,7 @@ struct HfTaskCorrelationD0Hadrons { if ((massDbar > signalRegionLeft->at(ptBinD) && massDbar < signalRegionRight->at(ptBinD)) && (signalStatus >= ParticleTypeData::D0barOnlySoftPi)) { // in signal region, fills for soft pion only in ME - registry.fill(HIST("hCorrel2DVsPtSignalRegionSoftPi"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegionSoftPi"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSignalRegionSoftPi"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSignalRegionSoftPi"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSignalRegionSoftPi"), deltaPhi, efficiencyWeight); @@ -341,9 +426,9 @@ struct HfTaskCorrelationD0Hadrons { if (((massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) || (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD))) && - ((signalStatus == ParticleTypeData::D0Only) || (signalStatus == ParticleTypeData::D0D0barBoth))) { + (signalStatus == ParticleTypeData::D0Only)) { // in sideband region - registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSidebands"), deltaPhi, efficiencyWeight); @@ -351,9 +436,9 @@ struct HfTaskCorrelationD0Hadrons { if (((massD > sidebandLeftOuter->at(ptBinD) && massD < sidebandLeftInner->at(ptBinD)) || (massD > sidebandRightInner->at(ptBinD) && massD < sidebandRightOuter->at(ptBinD))) && - ((signalStatus == ParticleTypeData::D0OnlySoftPi) || (signalStatus >= ParticleTypeData::D0D0barBothSoftPi))) { + (signalStatus == ParticleTypeData::D0OnlySoftPi)) { // in sideband region, fills for soft pion only in ME - registry.fill(HIST("hCorrel2DVsPtSidebandsSoftPi"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebandsSoftPi"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebandsSoftPi"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebandsSoftPi"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSidebandsSoftPi"), deltaPhi, efficiencyWeight); @@ -361,9 +446,9 @@ struct HfTaskCorrelationD0Hadrons { if (((massDbar > sidebandLeftOuter->at(ptBinD) && massDbar < sidebandLeftInner->at(ptBinD)) || (massDbar > sidebandRightInner->at(ptBinD) && massDbar < sidebandRightOuter->at(ptBinD))) && - ((signalStatus == ParticleTypeData::D0barOnly) || (signalStatus == ParticleTypeData::D0D0barBoth))) { + (signalStatus == ParticleTypeData::D0barOnly)) { // in sideband region - registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSidebands"), deltaPhi, efficiencyWeight); @@ -373,7 +458,7 @@ struct HfTaskCorrelationD0Hadrons { (massDbar > sidebandRightInner->at(ptBinD) && massDbar < sidebandRightOuter->at(ptBinD))) && (signalStatus >= ParticleTypeData::D0barOnlySoftPi)) { // in sideband region, fills for soft pion only in ME - registry.fill(HIST("hCorrel2DVsPtSidebandsSoftPi"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebandsSoftPi"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebandsSoftPi"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebandsSoftPi"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSidebandsSoftPi"), deltaPhi, efficiencyWeight); @@ -382,27 +467,84 @@ 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 const ptD = candidate.ptD(); + float const bdtScorePromptD0 = candidate.mlScorePromptD0(); + float const bdtScoreBkgD0 = candidate.mlScoreBkgD0(); + float const bdtScorePromptD0bar = candidate.mlScorePromptD0bar(); + float const bdtScoreBkgD0bar = candidate.mlScoreBkgD0bar(); + int const 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(); - double deltaEta = pairEntry.deltaEta(); - double ptD = pairEntry.ptD(); - double ptHadron = pairEntry.ptHadron(); - double massD = pairEntry.mD(); - double massDbar = pairEntry.mDbar(); - int signalStatus = pairEntry.signalStatus(); - int ptBinD = o2::analysis::findBin(binsCorrelations, ptD); - int poolBin = pairEntry.poolBin(); - + double const deltaPhi = pairEntry.deltaPhi(); + double const deltaEta = pairEntry.deltaEta(); + double const ptD = pairEntry.ptD(); + double const ptHadron = pairEntry.ptHadron(); + double const massD = pairEntry.mD(); + double const massDbar = pairEntry.mDbar(); + int const signalStatus = pairEntry.signalStatus(); + int const ptBinD = o2::analysis::findBin(binsCorrelations, ptD); + int const poolBin = pairEntry.poolBin(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + bool const isAutoCorrelated = pairEntry.isAutoCorrelated(); + float const bdtScorePromptD0 = pairEntry.mlScorePromptD0(); + float const bdtScoreBkgD0 = pairEntry.mlScoreBkgD0(); + float const bdtScorePromptD0bar = pairEntry.mlScorePromptD0bar(); + float const bdtScoreBkgD0bar = pairEntry.mlScoreBkgD0bar(); + bool const isPhysicalPrimary = pairEntry.isPhysicalPrimary(); + bool const isD0Prompt = pairEntry.isPrompt(); + int const 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))); + if (applyEfficiency != 0) { + 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 const 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()) { + if (pairEntry.signalStatus() != 0) { registry.fill(HIST("hCorrel2DVsPtRecSig"), deltaPhi, deltaEta, ptD, ptHadron, efficiencyWeight); } else { @@ -414,18 +556,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, static_cast(isD0Prompt), 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, static_cast(isD0Prompt), poolBin, efficiencyWeight); + if (isD0Prompt && statusPromptHadron == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptD0PromptHadronRecSig"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } else if (!isD0Prompt && statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + 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, static_cast(isD0Prompt), 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, static_cast(isD0Prompt), poolBin, efficiencyWeight); + if (isD0Prompt && statusPromptHadron == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptD0PromptHadronRecSig"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + } else if (!isD0Prompt && statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + 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)))) { @@ -580,30 +738,146 @@ 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 - double deltaPhi = pairEntry.deltaPhi(); - double deltaEta = pairEntry.deltaEta(); - double ptD = pairEntry.ptD(); - double ptHadron = pairEntry.ptHadron(); - int poolBin = pairEntry.poolBin(); + double const deltaPhi = pairEntry.deltaPhi(); + double const deltaEta = pairEntry.deltaEta(); + double const ptD = pairEntry.ptD(); + double const ptHadron = pairEntry.ptHadron(); + int const poolBin = pairEntry.poolBin(); + double const massD = pairEntry.mD(); + bool const isAutoCorrelated = pairEntry.isAutoCorrelated(); + int const statusPromptHadron = pairEntry.trackOrigin(); + bool const 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 const 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 == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtGenPromptD0PromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + } + } else { + registry.fill(HIST("hCorrel2DVsPtGenNonPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + if (statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + 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()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::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()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::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..652d49d29dc 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDDbar.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDDbar.cxx @@ -14,14 +14,26 @@ /// /// \author Fabio Colamaria , INFN Bari -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include using namespace o2; using namespace o2::framework; @@ -61,40 +73,40 @@ 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}; +const auto pTBinsCorrelationsV = std::vector{pTBinsCorrelations, pTBinsCorrelations + npTBinsCorrelations + 1}; const double signalRegionInnerDefault[npTBinsCorrelations] = {1.810, 1.810, 1.810, 1.810, 1.810, 1.810, 1.810, 1.810}; const double signalRegionOuterDefault[npTBinsCorrelations] = {1.922, 1.922, 1.922, 1.922, 1.922, 1.922, 1.922, 1.922}; const double sidebandLeftInnerDefault[npTBinsCorrelations] = {1.642, 1.642, 1.642, 1.642, 1.642, 1.642, 1.642, 1.642}; const double sidebandLeftOuterDefault[npTBinsCorrelations] = {1.754, 1.754, 1.754, 1.754, 1.754, 1.754, 1.754, 1.754}; const double sidebandRightInnerDefault[npTBinsCorrelations] = {1.978, 1.978, 1.978, 1.978, 1.978, 1.978, 1.978, 1.978}; const double sidebandRightOuterDefault[npTBinsCorrelations] = {2.090, 2.090, 2.090, 2.090, 2.090, 2.090, 2.090, 2.090}; -auto signalRegionInner_v = std::vector{signalRegionInnerDefault, signalRegionInnerDefault + npTBinsCorrelations}; -auto signalRegionOuter_v = std::vector{signalRegionOuterDefault, signalRegionOuterDefault + npTBinsCorrelations}; -auto sidebandLeftInner_v = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + npTBinsCorrelations}; -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 auto signalRegionInnerV = std::vector{signalRegionInnerDefault, signalRegionInnerDefault + npTBinsCorrelations}; +const auto signalRegionOuterV = std::vector{signalRegionOuterDefault, signalRegionOuterDefault + npTBinsCorrelations}; +const auto sidebandLeftInnerV = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + npTBinsCorrelations}; +const auto sidebandLeftOuterV = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + npTBinsCorrelations}; +const auto sidebandRightInnerV = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + npTBinsCorrelations}; +const auto sidebandRightOuterV = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + npTBinsCorrelations}; +const int npTBinsEfficiency = o2::analysis::hf_cuts_d0_to_pi_k::NBinsPt; const double efficiencyDmesonDefault[npTBinsEfficiency] = {}; -auto efficiencyDmeson_v = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsEfficiency}; +const auto efficiencyDmesonV = std::vector{efficiencyDmesonDefault, efficiencyDmesonDefault + npTBinsEfficiency}; struct HfTaskCorrelationDDbar { Configurable applyEfficiency{"applyEfficiency", 1, "Flag for applying efficiency weights"}; // 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> binsPtCorrelations{"binsPtCorrelations", std::vector{pTBinsCorrelations_v}, "pT bin limits for correlation plots"}; + Configurable> binsPtCorrelations{"binsPtCorrelations", std::vector{pTBinsCorrelationsV}, "pT bin limits for correlation plots"}; // pT bins for effiencies: same as above Configurable> binsPtEfficiency{"binsPtEfficiency", 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) - 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"}; - Configurable> sidebandLeftInner{"sidebandLeftInner", std::vector{sidebandLeftInner_v}, "Inner values of left sideband vs pT"}; - 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_v}, "Efficiency values for D meson specie under study"}; + Configurable> signalRegionInner{"signalRegionInner", std::vector{signalRegionInnerV}, "Inner values of signal region vs pT"}; + Configurable> signalRegionOuter{"signalRegionOuter", std::vector{signalRegionOuterV}, "Outer values of signal region vs pT"}; + Configurable> sidebandLeftInner{"sidebandLeftInner", std::vector{sidebandLeftInnerV}, "Inner values of left sideband vs pT"}; + Configurable> sidebandLeftOuter{"sidebandLeftOuter", std::vector{sidebandLeftOuterV}, "Outer values of left sideband vs pT"}; + Configurable> sidebandRightInner{"sidebandRightInner", std::vector{sidebandRightInnerV}, "Inner values of right sideband vs pT"}; + Configurable> sidebandRightOuter{"sidebandRightOuter", std::vector{sidebandRightOuterV}, "Outer values of right sideband vs pT"}; + Configurable> efficiencyD{"efficiencyD", std::vector{efficiencyDmesonV}, "Efficiency values for D meson specie under study"}; HistogramRegistry registry{ "registry", @@ -159,7 +171,7 @@ struct HfTaskCorrelationDDbar { void init(InitContext&) { // redefinition of pT axes for THnSparse holding correlation entries - int nBinspTaxis = binsPtCorrelations->size() - 1; + int const nBinspTaxis = binsPtCorrelations->size() - 1; const double* valuespTaxis = binsPtCorrelations->data(); for (int i = 2; i <= 3; i++) { @@ -233,33 +245,33 @@ struct HfTaskCorrelationDDbar { void processData(aod::DDbarPairFull 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 ptDbar = pairEntry.ptDbar(); - double massD = pairEntry.mD(); - double massDbar = pairEntry.mDbar(); + // define variables for widely used quantities + double const deltaPhi = pairEntry.deltaPhi(); + double const deltaEta = pairEntry.deltaEta(); + double const ptD = pairEntry.ptD(); + double const ptDbar = pairEntry.ptDbar(); + double const massD = pairEntry.mD(); + double const massDbar = pairEntry.mDbar(); - int pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); - int pTBinDbar = o2::analysis::findBin(binsPtCorrelations, ptDbar); + int const pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); + int const pTBinDbar = o2::analysis::findBin(binsPtCorrelations, ptDbar); double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { 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 +284,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,97 +302,97 @@ struct HfTaskCorrelationDDbar { void processMcRec(aod::DDbarPairFull 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 ptDbar = pairEntry.ptDbar(); - double massD = pairEntry.mD(); - double massDbar = pairEntry.mDbar(); + // define variables for widely used quantities + double const deltaPhi = pairEntry.deltaPhi(); + double const deltaEta = pairEntry.deltaEta(); + double const ptD = pairEntry.ptD(); + double const ptDbar = pairEntry.ptDbar(); + double const massD = pairEntry.mD(); + double const massDbar = pairEntry.mDbar(); - int pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); - int pTBinDbar = o2::analysis::findBin(binsPtCorrelations, ptDbar); + int const pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); + int const pTBinDbar = o2::analysis::findBin(binsPtCorrelations, ptDbar); double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { 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 +401,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 +449,13 @@ struct HfTaskCorrelationDDbar { void processMcGen(aod::DDbarPair 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 ptDbar = pairEntry.ptDbar(); + // define variables for widely used quantities + double const deltaPhi = pairEntry.deltaPhi(); + double const deltaEta = pairEntry.deltaEta(); + double const ptD = pairEntry.ptD(); + double const 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 41a1f77836f..955c2f559bc 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDMesonPairs.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDMesonPairs.cxx @@ -14,15 +14,21 @@ /// /// \author Andrea Tavira García , IJCLab Orsay -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/HFC/DataModel/DMesonPairsTables.h" +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -88,28 +94,29 @@ struct HfTaskCorrelationDMesonPairs { { if ((TESTBIT(candidateType, SelectedD) && TESTBIT(candidateType, TrueD)) || (TESTBIT(candidateType, SelectedDbar) && TESTBIT(candidateType, TrueDbar))) { return Signal; - } else if ((TESTBIT(candidateType, SelectedD) && TESTBIT(candidateType, TrueDbar)) || (TESTBIT(candidateType, SelectedDbar) && TESTBIT(candidateType, TrueD))) { + } + if ((TESTBIT(candidateType, SelectedD) && TESTBIT(candidateType, TrueDbar)) || (TESTBIT(candidateType, SelectedDbar) && TESTBIT(candidateType, TrueD))) { return Reflected; - } else if ((TESTBIT(candidateType, SelectedD) && !(TESTBIT(candidateType, TrueD) && TESTBIT(candidateType, TrueDbar))) || - (TESTBIT(candidateType, SelectedDbar) && !(TESTBIT(candidateType, TrueD) && TESTBIT(candidateType, TrueDbar)))) { + } + if ((TESTBIT(candidateType, SelectedD) && !(TESTBIT(candidateType, TrueD) && TESTBIT(candidateType, TrueDbar))) || + (TESTBIT(candidateType, SelectedDbar) && !(TESTBIT(candidateType, TrueD) && TESTBIT(candidateType, TrueDbar)))) { return Bkg; - } else { - return Default; } + return Default; } void processData(aod::D0Pair const& pairEntries) { for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities - float ptCand1 = pairEntry.ptCand1(); - float ptCand2 = pairEntry.ptCand2(); - float massDCand1 = pairEntry.mDCand1(); - float massDbarCand1 = pairEntry.mDbarCand1(); - float massDCand2 = pairEntry.mDCand2(); - float massDbarCand2 = pairEntry.mDbarCand2(); - float yCand1 = pairEntry.yCand1(); - float yCand2 = pairEntry.yCand2(); + float const ptCand1 = pairEntry.ptCand1(); + float const ptCand2 = pairEntry.ptCand2(); + float const massDCand1 = pairEntry.mDCand1(); + float const massDbarCand1 = pairEntry.mDbarCand1(); + float const massDCand2 = pairEntry.mDCand2(); + float const massDbarCand2 = pairEntry.mDbarCand2(); + float const yCand1 = pairEntry.yCand1(); + float const yCand2 = pairEntry.yCand2(); auto pairType = pairEntry.pairType(); auto d0Type1 = getD0Type(pairEntry.candidateType1()); auto d0Type2 = getD0Type(pairEntry.candidateType2()); @@ -135,14 +142,14 @@ struct HfTaskCorrelationDMesonPairs { { for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities - double ptParticle1 = pairEntry.ptCand1(); - double ptParticle2 = pairEntry.ptCand2(); - float massDParticle1 = pairEntry.mDCand1(); - float massDbarParticle1 = pairEntry.mDbarCand1(); - float massDParticle2 = pairEntry.mDCand2(); - float massDbarParticle2 = pairEntry.mDbarCand2(); - float yParticle1 = pairEntry.yCand1(); - float yParticle2 = pairEntry.yCand2(); + double const ptParticle1 = pairEntry.ptCand1(); + double const ptParticle2 = pairEntry.ptCand2(); + float const massDParticle1 = pairEntry.mDCand1(); + float const massDbarParticle1 = pairEntry.mDbarCand1(); + float const massDParticle2 = pairEntry.mDCand2(); + float const massDbarParticle2 = pairEntry.mDbarCand2(); + float const yParticle1 = pairEntry.yCand1(); + float const yParticle2 = pairEntry.yCand2(); auto pairType = pairEntry.pairType(); auto d0Type1 = getD0Type(pairEntry.candidateType1()); auto d0Type2 = getD0Type(pairEntry.candidateType2()); diff --git a/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx index 323288f392b..f374d34a42d 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx @@ -10,18 +10,53 @@ // or submit itself to any jurisdiction. /// \file taskCorrelationDplusHadrons.cxx +/// \brief D+-Hadrons azimuthal correlations analysis task - data-like, MC-reco and MC-Gen analyses /// \author Shyam Kumar -#include "CCDB/BasicCCDBManager.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include // std::shared_ptr +#include +#include using namespace o2; using namespace o2::constants::math; @@ -29,11 +64,6 @@ using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; -namespace o2::aod -{ -using DplusHadronPairFull = 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});"; @@ -51,24 +81,25 @@ 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.}; -auto pTBinsCorrelations_v = std::vector{pTBinsCorrelations, pTBinsCorrelations + npTBinsCorrelations + 1}; +const auto ptBinsCorrelationsVec = std::vector{pTBinsCorrelations, pTBinsCorrelations + npTBinsCorrelations + 1}; const double signalRegionInnerDefault[npTBinsCorrelations] = {1.8490, 1.8490, 1.8490, 1.8490, 1.8490, 1.8490, 1.8490, 1.8490}; const double signalRegionOuterDefault[npTBinsCorrelations] = {1.8890, 1.8890, 1.8890, 1.8890, 1.8890, 1.8890, 1.8890, 1.8890}; const double sidebandLeftOuterDefault[npTBinsCorrelations] = {1.7690, 1.7690, 1.7690, 1.7690, 1.7690, 1.7690, 1.7690, 1.7690}; const double sidebandLeftInnerDefault[npTBinsCorrelations] = {1.8250, 1.8250, 1.8250, 1.8250, 1.8250, 1.8250, 1.8250, 1.8250}; const double sidebandRightInnerDefault[npTBinsCorrelations] = {1.9130, 1.9130, 1.9130, 1.9130, 1.9130, 1.9130, 1.9130, 1.9130}; const double sidebandRightOuterDefault[npTBinsCorrelations] = {1.9690, 1.9690, 1.9690, 1.9690, 1.9690, 1.9690, 1.9690, 1.9690}; -auto signalRegionInner_v = std::vector{signalRegionInnerDefault, signalRegionInnerDefault + npTBinsCorrelations}; -auto signalRegionOuter_v = std::vector{signalRegionOuterDefault, signalRegionOuterDefault + npTBinsCorrelations}; -auto sidebandLeftInner_v = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + npTBinsCorrelations}; -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; -std::vector efficiencyDmeson(npTBinsEfficiency + 1); +const auto signalRegionInnerVec = std::vector{signalRegionInnerDefault, signalRegionInnerDefault + npTBinsCorrelations}; +const auto signalRegionOuterVec = std::vector{signalRegionOuterDefault, signalRegionOuterDefault + npTBinsCorrelations}; +const auto sidebandLeftInnerVec = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + npTBinsCorrelations}; +const auto sidebandLeftOuterVec = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + npTBinsCorrelations}; +const auto sidebandRightInnerVec = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + npTBinsCorrelations}; +const auto sidebandRightOuterVec = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + npTBinsCorrelations}; +const int npTBinsEfficiency = o2::analysis::hf_cuts_dplus_to_pi_k_pi::NBinsPt; +const 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 isPromptAnalysis{"isPromptAnalysis", true, "Flag for prompt D+-hadron correlations"}; 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"}; @@ -78,10 +109,11 @@ struct HfTaskCorrelationDplusHadrons { 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"}; + Configurable> mlScorePromptOrNonPromptMin{"mlScorePromptOrNonPromptMin", {0.5, 0.5, 0.5, 0.5}, "Minimum Machine learning scores for prompt or Feed-down"}; + Configurable> mlScorePromptOrNonPromptMax{"mlScorePromptOrNonPromptMax", {1.0, 1.0, 1.0, 1.0}, "Maximum Machine learning scores for prompt or Feed-down"}; + Configurable> mlScoreBkg{"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> binsPtCorrelations{"binsPtCorrelations", std::vector{ptBinsCorrelationsVec}, "pT bin limits for correlation plots"}; 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"}; @@ -89,12 +121,12 @@ struct HfTaskCorrelationDplusHadrons { 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"}; - Configurable> sidebandLeftInner{"sidebandLeftInner", std::vector{sidebandLeftInner_v}, "Inner values of left sideband vs pT"}; - 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> signalRegionInner{"signalRegionInner", std::vector{signalRegionInnerVec}, "Inner values of signal region vs pT"}; + Configurable> signalRegionOuter{"signalRegionOuter", std::vector{signalRegionOuterVec}, "Outer values of signal region vs pT"}; + Configurable> sidebandLeftInner{"sidebandLeftInner", std::vector{sidebandLeftInnerVec}, "Inner values of left sideband vs pT"}; + Configurable> sidebandLeftOuter{"sidebandLeftOuter", std::vector{sidebandLeftOuterVec}, "Outer values of left sideband vs pT"}; + Configurable> sidebandRightInner{"sidebandRightInner", std::vector{sidebandRightInnerVec}, "Inner values of right sideband vs pT"}; + Configurable> sidebandRightOuter{"sidebandRightOuter", std::vector{sidebandRightOuterVec}, "Outer values of right sideband vs 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"}; @@ -115,20 +147,13 @@ struct HfTaskCorrelationDplusHadrons { 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; + std::shared_ptr effD = nullptr; + int idxBdtScore = 1; // Index BDTScore 1 for Prompt and 2 for FD Analysis enum CandidateStep { kCandidateStepMcGenAll = 0, kCandidateStepMcGenDplusToPiKPi, @@ -138,6 +163,7 @@ struct HfTaskCorrelationDplusHadrons { kCandidateStepMcRecoInAcceptance, kCandidateNSteps }; + using DplusHadronPair = soa::Join; using DplusHadronPairFullWithMl = soa::Join; using CandDplusMcReco = soa::Filtered>; using CandDplusMcGen = soa::Join; @@ -145,6 +171,13 @@ struct HfTaskCorrelationDplusHadrons { 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); + // 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"}; HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -154,18 +187,19 @@ struct HfTaskCorrelationDplusHadrons { 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 const 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"}; + AxisSpec const 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}}); @@ -248,7 +282,7 @@ struct HfTaskCorrelationDplusHadrons { hCandidates->GetAxis(2)->SetTitle("Charm hadron origin"); // Loading efficiency histograms from CCDB - if (applyEfficiency && loadAccXEffFromCCDB) { + if ((applyEfficiency != 0) && loadAccXEffFromCCDB) { ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -272,6 +306,8 @@ struct HfTaskCorrelationDplusHadrons { } LOGF(info, "Loaded associated efficiency histogram from %s", associatedEffCcdbPath.value.c_str()); } + auto effD = isPromptAnalysis ? mEfficiencyPrompt : mEfficiencyFD; + idxBdtScore = isPromptAnalysis ? 1 : 2; if (activateQA) { const int regionLimits = 6; @@ -295,64 +331,69 @@ struct HfTaskCorrelationDplusHadrons { 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); + float const massD = candidate.mD(); + float const ptD = candidate.ptD(); + float const bdtScorePrompt = candidate.mlScorePrompt(); + float const bdtScoreNonPrompt = candidate.mlScoreNonPrompt(); + float const bdtScoreBkg = candidate.mlScoreBkg(); + int const effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + float const bdtScorePromptOrNonPrompt = isPromptAnalysis ? bdtScorePrompt : bdtScoreNonPrompt; // reject entries outside pT ranges of interest if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) { continue; } - if (bdtScorePrompt < mlOutputPrompt->at(effBinD) || bdtScoreBkg > mlOutputBkg->at(effBinD)) { + if (bdtScorePromptOrNonPrompt < mlScorePromptOrNonPromptMin->at(effBinD) || bdtScorePromptOrNonPrompt > mlScorePromptOrNonPromptMax->at(effBinD) || bdtScoreBkg > mlScoreBkg->at(effBinD)) { continue; } double efficiencyWeightD = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { efficiencyWeightD = 1. / efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)); if (loadAccXEffFromCCDB) { - efficiencyWeightD = 1. / mEfficiencyPrompt->GetBinContent(mEfficiencyPrompt->FindBin(ptD)); + efficiencyWeightD = 1. / effD->GetBinContent(effD->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 - 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(binsPtEfficiencyD, ptD); - int pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); + float const deltaPhi = pairEntry.deltaPhi(); + float const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.ptD(); + float const ptHadron = pairEntry.ptHadron(); + float const bdtScorePrompt = pairEntry.mlScorePrompt(); + float const bdtScoreNonPrompt = pairEntry.mlScoreNonPrompt(); + float const bdtScoreBkg = pairEntry.mlScoreBkg(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int const poolBin = pairEntry.poolBin(); + double const massD = pairEntry.mD(); + int const effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + int const pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); + float const bdtScorePromptOrNonPrompt = isPromptAnalysis ? bdtScorePrompt : bdtScoreNonPrompt; // reject entries outside pT ranges of interest if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) { continue; } - if (bdtScorePrompt < mlOutputPrompt->at(effBinD) || bdtScoreBkg > mlOutputBkg->at(effBinD)) { + if (bdtScorePromptOrNonPrompt < mlScorePromptOrNonPromptMin->at(effBinD) || bdtScorePromptOrNonPrompt > mlScorePromptOrNonPromptMax->at(effBinD) || bdtScoreBkg > mlScoreBkg->at(effBinD)) { continue; } if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { continue; } double efficiencyWeight = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { 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))); + efficiencyWeight = 1. / (effD->GetBinContent(effD->FindBin(ptD)) * mEfficiencyAssociated->GetBinContent(mEfficiencyAssociated->FindBin(ptHadron))); } } // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots @@ -392,28 +433,32 @@ struct HfTaskCorrelationDplusHadrons { 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(); + float const massD = candidate.mD(); + float const ptD = candidate.ptD(); + float const bdtScorePrompt = candidate.mlScorePrompt(); + float const bdtScoreNonPrompt = candidate.mlScoreNonPrompt(); + float const bdtScoreBkg = candidate.mlScoreBkg(); + int const effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + bool const isDplusPrompt = candidate.isPrompt(); + float const bdtScorePromptOrNonPrompt = isPromptAnalysis ? bdtScorePrompt : bdtScoreNonPrompt; // reject entries outside pT ranges of interest - if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) + if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) { continue; + } - if (bdtScorePrompt < mlOutputPrompt->at(effBinD) || bdtScoreBkg > mlOutputBkg->at(effBinD)) { + if (bdtScorePromptOrNonPrompt < mlScorePromptOrNonPromptMin->at(effBinD) || bdtScorePromptOrNonPrompt > mlScorePromptOrNonPromptMax->at(effBinD) || bdtScoreBkg > mlScoreBkg->at(effBinD)) { continue; } double efficiencyWeightD = 1.; - if (applyEfficiency) { + if (applyEfficiency != 0) { 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); @@ -423,6 +468,7 @@ struct HfTaskCorrelationDplusHadrons { 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); @@ -432,28 +478,31 @@ struct HfTaskCorrelationDplusHadrons { 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(); - 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(); - int effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); - int pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); + float const deltaPhi = pairEntry.deltaPhi(); + float const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.ptD(); + float const ptHadron = pairEntry.ptHadron(); + float const massD = pairEntry.mD(); + float const bdtScorePrompt = pairEntry.mlScorePrompt(); + float const bdtScoreNonPrompt = pairEntry.mlScoreNonPrompt(); + float const bdtScoreBkg = pairEntry.mlScoreBkg(); + bool const isPhysicalPrimary = pairEntry.isPhysicalPrimary(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + bool const isDplusPrompt = pairEntry.isPrompt(); + int const originHadron = pairEntry.trackOrigin(); + int const poolBin = pairEntry.poolBin(); + int const effBinD = o2::analysis::findBin(binsPtEfficiencyD, ptD); + int const pTBinD = o2::analysis::findBin(binsPtCorrelations, ptD); + float const bdtScorePromptOrNonPrompt = isPromptAnalysis ? bdtScorePrompt : bdtScoreNonPrompt; // reject entries outside pT ranges of interest - if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) + if (ptD < binsPtEfficiencyD->front() || ptD > binsPtEfficiencyD->back()) { continue; + } - if (bdtScorePrompt < mlOutputPrompt->at(effBinD) || bdtScoreBkg > mlOutputBkg->at(effBinD)) { + if (bdtScorePromptOrNonPrompt < mlScorePromptOrNonPromptMin->at(effBinD) || bdtScorePromptOrNonPrompt > mlScorePromptOrNonPromptMax->at(effBinD) || bdtScoreBkg > mlScoreBkg->at(effBinD)) { continue; } if (trackDcaXY > dcaXYTrackMax || trackDcaZ > dcaZTrackMax || trackTpcCrossedRows < nTpcCrossedRaws) { @@ -461,8 +510,8 @@ struct HfTaskCorrelationDplusHadrons { } double efficiencyWeight = 1.; - if (applyEfficiency) { - if (statusDplusPrompt) { + if (applyEfficiency != 0) { + if (isDplusPrompt) { 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))); @@ -486,15 +535,15 @@ struct HfTaskCorrelationDplusHadrons { // 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, statusDplusPrompt, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, ptD, ptHadron, static_cast(isDplusPrompt), 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("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, ptD, ptHadron, static_cast(isDplusPrompt), poolBin, efficiencyWeight); + if (isDplusPrompt && originHadron == RecoDecay::OriginType::Prompt) { registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptDplusPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - } else if (statusDplusPrompt == 0 && statusPromptHadron == 2) { + } else if (!isDplusPrompt && originHadron == RecoDecay::OriginType::NonPrompt) { registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDplusNonPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); } } @@ -524,29 +573,29 @@ struct HfTaskCorrelationDplusHadrons { 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(DplusHadronPairFullWithMl const& pairEntries) + void processMcGen(DplusHadronPair 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(); - int poolBin = pairEntry.poolBin(); - int statusPromptHadron = pairEntry.trackOrigin(); - bool isDplusPrompt = pairEntry.isPrompt(); + float const deltaPhi = pairEntry.deltaPhi(); + float const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.ptD(); + float const ptHadron = pairEntry.ptHadron(); + int const poolBin = pairEntry.poolBin(); + int const originHadron = pairEntry.trackOrigin(); + bool const 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) { + if (originHadron == RecoDecay::OriginType::Prompt) { registry.fill(HIST("hCorrel2DVsPtMcGenPromptDPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); } } else { registry.fill(HIST("hCorrel2DVsPtMcGenNonPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); - if (statusPromptHadron == 2) { + if (originHadron == RecoDecay::OriginType::NonPrompt) { registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptDNonPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); } } @@ -571,7 +620,7 @@ struct HfTaskCorrelationDplusHadrons { 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) { + if (std::abs(mcParticle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { hCandidates->Fill(kCandidateStepMcGenDplusToPiKPi, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); auto yDplus = RecoDecay::y(mcParticle.pVector(), o2::constants::physics::MassDPlus); if (std::abs(yDplus) <= yCandGenMax) { @@ -610,7 +659,7 @@ struct HfTaskCorrelationDplusHadrons { 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()))) { + if (outputMl[0] > mlScoreBkg->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())) || outputMl[idxBdtScore] < mlScorePromptOrNonPromptMin->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt())) || outputMl[idxBdtScore] > mlScorePromptOrNonPromptMax->at(o2::analysis::findBin(binsPtEfficiencyD, candidate.pt()))) { continue; } auto collision = candidate.template collision_as>(); @@ -618,9 +667,9 @@ struct HfTaskCorrelationDplusHadrons { continue; } multiplicity = collision.multFT0M(); - if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi) { + if (std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { hCandidates->Fill(kCandidateStepMcReco, candidate.pt(), multiplicity, candidate.originMcRec()); - if (std::abs(hfHelper.yDplus(candidate)) <= yCandMax) { + 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()); diff --git a/PWGHF/HFC/Tasks/taskCorrelationDsHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDsHadrons.cxx index 4abd5a12a70..ef43fff45d6 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDsHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDsHadrons.cxx @@ -14,15 +14,51 @@ /// \author Grazia Luparello /// \author Samuele Cattaruzzi -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::constants::physics; @@ -30,6 +66,16 @@ using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; +enum ResonantChannel : int8_t { + PhiPi = 1, + Kstar0K = 2 +}; + +namespace +{ +std::unordered_map channelsResonant = {{{ResonantChannel::PhiPi, hf_decay::hf_cand_3prong::DecayChannelResonant::DsToPhiPi}, {ResonantChannel::Kstar0K, hf_decay::hf_cand_3prong::DecayChannelResonant::DsToKstar0K}}}; +} + /// 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"}; @@ -40,27 +86,34 @@ struct HfTaskCorrelationDsHadrons { 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 useHighDimHistoForEff{"useHighDimHistoForEff", false, "Flag to create/use higher dimension histograms in the efficiency processes/correction"}; + Configurable applyDeltaPhiCorrEff{"applyDeltaPhiCorrEff", false, "Flag to use higher dimension histograms with delta phi correction in the efficiency correction"}; + Configurable doLSpair{"doLSpair", false, "Flag to evaluate correlations for like-sign pairs"}; + Configurable doULSpair{"doULSpair", false, "Flag to evaluate correlations for unlike-sign pairs"}; // 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 decayChannel{"decayChannel", 1, "Resonant 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"}; - 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 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"}; @@ -71,34 +124,28 @@ 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"}; - 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"}; + // 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"}; - HfHelper hfHelper; + std::shared_ptr hEfficiencyD = nullptr; + std::shared_ptr hEfficiencyAssociated = nullptr; + std::shared_ptr hEfficiencyDMult = nullptr; + std::shared_ptr hEfficiencyAssociatedMult = nullptr; + std::shared_ptr hEfficiencyAssociatedDeltaPhiCorr = nullptr; - enum CandidateStep { - kCandidateStepMcGenDsToKKPi = 0, - kCandidateStepMcCandInAcceptance, - kCandidateStepMcDaughtersInAcceptance, - kCandidateStepMcReco, - kCandidateStepMcRecoInAcceptance, - kCandidateNSteps - }; + static constexpr float Epsilon{1.e-8}; - enum AssocTrackStep { kAssocTrackStepMcGen = 0, - kAssocTrackStepMcGenInAcceptance, - kAssocTrackStepRecoAll, - kAssocTrackStepRecoMcMatch, - kAssocTrackStepRecoPrimaries, - kAssocTrackStepRecoSpecies, - kAssocTrackNSteps }; + 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 @@ -107,6 +154,21 @@ struct HfTaskCorrelationDsHadrons { 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 binsNumPvContr{"binsNumPvContr", {100, 0., 1000.}, "number PV contributors"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext&) @@ -118,16 +180,35 @@ struct HfTaskCorrelationDsHadrons { 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 const axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec const axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; AxisSpec axisPosZ = {binsPosZ, "PosZ"}; + AxisSpec axisNumPvContr = {binsNumPvContr, "Num PV contributors"}; AxisSpec axisDsPrompt = {2, -0.5, 1.5, "Prompt Ds"}; // Histograms for data analysis registry.add("hBdtScorePrompt", "Ds BDT prompt score", {HistType::kTH1F, {axisBdtScore}}); registry.add("hBdtScoreBkg", "Ds BDT bkg score", {HistType::kTH1F, {axisBdtScore}}); + registry.add("hMassDsVsPt", "Ds candidates massVsPt", {HistType::kTH2F, {{axisMassD}, {axisPtD}}}); + if (doLSpair) { + registry.add("hCorrel2DVsPtSignalRegionLS", "Ds-h correlations signal region - LS pairs", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSidebandLeftLS", "Ds-h correlations sideband left region - LS pairs", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSidebandRightLS", "Ds-h correlations sideband right region - LS pairs", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSignalRegionLS"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandLeftLS"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRightLS"))->Sumw2(); + } + if (doULSpair) { + registry.add("hCorrel2DVsPtSignalRegionULS", "Ds-h correlations signal region - ULS pairs", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSidebandLeftULS", "Ds-h correlations sideband left region - ULS pairs", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + registry.add("hCorrel2DVsPtSidebandRightULS", "Ds-h correlations sideband right region - ULS pairs", {HistType::kTHnSparseD, {{axisDetlaPhi}, {axisDetlaEta}, {axisPtD}, {axisPtHadron}, {axisPoolBin}}}); + + registry.get(HIST("hCorrel2DVsPtSignalRegionULS"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandLeftULS"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRightULS"))->Sumw2(); + } 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}}}); @@ -180,62 +261,199 @@ struct HfTaskCorrelationDsHadrons { } // 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"}}}); + registry.add("hNumPvContrib", "Num PV contributors", {HistType::kTH1F, {axisNumPvContr}}); + 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("hPtPrmPromptPartMcRec", "Primary prompt particles - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtPrmNonPromptPartMcRec", "Primary non-prompt particles - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtMcParticleAssocSpecieMcRec", "Associated Particle - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtParticleAssocMcRec", "Associated Particle - MC Rec", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hPtCandMcGenDaughterInAcc", "Ds,Hadron particles non prompt - MC Gen", {HistType::kTH1F, {axisPtD}}); + + if (useHighDimHistoForEff) { + registry.add("hPtCandMcRecPrompt", "Ds prompt candidates", {HistType::kTH2F, {{axisPtD}, {axisNumPvContr}}}); + registry.add("hPtCandMcRecNonPrompt", "Ds non prompt candidates pt", {HistType::kTH2F, {{axisPtD}, {axisNumPvContr}}}); + registry.add("hPtCandMcGenPrompt", "Ds,Hadron particles prompt - MC Gen", {HistType::kTH2F, {{axisPtD}, {axisNumPvContr}}}); + registry.add("hPtCandMcGenNonPrompt", "Ds,Hadron particles non prompt - MC Gen", {HistType::kTH2F, {{axisPtD}, {axisNumPvContr}}}); + registry.add("hPtParticleAssocSpecieMcRec", "Associated Particle - MC Rec", {HistType::kTHnSparseF, {axisPtHadron}}); + registry.add("hPtPrmPionMcRec", "Primary pions - MC Rec", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmKaonMcRec", "Primary kaons - MC Rec", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmProtonMcRec", "Primary protons - MC Rec", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmElectronMcRec", "Primary electrons - MC Rec", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmMuonMcRec", "Primary muons - MC Rec", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtParticleAssocMcGen", "Associated Particle - MC Gen", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmPionMcGen", "Primary pions - MC Gen", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmKaonMcGen", "Primary kaons - MC Gen", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmProtonMcGen", "Primary protons - MC Gen", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmElectronMcGen", "Primary electrons - MC Gen", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + registry.add("hPtPrmMuonMcGen", "Primary muons - MC Gen", {HistType::kTHnSparseF, {{axisPtHadron}, {axisEta}, {axisPosZ}, {axisNumPvContr}}}); + } else { + 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("hPtParticleAssocSpecieMcRec", "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("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}}); + } + } + + // 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()); + + if (useHighDimHistoForEff) { + hEfficiencyDMult = std::shared_ptr(ccdb->getForTimeStamp(promptEffCcdbPath, timestampCcdb)); + if (hEfficiencyDMult == 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()); + + if (applyDeltaPhiCorrEff) { + hEfficiencyAssociatedDeltaPhiCorr = std::shared_ptr(ccdb->getForTimeStamp(associatedEffCcdbPath, timestampCcdb)); + if (hEfficiencyAssociatedDeltaPhiCorr == 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()); + } else { + hEfficiencyAssociatedMult = std::shared_ptr(ccdb->getForTimeStamp(associatedEffCcdbPath, timestampCcdb)); + if (hEfficiencyAssociatedMult == 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()); + } + } else { + hEfficiencyD = std::shared_ptr(ccdb->getForTimeStamp(promptEffCcdbPath, timestampCcdb)); + if (hEfficiencyD == 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()); - 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"); + hEfficiencyAssociated = std::shared_ptr(ccdb->getForTimeStamp(associatedEffCcdbPath, timestampCcdb)); + if (hEfficiencyAssociated == 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()); + } + } + } + + enum class EfficiencyMode { + DsOnly = 1, + DsHadronPair = 2 + }; + + 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)); + } + + double getEfficiencyWeight(float ptD, std::optional multPvContrib = std::nullopt, std::optional ptAssoc = std::nullopt, std::optional deltaPhi = std::nullopt, EfficiencyMode mode = EfficiencyMode::DsOnly) + { + if (!applyEfficiency) { + return 1.; + } + + double weight = 1.; + + switch (mode) { + case EfficiencyMode::DsOnly: + if (loadAccXEffFromCCDB) { + if (useHighDimHistoForEff) { + if (hEfficiencyDMult->GetBinContent(hEfficiencyDMult->FindBin(ptD, static_cast(*multPvContrib))) <= Epsilon) { + LOG(fatal) << "A bin content in Ds-meson efficiency histogram is zero!"; + } + weight = 1. / hEfficiencyDMult->GetBinContent(hEfficiencyDMult->FindBin(ptD, static_cast(*multPvContrib))); + } else { + if (hEfficiencyD->GetBinContent(hEfficiencyD->FindBin(ptD)) <= Epsilon) { + LOG(fatal) << "A bin content in Ds-meson efficiency histogram is zero!"; + } + weight = 1. / hEfficiencyD->GetBinContent(hEfficiencyD->FindBin(ptD)); + } + } else { + if (efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) <= Epsilon) { + LOG(fatal) << "A bin content in Ds-meson efficiency vector is zero!"; + } + weight = 1. / efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)); + } + break; + case EfficiencyMode::DsHadronPair: + if (loadAccXEffFromCCDB) { + if (ptAssoc && (hEfficiencyAssociated || hEfficiencyAssociatedMult || hEfficiencyAssociatedDeltaPhiCorr)) { + if (useHighDimHistoForEff) { + if (applyDeltaPhiCorrEff) { + if (hEfficiencyAssociatedDeltaPhiCorr->GetBinContent(hEfficiencyAssociatedDeltaPhiCorr->FindBin(*ptAssoc, ptD, static_cast(*deltaPhi))) <= Epsilon) { + LOG(fatal) << "A bin content in associated particle efficiency histogram is zero!"; + } + weight = 1. / (hEfficiencyDMult->GetBinContent(hEfficiencyDMult->FindBin(ptD, static_cast(*multPvContrib))) * hEfficiencyAssociatedDeltaPhiCorr->GetBinContent(hEfficiencyAssociatedDeltaPhiCorr->FindBin(*ptAssoc, ptD, static_cast(*deltaPhi)))); + } else { + if (hEfficiencyAssociatedMult->GetBinContent(hEfficiencyAssociatedMult->FindBin(*ptAssoc, static_cast(*multPvContrib))) <= Epsilon) { + LOG(fatal) << "A bin content in associated particle efficiency histogram is zero!"; + } + weight = 1. / (hEfficiencyDMult->GetBinContent(hEfficiencyDMult->FindBin(ptD, static_cast(*multPvContrib))) * hEfficiencyAssociatedMult->GetBinContent(hEfficiencyAssociatedMult->FindBin(*ptAssoc, static_cast(*multPvContrib)))); + } + } else { + if (hEfficiencyAssociated->GetBinContent(hEfficiencyAssociated->FindBin(*ptAssoc)) <= Epsilon) { + LOG(fatal) << "A bin content in associated particle efficiency histogram is zero!"; + } + weight = 1. / (hEfficiencyD->GetBinContent(hEfficiencyD->FindBin(ptD)) * hEfficiencyAssociated->GetBinContent(hEfficiencyAssociated->FindBin(*ptAssoc))); + } + } + } else { + if (ptAssoc) { + if (efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, *ptAssoc)) <= Epsilon) { + LOG(fatal) << "A bin content in associated particle efficiency vector is zero!"; + } + weight = 1. / (efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)) * efficiencyHad->at(o2::analysis::findBin(binsPtEfficiencyHad, *ptAssoc))); + } + } + break; + default: + LOG(fatal) << "Unknown efficiency mode!"; + break; } + + return weight; } - void processData(DsHadronPairFullWithMl const& pairEntries, + void processData(DsHadronPairWithMl const& pairEntries, aod::DsCandRecoInfo 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); + float const massD = candidate.mD(); + float const ptD = candidate.signedPtD(); + float const bdtScorePrompt = candidate.mlScorePrompt(); + float const bdtScoreBkg = candidate.mlScoreBkg(); + int multPvContrib = candidate.numPvContrib(); + int const ptBinD = o2::analysis::findBin(binsPtD, std::abs(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 (useHighDimHistoForEff) { + efficiencyWeightD = getEfficiencyWeight(std::abs(ptD), multPvContrib); + } else { + efficiencyWeightD = getEfficiencyWeight(std::abs(ptD)); } - registry.fill(HIST("hMassDsVsPt"), massD, ptD, efficiencyWeightD); + + registry.fill(HIST("hMassDsVsPt"), massD, std::abs(ptD), efficiencyWeightD); registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); } @@ -243,46 +461,69 @@ struct HfTaskCorrelationDsHadrons { 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 ptBinD = o2::analysis::findBin(binsPtD, ptD); - - if (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + float const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.signedPtD(); + float const ptHadron = pairEntry.signedPtHadron(); + float const massD = pairEntry.mD(); + float const bdtScorePrompt = pairEntry.mlScorePrompt(); + float const bdtScoreBkg = pairEntry.mlScoreBkg(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int multPvContrib = pairEntry.numPvContrib(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int const poolBin = pairEntry.poolBin(); + int const ptBinD = o2::analysis::findBin(binsPtD, std::abs(ptD)); + + 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 (useHighDimHistoForEff) { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), multPvContrib, std::abs(ptHadron), deltaPhi, EfficiencyMode::DsHadronPair); + } else { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), std::nullopt, std::abs(ptHadron), std::nullopt, EfficiencyMode::DsHadronPair); } // 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); + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSignalRegionLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSignalRegionULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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); + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandLeftLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandLeftULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSidebandLeft"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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); + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandRightLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandRightULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSidebandRight"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + registry.fill(HIST("hDeltaEtaPtIntSidebandRight"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRight"), deltaPhi, efficiencyWeight); + } } } } @@ -293,26 +534,31 @@ struct HfTaskCorrelationDsHadrons { 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 (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + float const massD = candidate.mD(); + float const ptD = candidate.signedPtD(); + float const bdtScorePrompt = candidate.mlScorePrompt(); + float const bdtScoreBkg = candidate.mlScoreBkg(); + int const ptBinD = o2::analysis::findBin(binsPtD, std::abs(ptD)); + int multPvContrib = candidate.numPvContrib(); + bool const isDsPrompt = candidate.isPrompt(); + + if (!isSelectedCandidate(ptBinD, bdtScorePrompt, bdtScoreBkg)) { continue; } + double efficiencyWeightD = 1.; - if (applyEfficiency) { - efficiencyWeightD = 1. / efficiencyD->at(o2::analysis::findBin(binsPtEfficiencyD, ptD)); + if (useHighDimHistoForEff) { + efficiencyWeightD = getEfficiencyWeight(std::abs(ptD), multPvContrib); + } else { + efficiencyWeightD = getEfficiencyWeight(std::abs(ptD)); } + if (isDsPrompt) { - registry.fill(HIST("hMassPromptDsVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hMassPromptDsVsPt"), massD, std::abs(ptD), efficiencyWeightD); registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); } else { - registry.fill(HIST("hMassNonPromptDsVsPt"), massD, ptD, efficiencyWeightD); + registry.fill(HIST("hMassNonPromptDsVsPt"), massD, std::abs(ptD), efficiencyWeightD); registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); } @@ -321,57 +567,63 @@ struct HfTaskCorrelationDsHadrons { 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 (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + float const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.signedPtD(); + float const ptHadron = pairEntry.signedPtHadron(); + float const massD = pairEntry.mD(); + float const bdtScorePrompt = pairEntry.mlScorePrompt(); + float const bdtScoreBkg = pairEntry.mlScoreBkg(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int multPvContrib = pairEntry.numPvContrib(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int const poolBin = pairEntry.poolBin(); + int const statusDsPrompt = static_cast(pairEntry.isPrompt()); + int const statusPromptHadron = pairEntry.trackOrigin(); + int const ptBinD = o2::analysis::findBin(binsPtD, std::abs(ptD)); + bool const 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 (useHighDimHistoForEff) { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), multPvContrib, std::abs(ptHadron), deltaPhi, EfficiencyMode::DsHadronPair); + } else { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), std::nullopt, std::abs(ptHadron), std::nullopt, EfficiencyMode::DsHadronPair); } + // 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); + registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), statusDsPrompt, poolBin, efficiencyWeight); if (isPhysicalPrimary) { - registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, ptD, ptHadron, statusDsPrompt, poolBin, efficiencyWeight); - if (statusDsPrompt == 1 && statusPromptHadron == 1) { - registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptDsPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - } else if (statusDsPrompt == 0 && statusPromptHadron == 2) { - registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDsNonPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), statusDsPrompt, poolBin, efficiencyWeight); + if (statusDsPrompt == 1 && statusPromptHadron == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptDsPromptHadronMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (statusDsPrompt == 0 && statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDsNonPromptHadronMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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("hCorrel2DVsPtSidebandLeftMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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("hCorrel2DVsPtSidebandRightMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebandRightMcRec"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSidebandRightMcRec"), deltaPhi, efficiencyWeight); } @@ -384,139 +636,228 @@ struct HfTaskCorrelationDsHadrons { { 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(); - int poolBin = pairEntry.poolBin(); - int statusPromptHadron = pairEntry.trackOrigin(); - bool isDsPrompt = pairEntry.isPrompt(); - - registry.fill(HIST("hCorrel2DVsPtMcGen"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + float const deltaPhi = pairEntry.deltaPhi(); + float const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.signedPtD(); + float const ptHadron = pairEntry.signedPtHadron(); + int const poolBin = pairEntry.poolBin(); + int const statusPromptHadron = pairEntry.trackOrigin(); + bool const isDsPrompt = pairEntry.isPrompt(); + + registry.fill(HIST("hCorrel2DVsPtMcGen"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin); registry.fill(HIST("hDeltaEtaPtIntMcGen"), deltaEta); registry.fill(HIST("hDeltaPhiPtIntMcGen"), deltaPhi); if (isDsPrompt) { - registry.fill(HIST("hCorrel2DVsPtMcGenPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); - if (statusPromptHadron == 1) { - registry.fill(HIST("hCorrel2DVsPtMcGenPromptDsPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + registry.fill(HIST("hCorrel2DVsPtMcGenPrompt"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin); + if (statusPromptHadron == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtMcGenPromptDsPromptHadron"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin); } } else { - registry.fill(HIST("hCorrel2DVsPtMcGenNonPrompt"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); - if (statusPromptHadron == 2) { - registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptDsNonPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); + registry.fill(HIST("hCorrel2DVsPtMcGenNonPrompt"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin); + if (statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptDsNonPromptHadron"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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 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 ptBinD = o2::analysis::findBin(binsPtD, ptD); - - if (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + float const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.signedPtD(); + float const ptHadron = pairEntry.signedPtHadron(); + float const massD = pairEntry.mD(); + float const bdtScorePrompt = pairEntry.mlScorePrompt(); + float const bdtScoreBkg = pairEntry.mlScoreBkg(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int multPvContrib = pairEntry.numPvContrib(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int const poolBin = pairEntry.poolBin(); + int const ptBinD = o2::analysis::findBin(binsPtD, std::abs(ptD)); + + 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 (useHighDimHistoForEff) { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), multPvContrib, std::abs(ptHadron), deltaPhi, EfficiencyMode::DsHadronPair); + } else { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), std::nullopt, std::abs(ptHadron), std::nullopt, EfficiencyMode::DsHadronPair); } // 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); + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSignalRegionLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSignalRegionULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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); + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandLeftLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandLeftULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSidebandLeft"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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); + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandRightLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandRightULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSidebandRight"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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 const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.signedPtD(); + float const ptHadron = pairEntry.signedPtHadron(); + float const massD = pairEntry.mD(); + int multPvContrib = pairEntry.numPvContrib(); + int const poolBin = pairEntry.poolBin(); + int const ptBinD = o2::analysis::findBin(binsPtD, std::abs(ptD)); + + double efficiencyWeight = 1.; + if (useHighDimHistoForEff) { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), multPvContrib, std::abs(ptHadron), deltaPhi, EfficiencyMode::DsHadronPair); + } else { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), std::nullopt, std::abs(ptHadron), std::nullopt, EfficiencyMode::DsHadronPair); + } + + // in signal region + if (massD > signalRegionInner->at(ptBinD) && massD < signalRegionOuter->at(ptBinD)) { + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSignalRegionLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSignalRegionULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSignalRegion"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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)) { + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandLeftLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandLeftULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSidebandLeft"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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)) { + if (doLSpair && ((ptD > 0. && ptHadron > 0.) || (ptD < 0. && ptHadron < 0.))) { // like-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandRightLS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (doULSpair && ((ptD > 0. && ptHadron < 0.) || (ptD < 0. && ptHadron > 0.))) { // unlike-sign pairs + registry.fill(HIST("hCorrel2DVsPtSidebandRightULS"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (fillHistoData) { // default case + registry.fill(HIST("hCorrel2DVsPtSidebandRight"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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 (bdtScorePrompt < mlOutputPrompt->at(ptBinD) || bdtScoreBkg > mlOutputBkg->at(ptBinD)) { + float const deltaEta = pairEntry.deltaEta(); + float const ptD = pairEntry.signedPtD(); + float const ptHadron = pairEntry.signedPtHadron(); + float const massD = pairEntry.mD(); + float const bdtScorePrompt = pairEntry.mlScorePrompt(); + float const bdtScoreBkg = pairEntry.mlScoreBkg(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int multPvContrib = pairEntry.numPvContrib(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int const poolBin = pairEntry.poolBin(); + int const statusDsPrompt = static_cast(pairEntry.isPrompt()); + int const statusPromptHadron = pairEntry.trackOrigin(); + int const ptBinD = o2::analysis::findBin(binsPtD, std::abs(ptD)); + bool const 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 (useHighDimHistoForEff) { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), multPvContrib, std::abs(ptHadron), deltaPhi, EfficiencyMode::DsHadronPair); + } else { + efficiencyWeight = getEfficiencyWeight(std::abs(ptD), std::nullopt, std::abs(ptHadron), std::nullopt, EfficiencyMode::DsHadronPair); } + // 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); + registry.fill(HIST("hCorrel2DVsPtSignalRegionMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), statusDsPrompt, poolBin, efficiencyWeight); if (isPhysicalPrimary) { - registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, ptD, ptHadron, statusDsPrompt, poolBin, efficiencyWeight); - if (statusDsPrompt == 1 && statusPromptHadron == 1) { - registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptDsPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); - } else if (statusDsPrompt == 0 && statusPromptHadron == 2) { - registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDsNonPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), statusDsPrompt, poolBin, efficiencyWeight); + if (statusDsPrompt == 1 && statusPromptHadron == RecoDecay::OriginType::Prompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionPromptDsPromptHadronMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); + } else if (statusDsPrompt == 0 && statusPromptHadron == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDsNonPromptHadronMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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("hCorrel2DVsPtSidebandLeftMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(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("hCorrel2DVsPtSidebandRightMcRec"), deltaPhi, deltaEta, std::abs(ptD), std::abs(ptHadron), poolBin, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebandRightMcRec"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSidebandRightMcRec"), deltaPhi, efficiencyWeight); } @@ -524,11 +865,6 @@ struct HfTaskCorrelationDsHadrons { } PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcRecME, "Process MC Reco ME", false); - SliceCache cache; - Preslice perCollisionCand = o2::aod::hf_cand::collisionId; - Preslice perCollisionCandMc = o2::aod::mcparticle::mcCollisionId; - PresliceUnsorted> collPerCollMc = o2::aod::mccollisionlabel::mcCollisionId; - /// Ds-Hadron correlation - for calculating candidate reconstruction efficiency using MC reco-level analysis void processMcCandEfficiency(soa::Join const& collisions, soa::Join const& mcCollisions, @@ -536,8 +872,6 @@ struct HfTaskCorrelationDsHadrons { CandDsMcReco const& candidates, aod::TracksWMc const&) { - auto hCandidates = registry.get(HIST("hCandidates")); - /// loop over generated collisions for (const auto& mcCollision : mcCollisions) { @@ -569,38 +903,43 @@ struct HfTaskCorrelationDsHadrons { continue; } - float multiplicityReco = collision.multFT0M(); - float multiplicityGen = mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); // multFT0M = multFt0A + multFT0C + registry.fill(HIST("hNumPvContrib"), collision.numContrib()); 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()); + if ((std::abs(mcParticle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && (mcParticle.flagMcDecayChanGen() == channelsResonant[decayChannel])) { 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 (useHighDimHistoForEff) { + registry.fill(HIST("hPtCandMcGenPrompt"), mcParticle.pt(), collision.numContrib()); + } else { + registry.fill(HIST("hPtCandMcGenPrompt"), mcParticle.pt()); + } } if (mcParticle.originMcGen() == RecoDecay::OriginType::NonPrompt) { - registry.fill(HIST("hPtCandMcGenNonPrompt"), mcParticle.pt()); + if (useHighDimHistoForEff) { + registry.fill(HIST("hPtCandMcGenNonPrompt"), mcParticle.pt(), collision.numContrib()); + } else { + 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; + + 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) { + registry.fill(HIST("hPtCandMcGenDaughterInAcc"), mcParticle.pt()); } - } - if (isDaughterInAcceptance) { - hCandidates->Fill(kCandidateStepMcDaughtersInAcceptance, mcParticle.pt(), multiplicityGen, mcParticle.originMcGen()); - registry.fill(HIST("hPtCandMcGenDaughterInAcc"), mcParticle.pt()); } } - } + } // end loop candidate gen // reconstructed candidate loop for (const auto& candidate : groupedCandidates) { @@ -617,30 +956,35 @@ struct HfTaskCorrelationDsHadrons { outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; } } - if (outputMl[0] < mlOutputPrompt->at(o2::analysis::findBin(binsPtD, candidate.pt())) || outputMl[2] > mlOutputBkg->at(o2::analysis::findBin(binsPtD, candidate.pt()))) { + 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)) { + if ((std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && (candidate.flagMcDecayChanRec() == channelsResonant[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 (std::abs(HfHelper::yDs(candidate)) <= yCandMax) { if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { - registry.fill(HIST("hPtCandMcRecPrompt"), candidate.pt()); + if (useHighDimHistoForEff) { + registry.fill(HIST("hPtCandMcRecPrompt"), candidate.pt(), collision.numContrib()); + } else { + registry.fill(HIST("hPtCandMcRecPrompt"), candidate.pt()); + } } if (candidate.originMcRec() == RecoDecay::OriginType::NonPrompt) { - registry.fill(HIST("hPtCandMcRecNonPrompt"), candidate.pt()); + if (useHighDimHistoForEff) { + registry.fill(HIST("hPtCandMcRecNonPrompt"), candidate.pt(), collision.numContrib()); + } else { + registry.fill(HIST("hPtCandMcRecNonPrompt"), candidate.pt()); + } } } } } - } - + } // end loop candidate reco } // end loop reconstructed collision - } // end loop generated collisions + } // end loop generated collisions } PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcCandEfficiency, "Process MC for calculating candidate reconstruction efficiency", false); @@ -650,19 +994,12 @@ struct HfTaskCorrelationDsHadrons { 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()); + if ((std::abs(mcParticle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && (mcParticle.flagMcDecayChanGen() == channelsResonant[decayChannel])) { 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()); } @@ -678,7 +1015,6 @@ struct HfTaskCorrelationDsHadrons { } } if (isDaughterInAcceptance) { - hCandidates->Fill(kCandidateStepMcDaughtersInAcceptance, mcParticle.pt(), multiplicity, mcParticle.originMcGen()); registry.fill(HIST("hPtCandMcGenDaughterInAcc"), mcParticle.pt()); } } @@ -699,21 +1035,18 @@ struct HfTaskCorrelationDsHadrons { outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; } } - if (outputMl[0] < mlOutputPrompt->at(o2::analysis::findBin(binsPtD, candidate.pt())) || outputMl[2] > mlOutputBkg->at(o2::analysis::findBin(binsPtD, candidate.pt()))) { + 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)) { + if ((std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && (candidate.flagMcDecayChanRec() == channelsResonant[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 (std::abs(HfHelper::yDs(candidate)) <= yCandMax) { if (candidate.originMcRec() == RecoDecay::OriginType::Prompt) { registry.fill(HIST("hPtCandMcRecPrompt"), candidate.pt()); } @@ -727,16 +1060,12 @@ struct HfTaskCorrelationDsHadrons { } PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcCandEfficiencyWoColl, "Process MC for calculating candidate reconstruction efficiency", false); - Preslice perCollision = o2::aod::track::collisionId; - Preslice perCollisionMc = o2::aod::mcparticle::mcCollisionId; - /// 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) { @@ -769,37 +1098,47 @@ struct HfTaskCorrelationDsHadrons { 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 (useHighDimHistoForEff) { + registry.fill(HIST("hPtParticleAssocMcGen"), mcParticle.pt(), mcParticle.eta(), collision.posZ(), collision.numContrib()); + if (std::abs(mcParticle.pdgCode()) == kPiPlus) { + registry.fill(HIST("hPtPrmPionMcGen"), mcParticle.pt(), mcParticle.eta(), collision.posZ(), collision.numContrib()); + } else if (std::abs(mcParticle.pdgCode()) == kKPlus) { + registry.fill(HIST("hPtPrmKaonMcGen"), mcParticle.pt(), mcParticle.eta(), collision.posZ(), collision.numContrib()); + } else if (std::abs(mcParticle.pdgCode()) == kProton) { + registry.fill(HIST("hPtPrmProtonMcGen"), mcParticle.pt(), mcParticle.eta(), collision.posZ(), collision.numContrib()); + } else if (std::abs(mcParticle.pdgCode()) == kElectron) { + registry.fill(HIST("hPtPrmElectronMcGen"), mcParticle.pt(), mcParticle.eta(), collision.posZ(), collision.numContrib()); + } else if (std::abs(mcParticle.pdgCode()) == kMuonMinus) { + registry.fill(HIST("hPtPrmMuonMcGen"), mcParticle.pt(), mcParticle.eta(), collision.posZ(), collision.numContrib()); + } + } else { + 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()); + } } - int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); - if (trackOrigin == 1) { // charm orgin - registry.fill(HIST("hPtPrmPromptPartMcGen"), mcParticle.pt()); - } else if (trackOrigin == 2) { // beauty origin - registry.fill(HIST("hPtPrmNonPromptPartMcGen"), mcParticle.pt()); + if (separateTrackOrigins) { + int const 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()); + } } } } @@ -808,34 +1147,51 @@ struct HfTaskCorrelationDsHadrons { // 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()); + if (useHighDimHistoForEff) { + registry.fill(HIST("hPtParticleAssocSpecieMcRec"), track.pt()); + if (std::abs(mcParticle.pdgCode()) == kPiPlus) { + registry.fill(HIST("hPtPrmPionMcRec"), track.pt(), track.eta(), collision.posZ(), collision.numContrib()); + } else if (std::abs(mcParticle.pdgCode()) == kKPlus) { + registry.fill(HIST("hPtPrmKaonMcRec"), track.pt(), track.eta(), collision.posZ(), collision.numContrib()); + } else if (std::abs(mcParticle.pdgCode()) == kProton) { + registry.fill(HIST("hPtPrmProtonMcRec"), track.pt(), track.eta(), collision.posZ(), collision.numContrib()); + } else if (std::abs(mcParticle.pdgCode()) == kElectron) { + registry.fill(HIST("hPtPrmElectronMcRec"), track.pt(), track.eta(), collision.posZ(), collision.numContrib()); + } else if (std::abs(mcParticle.pdgCode()) == kMuonMinus) { + registry.fill(HIST("hPtPrmMuonMcRec"), track.pt(), track.eta(), collision.posZ(), collision.numContrib()); + } + } else { + registry.fill(HIST("hPtParticleAssocSpecieMcRec"), track.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 - int trackOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, true); - if (trackOrigin == 1) { // charm orgin - registry.fill(HIST("hPtPrmPromptPartMcRec"), track.pt()); - } else if (trackOrigin == 2) { // beauty origin - registry.fill(HIST("hPtPrmNonPromptPartMcRec"), track.pt()); + if (separateTrackOrigins) { + int const 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()); + } } } } @@ -846,7 +1202,7 @@ struct HfTaskCorrelationDsHadrons { } } // end loop reconstructed collision - } // end loop generated collisions + } // end loop generated collisions } PROCESS_SWITCH(HfTaskCorrelationDsHadrons, processMcTrackEfficiency, "Process MC for calculating associated particle tracking efficiency", false); }; diff --git a/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx index 609f213ae3a..0b354abecee 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDstarHadrons.cxx @@ -14,16 +14,23 @@ /// \author Fabrizio Grosa , CERN /// \author Shyam Kumar -// Framework -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - -// PWGHF #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" #include "PWGHF/Utils/utilsAnalysis.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -41,28 +48,28 @@ const TString stringPoolBin = "Pool Bin Number;"; 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 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 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 auto vecSignalRegionRightBoundDefault = std::vector{signalRegionRightBoundDefault, signalRegionRightBoundDefault + nBinsPtCorrelation}; // const double sidebandLeftOuterDefault[nBinsPtCorrelation] = {1.7690, 1.7690, 1.7690, 1.7690, 1.7690, 1.7690, 1.7690, 1.7690}; -// auto vecSidebandLeftOuterDefault = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + nBinsPtCorrelation}; +// const auto vecSidebandLeftOuterDefault = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + nBinsPtCorrelation}; // const double sidebandLeftInnerDefault[nBinsPtCorrelation] = {1.8250, 1.8250, 1.8250, 1.8250, 1.8250, 1.8250, 1.8250, 1.8250}; -// auto vecSidebandLeftInnerDefault = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + nBinsPtCorrelation}; +// const auto vecSidebandLeftInnerDefault = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + 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 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}; +const auto vecSidebandRightOuterDefault = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + nBinsPtCorrelation}; -const int npTBinsEfficiency = o2::analysis::hf_cuts_dstar_to_d0_pi::nBinsPt; -std::vector vecEfficiencyDstarDefault(npTBinsEfficiency); // line # 76 in taskCorrelationDstarHadron.cxx; why (npTBinsEfficiency+1) ? +const int npTBinsEfficiency = o2::analysis::hf_cuts_dstar_to_d0_pi::NBinsPt; +const std::vector vecEfficiencyDstarDefault(npTBinsEfficiency); // line # 76 in taskCorrelationDstarHadron.cxx; why (npTBinsEfficiency+1) ? // Dstar-Hadron correlation pair struct HfTaskCorrelationDstarHadrons { @@ -90,11 +97,11 @@ struct HfTaskCorrelationDstarHadrons { { auto axisPtDstar = (std::vector)binsPtEfficiency; - AxisSpec axisSpecPtDstar = {axisPtDstar}; - AxisSpec axisSpecDeltaPhi = {nBinsDeltaPhi, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}; - AxisSpec axisSpecDeltaEta = {deltaEtaBinEdges}; - AxisSpec axisSpecPtHadron = {ptHadronBinsEdges}; - AxisSpec axisSpecPoolBin = {9, 0., 9.}; + AxisSpec const axisSpecPtDstar = {axisPtDstar}; + AxisSpec const axisSpecDeltaPhi = {nBinsDeltaPhi, -o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf}; + AxisSpec const axisSpecDeltaEta = {deltaEtaBinEdges}; + AxisSpec const axisSpecPtHadron = {ptHadronBinsEdges}; + AxisSpec const axisSpecPoolBin = {9, 0., 9.}; registry.add("hCorrel2DVsPtSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtD + stringPtHadron + stringPoolBin + "entries", {HistType::kTHnSparseD, {axisSpecDeltaPhi, axisSpecDeltaEta, axisSpecPtDstar, axisSpecPtHadron, axisSpecPoolBin}}, true); registry.add("hCorrel2DPtIntSignalRegion", stringDHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2D, {axisSpecDeltaPhi, axisSpecDeltaEta}}, true); @@ -109,16 +116,16 @@ struct HfTaskCorrelationDstarHadrons { void processData(aod::DstarHadronPair const& dstarHPairs) { for (const auto& dstarHPair : dstarHPairs) { - float deltaPhi = dstarHPair.deltaPhi(); - float deltaEta = dstarHPair.deltaEta(); - float ptDstar = dstarHPair.ptDstar(); - float ptTrack = dstarHPair.ptTrack(); - int poolBin = dstarHPair.poolBin(); - float deltaM = dstarHPair.deltaM(); - - int effBinPtDstar = o2::analysis::findBin(binsPtEfficiency, ptDstar); + float const deltaPhi = dstarHPair.deltaPhi(); + float const deltaEta = dstarHPair.deltaEta(); + float const ptDstar = dstarHPair.ptDstar(); + float const ptTrack = dstarHPair.ptTrack(); + int const poolBin = dstarHPair.poolBin(); + float const deltaM = dstarHPair.deltaM(); + + int const effBinPtDstar = o2::analysis::findBin(binsPtEfficiency, ptDstar); // LOG(info) << "efficiency index " << effBinPtDstar; - int corrBinPtDstar = o2::analysis::findBin(binsPtCorrelations, ptDstar); + int const corrBinPtDstar = o2::analysis::findBin(binsPtCorrelations, ptDstar); // LOG(info) << "correlation index " << corrBinPtDstar; // reject candidate if outside pT ranges of interst @@ -130,10 +137,10 @@ struct HfTaskCorrelationDstarHadrons { // ptTrack = 10.5; // } float netEfficiencyWeight = 1.0; - float efficiencyWeightTracks = 1.0; + float const efficiencyWeightTracks = 1.0; if (applyEfficiency) { - float efficiencyWeightDstar = efficiencyDstar->at(effBinPtDstar); + float const efficiencyWeightDstar = efficiencyDstar->at(effBinPtDstar); // LOG(info)<<"efficiencyWeightDstar "<, IIT Indore +/// \author Ravindra Singh , IIT Indore + +#include "PWGHF/HFC/DataModel/CorrelationTables.h" + +#include +#include +#include +#include +#include +#include +#include + +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"}; + + 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 binsPt{"binsPt", {50, 0.0, 50}, "#it{p_{T}}(GeV/#it{c})"}; + + HistogramRegistry registry{ + "registry", + {}}; + + void init(InitContext&) + { + AxisSpec axisDeltaEta = {binsDeltaEta, "#Delta #eta = #eta_{Electron}- #eta_{Hadron}"}; + AxisSpec axisDeltaPhi = {binsDeltaPhi, "#Delta #varphi = #varphi_{Electron}- #varphi_{Hadron}"}; + AxisSpec axisPt = {binsPt, "#it{p_{T}}(GeV/#it{c})"}; + + registry.add("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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hLikeSignEHCorrel", "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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hUnLikeSignEHCorrel", "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;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hMcGenInclusiveEHCorrel", "Sparse for Delta phi and Delta eta for McGen Inclusive Electron with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hMcGenNonHfEHCorrel", "Sparse for Delta phi and Delta eta for McGen NonHeavy flavour Electron pair with Hadron;p_{T}^{e} (GeV#it{/c});p_{T}^{h} (GeV#it{/c});#Delta#varphi;#Delta#eta;", {HistType::kTHnSparseF, {{axisPt}, {axisPt}, {axisDeltaPhi}, {axisDeltaEta}}}); + } + + // 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.nPairsLS() > 0) { + for (int i = 0; i < pairEntry.nPairsLS(); ++i) { + + registry.fill(HIST("hLikeSignEHCorrel"), ptElectron, ptHadron, deltaPhi, deltaEta); + } + } + if (pairEntry.nPairsUS() > 0) { + for (int i = 0; i < pairEntry.nPairsLS(); ++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() != 0) { + + 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..a2e69b2e144 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationLcHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationLcHadrons.cxx @@ -14,177 +14,546 @@ /// \author Marianna Mazzilli /// \author Zhen Zhang -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include // std::shared_ptr +#include +#include 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; const double pTBinsCorrelations[nPtBinsCorrelations + 1] = {0., 2., 4., 6., 8., 12., 16., 24., 99.}; -auto vecBinsPtCorrelations = std::vector{pTBinsCorrelations, pTBinsCorrelations + nPtBinsCorrelations + 1}; +const auto vecBinsPtCorrelations = std::vector{pTBinsCorrelations, pTBinsCorrelations + nPtBinsCorrelations + 1}; const double signalRegionInnerDefault[nPtBinsCorrelations] = {2.269, 2.269, 2.269, 2.269, 2.269, 2.269, 2.269, 2.269}; const double signalRegionOuterDefault[nPtBinsCorrelations] = {2.309, 2.309, 2.309, 2.309, 2.309, 2.309, 2.309, 2.309}; const double sidebandLeftOuterDefault[nPtBinsCorrelations] = {2.209, 2.209, 2.209, 2.209, 2.209, 2.209, 2.209, 2.209}; const double sidebandLeftInnerDefault[nPtBinsCorrelations] = {2.249, 2.249, 2.249, 2.249, 2.249, 2.249, 2.249, 2.249}; const double sidebandRightInnerDefault[nPtBinsCorrelations] = {2.329, 2.329, 2.329, 2.329, 2.329, 2.329, 2.329, 2.329}; const double sidebandRightOuterDefault[nPtBinsCorrelations] = {2.369, 2.369, 2.369, 2.369, 2.369, 2.369, 2.369, 2.369}; -auto vecSignalRegionInner = std::vector{signalRegionInnerDefault, signalRegionInnerDefault + nPtBinsCorrelations}; -auto vecSignalRegionOuter = std::vector{signalRegionOuterDefault, signalRegionOuterDefault + nPtBinsCorrelations}; -auto vecSidebandLeftInner = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + nPtBinsCorrelations}; -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}; +const auto vecSignalRegionInner = std::vector{signalRegionInnerDefault, signalRegionInnerDefault + nPtBinsCorrelations}; +const auto vecSignalRegionOuter = std::vector{signalRegionOuterDefault, signalRegionOuterDefault + nPtBinsCorrelations}; +const auto vecSidebandLeftInner = std::vector{sidebandLeftInnerDefault, sidebandLeftInnerDefault + nPtBinsCorrelations}; +const auto vecSidebandLeftOuter = std::vector{sidebandLeftOuterDefault, sidebandLeftOuterDefault + nPtBinsCorrelations}; +const auto vecSidebandRightInner = std::vector{sidebandRightInnerDefault, sidebandRightInnerDefault + nPtBinsCorrelations}; +const auto vecSidebandRightOuter = std::vector{sidebandRightOuterDefault, sidebandRightOuterDefault + nPtBinsCorrelations}; /// 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 storeMass{"storeMass", 1, "Flag for storing mass information"}; 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"}; - // signal and sideband region edges, to be defined via json file (initialised to empty) + 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"}; 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> 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"}; + Configurable useCentrality{"useCentrality", false, "Flag for centrality dependent analyses"}; + // 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; + + 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"}; + ConfigurableAxis binsCentFt0m{"binsCentFt0m", {100, 0., 100.}, "Centrality percentile (FT0M)"}; + + 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 const 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 const axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec axisCorrelationState = {2, 0., 2., ""}; + AxisSpec axisSignPair = {4, 1., 5.}; + AxisSpec axisCentFT0M = {binsCentFt0m, "Centrality percentile (FT0M)"}; + + // Histograms for data analysis + registry.add("hBdtScorePrompt", "Lc BDT prompt score", {HistType::kTH1D, {axisBdtScore}}); + registry.add("hBdtScoreBkg", "Lc BDT bkg score", {HistType::kTH1D, {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::kTH1D, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1D, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hDeltaEtaPtIntSidebands", stringLcHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1D, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebands", stringLcHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1D, {axisDeltaPhi}}); + registry.add("hCorrel2DPtIntSidebands", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hCorrel2DVsPtSidebands", stringLcHadron + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}, {axisCentFT0M}}}); + registry.add("hDeltaEtaPtIntSidebandLeft", stringLcHadron + "Left" + stringSideband + stringDeltaEta, {HistType::kTH1D, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandLeft", stringLcHadron + "Left" + stringSideband + stringDeltaPhi, {HistType::kTH1D, {axisDeltaPhi}}); + registry.add("hDeltaEtaPtIntSidebandRight", stringLcHadron + "Right" + stringSideband + stringDeltaEta, {HistType::kTH1D, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandRight", stringLcHadron + "Right" + stringSideband + stringDeltaPhi, {HistType::kTH1D, {axisDeltaPhi}}); + + if (!fillSign) { + registry.add("hCorrel2DVsPtSidebandLeft", stringLcHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}, {axisCentFT0M}}}); + registry.add("hCorrel2DVsPtSidebandRight", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtLc}, {axisPtHadron}, {axisPoolBin}, {axisCentFT0M}}}); + registry.add("hCorrel2DVsPtSignalRegion", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}, {axisCentFT0M}}}); + registry.add("hCorrel2DVsPtGlobalRegion", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTHnSparseF, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtCorr}, {axisPtHadron}, {axisPoolBin}, {axisMassLc}}}); + registry.get(HIST("hCorrel2DVsPtSidebandLeft"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSidebandRight"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtGlobalRegion"))->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::kTH1D, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + "entries", {HistType::kTH1D, {axisDeltaPhi}}); + registry.add("hDeltaEtaPtIntSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaEta + "entries", {HistType::kTH1D, {axisDeltaEta}}); + registry.add("hCorrel2DPtIntSignalRegionMcRec", stringLcHadron + stringSignal + stringDeltaPhi + stringDeltaEta + "entries", {HistType::kTH2F, {{axisDeltaPhi}, {axisDeltaEta}}}); + registry.add("hDeltaPhiPtIntSidebandsMcRec", stringLcHadron + stringSideband + stringDeltaPhi + "entries", {HistType::kTH1D, {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::kTH1D, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandLeftMcRec", stringLcHadron + "Left" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTH1D, {axisDeltaPhi}}); + registry.add("hDeltaEtaPtIntSidebandRightMcRec", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTH1D, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntSidebandRightMcRec", stringLcHadron + "Right" + stringSideband + stringDeltaPhi + stringDeltaEta + stringPtLc + stringPtHadron + "entries", {HistType::kTH1D, {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::kTH1D, {axisDeltaEta}}); + registry.add("hDeltaPhiPtIntMcGen", stringMcParticles + stringDeltaPhi + "entries", {HistType::kTH1D, {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::kTH1D, {axisPtLc}}); + registry.add("Efficiency/hPtCandMcGenPrompt", stringMcGenLcPrompt + stringPtLc, {HistType::kTH1D, {axisPtLc}}); + registry.add("Efficiency/hPtCandMcRecNonPrompt", stringMcRecoLcFd + stringPtLc, {HistType::kTH1D, {axisPtLc}}); + registry.add("Efficiency/hPtCandMcGenNonPrompt", stringMcGenLcFd + stringPtLc, {HistType::kTH1D, {axisPtLc}}); + registry.add("Efficiency/hPtCandMcGenDaughterInAcc", stringMcGenLcFd + stringPtLc, {HistType::kTH1D, {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 != 0) && 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 const massLc = candidate.mLc(); + float const ptLc = std::abs(candidate.ptLc()); + float const bdtScorePrompt = candidate.mlScorePrompt(); + float const bdtScoreBkg = candidate.mlScoreBkg(); + int const 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 != 0) { + 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(); - double massLc = pairEntry.mLc(); - int effBinLc = o2::analysis::findBin(binsPtEfficiency, ptLc); - int ptBinLc = o2::analysis::findBin(binsPtCorrelations, ptLc); - int poolBin = pairEntry.poolBin(); + float const deltaPhi = pairEntry.deltaPhi(); + float cent = 0.; + if (useCentrality) { + cent = pairEntry.cent(); + } + float const deltaEta = pairEntry.deltaEta(); + double const ptLc = std::abs(pairEntry.ptLc()); + double const ptHadron = std::abs(pairEntry.ptHadron()); + float const bdtScorePrompt = pairEntry.mlScorePrompt(); + float const bdtScoreBkg = pairEntry.mlScoreBkg(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int const poolBin = pairEntry.poolBin(); + double const massLc = pairEntry.mLc(); + int const effBinLc = o2::analysis::findBin(binsPtEfficiencyLc, ptLc); + int const ptBinLc = o2::analysis::findBin(binsPtCorrelations, ptLc); + bool const 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); + if (applyEfficiency != 0) { + 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 const 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 (storeMass) { + registry.fill(HIST("hCorrel2DVsPtGlobalRegion"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, massLc, efficiencyWeight); + continue; + } 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, cent, 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 - registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, efficiencyWeight); + // 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, cent, efficiencyWeight); + } + registry.fill(HIST("hDeltaEtaPtIntSidebandLeft"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandLeft"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, cent, 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, cent, efficiencyWeight); + } + registry.fill(HIST("hDeltaEtaPtIntSidebandRight"), deltaEta, efficiencyWeight); + registry.fill(HIST("hDeltaPhiPtIntSidebandRight"), deltaPhi, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtSidebands"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, cent, efficiencyWeight); registry.fill(HIST("hCorrel2DPtIntSidebands"), deltaPhi, deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaEtaPtIntSidebands"), deltaEta, efficiencyWeight); registry.fill(HIST("hDeltaPhiPtIntSidebands"), deltaPhi, efficiencyWeight); @@ -194,49 +563,194 @@ 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 const massLc = candidate.mLc(); + float const ptLc = std::abs(candidate.ptLc()); + float const bdtScorePrompt = candidate.mlScorePrompt(); + float const bdtScoreBkg = candidate.mlScoreBkg(); + int const effBinLc = o2::analysis::findBin(binsPtEfficiencyLc, ptLc); + bool const 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 != 0) { + 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); - int poolBin = pairEntry.poolBin(); - if (ptBinLc < 0 || effBinLc < 0) { + float const deltaPhi = pairEntry.deltaPhi(); + float const deltaEta = pairEntry.deltaEta(); + float const ptLc = std::abs(pairEntry.ptLc()); + float const ptHadron = std::abs(pairEntry.ptHadron()); + float const massLc = pairEntry.mLc(); + float const bdtScorePrompt = pairEntry.mlScorePrompt(); + float const bdtScoreBkg = pairEntry.mlScoreBkg(); + bool const isPhysicalPrimary = pairEntry.isPhysicalPrimary(); + float const trackDcaXY = pairEntry.trackDcaXY(); + float const trackDcaZ = pairEntry.trackDcaZ(); + int const trackTpcCrossedRows = pairEntry.trackTPCNClsCrossedRows(); + int const statusLcPrompt = static_cast(pairEntry.isPrompt()); + int const statusPromptHadron = pairEntry.trackOrigin(); + int const poolBin = pairEntry.poolBin(); + int const effBinLc = o2::analysis::findBin(binsPtEfficiencyLc, ptLc); + int const ptBinLc = o2::analysis::findBin(binsPtCorrelations, ptLc); + bool const 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 != 0) { + if (statusLcPrompt != 0) { + 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 const 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 (applyEfficiency) { - efficiencyWeight = 1. / (efficiencyLc->at(effBinLc) * efficiencyHadron); + + 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 (pairEntry.signalStatus() != 0) { + 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 == RecoDecay::OriginType::Prompt) { + 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 == RecoDecay::OriginType::NonPrompt) { + 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 +761,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(); - int poolBin = pairEntry.poolBin(); - // reject entries outside Pt ranges of interest - if (o2::analysis::findBin(binsPtCorrelations, ptLc) < 0) { - continue; + float const deltaPhi = pairEntry.deltaPhi(); + float const deltaEta = pairEntry.deltaEta(); + float const ptLc = std::abs(pairEntry.ptLc()); + float const ptHadron = std::abs(pairEntry.ptHadron()); + int const poolBin = pairEntry.poolBin(); + int const statusPromptHadron = pairEntry.trackOrigin(); + bool const isLcPrompt = pairEntry.isPrompt(); + bool const isAutoCorrelated = pairEntry.isAutoCorrelated(); + int signPair = 0; + + if (isTowardTransverseAway) { + // Divide into three regions: toward, transverse, and away + if (ptHadron < leadingParticlePtMin) { + continue; + } + Region const 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 == RecoDecay::OriginType::Prompt) { + 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 == RecoDecay::OriginType::NonPrompt) { + 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()) == hf_decay::hf_cand_3prong::DecayChannelMain::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()) == hf_decay::hf_cand_3prong::DecayChannelMain::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 5f6a5b2a95a..d54bfda6956 100644 --- a/PWGHF/HFC/Tasks/taskFlow.cxx +++ b/PWGHF/HFC/Tasks/taskFlow.cxx @@ -10,580 +10,2799 @@ // 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 "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPObject.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/StepTHn.h" -#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsPid.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "CommonConstants/MathConstants.h" -#include "PWGCF/Core/CorrelationContainer.h" -#include "PWGCF/Core/PairCuts.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; +using namespace o2::aod::pid_tpc_tof_utils; +using namespace o2::aod::track; using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; +enum CorrelationCase { + TpcTpc, + TpcMft, + TpcFv0a, + MftFv0a, + TpcFt0a, + MftFt0a, + TpcFt0c, + Ft0aFt0c +}; + +enum CorrelatedParticles { + ChPartChPart, + D0ChPart, + LcChPart +}; + +enum DataType { + Data, + Mc +}; + +enum ReassociationMftTracks { + NotReassociatedMftTracks = 0, + ReassociatedMftTracks, + NReassociationMftTracksSteps +}; + +enum EventSelectionStep { + AllEvents = 0, + AfterEventSelection, + NEventSelectionSteps +}; + +enum FITIndex { + isFT0A = 0, + isFT0C = 1, + isFV0A = 2 +}; + +enum MftTrackAmbiguityStep { + AllMftTracks = 0, + AfterTrackSelection, + NumberOfAmbiguousTracks, + NumberOfNonAmbiguousTracks, + NMftAmbiguitySteps +}; + +enum MftTrackSelectionStep { + NoSelection = 0, + Eta, + Cluster, + Pt, + NMftTrackSelectionSteps +}; + +enum MultiplicityEstimators { + MultNTracksPV = 0, + MultNumContrib, + MultFT0C, + MultFT0M +}; + +enum TrackSelection { + TrackSelectionNoCut = 0, + TrackSelectionGlobalTrack +}; + +// static constexpr std::string_view whatEventType[] = {"SameEvent/", "MixedEvent/"}; +static constexpr std::string_view WhatDataType[] = {"Data/", "MC/"}; +static constexpr std::string_view WhatCorrelationCase[] = {"TpcTpc/", "TpcMft/", "TpcFv0a/", "MftFv0a/", "TpcFt0a/", "MftFt0a/", "TpcFt0c/", "Ft0aFt0c/"}; +static constexpr std::string_view WhatParticles[] = {"ChPartChPart/", "D0ChPart/", "LcChPart/"}; +static constexpr std::string_view WhatMultiplicityEstimator[] = {"multNTracksPV", "multNumContrib", "multFT0C", "multFT0M"}; +auto static constexpr MinFt0cCell = 96; + +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; + +static constexpr float PairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; + struct HfTaskFlow { + + struct : ConfigurableGroup { + std::string prefix = "ConfigCcdb_group"; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + Configurable noLaterThan{"noLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; + } configCcdb; + // configurables for processing options - 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"}; + + struct : ConfigurableGroup { + std::string prefix = "ConfigTask_group"; + Configurable centralityBinsForMc{"centralityBinsForMc", false, "falsce = OFF, true = ON for data like multiplicity/centrality bins for MC steps"}; + Configurable doHeavyFlavor{"doHeavyFlavor", false, "Flag to know we in the heavy flavor case or not"}; + Configurable doReferenceFlow{"doReferenceFlow", false, "Flag to know if reference flow should be done"}; + Configurable isReadoutCenter{"isReadoutCenter", false, "Enable Readout Center"}; + Configurable nMixedEvents{"nMixedEvents", 5, "Number of mixed events per event"}; + } configTask; + + // configurables for collisions + struct : ConfigurableGroup { + std::string prefix = "ConfigCollision_group"; + Configurable isApplyGoodItsLayersAll{"isApplyGoodItsLayersAll", false, "Enable GoodITSLayersAll"}; + Configurable isApplyGoodZvtxFT0vsPV{"isApplyGoodZvtxFT0vsPV", false, "Enable GoodZvtxFT0vsPV cut"}; + Configurable isApplySameBunchPileup{"isApplySameBunchPileup", false, "Enable SameBunchPileup cut"}; + Configurable maxMultiplicity{"maxMultiplicity", 300, "maximum multiplicity selection for collision"}; + Configurable minMultiplicity{"minMultiplicity", 0, "minimum multiplicity selection for collision"}; + Configurable multiplicityEstimator{"multiplicityEstimator", 0, "0: multNTracksPV, 1: numContrib, 2: multFT0C, 3: multFT0M, 4: centFT0C, 5: centFT0CVariants1s, 6: centFT0M, 7: centFV0A, 8: centNTracksPV, 9: centNGlobal, 10: centMFT"}; + Configurable isApplyNoCollInTimeRangeStrict{"isApplyNoCollInTimeRangeStrict", false, ""}; + Configurable zVertexMax{"zVertexMax", 10.0f, "Accepted z-vertex range"}; + } configCollision; + + // configurables for central barrel tracks + struct : ConfigurableGroup { + std::string prefix = "ConfigCentral_group"; + Configurable dcaZCentralTrackMax{"dcaZCentralTrackMax", 0.2f, "max dcaZ of central tracks"}; + Configurable etaCentralTrackMax{"etaCentralTrackMax", 0.8f, "max. eta of central tracks"}; + Configurable isApplyConversionCut{"isApplyConversionCut", false, "apply pair conversion cuts"}; + Configurable isApplyTwoTrackCut{"isApplyTwoTrackCut", false, "apply two track cut"}; + Configurable isApplyIndexOrdering{"isApplyIndexOrdering", false, "apply track1.index() <= track2.index() cut"}; + Configurable isApplyPtOrderingSameEvent{"isApplyPtOrderingSameEvent", false, "apply track1.pt() <= track2.pt() cut"}; + Configurable isApplyPtOrderingMixedEvent{"isApplyPtOrderingMixedEvent", false, "apply track1.pt() <= track2.pt() cut"}; + Configurable isApplySameTrackCut{"isApplySameTrackCut", false, "apply track1 == track2 cut"}; + Configurable maxChi2ItsClusters{"maxChi2ItsClusters", 36.f, "max chi2 per ITS clusters"}; + Configurable maxChi2TpcClusters{"maxChi2TpcClusters", 2.5f, "max chi2 per TPC clusters"}; + Configurable maxMergingRadius{"maxMergingRadius", 2.5, "max radius for merging cut"}; + Configurable mergingCut{"mergingCut", 0.02, "merging cut on track merge"}; + Configurable minItsClusters{"minItsClusters", 5.0f, "cut for minimum ITS clusters"}; + Configurable minMergingRadius{"minMergingRadius", 0.8, "max radius for merging cut"}; + Configurable minTpcClusters{"minTpcClusters", 50.0f, "cut for minimum TPC clusters"}; + Configurable minTpcCrossedRows{"minTpcCrossedRows", 70.0f, "cut for minimum TOC crossed rows"}; + Configurable> pairCut{"pairCut", {PairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"}; + Configurable ptCentralTrackMin{"ptCentralTrackMin", 0.2f, "min. pT of central tracks"}; + Configurable ptCentralTrackMax{"ptCentralTrackMax", 10.0f, "max. pT of central tracks"}; + Configurable trackSelectionType{"trackSelectionType", 1, "Track selection: 0 -> kGlobalTrack or isGlobalTrackSDD , 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> No globalTrack selection"}; + } configCentral; + // configurables for HF candidates - Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; - Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; - Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; - Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; + struct : ConfigurableGroup { + std::string prefix = "ConfigCandidates_group"; + Configurable etaCandidateMax{"etaCandidateMax", 0.8f, "max. eta of HF candidate"}; + Configurable> mcTriggerPdgs{"mcTriggerPdgs", {421, -421}, "MC PDG codes to use exclusively as trigger particles. D0= +-421, Lc = +-4122"}; + Configurable selectionFlagHf{"selectionFlagHf", 1, "Selection Flag for Hf candidates"}; + Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; + Configurable yCandRecoMax{"yCandRecoMax", 0.8, "max. cand. rapidity"}; + } configCandidates; + + // configurables for MFT tracks + struct : ConfigurableGroup { + std::string prefix = "ConfigMft_group"; + Configurable cutBestCollisionId{"cutBestCollisionId", 0, "cut on the best collision Id used in a filter"}; + Configurable etaMftTrackMax{"etaMftTrackMax", -2.4f, "Maximum value for the eta of MFT tracks when used in cut function"}; + Configurable etaMftTrackMin{"etaMftTrackMin", -3.36f, "Minimum value for the eta of MFT tracks when used in cut function"}; + Configurable etaMftTrackMaxFilter{"etaMftTrackMaxFilter", -2.0f, "Maximum value for the eta of MFT tracks when used in filter"}; + Configurable etaMftTrackMinFilter{"etaMftTrackMinFilter", -3.9f, "Minimum value for the eta of MFT tracks when used in filter"}; + Configurable mftMaxDCAxy{"mftMaxDCAxy", 2.0f, "Cut on dcaXY for MFT tracks"}; + Configurable mftMaxDCAz{"mftMaxDCAz", 2.0f, "Cut on dcaZ for MFT tracks"}; + Configurable nClustersMftTrack{"nClustersMftTrack", 5, "Minimum number of clusters for the reconstruction of MFT tracks"}; + Configurable ptMftTrackMax{"ptMftTrackMax", 10.0f, "max value of MFT tracks pT when used in cut function"}; + Configurable ptMftTrackMin{"ptMftTrackMin", 0.f, "min value of MFT tracks pT when used in cut function"}; + Configurable useMftPtCut{"useMftPtCut", false, "if true, use the Mft pt function cut"}; + } configMft; + + TF1* fPtDepDCAxy = nullptr; - HfHelper hfHelper; SliceCache cache; + Service pdg; + Service ccdb; + std::vector* offsetFT0{}; + std::vector* offsetFV0{}; + o2::ccdb::CcdbApi ccdbApi; + o2::ft0::Geometry ft0Det; + o2::fv0::Geometry* fv0Det{}; + + // ========================= + // using declarations : DATA + // ========================= using FilteredCollisionsWSelMult = soa::Filtered>; - using TracksWDcaSel = soa::Filtered>; - using HfCandidatesSel = soa::Filtered>; + using HfCandidatesSelD0 = soa::Filtered>; + using HfCandidatesSelLc = soa::Filtered>; + using FilteredTracksWDcaSel = soa::Filtered>; + + using FilteredMftTracks = soa::Filtered; + + // ========================= + // Filters & partitions : DATA + // ========================= - // 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) && - 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; + Filter candidateFilterD0 = (aod::hf_sel_candidate_d0::isSelD0 >= configCandidates.selectionFlagHf) || + (aod::hf_sel_candidate_d0::isSelD0bar >= configCandidates.selectionFlagHf); + + Filter candidateFilterLc = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= configCandidates.selectionFlagHf) || + (aod::hf_sel_candidate_lc::isSelLcToPiKP >= configCandidates.selectionFlagHf); + + // Collision filters + Filter collisionVtxZFilter = nabs(aod::collision::posZ) < configCollision.zVertexMax; + + // Central tracks filter + Filter trackFilter = (nabs(aod::track::eta) < configCentral.etaCentralTrackMax) && + (aod::track::pt > configCentral.ptCentralTrackMin) && + (aod::track::pt < configCentral.ptCentralTrackMax) && + requireGlobalTrackInFilter(); + + Filter centralTrackItsTpcMatchingFilter = ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC), ncheckbit(aod::track::trackCutFlag, TrackSelectionTpc), true) && + ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) && + ncheckbit(aod::track::trackCutFlag, TrackSelectionIts); + + Filter centralTrackDcaFilter = (ifnode(configCentral.dcaZCentralTrackMax.node() > 0.f, nabs(aod::track::dcaZ) <= configCentral.dcaZCentralTrackMax && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly), ncheckbit(aod::track::trackCutFlag, TrackSelectionDca))); + + Filter centralTrackChi2TpcClusterFilter = (aod::track::tpcChi2NCl < configCentral.maxChi2TpcClusters); + + Filter centralTrackChi2ItsClusterFilter = (aod::track::itsChi2NCl < configCentral.maxChi2ItsClusters); + + Filter mftTrackEtaFilter = ((aod::fwdtrack::eta < configMft.etaMftTrackMaxFilter) && (aod::fwdtrack::eta > configMft.etaMftTrackMinFilter)); - Preslice perCol = aod::track::collisionId; + // Filters below will be used for uncertainties + Filter mftTrackCollisionIdFilter = (aod::fwdtrack::bestCollisionId >= 0); + Filter mftTrackDcaXYFilter = (nabs(aod::fwdtrack::bestDCAXY) < configMft.mftMaxDCAxy); + // Filter mftTrackDcaZFilter = (nabs(aod::fwdtrack::bestDCAZ) < configMft.mftMaxDCAz); + + // ========================= + // Preslice : DATA + // ========================= + + Preslice perColD0s = aod::track::collisionId; + Preslice perColLcs = aod::track::collisionId; + Preslice perColMftTracks = o2::aod::fwdtrack::collisionId; + Preslice perColTracks = 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 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"}; - 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"}; // 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", {2, 1.7, 2.0}, "axis of invariant mass of HF candidates"}; + + struct : ConfigurableGroup { + std::string prefix = "ConfigAxis_group"; + ConfigurableAxis axisMass{"axisMass", {1, 1.5848, 2.1848}, "axis of invariant mass of candidates"}; + ConfigurableAxis binsMixingMultiplicity{"binsMixingMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}, "multiplicity bins for event mixing"}; + ConfigurableAxis binsMixingVertex{"binsMixingVertex", {20, -10, 10}, "vertex bins for event mixing"}; + ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {1, -1.0, 1.0}, "eta axis for efficiency histograms"}; + ConfigurableAxis axisEtaAssociated{"axisEtaAssociated", {48, -4, -2}, "eta axis for MFT histograms"}; + ConfigurableAxis axisEtaTrigger{"axisEtaTrigger", {48, -1, 1}, "eta axis for TPC 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 axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}, "multiplicity axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {72, 0, TwoPI}, "phi axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {72, 0, 36}, "pt axis for histograms"}; + ConfigurableAxis axisPtAssoc{"axisPtAssoc", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt associated axis for histograms"}; + ConfigurableAxis axisPtEfficiency{"axisPtEfficiency", {VARIABLE_WIDTH, 0.2, 10}, "pt axis for efficiency histograms"}; + ConfigurableAxis axisPtTrigger{"axisPtTrigger", {VARIABLE_WIDTH, 0.2, 0.5, 1, 1.5, 2, 3, 4, 6, 10}, "pt trigger axis for histograms"}; + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisVertexEfficiency{"axisVertexEfficiency", {1, -10, 10}, "vertex axis for efficiency histograms"}; + } configAxis; HistogramRegistry registry{"registry"}; + PairCuts mPairCuts; + + // Correlation containers used for data + OutputObj sameEvent{"sameEvent"}; + OutputObj mixedEvent{"mixedEvent"}; + OutputObj sameEventHf{"sameEventHf"}; + OutputObj mixedEventHf{"mixedEventHf"}; + + // Correlation containers used for Monte-Carlo + OutputObj sameEventHfMc{"sameEventHfMc"}; + OutputObj mixedEventHfMc{"mixedEventHfMc"}; + + template + void addHistograms() + { + registry.add(Form("%s%s%shEtaTrigger", WhatDataType[DataType].data(), WhatCorrelationCase[CorrelationCase].data(), WhatParticles[CorrelatedParticles].data()), "", {HistType::kTH1D, {configAxis.axisEtaTrigger}}); + registry.add(Form("%s%s%shPhiTrigger", WhatDataType[DataType].data(), WhatCorrelationCase[CorrelationCase].data(), WhatParticles[CorrelatedParticles].data()), "", {HistType::kTH1D, {configAxis.axisPhi}}); + registry.add(Form("%s%s%shPtTrigger", WhatDataType[DataType].data(), WhatCorrelationCase[CorrelationCase].data(), WhatParticles[CorrelatedParticles].data()), "", {HistType::kTH1D, {configAxis.axisPt}}); + registry.add(Form("%s%s%shYieldsTrigger", WhatDataType[DataType].data(), WhatCorrelationCase[CorrelationCase].data(), WhatParticles[CorrelatedParticles].data()), "", {HistType::kTH3F, {configAxis.axisMultiplicity, configAxis.axisPt, configAxis.axisEtaTrigger}}); + registry.add(Form("%s%s%shEtaPhiTrigger", WhatDataType[DataType].data(), WhatCorrelationCase[CorrelationCase].data(), WhatParticles[CorrelatedParticles].data()), "", {HistType::kTH3F, {configAxis.axisMultiplicity, configAxis.axisEtaTrigger, configAxis.axisPhi}}); + registry.add(Form("%s%s%shEtaAssociated", WhatDataType[DataType].data(), WhatCorrelationCase[CorrelationCase].data(), WhatParticles[CorrelatedParticles].data()), "", {HistType::kTH1D, {configAxis.axisEtaAssociated}}); + registry.add(Form("%s%s%shPhiAssociated", WhatDataType[DataType].data(), WhatCorrelationCase[CorrelationCase].data(), WhatParticles[CorrelatedParticles].data()), "", {HistType::kTH1D, {configAxis.axisPhi}}); + registry.add(Form("%s%s%shEtaPhiAssociated", WhatDataType[DataType].data(), WhatCorrelationCase[CorrelationCase].data(), WhatParticles[CorrelatedParticles].data()), "", {HistType::kTH3F, {configAxis.axisMultiplicity, configAxis.axisEtaAssociated, configAxis.axisPhi}}); + } + + void addMftHistograms() + { + registry.add("Data/Mft/hAmbiguityOfMftTracks", "hAmbiguityOfMftTracks", {HistType::kTH1D, {{MftTrackAmbiguityStep::NMftAmbiguitySteps, -0.5, +MftTrackAmbiguityStep::NMftAmbiguitySteps - 0.5}}}); + std::string labelsAmbiguityOfMftTracks[MftTrackAmbiguityStep::NMftAmbiguitySteps]; + labelsAmbiguityOfMftTracks[MftTrackAmbiguityStep::AllMftTracks] = "all MFT tracks"; + labelsAmbiguityOfMftTracks[MftTrackAmbiguityStep::AfterTrackSelection] = "MFT tracks after selection"; + labelsAmbiguityOfMftTracks[MftTrackAmbiguityStep::NumberOfAmbiguousTracks] = "how much tracks are ambigous"; + labelsAmbiguityOfMftTracks[MftTrackAmbiguityStep::NumberOfNonAmbiguousTracks] = "how much tracks are non-ambiguous"; + registry.get(HIST("Data/Mft/hAmbiguityOfMftTracks"))->SetMinimum(0); + + for (int iBin = 0; iBin < MftTrackAmbiguityStep::NMftAmbiguitySteps; iBin++) { + registry.get(HIST("Data/Mft/hAmbiguityOfMftTracks"))->GetXaxis()->SetBinLabel(iBin + 1, labelsAmbiguityOfMftTracks[iBin].data()); + } + + registry.add("Data/Mft/hMftTracksSelection", "hMftTracksSelection", {HistType::kTH1D, {{MftTrackSelectionStep::NMftTrackSelectionSteps, -0.5, +MftTrackSelectionStep::NMftTrackSelectionSteps - 0.5}}}); + std::string labelsMftTracksSelection[MftTrackSelectionStep::NMftTrackSelectionSteps]; + labelsMftTracksSelection[MftTrackSelectionStep::NoSelection] = "all MFT tracks"; + labelsMftTracksSelection[MftTrackSelectionStep::Eta] = "MFT tracks after eta selection"; + labelsMftTracksSelection[MftTrackSelectionStep::Cluster] = "MFT tracks after clusters selection"; + labelsMftTracksSelection[MftTrackSelectionStep::Pt] = "MFT tracks after pT selection"; + registry.get(HIST("Data/Mft/hMftTracksSelection"))->SetMinimum(0); + + for (int iBin = 0; iBin < MftTrackSelectionStep::NMftTrackSelectionSteps; iBin++) { + registry.get(HIST("Data/Mft/hMftTracksSelection"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMftTracksSelection[iBin].data()); + } + + registry.add("Data/Mft/hReassociationMftTracks", "hReassociationMftTracks", {HistType::kTH1D, {{ReassociationMftTracks::NReassociationMftTracksSteps, -0.5, +ReassociationMftTracks::NReassociationMftTracksSteps - 0.5}}}); + std::string labelsReassociationMftTracks[ReassociationMftTracks::NReassociationMftTracksSteps]; + labelsReassociationMftTracks[ReassociationMftTracks::NotReassociatedMftTracks] = "Ambiguous MFT tracks after track selection"; + labelsReassociationMftTracks[ReassociationMftTracks::ReassociatedMftTracks] = "Reassociated MFT tracks by DCAxy method"; + registry.get(HIST("Data/Mft/hReassociationMftTracks"))->SetMinimum(0); + + for (int iBin = 0; iBin < ReassociationMftTracks::NReassociationMftTracksSteps; iBin++) { + registry.get(HIST("Data/Mft/hReassociationMftTracks"))->GetXaxis()->SetBinLabel(iBin + 1, labelsReassociationMftTracks[iBin].data()); + } - OutputObj sameTPCTPCChCh{"sameTPCTPCChCh"}; - OutputObj mixedTPCTPCChCh{"mixedTPCTPCChCh"}; - OutputObj sameTPCTPCHfCh{"sameTPCTPCHfCh"}; - OutputObj mixedTPCTPCHfCh{"mixedTPCTPCHfCh"}; - OutputObj sameTPCMFTChCh{"sameTPCMFTChCh"}; - OutputObj mixedTPCMFTChCh{"mixedTPCMFTChCh"}; + registry.add("Data/Mft/hPtMft", "", {HistType::kTH1D, {configAxis.axisPt}}); + registry.add("Data/Mft/hNMftTracks", "", {HistType::kTH1F, {configAxis.axisMultiplicity}}); + registry.add("Data/Mft/hNBestCollisionFwd", "", {HistType::kTH1F, {configAxis.axisMultiplicity}}); + } // ========================= // init() // ========================= void init(InitContext&) { - // EVENT HISTOGRAMS - constexpr int kNBinsEvents = 3; - 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"; - for (int iBin = 0; iBin < kNBinsEvents; iBin++) { + ccdb->setURL(configCcdb.ccdbUrl); + 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()); + LOGF(info, "Getting alignment offsets from the CCDB..."); + offsetFT0 = ccdb->getForTimeStamp>("FT0/Calib/Align", configCcdb.noLaterThan.value); + offsetFV0 = ccdb->getForTimeStamp>("FV0/Calib/Align", configCcdb.noLaterThan.value); + LOGF(info, "Offset for FT0A: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[0].getX(), (*offsetFT0)[0].getY(), (*offsetFT0)[0].getZ()); + LOGF(info, "Offset for FT0C: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[1].getX(), (*offsetFT0)[1].getY(), (*offsetFT0)[1].getZ()); + LOGF(info, "Offset for FV0-left: x = %.3f y = %.3f z = %.3f\n", (*offsetFV0)[0].getX(), (*offsetFV0)[0].getY(), (*offsetFV0)[0].getZ()); + LOGF(info, "Offset for FV0-right: x = %.3f y = %.3f z = %.3f\n", (*offsetFV0)[1].getX(), (*offsetFV0)[1].getY(), (*offsetFV0)[1].getZ()); + + fv0Det = o2::fv0::Geometry::instance(o2::fv0::Geometry::eUninitialized); + + // ========================= + // Event histograms + // ========================= + + registry.add("Data/hVtxZ", "v_{z} (cm)", {HistType::kTH1D, {configAxis.axisVertex}}); + registry.add("Data/hNTracks", "", {HistType::kTH1F, {configAxis.axisMultiplicity}}); + registry.add(Form("Data/hMultiplicity_%s", WhatMultiplicityEstimator[configCollision.multiplicityEstimator].data()), "", {HistType::kTH1D, {configAxis.axisMultiplicity}}); + + registry.add("Data/hEventCounter", "hEventCounter", {HistType::kTH1D, {{EventSelectionStep::NEventSelectionSteps, -0.5, +EventSelectionStep::NEventSelectionSteps - 0.5}}}); + std::string labels[EventSelectionStep::NEventSelectionSteps]; + labels[EventSelectionStep::AllEvents] = "all"; + labels[EventSelectionStep::AfterEventSelection] = "after Physics selection"; + registry.get(HIST("Data/hEventCounter"))->SetMinimum(0); + + for (int iBin = 0; iBin < EventSelectionStep::NEventSelectionSteps; iBin++) { registry.get(HIST("Data/hEventCounter"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hMultiplicity", "hMultiplicity", {HistType::kTH1F, {{500, 0, 500}}}); - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hVtxZ", "hVtxZ", {HistType::kTH1F, {{400, -50, 50}}}); - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hNtracks", "hNtracks", {HistType::kTH1F, {{500, 0, 500}}}); - - // histograms for event mixing - const int maxMixBin = axisMultiplicity->size() * 14; // 14 bins for z-vertex - registry.add("Data/TpcTpc/HadronHadron/MixedEvent/hEventCountMixing", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); - registry.add("Data/TpcTpc/HfHadron/MixedEvent/hEventCountHFMixing", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hEventCountSame", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); - registry.add("Data/TpcTpc/HadronHadron/MixedEvent/hMultiplicityMixing", "hMultiplicityMixing", {HistType::kTH1F, {{500, 0, 500}}}); - registry.add("Data/TpcTpc/HadronHadron/MixedEvent/hVtxZMixing", "hVtxZMixing", {HistType::kTH1F, {{100, -10, 10}}}); - registry.add("Data/TpcTpc/HadronHadron/MixedEvent/hNtracksMixing", "hNtracksMixing", {HistType::kTH1F, {{500, 0, 500}}}); - registry.add("Data/TpcTpc/HfHadron/MixedEvent/hMultiplicityHFMixing", "hMultiplicityHFMixing", {HistType::kTH1F, {{500, 0, 500}}}); - registry.add("Data/TpcTpc/HfHadron/MixedEvent/hVtxZHFMixing", "hVtxZHFMixing", {HistType::kTH1F, {{100, -10, 10}}}); - registry.add("Data/TpcTpc/HfHadron/MixedEvent/hNtracksHFMixing", "hNtracksHFMixing", {HistType::kTH1F, {{500, 0, 500}}}); - - // TRACK HISTOGRAMS - // histograms for associated particles - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hYields", "multiplicity vs pT vs eta", {HistType::kTH3F, {{200, 0, 200, "multiplicity"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hEtaPhi", "multiplicity vs eta vs phi", {HistType::kTH3F, {{200, 0, 200, "multiplicity"}, {100, -2, 2, "#eta"}, {200, 0, TwoPI, "#varphi"}}}); - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hPt", "pT", {HistType::kTH1F, {{100, 0, 10, "p_{T}"}}}); - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hEta", "eta", {HistType::kTH1F, {{100, -4, 4, "#eta"}}}); - registry.add("Data/TpcTpc/HadronHadron/SameEvent/hPhi", "phi", {HistType::kTH1F, {{100, 0, TwoPI, "#varphi"}}}); - - // histograms for particles in event mixing - registry.add("Data/TpcTpc/HadronHadron/MixedEvent/hPtMixing", "pT", {HistType::kTH1F, {{100, 0, 10, "p_{T}"}}}); - registry.add("Data/TpcTpc/HadronHadron/MixedEvent/hEtaMixing", "eta", {HistType::kTH1F, {{100, -4, 4, "#eta"}}}); - registry.add("Data/TpcTpc/HadronHadron/MixedEvent/hPhiMixing", "phi", {HistType::kTH1F, {{100, 0, TwoPI, "#varphi"}}}); - - // histograms for MFT tracks - registry.add("Data/TpcMft/HadronHadron/hEtaPhiMFT", "multiplicity vs eta vs phi in MFT", {HistType::kTH3F, {{200, 0, 200, "multiplicity"}, {100, -2, 2, "#eta"}, {200, 0, TwoPI, "#varphi"}}}); - registry.add("Data/TpcMft/HadronHadron/hEtaMFT", "etaMFT", {HistType::kTH1F, {{100, -4, 4, "#eta"}}}); - registry.add("Data/TpcMft/HadronHadron/hPhiMFT", "phiMFT", {HistType::kTH1F, {{100, 0, TwoPI, "#varphi"}}}); - - // histograms for candidates - auto vbins = (std::vector)binsPt; - - registry.add("Data/TpcTpc/HfHadron/hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0, 10.}}}); - registry.add("Data/TpcTpc/HfHadron/hPtProng0", "2-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0, 10.}}}); - registry.add("Data/TpcTpc/HfHadron/hPtProng1", "2-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0, 10.}}}); - registry.add("Data/TpcTpc/HfHadron/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("Data/TpcTpc/HfHadron/hDecLength", "2-prong candidates;decay length (cm);entries", {HistType::kTH2F, {{200, 0., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/TpcTpc/HfHadron/hDecLengthXY", "2-prong candidates;decay length xy (cm);entries", {HistType::kTH2F, {{200, 0., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/TpcTpc/HfHadron/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("Data/TpcTpc/HfHadron/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("Data/TpcTpc/HfHadron/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("Data/TpcTpc/HfHadron/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("Data/TpcTpc/HfHadron/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("Data/TpcTpc/HfHadron/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("Data/TpcTpc/HfHadron/hEtaCand", "2-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/TpcTpc/HfHadron/hSelectionStatus", "2-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/TpcTpc/HfHadron/hImpParErr", "2-prong candidates;impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/TpcTpc/HfHadron/hDecLenErr", "2-prong candidates;decay length error (cm);entries", {HistType::kTH2F, {{100, 0., 1.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); - registry.add("Data/TpcTpc/HfHadron/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("Data/TpcTpc/HfHadron/MixedEvent/hPtHFMixing", "pT", {HistType::kTH1F, {{100, 0, 10, "p_{T}"}}}); - registry.add("Data/TpcTpc/HfHadron/MixedEvent/hEtaHFMixing", "eta", {HistType::kTH1F, {{100, -4, 4, "#eta"}}}); - registry.add("Data/TpcTpc/HfHadron/MixedEvent/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)"}, - {axisMultiplicity, "multiplicity"}, - {axisDeltaPhi, "#Delta#varphi (rad)"}, - {axisVertex, "z-vtx (cm)"}}; - std::vector effAxis = {{axisEtaEfficiency, "#eta"}, - {axisPtEfficiency, "p_{T} (GeV/c)"}, - {axisVertexEfficiency, "z-vtx (cm)"}}; - std::vector userAxis = {{axisMass, "m_{inv} (GeV/c^{2})"}}; - - sameTPCTPCChCh.setObject(new CorrelationContainer("sameTPCTPCChCh", "sameTPCTPCChCh", corrAxis, effAxis, {})); - mixedTPCTPCChCh.setObject(new CorrelationContainer("mixedTPCTPCChCh", "mixedTPCTPCChCh", corrAxis, effAxis, {})); - sameTPCTPCHfCh.setObject(new CorrelationContainer("sameTPCTPCHfCh", "sameTPCTPCHfCh", corrAxis, effAxis, userAxis)); - mixedTPCTPCHfCh.setObject(new CorrelationContainer("mixedTPCTPCHfCh", "mixedTPCTPCHfCh", corrAxis, effAxis, userAxis)); - sameTPCMFTChCh.setObject(new CorrelationContainer("sameTPCMFTChCh", "sameTPCMFTChCh", corrAxis, effAxis, {})); - mixedTPCMFTChCh.setObject(new CorrelationContainer("mixedTPCMFTChCh", "mixedTPCMFTChCh", corrAxis, effAxis, {})); - } - - // --------------- - // templates - // FIXME: Some collisions are rejected here, what causes (part of) differences with the D0 task - // --------------- + + mPairCuts.SetHistogramRegistry(®istry); + if (configCentral.pairCut->get("Photon") > 0 || configCentral.pairCut->get("K0") > 0 || configCentral.pairCut->get("Lambda") > 0 || configCentral.pairCut->get("Phi") > 0 || configCentral.pairCut->get("Rho") > 0) { + mPairCuts.SetPairCut(PairCuts::Photon, configCentral.pairCut->get("Photon")); + mPairCuts.SetPairCut(PairCuts::K0, configCentral.pairCut->get("K0")); + mPairCuts.SetPairCut(PairCuts::Lambda, configCentral.pairCut->get("Lambda")); + mPairCuts.SetPairCut(PairCuts::Phi, configCentral.pairCut->get("Phi")); + mPairCuts.SetPairCut(PairCuts::Rho, configCentral.pairCut->get("Rho")); + } + + // ========================= + // Declaration of correlation containers and their respective axis + // ========================= + + std::vector const corrAxis = {{configAxis.axisDeltaEta, "#Delta#eta"}, + {configAxis.axisPtAssoc, "p_{T} (GeV/c)"}, + {configAxis.axisPtTrigger, "p_{T} (GeV/c)"}, + {configAxis.axisMultiplicity, "multiplicity"}, + {configAxis.axisDeltaPhi, "#Delta#varphi (rad)"}, + {configAxis.axisVertex, "z-vtx (cm)"}}; + std::vector const effAxis = {{configAxis.axisEtaEfficiency, "#eta"}, + {configAxis.axisPtEfficiency, "p_{T} (GeV/c)"}, + {configAxis.axisVertexEfficiency, "z-vtx (cm)"}}; + std::vector const userAxis = {{configAxis.axisMass, "m_{inv} (GeV/c^{2})"}}; + + // ========================= + // Initialization of histograms and CorrelationContainers for TpcTpc cases + // ========================= + + if (doprocessSameTpcTpcChCh) { + addHistograms(); + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + } + + if (doprocessSameTpcTpcD0Ch) { + addHistograms(); + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + if (doprocessSameTpcTpcLcCh) { + addHistograms(); + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + // ========================= + // Initialization of histograms and CorrelationContainers for TpcMft cases + // ========================= + + if (doprocessSameTpcMftChCh || doprocessSameTpcMftChChReassociated || doprocessSameTpcMftChChReassociated3d || doprocessSameTpcMftChChNonAmbiguous) { + addHistograms(); + addMftHistograms(); + + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + } + + if (doprocessSameTpcMftD0Ch || doprocessSameTpcMftD0ChReassociated) { + addHistograms(); + addMftHistograms(); + + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + if (doprocessSameTpcMftLcCh || doprocessSameTpcMftLcChReassociated) { + addHistograms(); + addMftHistograms(); + + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + // ========================= + // Initialization of histograms and CorrelationContainers for TpcFv0a cases + // ========================= + + if (doprocessSameTpcFv0aChCh) { + addHistograms(); + + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + } + + if (doprocessSameTpcFv0aD0Ch) { + addHistograms(); + + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + if (doprocessSameTpcFv0aLcCh) { + addHistograms(); + + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + // ========================= + // Initialization of histograms and CorrelationContainers for MftFv0a cases + // ========================= + + // if (doprocessSameMftFv0aChCh || doprocessSameMftFv0aChChReassociated || doprocessSameMftFv0aReassociated3d || doprocessSameMftFv0aChChNonAmbiguous) { + if (doprocessSameMftFv0aChCh || doprocessSameMftFv0aChChReassociated || doprocessSameMftFv0aChChNonAmbiguous) { + addHistograms(); + addMftHistograms(); + + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + } + + // ========================= + // Initialization of histograms and CorrelationContainers for TpcFt0a cases + // ========================= + + if (doprocessSameTpcFt0aChCh) { + addHistograms(); + + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + } + + if (doprocessSameTpcFt0aD0Ch) { + addHistograms(); + + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + if (doprocessSameTpcFt0aLcCh) { + addHistograms(); + + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + // ========================= + // Initialization of histograms and CorrelationContainers for MftFt0a cases + // ========================= + + if (doprocessSameMftFt0aChCh || doprocessSameMftFt0aChChReassociated || doprocessSameMftFt0aChChReassociated3d || doprocessSameMftFt0aChChNonAmbiguous) { + addHistograms(); + addMftHistograms(); + + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + } + + // ========================= + // Initialization of histograms and CorrelationContainers for TpcFt0c cases + // ========================= + + if (doprocessSameTpcFt0cChCh) { + addHistograms(); + + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + } + + if (doprocessSameTpcFt0cD0Ch) { + addHistograms(); + + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + if (doprocessSameTpcFt0cLcCh) { + addHistograms(); + + sameEventHf.setObject(new CorrelationContainer("sameEventHf", "sameEventHf", corrAxis, effAxis, userAxis)); + mixedEventHf.setObject(new CorrelationContainer("mixedEventHf", "mixedEventHf", corrAxis, effAxis, userAxis)); + } + + // ========================= + // Initialization of histograms and CorrelationContainers for Ft0aFt0c cases + // ========================= + + if (doprocessSameFt0aFt0cChCh) { + addHistograms(); + + sameEvent.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixedEvent.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + } + + } // End of init() function + + // ========================= + // Quality assessment functions + // ========================= + + template + void fillTriggerQa(float multiplicity, float const& eta, float const& phi, float const& pt) + { + registry.fill(HIST(WhatDataType[DataType]) + HIST(WhatCorrelationCase[CorrelationCase]) + HIST(WhatParticles[CorrelatedParticles]) + HIST("hPtTrigger"), pt); + registry.fill(HIST(WhatDataType[DataType]) + HIST(WhatCorrelationCase[CorrelationCase]) + HIST(WhatParticles[CorrelatedParticles]) + HIST("hEtaTrigger"), eta); + registry.fill(HIST(WhatDataType[DataType]) + HIST(WhatCorrelationCase[CorrelationCase]) + HIST(WhatParticles[CorrelatedParticles]) + HIST("hPhiTrigger"), phi); + registry.fill(HIST(WhatDataType[DataType]) + HIST(WhatCorrelationCase[CorrelationCase]) + HIST(WhatParticles[CorrelatedParticles]) + HIST("hYieldsTrigger"), multiplicity, pt, eta); + registry.fill(HIST(WhatDataType[DataType]) + HIST(WhatCorrelationCase[CorrelationCase]) + HIST(WhatParticles[CorrelatedParticles]) + HIST("hEtaPhiTrigger"), multiplicity, eta, phi); + } + + template + void fillAssociatedQa(float multiplicity, float const& eta, float const& phi) + { + registry.fill(HIST(WhatDataType[DataType]) + HIST(WhatCorrelationCase[CorrelationCase]) + HIST(WhatParticles[CorrelatedParticles]) + HIST("hEtaAssociated"), eta); + registry.fill(HIST(WhatDataType[DataType]) + HIST(WhatCorrelationCase[CorrelationCase]) + HIST(WhatParticles[CorrelatedParticles]) + HIST("hPhiAssociated"), phi); + registry.fill(HIST(WhatDataType[DataType]) + HIST(WhatCorrelationCase[CorrelationCase]) + HIST(WhatParticles[CorrelatedParticles]) + HIST("hEtaPhiAssociated"), multiplicity, eta, phi); + } + + // ========================= + // Helper functions + // ========================= + + HfProngSpecies getSpecies(int pdgCode) + { + switch (std::abs(pdgCode)) { + case PDG_t::kPiPlus: // positive or negative pion + return HfProngSpecies::Pion; + case PDG_t::kKPlus: // positive or negative kaon + return HfProngSpecies::Kaon; + case PDG_t::kProton: // proton or proton bar + return HfProngSpecies::Proton; + default: // NOTE. The efficiency histogram is hardcoded to contain 4 species. Anything special will have the last slot. + return HfProngSpecies::NHfProngSpecies; + } + } + template - bool isCollisionSelected(TCollision const& collision, bool fillHistograms = false) + float getMultiplicityEstimator(TCollision collision, bool isSameEvent) { - if (processRun2 == true) { - // Run 2: trigger selection for data case - if (fillHistograms) - registry.fill(HIST("Data/hEventCounter"), 1); - if (!processMc) { - if (!collision.alias_bit(kINT7)) { - return false; + switch (configCollision.multiplicityEstimator) { + case MultiplicityEstimators::MultNTracksPV: + if (isSameEvent) { + registry.fill(HIST("Data/hMultiplicity_multNTracksPV"), collision.multNTracksPV()); } + return collision.multNTracksPV(); + case MultiplicityEstimators::MultNumContrib: + if (isSameEvent) { + registry.fill(HIST("Data/hMultiplicity_multNumContrib"), collision.numContrib()); + } + return collision.numContrib(); + case MultiplicityEstimators::MultFT0C: + if (isSameEvent) { + registry.fill(HIST("Data/hMultiplicity_multFT0C"), collision.multFT0C()); + } + return collision.multFT0C(); + case MultiplicityEstimators::MultFT0M: + if (isSameEvent) { + registry.fill(HIST("Data/hMultiplicity_multFT0M"), collision.multFT0M()); + } + return collision.multFT0M(); + default: + return collision.multNTracksPV(); + } + } + + 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; + } + + 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; } - // Run 2: further offline selection - if (fillHistograms) - registry.fill(HIST("Data/hEventCounter"), 2); - if (!collision.sel7()) { - return false; - } - if (fillHistograms) - registry.fill(HIST("Data/hEventCounter"), 3); + LOGF(info, "Retrieved GRP for timestamp %llu with magnetic field of %d kG", timestamp, grpo->getNominalL3Field()); + } + return grpo->getNominalL3Field(); + } + + double getPhiFT0(uint chno, int i) + { + ft0Det.calculateChannelCenter(); + auto chPos = ft0Det.getChannelCenter(chno); + return RecoDecay::phi(chPos.X() + (*offsetFT0)[i].getX(), chPos.Y() + (*offsetFT0)[i].getY()); + } + + double getPhiFV0(unsigned int chno) const + { + int const cellsInLeft[] = {0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, 32, 40, 33, 41, 34, 42, 35, 43}; + bool const isChnoInLeft = std::find(std::begin(cellsInLeft), std::end(cellsInLeft), chno) != std::end(cellsInLeft); + float offsetX, offsetY; + if (isChnoInLeft) { + offsetX = (*offsetFV0)[0].getX(); + offsetY = (*offsetFV0)[0].getY(); } else { - // Run 3: selection - if (fillHistograms) - registry.fill(HIST("Data/hEventCounter"), 1); - if (!collision.sel8()) { - return false; - } - if (fillHistograms) - registry.fill(HIST("Data/hEventCounter"), 3); + offsetX = (*offsetFV0)[1].getX(); + offsetY = (*offsetFV0)[1].getY(); } - return true; + + o2::fv0::Point3Dsimple chPos{}; + chPos = fv0Det->getReadoutCenter(chno); + + // if (configTask.isReadoutCenter) + // chPos = fv0Det->getReadoutCenter(chno); + // else + // chPos = fv0Det->getCellCenter(chno); + + return RecoDecay::phi(chPos.x + offsetX, chPos.y + offsetY); } - template - void fillQA(float multiplicity, TTracks const& tracks) + double getEtaFT0(uint chno, int i) { - int Ntracks = 0; - for (const auto& track1 : tracks) { - Ntracks++; - registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hPt"), track1.pt()); - registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hEta"), track1.eta()); - registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hPhi"), track1.phi()); - registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hYields"), multiplicity, track1.pt(), track1.eta()); - registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hEtaPhi"), multiplicity, track1.eta(), track1.phi()); + ft0Det.calculateChannelCenter(); + auto chPos = ft0Det.getChannelCenter(chno); + auto x = chPos.X() + (*offsetFT0)[i].getX(); + auto y = chPos.Y() + (*offsetFT0)[i].getY(); + auto z = chPos.Z() + (*offsetFT0)[i].getZ(); + if (chno >= MinFt0cCell) { + z = -z; } - registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hNtracks"), Ntracks); + auto r = std::sqrt(x * x + y * y); + auto theta = std::atan2(r, z); + return -std::log(std::tan(0.5 * theta)); } - template - void fillMixingQA(float multiplicity, float vz, TTracks const& tracks) + double getEtaFV0(unsigned int chno) const { - registry.fill(HIST("Data/TpcTpc/HadronHadron/MixedEvent/hMultiplicityMixing"), multiplicity); - registry.fill(HIST("Data/TpcTpc/HadronHadron/MixedEvent/hVtxZMixing"), vz); + int const cellsInLeft[] = {0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, 32, 40, 33, 41, 34, 42, 35, 43}; + bool const isChnoInLeft = std::find(std::begin(cellsInLeft), std::end(cellsInLeft), chno) != std::end(cellsInLeft); + float offsetX, offsetY, offsetZ; + if (isChnoInLeft) { + offsetX = (*offsetFV0)[0].getX(); + offsetY = (*offsetFV0)[0].getY(); + offsetZ = (*offsetFV0)[0].getZ(); + } else { + offsetX = (*offsetFV0)[1].getX(); + offsetY = (*offsetFV0)[1].getY(); + offsetZ = (*offsetFV0)[1].getZ(); + } + + o2::fv0::Point3Dsimple chPos{}; + chPos = fv0Det->getReadoutCenter(chno); + // if (configTask.isReadoutCenter) + // chPos = fv0Det->getReadoutCenter(chno); + // else + // chPos = fv0Det->getCellCenter(chno); + + auto x = chPos.x + offsetX; + auto y = chPos.y + offsetY; + auto z = chPos.z + offsetZ; + auto r = std::sqrt(x * x + y * y); + auto theta = std::atan2(r, z); + return -std::log(std::tan(0.5 * theta)); + } - int Ntracks = 0; - for (const auto& track1 : tracks) { - Ntracks++; - registry.fill(HIST("Data/TpcTpc/HadronHadron/MixedEvent/hPtMixing"), track1.pt()); - registry.fill(HIST("Data/TpcTpc/HadronHadron/MixedEvent/hEtaMixing"), track1.eta()); - registry.fill(HIST("Data/TpcTpc/HadronHadron/MixedEvent/hPhiMixing"), track1.phi()); + template + void getChannel(TFT0s const& ft0, std::size_t const& iCh, int& id, int fitType) + { + if (fitType == isFT0C) { + id = ft0.channelC()[iCh] + MinFt0cCell; + } else if (fitType == isFT0A) { + id = ft0.channelA()[iCh]; + } else { + LOGF(fatal, "Cor Index %d out of range", fitType); } - registry.fill(HIST("Data/TpcTpc/HadronHadron/MixedEvent/hNtracksMixing"), Ntracks); } - template - void fillHFMixingQA(float multiplicity, float vz, 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) { - registry.fill(HIST("Data/TpcTpc/HfHadron/MixedEvent/hMultiplicityHFMixing"), multiplicity); - registry.fill(HIST("Data/TpcTpc/HfHadron/MixedEvent/hVtxZHFMixing"), vz); + if (fillHistograms) { + registry.fill(HIST("Data/hEventCounter"), EventSelectionStep::AllEvents); + } + + if (!collision.sel8()) { + return false; + } + if (configCollision.isApplySameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (configCollision.isApplyGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (configCollision.isApplyNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (configCollision.isApplyGoodItsLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } - int Ntracks = 0; - for (const auto& track1 : tracks) { - Ntracks++; - registry.fill(HIST("Data/TpcTpc/HfHadron/MixedEvent/hPtHFMixing"), track1.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/MixedEvent/hEtaHFMixing"), track1.eta()); - registry.fill(HIST("Data/TpcTpc/HfHadron/MixedEvent/hPhiHFMixing"), track1.phi()); + if (fillHistograms) { + registry.fill(HIST("Data/hEventCounter"), EventSelectionStep::AfterEventSelection); } - registry.fill(HIST("Data/TpcTpc/HfHadron/MixedEvent/hNtracksHFMixing"), Ntracks); + + registry.fill(HIST("Data/hVtxZ"), collision.posZ()); + + return true; } - template - void fillMFTQA(float multiplicity, TTracks const& tracks) + template + bool isAcceptedCentralTrack(TTrack const& track) { - for (const auto& track1 : tracks) { - registry.fill(HIST("Data/TpcMft/HadronHadron/hEtaMFT"), track1.eta()); - float phi = track1.phi(); - o2::math_utils::bringTo02Pi(phi); - registry.fill(HIST("Data/TpcMft/HadronHadron/hPhiMFT"), phi); - registry.fill(HIST("Data/TpcMft/HadronHadron/hEtaPhiMFT"), multiplicity, track1.eta(), phi); + if (track.tpcNClsFound() < configCentral.minTpcClusters) { + return false; + } + if (track.tpcNClsCrossedRows() < configCentral.minTpcCrossedRows) { + return false; } + if (track.itsNCls() < configCentral.minItsClusters) { + return false; + } + 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 (configCandidates.etaCandidateMax >= 0. && std::abs(etaCandidate) > configCandidates.etaCandidateMax) { + return false; + } + if (configCandidates.yCandRecoMax >= 0. && std::abs(HfHelper::yLc(candidate)) > configCandidates.yCandRecoMax) { + return false; + } + return true; + } else { // For now, that means we do D0 + // Doesn't this exclude D0bar ? + if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + return false; + } + if (configCandidates.etaCandidateMax >= 0. && std::abs(etaCandidate) > configCandidates.etaCandidateMax) { + return false; + } + if (configCandidates.yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > configCandidates.yCandRecoMax) { + 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, bool fillHistograms) + { + // cut on the eta of MFT tracks + if (mftTrack.eta() > configMft.etaMftTrackMax || mftTrack.eta() < configMft.etaMftTrackMin) { + return false; + } + + if (fillHistograms) { + registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::Eta); + } + + // cut on the number of clusters of the reconstructed MFT track + if (mftTrack.nClusters() < configMft.nClustersMftTrack) { return false; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candidate)) > yCandMax) { + + if (fillHistograms) { + registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::Cluster); + } + + // cut on the pT of MFT tracks (for test purposes) + if (configMft.useMftPtCut && (mftTrack.pt() > configMft.ptMftTrackMax || mftTrack.pt() < configMft.ptMftTrackMin)) { return false; } + + if (fillHistograms) { + registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::Pt); + } + 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) + // Cut on ambiguous MFT tracks + template + bool isAmbiguousMftTrack(TTrack const& mftTrack, bool fillHistograms) { - for (const auto& candidate : candidates) { - if (!isAcceptedCandidate(candidate)) { - continue; - } - - if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("Data/TpcTpc/HfHadron/hMass"), hfHelper.invMassD0ToPiK(candidate), candidate.pt()); - } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("Data/TpcTpc/HfHadron/hMass"), hfHelper.invMassD0barToKPi(candidate), candidate.pt()); + if (mftTrack.ambDegree() > 1) { + if (fillHistograms) { + registry.fill(HIST("Data/Mft/hAmbiguityOfMftTracks"), MftTrackAmbiguityStep::NumberOfAmbiguousTracks); } + return true; + } - registry.fill(HIST("Data/TpcTpc/HfHadron/hPtCand"), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hPtProng0"), candidate.ptProng0()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hPtProng1"), candidate.ptProng1()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hDecLength"), candidate.decayLength(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hDecLengthXY"), candidate.decayLengthXY(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hd0Prong0"), candidate.impactParameter0(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hd0Prong1"), candidate.impactParameter1(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hd0d0"), candidate.impactParameterProduct(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hCTS"), hfHelper.cosThetaStarD0(candidate), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hCt"), hfHelper.ctD0(candidate), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hCPA"), candidate.cpa(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hEtaCand"), candidate.eta(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hSelectionStatus"), candidate.isSelD0() + (candidate.isSelD0bar() * 2), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hImpParErr"), candidate.errorImpactParameter0(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hImpParErr"), candidate.errorImpactParameter1(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hDecLenErr"), candidate.errorDecayLength(), candidate.pt()); - registry.fill(HIST("Data/TpcTpc/HfHadron/hDecLenXYErr"), candidate.errorDecayLengthXY(), candidate.pt()); + if (fillHistograms) { + registry.fill(HIST("Data/Mft/hAmbiguityOfMftTracks"), MftTrackAmbiguityStep::NumberOfNonAmbiguousTracks); } + return false; } + // =============================================================================================================================================================================== + // =============================================================================================================================================================================== + // Correlation functions + // =============================================================================================================================================================================== + // =============================================================================================================================================================================== + + // =============================================================================================================================================================================== + // fillCorrelations + // =============================================================================================================================================================================== + template - void fillCorrelations(TTarget target, TTracksTrig const& tracks1, TTracksAssoc const& tracks2, float multiplicity, float posZ) + void fillCorrelations(TTarget target, CorrelationContainer::CFStep step, + TTracksTrig const& tracks1, TTracksAssoc const& tracks2, + float multiplicity, float posZ, bool sameEvent, int magneticField) { auto triggerWeight = 1; auto associatedWeight = 1; + auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision + // TRIGGER PARTICLE for (const auto& track1 : tracks1) { + loopCounter++; - float eta1 = track1.eta(); - float pt1 = track1.pt(); - float phi1 = track1.phi(); - o2::math_utils::bringTo02Pi(phi1); + if constexpr (std::is_same_v) { + if (!isAcceptedCentralTrack(track1)) { + continue; + } + } + + float const eta1 = track1.eta(); + float const pt1 = track1.pt(); + float const phi1 = track1.phi(); // TODO: add getter for NUE trigger efficiency here // calculating inv. mass to be filled into the container below - // Note: this is needed only in case of HF-hadron correlations bool fillingHFcontainer = false; double invmass = 0; - if constexpr (std::is_same_v) { - // TODO: Check how to put this into a Filter + if constexpr (std::is_same_v || std::is_same_v) { + // TODO: Check how to put this into a Filter -> Pretty sure it cannot be a filter if (!isAcceptedCandidate(track1)) { continue; } fillingHFcontainer = true; - invmass = hfHelper.invMassD0ToPiK(track1); + if constexpr (std::is_same_v) { // If D0 + invmass = HfHelper::invMassD0ToPiK(track1); + } else { // If Lc + invmass = HfHelper::invMassLcToPKPi(track1); + } } // 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 && (step == CorrelationContainer::kCFStepReconstructed)) { + if constexpr (!std::is_same_v) { // IF TPC-TPC case + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-TPC D0-h + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-TPC Lc-h + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else { // IF NEITHER D0 NOR LC -> TPC-TPC h-h + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + } else { // IF TPC-MFT case + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-MFT D0-h + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-MFT Lc-h + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else { // IF NEITHER D0 NOR LC -> TPC-MFT h-h + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } // end of if condition for TPC-TPC or TPC-MFT case + } } + // ASSOCIATED PARTICLE for (const auto& track2 : tracks2) { - // 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) { - if (track1.index() <= track2.index()) { + if constexpr (std::is_same_v) { + if (!isAcceptedCentralTrack(track2)) { continue; } } - // 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())) { - continue; + // apply cuts for MFT tracks + if constexpr (std::is_same_v) { + + if (sameEvent && loopCounter == 1) { // To avoid double counting, we fill the plots only the first time + registry.fill(HIST("Data/Mft/hMftTracksSelection"), MftTrackSelectionStep::NoSelection); + + if (!isAcceptedMftTrack(track2, true)) { + continue; + } + } else { // After the first loop, we don't fill the plots anymore but still do the selection + if (!isAcceptedMftTrack(track2, false)) { + continue; + } } } - float eta2 = track2.eta(); - float pt2 = track2.pt(); - float phi2 = track2.phi(); - o2::math_utils::bringTo02Pi(phi2); + if (configCentral.isApplySameTrackCut && (track1 == track2)) { + continue; + } - // TODO: add getter for NUE associated efficiency here + if (configCentral.isApplyPtOrderingSameEvent && sameEvent && (track1.pt() <= track2.pt())) { + continue; + } + if (configCentral.isApplyPtOrderingMixedEvent && !sameEvent && (track1.pt() <= track2.pt())) { + continue; + } - // TODO: add pair cuts on phi* + if (configCentral.isApplyIndexOrdering && (track1.index() <= track2.index())) { + continue; + } - float deltaPhi = phi1 - phi2; - // set range of delta phi in (-pi/2 , 3/2*pi) - deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); + // I have to add this condition, because ConversionCut is template to get the same type of tracks for both tracks + if constexpr (std::is_same_v) { + if (configCentral.isApplyConversionCut && mPairCuts.conversionCuts(track1, track2)) { + continue; + } + } + + // I have to add this condition, because PhiStar need track1.sign() + if constexpr (std::is_same_v) { + if (configCentral.isApplyTwoTrackCut && std::abs(eta1 - track2.eta()) < configCentral.mergingCut) { + + double dPhiStarHigh = getDPhiStar(track1, track2, configCentral.maxMergingRadius, magneticField); + double dPhiStarLow = getDPhiStar(track1, track2, configCentral.minMergingRadius, magneticField); + + const double kLimit = 3.0 * configCentral.mergingCut; + + bool bIsBelow = false; + + if (std::abs(dPhiStarLow) < kLimit || std::abs(dPhiStarHigh) < kLimit || dPhiStarLow * dPhiStarHigh < 0) { + for (double rad(configCentral.minMergingRadius); rad < configCentral.maxMergingRadius; rad += 0.01) { + double dPhiStar = getDPhiStar(track1, track2, rad, magneticField); + if (std::abs(dPhiStar) < kLimit) { + bIsBelow = true; + break; + } + } + if (bIsBelow) + continue; + } + } + } + + // in case of HF-h correlations, remove candidate daughters from the pool of associated hadrons + // 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; + } + } + } + + float const eta2 = track2.eta(); + float const pt2 = track2.pt(); + float phi2 = track2.phi(); + o2::math_utils::bringTo02Pi(phi2); + + // TODO: add getter for NUE associated efficiency here + + float deltaPhi = phi1 - phi2; + // set range of delta phi in (-pi/2 , 3/2*pi) + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); + + if (!fillingHFcontainer) { + // fill pair correlations + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, + triggerWeight * associatedWeight); + } else { + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, + triggerWeight * associatedWeight); + } + + // FILL QA PLOTS for associated particle + if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + if constexpr (!std::is_same_v) { // IF TPC-TPC case + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-TPC D0-h + fillAssociatedQa(multiplicity, eta2, phi2); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-TPC Lc-h + fillAssociatedQa(multiplicity, eta2, phi2); + } else { + fillAssociatedQa(multiplicity, eta2, phi2); + } + } else { // IF TPC-MFT case + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-MFT D0-h + fillAssociatedQa(multiplicity, eta2, phi2); + registry.fill(HIST("Data/Mft/hPtMft"), pt2); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-MFT Lc-h + fillAssociatedQa(multiplicity, eta2, phi2); + registry.fill(HIST("Data/Mft/hPtMft"), pt2); + } else { // IF NEITHER D0 NOR LC -> TPC-MFT h-h + fillAssociatedQa(multiplicity, eta2, phi2); + registry.fill(HIST("Data/Mft/hPtMft"), pt2); + } // end of if condition for TPC-TPC or TPC-MFT case + } + } + + } // end of loop over tracks2 + } // end of loop over tracks 1 + } + + template + void fillCorrelationsReassociatedMftTracks(TTarget target, CorrelationContainer::CFStep step, + TTracksTrig const& tracks1, TTracksAssoc const& tracks2, + float multiplicity, float posZ, bool sameEvent, bool cutAmbiguousTracks) + { + auto triggerWeight = 1; + auto associatedWeight = 1; + auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision + + // TRIGGER PARTICLE + for (const auto& track1 : tracks1) { + loopCounter++; + + if constexpr (std::is_same_v) { + if (!isAcceptedCentralTrack(track1)) { + continue; + } + } + + float const eta1 = track1.eta(); + float const pt1 = track1.pt(); + float const phi1 = track1.phi(); + + bool fillingHFcontainer = false; + double invmass = 0; + if constexpr (std::is_same_v || std::is_same_v) { + if (!isAcceptedCandidate(track1)) { + continue; + } + fillingHFcontainer = true; + if constexpr (std::is_same_v) { // If D0 + invmass = HfHelper::invMassD0ToPiK(track1); + } else { // If Lc + invmass = HfHelper::invMassLcToPKPi(track1); + } + } + + // fill single-track distributions + if (!fillingHFcontainer) { // if not HF-h case + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); + } else { + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); + } + + // FILL QA PLOTS for trigger particle + if (sameEvent) { + if constexpr (std::is_same_v) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else if constexpr (std::is_same_v) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + } + + // ASSOCIATED PARTICLE + for (const auto& track2 : tracks2) { + + // Fill QA plot for all MFT tracks () (only if cutAmbiguousTracks is false to avoid double counting) + if (!cutAmbiguousTracks && sameEvent && (loopCounter == 1)) { + registry.fill(HIST("Data/Mft/hAmbiguityOfMftTracks"), MftTrackAmbiguityStep::AllMftTracks); + } + + auto reassociatedMftTrack = track2.template mfttrack_as(); + + if (!isAcceptedMftTrack(reassociatedMftTrack, false)) { + continue; + } + + // Fill QA plot for MFT tracks after physical selection (eta + clusters) + if (!cutAmbiguousTracks && sameEvent && (loopCounter == 1)) { + registry.fill(HIST("Data/Mft/hAmbiguityOfMftTracks"), MftTrackAmbiguityStep::AfterTrackSelection); + } + + // We check if the track is ambiguous or non-ambiguous (QA plots are filled in isAmbiguousMftTrack) + // Fill plots only if cutAmbiguousTracks is false (to avoid double counting) + if (isAmbiguousMftTrack(track2, (!cutAmbiguousTracks && sameEvent && (loopCounter == 1)))) { + // If the MFT track is ambiguous we may cut or not on the ambiguous track + if (sameEvent && (loopCounter == 1)) { + registry.fill(HIST("Data/Mft/hReassociationMftTracks"), ReassociationMftTracks::NotReassociatedMftTracks); + } + if (cutAmbiguousTracks) { + continue; + } + } + + if (reassociatedMftTrack.collisionId() != track2.bestCollisionId()) { + if (sameEvent && (loopCounter == 1)) { + registry.fill(HIST("Data/Mft/hReassociationMftTracks"), ReassociationMftTracks::ReassociatedMftTracks); + } + } + + // in case of HF-h correlations, remove candidate daughters from the pool of associated hadrons + // with which the candidate is being correlated (will not have to do it for TPC-MFT case) + if constexpr (std::is_same_v) { // Remove the 2 prong daughters + if ((track1.prong0Id() == reassociatedMftTrack.globalIndex()) || (track1.prong1Id() == reassociatedMftTrack.globalIndex())) { + continue; + } + } + if constexpr (std::is_same_v) { // Remove the 3 prong daughters + if ((track1.prong0Id() == reassociatedMftTrack.globalIndex()) || (track1.prong1Id() == reassociatedMftTrack.globalIndex()) || (track1.prong2Id() == reassociatedMftTrack.globalIndex())) { + continue; + } + } + + if (configCentral.isApplySameTrackCut && (track1 == reassociatedMftTrack)) { + continue; + } + + if (configCentral.isApplyPtOrderingSameEvent && sameEvent && (track1.pt() <= reassociatedMftTrack.pt())) { + continue; + } + if (configCentral.isApplyPtOrderingMixedEvent && !sameEvent && (track1.pt() <= reassociatedMftTrack.pt())) { + continue; + } + + if (configCentral.isApplyIndexOrdering && (track1.index() <= reassociatedMftTrack.index())) { + continue; + } + + float eta2 = reassociatedMftTrack.eta(); + float pt2 = reassociatedMftTrack.pt(); + float phi2 = reassociatedMftTrack.phi(); + o2::math_utils::bringTo02Pi(phi2); + + // TODO: add getter for NUE associated efficiency here + + float deltaPhi = phi1 - phi2; + // set range of delta phi in (-pi/2 , 3/2*pi) + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); + + if (!fillingHFcontainer) { + target->getPairHist()->Fill(step, eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, + triggerWeight * associatedWeight); + } else { + 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) { + fillAssociatedQa(multiplicity, eta2, phi2); + registry.fill(HIST("Data/Mft/hPtMft"), pt2); + } else if constexpr (std::is_same_v) { + fillAssociatedQa(multiplicity, eta2, phi2); + registry.fill(HIST("Data/Mft/hPtMft"), pt2); + } else { + fillAssociatedQa(multiplicity, eta2, phi2); + registry.fill(HIST("Data/Mft/hPtMft"), pt2); + } + } // end of fill QA + } // end of loop over tracks2 + } // end of loop over tracks 1 + } + + template + void fillCorrelationsFIT(TTarget target, CorrelationContainer::CFStep step, + TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TFits const&, + float multiplicity, float posZ, bool sameEvent, int fitType) + { + auto triggerWeight = 1; + auto associatedWeight = 1; + auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision + + // TRIGGER PARTICLE + for (auto const& track1 : tracks1) { + loopCounter++; + + if constexpr (std::is_same_v) { + if (!isAcceptedCentralTrack(track1)) { + continue; + } + } else if constexpr (std::is_same_v) { + if (!isAcceptedMftTrack(track1, true)) { + continue; + } + } + + float const eta1 = track1.eta(); + float const pt1 = track1.pt(); + float phi1 = track1.phi(); + if constexpr (std::is_same_v) { + o2::math_utils::bringTo02Pi(phi1); + } + + bool fillingHFcontainer = false; + double invmass = 0; + if constexpr (std::is_same_v || std::is_same_v) { + if (!isAcceptedCandidate(track1)) { + continue; + } + fillingHFcontainer = true; + if constexpr (std::is_same_v) { // If D0 + invmass = HfHelper::invMassD0ToPiK(track1); + } else { // If Lc + invmass = HfHelper::invMassLcToPKPi(track1); + } + } + + // fill single-track distributions + if (!fillingHFcontainer) { // if not HF-h case + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); + } else { + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, invmass, triggerWeight); + } + + // FILL QA PLOTS for trigger particle + if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { + if constexpr (!std::is_same_v) { // If not FilteredMftTracks as trigger -> TPC-FV0a correlations + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-FV0a D0-h + if constexpr (std::is_same_v) { // IF NEITHER D0 NOR LC -> + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else if constexpr (std::is_same_v) { + if (fitType == isFT0A) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + if (fitType == isFT0C) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + } + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-FV0a Lc-h + if constexpr (std::is_same_v) { // IF NEITHER D0 NOR LC -> + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else if constexpr (std::is_same_v) { + if (fitType == isFT0A) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + if (fitType == isFT0C) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + } + } else if constexpr (std::is_same_v) { // IF NEITHER D0 NOR LC - + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else if constexpr (std::is_same_v) { + if (fitType == isFT0A) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + if (fitType == isFT0C) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + } + } else { // If FilteredMftTracks as trigger + if constexpr (std::is_same_v) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else if constexpr (std::is_same_v) { + if (fitType == isFT0A) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + } + } + } // end of if condition to fill QA plots for trigger particle + + // ASSOCIATED PARTICLE IF USING FV0 + if constexpr (std::is_same_v) { + for (std::size_t indexChannel = 0; indexChannel < tracks2.channel().size(); indexChannel++) { + + auto channelId = tracks2.channel()[indexChannel]; + auto phi2 = getPhiFV0(channelId); + auto eta2 = getEtaFV0(channelId); + float deltaPhi = phi1 - phi2; + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); // set range of delta phi in (-pi/2 , 3/2*pi) + + if (!fillingHFcontainer) { + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, + triggerWeight * associatedWeight); + } else { + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, invmass, + triggerWeight * associatedWeight); + } + + // FILL QA PLOTS for associated particle + if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + if constexpr (!std::is_same_v) { // If not FilteredMftTracks as trigger -> TPC-FV0a correlations + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-FV0a D0-h + fillAssociatedQa(multiplicity, eta2, phi2); + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-FV0a Lc-h + fillAssociatedQa(multiplicity, eta2, phi2); + } else if constexpr (std::is_same_v) { // IF NEITHER D0 NOR LC -> ch. part. - ch. part + fillAssociatedQa(multiplicity, eta2, phi2); + } + } else { // If FilteredMftTracks as trigger -> MFT-FV0a (non reassoc/ambiguous) correlations + fillAssociatedQa(multiplicity, eta2, phi2); + } + } // end of if condition to fill QA plots for associated particle + } // end of loop over FV0 channel indices + } // end of if condition for FV0s + + // ASSOCIATED PARTICLE IF USING FT0 + if constexpr (std::is_same_v) { + + // select the right channel size if it is FT0a or FT0c + std::size_t channelSize = 0; + if (fitType == isFT0C) { + channelSize = tracks2.channelC().size(); + } else if (fitType == isFT0A) { + channelSize = tracks2.channelA().size(); + } else { + LOGF(fatal, "Cor Index %d out of range", fitType); + } + + for (std::size_t indexChannel = 0; indexChannel < channelSize; indexChannel++) { + + int channelId = 0; + getChannel(tracks2, indexChannel, channelId, fitType); + auto phi2 = getPhiFT0(channelId, fitType); + auto eta2 = getEtaFT0(channelId, fitType); + float deltaPhi = phi1 - phi2; + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); // set range of delta phi in (-pi/2 , 3/2*pi) + + if (!fillingHFcontainer) { + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, + triggerWeight * associatedWeight); + } else { + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, invmass, + triggerWeight * associatedWeight); + } + + // FILL QA PLOTS for associated particle + if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + if constexpr (!std::is_same_v) { // If not FilteredMftTracks as trigger -> TPC-Ft0a correlations + if constexpr (std::is_same_v) { // IF D0 CASE -> TPC-FV0a D0-h + if (fitType == isFT0A) { + fillAssociatedQa(multiplicity, eta2, phi2); + } + if (fitType == isFT0C) { + fillAssociatedQa(multiplicity, eta2, phi2); + } + } else if constexpr (std::is_same_v) { // IF LC CASE -> TPC-FV0a Lc-h + if (fitType == isFT0A) { + fillAssociatedQa(multiplicity, eta2, phi2); + } + if (fitType == isFT0C) { + fillAssociatedQa(multiplicity, eta2, phi2); + } + } else if constexpr (std::is_same_v) { // IF NEITHER D0 NOR LC -> ch. part. - ch. part + if (fitType == isFT0A) { + fillAssociatedQa(multiplicity, eta2, phi2); + } + if (fitType == isFT0C) { + fillAssociatedQa(multiplicity, eta2, phi2); + } + } + } else if constexpr (std::is_same_v) { // If FilteredMftTracks as trigger -> MFT-Ft0a (non reassoc/ambiguous) correlations + if (fitType == isFT0A) { + fillAssociatedQa(multiplicity, eta2, phi2); + } + } + } // end of if condition to fill QA plots for associated particle + } // end of loop over FT0 channel indices + } // end of if condition for FT0s + } // end of loop over tracks 1 + } + + template + void fillCorrelationsFITReassociatedMftTracks(TTarget target, CorrelationContainer::CFStep step, + TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TFits const&, + float multiplicity, float posZ, bool sameEvent, bool cutAmbiguousTracks, int fitType) + { + auto triggerWeight = 1; + auto associatedWeight = 1; + auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision + + // TRIGGER PARTICLE + for (auto const& track1 : tracks1) { + loopCounter++; + + auto reassociatedMftTrack = track1.template mfttrack_as(); + + if (!isAcceptedMftTrack(reassociatedMftTrack, true)) { + continue; + } + + if (isAmbiguousMftTrack(track1, false)) { + if (cutAmbiguousTracks) { + continue; + } + } + + float const eta1 = reassociatedMftTrack.eta(); + float const pt1 = reassociatedMftTrack.pt(); + float phi1 = reassociatedMftTrack.phi(); + o2::math_utils::bringTo02Pi(phi1); + + target->getTriggerHist()->Fill(step, pt1, multiplicity, posZ, triggerWeight); + + // FILL QA PLOTS for trigger particle + if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { + if constexpr (std::is_same_v) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } else if constexpr (std::is_same_v) { + if (fitType == isFT0A) { + fillTriggerQa(multiplicity, eta1, phi1, pt1); + } + } + } // end of if condition to fill QA plots for trigger particle + + // ASSOCIATED PARTICLE FOR FV0s + if constexpr (std::is_same_v) { + for (std::size_t indexChannel = 0; indexChannel < tracks2.channel().size(); indexChannel++) { + + auto channelId = tracks2.channel()[indexChannel]; + auto phi2 = getPhiFV0(channelId); + auto eta2 = getEtaFV0(channelId); + + float deltaPhi = phi1 - phi2; + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); // set range of delta phi in (-pi/2 , 3/2*pi) + + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, + triggerWeight * associatedWeight); + + // FILL QA PLOTS for associated particle + if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + fillAssociatedQa(multiplicity, eta2, phi2); + } // end of if condition to fill QA plots for associated particle + } // end of loop over FV0 channel indices + } // end of if condition for FV0s + + // ASSOCIATED PARTICLE FOR FT0s + if constexpr (std::is_same_v) { + + // select the right channel size if it is FT0a or FT0c + std::size_t channelSize = 0; + if (fitType == isFT0C) { + channelSize = tracks2.channelC().size(); + } else if (fitType == isFT0A) { + channelSize = tracks2.channelA().size(); + } else { + LOGF(fatal, "Cor Index %d out of range", fitType); + } + + for (std::size_t indexChannel = 0; indexChannel < channelSize; indexChannel++) { + + int channelId = 0; + getChannel(tracks2, indexChannel, channelId, fitType); + auto phi2 = getPhiFT0(channelId, fitType); + auto eta2 = getEtaFT0(channelId, fitType); + float deltaPhi = phi1 - phi2; + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); // set range of delta phi in (-pi/2 , 3/2*pi) + + target->getPairHist()->Fill(step, eta1 - eta2, pt1, pt1, multiplicity, deltaPhi, posZ, + triggerWeight * associatedWeight); + + // FILL QA PLOTS for associated particle + if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + if (fitType == isFT0A) { + fillAssociatedQa(multiplicity, eta2, phi2); + } + } // end of if condition to fill QA plots for associated particle + } // end of loop over FT0 channel indices + } // end of if condition for FT0s + } // end of loop over tracks 1 + } + + template + void fillCorrelationsFt0aFt0c(TTarget target, CorrelationContainer::CFStep step, + TFT0As const& ft0as, TFT0Cs const& ft0cs, + float multiplicity, float posZ, bool sameEvent) + { + auto triggerWeight = 1; + auto associatedWeight = 1; + auto loopCounter = 0; // To avoid filling associated tracks QA many times, I fill it only for the first trigger track of the collision + + // TRIGGER PARTICLE FROM FT0A + for (std::size_t indexChannelA = 0; indexChannelA < ft0as.channelA().size(); indexChannelA++) { + loopCounter++; + int channelIdA = 0; + getChannel(ft0as, indexChannelA, channelIdA, isFT0A); + auto phiA = getPhiFT0(channelIdA, isFT0A); + auto etaA = getEtaFT0(channelIdA, isFT0A); + + target->getTriggerHist()->Fill(step, 0.f, multiplicity, posZ, triggerWeight); + + if (sameEvent && (step == CorrelationContainer::kCFStepReconstructed)) { + fillTriggerQa(multiplicity, etaA, phiA, 0.f); + } // end of fill trigger QA + + // ASSOCIATED PARTICLE FROM FT0C + for (std::size_t indexChannelC = 0; indexChannelC < ft0cs.channelC().size(); indexChannelC++) { + + int channelIdC = 0; + getChannel(ft0cs, indexChannelC, channelIdC, isFT0C); + auto phiC = getPhiFT0(channelIdC, isFT0C); + auto etaC = getEtaFT0(channelIdC, isFT0C); + float deltaPhi = RecoDecay::constrainAngle(phiA - phiC, -PIHalf); + + target->getPairHist()->Fill(step, etaA - etaC, 0.f, 0.f, multiplicity, deltaPhi, posZ, + triggerWeight * associatedWeight); + + if (sameEvent && (loopCounter == 1) && (step == CorrelationContainer::kCFStepReconstructed)) { + fillAssociatedQa(multiplicity, etaC, phiC); + } // end of fill associated QA + } // end of associated loop + } // end of trigger loop + } // end of fillCorrelationsFt0aFt0c + + // =============================================================================================================================================================================== + // mixCollisions for RECONSTRUCTED events + // =============================================================================================================================================================================== + + template + void mixCollisions(TCollisions const& collisions, CorrelationContainer::CFStep step, + TTracksTrig const& tracks1, TTracksAssoc const& tracks2, + OutputObj& corrContainer, aod::BCsWithTimestamps const&) + { + auto getMultiplicity = [this](FilteredCollisionsWSelMult::iterator const& collision) { + auto multiplicity = getMultiplicityEstimator(collision, false); + return multiplicity; + }; + + // The first one that I call "Data" should work for data and mc rec + using BinningTypeData = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getMultiplicity)>; + + BinningTypeData binningWithTracksSize{{getMultiplicity}, {configAxis.binsMixingVertex, configAxis.binsMixingMultiplicity}, true}; + auto tracksTuple = std::make_tuple(tracks1, tracks2); + Pair pair{binningWithTracksSize, configTask.nMixedEvents, -1, collisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pair) { + + if (!(isAcceptedCollision(collision1, false))) { + continue; + } + if (!(isAcceptedCollision(collision2, false))) { + continue; + } + + auto bc = collision1.template bc_as(); + const auto multiplicity = getMultiplicityEstimator(collision1, false); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + corrContainer->fillEvent(multiplicity, step); + fillCorrelations(corrContainer, step, tracks1, tracks2, multiplicity, collision1.posZ(), false, getMagneticField(bc.timestamp())); + } + } + + template + void mixCollisionsFIT(TCollisions const& collisions, CorrelationContainer::CFStep step, + TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TPreslice const& preslice, + OutputObj& corrContainer, int fitType) + { + auto getMultiplicity = [this](FilteredCollisionsWSelMult::iterator const& collision) { + auto multiplicity = getMultiplicityEstimator(collision, false); + return multiplicity; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getMultiplicity)>; + MixedBinning const binningOnVtxAndMult{{getMultiplicity}, {configAxis.binsMixingVertex, configAxis.binsMixingMultiplicity}, true}; + + for (auto const& [collision1, collision2] : soa::selfCombinations(binningOnVtxAndMult, configTask.nMixedEvents, -1, collisions, collisions)) { + + if (!isAcceptedCollision(collision1) || !isAcceptedCollision(collision2)) { + continue; + } + + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + + if constexpr (std::is_same_v) { // IF ASSOCIATED PARTICLE FROM FV0A + if (collision1.has_foundFV0() && collision2.has_foundFV0()) { + + const auto multiplicity = getMultiplicityEstimator(collision1, false); + auto slicedTriggerTracks = tracks1.sliceBy(preslice, collision1.globalIndex()); + const auto& fv0 = collision2.foundFV0(); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + corrContainer->fillEvent(multiplicity, step); + fillCorrelationsFIT(corrContainer, step, slicedTriggerTracks, fv0, tracks2, multiplicity, collision1.posZ(), false, fitType); + } + } // end of if condition for FV0s + + if constexpr (std::is_same_v) { + if (collision1.has_foundFT0() && collision2.has_foundFT0()) { + + const auto multiplicity = getMultiplicityEstimator(collision1, false); + auto slicedTriggerTracks = tracks1.sliceBy(preslice, collision1.globalIndex()); + const auto& ft0 = collision2.foundFT0(); + + corrContainer->fillEvent(multiplicity, step); + fillCorrelationsFIT(corrContainer, step, slicedTriggerTracks, ft0, tracks2, multiplicity, collision1.posZ(), false, fitType); + } + } // end of if condition for TPC-FT0 or MFT-FT0s + } // end of for loop + } + + template + void mixCollisionsFt0aFt0c(TCollisions const& collisions, CorrelationContainer::CFStep step, + TFT0as const&, TFT0cs const&, + OutputObj& corrContainer) + { + auto getMultiplicity = [this](FilteredCollisionsWSelMult::iterator const& collision) { + auto multiplicity = getMultiplicityEstimator(collision, false); + return multiplicity; + }; + + using MixedBinning = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getMultiplicity)>; + MixedBinning const binningOnVtxAndMult{{getMultiplicity}, {configAxis.binsMixingVertex, configAxis.binsMixingMultiplicity}, true}; + + for (auto const& [collision1, collision2] : soa::selfCombinations(binningOnVtxAndMult, configTask.nMixedEvents, -1, collisions, collisions)) { + + if (!isAcceptedCollision(collision1) || !isAcceptedCollision(collision2)) { + continue; + } + + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + + if (collision1.has_foundFT0() && collision2.has_foundFT0()) { + + const auto multiplicity = getMultiplicityEstimator(collision1, false); + const auto& ft0as = collision1.foundFT0(); + const auto& ft0cs = collision2.foundFT0(); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + corrContainer->fillEvent(multiplicity, step); + fillCorrelationsFt0aFt0c(corrContainer, step, ft0as, ft0cs, multiplicity, collision1.posZ(), true); + } + } // end of for loop + } + + // =================================================================================================================================================================================================================================================================== + // =================================================================================================================================================================================================================================================================== + // SAME EVENT PROCESS FUNCTIONS + // =================================================================================================================================================================================================================================================================== + // =================================================================================================================================================================================================================================================================== + + // =================================================================================================================================================================================================================================================================== + // DATA + // =================================================================================================================================================================================================================================================================== + + // ===================================== + // DATA : process same event correlations: TPC-TPC h-h case + // ===================================== + + void processSameTpcTpcChCh(FilteredCollisionsWSelMult::iterator const& collision, + FilteredTracksWDcaSel const& tracks, + aod::BCsWithTimestamps const&) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + registry.fill(HIST("Data/hNTracks"), tracks.size()); + auto bc = collision.template bc_as(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + } + 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, + FilteredTracksWDcaSel const& tracks, + HfCandidatesSelD0 const& candidates, + aod::BCsWithTimestamps const&) + { + auto fillEventSelectionPlots = true; + + // When doing reference flow, two cases are used (HF-h, h-h) and thus eventSelectionPlots was filled twice + if (configTask.doReferenceFlow) { + fillEventSelectionPlots = false; + } + + if (!(isAcceptedCollision(collision, fillEventSelectionPlots))) { + return; + } + + registry.fill(HIST("Data/hNTracks"), tracks.size()); + auto bc = collision.template bc_as(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcD0Ch, "DATA : Process same-event correlations for TPC-TPC D0-h case", false); + + // ===================================== + // DATA : process same event correlations: TPC-TPC HF-h case for Lc + // ===================================== + + void processSameTpcTpcLcCh(FilteredCollisionsWSelMult::iterator const& collision, + FilteredTracksWDcaSel const& tracks, + HfCandidatesSelLc const& candidates, + aod::BCsWithTimestamps const&) + { + auto fillEventSelectionPlots = true; + + // When doing reference flow, two cases are used (HF-h, h-h) and thus eventSelectionPlots was filled twice + if (configTask.doReferenceFlow) { + fillEventSelectionPlots = false; + } + + if (!(isAcceptedCollision(collision, fillEventSelectionPlots))) { + return; + } + + registry.fill(HIST("Data/hNTracks"), tracks.size()); + auto bc = collision.template bc_as(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, tracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcLcCh, "DATA : Process same-event correlations for TPC-TPC Lc-h case", false); + + // ===================================== + // DATA : process same event correlations: TPC-MFT h-h case + // ===================================== + + void processSameTpcMftChCh(FilteredCollisionsWSelMult::iterator const& collision, + FilteredTracksWDcaSel const& tracks, + FilteredMftTracks const& mftTracks, + aod::BCsWithTimestamps const&) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + registry.fill(HIST("Data/hNTracks"), tracks.size()); + auto bc = collision.template bc_as(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChCh, "DATA : Process same-event correlations for TPC-MFT h-h case", false); + + void processSameTpcMftChChReassociated(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredTracksWDcaSel const& tracks, + FilteredMftTracks const& mftTracks) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + registry.fill(HIST("Data/hNTracks"), tracks.size()); + registry.fill(HIST("Data/Mft/hNMftTracks"), mftTracks.size()); + registry.fill(HIST("Data/Mft/hNBestCollisionFwd"), reassociatedMftTracks.size()); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChChReassociated, "DATA : Process same-event correlations for TPC-MFT h-h case reassociated", false); + + void processSameTpcMftChChReassociated3d(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredTracksWDcaSel const& tracks, + FilteredMftTracks const& mftTracks) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + registry.fill(HIST("Data/hNTracks"), tracks.size()); + registry.fill(HIST("Data/Mft/hNMftTracks"), mftTracks.size()); + registry.fill(HIST("Data/Mft/hNBestCollisionFwd"), reassociatedMftTracks.size()); + + // const auto multiplicity = collision.multNTracksPV(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChChReassociated3d, "DATA : Process same-event correlations for TPC-MFT h-h case 3d reassociated", false); + + void processSameTpcMftChChNonAmbiguous(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredTracksWDcaSel const& tracks, + FilteredMftTracks const& mftTracks) + { + if (!(isAcceptedCollision(collision, true))) { + return; // when process function has iterator + } + + registry.fill(HIST("Data/hNTracks"), tracks.size()); + registry.fill(HIST("Data/Mft/hNMftTracks"), mftTracks.size()); + registry.fill(HIST("Data/Mft/hNBestCollisionFwd"), reassociatedMftTracks.size()); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, reassociatedMftTracks, multiplicity, collision.posZ(), true, true); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChChNonAmbiguous, "DATA : Process same-event correlations for TPC-MFT h-h case with non-ambiguous tracks", false); + + // ===================================== + // DATA : process same event correlations: TPC-MFT HF-h case for D0 + // ===================================== + + void processSameTpcMftD0Ch(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelD0 const& candidates, + FilteredTracksWDcaSel const& /*tracks*/, + FilteredMftTracks const& mftTracks, + aod::BCsWithTimestamps const&) + { + auto fillEventSelectionPlots = true; + + // When doing reference flow, two cases are used (HF-h, h-h) and thus eventSelectionPlots was filled twice + if (configTask.doReferenceFlow) { + fillEventSelectionPlots = false; + } + + if (!(isAcceptedCollision(collision, fillEventSelectionPlots))) { + return; + } + + auto bc = collision.template bc_as(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftD0Ch, "DATA : Process same-event correlations for TPC-MFT D0-h case", false); + + void processSameTpcMftD0ChReassociated(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelD0 const& candidates, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&) + { + if (!(isAcceptedCollision(collision, true))) { + return; // when process function has iterator + } + + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsReassociatedMftTracks(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftD0ChReassociated, "DATA : Process same-event correlations for TPC-MFT D0-h case reassociated", false); + + // ===================================== + // DATA : process same event correlations: TPC-MFT HF-h case for Lc + // ===================================== + + void processSameTpcMftLcCh(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelLc const& candidates, + FilteredTracksWDcaSel const& /*tracks*/, + FilteredMftTracks const& mftTracks, + aod::BCsWithTimestamps const&) + { + auto fillEventSelectionPlots = true; + + // When doing reference flow, two cases are used (HF-h, h-h) and thus eventSelectionPlots was filled twice + if (configTask.doReferenceFlow) { + fillEventSelectionPlots = false; + } + + if (!(isAcceptedCollision(collision, fillEventSelectionPlots))) { + return; + } + + auto bc = collision.template bc_as(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, mftTracks, multiplicity, collision.posZ(), true, getMagneticField(bc.timestamp())); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftLcCh, "DATA : Process same-event correlations for TPC-MFT Lc-h case", false); + + void processSameTpcMftLcChReassociated(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelLc const& candidates, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&) + { + if (!(isAcceptedCollision(collision, true))) { + return; // when process function has iterator + } + + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsReassociatedMftTracks(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, reassociatedMftTracks, multiplicity, collision.posZ(), true, false); + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcMftLcChReassociated, "DATA : Process same-event correlations for TPC-MFT Lc-h case reassociated", false); + + // ===================================== + // DATA : process same event correlations: TPC-FV0A Ch. Part. - Ch. Part + // ===================================== + + void processSameTpcFv0aChCh(FilteredCollisionsWSelMult::iterator const& collision, + FilteredTracksWDcaSel const& tracks, + aod::FV0As const& fv0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFV0()) { + const auto& fv0 = collision.foundFV0(); + + registry.fill(HIST("Data/hNTracks"), tracks.size()); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, fv0, fv0as, multiplicity, collision.posZ(), true, isFV0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcFv0aChCh, "DATA : Process same-event correlations for TPC-FV0-A h-h case", false); + + // ===================================== + // DATA : process same event correlations: TPC-FV0A D0 - Ch. Part + // ===================================== + + void processSameTpcFv0aD0Ch(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelD0 const& candidates, + aod::FV0As const& fv0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFV0()) { + const auto& fv0 = collision.foundFV0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, fv0, fv0as, multiplicity, collision.posZ(), true, isFV0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcFv0aD0Ch, "DATA : Process same-event correlations for TPC-FV0-A D0-h case", false); - if (!fillingHFcontainer) { - // fill pair correlations - target->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, - eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, - triggerWeight * associatedWeight); - } else { - target->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, - eta1 - eta2, pt2, pt1, multiplicity, deltaPhi, posZ, invmass, - triggerWeight * associatedWeight); - } + // ===================================== + // DATA : process same event correlations: TPC-FV0A Lc - Ch. Part + // ===================================== + + void processSameTpcFv0aLcCh(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelLc const& candidates, + aod::FV0As const& fv0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFV0()) { + const auto& fv0 = collision.foundFV0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, fv0, fv0as, multiplicity, collision.posZ(), true, isFV0A); } } + PROCESS_SWITCH(HfTaskFlow, processSameTpcFv0aLcCh, "DATA : Process same-event correlations for TPC-FV0-A Lc-h case", false); + + // ===================================== + // DATA : process same event correlations: MFT-FV0A Ch. Part. - Ch. Part + // ===================================== - template - void mixCollisions(FilteredCollisionsWSelMult const& collisions, TTracksTrig const& tracks1, TTracksAssoc const& tracks2, TLambda getPartsSize, OutputObj& corrContainer) + void processSameMftFv0aChCh(FilteredCollisionsWSelMult::iterator const& collision, + FilteredMftTracks const& mftTracks, + aod::FV0As const& fv0as) { - using BinningType = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getPartsSize)>; - BinningType binningWithTracksSize{{getPartsSize}, {axisVertex, axisMultiplicity}, true}; - auto tracksTuple = std::make_tuple(tracks1, tracks2); - Pair pair{binningWithTracksSize, nMixedEvents, -1, collisions, tracksTuple, &cache}; + if (!(isAcceptedCollision(collision, true))) { + return; + } - for (const auto& [collision1, tracks1, collision2, tracks2] : pair) { + if (collision.has_foundFV0()) { + const auto& fv0 = collision.foundFV0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); - if (!(isCollisionSelected(collision1, false))) { - continue; + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; } - if (!(isCollisionSelected(collision2, false))) { - continue; + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, mftTracks, fv0, fv0as, multiplicity, collision.posZ(), true, isFV0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameMftFv0aChCh, "DATA : Process same-event correlations for MFT-FV0-A h-h case", false); + + void processSameMftFv0aChChReassociated(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&, + aod::FV0As const& fv0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFV0()) { + const auto& fv0 = collision.foundFV0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; } - auto binningValues = binningWithTracksSize.getBinningValues(collision1, collisions); - int bin = binningWithTracksSize.getBin(binningValues); + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, fv0, fv0as, multiplicity, collision.posZ(), true, false, isFV0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameMftFv0aChChReassociated, "DATA : Process same-event correlations for MFT-FV0a h-h case reassociated", false); + + /* + void processSameMftFv0aChChReassociated3d(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&, + aod::FV0As const& fv0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } - const auto multiplicity = tracks2.size(); // get multiplicity of charged hadrons, which is used for slicing in mixing - const auto vz = collision1.posZ(); + if (collision.has_foundFV0()) { + const auto& fv0 = collision.foundFV0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); - if constexpr (std::is_same_v) { - registry.fill(HIST("Data/TpcTpc/HfHadron/MixedEvent/hEventCountHFMixing"), bin); - fillHFMixingQA(multiplicity, vz, tracks1); - } else { - registry.fill(HIST("Data/TpcTpc/HadronHadron/MixedEvent/hEventCountMixing"), bin); - fillMixingQA(multiplicity, vz, tracks1); + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, fv0, fv0as, multiplicity, collision.posZ(), true, false, isFV0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameMftFv0aChChReassociated3d, "DATA : Process same-event correlations for MFT-FV0a h-h case 3d reassociated", false); + */ + + void processSameMftFv0aChChNonAmbiguous(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&, + aod::FV0As const& fv0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFV0()) { + const auto& fv0 = collision.foundFV0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; } - corrContainer->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillCorrelations(corrContainer, tracks1, tracks2, multiplicity, collision1.posZ()); + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, fv0, fv0as, multiplicity, collision.posZ(), true, true, isFV0A); } } + PROCESS_SWITCH(HfTaskFlow, processSameMftFv0aChChNonAmbiguous, "DATA : Process same-event correlations for MFT-FV0a h-h non-ambiguous case", false); // ===================================== - // process same event correlations: h-h case + // DATA : process same event correlations: TPC-FT0A Ch. Part. - Ch. Part // ===================================== - void processSameTpcTpcChCh(FilteredCollisionsWSelMult::iterator const& collision, - TracksWDcaSel const& tracks) + + void processSameTpcFt0aChCh(FilteredCollisionsWSelMult::iterator const& collision, + FilteredTracksWDcaSel const& tracks, + aod::FT0s const& ft0as) { - if (!(isCollisionSelected(collision, true))) { + if (!(isAcceptedCollision(collision, true))) { return; } - // the event histograms below are only filled for h-h case - // because there is a possibility of double-filling if more correlation - // 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("Data/TpcTpc/HadronHadron/SameEvent/hMultiplicity"), multiplicity); - registry.fill(HIST("Data/TpcTpc/HadronHadron/SameEvent/hVtxZ"), collision.posZ()); + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + registry.fill(HIST("Data/hNTracks"), tracks.size()); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0aChCh, "DATA : Process same-event correlations for TPC-FT0-A h-h case", false); + + // ===================================== + // DATA : process same event correlations: TPC-FT0A D0 - Ch. Part + // ===================================== + + void processSameTpcFt0aD0Ch(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelD0 const& candidates, + aod::FT0s const& ft0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } - 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); + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); - sameTPCTPCChCh->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } - fillQA(multiplicity, tracks); - fillCorrelations(sameTPCTPCChCh, tracks, tracks, multiplicity, collision.posZ()); + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + } } - PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcChCh, "Process same-event correlations for TPC-TPC h-h case", true); + PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0aD0Ch, "DATA : Process same-event correlations for TPC-FT0-A D0-h case", false); // ===================================== - // process same event correlations: HF-h case + // DATA : process same event correlations: TPC-FT0A Lc - Ch. Part // ===================================== - void processSameTpcTpcHfCh(FilteredCollisionsWSelMult::iterator const& collision, - TracksWDcaSel const& tracks, - HfCandidatesSel const& candidates) + + void processSameTpcFt0aLcCh(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelLc const& candidates, + aod::FT0s const& ft0as) { - if (!(isCollisionSelected(collision, true))) { + if (!(isAcceptedCollision(collision, true))) { return; } - const auto multiplicity = tracks.size(); - sameTPCTPCHfCh->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } - fillCandidateQA(candidates); - fillCorrelations(sameTPCTPCHfCh, candidates, tracks, multiplicity, collision.posZ()); + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + } } - PROCESS_SWITCH(HfTaskFlow, processSameTpcTpcHfCh, "Process same-event correlations for TPC-TPC HF-h case", true); + PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0aLcCh, "DATA : Process same-event correlations for TPC-FT0-A Lc-h case", false); // ===================================== - // process same event correlations: h-MFT case + // DATA : process same event correlations: TPC-FT0A Ch. Part. - Ch. Part // ===================================== - void processSameTpcMftChCh(FilteredCollisionsWSelMult::iterator const& collision, - TracksWDcaSel const& tracks, - aod::MFTTracks const& mfttracks) + + void processSameMftFt0aChCh(FilteredCollisionsWSelMult::iterator const& collision, + FilteredMftTracks const& mftTracks, + aod::FT0s const& ft0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, mftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, isFT0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameMftFt0aChCh, "DATA : Process same-event correlations for MFT-FT0-A h-h case", false); + + void processSameMftFt0aChChReassociated(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&, + aod::FT0s const& ft0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameMftFt0aChChReassociated, "DATA : Process same-event correlations for MFT-FT0-A h-h case reassociated", false); + + void processSameMftFt0aChChReassociated3d(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&, + aod::FT0s const& ft0as) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, false, isFT0A); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameMftFt0aChChReassociated3d, "DATA : Process same-event correlations for MFT-FT0-A h-h case reassociated 3d", false); + + void processSameMftFt0aChChNonAmbiguous(FilteredCollisionsWSelMult::iterator const& collision, + soa::SmallGroups const& reassociatedMftTracks, + FilteredMftTracks const&, + aod::FT0s const& ft0as) { - if (!(isCollisionSelected(collision, true))) { + if (!(isAcceptedCollision(collision, true))) { return; } - const auto multiplicity = tracks.size(); + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } - sameTPCMFTChCh->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); - fillMFTQA(multiplicity, mfttracks); - fillCorrelations(sameTPCMFTChCh, tracks, mfttracks, multiplicity, collision.posZ()); + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFITReassociatedMftTracks(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, reassociatedMftTracks, ft0, ft0as, multiplicity, collision.posZ(), true, true, isFT0A); + } } - PROCESS_SWITCH(HfTaskFlow, processSameTpcMftChCh, "Process same-event correlations for TPC-MFT h-h case", true); + PROCESS_SWITCH(HfTaskFlow, processSameMftFt0aChChNonAmbiguous, "DATA : Process same-event correlations for MFT-FT0-A h-h case non ambiguous", false); // ===================================== - // process mixed event correlations: h-h case + // DATA : process same event correlations: TPC-FT0C Ch. Part. - Ch. Part // ===================================== - void processMixedTpcTpcChCh(FilteredCollisionsWSelMult const& collisions, - TracksWDcaSel const& tracks) + + void processSameTpcFt0cChCh(FilteredCollisionsWSelMult::iterator const& collision, + FilteredTracksWDcaSel const& tracks, + aod::FT0s const& ft0cs) { - // 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); // it's cached, so slicing/grouping happens only once - auto size = associatedTracks.size(); - return size; - }; + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + registry.fill(HIST("Data/hNTracks"), tracks.size()); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } - mixCollisions(collisions, tracks, tracks, getTracksSize, mixedTPCTPCChCh); + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C); + } } - PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcChCh, "Process mixed-event correlations for TPC-TPC h-h case", true); + PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0cChCh, "DATA : Process same-event correlations for TPC-FT0C h-h case", false); // ===================================== - // process mixed event correlations: h-HF case + // DATA : process same event correlations: TPC-FT0C D0 - Ch. Part // ===================================== - void processMixedTpcTpcHfCh(FilteredCollisionsWSelMult const& collisions, - TracksWDcaSel const& tracks, - HfCandidatesSel const& candidates) + + void processSameTpcFt0cD0Ch(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelD0 const& candidates, + aod::FT0s const& ft0cs) { - // 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; - }; + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0cD0Ch, "DATA : Process same-event correlations for TPC-FT0C D0-h case", false); + + // ===================================== + // DATA : process same event correlations: TPC-FT0C D0 - Ch. Part + // ===================================== + + void processSameTpcFt0cLcCh(FilteredCollisionsWSelMult::iterator const& collision, + HfCandidatesSelLc const& candidates, + aod::FT0s const& ft0cs) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEventHf->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFIT(sameEventHf, CorrelationContainer::CFStep::kCFStepReconstructed, candidates, ft0, ft0cs, multiplicity, collision.posZ(), true, isFT0C); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameTpcFt0cLcCh, "DATA : Process same-event correlations for TPC-FT0C Lc-h case", false); + + // ===================================== + // DATA : process same event correlations: FT0A-FT0C Ch. Part. - Ch. Part + // ===================================== + + void processSameFt0aFt0cChCh(FilteredCollisionsWSelMult::iterator const& collision, + aod::FT0s const&) + { + if (!(isAcceptedCollision(collision, true))) { + return; + } + + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + const auto multiplicity = getMultiplicityEstimator(collision, true); + + if (multiplicity < configCollision.minMultiplicity || multiplicity > configCollision.maxMultiplicity) { + return; + } + + sameEvent->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelationsFt0aFt0c(sameEvent, CorrelationContainer::CFStep::kCFStepReconstructed, ft0, ft0, multiplicity, collision.posZ(), true); + } + } + PROCESS_SWITCH(HfTaskFlow, processSameFt0aFt0cChCh, "DATA : Process same-event correlations for FT0A-FT0C h-h case", false); + + // =================================================================================================================================================================================================================================================================== + // =================================================================================================================================================================================================================================================================== + // MIXED EVENT PROCESS FUNCTIONS + // =================================================================================================================================================================================================================================================================== + // =================================================================================================================================================================================================================================================================== + + // =================================================================================================================================================================================================================================================================== + // DATA + // =================================================================================================================================================================================================================================================================== + + // ===================================== + // DATA : process mixed event correlations:TPC-TPC h-h case + // ===================================== + + void processMixedTpcTpcChCh(FilteredCollisionsWSelMult const& collisions, + FilteredTracksWDcaSel const& tracks, + aod::BCsWithTimestamps const& bcs) + { + mixCollisions(collisions, CorrelationContainer::CFStep::kCFStepReconstructed, tracks, tracks, mixedEvent, bcs); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcChCh, "DATA : Process mixed-event correlations for TPC-TPC h-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-TPC HF-h case for D0 + // ===================================== + + void processMixedTpcTpcD0Ch(FilteredCollisionsWSelMult const& collisions, + FilteredTracksWDcaSel const& tracks, + HfCandidatesSelD0 const& candidates, + aod::BCsWithTimestamps const& bcs) + { + mixCollisions(collisions, CorrelationContainer::kCFStepReconstructed, candidates, tracks, mixedEventHf, bcs); + } + 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 + // ===================================== - mixCollisions(collisions, candidates, tracks, getTracksSize, mixedTPCTPCHfCh); + void processMixedTpcTpcLcCh(FilteredCollisionsWSelMult const& collisions, + FilteredTracksWDcaSel const& tracks, + HfCandidatesSelLc const& candidates, + aod::BCsWithTimestamps const& bcs) + { + mixCollisions(collisions, CorrelationContainer::kCFStepReconstructed, candidates, tracks, mixedEventHf, bcs); } - PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcHfCh, "Process mixed-event correlations for TPC-TPC HF-h case", true); + PROCESS_SWITCH(HfTaskFlow, processMixedTpcTpcLcCh, "DATA : Process mixed-event correlations for TPC-TPC Lc-h case", false); // ===================================== - // process mixed event correlations: h-MFT case + // 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; - }; + FilteredTracksWDcaSel const& tracks, + FilteredMftTracks const& mftTracks, + aod::BCsWithTimestamps const& bcs) + { + mixCollisions(collisions, CorrelationContainer::kCFStepReconstructed, tracks, mftTracks, mixedEvent, bcs); + } + 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, + FilteredMftTracks const& mftTracks, + FilteredTracksWDcaSel const& /*tracks*/, + aod::BCsWithTimestamps const& bcs) + { + mixCollisions(collisions, CorrelationContainer::kCFStepReconstructed, candidates, mftTracks, mixedEventHf, bcs); + } + 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, + FilteredMftTracks const& mftTracks, + aod::BCsWithTimestamps const& bcs) + { + mixCollisions(collisions, CorrelationContainer::kCFStepReconstructed, candidates, mftTracks, mixedEventHf, bcs); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcMftLcCh, "DATA : Process mixed-event correlations for TPC-MFT Lc-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FV0-A ch part. - ch. part. case + // ===================================== + + void processMixedTpcFv0aChCh(FilteredCollisionsWSelMult const& collisions, + FilteredTracksWDcaSel const& tracks, + aod::FV0As const& fv0as) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, tracks, fv0as, perColTracks, mixedEvent, isFV0A); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFv0aChCh, "DATA : Process mixed-event correlations for TPC-FV0-A h-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FV0-A D0 - ch. part. case + // ===================================== + + void processMixedTpcFv0aD0Ch(FilteredCollisionsWSelMult const& collisions, + HfCandidatesSelD0 const& candidates, + aod::FV0As const& fv0as) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, candidates, fv0as, perColD0s, mixedEventHf, isFV0A); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFv0aD0Ch, "DATA : Process mixed-event correlations for TPC-FV0-A D0-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FV0-A Lc - ch. part. case + // ===================================== + + void processMixedTpcFv0aLcCh(FilteredCollisionsWSelMult const& collisions, + HfCandidatesSelLc const& candidates, + aod::FV0As const& fv0as) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, candidates, fv0as, perColLcs, mixedEventHf, isFV0A); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFv0aLcCh, "DATA : Process mixed-event correlations for TPC-FV0-A Lc-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FV0-A ch part. - ch. part. case + // ===================================== + + void processMixedMftFv0aChCh(FilteredCollisionsWSelMult const& collisions, + FilteredMftTracks const& mftTracks, + aod::FV0As const& fv0as) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, mftTracks, fv0as, perColMftTracks, mixedEvent, isFV0A); + } + PROCESS_SWITCH(HfTaskFlow, processMixedMftFv0aChCh, "DATA : Process mixed-event correlations for Mft-FV0-A h-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FT0-A ch part. - ch. part. case + // ===================================== + + void processMixedTpcFt0aChCh(FilteredCollisionsWSelMult const& collisions, + FilteredTracksWDcaSel const& tracks, + aod::FT0s const& ft0s) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, tracks, ft0s, perColTracks, mixedEvent, isFT0A); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFt0aChCh, "DATA : Process mixed-event correlations for TPC-FT0-A h-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FT0-A D0 - ch. part. case + // ===================================== + + void processMixedTpcFt0aD0Ch(FilteredCollisionsWSelMult const& collisions, + HfCandidatesSelD0 const& candidates, + aod::FT0s const& ft0s) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, candidates, ft0s, perColD0s, mixedEventHf, isFT0A); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFt0aD0Ch, "DATA : Process mixed-event correlations for TPC-FT0-A D0-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FT0-A Lc - ch. part. case + // ===================================== - mixCollisions(collisions, tracks, mfttracks, getTracksSize, mixedTPCMFTChCh); + void processMixedTpcFt0aLcCh(FilteredCollisionsWSelMult const& collisions, + HfCandidatesSelLc const& candidates, + aod::FT0s const& ft0s) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, candidates, ft0s, perColLcs, mixedEventHf, isFT0A); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFt0aLcCh, "DATA : Process mixed-event correlations for TPC-FT0-A Lc-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FT0-A ch part. - ch. part. case + // ===================================== + + void processMixedMftFt0aChCh(FilteredCollisionsWSelMult const& collisions, + FilteredMftTracks const& mftTracks, + aod::FT0s const& ft0s) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, mftTracks, ft0s, perColMftTracks, mixedEvent, isFT0A); + } + PROCESS_SWITCH(HfTaskFlow, processMixedMftFt0aChCh, "DATA : Process mixed-event correlations for MFT-FT0-A h-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FT0C ch part. - ch. part. case + // ===================================== + + void processMixedTpcFt0cChCh(FilteredCollisionsWSelMult const& collisions, + FilteredTracksWDcaSel const& tracks, + aod::FT0s const& ft0s) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, tracks, ft0s, perColTracks, mixedEvent, isFT0C); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFt0cChCh, "DATA : Process mixed-event correlations for TPC-FT0C h-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FT0C D0 - ch. part. case + // ===================================== + + void processMixedTpcFt0cD0Ch(FilteredCollisionsWSelMult const& collisions, + HfCandidatesSelD0 const& candidates, + aod::FT0s const& ft0s) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, candidates, ft0s, perColD0s, mixedEventHf, isFT0C); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFt0cD0Ch, "DATA : Process mixed-event correlations for TPC-FT0C D0-h case", false); + + // ===================================== + // DATA : process mixed event correlations: TPC-FT0C Lc - ch. part. case + // ===================================== + + void processMixedTpcFt0cLcCh(FilteredCollisionsWSelMult const& collisions, + HfCandidatesSelLc const& candidates, + aod::FT0s const& ft0s) + { + mixCollisionsFIT(collisions, CorrelationContainer::kCFStepReconstructed, candidates, ft0s, perColLcs, mixedEventHf, isFT0C); + } + PROCESS_SWITCH(HfTaskFlow, processMixedTpcFt0cLcCh, "DATA : Process mixed-event correlations for TPC-FT0C Lc-h case", false); + + // ===================================== + // DATA : process mixed event correlations: FT0A-FT0C ch part. - ch. part. case + // ===================================== + + void processMixedFt0aFt0cChCh(FilteredCollisionsWSelMult const& collisions, + aod::FT0s const& ft0s) + { + mixCollisionsFt0aFt0c(collisions, CorrelationContainer::kCFStepReconstructed, ft0s, ft0s, mixedEvent); } - PROCESS_SWITCH(HfTaskFlow, processMixedTpcMftChCh, "Process mixed-event correlations for TPC-MFT h-h case", true); + PROCESS_SWITCH(HfTaskFlow, processMixedFt0aFt0cChCh, "DATA : Process mixed-event correlations for FT0A-FT0C 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..f6905e77b87 --- /dev/null +++ b/PWGHF/HFC/Utils/utilsCorrelations.h @@ -0,0 +1,234 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" + +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include + +#include + +#include + +#include +#include + +namespace o2::analysis::hf_correlations +{ +enum Region { + Default = 0, + Toward, + Away, + Transverse +}; + +enum PairSign { + SignNotDefined = 0, + LcPosTrkPos, + LcPosTrkNeg, + LcNegTrkPos, + LcNegTrkNeg +}; + +constexpr float PhiTowardMax{o2::constants::math::PIThird}; +constexpr float PhiAwayMin{2.f * o2::constants::math::PIThird}; +constexpr float PhiAwayMax{4.f * o2::constants::math::PIThird}; + +template +Region getRegion(T const deltaPhi) +{ + if (std::abs(deltaPhi) < PhiTowardMax) { + return Toward; + } + if (deltaPhi > PhiAwayMin && deltaPhi < PhiAwayMax) { + return Away; + } + 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 +} + +/// @brief Selects a candidate based on its PDG code, decay channel, and assigns the corresponding mass. +/// +/// @tparam isScCandidate Boolean template parameter: +/// - `true` to check for Sigma_c candidates +/// - `false` to check for Lambda_c candidates +/// @tparam McParticleType Type representing the MC particle, must provide `pdgCode()` and `flagMcMatchGen()` +/// +/// @param[in] particle MC particle whose PDG code and decay flag are evaluated +/// @param[out] massCand Mass of the matched candidate is set here, if a valid match is found +/// +/// @return `true` if candidate matches expected PDG and decay flag, and mass is set; `false` otherwise +template +bool matchCandAndMass(McParticleType const& particle, double& massCand) +{ + const auto pdgCand = std::abs(particle.pdgCode()); + const auto matchGenFlag = std::abs(particle.flagMcMatchGen()); + + // Validate PDG code based on candidate type + if (IsScCandidate) { + if (!(pdgCand == o2::constants::physics::Pdg::kSigmaC0 || + pdgCand == o2::constants::physics::Pdg::kSigmaCPlusPlus || + pdgCand == o2::constants::physics::Pdg::kSigmaCStar0 || + pdgCand == o2::constants::physics::Pdg::kSigmaCStarPlusPlus)) { + return false; + } + } else { + if (pdgCand != o2::constants::physics::Pdg::kLambdaCPlus) { + return false; + } + } + + // Map decay type to mass + switch (matchGenFlag) { + case o2::hf_decay::hf_cand_sigmac::DecayChannelMain::Sc0ToPKPiPi: { + massCand = o2::constants::physics::MassSigmaC0; + return true; + } + + case o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStar0ToPKPiPi: { + massCand = o2::constants::physics::MassSigmaCStar0; + return true; + } + + case o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScplusplusToPKPiPi: { + massCand = o2::constants::physics::MassSigmaCPlusPlus; + return true; + } + + case o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStarPlusPlusToPKPiPi: { + massCand = o2::constants::physics::MassSigmaCStarPlusPlus; + return true; + } + + case hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi: { + massCand = o2::constants::physics::MassLambdaCPlus; + return true; + } + + default: { + return false; + } + } +} + +// ========= 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/HFJ/CMakeLists.txt b/PWGHF/HFJ/CMakeLists.txt index bbfd7adac2b..62f88c324cf 100644 --- a/PWGHF/HFJ/CMakeLists.txt +++ b/PWGHF/HFJ/CMakeLists.txt @@ -7,4 +7,4 @@ # # In applying this license CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization -# or submit itself to any jurisdiction. +# or submit itself to any jurisdiction. \ No newline at end of file diff --git a/PWGHF/HFL/DataModel/ElectronSelectionTable.h b/PWGHF/HFL/DataModel/ElectronSelectionTable.h index ecf50e1e3de..5566f5ca6ff 100644 --- a/PWGHF/HFL/DataModel/ElectronSelectionTable.h +++ b/PWGHF/HFL/DataModel/ElectronSelectionTable.h @@ -18,11 +18,14 @@ #ifndef PWGHF_HFL_DATAMODEL_ELECTRONSELECTIONTABLE_H_ #define PWGHF_HFL_DATAMODEL_ELECTRONSELECTIONTABLE_H_ -#include "Framework/AnalysisDataModel.h" +#include +#include + +#include namespace o2::aod { -// definition of columns and tables forElectron Selection +// definition of columns and tables for electron selection namespace hf_sel_electron { DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! collisioniD of the electron track @@ -31,11 +34,11 @@ DECLARE_SOA_COLUMN(EtaTrack, etaTrack, float); //! pseudorapidit 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, rapadityTrack, float); //! rapidity 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) +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 @@ -48,11 +51,9 @@ DECLARE_SOA_COLUMN(TimeEmcCluster, timeEmcCluster, float); //! time of the 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 - +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, @@ -62,8 +63,8 @@ DECLARE_SOA_TABLE(HfSelEl, "AOD", "HFSELEL", //! Electron Informations hf_sel_electron::RapidityTrack, hf_sel_electron::DcaXYTrack, hf_sel_electron::DcaZTrack, - hf_sel_electron::TPCNSigmaElTrack, - hf_sel_electron::TOFNSigmaElTrack, + hf_sel_electron::TpcNSigmaElTrack, + hf_sel_electron::TofNSigmaElTrack, hf_sel_electron::EnergyEmcCluster, hf_sel_electron::EtaEmcCluster, hf_sel_electron::PhiEmcCluster, @@ -73,8 +74,55 @@ DECLARE_SOA_TABLE(HfSelEl, "AOD", "HFSELEL", //! Electron Informations hf_sel_electron::TimeEmcCluster, hf_sel_electron::DeltaEtaMatch, hf_sel_electron::DeltaPhiMatch, - hf_sel_electron::ISEmcal); + 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(InvariantMassEE, invariantMassEE, float); //! invariant mass of the non-Hfelectron +DECLARE_SOA_COLUMN(NElPairLS, nElPairLS, int); //! Number of Like sign electron pair +DECLARE_SOA_COLUMN(NElPairUS, nElPairUS, int); //! Number of UnLike sign electron pair +DECLARE_SOA_COLUMN(IsEmcal, isEmcal, bool); //! electron information +} // namespace hf_corr_sel_electron + +DECLARE_SOA_TABLE(HfCorrSelEl, "AOD", "HfCORRSELEL", //! Electron Informations + 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::InvariantMassEE, + hf_corr_sel_electron::NElPairLS, + hf_corr_sel_electron::NElPairUS, + 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 + 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/PWGHF/HFL/TableProducer/CMakeLists.txt b/PWGHF/HFL/TableProducer/CMakeLists.txt index 8782812337b..69f571377c8 100644 --- a/PWGHF/HFL/TableProducer/CMakeLists.txt +++ b/PWGHF/HFL/TableProducer/CMakeLists.txt @@ -11,6 +11,10 @@ o2physics_add_dpl_workflow(electron-selection-with-tpc-emcal SOURCES electronSelectionWithTpcEmcal.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(tree-creator-electron-d-c-a + SOURCES treeCreatorElectronDCA.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGHF/HFL/TableProducer/electronSelectionWithTpcEmcal.cxx b/PWGHF/HFL/TableProducer/electronSelectionWithTpcEmcal.cxx index 610a9e7a1ff..952883b3eac 100644 --- a/PWGHF/HFL/TableProducer/electronSelectionWithTpcEmcal.cxx +++ b/PWGHF/HFL/TableProducer/electronSelectionWithTpcEmcal.cxx @@ -14,25 +14,38 @@ /// \author Rashi Gupta , IIT Indore /// \author Ravindra Singh , IIT Indore -#include -#include "THnSparse.h" - -#include "DataFormatsEMCAL/AnalysisCluster.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/HFL/DataModel/ElectronSelectionTable.h" +#include "PWGJE/DataModel/EMCALClusters.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/Centrality.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/KFparticle/KFUtilities.h" -#include "PWGJE/DataModel/EMCALClusters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "PWGHF/HFL/DataModel/ElectronSelectionTable.h" +#include + +#include +#include + +#include +#include +#include using namespace o2; using namespace o2::constants::physics; @@ -40,12 +53,29 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; +const int kEtaLocal = 221; + struct HfElectronSelectionWithTpcEmcal { Produces electronSel; + Produces hfElectronSelection; + Produces hfGenElectronSel; + + // select the emcal or dcal acceptance + enum EMCalRegion { + NoAcceptance = 0, + EMCalAcceptance = 1, + DCalAcceptance = 2 + }; // 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"}; + Configurable skipNoEmcClusters{"skipNoEmcClusters", false, "Skip events with no EMCal clusters"}; + + // select the emcal or dcal acceptance + Configurable emcalRegion{"emcalRegion", 0, "Select EMCal region for filling histograms (see EMCalRegion enum)"}; // Event Selection Configurable zPvPosMax{"zPvPosMax", 10., "Maximum z of the primary vertex (cm)"}; @@ -58,15 +88,24 @@ struct HfElectronSelectionWithTpcEmcal { 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"}; + Configurable phiTrackDCalMax{"phiTrackDCalMax", 5.708f, "phi range for electron tracks associated Dcal"}; + Configurable phiTrackDCalMin{"phiTrackDCalMin", 4.5355f, "phi range for electron tracks associated Dcal"}; + Configurable phiTrackEMCalMax{"phiTrackEMCalMax", 3.3621f, "phi range for electron tracks associated Emcal"}; + Configurable phiTrackEMCalMin{"phiTrackEMCalMin", 1.3955f, "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"}; @@ -84,22 +123,10 @@ struct HfElectronSelectionWithTpcEmcal { 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"}; - - // Track and EMCal Cluster matching cut for Mc Reco - Configurable mcRecDeltaEtaMatchMin{"mcRecDeltaEtaMatchMin", -0.013f, "McReco Min Eta distance of EMCAL cluster to its closest track"}; - Configurable mcRecDeltaEtaMatchMax{"mcRecDeltaEtaMatchMax", 0.0171f, "McReco Max Eta distance of EMCAL cluster to its closest track"}; - Configurable mcRecDeltaPhiMatchMin{"mcRecDeltaPhiMatchMin", -0.022f, "McReco Min Phi distance of EMCAL cluster to its closest track"}; - Configurable mcRecDeltaPhiMatchMax{"mcRecDeltaPhiMatchMax", 0.028f, "McReco Max Phi distance of EMCAL cluster to its closest track"}; - - Configurable mcRecTimeEmcClusterMax{"mcRecTimeEmcClusterMax", 50.f, "McReco EMCal Cluster time"}; - - // Inclusive electron selection cut for Mc Reco - Configurable mcRecM02EmcClusterElectronMax{"mcRecM02EmcClusterElectronMax", 0.9f, "MC Reco max Electron EMCal Cluster M02"}; - Configurable mcRecM02EmcClusterElectronMin{"mcRecM02EmcClusterElectronMin", 0.02f, "MC Reco min Electron EMCal Cluster M02"}; - Configurable mcRecM20EmcClusterElectronMax{"mcRecM20EmcClusterElectronMax", 1000.f, "MC Reco max Electron EMCal Cluster M20"}; - Configurable mcRecM20EmcClusterElectronMin{"mcRecM20EmcClusterElectronMin", 0.0f, "MC Reco min Electron EMCal Cluster M20"}; - Configurable mcRecTpcNsigmaElectronMin{"mcRecTpcNsigmaElectronMin", -0.5f, "MC Reco min Electron TPCnsigma"}; - Configurable mcRecTpcNsigmaElectronMax{"mcRecTpcNsigmaElectronMax", 3.0f, "MC Reco max Electron TPCnsigma"}; + Configurable pdgCodeCharmMin{"pdgCodeCharmMin", 400, "Min Charm Hadron PdgCode"}; + Configurable pdgCodeCharmMax{"pdgCodeCharmMax", 600, "Max Charm Hadron PdgCode"}; + Configurable pdgCodeBeautyMin{"pdgCodeBeautyMin", 4000, "Min beauty Hadron PdgCode"}; + Configurable pdgCodeBeautyMax{"pdgCodeBeautyMax", 6000, "Max beauty Hadron PdgCode"}; using TableCollisions = o2::soa::Filtered>; using TableCollision = TableCollisions::iterator; @@ -107,40 +134,97 @@ struct HfElectronSelectionWithTpcEmcal { 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 > (uint16_t)1; + Filter collisionFilter = nabs(aod::collision::posZ) < zPvPosMax && aod::collision::numContrib > static_cast(1); PresliceUnsorted perClusterMatchedTracks = o2::aod::emcalmatchedtrack::trackId; - HistogramConfigSpec hEmcClusterInfoSpec{HistType::kTHnSparseD, {{300, 0.0, 30.0}, {100, -0.9, 0.9}, {200, 0, 6.3}, {50, 0, 50}, {1800, -900, 900}}}; - HistogramConfigSpec hDeltaPhiDeltaEtaEmcClusterTrackSpecEnergy{HistType::kTHnSparseD, {{400, -0.2, 0.2}, {400, -0.2, 0.2}, {600, -300, 300}, {300, 0.0, 30.0}}}; - HistogramConfigSpec hPIDSpec{HistType::kTHnSparseD, {{60, 0, 3}, {500, 0.0, 50.0}, {500, 0., 50.}, {300, -15, 15}, {300, 0.0, 30.0}, {400, 0, 2}, {400, 0, 2}}}; - HistogramConfigSpec hTrackAllInfoSpec{HistType::kTHnSparseD, {{480, 0, 160}, {300, -15, 15}, {500, 0., 50.}, {500, 0., 50.}, {100, -1.5, 1.5}, {100, 0, 7}, {3, 0, 3}}}; - HistogramConfigSpec hTrackInfoSpec{HistType::kTHnSparseD, {{60, 0, 3}, {480, 0, 160}, {300, -15, 15}, {500, 0., 50.}, {500, 0., 50.}, {100, -1.5, 1.5}, {100, 0, 7}}}; + // 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"}; HistogramRegistry registry{ "registry", - {{"hNevents", "No of events", {HistType::kTH1F, {{3, 1, 4}}}}, - {"hZvertex", "z vertex", {HistType::kTH1F, {{100, -100, 100}}}}, - {"hTrackInformation", "Sparse TPC info; dE/dx;n#sigma;#it{p} (GeV#it{/c});#it{p}_{T} (GeV#it{/c});#eta;#varphi;passEMcal;", hTrackAllInfoSpec}, - {"hEmcClusterInformationBefore", "EMCal Cluster Info before match; Energy (GeV);#eta;#varphi", hEmcClusterInfoSpec}, - {"hEmcClusterInformationAfter", "EMCal Cluster Info after match; Energy (GeV);#eta;#varphi", hEmcClusterInfoSpec}, - {"hPIDafterMatch", "PID Info after match; E/P; dE/dx;n#sigma;#it{p} (GeV#it{/c});#it{p}_{T} (GeV#it{/c});#eta;#varphi;", hTrackInfoSpec}, - {"hEPRatioafterPID", "E/P Ratio after PID Cuts apply only trackwodca filter", {HistType::kTH2F, {{60, 0, 3}, {100, 0, 10}}}}, - {"hPIDafterPIDcuts", "PID Info after PID cuts; E/P; #it{p} (GeV#it{/c});#it{p}_{T} (GeV#it{/c});n_{#sigma}^{e};GeV;M02;M20", hPIDSpec}, - {"hEmcClsTrkEtaPhiDiffTimeEnergy", "EmcClsTrkEtaPhiDiffTimeEnergy;#Delta#eta;#Delta#varphi;Sec; Energy (GeV)", hDeltaPhiDeltaEtaEmcClusterTrackSpecEnergy}}}; - - void init(InitContext&) + {}}; + + void init(o2::framework::InitContext&) { - registry.get(HIST("hTrackInformation"))->Sumw2(); - registry.get(HIST("hEmcClusterInformationBefore"))->Sumw2(); - registry.get(HIST("hEmcClusterInformationAfter"))->Sumw2(); - registry.get(HIST("hPIDafterMatch"))->Sumw2(); - registry.get(HIST("hPIDafterPIDcuts"))->Sumw2(); - registry.get(HIST("hEmcClsTrkEtaPhiDiffTimeEnergy"))->Sumw2(); + AxisSpec const axisPosZ = {binsPosZ, "Pos Z"}; + AxisSpec axisMass = {binsMass, "Mass (GeV/#it{c}^{2}); entries"}; + AxisSpec axisPt = {binsPt, "#it{p_{T}}(GeV/#it{c})"}; + AxisSpec axisEta = {binsEta, "#it{#eta}"}; + AxisSpec axisPhi = {binsPhi, "#it{#varphi}"}; + AxisSpec axisdEdx = {binsdEdx, "dE/dX"}; + AxisSpec axisnSigma = {binsnSigma, "it{#sigma_{TPC}}"}; + AxisSpec axisM02 = {binsM02, "M02; entries"}; + AxisSpec axisM20 = {binsM20, "M20; entries"}; + AxisSpec axisEoP = {binsEoP, "E/p"}; + AxisSpec axisEmcEnergy = {binsEmcEnergy, "Cluster Energy (GeV/#it{c}^{2})"}; + AxisSpec axisEmcClsNCells = {binsEmcClsNCells, "nCell"}; + AxisSpec axisEmcClsTime = {binsEmcClsTime, "Cluster Time"}; + AxisSpec axisPassEMcal = {binsPassEMcal, "Pass EMcal"}; + AxisSpec axisDeltaEta = {binsDeltaEta, "#Delta #eta = #eta_{trk}- #eta_{cluster}"}; + AxisSpec axisDeltaPhi = {binsDeltaPhi, "#Delta #varphi = #varphi_{trk}- #varphi_{cluster}"}; + + registry.add("hZvertex", "z vertex", {HistType::kTH1D, {axisPosZ}}); + registry.add("hNeventsAfterPassEmcal", "No of events pass the Emcal", {HistType::kTH1D, {{3, 1, 4}}}); + registry.add("hNevents", "No of events", {HistType::kTH1D, {{3, 1, 4}}}); + registry.add("hLikeMass", "Like mass", {HistType::kTH1D, {{axisMass}}}); + registry.add("hUnLikeMass", "unLike mass", {HistType::kTH1D, {{axisMass}}}); + registry.add("hLikeSignPt", "Like sign Momentum ", {HistType::kTH1D, {{axisPt}}}); + registry.add("hUnLikeSignPt", "UnLike sign Momentum", {HistType::kTH1D, {{axisPt}}}); + registry.add("hMcgenInElectron", "Mc Gen Inclusive Electron", {HistType::kTH1D, {{axisPt}}}); + registry.add("hMcgenAllNonHfeElectron", "Mc Gen All NonHf Electron", {HistType::kTH1D, {{axisPt}}}); + registry.add("hMcgenNonHfeElectron", "Mc Gen NonHf Electron with mother", {HistType::kTH1D, {{axisPt}}}); + registry.add("hPi0eEmbTrkPt", "Mc Gen Pi0 mother NonHf Electron", {HistType::kTH1D, {{axisPt}}}); + + registry.add("hEtaeEmbTrkPt", "Mc Gen Eta mother NonHf Electron", {HistType::kTH1D, {{axisPt}}}); + registry.add("hEmcClusterM02", "m02", {HistType::kTH1D, {{axisM02}}}); + registry.add("hEmcClusterM20", "m20", {HistType::kTH1D, {{axisM20}}}); + registry.add("hTrackEtaPhi", "TPC EtaPhi Info; #eta;#varphi;passEMcal;", {HistType::kTH3F, {{axisEta}, {axisPhi}, {axisPassEMcal}}}); + registry.add("hTrackEnergyLossVsP", " TPC Energy loss info vs P; dE/dx;#it{p} (GeV#it{/c});passEMcal;", {HistType::kTH3F, {{axisdEdx}, {axisPt}, {axisPassEMcal}}}); + registry.add("hTrackEnergyLossVsPt", "TPC Energy loss info vs Pt; dE/dx;#it{p}_{T} (GeV#it{/c});passEMcal;", {HistType::kTH3F, {{axisdEdx}, {axisPt}, {axisPassEMcal}}}); + registry.add("hTracknSigmaVsP", " TPC nSigma info vs P; n#sigma;#it{p} (GeV#it{/c});passEMcal;", {HistType::kTH3F, {{axisnSigma}, {axisPt}, {axisPassEMcal}}}); + registry.add("hTracknSigmaVsPt", " TPC nSigma info vs Pt; n#sigma;#it{p}_{T} (GeV#it{/c});passEMcal;", {HistType::kTH3F, {{axisnSigma}, {axisPt}, {axisPassEMcal}}}); + registry.add("hEmcClusterEnergy", "EMCal Cluster Info before match Energy; Energy (GeV); entries;", {HistType::kTH1D, {{axisEmcEnergy}}}); + registry.add("hEmcClusterEtaPhi", "EMCal Cluster Info before match Eta and Phi; #eta;#varphi;", {HistType::kTH2F, {{axisEta}, {axisPhi}}}); + registry.add("hEmcClusterEnergyCell", "EMCal Cluster Info before match Energy vs nCells; Energy (GeV);ncell;", {HistType::kTH2F, {{axisEmcEnergy}, {axisEmcClsNCells}}}); + registry.add("hEmcClusterEnergyTime", "EMCal Cluster Info before match Energy vs time; Energy (GeV); sec;", {HistType::kTH2F, {{axisEmcEnergy}, {axisEmcClsTime}}}); + registry.add("hEmcClusterAfterMatchEnergy", "EMCal Cluster Info After match Energy; Energy (GeV); entries;", {HistType::kTH1D, {{axisEmcEnergy}}}); + registry.add("hEmcClusterAfterMatchEtaPhi", "EMCal Cluster Info After match Eta and Phi; #eta;#varphi;", {HistType::kTH2F, {{axisEta}, {axisPhi}}}); + registry.add("hEmcClusterAfterMatchEnergyCells", "EMCal Cluster Info After match Energy vs nCells; Energy (GeV);ncell;", {HistType::kTH2F, {{axisEmcEnergy}, {axisEmcClsNCells}}}); + registry.add("hEmcClusterAfterMatchEnergyTime", "EMCal Cluster Info After match Energy vs time; Energy (GeV); sec;", {HistType::kTH2F, {{axisEmcEnergy}, {axisEmcClsTime}}}); + registry.add("hAfterMatchSigmaVsEoP", "PID Info after match EoP vs Sigma ; E/P;#it{p}_{T} (GeV#it{/c});n#sigma; m02; m20;", {HistType::kTHnSparseF, {{axisEoP}, {axisPt}, {axisnSigma}, {axisM02}, {axisM20}}}); + registry.add("hAfterMatchEoPVsP", "PID Info after match EoP vs P; E/P;#it{p} (GeV#it{/c});", {HistType::kTH2F, {{axisEoP}, {axisPt}}}); + registry.add("hAfterMatchSigmaVsP", "PID Info after match Sigma vs Momentum ; n#sigma; #it{p} (GeV#it{/c}; ", {HistType::kTH2F, {{axisnSigma}, {axisPt}}}); + registry.add("hAfterMatchEtaPhi", "PID Info after match Eta vs Phi ; #eta; #varphi; ", {HistType::kTH2F, {{axisEta}, {axisPhi}}}); + registry.add("hAfterMatchEnergyLossVsP", "PID Info after match Energy loss info vs P ; dE/dx;#it{p} (GeV#it{/c});; ", {HistType::kTH2F, {{axisdEdx}, {axisPt}}}); + registry.add("hAfterMatchEnergyLossVsPt", "PID Info after match Energy loss info vs Pt ;dE/dx;#it{p}_{T} (GeV#it{/c}); ", {HistType::kTH2F, {{axisdEdx}, {axisPt}}}); + + registry.add("hAfterPIDEtaPhi", "PID Info after PID Cuts Eta vs Phi ; #eta; #varphi; ", {HistType::kTH2F, {{axisEta}, {axisPhi}}}); + registry.add("hEPRatioAfterPID", "E/P Ratio after PID Cuts apply only trackwodca filter", {HistType::kTH2F, {{axisPt}, {axisEmcEnergy}}}); + + registry.add("hPIDAfterPIDCuts", "PID Info after PID cuts; E/P;#it{p}_{T} (GeV#it{/c});n#sigma;m02; m20;", {HistType::kTHnSparseF, {{axisEoP}, {axisPt}, {axisnSigma}, {axisM02}, {axisM20}}}); + registry.add("hEmcClsTrkEtaPhiDiffTime", "EmcClsTrkEtaPhiDiffTime;#Delta#eta;#Delta#varphi;Sec;", {HistType::kTH3F, {{axisDeltaEta}, {axisDeltaPhi}, {axisEmcClsTime}}}); } - // Track Selection Cut template bool selTracks(T const& track) @@ -162,26 +246,167 @@ struct HfElectronSelectionWithTpcEmcal { } 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 nElPairsLS = 0; + int nElPairsUS = 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 const kfpTrack = createKFPTrackFromTrack(electron); + KFPTrack const kfpAssociatedTrack = createKFPTrackFromTrack(pTrack); + KFParticle const kfTrack(kfpTrack, pdgE1); + KFParticle const kfAssociatedTrack(kfpAssociatedTrack, pdgE2); + const KFParticle* electronPairs[2] = {&kfTrack, &kfAssociatedTrack}; + kfNonHfe.SetConstructMethod(2); + kfNonHfe.Construct(electronPairs, 2); + + int const ndf = kfNonHfe.GetNDF(); + double const 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; + ++nElPairsLS; + if (isEMcal) { + registry.fill(HIST("hLikeSignPt"), electron.pt()); + } + } + // for unlike charge + if (isULSElectron && (invMassElectron <= invariantMass)) { + massUnLike = invMassElectron; + ++nElPairsUS; + 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(), invMassElectron, nElPairsLS, nElPairsUS, isEMcal); + } // Electron Identification - template + 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)))) + if (!(isRun3 ? collision.sel8() : (collision.sel7() && collision.alias_bit(kINT7)))) { return; + } - registry.fill(HIST("hNevents"), 1); - registry.fill(HIST("hZvertex"), collision.posZ()); + registry.fill(HIST("hNevents"), emcalRegion.value); + // skip events with no clusters + if (emcClusters.size() == 0 && skipNoEmcClusters) { + return; + } + registry.fill(HIST("hZvertex"), collision.posZ()); + registry.fill(HIST("hNeventsAfterPassEmcal"), static_cast(emcalRegion)); ///////////////////////////////// // EMCal cluster info before match /// /////////////////////////////// if (fillEmcClusterInfo) { for (const auto& emcClusterBefore : emcClusters) { - registry.fill(HIST("hEmcClusterInformationBefore"), emcClusterBefore.energy(), emcClusterBefore.eta(), emcClusterBefore.phi(), emcClusterBefore.nCells(), emcClusterBefore.time()); + 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; + EMCalRegion passEMCal = NoAcceptance; float phiTrack = -999; float etaTrack = -999; float pTrack = -999; @@ -191,7 +416,6 @@ struct HfElectronSelectionWithTpcEmcal { float tpcNsigmaTrack = -999; for (const auto& track : tracks) { - phiTrack = track.phi(); etaTrack = track.eta(); pTrack = track.p(); @@ -199,20 +423,24 @@ struct HfElectronSelectionWithTpcEmcal { 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 - - registry.fill(HIST("hTrackInformation"), track.tpcSignal(), tpcNsigmaTrack, pTrack, ptTrack, etaTrack, phiTrack, passEMCal); // track infor after filter bit + if ((phiTrack > phiTrackEMCalMin && phiTrack < phiTrackEMCalMax) && (etaTrack > etaTrackMin && etaTrack < etaTrackMax)) { + passEMCal = EMCalAcceptance; // EMcal acceptance passed + } + if ((phiTrack > phiTrackDCalMin && phiTrack < phiTrackDCalMax) && ((etaTrack > etaTrackDCalPositiveMin && etaTrack < etaTrackDCalPositiveMax) || (etaTrack > etaTrackDCalNegativeMin && etaTrack < etaTrackDCalNegativeMax))) { + passEMCal = DCalAcceptance; // 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; @@ -229,7 +457,7 @@ struct HfElectronSelectionWithTpcEmcal { float deltaPhiMatch = -999.; float deltaEtaMatch = -999.; float eop = -999; - bool isEMcal = false; + bool const isEMcal = false; float trackRapidity = track.rapidity(MassElectron); @@ -252,60 +480,60 @@ struct HfElectronSelectionWithTpcEmcal { timeEmcCluster = emcCluster.time(); cellEmcCluster = emcCluster.nCells(); - deltaPhiMatch = matchTrack.trackPhiEmcal() - phiMatchEmcCluster; - deltaEtaMatch = matchTrack.trackEtaEmcal() - etaMatchEmcCluster; + deltaPhiMatch = ematchTrack.deltaPhi(); + deltaEtaMatch = ematchTrack.deltaEta(); // Track and EMCal cluster Matching - - if constexpr (!isMc) { - if (std::abs(timeEmcCluster) > timeEmcClusterMax) { - continue; - } - if (deltaPhiMatch < deltaPhiMatchMin || deltaPhiMatch > deltaPhiMatchMax || deltaEtaMatch < deltaEtaMatchMin || deltaEtaMatch > deltaEtaMatchMax) { - continue; - } - } else { - if (std::abs(timeEmcCluster) > mcRecTimeEmcClusterMax) { - continue; - } - if (deltaPhiMatch < mcRecDeltaPhiMatchMin || deltaPhiMatch > mcRecDeltaPhiMatchMax || deltaEtaMatch < mcRecDeltaEtaMatchMin || deltaEtaMatch > mcRecDeltaEtaMatchMax) { - continue; - } + if (std::abs(timeEmcCluster) > timeEmcClusterMax) { + continue; + } + if (deltaPhiMatch < deltaPhiMatchMin || deltaPhiMatch > deltaPhiMatchMax || deltaEtaMatch < deltaEtaMatchMin || deltaEtaMatch > deltaEtaMatchMax) { + continue; } - registry.fill(HIST("hEmcClsTrkEtaPhiDiffTimeEnergy"), deltaEtaMatch, deltaPhiMatch, timeEmcCluster, eMatchEmcCluster); + 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 + } - if (fillEmcClusterInfo) - registry.fill(HIST("hEmcClusterInformationAfter"), eMatchEmcCluster, etaMatchEmcCluster, phiMatchEmcCluster, cellEmcCluster, timeEmcCluster); eop = eMatchEmcCluster / pMatchTrack; - registry.fill(HIST("hPIDafterMatch"), eop, matchTrack.tpcSignal(), tpcNsigmaMatchTrack, pMatchTrack, ptMatchTrack, etaMatchTrack, phiMatchTrack); + 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 constexpr (!isMc) { - if ((tpcNsigmaMatchTrack < tpcNsigmaElectronMin || tpcNsigmaMatchTrack > tpcNsigmaElectronMax) || (m02MatchEmcCluster < m02EmcClusterElectronMin || m02MatchEmcCluster > m02EmcClusterElectronMax) || (m20MatchEmcCluster < m20EmcClusterElectronMin || m20MatchEmcCluster > m20EmcClusterElectronMax)) { - continue; - } - } else { - if ((tpcNsigmaMatchTrack < mcRecTpcNsigmaElectronMin || tpcNsigmaMatchTrack > mcRecTpcNsigmaElectronMax) || (m02MatchEmcCluster < mcRecM02EmcClusterElectronMin || m02MatchEmcCluster > mcRecM02EmcClusterElectronMax) || (m20MatchEmcCluster < mcRecM20EmcClusterElectronMin || m20MatchEmcCluster > mcRecM20EmcClusterElectronMax)) { - continue; - } + + if ((tpcNsigmaMatchTrack < tpcNsigmaElectronMin || tpcNsigmaMatchTrack > tpcNsigmaElectronMax) || (m02MatchEmcCluster < m02EmcClusterElectronMin || m02MatchEmcCluster > m02EmcClusterElectronMax) || (m20MatchEmcCluster < m20EmcClusterElectronMin || m20MatchEmcCluster > m20EmcClusterElectronMax)) { + continue; } - registry.fill(HIST("hEPRatioafterPID"), eop, ptMatchTrack); + 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; } - registry.fill(HIST("hPIDafterPIDcuts"), eop, pMatchTrack, ptMatchTrack, tpcNsigmaMatchTrack, eMatchEmcCluster, m02MatchEmcCluster, m20MatchEmcCluster); - isEMcal = true; - electronSel(matchTrack.collisionId(), matchTrack.globalIndex(), etaMatchTrack, phiMatchTrack, ptMatchTrack, pMatchTrack, trackRapidity, matchTrack.dcaXY(), matchTrack.dcaZ(), matchTrack.tpcNSigmaEl(), matchTrack.tofNSigmaEl(), + ///////////////// 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); } @@ -320,7 +548,6 @@ struct HfElectronSelectionWithTpcEmcal { 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, @@ -331,6 +558,121 @@ struct HfElectronSelectionWithTpcEmcal { fillElectronTrack(mcCollision, mcTracks, mcEmcClusters, matchedTracks, mcParticles); } PROCESS_SWITCH(HfElectronSelectionWithTpcEmcal, processMcRec, "Process MC Reco mode", false); + + void processMcGen(McGenTableCollision const& mcCollision, aod::McParticles const& mcParticles) + { + + bool isNonHfe = false; + for (const auto& particleMc : mcParticles) { + + if (!mcGensel(particleMc)) { + continue; + } + if (std::abs(particleMc.pdgCode()) == kElectron) { + + registry.fill(HIST("hMcgenInElectron"), particleMc.pt()); + bool isEmbEta = false; + bool isEmbPi0 = false; + + // Check first mother + if (particleMc.has_mothers()) { + auto const& mother = particleMc.mothers_first_as(); + + if (std::abs(mother.pdgCode()) == kEtaLocal || std::abs(mother.pdgCode()) == kPi0 || std::abs(mother.pdgCode()) == kGamma) { + registry.fill(HIST("hMcgenAllNonHfeElectron"), particleMc.pt()); + + auto const& gmother = mother.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()) == kEtaLocal) { + + if (mother.isPhysicalPrimary()) { + if ((std::abs(gmother.pdgCode()) >= pdgCodeCharmMin && std::abs(gmother.pdgCode()) < pdgCodeCharmMax) || + (std::abs(gmother.pdgCode()) >= pdgCodeBeautyMin && std::abs(gmother.pdgCode()) < pdgCodeBeautyMax)) { + continue; + } + isEmbEta = true; + } + } + + //================= eta->pi0->e ====================================== + + if (std::abs(mother.pdgCode()) == kPi0) { + if (mother.isPhysicalPrimary()) { + if ((std::abs(gmother.pdgCode()) >= pdgCodeCharmMin && std::abs(gmother.pdgCode()) < pdgCodeCharmMax) || + (std::abs(gmother.pdgCode()) >= pdgCodeBeautyMin && std::abs(gmother.pdgCode()) < pdgCodeBeautyMax)) { + continue; + } + isEmbPi0 = true; // pi0 -> e + } + if (std::abs(gmother.pdgCode()) == kEtaLocal) { + if (gmother.isPhysicalPrimary() || gmother.has_mothers()) { + auto const& ggmother = gmother.mothers_first_as(); + if ((std::abs(ggmother.pdgCode()) >= pdgCodeCharmMin && std::abs(ggmother.pdgCode()) < pdgCodeCharmMax) || + (std::abs(ggmother.pdgCode()) >= pdgCodeBeautyMin && std::abs(ggmother.pdgCode()) < pdgCodeBeautyMax)) { + continue; + } + isEmbEta = true; // eta->pi0-> e + } + } + } + + /// ==================================== eta->gamma->e and eta->pi0->gamma->e============ + if (std::abs(mother.pdgCode()) == kGamma) { + + if (std::abs(gmother.pdgCode()) == kEtaLocal) { + if (gmother.isPhysicalPrimary() || gmother.has_mothers()) { + auto const& ggmother = gmother.mothers_first_as(); + if ((std::abs(ggmother.pdgCode()) >= pdgCodeCharmMin && std::abs(ggmother.pdgCode()) < pdgCodeCharmMax) || + (std::abs(ggmother.pdgCode()) >= pdgCodeBeautyMin && std::abs(ggmother.pdgCode()) < pdgCodeBeautyMax)) { + continue; + } + isEmbEta = true; // eta->gamma-> e + } + } + if (std::abs(gmother.pdgCode()) == kPi0) { + if (gmother.isPhysicalPrimary() || gmother.has_mothers()) { + auto const& ggmother = gmother.mothers_first_as(); + if ((std::abs(ggmother.pdgCode()) >= pdgCodeCharmMin && std::abs(ggmother.pdgCode()) < pdgCodeCharmMax) || + (std::abs(ggmother.pdgCode()) >= pdgCodeBeautyMin && std::abs(ggmother.pdgCode()) < pdgCodeBeautyMax)) { + continue; + } + isEmbPi0 = true; // pi0-> gamma-> e + } + if (gmother.has_mothers()) { + auto const& ggmother = gmother.mothers_first_as(); + if (std::abs(ggmother.pdgCode()) == kEtaLocal) { + if (ggmother.isPhysicalPrimary() || ggmother.has_mothers()) { + auto const& gggmother = ggmother.mothers_first_as(); + if ((std::abs(gggmother.pdgCode()) >= pdgCodeCharmMin && std::abs(gggmother.pdgCode()) < pdgCodeCharmMax) || + (std::abs(gggmother.pdgCode()) >= pdgCodeBeautyMin && std::abs(gggmother.pdgCode()) < pdgCodeBeautyMax)) { + continue; + } + 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) diff --git a/PWGHF/HFL/TableProducer/treeCreatorElectronDCA.cxx b/PWGHF/HFL/TableProducer/treeCreatorElectronDCA.cxx new file mode 100644 index 00000000000..beeb37d8689 --- /dev/null +++ b/PWGHF/HFL/TableProducer/treeCreatorElectronDCA.cxx @@ -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 treeCreatorElectronDCA.cxx +/// \brief Basic electron DCA analysis task +/// +/// \author Martin Voelkl , University of Birmingham + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +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"}; + + 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 const 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 ((absPDGCode / 100) == 4 || (absPDGCode / 1000) == 4) { + isCharm = true; + sourcePDG = pdgCode; + } + if ((absPDGCode / 100) == 5 || (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 609213a5716..2eac2ac28b6 100644 --- a/PWGHF/HFL/Tasks/CMakeLists.txt +++ b/PWGHF/HFL/Tasks/CMakeLists.txt @@ -9,16 +9,31 @@ # 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 KFParticle::KFParticle O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-muon-charm-beauty-separation SOURCES taskMuonCharmBeautySeparation.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-single-electron + SOURCES taskSingleElectron.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-single-muon SOURCES taskSingleMuon.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-single-muon-mult + SOURCES taskSingleMuonMult.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 diff --git a/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx b/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx new file mode 100644 index 00000000000..c3729516004 --- /dev/null +++ b/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx @@ -0,0 +1,814 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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) + +#ifndef HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (required by KFParticle) +#endif + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; +using namespace o2::hf_centrality; + +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 etaTrMin{"etaTrMin", -1.0f, "minimun track eta"}; + Configurable etaTrMax{"etaTrMax", 1.0f, "maximum track eta"}; + Configurable etaEmcMax{"etaEmcMax", 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 ptAssMin{"ptAssMin", 0.15, "minimum pT cut for associated hadrons"}; + Configurable ptMatch{"ptMatch", 0.001, "pT match in Z->ee and associated tracks"}; + 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 momentumIsolationMax{"momentumIsolationMax", 0.1, "isolation cut on momentum"}; + Configurable trackIsolationMax{"trackIsolationMax", 3, "Maximum number of tracks in isolation cone"}; + + Configurable massZMin{"massZMin", 60.0, "Minimum Z mass (GeV/c^2)"}; + Configurable massZMax{"massZMax", 120.0, "Maximum Z mass (GeV/c^2)"}; + Configurable correctionPtElectron{"correctionPtElectron", 1.0, "momentum correction factor for decay electrons from Z boson"}; + + // flag for THn + Configurable isTHnElectron{"isTHnElectron", true, "Enables THn for electrons"}; + Configurable ptTHnThresh{"ptTHnThresh", 5.0, "Threshold for THn make"}; + + // Skimmed (trigger) dataset processing configurations + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", true, "Enables processing of skimmed datasets"}; + Configurable cfgTriggerName{"cfgTriggerName", "fGammaHighPtEMCAL", "Trigger of interest (comma separated for multiple)"}; + Configurable applySel8{"applySel8", true, "Apply sel8 filter or not"}; + + // CCDB service configurations + Configurable cfgCCDBPath{"cfgCCDBPath", "Users/m/mpuccio/EventFiltering/OTS/", "Path to CCDB for trigger data"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + + // KFParticle + Configurable kfConstructMethod{"kfConstructMethod", 2, "KF Construct Method"}; + Configurable chiSqNdfMax{"chiSqNdfMax", 10, "Chi2 Max for mass reco by KF particle"}; + + // Centrality estimator configuration + Configurable centralityEstimator{"centralityEstimator", CentralityEstimator::FT0M, "Centrality estimator. See CentralityEstimator for valid values."}; + Configurable enableCentralityAnalysis{"enableCentralityAnalysis", true, "Enable centrality-dependent analysis"}; + Configurable centralityMin{"centralityMin", -1, "minimum cut on centrality selection"}; + Configurable centralityMax{"centralityMax", 101, "maximum cut on centrality selection"}; + Configurable> centralityBins{"centralityBins", {0, 20, 60, 100}, "centrality bins"}; + + // QA for Z->ee + Configurable enableZeeRecoQA{"enableZeeRecoQA", false, "Enable QA for Z->ee reconstruction"}; + Configurable massZMinQA{"massZMinQA", 0.1, "minimum mass cut for Zee Reco QA"}; + // CCDB service object + Service ccdb; + + struct HfElectronCandidate { + float pt, eta, phi, dcaxyTrk, dcazTrk, eop, energyIso, momIso; + int ntrackIso, nclusterTPC, nclusterITS; + HfElectronCandidate(float ptr, float e, float ph, float dcaxy, float dcaz, float ep, float eiso, float piso, int ntrkiso, int nclstpc, int nclsits) + : pt(ptr), eta(e), phi(ph), dcaxyTrk(dcaxy), dcazTrk(dcaz), eop(ep), energyIso(eiso), momIso(piso), ntrackIso(ntrkiso), nclusterTPC(nclstpc), nclusterITS(nclsits) {} + }; + std::vector selectedElectronsIso; + std::vector selectedPositronsIso; + std::vector selectedElectronsAss; + + struct HfZeeCandidate { + float pt, eta, phi, mass, ptchild0, ptchild1; + int charge; + HfZeeCandidate(float ptr, float e, float ph, float m, int ch, float ptzee0, float ptzee1) + : pt(ptr), eta(e), phi(ph), mass(m), ptchild0(ptzee0), ptchild1(ptzee1), charge(ch) {} + }; + std::vector reconstructedZ; + using CollisionsWithCent = soa::Join; + using SelectedClusters = o2::aod::EMCALClusters; + // PbPb + // using TrackEle = o2::soa::Join; + using TrackEle = o2::soa::Join; + + // pp + // using TrackEle = o2::soa::Filtered>; + + Filter eventFilter = (applySel8 ? (o2::aod::evsel::sel8 == true) : (o2::aod::evsel::sel8 == o2::aod::evsel::sel8)); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < vtxZ); + + Filter etafilter = (aod::track::eta < etaTrMax) && (aod::track::eta > etaTrMin); + 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; + + // config axis + ConfigurableAxis confaxisPt{"confaxisPt", {100, 0, 100}, "p_{T}"}; + ConfigurableAxis confaxisPtZee{"confaxisPtZee", {60, 20, 80}, "p_{T}"}; + ConfigurableAxis confaxisPtZneg{"confaxisPtZneg", {60, 20, 80}, "p_{T,neg} (GeV/c)"}; + ConfigurableAxis confaxisPtZpos{"confaxisPtZpos", {60, 20, 80}, "p_{T,pos} (GeV/c)"}; + ConfigurableAxis confaxisEop{"confaxisEop", {300, -0.01, 1.49}, "E/p"}; + ConfigurableAxis confaxisEopZneg{"confaxisEopZneg", {300, -0.01, 1.49}, "E/p_{neg}"}; + ConfigurableAxis confaxisEopZpos{"confaxisEopZpos", {300, -0.01, 1.49}, "E/p_{pos}"}; + ConfigurableAxis confaxisIsoEnergy{"confaxisIsoEnergy", {255, 0, 2.0}, "E_{iso}"}; + ConfigurableAxis confaxisIsoEnergyZneg{"confaxisIsoEnergyZneg", {255, 0, 2.0}, "E_{iso,neg}"}; + ConfigurableAxis confaxisIsoEnergyZpos{"confaxisIsoEnergyZpos", {255, 0, 2.0}, "E_{iso,pos}"}; + ConfigurableAxis confaxisIsoMomentum{"confaxisIsoMomentum", {255, 0, 2.0}, "E_{iso}"}; + ConfigurableAxis confaxisIsoMomentumZneg{"confaxisIsoMomentumZneg", {255, 0, 1.5}, "E_{iso,neg}"}; + ConfigurableAxis confaxisIsoMomentumZpos{"confaxisIsoMomentumZpos", {255, 0, 1.5}, "E_{iso,pos}"}; + ConfigurableAxis confaxisIsoTrack{"confaxisIsoTrack", {25, -0.5, 24.5}, "Isolation Track"}; + ConfigurableAxis confaxisIsoTrackZneg{"confaxisIsoTrackZneg", {25, -0.5, 24.5}, "N_{isotrk,neg}"}; + ConfigurableAxis confaxisIsoTrackZpos{"confaxisIsoTrackZpos", {25, -0.5, 24.5}, "N_{isotrk,pos}"}; + ConfigurableAxis confaxisInvMassZgamma{"confaxisInvMassZgamma", {150, 0, 150}, "M_{ee} (GeV/c^{2})"}; + ConfigurableAxis confaxisInvMassZ{"confaxisInvMassZ", {130, 20, 150}, "M_{ee} (GeV/c^{2})"}; + ConfigurableAxis confaxisZfrag{"confaxisZfrag", {200, 0, 2.0}, "p_{T,h}/p_{T,Z}"}; + + // Histogram registry: an object to hold your registrygrams + HistogramRegistry registry{"registry"}; + + // Zorro objects for skimmed data processing + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + void init(InitContext const&) + { + // Configure CCDB + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + // CCDB path for debug + LOGF(info, "CCDB path for Zorro: %s", cfgCCDBPath.value.c_str()); + + // Setup Zorro Summary + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + // check centrality + if (centralityEstimator < CentralityEstimator::FT0A || centralityEstimator > CentralityEstimator::FV0A) { + LOGF(fatal, "Invalid centrality estimator: %d", static_cast(centralityEstimator.value)); + } + + // add configurable for CCDB path + zorro.setBaseCCDBPath(cfgCCDBPath.value); + + // define axes you want to use + const AxisSpec axisZvtx{40, -20, 20, "Zvtx"}; + const AxisSpec axisCounter{1, 0, 1, "events"}; + const AxisSpec axisEta{20, -1.0, 1.0, "#eta"}; + const AxisSpec axisDCAxyneg{150, 0, 0.3, "DCAxy_{neg}"}; + const AxisSpec axisDCAxypos{150, 0, 0.3, "DCAxy_{pos}"}; + const AxisSpec axisDCAzneg{150, 0, 0.3, "DCAz_{neg}"}; + const AxisSpec axisDCAzpos{150, 0, 0.3, "DCAz_{neg}"}; + const AxisSpec axisNclsTPCneg{20, 79.5, 159.5, "nClsTpc_{neg}"}; + const AxisSpec axisNclsTPCpos{20, 79.5, 159.5, "nClsTpc_{neg}"}; + const AxisSpec axisNclsITSneg{9, -0.5, 8.5, "nClsIts_{neg}"}; + const AxisSpec axisNclsITSpos{9, -0.5, 8.5, "nClsIts_{neg}"}; + const AxisSpec axisSectorTPCneg{360, 0, 18, "TPCsector_{neg}"}; + const AxisSpec axisSectorTPCpos{360, 0, 18, "TPCsector_{pos}"}; + const AxisSpec axisNsigma{100, -5, 5, "N#sigma"}; + const AxisSpec axisDedx{150, 0, 150, "dEdx"}; + const AxisSpec axisE{nBinsE, 0, binEmax, "Energy"}; + const AxisSpec axisM02{100, 0, 1, "M02"}; + const AxisSpec axisdPhi{100, -0.5, 0.5, "dPhi"}; + const AxisSpec axisdEta{100, -0.5, 0.5, "dEta"}; + const AxisSpec axisdR{20, 0.0, 0.2, "dR"}; + const AxisSpec axisNcell{50, 0.0, 50.0, "Ncell"}; + const AxisSpec axisPhi{350, 0, 7, "Phi"}; + const AxisSpec axisChi2{250, 0.0, 25.0, "#chi^{2}"}; + const AxisSpec axisCluster{100, 0.0, 200.0, "counts"}; + const AxisSpec axisITSNCls{10, 0.0, 10, "counts"}; + const AxisSpec axisEMCtime{100, -50.0, 50, "EMC time"}; + const AxisSpec axisTrigger{3, -0.5, 2.5, "Trigger status of zorro"}; + const AxisSpec axisDPhiZh{64, -o2::constants::math::PIHalf, 3 * o2::constants::math::PIHalf, "#Delta#phi(Z-h)"}; + const AxisSpec axisPtHadron{nBinsPt, 0, binPtmax, "p_{T,hadron} (GeV/c)"}; + const AxisSpec axisPtZ{nBinsPt, 0, binPtmax, "p_{T,Z} (GeV/c)"}; + const AxisSpec axisSign{2, -2, 2, "charge sign"}; + const AxisSpec axisCentrality{centralityBins, "centrality"}; + const AxisSpec axisEop{confaxisEop, "E/p"}; + const AxisSpec axisEopZneg{confaxisEopZneg, "E/p_{neg}"}; + const AxisSpec axisEopZpos{confaxisEopZpos, "E/p_{[pos}"}; + const AxisSpec axisPt{confaxisPt, "p_{T}"}; + const AxisSpec axisPtZee{confaxisPtZee, "p_{T}"}; + const AxisSpec axisPtZneg{confaxisPtZneg, "p_{T,neg} (GeV/c)"}; + const AxisSpec axisPtZpos{confaxisPtZpos, "p_{T,pos} (GeV/c)"}; + const AxisSpec axisIsoEnergy{confaxisIsoEnergy, "E_{iso}"}; + const AxisSpec axisIsoEnergyZneg{confaxisIsoEnergyZneg, "E_{iso}"}; + const AxisSpec axisIsoEnergyZpos{confaxisIsoEnergyZpos, "E_{iso}"}; + const AxisSpec axisIsoMomentum{confaxisIsoMomentum, "Isolation momentum(GeV/C)"}; + const AxisSpec axisIsoMomentumZneg{confaxisIsoMomentumZneg, "Isolation momentum(GeV/C)"}; + const AxisSpec axisIsoMomentumZpos{confaxisIsoMomentumZpos, "Isolation momentum(GeV/C)"}; + const AxisSpec axisIsoTrack{confaxisIsoTrack, "Isolation Track"}; + const AxisSpec axisIsoTrackZneg{confaxisIsoTrackZneg, "N_{isotrk,neg}"}; + const AxisSpec axisIsoTrackZpos{confaxisIsoTrackZpos, "N_{isotrk,pos}"}; + const AxisSpec axisInvMassZgamma{confaxisInvMassZgamma, "M_{ee} (GeV/c^{2})"}; + const AxisSpec axisInvMassZ{confaxisInvMassZ, "M_{ee} (GeV/c^{2})"}; + const AxisSpec axisZfrag{confaxisZfrag, "p_{T,h}/p_{T,Z}"}; + + // create registrygrams + registry.add("hZvtx", "Z vertex", kTH1D, {axisZvtx}); + registry.add("hEventCounterInit", "hEventCounterInit", kTH1D, {axisCounter}); + registry.add("hEventCounter", "hEventCounter", kTH1D, {axisCounter}); + registry.add("hCentrality", "Centrality distribution", kTH1D, {axisCentrality}); + 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("hEnergyNcell", "EMC cluster energy and cell", kTH2F, {{axisE}, {axisNcell}}); + registry.add("hTrMatchR", "Track EMC Match in radius", kTH2F, {{axisPt}, {axisdR}}); + 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("hInvMassZee", "invariant mass for Z ULS pair", HistType::kTHnSparseF, {axisCentrality, axisSign, axisPt, axisInvMassZgamma}); + registry.add("hKfInvMassZee", "invariant mass for Z ULS pair KFp", HistType::kTHnSparseF, {axisCentrality, axisSign, axisPt, axisInvMassZgamma}); + registry.add("hInvMassZeeQA", "QA for invariant mass for Z", HistType::kTHnSparseF, {axisInvMassZ, axisPtZneg, axisPtZpos, axisDCAxyneg, axisDCAxypos, axisDCAzpos, axisNclsTPCneg, axisNclsTPCpos, axisNclsITSneg, axisNclsITSpos, axisSectorTPCneg, axisSectorTPCneg, axisEopZneg, axisEopZpos, axisIsoEnergyZneg, axisIsoEnergyZpos, axisIsoMomentumZneg, axisIsoMomentumZpos, axisIsoTrackZneg, axisIsoTrackZpos}); + registry.add("hInvMassZeeQAbg", "QA for invariant mass for Z", HistType::kTHnSparseF, {axisInvMassZ, axisPtZneg, axisPtZpos, axisDCAxyneg, axisDCAxypos, axisDCAzpos, axisNclsTPCneg, axisNclsTPCpos, axisNclsITSneg, axisNclsITSpos, axisSectorTPCneg, axisSectorTPCneg, axisEopZneg, axisEopZpos, axisIsoEnergyZneg, axisIsoEnergyZpos, axisIsoMomentumZneg, axisIsoMomentumZpos, axisIsoTrackZneg, axisIsoTrackZpos}); + registry.add("hTHnElectrons", "electron info", HistType::kTHnSparseF, {axisPt, axisNsigma, axisM02, axisEop, axisIsoEnergy, axisIsoMomentum, axisIsoTrack, axisEta, axisDedx}); + registry.add("hTHnTrMatch", "Track EMC Match", HistType::kTHnSparseF, {axisPt, axisdPhi, axisdEta}); + + // Z-hadron correlation histograms + registry.add("hZHadronDphi", "Z-hadron #Delta#phi correlation", HistType::kTHnSparseF, {axisCentrality, axisSign, axisPtZ, axisDPhiZh, axisZfrag, axisPtHadron}); + registry.add("hZptSpectrum", "Z boson p_{T} spectrum", kTH2F, {{axisSign}, {axisPtZ}}); + + // hisotgram for EMCal trigger + registry.add("hEMCalTrigger", "EMCal trigger", kTH1D, {axisTrigger}); + } + + double getIsolatedCluster(const o2::aod::EMCALCluster& cluster, + const SelectedClusters& clusters) + { + double energySum = 0.0; + double isoEnergy = 10.0; + double const etaAssCluster = cluster.eta(); + double const phiAssCluster = cluster.phi(); + + for (const auto& associateCluster : clusters) { + // Calculate angular distances + double const dEta = associateCluster.eta() - etaAssCluster; + double dPhi = associateCluster.phi() - phiAssCluster; + + // Normalize φ difference + dPhi = RecoDecay::constrainAngle(dPhi, -o2::constants::math::PI); + + // Calculate ΔR + double const 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); + } + std::pair getIsolatedTrack(double etaEle, + double phiEle, + float pEle, + TrackEle const& tracks) + { + int trackCount = 0; + double isoMomentum = 10; + double pSum = 0.0; + // LOG(info) << "track p = " << pEle; + + for (const auto& track : tracks) { + + double const dEta = track.eta() - etaEle; + double dPhi = track.phi() - phiEle; + dPhi = RecoDecay::constrainAngle(dPhi, -o2::constants::math::PI); + + double const deltaR = std::sqrt(dEta * dEta + dPhi * dPhi); + + if (deltaR < rIsolation) { + trackCount++; + pSum += track.p(); + } + } + + // LOG(info) << "momSun = " << pSum; + if (pSum > 0) { + isoMomentum = pSum / pEle - 1.0; + } + + // LOG(info) << "isop = " << isoMomentum; + return std::make_pair(trackCount - 1, isoMomentum); + } + + void recoMassZee(const KFParticle& kfpIsoEle, + int charge, + float centrality, + TrackEle const& tracks) + { + // LOG(info) << "Invarimass cal by KF particle "; + for (const auto& track : tracks) { + + if (std::abs(track.pt() - kfpIsoEle.GetPt()) < ptMatch) { + continue; + } + if (track.pt() < ptZeeMin) { + continue; + } + if (std::abs(track.tpcNSigmaEl()) > nsigTpcMax) { + continue; + } + if (std::abs(track.eta()) > etaTrMax) { + continue; + } + int pdgAss = kElectron; + if (track.sign() > 0) { + pdgAss = kPositron; + } + auto [trackCount, isoMomentum] = getIsolatedTrack(track.eta(), track.phi(), track.p(), tracks); + if (isoMomentum > momentumIsolationMax) { + continue; + } + + KFPTrack const kfpTrackAssEle = createKFPTrackFromTrack(track); + KFParticle const kfpAssEle(kfpTrackAssEle, pdgAss); + // reco by RecoDecay + auto child1 = RecoDecayPtEtaPhi::pVector(kfpIsoEle.GetPt() * correctionPtElectron, kfpIsoEle.GetEta(), kfpIsoEle.GetPhi()); + auto child2 = RecoDecayPtEtaPhi::pVector(kfpAssEle.GetPt() * correctionPtElectron, kfpAssEle.GetEta(), kfpAssEle.GetPhi()); + double const invMassEE = RecoDecay::m(std::array{child1, child2}, std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + + registry.fill(HIST("hInvMassZee"), centrality, track.sign() * charge, kfpIsoEle.GetPt(), invMassEE); + + // reco by KFparticle + const KFParticle* electronPairs[2] = {&kfpIsoEle, &kfpAssEle}; + KFParticle zeeKF; + zeeKF.SetConstructMethod(kfConstructMethod); + zeeKF.Construct(electronPairs, 2); + // LOG(info) << "Invarimass cal by KF particle Chi2/NDF = " << zeeKF.GetChi2()/zeeKF.GetNDF(); + float const chiSqNdf = zeeKF.GetChi2() / zeeKF.GetNDF(); + if (zeeKF.GetNDF() < 1) { + continue; + } + if (zeeKF.GetChi2() < 0) { + continue; + } + if (chiSqNdf > chiSqNdfMax) { + continue; + } + float massZee, massZeeErr; + zeeKF.GetMass(massZee, massZeeErr); + registry.fill(HIST("hKfInvMassZee"), centrality, track.sign() * charge, kfpIsoEle.GetPt(), massZee); + // LOG(info) << "Invarimass cal by KF particle mass = " << massZee; + // LOG(info) << "Invarimass cal by RecoDecay = " << invMassEE; + reconstructedZ.emplace_back( + zeeKF.GetPt(), + zeeKF.GetEta(), + zeeKF.GetPhi(), + massZee, + track.sign() * charge, + kfpIsoEle.GetPt(), + kfpAssEle.GetPt()); + } + } + + // void process(soa::Filtered::iterator const& collision, + void process(soa::Filtered::iterator const& collision, + aod::BCsWithTimestamps const&, + SelectedClusters const& emcClusters, + TrackEle const& tracks, + o2::aod::EMCALMatchedTracks const& matchedtracks) + { + registry.fill(HIST("hEventCounterInit"), 0.5); + + // Get BC for this collision + auto bc = collision.bc_as(); + uint64_t const globalBC = bc.globalBC(); + int const runNumber = bc.runNumber(); + + // Initialize Zorro for the first event (once per run) + static bool isFirstEvent = true; + static int lastRunNumber = -1; + + if ((isFirstEvent || runNumber != lastRunNumber) && cfgSkimmedProcessing) { + LOGF(info, "Initializing Zorro for run %d", runNumber); + uint64_t const currentTimestamp = bc.timestamp(); + + // debug for timestamp + LOGF(info, "Using CCDB path: %s, timestamp: %llu", cfgCCDBPath.value.c_str(), currentTimestamp); + + // initialize Zorro + zorro.initCCDB(ccdb.service, runNumber, currentTimestamp, cfgTriggerName); + isFirstEvent = false; + lastRunNumber = runNumber; + + // initialize magnetic field + auto* grpo = ccdb->getForTimeStamp(ccdbPathGrpMag, currentTimestamp); + o2::base::Propagator::initFieldFromGRP(grpo); + double const magneticField = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "magneticField = " << magneticField; + if (magneticField != 0.0) { + KFParticle::SetField(magneticField); + } + } + + // Check if this is a triggered event using Zorro + bool isTriggered = true; + if (cfgSkimmedProcessing) { + isTriggered = zorro.isSelected(globalBC); + registry.fill(HIST("hEMCalTrigger"), isTriggered ? 1 : 0); + + // Skip event if not triggered and we're processing skimmed data + if (!isTriggered) { + return; + } + } + // initialze for inclusive-electron + selectedElectronsIso.clear(); + selectedPositronsIso.clear(); + selectedElectronsAss.clear(); + reconstructedZ.clear(); + + 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()); + + // Calculate centrality + float centrality = 1.0; + if (enableCentralityAnalysis) { + centrality = o2::hf_centrality::getCentralityColl(collision, centralityEstimator); + // LOG(info) << centrality; + if (centrality < centralityMin || centrality > centralityMax) { + return; + } + registry.fill(HIST("hCentrality"), centrality); + } + + for (const auto& track : tracks) { + + if (std::abs(track.eta()) > etaTrMax) { + 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; + } + + 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 eop = -0.01; + float isoEnergy = 1.0; + // track isolation + auto [trackCount, isoMomentum] = getIsolatedTrack(track.eta(), track.phi(), track.p(), tracks); + // LOG(info) << "isoMomentum = " << isoMomentum; + + if (track.pt() > ptAssMin) { + selectedElectronsAss.emplace_back( + track.pt(), + track.eta(), + track.phi(), + track.dcaXY(), + track.dcaZ(), + eop, + isoEnergy, + isoMomentum, + trackCount, + track.tpcNClsCrossedRows(), + track.itsNCls()); + } + + if (track.pt() < ptMin) { + continue; + } + + // LOG(info) << "tr phi, eta = " << track.phi() << " ; " << track.eta(); + // EMC acc + bool isEMCacceptance = true; + if (track.phi() < phiEmcMin || track.phi() > phiEmcMax) { + isEMCacceptance = false; + } + if (std::abs(track.eta()) > etaEmcMax) { + isEMCacceptance = false; + } + // LOG(info) << "EMC acc = " << isEMCacceptance; + auto tracksofcluster = matchedtracks.sliceBy(perClusterMatchedTracks, track.globalIndex()); + + double rMin = 999.9; + double dPhiMin = 999.9; + double dEtaMin = 999.9; + bool isIsolated = false; + bool isIsolatedTr = false; + + if ((tracksofcluster.size() != 0) && isEMCacceptance) { + int nMatch = 0; + for (const auto& match : tracksofcluster) { + if (match.emcalcluster_as().time() < timeEmcMin || match.emcalcluster_as().time() > timeEmcMax) { + continue; + } + + float const m02Emc = match.emcalcluster_as().m02(); + float const energyEmc = match.emcalcluster_as().energy(); + double const phiEmc = match.emcalcluster_as().phi(); + double const etaEmc = match.emcalcluster_as().eta(); + double const 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 const 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 const r = RecoDecay::sqrtSumOfSquares(dPhi, dEta); + // LOG(info) << "r match = " << r; + if (r < rMin) { + rMin = r; + dPhiMin = dPhi; + dEtaMin = dEta; + } + registry.fill(HIST("hTHnTrMatch"), match.track_as().pt(), dPhi, dEta); + registry.fill(HIST("hEMCtime"), timeEmc); + registry.fill(HIST("hEnergy"), energyEmc); + + if (std::abs(dPhi) > rMatchMax || std::abs(dEta) > rMatchMax) { + continue; + } + + registry.fill(HIST("hTrMatchR"), match.track_as().pt(), r); + registry.fill(HIST("hEnergyNcell"), energyEmc, match.emcalcluster_as().nCells()); + + const auto& cluster = match.emcalcluster_as(); + + eop = energyEmc / match.track_as().p(); + // LOG(info) << "eop = " << eop; + + isoEnergy = getIsolatedCluster(cluster, emcClusters); + + if (match.track_as().pt() > ptTHnThresh && isTHnElectron) { + registry.fill(HIST("hTHnElectrons"), match.track_as().pt(), match.track_as().tpcNSigmaEl(), m02Emc, eop, isoEnergy, isoMomentum, trackCount, track.eta(), track.tpcSignal()); + } + // LOG(info) << "E/p" << eop; + registry.fill(HIST("hEopNsigTPC"), match.track_as().tpcNSigmaEl(), eop); + if (match.emcalcluster_as().m02() < m02Min || match.emcalcluster_as().m02() > m02Max) { + continue; + } + + 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 && isoEnergy < energyIsolationMax) { + isIsolated = true; + } + if (eop > eopMin && eop < eopMax && trackCount < trackIsolationMax && isoMomentum < momentumIsolationMax) { + isIsolatedTr = true; + } + + if (isIsolated && isIsolatedTr) { + registry.fill(HIST("hEopIsolation"), match.track_as().pt(), eop); + + if (match.track_as().pt() > ptZeeMin) { + int pdgIso = kElectron; + if (match.track_as().sign() > 0) { + pdgIso = kPositron; + } + KFPTrack const kfpTrackIsoEle = createKFPTrackFromTrack(match.track_as()); + KFParticle const kfpIsoEle(kfpTrackIsoEle, pdgIso); + recoMassZee(kfpIsoEle, match.track_as().sign(), centrality, tracks); + + } // end of pt cut for e from Z + } // end if isolation cut + if (isIsolatedTr) { + registry.fill(HIST("hEopIsolationTr"), match.track_as().pt(), eop); + } + } // end of PID cut + } // end of nmatch == 0 + nMatch++; + } // end of cluster match + } // end of cluster + + if (rMin < rMatchMax) { + // LOG(info) << "R mim = " << rMin; + registry.fill(HIST("hTrMatch_mim"), dPhiMin, dEtaMin); + } + if (enableZeeRecoQA && track.pt() > ptZeeMin) { + if (track.sign() < 0) { + selectedElectronsIso.emplace_back( + track.pt(), + track.eta(), + track.phi(), + track.dcaXY(), + track.dcaZ(), + eop, + isoEnergy, + isoMomentum, + trackCount, + track.tpcNClsFound(), + track.itsNCls()); + } else { + selectedPositronsIso.emplace_back( + track.pt(), + track.eta(), + track.phi(), + track.dcaXY(), + track.dcaZ(), + eop, + isoEnergy, + isoMomentum, + trackCount, + track.tpcNClsFound(), + track.itsNCls()); + } + } + + } // end of track loop + // Z-hadron + if (!reconstructedZ.empty()) { + for (const auto& zBoson : reconstructedZ) { + // Z boson selection + if (zBoson.mass < massZMin || zBoson.mass > massZMax) { + continue; + } + registry.fill(HIST("hZptSpectrum"), zBoson.charge, zBoson.pt); + for (const auto& trackAss : selectedElectronsAss) { + if (std::abs(trackAss.pt - zBoson.ptchild0) < ptMatch) { + continue; + } + if (std::abs(trackAss.pt - zBoson.ptchild1) < ptMatch) { + continue; + } + // calculate Z-h correlation + double const deltaPhi = RecoDecay::constrainAngle(trackAss.phi - zBoson.phi, -o2::constants::math::PIHalf); + double const ptRatio = trackAss.pt / zBoson.pt; + registry.fill(HIST("hZHadronDphi"), centrality, zBoson.charge, zBoson.pt, deltaPhi, ptRatio, trackAss.pt); + } + } + } // end of Z-hadron correlation + // Z->ee QA + if (enableZeeRecoQA) { + if (!selectedElectronsIso.empty() && !selectedPositronsIso.empty()) { + // signal + for (const auto& trackEle : selectedElectronsIso) { + auto child1 = RecoDecayPtEtaPhi::pVector(trackEle.pt, trackEle.eta, trackEle.phi); + float const sectorneg = trackEle.phi / o2::constants::math::SectorSpanRad; + for (const auto& trackPos : selectedPositronsIso) { + auto child2 = RecoDecayPtEtaPhi::pVector(trackPos.pt, trackPos.eta, trackPos.phi); + double const invMass = RecoDecay::m(std::array{child1, child2}, std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + float const sectorpos = trackPos.phi / o2::constants::math::SectorSpanRad; + if (invMass > massZMinQA) { + registry.fill(HIST("hInvMassZeeQA"), invMass, trackEle.pt, trackPos.pt, trackEle.dcaxyTrk, trackPos.dcaxyTrk, trackPos.dcazTrk, trackEle.nclusterTPC, trackPos.nclusterTPC, trackEle.nclusterITS, trackPos.nclusterITS, sectorneg, sectorpos, trackEle.eop, trackPos.eop, trackEle.energyIso, trackPos.energyIso, trackEle.momIso, trackPos.momIso, trackEle.ntrackIso, trackPos.ntrackIso); + } + } + } + // bg e-e- + for (size_t i = 0; i < selectedElectronsIso.size(); ++i) { + const auto& trackEle = selectedElectronsIso[i]; + auto child1 = RecoDecayPtEtaPhi::pVector(trackEle.pt, trackEle.eta, trackEle.phi); + float const sectorneg = trackEle.phi / o2::constants::math::SectorSpanRad; + for (size_t j = i + 1; j < selectedElectronsIso.size(); ++j) { + const auto& trackEle2 = selectedElectronsIso[j]; + auto child2 = RecoDecayPtEtaPhi::pVector(trackEle2.pt, trackEle2.eta, trackEle2.phi); + float const sectorpos = trackEle2.phi / o2::constants::math::SectorSpanRad; + double const invMass = RecoDecay::m(std::array{child1, child2}, std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + if (invMass > massZMinQA) { + registry.fill(HIST("hInvMassZeeQAbg"), invMass, trackEle.pt, trackEle2.pt, trackEle.dcaxyTrk, trackEle2.dcaxyTrk, trackEle2.dcazTrk, trackEle.nclusterTPC, trackEle2.nclusterTPC, trackEle.nclusterITS, trackEle2.nclusterITS, sectorneg, sectorpos, trackEle.eop, trackEle2.eop, trackEle.energyIso, trackEle2.energyIso, trackEle.momIso, trackEle2.momIso, trackEle.ntrackIso, trackEle2.ntrackIso); + } + } + } + // bg e+e+ + for (size_t i = 0; i < selectedPositronsIso.size(); ++i) { + const auto& trackPos = selectedPositronsIso[i]; + auto child1 = RecoDecayPtEtaPhi::pVector(trackPos.pt, trackPos.eta, trackPos.phi); + float const sectorneg = trackPos.phi / o2::constants::math::SectorSpanRad; + for (size_t j = i + 1; j < selectedPositronsIso.size(); ++j) { + const auto& trackPos2 = selectedPositronsIso[j]; + auto child2 = RecoDecayPtEtaPhi::pVector(trackPos2.pt, trackPos2.eta, trackPos2.phi); + float const sectorpos = trackPos2.phi / o2::constants::math::SectorSpanRad; + double const invMass = RecoDecay::m(std::array{child1, child2}, std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron}); + if (invMass > massZMinQA) { + registry.fill(HIST("hInvMassZeeQAbg"), invMass, trackPos.pt, trackPos2.pt, trackPos.dcaxyTrk, trackPos2.dcaxyTrk, trackPos2.dcazTrk, trackPos.nclusterTPC, trackPos2.nclusterTPC, trackPos.nclusterITS, trackPos2.nclusterITS, sectorneg, sectorpos, trackPos.eop, trackPos2.eop, trackPos.energyIso, trackPos2.energyIso, trackPos.momIso, trackPos2.momIso, trackPos.ntrackIso, trackPos2.ntrackIso); + } + } + } + } // check arrays aren't empty + } // end of Z->ee QA + } // process +}; // struct HfTaskElectronWeakBoson + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFL/Tasks/taskMuonCharmBeautySeparation.cxx b/PWGHF/HFL/Tasks/taskMuonCharmBeautySeparation.cxx index cc2637cedc3..818928f5055 100644 --- a/PWGHF/HFL/Tasks/taskMuonCharmBeautySeparation.cxx +++ b/PWGHF/HFL/Tasks/taskMuonCharmBeautySeparation.cxx @@ -14,13 +14,18 @@ /// \brief Task to estimate HF->mu in the forward direction and use DCA observable to separate b-> mu, c-> mu. /// \author Shreyasi Acharya , LPC, France -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/TrackFwd.h" - #include "Common/DataModel/TrackSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include + +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -30,20 +35,20 @@ struct HfTaskMuonCharmBeautySeparation { void init(InitContext&) { - AxisSpec trackTypeAxis = {6, -0.5, 5.5, "Track Type"}; - AxisSpec ptRecoAxis = {1500, 0, 15, "#it{p}_{T}_{Reco}"}; - AxisSpec dcaxAxis = {1000, -5.0, 5.0, "DCA {x or y} (cm)"}; - AxisSpec dcaAxis = {1000, 0.0, 100.0, "DCA {xy} (cm)"}; - AxisSpec zvtxAxis = {400, -20.0, 20.0, "zvtx (cm)"}; - AxisSpec etaRecoAxis = {150, -5, -2, "#eta_{Reco}"}; - AxisSpec rAbsAxis = {100, 0, 100, "R_{abs}"}; - AxisSpec pdcaAxis = {450, 0, 450, "p_{DCA}"}; - AxisSpec chi2GlobalAxis = {170, -1.5, 150.5, "#chi^{2} global"}; - AxisSpec chi2MCHMFTAxis = {170, -1.5, 150.5, "#chi^{2} MCH-MFT"}; - AxisSpec chi2MCHMIDAxis = {170, -1.5, 150.5, "#chi^{2} MCH-MID"}; + AxisSpec const trackTypeAxis = {6, -0.5, 5.5, "Track Type"}; + AxisSpec const ptRecoAxis = {1500, 0, 15, "#it{p}_{T}_{Reco}"}; + AxisSpec const dcaxAxis = {1000, -5.0, 5.0, "DCA {x or y} (cm)"}; + AxisSpec const dcaAxis = {1000, 0.0, 100.0, "DCA {xy} (cm)"}; + AxisSpec const zvtxAxis = {400, -20.0, 20.0, "zvtx (cm)"}; + AxisSpec const etaRecoAxis = {150, -5, -2, "#eta_{Reco}"}; + AxisSpec const rAbsAxis = {100, 0, 100, "R_{abs}"}; + AxisSpec const pdcaAxis = {450, 0, 450, "p_{DCA}"}; + AxisSpec const chi2GlobalAxis = {170, -1.5, 150.5, "#chi^{2} global"}; + AxisSpec const chi2MCHMFTAxis = {170, -1.5, 150.5, "#chi^{2} MCH-MFT"}; + AxisSpec const chi2MCHMIDAxis = {170, -1.5, 150.5, "#chi^{2} MCH-MID"}; - HistogramConfigSpec HistVariable({HistType::kTHnSparseF, {ptRecoAxis, dcaxAxis, dcaxAxis, dcaAxis, zvtxAxis}}); - registry.add("hBasicDist", "", HistVariable); + HistogramConfigSpec const histVariable({HistType::kTHnSparseF, {ptRecoAxis, dcaxAxis, dcaxAxis, dcaAxis, zvtxAxis}}); + registry.add("hBasicDist", "", histVariable); registry.add("hTrackType", "hTrackType", {HistType::kTH1F, {trackTypeAxis}}); registry.add("hZvtx", "Zvtx in cm", {HistType::kTH1F, {zvtxAxis}}); registry.add("hZvtx_WithMuons", "Zvtx with muons", {HistType::kTH1F, {zvtxAxis}}); @@ -81,8 +86,9 @@ struct HfTaskMuonCharmBeautySeparation { } } registry.fill(HIST("hForwardMultiplicity"), nFwdTracks); - if (nFwdTracks > 0) + if (nFwdTracks > 0) { registry.fill(HIST("hZvtx_WithMuons"), zvtx); + } } }; diff --git a/PWGHF/HFL/Tasks/taskSingleElectron.cxx b/PWGHF/HFL/Tasks/taskSingleElectron.cxx new file mode 100644 index 00000000000..6c4d1f76833 --- /dev/null +++ b/PWGHF/HFL/Tasks/taskSingleElectron.cxx @@ -0,0 +1,563 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file taskSingleElectron.cxx +/// \brief task for electrons from heavy-flavour hadron decays +/// \author Jonghan Park (Jeonbuk National University) + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace o2; +using namespace o2::constants::math; +using namespace o2::constants::physics; +using namespace o2::framework; +using namespace o2::framework::expressions; + +enum PdgCode { + kEta = 221, + kOmega = 223, + kEtaPrime = 331 +}; + +enum SourceType { + NotElec = 0, // not electron + DirectCharm = 1, // electrons from prompt charm hadrons + DirectBeauty = 2, // electrons from primary beauty hadrons + BeautyCharm = 3, // electrons from non-prompt charm hadrons + DirectGamma = 4, // electrons from direct photon + GammaPi0 = 5, + GammaEta = 6, + GammaOmega = 7, + GammaPhi = 8, + GammaEtaPrime = 9, + GammaRho0 = 10, + GammaK0s = 11, + GammaK0l = 12, + GammaKe3 = 13, + GammaLambda0 = 14, + GammaSigma = 15, + Pi0 = 16, + Eta = 17, + Omega = 18, + Phi = 19, + EtaPrime = 20, + Rho0 = 21, + K0s = 22, + K0l = 23, + Ke3 = 24, + Lambda0 = 25, + Sigma = 26, + Else = 27 +}; + +struct HfTaskSingleElectron { + + // Produces + + // Configurable + Configurable nContribMin{"nContribMin", 2, "min number of contributors"}; + Configurable posZMax{"posZMax", 10., "max posZ cut"}; + Configurable ptTrackMax{"ptTrackMax", 10., "max pt cut"}; + Configurable ptTrackMin{"ptTrackMin", 0.5, "min pt cut"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "eta cut"}; + Configurable tpcNCrossedRowMin{"tpcNCrossedRowMin", 70, "max of TPC n cluster crossed rows"}; + Configurable tpcNClsFoundOverFindableMin{"tpcNClsFoundOverFindableMin", 0.8, "min # of TPC found/findable clusters"}; + Configurable tpcChi2perNClMax{"tpcChi2perNClMax", 4., "min # of tpc chi2 per clusters"}; + Configurable itsIBClsMin{"itsIBClsMin", 3, "min # of its clusters in IB"}; + Configurable itsChi2perNClMax{"itsChi2perNClMax", 6., "min # of tpc chi2 per clusters"}; + Configurable dcaxyMax{"dcaxyMax", 1., "max of track dca in xy"}; + Configurable dcazMax{"dcazMax", 2., "max of track dca in z"}; + Configurable tofNSigmaMax{"tofNSigmaMax", 3., "max of tof nsigma"}; + Configurable tpcNSigmaMin{"tpcNSigmaMin", -1., "min of tpc nsigma"}; + Configurable tpcNSigmaMax{"tpcNSigmaMax", 3., "max of tpc nsigma"}; + + Configurable nBinsP{"nBinsP", 1500, "number of bins of particle momentum"}; + Configurable nBinsPt{"nBinsPt", 100, "N bins in pT histo"}; + + // SliceCache + SliceCache cache; + + // using declarations + using MyCollisions = soa::Join; + using TracksEl = soa::Join; + using McTracksEl = soa::Join; + + // Filter + Filter collZFilter = nabs(aod::collision::posZ) < posZMax; + + // Partition + + // ConfigurableAxis + ConfigurableAxis axisPtEl{"axisPtEl", {VARIABLE_WIDTH, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.75f, 2.0f, 2.25f, 2.5f, 2.75f, 3.f, 3.5f, 4.0f, 5.0f, 6.0f, 8.0f, 10.0f}, "electron pt bins"}; + + // Histogram registry + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + // AxisSpec + const AxisSpec axisEvt{4, 0., 4., "nEvents"}; + const AxisSpec axisNCont{100, 0., 100., "nCont"}; + const AxisSpec axisPosZ{600, -30., 30., "Z_{pos}"}; + const AxisSpec axisEta{30, -1.5, +1.5, "#eta"}; + const AxisSpec axisP{nBinsP, 0., 15., "p_{T}"}; + const AxisSpec axisPt{nBinsPt, 0., 15., "p_{T}"}; + const AxisSpec axisNsig{800, -20., 20.}; + const AxisSpec axisTrackIp{4000, -0.2, 0.2, "dca"}; + + // create histograms + histos.add("nEvents", "Number of events", kTH1D, {{1, 0., 1.}}); + histos.add("VtxZ", "VtxZ; cm; entries", kTH1D, {axisPosZ}); + histos.add("etaTrack", "etaTrack; #eta; entries", kTH1D, {axisEta}); + histos.add("ptTrack", "#it{p}_{T} distribution of selected tracks; #it{p}_{T} (GeV/#it{c}); entries", kTH1D, {axisPt}); + + // QA plots for trigger track selection + histos.add("tpcNClsTrack", "tpcNClsTrack", kTH1D, {{200, 0, 200}}); + histos.add("tpcFoundFindableTrack", "", kTH1D, {{10, 0, 1}}); + histos.add("tpcChi2Track", "", kTH1D, {{100, 0, 10}}); + histos.add("itsIBClsTrack", "", kTH1D, {{10, 0, 10}}); + histos.add("itsChi2Track", "", kTH1D, {{50, 0, 50}}); + histos.add("dcaXYTrack", "", kTH1D, {{600, -3, 3}}); + histos.add("dcaZTrack", "", kTH1D, {{600, -3, 3}}); + + // pid + histos.add("tofNSigPt", "", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("tofNSigPtQA", "", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("tpcNSigP", "", kTH2D, {{axisP}, {axisNsig}}); + histos.add("tpcNSigPt", "", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("tpcNSigPAfterTofCut", "", kTH2D, {{axisP}, {axisNsig}}); + histos.add("tpcNSigPtAfterTofCut", "", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("tpcNSigPtQA", "", kTH2D, {{axisPtEl}, {axisNsig}}); + + // track impact parameter + histos.add("dcaTrack", "", kTH2D, {{axisPtEl}, {axisTrackIp}}); + histos.add("dcaBeauty", "", kTH2D, {{axisPtEl}, {axisTrackIp}}); + histos.add("dcaCharm", "", kTH2D, {{axisPtEl}, {axisTrackIp}}); + histos.add("dcaDalitz", "", kTH2D, {{axisPtEl}, {axisTrackIp}}); + histos.add("dcaConv", "", kTH2D, {{axisPtEl}, {axisTrackIp}}); + + // QA plots for MC + histos.add("hPdgC", "", kTH1D, {{10001, -0.5, 10000.5}}); + histos.add("hPdgB", "", kTH1D, {{10001, -0.5, 10000.5}}); + histos.add("hPdgDa", "", kTH1D, {{10001, -0.5, 10000.5}}); + histos.add("hPdgCo", "", kTH1D, {{10001, -0.5, 10000.5}}); + } + + template + bool trackSel(const TrackType& track) + { + if ((track.pt() > ptTrackMax) || (track.pt() < ptTrackMin)) { + return false; + } + if (std::abs(track.eta()) > etaTrackMax) { + return false; + } + + if (track.tpcNClsCrossedRows() < tpcNCrossedRowMin) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < tpcNClsFoundOverFindableMin) { + return false; + } + + if (track.tpcChi2NCl() > tpcChi2perNClMax) { + return false; + } + + if (!(track.itsNClsInnerBarrel() == itsIBClsMin)) { + return false; + } + + if (track.itsChi2NCl() > itsChi2perNClMax) { + return false; + } + + if (std::abs(track.dcaXY()) > dcaxyMax) { + return false; + } + + if (std::abs(track.dcaZ()) > dcazMax) { + return false; + } + + return true; + } + + template + int getElecSource(const TrackType& track, double& mpt, int& mpdg) + { + auto mcpart = track.mcParticle(); + if (std::abs(mcpart.pdgCode()) != kElectron) { + return NotElec; + } + + int motherPdg = -999; + int grmotherPdg = -999; + int ggrmotherPdg = -999; // mother, grand mother, grand grand mother pdg + int motherPt = -999.; + int grmotherPt = -999; + int ggrmotherPt = -999.; // mother, grand mother, grand grand mother pt + + auto partMother = mcpart.template mothers_as(); // first mother particle of electron + auto partMotherCopy = partMother; // copy of the first mother + auto mctrack = partMother; // will change all the time + + motherPt = partMother.front().pt(); // first mother pt + motherPdg = std::abs(partMother.front().pdgCode()); // first mother pdg + mpt = motherPt; // copy of first mother pt + mpdg = motherPdg; // copy of first mother pdg + + // check if electron from charm hadrons + if ((static_cast(motherPdg / 100.) % 10) == kCharm || (static_cast(motherPdg / 1000.) % 10) == kCharm) { + + // iterate until B hadron is found as an ancestor + while (partMother.size()) { + mctrack = partMother.front().template mothers_as(); + if (mctrack.size()) { + auto const& grmothersIdsVec = mctrack.front().mothersIds(); + + if (grmothersIdsVec.empty()) { + return DirectCharm; + } + grmotherPt = mctrack.front().pt(); + grmotherPdg = std::abs(mctrack.front().pdgCode()); + if ((static_cast(grmotherPdg / 100.) % 10) == kBottom || (static_cast(grmotherPdg / 1000.) % 10) == kBottom) { + mpt = grmotherPt; + mpdg = grmotherPdg; + return BeautyCharm; + } + } + partMother = mctrack; + } + } else if ((static_cast(motherPdg / 100.) % 10) == kBottom || (static_cast(motherPdg / 1000.) % 10) == kBottom) { // check if electron from beauty hadrons + return DirectBeauty; + } else if (motherPdg == kGamma) { // check if electron from photon conversion + mctrack = partMother.front().template mothers_as(); + if (mctrack.size()) { + auto const& grmothersIdsVec = mctrack.front().mothersIds(); + if (grmothersIdsVec.empty()) { + return DirectGamma; + } + grmotherPdg = std::abs(mctrack.front().pdgCode()); + mpdg = grmotherPdg; + mpt = mctrack.front().pt(); + + partMother = mctrack; + mctrack = partMother.front().template mothers_as(); + if (mctrack.size()) { + auto const& ggrmothersIdsVec = mctrack.front().mothersIds(); + if (ggrmothersIdsVec.empty()) { + if (grmotherPdg == kPi0) { + return GammaPi0; + } + if (grmotherPdg == PdgCode::kEta) { + return GammaEta; + } + if (grmotherPdg == PdgCode::kOmega) { + return GammaOmega; + } + if (grmotherPdg == kPhi) { + return GammaPhi; + } + if (grmotherPdg == PdgCode::kEtaPrime) { + return GammaEtaPrime; + } + if (grmotherPdg == kRho770_0) { + return GammaRho0; + } + return Else; + } + ggrmotherPdg = mctrack.front().pdgCode(); + ggrmotherPt = mctrack.front().pt(); + mpdg = ggrmotherPdg; + mpt = ggrmotherPt; + if (grmotherPdg == kPi0) { + if (ggrmotherPdg == kK0Short) { + return GammaK0s; + } + if (ggrmotherPdg == kK0Long) { + return GammaK0l; + } + if (ggrmotherPdg == kKPlus) { + return GammaKe3; + } + if (ggrmotherPdg == kLambda0) { + return GammaLambda0; + } + if (ggrmotherPdg == kSigmaPlus) { + return GammaSigma; + } + mpdg = grmotherPdg; + mpt = grmotherPt; + return GammaPi0; + } + if (grmotherPdg == PdgCode::kEta) { + mpdg = grmotherPdg; + mpt = grmotherPt; + return GammaEta; + } + if (grmotherPdg == PdgCode::kOmega) { + mpdg = grmotherPdg; + mpt = grmotherPt; + return GammaOmega; + } + if (grmotherPdg == kPhi) { + mpdg = grmotherPdg; + mpt = grmotherPt; + return GammaPhi; + } + if (grmotherPdg == PdgCode::kEtaPrime) { + mpdg = grmotherPdg; + mpt = grmotherPt; + return GammaEtaPrime; + } + if (grmotherPdg == kRho770_0) { + mpdg = grmotherPdg; + mpt = grmotherPt; + return GammaRho0; + } + return Else; + } + } + } else { // check if electron from Dalitz decays + mctrack = partMother.front().template mothers_as(); + if (mctrack.size()) { + auto const& grmothersIdsVec = mctrack.front().mothersIds(); + if (grmothersIdsVec.empty()) { + static const std::map pdgToSource = { + {kPi0, Pi0}, + {PdgCode::kEta, Eta}, + {PdgCode::kOmega, Omega}, + {kPhi, Phi}, + {PdgCode::kEtaPrime, EtaPrime}, + {kRho770_0, Rho0}, + {kKPlus, Ke3}, + {kK0Long, K0l}}; + + auto it = pdgToSource.find(motherPdg); + if (it != pdgToSource.end()) { + return it->second; + } + return Else; + } + if (motherPdg == kPi0) { + grmotherPt = mctrack.front().pt(); + grmotherPdg = mctrack.front().pdgCode(); + mpt = grmotherPt; + mpdg = grmotherPdg; + if (grmotherPdg == kK0Short) { + return K0s; + } + if (grmotherPdg == kK0Long) { + return K0l; + } + if (grmotherPdg == kKPlus) { + return Ke3; + } + if (grmotherPdg == kLambda0) { + return Lambda0; + } + if (grmotherPdg == kSigmaPlus) { + return Sigma; + } + mpt = motherPt; + mpdg = motherPdg; + return Pi0; + } + if (motherPdg == PdgCode::kEta) { + return Eta; + } + if (motherPdg == PdgCode::kOmega) { + return Omega; + } + if (motherPdg == kPhi) { + return Phi; + } + if (motherPdg == PdgCode::kEtaPrime) { + return EtaPrime; + } + if (motherPdg == kRho770_0) { + return Rho0; + } + if (motherPdg == kKPlus) { + return Ke3; + } + if (motherPdg == kK0Long) { + return K0l; + } + return Else; + } + } + + return Else; + } + + void processData(soa::Filtered::iterator const& collision, + TracksEl const& tracks) + { + float const flagAnalysedEvt = 0.5; + + if (!collision.sel8()) { + return; + } + + if (collision.numContrib() < nContribMin) { + return; + } + + histos.fill(HIST("VtxZ"), collision.posZ()); + histos.fill(HIST("nEvents"), flagAnalysedEvt); + + for (const auto& track : tracks) { + + if (!trackSel(track)) { + continue; + } + + if (!(track.passedITSRefit() && track.passedTPCRefit())) { + continue; + } + + histos.fill(HIST("etaTrack"), track.eta()); + histos.fill(HIST("ptTrack"), track.pt()); + + histos.fill(HIST("tpcNClsTrack"), track.tpcNClsCrossedRows()); + histos.fill(HIST("tpcFoundFindableTrack"), track.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("tpcChi2Track"), track.tpcChi2NCl()); + histos.fill(HIST("itsIBClsTrack"), track.itsNClsInnerBarrel()); + histos.fill(HIST("itsChi2Track"), track.itsChi2NCl()); + histos.fill(HIST("dcaXYTrack"), track.dcaXY()); + histos.fill(HIST("dcaZTrack"), track.dcaZ()); + + histos.fill(HIST("tofNSigPt"), track.pt(), track.tofNSigmaEl()); + histos.fill(HIST("tpcNSigP"), track.p(), track.tpcNSigmaEl()); + histos.fill(HIST("tpcNSigPt"), track.pt(), track.tpcNSigmaEl()); + + if (std::abs(track.tofNSigmaEl()) > tofNSigmaMax) { + continue; + } + histos.fill(HIST("tofNSigPtQA"), track.pt(), track.tofNSigmaEl()); + histos.fill(HIST("tpcNSigPAfterTofCut"), track.p(), track.tpcNSigmaEl()); + histos.fill(HIST("tpcNSigPtAfterTofCut"), track.pt(), track.tpcNSigmaEl()); + + if (track.tpcNSigmaEl() < tpcNSigmaMin || track.tpcNSigmaEl() > tpcNSigmaMax) { + continue; + } + histos.fill(HIST("tpcNSigPtQA"), track.pt(), track.tpcNSigmaEl()); + + histos.fill(HIST("dcaTrack"), track.pt(), track.dcaXY()); + } + } + PROCESS_SWITCH(HfTaskSingleElectron, processData, "For real data", true); + + void processMc(soa::Filtered::iterator const& collision, + McTracksEl const& tracks, + aod::McParticles const&) + { + float const flagAnalysedEvt = 0.5; + + if (!collision.sel8()) { + return; + } + + if (collision.numContrib() < nContribMin) { + return; + } + + histos.fill(HIST("VtxZ"), collision.posZ()); + histos.fill(HIST("nEvents"), flagAnalysedEvt); + + for (const auto& track : tracks) { + + if (!trackSel(track)) { + continue; + } + + histos.fill(HIST("etaTrack"), track.eta()); + histos.fill(HIST("ptTrack"), track.pt()); + + histos.fill(HIST("tpcNClsTrack"), track.tpcNClsCrossedRows()); + histos.fill(HIST("tpcFoundFindableTrack"), track.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("tpcChi2Track"), track.tpcChi2NCl()); + histos.fill(HIST("itsIBClsTrack"), track.itsNClsInnerBarrel()); + histos.fill(HIST("dcaXYTrack"), track.dcaXY()); + histos.fill(HIST("dcaZTrack"), track.dcaZ()); + + histos.fill(HIST("tofNSigPt"), track.pt(), track.tofNSigmaEl()); + histos.fill(HIST("tpcNSigPt"), track.pt(), track.tpcNSigmaEl()); + + int mpdg; // electron source pdg code + double mpt; // electron source pt + int const source = getElecSource(track, mpt, mpdg); + + if (source == DirectBeauty || source == BeautyCharm) { + histos.fill(HIST("hPdgB"), mpdg); + histos.fill(HIST("dcaBeauty"), track.pt(), track.dcaXY()); + } + + if (source == DirectCharm) { + histos.fill(HIST("hPdgC"), mpdg); + histos.fill(HIST("dcaCharm"), track.pt(), track.dcaXY()); + } + + if (source >= GammaPi0 && source <= GammaSigma) { + histos.fill(HIST("hPdgCo"), mpdg); + histos.fill(HIST("dcaConv"), track.pt(), track.dcaXY()); + } + + if (source >= Pi0 && source <= Sigma) { + histos.fill(HIST("hPdgDa"), mpdg); + histos.fill(HIST("dcaDalitz"), track.pt(), track.dcaXY()); + } + + if (std::abs(track.tofNSigmaEl()) > tofNSigmaMax) { + continue; + } + histos.fill(HIST("tofNSigPtQA"), track.pt(), track.tofNSigmaEl()); + histos.fill(HIST("tpcNSigPtAfterTofCut"), track.pt(), track.tpcNSigmaEl()); + + if (track.tpcNSigmaEl() < tpcNSigmaMin || track.tpcNSigmaEl() > tpcNSigmaMax) { + continue; + } + histos.fill(HIST("tpcNSigPtQA"), track.pt(), track.tpcNSigmaEl()); + + histos.fill(HIST("dcaTrack"), track.pt(), track.dcaXY()); + } + } + PROCESS_SWITCH(HfTaskSingleElectron, processMc, "For real data", false); +}; + +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..95c6e6d70e8 100644 --- a/PWGHF/HFL/Tasks/taskSingleMuon.cxx +++ b/PWGHF/HFL/Tasks/taskSingleMuon.cxx @@ -13,17 +13,23 @@ /// \brief Task used to extract the 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -56,8 +62,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"}; @@ -82,24 +88,24 @@ struct HfTaskSingleMuon { void init(InitContext&) { - AxisSpec axisPt{200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec axisEta{250, -5., 0., "#it{#eta}"}; - AxisSpec axisDCA{500, 0., 5., "#it{DCA}_{xy} (cm)"}; - AxisSpec axisChi2MatchMCHMFT{100, 0., 100., "MCH-MFT matching #chi^{2}"}; - AxisSpec axisSign{5, -2.5, 2.5, "Charge"}; - AxisSpec axisPDca{100000, 0, 100000, "#it{p} #times DCA (GeV/#it{c} * cm)"}; - AxisSpec axisVtxZ{80, -20., 20., "#it{z}_{vtx} (cm)"}; - AxisSpec axisDCAx{1000, -5., 5., "#it{DCA}_{x or y} (cm)"}; - AxisSpec axisPtDif{200, -2., 2., "#it{p}_{T} diff (GeV/#it{c})"}; - AxisSpec axisEtaDif{200, -2., 2., "#it{#eta} diff"}; - AxisSpec axisDeltaPt{60, -30, 30, "#Delta #it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisPt{200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisEta{250, -5., 0., "#it{#eta}"}; + AxisSpec const axisDCA{500, 0., 5., "#it{DCA}_{xy} (cm)"}; + AxisSpec const axisChi2MatchMCHMFT{100, 0., 100., "MCH-MFT matching #chi^{2}"}; + AxisSpec const axisSign{5, -2.5, 2.5, "Charge"}; + AxisSpec const axisPDca{100000, 0, 100000, "#it{p} #times DCA (GeV/#it{c} * cm)"}; + AxisSpec const axisVtxZ{80, -20., 20., "#it{z}_{vtx} (cm)"}; + AxisSpec const axisDCAx{1000, -5., 5., "#it{DCA}_{x or y} (cm)"}; + AxisSpec const axisPtDif{200, -2., 2., "#it{p}_{T} diff (GeV/#it{c})"}; + AxisSpec const axisEtaDif{200, -2., 2., "#it{#eta} diff"}; + AxisSpec const axisDeltaPt{60, -30, 30, "#Delta #it{p}_{T} (GeV/#it{c})"}; - HistogramConfigSpec hTHnMu{HistType::kTHnSparseF, {axisPt, axisEta, axisDCA, axisPDca, axisSign, axisChi2MatchMCHMFT}, 6}; - HistogramConfigSpec h2PtMc{HistType::kTH2F, {axisPt, axisPtDif}}; - HistogramConfigSpec h2EtaMc{HistType::kTH2F, {axisEta, axisEtaDif}}; - HistogramConfigSpec h2DCA{HistType::kTH2F, {axisDCAx, axisDCAx}}; - HistogramConfigSpec h3DeltaPt{HistType::kTH3F, {axisPt, axisEta, axisDeltaPt}}; - HistogramConfigSpec hVtxZ{HistType::kTH1F, {axisVtxZ}}; + HistogramConfigSpec const hTHnMu{HistType::kTHnSparseF, {axisPt, axisEta, axisDCA, axisPDca, axisSign, axisChi2MatchMCHMFT}, 6}; + HistogramConfigSpec const h2PtMc{HistType::kTH2F, {axisPt, axisPtDif}}; + HistogramConfigSpec const h2EtaMc{HistType::kTH2F, {axisEta, axisEtaDif}}; + HistogramConfigSpec const h2DCA{HistType::kTH2F, {axisDCAx, axisDCAx}}; + HistogramConfigSpec const h3DeltaPt{HistType::kTH3F, {axisPt, axisEta, axisDeltaPt}}; + HistogramConfigSpec const hVtxZ{HistType::kTH1F, {axisVtxZ}}; registry.add("hMuBeforeCuts", "", hTHnMu); registry.add("hMuAfterCuts", "", hTHnMu); diff --git a/PWGHF/HFL/Tasks/taskSingleMuonMult.cxx b/PWGHF/HFL/Tasks/taskSingleMuonMult.cxx new file mode 100644 index 00000000000..f755dfac5e2 --- /dev/null +++ b/PWGHF/HFL/Tasks/taskSingleMuonMult.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 taskSingleMuonMult.cxx +/// \brief Task used to study the Open heavy flavour decay muon production as a function of multiplicity. +/// \author Md Samsul Islam , IITB + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::fwdtrack; + +struct HfTaskSingleMuonMult { + + // enum for event selection bins + enum EventSelection { + AllEvents = 0, + Sel8, + VtxZAfterSel, + NEventSelection + }; + + // enum for muon track selection bins + enum MuonSelection { + NoCut = 0, + EtaCut, + RAbsorbCut, + PDcaCut, + Chi2Cut, + NMuonSelection + }; + + Configurable zVtxMax{"zVtxMax", 10., "maxium z of primary vertex [cm]"}; + Configurable ptTrackMin{"ptTrackMin", 0.15, "minimum pt of tracks"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "maximum pseudorapidity of tracks"}; + Configurable etaMin{"etaMin", -3.6, "minimum pseudorapidity"}; + Configurable etaMax{"etaMax", -2.5, "maximum pseudorapidity"}; + Configurable pDcaMin{"pDcaMin", 324., "p*DCA value for small RAbsorb"}; + Configurable pDcaMax{"pDcaMax", 594., "p*DCA value for large RAbsorb"}; + Configurable rAbsorbMin{"rAbsorbMin", 17.6, "R at absorber end minimum value"}; + Configurable rAbsorbMax{"rAbsorbMax", 89.5, "R at absorber end maximum value"}; + Configurable rAbsorbMid{"rAbsorbMid", 26.5, "R at absorber end split point for different p*DCA selections"}; + Configurable reduceOrphMft{"reduceOrphMft", true, "reduce orphan MFT tracks"}; + + using MyCollisions = soa::Join; + using MyMuons = soa::Join; + using MyMcMuons = soa::Join; + using MyTracks = soa::Filtered>; + + // Filter Global Track for Multiplicty + Filter trackFilter = ((nabs(aod::track::eta) < etaTrackMax) && (aod::track::pt > ptTrackMin)); + + // Number the types of muon tracks + static constexpr uint8_t NTrackTypes{ForwardTrackTypeEnum::MCHStandaloneTrack + 1}; + + HistogramRegistry registry{"registry"}; + + void init(InitContext&) + { + AxisSpec const axisCent = {101, -0.5, 100.5, "centrality"}; + AxisSpec const axisEvent{NEventSelection, 0, NEventSelection, "Event Selection"}; + AxisSpec const axisVtxZ{80, -20., 20., "#it{z}_{vtx} (cm)"}; + AxisSpec const axisMuon{NMuonSelection, 0, NMuonSelection, "Muon Selection"}; + AxisSpec const axisNCh{500, 0.5, 500.5, "#it{N}_{ch}"}; + AxisSpec const axisNMu{20, -0.5, 19.5, "#it{N}_{#mu}"}; + AxisSpec const axisPt{1000, 0., 500., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisEta{250, -5., 5., "#it{#eta}"}; + AxisSpec const axisTheta{500, 170., 180., "#it{#theta}"}; + AxisSpec const axisRAbsorb{1000, 0., 100., "#it{R}_{Absorb} (cm)"}; + AxisSpec const axisDCA{500, 0., 5., "#it{DCA}_{xy} (cm)"}; + AxisSpec const axisChi2MatchMCHMFT{1000, 0., 1000., "MCH-MFT matching #chi^{2}"}; + AxisSpec const axisSign{5, -2.5, 2.5, "Charge"}; + AxisSpec const axisPDca{100000, 0, 100000, "#it{p} #times DCA (GeV/#it{c} * cm)"}; + AxisSpec const axisDCAx{1000, -5., 5., "#it{DCA}_{x or y} (cm)"}; + AxisSpec const axisEtaDif{200, -2., 2., "#it{#eta} diff"}; + AxisSpec const axisDeltaPt{10000, -50, 50, "#Delta #it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisTrackType{8, -1.5, 6.5, "TrackType"}; + AxisSpec const axisPtDif{200, -2., 2., "#it{p}_{T} diff (GeV/#it{c})"}; + + registry.add("hCentrality", "Centrality Percentile", {HistType::kTH1F, {axisCent}}); + registry.add("hEventSel", " Number of Events", {HistType::kTH1F, {axisEvent}}); + registry.add("hNch", "Charged Particle Multiplicity", {HistType::kTH1F, {axisNCh}}); + registry.add("hVtxZBeforeSel", "Z-vertex distribution before zVtx Cut", {HistType::kTH1F, {axisVtxZ}}); + registry.add("hVtxZAfterSel", "Z-vertex distribution after zVtx Cut", {HistType::kTH1F, {axisVtxZ}}); + + registry.add("hMuonSel", "Selection of muon tracks at various kinematic cuts", {HistType::kTH1F, {axisMuon}}); + registry.add("hMuBeforeMatchMFT", "Muon information before any Kinemeatic cuts applied", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisTheta, axisRAbsorb, axisDCA, axisPDca, axisChi2MatchMCHMFT, axisTrackType}, 10}); + registry.add("hMuBeforeAccCuts", "Muon information before applying Acceptance cuts", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisTheta, axisRAbsorb, axisDCA, axisPDca, axisChi2MatchMCHMFT, axisTrackType}, 10}); + registry.add("h3DCABeforeAccCuts", "DCAx,DCAy,DCAz information before Acceptance cuts", {HistType::kTH3F, {axisDCAx, axisDCAx, axisTrackType}}); + registry.add("hMuDeltaPtBeforeAccCuts", "Muon information with DeltaPt before applying Acceptance cuts", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisTheta, axisRAbsorb, axisDCA, axisPDca, axisChi2MatchMCHMFT, axisDeltaPt}, 10}); + registry.add("hMuAfterEtaCuts", "Muon information after applying Eta cuts", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisTheta, axisRAbsorb, axisDCA, axisPDca, axisChi2MatchMCHMFT, axisTrackType}, 10}); + registry.add("hMuAfterRAbsorbCuts", "Muon information after applying RAbsorb cuts", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisTheta, axisRAbsorb, axisDCA, axisPDca, axisChi2MatchMCHMFT, axisTrackType}, 10}); + registry.add("hMuAfterPdcaCuts", "Muon information after applying Pdca cuts", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisTheta, axisRAbsorb, axisDCA, axisPDca, axisChi2MatchMCHMFT, axisTrackType}, 10}); + registry.add("hMuAfterAccCuts", "Muon information after applying all Kinematic cuts", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisTheta, axisRAbsorb, axisDCA, axisPDca, axisChi2MatchMCHMFT, axisTrackType}, 10}); + registry.add("h3DCAAfterAccCuts", "DCAx,DCAy,DCAz information after Acceptance cuts", {HistType::kTH3F, {axisDCAx, axisDCAx, axisTrackType}}); + registry.add("hMuDeltaPtAfterAccCuts", "Muon information with DeltaPt after applying Acceptance cuts", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisTheta, axisRAbsorb, axisDCA, axisPDca, axisChi2MatchMCHMFT, axisDeltaPt}, 10}); + + registry.add("hTHnTrk", "Muon information with multiplicity", {HistType::kTHnSparseF, {axisCent, axisNCh, axisPt, axisEta, axisSign}, 5}); + registry.add("h3MultNchNmu", "Number of muons and multiplicity", {HistType::kTH3F, {axisCent, axisNCh, axisNMu}}); + registry.add("hMultNchNmuTrackType", "Number of muons with different types and multiplicity", {HistType::kTHnSparseF, {axisCent, axisNCh, axisNMu, axisTrackType}, 4}); + + auto hEvstat = registry.get(HIST("hEventSel")); + auto* xEv = hEvstat->GetXaxis(); + xEv->SetBinLabel(AllEvents + 1, "All events"); + xEv->SetBinLabel(Sel8 + 1, "sel8"); + xEv->SetBinLabel(VtxZAfterSel + 1, "VtxZAfterSel"); + + auto hMustat = registry.get(HIST("hMuonSel")); + auto* xMu = hMustat->GetXaxis(); + xMu->SetBinLabel(NoCut + 1, "noCut"); + xMu->SetBinLabel(EtaCut + 1, "etaCut"); + xMu->SetBinLabel(RAbsorbCut + 1, "RAbsorbCut"); + xMu->SetBinLabel(PDcaCut + 1, "pDcaCut"); + xMu->SetBinLabel(Chi2Cut + 1, "chi2Cut"); + } + + void process(MyCollisions::iterator const& collision, + MyTracks const& tracks, + MyMuons const& muons) + { + registry.fill(HIST("hEventSel"), AllEvents); + + if (!collision.sel8()) { + return; + } + registry.fill(HIST("hEventSel"), Sel8); + registry.fill(HIST("hVtxZBeforeSel"), collision.posZ()); + + if (std::abs(collision.posZ()) > zVtxMax) { + return; + } + registry.fill(HIST("hEventSel"), VtxZAfterSel); + registry.fill(HIST("hVtxZAfterSel"), collision.posZ()); + + // T0M centrality + const auto cent = collision.centFT0M(); + registry.fill(HIST("hCentrality"), cent); + + // Charged particles + for (const auto& track : tracks) { + if (!track.isGlobalTrack()) { + continue; + } + } + + auto nCh{tracks.size()}; + if (nCh < 1) { + return; + } + registry.fill(HIST("hNch"), nCh); + + for (const auto& track : tracks) { + registry.fill(HIST("hTHnTrk"), cent, nCh, track.pt(), track.eta(), track.sign()); + } + + // muons per event + int nMu{0}; + int nMuType[NTrackTypes] = {0}; + + for (const auto& muon : muons) { + const auto pt{muon.pt()}, eta{muon.eta()}, theta{90.0f - ((std::atan(muon.tgl())) * constants::math::Rad2Deg)}, pDca{muon.pDca()}, rAbsorb{muon.rAtAbsorberEnd()}, chi2{muon.chi2MatchMCHMFT()}; + const auto dcaXY{RecoDecay::sqrtSumOfSquares(muon.fwdDcaX(), muon.fwdDcaY())}; + const auto muTrackType{muon.trackType()}; + + registry.fill(HIST("hMuBeforeMatchMFT"), cent, nCh, pt, eta, theta, rAbsorb, dcaXY, pDca, chi2, muTrackType); + + // histograms before the acceptance cuts + registry.fill(HIST("hMuonSel"), NoCut); + registry.fill(HIST("hMuBeforeAccCuts"), cent, nCh, pt, eta, theta, rAbsorb, dcaXY, pDca, chi2, muTrackType); + registry.fill(HIST("h3DCABeforeAccCuts"), muon.fwdDcaX(), muon.fwdDcaY(), muTrackType); + + if (muon.has_matchMCHTrack()) { + auto muonType3 = muon.template matchMCHTrack_as(); + auto dpt = muonType3.pt() - pt; + if (muTrackType == ForwardTrackTypeEnum::GlobalMuonTrack) { + registry.fill(HIST("hMuDeltaPtBeforeAccCuts"), cent, nCh, pt, eta, theta, rAbsorb, dcaXY, pDca, chi2, dpt); + } + } + + // Apply various standard muon acceptance cuts + // eta cuts + if ((eta >= etaMax) || (eta < etaMin)) { + continue; + } + registry.fill(HIST("hMuonSel"), EtaCut); + registry.fill(HIST("hMuAfterEtaCuts"), cent, nCh, pt, eta, theta, rAbsorb, dcaXY, pDca, chi2, muTrackType); + + // Rabsorb cuts + if ((rAbsorb < rAbsorbMin) || (rAbsorb >= rAbsorbMax)) { + continue; + } + registry.fill(HIST("hMuonSel"), RAbsorbCut); + registry.fill(HIST("hMuAfterRAbsorbCuts"), cent, nCh, pt, eta, theta, rAbsorb, dcaXY, pDca, chi2, muTrackType); + + if ((rAbsorb < rAbsorbMid) && (pDca >= pDcaMin)) { + continue; + } + if ((rAbsorb >= rAbsorbMid) && (pDca >= pDcaMax)) { + continue; + } + registry.fill(HIST("hMuonSel"), PDcaCut); + registry.fill(HIST("hMuAfterPdcaCuts"), cent, nCh, pt, eta, theta, rAbsorb, dcaXY, pDca, chi2, muTrackType); + + // MCH-MFT matching chi2 + if (muon.chi2() >= 1e6) { + continue; + } + registry.fill(HIST("hMuonSel"), Chi2Cut); + + // histograms after acceptance cuts + registry.fill(HIST("hMuAfterAccCuts"), cent, nCh, pt, eta, theta, rAbsorb, dcaXY, pDca, chi2, muTrackType); + registry.fill(HIST("h3DCAAfterAccCuts"), muon.fwdDcaX(), muon.fwdDcaY(), muTrackType); + nMu++; + nMuType[muTrackType]++; + + if (muon.has_matchMCHTrack()) { + auto muonType3 = muon.template matchMCHTrack_as(); + auto dpt = muonType3.pt() - pt; + + if (muTrackType == ForwardTrackTypeEnum::GlobalMuonTrack) { + registry.fill(HIST("hMuDeltaPtAfterAccCuts"), cent, nCh, pt, eta, theta, rAbsorb, dcaXY, pDca, chi2, dpt); + } + } + } + + registry.fill(HIST("h3MultNchNmu"), cent, nCh, nMu); + + // Fill number of muons of various types with multiplicity + for (auto indexType{0u}; indexType < NTrackTypes; ++indexType) { + if (nMuType[indexType] > 0) { + registry.fill(HIST("hMultNchNmuTrackType"), cent, nCh, nMuType[indexType], indexType); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/HFL/Tasks/taskSingleMuonReader.cxx b/PWGHF/HFL/Tasks/taskSingleMuonReader.cxx index 7d04bead362..0db3d4a3350 100644 --- a/PWGHF/HFL/Tasks/taskSingleMuonReader.cxx +++ b/PWGHF/HFL/Tasks/taskSingleMuonReader.cxx @@ -12,17 +12,20 @@ /// \file taskSingleMuonReader.cxx /// \brief Task used to read the derived table produced by the tableMaker of DQ framework and extract observables on single muons needed for the HF-muon analysis. /// \author Maolin Zhang , CCNU -#include -#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 "PWGDQ/DataModel/ReducedInfoTables.h" + #include "Common/Core/RecoDecay.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -66,17 +69,17 @@ struct HfTaskSingleMuonReader { 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}}; + AxisSpec const axisPt{200, 0., 100., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisEta{100, -4., -2., "#it{#eta}"}; + AxisSpec const axisDCA{2000, 0., 2., "#it{DCA}_{xy} (cm)"}; + AxisSpec const axisChi2MatchMCHMFT{100, 0., 100., "MCH-MFT matching #chi^{2}"}; + AxisSpec const axisSign{5, -2.5, 2.5, "Charge"}; + AxisSpec const axisRabs{1000, 0, 100, "R at Absorber End (cm)"}; + AxisSpec const axisDeltaPt{10000, -50, 50, "#Delta #it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisVtxZ{80, -20., 20., "#it{z}_{vtx} (cm)"}; + + HistogramConfigSpec const hTHnMu{HistType::kTHnSparseF, {axisPt, axisEta, axisDCA, axisRabs, axisSign, axisChi2MatchMCHMFT, axisDeltaPt}, 7}; + HistogramConfigSpec const hVtxZ{HistType::kTH1F, {axisVtxZ}}; registry.add("hMuAfterCuts", "", hTHnMu); if (fillMcHist) { @@ -116,10 +119,10 @@ struct HfTaskSingleMuonReader { // histograms after acceptance cuts if (muon.has_matchMCHTrack()) { auto muonType3 = muon.template matchMCHTrack_as(); - auto Dpt = muonType3.pt() - pt; + auto dpt = muonType3.pt() - pt; - singleMuon(pt, dcaXY, Dpt, chi2); - registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + singleMuon(pt, dcaXY, dpt, chi2); + registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, charge, chi2, dpt); } } } @@ -153,15 +156,15 @@ struct HfTaskSingleMuonReader { // histograms after acceptance cuts if (muon.has_matchMCHTrack()) { auto muonType3 = muon.template matchMCHTrack_as(); - auto Dpt = muonType3.pt() - pt; + auto dpt = muonType3.pt() - pt; - singleMuon(pt, dcaXY, Dpt, chi2); - registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, 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); + 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); + registry.fill(HIST("hMuAfterCutsFake"), pt, eta, dcaXY, rAbs, charge, chi2, dpt); } } } diff --git a/PWGHF/HFL/Tasks/taskSingleMuonReaderAssoc.cxx b/PWGHF/HFL/Tasks/taskSingleMuonReaderAssoc.cxx index 03fa6efb5a5..1185268b0a6 100644 --- a/PWGHF/HFL/Tasks/taskSingleMuonReaderAssoc.cxx +++ b/PWGHF/HFL/Tasks/taskSingleMuonReaderAssoc.cxx @@ -13,18 +13,18 @@ /// \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 "PWGDQ/DataModel/ReducedInfoTables.h" #include "Common/Core/RecoDecay.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -62,17 +62,17 @@ struct HfTaskSingleMuonReaderAssoc { 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}}; + AxisSpec const axisPt{200, 0., 100., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisEta{100, -4., -2., "#it{#eta}"}; + AxisSpec const axisDCA{2000, 0., 2., "#it{DCA}_{xy} (cm)"}; + AxisSpec const axisChi2MatchMCHMFT{100, 0., 100., "MCH-MFT matching #chi^{2}"}; + AxisSpec const axisSign{5, -2.5, 2.5, "Charge"}; + AxisSpec const axisRabs{1000, 0, 100, "R at Absorber End (cm)"}; + AxisSpec const axisDeltaPt{10000, -50, 50, "#Delta #it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisVtxZ{80, -20., 20., "#it{z}_{vtx} (cm)"}; + + HistogramConfigSpec const hTHnMu{HistType::kTHnSparseF, {axisPt, axisEta, axisDCA, axisRabs, axisSign, axisChi2MatchMCHMFT, axisDeltaPt}, 7}; + HistogramConfigSpec const hVtxZ{HistType::kTH1F, {axisVtxZ}}; registry.add("hMuAfterCuts", "", hTHnMu); if (fillMcHist) { @@ -114,10 +114,10 @@ struct HfTaskSingleMuonReaderAssoc { // histograms after acceptance cuts if (muon.has_matchMCHTrack()) { auto muonType3 = muon.template matchMCHTrack_as(); - auto Dpt = muonType3.pt() - pt; + auto dpt = muonType3.pt() - pt; - singleMuon(pt, dcaXY, Dpt, chi2); - registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, charge, chi2, Dpt); + singleMuon(pt, dcaXY, dpt, chi2); + registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, charge, chi2, dpt); } } } @@ -154,15 +154,15 @@ struct HfTaskSingleMuonReaderAssoc { // histograms after acceptance cuts if (muon.has_matchMCHTrack()) { auto muonType3 = muon.template matchMCHTrack_as(); - auto Dpt = muonType3.pt() - pt; + auto dpt = muonType3.pt() - pt; - singleMuon(pt, dcaXY, Dpt, chi2); - registry.fill(HIST("hMuAfterCuts"), pt, eta, dcaXY, rAbs, 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); + 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); + registry.fill(HIST("hMuAfterCutsFake"), pt, eta, dcaXY, rAbs, charge, chi2, dpt); } } } diff --git a/PWGHF/HFL/Tasks/taskSingleMuonSource.cxx b/PWGHF/HFL/Tasks/taskSingleMuonSource.cxx index d60a04f80d0..20c3db63117 100644 --- a/PWGHF/HFL/Tasks/taskSingleMuonSource.cxx +++ b/PWGHF/HFL/Tasks/taskSingleMuonSource.cxx @@ -13,20 +13,30 @@ // \brief Task used to seperate single muons source in Monte Carlo simulation. // \author Maolin Zhang , CCNU +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include -#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 -#include "Common/Core/RecoDecay.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -93,17 +103,17 @@ struct HfTaskSingleMuonSource { "Hadron", "Unidentified"}; - 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})"}; + AxisSpec const axisColNumber{1, 0.5, 1.5, "Selected collisions"}; + AxisSpec const axisDCA{5000, 0., 5., "DCA (cm)"}; + AxisSpec const axisChi2{500, 0., 100., "#chi^{2} of MCH-MFT matching"}; + AxisSpec const axisPt{200, 0., 100., "#it{p}_{T,reco} (GeV/#it{c})"}; + AxisSpec const 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}}; + HistogramConfigSpec const h1ColNumber{HistType::kTH1F, {axisColNumber}}; + HistogramConfigSpec const h1Pt{HistType::kTH1F, {axisPt}}; + HistogramConfigSpec const h2PtDCA{HistType::kTH2F, {axisPt, axisDCA}}; + HistogramConfigSpec const h2PtChi2{HistType::kTH2F, {axisPt, axisChi2}}; + HistogramConfigSpec const h2PtDeltaPt{HistType::kTH2F, {axisPt, axisDeltaPt}}; registry.add("h1ColNumber", "", h1ColNumber); for (const auto& src : muonSources) { @@ -136,8 +146,9 @@ struct HfTaskSingleMuonSource { mcPart = *(mcPart.mothers_first_as()); const auto pdgAbs(std::abs(mcPart.pdgCode())); - if (pdgAbs < 10) + if (pdgAbs < 10) { break; // Quark + } if (!mcPart.producedByGenerator()) { // Produced in transport code SETBIT(mask, IsSecondary); @@ -171,8 +182,8 @@ struct HfTaskSingleMuonSource { continue; } - auto pdgData(TDatabasePDG::Instance()->GetParticle(mcPart.pdgCode())); - if (pdgData && !pdgData->AntiParticle()) { + auto* pdgData(TDatabasePDG::Instance()->GetParticle(mcPart.pdgCode())); + if ((pdgData != nullptr) && (pdgData->AntiParticle() == nullptr)) { SETBIT(mask, HasQuarkoniumParent); } else if (flv == 4) { SETBIT(mask, HasCharmParent); diff --git a/PWGHF/Macros/computeFonllPlusPythiaPredictions.C b/PWGHF/Macros/computeFonllPlusPythiaPredictions.C new file mode 100644 index 00000000000..86caa6243e7 --- /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 +#include +#include +#include +#include +#include + +#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(const std::string& inFile, const 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] == nullptr) { + 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] != nullptr) { + hFonllPromptChad[charmHadPdgs[iChad]][iFonll]->Write(); + } + } + } + } + outFile.Close(); +} diff --git a/PWGHF/TableProducer/CMakeLists.txt b/PWGHF/TableProducer/CMakeLists.txt index 96981187d1f..26b3400ca28 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 O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing O2::DCAFitter O2Physics::AnalysisCCDB O2Physics::MLCore O2Physics::SGCutParHolder 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 O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::SGCutParHolder O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-creator-3prong SOURCES candidateCreator3Prong.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::SGCutParHolder O2Physics::AnalysisCCDB 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 O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-creator-dstar SOURCES candidateCreatorDstar.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-creator-lb @@ -82,12 +87,12 @@ o2physics_add_dpl_workflow(candidate-creator-sigmac0plusplus-cascade o2physics_add_dpl_workflow(candidate-creator-xic0-omegac0 SOURCES candidateCreatorXic0Omegac0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter O2Physics::EventFilteringUtils KFParticle::KFParticle + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils 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 + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-creator-xicc @@ -95,16 +100,21 @@ o2physics_add_dpl_workflow(candidate-creator-xicc 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 SOURCES candidateSelectorB0ToDPi.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) 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 @@ -159,12 +169,22 @@ o2physics_add_dpl_workflow(candidate-selector-omegac0-to-omega-ka o2physics_add_dpl_workflow(candidate-selector-omegac0-to-omega-pi SOURCES candidateSelectorOmegac0ToOmegaPi.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(candidate-selector-omegac0-xic0-to-omega-ka + SOURCES candidateSelectorOmegac0Xic0ToOmegaKa.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 O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-selector-to-xi-pi SOURCES candidateSelectorToXiPi.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(candidate-selector-xic-to-p-k-pi @@ -182,6 +202,11 @@ o2physics_add_dpl_workflow(candidate-selector-xicc-to-p-k-pi-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(candidate-selector-cd + SOURCES candidateSelectorCd.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + # Tree creators o2physics_add_dpl_workflow(tree-creator-b0-to-d-pi @@ -229,18 +254,23 @@ o2physics_add_dpl_workflow(tree-creator-lc-to-p-k-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(tree-creator-sigmac-corr-bkg + SOURCES treeCreatorSigmacCorrBkg.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + 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 + SOURCES treeCreatorOmegac0ToOmegaKa.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(tree-creator-omegac0-to-omega-pi - SOURCES treeCreatorOmegacToOmegaPi.cxx + SOURCES treeCreatorOmegac0ToOmegaPi.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -249,6 +279,11 @@ 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 @@ -269,14 +304,55 @@ 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-b0-to-d-pi + SOURCES derivedDataCreatorB0ToDPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +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-ds-to-k-k-pi + SOURCES derivedDataCreatorDsToKKPi.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(derived-data-creator-dstar-to-d0-pi + SOURCES derivedDataCreatorDstarToD0Pi.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) + +o2physics_add_dpl_workflow(derived-data-creator-xic-to-xi-pi-pi + SOURCES derivedDataCreatorXicToXiPiPi.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 82412417a32..51c4cabf282 100644 --- a/PWGHF/TableProducer/candidateCreator2Prong.cxx +++ b/PWGHF/TableProducer/candidateCreator2Prong.cxx @@ -17,47 +17,87 @@ /// \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 - -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#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/Core/DecayChannels.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsMcGen.h" +#include "PWGHF/Utils/utilsMcMatching.h" +#include "PWGHF/Utils/utilsPid.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include 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::hf_decay; +using namespace o2::hf_decay::hf_cand_2prong; 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 rowCandidateKF; + Produces rowProng0PidPi; + Produces rowProng0PidKa; + Produces rowProng1PidPi; + Produces rowProng1PidKa; // vertexing Configurable constrainKfToPv{"constrainKfToPv", true, "constraint KFParticle to PV"}; @@ -72,41 +112,43 @@ 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; int runNumber{0}; - float toMicrometers = 10000.; // from cm to µm - double massPi{0.}; - double massK{0.}; - double massPiK{0.}; - double massKPi{0.}; double bz{0.}; + const float toMicrometers = 10000.; // from cm to µm + std::shared_ptr hCandidates; + + using TracksWCovExtraPidPiKa = soa::Join; + + ConfigurableAxis axisMass{"axisMass", {500, 1.6, 2.1}, "axis for mass (GeV/c^2)"}; + HistogramRegistry registry{"registry"}; + OutputObj zorroSummary{"zorroSummary"}; void init(InitContext const&) { - std::array doprocessDF{doprocessPvRefitWithDCAFitterN, doprocessNoPvRefitWithDCAFitterN, + std::array doprocessDF{doprocessPvRefitWithDCAFitterN, doprocessNoPvRefitWithDCAFitterN, doprocessPvRefitWithDCAFitterNCentFT0C, doprocessNoPvRefitWithDCAFitterNCentFT0C, - doprocessPvRefitWithDCAFitterNCentFT0M, doprocessNoPvRefitWithDCAFitterNCentFT0M}; - std::array doprocessKF{doprocessPvRefitWithKFParticle, doprocessNoPvRefitWithKFParticle, + doprocessPvRefitWithDCAFitterNCentFT0M, doprocessNoPvRefitWithDCAFitterNCentFT0M, doprocessPvRefitWithDCAFitterNUpc, doprocessNoPvRefitWithDCAFitterNUpc}; + std::array doprocessKF{doprocessPvRefitWithKFParticle, doprocessNoPvRefitWithKFParticle, doprocessPvRefitWithKFParticleCentFT0C, doprocessNoPvRefitWithKFParticleCentFT0C, - doprocessPvRefitWithKFParticleCentFT0M, doprocessNoPvRefitWithKFParticleCentFT0M}; + doprocessPvRefitWithKFParticleCentFT0M, doprocessNoPvRefitWithKFParticleCentFT0M, doprocessPvRefitWithKFParticleUpc, doprocessNoPvRefitWithKFParticleUpc}; 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."); } - std::array processesCollisions = {doprocessCollisions, doprocessCollisionsCentFT0C, doprocessCollisionsCentFT0M}; + std::array processesCollisions = {doprocessCollisions, doprocessCollisionsCentFT0C, doprocessCollisionsCentFT0M, doprocessCollisionsUpc}; const int nProcessesCollisions = std::accumulate(processesCollisions.begin(), processesCollisions.end(), 0); + std::array processesUpc = {doprocessPvRefitWithDCAFitterNUpc, doprocessNoPvRefitWithDCAFitterNUpc, doprocessPvRefitWithKFParticleUpc, doprocessNoPvRefitWithKFParticleUpc, doprocessCollisionsUpc}; + const int nProcessesUpc = std::accumulate(processesUpc.begin(), processesUpc.end(), 0); if (nProcessesCollisions > 1) { LOGP(fatal, "At most one process function for collision monitoring can be enabled at a time."); } @@ -120,10 +162,18 @@ struct HfCandidateCreator2Prong { if ((doprocessPvRefitWithDCAFitterNCentFT0M || doprocessNoPvRefitWithDCAFitterNCentFT0M || doprocessPvRefitWithKFParticleCentFT0M || doprocessNoPvRefitWithKFParticleCentFT0M) && !doprocessCollisionsCentFT0M) { LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisionsCentFT0M\"?"); } + if ((doprocessPvRefitWithDCAFitterNUpc || doprocessNoPvRefitWithDCAFitterNUpc || doprocessPvRefitWithKFParticleUpc || doprocessNoPvRefitWithKFParticleUpc) && !doprocessCollisionsUpc) { + LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisionsUpc\"?"); + } + } + if (nProcessesUpc > 0 && isRun2) { + LOGP(fatal, "Process function for UPC is only available in Run 3!"); } // histograms - registry.add("hMass2", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 1.6, 2.1}}}); + registry.add("hMass2", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); + registry.add("hMassEE", "2-prong candidates;inv. mass (e e) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); + registry.add("hMassMuMu", "2-prong candidates;inv. mass (#mu #mu) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); 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("hCovPVYY", "2-prong candidates;YY element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 1.e-4}}}); @@ -136,10 +186,9 @@ struct HfCandidateCreator2Prong { 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 hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); - hfEvSel.addHistograms(registry); // collision monitoring - massPi = MassPiPlus; - massK = MassKPlus; + // init HF event selection helper + hfEvSel.init(registry, zorroSummary); if (std::accumulate(doprocessDF.begin(), doprocessDF.end(), 0) == 1) { registry.fill(HIST("hVertexerType"), aod::hf_cand::VertexerType::DCAFitter); @@ -160,18 +209,17 @@ struct HfCandidateCreator2Prong { ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); runNumber = 0; /// candidate monitoring setLabelHistoCands(hCandidates); } - template + template void runCreator2ProngWithDCAFitterN(Coll const&, CandType const& rowsTrackIndexProng2, TTracks const&, - aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + BCsType const& bcs) { // loop over pairs of track indices for (const auto& rowTrackIndexProng2 : rowsTrackIndexProng2) { @@ -179,7 +227,12 @@ struct HfCandidateCreator2Prong { /// reject candidates not satisfying the event selections auto collision = rowTrackIndexProng2.template collision_as(); float centrality{-1.f}; - const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + if constexpr (ApplyUpcSel) { + rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); + } else { + rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + } if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -193,10 +246,10 @@ struct HfCandidateCreator2Prong { /// 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(); + 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 @@ -228,8 +281,8 @@ struct HfCandidateCreator2Prong { auto trackParVar1 = df.getTrack(1); // get track momenta - std::array pvec0; - std::array pvec1; + std::array pvec0{}; + std::array pvec1{}; trackParVar0.getPxPyPzGlo(pvec0); trackParVar1.getPxPyPzGlo(pvec1); @@ -237,7 +290,7 @@ struct HfCandidateCreator2Prong { // This modifies track momenta! auto primaryVertex = getPrimaryVertex(collision); auto covMatrixPV = primaryVertex.getCov(); - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { /// use PV refit /// Using it in the rowCandidateBase all dynamic columns shall take it into account // coordinates @@ -273,13 +326,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); } + const auto nProngsContributorsPV = hf_trkcandsel::countOnesInBinary(bitmapProngsContributorsPV); // fill candidate table rows rowCandidateBase(indexCollision, @@ -293,26 +347,36 @@ 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 - auto arrayMomenta = std::array{pvec0, pvec1}; - massPiK = RecoDecay::m(arrayMomenta, std::array{massPi, massK}); - massKPi = RecoDecay::m(arrayMomenta, std::array{massK, massPi}); + const auto arrayMomenta = std::array{pvec0, pvec1}; + const auto massPiK = RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus}); + const auto massKPi = RecoDecay::m(arrayMomenta, std::array{MassKPlus, MassPiPlus}); + const auto massEE = RecoDecay::m(arrayMomenta, std::array{MassElectron, MassElectron}); + const auto massMuMu = RecoDecay::m(arrayMomenta, std::array{MassMuon, MassMuon}); registry.fill(HIST("hMass2"), massPiK); registry.fill(HIST("hMass2"), massKPi); + registry.fill(HIST("hMassEE"), massEE); + registry.fill(HIST("hMassMuMu"), massMuMu); } } } - template + template void runCreator2ProngWithKFParticle(Coll const&, CandType const& rowsTrackIndexProng2, TTracks const&, - aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + BCsType const& bcs) { for (const auto& rowTrackIndexProng2 : rowsTrackIndexProng2) { @@ -320,7 +384,12 @@ struct HfCandidateCreator2Prong { /// reject candidates in collisions not satisfying the event selections auto collision = rowTrackIndexProng2.template collision_as(); float centrality{-1.f}; - const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + if constexpr (ApplyUpcSel) { + rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); + } else { + rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + } if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -332,10 +401,10 @@ struct HfCandidateCreator2Prong { /// 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(); + 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 @@ -346,7 +415,7 @@ struct HfCandidateCreator2Prong { KFParticle::SetField(bz); KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { /// use PV refit /// Using it in the rowCandidateBase all dynamic columns shall take it into account // coordinates @@ -355,31 +424,31 @@ struct HfCandidateCreator2Prong { kfpVertex.SetCovarianceMatrix(rowTrackIndexProng2.pvRefitSigmaX2(), rowTrackIndexProng2.pvRefitSigmaXY(), rowTrackIndexProng2.pvRefitSigmaY2(), rowTrackIndexProng2.pvRefitSigmaXZ(), rowTrackIndexProng2.pvRefitSigmaYZ(), rowTrackIndexProng2.pvRefitSigmaZ2()); } kfpVertex.GetCovarianceMatrix(covMatrixPV); - KFParticle KFPV(kfpVertex); + KFParticle const 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 const kfpTrack0 = createKFPTrackFromTrack(track0); + KFPTrack const kfpTrack1 = createKFPTrackFromTrack(track1); - KFParticle kfPosPion(kfpTrack0, kPiPlus); - KFParticle kfNegPion(kfpTrack1, kPiPlus); - KFParticle kfPosKaon(kfpTrack0, kKPlus); - KFParticle kfNegKaon(kfpTrack1, kKPlus); + KFParticle const kfPosPion(kfpTrack0, kPiPlus); + KFParticle const kfNegPion(kfpTrack1, kPiPlus); + KFParticle const kfPosKaon(kfpTrack0, kKPlus); + KFParticle const 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); @@ -402,10 +471,10 @@ struct HfCandidateCreator2Prong { registry.fill(HIST("hCovSVXZ"), kfCandD0.Covariance(2, 0)); registry.fill(HIST("hCovSVZZ"), kfCandD0.Covariance(2, 2)); - auto covMatrixSV = kfCandD0.CovarianceMatrix(); + 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.)); @@ -413,22 +482,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); } + const auto 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 @@ -438,8 +508,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); @@ -460,40 +538,40 @@ 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); + runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter w/ 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, aod::Hf2Prongs const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); + runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter w/o 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, soa::Join const& rowsTrackIndexProng2, - aod::TracksWCovExtra const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); + runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithKFParticle, "Run candidate creator using KFParticle package w/ PV refit and w/o centrality selections", false); /// @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); + runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithKFParticle, "Run candidate creator using KFParticle package w/o PV refit and w/o centrality selections", false); @@ -506,40 +584,40 @@ 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); + runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithDCAFitterNCentFT0C, "Run candidate creator using DCA fitter w/ PV refit and w/ centrality selection on FT0C", false); /// @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); + runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithDCAFitterNCentFT0C, "Run candidate creator using DCA fitter w/o PV refit and w/ centrality selection FT0C", false); /// @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); + runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithKFParticleCentFT0C, "Run candidate creator using KFParticle package w/ PV refit and w/ centrality selection on FT0C", false); /// @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); + runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithKFParticleCentFT0C, "Run candidate creator using KFParticle package w/o PV refit and w/ centrality selection on FT0C", false); @@ -552,43 +630,105 @@ 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); + runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter w/ PV refit and w/ centrality selection on FT0M", false); /// @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); + runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter w/o PV refit and w/ centrality selection FT0M", false); /// @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); + runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithKFParticleCentFT0M, "Run candidate creator using KFParticle package w/ PV refit and w/ centrality selection on FT0M", false); /// @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); + runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); } PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithKFParticleCentFT0M, "Run candidate creator using KFParticle package w/o PV refit and w/ centrality selection on FT0M", false); + ///////////////////////////////////////////// + /// /// + /// with centrality selection on UPC /// + /// /// + ///////////////////////////////////////////// + + /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on UPC + void processPvRefitWithDCAFitterNUpc(soa::Join const& collisions, + soa::Join const& rowsTrackIndexProng2, + TracksWCovExtraPidPiKa const& tracks, + aod::BcFullInfos const& bcWithTimeStamps, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithDCAFitterNUpc, "Run candidate creator using DCA fitter w/ PV refit and w/ centrality selection on UltraPeripheral Collision", false); + + /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection UPC + void processNoPvRefitWithDCAFitterNUpc(soa::Join const& collisions, + aod::Hf2Prongs const& rowsTrackIndexProng2, + TracksWCovExtraPidPiKa const& tracks, + aod::BcFullInfos const& bcWithTimeStamps, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + runCreator2ProngWithDCAFitterN(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithDCAFitterNUpc, "Run candidate creator using DCA fitter w/o PV refit and w/ centrality selection UltraPeripheral Collision", false); + + /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on UPC + void processPvRefitWithKFParticleUpc(soa::Join const& collisions, + soa::Join const& rowsTrackIndexProng2, + TracksWCovExtraPidPiKa const& tracks, + aod::BcFullInfos const& bcWithTimeStamps, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithKFParticleUpc, "Run candidate creator using KFParticle package w/ PV refit and w/ centrality selection on UltraPeripheral Collision", false); + + /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections on UPC + void processNoPvRefitWithKFParticleUpc(soa::Join const& collisions, + aod::Hf2Prongs const& rowsTrackIndexProng2, + TracksWCovExtraPidPiKa const& tracks, + aod::BcFullInfos const& bcWithTimeStamps, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + runCreator2ProngWithKFParticle(collisions, rowsTrackIndexProng2, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithKFParticleUpc, "Run candidate creator using KFParticle package w/o PV refit and w/ centrality selection on UltraPeripheral Collision", false); + /////////////////////////////////////////////////////////// /// /// /// Process functions only for collision monitoring /// @@ -603,10 +743,12 @@ struct HfCandidateCreator2Prong { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -620,10 +762,12 @@ struct HfCandidateCreator2Prong { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -637,14 +781,40 @@ struct HfCandidateCreator2Prong { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreator2Prong, processCollisionsCentFT0M, "Collision monitoring - FT0M centrality", false); + + /// @brief process function to monitor collisions - UPC collision + void processCollisionsUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + /// loop over collisions + for (const auto& collision : collisions) { + + /// bitmask with event. selection info + float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); + + } /// end loop over collisions + } + PROCESS_SWITCH(HfCandidateCreator2Prong, processCollisionsUpc, "Collision monitoring - UPC", false); }; /// Extends the base table with expression columns. @@ -654,19 +824,24 @@ struct HfCandidateCreator2ProngExpressions { Produces rowMcMatchGen; // Configuration - o2::framework::Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + 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"}; + Configurable matchCorrelatedBackground{"matchCorrelatedBackground", false, "Match correlated background candidates"}; 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; - Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; - using BCsInfo = soa::Join; HistogramRegistry registry{"registry"}; // inspect for which zPvPosMax cut was set for reconstructed @@ -679,33 +854,38 @@ struct HfCandidateCreator2ProngExpressions { const auto& workflows = initContext.services().get(); for (const DeviceSpec& device : workflows.devices) { - if (device.name.compare("hf-candidate-creator-2prong") == 0) { - hfEvSelMc.configureFromDevice(device); + if (device.name == "hf-candidate-creator-2prong") { + // init HF event selection helper + hfEvSelMc.init(device, registry); break; } } - hfEvSelMc.addHistograms(registry); // particles monitoring } /// Performs MC matching. - template + template void runCreator2ProngMc(aod::TracksWMc const& tracks, aod::McParticles const& mcParticles, CCs const& collInfos, - aod::McCollisions const& mcCollisions, + McCollisions const& mcCollisions, BCsInfo const&) { rowCandidateProng2->bindExternalIndices(&tracks); int indexRec = -1; int8_t sign = 0; - int8_t flag = 0; + int8_t flagChannelMain = 0; + int8_t flagChannelResonant = 0; int8_t origin = 0; + int8_t nKinkedTracks = 0; + int8_t nInteractionsWithMaterial = 0; + constexpr std::size_t NDaughtersResonant{2u}; // Match reconstructed candidates. // Spawned table can be used directly for (const auto& candidate : *rowCandidateProng2) { - flag = 0; + flagChannelMain = 0; + flagChannelResonant = 0; origin = 0; auto arrayDaughters = std::array{candidate.prong0_as(), candidate.prong1_as()}; @@ -722,44 +902,120 @@ struct HfCandidateCreator2ProngExpressions { } } if (fromBkg) { - rowMcMatchRec(flag, origin, -1.f, 0); + rowMcMatchRec(flagChannelMain, origin, flagChannelResonant, -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 (indexRec > -1) { - flag = sign * (1 << DecayType::D0ToPiK); - } + if (matchCorrelatedBackground) { + indexRec = -1; // Index of the matched reconstructed candidate + constexpr int FinalStateDepth = 2; + constexpr int ResoDepth = 1; + + // D0(bar) → π+ K−, π+ K− π0, π+ π−, π+ π− π0, K+ K− + for (const auto& [channelMain, finalState] : daughtersD0Main) { + std::array const arrPdgDaughtersMain2Prongs = std::array{finalState[0], finalState[1]}; + if (finalState.size() == 3) { // o2-linter: disable=magic-number (partially reconstructed 3-prong decays) + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, FinalStateDepth, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, FinalStateDepth, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, FinalStateDepth, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, FinalStateDepth); + } - // J/ψ → e+ e− - if (flag == 0) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kElectron, -kElectron}, true); + if (indexRec > -1) { + auto motherParticle = mcParticles.rawIteratorAt(indexRec); + std::array arrPdgDaughtersMain3Prongs = std::array{finalState[0], finalState[1], finalState[2]}; + flipPdgSign(motherParticle.pdgCode(), +kPi0, arrPdgDaughtersMain3Prongs); + if (!RecoDecay::isMatchedMCGen(mcParticles, motherParticle, Pdg::kD0, arrPdgDaughtersMain3Prongs, true, &sign, FinalStateDepth)) { + indexRec = -1; // Reset indexRec if the generated decay does not match the reconstructed one + } + } + } else if (finalState.size() == 2) { // o2-linter: disable=magic-number (fully reconstructed 2-prong decays) + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, FinalStateDepth, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, FinalStateDepth, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, FinalStateDepth, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, FinalStateDepth); + } + } else { + LOG(fatal) << "Final state size not supported: " << finalState.size(); + return; + } + if (indexRec > -1) { + flagChannelMain = sign * channelMain; + + // Flag the resonant decay channel + std::vector arrResoDaughIndex = {}; + RecoDecay::getDaughters(mcParticles.rawIteratorAt(indexRec), &arrResoDaughIndex, std::array{0}, ResoDepth); + std::array arrPdgDaughters = {}; + if (arrResoDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < arrResoDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrResoDaughIndex[iProng]); + arrPdgDaughters[iProng] = daughI.pdgCode(); + } + flagChannelResonant = getDecayChannelResonant(Pdg::kD0, arrPdgDaughters); + } + break; + } + } + } else { + // D0(bar) → π± K∓ + 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 = 1 << DecayType::JpsiToEE; + flagChannelMain = sign * DecayChannelMain::D0ToPiK; } - } - // J/ψ → μ+ μ− - if (flag == 0) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true); - if (indexRec > -1) { - flag = 1 << DecayType::JpsiToMuMu; + // J/ψ → e+ e− + if (flagChannelMain == 0) { + if (matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kElectron, +kPositron}, true, &sign, 1, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kElectron, +kPositron}, true); + } + if (indexRec > -1) { + flagChannelMain = DecayChannelMain::JpsiToEE; + } + } + + // J/ψ → μ+ μ− + if (flagChannelMain == 0) { + if (matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kMuonMinus, +kMuonPlus}, true, &sign, 1, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kJPsi, std::array{+kMuonMinus, +kMuonPlus}, true); + } + if (indexRec > -1) { + flagChannelMain = DecayChannelMain::JpsiToMuMu; + } } } // Check whether the particle is non-prompt (from a b quark). - if (flag != 0) { + if (flagChannelMain != 0) { auto particle = mcParticles.rawIteratorAt(indexRec); 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()); + rowMcMatchRec(flagChannelMain, origin, flagChannelResonant, bHadMother.pt(), bHadMother.pdgCode(), nKinkedTracks, nInteractionsWithMaterial); } else { - rowMcMatchRec(flag, origin, -1.f, 0); + rowMcMatchRec(flagChannelMain, origin, flagChannelResonant, -1.f, 0, nKinkedTracks, nInteractionsWithMaterial); } } @@ -769,66 +1025,28 @@ struct HfCandidateCreator2ProngExpressions { 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) { + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + 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) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (CentEstimator == CentralityEstimator::FT0M) { const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); - rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); - } else if constexpr (centEstimator == CentralityEstimator::None) { + 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); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); } - hfEvSelMc.fillHistograms(rejectionMask); + 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); + rowMcMatchGen(0, 0, 0, -1); } continue; } - - // Match generated particles. - for (const auto& particle : mcParticlesPerMcColl) { - flag = 0; - origin = 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 << DecayType::D0ToPiK); - } - - // J/ψ → e+ e− - if (flag == 0) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kJPsi, std::array{+kElectron, -kElectron}, true)) { - flag = 1 << DecayType::JpsiToEE; - } - } - - // J/ψ → μ+ μ− - if (flag == 0) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true)) { - flag = 1 << 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); - } - } + hf_mc_gen::fillMcMatchGen2Prong(mcParticles, mcParticlesPerMcColl, rowMcMatchGen, rejectBackground, matchCorrelatedBackground); } } @@ -836,9 +1054,9 @@ struct HfCandidateCreator2ProngExpressions { aod::McParticles const& mcParticles, McCollisionsNoCents const& collInfos, aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + BCsInfo const& bcsInfo) { - runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreator2ProngExpressions, processMc, "Process MC - no centrality", false); @@ -846,19 +1064,19 @@ struct HfCandidateCreator2ProngExpressions { aod::McParticles const& mcParticles, McCollisionsFT0Cs const& collInfos, aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + BCsInfo const& bcsInfo) { - runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreator2ProngExpressions, processMcCentFT0C, "Process MC - FT0c centrality", false); void processMcCentFT0M(aod::TracksWMc const& tracks, aod::McParticles const& mcParticles, McCollisionsFT0Ms const& collInfos, - aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + McCollisionsCentFT0Ms const& mcCollisions, + BCsInfo const& bcsInfo) { - runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreator2ProngMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreator2ProngExpressions, processMcCentFT0M, "Process MC - FT0m centrality", false); }; @@ -866,6 +1084,6 @@ struct HfCandidateCreator2ProngExpressions { 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 144f6c45ea6..1f10d21e90d 100644 --- a/PWGHF/TableProducer/candidateCreator3Prong.cxx +++ b/PWGHF/TableProducer/candidateCreator3Prong.cxx @@ -15,37 +15,98 @@ /// /// \author Vít Kučera , CERN -#include - -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#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" +#ifndef HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (required by KFParticle) +#endif #include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsMcGen.h" +#include "PWGHF/Utils/utilsMcMatching.h" +#include "PWGHF/Utils/utilsPid.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include 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::hf_decay; +using namespace o2::hf_decay::hf_cand_3prong; using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::aod::pid_tpc_tof_utils; /// Reconstruction of heavy-flavour 3-prong decay candidates struct HfCandidateCreator3Prong { Produces rowCandidateBase; + Produces rowCandidateKF; + Produces rowProng0PidPi; + Produces rowProng0PidKa; + Produces rowProng0PidPr; + Produces rowProng0PidDe; + Produces rowProng1PidPi; + Produces rowProng1PidKa; + Produces rowProng1PidPr; + Produces rowProng1PidDe; + Produces rowProng2PidPi; + Produces rowProng2PidKa; + Produces rowProng2PidPr; + Produces rowProng2PidDe; // vertexing Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -59,7 +120,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 @@ -67,62 +127,88 @@ struct HfCandidateCreator3Prong { Configurable createDs{"createDs", false, "enable Ds+/- candidate creation"}; Configurable createLc{"createLc", false, "enable Lc+/- candidate creation"}; Configurable createXic{"createXic", false, "enable Xic+/- candidate creation"}; + Configurable createCd{"createCd", false, "enable Cd candidate creation"}; + // KF + Configurable applyTopoConstraint{"applyTopoConstraint", false, "apply origin from PV hypothesis for created candidate, works only in KF mode"}; + Configurable applyInvMassConstraint{"applyInvMassConstraint", false, "apply particle type hypothesis to recalculate created candidate's momentum, works only in KF mode"}; 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 massPi{0.}; - double massK{0.}; - double massPiKPi{0.}; double bz{0.}; + const float toMicrometers = 10000.; // from cm to µm + constexpr static float UndefValueFloat{-999.f}; + using FilteredHf3Prongs = soa::Filtered; using FilteredPvRefitHf3Prongs = soa::Filtered>; + using TracksWCovExtraPidPiKaPrDe = soa::Join; // 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)); + Filter filterSelected3Prongs = (createDplus && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::DplusToPiKPi))) != static_cast(0)) || (createDs && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::DsToKKPi))) != static_cast(0)) || (createLc && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::LcToPKPi))) != static_cast(0)) || (createXic && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::XicToPKPi))) != static_cast(0)) || (createCd && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::CdToDeKPi))) != static_cast(0)); std::shared_ptr hCandidates; HistogramRegistry registry{"registry"}; + OutputObj zorroSummary{"zorroSummary"}; 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, doprocessPvRefitWithDCAFitterNUpc, doprocessNoPvRefitWithDCAFitterNUpc}; + std::array doprocessKF{doprocessPvRefitWithKFParticle, doprocessNoPvRefitWithKFParticle, + doprocessPvRefitWithKFParticleCentFT0C, doprocessNoPvRefitWithKFParticleCentFT0C, + doprocessPvRefitWithKFParticleCentFT0M, doprocessNoPvRefitWithKFParticleCentFT0M, doprocessPvRefitWithKFParticleUpc, doprocessNoPvRefitWithKFParticleUpc}; + 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."); } - - std::array processesCollisions = {doprocessCollisions, doprocessCollisionsCentFT0C, doprocessCollisionsCentFT0M}; + std::array processesCollisions = {doprocessCollisions, doprocessCollisionsCentFT0C, doprocessCollisionsCentFT0M, doprocessCollisionsUpc}; const int nProcessesCollisions = std::accumulate(processesCollisions.begin(), processesCollisions.end(), 0); + + std::array processesUpc = {doprocessPvRefitWithDCAFitterNUpc, doprocessNoPvRefitWithDCAFitterNUpc, doprocessPvRefitWithKFParticleUpc, doprocessNoPvRefitWithKFParticleUpc, doprocessCollisionsUpc}; + const int nProcessesUpc = std::accumulate(processesUpc.begin(), processesUpc.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 ((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\"?"); } + if ((doprocessPvRefitWithDCAFitterNUpc || doprocessNoPvRefitWithDCAFitterNUpc || doprocessPvRefitWithKFParticleUpc || doprocessNoPvRefitWithKFParticleUpc) && !doprocessCollisionsUpc) { + LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisionsUpc\"?"); + } } - - std::array creationFlags = {createDplus, createDs, createLc, createXic}; + if (nProcessesUpc > 0 && isRun2) { + LOGP(fatal, "Process function for UPC is only available in Run 3!"); + } + std::array creationFlags = {createDplus, createDs, createLc, createXic, createCd}; if (std::accumulate(creationFlags.begin(), creationFlags.end(), 0) == 0) { LOGP(fatal, "At least one particle specie should be enabled for the creation."); } + if (createLc && createXic && applyInvMassConstraint) { + LOGP(fatal, "Unable to apply invariant mass constraint due to ambiguity of mass hypothesis: only one of Lc and Xic and Cd can be reconstructed."); + } + // 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("hMass3DeKPi", "3-prong candidates;inv. mass (deK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{2000, 2.5, 4.5}}}); + registry.add("hMass3PiKDe", "3-prong candidates;inv. mass (#pi Kde) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{2000, 2.5, 4.5}}}); + 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}}}); @@ -134,10 +220,9 @@ struct HfCandidateCreator3Prong { 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.}}}); hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); - hfEvSel.addHistograms(registry); // collision monitoring - massPi = MassPiPlus; - massK = MassKPlus; + // init HF event selection helper + hfEvSel.init(registry, zorroSummary); // Configure DCAFitterN // df.setBz(bz); @@ -152,18 +237,40 @@ struct HfCandidateCreator3Prong { ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); runNumber = 0; /// candidate monitoring setLabelHistoCands(hCandidates); } - template - void runCreator3Prong(Coll const&, - Cand const& rowsTrackIndexProng3, - aod::TracksWCovExtra const&, - aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + template + void fillProngsPid(TRK const& track0, TRK const& track1, TRK const& track2) + { + fillProngPid(track0, rowProng0PidPi); + fillProngPid(track0, rowProng0PidKa); + fillProngPid(track1, rowProng1PidPi); + fillProngPid(track1, rowProng1PidKa); + fillProngPid(track2, rowProng2PidPi); + fillProngPid(track2, rowProng2PidKa); + + /// fill proton PID information only if necessary + if (createLc || createXic) { + fillProngPid(track0, rowProng0PidPr); + fillProngPid(track1, rowProng1PidPr); + fillProngPid(track2, rowProng2PidPr); + } + if (createCd) { + fillProngPid(track0, rowProng0PidDe); + fillProngPid(track1, rowProng1PidDe); + fillProngPid(track2, rowProng2PidDe); + } + } + + template + void runCreator3ProngWithDCAFitterN(Coll const&, + Cand const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe const&, + BCsType const& bcs) { // loop over triplets of track indices for (const auto& rowTrackIndexProng3 : rowsTrackIndexProng3) { @@ -171,15 +278,20 @@ struct HfCandidateCreator3Prong { /// 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); + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + if constexpr (ApplyUpcSel) { + rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); + } else { + 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(); + auto track0 = rowTrackIndexProng3.template prong0_as(); + auto track1 = rowTrackIndexProng3.template prong1_as(); + auto track2 = rowTrackIndexProng3.template prong2_as(); auto trackParVar0 = getTrackParCov(track0); auto trackParVar1 = getTrackParCov(track1); auto trackParVar2 = getTrackParCov(track2); @@ -187,10 +299,10 @@ struct HfCandidateCreator3Prong { /// 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(); + 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,9 +335,9 @@ struct HfCandidateCreator3Prong { trackParVar2 = df.getTrack(2); // get track momenta - std::array pvec0; - std::array pvec1; - std::array pvec2; + std::array pvec0{}; + std::array pvec1{}; + std::array pvec2{}; trackParVar0.getPxPyPzGlo(pvec0); trackParVar1.getPxPyPzGlo(pvec1); trackParVar2.getPxPyPzGlo(pvec2); @@ -234,7 +346,7 @@ struct HfCandidateCreator3Prong { // This modifies track momenta! auto primaryVertex = getPrimaryVertex(collision); auto covMatrixPV = primaryVertex.getCov(); - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { /// use PV refit /// Using it in the rowCandidateBase all dynamic columns shall take it into account // coordinates @@ -274,16 +386,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); } + const auto nProngsContributorsPV = hf_trkcandsel::countOnesInBinary(bitmapProngsContributorsPV); // fill candidate table rows rowCandidateBase(indexCollision, @@ -298,15 +411,277 @@ 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 candidate prong PID rows + fillProngsPid(track0, track1, track2); + // 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); + const auto arrayMomenta = std::array{pvec0, pvec1, pvec2}; + const auto massPKPi = RecoDecay::m(arrayMomenta, std::array{MassProton, MassKPlus, MassPiPlus}); + const auto massPiKP = RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus, MassProton}); + const auto massPiKPi = RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus, MassPiPlus}); + const auto massKKPi = RecoDecay::m(arrayMomenta, std::array{MassKPlus, MassKPlus, MassPiPlus}); + const auto massPiKK = RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus, MassKPlus}); + const auto massDeKPi = RecoDecay::m(arrayMomenta, std::array{MassDeuteron, MassKPlus, MassPiPlus}); + const auto massPiKDe = RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus, MassDeuteron}); + const auto massKPi = RecoDecay::m(std::array{arrayMomenta.at(1), arrayMomenta.at(2)}, std::array{MassKPlus, MassPiPlus}); + const auto massPiK = RecoDecay::m(std::array{arrayMomenta.at(0), arrayMomenta.at(1)}, std::array{MassPiPlus, MassKPlus}); + 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("hMass3DeKPi"), massDeKPi); + registry.fill(HIST("hMass3PiKDe"), massPiKDe); + registry.fill(HIST("hMass2KPi"), massKPi); + registry.fill(HIST("hMass2PiK"), massPiK); + } + } + } + + template + void runCreator3ProngWithKFParticle(Coll const&, + Cand const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe const&, + BCsType const& bcs) + { + for (const auto& rowTrackIndexProng3 : rowsTrackIndexProng3) { + /// reject candidates in collisions not satisfying the event selections + auto collision = rowTrackIndexProng3.template collision_as(); + float centrality{-1.f}; + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + if constexpr (ApplyUpcSel) { + rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); + } else { + 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 const kfpTrack0 = createKFPTrackFromTrack(track0); + KFPTrack const kfpTrack1 = createKFPTrackFromTrack(track1); + KFPTrack const kfpTrack2 = createKFPTrackFromTrack(track2); + + KFParticle const kfFirstProton(kfpTrack0, kProton); + KFParticle const kfFirstPion(kfpTrack0, kPiPlus); + KFParticle const kfFirstKaon(kfpTrack0, kKPlus); + KFParticle const kfSecondKaon(kfpTrack1, kKPlus); + KFParticle const kfThirdProton(kfpTrack2, kProton); + KFParticle const kfThirdPion(kfpTrack2, kPiPlus); + KFParticle const 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); + + const float chi2topo = kfCalculateChi2ToPrimaryVertex(kfCandPKPi, kfpV); + + if (applyTopoConstraint) { // constraints applied after chi2topo getter - to preserve unbiased value of chi2topo + for (const auto& kfCand : std::array{&kfCandPKPi, &kfCandPiKP, &kfCandPiKPi, &kfCandKKPi, &kfCandPiKK}) { + kfCand->SetProductionVertex(kfpV); + kfCand->TransportToDecayVertex(); + } + } + + 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(); + + if (applyInvMassConstraint) { // constraints applied after minv getters - to preserve unbiased values of minv + kfCandPKPi.SetNonlinearMassConstraint(createLc ? MassLambdaCPlus : MassXiCPlus); + kfCandPiKP.SetNonlinearMassConstraint(createLc ? MassLambdaCPlus : MassXiCPlus); + kfCandPiKPi.SetNonlinearMassConstraint(MassDPlus); + kfCandKKPi.SetNonlinearMassConstraint(MassDS); + kfCandPiKK.SetNonlinearMassConstraint(MassDS); + } + + const float chi2geo = kfCandPKPi.Chi2() / kfCandPKPi.NDF(); + 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); + } + const auto 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 candidate prong PID rows + fillProngsPid(track0, track1, track2); + + // 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); } } } @@ -317,25 +692,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, + TracksWCovExtraPidPiKaPrDe 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, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefit, "Run candidate creator with PV refit and w/o centrality selections", false); + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter without PV refit and w/o centrality selections", true); - /// @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/ PV refit and w/o centrality selections + void processPvRefitWithKFParticle(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe 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, processPvRefitWithKFParticle, "Run candidate creator using KFParticle package with PV refit and w/o centrality selections", false); + + /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections + void processNoPvRefitWithKFParticle(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithKFParticle, "Run candidate creator using KFParticle package without PV refit and w/o centrality selections", false); ///////////////////////////////////////////// /// /// @@ -343,25 +738,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, + TracksWCovExtraPidPiKaPrDe 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, + TracksWCovExtraPidPiKaPrDe 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, + TracksWCovExtraPidPiKaPrDe 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, + TracksWCovExtraPidPiKaPrDe 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); ///////////////////////////////////////////// /// /// @@ -369,25 +784,107 @@ 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, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter with PV refit and w/ centrality selection on FT0M", false); + + /// @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, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) + { + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + 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, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitCentFT0M, "Run candidate creator with PV refit and w/ centrality selection on FT0M", false); + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticleCentFT0M, "Run candidate creator using KFParticle package 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 KFParticle package w/o PV refit and w/ centrality selection on FT0M + void processNoPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BCsWithTimestamps const& bcWithTimeStamps) { - runCreator3Prong(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); } - PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitCentFT0M, "Run candidate creator without PV refit and w/ centrality selection on FT0M", false); + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithKFParticleCentFT0M, "Run candidate creator using KFParticle package without PV refit and w/ centrality selection on FT0M", false); + + ///////////////////////////////////////////// + /// /// + /// with centrality selection on UPC /// + /// /// + ///////////////////////////////////////////// + + /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on UPC + void processPvRefitWithDCAFitterNUpc(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BcFullInfos const& bcWithTimeStamps, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterNUpc, "Run candidate creator using DCA fitter with PV refit and w/ centrality selection on UPC", false); + + /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on UPC + void processNoPvRefitWithDCAFitterNUpc(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BcFullInfos const& bcWithTimeStamps, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterNUpc, "Run candidate creator using DCA fitter without PV refit and w/ centrality selection on UPC", false); + + /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on UPC + void processPvRefitWithKFParticleUpc(soa::Join const& collisions, + FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BcFullInfos const& bcWithTimeStamps, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticleUpc, "Run candidate creator using KFParticle package with PV refit and w/ centrality selection on UPC", false); + + /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on UPC + void processNoPvRefitWithKFParticleUpc(soa::Join const& collisions, + FilteredHf3Prongs const& rowsTrackIndexProng3, + TracksWCovExtraPidPiKaPrDe const& tracks, + aod::BcFullInfos const& bcWithTimeStamps, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithKFParticleUpc, "Run candidate creator using KFParticle package without PV refit and w/ centrality selection on UPC", false); /////////////////////////////////////////////////////////// /// /// @@ -403,10 +900,12 @@ struct HfCandidateCreator3Prong { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -420,10 +919,12 @@ struct HfCandidateCreator3Prong { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -437,14 +938,40 @@ struct HfCandidateCreator3Prong { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } PROCESS_SWITCH(HfCandidateCreator3Prong, processCollisionsCentFT0M, "Collision monitoring - FT0M centrality", false); + + /// @brief process function to monitor collisions - UPC + void processCollisionsUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + /// loop over collisions + for (const auto& collision : collisions) { + + /// bitmask with event. selection info + float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); + + } /// end loop over collisions + } + PROCESS_SWITCH(HfCandidateCreator3Prong, processCollisionsUpc, "Collision monitoring - UPC", false); }; /// Extends the base table with expression columns. @@ -454,24 +981,28 @@ struct HfCandidateCreator3ProngExpressions { Produces rowMcMatchGen; // Configuration - o2::framework::Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + 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"}; + Configurable matchCorrelatedBackground{"matchCorrelatedBackground", false, "Match correlated background candidates"}; + Configurable> pdgMothersCorrelBkg{"pdgMothersCorrelBkg", {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, Pdg::kLambdaCPlus, Pdg::kXiCPlus}, "PDG codes of the mother particles of correlated background candidates"}; - bool createDplus{false}; - bool createDs{false}; - bool createLc{false}; - bool createXic{false}; + constexpr static std::size_t NDaughtersResonant{2u}; HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring - using BCsInfo = soa::Join; - HistogramRegistry registry{"registry"}; + 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; - Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + + HistogramRegistry registry{"registry"}; void init(InitContext& initContext) { @@ -483,63 +1014,48 @@ struct HfCandidateCreator3ProngExpressions { // 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) { - hfEvSelMc.configureFromDevice(device); - 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(); - } - } + if (device.name == "hf-candidate-creator-3prong") { + // init HF event selection helper + hfEvSelMc.init(device, registry); break; } } - - hfEvSelMc.addHistograms(registry); // particles monitoring - - 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); } /// Performs MC matching. - template + template void runCreator3ProngMc(aod::TracksWMc const& tracks, aod::McParticles const& mcParticles, CCs const& collInfos, - aod::McCollisions const& mcCollisions, + McCollisions const& mcCollisions, BCsInfo const&) { rowCandidateProng3->bindExternalIndices(&tracks); int indexRec = -1; int8_t sign = 0; - int8_t flag = 0; + int8_t flagChannelMain = 0; + int8_t flagChannelResonant = 0; int8_t origin = 0; int8_t swapping = 0; - int8_t channel = 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 arrPDGResonantDPhiPi = {333, kPiPlus}; // Ds± → Phi π± and D± → Phi π± - std::array arrPDGResonantDKstarK = {313, kKPlus}; // Ds± → K*(892)0bar K± and D± → K*(892)0bar K± + int8_t nKinkedTracks = 0; + int8_t nInteractionsWithMaterial = 0; + std::vector arrDaughIndex{}; + std::array arrPdgDaugResonant{}; + const std::array arrPdgDaugResonantLcToPKstar0{daughtersLcResonant.at(DecayChannelResonant::LcToPKstar0)}; // Λc± → p± K* + const std::array arrPdgDaugResonantLcToDeltaplusplusK{daughtersLcResonant.at(DecayChannelResonant::LcToDeltaplusplusK)}; // Λc± → Δ(1232)±± K∓ + const std::array arrPdgDaugResonantLcToL1520Pi{daughtersLcResonant.at(DecayChannelResonant::LcToL1520Pi)}; // Λc± → Λ(1520) π± + const std::array arrPdgDaugResonantDToPhiPi{daughtersDsResonant.at(DecayChannelResonant::DsToPhiPi)}; // Ds± → φ π± and D± → φ π± + const std::array arrPdgDaugResonantDToKstar0K{daughtersDsResonant.at(DecayChannelResonant::DsToKstar0K)}; // Ds± → anti-K*(892)0 K± and D± → anti-K*(892)0 K± // Match reconstructed candidates. // Spawned table can be used directly for (const auto& candidate : *rowCandidateProng3) { - flag = 0; + flagChannelMain = 0; + flagChannelResonant = 0; origin = 0; swapping = 0; - channel = 0; + indexRec = -1; arrDaughIndex.clear(); std::vector idxBhadMothers{}; auto arrayDaughters = std::array{candidate.prong0_as(), candidate.prong1_as(), candidate.prong2_as()}; @@ -557,94 +1073,250 @@ struct HfCandidateCreator3ProngExpressions { } } if (fromBkg) { - rowMcMatchRec(flag, origin, swapping, channel, -1.f, 0); + rowMcMatchRec(flagChannelMain, origin, swapping, flagChannelResonant, -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 (indexRec > -1) { - flag = sign * (1 << DecayType::DplusToPiKPi); - } - } + if (matchCorrelatedBackground) { + indexRec = -1; // Index of the matched reconstructed candidate + constexpr int DepthMainMax = 2; // Depth for final state matching + constexpr int DepthResoMax = 1; // Depth for resonant decay matching + + for (const auto& pdgMother : pdgMothersCorrelBkg.value) { + int depthMainMax = DepthMainMax; + if (pdgMother == Pdg::kDStar) { + depthMainMax = DepthMainMax + 1; // D0 resonant decays are active + } + auto finalStates = getDecayChannelsMain(pdgMother); + for (const auto& [channelMain, finalState] : finalStates) { + std::array const arrPdgDaughtersMain3Prongs = std::array{finalState[0], finalState[1], finalState[2]}; + if (finalState.size() > 3) { // o2-linter: disable=magic-number (partially reconstructed decays with 4 or 5 final state particles) + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax); + } - // Ds± → K± K∓ π± and D± → K± K∓ π± - if (flag == 0 && createDs) { - bool isDplus = false; - 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 (indexRec > -1) { + auto motherParticle = mcParticles.rawIteratorAt(indexRec); + if (finalState.size() == 4) { // o2-linter: disable=magic-number (Check if the final state has 4 particles) + std::array arrPdgDaughtersMain4Prongs = std::array{finalState[0], finalState[1], finalState[2], finalState[3]}; + flipPdgSign(motherParticle.pdgCode(), +kPi0, arrPdgDaughtersMain4Prongs); + if (!RecoDecay::isMatchedMCGen(mcParticles, motherParticle, pdgMother, arrPdgDaughtersMain4Prongs, true, &sign, depthMainMax)) { + indexRec = -1; // Reset indexRec if the generated decay does not match the reconstructed one is not matched + } + } else if (finalState.size() == 5) { // o2-linter: disable=magic-number (Check if the final state has 5 particles) + std::array arrPdgDaughtersMain5Prongs = std::array{finalState[0], finalState[1], finalState[2], finalState[3], finalState[4]}; + flipPdgSign(motherParticle.pdgCode(), +kPi0, arrPdgDaughtersMain5Prongs); + if (!RecoDecay::isMatchedMCGen(mcParticles, motherParticle, pdgMother, arrPdgDaughtersMain5Prongs, true, &sign, depthMainMax)) { + indexRec = -1; // Reset indexRec if the generated decay does not match the reconstructed one is not matched + } + } + } + } else if (finalState.size() == 3) { // o2-linter: disable=magic-number (fully reconstructed 3-prong decays) + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax); + } + } else { + LOG(fatal) << "Final state size not supported: " << finalState.size(); + return; + } + if (indexRec > -1) { + flagChannelMain = sign * channelMain; + + /// swapping for D+, Ds->Kpipi; Lc, Xic->pKpi + if (std::abs(flagChannelMain) == DecayChannelMain::DplusToPiKK || std::abs(flagChannelMain) == DecayChannelMain::DsToPiKK || std::abs(flagChannelMain) == DecayChannelMain::LcToPKPi || std::abs(flagChannelMain) == DecayChannelMain::XicToPKPi) { + if (arrayDaughters[0].has_mcParticle()) { + swapping = static_cast(std::abs(arrayDaughters[0].mcParticle().pdgCode()) == kPiPlus); + } + } + + // Flag the resonant decay channel + std::vector arrResoDaughIndex = {}; + if (pdgMother == Pdg::kDStar) { + std::vector arrResoDaughIndexDstar = {}; + RecoDecay::getDaughters(mcParticles.rawIteratorAt(indexRec), &arrResoDaughIndexDstar, std::array{0}, DepthResoMax); + for (const int iDaug : arrResoDaughIndexDstar) { // o2-linter: disable=const-ref-in-for-loop (int elements) + auto daughDstar = mcParticles.rawIteratorAt(iDaug); + if (std::abs(daughDstar.pdgCode()) == Pdg::kD0 || std::abs(daughDstar.pdgCode()) == Pdg::kDPlus) { + RecoDecay::getDaughters(daughDstar, &arrResoDaughIndex, std::array{0}, DepthResoMax); + break; + } + } + } else { + RecoDecay::getDaughters(mcParticles.rawIteratorAt(indexRec), &arrResoDaughIndex, std::array{0}, DepthResoMax); + } + std::array arrPdgDaughters = {}; + if (arrResoDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < NDaughtersResonant; ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrResoDaughIndex[iProng]); + arrPdgDaughters[iProng] = daughI.pdgCode(); + } + flagChannelResonant = getDecayChannelResonant(pdgMother, arrPdgDaughters); + } + break; // Exit loop if a match is found + } + } + if (indexRec > -1) { + break; // Exit loop if a match is found + } + } + } else { + // D± → π± K∓ π± + if (flagChannelMain == 0) { + auto arrPdgDaughtersDplusToPiKPi{std::array{+kPiPlus, -kKPlus, +kPiPlus}}; + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, arrPdgDaughtersDplusToPiKPi, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, arrPdgDaughtersDplusToPiKPi, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, arrPdgDaughtersDplusToPiKPi, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, arrPdgDaughtersDplusToPiKPi, true, &sign, 2); + } + if (indexRec > -1) { + flagChannelMain = sign * DecayChannelMain::DplusToPiKPi; + } } - if (indexRec > -1) { - // 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); - if (arrayDaughters[0].has_mcParticle()) { - swapping = int8_t(std::abs(arrayDaughters[0].mcParticle().pdgCode()) == kPiPlus); + + // Ds± → K± K∓ π± and D± → K± K∓ π± + if (flagChannelMain == 0) { + auto arrPdgDaughtersDToPiKK{std::array{+kKPlus, -kKPlus, +kPiPlus}}; + bool isDplus = false; + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, arrPdgDaughtersDToPiKK, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, arrPdgDaughtersDToPiKK, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, arrPdgDaughtersDToPiKK, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDS, arrPdgDaughtersDToPiKK, true, &sign, 2); + } + if (indexRec == -1) { + isDplus = true; + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, arrPdgDaughtersDToPiKK, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, arrPdgDaughtersDToPiKK, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, arrPdgDaughtersDToPiKK, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDPlus, arrPdgDaughtersDToPiKK, true, &sign, 2); + } } - RecoDecay::getDaughters(mcParticles.rawIteratorAt(indexRec), &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 (indexRec > -1) { + flagChannelMain = sign * (isDplus ? DecayChannelMain::DplusToPiKK : DecayChannelMain::DsToPiKK); + if (arrayDaughters[0].has_mcParticle()) { + swapping = static_cast(std::abs(arrayDaughters[0].mcParticle().pdgCode()) == kPiPlus); } - 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; + RecoDecay::getDaughters(mcParticles.rawIteratorAt(indexRec), &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < arrDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrDaughIndex[iProng]); + arrPdgDaugResonant[iProng] = std::abs(daughI.pdgCode()); + } + if ((arrPdgDaugResonant[0] == arrPdgDaugResonantDToPhiPi[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantDToPhiPi[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantDToPhiPi[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantDToPhiPi[0])) { + flagChannelResonant = isDplus ? DecayChannelResonant::DplusToPhiPi : DecayChannelResonant::DsToPhiPi; + } else if ((arrPdgDaugResonant[0] == arrPdgDaugResonantDToKstar0K[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantDToKstar0K[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantDToKstar0K[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantDToKstar0K[0])) { + flagChannelResonant = isDplus ? DecayChannelResonant::DplusToKstar0K : DecayChannelResonant::DsToKstar0K; + } } } } - } - // Λc± → p± K∓ π± - if (flag == 0 && createLc) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); - if (indexRec > -1) { - flag = sign * (1 << DecayType::LcToPKPi); + // D* → D0 π → K π π + if (flagChannelMain == 0) { + auto arrPdgDaughtersDstarToPiKPi{std::array{+kPiPlus, +kPiPlus, -kKPlus}}; + if (matchKinkedDecayTopology) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDStar, arrPdgDaughtersDstarToPiKPi, true, &sign, 2, &nKinkedTracks); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kDStar, arrPdgDaughtersDstarToPiKPi, true, &sign, 2); + } + if (indexRec > -1) { + flagChannelMain = sign * DecayChannelMain::DstarToPiKPi; + flagChannelResonant = 0; + } + } - // Flagging the different Λc± → p± K∓ π± decay channels - if (arrayDaughters[0].has_mcParticle()) { - swapping = int8_t(std::abs(arrayDaughters[0].mcParticle().pdgCode()) == kPiPlus); + // Λc± → p± K∓ π± + if (flagChannelMain == 0) { + auto arrPdgDaughtersLcToPKPi{std::array{+kProton, -kKPlus, +kPiPlus}}; + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, arrPdgDaughtersLcToPKPi, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, arrPdgDaughtersLcToPKPi, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, arrPdgDaughtersLcToPKPi, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kLambdaCPlus, arrPdgDaughtersLcToPKPi, true, &sign, 2); } - RecoDecay::getDaughters(mcParticles.rawIteratorAt(indexRec), &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 (indexRec > -1) { + flagChannelMain = sign * DecayChannelMain::LcToPKPi; + + // Flagging the different Λc± → p± K∓ π± decay channels + if (arrayDaughters[0].has_mcParticle()) { + swapping = static_cast(std::abs(arrayDaughters[0].mcParticle().pdgCode()) == kPiPlus); } - 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; + RecoDecay::getDaughters(mcParticles.rawIteratorAt(indexRec), &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < arrDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrDaughIndex[iProng]); + arrPdgDaugResonant[iProng] = std::abs(daughI.pdgCode()); + } + if ((arrPdgDaugResonant[0] == arrPdgDaugResonantLcToPKstar0[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToPKstar0[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantLcToPKstar0[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToPKstar0[0])) { + flagChannelResonant = DecayChannelResonant::LcToPKstar0; + } else if ((arrPdgDaugResonant[0] == arrPdgDaugResonantLcToDeltaplusplusK[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToDeltaplusplusK[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantLcToDeltaplusplusK[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToDeltaplusplusK[0])) { + flagChannelResonant = DecayChannelResonant::LcToDeltaplusplusK; + } else if ((arrPdgDaugResonant[0] == arrPdgDaugResonantLcToL1520Pi[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToL1520Pi[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantLcToL1520Pi[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToL1520Pi[0])) { + flagChannelResonant = DecayChannelResonant::LcToL1520Pi; + } } } } - } - // Ξc± → p± K∓ π± - if (flag == 0 && createXic) { - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); - if (indexRec > -1) { - flag = sign * (1 << DecayType::XicToPKPi); + // Ξc± → p± K∓ π± + if (flagChannelMain == 0) { + auto arrPdgDaughtersXicToPKPi{std::array{+kProton, -kKPlus, +kPiPlus}}; + if (matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, arrPdgDaughtersXicToPKPi, true, &sign, 2, &nKinkedTracks, &nInteractionsWithMaterial); + } else if (matchKinkedDecayTopology && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, arrPdgDaughtersXicToPKPi, true, &sign, 2, &nKinkedTracks); + } else if (!matchKinkedDecayTopology && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, arrPdgDaughtersXicToPKPi, true, &sign, 2, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, arrPdgDaughtersXicToPKPi, true, &sign, 2); + } + if (indexRec > -1) { + flagChannelMain = sign * DecayChannelMain::XicToPKPi; + flagChannelResonant = 0; // TODO + if (arrayDaughters[0].has_mcParticle()) { + swapping = static_cast(std::abs(arrayDaughters[0].mcParticle().pdgCode()) == kPiPlus); + } + } } } // Check whether the particle is non-prompt (from a b quark). - if (flag != 0) { + if (flagChannelMain != 0) { auto particle = mcParticles.rawIteratorAt(indexRec); origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); } if (origin == RecoDecay::OriginType::NonPrompt) { auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); - rowMcMatchRec(flag, origin, swapping, channel, bHadMother.pt(), bHadMother.pdgCode()); + rowMcMatchRec(flagChannelMain, origin, swapping, flagChannelResonant, bHadMother.pt(), bHadMother.pdgCode(), nKinkedTracks, nInteractionsWithMaterial); } else { - rowMcMatchRec(flag, origin, swapping, channel, -1.f, 0); + rowMcMatchRec(flagChannelMain, origin, swapping, flagChannelResonant, -1.f, 0, nKinkedTracks, nInteractionsWithMaterial); } } @@ -654,18 +1326,20 @@ struct HfCandidateCreator3ProngExpressions { 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) { + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + 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) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (CentEstimator == CentralityEstimator::FT0M) { const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); - rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); - } else if constexpr (centEstimator == CentralityEstimator::None) { + 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); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); } - hfEvSelMc.fillHistograms(rejectionMask); + 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) { @@ -673,96 +1347,7 @@ struct HfCandidateCreator3ProngExpressions { } continue; } - - // Match generated particles. - for (const auto& particle : mcParticlesPerMcColl) { - flag = 0; - origin = 0; - channel = 0; - arrDaughIndex.clear(); - std::vector idxBhadMothers{}; - // Reject particles from background events - if (particle.fromBackgroundEvent() && rejectBackground) { - rowMcMatchGen(flag, origin, channel, -1); - continue; - } - - // 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; - } - } - } - } - - // Λ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); - - // 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 && createXic) { - if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { - flag = sign * (1 << 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); - } - } + hf_mc_gen::fillMcMatchGen3Prong(mcParticles, mcParticlesPerMcColl, rowMcMatchGen, rejectBackground, matchCorrelatedBackground ? pdgMothersCorrelBkg : std::vector{}); } } @@ -770,9 +1355,9 @@ struct HfCandidateCreator3ProngExpressions { aod::McParticles const& mcParticles, McCollisionsNoCents const& collInfos, aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + BCsInfo const& bcsInfo) { - runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreator3ProngExpressions, processMc, "Process MC - no centrality", false); @@ -780,19 +1365,19 @@ struct HfCandidateCreator3ProngExpressions { aod::McParticles const& mcParticles, McCollisionsFT0Cs const& collInfos, aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + BCsInfo const& bcsInfo) { - runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreator3ProngExpressions, processMcCentFT0C, "Process MC - FT0c centrality", false); void processMcCentFT0M(aod::TracksWMc const& tracks, aod::McParticles const& mcParticles, McCollisionsFT0Ms const& collInfos, - aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + McCollisionsCentFT0Ms const& mcCollisions, + BCsInfo const& bcsInfo) { - runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreator3ProngMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreator3ProngExpressions, processMcCentFT0M, "Process MC - FT0m centrality", false); }; @@ -800,6 +1385,6 @@ struct HfCandidateCreator3ProngExpressions { 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 559734c7b12..0387acf0b15 100644 --- a/PWGHF/TableProducer/candidateCreatorB0.cxx +++ b/PWGHF/TableProducer/candidateCreatorB0.cxx @@ -15,22 +15,51 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/V0.h" - -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsMcGen.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::aod; @@ -38,6 +67,7 @@ using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::hf_trkcandsel; +using namespace o2::hf_decay::hf_cand_beauty; /// Reconstruction of B0 candidates struct HfCandidateCreatorB0 { @@ -57,7 +87,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 @@ -67,11 +97,10 @@ struct HfCandidateCreatorB0 { 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)"}; - HfHelper hfHelper; Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - int runNumber; + int runNumber{}; double massPi{0.}; double massD{0.}; @@ -93,6 +122,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 +133,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 @@ -200,7 +229,7 @@ struct HfCandidateCreatorB0 { auto candsDThisColl = candsD.sliceBy(candsDPerCollision, thisCollId); for (const auto& candD : candsDThisColl) { // start loop over filtered D candidates indices as associated to this collision in candidateCreator3Prong.cxx - hMassDToPiKPi->Fill(hfHelper.invMassDplusToPiKPi(candD), candD.pt()); + hMassDToPiKPi->Fill(HfHelper::invMassDplusToPiKPi(candD), candD.pt()); hPtD->Fill(candD.pt()); hCPAD->Fill(candD.cpa()); @@ -259,14 +288,14 @@ struct HfCandidateCreatorB0 { df3.getTrack(2).getPxPyPzGlo(pVec2); // D∓ → π∓ K± π∓ - std::array pVecPiK = RecoDecay::pVec(pVec0, pVec1); + std::array const pVecPiK = RecoDecay::pVec(pVec0, pVec1); std::array pVecD = RecoDecay::pVec(pVec0, pVec1, pVec2); auto trackParCovPiK = o2::dataformats::V0(df3.getPCACandidatePos(), pVecPiK, df3.calcPCACovMatrixFlat(), trackParCov0, trackParCov1); auto trackParCovD = o2::dataformats::V0(df3.getPCACandidatePos(), pVecD, df3.calcPCACovMatrixFlat(), trackParCovPiK, trackParCov2); - int indexTrack0 = track0.globalIndex(); - int indexTrack1 = track1.globalIndex(); - int indexTrack2 = track2.globalIndex(); + int const indexTrack0 = track0.globalIndex(); + int const indexTrack1 = track1.globalIndex(); + int const indexTrack2 = track2.globalIndex(); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); @@ -355,10 +384,10 @@ struct HfCandidateCreatorB0 { 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 { @@ -376,13 +405,14 @@ struct HfCandidateCreatorB0Expressions { int indexRec = -1; int8_t sign = 0; - int8_t flag = 0; + int8_t flagChannelMain = 0; + int8_t flagChannelReso = 0; int8_t origin = 0; int8_t debug = 0; // Match reconstructed candidates. for (const auto& candidate : candsB0) { - flag = 0; + flagChannelMain = 0; origin = 0; debug = 0; auto candD = candidate.prong0(); @@ -400,7 +430,7 @@ struct HfCandidateCreatorB0Expressions { // D- → π- K+ π- indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersD, Pdg::kDMinus, std::array{-kPiPlus, +kKPlus, -kPiPlus}, true, &sign, 2); if (indexRec > -1) { - flag = sign * BIT(hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi); + flagChannelMain = sign * DecayChannelMain::B0ToDminusPi; } else { debug = 1; LOGF(debug, "WARNING: B0 in decays in the expected final state but the condition on the intermediate state is not fulfilled"); @@ -408,61 +438,46 @@ struct HfCandidateCreatorB0Expressions { } // B0 → Ds- π+ → (K- K+ π-) π+ - if (!flag) { + if (flagChannelMain == 0) { indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersB0, Pdg::kB0, std::array{-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); if (indexRec > -1) { // Ds- → K- K+ π- indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersD, -Pdg::kDS, std::array{-kKPlus, +kKPlus, -kPiPlus}, true, &sign, 2); if (indexRec > -1) { - flag = sign * BIT(hf_cand_b0::DecayTypeMc::B0ToDsPiToKKPiPi); + flagChannelMain = sign * DecayChannelMain::B0ToDsPi; } } } // 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) { + if (flagChannelMain == 0) { auto particleProng0 = arrayDaughtersB0[0].mcParticle(); auto particleProng1 = arrayDaughtersB0[1].mcParticle(); auto particleProng2 = arrayDaughtersB0[2].mcParticle(); auto particleProng3 = arrayDaughtersB0[3].mcParticle(); // b-hadron hypothesis - std::array bHadronMotherHypos = {Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; + std::array const bHadronMotherHypos = {Pdg::kB0, Pdg::kBS, Pdg::kLambdaB0}; for (const auto& bHadronMotherHypo : bHadronMotherHypos) { - int index0Mother = RecoDecay::getMother(mcParticles, particleProng0, bHadronMotherHypo, true); - int index1Mother = RecoDecay::getMother(mcParticles, particleProng1, bHadronMotherHypo, true); - int index2Mother = RecoDecay::getMother(mcParticles, particleProng2, bHadronMotherHypo, true); - int index3Mother = RecoDecay::getMother(mcParticles, particleProng3, bHadronMotherHypo, true); + int const index0Mother = RecoDecay::getMother(mcParticles, particleProng0, bHadronMotherHypo, true); + int const index1Mother = RecoDecay::getMother(mcParticles, particleProng1, bHadronMotherHypo, true); + int const index2Mother = RecoDecay::getMother(mcParticles, particleProng2, bHadronMotherHypo, true); + int const index3Mother = RecoDecay::getMother(mcParticles, 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_b0::DecayTypeMc::PartlyRecoDecay); - break; - } + if (index0Mother > -1 && index0Mother == index1Mother && index1Mother == index2Mother && index2Mother == index3Mother) { + flagChannelMain = hf_cand_b0::DecayTypeMc::PartlyRecoDecay; // FIXME + break; } } } - rowMcMatchRec(flag, origin, debug); + rowMcMatchRec(flagChannelMain, flagChannelReso, 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 b8845945df9..20e1536cd7e 100644 --- a/PWGHF/TableProducer/candidateCreatorBplus.cxx +++ b/PWGHF/TableProducer/candidateCreatorBplus.cxx @@ -18,22 +18,54 @@ /// \author Deepa Thomas , UT Austin /// \author Antonio Palasciano , Università degli Studi di Bari & INFN, Sezione di Bari -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/V0.h" - -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsMcGen.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::hf_trkcandsel; @@ -41,6 +73,7 @@ using namespace o2::aod; using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_decay::hf_cand_beauty; /// Reconstruction of B± → D0bar(D0) π± → (K± π∓) π± struct HfCandidateCreatorBplus { @@ -60,7 +93,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"}; @@ -73,15 +106,11 @@ struct HfCandidateCreatorBplus { 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)"}; - HfHelper hfHelper; Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - int runNumber; + int runNumber{}; - double massPi{0.}; - double massD0{0.}; - double massBplus{0.}; double invMass2D0PiMin{0.}; double invMass2D0PiMax{0.}; double bz{0.}; @@ -98,23 +127,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 +199,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. @@ -205,11 +223,11 @@ struct HfCandidateCreatorBplus { if (!TESTBIT(candD0.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yD0(candD0)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yD0(candD0)) > yCandMax) { continue; } - hRapidityD0->Fill(hfHelper.yD0(candD0)); + hRapidityD0->Fill(HfHelper::yD0(candD0)); // track0 <-> pi, track1 <-> K auto prong0 = candD0.prong0_as(); @@ -251,13 +269,13 @@ struct HfCandidateCreatorBplus { df.getTrack(0).getPxPyPzGlo(pVec0); df.getTrack(1).getPxPyPzGlo(pVec1); // Get D0 momentum - std::array pVecD = RecoDecay::pVec(pVec0, pVec1); + std::array const pVecD = RecoDecay::pVec(pVec0, pVec1); // build a D0 neutral track auto trackD0 = o2::dataformats::V0(vertexD0, pVecD, df.calcPCACovMatrixFlat(), trackParCovProng0, trackParCovProng1); - int indexTrack0 = prong0.globalIndex(); - int indexTrack1 = prong1.globalIndex(); + int const indexTrack0 = prong0.globalIndex(); + int const indexTrack1 = prong1.globalIndex(); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); @@ -271,7 +289,7 @@ struct HfCandidateCreatorBplus { } // Select D0pi- and D0(bar)pi+ pairs only - if (!((candD0.isSelD0() >= selectionFlagD0 && trackPion.sign() < 0) || (candD0.isSelD0bar() >= selectionFlagD0bar && trackPion.sign() > 0))) { + if ((candD0.isSelD0() < selectionFlagD0 || trackPion.sign() >= 0) && (candD0.isSelD0bar() < selectionFlagD0bar || trackPion.sign() <= 0)) { // LOGF(debug, "D0: %d, D0bar%d, sign: %d", candD0.isSelD0(), candD0.isSelD0bar(), track.sign()); continue; } @@ -294,7 +312,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); @@ -318,8 +335,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(); @@ -336,7 +351,7 @@ struct HfCandidateCreatorBplus { auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); // 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; } @@ -354,11 +369,11 @@ struct HfCandidateCreatorBplus { 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 { @@ -376,15 +391,16 @@ struct HfCandidateCreatorBplusExpressions { int indexRec = -1, indexRecD0 = -1; int8_t signB = 0, signD0 = 0; - int8_t flag = 0; + int8_t flagChannelMain = 0; + int8_t flagChannelReso = 0; int8_t origin = 0; - int kD0pdg = Pdg::kD0; // Match reconstructed candidates. // Spawned table can be used directly for (const auto& candidate : candsBplus) { - flag = 0; + flagChannelMain = 0; + flagChannelReso = 0; origin = 0; auto candDaughterD0 = candidate.prong0(); auto arrayDaughtersD0 = std::array{candDaughterD0.prong0_as(), candDaughterD0.prong1_as()}; @@ -395,36 +411,12 @@ struct HfCandidateCreatorBplusExpressions { indexRecD0 = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersD0, -Pdg::kD0, std::array{+kKPlus, -kPiPlus}, true, &signD0, 1); if (indexRecD0 > -1 && indexRec > -1) { - flag = signB * (1 << hf_cand_bplus::DecayType::BplusToD0Pi); + flagChannelMain = signB * DecayChannelMain::BplusToD0Pi; } - rowMcMatchRec(flag, origin); + rowMcMatchRec(flagChannelMain, flagChannelReso, 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 69fb0c3f178..e73eaa4215a 100644 --- a/PWGHF/TableProducer/candidateCreatorBs.cxx +++ b/PWGHF/TableProducer/candidateCreatorBs.cxx @@ -15,22 +15,50 @@ /// /// \author Phil Stahlhut -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/V0.h" - -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::aod; @@ -38,10 +66,12 @@ using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::hf_trkcandsel; +using namespace o2::hf_decay::hf_cand_beauty; /// 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 +86,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 @@ -68,9 +98,8 @@ struct HfCandidateCreatorBs { o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter - HfHelper hfHelper; Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; int runNumber{0}; @@ -88,6 +117,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 +128,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; @@ -239,16 +268,16 @@ struct HfCandidateCreatorBs { df3.getTrack(2).getPxPyPzGlo(pVec2); // Ds∓ → K∓ K± π∓ - std::array pVecKK = RecoDecay::pVec(pVec0, pVec1); + std::array const pVecKK = RecoDecay::pVec(pVec0, pVec1); std::array pVecDs = RecoDecay::pVec(pVec0, pVec1, pVec2); auto trackParCovKK = o2::dataformats::V0(df3.getPCACandidatePos(), pVecKK, df3.calcPCACovMatrixFlat(), trackParCov0, trackParCov1); auto trackParCovDs = o2::dataformats::V0(df3.getPCACandidatePos(), pVecDs, df3.calcPCACovMatrixFlat(), trackParCovKK, trackParCov2); - int indexTrack0 = track0.globalIndex(); - int indexTrack1 = track1.globalIndex(); - int indexTrack2 = track2.globalIndex(); + int const indexTrack0 = track0.globalIndex(); + int const indexTrack1 = track1.globalIndex(); + int const indexTrack2 = track2.globalIndex(); auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); @@ -320,10 +349,8 @@ 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()); + hMassDsToKKPi->Fill(HfHelper::invMassDsToKKPi(candDs), candDs.pt()); hCovSVXX->Fill(covMatrixPCA[0]); hCovPVXX->Fill(covMatrixPV[0]); hMassBsToDsPi->Fill(massDsPi); @@ -340,14 +367,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,24 +384,23 @@ 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; - std::vector arrDaughDsIndex; - std::array arrPDGDaughDs; + int8_t flagChannelMain = 0; + int8_t flagChannelReso = 0; + std::vector arrDaughDsIndex{}; + std::array arrPDGDaughDs{}; std::array arrPDGResonantDsPhiPi = {Pdg::kPhi, kPiPlus}; // Ds± → Phi π± // Match reconstructed candidates. - // Spawned table can be used directly - for (const auto& candidate : *rowCandidateBs) { - flag = 0; + for (const auto& candidate : candsBs) { + flagChannelMain = 0; + flagChannelReso = 0; arrDaughDsIndex.clear(); auto candDs = candidate.prong0(); auto arrayDaughtersBs = std::array{candDs.prong0_as(), @@ -398,13 +424,13 @@ 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); + flagChannelMain = sign * DecayChannelMain::BsToDsPi; } } } } - if (!flag) { + if (flagChannelMain == 0) { // Checking B0(bar) → Ds± π∓ → (K- K+ π±) π∓ indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersBs, Pdg::kB0, std::array{-kKPlus, +kKPlus, +kPiPlus, -kPiPlus}, true, &sign, 3); if (indexRec > -1) { @@ -418,7 +444,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); + flagChannelMain = sign * DecayChannelMain::B0ToDsPi; } } } @@ -427,36 +453,35 @@ struct HfCandidateCreatorBsExpressions { // 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) { + if (flagChannelMain == 0) { auto particleProng0 = arrayDaughtersBs[0].mcParticle(); auto particleProng1 = arrayDaughtersBs[1].mcParticle(); auto particleProng2 = arrayDaughtersBs[2].mcParticle(); auto particleProng3 = arrayDaughtersBs[3].mcParticle(); // b-hadron hypothesis - std::array bHadronMotherHypos = {Pdg::kB0, Pdg::kBPlus, Pdg::kBS, Pdg::kLambdaB0}; + std::array const bHadronMotherHypos = {Pdg::kB0, Pdg::kBPlus, Pdg::kBS, Pdg::kLambdaB0}; for (const auto& bHadronMotherHypo : bHadronMotherHypos) { - int index0Mother = RecoDecay::getMother(mcParticles, particleProng0, bHadronMotherHypo, true); - int index1Mother = RecoDecay::getMother(mcParticles, particleProng1, bHadronMotherHypo, true); - int index2Mother = RecoDecay::getMother(mcParticles, particleProng2, bHadronMotherHypo, true); - int index3Mother = RecoDecay::getMother(mcParticles, particleProng3, bHadronMotherHypo, true); + int const index0Mother = RecoDecay::getMother(mcParticles, particleProng0, bHadronMotherHypo, true); + int const index1Mother = RecoDecay::getMother(mcParticles, particleProng1, bHadronMotherHypo, true); + int const index2Mother = RecoDecay::getMother(mcParticles, particleProng2, bHadronMotherHypo, true); + int const index3Mother = RecoDecay::getMother(mcParticles, 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); - break; - } + if (index0Mother > -1 && index0Mother == index1Mother && index1Mother == index2Mother && index2Mother == index3Mother) { + flagChannelMain = hf_cand_bs::DecayTypeMc::PartlyRecoDecay; // FIXME + break; } } } - rowMcMatchRec(flag); + rowMcMatchRec(flagChannelMain, flagChannelReso); } // rec // Match generated particles. for (const auto& particle : mcParticles) { - flag = 0; + flagChannelMain = 0; + flagChannelReso = 0; arrDaughDsIndex.clear(); // Checking Bs0(bar) → Ds∓ π± → (K- K+ π∓) π± @@ -471,13 +496,13 @@ 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); + flagChannelMain = sign * DecayChannelMain::BsToDsPi; } } } } - if (!flag) { + if (flagChannelMain == 0) { // Checking B0(bar) → Ds± π∓ → (K- K+ π±) π∓ if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kB0, std::array{+Pdg::kDS, -kPiPlus}, true)) { // Checking Ds± → K- K+ π± @@ -490,16 +515,16 @@ 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); + flagChannelMain = sign * DecayChannelMain::B0ToDsPi; } } } } } - rowMcMatchGen(flag); + rowMcMatchGen(flagChannelMain, flagChannelReso); } // gen - } // processMc + } // processMc PROCESS_SWITCH(HfCandidateCreatorBsExpressions, processMc, "Process MC", false); }; // struct diff --git a/PWGHF/TableProducer/candidateCreatorCascade.cxx b/PWGHF/TableProducer/candidateCreatorCascade.cxx index 3b1a5685ac8..aac477ff017 100644 --- a/PWGHF/TableProducer/candidateCreatorCascade.cxx +++ b/PWGHF/TableProducer/candidateCreatorCascade.cxx @@ -15,27 +15,54 @@ /// \author Chiara Zampolli, , CERN /// Paul Buehler, , Vienna -#include - -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#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 "Common/Core/trackUtilities.h" - #include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" #include "PWGHF/Utils/utilsEvSelHf.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; -using namespace o2::analysis; using namespace o2::hf_evsel; using namespace o2::hf_trkcandsel; using namespace o2::hf_centrality; @@ -67,7 +94,7 @@ struct HfCandidateCreatorCascade { HfEventSelection hfEvSel; // event selection and monitoring o2::vertexing::DCAFitterN<2> df; // 2-prong vertex fitter Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; int runNumber{0}; @@ -78,8 +105,11 @@ struct HfCandidateCreatorCascade { double mass2K0sP{0.}; double bz = 0.; + using V0full = soa::Join; + std::shared_ptr hCandidates; HistogramRegistry registry{"registry"}; + OutputObj zorroSummary{"zorroSummary"}; void init(InitContext const&) { @@ -110,7 +140,9 @@ struct HfCandidateCreatorCascade { 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}}}); hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); - hfEvSel.addHistograms(registry); // collision monitoring + + // init HF event selection helper + hfEvSel.init(registry, zorroSummary); massP = MassProton; massK0s = MassK0Short; @@ -136,22 +168,22 @@ struct HfCandidateCreatorCascade { setLabelHistoCands(hCandidates); } - template + template void runCreatorCascade(Coll const&, aod::HfCascades const& rowsTrackIndexCasc, aod::V0sLinked const&, - aod::V0Datas const&, - aod::V0fCDatas const&, + V0full const&, aod::TracksWCov 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 = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -165,26 +197,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(); @@ -198,37 +226,15 @@ struct HfCandidateCreatorCascade { dcaPosToPV = v0row.dcapostopv(); dcaNegToPV = v0row.dcanegtopv(); v0cosPA = v0row.v0cosPA(); - posTrackX = v0row.posX(); - negTrackX = v0row.negX(); - } else if (v0index.has_v0fCData()) { - // this V0 passes only V0-for-cascade selections, use that instead - auto v0row = v0index.v0fCData(); - 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(); - v0px = v0row.px(); - v0py = v0row.py(); - v0pz = v0row.pz(); - v0PosPx = v0row.pxpos(); - v0PosPy = v0row.pypos(); - v0PosPz = v0row.pzpos(); - v0NegPx = v0row.pxneg(); - v0NegPy = v0row.pyneg(); - v0NegPz = v0row.pzneg(); - dcaV0dau = v0row.dcaV0daughters(); - dcaPosToPV = v0row.dcapostopv(); - dcaNegToPV = v0row.dcanegtopv(); - v0cosPA = v0row.v0cosPA(); - posTrackX = v0row.posX(); - negTrackX = v0row.negX(); + + int const momIndSize = 6; + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < momIndSize; 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()); + LOGF(warning, "V0Data not there for V0 %d in HF cascade %d. Skipping candidate.", casc.v0Id(), casc.globalIndex()); continue; // this was inadequately linked, should not happen } @@ -243,24 +249,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() << ". DCAFitterN cannot work, skipping the candidate."; + LOG(debug) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; hCandidates->Fill(SVFitting::Fail); continue; } @@ -275,8 +281,8 @@ struct HfCandidateCreatorCascade { auto trackParVarBach = df.getTrack(1); // get track momenta - std::array pVecV0; - std::array pVecBach; + std::array pVecV0{}; + std::array pVecBach{}; trackParVarV0.getPxPyPzGlo(pVecV0); trackParVarBach.getPxPyPzGlo(pVecBach); @@ -307,8 +313,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, @@ -324,20 +329,17 @@ struct HfCandidateCreatorCascade { registry.fill(HIST("hMass2"), mass2K0sP); } } - - return; } /// @brief process function w/o centrality selections 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, aod::TracksWCov const& tracks, aod::BCsWithTimestamps const& bcs) { - runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Data, v0fCDatas, tracks, bcs); + runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Full, tracks, bcs); } PROCESS_SWITCH(HfCandidateCreatorCascade, processNoCent, " Run candidate creator w/o centrality selections", true); @@ -345,12 +347,11 @@ 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, aod::TracksWCov const& tracks, aod::BCsWithTimestamps const& bcs) { - runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Data, v0fCDatas, tracks, bcs); + runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Full, tracks, bcs); } PROCESS_SWITCH(HfCandidateCreatorCascade, processCentFT0C, " Run candidate creator w/ centrality selection on FT0C", false); @@ -358,12 +359,11 @@ 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, aod::TracksWCov const& tracks, aod::BCsWithTimestamps const& bcs) { - runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Data, v0fCDatas, tracks, bcs); + runCreatorCascade(collisions, rowsTrackIndexCasc, v0sLinked, v0Full, tracks, bcs); } PROCESS_SWITCH(HfCandidateCreatorCascade, processCentFT0M, " Run candidate creator w/ centrality selection on FT0M", false); @@ -381,10 +381,12 @@ struct HfCandidateCreatorCascade { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -398,10 +400,12 @@ struct HfCandidateCreatorCascade { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -415,10 +419,12 @@ struct HfCandidateCreatorCascade { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -431,21 +437,24 @@ 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; - HistogramRegistry registry{"registry"}; - - // Configuration - o2::framework::Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; - 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; - Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + + HistogramRegistry registry{"registry"}; // inspect for which zPvPosMax cut was set for reconstructed void init(InitContext& initContext) @@ -457,32 +466,29 @@ struct HfCandidateCreatorCascadeMc { const auto& workflows = initContext.services().get(); for (const DeviceSpec& device : workflows.devices) { - if (device.name.compare("hf-candidate-creator-cascade") == 0) { - hfEvSelMc.configureFromDevice(device); + if (device.name == "hf-candidate-creator-cascade") { + // init HF event selection helper + hfEvSelMc.init(device, registry); break; } } - hfEvSelMc.addHistograms(registry); // particles monitoring } - template + template void runCreatorCascMc(MyTracksWMc const& tracks, aod::McParticles const& mcParticles, CCs const& collInfos, - aod::McCollisions const& mcCollisions, + McCollisions const& mcCollisions, BCsInfo const&) { - int8_t sign = 0; - int8_t origin = 0; - int indexRec = -1; - std::vector arrDaughLcIndex; - std::array arrDaughLcPDG; - std::array arrDaughLcPDGRef = {+kProton, +kPiPlus, -kPiPlus}; - // 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(); @@ -509,14 +515,14 @@ struct HfCandidateCreatorCascadeMc { } } - RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, kK0Short, std::array{+kPiPlus, -kPiPlus}, false, &sign, 1); - if (sign != 0) { // we have already positively checked the K0s + int const 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, false, &idxBhadMothers); } @@ -534,18 +540,20 @@ struct HfCandidateCreatorCascadeMc { 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) { + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + 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) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (CentEstimator == CentralityEstimator::FT0M) { const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); - rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); - } else if constexpr (centEstimator == CentralityEstimator::None) { + 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); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); } - hfEvSelMc.fillHistograms(rejectionMask); + 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) { @@ -556,7 +564,11 @@ struct HfCandidateCreatorCascadeMc { // Match generated particles. for (const auto& particle : mcParticlesPerMcColl) { - origin = 0; + + int8_t sign = 0; + int8_t origin = 0; + int8_t flag = 0; + std::vector idxBhadMothers{}; // Reject particles from background events if (particle.fromBackgroundEvent() && rejectBackground) { @@ -564,35 +576,35 @@ struct HfCandidateCreatorCascadeMc { continue; } // checking if I have a Lc --> K0S + p - RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaCPlus, std::array{+kProton, +kK0Short}, false, &sign, 2); + 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); + RecoDecay::isMatchedMCGen(mcParticles, particle, -Pdg::kLambdaCPlus, std::array{-kProton, +kK0Short}, false, &sign, 2); sign = -sign; } 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(); + // we check the K0S + for (const auto& daughterK0 : particle.template daughters_as()) { + if (std::abs(daughterK0.pdgCode()) != kK0) { + continue; } - 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"; + 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 (sign != 0) { + if (flag != 0) { origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); } if (origin == RecoDecay::OriginType::NonPrompt) { - rowMcMatchGen(sign, origin, idxBhadMothers[0]); + rowMcMatchGen(flag, origin, idxBhadMothers[0]); } else { - rowMcMatchGen(sign, origin, -1); + rowMcMatchGen(flag, origin, -1); } } } @@ -602,9 +614,9 @@ struct HfCandidateCreatorCascadeMc { aod::McParticles const& mcParticles, McCollisionsNoCents const& collInfos, aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + BCsInfo const& bcsInfo) { - runCreatorCascMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreatorCascMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreatorCascadeMc, processMc, "Process MC - no centrality", false); @@ -612,19 +624,19 @@ struct HfCandidateCreatorCascadeMc { aod::McParticles const& mcParticles, McCollisionsFT0Cs const& collInfos, aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + BCsInfo const& bcsInfo) { - runCreatorCascMc(tracks, mcParticles, collInfos, mcCollisions, 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, - aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + McCollisionsCentFT0Ms const& mcCollisions, + BCsInfo const& bcsInfo) { - runCreatorCascMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreatorCascMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreatorCascadeMc, processMcCentFT0M, "Process MC - FT0m centrality", false); }; diff --git a/PWGHF/TableProducer/candidateCreatorDstar.cxx b/PWGHF/TableProducer/candidateCreatorDstar.cxx index c343d8ce526..67883d32b2e 100644 --- a/PWGHF/TableProducer/candidateCreatorDstar.cxx +++ b/PWGHF/TableProducer/candidateCreatorDstar.cxx @@ -16,23 +16,53 @@ /// \author Deependra Sharma , IITB /// \author Fabrizio Grosa , CERN -// ROOT -#include -// O2 -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#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/Core/DecayChannels.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsPid.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::hf_evsel; @@ -40,6 +70,7 @@ using namespace o2::hf_trkcandsel; using namespace o2::hf_centrality; using namespace o2::constants::physics; using namespace o2::framework; +using namespace o2::aod::pid_tpc_tof_utils; namespace o2::aod { @@ -50,6 +81,12 @@ using HfDstarsWithPvRefitInfo = soa::Join; struct HfCandidateCreatorDstar { Produces rowCandD0Base; Produces rowCandDstarBase; + Produces rowProng0PidPi; + Produces rowProng0PidKa; + Produces rowProng1PidPi; + Produces rowProng1PidKa; + Produces rowProngSoftPiPidPi; + Produces rowProngSoftPiPidKa; Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; @@ -74,10 +111,12 @@ struct HfCandidateCreatorDstar { o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // D0-prong vertex fitter o2::vertexing::DCAFitterN<2> df; - int runNumber; - double bz; + int runNumber{}; + double bz{}; static constexpr float CmToMicrometers = 10000.; // from cm to µm - double massPi, massK, massD0; + double massPi{}, massK{}, massD0{}; + + using TracksWCovExtraPidPiKa = soa::Join; AxisSpec ptAxis = {100, 0., 2.0, "#it{p}_{T} (GeV/#it{c}"}; AxisSpec dcaAxis = {200, -500., 500., "#it{d}_{xy,z} (#mum)"}; @@ -104,6 +143,7 @@ struct HfCandidateCreatorDstar { {"QA/hPtD0Prong1", "D^{0} candidates' prong1", {HistType::kTH1F, {ptAxis}}}, {"QA/hPtD0", "D^{0} candidates", {HistType::kTH1F, {ptAxis}}}, {"QA/hPtDstar", "D* candidates", {HistType::kTH1F, {ptAxis}}}}}; + OutputObj zorroSummary{"zorroSummary"}; /// @brief This function initializes the ccdb setting, vertex fitter and runs function MatLayerCylSet::rectifyPtrFromFile(..args..) void init(InitContext const&) @@ -133,7 +173,9 @@ struct HfCandidateCreatorDstar { } hCandidates = registry.add("hCandidates", "candidates counter", {HistType::kTH1D, {axisCands}}); - hfEvSel.addHistograms(registry); // collision monitoring + + // init HF event selection helper + hfEvSel.init(registry, zorroSummary); // LOG(info) << "Init Function Invoked"; massPi = MassPiPlus; @@ -167,11 +209,11 @@ 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&, + TracksWCovExtraPidPiKa const&, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { // LOG(info) << "runCreatorDstar function called"; @@ -182,16 +224,16 @@ struct HfCandidateCreatorDstar { /// reject candidates in collisions not satisfying the event selections auto collision = rowTrackIndexDstar.template collision_as(); float centrality{-1.f}; - const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; } - auto trackPi = rowTrackIndexDstar.template prong0_as(); + auto trackPi = rowTrackIndexDstar.template prong0_as(); auto prongD0 = rowTrackIndexDstar.template prongD0_as(); - auto trackD0Prong0 = prongD0.template prong0_as(); - auto trackD0Prong1 = prongD0.template prong1_as(); + auto trackD0Prong0 = prongD0.template prong0_as(); + auto trackD0Prong1 = prongD0.template prong1_as(); // Extracts primary vertex position and covariance matrix from a collision auto primaryVertex = getPrimaryVertex(collision); @@ -212,7 +254,7 @@ struct HfCandidateCreatorDstar { 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()); + auto* 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()); } @@ -250,13 +292,13 @@ struct HfCandidateCreatorDstar { auto trackD0ProngParVar0 = df.getTrack(0); auto trackD0ProngParVar1 = df.getTrack(1); - std::array pVecD0Prong0; - std::array pVecD0Prong1; + std::array pVecD0Prong0{}; + std::array pVecD0Prong1{}; trackD0ProngParVar0.getPxPyPzGlo(pVecD0Prong0); trackD0ProngParVar1.getPxPyPzGlo(pVecD0Prong1); // This modifies track momenta! - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { /// use PV refit /// Using it in the *HfCand3ProngBase/HfCand2ProngBase* all dynamic columns shall take it into account // coordinates @@ -309,9 +351,9 @@ struct HfCandidateCreatorDstar { auto ptD0 = RecoDecay::pt(pVecD0); // Soft pi momentum vector and sign - std::array pVecSoftPi; + std::array pVecSoftPi{}; trackPiParVar.getPxPyPzGlo(pVecSoftPi); - int8_t signSoftPi = static_cast(trackPi.sign()); + auto signSoftPi = static_cast(trackPi.sign()); // D* pt magnitude auto ptDstar = RecoDecay::pt(pVecD0, pVecSoftPi); @@ -341,6 +383,14 @@ struct HfCandidateCreatorDstar { std::sqrt(impactParameter0.getSigmaZ2()), std::sqrt(impactParameter1.getSigmaZ2()), prongD0.prong0Id(), prongD0.prong1Id(), prongD0.hfflag()); + // fill candidate D0 prong PID rows + fillProngPid(trackD0Prong0, rowProng0PidPi); + fillProngPid(trackD0Prong0, rowProng0PidKa); + fillProngPid(trackD0Prong1, rowProng1PidPi); + fillProngPid(trackD0Prong1, rowProng1PidKa); + // fill soft-pion PID rows + fillProngPid(trackPi, rowProngSoftPiPidPi); + fillProngPid(trackPi, rowProngSoftPiPidKa); if (fillHistograms) { registry.fill(HIST("QA/hPtD0"), ptD0); @@ -363,7 +413,7 @@ struct HfCandidateCreatorDstar { void processPvRefit(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstarsWithPvRefitInfo const& rowsTrackIndexDstar, - aod::TracksWCov const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreatorDstar(collisions, rowsTrackIndexDstar, rowsTrackIndexD0, tracks, bcWithTimeStamps); @@ -374,7 +424,7 @@ struct HfCandidateCreatorDstar { void processNoPvRefit(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstars const& rowsTrackIndexDstar, - aod::TracksWCov const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreatorDstar(collisions, rowsTrackIndexDstar, rowsTrackIndexD0, tracks, bcWithTimeStamps); @@ -391,7 +441,7 @@ struct HfCandidateCreatorDstar { void processPvRefitCentFT0C(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstarsWithPvRefitInfo const& rowsTrackIndexDstar, - aod::TracksWCov const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreatorDstar(collisions, rowsTrackIndexDstar, rowsTrackIndexD0, tracks, bcWithTimeStamps); @@ -402,7 +452,7 @@ struct HfCandidateCreatorDstar { void processNoPvRefitCentFT0C(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstars const& rowsTrackIndexDstar, - aod::TracksWCov const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreatorDstar(collisions, rowsTrackIndexDstar, rowsTrackIndexD0, tracks, bcWithTimeStamps); @@ -419,7 +469,7 @@ struct HfCandidateCreatorDstar { void processPvRefitCentFT0M(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstarsWithPvRefitInfo const& rowsTrackIndexDstar, - aod::TracksWCov const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreatorDstar(collisions, rowsTrackIndexDstar, rowsTrackIndexD0, tracks, bcWithTimeStamps); @@ -430,7 +480,7 @@ struct HfCandidateCreatorDstar { void processNoPvRefitCentFT0M(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstars const& rowsTrackIndexDstar, - aod::TracksWCov const& tracks, + TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreatorDstar(collisions, rowsTrackIndexDstar, rowsTrackIndexD0, tracks, bcWithTimeStamps); @@ -451,10 +501,12 @@ struct HfCandidateCreatorDstar { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -468,10 +520,12 @@ struct HfCandidateCreatorDstar { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -485,10 +539,12 @@ struct HfCandidateCreatorDstar { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -497,26 +553,27 @@ struct HfCandidateCreatorDstar { struct HfCandidateCreatorDstarExpressions { Spawns rowsCandidateD0; - Produces rowsMcMatchRecD0; - Produces rowsMcMatchGenD0; - Spawns rowsCandidateDstar; Produces rowsMcMatchRecDstar; Produces rowsMcMatchGenDstar; // Configuration - o2::framework::Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + 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; - Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring - using BCsInfo = soa::Join; HistogramRegistry registry{"registry"}; // inspect for which zPvPosMax cut was set for reconstructed @@ -529,20 +586,20 @@ struct HfCandidateCreatorDstarExpressions { const auto& workflows = initContext.services().get(); for (const DeviceSpec& device : workflows.devices) { - if (device.name.compare("hf-candidate-creator-dstar") == 0) { - hfEvSelMc.configureFromDevice(device); + if (device.name == "hf-candidate-creator-dstar") { + // init HF event selection helper + hfEvSelMc.init(device, registry); break; } } - hfEvSelMc.addHistograms(registry); // particles monitoring } /// Perform MC Matching. - template + template void runCreatorDstarMc(aod::TracksWMc const& tracks, aod::McParticles const& mcParticles, CCs const& collInfos, - aod::McCollisions const& mcCollisions, + McCollisions const& mcCollisions, BCsInfo const&) { rowsCandidateD0->bindExternalIndices(&tracks); @@ -551,14 +608,15 @@ 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(); @@ -581,21 +639,90 @@ struct HfCandidateCreatorDstarExpressions { } } if (fromBkg) { - rowsMcMatchRecDstar(flagDstar, originDstar, -1.f, 0); + rowsMcMatchRecDstar(flagDstar, flagD0, originDstar, -1.f, 0, 0, 0); continue; } } - // 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 (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)); + flagDstar = signDstar * hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi; } if (indexRecD0 > -1) { - flagD0 = signD0 * (BIT(aod::hf_cand_dstar::DecayType::D0ToPiK)); + flagD0 = signD0 * hf_decay::hf_cand_2prong::DecayChannelMain::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 * hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPiPi0; + } + } else { + if (RecoDecay::isMatchedMCGen(mcParticles, motherParticleDstar, -Pdg::kDStar, std::array{-kPiPlus, -kPiPlus, +kKPlus, +kPi0}, false, &signDstar, 2)) { + flagDstar = signDstar * hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPiPi0; + } + } + } + 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 * hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiKPi0; + } + } else { + if (RecoDecay::isMatchedMCGen(mcParticles, motherParticleD0, -Pdg::kD0, std::array{-kPiPlus, +kKPlus, +kPi0}, false, &signD0)) { + flagD0 = signD0 * hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiKPi0; + } + } + } } // check wether the particle is non-promt (from a B0 hadron) @@ -603,17 +730,12 @@ struct HfCandidateCreatorDstarExpressions { auto particleDstar = mcParticles.iteratorAt(indexRecDstar); 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, originDstar, bHadMother.pt(), bHadMother.pdgCode()); + rowsMcMatchRecDstar(flagDstar, flagD0, originDstar, bHadMother.pt(), bHadMother.pdgCode(), nKinkedTracksDstar, nInteractionsWithMaterialDstar); } else { - rowsMcMatchRecDstar(flagDstar, originDstar, -1.f, 0); + rowsMcMatchRecDstar(flagDstar, flagD0, originDstar, -1.f, 0, nKinkedTracksDstar, nInteractionsWithMaterialDstar); } - rowsMcMatchRecD0(flagD0, originD0, -1.f, 0); } for (const auto& mcCollision : mcCollisions) { @@ -621,23 +743,24 @@ struct HfCandidateCreatorDstarExpressions { 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) { + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + 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) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (CentEstimator == CentralityEstimator::FT0M) { const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); - rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); - } else if constexpr (centEstimator == CentralityEstimator::None) { + 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); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); } - hfEvSelMc.fillHistograms(rejectionMask); + 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, -1); - rowsMcMatchGenD0(0, 0, -1); + rowsMcMatchGenDstar(0, 0, 0, -1); } continue; } @@ -647,38 +770,47 @@ struct HfCandidateCreatorDstarExpressions { flagDstar = 0; flagD0 = 0; originDstar = 0; - originD0 = 0; std::vector idxBhadMothers{}; // Reject particles from background events if (particle.fromBackgroundEvent() && rejectBackground) { - rowsMcMatchGenDstar(flagDstar, originDstar, -1); - rowsMcMatchGenD0(flagD0, originD0, -1); + rowsMcMatchGenDstar(flagDstar, flagD0, originDstar, -1); continue; } // 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)); - } + std::vector listIndexDaughters{}; + bool const isDstarToDzeroPi = RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDStar, std::array{+Pdg::kD0, +kPiPlus}, true, &signDstar, 1, &listIndexDaughters); + // 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)); + 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 * hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi; + flagD0 = signD0 * hf_decay::hf_cand_2prong::DecayChannelMain::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 * hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPiPi0; + flagD0 = signD0 * hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiKPi0; + } } - // check wether the particle is non-promt (from a B0 hadron) + // check wether the particle is non-prompt (from a B0 hadron) if (flagDstar != 0) { originDstar = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); } - if (flagD0 != 0) { - originD0 = RecoDecay::getCharmHadronOrigin(mcParticles, particle); - } if (originDstar == RecoDecay::OriginType::NonPrompt) { - rowsMcMatchGenDstar(flagDstar, originDstar, idxBhadMothers[0]); + rowsMcMatchGenDstar(flagDstar, flagD0, originDstar, idxBhadMothers[0]); } else { - rowsMcMatchGenDstar(flagDstar, originDstar, -1); + rowsMcMatchGenDstar(flagDstar, flagD0, originDstar, -1); } - rowsMcMatchGenD0(flagD0, originD0, -1.); } } } @@ -687,9 +819,9 @@ struct HfCandidateCreatorDstarExpressions { aod::McParticles const& mcParticles, McCollisionsNoCents const& collInfos, aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + BCsInfo const& bcsInfo) { - runCreatorDstarMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreatorDstarMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreatorDstarExpressions, processMc, "Process MC - no centrality", false); @@ -697,19 +829,19 @@ struct HfCandidateCreatorDstarExpressions { aod::McParticles const& mcParticles, McCollisionsFT0Cs const& collInfos, aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + BCsInfo const& bcsInfo) { - runCreatorDstarMc(tracks, mcParticles, collInfos, mcCollisions, 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, - aod::McCollisions const& mcCollisions, - BCsInfo const& BCsInfo) + McCollisionsCentFT0Ms const& mcCollisions, + BCsInfo const& bcsInfo) { - runCreatorDstarMc(tracks, mcParticles, collInfos, mcCollisions, BCsInfo); + runCreatorDstarMc(tracks, mcParticles, collInfos, mcCollisions, bcsInfo); } PROCESS_SWITCH(HfCandidateCreatorDstarExpressions, processMcCentFT0M, "Process MC - FT0m centrality", false); }; diff --git a/PWGHF/TableProducer/candidateCreatorLb.cxx b/PWGHF/TableProducer/candidateCreatorLb.cxx index a47c0bde898..3cc9716241e 100644 --- a/PWGHF/TableProducer/candidateCreatorLb.cxx +++ b/PWGHF/TableProducer/candidateCreatorLb.cxx @@ -15,20 +15,41 @@ /// /// \author Panos Christakoglou , Nikhef -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/V0.h" - -#include "Common/Core/trackUtilities.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsTrkCandHf.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::aod; @@ -36,11 +57,12 @@ using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::hf_trkcandsel; +using namespace o2::hf_decay::hf_cand_beauty; /// Reconstruction of Λb candidates struct HfCandidateCreatorLb { Produces rowCandidateBase; - + Produces rowCandidateProngs; // vertexing Configurable bz{"bz", 20., "magnetic field"}; Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -57,7 +79,6 @@ struct HfCandidateCreatorLb { o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter (to rebuild Lc vertex) - HfHelper hfHelper; double massPi{0.}; double massLc{0.}; @@ -65,6 +86,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.)}; @@ -73,9 +97,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; @@ -114,14 +135,14 @@ struct HfCandidateCreatorLb { { // loop over Lc candidates for (const auto& lcCand : lcCands) { - if (!(lcCand.hfflag() & 1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi)) { + if ((lcCand.hfflag() & 1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi) == 0) { continue; } if (lcCand.isSelLcToPKPi() >= selectionFlagLc) { - hMassLcToPKPi->Fill(hfHelper.invMassLcToPKPi(lcCand), lcCand.pt()); + hMassLcToPKPi->Fill(HfHelper::invMassLcToPKPi(lcCand), lcCand.pt()); } if (lcCand.isSelLcToPiKP() >= selectionFlagLc) { - hMassLcToPKPi->Fill(hfHelper.invMassLcToPiKP(lcCand), lcCand.pt()); + hMassLcToPKPi->Fill(HfHelper::invMassLcToPiKP(lcCand), lcCand.pt()); } hPtLc->Fill(lcCand.pt()); hCPALc->Fill(lcCand.cpa()); @@ -152,14 +173,14 @@ struct HfCandidateCreatorLb { trackParVar1.propagateTo(secondaryVertex[0], bz); trackParVar2.propagateTo(secondaryVertex[0], bz); - std::array pvecpK = RecoDecay::pVec(track0.pVector(), track1.pVector()); + std::array const pvecpK = RecoDecay::pVec(track0.pVector(), track1.pVector()); std::array pvecLc = RecoDecay::pVec(pvecpK, track2.pVector()); auto trackpK = o2::dataformats::V0(df3.getPCACandidatePos(), pvecpK, df3.calcPCACovMatrixFlat(), trackParVar0, trackParVar1); auto trackLc = o2::dataformats::V0(df3.getPCACandidatePos(), pvecLc, df3.calcPCACovMatrixFlat(), trackpK, trackParVar2); - int index0Lc = track0.globalIndex(); - int index1Lc = track1.globalIndex(); - int index2Lc = track2.globalIndex(); + int const index0Lc = track0.globalIndex(); + int const index1Lc = track1.globalIndex(); + int const index2Lc = track2.globalIndex(); // int charge = track0.sign() + track1.sign() + track2.sign(); for (const auto& trackPion : tracks) { @@ -173,7 +194,7 @@ struct HfCandidateCreatorLb { continue; } hPtPion->Fill(trackPion.pt()); - std::array pvecPion; + std::array pvecPion{}; auto trackParVarPi = getTrackParCov(trackPion); // reconstruct the 3-prong Lc vertex @@ -214,8 +235,6 @@ struct HfCandidateCreatorLb { 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 = 1 << hf_cand_lb::DecayType::LbToLcPi; - // fill the candidate table for the Lb here: rowCandidateBase(collision.globalIndex(), collision.posX(), collision.posY(), collision.posZ(), @@ -225,13 +244,11 @@ struct HfCandidateCreatorLb { pvecLc[0], pvecLc[1], pvecLc[2], pvecPion[0], pvecPion[1], pvecPion[2], impactParameter0.getY(), impactParameter1.getY(), - std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), - lcCand.globalIndex(), trackPion.globalIndex(), - hfFlag); - + std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2())); + rowCandidateProngs(lcCand.globalIndex(), trackPion.globalIndex()); // calculate invariant mass auto arrayMomenta = std::array{pvecLc, pvecPion}; - massLcPi = RecoDecay::m(std::move(arrayMomenta), std::array{massLc, massPi}); + massLcPi = RecoDecay::m(arrayMomenta, std::array{massLc, massPi}); if (lcCand.isSelLcToPKPi() > 0) { hMassLbToLcPi->Fill(massLcPi); } @@ -239,38 +256,37 @@ 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; - - void init(InitContext const&) {} - Produces rowMcMatchRec; Produces rowMcMatchGen; + void init(InitContext const&) {} + /// @brief dummy process function, to be run on data void process(aod::Tracks const&) {} - void processMc(aod::HfCand3Prong const& lcCandidates, - aod::TracksWMc const& tracks, - aod::McParticles const& mcParticles) + void processMc(aod::HfCand3Prong const&, + aod::TracksWMc const&, + aod::McParticles const& mcParticles, + aod::HfCandLbProngs const& candsLb) { int indexRec = -1; int8_t sign = 0; - int8_t flag = 0; + int8_t flagChannelMain = 0; + int8_t flagChannelReso = 0; int8_t origin = 0; int8_t debug = 0; - rowCandidateLb->bindExternalIndices(&tracks); - rowCandidateLb->bindExternalIndices(&lcCandidates); - // Match reconstructed candidates. - for (const auto& candidate : *rowCandidateLb) { - flag = 0; + for (const auto& candidate : candsLb) { + flagChannelMain = 0; + flagChannelReso = 0; origin = 0; debug = 0; auto lcCand = candidate.prong0(); @@ -287,28 +303,29 @@ struct HfCandidateCreatorLbExpressions { // Λb → Λc+ π- indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersLc, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 1); if (indexRec > -1) { - flag = 1 << hf_cand_lb::DecayType::LbToLcPi; + flagChannelMain = sign * DecayChannelMain::LbToLcPi; } else { debug = 1; LOGF(info, "WARNING: Λb in decays in the expected final state but the condition on the intermediate state is not fulfilled"); } } - rowMcMatchRec(flag, origin, debug); + rowMcMatchRec(flagChannelMain, flagChannelReso, origin, debug); } // Match generated particles. for (const auto& particle : mcParticles) { - flag = 0; + flagChannelMain = 0; + flagChannelReso = 0; origin = 0; // Λ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)) { - flag = sign * (1 << hf_cand_lb::DecayType::LbToLcPi); + auto candLcMc = mcParticles.rawIteratorAt(particle.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(mcParticles, candLcMc, static_cast(Pdg::kLambdaCPlus), std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign)) { + flagChannelMain = sign * DecayChannelMain::LbToLcPi; } } - rowMcMatchGen(flag, origin); + rowMcMatchGen(flagChannelMain, flagChannelReso, origin); } } PROCESS_SWITCH(HfCandidateCreatorLbExpressions, processMc, "Process MC", false); diff --git a/PWGHF/TableProducer/candidateCreatorMcGen.cxx b/PWGHF/TableProducer/candidateCreatorMcGen.cxx new file mode 100644 index 00000000000..1c923a5b6e3 --- /dev/null +++ b/PWGHF/TableProducer/candidateCreatorMcGen.cxx @@ -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 candidateCreatorMcGen.cxx +/// \brief McGen only selection of heavy-flavour particles +/// +/// \author Nima Zardoshti, nima.zardoshti@cern.ch, CERN + +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsMcGen.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::constants::physics; + +/// 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 matchCorrelatedBackground{"matchCorrelatedBackground", false, "Match correlated background candidates"}; + Configurable> pdgMothersCorrelBkg{"pdgMothersCorrelBkg", {Pdg::kDPlus, Pdg::kDS, Pdg::kDStar, Pdg::kLambdaCPlus, Pdg::kXiCPlus}, "PDG codes of the mother particles of correlated background 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, matchCorrelatedBackground); + } + if (fill3Prong) { + hf_mc_gen::fillMcMatchGen3Prong(mcParticles, mcParticlesPerMcColl, rowMcMatchGen3Prong, rejectBackground3Prong, matchCorrelatedBackground ? pdgMothersCorrelBkg : std::vector{}); + } + } + 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 509b74d1daa..9423e15931a 100644 --- a/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx +++ b/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx @@ -15,26 +15,54 @@ /// /// \author Mattia Faggin , University and INFN PADOVA -#include "CCDB/BasicCCDBManager.h" // for dca recalculation -#include "CommonConstants/PhysicsConstants.h" -#include "DataFormatsParameters/GRPMagField.h" // for dca recalculation -#include "DataFormatsParameters/GRPObject.h" // for dca recalculation -#include "DetectorsBase/GeometryManager.h" // for dca recalculation -#include "DetectorsBase/Propagator.h" // for dca recalculation -#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" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/Core/TrackSelectionDefaults.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsBfieldCCDB.h" // for dca recalculation +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" + +#include // for dca recalculation +#include +#include +#include // for dca recalculation +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -51,7 +79,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"}; @@ -69,15 +97,14 @@ struct HfCandidateCreatorSigmac0plusplus { 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)"}; - HfHelper hfHelper; /// Cut selection object for soft π-,+ TrackSelection softPiCuts; // Needed for dcaXY, dcaZ recalculation of soft pions reassigned to a new collision Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - int runNumber; + int runNumber{}; using CandidatesLc = soa::Filtered>; @@ -106,7 +133,7 @@ struct HfCandidateCreatorSigmac0plusplus { /// process function switches std::array arrProcess = {doprocessDataTrackToCollAssoc, doprocessDataNoTrackToCollAssoc}; - int processes = std::accumulate(arrProcess.begin(), arrProcess.end(), 0); + int const processes = std::accumulate(arrProcess.begin(), arrProcess.end(), 0); if (processes != 1) { LOG(fatal) << "Check the enabled process functions. doprocessDataTrackToCollAssoc=" << doprocessDataTrackToCollAssoc << ", doprocessDataNoTrackToCollAssoc=" << doprocessDataNoTrackToCollAssoc; } @@ -138,7 +165,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)); } @@ -146,8 +174,8 @@ struct HfCandidateCreatorSigmac0plusplus { LOG(info) << "### ITS hitmap for soft pion"; LOG(info) << " >>> setSoftPiItsHitMap.size(): " << setSoftPiItsHitMap.size(); LOG(info) << " >>> Custom ITS hitmap dfchecked: "; - for (std::set::iterator it = setSoftPiItsHitMap.begin(); it != setSoftPiItsHitMap.end(); it++) { - LOG(info) << " Layer " << static_cast(*it) << " "; + for (const auto it : setSoftPiItsHitMap) { + LOG(info) << " Layer " << static_cast(it) << " "; } LOG(info) << "############"; softPiCuts.SetRequireITSRefit(); @@ -165,7 +193,7 @@ struct HfCandidateCreatorSigmac0plusplus { /// @param candidates are 3-prong candidates satisfying the analysis selections for Λc+ → pK-π+ (and charge conj.) /// @param tracks are the tracks (with dcaXY, dcaZ information) → soft-pion candidate tracks template - void makeSoftPiLcPair(TRK const& trackSoftPi, CAND const& candidatesThisColl, aod::TracksWDcaExtra const&) + void makeSoftPiLcPair(const std::array softPiDca, TRK const& trackSoftPi, CAND const& candidatesThisColl, aod::TracksWDcaExtra const&) { /// loop over Λc+ → pK-π+ (and charge conj.) candidates @@ -174,12 +202,12 @@ 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 /// if not selected, skip it and go to the next one - if (yCandLcMax >= 0. && std::abs(hfHelper.yLc(candLc)) > yCandLcMax) { + if (yCandLcMax >= 0. && std::abs(HfHelper::yLc(candLc)) > yCandLcMax) { continue; } @@ -196,10 +224,10 @@ struct HfCandidateCreatorSigmac0plusplus { mPiKPCandLcMax = cutsMassLcMax->get(pTBin, "max piKp mass Lc"); } - if (candLc.isSelLcToPKPi() >= 1 && std::abs(hfHelper.invMassLcToPKPi(candLc) - MassLambdaCPlus) <= mPKPiCandLcMax) { + if (candLc.isSelLcToPKPi() >= 1 && std::abs(HfHelper::invMassLcToPKPi(candLc) - MassLambdaCPlus) <= mPKPiCandLcMax) { statusSpreadMinvPKPiFromPDG = 1; } - if (candLc.isSelLcToPiKP() >= 1 && std::abs(hfHelper.invMassLcToPiKP(candLc) - MassLambdaCPlus) <= mPiKPCandLcMax) { + if (candLc.isSelLcToPiKP() >= 1 && std::abs(HfHelper::invMassLcToPiKP(candLc) - MassLambdaCPlus) <= mPiKPCandLcMax) { statusSpreadMinvPiKPFromPDG = 1; } if (statusSpreadMinvPKPiFromPDG == 0 && statusSpreadMinvPiKPFromPDG == 0) { @@ -230,7 +258,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; } @@ -246,16 +274,17 @@ struct HfCandidateCreatorSigmac0plusplus { candLc.hfflag(), /* Σc0,++ specific columns */ chargeSigmac, - statusSpreadMinvPKPiFromPDG, statusSpreadMinvPiKPFromPDG); + statusSpreadMinvPKPiFromPDG, statusSpreadMinvPiKPFromPDG, + softPiDca[0], softPiDca[1]); } /// 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 /// @param trackSoftPi is the track (with dcaXY, dcaZ information)of a candidate soft-pion in the collision /// @param tracks are the tracks (with dcaXY, dcaZ information) → soft-pion candidate tracks /// @param candidates are 3-prong candidates satisfying the analysis selections for Λc+ → pK-π+ (and charge conj.) - template + template void createSigmaC(aod::Collisions::iterator const& collision, TRK const& trackSoftPi, aod::TracksWDcaExtra const& tracks, @@ -271,46 +300,48 @@ struct HfCandidateCreatorSigmac0plusplus { if (!softPiCuts.IsSelected(trackSoftPi)) { return; } - if constexpr (withTimeAssoc) { + std::array softPiDca = {-999.f, -999.f}; + if constexpr (WithTimeAssoc) { /// dcaXY, dcaZ selections /// To be done separately from the others, because for reassigned tracks the dca must be recalculated /// TODO: to be properly adapted in case of PV refit usage if (trackSoftPi.collisionId() == thisCollId) { /// this is a track originally assigned to the current collision /// therefore, the dcaXY, dcaZ are those already calculated in the track-propagation workflow - if (std::abs(trackSoftPi.dcaXY()) > softPiDcaXYMax || std::abs(trackSoftPi.dcaZ()) > softPiDcaZMax) { - return; - } + softPiDca[0] = trackSoftPi.dcaXY(); + softPiDca[1] = trackSoftPi.dcaZ(); } else { /// this is a reassigned track /// therefore we need to calculate the dcaXY, dcaZ with respect to this new primary vertex auto bc = collision.bc_as(); initCCDB(bc, runNumber, ccdb, isRun2Ccdb ? ccdbPathGrp : ccdbPathGrpMag, lut, isRun2Ccdb); auto trackParSoftPi = getTrackPar(trackSoftPi); - o2::gpu::gpustd::array dcaInfo{-999., -999.}; + std::array dcaInfo{-999., -999.}; o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParSoftPi, 2.f, noMatCorr, &dcaInfo); - if (std::abs(dcaInfo[0]) > softPiDcaXYMax || std::abs(dcaInfo[1]) > softPiDcaZMax) { - return; - } + softPiDca[0] = dcaInfo[0]; + softPiDca[1] = dcaInfo[1]; } } else { /// this is a track originally assigned to the current collision /// therefore, the dcaXY, dcaZ are those already calculated in the track-propagation workflow /// No need to consider the time-reassociated tracks, since withTimeAssoc == false here - if (std::abs(trackSoftPi.dcaXY()) > softPiDcaXYMax || std::abs(trackSoftPi.dcaZ()) > softPiDcaZMax) { - return; - } + softPiDca[0] = trackSoftPi.dcaXY(); + softPiDca[1] = trackSoftPi.dcaZ(); + } + if (std::abs(softPiDca[0]) > softPiDcaXYMax || std::abs(softPiDca[1]) > softPiDcaZMax) { + /// soft-pion dca too large, reject the candidate + return; } histos.fill(HIST("hCounter"), 3); /// loop over Λc+ → pK-π+ (and charge conj.) candidates - if constexpr (withTimeAssoc) { + if constexpr (WithTimeAssoc) { /// need to group candidates manually auto candidatesThisColl = candidates.sliceBy(hf3ProngPerCollision, thisCollId); - makeSoftPiLcPair(trackSoftPi, candidatesThisColl, tracks); + makeSoftPiLcPair(softPiDca, trackSoftPi, candidatesThisColl, tracks); } else { /// tracks and candidates already grouped by collision at the level of process function - makeSoftPiLcPair(trackSoftPi, candidates, tracks); + makeSoftPiLcPair(softPiDca, trackSoftPi, candidates, tracks); } } /// end createSigmaC @@ -383,28 +414,53 @@ 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 McParticlesLcGenMatch = soa::Join; // including response of particle matching to MC from candidate-creator-3-prong + using McCollisionsNoCents = soa::Join; - float zPvPosMax{1000.f}; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + HistogramRegistry registry{"registry"}; /// @brief init function void init(InitContext& initContext) { const auto& workflows = initContext.services().get(); for (const DeviceSpec& device : workflows.devices) { - if (device.name.compare("hf-candidate-creator-3prong") == 0) { // here we assume that the hf-candidate-creator-3prong is in the workflow - for (const auto& option : device.options) { - if (option.name.compare("hfEvSel.zPvPosMax") == 0) { - zPvPosMax = option.defaultValue.get(); - break; - } - } + // here we assume that the hf-candidate-creator-3prong is in the workflow + // configure the ev. sel from that workflow + if (device.name == "hf-candidate-creator-3prong") { + // init HF event selection helper + hfEvSelMc.init(device, registry); break; } } } + // @brief function to check whether a matched Sigmac is particle or antiparticle + // @tparam particle the MC particle under study, matched with some Sigmac + // @param pdgSigmac the pdgcode to look for (either of Sigmac(2455), or of Sigmac(2520)) + template + int8_t isParticleAntiparticle(PART const& particle, int pdgSigmac) + { + + int pdgCode = particle.pdgCode(); + if (pdgCode == pdgSigmac) { + // particle + return aod::hf_cand_sigmac::Particle; + } + if (pdgCode == -pdgSigmac) { + // antiparticle + return aod::hf_cand_sigmac::Antiparticle; + } + + // the current particle is not a Sigmac of this species + return -1; + } + /// @brief dummy process function, to be run on data /// @param void process(aod::Tracks const&) {} @@ -412,10 +468,12 @@ struct HfCandidateSigmac0plusplusMc { /// @brief process function for MC matching of Σc0,++ → Λc+(→pK-π+) π- reconstructed candidates and counting of generated ones /// @param candidatesSigmac reconstructed Σc0,++ candidates /// @param mcParticles table of generated particles - void processMc(aod::McParticles const& mcParticles, + void processMc(McParticlesLcGenMatch const& mcParticles, aod::TracksWMc const& tracks, - LambdacMc const& candsLc /*, const LambdacMcGen&*/, - aod::McCollisions const&) + LambdacMc const& candsLc, + McCollisionsNoCents const& collInfos, + aod::McCollisions const&, + BCsInfo const&) { // Match reconstructed candidates. @@ -435,11 +493,12 @@ struct HfCandidateSigmac0plusplusMc { flag = 0; origin = 0; std::vector idxBhadMothers{}; + int8_t particleAntiparticle = -1; /// 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, -1.f, 0); + if (std::abs(candLc.flagMcMatchRec()) != hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { /// (*) + rowMCMatchScRec(flag, origin, -1.f, 0, -1); continue; } @@ -449,25 +508,58 @@ 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 * o2::hf_decay::hf_cand_sigmac::DecayChannelMain::Sc0ToPKPiPi; } - } else if (std::abs(chargeSigmac) == 2) { + auto particle = mcParticles.rawIteratorAt(indexRec); + particleAntiparticle = isParticleAntiparticle(particle, Pdg::kSigmaC0); + + /// 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 * o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStar0ToPKPiPi; + } + if (particleAntiparticle < 0) { + auto particle = mcParticles.rawIteratorAt(indexRec); + particleAntiparticle = isParticleAntiparticle(particle, Pdg::kSigmaCStar0); + } + } + + } 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 * o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScplusplusToPKPiPi; + } + auto particle = mcParticles.rawIteratorAt(indexRec); + particleAntiparticle = isParticleAntiparticle(particle, Pdg::kSigmaCPlusPlus); + + /// 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 * o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStarPlusPlusToPKPiPi; + } + if (particleAntiparticle < 0) { + auto particle = mcParticles.rawIteratorAt(indexRec); + particleAntiparticle = isParticleAntiparticle(particle, Pdg::kSigmaCStarPlusPlus); + } } } @@ -479,9 +571,9 @@ struct HfCandidateSigmac0plusplusMc { /// fill the table with results of reconstruction level MC matching if (origin == RecoDecay::OriginType::NonPrompt) { auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); - rowMCMatchScRec(flag, origin, bHadMother.pt(), bHadMother.pdgCode()); + rowMCMatchScRec(flag, origin, bHadMother.pt(), bHadMother.pdgCode(), particleAntiparticle); } else { - rowMCMatchScRec(flag, origin, -1.f, 0); + rowMCMatchScRec(flag, origin, -1.f, 0, particleAntiparticle); } } /// end loop over reconstructed Σc0,++ candidates @@ -490,11 +582,18 @@ struct HfCandidateSigmac0plusplusMc { flag = 0; origin = 0; std::vector idxBhadMothers{}; + int8_t particleAntiparticle = -1; + /// MC ev. selection done w/o centrality estimator + /// In case of need, readapt the code templetizing the function auto mcCollision = particle.mcCollision(); - float zPv = mcCollision.posZ(); - if (zPv < -zPvPosMax || zPv > zPvPosMax) { // to avoid counting particles in collisions with Zvtx larger than the maximum, we do not match them - rowMCMatchScGen(flag, origin, -1); + float centrality{-1.f}; + const auto collSlice = collInfos.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + const auto 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, -1); continue; } @@ -503,49 +602,89 @@ struct HfCandidateSigmac0plusplusMc { /// 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()) { - 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) + 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 (std::abs(daughter.flagMcMatchGen()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { /// Λc+ daughter decaying in pK-π+ found! - flag = sign * (1 << aod::hf_cand_sigmac::DecayType::Sc0ToPKPiPi); + flag = sign * o2::hf_decay::hf_cand_sigmac::DecayChannelMain::Sc0ToPKPiPi; + particleAntiparticle = isParticleAntiparticle(particle, Pdg::kSigmaC0); 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()) { - 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) + 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 (std::abs(daughter.flagMcMatchGen()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { /// Λc+ daughter decaying in pK-π+ found! - flag = sign * (1 << aod::hf_cand_sigmac::DecayType::ScplusplusToPKPiPi); + flag = sign * o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScplusplusToPKPiPi; + particleAntiparticle = isParticleAntiparticle(particle, Pdg::kSigmaCPlusPlus); 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 (std::abs(daughter.flagMcMatchGen()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + /// Λc+ daughter decaying in pK-π+ found! + flag = sign * o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStar0ToPKPiPi; + particleAntiparticle = isParticleAntiparticle(particle, Pdg::kSigmaCStar0); + 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 (std::abs(daughter.flagMcMatchGen()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + /// Λc+ daughter decaying in pK-π+ found! + flag = sign * o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStarPlusPlusToPKPiPi; + particleAntiparticle = isParticleAntiparticle(particle, Pdg::kSigmaCStarPlusPlus); + break; + } + } + } + } + /// check the origin (prompt vs. non-prompt) if (flag != 0) { - auto particle = mcParticles.rawIteratorAt(indexRec); origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); } /// fill the table with results of generation level MC matching if (origin == RecoDecay::OriginType::NonPrompt) { - rowMCMatchScGen(flag, origin, idxBhadMothers[0]); + rowMCMatchScGen(flag, origin, idxBhadMothers[0], particleAntiparticle); } else { - rowMCMatchScGen(flag, origin, -1); + rowMCMatchScGen(flag, origin, -1, particleAntiparticle); } + + // 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 index 3a953ba0ba1..017013f5179 100644 --- a/PWGHF/TableProducer/candidateCreatorSigmac0plusplusCascade.cxx +++ b/PWGHF/TableProducer/candidateCreatorSigmac0plusplusCascade.cxx @@ -15,18 +15,28 @@ /// \author Rutuparna Rath , INFN BOLOGNA and GSI Darmstadt /// In collaboration with Andrea Alici , INFN BOLOGNA -#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/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::constants::physics; @@ -76,30 +86,29 @@ struct HfCandidateCreatorSigmac0plusplusCascade { Preslice trackIndicesPerCollision = aod::track::collisionId; HistogramRegistry 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 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})"}; + AxisSpec const axisBinsPt = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisPt = {300, 0.0f, 30.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisEta = {500, -2.0f, 2.0f, "#it{#eta}"}; + AxisSpec const axisPhi = {100, 0.f, 6.3f, "#it{#phi}"}; + AxisSpec const axisMassCand = {600, 1.98f, 2.58f, "inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec const axisd0 = {500, -0.5f, 0.5f, "DCAxy (cm)"}; + AxisSpec const axisd0V0Daughters = {1000, -5.0f, 5.0f, "DCAxy (cm)"}; + AxisSpec const axisV0CPA = {500, 0.98f, 1.0001f, "v0 cos pointing angle"}; + AxisSpec const axisV0Radius = {1000, 0.f, 40.f, "V0 radius (cm)"}; + AxisSpec const axisV0DCADaughters = {200, 0.f, 2.f, "DCA (cm)"}; + AxisSpec const axisMassK0Short = {500, 0.4f, 0.6f, "#it{m}(K_{S}^{0}) (GeV/#it{c}^{2})"}; + AxisSpec const axisMassLambda = {500, 1.0f, 1.2f, "#it{m}(#Lambda) (GeV/#it{c}^{2})"}; + AxisSpec const axisMassGamma = {500, 0.0f, 0.4f, "#it{m}(#gamma) (GeV/#it{c}^{2})"}; + AxisSpec const axisCPACand = {110, -1.1f, 1.1f, "candiate cos pointing angle"}; + AxisSpec const axisDecLength = {200, 0.f, 2.0f, "decay length (cm)"}; + AxisSpec const axisProperLifetime = {100, 0.f, 0.2f, "#it{c#tau} (cm)"}; + AxisSpec const axisProperLifetimeV0 = {1000, 0.f, 80.f, "#it{c#tau} (cm)"}; + AxisSpec const axisNSigma = {100, -6.f, 6.f, "n#it{#sigma}_{p}"}; + AxisSpec const 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"); @@ -169,24 +178,33 @@ struct HfCandidateCreatorSigmac0plusplusCascade { template bool isTrackSelected(const TrackType& track) { - if (track.pt() < trkMinPt) + if (track.pt() < trkMinPt) { return false; - if (std::abs(track.eta()) > trkMaxEta) + } + if (std::abs(track.eta()) > trkMaxEta) { return false; - if (std::abs(track.dcaXY()) > maxDCAxyToPVcut) + } + if (std::abs(track.dcaXY()) > maxDCAxyToPVcut) { return false; - if (std::abs(track.dcaZ()) > maxDCAzToPVcut) + } + if (std::abs(track.dcaZ()) > maxDCAzToPVcut) { return false; - if (track.tpcNClsFound() < nTpcNClsFound) + } + if (track.tpcNClsFound() < nTpcNClsFound) { return false; - if (track.tpcNClsCrossedRows() < nTPCCrossedRows) + } + if (track.tpcNClsCrossedRows() < nTPCCrossedRows) { return false; - if (track.tpcChi2NCl() > nTPCChi2) + } + if (track.tpcChi2NCl() > nTPCChi2) { return false; - if (track.itsChi2NCl() > nITSChi2) + } + if (track.itsChi2NCl() > nITSChi2) { return false; - if (track.tpcNSigmaPi() > tpcnSigmaPi) + } + if (track.tpcNSigmaPi() > tpcnSigmaPi) { return false; + } return true; } @@ -208,7 +226,7 @@ struct HfCandidateCreatorSigmac0plusplusCascade { auto ptCand = candidateLc.pt(); auto eta = candidateLc.eta(); auto phi = candidateLc.phi(); - auto invMassLcToK0sP = hfHelper.invMassLcToK0sP(candidateLc); + auto invMassLcToK0sP = HfHelper::invMassLcToK0sP(candidateLc); auto ptProng0 = candidateLc.ptProng0(); auto ptProng1 = candidateLc.ptProng1(); auto impactParameter0 = candidateLc.impactParameter0(); @@ -224,13 +242,13 @@ struct HfCandidateCreatorSigmac0plusplusCascade { auto mLambda = candidateLc.mLambda(); auto mAntiLambda = candidateLc.mAntiLambda(); auto mGamma = candidateLc.mGamma(); - auto ctV0K0Short = hfHelper.ctV0K0s(candidateLc); - auto ctV0Lambda = hfHelper.ctV0Lambda(candidateLc); + 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); + auto ctLc = HfHelper::ctLc(candidateLc); if (addQA) { registry.fill(HIST("lc/hPtCand"), ptCand); registry.fill(HIST("lc/hEtaCand"), eta); @@ -288,9 +306,9 @@ struct HfCandidateCreatorSigmac0plusplusCascade { 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(); + 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()) { diff --git a/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx b/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx index d68fbdb7486..a3a6fed8579 100644 --- a/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx +++ b/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx @@ -12,52 +12,73 @@ /// \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 +/// \author Ran Tu , Fudan University +/// \author Tao Fang , Central China Normal University #ifndef HomogeneousField -#define HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (required by KFParticle) #endif -/// 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 "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" #include "Common/Core/trackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/Centrality.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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include 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; @@ -68,12 +89,22 @@ 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; + Produces rowKfXic0Qa; + Produces kfCandidateOmegaKaData; Configurable propagateToPCA{"propagateToPCA", false, "create tracks version propagated to PCA"}; Configurable useAbsDCA{"useAbsDCA", true, "Minimise abs. distance rather than chi2"}; @@ -86,6 +117,11 @@ struct HfCandidateCreatorXic0Omegac0 { 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"}; + Configurable doCascadePreselection{"doCascadePreselection", true, "Use invariant mass and dcaXY cuts to preselect cascade candidates"}; + Configurable dcaXYToPVCascadeMax{"dcaXYToPVCascadeMax", 3.0, "Max cascade DCA to PV in xy plane"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 1.0, "Max DCA of V0 daughter"}; + Configurable dcaCascDaughtersMax{"dcaCascDaughtersMax", 1.0, "Max DCA of cascade daughter"}; // magnetic field setting from CCDB Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; @@ -99,23 +135,29 @@ struct HfCandidateCreatorXic0Omegac0 { Configurable lambdaMassWindow{"lambdaMassWindow", 0.0075, "Distance from Lambda mass"}; // cascade cuts Configurable massToleranceCascade{"massToleranceCascade", 0.01, "Invariant mass tolerance for cascade"}; + Configurable massToleranceCascadeRej{"massToleranceCascadeRej", 0.01, "Invariant mass tolerance for rejected Xi"}; // 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"}; + Configurable kfResolutionQA{"kfResolutionQA", false, "KF: KFParticle Quality Assurance"}; 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::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; int runNumber{-1}; double magneticField{0.}; - using MyCascTable = soa::Join; // to use strangeness tracking, use aod::TraCascDatas instead of aod::CascDatas + 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 MyKfTracksIU = soa::Join; using MyKfTracks = soa::Join; using MyKfCascTable = soa::Join; using KFCascadesLinked = soa::Join; @@ -123,24 +165,26 @@ struct HfCandidateCreatorXic0Omegac0 { std::shared_ptr hInvMassCharmBaryonToXiPi, hInvMassCharmBaryonToOmegaPi, hInvMassCharmBaryonToOmegaK, hFitterStatusToXiPi, hFitterStatusToOmegaPi, hFitterStatusToOmegaK, hCandidateCounterToXiPi, hCandidateCounterToOmegaPi, hCandidateCounterToOmegaK, hCascadesCounterToXiPi, hCascadesCounterToOmegaPi, hCascadesCounterToOmegaK; HistogramRegistry registry{"registry"}; + OutputObj zorroSummary{"zorroSummary"}; + // Helper struct to pass information struct { float chi2GeoV0; float ldlV0; - float chi2TopoV0ToPv; + float chi2NdfTopoV0ToPv; float chi2GeoCasc; float ldlCasc; - float chi2TopoCascToPv; + float chi2NdfTopoCascToPv; float decayLenXYLambda; float decayLenXYCasc; - float cosPaV0ToCasc; // PA + float cosPaV0ToCasc; float cosPaXYV0ToCasc; - float cosPaV0ToPv; // PA + float cosPaV0ToPv; float cosPaXYV0ToPv; - float cosPaCascToOmegac; // PA + float cosPaCascToOmegac; float cosPaXYCascToOmegac; - float cosPaCascToPv; // PA - float cosPaXYCascToPv; // PA + float cosPaCascToPv; + float cosPaXYCascToPv; float massV0; float massCasc; float ptPiFromOmegac; @@ -148,18 +192,19 @@ struct HfCandidateCreatorXic0Omegac0 { float rapOmegac; float massOmegac; float cosThetaStarPiFromOmegac; - float chi2TopoPiFromOmegacToPv; + float chi2NdfTopoPiFromOmegacToPv; + float deviationPiFromOmegacToPv; float kfDcaXYPiFromOmegac; - float chi2TopoV0ToCasc; - float chi2TopoCascToOmegac; + float chi2NdfTopoV0ToCasc; + float chi2NdfTopoCascToOmegac; float decayLenXYOmegac; float chi2GeoOmegac; float kfDcaV0Dau; float kfDcaCascDau; float kfDcaOmegacDau; float kfDcaXYCascToPv; - float chi2TopoOmegacToPv; - float cosPaOmegacToPv; // PA + float chi2NdfTopoOmegacToPv; + float cosPaOmegacToPv; float cosPaXYOmegacToPv; float ldlOmegac; float ctV0; @@ -168,19 +213,65 @@ struct HfCandidateCreatorXic0Omegac0 { float chi2MassV0; float chi2MassCasc; float etaOmegac; - } kfOmegac0Candidate; + 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 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 chi2MassV0; + float chi2MassCasc; + float etaXic; + } kfXic0Candidate{}; + void init(InitContext const&) { - std::array allProcesses = {doprocessNoCentToXiPi, doprocessCentFT0CToXiPi, doprocessCentFT0MToXiPi, doprocessNoCentToOmegaPi, doprocessOmegacToOmegaPiWithKFParticle, doprocessCentFT0CToOmegaPi, doprocessCentFT0MToOmegaPi, doprocessNoCentToOmegaK, doprocessCentFT0CToOmegaK, doprocessCentFT0MToOmegaK}; + std::array allProcesses = {doprocessNoCentToXiPi, doprocessNoCentToXiPiTraCasc, doprocessCentFT0CToXiPi, doprocessCentFT0MToXiPi, doprocessNoCentToOmegaPi, doprocessNoCentOmegacToOmegaPiWithKFParticle, doprocessCentFT0COmegacToOmegaPiWithKFParticle, doprocessCentFT0MOmegacToOmegaPiWithKFParticle, doprocessCentFT0CToOmegaPi, doprocessCentFT0MToOmegaPi, doprocessNoCentToOmegaK, doprocessCentFT0CToOmegaK, doprocessCentFT0MToOmegaK, doprocessNoCentXicToXiPiWithKFParticle, doprocessCentFT0CXicToXiPiWithKFParticle, doprocessCentFT0MXicToXiPiWithKFParticle}; 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, doprocessCentFT0CToXiPi, doprocessCentFT0MToXiPi}; + std::array processesToXiPi = {doprocessNoCentToXiPi, doprocessNoCentToXiPiTraCasc, doprocessCentFT0CToXiPi, doprocessCentFT0MToXiPi, doprocessNoCentXicToXiPiWithKFParticle, doprocessCentFT0CXicToXiPiWithKFParticle, doprocessCentFT0MXicToXiPiWithKFParticle}; 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}; + std::array processesToOmegaPi = {doprocessNoCentToOmegaPi, doprocessCentFT0CToOmegaPi, doprocessCentFT0MToOmegaPi, doprocessNoCentOmegacToOmegaPiWithKFParticle, doprocessCentFT0COmegacToOmegaPiWithKFParticle, doprocessCentFT0MOmegacToOmegaPiWithKFParticle}; if (std::accumulate(processesToOmegaPi.begin(), processesToOmegaPi.end(), 0) > 1) { LOGP(fatal, "One and only one process ToOmegaPi function must be enabled at a time."); } @@ -195,7 +286,7 @@ struct HfCandidateCreatorXic0Omegac0 { LOGP(fatal, "At most one process function for collision monitoring can be enabled at a time."); } if (nProcessesCollisions == 1) { - if ((doprocessNoCentToXiPi && !doprocessCollisions) || (doprocessNoCentToOmegaPi && !doprocessCollisions) || (doprocessNoCentToOmegaK && !doprocessCollisions) || (doprocessOmegacToOmegaPiWithKFParticle && !doprocessCollisions)) { + if ((doprocessNoCentToXiPi && !doprocessCollisions) || (doprocessNoCentToXiPiTraCasc && !doprocessCollisions) || (doprocessNoCentToOmegaPi && !doprocessCollisions) || (doprocessNoCentToOmegaK && !doprocessCollisions) || (doprocessNoCentOmegacToOmegaPiWithKFParticle && !doprocessCollisions) || (doprocessNoCentXicToXiPiWithKFParticle && !doprocessCollisions)) { LOGP(fatal, "Process function for collision monitoring not correctly enabled. Did you enable \"processCollisions\"?"); } if ((doprocessCentFT0CToXiPi && !doprocessCollisionsCentFT0C) || (doprocessCentFT0CToOmegaPi && !doprocessCollisionsCentFT0C) || (doprocessCentFT0CToOmegaK && !doprocessCollisionsCentFT0C)) { @@ -206,33 +297,77 @@ struct HfCandidateCreatorXic0Omegac0 { } } - hInvMassCharmBaryonToXiPi = registry.add("hInvMassCharmBaryonToXiPi", "Charm baryon invariant mass - #Xi #pi decay;inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 2.2, 3.1}}}); - hInvMassCharmBaryonToOmegaPi = registry.add("hInvMassCharmBaryonToOmegaPi", "Charm baryon invariant mass - #Omega #pi decay;inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 2.2, 3.1}}}); - hInvMassCharmBaryonToOmegaK = registry.add("hInvMassCharmBaryonToOmegaK", "Charm baryon invariant mass - #Omega K decay;inv. mass (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 2.2, 3.1}}}); - hFitterStatusToXiPi = registry.add("hFitterStatusToXiPi", "Charm DCAFitter status - #Xi #pi vtx;status;entries", {HistType::kTH1F, {{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::kTH1F, {{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::kTH1F, {{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::kTH1F, {{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::kTH1F, {{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::kTH1F, {{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::kTH1F, {{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::kTH1F, {{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::kTH1F, {{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 hist - registry.add("hKFParticleV0Chi2", "hKFParticleV0Chi2", kTH1F, {{1000, -0.10f, 100.0f}}); - registry.add("hKFParticleCascChi2", "hKFParticleCascChi2 from \"track to kf\" daughter", kTH1F, {{1000, -0.1f, 100.0f}}); - registry.add("hKFParticleOmegaC0Chi2", "hKFParticleOmegaC0Chi2", kTH1F, {{1000, -0.1f, 10.0f}}); - registry.add("hKFParticleV0TopoChi2", "hKFParticleV0TopoChi2", kTH1F, {{1000, -0.10f, 100.0f}}); - registry.add("hKFParticleCascTopoChi2", "hKFParticleCascTopoChi2", kTH1F, {{1000, -0.1f, 100.0f}}); - registry.add("hKFParticleCascBachTopoChi2", "hKFParticleCascBachTopoChi2", kTH1F, {{1000, -0.1f, 100.0f}}); - registry.add("hKfLambda_ldl", "hKfLambda_ldl", kTH1F, {{1000, 0.0f, 1000.0f}}); - registry.add("hKfOmega_ldl", "hKfOmega_ldl", kTH1F, {{1000, 0.0f, 1000.0f}}); - registry.add("hKfOmegaC0_ldl", "hKfOmegaC0_ldl", kTH1F, {{1000, 0.0f, 1000.0f}}); - registry.add("hDcaXYCascadeToPVKf", "hDcaXYCascadeToPVKf", kTH1F, {{1000, 0.0f, 2.0f}}); - registry.add("hInvMassOmegaMinus", "hInvMassOmegaMinus", kTH1F, {{1000, 1.6f, 2.0f}}); - - hfEvSel.addHistograms(registry); // collision monitoring + 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}}); + } + + // init HF event selection helper + hfEvSel.init(registry, zorroSummary); df.setPropagateToPCA(propagateToPCA); df.setMaxR(maxR); @@ -252,11 +387,12 @@ struct HfCandidateCreatorXic0Omegac0 { runNumber = 0; } - template + template void runXic0Omegac0Creator(Coll const&, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/, - TracksWCovDca const&, - MyCascTable const&, CascadesLinked const&, + MyLFTracksWCov const& lfTracks, + TracksWCovDca const& tracks, + TCascTable const&, TCascLinkTable const&, aod::HfCascLf2Prongs const& candidates, Hist& hInvMassCharmBaryon, Hist& hFitterStatus, @@ -264,7 +400,7 @@ struct HfCandidateCreatorXic0Omegac0 { 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) { + 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!"); } @@ -272,15 +408,15 @@ struct HfCandidateCreatorXic0Omegac0 { hCandidateCounter->Fill(0); - if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + 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) { + } 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) { + } else if constexpr (DecayChannel == hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK) { if (!TESTBIT(cand.hfflag(), aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK)) { continue; } @@ -290,7 +426,7 @@ struct HfCandidateCreatorXic0Omegac0 { auto collision = cand.collision_as(); float centrality{-1.f}; - const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -307,24 +443,49 @@ struct HfCandidateCreatorXic0Omegac0 { } df.setBz(magneticField); - auto trackCharmBachelor = cand.prong0_as(); + auto trackCharmBachelorId = cand.prong0Id(); + auto trackCharmBachelor = tracks.rawIteratorAt(trackCharmBachelorId); - auto cascAodElement = cand.cascade_as(); + auto cascAodElement = cand.template cascade_as(); hCascadesCounter->Fill(0); int v0index = cascAodElement.v0Id(); - if (!cascAodElement.has_cascData()) { + + // 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; } - auto casc = cascAodElement.cascData_as(); + + 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 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 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 = trackV0Dau0.eta(); - float pseudorapV0Dau1 = trackV0Dau1.eta(); + float pseudorapV0Dau0 = casc.positiveeta(); + float pseudorapV0Dau1 = casc.negativeeta(); // info from LF table std::array pVecV0 = {casc.pxlambda(), casc.pylambda(), casc.pzlambda()}; @@ -334,14 +495,15 @@ struct HfCandidateCreatorXic0Omegac0 { //-------------------reconstruct cascade track------------------ // pseudorapidity - float pseudorapCascBachelor = trackCascDauCharged.eta(); + 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 const 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++) { + constexpr int NumCovElements = 6; + constexpr int MomInd[NumCovElements] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < NumCovElements; i++) { covCasc[MomInd[i]] = casc.momentumCovMat()[i]; covCasc[i] = casc.positionCovMat()[i]; } @@ -355,7 +517,7 @@ struct HfCandidateCreatorXic0Omegac0 { continue; } trackCasc.setAbsCharge(1); - if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + if constexpr (DecayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { trackCasc.setPID(o2::track::PID::XiMinus); } else { trackCasc.setPID(o2::track::PID::OmegaMinus); @@ -382,8 +544,8 @@ struct HfCandidateCreatorXic0Omegac0 { hFitterStatus->Fill(0); hCandidateCounter->Fill(2); auto vertexCharmBaryonFromFitter = df.getPCACandidate(); - std::array pVecCascAsD; - std::array pVecCharmBachelorAsD; + std::array pVecCascAsD{}; + std::array pVecCharmBachelorAsD{}; df.propagateTracksToVertex(); if (!df.isPropagateTracksToVertexDone()) { continue; @@ -392,46 +554,53 @@ struct HfCandidateCreatorXic0Omegac0 { 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 const coordVtxCharmBaryon = df.getPCACandidatePos(); std::array covVtxCharmBaryon = df.calcPCACovMatrixFlat(); // pseudorapidity - float pseudorapCharmBachelor = trackCharmBachelor.eta(); - - // DCAxy (computed with propagateToDCABxByBz method) - float dcaxyV0Dau0 = trackV0Dau0.dcaXY(); - float dcaxyV0Dau1 = trackV0Dau1.dcaXY(); - float dcaxyCascBachelor = trackCascDauCharged.dcaXY(); - - // DCAz (computed with propagateToDCABxByBz method) - float dcazV0Dau0 = trackV0Dau0.dcaZ(); - float dcazV0Dau1 = trackV0Dau1.dcaZ(); - float dcazCascBachelor = trackCascDauCharged.dcaZ(); + float const 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 const dcaxyV0Dau0 = impactParameterV0Dau0.getY(); + float const dcaxyV0Dau1 = impactParameterV0Dau1.getY(); + float const dcaxyCascBachelor = impactParameterCascDauCharged.getY(); + float const dcazV0Dau0 = impactParameterV0Dau0.getZ(); + float const dcazV0Dau1 = impactParameterV0Dau1.getZ(); + float const 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(); + float const impactParBachFromCharmBaryonXY = impactParameterCharmBachelor.getY(); + float const 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) { + 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) { + if constexpr (DecayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { arrMassCharmBaryon = {MassXiMinus, MassPiPlus}; - } else if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) { + } else if constexpr (DecayChannel == hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) { arrMassCharmBaryon = {MassOmegaMinus, MassPiPlus}; } else { arrMassCharmBaryon = {MassOmegaMinus, MassKPlus}; @@ -440,48 +609,48 @@ struct HfCandidateCreatorXic0Omegac0 { // computing cosPA float cpaV0 = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); - float cpaCharmBaryon = RecoDecay::cpa(pvCoord, coordVtxCharmBaryon, pVecCharmBaryon); + float const 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); + float const cpaxyV0 = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); + float const cpaxyCharmBaryon = RecoDecay::cpaXY(pvCoord, coordVtxCharmBaryon, pVecCharmBaryon); + float const 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); + float const decLenCharmBaryon = RecoDecay::distance(pvCoord, coordVtxCharmBaryon); + float const decLenCascade = RecoDecay::distance(coordVtxCharmBaryon, vertexCasc); + float const 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 const ctOmegac = RecoDecay::ct(pVecCharmBaryon, decLenCharmBaryon, MassOmegaC0); + float const ctXic = RecoDecay::ct(pVecCharmBaryon, decLenCharmBaryon, MassXiC0); float ctCascade = 0.; - if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { + 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); + float const ctV0 = RecoDecay::ct(pVecV0, decLenV0, MassLambda0); // computing eta - float pseudorapCharmBaryon = RecoDecay::eta(pVecCharmBaryon); - float pseudorapCascade = RecoDecay::eta(pVecCasc); - float pseudorapV0 = RecoDecay::eta(pVecV0); + float const pseudorapCharmBaryon = RecoDecay::eta(pVecCharmBaryon); + float const pseudorapCascade = RecoDecay::eta(pVecCasc); + float const pseudorapV0 = RecoDecay::eta(pVecV0); // DCA between daughters float dcaCascDau = casc.dcacascdaughters(); float dcaV0Dau = casc.dcaV0daughters(); - float dcaCharmBaryonDau = std::sqrt(df.getChi2AtPCACandidate()); + float const 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) { + if constexpr (DecayChannel == hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi) { rowCandToXiPi(collision.globalIndex(), pvCoord[0], pvCoord[1], pvCoord[2], vertexCharmBaryonFromFitter[0], vertexCharmBaryonFromFitter[1], vertexCharmBaryonFromFitter[2], @@ -490,7 +659,7 @@ struct HfCandidateCreatorXic0Omegac0 { trackCascDauCharged.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], + pVecCascAsD[0], pVecCascAsD[1], pVecCascAsD[2], pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], pVecV0[0], pVecV0[1], pVecV0[2], pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], @@ -511,7 +680,7 @@ struct HfCandidateCreatorXic0Omegac0 { dcaCascDau, dcaV0Dau, dcaCharmBaryonDau, decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon); - } else if constexpr (decayChannel == hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) { + } 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], @@ -520,7 +689,7 @@ struct HfCandidateCreatorXic0Omegac0 { trackCascDauCharged.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], + pVecCascAsD[0], pVecCascAsD[1], pVecCascAsD[2], pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], pVecV0[0], pVecV0[1], pVecV0[2], pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], @@ -539,7 +708,7 @@ struct HfCandidateCreatorXic0Omegac0 { dcaxyV0Dau0, dcaxyV0Dau1, dcaxyCascBachelor, dcazV0Dau0, dcazV0Dau1, dcazCascBachelor, dcaCascDau, dcaV0Dau, dcaCharmBaryonDau, - decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon); + decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon, cand.hfflag()); } else { rowCandToOmegaK( @@ -550,7 +719,7 @@ struct HfCandidateCreatorXic0Omegac0 { trackCascDauCharged.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], + pVecCascAsD[0], pVecCascAsD[1], pVecCascAsD[2], pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], pVecV0[0], pVecV0[1], pVecV0[2], pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], @@ -573,12 +742,13 @@ struct HfCandidateCreatorXic0Omegac0 { } } // loop over LF Cascade-bachelor candidates - } // end of run function + } // end of run function - template + template void runKfOmegac0CreatorWithKFParticle(Coll const&, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/, - MyKfTracks const&, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, MyKfCascTable const&, KFCascadesLinked const&, aod::HfCascLf2Prongs const& candidates, Hist& hInvMassCharmBaryon, @@ -590,6 +760,12 @@ struct HfCandidateCreatorXic0Omegac0 { 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(); @@ -603,19 +779,22 @@ struct HfCandidateCreatorXic0Omegac0 { df.setBz(magneticField); KFParticle::SetField(magneticField); // bachelor from Omegac0 - auto trackCharmBachelor = cand.prong0_as(); - + auto trackCharmBachelorId = cand.prong0Id(); + auto trackCharmBachelor = tracks.rawIteratorAt(trackCharmBachelorId); auto cascAodElement = cand.cascade_as(); hCascadesCounter->Fill(0); - int v0index = cascAodElement.v0Id(); + int const 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 trackCascDauChargedId = casc.bachelorId(); + auto trackV0Dau0Id = casc.posTrackId(); + auto trackV0Dau1Id = casc.negTrackId(); + auto trackCascDauCharged = tracksIU.rawIteratorAt(trackCascDauChargedId); // pion <- xi track + auto trackV0Dau0 = tracksIU.rawIteratorAt(trackV0Dau0Id); // V0 positive daughter track + auto trackV0Dau1 = tracksIU.rawIteratorAt(trackV0Dau1Id); // V0 negative daughter track auto bachCharge = trackCascDauCharged.signed1Pt() > 0 ? +1 : -1; @@ -625,38 +804,43 @@ struct HfCandidateCreatorXic0Omegac0 { // kaon <- casc TrackParCov auto omegaDauChargedTrackParCov = getTrackParCov(trackCascDauCharged); // convert tracks into KFParticle object - KFPTrack kfpTrack0 = createKFPTrackFromTrack(trackV0Dau0); - KFPTrack kfpTrack1 = createKFPTrackFromTrack(trackV0Dau1); - KFPTrack kfpTrackBach = createKFPTrackFromTrack(trackCascDauCharged); - - KFParticle kfpPosPr(kfpTrack0, kProton); - KFParticle kfpNegPi(kfpTrack1, kPiMinus); - KFParticle kfpNegKa(kfpTrackBach, kKMinus); - KFParticle kfpPosPi(kfpTrack0, kPiPlus); - KFParticle kfpNegPr(kfpTrack1, kProton); - KFParticle kfpPosKa(kfpTrackBach, kKPlus); - - KFParticle kfpBachKaon; - KFParticle kfpPos; - KFParticle kfpNeg; + KFPTrack const kfTrack0 = createKFPTrackFromTrack(trackV0Dau0); + KFPTrack const kfTrack1 = createKFPTrackFromTrack(trackV0Dau1); + KFPTrack const kfTrackBach = createKFPTrackFromTrack(trackCascDauCharged); + + KFParticle const kfPosPr(kfTrack0, kProton); + KFParticle const kfNegPi(kfTrack1, kPiMinus); + KFParticle const kfNegKa(kfTrackBach, kKMinus); + KFParticle const kfNegPiRej(kfTrackBach, kPiMinus); // rej + KFParticle const kfPosPi(kfTrack0, kPiPlus); + KFParticle const kfNegPr(kfTrack1, kProton); + KFParticle const kfPosKa(kfTrackBach, kKPlus); + KFParticle const kfPosPiRej(kfTrackBach, kPiPlus); // rej + + KFParticle kfBachKaon; + KFParticle kfPos; + KFParticle kfNeg; + KFParticle kfBachPionRej; // rej if (bachCharge < 0) { - kfpPos = kfpPosPr; - kfpNeg = kfpNegPi; - kfpBachKaon = kfpNegKa; + kfPos = kfPosPr; + kfNeg = kfNegPi; + kfBachKaon = kfNegKa; + kfBachPionRej = kfNegPiRej; // rej } else { - kfpPos = kfpPosPi; - kfpNeg = kfpNegPr; - kfpBachKaon = kfpPosKa; + kfPos = kfPosPi; + kfNeg = kfNegPr; + kfBachKaon = kfPosKa; + kfBachPionRej = kfPosPiRej; // rej } //__________________________________________ //*>~<* step 1 : construct V0 with KF - const KFParticle* V0Daughters[2] = {&kfpPos, &kfpNeg}; + const KFParticle* v0Daughters[2] = {&kfPos, &kfNeg}; // construct V0 - KFParticle KFV0; - KFV0.SetConstructMethod(kfConstructMethod); + KFParticle kfV0; + kfV0.SetConstructMethod(kfConstructMethod); try { - KFV0.Construct(V0Daughters, 2); + kfV0.Construct(v0Daughters, 2); } catch (std::runtime_error& e) { LOG(debug) << "Failed to construct cascade V0 from daughter tracks: " << e.what(); continue; @@ -664,133 +848,179 @@ struct HfCandidateCreatorXic0Omegac0 { // mass window cut on lambda before mass constraint float massLam, sigLam; - KFV0.GetMass(massLam, sigLam); - if (TMath::Abs(massLam - MassLambda0) > lambdaMassWindow) + kfV0.GetMass(massLam, sigLam); + if (std::abs(massLam - MassLambda0) > lambdaMassWindow) { continue; - registry.fill(HIST("hKFParticleV0Chi2"), KFV0.GetChi2()); + } + // 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) { - KFV0.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); + KFParticle const kfV0 = kfV0MassConstrained; } - - KFParticle KFV0_m = KFV0; - KFV0_m.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); - - //-------------------------- V0 info--------------------------- - // pseudorapidity - float pseudorapV0Dau0 = trackV0Dau0.eta(); - float pseudorapV0Dau1 = trackV0Dau1.eta(); - - // 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 = {kfpPos.GetPx(), kfpPos.GetPy(), kfpPos.GetPz()}; - std::array pVecV0Dau1 = {kfpNeg.GetPx(), kfpNeg.GetPy(), kfpNeg.GetPz()}; + kfV0.TransportToDecayVertex(); //__________________________________________ - //*>~<* step 2 : reconstruc cascade(Omega) with KF - KFParticle kfpV0 = KFV0; - const KFParticle* OmegaDaugthers[2] = {&kfpBachKaon, &kfpV0}; + //*>~<* step 2 : reconstruct cascade(Omega) with KF + const KFParticle* omegaDaugthers[2] = {&kfBachKaon, &kfV0}; + const KFParticle* omegaDaugthersRej[2] = {&kfBachPionRej, &kfV0}; // rej // construct cascade - KFParticle KFOmega; - KFOmega.SetConstructMethod(kfConstructMethod); + KFParticle kfOmega; + KFParticle kfOmegarej; // rej + kfOmega.SetConstructMethod(kfConstructMethod); + kfOmegarej.SetConstructMethod(kfConstructMethod); // rej try { - KFOmega.Construct(OmegaDaugthers, 2); + kfOmega.Construct(omegaDaugthers, 2); + kfOmegarej.Construct(omegaDaugthersRej, 2); // rej } catch (std::runtime_error& e) { - LOG(debug) << "Failed to construct omega from V0 and bachelor track: " << e.what(); + LOG(debug) << "Failed to construct Omega or Omega_rej from V0 and bachelor track: " << e.what(); continue; } float massCasc, sigCasc; - KFOmega.GetMass(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 - KFOmega.SetNonlinearMassConstraint(o2::constants::physics::MassOmegaMinus); + KFParticle const kfOmega = kfOmegaMassConstrained; } - KFParticle KFOmega_m = KFOmega; - KFOmega_m.SetNonlinearMassConstraint(o2::constants::physics::MassOmegaMinus); registry.fill(HIST("hInvMassOmegaMinus"), massCasc); - registry.fill(HIST("hKFParticleCascChi2"), KFOmega.GetChi2()); - - //-------------------reconstruct cascade track------------------ - // pseudorapidity - float pseudorapCascBachelor = trackCascDauCharged.eta(); - - // info from KFParticle - std::array vertexCasc = {KFOmega.GetX(), KFOmega.GetY(), KFOmega.GetZ()}; - std::array pVecCasc = {KFOmega.GetPx(), KFOmega.GetPy(), KFOmega.GetPz()}; - std::array covCasc = {0.}; - for (int i = 0; i < 21; i++) { - covCasc[i] = KFOmega.GetCovariance(i); - } - o2::track::TrackParCov trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, bachCharge, true, o2::track::PID::OmegaMinus); - trackCasc.setAbsCharge(1); - trackCasc.setPID(o2::track::PID::OmegaMinus); - std::array pVecCascBachelor = {kfpBachKaon.GetPx(), kfpBachKaon.GetPy(), kfpBachKaon.GetPz()}; - - //------------reconstruct charm baryon decay vtx--------------- - auto trackParVarCharmBachelor = getTrackParCov(trackCharmBachelor); // charm bachelor pion track to be processed with DCAFitter + 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 kfpTrackBachPion = createKFPTrackFromTrack(trackCharmBachelor); - - KFParticle kfpBachPion(kfpTrackBachPion, kPiPlus); - KFParticle kfpCasc = KFOmega; - const KFParticle* OmegaC0Daugthers[2] = {&kfpBachPion, &kfpCasc}; + KFPTrack const kfTrackBachPion = createKFPTrackFromTrack(trackCharmBachelor); + KFParticle const kfBachPion(kfTrackBachPion, kPiPlus); + const KFParticle* omegaC0Daugthers[2] = {&kfBachPion, &kfOmega}; // construct OmegaC0 - KFParticle KFOmegaC0; - KFOmegaC0.SetConstructMethod(kfConstructMethod); + KFParticle kfOmegaC0; + kfOmegaC0.SetConstructMethod(kfConstructMethod); try { - KFOmegaC0.Construct(OmegaC0Daugthers, 2); + kfOmegaC0.Construct(omegaC0Daugthers, 2); } catch (std::runtime_error& e) { - LOG(debug) << "Failed to construct OmegaC0 from V0 and bachelor track: " << e.what(); + LOG(debug) << "Failed to construct OmegaC0 from Cascade and bachelor pion track: " << e.what(); continue; } float massOmegaC0, sigOmegaC0; - KFOmegaC0.GetMass(massOmegaC0, sigOmegaC0); - registry.fill(HIST("hKFParticleOmegaC0Chi2"), KFOmegaC0.GetChi2()); + kfOmegaC0.GetMass(massOmegaC0, sigOmegaC0); + if (sigOmegaC0 <= 0) { + continue; + } + hFitterStatus->Fill(0); hCandidateCounter->Fill(2); - + kfOmegaC0.TransportToDecayVertex(); // PV - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - KFParticle KFPV(kfpVertex); + KFPVertex const kfVertex = createKFPVertexFromCollision(collision); + KFParticle const 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 const pseudorapV0Dau0 = kfPos.GetEta(); + float const 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 const 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 pVecCascAsD; - std::array pVecCharmBachelorAsD; - pVecCharmBachelorAsD[0] = kfpBachPion.GetPx(); - pVecCharmBachelorAsD[1] = kfpBachPion.GetPy(); - pVecCharmBachelorAsD[2] = kfpBachPion.GetPz(); - pVecCascAsD[0] = kfpCasc.GetPx(); - pVecCascAsD[1] = kfpCasc.GetPy(); - pVecCascAsD[2] = kfpCasc.GetPz(); - - std::array pVecCharmBaryon = {pVecCascAsD[0] + pVecCharmBachelorAsD[0], pVecCascAsD[1] + pVecCharmBachelorAsD[1], pVecCascAsD[2] + pVecCharmBachelorAsD[2]}; - std::array coordVtxCharmBaryon = {KFOmegaC0.GetX(), KFOmegaC0.GetY(), KFOmegaC0.GetZ()}; - auto covVtxCharmBaryon = KFOmegaC0.CovarianceMatrix(); + 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 const coordVtxCharmBaryon = {kfOmegaC0.GetX(), kfOmegaC0.GetY(), kfOmegaC0.GetZ()}; + auto* covVtxCharmBaryon = kfOmegaC0.CovarianceMatrix(); float covMatrixPV[6]; - kfpVertex.GetCovarianceMatrix(covMatrixPV); + kfVertex.GetCovarianceMatrix(covMatrixPV); // impact parameters - o2::dataformats::DCA impactParameterV0Dau0; - o2::dataformats::DCA impactParameterV0Dau1; - o2::dataformats::DCA impactParameterKaFromCasc; - o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParCovV0Dau0, 2.f, matCorr, &impactParameterV0Dau0); - o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParCovV0Dau1, 2.f, matCorr, &impactParameterV0Dau1); - o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, omegaDauChargedTrackParCov, 2.f, matCorr, &impactParameterKaFromCasc); - float dcaxyV0Dau0 = impactParameterV0Dau0.getY(); - float dcaxyV0Dau1 = impactParameterV0Dau1.getY(); - float dcaxyCascBachelor = impactParameterKaFromCasc.getY(); - float dcazV0Dau0 = impactParameterV0Dau0.getZ(); - float dcazV0Dau1 = impactParameterV0Dau1.getZ(); - float dcazCascBachelor = impactParameterKaFromCasc.getZ(); + std::array impactParameterV0Dau0{}; + std::array impactParameterV0Dau1{}; + std::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 const dcazV0Dau0 = impactParameterV0Dau0[1]; + float const dcazV0Dau1 = impactParameterV0Dau1[1]; + float const dcazCascBachelor = impactParameterKaFromCasc[1]; // pseudorapidity - float pseudorapCharmBachelor = trackCharmBachelor.eta(); + float const pseudorapCharmBachelor = kfBachPionToOmegaC.GetEta(); // impact parameters o2::dataformats::DCA impactParameterCasc; @@ -801,12 +1031,12 @@ struct HfCandidateCreatorXic0Omegac0 { 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); + float const decLenCharmBaryon = RecoDecay::distance(pvCoord, coordVtxCharmBaryon); + float const decLenCascade = RecoDecay::distance(coordVtxCharmBaryon, vertexCasc); + float const decLenV0 = RecoDecay::distance(vertexCasc, vertexV0); double phiCharmBaryon, thetaCharmBaryon; - getPointDirection(std::array{KFV0.GetX(), KFV0.GetY(), KFV0.GetZ()}, coordVtxCharmBaryon, 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.)); @@ -815,132 +1045,145 @@ struct HfCandidateCreatorXic0Omegac0 { hCandidateCounter->Fill(3); //// KFParticle table information - KFParticle kfpNegToV0 = kfpNeg; - KFParticle kfpPosToV0 = kfpPos; - kfpNegToV0.SetProductionVertex(KFV0); - kfpPosToV0.SetProductionVertex(KFV0); - - KFParticle kfpBachKaonToOmega = kfpBachKaon; - KFParticle kfpV0ToCasc = kfpV0; - kfpBachKaonToOmega.SetProductionVertex(KFOmega); - kfpV0ToCasc.SetProductionVertex(KFOmega); - - KFParticle kfpCascToOmegaC = kfpCasc; - KFParticle kfpBachPionToOmegaC = kfpBachPion; - kfpBachPionToOmegaC.SetProductionVertex(KFOmegaC0); - kfpCascToOmegaC.SetProductionVertex(KFOmegaC0); - - // KFParticle to PV - KFParticle kfpV0ToPv = kfpV0; - KFParticle kfpCascToPv = kfpCasc; - KFParticle kfpOmegacToPv = KFOmegaC0; - KFParticle kfpPiFromOmegacToPv = kfpBachPion; - - kfpV0ToPv.SetProductionVertex(KFPV); - kfpCascToPv.SetProductionVertex(KFPV); - kfpOmegacToPv.SetProductionVertex(KFPV); - kfpPiFromOmegacToPv.SetProductionVertex(KFPV); - - // KF geochi2 - kfOmegac0Candidate.chi2GeoV0 = KFV0.GetChi2(); - auto v0NDF = KFV0.GetNDF(); + // KF chi2 + auto v0NDF = kfV0.GetNDF(); auto v0Chi2OverNdf = kfOmegac0Candidate.chi2GeoV0 / v0NDF; - kfOmegac0Candidate.chi2GeoCasc = KFOmega.GetChi2(); - auto cascNDF = KFOmega.GetNDF(); + auto cascNDF = kfOmega.GetNDF(); auto cascChi2OverNdf = kfOmegac0Candidate.chi2GeoCasc / cascNDF; - kfOmegac0Candidate.chi2GeoOmegac = KFOmegaC0.GetChi2(); - auto charmbaryonNDF = KFOmegaC0.GetNDF(); + kfOmegac0Candidate.chi2GeoOmegac = kfOmegaC0.GetChi2(); + auto charmbaryonNDF = kfOmegaC0.GetNDF(); auto charmbaryonChi2OverNdf = kfOmegac0Candidate.chi2GeoOmegac / charmbaryonNDF; - kfOmegac0Candidate.chi2MassV0 = KFV0_m.GetChi2(); - auto v0NDF_m = KFV0_m.GetNDF(); - auto v0Chi2OverNdf_m = kfOmegac0Candidate.chi2MassV0 / v0NDF_m; + kfOmegac0Candidate.chi2MassV0 = kfV0MassConstrained.GetChi2(); + auto v0Ndfm = kfV0MassConstrained.GetNDF(); + auto v0Chi2OverNdfm = kfOmegac0Candidate.chi2MassV0 / v0Ndfm; - kfOmegac0Candidate.chi2MassCasc = KFOmega_m.GetChi2(); - auto cascNDF_m = KFOmega_m.GetNDF(); - auto cascChi2OverNdf_m = kfOmegac0Candidate.chi2MassCasc / cascNDF_m; + kfOmegac0Candidate.chi2MassCasc = kfOmegaMassConstrained.GetChi2(); + auto cascNdfm = kfOmegaMassConstrained.GetNDF(); + auto cascChi2OverNdfm = kfOmegac0Candidate.chi2MassCasc / cascNdfm; - // KF topo Chi2 - kfOmegac0Candidate.chi2TopoV0ToPv = kfpV0ToPv.GetChi2(); - kfOmegac0Candidate.chi2TopoCascToPv = kfpCascToPv.GetChi2(); - kfOmegac0Candidate.chi2TopoPiFromOmegacToPv = kfpPiFromOmegacToPv.GetChi2(); - kfOmegac0Candidate.chi2TopoOmegacToPv = kfpOmegacToPv.GetChi2(); + // 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 cascBachTopoChi2 = kfpBachKaonToOmega.GetChi2(); - kfOmegac0Candidate.chi2TopoV0ToCasc = kfpV0ToCasc.GetChi2(); - kfOmegac0Candidate.chi2TopoCascToOmegac = kfpCascToOmegaC.GetChi2(); + 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); + kfOmegac0Candidate.ldlV0 = ldlFromKF(kfV0, kfPV); + kfOmegac0Candidate.ldlCasc = ldlFromKF(kfOmega, kfPV); + kfOmegac0Candidate.ldlOmegac = ldlFromKF(kfOmegaC0, kfPV); // KF dca - kfOmegac0Candidate.kfDcaXYPiFromOmegac = kfpBachPion.GetDistanceFromVertexXY(KFPV); - kfOmegac0Candidate.kfDcaV0Dau = kfpNegToV0.GetDistanceFromParticle(kfpPosToV0); - kfOmegac0Candidate.kfDcaCascDau = kfpBachKaon.GetDistanceFromParticle(kfpV0); - kfOmegac0Candidate.kfDcaXYCascToPv = kfpCasc.GetDistanceFromVertexXY(KFPV); - kfOmegac0Candidate.kfDcaOmegacDau = kfpBachPion.GetDistanceFromParticle(kfpCasc); + 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 DecayLxy_Lam, err_DecayLxy_Lam; - kfpV0ToCasc.GetDecayLengthXY(DecayLxy_Lam, err_DecayLxy_Lam); - kfOmegac0Candidate.decayLenXYLambda = DecayLxy_Lam; + float decayLxyLam, errDecayLxyLam; + kfV0ToCasc.GetDecayLengthXY(decayLxyLam, errDecayLxyLam); + kfOmegac0Candidate.decayLenXYLambda = decayLxyLam; - float DecayLxy_Casc, err_DecayLxy_Casc; - kfpCascToPv.GetDecayLengthXY(DecayLxy_Casc, err_DecayLxy_Casc); - kfOmegac0Candidate.decayLenXYCasc = DecayLxy_Casc; + float decayLxyCasc, errDecayLxyCasc; + kfOmegaToOmegaC.GetDecayLengthXY(decayLxyCasc, errDecayLxyCasc); + kfOmegac0Candidate.decayLenXYCasc = decayLxyCasc; - float DecayLxy_Omegac0, err_DecayLxy_Omegac0; - kfpOmegacToPv.GetDecayLengthXY(DecayLxy_Omegac0, err_DecayLxy_Omegac0); - kfOmegac0Candidate.decayLenXYOmegac = DecayLxy_Omegac0; + float decayLxyOmegac0, errDecayLxyOmegac0; + kfOmegac0ToPv.GetDecayLengthXY(decayLxyOmegac0, errDecayLxyOmegac0); + kfOmegac0Candidate.decayLenXYOmegac = decayLxyOmegac0; // KF cosPA - kfOmegac0Candidate.cosPaV0ToPv = cpaFromKF(kfpV0, KFPV); - kfOmegac0Candidate.cosPaCascToPv = cpaFromKF(kfpCasc, KFPV); - kfOmegac0Candidate.cosPaOmegacToPv = cpaFromKF(KFOmegaC0, KFPV); - kfOmegac0Candidate.cosPaXYV0ToPv = cpaXYFromKF(kfpV0, KFPV); - kfOmegac0Candidate.cosPaXYCascToPv = cpaXYFromKF(kfpCasc, KFPV); - kfOmegac0Candidate.cosPaXYOmegacToPv = cpaXYFromKF(KFOmegaC0, KFPV); - - kfOmegac0Candidate.cosPaV0ToCasc = cpaFromKF(kfpV0, kfpCasc); - kfOmegac0Candidate.cosPaCascToOmegac = cpaFromKF(kfpCasc, KFOmegaC0); - kfOmegac0Candidate.cosPaXYV0ToCasc = cpaXYFromKF(kfpV0, kfpCasc); - kfOmegac0Candidate.cosPaXYCascToOmegac = cpaXYFromKF(kfpCasc, KFOmegaC0); + 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 = trackCharmBachelor.pt(); - kfOmegac0Candidate.ptOmegac = kfpOmegacToPv.GetPt(); + kfOmegac0Candidate.ptPiFromOmegac = kfBachPionToOmegaC.GetPt(); + kfOmegac0Candidate.ptOmegac = kfOmegaC0.GetPt(); // KF rapidity - kfOmegac0Candidate.rapOmegac = kfpOmegacToPv.GetRapidity(); + kfOmegac0Candidate.rapOmegac = kfOmegaC0.GetRapidity(); // KF cosThetaStar - kfOmegac0Candidate.cosThetaStarPiFromOmegac = cosThetaStarFromKF(0, 4332, 211, 3312, kfpBachPionToOmegaC, kfpCascToOmegaC); + kfOmegac0Candidate.cosThetaStarPiFromOmegac = cosThetaStarFromKF(0, 4332, 211, 3312, kfBachPionToOmegaC, kfOmegaToOmegaC); // KF ct - kfOmegac0Candidate.ctV0 = kfpV0ToCasc.GetLifeTime(); - kfOmegac0Candidate.ctCasc = kfpCascToOmegaC.GetLifeTime(); - kfOmegac0Candidate.ctOmegac = kfpOmegacToPv.GetLifeTime(); + kfOmegac0Candidate.ctV0 = kfV0.GetLifeTime(); + kfOmegac0Candidate.ctCasc = kfOmega.GetLifeTime(); + kfOmegac0Candidate.ctOmegac = kfOmegaC0.GetLifeTime(); // KF eta - kfOmegac0Candidate.etaOmegac = kfpOmegacToPv.GetEta(); + kfOmegac0Candidate.etaOmegac = kfOmegaC0.GetEta(); // fill KF hist - registry.fill(HIST("hKFParticleCascBachTopoChi2"), cascBachTopoChi2); - registry.fill(HIST("hKFParticleV0TopoChi2"), kfOmegac0Candidate.chi2TopoV0ToCasc); - registry.fill(HIST("hKFParticleCascTopoChi2"), kfOmegac0Candidate.chi2TopoCascToOmegac); - + 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(), @@ -951,7 +1194,7 @@ struct HfCandidateCreatorXic0Omegac0 { trackCascDauCharged.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], + kfOmegaToOmegaC.GetPx(), kfOmegaToOmegaC.GetPy(), kfOmegaToOmegaC.GetPz(), pVecCharmBachelorAsD[0], pVecCharmBachelorAsD[1], pVecCharmBachelorAsD[2], pVecV0[0], pVecV0[1], pVecV0[2], pVecCascBachelor[0], pVecCascBachelor[1], pVecCascBachelor[2], @@ -966,69 +1209,871 @@ struct HfCandidateCreatorXic0Omegac0 { 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(), + kfOmegac0Candidate.etaOmegac, kfOmega.GetEta(), kfV0.GetEta(), dcaxyV0Dau0, dcaxyV0Dau1, dcaxyCascBachelor, dcazV0Dau0, dcazV0Dau1, dcazCascBachelor, kfOmegac0Candidate.kfDcaCascDau, kfOmegac0Candidate.kfDcaV0Dau, kfOmegac0Candidate.kfDcaOmegacDau, - decLenCharmBaryon, decLenCascade, decLenV0, errorDecayLengthCharmBaryon, errorDecayLengthXYCharmBaryon); + 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.chi2TopoV0ToPv, kfOmegac0Candidate.chi2TopoCascToPv, kfOmegac0Candidate.chi2TopoPiFromOmegacToPv, kfOmegac0Candidate.chi2TopoOmegacToPv, - kfOmegac0Candidate.chi2TopoV0ToCasc, kfOmegac0Candidate.chi2TopoCascToOmegac, + 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, v0NDF_m, cascNDF_m, - v0Chi2OverNdf, cascChi2OverNdf, charmbaryonChi2OverNdf, v0Chi2OverNdf_m, cascChi2OverNdf_m); + v0NDF, cascNDF, charmbaryonNDF, v0Ndfm, cascNdfm, + v0Chi2OverNdf, cascChi2OverNdf, charmbaryonChi2OverNdf, v0Chi2OverNdfm, cascChi2OverNdfm, kfOmegac0Candidate.cascRejectInvmass); } // loop over LF Cascade-bachelor candidates - } // end of run function + } // end of run function + //========================================================== + template + void runKfXic0CreatorWithKFParticle(Coll const&, + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const&, KFCascadesLinked const&, + aod::HfCascLf2Prongs const& candidates, + Hist& hInvMassCharmBaryon, + Hist& hFitterStatus, + Hist& hCandidateCounter, + Hist& hCascadesCounter) + { + for (const auto& cand : candidates) { + hCandidateCounter->Fill(1); + if (!TESTBIT(cand.hfflag(), aod::hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi)) { + continue; + } + 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); + KFParticle::SetField(magneticField); + // bachelor from Xic0 + auto trackCharmBachelorId = cand.prong0Id(); + auto trackCharmBachelor = tracks.rawIteratorAt(trackCharmBachelorId); + auto cascAodElement = cand.cascade_as(); + hCascadesCounter->Fill(0); + int const v0index = cascAodElement.v0Id(); + if (!cascAodElement.has_kfCascData()) { + continue; + } + auto casc = cascAodElement.kfCascData_as(); + hCascadesCounter->Fill(1); + auto trackCascDauChargedId = casc.bachelorId(); + auto trackV0Dau0Id = casc.posTrackId(); + auto trackV0Dau1Id = casc.negTrackId(); + auto trackCascDauCharged = tracksIU.rawIteratorAt(trackCascDauChargedId); // pion <- xi track + auto trackV0Dau0 = tracksIU.rawIteratorAt(trackV0Dau0Id); // V0 positive daughter track + auto trackV0Dau1 = tracksIU.rawIteratorAt(trackV0Dau1Id); // 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 const kfTrack0 = createKFPTrackFromTrack(trackV0Dau0); + KFPTrack const kfTrack1 = createKFPTrackFromTrack(trackV0Dau1); + KFPTrack const kfTrackBach = createKFPTrackFromTrack(trackCascDauCharged); + + KFParticle const kfPosPr(kfTrack0, kProton); + KFParticle const kfNegPi(kfTrack1, kPiMinus); + KFParticle const kfNegBachPi(kfTrackBach, kPiMinus); + KFParticle const kfPosPi(kfTrack0, kPiPlus); + KFParticle const kfNegPr(kfTrack1, kProton); + KFParticle const 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) { + 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 const kfXi = kfXiMassConstrained; + } + registry.fill(HIST("hInvMassXiMinus"), massCasc); + kfXi.TransportToDecayVertex(); + + //__________________________________________ + //*>~<* step 3 : reconstruc Xic0 with KF + // Create KF charm bach Pion from track + KFPTrack const kfTrackBachPion = createKFPTrackFromTrack(trackCharmBachelor); + KFParticle const 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 const kfVertex = createKFPVertexFromCollision(collision); + KFParticle const kfPV(kfVertex); + + KFParticle const kfPosOrigin = kfPos; + KFParticle const kfNegOrigin = kfNeg; + // 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 const pseudorapV0Dau0 = kfPos.GetEta(); + float const 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 const pseudorapCascBachelor = kfBachPionToXi.GetEta(); + + // info from KFParticle + std::array vertexCasc = {kfXi.GetX(), kfXi.GetY(), kfXi.GetZ()}; + std::array pVecCascBachelor = {kfBachPionToXi.GetPx(), kfBachPionToXi.GetPy(), kfBachPionToXi.GetPz()}; + + std::array pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; + std::array pVecCharmBachelorAsD{}; + pVecCharmBachelorAsD[0] = kfCharmBachPionToXiC.GetPx(); + pVecCharmBachelorAsD[1] = kfCharmBachPionToXiC.GetPy(); + pVecCharmBachelorAsD[2] = kfCharmBachPionToXiC.GetPz(); + + std::array pVecCharmBaryon = {kfXiC0.GetPx(), kfXiC0.GetPy(), kfXiC0.GetPz()}; + auto* covVtxCharmBaryon = kfXiC0.CovarianceMatrix(); + float covMatrixPV[6]; + kfVertex.GetCovarianceMatrix(covMatrixPV); + + // impact parameters + std::array impactParameterV0Dau0{}; + std::array impactParameterV0Dau1{}; + std::array impactParameterPiFromCasc{}; + 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, &impactParameterPiFromCasc); + float const dcaxyV0Dau0 = impactParameterV0Dau0[0]; + float const dcaxyV0Dau1 = impactParameterV0Dau1[0]; + float const dcaxyCascBachelor = impactParameterPiFromCasc[0]; + + // pseudorapidity + float const pseudorapCharmBachelor = kfCharmBachPionToXiC.GetEta(); + + // 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 rapidity + kfXic0Candidate.rapXic = kfXiC0.GetRapidity(); + + // KF cosThetaStar + kfXic0Candidate.cosThetaStarPiFromXic = cosThetaStarFromKF(0, 4132, 211, 3312, kfCharmBachPionToXiC, kfXiToXiC); + + // KF ct + kfXic0Candidate.ctV0 = kfV0ToCasc.GetLifeTime(); + kfXic0Candidate.ctCasc = kfXiToXiC.GetLifeTime(); + kfXic0Candidate.ctXic = kfXic0ToPv.GetLifeTime(); + // KF eta + kfXic0Candidate.etaXic = kfXiC0.GetEta(); + + // fill KF hist + registry.fill(HIST("hKFParticleCascBachTopoChi2"), cascBachTopoChi2); + registry.fill(HIST("hKfXiC0_ldl"), kfXic0Candidate.ldlXic); + + // fill kf table + kfCandidateXicData(collision.globalIndex(), + pvCoord[0], pvCoord[1], pvCoord[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], + v0index, casc.posTrackId(), casc.negTrackId(), + casc.cascadeId(), trackCharmBachelor.globalIndex(), casc.bachelorId(), + kfXic0Candidate.massV0, kfXic0Candidate.massCasc, kfXic0Candidate.massXic, + kfXic0Candidate.cosPaV0ToPv, kfXic0Candidate.cosPaCascToPv, + kfXic0Candidate.ctCasc, kfXic0Candidate.ctV0, kfXic0Candidate.ctXic, + pseudorapV0Dau0, pseudorapV0Dau1, pseudorapCascBachelor, pseudorapCharmBachelor, + kfXic0Candidate.etaXic, kfXi.GetEta(), kfV0.GetEta(), + dcaxyV0Dau0, dcaxyV0Dau1, dcaxyCascBachelor, + kfXic0Candidate.kfDcaCascDau, kfXic0Candidate.kfDcaV0Dau, kfXic0Candidate.kfDcaXicDau, + kfXic0Candidate.kfDcaXYPiFromXic, kfXic0Candidate.kfDcaXYCascToPv, + kfXic0Candidate.chi2GeoV0, kfXic0Candidate.chi2GeoCasc, kfXic0Candidate.chi2GeoXic, kfXic0Candidate.chi2MassV0, kfXic0Candidate.chi2MassCasc, + kfXic0Candidate.ldlV0, kfXic0Candidate.ldlCasc, + kfXic0Candidate.chi2NdfTopoV0ToPv, kfXic0Candidate.chi2NdfTopoCascToPv, kfXic0Candidate.chi2NdfTopoPiFromXicToPv, kfXic0Candidate.chi2NdfTopoXicToPv, + kfXic0Candidate.chi2NdfTopoV0ToCasc, kfXic0Candidate.chi2NdfTopoCascToXic, + kfXic0Candidate.decayLenXYLambda, kfXic0Candidate.decayLenXYCasc, kfXic0Candidate.decayLenXYXic, + kfXic0Candidate.cosPaV0ToCasc, kfXic0Candidate.cosPaCascToXic, + kfXic0Candidate.rapXic, + kfXic0Candidate.cosThetaStarPiFromXic, + v0NDF, cascNDF, charmbaryonNDF, v0Ndfm, cascNdfm, + v0Chi2OverNdf, cascChi2OverNdf, charmbaryonChi2OverNdf, v0Chi2OverNdfm, cascChi2OverNdfm); + // fill QA table + if (kfResolutionQA) { + rowKfXic0Qa(massLam, massCasc, massXiC0, sigLam, sigCasc, sigXiC0, + collision.globalIndex(), v0index, casc.posTrackId(), casc.negTrackId(), casc.cascadeId(), trackCharmBachelor.globalIndex(), casc.bachelorId(), + kfPos.GetX(), kfPos.GetY(), kfPos.GetZ(), kfPos.GetErrX(), kfPos.GetErrY(), kfPos.GetErrZ(), kfPos.GetPt(), + kfNeg.GetX(), kfNeg.GetY(), kfNeg.GetZ(), kfNeg.GetErrX(), kfNeg.GetErrY(), kfNeg.GetErrZ(), kfNeg.GetPt(), + kfV0.GetX(), kfV0.GetY(), kfV0.GetZ(), kfV0.GetErrX(), kfV0.GetErrY(), kfV0.GetErrZ(), kfV0.GetPt(), + kfBachPionToXi.GetX(), kfBachPionToXi.GetY(), kfBachPionToXi.GetZ(), kfBachPionToXi.GetErrX(), kfBachPionToXi.GetErrY(), kfBachPionToXi.GetErrZ(), kfBachPionToXi.GetPt(), + kfXi.GetX(), kfXi.GetY(), kfXi.GetZ(), kfXi.GetErrX(), kfXi.GetErrY(), kfXi.GetErrZ(), kfXi.GetPt(), + kfCharmBachPionToXiC.GetX(), kfCharmBachPionToXiC.GetY(), kfCharmBachPionToXiC.GetZ(), kfCharmBachPionToXiC.GetErrX(), kfCharmBachPionToXiC.GetErrY(), kfCharmBachPionToXiC.GetErrZ(), kfCharmBachPionToXiC.GetPt(), + kfXiC0.GetX(), kfXiC0.GetY(), kfXiC0.GetZ(), kfXiC0.GetErrX(), kfXiC0.GetErrY(), kfXiC0.GetErrZ(), kfXiC0.GetPt(), + casc.xlambda(), casc.ylambda(), casc.zlambda(), casc.x(), casc.y(), casc.z()); + } + } // loop over LF Cascade-bachelor candidates + } + + template + void runOmegac0Xic0ToOmegaKaCreatorWithKFParticle(Coll const&, + aod::BCsWithTimestamps const& /*bcWithTimeStamps*/, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const&, KFCascadesLinked const&, + aod::HfCascLf2Prongs const& candidates, + Hist& hInvMassCharmBaryon, + Hist& hFitterStatus, + Hist& hCandidateCounter, + Hist& hCascadesCounter) + { + for (const auto& cand : candidates) { + hCandidateCounter->Fill(1); + + //----------------------check if the event is selected----------------------------- + 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(); + } + KFParticle::SetField(magneticField); + + // Retrieve skimmed cascade and pion tracks + auto cascAodElement = cand.cascade_as(); + hCascadesCounter->Fill(0); + if (!cascAodElement.has_kfCascData()) { + continue; + } + auto casc = cascAodElement.kfCascData_as(); + hCascadesCounter->Fill(1); + + // convert KaonFromCharm&KaFromOmega&V0DauPos&V0DauNeg tracks into KFParticle object + auto trackCharmBachelorId = cand.prong0Id(); + auto trackKaFromCharm = tracks.rawIteratorAt(trackCharmBachelorId); + auto trackCascDauChargedId = casc.bachelorId(); + auto trackV0Dau0Id = casc.posTrackId(); + auto trackV0Dau1Id = casc.negTrackId(); + auto trackKaFromOmega = tracksIU.rawIteratorAt(trackCascDauChargedId); // Ka <- Omega track + auto trackV0DauPos = tracksIU.rawIteratorAt(trackV0Dau0Id); // V0 positive daughter track + auto trackV0DauNeg = tracksIU.rawIteratorAt(trackV0Dau1Id); // V0 negative daughter track + auto kaFromOmegaCharge = trackKaFromOmega.sign(); + auto signOmega = casc.sign(); + + KFPTrack const kfpTrackKaFromCharm = createKFPTrackFromTrack(trackKaFromCharm); + KFPTrack const kfpTrackKaFromOmega = createKFPTrackFromTrack(trackKaFromOmega); + KFPTrack const kfpTrackV0DauPos = createKFPTrackFromTrack(trackV0DauPos); + KFPTrack const kfpTrackV0DauNeg = createKFPTrackFromTrack(trackV0DauNeg); + + KFParticle kfPrFromV0(kfpTrackV0DauPos, kProton); + KFParticle kfPiFromV0(kfpTrackV0DauNeg, kPiMinus); + KFParticle kfKaFromOmega(kfpTrackKaFromOmega, kKMinus); + KFParticle kfPiFromXiRej(kfpTrackKaFromOmega, kPiMinus); // rej + KFParticle kfKaFromCharm(kfpTrackKaFromCharm, kKPlus); + + if (signOmega == 0 || kaFromOmegaCharge == 0 || kaFromOmegaCharge != signOmega) { + continue; + } + // convert for Pos and Neg Particles + if (signOmega > 0) { + kfPiFromV0 = KFParticle(kfpTrackV0DauPos, kPiPlus); + kfPrFromV0 = KFParticle(kfpTrackV0DauNeg, -kProton); + kfKaFromOmega = KFParticle(kfpTrackKaFromOmega, kKPlus); + kfPiFromXiRej = KFParticle(kfpTrackKaFromOmega, kPiPlus); // rej + kfKaFromCharm = KFParticle(kfpTrackKaFromCharm, kKMinus); + } + + if (doCascadePreselection) { + if (std::abs(casc.dcaXYCascToPV()) > dcaXYToPVCascadeMax) { + continue; + } + if (std::abs(casc.dcaV0daughters()) > dcaV0DaughtersMax) { + continue; + } + if (std::abs(casc.dcacascdaughters()) > dcaCascDaughtersMax) { + continue; + } + if (std::abs(casc.mOmega() - MassOmegaMinus) > massToleranceCascade) { + continue; + } + } + + //----------------------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()}; + + // step 1 : construct V0 with KF + const KFParticle* v0Daughters[2] = {&kfPrFromV0, &kfPiFromV0}; + // 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; + } + KFParticle kfV0MassConstrained = kfV0; + kfV0MassConstrained.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); // set mass constrain to Lambda + if (kfUseV0MassConstraint) { + kfV0 = kfV0MassConstrained; + } + kfV0.TransportToDecayVertex(); + + // step 2 : reconstruct cascade(Omega) with KF + const KFParticle* omegaDaugthers[2] = {&kfKaFromOmega, &kfV0}; + const KFParticle* omegaDaugthersRej[2] = {&kfPiFromXiRej, &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 and err_massXiRej > 0 + if (sigCasc <= 0 || sigCascrej <= 0) { + continue; + } + // chi2>0 && NDF>0 + if (kfOmega.GetNDF() <= 0 || kfOmega.GetChi2() <= 0) { + continue; + } + if ((std::abs(massCasc - MassOmegaMinus) > massToleranceCascade) || (std::abs(massCascrej - MassXiMinus) < massToleranceCascadeRej)) { + continue; + } + registry.fill(HIST("hInvMassXiMinus_rej"), massCascrej); // rej: Add competing rejection to minimize misidentified Xi impact. Reject if kfBachPionRej is Pion and the constructed cascade has Xi's invariant mass. + KFParticle kfOmegaMassConstrained = kfOmega; + kfOmegaMassConstrained.SetNonlinearMassConstraint(o2::constants::physics::MassOmegaMinus); // set mass constrain to XiMinus + if (kfUseCascadeMassConstraint) { + // set mass constraint if requested + kfOmega = kfOmegaMassConstrained; + } + registry.fill(HIST("hInvMassXiMinus"), 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 OmegaKa with KF + // Create KF charm bach Pion from track + const KFParticle* omegaKaDaugthers[2] = {&kfKaFromCharm, &kfOmega}; + // construct Omegac0 or Xic0 + KFParticle kfOmegaKa; + kfOmegaKa.SetConstructMethod(kfConstructMethod); + try { + kfOmegaKa.Construct(omegaKaDaugthers, 2); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to construct OmegaKa from Cascade and bachelor pion track: " << e.what(); + continue; + } + float massOmegaKa, sigOmegaKa; + kfOmegaKa.GetMass(massOmegaKa, sigOmegaKa); + if (sigOmegaKa <= 0) { + continue; + } + if (kfOmegaKa.GetNDF() <= 0 || kfOmegaKa.GetChi2() <= 0) { + continue; + } + kfOmegaKa.TransportToDecayVertex(); + hFitterStatus->Fill(0); + hCandidateCounter->Fill(2); + + // initialize primary vertex + KFPVertex const kfpVertex = createKFPVertexFromCollision(collision); + float covMatrixPV[6]; + kfpVertex.GetCovarianceMatrix(covMatrixPV); + KFParticle const kfPv(kfpVertex); // for calculation of DCAs to PV + + // fill test histograms + hInvMassCharmBaryon->Fill(massOmegaKa); + + // topological constraint of daughter to mother + KFParticle kfKaFromCharmToOmegaKa = kfKaFromCharm; + KFParticle kfOmegaToOmegaKa = kfOmega; + KFParticle kfV0ToOmega = kfV0; + KFParticle kfKaToOmega = kfKaFromOmega; + KFParticle kfPrToV0 = kfPrFromV0; + KFParticle kfPiToV0 = kfPiFromV0; + + kfPrToV0.SetProductionVertex(kfV0); + kfPiToV0.SetProductionVertex(kfV0); + kfV0ToOmega.SetProductionVertex(kfOmega); + kfKaToOmega.SetProductionVertex(kfOmega); + kfKaFromCharmToOmegaKa.SetProductionVertex(kfOmegaKa); + kfOmegaToOmegaKa.SetProductionVertex(kfOmegaKa); + + // topological constraint to PV + // KFParticle to PV + KFParticle kfV0ToPv = kfV0; + KFParticle kfOmegaToPv = kfOmega; + KFParticle kfCharmToPv = kfOmegaKa; + KFParticle kfKaFromCharmToPv = kfKaFromCharm; + + kfV0ToPv.SetProductionVertex(kfPv); + kfOmegaToPv.SetProductionVertex(kfPv); + kfCharmToPv.SetProductionVertex(kfPv); + kfKaFromCharmToPv.SetProductionVertex(kfPv); + + //---------------------calculate physical parameters of OmegaKa candidate---------------------- + + // transport OmegaKa daughters to decay vertex (secondary vertex) + float secondaryVertex[3] = {0.}; + secondaryVertex[0] = kfOmegaKa.GetX(); + secondaryVertex[1] = kfOmegaKa.GetY(); + secondaryVertex[2] = kfOmegaKa.GetZ(); + kfKaFromCharm.TransportToPoint(secondaryVertex); + kfOmega.TransportToPoint(secondaryVertex); + + // get impact parameters of OmegaKa daughters + float impactParameterKaFromCharmXY = 0., errImpactParameterKaFromCharmXY = 0.; + float impactParameterOmegaXY = 0., errImpactParameterOmegaXY = 0.; + kfKaFromCharm.GetDistanceFromVertexXY(kfPv, impactParameterKaFromCharmXY, errImpactParameterKaFromCharmXY); + kfOmega.GetDistanceFromVertexXY(kfPv, impactParameterOmegaXY, errImpactParameterOmegaXY); + + // calculate cosine of pointing angle + float const cosPaV0ToPv = cpaFromKF(kfV0, kfPv); + float const cosPaCascToPv = cpaFromKF(kfOmega, kfPv); + float const cosPaOmegaKaToPv = cpaFromKF(kfOmegaKa, kfPv); + float const cosPaXYV0ToPv = cpaXYFromKF(kfV0, kfPv); + float const cosPaXYCascToPv = cpaXYFromKF(kfOmega, kfPv); + float const cosPaXYOmegaKaToPv = cpaXYFromKF(kfOmegaKa, kfPv); + float const cosPaV0ToCasc = cpaFromKF(kfV0, kfOmega); + float const cosPaCascToOmegaKa = cpaFromKF(kfOmega, kfOmegaKa); + float const cosPaXYV0ToCasc = cpaXYFromKF(kfV0, kfOmega); + float const cosPaXYCascToOmegaKa = cpaXYFromKF(kfOmega, kfOmegaKa); + + // Get Chi2Geo/NDF + float const chi2GeoV0 = kfV0.GetChi2() / kfV0.GetNDF(); + float const chi2GeoCasc = kfOmega.GetChi2() / kfOmega.GetNDF(); + float const chi2GeoOmegaKa = kfOmegaKa.GetChi2() / kfOmegaKa.GetNDF(); + + // Get Chi2Topo/NDF + float const chi2NdfTopoV0ToCasc = kfV0ToOmega.GetChi2() / kfV0ToOmega.GetNDF(); + float const chi2NdfTopoKaToCasc = kfKaToOmega.GetChi2() / kfKaToOmega.GetNDF(); + float const chi2NdfTopoKaFromOmegaKaToOmegaKa = kfKaFromCharmToOmegaKa.GetChi2() / kfKaFromCharmToOmegaKa.GetNDF(); + float const chi2NdfTopoCascToOmegaKa = kfOmegaToOmegaKa.GetChi2() / kfOmegaToOmegaKa.GetNDF(); + float const chi2NdfTopoV0ToPv = kfV0ToPv.GetChi2() / kfV0ToPv.GetNDF(); + float const chi2NdfTopoCascToPv = kfOmegaToPv.GetChi2() / kfOmegaToPv.GetNDF(); + float const chi2NdfTopoOmegaKaToPv = kfCharmToPv.GetChi2() / kfCharmToPv.GetNDF(); + float const chi2NdfTopoKaFromOmegaKaToPv = kfKaFromCharmToPv.GetChi2() / kfKaFromCharmToPv.GetNDF(); + + // Get MassChi2/NDF + auto v0Chi2OverNdfm = kfV0MassConstrained.GetChi2() / kfV0MassConstrained.GetNDF(); + auto cascChi2OverNdfm = kfOmegaMassConstrained.GetChi2() / kfOmegaMassConstrained.GetNDF(); + + // KF ldl + float const ldlV0 = ldlFromKF(kfV0, kfPv); + float const ldlCasc = ldlFromKF(kfOmega, kfPv); + float const ldlOmegaKa = ldlFromKF(kfOmegaKa, kfPv); + + // KF decay length + float decayLxyLam, errDecayLxyLam; + kfV0ToOmega.GetDecayLengthXY(decayLxyLam, errDecayLxyLam); + float decayLxyCasc, errDecayLxyCasc; + kfOmegaToOmegaKa.GetDecayLengthXY(decayLxyCasc, errDecayLxyCasc); + float decayLxyOmegaKa, errDecayLxyOmegaKa; + kfCharmToPv.GetDecayLengthXY(decayLxyOmegaKa, errDecayLxyOmegaKa); + + // KF pT + float const ptOmegaKa = kfOmegaKa.GetPt(); + float const ptKaFromCharm = kfKaFromCharm.GetPt(); + float const ptOmega = kfOmega.GetPt(); + + // KF cosThetaStar + float const cosThetaStarKaFromOmegac = cosThetaStarFromKF(0, 4332, 321, 3334, kfKaFromCharmToOmegaKa, kfOmegaToOmegaKa); + float const cosThetaStarKaFromXic = cosThetaStarFromKF(0, 4132, 321, 3334, kfKaFromCharmToOmegaKa, kfOmegaToOmegaKa); + + // KF ct + float const ctV0 = kfV0ToOmega.GetLifeTime(); + float const ctCasc = kfOmegaToOmegaKa.GetLifeTime(); + float const ctOmegaKa = kfCharmToPv.GetLifeTime(); + + hCandidateCounter->Fill(3); + + // fill full kf table + kfCandidateOmegaKaData(collision.globalIndex(), + collision.posX(), collision.posY(), collision.posZ(), // PV Coord + kfPv.GetX(), kfPv.GetY(), kfPv.GetZ(), // PV KF + vertexV0[0], vertexV0[1], vertexV0[2], // V0 Vtx from LF-table + pVecV0[0], pVecV0[1], pVecV0[2], // V0 P from LF-table + vertexCasc[0], vertexCasc[1], vertexCasc[2], // Casc Vtx from LF-table + pVecCasc[0], pVecCasc[1], pVecCasc[2], // Casc P from LF-table + kfV0.GetX(), kfV0.GetY(), kfV0.GetZ(), // V0 Vtx KF + kfV0.GetPx(), kfV0.GetPy(), kfV0.GetPz(), // V0 P KF + kfOmega.GetX(), kfOmega.GetY(), kfOmega.GetZ(), // Omega Vtx KF + kfOmega.GetPx(), kfOmega.GetPx(), kfOmega.GetPx(), // Omega Vtx KF + kfOmegaKa.GetX(), kfOmegaKa.GetY(), kfOmegaKa.GetZ(), // OmegaKa Vtx KF (SecondaryVertex) + kfOmegaKa.GetPx(), kfOmegaKa.GetPx(), kfOmegaKa.GetPx(), // OmegaKa P KF + signOmega, // Check Omega sign + kfPrFromV0.GetEta(), kfPiFromV0.GetEta(), kfKaFromOmega.GetEta(), kfKaFromCharm.GetEta(), kfV0.GetEta(), kfOmega.GetEta(), kfOmegaKa.GetEta(), kfOmegaKa.GetRapidity(), // Eta of daughters and mothers. Rapidity of OmegaKa + impactParameterKaFromCharmXY, errImpactParameterKaFromCharmXY, impactParameterOmegaXY, errImpactParameterOmegaXY, // DCAXY of KaFromCharm and Omega + kfPrToV0.GetDistanceFromParticle(kfPiToV0), kfV0ToOmega.GetDistanceFromParticle(kfKaToOmega), kfOmegaToOmegaKa.GetDistanceFromParticle(kfKaFromCharmToOmegaKa), // DCA of daughters + cosPaV0ToPv, cosPaCascToPv, cosPaOmegaKaToPv, cosPaXYV0ToPv, cosPaXYCascToPv, cosPaXYOmegaKaToPv, cosPaV0ToCasc, cosPaCascToOmegaKa, cosPaXYV0ToCasc, cosPaXYCascToOmegaKa, // CosPA of PV and mothers + chi2GeoV0, chi2GeoCasc, chi2GeoOmegaKa, // Chi2Geo/NDF + v0Chi2OverNdfm, cascChi2OverNdfm, // Chi2Mass/NDF + chi2NdfTopoV0ToCasc, chi2NdfTopoKaToCasc, chi2NdfTopoKaFromOmegaKaToOmegaKa, chi2NdfTopoCascToOmegaKa, chi2NdfTopoV0ToPv, chi2NdfTopoCascToPv, chi2NdfTopoKaFromOmegaKaToPv, chi2NdfTopoOmegaKaToPv, // Chi2Topo/NDF + ldlV0, ldlCasc, ldlOmegaKa, // ldl + decayLxyLam, decayLxyCasc, decayLxyOmegaKa, // DecaylengthXY + massLam, sigLam, massCasc, sigCasc, massCascrej, sigCascrej, massOmegaKa, sigOmegaKa, // massKF and masserror + ptOmegaKa, ptKaFromCharm, ptOmega, // pT + cosThetaStarKaFromOmegac, cosThetaStarKaFromXic, ctV0, ctCasc, ctOmegaKa, // cosThetaStar & ct + cascAodElement.v0Id(), casc.posTrackId(), casc.negTrackId(), casc.cascadeId(), casc.bachelorId(), trackKaFromCharm.globalIndex()); + } + } /// @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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + 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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + 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, + void processNoCentOmegacToOmegaPiWithKFParticle(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runKfOmegac0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentOmegacToOmegaPiWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega pi decay channel using KFParticle", false); + + void processNoCentOmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runOmegac0Xic0ToOmegaKaCreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentOmegac0Xic0ToOmegaKaCreatorWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega ka decay channel using KFParticle", false); + + void processNoCentXicToXiPiWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, MyKfCascTable const& cascades, KFCascadesLinked const& cascadeLinks, aod::HfCascLf2Prongs const& candidates) { - runKfOmegac0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + runKfXic0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); } - PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processOmegacToOmegaPiWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega pi decay channel using KFParticle", false); + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentXicToXiPiWithKFParticle, "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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + 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); @@ -1036,33 +2081,72 @@ struct HfCandidateCreatorXic0Omegac0 { 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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + 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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + 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 processCentFT0COmegacToOmegaPiWithKFParticle(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runKfOmegac0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0COmegacToOmegaPiWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega pi decay channel using KFParticle", false); + + void processCentFT0COmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runOmegac0Xic0ToOmegaKaCreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0COmegac0Xic0ToOmegaKaCreatorWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega ka decay channel using KFParticle", false); + + void processCentFT0CXicToXiPiWithKFParticle(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runKfXic0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0CXicToXiPiWithKFParticle, "Run candidate creator w FT0C centrality selections for Xic0 To Xi pi decay channel using KFParticle", 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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + 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); @@ -1070,33 +2154,72 @@ struct HfCandidateCreatorXic0Omegac0 { 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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + 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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + 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 processCentFT0MOmegacToOmegaPiWithKFParticle(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runKfOmegac0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaPi, hFitterStatusToOmegaPi, hCandidateCounterToOmegaPi, hCascadesCounterToOmegaPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MOmegacToOmegaPiWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega pi decay channel using KFParticle", false); + + void processCentFT0MOmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runOmegac0Xic0ToOmegaKaCreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MOmegac0Xic0ToOmegaKaCreatorWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega ka decay channel using KFParticle", false); + + void processCentFT0MXicToXiPiWithKFParticle(soa::Join const& collisions, + aod::BCsWithTimestamps const& bcWithTimeStamps, + MyKfTracksIU const& tracksIU, + MyKfTracks const& tracks, + MyKfCascTable const& cascades, + KFCascadesLinked const& cascadeLinks, + aod::HfCascLf2Prongs const& candidates) + { + runKfXic0CreatorWithKFParticle(collisions, bcWithTimeStamps, tracksIU, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToXiPi, hFitterStatusToXiPi, hCandidateCounterToXiPi, hCascadesCounterToXiPi); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MXicToXiPiWithKFParticle, "Run candidate creator w FT0M centrality selections for Xic0 To Xi pi decay channel using KFParticle", 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, tracks, cascades, cascadeLinks, candidates, hInvMassCharmBaryonToOmegaK, hFitterStatusToOmegaK, hCandidateCounterToOmegaK, hCascadesCounterToOmegaK); + 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); @@ -1114,10 +2237,12 @@ struct HfCandidateCreatorXic0Omegac0 { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -1131,10 +2256,12 @@ struct HfCandidateCreatorXic0Omegac0 { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -1148,10 +2275,12 @@ struct HfCandidateCreatorXic0Omegac0 { /// bitmask with event. selection info float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); - + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz /// monitor the satisfied event selections - hfEvSel.fillHistograms(collision, rejectionMask, centrality); + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); } /// end loop over collisions } @@ -1171,18 +2300,22 @@ struct HfCandidateCreatorXic0Omegac0Mc { Produces rowMCMatchGenToOmegaK; // Configuration - o2::framework::Configurable rejectBackground{"rejectBackground", true, "Reject particles from background events"}; + 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; - Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring - using BCsInfo = soa::Join; std::shared_ptr hGenCharmBaryonPtRapidityTightXicToXiPi, hGenCharmBaryonPtRapidityLooseXicToXiPi, hGenCharmBaryonPtRapidityTightOmegacToXiPi, hGenCharmBaryonPtRapidityLooseOmegacToXiPi, hGenCharmBaryonPtRapidityTightOmegacToOmegaPi, hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi, hGenCharmBaryonPtRapidityTightOmegacToOmegaK, hGenCharmBaryonPtRapidityLooseOmegacToOmegaK; @@ -1191,7 +2324,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { // inspect for which zPvPosMax cut was set for reconstructed void init(InitContext& initContext) { - std::array procCollisionsXicToXiPi{doprocessMcXicToXiPi, doprocessMcXicToXiPiFT0m, doprocessMcXicToXiPiFT0c}; + std::array procCollisionsXicToXiPi{doprocessMcXicToXiPi, doprocessMcXicToXiPiFT0m, doprocessMcXicToXiPiFT0c, doprocessMcXicToXiPiKf, doprocessMcXicToXiPiKfQa}; 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."); } @@ -1210,12 +2343,12 @@ struct HfCandidateCreatorXic0Omegac0Mc { 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); + if (device.name == "hf-candidate-creator-xic0-omegac0") { + // init HF event selection helper + hfEvSelMc.init(device, registry); 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 @@ -1228,14 +2361,149 @@ struct HfCandidateCreatorXic0Omegac0Mc { 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}}}); + + // QA + if (doprocessMcXicToXiPiKfQa) { + AxisSpec const axisPt{20, 0., 20.}; + AxisSpec const axisDelta{1000, -0.5, 0.5}; + AxisSpec const axisPull{2000, -10., 10.}; + AxisSpec const axisPtRes{400, -0.2, 0.2}; + // mass over pt + registry.add("hV0MassPullVsPt", "m_{PULL}(V0) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXiMassPullVsPt", "m_{PULL}(#Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXic0MassPullVsPt", "m_{PULL}(#Xic0) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + // delta + registry.add("hV0DauPosXDelta", "x^{p} - x^{MC}", kTH1D, {axisDelta}); + registry.add("hV0DauPosYDelta", "y^{p} - y^{MC}", kTH1D, {axisDelta}); + registry.add("hV0DauPosZDelta", "z^{p} - z^{MC}", kTH1D, {axisDelta}); + registry.add("hV0DauNegXDelta", "x^{#pi^{-}} - x^{MC}", kTH1D, {axisDelta}); + registry.add("hV0DauNegYDelta", "y^{#pi^{-}} - y^{MC}", kTH1D, {axisDelta}); + registry.add("hV0DauNegZDelta", "z^{#pi^{-}} - z^{MC}", kTH1D, {axisDelta}); + registry.add("hV0XDelta", "x^{#Lambda} - x^{MC}", kTH1D, {axisDelta}); + registry.add("hV0YDelta", "y^{#Lambda} - y^{MC}", kTH1D, {axisDelta}); + registry.add("hV0ZDelta", "z^{#Lambda} - z^{MC}", kTH1D, {axisDelta}); + + registry.add("hXiBachelorXDelta", "x^{#pi^{-} from #Xi^{-}} - x^{MC}", kTH1D, {axisDelta}); + registry.add("hXiBachelorYDelta", "y^{#pi^{-} from #Xi^{-}} - y^{MC}", kTH1D, {axisDelta}); + registry.add("hXiBachelorZDelta", "z^{#pi^{-} from #Xi^{-}} - z^{MC}", kTH1D, {axisDelta}); + + registry.add("hXiXDelta", "x^{#Xi^{-}} - x^{MC}", kTH1D, {axisDelta}); + registry.add("hXiYDelta", "y^{#Xi^{-}} - y^{MC}", kTH1D, {axisDelta}); + registry.add("hXiZDelta", "z^{#Xi^{-}} - z^{MC}", kTH1D, {axisDelta}); + + registry.add("hXic0BachelorXDelta", "x^{#pi^{+} from #Xi_{c}^{0}} - x^{MC}", kTH1D, {axisDelta}); + registry.add("hXic0BachelorYDelta", "y^{#pi^{+} from #Xi_{c}^{0}} - y^{MC}", kTH1D, {axisDelta}); + registry.add("hXic0BachelorZDelta", "z^{#pi^{+} from #Xi_{c}^{0}} - z^{MC}", kTH1D, {axisDelta}); + + registry.add("hXic0XDelta", "x^{#Xi_(c)^(0)} - x^{MC}", kTH1D, {axisDelta}); + registry.add("hXic0YDelta", "y^{#Xi_(c)^(0)} - y^{MC}", kTH1D, {axisDelta}); + registry.add("hXic0ZDelta", "z^{#Xi_(c)^(0)} - z^{MC}", kTH1D, {axisDelta}); + // delta over pt + registry.add("hV0DauPosXDeltaVsPt", "#Delta_{x}(p) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hV0DauPosYDeltaVsPt", "#Delta_{y}(p) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hV0DauPosZDeltaVsPt", "#Delta_{z}(p) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hV0DauNegXDeltaVsPt", "#Delta_{x}(#pi) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hV0DauNegYDeltaVsPt", "#Delta_{y}(#pi) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hV0DauNegZDeltaVsPt", "#Delta_{z}(#pi) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hV0XDeltaVsPt", "#Delta_{x}(#Lambda) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hV0YDeltaVsPt", "#Delta_{y}(#Lambda) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hV0ZDeltaVsPt", "#Delta_{z}(#Lambda) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + + registry.add("hXiBachelorXDeltaVsPt", "#Delta_{x}(#pi^{-} from #Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hXiBachelorYDeltaVsPt", "#Delta_{y}(#pi^{-} from #Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hXiBachelorZDeltaVsPt", "#Delta_{z}(#pi^{-} from #Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + + registry.add("hXiXDeltaVsPt", "#Delta_{x}(#Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hXiYDeltaVsPt", "#Delta_{y}(#Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hXiZDeltaVsPt", "#Delta_{z}(#Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + + registry.add("hXic0BachelorXDeltaVsPt", "#Delta_{x}(#pi^{+} from #Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hXic0BachelorYDeltaVsPt", "#Delta_{y}(#pi^{+} from #Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hXic0BachelorZDeltaVsPt", "#Delta_{z}(#pi^{+} from #Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + + registry.add("hXic0XDeltaVsPt", "#Delta_{x}(#Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hXic0YDeltaVsPt", "#Delta_{y}(#Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + registry.add("hXic0ZDeltaVsPt", "#Delta_{z}(#Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisDelta}); + + // pull + registry.add("hV0DauPosXPull", "x^{PULL}", kTH1D, {axisPull}); + registry.add("hV0DauPosYPull", "y^{PULL}", kTH1D, {axisPull}); + registry.add("hV0DauPosZPull", "z^{PULL}", kTH1D, {axisPull}); + registry.add("hV0DauNegXPull", "x^{PULL}", kTH1D, {axisPull}); + registry.add("hV0DauNegYPull", "y^{PULL}", kTH1D, {axisPull}); + registry.add("hV0DauNegZPull", "z^{PULL}", kTH1D, {axisPull}); + registry.add("hV0XPull", "x^{PULL}(#Lambda)", kTH1D, {axisPull}); + registry.add("hV0YPull", "y^{PULL}(#Lambda)", kTH1D, {axisPull}); + registry.add("hV0ZPull", "z^{PULL}(#Lambda)", kTH1D, {axisPull}); + + registry.add("hXiBachelorXPull", "x^{PULL}", kTH1D, {axisPull}); + registry.add("hXiBachelorYPull", "y^{PULL}", kTH1D, {axisPull}); + registry.add("hXiBachelorZPull", "z^{PULL}", kTH1D, {axisPull}); + + registry.add("hXiXPull", "x^{PULL}(#Xi^{-})", kTH1D, {axisPull}); + registry.add("hXiYPull", "y^{PULL}(#Xi^{-})", kTH1D, {axisPull}); + registry.add("hXiZPull", "z^{PULL}(#Xi^{-})", kTH1D, {axisPull}); + + registry.add("hXic0BachelorXPull", "x^{PULL}", kTH1D, {axisPull}); + registry.add("hXic0BachelorYPull", "y^{PULL}", kTH1D, {axisPull}); + registry.add("hXic0BachelorZPull", "z^{PULL}", kTH1D, {axisPull}); + + registry.add("hXic0XPull", "x^{PULL}(#Xi_{c}^{0})", kTH1D, {axisPull}); + registry.add("hXic0YPull", "y^{PULL}(#Xi_{c}^{0})", kTH1D, {axisPull}); + registry.add("hXic0ZPull", "z^{PULL}(#Xi_{c}^{0})", kTH1D, {axisPull}); + // pull over pt + registry.add("hV0DauPosXPullVsPt", "x_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hV0DauPosYPullVsPt", "y_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hV0DauPosZPullVsPt", "z_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hV0DauNegXPullVsPt", "x_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hV0DauNegYPullVsPt", "y_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hV0DauNegZPullVsPt", "z_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hV0XPullVsPt", "x_{PULL}(#Lambda) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hV0YPullVsPt", "y_{PULL}(#Lambda) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hV0ZPullVsPt", "z_{PULL}(#Lambda) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + + registry.add("hXiBachelorXPullVsPt", "x_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXiBachelorYPullVsPt", "y_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXiBachelorZPullVsPt", "z_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + + registry.add("hXiXPullVsPt", "x_{PULL}(#Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXiYPullVsPt", "y_{PULL}(#Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXiZPullVsPt", "z_{PULL}(#Xi^{-}) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + + registry.add("hXic0BachelorXPullVsPt", "x_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXic0BachelorYPullVsPt", "y_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXic0BachelorZPullVsPt", "z_{PULL} vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + + registry.add("hXic0XPullVsPt", "x_{PULL}(#Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXic0YPullVsPt", "y_{PULL}(#Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + registry.add("hXic0ZPullVsPt", "z_{PULL}(#Xi_{c}^{0}) vs. p_{T}", HistType::kTH2D, {axisPt, axisPull}); + + // Defaut delta + registry.add("hLambdaXDelta", "x^{#Lambda} - x^{MC}(Default)", kTH1D, {axisDelta}); + registry.add("hLambdaYDelta", "y^{#Lambda} - y^{MC}(Default)", kTH1D, {axisDelta}); + registry.add("hLambdaZDelta", "z^{#Lambda} - z^{MC}(Default)", kTH1D, {axisDelta}); + + registry.add("hCascXDelta", "x^{#Xi^{-}} - x^{MC}(Default)", kTH1D, {axisDelta}); + registry.add("hCascYDelta", "y^{#Xi^{-}} - y^{MC}(Default)", kTH1D, {axisDelta}); + registry.add("hCascZDelta", "z^{#Xi^{-}} - z^{MC}(Default)", kTH1D, {axisDelta}); + + // Pt Resolution + registry.add("hV0DauPosPtRes", "Pt Resolution (p)", kTH1D, {axisPtRes}); + registry.add("hV0DauNegPtRes", "Pt Resolution (#pi^{-} from #Lambda)", kTH1D, {axisPtRes}); + registry.add("hV0PtRes", "Pt Resolution (V0)", kTH1D, {axisPtRes}); + registry.add("hXiBachelorPtRes", "Pt Resolution (#pi^{-} from #Xi^{-})", kTH1D, {axisPtRes}); + registry.add("hXiPtRes", "Pt Resolution (#Xi^{-})", kTH1D, {axisPtRes}); + registry.add("hXic0BachelorPtRes", "Pt Resolution (#pi^{+} from #Xi_{c}^{0})", kTH1D, {axisPtRes}); + registry.add("hXic0PtRes", "Pt Resolution (#Xi_{c}^{0})", kTH1D, {axisPtRes}); + } } - template + template void runXic0Omegac0Mc(TMyRecoCand const& candidates, - aod::TracksWMc const&, + MyTracksWMc const&, aod::McParticles const& mcParticles, Colls const& collsWithMcLabels, - aod::McCollisions const& mcCollisions, + McCollisions const& mcCollisions, BCsInfo const&) { float ptCharmBaryonGen = -999.; @@ -1247,40 +2515,31 @@ struct HfCandidateCreatorXic0Omegac0Mc { int8_t signV0 = -9; int8_t flag = 0; int8_t origin = 0; // to be used for prompt/non prompt - int8_t debug = 0; + 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; - int pdgCodeOmegac0 = Pdg::kOmegaC0; // 4332 - int pdgCodeXic0 = Pdg::kXiC0; // 4132 - int pdgCodeXiMinus = kXiMinus; // 3312 - int pdgCodeOmegaMinus = kOmegaMinus; // 3334 - int pdgCodeLambda = kLambda0; // 3122 - int pdgCodePiPlus = kPiPlus; // 211 - int pdgCodePiMinus = kPiMinus; // -211 - int pdgCodeProton = kProton; // 2212 - int pdgCodeKaonPlus = kKPlus; // 321 - int pdgCodeKaonMinus = kKMinus; // -321 - // Match reconstructed candidates. for (const auto& candidate : candidates) { flag = 0; origin = RecoDecay::OriginType::None; - debug = 0; + 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()}; + 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) { @@ -1302,26 +2561,25 @@ struct HfCandidateCreatorXic0Omegac0Mc { continue; } } - // Xic0 -> xi pi matching - if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + if constexpr (DecayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { // Xic → pi pi pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgCodeXic0, std::array{pdgCodePiPlus, pdgCodePiMinus, pdgCodeProton, pdgCodePiMinus}, true, &sign, 3); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kXiC0, std::array{+kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 3); indexRecCharmBaryon = indexRec; if (indexRec == -1) { - debug = 1; + debug = McMatchFlag::CharmbaryonUnmatched; } if (indexRec > -1) { // Xi- → pi pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, pdgCodeXiMinus, std::array{pdgCodePiMinus, pdgCodeProton, pdgCodePiMinus}, true, &signCasc, 2); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &signCasc, 2); if (indexRec == -1) { - debug = 2; + debug = McMatchFlag::CascUnmatched; } if (indexRec > -1) { // Lambda → p pi - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true, &signV0, 1); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); if (indexRec == -1) { - debug = 3; + debug = McMatchFlag::V0Unmatched; } if (indexRec > -1) { flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi); @@ -1340,27 +2598,27 @@ struct HfCandidateCreatorXic0Omegac0Mc { } else { rowMCMatchRecXicToXiPi(flag, debug, origin, collisionMatched, -1.f, 0); } - if (debug == 2 || debug == 3) { + 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 + } 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, pdgCodeOmegac0, std::array{pdgCodePiPlus, pdgCodePiMinus, pdgCodeProton, pdgCodePiMinus}, true, &sign, 3); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kOmegaC0, std::array{+kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 3); indexRecCharmBaryon = indexRec; if (indexRec == -1) { - debug = 1; + debug = McMatchFlag::CharmbaryonUnmatched; } if (indexRec > -1) { // Xi- → pi pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, pdgCodeXiMinus, std::array{pdgCodePiMinus, pdgCodeProton, pdgCodePiMinus}, true, &signCasc, 2); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &signCasc, 2); if (indexRec == -1) { - debug = 2; + debug = McMatchFlag::CascUnmatched; } if (indexRec > -1) { // Lambda → p pi - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true, &signV0, 1); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); if (indexRec == -1) { - debug = 3; + debug = McMatchFlag::V0Unmatched; } if (indexRec > -1) { flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi); @@ -1379,31 +2637,64 @@ struct HfCandidateCreatorXic0Omegac0Mc { } else { rowMCMatchRecOmegacToXiPi(flag, debug, origin, collisionMatched, -1.f, 0); } - if (debug == 2 || debug == 3) { + 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 - // Omegac → pi K pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, pdgCodeOmegac0, std::array{pdgCodePiPlus, pdgCodeKaonMinus, pdgCodeProton, pdgCodePiMinus}, true, &sign, 3); - indexRecCharmBaryon = indexRec; - if (indexRec == -1) { - debug = 1; - } - if (indexRec > -1) { - // Omega- → K pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, pdgCodeOmegaMinus, std::array{pdgCodeKaonMinus, pdgCodeProton, pdgCodePiMinus}, true, &signCasc, 2); + } 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 = 2; + debug = McMatchFlag::CharmbaryonUnmatched; } if (indexRec > -1) { - // Lambda → p pi - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true, &signV0, 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 = 3; + debug = McMatchFlag::CascUnmatched; } if (indexRec > -1) { - flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi); - collisionMatched = candidate.template collision_as().mcCollisionId() == mcParticles.iteratorAt(indexRecCharmBaryon).mcCollisionId(); + // 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(); + } } } } @@ -1418,27 +2709,27 @@ struct HfCandidateCreatorXic0Omegac0Mc { } else { rowMCMatchRecToOmegaPi(flag, debug, origin, collisionMatched, -1.f, 0); } - if (debug == 2 || debug == 3) { + 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 + } 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, pdgCodeOmegac0, std::array{pdgCodeKaonPlus, pdgCodeKaonMinus, pdgCodeProton, pdgCodePiMinus}, true, &sign, 3); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kOmegaC0, std::array{+kKPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3); indexRecCharmBaryon = indexRec; if (indexRec == -1) { - debug = 1; + debug = McMatchFlag::CharmbaryonUnmatched; } if (indexRec > -1) { // Omega- → K pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, pdgCodeOmegaMinus, std::array{pdgCodeKaonMinus, pdgCodeProton, pdgCodePiMinus}, true, &signCasc, 2); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2); if (indexRec == -1) { - debug = 2; + debug = McMatchFlag::CascUnmatched; } if (indexRec > -1) { // Lambda → p pi - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true, &signV0, 1); + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); if (indexRec == -1) { - debug = 3; + debug = McMatchFlag::V0Unmatched; } if (indexRec > -1) { flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK); @@ -1457,7 +2748,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { } else { rowMCMatchRecToOmegaK(flag, debug, origin, collisionMatched, -1.f, 0); } - if (debug == 2 || debug == 3) { + 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"); } } @@ -1469,28 +2760,32 @@ struct HfCandidateCreatorXic0Omegac0Mc { 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) { + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + int nSplitColl = 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) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + nSplitColl = collSlice.size(); + } 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) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + nSplitColl = collSlice.size(); + } else if constexpr (CentEstimator == CentralityEstimator::None) { const auto collSlice = collsWithMcLabels.sliceBy(colPerMcCollision, mcCollision.globalIndex()); - rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + nSplitColl = collSlice.size(); } - hfEvSelMc.fillHistograms(rejectionMask); + 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) { - if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + 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) { + } 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) { + } 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) { + } else if constexpr (DecayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK) { rowMCMatchGenToOmegaK(0, 0, 0, 0, -999., -999., RecoDecay::OriginType::None, -1); } } @@ -1508,40 +2803,42 @@ struct HfCandidateCreatorXic0Omegac0Mc { debugGenLambda = 0; origin = RecoDecay::OriginType::None; std::vector idxBhadMothers{}; + float const kRapidityCutTight = 0.5; + float const kRapidityCutLoose = 0.8; // Reject particles from background events if (particle.fromBackgroundEvent() && rejectBackground) { - if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + 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) { + } 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) { + } 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) { + } 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) { + if constexpr (DecayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { // Xic → Xi pi - if (RecoDecay::isMatchedMCGen(mcParticles, particle, pdgCodeXic0, std::array{pdgCodeXiMinus, pdgCodePiPlus}, true, &sign)) { + 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.daughters_as()) { - if (std::abs(daughterCharm.pdgCode()) != pdgCodeXiMinus) { + for (const auto& daughterCharm : particle.template daughters_as()) { + if (std::abs(daughterCharm.pdgCode()) != +kXiMinus) { continue; } // Xi -> Lambda pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, pdgCodeXiMinus, std::array{pdgCodeLambda, pdgCodePiMinus}, true)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, +kXiMinus, std::array{+kLambda0, +kPiMinus}, true)) { debugGenCasc = 1; - for (const auto& daughterCascade : daughterCharm.daughters_as()) { - if (std::abs(daughterCascade.pdgCode()) != pdgCodeLambda) { + for (const auto& daughterCascade : daughterCharm.template daughters_as()) { + if (std::abs(daughterCascade.pdgCode()) != +kLambda0) { continue; } // Lambda -> p pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { debugGenLambda = 1; flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi); } @@ -1552,10 +2849,10 @@ struct HfCandidateCreatorXic0Omegac0Mc { // 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) { + if (std::abs(rapidityCharmBaryonGen) < kRapidityCutTight) { hGenCharmBaryonPtRapidityTightXicToXiPi->SetBinContent(hGenCharmBaryonPtRapidityTightXicToXiPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityTightXicToXiPi->GetBinContent(hGenCharmBaryonPtRapidityTightXicToXiPi->FindBin(ptCharmBaryonGen)) + 1); } - if (std::abs(rapidityCharmBaryonGen) < 0.8) { + if (std::abs(rapidityCharmBaryonGen) < kRapidityCutLoose) { hGenCharmBaryonPtRapidityLooseXicToXiPi->SetBinContent(hGenCharmBaryonPtRapidityLooseXicToXiPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityLooseXicToXiPi->GetBinContent(hGenCharmBaryonPtRapidityLooseXicToXiPi->FindBin(ptCharmBaryonGen)) + 1); } } @@ -1565,25 +2862,25 @@ struct HfCandidateCreatorXic0Omegac0Mc { rowMCMatchGenXicToXiPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); } - } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi) { + } else if constexpr (DecayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi) { // Omegac → Xi pi - if (RecoDecay::isMatchedMCGen(mcParticles, particle, pdgCodeOmegac0, std::array{pdgCodeXiMinus, pdgCodePiPlus}, true, &sign)) { + 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.daughters_as()) { - if (std::abs(daughterCharm.pdgCode()) != pdgCodeXiMinus) { + for (const auto& daughterCharm : particle.template daughters_as()) { + if (std::abs(daughterCharm.pdgCode()) != +kXiMinus) { continue; } // Xi -> Lambda pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, pdgCodeXiMinus, std::array{pdgCodeLambda, pdgCodePiMinus}, true)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, +kXiMinus, std::array{+kLambda0, +kPiMinus}, true)) { debugGenCasc = 1; - for (const auto& daughterCascade : daughterCharm.daughters_as()) { - if (std::abs(daughterCascade.pdgCode()) != pdgCodeLambda) { + for (const auto& daughterCascade : daughterCharm.template daughters_as()) { + if (std::abs(daughterCascade.pdgCode()) != +kLambda0) { continue; } // Lambda -> p pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { debugGenLambda = 1; flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToXiPi); } @@ -1594,10 +2891,10 @@ struct HfCandidateCreatorXic0Omegac0Mc { // 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) { + if (std::abs(rapidityCharmBaryonGen) < kRapidityCutTight) { hGenCharmBaryonPtRapidityTightOmegacToXiPi->SetBinContent(hGenCharmBaryonPtRapidityTightOmegacToXiPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityTightOmegacToXiPi->GetBinContent(hGenCharmBaryonPtRapidityTightOmegacToXiPi->FindBin(ptCharmBaryonGen)) + 1); } - if (std::abs(rapidityCharmBaryonGen) < 0.8) { + if (std::abs(rapidityCharmBaryonGen) < kRapidityCutLoose) { hGenCharmBaryonPtRapidityLooseOmegacToXiPi->SetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToXiPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityLooseOmegacToXiPi->GetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToXiPi->FindBin(ptCharmBaryonGen)) + 1); } } @@ -1607,25 +2904,25 @@ struct HfCandidateCreatorXic0Omegac0Mc { rowMCMatchGenOmegacToXiPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); } - } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi) { + } else if constexpr (DecayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi) { // Omegac → Omega pi - if (RecoDecay::isMatchedMCGen(mcParticles, particle, pdgCodeOmegac0, std::array{pdgCodeOmegaMinus, pdgCodePiPlus}, true, &sign)) { + 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.daughters_as()) { - if (std::abs(daughterCharm.pdgCode()) != pdgCodeOmegaMinus) { + for (const auto& daughterCharm : particle.template daughters_as()) { + if (std::abs(daughterCharm.pdgCode()) != +kOmegaMinus) { continue; } // Omega -> Lambda K - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, pdgCodeOmegaMinus, std::array{pdgCodeLambda, pdgCodeKaonMinus}, true)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, +kOmegaMinus, std::array{+kLambda0, +kKMinus}, true)) { debugGenCasc = 1; - for (const auto& daughterCascade : daughterCharm.daughters_as()) { - if (std::abs(daughterCascade.pdgCode()) != pdgCodeLambda) { + for (const auto& daughterCascade : daughterCharm.template daughters_as()) { + if (std::abs(daughterCascade.pdgCode()) != +kLambda0) { continue; } // Lambda -> p pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { debugGenLambda = 1; flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaPi); } @@ -1636,10 +2933,10 @@ struct HfCandidateCreatorXic0Omegac0Mc { // 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) { + if (std::abs(rapidityCharmBaryonGen) < kRapidityCutTight) { hGenCharmBaryonPtRapidityTightOmegacToOmegaPi->SetBinContent(hGenCharmBaryonPtRapidityTightOmegacToOmegaPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityTightOmegacToOmegaPi->GetBinContent(hGenCharmBaryonPtRapidityTightOmegacToOmegaPi->FindBin(ptCharmBaryonGen)) + 1); } - if (std::abs(rapidityCharmBaryonGen) < 0.8) { + if (std::abs(rapidityCharmBaryonGen) < kRapidityCutLoose) { hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi->SetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi->GetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToOmegaPi->FindBin(ptCharmBaryonGen)) + 1); } } @@ -1649,25 +2946,25 @@ struct HfCandidateCreatorXic0Omegac0Mc { rowMCMatchGenToOmegaPi(flag, debugGenCharmBar, debugGenCasc, debugGenLambda, ptCharmBaryonGen, rapidityCharmBaryonGen, origin, -1); } - } else if constexpr (decayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK) { + } else if constexpr (DecayChannel == aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK) { // Omegac → Omega K - if (RecoDecay::isMatchedMCGen(mcParticles, particle, pdgCodeOmegac0, std::array{pdgCodeOmegaMinus, pdgCodeKaonPlus}, true, &sign)) { + 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.daughters_as()) { - if (std::abs(daughterCharm.pdgCode()) != pdgCodeOmegaMinus) { + for (const auto& daughterCharm : particle.template daughters_as()) { + if (std::abs(daughterCharm.pdgCode()) != +kOmegaMinus) { continue; } // Omega -> Lambda K - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, pdgCodeOmegaMinus, std::array{pdgCodeLambda, pdgCodeKaonMinus}, true)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCharm, +kOmegaMinus, std::array{+kLambda0, +kKMinus}, true)) { debugGenCasc = 1; - for (const auto& daughterCascade : daughterCharm.daughters_as()) { - if (std::abs(daughterCascade.pdgCode()) != pdgCodeLambda) { + for (const auto& daughterCascade : daughterCharm.template daughters_as()) { + if (std::abs(daughterCascade.pdgCode()) != +kLambda0) { continue; } // Lambda -> p pi - if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, pdgCodeLambda, std::array{pdgCodeProton, pdgCodePiMinus}, true)) { + if (RecoDecay::isMatchedMCGen(mcParticles, daughterCascade, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { debugGenLambda = 1; flag = sign * (1 << aod::hf_cand_xic0_omegac0::DecayType::OmegaczeroToOmegaK); } @@ -1678,10 +2975,10 @@ struct HfCandidateCreatorXic0Omegac0Mc { // 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) { + if (std::abs(rapidityCharmBaryonGen) < kRapidityCutTight) { hGenCharmBaryonPtRapidityTightOmegacToOmegaK->SetBinContent(hGenCharmBaryonPtRapidityTightOmegacToOmegaK->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityTightOmegacToOmegaK->GetBinContent(hGenCharmBaryonPtRapidityTightOmegacToOmegaK->FindBin(ptCharmBaryonGen)) + 1); } - if (std::abs(rapidityCharmBaryonGen) < 0.8) { + if (std::abs(rapidityCharmBaryonGen) < kRapidityCutLoose) { hGenCharmBaryonPtRapidityLooseOmegacToOmegaK->SetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToOmegaK->FindBin(ptCharmBaryonGen), hGenCharmBaryonPtRapidityLooseOmegacToOmegaK->GetBinContent(hGenCharmBaryonPtRapidityLooseOmegacToOmegaK->FindBin(ptCharmBaryonGen)) + 1); } } @@ -1692,8 +2989,238 @@ struct HfCandidateCreatorXic0Omegac0Mc { } } } // close loop on MCParticles - } // close loop on MCCollisions - } // close process + } // close loop on MCCollisions + } // close process + + template + void runXic0Omegac0McQa(TMyRecoCand const& candidates, + MyTracksWMc const&, + aod::McParticles const& mcParticles, + BCsInfo const&) + { + int indexRec = -1; + int8_t sign = -9; + int8_t signCasc = -9; + int8_t signV0 = -9; + + for (const auto& candidate : candidates) { + + 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()}; + + auto mcV0DauPos = arrayDaughtersV0[0].mcParticle(); + auto mcV0DauNeg = arrayDaughtersV0[1].mcParticle(); + auto mcXiBachelor = arrayDaughtersCasc[0].mcParticle(); + auto mcXic0Bachelor = arrayDaughters[0].mcParticle(); + + // Xic0 -> xi pi matching + if constexpr (DecayChannel == aod::hf_cand_xic0_omegac0::DecayType::XiczeroToXiPi) { + // Lambda → p pi + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1); + if (indexRec > -1 && signV0 == 1) { + auto mcV0 = mcParticles.rawIteratorAt(indexRec - mcParticles.offset()); + + float const v0MassPull = (candidate.invMassLambda() - MassLambda0) / candidate.invMassV0Err(); + registry.fill(HIST("hV0MassPullVsPt"), candidate.v0Pt(), v0MassPull); + + float const v0DauPosXDelta = candidate.v0DauPosX() - mcV0DauPos.vx(); + float const v0DauPosYDelta = candidate.v0DauPosY() - mcV0DauPos.vy(); + float const v0DauPosZDelta = candidate.v0DauPosZ() - mcV0DauPos.vz(); + float const v0DauPosPt = mcV0DauPos.pt(); + float const v0DauPosXPull = v0DauPosXDelta / candidate.v0DauPosXError(); + float const v0DauPosYPull = v0DauPosYDelta / candidate.v0DauPosYError(); + float const v0DauPosZPull = v0DauPosZDelta / candidate.v0DauPosZError(); + + float const v0DauNegXDelta = candidate.v0DauNegX() - mcV0DauNeg.vx(); + float const v0DauNegYDelta = candidate.v0DauNegY() - mcV0DauNeg.vy(); + float const v0DauNegZDelta = candidate.v0DauNegZ() - mcV0DauNeg.vz(); + float const v0DauNegPt = mcV0DauNeg.pt(); + float const v0DauNegXPull = v0DauNegXDelta / candidate.v0DauNegXError(); + float const v0DauNegYPull = v0DauNegYDelta / candidate.v0DauNegYError(); + float const v0DauNegZPull = v0DauNegZDelta / candidate.v0DauNegZError(); + + float const v0XDelta = candidate.v0VtxX() - mcV0DauNeg.vx(); + float const v0YDelta = candidate.v0VtxY() - mcV0DauNeg.vy(); + float const v0ZDelta = candidate.v0VtxZ() - mcV0DauNeg.vz(); + float const v0Pt = mcV0.pt(); + float const v0XPull = v0XDelta / candidate.v0XError(); + float const v0YPull = v0YDelta / candidate.v0YError(); + float const v0ZPull = v0ZDelta / candidate.v0ZError(); + + float const lambdaXDelta = candidate.v0X() - mcV0DauNeg.vx(); + float const lambdaYDelta = candidate.v0Y() - mcV0DauNeg.vy(); + float const lambdaZDelta = candidate.v0Z() - mcV0DauNeg.vz(); + registry.fill(HIST("hV0DauPosXDelta"), v0DauPosXDelta); + registry.fill(HIST("hV0DauPosYDelta"), v0DauPosYDelta); + registry.fill(HIST("hV0DauPosZDelta"), v0DauPosZDelta); + registry.fill(HIST("hV0DauPosXDeltaVsPt"), v0DauPosPt, v0DauPosXDelta); + registry.fill(HIST("hV0DauPosYDeltaVsPt"), v0DauPosPt, v0DauPosYDelta); + registry.fill(HIST("hV0DauPosZDeltaVsPt"), v0DauPosPt, v0DauPosZDelta); + registry.fill(HIST("hV0DauPosXPull"), v0DauPosXPull); + registry.fill(HIST("hV0DauPosYPull"), v0DauPosYPull); + registry.fill(HIST("hV0DauPosZPull"), v0DauPosZPull); + registry.fill(HIST("hV0DauPosXPullVsPt"), v0DauPosPt, v0DauPosXPull); + registry.fill(HIST("hV0DauPosYPullVsPt"), v0DauPosPt, v0DauPosYPull); + registry.fill(HIST("hV0DauPosZPullVsPt"), v0DauPosPt, v0DauPosZPull); + + registry.fill(HIST("hV0DauNegXDelta"), v0DauNegXDelta); + registry.fill(HIST("hV0DauNegYDelta"), v0DauNegYDelta); + registry.fill(HIST("hV0DauNegZDelta"), v0DauNegZDelta); + registry.fill(HIST("hV0DauNegXDeltaVsPt"), v0DauNegPt, v0DauNegXDelta); + registry.fill(HIST("hV0DauNegYDeltaVsPt"), v0DauNegPt, v0DauNegYDelta); + registry.fill(HIST("hV0DauNegZDeltaVsPt"), v0DauNegPt, v0DauNegZDelta); + registry.fill(HIST("hV0DauNegXPull"), v0DauNegXPull); + registry.fill(HIST("hV0DauNegYPull"), v0DauNegYPull); + registry.fill(HIST("hV0DauNegZPull"), v0DauNegZPull); + registry.fill(HIST("hV0DauNegXPullVsPt"), v0DauNegPt, v0DauNegXPull); + registry.fill(HIST("hV0DauNegYPullVsPt"), v0DauNegPt, v0DauNegYPull); + registry.fill(HIST("hV0DauNegZPullVsPt"), v0DauNegPt, v0DauNegZPull); + + registry.fill(HIST("hV0XDelta"), v0XDelta); + registry.fill(HIST("hV0YDelta"), v0YDelta); + registry.fill(HIST("hV0ZDelta"), v0ZDelta); + registry.fill(HIST("hV0XDeltaVsPt"), v0Pt, v0XDelta); + registry.fill(HIST("hV0YDeltaVsPt"), v0Pt, v0YDelta); + registry.fill(HIST("hV0ZDeltaVsPt"), v0Pt, v0ZDelta); + registry.fill(HIST("hV0XPull"), v0XPull); + registry.fill(HIST("hV0YPull"), v0YPull); + registry.fill(HIST("hV0ZPull"), v0ZPull); + registry.fill(HIST("hV0XPullVsPt"), v0Pt, v0XPull); + registry.fill(HIST("hV0YPullVsPt"), v0Pt, v0YPull); + registry.fill(HIST("hV0ZPullVsPt"), v0Pt, v0ZPull); + + registry.fill(HIST("hLambdaXDelta"), lambdaXDelta); + registry.fill(HIST("hLambdaYDelta"), lambdaYDelta); + registry.fill(HIST("hLambdaZDelta"), lambdaZDelta); + + registry.fill(HIST("hV0DauPosPtRes"), (candidate.v0DauPosPt() - mcV0DauPos.pt()) / candidate.v0DauPosPt()); + registry.fill(HIST("hV0DauNegPtRes"), (candidate.v0DauNegPt() - mcV0DauNeg.pt()) / candidate.v0DauNegPt()); + registry.fill(HIST("hV0PtRes"), (candidate.v0Pt() - mcV0.pt()) / candidate.v0Pt()); + // Xi- → pi pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &signCasc, 2); + if (indexRec > -1 && signCasc == 1) { + // QA + float const xiMassPull = (candidate.invMassCascade() - MassXiMinus) / candidate.invMassXiErr(); + registry.fill(HIST("hXiMassPullVsPt"), candidate.xiPt(), xiMassPull); + + float const xiBachelorXDelta = candidate.xiBachelorX() - mcXiBachelor.vx(); + float const xiBachelorYDelta = candidate.xiBachelorY() - mcXiBachelor.vy(); + float const xiBachelorZDelta = candidate.xiBachelorZ() - mcXiBachelor.vz(); + float const xiBachelorPt = mcXiBachelor.pt(); + float const xiBachelorXPull = xiBachelorXDelta / candidate.xiBachelorXError(); + float const xiBachelorYPull = xiBachelorYDelta / candidate.xiBachelorYError(); + float const xiBachelorZPull = xiBachelorZDelta / candidate.xiBachelorZError(); + + auto mcXi = mcParticles.rawIteratorAt(indexRec - mcParticles.offset()); + + float const xiXDelta = candidate.xiX() - mcXiBachelor.vx(); + float const xiYDelta = candidate.xiY() - mcXiBachelor.vy(); + float const xiZDelta = candidate.xiZ() - mcXiBachelor.vz(); + float const xiPt = mcXi.pt(); + float const xiXPull = xiXDelta / candidate.xiXError(); + float const xiYPull = xiYDelta / candidate.xiYError(); + float const xiZPull = xiZDelta / candidate.xiZError(); + + float const cascXDelta = candidate.xDecayVtxCascade() - mcXiBachelor.vx(); + float const cascYDelta = candidate.yDecayVtxCascade() - mcXiBachelor.vy(); + float const cascZDelta = candidate.zDecayVtxCascade() - mcXiBachelor.vz(); + + registry.fill(HIST("hXiBachelorXDelta"), xiBachelorXDelta); + registry.fill(HIST("hXiBachelorYDelta"), xiBachelorYDelta); + registry.fill(HIST("hXiBachelorZDelta"), xiBachelorZDelta); + registry.fill(HIST("hXiBachelorXDeltaVsPt"), xiBachelorPt, xiBachelorXDelta); + registry.fill(HIST("hXiBachelorYDeltaVsPt"), xiBachelorPt, xiBachelorYDelta); + registry.fill(HIST("hXiBachelorZDeltaVsPt"), xiBachelorPt, xiBachelorZDelta); + registry.fill(HIST("hXiBachelorXPull"), xiBachelorXPull); + registry.fill(HIST("hXiBachelorYPull"), xiBachelorYPull); + registry.fill(HIST("hXiBachelorZPull"), xiBachelorZPull); + registry.fill(HIST("hXiBachelorXPullVsPt"), xiBachelorPt, xiBachelorXPull); + registry.fill(HIST("hXiBachelorYPullVsPt"), xiBachelorPt, xiBachelorYPull); + registry.fill(HIST("hXiBachelorZPullVsPt"), xiBachelorPt, xiBachelorZPull); + + registry.fill(HIST("hXiXDelta"), xiXDelta); + registry.fill(HIST("hXiYDelta"), xiYDelta); + registry.fill(HIST("hXiZDelta"), xiZDelta); + registry.fill(HIST("hXiXDeltaVsPt"), xiPt, xiXDelta); + registry.fill(HIST("hXiYDeltaVsPt"), xiPt, xiYDelta); + registry.fill(HIST("hXiZDeltaVsPt"), xiPt, xiZDelta); + registry.fill(HIST("hXiXPull"), xiXPull); + registry.fill(HIST("hXiYPull"), xiYPull); + registry.fill(HIST("hXiZPull"), xiZPull); + registry.fill(HIST("hXiXPullVsPt"), xiPt, xiXPull); + registry.fill(HIST("hXiYPullVsPt"), xiPt, xiYPull); + registry.fill(HIST("hXiZPullVsPt"), xiPt, xiZPull); + + registry.fill(HIST("hCascXDelta"), cascXDelta); + registry.fill(HIST("hCascYDelta"), cascYDelta); + registry.fill(HIST("hCascZDelta"), cascZDelta); + + registry.fill(HIST("hXiBachelorPtRes"), (candidate.xiBachelorPt() - mcXiBachelor.pt()) / candidate.xiBachelorPt()); + registry.fill(HIST("hXiPtRes"), (candidate.xiPt() - mcXi.pt()) / candidate.xiPt()); + + // Xic → pi pi pi p + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, +kXiC0, std::array{+kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 3); + if (indexRec > -1 && sign == 1) { + auto mcXic0 = mcParticles.rawIteratorAt(indexRec - mcParticles.offset()); + float const xic0MassPull = (candidate.invMassCharmBaryon() - MassXiC0) / candidate.invMassXic0Err(); + registry.fill(HIST("hXic0MassPullVsPt"), candidate.xic0Pt(), xic0MassPull); + + float const xic0BachelorXDelta = candidate.xic0BachelorX() - mcXic0Bachelor.vx(); + float const xic0BachelorYDelta = candidate.xic0BachelorY() - mcXic0Bachelor.vy(); + float const xic0BachelorZDelta = candidate.xic0BachelorZ() - mcXic0Bachelor.vz(); + float const xic0BachelorPt = mcXic0Bachelor.pt(); + float const xic0BachelorXPull = xic0BachelorXDelta / candidate.xic0BachelorXError(); + float const xic0BachelorYPull = xic0BachelorYDelta / candidate.xic0BachelorYError(); + float const xic0BachelorZPull = xic0BachelorZDelta / candidate.xic0BachelorZError(); + + float const xic0XDelta = candidate.xDecayVtxCharmBaryon() - mcXic0Bachelor.vx(); + float const xic0YDelta = candidate.yDecayVtxCharmBaryon() - mcXic0Bachelor.vy(); + float const xic0ZDelta = candidate.zDecayVtxCharmBaryon() - mcXic0Bachelor.vz(); + float const xic0Pt = mcXic0.pt(); + float const xic0XPull = xic0XDelta / candidate.xic0XError(); + float const xic0YPull = xic0YDelta / candidate.xic0YError(); + float const xic0ZPull = xic0ZDelta / candidate.xic0ZError(); + registry.fill(HIST("hXic0BachelorXDelta"), xic0BachelorXDelta); + registry.fill(HIST("hXic0BachelorYDelta"), xic0BachelorYDelta); + registry.fill(HIST("hXic0BachelorZDelta"), xic0BachelorZDelta); + registry.fill(HIST("hXic0BachelorXDeltaVsPt"), xic0BachelorPt, xic0BachelorXDelta); + registry.fill(HIST("hXic0BachelorYDeltaVsPt"), xic0BachelorPt, xic0BachelorYDelta); + registry.fill(HIST("hXic0BachelorZDeltaVsPt"), xic0BachelorPt, xic0BachelorZDelta); + registry.fill(HIST("hXic0BachelorXPull"), xic0BachelorXPull); + registry.fill(HIST("hXic0BachelorYPull"), xic0BachelorYPull); + registry.fill(HIST("hXic0BachelorZPull"), xic0BachelorZPull); + registry.fill(HIST("hXic0BachelorXPullVsPt"), xic0BachelorPt, xic0BachelorXPull); + registry.fill(HIST("hXic0BachelorYPullVsPt"), xic0BachelorPt, xic0BachelorYPull); + registry.fill(HIST("hXic0BachelorZPullVsPt"), xic0BachelorPt, xic0BachelorZPull); + + registry.fill(HIST("hXic0XDelta"), xic0XDelta); + registry.fill(HIST("hXic0YDelta"), xic0YDelta); + registry.fill(HIST("hXic0ZDelta"), xic0ZDelta); + registry.fill(HIST("hXic0XDeltaVsPt"), xic0Pt, xic0XDelta); + registry.fill(HIST("hXic0YDeltaVsPt"), xic0Pt, xic0YDelta); + registry.fill(HIST("hXic0ZDeltaVsPt"), xic0Pt, xic0ZDelta); + registry.fill(HIST("hXic0XPull"), xic0XPull); + registry.fill(HIST("hXic0YPull"), xic0YPull); + registry.fill(HIST("hXic0ZPull"), xic0ZPull); + registry.fill(HIST("hXic0XPullVsPt"), xic0Pt, xic0XPull); + registry.fill(HIST("hXic0YPullVsPt"), xic0Pt, xic0YPull); + registry.fill(HIST("hXic0ZPullVsPt"), xic0Pt, xic0ZPull); + + registry.fill(HIST("hXic0BachelorPtRes"), (candidate.xic0BachelorPt() - mcXic0Bachelor.pt()) / candidate.xic0BachelorPt()); + registry.fill(HIST("hXic0PtRes"), (candidate.xic0Pt() - mcXic0.pt()) / candidate.xic0Pt()); + } + } + } + } + } + } void processDoNoMc(aod::Collisions::iterator const&) { @@ -1702,7 +3229,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processDoNoMc, "Do not run any MC process function", true); void processMcXicToXiPi(aod::HfCandToXiPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcColls, McCollisionsNoCents const& collsWithMcLabels, @@ -1712,10 +3239,30 @@ struct HfCandidateCreatorXic0Omegac0Mc { } 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 processMcXicToXiPiKfQa(aod::HfCandToXiPiKfQa const& candidates, + MyTracksWMc const& tracks, + aod::McParticles const& mcParticles, + BCsInfo const& bcs) + { + runXic0Omegac0McQa(candidates, tracks, mcParticles, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcXicToXiPiKfQa, "Run Xic0 to xi pi MC QA process function - no centrality", false); + void processMcXicToXiPiFT0m(aod::HfCandToXiPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, - aod::McCollisions const& mcColls, + McCollisionsCentFT0Ms const& mcColls, McCollisionsFT0Ms const& collsWithMcLabels, BCsInfo const& bcs) { @@ -1724,7 +3271,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcXicToXiPiFT0m, "Run Xic0 to xi pi MC process function - FT0M", false); void processMcXicToXiPiFT0c(aod::HfCandToXiPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcColls, McCollisionsFT0Cs const& collsWithMcLabels, @@ -1735,7 +3282,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcXicToXiPiFT0c, "Run Xic0 to xi pi MC process function - FT0C", false); void processMcOmegacToXiPi(aod::HfCandToXiPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcColls, McCollisionsNoCents const& collsWithMcLabels, @@ -1746,9 +3293,9 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToXiPi, "Run Omegac0 to xi pi MC process function - no centrality", false); void processMcOmegacToXiPiFT0m(aod::HfCandToXiPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, - aod::McCollisions const& mcColls, + McCollisionsCentFT0Ms const& mcColls, McCollisionsFT0Ms const& collsWithMcLabels, BCsInfo const& bcs) { @@ -1757,7 +3304,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToXiPiFT0m, "Run Omegac0 to xi pi MC process function - FT0M", false); void processMcOmegacToXiPiFT0c(aod::HfCandToXiPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcColls, McCollisionsFT0Cs const& collsWithMcLabels, @@ -1768,7 +3315,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToXiPiFT0c, "Run Omegac0 to xi pi MC process function - FT0C", false); void processMcOmegacToOmegaPi(aod::HfCandToOmegaPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcColls, McCollisionsNoCents const& collsWithMcLabels, @@ -1779,9 +3326,9 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaPi, "Run Omegac0 to omega pi MC process function - no centrality", false); void processMcOmegacToOmegaPiFT0m(aod::HfCandToOmegaPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, - aod::McCollisions const& mcColls, + McCollisionsCentFT0Ms const& mcColls, McCollisionsFT0Ms const& collsWithMcLabels, BCsInfo const& bcs) { @@ -1790,7 +3337,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaPiFT0m, "Run Omegac0 to omega pi MC process function - FT0M", false); void processMcOmegacToOmegaPiFT0c(aod::HfCandToOmegaPi const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcColls, McCollisionsFT0Cs const& collsWithMcLabels, @@ -1801,7 +3348,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaPiFT0c, "Run Omegac0 to omega pi MC process function - FT0C", false); void processMcOmegacToOmegaK(aod::HfCandToOmegaK const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcColls, McCollisionsNoCents const& collsWithMcLabels, @@ -1812,9 +3359,9 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaK, "Run Omegac0 to omega K MC process function - no centrality", false); void processMcOmegacToOmegaKFT0m(aod::HfCandToOmegaK const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, - aod::McCollisions const& mcColls, + McCollisionsCentFT0Ms const& mcColls, McCollisionsFT0Ms const& collsWithMcLabels, BCsInfo const& bcs) { @@ -1823,7 +3370,7 @@ struct HfCandidateCreatorXic0Omegac0Mc { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Mc, processMcOmegacToOmegaKFT0m, "Run Omegac0 to omega K MC process function - FT0M", false); void processMcOmegacToOmegaKFT0c(aod::HfCandToOmegaK const& candidates, - aod::TracksWMc const& tracks, + MyTracksWMc const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const& mcColls, McCollisionsFT0Cs const& collsWithMcLabels, diff --git a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx index c5390548579..8c71e2951c1 100644 --- a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx @@ -13,41 +13,75 @@ /// \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 +#define HomogeneousField // o2-linter: disable=name/macro (required by KFParticle) #endif -#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 "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" #include "Common/Core/trackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Tools/KFparticle/KFUtilities.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include 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; +using namespace o2::hf_evsel; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; +using namespace o2::aod::hf_cand_xic_to_xi_pi_pi; /// Reconstruction of heavy-flavour 3-prong decay candidates struct HfCandidateCreatorXicToXiPiPi { @@ -74,37 +108,55 @@ struct HfCandidateCreatorXicToXiPiPi { 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::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; o2::vertexing::DCAFitterN<3> df; + HfEventSelection hfEvSel; + int runNumber{0}; float massXiPiPi{0.}; float massXiPi0{0.}; float massXiPi1{0.}; double bz{0.}; + enum XicCandCounter { TotalSkimmedTriplets = 0, + SelEvent, + 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"}; + OutputObj zorroSummary{"zorroSummary"}; void init(InitContext const&) { - if ((doprocessXicplusWithDcaFitter + doprocessXicplusWithKFParticle) != 1) { - LOGP(fatal, "Only one process function can be enabled at a time."); + if ((doprocessNoCentXicplusWithDcaFitter + doprocessCentFT0CXicplusWithDcaFitter + doprocessCentFT0MXicplusWithDcaFitter + doprocessNoCentXicplusWithKFParticle + doprocessCentFT0CXicplusWithKFParticle + doprocessCentFT0MXicplusWithKFParticle) != 1) { + LOGP(fatal, "Only one process function for the Xic reconstruction can be enabled at a time."); } // add histograms to registry + registry.add("hVertexerType", "Use DCAFitter or KFParticle;;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.get(HIST("hVertexerType"))->GetXaxis()->SetBinLabel(1 + aod::hf_cand::VertexerType::DCAFitter, "DCAFitter"); + registry.get(HIST("hVertexerType"))->GetXaxis()->SetBinLabel(1 + aod::hf_cand::VertexerType::KfParticle, "KFParticle"); + registry.add("hCandCounter", "hCandCounter", {HistType::kTH1D, {{4, -0.5, 3.5}}}); + registry.get(HIST("hCandCounter"))->GetXaxis()->SetBinLabel(1 + TotalSkimmedTriplets, "total"); + registry.get(HIST("hCandCounter"))->GetXaxis()->SetBinLabel(1 + SelEvent, "Event selected"); + registry.get(HIST("hCandCounter"))->GetXaxis()->SetBinLabel(1 + CascPreSel, "Cascade preselection"); + registry.get(HIST("hCandCounter"))->GetXaxis()->SetBinLabel(1 + VertexFit, "Successful vertex fit"); + // physical variables if (fillHistograms) { 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}}}); @@ -115,16 +167,15 @@ struct HfCandidateCreatorXicToXiPiPi { 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("hVertexerType", "Use KF or DCAFitterN;Vertexer type;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); // See o2::aod::hf_cand::VertexerType 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) { + if ((doprocessNoCentXicplusWithDcaFitter || doprocessCentFT0CXicplusWithDcaFitter || doprocessCentFT0MXicplusWithDcaFitter) && fillHistograms) { registry.fill(HIST("hVertexerType"), aod::hf_cand::VertexerType::DCAFitter); } - if (doprocessXicplusWithKFParticle && fillHistograms) { + if ((doprocessNoCentXicplusWithKFParticle || doprocessCentFT0CXicplusWithKFParticle || doprocessCentFT0MXicplusWithKFParticle) && fillHistograms) { registry.fill(HIST("hVertexerType"), aod::hf_cand::VertexerType::KfParticle); } @@ -135,6 +186,9 @@ struct HfCandidateCreatorXicToXiPiPi { lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); runNumber = 0; + // initialize HF event selection helper + hfEvSel.init(registry, zorroSummary); + // initialize 3-prong vertex fitter df.setPropagateToPCA(propagateToPCA); df.setMaxR(maxR); @@ -145,23 +199,36 @@ struct HfCandidateCreatorXicToXiPiPi { df.setWeightedFinalPCA(useWeightedFinalPCA); } - void processXicplusWithDcaFitter(aod::Collisions const&, - aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, - CascadesLinked const&, - CascFull const&, - aod::TracksWCovDca const&, - aod::BCsWithTimestamps const&) + template + void runXicplusCreatorWithDcaFitter(Collision 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) { + registry.fill(HIST("hCandCounter"), TotalSkimmedTriplets); + + // check if the event is selected + auto collision = rowTrackIndexXicPlus.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; + } + registry.fill(HIST("hCandCounter"), SelEvent); + + // Retrieve skimmed cascade and pion tracks 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(); + auto trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as(); + auto trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as(); // preselect cascade candidates if (doCascadePreselection) { @@ -172,11 +239,12 @@ struct HfCandidateCreatorXicToXiPiPi { continue; } } + registry.fill(HIST("hCandCounter"), 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(); + 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); @@ -185,27 +253,25 @@ struct HfCandidateCreatorXicToXiPiPi { } df.setBz(bz); - //----------------accessing particles in the decay chain------------- - auto trackPionFromXi = casc.bachelor_as(); // pion <- xi track from TracksWCovDca table - //--------------------------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 const vertexV0 = {casc.xlambda(), casc.ylambda(), casc.zlambda()}; + std::array const pVecV0 = {casc.pxlambda(), casc.pylambda(), casc.pzlambda()}; + std::array const vertexCasc = {casc.x(), casc.y(), casc.z()}; + std::array const 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]; + constexpr std::size_t NElementsCovMatrix{6u}; + constexpr std::array MomInd = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (auto i = 0u; i < NElementsCovMatrix; i++) { covCasc[i] = casc.positionCovMat()[i]; + covCasc[MomInd[i]] = casc.momentumCovMat()[i]; } // create cascade track o2::track::TrackParCov trackCasc; - if (trackPionFromXi.sign() > 0) { + if (casc.sign() > 0) { trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, 1, true); - } else if (trackPionFromXi.sign() < 0) { + } else if (casc.sign() < 0) { trackCasc = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, -1, true); } else { continue; @@ -226,10 +292,11 @@ struct HfCandidateCreatorXicToXiPiPi { LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN cannot work, skipping the candidate."; continue; } + registry.fill(HIST("hCandCounter"), VertexFit); //----------------------------calculate physical properties----------------------- // Charge of charm baryon - int signXic = casc.sign() < 0 ? +1 : -1; + int8_t const signXic = casc.sign() < 0 ? +1 : -1; // get SV properties const auto& secondaryVertex = df.getPCACandidate(); @@ -240,16 +307,16 @@ struct HfCandidateCreatorXicToXiPiPi { trackCasc = df.getTrack(0); trackParCovCharmBachelor0 = df.getTrack(1); trackParCovCharmBachelor1 = df.getTrack(2); - std::array pVecXi; - std::array pVecPi0; - std::array pVecPi1; + 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}); + massXiPiPi = RecoDecay::m(arrayMomenta, std::array{MassXiMinus, MassPiPlus, MassPiPlus}); // get track impact parameters // This modifies track momenta! @@ -264,24 +331,55 @@ struct HfCandidateCreatorXicToXiPiPi { trackParCovCharmBachelor1.propagateToDCA(primaryVertex, bz, &impactParameter1); // calculate cosine of pointing angle - std::array pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; - double cpaLambda = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); - double cpaXYLambda = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); - double cpaXi = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); - double cpaXYXi = RecoDecay::cpaXY(pvCoord, vertexCasc, pVecCasc); + std::array const pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; + float cpaLambda = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + float const cpaXYLambda = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); + float cpaXi = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float const cpaXYXi = RecoDecay::cpaXY(pvCoord, vertexCasc, pVecCasc); + float const cpaLambdaToXi = RecoDecay::cpa(vertexCasc, vertexV0, pVecV0); + float const 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}); + massXiPi0 = RecoDecay::m(arrayMomentaXiPi0, std::array{MassXiMinus, MassPiPlus}); auto arrayMomentaXiPi1 = std::array{pVecXi, pVecPi1}; - massXiPi1 = RecoDecay::m(std::move(arrayMomentaXiPi1), std::array{MassXiMinus, MassPiPlus}); + massXiPi1 = RecoDecay::m(arrayMomentaXiPi1, std::array{MassXiMinus, MassPiPlus}); // get uncertainty of the decay length - double phi, theta; + 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 const nSigTpcPiFromXicPlus0 = trackCharmBachelor0.tpcNSigmaPi(); + float const nSigTofPiFromXicPlus0 = trackCharmBachelor0.tofNSigmaPi(); + float const nSigTpcPiFromXicPlus1 = trackCharmBachelor1.tpcNSigmaPi(); + float const nSigTofPiFromXicPlus1 = trackCharmBachelor1.tofNSigmaPi(); + // Bachelor pion + auto trackPionFromXi = casc.bachelor_as(); + float const nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); + float const 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 @@ -308,12 +406,12 @@ struct HfCandidateCreatorXicToXiPiPi { //---------------------------------fill candidate table rows------------------------------------------------------------------------------------------- rowCandidateBase(collision.globalIndex(), primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), - covMatrixPV[0], covMatrixPV[2], covMatrixPV[5], + 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], - covMatrixSV[0], covMatrixSV[2], covMatrixSV[5], + std::sqrt(covMatrixSV[0]), std::sqrt(covMatrixSV[2]), std::sqrt(covMatrixSV[5]), errorDecayLength, errorDecayLengthXY, chi2SV, massXiPiPi, signXic, pVecXi[0], pVecXi[1], pVecXi[2], @@ -322,31 +420,48 @@ struct HfCandidateCreatorXicToXiPiPi { impactParameterCasc.getY(), impactParameter0.getY(), impactParameter1.getY(), std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), /*cascade specific columns*/ - vertexCasc[0], vertexCasc[1], vertexCasc[2], - vertexV0[0], vertexV0[1], vertexV0[2], - cpaXi, cpaXYXi, cpaLambda, cpaXYLambda, - massXiPi0, massXiPi1); + 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&, - aod::TracksWCovExtra const&, - aod::BCsWithTimestamps const&) + + template + void runXicplusCreatorWithKFParticle(Collision 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) { + registry.fill(HIST("hCandCounter"), TotalSkimmedTriplets); + + // check if the event is selected + auto collision = rowTrackIndexXicPlus.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; + } + registry.fill(HIST("hCandCounter"), SelEvent); + + // Retrieve skimmed cascade and pion tracks 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(); + auto trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as(); + auto trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as(); //-------------------preselect cascade candidates-------------------------------------- if (doCascadePreselection) { @@ -357,11 +472,12 @@ struct HfCandidateCreatorXicToXiPiPi { continue; } } + registry.fill(HIST("hCandCounter"), 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(); + 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); @@ -371,34 +487,37 @@ struct HfCandidateCreatorXicToXiPiPi { 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()}; + std::array const vertexV0 = {casc.xlambda(), casc.ylambda(), casc.zlambda()}; + std::array const pVecV0 = {casc.pxlambda(), casc.pylambda(), casc.pzlambda()}; + std::array const vertexCasc = {casc.x(), casc.y(), casc.z()}; + std::array const pVecCasc = {casc.px(), casc.py(), casc.pz()}; //----------------------Create XicPlus as KFParticle object------------------------------------------- // initialize primary vertex - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + KFPVertex const kfpVertex = createKFPVertexFromCollision(collision); float covMatrixPV[6]; kfpVertex.GetCovarianceMatrix(covMatrixPV); - KFParticle KFPV(kfpVertex); // for calculation of DCAs to PV + KFParticle const kfPv(kfpVertex); // for calculation of DCAs to PV // convert pion tracks into KFParticle object - KFPTrack kfpTrackCharmBachelor0 = createKFPTrackFromTrack(trackCharmBachelor0); - KFPTrack kfpTrackCharmBachelor1 = createKFPTrackFromTrack(trackCharmBachelor1); + KFPTrack const kfpTrackCharmBachelor0 = createKFPTrackFromTrack(trackCharmBachelor0); + KFPTrack const 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]; - } + constexpr std::size_t NElementsStateVector{6}; + std::array xyzpxpypz = {casc.x(), casc.y(), casc.z(), casc.px(), casc.py(), casc.pz()}; + float parPosMom[NElementsStateVector]; + std::copy(xyzpxpypz.begin(), xyzpxpypz.end(), parPosMom); // create KFParticle KFParticle kfXi; - kfXi.Create(parPosMom, casc.kfTrackCovMat(), casc.sign(), casc.mXi()); + float const massXi = casc.mXi(); + kfXi.Create(parPosMom, casc.kfTrackCovMat(), casc.sign(), massXi); + if (useXiMassConstraint) { + kfXi.SetNonlinearMassConstraint(MassXiMinus); + } // create XicPlus as KFParticle object KFParticle kfXicPlus; @@ -410,75 +529,66 @@ struct HfCandidateCreatorXicToXiPiPi { LOG(debug) << "Failed to construct XicPlus : " << e.what(); continue; } + registry.fill(HIST("hCandCounter"), VertexFit); - // get geometrical chi2 of XicPlus - float chi2GeoXicPlus = kfXicPlus.GetChi2() / kfXicPlus.GetNDF(); + // get chi2 values + float const chi2GeoXicPlus = kfXicPlus.GetChi2() / kfXicPlus.GetNDF(); + float chi2PrimXi = kfXi.GetDeviationFromVertex(kfPv); + float chi2PrimPi0 = kfCharmBachelor0.GetDeviationFromVertex(kfPv); + float chi2PrimPi1 = kfCharmBachelor1.GetDeviationFromVertex(kfPv); // topological constraint of Xic to PV + float chi2TopoXicPlusToPVBefConst = kfXicPlus.GetDeviationFromVertex(kfPv); KFParticle kfXicPlusToPV = kfXicPlus; - kfXicPlusToPV.SetProductionVertex(KFPV); - float chi2topoXicPlusPV = kfXicPlusToPV.GetChi2() / kfXicPlusToPV.GetNDF(); + kfXicPlusToPV.SetProductionVertex(kfPv); + float chi2TopoXicPlusToPV = kfXicPlusToPV.GetChi2() / kfXicPlusToPV.GetNDF(); if (constrainXicPlusToPv) { kfXicPlus = kfXicPlusToPV; kfXicPlus.TransportToDecayVertex(); } - // topological constraint of Xi to XicPlus - 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; - - // get updated daughter tracks after vertex fit - // after production vertex constraint the parameters of the particle are stored at the position of the production vertex - KFParticle kfCharmBachelor0Upd = kfCharmBachelor0; - KFParticle kfCharmBachelor1Upd = kfCharmBachelor1; - KFParticle kfXiUpd = kfXi; - kfCharmBachelor0Upd.SetProductionVertex(kfXicPlus); - kfCharmBachelor1Upd.SetProductionVertex(kfXicPlus); - kfXiUpd.SetProductionVertex(kfXicPlus); - - // get impact parameters of updated XicPlus daughters + int8_t const 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.; - kfCharmBachelor0Upd.GetDistanceFromVertexXY(KFPV, impactParameterPi0XY, errImpactParameterPi0XY); - kfCharmBachelor1Upd.GetDistanceFromVertexXY(KFPV, impactParameterPi1XY, errImpactParameterPi1XY); - kfXiUpd.GetDistanceFromVertexXY(KFPV, impactParameterXiXY, errImpactParameterXiXY); + 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()}; - double cpaLambda = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); - double cpaXYLambda = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); - double cpaXi = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); - double cpaXYXi = RecoDecay::cpaXY(pvCoord, vertexCasc, pVecCasc); + std::array const pvCoord = {collision.posX(), collision.posY(), collision.posZ()}; + float cpaLambda = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + float const cpaXYLambda = RecoDecay::cpaXY(pvCoord, vertexV0, pVecV0); + float cpaXi = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float const cpaXYXi = RecoDecay::cpaXY(pvCoord, vertexCasc, pVecCasc); + float const cpaLambdaToXi = RecoDecay::cpa(vertexCasc, vertexV0, pVecV0); + float const cpaXYLambdaToXi = RecoDecay::cpaXY(vertexCasc, vertexV0, pVecV0); + + // get chi2 deviation of Pi0-Pi1, Pi0-Xi, Pi1-Xi + float chi2DevPi0Pi1 = kfCharmBachelor0.GetDeviationFromParticle(kfCharmBachelor1); + float chi2DevPi0Xi = kfCharmBachelor0.GetDeviationFromParticle(kfXi); + float chi2DevPi1Xi = kfCharmBachelor1.GetDeviationFromParticle(kfXi); // get DCAs of Pi0-Pi1, Pi0-Xi, Pi1-Xi - float dcaXYPi0Pi1 = kfCharmBachelor0Upd.GetDistanceFromParticleXY(kfCharmBachelor1Upd); - float dcaXYPi0Xi = kfCharmBachelor0Upd.GetDistanceFromParticleXY(kfXiUpd); - float dcaXYPi1Xi = kfCharmBachelor1Upd.GetDistanceFromParticleXY(kfXiUpd); - float dcaPi0Pi1 = kfCharmBachelor0Upd.GetDistanceFromParticle(kfCharmBachelor1Upd); - float dcaPi0Xi = kfCharmBachelor0Upd.GetDistanceFromParticle(kfXiUpd); - float dcaPi1Xi = kfCharmBachelor1Upd.GetDistanceFromParticle(kfXiUpd); + float dcaPi0Pi1 = kfCharmBachelor0.GetDistanceFromParticle(kfCharmBachelor1); + float dcaPi0Xi = kfCharmBachelor0.GetDistanceFromParticle(kfXi); + float dcaPi1Xi = kfCharmBachelor1.GetDistanceFromParticle(kfXi); + float dcaXYPi0Pi1 = kfCharmBachelor0.GetDistanceFromParticleXY(kfCharmBachelor1); + float dcaXYPi0Xi = kfCharmBachelor0.GetDistanceFromParticleXY(kfXi); + float dcaXYPi1Xi = kfCharmBachelor1.GetDistanceFromParticleXY(kfXi); // mass of Xi-Pi0 pair KFParticle kfXiPi0; @@ -508,6 +618,43 @@ struct HfCandidateCreatorXicToXiPiPi { 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 const nSigTpcPiFromXicPlus0 = trackCharmBachelor0.tpcNSigmaPi(); + float const nSigTofPiFromXicPlus0 = trackCharmBachelor0.tofNSigmaPi(); + float const nSigTpcPiFromXicPlus1 = trackCharmBachelor1.tpcNSigmaPi(); + float const nSigTofPiFromXicPlus1 = trackCharmBachelor1.tofNSigmaPi(); + // Bachelor pion + auto trackPionFromXi = casc.bachelor_as(); + float const nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); + float const 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 @@ -518,6 +665,7 @@ struct HfCandidateCreatorXicToXiPiPi { registry.fill(HIST("hCovPVXZ"), covMatrixPV[3]); registry.fill(HIST("hCovPVZZ"), covMatrixPV[5]); // covariance matrix elements of SV + auto* covMatrixXicPlus = kfXicPlus.CovarianceMatrix(); registry.fill(HIST("hCovSVXX"), covMatrixXicPlus[0]); registry.fill(HIST("hCovSVYY"), covMatrixXicPlus[2]); registry.fill(HIST("hCovSVXZ"), covMatrixXicPlus[3]); @@ -530,14 +678,14 @@ struct HfCandidateCreatorXicToXiPiPi { //------------------------------fill candidate table rows-------------------------------------- rowCandidateBase(collision.globalIndex(), - KFPV.GetX(), KFPV.GetY(), KFPV.GetZ(), - covMatrixPV[0], covMatrixPV[2], covMatrixPV[5], + 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(), - kfXicPlus.GetX(), kfXicPlus.GetY(), kfXicPlus.GetZ(), + secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], kfXicPlus.GetErrX(), kfXicPlus.GetErrY(), kfXicPlus.GetErrZ(), - kfXicPlus.GetErrDecayLength(), kfXicPlus.GetErrDecayLengthXY(), + errorKfDecayLength, errorKfDecayLengthXY, chi2GeoXicPlus, massXiPiPi, signXic, kfXi.GetPx(), kfXi.GetPy(), kfXi.GetPz(), kfCharmBachelor0.GetPx(), kfCharmBachelor0.GetPy(), kfCharmBachelor0.GetPz(), @@ -545,17 +693,162 @@ struct HfCandidateCreatorXicToXiPiPi { impactParameterXiXY, impactParameterPi0XY, impactParameterPi1XY, errImpactParameterXiXY, errImpactParameterPi0XY, errImpactParameterPi1XY, /*cascade specific columns*/ - casc.x(), casc.y(), casc.z(), - casc.xlambda(), casc.ylambda(), casc.zlambda(), - cpaXi, cpaXYXi, cpaLambda, cpaXYLambda, - massXiPi0, massXiPi1); - rowCandidateKF(casc.kfCascadeChi2(), casc.kfV0Chi2(), chi2topoXicPlusPV, chi2topoXiToXicPlus, - dcaXYPi0Pi1, dcaXYPi0Xi, dcaXYPi1Xi, + 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(kfDecayLength, kfDecayLengthNormalised, kfDecayLengthXY, kfDecayLengthXYNormalised, + casc.kfCascadeChi2(), casc.kfV0Chi2(), + chi2TopoXicPlusToPVBefConst, chi2TopoXicPlusToPV, + chi2PrimXi, chi2PrimPi0, chi2PrimPi1, + chi2DevPi0Pi1, chi2DevPi0Xi, chi2DevPi1Xi, dcaPi0Pi1, dcaPi0Xi, dcaPi1Xi, - casc.dcacascdaughters()); + dcaXYPi0Pi1, dcaXYPi0Xi, dcaXYPi1Xi); } // loop over track triplets } - PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processXicplusWithKFParticle, "Run candidate creator with KFParticle using derived data from HfTrackIndexSkimCreatorLfCascades.", false); + + /////////////////////////////////////////////////////////// + /// /// + /// Process functions with DCAFitter /// + /// /// + /////////////////////////////////////////////////////////// + + void processNoCentXicplusWithDcaFitter(soa::Join const& collisions, + aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, + CascadesLinked const& cascadesLinked, + CascFull const& cascadesFull, + TracksWCovDcaPidPrPi const& tracks, + aod::BCsWithTimestamps const& bcs) + { + runXicplusCreatorWithDcaFitter(collisions, rowsTrackIndexXicPlus, cascadesLinked, cascadesFull, tracks, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processNoCentXicplusWithDcaFitter, "Run candidate creator with DCAFitter without centrality selection.", true); + + void processCentFT0CXicplusWithDcaFitter(soa::Join const& collisions, + aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, + CascadesLinked const& cascadesLinked, + CascFull const& cascadesFull, + TracksWCovDcaPidPrPi const& tracks, + aod::BCsWithTimestamps const& bcs) + { + runXicplusCreatorWithDcaFitter(collisions, rowsTrackIndexXicPlus, cascadesLinked, cascadesFull, tracks, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCentFT0CXicplusWithDcaFitter, "Run candidate creator with DCAFitter with centrality selection on FT0C.", false); + + void processCentFT0MXicplusWithDcaFitter(soa::Join const& collisions, + aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, + CascadesLinked const& cascadesLinked, + CascFull const& cascadesFull, + TracksWCovDcaPidPrPi const& tracks, + aod::BCsWithTimestamps const& bcs) + { + runXicplusCreatorWithDcaFitter(collisions, rowsTrackIndexXicPlus, cascadesLinked, cascadesFull, tracks, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCentFT0MXicplusWithDcaFitter, "Run candidate creator with DCAFitter with centrality selection on FT0M.", false); + + /////////////////////////////////////////////////////////// + /// /// + /// Process functions with KFParticle /// + /// /// + /////////////////////////////////////////////////////////// + + void processNoCentXicplusWithKFParticle(soa::Join const& collisions, + aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, + KFCascadesLinked const& kfCascadesLinked, + KFCascFull const& kfCascadesFull, + TracksWCovExtraPidPrPi const& tracks, + aod::BCsWithTimestamps const& bcs) + { + runXicplusCreatorWithKFParticle(collisions, rowsTrackIndexXicPlus, kfCascadesLinked, kfCascadesFull, tracks, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processNoCentXicplusWithKFParticle, "Run candidate creator with KFParticle without centrality selection.", false); + + void processCentFT0CXicplusWithKFParticle(soa::Join const& collisions, + aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, + KFCascadesLinked const& kfCascadesLinked, + KFCascFull const& kfCascadesFull, + TracksWCovExtraPidPrPi const& tracks, + aod::BCsWithTimestamps const& bcs) + { + runXicplusCreatorWithKFParticle(collisions, rowsTrackIndexXicPlus, kfCascadesLinked, kfCascadesFull, tracks, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCentFT0CXicplusWithKFParticle, "Run candidate creator with KFParticle with centrality selection on FT0C.", false); + + void processCentFT0MXicplusWithKFParticle(soa::Join const& collisions, + aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, + KFCascadesLinked const& kfCascadesLinked, + KFCascFull const& kfCascadesFull, + TracksWCovExtraPidPrPi const& tracks, + aod::BCsWithTimestamps const& bcs) + { + runXicplusCreatorWithKFParticle(collisions, rowsTrackIndexXicPlus, kfCascadesLinked, kfCascadesFull, tracks, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCentFT0MXicplusWithKFParticle, "Run candidate creator with KFParticle with centrality selection on FT0M.", false); + + /////////////////////////////////////////////////////////// + /// /// + /// Process functions only for collision monitoring /// + /// /// + /////////////////////////////////////////////////////////// + + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const&) + { + /// loop over collisions + for (const auto& collision : collisions) { + + /// bitmask with event. selection info + float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); + + } /// end loop over collisions + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCollisions, "Collision monitoring - no centrality", false); + + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const&) + { + /// loop over collisions + for (const auto& collision : collisions) { + + /// bitmask with event. selection info + float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); + + } /// end loop over collisions + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); + + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const&) + { + /// loop over collisions + for (const auto& collision : collisions) { + + /// bitmask with event. selection info + float centrality{-1.f}; + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, hfEvSel.occEstimator); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + const auto bc = collision.template foundBC_as(); + const auto ir = hfEvSel.getInteractionRate(bc, ccdb); // Hz + /// monitor the satisfied event selections + hfEvSel.fillHistograms(collision, rejectionMask, centrality, occupancy, ir); + + } /// end loop over collisions + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCollisionsCentFT0M, "Collision monitoring - FT0M centrality", false); }; // struct /// Performs MC matching. @@ -563,11 +856,62 @@ struct HfCandidateCreatorXicToXiPiPiExpressions { Spawns rowCandidateXic; Produces rowMcMatchRec; Produces rowMcMatchGen; + Produces rowResiduals; - void init(InitContext const&) {} + Configurable fillMcHistograms{"fillMcHistograms", true, "Fill validation plots"}; + Configurable matchDecayedPions{"matchDecayedPions", true, "Match also candidates with daughter pion tracks that decay with kinked topology"}; + Configurable matchInteractionsWithMaterial{"matchInteractionsWithMaterial", true, "Match also candidates with daughter tracks that interact with material"}; + Configurable fillResidualTable{"fillResidualTable", false, "Fill table containing residuals and pulls of PV and SV"}; - void processMc(aod::TracksWMc const& tracks, - aod::McParticles const& mcParticles) + HfEventSelectionMc hfEvSelMc; + + enum DebugRec { TotalRec = 0, + XicToFinalState, + XiToPiPPi, + LambdaToPPi }; + + 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"}; + + void init(InitContext& initContext) + { + // add histograms to registry + if (fillMcHistograms) { + registry.add("hDecayedPions", "hDecayedPions", {HistType::kTH1F, {{5, -0.5, 4.5}}}); + registry.add("hInteractionsWithMaterial", "hInteractionsWithMaterial", {HistType::kTH1F, {{6, -0.5, 5.5}}}); + registry.add("hDebugRec", "hDebugRec", {HistType::kTH1F, {{4, -0.5, 3.5}}}); + registry.get(HIST("hDebugRec"))->GetXaxis()->SetBinLabel(1 + TotalRec, "total"); + registry.get(HIST("hDebugRec"))->GetXaxis()->SetBinLabel(1 + XicToFinalState, "#Xi^{+}_{c} #rightarrow #pi^{#plus} #pi^{#plus} #pi^{#minus} p #pi^{#minus}"); + registry.get(HIST("hDebugRec"))->GetXaxis()->SetBinLabel(1 + XiToPiPPi, "#Xi^{#minus} #rightarrow #pi^{#minus} p #pi^{#minus}"); + registry.get(HIST("hDebugRec"))->GetXaxis()->SetBinLabel(1 + LambdaToPPi, "#Lambda #rightarrow p #pi^{#minus}"); + } + + // initialize HF event selection helper + const auto& workflows = initContext.services().get(); + for (const DeviceSpec& device : workflows.devices) { + if (device.name == "hf-candidate-creator-xic-to-xi-pi-pi") { + hfEvSelMc.init(device, registry); + break; + } + } + } + + template + void runMcMatching(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisions const& mcCollisions, + CollInfos const& collInfos, + BCsInfo const&) { rowCandidateXic->bindExternalIndices(&tracks); @@ -575,20 +919,39 @@ struct HfCandidateCreatorXicToXiPiPiExpressions { int indexRecXicPlus = -1; int8_t sign = 0; int8_t flag = 0; - int8_t origin = 0; - int8_t debug = 0; - // for resonance matching: + int8_t origin = RecoDecay::OriginType::None; + float decayLengthGen = -999.f; + int8_t nPionsDecayed = 0; + int8_t nInteractionsWithMaterial = 0; + // for resonance matching std::vector arrDaughIndex; - std::array arrPDGDaugh; - std::array arrXiResonance = {3324, kPiPlus}; // 3324: Ξ(1530) + constexpr std::size_t NDaughtersResonant{2u}; + std::array arrPDGDaugh{}; + std::array arrXiResonance = {3324, kPiPlus}; // 3324: Ξ(1530) + // for non-prompt + std::vector idxBhadMothers; + // residuals and pulls + std::array momentumResiduals{-9999.f}; + std::array pvResiduals{-9999.f}; + std::array pvPulls{-9999.f}; + std::array svResiduals{-9999.f}; + std::array svPulls{-9999.f}; // Match reconstructed candidates. for (const auto& candidate : *rowCandidateXic) { - flag = 0; sign = 0; + flag = 0; origin = RecoDecay::OriginType::None; - debug = 0; + nPionsDecayed = 0; + nInteractionsWithMaterial = 0; arrDaughIndex.clear(); + if (fillResidualTable) { + momentumResiduals.fill(-9999.f); + pvResiduals.fill(-9999.f); + pvPulls.fill(-9999.f); + svResiduals.fill(-9999.f); + svPulls.fill(-9999.f); + } auto arrayDaughters = std::array{candidate.pi0_as(), // pi <- Xic candidate.pi1_as(), // pi <- Xic @@ -601,99 +964,231 @@ struct HfCandidateCreatorXicToXiPiPiExpressions { auto arrayDaughtersV0 = std::array{candidate.posTrack_as(), candidate.negTrack_as()}; + if (fillMcHistograms) { + registry.fill(HIST("hDebugRec"), TotalRec); + } + // 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 (matchDecayedPions && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kPiPlus, +kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 4, &nPionsDecayed, nullptr, &nInteractionsWithMaterial); + } else if (matchDecayedPions && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kPiPlus, +kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 4, &nPionsDecayed, nullptr, &nInteractionsWithMaterial); + } else if (!matchDecayedPions && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kPiPlus, +kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 4, &nPionsDecayed, nullptr, &nInteractionsWithMaterial); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCPlus, std::array{+kPiPlus, +kPiPlus, +kPiMinus, +kProton, +kPiMinus}, true, &sign, 4, &nPionsDecayed, nullptr, &nInteractionsWithMaterial); } + indexRecXicPlus = indexRec; if (indexRec > -1) { + if (fillMcHistograms) { + registry.fill(HIST("hDebugRec"), XicToFinalState); + } // Xi- → pi pi p - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, &sign, 2); - if (indexRec == -1) { - debug = 2; + if (matchDecayedPions && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, nullptr, 2); + } else if (matchDecayedPions && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, nullptr, 2); + } else if (!matchDecayedPions && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, nullptr, 2); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersCasc, +kXiMinus, std::array{+kPiMinus, +kProton, +kPiMinus}, true, nullptr, 2); } if (indexRec > -1) { + if (fillMcHistograms) { + registry.fill(HIST("hDebugRec"), XiToPiPPi); + } // Lambda → p pi - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &sign, 1); - if (indexRec == -1) { - debug = 3; + if (matchDecayedPions && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true); + } else if (matchDecayedPions && !matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true); + } else if (!matchDecayedPions && matchInteractionsWithMaterial) { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true); + } else { + indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true); } 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) { + if (fillMcHistograms) { + registry.fill(HIST("hDebugRec"), LambdaToPPi); + } + auto particleXicPlus = mcParticles.rawIteratorAt(indexRecXicPlus); + // Check whether XicPlus decays via resonant decay + RecoDecay::getDaughters(particleXicPlus, &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < NDaughtersResonant; ++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, particleXicPlus, false); + } + // Calculate residuals and pulls + if (flag != 0 && fillResidualTable) { + auto mcCollision = particleXicPlus.template mcCollision_as(); + auto particleDaughter0 = mcParticles.rawIteratorAt(arrDaughIndex[0]); + + momentumResiduals[0] = candidate.p() - particleXicPlus.p(); + momentumResiduals[1] = candidate.pt() - particleXicPlus.pt(); + pvResiduals[0] = candidate.posX() - mcCollision.posX(); + pvResiduals[1] = candidate.posY() - mcCollision.posY(); + pvResiduals[2] = candidate.posZ() - mcCollision.posZ(); + svResiduals[0] = candidate.xSecondaryVertex() - particleDaughter0.vx(); + svResiduals[1] = candidate.ySecondaryVertex() - particleDaughter0.vy(); + svResiduals[2] = candidate.zSecondaryVertex() - particleDaughter0.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."; + } + } } } } - // 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, true); + // Fill histograms + if (flag != 0 && fillMcHistograms) { + registry.fill(HIST("hDecayedPions"), nPionsDecayed); + registry.fill(HIST("hInteractionsWithMaterial"), nInteractionsWithMaterial); } - rowMcMatchRec(flag, debug, origin); + // Fill tables + rowMcMatchRec(flag, origin); + if (flag != 0 && fillResidualTable) { + rowResiduals(origin, momentumResiduals[0], momentumResiduals[1], + pvResiduals[0], pvResiduals[1], pvResiduals[2], + pvPulls[0], pvPulls[1], pvPulls[2], + svResiduals[0], svResiduals[1], svResiduals[2], + svPulls[0], svPulls[1], svPulls[2]); + } } // close loop over candidates // Match generated particles. - for (const auto& particle : mcParticles) { - flag = 0; - sign = 0; - debug = 0; - origin = RecoDecay::OriginType::None; - arrDaughIndex.clear(); + 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}; + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + int nSplitColl = 0; + if constexpr (CentEstimator == o2::hf_centrality::CentralityEstimator::FT0C) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0C, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (CentEstimator == o2::hf_centrality::CentralityEstimator::FT0M) { + const auto collSlice = collInfos.sliceBy(colPerMcCollisionFT0M, mcCollision.globalIndex()); + nSplitColl = collSlice.size(); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } else if constexpr (CentEstimator == o2::hf_centrality::CentralityEstimator::None) { + const auto collSlice = collInfos.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, collSlice, centrality); + } + 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(-99, -99, -99, decayLengthGen); + } + continue; + } - // 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()); - 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; - - RecoDecay::getDaughters(particle, &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); + for (const auto& particle : mcParticlesPerMcColl) { + sign = 0; + flag = 0; + origin = RecoDecay::OriginType::None; + arrDaughIndex.clear(); + idxBhadMothers.clear(); + + // Xic → Xi pi pi + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kXiCPlus, std::array{+kXiMinus, +kPiPlus, +kPiPlus}, true, &sign, 2)) { + // 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() == NDaughtersResonant) { + 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)) { + // Lambda -> p pi + auto v0MC = mcParticles.rawIteratorAt(cascMC.daughtersIds().front()); + if (RecoDecay::isMatchedMCGen(mcParticles, v0MC, +kLambda0, std::array{+kProton, +kPiMinus}, true)) { + if (arrDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < NDaughtersResonant; ++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; + flag = sign * (1 << aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi); } - } 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, true); - } + // Check whether the charm baryon is non-prompt (from a b quark). + if (flag != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + // Calculate the decay length of the generated particle + auto dau0 = particle.template daughters_as().begin(); + const std::array vtxDau{dau0.vx(), dau0.vy(), dau0.vz()}; + const std::array vtxPV{mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()}; + decayLengthGen = RecoDecay::distance(vtxPV, vtxDau); + } + // Fill table + if (origin == RecoDecay::OriginType::NonPrompt) { + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); + rowMcMatchGen(flag, origin, bHadMother.pdgCode(), decayLengthGen); + } else { + rowMcMatchGen(flag, origin, 0, decayLengthGen); + } + } // close loop over generated particles + } // close loop over McCollisions + } // close template function + + void processMc(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions, + McCollisionsNoCents const& mcCollisionsNoCents, + BCsInfo const& bcs) + { + runMcMatching(tracks, mcParticles, mcCollisions, mcCollisionsNoCents, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPiExpressions, processMc, "Perform MC matching with no centrality selection.", true); + + void processMcCentFT0C(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions, + McCollisionsFT0Cs const& mcCollisionsFT0Cs, + BCsInfo const& bcs) + { + runMcMatching(tracks, mcParticles, mcCollisions, mcCollisionsFT0Cs, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPiExpressions, processMcCentFT0C, "Perform MC matching with centrality selection on FT0C.", false); - rowMcMatchGen(flag, debug, origin); - } // close loop over generated particles - } // close process - PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPiExpressions, processMc, "Process MC", false); + void processMcCentFT0M(aod::TracksWMc const& tracks, + aod::McParticles const& mcParticles, + McCollisionsCentFT0Ms const& mcCollisionsCentFT0Ms, + McCollisionsFT0Ms const& mcCollisionsFT0Ms, + BCsInfo const& bcs) + { + runMcMatching(tracks, mcParticles, mcCollisionsCentFT0Ms, mcCollisionsFT0Ms, bcs); + } + PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPiExpressions, processMcCentFT0M, "Perform MC matching with centrality selection on FT0M.", false); }; // close struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/candidateCreatorXicc.cxx b/PWGHF/TableProducer/candidateCreatorXicc.cxx index 214c2cea891..cde56b878aa 100644 --- a/PWGHF/TableProducer/candidateCreatorXicc.cxx +++ b/PWGHF/TableProducer/candidateCreatorXicc.cxx @@ -17,17 +17,36 @@ /// \author Luigi Dello Stritto , SALERNO /// \author Mattia Faggin , University and INFN PADOVA -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisTask.h" -#include "ReconstructionDataFormats/DCA.h" -#include "ReconstructionDataFormats/V0.h" - -#include "Common/Core/trackUtilities.h" - +#include "PWGHF/ALICE3/Core/DecayChannelsLegacy.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -37,11 +56,11 @@ using namespace o2::framework::expressions; void customize(std::vector& workflowOptions) { - ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, true, {"Perform MC matching."}}; + ConfigParamSpec const optionDoMC{"doMC", VariantType::Bool, true, {"Perform MC matching."}}; workflowOptions.push_back(optionDoMC); } -#include "Framework/runDataProcessing.h" +#include /// Reconstruction of xicc candidates struct HfCandidateCreatorXicc { @@ -62,12 +81,6 @@ struct HfCandidateCreatorXicc { o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter to rebuild the Xic vertex o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter to build the Xicc vertex - HfHelper hfHelper; - - double massPi{0.}; - double massK{0.}; - double massXic{0.}; - double massXicc{0.}; Filter filterSelectCandidates = (aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlagXic || aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlagXic); @@ -77,10 +90,6 @@ struct HfCandidateCreatorXicc { void init(InitContext const&) { - massPi = MassPiPlus; - massK = MassKPlus; - massXic = MassXiCPlus; - df3.setBz(bz); df3.setPropagateToPCA(propagateToPCA); df3.setMaxR(maxR); @@ -105,14 +114,14 @@ struct HfCandidateCreatorXicc { aod::TracksWCov const& tracks) { for (const auto& xicCand : xicCands) { - if (!(xicCand.hfflag() & 1 << o2::aod::hf_cand_3prong::XicToPKPi)) { + if ((xicCand.hfflag() & 1 << o2::aod::hf_cand_3prong::DecayType::XicToPKPi) == 0) { continue; } if (xicCand.isSelXicToPKPi() >= selectionFlagXic) { - hMassXic->Fill(hfHelper.invMassXicToPKPi(xicCand), xicCand.pt()); + hMassXic->Fill(HfHelper::invMassXicToPKPi(xicCand), xicCand.pt()); } if (xicCand.isSelXicToPiKP() >= selectionFlagXic) { - hMassXic->Fill(hfHelper.invMassXicToPiKP(xicCand), xicCand.pt()); + hMassXic->Fill(HfHelper::invMassXicToPiKP(xicCand), xicCand.pt()); } auto track0 = xicCand.prong0_as(); auto track1 = xicCand.prong1_as(); @@ -131,15 +140,15 @@ struct HfCandidateCreatorXicc { trackParVar1.propagateTo(secondaryVertex[0], bz); trackParVar2.propagateTo(secondaryVertex[0], bz); - std::array pvecpK = RecoDecay::pVec(track0.pVector(), track1.pVector()); + std::array const pvecpK = RecoDecay::pVec(track0.pVector(), track1.pVector()); std::array pvecxic = RecoDecay::pVec(pvecpK, track2.pVector()); auto trackpK = o2::dataformats::V0(df3.getPCACandidatePos(), pvecpK, df3.calcPCACovMatrixFlat(), trackParVar0, trackParVar1); auto trackxic = o2::dataformats::V0(df3.getPCACandidatePos(), pvecxic, df3.calcPCACovMatrixFlat(), trackpK, trackParVar2); - int index0Xic = track0.globalIndex(); - int index1Xic = track1.globalIndex(); - int index2Xic = track2.globalIndex(); - int charge = track0.sign() + track1.sign() + track2.sign(); + int const index0Xic = track0.globalIndex(); + int const index1Xic = track1.globalIndex(); + int const index2Xic = track2.globalIndex(); + int const charge = track0.sign() + track1.sign() + track2.sign(); for (const auto& trackpion : tracks) { if (trackpion.pt() < cutPtPionMin) { @@ -151,7 +160,7 @@ struct HfCandidateCreatorXicc { if (trackpion.globalIndex() == index0Xic || trackpion.globalIndex() == index1Xic || trackpion.globalIndex() == index2Xic) { continue; } - std::array pvecpion; + std::array pvecpion{}; auto trackParVarPi = getTrackParCov(trackpion); // reconstruct the 3-prong X vertex @@ -195,9 +204,9 @@ struct HfCandidateCreatorXicc { xicCand.globalIndex(), trackpion.globalIndex(), hfFlag); } // if on selected Xicc - } // loop over candidates - } // end of process -}; // end of struct + } // loop over candidates + } // end of process +}; // end of struct /// Extends the base table with expression columns. struct HfCandidateCreatorXiccExpressions { @@ -216,17 +225,15 @@ struct HfCandidateCreatorXiccMc { aod::TracksWMc const&, aod::McParticles const& mcParticles) { - int indexRec = -1; int8_t sign = 0; - int8_t flag = 0; - int8_t origin = 0; - int8_t debug = 0; + int8_t flag; + int8_t origin; // Match reconstructed candidates. for (const auto& candidate : candidates) { + int8_t debug = 0; flag = 0; origin = 0; - debug = 0; auto xicCand = candidate.prong0(); auto arrayDaughters = std::array{xicCand.prong0_as(), xicCand.prong1_as(), @@ -236,7 +243,7 @@ struct HfCandidateCreatorXiccMc { xicCand.prong1_as(), xicCand.prong2_as()}; // Ξcc±± → p± K∓ π± π± - indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCCPlusPlus, std::array{+kProton, -kKPlus, +kPiPlus, +kPiPlus}, true, &sign, 2); + auto indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, Pdg::kXiCCPlusPlus, std::array{+kProton, -kKPlus, +kPiPlus, +kPiPlus}, true, &sign, 2); if (indexRec > -1) { // Ξc± → p± K∓ π± indexRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughtersXic, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 1); diff --git a/PWGHF/TableProducer/candidateSelectorB0ToDPi.cxx b/PWGHF/TableProducer/candidateSelectorB0ToDPi.cxx index 985be6f5aa6..c083d530baf 100644 --- a/PWGHF/TableProducer/candidateSelectorB0ToDPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorB0ToDPi.cxx @@ -14,29 +14,55 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" - -#include "Common/Core/TrackSelectorPID.h" - #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseB0ToDPi.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/TrackSelectorPID.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::analysis; +using namespace o2::aod::pid_tpc_tof_utils; struct HfCandidateSelectorB0ToDPi { Produces hfSelB0ToDPiCandidate; // table defined in CandidateSelectionTables.h + Produces hfMlB0ToDPiCandidate; // 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", PidMethod::TpcOrTof, "PID selection method for the bachelor pion (PidMethod::NoPid: none, PidMethod::TpcOrTof: TPC or TOF, PidMethod::TpcAndTof: 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,22 +76,49 @@ 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"}; + // 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"}; - // check if selectionFlagD (defined in candidateCreatorB0.cxx) and usePid configurables are in sync + // 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", 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_B0/"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_B0ToDPi.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::HfMlResponseB0ToDPi hfMlResponse; + float outputMlNotPreselected = -1.; + std::vector outputMl; + o2::ccdb::CcdbApi ccdbApi; - bool selectionFlagDAndUsePidInSync = true; TrackSelectorPi selectorPion; - HfHelper hfHelper; - 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 >= PidMethod::NPidMethods) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (pionPidMethod != PidMethod::NoPid) { selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); @@ -81,6 +134,7 @@ struct HfCandidateSelectorB0ToDPi { 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) { @@ -88,76 +142,129 @@ struct HfCandidateSelectorB0ToDPi { } } - int selectionFlagD = -1; - auto& workflows = initContext.services().get(); - for (const DeviceSpec& device : workflows.devices) { - if (device.name.compare("hf-candidate-creator-b0") == 0) { - for (const auto& option : device.options) { - if (option.name.compare("selectionFlagD") == 0) { - selectionFlagD = option.defaultValue.get(); - LOGF(info, "selectionFlagD = %d", selectionFlagD); - } - } + if (applyB0Ml) { + hfMlResponse.configure(binsPtB0Ml, cutsB0Ml, cutDirB0Ml, nClassesB0Ml); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponse.setModelPathsLocal(onnxFileNames); } - } - - if (usePid && !TESTBIT(selectionFlagD, SelectionStep::RecoPID)) { - selectionFlagDAndUsePidInSync = false; - LOG(warning) << "PID selections required on B0 daughters (usePid=true) but no PID selections on D candidates were required a priori (selectionFlagD<7). Set selectionFlagD=7 in hf-candidate-creator-b0"; - } - if (!usePid && TESTBIT(selectionFlagD, SelectionStep::RecoPID)) { - selectionFlagDAndUsePidInSync = false; - LOG(warning) << "No PID selections required on B0 daughters (usePid=false) but PID selections on D candidates were required a priori (selectionFlagD=7). Set selectionFlagD<7 in hf-candidate-creator-b0"; + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); } } - void process(aod::HfCandB0 const& hfCandsB0, - TracksPidWithSel const&) + /// Main function to perform B0 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 hfCandsB0 B0 candidates + /// \param pionTracks pion tracks + template + void runSelection(Cands const& hfCandsB0, + CandsDmes const& /*hfCandsD*/, + TracksPion const& /*pionTracks*/) { + for (const auto& hfCandB0 : hfCandsB0) { - int statusB0ToDPi = 0; + int statusB0 = 0; auto ptCandB0 = hfCandB0.pt(); - SETBIT(statusB0ToDPi, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusB0ToDPi = 1 + SETBIT(statusB0, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusB0 = 1 if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandB0); } // topological cuts - if (!hfHelper.selectionB0ToDPiTopol(hfCandB0, cuts, binsPt)) { - hfSelB0ToDPiCandidate(statusB0ToDPi); + if (!HfHelper::selectionB0ToDPiTopol(hfCandB0, cuts, binsPt)) { + hfSelB0ToDPiCandidate(statusB0); + if (applyB0Ml) { + hfMlB0ToDPiCandidate(outputMlNotPreselected); + } // LOGF(info, "B0 candidate selection failed at topology selection"); continue; } - SETBIT(statusB0ToDPi, SelectionStep::RecoTopol); // RecoTopol = 1 --> statusB0ToDPi = 3 + + auto trackPi = hfCandB0.template prong1_as(); + auto hfCandD = hfCandB0.template prong0_as(); + + std::vector mlScoresD; + if constexpr (WithDmesMl) { + std::copy(hfCandD.mlProbDplusToPiKPi().begin(), hfCandD.mlProbDplusToPiKPi().end(), std::back_inserter(mlScoresD)); + + if (!HfHelper::selectionDmesMlScoresForB(hfCandD, cutsDmesMl, binsPtDmesMl, mlScoresD)) { + hfSelB0ToDPiCandidate(statusB0); + if (applyB0Ml) { + hfMlB0ToDPiCandidate(outputMlNotPreselected); + } + // LOGF(info, "B0 candidate selection failed at D-meson ML selection"); + continue; + } + } + + SETBIT(statusB0, SelectionStep::RecoTopol); // RecoTopol = 1 --> statusB0 = 3 if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoTopol, ptCandB0); } - // checking if selectionFlagD and usePid are in sync - if (!selectionFlagDAndUsePidInSync) { - hfSelB0ToDPiCandidate(statusB0ToDPi); - continue; - } // track-level PID selection - if (usePid) { - auto trackPi = hfCandB0.prong1_as(); - int pidTrackPi = selectorPion.statusTpcAndTof(trackPi); - if (!hfHelper.selectionB0ToDPiPid(pidTrackPi, acceptPIDNotApplicable.value)) { + if (pionPidMethod == PidMethod::TpcOrTof || pionPidMethod == PidMethod::TpcAndTof) { + int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; + if (pionPidMethod == PidMethod::TpcOrTof) { + pidTrackPi = selectorPion.statusTpcOrTof(trackPi); + } else if (pionPidMethod == PidMethod::TpcAndTof) { + pidTrackPi = selectorPion.statusTpcAndTof(trackPi); + } + if (!HfHelper::selectionB0ToDPiPid(pidTrackPi, acceptPIDNotApplicable.value)) { // LOGF(info, "B0 candidate selection failed at PID selection"); - hfSelB0ToDPiCandidate(statusB0ToDPi); + hfSelB0ToDPiCandidate(statusB0); + if (applyB0Ml) { + hfMlB0ToDPiCandidate(outputMlNotPreselected); + } continue; } - SETBIT(statusB0ToDPi, SelectionStep::RecoPID); // RecoPID = 2 --> statusB0ToDPi = 7 + SETBIT(statusB0, SelectionStep::RecoPID); // RecoPID = 2 --> statusB0 = 7 if (activateQA) { registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandB0); } } + if (applyB0Ml) { + // B0 ML selections + std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandB0, trackPi, &mlScoresD); + bool const isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandB0, outputMl); + hfMlB0ToDPiCandidate(outputMl[1]); // storing ML score for signal class + + if (!isSelectedMl) { + hfSelB0ToDPiCandidate(statusB0); + continue; + } + SETBIT(statusB0, SelectionStep::RecoMl); // RecoML = 3 --> statusB0 = 15 if pionPidMethod, 11 otherwise + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoMl, ptCandB0); + } + } - hfSelB0ToDPiCandidate(statusB0ToDPi); + hfSelB0ToDPiCandidate(statusB0); // LOGF(info, "B0 candidate selection passed all selections"); } } + + void processSelection(HfCandB0 const& hfCandsB0, + aod::HfCand3ProngWPidPiKa const& hfCandsD, + TracksPion const& pionTracks) + { + runSelection(hfCandsB0, hfCandsD, pionTracks); + } // processSelection + + PROCESS_SWITCH(HfCandidateSelectorB0ToDPi, processSelection, "Process selection without ML scores of D mesons", true); + + void processSelectionWithDmesMl(HfCandB0 const& hfCandsB0, + soa::Join const& hfCandsD, + TracksPion const& pionTracks) + { + runSelection(hfCandsB0, hfCandsD, pionTracks); + } // processSelectionWithDmesMl + + PROCESS_SWITCH(HfCandidateSelectorB0ToDPi, processSelectionWithDmesMl, "Process selection with ML scores of D mesons", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/candidateSelectorBplusToD0Pi.cxx b/PWGHF/TableProducer/candidateSelectorBplusToD0Pi.cxx index e8589833f9e..7b51a915c4c 100644 --- a/PWGHF/TableProducer/candidateSelectorBplusToD0Pi.cxx +++ b/PWGHF/TableProducer/candidateSelectorBplusToD0Pi.cxx @@ -10,63 +10,118 @@ // 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 - -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" - -#include "Common/Core/TrackSelectorPID.h" +/// \author Nima Zardoshti , CERN #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/HfMlResponseBplusToD0Pi.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsPid.h" + +#include "Common/Core/TrackSelectorPID.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::analysis; +using namespace o2::aod::pid_tpc_tof_utils; 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", PidMethod::TpcOrTof, "PID selection method for the bachelor pion (PidMethod::NoPid: none, PidMethod::TpcOrTof: TPC or TOF, PidMethod::TpcAndTof: 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; - 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 >= PidMethod::NPidMethods) { + LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); + } + + if (pionPidMethod != PidMethod::NoPid) { selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); @@ -82,6 +137,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,104 +145,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); } + hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponse.init(); } - 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."; - } - } - - /// 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) - { - 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&) + /// 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*/) { - 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(); 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 == PidMethod::TpcOrTof || pionPidMethod == PidMethod::TpcAndTof) { + int pidTrackPi{TrackSelectorPID::Status::NotApplicable}; + if (pionPidMethod == PidMethod::TpcOrTof) { + pidTrackPi = selectorPion.statusTpcOrTof(trackPi); + } else if (pionPidMethod == PidMethod::TpcAndTof) { + 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 const 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..eee6a06b93f 100644 --- a/PWGHF/TableProducer/candidateSelectorBsToDsPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorBsToDsPi.cxx @@ -15,18 +15,38 @@ /// /// \author Phil Stahlhut -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" - -#include "Common/Core/TrackSelectorPID.h" - #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponse.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/TrackSelectorPID.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -51,19 +71,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"}; @@ -71,12 +91,11 @@ struct HfCandidateSelectorBsToDsPi { bool selectionFlagDsAndUsePidInSync = true; o2::analysis::HfMlResponse hfMlResponse; - std::vector outputMl = {}; + std::vector outputMl; o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; - HfHelper hfHelper; using TracksPidWithSel = soa::Join; @@ -116,15 +135,14 @@ struct HfCandidateSelectorBsToDsPi { hfMlResponse.setModelPathsLocal(onnxFileNames); } hfMlResponse.init(); - outputMl.assign(((std::vector)cutDirMl).size(), -1.f); // dummy value for ML output } int selectionFlagDs = -1; - auto& workflows = initContext.services().get(); + const auto& workflows = initContext.services().get(); for (const DeviceSpec& device : workflows.devices) { - if (device.name.compare("hf-candidate-creator-bs") == 0) { + if (device.name == "hf-candidate-creator-bs") { for (const auto& option : device.options) { - if (option.name.compare("selectionFlagDs") == 0) { + if (option.name == "selectionFlagDs") { selectionFlagDs = option.defaultValue.get(); LOGF(info, "selectionFlagDs = %d", selectionFlagDs); } @@ -147,26 +165,16 @@ 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); } // topological cuts - if (!hfHelper.selectionBsToDsPiTopol(hfCandBs, cuts, binsPt)) { + if (!HfHelper::selectionBsToDsPiTopol(hfCandBs, cuts, binsPt)) { hfSelBsToDsPiCandidate(statusBsToDsPi); if (applyMl) { hfMlBsToDsPiCandidate(outputMl); @@ -189,8 +197,8 @@ struct HfCandidateSelectorBsToDsPi { // track-level PID selection if (usePid) { auto trackPi = hfCandBs.prong1_as(); - int pidTrackPi = selectorPion.statusTpcAndTof(trackPi); - if (!hfHelper.selectionBsToDsPiPid(pidTrackPi, acceptPIDNotApplicable.value)) { + int const pidTrackPi = selectorPion.statusTpcAndTof(trackPi); + if (!HfHelper::selectionBsToDsPiPid(pidTrackPi, acceptPIDNotApplicable.value)) { hfSelBsToDsPiCandidate(statusBsToDsPi); if (applyMl) { hfMlBsToDsPiCandidate(outputMl); @@ -215,7 +223,7 @@ struct HfCandidateSelectorBsToDsPi { hfCandBs.maxNormalisedDeltaIP(), hfCandBs.impactParameterProduct()}; - bool isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandBs, outputMl); + bool const isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCandBs, outputMl); hfMlBsToDsPiCandidate(outputMl); if (!isSelectedMl) { diff --git a/PWGHF/TableProducer/candidateSelectorCd.cxx b/PWGHF/TableProducer/candidateSelectorCd.cxx new file mode 100644 index 00000000000..eb5173c3570 --- /dev/null +++ b/PWGHF/TableProducer/candidateSelectorCd.cxx @@ -0,0 +1,378 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file candidateSelectorCd.cxx +/// \brief Cd± → d± K∓ π± selection task +/// +/// \author Biao Zhang , Heidelberg Universiity + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; + +/// Struct for applying Cd selection cuts +struct HfCandidateSelectorCd { + Produces hfSelCdCandidate; + + 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 based on nSigma cut at filtering level"}; + // TPC PID + Configurable ptPidTpcMin{"ptPidTpcMin", 0.1, "Lower bound of track pT for TPC PID"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 1., "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"}; + // TOF PID + Configurable ptPidTofMin{"ptPidTofMin", 0.5, "Lower bound of track pT for TOF PID"}; + Configurable ptPidTofMax{"ptPidTofMax", 2.5, "Upper bound of track pT for TOF PID"}; + Configurable nSigmaTofMax{"nSigmaTofMax", 3., "Nsigma cut on TOF only"}; + Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; + // 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_cd_to_de_k_pi::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_cd_to_de_k_pi::Cuts[0], hf_cuts_cd_to_de_k_pi::NBinsPt, hf_cuts_cd_to_de_k_pi::NCutVars, hf_cuts_cd_to_de_k_pi::labelsPt, hf_cuts_cd_to_de_k_pi::labelsCutVar}, "Cd candidate selection per pT bin"}; + // QA switch + Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; + + TrackSelectorPi selectorPion; + TrackSelectorKa selectorKaon; + TrackSelectorDe selectorDeuteron; + + const float massCharmDeuteron = 3.23; // possible mass + + using TracksSel = soa::Join; + + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + + selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); + selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); + selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); + selectorPion.setRangePtTof(ptPidTofMin, ptPidTofMax); + selectorPion.setRangeNSigmaTof(-nSigmaTofMax, nSigmaTofMax); + selectorPion.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedMax, nSigmaTofCombinedMax); + selectorKaon = selectorPion; + selectorDeuteron = selectorPion; + + if (activateQA) { + constexpr int kNBinsSelections = 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"; + 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()); + } + } + } + + /// 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 + /// \param candidate is candidate + /// \return true if candidate passes all cuts + template + bool selectionTopol(const T& candidate) + { + auto ptCand = candidate.pt(); + + int const binPt = findBin(binsPt, ptCand); + if (binPt == -1) { + return false; + } + + // check that the candidate pT is within the analysis range + if (ptCand < ptCandMin || ptCand >= ptCandMax) { + return false; + } + + // cosine of pointing angle + if (candidate.cpa() <= cuts->get(binPt, "cos pointing angle")) { + return false; + } + + // candidate chi2PCA + if (candidate.chi2PCA() > cuts->get(binPt, "Chi2PCA")) { + return false; + } + + if (candidate.decayLength() <= cuts->get(binPt, "decay length")) { + return false; + } + + // candidate decay length XY + if (candidate.decayLengthXY() <= cuts->get(binPt, "decLengthXY")) { + return false; + } + + // candidate normalized decay length XY + if (candidate.decayLengthXYNormalised() < cuts->get(binPt, "normDecLXY")) { + return false; + } + + // candidate impact parameter XY + if (std::abs(candidate.impactParameterXY()) > cuts->get(binPt, "impParXY")) { + return false; + } + + if (!isSelectedCandidateProngDca(candidate)) { + return false; + } + + return true; + } + + /// Conjugate-dependent topological cuts + /// \param candidate is candidate + /// \param trackDeuteron is the track with the deuteron hypothesis + /// \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 + bool selectionTopolConjugate(const T1& candidate, const T2& trackDeuteron, const T2& trackKaon, const T2& trackPion) + { + + auto ptCand = candidate.pt(); + int const binPt = findBin(binsPt, ptCand); + if (binPt == -1) { + return false; + } + + // cut on daughter pT + if (trackDeuteron.pt() < cuts->get(binPt, "pT De") || trackKaon.pt() < cuts->get(binPt, "pT K") || trackPion.pt() < cuts->get(binPt, "pT Pi")) { + return false; + } + + float massCd{0.f}; + if (trackDeuteron.globalIndex() == candidate.prong0Id()) { + massCd = HfHelper::invMassCdToDeKPi(candidate); + } else { + massCd = HfHelper::invMassCdToPiKDe(candidate); + } + + // cut on Cd->deKpi, piKde mass values + if (std::abs(massCd - massCharmDeuteron) > cuts->get(binPt, "m")) { + return false; + } + + return true; + } + + /// Single-track dca_xy and dca_z cuts + /// \param candidate is the Cd 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 pidTrackDeuteron is the PID status of deuteron 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 pidTrackDeuteron, const TrackSelectorPID::Status pidTrackKaon, const TrackSelectorPID::Status pidTrackPion) + { + return pidTrackDeuteron != TrackSelectorPID::Rejected && + pidTrackKaon != TrackSelectorPID::Rejected && + pidTrackPion != TrackSelectorPID::Rejected; + } + + /// \brief function to apply Cd selections + /// \param reconstructionType is the reconstruction type (DCAFitterN ) + /// \param candidates Cd candidate table + /// \param tracks track table + template + void runSelectCd(CandType const& candidates, TTracks const&) + { + // looping over 3-prong candidates + for (const auto& candidate : candidates) { + + // final selection flag + auto statusCdToDeKPi = 0; + auto statusCdToPiKDe = 0; + + auto ptCand = candidate.pt(); + + if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::CdToDeKPi)) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + if (activateQA) { + registry.fill(HIST("hSelections"), 1, ptCand); + } + continue; + } + + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoSkims, ptCand); + } + + 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 const trackQualitySel = isSelectedCandidateProngQuality(trackPos1, trackNeg, trackPos2); + if (!trackQualitySel) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + continue; + } + + // conjugate-independent topological selection + if (!selectionTopol(candidate)) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + continue; + } + + // conjugate-dependent topological selection for Cd + bool const topolCdToDeKPi = selectionTopolConjugate(candidate, trackPos1, trackNeg, trackPos2); + bool const topolCdToPiKDe = selectionTopolConjugate(candidate, trackPos2, trackNeg, trackPos1); + + if (!topolCdToDeKPi && !topolCdToPiKDe) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + continue; + } + + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoTopol, candidate.pt()); + } + + // PID not applied, accepted by default + auto pidCdToDeKPi = 1; + auto pidCdToPiKDe = 1; + + if (usePid) { + // track-level PID selection + TrackSelectorPID::Status pidTrackPos1Deuteron; + TrackSelectorPID::Status pidTrackPos2Deuteron; + TrackSelectorPID::Status pidTrackPos1Pion; + TrackSelectorPID::Status pidTrackPos2Pion; + TrackSelectorPID::Status pidTrackNegKaon; + if (usePidTpcAndTof) { + pidTrackPos1Deuteron = selectorDeuteron.statusTpcAndTof(trackPos1, candidate.nSigTpcDe0(), candidate.nSigTofDe0()); + pidTrackPos2Deuteron = selectorDeuteron.statusTpcAndTof(trackPos2, candidate.nSigTpcDe2(), candidate.nSigTofDe2()); + pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + } else { + pidTrackPos1Deuteron = selectorDeuteron.statusTpcOrTof(trackPos1, candidate.nSigTpcDe0(), candidate.nSigTofDe0()); + pidTrackPos2Deuteron = selectorDeuteron.statusTpcOrTof(trackPos2, candidate.nSigTpcDe2(), candidate.nSigTofDe2()); + pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + } + + if (!isSelectedPID(pidTrackPos1Deuteron, pidTrackNegKaon, pidTrackPos2Pion)) { + pidCdToDeKPi = 0; // reject CdToDeKPi + } + if (!isSelectedPID(pidTrackPos2Deuteron, pidTrackNegKaon, pidTrackPos1Pion)) { + pidCdToPiKDe = 0; // accept CdToPiKDe + } + } + + if (pidCdToDeKPi == 0 && pidCdToPiKDe == 0) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + continue; + } + + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoPID, candidate.pt()); + } + + if (pidCdToDeKPi == 1 && topolCdToDeKPi && trackQualitySel) { + statusCdToDeKPi = 1; // identified as CdToDeKPi + } + if (pidCdToPiKDe == 1 && topolCdToPiKDe && trackQualitySel) { + statusCdToPiKDe = 1; // identified as CdToPiKDe + } + + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + } + } + + /// \brief process function with DCAFitterN + /// \param candidates Cd candidate table + /// \param tracks track table + void processCdWithDCAFitterN(aod::HfCand3ProngWPidPiKaDe const& candidates, + TracksSel const& tracks) + { + runSelectCd(candidates, tracks); + } + PROCESS_SWITCH(HfCandidateSelectorCd, processCdWithDCAFitterN, "Process Cd selection with DCAFitterN", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateSelectorD0.cxx b/PWGHF/TableProducer/candidateSelectorD0.cxx index 3254d513237..8d72e1c2b3a 100644 --- a/PWGHF/TableProducer/candidateSelectorD0.cxx +++ b/PWGHF/TableProducer/candidateSelectorD0.cxx @@ -15,17 +15,35 @@ /// \author Nima Zardoshti , CERN /// \author Vít Kučera , CERN -#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/HfMlResponse.h" #include "PWGHF/Core/HfMlResponseD0ToKPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -52,18 +70,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 @@ -72,14 +98,16 @@ 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 = {}; - std::vector outputMlD0bar = {}; + std::vector outputMlD0; + std::vector outputMlD0bar; o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; TrackSelectorKa selectorKaon; - HfHelper hfHelper; + HfTrigger2ProngCuts hfTriggerCuts; using TracksSel = soa::Join; @@ -124,11 +152,28 @@ 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 /// \return true if candidate passes all cuts - template + template bool selectionTopol(const T& candidate) { auto candpT = candidate.pt(); @@ -158,7 +203,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) { @@ -187,7 +234,7 @@ struct HfCandidateSelectorD0 { /// \param trackKaon is the track with the kaon hypothesis /// \note trackPion = positive and trackKaon = negative for D0 selection and inverse for D0bar /// \return true if candidate passes all cuts for the given Conjugate - template + template bool selectionTopolConjugate(const T1& candidate, const T2& trackPion, const T2& trackKaon) { auto candpT = candidate.pt(); @@ -198,21 +245,27 @@ struct HfCandidateSelectorD0 { // invariant-mass cut float massD0, massD0bar; - if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { massD0 = candidate.kfGeoMassD0(); massD0bar = candidate.kfGeoMassD0bar(); } else { - massD0 = hfHelper.invMassD0ToPiK(candidate); - massD0bar = hfHelper.invMassD0barToKPi(candidate); + massD0 = HfHelper::invMassD0ToPiK(candidate); + massD0bar = HfHelper::invMassD0barToKPi(candidate); } if (trackPion.sign() > 0) { 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 @@ -227,11 +280,11 @@ struct HfCandidateSelectorD0 { // cut on cos(theta*) if (trackPion.sign() > 0) { - if (std::abs(hfHelper.cosThetaStarD0(candidate)) > cuts->get(pTBin, "cos theta*")) { + if (std::abs(HfHelper::cosThetaStarD0(candidate)) > cuts->get(pTBin, "cos theta*")) { return false; } } else { - if (std::abs(hfHelper.cosThetaStarD0bar(candidate)) > cuts->get(pTBin, "cos theta*")) { + if (std::abs(HfHelper::cosThetaStarD0bar(candidate)) > cuts->get(pTBin, "cos theta*")) { return false; } } @@ -239,11 +292,11 @@ struct HfCandidateSelectorD0 { // in case only sideband candidates have to be stored, additional invariant-mass cut if (keepOnlySidebandCandidates) { if (trackPion.sign() > 0) { - if (std::abs(hfHelper.invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) < distanceFromD0MassForSidebands) { + if (std::abs(HfHelper::invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) < distanceFromD0MassForSidebands) { return false; } } else { - if (std::abs(hfHelper.invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) < distanceFromD0MassForSidebands) { + if (std::abs(HfHelper::invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) < distanceFromD0MassForSidebands) { return false; } } @@ -251,7 +304,7 @@ struct HfCandidateSelectorD0 { return true; } - template + template void processSel(CandType const& candidates, TracksSel const&) { @@ -282,8 +335,17 @@ 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)) { + if (!selectionTopol(candidate)) { hfSelD0Candidate(statusD0, statusD0bar, statusHFFlag, statusTopol, statusCand, statusPID); if (applyMl) { hfMlD0Candidate(outputMlD0, outputMlD0bar); @@ -296,9 +358,9 @@ struct HfCandidateSelectorD0 { // need to add special cuts (additional cuts on decay length and d0 norm) // conjugate-dependent topological selection for D0 - bool topolD0 = selectionTopolConjugate(candidate, trackPos, trackNeg); + bool const topolD0 = selectionTopolConjugate(candidate, trackPos, trackNeg); // conjugate-dependent topological selection for D0bar - bool topolD0bar = selectionTopolConjugate(candidate, trackNeg, trackPos); + bool const topolD0bar = selectionTopolConjugate(candidate, trackNeg, trackPos); if (!topolD0 && !topolD0bar) { hfSelD0Candidate(statusD0, statusD0bar, statusHFFlag, statusTopol, statusCand, statusPID); @@ -317,20 +379,32 @@ struct HfCandidateSelectorD0 { int pidTrackNegPion = -1; if (usePidTpcOnly) { - pidTrackPosKaon = selectorKaon.statusTpc(trackPos); - pidTrackPosPion = selectorPion.statusTpc(trackPos); - pidTrackNegKaon = selectorKaon.statusTpc(trackNeg); - pidTrackNegPion = selectorPion.statusTpc(trackNeg); + /// 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) { - pidTrackPosKaon = selectorKaon.statusTpcAndTof(trackPos); - pidTrackPosPion = selectorPion.statusTpcAndTof(trackPos); - pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg); - pidTrackNegPion = selectorPion.statusTpcAndTof(trackNeg); + /// 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 { - pidTrackPosKaon = selectorKaon.statusTpcOrTof(trackPos); - pidTrackPosPion = selectorPion.statusTpcOrTof(trackPos); - pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); - pidTrackNegPion = selectorPion.statusTpcOrTof(trackNeg); + /// 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); @@ -384,11 +458,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); } @@ -406,13 +480,13 @@ struct HfCandidateSelectorD0 { registry.fill(HIST("DebugBdt/hBdtScore1VsStatus"), outputMlD0[0], statusD0); registry.fill(HIST("DebugBdt/hBdtScore2VsStatus"), outputMlD0[1], statusD0); registry.fill(HIST("DebugBdt/hBdtScore3VsStatus"), outputMlD0[2], statusD0); - registry.fill(HIST("DebugBdt/hMassDmesonSel"), hfHelper.invMassD0ToPiK(candidate)); + registry.fill(HIST("DebugBdt/hMassDmesonSel"), HfHelper::invMassD0ToPiK(candidate)); } if (isSelectedMlD0bar) { registry.fill(HIST("DebugBdt/hBdtScore1VsStatus"), outputMlD0bar[0], statusD0bar); registry.fill(HIST("DebugBdt/hBdtScore2VsStatus"), outputMlD0bar[1], statusD0bar); registry.fill(HIST("DebugBdt/hBdtScore3VsStatus"), outputMlD0bar[2], statusD0bar); - registry.fill(HIST("DebugBdt/hMassDmesonSel"), hfHelper.invMassD0barToKPi(candidate)); + registry.fill(HIST("DebugBdt/hMassDmesonSel"), HfHelper::invMassD0barToKPi(candidate)); } } } @@ -420,13 +494,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 326833bfa08..b66c7ac8540 100644 --- a/PWGHF/TableProducer/candidateSelectorDplusToPiKPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorDplusToPiKPi.cxx @@ -15,16 +15,36 @@ /// \author Fabio Catalano , Politecnico and INFN Torino /// \author Vít Kučera , CERN -#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/HfMlResponseDplusToPiKPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -53,9 +73,9 @@ 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> 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"}; @@ -63,8 +83,8 @@ struct HfCandidateSelectorDplusToPiKPi { 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 +92,16 @@ 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; - std::vector outputMlNotPreselected = {}; - std::vector outputMl = {}; + 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 +154,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 const 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 @@ -146,7 +168,10 @@ struct HfCandidateSelectorDplusToPiKPi { return false; } // invariant-mass cut - if (std::abs(hfHelper.invMassDplusToPiKPi(candidate) - o2::constants::physics::MassDPlus) > cuts->get(pTBin, "deltaM")) { + 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")) { @@ -205,7 +230,7 @@ struct HfCandidateSelectorDplusToPiKPi { return true; } - void process(aod::HfCand3Prong const& candidates, + void process(aod::HfCand3ProngWPidPiKa const& candidates, TracksSel const&) { // looping over 3-prong candidates @@ -254,13 +279,13 @@ struct HfCandidateSelectorDplusToPiKPi { int pidTrackPos2Pion = -1; if (usePidTpcAndTof) { - pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1); - pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg); - pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2); + pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); } else { - pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1); - pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); - pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2); + pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); } if (!selectionPID(pidTrackPos1Pion, pidTrackNegKaon, pidTrackPos2Pion)) { // exclude D± @@ -277,8 +302,8 @@ struct HfCandidateSelectorDplusToPiKPi { if (applyMl) { // ML selections - std::vector inputFeatures = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); - bool isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCand, outputMl); + std::vector inputFeatures = hfMlResponse.getInputFeatures(candidate); + bool const isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCand, outputMl); hfMlDplusToPiKPiCandidate(outputMl); if (!isSelectedMl) { diff --git a/PWGHF/TableProducer/candidateSelectorDsToKKPi.cxx b/PWGHF/TableProducer/candidateSelectorDsToKKPi.cxx index c32ffdfd711..bbe41e275fe 100644 --- a/PWGHF/TableProducer/candidateSelectorDsToKKPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorDsToKKPi.cxx @@ -15,16 +15,36 @@ /// \author Fabio Catalano , Universita and INFN Torino /// \author Stefano Politano , Politecnico and INFN Torino -#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/HfMlResponseDsToKKPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -51,9 +71,11 @@ 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"}; + 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"}; + 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 pT-dependent cut"}; // QA switch @@ -62,8 +84,8 @@ struct HfCandidateSelectorDsToKKPi { 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,14 +93,16 @@ 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; - std::vector outputMlDsToKKPi = {}; - std::vector outputMlDsToPiKK = {}; + std::vector outputMlDsToKKPi; + std::vector outputMlDsToPiKK; o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; TrackSelectorKa selectorKaon; + HfTrigger3ProngCuts hfTriggerCuts; using TracksSel = soa::Join; @@ -128,12 +152,9 @@ struct HfCandidateSelectorDsToKKPi { template bool isSelectedCandidateProngDca(const T1& candidate) { - 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; + return static_cast(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())); } /// Candidate selections independent from the daugther-mass hypothesis @@ -143,7 +164,7 @@ struct HfCandidateSelectorDsToKKPi { bool selection(const T1& candidate) { auto candpT = candidate.pt(); - int pTBin = findBin(binsPt, candpT); + int const pTBin = findBin(binsPt, candpT); if (pTBin == -1) { return false; } @@ -172,6 +193,9 @@ struct HfCandidateSelectorDsToKKPi { if (!isSelectedCandidateProngDca(candidate)) { return false; } + if (rejectCandsInDplusToPiKPiRegion && std::abs(HfHelper::invMassDplusToPiKPi(candidate) - o2::constants::physics::MassDPlus) < deltaMRegionDplusToPiKPi) { + return false; + } return true; } @@ -184,7 +208,7 @@ struct HfCandidateSelectorDsToKKPi { template bool selectionKKPi(const T1& candidate, const T2& trackKaon1, const T2& trackKaon2, const T2& trackPion) { - int pTBin = findBin(binsPt, candidate.pt()); + int const pTBin = findBin(binsPt, candidate.pt()); if (pTBin == -1) { return false; } @@ -192,13 +216,16 @@ struct HfCandidateSelectorDsToKKPi { if (trackKaon1.pt() < cuts->get(pTBin, "pT K") || trackKaon2.pt() < cuts->get(pTBin, "pT K") || trackPion.pt() < cuts->get(pTBin, "pT Pi")) { return false; } - if (std::abs(hfHelper.invMassDsToKKPi(candidate) - o2::constants::physics::MassDS) > cuts->get(pTBin, "deltaM")) { + if (std::abs(HfHelper::invMassDsToKKPi(candidate) - o2::constants::physics::MassDS) > cuts->get(pTBin, "deltaM")) { return false; } - if (hfHelper.deltaMassPhiDsToKKPi(candidate) > cuts->get(pTBin, "deltaM Phi")) { + if (useTriggerMassCut && !isCandidateInMassRange(HfHelper::invMassDsToKKPi(candidate), o2::constants::physics::MassDS, candidate.pt(), hfTriggerCuts)) { return false; } - if (hfHelper.absCos3PiKDsToKKPi(candidate) < cuts->get(pTBin, "cos^3 theta_PiK")) { + if (HfHelper::deltaMassPhiDsToKKPi(candidate) > cuts->get(pTBin, "deltaM Phi")) { + return false; + } + if (HfHelper::absCos3PiKDsToKKPi(candidate) < cuts->get(pTBin, "cos^3 theta_PiK")) { return false; } return true; @@ -213,7 +240,7 @@ struct HfCandidateSelectorDsToKKPi { template bool selectionPiKK(const T1& candidate, const T2& trackPion, const T2& trackKaon1, const T2& trackKaon2) { - int pTBin = findBin(binsPt, candidate.pt()); + int const pTBin = findBin(binsPt, candidate.pt()); if (pTBin == -1) { return false; } @@ -221,19 +248,22 @@ struct HfCandidateSelectorDsToKKPi { if (trackKaon1.pt() < cuts->get(pTBin, "pT K") || trackKaon2.pt() < cuts->get(pTBin, "pT K") || trackPion.pt() < cuts->get(pTBin, "pT Pi")) { return false; } - if (std::abs(hfHelper.invMassDsToPiKK(candidate) - o2::constants::physics::MassDS) > cuts->get(pTBin, "deltaM")) { + 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")) { + if (HfHelper::deltaMassPhiDsToPiKK(candidate) > cuts->get(pTBin, "deltaM Phi")) { return false; } - if (hfHelper.absCos3PiKDsToPiKK(candidate) < cuts->get(pTBin, "cos^3 theta_PiK")) { + if (HfHelper::absCos3PiKDsToPiKK(candidate) < cuts->get(pTBin, "cos^3 theta_PiK")) { return false; } return true; } - void process(aod::HfCand3Prong const& candidates, + void process(aod::HfCand3ProngWPidPiKa const& candidates, TracksSel const&) { // looping over 3-prong candidates @@ -246,7 +276,7 @@ struct HfCandidateSelectorDsToKKPi { outputMlDsToKKPi.clear(); outputMlDsToPiKK.clear(); - if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DsToKKPi)) { + if ((candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::DsToKKPi) == 0) { hfSelDsToKKPiCandidate(statusDsToKKPi, statusDsToPiKK); if (applyMl) { hfMlDsToKKPiCandidate(outputMlDsToKKPi, outputMlDsToPiKK); @@ -275,8 +305,8 @@ struct HfCandidateSelectorDsToKKPi { continue; } - bool topolDsToKKPi = selectionKKPi(candidate, trackPos1, trackNeg, trackPos2); - bool topolDsToPiKK = selectionPiKK(candidate, trackPos1, trackNeg, trackPos2); + bool const topolDsToKKPi = selectionKKPi(candidate, trackPos1, trackNeg, trackPos2); + bool const topolDsToPiKK = selectionPiKK(candidate, trackPos1, trackNeg, trackPos2); if (!topolDsToKKPi && !topolDsToPiKK) { hfSelDsToKKPiCandidate(statusDsToKKPi, statusDsToPiKK); if (applyMl) { @@ -302,26 +332,26 @@ struct HfCandidateSelectorDsToKKPi { int pidTrackNegKaon = -1; if (usePidTpcAndTof) { - pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1); - pidTrackPos1Kaon = selectorKaon.statusTpcAndTof(trackPos1); - pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2); - pidTrackPos2Kaon = selectorKaon.statusTpcAndTof(trackPos2); - pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg); + pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos1Kaon = selectorKaon.statusTpcAndTof(trackPos1, candidate.nSigTpcKa0(), candidate.nSigTofKa0()); + pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackPos2Kaon = selectorKaon.statusTpcAndTof(trackPos2, candidate.nSigTpcKa2(), candidate.nSigTofKa2()); + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); } else { - pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1); - pidTrackPos1Kaon = selectorKaon.statusTpcOrTof(trackPos1); - pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2); - pidTrackPos2Kaon = selectorKaon.statusTpcOrTof(trackPos2); - pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); + pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos1Kaon = selectorKaon.statusTpcOrTof(trackPos1, candidate.nSigTpcKa0(), candidate.nSigTofKa0()); + pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackPos2Kaon = selectorKaon.statusTpcOrTof(trackPos2, candidate.nSigTpcKa2(), candidate.nSigTofKa2()); + pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); } - bool pidDsToKKPi = !(pidTrackPos1Kaon == TrackSelectorPID::Rejected || - pidTrackNegKaon == TrackSelectorPID::Rejected || - pidTrackPos2Pion == TrackSelectorPID::Rejected); + bool const pidDsToKKPi = pidTrackPos1Kaon != TrackSelectorPID::Rejected && + pidTrackNegKaon != TrackSelectorPID::Rejected && + pidTrackPos2Pion != TrackSelectorPID::Rejected; - bool pidDsToPiKK = !(pidTrackPos1Pion == TrackSelectorPID::Rejected || - pidTrackNegKaon == TrackSelectorPID::Rejected || - pidTrackPos2Kaon == TrackSelectorPID::Rejected); + bool const pidDsToPiKK = pidTrackPos1Pion != TrackSelectorPID::Rejected && + pidTrackNegKaon != TrackSelectorPID::Rejected && + pidTrackPos2Kaon != TrackSelectorPID::Rejected; if (!pidDsToKKPi && !pidDsToPiKK) { hfSelDsToKKPiCandidate(statusDsToKKPi, statusDsToPiKK); @@ -346,11 +376,11 @@ struct HfCandidateSelectorDsToKKPi { bool isSelectedMlDsToPiKK = false; if (topolDsToKKPi && pidDsToKKPi) { - std::vector inputFeaturesDsToKKPi = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2, true); + std::vector inputFeaturesDsToKKPi = hfMlResponse.getInputFeatures(candidate, true); isSelectedMlDsToKKPi = hfMlResponse.isSelectedMl(inputFeaturesDsToKKPi, candidate.pt(), outputMlDsToKKPi); } if (topolDsToPiKK && pidDsToPiKK) { - std::vector inputFeaturesDsToPiKK = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2, false); + std::vector inputFeaturesDsToPiKK = hfMlResponse.getInputFeatures(candidate, false); isSelectedMlDsToPiKK = hfMlResponse.isSelectedMl(inputFeaturesDsToPiKK, candidate.pt(), outputMlDsToPiKK); } diff --git a/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx b/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx index 7f7f8501863..83098a40deb 100644 --- a/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx +++ b/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx @@ -15,21 +15,37 @@ /// \author Deependra Sharma , IITB /// \author Fabrizio Grosa , CERN -// O2 -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/Logger.h" -#include "Framework/runDataProcessing.h" -// O2Physics -#include "Common/Core/TrackSelectorPID.h" -// PWGHF #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponseDstarToD0Pi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsAnalysis.h" +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + using namespace o2; using namespace o2::constants::physics; using namespace o2::analysis; @@ -44,13 +60,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 @@ -74,13 +92,14 @@ struct HfCandidateSelectorDstarToD0Pi { // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; - // ML inference + // ML inference D* 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"}; + Configurable isTriggerBDT{"isTriggerBDT", false, "Flag to enable / disable features for software trigger BDTs"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -89,30 +108,24 @@ struct HfCandidateSelectorDstarToD0Pi { 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"}; - // PDG mass for kaon, pion and D0 - double massD0, massPi, massK; - - HfHelper hfHelper; o2::analysis::HfMlResponseDstarToD0Pi hfMlResponse; - std::vector outputMlDstarToD0Pi = {}; + std::vector outputMlDstarToD0Pi; o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; TrackSelectorKa selectorKaon; using TracksSel = soa::Join; - // using TracksSel = soa::Join; - using HfFullDstarCandidate = soa::Join; + using HfFullDstarCandidate = soa::Join; AxisSpec axisBdtScore{100, 0.f, 1.f}; AxisSpec axisSelStatus{2, -0.5f, 1.5f}; HistogramRegistry registry{"registry"}; + HfTrigger2ProngCuts hfTriggerCuts; + void init(InitContext&) { - massPi = MassPiPlus; - massK = MassKPlus; - massD0 = MassD0; selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); @@ -207,8 +220,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")) { @@ -218,10 +230,6 @@ struct HfCandidateSelectorDstarToD0Pi { return false; } - //.............Why is this if condition commented? - if (candidate.decayLengthNormalisedD0() * candidate.decayLengthNormalisedD0() < 1.0) { - // return false; // add back when getter fixed - } return true; } @@ -279,7 +287,10 @@ struct HfCandidateSelectorDstarToD0Pi { if (prongSoftPi.sign() > 0.) { // Selection of D*+ mInvDstar = candidate.invMassDstar(); mInvD0 = candidate.invMassD0(); - if (std::abs(mInvD0 - massD0) > cutsD0->get(binPt, "m")) { + 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 @@ -304,7 +315,10 @@ struct HfCandidateSelectorDstarToD0Pi { } else if (prongSoftPi.sign() < 0.) { // Selection of D*- mInvAntiDstar = candidate.invMassAntiDstar(); mInvD0Bar = candidate.invMassD0Bar(); - if (std::abs(mInvD0Bar - massD0) > cutsD0->get(binPt, "m")) { + 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 @@ -329,11 +343,11 @@ struct HfCandidateSelectorDstarToD0Pi { // in case only sideband candidates have to be stored, additional invariant-mass cut if (keepOnlySidebandCandidates && prongSoftPi.sign() > 0.) { - if (std::abs((mInvDstar - mInvD0) - massPi) < distanceFromDeltaMassForSidebands) { + if (std::abs((mInvDstar - mInvD0) - MassPiPlus) < distanceFromDeltaMassForSidebands) { return false; } } else if (keepOnlySidebandCandidates && prongSoftPi.sign() < 0.) { - if (std::abs((mInvAntiDstar - mInvD0Bar) - massPi) < distanceFromDeltaMassForSidebands) { + if (std::abs((mInvAntiDstar - mInvD0Bar) - MassPiPlus) < distanceFromDeltaMassForSidebands) { return false; } } @@ -352,10 +366,6 @@ struct HfCandidateSelectorDstarToD0Pi { outputMlDstarToD0Pi.clear(); auto ptCand = candDstar.pt(); - auto prongPi = candDstar.prongPi_as(); - auto prong0 = candDstar.prong0_as(); - auto prong1 = candDstar.prong1_as(); - if (!TESTBIT(candDstar.hfflag(), aod::hf_cand_2prong::DecayType::D0ToPiK)) { hfSelDstarCandidate(statusDstar, statusD0Flag, statusTopol, statusCand, statusPID); if (applyMl) { @@ -384,7 +394,7 @@ struct HfCandidateSelectorDstarToD0Pi { // need to add special cuts (additional cuts on decay length and d0 norm) // conjugate-dependent topological selection for Dstar - bool topoDstar = selectionTopolConjugate(candDstar); + bool const topoDstar = selectionTopolConjugate(candDstar); if (!topoDstar) { hfSelDstarCandidate(statusDstar, statusD0Flag, statusTopol, statusCand, statusPID); if (applyMl) { @@ -404,16 +414,18 @@ struct HfCandidateSelectorDstarToD0Pi { int pidTrackNegKaon = -1; int pidTrackNegPion = -1; + auto prong0 = candDstar.prong0_as(); + auto prong1 = candDstar.prong1_as(); if (usePidTpcAndTof) { - pidTrackPosKaon = selectorKaon.statusTpcAndTof(candDstar.prong0_as()); - pidTrackPosPion = selectorPion.statusTpcAndTof(candDstar.prong0_as()); - pidTrackNegKaon = selectorKaon.statusTpcAndTof(candDstar.prong1_as()); - pidTrackNegPion = selectorPion.statusTpcAndTof(candDstar.prong1_as()); + pidTrackPosKaon = selectorKaon.statusTpcAndTof(prong0, candDstar.nSigTpcKa0(), candDstar.nSigTofKa0()); + pidTrackPosPion = selectorPion.statusTpcAndTof(prong0, candDstar.nSigTpcPi0(), candDstar.nSigTofPi0()); + pidTrackNegKaon = selectorKaon.statusTpcAndTof(prong1, candDstar.nSigTpcKa1(), candDstar.nSigTofKa1()); + pidTrackNegPion = selectorPion.statusTpcAndTof(prong1, candDstar.nSigTpcPi1(), candDstar.nSigTofPi1()); } else { - pidTrackPosKaon = selectorKaon.statusTpcOrTof(candDstar.prong0_as()); - pidTrackPosPion = selectorPion.statusTpcOrTof(candDstar.prong0_as()); - pidTrackNegKaon = selectorKaon.statusTpcOrTof(candDstar.prong1_as()); - pidTrackNegPion = selectorPion.statusTpcOrTof(candDstar.prong1_as()); + pidTrackPosKaon = selectorKaon.statusTpcOrTof(prong0, candDstar.nSigTpcKa0(), candDstar.nSigTofKa0()); + pidTrackPosPion = selectorPion.statusTpcOrTof(prong0, candDstar.nSigTpcPi0(), candDstar.nSigTofPi0()); + pidTrackNegKaon = selectorKaon.statusTpcOrTof(prong1, candDstar.nSigTpcKa1(), candDstar.nSigTofKa1()); + pidTrackNegPion = selectorPion.statusTpcOrTof(prong1, candDstar.nSigTpcPi1(), candDstar.nSigTofPi1()); } int pidDstar = -1; @@ -451,8 +463,7 @@ struct HfCandidateSelectorDstarToD0Pi { if (applyMl) { // ML selections bool isSelectedMlDstar = false; - - std::vector inputFeatures = hfMlResponse.getInputFeatures(candDstar, prong0, prong1, prongPi); + std::vector inputFeatures = hfMlResponse.getInputFeatures(candDstar, !isTriggerBDT); isSelectedMlDstar = hfMlResponse.isSelectedMl(inputFeatures, ptCand, outputMlDstarToD0Pi); hfMlDstarCandidate(outputMlDstarToD0Pi); diff --git a/PWGHF/TableProducer/candidateSelectorLbToLcPi.cxx b/PWGHF/TableProducer/candidateSelectorLbToLcPi.cxx index 7ff5d21828d..3d63ebd0a77 100644 --- a/PWGHF/TableProducer/candidateSelectorLbToLcPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorLbToLcPi.cxx @@ -14,17 +14,27 @@ /// /// \author Panos Christakoglou , Nikhef -#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/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; @@ -50,20 +60,16 @@ struct HfCandidateSelectorLbToLcPi { 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> 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 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 * exp(-0.655 * pT)); - if (d0Resolution > expectedResolution * 1.5) - return false; - else - return true; + float const expectedResolution(0.001 + 0.0052 * std::exp(-0.655 * pT)); + return d0Resolution <= expectedResolution * 1.5; } // Compares to pT dependent cut on impact parameter resolution // Apply topological cuts as defined in SelectorCuts.h; return true if candidate passes all cuts @@ -71,7 +77,7 @@ struct HfCandidateSelectorLbToLcPi { bool selectionTopol(const T1& hfCandLb, const T2& hfCandLc, const T3& trackPi) { auto candpT = hfCandLb.pt(); - int pTBin = findBin(binsPt, candpT); + int const pTBin = findBin(binsPt, candpT); if (pTBin == -1) { // LOGF(debug, "Lb topol selection failed at getpTBin"); return false; @@ -83,7 +89,7 @@ struct HfCandidateSelectorLbToLcPi { } // Λb0 mass cut - if (std::abs(hfHelper.invMassLbToLcPi(hfCandLb) - o2::constants::physics::MassLambdaB0) > cuts->get(pTBin, "m")) { + 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; } @@ -99,17 +105,22 @@ struct HfCandidateSelectorLbToLcPi { } 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")) + 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) + if (hfCandLb.errorDecayLengthXY() > maxDecayLengthXYError) { return false; - if (hfCandLb.errorDecayLength() > maxDecayLengthError) + } + if (hfCandLb.errorDecayLength() > maxDecayLengthError) { return false; + } // Lb Decay length if (hfCandLb.decayLength() < cuts->get(pTBin, "Lb decLen")) { @@ -142,7 +153,12 @@ struct HfCandidateSelectorLbToLcPi { return false; } - return true; + // distance between Lb and Lc decay + float const diffXVert = hfCandLb.xSecondaryVertex() - hfCandLc.xSecondaryVertex(); + float const diffYVert = hfCandLb.ySecondaryVertex() - hfCandLc.ySecondaryVertex(); + float const diffZVert = hfCandLb.zSecondaryVertex() - hfCandLc.zSecondaryVertex(); + float const vertexDistance = std::sqrt(diffXVert * diffXVert + diffYVert * diffYVert + diffZVert * diffZVert); + return vertexDistance <= maxVertexDistanceLbLc; } void process(aod::HfCandLb const& hfCandLbs, @@ -152,14 +168,6 @@ struct HfCandidateSelectorLbToLcPi { for (const auto& hfCandLb : hfCandLbs) { // looping over Lb candidates int statusLb = 0; - - // check if flagged as Λb --> Λc+ π- - if (!(hfCandLb.hfflag() & 1 << hf_cand_lb::DecayType::LbToLcPi)) { - hfSelLbToLcPiCandidate(statusLb); - // LOGF(debug, "Lb candidate selection failed at hfflag check"); - continue; - } - // Lc is always index0 and pi is index1 by default // auto candLc = hfCandLb.prong0(); auto candLc = hfCandLb.prong0_as>(); @@ -169,9 +177,9 @@ struct HfCandidateSelectorLbToLcPi { 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(); + float const reso0 = candLc.errorImpactParameter0(); + float const reso1 = candLc.errorImpactParameter1(); + float const reso2 = candLc.errorImpactParameter2(); if (!passesImpactParameterResolution(track0.pt(), reso0) || !passesImpactParameterResolution(track1.pt(), reso1) || !passesImpactParameterResolution(track2.pt(), reso2) || !passesImpactParameterResolution(trackPi.pt(), hfCandLb.errorImpactParameter1())) { hfSelLbToLcPiCandidate(statusLb); continue; diff --git a/PWGHF/TableProducer/candidateSelectorLc.cxx b/PWGHF/TableProducer/candidateSelectorLc.cxx index afeba207356..b372780c1f3 100644 --- a/PWGHF/TableProducer/candidateSelectorLc.cxx +++ b/PWGHF/TableProducer/candidateSelectorLc.cxx @@ -17,17 +17,37 @@ /// \author Vít Kučera , CERN /// \author Grazia Luparello , INFN Trieste -#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/HfMlResponseLcToPKPi.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include "Common/Core/TrackSelectorPID.h" +#include "Common/DataModel/PIDResponseCombined.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -66,18 +86,21 @@ struct HfCandidateSelectorLc { 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"}; + 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"}; + Configurable> kfCuts{"kfCuts", {hf_cuts_lc_to_p_k_pi::CutsKf[0], hf_cuts_lc_to_p_k_pi::NBinsPt, hf_cuts_lc_to_p_k_pi::NCutKfVars, hf_cuts_lc_to_p_k_pi::labelsPt, hf_cuts_lc_to_p_k_pi::labelsCutKfVar}, "Lc candidate selection per pT bin with KF-associated variables"}; + Configurable applyNonKfCuts{"applyNonKfCuts", true, "Whether to apply non-KF cuts when running in KF mode. In DCAFitter mode this field is not effective"}; + Configurable applyKfCuts{"applyKfCuts", true, "Whether to apply KF cuts when running in KF mode. In DCAFitter mode this field is not effective"}; // 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,10 +109,10 @@ struct HfCandidateSelectorLc { 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; - o2::analysis::HfMlResponseLcToPKPi hfMlResponse; - std::vector outputMlLcToPKPi = {}; - std::vector outputMlLcToPiKP = {}; + o2::analysis::HfMlResponseLcToPKPi hfMlResponseDCA; + o2::analysis::HfMlResponseLcToPKPi hfMlResponseKF; + std::vector outputMlLcToPKPi; + std::vector outputMlLcToPiKP; o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; TrackSelectorKa selectorKaon; @@ -101,11 +124,11 @@ struct HfCandidateSelectorLc { HistogramRegistry registry{"registry"}; - double massK0Star892; + double massK0Star892{}; void init(InitContext const&) { - std::array processes = {doprocessNoBayesPid, doprocessBayesPid}; + 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."); } @@ -136,15 +159,28 @@ struct HfCandidateSelectorLc { } if (applyMl) { - hfMlResponse.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); - if (loadModelsFromCCDB) { - ccdbApi.init(ccdbUrl); - hfMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); - } else { - hfMlResponse.setModelPathsLocal(onnxFileNames); + if (doprocessNoBayesPidWithDCAFitterN || doprocessBayesPidWithDCAFitterN) { + hfMlResponseDCA.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponseDCA.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponseDCA.setModelPathsLocal(onnxFileNames); + } + hfMlResponseDCA.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponseDCA.init(); + } + if (doprocessNoBayesPidWithKFParticle || doprocessBayesPidWithKFParticle) { + hfMlResponseKF.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); + if (loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + hfMlResponseKF.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); + } else { + hfMlResponseKF.setModelPathsLocal(onnxFileNames); + } + hfMlResponseKF.cacheInputFeaturesIndices(namesInputFeatures); + hfMlResponseKF.init(); } - hfMlResponse.cacheInputFeaturesIndices(namesInputFeatures); - hfMlResponse.init(); } massK0Star892 = o2::constants::physics::MassK0Star892; @@ -172,12 +208,12 @@ struct HfCandidateSelectorLc { /// Conjugate-independent topological cuts /// \param candidate is candidate /// \return true if candidate passes all cuts - template + template bool selectionTopol(const T& candidate) { auto candpT = candidate.pt(); - int pTBin = findBin(binsPt, candpT); + int const pTBin = findBin(binsPt, candpT); if (pTBin == -1) { return false; } @@ -187,18 +223,54 @@ struct HfCandidateSelectorLc { return false; } - // cosine of pointing angle - if (candidate.cpa() <= cuts->get(pTBin, "cos pointing angle")) { - return false; - } + if (ReconstructionType == aod::hf_cand::VertexerType::DCAFitter || (ReconstructionType == aod::hf_cand::VertexerType::KfParticle && applyNonKfCuts)) { + // cosine of pointing angle + if (candidate.cpa() <= cuts->get(pTBin, "cos pointing angle")) { + return false; + } - // candidate chi2PCA - if (candidate.chi2PCA() > cuts->get(pTBin, "Chi2PCA")) { - return false; + // candidate chi2PCA + if (candidate.chi2PCA() > cuts->get(pTBin, "Chi2PCA")) { + return false; + } + + 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 (candidate.decayLength() <= cuts->get(pTBin, "decay length")) { - return false; + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if (applyKfCuts) { + // candidate chi2geo of the triplet of prongs + if (candidate.kfChi2Geo() > kfCuts->get(pTBin, "kfChi2Geo")) { + return false; + } + + // candidate's decay point separation from the PV in terms of its error + if (candidate.kfDecayLength() / candidate.kfDecayLengthError() < kfCuts->get(pTBin, "kfLdL")) { + return false; + } + + // candidate's chi2 to the PV + if (candidate.kfChi2Topo() > kfCuts->get(pTBin, "kfChi2Topo")) { + return false; + } + } } if (!isSelectedCandidateProngDca(candidate)) { @@ -214,45 +286,124 @@ 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) { auto candpT = candidate.pt(); - int pTBin = findBin(binsPt, candpT); + int const pTBin = findBin(binsPt, candpT); if (pTBin == -1) { return false; } - // cut on daughter pT - if (trackProton.pt() < cuts->get(pTBin, "pT p") || trackKaon.pt() < cuts->get(pTBin, "pT K") || trackPion.pt() < cuts->get(pTBin, "pT Pi")) { - return false; - } + if (ReconstructionType == aod::hf_cand::VertexerType::DCAFitter || (ReconstructionType == aod::hf_cand::VertexerType::KfParticle && applyNonKfCuts)) { + + // cut on daughter pT + if (trackProton.pt() < cuts->get(pTBin, "pT p") || trackKaon.pt() < cuts->get(pTBin, "pT K") || trackPion.pt() < cuts->get(pTBin, "pT Pi")) { + return false; + } + + float massLc{0.f}, massKPi{0.f}; + 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 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(); + } + } - // cut on Lc->pKpi, piKp mass values - if (trackProton.globalIndex() == candidate.prong0Id()) { - if (std::abs(hfHelper.invMassLcToPKPi(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { + // cut on Lc->pKpi, piKp mass values + if (std::abs(massLc - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { return false; } - } else { - if (std::abs(hfHelper.invMassLcToPiKP(candidate) - o2::constants::physics::MassLambdaCPlus) > cuts->get(pTBin, "m")) { + + /// 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; } } - /// cut on the Kpi pair invariant mass, to study Lc->pK*(->Kpi) - const double cutMassKPi = cuts->get(pTBin, "mass (Kpi)"); - if (cutMassKPi > 0) { - if (trackProton.globalIndex() == candidate.prong0Id()) { - // inspecting the pKpi hypothesis - // K: prong1, pi: prong 2 - if (std::abs(hfHelper.invMassKPiPairLcToPKPi(candidate) - massK0Star892) > cutMassKPi) { + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if (applyKfCuts) { + const float chi2PrimProng0 = candidate.kfChi2PrimProng0(); + const float chi2PrimProng1 = candidate.kfChi2PrimProng1(); + const float chi2PrimProng2 = candidate.kfChi2PrimProng2(); + + const float chi2GeoProng1Prong2 = candidate.kfChi2GeoProng1Prong2(); + const float chi2GeoProng0Prong2 = candidate.kfChi2GeoProng0Prong2(); + const float chi2GeoProng0Prong1 = candidate.kfChi2GeoProng0Prong1(); + + const float dcaProng1Prong2 = candidate.kfDcaProng1Prong2(); + const float dcaProng0Prong2 = candidate.kfDcaProng0Prong2(); + const float dcaProng0Prong1 = candidate.kfDcaProng0Prong1(); + + const double cutChi2PrimPr = kfCuts->get(pTBin, "kfChi2PrimPr"); + const double cutChi2PrimKa = kfCuts->get(pTBin, "kfChi2PrimKa"); + const double cutChi2PrimPi = kfCuts->get(pTBin, "kfChi2PrimPi"); + + const double cutChi2GeoKaPi = kfCuts->get(pTBin, "kfChi2GeoKaPi"); + const double cutChi2GeoPrPi = kfCuts->get(pTBin, "kfChi2GeoPrPi"); + const double cutChi2GeoPrKa = kfCuts->get(pTBin, "kfChi2GeoPrKa"); + + const double cutDcaKaPi = kfCuts->get(pTBin, "kfDcaKaPi"); + const double cutDcaPrPi = kfCuts->get(pTBin, "kfDcaPrPi"); + const double cutDcaPrKa = kfCuts->get(pTBin, "kfDcaPrKa"); + + // kaon's chi2 to the PV + if (chi2PrimProng1 < cutChi2PrimKa) { + return false; + } + + // chi2geo between proton and pion + if (chi2GeoProng0Prong2 > cutChi2GeoPrPi) { + return false; + } + + // dca between proton and pion + if (dcaProng0Prong2 > cutDcaPrPi) { + return false; + } + + const bool isPKPi = trackProton.globalIndex() == candidate.prong0Id(); + + // 0-th prong chi2 to the PV + if (chi2PrimProng0 < (isPKPi ? cutChi2PrimPr : cutChi2PrimPi)) { + return false; + } + + // 2-nd prong chi2 to the PV + if (chi2PrimProng2 < (isPKPi ? cutChi2PrimPi : cutChi2PrimPr)) { + return false; + } + + // chi2geo between 1-st and 2-nd prongs + if (chi2GeoProng1Prong2 > (isPKPi ? cutChi2GeoKaPi : cutChi2GeoPrKa)) { + return false; + } + + // chi2geo between 0-th and 1-st prongs + if (chi2GeoProng0Prong1 > (isPKPi ? cutChi2GeoPrKa : cutChi2GeoKaPi)) { + return false; + } + + // dca between 1-st and 2-nd prongs + if (dcaProng1Prong2 > (isPKPi ? cutDcaKaPi : cutDcaPrKa)) { return false; } - } else { - // inspecting the piKp hypothesis - // K: prong1, pi: prong 0 - if (std::abs(hfHelper.invMassKPiPairLcToPiKP(candidate) - massK0Star892) > cutMassKPi) { + + // dca between 0-th and 1-st prongs + if (dcaProng0Prong1 > (isPKPi ? cutDcaPrKa : cutDcaKaPi)) { return false; } } @@ -279,19 +430,17 @@ struct HfCandidateSelectorLc { /// \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; + return pidTrackProton != TrackSelectorPID::Rejected && + pidTrackKaon != TrackSelectorPID::Rejected && + pidTrackPion != TrackSelectorPID::Rejected; } /// \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(aod::HfCand3Prong const& candidates, TTracks const&) + template + void runSelectLc(CandType const& candidates, TTracks const&) { // looping over 3-prong candidates for (const auto& candidate : candidates) { @@ -327,7 +476,7 @@ struct HfCandidateSelectorLc { // 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); + bool const trackQualitySel = isSelectedCandidateProngQuality(trackPos1, trackNeg, trackPos2); if (!trackQualitySel) { hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); if (applyMl) { @@ -337,7 +486,7 @@ struct HfCandidateSelectorLc { } // conjugate-independent topological selection - if (!selectionTopol(candidate)) { + if (!selectionTopol(candidate)) { hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); if (applyMl) { hfMlLcToPKPiCandidate(outputMlLcToPKPi, outputMlLcToPiKP); @@ -346,8 +495,8 @@ struct HfCandidateSelectorLc { } // conjugate-dependent topological selection for Lc - bool topolLcToPKPi = selectionTopolConjugate(candidate, trackPos1, trackNeg, trackPos2); - bool topolLcToPiKP = selectionTopolConjugate(candidate, trackPos2, trackNeg, trackPos1); + bool const topolLcToPKPi = selectionTopolConjugate(candidate, trackPos1, trackNeg, trackPos2); + bool const topolLcToPiKP = selectionTopolConjugate(candidate, trackPos2, trackNeg, trackPos1); if (!topolLcToPKPi && !topolLcToPiKP) { hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); @@ -369,23 +518,23 @@ struct HfCandidateSelectorLc { if (usePid) { // track-level PID selection - 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; + TrackSelectorPID::Status pidTrackPos1Proton; + TrackSelectorPID::Status pidTrackPos2Proton; + TrackSelectorPID::Status pidTrackPos1Pion; + TrackSelectorPID::Status pidTrackPos2Pion; + TrackSelectorPID::Status pidTrackNegKaon; if (usePidTpcAndTof) { - pidTrackPos1Proton = selectorProton.statusTpcAndTof(trackPos1); - pidTrackPos2Proton = selectorProton.statusTpcAndTof(trackPos2); - pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1); - pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2); - pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg); + pidTrackPos1Proton = selectorProton.statusTpcAndTof(trackPos1, candidate.nSigTpcPr0(), candidate.nSigTofPr0()); + pidTrackPos2Proton = selectorProton.statusTpcAndTof(trackPos2, candidate.nSigTpcPr2(), candidate.nSigTofPr2()); + pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); } else { - pidTrackPos1Proton = selectorProton.statusTpcOrTof(trackPos1); - pidTrackPos2Proton = selectorProton.statusTpcOrTof(trackPos2); - pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1); - pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2); - pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); + pidTrackPos1Proton = selectorProton.statusTpcOrTof(trackPos1, candidate.nSigTpcPr0(), candidate.nSigTofPr0()); + pidTrackPos2Proton = selectorProton.statusTpcOrTof(trackPos2, candidate.nSigTpcPr2(), candidate.nSigTofPr2()); + pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); } if (!isSelectedPID(pidTrackPos1Proton, pidTrackNegKaon, pidTrackPos2Pion)) { @@ -396,12 +545,12 @@ struct HfCandidateSelectorLc { } } - 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 constexpr (UseBayesPid) { + TrackSelectorPID::Status const pidBayesTrackPos1Proton = selectorProton.statusBayes(trackPos1); + TrackSelectorPID::Status const pidBayesTrackPos2Proton = selectorProton.statusBayes(trackPos2); + TrackSelectorPID::Status const pidBayesTrackPos1Pion = selectorPion.statusBayes(trackPos1); + TrackSelectorPID::Status const pidBayesTrackPos2Pion = selectorPion.statusBayes(trackPos2); + TrackSelectorPID::Status const pidBayesTrackNegKaon = selectorKaon.statusBayes(trackNeg); if (!isSelectedPID(pidBayesTrackPos1Proton, pidBayesTrackNegKaon, pidBayesTrackPos2Pion)) { pidBayesLcToPKPi = 0; // reject LcToPKPi @@ -431,13 +580,24 @@ struct HfCandidateSelectorLc { isSelectedMlLcToPKPi = false; isSelectedMlLcToPiKP = false; - if (pidLcToPKPi == 1 && pidBayesLcToPKPi == 1 && topolLcToPKPi) { - std::vector inputFeaturesLcToPKPi = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); - isSelectedMlLcToPKPi = hfMlResponse.isSelectedMl(inputFeaturesLcToPKPi, candidate.pt(), outputMlLcToPKPi); - } - if (pidLcToPiKP == 1 && pidBayesLcToPiKP == 1 && topolLcToPiKP) { - std::vector inputFeaturesLcToPiKP = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); - isSelectedMlLcToPiKP = hfMlResponse.isSelectedMl(inputFeaturesLcToPiKP, candidate.pt(), outputMlLcToPiKP); + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::DCAFitter) { + if (pidLcToPKPi == 1 && pidBayesLcToPKPi == 1 && topolLcToPKPi) { + std::vector inputFeaturesLcToPKPi = hfMlResponseDCA.getInputFeatures(candidate, true); + isSelectedMlLcToPKPi = hfMlResponseDCA.isSelectedMl(inputFeaturesLcToPKPi, candidate.pt(), outputMlLcToPKPi); + } + if (pidLcToPiKP == 1 && pidBayesLcToPiKP == 1 && topolLcToPiKP) { + std::vector inputFeaturesLcToPiKP = hfMlResponseDCA.getInputFeatures(candidate, false); + isSelectedMlLcToPiKP = hfMlResponseDCA.isSelectedMl(inputFeaturesLcToPiKP, candidate.pt(), outputMlLcToPiKP); + } + } else { + if (pidLcToPKPi == 1 && pidBayesLcToPKPi == 1 && topolLcToPKPi) { + std::vector inputFeaturesLcToPKPi = hfMlResponseKF.getInputFeatures(candidate, true); + isSelectedMlLcToPKPi = hfMlResponseKF.isSelectedMl(inputFeaturesLcToPKPi, candidate.pt(), outputMlLcToPKPi); + } + if (pidLcToPiKP == 1 && pidBayesLcToPiKP == 1 && topolLcToPiKP) { + std::vector inputFeaturesLcToPiKP = hfMlResponseKF.getInputFeatures(candidate, false); + isSelectedMlLcToPiKP = hfMlResponseKF.isSelectedMl(inputFeaturesLcToPiKP, candidate.pt(), outputMlLcToPiKP); + } } hfMlLcToPKPiCandidate(outputMlLcToPKPi, outputMlLcToPiKP); @@ -463,25 +623,45 @@ struct HfCandidateSelectorLc { } } - /// \brief process function w/o Bayes PID + /// \brief process function w/o Bayes PID with DCAFitterN + /// \param candidates Lc candidate table + /// \param tracks track table + void processNoBayesPidWithDCAFitterN(aod::HfCand3ProngWPidPiKaPr 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::HfCand3ProngWPidPiKaPr 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 processNoBayesPid(aod::HfCand3Prong const& candidates, - TracksSel const& tracks) + void processNoBayesPidWithKFParticle(soa::Join const& candidates, + TracksSel const& tracks) { - runSelectLc(candidates, tracks); + runSelectLc(candidates, tracks); } - PROCESS_SWITCH(HfCandidateSelectorLc, processNoBayesPid, "Process Lc selection w/o Bayes PID", true); + PROCESS_SWITCH(HfCandidateSelectorLc, processNoBayesPidWithKFParticle, "Process Lc selection w/o Bayes PID with KFParticle", false); - /// \brief process function with Bayes PID + /// \brief process function with Bayes PID with KFParticle /// \param candidates Lc candidate table /// \param tracks track table with Bayes PID information - void processBayesPid(aod::HfCand3Prong const& candidates, - TracksSelBayesPid const& tracks) + void processBayesPidWithKFParticle(soa::Join const& candidates, + TracksSelBayesPid const& tracks) { - runSelectLc(candidates, tracks); + runSelectLc(candidates, tracks); } - PROCESS_SWITCH(HfCandidateSelectorLc, processBayesPid, "Process Lc selection with Bayes PID", false); + 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 1bac21ed7cf..f27e5edc3cd 100644 --- a/PWGHF/TableProducer/candidateSelectorLcPidMl.cxx +++ b/PWGHF/TableProducer/candidateSelectorLcPidMl.cxx @@ -17,18 +17,43 @@ /// \author Vít Kučera , CERN /// \author Maja Kabus , CERN, Warsaw University of Technology -#include "CommonConstants/PhysicsConstants.h" -#include "CCDB/CcdbApi.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelectorPID.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/PIDResponseCombined.h" #include "Tools/ML/model.h" -#include "PWGHF/Core/SelectorCuts.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -61,7 +86,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"}; @@ -70,7 +95,7 @@ struct HfCandidateSelectorLcPidMl { Configurable activateQA{"activateQA", false, "flag to enable QA histos"}; - int dataTypeML; + int dataTypeML{}; o2::ccdb::CcdbApi ccdbApi; OnnxModel model; TrackSelectorPi selectorPion; @@ -95,7 +120,7 @@ struct HfCandidateSelectorLcPidMl { selectorKaon = selectorPion; selectorProton = selectorPion; - AxisSpec bdtAxis{100, 0.f, 1.f}; + AxisSpec const bdtAxis{100, 0.f, 1.f}; if (applyML && activateQA) { registry.add("hLcBDTScoreBkg", "BDT background score distribution for Lc;BDT background score;counts", HistType::kTH1F, {bdtAxis}); registry.add("hLcBDTScorePrompt", "BDT prompt score distribution for Lc;BDT prompt score;counts", HistType::kTH1F, {bdtAxis}); @@ -105,17 +130,17 @@ struct HfCandidateSelectorLcPidMl { ccdbApi.init(url); // init ONNX runtime session - std::map metadata; + std::map const metadata; std::map headers; bool retrieveSuccess = true; if (applyML) { - if (onnxFileLcToPiKPConf.value == "") { + if (onnxFileLcToPiKPConf.value.empty()) { LOG(error) << "Apply ML specified, but no name given to the local model file"; } if (loadModelsFromCCDB && timestampCCDB > 0) { retrieveSuccess = ccdbApi.retrieveBlob(mlModelPathCCDB.value, ".", metadata, timestampCCDB.value, false, onnxFileLcToPiKPConf.value); headers = ccdbApi.retrieveHeaders(mlModelPathCCDB.value, metadata, timestampCCDB.value); - model.initModel(onnxFileLcToPiKPConf.value, false, 1, strtoul(headers["Valid-From"].c_str(), NULL, 0), strtoul(headers["Valid-Until"].c_str(), NULL, 0)); + model.initModel(onnxFileLcToPiKPConf.value, false, 1, strtoul(headers["Valid-From"].c_str(), nullptr, 0), strtoul(headers["Valid-Until"].c_str(), nullptr, 0)); } else if (!loadModelsFromCCDB) { model.initModel(onnxFileLcToPiKPConf.value, false, 1); } else { @@ -123,15 +148,11 @@ struct HfCandidateSelectorLcPidMl { } if (retrieveSuccess) { auto session = model.getSession(); -#if __has_include() - auto inputShapes = session->GetInputShapes(); -#else std::vector> inputShapes; - Ort::AllocatorWithDefaultOptions tmpAllocator; + Ort::AllocatorWithDefaultOptions const 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; @@ -145,7 +166,7 @@ struct HfCandidateSelectorLcPidMl { } } - void process(aod::HfCand3Prong const& candidates, + void process(aod::HfCand3ProngWPidPiKaPr const& candidates, TracksSel const&) { // looping over 3-prong candidates @@ -155,7 +176,7 @@ struct HfCandidateSelectorLcPidMl { auto statusLcToPKPi = 0; auto statusLcToPiKP = 0; - if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + if ((candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) == 0) { hfSelLcCandidate(statusLcToPKPi, statusLcToPiKP); continue; } @@ -177,11 +198,11 @@ struct HfCandidateSelectorLcPidMl { pidLcToPiKP = 1; } else { // track-level PID selection - int pidTrackPos1Proton = selectorProton.statusTpcOrTof(trackPos1); - int pidTrackPos2Proton = selectorProton.statusTpcOrTof(trackPos2); - int pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1); - int pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2); - int pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); + TrackSelectorPID::Status const pidTrackPos1Proton = selectorProton.statusTpcOrTof(trackPos1, candidate.nSigTpcPr0(), candidate.nSigTofPr0()); + TrackSelectorPID::Status const pidTrackPos2Proton = selectorProton.statusTpcOrTof(trackPos2, candidate.nSigTpcPr2(), candidate.nSigTofPr2()); + TrackSelectorPID::Status const pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + TrackSelectorPID::Status const pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + TrackSelectorPID::Status const pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); if (pidTrackPos1Proton == TrackSelectorPID::Accepted && pidTrackNegKaon == TrackSelectorPID::Accepted && @@ -208,11 +229,11 @@ struct HfCandidateSelectorLcPidMl { 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); + int const pidBayesTrackPos1Proton = selectorProton.statusBayes(trackPos1); + int const pidBayesTrackPos2Proton = selectorProton.statusBayes(trackPos2); + int const pidBayesTrackPos1Pion = selectorPion.statusBayes(trackPos1); + int const pidBayesTrackPos2Pion = selectorPion.statusBayes(trackPos2); + int const pidBayesTrackNegKaon = selectorKaon.statusBayes(trackNeg); if (pidBayesTrackPos1Proton == TrackSelectorPID::Accepted && pidBayesTrackNegKaon == TrackSelectorPID::Accepted && @@ -258,9 +279,9 @@ struct HfCandidateSelectorLcPidMl { continue; } - std::array pVecPos1 = trackPos1.pVector(); - std::array pVecNeg = trackNeg.pVector(); - std::array pVecPos2 = trackPos2.pVector(); + std::array const pVecPos1 = trackPos1.pVector(); + std::array const pVecNeg = trackNeg.pVector(); + std::array const pVecPos2 = trackPos2.pVector(); const float massPi = o2::constants::physics::MassPiPlus; const float massK = o2::constants::physics::MassKPlus; const float massProton = o2::constants::physics::MassProton; @@ -286,12 +307,12 @@ struct HfCandidateSelectorLcPidMl { std::vector inputFeaturesD{trackParPos1.getPt(), trackPos1.dcaXY(), trackPos1.dcaZ(), trackParNeg.getPt(), trackNeg.dcaXY(), trackNeg.dcaZ(), trackParPos2.getPt(), trackPos2.dcaXY(), trackPos2.dcaZ()}; float scores[3] = {-1.f, -1.f, -1.f}; if (dataTypeML == 1) { - auto scoresRaw = model.evalModel(inputFeaturesF); + auto* scoresRaw = model.evalModel(inputFeaturesF); for (int iScore = 0; iScore < 3; ++iScore) { scores[iScore] = scoresRaw[iScore]; } } else if (dataTypeML == 11) { - auto scoresRaw = model.evalModel(inputFeaturesD); + auto* scoresRaw = model.evalModel(inputFeaturesD); for (int iScore = 0; iScore < 3; ++iScore) { scores[iScore] = scoresRaw[iScore]; } diff --git a/PWGHF/TableProducer/candidateSelectorLcToK0sP.cxx b/PWGHF/TableProducer/candidateSelectorLcToK0sP.cxx index 7e8d48085f0..0720953a7df 100644 --- a/PWGHF/TableProducer/candidateSelectorLcToK0sP.cxx +++ b/PWGHF/TableProducer/candidateSelectorLcToK0sP.cxx @@ -17,24 +17,45 @@ /// Daniel Samitz, , Vienna /// Elisa Meninno, , Vienna -#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/HfMlResponse.h" #include "PWGHF/Core/HfMlResponseLcToK0sP.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/TrackSelectorPID.h" +#include "Common/DataModel/PIDResponseCombined.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + using namespace o2; using namespace o2::analysis; using namespace o2::framework; struct HfCandidateSelectorLcToK0sP { Produces hfSelLcToK0sPCandidate; + Produces hfMlLcToK0sPCandidate; Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; Configurable ptCandMax{"ptCandMax", 50., "Upper bound of candidate pT"}; @@ -56,13 +77,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"}; @@ -71,11 +92,11 @@ struct HfCandidateSelectorLcToK0sP { 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; TrackSelectorPr selectorProtonLowP; TrackSelectorPr selectorProtonHighP; o2::analysis::HfMlResponseLcToK0sP hfMlResponse; + std::vector outputMl; o2::ccdb::CcdbApi ccdbApi; @@ -120,8 +141,8 @@ struct HfCandidateSelectorLcToK0sP { hfMlResponse.init(); // load histograms for ML score - AxisSpec axisScore = {100, 0, 1, "score"}; - AxisSpec axisBinsPt = {binsPtMl, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec const axisScore = {100, 0, 1, "score"}; + AxisSpec const axisBinsPt = {binsPtMl, "#it{p}_{T} (GeV/#it{c})"}; for (int classMl = 0; classMl < nClassesMl; classMl++) { hModelScore.push_back(registry.add(Form("hMlScoreClass%d", classMl), "Model score distribution for Lc;Model score;counts", HistType::kTH1F, {axisScore})); hModelScoreVsPtCand.push_back(registry.add(Form("hMlScoreClass%dVsPtCand", classMl), "Model score distribution for Lc;Model score;counts", HistType::kTH2F, {axisScore, axisBinsPt})); @@ -136,7 +157,7 @@ struct HfCandidateSelectorLcToK0sP { bool selectionTopol(const T& hfCandCascade) { auto candPt = hfCandCascade.pt(); - int ptBin = findBin(binsPt, candPt); + int const ptBin = findBin(binsPt, candPt); if (ptBin == -1) { return false; } @@ -145,6 +166,10 @@ struct HfCandidateSelectorLcToK0sP { return false; // check that the candidate pT is within the analysis range } + if (std::abs(HfHelper::invMassLcToK0sP(hfCandCascade) - o2::constants::physics::MassLambdaCPlus) > cuts->get(ptBin, "mLc")) { + return false; // mass of the Lambda c + } + if (std::abs(hfCandCascade.mK0Short() - o2::constants::physics::MassK0Short) > cuts->get(ptBin, "mK0s")) { return false; // mass of the K0s } @@ -196,9 +221,8 @@ struct HfCandidateSelectorLcToK0sP { { if (track.p() < pPidThreshold) { return selectorProtonLowP.statusTpcAndTof(track) == TrackSelectorPID::Accepted; - } else { - return selectorProtonHighP.statusTpcAndTof(track) == TrackSelectorPID::Accepted; } + return selectorProtonHighP.statusTpcAndTof(track) == TrackSelectorPID::Accepted; } template @@ -210,20 +234,18 @@ struct HfCandidateSelectorLcToK0sP { if (track.p() < pPidThreshold) { return selectorProtonLowP.statusBayesProb(track) == TrackSelectorPID::Accepted; - } else { - return selectorProtonHighP.statusBayesProb(track) == TrackSelectorPID::Accepted; } + return selectorProtonHighP.statusBayesProb(track) == TrackSelectorPID::Accepted; } template - bool selectionMl(const T& hfCandCascade, const U& bach) + bool selectionMl(const T& hfCandCascade, const U& bach, std::vector& outputMl) { auto ptCand = hfCandCascade.pt(); std::vector inputFeatures = hfMlResponse.getInputFeatures(hfCandCascade, bach); - std::vector outputMl = {}; - bool isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCand, outputMl); + bool const isSelectedMl = hfMlResponse.isSelectedMl(inputFeatures, ptCand, outputMl); for (int classMl = 0; classMl < nClassesMl; classMl++) { hModelScore[classMl]->Fill(outputMl[classMl]); @@ -242,26 +264,37 @@ struct HfCandidateSelectorLcToK0sP { const auto& bach = candidate.prong0_as(); // bachelor track statusLc = 0; + outputMl.clear(); // implement filter bit 4 cut - should be done before this task at the track selection level // need to add special cuts (additional cuts on decay length and d0 norm) if (!selectionTopol(candidate)) { hfSelLcToK0sPCandidate(statusLc); + if (applyMl) { + hfMlLcToK0sPCandidate(outputMl); + } continue; } if (!selectionStandardPID(bach)) { hfSelLcToK0sPCandidate(statusLc); + if (applyMl) { + hfMlLcToK0sPCandidate(outputMl); + } continue; } - if (applyMl && !selectionMl(candidate, bach)) { - hfSelLcToK0sPCandidate(statusLc); - continue; + if (applyMl) { + bool const isSelectedMlLcToK0sP = selectionMl(candidate, bach, outputMl); + hfMlLcToK0sPCandidate(outputMl); + + if (!isSelectedMlLcToK0sP) { + hfSelLcToK0sPCandidate(statusLc); + continue; + } } statusLc = 1; - hfSelLcToK0sPCandidate(statusLc); } } @@ -276,24 +309,35 @@ struct HfCandidateSelectorLcToK0sP { const auto& bach = candidate.prong0_as(); // bachelor track statusLc = 0; + outputMl.clear(); if (!selectionTopol(candidate)) { hfSelLcToK0sPCandidate(statusLc); + if (applyMl) { + hfMlLcToK0sPCandidate(outputMl); + } continue; } if (!selectionBayesPID(bach)) { hfSelLcToK0sPCandidate(statusLc); + if (applyMl) { + hfMlLcToK0sPCandidate(outputMl); + } continue; } - if (applyMl && !selectionMl(candidate, bach)) { - hfSelLcToK0sPCandidate(statusLc); - continue; + if (applyMl) { + bool const isSelectedMlLcToK0sP = selectionMl(candidate, bach, outputMl); + hfMlLcToK0sPCandidate(outputMl); + + if (!isSelectedMlLcToK0sP) { + hfSelLcToK0sPCandidate(statusLc); + continue; + } } statusLc = 1; - hfSelLcToK0sPCandidate(statusLc); } } diff --git a/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaKa.cxx b/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaKa.cxx index 12f2dddc6f6..44cb77e44a3 100644 --- a/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaKa.cxx +++ b/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaKa.cxx @@ -9,31 +9,47 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file candidateSelectorToOmegaKa.cxx +/// \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/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsAnalysis.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::analysis; -enum pidInfoStored { - kPiFromLam = 0, - kPrFromLam, - kKaFromCasc, - kKaFromCharm +enum PidInfoStored { + PiFromLam = 0, + PrFromLam, + KaFromCasc, + KaFromCharm }; /// Struct for applying Omegac0 -> Omega pi selection cuts @@ -129,6 +145,7 @@ struct HfCandidateSelectorToOmegaKa { TrackSelectorKa selectorKaon; using TracksSel = soa::Join; + using TracksSelLf = soa::Join; HistogramRegistry registry{"registry"}; // for QA of selections @@ -194,7 +211,8 @@ struct HfCandidateSelectorToOmegaKa { } void process(aod::HfCandToOmegaK const& candidates, - TracksSel const&) + TracksSel const& tracks, + TracksSelLf const& lfTracks) { // looping over charm baryon candidates @@ -202,15 +220,19 @@ struct HfCandidateSelectorToOmegaKa { 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 trackKaFromCasc = candidate.bachelor_as(); // kaon <- cascade - auto trackKaFromCharm = candidate.bachelorFromCharmBaryon_as(); // kaon <- charm baryon + 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 + int8_t const signDecay = candidate.signDecay(); // sign of pi <- cascade if (signDecay > 0) { trackPiFromLam = trackV0PosDau; @@ -221,10 +243,10 @@ struct HfCandidateSelectorToOmegaKa { } // eta selection - double etaV0PosDau = candidate.etaV0PosDau(); - double etaV0NegDau = candidate.etaV0NegDau(); - double etaKaFromCasc = candidate.etaBachFromCasc(); - double etaKaFromCharmBaryon = candidate.etaBachFromCharmBaryon(); + double const etaV0PosDau = candidate.etaV0PosDau(); + double const etaV0NegDau = candidate.etaV0NegDau(); + double const etaKaFromCasc = candidate.etaBachFromCasc(); + double const etaKaFromCharmBaryon = candidate.etaBachFromCharmBaryon(); if (std::abs(etaV0PosDau) > etaTrackLFDauMax) { resultSelections = false; registry.fill(HIST("hSelEtaPosV0Dau"), 0); @@ -302,7 +324,7 @@ struct HfCandidateSelectorToOmegaKa { } // 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 { @@ -310,7 +332,7 @@ struct HfCandidateSelectorToOmegaKa { } // dcaXY ka <-- cascade to PV cut - if (candidate.dcaXYToPvCascDau() < dcaBachToPvMin) { + if (std::abs(candidate.dcaXYToPvCascDau()) < dcaBachToPvMin) { resultSelections = false; registry.fill(HIST("hSelDcaXYToPvKaFromCasc"), 0); } else { @@ -346,8 +368,8 @@ struct HfCandidateSelectorToOmegaKa { } // pT selections - double ptKaFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); - double ptKaFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); + double const ptKaFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); + double const ptKaFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); if (std::abs(ptKaFromCasc) < ptKaFromCascMin) { resultSelections = false; registry.fill(HIST("hSelPtKaFromCasc"), 0); @@ -417,28 +439,28 @@ struct HfCandidateSelectorToOmegaKa { } if (trackPiFromLam.hasTPC()) { - SETBIT(infoTpcStored, kPiFromLam); + SETBIT(infoTpcStored, PiFromLam); } if (trackPrFromLam.hasTPC()) { - SETBIT(infoTpcStored, kPrFromLam); + SETBIT(infoTpcStored, PrFromLam); } if (trackKaFromCasc.hasTPC()) { - SETBIT(infoTpcStored, kKaFromCasc); + SETBIT(infoTpcStored, KaFromCasc); } if (trackKaFromCharm.hasTPC()) { - SETBIT(infoTpcStored, kKaFromCharm); + SETBIT(infoTpcStored, KaFromCharm); } if (trackPiFromLam.hasTOF()) { - SETBIT(infoTofStored, kPiFromLam); + SETBIT(infoTofStored, PiFromLam); } if (trackPrFromLam.hasTOF()) { - SETBIT(infoTofStored, kPrFromLam); + SETBIT(infoTofStored, PrFromLam); } if (trackKaFromCasc.hasTOF()) { - SETBIT(infoTofStored, kKaFromCasc); + SETBIT(infoTofStored, KaFromCasc); } if (trackKaFromCharm.hasTOF()) { - SETBIT(infoTofStored, kKaFromCharm); + SETBIT(infoTofStored, KaFromCharm); } if (usePidTpcOnly) { @@ -479,9 +501,9 @@ struct HfCandidateSelectorToOmegaKa { bool statusInvMassCascade = false; bool statusInvMassCharmBaryon = false; - double invMassLambda = candidate.invMassLambda(); - double invMassCascade = candidate.invMassCascade(); - double invMassCharmBaryon = candidate.invMassCharmBaryon(); + double const invMassLambda = candidate.invMassLambda(); + double const invMassCascade = candidate.invMassCascade(); + double const invMassCharmBaryon = candidate.invMassCharmBaryon(); if (std::abs(invMassLambda - o2::constants::physics::MassLambda0) < v0MassWindow) { statusInvMassLambda = true; @@ -561,7 +583,7 @@ struct HfCandidateSelectorToOmegaKa { } } } // end process -}; // end struct +}; // end struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaPi.cxx b/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaPi.cxx index 2ecc7afc038..87856e1554a 100644 --- a/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorOmegac0ToOmegaPi.cxx @@ -9,36 +9,64 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file candidateSelectorToOmegaPi.cxx +/// \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 "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectorPID.h" - +#include "PWGHF/Core/HfMlResponseOmegacToOmegaPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsAnalysis.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::analysis; -enum pidInfoStored { - kPiFromLam = 0, - kPrFromLam, - kKaFromCasc, - kPiFromCharm +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"}; @@ -68,7 +96,7 @@ struct HfCandidateSelectorToOmegaPi { 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"}; @@ -123,19 +151,70 @@ struct HfCandidateSelectorToOmegaPi { 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{TH1F("hInvMassCharmBaryon", "Charm baryon invariant mass;inv mass;entries", 500, 2.3, 3.1)}; + 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); @@ -159,57 +238,127 @@ struct HfCandidateSelectorToOmegaPi { 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.}}}); + 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::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("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("hSelPtKaFromCasc", "hSelPtKaFromCasc;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("hSelTPCQualityKaFromCasc", "hSelTPCQualityKaFromCasc;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("hSelDcaXYToPvKaFromCasc", "hSelDcaXYToPvKaFromCasc;status;entries", {HistType::kTH1F, {axisSel}}); + 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 const 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; + } - void process(aod::HfCandToOmegaPi const& candidates, - TracksSel const&) + // 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; + } + 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 - auto trackV0PosDau = candidate.posTrack_as(); // positive V0 daughter - auto trackV0NegDau = candidate.negTrack_as(); // negative V0 daughter - auto trackKaFromCasc = candidate.bachelor_as(); // kaon <- cascade - auto trackPiFromCharm = candidate.bachelorFromCharmBaryon_as(); // pion <- charm baryon + 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; - int8_t signDecay = candidate.signDecay(); // sign of pi <- cascade + auto ptCand = candidate.ptCharmBaryon(); + int8_t const signDecay = candidate.signDecay(); // sign of pi <- cascade if (signDecay > 0) { trackPiFromLam = trackV0PosDau; @@ -219,11 +368,25 @@ struct HfCandidateSelectorToOmegaPi { 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(); + double const etaV0PosDau = candidate.etaV0PosDau(); + double const etaV0NegDau = candidate.etaV0NegDau(); + double const etaKaFromCasc = candidate.etaBachFromCasc(); + double const etaPiFromCharmBaryon = candidate.etaBachFromCharmBaryon(); if (std::abs(etaV0PosDau) > etaTrackLFDauMax) { resultSelections = false; registry.fill(HIST("hSelEtaPosV0Dau"), 0); @@ -301,7 +464,7 @@ struct HfCandidateSelectorToOmegaPi { } // 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 { @@ -309,7 +472,7 @@ struct HfCandidateSelectorToOmegaPi { } // dcaXY ka <-- cascade to PV cut - if (candidate.dcaXYToPvCascDau() < dcaBachToPvMin) { + if (std::abs(candidate.dcaXYToPvCascDau()) < dcaBachToPvMin) { resultSelections = false; registry.fill(HIST("hSelDcaXYToPvKaFromCasc"), 0); } else { @@ -345,8 +508,8 @@ struct HfCandidateSelectorToOmegaPi { } // pT selections - double ptKaFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); - double ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); + double const ptKaFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); + double const ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); if (std::abs(ptKaFromCasc) < ptKaFromCascMin) { resultSelections = false; registry.fill(HIST("hSelPtKaFromCasc"), 0); @@ -360,6 +523,89 @@ struct HfCandidateSelectorToOmegaPi { 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.v0Chi2OverNdf() < 0) || (candidate.cascChi2OverNdf() > kfConfigurableGroup.cascChi2OverNdfMax) || (candidate.cascChi2OverNdf() < 0) || (candidate.omegacChi2OverNdf() > kfConfigurableGroup.omegacChi2OverNdfMax) || (candidate.omegacChi2OverNdf() < 0)) { + 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.chi2TopoV0ToCasc() < 0) || (candidate.chi2TopoOmegacToPv() > kfConfigurableGroup.chi2TopoOmegacToPvMax) || (candidate.chi2TopoOmegacToPv() < 0) || (candidate.chi2TopoCascToOmegac() > kfConfigurableGroup.chi2TopoCascToOmegacMax) || (candidate.chi2TopoCascToOmegac() < 0) || (candidate.chi2TopoCascToPv() > kfConfigurableGroup.chi2TopoCascToPvMax) || (candidate.chi2TopoCascToPv() < 0)) { + 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)) { @@ -404,40 +650,33 @@ struct HfCandidateSelectorToOmegaPi { int statusPidKaFromCasc = -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, kPiFromLam); + SETBIT(infoTpcStored, PiFromLam); } if (trackPrFromLam.hasTPC()) { - SETBIT(infoTpcStored, kPrFromLam); + SETBIT(infoTpcStored, PrFromLam); } if (trackKaFromCasc.hasTPC()) { - SETBIT(infoTpcStored, kKaFromCasc); + SETBIT(infoTpcStored, KaFromCasc); } 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 (trackKaFromCasc.hasTOF()) { - SETBIT(infoTofStored, kKaFromCasc); + SETBIT(infoTofStored, KaFromCasc); } if (trackPiFromCharm.hasTOF()) { - SETBIT(infoTofStored, kPiFromCharm); + SETBIT(infoTofStored, PiFromCharm); } if (usePidTpcOnly) { @@ -457,6 +696,8 @@ struct HfCandidateSelectorToOmegaPi { if (resultSelections) { registry.fill(HIST("hStatusCheck"), 0.5); } + } else { + resultSelections = false; } if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted && statusPidKaFromCasc == TrackSelectorPID::Accepted) { @@ -464,6 +705,8 @@ struct HfCandidateSelectorToOmegaPi { if (resultSelections) { registry.fill(HIST("hStatusCheck"), 1.5); } + } else { + resultSelections = false; } if (statusPidPrFromLam == TrackSelectorPID::Accepted && statusPidPiFromLam == TrackSelectorPID::Accepted && statusPidKaFromCasc == TrackSelectorPID::Accepted && statusPidPiFromCharmBaryon == TrackSelectorPID::Accepted) { @@ -471,16 +714,14 @@ struct HfCandidateSelectorToOmegaPi { if (resultSelections) { registry.fill(HIST("hStatusCheck"), 2.5); } + } else { + resultSelections = false; } // invariant mass cuts - bool statusInvMassLambda = false; - bool statusInvMassCascade = false; - bool statusInvMassCharmBaryon = false; - - double invMassLambda = candidate.invMassLambda(); - double invMassCascade = candidate.invMassCascade(); - double invMassCharmBaryon = candidate.invMassCharmBaryon(); + double const invMassLambda = candidate.invMassLambda(); + double const invMassCascade = candidate.invMassCascade(); + double const invMassCharmBaryon = candidate.invMassCharmBaryon(); if (std::abs(invMassLambda - o2::constants::physics::MassLambda0) < v0MassWindow) { statusInvMassLambda = true; @@ -490,6 +731,7 @@ struct HfCandidateSelectorToOmegaPi { } } else { registry.fill(HIST("hSelMassLam"), 0); + resultSelections = false; } if (std::abs(invMassCascade - o2::constants::physics::MassOmegaMinus) < cascadeMassWindow) { @@ -500,6 +742,7 @@ struct HfCandidateSelectorToOmegaPi { } } else { registry.fill(HIST("hSelMassCasc"), 0); + resultSelections = false; } if ((invMassCharmBaryon >= invMassCharmBaryonMin) && (invMassCharmBaryon <= invMassCharmBaryonMax)) { @@ -510,6 +753,19 @@ struct HfCandidateSelectorToOmegaPi { } } 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, @@ -557,10 +813,32 @@ struct HfCandidateSelectorToOmegaPi { 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 -}; // end struct + + 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) { diff --git a/PWGHF/TableProducer/candidateSelectorOmegac0Xic0ToOmegaKa.cxx b/PWGHF/TableProducer/candidateSelectorOmegac0Xic0ToOmegaKa.cxx new file mode 100644 index 00000000000..e1e32120543 --- /dev/null +++ b/PWGHF/TableProducer/candidateSelectorOmegac0Xic0ToOmegaKa.cxx @@ -0,0 +1,718 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file candidateSelectorOmegac0Xic0ToOmegaKa.cxx +/// \brief Omegac0 Xic0 → Omega Ka selection task +/// \author Federica Zanone , Heidelberg University +/// \author Ruiqi Yin , Fudan University + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +// #include "PWGHF/Core/HfMlResponseOmegaKaToOmegaKa.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.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 OmegaKa -> Omega Ka selection cuts +struct HfCandidateSelectorOmegac0Xic0ToOmegaKa { + Produces hfSelToOmegaKaKf; + // Produces hfMlSelToOmegaKa; + + // LF analysis selections + Configurable radiusCascMin{"radiusCascMin", 0.1, "Min cascade radius"}; + Configurable radiusV0Min{"radiusV0Min", 1.1, "Min V0 radius"}; + Configurable cosPAV0Min{"cosPAV0Min", 0.95, "Min valueCosPA V0"}; + Configurable cosPACascMin{"cosPACascMin", 0.95, "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 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"}; + + // topological cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_omegacxic_to_omega_ka::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_omegacxic_to_omega_ka::Cuts[0], hf_cuts_omegacxic_to_omega_ka::NBinsPt, hf_cuts_omegacxic_to_omega_ka::NCutVars, hf_cuts_omegacxic_to_omega_ka::labelsPt, hf_cuts_omegacxic_to_omega_ka::labelsCutVar}, "OmegaC0 candidate selection per pT bin"}; + + // limit charm baryon invariant mass spectrum + Configurable invMassCharmBaryonMin{"invMassCharmBaryonMin", 2.0, "Lower limit invariant mass spectrum charm baryon"}; // Xic0:2.470 Omegac0:2.695 + 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", 0.8, "Max absolute value of eta for V0 and cascade daughters"}; + Configurable ptCascMin{"ptCascMin", 0.1, "Min pT kaon <- casc"}; + Configurable ptKaFromCharmBaryonMin{"ptKaFromCharmBaryonMin", 0.2, "Min pT Ka <- 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 impactParameterXYCascMin{"impactParameterXYCascMin", 0., "Min dcaxy cascade track to PV"}; + Configurable impactParameterXYCascMax{"impactParameterXYCascMax", 10., "Max dcaxy cascade track to PV"}; + + Configurable ptCandMin{"ptCandMin", 1., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 12., "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 applyCompetingCascRejection{"applyCompetingCascRejection", false, "Apply competing Xi(for OmegaKa) rejection"}; + Configurable cascadeRejMassWindow{"cascadeRejMassWindow", 0.01, "competing Xi(for OmegaKa) 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 omegaKaLdlMax{"omegaKaLdlMax", 5., "Maximum value of l/dl of OmegaKa"}; + Configurable cTauOmegaKaMax{"cTauOmegaKaMax", 0.4, "lifetime τ of OmegaKa"}; + Configurable v0Chi2OverNdfMax{"v0Chi2OverNdfMax", 100., "Maximum chi2Geo/NDF of V0"}; + Configurable cascChi2OverNdfMax{"cascChi2OverNdfMax", 100., "Maximum chi2Geo/NDF of casc"}; + Configurable omegaKaChi2OverNdfMax{"omegaKaChi2OverNdfMax", 100., "Maximum chi2Geo/NDF of OmegaKa"}; + Configurable chi2TopoV0ToCascMax{"chi2TopoV0ToCascMax", 100., "Maximum chi2Topo/NDF of V0ToCasc"}; + Configurable chi2TopoKaToCascMax{"chi2TopoKaToCascMax", 100., "Maximum chi2Topo/NDF of KaToCasc"}; + Configurable chi2TopoOmegaKaToPvMax{"chi2TopoOmegaKaToPvMax", 100., "Maximum chi2Topo/NDF of OmegaKaToPv"}; + Configurable chi2TopoCascToOmegaKaMax{"chi2TopoCascToOmegaKaMax", 100., "Maximum chi2Topo/NDF of CascToOmegaKa"}; + Configurable chi2TopoKaToOmegaKaMax{"chi2TopoKaToOmegaKaMax", 100., "Maximum chi2Topo/NDF of KaToOmegaKa"}; + Configurable chi2TopoCascToPvMax{"chi2TopoCascToPvMax", 100., "Maximum chi2Topo/NDF of CascToPv"}; + Configurable chi2TopoKaFromOmegaKaToPvMax{"chi2TopoKaFromOmegaKaToPvMax", 100., "Maximum chi2Topo/NDF of CascToPv"}; + Configurable decayLenOmegaKaMax{"decayLenOmegaKaMax", 1.5, "Maximum decay lengthXY of OmegaKa"}; + Configurable decayLenCascMin{"decayLenCascMin", 1., "Minimum decay lengthXY of Cascade"}; + Configurable decayLenLambdaMin{"decayLenLambdaMin", 0., "Minimum decay lengthXY of V0"}; + Configurable cosPaCascToOmegaKaMin{"cosPaCascToOmegaKaMin", 0.995, "Minimum cosPA of cascade<-OmegaKa"}; + Configurable cosPaV0ToCascMin{"cosPaV0ToCascMin", 0.99, "Minimum cosPA of V0<-cascade"}; + } kfConfigurableGroup; + + TrackSelectorPi selectorPion; + TrackSelectorPr selectorProton; + TrackSelectorKa selectorKaon; + + using TracksSel = soa::Join; + using TracksSelLf = soa::Join; + + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {120, 2.4, 3.1}, "Cand. inv-mass bins"}; + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {100, 0, 20}, "Cand. pT bins"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {100, 0, 100}, "Centrality bins"}; + ConfigurableAxis thnConfigAxisPtKaon{"thnConfigAxisPtKaon", {100, 0, 10}, "PtPion from Omegac0 bins"}; + + HistogramRegistry registry{"registry"}; // for QA of selections + + OutputObj hInvMassCharmBaryon{TH1D("hInvMassCharmBaryon", "Charm baryon invariant mass;inv mass;entries", 500, 2.0, 3.1)}; + OutputObj hPtCharmBaryon{TH1D("hPtCharmBaryon", "Charm baryon transverse momentum before sel;Pt;entries", 3000, 0., 30)}; + OutputObj hPtKaFromCharmBaryon{TH1D("hPtKaFromCharmBaryon", "Ka from charm baryon transverse momentum before sel;Pt;entries", 2000, 0., 20)}; + + void init(InitContext const&) + { + const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (#Omega#Ka) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisPtKaon{thnConfigAxisPtKaon, "Pt of Kaon from Omegac0."}; + std::vector const axes = {thnAxisMass, thnAxisPt, thnAxisPtKaon}; + registry.add("hMassVsPtVsPtKaon", "Thn for Omegac0 or Xic candidates with InvmassOmegaKa&pT&pTKa", HistType::kTHnSparseF, axes); + registry.get(HIST("hMassVsPtVsPtKaon"))->Sumw2(); + + 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("hSelEtaKaFromCharm", "hSelEtaKaFromCharm;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("hSelKfPtOmega", "hSelKfPtOmega;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelPtKaFromCharm", "hSelPtKaFromCharm;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelTPCQualityKaFromCharm", "hSelTPCQualityKaFromCharm;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("hSelITSQualityKaFromCharm", "hSelITSQualityKaFromCharm;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("hSelDcaXYToPvKaFromCasc", "hSelDcaXYToPvKaFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelCompetingCasc", "hSelCompetingCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelV0_Casc_OmegaKaldl", "hSelV0_Casc_OmegaKaldl;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelctauOmegaKa", "hSelctauOmegaKa;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelChi2GeooverNDFV0_Casc_OmegaKa", "hSelChi2GeooverNDFV0_Casc_OmegaKa;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelChi2TopooverNDFV0_Casc_OmegaKa", "hSelChi2TopooverNDFV0_Casc_OmegaKa;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSeldecayLenOmegaKa_Casc_V0", "hSeldecayLenOmegaKa_Casc_V0;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelcosPaCascToOmegaKa_V0ToCasc", "hSelcosPaCascToOmegaKa_V0ToCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hInvMassXiMinus_rej_cut", "hInvMassXiMinus_rej_cut", kTH1D, {{1000, 1.25f, 1.65f}}); + } + // for pT-dependent cuts (other selections will move into this in futrue) + // \param hfCandOmegaKa is candidate + // return true if candidate passes all cuts + template + bool selectionTopol(const T1& hfCandOmegaKa) + { + auto candpT = hfCandOmegaKa.kfPtOmegaKa(); + // check that the candidate pT is within the analysis range + if (candpT < ptCandMin || candpT > ptCandMax) { + return false; + } + auto kaPtFromOmegaKa = hfCandOmegaKa.kfPtKaFromOmegaKa(); + int const pTBin = findBin(binsPt, candpT); + if (pTBin == -1) { + return false; + } + + // check that the candidate pT is within the analysis range + if (kaPtFromOmegaKa < cuts->get(pTBin, "pT Ka from Omegac")) { + registry.fill(HIST("hSelPtKaFromCharm"), 0); + return false; + } + registry.fill(HIST("hSelPtKaFromCharm"), 1); + + return true; + } // end template + + void process(aod::HfCandToOmegaKaKf const& 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 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 const 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; + hfSelToOmegaKaKf(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()); + continue; + } + + // eta selection + double const etaV0DauPr = candidate.etaV0DauPr(); + double const etaV0DauPi = candidate.etaV0DauPi(); + double const etaKaFromCasc = candidate.etaBachFromCasc(); + double const etaKaFromCharmBaryon = candidate.etaBachFromCharmBaryon(); + if (std::abs(etaV0DauPr) > etaTrackLFDauMax) { + resultSelections = false; + registry.fill(HIST("hSelEtaPosV0Dau"), 0); + } else { + registry.fill(HIST("hSelEtaPosV0Dau"), 1); + } + if (std::abs(etaV0DauPi) > 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.xDecayVtxCascadeKf(), candidate.yDecayVtxCascadeKf()) < radiusCascMin) { + resultSelections = false; + registry.fill(HIST("hSelRadCasc"), 0); + } else { + registry.fill(HIST("hSelRadCasc"), 1); + } + if (RecoDecay::sqrtSumOfSquares(candidate.xDecayVtxV0Kf(), candidate.yDecayVtxV0Kf()) < 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); + } + + // cut on charm bachelor Kaon dcaXY + if ((std::abs(candidate.impactParBachFromCharmBaryonXY()) < impactParameterXYKaFromCharmBaryonMin) || (std::abs(candidate.impactParBachFromCharmBaryonXY()) > impactParameterXYKaFromCharmBaryonMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAXYPrimPi"), 0); + } else { + registry.fill(HIST("hSelDCAXYPrimPi"), 1); + } + + // cut on cascade dcaXY + if ((std::abs(candidate.impactParCascXY()) < impactParameterXYCascMin) || (std::abs(candidate.impactParCascXY()) > impactParameterXYCascMax)) { + resultSelections = false; + registry.fill(HIST("hSelDCAXYCasc"), 0); + } else { + registry.fill(HIST("hSelDCAXYCasc"), 1); + } + + // Charm daughter pT selections + if (std::abs(candidate.kfPtOmega()) < ptCascMin) { + resultSelections = false; + registry.fill(HIST("hSelKfPtOmega"), 0); + } else { + registry.fill(HIST("hSelKfPtOmega"), 1); + } + if (std::abs(candidate.kfPtKaFromOmegaKa()) < ptKaFromCharmBaryonMin) { + resultSelections = false; + } + + // 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.invMassCascadeRej() - 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.invMassCascadeRej()); + } + } + + // v0&Casc&OmegaKa ldl selection + if ((candidate.v0ldl() < kfConfigurableGroup.v0LdlMin) || (candidate.cascldl() < kfConfigurableGroup.cascLdlMin) || (candidate.omegaKaldl() > kfConfigurableGroup.omegaKaLdlMax)) { + resultSelections = false; + registry.fill(HIST("hSelV0_Casc_OmegaKaldl"), 0); + } else { + registry.fill(HIST("hSelV0_Casc_OmegaKaldl"), 1); + } + + // OmegaKa ctau selsection + if (candidate.cTauOmegaKa() > kfConfigurableGroup.cTauOmegaKaMax) { + resultSelections = false; + registry.fill(HIST("hSelctauOmegaKa"), 0); + } else { + registry.fill(HIST("hSelctauOmegaKa"), 1); + } + + // Chi2Geo/NDF V0&Casc&OmegaKa selection + if ((candidate.chi2GeoV0() > kfConfigurableGroup.v0Chi2OverNdfMax) || (candidate.chi2GeoV0() < 0) || (candidate.chi2GeoCasc() > kfConfigurableGroup.cascChi2OverNdfMax) || (candidate.chi2GeoCasc() < 0) || (candidate.chi2GeoOmegaKa() > kfConfigurableGroup.omegaKaChi2OverNdfMax) || (candidate.chi2GeoOmegaKa() < 0)) { + resultSelections = false; + registry.fill(HIST("hSelChi2GeooverNDFV0_Casc_OmegaKa"), 0); + } else { + registry.fill(HIST("hSelChi2GeooverNDFV0_Casc_OmegaKa"), 1); + } + + // Chi2Topo/NDF selection + if ((candidate.chi2TopoV0ToCasc() > kfConfigurableGroup.chi2TopoV0ToCascMax) || (candidate.chi2TopoV0ToCasc() < 0) || (candidate.chi2TopoKaToCasc() > kfConfigurableGroup.chi2TopoKaToCascMax) || (candidate.chi2TopoKaToCasc() < 0) || (candidate.chi2TopoCascToOmegaKa() > kfConfigurableGroup.chi2TopoCascToOmegaKaMax) || (candidate.chi2TopoCascToOmegaKa() < 0) || (candidate.chi2TopoKaToOmegaKa() > kfConfigurableGroup.chi2TopoKaToOmegaKaMax) || (candidate.chi2TopoKaToOmegaKa() < 0) || + (candidate.chi2TopoOmegaKaToPv() > kfConfigurableGroup.chi2TopoOmegaKaToPvMax) || (candidate.chi2TopoOmegaKaToPv() < 0) || (candidate.chi2TopoCascToPv() > kfConfigurableGroup.chi2TopoCascToPvMax) || (candidate.chi2TopoCascToPv() < 0) || (candidate.chi2TopoKaFromOmegaKaToPv() > kfConfigurableGroup.chi2TopoKaFromOmegaKaToPvMax) || (candidate.chi2TopoKaFromOmegaKaToPv() < 0)) { + resultSelections = false; + registry.fill(HIST("hSelChi2TopooverNDFV0_Casc_OmegaKa"), 0); + } else { + registry.fill(HIST("hSelChi2TopooverNDFV0_Casc_OmegaKa"), 1); + } + + // DecaylengthXY of OmegaKa&Casc&V0 selection + if ((std::abs(candidate.decLenCharmBaryon()) > kfConfigurableGroup.decayLenOmegaKaMax) || (std::abs(candidate.decLenCascade()) < kfConfigurableGroup.decayLenCascMin) || (std::abs(candidate.decLenV0()) < kfConfigurableGroup.decayLenLambdaMin)) { + resultSelections = false; + registry.fill(HIST("hSeldecayLenOmegaKa_Casc_V0"), 0); + } else { + registry.fill(HIST("hSeldecayLenOmegaKa_Casc_V0"), 1); + } + + // KFPA cut cosPaCascToOmegaKa cosPaV0ToCasc + if ((candidate.cosPaCascToOmegaKa() < kfConfigurableGroup.cosPaCascToOmegaKaMin) || (candidate.cosPaV0ToCasc() < kfConfigurableGroup.cosPaV0ToCascMin)) { + resultSelections = false; + registry.fill(HIST("hSelcosPaCascToOmegaKa_V0ToCasc"), 0); + } else { + registry.fill(HIST("hSelcosPaCascToOmegaKa_V0ToCasc"), 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; + + if (usePidTpcOnly && usePidTpcTofCombined) { + LOGF(fatal, "Check the PID configurables, usePidTpcOnly and usePidTpcTofCombined can't have the same value"); + } else if (!usePidTpcOnly && !usePidTpcTofCombined) { + LOGF(fatal, "At least one PID method must be enabled"); + } + + 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); + } + } 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 && statusPidKaFromCharmBaryon == TrackSelectorPID::Accepted) { + statusPidCharmBaryon = true; + if (resultSelections) { + registry.fill(HIST("hStatusCheck"), 2.5); + } + } else { + resultSelections = false; + } + + // invariant mass cuts + double const invMassLambda = candidate.invMassLambda(); + double const invMassCascade = candidate.invMassCascade(); + double const 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; + } + + hfSelToOmegaKaKf(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); + hPtCharmBaryon->Fill(candidate.kfPtOmegaKa()); + hPtKaFromCharmBaryon->Fill(candidate.kfPtKaFromOmegaKa()); + registry.fill(HIST("hMassVsPtVsPtKaon"), + candidate.invMassCharmBaryon(), + candidate.kfPtOmegaKa(), + candidate.kfPtKaFromOmegaKa()); + } + } + } // end process +}; // end struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/candidateSelectorToXiPi.cxx b/PWGHF/TableProducer/candidateSelectorToXiPi.cxx index eff8377e44a..84a6cfac6b3 100644 --- a/PWGHF/TableProducer/candidateSelectorToXiPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorToXiPi.cxx @@ -12,33 +12,57 @@ /// \file candidateSelectorToXiPi.cxx /// \brief Xic0 and Omegac0 → Xi Pi selection task /// \author Federica Zanone , Heidelberg University +/// \author Tao Fang , Central China Normal 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/Core/HfMlResponseXic0ToXiPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/Utils/utilsAnalysis.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + 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 struct HfCandidateSelectorToXiPi { Produces hfSelToXiPi; + Produces hfMlToXiPi; // LF analysis selections Configurable radiusCascMin{"radiusCascMin", 0.6, "Min cascade radius"}; @@ -114,10 +138,30 @@ struct HfCandidateSelectorToXiPi { 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"}; + // ML inference + Configurable applyMl{"applyMl", true, "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/BDTXic0ToXipiKf"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_Xic0ToXipiKf.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::HfMlResponseXic0ToXiPi hfMlResponse; + std::vector outputMlXic0ToXiPi = {}; + o2::ccdb::CcdbApi ccdbApi; + TrackSelectorPi selectorPion; TrackSelectorPr selectorProton; using TracksSel = soa::Join; + using TracksSelLf = soa::Join; HistogramRegistry registry{"registry"}; // for QA of selections @@ -173,29 +217,47 @@ struct HfCandidateSelectorToXiPi { 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}}); + + 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(); + } } void process(aod::HfCandToXiPi const& candidates, - TracksSel const&) + TracksSel const& tracks, + TracksSelLf const& lfTracks) { - double massLambdaFromPDG = o2::constants::physics::MassLambda0; - double massXiFromPDG = o2::constants::physics::MassXiMinus; + double const massLambdaFromPDG = o2::constants::physics::MassLambda0; + double const massXiFromPDG = o2::constants::physics::MassXiMinus; // looping over charm baryon candidates for (const auto& candidate : candidates) { 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.bachelorFromCharmBaryon_as(); // pion <- charm baryon + auto ptCand = RecoDecay::pt(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()); + 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 + int8_t const signDecay = candidate.signDecay(); // sign of pi <- cascade if (signDecay > 0) { trackPiFromLam = trackV0PosDau; @@ -206,10 +268,10 @@ struct HfCandidateSelectorToXiPi { } // eta selection - double etaV0PosDau = candidate.etaV0PosDau(); - double etaV0NegDau = candidate.etaV0NegDau(); - double etaPiFromCasc = candidate.etaBachFromCasc(); - double etaPiFromCharmBaryon = candidate.etaBachFromCharmBaryon(); + double const etaV0PosDau = candidate.etaV0PosDau(); + double const etaV0NegDau = candidate.etaV0NegDau(); + double const etaPiFromCasc = candidate.etaBachFromCasc(); + double const etaPiFromCharmBaryon = candidate.etaBachFromCharmBaryon(); if (std::abs(etaV0PosDau) > etaTrackLFDauMax) { resultSelections = false; registry.fill(HIST("hSelEtaPosV0Dau"), 0); @@ -287,7 +349,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 { @@ -295,7 +357,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 { @@ -331,8 +393,8 @@ struct HfCandidateSelectorToXiPi { } // pT selections - double ptPiFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); - double ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); + double const ptPiFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); + double const ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); if (std::abs(ptPiFromCasc) < ptPiFromCascMin) { resultSelections = false; registry.fill(HIST("hSelPtPiFromCasc"), 0); @@ -402,28 +464,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) { @@ -464,9 +526,9 @@ struct HfCandidateSelectorToXiPi { bool statusInvMassCascade = false; bool statusInvMassCharmBaryon = false; - double invMassLambda = candidate.invMassLambda(); - double invMassCascade = candidate.invMassCascade(); - double invMassCharmBaryon = candidate.invMassCharmBaryon(); + double const invMassLambda = candidate.invMassLambda(); + double const invMassCascade = candidate.invMassCascade(); + double const invMassCharmBaryon = candidate.invMassCharmBaryon(); if (std::abs(invMassLambda - massLambdaFromPDG) < v0MassWindow) { statusInvMassLambda = true; @@ -498,6 +560,17 @@ struct HfCandidateSelectorToXiPi { registry.fill(HIST("hSelMassCharmBaryon"), 0); } + // ML selections + if (applyMl) { + bool isSelectedMlXic0 = false; + std::vector inputFeaturesXic0 = hfMlResponse.getInputFeatures(candidate, trackPiFromLam, trackPiFromCasc, trackPiFromCharm); + isSelectedMlXic0 = hfMlResponse.isSelectedMl(inputFeaturesXic0, ptCand, outputMlXic0ToXiPi); + if (!isSelectedMlXic0) { + continue; + } + hfMlToXiPi(outputMlXic0ToXiPi); + } + hfSelToXiPi(statusPidLambda, statusPidCascade, statusPidCharmBaryon, statusInvMassLambda, statusInvMassCascade, statusInvMassCharmBaryon, resultSelections, infoTpcStored, infoTofStored, trackPiFromCharm.tpcNSigmaPi(), trackPiFromCasc.tpcNSigmaPi(), trackPiFromLam.tpcNSigmaPi(), trackPrFromLam.tpcNSigmaPr(), trackPiFromCharm.tofNSigmaPi(), trackPiFromCasc.tofNSigmaPi(), trackPiFromLam.tofNSigmaPi(), trackPrFromLam.tofNSigmaPr()); @@ -546,7 +619,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..69d2a73339b --- /dev/null +++ b/PWGHF/TableProducer/candidateSelectorXic0ToXiPiKf.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 candidateSelectorXic0ToXiPiKf.cxx +/// \brief Xic0 → Xi Pi selection task +/// \author Ran Tu , Fudan University +/// \author Tao Fang , Central China Normal University + +#include "PWGHF/Core/HfMlResponseXic0ToXiPiKf.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +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; + Produces hfMlToXiPi; + + // kinematic selections + Configurable etaTrackCharmBachMax{"etaTrackCharmBachMax", 0.8, "Max absolute value of eta for charm baryon bachelor"}; + Configurable etaTrackLFDauMax{"etaTrackLFDauMax", 0.8, "Max absolute value of eta for V0 and cascade daughters"}; + Configurable ptPiFromCascMin{"ptPiFromCascMin", 0.15, "Min pT pion <- casc"}; + + // minimum radius cut (LFcut) + Configurable radiusCascMin{"radiusCascMin", 0.5, "Min cascade radius"}; + Configurable radiusV0Min{"radiusV0Min", 1.1, "Min V0 radius"}; + + 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"}; + + // 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", 5., "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", 5., "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"}; + + // topological cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_xic_to_xi_pi::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_xic_to_xi_pi::Cuts[0], hf_cuts_xic_to_xi_pi::NBinsPt, hf_cuts_xic_to_xi_pi::NCutVars, hf_cuts_xic_to_xi_pi::labelsPt, hf_cuts_xic_to_xi_pi::labelsCutVar}, "Xic0 candidate selection per pT bin"}; + + // ML inference + Configurable applyMl{"applyMl", true, "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/BDTXic0ToXipiKf"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_Xic0ToXipiKf.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::HfMlResponseXic0ToXiPiKf hfMlResponse; + std::vector outputMlXic0ToXiPiKf; + o2::ccdb::CcdbApi ccdbApi; + + 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("hStatusCheck", "Check consecutive selections status;status;entries", {HistType::kTH1D, {{3, 0., 3.}}}); + // sign of candidates + registry.add("hSelSignDec", "hSelSignDec;status;entries", {HistType::kTH1D, {axisSel}}); + // basic selections (bin 0 -> candidates that did not pass the selection, bin 1 -> candidates that passed the selection) + registry.add("hSelPtPiFromCasc", "hSelPtPiFromCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelRadCasc", "hSelRadCasc;status;entries", {HistType::kTH1D, {axisSel}}); + registry.add("hSelRadV0", "hSelRadV0;status;entries", {HistType::kTH1D, {axisSel}}); + + // TPC and ITS selections (bin 0 -> candidates that did not pass the selection, bin 1 -> candidates that passed the selection) + 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("hSelPID", "hSelPID;status;entries", {HistType::kTH1D, {{12, 0., 12.}}}); + 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("hSelMlXic0", "hSelMlXic0;status;entries", {HistType::kTH1D, {axisSel}}); + + 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(); + } + } + + void process(aod::HfCandToXiPiKf const& candidates, + TracksSel const& tracks, + TracksSelLf const& lfTracks) + { + + // looping over charm baryon candidates + for (const auto& candidate : candidates) { + + outputMlXic0ToXiPiKf.clear(); + + auto ptCand = RecoDecay::pt(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()); + + 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 const 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 const etaV0PosDau = candidate.etaV0PosDau(); + double const etaV0NegDau = candidate.etaV0NegDau(); + double const etaPiFromCasc = candidate.etaBachFromCasc(); + double const etaPiFromCharmBaryon = candidate.etaBachFromCharmBaryon(); + if (std::abs(etaV0PosDau) > etaTrackLFDauMax || std::abs(etaV0NegDau) > etaTrackLFDauMax || std::abs(etaPiFromCasc) > etaTrackLFDauMax || std::abs(etaPiFromCharmBaryon) > etaTrackCharmBachMax) { + resultSelections = false; + } + double const ptPiFromCasc = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCasc(), candidate.pyBachFromCasc()); + if (std::abs(ptPiFromCasc) < ptPiFromCascMin) { + resultSelections = false; + registry.fill(HIST("hSelPtPiFromCasc"), 0); + } else { + registry.fill(HIST("hSelPtPiFromCasc"), 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); + } + + // 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; + } else { + registry.fill(HIST("hStatusCheck"), 2.5); + resultSelections = false; + } + + // invariant mass cuts + bool statusInvMassLambda = false; + bool statusInvMassCascade = false; + bool statusInvMassCharmBaryon = false; + + double const invMassLambda = candidate.invMassLambda(); + double const invMassCascade = candidate.invMassCascade(); + double const invMassCharmBaryon = candidate.invMassCharmBaryon(); + + if (resultSelections) { + resultSelections = selectionTopolKf(candidate); + if (std::abs(invMassLambda - o2::constants::physics::MassLambda0) < v0MassWindow) { + statusInvMassLambda = true; + registry.fill(HIST("hSelMassLam"), 1); + } else { + resultSelections = false; + registry.fill(HIST("hSelMassLam"), 0); + } + + if (std::abs(invMassCascade - o2::constants::physics::MassXiMinus) < cascadeMassWindow) { + statusInvMassCascade = true; + registry.fill(HIST("hSelMassCasc"), 1); + } else { + resultSelections = false; + registry.fill(HIST("hSelMassCasc"), 0); + } + + if ((invMassCharmBaryon >= invMassCharmBaryonMin) && (invMassCharmBaryon <= invMassCharmBaryonMax)) { + statusInvMassCharmBaryon = true; + registry.fill(HIST("hSelMassCharmBaryon"), 1); + } else { + resultSelections = false; + registry.fill(HIST("hSelMassCharmBaryon"), 0); + } + } + // ML selections + if (applyMl) { + bool isSelectedMlXic0 = false; + std::vector inputFeaturesXic0 = hfMlResponse.getInputFeatures(candidate, trackPiFromLam, trackPiFromCasc, trackPiFromCharm); + if (!resultSelections) { + hfMlToXiPi(outputMlXic0ToXiPiKf); + } else { + isSelectedMlXic0 = hfMlResponse.isSelectedMl(inputFeaturesXic0, ptCand, outputMlXic0ToXiPiKf); + registry.fill(HIST("hSelMlXic0"), isSelectedMlXic0); + hfMlToXiPi(outputMlXic0ToXiPiKf); + } + } + + hfSelToXiPi(resultSelections, + 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 + + /// \param candidate is candidate + /// \return true if candidate passes all cuts + template + bool selectionTopolKf(const T& candidate) + { + auto candpT = RecoDecay::pt(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()); + + int const pTBin = findBin(binsPt, candpT); + if (pTBin == -1) { + return false; + } + + double const ptPiFromCharmBaryon = RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()); + if (ptPiFromCharmBaryon <= cuts->get(pTBin, "ptPiFromCharmBaryon")) { + return false; + } + + // cosPA (LFcut) + if (candidate.cosPACasc() < cuts->get(pTBin, "cosPACasc")) { + return false; + } + if (candidate.cosPAV0() < cuts->get(pTBin, "cosPAV0")) { + return false; + } + if (candidate.cosPaCascToXic() < cuts->get(pTBin, "cosPaCascToXic")) { + return false; + } + if (candidate.cosPaV0ToCasc() < cuts->get(pTBin, "cosPaV0ToCasc")) { + return false; + } + + // dca cut + if (candidate.dcaCharmBaryonDau() > cuts->get(pTBin, "dcaCharmBaryonDau")) { + return false; + } + if (candidate.dcaCascDau() > cuts->get(pTBin, "dcaCascDau")) { + return false; + } + + if (candidate.dcaV0Dau() > cuts->get(pTBin, "dcaV0Dau")) { + return false; + } + + // dcaXY pion <-- cascade to PV cut + if (std::abs(candidate.dcaXYToPvCascDau()) < cuts->get(pTBin, "dcaXYToPvCascDau")) { + return false; + } + + // dcaXY v0 daughters to PV cut + if (std::abs(candidate.dcaXYToPvV0Dau0()) < cuts->get(pTBin, "dcaXYToPvV0Dau0") || std::abs(candidate.dcaXYToPvV0Dau1()) < cuts->get(pTBin, "dcaXYToPvV0Dau0")) { + return false; + } + + // dacXY pion <-- Xic0 to PV cut + if (std::abs(candidate.kfDcaXYPiFromXic()) > cuts->get(pTBin, "kfDcaXYPiFromXic")) { + return false; + } + + // dacXY cascade to PV cut + if (std::abs(candidate.kfDcaXYCascToPv()) > cuts->get(pTBin, "kfDcaXYCascToPv")) { + return false; + } + + // Chi2Geo + if (candidate.chi2GeoXic() < 0 || candidate.chi2GeoXic() > cuts->get(pTBin, "chi2GeoXic")) { + return false; + } + if (candidate.chi2GeoCasc() < 0 || candidate.chi2GeoCasc() > cuts->get(pTBin, "chi2GeoCasc")) { + return false; + } + if (candidate.chi2GeoV0() < 0 || candidate.chi2GeoV0() > cuts->get(pTBin, "chi2GeoV0")) { + return false; + } + + // Chi2Topo + if (candidate.chi2TopoXicToPv() < 0 || candidate.chi2TopoXicToPv() > cuts->get(pTBin, "chi2TopoXicToPv")) { + return false; + } + if (candidate.chi2TopoPiFromXicToPv() < 0 || candidate.chi2TopoPiFromXicToPv() > cuts->get(pTBin, "chi2TopoPiFromXicToPv")) { + return false; + } + if (candidate.chi2TopoCascToPv() < 0 || candidate.chi2TopoCascToPv() > cuts->get(pTBin, "chi2TopoCascToPv")) { + return false; + } + if (candidate.chi2TopoV0ToPv() > 0 && candidate.chi2TopoV0ToPv() < cuts->get(pTBin, "chi2TopoV0ToPv")) { + return false; + } + if (candidate.chi2TopoV0ToCasc() < 0 || candidate.chi2TopoV0ToCasc() > cuts->get(pTBin, "chi2TopoV0ToCasc")) { + return false; + } + if (candidate.chi2TopoCascToXic() < 0 || candidate.chi2TopoCascToXic() > cuts->get(pTBin, "chi2TopoCascToXic")) { + return false; + } + + // ldl + if (candidate.cascldl() < cuts->get(pTBin, "cascldl")) { + return false; + } + if (candidate.v0ldl() < cuts->get(pTBin, "v0ldl")) { + return false; + } + // decay length + if (std::abs(candidate.decayLenXYXic()) > cuts->get(pTBin, "decayLenXYXic")) { + return false; + } + if (std::abs(candidate.decayLenXYCasc()) < cuts->get(pTBin, "decayLenXYCasc")) { + return false; + } + if (std::abs(candidate.decayLenXYLambda()) < cuts->get(pTBin, "decayLenXYLambda")) { + return false; + } + // ctau + if (std::abs(candidate.cTauXic()) > cuts->get(pTBin, "cTauXic")) { + return false; + } + return true; + } + +}; // 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..cd7d7028925 100644 --- a/PWGHF/TableProducer/candidateSelectorXicToPKPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorXicToPKPi.cxx @@ -17,17 +17,35 @@ /// \author Vít Kučera , CERN /// \author Cristina Terrevoli , INFN BARI -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -#include "Common/Core/TrackSelectorPID.h" - -#include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponseXicToPKPi.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -41,6 +59,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 +74,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,17 +88,20 @@ 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 = {}; - std::vector outputMlXicToPiKP = {}; + std::vector outputMlXicToPKPi; + std::vector outputMlXicToPiKP; o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; TrackSelectorKa selectorKaon; TrackSelectorPr selectorProton; - HfHelper hfHelper; - using TracksSel = soa::Join; + using TracksSel = soa::Join; + + HistogramRegistry registry{"registry"}; void init(InitContext const&) { @@ -91,6 +114,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) { @@ -111,7 +149,7 @@ struct HfCandidateSelectorXicToPKPi { bool selectionTopol(const T& candidate) { auto candpT = candidate.pt(); - int pTBin = findBin(binsPt, candpT); + int const pTBin = findBin(binsPt, candpT); if (pTBin == -1) { return false; } @@ -152,7 +190,7 @@ struct HfCandidateSelectorXicToPKPi { } // candidate ct - if (hfHelper.ctXic(candidate) > cuts->get(pTBin, "ct")) { + if (HfHelper::ctXic(candidate) > cuts->get(pTBin, "ct")) { return false; } @@ -175,7 +213,7 @@ struct HfCandidateSelectorXicToPKPi { { auto candpT = candidate.pt(); - int pTBin = findBin(binsPt, candpT); + int const pTBin = findBin(binsPt, candpT); if (pTBin == -1) { return false; } @@ -186,11 +224,11 @@ struct HfCandidateSelectorXicToPKPi { } if (trackProton.globalIndex() == candidate.prong0Id()) { - if (std::abs(hfHelper.invMassXicToPKPi(candidate) - o2::constants::physics::MassXiCPlus) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassXicToPKPi(candidate) - o2::constants::physics::MassXiCPlus) > cuts->get(pTBin, "m")) { return false; } } else { - if (std::abs(hfHelper.invMassXicToPiKP(candidate) - o2::constants::physics::MassXiCPlus) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassXicToPiKP(candidate) - o2::constants::physics::MassXiCPlus) > cuts->get(pTBin, "m")) { return false; } } @@ -198,7 +236,7 @@ struct HfCandidateSelectorXicToPKPi { return true; } - void process(aod::HfCand3Prong const& candidates, + void process(aod::HfCand3ProngWPidPiKaPr const& candidates, TracksSel const&) { // looping over 3-prong candidates @@ -211,18 +249,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) @@ -240,8 +284,8 @@ struct HfCandidateSelectorXicToPKPi { // conjugate-dependent topplogical selection for Xic - bool topolXicToPKPi = selectionTopolConjugate(candidate, trackPos1, trackNeg, trackPos2); - bool topolXicToPiKP = selectionTopolConjugate(candidate, trackPos2, trackNeg, trackPos1); + bool const topolXicToPKPi = selectionTopolConjugate(candidate, trackPos1, trackNeg, trackPos2); + bool const topolXicToPiKP = selectionTopolConjugate(candidate, trackPos2, trackNeg, trackPos1); if (!topolXicToPKPi && !topolXicToPiKP) { hfSelXicToPKPiCandidate(statusXicToPKPi, statusXicToPiKP); @@ -257,6 +301,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 +314,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::Status pidTrackPos2Proton; + TrackSelectorPID::Status pidTrackPos1Pion; + TrackSelectorPID::Status pidTrackPos2Pion; + TrackSelectorPID::Status pidTrackNegKaon; + if (usePidTpcAndTof) { + + pidTrackPos1Proton = selectorProton.statusTpcAndTof(trackPos1, candidate.nSigTpcPr0(), candidate.nSigTofPr0()); + pidTrackPos2Proton = selectorProton.statusTpcAndTof(trackPos2, candidate.nSigTpcPr2(), candidate.nSigTofPr2()); + pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + } else { + pidTrackPos1Proton = selectorProton.statusTpcOrTof(trackPos1, candidate.nSigTpcPr0(), candidate.nSigTofPr0()); + pidTrackPos2Proton = selectorProton.statusTpcOrTof(trackPos2, candidate.nSigTpcPr2(), candidate.nSigTofPr2()); + pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + } if (pidTrackPos1Proton == TrackSelectorPID::Accepted && pidTrackNegKaon == TrackSelectorPID::Accepted && @@ -306,18 +368,21 @@ 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 bool isSelectedMlXicToPKPi = false; bool isSelectedMlXicToPiKP = false; - if (topolXicToPKPi && pidXicToPKPi) { - std::vector inputFeaturesXicToPKPi = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); + if (topolXicToPKPi && (pidXicToPKPi != 0)) { + std::vector inputFeaturesXicToPKPi = hfMlResponse.getInputFeatures(candidate, true); isSelectedMlXicToPKPi = hfMlResponse.isSelectedMl(inputFeaturesXicToPKPi, ptCand, outputMlXicToPKPi); } - if (topolXicToPiKP && pidXicToPiKP) { - std::vector inputFeaturesXicToPiKP = hfMlResponse.getInputFeatures(candidate, trackPos1, trackNeg, trackPos2); + if (topolXicToPiKP && (pidXicToPiKP != 0)) { + std::vector inputFeaturesXicToPiKP = hfMlResponse.getInputFeatures(candidate, false); isSelectedMlXicToPiKP = hfMlResponse.isSelectedMl(inputFeaturesXicToPiKP, ptCand, outputMlXicToPiKP); } @@ -332,7 +397,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 index 5e2d69d04bd..6355024ec2b 100644 --- a/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx @@ -12,17 +12,37 @@ /// \file candidateSelectorXicToXiPiPi.cxx /// \brief Ξc± → Ξ∓ π± π± candidate selector /// -/// \author Phil Lennart Stahlhut , CERN - -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -#include "Common/Core/TrackSelectorPID.h" +/// \author Phil Lennart Stahlhut , Heidelberg University +/// \author Jaeyoon Cho , Inha University +#include "PWGHF/Core/HfMlResponseXicToXiPiPi.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/Utils/utilsAnalysis.h" // findBin function +#include "PWGHF/Utils/utilsAnalysis.h" + +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -31,17 +51,14 @@ 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"}; + 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"}; + Configurable fillQAHistograms{"fillQAHistograms", false, "Switch to enable filling of QA histograms"}; // 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"}; + Configurable useTpcPidOnly{"useTpcPidOnly", false, "Switch to use TPC PID only instead of TPC OR TOF)"}; // 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"}; @@ -52,16 +69,62 @@ struct HfCandidateSelectorXicToXiPiPi { 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"}; - + // TrackQualitySelection + Configurable doTrackQualitySelection{"doTrackQualitySelection", true, "Switch to apply track quality selections on final state daughter particles"}; + 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"}; + // 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; + enum XicSelCriteria { All = 0, + Pt, + Mass, + Rapidity, + Eta, + EtaPionFromXicPlus, + EtaXiDaughters, + PtPionFromXicPlus, + Chi2SV, + MinDecayLength, + MaxInvMassXiPiPairs, + TpcTrackQualityXiDaughters, + TpcTrackQualityPiFromCharm, + ItsTrackQualityPiFromCharm, + PidSelected, + BdtSelected, + NSelectionCriteria }; + + using TracksExtraWPid = soa::Join; HistogramRegistry registry{"registry"}; void init(InitContext&) { + if ((doprocessData + doprocessMc) != 1) { + LOGP(fatal, "Enable exactly one process function at a time."); + } + if (usePid) { // pion selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); @@ -79,171 +142,626 @@ struct HfCandidateSelectorXicToXiPiPi { 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()); + std::string labels[NSelectionCriteria]; + labels[All] = "All"; + labels[Pt] = "#it{p}_{T}"; + labels[Mass] = "#Delta M"; + labels[Rapidity] = "y"; + labels[Eta] = "#eta"; + labels[EtaPionFromXicPlus] = "#eta (#pi #leftarrow #Xi_{c}^{#plus})"; + labels[EtaXiDaughters] = "#eta (#Xi daughters)"; + labels[PtPionFromXicPlus] = "#it{p}_{T} (#pi #leftarrow #Xi_{c}^{#plus})"; + labels[Chi2SV] = "#chi^{2}_{SV}"; + labels[MinDecayLength] = "Decay length"; + labels[MaxInvMassXiPiPairs] = "M_{#Xi #pi}"; + labels[TpcTrackQualityXiDaughters] = "TPC track quality selection on #Xi daughters"; + labels[TpcTrackQualityPiFromCharm] = "TPC track quality selection on #pi #leftarrow #Xi_{c}^{#plus}"; + labels[ItsTrackQualityPiFromCharm] = "ITS track quality selection on #pi #leftarrow #Xi_{c}^{#plus}"; + labels[PidSelected] = "PID selection"; + labels[BdtSelected] = "BDT selection"; + + if (doprocessData) { + registry.add("hSelCandidates", ";;entries", {HistType::kTH1D, {{NSelectionCriteria, -0.5f, +NSelectionCriteria - 0.5f}}}); + for (int iBin = 0; iBin < NSelectionCriteria; ++iBin) { + registry.get(HIST("hSelCandidates"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + } + } else if (doprocessMc) { + registry.add("hSelCandidatesRecSig", ";;entries", {HistType::kTH1D, {{NSelectionCriteria, -0.5f, +NSelectionCriteria - 0.5f}}}); + registry.add("hSelCandidatesRecBkg", ";;entries", {HistType::kTH1D, {{NSelectionCriteria, -0.5f, +NSelectionCriteria - 0.5f}}}); + for (int iBin = 0; iBin < NSelectionCriteria; ++iBin) { + registry.get(HIST("hSelCandidatesRecSig"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + registry.get(HIST("hSelCandidatesRecBkg"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } } + + if (fillQAHistograms) { + if (doprocessData) { + // eta of all final state daughters + registry.add("hEtaPi0FromXic", ";#eta (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaPi1FromXic", ";#eta (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaBachelorPion", ";#eta (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaV0PosDau", ";;#eta (V0 pos. dau.);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaV0NegDau", ";;#eta (V0 neg. dau.);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + // pions from XicPlus + registry.add("hNClustersTpcPi0FromXic", ";#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcPi1FromXic", ";#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcPi0FromXic", ";#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcPi1FromXic", ";#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersItsPi0FromXic", ";#it{N}_{clusters}^{ITS} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{7, 0.5, 7.5}}}); + registry.add("hNClustersItsPi1FromXic", ";#it{N}_{clusters}^{ITS} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{7, 0.5, 7.5}}}); + registry.add("hNClustersItsInnBarrPi0FromXic", ";#it{N}_{clusters}^{ITS-IB} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{3, 0.5, 3.5}}}); + registry.add("hNClustersItsInnBarrPi1FromXic", ";#it{N}_{clusters}^{ITS-IB} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{3, 0.5, 3.5}}}); + // Xi daughters + registry.add("hNClustersTpcBachelorPion", ";#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcV0PosDau", ";#it{N}_{clusters}^{TPC} (V0 pos. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcV0NegDau", ";#it{N}_{clusters}^{TPC} (V0 neg. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcBachelorPion", ";#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcV0PosDau", ";#it{N}_{rows}^{TPC} (V0 pos. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcV0NegDau", ";#it{N}_{rows}^{TPC} (V0 neg. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + } else if (doprocessMc) { + // Reconstructed signal + // eta of all final state daughters + registry.add("hEtaPi0FromXicRecSig", "Reconstructed signal;#eta (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaPi1FromXicRecSig", "Reconstructed signal;#eta (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaBachelorPionRecSig", "Reconstructed signal;#eta (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaV0PosDauRecSig", "Reconstructed signal;#eta (V0 pos. dau.);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaV0NegDauRecSig", "Reconstructed signal;#eta (V0 neg. dau.);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + // pions from XicPlus + registry.add("hNClustersTpcPi0FromXicRecSig", "Reconstructed signal;#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcPi1FromXicRecSig", "Reconstructed signal;#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcPi0FromXicRecSig", "Reconstructed signal;#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcPi1FromXicRecSig", "Reconstructed signal;#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersItsPi0FromXicRecSig", "Reconstructed signal;#it{N}_{clusters}^{ITS} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{7, 0.5, 7.5}}}); + registry.add("hNClustersItsPi1FromXicRecSig", "Reconstructed signal;#it{N}_{clusters}^{ITS} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{7, 0.5, 7.5}}}); + registry.add("hNClustersItsInnBarrPi0FromXicRecSig", "Reconstructed signal;#it{N}_{clusters}^{ITS-IB} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{3, 0.5, 3.5}}}); + registry.add("hNClustersItsInnBarrPi1FromXicRecSig", "Reconstructed signal;#it{N}_{clusters}^{ITS-IB} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{3, 0.5, 3.5}}}); + // Xi daughters + registry.add("hNClustersTpcBachelorPionRecSig", "Reconstructed signal;#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcV0PosDauRecSig", "Reconstructed signal;#it{N}_{clusters}^{TPC} (V0 pos. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcV0NegDauRecSig", "Reconstructed signal;#it{N}_{clusters}^{TPC} (V0 neg. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcBachelorPionRecSig", "Reconstructed signal;#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcV0PosDauRecSig", "Reconstructed signal;#it{N}_{rows}^{TPC} (V0 pos. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcV0NegDauRecSig", "Reconstructed signal;#it{N}_{rows}^{TPC} (V0 neg. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + // Reconstructed background + // eta of all final state daughters + registry.add("hEtaPi0FromXicRecBkg", "Reconstructed background;#eta (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaPi1FromXicRecBkg", "Reconstructed background;#eta (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaBachelorPionRecBkg", "Reconstructed background;#eta (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaV0PosDauRecBkg", "Reconstructed background;#eta (V0 pos. dau.);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + registry.add("hEtaV0NegDauRecBkg", "Reconstructed background;#eta (V0 neg. dau.);entries", {HistType::kTH1F, {{150, -1.5f, +1.5f}}}); + // pions from XicPlus + registry.add("hNClustersTpcPi0FromXicRecBkg", "Reconstructed background;#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcPi1FromXicRecBkg", "Reconstructed background;#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcPi0FromXicRecBkg", "Reconstructed background;#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcPi1FromXicRecBkg", "Reconstructed background;#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersItsPi0FromXicRecBkg", "Reconstructed background;#it{N}_{clusters}^{ITS} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{7, 0.5, 7.5}}}); + registry.add("hNClustersItsPi1FromXicRecBkg", "Reconstructed background;#it{N}_{clusters}^{ITS} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{7, 0.5, 7.5}}}); + registry.add("hNClustersItsInnBarrPi0FromXicRecBkg", "Reconstructed background;#it{N}_{clusters}^{ITS-IB} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{3, 0.5, 3.5}}}); + registry.add("hNClustersItsInnBarrPi1FromXicRecBkg", "Reconstructed background;#it{N}_{clusters}^{ITS-IB} (#pi #leftarrow #Xi_{c}^{#plus});entries", {HistType::kTH1F, {{3, 0.5, 3.5}}}); + // Xi daughters + registry.add("hNClustersTpcBachelorPionRecBkg", "Reconstructed background;#it{N}_{clusters}^{TPC} (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcV0PosDauRecBkg", "Reconstructed background;#it{N}_{clusters}^{TPC} (V0 pos. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNClustersTpcV0NegDauRecBkg", "Reconstructed background;#it{N}_{clusters}^{TPC} (V0 neg. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcBachelorPionRecBkg", "Reconstructed background;#it{N}_{rows}^{TPC} (#pi #leftarrow #Xi);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcV0PosDauRecBkg", "Reconstructed background;#it{N}_{rows}^{TPC} (V0 pos. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + registry.add("hNCrossedRowsTpcV0NegDauRecBkg", "Reconstructed background;#it{N}_{rows}^{TPC} (V0 neg. dau.);entries", {HistType::kTH1F, {{103, 49.5, 152.5}}}); + } + } + + 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(); + } + } + + /// Apply PID selection + /// \param statusPidPi0 PID status of prong1 with pion hypothesis + /// \param statusPidPi1 PID status of prong2 with pion hypothesis + /// \param statusPidPiXi PID status of bachelor track with pion hypothesis + /// \param statusPidPrLam PID status of V0 daughter with proton hypothesis + /// \param statusPidPiLam PID status of V0 daughter with pion hypothesis + /// \param usePidTpcOnly switch to check only TPC status + /// \return true if prongs of Xic candidate pass all PID selections + bool isSelectedPid(TrackSelectorPID::Status const statusPidPi0, + TrackSelectorPID::Status const statusPidPi1, + TrackSelectorPID::Status const statusPidPiXi, + TrackSelectorPID::Status const statusPidPrLam, + TrackSelectorPID::Status const statusPidPiLam, + bool const useTpcPidOnly) + { + if (useTpcPidOnly) { + return (statusPidPi0 == TrackSelectorPID::Accepted || statusPidPi0 == TrackSelectorPID::NotApplicable) && (statusPidPi1 == TrackSelectorPID::Accepted || statusPidPi1 == TrackSelectorPID::NotApplicable) && (statusPidPiXi == TrackSelectorPID::Accepted || statusPidPiXi == TrackSelectorPID::NotApplicable) && (statusPidPrLam == TrackSelectorPID::Accepted || statusPidPrLam == TrackSelectorPID::NotApplicable) && (statusPidPiLam == TrackSelectorPID::Accepted || statusPidPiLam == TrackSelectorPID::NotApplicable); + } + if (statusPidPi0 == TrackSelectorPID::Rejected || statusPidPi1 == TrackSelectorPID::Rejected || statusPidPiXi == TrackSelectorPID::Rejected || statusPidPrLam == TrackSelectorPID::Rejected || statusPidPiLam == TrackSelectorPID::Rejected) { + return false; + } + return true; } - /// Conjugate-independent topological cuts - /// \param candidate is candidate - /// \return true if candidate passes all cuts - template - bool selectionTopol(const T1& hfCandXic) + /// Combine kinematic, topological, track quality and PID selections + /// \param hfCandXic Xic candidate + /// \param statusXicToXiPiPi Flag to store selection status as defined in hf_sel_candidate_xic::XicToXiPiPiSelectionStep + /// \param isMatchedSignal Flag to indicate if the candidate is matched to a genereated XiCplus MC particle + /// \return true if Xic candidate passes all selections, otherwise false + template + bool isSelectedXicToXiPiPiCandidateWoMl(XicCandidate const& hfCandXic, + TracksExtraWPid const&, + int& statusXicToXiPiPi, + bool const isMatchedSignal = false) { - auto candpT = hfCandXic.pt(); - int pTBin = findBin(binsPt, candpT); + // Successful reconstruction + SETBIT(statusXicToXiPiPi, hf_sel_candidate_xic::XicToXiPiPiSelectionStep::RecoTotal); // RecoTotal = 0 --> statusXicToXiPiPi += 1 + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), All); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), All); + } + } else { + registry.fill(HIST("hSelCandidates"), All); + } + + // Retrieve daughter tracks + auto trackPi0 = hfCandXic.template pi0_as(); + auto trackPi1 = hfCandXic.template pi1_as(); + auto trackPiFromXi = hfCandXic.template bachelor_as(); + auto trackV0PosDau = hfCandXic.template posTrack_as(); + auto trackV0NegDau = hfCandXic.template negTrack_as(); + + if (fillQAHistograms) { + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hEtaPi0FromXicRecSig"), trackPi0.eta()); + registry.fill(HIST("hEtaPi1FromXicRecSig"), trackPi1.eta()); + registry.fill(HIST("hEtaBachelorPionRecSig"), trackPiFromXi.eta()); + registry.fill(HIST("hEtaV0PosDauRecSig"), trackV0PosDau.eta()); + registry.fill(HIST("hEtaV0NegDauRecSig"), trackV0NegDau.eta()); + registry.fill(HIST("hNClustersTpcPi0FromXicRecSig"), trackPi0.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcPi1FromXicRecSig"), trackPi1.tpcNClsFound()); + registry.fill(HIST("hNCrossedRowsTpcPi0FromXicRecSig"), trackPi0.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcPi1FromXicRecSig"), trackPi1.tpcNClsCrossedRows()); + registry.fill(HIST("hNClustersItsPi0FromXicRecSig"), trackPi0.itsNCls()); + registry.fill(HIST("hNClustersItsPi1FromXicRecSig"), trackPi1.itsNCls()); + registry.fill(HIST("hNClustersItsInnBarrPi0FromXicRecSig"), trackPi0.itsNClsInnerBarrel()); + registry.fill(HIST("hNClustersItsInnBarrPi1FromXicRecSig"), trackPi1.itsNClsInnerBarrel()); + registry.fill(HIST("hNClustersTpcBachelorPionRecSig"), trackPiFromXi.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcV0PosDauRecSig"), trackV0PosDau.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcV0NegDauRecSig"), trackV0NegDau.tpcNClsFound()); + registry.fill(HIST("hNCrossedRowsTpcBachelorPionRecSig"), trackPiFromXi.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcV0PosDauRecSig"), trackV0PosDau.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcV0NegDauRecSig"), trackV0NegDau.tpcNClsCrossedRows()); + } else { + registry.fill(HIST("hEtaPi0FromXicRecBkg"), trackPi0.eta()); + registry.fill(HIST("hEtaPi1FromXicRecBkg"), trackPi1.eta()); + registry.fill(HIST("hEtaBachelorPionRecBkg"), trackPiFromXi.eta()); + registry.fill(HIST("hEtaV0PosDauRecBkg"), trackV0PosDau.eta()); + registry.fill(HIST("hEtaV0NegDauRecBkg"), trackV0NegDau.eta()); + registry.fill(HIST("hNClustersTpcPi0FromXicRecBkg"), trackPi0.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcPi1FromXicRecBkg"), trackPi1.tpcNClsFound()); + registry.fill(HIST("hNCrossedRowsTpcPi0FromXicRecBkg"), trackPi0.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcPi1FromXicRecBkg"), trackPi1.tpcNClsCrossedRows()); + registry.fill(HIST("hNClustersItsPi0FromXicRecBkg"), trackPi0.itsNCls()); + registry.fill(HIST("hNClustersItsPi1FromXicRecBkg"), trackPi1.itsNCls()); + registry.fill(HIST("hNClustersItsInnBarrPi0FromXicRecBkg"), trackPi0.itsNClsInnerBarrel()); + registry.fill(HIST("hNClustersItsInnBarrPi1FromXicRecBkg"), trackPi1.itsNClsInnerBarrel()); + registry.fill(HIST("hNClustersTpcBachelorPionRecBkg"), trackPiFromXi.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcV0PosDauRecBkg"), trackV0PosDau.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcV0NegDauRecBkg"), trackV0NegDau.tpcNClsFound()); + registry.fill(HIST("hNCrossedRowsTpcBachelorPionRecBkg"), trackPiFromXi.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcV0PosDauRecBkg"), trackV0PosDau.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcV0NegDauRecBkg"), trackV0NegDau.tpcNClsCrossedRows()); + } + } else { + registry.fill(HIST("hEtaPi0FromXic"), trackPi0.eta()); + registry.fill(HIST("hEtaPi1FromXic"), trackPi1.eta()); + registry.fill(HIST("hEtaBachelorPion"), trackPiFromXi.eta()); + registry.fill(HIST("hEtaV0PosDau"), trackV0PosDau.eta()); + registry.fill(HIST("hEtaV0NegDau"), trackV0NegDau.eta()); + registry.fill(HIST("hNClustersTpcPi0FromXic"), trackPi0.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcPi1FromXic"), trackPi1.tpcNClsFound()); + registry.fill(HIST("hNCrossedRowsTpcPi0FromXic"), trackPi0.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcPi1FromXic"), trackPi1.tpcNClsCrossedRows()); + registry.fill(HIST("hNClustersItsPi0FromXic"), trackPi0.itsNCls()); + registry.fill(HIST("hNClustersItsPi1FromXic"), trackPi1.itsNCls()); + registry.fill(HIST("hNClustersItsInnBarrPi0FromXic"), trackPi0.itsNClsInnerBarrel()); + registry.fill(HIST("hNClustersItsInnBarrPi1FromXic"), trackPi1.itsNClsInnerBarrel()); + registry.fill(HIST("hNClustersTpcBachelorPion"), trackPiFromXi.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcV0PosDau"), trackV0PosDau.tpcNClsFound()); + registry.fill(HIST("hNClustersTpcV0NegDau"), trackV0NegDau.tpcNClsFound()); + registry.fill(HIST("hNCrossedRowsTpcBachelorPion"), trackPiFromXi.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcV0PosDau"), trackV0PosDau.tpcNClsCrossedRows()); + registry.fill(HIST("hNCrossedRowsTpcV0NegDau"), trackV0NegDau.tpcNClsCrossedRows()); + } + } + + //////////////////////////////////////////////// + // Kinematic and topological selection // + //////////////////////////////////////////////// + + // check whether candidate is in analyzed pT range + auto ptCandXic = hfCandXic.pt(); + int const pTBin = findBin(binsPt, ptCandXic); if (pTBin == -1) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), Pt); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), Pt); + } + } else { + registry.fill(HIST("hSelCandidates"), Pt); + } - // check that the candidate pT is within the analysis range - if (candpT < ptCandMin || candpT >= ptCandMax) { + // check whether candidate mass is within a defined mass window + if (std::abs(hfCandXic.invMassXicPlus() - o2::constants::physics::MassXiCPlus) > cuts->get(pTBin, "m")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), Mass); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), Mass); + } + } else { + registry.fill(HIST("hSelCandidates"), Mass); + } - // check candidate mass is within a defined mass window - if (std::abs(hfCandXic.invMassXic() - o2::constants::physics::MassXiCPlus) > cuts->get(pTBin, "m")) { + // cut on candidate rapidity + if (std::abs(hfCandXic.y(o2::constants::physics::MassXiCPlus)) > cuts->get(pTBin, "y")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), Rapidity); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), Rapidity); + } + } else { + registry.fill(HIST("hSelCandidates"), Rapidity); + } - // cosine of pointing angle - if (hfCandXic.cpa() <= cuts->get(pTBin, "cos pointing angle")) { + // cut on candidate pseudorapidity + if (std::abs(hfCandXic.eta()) > cuts->get(pTBin, "eta")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), Eta); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), Eta); + } + } else { + registry.fill(HIST("hSelCandidates"), Eta); + } - // cosine of pointing angle XY - if (hfCandXic.cpaXY() <= cuts->get(pTBin, "cos pointing angle XY")) { + // cut on pseudorapidity of pions from XicPlus + if (std::abs(trackPi0.eta()) > cuts->get(pTBin, "eta Pi from XicPlus") || std::abs(trackPi1.eta()) > cuts->get(pTBin, "eta Pi from XicPlus")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), EtaPionFromXicPlus); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), EtaPionFromXicPlus); + } + } else { + registry.fill(HIST("hSelCandidates"), EtaPionFromXicPlus); + } - // candidate maximum decay length - if (hfCandXic.decayLength() > cuts->get(pTBin, "max decay length")) { + // cut on pseudorapidity of Xi daughters + if (std::abs(trackPiFromXi.eta()) > cuts->get(pTBin, "eta Xi Daughters") || std::abs(trackV0PosDau.eta()) > cuts->get(pTBin, "eta Xi Daughters") || std::abs(trackV0NegDau.eta()) > cuts->get(pTBin, "eta Xi Daughters")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), EtaXiDaughters); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), EtaXiDaughters); + } + } else { + registry.fill(HIST("hSelCandidates"), EtaXiDaughters); + } - // candidate maximum decay length XY - if (hfCandXic.decayLengthXY() > cuts->get(pTBin, "max decay length XY")) { + // cut on pion pT + if (hfCandXic.ptProng1() < cuts->get(pTBin, "pT Pi0") || hfCandXic.ptProng2() < cuts->get(pTBin, "pT Pi1") || (hfCandXic.ptProng1() + hfCandXic.ptProng2()) < cuts->get(pTBin, "pT Pi0 + Pi1")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), PtPionFromXicPlus); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), PtPionFromXicPlus); + } + } else { + registry.fill(HIST("hSelCandidates"), PtPionFromXicPlus); + } - // candidate chi2PC - if (hfCandXic.chi2PCA() > cuts->get(pTBin, "chi2PCA")) { + // cut on chi2 of secondary vertex + if (hfCandXic.chi2PCA() > cuts->get(pTBin, "chi2SV")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), Chi2SV); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), Chi2SV); + } + } else { + registry.fill(HIST("hSelCandidates"), Chi2SV); + } - // 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"))) { + // cut on candidate decay length + if (hfCandXic.decayLength() < cuts->get(pTBin, "min decay length") || hfCandXic.decayLengthXY() < cuts->get(pTBin, "min decay length XY")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), MinDecayLength); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), MinDecayLength); + } + } else { + registry.fill(HIST("hSelCandidates"), MinDecayLength); + } - // 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")) { + // cut on invariant mass of Xi-pion pairs + if (hfCandXic.invMassXiPi0() > cuts->get(pTBin, "max inv mass Xi-Pi0") || hfCandXic.invMassXiPi1() > cuts->get(pTBin, "max inv mass Xi-Pi1")) { return false; } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), MaxInvMassXiPiPairs); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), MaxInvMassXiPiPairs); + } + } else { + registry.fill(HIST("hSelCandidates"), MaxInvMassXiPiPairs); + } + + // Successful kinematic and topological selection + SETBIT(statusXicToXiPiPi, hf_sel_candidate_xic::XicToXiPiPiSelectionStep::RecoKinTopol); // RecoKinTopol = 1 --> statusXicToXiPiPi += 2 + + //////////////////////////////////////////////// + // Track quality selection // + //////////////////////////////////////////////// + if (doTrackQualitySelection) { + // TPC track quality selection on Xi daughters (bachelor pion and V0 daughters) + if (!isSelectedTrackTpcQuality(trackPiFromXi, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax) || + !isSelectedTrackTpcQuality(trackV0PosDau, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax) || + !isSelectedTrackTpcQuality(trackV0NegDau, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + return false; + } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), TpcTrackQualityXiDaughters); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), TpcTrackQualityXiDaughters); + } + } else { + registry.fill(HIST("hSelCandidates"), TpcTrackQualityXiDaughters); + } + + // TPC track quality selection on pions from charm baryon + if (!isSelectedTrackTpcQuality(trackPi0, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax) || + !isSelectedTrackTpcQuality(trackPi1, nClustersTpcMin, nTpcCrossedRowsMin, tpcCrossedRowsOverFindableClustersRatioMin, tpcChi2PerClusterMax)) { + return false; + } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), TpcTrackQualityPiFromCharm); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), TpcTrackQualityPiFromCharm); + } + } else { + registry.fill(HIST("hSelCandidates"), TpcTrackQualityPiFromCharm); + } + + // ITS track quality selection on pions from charm baryon + if ((!isSelectedTrackItsQuality(trackPi0, nClustersItsMin, itsChi2PerClusterMax) || trackPi0.itsNClsInnerBarrel() < nClustersItsInnBarrMin) || + (!isSelectedTrackItsQuality(trackPi0, nClustersItsMin, itsChi2PerClusterMax) || trackPi1.itsNClsInnerBarrel() < nClustersItsInnBarrMin)) { + return false; + } + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), ItsTrackQualityPiFromCharm); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), ItsTrackQualityPiFromCharm); + } + } else { + registry.fill(HIST("hSelCandidates"), ItsTrackQualityPiFromCharm); + } + + // Successful track quality selection + SETBIT(statusXicToXiPiPi, hf_sel_candidate_xic::XicToXiPiPiSelectionStep::RecoTrackQuality); // RecoTrackQuality = 2 --> statusXicToXiPiPi += 4 + } else { + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), TpcTrackQualityXiDaughters); + registry.fill(HIST("hSelCandidatesRecSig"), TpcTrackQualityPiFromCharm); + registry.fill(HIST("hSelCandidatesRecSig"), ItsTrackQualityPiFromCharm); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), TpcTrackQualityXiDaughters); + registry.fill(HIST("hSelCandidatesRecBkg"), TpcTrackQualityPiFromCharm); + registry.fill(HIST("hSelCandidatesRecBkg"), ItsTrackQualityPiFromCharm); + } + } else { + registry.fill(HIST("hSelCandidates"), TpcTrackQualityXiDaughters); + registry.fill(HIST("hSelCandidates"), TpcTrackQualityPiFromCharm); + registry.fill(HIST("hSelCandidates"), ItsTrackQualityPiFromCharm); + } + } + + //////////////////////////////////////////////// + // PID selection // + //////////////////////////////////////////////// + if (usePid) { + TrackSelectorPID::Status statusPidPi0; + TrackSelectorPID::Status statusPidPi1; + TrackSelectorPID::Status statusPidPiXi; + TrackSelectorPID::Status statusPidPrLam; + TrackSelectorPID::Status statusPidPiLam; + + // assign proton and pion hypothesis to V0 daughters + auto trackPr = trackV0PosDau; + auto trackPiFromLam = trackV0NegDau; + if (hfCandXic.sign() < 0) { + trackPr = trackV0NegDau; + trackPiFromLam = trackV0PosDau; + } + + if (useTpcPidOnly) { + statusPidPi0 = selectorPion.statusTpc(trackPi0); + statusPidPi1 = selectorPion.statusTpc(trackPi1); + statusPidPiXi = selectorPion.statusTpc(trackPiFromXi); + statusPidPrLam = selectorProton.statusTpc(trackPr); + statusPidPiLam = selectorPion.statusTpc(trackPiFromLam); + } else { + statusPidPi0 = selectorPion.statusTpcOrTof(trackPi0); + statusPidPi1 = selectorPion.statusTpcOrTof(trackPi1); + statusPidPiXi = selectorPion.statusTpcOrTof(trackPiFromXi); + statusPidPrLam = selectorProton.statusTpcOrTof(trackPr); + statusPidPiLam = selectorPion.statusTpcOrTof(trackPiFromLam); + } + + if (!isSelectedPid(statusPidPi0, statusPidPi1, statusPidPiXi, statusPidPrLam, statusPidPiLam, useTpcPidOnly.value)) { + return false; + } + + // Successful PID selection + SETBIT(statusXicToXiPiPi, hf_sel_candidate_xic::XicToXiPiPiSelectionStep::RecoPID); // RecoPID = 3 --> statusXicToXiPiPi += 8 + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), PidSelected); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), PidSelected); + } + } else { + registry.fill(HIST("hSelCandidates"), PidSelected); + } + } else { + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), PidSelected); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), PidSelected); + } + } else { + registry.fill(HIST("hSelCandidates"), PidSelected); + } + } 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) + /// Apply BDT selection + /// \param hfCandXic Xic candidate + /// \param statusXicToXiPiPi Flag to store selection status as defined in hf_sel_candidate_xic::XicToXiPiPiSelectionStep + /// \param isMatchedSignal Flag to indicate if the candidate is matched to a genereated XiCplus MC particle + template + void isBdtSelected(XicCandidate const& hfCandXic, + int& statusXicToXiPiPi, + bool const isMatchedSignal = false) { - if (!acceptPIDNotApplicable && (pidTrackPi0 != TrackSelectorPID::Accepted || pidTrackPi1 != TrackSelectorPID::Accepted || pidTrackPr != TrackSelectorPID::Accepted || pidTrackPiLam != TrackSelectorPID::Accepted || pidTrackPiXi != TrackSelectorPID::Accepted)) { - return false; + bool isSelectedMlXicToXiPiPi = false; + float const ptCandXic = hfCandXic.pt(); + + std::vector inputFeaturesXicToXiPiPi = hfMlResponse.getInputFeatures(hfCandXic); + isSelectedMlXicToXiPiPi = hfMlResponse.isSelectedMl(inputFeaturesXicToXiPiPi, ptCandXic, outputMlXicToXiPiPi); + + hfMlXicToXiPiPiCandidate(outputMlXicToXiPiPi); + + if (!isSelectedMlXicToXiPiPi) { + return; } - if (acceptPIDNotApplicable && (pidTrackPi0 == TrackSelectorPID::Rejected || pidTrackPi1 == TrackSelectorPID::Rejected || pidTrackPr == TrackSelectorPID::Rejected || pidTrackPiLam == TrackSelectorPID::Rejected || pidTrackPiXi == TrackSelectorPID::Rejected)) { - return false; + + // Successful ML selection + SETBIT(statusXicToXiPiPi, hf_sel_candidate_xic::XicToXiPiPiSelectionStep::RecoMl); // RecoML = 4 --> statusXicToXiPiPi += 16 + if constexpr (IsMc) { + if (isMatchedSignal) { + registry.fill(HIST("hSelCandidatesRecSig"), BdtSelected); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), BdtSelected); + } + } else { + registry.fill(HIST("hSelCandidates"), BdtSelected); } - return true; } - void process(aod::HfCandXic const& hfCandsXic, - TracksPidWithSel const&) + void processData(aod::HfCandXic const& hfCandsXic, + TracksExtraWPid const& tracks) { for (const auto& hfCandXic : hfCandsXic) { int statusXicToXiPiPi = 0; - auto ptCandXic = hfCandXic.pt(); + if (applyMl) { + outputMlXicToXiPiPi.clear(); + } + + // Kinematic, topological, track quality and PID selections + if (!isSelectedXicToXiPiPiCandidateWoMl(hfCandXic, tracks, statusXicToXiPiPi)) { + hfSelXicToXiPiPiCandidate(statusXicToXiPiPi); + if (applyMl) { + hfMlXicToXiPiPiCandidate(outputMlXicToXiPiPi); + } + continue; + } - if (activateQA) { - registry.fill(HIST("hSelections"), 1, ptCandXic); + // ML selection + if (applyMl) { + isBdtSelected(hfCandXic, statusXicToXiPiPi); + } else { + registry.fill(HIST("hSelCandidates"), BdtSelected); } - // No hfFlag -> by default skim selected - SETBIT(statusXicToXiPiPi, SelectionStep::RecoSkims); // RecoSkims = 0 --> statusXicToXiPiPi = 1 - if (activateQA) { - registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoSkims, ptCandXic); + hfSelXicToXiPiPiCandidate(statusXicToXiPiPi); + } + } + PROCESS_SWITCH(HfCandidateSelectorXicToXiPiPi, processData, "Select candidates without MC matching information", true); + + void processMc(soa::Join const& hfCandsXic, + TracksExtraWPid const& tracks) + { + for (const auto& hfCandXic : hfCandsXic) { + int statusXicToXiPiPi = 0; + if (applyMl) { + outputMlXicToXiPiPi.clear(); } - // topological cuts - if (!selectionTopol(hfCandXic)) { + bool isMatchedCandidate = false; + if (hfCandXic.flagMcMatchRec() != int8_t(0)) { + isMatchedCandidate = true; + } + + // Kinematic, topological, track quality and PID selections + if (!isSelectedXicToXiPiPiCandidateWoMl(hfCandXic, tracks, statusXicToXiPiPi, isMatchedCandidate)) { 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); - continue; - } - SETBIT(statusXicToXiPiPi, SelectionStep::RecoPID); // RecoPID = 2 --> statusXicToXiPiPi = 7 - if (activateQA) { - registry.fill(HIST("hSelections"), 2 + SelectionStep::RecoPID, ptCandXic); - } + + // ML selection + if (applyMl) { + isBdtSelected(hfCandXic, statusXicToXiPiPi, isMatchedCandidate); + } else if (isMatchedCandidate) { + registry.fill(HIST("hSelCandidatesRecSig"), BdtSelected); + } else { + registry.fill(HIST("hSelCandidatesRecBkg"), BdtSelected); } hfSelXicToXiPiPiCandidate(statusXicToXiPiPi); } } + PROCESS_SWITCH(HfCandidateSelectorXicToXiPiPi, processMc, "Select candidates with MC matching information", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/candidateSelectorXiccToPKPiPi.cxx b/PWGHF/TableProducer/candidateSelectorXiccToPKPiPi.cxx index ce9a5f3375f..12a5bc3477f 100644 --- a/PWGHF/TableProducer/candidateSelectorXiccToPKPiPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorXiccToPKPiPi.cxx @@ -14,16 +14,27 @@ /// /// \author Gian Michele Innocenti , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -#include "Common/Core/TrackSelectorPID.h" - +#include "PWGHF/ALICE3/Core/DecayChannelsLegacy.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/TrackSelectorPID.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + using namespace o2; using namespace o2::analysis; using namespace o2::framework; @@ -47,9 +58,8 @@ 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; using TracksSel = soa::Join; @@ -71,7 +81,7 @@ struct HfCandidateSelectorXiccToPKPiPi { bool selectionTopol(const T1& hfCandXicc, const T2& hfCandXic, const T3& trackPi) { auto candpT = hfCandXicc.pt(); - int pTBin = findBin(binsPt, candpT); + int const pTBin = findBin(binsPt, candpT); if (pTBin == -1) { return false; } @@ -82,7 +92,7 @@ struct HfCandidateSelectorXiccToPKPiPi { } // check candidate mass is within a defined mass window - if (std::abs(hfHelper.invMassXiccToXicPi(hfCandXicc) - o2::constants::physics::MassXiCCPlusPlus) > cuts->get(pTBin, "m")) { + if (std::abs(HfHelper::invMassXiccToXicPi(hfCandXicc) - o2::constants::physics::MassXiCCPlusPlus) > cuts->get(pTBin, "m")) { return false; } @@ -152,7 +162,7 @@ struct HfCandidateSelectorXiccToPKPiPi { // final selection flag: 0 - rejected, 1 - accepted auto statusXiccToPKPiPi = 0; - if (!(hfCandXicc.hfflag() & 1 << aod::hf_cand_xicc::DecayType::XiccToXicPi)) { + if ((hfCandXicc.hfflag() & 1 << aod::hf_cand_xicc::DecayType::XiccToXicPi) == 0) { hfSelXiccToPKPiPiCandidate(statusXiccToPKPiPi); continue; } @@ -170,7 +180,7 @@ struct HfCandidateSelectorXiccToPKPiPi { pidPi = 1; } else { // track-level PID selection - int pidPion = selectorPion.statusTpcOrTof(trackPi); + int const pidPion = selectorPion.statusTpcOrTof(trackPi); if (pidPion == TrackSelectorPID::Accepted) { pidPi = 1; } diff --git a/PWGHF/TableProducer/converterDstarIndices.cxx b/PWGHF/TableProducer/converterDstarIndices.cxx new file mode 100644 index 00000000000..18d7fffe6c1 --- /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 "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include +#include +#include + +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/derivedDataCreatorB0ToDPi.cxx b/PWGHF/TableProducer/derivedDataCreatorB0ToDPi.cxx new file mode 100644 index 00000000000..5378586cff8 --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorB0ToDPi.cxx @@ -0,0 +1,444 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file derivedDataCreatorB0ToDPi.cxx +/// \brief Producer of derived tables of B+ candidates, collisions and MC particles +/// \note Based on derivedDataCreatorBplusToD0Pi.cxx +/// +/// \author Vít Kučera , Inha University + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#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; +using namespace o2::aod::pid_tpc_tof_utils; +using namespace o2::analysis::hf_derived; +using namespace o2::hf_decay::hf_cand_beauty; + +/// Writes the full information in an output TTree +struct HfDerivedDataCreatorB0ToDPi { + HfProducesDerivedData< + o2::aod::HfB0Bases, + o2::aod::HfB0CollBases, + o2::aod::HfB0CollIds, + o2::aod::HfB0McCollBases, + o2::aod::HfB0McCollIds, + o2::aod::HfB0McRCollIds, + o2::aod::HfB0PBases, + o2::aod::HfB0PIds> + rowsCommon; + // Candidates + Produces rowCandidatePar; + Produces rowCandidateParDplus; + Produces rowCandidateParE; + Produces rowCandidateSel; + Produces rowCandidateMl; + Produces rowCandidateMlDplus; + Produces rowCandidateId; + Produces rowCandidateMc; + + // Switches for filling tables + HfConfigurableDerivedData confDerData; + Configurable fillCandidatePar{"fillCandidatePar", true, "Fill candidate parameters"}; + Configurable fillCandidateParDplus{"fillCandidateParDplus", true, "Fill D+ 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 fillCandidateMlDplus{"fillCandidateMlDplus", true, "Fill D+ 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"}; + + SliceCache cache; + static constexpr double Mass{o2::constants::physics::MassB0}; + + 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_b0::isSelB0ToDPi & static_cast(BIT(aod::SelectionStep::RecoMl - 1))) != 0; + Filter filterMcGenMatching = nabs(aod::hf_cand_b0::flagMcMatchGen) == static_cast(DecayChannelMain::B0ToDminusPi); + + 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_b0::isSelB0ToDPi >= 0; + Partition candidatesMcAll = aod::hf_sel_candidate_b0::isSelB0ToDPi >= 0; + Partition candidatesMlAll = aod::hf_sel_candidate_b0::isSelB0ToDPi >= 0; + Partition candidatesMcMlAll = aod::hf_sel_candidate_b0::isSelB0ToDPi >= 0; + // partitions for signal and background + Partition candidatesMcSig = nabs(aod::hf_cand_b0::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); + Partition candidatesMcBkg = nabs(aod::hf_cand_b0::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_b0::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_b0::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); + + 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 (fillCandidateParDplus) { + rowCandidateParDplus( + prongCharm.chi2PCA(), + prongCharm.nProngsContributorsPV(), + prongCharm.cpa(), + prongCharm.cpaXY(), + prongCharm.decayLength(), + prongCharm.decayLengthXY(), + prongCharm.decayLengthNormalised(), + prongCharm.decayLengthXYNormalised(), + prongCharm.ptProng0(), + prongCharm.ptProng1(), + prongCharm.ptProng2(), + prongCharm.impactParameter0(), + prongCharm.impactParameter1(), + prongCharm.impactParameter2(), + prongCharm.impactParameterNormalised0(), + prongCharm.impactParameterNormalised1(), + prongCharm.impactParameterNormalised2(), + prongCharm.nSigTpcPi0(), + prongCharm.nSigTofPi0(), + prongCharm.tpcTofNSigmaPi0(), + prongCharm.nSigTpcKa1(), + prongCharm.nSigTofKa1(), + prongCharm.tpcTofNSigmaKa1(), + prongCharm.nSigTpcPi2(), + prongCharm.nSigTofPi2(), + prongCharm.tpcTofNSigmaPi2()); + } + 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::cosThetaStarB0(candidate), + ct); + } + if (fillCandidateSel) { + rowCandidateSel( + BIT(candFlag)); + } + if (fillCandidateMl) { + rowCandidateMl( + mlScore); + } + if (fillCandidateMlDplus) { + rowCandidateMlDplus( + mlScoresCharm); + } + if (fillCandidateId) { + rowCandidateId( + candidate.collisionId(), + prongCharm.prong0Id(), + prongCharm.prong1Id(), + prongCharm.prong2Id(), + 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(rowCandidateParDplus, fillCandidateParDplus, sizeTableCand); + reserveTable(rowCandidateParE, fillCandidateParE, sizeTableCand); + reserveTable(rowCandidateSel, fillCandidateSel, sizeTableCand); + reserveTable(rowCandidateMl, fillCandidateMl, sizeTableCand); + reserveTable(rowCandidateMlDplus, fillCandidateMlDplus, 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.isSelB0ToDPi(), aod::SelectionStep::RecoMl)) { + continue; + } + } + if constexpr (IsMc) { + flagMcRec = candidate.flagMcMatchRec(); + origin = candidate.originMcRec(); + if constexpr (OnlyBkg) { + if (std::abs(flagMcRec) == DecayChannelMain::B0ToDminusPi) { + continue; + } + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (OnlySig) { + if (std::abs(flagMcRec) != DecayChannelMain::B0ToDminusPi) { + continue; + } + } + } + auto prongCharm = candidate.template prong0_as(); + auto prongBachelor = candidate.template prong1_as(); + double const ct = HfHelper::ctB0(candidate); + double const y = HfHelper::yB0(candidate); + float const massB0ToDPi = HfHelper::invMassB0ToDPi(candidate); + float mlScoreB0ToDPi{-1.f}; + std::vector mlScoresDplus; + std::copy(prongCharm.mlProbDplusToPiKPi().begin(), prongCharm.mlProbDplusToPiKPi().end(), std::back_inserter(mlScoresDplus)); + if constexpr (IsMl) { + mlScoreB0ToDPi = candidate.mlProbB0ToDPi(); + } + fillTablesCandidate(candidate, prongCharm, prongBachelor, 0, massB0ToDPi, ct, y, flagMcRec, origin, mlScoreB0ToDPi, mlScoresDplus); + } + } + } + + 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(HfDerivedDataCreatorB0ToDPi, 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(HfDerivedDataCreatorB0ToDPi, 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(HfDerivedDataCreatorB0ToDPi, 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(HfDerivedDataCreatorB0ToDPi, 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(HfDerivedDataCreatorB0ToDPi, 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(HfDerivedDataCreatorB0ToDPi, 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(HfDerivedDataCreatorB0ToDPi, 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(HfDerivedDataCreatorB0ToDPi, processMcMlAll, "Process MC with ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorB0ToDPi, processMcGenOnly, "Process MC gen. only", false); +}; + +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..05c34f4c85b --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorBplusToD0Pi.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. + +/// \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 "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.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" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#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; +using namespace o2::aod::pid_tpc_tof_utils; +using namespace o2::analysis::hf_derived; +using namespace o2::hf_decay::hf_cand_beauty; + +/// 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"}; + + 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(DecayChannelMain::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(DecayChannelMain::BplusToD0Pi); + Partition candidatesMcBkg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != static_cast(DecayChannelMain::BplusToD0Pi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_bplus::flagMcMatchRec) == static_cast(DecayChannelMain::BplusToD0Pi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != static_cast(DecayChannelMain::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 (std::abs(flagMcRec) == DecayChannelMain::BplusToD0Pi) { + continue; + } + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (OnlySig) { + if (std::abs(flagMcRec) != DecayChannelMain::BplusToD0Pi) { + continue; + } + } + } + auto prongCharm = candidate.template prong0_as(); + auto prongBachelor = candidate.template prong1_as(); + double const ct = HfHelper::ctBplus(candidate); + double const y = HfHelper::yBplus(candidate); + float const massBplusToD0Pi = HfHelper::invMassBplusToD0Pi(candidate); + float mlScoreBplusToD0Pi{-1.f}; + std::vector mlScoresD0; + bool const 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 694d773cf4f..6e9a18014a5 100644 --- a/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorD0ToKPi.cxx @@ -15,84 +15,97 @@ /// /// \author Vít Kučera , Inha University -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/DecayChannels.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" +#include "PWGLF/DataModel/mcCentrality.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/DataModel/DerivedTables.h" +#include +#include +#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; +using namespace o2::aod::pid_tpc_tof_utils; +using namespace o2::analysis::hf_derived; /// Writes the full information in an output TTree struct HfDerivedDataCreatorD0ToKPi { + 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 rowCandidateBase; Produces rowCandidatePar; Produces rowCandidateParE; Produces rowCandidateSel; Produces rowCandidateMl; Produces rowCandidateId; Produces rowCandidateMc; - // Collisions - Produces rowCollBase; - Produces rowCollId; - // MC collisions - Produces rowMcCollBase; - Produces rowMcCollId; - Produces rowMcRCollId; - // MC particles - 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 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 original collision indices"}; - Configurable fillMcCollBase{"fillMcCollBase", true, "Fill MC collision base properties"}; - Configurable fillMcCollId{"fillMcCollId", true, "Fill original MC collision indices"}; - Configurable fillMcRCollId{"fillMcRCollId", true, "Fill indices of saved derived reconstructed collisions matched to saved derived MC collisions"}; - Configurable fillParticleBase{"fillParticleBase", true, "Fill MC particle properties"}; - Configurable fillParticleId{"fillParticleId", true, "Fill original MC 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; - 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 + static constexpr double Mass{o2::constants::physics::MassD0}; using CollisionsWCentMult = soa::Join; 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 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 = aod::McCollisions; + 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)); + Filter filterMcGenMatching = nabs(aod::hf_cand_2prong::flagMcMatchGen) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesKfPerCollision = aod::hf_cand::collisionId; @@ -114,97 +127,43 @@ struct HfDerivedDataCreatorD0ToKPi { Partition candidatesMcMlAll = aod::hf_sel_candidate_d0::isSelD0 >= 0; Partition candidatesMcKfMlAll = aod::hf_sel_candidate_d0::isSelD0 >= 0; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - Partition candidatesMcBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - Partition candidatesMcKfSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - Partition candidatesMcKfBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - Partition candidatesMcMlSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - Partition candidatesMcKfMlSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - Partition candidatesMcKfMlBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); + Partition candidatesMcSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcKfSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcKfBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcMlSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcKfMlSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition candidatesMcKfMlBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); 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) - 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()); - } - if constexpr (isMC) { - if (fillMcRCollId && 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 (fillMcCollBase) { - rowMcCollBase( - mcCollision.posX(), - mcCollision.posY(), - mcCollision.posZ()); - } - if (fillMcCollId) { - rowMcCollId( - mcCollision.globalIndex()); - } - if (fillMcRCollId) { - // Fill the table with the vector of indices of derived reconstructed collisions matched to mcCollision.globalIndex() - rowMcRCollId( - matchedCollisions[mcCollision.globalIndex()]); - } - } - - template - void fillTablesCandidate(const T& candidate, const U& prong0, const U& prong1, int candFlag, double invMass, double cosThetaStar, double topoChi2, + 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, - y); - } + 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(), @@ -219,18 +178,18 @@ 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()); } @@ -277,41 +236,20 @@ struct HfDerivedDataCreatorD0ToKPi { } } - template - void fillTablesParticle(const T& particle, U mass) - { - if (fillParticleBase) { - rowParticleBase( - rowMcCollBase.lastIndex(), - particle.pt(), - particle.eta(), - particle.phi(), - RecoDecayPtEtaPhi::y(particle.pt(), particle.eta(), mass), - particle.flagMcMatchGen(), - particle.originMcGen()); - } - if (fillParticleId) { - rowParticleId( - particle.mcCollisionId(), - particle.globalIndex()); - } - } - - template + template void processCandidates(CollType const& collisions, Partition& candidates, - TracksWPid const&, + aod::Tracks const&, aod::BCs const&) { // Fill collision properties - if constexpr (isMc) { - if (fillMcRCollId) { - matchedCollisions.clear(); + 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 @@ -319,129 +257,87 @@ struct HfDerivedDataCreatorD0ToKPi { 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 = fillMcRCollId && collision.has_mcCollision() && hasMcParticles[collision.mcCollisionId()]; + 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 && (!fillMcRCollId || !mcCollisionHasMcParticles)) { + 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, rowCollBase.lastIndex() + 1); - // 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) { + if constexpr (IsMc) { reserveTable(rowCandidateMc, fillCandidateMc, sizeTableCand); } int8_t flagMcRec = 0, origin = 0; for (const auto& candidate : candidatesThisColl) { - if constexpr (isMc) { + if constexpr (IsMc) { flagMcRec = candidate.flagMcMatchRec(); origin = candidate.originMcRec(); - if constexpr (onlyBkg) { - if (TESTBIT(std::abs(flagMcRec), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if constexpr (OnlyBkg) { + if (std::abs(flagMcRec) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { continue; } if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const 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_2prong::DecayType::D0ToPiK)) { + if constexpr (OnlySig) { + if (std::abs(flagMcRec) != o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + continue; + } + } + } else { + if (downSampleBkgFactor < 1.) { + float const 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 ct = hfHelper.ctD0(candidate); - double y = hfHelper.yD0(candidate); + + double const ct = HfHelper::ctD0(candidate); + double const y = HfHelper::yD0(candidate); float massD0, massD0bar; float topolChi2PerNdf = -999.; - if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { massD0 = candidate.kfGeoMassD0(); massD0bar = candidate.kfGeoMassD0bar(); topolChi2PerNdf = candidate.kfTopolChi2OverNdf(); } else { - massD0 = hfHelper.invMassD0ToPiK(candidate); - massD0bar = hfHelper.invMassD0barToKPi(candidate); + massD0 = HfHelper::invMassD0ToPiK(candidate); + massD0bar = HfHelper::invMassD0barToKPi(candidate); } std::vector mlScoresD0, mlScoresD0bar; - if constexpr (isMl) { + if constexpr (IsMl) { std::copy(candidate.mlProbD0().begin(), candidate.mlProbD0().end(), std::back_inserter(mlScoresD0)); 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, ct, y, 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, ct, y, flagMcRec, origin, mlScoresD0bar); + fillTablesCandidate(candidate, 1, massD0bar, HfHelper::cosThetaStarD0bar(candidate), topolChi2PerNdf, ct, y, flagMcRec, origin, mlScoresD0bar); } } } } - template - void preProcessMcCollisions(CollisionType const& mcCollisions, - ParticleType const& mcParticles) - { - if (!fillMcRCollId) { - 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, - ParticleType const& mcParticles) - { - // Fill MC collision properties - auto sizeTableMcColl = mcCollisions.size(); - reserveTable(rowMcCollBase, fillMcCollBase, sizeTableMcColl); - reserveTable(rowMcRCollId, fillMcRCollId, 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 && (!fillMcRCollId || 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 - reserveTable(rowParticleBase, fillParticleBase, sizeTablePart); - reserveTable(rowParticleId, fillParticleId, sizeTablePart); - for (const auto& particle : particlesThisMcColl) { - 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); @@ -450,7 +346,7 @@ 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); @@ -461,12 +357,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMc const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcSig, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterSig, "Process MC with DCAFitterN only for signals", false); @@ -474,12 +370,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMc const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcBkg, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterBkg, "Process MC with DCAFitterN only for background", false); @@ -487,12 +383,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMc const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcAll, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterAll, "Process MC with DCAFitterN", false); @@ -500,12 +396,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcKf const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfSig, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleSig, "Process MC with KFParticle only for signals", false); @@ -513,12 +409,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcKf const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfBkg, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleBkg, "Process MC with KFParticle only for background", false); @@ -526,12 +422,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcKf const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfAll, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleAll, "Process MC with KFParticle", false); @@ -539,7 +435,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); @@ -548,7 +444,7 @@ 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); @@ -559,12 +455,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcMl const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlSig, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterMlSig, "Process MC with DCAFitterN and ML only for signals", false); @@ -572,12 +468,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcMl const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlBkg, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterMlBkg, "Process MC with DCAFitterN and ML only for background", false); @@ -585,12 +481,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcMl const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlAll, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithDCAFitterMlAll, "Process MC with DCAFitterN and ML", false); @@ -598,12 +494,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcKfMl const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfMlSig, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleMlSig, "Process MC with KFParticle and ML only for signals", false); @@ -611,12 +507,12 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcKfMl const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfMlBkg, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorD0ToKPi, processMcWithKFParticleMlBkg, "Process MC with KFParticle and ML only for background", false); @@ -624,14 +520,21 @@ struct HfDerivedDataCreatorD0ToKPi { SelectedCandidatesMcKfMl const&, TypeMcCollisions const& mcCollisions, MatchedGenCandidatesMc const& mcParticles, - TracksWPid const& tracks, + aod::Tracks const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcKfMlAll, tracks, bcs); - processMcParticles(mcCollisions, 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..ce15964cade --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorDplusToPiKPi.cxx @@ -0,0 +1,408 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#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; +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"}; + + 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(hf_decay::hf_cand_3prong::DecayChannelMain::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(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition candidatesMcBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::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, 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(), + candidate.nSigTpcPi0(), + candidate.nSigTofPi0(), + candidate.tpcTofNSigmaPi0(), + candidate.nSigTpcKa1(), + candidate.nSigTofKa1(), + candidate.tpcTofNSigmaKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTofPi2(), + candidate.tpcTofNSigmaPi2()); + } + 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 (std::abs(flagMcRec) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { + continue; + } + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (OnlySig) { + if (std::abs(flagMcRec) != hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { + continue; + } + } + } + double const ct = HfHelper::ctDplus(candidate); + double const y = HfHelper::yDplus(candidate); + float const massDplusToPiKPi = HfHelper::invMassDplusToPiKPi(candidate); + std::vector mlScoresDplusToPiKPi; + if constexpr (IsMl) { + std::copy(candidate.mlProbDplusToPiKPi().begin(), candidate.mlProbDplusToPiKPi().end(), std::back_inserter(mlScoresDplusToPiKPi)); + } + auto trackprong0 = candidate.template prong0_as(); + int const candFlag = (trackprong0.sign() > 0) ? 0 : 1; // 0: D+, 1: D- + fillTablesCandidate(candidate, candFlag, 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/derivedDataCreatorDsToKKPi.cxx b/PWGHF/TableProducer/derivedDataCreatorDsToKKPi.cxx new file mode 100644 index 00000000000..0a5f217e19e --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorDsToKKPi.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. + +/// \file derivedDataCreatorDsToKKPi.cxx +/// \brief Producer of derived tables of Ds candidates, collisions and MC particles +/// \note Based on derivedDataCreatorDplusToPiKPi.cxx +/// +/// \author Vít Kučera , Inha University + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#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; +using namespace o2::analysis::hf_derived; + +/// Writes the full information in an output TTree +struct HfDerivedDataCreatorDsToKKPi { + HfProducesDerivedData< + o2::aod::HfDsBases, + o2::aod::HfDsCollBases, + o2::aod::HfDsCollIds, + o2::aod::HfDsMcCollBases, + o2::aod::HfDsMcCollIds, + o2::aod::HfDsMcRCollIds, + o2::aod::HfDsPBases, + o2::aod::HfDsPIds> + 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"}; + + SliceCache cache; + static constexpr double Mass{o2::constants::physics::MassDS}; + + 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_ds::isSelDsToKKPi & 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(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + + 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_ds::isSelDsToKKPi >= 0; + Partition candidatesMcAll = aod::hf_sel_candidate_ds::isSelDsToKKPi >= 0; + Partition candidatesMlAll = aod::hf_sel_candidate_ds::isSelDsToKKPi >= 0; + Partition candidatesMcMlAll = aod::hf_sel_candidate_ds::isSelDsToKKPi >= 0; + // partitions for signal and background + Partition candidatesMcSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + Partition candidatesMcBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + Partition candidatesMcMlSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK); + + 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, 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(), + candidate.nSigTpcPi0(), + candidate.nSigTpcKa0(), + candidate.nSigTofPi0(), + candidate.nSigTofKa0(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaKa0(), + candidate.nSigTpcKa1(), + candidate.nSigTofKa1(), + candidate.tpcTofNSigmaKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTpcKa2(), + candidate.nSigTofPi2(), + candidate.nSigTofKa2(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaKa2()); + } + 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.isSelDsToKKPi(), aod::SelectionStep::RecoMl)) { + continue; + } + } + if constexpr (IsMc) { + flagMcRec = candidate.flagMcMatchRec(); + origin = candidate.originMcRec(); + swapping = candidate.isCandidateSwapped(); + flagDecayChanRec = candidate.flagMcDecayChanRec(); + if constexpr (OnlyBkg) { + if (std::abs(flagMcRec) == hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) { + continue; + } + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (OnlySig) { + if (std::abs(flagMcRec) != hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) { + continue; + } + } + } + double const ct = HfHelper::ctDs(candidate); + double const y = HfHelper::yDs(candidate); + float const massDsToKKPi = HfHelper::invMassDsToKKPi(candidate); + std::vector mlScoresDsToKKPi; + if constexpr (IsMl) { + std::copy(candidate.mlProbDsToKKPi().begin(), candidate.mlProbDsToKKPi().end(), std::back_inserter(mlScoresDsToKKPi)); + } + fillTablesCandidate(candidate, 0, massDsToKKPi, ct, y, flagMcRec, origin, swapping, flagDecayChanRec, mlScoresDsToKKPi); + } + } + } + + void processData(CollisionsWCentMult const& collisions, + SelectedCandidates const&, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesAll, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorDsToKKPi, 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(HfDerivedDataCreatorDsToKKPi, 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(HfDerivedDataCreatorDsToKKPi, 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(HfDerivedDataCreatorDsToKKPi, 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(HfDerivedDataCreatorDsToKKPi, 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(HfDerivedDataCreatorDsToKKPi, 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(HfDerivedDataCreatorDsToKKPi, 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(HfDerivedDataCreatorDsToKKPi, processMcMlAll, "Process MC with ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDsToKKPi, processMcGenOnly, "Process MC gen. only", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx b/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx new file mode 100644 index 00000000000..1a15c3b1fb3 --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx @@ -0,0 +1,416 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file derivedDataCreatorDstarToD0Pi.cxx +/// \brief Producer of derived tables of D*+ candidates, collisions and MC particles +/// \note Based on derivedDataCreatorLcToPKPi.cxx +/// +/// \author Mingze Li , CCNU + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#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; +using namespace o2::analysis::hf_derived; + +/// Writes the full information in an output TTree +struct HfDerivedDataCreatorDstarToD0Pi { + HfProducesDerivedData< + o2::aod::HfDstarBases, + o2::aod::HfDstarCollBases, + o2::aod::HfDstarCollIds, + o2::aod::HfDstarMcCollBases, + o2::aod::HfDstarMcCollIds, + o2::aod::HfDstarMcRCollIds, + o2::aod::HfDstarPBases, + o2::aod::HfDstarPIds> + rowsCommon; + // Candidates + Produces rowCandidatePar; + Produces rowCandidateParD0; + Produces rowCandidateSel; + Produces rowCandidateMl; + Produces rowCandidateId; + Produces rowCandidateMc; + + // Switches for filling tables + HfConfigurableDerivedData confDerData; + Configurable fillCandidatePar{"fillCandidatePar", true, "Fill candidate parameters"}; + Configurable fillCandidateParD0{"fillCandidateParD0", true, "Fill charm daughter 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"}; + + SliceCache cache; + static constexpr double Mass{o2::constants::physics::MassDStar}; + + 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_dstar::isSelDstarToD0Pi == true; + Filter filterMcGenMatching = nabs(aod::hf_cand_dstar::flagMcMatchGen) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + + 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_dstar::isSelDstarToD0Pi == true; + Partition candidatesMcAll = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == true; + Partition candidatesMlAll = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == true; + Partition candidatesMcMlAll = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == true; + // partitions for signal and background + Partition candidatesMcSig = nabs(aod::hf_cand_dstar::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition candidatesMcBkg = nabs(aod::hf_cand_dstar::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_dstar::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_dstar::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + + 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& prongSoftPi, int candFlag, double invMass, double invMassD0, + double y, int8_t flagMc, int8_t flagMcD0, int8_t origin, int8_t nTracksDecayed, double ptBhad, int pdgBhad, const std::vector& mlScores) + { + rowsCommon.fillTablesCandidate(candidate, invMass, y); + if (fillCandidatePar) { + rowCandidatePar( + candidate.pxD0(), + candidate.pyD0(), + candidate.pzD0(), + candidate.pxSoftPi(), + candidate.pySoftPi(), + candidate.pzSoftPi(), + candidate.signSoftPi(), + candidate.impParamSoftPi(), + candidate.normalisedImpParamSoftPi(), + prongSoftPi.tpcNSigmaPi(), + prongSoftPi.tofNSigmaPi(), + prongSoftPi.tpcTofNSigmaPi()); + } + if (fillCandidateParD0) { + rowCandidateParD0( + candidate.chi2PCAD0(), + candidate.cpaD0(), + candidate.cpaXYD0(), + candidate.decayLengthD0(), + candidate.decayLengthXYD0(), + candidate.decayLengthNormalisedD0(), + candidate.decayLengthXYNormalisedD0(), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + invMassD0, + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameterNormalised0(), + candidate.impactParameterNormalised1(), + prong0.tpcNSigmaPi(), + prong0.tofNSigmaPi(), + prong0.tpcTofNSigmaPi(), + prong0.tpcNSigmaKa(), + prong0.tofNSigmaKa(), + prong0.tpcTofNSigmaKa(), + prong1.tpcNSigmaPi(), + prong1.tofNSigmaPi(), + prong1.tpcTofNSigmaPi(), + prong1.tpcNSigmaKa(), + prong1.tofNSigmaKa(), + prong1.tpcTofNSigmaKa()); + } + if (fillCandidateSel) { + rowCandidateSel( + BIT(candFlag)); + } + if (fillCandidateMl) { + rowCandidateMl( + mlScores); + } + if (fillCandidateId) { + rowCandidateId( + candidate.collisionId(), + candidate.prong0Id(), + candidate.prong1Id(), + candidate.prongPiId()); + } + if (fillCandidateMc) { + rowCandidateMc( + flagMc, + flagMcD0, + origin, + ptBhad, + pdgBhad, + nTracksDecayed); + } + } + + 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(rowCandidateParD0, fillCandidateParD0, sizeTableCand); + reserveTable(rowCandidateSel, fillCandidateSel, sizeTableCand); + reserveTable(rowCandidateMl, fillCandidateMl, sizeTableCand); + reserveTable(rowCandidateId, fillCandidateId, sizeTableCand); + if constexpr (IsMc) { + reserveTable(rowCandidateMc, fillCandidateMc, sizeTableCand); + } + int8_t flagMcRec = 0, flagMcRecD0 = 0, origin = 0, nTracksDecayed = 0; + double ptBhadMotherPart = 0; + int pdgBhadMotherPart = 0; + for (const auto& candidate : candidatesThisColl) { + if constexpr (IsMl) { + if (!TESTBIT(candidate.isSelDstarToD0Pi(), aod::SelectionStep::RecoMl)) { + continue; + } + } + if constexpr (IsMc) { + flagMcRec = candidate.flagMcMatchRec(); + flagMcRecD0 = candidate.flagMcMatchRecD0(); + origin = candidate.originMcRec(); + nTracksDecayed = candidate.nTracksDecayed(); + ptBhadMotherPart = candidate.ptBhadMotherPart(); + pdgBhadMotherPart = candidate.pdgBhadMotherPart(); + if constexpr (OnlyBkg) { + if (std::abs(flagMcRec) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { + continue; + } + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (OnlySig) { + if (std::abs(flagMcRec) != hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { + continue; + } + } + } + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + auto prongSoftPi = candidate.template prongPi_as(); + double const y = candidate.y(o2::constants::physics::MassDStar); + int flagSign = -1; + double massDstar = 0, invMassD0 = 0; + std::vector mlScoresDstarToD0Pi; + if constexpr (IsMl) { + std::copy(candidate.mlProbDstarToD0Pi().begin(), candidate.mlProbDstarToD0Pi().end(), std::back_inserter(mlScoresDstarToD0Pi)); + } + if (candidate.signSoftPi() > 0) { + massDstar = candidate.invMassDstar(); + invMassD0 = candidate.invMassD0(); + flagSign = 0; + } else { + massDstar = candidate.invMassAntiDstar(); + invMassD0 = candidate.invMassD0Bar(); + flagSign = 1; + } + fillTablesCandidate(candidate, prong0, prong1, prongSoftPi, flagSign, massDstar, invMassD0, y, flagMcRec, flagMcRecD0, origin, nTracksDecayed, ptBhadMotherPart, pdgBhadMotherPart, mlScoresDstarToD0Pi); + } + } + } + + void processData(CollisionsWCentMult const& collisions, + SelectedCandidates const&, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesAll, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorDstarToD0Pi, 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(HfDerivedDataCreatorDstarToD0Pi, 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(HfDerivedDataCreatorDstarToD0Pi, 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(HfDerivedDataCreatorDstarToD0Pi, 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(HfDerivedDataCreatorDstarToD0Pi, 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(HfDerivedDataCreatorDstarToD0Pi, 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(HfDerivedDataCreatorDstarToD0Pi, 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(HfDerivedDataCreatorDstarToD0Pi, processMcMlAll, "Process MC with ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorDstarToD0Pi, 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 645deab1c39..b96ac350953 100644 --- a/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorLcToPKPi.cxx @@ -15,80 +15,92 @@ /// /// \author Vít Kučera , Inha University -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGLF/DataModel/mcCentrality.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGHF/DataModel/DerivedTables.h" +#include +#include +#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; +using namespace o2::analysis::hf_derived; /// Writes the full information in an output TTree struct HfDerivedDataCreatorLcToPKPi { + 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 rowCandidateBase; - Produces rowCandidatePar; - Produces rowCandidateParE; - Produces rowCandidateSel; - Produces rowCandidateMl; - Produces rowCandidateId; - Produces rowCandidateMc; - // Collisions - Produces rowCollBase; - Produces rowCollId; - // MC collisions - Produces rowMcCollBase; - Produces rowMcCollId; - Produces rowMcRCollId; - // MC particles - Produces rowParticleBase; - Produces rowParticleId; + 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 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 original collision indices"}; - Configurable fillMcCollBase{"fillMcCollBase", true, "Fill MC collision base properties"}; - Configurable fillMcCollId{"fillMcCollId", true, "Fill original MC collision indices"}; - Configurable fillMcRCollId{"fillMcRCollId", true, "Fill indices of saved derived reconstructed collisions matched to saved derived MC collisions"}; - Configurable fillParticleBase{"fillParticleBase", true, "Fill MC particle properties"}; - Configurable fillParticleId{"fillParticleId", true, "Fill original MC 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; - 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 + 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 SelectedCandidates = soa::Filtered>; + using SelectedCandidatesMc = soa::Filtered>; + using SelectedCandidatesMl = soa::Filtered>; + using SelectedCandidatesMcMl = soa::Filtered>; using MatchedGenCandidatesMc = soa::Filtered>; - using TypeMcCollisions = aod::McCollisions; + 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)); + Filter filterMcGenMatching = nabs(aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); Preslice candidatesPerCollision = aod::hf_cand::collisionId; Preslice candidatesMcPerCollision = aod::hf_cand::collisionId; @@ -102,91 +114,25 @@ struct HfDerivedDataCreatorLcToPKPi { Partition candidatesMlAll = aod::hf_sel_candidate_lc::isSelLcToPKPi >= 0; Partition candidatesMcMlAll = aod::hf_sel_candidate_lc::isSelLcToPKPi >= 0; // partitions for signal and background - Partition candidatesMcSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::LcToPKPi)); - Partition candidatesMcBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::LcToPKPi)); - Partition candidatesMcMlSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::LcToPKPi)); - Partition candidatesMcMlBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::LcToPKPi)); + Partition candidatesMcSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); + Partition candidatesMcBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); + Partition candidatesMcMlSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); + Partition candidatesMcMlBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi); 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."); } + 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) - 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()); - } - if constexpr (isMC) { - if (fillMcRCollId && 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 (fillMcCollBase) { - rowMcCollBase( - mcCollision.posX(), - mcCollision.posY(), - mcCollision.posZ()); - } - if (fillMcCollId) { - rowMcCollId( - mcCollision.globalIndex()); - } - if (fillMcRCollId) { - // Fill the table with the vector of indices of derived reconstructed collisions matched to mcCollision.globalIndex() - rowMcRCollId( - matchedCollisions[mcCollision.globalIndex()]); - } - } - - template - void fillTablesCandidate(const T& candidate, const U& prong0, const U& prong1, const U& prong2, int candFlag, double invMass, + void fillTablesCandidate(const T& candidate, 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, - y); - } + rowsCommon.fillTablesCandidate(candidate, invMass, y); if (fillCandidatePar) { rowCandidatePar( candidate.chi2PCA(), @@ -206,21 +152,21 @@ struct HfDerivedDataCreatorLcToPKPi { candidate.impactParameterNormalised0(), candidate.impactParameterNormalised1(), candidate.impactParameterNormalised2(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaPr(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaPr(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaPr(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaKa(), - prong2.tpcNSigmaPi(), - prong2.tpcNSigmaPr(), - prong2.tofNSigmaPi(), - prong2.tofNSigmaPr(), - prong2.tpcTofNSigmaPi(), - prong2.tpcTofNSigmaPr()); + candidate.nSigTpcPi0(), + candidate.nSigTpcPr0(), + candidate.nSigTofPi0(), + candidate.nSigTofPr0(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaPr0(), + candidate.nSigTpcKa1(), + candidate.nSigTofKa1(), + candidate.tpcTofNSigmaKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTpcPr2(), + candidate.nSigTofPi2(), + candidate.nSigTofPr2(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaPr2()); } if (fillCandidateParE) { rowCandidateParE( @@ -270,41 +216,20 @@ struct HfDerivedDataCreatorLcToPKPi { } } - template - void fillTablesParticle(const T& particle, U mass) - { - if (fillParticleBase) { - rowParticleBase( - rowMcCollBase.lastIndex(), - particle.pt(), - particle.eta(), - particle.phi(), - RecoDecayPtEtaPhi::y(particle.pt(), particle.eta(), mass), - particle.flagMcMatchGen(), - particle.originMcGen()); - } - if (fillParticleId) { - rowParticleId( - particle.mcCollisionId(), - particle.globalIndex()); - } - } - - template + template void processCandidates(CollType const& collisions, Partition& candidates, TracksWPid const&, aod::BCs const&) { // Fill collision properties - if constexpr (isMc) { - if (fillMcRCollId) { - matchedCollisions.clear(); + 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 @@ -312,120 +237,76 @@ struct HfDerivedDataCreatorLcToPKPi { 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 = fillMcRCollId && collision.has_mcCollision() && hasMcParticles[collision.mcCollisionId()]; + 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 && (!fillMcRCollId || !mcCollisionHasMcParticles)) { + 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, rowCollBase.lastIndex() + 1); - // 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) { + if constexpr (IsMc) { reserveTable(rowCandidateMc, fillCandidateMc, sizeTableCand); } int8_t flagMcRec = 0, origin = 0, swapping = 0; for (const auto& candidate : candidatesThisColl) { - if constexpr (isMc) { + if constexpr (IsMc) { flagMcRec = candidate.flagMcMatchRec(); origin = candidate.originMcRec(); swapping = candidate.isCandidateSwapped(); - if constexpr (onlyBkg) { - if (TESTBIT(std::abs(flagMcRec), aod::hf_cand_3prong::DecayType::LcToPKPi)) { + if constexpr (OnlyBkg) { + if (std::abs(flagMcRec) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { continue; } if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const 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::LcToPKPi)) { + if constexpr (OnlySig) { + if (std::abs(flagMcRec) != hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + continue; + } + } + } else { + if (downSampleBkgFactor < 1.) { + float const 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(); - 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); + double const ct = HfHelper::ctLc(candidate); + double const y = HfHelper::yLc(candidate); + float const massLcToPKPi = HfHelper::invMassLcToPKPi(candidate); + float const massLcToPiKP = HfHelper::invMassLcToPiKP(candidate); std::vector mlScoresLcToPKPi, mlScoresLcToPiKP; - if constexpr (isMl) { + if constexpr (IsMl) { std::copy(candidate.mlProbLcToPKPi().begin(), candidate.mlProbLcToPKPi().end(), std::back_inserter(mlScoresLcToPKPi)); std::copy(candidate.mlProbLcToPiKP().begin(), candidate.mlProbLcToPiKP().end(), std::back_inserter(mlScoresLcToPiKP)); } if (candidate.isSelLcToPKPi()) { - fillTablesCandidate(candidate, prong0, prong1, prong2, 0, massLcToPKPi, ct, y, flagMcRec, origin, swapping, mlScoresLcToPKPi); + fillTablesCandidate(candidate, 0, massLcToPKPi, ct, y, flagMcRec, origin, swapping, mlScoresLcToPKPi); } if (candidate.isSelLcToPiKP()) { - fillTablesCandidate(candidate, prong0, prong1, prong2, 1, massLcToPiKP, ct, y, flagMcRec, origin, swapping, mlScoresLcToPiKP); + fillTablesCandidate(candidate, 1, massLcToPiKP, ct, y, flagMcRec, origin, swapping, mlScoresLcToPiKP); } } } } - template - void preProcessMcCollisions(CollisionType const& mcCollisions, - ParticleType const& mcParticles) - { - if (!fillMcRCollId) { - 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, - ParticleType const& mcParticles) - { - // Fill MC collision properties - auto sizeTableMcColl = mcCollisions.size(); - reserveTable(rowMcCollBase, fillMcCollBase, sizeTableMcColl); - reserveTable(rowMcRCollId, fillMcRCollId, 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 && (!fillMcRCollId || 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 - reserveTable(rowParticleBase, fillParticleBase, sizeTablePart); - reserveTable(rowParticleId, fillParticleId, sizeTablePart); - for (const auto& particle : particlesThisMcColl) { - fillTablesParticle(particle, o2::constants::physics::MassLambdaCPlus); - } - } - } - void processData(CollisionsWCentMult const& collisions, SelectedCandidates const&, TracksWPid const& tracks, @@ -442,9 +323,9 @@ struct HfDerivedDataCreatorLcToPKPi { TracksWPid const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcSig, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcSig, "Process MC only for signals", false); @@ -455,9 +336,9 @@ struct HfDerivedDataCreatorLcToPKPi { TracksWPid const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcBkg, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcBkg, "Process MC only for background", false); @@ -468,9 +349,9 @@ struct HfDerivedDataCreatorLcToPKPi { TracksWPid const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcAll, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcAll, "Process MC", false); @@ -492,9 +373,9 @@ struct HfDerivedDataCreatorLcToPKPi { TracksWPid const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlSig, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcMlSig, "Process MC with ML only for signals", false); @@ -505,9 +386,9 @@ struct HfDerivedDataCreatorLcToPKPi { TracksWPid const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlBkg, tracks, bcs); - processMcParticles(mcCollisions, mcParticles); + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); } PROCESS_SWITCH(HfDerivedDataCreatorLcToPKPi, processMcMlBkg, "Process MC with ML only for background", false); @@ -518,11 +399,18 @@ struct HfDerivedDataCreatorLcToPKPi { TracksWPid const& tracks, aod::BCs const& bcs) { - preProcessMcCollisions(mcCollisions, mcParticles); + rowsCommon.preProcessMcCollisions(mcCollisions, mcParticlesPerMcCollision, mcParticles); processCandidates(collisions, candidatesMcMlAll, tracks, bcs); - processMcParticles(mcCollisions, 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/derivedDataCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/derivedDataCreatorXicToXiPiPi.cxx new file mode 100644 index 00000000000..fa52ec0a79f --- /dev/null +++ b/PWGHF/TableProducer/derivedDataCreatorXicToXiPiPi.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 derivedDataCreatorXicToXiPiPi.cxx +/// \brief Producer of derived tables of Ξc± → (Ξ∓ → (Λ → p π∓) π∓) π± π± candidates, collisions and MC particles +/// \note Based on derivedDataCreatorBplusToD0Pi.cxx +/// +/// \author Vít Kučera , Inha University + +#include "PWGHF/Core/DecayChannelsLegacy.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsDerivedData.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#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; +using namespace o2::aod::pid_tpc_tof_utils; +using namespace o2::analysis::hf_derived; +using namespace o2::aod::hf_cand_xic_to_xi_pi_pi; + +/// Writes the full information in an output TTree +struct HfDerivedDataCreatorXicToXiPiPi { + HfProducesDerivedData< + o2::aod::HfXicToXiPiPiBases, + o2::aod::HfXicToXiPiPiCollBases, + o2::aod::HfXicToXiPiPiCollIds, + o2::aod::HfXicToXiPiPiMcCollBases, + o2::aod::HfXicToXiPiPiMcCollIds, + o2::aod::HfXicToXiPiPiMcRCollIds, + o2::aod::HfXicToXiPiPiPBases, + o2::aod::HfXicToXiPiPiPIds> + 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"}; + + SliceCache cache; + static constexpr double Mass{o2::constants::physics::MassXiCPlus}; + + 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 = aod::Cascades; + + Filter filterSelectCandidates = (aod::hf_sel_candidate_xic::isSelXicToXiPiPi & static_cast(BIT(o2::aod::hf_sel_candidate_xic::XicToXiPiPiSelectionStep::RecoMl - 1))) != 0; + Filter filterMcGenMatching = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchGen != 0; + + 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_xic::isSelXicToXiPiPi >= 0; + Partition candidatesMcAll = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= 0; + Partition candidatesMlAll = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= 0; + Partition candidatesMcMlAll = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= 0; + // partitions for signal and background + Partition candidatesMcSig = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec != 0; + Partition candidatesMcBkg = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec == 0; + Partition candidatesMcMlSig = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec != 0; + Partition candidatesMcMlBkg = aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchRec == 0; + + 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, int candFlag, double invMass, + double ct, double y, int8_t flagMc, int8_t origin, const std::vector& mlScores) + { + rowsCommon.fillTablesCandidate(candidate, invMass, y); + if (fillCandidatePar) { + rowCandidatePar( + candidate.sign(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.ptProng2(), + candidate.invMassXi(), + candidate.invMassLambda(), + candidate.invMassXiPi0(), + candidate.invMassXiPi1(), + candidate.chi2PCA(), + ct, + candidate.decayLength(), + candidate.decayLengthNormalised(), + candidate.decayLengthXY(), + candidate.decayLengthXYNormalised(), + candidate.cpa(), + candidate.cpaXY(), + candidate.cpaXi(), + candidate.cpaXYXi(), + candidate.cpaLambda(), + candidate.cpaXYLambda(), + candidate.impactParameter0(), + candidate.impactParameterNormalised0(), + candidate.impactParameter1(), + candidate.impactParameterNormalised1(), + candidate.impactParameter2(), + candidate.impactParameterNormalised2(), + candidate.maxNormalisedDeltaIP()); + } + if (fillCandidateParE) { + rowCandidateParE( + candidate.cpaLambdaToXi(), + candidate.cpaXYLambdaToXi(), + 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()); + } + if (fillCandidateSel) { + rowCandidateSel( + BIT(candFlag)); + } + if (fillCandidateMl) { + rowCandidateMl( + mlScores); + } + if (fillCandidateId) { + rowCandidateId( + candidate.collisionId(), + candidate.pi0Id(), + candidate.pi1Id(), + candidate.bachelorId(), + candidate.posTrackId(), + candidate.negTrackId()); + } + if (fillCandidateMc) { + rowCandidateMc( + flagMc, + origin); + } + } + + 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; + for (const auto& candidate : candidatesThisColl) { + if constexpr (IsMl) { + if (!TESTBIT(candidate.isSelXicToXiPiPi(), o2::aod::hf_sel_candidate_xic::XicToXiPiPiSelectionStep::RecoMl)) { + continue; + } + } + if constexpr (IsMc) { + flagMcRec = candidate.flagMcMatchRec(); + origin = candidate.originMcRec(); + if constexpr (OnlyBkg) { + if (TESTBIT(std::abs(flagMcRec), DecayType::XicToXiPiPi)) { + continue; + } + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } + } + } + if constexpr (OnlySig) { + if (!TESTBIT(std::abs(flagMcRec), DecayType::XicToXiPiPi)) { + continue; + } + } + } + float const massXicToXiPiPi = candidate.invMassXicPlus(); + double const ct = HfHelper::ctXic(candidate); + double const y = HfHelper::yXic(candidate); + std::vector mlScoresXicToXiPiPi; + if constexpr (IsMl) { + std::copy(candidate.mlProbXicToXiPiPi().begin(), candidate.mlProbXicToXiPiPi().end(), std::back_inserter(mlScoresXicToXiPiPi)); + } + // FIXME: Remove candFlag? + fillTablesCandidate(candidate, 1, massXicToXiPiPi, ct, y, flagMcRec, origin, mlScoresXicToXiPiPi); + } + } + } + + void processData(CollisionsWCentMult const& collisions, + SelectedCandidates const&, + TracksWPid const& tracks, + aod::BCs const& bcs) + { + processCandidates(collisions, candidatesAll, tracks, bcs); + } + PROCESS_SWITCH(HfDerivedDataCreatorXicToXiPiPi, 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(HfDerivedDataCreatorXicToXiPiPi, 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(HfDerivedDataCreatorXicToXiPiPi, 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(HfDerivedDataCreatorXicToXiPiPi, 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(HfDerivedDataCreatorXicToXiPiPi, 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(HfDerivedDataCreatorXicToXiPiPi, 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(HfDerivedDataCreatorXicToXiPiPi, 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(HfDerivedDataCreatorXicToXiPiPi, processMcMlAll, "Process MC with ML", false); + + void processMcGenOnly(TypeMcCollisions const& mcCollisions, + MatchedGenCandidatesMc const& mcParticles) + { + rowsCommon.processMcParticles(mcCollisions, mcParticlesPerMcCollision, mcParticles, Mass); + } + PROCESS_SWITCH(HfDerivedDataCreatorXicToXiPiPi, processMcGenOnly, "Process MC gen. only", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/mcPidTof.cxx b/PWGHF/TableProducer/mcPidTof.cxx new file mode 100644 index 00000000000..382cf870897 --- /dev/null +++ b/PWGHF/TableProducer/mcPidTof.cxx @@ -0,0 +1,1128 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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, de, 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 "Common/Core/CollisionTypeHelper.h" +#include "Common/Core/MetadataHelper.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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::pid; +using namespace o2::framework::expressions; +using namespace o2::track; + +o2::common::core::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{0}; + 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{false}; + bool mEnableTimeDependentResponse{false}; + int mCollisionSystem{-1}; + bool mAutoSetProcessFunctions{false}; +}; + +// Part 1 TOF signal definition + +/// Selection criteria for tracks used for TOF event time +bool isTrackGoodMatchForTOFPID(const Trks::iterator& tr) +{ + return tr.hasTOF(); +} + +/// 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) { + 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) && !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) && !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; +static constexpr int IdxDe = 5; + +/// Task to produce the response table +struct McPidTof { + // Tables to produce + Produces tablePIDPi; + Produces tablePIDKa; + Produces tablePIDPr; + Produces tablePIDDe; + + // Tables to produce (full) + Produces tablePIDFullPi; + Produces tablePIDFullKa; + Produces tablePIDFullPr; + Produces tablePIDFullDe; + + // 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; + + // list of productions for which the postcalibrations is needed (bug in FT0 digitisation) + const std::vector prodPostCalib = {"LHC24d3a", "LHC24d3b", "LHC24e3", "LHC24g5", "LHC24g6", "LHC24h2", "LHC24i1", "LHC24i2", "LHC24i3", "LHC24i4", "LHC24j6", "LHC24k3", "LHC24f3c", "LHC25e2", "LHC24h1b", "LHC25e4", "LHC25f5", "LHC25e8", "LHC25e9", "LHC25e10", "LHC25e11", "LHC23k4"}; + bool enableMcRecalib{false}; + + 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, IdxDe}; + 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.empty() && mEnabledParticles.empty()) { + 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}); + } + + enableMcRecalib = mcRecalib.enable; + } + + // 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; + } + case IdxDe: { + if (fullTable) { + tablePIDFullDe.reserve(size); + } else { + tablePIDDe.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::pidtof_tiny::binning::packInTable(-999.f, tablePIDPi); + } + break; + case IdxKa: + if (fullTable) { + tablePIDFullKa(-999.f, -999.f); + } else { + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDKa); + } + break; + case IdxPr: + if (fullTable) { + tablePIDFullPr(-999.f, -999.f); + } else { + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDPr); + } + break; + case IdxDe: + if (fullTable) { + tablePIDFullDe(-999.f, -999.f); + } else { + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDDe); + } + 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"); + if (std::find(prodPostCalib.begin(), prodPostCalib.end(), metadataInfo.get("LPMProductionTag")) == prodPostCalib.end()) { + enableMcRecalib = false; + LOGP(warn, "Nsigma postcalibrations turned off for {} (new MC productions have FT0 digitisation fixed)", metadataInfo.get("LPMProductionTag")); + } + } 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 const nPoints = gMcPostCalibMean[pidId]->GetN(); + double const ptMin = gMcPostCalibMean[pidId]->GetX()[0]; + double const 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(); + constexpr auto ResponseDe = 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 (enableMcRecalib) { + 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 (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kPiPlus) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + aod::pidtof_tiny::binning::packInTable(nSigma, tablePIDPi); + break; + } + case IdxKa: { + nSigma = ResponseKa.GetSeparation(mRespParamsV3, trk); + if (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kKPlus) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + aod::pidtof_tiny::binning::packInTable(nSigma, tablePIDKa); + break; + } + case IdxPr: { + nSigma = ResponsePr.GetSeparation(mRespParamsV3, trk); + if (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == kProton) { // we rescale only true signal + nSigma = applyMcRecalib(pidId, trk.pt(), nSigma); + } + } + aod::pidtof_tiny::binning::packInTable(nSigma, tablePIDPr); + break; + } + case IdxDe: { + nSigma = ResponseDe.GetSeparation(mRespParamsV3, trk); + if (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == o2::constants::physics::kDeuteron) { // we rescale only true signal + nSigma = applyMcRecalib(IdxPr, trk.pt(), nSigma); // FIXME: currently postcalibrations for protons applied to deuterons, to be checked + } + } + aod::pidtof_tiny::binning::packInTable(nSigma, tablePIDDe); + 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 (enableMcRecalib && 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 (enableMcRecalib && 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 (enableMcRecalib && 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; + } + case IdxDe: { + resolution = ResponseDe.GetExpectedSigma(mRespParamsV3, trk); + nSigma = ResponseDe.GetSeparation(mRespParamsV3, trk, resolution); + if (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == o2::constants::physics::kDeuteron) { // we rescale only true signal + nSigma = applyMcRecalib(IdxPr, trk.pt(), nSigma); // FIXME: currently postcalibrations for protons applied to deuterons, to be checked + } + } + tablePIDFullDe(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..a563e8f5d43 100644 --- a/PWGHF/TableProducer/pidCreator.cxx +++ b/PWGHF/TableProducer/pidCreator.cxx @@ -14,16 +14,25 @@ /// /// \author Vít Kučera , Inha University -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/DataModel/AliasTables.h" // IWYU pragma: keep +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/Utils/utilsPid.h" #include "Common/Core/TableHelper.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include +#include +#include +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; +using namespace o2::aod::pid_tpc_tof_utils; struct HfPidCreator { Produces trackPidFullEl; @@ -36,9 +45,8 @@ struct HfPidCreator { Produces trackPidTinyKa; 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 + Produces trackPidFullDe; + Produces trackPidTinyDe; /// Function to check whether the process function flag matches the need for filling the table /// \param initContext workflow context (argument of the init function) @@ -71,30 +79,8 @@ struct HfPidCreator { checkTableSwitch(initContext, "PidTpcTofTinyKa", doprocessTinyKa); checkTableSwitch(initContext, "PidTpcTofFullPr", doprocessFullPr); checkTableSwitch(initContext, "PidTpcTofTinyPr", doprocessTinyPr); - } - - /// 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) - { - 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 + checkTableSwitch(initContext, "PidTpcTofFullDe", doprocessFullDe); + checkTableSwitch(initContext, "PidTpcTofTinyDe", doprocessTinyDe); } void processDummy(aod::Collisions const&) {} @@ -124,6 +110,7 @@ struct HfPidCreator { PROCESS_PID(Pi) PROCESS_PID(Ka) PROCESS_PID(Pr) + PROCESS_PID(De) #undef PROCESS_PID }; diff --git a/PWGHF/TableProducer/refitPvDummy.cxx b/PWGHF/TableProducer/refitPvDummy.cxx index 64b13f2d5cb..b8a90739438 100644 --- a/PWGHF/TableProducer/refitPvDummy.cxx +++ b/PWGHF/TableProducer/refitPvDummy.cxx @@ -14,14 +14,15 @@ /// /// \author Mattia Faggin , University and INFN Padova, Italy -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/Track.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "Common/Core/trackUtilities.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 6ade0108040..83e558c0dca 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -19,40 +19,69 @@ /// \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 -#include // std::string -#include // std::vector - -#include "CommonConstants/PhysicsConstants.h" -#include "CCDB/BasicCCDBManager.h" // for PV refit -#include "DataFormatsParameters/GRPMagField.h" // for PV refit -#include "DataFormatsParameters/GRPObject.h" // for PV refit -#include "DCAFitter/DCAFitterN.h" -#include "DetectorsBase/Propagator.h" // for PV refit -#include "DetectorsVertexing/PVertexer.h" // for PV refit -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/V0.h" -#include "ReconstructionDataFormats/Vertex.h" // for PV refit +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelectorPID.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Tools/ML/MlResponse.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include // for PV refit +#include +#include +#include +#include +#include +#include // for PV refit +#include // for PV refit +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for PV refit + +#include +#include + +#include + +#include -#include "PWGHF/Core/CentralityEstimation.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/Utils/utilsAnalysis.h" -#include "PWGHF/Utils/utilsBfieldCCDB.h" -#include "PWGHF/Utils/utilsEvSelHf.h" +#include // std::find +#include +#include +#include +#include +#include // std::distance +#include +#include // std::string +#include // std::forward +#include // std::vector using namespace o2; using namespace o2::analysis; @@ -61,6 +90,7 @@ using namespace o2::aod; using namespace o2::hf_centrality; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::constants::physics; // enum for candidate type enum CandidateType { @@ -90,7 +120,8 @@ enum ChannelsProtonPid { NChannelsProtonPid }; // kaon PID (opposite-sign track in 3-prong decays) -constexpr int channelKaonPid = ChannelsProtonPid::NChannelsProtonPid; +constexpr int ChannelKaonPid = ChannelsProtonPid::NChannelsProtonPid; +constexpr int ChannelsDeuteronPid = ChannelsProtonPid::NChannelsProtonPid + 1; /// Event selection struct HfTrackIndexSkimCreatorTagSelCollisions { @@ -106,13 +137,13 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { void init(InitContext const&) { - std::array doProcess = {doprocessTrigAndCentFT0ASel, doprocessTrigAndCentFT0CSel, doprocessTrigAndCentFT0MSel, doprocessTrigAndCentFV0ASel, doprocessTrigSel, doprocessNoTrigSel}; + const std::array doProcess = {doprocessTrigAndCentFT0ASel, doprocessTrigAndCentFT0CSel, doprocessTrigAndCentFT0MSel, doprocessTrigAndCentFV0ASel, doprocessTrigSel, doprocessNoTrigSel, doprocessUpcSel}; if (std::accumulate(doProcess.begin(), doProcess.end(), 0) != 1) { LOGP(fatal, "One and only one process function for collision selection can be enabled at a time!"); } // set numerical value of the Run 2 trigger class - auto triggerAlias = std::find(aliasLabels, aliasLabels + kNaliases, triggerClassName.value.data()); + auto* const triggerAlias = std::find(aliasLabels, aliasLabels + kNaliases, triggerClassName.value.data()); if (triggerAlias != aliasLabels + kNaliases) { hfEvSel.triggerClass.value = std::distance(aliasLabels, triggerAlias); } @@ -121,7 +152,7 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { hfEvSel.addHistograms(registry); // collision monitoring if (doprocessTrigAndCentFT0ASel || doprocessTrigAndCentFT0CSel || doprocessTrigAndCentFT0MSel || doprocessTrigAndCentFV0ASel) { - AxisSpec axisCentrality{200, 0., 100., "centrality percentile"}; + const AxisSpec axisCentrality{200, 0., 100., "centrality percentile"}; registry.add("hCentralitySelected", "Centrality percentile of selected events in the centrality interval; centrality percentile;entries", {HistType::kTH1D, {axisCentrality}}); registry.add("hCentralityRejected", "Centrality percentile of selected events outside the centrality interval; centrality percentile;entries", {HistType::kTH1D, {axisCentrality}}); } @@ -130,16 +161,25 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { /// Collision selection /// \param collision collision table with - template - void selectCollision(const Col& collision, const BCs&) + template + void selectCollision(const Col& collision, + const BCsType& bcs) { - float centrality = -1.; - const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + float centrality{-1.f}; + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + + if constexpr (ApplyUpcSel) { + rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc( + collision, centrality, ccdb, registry, bcs); + } else { + rejectionMask = hfEvSel.getHfCollisionRejectionMask( + collision, centrality, ccdb, registry); + } if (fillHistograms) { hfEvSel.fillHistograms(collision, rejectionMask, centrality); // additional centrality histos - if constexpr (centEstimator != o2::hf_centrality::None) { + if constexpr (CentEstimator != o2::hf_centrality::None) { if (rejectionMask == 0) { registry.fill(HIST("hCentralitySelected"), centrality); } else if (rejectionMask == BIT(EventRejection::Centrality)) { // rejected by centrality only @@ -153,57 +193,78 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { } /// Event selection with trigger and FT0A centrality selection - void processTrigAndCentFT0ASel(soa::Join::iterator const& collision, aod::BCsWithTimestamps const& bcs) + void processTrigAndCentFT0ASel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) { - selectCollision(collision, bcs); + 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, aod::BCsWithTimestamps const& bcs) + void processTrigAndCentFT0CSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) { - selectCollision(collision, bcs); + 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, aod::BCsWithTimestamps const& bcs) + void processTrigAndCentFT0MSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) { - selectCollision(collision, bcs); + 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, aod::BCsWithTimestamps const& bcs) + void processTrigAndCentFV0ASel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) { - selectCollision(collision, bcs); + 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, aod::BCsWithTimestamps const& bcs) + void processTrigSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) { - selectCollision(collision, bcs); + selectCollision(collision, bcs); } PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processTrigSel, "Use trigger selection", false); /// Event selection without trigger selection - void processNoTrigSel(aod::Collision const& collision, aod::BCsWithTimestamps const& bcs) + void processNoTrigSel(aod::Collision const& collision, + aod::BcFullInfos const& bcs) { - selectCollision(collision, bcs); + selectCollision(collision, bcs); } PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processNoTrigSel, "Do not use trigger selection", true); + + /// Event selection with UPC + void processUpcSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + selectCollision(collision, bcs); + } + PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processUpcSel, "Use UPC event selection", false); }; /// Track selection struct HfTrackIndexSkimCreatorTagSelTracks { - SliceCache cache; - Preslice perCol = aod::track::collisionId; - Produces rowSelectedTrack; Produces tabPvRefitTrack; struct : ConfigurableGroup { + double etaMinDefault{-99999.}; 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"}; @@ -218,37 +279,37 @@ struct HfTrackIndexSkimCreatorTagSelTracks { 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> 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", std::forward(etaMinDefault), "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> 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", std::forward(etaMinDefault), "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> 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", std::forward(etaMinDefault), "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> 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", std::forward(etaMinDefault), "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 etaMinSoftPionForDstar{"etaMinSoftPionForDstar", std::forward(etaMinDefault), "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> 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"}; + Configurable> selectionsPid{"selectionsPid", {hf_presel_pid::CutsPid[0], 5, 6, hf_presel_pid::labelsRowsPid, hf_presel_pid::labelsCutsPid}, "PID selections for proton / kaon / deuteron 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"}; @@ -256,31 +317,35 @@ struct HfTrackIndexSkimCreatorTagSelTracks { Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; } config; + SliceCache cache; + // Needed for PV refitting Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - int runNumber; + 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 - std::array, CandidateType::NCandidateTypes> cutsSingleTrack; + std::array, CandidateType::NCandidateTypes> cutsSingleTrack{}; // proton PID, if enabled - std::array selectorProton; + std::array selectorProton{}; TrackSelectorKa selectorKaon; + TrackSelectorDe selectorDeuteron; - 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"}; @@ -291,26 +356,26 @@ struct HfTrackIndexSkimCreatorTagSelTracks { void init(InitContext const&) { - std::array doProcess = {doprocessNoPid, doprocessProtonPidTpc, doprocessProtonPidTof, doprocessProtonPidTpcOrTof, doprocessProtonPidTpcAndTof}; + const std::array doProcess = {doprocessNoPid, doprocessProtonPidTpc, doprocessProtonPidTof, doprocessProtonPidTpcOrTof, doprocessProtonPidTpcAndTof}; if (std::accumulate(doProcess.begin(), doProcess.end(), 0) != 1) { LOGP(fatal, "One and only one process function for the different PID selection strategies can be enabled at a time!"); } cutsSingleTrack = {config.cutsTrack2Prong, config.cutsTrack3Prong, config.cutsTrackBach, config.cutsTrackDstar, config.cutsTrackBachLfCasc}; - if (config.etaMinTrack2Prong == -99999.) { + if (config.etaMinTrack2Prong == config.etaMinDefault) { config.etaMinTrack2Prong.value = -config.etaMaxTrack2Prong; } - if (config.etaMinTrack3Prong == -99999.) { + if (config.etaMinTrack3Prong == config.etaMinDefault) { config.etaMinTrack3Prong.value = -config.etaMaxTrack3Prong; } - if (config.etaMinTrackBach == -99999.) { + if (config.etaMinTrackBach == config.etaMinDefault) { config.etaMinTrackBach.value = -config.etaMaxTrackBach; } - if (config.etaMinSoftPionForDstar == -99999.) { + if (config.etaMinSoftPionForDstar == config.etaMinDefault) { config.etaMinSoftPionForDstar.value = -config.etaMaxSoftPionForDstar; } - if (config.etaMinTrackBachLfCasc == -99999.) { + if (config.etaMinTrackBachLfCasc == config.etaMinDefault) { config.etaMinTrackBachLfCasc.value = -config.etaMaxTrackBachLfCasc; } @@ -340,8 +405,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { 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"}; + const std::string cutNames[nCuts + 1] = {"selected", "rej pT", "rej eta", "rej track quality", "rej dca"}; + const std::string candNames[CandidateType::NCandidateTypes] = {"2-prong", "3-prong", "bachelor", "dstar", "lfCascBachelor"}; for (int iCandType = 0; iCandType < CandidateType::NCandidateTypes; iCandType++) { for (int iCut = 0; iCut < nCuts + 1; iCut++) { registry.get(HIST("hRejTracks"))->GetXaxis()->SetBinLabel((nCuts + 1) * iCandType + iCut + 1, Form("%s %s", candNames[iCandType].data(), cutNames[iCut].data())); @@ -352,16 +417,16 @@ struct HfTrackIndexSkimCreatorTagSelTracks { // Needed for PV refitting 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)"}; - AxisSpec axisCollisionXOriginal{100, -2.f, 2.f, "X original PV (cm)"}; - AxisSpec axisCollisionYOriginal{100, -2.f, 2.f, "Y original PV (cm)"}; - AxisSpec axisCollisionZOriginal{100, -2.f, 2.f, "Z original PV (cm)"}; - AxisSpec axisCollisionNContrib{1000, 0, 1000, "Number of contributors"}; - AxisSpec axisCollisionDeltaX{axisPvRefitDeltaX, "#Delta x_{PV} (cm)"}; - AxisSpec axisCollisionDeltaY{axisPvRefitDeltaY, "#Delta y_{PV} (cm)"}; - AxisSpec axisCollisionDeltaZ{axisPvRefitDeltaZ, "#Delta z_{PV} (cm)"}; + const AxisSpec axisCollisionX{100, -20.f, 20.f, "X (cm)"}; + const AxisSpec axisCollisionY{100, -20.f, 20.f, "Y (cm)"}; + const AxisSpec axisCollisionZ{100, -20.f, 20.f, "Z (cm)"}; + const AxisSpec axisCollisionXOriginal{100, -2.f, 2.f, "X original PV (cm)"}; + const AxisSpec axisCollisionYOriginal{100, -2.f, 2.f, "Y original PV (cm)"}; + const AxisSpec axisCollisionZOriginal{100, -2.f, 2.f, "Z original PV (cm)"}; + const AxisSpec axisCollisionNContrib{1000, 0, 1000, "Number of contributors"}; + const AxisSpec axisCollisionDeltaX{axisPvRefitDeltaX, "#Delta x_{PV} (cm)"}; + const AxisSpec axisCollisionDeltaY{axisPvRefitDeltaY, "#Delta y_{PV} (cm)"}; + const AxisSpec axisCollisionDeltaZ{axisPvRefitDeltaZ, "#Delta z_{PV} (cm)"}; registry.add("PvRefit/hVerticesPerTrack", "", kTH1D, {{3, 0.5f, 3.5f, ""}}); registry.get(HIST("PvRefit/hVerticesPerTrack"))->GetXaxis()->SetBinLabel(1, "All PV"); @@ -394,50 +459,59 @@ struct HfTrackIndexSkimCreatorTagSelTracks { 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(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" + 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" + + selectorDeuteron.setRangePtTpc(config.selectionsPid->get(ChannelsDeuteronPid, 0u), config.selectionsPid->get(ChannelsDeuteronPid, 1u)); // 0u == "minPtTpc", 1u == "maxPtTpc" + selectorDeuteron.setRangePtTof(config.selectionsPid->get(ChannelsDeuteronPid, 3u), config.selectionsPid->get(ChannelsDeuteronPid, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" + selectorDeuteron.setRangeNSigmaTpc(-config.selectionsPid->get(ChannelsDeuteronPid, 2u), config.selectionsPid->get(ChannelsDeuteronPid, 2u)); // 2u == "nSigmaMaxTpc" + selectorDeuteron.setRangeNSigmaTof(-config.selectionsPid->get(ChannelsDeuteronPid, 5u), config.selectionsPid->get(ChannelsDeuteronPid, 5u)); // 5u == "nSigmaMaxTof" } /// PID track cuts (for proton only) /// \param hfTrack is a track /// \return true if the track is compatible with a proton hypothesis - template + template uint8_t isSelectedPid(const T& hfTrack) { - std::array statusPid = {TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted}; - if constexpr (pidStrategy == ProtonPidStrategy::PidTofOnly) { + std::array statusPid{TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted}; + if constexpr (PidStrategy == ProtonPidStrategy::PidTofOnly) { if (hfTrack.hasTOF()) { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { statusPid[iChannel] = selectorProton[iChannel].statusTof(hfTrack); } - statusPid[channelKaonPid] = selectorKaon.statusTof(hfTrack); + statusPid[ChannelKaonPid] = selectorKaon.statusTof(hfTrack); + statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTof(hfTrack); } } - if constexpr (pidStrategy == ProtonPidStrategy::PidTpcOnly) { + if constexpr (PidStrategy == ProtonPidStrategy::PidTpcOnly) { if (hfTrack.hasTPC()) { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { statusPid[iChannel] = selectorProton[iChannel].statusTpc(hfTrack); } - statusPid[channelKaonPid] = selectorKaon.statusTpc(hfTrack); + statusPid[ChannelKaonPid] = selectorKaon.statusTpc(hfTrack); + statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpc(hfTrack); } } - if constexpr (pidStrategy == ProtonPidStrategy::PidTpcOrTof) { + 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); + statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpcOrTof(hfTrack); } - if constexpr (pidStrategy == ProtonPidStrategy::PidTpcAndTof) { + 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); + statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpcAndTof(hfTrack); } - int8_t flag = BIT(ChannelsProtonPid::NChannelsProtonPid + 1) - 1; // all bits on (including the kaon one) - for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid + 1; ++iChannel) { + int8_t flag = BIT(ChannelsProtonPid::NChannelsProtonPid + 2) - 1; // all bits on (including the kaon one) + for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid + 2; ++iChannel) { if (statusPid[iChannel] == TrackSelectorPID::Rejected) { CLRBIT(flag, iChannel); } @@ -453,7 +527,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { /// \param dca is a 2-element array with dca in transverse and longitudinal directions /// \param statusProng is the selection flag template - void isSelectedTrack(const T& hfTrack, const float& trackPt, const float& trackEta, const std::array& dca, int& statusProng) + void isSelectedTrack(const T& hfTrack, const float trackPt, const float trackEta, const std::array& dca, int& statusProng) { if (config.fillHistograms) { registry.fill(HIST("hPtNoCuts"), trackPt); @@ -542,7 +616,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { hasGoodQuality = false; } } else { - UChar_t clustermap = hfTrack.itsClusterMap(); + const auto clustermap = hfTrack.itsClusterMap(); 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)))) { @@ -578,7 +652,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { hasGoodQuality = false; } } else { // selections for Run2 converted data - UChar_t clustermap = hfTrack.itsClusterMap(); + const auto clustermap = hfTrack.itsClusterMap(); if (!(TESTBIT(hfTrack.flags(), o2::aod::track::ITSrefit) && (TESTBIT(clustermap, 0) || TESTBIT(clustermap, 1)))) { hasGoodQuality = false; } @@ -607,7 +681,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { hasGoodQuality = false; } } else { // selections for Run2 converted data - UChar_t clustermap = hfTrack.itsClusterMap(); + const auto clustermap = hfTrack.itsClusterMap(); if (!(TESTBIT(hfTrack.flags(), o2::aod::track::ITSrefit) && (TESTBIT(clustermap, 0) || TESTBIT(clustermap, 1)))) { hasGoodQuality = false; } @@ -681,8 +755,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { template void performPvRefitTrack(aod::Collision const& collision, aod::BCsWithTimestamps const&, - std::vector vecPvContributorGlobId, - std::vector vecPvContributorTrackParCov, + std::vector const& vecPvContributorGlobId, + std::vector const& vecPvContributorTrackParCov, TTrack const& trackToRemove, std::array& pvCoord, std::array& pvCovMatrix, @@ -692,7 +766,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { /// Prepare the vertex refitting // set the magnetic field from CCDB - auto bc = collision.bc_as(); + const auto bc = collision.bc_as(); initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); /*if (runNumber != bc.runNumber()) { @@ -729,7 +803,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { o2::vertexing::PVertexer vertexer; o2::conf::ConfigurableParam::updateFromString("pvertexer.useMeanVertexConstraint=false"); /// remove diamond constraint (let's keep it at the moment...) vertexer.init(); - bool pvRefitDoable = vertexer.prepareVertexRefit(vecPvContributorTrackParCov, primVtx); + const bool pvRefitDoable = vertexer.prepareVertexRefit(vecPvContributorTrackParCov, primVtx); if (!pvRefitDoable) { LOG(info) << "Not enough tracks accepted for the refit"; if (config.doPvRefit && config.fillHistograms) { @@ -751,7 +825,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { bool recalcImpPar = false; if (config.doPvRefit && pvRefitDoable) { recalcImpPar = true; - auto trackIterator = std::find(vecPvContributorGlobId.begin(), vecPvContributorGlobId.end(), trackToRemove.globalIndex()); /// track global index + const auto trackIterator = std::find(vecPvContributorGlobId.begin(), vecPvContributorGlobId.end(), trackToRemove.globalIndex()); /// track global index if (trackIterator != vecPvContributorGlobId.end()) { /// this track contributed to the PV fit: let's do the refit without it @@ -759,7 +833,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { vecPvRefitContributorUsed[entry] = false; /// remove the track from the PV refitting - auto primVtxRefitted = vertexer.refitVertex(vecPvRefitContributorUsed, primVtx); // vertex refit + const auto primVtxRefitted = vertexer.refitVertex(vecPvRefitContributorUsed, primVtx); // vertex refit // LOG(info) << "refit " << cnt << "/" << ntr << " result = " << primVtxRefitted.asString(); if (config.debugPvRefit) { LOG(info) << "refit for track with global index " << static_cast(trackToRemove.globalIndex()) << " " << primVtxRefitted.asString(); @@ -812,7 +886,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { /// Track propagation to the PV refit considering also the material budget /// Mandatory for tracks updated at most only to the innermost ITS layer auto trackPar = getTrackPar(trackToRemove); - o2::gpu::gpustd::array dcaInfo{-999., -999.}; + std::array dcaInfo{-999.f, -999.f}; if (o2::base::Propagator::Instance()->propagateToDCABxByBz({primVtxBaseRecalc.getX(), primVtxBaseRecalc.getY(), primVtxBaseRecalc.getZ()}, trackPar, 2.f, noMatCorr, &dcaInfo)) { pvCoord[0] = primVtxBaseRecalc.getX(); pvCoord[1] = primVtxBaseRecalc.getY(); @@ -849,21 +923,18 @@ struct HfTrackIndexSkimCreatorTagSelTracks { // // TODO: add DCAxy and DCAz uncertainties? // } } - - return; } /// end of performPvRefitTrack function /// Selection tag for tracks + /// \tparam TTracks is the type of the track table /// \param collision is the collision iterator - /// \param tracks is the entire track table /// \param trackIndicesCollision are the track indices associated to this collision (from track-to-collision-associator) /// \param pvContrCollision are the PV contributors of this collision /// \param bcWithTimeStamps is the bc with timestamp for PVrefit /// \param pvRefitDcaPerTrack is a vector to be filled with track dcas after PV refit /// \param pvRefitPvCoordPerTrack is a vector to be filled with PV coordinates after PV refit /// \param pvRefitPvCovMatrixPerTrack is a vector to be filled with PV coordinate covariances after PV refit - /// \return true if the track is compatible with a proton hypothesis - template + template void runTagSelTracks(aod::Collision const& collision, TTracks const&, GroupedTrackIndices const& trackIndicesCollision, @@ -873,17 +944,16 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector>& pvRefitPvCoordPerTrack, std::vector>& pvRefitPvCovMatrixPerTrack) { - auto thisCollId = collision.globalIndex(); + const auto thisCollId = collision.globalIndex(); for (const auto& trackId : trackIndicesCollision) { int statusProng = BIT(CandidateType::NCandidateTypes) - 1; // all bits on - auto track = trackId.template track_as(); - auto trackIdx = track.globalIndex(); + const auto track = trackId.template track_as(); float trackPt = track.pt(); float trackEta = track.eta(); - std::array pvRefitDcaXYDcaZ{track.dcaXY(), track.dcaZ()}; - std::array pvRefitPvCoord{0.f, 0.f, 0.f}; - std::array pvRefitPvCovMatrix{1e10f, 1e10f, 1e10f, 1e10f, 1e10f, 1e10f}; + std::array pvRefitDcaXYDcaZ{track.dcaXY(), track.dcaZ()}; + std::array pvRefitPvCoord{0.f, 0.f, 0.f}; + std::array pvRefitPvCovMatrix{1e10f, 1e10f, 1e10f, 1e10f, 1e10f, 1e10f}; // PV refit and DCA recalculation only for tracks with an assigned collision if (config.doPvRefit && track.has_collision() && track.collisionId() == thisCollId && track.isPVContributor()) { @@ -891,8 +961,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { pvRefitPvCovMatrix = {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; /// retrieve PV contributors for the current collision - std::vector vecPvContributorGlobId = {}; - std::vector vecPvContributorTrackParCov = {}; + std::vector vecPvContributorGlobId{}; + std::vector vecPvContributorTrackParCov{}; for (const auto& contributor : pvContrCollision) { vecPvContributorGlobId.push_back(contributor.globalIndex()); @@ -900,22 +970,20 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } 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 (config.debugPvRefit) { + /// Perform the PV refit only for tracks with an assigned collision LOG(info) << "[BEFORE performPvRefitTrack] track.collision().globalIndex(): " << collision.globalIndex(); } performPvRefitTrack(collision, bcWithTimeStamps, vecPvContributorGlobId, vecPvContributorTrackParCov, track, pvRefitPvCoord, pvRefitPvCovMatrix, pvRefitDcaXYDcaZ); // we subtract the offset since trackIdx is the global index referred to the total track table + const auto trackIdx = track.globalIndex(); pvRefitDcaPerTrack[trackIdx] = pvRefitDcaXYDcaZ; pvRefitPvCoordPerTrack[trackIdx] = pvRefitPvCoord; pvRefitPvCovMatrixPerTrack[trackIdx] = pvRefitPvCovMatrix; } else if (track.collisionId() != thisCollId) { - auto bc = collision.bc_as(); + const auto bc = collision.bc_as(); initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); auto trackPar = getTrackPar(track); - o2::gpu::gpustd::array dcaInfo{-999., -999.}; + std::array dcaInfo{-999.f, -999.f}; o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, noMatCorr, &dcaInfo); trackPt = trackPar.getPt(); trackEta = trackPar.getEta(); @@ -933,20 +1001,19 @@ struct HfTrackIndexSkimCreatorTagSelTracks { // } isSelectedTrack(track, trackPt, trackEta, pvRefitDcaXYDcaZ, statusProng); - int8_t isIdentifiedPid = isSelectedPid(track); - bool isPositive = track.sign() > 0; + const int8_t isIdentifiedPid = isSelectedPid(track); + const bool isPositive = track.sign() > 0; rowSelectedTrack(statusProng, isIdentifiedPid, isPositive); } } /// Helper function to fill PVrefit table - /// \param pvRefitDcaPerTrack is a vector to be filled with track dcas after PV refit - /// \param pvRefitPvCoordPerTrack is a vector to be filled with PV coordinates after PV refit - /// \param pvRefitPvCovMatrixPerTrack is a vector to be filled with PV coordinate covariances after PV refit - /// \return true if the track is compatible with a proton hypothesis - void fillPvRefitTable(std::vector>& pvRefitDcaPerTrack, - std::vector>& pvRefitPvCoordPerTrack, - std::vector>& pvRefitPvCovMatrixPerTrack) + /// \param pvRefitDcaPerTrack is a vector filled with track dcas after PV refit + /// \param pvRefitPvCoordPerTrack is a vector filled with PV coordinates after PV refit + /// \param pvRefitPvCovMatrixPerTrack is a vector filled with PV coordinate covariances after PV refit + void fillPvRefitTable(std::vector> const& pvRefitDcaPerTrack, + std::vector> const& pvRefitPvCoordPerTrack, + std::vector> const& pvRefitPvCovMatrixPerTrack) { for (auto iTrack{0u}; iTrack < pvRefitDcaPerTrack.size(); ++iTrack) { tabPvRefitTrack(pvRefitPvCoordPerTrack[iTrack][0], pvRefitPvCoordPerTrack[iTrack][1], pvRefitPvCoordPerTrack[iTrack][2], @@ -966,7 +1033,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; if (config.doPvRefit) { - auto numTracks = tracks.size(); + const auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); pvRefitPvCovMatrixPerTrack.resize(numTracks); @@ -974,9 +1041,9 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } for (const auto& collision : collisions) { - auto thisCollId = collision.globalIndex(); - auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - auto pvContrCollision = pvContributors->sliceByCached(aod::track::collisionId, thisCollId, cache); + const auto thisCollId = collision.globalIndex(); + const auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + const auto pvContrCollision = pvContributors->sliceByCached(aod::track::collisionId, thisCollId, cache); runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } @@ -997,7 +1064,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; if (config.doPvRefit) { - auto numTracks = tracks.size(); + const auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); pvRefitPvCovMatrixPerTrack.resize(numTracks); @@ -1005,9 +1072,9 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } for (const auto& collision : collisions) { - auto thisCollId = collision.globalIndex(); - auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - auto pvContrCollision = pvContributorsWithPidTpc->sliceByCached(aod::track::collisionId, thisCollId, cache); + const auto thisCollId = collision.globalIndex(); + const auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + const auto pvContrCollision = pvContributorsWithPidTpc->sliceByCached(aod::track::collisionId, thisCollId, cache); runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } @@ -1028,7 +1095,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; if (config.doPvRefit) { - auto numTracks = tracks.size(); + const auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); pvRefitPvCovMatrixPerTrack.resize(numTracks); @@ -1036,9 +1103,9 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } for (const auto& collision : collisions) { - auto thisCollId = collision.globalIndex(); - auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - auto pvContrCollision = pvContributorsWithPidTof->sliceByCached(aod::track::collisionId, thisCollId, cache); + const auto thisCollId = collision.globalIndex(); + const auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + const auto pvContrCollision = pvContributorsWithPidTof->sliceByCached(aod::track::collisionId, thisCollId, cache); runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } @@ -1059,7 +1126,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; if (config.doPvRefit) { - auto numTracks = tracks.size(); + const auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); pvRefitPvCovMatrixPerTrack.resize(numTracks); @@ -1067,9 +1134,9 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } for (const auto& collision : collisions) { - auto thisCollId = collision.globalIndex(); - auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - auto pvContrCollision = pvContributorsWithPidTpcTof->sliceByCached(aod::track::collisionId, thisCollId, cache); + const auto thisCollId = collision.globalIndex(); + const auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + const auto pvContrCollision = pvContributorsWithPidTpcTof->sliceByCached(aod::track::collisionId, thisCollId, cache); runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } @@ -1090,7 +1157,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::vector> pvRefitPvCoordPerTrack{}; std::vector> pvRefitPvCovMatrixPerTrack{}; if (config.doPvRefit) { - auto numTracks = tracks.size(); + const auto numTracks = tracks.size(); pvRefitDcaPerTrack.resize(numTracks); pvRefitPvCoordPerTrack.resize(numTracks); pvRefitPvCovMatrixPerTrack.resize(numTracks); @@ -1098,9 +1165,9 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } for (const auto& collision : collisions) { - auto thisCollId = collision.globalIndex(); - auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - auto pvContrCollision = pvContributorsWithPidTpcTof->sliceByCached(aod::track::collisionId, thisCollId, cache); + const auto thisCollId = collision.globalIndex(); + const auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + const auto pvContrCollision = pvContributorsWithPidTpcTof->sliceByCached(aod::track::collisionId, thisCollId, cache); runTagSelTracks(collision, tracks, groupedTrackIndices, pvContrCollision, bcWithTimeStamps, pvRefitDcaPerTrack, pvRefitPvCoordPerTrack, pvRefitPvCovMatrixPerTrack); } @@ -1130,7 +1197,7 @@ struct HfTrackIndexSkimCreator { 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 do3Prong{"do3Prong", false, "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"}; @@ -1158,34 +1225,38 @@ struct HfTrackIndexSkimCreator { // 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"}; + 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"}; + 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"}; + 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"}; + 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"}; + 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"}; + 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"}; + 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"}; + // Cd cuts + Configurable> binsPtCdToDeKPi{"binsPtCdToDeKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Cd->DeKpi pT-dependent cuts"}; + Configurable> cutsCdToDeKPi{"cutsCdToDeKPi", {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}, "Cd->deKpi 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"}; + 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"}; - + Configurable applyDeuteronPidForCdToDeKPi{"applyDeuteronPidForCdToDeKPi", false, "Require deuteron PID for Cd->deKpi"}; // 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"}; @@ -1194,11 +1265,11 @@ struct HfTrackIndexSkimCreator { 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"}; + 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; @@ -1206,36 +1277,28 @@ struct HfTrackIndexSkimCreator { o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter // Needed for PV refitting Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - int runNumber; - - double massPi{0.}; - double massK{0.}; - double massProton{0.}; - double massElectron{0.}; - double massMuon{0.}; - double massDzero{0.}; - double massPhi{0.}; + int runNumber{}; // int nColls{0}; //can be added to run over limited collisions per file - for tesing purposes - 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 kNCutsDstar = 3; // how many different selections are made on Dstars - std::array, 2>, kN2ProngDecays> arrMass2Prong; - std::array, 2>, kN3ProngDecays> arrMass3Prong; + 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, 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{}; // arrays of 2-prong and 3-prong cuts - std::array, kN2ProngDecays> cut2Prong; - std::array, kN2ProngDecays> pTBins2Prong; - std::array, kN3ProngDecays> cut3Prong; - std::array, kN3ProngDecays> pTBins3Prong; + std::array, kN2ProngDecays> cut2Prong{}; + std::array, kN2ProngDecays> binsPt2Prong{}; + std::array, kN3ProngDecays> cut3Prong{}; + std::array, kN3ProngDecays> binsPt3Prong{}; // ML response - o2::analysis::MlResponse hfMlResponse2Prongs; // only D0 - std::array, kN3ProngDecays> hfMlResponse3Prongs; // D+, Lc, Ds, Xic + o2::analysis::MlResponse hfMlResponse2Prongs; // only D0 + std::array, kN3ProngDecays> hfMlResponse3Prongs{}; // D+, Lc, Ds, Xic std::array hasMlModel3Prong{false}; o2::ccdb::CcdbApi ccdbApi; @@ -1244,14 +1307,13 @@ struct HfTrackIndexSkimCreator { using FilteredTrackAssocSel = soa::Filtered>; // 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 filterSelectCollisions = (aod::hf_sel_collision::whyRejectColl == static_cast(0)); // 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)); @@ -1268,45 +1330,40 @@ struct HfTrackIndexSkimCreator { void init(InitContext const&) { - if (!doprocess2And3ProngsWithPvRefit && !doprocess2And3ProngsNoPvRefit) { + if (!doprocess2And3ProngsWithPvRefit && !doprocess2And3ProngsNoPvRefit && !doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt && !doprocess2And3ProngsNoPvRefitWithPidForHfFiltersBdt) { return; } - massPi = o2::constants::physics::MassPiPlus; - massK = o2::constants::physics::MassKPlus; - massProton = o2::constants::physics::MassProton; - massElectron = o2::constants::physics::MassElectron; - massMuon = o2::constants::physics::MassMuonPlus; - massDzero = o2::constants::physics::MassD0; - massPhi = o2::constants::physics::MassPhi; + arrMass2Prong[hf_cand_2prong::DecayType::D0ToPiK] = std::array{std::array{MassPiPlus, MassKPlus}, + std::array{MassKPlus, MassPiPlus}}; - arrMass2Prong[hf_cand_2prong::DecayType::D0ToPiK] = std::array{std::array{massPi, massK}, - std::array{massK, massPi}}; + arrMass2Prong[hf_cand_2prong::DecayType::JpsiToEE] = std::array{std::array{MassElectron, MassElectron}, + std::array{MassElectron, MassElectron}}; - arrMass2Prong[hf_cand_2prong::DecayType::JpsiToEE] = std::array{std::array{massElectron, massElectron}, - std::array{massElectron, massElectron}}; + arrMass2Prong[hf_cand_2prong::DecayType::JpsiToMuMu] = std::array{std::array{MassMuonPlus, MassMuonPlus}, + std::array{MassMuonPlus, MassMuonPlus}}; - arrMass2Prong[hf_cand_2prong::DecayType::JpsiToMuMu] = std::array{std::array{massMuon, massMuon}, - std::array{massMuon, massMuon}}; + arrMass3Prong[hf_cand_3prong::DecayType::DplusToPiKPi] = std::array{std::array{MassPiPlus, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassPiPlus}}; - arrMass3Prong[hf_cand_3prong::DecayType::DplusToPiKPi] = std::array{std::array{massPi, massK, massPi}, - std::array{massPi, massK, massPi}}; + arrMass3Prong[hf_cand_3prong::DecayType::LcToPKPi] = std::array{std::array{MassProton, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassProton}}; - arrMass3Prong[hf_cand_3prong::DecayType::LcToPKPi] = std::array{std::array{massProton, massK, massPi}, - std::array{massPi, massK, massProton}}; + arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi] = std::array{std::array{MassKPlus, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassKPlus}}; - arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi] = std::array{std::array{massK, massK, massPi}, - std::array{massPi, massK, massK}}; + arrMass3Prong[hf_cand_3prong::DecayType::XicToPKPi] = std::array{std::array{MassProton, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassProton}}; - arrMass3Prong[hf_cand_3prong::DecayType::XicToPKPi] = std::array{std::array{massProton, massK, massPi}, - std::array{massPi, massK, massProton}}; + arrMass3Prong[hf_cand_3prong::DecayType::CdToDeKPi] = std::array{std::array{MassDeuteron, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassDeuteron}}; // cuts for 2-prong decays retrieved by json. the order must be then one in hf_cand_2prong::DecayType cut2Prong = {config.cutsD0ToPiK, config.cutsJpsiToEE, config.cutsJpsiToMuMu}; - pTBins2Prong = {config.binsPtD0ToPiK, config.binsPtJpsiToEE, config.binsPtJpsiToMuMu}; + binsPt2Prong = {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 = {config.cutsDplusToPiKPi, config.cutsLcToPKPi, config.cutsDsToKKPi, config.cutsXicToPKPi}; - pTBins3Prong = {config.binsPtDplusToPiKPi, config.binsPtLcToPKPi, config.binsPtDsToKKPi, config.binsPtXicToPKPi}; + cut3Prong = {config.cutsDplusToPiKPi, config.cutsLcToPKPi, config.cutsDsToKKPi, config.cutsXicToPKPi, config.cutsCdToDeKPi}; + binsPt3Prong = {config.binsPtDplusToPiKPi, config.binsPtLcToPKPi, config.binsPtDsToKKPi, config.binsPtXicToPKPi, config.binsPtCdToDeKPi}; df2.setPropagateToPCA(config.propagateToPCA); df2.setMaxR(config.maxR); @@ -1331,8 +1388,8 @@ struct HfTrackIndexSkimCreator { runNumber = 0; if (config.fillHistograms) { - AxisSpec axisNumTracks{500, -0.5f, 499.5f, "Number of tracks"}; - AxisSpec axisNumCands{1000, -0.5f, 999.5f, "Number of candidates"}; + const AxisSpec axisNumTracks{500, -0.5f, 499.5f, "Number of tracks"}; + const AxisSpec axisNumCands{1000, -0.5f, 999.5f, "Number of candidates"}; 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::kTH1D, {{1000, -2., 2.}}}); @@ -1354,19 +1411,20 @@ struct HfTrackIndexSkimCreator { 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}}}); + registry.add("hMassCdToDeKPi", "C Deuteron candidates;inv. mass (De K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); // needed for PV refitting - if (doprocess2And3ProngsWithPvRefit) { - 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)"}; - AxisSpec axisCollisionXOriginal{1000, -20.f, 20.f, "X original PV (cm)"}; - AxisSpec axisCollisionYOriginal{1000, -20.f, 20.f, "Y original PV (cm)"}; - AxisSpec axisCollisionZOriginal{1000, -20.f, 20.f, "Z original PV (cm)"}; - AxisSpec axisCollisionNContrib{1000, 0, 1000, "Number of contributors"}; - AxisSpec axisCollisionDeltaX{axisPvRefitDeltaX, "#Delta x_{PV} (cm)"}; - AxisSpec axisCollisionDeltaY{axisPvRefitDeltaY, "#Delta y_{PV} (cm)"}; - AxisSpec axisCollisionDeltaZ{axisPvRefitDeltaZ, "#Delta z_{PV} (cm)"}; + if (doprocess2And3ProngsWithPvRefit || doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt) { + const AxisSpec axisCollisionX{100, -20.f, 20.f, "X (cm)"}; + const AxisSpec axisCollisionY{100, -20.f, 20.f, "Y (cm)"}; + const AxisSpec axisCollisionZ{100, -20.f, 20.f, "Z (cm)"}; + const AxisSpec axisCollisionXOriginal{1000, -20.f, 20.f, "X original PV (cm)"}; + const AxisSpec axisCollisionYOriginal{1000, -20.f, 20.f, "Y original PV (cm)"}; + const AxisSpec axisCollisionZOriginal{1000, -20.f, 20.f, "Z original PV (cm)"}; + const AxisSpec axisCollisionNContrib{1000, 0, 1000, "Number of contributors"}; + const AxisSpec axisCollisionDeltaX{axisPvRefitDeltaX, "#Delta x_{PV} (cm)"}; + const AxisSpec axisCollisionDeltaY{axisPvRefitDeltaY, "#Delta y_{PV} (cm)"}; + const AxisSpec axisCollisionDeltaZ{axisPvRefitDeltaZ, "#Delta z_{PV} (cm)"}; 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"); @@ -1386,7 +1444,7 @@ struct HfTrackIndexSkimCreator { } if (config.applyMlForHfFilters) { - AxisSpec axisBdtScore{100, 0.f, 1.f}; + const AxisSpec axisBdtScore{100, 0.f, 1.f}; 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}); @@ -1406,13 +1464,14 @@ struct HfTrackIndexSkimCreator { } 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 = {config.thresholdMlScoreDplusToPiKPi, config.thresholdMlScoreLcToPiKP, config.thresholdMlScoreDsToPiKK, config.thresholdMlScoreXicToPiKP}; + const std::vector onnxFileNames2Prongs{config.onnxFileNames->get(0u, 0u)}; + // Exclude Cd from the 3-prong list, as it is not included in the pp trigger program + const std::array, kN3ProngDecays - 1> 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 - 1> 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 - 1> thresholdMlScore3Prongs{config.thresholdMlScoreDplusToPiKPi, config.thresholdMlScoreLcToPiKP, config.thresholdMlScoreDsToPiKK, config.thresholdMlScoreXicToPiKP}; // initialise 2-prong ML response hfMlResponse2Prongs.configure(ptBinsMl, config.thresholdMlScoreD0ToKPi, cutDirMl, 3); @@ -1425,8 +1484,8 @@ struct HfTrackIndexSkimCreator { hfMlResponse2Prongs.init(); // initialise 3-prong ML responses - for (int iDecay3P{0}; iDecay3P < kN3ProngDecays; ++iDecay3P) { - if (onnxFileNames3Prongs[iDecay3P][0] == "") { // 3-prong species to be skipped + for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 1; ++iDecay3P) { + if (onnxFileNames3Prongs[iDecay3P][0].empty()) { // 3-prong species to be skipped continue; } hasMlModel3Prong[iDecay3P] = true; @@ -1452,20 +1511,19 @@ struct HfTrackIndexSkimCreator { /// \param isSelected is a bitmap with selection outcome /// \param pt2Prong is the pt of the 2-prong candidate template - void applyPreselection2Prong(T1 const& pVecTrack0, T1 const& pVecTrack1, T2 const& dcaTrack0, T2 const& dcaTrack1, T3& cutStatus, T4& whichHypo, int& isSelected, float& pt2Prong) + void applyPreselection2Prong(T1 const& pVecTrack0, T1 const& pVecTrack1, T2 const& dcaTrack0, T2 const& dcaTrack1, T3& cutStatus, T4& whichHypo, auto& isSelected, float& pt2Prong) { whichHypo[kN2ProngDecays] = 0; // D0 for D* - auto arrMom = std::array{pVecTrack0, pVecTrack1}; pt2Prong = RecoDecay::pt(pVecTrack0, pVecTrack1); - auto pT = pt2Prong + config.ptTolerance; // add tolerance because of no reco decay vertex + const auto pt = pt2Prong + config.ptTolerance; // add tolerance because of no reco decay vertex for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { // pT - auto pTBin = findBin(&pTBins2Prong[iDecay2P], pT); + const auto binPt = findBin(&binsPt2Prong[iDecay2P], pt); // return immediately if it is outside the defined pT bins - if (pTBin == -1) { + if (binPt == -1) { CLRBIT(isSelected, iDecay2P); if (config.debug) { cutStatus[iDecay2P][0] = false; @@ -1474,34 +1532,37 @@ struct HfTrackIndexSkimCreator { } // invariant mass - double massHypos[2] = {0.f, 0.f}; - whichHypo[iDecay2P] = 3; - double minMass = cut2Prong[iDecay2P].get(pTBin, 0u); - double maxMass = cut2Prong[iDecay2P].get(pTBin, 1u); - double min2 = minMass * minMass; - double max2 = maxMass * maxMass; - - 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) { - CLRBIT(whichHypo[iDecay2P], 0); - } - if (massHypos[1] < min2 || massHypos[1] >= max2) { - CLRBIT(whichHypo[iDecay2P], 1); - } - if (whichHypo[iDecay2P] == 0) { - CLRBIT(isSelected, iDecay2P); - if (config.debug) { - cutStatus[iDecay2P][1] = false; + double massHypos[2] = {0., 0.}; + whichHypo[iDecay2P] = 3; // 2 bits on + + if (config.debug || TESTBIT(isSelected, iDecay2P)) { + const double minMass = cut2Prong[iDecay2P].get(binPt, 0u); + const double maxMass = cut2Prong[iDecay2P].get(binPt, 1u); + if (minMass >= 0. && maxMass > 0.) { + const std::array arrMom{pVecTrack0, pVecTrack1}; + massHypos[0] = RecoDecay::m2(arrMom, arrMass2Prong[iDecay2P][0]); + massHypos[1] = (iDecay2P == hf_cand_2prong::DecayType::D0ToPiK) ? RecoDecay::m2(arrMom, arrMass2Prong[iDecay2P][1]) : massHypos[0]; + const double min2 = minMass * minMass; + const double max2 = maxMass * maxMass; + if (massHypos[0] < min2 || massHypos[0] >= max2) { + CLRBIT(whichHypo[iDecay2P], 0); + } + if (massHypos[1] < min2 || massHypos[1] >= max2) { + CLRBIT(whichHypo[iDecay2P], 1); + } + if (whichHypo[iDecay2P] == 0) { + CLRBIT(isSelected, iDecay2P); + if (config.debug) { + cutStatus[iDecay2P][1] = false; + } } } } // imp. par. product cut if (config.debug || TESTBIT(isSelected, iDecay2P)) { - auto impParProduct = dcaTrack0 * dcaTrack1; - if (impParProduct > cut2Prong[iDecay2P].get(pTBin, 3u)) { + const auto impParProduct = dcaTrack0 * dcaTrack1; + if (impParProduct > cut2Prong[iDecay2P].get(binPt, 3u)) { CLRBIT(isSelected, iDecay2P); if (config.debug) { cutStatus[iDecay2P][2] = false; @@ -1511,15 +1572,15 @@ struct HfTrackIndexSkimCreator { // additional check for D0 to be used in D* finding 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) { + const auto binPtDstar = findBin(config.binsPtDstarToD0Pi, pt * 1.2); // assuming the D* pT about 20% higher than the one of the D0 to be safe + if (binPtDstar >= 0) { whichHypo[kN2ProngDecays] = whichHypo[hf_cand_2prong::DecayType::D0ToPiK]; - double deltaMass = config.cutsDstarToD0Pi->get(pTBinDstar, 1u); + const double deltaMass = config.cutsDstarToD0Pi->get(binPtDstar, 1u); - if (TESTBIT(whichHypo[iDecay2P], 0) && (massHypos[0] > (massDzero + deltaMass) * (massDzero + deltaMass) || massHypos[0] < (massDzero - deltaMass) * (massDzero - deltaMass))) { + if (TESTBIT(whichHypo[iDecay2P], 0) && (massHypos[0] > (MassD0 + deltaMass) * (MassD0 + deltaMass) || massHypos[0] < (MassD0 - deltaMass) * (MassD0 - deltaMass))) { CLRBIT(whichHypo[kN2ProngDecays], 0); } - if (TESTBIT(whichHypo[iDecay2P], 1) && (massHypos[1] > (massDzero + deltaMass) * (massDzero + deltaMass) || massHypos[1] < (massDzero - deltaMass) * (massDzero - deltaMass))) { + if (TESTBIT(whichHypo[iDecay2P], 1) && (massHypos[1] > (MassD0 + deltaMass) * (MassD0 + deltaMass) || massHypos[1] < (MassD0 - deltaMass) * (MassD0 - deltaMass))) { CLRBIT(whichHypo[kN2ProngDecays], 1); } } @@ -1528,7 +1589,7 @@ struct HfTrackIndexSkimCreator { } /// Method to perform selections on difference from nominal mass for phi decay - /// \param pTBin pt bin for the cuts + /// \param binPt pt bin for the cuts /// \param pVecTrack0 is the momentum array of the first daughter track /// \param pVecTrack1 is the momentum array of the second daughter track /// \param pVecTrack2 is the momentum array of the third daughter track @@ -1536,22 +1597,21 @@ struct HfTrackIndexSkimCreator { /// \param whichHypo information of the mass hypoteses that were selected /// \param isSelected is a bitmap with selection outcome template - void applyPreselectionPhiDecay(int& pTBin, T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, T2& cutStatus, T3& whichHypo, int& isSelected) + void applyPreselectionPhiDecay(const int binPt, T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, T2& cutStatus, T3& whichHypo, auto& isSelected) { - double deltaMassMax = cut3Prong[hf_cand_3prong::DecayType::DsToKKPi].get(pTBin, 4u); + const double deltaMassMax = cut3Prong[hf_cand_3prong::DecayType::DsToKKPi].get(binPt, 4u); if (TESTBIT(whichHypo[hf_cand_3prong::DecayType::DsToKKPi], 0)) { - double mass2PhiKKPi = RecoDecay::m2(std::array{pVecTrack0, pVecTrack1}, std::array{arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi][0][0], arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi][0][1]}); - if (mass2PhiKKPi > (massPhi + deltaMassMax) * (massPhi + deltaMassMax) || mass2PhiKKPi < (massPhi - deltaMassMax) * (massPhi - deltaMassMax)) { + const double mass2PhiKKPi = RecoDecay::m2(std::array{pVecTrack0, pVecTrack1}, std::array{arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi][0][0], arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi][0][1]}); + if (mass2PhiKKPi > (MassPhi + deltaMassMax) * (MassPhi + deltaMassMax) || mass2PhiKKPi < (MassPhi - deltaMassMax) * (MassPhi - deltaMassMax)) { CLRBIT(whichHypo[hf_cand_3prong::DecayType::DsToKKPi], 0); } } if (TESTBIT(whichHypo[hf_cand_3prong::DecayType::DsToKKPi], 1)) { - double mass2PhiPiKK = RecoDecay::m2(std::array{pVecTrack1, pVecTrack2}, std::array{arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi][1][1], arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi][1][2]}); - if (mass2PhiPiKK > (massPhi + deltaMassMax) * (massPhi + deltaMassMax) || mass2PhiPiKK < (massPhi - deltaMassMax) * (massPhi - deltaMassMax)) { + const double mass2PhiPiKK = RecoDecay::m2(std::array{pVecTrack1, pVecTrack2}, std::array{arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi][1][1], arrMass3Prong[hf_cand_3prong::DecayType::DsToKKPi][1][2]}); + if (mass2PhiPiKK > (MassPhi + deltaMassMax) * (MassPhi + deltaMassMax) || mass2PhiPiKK < (MassPhi - deltaMassMax) * (MassPhi - deltaMassMax)) { CLRBIT(whichHypo[hf_cand_3prong::DecayType::DsToKKPi], 1); } } - if (whichHypo[hf_cand_3prong::DecayType::DsToKKPi] == 0) { CLRBIT(isSelected, hf_cand_3prong::DecayType::DsToKKPi); if (config.debug) { @@ -1570,36 +1630,35 @@ struct HfTrackIndexSkimCreator { /// \param whichHypo information of the mass hypoteses that were selected /// \param isSelected is a bitmap with selection outcome template - void applyPreselection3Prong(T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, int8_t& isIdentifiedPidTrack0, int8_t& isIdentifiedPidTrack2, T2& cutStatus, T3& whichHypo, int& isSelected) + void applyPreselection3Prong(T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, const auto isIdentifiedPidTrack0, const auto isIdentifiedPidTrack2, T2& cutStatus, T3& whichHypo, auto& isSelected) { - - auto arrMom = std::array{pVecTrack0, pVecTrack1, pVecTrack2}; - auto pT = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + config.ptTolerance; // add tolerance because of no reco decay vertex + const 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 && 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))) { + whichHypo[iDecay3P] = 3; // 2 bits on + + if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && config.applyProtonPidForLcToPKPi) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && config.applyProtonPidForXicToPKPi) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && config.applyDeuteronPidForCdToDeKPi)) { + + if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::XicToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsDeuteronPid))) { CLRBIT(whichHypo[iDecay3P], 0); } - if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsProtonPid::XicToPKPi))) { + if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsProtonPid::XicToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsDeuteronPid))) { CLRBIT(whichHypo[iDecay3P], 1); } if (whichHypo[iDecay3P] == 0) { CLRBIT(isSelected, iDecay3P); if (config.debug) { - cutStatus[iDecay3P][hf_cuts_presel_3prong::nCutVars] = false; // PID + cutStatus[iDecay3P][hf_cuts_presel_3prong::NCutVars] = false; // PID } continue; // no need to check further for this particle hypothesis } } - // pT - auto pTBin = findBin(&pTBins3Prong[iDecay3P], pT); + const auto binPt = findBin(&binsPt3Prong[iDecay3P], pt); // return immediately if it is outside the defined pT bins - if (pTBin == -1) { + if (binPt == -1) { CLRBIT(isSelected, iDecay3P); whichHypo[iDecay3P] = 0; if (config.debug) { @@ -1609,31 +1668,33 @@ struct HfTrackIndexSkimCreator { } // invariant mass - double massHypos[2]; - double minMass = cut3Prong[iDecay3P].get(pTBin, 0u); - double maxMass = cut3Prong[iDecay3P].get(pTBin, 1u); - double min2 = minMass * minMass; - double max2 = maxMass * maxMass; - - 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) { - CLRBIT(whichHypo[iDecay3P], 0); - } - if (massHypos[1] < min2 || massHypos[1] >= max2) { - CLRBIT(whichHypo[iDecay3P], 1); - } - if (whichHypo[iDecay3P] == 0) { - CLRBIT(isSelected, iDecay3P); - if (config.debug) { - cutStatus[iDecay3P][1] = false; + if ((config.debug || TESTBIT(isSelected, iDecay3P))) { + const double minMass = cut3Prong[iDecay3P].get(binPt, 0u); + const double maxMass = cut3Prong[iDecay3P].get(binPt, 1u); + if (minMass >= 0. && maxMass > 0.) { // no need to check isSelected but to avoid mistakes + double massHypos[2] = {0., 0.}; + const std::array arrMom{pVecTrack0, pVecTrack1, pVecTrack2}; + const double min2 = minMass * minMass; + const double max2 = maxMass * maxMass; + 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) { + CLRBIT(whichHypo[iDecay3P], 0); + } + if (massHypos[1] < min2 || massHypos[1] >= max2) { + CLRBIT(whichHypo[iDecay3P], 1); + } + if (whichHypo[iDecay3P] == 0) { + CLRBIT(isSelected, iDecay3P); + if (config.debug) { + cutStatus[iDecay3P][1] = false; + } } } } if ((config.debug || TESTBIT(isSelected, iDecay3P)) && iDecay3P == hf_cand_3prong::DecayType::DsToKKPi) { - applyPreselectionPhiDecay(pTBin, pVecTrack0, pVecTrack1, pVecTrack2, cutStatus, whichHypo, isSelected); + applyPreselectionPhiDecay(binPt, pVecTrack0, pVecTrack1, pVecTrack2, cutStatus, whichHypo, isSelected); } } } @@ -1645,15 +1706,15 @@ struct HfTrackIndexSkimCreator { /// \param cutStatus is a 2D array with outcome of each selection (filled only in debug mode) /// \param isSelected ia s bitmap with selection outcome template - void applySelections2Prong(const T1& pVecCand, const T2& secVtx, const T3& primVtx, T4& cutStatus, int& isSelected) + void applySelection2Prong(const T1& pVecCand, const T2& secVtx, const T3& primVtx, T4& cutStatus, auto& isSelected) { if (config.debug || isSelected > 0) { for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { // pT - auto pTBin = findBin(&pTBins2Prong[iDecay2P], RecoDecay::pt(pVecCand)); - if (pTBin == -1) { // cut if it is outside the defined pT bins + const auto binPt = findBin(&binsPt2Prong[iDecay2P], RecoDecay::pt(pVecCand)); + if (binPt == -1) { // cut if it is outside the defined pT bins CLRBIT(isSelected, iDecay2P); if (config.debug) { cutStatus[iDecay2P][0] = false; @@ -1661,10 +1722,10 @@ struct HfTrackIndexSkimCreator { continue; } - // cosp + // cos of pointing angle if (config.debug || TESTBIT(isSelected, iDecay2P)) { - auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecCand); - if (cpa < cut2Prong[iDecay2P].get(pTBin, 2u)) { // 2u == "cospIndex[iDecay2P]" + const auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecCand); + if (cpa < cut2Prong[iDecay2P].get(binPt, 2u)) { // 2u == "cospIndex[iDecay2P]" CLRBIT(isSelected, iDecay2P); if (config.debug) { cutStatus[iDecay2P][3] = false; @@ -1679,13 +1740,13 @@ struct HfTrackIndexSkimCreator { /// \param featuresCand is the vector with the candidate features /// \param outputScores is the vector with the output scores to be filled /// \param isSelected ia s bitmap with selection outcome - void applyMlSelectionForHfFilters2Prong(std::vector featuresCand, std::vector& outputScores, int& isSelected) + void applyMlSelectionForHfFilters2Prong(std::vector featuresCand, std::vector& outputScores, auto& isSelected) { if (!TESTBIT(isSelected, hf_cand_2prong::DecayType::D0ToPiK)) { return; } const float ptDummy = 1.; // dummy pT value (only one pT bin) - bool isSelMl = hfMlResponse2Prongs.isSelectedMl(featuresCand, ptDummy, outputScores); + const bool isSelMl = hfMlResponse2Prongs.isSelectedMl(featuresCand, ptDummy, outputScores); if (config.fillHistograms) { registry.fill(HIST("ML/hMlScoreBkgD0"), outputScores[0]); registry.fill(HIST("ML/hMlScorePromptD0"), outputScores[1]); @@ -1707,12 +1768,8 @@ struct HfTrackIndexSkimCreator { if (dcaFitter.getChi2AtPCACandidate() > config.maxTwoTrackChi2PcaFor3Prongs) { return false; } - auto decLen = RecoDecay::distance(primVtx, secVtx); - if (decLen < config.minTwoTrackDecayLengthFor3Prongs) { - return false; - } - - return true; + const auto decLen = RecoDecay::distance(primVtx, secVtx); + return static_cast(decLen >= config.minTwoTrackDecayLengthFor3Prongs); } /// Method to perform selections for 3-prong candidates after vertex reconstruction @@ -1722,16 +1779,16 @@ struct HfTrackIndexSkimCreator { /// \param cutStatus is a 2D array with outcome of each selection (filled only in debug mode) /// \param isSelected ia s bitmap with selection outcome template - void applySelection3Prong(const T1& pVecCand, const T2& secVtx, const T3& primVtx, T4& cutStatus, int& isSelected) + void applySelection3Prong(const T1& pVecCand, const T2& secVtx, const T3& primVtx, T4& cutStatus, auto& isSelected) { if (config.debug || isSelected > 0) { - auto pT = RecoDecay::pt(pVecCand); + const auto pt = RecoDecay::pt(pVecCand); for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { // pT - auto pTBin = findBin(&pTBins3Prong[iDecay3P], pT); - if (pTBin == -1) { // cut if it is outside the defined pT bins + const auto binPt = findBin(&binsPt3Prong[iDecay3P], pt); + if (binPt == -1) { // cut if it is outside the defined pT bins CLRBIT(isSelected, iDecay3P); if (config.debug) { cutStatus[iDecay3P][0] = false; @@ -1739,10 +1796,10 @@ struct HfTrackIndexSkimCreator { continue; } - // cosp - if ((config.debug || TESTBIT(isSelected, iDecay3P))) { - auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecCand); - if (cpa < cut3Prong[iDecay3P].get(pTBin, 2u)) { // 2u == cospIndex[iDecay3P] + // cos of pointing angle + if (config.debug || TESTBIT(isSelected, iDecay3P)) { + const auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecCand); + if (cpa < cut3Prong[iDecay3P].get(binPt, 2u)) { // 2u == cospIndex[iDecay3P] CLRBIT(isSelected, iDecay3P); if (config.debug) { cutStatus[iDecay3P][2] = false; @@ -1752,8 +1809,8 @@ struct HfTrackIndexSkimCreator { // decay length if ((config.debug || TESTBIT(isSelected, iDecay3P))) { - auto decayLength = RecoDecay::distance(primVtx, secVtx); - if (decayLength < cut3Prong[iDecay3P].get(pTBin, 3u)) { // 3u == decLenIndex[iDecay3P] + const auto decayLength = RecoDecay::distance(primVtx, secVtx); + if (decayLength < cut3Prong[iDecay3P].get(binPt, 3u)) { // 3u == decLenIndex[iDecay3P] CLRBIT(isSelected, iDecay3P); if (config.debug) { cutStatus[iDecay3P][3] = false; @@ -1765,19 +1822,33 @@ struct HfTrackIndexSkimCreator { } /// Method to perform ML selections for 2-prong candidates after the rectangular selections + /// \tparam usePidForHfFiltersBdt is the flag to determine whether to use also the PID features for the Lc BDT /// \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) + template + void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::vector featuresCandPid, std::array, kN3ProngDecays - 1>& outputScores, auto& isSelected) { if (isSelected == 0) { return; } - const float ptDummy = 1.; // dummy pT value (only one pT bin) - for (int iDecay3P{0}; iDecay3P < kN3ProngDecays; ++iDecay3P) { + const float ptDummy = 1.f; // dummy pT value (only one pT bin) + for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 1; ++iDecay3P) { if (TESTBIT(isSelected, iDecay3P) && hasMlModel3Prong[iDecay3P]) { - bool isMlSel = hfMlResponse3Prongs[iDecay3P].isSelectedMl(featuresCand, ptDummy, outputScores[iDecay3P]); + 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: { @@ -1824,26 +1895,25 @@ struct HfTrackIndexSkimCreator { uint8_t applySelectionDstar(T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, uint8_t& cutStatus, T2& deltaMass) { uint8_t isSelected{1}; - auto arrMom = std::array{pVecTrack0, pVecTrack1, pVecTrack2}; - auto arrMomD0 = std::array{pVecTrack0, pVecTrack1}; - auto pT = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + config.ptTolerance; // add tolerance because of no reco decay vertex + const std::array arrMom{pVecTrack0, pVecTrack1, pVecTrack2}; + const std::array arrMomD0{pVecTrack0, pVecTrack1}; + const auto pt = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + config.ptTolerance; // add tolerance because of no reco decay vertex // pT - auto pTBin = findBin(config.binsPtDstarToD0Pi, pT); + const auto binPt = findBin(config.binsPtDstarToD0Pi, pt); // return immediately if it is outside the defined pT bins - if (pTBin == -1) { + if (binPt == -1) { isSelected = 0; if (config.debug) { CLRBIT(cutStatus, 0); - } else { - return isSelected; } + return isSelected; } // D0 mass - double deltaMassD0 = config.cutsDstarToD0Pi->get(pTBin, 1u); // 1u == deltaMassD0Index - double invMassD0 = RecoDecay::m(arrMomD0, std::array{massPi, massK}); - if (std::abs(invMassD0 - massDzero) > deltaMassD0) { + const double deltaMassD0 = config.cutsDstarToD0Pi->get(binPt, 1u); // 1u == deltaMassD0Index + const double invMassD0 = RecoDecay::m(arrMomD0, std::array{MassPiPlus, MassKPlus}); + if (std::abs(invMassD0 - MassD0) > deltaMassD0) { isSelected = 0; if (config.debug) { CLRBIT(cutStatus, 1); @@ -1852,8 +1922,8 @@ struct HfTrackIndexSkimCreator { } // D*+ mass - double maxDeltaMass = config.cutsDstarToD0Pi->get(pTBin, 0u); // 0u == deltaMassIndex - double invMassDstar = RecoDecay::m(arrMom, std::array{massPi, massK, massPi}); + const double maxDeltaMass = config.cutsDstarToD0Pi->get(binPt, 0u); // 0u == deltaMassIndex + const double invMassDstar = RecoDecay::m(arrMom, std::array{MassPiPlus, MassKPlus, MassPiPlus}); deltaMass = invMassDstar - invMassD0; if (deltaMass > maxDeltaMass) { isSelected = 0; @@ -1876,9 +1946,9 @@ struct HfTrackIndexSkimCreator { /// \param pvCovMatrix is a vector where to store the covariance matrix values of refitted PV void performPvRefitCandProngs(SelectedCollisions::iterator const& collision, aod::BCsWithTimestamps const&, - std::vector vecPvContributorGlobId, - std::vector vecPvContributorTrackParCov, - std::vector vecCandPvContributorGlobId, + std::vector const& vecPvContributorGlobId, + std::vector const& vecPvContributorTrackParCov, + std::vector const& vecCandPvContributorGlobId, std::array& pvCoord, std::array& pvCovMatrix) { @@ -1886,7 +1956,7 @@ struct HfTrackIndexSkimCreator { /// Prepare the vertex refitting // set the magnetic field from CCDB - auto bc = collision.bc_as(); + const auto bc = collision.bc_as(); initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); // build the VertexBase to initialize the vertexer @@ -1899,10 +1969,10 @@ struct HfTrackIndexSkimCreator { o2::vertexing::PVertexer vertexer; o2::conf::ConfigurableParam::updateFromString("pvertexer.useMeanVertexConstraint=false"); /// remove diamond constraint (let's keep it at the moment...) vertexer.init(); - bool pvRefitDoable = vertexer.prepareVertexRefit(vecPvContributorTrackParCov, primVtx); + const bool pvRefitDoable = vertexer.prepareVertexRefit(vecPvContributorTrackParCov, primVtx); if (!pvRefitDoable) { LOG(info) << "Not enough tracks accepted for the refit"; - if (doprocess2And3ProngsWithPvRefit && config.fillHistograms) { + if ((doprocess2And3ProngsWithPvRefit || doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt) && config.fillHistograms) { registry.fill(HIST("PvRefit/hNContribPvRefitNotDoable"), collision.numContrib()); } } @@ -1912,14 +1982,13 @@ struct HfTrackIndexSkimCreator { /// PV refitting, if the tracks contributed to this at the beginning o2::dataformats::VertexBase primVtxBaseRecalc; - bool recalcPvRefit = false; - if (doprocess2And3ProngsWithPvRefit && pvRefitDoable) { + if ((doprocess2And3ProngsWithPvRefit || doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt) && pvRefitDoable) { if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 2); } - recalcPvRefit = true; + bool recalcPvRefit = true; int nCandContr = 0; - for (uint64_t myGlobalID : vecCandPvContributorGlobId) { + for (const 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 @@ -1955,10 +2024,6 @@ struct HfTrackIndexSkimCreator { registry.fill(HIST("PvRefit/hChi2vsNContrib"), primVtxRefitted.getNContributors(), primVtxRefitted.getChi2()); } - for (size_t i = 0; i < vecPvContributorGlobId.size(); i++) { - vecPvRefitContributorUsed[i] = true; /// restore the tracks for the next PV refitting (probably not necessary here) - } - if (recalcPvRefit) { // fill the histograms for refitted PV with good Chi2 const double deltaX = primVtx.getX() - primVtxRefitted.getX(); @@ -1999,10 +2064,9 @@ struct HfTrackIndexSkimCreator { } /// end 'if (doprocess2And3ProngsWithPvRefit && pvRefitDoable)' - return; } /// end of performPvRefitCandProngs function - template + template void run2And3Prongs(SelectedCollisions const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, FilteredTrackAssocSel const&, @@ -2026,7 +2090,7 @@ struct HfTrackIndexSkimCreator { std::vector vecPvContributorGlobId{}; std::vector vecPvContributorTrackParCov{}; std::vector vecPvRefitContributorUsed{}; - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { auto groupedTracksUnfiltered = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); const int nTrk = groupedTracksUnfiltered.size(); int nContrib = 0; @@ -2036,19 +2100,18 @@ struct HfTrackIndexSkimCreator { /// the track did not contribute to fit the primary vertex nNonContrib++; continue; - } else { - vecPvContributorGlobId.push_back(trackUnfiltered.globalIndex()); - vecPvContributorTrackParCov.push_back(getTrackParCov(trackUnfiltered)); - nContrib++; - if (config.debugPvRefit) { - LOG(info) << "---> a contributor! stuff saved"; - LOG(info) << "vec_contrib size: " << vecPvContributorTrackParCov.size() << ", nContrib: " << nContrib; - } + } + vecPvContributorGlobId.push_back(trackUnfiltered.globalIndex()); + vecPvContributorTrackParCov.push_back(getTrackParCov(trackUnfiltered)); + nContrib++; + if (config.debugPvRefit) { + LOG(info) << "---> a contributor! stuff saved"; + LOG(info) << "vec_contrib size: " << vecPvContributorTrackParCov.size() << ", nContrib: " << nContrib; } } 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(); } } @@ -2057,13 +2120,13 @@ struct HfTrackIndexSkimCreator { // auto centrality = collision.centV0M(); //FIXME add centrality when option for variations to the process function appears - int n2ProngBit = BIT(kN2ProngDecays) - 1; // bit value for 2-prong candidates where each candidate is one bit and they are all set to 1 - int n3ProngBit = BIT(kN3ProngDecays) - 1; // bit value for 3-prong candidates where each candidate is one bit and they are all set to 1 + const auto n2ProngBit = BIT(kN2ProngDecays) - 1; // bit value for 2-prong candidates where each candidate is one bit and they are all set to 1 + const auto n3ProngBit = BIT(kN3ProngDecays) - 1; // bit value for 3-prong candidates where each candidate is one bit and they are all set to 1 - std::array, kN2ProngDecays> cutStatus2Prong; - std::array, kN3ProngDecays> cutStatus3Prong; - bool nCutStatus2ProngBit[kN2ProngDecays]; // bit value for selection status for each 2-prong candidate where each selection is one bit and they are all set to 1 - bool nCutStatus3ProngBit[kN3ProngDecays]; // bit value for selection status for each 3-prong candidate where each selection is one bit and they are all set to 1 + std::array, kN2ProngDecays> cutStatus2Prong{}; + std::array, kN3ProngDecays> cutStatus3Prong{}; + uint8_t nCutStatus2ProngBit[kN2ProngDecays]; // bit value for selection status for each 2-prong candidate where each selection is one bit and they are all set to 1 + uint8_t nCutStatus3ProngBit[kN3ProngDecays]; // bit value for selection status for each 3-prong candidate where each selection is one bit and they are all set to 1 for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { nCutStatus2ProngBit[iDecay2P] = BIT(kNCuts2Prong[iDecay2P]) - 1; @@ -2078,7 +2141,7 @@ struct HfTrackIndexSkimCreator { int whichHypo3Prong[kN3ProngDecays]; // set the magnetic field from CCDB - auto bc = collision.bc_as(); + const auto bc = collision.bc_as(); 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()); @@ -2092,46 +2155,46 @@ struct HfTrackIndexSkimCreator { // return; //} - auto thisCollId = collision.globalIndex(); + const auto thisCollId = collision.globalIndex(); // first loop over positive tracks - auto groupedTrackIndicesPos1 = positiveFor2And3Prongs->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + const auto groupedTrackIndicesPos1 = positiveFor2And3Prongs->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); int lastFilledD0 = -1; // index to be filled in table for D* mesons for (auto trackIndexPos1 = groupedTrackIndicesPos1.begin(); trackIndexPos1 != groupedTrackIndicesPos1.end(); ++trackIndexPos1) { - auto trackPos1 = trackIndexPos1.template track_as(); + const auto trackPos1 = trackIndexPos1.template track_as(); // retrieve the selection flag that corresponds to this collision - auto isSelProngPos1 = trackIndexPos1.isSelProng(); - bool sel2ProngStatusPos = TESTBIT(isSelProngPos1, CandidateType::Cand2Prong); - bool sel3ProngStatusPos1 = TESTBIT(isSelProngPos1, CandidateType::Cand3Prong); + const auto isSelProngPos1 = trackIndexPos1.isSelProng(); + const bool sel2ProngStatusPos = TESTBIT(isSelProngPos1, CandidateType::Cand2Prong); + const bool sel3ProngStatusPos1 = TESTBIT(isSelProngPos1, CandidateType::Cand3Prong); auto trackParVarPos1 = getTrackParCov(trackPos1); - std::array pVecTrackPos1{trackPos1.pVector()}; - o2::gpu::gpustd::array dcaInfoPos1{trackPos1.dcaXY(), trackPos1.dcaZ()}; + std::array pVecTrackPos1{trackPos1.pVector()}; + std::array dcaInfoPos1{trackPos1.dcaXY(), trackPos1.dcaZ()}; if (thisCollId != trackPos1.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarPos1, 2.f, noMatCorr, &dcaInfoPos1); getPxPyPz(trackParVarPos1, pVecTrackPos1); } // first loop over negative tracks - auto groupedTrackIndicesNeg1 = negativeFor2And3Prongs->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + const auto groupedTrackIndicesNeg1 = negativeFor2And3Prongs->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (auto trackIndexNeg1 = groupedTrackIndicesNeg1.begin(); trackIndexNeg1 != groupedTrackIndicesNeg1.end(); ++trackIndexNeg1) { - auto trackNeg1 = trackIndexNeg1.template track_as(); + const auto trackNeg1 = trackIndexNeg1.template track_as(); // retrieve the selection flag that corresponds to this collision - auto isSelProngNeg1 = trackIndexNeg1.isSelProng(); - bool sel2ProngStatusNeg = TESTBIT(isSelProngNeg1, CandidateType::Cand2Prong); - bool sel3ProngStatusNeg1 = TESTBIT(isSelProngNeg1, CandidateType::Cand3Prong); + const auto isSelProngNeg1 = trackIndexNeg1.isSelProng(); + const bool sel2ProngStatusNeg = TESTBIT(isSelProngNeg1, CandidateType::Cand2Prong); + const bool sel3ProngStatusNeg1 = TESTBIT(isSelProngNeg1, CandidateType::Cand3Prong); auto trackParVarNeg1 = getTrackParCov(trackNeg1); - std::array pVecTrackNeg1{trackNeg1.pVector()}; - o2::gpu::gpustd::array dcaInfoNeg1{trackNeg1.dcaXY(), trackNeg1.dcaZ()}; + std::array pVecTrackNeg1{trackNeg1.pVector()}; + std::array dcaInfoNeg1{trackNeg1.dcaXY(), trackNeg1.dcaZ()}; if (thisCollId != trackNeg1.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarNeg1, 2.f, noMatCorr, &dcaInfoNeg1); getPxPyPz(trackParVarNeg1, pVecTrackNeg1); } - int isSelected2ProngCand = n2ProngBit; // bitmap for checking status of two-prong candidates (1 is true, 0 is rejected) + uint isSelected2ProngCand = n2ProngBit; // bitmap for checking status of two-prong candidates (1 is true, 0 is rejected) if (config.debug) { for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { @@ -2142,8 +2205,8 @@ struct HfTrackIndexSkimCreator { } // initialise PV refit coordinates and cov matrix for 2-prongs already here for D* - std::array pvRefitCoord2Prong = {collision.posX(), collision.posY(), collision.posZ()}; /// initialize to the original PV - std::array pvRefitCovMatrix2Prong = getPrimaryVertex(collision).getCov(); /// initialize to the original PV + std::array pvRefitCoord2Prong = {collision.posX(), collision.posY(), collision.posZ()}; /// initialize to the original PV + std::array pvRefitCovMatrix2Prong = getPrimaryVertex(collision).getCov(); /// initialize to the original PV // 2-prong vertex reconstruction float pt2Prong{-1.}; @@ -2166,13 +2229,13 @@ struct HfTrackIndexSkimCreator { // get secondary vertex const auto& secondaryVertex2 = df2.getPCACandidate(); // get track momenta - std::array pvec0; - std::array pvec1; + std::array pvec0{}; + std::array pvec1{}; df2.getTrack(0).getPxPyPzGlo(pvec0); df2.getTrack(1).getPxPyPzGlo(pvec1); /// PV refit excluding the candidate daughters, if contributors - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { if (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 1); } @@ -2197,7 +2260,7 @@ struct HfTrackIndexSkimCreator { nCandContr--; isTrackSecondContr = false; } - if (nCandContr == 2) { + if (nCandContr == 2) { // o2-linter: disable="magic-number" (see comment below) /// Both the daughter tracks were used for the original PV refit, let's refit it after excluding them if (config.debugPvRefit) { LOG(info) << "### [2 Prong] Calling performPvRefitCandProngs for HF 2 prong candidate"; @@ -2231,24 +2294,24 @@ struct HfTrackIndexSkimCreator { } } - auto pVecCandProng2 = RecoDecay::pVec(pvec0, pvec1); + const auto pVecCandProng2 = RecoDecay::pVec(pvec0, pvec1); // 2-prong selections after secondary vertex - std::array pvCoord2Prong = {collision.posX(), collision.posY(), collision.posZ()}; - if constexpr (doPvRefit) { + std::array pvCoord2Prong = {collision.posX(), collision.posY(), collision.posZ()}; + if constexpr (DoPvRefit) { pvCoord2Prong[0] = pvRefitCoord2Prong[0]; pvCoord2Prong[1] = pvRefitCoord2Prong[1]; pvCoord2Prong[2] = pvRefitCoord2Prong[2]; } - applySelections2Prong(pVecCandProng2, secondaryVertex2, pvCoord2Prong, cutStatus2Prong, isSelected2ProngCand); - if (is2ProngCandidateGoodFor3Prong && config.do3Prong == 1) { + applySelection2Prong(pVecCandProng2, secondaryVertex2, pvCoord2Prong, cutStatus2Prong, isSelected2ProngCand); + if (is2ProngCandidateGoodFor3Prong && config.do3Prong) { is2ProngCandidateGoodFor3Prong = isTwoTrackVertexSelectedFor3Prongs(secondaryVertex2, pvCoord2Prong, df2); } std::vector mlScoresD0{}; 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]}; + const auto trackParVarPcaPos1 = df2.getTrack(0); + const auto trackParVarPcaNeg1 = df2.getTrack(1); + const std::vector inputFeatures{trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1]}; applyMlSelectionForHfFilters2Prong(inputFeatures, mlScoresD0, isSelected2ProngCand); } @@ -2262,23 +2325,23 @@ struct HfTrackIndexSkimCreator { lastFilledD0 = rowTrackIndexProng2.lastIndex(); } - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { // fill table row with coordinates of PV refit rowProng2PVrefit(pvRefitCoord2Prong[0], pvRefitCoord2Prong[1], pvRefitCoord2Prong[2], pvRefitCovMatrix2Prong[0], pvRefitCovMatrix2Prong[1], pvRefitCovMatrix2Prong[2], pvRefitCovMatrix2Prong[3], pvRefitCovMatrix2Prong[4], pvRefitCovMatrix2Prong[5]); } if (config.debug) { - int Prong2CutStatus[kN2ProngDecays]; + uint8_t 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 @@ -2286,11 +2349,11 @@ struct HfTrackIndexSkimCreator { registry.fill(HIST("hVtx2ProngX"), secondaryVertex2[0]); registry.fill(HIST("hVtx2ProngY"), secondaryVertex2[1]); registry.fill(HIST("hVtx2ProngZ"), secondaryVertex2[2]); - std::array, 2> arrMom = {pvec0, pvec1}; + const std::array arrMom{pvec0, pvec1}; for (int iDecay2P = 0; iDecay2P < kN2ProngDecays; iDecay2P++) { if (TESTBIT(isSelected2ProngCand, iDecay2P)) { if (TESTBIT(whichHypo2Prong[iDecay2P], 0)) { - auto mass2Prong = RecoDecay::m(arrMom, arrMass2Prong[iDecay2P][0]); + const auto mass2Prong = RecoDecay::m(arrMom, arrMass2Prong[iDecay2P][0]); switch (iDecay2P) { case hf_cand_2prong::DecayType::D0ToPiK: registry.fill(HIST("hMassD0ToPiK"), mass2Prong); @@ -2304,7 +2367,7 @@ struct HfTrackIndexSkimCreator { } } if (TESTBIT(whichHypo2Prong[iDecay2P], 1)) { - auto mass2Prong = RecoDecay::m(arrMom, arrMass2Prong[iDecay2P][1]); + const auto mass2Prong = RecoDecay::m(arrMom, arrMass2Prong[iDecay2P][1]); if (iDecay2P == hf_cand_2prong::DecayType::D0ToPiK) { registry.fill(HIST("hMassD0ToPiK"), mass2Prong); } @@ -2322,48 +2385,46 @@ 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 (config.do3Prong == 1 && is2ProngCandidateGoodFor3Prong && (config.minTwoTrackDecayLengthFor3Prongs > 0.f || config.maxTwoTrackChi2PcaFor3Prongs < 1.e9f) && nVtxFrom2ProngFitter == 0) { + if (config.do3Prong && is2ProngCandidateGoodFor3Prong && (config.minTwoTrackDecayLengthFor3Prongs > 0.f || config.maxTwoTrackChi2PcaFor3Prongs < 1.e9f) && nVtxFrom2ProngFitter == 0) { // o2-linter: disable="magic-number" (default maxTwoTrackChi2PcaFor3Prongs is 1.e10) try { nVtxFrom2ProngFitter = df2.process(trackParVarPos1, trackParVarNeg1); } catch (...) { } if (nVtxFrom2ProngFitter > 0) { const auto& secondaryVertex2 = df2.getPCACandidate(); - std::array pvCoord2Prong = {collision.posX(), collision.posY(), collision.posZ()}; + const std::array pvCoord2Prong{collision.posX(), collision.posY(), collision.posZ()}; is2ProngCandidateGoodFor3Prong = isTwoTrackVertexSelectedFor3Prongs(secondaryVertex2, pvCoord2Prong, df2); } else { is2ProngCandidateGoodFor3Prong = false; } } - if (config.do3Prong == 1 && is2ProngCandidateGoodFor3Prong) { // if 3 prongs are enabled and the first 2 tracks are selected for the 3-prong channels + if (config.do3Prong && 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; + uint isSelected3ProngCand = n3ProngBit; if (!TESTBIT(trackIndexPos2.isSelProng(), CandidateType::Cand3Prong)) { // continue immediately if (!config.debug) { continue; - } else { - isSelected3ProngCand = 0; } + isSelected3ProngCand = 0; } - if (config.applyKaonPidIn3Prongs && !TESTBIT(trackIndexNeg1.isIdentifiedPid(), channelKaonPid)) { // continue immediately if kaon PID enabled and opposite-sign track not a kaon + 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; } + isSelected3ProngCand = 0; } - auto trackPos2 = trackIndexPos2.template track_as(); + const auto trackPos2 = trackIndexPos2.template track_as(); auto trackParVarPos2 = getTrackParCov(trackPos2); - o2::gpu::gpustd::array dcaInfoPos2{trackPos2.dcaXY(), trackPos2.dcaZ()}; + std::array dcaInfoPos2{trackPos2.dcaXY(), trackPos2.dcaZ()}; // preselection of 3-prong candidates if (isSelected3ProngCand) { - std::array pVecTrackPos2{trackPos2.pVector()}; + std::array pVecTrackPos2{trackPos2.pVector()}; if (thisCollId != trackPos2.collisionId()) { // this is not the "default" collision for this track and we still did not re-propagate it, we have to re-propagate it o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarPos2, 2.f, noMatCorr, &dcaInfoPos2); getPxPyPz(trackParVarPos2, pVecTrackPos2); @@ -2378,8 +2439,8 @@ struct HfTrackIndexSkimCreator { } // 3-prong preselections - int8_t isIdentifiedPidTrackPos1 = trackIndexPos1.isIdentifiedPid(); - int8_t isIdentifiedPidTrackPos2 = trackIndexPos2.isIdentifiedPid(); + const auto isIdentifiedPidTrackPos1 = trackIndexPos1.isIdentifiedPid(); + const auto isIdentifiedPidTrackPos2 = trackIndexPos2.isIdentifiedPid(); applyPreselection3Prong(pVecTrackPos1, pVecTrackNeg1, pVecTrackPos2, isIdentifiedPidTrackPos1, isIdentifiedPidTrackPos2, cutStatus3Prong, whichHypo3Prong, isSelected3ProngCand); if (!config.debug && isSelected3ProngCand == 0) { continue; @@ -2387,9 +2448,9 @@ struct HfTrackIndexSkimCreator { } /// PV refit excluding the candidate daughters, if contributors - 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) { + 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 (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 1); } @@ -2437,7 +2498,7 @@ struct HfTrackIndexSkimCreator { vecCandPvContributorGlobId.push_back(trackPos2.globalIndex()); } - if (nCandContr == 3 || nCandContr == 2) { + if (nCandContr == 3 || nCandContr == 2) { // o2-linter: disable="magic-number" (see comment below) /// At least two of the daughter tracks were used for the original PV refit, let's refit it after excluding them if (config.debugPvRefit) { LOG(info) << "### [3 prong] Calling performPvRefitCandProngs for HF 3 prong candidate, removing " << nCandContr << " daughters"; @@ -2489,24 +2550,32 @@ struct HfTrackIndexSkimCreator { // get secondary vertex const auto& secondaryVertex3 = df3.getPCACandidate(); // get track momenta - std::array pvec0; - std::array pvec1; - std::array pvec2; - auto trackParVarPcaPos1 = df3.getTrack(0); - auto trackParVarPcaNeg1 = df3.getTrack(1); - auto trackParVarPcaPos2 = df3.getTrack(2); + std::array pvec0{}; + std::array pvec1{}; + std::array pvec2{}; + const auto trackParVarPcaPos1 = df3.getTrack(0); + const auto trackParVarPcaNeg1 = df3.getTrack(1); + const auto trackParVarPcaPos2 = df3.getTrack(2); trackParVarPcaPos1.getPxPyPzGlo(pvec0); trackParVarPcaNeg1.getPxPyPzGlo(pvec1); trackParVarPcaPos2.getPxPyPzGlo(pvec2); - auto pVecCandProng3Pos = RecoDecay::pVec(pvec0, pvec1, pvec2); + const auto pVecCandProng3Pos = RecoDecay::pVec(pvec0, pvec1, pvec2); // 3-prong selections after secondary vertex applySelection3Prong(pVecCandProng3Pos, secondaryVertex3, pvRefitCoord3Prong2Pos1Neg, cutStatus3Prong, isSelected3ProngCand); - std::array, kN3ProngDecays> mlScores3Prongs; + std::array, kN3ProngDecays - 1> mlScores3Prongs; 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); + const std::vector inputFeatures{trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1], trackParVarPcaPos2.getPt(), dcaInfoPos2[0], dcaInfoPos2[1]}; + 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 (!config.debug && isSelected3ProngCand == 0) { @@ -2518,23 +2587,23 @@ struct HfTrackIndexSkimCreator { if (config.applyMlForHfFilters) { rowTrackIndexMlScoreProng3(mlScores3Prongs[0], mlScores3Prongs[1], mlScores3Prongs[2], mlScores3Prongs[3]); } - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { // fill table row of coordinates of PV refit rowProng3PVrefit(pvRefitCoord3Prong2Pos1Neg[0], pvRefitCoord3Prong2Pos1Neg[1], pvRefitCoord3Prong2Pos1Neg[2], pvRefitCovMatrix3Prong2Pos1Neg[0], pvRefitCovMatrix3Prong2Pos1Neg[1], pvRefitCovMatrix3Prong2Pos1Neg[2], pvRefitCovMatrix3Prong2Pos1Neg[3], pvRefitCovMatrix3Prong2Pos1Neg[4], pvRefitCovMatrix3Prong2Pos1Neg[5]); } if (config.debug) { - int Prong3CutStatus[kN3ProngDecays]; + uint8_t 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 @@ -2542,11 +2611,11 @@ struct HfTrackIndexSkimCreator { registry.fill(HIST("hVtx3ProngX"), secondaryVertex3[0]); registry.fill(HIST("hVtx3ProngY"), secondaryVertex3[1]); registry.fill(HIST("hVtx3ProngZ"), secondaryVertex3[2]); - std::array, 3> arr3Mom = {pvec0, pvec1, pvec2}; + const std::array arr3Mom{pvec0, pvec1, pvec2}; for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { if (TESTBIT(isSelected3ProngCand, iDecay3P)) { if (TESTBIT(whichHypo3Prong[iDecay3P], 0)) { - auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iDecay3P][0]); + const auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iDecay3P][0]); switch (iDecay3P) { case hf_cand_3prong::DecayType::DplusToPiKPi: registry.fill(HIST("hMassDPlusToPiKPi"), mass3Prong); @@ -2560,10 +2629,13 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::XicToPKPi: registry.fill(HIST("hMassXicToPKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CdToDeKPi: + registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); + break; } } if (TESTBIT(whichHypo3Prong[iDecay3P], 1)) { - auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iDecay3P][1]); + const auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iDecay3P][1]); switch (iDecay3P) { case hf_cand_3prong::DecayType::DsToKKPi: registry.fill(HIST("hMassDsToKKPi"), mass3Prong); @@ -2574,6 +2646,9 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::XicToPKPi: registry.fill(HIST("hMassXicToPKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CdToDeKPi: + registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); + break; } } } @@ -2588,26 +2663,24 @@ struct HfTrackIndexSkimCreator { if (!TESTBIT(trackIndexNeg2.isSelProng(), CandidateType::Cand3Prong)) { // continue immediately if (!config.debug) { continue; - } else { - isSelected3ProngCand = 0; } + isSelected3ProngCand = 0; } - if (config.applyKaonPidIn3Prongs && !TESTBIT(trackIndexPos1.isIdentifiedPid(), channelKaonPid)) { // continue immediately if kaon PID enabled and opposite-sign track not a kaon + 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; } + isSelected3ProngCand = 0; } auto trackNeg2 = trackIndexNeg2.template track_as(); auto trackParVarNeg2 = getTrackParCov(trackNeg2); - o2::gpu::gpustd::array dcaInfoNeg2{trackNeg2.dcaXY(), trackNeg2.dcaZ()}; + std::array dcaInfoNeg2{trackNeg2.dcaXY(), trackNeg2.dcaZ()}; // preselection of 3-prong candidates if (isSelected3ProngCand) { - std::array pVecTrackNeg2{trackNeg2.pVector()}; + std::array pVecTrackNeg2{trackNeg2.pVector()}; if (thisCollId != trackNeg2.collisionId()) { // this is not the "default" collision for this track and we still did not re-propagate it, we have to re-propagate it o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarNeg2, 2.f, noMatCorr, &dcaInfoNeg2); getPxPyPz(trackParVarNeg2, pVecTrackNeg2); @@ -2622,8 +2695,8 @@ struct HfTrackIndexSkimCreator { } // 3-prong preselections - int8_t isIdentifiedPidTrackNeg1 = trackIndexNeg1.isIdentifiedPid(); - int8_t isIdentifiedPidTrackNeg2 = trackIndexNeg2.isIdentifiedPid(); + int8_t const isIdentifiedPidTrackNeg1 = trackIndexNeg1.isIdentifiedPid(); + int8_t const isIdentifiedPidTrackNeg2 = trackIndexNeg2.isIdentifiedPid(); applyPreselection3Prong(pVecTrackNeg1, pVecTrackPos1, pVecTrackNeg2, isIdentifiedPidTrackNeg1, isIdentifiedPidTrackNeg2, cutStatus3Prong, whichHypo3Prong, isSelected3ProngCand); if (!config.debug && isSelected3ProngCand == 0) { continue; @@ -2631,9 +2704,9 @@ struct HfTrackIndexSkimCreator { } /// PV refit excluding the candidate daughters, if contributors - 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) { + 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 (config.fillHistograms) { registry.fill(HIST("PvRefit/verticesPerCandidate"), 1); } @@ -2681,7 +2754,7 @@ struct HfTrackIndexSkimCreator { vecCandPvContributorGlobId.push_back(trackNeg2.globalIndex()); } - if (nCandContr == 3 || nCandContr == 2) { + if (nCandContr == 3 || nCandContr == 2) { // o2-linter: disable="magic-number" (see comment below) /// At least two of the daughter tracks were used for the original PV refit, let's refit it after excluding them if (config.debugPvRefit) { LOG(info) << "### [3 prong] Calling performPvRefitCandProngs for HF 3 prong candidate, removing " << nCandContr << " daughters"; @@ -2733,25 +2806,33 @@ struct HfTrackIndexSkimCreator { // get secondary vertex const auto& secondaryVertex3 = df3.getPCACandidate(); // get track momenta - std::array pvec0; - std::array pvec1; - std::array pvec2; - auto trackParVarPcaNeg1 = df3.getTrack(0); - auto trackParVarPcaPos1 = df3.getTrack(1); - auto trackParVarPcaNeg2 = df3.getTrack(2); + std::array pvec0{}; + std::array pvec1{}; + std::array pvec2{}; + const auto trackParVarPcaNeg1 = df3.getTrack(0); + const auto trackParVarPcaPos1 = df3.getTrack(1); + const auto trackParVarPcaNeg2 = df3.getTrack(2); trackParVarPcaNeg1.getPxPyPzGlo(pvec0); trackParVarPcaPos1.getPxPyPzGlo(pvec1); trackParVarPcaNeg2.getPxPyPzGlo(pvec2); - auto pVecCandProng3Neg = RecoDecay::pVec(pvec0, pvec1, pvec2); + const auto pVecCandProng3Neg = RecoDecay::pVec(pvec0, pvec1, pvec2); // 3-prong selections after secondary vertex applySelection3Prong(pVecCandProng3Neg, secondaryVertex3, pvRefitCoord3Prong1Pos2Neg, cutStatus3Prong, isSelected3ProngCand); - std::array, kN3ProngDecays> mlScores3Prongs; + std::array, kN3ProngDecays - 1> mlScores3Prongs{}; 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); + const std::vector inputFeatures{trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1], trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg2.getPt(), dcaInfoNeg2[0], dcaInfoNeg2[1]}; + 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 (!config.debug && isSelected3ProngCand == 0) { @@ -2763,23 +2844,23 @@ struct HfTrackIndexSkimCreator { if (config.applyMlForHfFilters) { rowTrackIndexMlScoreProng3(mlScores3Prongs[0], mlScores3Prongs[1], mlScores3Prongs[2], mlScores3Prongs[3]); } - // fill table row of coordinates of PV refit - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { + // fill table row of coordinates of PV refit rowProng3PVrefit(pvRefitCoord3Prong1Pos2Neg[0], pvRefitCoord3Prong1Pos2Neg[1], pvRefitCoord3Prong1Pos2Neg[2], pvRefitCovMatrix3Prong1Pos2Neg[0], pvRefitCovMatrix3Prong1Pos2Neg[1], pvRefitCovMatrix3Prong1Pos2Neg[2], pvRefitCovMatrix3Prong1Pos2Neg[3], pvRefitCovMatrix3Prong1Pos2Neg[4], pvRefitCovMatrix3Prong1Pos2Neg[5]); } if (config.debug) { - int Prong3CutStatus[kN3ProngDecays]; + 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 @@ -2787,11 +2868,11 @@ struct HfTrackIndexSkimCreator { registry.fill(HIST("hVtx3ProngX"), secondaryVertex3[0]); registry.fill(HIST("hVtx3ProngY"), secondaryVertex3[1]); registry.fill(HIST("hVtx3ProngZ"), secondaryVertex3[2]); - std::array, 3> arr3Mom = {pvec0, pvec1, pvec2}; + const std::array arr3Mom{pvec0, pvec1, pvec2}; for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { if (TESTBIT(isSelected3ProngCand, iDecay3P)) { if (TESTBIT(whichHypo3Prong[iDecay3P], 0)) { - auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iDecay3P][0]); + const auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iDecay3P][0]); switch (iDecay3P) { case hf_cand_3prong::DecayType::DplusToPiKPi: registry.fill(HIST("hMassDPlusToPiKPi"), mass3Prong); @@ -2805,10 +2886,13 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::XicToPKPi: registry.fill(HIST("hMassXicToPKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CdToDeKPi: + registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); + break; } } if (TESTBIT(whichHypo3Prong[iDecay3P], 1)) { - auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iDecay3P][1]); + const auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iDecay3P][1]); switch (iDecay3P) { case hf_cand_3prong::DecayType::DsToKKPi: registry.fill(HIST("hMassDsToKKPi"), mass3Prong); @@ -2819,6 +2903,9 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::XicToPKPi: registry.fill(HIST("hMassXicToPKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CdToDeKPi: + registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); + break; } } } @@ -2827,19 +2914,20 @@ struct HfTrackIndexSkimCreator { } } - 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) + if (config.doDstar && TESTBIT(isSelected2ProngCand, hf_cand_2prong::DecayType::D0ToPiK) && (pt2Prong + config.ptTolerance) * 1.2 > config.binsPtDstarToD0Pi->at(0) && whichHypo2Prong[kN2ProngDecays] != 0) { // o2-linter: disable="magic-number" (see comment below) + // 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) && (!config.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) { continue; } auto trackPos2 = trackIndexPos2.template track_as(); - std::array pVecTrackPos2{trackPos2.pVector()}; + std::array pVecTrackPos2{trackPos2.pVector()}; if (thisCollId != trackPos2.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it auto trackParVarPos2 = getTrackParCov(trackPos2); - o2::gpu::gpustd::array dcaInfoPos2{trackPos2.dcaXY(), trackPos2.dcaZ()}; + std::array dcaInfoPos2{trackPos2.dcaXY(), trackPos2.dcaZ()}; o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarPos2, 2.f, noMatCorr, &dcaInfoPos2); getPxPyPz(trackParVarPos2, pVecTrackPos2); } @@ -2853,7 +2941,7 @@ struct HfTrackIndexSkimCreator { if (config.fillHistograms) { registry.fill(HIST("hMassDstarToD0Pi"), deltaMass); } - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { // fill table row with coordinates of PV refit (same as 2-prong because we do not remove the soft pion) rowDstarPVrefit(pvRefitCoord2Prong[0], pvRefitCoord2Prong[1], pvRefitCoord2Prong[2], pvRefitCovMatrix2Prong[0], pvRefitCovMatrix2Prong[1], pvRefitCovMatrix2Prong[2], pvRefitCovMatrix2Prong[3], pvRefitCovMatrix2Prong[4], pvRefitCovMatrix2Prong[5]); @@ -2866,17 +2954,17 @@ struct HfTrackIndexSkimCreator { } // second loop over negative tracks - 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 + 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) { continue; } auto trackNeg2 = trackIndexNeg2.template track_as(); - std::array pVecTrackNeg2{trackNeg2.pVector()}; + std::array pVecTrackNeg2{trackNeg2.pVector()}; if (thisCollId != trackNeg2.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it auto trackParVarNeg2 = getTrackParCov(trackNeg2); - o2::gpu::gpustd::array dcaInfoNeg2{trackNeg2.dcaXY(), trackNeg2.dcaZ()}; + std::array dcaInfoNeg2{trackNeg2.dcaXY(), trackNeg2.dcaZ()}; o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarNeg2, 2.f, noMatCorr, &dcaInfoNeg2); getPxPyPz(trackParVarNeg2, pVecTrackNeg2); } @@ -2890,7 +2978,7 @@ struct HfTrackIndexSkimCreator { if (config.fillHistograms) { registry.fill(HIST("hMassDstarToD0Pi"), deltaMass); } - if constexpr (doPvRefit) { + if constexpr (DoPvRefit) { // fill table row with coordinates of PV refit (same as 2-prong because we do not remove the soft pion) rowDstarPVrefit(pvRefitCoord2Prong[0], pvRefitCoord2Prong[1], pvRefitCoord2Prong[2], pvRefitCovMatrix2Prong[0], pvRefitCovMatrix2Prong[1], pvRefitCovMatrix2Prong[2], pvRefitCovMatrix2Prong[3], pvRefitCovMatrix2Prong[4], pvRefitCovMatrix2Prong[5]); @@ -2905,7 +2993,7 @@ struct HfTrackIndexSkimCreator { } } - int nTracks = 0; + const int nTracks = 0; // auto nTracks = trackIndicesPerCollision.lastIndex() - trackIndicesPerCollision.firstIndex(); // number of tracks passing 2 and 3 prong selection in this collision nCand2 = rowTrackIndexProng2.lastIndex() - nCand2; // number of 2-prong candidates in this collision nCand3 = rowTrackIndexProng3.lastIndex() - nCand3; // number of 3-prong candidates in this collision @@ -2932,7 +3020,7 @@ struct HfTrackIndexSkimCreator { FilteredTrackAssocSel const& trackIndices, TracksWithPVRefitAndDCA const& tracks) { - run2And3Prongs(collisions, bcWithTimeStamps, trackIndices, tracks); + run2And3Prongs(collisions, bcWithTimeStamps, trackIndices, tracks); } PROCESS_SWITCH(HfTrackIndexSkimCreator, process2And3ProngsWithPvRefit, "Process 2-prong and 3-prong skim with PV refit", false); @@ -2942,9 +3030,29 @@ struct HfTrackIndexSkimCreator { FilteredTrackAssocSel const& trackIndices, aod::TracksWCovDcaExtra const& tracks) { - run2And3Prongs(collisions, bcWithTimeStamps, trackIndices, tracks); + 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); }; //________________________________________________________________________________________________________________________ @@ -2960,12 +3068,11 @@ struct HfTrackIndexSkimCreatorCascades { Produces rowTrackIndexCasc; struct : ConfigurableGroup { + double etaMinDefault{-99999.}; 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 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"}; @@ -2973,24 +3080,12 @@ struct HfTrackIndexSkimCreatorCascades { 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 etaMinV0Daugh{"etaMinV0Daugh", std::forward(etaMinDefault), "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 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 @@ -3009,20 +3104,16 @@ struct HfTrackIndexSkimCreatorCascades { o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter // Needed for PV refitting Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - int runNumber; - - double massP{0.}; - double massK0s{0.}; - double massPi{0.}; - double massLc{0.}; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + int runNumber{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 && (config.applyProtonPid == false || (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsProtonPid::LcToPK0S))) != 0u); + Filter filterSelectCollisions = (aod::hf_sel_collision::whyRejectColl == static_cast(0)); + Filter filterSelectTrackIds = (aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::CandV0bachelor))) != 0u && (!config.applyProtonPid || (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsProtonPid::LcToPK0S))) != 0u); Preslice trackIndicesPerCollision = aod::track_association::collisionId; Preslice v0sPerCollision = aod::v0data::collisionId; @@ -3036,29 +3127,24 @@ struct HfTrackIndexSkimCreatorCascades { return; } - if (config.etaMinV0Daugh == -99999.) { + if (config.etaMinV0Daugh == config.etaMinDefault) { 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(config.propagateToPCA); - df2.setMaxR(config.maxR); - df2.setMinParamChange(config.minParamChange); - df2.setMinRelChi2Change(config.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(config.useAbsDCA); - df2.setWeightedFinalPCA(config.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(config.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(config.ccdbPathLut)); - runNumber = 0; if (config.fillHistograms) { registry.add("hVtx2ProngX", "2-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); @@ -3075,81 +3161,66 @@ 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&) { // set the magnetic field from CCDB for (const auto& collision : collisions) { - auto bc = collision.bc_as(); + const auto bc = collision.bc_as(); initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); - df2.setBz(o2::base::Propagator::Instance()->getNominalBz()); - - // fist we loop over the bachelor candidate + if (config.useDCAFitter) { + df2.setBz(o2::base::Propagator::Instance()->getNominalBz()); + df2.setMatCorrType(matCorr); + } const auto thisCollId = collision.globalIndex(); - auto groupedBachTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + const auto groupedBachTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + const 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 (config.tpcRefitBach) { - if (!(bach.trackType() & o2::aod::track::TPCrefit)) { - continue; - } - } - if (bach.tpcNClsCrossedRows() < config.nCrossedRowsMinBach) { - continue; - } - + const auto bach = bachIdx.track_as(); + 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 + std::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 (config.tpcRefitV0Daugh) { - if (!(trackV0DaughPos.trackType() & o2::aod::track::TPCrefit) || - !(trackV0DaughNeg.trackType() & o2::aod::track::TPCrefit)) { - continue; - } - } - if (trackV0DaughPos.tpcNClsCrossedRows() < config.nCrossedRowsMinV0Daugh || - trackV0DaughNeg.tpcNClsCrossedRows() < config.nCrossedRowsMinV0Daugh) { - continue; - } - // - // if (trackV0DaughPos.dcaXY() < dcaXYPosToPvMin || // to the filters? - // trackV0DaughNeg.dcaXY() < dcaXYNegToPvMin) { - // continue; - // } - // - if (trackV0DaughPos.pt() < config.ptMinV0Daugh || // to the filters? I can't for now, it is not in the tables - trackV0DaughNeg.pt() < config.ptMinV0Daugh) { + const std::array pVecPos{v0.pxpos(), v0.pypos(), v0.pzpos()}; + const std::array pVecNeg{v0.pxneg(), v0.pyneg(), v0.pzneg()}; + + const float ptPos = RecoDecay::pt(pVecPos); + const 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() > config.etaMaxV0Daugh || trackV0DaughPos.eta() < config.etaMinV0Daugh) || // to the filters? I can't for now, it is not in the tables - (trackV0DaughNeg.eta() > config.etaMaxV0Daugh || trackV0DaughNeg.eta() < config.etaMinV0Daugh)) { + + const float etaPos = RecoDecay::eta(pVecPos); + const 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) > config.cutInvMassV0) { + if (std::abs(v0.mK0Short() - MassK0Short) > config.cutInvMassV0) { continue; // should go to the filter, but since it is a dynamic column, I cannot use it there } @@ -3158,55 +3229,61 @@ struct HfTrackIndexSkimCreatorCascades { 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 ((config.cutInvMassCascLc >= 0.) && (std::abs(mass2K0sP - massLc) > config.cutInvMassCascLc)) { + double mass2K0sP = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassProton, MassK0Short}); + if ((config.cutInvMassCascLc >= 0.) && (std::abs(mass2K0sP - MassLambdaCPlus) > 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{}; + constexpr std::size_t NIndicesMom{6u}; + constexpr std::size_t MomInd[NIndicesMom] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (std::size_t i = 0; i < NIndicesMom; 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); + const auto ptCascCand = RecoDecay::pt(pVecBach, pVecV0); 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]; + mass2K0sP = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassProton, MassK0Short}); + std::array posCasc{0., 0., 0.}; + if (config.useDCAFitter) { + const auto& cascVtx = df2.getPCACandidate(); + for (int iCoord{0}; iCoord < 3; ++iCoord) { // o2-linter: disable="magic-number" ({x, y, z} coordinates}) + posCasc[iCoord] = cascVtx[iCoord]; + } } // fill table row @@ -3235,6 +3312,7 @@ struct HfTrackIndexSkimCreatorLfCascades { Configurable do3Prong{"do3Prong", false, "do 3-prong cascade"}; Configurable rejDiffCollTrack{"rejDiffCollTrack", false, "Reject tracks coming from different collisions"}; + Configurable ptTolerance{"ptTolerance", 0.1, "pT tolerance in GeV/c for applying preselections before vertex reconstruction"}; // charm baryon invariant mass spectra limits Configurable massXiPiMin{"massXiPiMin", 2.1, "Invariant mass lower limit for xi pi decay channel"}; @@ -3259,19 +3337,25 @@ struct HfTrackIndexSkimCreatorLfCascades { // 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"}; + // 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.f, "V0 radius in xy plane"}; // 1.2 (xi) and 1.1 (omega) in run2 + Configurable cascTransvRadius{"cascTransvRadius", 0.4f, "Cascade radius in xy plane"}; // 0.5 cm (xi) and 0.6 (omega) in run2 + Configurable decayLengthXicMin{"decayLengthXicMin", -1.f, "Min. decay length of Xic"}; // ... + Configurable dcaBachToPv{"dcaBachToPv", 0.03f, "DCA Bach To PV"}; // 0.04 in run2 + Configurable dcaV0ToPv{"dcaV0ToPv", 0.02f, "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 xicCosPA{"xicCosPA", 0.95, "Xic CosPA"}; // ... + Configurable dcaV0Dau{"dcaV0Dau", 2.f, "DCA V0 Daughters"}; // conservative, a cut ar 1.0 should also be fine + Configurable dcaCascDau{"dcaCascDau", 2.f, "DCA Casc Daughters"}; // conservative, a cut ar 1.0 should also be fine + Configurable dcaNegToPv{"dcaNegToPv", 0.05f, "DCA Neg To PV"}; // 0.06 in run2 + Configurable dcaPosToPv{"dcaPosToPv", 0.05f, "DCA Pos To PV"}; // 0.06 in run2 + Configurable v0MassWindow{"v0MassWindow", 0.01f, "V0 mass window"}; // 0.008 in run2 + Configurable cascadeMassWindow{"cascadeMassWindow", 0.01f, "Cascade mass window"}; // magnetic field setting from CCDB Configurable isRun2{"isRun2", false, "enable Run 2 or Run 3 GRP objects for magnetic field"}; @@ -3282,32 +3366,23 @@ struct HfTrackIndexSkimCreatorLfCascades { } config; o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter - o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter Service ccdb; - o2::base::MatLayerCylSet* lut; + o2::base::MatLayerCylSet* lut{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - int runNumber; + int runNumber{}; // array of PDG masses of possible charm baryon daughters static constexpr int kN2ProngDecays = hf_cand_casc_lf::DecayType2Prong::N2ProngDecays; // number of 2-prong hadron types static constexpr int kN3ProngDecays = hf_cand_casc_lf::DecayType3Prong::N3ProngDecays; // number of 3-prong hadron types - std::array, kN2ProngDecays> arrMass2Prong; - std::array, kN3ProngDecays> arrMass3Prong; - - // PDG masses - double massP{0.}; - double massPi{0.}; - double massKaon{0.}; - double massXi{0.}; - double massOmega{0.}; - double massLambda{0.}; + std::array, kN2ProngDecays> arrMass2Prong{}; + std::array, kN3ProngDecays> arrMass3Prong{}; using SelectedCollisions = soa::Filtered>; using SelectedHfTrackAssoc = soa::Filtered>; using CascFull = soa::Join; using V0Full = soa::Join; - Filter filterSelectCollisions = (aod::hf_sel_collision::whyRejectColl == static_cast(0)); + Filter filterSelectCollisions = (aod::hf_sel_collision::whyRejectColl == static_cast(0)); Filter filterSelectTrackIds = (aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::CandCascadeBachelor))) != 0u; Preslice tracksPerCollision = aod::track::collisionId; // needed for PV refit @@ -3323,17 +3398,10 @@ struct HfTrackIndexSkimCreatorLfCascades { return; } - 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}; + arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi] = std::array{MassXiMinus, MassPiPlus}; + arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi] = std::array{MassOmegaMinus, MassPiPlus}; + arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK] = std::array{MassOmegaMinus, MassKPlus}; + arrMass3Prong[hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi] = std::array{MassXiMinus, MassPiPlus, MassPiPlus}; df2.setPropagateToPCA(config.propagateToPCA); df2.setMaxR(config.maxR); @@ -3343,14 +3411,6 @@ struct HfTrackIndexSkimCreatorLfCascades { 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(); @@ -3358,9 +3418,9 @@ struct HfTrackIndexSkimCreatorLfCascades { runNumber = 0; 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})"}; + const AxisSpec ptAxis = {400, 0.0f, 20.0f, "it{p}_{T} (GeV/c)"}; + const AxisSpec massAxisXi = {200, 1.222f, 1.422f, "Inv. Mass (GeV/c^{2})"}; + const AxisSpec massAxisOmega = {200, 1.572f, 1.772f, "Inv. Mass (GeV/c^{2})"}; registry.add("hCandidateCounter", "hCandidateCounter", {HistType::kTH1D, {{10, 0.0f, 10.0f}}}); @@ -3383,6 +3443,16 @@ struct HfTrackIndexSkimCreatorLfCascades { 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::kTH1D, {{500, 2., 3.}}}); registry.add("hMassOmegacZeroToOmegaPi", "2-prong candidates;inv. mass (#Omega #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 3.}}}); @@ -3398,7 +3468,7 @@ struct HfTrackIndexSkimCreatorLfCascades { /// Single-cascade cuts template - bool isPreselectedCascade(const TCascade& casc, const float& pvx, const float& pvy, const float& pvz) + bool isPreselectedCascade(const TCascade& casc, const float pvx, const float pvy, const float pvz) { registry.fill(HIST("hCandidateCounter"), 2.5); @@ -3412,7 +3482,7 @@ struct HfTrackIndexSkimCreatorLfCascades { std::abs(casc.dcav0topv(pvx, pvy, pvz)) > config.dcaV0ToPv && casc.v0radius() > config.v0TransvRadius && casc.cascradius() > config.cascTransvRadius && - std::abs(casc.mLambda() - massLambda) < config.v0MassWindow) { + std::abs(casc.mLambda() - MassLambda0) < config.v0MassWindow) { registry.fill(HIST("hCandidateCounter"), 3.5); // pass cascade selections @@ -3442,6 +3512,71 @@ struct HfTrackIndexSkimCreatorLfCascades { return false; } + /// Method to perform selections for Xic 3-prong candidates before vertex reconstruction + /// \param pVecXi is the momentum array of the Xi daughter track + /// \param pVecPi1 is the momentum array of the first pion daughter track + /// \param pVecPi2 is the momentum array of the second pion daughter track + /// \return selection outcome + template + bool isPreselectedCandidateXic(T1 const& pVecXi, T1 const& pVecPi1, T1 const& pVecPi2) + { + // pT + if (config.ptMinXicplusLfCasc > 0.f) { + const auto pt = RecoDecay::pt(pVecXi, pVecPi1, pVecPi2) + config.ptTolerance; // add tolerance because of no reco decay vertex + if (pt < config.ptMinXicplusLfCasc) { + return false; + } + } + + // invariant mass + if (config.massXiPiPiMin >= 0.f && config.massXiPiPiMax > 0.f) { + const double invMassMin = config.massXiPiPiMin; + const double invMassMax = config.massXiPiPiMax; + const std::array arrMom{pVecXi, pVecPi1, pVecPi2}; + const auto invMass2 = RecoDecay::m2(arrMom, arrMass3Prong[hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi]); + if (invMass2 < invMassMin * invMassMin || invMass2 >= invMassMax * invMassMax) { + return false; + } + } + + return true; + } + + /// Method to perform selections for Xic 3-prong candidates after vertex reconstruction + /// \param pVecCand is the momentum array of the candidate after the reconstruction of the secondary vertex + /// \param secVtx is the secondary vertex + /// \param primVtx is the primary vertex + /// \return selection outcome + template + bool isSelectedCandidateXic(const T1& pVecCand, const T2& secVtx, const T3& primVtx) + { + // pT + if (config.ptMinXicplusLfCasc > 0.f) { + const auto pt = RecoDecay::pt(pVecCand); + if (pt < config.ptMinXicplusLfCasc) { + return false; + } + } + + // CPA + if (config.xicCosPA > -1.f) { + const auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecCand); + if (cpa < config.xicCosPA) { + return false; + } + } + + // decay length + if (config.decayLengthXicMin > 0.f) { + const auto decayLength = RecoDecay::distance(primVtx, secVtx); + if (decayLength < config.decayLengthXicMin) { + return false; + } + } + + return true; + } + void processNoLfCascades(SelectedCollisions const&) { // dummy @@ -3462,19 +3597,16 @@ struct HfTrackIndexSkimCreatorLfCascades { for (const auto& collision : collisions) { // set the magnetic field from CCDB - auto bc = collision.bc_as(); + const auto bc = collision.bc_as(); initCCDB(bc, runNumber, ccdb, config.isRun2 ? config.ccdbPathGrp : config.ccdbPathGrpMag, lut, config.isRun2); - auto magneticField = o2::base::Propagator::Instance()->getNominalBz(); // z component + const auto magneticField = o2::base::Propagator::Instance()->getNominalBz(); // z component df2.setBz(magneticField); df2.setRefitWithMatCorr(config.refitWithMatCorr); - df3.setBz(magneticField); - df3.setRefitWithMatCorr(config.refitWithMatCorr); - // cascade loop - auto thisCollId = collision.globalIndex(); - auto groupedCascades = cascades.sliceBy(cascadesPerCollision, thisCollId); + const auto thisCollId = collision.globalIndex(); + const auto groupedCascades = cascades.sliceBy(cascadesPerCollision, thisCollId); for (const auto& casc : groupedCascades) { @@ -3482,11 +3614,11 @@ struct HfTrackIndexSkimCreatorLfCascades { //----------------accessing particles in the decay chain------------- // cascade daughter - charged particle - auto trackCascDauCharged = casc.bachelor_as(); // meson <- xi track + const auto trackCascDauCharged = casc.bachelor_as(); // meson <- xi track // cascade daughter - V0 - auto trackV0PosDau = casc.posTrack_as(); // p <- V0 track (positive track) 0 + const 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 + const auto trackV0NegDau = casc.negTrack_as(); // pion <- V0 track (negative track) 1 // check that particles come from the same collision if (config.rejDiffCollTrack) { @@ -3506,39 +3638,40 @@ struct HfTrackIndexSkimCreatorLfCascades { continue; } - 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++) { + const std::array vertexCasc{casc.x(), casc.y(), casc.z()}; + const std::array pVecCasc{casc.px(), casc.py(), casc.pz()}; + std::array covCasc{}; + constexpr std::size_t NIndicesMom{6u}; + constexpr std::size_t MomInd[NIndicesMom] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (std::size_t i = 0; i < NIndicesMom; i++) { covCasc[MomInd[i]] = casc.momentumCovMat()[i]; covCasc[i] = casc.positionCovMat()[i]; } // create cascade track - o2::track::TrackParCov trackCascXi; + o2::track::TrackParCov trackParCovCascXi; if (trackCascDauCharged.sign() > 0) { - trackCascXi = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, 1, true); + trackParCovCascXi = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, 1, true); } else if (trackCascDauCharged.sign() < 0) { - trackCascXi = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, -1, true); + trackParCovCascXi = o2::track::TrackParCov(vertexCasc, pVecCasc, covCasc, -1, true); } else { continue; } - trackCascXi.setAbsCharge(1); + trackParCovCascXi.setAbsCharge(1); - auto trackCascOmega = trackCascXi; + auto trackParCovCascOmega = trackParCovCascXi; - trackCascXi.setPID(o2::track::PID::XiMinus); - trackCascOmega.setPID(o2::track::PID::OmegaMinus); + trackParCovCascXi.setPID(o2::track::PID::XiMinus); + trackParCovCascOmega.setPID(o2::track::PID::OmegaMinus); //--------------combining cascade and pion tracks-------------- - auto groupedBachTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); + const auto groupedBachTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); for (auto trackIdCharmBachelor1 = groupedBachTrackIndices.begin(); trackIdCharmBachelor1 != groupedBachTrackIndices.end(); ++trackIdCharmBachelor1) { hfFlag = 0; isGoogForXi2Prong = true; isGoogForOmega2Prong = true; - auto trackCharmBachelor1 = trackIdCharmBachelor1.track_as(); + const auto trackCharmBachelor1 = trackIdCharmBachelor1.track_as(); if ((config.rejDiffCollTrack) && (trackCascDauCharged.collisionId() != trackCharmBachelor1.collisionId())) { continue; @@ -3555,12 +3688,12 @@ struct HfTrackIndexSkimCreatorLfCascades { } // primary pion track to be processed with DCAFitter - auto trackParVarCharmBachelor1 = getTrackParCov(trackCharmBachelor1); + const auto trackParCovCharmBachelor1 = getTrackParCov(trackCharmBachelor1); // find charm baryon decay using xi PID hypothesis (xi pi channel) int nVtxFrom2ProngFitterXiHyp = 0; try { - nVtxFrom2ProngFitterXiHyp = df2.process(trackCascXi, trackParVarCharmBachelor1); + nVtxFrom2ProngFitterXiHyp = df2.process(trackParCovCascXi, trackParCovCharmBachelor1); } catch (...) { if (config.fillHistograms) { registry.fill(HIST("hFitterStatusXi2Prong"), 1); @@ -3576,21 +3709,27 @@ struct HfTrackIndexSkimCreatorLfCascades { df2.propagateTracksToVertex(); if (df2.isPropagateTracksToVertexDone()) { - std::array pVecXi = {0.}; - std::array pVecPion1XiHyp = {0.}; + std::array pVecXi{}; + std::array pVecPion1XiHyp{}; df2.getTrack(0).getPxPyPzGlo(pVecXi); df2.getTrack(1).getPxPyPzGlo(pVecPion1XiHyp); + const float ptXic = RecoDecay::pt(pVecXi, pVecPion1XiHyp); - std::array, 2> arrMomToXi = {pVecXi, pVecPion1XiHyp}; - auto mass2ProngXiHyp = RecoDecay::m(arrMomToXi, arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi]); + const std::array arrMomToXi{pVecXi, pVecPion1XiHyp}; + const auto mass2ProngXiHyp = RecoDecay::m(arrMomToXi, arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi]); - if ((std::abs(casc.mXi() - massXi) < config.cascadeMassWindow) && (mass2ProngXiHyp >= config.massXiPiMin) && (mass2ProngXiHyp <= config.massXiPiMax)) { - SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::XiczeroOmegaczeroToXiPi); + if ((std::abs(casc.mXi() - MassXiMinus) < 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 (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"); @@ -3600,7 +3739,7 @@ struct HfTrackIndexSkimCreatorLfCascades { // 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, trackParVarCharmBachelor1); + nVtxFrom2ProngFitterOmegaHyp = df2.process(trackParCovCascOmega, trackParCovCharmBachelor1); } catch (...) { if (config.fillHistograms) { registry.fill(HIST("hFitterStatusOmega2Prong"), 1); @@ -3617,21 +3756,30 @@ struct HfTrackIndexSkimCreatorLfCascades { if (df2.isPropagateTracksToVertexDone()) { - std::array pVecOmega = {0.}; - std::array pVecCharmBachelor1OmegaHyp = {0.}; + std::array pVecOmega{}; + std::array pVecCharmBachelor1OmegaHyp{}; df2.getTrack(0).getPxPyPzGlo(pVecOmega); df2.getTrack(1).getPxPyPzGlo(pVecCharmBachelor1OmegaHyp); + const 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]); + const std::array arrMomToOmega{pVecOmega, pVecCharmBachelor1OmegaHyp}; + const auto mass2ProngOmegaPiHyp = RecoDecay::m(arrMomToOmega, arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi]); + const auto mass2ProngOmegaKHyp = RecoDecay::m(arrMomToOmega, arrMass2Prong[hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK]); - if (std::abs(casc.mOmega() - massOmega) < config.cascadeMassWindow) { + if (std::abs(casc.mOmega() - MassOmegaMinus) < config.cascadeMassWindow) { if ((mass2ProngOmegaPiHyp >= config.massOmegaCharmBachelorMin) && (mass2ProngOmegaPiHyp <= config.massOmegaCharmBachelorMax)) { - SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi); + 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)) { - SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK); + registry.fill(HIST("hRejpTStatusOmegacZeroToOmegaKa"), 0); + if (ptOmegac >= config.ptMinOmegaczeroToOmegaKaLfCasc) { + SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK); + registry.fill(HIST("hRejpTStatusOmegacZeroToOmegaKa"), 1); + } } } @@ -3639,9 +3787,11 @@ struct HfTrackIndexSkimCreatorLfCascades { 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()) { @@ -3657,19 +3807,21 @@ struct HfTrackIndexSkimCreatorLfCascades { hfFlag); } - // first loop over tracks + // Xic -> Xi pi pi if (config.do3Prong) { + // Xi mass cut + if (std::abs(casc.mXi() - MassXiMinus) > config.cascadeMassWindow) { + continue; + } - // second loop over positive tracks + // second loop over tracks for (auto trackIdCharmBachelor2 = trackIdCharmBachelor1 + 1; trackIdCharmBachelor2 != groupedBachTrackIndices.end(); ++trackIdCharmBachelor2) { - hfFlag = 0; - if (!TESTBIT(trackIdCharmBachelor2.isSelProng(), CandidateType::CandCascadeBachelor)) { continue; } - auto trackCharmBachelor2 = trackIdCharmBachelor2.track_as(); + const auto trackCharmBachelor2 = trackIdCharmBachelor2.track_as(); if ((config.rejDiffCollTrack) && (trackCascDauCharged.collisionId() != trackCharmBachelor2.collisionId())) { continue; @@ -3685,13 +3837,16 @@ struct HfTrackIndexSkimCreatorLfCascades { continue; } - // primary pion track to be processed with DCAFitter - auto trackParVarPion2 = getTrackParCov(trackCharmBachelor2); + if (!isPreselectedCandidateXic(pVecCasc, trackCharmBachelor1.pVector(), trackCharmBachelor2.pVector())) { + continue; + } // reconstruct Xic with DCAFitter + // Use only bachelor tracks for vertex reconstruction because the Xi track has large uncertainties. int nVtxFrom3ProngFitterXiHyp = 0; try { - nVtxFrom3ProngFitterXiHyp = df3.process(trackCascXi, trackParVarCharmBachelor1, trackParVarPion2); + const auto trackParCovCharmBachelor2 = getTrackParCov(trackCharmBachelor2); + nVtxFrom3ProngFitterXiHyp = df2.process(trackParCovCharmBachelor1, trackParCovCharmBachelor2); } catch (...) { if (config.fillHistograms) { registry.fill(HIST("hFitterStatusXi3Prong"), 1); @@ -3703,42 +3858,44 @@ struct HfTrackIndexSkimCreatorLfCascades { } if (nVtxFrom3ProngFitterXiHyp > 0) { + df2.propagateTracksToVertex(); + if (df2.isPropagateTracksToVertexDone()) { + std::array pVecPi1{}; + std::array pVecPi2{}; + // get bachelor momenta at the Xic vertex + df2.getTrack(0).getPxPyPzGlo(pVecPi1); + df2.getTrack(1).getPxPyPzGlo(pVecPi2); + const auto pVecCand = RecoDecay::pVec(pVecCasc, pVecPi1, pVecPi2); + const auto ptCand = RecoDecay::pt(pVecCand); + const std::array primaryVertex{collision.posX(), collision.posY(), collision.posZ()}; // primary vertex + const auto& secondaryVertex = df2.getPCACandidate(); // secondary vertex + + registry.fill(HIST("hRejpTStatusXicPlusToXiPiPi"), 0); + if (ptCand >= config.ptMinXicplusLfCasc) { + registry.fill(HIST("hRejpTStatusXicPlusToXiPiPi"), 1); + } - df3.propagateTracksToVertex(); - - if (df3.isPropagateTracksToVertexDone()) { - - std::array pVec1 = {0.}; - std::array pVec2 = {0.}; - std::array pVec3 = {0.}; - df3.getTrack(0).getPxPyPzGlo(pVec1); // take the momentum at the Xic vertex - df3.getTrack(1).getPxPyPzGlo(pVec2); - df3.getTrack(2).getPxPyPzGlo(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) < config.cascadeMassWindow) && (mass3Prong >= config.massXiPiPiMin) && (mass3Prong <= config.massXiPiPiMax)) { - SETBIT(hfFlag, aod::hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi); + if (!isSelectedCandidateXic(pVecCand, secondaryVertex, primaryVertex)) { + continue; } // fill histograms - if (config.fillHistograms && (TESTBIT(hfFlag, aod::hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi))) { + if (config.fillHistograms) { + const std::array arr3Mom{pVecCasc, pVecPi1, pVecPi2}; + const auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[hf_cand_casc_lf::DecayType3Prong::XicplusToXiPiPi]); registry.fill(HIST("hMassXicPlusToXiPiPi"), mass3Prong); + registry.fill(HIST("hPtCutsXicPlusToXiPiPi"), ptCand); } - } else if (df3.isPropagationFailure()) { + + // fill table row if a vertex was found + rowTrackIndexCasc3Prong(thisCollId, + casc.cascadeId(), + trackCharmBachelor1.globalIndex(), + trackCharmBachelor2.globalIndex()); + } else if (df2.isPropagationFailure()) { LOGF(info, "Exception caught: failed to propagate tracks (3prong) to charm baryon decay vtx"); } } - - // fill table row only if a vertex was found - if (hfFlag != 0) { - rowTrackIndexCasc3Prong(thisCollId, - casc.cascadeId(), - trackCharmBachelor1.globalIndex(), - trackCharmBachelor2.globalIndex()); - } - } // end 3prong loop } // end 3prong condition diff --git a/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx b/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx index f6c717e6e08..af4663a1b41 100644 --- a/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx +++ b/PWGHF/TableProducer/treeCreatorB0ToDPi.cxx @@ -16,17 +16,30 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_decay::hf_cand_beauty; namespace o2::aod { @@ -162,7 +175,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"}; @@ -170,15 +183,13 @@ struct HfTreeCreatorB0ToDPi { 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_b0::isSelB0ToDPi >= selectionFlagB0; - Partition recSig = nabs(aod::hf_cand_b0::flagMcMatchRec) == (int8_t)BIT(aod::hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi); - Partition recBg = nabs(aod::hf_cand_b0::flagMcMatchRec) != (int8_t)BIT(aod::hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi); + Partition recSig = nabs(aod::hf_cand_b0::flagMcMatchRec) == static_cast(DecayChannelMain::B0ToDminusPi); + Partition recBg = nabs(aod::hf_cand_b0::flagMcMatchRec) != static_cast(DecayChannelMain::B0ToDminusPi); void init(InitContext const&) { @@ -197,12 +208,12 @@ struct HfTreeCreatorB0ToDPi { runNumber); } - template + template void fillCandidateTable(const T& candidate, const U& prong1) { int8_t flagMc = 0; int8_t originMc = 0; - if constexpr (doMc) { + if constexpr (DoMc) { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); } @@ -220,14 +231,14 @@ struct HfTreeCreatorB0ToDPi { prong1.tpcNSigmaPi(), prong1.tofNSigmaPi(), candidate.isSelB0ToDPi(), - hfHelper.invMassB0ToDPi(candidate), + HfHelper::invMassB0ToDPi(candidate), candidate.pt(), candidate.cpa(), candidate.cpaXY(), candidate.maxNormalisedDeltaIP(), candidate.eta(), candidate.phi(), - hfHelper.yB0(candidate), + HfHelper::yB0(candidate), flagMc, originMc); } else { @@ -267,17 +278,17 @@ struct HfTreeCreatorB0ToDPi { prong1.tpcNSigmaPi(), prong1.tofNSigmaPi(), candidate.isSelB0ToDPi(), - hfHelper.invMassB0ToDPi(candidate), + HfHelper::invMassB0ToDPi(candidate), candidate.pt(), candidate.p(), candidate.cpa(), candidate.cpaXY(), candidate.maxNormalisedDeltaIP(), - hfHelper.ctB0(candidate), + HfHelper::ctB0(candidate), candidate.eta(), candidate.phi(), - hfHelper.yB0(candidate), - hfHelper.eB0(candidate), + HfHelper::yB0(candidate), + HfHelper::eB0(candidate), flagMc, originMc); } @@ -300,7 +311,7 @@ struct HfTreeCreatorB0ToDPi { } for (const auto& candidate : candidates) { if (fillOnlyBackground) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -340,7 +351,7 @@ struct HfTreeCreatorB0ToDPi { rowCandidateLite.reserve(recBg.size()); } for (const auto& candidate : recBg) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -361,7 +372,7 @@ struct HfTreeCreatorB0ToDPi { // Filling particle properties rowCandidateFullParticles.reserve(particles.size()); for (const auto& particle : particles) { - if (TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi)) { + if (std::abs(particle.flagMcMatchGen()) == DecayChannelMain::B0ToDminusPi) { rowCandidateFullParticles( particle.mcCollision().bcId(), particle.pt(), diff --git a/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx b/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx index fdc18d3b3e0..9aa6b5f7cab 100644 --- a/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx +++ b/PWGHF/TableProducer/treeCreatorBplusToD0Pi.cxx @@ -17,17 +17,31 @@ /// /// \author Antonio Palasciano , Università & INFN, Bari -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_decay::hf_cand_beauty; namespace o2::aod { @@ -225,15 +239,13 @@ struct HfTreeCreatorBplusToD0Pi { 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); + Partition recSig = nabs(aod::hf_cand_bplus::flagMcMatchRec) == static_cast(DecayChannelMain::BplusToD0Pi); + Partition recBg = nabs(aod::hf_cand_bplus::flagMcMatchRec) != static_cast(DecayChannelMain::BplusToD0Pi); void init(InitContext const&) { @@ -252,12 +264,12 @@ struct HfTreeCreatorBplusToD0Pi { runNumber); } - template + template void fillCandidateTable(const T& candidate, const U& prong1) { int8_t flagMc = 0; int8_t originMc = 0; - if constexpr (doMc) { + if constexpr (DoMc) { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); } @@ -267,9 +279,9 @@ struct HfTreeCreatorBplusToD0Pi { auto d0Daughter1 = d0Cand.template prong1_as(); auto invMassD0 = 0.; if (prong1.signed1Pt() > 0) { - invMassD0 = hfHelper.invMassD0barToKPi(d0Cand); + invMassD0 = HfHelper::invMassD0barToKPi(d0Cand); } else if (prong1.signed1Pt() < 0) { - invMassD0 = hfHelper.invMassD0ToPiK(d0Cand); + invMassD0 = HfHelper::invMassD0ToPiK(d0Cand); } if (fillCandidateLiteTable) { rowCandidateLite( @@ -285,14 +297,14 @@ struct HfTreeCreatorBplusToD0Pi { prong1.tpcNSigmaPi(), prong1.tofNSigmaPi(), candidate.isSelBplusToD0Pi(), - hfHelper.invMassBplusToD0Pi(candidate), + HfHelper::invMassBplusToD0Pi(candidate), candidate.pt(), candidate.cpa(), candidate.cpaXY(), candidate.maxNormalisedDeltaIP(), candidate.eta(), candidate.phi(), - hfHelper.yBplus(candidate), + HfHelper::yBplus(candidate), flagMc, originMc); } else { @@ -332,22 +344,22 @@ struct HfTreeCreatorBplusToD0Pi { prong1.tpcNSigmaPi(), prong1.tofNSigmaPi(), candidate.isSelBplusToD0Pi(), - hfHelper.invMassBplusToD0Pi(candidate), + HfHelper::invMassBplusToD0Pi(candidate), candidate.pt(), candidate.p(), candidate.cpa(), candidate.cpaXY(), candidate.maxNormalisedDeltaIP(), - hfHelper.ctBplus(candidate), + HfHelper::ctBplus(candidate), candidate.eta(), candidate.phi(), - hfHelper.yBplus(candidate), - hfHelper.eBplus(candidate), + HfHelper::yBplus(candidate), + HfHelper::eBplus(candidate), flagMc, invMassD0, d0Cand.ptProng0(), d0Cand.ptProng1(), - hfHelper.yD0(d0Cand), + HfHelper::yD0(d0Cand), d0Cand.eta(), d0Cand.cpa(), d0Cand.cpaXY(), @@ -389,7 +401,7 @@ struct HfTreeCreatorBplusToD0Pi { } for (const auto& candidate : candidates) { if (fillOnlyBackground) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -429,7 +441,7 @@ struct HfTreeCreatorBplusToD0Pi { rowCandidateLite.reserve(recBg.size()); } for (const auto& candidate : recBg) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -450,7 +462,7 @@ struct HfTreeCreatorBplusToD0Pi { // Filling particle properties rowCandidateFullParticles.reserve(particles.size()); for (const auto& particle : particles) { - if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_bplus::DecayTypeMc::BplusToD0PiToKPiPi) { + if (std::abs(particle.flagMcMatchGen()) == DecayChannelMain::BplusToD0Pi) { rowCandidateFullParticles( particle.mcCollision().bcId(), particle.mcCollisionId(), diff --git a/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx b/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx index aac534e265e..6e30341f584 100644 --- a/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx +++ b/PWGHF/TableProducer/treeCreatorBsToDsPi.cxx @@ -16,17 +16,30 @@ /// \note Adapted from treeCreatorB0T0DPi.cxx /// \author Phil Stahlhut -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_decay::hf_cand_beauty; namespace o2::aod { @@ -165,15 +178,13 @@ struct HfTreeCreatorBsToDsPi { 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_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) == static_cast(DecayChannelMain::BsToDsPi); + Partition recBg = nabs(aod::hf_cand_bs::flagMcMatchRec) != static_cast(DecayChannelMain::BsToDsPi); void init(InitContext const&) { @@ -192,11 +203,11 @@ struct HfTreeCreatorBsToDsPi { runNumber); } - template + template void fillCandidateTable(const T& candidate, const U& prong1) { int8_t flagMc = 0; - if constexpr (doMc) { + if constexpr (DoMc) { flagMc = candidate.flagMcMatchRec(); } if (fillCandidateLiteTable) { @@ -213,14 +224,14 @@ struct HfTreeCreatorBsToDsPi { prong1.tpcNSigmaPi(), prong1.tofNSigmaPi(), candidate.isSelBsToDsPi(), - hfHelper.invMassBsToDsPi(candidate), + HfHelper::invMassBsToDsPi(candidate), candidate.pt(), candidate.cpa(), candidate.cpaXY(), candidate.maxNormalisedDeltaIP(), candidate.eta(), candidate.phi(), - hfHelper.yBs(candidate), + HfHelper::yBs(candidate), flagMc); } else { rowCandidateFull( @@ -258,17 +269,17 @@ struct HfTreeCreatorBsToDsPi { prong1.tpcNSigmaPi(), prong1.tofNSigmaPi(), candidate.isSelBsToDsPi(), - hfHelper.invMassBsToDsPi(candidate), + HfHelper::invMassBsToDsPi(candidate), candidate.pt(), candidate.p(), candidate.cpa(), candidate.cpaXY(), candidate.maxNormalisedDeltaIP(), - hfHelper.ctBs(candidate), + HfHelper::ctBs(candidate), candidate.eta(), candidate.phi(), - hfHelper.yBs(candidate), - hfHelper.eBs(candidate), + HfHelper::yBs(candidate), + HfHelper::eBs(candidate), flagMc); } } @@ -290,7 +301,7 @@ struct HfTreeCreatorBsToDsPi { } for (const auto& candidate : candidates) { if (fillOnlyBackground && downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (pseudoRndm >= downSampleBkgFactor && candidate.pt() < ptMaxForDownSample) { continue; } @@ -330,7 +341,7 @@ struct HfTreeCreatorBsToDsPi { rowCandidateLite.reserve(recBg.size()); } for (const auto& candidate : recBg) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -351,7 +362,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 (std::abs(particle.flagMcMatchGen()) == DecayChannelMain::BsToDsPi) { rowCandidateFullParticles( particle.mcCollision().bcId(), particle.pt(), diff --git a/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx b/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx index 3487f1615dd..17093c0ef64 100644 --- a/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx @@ -17,14 +17,27 @@ /// \author Nicolo' Jacazio , CERN /// \author Andrea Tavira García , IJCLab -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -72,6 +85,8 @@ DECLARE_SOA_COLUMN(Ct, ct, float); DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float); DECLARE_SOA_COLUMN(FlagMc, flagMc, int8_t); +DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); +DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); // is prompt or non-prompt, reco level DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); // is prompt or non-prompt, Gen level DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfCand2Prong, "_0"); @@ -81,6 +96,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, @@ -117,10 +138,10 @@ DECLARE_SOA_TABLE(HfCandD0Lites, "AOD", "HFCANDD0LITE", full::Phi, full::Y, full::FlagMc, + full::FlagMcDecayChanRec, full::OriginMcRec) DECLARE_SOA_TABLE(HfCandD0Fulls, "AOD", "HFCANDD0FULL", - full::CollisionId, collision::PosX, collision::PosY, collision::PosZ, @@ -179,11 +200,10 @@ DECLARE_SOA_TABLE(HfCandD0Fulls, "AOD", "HFCANDD0FULL", full::Y, full::E, full::FlagMc, - full::OriginMcRec, - full::CandidateId); + full::FlagMcDecayChanRec, + full::OriginMcRec); DECLARE_SOA_TABLE(HfCandD0FullEvs, "AOD", "HFCANDD0FULLEV", - full::CollisionId, collision::NumContrib, collision::PosX, collision::PosY, @@ -192,14 +212,18 @@ DECLARE_SOA_TABLE(HfCandD0FullEvs, "AOD", "HFCANDD0FULLEV", full::RunNumber); DECLARE_SOA_TABLE(HfCandD0FullPs, "AOD", "HFCANDD0FULLP", - full::McCollisionId, full::Pt, full::Eta, full::Phi, full::Y, full::FlagMc, - full::OriginMcGen, - full::McParticleId); + full::FlagMcDecayChanGen, + full::OriginMcGen); + +DECLARE_SOA_TABLE(HfCandD0Mls, "AOD", "HFCANDD0ML", + ml::BdtOutputBkg, + ml::BdtOutputNonPrompt, + ml::BdtOutputPrompt); } // namespace o2::aod @@ -209,30 +233,40 @@ 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 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 fillCorrBkgs{"fillCorrBkgs", false, "Flag to fill derived tables with correlated background candidates"}; - 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; - Filter filterMcGenMatching = nabs(aod::hf_cand_2prong::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); + Filter filterMcGenMatching = nabs(aod::hf_cand_2prong::flagMcMatchGen) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && (nabs(aod::hf_cand_2prong::flagMcMatchGen) != 0)); + + Partition reconstructedCandSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_2prong::flagMcMatchRec) != 0); + Partition reconstructedCandBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition reconstructedCandSigKF = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_2prong::flagMcMatchRec) != 0); + Partition reconstructedCandBkgKF = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); - Partition reconstructedCandSig = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - Partition reconstructedCandBkg = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK)); - 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(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_2prong::flagMcMatchRec) != 0); + Partition reconstructedCandBkgMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK); + Partition reconstructedCandSigKFMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) == static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && nabs(aod::hf_cand_2prong::flagMcMatchRec) != 0); + Partition reconstructedCandBkgKFMl = nabs(aod::hf_cand_2prong::flagMcMatchRec) != static_cast(o2::hf_decay::hf_cand_2prong::DecayChannelMain::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."); } @@ -242,7 +276,6 @@ struct HfTreeCreatorD0ToKPi { void fillEvent(const T& collision, int isEventReject, int runNumber) { rowCandidateFullEvents( - collision.globalIndex(), collision.numContrib(), collision.posX(), collision.posY(), @@ -251,9 +284,9 @@ struct HfTreeCreatorD0ToKPi { runNumber); } - template - auto fillTable(const T& candidate, const U& prong0, const U& prong1, int candFlag, double invMass, double cosThetaStar, double topoChi2, - double ct, double y, double e, int8_t flagMc, int8_t origin) + template + auto fillTable(const T& candidate, int candFlag, double invMass, double topoChi2, + double ct, double y, double e, int8_t flagMc, int8_t flagMcDecay, int8_t origin) { if (fillCandidateLiteTable) { rowCandidateLite( @@ -268,18 +301,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(), @@ -291,10 +324,11 @@ struct HfTreeCreatorD0ToKPi { candidate.phi(), y, flagMc, + flagMcDecay, origin); } else { + double cosThetaStar = candFlag == 0 ? HfHelper::cosThetaStarD0(candidate) : HfHelper::cosThetaStarD0bar(candidate); rowCandidateFull( - candidate.collisionId(), candidate.posX(), candidate.posY(), candidate.posZ(), @@ -326,18 +360,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(), @@ -353,15 +387,28 @@ struct HfTreeCreatorD0ToKPi { y, e, flagMc, - origin, - candidate.globalIndex()); + flagMcDecay, + origin); + } + 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,61 +422,80 @@ 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 const 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); + double const yD = HfHelper::yD0(candidate); + double const eD = HfHelper::eD0(candidate); + double const ctD = HfHelper::ctD0(candidate); float massD0, massD0bar; float topolChi2PerNdf = -999.; - if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { massD0 = candidate.kfGeoMassD0(); massD0bar = candidate.kfGeoMassD0bar(); topolChi2PerNdf = candidate.kfTopolChi2OverNdf(); } else { - massD0 = hfHelper.invMassD0ToPiK(candidate); - massD0bar = hfHelper.invMassD0barToKPi(candidate); + massD0 = HfHelper::invMassD0ToPiK(candidate); + 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, 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, 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,59 +510,62 @@ 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)) { + if constexpr (OnlyBkg) { + if ((std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && (candidate.flagMcMatchRec() != 0))) { continue; } if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } } } - if constexpr (onlySig) { - if (!TESTBIT(std::abs(candidate.flagMcMatchRec()), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if constexpr (OnlySig) { + if (fillCorrBkgs && candidate.flagMcMatchRec() == 0) { + continue; + } + if (!fillCorrBkgs && std::abs(candidate.flagMcMatchRec()) != o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { 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); + double const yD = HfHelper::yD0(candidate); + double const eD = HfHelper::eD0(candidate); + double const ctD = HfHelper::ctD0(candidate); float massD0, massD0bar; float topolChi2PerNdf = -999.; - if constexpr (reconstructionType == aod::hf_cand::VertexerType::KfParticle) { + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { massD0 = candidate.kfGeoMassD0(); massD0bar = candidate.kfGeoMassD0bar(); topolChi2PerNdf = candidate.kfTopolChi2OverNdf(); } else { - massD0 = hfHelper.invMassD0ToPiK(candidate); - massD0bar = hfHelper.invMassD0barToKPi(candidate); + massD0 = HfHelper::invMassD0ToPiK(candidate); + 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.flagMcDecayChanRec(), 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.flagMcDecayChanRec(), candidate.originMcRec()); } } // Filling particle properties rowCandidateFullParticles.reserve(mcParticles.size()); for (const auto& particle : mcParticles) { - if (TESTBIT(std::abs(particle.flagMcMatchGen()), aod::hf_cand_2prong::DecayType::D0ToPiK)) { + if ((std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) || (fillCorrBkgs && particle.flagMcMatchGen() != 0)) { rowCandidateFullParticles( - particle.mcCollisionId(), particle.pt(), particle.eta(), particle.phi(), RecoDecay::y(particle.pVector(), o2::constants::physics::MassD0), particle.flagMcMatchGen(), - particle.originMcGen(), - particle.globalIndex()); + particle.flagMcDecayChanGen(), + particle.originMcGen()); } } } @@ -505,67 +574,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..97978baac1e 100644 --- a/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorDplusToPiKPi.cxx @@ -16,17 +16,32 @@ /// /// \author Alexandre Bigot , IPHC Strasbourg -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::hf_centrality; namespace o2::aod { @@ -50,6 +65,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 +95,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,11 +145,13 @@ DECLARE_SOA_TABLE(HfCandDpLites, "AOD", "HFCANDDPLITE", full::Eta, full::Phi, full::Y, + full::Centrality, + collision::NumContrib, hf_cand_3prong::FlagMcMatchRec, - hf_cand_3prong::OriginMcRec) + hf_cand_3prong::OriginMcRec, + hf_cand_3prong::FlagMcDecayChanRec) DECLARE_SOA_TABLE(HfCandDpFulls, "AOD", "HFCANDDPFULL", - collision::BCId, collision::NumContrib, collision::PosX, collision::PosY, @@ -203,11 +227,12 @@ 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, collision::NumContrib, collision::PosX, collision::PosY, @@ -216,12 +241,12 @@ DECLARE_SOA_TABLE(HfCandDpFullEvs, "AOD", "HFCANDDPFULLEV", full::RunNumber); DECLARE_SOA_TABLE(HfCandDpFullPs, "AOD", "HFCANDDPFULLP", - collision::BCId, full::Pt, full::Eta, full::Phi, full::Y, - hf_cand_3prong::FlagMcMatchRec, + hf_cand_3prong::FlagMcMatchGen, + hf_cand_3prong::FlagMcDecayChanGen, hf_cand_3prong::OriginMcGen); } // namespace o2::aod @@ -231,26 +256,32 @@ 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 fillCorrBkgs{"fillCorrBkgs", false, "Flag to fill derived tables with correlated background candidates"}; 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 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)); + Filter filterMcGenMatching = (nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) != 0)); - Partition reconstructedCandSig = 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::DplusToPiKPi)); + Partition reconstructedCandSig = (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchRec) != 0)); + Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi); + Partition reconstructedCandSigMl = (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi)) || (fillCorrBkgs && (nabs(o2::aod::hf_cand_3prong::flagMcMatchRec) != 0)); void init(InitContext const&) { @@ -260,7 +291,6 @@ struct HfTreeCreatorDplusToPiKPi { void fillEvent(const T& collision, int isEventReject, int runNumber) { rowCandidateFullEvents( - collision.bcId(), collision.numContrib(), collision.posX(), collision.posY(), @@ -269,19 +299,33 @@ struct HfTreeCreatorDplusToPiKPi { runNumber); } - template + template void fillCandidateTable(const T& candidate) { int8_t flagMc = 0; int8_t originMc = 0; - if constexpr (doMc) { + 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( @@ -299,39 +343,41 @@ struct HfTreeCreatorDplusToPiKPi { candidate.impactParameterZ0(), candidate.impactParameterZ1(), candidate.impactParameterZ2(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaKa(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), - prong2.tpcNSigmaPi(), - prong2.tpcNSigmaKa(), - prong2.tofNSigmaPi(), - prong2.tofNSigmaKa(), - prong2.tpcTofNSigmaPi(), - prong2.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(), + candidate.nSigTpcPi2(), + candidate.nSigTpcKa2(), + candidate.nSigTofPi2(), + candidate.nSigTofKa2(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaKa2(), candidate.isSelDplusToPiKPi(), - hfHelper.invMassDplusToPiKPi(candidate), + HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), candidate.cpa(), candidate.cpaXY(), candidate.maxNormalisedDeltaIP(), candidate.eta(), candidate.phi(), - hfHelper.yDplus(candidate), + HfHelper::yDplus(candidate), + cent, + coll.numContrib(), flagMc, - originMc); + originMc, + channelMc); } else { rowCandidateFull( - candidate.collision().bcId(), - candidate.collision().numContrib(), + coll.numContrib(), candidate.posX(), candidate.posY(), candidate.posZ(), @@ -376,43 +422,45 @@ struct HfTreeCreatorDplusToPiKPi { candidate.errorImpactParameterZ0(), candidate.errorImpactParameterZ1(), candidate.errorImpactParameterZ2(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaKa(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), - prong2.tpcNSigmaPi(), - prong2.tpcNSigmaKa(), - prong2.tofNSigmaPi(), - prong2.tofNSigmaKa(), - prong2.tpcTofNSigmaPi(), - prong2.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(), + candidate.nSigTpcPi2(), + candidate.nSigTpcKa2(), + candidate.nSigTofPi2(), + candidate.nSigTofKa2(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaKa2(), candidate.isSelDplusToPiKPi(), - hfHelper.invMassDplusToPiKPi(candidate), + HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), candidate.p(), candidate.cpa(), candidate.cpaXY(), candidate.maxNormalisedDeltaIP(), - hfHelper.ctDplus(candidate), + HfHelper::ctDplus(candidate), candidate.eta(), candidate.phi(), - hfHelper.yDplus(candidate), - hfHelper.eDplus(candidate), + HfHelper::yDplus(candidate), + HfHelper::eDplus(candidate), + cent, flagMc, - originMc); + originMc, + channelMc); } } void processData(aod::Collisions const& collisions, - soa::Filtered> const& candidates, + soa::Filtered> const& candidates, TracksWPid const&) { // Filling event properties @@ -429,22 +477,20 @@ struct HfTreeCreatorDplusToPiKPi { } for (const auto& candidate : candidates) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } } - fillCandidateTable(candidate); + fillCandidateTable(candidate); } } PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processData, "Process data", true); - void processMc(aod::Collisions const& collisions, - aod::McCollisions const&, - SelectedCandidatesMc const& candidates, - MatchedGenCandidatesMc const& particles, - TracksWPid const&) + void processDataWCent(CollisionsCent const& collisions, + soa::Filtered> const& candidates, + TracksWPid const&) { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); @@ -453,56 +499,122 @@ struct HfTreeCreatorDplusToPiKPi { } // 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 (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. - (int64_t)(candidate.ptProng0() * 1000); - if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { - continue; - } + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidates.size()); + } else { + rowCandidateFull.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; } - fillCandidateTable(candidate); } + fillCandidateTable(candidate); + } + } + + PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processDataWCent, "Process data with cent", false); + + template + void fillMcTables(CollType const& collisions, + aod::McCollisions const&, + CandTypeMcRec const& candidates, + CandTypeMcGen const& particles, + 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 { - if (fillCandidateLiteTable) { - rowCandidateLite.reserve(candidates.size()); - } else { - rowCandidateFull.reserve(candidates.size()); - } - for (const auto& candidate : candidates) { - fillCandidateTable(candidate); + rowCandidateFull.reserve(candidates.size()); + } + for (const auto& candidate : candidates) { + if (downSampleBkgFactor < 1.) { + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { + continue; + } } + 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.flagMcDecayChanGen(), particle.originMcGen()); } } + void processMc(aod::Collisions const& collisions, + aod::McCollisions const& mccollisions, + SelectedCandidatesMc const& candidates, + MatchedGenCandidatesMc const& particles, + TracksWPid const& tracks) + { + if (fillOnlySignal) { + fillMcTables(collisions, mccollisions, reconstructedCandSig, particles, tracks); + } else if (fillOnlyBackground) { + fillMcTables(collisions, mccollisions, reconstructedCandBkg, particles, tracks); + } else { + fillMcTables(collisions, mccollisions, candidates, particles, tracks); + } + } + PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processMc, "Process MC", false); + + void processMcWCent(CollisionsCent const& collisions, + aod::McCollisions const& mccollisions, + SelectedCandidatesMc const& candidates, + MatchedGenCandidatesMc const& particles, + TracksWPid const& tracks) + { + if (fillOnlySignal) { + fillMcTables(collisions, mccollisions, reconstructedCandSig, particles, tracks); + } else if (fillOnlyBackground) { + fillMcTables(collisions, mccollisions, reconstructedCandBkg, particles, tracks); + } else { + fillMcTables(collisions, mccollisions, candidates, particles, tracks); + } + } + + PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processMcWCent, "Process MC with cent", false); + + void processMcSgnWMl(aod::Collisions const& collisions, + aod::McCollisions const& mccollisions, + SelectedCandidatesMcWithMl const&, + MatchedGenCandidatesMc const& particles, + TracksWPid const& tracks) + { + fillMcTables(collisions, mccollisions, reconstructedCandSigMl, particles, tracks); + } + + PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processMcSgnWMl, "Process MC signal with ML info", false); + + void processMcSgnWCentMl(CollisionsCent const& collisions, + aod::McCollisions const& mccollisions, + SelectedCandidatesMcWithMl const&, + MatchedGenCandidatesMc const& particles, + TracksWPid const& tracks) + { + fillMcTables(collisions, mccollisions, reconstructedCandSigMl, particles, tracks); + } + + PROCESS_SWITCH(HfTreeCreatorDplusToPiKPi, processMcSgnWCentMl, "Process MC signal with cent and ML info", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx b/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx index 4e7e3fb7471..90dfa44d771 100644 --- a/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorDsToKKPi.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2023 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. // @@ -17,14 +17,31 @@ /// \author Stefano Politanò , Politecnico & INFN, Torino /// \author Fabio Catalano , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -77,10 +94,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 +144,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 +218,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 +231,7 @@ DECLARE_SOA_TABLE(HfCandDsFullEvs, "AOD", "HFCANDDSFULLEV", collision::PosX, collision::PosY, collision::PosZ, + full::Centrality, full::IsEventReject, full::RunNumber); @@ -221,6 +245,22 @@ DECLARE_SOA_TABLE(HfCandDsFullPs, "AOD", "HFCANDDSFULLP", hf_cand_3prong::OriginMcGen); } // namespace o2::aod +enum Mother : int8_t { + Ds, + Dplus +}; + +enum ResonantChannel : int8_t { + PhiPi = 1, + Kstar0K = 2 +}; + +namespace +{ +std::unordered_map> channelsResonant = {{{Mother::Ds, {{ResonantChannel::PhiPi, hf_decay::hf_cand_3prong::DecayChannelResonant::DsToPhiPi}, {ResonantChannel::Kstar0K, hf_decay::hf_cand_3prong::DecayChannelResonant::DsToKstar0K}}}, + {Mother::Dplus, {{ResonantChannel::PhiPi, hf_decay::hf_cand_3prong::DecayChannelResonant::DplusToPhiPi}, {ResonantChannel::Kstar0K, hf_decay::hf_cand_3prong::DecayChannelResonant::DplusToKstar0K}}}}}; +} + /// Writes the full information in an output TTree struct HfTreeCreatorDsToKKPi { Produces rowCandidateFull; @@ -228,7 +268,7 @@ struct HfTreeCreatorDsToKKPi { Produces rowCandidateFullParticles; Produces rowCandidateLite; - Configurable decayChannel{"decayChannel", 1, "Switch between decay channels: 1 for Ds/Dplus->PhiPi->KKpi, 2 for Ds/Dplus->K0*K->KKPi"}; + Configurable decayChannel{"decayChannel", 1, "Switch between resonant decay channels: 1 for Ds/Dplus->PhiPi->KKpi, 2 for Ds/Dplus->K0*K->KKPi"}; Configurable fillDplusMc{"fillDplusMc", false, "Switch to fill Dplus MC information"}; Configurable selectionFlagDs{"selectionFlagDs", 1, "Selection flag for Ds"}; Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; @@ -238,26 +278,35 @@ struct HfTreeCreatorDsToKKPi { 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 CandDsData = soa::Filtered>; - using CandDsMcReco = soa::Filtered>; + using CandDsData = soa::Filtered>; + using CandDsMcReco = soa::Filtered>; using CandDsMcGen = soa::Filtered>; using TracksWPid = 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 + using CollisionsWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + using CollisionsWithNTracksPV = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; - Filter filterMcGenMatching = nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && (aod::hf_cand_3prong::flagMcDecayChanGen == decayChannel || (fillDplusMc && aod::hf_cand_3prong::flagMcDecayChanGen == (decayChannel + offsetDplusDecayChannel))); // Do not store Dplus MC if fillDplusMc is false + Filter filterMcGenMatching = + nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && + (aod::hf_cand_3prong::flagMcDecayChanGen == channelsResonant[Mother::Ds][decayChannel] || + (fillDplusMc && aod::hf_cand_3prong::flagMcDecayChanGen == channelsResonant[Mother::Dplus][decayChannel])); // Do not store Dplus MC if fillDplusMc is false Partition selectedDsToKKPiCand = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlagDs; Partition selectedDsToPiKKCand = aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlagDs; - Partition reconstructedCandSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)) && (aod::hf_cand_3prong::flagMcDecayChanRec == decayChannel || (fillDplusMc && aod::hf_cand_3prong::flagMcDecayChanRec == (decayChannel + offsetDplusDecayChannel))); // Do not store Dplus MC if fillDplusMc is false - Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::DsToKKPi)); + Partition reconstructedCandSig = (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec == channelsResonant[Mother::Ds][decayChannel]) || (fillDplusMc && nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec == channelsResonant[Mother::Dplus][decayChannel]); // Do not store Dplus MC if fillDplusMc is false + Partition reconstructedCandBkg = (nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK)) || + (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec != channelsResonant[Mother::Ds][decayChannel]) || + (nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec != channelsResonant[Mother::Dplus][decayChannel]) || + (!fillDplusMc && nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKK) && aod::hf_cand_3prong::flagMcDecayChanRec == channelsResonant[Mother::Dplus][decayChannel]); void init(InitContext const&) { + if (decayChannel != ResonantChannel::PhiPi && decayChannel != ResonantChannel::Kstar0K) { + LOGP(fatal, "Invalid value of decayChannel"); + } } template @@ -269,6 +318,7 @@ struct HfTreeCreatorDsToKKPi { collision.posX(), collision.posY(), collision.posZ(), + o2::hf_centrality::getCentralityColl(collision), isEventReject, runNumber); } @@ -277,42 +327,45 @@ 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; - float yCand = 0; - float eCand = 0; - float ctCand = 0; - if constexpr (doMc) { + float invMassDs = 0; + float deltaMassPhiKK = 0; + float absCos3PiKDs = 0; + if constexpr (MassHypo == 0) { + invMassDs = HfHelper::invMassDsToKKPi(candidate); + deltaMassPhiKK = HfHelper::deltaMassPhiDsToKKPi(candidate); + absCos3PiKDs = HfHelper::absCos3PiKDsToKKPi(candidate); + } else if constexpr (MassHypo == 1) { + invMassDs = HfHelper::invMassDsToPiKK(candidate); + deltaMassPhiKK = HfHelper::deltaMassPhiDsToPiKK(candidate); + absCos3PiKDs = HfHelper::absCos3PiKDsToPiKK(candidate); + } + + int8_t flagMc{0}; + int8_t originMc{0}; + int8_t channelMc{0}; + int8_t isSwapped{MassHypo}; // 0 if KKPi, 1 if PiKK + float eCand{0.f}; + float ctCand{0.f}; + float yCand = candidate.y(invMassDs); + if constexpr (DoMc) { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); channelMc = candidate.flagMcDecayChanRec(); - if (fillDplusMc && candidate.flagMcDecayChanRec() == (decayChannel + offsetDplusDecayChannel)) { - yCand = hfHelper.yDplus(candidate); - eCand = hfHelper.eDplus(candidate); - ctCand = hfHelper.ctDplus(candidate); + isSwapped = candidate.isCandidateSwapped(); + if (fillDplusMc && candidate.flagMcDecayChanRec() == channelsResonant[Mother::Dplus][decayChannel]) { + eCand = HfHelper::eDplus(candidate); + ctCand = HfHelper::ctDplus(candidate); } else { - yCand = hfHelper.yDs(candidate); - eCand = hfHelper.eDs(candidate); - ctCand = hfHelper.ctDs(candidate); + eCand = HfHelper::eDs(candidate); + ctCand = HfHelper::ctDs(candidate); } } - float invMassDs = 0; - float deltaMassPhiKK = 0; - float absCos3PiKDs = 0; - if constexpr (massHypo == 0) { - invMassDs = hfHelper.invMassDsToKKPi(candidate); - deltaMassPhiKK = hfHelper.deltaMassPhiDsToKKPi(candidate); - absCos3PiKDs = hfHelper.absCos3PiKDsToKKPi(candidate); - } else if constexpr (massHypo == 1) { - invMassDs = hfHelper.invMassDsToPiKK(candidate); - deltaMassPhiKK = hfHelper.deltaMassPhiDsToPiKK(candidate); - 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(); @@ -326,26 +379,26 @@ struct HfTreeCreatorDsToKKPi { candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaKa(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), - prong2.tpcNSigmaPi(), - prong2.tpcNSigmaKa(), - prong2.tofNSigmaPi(), - prong2.tofNSigmaKa(), - prong2.tpcTofNSigmaPi(), - prong2.tpcTofNSigmaKa(), - candidate.isSelDsToKKPi(), - candidate.isSelDsToPiKK(), + candidate.nSigTpcPi0(), + candidate.nSigTpcKa0(), + candidate.nSigTofPi0(), + candidate.nSigTofKa0(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaKa0(), + candidate.nSigTpcPi1(), + candidate.nSigTpcKa1(), + candidate.nSigTofPi1(), + candidate.nSigTofKa1(), + candidate.tpcTofNSigmaPi1(), + candidate.tpcTofNSigmaKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTpcKa2(), + candidate.nSigTofPi2(), + candidate.nSigTofKa2(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaKa2(), + MassHypo == 0 ? candidate.isSelDsToKKPi() : -1, + MassHypo == 1 ? candidate.isSelDsToPiKK() : -1, invMassDs, candidate.pt(), candidate.eta(), @@ -362,14 +415,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(), @@ -391,26 +447,26 @@ struct HfTreeCreatorDsToKKPi { candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaKa(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), - prong2.tpcNSigmaPi(), - prong2.tpcNSigmaKa(), - prong2.tofNSigmaPi(), - prong2.tofNSigmaKa(), - prong2.tpcTofNSigmaPi(), - prong2.tpcTofNSigmaKa(), - candidate.isSelDsToKKPi(), - candidate.isSelDsToPiKK(), + candidate.nSigTpcPi0(), + candidate.nSigTpcKa0(), + candidate.nSigTofPi0(), + candidate.nSigTofKa0(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaKa0(), + candidate.nSigTpcPi1(), + candidate.nSigTpcKa1(), + candidate.nSigTofPi1(), + candidate.nSigTofKa1(), + candidate.tpcTofNSigmaPi1(), + candidate.tpcTofNSigmaKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTpcKa2(), + candidate.nSigTofPi2(), + candidate.nSigTofKa2(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaKa2(), + MassHypo == 0 ? candidate.isSelDsToKKPi() : -1, + MassHypo == 1 ? candidate.isSelDsToPiKK() : -1, candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), @@ -433,16 +489,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 +517,30 @@ struct HfTreeCreatorDsToKKPi { for (const auto& candidate : selectedDsToKKPiCand) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const 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 const 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 +558,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 +573,17 @@ struct HfTreeCreatorDsToKKPi { for (const auto& candidate : reconstructedCandBkg) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const 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 +595,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); } } } @@ -565,13 +621,83 @@ struct HfTreeCreatorDsToKKPi { particle.pt(), particle.eta(), particle.phi(), - RecoDecay::y(particle.pVector(), o2::constants::physics::MassDS), + std::abs(particle.pdgCode()) == o2::constants::physics::Pdg::kDS ? RecoDecay::y(particle.pVector(), o2::constants::physics::MassDS) : RecoDecay::y(particle.pVector(), o2::constants::physics::MassDPlus), particle.flagMcMatchGen(), particle.originMcGen()); } } - 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 dd863781594..059c3ed8f11 100644 --- a/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx +++ b/PWGHF/TableProducer/treeCreatorDstarToD0Pi.cxx @@ -16,13 +16,24 @@ /// /// \author Fabrizio Grosa , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -255,16 +266,16 @@ struct HfTreeCreatorDstarToD0Pi { 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 CandDstarWSelFlag = soa::Filtered>; - using CandDstarWSelFlagMcRec = soa::Filtered>; + using CandDstarWSelFlag = soa::Filtered>; + using CandDstarWSelFlagMcRec = soa::Filtered>; using TracksWPid = soa::Join; using CandDstarMcGen = soa::Filtered>; Filter filterSelectCandidates = aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == selectionFlagDstarToD0Pi; - Filter filterMcGenMatching = nabs(aod::hf_cand_dstar::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_dstar::DecayType::DstarToD0Pi)); + Filter filterMcGenMatching = nabs(aod::hf_cand_dstar::flagMcMatchGen) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); - Partition reconstructedCandSig = nabs(aod::hf_cand_dstar::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_dstar::DecayType::DstarToD0Pi)); - Partition reconstructedCandBkg = nabs(aod::hf_cand_dstar::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_dstar::DecayType::DstarToD0Pi)); + Partition reconstructedCandSig = nabs(aod::hf_cand_dstar::flagMcMatchRec) == static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); + Partition reconstructedCandBkg = nabs(aod::hf_cand_dstar::flagMcMatchRec) != static_cast(hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi); void init(InitContext const&) { @@ -283,31 +294,59 @@ struct HfTreeCreatorDstarToD0Pi { runNumber); } - template + template void fillCandidateTable(const T& candidate, float ptBhadMotherPart = -1) { int8_t flagMc{0}; int8_t originMc{0}; - if constexpr (doMc) { + if constexpr (DoMc) { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); } - auto prong0 = candidate.template prong0_as(); - auto prong1 = candidate.template prong1_as(); - auto prongSoftPi = candidate.template prongPi_as(); + TracksWPid::iterator prong0; + TracksWPid::iterator prong1; 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) { @@ -322,33 +361,33 @@ 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(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), - prongSoftPi.tpcNSigmaPi(), - prongSoftPi.tpcNSigmaKa(), - prongSoftPi.tofNSigmaPi(), - prongSoftPi.tofNSigmaKa(), - prongSoftPi.tpcTofNSigmaPi(), - prongSoftPi.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(), + candidate.nSigTpcPi2(), + candidate.nSigTpcKa2(), + candidate.nSigTofPi2(), + candidate.nSigTofKa2(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaKa2(), massD0, candidate.ptD0(), candidate.etaD0(), @@ -385,39 +424,39 @@ 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(), candidate.errorImpParamSoftPi(), - prong0.tpcNSigmaPi(), - prong0.tpcNSigmaKa(), - prong0.tofNSigmaPi(), - prong0.tofNSigmaKa(), - prong0.tpcTofNSigmaPi(), - prong0.tpcTofNSigmaKa(), - prong1.tpcNSigmaPi(), - prong1.tpcNSigmaKa(), - prong1.tofNSigmaPi(), - prong1.tofNSigmaKa(), - prong1.tpcTofNSigmaPi(), - prong1.tpcTofNSigmaKa(), - prongSoftPi.tpcNSigmaPi(), - prongSoftPi.tpcNSigmaKa(), - prongSoftPi.tofNSigmaPi(), - prongSoftPi.tofNSigmaKa(), - prongSoftPi.tpcTofNSigmaPi(), - prongSoftPi.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(), + candidate.nSigTpcPi2(), + candidate.nSigTpcKa2(), + candidate.nSigTofPi2(), + candidate.nSigTofKa2(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaKa2(), massD0, candidate.ptD0(), candidate.pD0(), @@ -457,7 +496,7 @@ struct HfTreeCreatorDstarToD0Pi { } for (const auto& candidate : candidates) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -498,7 +537,7 @@ struct HfTreeCreatorDstarToD0Pi { } for (const auto& candidate : reconstructedCandBkg) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } diff --git a/PWGHF/TableProducer/treeCreatorLbToLcPi.cxx b/PWGHF/TableProducer/treeCreatorLbToLcPi.cxx index 42e8001022f..925a005022c 100644 --- a/PWGHF/TableProducer/treeCreatorLbToLcPi.cxx +++ b/PWGHF/TableProducer/treeCreatorLbToLcPi.cxx @@ -18,15 +18,22 @@ /// \author Panos Christakoglou , Nikhef /// \author Maurice Jongerhuis , University Utrecht -#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" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include + +#include + using namespace o2; using namespace o2::framework; @@ -34,6 +41,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 +60,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 +84,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 +146,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 +167,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,171 +188,121 @@ 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) { - auto fillTable = [&](int FunctionSelection, - 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 fillTable = [&](int functionSelection, + float functionInvMass, + float functionCt, + float functionY) { + 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(), + candLc.nSigTpcPi0(), + candLc.nSigTpcKa0(), + candLc.nSigTpcPr0(), + candLc.nSigTpcPi1(), + candLc.nSigTpcKa1(), + candLc.nSigTpcPr1(), + candLc.nSigTpcPi2(), + candLc.nSigTpcKa2(), + candLc.nSigTpcPr2(), + candLc.nSigTofPr0(), + candLc.nSigTofKa1(), + candLc.nSigTofPi2(), + 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)); + fillTable(candidate.isSelLbToLcPi(), HfHelper::invMassLbToLcPi(candidate), HfHelper::ctLb(candidate), HfHelper::yLb(candidate)); } } }; @@ -330,7 +310,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..d28e7c5b560 100644 --- a/PWGHF/TableProducer/treeCreatorLcToK0sP.cxx +++ b/PWGHF/TableProducer/treeCreatorLcToK0sP.cxx @@ -17,16 +17,32 @@ /// /// \author Daniel Samitz -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; +using namespace o2::framework::expressions; namespace o2::aod { @@ -55,8 +71,8 @@ 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(PtV0Pos, ptV0Pos, float); DECLARE_SOA_COLUMN(PtV0Neg, ptV0Neg, float); @@ -71,6 +87,9 @@ DECLARE_SOA_COLUMN(V0CtLambda, v0CtLambda, 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(MlScoreFirstClass, mlScoreFirstClass, float); +DECLARE_SOA_COLUMN(MlScoreSecondClass, mlScoreSecondClass, float); +DECLARE_SOA_COLUMN(MlScoreThirdClass, mlScoreThirdClass, float); // Events DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); DECLARE_SOA_COLUMN(RunNumber, runNumber, int); @@ -105,15 +124,18 @@ DECLARE_SOA_TABLE(HfCandCascLites, "AOD", "HFCANDCASCLITE", full::NSigmaTOFPr0, full::M, full::Pt, - full::CPA, - full::CPAXY, + full::Cpa, + full::CpaXY, full::Ct, full::Eta, full::Phi, full::Y, full::E, full::FlagMc, - full::OriginMcRec); + full::OriginMcRec, + full::MlScoreFirstClass, + full::MlScoreSecondClass, + full::MlScoreThirdClass); DECLARE_SOA_TABLE(HfCandCascFulls, "AOD", "HFCANDCASCFULL", collision::BCId, @@ -175,15 +197,18 @@ DECLARE_SOA_TABLE(HfCandCascFulls, "AOD", "HFCANDCASCFULL", full::M, full::Pt, full::P, - full::CPA, - full::CPAXY, + full::Cpa, + full::CpaXY, full::Ct, full::Eta, full::Phi, full::Y, full::E, full::FlagMc, - full::OriginMcRec); + full::OriginMcRec, + full::MlScoreFirstClass, + full::MlScoreSecondClass, + full::MlScoreThirdClass); DECLARE_SOA_TABLE(HfCandCascFullEs, "AOD", "HFCANDCASCFULLE", collision::BCId, @@ -193,7 +218,6 @@ DECLARE_SOA_TABLE(HfCandCascFullEs, "AOD", "HFCANDCASCFULLE", collision::PosZ); DECLARE_SOA_TABLE(HfCandCascFullPs, "AOD", "HFCANDCASCFULLP", - collision::BCId, full::Pt, full::Eta, full::Phi, @@ -213,18 +237,56 @@ 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"}; + Configurable applyMl{"applyMl", false, "Whether ML was used in candidateSelectorLc"}; - HfHelper hfHelper; + constexpr static float UndefValueFloat = -999.f; using TracksWPid = soa::Join; + using SelectedCandidatesMc = soa::Filtered>; + Filter filterSelectCandidates = aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= 1; void init(InitContext const&) { } + /// \brief function to get ML score values for the current candidate and assign them to input parameters + /// \param candidate candidate instance + /// \param candidateMlScore instance of handler of vectors with ML scores associated with the current candidate + /// \param mlScoreFirstClass ML score for belonging to the first class + /// \param mlScoreSecondClass ML score for belonging to the second class + /// \param mlScoreThirdClass ML score for belonging to the third class + void assignMlScores(aod::HfMlLcToK0sP::iterator const& candidateMlScore, float& mlScoreFirstClass, float& mlScoreSecondClass, float& mlScoreThirdClass) + { + std::vector mlScores; + std::copy(candidateMlScore.mlProbLcToK0sP().begin(), candidateMlScore.mlProbLcToK0sP().end(), std::back_inserter(mlScores)); + + constexpr int IndexFirstClass{0}; + constexpr int IndexSecondClass{1}; + constexpr int IndexThirdClass{2}; + if (mlScores.empty()) { + return; // when candidateSelectorLcK0sP rejects a candidate by "usual", non-ML cut, the ml score vector remains empty + } + mlScoreFirstClass = mlScores.at(IndexFirstClass); + mlScoreSecondClass = mlScores.at(IndexSecondClass); + if (mlScores.size() > IndexThirdClass) { + mlScoreThirdClass = mlScores.at(IndexThirdClass); + } + } + template - void fillCandidate(const T& candidate, const U& bach, int8_t flagMc, int8_t originMcRec) + void fillCandidate(const T& candidate, const U& bach, int8_t flagMc, int8_t originMcRec, aod::HfMlLcToK0sP::iterator const& candidateMlScore) { + + float mlScoreFirstClass{UndefValueFloat}; + float mlScoreSecondClass{UndefValueFloat}; + float mlScoreThirdClass{UndefValueFloat}; + + if (applyMl) { + assignMlScores(candidateMlScore, mlScoreFirstClass, mlScoreSecondClass, mlScoreThirdClass); + } + if (fillCandidateLiteTable) { rowCandidateLite( candidate.chi2PCA(), @@ -244,8 +306,8 @@ struct HfTreeCreatorLcToK0sP { candidate.mAntiLambda(), candidate.mK0Short(), candidate.mGamma(), - hfHelper.ctV0K0s(candidate), - hfHelper.ctV0Lambda(candidate), + HfHelper::ctV0K0s(candidate), + HfHelper::ctV0Lambda(candidate), candidate.dcaV0daughters(), candidate.ptV0Pos(), candidate.ptV0Neg(), @@ -253,17 +315,20 @@ struct HfTreeCreatorLcToK0sP { candidate.dcapostopv(), bach.tpcNSigmaPr(), bach.tofNSigmaPr(), - hfHelper.invMassLcToK0sP(candidate), + HfHelper::invMassLcToK0sP(candidate), candidate.pt(), candidate.cpa(), candidate.cpaXY(), - hfHelper.ctLc(candidate), + HfHelper::ctLc(candidate), candidate.eta(), candidate.phi(), - hfHelper.yLc(candidate), - hfHelper.eLc(candidate), + HfHelper::yLc(candidate), + HfHelper::eLc(candidate), flagMc, - originMcRec); + originMcRec, + mlScoreFirstClass, + mlScoreSecondClass, + mlScoreThirdClass); } else { rowCandidateFull( bach.collision().bcId(), @@ -298,17 +363,17 @@ 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(), candidate.mAntiLambda(), candidate.mK0Short(), candidate.mGamma(), - hfHelper.ctV0K0s(candidate), - hfHelper.ctV0Lambda(candidate), + HfHelper::ctV0K0s(candidate), + HfHelper::ctV0Lambda(candidate), candidate.dcaV0daughters(), candidate.pxpos(), candidate.pypos(), @@ -322,18 +387,21 @@ struct HfTreeCreatorLcToK0sP { candidate.dcanegtopv(), bach.tpcNSigmaPr(), bach.tofNSigmaPr(), - hfHelper.invMassLcToK0sP(candidate), + HfHelper::invMassLcToK0sP(candidate), candidate.pt(), candidate.p(), candidate.cpa(), candidate.cpaXY(), - hfHelper.ctLc(candidate), + HfHelper::ctLc(candidate), candidate.eta(), candidate.phi(), - hfHelper.yLc(candidate), - hfHelper.eLc(candidate), + HfHelper::yLc(candidate), + HfHelper::eLc(candidate), flagMc, - originMcRec); + originMcRec, + mlScoreFirstClass, + mlScoreSecondClass, + mlScoreThirdClass); } } template @@ -349,33 +417,38 @@ struct HfTreeCreatorLcToK0sP { void processMc(aod::Collisions const& collisions, aod::McCollisions const&, - soa::Join const& candidates, + SelectedCandidatesMc const& candidates, + aod::HfMlLcToK0sP const& candidateMlScores, soa::Join const& particles, TracksWPid const&) { + if (applyMl && candidateMlScores.size() == 0) { + LOG(fatal) << "ML enabled but table with the ML scores is empty! Please check your configurables."; + return; + } + // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); for (const auto& collision : collisions) { fillEvent(collision); } - // Filling candidate properties if (fillCandidateLiteTable) { rowCandidateLite.reserve(candidates.size()); } else { rowCandidateFull.reserve(candidates.size()); } + + int iCand{0}; for (const auto& candidate : candidates) { + auto candidateMlScore = candidateMlScores.rawIteratorAt(iCand); + ++iCand; 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 (candidate.isSelLcToK0sP() >= 1) { - fillCandidate(candidate, bach, candidate.flagMcMatchRec(), candidate.originMcRec()); + const int flag = candidate.flagMcMatchRec(); + + if ((fillOnlySignal && flag != 0) || (fillOnlyBackground && flag == 0) || (!fillOnlySignal && !fillOnlyBackground)) { + fillCandidate(candidate, bach, candidate.flagMcMatchRec(), candidate.originMcRec(), candidateMlScore); } } @@ -384,7 +457,6 @@ struct HfTreeCreatorLcToK0sP { for (const auto& particle : particles) { if (std::abs(particle.flagMcMatchGen()) == 1) { rowCandidateFullParticles( - particle.mcCollision().bcId(), particle.pt(), particle.eta(), particle.phi(), @@ -399,9 +471,15 @@ struct HfTreeCreatorLcToK0sP { void processData(aod::Collisions const& collisions, soa::Join const& candidates, + aod::HfMlLcToK0sP const& candidateMlScores, TracksWPid const&) { + if (applyMl && candidateMlScores.size() == 0) { + LOG(fatal) << "ML enabled but table with the ML scores is empty! Please check your configurables."; + return; + } + // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); for (const auto& collision : collisions) { @@ -414,11 +492,15 @@ struct HfTreeCreatorLcToK0sP { } else { rowCandidateFull.reserve(candidates.size()); } + + int iCand{0}; for (const auto& candidate : candidates) { + auto candidateMlScore = candidateMlScores.rawIteratorAt(iCand); + ++iCand; auto bach = candidate.prong0_as(); // bachelor - double pseudoRndm = bach.pt() * 1000. - (int16_t)(bach.pt() * 1000); + double const pseudoRndm = bach.pt() * 1000. - static_cast(bach.pt() * 1000); if (candidate.isSelLcToK0sP() >= 1 && pseudoRndm < downSampleBkgFactor) { - fillCandidate(candidate, bach, 0, 0); + fillCandidate(candidate, bach, 0, 0, candidateMlScore); } } } diff --git a/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx b/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx index d9efc0202a7..97264a2336a 100644 --- a/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx @@ -17,19 +17,39 @@ /// \author Nicolo' Jacazio , CERN /// \author Luigi Dello Stritto , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/Multiplicity.h" -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#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::constants::physics; namespace o2::aod { @@ -65,11 +85,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); @@ -81,9 +101,12 @@ 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, int8_t); -DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfCand3Prong, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfCand3ProngWPidPiKaPr, "_0"); DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); DECLARE_SOA_COLUMN(Channel, channel, int8_t); // direct or resonant +DECLARE_SOA_COLUMN(MlScoreFirstClass, mlScoreFirstClass, float); +DECLARE_SOA_COLUMN(MlScoreSecondClass, mlScoreSecondClass, float); +DECLARE_SOA_COLUMN(MlScoreThirdClass, mlScoreThirdClass, float); // Events DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); @@ -96,30 +119,118 @@ 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 +DECLARE_SOA_COLUMN(NSigTpcPi, nSigTpcPi, float); +DECLARE_SOA_COLUMN(NSigTpcKa, nSigTpcKa, float); +DECLARE_SOA_COLUMN(NSigTpcPr, nSigTpcPr, float); +DECLARE_SOA_COLUMN(NSigTofPi, nSigTofPi, float); +DECLARE_SOA_COLUMN(NSigTofKa, nSigTofKa, float); +DECLARE_SOA_COLUMN(NSigTofPr, nSigTofPr, float); +DECLARE_SOA_COLUMN(NSigTpcTofPi, nSigTpcTofPi, float); +DECLARE_SOA_COLUMN(NSigTpcTofKa, nSigTpcTofKa, float); +DECLARE_SOA_COLUMN(NSigTpcTofPr, nSigTpcTofPr, float); +DECLARE_SOA_COLUMN(MultNTracksPV, multNTracksPV, int); +} // namespace kf + +namespace kf_collision +{ +DECLARE_SOA_COLUMN(PosXErr, posXErr, float); //! PV X coordinate uncertainty +DECLARE_SOA_COLUMN(PosYErr, posYErr, float); //! PV Y coordinate uncertainty +DECLARE_SOA_COLUMN(PosZErr, posZErr, float); //! PV Z coordinate uncertainty +DECLARE_SOA_COLUMN(McPosX, mcPosX, float); //! PV X coordinate uncertainty +DECLARE_SOA_COLUMN(McPosY, mcPosY, float); //! PV Y coordinate uncertainty +DECLARE_SOA_COLUMN(McPosZ, mcPosZ, float); //! PV Z coordinate uncertainty +} // namespace kf_collision + +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, + kf::MultNTracksPV, + kf::NSigTpcPr, + kf::NSigTpcKa, + kf::NSigTpcPi, + kf::NSigTofPr, + kf::NSigTofKa, + kf::NSigTofPi, + kf::NSigTpcTofPr, + kf::NSigTpcTofKa, + kf::NSigTpcTofPi); + 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::DecayLengthXYNormalised, 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, @@ -148,7 +259,10 @@ DECLARE_SOA_TABLE(HfCandLcLites, "AOD", "HFCANDLCLITE", full::OriginMcRec, full::IsCandidateSwapped, full::Channel, - full::MassKPi); + full::MassKPi, + full::MlScoreFirstClass, + full::MlScoreSecondClass, + full::MlScoreThirdClass); DECLARE_SOA_TABLE(HfCollIdLCLite, "AOD", "HFCOLLIDLCLITE", full::CollisionId); @@ -159,6 +273,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, @@ -225,7 +340,10 @@ DECLARE_SOA_TABLE(HfCandLcFulls, "AOD", "HFCANDLCFULL", full::IsCandidateSwapped, full::CandidateId, full::Channel, - full::MassKPi); + full::MassKPi, + full::MlScoreFirstClass, + full::MlScoreSecondClass, + full::MlScoreThirdClass); DECLARE_SOA_TABLE(HfCandLcFullEvs, "AOD", "HFCANDLCFULLEV", full::CollisionId, @@ -234,6 +352,12 @@ DECLARE_SOA_TABLE(HfCandLcFullEvs, "AOD", "HFCANDLCFULLEV", collision::PosX, collision::PosY, collision::PosZ, + kf_collision::PosXErr, + kf_collision::PosYErr, + kf_collision::PosZErr, + kf_collision::McPosX, + kf_collision::McPosY, + kf_collision::McPosZ, full::IsEventReject, full::RunNumber, full::CentFT0A, @@ -241,17 +365,25 @@ DECLARE_SOA_TABLE(HfCandLcFullEvs, "AOD", "HFCANDLCFULLEV", full::CentFT0M, full::CentFV0A, full::CentFDDM, - full::MultZeqNTracksPV); + full::MultZeqNTracksPV, + kf::MultNTracksPV); DECLARE_SOA_TABLE(HfCandLcFullPs, "AOD", "HFCANDLCFULLP", - full::McCollisionId, full::Pt, full::Eta, full::Phi, full::Y, full::FlagMc, full::OriginMcGen, - full::McParticleId); + mc_match::P, + mc_match::XDecay, + mc_match::YDecay, + mc_match::ZDecay, + mc_match::LDecay, + mc_match::TDecay, + mc_match::XEvent, + mc_match::YEvent, + mc_match::ZEvent); } // namespace o2::aod @@ -259,43 +391,98 @@ 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 keepOnlySignalMc{"keepOnlySignalMc", false, "Fill MC tree only with signal candidates"}; - Configurable keepOnlyBkg{"keepOnlyBkg", false, "Fill MC tree only with background candidates"}; + Configurable fillCandidateMcTable{"fillCandidateMcTable", false, "Switch to fill a table with MC particles matched to candidates"}; + Configurable applyMl{"applyMl", false, "Whether ML was used in candidateSelectorLc"}; + Configurable keepSignalMc{"keepSignalMc", false, "Fill MC tree with signal candidates"}; + Configurable keepBkgMc{"keepBkgMc", false, "Fill MC tree with background candidates"}; + Configurable keepCorrBkgMC{"keepCorrBkgMC", false, "Flag to keep correlated background sources (Λc+ -> p K− π+ π0, p π− π+, p K− K+ and other charm hadrons)"}; Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of candidates to store in the tree"}; Configurable downSampleBkgPtMax{"downSampleBkgPtMax", 100.f, "Max. pt for background downsampling"}; - HfHelper hfHelper; + constexpr static float UndefValueFloat = -999.f; + constexpr static int UndefValueInt = -999; + constexpr static float NanoToPico = 1000.f; 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) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::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 = {doprocessDataNoCentrality, doprocessDataWithCentrality, doprocessMcNoCentrality, doprocessMcWithCentrality}; + 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) != 0) && fillCandidateMcTable) { + LOGP(fatal, "fillCandidateMcTable can be activated only in case of MC processing."); + } } - /// \brief core function to fill tables in MC + /// \brief function to fill event properties /// \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&, - soa::Join const& candidates, - soa::Join const& particles, - TracksWPid const&, aod::BCs const&) + template + void fillEventProperties(Colls const& collisions) { - // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); for (const auto& collision : collisions) { @@ -305,7 +492,7 @@ struct HfTreeCreatorLcToPKPi { float centFT0M = -1.f; float centFV0A = -1.f; float centFDDM = -1.f; - if constexpr (useCentrality) { + if constexpr (UseCentrality) { centFT0A = collision.centFT0A(); centFT0C = collision.centFT0C(); centFT0M = collision.centFT0M(); @@ -313,13 +500,34 @@ struct HfTreeCreatorLcToPKPi { centFDDM = collision.centFDDM(); } + float mcPosX{UndefValueFloat}; + float mcPosY{UndefValueFloat}; + float mcPosZ{UndefValueFloat}; + int mcCollId{-1}; + + if constexpr (IsMc) { + auto mcCollision = collision.template mcCollision_as(); + + mcPosX = mcCollision.posX(); + mcPosY = mcCollision.posY(); + mcPosZ = mcCollision.posZ(); + + mcCollId = collision.mcCollisionId(); + } + rowCandidateFullEvents( collision.globalIndex(), - collision.mcCollisionId(), + mcCollId, collision.numContrib(), collision.posX(), collision.posY(), collision.posZ(), + std::sqrt(collision.covXX()), + std::sqrt(collision.covYY()), + std::sqrt(collision.covZZ()), + mcPosX, + mcPosY, + mcPosZ, 0, collision.bc().runNumber(), centFT0A, @@ -327,189 +535,494 @@ struct HfTreeCreatorLcToPKPi { centFT0M, centFV0A, centFDDM, - collision.multZeqNTracksPV()); + collision.multZeqNTracksPV(), + collision.multNTracksPV()); + } + } + + /// \brief function to reserve tables size + /// \param candidatesSize size of the candidates table + /// \param isMc boolean flag whether MC or data is processed + template + void reserveTables(size_t candidatesSize, bool isMc) + { + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::DCAFitter) { + if (fillCandidateLiteTable) { + rowCandidateLite.reserve(candidatesSize * 2); + } else { + rowCandidateFull.reserve(candidatesSize * 2); + } + } else { + rowCandidateKF.reserve(candidatesSize * 2); + } + if (fillCollIdTable) { + /// save also candidate collision indices + rowCollisionId.reserve(candidatesSize); + } + if (isMc && fillCandidateMcTable) { + rowCandidateMC.reserve(candidatesSize * 2); } + } - // Filling candidate properties - if (fillCandidateLiteTable) { - rowCandidateLite.reserve(candidates.size()); + /// \brief function to evaluate invariant mass of the Lc candidate and KPi pair + /// \param candidate candidate instance + /// \param candFlag flag indicating if PKPi (0) or PiKP (1) hypothesis is used + template + std::pair evaluateInvariantMassesDCAFitter(CandType const& candidate, int candFlag) + { + const float invMass = candFlag == 0 ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); + const float invMassKPi = candFlag == 0 ? HfHelper::invMassKPiPairLcToPKPi(candidate) : HfHelper::invMassKPiPairLcToPiKP(candidate); + + return std::make_pair(invMass, invMassKPi); + } + + /// \brief function to get ML score values for the current candidate and assign them to input parameters + /// \param candidate candidate instance + /// \param candidateMlScore instance of handler of vectors with ML scores associated with the current candidate + /// \param mlScoreFirstClass ML score for belonging to the first class + /// \param mlScoreSecondClass ML score for belonging to the second class + /// \param mlScoreThirdClass ML score for belonging to the third class + /// \param candFlag flag indicating if PKPi (0) or PiKP (1) hypothesis is used + void assignMlScores(aod::HfMlLcToPKPi::iterator const& candidateMlScore, float& mlScoreFirstClass, float& mlScoreSecondClass, float& mlScoreThirdClass, int candFlag) + { + std::vector mlScores; + if (candFlag == 0) { + std::copy(candidateMlScore.mlProbLcToPKPi().begin(), candidateMlScore.mlProbLcToPKPi().end(), std::back_inserter(mlScores)); } else { - rowCandidateFull.reserve(candidates.size()); + std::copy(candidateMlScore.mlProbLcToPiKP().begin(), candidateMlScore.mlProbLcToPiKP().end(), std::back_inserter(mlScores)); + } + constexpr int IndexFirstClass{0}; + constexpr int IndexSecondClass{1}; + constexpr int IndexThirdClass{2}; + if (mlScores.empty()) { + return; // when candidateSelectorLc rejects a candidate by "usual", non-ML cut, the ml score vector remains empty + } + mlScoreFirstClass = mlScores.at(IndexFirstClass); + mlScoreSecondClass = mlScores.at(IndexSecondClass); + if (mlScores.size() > IndexThirdClass) { + mlScoreThirdClass = mlScores.at(IndexThirdClass); + } + } + + /// \brief function to fill lite table + /// \param candidate candidate instance + /// \param candidateMlScore instance of handler of vectors with ML scores associated with the current candidate + /// \param candFlag flag indicating if PKPi (0) or PiKP (1) hypothesis is used + template + void fillLiteTable(CandType const& candidate, aod::HfMlLcToPKPi::iterator const& candidateMlScore, int candFlag) + { + auto [functionInvMass, functionInvMassKPi] = evaluateInvariantMassesDCAFitter(candidate, candFlag); + const float functionCt = HfHelper::ctLc(candidate); + const float functionY = HfHelper::yLc(candidate); + + int8_t functionFlagMcMatchRec{0}; + int8_t functionOriginMcRec{0}; + int8_t functionIsCandidateSwapped{0}; + int8_t functionFlagMcDecayChanRec{-1}; + + if constexpr (IsMc) { + functionFlagMcMatchRec = candidate.flagMcMatchRec(); + functionOriginMcRec = candidate.originMcRec(); + functionIsCandidateSwapped = candidate.isCandidateSwapped(); + functionFlagMcDecayChanRec = candidate.flagMcDecayChanRec(); + } + + float mlScoreFirstClass{UndefValueFloat}; + float mlScoreSecondClass{UndefValueFloat}; + float mlScoreThirdClass{UndefValueFloat}; + + if (applyMl) { + assignMlScores(candidateMlScore, mlScoreFirstClass, mlScoreSecondClass, mlScoreThirdClass, candFlag); } + + rowCandidateLite( + candidate.posX(), + candidate.posY(), + candidate.posZ(), + candidate.nProngsContributorsPV(), + candidate.bitmapProngsContributorsPV(), + candidate.chi2PCA(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthXYNormalised(), + candidate.ptProng0(), + candidate.ptProng1(), + candidate.ptProng2(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameter2(), + candidate.nSigTpcPi0(), + candidate.nSigTpcPr0(), + candidate.nSigTofPi0(), + candidate.nSigTofPr0(), + candidate.nSigTpcKa1(), + candidate.nSigTofKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTpcPr2(), + candidate.nSigTofPi2(), + candidate.nSigTofPr2(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaPr0(), + candidate.tpcTofNSigmaKa1(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaPr2(), + 1 << candFlag, + functionInvMass, + candidate.pt(), + candidate.cpa(), + candidate.cpaXY(), + functionCt, + candidate.eta(), + candidate.phi(), + functionY, + functionFlagMcMatchRec, + functionOriginMcRec, + functionIsCandidateSwapped, + functionFlagMcDecayChanRec, + functionInvMassKPi, + mlScoreFirstClass, + mlScoreSecondClass, + mlScoreThirdClass); + if (fillCollIdTable) { /// save also candidate collision indices - rowCollisionId.reserve(candidates.size()); + rowCollisionId(candidate.collisionId()); + } + } + + /// \brief function to fill lite table + /// \param candidate candidate instance + /// \param candidateMlScore instance of handler of vectors with ML scores associated with the current candidate + /// \param candFlag flag indicating if PKPi (0) or PiKP (1) hypothesis is used + template + void fillFullTable(CandType const& candidate, aod::HfMlLcToPKPi::iterator const& candidateMlScore, int candFlag) + { + auto [functionInvMass, functionInvMassKPi] = evaluateInvariantMassesDCAFitter(candidate, candFlag); + const float functionCt = HfHelper::ctLc(candidate); + const float functionY = HfHelper::yLc(candidate); + const float functionE = HfHelper::eLc(candidate); + + int8_t functionFlagMcMatchRec{0}; + int8_t functionOriginMcRec{0}; + int8_t functionIsCandidateSwapped{0}; + int8_t functionFlagMcDecayChanRec{-1}; + + if constexpr (IsMc) { + functionFlagMcMatchRec = candidate.flagMcMatchRec(); + functionOriginMcRec = candidate.originMcRec(); + functionIsCandidateSwapped = candidate.isCandidateSwapped(); + functionFlagMcDecayChanRec = candidate.flagMcDecayChanRec(); } + + float mlScoreFirstClass{UndefValueFloat}; + float mlScoreSecondClass{UndefValueFloat}; + float mlScoreThirdClass{UndefValueFloat}; + + if (applyMl) { + assignMlScores(candidateMlScore, mlScoreFirstClass, mlScoreSecondClass, mlScoreThirdClass, candFlag); + } + + rowCandidateFull( + candidate.collisionId(), + candidate.posX(), + candidate.posY(), + candidate.posZ(), + candidate.nProngsContributorsPV(), + candidate.bitmapProngsContributorsPV(), + 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.impactParameterNormalised2(), + candidate.ptProng2(), + 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.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameter2(), + candidate.errorImpactParameter0(), + candidate.errorImpactParameter1(), + candidate.errorImpactParameter2(), + candidate.nSigTpcPi0(), + candidate.nSigTpcPr0(), + candidate.nSigTofPi0(), + candidate.nSigTofPr0(), + candidate.nSigTpcKa1(), + candidate.nSigTofKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTpcPr2(), + candidate.nSigTofPi2(), + candidate.nSigTofPr2(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaPr0(), + candidate.tpcTofNSigmaKa1(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaPr2(), + 1 << candFlag, + functionInvMass, + candidate.pt(), + candidate.p(), + candidate.cpa(), + candidate.cpaXY(), + functionCt, + candidate.eta(), + candidate.phi(), + functionY, + functionE, + functionFlagMcMatchRec, + functionOriginMcRec, + functionIsCandidateSwapped, + candidate.globalIndex(), + functionFlagMcDecayChanRec, + functionInvMassKPi, + mlScoreFirstClass, + mlScoreSecondClass, + mlScoreThirdClass); + } + + /// \brief function to fill lite table + /// \param candidate candidate instance + /// \param collision collision, to which the candidate belongs + /// \param candFlag flag indicating if PKPi (0) or PiKP (1) hypothesis is used + /// \param functionSelection flag indicating if candidate was selected by candidateSelectorLc task + /// \param sigbgstatus for MC: number indicating if candidate is prompt, non-prompt or background; for data: UndefValueInt + template + void fillKFTable(CandType const& candidate, + CollType const& collision, + int candFlag, + int functionSelection, + int sigbgstatus) + { + float chi2primProton; + float chi2primPion; + float dcaProtonKaon; + float dcaPionKaon; + float chi2GeoProtonKaon; + float chi2GeoPionKaon; + float mass; + float valueTpcNSigmaPr; + const float valueTpcNSigmaKa = candidate.nSigTpcKa1(); + float valueTpcNSigmaPi; + float valueTofNSigmaPr; + const float valueTofNSigmaKa = candidate.nSigTofKa1(); + float valueTofNSigmaPi; + float valueTpcTofNSigmaPr; + const float valueTpcTofNSigmaKa = candidate.tpcTofNSigmaKa1(); + float valueTpcTofNSigmaPi; + if (candFlag == 0) { + chi2primProton = candidate.kfChi2PrimProng0(); + chi2primPion = candidate.kfChi2PrimProng2(); + dcaProtonKaon = candidate.kfDcaProng0Prong1(); + dcaPionKaon = candidate.kfDcaProng1Prong2(); + chi2GeoProtonKaon = candidate.kfChi2GeoProng0Prong1(); + chi2GeoPionKaon = candidate.kfChi2GeoProng1Prong2(); + mass = candidate.kfMassPKPi(); + valueTpcNSigmaPr = candidate.nSigTpcPr0(); + valueTpcNSigmaPi = candidate.nSigTpcPi2(); + valueTofNSigmaPr = candidate.nSigTofPr0(); + valueTofNSigmaPi = candidate.nSigTofPi2(); + valueTpcTofNSigmaPr = candidate.tpcTofNSigmaPr0(); + valueTpcTofNSigmaPi = candidate.tpcTofNSigmaPi2(); + } else { + chi2primProton = candidate.kfChi2PrimProng2(); + chi2primPion = candidate.kfChi2PrimProng0(); + dcaProtonKaon = candidate.kfDcaProng1Prong2(); + dcaPionKaon = candidate.kfDcaProng0Prong1(); + chi2GeoProtonKaon = candidate.kfChi2GeoProng1Prong2(); + chi2GeoPionKaon = candidate.kfChi2GeoProng0Prong1(); + mass = candidate.kfMassPiKP(); + valueTpcNSigmaPr = candidate.nSigTpcPr2(); + valueTpcNSigmaPi = candidate.nSigTpcPi0(); + valueTofNSigmaPr = candidate.nSigTofPr2(); + valueTofNSigmaPi = candidate.nSigTofPi0(); + valueTpcTofNSigmaPr = candidate.tpcTofNSigmaPr2(); + valueTpcTofNSigmaPi = candidate.tpcTofNSigmaPi0(); + } + 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 chi2primKaon = candidate.kfChi2PrimProng1(); + const float dcaProtonPion = candidate.kfDcaProng0Prong2(); + const float chi2GeoProtonPion = candidate.kfChi2GeoProng0Prong2(); + const float chi2Geo = candidate.kfChi2Geo(); + const float chi2Topo = candidate.kfChi2Topo(); + const float decayLength = 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 lifetime = decayLength * MassLambdaCPlus / LightSpeedCm2PS / p; + const float deltaT = dl * MassLambdaCPlus / LightSpeedCm2PS / p; + rowCandidateKF( + svX, svY, svZ, svErrX, svErrY, svErrZ, + pvErrX, pvErrY, pvErrZ, + chi2primProton, chi2primKaon, chi2primPion, + dcaProtonKaon, dcaProtonPion, dcaPionKaon, + chi2GeoProtonKaon, chi2GeoProtonPion, chi2GeoPionKaon, + chi2Geo, chi2Topo, decayLength, dl, decayLength / dl, lifetime, deltaT, + mass, p, pt, deltaP, deltaPt, + functionSelection, sigbgstatus, + collision.multNTracksPV(), + valueTpcNSigmaPr, + valueTpcNSigmaKa, + valueTpcNSigmaPi, + valueTofNSigmaPr, + valueTofNSigmaKa, + valueTofNSigmaPi, + valueTpcTofNSigmaPr, + valueTpcTofNSigmaKa, + valueTpcTofNSigmaPi); + } + + /// \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, + aod::HfMlLcToPKPi const& candidateMlScores, + soa::Join const& particles, + soa::Join const&, aod::BCs const&) + { + + constexpr bool IsMc = true; + + fillEventProperties(collisions); + + const size_t candidatesSize = candidates.size(); + reserveTables(candidatesSize, IsMc); + + int iCand{0}; 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, - float FunctionInvMassKPi) { - 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 candidateMlScore = candidateMlScores.rawIteratorAt(iCand); + ++iCand; + float ptProng0 = candidate.ptProng0(); + auto collision = candidate.template collision_as(); + auto fillTable = [&](int candFlag) { + double const pseudoRndm = ptProng0 * 1000. - static_cast(ptProng0 * 1000); + const int functionSelection = candFlag == 0 ? candidate.isSelLcToPKPi() : candidate.isSelLcToPiKP(); + const int sigbgstatus = determineSignalBgStatus(candidate, candFlag); + const bool isMcCandidateSignal = (sigbgstatus == Prompt) || (sigbgstatus == NonPrompt); + const bool passSelection = functionSelection >= selectionFlagLc; + const bool keepAll = !keepSignalMc && !keepBkgMc && !keepCorrBkgMC; + const int flag = candidate.flagMcMatchRec(); + const bool isCorrBkg = (std::abs(flag) != 0 && std::abs(flag) != o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) || sigbgstatus == WrongOrder; + const bool notSkippedBkg = isMcCandidateSignal || candidate.pt() > downSampleBkgPtMax || pseudoRndm < downSampleBkgFactor; + if (passSelection && notSkippedBkg && (keepAll || (keepSignalMc && isMcCandidateSignal) || (keepBkgMc && !isMcCandidateSignal) || (keepCorrBkgMC && isCorrBkg))) { if (fillCandidateLiteTable) { - rowCandidateLite( - candidate.posX(), - candidate.posY(), - candidate.posZ(), - candidate.nProngsContributorsPV(), - // candidate.errorDecayLength(), - // candidate.errorDecayLengthXY(), - 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(), - trackPos1.tofNSigmaPr(), - trackNeg.tpcNSigmaKa(), - trackNeg.tofNSigmaKa(), - trackPos2.tpcNSigmaPi(), - trackPos2.tpcNSigmaPr(), - trackPos2.tofNSigmaPi(), - trackPos2.tofNSigmaPr(), - trackPos1.tpcTofNSigmaPi(), - trackPos1.tpcTofNSigmaPr(), - trackNeg.tpcTofNSigmaKa(), - trackPos2.tpcTofNSigmaPi(), - trackPos2.tpcTofNSigmaPr(), - 1 << CandFlag, - FunctionInvMass, - candidate.pt(), - candidate.cpa(), - candidate.cpaXY(), - FunctionCt, - candidate.eta(), - candidate.phi(), - FunctionY, - candidate.flagMcMatchRec(), - candidate.originMcRec(), - candidate.isCandidateSwapped(), - candidate.flagMcDecayChanRec(), - FunctionInvMassKPi); - // candidate.globalIndex()); - - if (fillCollIdTable) { - /// save also candidate collision indices - rowCollisionId(candidate.collisionId()); - } - + fillLiteTable(candidate, candidateMlScore, candFlag); } else { - rowCandidateFull( - candidate.collisionId(), - candidate.posX(), - candidate.posY(), - candidate.posZ(), - candidate.nProngsContributorsPV(), - 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.impactParameterNormalised2(), - candidate.ptProng2(), - 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.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameter2(), - candidate.errorImpactParameter0(), - candidate.errorImpactParameter1(), - candidate.errorImpactParameter2(), - trackPos1.tpcNSigmaPi(), - trackPos1.tpcNSigmaPr(), - trackPos1.tofNSigmaPi(), - trackPos1.tofNSigmaPr(), - trackNeg.tpcNSigmaKa(), - trackNeg.tofNSigmaKa(), - trackPos2.tpcNSigmaPi(), - trackPos2.tpcNSigmaPr(), - trackPos2.tofNSigmaPi(), - trackPos2.tofNSigmaPr(), - trackPos1.tpcTofNSigmaPi(), - trackPos1.tpcTofNSigmaPr(), - trackNeg.tpcTofNSigmaKa(), - trackPos2.tpcTofNSigmaPi(), - trackPos2.tpcTofNSigmaPr(), - 1 << CandFlag, - FunctionInvMass, - candidate.pt(), - candidate.p(), - candidate.cpa(), - candidate.cpaXY(), - FunctionCt, - candidate.eta(), - candidate.phi(), - FunctionY, - FunctionE, - candidate.flagMcMatchRec(), - candidate.originMcRec(), - candidate.isCandidateSwapped(), - candidate.globalIndex(), - candidate.flagMcDecayChanRec(), - FunctionInvMassKPi); + fillFullTable(candidate, candidateMlScore, candFlag); + } + + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { + fillKFTable(candidate, collision, candFlag, functionSelection, sigbgstatus); + } + if (fillCandidateMcTable) { + float p, pt, svX, svY, svZ, pvX, pvY, pvZ, decayLength, lifetime; + if (!isMcCandidateSignal) { + p = UndefValueFloat; + pt = UndefValueFloat; + svX = UndefValueFloat; + svY = UndefValueFloat; + svZ = UndefValueFloat; + pvX = UndefValueFloat; + pvY = UndefValueFloat; + pvZ = UndefValueFloat; + decayLength = UndefValueFloat; + lifetime = 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(); + decayLength = RecoDecay::distance(std::array{svX, svY, svZ}, std::array{pvX, pvY, pvZ}); + lifetime = mcParticleProng0.vt() * NanoToPico / gamma; // from ns to ps * from lab time to proper time + } + rowCandidateMC( + p, pt, + svX, svY, svZ, decayLength, lifetime, + pvX, pvY, pvZ); } } }; - fillTable(0, candidate.isSelLcToPKPi(), hfHelper.invMassLcToPKPi(candidate), hfHelper.ctLc(candidate), hfHelper.yLc(candidate), hfHelper.eLc(candidate), hfHelper.invMassKPiPairLcToPKPi(candidate)); - fillTable(1, candidate.isSelLcToPiKP(), hfHelper.invMassLcToPiKP(candidate), hfHelper.ctLc(candidate), hfHelper.yLc(candidate), hfHelper.eLc(candidate), hfHelper.invMassKPiPairLcToPiKP(candidate)); + fillTable(0); + fillTable(1); } // Filling particle properties rowCandidateFullParticles.reserve(particles.size()); for (const auto& particle : particles) { - if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { + if (std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + auto mcDaughter0 = particle.template daughters_as>().begin(); + auto mcCollision = particle.template mcCollision_as(); + auto p = particle.p(); + const float p2m = p / MassLambdaCPlus; + const float gamma = std::sqrt(1 + p2m * p2m); // mother's particle Lorentz factor + const float pvX = mcCollision.posX(); + const float pvY = mcCollision.posY(); + const float pvZ = mcCollision.posZ(); + const float svX = mcDaughter0.vx(); + const float svY = mcDaughter0.vy(); + const float svZ = mcDaughter0.vz(); + const float l = RecoDecay::distance(std::array{svX, svY, svZ}, std::array{pvX, pvY, pvZ}); + const float t = mcDaughter0.vt() * NanoToPico / gamma; // from ns to ps * from lab time to proper time rowCandidateFullParticles( - particle.mcCollisionId(), particle.pt(), particle.eta(), particle.phi(), RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus), particle.flagMcMatchGen(), particle.originMcGen(), - particle.globalIndex()); + p, + svX, svY, svZ, l, t, + pvX, pvY, pvZ); } } } @@ -521,15 +1034,51 @@ struct HfTreeCreatorLcToPKPi { /// \param particles Generated particle table /// \param tracks Track table /// \param bcs Bunch-crossing table - void processMcNoCentrality(soa::Join const& collisions, - aod::McCollisions const& mcCollisions, - soa::Join const& candidates, - soa::Join const& particles, - TracksWPid const& tracks, aod::BCs const& bcs) + void processMcNoCentralityWithDCAFitterN(soa::Join const& collisions, + aod::McCollisions const& mcCollisions, + soa::Join const& candidates, + aod::HfMlLcToPKPi const& candidateMlScores, + soa::Join const& particles, + soa::Join const& tracks, aod::BCs const& bcs) + { + fillTablesMc(collisions, mcCollisions, candidates, candidateMlScores, 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, + aod::HfMlLcToPKPi const& candidateMlScores, + soa::Join const& particles, + soa::Join const& tracks, aod::BCs const& bcs) + { + fillTablesMc(collisions, mcCollisions, candidates, candidateMlScores, 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, + aod::HfMlLcToPKPi const& candidateMlScores, + soa::Join const& particles, + soa::Join const& tracks, aod::BCs const& bcs) { - fillTablesMc(collisions, mcCollisions, candidates, particles, tracks, bcs); + fillTablesMc(collisions, mcCollisions, candidates, candidateMlScores, particles, tracks, bcs); } - PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processMcNoCentrality, "Process MC tree writer w/o centrality", false); + 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 @@ -537,223 +1086,60 @@ struct HfTreeCreatorLcToPKPi { /// \param candidates Lc->pKpi candidate table /// \param tracks Track table /// \param bcs Bunch-crossing table - void processMcWithCentrality(soa::Join const& collisions, - aod::McCollisions const& mcCollisions, - soa::Join const& candidates, - soa::Join const& particles, - TracksWPid const& tracks, aod::BCs const& bcs) + void processMcWithCentralityWithKFParticle(soa::Join const& collisions, + aod::McCollisions const& mcCollisions, + soa::Join const& candidates, + aod::HfMlLcToPKPi const& candidateMlScores, + soa::Join const& particles, + soa::Join const& tracks, aod::BCs const& bcs) { - fillTablesMc(collisions, mcCollisions, candidates, particles, tracks, bcs); + fillTablesMc(collisions, mcCollisions, candidates, candidateMlScores, particles, tracks, bcs); } - PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processMcWithCentrality, "Process MC tree writer with centrality", false); + 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 + template void fillTablesData(Colls const& collisions, - soa::Join const& candidates, + CandType const& candidates, + aod::HfMlLcToPKPi const& candidateMlScores, TracksWPid const&, aod::BCs const&) { - // Filling event properties - rowCandidateFullEvents.reserve(collisions.size()); - for (const auto& collision : collisions) { + constexpr bool IsMc = false; - 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(); - } + fillEventProperties(collisions); - rowCandidateFullEvents( - collision.globalIndex(), - -1, - collision.numContrib(), - collision.posX(), - collision.posY(), - collision.posZ(), - 0, - collision.bc().runNumber(), - centFT0A, - centFT0C, - centFT0M, - centFV0A, - centFDDM, - collision.multZeqNTracksPV()); - } + const size_t candidatesSize = candidates.size(); + reserveTables(candidatesSize, IsMc); // Filling candidate properties - if (fillCandidateLiteTable) { - rowCandidateLite.reserve(candidates.size()); - } else { - rowCandidateFull.reserve(candidates.size()); - } - if (fillCollIdTable) { - /// save also candidate collision indices - rowCollisionId.reserve(candidates.size()); - } + + int iCand{0}; 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, - float FunctionInvMassKPi) { - double pseudoRndm = trackPos1.pt() * 1000. - (int64_t)(trackPos1.pt() * 1000); - if (FunctionSelection >= 1 && (candidate.pt() > downSampleBkgPtMax || (pseudoRndm < downSampleBkgFactor && candidate.pt() < downSampleBkgPtMax))) { + auto candidateMlScore = candidateMlScores.rawIteratorAt(iCand); + ++iCand; + float ptProng0 = candidate.ptProng0(); + auto collision = candidate.template collision_as(); + auto fillTable = [&](int candFlag) { + double const pseudoRndm = ptProng0 * 1000. - static_cast(ptProng0 * 1000); + const int functionSelection = candFlag == 0 ? candidate.isSelLcToPKPi() : candidate.isSelLcToPiKP(); + if (functionSelection >= selectionFlagLc && (candidate.pt() > downSampleBkgPtMax || (pseudoRndm < downSampleBkgFactor && candidate.pt() < downSampleBkgPtMax))) { if (fillCandidateLiteTable) { - rowCandidateLite( - candidate.posX(), - candidate.posY(), - candidate.posZ(), - candidate.nProngsContributorsPV(), - // candidate.errorDecayLength(), - // candidate.errorDecayLengthXY(), - 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(), - trackPos1.tofNSigmaPr(), - trackNeg.tpcNSigmaKa(), - trackNeg.tofNSigmaKa(), - trackPos2.tpcNSigmaPi(), - trackPos2.tpcNSigmaPr(), - trackPos2.tofNSigmaPi(), - trackPos2.tofNSigmaPr(), - trackPos1.tpcTofNSigmaPi(), - trackPos1.tpcTofNSigmaPr(), - trackNeg.tpcTofNSigmaKa(), - trackPos2.tpcTofNSigmaPi(), - trackPos2.tpcTofNSigmaPr(), - 1 << CandFlag, - FunctionInvMass, - candidate.pt(), - candidate.cpa(), - candidate.cpaXY(), - FunctionCt, - candidate.eta(), - candidate.phi(), - FunctionY, - 0., - 0., - 0., - -1, - FunctionInvMassKPi); - // candidate.globalIndex()); - - if (fillCollIdTable) { - /// save also candidate collision indices - rowCollisionId(candidate.collisionId()); - } - + fillLiteTable(candidate, candidateMlScore, candFlag); } else { - rowCandidateFull( - candidate.collisionId(), - candidate.posX(), - candidate.posY(), - candidate.posZ(), - candidate.nProngsContributorsPV(), - 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.impactParameterNormalised2(), - candidate.ptProng2(), - 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.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameter2(), - candidate.errorImpactParameter0(), - candidate.errorImpactParameter1(), - candidate.errorImpactParameter2(), - trackPos1.tpcNSigmaPi(), - trackPos1.tpcNSigmaPr(), - trackPos1.tofNSigmaPi(), - trackPos1.tofNSigmaPr(), - trackNeg.tpcNSigmaKa(), - trackNeg.tofNSigmaKa(), - trackPos2.tpcNSigmaPi(), - trackPos2.tpcNSigmaPr(), - trackPos2.tofNSigmaPi(), - trackPos2.tofNSigmaPr(), - trackPos1.tpcTofNSigmaPi(), - trackPos1.tpcTofNSigmaPr(), - trackNeg.tpcTofNSigmaKa(), - trackPos2.tpcTofNSigmaPi(), - trackPos2.tpcTofNSigmaPr(), - 1 << CandFlag, - FunctionInvMass, - candidate.pt(), - candidate.p(), - candidate.cpa(), - candidate.cpaXY(), - FunctionCt, - candidate.eta(), - candidate.phi(), - FunctionY, - FunctionE, - 0., - 0., - 0., - candidate.globalIndex(), - -1, - FunctionInvMassKPi); + fillFullTable(candidate, candidateMlScore, candFlag); + } + + if constexpr (ReconstructionType == aod::hf_cand::VertexerType::KfParticle) { + fillKFTable(candidate, collision, candFlag, functionSelection, UndefValueInt); } } }; - fillTable(0, candidate.isSelLcToPKPi(), hfHelper.invMassLcToPKPi(candidate), hfHelper.ctLc(candidate), hfHelper.yLc(candidate), hfHelper.eLc(candidate), hfHelper.invMassKPiPairLcToPKPi(candidate)); - fillTable(1, candidate.isSelLcToPiKP(), hfHelper.invMassLcToPiKP(candidate), hfHelper.ctLc(candidate), hfHelper.yLc(candidate), hfHelper.eLc(candidate), hfHelper.invMassKPiPairLcToPiKP(candidate)); + fillTable(0); + fillTable(1); } } @@ -762,26 +1148,56 @@ struct HfTreeCreatorLcToPKPi { /// \param candidates Lc->pKpi candidate table /// \param tracks Track table /// \param bcs Bunch-crossing table - void processDataNoCentrality(soa::Join const& collisions, - soa::Join const& candidates, - TracksWPid const& tracks, aod::BCs const& bcs) + void processDataNoCentralityWithDCAFitterN(soa::Join const& collisions, + soa::Join const& candidates, + aod::HfMlLcToPKPi const& candidateMlScores, + TracksWPid const& tracks, aod::BCs const& bcs) + { + fillTablesData(collisions, candidates, candidateMlScores, 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, + aod::HfMlLcToPKPi const& candidateMlScores, + TracksWPid const& tracks, aod::BCs const& bcs) + { + fillTablesData(collisions, candidates, candidateMlScores, 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, + aod::HfMlLcToPKPi const& candidateMlScores, + TracksWPid const& tracks, aod::BCs const& bcs) { - fillTablesData(collisions, candidates, tracks, bcs); + fillTablesData(collisions, candidates, candidateMlScores, tracks, bcs); } - PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processDataNoCentrality, "Process data tree writer w/o centrality", false); + 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 processDataWithCentrality(soa::Join const& collisions, - soa::Join const& candidates, - TracksWPid const& tracks, aod::BCs const& bcs) + void processDataWithCentralityWithKFParticle(soa::Join const& collisions, + soa::Join const& candidates, + aod::HfMlLcToPKPi const& candidateMlScores, + TracksWPid const& tracks, aod::BCs const& bcs) { - fillTablesData(collisions, candidates, tracks, bcs); + fillTablesData(collisions, candidates, candidateMlScores, tracks, bcs); } - PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processDataWithCentrality, "Process data tree writer with centrality", true); + PROCESS_SWITCH(HfTreeCreatorLcToPKPi, processDataWithCentralityWithKFParticle, "Process data tree writer with centrality with KFParticle", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/TableProducer/treeCreatorOmegacToOmegaKa.cxx b/PWGHF/TableProducer/treeCreatorOmegac0ToOmegaKa.cxx similarity index 95% rename from PWGHF/TableProducer/treeCreatorOmegacToOmegaKa.cxx rename to PWGHF/TableProducer/treeCreatorOmegac0ToOmegaKa.cxx index 0330cabc861..aaa3ee36337 100644 --- a/PWGHF/TableProducer/treeCreatorOmegacToOmegaKa.cxx +++ b/PWGHF/TableProducer/treeCreatorOmegac0ToOmegaKa.cxx @@ -9,19 +9,28 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file treeCreatorOmegacToOmegaKa.cxx +/// \file treeCreatorOmegac0ToOmegaKa.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 "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; @@ -86,7 +95,7 @@ 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(OriginMcRec, originMcRec, int8_t); DECLARE_SOA_COLUMN(CollisionMatched, collisionMatched, bool); // from selector DECLARE_SOA_COLUMN(PidTpcInfoStored, pidTpcInfoStored, int); @@ -127,7 +136,7 @@ DECLARE_SOA_TABLE(HfOmegac0ToOmegaKaLites, "AOD", "HFTOOMEKALITE", 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); + full::FlagMcMatchRec, full::OriginMcRec, full::CollisionMatched); } // namespace o2::aod @@ -255,7 +264,7 @@ struct HfTreeCreatorOmegac0ToOmegaKa { // 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.originMcRec(), candidate.collisionMatched()); } } PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaKa, processMcLite, "Process MC", false); diff --git a/PWGHF/TableProducer/treeCreatorOmegac0ToOmegaPi.cxx b/PWGHF/TableProducer/treeCreatorOmegac0ToOmegaPi.cxx new file mode 100644 index 00000000000..cf8cf1242e2 --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorOmegac0ToOmegaPi.cxx @@ -0,0 +1,709 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file treeCreatorOmegac0ToOmegaPi.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 +/// \author Ruiqi Yin , Fudan University + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +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(OriginMcRec, originMcRec, 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, cent::CentFT0M, + 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::OriginMcRec, 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::OriginMcRec, full::CollisionMatched, hf_track_index::HFflag, collision::NumContrib, cent::CentFT0M); + +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::OriginMcRec, full::CollisionMatched, hf_track_index::HFflag, collision::NumContrib, cent::CentFT0M); +} // namespace o2::aod + +/// Writes the full information in an output TTree +struct HfTreeCreatorOmegac0ToOmegaPi { + + 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 CandSel = soa::Filtered>; + using CandKfSel = soa::Filtered>; + using CandMcSel = soa::Filtered>; + using CandKfMcSel = soa::Filtered>; + + using Colls = soa::Join; + using CollsWithFT0M = soa::Join; + using CollsWithMcLabels = soa::Join; + using McCollsWithFT0M = soa::Join; + + 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 C& collision, float cutZPv) + { + rowEv(collision.sel8(), std::abs(collision.posZ()) < cutZPv); + } + + template + void fillCandidateLite(const P& candidate, const C&, int8_t flagMc, int8_t originMc, bool collisionMatched, float centFt0m) + { + 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(), + centFt0m, + 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 P& candidate, const C&, int8_t flagMc, int8_t originMc, bool collisionMatched, float centFt0m) + { + 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(), + candidate.template collision_as().numContrib(), + centFt0m); + } + } + + template + void fillKfCandidateLite(const P& candidate, const C&, int8_t flagMc, int8_t originMc, bool collisionMatched, float centFt0m) + { + 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(), + candidate.template collision_as().numContrib(), + centFt0m); + } + } // fillKfCandidateLite end + + void processData(Colls const& collisions, + CandSel const& candidates, + Tracks const&) + { + // 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, collisions, -7, RecoDecay::OriginType::None, false, -1.); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processData, "Process data", false); + + void processKfData(Colls const& collisions, + 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, collisions, -7, RecoDecay::OriginType::None, false, -1.); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKfData, "Process KF data", false); + + void processKfDataLite(Colls const& collisions, + CandKfSel const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowKfCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillKfCandidateLite(candidate, collisions, -7, RecoDecay::OriginType::None, false, -1.); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKfDataLite, "Process KF data lite", false); + + void processDataCent(CollsWithFT0M const& collisions, + CandSel const& candidates, + Tracks const&) + { + // 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) { + auto collision = candidate.collision_as(); + float centFt0m = o2::hf_centrality::getCentralityColl(collision); + fillCandidateLite(candidate, collisions, -7, RecoDecay::OriginType::None, false, centFt0m); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processDataCent, "Process data with FT0M info", false); + + void processKfDataCent(CollsWithFT0M const& collisions, + 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) { + auto collision = candidate.collision_as(); + float centFt0m = o2::hf_centrality::getCentralityColl(collision); + fillKfCandidate(candidate, collisions, -7, RecoDecay::OriginType::None, false, centFt0m); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKfDataCent, "Process KF data with FT0M info", false); + + void processKfDataCentLite(CollsWithFT0M const& collisions, + CandKfSel const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowKfCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + auto collision = candidate.collision_as(); + float centFt0m = o2::hf_centrality::getCentralityColl(collision); + fillKfCandidateLite(candidate, collisions, -7, RecoDecay::OriginType::None, false, centFt0m); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKfDataCentLite, "Process KF data lite with FT0M info", false); + + void processMc(Colls const& collisions, + CandMcSel const& candidates, + Tracks const&) + { + // 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 && candidate.originMcRec() == RecoDecay::OriginType::None) { + continue; + } + fillCandidateLite(candidate, collisions, candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.collisionMatched(), -1.); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processMc, "Process MC", false); + + void processKFMc(Colls const& collisions, + CandKfMcSel 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) { + if (keepOnlyMcSignal && candidate.originMcRec() == RecoDecay::OriginType::None) { + continue; + } + fillKfCandidate(candidate, collisions, candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.collisionMatched(), -1.); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKFMc, "Process KF MC", false); + + void processKFMcLite(Colls const& collisions, + CandKfMcSel const& candidates) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowKfCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + if (keepOnlyMcSignal && candidate.originMcRec() == RecoDecay::OriginType::None) { + continue; + } + fillKfCandidateLite(candidate, collisions, candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.collisionMatched(), -1.); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKFMcLite, "Process KF MC Lite", false); + + void processMcCent(CollsWithMcLabels const& collisions, + CandMcSel const& candidates, + Tracks const&, + McCollsWithFT0M const&) + { + // 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 && candidate.originMcRec() == RecoDecay::OriginType::None) { + continue; + } + auto mcCollision = candidate.collision_as().mcCollision_as(); + float centFt0m = o2::hf_centrality::getCentralityColl(mcCollision); + fillCandidateLite(candidate, collisions, candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.collisionMatched(), centFt0m); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processMcCent, "Process MC with FT0M info", false); + + void processKFMcCent(CollsWithMcLabels const& collisions, + CandKfMcSel const& candidates, + McCollsWithFT0M const&) + { + // 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) { + if (keepOnlyMcSignal && candidate.originMcRec() == RecoDecay::OriginType::None) { + continue; + } + auto mcCollision = candidate.collision_as().mcCollision_as(); + float centFt0m = o2::hf_centrality::getCentralityColl(mcCollision); + fillKfCandidate(candidate, collisions, candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.collisionMatched(), centFt0m); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKFMcCent, "Process KF MC with FT0M info", false); + + void processKFMcCentLite(CollsWithMcLabels const& collisions, + CandKfMcSel const& candidates, + McCollsWithFT0M const&) + { + // Filling event properties + rowEv.reserve(collisions.size()); + for (const auto& collision : collisions) { + fillEvent(collision, zPvCut); + } + + // Filling candidate properties + rowKfCandidateLite.reserve(candidates.size()); + for (const auto& candidate : candidates) { + if (keepOnlyMcSignal && candidate.originMcRec() == RecoDecay::OriginType::None) { + continue; + } + auto mcCollision = candidate.collision_as().mcCollision_as(); + float centFt0m = o2::hf_centrality::getCentralityColl(mcCollision); + fillKfCandidateLite(candidate, collisions, candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.collisionMatched(), centFt0m); + } + } + PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKFMcCentLite, "Process KF MC Lite with FT0M info", false); + +}; // end of struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/treeCreatorOmegacSt.cxx b/PWGHF/TableProducer/treeCreatorOmegacSt.cxx index b91f65cb654..b443d8abc5a 100644 --- a/PWGHF/TableProducer/treeCreatorOmegacSt.cxx +++ b/PWGHF/TableProducer/treeCreatorOmegacSt.cxx @@ -9,37 +9,62 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file taskOmegacSt.cxx -/// \brief Task to reconstruct Ωc from strangeness-tracked Ω and pion +/// \file treeCreatorOmegacSt.cxx +/// \brief Task to reconstruct Ωc from strangeness-tracked Ω and pion/kaon /// /// \author Jochen Klein +/// \author Tiantian Cheng -#include -#include +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGLF/DataModel/LFStrangenessTables.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/ASoA.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" -#include "ReconstructionDataFormats/DCA.h" -#include "Common/DataModel/EventSelection.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" #include "Common/Core/trackUtilities.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/CollisionAssociationTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGHF/Core/SelectorCuts.h" -#include "PWGHF/Utils/utilsTrkCandHf.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -62,6 +87,8 @@ DECLARE_SOA_COLUMN(DecayLengthCharmedBaryon, decayLengthCharmedBaryon, float); DECLARE_SOA_COLUMN(DecayLengthXYCharmedBaryon, decayLengthXYCharmedBaryon, float); DECLARE_SOA_COLUMN(DecayLengthCasc, decayLengthCasc, float); DECLARE_SOA_COLUMN(DecayLengthXYCasc, decayLengthXYCasc, float); +DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int); +DECLARE_SOA_COLUMN(DecayChannel, decayChannel, int); } // namespace hf_st_charmed_baryon_gen DECLARE_SOA_TABLE(HfStChBarGens, "AOD", "HFSTCHBARGEN", @@ -76,9 +103,11 @@ DECLARE_SOA_TABLE(HfStChBarGens, "AOD", "HFSTCHBARGEN", hf_st_charmed_baryon_gen::DecayLengthCharmedBaryon, hf_st_charmed_baryon_gen::DecayLengthXYCharmedBaryon, hf_st_charmed_baryon_gen::DecayLengthCasc, - hf_st_charmed_baryon_gen::DecayLengthXYCasc); + hf_st_charmed_baryon_gen::DecayLengthXYCasc, + hf_st_charmed_baryon_gen::OriginMcGen, + hf_st_charmed_baryon_gen::DecayChannel); -// CharmedBaryon -> Casc + Pion +// CharmedBaryon -> Casc + Pion/Kaon // -> Lambda + BachPi/BachKa // -> Pr + Pi namespace hf_st_charmed_baryon @@ -88,6 +117,8 @@ DECLARE_SOA_COLUMN(MassXi, massXi, float); DECLARE_SOA_COLUMN(MassLambda, massLambda, float); DECLARE_SOA_COLUMN(NSigmaTpcPion, nSigmaTpcPion, float); DECLARE_SOA_COLUMN(NSigmaTofPion, nSigmaTofPion, float); +DECLARE_SOA_COLUMN(NSigmaTpcKaon, nSigmaTpcKaon, float); +DECLARE_SOA_COLUMN(NSigmaTofKaon, nSigmaTofKaon, float); DECLARE_SOA_COLUMN(NSigmaTpcV0Pr, nSigmaTpcV0Pr, float); DECLARE_SOA_COLUMN(NSigmaTofV0Pr, nSigmaTofV0Pr, float); DECLARE_SOA_COLUMN(NSigmaTpcV0Pi, nSigmaTpcV0Pi, float); @@ -100,11 +131,11 @@ DECLARE_SOA_COLUMN(PxCasc, pxCasc, float); DECLARE_SOA_COLUMN(PyCasc, pyCasc, float); DECLARE_SOA_COLUMN(PzCasc, pzCasc, float); DECLARE_SOA_COLUMN(IsPositiveCasc, isPositiveCasc, bool); -DECLARE_SOA_COLUMN(PxPion, pxPion, float); -DECLARE_SOA_COLUMN(PyPion, pyPion, float); -DECLARE_SOA_COLUMN(PzPion, pzPion, float); -DECLARE_SOA_COLUMN(IsPositivePion, isPositivePion, bool); -DECLARE_SOA_COLUMN(ITSClusterMapPion, itsClusterMapPion, uint8_t); +DECLARE_SOA_COLUMN(PxPionOrKaon, pxPionOrKaon, float); +DECLARE_SOA_COLUMN(PyPionOrKaon, pyPionOrKaon, float); +DECLARE_SOA_COLUMN(PzPionOrKaon, pzPionOrKaon, float); +DECLARE_SOA_COLUMN(IsPositivePionOrKaon, isPositivePionOrKaon, bool); +DECLARE_SOA_COLUMN(ItsClusterMapPionOrKaon, itsClusterMapPionOrKaon, uint8_t); DECLARE_SOA_COLUMN(CpaCharmedBaryon, cpaCharmedBaryon, float); DECLARE_SOA_COLUMN(CpaXYCharmedBaryon, cpaXYCharmedBaryon, float); DECLARE_SOA_COLUMN(CpaCasc, cpaCasc, float); @@ -113,10 +144,10 @@ DECLARE_SOA_COLUMN(DcaXYCasc, dcaXYCasc, float); DECLARE_SOA_COLUMN(DcaXYUncCasc, dcaXYUncCasc, float); DECLARE_SOA_COLUMN(DcaZCasc, dcaZCasc, float); DECLARE_SOA_COLUMN(DcaZUncCasc, dcaZUncCasc, float); -DECLARE_SOA_COLUMN(DcaXYPion, dcaXYPion, float); -DECLARE_SOA_COLUMN(DcaXYUncPion, dcaXYUncPion, float); -DECLARE_SOA_COLUMN(DcaZPion, dcaZPion, float); -DECLARE_SOA_COLUMN(DcaZUncPion, dcaZUncPion, float); +DECLARE_SOA_COLUMN(DcaXYPionOrKaon, dcaXYPionOrKaon, float); +DECLARE_SOA_COLUMN(DcaXYUncPionOrKaon, dcaXYUncPionOrKaon, float); +DECLARE_SOA_COLUMN(DcaZPionOrKaon, dcaZPionOrKaon, float); +DECLARE_SOA_COLUMN(DcaZUncPionOrKaon, dcaZUncPionOrKaon, float); DECLARE_SOA_COLUMN(DcaXYPr, dcaXYPr, float); DECLARE_SOA_COLUMN(DcaZPr, dcaZPr, float); DECLARE_SOA_COLUMN(DcaXYKa, dcaXYKa, float); @@ -127,10 +158,14 @@ 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); DECLARE_SOA_INDEX_COLUMN_FULL(MotherCasc, motherCasc, int, HfStChBarGens, "_Casc"); -DECLARE_SOA_INDEX_COLUMN_FULL(MotherPion, motherPion, int, HfStChBarGens, "_Pion"); +DECLARE_SOA_INDEX_COLUMN_FULL(MotherPionOrKaon, motherPionOrKaon, int, HfStChBarGens, "_PionOrKaon"); +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int); +DECLARE_SOA_COLUMN(ToiMask, toiMask, uint32_t); } // namespace hf_st_charmed_baryon DECLARE_SOA_TABLE(HfStChBars, "AOD", "HFSTCHBAR", @@ -139,6 +174,8 @@ DECLARE_SOA_TABLE(HfStChBars, "AOD", "HFSTCHBAR", hf_st_charmed_baryon::MassLambda, hf_st_charmed_baryon::NSigmaTpcPion, hf_st_charmed_baryon::NSigmaTofPion, + hf_st_charmed_baryon::NSigmaTpcKaon, + hf_st_charmed_baryon::NSigmaTofKaon, hf_st_charmed_baryon::NSigmaTpcV0Pr, hf_st_charmed_baryon::NSigmaTofV0Pr, hf_st_charmed_baryon::NSigmaTpcV0Pi, @@ -151,11 +188,11 @@ DECLARE_SOA_TABLE(HfStChBars, "AOD", "HFSTCHBAR", 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::PxPionOrKaon, + hf_st_charmed_baryon::PyPionOrKaon, + hf_st_charmed_baryon::PzPionOrKaon, + hf_st_charmed_baryon::IsPositivePionOrKaon, + hf_st_charmed_baryon::ItsClusterMapPionOrKaon, hf_st_charmed_baryon::CpaCharmedBaryon, hf_st_charmed_baryon::CpaXYCharmedBaryon, hf_st_charmed_baryon::CpaCasc, @@ -164,10 +201,10 @@ DECLARE_SOA_TABLE(HfStChBars, "AOD", "HFSTCHBAR", 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::DcaXYPionOrKaon, + hf_st_charmed_baryon::DcaXYUncPionOrKaon, + hf_st_charmed_baryon::DcaZPionOrKaon, + hf_st_charmed_baryon::DcaZUncPionOrKaon, hf_st_charmed_baryon::DcaXYPr, hf_st_charmed_baryon::DcaZPr, hf_st_charmed_baryon::DcaXYKa, @@ -178,10 +215,14 @@ DECLARE_SOA_TABLE(HfStChBars, "AOD", "HFSTCHBAR", 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); + hf_st_charmed_baryon::MotherPionOrKaonId, + hf_st_charmed_baryon::OriginMcRec, + hf_st_charmed_baryon::ToiMask); } // namespace o2::aod struct HfTreeCreatorOmegacSt { @@ -195,13 +236,14 @@ 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"}; Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; Configurable minNoClsTrackedCascade{"minNoClsTrackedCascade", 70, "Minimum number of clusters required for daughters of tracked cascades"}; - Configurable minNoClsTrackedPion{"minNoClsTrackedPion", 70, "Minimum number of clusters required for associated pions"}; - Configurable filterCollisions{"filterCollisions", 8, "0: no filtering; 8: sel8"}; + Configurable minNoClsTrackedPionOrKaon{"minNoClsTrackedPionOrKaon", 70, "Minimum number of clusters required for associated pions/kaons"}; + Configurable useSel8Trigger{"useSel8Trigger", true, "filter collisions on sel 8 trigger"}; Configurable massWindowTrackedOmega{"massWindowTrackedOmega", 0.05, "Inv. mass window for tracked Omega"}; Configurable massWindowXiExclTrackedOmega{"massWindowXiExclTrackedOmega", 0.005, "Inv. mass window for exclusion of Xi for tracked Omega-"}; Configurable massWindowTrackedXi{"massWindowTrackedXi", 0., "Inv. mass window for tracked Xi"}; @@ -214,13 +256,20 @@ struct HfTreeCreatorOmegacSt { Configurable maxNSigmaV0Pr{"maxNSigmaV0Pr", 5., "Max Nsigma for proton from V0 from tracked cascade"}; Configurable maxNSigmaV0Pi{"maxNSigmaV0Pi", 5., "Max Nsigma for pion from V0 from tracked cascade"}; Configurable maxNSigmaPion{"maxNSigmaPion", 5., "Max Nsigma for pion to be paired with Omega"}; + Configurable maxNSigmaKaon{"maxNSigmaKaon", 5., "Max Nsigma for kaon to be paired with Omega"}; Configurable bzOnly{"bzOnly", true, "Use B_z instead of full field map"}; + Configurable cfgTriggersOfInterest{"cfgTriggersOfInterest", "fTrackedOmega,fHfCharmBarToXiBach", "Triggers of interest, comma separated for Zorro"}; SliceCache cache; Service ccdb; o2::vertexing::DCAFitterN<2> df2; - float bz = 0.; + static constexpr int ItsNClsMin{4}; + static constexpr float TpcNclsFindableFraction{0.8f}; + static constexpr float TpcChi2NclMax{4.f}; + static constexpr float ItsChi2NclMax{36.f}; + + float bz{0.f}; int runNumber{0}; std::map mapMcPartToGenTable; @@ -228,14 +277,13 @@ struct HfTreeCreatorOmegacSt { using TracksExt = soa::Join; using TracksExtMc = soa::Join; - Filter collisionFilter = (filterCollisions.node() == 0) || - (filterCollisions.node() == 8 && o2::aod::evsel::sel8 == true); + Filter collisionFilter = (useSel8Trigger.node() == false) || (o2::aod::evsel::sel8 == true); // Preslice perCol = aod::track::collisionId; PresliceUnsorted trackIndicesPerCollision = aod::track_association::collisionId; PresliceUnsorted assignedTrackedCascadesPerCollision = aod::track::collisionId; - std::shared_ptr hCandidatesPrPi, hCandidatesV0Pi, hCandidatesCascPi; + std::shared_ptr hCandidatesPrPi, hCandidatesV0Pi, hCandidatesCascPiOrK; HistogramRegistry registry{ "registry", { @@ -254,14 +302,19 @@ struct HfTreeCreatorOmegacSt { {"hDecayLengthScaledId", "Decay length * M/p (true #Omega_{c});L (#mum / #it{c})", {HistType::kTH1D, {{200, 0., 500.}}}}, {"hDecayLengthScaledGen", "Decay length * M/p (MC id);L (#mum / #it{c})", {HistType::kTH1D, {{200, 0., 500.}}}}, {"hDecayLengthScaledMc", "Decay length * M/p (MC);L (#mum / #it{c})", {HistType::kTH1D, {{200, 0., 500.}}}}, - {"hMassOmegac", "inv. mass #Omega + #pi;inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.5, 3.}}}}, - {"hMassOmegacVsPt", "inv. mass #Omega + #pi;inv. mass (GeV/#it{c}^{2});p_{T} (GeV/#it{c})", {HistType::kTH2D, {{400, 1.5, 3.}, {10, 0., 10.}}}}, + {"hMassOmegaPi", "inv. mass #Omega + #pi;inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.5, 3.}}}}, + {"hMassOmegaPiVsPt", "inv. mass #Omega + #pi;inv. mass (GeV/#it{c}^{2});p_{T} (GeV/#it{c})", {HistType::kTH2D, {{400, 1.5, 3.}, {10, 0., 10.}}}}, + {"hMassOmegaK", "inv. mass #Omega + K;inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.5, 3.}}}}, + {"hMassOmegaKVsPt", "inv. mass #Omega + K;inv. mass (GeV/#it{c}^{2});p_{T} (GeV/#it{c})", {HistType::kTH2D, {{400, 1.5, 3.}, {10, 0., 10.}}}}, {"hMassOmegacId", "inv. mass #Omega + #pi (MC ID);inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.5, 3.}}}}, {"hMassOmegacGen", "inv. mass #Omega + #pi (from MC);inv. mass (GeV/#it{c}^{2})", {HistType::kTH1D, {{400, 1.5, 3.}}}}, {"hPtVsMassOmega", "#Omega mass;p_{T} (GeV/#it{c});m (GeV/#it{c}^3)", {HistType::kTH2D, {{200, 0., 10.}, {1000, 1., 3.}}}}, {"hDeltaPtVsPt", "Delta pt;p_{T} (GeV/#it{c});#Delta p_{T} / p_{T}", {HistType::kTH2D, {{200, 0., 10.}, {200, -1., 1.}}}}, }}; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + void init(InitContext const&) { df2.setPropagateToPCA(propToDCA); @@ -284,15 +337,27 @@ struct HfTreeCreatorOmegacSt { /// candidate monitoring hCandidatesPrPi = registry.add("hCandidatesPrPi", "Pr-Pi candidates counter", {HistType::kTH1D, {axisCands}}); hCandidatesV0Pi = registry.add("hCandidatesV0Pi", "V0-Pi candidates counter", {HistType::kTH1D, {axisCands}}); - hCandidatesCascPi = registry.add("hCandidatesCascPi", "Casc-Pi candidates counter", {HistType::kTH1D, {axisCands}}); + hCandidatesCascPiOrK = registry.add("hCandidatesCascPiOrK", "Casc-Pi/K candidates counter", {HistType::kTH1D, {axisCands}}); setLabelHistoCands(hCandidatesPrPi); setLabelHistoCands(hCandidatesV0Pi); - setLabelHistoCands(hCandidatesCascPi); + setLabelHistoCands(hCandidatesCascPiOrK); } // processMC: loop over MC objects // processData: loop over reconstructed objects, no MC information // processGen: loop over reconstructed objects, use MC information (mutually exclusive? combine?) + int indexRec = -1; + int indexRecCharmBaryon = -1; + int8_t sign = -9; + int8_t signCasc = -9; + int8_t signV0 = -9; + int8_t origin = 0; // to be used for prompt/non prompt + int8_t nPiToMuV0{0}, nPiToMuCasc{0}, nPiToMuOmegac0{0}; + int8_t nKaToPiCasc{0}, nKaToPiOmegac0{0}; + std::vector idxBhadMothers; + int decayChannel = -1; // flag for different decay channels + bool isMatched = false; + static constexpr std::size_t NDaughters{2u}; void processMc(aod::McCollisions const&, aod::McParticles const& mcParticles) @@ -303,9 +368,10 @@ struct HfTreeCreatorOmegacSt { const bool isXiC = std::abs(mcParticle.pdgCode()) == constants::physics::Pdg::kXiC0; if (isOmegaC || isXiC) { const auto daughters = mcParticle.daughters_as(); - if (daughters.size() == 2) { + if (daughters.size() == NDaughters) { int idxPionDaughter = -1; int idxCascDaughter = -1; + int idxKaonDaughter = -1; const auto daughters = mcParticle.daughters_as(); for (const auto& daughter : daughters) { if (idxCascDaughter < 0 && (std::abs(daughter.pdgCode()) == (isOmegaC ? kOmegaMinus : kXiMinus))) { @@ -314,17 +380,31 @@ struct HfTreeCreatorOmegacSt { if (idxPionDaughter < 0 && (std::abs(daughter.pdgCode()) == kPiPlus)) { idxPionDaughter = daughter.globalIndex(); } + if (idxKaonDaughter < 0 && (std::abs(daughter.pdgCode()) == kKPlus)) { + idxKaonDaughter = daughter.globalIndex(); + } } - if ((idxPionDaughter >= 0) && (idxCascDaughter >= 0)) { + if (idxPionDaughter >= 0 && idxCascDaughter >= 0) { + decayChannel = o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi; // OmegaC -> Omega + Pi + } else if (idxKaonDaughter >= 0 && idxCascDaughter >= 0) { + decayChannel = o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK; // OmegaC -> Omega + K + } else { + decayChannel = -1; // LOG(warning) << "Decay channel not recognized!"; + } + if (decayChannel != -1) { + int const idxDaughter = (decayChannel == o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) ? idxPionDaughter : idxKaonDaughter; + auto particle = mcParticles.rawIteratorAt(idxDaughter); + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + 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()}; + std::array const primaryVertexPosGen = {mcColl.posX(), mcColl.posY(), mcColl.posZ()}; + std::array const 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()}; + std::array const tertiaryVertexGen = {cascDecayDaughter.vx(), cascDecayDaughter.vy(), cascDecayDaughter.vz()}; decayLengthCascGen = RecoDecay::distance(tertiaryVertexGen, primaryVertexPosGen); decayLengthXYCascGen = RecoDecay::distanceXY(tertiaryVertexGen, primaryVertexPosGen); } @@ -343,7 +423,9 @@ struct HfTreeCreatorOmegacSt { decayLengthGen, decayLengthXYGen, decayLengthCascGen, - decayLengthXYCascGen); + decayLengthXYCascGen, + origin, + decayChannel); mapMcPartToGenTable[mcParticle.globalIndex()] = outputTableGen.lastIndex(); } } @@ -355,20 +437,28 @@ struct HfTreeCreatorOmegacSt { template void fillTable(Collisions const& collisions, aod::AssignedTrackedCascades const& trackedCascades, - aod::TrackAssoc const& trackIndices) + aod::TrackAssoc const& trackIndices, + std::optional> mcParticles = std::nullopt) { 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(), cfgTriggersOfInterest.value); + zorro.populateHistRegistry(registry, bc.runNumber()); + } runNumber = bc.runNumber(); auto timestamp = bc.timestamp(); - if (o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, timestamp)) { + if (auto* grpo = ccdb->getForTimeStamp(grpPath, timestamp)) { o2::base::Propagator::initFieldFromGRP(grpo); bz = grpo->getNominalL3Field(); - } else if (o2::parameters::GRPMagField* grpmag = ccdb->getForTimeStamp(grpMagPath, timestamp)) { + } else if (auto* grpmag = ccdb->getForTimeStamp(grpMagPath, timestamp)) { o2::base::Propagator::initFieldFromGRP(grpmag); bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); } else { @@ -376,6 +466,16 @@ struct HfTreeCreatorOmegacSt { } df2.setBz(bz); } + uint32_t toiMask = 0; + if (skimmedProcessing) { + bool const sel = zorro.isSelected(bc.globalBC()); + if (sel) { + std::vector toivect = zorro.getTriggerOfInterestResults(); + for (size_t i{0}; i < toivect.size(); i++) { + toiMask |= static_cast(toivect[i]) << i; + } + } + } const auto primaryVertex = getPrimaryVertex(collision); const std::array primaryVertexPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; @@ -431,15 +531,15 @@ struct HfTreeCreatorOmegacSt { } hCandidatesPrPi->Fill(SVFitting::FitOk); - std::array massesV0Daughters{o2::constants::physics::MassProton, o2::constants::physics::MassPiMinus}; - std::array, 2> momentaV0Daughters; - o2::track::TrackPar trackParV0Pr = df2.getTrackParamAtPCA(0); + std::array const massesV0Daughters{o2::constants::physics::MassProton, o2::constants::physics::MassPiMinus}; + std::array, NDaughters> momentaV0Daughters{}; + o2::track::TrackPar const trackParV0Pr = df2.getTrackParamAtPCA(0); trackParV0Pr.getPxPyPzGlo(momentaV0Daughters[0]); - o2::track::TrackPar trackParV0Pi = df2.getTrackParamAtPCA(1); + o2::track::TrackPar const trackParV0Pi = df2.getTrackParamAtPCA(1); trackParV0Pi.getPxPyPzGlo(momentaV0Daughters[1]); const auto massV0 = RecoDecay::m(momentaV0Daughters, massesV0Daughters); - o2::track::TrackParCov trackParCovV0 = df2.createParentTrackParCov(0); + o2::track::TrackParCov const trackParCovV0 = df2.createParentTrackParCov(0); hCandidatesV0Pi->Fill(SVFitting::BeforeFit); try { if (!df2.process(trackParCovV0, getTrackParCov(bachelor))) { @@ -455,19 +555,20 @@ struct HfTreeCreatorOmegacSt { const auto& secondaryVertex = df2.getPCACandidate(); const auto decayLengthCasc = RecoDecay::distance(secondaryVertex, primaryVertexPos); const auto decayLengthCascXY = RecoDecay::distanceXY(secondaryVertex, primaryVertexPos); - o2::track::TrackPar trackParV0 = df2.getTrackParamAtPCA(0); - o2::track::TrackPar trackParBachelor = df2.getTrackParamAtPCA(1); - std::array, 2> momentaCascDaughters; + o2::track::TrackPar const trackParV0 = df2.getTrackParamAtPCA(0); + o2::track::TrackPar const trackParBachelor = df2.getTrackParamAtPCA(1); + std::array, NDaughters> momentaCascDaughters{}; trackParV0.getPxPyPzGlo(momentaCascDaughters[0]); trackParBachelor.getPxPyPzGlo(momentaCascDaughters[1]); - std::array pCasc; - df2.createParentTrackParCov().getPxPyPzGlo(pCasc); + o2::track::TrackParCov const trackParCovCascUntracked = df2.createParentTrackParCov(0); + std::array pCasc{}; + trackParCovCascUntracked.getPxPyPzGlo(pCasc); const auto cpaCasc = RecoDecay::cpa(primaryVertexPos, df2.getPCACandidate(), pCasc); const auto cpaXYCasc = RecoDecay::cpaXY(primaryVertexPos, df2.getPCACandidate(), pCasc); - std::array massesXiDaughters = {o2::constants::physics::MassLambda0, o2::constants::physics::MassPiPlus}; + std::array const massesXiDaughters = {o2::constants::physics::MassLambda0, o2::constants::physics::MassPiPlus}; const auto massXi = RecoDecay::m(momentaCascDaughters, massesXiDaughters); - std::array massesOmegaDaughters = {o2::constants::physics::MassLambda0, o2::constants::physics::MassKPlus}; + std::array const massesOmegaDaughters = {o2::constants::physics::MassLambda0, o2::constants::physics::MassKPlus}; const auto massOmega = RecoDecay::m(momentaCascDaughters, massesOmegaDaughters); registry.fill(HIST("hDca"), std::sqrt(impactParameterCasc.getR2())); @@ -484,9 +585,11 @@ struct HfTreeCreatorOmegacSt { if (((std::abs(bachelor.tpcNSigmaKa()) < maxNSigmaBachelor) || (std::abs(bachelor.tpcNSigmaPi()) < maxNSigmaBachelor)) && (std::abs(v0TrackPr.tpcNSigmaPr()) < maxNSigmaV0Pr) && (std::abs(v0TrackPi.tpcNSigmaPi()) < maxNSigmaV0Pi)) { - std::array massesOmegacDaughters{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassPiPlus}; - std::array massesXicDaughters{o2::constants::physics::MassXiMinus, o2::constants::physics::MassPiPlus}; - std::array, 2> momenta; + + std::array const massesOmegacToOmegaPi{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassPiPlus}; + std::array const massesOmegacToOmegaK{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassKPlus}; + std::array const massesXicDaughters{o2::constants::physics::MassXiMinus, o2::constants::physics::MassPiPlus}; + std::array, NDaughters> momenta{}; auto trackParCovPr = getTrackParCov(v0TrackPr); auto trackParCovKa = getTrackParCov(v0TrackPi); @@ -504,21 +607,21 @@ struct HfTreeCreatorOmegacSt { o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParCovPi, 2.f, matCorr, &impactParameterPi); } - for (auto trackId : groupedTrackIds) { + for (const auto& trackId : groupedTrackIds) { const auto track = trackId.template track_as(); if (track.globalIndex() == v0TrackPr.globalIndex() || track.globalIndex() == v0TrackPi.globalIndex() || track.globalIndex() == bachelor.globalIndex()) { continue; } - if ((track.itsNCls() >= 4) && - (track.tpcNClsFound() >= minNoClsTrackedPion) && - (track.tpcNClsCrossedRows() >= minNoClsTrackedPion) && - (track.tpcNClsCrossedRows() >= 0.8 * track.tpcNClsFindable()) && - (track.tpcChi2NCl() <= 4.f) && - (track.itsChi2NCl() <= 36.f) && - (std::abs(track.tpcNSigmaPi()) < maxNSigmaPion)) { - LOGF(debug, " .. combining with pion candidate %d", track.globalIndex()); + if ((track.itsNCls() >= ItsNClsMin) && + (track.tpcNClsFound() >= minNoClsTrackedPionOrKaon) && + (track.tpcNClsCrossedRows() >= minNoClsTrackedPionOrKaon) && + (track.tpcNClsCrossedRows() >= TpcNclsFindableFraction * track.tpcNClsFindable()) && + (track.tpcChi2NCl() <= TpcChi2NclMax) && + (track.itsChi2NCl() <= ItsChi2NclMax) && + (std::abs(track.tpcNSigmaPi()) < maxNSigmaPion || std::abs(track.tpcNSigmaKa()) < maxNSigmaKaon)) { + LOGF(debug, " .. combining with pion/kaon candidate %d", track.globalIndex()); int trackMotherId = -1; if constexpr (std::is_same::value) { if (track.has_mcParticle() && track.mcParticle().has_mothers()) { @@ -528,34 +631,100 @@ struct HfTreeCreatorOmegacSt { } } auto trackParCovCasc = getTrackParCov(trackCasc); - auto trackParCovPion = getTrackParCov(track); + auto trackParCovPionOrKaon = getTrackParCov(track); o2::dataformats::DCA impactParameterPion; if (bzOnly) { - o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackParCovPion, bz, 2.f, matCorr, &impactParameterPion); + o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, trackParCovPionOrKaon, bz, 2.f, matCorr, &impactParameterPion); } else { - o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParCovPion, 2.f, matCorr, &impactParameterPion); + o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertex, trackParCovPionOrKaon, 2.f, matCorr, &impactParameterPion); } - hCandidatesCascPi->Fill(SVFitting::BeforeFit); + hCandidatesCascPiOrK->Fill(SVFitting::BeforeFit); try { - if (df2.process(trackParCovCasc, trackParCovPion)) { + auto decayLengthUntracked = -1.; + auto decayLengthXYUntracked = -1.; + if (df2.process(trackParCovCascUntracked, trackParCovPionOrKaon)) { + const auto& secondaryVertexUntracked = df2.getPCACandidate(); + decayLengthUntracked = RecoDecay::distance(secondaryVertexUntracked, primaryVertexPos); + decayLengthXYUntracked = RecoDecay::distanceXY(secondaryVertexUntracked, primaryVertexPos); + } + if (df2.process(trackParCovCasc, trackParCovPionOrKaon)) { const auto& secondaryVertex = df2.getPCACandidate(); const auto decayLength = RecoDecay::distance(secondaryVertex, primaryVertexPos); const auto decayLengthXY = RecoDecay::distanceXY(secondaryVertex, primaryVertexPos); const auto chi2TopCharmedBaryon = df2.getChi2AtPCACandidate(); - std::array pCharmedBaryon; + std::array pCharmedBaryon{}; df2.createParentTrackParCov().getPxPyPzGlo(pCharmedBaryon); const auto cpaCharmedBaryon = RecoDecay::cpa(primaryVertexPos, df2.getPCACandidate(), pCharmedBaryon); const auto cpaXYCharmedBaryon = RecoDecay::cpaXY(primaryVertexPos, df2.getPCACandidate(), pCharmedBaryon); df2.getTrackParamAtPCA(0).getPxPyPzGlo(momenta[0]); df2.getTrackParamAtPCA(1).getPxPyPzGlo(momenta[1]); - const auto massOmegaC = RecoDecay::m(momenta, massesOmegacDaughters); + const auto massOmegaPi = RecoDecay::m(momenta, massesOmegacToOmegaPi); + const auto massOmegaK = RecoDecay::m(momenta, massesOmegacToOmegaK); const auto massXiC = RecoDecay::m(momenta, massesXicDaughters); - registry.fill(HIST("hMassOmegac"), massOmegaC); - registry.fill(HIST("hMassOmegacVsPt"), massOmegaC, RecoDecay::pt(momenta[0], momenta[1])); + registry.fill(HIST("hMassOmegaPi"), massOmegaPi); + registry.fill(HIST("hMassOmegaPiVsPt"), massOmegaPi, RecoDecay::pt(momenta[0], momenta[1])); + registry.fill(HIST("hMassOmegaK"), massOmegaK); + registry.fill(HIST("hMassOmegaKVsPt"), massOmegaK, RecoDecay::pt(momenta[0], momenta[1])); + + //--- do the MC Rec match + if (mcParticles) { + auto arrayDaughters = std::array{ + trackId.template track_as(), // bachelor <- charm baryon + casc.bachelor_as(), // bachelor <- cascade + v0.posTrack_as(), // p <- lambda + v0.negTrack_as()}; // pi <- lambda + + auto arrayDaughtersCasc = std::array{ + casc.bachelor_as(), // bachelor <- cascade + v0.posTrack_as(), // p <- lambda + v0.negTrack_as()}; // pi <- lambda + auto arrayDaughtersV0 = std::array{ + v0.posTrack_as(), // p <- lambda + v0.negTrack_as()}; // pi <- lambda + + if (decayChannel == o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaPi) { + // Match Omegac0 → Omega- + Pi+ + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughters, o2::constants::physics::kOmegaC0, + std::array{+kPiPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3, &nPiToMuOmegac0, &nKaToPiOmegac0); + indexRecCharmBaryon = indexRec; + if (indexRec > -1) { + // Omega- → K pi p (Cascade match) + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2, &nPiToMuCasc, &nKaToPiCasc); + if (indexRec > -1) { + // Lambda → p pi (Lambda match) + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1, &nPiToMuV0); + if (indexRec > -1) { + isMatched = true; + } + } + } + } else if (decayChannel == o2::aod::hf_cand_casc_lf::DecayType2Prong::OmegaczeroToOmegaK) { + // Match Omegac0 → Omega- + K+ + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughters, o2::constants::physics::kOmegaC0, + std::array{+kKPlus, +kKMinus, +kProton, +kPiMinus}, true, &sign, 3, &nPiToMuOmegac0, &nKaToPiOmegac0); + indexRecCharmBaryon = indexRec; + if (indexRec > -1) { + // Omega- → K pi p (Cascade match) + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersCasc, +kOmegaMinus, std::array{+kKMinus, +kProton, +kPiMinus}, true, &signCasc, 2, &nPiToMuCasc, &nKaToPiCasc); + if (indexRec > -1) { + // Lambda → p pi (Lambda match) + indexRec = RecoDecay::getMatchedMCRec(mcParticles->get(), arrayDaughtersV0, +kLambda0, std::array{+kProton, +kPiMinus}, true, &signV0, 1, &nPiToMuV0); + if (indexRec > -1) { + isMatched = true; + } + } + } + } + if (isMatched && indexRecCharmBaryon > -1) { + auto particle = mcParticles->get().rawIteratorAt(indexRecCharmBaryon); + origin = RecoDecay::getCharmHadronOrigin(mcParticles->get(), particle, false, &idxBhadMothers); + } + } - if ((std::abs(massOmegaC - o2::constants::physics::MassOmegaC0) < massWindowOmegaC) || + if ((std::abs(massOmegaK - o2::constants::physics::MassOmegaC0) < massWindowOmegaC) || + (std::abs(massOmegaPi - o2::constants::physics::MassOmegaC0) < massWindowOmegaC) || (std::abs(massXiC - o2::constants::physics::MassXiC0) < massWindowXiC)) { registry.fill(HIST("hDecayLength"), decayLength * 1e4); registry.fill(HIST("hDecayLengthScaled"), decayLength * o2::constants::physics::MassOmegaC0 / RecoDecay::p(momenta[0], momenta[1]) * 1e4); @@ -564,6 +733,8 @@ struct HfTreeCreatorOmegacSt { massV0, track.tpcNSigmaPi(), track.tofNSigmaPi(), + track.tpcNSigmaKa(), + track.tofNSigmaKa(), v0TrackPr.tpcNSigmaPr(), v0TrackPr.tofNSigmaPr(), v0TrackPi.tpcNSigmaPi(), @@ -575,11 +746,11 @@ struct HfTreeCreatorOmegacSt { momenta[0][0], // cascade momentum momenta[0][1], momenta[0][2], - trackCasc.sign() > 0 ? true : false, - momenta[1][0], // pion momentum + static_cast(trackCasc.sign() > 0), + momenta[1][0], // pion/kaon momentum momenta[1][1], momenta[1][2], - track.sign() > 0 ? true : false, + static_cast(track.sign() > 0), track.itsClusterMap(), cpaCharmedBaryon, cpaXYCharmedBaryon, @@ -603,20 +774,24 @@ struct HfTreeCreatorOmegacSt { trackedCascade.topologyChi2(), decayLength, decayLengthXY, + decayLengthUntracked, + decayLengthXYUntracked, decayLengthCasc, decayLengthCascXY, trackCascMotherId, - trackMotherId); + trackMotherId, + origin, + toiMask); } } else { continue; } } catch (const std::runtime_error& error) { - LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for Casc-Pi cannot work, skipping the candidate."; - hCandidatesCascPi->Fill(SVFitting::Fail); + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for Casc-Pi/K cannot work, skipping the candidate."; + hCandidatesCascPiOrK->Fill(SVFitting::Fail); continue; } - hCandidatesCascPi->Fill(SVFitting::FitOk); + hCandidatesCascPiOrK->Fill(SVFitting::FitOk); } } } @@ -645,10 +820,10 @@ struct HfTreeCreatorOmegacSt { aod::V0s const&, // TracksExt const& tracks, // TODO: should be TracksExtMc TracksExtMc const&, - aod::McParticles const&, + aod::McParticles const& mcParticles, aod::BCsWithTimestamps const&) { - fillTable(collisions, trackedCascades, trackIndices); + fillTable(collisions, trackedCascades, trackIndices, mcParticles); } PROCESS_SWITCH(HfTreeCreatorOmegacSt, processMcRec, "Process MC reco", true); @@ -666,9 +841,9 @@ struct HfTreeCreatorOmegacSt { runNumber = bc.runNumber(); auto timestamp = bc.timestamp(); - if (o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, timestamp)) { + if (auto* grpo = ccdb->getForTimeStamp(grpPath, timestamp)) { o2::base::Propagator::initFieldFromGRP(grpo); - } else if (o2::parameters::GRPMagField* grpmag = ccdb->getForTimeStamp(grpMagPath, timestamp)) { + } else if (auto* grpmag = ccdb->getForTimeStamp(grpMagPath, timestamp)) { o2::base::Propagator::initFieldFromGRP(grpmag); } else { LOG(fatal) << "Got nullptr from CCDB for path " << grpMagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << timestamp; @@ -714,11 +889,11 @@ struct HfTreeCreatorOmegacSt { LOG(debug) << "cascade with PDG code: " << pdgCode; if (std::abs(pdgCode) == kOmegaMinus) { LOG(debug) << "found Omega, looking for pions"; - std::array masses{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassPiPlus}; - std::array, 2> momenta; - std::array primaryVertexPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; + std::array const masses{o2::constants::physics::MassOmegaMinus, o2::constants::physics::MassPiPlus}; + std::array, NDaughters> momenta{}; + std::array const primaryVertexPos = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; const auto& mcColl = mother.mcCollision(); - std::array primaryVertexPosGen = {mcColl.posX(), mcColl.posY(), mcColl.posZ()}; + std::array const primaryVertexPosGen = {mcColl.posX(), mcColl.posY(), mcColl.posZ()}; for (const auto& track : tracks) { if (!track.has_mcParticle()) { @@ -740,9 +915,9 @@ struct HfTreeCreatorOmegacSt { registry.fill(HIST("hDeltaPtVsPt"), mcpart.pt(), (trackParCovPion.getPt() - mcpart.pt()) / mcpart.pt()); registry.fill(HIST("hMassOmegacId"), RecoDecay::m(momenta, masses)); - hCandidatesCascPi->Fill(SVFitting::BeforeFit); + hCandidatesCascPiOrK->Fill(SVFitting::BeforeFit); try { - if (df2.process(trackParCovCasc, trackParCovPion)) { + if (df2.process(trackParCovCasc, trackParCovPion) != 0) { const auto& secondaryVertex = df2.getPCACandidate(); const auto decayLength = RecoDecay::distance(secondaryVertex, primaryVertexPos); if (mother.has_mothers()) { @@ -752,7 +927,7 @@ struct HfTreeCreatorOmegacSt { registry.fill(HIST("hDecayLengthId"), decayLength * 1e4); registry.fill(HIST("hDecayLengthScaledId"), decayLength * o2::constants::physics::MassOmegaC0 / RecoDecay::p(momenta[0], momenta[1]) * 1e4); - std::array secondaryVertexGen = {mother.vx(), mother.vy(), mother.vz()}; + std::array const secondaryVertexGen = {mother.vx(), mother.vy(), mother.vz()}; const auto decayLengthGen = RecoDecay::distance(secondaryVertexGen, primaryVertexPosGen); registry.fill(HIST("hDecayLengthGen"), decayLengthGen * 1e4); registry.fill(HIST("hDecayLengthScaledGen"), decayLengthGen * o2::constants::physics::MassOmegaC0 / RecoDecay::p(momenta[0], momenta[1]) * 1e4); @@ -761,11 +936,11 @@ struct HfTreeCreatorOmegacSt { } } } - hCandidatesCascPi->Fill(SVFitting::FitOk); + hCandidatesCascPiOrK->Fill(SVFitting::FitOk); } } catch (const std::runtime_error& error) { LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for Casc-Pi cannot work, skipping the candidate."; - hCandidatesCascPi->Fill(SVFitting::Fail); + hCandidatesCascPiOrK->Fill(SVFitting::Fail); continue; } diff --git a/PWGHF/TableProducer/treeCreatorOmegacToOmegaPi.cxx b/PWGHF/TableProducer/treeCreatorOmegacToOmegaPi.cxx deleted file mode 100644 index 7d81746cb7c..00000000000 --- a/PWGHF/TableProducer/treeCreatorOmegacToOmegaPi.cxx +++ /dev/null @@ -1,414 +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 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 - -#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(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(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); - -} // 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); - -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::Chi2GeoV0, full::Chi2GeoCasc, full::Chi2GeoOmegac, - full::Chi2MassV0, full::Chi2MassCasc, - full::V0ldl, full::Cascldl, full::Omegacldl, - full::Chi2TopoV0ToPv, full::Chi2TopoCascToPv, full::Chi2TopoPiFromOmegacToPv, full::Chi2TopoOmegacToPv, - 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::FlagMcMatchRec, full::OriginRec, full::CollisionMatched); -} // namespace o2::aod - -/// Writes the full information in an output TTree -struct HfTreeCreatorOmegac0ToOmegaPi { - - Produces rowCandidateLite; - Produces rowKfCandidateFull; - 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.tpcNSigmaPiFromCharmBaryon(), - candidate.tpcNSigmaKaFromCasc(), - candidate.tpcNSigmaPiFromLambda(), - candidate.tpcNSigmaPrFromLambda(), - candidate.tofNSigmaPiFromCharmBaryon(), - candidate.tofNSigmaKaFromCasc(), - candidate.tofNSigmaPiFromLambda(), - candidate.tofNSigmaPrFromLambda(), - flagMc, - originMc, - collisionMatched); - } - } - - template - void fillKfCandidate(const T& candidate, int8_t flagMc, int8_t originMc, bool collisionMatched) - { - rowKfCandidateFull( - candidate.tpcNSigmaPiFromCharmBaryon(), - candidate.tofNSigmaPiFromCharmBaryon(), - candidate.tpcNSigmaKaFromCasc(), - candidate.tofNSigmaKaFromCasc(), - candidate.tpcNSigmaPiFromLambda(), - candidate.tpcNSigmaPrFromLambda(), - candidate.kfDcaXYPiFromOmegac(), - candidate.dcaCascDau(), - candidate.dcaCharmBaryonDau(), - candidate.kfDcaXYCascToPv(), - 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.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(), - 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, false); - } - } - PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processDataLite, "Process data", true); - - void processKfDataFull(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 - rowKfCandidateFull.reserve(candidates.size()); - for (const auto& candidate : candidates) { - fillKfCandidate(candidate, -7, RecoDecay::OriginType::None, false); - } - } - PROCESS_SWITCH(HfTreeCreatorOmegac0ToOmegaPi, processKfDataFull, "Process KF data", false); - - 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(HfTreeCreatorOmegac0ToOmegaPi, processMcLite, "Process MC", false); - -}; // end of struct - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGHF/TableProducer/treeCreatorSigmacCorrBkg.cxx b/PWGHF/TableProducer/treeCreatorSigmacCorrBkg.cxx new file mode 100644 index 00000000000..212d6e597a6 --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorSigmacCorrBkg.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. + +/// \file treeCreatorSigmacCorrBkg.cxx +/// \brief Code to reconstruct correlated-background candidates for Σc0,++ analysis +/// \note Λc± candidates selected from the HFLcCandidateSelector.cxx +/// \note Σc0,++ candidates selected from the candidateCreatorSigmac0plusplus.cxx +/// +/// \author Mattia Faggin , INFN PADOVA + +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/D2H/Utils/utilsSigmac.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; // for Produces, Configuable + +namespace o2::aod +{ +namespace hf_sigmac_bkg +{ +const int pdgCodeLambdac2595 = 14122; // o2-linter: disable=pdg/explicit-code (PDG code needed only for this study) +const int pdgCodeLambdac2625 = 4124; // o2-linter: disable=pdg/explicit-code (PDG code needed only for this study) +enum Decays { Sigmac2455Pi = 0, + LambdacPiPi }; +enum DecaysLambdac { PKPi = 0, + PiKP }; +DECLARE_SOA_COLUMN(Y, y, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Mass, mass, float); +DECLARE_SOA_COLUMN(DeltaMass, deltaMass, float); +DECLARE_SOA_COLUMN(Charge, charge, int8_t); +DECLARE_SOA_COLUMN(MotherPdg, motherPdg, int); +DECLARE_SOA_COLUMN(Decay, decay, int8_t); +DECLARE_SOA_COLUMN(DecayLambdac, decayLambdac, int8_t); +DECLARE_SOA_COLUMN(MlScoreFirstClass, mlScoreFirstClass, float); /// background score Λc +DECLARE_SOA_COLUMN(MlScoreThirdClass, mlScoreThirdClass, float); /// non-prompt score Λc +} // namespace hf_sigmac_bkg +DECLARE_SOA_TABLE(HfCorrBkgSc, "AOD", "HFCORRBKGSC", + hf_sigmac_bkg::Y, + hf_sigmac_bkg::Pt, + hf_sigmac_bkg::Mass, + hf_sigmac_bkg::DeltaMass, + hf_sigmac_bkg::Charge, + hf_sigmac_bkg::MotherPdg, + hf_sigmac_bkg::Decay, + hf_sigmac_bkg::DecayLambdac, + hf_sigmac_bkg::MlScoreFirstClass, + hf_sigmac_bkg::MlScoreThirdClass); +} // namespace o2::aod + +struct HfTreeCreatorSigmacCorrBkg { + + Produces rowCorrBkgSc; + + /// Selection of candidates Λc+ + Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; + Configurable yCandRecoMax{"yCandRecoMax", -1, "Maximum Sc candidate rapidity"}; + + using RecoLcMc = soa::Join; + using RecoScMc = soa::Join; + using ParticlesLcSigmac = soa::Join; + + /// @brief init function + void init(InitContext&) {} + + /// + void fillTable(RecoScMc::iterator candidateSc, RecoLcMc::iterator candLcDauSc, int motherPdg, int motherDecay = -1) + { + const int8_t chargeSc = candidateSc.charge(); // either Σc0 or Σc++ + const float rapidity = chargeSc == 0 ? HfHelper::ySc0(candidateSc) : HfHelper::yScPlusPlus(candidateSc); // NB: since in data we cannot tag Sc(2455) and Sc(2520), then we use only Sc(2455) for y selection on reconstructed signal + float massSc = -1.f; + float massLc = -1.f; + float deltaMass = -1.f; + const int8_t isCandPKPiPiKP = hf_sigmac_utils::isDecayToPKPiToPiKP(candLcDauSc, candidateSc); + std::array outputMl{-1., -1.}; + /// rapidity selection on Σc0,++ + if (yCandRecoMax >= 0. && std::abs(rapidity) > yCandRecoMax) { + return; + } + + /// BDT scores + if (!candLcDauSc.mlProbLcToPiKP().empty()) { + outputMl.at(0) = candLcDauSc.mlProbLcToPiKP()[0]; /// bkg score + outputMl.at(1) = candLcDauSc.mlProbLcToPiKP()[2]; /// non-prompt score + } + + if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PKPi)) && std::abs(candLcDauSc.template prong0_as().template mcParticle_as().pdgCode()) == kProton) { + massSc = HfHelper::invMassScRecoLcToPKPi(candidateSc, candLcDauSc); + massLc = HfHelper::invMassLcToPKPi(candLcDauSc); + deltaMass = massSc - massLc; + + /// fill the tree + rowCorrBkgSc(rapidity, candidateSc.pt(), massSc, deltaMass, chargeSc, motherPdg, motherDecay, aod::hf_sigmac_bkg::DecaysLambdac::PKPi, outputMl.at(0), outputMl.at(1)); + } + if ((TESTBIT(isCandPKPiPiKP, o2::aod::hf_cand_sigmac::Decays::PiKP)) && std::abs(candLcDauSc.template prong0_as().template mcParticle_as().pdgCode()) == kPiPlus) { + massSc = HfHelper::invMassScRecoLcToPiKP(candidateSc, candLcDauSc); + massLc = HfHelper::invMassLcToPiKP(candLcDauSc); + deltaMass = massSc - massLc; + + /// fill the tree + rowCorrBkgSc(rapidity, candidateSc.pt(), massSc, deltaMass, chargeSc, motherPdg, motherDecay, aod::hf_sigmac_bkg::DecaysLambdac::PiKP, outputMl.at(0), outputMl.at(1)); + } + } + + /// @brief process function to loop over the Σc reconstructed candidates and match them to corr. background sources in MC + void process(RecoScMc const& candidatesSc, + ParticlesLcSigmac const& particles, + RecoLcMc const&, + aod::TracksWMc const&) + { + /// loop over reconstructed Σc candidates + for (auto const& candidateSc : candidatesSc) { + + auto candLcDauSc = candidateSc.template prongLc_as(); + auto candSoftPiDauSc = candidateSc.template prong1_as(); + + /// tag immediately the Σc0,++(2455) and Σc0,++(2520) signal + auto flagMcDecayChanScAbs = std::abs(candidateSc.flagMcMatchRec()); + bool const isTrueSigmac0 = (flagMcDecayChanScAbs == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::Sc0ToPKPiPi); + bool const isTrueSigmacPlusPlus = (flagMcDecayChanScAbs == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScplusplusToPKPiPi); + bool const isTrueSigmacStar0 = (flagMcDecayChanScAbs == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStar0ToPKPiPi); + bool const isTrueSigmacStarPlusPlus = (flagMcDecayChanScAbs == o2::hf_decay::hf_cand_sigmac::DecayChannelMain::ScStarPlusPlusToPKPiPi); + if (isTrueSigmac0) { + /// fill the output for the signal + fillTable(candidateSc, candLcDauSc, o2::constants::physics::Pdg::kSigmaC0); + + /// the candidate that we reconstructed is a real Sigmac(2455, 2520), but later we look for correlated background sources + /// let's continue + continue; + } + if (isTrueSigmacPlusPlus) { + /// fill the output for the signal + fillTable(candidateSc, candLcDauSc, o2::constants::physics::Pdg::kSigmaCPlusPlus); + + /// the candidate that we reconstructed is a real Sigmac(2455, 2520), but later we look for correlated background sources + /// let's continue + continue; + } + if (isTrueSigmacStar0) { + /// fill the output for the signal + fillTable(candidateSc, candLcDauSc, o2::constants::physics::Pdg::kSigmaCStar0); + + /// the candidate that we reconstructed is a real Sigmac(2455, 2520), but later we look for correlated background sources + /// let's continue + continue; + } + if (isTrueSigmacStarPlusPlus) { + /// fill the output for the signal + fillTable(candidateSc, candLcDauSc, o2::constants::physics::Pdg::kSigmaCStarPlusPlus); + + /// the candidate that we reconstructed is a real Sigmac(2455, 2520), but later we look for correlated background sources + /// let's continue + continue; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// /// + /// Look for the Σc0,++ correlated background sources. /// + /// /// + /// Two sources are possible: /// + /// /// + /// 1) Λc±(2595, 2625) → Σc0,++(2455) π+,- /// + /// In this case, we need that the candidate Σc0,++(2455) is formed by the Λc± daughter of a real Σc0,++(2455) /// + /// paired with the bachelor pion of the Λc±(2595, 2625) /// + /// /// + /// 2) Λc±(2595, 2625) → Λc± π+ π- /// + /// It means that the reconstructed Σc candidate it's actually the pair of Λc± π+ or Λc± π- /// + /// coming from the same Λc±(2595) or Λc±(2625) /// + /// /// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /// check if the candidate Lc and soft pion daugthers are not real Lc or pion + bool const isLambdac = std::abs(candLcDauSc.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi; + bool isPion = false; + if (candSoftPiDauSc.has_mcParticle()) { + isPion = std::abs(candSoftPiDauSc.template mcParticle_as().pdgCode()) == kPiPlus; + } + if (!isLambdac || !isPion) { + continue; + } + + /// First of all, search for an incomplete decay of Λc±(2595, 2625) into Λc± (→ pK-π+) π+ π-, + /// we will distinguish the two background sources from the first mother of the Λc± + /// This means that we look for cases in which we use 4 tracks out of 5, missing one pion. + /// The possible combinations are: (1) pK-π+ π+; (2) pK-π+ π- + /// The full chain has a max depth of 4: + /// i. Λc±(2595, 2625) → Σc0,++(2455) π+,- (+1) + /// ii. Σc0,++(2455) → Λc+ π-,+ (+1) + /// ii. Λc+ → pK-π+ which can go in the direct channel direct (+1) or through a resonance (+2) + auto arrayDaughters = std::array{candLcDauSc.template prong0_as(), + candLcDauSc.template prong1_as(), + candLcDauSc.template prong2_as(), + candidateSc.template prong1_as()}; + auto arrayPdgDaughters1 = std::array{+kProton, -kKPlus, +kPiPlus, +kPiPlus}; /// (1) + auto arrayPdgDaughters2 = std::array{+kProton, -kKPlus, +kPiPlus, -kPiPlus}; /// (2) + int8_t sign = 0; + int indexMother = -1; + int motherPdg = -1; + int motherDecay = -1; + // look for Λc±(2595) - first daughter pdg-code combination + indexMother = RecoDecay::getMatchedMCRec(particles, arrayDaughters, aod::hf_sigmac_bkg::pdgCodeLambdac2595, arrayPdgDaughters1, true, &sign, 4 /*depthMainMax*/); + if (indexMother >= 0) { + /// mother found! + motherPdg = aod::hf_sigmac_bkg::pdgCodeLambdac2595; + } else { + // look for Λc±(2595) - second daughter pdg-code combination + indexMother = RecoDecay::getMatchedMCRec(particles, arrayDaughters, aod::hf_sigmac_bkg::pdgCodeLambdac2595, arrayPdgDaughters2, true, &sign, 4 /*depthMainMax*/); + if (indexMother >= 0) { + /// mother found! + motherPdg = aod::hf_sigmac_bkg::pdgCodeLambdac2595; + } else { + // look for Λc±(2625) - first daughter pdg-code combination + indexMother = RecoDecay::getMatchedMCRec(particles, arrayDaughters, aod::hf_sigmac_bkg::pdgCodeLambdac2625, arrayPdgDaughters1, true, &sign, 4 /*depthMainMax*/); + if (indexMother >= 0) { + /// mother found! + motherPdg = aod::hf_sigmac_bkg::pdgCodeLambdac2625; + } else { + // look for Λc±(2625) - second daughter pdg-code combination + indexMother = RecoDecay::getMatchedMCRec(particles, arrayDaughters, aod::hf_sigmac_bkg::pdgCodeLambdac2625, arrayPdgDaughters2, true, &sign, 4 /*depthMainMax*/); + if (indexMother >= 0) { + /// mother found! + motherPdg = aod::hf_sigmac_bkg::pdgCodeLambdac2625; + } else { + /// no mother found, it means that this is not a corr. bkg candidate + /// let's skip it + continue; + } + } + } + } + // LOG(info) << "motherPdg: " << motherPdg; + + /// now that we matched a Λc±(2595, 2625), let's determine the precise decay channel + /// by checking the mother of the Λc± + auto arrayDaughtersLambdac = std::array{candLcDauSc.template prong0_as(), + candLcDauSc.template prong1_as(), + candLcDauSc.template prong2_as()}; + int8_t signLambdac = 0; + int const indexRecLc = RecoDecay::getMatchedMCRec(particles, arrayDaughtersLambdac, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &signLambdac, 2); + if (indexRecLc < 0) { + /// this should never happen, since we check above that the isLambdac==true + LOG(fatal) << "Generated Lambdac not found. Not expected. Aborting."; + } + auto particleLc = particles.rawIteratorAt(indexRecLc); + if (particleLc.has_mothers()) { + /// we should always enter here, since the Λc± is coming from a Λc±(2595, 2625) decay + for (auto iMother = particleLc.mothersIds().front(); iMother <= particleLc.mothersIds().back(); ++iMother) { + auto mother = particles.rawIteratorAt(iMother); + int const pdgCodeMotherAbs = std::abs(mother.pdgCode()); + if (pdgCodeMotherAbs == o2::constants::physics::Pdg::kSigmaC0 || pdgCodeMotherAbs == o2::constants::physics::Pdg::kSigmaCPlusPlus) { + /// the Λc± comes from a Σc0,++(2455) + /// ==> we found a Λc±(2595, 2625) → Σc0,++(2455) π+,- decay! + motherDecay = aod::hf_sigmac_bkg::Decays::Sigmac2455Pi; + + /// This should be enough, i.e. not necessary to check that the pion is not daughter of the same Sigmac + /// This case should be already excluded by searching for real Sigmac (see the beginning of the process function) + + } else { + /// considering all the checks done before, the only other possibility is that this Λc± directly comes from a Λc±(2595, 2625) + motherDecay = aod::hf_sigmac_bkg::Decays::LambdacPiPi; + } + break; + } + } else { + /// we should never eneter here + LOG(fatal) << "Lambdac particle without mothers. Not expected. Aborting."; + } + + /// we found a corr. bkg. candidate + /// let's fill our output + fillTable(candidateSc, candLcDauSc, motherPdg, motherDecay); + + } /// end loop over reconstructed Σc candidates + } +}; + +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..e57a9c5c7c0 --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorTccToD0D0Pi.cxx @@ -0,0 +1,754 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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(ImpactParameterD1, impactParameterD1, float); +DECLARE_SOA_COLUMN(ImpactParameterD2, impactParameterD2, float); +DECLARE_SOA_COLUMN(ImpactParameterSoftPi, impactParameterSoftPi, float); +DECLARE_SOA_COLUMN(CpaD1, cpaD1, float); +DECLARE_SOA_COLUMN(CpaD2, cpaD2, float); +DECLARE_SOA_COLUMN(Chi2PCA, chi2PCA, 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); +DECLARE_SOA_COLUMN(GIndexCol, gIndexCol, int); //! Global index for the collisionAdd commentMore actions +DECLARE_SOA_COLUMN(TimeStamp, timeStamp, int64_t); //! Timestamp for the collision +} // namespace full + +DECLARE_SOA_TABLE(HfCandTccLites, "AOD", "HFCANDTCCLITE", + 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::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::ImpactParameterD1, + full::ImpactParameterD2, + full::ImpactParameterSoftPi, + full::CpaD1, + full::CpaD2, + full::Chi2PCA, + full::SignSoftPi, + full::DcaXYSoftPi, + full::DcaZSoftPi, + full::NITSClsSoftPi, + full::NTPCClsCrossedRowsSoftPi, + full::NTPCChi2NClSoftPi, + full::CentOfCand, + full::GIndexCol, + full::TimeStamp); + +DECLARE_SOA_TABLE(HfCandDDPairs, "AOD", "HFCANDDDPAIR", + 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::SelFlagD1, + full::SelFlagD2, + full::EtaD1, + full::EtaD2, + full::PhiD1, + full::PhiD2, + full::MlScoreD1, + full::MlScoreD2, + full::CentOfCand, + full::GIndexCol, + full::TimeStamp); + +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 rowCandidateDDPair; + Produces rowCandidateFullEvents; + + Configurable ptMinSoftPion{"ptMinSoftPion", 0.0, "Min pt for the soft pion"}; + Configurable usePionIsGlobalTrackWoDCA{"usePionIsGlobalTrackWoDCA", true, "check isGlobalTrackWoDCA status for pions"}; + + // vertexing + Configurable buildVertex{"buildVertex", false, "build vertext for Tcc"}; + 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 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)"}; + + // 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<3> dfTcc; // Tcc vertex fitter + o2::vertexing::DCAFitterN<2> dfDD; // DD pair vertex fitter + o2::vertexing::DCAFitterN<2> dfD1; // 2-prong vertex fitter (to rebuild D01 vertex) + o2::vertexing::DCAFitterN<2> dfD2; // 2-prong vertex fitter (to rebuild D02 vertex) + + Service ccdb; + o2::base::MatLayerCylSet* lut{}; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + double bz{0.}; + int runNumber{0}; + + 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; + std::shared_ptr hCandidatesD1, hCandidatesD2, hCandidatesTcc, hCandidatesDD; + HistogramRegistry registry{"registry"}; + OutputObj hCovPVXX{TH1F("hCovPVXX", "Tcc candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", 100, 0., 1.e-4)}; + OutputObj hCovSVXX{TH1F("hCovSVXX", "Tcc candidates;XX element of cov. matrix of sec. vtx. position (cm^{2});entries", 100, 0., 0.2)}; + 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."); + } + if (buildVertex) { + dfD1.setPropagateToPCA(propagateToPCA); + dfD1.setMaxR(maxR); + dfD1.setMaxDZIni(maxDZIni); + dfD1.setMinParamChange(minParamChange); + dfD1.setMinRelChi2Change(minRelChi2Change); + dfD1.setUseAbsDCA(useAbsDCA); + dfD1.setWeightedFinalPCA(useWeightedFinalPCA); + + dfD2.setPropagateToPCA(propagateToPCA); + dfD2.setMaxR(maxR); + dfD2.setMaxDZIni(maxDZIni); + dfD2.setMinParamChange(minParamChange); + dfD2.setMinRelChi2Change(minRelChi2Change); + dfD2.setUseAbsDCA(useAbsDCA); + dfD2.setWeightedFinalPCA(useWeightedFinalPCA); + + dfDD.setPropagateToPCA(propagateToPCA); + dfDD.setMaxR(maxR); + dfDD.setMaxDZIni(maxDZIni); + dfDD.setMinParamChange(minParamChange); + dfDD.setMinRelChi2Change(minRelChi2Change); + dfDD.setUseAbsDCA(useAbsDCA); + dfDD.setWeightedFinalPCA(useWeightedFinalPCA); + + dfTcc.setPropagateToPCA(propagateToPCA); + dfTcc.setMaxR(maxR); + dfTcc.setMaxDZIni(maxDZIni); + dfTcc.setMinParamChange(minParamChange); + dfTcc.setMinRelChi2Change(minRelChi2Change); + dfTcc.setUseAbsDCA(useAbsDCA); + dfTcc.setWeightedFinalPCA(useWeightedFinalPCA); + + // Configure CCDB access + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbPathLut)); + + hCandidatesD1 = registry.add("hCandidatesD1", "D1 candidate counter", {HistType::kTH1D, {axisCands}}); + hCandidatesD2 = registry.add("hCandidatesD2", "D2 candidate counter", {HistType::kTH1D, {axisCands}}); + hCandidatesTcc = registry.add("hCandidatesTcc", "Tcc candidate counter", {HistType::kTH1D, {axisCands}}); + hCandidatesDD = registry.add("hCandidatesDD", "DD pair candidate counter", {HistType::kTH1D, {axisCands}}); + + setLabelHistoCands(hCandidatesD1); + setLabelHistoCands(hCandidatesD2); + setLabelHistoCands(hCandidatesTcc); + setLabelHistoCands(hCandidatesDD); + } + } + + 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& collisions, + CandType const& candidates, + aod::TrackAssoc const& trackIndices, + TrkType const& tracks) + { + + for (const auto& collision : collisions) { + auto primaryVertex = getPrimaryVertex(collision); + auto bc = collision.template bc_as(); + fillEvent(collision, 0, bc.runNumber()); + int64_t timeStamp = bc.timestamp(); + if (buildVertex) { + 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; + } + dfTcc.setBz(bz); + dfDD.setBz(bz); + dfD1.setBz(bz); + dfD2.setBz(bz); + } + + o2::dataformats::V0 trackD1; + o2::dataformats::V0 trackD2; + 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); + + for (const auto& candidateD1 : candwD0ThisColl) { + + auto trackD1Prong0 = tracks.rawIteratorAt(candidateD1.prong0Id()); // positive daughter for D1 + auto trackD1Prong1 = tracks.rawIteratorAt(candidateD1.prong1Id()); // negative daughter for D1 + std::array const pVecD1Prong0{trackD1Prong0.pVector()}; + std::array const pVecD1Prong1{trackD1Prong1.pVector()}; + std::array pVecD1 = RecoDecay::pVec(pVecD1Prong0, pVecD1Prong1); + + for (auto candidateD2 = candidateD1 + 1; candidateD2 != candwD0ThisColl.end(); ++candidateD2) { + // avoid shared tracks + if ( + (candidateD1.prong0Id() == candidateD2.prong0Id()) || + (candidateD1.prong0Id() == candidateD2.prong1Id()) || + (candidateD1.prong1Id() == candidateD2.prong0Id()) || + (candidateD1.prong1Id() == candidateD2.prong1Id())) { + continue; + } + + auto trackD2Prong0 = tracks.rawIteratorAt(candidateD2.prong0Id()); // positive daughter for D2 + auto trackD2Prong1 = tracks.rawIteratorAt(candidateD2.prong1Id()); // negative daughter for D2 + std::array const pVecD2Prong0{trackD2Prong0.pVector()}; + std::array const pVecD2Prong1{trackD2Prong1.pVector()}; + std::array pVecD2 = RecoDecay::pVec(pVecD2Prong0, pVecD2Prong1); + + if (buildVertex) { + auto trackParVarD1Prong0 = getTrackParCov(trackD1Prong0); + auto trackParVarD1Prong1 = getTrackParCov(trackD1Prong1); + auto dca0D1 = o2::dataformats::DCA(trackD1Prong0.dcaXY(), trackD1Prong0.dcaZ(), trackD1Prong0.cYY(), trackD1Prong0.cZY(), trackD1Prong0.cZZ()); + auto dca1D1 = o2::dataformats::DCA(trackD1Prong1.dcaXY(), trackD1Prong1.dcaZ(), trackD1Prong1.cYY(), trackD1Prong1.cZY(), trackD1Prong1.cZZ()); + + // repropagate tracks to this collision if needed + if (trackD1Prong0.collisionId() != thisCollId) { + trackParVarD1Prong0.propagateToDCA(primaryVertex, bz, &dca0D1); + } + + if (trackD1Prong1.collisionId() != thisCollId) { + trackParVarD1Prong1.propagateToDCA(primaryVertex, bz, &dca1D1); + } + // reconstruct the 2-prong secondary vertex + hCandidatesD1->Fill(SVFitting::BeforeFit); + try { + if (dfD1.process(trackParVarD1Prong0, trackParVarD1Prong1) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for first D0 cannot work, skipping the candidate."; + hCandidatesD1->Fill(SVFitting::Fail); + continue; + } + hCandidatesD1->Fill(SVFitting::FitOk); + const auto& vertexD1 = dfD1.getPCACandidatePos(); + trackParVarD1Prong0.propagateTo(vertexD1[0], bz); + trackParVarD1Prong1.propagateTo(vertexD1[0], bz); + + // build a D1 neutral track + trackD1 = o2::dataformats::V0(vertexD1, pVecD1, dfD1.calcPCACovMatrixFlat(), trackParVarD1Prong0, trackParVarD1Prong1); + + auto trackParVarD2Prong0 = getTrackParCov(trackD2Prong0); + auto trackParVarD2Prong1 = getTrackParCov(trackD2Prong1); + auto dca0D2 = o2::dataformats::DCA(trackD2Prong0.dcaXY(), trackD2Prong0.dcaZ(), trackD2Prong0.cYY(), trackD2Prong0.cZY(), trackD2Prong0.cZZ()); + auto dca1D2 = o2::dataformats::DCA(trackD2Prong1.dcaXY(), trackD2Prong1.dcaZ(), trackD2Prong1.cYY(), trackD2Prong1.cZY(), trackD2Prong1.cZZ()); + + // repropagate tracks to this collision if needed + if (trackD2Prong0.collisionId() != thisCollId) { + trackParVarD2Prong0.propagateToDCA(primaryVertex, bz, &dca0D2); + } + if (trackD2Prong1.collisionId() != thisCollId) { + trackParVarD2Prong1.propagateToDCA(primaryVertex, bz, &dca1D2); + } + + // reconstruct the 2-prong secondary vertex + hCandidatesD2->Fill(SVFitting::BeforeFit); + try { + if (dfD2.process(trackParVarD2Prong0, trackParVarD2Prong1) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for second D0 cannot work, skipping the candidate."; + hCandidatesD2->Fill(SVFitting::Fail); + continue; + } + + hCandidatesD2->Fill(SVFitting::FitOk); + const auto& vertexD2 = dfD2.getPCACandidatePos(); + trackParVarD2Prong0.propagateTo(vertexD2[0], bz); + trackParVarD2Prong1.propagateTo(vertexD2[0], bz); + // build a D2 neutral track + trackD2 = o2::dataformats::V0(vertexD2, pVecD2, dfD2.calcPCACovMatrixFlat(), trackParVarD2Prong0, trackParVarD2Prong1); + + hCandidatesDD->Fill(SVFitting::BeforeFit); + try { + if (dfDD.process(trackD1, trackD2) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for DD cannot work, skipping the candidate."; + hCandidatesDD->Fill(SVFitting::Fail); + continue; + } + hCandidatesDD->Fill(SVFitting::FitOk); + } + + int candFlagD1 = -999; + int candFlagD2 = -999; + float cent = evaluateCentralityColl(collision); + float massD01 = -999; + float massD02 = -999; + 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() && !candidateD1.isSelD0()) { + 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() && !candidateD2.isSelD0()) { + candFlagD2 = 2; + std::copy(candidateD2.mlProbD0bar().begin(), candidateD2.mlProbD0bar().end(), std::back_inserter(mlScoresD2)); + massD02 = HfHelper::invMassD0barToKPi(candidateD2); + } + + // const auto massD0D0Pair = RecoDecay::m(std::array{pVecD1, pVecD2}, std::array{MassD0, MassD0}); + + rowCandidateDDPair( + candidateD1.pxProng0(), + candidateD1.pxProng1(), + candidateD1.pyProng0(), + candidateD1.pyProng1(), + candidateD1.pzProng0(), + candidateD1.pzProng1(), + candidateD2.pxProng0(), + candidateD2.pxProng1(), + candidateD2.pyProng0(), + candidateD2.pyProng1(), + candidateD2.pzProng0(), + candidateD2.pzProng1(), + candFlagD1, + candFlagD2, + candidateD1.eta(), + candidateD2.eta(), + candidateD1.phi(), + candidateD2.phi(), + mlScoresD1[0], + mlScoresD2[0], + cent, + collision.globalIndex(), + timeStamp); + + // start to add the track of softpi to reconstruct Tcc + for (const auto& trackId : trackIdsThisCollision) { + + 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() == trackPion.globalIndex()) || + (candidateD1.prong1Id() == trackPion.globalIndex()) || + (candidateD2.prong0Id() == trackPion.globalIndex()) || + (candidateD2.prong1Id() == trackPion.globalIndex())) { + continue; + } + + std::array pVecSoftPi = {trackPion.pVector()}; + + float impactParameterYD1 = -999.f; + float impactParameterYD2 = -999.f; + float impactParameterYSoftPi = -999.f; + float chi2PCA = -999.f; + if (buildVertex) { + auto trackParCovPi = getTrackParCov(trackPion); + // find the DCA between the D01, D02 and the bachelor track, for Tcc + hCandidatesTcc->Fill(SVFitting::BeforeFit); + try { + if (dfTcc.process(trackD1, trackD2, trackParCovPi) == 0) { + continue; + } + } catch (const std::runtime_error& error) { + LOG(info) << "Run time error found: " << error.what() << ". DCAFitterN for Tcc cannot work, skipping the candidate."; + hCandidatesTcc->Fill(SVFitting::Fail); + continue; + } + hCandidatesTcc->Fill(SVFitting::FitOk); + + dfTcc.propagateTracksToVertex(); // propagate the softpi and D0 pair to the Tcc vertex + trackD1.getPxPyPzGlo(pVecD1); // momentum of D1 at the Tcc vertex + trackD2.getPxPyPzGlo(pVecD2); // momentum of D2 at the Tcc vertex + trackParCovPi.getPxPyPzGlo(pVecSoftPi); // momentum of pi at the Tcc vertex + + chi2PCA = dfTcc.getChi2AtPCACandidate(); + auto covMatrixPCA = dfTcc.calcPCACovMatrixFlat(); + hCovSVXX->Fill(covMatrixPCA[0]); + + // get track impact parameters + // This modifies track momenta! + auto covMatrixPV = primaryVertex.getCov(); + hCovPVXX->Fill(covMatrixPV[0]); + o2::dataformats::DCA impactParameterD1; + o2::dataformats::DCA impactParameterD2; + o2::dataformats::DCA impactParameterSoftPi; + + trackD1.propagateToDCA(primaryVertex, bz, &impactParameterD1); + trackD2.propagateToDCA(primaryVertex, bz, &impactParameterD2); + trackParCovPi.propagateToDCA(primaryVertex, bz, &impactParameterSoftPi); + + impactParameterYD1 = impactParameterD1.getY(); + impactParameterYD2 = impactParameterD2.getY(); + impactParameterYSoftPi = impactParameterSoftPi.getY(); + } + // Retrieve properties of the two D0 candidates + float yD1 = HfHelper::yD0(candidateD1); + float yD2 = HfHelper::yD0(candidateD2); + float deltaMassD01 = -999; + float deltaMassD02 = -999; + + 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{pVecD1Prong0, pVecD1Prong1, pVecSoftPi}, std::array{massD1Daus[0], massD1Daus[1], MassPiPlus}); + auto massKpipi2 = RecoDecay::m(std::array{pVecD2Prong0, pVecD2Prong1, pVecSoftPi}, std::array{massD2Daus[0], massD2Daus[1], MassPiPlus}); + auto arrayMomentaDDpi = std::array{pVecD1, pVecD2, pVecSoftPi}; + const auto massD0D0Pi = RecoDecay::m(arrayMomentaDDpi, std::array{MassD0, MassD0, MassPiPlus}); + const auto deltaMassD0D0Pi = massD0D0Pi - (massD01 + massD02); + + deltaMassD01 = massKpipi1 - massD01; + deltaMassD02 = massKpipi2 - massD02; + + if (deltaMassD0D0Pi > deltaMassCanMax || massD0D0Pi > massCanMax) { + continue; + } + + rowCandidateLite( + 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, + 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], + impactParameterYD1, + impactParameterYD2, + impactParameterYSoftPi, + candidateD1.cpa(), + candidateD2.cpa(), + chi2PCA, + trackPion.sign(), + trackPion.dcaXY(), + trackPion.dcaZ(), + trackPion.itsNCls(), + trackPion.tpcNClsCrossedRows(), + trackPion.tpcChi2NCl(), + cent, + collision.globalIndex(), + timeStamp); + } // end of loop track + } // end of loop second D0 + } // end of loop first D0 + } // end of loop collision + } + void processDataWithMl(Collisions const& collisions, + SelectedCandidatesMl const& candidates, + aod::TrackAssoc const& trackIndices, + TracksWPid const& tracks, + aod::BCsWithTimestamps const&) + { + rowCandidateFullEvents.reserve(collisions.size()); + runCandCreatorData(collisions, candidates, trackIndices, tracks); + } + 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::BCsWithTimestamps const&) + { + rowCandidateFullEvents.reserve(collisions.size()); + runCandCreatorData(collisions, candidates, trackIndices, tracks); + } + 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::BCsWithTimestamps const&) + { + rowCandidateFullEvents.reserve(collisions.size()); + runCandCreatorData(collisions, candidates, trackIndices, tracks); + } + 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 facd45a4718..666b5c70579 100644 --- a/PWGHF/TableProducer/treeCreatorToXiPi.cxx +++ b/PWGHF/TableProducer/treeCreatorToXiPi.cxx @@ -15,13 +15,25 @@ /// /// \author Federica Zanone , Heidelberg University -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; @@ -33,6 +45,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); @@ -62,6 +75,8 @@ DECLARE_SOA_COLUMN(PzPiFromCharmBaryon, pzPiFromCharmBaryon, float); DECLARE_SOA_COLUMN(PxLambda, pxLambda, float); DECLARE_SOA_COLUMN(PyLambda, pyLambda, float); DECLARE_SOA_COLUMN(PzLambda, pzLambda, float); +DECLARE_SOA_COLUMN(PtCharmBaryon, ptCharmBaryon, float); +DECLARE_SOA_COLUMN(PtPiFromCharmBaryon, ptPiFromCharmBaryon, float); DECLARE_SOA_COLUMN(PxPiFromCasc, pxPiFromCasc, float); DECLARE_SOA_COLUMN(PyPiFromCasc, pyPiFromCasc, float); DECLARE_SOA_COLUMN(PzPiFromCasc, pzPiFromCasc, float); @@ -86,10 +101,10 @@ 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(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); @@ -116,10 +131,14 @@ 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 -DECLARE_SOA_COLUMN(OriginRec, originRec, int8_t); +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); DECLARE_SOA_COLUMN(CollisionMatched, collisionMatched, bool); // from selector DECLARE_SOA_COLUMN(StatusPidLambda, statusPidLambda, bool); @@ -146,12 +165,13 @@ 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, full::SignDecay, full::CovVtxCharmBaryonXX, full::CovVtxCharmBaryonYY, full::CovVtxCharmBaryonZZ, + full::PtCharmBaryon, full::PtPiFromCharmBaryon, full::PxCharmBaryon, full::PyCharmBaryon, full::PzCharmBaryon, full::PxCasc, full::PyCasc, full::PzCasc, full::PxPiFromCharmBaryon, full::PyPiFromCharmBaryon, full::PzPiFromCharmBaryon, @@ -172,18 +192,20 @@ 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, full::TofNSigmaPiFromCharmBaryon, full::TofNSigmaPiFromCasc, full::TofNSigmaPiFromLambda, full::TofNSigmaPrFromLambda, - full::FlagMcMatchRec, full::DebugMcRec, full::OriginRec, full::CollisionMatched); + full::FlagMcMatchRec, full::DebugMcRec, full::OriginMcRec, 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, full::SignDecay, + full::PtCharmBaryon, full::PtPiFromCharmBaryon, full::PxCharmBaryon, full::PyCharmBaryon, full::PzCharmBaryon, full::PxPiFromCharmBaryon, full::PyPiFromCharmBaryon, full::PzPiFromCharmBaryon, full::PxPiFromCasc, full::PyPiFromCasc, full::PzPiFromCasc, @@ -192,15 +214,18 @@ DECLARE_SOA_TABLE(HfToXiPiLites, "AOD", "HFTOXIPILITE", full::ImpactParCascXY, full::ImpactParPiFromCharmBaryonXY, full::ErrImpactParCascXY, full::ErrImpactParPiFromCharmBaryonXY, full::InvMassLambda, full::InvMassCascade, full::InvMassCharmBaryon, + full::CosPAV0, full::CosPACharmBaryon, full::CosPACasc, full::EtaV0PosDau, full::EtaV0NegDau, full::EtaPiFromCasc, full::EtaPiFromCharmBaryon, + full::EtaCharmBaryon, full::DcaXYToPvV0Dau0, full::DcaXYToPvV0Dau1, full::DcaXYToPvCascDau, 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, - full::FlagMcMatchRec, full::OriginRec, full::CollisionMatched); + full::FlagMcMatchRec, full::OriginMcRec, full::CollisionMatched); } // namespace o2::aod @@ -213,8 +238,12 @@ 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&) { @@ -223,21 +252,30 @@ struct HfTreeCreatorToXiPi { } } - 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(), @@ -251,6 +289,8 @@ struct HfTreeCreatorToXiPi { candidate.covVtxCharmBaryon0(), candidate.covVtxCharmBaryon3(), candidate.covVtxCharmBaryon5(), + RecoDecay::pt(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()), + RecoDecay::pt(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()), candidate.pxCharmBaryon(), candidate.pyCharmBaryon(), candidate.pzCharmBaryon(), @@ -287,10 +327,10 @@ 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.etaBachFromCasc(), @@ -317,6 +357,10 @@ struct HfTreeCreatorToXiPi { candidate.decLenCharmBaryon() / candidate.errorDecayLengthCharmBaryon(), 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(), @@ -340,17 +384,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,6 +412,8 @@ struct HfTreeCreatorToXiPi { candidate.yDecayVtxV0(), candidate.zDecayVtxV0(), candidate.signDecay(), + RecoDecay::pt(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()), + RecoDecay::pt(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()), candidate.pxCharmBaryon(), candidate.pyCharmBaryon(), candidate.pzCharmBaryon(), @@ -383,10 +436,14 @@ struct HfTreeCreatorToXiPi { candidate.invMassLambda(), candidate.invMassCascade(), candidate.invMassCharmBaryon(), + candidate.cosPAV0(), + candidate.cosPACharmBaryon(), + candidate.cosPACasc(), candidate.etaV0PosDau(), candidate.etaV0NegDau(), candidate.etaBachFromCasc(), candidate.etaBachFromCharmBaryon(), + candidate.etaCharmBaryon(), candidate.dcaXYToPvV0Dau0(), candidate.dcaXYToPvV0Dau1(), candidate.dcaXYToPvCascDau(), @@ -398,6 +455,10 @@ struct HfTreeCreatorToXiPi { 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(), @@ -420,16 +481,16 @@ 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); + fillCandidate(candidate, -7, -7, RecoDecay::OriginType::None, false); } } - PROCESS_SWITCH(HfTreeCreatorToXiPi, processDataFull, "Process data with full information", true); + PROCESS_SWITCH(HfTreeCreatorToXiPi, processDataFull, "Process data with full information w/o centrality", true); void processMcFullXic0(MyEventTable const& collisions, MyTrackTable const&, soa::Join const& candidates) @@ -437,16 +498,16 @@ 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, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originRec(), candidate.collisionMatched()); + fillCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originMcRec(), candidate.collisionMatched()); } } - PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcFullXic0, "Process MC with full information for xic0", false); + PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcFullXic0, "Process MC with full information for xic0 w/o centrality", false); void processMcFullOmegac0(MyEventTable const& collisions, MyTrackTable const&, soa::Join const& candidates) @@ -454,13 +515,13 @@ 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, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originRec(), candidate.collisionMatched()); + fillCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originMcRec(), candidate.collisionMatched()); } } PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcFullOmegac0, "Process MC with full information for omegac0", false); @@ -471,47 +532,149 @@ 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 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); + 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.originMcRec(), 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.originMcRec(), 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.originMcRec(), 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.originMcRec(), 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.originMcRec(), candidate.collisionMatched()); } } PROCESS_SWITCH(HfTreeCreatorToXiPi, processMcLiteOmegac0, "Process MC and produce lite table version for omegac0", false); diff --git a/PWGHF/TableProducer/treeCreatorXic0ToXiPiKf.cxx b/PWGHF/TableProducer/treeCreatorXic0ToXiPiKf.cxx new file mode 100644 index 00000000000..e1e8a27e38e --- /dev/null +++ b/PWGHF/TableProducer/treeCreatorXic0ToXiPiKf.cxx @@ -0,0 +1,323 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; + +namespace o2::aod +{ +namespace full +{ +DECLARE_SOA_COLUMN(Centrality, centrality, float); +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(DcaV0Dau, dcaV0Dau, 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(OriginMcRec, originMcRec, 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(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(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::Centrality, + full::TpcNSigmaPiFromCharmBaryon, full::TofNSigmaPiFromCharmBaryon, full::TpcNSigmaPiFromCasc, full::TofNSigmaPiFromCasc, + full::TpcNSigmaPiFromLambda, full::TofNSigmaPiFromLambda, full::TpcNSigmaPrFromLambda, full::TofNSigmaPrFromLambda, + full::KfDcaXYPiFromXic, full::DcaCascDau, full::DcaV0Dau, 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::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::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::OriginMcRec, 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; + using MyEventTable = soa::Join; + using MyEventTableWithFT0C = soa::Join; + using MyEventTableWithFT0M = soa::Join; + using MyEventTableWithNTracksPV = soa::Join; + + HistogramRegistry registry{"registry"}; // for QA of selections + + void init(InitContext const&) + { + registry.add("hPiFromXic0ItsChi2NCls", "hItsChi2NCls;status;entries", {HistType::kTH1D, {{1000, -5.0f, 5.0f}}}); + registry.add("hPiFromCacsItsChi2NCls", "hItsChi2NCls;status;entries", {HistType::kTH1D, {{1000, -5.0f, 5.0f}}}); + registry.add("hV0Dau0ItsChi2NCls", "hItsChi2NCls;status;entries", {HistType::kTH1D, {{1000, -5.0f, 5.0f}}}); + registry.add("hV0Dau1ItsChi2NCls", "hItsChi2NCls;status;entries", {HistType::kTH1D, {{1000, -5.0f, 5.0f}}}); + } + + template + void fillKfCandidate(const T& candidate, int8_t flagMc, int8_t debugMc, int8_t originMc, bool collisionMatched) + { + + if (candidate.resultSelections()) { + + float centrality = -999.f; + if constexpr (UseCentrality) { + auto const& collision = candidate.template collision_as(); + centrality = o2::hf_centrality::getCentralityColl(collision); + } + registry.fill(HIST("hPiFromXic0ItsChi2NCls"), candidate.template bachelorFromCharmBaryon_as().itsChi2NCl()); + registry.fill(HIST("hPiFromCacsItsChi2NCls"), candidate.template bachelor_as().itsChi2NCl()); + registry.fill(HIST("hV0Dau0ItsChi2NCls"), candidate.template posTrack_as().itsChi2NCl()); + registry.fill(HIST("hV0Dau1ItsChi2NCls"), candidate.template negTrack_as().itsChi2NCl()); + rowKfCandidate( + centrality, + candidate.tpcNSigmaPiFromCharmBaryon(), + candidate.tofNSigmaPiFromCharmBaryon(), + candidate.tpcNSigmaPiFromCasc(), + candidate.tofNSigmaPiFromCasc(), + candidate.tpcNSigmaPiFromLambda(), + candidate.tofNSigmaPiFromLambda(), + candidate.tpcNSigmaPrFromLambda(), + candidate.tofNSigmaPrFromLambda(), + candidate.kfDcaXYPiFromXic(), + candidate.dcaCascDau(), + candidate.dcaV0Dau(), + 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.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.invMassLambda(), + candidate.invMassCascade(), + candidate.invMassCharmBaryon(), + candidate.kfRapXic(), + RecoDecay::sqrtSumOfSquares(candidate.pxBachFromCharmBaryon(), candidate.pyBachFromCharmBaryon()), + RecoDecay::sqrtSumOfSquares(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()), + 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&, MyEventTable 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 processKfDataWithFT0C(MyTrackTable const&, MyEventTableWithFT0C 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, processKfDataWithFT0C, "Process KF data with FT0C", false); + + void processKfDataWithFT0M(MyTrackTable const&, MyEventTableWithFT0M 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, processKfDataWithFT0M, "Process KF data with FT0M", false); + + void processDataLiteWithNTracksPV(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, processDataLiteWithNTracksPV, "Process KF data with Ntracks", 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.originMcRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorXic0ToXiPiKf, processKfMcXic0, "Process MC with information for xic0", false); + + void processKfMCWithFT0C(MyTrackTable const&, + soa::Join const& candidates) + { + rowKfCandidate.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillKfCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originMcRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorXic0ToXiPiKf, processKfMCWithFT0C, "Process MC with information for xic0 at FT0C", false); + + void processKfMCWithFT0M(MyTrackTable const&, + soa::Join const& candidates) + { + rowKfCandidate.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillKfCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originMcRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorXic0ToXiPiKf, processKfMCWithFT0M, "Process MC with information for xic0 at FT0M", false); + + void processMCLiteWithNTracksPV(MyTrackTable const&, + soa::Join const& candidates) + { + rowKfCandidate.reserve(candidates.size()); + for (const auto& candidate : candidates) { + fillKfCandidate(candidate, candidate.flagMcMatchRec(), candidate.debugMcRec(), candidate.originMcRec(), candidate.collisionMatched()); + } + } + PROCESS_SWITCH(HfTreeCreatorXic0ToXiPiKf, processMCLiteWithNTracksPV, "Process MC with information for xic0 at Ntrack", 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..81543b0e7bf 100644 --- a/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorXicToPKPi.cxx @@ -16,14 +16,24 @@ /// \author Himanshu Sharma , INFN Padova /// \author Cristina Terrevoli , INFN Bari -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -60,11 +70,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 +85,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 +128,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 +198,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, @@ -220,21 +234,18 @@ struct HfTreeCreatorXicToPKPi { 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 CandXicData = soa::Filtered>; - using CandXicMcReco = soa::Filtered>; + using CandXicData = soa::Filtered>; + using CandXicMcReco = soa::Filtered>; using CandXicMcGen = soa::Filtered>; - using TracksWPid = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlagXic || aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlagXic; - Filter filterMcGenMatching = nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_3prong::DecayType::XicToPKPi)); + Filter filterMcGenMatching = nabs(o2::aod::hf_cand_3prong::flagMcMatchGen) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); Partition selectedXicToPKPiCand = aod::hf_sel_candidate_xic::isSelXicToPKPi >= selectionFlagXic; Partition selectedXicToPiKPCand = aod::hf_sel_candidate_xic::isSelXicToPiKP >= selectionFlagXic; - Partition reconstructedCandSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(BIT(aod::hf_cand_3prong::DecayType::XicToPKPi)); - Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(BIT(aod::hf_cand_3prong::DecayType::XicToPKPi)); + Partition reconstructedCandSig = nabs(aod::hf_cand_3prong::flagMcMatchRec) == static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); + Partition reconstructedCandBkg = nabs(aod::hf_cand_3prong::flagMcMatchRec) != static_cast(hf_decay::hf_cand_3prong::DecayChannelMain::XicToPKPi); void init(InitContext const&) { @@ -256,27 +267,29 @@ struct HfTreeCreatorXicToPKPi { /// \param doMc true to fill MC information /// \param massHypo mass hypothesis considered: 0 = PKPi, 1 = PiKP /// \param candidate is candidate - template + template void fillCandidateTable(const T& candidate) { int8_t flagMc = 0; int8_t originMc = 0; - if constexpr (doMc) { + int candSwapped = 0; + if constexpr (DoMc) { flagMc = candidate.flagMcMatchRec(); originMc = candidate.originMcRec(); + candSwapped = candidate.isCandidateSwapped(); } float invMassXic = 0; - if constexpr (massHypo == 0) { - invMassXic = hfHelper.invMassXicToPKPi(candidate); - } else if constexpr (massHypo == 1) { - invMassXic = hfHelper.invMassXicToPiKP(candidate); + int selStatusPKPi = candidate.isSelXicToPKPi(); + int selStatusPiKP = candidate.isSelXicToPiKP(); + + if constexpr (MassHypo == 0) { // Xic->PKPi + selStatusPiKP *= -1; + invMassXic = HfHelper::invMassXicToPKPi(candidate); + } else if constexpr (MassHypo == 1) { // Xic->PiKP + selStatusPKPi *= -1; + invMassXic = HfHelper::invMassXicToPiKP(candidate); } - - 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) - if (fillCandidateLiteTable) { rowCandidateLite( candidate.chi2PCA(), @@ -290,23 +303,23 @@ struct HfTreeCreatorXicToPKPi { candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), - trackPos1.tpcNSigmaPi(), - trackPos1.tpcNSigmaPr(), - trackPos1.tofNSigmaPi(), - trackPos1.tofNSigmaPr(), - trackNeg.tpcNSigmaKa(), - trackNeg.tofNSigmaKa(), - trackPos2.tpcNSigmaPi(), - trackPos2.tpcNSigmaPr(), - trackPos2.tofNSigmaPi(), - trackPos2.tofNSigmaPr(), - trackPos1.tpcTofNSigmaPi(), - trackPos1.tpcTofNSigmaPr(), - trackNeg.tpcTofNSigmaKa(), - trackPos2.tpcTofNSigmaPi(), - trackPos2.tpcTofNSigmaPr(), - candidate.isSelXicToPKPi(), - candidate.isSelXicToPiKP(), + candidate.nSigTpcPi0(), + candidate.nSigTpcPr0(), + candidate.nSigTofPi0(), + candidate.nSigTofPr0(), + candidate.nSigTpcKa1(), + candidate.nSigTofKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTpcPr2(), + candidate.nSigTofPi2(), + candidate.nSigTofPr2(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaPr0(), + candidate.tpcTofNSigmaKa1(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaPr2(), + selStatusPKPi, + selStatusPiKP, invMassXic, candidate.pt(), candidate.cpa(), @@ -314,7 +327,8 @@ struct HfTreeCreatorXicToPKPi { candidate.eta(), candidate.phi(), flagMc, - originMc); + originMc, + candSwapped); } else { rowCandidateFull( @@ -356,41 +370,41 @@ struct HfTreeCreatorXicToPKPi { candidate.errorImpactParameter0(), candidate.errorImpactParameter1(), candidate.errorImpactParameter2(), - trackPos1.tpcNSigmaPi(), - trackPos1.tpcNSigmaPr(), - trackPos1.tofNSigmaPi(), - trackPos1.tofNSigmaPr(), - trackNeg.tpcNSigmaKa(), - trackNeg.tofNSigmaKa(), - trackPos2.tpcNSigmaPi(), - trackPos2.tpcNSigmaPr(), - trackPos2.tofNSigmaPi(), - trackPos2.tofNSigmaPr(), - trackPos1.tpcTofNSigmaPi(), - trackPos1.tpcTofNSigmaPr(), - trackNeg.tpcTofNSigmaKa(), - trackPos2.tpcTofNSigmaPi(), - trackPos2.tpcTofNSigmaPr(), - candidate.isSelXicToPKPi(), - candidate.isSelXicToPiKP(), + candidate.nSigTpcPi0(), + candidate.nSigTpcPr0(), + candidate.nSigTofPi0(), + candidate.nSigTofPr0(), + candidate.nSigTpcKa1(), + candidate.nSigTofKa1(), + candidate.nSigTpcPi2(), + candidate.nSigTpcPr2(), + candidate.nSigTofPi2(), + candidate.nSigTofPr2(), + candidate.tpcTofNSigmaPi0(), + candidate.tpcTofNSigmaPr0(), + candidate.tpcTofNSigmaKa1(), + candidate.tpcTofNSigmaPi2(), + candidate.tpcTofNSigmaPr2(), + selStatusPKPi, + selStatusPiKP, invMassXic, candidate.pt(), candidate.p(), candidate.cpa(), candidate.cpaXY(), - hfHelper.ctXic(candidate), + HfHelper::ctXic(candidate), candidate.eta(), candidate.phi(), - hfHelper.yXic(candidate), - hfHelper.eXic(candidate), + HfHelper::yXic(candidate), + HfHelper::eXic(candidate), flagMc, - originMc); + originMc, + candSwapped); } } void processData(aod::Collisions const& collisions, - CandXicData const&, - TracksWPid const&) + CandXicData const&) { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); @@ -406,7 +420,7 @@ struct HfTreeCreatorXicToPKPi { for (const auto& candidate : selectedXicToPKPiCand) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -416,7 +430,7 @@ struct HfTreeCreatorXicToPKPi { for (const auto& candidate : selectedXicToPiKPCand) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); + float const pseudoRndm = candidate.ptProng0() * 1000. - static_cast(candidate.ptProng0() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } @@ -430,8 +444,7 @@ struct HfTreeCreatorXicToPKPi { void processMc(aod::Collisions const& collisions, aod::McCollisions const&, CandXicMcReco const&, - CandXicMcGen const& mcParticles, - TracksWPid const&) + CandXicMcGen const& mcParticles) { // Filling event properties rowCandidateFullEvents.reserve(collisions.size()); @@ -464,7 +477,7 @@ struct HfTreeCreatorXicToPKPi { for (const auto& candidate : reconstructedCandBkg) { if (downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng0() * 1000. - (int64_t)(candidate.ptProng0() * 1000); + float const 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 index 06d16c85d1e..3d0500c3690 100644 --- a/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx @@ -12,52 +12,45 @@ /// \file treeCreatorXicToXiPiPi.cxx /// \brief Writer of Ξc± → Ξ∓ π± π± candidates in the form of flat tables to be stored in TTrees. /// -/// \author Phil Lennart Stahlhut , CERN - -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" +/// \author Phil Lennart Stahlhut , Heidelberg University +/// \author Carolina Reetz , Heidelberg University +/// \author Jaeyoon Cho , Inha University +#include "PWGHF/Core/DecayChannelsLegacy.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::constants::physics; namespace o2::aod { namespace full { -// track indices +DECLARE_SOA_COLUMN(ParticleFlag, particleFlag, int8_t); //! hf_cand_xic_to_xi_pi_pi::Sign for data, hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec for MC DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int); //! Selection flag of candidate (output of candidateSelector) -DECLARE_SOA_INDEX_COLUMN_FULL(Xi, xi, int, Tracks, "_pi0"); -DECLARE_SOA_INDEX_COLUMN_FULL(Pi0, pi0, int, Tracks, "_pi0"); -DECLARE_SOA_INDEX_COLUMN_FULL(Pi1, pi1, int, Tracks, "_pi1"); // vertices -DECLARE_SOA_COLUMN(XPv, xPv, float); -DECLARE_SOA_COLUMN(YPv, yPv, float); -DECLARE_SOA_COLUMN(ZPv, zPv, float); -DECLARE_SOA_COLUMN(XPvErr, xPvErr, float); -DECLARE_SOA_COLUMN(YPvErr, yPvErr, float); -DECLARE_SOA_COLUMN(ZPvErr, zPvErr, float); -DECLARE_SOA_COLUMN(XSv, xSv, float); -DECLARE_SOA_COLUMN(YSv, ySv, float); -DECLARE_SOA_COLUMN(ZSv, zSv, float); -DECLARE_SOA_COLUMN(Chi2Sv, chi2Sv, float); -DECLARE_SOA_COLUMN(XSvErr, xSvErr, float); -DECLARE_SOA_COLUMN(YSvErr, ySvErr, float); -DECLARE_SOA_COLUMN(ZSvErr, zSvErr, float); -DECLARE_SOA_COLUMN(XDecVtxXi, xDecVtxXi, float); -DECLARE_SOA_COLUMN(YDecVtxXi, yDecVtxXi, float); -DECLARE_SOA_COLUMN(ZDecVtxXi, zDecVtxXi, float); -DECLARE_SOA_COLUMN(Chi2XiVtx, chi2XiVtx, float); -DECLARE_SOA_COLUMN(XDecVtxLam, xDecVtxLam, float); -DECLARE_SOA_COLUMN(YDecVtxLam, yDecVtxLam, float); -DECLARE_SOA_COLUMN(ZDecVtxLam, zDecVtxLam, float); -DECLARE_SOA_COLUMN(Chi2LamVtx, chi2LamVtx, float); +DECLARE_SOA_COLUMN(Chi2SV, chi2SV, float); //! Chi2 of candidate vertex +DECLARE_SOA_COLUMN(Chi2GeoXi, chi2GeoXi, float); //! Chi2 of Xi vertex +DECLARE_SOA_COLUMN(Chi2GeoLambda, chi2GeoLambda, float); //! Chi2 of Lambda vertex // 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) @@ -72,142 +65,145 @@ DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! 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(Chi2XicPlusTopoToPV, chi2XicPlusTopoToPV, float); -DECLARE_SOA_COLUMN(Chi2XicPlusTopoXiToXicPlus, chi2XicPlusTopoXiToXicPlus, 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); //! Momentum of Pi0 (prong1) (GeV/c) 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); //! Momentum of Pi1 (prong2) (GeV/c) 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(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(DcaXiDaughters, dcaXiDaughters, float); -DECLARE_SOA_COLUMN(InvMassXiPi0, invMassXiPi0, float); -DECLARE_SOA_COLUMN(InvMassXiPi1, invMassXiPi1, float); } // namespace full DECLARE_SOA_TABLE(HfCandXicToXiPiPiLites, "AOD", "HFXICXI2PILITE", + full::ParticleFlag, + hf_cand_xic_to_xi_pi_pi::OriginMcRec, full::CandidateSelFlag, - full::XPv, - full::YPv, - full::ZPv, - full::XSv, - full::YSv, - full::ZSv, - full::Chi2Sv, - full::Sign, - full::E, - full::M, - full::P, - full::Pt, full::Y, full::Eta, full::Phi, + full::P, + full::Pt, + full::PtXi, + full::PtPi0, + full::PtPi1, + full::M, + 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, + full::Chi2SV, full::Ct, full::DecayLength, + full::DecayLengthNormalised, full::DecayLengthXY, + full::DecayLengthXYNormalised, full::Cpa, full::CpaXY, - full::PtXi, - full::PtPi0, - full::PtPi1, + hf_cand_xic_to_xi_pi_pi::CpaXi, + hf_cand_xic_to_xi_pi_pi::CpaXYXi, + hf_cand_xic_to_xi_pi_pi::CpaLambda, + hf_cand_xic_to_xi_pi_pi::CpaXYLambda, full::ImpactParameterXi, + full::ImpactParameterNormalisedXi, full::ImpactParameterPi0, + full::ImpactParameterNormalisedPi0, full::ImpactParameterPi1, - full::CpaXi, - full::CpaXYXi, - full::CpaLam, - full::CpaXYLam, - hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec); + full::ImpactParameterNormalisedPi1, + full::MaxNormalisedDeltaIP); DECLARE_SOA_TABLE(HfCandXicToXiPiPiLiteKfs, "AOD", "HFXICXI2PILITKF", + full::ParticleFlag, + hf_cand_xic_to_xi_pi_pi::OriginMcRec, full::CandidateSelFlag, - full::XPv, - full::YPv, - full::ZPv, - full::XSv, - full::YSv, - full::ZSv, - full::Chi2Sv, - full::Sign, - full::E, - full::M, - full::P, - full::Pt, full::Y, full::Eta, full::Phi, + full::Pt, + full::PtXi, + full::PtPi0, + full::PtPi1, + full::M, + full::Chi2SV, full::Ct, full::DecayLength, + full::DecayLengthNormalised, full::DecayLengthXY, + full::DecayLengthXYNormalised, full::Cpa, full::CpaXY, - full::PtXi, - full::PtPi0, - full::PtPi1, + hf_cand_xic_to_xi_pi_pi::CpaXi, + hf_cand_xic_to_xi_pi_pi::CpaXYXi, + hf_cand_xic_to_xi_pi_pi::CpaLambda, + hf_cand_xic_to_xi_pi_pi::CpaXYLambda, + hf_cand_xic_to_xi_pi_pi::CpaLambdaToXi, + hf_cand_xic_to_xi_pi_pi::CpaXYLambdaToXi, full::ImpactParameterXi, + full::ImpactParameterNormalisedXi, full::ImpactParameterPi0, + full::ImpactParameterNormalisedPi0, full::ImpactParameterPi1, - full::CpaXi, - full::CpaXYXi, - full::CpaLam, - full::CpaXYLam, - full::Chi2XiVtx, - full::Chi2LamVtx, - full::Chi2XicPlusTopoToPV, - full::Chi2XicPlusTopoXiToXicPlus, - full::DcaXYPi0Pi1, - full::DcaXYPi0Xi, - full::DcaXYPi1Xi, - full::DcaPi0Pi1, - full::DcaPi0Xi, - full::DcaPi1Xi, - full::DcaXiDaughters, - hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec); + full::ImpactParameterNormalisedPi1, + full::MaxNormalisedDeltaIP, + hf_cand_xic_to_xi_pi_pi::DcaXiDaughters, + hf_cand_xic_to_xi_pi_pi::DcaV0Daughters, + hf_cand_xic_to_xi_pi_pi::DcaXYCascToPV, + hf_cand_xic_to_xi_pi_pi::DcaZCascToPV, + hf_cand_xic_to_xi_pi_pi::DcaBachelorToPV, + hf_cand_xic_to_xi_pi_pi::DcaPosToPV, + hf_cand_xic_to_xi_pi_pi::DcaNegToPV, + // PID information + 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::Chi2GeoXi, + full::Chi2GeoLambda, + hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPVBefConst, + hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPV, + hf_cand_xic_to_xi_pi_pi::Chi2PrimXi, + hf_cand_xic_to_xi_pi_pi::Chi2PrimPi0, + hf_cand_xic_to_xi_pi_pi::Chi2PrimPi1, + hf_cand_xic_to_xi_pi_pi::Chi2DevPi0Pi1, + hf_cand_xic_to_xi_pi_pi::Chi2DevPi0Xi, + hf_cand_xic_to_xi_pi_pi::Chi2DevPi1Xi, + hf_cand_xic_to_xi_pi_pi::DcaPi0Pi1, + hf_cand_xic_to_xi_pi_pi::DcaPi0Xi, + hf_cand_xic_to_xi_pi_pi::DcaPi1Xi, + hf_cand_xic_to_xi_pi_pi::DcaXYPi0Pi1, + hf_cand_xic_to_xi_pi_pi::DcaXYPi0Xi, + hf_cand_xic_to_xi_pi_pi::DcaXYPi1Xi); DECLARE_SOA_TABLE(HfCandXicToXiPiPiFulls, "AOD", "HFXICXI2PIFULL", + full::ParticleFlag, + hf_cand_xic_to_xi_pi_pi::OriginMcRec, full::CandidateSelFlag, - full::XPv, - full::YPv, - full::ZPv, - full::XPvErr, - full::YPvErr, - full::ZPvErr, - full::XSv, - full::YSv, - full::ZSv, - full::Chi2Sv, - full::XSvErr, - full::YSvErr, - full::ZSvErr, - full::XDecVtxXi, - full::YDecVtxXi, - full::ZDecVtxXi, - full::XDecVtxLam, - full::YDecVtxLam, - full::ZDecVtxLam, - full::Sign, - full::E, - full::M, - full::P, - full::Pt, full::Y, full::Eta, full::Phi, + full::P, + full::Pt, + full::PtXi, + full::PtPi0, + full::PtPi1, + full::M, + 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, + full::Chi2SV, full::Ct, full::DecayLength, full::DecayLengthNormalised, @@ -215,9 +211,10 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiFulls, "AOD", "HFXICXI2PIFULL", full::DecayLengthXYNormalised, full::Cpa, full::CpaXY, - full::PtXi, - full::PtPi0, - full::PtPi1, + hf_cand_xic_to_xi_pi_pi::CpaXi, + hf_cand_xic_to_xi_pi_pi::CpaXYXi, + hf_cand_xic_to_xi_pi_pi::CpaLambda, + hf_cand_xic_to_xi_pi_pi::CpaXYLambda, full::ImpactParameterXi, full::ImpactParameterNormalisedXi, full::ImpactParameterPi0, @@ -225,43 +222,45 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiFulls, "AOD", "HFXICXI2PIFULL", full::ImpactParameterPi1, full::ImpactParameterNormalisedPi1, full::MaxNormalisedDeltaIP, - full::CpaXi, - full::CpaXYXi, - full::CpaLam, - full::CpaXYLam, - full::InvMassXiPi0, - full::InvMassXiPi1, - hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec); + // additional columns only stored in the full candidate table + hf_cand_xic_to_xi_pi_pi::CpaLambdaToXi, + hf_cand_xic_to_xi_pi_pi::CpaXYLambdaToXi, + full::PPi0, + full::PPi1, + 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::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", + full::ParticleFlag, + hf_cand_xic_to_xi_pi_pi::OriginMcRec, full::CandidateSelFlag, - full::XPv, - full::YPv, - full::ZPv, - full::XPvErr, - full::YPvErr, - full::ZPvErr, - full::XSv, - full::YSv, - full::ZSv, - full::Chi2Sv, - full::XSvErr, - full::YSvErr, - full::ZSvErr, - full::XDecVtxXi, - full::YDecVtxXi, - full::ZDecVtxXi, - full::XDecVtxLam, - full::YDecVtxLam, - full::ZDecVtxLam, - full::Sign, - full::E, - full::M, - full::P, - full::Pt, full::Y, full::Eta, full::Phi, + full::Pt, + full::PtXi, + full::PtPi0, + full::PtPi1, + full::M, + full::Chi2SV, full::Ct, full::DecayLength, full::DecayLengthNormalised, @@ -269,9 +268,12 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullKfs, "AOD", "HFXICXI2PIFULKF", full::DecayLengthXYNormalised, full::Cpa, full::CpaXY, - full::PtXi, - full::PtPi0, - full::PtPi1, + hf_cand_xic_to_xi_pi_pi::CpaXi, + hf_cand_xic_to_xi_pi_pi::CpaXYXi, + hf_cand_xic_to_xi_pi_pi::CpaLambda, + hf_cand_xic_to_xi_pi_pi::CpaXYLambda, + hf_cand_xic_to_xi_pi_pi::CpaLambdaToXi, + hf_cand_xic_to_xi_pi_pi::CpaXYLambdaToXi, full::ImpactParameterXi, full::ImpactParameterNormalisedXi, full::ImpactParameterPi0, @@ -279,44 +281,62 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullKfs, "AOD", "HFXICXI2PIFULKF", full::ImpactParameterPi1, full::ImpactParameterNormalisedPi1, full::MaxNormalisedDeltaIP, - full::CpaXi, - full::CpaXYXi, - full::CpaLam, - full::CpaXYLam, - full::InvMassXiPi0, - full::InvMassXiPi1, - full::Chi2XiVtx, - full::Chi2LamVtx, - full::Chi2XicPlusTopoToPV, - full::Chi2XicPlusTopoXiToXicPlus, - full::DcaXYPi0Pi1, - full::DcaXYPi0Xi, - full::DcaXYPi1Xi, - full::DcaPi0Pi1, - full::DcaPi0Xi, - full::DcaPi1Xi, - full::DcaXiDaughters, - hf_cand_xic_to_xi_pi_pi::FlagMcMatchRec); - -DECLARE_SOA_TABLE(HfCandXicToXiPiPiDauInds, "AOD", "HFXICXI2PIDAUIN", - full::XiId, - full::Pi0Id, - full::Pi1Id); - -DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullEvs, "AOD", "HFXICXI2PIFULEV", - collision::BCId, - collision::NumContrib, - collision::PosX, - collision::PosY, - collision::PosZ); + hf_cand_xic_to_xi_pi_pi::DcaXiDaughters, + hf_cand_xic_to_xi_pi_pi::DcaV0Daughters, + hf_cand_xic_to_xi_pi_pi::DcaXYCascToPV, + hf_cand_xic_to_xi_pi_pi::DcaZCascToPV, + hf_cand_xic_to_xi_pi_pi::DcaBachelorToPV, + hf_cand_xic_to_xi_pi_pi::DcaPosToPV, + hf_cand_xic_to_xi_pi_pi::DcaNegToPV, + // additional columns only stored in the full candidate table + hf_cand_xic_to_xi_pi_pi::InvMassXi, + hf_cand_xic_to_xi_pi_pi::InvMassXiPi0, + hf_cand_xic_to_xi_pi_pi::InvMassXiPi1, + hf_cand_xic_to_xi_pi_pi::InvMassLambda, + full::P, + full::PPi0, + full::PPi1, + hf_cand_xic_to_xi_pi_pi::PBachelorPi, + hf_cand_xic_to_xi_pi_pi::PPiFromLambda, + hf_cand_xic_to_xi_pi_pi::PPrFromLambda, + // PID information + 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::Chi2GeoXi, + full::Chi2GeoLambda, + hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPVBefConst, + hf_cand_xic_to_xi_pi_pi::Chi2TopoXicPlusToPV, + hf_cand_xic_to_xi_pi_pi::Chi2PrimXi, + hf_cand_xic_to_xi_pi_pi::Chi2PrimPi0, + hf_cand_xic_to_xi_pi_pi::Chi2PrimPi1, + hf_cand_xic_to_xi_pi_pi::Chi2DevPi0Pi1, + hf_cand_xic_to_xi_pi_pi::Chi2DevPi0Xi, + hf_cand_xic_to_xi_pi_pi::Chi2DevPi1Xi, + hf_cand_xic_to_xi_pi_pi::DcaPi0Pi1, + hf_cand_xic_to_xi_pi_pi::DcaPi0Xi, + hf_cand_xic_to_xi_pi_pi::DcaPi1Xi, + hf_cand_xic_to_xi_pi_pi::DcaXYPi0Pi1, + hf_cand_xic_to_xi_pi_pi::DcaXYPi0Xi, + hf_cand_xic_to_xi_pi_pi::DcaXYPi1Xi); DECLARE_SOA_TABLE(HfCandXicToXiPiPiFullPs, "AOD", "HFXICXI2PIFULLP", - collision::BCId, + hf_cand_xic_to_xi_pi_pi::FlagMcMatchGen, + hf_cand_xic_to_xi_pi_pi::OriginMcGen, + hf_cand::PdgBhadMotherPart, full::Pt, full::Eta, full::Phi, full::Y, - hf_cand_xic_to_xi_pi_pi::FlagMcMatchGen); + hf_cand_xic_to_xi_pi_pi::DecayLengthMcGen); } // namespace o2::aod /// Writes the full information in an output TTree @@ -325,13 +345,11 @@ struct HfTreeCreatorXicToXiPiPi { Produces rowCandidateLiteKf; Produces rowCandidateFull; Produces rowCandidateFullKf; - Produces rowCandidateDauIndices; - Produces rowCandidateFullEvents; Produces rowCandidateFullParticles; - Configurable selectionFlagXic{"selectionXic", 1, "Selection Flag for Xic"}; + Configurable selectionFlagXic{"selectionFlagXic", 1, "Selection Flag for Xic"}; Configurable fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"}; - Configurable fillCandidateDauIndexTable{"fillCandidateDauIndexTable", false, "Switch to fill table with Xic daughters track indices"}; + 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"}; @@ -342,9 +360,10 @@ struct HfTreeCreatorXicToXiPiPi { using SelectedCandidatesKf = soa::Filtered>; using SelectedCandidatesMc = soa::Filtered>; using SelectedCandidatesKfMc = soa::Filtered>; - using TracksWPid = soa::Join; + using MatchedGenXicToXiPiPi = soa::Filtered>; Filter filterSelectCandidates = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= selectionFlagXic; + Filter filterGenXicToXiPiPi = (nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi)) || nabs(aod::hf_cand_xic_to_xi_pi_pi::flagMcMatchGen) == static_cast(BIT(aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiResPiToXiPiPi))); 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); @@ -355,98 +374,72 @@ struct HfTreeCreatorXicToXiPiPi { { } - template - void fillEvent(const T& collision) - { - rowCandidateFullEvents( - collision.bcId(), - collision.numContrib(), - collision.posX(), - collision.posY(), - collision.posZ()); - } - - template - void fillIndexTable(const T& candidate) - { - rowCandidateDauIndices( - candidate.cascadeId(), - candidate.pi0Id(), - candidate.pi1Id()); - } - - template + template void fillCandidateTable(const T& candidate) { - int8_t flagMc = 0; - if constexpr (doMc) { - flagMc = candidate.flagMcMatchRec(); + int8_t particleFlag = candidate.sign(); + int8_t originMc = 0; + if constexpr (DoMc) { + particleFlag = candidate.flagMcMatchRec(); + originMc = candidate.originMcRec(); } - if constexpr (!doKf) { + if constexpr (!DoKf) { if (fillCandidateLiteTable) { rowCandidateLite( + particleFlag, + originMc, candidate.isSelXicToXiPiPi(), - candidate.posX(), - candidate.posY(), - candidate.posZ(), - candidate.xSecondaryVertex(), - candidate.ySecondaryVertex(), - candidate.zSecondaryVertex(), - candidate.chi2PCA(), - candidate.sign(), - candidate.e(o2::constants::physics::MassXiCPlus), - candidate.invMassXic(), - candidate.p(), - candidate.pt(), 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.ptProng0(), - candidate.ptProng1(), - candidate.ptProng2(), + candidate.cpaXi(), + candidate.cpaXYXi(), + candidate.cpaLambda(), + candidate.cpaXYLambda(), candidate.impactParameter0(), + candidate.impactParameterNormalised0(), candidate.impactParameter1(), + candidate.impactParameterNormalised1(), candidate.impactParameter2(), - candidate.cosPaXi(), - candidate.cosPaXYXi(), - candidate.cosPaLambda(), - candidate.cosPaXYLambda(), - flagMc); + candidate.impactParameterNormalised2(), + candidate.maxNormalisedDeltaIP()); } else { rowCandidateFull( + particleFlag, + originMc, candidate.isSelXicToXiPiPi(), - candidate.posX(), - candidate.posY(), - candidate.posZ(), - candidate.xPvErr(), - candidate.yPvErr(), - candidate.zPvErr(), - candidate.xSecondaryVertex(), - candidate.ySecondaryVertex(), - candidate.zSecondaryVertex(), - candidate.chi2PCA(), - candidate.xSvErr(), - candidate.ySvErr(), - candidate.zSvErr(), - candidate.xDecayVtxXi(), - candidate.yDecayVtxXi(), - candidate.zDecayVtxXi(), - candidate.xDecayVtxLambda(), - candidate.yDecayVtxLambda(), - candidate.zDecayVtxLambda(), - candidate.sign(), - candidate.e(o2::constants::physics::MassXiCPlus), - candidate.invMassXic(), - candidate.p(), - candidate.pt(), 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(), @@ -454,9 +447,10 @@ struct HfTreeCreatorXicToXiPiPi { candidate.decayLengthXYNormalised(), candidate.cpa(), candidate.cpaXY(), - candidate.ptProng0(), - candidate.ptProng1(), - candidate.ptProng2(), + candidate.cpaXi(), + candidate.cpaXYXi(), + candidate.cpaLambda(), + candidate.cpaXYLambda(), candidate.impactParameter0(), candidate.impactParameterNormalised0(), candidate.impactParameter1(), @@ -464,100 +458,129 @@ struct HfTreeCreatorXicToXiPiPi { candidate.impactParameter2(), candidate.impactParameterNormalised2(), candidate.maxNormalisedDeltaIP(), - candidate.cosPaXi(), - candidate.cosPaXYXi(), - candidate.cosPaLambda(), - candidate.cosPaXYLambda(), - candidate.invMassXiPi0(), - candidate.invMassXiPi1(), - flagMc); + // additional columns only stored in the full candidate table + candidate.cpaLambdaToXi(), + candidate.cpaXYLambdaToXi(), + 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( + particleFlag, + originMc, candidate.isSelXicToXiPiPi(), - candidate.posX(), - candidate.posY(), - candidate.posZ(), - candidate.xSecondaryVertex(), - candidate.ySecondaryVertex(), - candidate.zSecondaryVertex(), - candidate.chi2PCA(), - candidate.sign(), - candidate.e(o2::constants::physics::MassXiCPlus), - candidate.invMassXic(), - candidate.p(), - candidate.pt(), candidate.y(o2::constants::physics::MassXiCPlus), candidate.eta(), candidate.phi(), - candidate.ct(o2::constants::physics::MassXiCPlus), - candidate.decayLength(), - candidate.decayLengthXY(), - candidate.cpa(), - candidate.cpaXY(), + candidate.pt(), candidate.ptProng0(), candidate.ptProng1(), candidate.ptProng2(), + candidate.invMassXicPlus(), + candidate.chi2PCA(), + candidate.ct(o2::constants::physics::MassXiCPlus), + candidate.kfDecayLength(), + candidate.kfDecayLengthNormalised(), + candidate.kfDecayLengthXY(), + candidate.kfDecayLengthXYNormalised(), + candidate.cpa(), + candidate.cpaXY(), + candidate.cpaXi(), + candidate.cpaXYXi(), + candidate.cpaLambda(), + candidate.cpaXYLambda(), + candidate.cpaLambdaToXi(), + candidate.cpaXYLambdaToXi(), candidate.impactParameter0(), + candidate.impactParameterNormalised0(), candidate.impactParameter1(), + candidate.impactParameterNormalised1(), candidate.impactParameter2(), - candidate.cosPaXi(), - candidate.cosPaXYXi(), - candidate.cosPaLambda(), - candidate.cosPaXYLambda(), + candidate.impactParameterNormalised2(), + candidate.maxNormalisedDeltaIP(), + candidate.dcaXiDaughters(), + candidate.dcaV0Daughters(), + candidate.dcaXYCascToPV(), + candidate.dcaZCascToPV(), + candidate.dcaBachelorToPV(), + candidate.dcaPosToPV(), + candidate.dcaNegToPV(), + // PID information + 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.chi2TopoXicPlusToPVBefConst(), candidate.chi2TopoXicPlusToPV(), - candidate.chi2TopoXiToXicPlus(), - candidate.dcaXYPi0Pi1(), - candidate.dcaXYPi0Xi(), - candidate.dcaXYPi1Xi(), + candidate.chi2PrimXi(), + candidate.chi2PrimPi0(), + candidate.chi2PrimPi1(), + candidate.chi2DevPi0Pi1(), + candidate.chi2DevPi0Xi(), + candidate.chi2DevPi1Xi(), candidate.dcaPi0Pi1(), candidate.dcaPi0Xi(), candidate.dcaPi1Xi(), - candidate.dcacascdaughters(), - flagMc); + candidate.dcaXYPi0Pi1(), + candidate.dcaXYPi0Xi(), + candidate.dcaXYPi1Xi()); } else { rowCandidateFullKf( + particleFlag, + originMc, candidate.isSelXicToXiPiPi(), - candidate.posX(), - candidate.posY(), - candidate.posZ(), - candidate.xPvErr(), - candidate.yPvErr(), - candidate.zPvErr(), - candidate.xSecondaryVertex(), - candidate.ySecondaryVertex(), - candidate.zSecondaryVertex(), - candidate.chi2PCA(), - candidate.xSvErr(), - candidate.ySvErr(), - candidate.zSvErr(), - candidate.xDecayVtxXi(), - candidate.yDecayVtxXi(), - candidate.zDecayVtxXi(), - candidate.xDecayVtxLambda(), - candidate.yDecayVtxLambda(), - candidate.zDecayVtxLambda(), - candidate.sign(), - candidate.e(o2::constants::physics::MassXiCPlus), - candidate.invMassXic(), - candidate.p(), - candidate.pt(), candidate.y(o2::constants::physics::MassXiCPlus), candidate.eta(), candidate.phi(), - candidate.ct(o2::constants::physics::MassXiCPlus), - candidate.decayLength(), - candidate.decayLengthNormalised(), - candidate.decayLengthXY(), - candidate.decayLengthXYNormalised(), - candidate.cpa(), - candidate.cpaXY(), + candidate.pt(), candidate.ptProng0(), candidate.ptProng1(), candidate.ptProng2(), + candidate.invMassXicPlus(), + candidate.chi2PCA(), + candidate.ct(o2::constants::physics::MassXiCPlus), + candidate.kfDecayLength(), + candidate.kfDecayLengthNormalised(), + candidate.kfDecayLengthXY(), + candidate.kfDecayLengthXYNormalised(), + candidate.cpa(), + candidate.cpaXY(), + candidate.cpaXi(), + candidate.cpaXYXi(), + candidate.cpaLambda(), + candidate.cpaXYLambda(), + candidate.cpaLambdaToXi(), + candidate.cpaXYLambdaToXi(), candidate.impactParameter0(), candidate.impactParameterNormalised0(), candidate.impactParameter1(), @@ -565,42 +588,59 @@ struct HfTreeCreatorXicToXiPiPi { candidate.impactParameter2(), candidate.impactParameterNormalised2(), candidate.maxNormalisedDeltaIP(), - candidate.cosPaXi(), - candidate.cosPaXYXi(), - candidate.cosPaLambda(), - candidate.cosPaXYLambda(), + candidate.dcaXiDaughters(), + candidate.dcaV0Daughters(), + candidate.dcaXYCascToPV(), + candidate.dcaZCascToPV(), + candidate.dcaBachelorToPV(), + candidate.dcaPosToPV(), + candidate.dcaNegToPV(), + // additional columns only stored in the full candidate table + candidate.invMassXi(), candidate.invMassXiPi0(), candidate.invMassXiPi1(), + candidate.invMassLambda(), + candidate.p(), + candidate.pProng1(), + candidate.pProng2(), + candidate.pBachelorPi(), + candidate.pPiFromLambda(), + candidate.pPrFromLambda(), + // PID information + 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.chi2TopoXicPlusToPVBefConst(), candidate.chi2TopoXicPlusToPV(), - candidate.chi2TopoXiToXicPlus(), - candidate.dcaXYPi0Pi1(), - candidate.dcaXYPi0Xi(), - candidate.dcaXYPi1Xi(), + candidate.chi2PrimXi(), + candidate.chi2PrimPi0(), + candidate.chi2PrimPi1(), + candidate.chi2DevPi0Pi1(), + candidate.chi2DevPi0Xi(), + candidate.chi2DevPi1Xi(), candidate.dcaPi0Pi1(), candidate.dcaPi0Xi(), candidate.dcaPi1Xi(), - candidate.dcacascdaughters(), - flagMc); + candidate.dcaXYPi0Pi1(), + candidate.dcaXYPi0Xi(), + candidate.dcaXYPi1Xi()); } } } - void processData(aod::Collisions const& collisions, - SelectedCandidates const& candidates, - TracksWPid const&) + void processData(SelectedCandidates const& candidates) { - // Filling event properties - rowCandidateFullEvents.reserve(collisions.size()); - for (const auto& collision : collisions) { - fillEvent(collision); - } - // Filling candidate properties - if (fillCandidateDauIndexTable) { - rowCandidateDauIndices.reserve(candidates.size()); - } if (fillCandidateLiteTable) { rowCandidateLite.reserve(candidates.size()); } else { @@ -608,33 +648,19 @@ struct HfTreeCreatorXicToXiPiPi { } for (const auto& candidate : candidates) { if (fillOnlyBackground && downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (pseudoRndm >= downSampleBkgFactor && candidate.pt() < ptMaxForDownSample) { continue; } } fillCandidateTable(candidate); - if (fillCandidateDauIndexTable) { - fillIndexTable(candidate); - } } } - PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processData, "Process data", true); + PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processData, "Process data with DCAFitter reconstruction", true); - void processDataKf(aod::Collisions const& collisions, - SelectedCandidatesKf const& candidates, - TracksWPid const&) + void processDataKf(SelectedCandidatesKf const& candidates) { - // Filling event properties - rowCandidateFullEvents.reserve(collisions.size()); - for (const auto& collision : collisions) { - fillEvent(collision); - } - // Filling candidate properties - if (fillCandidateDauIndexTable) { - rowCandidateDauIndices.reserve(candidates.size()); - } if (fillCandidateLiteTable) { rowCandidateLite.reserve(candidates.size()); } else { @@ -642,36 +668,21 @@ struct HfTreeCreatorXicToXiPiPi { } for (const auto& candidate : candidates) { if (fillOnlyBackground && downSampleBkgFactor < 1.) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (pseudoRndm >= downSampleBkgFactor && candidate.pt() < ptMaxForDownSample) { continue; } } fillCandidateTable(candidate); - if (fillCandidateDauIndexTable) { - fillIndexTable(candidate); - } } } - PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processDataKf, "Process data with KF Particle reconstruction", false); + PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processDataKf, "Process data with KFParticle reconstruction", false); - void processMc(aod::Collisions const& collisions, - aod::McCollisions const&, - SelectedCandidatesMc const& candidates, - soa::Join const& particles, - TracksWPid const&) + void processMc(SelectedCandidatesMc const& candidates, + MatchedGenXicToXiPiPi const& particles) { - // Filling event properties - rowCandidateFullEvents.reserve(collisions.size()); - for (const auto& collision : collisions) { - fillEvent(collision); - } - // Filling candidate properties if (fillOnlySignal) { - if (fillCandidateDauIndexTable) { - rowCandidateDauIndices.reserve(candidates.size()); - } if (fillCandidateLiteTable) { rowCandidateLite.reserve(recSig.size()); } else { @@ -679,33 +690,21 @@ struct HfTreeCreatorXicToXiPiPi { } for (const auto& candidate : recSig) { fillCandidateTable(candidate); - if (fillCandidateDauIndexTable) { - fillIndexTable(candidate); - } } } else if (fillOnlyBackground) { - if (fillCandidateDauIndexTable) { - rowCandidateDauIndices.reserve(candidates.size()); - } if (fillCandidateLiteTable) { rowCandidateLite.reserve(recBg.size()); } else { rowCandidateFull.reserve(recBg.size()); } for (const auto& candidate : recBg) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } fillCandidateTable(candidate); - if (fillCandidateDauIndexTable) { - fillIndexTable(candidate); - } } } else { - if (fillCandidateDauIndexTable) { - rowCandidateDauIndices.reserve(candidates.size()); - } if (fillCandidateLiteTable) { rowCandidateLite.reserve(candidates.size()); } else { @@ -713,45 +712,31 @@ struct HfTreeCreatorXicToXiPiPi { } for (const auto& candidate : candidates) { fillCandidateTable(candidate); - if (fillCandidateDauIndexTable) { - fillIndexTable(candidate); - } } } - // Filling particle properties - 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)) { + if (fillGenParticleTable) { + rowCandidateFullParticles.reserve(particles.size()); + for (const auto& particle : particles) { rowCandidateFullParticles( - particle.mcCollision().bcId(), + particle.flagMcMatchGen(), + particle.originMcGen(), + particle.pdgBhadMotherPart(), particle.pt(), particle.eta(), particle.phi(), - RecoDecay::y(std::array{particle.px(), particle.py(), particle.pz()}, o2::constants::physics::MassXiCPlus), - particle.flagMcMatchGen()); + RecoDecay::y(particle.pVector(), o2::constants::physics::MassXiCPlus), + particle.decayLengthMcGen()); } } } - PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processMc, "Process MC", false); + PROCESS_SWITCH(HfTreeCreatorXicToXiPiPi, processMc, "Process MC with DCAFitter reconstruction", false); - void processMcKf(aod::Collisions const& collisions, - aod::McCollisions const&, - SelectedCandidatesKfMc const& candidates, - soa::Join const& particles, - TracksWPid const&) + void processMcKf(SelectedCandidatesKfMc const& candidates, + MatchedGenXicToXiPiPi const& particles) { - // Filling event properties - rowCandidateFullEvents.reserve(collisions.size()); - for (const auto& collision : collisions) { - fillEvent(collision); - } - // Filling candidate properties if (fillOnlySignal) { - if (fillCandidateDauIndexTable) { - rowCandidateDauIndices.reserve(candidates.size()); - } if (fillCandidateLiteTable) { rowCandidateLite.reserve(recSigKf.size()); } else { @@ -759,33 +744,21 @@ struct HfTreeCreatorXicToXiPiPi { } for (const auto& candidate : recSigKf) { fillCandidateTable(candidate); - if (fillCandidateDauIndexTable) { - fillIndexTable(candidate); - } } } else if (fillOnlyBackground) { - if (fillCandidateDauIndexTable) { - rowCandidateDauIndices.reserve(candidates.size()); - } if (fillCandidateLiteTable) { rowCandidateLite.reserve(recBgKf.size()); } else { rowCandidateFull.reserve(recBgKf.size()); } for (const auto& candidate : recBgKf) { - float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000); + float const pseudoRndm = candidate.ptProng1() * 1000. - static_cast(candidate.ptProng1() * 1000); if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) { continue; } fillCandidateTable(candidate); - if (fillCandidateDauIndexTable) { - fillIndexTable(candidate); - } } } else { - if (fillCandidateDauIndexTable) { - rowCandidateDauIndices.reserve(candidates.size()); - } if (fillCandidateLiteTable) { rowCandidateLite.reserve(candidates.size()); } else { @@ -793,23 +766,21 @@ struct HfTreeCreatorXicToXiPiPi { } for (const auto& candidate : candidates) { fillCandidateTable(candidate); - if (fillCandidateDauIndexTable) { - fillIndexTable(candidate); - } } } - // Filling particle properties - 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)) { + if (fillGenParticleTable) { + rowCandidateFullParticles.reserve(particles.size()); + for (const auto& particle : particles) { rowCandidateFullParticles( - particle.mcCollision().bcId(), + particle.flagMcMatchGen(), + particle.originMcGen(), + particle.pdgBhadMotherPart(), particle.pt(), particle.eta(), particle.phi(), - RecoDecay::y(std::array{particle.px(), particle.py(), particle.pz()}, o2::constants::physics::MassXiCPlus), - particle.flagMcMatchGen()); + RecoDecay::y(particle.pVector(), o2::constants::physics::MassXiCPlus), + particle.decayLengthMcGen()); } } } diff --git a/PWGHF/TableProducer/treeCreatorXiccToPKPiPi.cxx b/PWGHF/TableProducer/treeCreatorXiccToPKPiPi.cxx index 2ceeb567de2..305ec024513 100644 --- a/PWGHF/TableProducer/treeCreatorXiccToPKPiPi.cxx +++ b/PWGHF/TableProducer/treeCreatorXiccToPKPiPi.cxx @@ -17,14 +17,25 @@ /// /// \author Jinjoo Seo , Inha University -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/ALICE3/Core/DecayChannelsLegacy.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/PIDResponseTOF.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + using namespace o2; using namespace o2::framework; @@ -162,8 +173,6 @@ struct HfTreeCreatorXiccToPKPiPi { Produces rowCandidateFullEvents; Produces rowCandidateFullParticles; - HfHelper hfHelper; - using TracksWPid = soa::Join; void init(InitContext const&) @@ -194,12 +203,12 @@ struct HfTreeCreatorXiccToPKPiPi { // Filling candidate properties rowCandidateFull.reserve(candidates.size()); for (const auto& candidate : candidates) { - auto fillTable = [&](int CandFlag, - int FunctionSelection, - float FunctionInvMass, - float FunctionCt, - float FunctionY) { - if (FunctionSelection >= 1) { + auto fillTable = [&](int candFlag, + int functionSelection, + float functionInvMass, + float functionCt, + float functionY) { + if (functionSelection >= 1) { auto xicCand = candidate.prong0(); rowCandidateFull( @@ -227,10 +236,10 @@ struct HfTreeCreatorXiccToPKPiPi { candidate.errorImpactParameter0(), candidate.errorImpactParameter1(), candidate.impactParameterProduct(), - hfHelper.invMassXicToPKPi(xicCand), - hfHelper.ctXic(xicCand), - hfHelper.yXic(xicCand), - hfHelper.eXic(xicCand), + HfHelper::invMassXicToPKPi(xicCand), + HfHelper::ctXic(xicCand), + HfHelper::yXic(xicCand), + HfHelper::eXic(xicCand), xicCand.eta(), xicCand.cpa(), xicCand.cpaXY(), @@ -243,22 +252,22 @@ struct HfTreeCreatorXiccToPKPiPi { xicCand.prong1_as().tofNSigmaKa(), xicCand.prong2_as().tofNSigmaPr(), xicCand.prong2_as().tofNSigmaPi(), - 1 << CandFlag, - FunctionInvMass, + 1 << candFlag, + functionInvMass, candidate.pt(), candidate.p(), candidate.cpa(), candidate.cpaXY(), - FunctionCt, + functionCt, candidate.eta(), candidate.phi(), - FunctionY, + functionY, candidate.flagMcMatchRec(), candidate.originMcRec()); } }; - fillTable(0, candidate.isSelXiccToPKPiPi(), hfHelper.invMassXiccToXicPi(candidate), hfHelper.ctXicc(candidate), hfHelper.yXicc(candidate)); + fillTable(0, candidate.isSelXiccToPKPiPi(), HfHelper::invMassXiccToXicPi(candidate), HfHelper::ctXicc(candidate), HfHelper::yXicc(candidate)); } // Filling particle properties diff --git a/PWGHF/Tasks/CMakeLists.txt b/PWGHF/Tasks/CMakeLists.txt index 00878e48a2c..d75bbfee3c8 100644 --- a/PWGHF/Tasks/CMakeLists.txt +++ b/PWGHF/Tasks/CMakeLists.txt @@ -39,6 +39,21 @@ o2physics_add_dpl_workflow(task-mc-validation PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) +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::AnalysisCCDB O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(task-mc-injection + SOURCES taskMcInjection.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + # o2physics_add_dpl_workflow(task-sel-optimisation # SOURCES taskSelOptimisation.cxx # PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/PWGHF/Tasks/taskCharmHadImpactPar.cxx b/PWGHF/Tasks/taskCharmHadImpactPar.cxx index dc37599ccff..ca288dfa839 100644 --- a/PWGHF/Tasks/taskCharmHadImpactPar.cxx +++ b/PWGHF/Tasks/taskCharmHadImpactPar.cxx @@ -13,19 +13,44 @@ /// \brief Analysis task to produce impact-parameter distributions of charm hadrons /// /// \author Fabrizio Grosa , CERN +/// \author Antonio Palasciano , INFN Bari -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include 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, @@ -33,116 +58,325 @@ enum Channel : uint8_t { 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 { - Configurable selectionFlag{"selectionFlag", 15, "Selection Flag for the considered charm hadron"}; - 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 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"}; + Produces hfCharmCandLite; - HfHelper hfHelper; + 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"}; + 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{doprocessDplus, doprocessDplusWithMl, doprocessDzero, doprocessDzeroWithMl}; + 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 (doprocessDplus || doprocessDzero) { - registry.add("hMassPtImpPar", ";#it{M} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c});dca XY (#mum);", HistType::kTHnSparseF, {axisMass, axisPt, axisImpPar}); - } else if (doprocessDplusWithMl || doprocessDzeroWithMl) { - registry.add("hMassPtImpPar", ";#it{M} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c});dca XY (#mum);ML score 0;ML score 1; ML score 2;", HistType::kTHnSparseF, {axisMass, axisPt, axisImpPar, axisMlScore0, axisMlScore1, axisMlScore2}); + 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 + template void fillSparse(const CCands& candidate) { std::vector outputMl = {-999., -999., -999.}; float invMass{-1.f}; - if constexpr (channel == Channel::DplusToKPiPi) { // D+ -> Kpipi - invMass = hfHelper.invMassDplusToPiKPi(candidate); - if constexpr (withMl) { + float yCand{-999.f}; + if constexpr (Channel == Channel::DplusToKPiPi) { // D+ -> Kpipi + if constexpr (DoMc) { + if (fillOnlySignal) { + if (std::abs(candidate.flagMcMatchRec()) != o2::hf_decay::hf_cand_3prong::DecayChannelMain::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("hMassPtImpPar"), invMass, candidate.pt(), candidate.impactParameterXY(), outputMl[0], outputMl[1], outputMl[2]); + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand, outputMl[0], outputMl[1], outputMl[2]); } else { - registry.fill(HIST("hMassPtImpPar"), invMass, candidate.pt(), candidate.impactParameterXY()); + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand); } - } else if constexpr (channel == Channel::DzeroToKPi) { + } else if constexpr (Channel == Channel::DzeroToKPi) { if (candidate.isSelD0()) { // D0 -> Kpi - invMass = hfHelper.invMassD0ToPiK(candidate); - if constexpr (withMl) { + if constexpr (DoMc) { + if (fillOnlySignal) { + if (std::abs(candidate.flagMcMatchRec()) != o2::hf_decay::hf_cand_2prong::DecayChannelMain::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("hMassPtImpPar"), invMass, candidate.pt(), candidate.impactParameterXY(), outputMl[0], outputMl[1], outputMl[2]); + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand, outputMl[0], outputMl[1], outputMl[2]); } else { - registry.fill(HIST("hMassPtImpPar"), invMass, candidate.pt(), candidate.impactParameterXY()); + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand); } } if (candidate.isSelD0bar()) { - invMass = hfHelper.invMassD0barToKPi(candidate); - if constexpr (withMl) { + 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("hMassPtImpPar"), invMass, candidate.pt(), candidate.impactParameterXY(), outputMl[0], outputMl[1], outputMl[2]); + registry.fill(HIST("hMassPtImpParPhiY"), invMass, candidate.pt(), candidate.impactParameterXY(), candidate.phi(), yCand, outputMl[0], outputMl[1], outputMl[2]); } else { - registry.fill(HIST("hMassPtImpPar"), invMass, candidate.pt(), candidate.impactParameterXY()); + 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.f; + float occupancy = 0.f; + if (centEstimator != CentralityEstimator::None) { + centrality = getCentralityColl(collision, centEstimator); + } + if (occEstimator != OccupancyEstimator::None) { + occupancy = o2::hf_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) + template + void runAnalysis(const CCands& candidates, CollisionsCent const&) { for (auto const& candidate : candidates) { - fillSparse(candidate); + auto collision = candidate.template collision_as(); + fillSparse(candidate); + if (fillLightTreeCandidate) { + fillTree(candidate, collision); + } } } // process functions - void processDplus(CandDplusData const& candidates) + 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); + runAnalysis(candidates, collisions); } - PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDplus, "Process D+ w/o ML", false); + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDataDzero, "Process Data D0 w/o ML", false); - void processDplusWithMl(CandDplusDataWithMl const& candidates) + void processDataDzeroWithMl(CandDzeroDataWithMl const& candidates, CollisionsCent const& collisions) { - runAnalysis(candidates); + runAnalysis(candidates, collisions); } - PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDplusWithMl, "Process D+ with ML", true); + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDataDzeroWithMl, "Process Data D0 with ML", false); - void processDzero(CandDzeroData const& candidates) + void processMCDzero(CandDzeroMc const& candidates, CollisionsCent const& collisions) { - runAnalysis(candidates); + runAnalysis(candidates, collisions); } - PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDzero, "Process D0 w/o ML", false); + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processMCDzero, "Process MC D0 w/o ML", false); - void processDzeroWithMl(CandDzeroDataWithMl const& candidates) + void processMCDzeroWithMl(CandDzeroMcWithMl const& candidates, CollisionsCent const& collisions) { - runAnalysis(candidates); + runAnalysis(candidates, collisions); } - PROCESS_SWITCH(HfTaskCharmHadImpactPar, processDzeroWithMl, "Process D0 with ML", false); + PROCESS_SWITCH(HfTaskCharmHadImpactPar, processMCDzeroWithMl, "Process MC D0 with ML", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/Tasks/taskLcCentrality.cxx b/PWGHF/Tasks/taskLcCentrality.cxx index aafdb93b8fe..ce3752b40e1 100644 --- a/PWGHF/Tasks/taskLcCentrality.cxx +++ b/PWGHF/Tasks/taskLcCentrality.cxx @@ -16,15 +16,29 @@ /// \author Luigi Dello Stritto , University and INFN SALERNO /// \author Vít Kučera , CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" - -#include "Common/DataModel/Centrality.h" - +#include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include using namespace o2; using namespace o2::analysis; @@ -33,11 +47,11 @@ using namespace o2::framework::expressions; void customize(std::vector& workflowOptions) { - ConfigParamSpec optionDoMC{"doMC", VariantType::Bool, true, {"Fill MC histograms."}}; + ConfigParamSpec const optionDoMC{"doMC", VariantType::Bool, true, {"Fill MC histograms."}}; workflowOptions.push_back(optionDoMC); } -#include "Framework/runDataProcessing.h" +#include /// Λc± → p± K∓ π± analysis task struct HfTaskLcCentrality { @@ -45,8 +59,6 @@ struct HfTaskLcCentrality { Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc); HistogramRegistry registry{ @@ -79,21 +91,21 @@ struct HfTaskLcCentrality { void process(soa::Join::iterator const& collision, soa::Filtered> const& candidates) { - float centrality = collision.centRun2V0M(); + float const centrality = collision.centRun2V0M(); registry.fill(HIST("hCentrality"), centrality); for (const auto& candidate : candidates) { - if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + if ((candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) == 0) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yLc(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yLc(candidate)) > yCandMax) { continue; } if (candidate.isSelLcToPKPi() >= selectionFlagLc) { - registry.fill(HIST("hMass"), hfHelper.invMassLcToPKPi(candidate), candidate.pt(), centrality); + registry.fill(HIST("hMass"), HfHelper::invMassLcToPKPi(candidate), candidate.pt(), centrality); } if (candidate.isSelLcToPiKP() >= selectionFlagLc) { - registry.fill(HIST("hMass"), hfHelper.invMassLcToPiKP(candidate), candidate.pt(), centrality); + registry.fill(HIST("hMass"), HfHelper::invMassLcToPiKP(candidate), candidate.pt(), centrality); } registry.fill(HIST("hPtCand"), candidate.pt()); registry.fill(HIST("hPtProng0"), candidate.ptProng0()); @@ -103,7 +115,7 @@ struct HfTaskLcCentrality { registry.fill(HIST("hd0Prong0"), candidate.impactParameter0(), candidate.pt()); registry.fill(HIST("hd0Prong1"), candidate.impactParameter1(), candidate.pt()); registry.fill(HIST("hd0Prong2"), candidate.impactParameter2(), candidate.pt()); - registry.fill(HIST("hCt"), hfHelper.ctLc(candidate), candidate.pt()); + registry.fill(HIST("hCt"), HfHelper::ctLc(candidate), candidate.pt()); registry.fill(HIST("hCPA"), candidate.cpa(), candidate.pt()); registry.fill(HIST("hEta"), candidate.eta(), candidate.pt()); registry.fill(HIST("hSelectionStatus"), candidate.isSelLcToPKPi(), candidate.pt()); @@ -123,8 +135,6 @@ struct HfTaskLcCentralityMc { Configurable yCandMax{"yCandMax", -1., "max. cand. rapidity"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_lc_to_p_k_pi::vecBinsPt}, "pT bin limits"}; - HfHelper hfHelper; - Filter filterSelectCandidates = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc); HistogramRegistry registry{ @@ -154,13 +164,13 @@ struct HfTaskLcCentralityMc { { // MC rec. for (const auto& candidate : candidates) { - if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) { + if ((candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) == 0) { continue; } - if (yCandMax >= 0. && std::abs(hfHelper.yLc(candidate)) > yCandMax) { + if (yCandMax >= 0. && std::abs(HfHelper::yLc(candidate)) > yCandMax) { continue; } - if (std::abs(candidate.flagMcMatchRec()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { + if (std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { // Get the corresponding MC particle. auto indexMother = RecoDecay::getMother(mcParticles, candidate.prong0_as().mcParticle_as>(), o2::constants::physics::Pdg::kLambdaCPlus, true); auto particleMother = mcParticles.rawIteratorAt(indexMother); @@ -182,7 +192,7 @@ struct HfTaskLcCentralityMc { } // MC gen. for (const auto& particle : mcParticles) { - if (std::abs(particle.flagMcMatchGen()) == 1 << aod::hf_cand_3prong::DecayType::LcToPKPi) { + if (std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { if (yCandMax >= 0. && std::abs(RecoDecay::y(particle.pVector(), o2::constants::physics::MassLambdaCPlus)) > yCandMax) { continue; } diff --git a/PWGHF/Tasks/taskMcEfficiency.cxx b/PWGHF/Tasks/taskMcEfficiency.cxx index 024632dd7a1..5f706c7bede 100644 --- a/PWGHF/Tasks/taskMcEfficiency.cxx +++ b/PWGHF/Tasks/taskMcEfficiency.cxx @@ -14,18 +14,42 @@ /// /// \author Jan Fiete Grosse-Oetringhaus, CERN -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -39,14 +63,13 @@ 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"}; Configurable mcAcceptanceEta{"mcAcceptanceEta", 0.8, "MC Acceptance: upper eta limit"}; Service pdg; - HfHelper hfHelper; enum HFStep { kHFStepMC = 0, kHFStepMcInRapidity, // MC mothers in rapidity |y| < 0.5 @@ -95,14 +118,14 @@ struct HfTaskMcEfficiency { } template - inline bool checkTrack(T track) + bool checkTrack(T track) { // TODO configurable? return track.isGlobalTrackWoDCA(); } - template - void candidate3ProngLoop(T1& candidates, T2& tracks, T3& mcParticles, std::vector pdgCodes) + template + void candidate3ProngLoop(T1 const& candidates, T2 const& tracks, T3 const& mcParticles, std::vector const& pdgCodes) { using TracksType = std::decay_t; @@ -113,7 +136,7 @@ struct HfTaskMcEfficiency { for (const auto pdgCode : pdgCodes) { /// loop on pdg codes auto decayType = -1; - std::array pdgDaughters; + std::array pdgDaughters{}; if (pdgCode == Pdg::kDPlus) { decayType = 1 << aod::hf_cand_3prong::DecayType::DplusToPiKPi; @@ -130,6 +153,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); } @@ -147,29 +175,35 @@ struct HfTaskMcEfficiency { bool isHypoMass1SelStep = false; bool isHypoMass2SelStep = false; /// selections from candidate selectors - if constexpr (hasDplus) { + if constexpr (HasDplus) { if (pdgCode == Pdg::kDPlus) { isHypoMass1SelStep = candidate.isSelDplusToPiKPi(); // only one mass hypo for D+ } } - if constexpr (hasDs) { + if constexpr (HasDs) { if (pdgCode == Pdg::kDS) { isHypoMass1SelStep = candidate.isSelDsToKKPi(); isHypoMass2SelStep = candidate.isSelDsToPiKK(); } } - if constexpr (hasLc) { + if constexpr (HasLc) { if (pdgCode == Pdg::kLambdaCPlus) { isHypoMass1SelStep = candidate.isSelLcToPKPi(); isHypoMass2SelStep = candidate.isSelLcToPiKP(); } } + if constexpr (HasXicPlus) { + if (pdgCode == Pdg::kXiCPlus) { + isHypoMass1SelStep = candidate.isSelXicToPKPi(); + isHypoMass2SelStep = candidate.isSelXicToPiKP(); + } + } bool collisionMatched = false; int origin = RecoDecay::OriginType::None; - if constexpr (mc) { /// info MC used + if constexpr (Mc) { /// info MC used int8_t sign = 0; - int indexRec = RecoDecay::getMatchedMCRec(mcParticles, std::array{trackPos, trackNeg, trackThird}, pdgCode, pdgDaughters, true, &sign, 2); + int const indexRec = RecoDecay::getMatchedMCRec(mcParticles, std::array{trackPos, trackNeg, trackThird}, pdgCode, pdgDaughters, true, &sign, 2); if (indexRec < 0) { continue; @@ -194,31 +228,52 @@ 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 float massHypo1 = -1; float massHypo2 = -1; - float cpa = candidate.cpa(); - float pt = candidate.pt(); + float const cpa = candidate.cpa(); + float const pt = candidate.pt(); // bool selected = false; /// all candidates if (isHypoMass1TrackStep) { if (pdgCode == Pdg::kLambdaCPlus) { - massHypo1 = hfHelper.invMassLcToPKPi(candidate); + massHypo1 = HfHelper::invMassLcToPKPi(candidate); + } else if (pdgCode == Pdg::kXiCPlus) { + massHypo1 = HfHelper::invMassXicToPKPi(candidate); } else if (pdgCode == Pdg::kDPlus) { - massHypo1 = hfHelper.invMassDplusToPiKPi(candidate); + massHypo1 = HfHelper::invMassDplusToPiKPi(candidate); } else if (pdgCode == Pdg::kDS) { - massHypo1 = hfHelper.invMassDsToKKPi(candidate); + massHypo1 = HfHelper::invMassDsToKKPi(candidate); } hCandidates->Fill(kHFStepTracked, pt, massHypo1, pdgCode, cpa, collisionMatched, origin); } if (isHypoMass2TrackStep) { if (pdgCode == Pdg::kLambdaCPlus) { - massHypo2 = hfHelper.invMassLcToPiKP(candidate); + massHypo2 = HfHelper::invMassLcToPiKP(candidate); + } else if (pdgCode == Pdg::kXiCPlus) { + massHypo2 = HfHelper::invMassXicToPiKP(candidate); } else if (pdgCode == Pdg::kDS) { - massHypo2 = hfHelper.invMassDsToPiKK(candidate); + massHypo2 = HfHelper::invMassDsToPiKK(candidate); } hCandidates->Fill(kHFStepTracked, pt, massHypo2, pdgCode, cpa, collisionMatched, origin); } @@ -248,8 +303,8 @@ struct HfTaskMcEfficiency { // duplicates std::array prongIds = {candidate.prong0Id(), candidate.prong1Id(), candidate.prong2Id()}; std::sort(prongIds.begin(), prongIds.end()); - std::string concat = std::to_string(prongIds[0]) + std::to_string(prongIds[1]) + std::to_string(prongIds[2]); - std::size_t hash = std::hash{}(concat); /// unique value for the 'concat' string + std::string const concat = std::to_string(prongIds[0]) + std::to_string(prongIds[1]) + std::to_string(prongIds[2]); + std::size_t const hash = std::hash{}(concat); /// unique value for the 'concat' string if (duplicates.find(hash) != duplicates.end()) { if (isHypoMass1TrackStep) { hCandidates->Fill(kHFStepTrackedDuplicates, pt, massHypo1, pdgCode, cpa, collisionMatched, origin); @@ -261,7 +316,7 @@ struct HfTaskMcEfficiency { duplicates[hash]++; } /// end loop on pdg codes - } /// end loop over candidates + } /// end loop over candidates auto hDuplicateCount = registry.get(HIST("hDuplicateCount")); for (const auto& i : duplicates) { @@ -269,8 +324,8 @@ struct HfTaskMcEfficiency { } } - template - void candidate2ProngLoop(T1 const& candidates, T2 const& tracks, T3 const& mcParticles, std::vector pdgCodes) + template + void candidate2ProngLoop(T1 const& candidates, T2 const& tracks, T3 const& mcParticles, std::vector const& pdgCodes) { using TracksType = std::decay_t; @@ -279,7 +334,7 @@ struct HfTaskMcEfficiency { for (const auto pdgCode : pdgCodes) { auto decayType = -1; - std::array pdgDaughters; + std::array pdgDaughters{}; if (pdgCode == Pdg::kD0) { decayType = 1 << aod::hf_cand_2prong::DecayType::D0ToPiK; @@ -305,7 +360,7 @@ struct HfTaskMcEfficiency { bool collisionMatched = false; int origin = RecoDecay::OriginType::None; - if constexpr (mc) { + if constexpr (Mc) { auto indexRec = RecoDecay::getMatchedMCRec(mcParticles, std::array{trackPos, trackNeg}, pdgCode, pdgDaughters, false); if (indexRec < 0) { continue; @@ -316,14 +371,14 @@ struct HfTaskMcEfficiency { } float mass = -1; - float cpa = candidate.cpa(); - float pt = candidate.pt(); + float const cpa = candidate.cpa(); + float const pt = candidate.pt(); bool selected = false; if (pdgCode == Pdg::kD0) { - mass = hfHelper.invMassD0ToPiK(candidate); + mass = HfHelper::invMassD0ToPiK(candidate); selected = candidate.isSelD0() >= selectionFlagD0; } else if (pdgCode == Pdg::kD0Bar) { - mass = hfHelper.invMassD0barToKPi(candidate); + mass = HfHelper::invMassD0barToKPi(candidate); selected = candidate.isSelD0bar() >= selectionFlagD0bar; } LOGP(debug, "Candidate {} has prong {} and prong {} and pT {} and mass {}", candidate.globalIndex(), candidate.prong0Id(), candidate.prong1Id(), candidate.pt(), mass); @@ -349,9 +404,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); @@ -410,7 +465,7 @@ struct HfTaskMcEfficiency { continue; } - int origin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle); + int const origin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle); hCandidates->Fill(kHFStepMC, mcParticle.pt(), mass, pdgCode, 1.0, true, origin); @@ -481,10 +536,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")); @@ -522,7 +577,7 @@ struct HfTaskMcEfficiency { continue; } - std::array pdgDaughters; + std::array pdgDaughters{}; if (pdgCode == Pdg::kDPlus) { pdgDaughters[0] = +kPiPlus; pdgDaughters[1] = -kKPlus; @@ -535,19 +590,23 @@ 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); } /// check if we end-up with the correct final state using MC info int8_t sign = 0; - std::unique_ptr> listIndexDaughters(new std::vector{}); + std::unique_ptr> const listIndexDaughters(new std::vector{}); if (!RecoDecay::isMatchedMCGen(mcParticles, mcParticle, pdgCode, pdgDaughters, true, &sign, 2, listIndexDaughters.get())) { /// check if we have Λc± → p± K∓ π± (either direct or resonant), or D± → π± K∓ π± (either direct or resonant) or Ds± → K± K∓ π± (either direct or resonant) continue; } - int origin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle); + int const origin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle); hCandidates->Fill(kHFStepMC, mcParticle.pt(), mass, pdgCode * sign, 1.0, true, origin); @@ -644,7 +703,7 @@ struct HfTaskMcEfficiency { } /// end "if(selected[...])" } /// end loop over MC particles - } /// end loop over PDG codes + } /// end loop over PDG codes } /// end candidate3ProngMcLoop @@ -652,7 +711,7 @@ struct HfTaskMcEfficiency { void processDataD0(soa::Join const& candidates, TracksWithSelection const& tracks) { - std::vector pdgCodes{Pdg::kD0Bar, Pdg::kD0}; + std::vector const pdgCodes{Pdg::kD0Bar, Pdg::kD0}; candidate2ProngLoop(candidates, tracks, tracks, pdgCodes); // NOTE third argument has to be provided but is not used as template argument is } PROCESS_SWITCH(HfTaskMcEfficiency, processDataD0, "Process D0 data (no MC information needed)", false); @@ -660,56 +719,64 @@ struct HfTaskMcEfficiency { void processDataDplus(soa::Join const& candidates, TracksWithSelection const& tracks) { - std::vector pdgCodes{Pdg::kDPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + std::vector const pdgCodes{Pdg::kDPlus}; + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDplus, "Process D+ data (no MC information needed)", false); void processDataDs(soa::Join const& candidates, TracksWithSelection const& tracks) { - std::vector pdgCodes{Pdg::kDS}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + std::vector const pdgCodes{Pdg::kDS}; + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDs, "Process Ds+ data (no MC information needed)", false); void processDataLc(soa::Join const& candidates, TracksWithSelection const& tracks) { - std::vector pdgCodes{Pdg::kLambdaCPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + std::vector const pdgCodes{Pdg::kLambdaCPlus}; + 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 const 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); + std::vector const pdgCodes{Pdg::kDPlus, Pdg::kDS}; + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDplusDs, "Process D+ and Ds+ data (no MC information needed)", false); void processDataDplusDsLc(soa::Join const& candidates, TracksWithSelection const& tracks) { - std::vector pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + std::vector const pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDplusDsLc, "Process D+, Ds+, and Lc data (no MC information needed)", false); void processDataDplusLc(soa::Join const& candidates, TracksWithSelection const& tracks) { - std::vector pdgCodes{Pdg::kDPlus, Pdg::kLambdaCPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + std::vector const pdgCodes{Pdg::kDPlus, Pdg::kLambdaCPlus}; + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDplusLc, "Process D+ and Lc data (no MC information needed)", false); void processDataDsLc(soa::Join const& candidates, TracksWithSelection const& tracks) { - std::vector pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; - candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); + std::vector const pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; + candidate3ProngLoop(candidates, tracks, tracks, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processDataDsLc, "Process Ds+ and Lc data (no MC information needed)", false); @@ -719,7 +786,7 @@ struct HfTaskMcEfficiency { aod::McParticles const& mcParticles, aod::McCollisionLabels const& colls) { - std::vector pdgCodes{Pdg::kD0Bar, Pdg::kD0}; + std::vector const pdgCodes{Pdg::kD0Bar, Pdg::kD0}; candidate2ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcD0, "Process MC for D0 signal", true); @@ -729,8 +796,8 @@ struct HfTaskMcEfficiency { aod::McParticles const& mcParticles, aod::McCollisionLabels const& colls) { - std::vector pdgCodes{Pdg::kDPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + std::vector const pdgCodes{Pdg::kDPlus}; + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDplus, "Process MC for D+ signal", false); @@ -739,8 +806,8 @@ struct HfTaskMcEfficiency { aod::McParticles const& mcParticles, aod::McCollisionLabels const& colls) { - std::vector pdgCodes{Pdg::kDS}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + std::vector const pdgCodes{Pdg::kDS}; + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDs, "Process MC for Ds+ signal", false); @@ -749,18 +816,28 @@ struct HfTaskMcEfficiency { aod::McParticles const& mcParticles, aod::McCollisionLabels const& colls) { - std::vector pdgCodes{Pdg::kLambdaCPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + std::vector const pdgCodes{Pdg::kLambdaCPlus}; + 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 const 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); + std::vector const pdgCodes{Pdg::kDPlus, Pdg::kDS}; + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDplusDs, "Process MC for D+ and Ds+ signals", false); @@ -769,8 +846,8 @@ struct HfTaskMcEfficiency { aod::McParticles const& mcParticles, aod::McCollisionLabels const& colls) { - std::vector pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + std::vector const pdgCodes{Pdg::kDPlus, Pdg::kDS, Pdg::kLambdaCPlus}; + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDplusDsLc, "Process MC for D+, Ds+, and Lc signals", false); @@ -779,8 +856,8 @@ struct HfTaskMcEfficiency { aod::McParticles const& mcParticles, aod::McCollisionLabels const& colls) { - std::vector pdgCodes{Pdg::kDPlus, Pdg::kLambdaCPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + std::vector const pdgCodes{Pdg::kDPlus, Pdg::kLambdaCPlus}; + candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); } PROCESS_SWITCH(HfTaskMcEfficiency, processMcDplusLc, "Process MC for D+ and Lc signals", false); @@ -789,8 +866,8 @@ struct HfTaskMcEfficiency { aod::McParticles const& mcParticles, aod::McCollisionLabels const& colls) { - std::vector pdgCodes{Pdg::kDS, Pdg::kLambdaCPlus}; - candidate3ProngMcLoop(candidates, tracks, mcParticles, colls, pdgCodes); + std::vector const pdgCodes{Pdg::kDS, Pdg::kLambdaCPlus}; + 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 ffb34743fff..4ac10b7c538 100644 --- a/PWGHF/Tasks/taskMcEfficiencyToXiPi.cxx +++ b/PWGHF/Tasks/taskMcEfficiencyToXiPi.cxx @@ -14,21 +14,32 @@ /// /// \author Federica Zanone, Heidelberg University -#include "TMCProcess.h" // for VMC Particle Production Process - -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // for VMC Particle Production Process +#include + +#include using namespace o2; -using namespace o2::analysis; using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; @@ -44,9 +55,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"}; - ConfigurableAxis axisPt{"axisPt", {200, 0, 20}, "pT axis"}; - ConfigurableAxis axisMass{"axisMass", {900, 2.1, 3}, "m_inv axis"}; - enum HFStep { kHFStepMC = 0, // all generated mothers kHFStepMcInRapidity, // MC mother in rapidity |y| < rapidityCharmBaryonMax=0.5 kHFStepAcceptance, // MC mother where all final state candidates pass eta and pt selection @@ -72,6 +80,9 @@ struct HfTaskMcEfficiencyToXiPi { using ParticleInfoOmegac0 = soa::Join; using BCsInfo = soa::Join; + ConfigurableAxis axisPt{"axisPt", {200, 0, 20}, "pT axis"}; + ConfigurableAxis axisMass{"axisMass", {900, 2.1, 3}, "m_inv axis"}; + HistogramRegistry registry{"registry"}; void init(InitContext&) @@ -94,13 +105,13 @@ struct HfTaskMcEfficiencyToXiPi { } template - inline bool checkTrackGlbTrk(T const& track) + bool checkTrackGlbTrk(T const& track) { return (track.isGlobalTrackWoDCA() && track.tpcNClsFound() > nClustersTpcMin && track.itsNCls() > nClustersItsMin); } template - inline bool checkTrackItsTrk(T const& track) + bool checkTrackItsTrk(T const& track) { return (track.isQualityTrackITS() && track.itsNCls() > nClustersItsMin); } @@ -139,11 +150,11 @@ struct HfTaskMcEfficiencyToXiPi { pt = RecoDecay::sqrtSumOfSquares(candidate.pxCharmBaryon(), candidate.pyCharmBaryon()); // all candidates (candidateCreator) - hCandidates->Fill(kHFStepTracked, pt, mass, candidate.collisionMatched(), candidate.originRec()); + hCandidates->Fill(kHFStepTracked, pt, mass, candidate.collisionMatched(), candidate.originMcRec()); // check xi-pi candidate passed candidate selector cuts (except PID) if (candidate.resultSelections() && candidate.statusInvMassLambda() && candidate.statusInvMassCascade() && candidate.statusInvMassCharmBaryon()) { - hCandidates->Fill(kHFStepTrackedCuts, pt, mass, candidate.collisionMatched(), candidate.originRec()); + hCandidates->Fill(kHFStepTrackedCuts, pt, mass, candidate.collisionMatched(), candidate.originMcRec()); selectedKine = true; } if (!selectedKine) { @@ -152,7 +163,7 @@ struct HfTaskMcEfficiencyToXiPi { // check xi-pi candidate passed candidate selector cuts (PID included) if (candidate.statusPidCharmBaryon()) { - hCandidates->Fill(kHFStepTrackedSelected, pt, mass, candidate.collisionMatched(), candidate.originRec()); + hCandidates->Fill(kHFStepTrackedSelected, pt, mass, candidate.collisionMatched(), candidate.originMcRec()); selectedPid = true; } if (!selectedPid) { @@ -221,17 +232,17 @@ struct HfTaskMcEfficiencyToXiPi { } // all candidates - hCandidates->Fill(kHFStepMC, mcParticle.pt(), mass, true, mcParticle.originGen()); // set matchedCollision to true by default at gen level + hCandidates->Fill(kHFStepMC, mcParticle.pt(), mass, true, mcParticle.originMcGen()); // set matchedCollision to true by default at gen level // candidates with charm baryon within eta range if (std::abs(mcParticle.y()) < rapidityCharmBaryonMax) { - hCandidates->Fill(kHFStepMcInRapidity, mcParticle.pt(), mass, true, mcParticle.originGen()); + hCandidates->Fill(kHFStepMcInRapidity, mcParticle.pt(), mass, true, mcParticle.originMcGen()); } // exclude cases with undesired decays int cascId = -999; int pionId = -999; - for (auto& dauCharm : mcParticle.template daughters_as()) { + for (auto const& dauCharm : mcParticle.template daughters_as()) { if (std::abs(dauCharm.pdgCode()) == kXiMinus && (dauCharm.getProcess() == TMCProcess::kPDecay || dauCharm.getProcess() == TMCProcess::kPPrimary)) { cascId = dauCharm.globalIndex(); } else if (std::abs(dauCharm.pdgCode()) == kPiPlus && (dauCharm.getProcess() == TMCProcess::kPDecay || dauCharm.getProcess() == TMCProcess::kPPrimary)) { @@ -254,7 +265,7 @@ struct HfTaskMcEfficiencyToXiPi { // first create cascade daughters objects int lambdaId = -999; int pionFromCascadeId = -999; - for (auto& dauCasc : cascade.template daughters_as()) { + for (auto const& dauCasc : cascade.template daughters_as()) { if (std::abs(dauCasc.pdgCode()) == kLambda0 && dauCasc.getProcess() == TMCProcess::kPDecay) { lambdaId = dauCasc.globalIndex(); } else if (std::abs(dauCasc.pdgCode()) == kPiPlus && dauCasc.getProcess() == TMCProcess::kPDecay) { @@ -270,7 +281,7 @@ struct HfTaskMcEfficiencyToXiPi { // then create lambda daughters objects int protonId = -999; int pionFromLambdaId = -999; - for (auto& dauV0 : lambda.template daughters_as()) { + for (auto const& dauV0 : lambda.template daughters_as()) { if (std::abs(dauV0.pdgCode()) == kProton && dauV0.getProcess() == TMCProcess::kPDecay) { protonId = dauV0.globalIndex(); } else if (std::abs(dauV0.pdgCode()) == kPiPlus && dauV0.getProcess() == TMCProcess::kPDecay) { @@ -292,14 +303,14 @@ struct HfTaskMcEfficiencyToXiPi { } // final state candidates pass eta and pt selection if (inAcceptance) { - hCandidates->Fill(kHFStepAcceptance, mcParticle.pt(), mass, true, mcParticle.originGen()); + hCandidates->Fill(kHFStepAcceptance, mcParticle.pt(), mass, true, mcParticle.originMcGen()); } if (tracked[pionId] && tracked[pionFromCascadeId] && tracked[pionFromLambdaId] && tracked[protonId]) { // final state candidates have a mc particleID != 0 - hCandidates->Fill(kHFStepTrackable, mcParticle.pt(), mass, true, mcParticle.originGen()); + hCandidates->Fill(kHFStepTrackable, mcParticle.pt(), mass, true, mcParticle.originMcGen()); if (inAcceptance) { - hCandidates->Fill(kHFStepAcceptanceTrackable, mcParticle.pt(), mass, true, mcParticle.originGen()); + hCandidates->Fill(kHFStepAcceptanceTrackable, mcParticle.pt(), mass, true, mcParticle.originMcGen()); } else { LOGP(debug, "Candidate {} not in acceptance but tracked.", mcParticle.globalIndex()); LOGP(debug, "MC cascade: pt={} eta={}", cascade.pt(), cascade.eta()); @@ -355,20 +366,20 @@ struct HfTaskMcEfficiencyToXiPi { // with pion track cuts (see checkTrackGlbTrk and checkTrkItsTrk) if (selectedIts[pionId]) { - hCandidates->Fill(kHFStepItsTrackableCuts, mcParticle.pt(), mass, true, mcParticle.originGen()); + hCandidates->Fill(kHFStepItsTrackableCuts, mcParticle.pt(), mass, true, mcParticle.originMcGen()); if (!inAcceptance) { LOGP(debug, "Candidate {} has daughters not in acceptance but pion <-- charm tracked and selected (its only)", mcParticle.globalIndex()); } } if (selectedItsTpc[pionId]) { - hCandidates->Fill(kHFStepItsTpcTrackableCuts, mcParticle.pt(), mass, true, mcParticle.originGen()); + hCandidates->Fill(kHFStepItsTpcTrackableCuts, mcParticle.pt(), mass, true, mcParticle.originMcGen()); if (!inAcceptance) { LOGP(debug, "Candidate {} has daughters not in acceptance but pion <-- charm tracked and selected (its & tpc)", mcParticle.globalIndex()); } } } // close loop mcParticles - } // close candidateMcLoop + } // close candidateMcLoop // process functions void processXic0(Xic0CandidateInfo const& candidates, diff --git a/PWGHF/Tasks/taskMcGenPtRapShapes.cxx b/PWGHF/Tasks/taskMcGenPtRapShapes.cxx index 23f66a0b8ee..fef12e8dd14 100644 --- a/PWGHF/Tasks/taskMcGenPtRapShapes.cxx +++ b/PWGHF/Tasks/taskMcGenPtRapShapes.cxx @@ -14,14 +14,26 @@ /// \author Fabrizio Grosa , CERN -#include - #include "Common/Core/RecoDecay.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::aod; @@ -32,14 +44,16 @@ 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}; +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}; +constexpr std::array PdgCodesBeauty = {Pdg::kB0, Pdg::kBPlus, Pdg::kBS, Pdg::kLambdaB0}; } // namespace struct HfTaskMcGenPtRapShapes { + Configurable rejectBackground{"rejectBackground", false, "Reject particles from background events"}; + Configurable absRapidityMax{"absRapidityMax", 0.5, "Absolute maximum rapidity"}; 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"}; @@ -50,45 +64,48 @@ struct HfTaskMcGenPtRapShapes { std::array, nCharmHadrons> histPtCharmVsPtBeautyNonPrompt{}; std::array, nBeautyHadrons> histRapVsPtBeauty{}; - HistogramRegistry registry{}; + 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}}); + 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}}); + 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); + if (rejectBackground && mcParticle.fromBackgroundEvent()) { + continue; + } + int const absPdgCode = std::abs(mcParticle.pdgCode()); + float const pt = mcParticle.pt(); + float const rap = mcParticle.y(); + const auto* itCharm = std::find(PdgCodesCharm.begin(), PdgCodesCharm.end(), absPdgCode); + const 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) { + if (std::abs(rap) < absRapidityMax) { auto bMother = mcParticles.rawIteratorAt(idxBhadMothers[0]); histPtCharmVsPtBeautyNonPrompt[idxCharm]->Fill(bMother.pt(), pt); } } - } else if (itBeauty != pdgCodesBeauty.end()) { - auto idxBeauty = std::distance(pdgCodesBeauty.begin(), itBeauty); + } else if (itBeauty != PdgCodesBeauty.end()) { + auto idxBeauty = std::distance(PdgCodesBeauty.begin(), itBeauty); histRapVsPtBeauty[idxBeauty]->Fill(pt, rap); } } diff --git a/PWGHF/Tasks/taskMcInjection.cxx b/PWGHF/Tasks/taskMcInjection.cxx new file mode 100644 index 00000000000..b0377cecc23 --- /dev/null +++ b/PWGHF/Tasks/taskMcInjection.cxx @@ -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. + +/// \file taskMcInjection.cxx +/// \brief Task for checking injected events in Pb-Pb MC productions +/// +/// \author Fabrizio Chinu , Università and INFN Torino + +#include "Common/DataModel/Centrality.h" + +#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; + +namespace o2::aod +{ +namespace check_mc_pv_contr +{ +// Collisions +DECLARE_SOA_COLUMN(IdCollGen, idCollGen, int); //! Generated collision index +DECLARE_SOA_COLUMN(ImpParGen, impParGen, float); //! Generated impact parameter +DECLARE_SOA_COLUMN(XCollGen, xCollGen, float); //! Generated x coordinate of the collision +DECLARE_SOA_COLUMN(YCollGen, yCollGen, float); //! Generated y coordinate of the collision +DECLARE_SOA_COLUMN(ZCollGen, zCollGen, float); //! Generated z coordinate of the collision +DECLARE_SOA_COLUMN(TimeGen, timeGen, float); //! Generated collision time +DECLARE_SOA_COLUMN(TimeRec, timeRec, float); //! Reconstructed collision time +DECLARE_SOA_COLUMN(NCharm, nCharm, int); //! Number of charm quarks in the collision +DECLARE_SOA_COLUMN(NCharmFromInj, nCharmFromInj, int); //! Number of charm quarks from injected events +DECLARE_SOA_COLUMN(NPVContributors, nPVContributors, int); //! Number of contributors to the PV +DECLARE_SOA_COLUMN(Centrality, centrality, int); //! Centrality FT0C +DECLARE_SOA_COLUMN(XCollRec, xCollRec, float); //! Reconstructed x coordinate of the collision +DECLARE_SOA_COLUMN(YCollRec, yCollRec, float); //! Reconstructed y coordinate of the collision +DECLARE_SOA_COLUMN(ZCollRec, zCollRec, float); //! Reconstructed z coordinate of the collision +DECLARE_SOA_COLUMN(Bc, bc, int); //! Bunch crossing +// Tracks +DECLARE_SOA_COLUMN(Vx, vx, float); // x coordinate of the track production vertex +DECLARE_SOA_COLUMN(Vy, vy, float); // y coordinate of the track production vertex +DECLARE_SOA_COLUMN(Vz, vz, float); // z coordinate of the track production vertex +DECLARE_SOA_COLUMN(IsFromSignal, isFromSignal, bool); // Whether the track is from the signal event +} // namespace check_mc_pv_contr + +DECLARE_SOA_TABLE(CheckInj, "AOD", "CHECKINJ", //! Table with PID information + check_mc_pv_contr::IdCollGen, + check_mc_pv_contr::ImpParGen, + check_mc_pv_contr::XCollGen, + check_mc_pv_contr::YCollGen, + check_mc_pv_contr::ZCollGen, + check_mc_pv_contr::TimeGen, + check_mc_pv_contr::XCollRec, + check_mc_pv_contr::YCollRec, + check_mc_pv_contr::ZCollRec, + check_mc_pv_contr::TimeRec, + check_mc_pv_contr::NCharm, + check_mc_pv_contr::NCharmFromInj, + check_mc_pv_contr::NPVContributors, + check_mc_pv_contr::Centrality, + check_mc_pv_contr::Bc); + +DECLARE_SOA_TABLE(TracksInjection, "AOD", "TRKINJ", //! Table with MC labels for tracks + check_mc_pv_contr::IdCollGen, + check_mc_pv_contr::Vx, + check_mc_pv_contr::Vy, + check_mc_pv_contr::Vz, + check_mc_pv_contr::IsFromSignal); +} // namespace o2::aod + +struct HfTaskMcInjection { + + Produces checkInj; + Produces tracksInj; + + Configurable centMaxForCollDelta{"centMaxForCollDelta", 20., "max. cent. for gen-rec collision position histograms"}; + Configurable nPvContribMaxForCollDelta{"nPvContribMaxForCollDelta", 2000, "max. PV contrib. for gen-rec collision position histograms"}; + + std::shared_ptr hCharmPerCollImpPar, hCollisions; + + using TrackWLabels = soa::Join; + using CollisionWLabels = soa::Join; + + Preslice tracksPerCollision = aod::track::collisionId; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + + HistogramRegistry registry{"registry", {}}; + + void init(InitContext&) + { + AxisSpec impParBins = {200, 0, 20}; + AxisSpec deltaXYbins = {200, -0.05, 0.05}; + AxisSpec deltaZbins = {200, -10, 10}; + + registry.add("hCharmImpPar", ";Impact parameter (fm);Charm counts", {HistType::kTH1F, {impParBins}}); + registry.add("hCollImpPar", ";Impact parameter (fm);Counts", {HistType::kTH1F, {impParBins}}); + hCharmPerCollImpPar = registry.add("hCharmPerCollImpPar", ";Impact parameter (fm);Charm counts per collision", {HistType::kTH1F, {impParBins}}); + + registry.add("hDeltaX", ";#DeltaX (cm);Counts", {HistType::kTH1F, {{deltaXYbins}}}); + registry.add("hDeltaY", ";#DeltaY (cm);Counts", {HistType::kTH1F, {{deltaXYbins}}}); + registry.add("hDeltaZ", ";#DeltaZ (cm);Counts", {HistType::kTH1F, {{deltaZbins}}}); + + registry.add("hDeltaX_NPV_lt", ";#DeltaX (cm);Counts", {HistType::kTH1F, {{deltaXYbins}}}); + registry.add("hDeltaY_NPV_lt", ";#DeltaY (cm);Counts", {HistType::kTH1F, {{deltaXYbins}}}); + registry.add("hDeltaZ_NPV_lt", ";#DeltaZ (cm);Counts", {HistType::kTH1F, {{deltaZbins}}}); + + registry.add("hDeltaX_NPV_gt", ";#DeltaX (cm);Counts", {HistType::kTH1F, {{deltaXYbins}}}); + registry.add("hDeltaY_NPV_gt", ";#DeltaY (cm);Counts", {HistType::kTH1F, {{deltaXYbins}}}); + registry.add("hDeltaZ_NPV_gt", ";#DeltaZ (cm);Counts", {HistType::kTH1F, {{deltaZbins}}}); + + registry.add("hDeltaXSngBkg", ";#DeltaX (signal/bkg) (cm);Counts", {HistType::kTH1F, {{200, -10, 10}}}); + registry.add("hDeltaYSngBkg", ";#DeltaY (signal/bkg) (cm);Counts", {HistType::kTH1F, {{200, -10, 10}}}); + registry.add("hDeltaZSngBkg", ";#DeltaZ (signal/bkg) (cm);Counts", {HistType::kTH1F, {{200, -20, 20}}}); + + hCollisions = registry.add("hCollisions", ";;Counts", {HistType::kTH1F, {{2, 0.5, 2.5}}}); + hCollisions->GetXaxis()->SetBinLabel(1, "Generated"); + hCollisions->GetXaxis()->SetBinLabel(2, "Reconstructed"); + } + + bool isCharm(int pdg) + { + if (std::abs(pdg) / 1000 == PDG_t::kCharm) // o2-linter: disable=magic-number (get thousands digit) + return true; + if (std::abs(pdg) / 100 == PDG_t::kCharm) // o2-linter: disable=magic-number (get hundreds digit) + return true; + return false; + } + + bool isBeauty(int pdg) // if needed in the future + { + if (std::abs(pdg) / 1000 == PDG_t::kBottom) // o2-linter: disable=magic-number (get thousands digit) + return true; + if (std::abs(pdg) / 100 == PDG_t::kBottom) // o2-linter: disable=magic-number (get hundreds digit) + return true; + return false; + } + + void process(CollisionWLabels const& collisions, + TrackWLabels const& tracks, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions) + { + for (const auto& mcColl : mcCollisions) { + registry.fill(HIST("hCollImpPar"), mcColl.impactParameter()); + const auto mcPartColl = mcParticles.sliceBy(perMcCollision, mcColl.globalIndex()); + double xAvgSgn{0.}, yAvgSgn{0.}, zAvgSgn{0.}; + double xAvgBkg{0.}, yAvgBkg{0.}, zAvgBkg{0.}; + int nSgn{0}, nBkg{0}; + for (const auto& mcPart : mcPartColl) { + if (isCharm(mcPart.pdgCode())) { // charm hadron + registry.fill(HIST("hCharmImpPar"), mcColl.impactParameter()); + } + if (mcPart.fromBackgroundEvent()) { + xAvgBkg += mcPart.vx(); + yAvgBkg += mcPart.vy(); + zAvgBkg += mcPart.vz(); + nBkg++; + tracksInj(mcPart.mcCollisionId(), mcPart.vx(), mcPart.vy(), mcPart.vz(), false); + } else { + xAvgSgn += mcPart.vx(); + yAvgSgn += mcPart.vy(); + zAvgSgn += mcPart.vz(); + nSgn++; + tracksInj(mcPart.mcCollisionId(), mcPart.vx(), mcPart.vy(), mcPart.vz(), true); + } + } + registry.fill(HIST("hDeltaXSngBkg"), xAvgSgn / nSgn - xAvgBkg / nBkg); + registry.fill(HIST("hDeltaYSngBkg"), yAvgSgn / nSgn - yAvgBkg / nBkg); + registry.fill(HIST("hDeltaZSngBkg"), zAvgSgn / nSgn - zAvgBkg / nBkg); + + const auto collSlice = collisions.sliceBy(colPerMcCollision, mcColl.globalIndex()); + + // Then we fill the histogram with the distances of the collisions + for (const auto& collision : collSlice) { + const auto collTracks = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + int fromSignalEv{0}; + if (collision.centFT0C() < centMaxForCollDelta) { + registry.fill(HIST("hDeltaX"), collision.posX() - collision.mcCollision().posX()); + registry.fill(HIST("hDeltaY"), collision.posY() - collision.mcCollision().posY()); + registry.fill(HIST("hDeltaZ"), collision.posZ() - collision.mcCollision().posZ()); + + if (collision.numContrib() > nPvContribMaxForCollDelta) { + registry.fill(HIST("hDeltaX_NPV_gt"), collision.posX() - collision.mcCollision().posX()); + registry.fill(HIST("hDeltaY_NPV_gt"), collision.posY() - collision.mcCollision().posY()); + registry.fill(HIST("hDeltaZ_NPV_gt"), collision.posZ() - collision.mcCollision().posZ()); + } else { + registry.fill(HIST("hDeltaX_NPV_lt"), collision.posX() - collision.mcCollision().posX()); + registry.fill(HIST("hDeltaY_NPV_lt"), collision.posY() - collision.mcCollision().posY()); + registry.fill(HIST("hDeltaZ_NPV_lt"), collision.posZ() - collision.mcCollision().posZ()); + } + } + std::unordered_set charmIds{}; + for (const auto& track : collTracks) { + if (track.has_mcParticle()) { + auto mcPart = track.mcParticle_as(); + for (const auto& mother : mcPart.mothers_as()) { + if (isCharm(mother.pdgCode())) { // charm hadron + if (!charmIds.contains(mother.globalIndex())) { + charmIds.emplace(mother.globalIndex()); + fromSignalEv += static_cast(!mother.fromBackgroundEvent()); + } + break; + } + } + } + } + checkInj( + mcColl.globalIndex(), mcColl.impactParameter(), + mcColl.posX(), mcColl.posY(), mcColl.posZ(), mcColl.t(), + collision.posX(), collision.posY(), collision.posZ(), collision.collisionTime(), + charmIds.size(), fromSignalEv, collision.numContrib(), collision.centFT0C(), collision.bcId()); + } + } + + hCharmPerCollImpPar->Divide(registry.get(HIST("hCharmImpPar")).get(), registry.get(HIST("hCollImpPar")).get(), 1, 1); + hCollisions->Fill(1, mcCollisions.size()); + hCollisions->Fill(2, collisions.size()); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/Tasks/taskMcValidation.cxx b/PWGHF/Tasks/taskMcValidation.cxx index 7d4ddef0a9f..928dba464ba 100644 --- a/PWGHF/Tasks/taskMcValidation.cxx +++ b/PWGHF/Tasks/taskMcValidation.cxx @@ -18,28 +18,64 @@ /// \author Fabrizio Grosa , CERN /// \author Fabio Catalano , CERN -#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/Core/DecayChannels.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include 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 { @@ -49,6 +85,13 @@ enum DecayChannels { DzeroToKPi = 0, 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, + BsToDsPi, LcToPKPi, LcToPiK0s, XiCplusToPKPi, @@ -56,27 +99,39 @@ enum DecayChannels { DzeroToKPi = 0, XiCzeroToXiPi, OmegaCToOmegaPi, OmegaCToXiPi, - nChannels }; // always keep nChannels at the end - -static constexpr int nMesonChannels = 6; // number of meson channels -static constexpr int nOriginTypes = 2; // number of origin types (prompt, non-prompt) -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::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, 3, 3, 3, 5, 4, 4, 4}; -static constexpr std::array maxDepthForSearch = {1, 2, 2, 2, 2, 2, 2, 3, 2, 4, 3, 3, 3}; + NChannels +}; // always keep nChannels at the end + +constexpr int NCharmMesonChannels = 10; // number of charm meson channels +constexpr int NBeautyChannels = 3; // number of beauty hadron channels +constexpr int NCharmBaryonChannels = NChannels - NCharmMesonChannels - NBeautyChannels; // number of charm baryon channels +constexpr int NOriginTypes = 2; // number of origin types (prompt, non-prompt; only for charm hadrons) +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::kBS, + 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}; +constexpr std::array NDaughters = {2, 3, 3, 3, 3, 3, 5, 5, 4, 4, 4, 3, 4, 3, 3, 3, 5, 4, 4, 4}; +constexpr std::array MaxDepthForSearch = {1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 2, 3, 2, 4, 3, 3, 3}; // keep coherent indexing with PDGArrayParticle // FIXME: look for a better solution -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}, {+kProton, -kKPlus, +kPiPlus}, {+kProton, -kPiPlus, +kPiPlus}, {+kProton, -kKPlus, +kPiPlus}, {}, {}, {}, {}}}; -static constexpr std::array, nChannels> arrPDGFinal4Prong = {{{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}, {+kPiPlus, -kKPlus, -kPiPlus, +kProton}, {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}}}; -static constexpr std::array, nChannels> arrPDGFinal5Prong = {{{}, {}, {}, {}, {}, {}, {}, {}, {}, {+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", "#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", - "LcToPKPi", "LcToPiK0s", "XiCplusToPKPi", "XiCplusToXiPiPi", "XiCzeroToXiPi", "OmegaCToOmegaPi", "OmegaCToXiPi"}; -static constexpr std::string_view originNames[nOriginTypes] = {"Prompt", "NonPrompt"}; +constexpr std::array, NChannels> ArrPdgFinal2Prong = {{{+kPiPlus, -kKPlus}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}}}; +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}, {}, {}, {}, {}}}; +constexpr std::array, NChannels> ArrPdgFinal4Prong = {{{}, {}, {}, {}, {}, {}, {}, {}, {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus, -kPiPlus}, {-kPiPlus, +kKPlus, -kPiPlus, +kPiPlus}, {}, {-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, {}, {}, {}, {}, {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}, {+kPiPlus, -kKPlus, -kPiPlus, +kProton}, {+kPiPlus, -kPiPlus, -kPiPlus, +kProton}}}; +constexpr std::array, NChannels> ArrPdgFinal5Prong = {{{}, {}, {}, {}, {}, {}, {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, {+kPiPlus, -kKPlus, +kPiPlus, +kPiPlus, -kPiPlus}, {}, {}, {}, {}, {}, {}, {}, {}, {+kPiPlus, +kPiPlus, -kPiPlus, -kPiPlus, +kProton}, {}, {}, {}}}; +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", "B_{s}^{+} #rightarrow D_{s}^{-}#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"}; +constexpr std::string_view ParticleNames[NChannels] = {"DzeroToKPi", "DstarToDzeroPi", "DplusToPiKPi", "DplusToPhiPiToKKPi", "DsToPhiPiToKKPi", "DsToK0starKToKKPi", "Ds1ToDStarK0s", "Ds2StarToDPlusK0s", "D10ToDStarPi", "D2Star0ToDPlusPi", "B0ToDminusPi", "BplusToD0Pi", "BsToDsPi", + "LcToPKPi", "LcToPiK0s", "XiCplusToPKPi", "XiCplusToXiPiPi", "XiCzeroToXiPi", "OmegaCToOmegaPi", "OmegaCToXiPi"}; +constexpr std::string_view OriginNames[NOriginTypes] = {"Prompt", "NonPrompt"}; } // namespace /// Generated Level Validation @@ -90,6 +145,7 @@ struct HfTaskMcValidationGen { 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; @@ -97,21 +153,26 @@ struct HfTaskMcValidationGen { 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 axisMesonSpecies{nMesonChannels, -0.5, static_cast(nMesonChannels) - 0.5}; - AxisSpec axisBaryonSpecies{nChannels - nMesonChannels, -0.5, static_cast(nChannels - nMesonChannels) - 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}}}, @@ -123,18 +184,31 @@ struct HfTaskMcValidationGen { {"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, {axisMesonSpecies, axisPt}}}, - {"PromptCharmMesons/hPromptMesonsYDistr", "Y distribution vs prompt charm meson; ; #it{y}^{gen}", {HistType::kTH2F, {axisMesonSpecies, axisY}}}, - {"PromptCharmMesons/hPromptMesonsDecLenDistr", "Decay length distribution vs prompt charm meson; ; decay length (#mum)", {HistType::kTH2F, {axisMesonSpecies, 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, {axisMesonSpecies, axisPt}}}, - {"NonPromptCharmMesons/hNonPromptMesonsYDistr", "Y distribution vs non-prompt charm meson; ; #it{y}^{gen}", {HistType::kTH2F, {axisMesonSpecies, axisY}}}, - {"NonPromptCharmMesons/hNonPromptMesonsDecLenDistr", "Decay length distribution vs non-prompt charm meson; ; decay length (#mum)", {HistType::kTH2F, {axisMesonSpecies, axisDecLen}}}, - {"PromptCharmBaryons/hPromptBaryonsPtDistr", "Pt distribution vs prompt charm baryon in |#it{y}^{gen}|<0.5; ; #it{p}_{T}^{gen} (GeV/#it{c})", {HistType::kTH2F, {axisBaryonSpecies, axisPt}}}, - {"PromptCharmBaryons/hPromptBaryonsYDistr", "Y distribution vs prompt charm baryon; ; #it{y}^{gen}", {HistType::kTH2F, {axisBaryonSpecies, axisY}}}, - {"PromptCharmBaryons/hPromptBaryonsDecLenDistr", "Decay length distribution vs prompt charm baryon; ; decay length (#mum)", {HistType::kTH2F, {axisBaryonSpecies, 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, {axisBaryonSpecies, axisPt}}}, - {"NonPromptCharmBaryons/hNonPromptBaryonsYDistr", "Y distribution vs non-prompt charm baryon; ; #it{y}^{gen}", {HistType::kTH2F, {axisBaryonSpecies, axisY}}}, - {"NonPromptCharmBaryons/hNonPromptBaryonsDecLenDistr", "Decay length distribution vs non-prompt charm baryon; ; decay length (#mum)", {HistType::kTH2F, {axisBaryonSpecies, axisDecLen}}}}}; + {"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& initContext) { @@ -145,38 +219,57 @@ struct HfTaskMcValidationGen { } // add per species histograms - for (size_t iOrigin = 0; iOrigin < nOriginTypes; iOrigin++) { - for (int iChannel = 0; iChannel < nMesonChannels; iChannel++) { - 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 (auto originName : OriginNames) { + for (int iChannel = 0; iChannel < NCharmMesonChannels; iChannel++) { // Charm mesons + registry.add(Form("%sCharmMesons/hCount%s%s", originName.data(), originName.data(), ParticleNames[iChannel].data()), + Form("Event counter - %s %s; Events Per Collision; entries", originName.data(), Labels[iChannel].data()), {HistType::kTH1F, {axisNhadrons}}); } - for (int iChannel = nMesonChannels; iChannel < nChannels; iChannel++) { - 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}}); + for (int iChannel = NCharmMesonChannels + NBeautyChannels; iChannel < NChannels; iChannel++) { // Charm baryons + registry.add(Form("%sCharmBaryons/hCount%s%s", originName.data(), originName.data(), ParticleNames[iChannel].data()), + Form("Event counter - %s %s; Events Per Collision; entries", originName.data(), Labels[iChannel].data()), {HistType::kTH1F, {axisNhadrons}}); } } + 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}}); + } - for (auto iBin = 1; iBin <= nMesonChannels; ++iBin) { - registry.get(HIST("PromptCharmMesons/hPromptMesonsPtDistr"))->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/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 <= 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 <= nChannels - nMesonChannels; ++iBin) { - registry.get(HIST("PromptCharmBaryons/hPromptBaryonsPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nMesonChannels - 1].data()); - registry.get(HIST("PromptCharmBaryons/hPromptBaryonsYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nMesonChannels - 1].data()); - registry.get(HIST("PromptCharmBaryons/hPromptBaryonsDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nMesonChannels - 1].data()); - registry.get(HIST("NonPromptCharmBaryons/hNonPromptBaryonsPtDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nMesonChannels - 1].data()); - registry.get(HIST("NonPromptCharmBaryons/hNonPromptBaryonsYDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nMesonChannels - 1].data()); - registry.get(HIST("NonPromptCharmBaryons/hNonPromptBaryonsDecLenDistr"))->GetXaxis()->SetBinLabel(iBin, labels[iBin + nMesonChannels - 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) { + if (device.name == "hf-task-mc-validation-rec") { hfEvSelMc.configureFromDevice(device); break; } @@ -185,24 +278,25 @@ struct HfTaskMcValidationGen { hfEvSelMc.addHistograms(registry); // particles monitoring } - template - void runCheckGenParticles(GenColl const& mcCollision, Particles const& mcParticles, RecoColls const& recoCollisions, BCsInfo const&, std::array& counterPrompt, std::array& counterNonPrompt) + 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; } + registry.fill(HIST("hNevGen"), 1); // 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) { - 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); + float centrality{105.f}; + float occupancy{0.f}; + if (storeOccupancy) { + occupancy = o2::hf_occupancy::getOccupancyGenColl(recoCollisions, OccupancyEstimator::Its); + } + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + if constexpr (CentEstimator == CentralityEstimator::FT0C || CentEstimator == CentralityEstimator::FT0M || CentEstimator == CentralityEstimator::None) { + rejectionMask = hfEvSelMc.getHfMcCollisionRejectionMask(mcCollision, recoCollisions, centrality); } - hfEvSelMc.fillHistograms(rejectionMask); + hfEvSelMc.fillHistograms(mcCollision, rejectionMask); if (rejectionMask != 0) { return; } @@ -222,7 +316,7 @@ struct HfTaskMcValidationGen { continue; } - int particlePdgCode = particle.pdgCode(); + int const particlePdgCode = particle.pdgCode(); bool isDiffFromMothers = true; for (const auto& mother : particle.template mothers_as()) { if (particlePdgCode == mother.pdgCode()) { @@ -260,14 +354,14 @@ struct HfTaskMcValidationGen { std::vector listDaughters{}; // Check that the decay channel is correct and retrieve the daughters - if (nDaughters[iD] == 2) { - if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal2Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { + if (NDaughters[iD] == 2) { + if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], ArrPdgFinal2Prong[iD], true, nullptr, MaxDepthForSearch[iD], &listDaughters)) { continue; } } - 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 && @@ -288,10 +382,28 @@ struct HfTaskMcValidationGen { !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 (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal4Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { + 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) && @@ -302,10 +414,28 @@ struct HfTaskMcValidationGen { !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 (iD == BsToDsPi && + !RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], std::array{-o2::constants::physics::Pdg::kDS, +kPiPlus}, true)) { + continue; + } } - if (nDaughters[iD] == 5) { - if (!RecoDecay::isMatchedMCGen(mcParticles, particle, PDGArrayParticle[iD], arrPDGFinal5Prong[iD], true, nullptr, maxDepthForSearch[iD], &listDaughters)) { + 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 && @@ -319,8 +449,8 @@ struct HfTaskMcValidationGen { double sumPyDau = 0.; double sumPzDau = 0.; bool momentumCheck = true; - for (std::size_t iDau = 0; iDau < listDaughters.size(); ++iDau) { - auto daughter = mcParticles.rawIteratorAt(listDaughters.at(iDau) - mcParticles.offset()); + for (const int listDaughter : listDaughters) { + auto daughter = mcParticles.rawIteratorAt(listDaughter - mcParticles.offset()); sumPxDau += daughter.px(); sumPyDau += daughter.py(); sumPzDau += daughter.pz(); @@ -331,8 +461,8 @@ struct HfTaskMcValidationGen { if (std::abs(pxDiff) > 0.001 || std::abs(pyDiff) > 0.001 || std::abs(pzDiff) > 0.001) { momentumCheck = false; } - double pDiff = RecoDecay::p(pxDiff, pyDiff, pzDiff); - double ptDiff = RecoDecay::pt(pxDiff, pyDiff); + double const pDiff = RecoDecay::p(pxDiff, pyDiff, pzDiff); + double const ptDiff = RecoDecay::pt(pxDiff, pyDiff); registry.fill(HIST("hMomentumCheck"), static_cast(momentumCheck)); registry.fill(HIST("hPxDiffMotherDaughterGen"), pxDiff); registry.fill(HIST("hPyDiffMotherDaughterGen"), pyDiff); @@ -340,44 +470,70 @@ 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.template daughters_as().begin(); - double vertexDau[3] = {daughter0.vx(), daughter0.vy(), daughter0.vz()}; - double vertexPrimary[3] = {mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()}; + double const vertexDau[3] = {daughter0.vx(), daughter0.vy(), daughter0.vz()}; + double const vertexPrimary[3] = {mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()}; auto decayLength = RecoDecay::distance(vertexPrimary, vertexDau); - if (iD < nMesonChannels) { - if (origin == RecoDecay::OriginType::Prompt) { + 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); } - } else { + } else if (iD < NCharmMesonChannels + NBeautyChannels) { // Beauty mesons + if (std::abs(particle.y()) < 0.5) { + 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 - nMesonChannels, particle.pt()); + 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 - nMesonChannels, particle.y()); - registry.fill(HIST("PromptCharmBaryons/hPromptBaryonsDecLenDistr"), iD - nMesonChannels, decayLength * 10000); + 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 - nMesonChannels, particle.pt()); + 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 - nMesonChannels, particle.y()); - registry.fill(HIST("NonPromptCharmBaryons/hNonPromptBaryonsDecLenDistr"), iD - nMesonChannels, decayLength * 10000); + registry.fill(HIST("NonPromptCharmBaryons/hNonPromptBaryonsYDistr"), iD - NCharmMesonChannels - NBeautyChannels, particle.y()); + registry.fill(HIST("NonPromptCharmBaryons/hNonPromptBaryonsDecLenDistr"), iD - NCharmMesonChannels - NBeautyChannels, decayLength * 10000); } } } @@ -397,17 +553,21 @@ struct HfTaskMcValidationGen { 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}; + std::array counterPrompt{0}, counterNonPrompt{0}; runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); - static_for<0, nMesonChannels - 1>([&](auto i) { - 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<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) { - 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]); + 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 @@ -421,23 +581,27 @@ struct HfTaskMcValidationGen { 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}; + std::array counterPrompt{0}, counterNonPrompt{0}; runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); - static_for<0, nMesonChannels - 1>([&](auto i) { - 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<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) { - 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]); + 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(aod::McCollisions const& mcCollisions, + void processCentFT0M(McCollisionsCentFT0Ms const& mcCollisions, aod::McParticles const& mcParticles, CollisionsFT0Ms const& recoCollisions, BCsInfo const& bcInfo) @@ -445,17 +609,21 @@ struct HfTaskMcValidationGen { 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}; + std::array counterPrompt{0}, counterNonPrompt{0}; runCheckGenParticles(mcCollision, mcParticlesPerMcColl, recoCollsPerMcColl, bcInfo, counterPrompt, counterNonPrompt); - static_for<0, nMesonChannels - 1>([&](auto i) { - 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<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) { - 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]); + 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 @@ -471,16 +639,19 @@ 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, 5>, 2>, nChannels> histPtDau, histEtaDau, histImpactParameterDau; - std::array, 2>, nChannels> histPtReco; + std::array, NChannels> histDeltaPt, histDeltaPx, histDeltaPy, histDeltaPz, histDeltaSecondaryVertexX, histDeltaSecondaryVertexY, histDeltaSecondaryVertexZ, histDeltaDecayLength; + 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 CandMcGen = soa::Join; using CollisionsWithMCLabels = soa::Join; using CollisionsWithMCLabelsAndCentFT0C = soa::Join; using CollisionsWithMCLabelsAndCentFT0M = soa::Join; @@ -489,6 +660,9 @@ struct HfTaskMcValidationRec { 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 @@ -497,6 +671,8 @@ struct HfTaskMcValidationRec { 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}; @@ -507,6 +683,7 @@ 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.}}}}, @@ -515,6 +692,8 @@ struct HfTaskMcValidationRec { {"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 @@ -526,8 +705,8 @@ struct HfTaskMcValidationRec { 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; } @@ -537,8 +716,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()); @@ -546,21 +727,24 @@ struct HfTaskMcValidationRec { histDeltaPz[whichHad]->Fill(candidate.pz() - mother.pz()); // Compare Secondary vertex and decay length with MC 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()}; + double const vertexDau[3] = {daughter0.vx(), daughter0.vy(), daughter0.vz()}; + double const vertexMoth[3] = {mother.vx(), mother.vy(), mother.vz()}; auto decayLength = RecoDecay::distance(vertexMoth, vertexDau); histDeltaSecondaryVertexX[whichHad]->Fill(candidate.xSecondaryVertex() - vertexDau[0]); histDeltaSecondaryVertexY[whichHad]->Fill(candidate.ySecondaryVertex() - vertexDau[1]); histDeltaSecondaryVertexZ[whichHad]->Fill(candidate.zSecondaryVertex() - vertexDau[2]); histDeltaDecayLength[whichHad]->Fill(candidate.decayLength() - decayLength); - std::array momDau0 = {candidate.pxProng0(), - candidate.pyProng0(), - candidate.pzProng0()}; - std::array momDau1 = {candidate.pxProng1(), - candidate.pyProng1(), - candidate.pzProng1()}; - histPtReco[whichHad][whichOrigin]->Fill(candidate.pt()); + std::array const momDau0 = {candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0()}; + std::array const momDau1 = {candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1()}; + 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()); @@ -601,21 +785,46 @@ struct HfTaskMcValidationRec { histAmbiguousTracks->GetXaxis()->SetBinLabel(2, "no quark"); 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}); + for (auto iHad = 0; iHad < NChannels; ++iHad) { + 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}); + } } } } @@ -629,7 +838,7 @@ struct HfTaskMcValidationRec { ccdb->setLocalObjectValidityChecking(); } - template + template void checkCollisions(Coll const& collision, aod::McCollisions const&, aod::BCsWithTimestamps const&) @@ -640,7 +849,7 @@ struct HfTaskMcValidationRec { } float centrality{-1.f}; - const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate return; @@ -651,13 +860,14 @@ struct HfTaskMcValidationRec { 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()); } - template + template void checkCollisionAssociation(Colls const& collisions, TracksWithSel const&, aod::McParticles const& mcParticles, @@ -669,7 +879,7 @@ struct HfTaskMcValidationRec { // 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); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, centrality, ccdb, registry); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; @@ -699,14 +909,14 @@ struct HfTaskMcValidationRec { nGoodContributors++; } } - float frac = (nContributors > 0) ? static_cast(nGoodContributors) / nContributors : 1.; + float const frac = (nContributors > 0) ? static_cast(nGoodContributors) / nContributors : 1.; registry.fill(HIST("TrackToCollChecks/histFracGoodContributors"), frac); - uint64_t mostProbableBC = collision.bc().globalBC(); + uint64_t const mostProbableBC = collision.bc().globalBC(); for (auto collision2 = collision + 1; collision2 != collisions.end(); ++collision2) { - uint64_t mostProbableBC2 = collision2.bc().globalBC(); + uint64_t const mostProbableBC2 = collision2.bc().globalBC(); if (mostProbableBC2 == mostProbableBC) { - float radColl1 = std::sqrt(collision.posX() * collision.posX() + collision.posY() * collision.posY()); - float radColl2 = std::sqrt(collision2.posX() * collision2.posX() + collision2.posY() * collision2.posY()); + float const radColl1 = std::sqrt(collision.posX() * collision.posX() + collision.posY() * collision.posY()); + float const radColl2 = std::sqrt(collision2.posX() * collision2.posX() + collision2.posY() * collision2.posY()); int nFromBeautyColl1 = 0, nFromBeautyColl2 = 0; for (const auto& trackColl1 : tracksColl1) { if (trackColl1.has_mcParticle() && trackColl1.isPVContributor()) { @@ -737,39 +947,38 @@ struct HfTaskMcValidationRec { for (const auto& track : tracksFilteredGlobalTrackWoDCA) { // check number of ITS hits int nITSlayers = 0; - uint8_t ITSHitMap = track.itsClusterMap(); + uint8_t const itsHitMap = track.itsClusterMap(); for (int iLayer = 0; iLayer < 7; ++iLayer) { - if (TESTBIT(ITSHitMap, iLayer)) { + if (TESTBIT(itsHitMap, iLayer)) { nITSlayers++; } } - uint index = uint(track.collisionId() >= 0); + uint const index = uint(track.collisionId() >= 0); if (track.has_mcParticle()) { - auto particle = track.mcParticle(); // get corresponding MC particle to check origin - auto mcCollision = particle.mcCollision_as(); + const auto& particle = track.mcParticle(); // get corresponding MC particle to check origin + const auto& mcCollision = particle.mcCollision_as(); if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { continue; } auto origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, true); histTracks->Fill(origin, track.pt()); - bool isAmbiguous = (track.compatibleCollIds().size() != 1); + bool const isAmbiguous = (track.compatibleCollIds().size() != 1); if (isAmbiguous) { registry.fill(HIST("TrackToCollChecks/histAmbiguousTrackNumCollisions"), track.compatibleCollIds().size()); histAmbiguousTracks->Fill(origin, track.pt()); std::vector ambCollPosZ{}; for (const auto& collIdx : track.compatibleCollIds()) { - auto ambCollision = collisions.rawIteratorAt(collIdx); + const auto& ambCollision = collisions.rawIteratorAt(collIdx); ambCollPosZ.push_back(ambCollision.posZ()); } // here we are only interested to tracks associated to multiple vertices - if (ambCollPosZ.size() > 0) { + if (!ambCollPosZ.empty()) { registry.fill(HIST("TrackToCollChecks/histAmbiguousTrackZvtxRMS"), computeRMS(ambCollPosZ)); } } float deltaZ = -999.f; if (index) { - auto collision = track.collision_as(); - auto mcCollision = particle.mcCollision_as(); + const auto& collision = track.collision_as(); deltaZ = collision.posZ() - mcCollision.posZ(); if (collision.has_mcCollision() && collision.mcCollisionId() == particle.mcCollisionId()) { histOriginTracks[index + 1]->Fill(origin, track.pt(), track.eta(), deltaZ, track.isPVContributor(), track.hasTOF(), nITSlayers); @@ -854,116 +1063,146 @@ struct HfTaskMcValidationRec { } 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&, - CollisionsWithMCLabels const& /*collisions*/) + aod::BCsWithTimestamps const&, + Coll const& collisions, + Preslice cand2ProngsPerCollision, + Preslice cand3ProngsPerCollision) { - // loop over 2-prong candidates - for (const auto& cand2Prong : cand2Prongs) { - - if (cand2Prong.collision_as().has_mcCollision()) { - auto mcCollision = cand2Prong.collision_as().mcCollision_as(); - if (eventGeneratorType >= 0 && mcCollision.getSubGeneratorId() != eventGeneratorType) { - continue; - } - } - - // 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; + // loop over collisions + for (const auto& collision : collisions) { + // apply event selection + float centrality{105.f}; + int const 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 const isD0Sel = TESTBIT(cand2Prong.hfflag(), o2::aod::hf_cand_2prong::DecayType::D0ToPiK); + if (!isD0Sel) { continue; } - } - - // 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; - } - 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; + int whichHad = -1; + if (std::abs(cand2Prong.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + whichHad = DzeroToKPi; } - if (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 = XiCplusToPKPi; - } - 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 const isDPlusSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::DplusToPiKPi); + bool const isDsSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::DsToKKPi); + bool const isLcSel = TESTBIT(cand3Prong.hfflag(), hf_cand_3prong::DecayType::LcToPKPi); + bool const 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 + int whichHad = -1; + if (isDPlusSel && std::abs(cand3Prong.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { + whichHad = DplusToPiKPi; + } else if (isDsSel && std::abs(cand3Prong.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) { + if (cand3Prong.flagMcDecayChanRec() == o2::hf_decay::hf_cand_3prong::DecayChannelResonant::DsToPhiPi) { + whichHad = DsToPhiPiToKKPi; + } + if (cand3Prong.flagMcDecayChanRec() == o2::hf_decay::hf_cand_3prong::DecayChannelResonant::DsToKstar0K) { + whichHad = DsToK0starKToKKPi; + } + if (cand3Prong.flagMcDecayChanRec() == o2::hf_decay::hf_cand_3prong::DecayChannelResonant::DplusToPhiPi) { + whichHad = DplusToPhiPiToKKPi; + } + } else if (isLcSel && std::abs(cand3Prong.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + whichHad = LcToPKPi; + } else if (isXicSel && std::abs(cand3Prong.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::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 const 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, processEff, "Compute charm-hadron efficiencies (not all of them are implemented), requires HF candidate creators", false); + 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..3df1ca0fc65 --- /dev/null +++ b/PWGHF/Tasks/taskMultiplicityEstimatorCorrelation.cxx @@ -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 taskMultiplicityEstimatorCorrelation.cxx +/// \brief Task for correlating the multiplicity estimator with generated dN/deta +/// +/// \author Fabrizio Chinu , Università and INFN Torino + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#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 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..75878f4f9a6 --- /dev/null +++ b/PWGHF/Tasks/taskPidStudies.cxx @@ -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. + +/// \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 "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#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; +using namespace o2::hf_evsel; +using namespace o2::hf_centrality; + +enum Particle { NotMatched = 0, + K0s, + Lambda, + Omega }; + +enum TrackCuts { All = 0, + HasIts, + HasTpc, + TpcNClsCrossedRows, + Eta, + Pt, + TpcChi2NCls, + ItsChi2NCls, + NCuts }; + +namespace o2::aod +{ +namespace pid_studies +{ +// 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(InteractionRate, interactionRate, double); //! Centrality from FT0M +DECLARE_SOA_COLUMN(CandFlag, candFlag, int); //! Flag for MC matching +} // 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::InteractionRate, + 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::InteractionRate, + 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 tpcNClsCrossedRowsTrackMin{"tpcNClsCrossedRowsTrackMin", 70, "Minimum number of crossed rows in TPC"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "Maximum pseudorapidity"}; + Configurable ptTrackMin{"ptTrackMin", 0.1, "Minimum transverse momentum"}; + Configurable tpcChi2NClTrackMax{"tpcChi2NClTrackMax", 4, "Maximum TPC chi2 per number of TPC clusters"}; + Configurable itsChi2NClTrackMax{"itsChi2NClTrackMax", 36, "Maximum ITS chi2 per number of ITS clusters"}; + 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 interactionRateMin{"interactionRateMin", -1, "Minimum interaction rate (kHz)"}; + Configurable interactionRateMax{"interactionRateMax", 1.e20, "Maximum interaction rate (kHz)"}; + 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 ctpFetcherSource{"ctpFetcherSource", "T0VTX", "Source for CTP rate fetching, e.g. T0VTX, T0CE, T0SC, ZNC (hadronic)"}; + 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; + + ctpRateFetcher rateFetcher; + HfEventSelection hfEvSel; + HfEventSelectionMc hfEvSelMc; + double interactionRate{-1.}; + + 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); + + std::shared_ptr const hTrackSel = registry.add("hTrackSel", "Track selection;;Counts", {HistType::kTH1F, {{TrackCuts::NCuts, 0, TrackCuts::NCuts}}}); + + // Set Labels for hTrackSel + hTrackSel->GetXaxis()->SetBinLabel(TrackCuts::All + 1, "All"); + hTrackSel->GetXaxis()->SetBinLabel(TrackCuts::HasIts + 1, "HasITS"); + hTrackSel->GetXaxis()->SetBinLabel(TrackCuts::HasTpc + 1, "HasTPC"); + hTrackSel->GetXaxis()->SetBinLabel(TrackCuts::TpcNClsCrossedRows + 1, "TPC NCls/CrossedRows"); + hTrackSel->GetXaxis()->SetBinLabel(TrackCuts::Eta + 1, "#eta"); + hTrackSel->GetXaxis()->SetBinLabel(TrackCuts::Pt + 1, "#it{p}_{T}"); + hTrackSel->GetXaxis()->SetBinLabel(TrackCuts::TpcChi2NCls + 1, "TPC #chi^{2}/NCls"); + hTrackSel->GetXaxis()->SetBinLabel(TrackCuts::ItsChi2NCls + 1, "ITS #chi^{2}/NCls"); + } + + template + void fillTree(Cand const& candidate, const int flag) + { + float const 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(), + interactionRate, + 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(), + interactionRate, + flag); + } + } + + template + int isMatched(const T1& cand) + { + if constexpr (std::is_same::value) { + if (!cand.has_v0MCCore()) { + return Particle::NotMatched; + } + auto v0MC = cand.template v0MCCore_as(); + if (v0MC.pdgCode() == kK0Short && v0MC.pdgCodeNegative() == -kPiPlus && v0MC.pdgCodePositive() == kPiPlus) { + return Particle::K0s; + } + if (v0MC.pdgCode() == kLambda0 && v0MC.pdgCodeNegative() == -kPiPlus && v0MC.pdgCodePositive() == kProton) { + return Particle::Lambda; + } + if (v0MC.pdgCode() == -kLambda0 && v0MC.pdgCodeNegative() == -kProton && v0MC.pdgCodePositive() == kPiPlus) { + return -Particle::Lambda; + } + } + if constexpr (std::is_same::value) { + if (!cand.has_cascMCCore()) { + return 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 Particle::Omega; + } + if (cascMC.pdgCode() == -kOmegaMinus && + cascMC.pdgCodeBachelor() == kKPlus && + cascMC.pdgCodeV0() == -kLambda0 && + cascMC.pdgCodePositive() == kPiPlus && + cascMC.pdgCodeNegative() == -kProton) { + return -Particle::Omega; + } + } + return Particle::NotMatched; + } + + template + bool isCollSelected(const Coll& coll) + { + auto bc = coll.template bc_as(); + interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), ctpFetcherSource.value) * 1.e-3; // convert to kHz + if (interactionRate < interactionRateMin || interactionRate > interactionRateMax) { + return false; + } + + 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(); + registry.fill(HIST("hTrackSel"), TrackCuts::All); + if constexpr (IsV0) { + if (!posTrack.hasITS() || !negTrack.hasITS()) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::HasIts); + if (!posTrack.hasTPC() || !negTrack.hasTPC()) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::HasTpc); + if (posTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::TpcNClsCrossedRows); + if (std::abs(posTrack.eta()) > etaTrackMax || std::abs(negTrack.eta()) > etaTrackMax) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::Eta); + if (posTrack.pt() < ptTrackMin || negTrack.pt() < ptTrackMin) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::Pt); + if (posTrack.tpcChi2NCl() > tpcChi2NClTrackMax || negTrack.tpcChi2NCl() > tpcChi2NClTrackMax) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::TpcChi2NCls); + if (posTrack.itsChi2NCl() > itsChi2NClTrackMax || negTrack.itsChi2NCl() > itsChi2NClTrackMax) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::ItsChi2NCls); + } else { + const auto& bachTrack = candidate.template bachelor_as(); + if (!posTrack.hasITS() || !negTrack.hasITS() || !bachTrack.hasITS()) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::HasIts); + if (!posTrack.hasTPC() || !negTrack.hasTPC() || !bachTrack.hasTPC()) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::HasTpc); + if (posTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin || bachTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::TpcNClsCrossedRows); + if (std::abs(posTrack.eta()) > etaTrackMax || std::abs(negTrack.eta()) > etaTrackMax || std::abs(bachTrack.eta()) > etaTrackMax) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::Eta); + if (posTrack.pt() < ptTrackMin || negTrack.pt() < ptTrackMin || bachTrack.pt() < ptTrackMin) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::Pt); + if (posTrack.tpcChi2NCl() > tpcChi2NClTrackMax || negTrack.tpcChi2NCl() > tpcChi2NClTrackMax || bachTrack.tpcChi2NCl() > tpcChi2NClTrackMax) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::TpcChi2NCls); + if (posTrack.itsChi2NCl() > itsChi2NClTrackMax || negTrack.itsChi2NCl() > itsChi2NClTrackMax || bachTrack.itsChi2NCl() > itsChi2NClTrackMax) { + return false; + } + registry.fill(HIST("hTrackSel"), TrackCuts::ItsChi2NCls); + } + 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())) { + continue; + } + if (applyTrackSels && !isTrackSelected(v0)) { + continue; + } + if (isSelectedV0AsK0s(v0) || isSelectedV0AsLambda(v0)) { + int const matched = isMatched(v0); + if (matched != 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())) { + continue; + } + if (applyTrackSels && !isTrackSelected(v0)) { + continue; + } + if (isSelectedV0AsK0s(v0) || isSelectedV0AsLambda(v0)) { + fillTree(v0, 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())) { + continue; + } + if (applyTrackSels && !isTrackSelected(casc)) { + continue; + } + if (isSelectedCascAsOmega(casc)) { + int const matched = isMatched(casc); + if (matched != 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())) { + continue; + } + if (applyTrackSels && !isTrackSelected(casc)) { + continue; + } + if (isSelectedCascAsOmega(casc)) { + fillTree(casc, 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..cd4425ff6b9 100644 --- a/PWGHF/Tasks/taskSelOptimisation.cxx +++ b/PWGHF/Tasks/taskSelOptimisation.cxx @@ -14,12 +14,32 @@ /// /// \author Fabrizio Grosa , CERN -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -27,74 +47,74 @@ using namespace o2::framework::expressions; namespace { -static constexpr int nCutsToTestCosp = 15; -static constexpr int nCutsToTestDecLen = 11; -static constexpr int nCutsToTestImpParProd = 11; -static constexpr int nCutsToTestMinDCAxy = 9; -static constexpr int nCutsToTestMinTrackPt = 7; - -constexpr float cutsCosp[nCutsToTestCosp] = {0.70, 0.75, 0.80, 0.85, 0.88, 0.90, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 0.995}; -constexpr float cutsDecLen[nCutsToTestDecLen] = {0., 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.04, 0.05, 0.075, 0.1}; -constexpr float cutsImpParProd[nCutsToTestImpParProd] = {-0.00005, -0.00004, -0.00003, -0.00002, -0.00001, 0., 0.00001, 0.00002, 0.00003, 0.00004, 0.00005}; -constexpr float cutsMinDCAxy[nCutsToTestMinDCAxy] = {0., 0.0005, 0.001, 0.0015, 0.0020, 0.0025, 0.0030, 0.0040, 0.0050}; -constexpr float cutsMinTrackPt[nCutsToTestMinTrackPt] = {0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60}; - -auto vecCutsCosp = std::vector{cutsCosp, cutsCosp + nCutsToTestCosp}; -auto vecCutsDecLen = std::vector{cutsDecLen, cutsDecLen + nCutsToTestDecLen}; -auto vecCutsImpParProd = std::vector{cutsImpParProd, cutsImpParProd + nCutsToTestImpParProd}; -auto vecCutsMinDCAxy = std::vector{cutsMinDCAxy, cutsMinDCAxy + nCutsToTestMinDCAxy}; -auto vecCutsMinTrackPt = std::vector{cutsMinTrackPt, cutsMinTrackPt + nCutsToTestMinTrackPt}; - -static const int n2Prong = o2::aod::hf_cand_2prong::DecayType::N2ProngDecays; -static const int n3Prong = o2::aod::hf_cand_3prong::DecayType::N3ProngDecays; - -static constexpr std::array, 3> histoNames2Prong = {{{"hPromptVsPtD0ToPiK", "hPromptVsPtJpsiToEE", "hPromptVsPtJpsiToMuMu", "hPromptVsPt2Prong"}, - {"hNonPromptVsPtD0ToPiK", "hNonPromptVsPtJpsiToEE", "hNonPromptVsPtJpsiToMuMu", "hNonPromptVsPt2Prong"}, - {"hBkgVsPtD0ToPiK", "hBkgVsPtJpsiToEE", "hBkgVsPtJpsiToMuMu", "hBkgVsPt2Prong"}}}; -static constexpr std::array, 3> histoNamesCosp2Prong = {{{"hPromptCospVsPtD0ToPiK", "hPromptCospVsPtJpsiToEE", "hPromptCospVsPtJpsiToMuMu", "hPromptCospVsPt2Prong"}, - {"hNonPromptCospVsPtD0ToPiK", "hNonPromptCospVsPtJpsiToEE", "hNonPromptCospVsPtJpsiToMuMu", "hNonPromptCospVsPt2Prong"}, - {"hBkgCospVsPtD0ToPiK", "hBkgCospVsPtJpsiToEE", "hBkgCospVsPtJpsiToMuMu", "hBkgCospVsPt2Prong"}}}; -static constexpr std::array, 3> histoNamesDecLen2Prong = {{{"hPromptDecLenVsPtD0ToPiK", "hPromptDecLenVsPtJpsiToEE", "hPromptDecLenVsPtJpsiToMuMu", "hPromptDecLenVsPt2Prong"}, - {"hNonPromptDecLenVsPtD0ToPiK", "hNonPromptDecLenVsPtJpsiToEE", "hNonPromptDecLenVsPtJpsiToMuMu", "hNonPromptDecLenVsPt2Prong"}, - {"hBkgDecLenVsPtD0ToPiK", "hBkgDecLenVsPtJpsiToEE", "hBkgDecLenVsPtJpsiToMuMu", "hBkgDecLenVsPt2Prong"}}}; -static constexpr std::array, 3> histoNamesImpParProd2Prong = {{{"hPromptImpParProdVsPtD0ToPiK", "hPromptImpParProdVsPtJpsiToEE", "hPromptImpParProdVsPtJpsiToMuMu", "hPromptImpParProdVsPt2Prong"}, - {"hNonPromptImpParProdVsPtD0ToPiK", "hNonPromptImpParProdVsPtJpsiToEE", "hNonPromptImpParProdVsPtJpsiToMuMu", "hNonPromptImpParProdVsPt2Prong"}, - {"hBkgImpParProdVsPtD0ToPiK", "hBkgImpParProdVsPtJpsiToEE", "hBkgImpParProdVsPtJpsiToMuMu", "hBkgImpParProdVsPt2Prong"}}}; -static constexpr std::array, 3> histoNamesMinDCAxy2Prong = {{{"hPromptMinDCAxyVsPtD0ToPiK", "hPromptMinDCAxyVsPtJpsiToEE", "hPromptMinDCAxyVsPtJpsiToMuMu", "hPromptMinDCAxyVsPt2Prong"}, - {"hNonPromptMinDCAxyVsPtD0ToPiK", "hNonPromptMinDCAxyVsPtJpsiToEE", "hNonPromptMinDCAxyVsPtJpsiToMuMu", "hNonPromptMinDCAxyVsPt2Prong"}, - {"hBkgMinDCAxyVsPtD0ToPiK", "hBkgMinDCAxyVsPtJpsiToEE", "hBkgMinDCAxyVsPtJpsiToMuMu", "hBkgMinDCAxyVsPt2Prong"}}}; -static constexpr std::array, 3> histoNamesMinTrackPt2Prong = {{{"hPromptMinTrackPtVsPtD0ToPiK", "hPromptMinTrackPtVsPtJpsiToEE", "hPromptMinTrackPtVsPtJpsiToMuMu", "hPromptMinTrackPtVsPt2Prong"}, - {"hNonPromptMinTrackPtVsPtD0ToPiK", "hNonPromptMinTrackPtVsPtJpsiToEE", "hNonPromptMinTrackPtVsPtJpsiToMuMu", "hNonPromptMinTrackPtVsPt2Prong"}, - {"hBkgMinTrackPtVsPtD0ToPiK", "hBkgMinTrackPtVsPtJpsiToEE", "hBkgMinTrackPtVsPtJpsiToMuMu", "hBkgMinTrackPtVsPt2Prong"}}}; - -static constexpr std::array, 3> histoNames3Prong = {{{"hPromptVsPtDPlusToPiKPi", "hPromptVsPtLcToPKPi", "hPromptVsPtDsToPiKK", "hPromptVsPtXicToPKPi", "hPromptVsPt3Prong"}, - {"hNonPromptVsPtDPlusToPiKPi", "hNonPromptVsPtLcToPKPi", "hNonPromptVsPtDsToPiKK", "hNonPromptVsPtXicToPKPi", "hNonPromptVsPt3Prong"}, - {"hBkgVsPtDPlusToPiKPi", "hBkgVsPtLcToPKPi", "hBkgVsPtDsToPiKK", "hBkgVsPtXicToPKPi", "hBkgVsPt3Prong"}}}; -static constexpr std::array, 3> histoNamesCosp3Prong = {{{"hPromptCospVsPtDPlusToPiKPi", "hPromptCospVsPtLcToPKPi", "hPromptCospVsPtDsToPiKK", "hPromptCospVsPtXicToPKPi", "hPromptCospVsPt3Prong"}, - {"hNonPromptCospVsPtDPlusToPiKPi", "hNonPromptCospVsPtLcToPKPi", "hNonPromptCospVsPtDsToPiKK", "hNonPromptCospVsPtXicToPKPi", "hNonPromptCospVsPt3Prong"}, - {"hBkgCospVsPtDPlusToPiKPi", "hBkgCospVsPtLcToPKPi", "hBkgCospVsPtDsToPiKK", "hBkgCospVsPtXicToPKPi", "hBkgCospVsPt3Prong"}}}; -static constexpr std::array, 3> histoNamesDecLen3Prong = {{{"hPromptDecLenVsPtDPlusToPiKPi", "hPromptDecLenVsPtLcToPKPi", "hPromptDecLenVsPtDsToPiKK", "hPromptDecLenVsPtXicToPKPi", "hPromptDecLenVsPt3Prong"}, - {"hNonPromptDecLenVsPtDPlusToPiKPi", "hNonPromptDecLenVsPtLcToPKPi", "hNonPromptDecLenVsPtDsToPiKK", "hNonPromptDecLenVsPtXicToPKPi", "hNonPromptDecLenVsPt3Prong"}, - {"hBkgDecLenVsPtDPlusToPiKPi", "hBkgDecLenVsPtLcToPKPi", "hBkgDecLenVsPtDsToPiKK", "hBkgDecLenVsPtXicToPKPi", "hBkgDecLenVsPt3Prong"}}}; -static constexpr std::array, 3> histoNamesMinDCAxy3Prong = {{{"hPromptMinDCAxyVsPtDPlusToPiKPi", "hPromptMinDCAxyVsPtLcToPKPi", "hPromptMinDCAxyVsPtDsToPiKK", "hPromptMinDCAxyVsPtXicToPKPi", "hPromptMinDCAxyVsPt3Prong"}, - {"hNonPromptMinDCAxyVsPtDPlusToPiKPi", "hNonPromptMinDCAxyVsPtLcToPKPi", "hNonPromptMinDCAxyVsPtDsToPiKK", "hNonPromptMinDCAxyVsPtXicToPKPi", "hNonPromptMinDCAxyVsPt3Prong"}, - {"hBkgMinDCAxyVsPtDPlusToPiKPi", "hBkgMinDCAxyVsPtLcToPKPi", "hBkgMinDCAxyVsPtDsToPiKK", "hBkgMinDCAxyVsPtXicToPKPi", "hBkgMinDCAxyVsPt3Prong"}}}; -static constexpr std::array, 3> histoNamesMinTrackPt3Prong = {{{"hPromptMinTrackPtVsPtDPlusToPiKPi", "hPromptMinTrackPtVsPtLcToPKPi", "hPromptMinTrackPtVsPtDsToPiKK", "hPromptMinTrackPtVsPtXicToPKPi", "hPromptMinTrackPtVsPt3Prong"}, - {"hNonPromptMinTrackPtVsPtDPlusToPiKPi", "hNonPromptMinTrackPtVsPtLcToPKPi", "hNonPromptMinTrackPtVsPtDsToPiKK", "hNonPromptMinTrackPtVsPtXicToPKPi", "hNonPromptMinTrackPtVsPt3Prong"}, - {"hBkgMinTrackPtVsPtDPlusToPiKPi", "hBkgMinTrackPtVsPtLcToPKPi", "hBkgMinTrackPtVsPtDsToPiKK", "hBkgMinTrackPtVsPtXicToPKPi", "hBkgMinTrackPtVsPt3Prong"}}}; - -static std::array, n2Prong + 1>, 3> histPt2Prong{}; -static std::array, n2Prong + 1>, 3> histCospVsPt2Prong{}; -static std::array, n2Prong + 1>, 3> histDecLenVsPt2Prong{}; -static std::array, n2Prong + 1>, 3> histImpParProdVsPt2Prong{}; -static std::array, n2Prong + 1>, 3> histMinDCAxyVsPt2Prong{}; -static std::array, n2Prong + 1>, 3> histMinTrackPtVsPt2Prong{}; - -static std::array, n3Prong + 1>, 3> histPt3Prong{}; -static std::array, n3Prong + 1>, 3> histCospVsPt3Prong{}; -static std::array, n3Prong + 1>, 3> histDecLenVsPt3Prong{}; -static std::array, n3Prong + 1>, 3> histMinDCAxyVsPt3Prong{}; -static std::array, n3Prong + 1>, 3> histMinTrackPtVsPt3Prong{}; +constexpr int NCutsToTestCosp = 15; +constexpr int NCutsToTestDecLen = 11; +constexpr int NCutsToTestImpParProd = 11; +constexpr int NCutsToTestMinDcAxy = 9; +constexpr int NCutsToTestMinTrackPt = 7; + +constexpr float CutsCosp[NCutsToTestCosp] = {0.70, 0.75, 0.80, 0.85, 0.88, 0.90, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 0.995}; +constexpr float CutsDecLen[NCutsToTestDecLen] = {0., 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.04, 0.05, 0.075, 0.1}; +constexpr float CutsImpParProd[NCutsToTestImpParProd] = {-0.00005, -0.00004, -0.00003, -0.00002, -0.00001, 0., 0.00001, 0.00002, 0.00003, 0.00004, 0.00005}; +constexpr float CutsMinDcAxy[NCutsToTestMinDcAxy] = {0., 0.0005, 0.001, 0.0015, 0.0020, 0.0025, 0.0030, 0.0040, 0.0050}; +constexpr float CutsMinTrackPt[NCutsToTestMinTrackPt] = {0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60}; + +auto vecCutsCosp = std::vector{CutsCosp, CutsCosp + NCutsToTestCosp}; +auto vecCutsDecLen = std::vector{CutsDecLen, CutsDecLen + NCutsToTestDecLen}; +auto vecCutsImpParProd = std::vector{CutsImpParProd, CutsImpParProd + NCutsToTestImpParProd}; +auto vecCutsMinDCAxy = std::vector{CutsMinDcAxy, CutsMinDcAxy + NCutsToTestMinDcAxy}; +auto vecCutsMinTrackPt = std::vector{CutsMinTrackPt, CutsMinTrackPt + NCutsToTestMinTrackPt}; + +const int n2Prong = o2::aod::hf_cand_2prong::DecayType::N2ProngDecays; +const int n3Prong = o2::aod::hf_cand_3prong::DecayType::N3ProngDecays; + +constexpr std::array, 3> HistoNames2Prong = {{{"hPromptVsPtD0ToPiK", "hPromptVsPtJpsiToEE", "hPromptVsPtJpsiToMuMu", "hPromptVsPt2Prong"}, + {"hNonPromptVsPtD0ToPiK", "hNonPromptVsPtJpsiToEE", "hNonPromptVsPtJpsiToMuMu", "hNonPromptVsPt2Prong"}, + {"hBkgVsPtD0ToPiK", "hBkgVsPtJpsiToEE", "hBkgVsPtJpsiToMuMu", "hBkgVsPt2Prong"}}}; +constexpr std::array, 3> HistoNamesCosp2Prong = {{{"hPromptCospVsPtD0ToPiK", "hPromptCospVsPtJpsiToEE", "hPromptCospVsPtJpsiToMuMu", "hPromptCospVsPt2Prong"}, + {"hNonPromptCospVsPtD0ToPiK", "hNonPromptCospVsPtJpsiToEE", "hNonPromptCospVsPtJpsiToMuMu", "hNonPromptCospVsPt2Prong"}, + {"hBkgCospVsPtD0ToPiK", "hBkgCospVsPtJpsiToEE", "hBkgCospVsPtJpsiToMuMu", "hBkgCospVsPt2Prong"}}}; +constexpr std::array, 3> HistoNamesDecLen2Prong = {{{"hPromptDecLenVsPtD0ToPiK", "hPromptDecLenVsPtJpsiToEE", "hPromptDecLenVsPtJpsiToMuMu", "hPromptDecLenVsPt2Prong"}, + {"hNonPromptDecLenVsPtD0ToPiK", "hNonPromptDecLenVsPtJpsiToEE", "hNonPromptDecLenVsPtJpsiToMuMu", "hNonPromptDecLenVsPt2Prong"}, + {"hBkgDecLenVsPtD0ToPiK", "hBkgDecLenVsPtJpsiToEE", "hBkgDecLenVsPtJpsiToMuMu", "hBkgDecLenVsPt2Prong"}}}; +constexpr std::array, 3> HistoNamesImpParProd2Prong = {{{"hPromptImpParProdVsPtD0ToPiK", "hPromptImpParProdVsPtJpsiToEE", "hPromptImpParProdVsPtJpsiToMuMu", "hPromptImpParProdVsPt2Prong"}, + {"hNonPromptImpParProdVsPtD0ToPiK", "hNonPromptImpParProdVsPtJpsiToEE", "hNonPromptImpParProdVsPtJpsiToMuMu", "hNonPromptImpParProdVsPt2Prong"}, + {"hBkgImpParProdVsPtD0ToPiK", "hBkgImpParProdVsPtJpsiToEE", "hBkgImpParProdVsPtJpsiToMuMu", "hBkgImpParProdVsPt2Prong"}}}; +constexpr std::array, 3> HistoNamesMinDcAxy2Prong = {{{"hPromptMinDCAxyVsPtD0ToPiK", "hPromptMinDCAxyVsPtJpsiToEE", "hPromptMinDCAxyVsPtJpsiToMuMu", "hPromptMinDCAxyVsPt2Prong"}, + {"hNonPromptMinDCAxyVsPtD0ToPiK", "hNonPromptMinDCAxyVsPtJpsiToEE", "hNonPromptMinDCAxyVsPtJpsiToMuMu", "hNonPromptMinDCAxyVsPt2Prong"}, + {"hBkgMinDCAxyVsPtD0ToPiK", "hBkgMinDCAxyVsPtJpsiToEE", "hBkgMinDCAxyVsPtJpsiToMuMu", "hBkgMinDCAxyVsPt2Prong"}}}; +constexpr std::array, 3> HistoNamesMinTrackPt2Prong = {{{"hPromptMinTrackPtVsPtD0ToPiK", "hPromptMinTrackPtVsPtJpsiToEE", "hPromptMinTrackPtVsPtJpsiToMuMu", "hPromptMinTrackPtVsPt2Prong"}, + {"hNonPromptMinTrackPtVsPtD0ToPiK", "hNonPromptMinTrackPtVsPtJpsiToEE", "hNonPromptMinTrackPtVsPtJpsiToMuMu", "hNonPromptMinTrackPtVsPt2Prong"}, + {"hBkgMinTrackPtVsPtD0ToPiK", "hBkgMinTrackPtVsPtJpsiToEE", "hBkgMinTrackPtVsPtJpsiToMuMu", "hBkgMinTrackPtVsPt2Prong"}}}; + +constexpr std::array, 3> HistoNames3Prong = {{{"hPromptVsPtDPlusToPiKPi", "hPromptVsPtLcToPKPi", "hPromptVsPtDsToPiKK", "hPromptVsPtXicToPKPi", "hPromptVsPt3Prong"}, + {"hNonPromptVsPtDPlusToPiKPi", "hNonPromptVsPtLcToPKPi", "hNonPromptVsPtDsToPiKK", "hNonPromptVsPtXicToPKPi", "hNonPromptVsPt3Prong"}, + {"hBkgVsPtDPlusToPiKPi", "hBkgVsPtLcToPKPi", "hBkgVsPtDsToPiKK", "hBkgVsPtXicToPKPi", "hBkgVsPt3Prong"}}}; +constexpr std::array, 3> HistoNamesCosp3Prong = {{{"hPromptCospVsPtDPlusToPiKPi", "hPromptCospVsPtLcToPKPi", "hPromptCospVsPtDsToPiKK", "hPromptCospVsPtXicToPKPi", "hPromptCospVsPt3Prong"}, + {"hNonPromptCospVsPtDPlusToPiKPi", "hNonPromptCospVsPtLcToPKPi", "hNonPromptCospVsPtDsToPiKK", "hNonPromptCospVsPtXicToPKPi", "hNonPromptCospVsPt3Prong"}, + {"hBkgCospVsPtDPlusToPiKPi", "hBkgCospVsPtLcToPKPi", "hBkgCospVsPtDsToPiKK", "hBkgCospVsPtXicToPKPi", "hBkgCospVsPt3Prong"}}}; +constexpr std::array, 3> HistoNamesDecLen3Prong = {{{"hPromptDecLenVsPtDPlusToPiKPi", "hPromptDecLenVsPtLcToPKPi", "hPromptDecLenVsPtDsToPiKK", "hPromptDecLenVsPtXicToPKPi", "hPromptDecLenVsPt3Prong"}, + {"hNonPromptDecLenVsPtDPlusToPiKPi", "hNonPromptDecLenVsPtLcToPKPi", "hNonPromptDecLenVsPtDsToPiKK", "hNonPromptDecLenVsPtXicToPKPi", "hNonPromptDecLenVsPt3Prong"}, + {"hBkgDecLenVsPtDPlusToPiKPi", "hBkgDecLenVsPtLcToPKPi", "hBkgDecLenVsPtDsToPiKK", "hBkgDecLenVsPtXicToPKPi", "hBkgDecLenVsPt3Prong"}}}; +constexpr std::array, 3> HistoNamesMinDcAxy3Prong = {{{"hPromptMinDCAxyVsPtDPlusToPiKPi", "hPromptMinDCAxyVsPtLcToPKPi", "hPromptMinDCAxyVsPtDsToPiKK", "hPromptMinDCAxyVsPtXicToPKPi", "hPromptMinDCAxyVsPt3Prong"}, + {"hNonPromptMinDCAxyVsPtDPlusToPiKPi", "hNonPromptMinDCAxyVsPtLcToPKPi", "hNonPromptMinDCAxyVsPtDsToPiKK", "hNonPromptMinDCAxyVsPtXicToPKPi", "hNonPromptMinDCAxyVsPt3Prong"}, + {"hBkgMinDCAxyVsPtDPlusToPiKPi", "hBkgMinDCAxyVsPtLcToPKPi", "hBkgMinDCAxyVsPtDsToPiKK", "hBkgMinDCAxyVsPtXicToPKPi", "hBkgMinDCAxyVsPt3Prong"}}}; +constexpr std::array, 3> HistoNamesMinTrackPt3Prong = {{{"hPromptMinTrackPtVsPtDPlusToPiKPi", "hPromptMinTrackPtVsPtLcToPKPi", "hPromptMinTrackPtVsPtDsToPiKK", "hPromptMinTrackPtVsPtXicToPKPi", "hPromptMinTrackPtVsPt3Prong"}, + {"hNonPromptMinTrackPtVsPtDPlusToPiKPi", "hNonPromptMinTrackPtVsPtLcToPKPi", "hNonPromptMinTrackPtVsPtDsToPiKK", "hNonPromptMinTrackPtVsPtXicToPKPi", "hNonPromptMinTrackPtVsPt3Prong"}, + {"hBkgMinTrackPtVsPtDPlusToPiKPi", "hBkgMinTrackPtVsPtLcToPKPi", "hBkgMinTrackPtVsPtDsToPiKK", "hBkgMinTrackPtVsPtXicToPKPi", "hBkgMinTrackPtVsPt3Prong"}}}; + +std::array, n2Prong + 1>, 3> histPt2Prong{}; +std::array, n2Prong + 1>, 3> histCospVsPt2Prong{}; +std::array, n2Prong + 1>, 3> histDecLenVsPt2Prong{}; +std::array, n2Prong + 1>, 3> histImpParProdVsPt2Prong{}; +std::array, n2Prong + 1>, 3> histMinDCAxyVsPt2Prong{}; +std::array, n2Prong + 1>, 3> histMinTrackPtVsPt2Prong{}; + +std::array, n3Prong + 1>, 3> histPt3Prong{}; +std::array, n3Prong + 1>, 3> histCospVsPt3Prong{}; +std::array, n3Prong + 1>, 3> histDecLenVsPt3Prong{}; +std::array, n3Prong + 1>, 3> histMinDCAxyVsPt3Prong{}; +std::array, n3Prong + 1>, 3> histMinTrackPtVsPt3Prong{}; } // namespace @@ -121,43 +141,43 @@ struct HfSelOptimisation { { for (int iOrig{0}; iOrig < 3; iOrig++) { for (int i2Prong = 0; i2Prong < n2Prong + 1; ++i2Prong) { - histPt2Prong[iOrig][i2Prong] = registry.add(histoNames2Prong[iOrig][i2Prong].data(), "", HistType::kTH1F, {axisPt}); - histCospVsPt2Prong[iOrig][i2Prong] = registry.add(histoNamesCosp2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisCosp}); + histPt2Prong[iOrig][i2Prong] = registry.add(HistoNames2Prong[iOrig][i2Prong].data(), "", HistType::kTH1F, {axisPt}); + histCospVsPt2Prong[iOrig][i2Prong] = registry.add(HistoNamesCosp2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisCosp}); for (int iBin{0}; iBin < histCospVsPt2Prong[iOrig][i2Prong]->GetYaxis()->GetNbins(); ++iBin) { histCospVsPt2Prong[iOrig][i2Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.4f", cutsToTestCpa->at(iBin))); } - histDecLenVsPt2Prong[iOrig][i2Prong] = registry.add(histoNamesDecLen2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisDecLen}); + histDecLenVsPt2Prong[iOrig][i2Prong] = registry.add(HistoNamesDecLen2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisDecLen}); for (int iBin{0}; iBin < histDecLenVsPt2Prong[iOrig][i2Prong]->GetYaxis()->GetNbins(); ++iBin) { histDecLenVsPt2Prong[iOrig][i2Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.3f", cutsToTestDecLen->at(iBin))); } - histImpParProdVsPt2Prong[iOrig][i2Prong] = registry.add(histoNamesImpParProd2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisImpParProd}); + histImpParProdVsPt2Prong[iOrig][i2Prong] = registry.add(HistoNamesImpParProd2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisImpParProd}); for (int iBin{0}; iBin < histImpParProdVsPt2Prong[iOrig][i2Prong]->GetYaxis()->GetNbins(); ++iBin) { histImpParProdVsPt2Prong[iOrig][i2Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.4f", cutsToTestImpParProd->at(iBin))); } - histMinDCAxyVsPt2Prong[iOrig][i2Prong] = registry.add(histoNamesMinDCAxy2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisMinDCAxy}); + histMinDCAxyVsPt2Prong[iOrig][i2Prong] = registry.add(HistoNamesMinDcAxy2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisMinDCAxy}); for (int iBin{0}; iBin < histMinDCAxyVsPt2Prong[iOrig][i2Prong]->GetYaxis()->GetNbins(); ++iBin) { histMinDCAxyVsPt2Prong[iOrig][i2Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.4f", cutsToTestMinDcaXY->at(iBin))); } - histMinTrackPtVsPt2Prong[iOrig][i2Prong] = registry.add(histoNamesMinTrackPt2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisMinTrackPt}); + histMinTrackPtVsPt2Prong[iOrig][i2Prong] = registry.add(HistoNamesMinTrackPt2Prong[iOrig][i2Prong].data(), "", HistType::kTH2F, {axisPt, axisMinTrackPt}); for (int iBin{0}; iBin < histMinTrackPtVsPt2Prong[iOrig][i2Prong]->GetYaxis()->GetNbins(); ++iBin) { histMinTrackPtVsPt2Prong[iOrig][i2Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.2f", cutsToTestMinTrackPt->at(iBin))); } } for (int i3Prong{0}; i3Prong < n3Prong + 1; ++i3Prong) { - histPt3Prong[iOrig][i3Prong] = registry.add(histoNames3Prong[iOrig][i3Prong].data(), "", HistType::kTH1F, {axisPt}); - histCospVsPt3Prong[iOrig][i3Prong] = registry.add(histoNamesCosp3Prong[iOrig][i3Prong].data(), "", HistType::kTH2F, {axisPt, axisCosp}); + histPt3Prong[iOrig][i3Prong] = registry.add(HistoNames3Prong[iOrig][i3Prong].data(), "", HistType::kTH1F, {axisPt}); + histCospVsPt3Prong[iOrig][i3Prong] = registry.add(HistoNamesCosp3Prong[iOrig][i3Prong].data(), "", HistType::kTH2F, {axisPt, axisCosp}); for (int iBin{0}; iBin < histCospVsPt3Prong[iOrig][i3Prong]->GetYaxis()->GetNbins(); ++iBin) { histCospVsPt3Prong[iOrig][i3Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.4f", cutsToTestCpa->at(iBin))); } - histDecLenVsPt3Prong[iOrig][i3Prong] = registry.add(histoNamesDecLen3Prong[iOrig][i3Prong].data(), "", HistType::kTH2F, {axisPt, axisDecLen}); + histDecLenVsPt3Prong[iOrig][i3Prong] = registry.add(HistoNamesDecLen3Prong[iOrig][i3Prong].data(), "", HistType::kTH2F, {axisPt, axisDecLen}); for (int iBin{0}; iBin < histDecLenVsPt3Prong[iOrig][i3Prong]->GetYaxis()->GetNbins(); ++iBin) { histDecLenVsPt3Prong[iOrig][i3Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.4f", cutsToTestDecLen->at(iBin))); } - histMinDCAxyVsPt3Prong[iOrig][i3Prong] = registry.add(histoNamesMinDCAxy3Prong[iOrig][i3Prong].data(), "", HistType::kTH2F, {axisPt, axisMinDCAxy}); + histMinDCAxyVsPt3Prong[iOrig][i3Prong] = registry.add(HistoNamesMinDcAxy3Prong[iOrig][i3Prong].data(), "", HistType::kTH2F, {axisPt, axisMinDCAxy}); for (int iBin{0}; iBin < histMinDCAxyVsPt3Prong[iOrig][i3Prong]->GetYaxis()->GetNbins(); ++iBin) { histMinDCAxyVsPt3Prong[iOrig][i3Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.4f", cutsToTestMinDcaXY->at(iBin))); } - histMinTrackPtVsPt3Prong[iOrig][i3Prong] = registry.add(histoNamesMinTrackPt3Prong[iOrig][i3Prong].data(), "", HistType::kTH2F, {axisPt, axisMinTrackPt}); + histMinTrackPtVsPt3Prong[iOrig][i3Prong] = registry.add(HistoNamesMinTrackPt3Prong[iOrig][i3Prong].data(), "", HistType::kTH2F, {axisPt, axisMinTrackPt}); for (int iBin{0}; iBin < histMinTrackPtVsPt3Prong[iOrig][i3Prong]->GetYaxis()->GetNbins(); ++iBin) { histMinTrackPtVsPt3Prong[iOrig][i3Prong]->GetYaxis()->SetBinLabel(iBin + 1, Form("%0.4f", cutsToTestMinTrackPt->at(iBin))); } @@ -170,7 +190,7 @@ struct HfSelOptimisation { /// \param candOrig is candidate type (Prompt, NonPrompt, Bkg) /// \param candidate is a candidate /// \param tracks is the array of daughter tracks - template + template void testSelections2Prong(const T1& candidate, const T2& tracks) { auto pT = candidate.pt(); @@ -180,35 +200,35 @@ struct HfSelOptimisation { std::array ptTrack{tracks[0].pt(), tracks[1].pt()}; std::sort(ptTrack.begin(), ptTrack.end()); - histPt2Prong[candOrig][candType]->Fill(pT); + histPt2Prong[CandOrig][CandType]->Fill(pT); for (std::size_t iCospCut{0}; iCospCut < cutsToTestCpa->size(); ++iCospCut) { if (candidate.cpa() > cutsToTestCpa->at(iCospCut)) { - histCospVsPt2Prong[candOrig][candType]->Fill(pT, iCospCut + 1); + histCospVsPt2Prong[CandOrig][CandType]->Fill(pT, iCospCut + 1); } } for (std::size_t iDecLenCut{0}; iDecLenCut < cutsToTestDecLen->size(); ++iDecLenCut) { if (candidate.decayLength() > cutsToTestDecLen->at(iDecLenCut)) { - histDecLenVsPt2Prong[candOrig][candType]->Fill(pT, iDecLenCut + 1); + histDecLenVsPt2Prong[CandOrig][CandType]->Fill(pT, iDecLenCut + 1); } } for (std::size_t iImpParProd{0}; iImpParProd < cutsToTestImpParProd->size(); ++iImpParProd) { if (candidate.impactParameterProduct() < cutsToTestImpParProd->at(iImpParProd)) { - histImpParProdVsPt2Prong[candOrig][candType]->Fill(pT, iImpParProd + 1); + histImpParProdVsPt2Prong[CandOrig][CandType]->Fill(pT, iImpParProd + 1); } } for (std::size_t iMinDCAxy{0}; iMinDCAxy < cutsToTestMinDcaXY->size(); ++iMinDCAxy) { if (absDCA[0] > cutsToTestMinDcaXY->at(iMinDCAxy)) { - histMinDCAxyVsPt2Prong[candOrig][candType]->Fill(pT, iMinDCAxy + 1); + histMinDCAxyVsPt2Prong[CandOrig][CandType]->Fill(pT, iMinDCAxy + 1); } } for (std::size_t iMinTrackPt{0}; iMinTrackPt < cutsToTestMinTrackPt->size(); ++iMinTrackPt) { if (ptTrack[0] > cutsToTestMinTrackPt->at(iMinTrackPt)) { - histMinTrackPtVsPt2Prong[candOrig][candType]->Fill(pT, iMinTrackPt + 1); + histMinTrackPtVsPt2Prong[CandOrig][CandType]->Fill(pT, iMinTrackPt + 1); } } } @@ -218,7 +238,7 @@ struct HfSelOptimisation { /// \param candOrig is candidate type (Prompt, NonPrompt, Bkg) /// \param candidate is a candidate /// \param tracks is the array of doughter tracks - template + template void testSelections3Prong(const T1& candidate, const T2& tracks) { auto pT = candidate.pt(); @@ -228,29 +248,29 @@ struct HfSelOptimisation { std::array ptTrack{tracks[0].pt(), tracks[1].pt(), tracks[2].pt()}; std::sort(ptTrack.begin(), ptTrack.end()); - histPt3Prong[candOrig][candType]->Fill(pT); + histPt3Prong[CandOrig][CandType]->Fill(pT); for (std::size_t iCospCut{0}; iCospCut < cutsToTestCpa->size(); ++iCospCut) { if (candidate.cpa() > cutsToTestCpa->at(iCospCut)) { - histCospVsPt3Prong[candOrig][candType]->Fill(pT, iCospCut + 1); + histCospVsPt3Prong[CandOrig][CandType]->Fill(pT, iCospCut + 1); } } for (std::size_t iDecLenCut{0}; iDecLenCut < cutsToTestDecLen->size(); ++iDecLenCut) { if (candidate.decayLength() > cutsToTestDecLen->at(iDecLenCut)) { - histDecLenVsPt3Prong[candOrig][candType]->Fill(pT, iDecLenCut + 1); + histDecLenVsPt3Prong[CandOrig][CandType]->Fill(pT, iDecLenCut + 1); } } for (std::size_t iMinDCAxy{0}; iMinDCAxy < cutsToTestMinDcaXY->size(); ++iMinDCAxy) { if (absDCA[0] > cutsToTestMinDcaXY->at(iMinDCAxy)) { - histMinDCAxyVsPt3Prong[candOrig][candType]->Fill(pT, iMinDCAxy + 1); + histMinDCAxyVsPt3Prong[CandOrig][CandType]->Fill(pT, iMinDCAxy + 1); } } for (std::size_t iMinTrackPt{0}; iMinTrackPt < cutsToTestMinTrackPt->size(); ++iMinTrackPt) { if (ptTrack[0] > cutsToTestMinTrackPt->at(iMinTrackPt)) { - histMinTrackPtVsPt3Prong[candOrig][candType]->Fill(pT, iMinTrackPt + 1); + histMinTrackPtVsPt3Prong[CandOrig][CandType]->Fill(pT, iMinTrackPt + 1); } } } @@ -264,12 +284,12 @@ struct HfSelOptimisation { auto trackPos = cand2Prong.prong0_as(); // positive daughter auto trackNeg = cand2Prong.prong1_as(); // negative daughter - std::array tracks = {trackPos, trackNeg}; + std::array const tracks = {trackPos, trackNeg}; bool isPrompt = false, isNonPrompt = false, isBkg = false; for (int iDecay{0}; iDecay < n2Prong; ++iDecay) { if (TESTBIT(cand2Prong.hfflag(), iDecay)) { - if (std::abs(cand2Prong.flagMcMatchRec()) == BIT(iDecay)) { + if (std::abs(cand2Prong.flagMcMatchRec()) == BIT(iDecay)) { // FIXME: Migrate to DecayChannelMain if (cand2Prong.originMcRec() == RecoDecay::OriginType::Prompt) { isPrompt = true; switch (iDecay) { @@ -320,12 +340,12 @@ struct HfSelOptimisation { auto trackFirst = cand3Prong.prong0_as(); // first daughter auto trackSecond = cand3Prong.prong1_as(); // second daughter auto trackThird = cand3Prong.prong2_as(); // third daughter - std::array tracks = {trackFirst, trackSecond, trackThird}; + std::array const tracks = {trackFirst, trackSecond, trackThird}; bool isPrompt = false, isNonPrompt = false, isBkg = false; for (int iDecay{0}; iDecay < n3Prong; ++iDecay) { if (TESTBIT(cand3Prong.hfflag(), iDecay)) { - if (std::abs(cand3Prong.flagMcMatchRec()) == BIT(iDecay)) { + if (std::abs(cand3Prong.flagMcMatchRec()) == BIT(iDecay)) { // FIXME: Migrate to DecayChannelMain if (cand3Prong.originMcRec() == RecoDecay::OriginType::Prompt) { isPrompt = true; switch (iDecay) { diff --git a/PWGHF/Utils/utilsAnalysis.h b/PWGHF/Utils/utilsAnalysis.h index 0b4233bff15..dfc4ef46fdd 100644 --- a/PWGHF/Utils/utilsAnalysis.h +++ b/PWGHF/Utils/utilsAnalysis.h @@ -11,30 +11,64 @@ /// \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 +#include +#include + #include // std::upper_bound -#include // std::distance +#include +#include // std::distance +#include //std::string namespace o2::analysis { -/// Finds pT bin in an array. -/// \param bins array of pT bins -/// \param value pT +enum BHadMothers { NotMatched = 0, + BPlus, + BZero, + Bs, + LambdaBZero }; + +/// Convert the B hadron mother PDG for non prompt candidates to a flag +/// \param flagBHad pdg of the b hadron mother +/// \return integer map to specific mothers' PDG codes +inline 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 bin in an array that contains a value. +/// \param bins array of bins +/// \param value value to find /// \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. -template -int findBin(T1 const& binsPt, T2 value) +/// \note Accounts for the offset so that pT bin array can be used to also configure a histogram axis. +template +int findBin(TArrayPt const& bins, TNumber const value) { - if (value < binsPt->front()) { + if (value < bins->front()) { return -1; } - if (value >= binsPt->back()) { + if (value >= bins->back()) { return -1; } - return std::distance(binsPt->begin(), std::upper_bound(binsPt->begin(), binsPt->end(), value)) - 1; + return std::distance(bins->begin(), std::upper_bound(bins->begin(), bins->end(), value)) - 1; } /// Single-track cut on DCAxy and DCAz @@ -44,8 +78,12 @@ int findBin(T1 const& binsPt, T2 value) /// \param dcaXY is the prong dcaXY /// \param dcaZ is the prong dcaZ /// \return true if track passes all cuts -template -bool isSelectedTrackDca(T1 const& binsPt, T2 const& cuts, const float pt, const float dcaXY, const float dcaZ) +template +bool isSelectedTrackDca(TArrayPt const& binsPt, + TArrayCuts const& cuts, + const float pt, + const float dcaXY, + const float dcaZ) { auto binPt = findBin(binsPt, pt); if (binPt == -1) { @@ -71,8 +109,10 @@ bool isSelectedTrackDca(T1 const& binsPt, T2 const& cuts, const float pt, const /// \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) +template +bool isSelectedTrackItsQuality(TTrack const& track, + const int itsNClustersFoundMin, + const float itsChi2PerClusterMax) { if (track.itsNCls() < itsNClustersFoundMin) { return false; @@ -90,8 +130,12 @@ bool isSelectedTrackItsQuality(T const& track, const int itsNClustersFoundMin, c /// \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) +template +bool isSelectedTrackTpcQuality(TTrack const& track, + const int tpcNClustersFoundMin, + const int tpcNCrossedRowsMin, + const float tpcNCrossedRowsOverFindableClustersMin, + const float tpcChi2PerClusterMax) { if (track.tpcNClsFound() < tpcNClustersFoundMin) { return false; @@ -108,6 +152,51 @@ bool isSelectedTrackTpcQuality(T const& track, const int tpcNClustersFoundMin, c return true; } +/// Mass selection of 2 or 3 prong candidates 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) +{ + const float peakMean = (pt < cutConfig.ptDeltaMassMax.value) ? ((pdgMass + cutConfig.deltaMassPars->get("constant")) + cutConfig.deltaMassPars->get("linear") * pt) : pdgMass; + const 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.f, "Maximum number of sigmas for pT-differential mass cut for 2-prong candidates"}; + o2::framework::Configurable ptDeltaMassMax{"ptDeltaMassMax", 10.f, "Max pT to apply delta mass shift to PDG mass value for 2-prong candidates"}; + o2::framework::Configurable ptMassCutMax{"ptMassCutMax", 9999.f, "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.f, "Max pT to apply delta mass shift to PDG mass value for 3-prong candidates"}; + o2::framework::Configurable ptMassCutMax{"ptMassCutMax", 9999.f, "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/utilsBfieldCCDB.h b/PWGHF/Utils/utilsBfieldCCDB.h index 8e61485ae53..d14203161e4 100644 --- a/PWGHF/Utils/utilsBfieldCCDB.h +++ b/PWGHF/Utils/utilsBfieldCCDB.h @@ -16,11 +16,15 @@ #ifndef PWGHF_UTILS_UTILSBFIELDCCDB_H_ #define PWGHF_UTILS_UTILSBFIELDCCDB_H_ -#include // std::string +#include +#include +#include +#include +#include +#include +#include -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.h" +#include // std::string /// \brief Sets up the grp object for magnetic field (w/o matCorr for propagation) /// \param bc is the bunch crossing @@ -29,9 +33,13 @@ /// \param ccdbPathGrp is the path where the GRP oject is stored /// \param lut is a pointer to the o2::base::MatLayerCylSet object /// \param isRun2 tells whether we are analysing Run2 converted data or not (different GRP object type) -void initCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string const& ccdbPathGrp, o2::base::MatLayerCylSet* lut, - bool isRun2) +template +void initCCDB(TBc const& bc, + int& mRunNumber, + o2::framework::Service const& ccdb, + std::string const& ccdbPathGrp, + o2::base::MatLayerCylSet* lut, + const bool isRun2) { if (mRunNumber != bc.runNumber()) { LOGF(info, "====== initCCDB function called (isRun2==%d)", isRun2); diff --git a/PWGHF/Utils/utilsDerivedData.h b/PWGHF/Utils/utilsDerivedData.h new file mode 100644 index 00000000000..8b2b4fd431a --- /dev/null +++ b/PWGHF/Utils/utilsDerivedData.h @@ -0,0 +1,259 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Common/Core/RecoDecay.h" + +#include +#include +#include +#include + +#include +#include +#include + +// 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(TCursor& 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; + } + + void reserveTablesCandidates(const uint64_t size) + { + o2::analysis::hf_derived::reserveTable(rowCandidateBase, conf->fillCandidateBase, size); + } + + void reserveTablesColl(const uint64_t size) + { + o2::analysis::hf_derived::reserveTable(rowCollBase, conf->fillCollBase, size); + o2::analysis::hf_derived::reserveTable(rowCollId, conf->fillCollId, size); + } + + void reserveTablesMcColl(const uint64_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); + } + + void reserveTablesParticles(const uint64_t size) + { + o2::analysis::hf_derived::reserveTable(rowParticleBase, conf->fillParticleBase, size); + o2::analysis::hf_derived::reserveTable(rowParticleId, conf->fillParticleId, size); + } + + template + void fillTablesCandidate(const TCandidate& candidate, + const double invMass, + const double y) + { + if (conf->fillCandidateBase.value) { + rowCandidateBase( + rowCollBase.lastIndex(), + candidate.pt(), + candidate.eta(), + candidate.phi(), + invMass, + y); + } + } + + template + void fillTablesCollision(TCollision const& 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(TMcCollision const& 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(TMcParticle const& particle, const TMass 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(TMcCollisions const& mcCollisions, + o2::framework::Preslice const& mcParticlesPerMcCollision, + TMcParticles const& mcParticles) + { + if (!conf->fillMcRCollId.value) { + return; + } + hasMcParticles.clear(); + // Fill MC collision flags + for (const auto& mcCollision : mcCollisions) { + const auto thisMcCollId = mcCollision.globalIndex(); + const 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(TMcCollisions const& mcCollisions, + o2::framework::Preslice const& mcParticlesPerMcCollision, + TMcParticles const& mcParticles, + const TMass massParticle) + { + // Fill MC collision properties + const auto sizeTableMcColl = mcCollisions.size(); + reserveTablesMcColl(sizeTableMcColl); + for (const auto& mcCollision : mcCollisions) { + const auto thisMcCollId = mcCollision.globalIndex(); + const auto particlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, thisMcCollId); + const 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 56c5ac17f67..f520fd5f476 100644 --- a/PWGHF/Utils/utilsEvSelHf.h +++ b/PWGHF/Utils/utilsEvSelHf.h @@ -18,21 +18,88 @@ #ifndef PWGHF_UTILS_UTILSEVSELHF_H_ #define PWGHF_UTILS_UTILSEVSELHF_H_ +#include "PWGHF/Core/CentralityEstimation.h" +// +#include "PWGUD/Core/SGCutParHolder.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/CollisionTypeHelper.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include #include // std::shared_ptr #include // std::string -#include "Framework/Configurable.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/HistogramSpec.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(TCollision const& collision, const int occEstimator) +{ + switch (occEstimator) { + case OccupancyEstimator::Its: + return static_cast(collision.trackOccupancyInTimeRange()); + case OccupancyEstimator::Ft0c: + return static_cast(collision.ft0cOccupancyInTimeRange()); + default: + LOG(fatal) << "Occupancy estimator not valid. See OccupancyEstimator for valid values."; + break; + } + return -999.f; +}; -#include "EventFiltering/Zorro.h" -#include "PWGHF/Core/CentralityEstimation.h" +/// \brief Function to get MC collision occupancy +/// \param collSlice collection of reconstructed collisions associated to a generated one +/// \return generated MC collision occupancy +template +float getOccupancyGenColl(TCollisions const& collSlice, const int occEstimator) +{ + using TMult = uint16_t; // type of numContrib + TMult multiplicity{}; + float occupancy{0.f}; + for (const auto& collision : collSlice) { + const TMult 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, + Rct, SoftwareTrigger, Centrality, Trigger, @@ -41,42 +108,54 @@ enum EventRejection { ItsRofBorderCut, IsGoodZvtxFT0vsPV, NoSameBunchPileup, - NumTracksInTimeRange, + Occupancy, NContrib, + NoCollInTimeRangeNarrow, + NoCollInTimeRangeStandard, + NoCollInRofStandard, + UpcEventCut, Chi2, PositionZ, NEventRejection }; -o2::framework::AxisSpec axisEvents = {EventRejection::NEventRejection, -0.5f, +EventRejection::NEventRejection - 0.5f, ""}; +using HfCollisionRejectionMask = uint32_t; // 32 bits, in case new ev. selections will be added + +const o2::framework::AxisSpec axisEvents = {EventRejection::NEventRejection, -0.5f, +EventRejection::NEventRejection - 0.5f, ""}; +const o2::framework::AxisSpec axisUpcEvents = {o2::aod::sgselector::DoubleGap + 1, -0.5f, +o2::aod::sgselector::DoubleGap + 0.5f, ""}; /// \brief Function to put labels on monitoring histogram /// \param hRejection monitoring histogram /// \param softwareTriggerLabel bin label for software trigger rejection template -void setEventRejectionLabels(Histo& hRejection, std::string softwareTriggerLabel = "") +void setEventRejectionLabels(Histo& hRejection, std::string const& softwareTriggerLabel = "") { // Puts labels on the collision monitoring histogram. hRejection->GetXaxis()->SetBinLabel(EventRejection::None + 1, "All"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::Rct + 1, "RCT"); 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::UpcEventCut + 1, "UPC event"); 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::NumTracksInTimeRange + 1, "Occupancy"); + 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"); } 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 centralityMin{"centralityMin", -10.f, "Minimum centrality (0 rejects gen. collisions with no reco. collision)"}; + o2::framework::Configurable centralityMax{"centralityMax", 100.f, "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"}; @@ -84,42 +163,116 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { 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 useNumTracksInTimeRange{"useNumTracksInTimeRange", false, "Apply occupancy selection (num. ITS tracks with at least 5 clusters in +-100us from current collision)"}; - o2::framework::Configurable numTracksInTimeRangeMin{"numTracksInTimeRangeMin", 0, "Minimum occupancy"}; - o2::framework::Configurable numTracksInTimeRangeMax{"numTracksInTimeRangeMax", 1000000, "Maximum occupancy"}; + 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 softwareTrigger{"softwareTrigger", "", "Label of software trigger. Multiple triggers can be selected dividing them by a comma"}; + 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", "EventFiltering/Zorro/", "ccdb path for ZORRO objects"}; + o2::framework::ConfigurableAxis th2ConfigAxisCent{"th2ConfigAxisCent", {100, 0., 100.}, ""}; + o2::framework::ConfigurableAxis th2ConfigAxisOccupancy{"th2ConfigAxisOccupancy", {100, 0, 100000}, ""}; + o2::framework::ConfigurableAxis th2ConfigAxisInteractionRate{"th2ConfigAxisInteractionRate", {500, 0, 50000}, ""}; + o2::framework::Configurable requireGoodRct{"requireGoodRct", false, "Flag to require good RCT"}; + o2::framework::Configurable rctLabel{"rctLabel", "CBT_hadronPID", "RCT selection flag (CBT, CBT_hadronPID, CBT_electronPID, CBT_calo, CBT_muon, CBT_muon_glo)"}; + o2::framework::Configurable rctCheckZDC{"rctCheckZDC", false, "RCT flag to check whether the ZDC is present or not"}; + o2::framework::Configurable rctTreatLimitedAcceptanceAsBad{"rctTreatLimitedAcceptanceAsBad", false, "RCT flag to reject events with limited acceptance for selected detectors"}; + o2::framework::Configurable irSource{"irSource", "", "Estimator of the interaction rate (Empty: automatically set. Otherwise recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + // SG selector + SGSelector sgSelector; // 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"; - - std::shared_ptr hCollisions, hSelCollisionsCent, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel; + 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"; + static constexpr char NameHistCollisionsCentIR[] = "hCollisionsCentIR"; + static constexpr char NameHistUpCollisions[] = "hUpCollisions"; + + std::shared_ptr hCollisions, hSelCollisionsCent, hPosZBeforeEvSel, hPosZAfterEvSel, hPosXAfterEvSel, hPosYAfterEvSel, hNumPvContributorsAfterSel, hUpCollisions; + std::shared_ptr hCollisionsCentOcc; + std::shared_ptr hCollisionsCentIR; + + // util to retrieve the RCT info from CCDB + o2::aod::rctsel::RCTFlagsChecker rctChecker; // util to retrieve trigger mask in case of software triggers Zorro zorro; int currentRun{-1}; + // util to retrieve IR + ctpRateFetcher irFetcher; + std::string irSourceForCptFetcher; + + /// Set standard preselection gap trigger (values taken from UD group) + SGCutParHolder setSgPreselection() + { + SGCutParHolder sgCuts; + sgCuts.SetNDtcoll(1); // Minimum number of sigma around the collision + sgCuts.SetMinNBCs(2); // Minimum number of bunch crossings + sgCuts.SetNTracks(2, 1000); // Minimum and maximum number of PV contributors + sgCuts.SetMaxFITtime(34.f); // Maximum FIT time in ns + + // Set FIT amplitudes: FV0, FT0A, FT0C, FDDA, FDDC + sgCuts.SetFITAmpLimits({-1.f, 1000.f, 1000.f, -1.f, -1.f}); + + return sgCuts; + } + /// \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}}}); + 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;number of prim. vtx. contributors;entries", {o2::framework::HistType::kTH1D, {{500, -0.5, 499.5}}}); setEventRejectionLabels(hCollisions, softwareTrigger); + hUpCollisions = registry.add(NameHistUpCollisions, "HF UPC counter;;# of UPC events", {o2::framework::HistType::kTH1D, {axisUpcEvents}}); + const o2::framework::AxisSpec th2AxisCent{th2ConfigAxisCent, "Centrality"}; + const o2::framework::AxisSpec th2AxisOccupancy{th2ConfigAxisOccupancy, "Occupancy"}; + const o2::framework::AxisSpec th2AxisInteractionRate{th2ConfigAxisInteractionRate, "Interaction Rate [Hz]"}; + + hCollisionsCentOcc = registry.add(NameHistCollisionsCentOcc, "selected events;Centrality; Occupancy", {o2::framework::HistType::kTH2D, {th2AxisCent, th2AxisOccupancy}}); + hCollisionsCentIR = registry.add(NameHistCollisionsCentIR, "selected events;Centrality; Interaction Rate [Hz]", {o2::framework::HistType::kTH2D, {th2AxisCent, th2AxisInteractionRate}}); + } + + /// \brief Inits the HF event selection object + /// \param registry reference to the histogram registry + void init(o2::framework::HistogramRegistry& registry, o2::framework::OutputObj& zorroSummary) + { + // we initialise the RCT checker + if (requireGoodRct) { + rctChecker.init(rctLabel.value, rctCheckZDC.value, rctTreatLimitedAcceptanceAsBad.value); + } + + // we initialise the summary object + if (!softwareTrigger.value.empty()) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + // we initialise histograms + addHistograms(registry); + + // we initialise IR fetcher + if (!irSource.value.empty()) { + irSourceForCptFetcher = irSource.value; + } } /// \brief Applies event selection. @@ -130,29 +283,26 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { /// \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) + template + HfCollisionRejectionMask getHfCollisionRejectionMask(TCollision const& 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) { - if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FT0A) { - centrality = collision.centFT0A(); - } else if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FT0C) { - centrality = collision.centFT0C(); - } else if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FT0M) { - centrality = collision.centFT0M(); - } else if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FV0A) { - centrality = collision.centFV0A(); - } else { - LOGP(fatal, "Unsupported centrality estimator!"); - } + HfCollisionRejectionMask rejectionMask{}; + + if constexpr (CentEstimator != o2::hf_centrality::CentralityEstimator::None) { + centrality = o2::hf_centrality::getCentralityColl(collision, CentEstimator); if (centrality < centralityMin || centrality > centralityMax) { SETBIT(rejectionMask, EventRejection::Centrality); } } - if constexpr (useEvSel) { + if constexpr (UseEvSel) { + /// RCT condition + if (requireGoodRct && !rctChecker.checkTable(collision)) { + SETBIT(rejectionMask, EventRejection::Rct); + } /// trigger condition if ((useSel8Trigger && !collision.sel8()) || (!useSel8Trigger && triggerClass > -1 && !collision.alias_bit(triggerClass))) { SETBIT(rejectionMask, EventRejection::Trigger); @@ -178,11 +328,22 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { if (useNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { SETBIT(rejectionMask, EventRejection::NoSameBunchPileup); } - /// occupancy estimator (ITS tracks with at least 5 clusters in +-10us from current collision) - if (useNumTracksInTimeRange) { - const int numTracksInTimeRange = collision.trackOccupancyInTimeRange(); - if (numTracksInTimeRange < numTracksInTimeRangeMin || numTracksInTimeRange > numTracksInTimeRangeMax) { - SETBIT(rejectionMask, EventRejection::NumTracksInTimeRange); + /// 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) { + const auto occupancy = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + if (occupancy < occupancyMin || occupancy > occupancyMax) { + SETBIT(rejectionMask, EventRejection::Occupancy); } } } @@ -202,33 +363,69 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { SETBIT(rejectionMask, EventRejection::PositionZ); } - if (softwareTrigger.value != "") { + if (!softwareTrigger.value.empty()) { // we might have to update it from CCDB - auto bc = collision.template bc_as(); - - int runNumber = bc.runNumber(); + const auto bc = collision.template bc_as(); + const auto 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); - if (!zorro.isSelected(bc.globalBC())) { /// Just let Zorro do the accounting - SETBIT(rejectionMask, EventRejection::SoftwareTrigger); + 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); + } } } return rejectionMask; } + template + HfCollisionRejectionMask getHfCollisionRejectionMaskWithUpc(TCollision const& collision, + float& centrality, + o2::framework::Service const& ccdb, + o2::framework::HistogramRegistry& registry, + TBcs const& bcs) + { + auto rejectionMaskWithUpc = getHfCollisionRejectionMask(collision, centrality, ccdb, registry); + + if (UseEvSel) { + const SGCutParHolder sgCuts = setSgPreselection(); + const auto bc = collision.template foundBC_as(); + const auto bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); + const auto sgSelectionResult = sgSelector.IsSelected(sgCuts, collision, bcRange, bc); + const int upcEventType = sgSelectionResult.value; + if (upcEventType > o2::aod::sgselector::DoubleGap) { + SETBIT(rejectionMaskWithUpc, EventRejection::UpcEventCut); + } else { + hUpCollisions->Fill(upcEventType); + } + } + + return rejectionMaskWithUpc; + } + /// \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) + template + void fillHistograms(TCollision const& collision, + const HfCollisionRejectionMask rejectionMask, + const float centrality, + const float occupancy = -1.f, + const float ir = -1.f) { hCollisions->Fill(EventRejection::None); - const float posZ = collision.posZ(); + const auto posZ = collision.posZ(); hPosZBeforeEvSel->Fill(posZ); for (std::size_t reason = 1; reason < EventRejection::NEventRejection; reason++) { @@ -243,95 +440,152 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { hPosZAfterEvSel->Fill(posZ); hNumPvContributorsAfterSel->Fill(collision.numContrib()); hSelCollisionsCent->Fill(centrality); + hCollisionsCentOcc->Fill(centrality, occupancy); + hCollisionsCentIR->Fill(centrality, ir); + } + + template + double getInteractionRate(TBc const& bc, + o2::framework::Service const& ccdb) + { + if (irSourceForCptFetcher.empty()) { + o2::parameters::GRPLHCIFData* grpo = ccdb.service->getSpecificForRun("GLO/Config/GRPLHCIF", bc.runNumber()); + auto collsys = o2::common::core::CollisionSystemType::getCollisionTypeFromGrp(grpo); + if (collsys == o2::common::core::CollisionSystemType::kCollSyspp) { + irSourceForCptFetcher = std::string("T0VTX"); + } else { + irSourceForCptFetcher = std::string("ZNC hadronic"); + } + } + + return irFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSourceForCptFetcher, true); } }; 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 + 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{-10.f}; // Minimum centrality + float centralityMax{100.f}; // Maximum centrality + bool requireGoodRct{false}; // Apply RCT selection + std::string rctLabel; // RCT selection flag + bool rctCheckZDC{false}; // require ZDC from RCT + bool rctTreatLimitedAcceptanceAsBad{false}; // RCT flag to reject events with limited acceptance for selected detectors + + // util to retrieve the RCT info from CCDB + o2::aod::rctsel::RCTFlagsChecker rctChecker; // histogram names - static constexpr char nameHistParticles[] = "hParticles"; - std::shared_ptr hParticles; + static constexpr char NameHistGenCollisionsCent[] = "hGenCollisionsCent"; + static constexpr char NameHistRecCollisionsCentMc[] = "hRecCollisionsCentMc"; + static constexpr char NameHistNSplitVertices[] = "hNSplitVertices"; + static constexpr char NameHistGenCollisions[] = "hGenCollisions"; + + std::shared_ptr hGenCollisionsCent; + std::shared_ptr hRecCollisionsCentMc; + std::shared_ptr hNSplitVertices; + std::shared_ptr hGenCollisions; /// \brief Adds collision monitoring histograms in the histogram registry. /// \param registry reference to the histogram registry void addHistograms(o2::framework::HistogramRegistry& registry) { - hParticles = registry.add(nameHistParticles, "HF particle counter;;# of accepted particles", {o2::framework::HistType::kTH1D, {axisEvents}}); + 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.}}}); + hGenCollisions = registry.add(NameHistGenCollisions, "HF event counter;;# of accepted collisions", {o2::framework::HistType::kTH1D, {axisEvents}}); // Puts labels on the collision monitoring histogram. - setEventRejectionLabels(hParticles); + setEventRejectionLabels(hGenCollisions); } - void configureFromDevice(const o2::framework::DeviceSpec& device) + /// \brief Configures the object from the reco workflow + /// \param registry reference to the histogram registry + /// \param device device spec to get the configs from the reco workflow + void configureFromDevice(o2::framework::DeviceSpec const& device) { for (const auto& option : device.options) { - if (option.name.compare("hfEvSel.useSel8Trigger") == 0) { + if (option.name == "hfEvSel.useSel8Trigger") { useSel8Trigger = option.defaultValue.get(); - } else if (option.name.compare("hfEvSel.useTvxTrigger") == 0) { + } else if (option.name == "hfEvSel.useTvxTrigger") { useTvxTrigger = option.defaultValue.get(); - } else if (option.name.compare("hfEvSel.useTimeFrameBorderCut") == 0) { + } else if (option.name == "hfEvSel.useTimeFrameBorderCut") { useTimeFrameBorderCut = option.defaultValue.get(); - } else if (option.name.compare("hfEvSel.useItsRofBorderCut") == 0) { + } else if (option.name == "hfEvSel.useItsRofBorderCut") { useItsRofBorderCut = option.defaultValue.get(); - } else if (option.name.compare("hfEvSel.zPvPosMin") == 0) { + } else if (option.name == "hfEvSel.zPvPosMin") { zPvPosMin = option.defaultValue.get(); - } else if (option.name.compare("hfEvSel.zPvPosMax") == 0) { + } else if (option.name == "hfEvSel.zPvPosMax") { zPvPosMax = option.defaultValue.get(); - } else if (option.name.compare("hfEvSel.centralityMin") == 0) { + } else if (option.name == "hfEvSel.centralityMin") { centralityMin = option.defaultValue.get(); - } else if (option.name.compare("hfEvSel.centralityMax") == 0) { + } else if (option.name == "hfEvSel.centralityMax") { centralityMax = option.defaultValue.get(); + } else if (option.name == "hfEvSel.requireGoodRct") { + requireGoodRct = option.defaultValue.get(); + } else if (option.name == "hfEvSel.rctLabel") { + rctLabel = option.defaultValue.get(); + } else if (option.name == "hfEvSel.rctCheckZDC") { + rctCheckZDC = option.defaultValue.get(); + } else if (option.name == "hfEvSel.rctTreatLimitedAcceptanceAsBad") { + rctTreatLimitedAcceptanceAsBad = option.defaultValue.get(); } } } + /// \brief Inits the HF event selection object + /// \param device device spec to get the configs from the reco workflow + /// \param registry reference to the histogram registry + void init(o2::framework::DeviceSpec const& device, + o2::framework::HistogramRegistry& registry) + { + // we get the configuration from the reco workflow + configureFromDevice(device); + + // we initialise the RCT checker + if (requireGoodRct) { + rctChecker.init(rctLabel, rctCheckZDC, rctTreatLimitedAcceptanceAsBad); + } + + // we initialise histograms + addHistograms(registry); + } + /// \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) + template + HfCollisionRejectionMask getHfMcCollisionRejectionMask(TMcCollision const& mcCollision, + TCollisions 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) { - float multiplicity{0.f}; - for (const auto& collision : collSlice) { - float collCent{0.f}; - float collMult{0.f}; - if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FT0A) { - collCent = collision.centFT0A(); - } else if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FT0C) { - collCent = collision.centFT0C(); - } else if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FT0M) { - collCent = collision.centFT0M(); - } else if constexpr (centEstimator == o2::hf_centrality::CentralityEstimator::FV0A) { - collCent = collision.centFV0A(); - } else { - LOGP(fatal, "Unsupported centrality estimator!"); - } - collMult = collision.numContrib(); - if (collMult > multiplicity) { - centrality = collCent; - multiplicity = collMult; - } - } + HfCollisionRejectionMask rejectionMask{}; + const auto zPv = mcCollision.posZ(); + const 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); } } + + /// RCT condition + if (requireGoodRct) { + for (auto const& collision : collSlice) { + if (!rctChecker.checkTable(collision)) { + SETBIT(rejectionMask, EventRejection::Rct); + break; + } + } + } /// 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); @@ -357,16 +611,33 @@ struct HfEventSelectionMc { } /// \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 - void fillHistograms(const uint16_t rejectionMask) + template + void fillHistograms(TMcCollision const& mcCollision, + const HfCollisionRejectionMask rejectionMask, + const int nSplitColl = 0) { - hParticles->Fill(EventRejection::None); + hGenCollisions->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); + hGenCollisions->Fill(reason); + } + + if constexpr (CentEstimator == o2::hf_centrality::CentralityEstimator::FT0M) { + hNSplitVertices->Fill(nSplitColl); + for (int nColl = 0; nColl < nSplitColl; nColl++) { + hRecCollisionsCentMc->Fill(mcCollision.centFT0M()); + } } } }; diff --git a/PWGHF/Utils/utilsMcGen.h b/PWGHF/Utils/utilsMcGen.h new file mode 100644 index 00000000000..18734c1e96a --- /dev/null +++ b/PWGHF/Utils/utilsMcGen.h @@ -0,0 +1,377 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Utils/utilsMcMatching.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include + +#include + +#include +#include +#include +#include + +namespace hf_mc_gen +{ + +template +void fillMcMatchGen2Prong(TMcParticles const& mcParticles, + TMcParticlesPerColl const& mcParticlesPerMcColl, + TCursor& rowMcMatchGen, + const bool rejectBackground, + const bool matchCorrelatedBackground) +{ + using namespace o2::constants::physics; + using namespace o2::hf_decay::hf_cand_2prong; + + constexpr std::size_t NDaughtersResonant{2u}; + + // Match generated particles. + for (const auto& particle : mcParticlesPerMcColl) { + int8_t flagChannelMain = 0; + int8_t flagChannelResonant = 0; + int8_t origin = 0; + int8_t sign = 0; + std::vector idxBhadMothers{}; + // Reject particles from background events + if (particle.fromBackgroundEvent() && rejectBackground) { + rowMcMatchGen(flagChannelMain, origin, flagChannelResonant, -1); + continue; + } + if (matchCorrelatedBackground) { + constexpr int DepthMainMax = 2; // Depth for final state matching + constexpr int DepthResoMax = 1; // Depth for resonant decay matching + bool matched = false; + + // TODO: J/ψ + for (const auto& [channelMain, finalState] : daughtersD0Main) { + if (finalState.size() == 3) { // o2-linter: disable=magic-number (partially reconstructed 3-prong decays) + std::array arrPdgDaughtersMain3Prongs = std::array{finalState[0], finalState[1], finalState[2]}; + o2::hf_decay::flipPdgSign(particle.pdgCode(), +kPi0, arrPdgDaughtersMain3Prongs); + matched = RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kD0, arrPdgDaughtersMain3Prongs, true, &sign, DepthMainMax); + } else if (finalState.size() == 2) { // o2-linter: disable=magic-number (fully reconstructed 2-prong decays) + std::array arrPdgDaughtersMain2Prongs = std::array{finalState[0], finalState[1]}; + matched = RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kD0, arrPdgDaughtersMain2Prongs, true, &sign, DepthMainMax); + } else { + LOG(fatal) << "Final state size not supported: " << finalState.size(); + return; + } + if (matched) { + flagChannelMain = sign * channelMain; + + // Flag the resonant decay channel + std::vector arrResoDaughIndex = {}; + RecoDecay::getDaughters(particle, &arrResoDaughIndex, std::array{0}, DepthResoMax); + std::array arrPdgDaughters = {}; + if (arrResoDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < arrResoDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrResoDaughIndex[iProng]); + arrPdgDaughters[iProng] = daughI.pdgCode(); + } + flagChannelResonant = o2::hf_decay::getDecayChannelResonant(Pdg::kD0, arrPdgDaughters); + } + break; + } + } + } else { + // D0(bar) → π± K∓ + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign)) { + flagChannelMain = sign * DecayChannelMain::D0ToPiK; + } + + // J/ψ → e+ e− + if (flagChannelMain == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kJPsi, std::array{+kElectron, -kElectron}, true)) { + flagChannelMain = DecayChannelMain::JpsiToEE; + } + } + + // J/ψ → μ+ μ− + if (flagChannelMain == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kJPsi, std::array{+kMuonPlus, -kMuonPlus}, true)) { + flagChannelMain = DecayChannelMain::JpsiToMuMu; + } + } + } + + // Check whether the particle is non-prompt (from a b quark). + if (flagChannelMain != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMcMatchGen(flagChannelMain, origin, flagChannelResonant, idxBhadMothers[0]); + } else { + rowMcMatchGen(flagChannelMain, origin, flagChannelResonant, -1); + } + } +} + +template +void fillMcMatchGen3Prong(TMcParticles const& mcParticles, + TMcParticlesPerColl const& mcParticlesPerMcColl, + TCursor& rowMcMatchGen, + const bool rejectBackground, + std::vector const& pdgMothersCorrelBkg = {}) +{ + using namespace o2::constants::physics; + using namespace o2::hf_decay::hf_cand_3prong; + + constexpr std::size_t NDaughtersResonant{2u}; + + // Match generated particles. + for (const auto& particle : mcParticlesPerMcColl) { + int8_t flagChannelMain = 0; + int8_t flagChannelResonant = 0; + int8_t origin = 0; + int8_t sign = 0; + std::vector arrDaughIndex; + std::vector idxBhadMothers{}; + std::array arrPdgDaugResonant{}; + const std::array arrPdgDaugResonantLcToPKstar0{daughtersLcResonant.at(DecayChannelResonant::LcToPKstar0)}; // Λc± → p± K* + const std::array arrPdgDaugResonantLcToDeltaplusplusK{daughtersLcResonant.at(DecayChannelResonant::LcToDeltaplusplusK)}; // Λc± → Δ(1232)±± K∓ + const std::array arrPdgDaugResonantLcToL1520Pi{daughtersLcResonant.at(DecayChannelResonant::LcToL1520Pi)}; // Λc± → Λ(1520) π± + const std::array arrPdgDaugResonantDToPhiPi{daughtersDsResonant.at(DecayChannelResonant::DsToPhiPi)}; // Ds± → φ π± and D± → φ π± + const std::array arrPdgDaugResonantDToKstar0K{daughtersDsResonant.at(DecayChannelResonant::DsToKstar0K)}; // Ds± → anti-K*(892)0 K± and D± → anti-K*(892)0 K± + + // Reject particles from background events + if (particle.fromBackgroundEvent() && rejectBackground) { + rowMcMatchGen(flagChannelMain, origin, flagChannelResonant, -1); + continue; + } + + if (!pdgMothersCorrelBkg.empty()) { + for (const auto& pdgMother : pdgMothersCorrelBkg) { + if (std::abs(particle.pdgCode()) != pdgMother) { + continue; // Skip if the particle PDG code does not match the mother PDG code + } + const auto finalStates = getDecayChannelsMain(pdgMother); + constexpr int DepthMainMax = 2; // Depth for final state matching + constexpr int DepthResoMax = 1; // Depth for resonant decay matching + + int depthMainMax = DepthMainMax; + bool matched = false; + if (pdgMother == Pdg::kDStar) { + depthMainMax = DepthMainMax + 1; // D0 resonant decays are switched on + } + + std::vector arrAllDaughtersIndex; + for (const auto& [channelMain, finalState] : finalStates) { + if (finalState.size() == 5) { // o2-linter: disable=magic-number (partially reconstructed 3-prong decays from 5-prong decays) + std::array arrPdgDaughtersMain5Prongs = std::array{finalState[0], finalState[1], finalState[2], finalState[3], finalState[4]}; + o2::hf_decay::flipPdgSign(particle.pdgCode(), +kPi0, arrPdgDaughtersMain5Prongs); + RecoDecay::getDaughters(particle, &arrAllDaughtersIndex, arrPdgDaughtersMain5Prongs, depthMainMax); + matched = RecoDecay::isMatchedMCGen(mcParticles, particle, pdgMother, arrPdgDaughtersMain5Prongs, true, &sign, -1); + } else if (finalState.size() == 4) { // o2-linter: disable=magic-number (partially reconstructed 3-prong decays from 4-prong decays) + std::array arrPdgDaughtersMain4Prongs = std::array{finalState[0], finalState[1], finalState[2], finalState[3]}; + o2::hf_decay::flipPdgSign(particle.pdgCode(), +kPi0, arrPdgDaughtersMain4Prongs); + RecoDecay::getDaughters(particle, &arrAllDaughtersIndex, arrPdgDaughtersMain4Prongs, depthMainMax); + matched = RecoDecay::isMatchedMCGen(mcParticles, particle, pdgMother, arrPdgDaughtersMain4Prongs, true, &sign, -1); + } else if (finalState.size() == 3) { // o2-linter: disable=magic-number (fully reconstructed 3-prong decays) + std::array arrPdgDaughtersMain3Prongs = std::array{finalState[0], finalState[1], finalState[2]}; + RecoDecay::getDaughters(particle, &arrAllDaughtersIndex, arrPdgDaughtersMain3Prongs, depthMainMax); + matched = RecoDecay::isMatchedMCGen(mcParticles, particle, pdgMother, arrPdgDaughtersMain3Prongs, true, &sign, depthMainMax); + } else { + LOG(fatal) << "Final state size not supported: " << finalState.size(); + return; + } + if (matched) { + flagChannelMain = sign * channelMain; + // Flag the resonant decay channel + std::vector arrResoDaughIndex = {}; + if (std::abs(pdgMother) == Pdg::kDStar) { + std::vector arrResoDaughIndexDStar = {}; + RecoDecay::getDaughters(particle, &arrResoDaughIndexDStar, std::array{0}, DepthResoMax); + for (const int iDaug : arrResoDaughIndexDStar) { + auto daughDstar = mcParticles.rawIteratorAt(iDaug); + if (std::abs(daughDstar.pdgCode()) == Pdg::kD0 || std::abs(daughDstar.pdgCode()) == Pdg::kDPlus) { + RecoDecay::getDaughters(daughDstar, &arrResoDaughIndex, std::array{0}, DepthResoMax); + break; + } + } + } else { + RecoDecay::getDaughters(particle, &arrResoDaughIndex, std::array{0}, DepthResoMax); + } + std::array arrPdgDaughters = {}; + if (arrResoDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < NDaughtersResonant; ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrResoDaughIndex[iProng]); + arrPdgDaughters[iProng] = daughI.pdgCode(); + } + flagChannelResonant = o2::hf_decay::getDecayChannelResonant(pdgMother, arrPdgDaughters); + } + break; // Exit loop if a match is found + } + } + if (matched) { + break; // Exit loop if a match is found + } + } + } else { + + // D± → π± K∓ π± + if (flagChannelMain == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDPlus, std::array{+kPiPlus, -kKPlus, +kPiPlus}, true, &sign, 2)) { + flagChannelMain = sign * DecayChannelMain::DplusToPiKPi; + } + } + + // Ds± → K± K∓ π± and D± → K± K∓ π± + if (flagChannelMain == 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 + flagChannelMain = sign * DecayChannelMain::DsToPiKK; + } 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 + flagChannelMain = sign * DecayChannelMain::DplusToPiKK; + isDplus = true; + } + if (flagChannelMain != 0) { + RecoDecay::getDaughters(particle, &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < arrDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrDaughIndex[iProng]); + arrPdgDaugResonant[iProng] = std::abs(daughI.pdgCode()); + } + if ((arrPdgDaugResonant[0] == arrPdgDaugResonantDToPhiPi[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantDToPhiPi[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantDToPhiPi[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantDToPhiPi[0])) { + flagChannelResonant = isDplus ? DecayChannelResonant::DplusToPhiPi : DecayChannelResonant::DsToPhiPi; + } else if ((arrPdgDaugResonant[0] == arrPdgDaugResonantDToKstar0K[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantDToKstar0K[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantDToKstar0K[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantDToKstar0K[0])) { + flagChannelResonant = isDplus ? DecayChannelResonant::DplusToKstar0K : DecayChannelResonant::DsToKstar0K; + } + } + } + } + + // D*± → D0(bar) π± + if (flagChannelMain == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kDStar, std::array{+kPiPlus, +kPiPlus, -kKPlus}, true, &sign, 2)) { + flagChannelMain = sign * DecayChannelMain::DstarToPiKPi; + } + } + + // Λc± → p± K∓ π± + if (flagChannelMain == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + flagChannelMain = sign * DecayChannelMain::LcToPKPi; + + // Flagging the different Λc± → p± K∓ π± decay channels + RecoDecay::getDaughters(particle, &arrDaughIndex, std::array{0}, 1); + if (arrDaughIndex.size() == NDaughtersResonant) { + for (auto iProng = 0u; iProng < arrDaughIndex.size(); ++iProng) { + auto daughI = mcParticles.rawIteratorAt(arrDaughIndex[iProng]); + arrPdgDaugResonant[iProng] = std::abs(daughI.pdgCode()); + } + if ((arrPdgDaugResonant[0] == arrPdgDaugResonantLcToPKstar0[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToPKstar0[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantLcToPKstar0[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToPKstar0[0])) { + flagChannelResonant = DecayChannelResonant::LcToPKstar0; + } else if ((arrPdgDaugResonant[0] == arrPdgDaugResonantLcToDeltaplusplusK[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToDeltaplusplusK[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantLcToDeltaplusplusK[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToDeltaplusplusK[0])) { + flagChannelResonant = DecayChannelResonant::LcToDeltaplusplusK; + } else if ((arrPdgDaugResonant[0] == arrPdgDaugResonantLcToL1520Pi[0] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToL1520Pi[1]) || (arrPdgDaugResonant[0] == arrPdgDaugResonantLcToL1520Pi[1] && arrPdgDaugResonant[1] == arrPdgDaugResonantLcToL1520Pi[0])) { + flagChannelResonant = DecayChannelResonant::LcToL1520Pi; + } + } + } + } + + // Ξc± → p± K∓ π± + if (flagChannelMain == 0) { + if (RecoDecay::isMatchedMCGen(mcParticles, particle, Pdg::kXiCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + flagChannelMain = sign * DecayChannelMain::XicToPKPi; + } + } + } + + // Check whether the particle is non-prompt (from a b quark). + if (flagChannelMain != 0) { + origin = RecoDecay::getCharmHadronOrigin(mcParticles, particle, false, &idxBhadMothers); + } + if (origin == RecoDecay::OriginType::NonPrompt) { + rowMcMatchGen(flagChannelMain, origin, flagChannelResonant, idxBhadMothers[0]); + } else { + rowMcMatchGen(flagChannelMain, origin, flagChannelResonant, -1); + } + } +} + +template +void fillMcMatchGenBplus(TMcParticles const& mcParticles, TCursor& rowMcMatchGen) +{ + using namespace o2::constants::physics; + using namespace o2::hf_decay::hf_cand_beauty; + + // Match generated particles. + for (const auto& particle : mcParticles) { + int8_t flagChannelMain = 0; + int8_t flagChannelReso = 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) { + flagChannelMain = signB * DecayChannelMain::BplusToD0Pi; + } + } + rowMcMatchGen(flagChannelMain, flagChannelReso, origin); + } // B candidate +} + +template +void fillMcMatchGenB0(TMcParticles const& mcParticles, TCursor& rowMcMatchGen) +{ + using namespace o2::constants::physics; + using namespace o2::hf_decay::hf_cand_beauty; + + // Match generated particles. + for (const auto& particle : mcParticles) { + int8_t flagChannelMain = 0; + int8_t flagChannelReso = 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)) { + flagChannelMain = sign * DecayChannelMain::B0ToDminusPi; + } + } + rowMcMatchGen(flagChannelMain, flagChannelReso, origin); + } // gen +} + +} // namespace hf_mc_gen + +#endif // PWGHF_UTILS_UTILSMCGEN_H_ diff --git a/PWGHF/Utils/utilsMcMatching.h b/PWGHF/Utils/utilsMcMatching.h new file mode 100644 index 00000000000..097c13a901e --- /dev/null +++ b/PWGHF/Utils/utilsMcMatching.h @@ -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 utilsMcMatching.h +/// \brief Mapping of MC flags contained in DecayChannels.h +/// \author Marcello Di Costanzo , Polytechnic University of Turin and INFN + +#ifndef PWGHF_UTILS_UTILSMCMATCHING_H_ +#define PWGHF_UTILS_UTILSMCMATCHING_H_ + +#include "PWGHF/Core/DecayChannels.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace o2::hf_decay +{ + +namespace hf_cand_2prong +{ + +// D0 + +static const std::unordered_map> daughtersD0Main{ + {DecayChannelMain::D0ToPiK, {+PDG_t::kKMinus, +PDG_t::kPiPlus}}, + {DecayChannelMain::D0ToPiKPi0, {+PDG_t::kKMinus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, + {DecayChannelMain::D0ToPiPi, {+PDG_t::kPiMinus, +PDG_t::kPiPlus}}, + {DecayChannelMain::D0ToPiPiPi0, {+PDG_t::kPiMinus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, + {DecayChannelMain::D0ToKK, {+PDG_t::kKMinus, +PDG_t::kKPlus}}, +}; + +static const std::unordered_map> daughtersD0Resonant{ + {DecayChannelResonant::D0ToRhoplusPi, {+PDG_t::kRho770Plus, +PDG_t::kPiMinus}}, + {DecayChannelResonant::D0ToRhoplusK, {+PDG_t::kRho770Plus, +PDG_t::kKMinus}}, + {DecayChannelResonant::D0ToKstar0Pi0, {-o2::constants::physics::Pdg::kK0Star892, +PDG_t::kPi0}}, + {DecayChannelResonant::D0ToKstarPi, {-o2::constants::physics::Pdg::kKPlusStar892, +PDG_t::kPiPlus}}, +}; + +// J/ψ + +static const std::unordered_map> daughtersJpsiMain{ + {DecayChannelMain::JpsiToEE, {+PDG_t::kElectron, +PDG_t::kPositron}}, + {DecayChannelMain::JpsiToMuMu, {+PDG_t::kMuonMinus, +PDG_t::kMuonPlus}}, +}; +} // namespace hf_cand_2prong + +namespace hf_cand_3prong +{ + +// D± + +static const std::unordered_map> daughtersDplusMain{ + {DecayChannelMain::DplusToPiKPi, {+PDG_t::kKMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus}}, + {DecayChannelMain::DplusToPiKK, {+PDG_t::kKMinus, +PDG_t::kKPlus, +PDG_t::kPiPlus}}, + {DecayChannelMain::DplusToPiKPiPi0, {+PDG_t::kKMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, + {DecayChannelMain::DplusToPiPiPi, {+PDG_t::kPiMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus}}, +}; + +static const std::unordered_map> daughtersDplusResonant{ + {DecayChannelResonant::DplusToPhiPi, {+o2::constants::physics::Pdg::kPhi, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DplusToKstar0K, {-o2::constants::physics::Pdg::kK0Star892, +PDG_t::kKPlus}}, + {DecayChannelResonant::DplusToKstar1430_0K, {-10311, +PDG_t::kKPlus}}, + {DecayChannelResonant::DplusToRho0Pi, {+PDG_t::kRho770_0, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DplusToF2_1270Pi, {+225, +PDG_t::kPiPlus}}, +}; + +// Ds± + +static const std::unordered_map> daughtersDsMain{ + {DecayChannelMain::DsToPiKK, {+PDG_t::kKMinus, +PDG_t::kKPlus, +PDG_t::kPiPlus}}, + {DecayChannelMain::DsToPiKKPi0, {+PDG_t::kKMinus, +PDG_t::kKPlus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, + {DecayChannelMain::DsToPiPiK, {+PDG_t::kKPlus, +PDG_t::kPiPlus, +PDG_t::kPiMinus}}, + {DecayChannelMain::DsToPiPiPi, {+PDG_t::kPiMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus}}, + {DecayChannelMain::DsToPiPiPiPi0, {+PDG_t::kPiMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, +}; + +static const std::unordered_map> daughtersDsResonant{ + {DecayChannelResonant::DsToPhiPi, {+o2::constants::physics::Pdg::kPhi, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DsToPhiRhoplus, {+o2::constants::physics::Pdg::kPhi, +PDG_t::kRho770Plus}}, + {DecayChannelResonant::DsToKstar0K, {-o2::constants::physics::Pdg::kK0Star892, +PDG_t::kKPlus}}, + {DecayChannelResonant::DsToKstar0Pi, {+o2::constants::physics::Pdg::kK0Star892, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DsToRho0Pi, {+PDG_t::kRho770_0, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DsToRho0K, {+PDG_t::kRho770_0, +PDG_t::kKPlus}}, + {DecayChannelResonant::DsToF2_1270Pi, {225, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DsToF0_1370K, {10221, +PDG_t::kKPlus}}, + {DecayChannelResonant::DsToEtaPi, {221, +PDG_t::kPiPlus}}, +}; + +// D*+ + +static const std::unordered_map> daughtersDstarMain{ + {DecayChannelMain::DstarToPiKPi, {+PDG_t::kKMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus}}, + {DecayChannelMain::DstarToPiKPiPi0, {+PDG_t::kKMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, + {DecayChannelMain::DstarToPiKPiPi0Pi0, {+PDG_t::kKMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus, +PDG_t::kPi0, +PDG_t::kPi0}}, + {DecayChannelMain::DstarToPiKK, {+PDG_t::kKMinus, +PDG_t::kKPlus, +PDG_t::kPiPlus}}, + {DecayChannelMain::DstarToPiKKPi0, {+PDG_t::kKMinus, +PDG_t::kKPlus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, + {DecayChannelMain::DstarToPiPiPi, {+PDG_t::kPiMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus}}, + {DecayChannelMain::DstarToPiPiPiPi0, {+PDG_t::kPiMinus, +PDG_t::kPiPlus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, +}; + +static const std::unordered_map> daughtersDstarResonant{ + {DecayChannelResonant::DstarToD0ToRhoplusPi, {+PDG_t::kRho770Plus, +PDG_t::kPiMinus}}, + {DecayChannelResonant::DstarToD0ToRhoplusK, {+PDG_t::kRho770Plus, +PDG_t::kKMinus}}, + {DecayChannelResonant::DstarToD0ToKstar0Pi0, {-o2::constants::physics::Pdg::kK0Star892, +PDG_t::kPi0}}, + {DecayChannelResonant::DstarToD0ToKstarPi, {-o2::constants::physics::Pdg::kKPlusStar892, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DstarToDplusToPhiPi, {+o2::constants::physics::Pdg::kPhi, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DstarToDplusToKstar0K, {-o2::constants::physics::Pdg::kK0Star892, +PDG_t::kKPlus}}, + {DecayChannelResonant::DstarToDplusToKstar1430_0K, {-10311, +PDG_t::kKPlus}}, + {DecayChannelResonant::DstarToDplusToRho0Pi, {+PDG_t::kRho770_0, +PDG_t::kPiPlus}}, + {DecayChannelResonant::DstarToDplusToF2_1270Pi, {+225, +PDG_t::kPiPlus}}, +}; + +// Λc+ + +static const std::unordered_map> daughtersLcMain{ + {DecayChannelMain::LcToPKPi, {+PDG_t::kProton, +PDG_t::kKMinus, +PDG_t::kPiPlus}}, + {DecayChannelMain::LcToPKPiPi0, {+PDG_t::kProton, +PDG_t::kKMinus, +PDG_t::kPiPlus, +PDG_t::kPi0}}, + {DecayChannelMain::LcToPPiPi, {+PDG_t::kProton, +PDG_t::kPiMinus, +PDG_t::kPiPlus}}, + {DecayChannelMain::LcToPKK, {+PDG_t::kProton, +PDG_t::kKMinus, +PDG_t::kKPlus}}}; + +static const std::unordered_map> daughtersLcResonant{ + {DecayChannelResonant::LcToPKstar0, {-o2::constants::physics::Pdg::kK0Star892, +PDG_t::kProton}}, + {DecayChannelResonant::LcToDeltaplusplusK, {+2224, +PDG_t::kKMinus}}, + {DecayChannelResonant::LcToL1520Pi, {+102134, +PDG_t::kPiPlus}}, + {DecayChannelResonant::LcToPPhi, {+PDG_t::kProton, +o2::constants::physics::Pdg::kPhi}}, +}; + +// Ξc+ + +static const std::unordered_map> daughtersXicMain{ + {DecayChannelMain::XicToPKPi, {+PDG_t::kProton, +PDG_t::kKMinus, +PDG_t::kPiPlus}}, + {DecayChannelMain::XicToPKK, {+PDG_t::kProton, +PDG_t::kKMinus, +PDG_t::kKPlus}}, + {DecayChannelMain::XicToSPiPi, {+PDG_t::kSigmaPlus, +PDG_t::kPiMinus, +PDG_t::kPiPlus}}, +}; + +static const std::unordered_map> daughtersXicResonant{ + {DecayChannelResonant::XicToPKstar0, {-o2::constants::physics::Pdg::kK0Star892, +PDG_t::kProton}}, + {DecayChannelResonant::XicToPPhi, {+PDG_t::kProton, +o2::constants::physics::Pdg::kPhi}}, +}; + +/// Returns a map of the possible final states for a specific 3-prong particle specie +/// \param pdgMother PDG code of the mother particle +/// \return a map of final states with their corresponding PDG codes +inline std::unordered_map> getDecayChannelsMain(int pdgMother) +{ + switch (pdgMother) { + case o2::constants::physics::Pdg::kDPlus: + return daughtersDplusMain; + case o2::constants::physics::Pdg::kDS: + return daughtersDsMain; + case o2::constants::physics::Pdg::kDStar: + return daughtersDstarMain; + case o2::constants::physics::Pdg::kLambdaCPlus: + return daughtersLcMain; + case o2::constants::physics::Pdg::kXiCPlus: + return daughtersXicMain; + default: + LOG(fatal) << "Unknown PDG code for 3-prong final states: " << pdgMother; + return {}; + } +} +} // namespace hf_cand_3prong + +namespace hf_cand_reso +{ +const std::unordered_map particlesToDstarK0s = { + {DecayChannelMain::Ds1ToDstarK0s, constants::physics::Pdg::kDS1}, + {DecayChannelMain::Ds2starToDstarK0s, constants::physics::Pdg::kDS2Star}, + {DecayChannelMain::Ds1star2700ToDstarK0s, constants::physics::Pdg::kDS1Star2700}, + {DecayChannelMain::Ds1star2860ToDstarK0s, constants::physics::Pdg::kDS1Star2860}, + {DecayChannelMain::Ds3star2860ToDstarK0s, constants::physics::Pdg::kDS3Star2860}}; +const std::unordered_map particlesToDplusK0s = { + {DecayChannelMain::Ds2starToDplusK0s, constants::physics::Pdg::kDS2Star}}; +const std::unordered_map particlesToDplusLambda = { + {DecayChannelMain::Xic3055plusToDplusLambda, constants::physics::Pdg::kXiC3055Plus}, + {DecayChannelMain::Xic3080plusToDplusLambda, constants::physics::Pdg::kXiC3080Plus}}; +const std::unordered_map particlesToD0Lambda = { + {DecayChannelMain::Xic3055zeroToD0Lambda, constants::physics::Pdg::kXiC3055_0}, + {DecayChannelMain::Xic3080zeroToD0Lambda, constants::physics::Pdg::kXiC3080_0}}; +const std::unordered_map particlesToDstarPi = { + {DecayChannelMain::D1zeroToDstarPi, constants::physics::Pdg::kD10}, + {DecayChannelMain::D2starzeroToDstarPi, constants::physics::Pdg::kD2Star0}}; +const std::unordered_map particlesToDplusPi = { + {DecayChannelMain::D2starzeroToDplusPi, constants::physics::Pdg::kD2Star0}}; +const std::unordered_map particlesToD0Pi = { + {DecayChannelMain::D2starplusToD0Pi, constants::physics::Pdg::kD2StarPlus}, + {DecayChannelMain::DstarToD0Pi, constants::physics::Pdg::kDStar}}; +const std::unordered_map particlesToD0Kplus = { + {DecayChannelMain::Ds2starToD0Kplus, constants::physics::Pdg::kDS2Star}}; + +enum PartialMatchMc : uint8_t { + D0Matched = 0, + DstarMatched, + DplusMatched, + K0Matched, + LambdaMatched, + PionMatched, + KaonMatched, + ProtonMatched, + ResoPartlyMatched +}; +} // namespace hf_cand_reso + +/// Compare an array of PDG codes with an expected array +/// \tparam N size of the arrays to be compared +/// \param arrPdgTested array of PDG codes to be tested +/// \param arrPdgExpected array of the expected PDG codes +/// \return true if the arrays are equal, false otherwise +template +inline bool areSamePdgArrays(std::array const& arrPdgTested, std::array arrPdgExpected) +{ + for (std::size_t i = 0; i < N; i++) { + bool foundPdg = false; + for (std::size_t j = 0; j < N; j++) { + if (std::abs(arrPdgTested[i]) == std::abs(arrPdgExpected[j])) { + arrPdgExpected[j] = -1; // Mark as found + foundPdg = true; + break; + } + } + if (!foundPdg) { + return false; + } + } + return true; +} + +/// Flag the resonant decay channel +/// \tparam N size of the array of daughter PDG codes +/// \param pdgMother PDG code of the mother particle +/// \param arrPdgDaughters array of daughter PDG codes +/// \return the channel for the matched resonant decay channel +template +inline int8_t getDecayChannelResonant(const int pdgMother, std::array const& arrPdgDaughters) +{ + switch (pdgMother) { + case o2::constants::physics::Pdg::kD0: + for (const auto& [channelResonant, arrPdgDaughtersResonant] : hf_cand_2prong::daughtersD0Resonant) { + if (areSamePdgArrays(arrPdgDaughters, arrPdgDaughtersResonant)) { + return channelResonant; + } + } + break; + case o2::constants::physics::Pdg::kDPlus: + for (const auto& [channelResonant, arrPdgDaughtersResonant] : hf_cand_3prong::daughtersDplusResonant) { + if (areSamePdgArrays(arrPdgDaughters, arrPdgDaughtersResonant)) { + return channelResonant; + } + } + break; + case o2::constants::physics::Pdg::kDS: + for (const auto& [channelResonant, arrPdgDaughtersResonant] : hf_cand_3prong::daughtersDsResonant) { + if (areSamePdgArrays(arrPdgDaughters, arrPdgDaughtersResonant)) { + return channelResonant; + } + } + break; + case o2::constants::physics::Pdg::kDStar: + for (const auto& [channelResonant, arrPdgDaughtersResonant] : hf_cand_3prong::daughtersDstarResonant) { + if (areSamePdgArrays(arrPdgDaughters, arrPdgDaughtersResonant)) { + return channelResonant; + } + } + break; + case o2::constants::physics::Pdg::kLambdaCPlus: + for (const auto& [channelResonant, arrPdgDaughtersResonant] : hf_cand_3prong::daughtersLcResonant) { + if (areSamePdgArrays(arrPdgDaughters, arrPdgDaughtersResonant)) { + return channelResonant; + } + } + break; + case o2::constants::physics::Pdg::kXiCPlus: + for (const auto& [channelResonant, arrPdgDaughtersResonant] : hf_cand_3prong::daughtersXicResonant) { + if (areSamePdgArrays(arrPdgDaughters, arrPdgDaughtersResonant)) { + return channelResonant; + } + } + break; + default: + LOG(fatal) << "Unknown PDG code for 3-prong final states: " << pdgMother; + return -1; + } + return 0; +} + +/// Flip the sign of a specific PDG code in an array +/// of PDG codes associated to an antiparticle. +/// \tparam N size of the array of PDG codes +/// \param pdgMother PDG code of the mother particle +/// \param pdgToFlip PDG code to be flipped +/// \param arrPdg array of PDG codes to be modified +template +inline void flipPdgSign(const int pdgMother, const int pdgToFlip, std::array& arrPdg) +{ + if (pdgMother >= 0) { + return; + } + for (auto& pdg : arrPdg) { // o2-linter: disable=const-ref-in-for-loop (arrPdg entries are modified) + if (pdg == pdgToFlip) { + pdg = -pdg; + } + } +} +} // namespace o2::hf_decay + +#endif // PWGHF_UTILS_UTILSMCMATCHING_H_ diff --git a/PWGHF/Utils/utilsPid.h b/PWGHF/Utils/utilsPid.h new file mode 100644 index 00000000000..fc1d0d18940 --- /dev/null +++ b/PWGHF/Utils/utilsPid.h @@ -0,0 +1,129 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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_ + +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include + +#include + +namespace o2::aod::pid_tpc_tof_utils +{ +/// @brief Species of HF-candidate daughter tracks +enum HfProngSpecies : uint8_t { + Pion = 0, + Kaon, + Proton, + Deuteron, + NHfProngSpecies +}; + +/// @brief PID methods used for HF-candidate daughter tracks +enum PidMethod { + NoPid = 0, // none + TpcOrTof, // TPC or TOF + TpcAndTof, // TPC and TOF + NPidMethods +}; + +/// Function to combine TPC and TOF nSigma +/// \tparam Tiny switch between full and tiny (binned) PID tables +/// \param nSigmaTpc is the (binned) nSigma separation in TPC (if Tiny = true) +/// \param nSigmaTof is the (binned) nSigma separation in TOF (if Tiny = true) +/// \return combined nSigma of TPC and TOF +template +TNumber combineNSigma(TNumber nSigmaTpc, TNumber nSigmaTof) +{ + 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 + + if constexpr (Tiny) { + nSigmaTpc *= aod::pidtpc_tiny::binning::bin_width; + nSigmaTof *= aod::pidtof_tiny::binning::bin_width; + } + + if ((nSigmaTpc > NSigmaDefault) && (nSigmaTof > NSigmaDefault)) { // TPC and TOF + return std::sqrt(.5f * (nSigmaTpc * nSigmaTpc + nSigmaTof * nSigmaTof)); + } + if (nSigmaTpc > NSigmaDefault) { // only TPC + return std::abs(nSigmaTpc); + } + if (nSigmaTof > NSigmaDefault) { // only TOF + return std::abs(nSigmaTof); + } + return nSigmaTof; // no TPC nor TOF +} + +/// \brief Function to fill tables with HF prong PID information +/// \tparam specPid particle species +/// \tparam TTrack datatype of the prong track +/// \tparam TCursor datatype of the cursor of the prong PID table to fill +/// \param track prong track +/// \param rowPid cursor of the prong PID table to fill +template +void fillProngPid(TTrack const& track, TCursor& 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 if constexpr (SpecPid == HfProngSpecies::Deuteron) { + // deuteron PID + if (track.hasTPC()) { + nSigTpc = track.tpcNSigmaDe(); + } + if (track.hasTOF()) { + nSigTof = track.tofNSigmaDe(); + } + } else { + LOG(fatal) << "Unsupported PID. Supported species in HF framework: HfProngSpecies::Pion, HfProngSpecies::Kaon, HfProngSpecies::Proton, HfProngSpecies::Deuteron"; + } + + // 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..20167cb82eb 100644 --- a/PWGHF/Utils/utilsTrkCandHf.h +++ b/PWGHF/Utils/utilsTrkCandHf.h @@ -16,7 +16,14 @@ #ifndef PWGHF_UTILS_UTILSTRKCANDHF_H_ #define PWGHF_UTILS_UTILSTRKCANDHF_H_ -#include "Framework/HistogramSpec.h" +#include "PWGHF/Utils/utilsAnalysis.h" + +#include + +#include + +#include +#include namespace o2::hf_trkcandsel { @@ -28,12 +35,12 @@ enum SVFitting { NCases }; -o2::framework::AxisSpec axisCands = {SVFitting::NCases, -0.5f, static_cast(SVFitting::NCases) - 0.5f, ""}; +const o2::framework::AxisSpec axisCands = {SVFitting::NCases, -0.5f, static_cast(SVFitting::NCases) - 0.5f, ""}; -/// @brief Function to put labels on candidate monitoring histogram +/// \brief Function to put labels on candidate monitoring histogram /// \param hCandidates is the histogram -template -void setLabelHistoCands(Histo& hCandidates) +template +void setLabelHistoCands(THisto& hCandidates) { hCandidates->SetTitle("HF candidate counter;;candidates"); hCandidates->GetXaxis()->SetBinLabel(SVFitting::BeforeFit + 1, "Before secondary vertexing"); @@ -41,6 +48,44 @@ 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 +inline int countOnesInBinary(const uint8_t num) +{ + int count{0}; + constexpr std::size_t NBits{8u}; + for (std::size_t iBit{0u}; iBit < NBits; iBit++) { + count += TESTBIT(num, iBit); + } + return count; +} + +/// Single-track cuts on dcaXY +/// \param trackPar is the track parametrisation +/// \param dca is the 2-D array with track DCAs +/// \param binsPtTrack is the array of pt bins for track selection +/// \param cutsTrackDCA are the cuts for track DCA selection +/// \return true if track passes all cuts +template +bool isSelectedTrackDCA(TTrackPar const& trackPar, + TArrayDca const& dca, + TArrayPt const& binsPtTrack, + TArrayCuts const& cutsTrackDCA) +{ + const auto binPtTrack = o2::analysis::findBin(binsPtTrack, trackPar.getPt()); + if (binPtTrack == -1) { + return false; + } + + if (std::abs(dca[0]) < cutsTrackDCA->get(binPtTrack, "min_dcaxytoprimary")) { + return false; // minimum DCAxy + } + if (std::abs(dca[0]) > cutsTrackDCA->get(binPtTrack, "max_dcaxytoprimary")) { + return false; // maximum DCAxy + } + return true; +} + } // namespace o2::hf_trkcandsel #endif // PWGHF_UTILS_UTILSTRKCANDHF_H_ diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h new file mode 100644 index 00000000000..436afc34710 --- /dev/null +++ b/PWGHF/Utils/utilsUpcHf.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. + +/// \file utilsUpcHf.h +/// \brief Utility functions for Ultra-Peripheral Collision (UPC) analysis in Heavy Flavor physics +/// +/// \author Minjung Kim , CERN + +#ifndef PWGHF_UTILS_UTILSUPCHF_H_ +#define PWGHF_UTILS_UTILSUPCHF_H_ + +#include "PWGUD/Core/SGCutParHolder.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UDHelpers.h" + +#include + +#include + +namespace o2::analysis::hf_upc +{ + +/// \brief Use TrueGap enum from SGSelector for gap type classification +using o2::aod::sgselector::TrueGap; + +/// \brief Configurable group for UPC gap determination thresholds +struct HfUpcGapThresholds : o2::framework::ConfigurableGroup { + std::string prefix = "upc"; // JSON group name + o2::framework::Configurable fv0aThreshold{"fv0aThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable ft0aThreshold{"ft0aThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable ft0cThreshold{"ft0cThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable zdcThreshold{"zdcThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; +}; + +/// \brief Default thresholds for gap determination +namespace defaults +{ +constexpr float AmplitudeThresholdFV0A = 100.0f; ///< Amplitude threshold for FV0-A (a.u.) +constexpr float AmplitudeThresholdFT0A = 100.0f; ///< Amplitude threshold for FT0-A (a.u.) +constexpr float AmplitudeThresholdFT0C = 50.0f; ///< Amplitude threshold for FT0-C (a.u.) +constexpr float MaxFITTime = 4.0f; ///< Maximum FIT time (ns) +constexpr int NDtColl = 1000; ///< Time window for BC range (ns) +constexpr int MinNBCs = 7; ///< Minimum number of BCs to check +constexpr int MinNTracks = 0; ///< Minimum number of tracks +constexpr int MaxNTracks = 100; ///< Maximum number of tracks +} // namespace defaults + +/// \brief Determine gap type using SGSelector with BC range checking +/// \tparam TCollision Collision type +/// \tparam TBCs BC table type +/// \param collision Collision object +/// \param bcs BC table +/// \param amplitudeThresholdFV0A Threshold for FV0-A (default: 100.0) +/// \param amplitudeThresholdFT0A Threshold for FT0-A (default: 100.0) +/// \param amplitudeThresholdFT0C Threshold for FT0-C (default: 50.0) +/// \return SelectionResult with gap type value and BC pointer +template +inline auto determineGapType(TCollision const& collision, + TBCs const& bcs, + float amplitudeThresholdFV0A = defaults::AmplitudeThresholdFV0A, + float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, + float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C) +{ + using BCType = std::decay_t())>; + + // Configure SGSelector thresholds + SGCutParHolder sgCuts; + sgCuts.SetNDtcoll(defaults::NDtColl); + sgCuts.SetMinNBCs(defaults::MinNBCs); + sgCuts.SetNTracks(defaults::MinNTracks, defaults::MaxNTracks); + sgCuts.SetMaxFITtime(defaults::MaxFITTime); + sgCuts.SetFITAmpLimits({amplitudeThresholdFV0A, amplitudeThresholdFT0A, amplitudeThresholdFT0C}); + + // Get BC and BC range + if (!collision.has_foundBC()) { + return SelectionResult{TrueGap::NoGap, nullptr}; + } + + const auto bc = collision.template foundBC_as(); + const auto bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); + + // Create SGSelector instance and determine gap type with BC range checking + SGSelector sgSelector; + const auto sgResult = sgSelector.IsSelected(sgCuts, collision, bcRange, bc); + + return sgResult; +} + +/// \brief Determine gap type using SGSelector with BC range checking and HfUpcGapThresholds +/// \tparam TCollision Collision type +/// \tparam TBCs BC table type +/// \param collision Collision object +/// \param bcs BC table +/// \param thresholds HfUpcGapThresholds object containing all UPC thresholds +/// \return SelectionResult with gap type value and BC pointer +template +inline auto determineGapType(TCollision const& collision, + TBCs const& bcs, + HfUpcGapThresholds const& thresholds) +{ + return determineGapType(collision, bcs, + thresholds.fv0aThreshold.value, + thresholds.ft0aThreshold.value, + thresholds.ft0cThreshold.value); +} +/* +/// \brief Check if the gap type is a single-sided gap (SingleGapA or SingleGapC) +/// \param gap TrueGap enum value +/// \return true if single-sided gap, false otherwise +constexpr bool isSingleSidedGap(int gap) noexcept +{ + return (gap == TrueGap::SingleGapA || gap == TrueGap::SingleGapC || gap == TrueGap::DoubleGap || gap == TrueGap::BadDoubleGap || gap == TrueGap::TrkOutOfRange || gap == TrueGap::NoUpc); +} +*/ +/// \brief Get gap type name as string +/// \param gap TrueGap enum value +/// \return String representation of gap type +constexpr const char* getGapTypeName(int gap) noexcept +{ + switch (gap) { + case TrueGap::NoGap: + return "NoGap"; + case TrueGap::SingleGapA: + return "SingleGapA"; + case TrueGap::SingleGapC: + return "SingleGapC"; + case TrueGap::DoubleGap: + return "DoubleGap"; + case TrueGap::NoUpc: + return "NoUpc"; + case TrueGap::TrkOutOfRange: + return "TrkOutOfRange"; + case TrueGap::BadDoubleGap: + return "BadDoubleGap"; + default: + return "Unknown"; + } +} + +} // namespace o2::analysis::hf_upc + +#endif // PWGHF_UTILS_UTILSUPCHF_H_ diff --git a/PWGJE/Core/CMakeLists.txt b/PWGJE/Core/CMakeLists.txt index 592e1686ff5..b6ccafb2be2 100644 --- a/PWGJE/Core/CMakeLists.txt +++ b/PWGJE/Core/CMakeLists.txt @@ -14,7 +14,8 @@ o2physics_add_library(PWGJECore SOURCES FastJetUtilities.cxx JetFinder.cxx JetBkgSubUtils.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib) + emcalCrossTalkEmulation.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib ONNXRuntime::ONNXRuntime O2::EMCALBase O2::EMCALReconstruction) o2physics_target_root_dictionary(PWGJECore HEADERS JetFinder.h @@ -23,5 +24,7 @@ o2physics_target_root_dictionary(PWGJECore JetTaggingUtilities.h JetBkgSubUtils.h JetDerivedDataUtilities.h + emcalCrossTalkEmulation.h + utilsTrackMatchingEMC.h LINKDEF PWGJECoreLinkDef.h) endif() diff --git a/PWGJE/Core/FastJetUtilities.cxx b/PWGJE/Core/FastJetUtilities.cxx index ba7acabbdf3..ca5956a1554 100644 --- a/PWGJE/Core/FastJetUtilities.cxx +++ b/PWGJE/Core/FastJetUtilities.cxx @@ -11,6 +11,10 @@ #include "FastJetUtilities.h" +#include + +#include + void fastjetutilities::setFastJetUserInfo(std::vector& constituents, int index, int status) { fastjet_user_info* user_info = new fastjet_user_info(status, index); // FIXME: can setting this as a pointer be avoided? diff --git a/PWGJE/Core/FastJetUtilities.h b/PWGJE/Core/FastJetUtilities.h index 01da286521b..aebb41ab5d0 100644 --- a/PWGJE/Core/FastJetUtilities.h +++ b/PWGJE/Core/FastJetUtilities.h @@ -17,15 +17,10 @@ #ifndef PWGJE_CORE_FASTJETUTILITIES_H_ #define PWGJE_CORE_FASTJETUTILITIES_H_ +#include + #include -#include -#include -#include #include -#include - -#include "fastjet/PseudoJet.hh" -#include "fastjet/Selector.hh" enum class JetConstituentStatus { track = 0, @@ -103,11 +98,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..baa8e65d727 100644 --- a/PWGJE/Core/JetBkgSubUtils.cxx +++ b/PWGJE/Core/JetBkgSubUtils.cxx @@ -12,13 +12,26 @@ // jet finder task // // Author: Hadi Hassan, Universiy of Jväskylä, hadi.hassan@cern.ch -#include -#include -#include "Framework/Logger.h" -#include "Common/Core/RecoDecay.h" -#include "PWGJE/Core/JetUtilities.h" + #include "PWGJE/Core/JetBkgSubUtils.h" -#include "PWGJE/Core/FastJetUtilities.h" + +#include "Common/Core/RecoDecay.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include JetBkgSubUtils::JetBkgSubUtils(float jetBkgR_out, float bkgEtaMin_out, float bkgEtaMax_out, float bkgPhiMin_out, float bkgPhiMax_out, float constSubAlpha_out, float constSubRMax_out, int nHardReject_out, fastjet::GhostedAreaSpec ghostAreaSpec_out) : jetBkgR(jetBkgR_out), bkgEtaMin(bkgEtaMin_out), @@ -35,7 +48,7 @@ JetBkgSubUtils::JetBkgSubUtils(float jetBkgR_out, float bkgEtaMin_out, float bkg void JetBkgSubUtils::initialise() { - // Note: if you are using the PerpCone method you should jetBkgR to be the same as the anit_kt jets R, otherwise use R=0.2 + // Note: recommended to use R=0.2 jetDefBkg = fastjet::JetDefinition(algorithmBkg, jetBkgR, recombSchemeBkg, fastjet::Best); areaDefBkg = fastjet::AreaDefinition(fastjet::active_area_explicit_ghosts, ghostAreaSpec); selRho = fastjet::SelectorRapRange(bkgEtaMin, bkgEtaMax) && fastjet::SelectorPhiRange(bkgPhiMin, bkgPhiMax) && !fastjet::SelectorNHardest(nHardReject); // here we have to put rap range, to be checked! @@ -91,63 +104,7 @@ std::tuple JetBkgSubUtils::estimateRhoAreaMedian(const std::vect return std::make_tuple(rho, rhoM); } -std::tuple JetBkgSubUtils::estimateRhoPerpCone(const std::vector& inputParticles, const std::vector& jets) -{ - - JetBkgSubUtils::initialise(); - if (inputParticles.size() == 0 || jets.size() == 0) { - return std::make_tuple(0.0, 0.0); - } - - double perpPtDensity1 = 0; - double perpPtDensity2 = 0; - double perpMdDensity1 = 0; - double perpMdDensity2 = 0; - - fastjet::Selector selectJet = fastjet::SelectorEtaRange(bkgEtaMin, bkgEtaMax) && fastjet::SelectorPhiRange(bkgPhiMin, bkgPhiMax); - - std::vector selectedJets = fastjet::sorted_by_pt(selectJet(jets)); - - if (selectedJets.size() == 0) { - return std::make_tuple(0.0, 0.0); - } - - fastjet::PseudoJet leadingJet = selectedJets[0]; - - double dPhi1 = 999.; - double dPhi2 = 999.; - double dEta = 999.; - double PerpendicularConeAxisPhi1 = 999., PerpendicularConeAxisPhi2 = 999.; - // build 2 perp cones in phi around the leading jet (right and left of the jet) - PerpendicularConeAxisPhi1 = RecoDecay::constrainAngle(leadingJet.phi() + (M_PI / 2.)); // This will contrain the angel between 0-2Pi - PerpendicularConeAxisPhi2 = RecoDecay::constrainAngle(leadingJet.phi() - (M_PI / 2.)); // This will contrain the angel between 0-2Pi - - for (auto& particle : inputParticles) { - // sum the momentum of all paricles that fill the two cones - dPhi1 = particle.phi() - PerpendicularConeAxisPhi1; - dPhi1 = RecoDecay::constrainAngle(dPhi1, -M_PI); // This will contrain the angel between -pi & Pi - dPhi2 = particle.phi() - PerpendicularConeAxisPhi2; - dPhi2 = RecoDecay::constrainAngle(dPhi2, -M_PI); // This will contrain the angel between -pi & Pi - dEta = leadingJet.eta() - particle.eta(); // The perp cone eta is the same as the leading jet since the cones are perpendicular only in phi - if (TMath::Sqrt(dPhi1 * dPhi1 + dEta * dEta) <= jetBkgR) { - perpPtDensity1 += particle.perp(); - perpMdDensity1 += TMath::Sqrt(particle.m() * particle.m() + particle.pt() * particle.pt()) - particle.pt(); - } - - if (TMath::Sqrt(dPhi2 * dPhi2 + dEta * dEta) <= jetBkgR) { - perpPtDensity2 += particle.perp(); - perpMdDensity2 += TMath::Sqrt(particle.m() * particle.m() + particle.pt() * particle.pt()) - particle.pt(); - } - } - - // Caculate rho as the ratio of average pT of the two cones / the cone area - double perpPtDensity = (perpPtDensity1 + perpPtDensity2) / (2 * M_PI * jetBkgR * jetBkgR); - double perpMdDensity = (perpMdDensity1 + perpMdDensity2) / (2 * M_PI * jetBkgR * jetBkgR); - - return std::make_tuple(perpPtDensity, perpMdDensity); -} - -fastjet::PseudoJet JetBkgSubUtils::doRhoAreaSub(fastjet::PseudoJet& jet, double rhoParam, double rhoMParam) +fastjet::PseudoJet JetBkgSubUtils::doRhoAreaSub(const fastjet::PseudoJet& jet, double rhoParam, double rhoMParam) { fastjet::Subtractor sub = fastjet::Subtractor(rhoParam, rhoMParam); @@ -159,7 +116,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/JetBkgSubUtils.h b/PWGJE/Core/JetBkgSubUtils.h index e74aa512b99..03b22433460 100644 --- a/PWGJE/Core/JetBkgSubUtils.h +++ b/PWGJE/Core/JetBkgSubUtils.h @@ -17,28 +17,21 @@ #ifndef PWGJE_CORE_JETBKGSUBUTILS_H_ #define PWGJE_CORE_JETBKGSUBUTILS_H_ -#include -#include +#include +#include +#include +#include +#include + #include #include -#include - -#include "PWGJE/Core/FastJetUtilities.h" - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" -#include "fastjet/AreaDefinition.hh" -#include "fastjet/JetDefinition.hh" -#include "fastjet/tools/JetMedianBackgroundEstimator.hh" -#include "fastjet/tools/Subtractor.hh" -#include "fastjet/contrib/ConstituentSubtractor.hh" -#include "Framework/Logger.h" +#include enum class BkgSubEstimator { none = 0, medianRho = 1, - medianRhoSparse = 2, - perpCone = 3 + medianRhoSparse = 2 + // perpendicular cone method is in JetUtilities }; enum class BkgSubMode { none = 0, @@ -75,18 +68,12 @@ class JetBkgSubUtils /// @return Rho, RhoM the underlying event density std::tuple estimateRhoAreaMedian(const std::vector& inputParticles, bool doSparseSub); - /// @brief Background estimator using the perpendicular cone method - /// @param inputParticles - /// @param jets (all jets in the event) - /// @return Rho, RhoM the underlying event density - std::tuple estimateRhoPerpCone(const std::vector& inputParticles, const std::vector& jets); - /// @brief method that subtracts the background from jets using the area method /// @param jet input jet to be background subtracted /// @param rhoParam the underlying evvent density vs pT (to be set) /// @param rhoParam the underlying evvent density vs jet mass (to be set) /// @return jet, background subtracted jet - fastjet::PseudoJet doRhoAreaSub(fastjet::PseudoJet& jet, double rhoParam, double rhoMParam); + fastjet::PseudoJet doRhoAreaSub(const fastjet::PseudoJet& jet, double rhoParam, double rhoMParam); /// @brief method that subtracts the background from the input particles using the event-wise cosntituent subtractor /// @param inputParticles (all the tracks/clusters/particles in the event) diff --git a/PWGJE/Core/JetCandidateUtilities.h b/PWGJE/Core/JetCandidateUtilities.h index 43e66f82d66..de6b7faf8f9 100644 --- a/PWGJE/Core/JetCandidateUtilities.h +++ b/PWGJE/Core/JetCandidateUtilities.h @@ -17,36 +17,12 @@ #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 "PWGHF/DataModel/DerivedTablesStored.h" - -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/Core/JetHFUtilities.h" #include "PWGJE/Core/JetDQUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" #include "PWGJE/Core/JetV0Utilities.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/DataModel/Jet.h" + +#include +#include namespace jetcandidateutilities { @@ -142,17 +118,16 @@ constexpr bool isMatchedCandidate(T const& 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) +template +bool isDaughterTrack(T& track, U& candidate) { if constexpr (jethfutilities::isHFCandidate()) { - return jethfutilities::isHFDaughterTrack(track, candidate, tracks); + return jethfutilities::isHFDaughterTrack(track, candidate); } else if constexpr (jetv0utilities::isV0Candidate()) { - return jetv0utilities::isV0DaughterTrack(track, candidate, tracks); + return jetv0utilities::isV0DaughterTrack(track, candidate); } else if constexpr (jetdqutilities::isDielectronCandidate()) { - return jetdqutilities::isDielectronDaughterTrack(track, candidate, tracks); + return jetdqutilities::isDielectronDaughterTrack(track, candidate); } else { return false; } @@ -167,6 +142,9 @@ bool isDaughterTrack(T& track, U& candidate, V const& tracks) 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; @@ -226,11 +204,11 @@ auto matchedParticle(const T& candidate, const U& tracks, const V& particles) * @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& perLcCandidate, N const& perBplusCandidate, O const& perDielectronCandidate) +template +auto slicedPerCandidate(T const& table, U const& candidate, V const& perD0Candidate, M const& perDplusCandidate, N const& perDsCandidate, O const& perDstarCandidate, P const& perLcCandidate, Q const& perB0Candidate, R const& perBplusCandidate, S const& perXicToXiPiPiCandidate, A const& perDielectronCandidate) { if constexpr (jethfutilities::isHFCandidate()) { - return jethfutilities::slicedPerHFCandidate(table, candidate, perD0Candidate, perLcCandidate, perBplusCandidate); + return jethfutilities::slicedPerHFCandidate(table, candidate, perD0Candidate, perDplusCandidate, perDsCandidate, perDstarCandidate, perLcCandidate, perB0Candidate, perBplusCandidate, perXicToXiPiPiCandidate); } else if constexpr (jetdqutilities::isDielectronCandidate()) { return jetdqutilities::slicedPerDielectronCandidate(table, candidate, perDielectronCandidate); } else { @@ -239,18 +217,18 @@ auto slicedPerCandidate(T const& table, U const& candidate, V const& perD0Candid } /** - * returns a slice of the table depending on the type of the candidate and index of the collision - * - * @param candidate candidate that is being checked + * 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 slicedPerCandidateCollision(T const& table, U const& candidates, V const& collision, M const& D0CollisionPerCollision, N const& LcCollisionPerCollision, O const& BplusCollisionPerCollision, P const& DielectronCollisionPerCollision) +template +auto slicedPerJet(T const& table, U const& jet, V const& perD0Jet, M const& perDplusJet, N const& perDsJet, O const& perDstarJet, P const& perLcJet, Q const& perB0Jet, R const& perBplusJet, S const& perXicToXiPiPiJet, A const& perDielectronJet) { - if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { - return jethfutilities::slicedPerHFCollision(table, candidates, collision, D0CollisionPerCollision, LcCollisionPerCollision, BplusCollisionPerCollision); - } else if constexpr (jetdqutilities::isDielectronTable() || jetdqutilities::isDielectronMcTable()) { - return jetdqutilities::slicedPerDielectronCollision(table, candidates, collision, DielectronCollisionPerCollision); + if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { + return jethfutilities::slicedPerHFJet(table, jet, perD0Jet, perDplusJet, perDsJet, perDstarJet, perLcJet, perB0Jet, perBplusJet, perXicToXiPiPiJet); + } else if constexpr (jetdqutilities::isDielectronTable() || jetdqutilities::isDielectronMcTable()) { + return jetdqutilities::slicedPerDielectronJet(table, jet, perDielectronJet); } else { return table; } @@ -374,42 +352,42 @@ float getCandidateInvariantMass(T const& candidate) } template -void fillCandidateCollisionTable(T const& collision, U const& candidates, V& CandiateCollisionTable, int32_t& CandidateCollisionTableIndex) +void fillCandidateCollisionTable(T const& collision, U const& /*candidates*/, V& CandiateCollisionTable) { if constexpr (jethfutilities::isHFTable()) { - jethfutilities::fillHFCollisionTable(collision, candidates, CandiateCollisionTable, CandidateCollisionTableIndex); + jethfutilities::fillHFCollisionTable(collision, CandiateCollisionTable); } else if constexpr (jetdqutilities::isDielectronTable()) { - jetdqutilities::fillDielectronCollisionTable(collision, CandiateCollisionTable, CandidateCollisionTableIndex); // if more dilepton tables are added we would need a fillDQCollisionTable + 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, int32_t& CandidateMcCollisionTableIndex) +void fillCandidateMcCollisionTable(T const& mcCollision, U const& /*candidates*/, V& CandiateMcCollisionTable) { if constexpr (jethfutilities::isHFMcTable()) { - jethfutilities::fillHFMcCollisionTable(mcCollision, candidates, CandiateMcCollisionTable, CandidateMcCollisionTableIndex); + jethfutilities::fillHFMcCollisionTable(mcCollision, CandiateMcCollisionTable); } else if constexpr (jetdqutilities::isDielectronMcTable()) { - jetdqutilities::fillDielectronMcCollisionTable(mcCollision, CandiateMcCollisionTable, CandidateMcCollisionTableIndex); + jetdqutilities::fillDielectronMcCollisionTable(mcCollision, CandiateMcCollisionTable); } } -template -void fillCandidateTable(T const& candidate, int32_t collisionIndex, U& BaseTable, V& HFParTable, M& HFParETable, N& HFSelectionFlagTable, O& HFMlTable, P& HFMCDTable, int32_t& candidateTableIndex) +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, HFSelectionFlagTable, HFMlTable, HFMCDTable, candidateTableIndex); + jethfutilities::fillHFCandidateTable(candidate, collisionIndex, BaseTable, HFParTable, HFParETable, HFParDaughterTable, HFSelectionFlagTable, HFMlTable, HFMlDaughterTable, HFMCDTable); } else if constexpr (jetdqutilities::isDielectronCandidate()) { - jetdqutilities::fillDielectronCandidateTable(candidate, collisionIndex, BaseTable, candidateTableIndex); + jetdqutilities::fillDielectronCandidateTable(candidate, collisionIndex, BaseTable, HFParTable); } } template -void fillCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& BaseMcTable, int32_t& candidateTableIndex) +void fillCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& BaseMcTable) { if constexpr (jethfutilities::isHFMcCandidate()) { - jethfutilities::fillHFCandidateMcTable(candidate, mcCollisionIndex, BaseMcTable, candidateTableIndex); + jethfutilities::fillHFCandidateMcTable(candidate, mcCollisionIndex, BaseMcTable); } else if constexpr (jetdqutilities::isDielectronMcCandidate()) { - jetdqutilities::fillDielectronCandidateMcTable(candidate, mcCollisionIndex, BaseMcTable, candidateTableIndex); + jetdqutilities::fillDielectronCandidateMcTable(candidate, mcCollisionIndex, BaseMcTable); } } diff --git a/PWGJE/Core/JetDQUtilities.h b/PWGJE/Core/JetDQUtilities.h index fdd5ca9cbcd..e51e8232c26 100644 --- a/PWGJE/Core/JetDQUtilities.h +++ b/PWGJE/Core/JetDQUtilities.h @@ -17,31 +17,21 @@ #ifndef PWGJE_CORE_JETDQUTILITIES_H_ #define PWGJE_CORE_JETDQUTILITIES_H_ -#include -#include -#include -#include +#include "PWGJE/DataModel/Jet.h" -#include +#include "Common/Core/RecoDecay.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" +#include +#include -#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 -#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/DataModel/Jet.h" +#include +#include +#include +#include namespace jetdqutilities { @@ -52,7 +42,7 @@ namespace jetdqutilities template constexpr bool isDielectronCandidate() { - return std::is_same_v, CandidatesDielectronData::iterator> || std::is_same_v, CandidatesDielectronData::filtered_iterator> || std::is_same_v, CandidatesDielectronMCD::iterator> || std::is_same_v, CandidatesDielectronMCD::filtered_iterator>; + 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>; } /** @@ -61,7 +51,7 @@ constexpr bool isDielectronCandidate() template constexpr bool isDielectronMcCandidate() { - return std::is_same_v, CandidatesDielectronMCP::iterator> || std::is_same_v, CandidatesDielectronMCP::filtered_iterator>; + return std::is_same_v, o2::aod::CandidatesDielectronMCP::iterator> || std::is_same_v, o2::aod::CandidatesDielectronMCP::filtered_iterator>; } /** @@ -104,10 +94,9 @@ constexpr bool isMatchedDielectronCandidate(T const& /*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*/) +template +bool isDielectronDaughterTrack(T& track, U& candidate) { if constexpr (isDielectronCandidate()) { if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex()) { @@ -165,16 +154,16 @@ auto slicedPerDielectronCandidate(T const& table, U const& candidate, V const& p } /** - * returns a slice of the table depending on the type of the Dielectron candidate and index of the collision - * - * @param candidate dielectron candidate that is being checked + * 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 slicedPerDielectronCollision(T const& table, U const& /*candidates*/, V const& collision, M const& DielectronCollisionPerCollision) +template +auto slicedPerDielectronJet(T const& table, U const& jet, V const& perDielectronJet) { - if constexpr (isDielectronTable() || isDielectronMcTable()) { - return table.sliceBy(DielectronCollisionPerCollision, collision.globalIndex()); + if constexpr (isDielectronTable() || isDielectronMcTable()) { + return table.sliceBy(perDielectronJet, jet.globalIndex()); } else { return table; } @@ -188,11 +177,7 @@ auto slicedPerDielectronCollision(T const& table, U const& /*candidates*/, V con template int getDielectronCandidateCollisionId(T const& candidate) { - if constexpr (isDielectronCandidate()) { - return candidate.reducedeventId(); - } else { - return -1; - } + return candidate.reducedeventId(); } /** @@ -275,11 +260,7 @@ float getDielectronTablePDGMass() template float getDielectronCandidateInvariantMass(T const& candidate) { - if constexpr (isDielectronCandidate()) { - return candidate.mass(); - } else { - return -1.0; - } + return candidate.mass(); } template @@ -301,7 +282,7 @@ bool selectDielectronParticleDecay(T const& dielectronParticle, int dielectronPa return (dielectronParticle.decayFlag() & (1 << dielectronParticleDecaySelection)); } -int initialiseDielectronParticleDecaySelection(std::string dielectronParticleDecaySelection) +int initialiseDielectronParticleDecaySelection(const std::string& dielectronParticleDecaySelection) { if (dielectronParticleDecaySelection == "JPsiToEE") { return JDielectronParticleDecays::JPsiToEE; @@ -320,31 +301,58 @@ uint8_t setDielectronParticleDecayBit(T const& particles, U const& particle) } template -void fillDielectronCollisionTable(T const& collision, U& DielectronCollisionTable, int32_t& DielectronCollisionTableIndex) +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()); - DielectronCollisionTableIndex = DielectronCollisionTable.lastIndex(); } template -void fillDielectronMcCollisionTable(T const& mcCollision, U& DielectronMcCollisionTable, int32_t& DielectronMcCollisionTableIndex) +void fillDielectronMcCollisionTable(T const& mcCollision, U& DielectronMcCollisionTable) { DielectronMcCollisionTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); - DielectronMcCollisionTableIndex = DielectronMcCollisionTable.lastIndex(); } -template -void fillDielectronCandidateTable(T const& candidate, int32_t collisionIndex, U& DielectronTable, int32_t& DielectronCandidateTableIndex) +template +void fillDielectronCandidateTable(T const& candidate, int32_t collisionIndex, U& DielectronTable, V& DielectronAllTable) { DielectronTable(collisionIndex, candidate.mass(), candidate.pt(), candidate.eta(), candidate.phi(), candidate.sign(), candidate.filterMap_raw(), candidate.mcDecision()); - DielectronCandidateTableIndex = DielectronTable.lastIndex(); + + DielectronAllTable( + candidate.mass(), candidate.pt(), candidate.eta(), candidate.phi(), candidate.sign(), + candidate.filterMap_raw(), candidate.mcDecision(), + + candidate.pt1(), candidate.eta1(), candidate.phi1(), + candidate.itsClusterMap1(), candidate.itsChi2NCl1(), + candidate.tpcNClsCR1(), candidate.tpcNClsFound1(), candidate.tpcChi2NCl1(), + candidate.dcaXY1(), candidate.dcaZ1(), + candidate.tpcSignal1(), candidate.tpcNSigmaEl1(), candidate.tpcNSigmaPi1(), candidate.tpcNSigmaPr1(), + candidate.tofBeta1(), candidate.tofNSigmaEl1(), candidate.tofNSigmaPi1(), candidate.tofNSigmaPr1(), + + candidate.pt2(), candidate.eta2(), candidate.phi2(), + candidate.itsClusterMap2(), candidate.itsChi2NCl2(), + candidate.tpcNClsCR2(), candidate.tpcNClsFound2(), candidate.tpcChi2NCl2(), + candidate.dcaXY2(), candidate.dcaZ2(), + candidate.tpcSignal2(), candidate.tpcNSigmaEl2(), candidate.tpcNSigmaPi2(), candidate.tpcNSigmaPr2(), + candidate.tofBeta2(), candidate.tofNSigmaEl2(), candidate.tofNSigmaPi2(), candidate.tofNSigmaPr2(), + + candidate.dcaxyztrk0KF(), candidate.dcaxyztrk1KF(), candidate.dcaxyzbetweentrksKF(), + candidate.dcaxytrk0KF(), candidate.dcaxytrk1KF(), candidate.dcaxybetweentrksKF(), + candidate.deviationTrk0KF(), candidate.deviationTrk1KF(), + candidate.deviationxyTrk0KF(), candidate.deviationxyTrk1KF(), + candidate.massKFGeo(), candidate.chi2overndfKFGeo(), + candidate.decaylengthKFGeo(), candidate.decaylengthovererrKFGeo(), + candidate.decaylengthxyKFGeo(), candidate.decaylengthxyovererrKFGeo(), + candidate.pseudoproperdecaytimeKFGeo(), candidate.pseudoproperdecaytimeErrKFGeo(), candidate.cosPAKFGeo(), + candidate.pairDCAxyz(), candidate.pairDCAxy(), + candidate.deviationPairKF(), candidate.deviationxyPairKF(), + candidate.massKFGeoTop(), candidate.chi2overndfKFGeoTop(), + candidate.tauz(), candidate.tauxy(), candidate.lz(), candidate.lxy()); } template -void fillDielectronCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& DielectronMcTable, int32_t& DielectronCandidateTableIndex) +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()); - DielectronCandidateTableIndex = DielectronMcTable.lastIndex(); + DielectronMcTable(mcCollisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.y(), candidate.e(), candidate.m(), candidate.pdgCode(), candidate.statusCode(), candidate.flags(), candidate.decayFlag(), candidate.origin()); } }; // namespace jetdqutilities diff --git a/PWGJE/Core/JetDerivedDataUtilities.h b/PWGJE/Core/JetDerivedDataUtilities.h index 389f2732b07..1b02a380312 100644 --- a/PWGJE/Core/JetDerivedDataUtilities.h +++ b/PWGJE/Core/JetDerivedDataUtilities.h @@ -17,9 +17,18 @@ #ifndef PWGJE_CORE_JETDERIVEDDATAUTILITIES_H_ #define PWGJE_CORE_JETDERIVEDDATAUTILITIES_H_ -#include -#include "Common/CCDB/TriggerAliases.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/TriggerAliases.h" + +#include + +#include +#include +#include +#include +#include +#include namespace jetderiveddatautilities { @@ -28,66 +37,158 @@ static constexpr float mPion = 0.139; // TDatabasePDG::Instance()->GetParticle(2 enum JCollisionSel { sel8 = 0, - sel8Full = 1, - sel7 = 2, - selMC = 3, - selUnanchoredMC = 4, - sel7KINT7 = 5 + 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, const std::vector& eventSelectionMaskBits, bool skipMBGapEvents = true, bool rctSelection = true, std::string rctLabel = "CBT_hadronPID", bool rejectLimitedAcceptanceRct = false, bool requireZDCRct = false) { - if (eventSelection == -1) { + if (skipMBGapEvents && collision.subGeneratorId() == JCollisionSubGeneratorId::mbGap) { + return false; + } + o2::aod::rctsel::RCTFlagsChecker rctChecker; + rctChecker.init(rctLabel, requireZDCRct, rejectLimitedAcceptanceRct); + if (rctSelection && !rctChecker.checkTable(collision)) { // CBT_hadronPID given as default so that TOF is included in RCT selection to benefit from better timing for tracks. Impact of this for inclusive jets should be studied + 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; } -int initialiseEventSelection(std::string eventSelection) +bool eventSelectionMasksContainSelection(const std::string& eventSelectionMasks, std::string selection) { - if (eventSelection == "sel8") { - return JCollisionSel::sel8; + 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(); } - if (eventSelection == "sel8Full") { - return JCollisionSel::sel8Full; + return false; +} + +std::vector initialiseEventSelectionBits(const std::string& eventSelectionMasks) +{ + std::vector eventSelectionMaskBits; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "sel8")) { + eventSelectionMaskBits.push_back(JCollisionSel::sel8); } - if (eventSelection == "sel7") { - return JCollisionSel::sel7; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "sel7")) { + eventSelectionMaskBits.push_back(JCollisionSel::sel7); } - if (eventSelection == "selMC") { - return JCollisionSel::selMC; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "selKINT7")) { + eventSelectionMaskBits.push_back(JCollisionSel::selKINT7); } - if (eventSelection == "selUnanchoredMC") { - return JCollisionSel::selUnanchoredMC; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "TVX")) { + eventSelectionMaskBits.push_back(JCollisionSel::selTVX); } - if (eventSelection == "sel7KINT7") { - return JCollisionSel::sel7KINT7; + if (eventSelectionMasksContainSelection(eventSelectionMasks, "NoTimeFrameBorder")) { + eventSelectionMaskBits.push_back(JCollisionSel::selNoTimeFrameBorder); } - return -1; + 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::sel7KINT7); - } + } + if (collision.alias_bit(kINT7)) { + SETBIT(bit, JCollisionSel::selKINT7); } if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { - SETBIT(bit, JCollisionSel::selUnanchoredMC); - if (collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - SETBIT(bit, JCollisionSel::selMC); - } + 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; } @@ -107,10 +208,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, const 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(const 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(const 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(const 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 }; @@ -124,13 +369,13 @@ bool selectChargedTrigger(T const& collision, int triggerSelection) return (collision.chargedTriggerSel() & (1 << triggerSelection)); } -int initialiseChargedTriggerSelection(std::string triggerSelection) +int initialiseChargedTriggerSelection(const 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; @@ -148,10 +393,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); @@ -165,18 +410,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 @@ -188,32 +434,34 @@ bool selectFullTrigger(T const& collision, int triggerSelection) return (collision.fullTriggerSel() & (1 << triggerSelection)); } -int initialiseFullTriggerSelection(std::string triggerSelection) +int initialiseFullTriggerSelection(const 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; } @@ -222,51 +470,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 @@ -278,19 +529,19 @@ bool selectChargedHFTrigger(T const& collision, int triggerSelection) return (collision.chargedHFTriggerSel() & (1 << triggerSelection)); } -int initialiseChargedHFTriggerSelection(std::string triggerSelection) +int initialiseChargedHFTriggerSelection(const 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; } @@ -301,16 +552,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; } @@ -319,9 +570,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, - uniformTrack = 4, - uniformTrackWoDCA = 5 + qualityTrackWDCA = 3, + hybridTrack = 4 }; template @@ -342,24 +592,22 @@ bool selectTrack(T const& track, int trackSelection) return (track.trackSel() & (1 << trackSelection)); } -int initialiseTrackSelection(std::string trackSelection) +int initialiseTrackSelection(const std::string& trackSelection) { if (trackSelection == "globalTracks") { return JTrackSel::globalTrack; } else if (trackSelection == "QualityTracks") { return JTrackSel::qualityTrack; + } else if (trackSelection == "QualityTracksWDCA") { + return JTrackSel::qualityTrackWDCA; } else if (trackSelection == "hybridTracks") { return JTrackSel::hybridTrack; - } else if (trackSelection == "uniformTracks") { - return JTrackSel::uniformTrack; - } else if (trackSelection == "uniformTracksWoDCA") { - return JTrackSel::uniformTrackWoDCA; } return -1; } template -uint8_t setTrackSelectionBit(T const& track) +uint8_t setTrackSelectionBit(T const& track, float trackDCAZ, float maxDCAZ) { uint8_t bit = 0; @@ -372,20 +620,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); } - if ((track.passedGoldenChi2() && track.passedDCAxy()) && - (track.passedITSNCls() && track.passedITSChi2NDF() && track.passedITSHits()) && - (!track.hasTPC() || (track.passedTPCNCls() && track.passedTPCChi2NDF() && track.passedTPCCrossedRowsOverNCls()))) { // removing track.passedDCAz() so aimeric can test. Needs to be added into the bracket with passedGoldenChi2 - SETBIT(bit, JTrackSel::uniformTrack); - } - if (track.passedGoldenChi2() && - (track.passedITSNCls() && track.passedITSChi2NDF() && track.passedITSHits()) && - (!track.hasTPC() || (track.passedTPCNCls() && track.passedTPCChi2NDF() && track.passedTPCCrossedRowsOverNCls()))) { - SETBIT(bit, JTrackSel::uniformTrackWoDCA); - } return bit; } diff --git a/PWGJE/Core/JetFinder.cxx b/PWGJE/Core/JetFinder.cxx index 940a201bb92..87a71fb19e3 100644 --- a/PWGJE/Core/JetFinder.cxx +++ b/PWGJE/Core/JetFinder.cxx @@ -15,7 +15,13 @@ /// \author Jochen Klein #include "PWGJE/Core/JetFinder.h" -#include "Framework/Logger.h" + +#include +#include +#include +#include + +#include /// Sets the jet finding parameters void JetFinder::setParams() @@ -37,7 +43,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..94afd0117ec 100644 --- a/PWGJE/Core/JetFinder.h +++ b/PWGJE/Core/JetFinder.h @@ -18,18 +18,18 @@ #ifndef PWGJE_CORE_JETFINDER_H_ #define PWGJE_CORE_JETFINDER_H_ -#include -#include +#include +#include +#include +#include +#include +#include + +#include -#include -#include -#include +#include -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" -#include "fastjet/AreaDefinition.hh" -#include "fastjet/JetDefinition.hh" -#include "fastjet/tools/Subtractor.hh" +#include enum class JetType { full = 0, @@ -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 b624ba4a927..b082b5df4e4 100644 --- a/PWGJE/Core/JetFindingUtilities.h +++ b/PWGJE/Core/JetFindingUtilities.h @@ -17,60 +17,104 @@ #ifndef PWGJE_CORE_JETFINDINGUTILITIES_H_ #define PWGJE_CORE_JETFINDINGUTILITIES_H_ -#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/HistogramRegistry.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 "PWGJE/Core/JetBkgSubUtils.h" #include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetCandidateUtilities.h" #include "PWGJE/Core/JetDerivedDataUtilities.h" #include "PWGJE/Core/JetFinder.h" #include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" -#include "PWGJE/Core/JetCandidateUtilities.h" -#include "PWGJE/Core/JetHFUtilities.h" +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include 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, JetClusters::iterator> || std::is_same_v, JetClusters::filtered_iterator> || std::is_same_v, JetClustersMCD::iterator> || std::is_same_v, JetClustersMCD::filtered_iterator>; + 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 isEMCALTable() +constexpr bool isEMCALClusterTable() { return isEMCALCluster() || isEMCALCluster(); } +/** + * performs all track selections + * + * @param track track to be checked + * @param trackSelection track selection to be applied to tracks + * @param candidate optional HF candidiate + */ + +template +bool isTrackSelected(T const& track, int trackSelection, bool applyTrackingEfficiency, const std::vector& trackingEfficiency, const std::vector& trackingEfficiencyPtBinning, const U* candidate = nullptr) +{ + + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + return false; + } + if (candidate != nullptr) { + if (jetcandidateutilities::isDaughterTrack(track, *candidate)) { + return false; + } + } + if (applyTrackingEfficiency) { + auto iter = std::upper_bound(trackingEfficiencyPtBinning.begin(), trackingEfficiencyPtBinning.end(), track.pt()); + if (iter != trackingEfficiencyPtBinning.begin() && iter != trackingEfficiencyPtBinning.end()) { + std::size_t index = std::distance(trackingEfficiencyPtBinning.begin(), iter) - 1; + TRandom3 randomNumber(0); + if (randomNumber.Rndm() > trackingEfficiency[index]) { + return false; + } + } + } + return true; +} + /** * Adds tracks to a fastjet inputParticles list * @@ -81,25 +125,12 @@ constexpr bool isEMCALTable() */ template -void analyseTracks(std::vector& inputParticles, T const& tracks, int trackSelection, double trackingEfficinecy, std::optional const& candidate = std::nullopt) +void analyseTracks(std::vector& inputParticles, T const& tracks, int trackSelection, bool applyTrackingEfficiency, const std::vector& trackingEfficiency, const std::vector& trackingEfficiencyPtBinning, const U* candidate = nullptr) { for (auto& track : tracks) { - if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { - continue; + if (isTrackSelected(track, trackSelection, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning, candidate)) { + fastjetutilities::fillTracks(track, inputParticles, track.globalIndex()); } - if (candidate != std::nullopt) { - auto cand = candidate.value(); - 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()); } } @@ -113,21 +144,25 @@ void analyseTracks(std::vector& inputParticles, T const& tra */ template -void analyseTracksMultipleCandidates(std::vector& inputParticles, T const& tracks, int trackSelection, double trackingEfficinecy, U const& candidates) +void analyseTracksMultipleCandidates(std::vector& inputParticles, T const& tracks, int trackSelection, bool applyTrackingEfficiency, const std::vector& trackingEfficiency, const std::vector& trackingEfficiencyPtBinning, U const& candidates) { for (auto& track : tracks) { if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; } for (auto& candidate : candidates) { - if (jetcandidateutilities::isDaughterTrack(track, candidate, tracks)) { + if (jetcandidateutilities::isDaughterTrack(track, candidate)) { 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; + if (applyTrackingEfficiency) { + auto iter = std::upper_bound(trackingEfficiencyPtBinning.begin(), trackingEfficiencyPtBinning.end(), track.pt()); + if (iter != trackingEfficiencyPtBinning.begin() && iter != trackingEfficiencyPtBinning.end()) { + std::size_t index = std::distance(trackingEfficiencyPtBinning.begin(), iter) - 1; + TRandom3 randomNumber(0); + if (randomNumber.Rndm() > trackingEfficiency[index]) { + continue; + } } } fastjetutilities::fillTracks(track, inputParticles, track.globalIndex()); @@ -141,11 +176,11 @@ void analyseTracksMultipleCandidates(std::vector& inputParti * @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); } } @@ -208,7 +243,7 @@ bool analyseCandidateMC(std::vector& inputParticles, T const * @param v0s V0 candidates */ template -bool analyseV0s(std::vector& inputParticles, T const& v0s, float v0PtMin, float v0PtMax, float v0YMin, float v0YMax, int v0Index) +bool analyseV0s(std::vector& inputParticles, T const& v0s, float v0PtMin, float v0PtMax, float v0YMin, float v0YMax, int v0Index, bool useV0SignalFlags) { float v0Mass = 0; float v0Y = -10.0; @@ -219,6 +254,9 @@ bool analyseV0s(std::vector& inputParticles, T const& v0s, f v0Mass = v0.m(); v0Y = v0.y(); } else { + if (useV0SignalFlags && v0.isRejectedCandidate()) { + continue; + } if (v0Index == 0) { v0Mass = o2::constants::physics::MassKaonNeutral; } @@ -274,8 +312,8 @@ void findJets(JetFinder& jetFinder, std::vector& inputPartic 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) { + bool isCandidateJet = false; for (const auto& constituent : jet.constituents()) { 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 @@ -318,8 +356,8 @@ void findJets(JetFinder& jetFinder, std::vector& inputPartic * @param pdgDatabase database of pdg codes * @param candidate optional hf candidiate */ -template -void analyseParticles(std::vector& inputParticles, std::string particleSelection, int jetTypeParticleLevel, T const& particles, o2::framework::Service pdgDatabase, std::optional const& candidate = std::nullopt) +template +void analyseParticles(std::vector& inputParticles, const std::string& particleSelection, int jetTypeParticleLevel, T const& particles, o2::framework::Service pdgDatabase, const U* candidate = nullptr) { for (auto& particle : particles) { if (particleSelection == "PhysicalPrimary" && !particle.isPhysicalPrimary()) { // CHECK : Does this exclude the HF hadron? @@ -343,21 +381,21 @@ void analyseParticles(std::vector& inputParticles, std::stri continue; } if constexpr (jetcandidateutilities::isMcCandidate() && !jetv0utilities::isV0McCandidate()) { - if (candidate != std::nullopt) { - auto cand = candidate.value(); - if (cand.mcParticleId() == particle.globalIndex()) { + if (candidate != nullptr) { + if ((*candidate).mcParticleId() == particle.globalIndex()) { continue; } - auto hfParticle = cand.template mcParticle_as(); - if (jetcandidateutilities::isDaughterParticle(hfParticle, particle.globalIndex())) { - continue; + if constexpr (checkIsDaughter) { + auto hfParticle = (*candidate).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 (candidate != nullptr) { + for (auto const& cand : (*candidate)) { if (cand.mcParticleId() == particle.globalIndex()) { continue; } diff --git a/PWGJE/Core/JetHFUtilities.h b/PWGJE/Core/JetHFUtilities.h index 3ede850f1fd..1d9bf0841a5 100644 --- a/PWGJE/Core/JetHFUtilities.h +++ b/PWGJE/Core/JetHFUtilities.h @@ -17,34 +17,19 @@ #ifndef PWGJE_CORE_JETHFUTILITIES_H_ #define PWGJE_CORE_JETHFUTILITIES_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 "PWGHF/DataModel/DerivedTablesStored.h" - -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/Core/JetFinder.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/DecayChannelsLegacy.h" #include "PWGJE/DataModel/Jet.h" +#include +#include + +#include +#include +#include +#include +#include + namespace jethfutilities { @@ -54,7 +39,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>; } /** @@ -63,7 +48,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>; } /** @@ -84,13 +69,121 @@ 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 Ds table + */ +template +constexpr bool isDsCandidate() +{ + return std::is_same_v, o2::aod::CandidatesDsData::iterator> || std::is_same_v, o2::aod::CandidatesDsData::filtered_iterator> || std::is_same_v, o2::aod::CandidatesDsMCD::iterator> || std::is_same_v, o2::aod::CandidatesDsMCD::filtered_iterator>; +} + +/** + * returns true if the particle is from a Ds MC table + */ +template +constexpr bool isDsMcCandidate() +{ + return std::is_same_v, o2::aod::CandidatesDsMCP::iterator> || std::is_same_v, o2::aod::CandidatesDsMCP::filtered_iterator>; +} + +/** + * returns true if the table is a Ds table + */ +template +constexpr bool isDsTable() +{ + return isDsCandidate() || isDsCandidate(); +} + +/** + * returns true if the table is a Ds MC table + */ +template +constexpr bool isDsMcTable() +{ + return isDsMcCandidate() || isDsMcCandidate(); +} + +/** + * returns true if the candidate is from a D* table + */ +template +constexpr bool isDstarCandidate() +{ + return std::is_same_v, o2::aod::CandidatesDstarData::iterator> || std::is_same_v, o2::aod::CandidatesDstarData::filtered_iterator> || std::is_same_v, o2::aod::CandidatesDstarMCD::iterator> || std::is_same_v, o2::aod::CandidatesDstarMCD::filtered_iterator>; +} + +/** + * returns true if the particle is from a D* MC table + */ +template +constexpr bool isDstarMcCandidate() +{ + return std::is_same_v, o2::aod::CandidatesDstarMCP::iterator> || std::is_same_v, o2::aod::CandidatesDstarMCP::filtered_iterator>; +} + +/** + * returns true if the table is a D* table + */ +template +constexpr bool isDstarTable() +{ + return isDstarCandidate() || isDstarCandidate(); +} + +/** + * returns true if the table is a D* MC table + */ +template +constexpr bool isDstarMcTable() +{ + return isDstarMcCandidate() || isDstarMcCandidate(); +} + /** * 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>; } /** @@ -99,7 +192,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>; } /** @@ -120,13 +213,49 @@ constexpr bool isLcMcTable() return isLcMcCandidate() || isLcMcCandidate(); } +/** + * returns true if the candidate is from a B0 table + */ +template +constexpr bool isB0Candidate() +{ + return std::is_same_v, o2::aod::CandidatesB0Data::iterator> || std::is_same_v, o2::aod::CandidatesB0Data::filtered_iterator> || std::is_same_v, o2::aod::CandidatesB0MCD::iterator> || std::is_same_v, o2::aod::CandidatesB0MCD::filtered_iterator>; +} + +/** + * returns true if the particle is from a B0 MC table + */ +template +constexpr bool isB0McCandidate() +{ + return std::is_same_v, o2::aod::CandidatesB0MCP::iterator> || std::is_same_v, o2::aod::CandidatesB0MCP::filtered_iterator>; +} + +/** + * returns true if the table is a B0 table + */ +template +constexpr bool isB0Table() +{ + return isB0Candidate() || isB0Candidate(); +} + +/** + * returns true if the table is a B0 MC table + */ +template +constexpr bool isB0McTable() +{ + return isB0McCandidate() || isB0McCandidate(); +} + /** * returns true if the candidate is from a Bplus table */ 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>; } /** @@ -135,7 +264,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>; } /** @@ -156,6 +285,42 @@ constexpr bool isBplusMcTable() return isBplusMcCandidate() || isBplusMcCandidate(); } +/** + * returns true if the candidate is from a XicToXiPiPi table + */ +template +constexpr bool isXicToXiPiPiCandidate() +{ + return std::is_same_v, o2::aod::CandidatesXicToXiPiPiData::iterator> || std::is_same_v, o2::aod::CandidatesXicToXiPiPiData::filtered_iterator> || std::is_same_v, o2::aod::CandidatesXicToXiPiPiMCD::iterator> || std::is_same_v, o2::aod::CandidatesXicToXiPiPiMCD::filtered_iterator>; +} + +/** + * returns true if the particle is from a XicToXiPiPi MC table + */ +template +constexpr bool isXicToXiPiPiMcCandidate() +{ + return std::is_same_v, o2::aod::CandidatesXicToXiPiPiMCP::iterator> || std::is_same_v, o2::aod::CandidatesXicToXiPiPiMCP::filtered_iterator>; +} + +/** + * returns true if the table is a XicToXiPiPi table + */ +template +constexpr bool isXicToXiPiPiTable() +{ + return isXicToXiPiPiCandidate() || isXicToXiPiPiCandidate(); +} + +/** + * returns true if the table is a XicToXiPiPi MC table + */ +template +constexpr bool isXicToXiPiPiMcTable() +{ + return isXicToXiPiPiMcCandidate() || isXicToXiPiPiMcCandidate(); +} + /** * returns true if the candidate is from a HF table * * @param candidate candidate that is being checked @@ -165,10 +330,20 @@ constexpr bool isHFCandidate() { if constexpr (isD0Candidate()) { return true; + } else if constexpr (isDplusCandidate()) { + return true; + } else if constexpr (isDsCandidate()) { + return true; + } else if constexpr (isDstarCandidate()) { + return true; } else if constexpr (isLcCandidate()) { return true; + } else if constexpr (isB0Candidate()) { + return true; } else if constexpr (isBplusCandidate()) { return true; + } else if constexpr (isXicToXiPiPiCandidate()) { + return true; } else { return false; } @@ -183,9 +358,19 @@ constexpr bool isHFMcCandidate() { if constexpr (isD0McCandidate()) { return true; + } else if constexpr (isDplusMcCandidate()) { + return true; + } else if constexpr (isDsMcCandidate()) { + return true; + } else if constexpr (isDstarMcCandidate()) { + return true; } else if constexpr (isLcMcCandidate()) { return true; - } else if constexpr (isBplusMcCandidate()) { + } else if constexpr (isB0McCandidate()) { + return true; + } else if constexpr (isXicToXiPiPiMcCandidate()) { + return true; + } else if constexpr (isDstarMcCandidate()) { return true; } else { return false; @@ -200,10 +385,20 @@ constexpr bool isHFTable() { if constexpr (isD0Candidate() || isD0Candidate()) { return true; + } else if constexpr (isDplusCandidate() || isDplusCandidate()) { + return true; + } else if constexpr (isDsCandidate() || isDsCandidate()) { + return true; + } else if constexpr (isDstarCandidate() || isDstarCandidate()) { + return true; } else if constexpr (isLcCandidate() || isLcCandidate()) { return true; + } else if constexpr (isB0Candidate() || isB0Candidate()) { + return true; } else if constexpr (isBplusCandidate() || isBplusCandidate()) { return true; + } else if constexpr (isXicToXiPiPiCandidate() || isXicToXiPiPiCandidate()) { + return true; } else { return false; } @@ -217,10 +412,20 @@ constexpr bool isHFMcTable() { if constexpr (isD0McCandidate() || isD0McCandidate()) { return true; + } else if constexpr (isDplusMcCandidate() || isDplusMcCandidate()) { + return true; + } else if constexpr (isDsMcCandidate() || isDsMcCandidate()) { + return true; + } else if constexpr (isDstarMcCandidate() || isDstarMcCandidate()) { + return true; } else if constexpr (isLcMcCandidate() || isLcMcCandidate()) { return true; + } else if constexpr (isB0McCandidate() || isB0McCandidate()) { + return true; } else if constexpr (isBplusMcCandidate() || isBplusMcCandidate()) { return true; + } else if constexpr (isXicToXiPiPiMcCandidate() || isXicToXiPiPiMcCandidate()) { + return true; } else { return false; } @@ -234,37 +439,97 @@ template constexpr bool isMatchedHFCandidate(T const& candidate) { if constexpr (isD0Candidate()) { - if (std::abs(candidate.flagMcMatchRec()) == 1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + return true; + } else { + return false; + } + } else if constexpr (isDplusCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { + return true; + } else { + return false; + } + } else if constexpr (isDsCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) { + return true; + } else { + return false; + } + } else if constexpr (isDstarCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { return true; } else { return false; } } else if constexpr (isLcCandidate()) { - if (std::abs(candidate.flagMcMatchRec()) == 1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + return true; + } else { + return false; + } + } else if constexpr (isB0Candidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::B0ToDminusPi) { return true; } else { return false; } } else if constexpr (isBplusCandidate()) { - if (std::abs(candidate.flagMcMatchRec()) == 1 << o2::aod::hf_cand_bplus::DecayType::BplusToD0Pi) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::BplusToD0Pi) { + return true; + } else { + return false; + } + } else if constexpr (isXicToXiPiPiCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi) { return true; } else { return false; } } else if constexpr (isD0McCandidate()) { - if (std::abs(candidate.flagMcMatchGen()) == 1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK) { + if (std::abs(candidate.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + return true; + } else { + return false; + } + } else if constexpr (isDplusMcCandidate()) { + if (std::abs(candidate.flagMcMatchGen()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { + return true; + } else { + return false; + } + } else if constexpr (isDsMcCandidate()) { + if (std::abs(candidate.flagMcMatchGen()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) { + return true; + } else { + return false; + } + } else if constexpr (isDstarMcCandidate()) { + if (std::abs(candidate.flagMcMatchGen()) == o2::hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { return true; } else { return false; } } else if constexpr (isLcMcCandidate()) { - if (std::abs(candidate.flagMcMatchGen()) == 1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi) { + if (std::abs(candidate.flagMcMatchGen()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + return true; + } else { + return false; + } + } else if constexpr (isB0McCandidate()) { + if (std::abs(candidate.flagMcMatchGen()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::B0ToDminusPi) { return true; } else { return false; } } else if constexpr (isBplusMcCandidate()) { - if (std::abs(candidate.flagMcMatchGen()) == 1 << o2::aod::hf_cand_bplus::DecayType::BplusToD0Pi) { + if (std::abs(candidate.flagMcMatchGen()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::BplusToD0Pi) { + return true; + } else { + return false; + } + } else if constexpr (isXicToXiPiPiMcCandidate()) { + if (std::abs(candidate.flagMcMatchGen()) == o2::aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi) { return true; } else { return false; @@ -279,10 +544,9 @@ constexpr bool isMatchedHFCandidate(T const& candidate) * * @param track track that is being checked * @param candidate HF candidate that is being checked - * @param tracks the track table */ -template -bool isHFDaughterTrack(T& track, U& candidate, V const& /*tracks*/) +template +bool isHFDaughterTrack(T& track, U& candidate) { if constexpr (isD0Candidate()) { if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex()) { @@ -290,14 +554,44 @@ bool isHFDaughterTrack(T& track, U& candidate, V const& /*tracks*/) } 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 (isDsCandidate()) { + if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex() || candidate.prong2Id() == track.globalIndex()) { + return true; + } else { + return false; + } + } else if constexpr (isDstarCandidate()) { + 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; } else { return false; } + } else if constexpr (isB0Candidate()) { + if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex() || candidate.prong2Id() == track.globalIndex() || candidate.prong3Id() == track.globalIndex()) { + return true; + } else { + 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; + } + } else if constexpr (isXicToXiPiPiCandidate()) { + if (candidate.prong0Id() == track.globalIndex() || candidate.prong1Id() == track.globalIndex() || candidate.prong2Id() == track.globalIndex() || candidate.prong3Id() == track.globalIndex() || candidate.prong4Id() == track.globalIndex()) { return true; } else { return false; @@ -308,31 +602,71 @@ bool isHFDaughterTrack(T& track, U& candidate, V const& /*tracks*/) } /** - * returns the index of the JMcParticle matched to the HF candidate + * 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 matchedHFParticleId(const T& candidate, const U& /*tracks*/, const V& /*particles*/) +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().globalIndex(); // can we get the Id directly? + + typename V::iterator candidateDaughterParticle; + if constexpr (isD0Candidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); + } + } + if constexpr (isDplusCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); + } + } + if constexpr (isDsCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::DsToPiKK) { + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); + } + } + if constexpr (isDstarCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { + candidateDaughterParticle = candidate.template prong2_as().template mcParticle_as(); + } + } + if constexpr (isLcCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); + } + } + if constexpr (isB0Candidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::B0ToDminusPi) { + candidateDaughterParticle = candidate.template prong3_as().template mcParticle_as(); + } + } + if constexpr (isBplusCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::hf_decay::hf_cand_beauty::DecayChannelMain::BplusToD0Pi) { + candidateDaughterParticle = candidate.template prong2_as().template mcParticle_as(); + } + } + if constexpr (isXicToXiPiPiCandidate()) { + if (std::abs(candidate.flagMcMatchRec()) == o2::aod::hf_cand_xic_to_xi_pi_pi::DecayType::XicToXiPiPi) { + candidateDaughterParticle = candidate.template prong0_as().template mcParticle_as(); + } + } + return candidateDaughterParticle.template mothers_first_as(); } /** - * returns the JMcParticle matched to the HF candidate + * returns the index of 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*/) +auto matchedHFParticleId(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(); + return (matchedHFParticle(candidate, tracks, particles)).globalIndex(); } /** @@ -341,35 +675,56 @@ auto matchedHFParticle(const T& candidate, const U& /*tracks*/, const V& /*parti * @param candidate HF candidate that is being checked * @param table the table to be sliced */ -template -auto slicedPerHFCandidate(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& perDsCandidate, O const& perDstarCandidate, P const& perLcCandidate, Q const& perB0Candidate, R const& perBplusCandidate, S const& perXicToXiPiPiCandidate) { if constexpr (isD0Candidate()) { return table.sliceBy(perD0Candidate, candidate.globalIndex()); + } else if constexpr (isDplusCandidate()) { + return table.sliceBy(perDplusCandidate, candidate.globalIndex()); + } else if constexpr (isDstarCandidate()) { + return table.sliceBy(perDstarCandidate, candidate.globalIndex()); + } else if constexpr (isDsCandidate()) { + return table.sliceBy(perDsCandidate, candidate.globalIndex()); } else if constexpr (isLcCandidate()) { return table.sliceBy(perLcCandidate, candidate.globalIndex()); + } else if constexpr (isB0Candidate()) { + return table.sliceBy(perB0Candidate, candidate.globalIndex()); } else if constexpr (isBplusCandidate()) { return table.sliceBy(perBplusCandidate, candidate.globalIndex()); + } else if constexpr (isXicToXiPiPiCandidate()) { + return table.sliceBy(perXicToXiPiPiCandidate, candidate.globalIndex()); } else { return table; } } /** - * returns a slice of the table depending on the type of the HF candidate and index of the collision + * returns a slice of the table depending on the index of the HF candidate * - * @param candidate HF candidate that is being checked + * @param HFTable HF table type + * @param jet jet that is being sliced based on * @param table the table to be sliced */ -template -auto slicedPerHFCollision(T const& table, U const& /*candidates*/, V const& collision, M const& D0CollisionPerCollision, N const& LcCollisionPerCollision, O const& BplusCollisionPerCollision) +template +auto slicedPerHFJet(T const& table, U const& jet, V const& perD0Jet, M const& perDplusJet, N const& perDsJet, O const& perDstarJet, P const& perLcJet, Q const& perB0Jet, R const& perBplusJet, S const& perXicToXiPiPiJet) { - if constexpr (isD0Table() || isD0McTable()) { - return table.sliceBy(D0CollisionPerCollision, collision.globalIndex()); - } else if constexpr (isLcTable() || isLcMcTable()) { - return table.sliceBy(LcCollisionPerCollision, collision.globalIndex()); - } else if constexpr (isBplusTable() || isBplusMcTable()) { - return table.sliceBy(BplusCollisionPerCollision, collision.globalIndex()); + if constexpr (isD0Table() || isD0McTable()) { + return table.sliceBy(perD0Jet, jet.globalIndex()); + } else if constexpr (isDplusTable() || isDplusMcTable()) { + return table.sliceBy(perDplusJet, jet.globalIndex()); + } else if constexpr (isDstarTable() || isDstarMcTable()) { + return table.sliceBy(perDstarJet, jet.globalIndex()); + } else if constexpr (isDsTable() || isDsMcTable()) { + return table.sliceBy(perDsJet, jet.globalIndex()); + } else if constexpr (isLcTable() || isLcMcTable()) { + return table.sliceBy(perLcJet, jet.globalIndex()); + } else if constexpr (isB0Table() || isB0McTable()) { + return table.sliceBy(perB0Jet, jet.globalIndex()); + } else if constexpr (isBplusTable() || isBplusMcTable()) { + return table.sliceBy(perBplusJet, jet.globalIndex()); + } else if constexpr (isXicToXiPiPiTable() || isXicToXiPiPiMcTable()) { + return table.sliceBy(perXicToXiPiPiJet, jet.globalIndex()); } else { return table; } @@ -383,15 +738,7 @@ auto slicedPerHFCollision(T const& table, U const& /*candidates*/, V const& coll template int getHFCandidateCollisionId(T const& candidate) { - if constexpr (isD0Candidate()) { - return candidate.hfCollBaseId(); - } else if constexpr (isLcCandidate()) { - return candidate.hfCollBaseId(); - } else if constexpr (isBplusCandidate()) { - return candidate.hfCollBaseId(); - } else { - return -1; - } + return candidate.hfCollBaseId(); } /** @@ -402,15 +749,7 @@ int getHFCandidateCollisionId(T const& candidate) template int getHFMcCandidateCollisionId(T const& candidate) { - if constexpr (isD0McCandidate()) { - return candidate.hfMcCollBaseId(); - } else if constexpr (isLcMcCandidate()) { - return candidate.hfMcCollBaseId(); - } else if constexpr (isBplusMcCandidate()) { - return candidate.hfMcCollBaseId(); - } else { - return -1; - } + return candidate.hfMcCollBaseId(); } /** @@ -423,12 +762,20 @@ 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 (isDsCandidate() || isDsMcCandidate()) { + return static_cast(o2::constants::physics::Pdg::kDS); + } else if constexpr (isDstarCandidate() || isDstarMcCandidate()) { + return static_cast(o2::constants::physics::Pdg::kDStar); + } else if constexpr (isLcCandidate() || isLcMcCandidate()) { return static_cast(o2::constants::physics::Pdg::kLambdaCPlus); - } - if constexpr (isBplusCandidate() || isBplusMcCandidate()) { + } else if constexpr (isB0Candidate() || isB0McCandidate()) { + return static_cast(o2::constants::physics::Pdg::kB0); + } else if constexpr (isBplusCandidate() || isBplusMcCandidate()) { return static_cast(o2::constants::physics::Pdg::kBPlus); + } else if constexpr (isXicToXiPiPiCandidate() || isXicToXiPiPiMcCandidate()) { + return static_cast(o2::constants::physics::Pdg::kXiCPlus); } else { return 0; } @@ -442,12 +789,20 @@ 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 (isDsTable() || isDsMcTable()) { + return static_cast(o2::constants::physics::Pdg::kDS); + } else if constexpr (isDstarTable() || isDstarMcTable()) { + return static_cast(o2::constants::physics::Pdg::kDStar); + } else if constexpr (isLcTable() || isLcMcTable()) { return static_cast(o2::constants::physics::Pdg::kLambdaCPlus); - } - if constexpr (isBplusTable() || isBplusMcTable()) { + } else if constexpr (isB0Table() || isB0McTable()) { + return static_cast(o2::constants::physics::Pdg::kB0); + } else if constexpr (isBplusTable() || isBplusMcTable()) { return static_cast(o2::constants::physics::Pdg::kBPlus); + } else if constexpr (isXicToXiPiPiTable() || isXicToXiPiPiMcTable()) { + return static_cast(o2::constants::physics::Pdg::kXiCPlus); } else { return 0; } @@ -463,12 +818,20 @@ 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 (isDsCandidate() || isDsMcCandidate()) { + return static_cast(o2::constants::physics::MassDS); + } else if constexpr (isDstarCandidate() || isDstarMcCandidate()) { + return static_cast(o2::constants::physics::MassDStar); + } else if constexpr (isLcCandidate() || isLcMcCandidate()) { return static_cast(o2::constants::physics::MassLambdaCPlus); - } - if constexpr (isBplusCandidate() || isBplusMcCandidate()) { + } else if constexpr (isB0Candidate() || isB0McCandidate()) { + return static_cast(o2::constants::physics::MassB0); + } else if constexpr (isBplusCandidate() || isBplusMcCandidate()) { return static_cast(o2::constants::physics::MassBPlus); + } else if constexpr (isXicToXiPiPiCandidate() || isXicToXiPiPiMcCandidate()) { + return static_cast(o2::constants::physics::MassXiCPlus); } else { return -1.0; } @@ -483,12 +846,20 @@ 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 (isDsTable() || isDsMcTable()) { + return static_cast(o2::constants::physics::MassDS); + } else if constexpr (isDstarTable() || isDstarMcTable()) { + return static_cast(o2::constants::physics::MassDStar); + } else if constexpr (isLcTable() || isLcMcTable()) { return static_cast(o2::constants::physics::MassLambdaCPlus); - } - if constexpr (isBplusTable() || isBplusMcTable()) { + } else if constexpr (isB0Table() || isB0McTable()) { + return static_cast(o2::constants::physics::MassB0); + } else if constexpr (isBplusTable() || isBplusMcTable()) { return static_cast(o2::constants::physics::MassBPlus); + } else if constexpr (isXicToXiPiPiTable() || isXicToXiPiPiMcTable()) { + return static_cast(o2::constants::physics::MassXiCPlus); } else { return -1.0; } @@ -502,76 +873,157 @@ float getHFTablePDGMass() template float getHFCandidateInvariantMass(T const& candidate) { - if constexpr (isD0Candidate()) { - return candidate.m(); - } - if constexpr (isLcCandidate()) { - return candidate.m(); - } - if constexpr (isBplusCandidate()) { - return candidate.m(); - } else { - return -1.0; - } + return candidate.m(); } template -void fillD0CollisionTable(T const& collision, U& D0CollisionTable, int32_t& D0CollisionTableIndex) +void fillHFCollisionTable(T const& collision, U& HFCollisionTable) { - D0CollisionTable(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.centFV0A(), collision.multZeqNTracksPV()); - D0CollisionTableIndex = D0CollisionTable.lastIndex(); + HFCollisionTable(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.centFV0A(), collision.multZeqNTracksPV()); } template -void fillLcCollisionTable(T const& collision, U& LcCollisionTable, int32_t& LcCollisionTableIndex) +void fillHFMcCollisionTable(T const& mcCollision, U& HFMcCollisionTable) { - LcCollisionTable(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.centFV0A(), collision.multZeqNTracksPV()); - LcCollisionTableIndex = LcCollisionTable.lastIndex(); + HFMcCollisionTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.centFT0M()); } -template -void fillHFCollisionTable(T const& collision, U const& /*candidates*/, V& HFCollisionTable, int32_t& HFCollisionTableIndex) +template +void fillD0CandidateTable(T const& candidate, U& D0ParTable, V& D0ParETable, M& D0MlTable, N& D0MCDTable) { - if constexpr (isD0Table()) { - fillD0CollisionTable(collision, HFCollisionTable, HFCollisionTableIndex); - } - if constexpr (isLcTable()) { - fillLcCollisionTable(collision, HFCollisionTable, HFCollisionTableIndex); + D0ParTable( + 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.nSigTpcPiExpKa(), + candidate.nSigTofPiExpKa(), + candidate.nSigTpcTofPiExpKa(), + candidate.nSigTpcKaExpKa(), + candidate.nSigTofKaExpKa(), + candidate.nSigTpcTofKaExpKa(), + candidate.maxNormalisedDeltaIP(), + candidate.impactParameterProduct()); + + D0ParETable( + candidate.xSecondaryVertex(), + candidate.ySecondaryVertex(), + candidate.zSecondaryVertex(), + candidate.errorDecayLength(), + candidate.errorDecayLengthXY(), + candidate.kfTopolChi2OverNdf(), + candidate.rSecondaryVertex(), + candidate.pProng0(), + candidate.pProng1(), + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.errorImpactParameter0(), + candidate.errorImpactParameter1(), + candidate.cosThetaStar(), + candidate.ct()); + + 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 fillD0McCollisionTable(T const& mcCollision, U& D0McCollisionTable, int32_t& D0McCollisionTableIndex) +template +void fillDplusCandidateTable(T const& candidate, U& DplusParTable, V& DplusParETable, M& DplusMlTable, N& DplusMCDTable) { - D0McCollisionTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); - D0McCollisionTableIndex = D0McCollisionTable.lastIndex(); -} -template -void fillLcMcCollisionTable(T const& mcCollision, U& LcMcCollisionTable, int32_t& LcMcCollisionTableIndex) -{ - LcMcCollisionTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); - LcMcCollisionTableIndex = LcMcCollisionTable.lastIndex(); -} + 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()); -template -void fillHFMcCollisionTable(T const& mcCollision, U const& /*candidates*/, V& HFMcCollisionTable, int32_t& HFMcCollisionTableIndex) -{ - if constexpr (isD0McTable()) { - fillD0McCollisionTable(mcCollision, HFMcCollisionTable, HFMcCollisionTableIndex); - } - if constexpr (isLcMcTable()) { - fillLcMcCollisionTable(mcCollision, HFMcCollisionTable, HFMcCollisionTableIndex); + 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)); + DplusMlTable(mlScoresVector); + + if constexpr (isMc) { + DplusMCDTable(candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.isCandidateSwapped(), candidate.flagMcDecayChanRec()); } } -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 fillDsCandidateTable(T const& candidate, U& DsParTable, V& DsParETable, M& DsMlTable, N& DsMCDTable) { - D0BaseTable(collisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.m(), candidate.y()); - D0ParTable( + DsParTable( candidate.chi2PCA(), + candidate.nProngsContributorsPV(), candidate.cpa(), candidate.cpaXY(), candidate.decayLength(), @@ -580,63 +1032,132 @@ void fillD0CandidateTable(T const& candidate, int32_t collisionIndex, U& D0BaseT candidate.decayLengthXYNormalised(), candidate.ptProng0(), candidate.ptProng1(), + candidate.ptProng2(), candidate.impactParameter0(), candidate.impactParameter1(), + candidate.impactParameter2(), candidate.impactParameterNormalised0(), candidate.impactParameterNormalised1(), + candidate.impactParameterNormalised2(), 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.maxNormalisedDeltaIP(), - candidate.impactParameterProduct()); + candidate.nSigTpcPi2(), + candidate.nSigTpcKa2(), + candidate.nSigTofPi2(), + candidate.nSigTofKa2(), + candidate.nSigTpcTofPi2(), + candidate.nSigTpcTofKa2()); - D0ParETable( + DsParETable( candidate.xSecondaryVertex(), candidate.ySecondaryVertex(), candidate.zSecondaryVertex(), candidate.errorDecayLength(), candidate.errorDecayLengthXY(), - candidate.kfTopolChi2OverNdf(), 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.cosThetaStar(), + candidate.errorImpactParameter2(), candidate.ct()); - D0SelectionFlagTable(candidate.candidateSelFlag()); + std::vector mlScoresVector; + auto mlScoresSpan = candidate.mlScores(); + std::copy(mlScoresSpan.begin(), mlScoresSpan.end(), std::back_inserter(mlScoresVector)); + DsMlTable(mlScoresVector); + if constexpr (isMc) { - D0MCDTable(candidate.flagMcMatchRec(), candidate.originMcRec()); + DsMCDTable(candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.isCandidateSwapped(), candidate.flagMcDecayChanRec()); } +} + +template +void fillDstarCandidateTable(T const& candidate, U& DstarParTable, V& DstarParDaughterTable, M& DstarMlTable, N& DstarMCDTable) +{ + + DstarParTable( + candidate.pxProng0(), + candidate.pyProng0(), + candidate.pzProng0(), + candidate.pxProng1(), + candidate.pyProng1(), + candidate.pzProng1(), + candidate.signProng1(), + candidate.impactParameter1(), + candidate.impactParameterNormalised1(), + candidate.nSigTpcPi1(), + candidate.nSigTofPi1(), + candidate.nSigTpcTofPi1()); + + DstarParDaughterTable( + candidate.chi2PCACharm(), + candidate.cpaCharm(), + candidate.cpaXYCharm(), + candidate.decayLengthCharm(), + candidate.decayLengthXYCharm(), + candidate.decayLengthNormalisedCharm(), + candidate.decayLengthXYNormalisedCharm(), + candidate.pxProng0Charm(), + candidate.pyProng0Charm(), + candidate.pzProng0Charm(), + candidate.pxProng1Charm(), + candidate.pyProng1Charm(), + candidate.pzProng1Charm(), + candidate.invMassCharm(), + candidate.impactParameter0Charm(), + candidate.impactParameter1Charm(), + candidate.impactParameterNormalised0Charm(), + candidate.impactParameterNormalised1Charm(), + candidate.nSigTpcPi0Charm(), + candidate.nSigTofPi0Charm(), + candidate.nSigTpcTofPi0Charm(), + candidate.nSigTpcKa0Charm(), + candidate.nSigTofKa0Charm(), + candidate.nSigTpcTofKa0Charm(), + candidate.nSigTpcPi1Charm(), + candidate.nSigTofPi1Charm(), + candidate.nSigTpcTofPi1Charm(), + candidate.nSigTpcKa1Charm(), + candidate.nSigTofKa1Charm(), + candidate.nSigTpcTofKa1Charm()); std::vector mlScoresVector; auto mlScoresSpan = candidate.mlScores(); std::copy(mlScoresSpan.begin(), mlScoresSpan.end(), std::back_inserter(mlScoresVector)); - D0MlTable(mlScoresVector); + DstarMlTable(mlScoresVector); - D0CandidateTableIndex = D0BaseTable.lastIndex(); + if constexpr (isMc) { + DstarMCDTable( + candidate.flagMcMatchRec(), + candidate.flagMcMatchRecCharm(), + candidate.originMcRec(), + candidate.ptBhadMotherPart(), + candidate.pdgBhadMotherPart(), + candidate.nTracksDecayed()); + } } -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(), candidate.y()); LcParTable( candidate.chi2PCA(), @@ -696,52 +1217,282 @@ 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 fillHFCandidateTable(T const& candidate, int32_t collisionIndex, U& HFBaseTable, V& HFParTable, M& HFParETable, N& HFSelectionFlagTable, O& HFMlTable, P& HFMCDTable, int32_t& HFCandidateTableIndex) +void fillB0CandidateTable(T const& candidate, U& B0ParTable, V& B0ParETable, M& B0ParD0Table, N& B0MlTable, O& B0MlD0Table, P& B0MCDTable) { - 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); + + B0ParTable( + 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()); + + B0ParETable( + 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()); + + B0ParD0Table( + candidate.chi2PCACharm(), + candidate.nProngsContributorsPVCharm(), + candidate.cpaCharm(), + candidate.cpaXYCharm(), + candidate.decayLengthCharm(), + candidate.decayLengthXYCharm(), + candidate.decayLengthNormalisedCharm(), + candidate.decayLengthXYNormalisedCharm(), + candidate.ptProng0Charm(), + candidate.ptProng1Charm(), + candidate.ptProng2Charm(), + candidate.impactParameter0Charm(), + candidate.impactParameter1Charm(), + candidate.impactParameter2Charm(), + candidate.impactParameterNormalised0Charm(), + candidate.impactParameterNormalised1Charm(), + candidate.impactParameterNormalised2Charm(), + candidate.nSigTpcPi0Charm(), + candidate.nSigTofPi0Charm(), + candidate.nSigTpcTofPi0Charm(), + candidate.nSigTpcKa1Charm(), + candidate.nSigTofKa1Charm(), + candidate.nSigTpcTofKa1Charm(), + candidate.nSigTpcPi2Charm(), + candidate.nSigTofPi2Charm(), + candidate.nSigTpcTofPi2Charm()); + + // B0SelectionFlagTable(candidate.candidateSelFlag()); + + B0MlTable(candidate.mlScoreSig()); + + std::vector mlScoresCharmVector; + auto mlScoresCharmSpan = candidate.mlScoresCharm(); + std::copy(mlScoresCharmSpan.begin(), mlScoresCharmSpan.end(), std::back_inserter(mlScoresCharmVector)); + B0MlD0Table(mlScoresCharmVector); + + if constexpr (isMc) { + B0MCDTable(candidate.flagMcMatchRec(), candidate.originMcRec()); } } -template -void fillD0CandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& D0PBaseTable, int32_t& D0CandidateTableIndex) +// need to update this +template +void fillBplusCandidateTable(T const& candidate, U& BplusParTable, V& BplusParETable, M& BplusParD0Table, N& BplusMlTable, O& BplusMlD0Table, P& BplusMCDTable) { - D0PBaseTable(mcCollisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.y(), candidate.flagMcMatchGen(), candidate.originMcGen()); - D0CandidateTableIndex = D0PBaseTable.lastIndex(); + + 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 fillLcCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& LcPBaseTable, int32_t& LcCandidateTableIndex) + +template +void fillXicToXiPiPiCandidateTable(T const& candidate, U& XicToXiPiPiParTable, V& XicToXiPiPiParETable, M& XicToXiPiPiMlTable, N& XicToXiPiPiMCDTable) { - LcPBaseTable(mcCollisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.y(), candidate.flagMcMatchGen(), candidate.originMcGen()); - LcCandidateTableIndex = LcPBaseTable.lastIndex(); + + XicToXiPiPiParTable( + candidate.sign(), + candidate.ptProngXi(), + candidate.ptProngPi0(), + candidate.ptProngPi1(), + candidate.invMassXi(), + candidate.invMassLambda(), + candidate.invMassXiPi0(), + candidate.invMassXiPi1(), + candidate.chi2PCA(), + candidate.ct(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.decayLengthNormalised(), + candidate.decayLengthXYNormalised(), + candidate.cpa(), + candidate.cpaXY(), + candidate.cpaXi(), + candidate.cpaXYXi(), + candidate.cpaLambda(), + candidate.cpaXYLambda(), + candidate.impactParameterXi(), + candidate.impactParameterNormalisedXi(), + candidate.impactParameterPi0(), + candidate.impactParameterNormalisedPi0(), + candidate.impactParameterPi1(), + candidate.impactParameterNormalisedPi1(), + candidate.maxNormalisedDeltaIP()); + + XicToXiPiPiParETable( + candidate.cpaLambdaToXi(), + candidate.cpaXYLambdaToXi(), + candidate.pProngPi0(), + candidate.pProngPi1(), + 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()); + + std::vector mlScoresVector; + auto mlScoresSpan = candidate.mlScores(); + std::copy(mlScoresSpan.begin(), mlScoresSpan.end(), std::back_inserter(mlScoresVector)); + XicToXiPiPiMlTable(mlScoresVector); + + if constexpr (isMc) { + XicToXiPiPiMCDTable(candidate.flagMcMatchRec(), candidate.originMcRec()); + } } -template -void fillHFCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& BaseMcTable, int32_t& candidateTableIndex) +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) { - if constexpr (isD0McCandidate()) { - fillD0CandidateMcTable(candidate, mcCollisionIndex, BaseMcTable, candidateTableIndex); + HFBaseTable(collisionIndex, candidate.pt(), candidate.eta(), candidate.phi(), candidate.m(), candidate.y()); + HFSelectionFlagTable(candidate.candidateSelFlag()); + + if constexpr (isD0Candidate()) { + fillD0CandidateTable(candidate, HFParTable, HFParETable, HFMlTable, HFMCDTable); } - if constexpr (isLcMcCandidate()) { - fillLcCandidateMcTable(candidate, mcCollisionIndex, BaseMcTable, candidateTableIndex); + if constexpr (isDplusCandidate()) { + fillDplusCandidateTable(candidate, HFParTable, HFParETable, HFMlTable, HFMCDTable); + } + if constexpr (isDsCandidate()) { + fillDsCandidateTable(candidate, HFParTable, HFParETable, HFMlTable, HFMCDTable); + } + if constexpr (isDstarCandidate()) { + fillDstarCandidateTable(candidate, HFParTable, HFParDaughterTable, HFMlTable, HFMCDTable); + } + if constexpr (isLcCandidate()) { + fillLcCandidateTable(candidate, HFParTable, HFParETable, HFMlTable, HFMCDTable); } + if constexpr (isB0Candidate()) { + fillB0CandidateTable(candidate, HFParTable, HFParETable, HFParDaughterTable, HFMlTable, HFMlDaughterTable, HFMCDTable); + } + if constexpr (isBplusCandidate()) { + fillBplusCandidateTable(candidate, HFParTable, HFParETable, HFParDaughterTable, HFMlTable, HFMlDaughterTable, HFMCDTable); + } + if constexpr (isXicToXiPiPiCandidate()) { + fillXicToXiPiPiCandidateTable(candidate, HFParTable, HFParETable, HFMlTable, HFMCDTable); + } +} + +template +void fillHFCandidateMcTable(T const& candidate, int32_t mcCollisionIndex, U& BaseMcTable) +{ + 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 b88ad32337c..cc972fc0a9c 100644 --- a/PWGJE/Core/JetMatchingUtilities.h +++ b/PWGJE/Core/JetMatchingUtilities.h @@ -20,26 +20,25 @@ #ifndef PWGJE_CORE_JETMATCHINGUTILITIES_H_ #define PWGJE_CORE_JETMATCHINGUTILITIES_H_ -#include -#include -#include -#include -#include +#include "PWGJE/Core/JetCandidateUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include + +#include + +#include + #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/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 "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetCandidateUtilities.h" +#include namespace jetmatchingutilities { @@ -124,13 +123,13 @@ std::tuple, std::vector> MatchJetsGeometricallyImpl( const std::vector& jetsBaseEta, std::vector jetsBasePhiForMatching, std::vector jetsBaseEtaForMatching, - const std::vector jetMapBaseToJetIndex, + const std::vector& jetMapBaseToJetIndex, const std::vector& jetsTagPhi, const std::vector& jetsTagEta, std::vector jetsTagPhiForMatching, std::vector jetsTagEtaForMatching, - const std::vector jetMapTagToJetIndex, - double maxMatchingDistance) + const std::vector& jetMapTagToJetIndex, + const double maxMatchingDistance) { // Validation // If no jets in either collection, then return immediately. @@ -331,27 +330,25 @@ void MatchGeo(T const& jetsBasePerCollision, U const& jetsTagPerCollision, std:: } std::tie(baseToTagMatchingGeoIndex, tagToBaseMatchingGeoIndex) = MatchJetsGeometrically(jetsBasePhi, jetsBaseEta, jetsTagPhi, jetsTagEta, maxMatchingDistance); // change max distnace to a function call int jetBaseIndex = 0; + int jetTagIndex = 0; for (const auto& jetBase : jetsBasePerCollision) { if (std::round(jetBase.r()) != std::round(jetR)) { continue; } - int jetTagIndex = baseToTagMatchingGeoIndex[jetBaseIndex]; - int jetTagGlobalIndex; + jetTagIndex = baseToTagMatchingGeoIndex[jetBaseIndex]; if (jetTagIndex > -1 && jetTagIndex < jetsTagPerCollision.size()) { - jetTagGlobalIndex = jetsTagPerCollision.iteratorAt(jetTagIndex).globalIndex(); + int jetTagGlobalIndex = jetsTagPerCollision.iteratorAt(jetTagIndex).globalIndex(); baseToTagMatchingGeo[jetBase.globalIndex()].push_back(jetTagGlobalIndex); } jetBaseIndex++; } - int jetTagIndex = 0; for (const auto& jetTag : jetsTagPerCollision) { if (std::round(jetTag.r()) != std::round(jetR)) { continue; } - int jetBaseIndex = tagToBaseMatchingGeoIndex[jetTagIndex]; - int jetBaseGlobalIndex; + jetBaseIndex = tagToBaseMatchingGeoIndex[jetTagIndex]; if (jetBaseIndex > -1 && jetBaseIndex < jetsBasePerCollision.size()) { - jetBaseGlobalIndex = jetsBasePerCollision.iteratorAt(jetBaseIndex).globalIndex(); + int jetBaseGlobalIndex = jetsBasePerCollision.iteratorAt(jetBaseIndex).globalIndex(); tagToBaseMatchingGeo[jetTag.globalIndex()].push_back(jetBaseGlobalIndex); } jetTagIndex++; @@ -364,8 +361,14 @@ template >& baseToTagMatchingHF, std::vector>& tagToBaseMatchingHF, V const& /*candidatesBase*/, M const& /*candidatesTag*/, N const& tracksBase, O const& tracksTag) { for (const auto& jetBase : jetsBasePerCollision) { + 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; } @@ -406,8 +409,8 @@ auto constexpr getConstituentId(T const& track) } } -template -float getPtSum(T const& tracksBase, U const& clustersBase, V const& tracksTag, O const& clustersTag) +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.; @@ -427,7 +430,7 @@ float getPtSum(T const& tracksBase, U const& clustersBase, V const& tracksTag, O if constexpr (isEMCAL) { if constexpr (jetsTagIsMc) { for (const auto& clusterBase : clustersBase) { - for (const auto& clusterBaseParticleId : clusterBase.mcParticleIds()) { + for (const auto& clusterBaseParticleId : clusterBase.mcParticlesIds()) { bool isClusterMatched = false; for (const auto& trackTag : tracksTag) { if (clusterBaseParticleId != -1 && clusterBaseParticleId == trackTag.globalIndex()) { @@ -450,7 +453,7 @@ float getPtSum(T const& tracksBase, U const& clustersBase, V const& tracksTag, O auto trackBaseId = trackBase.globalIndex(); for (const auto& clusterTag : clustersTag) { bool isClusterMatched = false; - for (const auto& clusterTagParticleId : clusterTag.mcParticleIds()) { + for (const auto& clusterTagParticleId : clusterTag.mcParticlesIds()) { if (trackBaseId != -1 && trackBaseId == clusterTagParticleId) { ptSum += trackBase.pt(); isClusterMatched = true; @@ -464,36 +467,85 @@ float getPtSum(T const& tracksBase, U const& clustersBase, V const& tracksTag, O } } } + 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; + } + } + } return ptSum; } template auto getConstituents(T const& jet, U const& /*constituents*/) { - if constexpr (jetfindingutilities::isEMCALTable()) { + 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& clustersBase, N const& tracksTag, O const& clustersTag, float minPtFraction) +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 = 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 = getConstituents(jetTag, tracksTag); auto jetTagClusters = getConstituents(jetTag, clustersTag); + auto jetTagCandidates = getConstituents(jetTag, candidatesTag); - ptSumBase = getPtSum < jetfindingutilities::isEMCALTable() || jetfindingutilities::isEMCALTable(), jetsBaseIsMc, jetsTagIsMc > (jetBaseTracks, jetBaseClusters, jetTagTracks, jetTagClusters); - ptSumTag = getPtSum < jetfindingutilities::isEMCALTable() || jetfindingutilities::isEMCALTable(), jetsTagIsMc, jetsBaseIsMc > (jetTagTracks, jetTagClusters, jetBaseTracks, jetBaseClusters); + constexpr bool IsEMCAL{jetfindingutilities::isEMCALClusterTable() || jetfindingutilities::isEMCALClusterTable()}; + constexpr bool IsCandidate{(jetcandidateutilities::isCandidateTable() || jetcandidateutilities::isCandidateMcTable()) && (jetcandidateutilities::isCandidateTable

() || jetcandidateutilities::isCandidateMcTable

())}; + ptSumBase = getPtSum(jetBaseTracks, jetBaseCandidates, jetBaseClusters, jetTagTracks, jetTagCandidates, jetTagClusters, tracksBase, tracksTag); + ptSumTag = getPtSum(jetTagTracks, jetTagCandidates, jetTagClusters, jetBaseTracks, jetBaseCandidates, jetBaseClusters, tracksTag, tracksBase); if (ptSumBase > jetBase.pt() * minPtFraction) { baseToTagMatchingPt[jetBase.globalIndex()].push_back(jetTag.globalIndex()); } @@ -506,7 +558,7 @@ 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& clustersBase, P const& tracksTag, R const& clustersTag, bool doMatchingGeo, bool doMatchingHf, bool doMatchingPt, float maxMatchingDistance, float minPtFraction) +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) { @@ -514,14 +566,179 @@ void doAllMatching(T const& jetsBasePerCollision, U const& jetsTagPerCollision, } // pt matching if (doMatchingPt) { - MatchPt(jetsBasePerCollision, jetsTagPerCollision, baseToTagMatchingPt, tagToBaseMatchingPt, tracksBase, clustersBase, tracksTag, clustersTag, minPtFraction); + MatchPt(jetsBasePerCollision, jetsTagPerCollision, baseToTagMatchingPt, tagToBaseMatchingPt, tracksBase, candidatesBase, clustersBase, tracksTag, candidatesTag, clustersTag, minPtFraction); } // HF matching - if constexpr (jetcandidateutilities::isCandidateTable()) { + if constexpr (jetcandidateutilities::isCandidateTable() || jetcandidateutilities::isCandidateMcTable()) { if (doMatchingHf) { MatchHF(jetsBasePerCollision, jetsTagPerCollision, baseToTagMatchingHF, tagToBaseMatchingHF, candidatesBase, candidatesTag, tracksBase, tracksTag); } } } -}; // namespace jetmatchingutilities + +// 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 cf67d789ead..089c1012656 100644 --- a/PWGJE/Core/JetSubstructureUtilities.h +++ b/PWGJE/Core/JetSubstructureUtilities.h @@ -17,28 +17,22 @@ #ifndef PWGJE_CORE_JETSUBSTRUCTUREUTILITIES_H_ #define PWGJE_CORE_JETSUBSTRUCTUREUTILITIES_H_ -#include -#include - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" - -#include "Framework/Logger.h" -#include "PWGJE/DataModel/EMCALClusters.h" - -#include "PWGHF/DataModel/CandidateReconstructionTables.h" - #include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/Core/JetFinder.h" #include "PWGJE/Core/JetCandidateUtilities.h" +#include "PWGJE/Core/JetFinder.h" #include "PWGJE/DataModel/Jet.h" -#include "fastjet/contrib/Nsubjettiness.hh" -#include "fastjet/contrib/AxesDefinition.hh" -#include "fastjet/contrib/MeasureDefinition.hh" -#include "fastjet/contrib/SoftDrop.hh" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include namespace jetsubstructureutilities { @@ -53,15 +47,15 @@ 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 (jetcandidateutilities::isCandidateTable() || jetcandidateutilities::isCandidateMcTable()) { @@ -96,11 +90,11 @@ 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, std::vector::size_type 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); diff --git a/PWGJE/Core/JetTaggingUtilities.h b/PWGJE/Core/JetTaggingUtilities.h index 5e8793ed718..56c4d26b989 100644 --- a/PWGJE/Core/JetTaggingUtilities.h +++ b/PWGJE/Core/JetTaggingUtilities.h @@ -18,20 +18,31 @@ #ifndef PWGJE_CORE_JETTAGGINGUTILITIES_H_ #define PWGJE_CORE_JETTAGGINGUTILITIES_H_ +#include "PWGJE/Core/JetUtilities.h" + +#include "Common/Core/RecoDecay.h" + +#include +#include + +#include +#include + +#include + +#include +#include #include +#include +#include +#include #include -#include +#include +#include #include +#include +#include #include -#include -#include -#include - -#include "TF1.h" -#include "Framework/Logger.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "PWGJE/Core/JetUtilities.h" enum JetTaggingSpecies { none = 0, @@ -39,13 +50,99 @@ enum JetTaggingSpecies { beauty = 2, lightflavour = 3, lightquark = 4, - gluon = 5 + gluon = 5, + udg = 6, + strange = 7, +}; + +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 signedIPz = 0.0; + double signedIPzSign = 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 * @@ -109,28 +206,30 @@ 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); - if (origin == 1 || origin == 2) { // 1=charm , 2=beauty + origin = RecoDecay::getParticleOrigin(particles, particle, searchUpToQuark); + if (origin == RecoDecay::OriginType::Prompt || origin == RecoDecay::OriginType::NonPrompt) { // 1=charm , 2=beauty hftrack = track; - if (origin == 1) { + if (origin == RecoDecay::OriginType::Prompt) { return JetTaggingSpecies::charm; } - if (origin == 2) { + if (origin == RecoDecay::OriginType::NonPrompt) { return JetTaggingSpecies::beauty; } } } + if (hasMcParticle) { return JetTaggingSpecies::lightflavour; } else { @@ -146,18 +245,18 @@ 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 (const auto& particle : jet.template tracks_as()) { - origin = RecoDecay::getCharmHadronOrigin(particles, particle, true); - if (origin == 1 || origin == 2) { // 1=charm , 2=beauty + hfparticle = particle; // for init if origin is 1 or 2, the particle is not hfparticle + int origin = RecoDecay::getParticleOrigin(particles, particle, searchUpToQuark); + if (origin == RecoDecay::OriginType::Prompt || origin == RecoDecay::OriginType::NonPrompt) { // 1=charm , 2=beauty hfparticle = particle; - if (origin == 1) { + if (origin == RecoDecay::OriginType::Prompt) { return JetTaggingSpecies::charm; } - if (origin == 2) { + if (origin == RecoDecay::OriginType::NonPrompt) { return JetTaggingSpecies::beauty; } } @@ -174,11 +273,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; @@ -215,11 +314,11 @@ int mcdJetFromHFShower(T const& jet, U const& tracks, V const& particles, float */ template -int mcpJetFromHFShower(T const& jet, U const& particles, float dRMax = 0.25) +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); @@ -257,8 +356,8 @@ 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) { - if (std::abs(particle.getGenStatusCode() == 23)) { + for (auto const& particle : particles) { + if (std::abs(particle.getGenStatusCode()) == 23) { if (!firstPartonFound) { parton1 = particle; firstPartonFound = true; @@ -292,35 +391,148 @@ int jetOrigin(T const& jet, U const& particles, float dRMax = 0.25) template int16_t getJetFlavor(AnyJet const& jet, AllMCParticles const& mcparticles) { - const int arraySize = 99; + 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; + } + } + } + } - std::array countpartcode; - int count = 0; + if (charmQuark) { + return JetTaggingSpecies::charm; // Charm jet + } + + return JetTaggingSpecies::lightflavour; // Light flavor jet +} + +/** + * return also the s-jet flavor: 1 for c-jet, 2 for b-jet, 7 for s-jet + * 6 for u,d or g jets. + * + * @param AnyJet the jet that we need to study its flavor + * @param AllMCParticles a vector of all the mc particles stack + */ +template +int16_t getSJetFlavor(AnyJet const& jet, AllMCParticles const& mcparticles) +{ + bool charmQuark = false; + bool strangeQuark = false; - for (auto& mcpart : mcparticles) { + for (auto const& mcpart : mcparticles) { int pdgcode = mcpart.pdgCode(); - if (TMath::Abs(pdgcode) == 21 || (TMath::Abs(pdgcode) >= 1 && TMath::Abs(pdgcode) <= 5)) { + 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 (TMath::Abs(pdgcode) == 5) { - return 2; // Beauty jet - } else { - if (count > arraySize - 1) - return 0; - countpartcode[count] = pdgcode; - count++; + if (std::abs(pdgcode) == 5) { + return JetTaggingSpecies::beauty; // Beauty jet + } else if (std::abs(pdgcode) == 4) { + charmQuark = true; + } else if (std::abs(pdgcode) == 3) { + strangeQuark = true; } } } } - for (int ij = 0; ij < count; ij++) { - if (TMath::Abs(countpartcode[ij]) == 4) - return 1; // Charm jet + if (charmQuark) { + return JetTaggingSpecies::charm; // Charm jet + } else if (strangeQuark) { + return JetTaggingSpecies::strange; // Strange jet } - return 0; // Light flavor jet + return JetTaggingSpecies::udg; // Up, Down or Gluon 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; } /** @@ -328,18 +540,13 @@ int16_t getJetFlavor(AnyJet const& jet, AllMCParticles const& mcparticles) * 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; @@ -349,39 +556,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() > static_cast::size_type>(cnt) - 1) { - for (int i = 0; i < cnt; i++) { - if (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); } /** @@ -417,10 +637,10 @@ std::unique_ptr setResolutionFunction(T const& vecParams) * impact parameter significance. */ template -float getTrackProbability(T const& fResoFuncjet, U const& track, const float& minSignImpXYSig = -40) +float getTrackProbability(T const& fResoFuncjet, U const& track, float minSignImpXYSig = -40) { float probTrack = 0; - auto varSignImpXYSig = TMath::Abs(track.dcaXY()) / TMath::Sqrt(track.sigmaDcaXY2()); + 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); @@ -438,8 +658,7 @@ float getTrackProbability(T const& fResoFuncjet, U const& track, const float& mi * 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 @@ -447,38 +666,489 @@ float getTrackProbability(T const& fResoFuncjet, U const& track, const float& mi * 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, 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 (std::vector::size_type i = 0; i < jetTracksPt.size(); i++) { - sumjetProb += (TMath::Power(-1 * TMath::Log(trackjetProb), static_cast(i)) / TMath::Factorial(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, float trackDcaXYMax = 10.0, float trackDcaZMax = 10.0) +{ + for (const auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin || !trackAcceptanceWithDca(constituent, trackDcaXYMax, trackDcaZMax)) { + 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.dcaZ()) * sign, constituent.sigmadcaZ(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), rClosestSV}); + } + + auto compare = [](const BJetTrackParams& tr1, const 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, float trackDcaXYMax = 10.0, float trackDcaZMax = 10.0) +{ + for (const auto& constituent : analysisJet.template tracks_as()) { + + if (constituent.pt() < trackPtMin || !trackAcceptanceWithDca(constituent, trackDcaXYMax, trackDcaZMax)) { + 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.dcaZ()) * sign, constituent.sigmadcaZ(), std::abs(constituent.dcaXYZ()) * sign, constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), 0.0}); + } + + auto compare = [](const BJetTrackParams& tr1, const 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.dcaZ()) * sign, constituent.sigmadcaZ(), 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.dcaZ()) * sign, constituent.sigmadcaZ(), 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..9c0df210987 100644 --- a/PWGJE/Core/JetUtilities.h +++ b/PWGJE/Core/JetUtilities.h @@ -18,16 +18,19 @@ #ifndef PWGJE_CORE_JETUTILITIES_H_ #define PWGJE_CORE_JETUTILITIES_H_ +#include "Common/Core/RecoDecay.h" + +#include + +#include #include +#include #include -#include +#include #include #include -#include - -#include "Framework/Logger.h" -#include "Common/Core/RecoDecay.h" +#include namespace jetutilities { @@ -73,11 +76,6 @@ std::tuple>, std::vector>> MatchCl throw std::invalid_argument("track collection eta and phi sizes don't match. Check the inputs."); } - // for (std::size_t iTrack = 0; iTrack < nTracks; iTrack++) { - // if (trackEta[iTrack] == 0) - // LOG(warning) << "Track eta is 0!"; - // } - // Build the KD-trees using vectors // We build two trees: // treeBase, which contains the base collection. @@ -144,7 +142,66 @@ 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); +} + +/// @brief Background estimator using the perpendicular cone method +/// @param inputParticles +/// @param jet +/// @return Rho, RhoM the underlying event density + +template +std::tuple estimateRhoPerpCone(const T& inputParticles, const U& jet, V perpConeR) +{ + + if (inputParticles.size() == 0) { + return std::make_tuple(0.0, 0.0); + } + + double perpPtDensity1 = 0; + double perpPtDensity2 = 0; + double perpMdDensity1 = 0; + double perpMdDensity2 = 0; + + const double jetPhi = RecoDecay::constrainAngle(jet.phi(), -M_PI); + const double jetEta = jet.eta(); + const double radius = static_cast(perpConeR); + + // build 2 perp cones in phi around the leading jet (right and left of the jet) + double PerpendicularConeAxisPhi1 = RecoDecay::constrainAngle(jetPhi + (M_PI / 2.), -M_PI); // This will contrain the angel between -pi & Pi + double PerpendicularConeAxisPhi2 = RecoDecay::constrainAngle(jetPhi - (M_PI / 2.), -M_PI); // This will contrain the angel between -pi & Pi + + for (const auto& particle : inputParticles) { + // sum the momentum of all paricles that fill the two cones + const double phi = RecoDecay::constrainAngle(particle.phi(), -M_PI); + double dPhi1 = RecoDecay::constrainAngle(phi - PerpendicularConeAxisPhi1, -M_PI); // This will contrain the angel between -pi & Pi + double dPhi2 = RecoDecay::constrainAngle(phi - PerpendicularConeAxisPhi2, -M_PI); // This will contrain the angel between -pi & Pi + double dEta = jetEta - particle.eta(); // The perp cone eta is the same as the leading jet since the cones are perpendicular only in phi + if (TMath::Sqrt(dPhi1 * dPhi1 + dEta * dEta) <= static_cast(radius)) { + perpPtDensity1 += particle.pt(); + perpMdDensity1 += TMath::Sqrt(particle.m() * particle.m() + particle.pt() * particle.pt()) - particle.pt(); + } + + if (TMath::Sqrt(dPhi2 * dPhi2 + dEta * dEta) <= static_cast(radius)) { + perpPtDensity2 += particle.pt(); + perpMdDensity2 += TMath::Sqrt(particle.m() * particle.m() + particle.pt() * particle.pt()) - particle.pt(); + } + } + + // Caculate rho as the ratio of average pT of the two cones / the cone area + double perpPtDensity = (perpPtDensity1 + perpPtDensity2) / (2 * M_PI * static_cast(radius) * static_cast(radius)); + double perpMdDensity = (perpMdDensity1 + perpMdDensity2) / (2 * M_PI * static_cast(radius) * static_cast(radius)); + + return std::make_tuple(perpPtDensity, perpMdDensity); } }; // namespace jetutilities diff --git a/PWGJE/Core/JetV0Utilities.h b/PWGJE/Core/JetV0Utilities.h index 9e25fb13461..61a8dd9ec86 100644 --- a/PWGJE/Core/JetV0Utilities.h +++ b/PWGJE/Core/JetV0Utilities.h @@ -17,33 +17,20 @@ #ifndef PWGJE_CORE_JETV0UTILITIES_H_ #define PWGJE_CORE_JETV0UTILITIES_H_ -#include -#include -#include -#include +#include "PWGJE/DataModel/Jet.h" + +#include "Common/Core/RecoDecay.h" + +#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" +#include + +#include +#include +#include +#include namespace jetv0utilities { @@ -54,7 +41,7 @@ namespace jetv0utilities template constexpr bool isV0Candidate() { - return std::is_same_v, CandidatesV0Data::iterator> || std::is_same_v, CandidatesV0Data::filtered_iterator> || std::is_same_v, CandidatesV0MCD::iterator> || std::is_same_v, CandidatesV0MCD::filtered_iterator>; + 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>; } /** @@ -63,7 +50,7 @@ constexpr bool isV0Candidate() template constexpr bool isV0McCandidate() { - return std::is_same_v, CandidatesV0MCP::iterator> || std::is_same_v, CandidatesV0MCP::filtered_iterator>; + return std::is_same_v, o2::aod::CandidatesV0MCP::iterator> || std::is_same_v, o2::aod::CandidatesV0MCP::filtered_iterator>; } /** @@ -82,7 +69,7 @@ constexpr bool isV0Table() template constexpr bool isV0McTable() { - return std::is_same_v, CandidatesV0MCP> || std::is_same_v, o2::soa::Filtered>; // note not optimal way but needed for jetfindingutilities::analyseParticles() + return std::is_same_v, o2::aod::CandidatesV0MCP> || std::is_same_v, o2::soa::Filtered>; // note not optimal way but needed for jetfindingutilities::analyseParticles() } /** @@ -90,10 +77,9 @@ constexpr bool isV0McTable() * * @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*/) +template +bool isV0DaughterTrack(T& track, U& candidate) { if constexpr (isV0Candidate()) { if (candidate.posTrackId() == track.globalIndex() || candidate.negTrackId() == track.globalIndex()) { @@ -151,9 +137,13 @@ auto slicedPerV0Candidate(T const& table, U const& candidate, V const& perV0Cand } template -bool isV0Particle(T const& particles, U const& particle) +bool isV0Particle(T const& particles, U const& particle, bool v0ChargedDecaysOnly) { - 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); + if (v0ChargedDecaysOnly) { + 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); + } else { + return RecoDecay::isMatchedMCGen(particles, particle, +kK0Short, std::array{+kPiPlus, -kPiPlus}, true) || RecoDecay::isMatchedMCGen(particles, particle, +kK0Short, std::array{+kPi0, +kPi0}, true) || RecoDecay::isMatchedMCGen(particles, particle, +kLambda0, std::array{+kProton, -kPiPlus}, true) || RecoDecay::isMatchedMCGen(particles, particle, +kLambda0, std::array{+kNeutron, +kPi0}, true) || RecoDecay::isMatchedMCGen(particles, particle, -kLambda0, std::array{-kProton, +kPiPlus}, true) || RecoDecay::isMatchedMCGen(particles, particle, -kLambda0, std::array{+kNeutron, +kPi0}, true); + } } enum JV0ParticleDecays { @@ -170,7 +160,7 @@ bool selectV0ParticleDecay(T const& v0Particle, int v0ParticleDecaySelection = - return (v0Particle.decayFlag() & (1 << v0ParticleDecaySelection)); } -int initialiseV0ParticleDecaySelection(std::string v0ParticleDecaySelection) +int initialiseV0ParticleDecaySelection(const std::string& v0ParticleDecaySelection) { if (v0ParticleDecaySelection == "K0sToPiPi") { return JV0ParticleDecays::K0sToPiPi; diff --git a/PWGJE/Core/MlResponseHfTagging.h b/PWGJE/Core/MlResponseHfTagging.h new file mode 100644 index 00000000000..2b07e1c1c25 --- /dev/null +++ b/PWGJE/Core/MlResponseHfTagging.h @@ -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. + +/// \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 "Tools/ML/MlResponse.h" + +#include + +#include + +#include + +#include +#include +#include +#include + +// 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, + signedIPz, + signedIPzSign, + 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(); } + + /// @brief Method to get the output shape of a model + /// \param imod is the index of the model + /// @return number of output nodes + int getOutputNodes(int imod = 0) const { return this->mModels[imod].getNumOutputNodes(); } + + /// 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, signedIPz) + CHECK_AND_FILL_VEC_BTAG(trackInput, track, signedIPzSign) + 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; + } + } + } + } + + /// @brief Method to replace NaN and infinity values in a vector with a specified value + /// @param vec is the vector to be processed + /// @param value is the value to replace NaN values with + /// @return the number of NaN values replaced + template + static int replaceNaN(std::vector& vec, T value) + { + int numNaN = 0; + for (auto& el : vec) { + if (std::isnan(el) || std::isinf(el)) { + el = value; + ++numNaN; + } + } + return numNaN; + } + + /// 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; + + replaceNaN(jetInput, 0.f); + replaceNaN(trackInput, 0.f); + replaceNaN(svInput, 0.f); + + 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()); + + replaceNaN(inputFeatures, 0.f); + + 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(signedIPz), + FILL_MAP_BJET(signedIPzSign), + 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: + Ort::MemoryInfo memInfo; + public: + TensorAllocator() + : memInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault)) + { + } + ~TensorAllocator() = default; + template + Ort::Value createTensor(std::vector& input, std::vector& inputShape) + { + return Ort::Value::CreateTensor(memInfo, input.data(), input.size(), inputShape.data(), inputShape.size()); + } +}; + +// 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/emcalCrossTalkEmulation.cxx b/PWGJE/Core/emcalCrossTalkEmulation.cxx new file mode 100644 index 00000000000..32b08cd13dc --- /dev/null +++ b/PWGJE/Core/emcalCrossTalkEmulation.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 emcalCrossTalkEmulation.cxx +/// \brief emulation of emcal cross talk for simulations +/// \author Marvin Hemmer , Goethe-University + +#include "emcalCrossTalkEmulation.h" + +#include +#include +#include +#include +#include +#include +#include + +#include // std::find_if +#include +#include // size_t +#include // std::abs +#include // setw +#include // left and right +#include +#include +#include +#include +#include +// #include "Framework/OutputObjHeader.h" + +// #include "Common/CCDB/EventSelectionParams.h" +#include +#include + +#include + +using namespace o2; +using namespace o2::emccrosstalk; +using namespace o2::framework; + +template +auto printArray(std::array const& arr) +{ + std::stringstream ss; + ss << "\n[SM0: " << arr[0]; + for (auto i = 1u; i < N; ++i) { + ss << ", SM" << i << ": " << arr[i]; + } + ss << "]"; + return ss.str(); +} + +template +auto printMatrix(Array2D const& m) +{ + std::stringstream ss; + // Print column headers + ss << std::endl + << std::setw(6) << " " << std::setw(10) << "value1" + << std::setw(10) << "value2" + << std::setw(10) << "value3" + << std::setw(10) << "value4" << std::endl; + + // Print rows with SM labels + for (size_t i = 0; i < m.rows; ++i) { + ss << "SM" << std::left << std::setw(3) << i; // e.g., SM0, SM1... + for (size_t j = 0; j < m.cols; ++j) { + ss << std::right << std::setw(10) << m(i, j); + } + ss << std::endl; + } + + return ss.str(); +} + +void init2DElement(Array2D& matrix, const Array2D& config, const char* name) +{ + int rows = config.rows; + int cols = config.cols; + + if (rows == 0 && cols == 0) { + LOG(info) << name << " has size 0 x 0, so it is disabled!"; + } else if (cols != NNeighbourCases || (rows != 1 && rows != NSM)) { + LOG(error) << name << " must have 4 columns and either 1 or 20 rows!"; + } else { + for (int sm = 0; sm < NSM; ++sm) { + const int row = (rows == 1) ? 0 : sm; + + for (int i = 0; i < cols; ++i) { + matrix[sm][i] = config(row, i); + } + } + } +} + +void init1DElement(std::array& arr, const std::vector& config, const char* name) +{ + size_t confSize = config.size(); + if (confSize == 0) { + LOG(info) << name << " has size 0, so it is disabled!"; + } else if (config.size() != 1 && confSize != NSM) { + LOG(error) << name << " must have either size 1 or 20!"; + } else { + for (int sm = 0; sm < NSM; ++sm) { + const int row = (confSize == 1) ? 0 : sm; + arr[sm] = config[row]; + } + } +} + +o2::framework::AxisSpec axisEnergy = {7000, 0.f, 70.f, "#it{E}_{cell} (GeV)"}; +// For each of the following configurables we will use: +// empty vector == disabled +// vector of size 4 == same for all SM +// vector of vectors with size nSM * 4 == each SM has its own setting +// the 4 values (0-3) correspond to in relative [row,col]: 0: [+-1,0], 1: [+-1,+or-1], 2: [0,+or-1], 3: [+-2, 0 AND +or-1] +// +---+---+-----+---+---+--+--+--+ +// | 3 | 0 | Hit | 0 | 3 | | | | +// +---+---+-----+---+---+--+--+--+ +// | 3 | 1 | 2 | 1 | 3 | | | | +// +---+---+-----+---+---+--+--+--+ + +void EMCCrossTalk::initObjects(const EmcCrossTalkConf& config) +{ + const int run3RunNumber = 223409; + mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(run3RunNumber); + if (!mGeometry) { + LOG(error) << "Failure accessing mGeometry"; + } + + // first set the simple run time variables + mTCardCorrClusEnerConserv = config.conserveEnergy.value; + mRandomizeTCard = config.randomizeTCardInducedEnergy.value; + mTCardCorrMinAmp = config.inducedTCardMinimumCellEnergy.value; + mTCardCorrMinInduced = config.inducedTCardMinimum.value; + mTCardCorrMaxInducedELeak = config.inducedTCardMaximumELeak.value; + mTCardCorrMaxInduced = config.inducedTCardMaximum.value; + + // 2nd define the NSM x NNeighbourCases matrices + mTCardCorrInduceEner = Array2D(std::vector(NSM * 4, 0.f), NSM, 4); + mTCardCorrInduceEnerFrac = Array2D(std::vector(NSM * 4, 0.f), NSM, 4); + mTCardCorrInduceEnerFracP1 = Array2D(std::vector(NSM * 4, 0.f), NSM, 4); + mTCardCorrInduceEnerFracWidth = Array2D(std::vector(NSM * 4, 0.f), NSM, 4); + + // now properly init the NSM x NNeighbourCases matrices + // ------------------------------------------------------------------------ + // mTCardCorrInduceEner + init2DElement(mTCardCorrInduceEner, config.inducedEnergyLossConstant.value, "inducedEnergyLossConstant"); + + // mTCardCorrInduceEnerFrac + init2DElement(mTCardCorrInduceEnerFrac, config.inducedEnergyLossFraction.value, "inducedEnergyLossFraction"); + + // mTCardCorrInduceEnerFracP1 + init2DElement(mTCardCorrInduceEnerFracP1, config.inducedEnergyLossFractionP1.value, "inducedEnergyLossFractionP1"); + + // mTCardCorrInduceEnerFracWidth + init2DElement(mTCardCorrInduceEnerFracWidth, config.inducedEnergyLossFractionWidth.value, "inducedEnergyLossFractionWidth"); + // ------------------------------------------------------------------------ + + init1DElement(mTCardCorrInduceEnerFracMax, config.inducedEnergyLossMaximumFraction.value, "inducedEnergyLossMaximumFraction"); + init1DElement(mTCardCorrInduceEnerFracMin, config.inducedEnergyLossMinimumFraction.value, "inducedEnergyLossMinimumFraction"); + init1DElement(mTCardCorrInduceEnerFracMinCentralEta, config.inducedEnergyLossMinimumFractionCentralEta.value, "inducedEnergyLossMinimumFractionCentralEta"); + init1DElement(mTCardCorrInduceEnerProb, config.inducedEnergyLossProbability.value, "inducedEnergyLossProbability"); + + resetArrays(); + + // Print the full matrices and vectors that will be used: + if (config.printConfiguration.value) { + LOGF(info, "inducedEnergyLossConstant: %s", printMatrix((mTCardCorrInduceEner))); + LOGF(info, "inducedEnergyLossFraction: %s", printMatrix((mTCardCorrInduceEnerFrac))); + LOGF(info, "inducedEnergyLossFractionP1: %s", printMatrix((mTCardCorrInduceEnerFracP1))); + LOGF(info, "inducedEnergyLossFractionWidth: %s", printMatrix((mTCardCorrInduceEnerFracWidth))); + LOGF(info, "inducedEnergyLossMaximumFraction: %s", printArray(mTCardCorrInduceEnerFracMax).c_str()); + LOGF(info, "inducedEnergyLossMinimumFraction: %s", printArray(mTCardCorrInduceEnerFracMin).c_str()); + LOGF(info, "inducedEnergyLossMinimumFractionCentralEta: %s", printArray(mTCardCorrInduceEnerFracMinCentralEta).c_str()); + LOGF(info, "inducedEnergyLossProbability: %s", printArray(mTCardCorrInduceEnerProb).c_str()); + } +} + +void EMCCrossTalk::resetArrays() +{ + for (size_t j = 0; j < NCells; j++) { + mTCardCorrCellsEner[j] = 0.; + mTCardCorrCellsNew[j] = false; + } + + mCellsTmp.clear(); +} + +void EMCCrossTalk::setCells(std::vector& cells, std::vector& cellLabels) +{ + mCells = &cells; + mCellsTmp = cells; // a copy since we will need one vector with the changed energies and one with the original ones + mCellLabels = &cellLabels; +} + +void EMCCrossTalk::calculateInducedEnergyInTCardCell(int absId, int absIdRef, int iSM, float ampRef, int cellCase) +{ + // Check that the cell exists + if (absId < 0) { + return; + } + + // Get the fraction + float frac = mTCardCorrInduceEnerFrac[iSM][cellCase] + ampRef * mTCardCorrInduceEnerFracP1[iSM][cellCase]; + + // Use an absolute minimum and maximum fraction if calculated one is out of range + if (frac < mTCardCorrInduceEnerFracMin[iSM]) { + frac = mTCardCorrInduceEnerFracMin[iSM]; + } else if (frac > mTCardCorrInduceEnerFracMax[iSM]) { + frac = mTCardCorrInduceEnerFracMax[iSM]; + } + + // If active, use different absolute minimum fraction for central eta, exclude DCal 2/3 SM + if (mTCardCorrInduceEnerFracMinCentralEta[iSM] > 0 && (iSM < FirstDCal23SM || iSM > LastDCal23SM)) { + // Odd SM + int ietaMin = 32; + int ietaMax = 47; + + // Even SM + if (iSM % 2) { + ietaMin = 0; + ietaMax = 15; + } + + // First get the SM, col-row of this tower + // int imod = -1, iphi =-1, ieta=-1,iTower = -1, iIphi = -1, iIeta = -1; + auto [iSM, iMod, iIphi, iIeta] = mGeometry->GetCellIndex(absId); + auto [iphi, ieta] = mGeometry->GetCellPhiEtaIndexInSModule(iSM, iMod, iIphi, iIeta); + + if (ieta >= ietaMin && ieta <= ietaMax) { + if (frac < mTCardCorrInduceEnerFracMinCentralEta[iSM]) + frac = mTCardCorrInduceEnerFracMinCentralEta[iSM]; + } + } // central eta + + LOGF(debug, "\t fraction %2.3f", frac); + + // Randomize the induced fraction, if requested + if (mRandomizeTCard) { + frac = mRandom.Gaus(frac, mTCardCorrInduceEnerFracWidth[iSM][cellCase]); + LOGF(debug, "\t randomized fraction %2.3f", frac); + } + + // If fraction too small or negative, do nothing else + if (frac < Epsilon) { + return; + } + + // Calculate induced energy + float inducedE = mTCardCorrInduceEner[iSM][cellCase] + ampRef * frac; + + // Check if we induce too much energy, in such case use a constant value + if (mTCardCorrMaxInduced < inducedE) + inducedE = mTCardCorrMaxInduced; + + LOGF(debug, "\t induced E %2.3f", inducedE); + + // Try to find the cell that will get energy induced + float amp = 0.f; + auto itCell = std::find_if((*mCells).begin(), (*mCells).end(), [absId](const o2::emcal::Cell& cell) { + return cell.getTower() == absId; + }); + + if (itCell != (*mCells).end()) { + // We found a cell, so let's get the amplitude of that cell + amp = itCell->getAmplitude(); + } else { + amp = 0.f; // this is a new cell, so the base amp is 0.f + } + + // Check that the induced+amp is large enough to avoid extra linearity effects + // typically of the order of the clusterization cell energy cut + // if inducedTCardMaximumELeak was set to a positive value, then induce the energy as long as its smaller than that value + if ((amp + inducedE) > mTCardCorrMinInduced || inducedE < mTCardCorrMaxInducedELeak) { + mTCardCorrCellsEner[absId] += inducedE; + + // If original energy of cell was null, create new one + if (amp <= Epsilon) { + mTCardCorrCellsNew[absId] = true; + } + } else { + return; + } + + LOGF(debug, "Cell %d is with amplitude %2.3f GeV is inducing %1.3f GeV energy to cell %d which already has %2.3f GeV energy with fraction %1.5f", absIdRef, ampRef, inducedE, absId, amp, frac); + + // Subtract the added energy to main cell, if energy conservation is requested + if (mTCardCorrClusEnerConserv) { + mTCardCorrCellsEner[absIdRef] -= inducedE; + } +} + +void EMCCrossTalk::makeCellTCardCorrelation() +{ + int id = -1; + float amp = -1; + + // Loop on all cells with signal + for (const auto& cell : (*mCells)) { + id = cell.getTower(); + amp = cell.getAmplitude(); + + if (amp <= mTCardCorrMinAmp) { + continue; + } + + // First get the SM, col-row of this tower + auto [iSM, iMod, iIphi, iIeta] = mGeometry->GetCellIndex(id); + auto [iphi, ieta] = mGeometry->GetCellPhiEtaIndexInSModule(iSM, iMod, iIphi, iIeta); + + // Determine randomly if we want to create a correlation for this cell, + // depending the SM number of the cell + if (mTCardCorrInduceEnerProb[iSM] < 1) { + if (mRandom.Uniform(0, 1) > mTCardCorrInduceEnerProb[iSM]) { + continue; + } + } + + LOGF(debug, "Reference cell absId %d, iEta %d, iPhi %d, amp %2.3f", id, ieta, iphi, amp); + + // Get the absId of the cells in the cross and same T-Card + int absIDup = -1; + int absIDdo = -1; + int absIDlr = -1; + int absIDuplr = -1; + int absIDdolr = -1; + + int absIDup2 = -1; + int absIDup2lr = -1; + int absIDdo2 = -1; + int absIDdo2lr = -1; + + // Only 2 columns in the T-Card, +1 for even and -1 for odd with respect reference cell + // Sine we only have full T-Cards, we do not need to make any edge case checks + // There is always either a column (eta direction) below or above + int colShift = +1; + if (ieta % 2) { + colShift = -1; + } + + absIDlr = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta + colShift); + + // Check if up / down cells from reference cell are not out of SM + // First check if there is space one above + if (iphi < emcal::EMCAL_ROWS - 1) { + absIDup = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi + 1, ieta); + absIDuplr = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi + 1, ieta + colShift); + } + + // 2nd check if there is space one below + if (iphi > 0) { + absIDdo = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi - 1, ieta); + absIDdolr = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi - 1, ieta + colShift); + } + + // 3rd check if there is space two above + if (iphi < emcal::EMCAL_ROWS - 2) { + absIDup2 = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi + 2, ieta); + absIDup2lr = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi + 2, ieta + colShift); + } + + // 4th check if there is space two below + if (iphi > 1) { + absIDdo2 = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi - 2, ieta); + absIDdo2lr = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphi - 2, ieta + colShift); + } + + // Check if those cells are in the same T-Card + int tCard = iphi / 8; + if (tCard != (iphi + 1) / 8) { + absIDup = -1; + absIDuplr = -1; + } + if (tCard != (iphi - 1) / 8) { + absIDdo = -1; + absIDdolr = -1; + } + if (tCard != (iphi + 2) / 8) { + absIDup2 = -1; + absIDup2lr = -1; + } + if (tCard != (iphi - 2) / 8) { + absIDdo2 = -1; + absIDdo2lr = -1; + } + + // Calculate induced energy to T-Card cells + // first check if for the given cell case we actually do induce some energy + if (((std::abs(mTCardCorrInduceEner[iSM][0]) > Epsilon) || (std::abs(mTCardCorrInduceEnerFrac[iSM][0]) > Epsilon)) && (std::abs(mTCardCorrInduceEnerFracP1[iSM][0]) > Epsilon) && (std::abs(mTCardCorrInduceEnerFracWidth[iSM][0]) > Epsilon)) { + if (absIDup >= 0) { + LOGF(debug, "cell up %d:", absIDup); + calculateInducedEnergyInTCardCell(absIDup, id, iSM, amp, 0); + } + if (absIDdo >= 0) { + LOGF(debug, "cell down %d:", absIDdo); + calculateInducedEnergyInTCardCell(absIDdo, id, iSM, amp, 0); + } + } + if (((std::abs(mTCardCorrInduceEner[iSM][1]) > Epsilon) || (std::abs(mTCardCorrInduceEnerFrac[iSM][1]) > Epsilon)) && (std::abs(mTCardCorrInduceEnerFracP1[iSM][1]) > Epsilon) && (std::abs(mTCardCorrInduceEnerFracWidth[iSM][1]) > Epsilon)) { + if (absIDuplr >= 0) { + LOGF(debug, "cell up left-right %d:", absIDuplr); + calculateInducedEnergyInTCardCell(absIDuplr, id, iSM, amp, 1); + } + if (absIDdolr >= 0) { + LOGF(debug, "cell down left-right %d:", absIDdolr); + calculateInducedEnergyInTCardCell(absIDdolr, id, iSM, amp, 1); + } + } + if (((std::abs(mTCardCorrInduceEner[iSM][2]) > Epsilon) || (std::abs(mTCardCorrInduceEnerFrac[iSM][2]) > Epsilon)) && (std::abs(mTCardCorrInduceEnerFracP1[iSM][2]) > Epsilon) && (std::abs(mTCardCorrInduceEnerFracWidth[iSM][2]) > Epsilon)) { + if (absIDlr >= 0) { + LOGF(debug, "cell left-right %d:", absIDlr); + calculateInducedEnergyInTCardCell(absIDlr, id, iSM, amp, 2); + } + } + if (((std::abs(mTCardCorrInduceEner[iSM][3]) > Epsilon) || (std::abs(mTCardCorrInduceEnerFrac[iSM][3]) > Epsilon)) && (std::abs(mTCardCorrInduceEnerFracP1[iSM][3]) > Epsilon) && (std::abs(mTCardCorrInduceEnerFracWidth[iSM][3]) > Epsilon)) { + if (absIDup2 >= 0) { + LOGF(debug, "cell up 2nd row %d:", absIDup2); + calculateInducedEnergyInTCardCell(absIDup2, id, iSM, amp, 3); + } + if (absIDdo2 >= 0) { + LOGF(debug, "cell down 2nd row %d:", absIDdo2); + calculateInducedEnergyInTCardCell(absIDdo2, id, iSM, amp, 3); + } + if (absIDup2lr >= 0) { + LOGF(debug, "cell up left-right 2nd row %d:", absIDup2lr); + calculateInducedEnergyInTCardCell(absIDup2lr, id, iSM, amp, 3); + } + if (absIDdo2lr >= 0) { + LOGF(debug, "cell down left-right 2nd row %d:", absIDdo2lr); + calculateInducedEnergyInTCardCell(absIDdo2lr, id, iSM, amp, 3); + } + } + } // cell loop +} + +void EMCCrossTalk::addInducedEnergiesToExistingCells() +{ + // Add the induced energy to the cells and copy them into a new temporal container + // used in AddInducedEnergiesToNewCells() to refill the default cells list fCaloCells + // Create the data member only once. Done here, not sure where to do this properly in the framework. + + for (auto& cell : mCellsTmp) { // o2-linter: disable=const-ref-in-for-loop (we are changing a value here) + float amp = cell.getAmplitude() + mTCardCorrCellsEner[cell.getTower()]; + // Set new amplitude in new temporal container + cell.setAmplitude(amp); + } +} + +void EMCCrossTalk::addInducedEnergiesToNewCells() +{ + // count how many new cells + size_t nCells = (*mCells).size(); + int nCellsNew = 0; + for (size_t j = 0; j < NCells; j++) { + // Newly created? + if (!mTCardCorrCellsNew[j]) { + continue; + } + // Accept only if at least 10 MeV + if (mTCardCorrCellsEner[j] < MinCellEnergy) { + continue; + } + nCellsNew++; + } + + // reserve more space for new cell entries in original cells and celllabels + (*mCells).reserve(nCells + nCellsNew); + (*mCellLabels).reserve(nCells + nCellsNew); + + // change the amplitude of the original cells using + for (size_t iCell = 0; iCell < mCellsTmp.size(); ++iCell) { + (*mCells)[iCell].setAmplitude(mCellsTmp[iCell].getAmplitude()); + } + + // Add the new cells + int absId = -1; + float amp = -1; + float time = 0; + std::vector mclabel; + + for (size_t j = 0; j < NCells; j++) { + // Newly created? + if (!mTCardCorrCellsNew[j]) { + continue; + } + + // Accept only if at least 10 MeV + if (mTCardCorrCellsEner[j] < MinCellEnergy) { + continue; + } + + // Add new cell + absId = j; + amp = mTCardCorrCellsEner[j]; + time = 615.e-9f; + mclabel = {-1}; + + // Assign as MC label the label of the neighboring cell with highest energy + // within the same T-Card. Follow same approach for time. + // Simplest assumption, not fully correct. + // Still assign 0 as fraction of energy. + + // First get the iphi and ieta of this tower + auto [iSM, iMod, iIphi, iIeta] = mGeometry->GetCellIndex(absId); + auto [iphi, ieta] = mGeometry->GetCellPhiEtaIndexInSModule(iSM, iMod, iIphi, iIeta); + + LOGF(debug, "Trying to add cell %d \t ieta = %d\t iphi = %d\t amplitude = %1.3f", absId, ieta, iphi, amp); + + // Loop on the nearest cells around, check the highest energy one, + // and assign its MC label and the time + float ampMax = 0.f; + for (int ietai = ieta - 1; ietai <= ieta + 1; ++ietai) { + for (int iphii = iphi - 1; iphii <= iphi + 1; ++iphii) { + + // Avoid same cell + if (iphii == iphi && ietai == ieta) { + continue; + } + + // Avoid cells out of SM + if (ietai < 0 || ietai >= NColumns[iSM] || iphii < 0 || iphii >= NRows[iSM]) { + continue; + } + + int absIDi = mGeometry->GetAbsCellIdFromCellIndexes(iSM, iphii, ietai); + // Try to find the cell that will get energy induced + float ampi = 0.f; + size_t indexInCells = 0; + auto itCell = std::find_if((*mCells).begin(), (*mCells).begin() + nCells, [absIDi](const o2::emcal::Cell& cell) { + return cell.getTower() == absIDi; + }); + + if (itCell != (*mCells).begin() + nCells) { + // We found a cell, so let's get the amplitude of that cell + ampi = itCell->getAmplitude(); + if (ampi <= ampMax) { + continue; // early continue if the new amplitude is not the biggest one + } + indexInCells = std::distance((*mCells).begin(), itCell); + LOGF(debug, "Found cell with index %d", indexInCells); + } else { + continue; + } + + // Remove cells with no energy + if (ampi <= MinCellEnergy) { + continue; + } + + // Only same TCard + if (!std::get<0>(mGeometry->areAbsIDsFromSameTCard(absId, absIDi))) { + continue; + } + + std::vector mclabeli = {(*mCellLabels)[indexInCells].GetLeadingMCLabel()}; + float timei = (*mCells)[indexInCells].getTimeStamp(); + + ampMax = ampi; + mclabel = mclabeli; + time = timei; + } // loop phi + } // loop eta + // End Assign MC label + LOGF(debug, "Final ampMax %1.2f\n", ampMax); + LOGF(debug, "--- End : Added cell ID %d, ieta %d, iphi %d, E %1.3f, time %1.3e, mc label %d\n", absId, ieta, iphi, amp, time, mclabel[0]); + + // Add the new cell + (*mCells).emplace_back(absId, amp, time, o2::emcal::intToChannelType(1)); + (*mCellLabels).emplace_back(std::vector{mclabel[0]}, std::vector{0.f}); + } // loop over cells +} + +bool EMCCrossTalk::run() +{ + // START PROCESSING + // Test if cells present + if ((*mCells).size() == 0) { + LOGF(error, "No EMCAL cells found, exiting EMCCrossTalk::run()!"); + return false; + } + + // CELL CROSSTALK EMULATION + // Compute the induced cell energies by T-Card correlation emulation, ONLY MC + makeCellTCardCorrelation(); + + // Add to existing cells the found induced energies in MakeCellTCardCorrelation() if new signal is larger than 10 MeV. + addInducedEnergiesToExistingCells(); + + // Add new cells with found induced energies in MakeCellTCardCorrelation() if new signal is larger than 10 MeV. + addInducedEnergiesToNewCells(); + + resetArrays(); + + return true; +} diff --git a/PWGJE/Core/emcalCrossTalkEmulation.h b/PWGJE/Core/emcalCrossTalkEmulation.h new file mode 100644 index 00000000000..fb84ec7c1ad --- /dev/null +++ b/PWGJE/Core/emcalCrossTalkEmulation.h @@ -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 emcalCrossTalkEmulation.h +/// \brief emulation of emcal cross talk for simulations +/// \author Marvin Hemmer , Goethe-University + +#ifndef PWGJE_CORE_EMCALCROSSTALKEMULATION_H_ +#define PWGJE_CORE_EMCALCROSSTALKEMULATION_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace o2::emccrosstalk +{ +// cell types for enegery induction +enum InductionCellType { + UpDown = 0, + UpDownLeftRight, + LeftRight, + Up2Down2, + NInductionCellType +}; + +// default values for cross talk emulation +// small value to use for comarison equal to 0, std::abs(x) > epsilon +static constexpr float Epsilon = 1e-6f; + +// default for inducedEnergyLossConstant +// static constexpr float DefaultIELC[1][4] = {{0.02f, 0.02f, 0.02f, 0.f}}; // default from https://github.com/alisw/AliPhysics/blob/master/PWG/EMCAL/config/AliEmcalCorrectionConfiguration.yaml (but is deactivated per default) +static constexpr float DefaultIELC[1][4] = {{0.f, 0.f, 0.f, 0.f}}; // default from pp 13 TeV + +// default for inducedEnergyLossFraction, default from https://github.com/alisw/AliPhysics/blob/master/PWG/EMCAL/config/AliEmcalCorrectionConfiguration.yaml same as in https://cds.cern.ch/record/2910556/ +static constexpr float DefaultIELF[20][4] = {{1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {1.20e-02, 1.20e-02, 1.20e-02, 0.f}, + {1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {1.20e-02, 1.20e-02, 1.20e-02, 0.f}, + {1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {1.20e-02, 1.20e-02, 1.20e-02, 0.f}, + {0.80e-02, 0.80e-02, 0.80e-02, 0.f}, + {0.80e-02, 0.80e-02, 0.80e-02, 0.f}, + {1.20e-02, 1.20e-02, 1.20e-02, 0.f}, + {1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {0.80e-02, 0.80e-02, 0.80e-02, 0.f}, + {0.80e-02, 0.80e-02, 0.80e-02, 0.f}, + {1.15e-02, 1.15e-02, 1.15e-02, 0.f}, + {0.80e-02, 0.80e-02, 0.80e-02, 0.f}, + {0.80e-02, 0.80e-02, 0.80e-02, 0.f}, + {0.80e-02, 0.80e-02, 0.80e-02, 0.f}}; + +// default for inducedEnergyLossFractionP1, default from https://github.com/alisw/AliPhysics/blob/master/PWG/EMCAL/config/AliEmcalCorrectionConfiguration.yaml same as in https://cds.cern.ch/record/2910556/ +static constexpr float DefaultIELFP1[1][4] = {{-1.1e-03, -1.1e-03, -1.1e-03, 0.f}}; + +// default for inducedEnergyLossFractionWidth, default from https://github.com/alisw/AliPhysics/blob/master/PWG/EMCAL/config/AliEmcalCorrectionConfiguration.yaml same as in https://cds.cern.ch/record/2910556/ +static constexpr float DefaultIELFWidth[1][4] = {{5.0e-03, 5.0e-03, 5.0e-03, 0.f}}; + +// default for inducedEnergyLossMinimumFractionCentralEta, IF someone wants to try it. This is purely to document those test numbers from AliEmcalCorrectionConfiguration.yaml! Default is to not use this! Values from default from https://github.com/alisw/AliPhysics/blob/master/PWG/EMCAL/config/AliEmcalCorrectionConfiguration.yaml +// std::vector DefaultIELMFCE = {6.8e-3, 7.5e-3, 6.8e-3, 9.0e-3, 6.8e-3, 6.8e-3, 6.8e-3, 9.0e-3, 5.2e-3, 5.2e-3, 7.5e-3, 6.8e-3, 6.8e-3, 6.8e-3, 5.2e-3, 5.2e-3, 6.8e-3, 5.2e-3, 5.2e-3, 5.2e-3}; + +struct EmcCrossTalkConf : o2::framework::ConfigurableGroup { + std::string prefix = "emccrosstalk"; + o2::framework::Configurable enableCrossTalk{"enableCrossTalk", false, "Flag to enable cross talk emulation. This should only ever be used for MC!"}; + o2::framework::Configurable createHistograms{"createHistograms", false, "Flag to enable QA histograms."}; + o2::framework::Configurable printConfiguration{"printConfiguration", true, "Flag to print the configuration after initialization."}; + o2::framework::Configurable conserveEnergy{"conserveEnergy", true, "Flag to enable cluster energy conservation."}; + o2::framework::Configurable randomizeTCardInducedEnergy{"randomizeTCardInducedEnergy", true, "Flag to randomize the energy fraction induced by the TCard."}; + o2::framework::Configurable inducedTCardMinimumCellEnergy{"inducedTCardMinimumCellEnergy", 0.01f, "Minimum cell energy in GeV induced by the TCard."}; + o2::framework::Configurable inducedTCardMaximum{"inducedTCardMaximum", 100.f, "Maximum energy in GeV induced by the TCard."}; + o2::framework::Configurable inducedTCardMinimum{"inducedTCardMinimum", 0.1f, "Minimum energy in GeV induced by the TCard + cell energy, IMPORTANT use the same value as the clusterization cell E threshold or not too far from it."}; + o2::framework::Configurable inducedTCardMaximumELeak{"inducedTCardMaximumELeak", 0.f, "Maximum energy in GeV that is going to be leaked independently of what is set with inducedTCardMinimum."}; + // For each of the following Array2D configurables we will use: + // empty vector == disabled + // vector of size 4 == same for all SM + // vector of vectors with size nSM * 4 == each SM has its own setting + // the 4 values (0-3) correspond to in relative [row,col]: 0: [+-1,0], 1: [+-1,+or-1], 2: [0,+or-1], 3: [+-2, 0 AND +or-1] + // +---+---+-----+---+---+--+--+--+ + // | 3 | 0 | Hit | 0 | 3 | | | | + // +---+---+-----+---+---+--+--+--+ + // | 3 | 1 | 2 | 1 | 3 | | | | + // +---+---+-----+---+---+--+--+--+ + // For the std::vector it is similar, empty vector means not used, single value means one value for all SM and 20 values means specifiyng a value for all SM + o2::framework::Configurable> inducedEnergyLossConstant{"inducedEnergyLossConstant", {DefaultIELC[0], 1, 4}, "Constant energy lost by max energy cell in one of T-Card cells. Empty vector == disabled, size 4 vector == enabled. For information on the exact formatting please check the header file."}; + o2::framework::Configurable> inducedEnergyLossFraction{"inducedEnergyLossFraction", {DefaultIELF[0], 20, 4}, "Fraction of energy lost by max energy cell in one of T-Card cells."}; + o2::framework::Configurable> inducedEnergyLossFractionP1{"inducedEnergyLossFractionP1", {DefaultIELFP1[0], 1, 4}, "Slope parameter of fraction of energy lost by max energy cell in one of T-Card cells."}; + o2::framework::Configurable> inducedEnergyLossFractionWidth{"inducedEnergyLossFractionWidth", {DefaultIELFWidth[0], 1, 4}, "Fraction of energy lost by max energy cell in one of T-Card cells, width of random gaussian."}; + // default from https://github.com/alisw/AliPhysics/blob/master/PWG/EMCAL/config/AliEmcalCorrectionConfiguration.yaml : + // o2::framework::Configurable> inducedEnergyLossMinimumFraction{"inducedEnergyLossMinimumFraction", {3.5e-3f, 5.0e-3f, 4.5e-3f, 6.0e-3f, 3.5e-3f, 3.5e-3f, 3.5e-3f, 6.0e-3f, 3.5e-3f, 3.5e-3f, 5.0e-3f, 5.0e-3f, 3.5e-3f, 3.5e-3f, 3.5e-3f, 3.5e-3f, 3.5e-3f, 3.5e-3f, 3.5e-3f, 3.5e-3f}, "Minimum induced energy fraction when linear dependency is set."}; + // value from https://cds.cern.ch/record/2910556/: + o2::framework::Configurable> inducedEnergyLossMinimumFraction{"inducedEnergyLossMinimumFraction", {2.35e-3f, 2.5e-3f, 2.35e-3f, 3.0e-3f, 2.35e-3f, 2.35e-3f, 2.35e-3f, 3.0e-3f, 1.75e-3f, 1.75e-3f, 2.5e-3f, 2.35e-3f, 2.35e-3f, 2.35e-3f, 1.75e-3f, 1.75e-3f, 2.35e-3f, 1.75e-3f, 1.75e-3f, 1.75e-3f}, "Minimum induced energy fraction when linear dependency is set."}; + + o2::framework::Configurable> inducedEnergyLossMinimumFractionCentralEta{"inducedEnergyLossMinimumFractionCentralEta", {}, "Minimum induced energy fraction when linear dependency is set. For |eta| < 0.22, if empty no difference in eta. NOT TUNED for TESTING!"}; + + // default from https://github.com/alisw/AliPhysics/blob/master/PWG/EMCAL/config/AliEmcalCorrectionConfiguration.yaml : + // o2::framework::Configurable> inducedEnergyLossMaximumFraction{"inducedEnergyLossMaximumFraction", {0.018f}, "Maximum induced energy fraction when linear dependency is set."}; + // value from https://cds.cern.ch/record/2910556/: + o2::framework::Configurable> inducedEnergyLossMaximumFraction{"inducedEnergyLossMaximumFraction", {0.016f, 0.016f, 0.016f, 0.018f, 0.016f, 0.016f, 0.016f, 0.018f, 0.016f, 0.016f, 0.016f, 0.016f, 0.016f, 0.016f, 0.016f, 0.016f, 0.016f, 0.016f, 0.016f, 0.016f}, "Maximum induced energy fraction when linear dependency is set."}; + o2::framework::Configurable> inducedEnergyLossProbability{"inducedEnergyLossProbability", {1.0f}, "Fraction of times max cell energy correlates with cross cells."}; +}; + +static constexpr int NSM = 20; // Number of Supermodules (12 for EMCal + 8 for DCal) +static constexpr int NCells = 17664; // Number of cells in the EMCal +static constexpr int NNeighbourCases = 4; // 0-same row, diff col, 1-up/down cells left/right col 2-left/righ col, and 2nd row cells +static constexpr int FirstDCal23SM = 12; // index of the first 2/3 DCal SM +static constexpr int LastDCal23SM = 17; // index of the last 2/3 DCal SM +static constexpr float MinCellEnergy = 0.01f; // Minimum energy a new cell needs to be added + +static constexpr int NColumns[NSM] = {48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 48, 48}; +static constexpr int NRows[NSM] = {24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 8, 8, 24, 24, 24, 24, 24, 24, 8, 8}; + +// these labels are for later once labeledArrays work on hyperloop. Currently they sadly only allow fixed size not variable size. +// static const std::vector labelsSM{"SM0/all", "SM1", "SM2", "SM3", "SM4", "SM5", "SM6", "SM7", "SM8", "SM9", "SM10", "SM11", "SM12", "SM13", "SM14", "SM15", "SM16", "SM17", "SM18", "SM19"}; +// static const std::vector labelsCells = {"Up&Down", "Up&Down x Left|Right", "Left|Right", "2Up&Down + 2Up&Down xLeft|Right"}; + +class EMCCrossTalk +{ + + public: + ~EMCCrossTalk() + { + LOG(info) << "Destroying EMCCrossTalk"; + } + + /// \brief Basic init function. + /// \param config configurable group containing the config for the cross talk emulation + void initObjects(const EmcCrossTalkConf& config); + + /// \brief Reset arrays containing information for all possible cells. + /// \details mTCardCorrCellsEner and mTCardCorrCellsNew + void resetArrays(); + + /// \brief Sets the pointer the current vector of cells. + /// \param cells pointer to emcal cells of the current event + /// \param cellLabels pointer to emcal cell labels of the current event + void setCells(std::vector& cells, std::vector& cellLabels); + + /// \brief Main function to call later to perform the full cross talk emulation + /// \return flag if everything went well or not + bool run(); + + /// \brief Recover each cell amplitude and absId and induce energy in cells in cross of the same T-Card + void makeCellTCardCorrelation(); + + /// \brief Add to existing cells the found induced energies in makeCellTCardCorrelation() if new signal is larger than 10 MeV. + /// \details Need to destroy/create the default cells list and do a copy from the old to the new via a temporal array fAODCellsTmp. Not too nice or fast, but it works. + void addInducedEnergiesToExistingCells(); + + /// \brief Add new cells with found induced energies in makeCellTCardCorrelation() if new signal is larger than 10 MeV. + void addInducedEnergiesToNewCells(); + + /// \brief Calculate the induced energy in a cell belonging to thesame T-Card as the reference cell. Used in makeCellTCardCorrelation() + /// \param absId Id number of cell in same T-Card as reference cell + /// \param absIdRef Id number of reference cell + /// \param iSM Supermodule number of cell + /// \param ampRef Amplitude of the reference cell + /// \param cellCase Type of cell with respect reference cell 0: up or down, 1: up or down on the diagonal, 2: left or right, 3: 2nd row up/down both left/right + void calculateInducedEnergyInTCardCell(int absId, int absIdRef, int iSM, float ampRef, int cellCase); + + private: + // T-Card correlation emulation, do on MC + bool mTCardCorrClusEnerConserv; // When making correlation, subtract from the reference cell the induced energy on the neighbour cells + std::array mTCardCorrCellsEner; // Array with induced cell energy in T-Card neighbour cells + std::array mTCardCorrCellsNew; // Array with induced cell energy in T-Card neighbour cells, that before had no signal + + o2::framework::Array2D mTCardCorrInduceEner; // Induced energy loss gauss constant on 0-same row, diff col, 1-up/down cells left/right col 2-left/righ col, and 2nd row cells, param 0 + o2::framework::Array2D mTCardCorrInduceEnerFrac; // Induced energy loss gauss fraction param0 on 0-same row, diff col, 1-up/down cells left/right col 2-left/righ col, and 2nd row cells, param 0 + o2::framework::Array2D mTCardCorrInduceEnerFracP1; // Induced energy loss gauss fraction param1 on 0-same row, diff col, 1-up/down cells left/right col 2-left/righ col, and 2nd row cells, param1 + o2::framework::Array2D mTCardCorrInduceEnerFracWidth; // Induced energy loss gauss witdth on 0-same row, diff col, 1-up/down cells left/right col 2-left/righ col, and 2nd row cells + std::array mTCardCorrInduceEnerFracMax; // In case fTCardCorrInduceEnerFracP1 is non null, restrict the maximum fraction of induced energy per SM + std::array mTCardCorrInduceEnerFracMin; // In case fTCardCorrInduceEnerFracP1 is non null, restrict the minimum fraction of induced energy per SM + std::array mTCardCorrInduceEnerFracMinCentralEta; // In case fTCardCorrInduceEnerFracP1 is non null, restrict the minimum fraction of induced energy per SM. Different at central |eta| < 0.22 + std::array mTCardCorrInduceEnerProb; // Probability to induce energy loss per SM + + TRandom3 mRandom; // Random generator + bool mRandomizeTCard; // Use random induced energy + + float mTCardCorrMinAmp; // Minimum cell energy to induce signal on adjacent cells + float mTCardCorrMinInduced; // Minimum induced energy signal on adjacent cells, sum of induced plus original energy, use same as cell energy clusterization cut + float mTCardCorrMaxInducedELeak; // Maximum value of induced energy signal that is always leaked, ~5-10 MeV + float mTCardCorrMaxInduced; // Maximum induced energy signal on adjacent cells + + std::vector* mCells = nullptr; // Pointer to the original cells of the current event + std::vector* mCellLabels = nullptr; // Pointer to the original cell labels of the current event + std::vector mCellsTmp; // Temporal vector of cells (copy) + + o2::emcal::Geometry* mGeometry; // EMCal geometry +}; + +} // namespace o2::emccrosstalk + +#endif // PWGJE_CORE_EMCALCROSSTALKEMULATION_H_ diff --git a/PWGJE/Core/utilsBcSelEMC.h b/PWGJE/Core/utilsBcSelEMC.h new file mode 100644 index 00000000000..603e5190655 --- /dev/null +++ b/PWGJE/Core/utilsBcSelEMC.h @@ -0,0 +1,154 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Common/CCDB/EventSelectionParams.h" + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include // std::shared_ptr +#include // std::string + +namespace o2::emc_evsel +{ +// event rejection types +enum EventRejection { + None = 0, + Trigger, + TvxTrigger, + TimeFrameBorderCut, + ItsRofBorderCut, + NEventRejection +}; + +inline 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"); +} + +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"}; + // 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::kIsTriggerTVX) && bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); + 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); + } + } + 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/Core/utilsTrackMatchingEMC.h b/PWGJE/Core/utilsTrackMatchingEMC.h new file mode 100644 index 00000000000..05790a3fb88 --- /dev/null +++ b/PWGJE/Core/utilsTrackMatchingEMC.h @@ -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. + +/// \file utilsTrackMatchingEMC.h +/// \brief EMCal track matching related utils +/// \author Marvin Hemmer + +#ifndef PWGJE_CORE_UTILSTRACKMATCHINGEMC_H_ +#define PWGJE_CORE_UTILSTRACKMATCHINGEMC_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace tmemcutilities +{ + +struct MatchResult { + std::vector> matchIndexTrack; + std::vector> matchDeltaPhi; + std::vector> matchDeltaEta; +}; + +/** + * Match clusters and tracks. + * + * Match cluster with tracks, where maxNumberMatches are considered in dR=maxMatchingDistance. + * If no unique match was found for a jet, an index of -1 is stored. + * The same map is created for clusters matched to tracks e.g. for electron analyses. + * + * @param clusterPhi cluster collection phi. + * @param clusterEta cluster collection eta. + * @param trackPhi track collection phi. + * @param trackEta track collection eta. + * @param maxMatchingDistance Maximum matching distance. + * @param maxNumberMatches Maximum number of matches (e.g. 5 closest). + * + * @returns (cluster to track index map, track to cluster index map) + */ +MatchResult matchTracksToCluster( + std::span clusterPhi, + std::span clusterEta, + std::span trackPhi, + std::span trackEta, + double maxMatchingDistance, + int maxNumberMatches) +{ + const std::size_t nClusters = clusterEta.size(); + const std::size_t nTracks = trackEta.size(); + MatchResult result; + + if (nClusters == 0 || nTracks == 0) { + // There are no jets, so nothing to be done. + return result; + } + // Input sizes must match + if (clusterPhi.size() != clusterEta.size()) { + throw std::invalid_argument("cluster collection eta and phi sizes don't match. Check the inputs."); + } + if (trackPhi.size() != trackEta.size()) { + throw std::invalid_argument("track collection eta and phi sizes don't match. Check the inputs."); + } + + result.matchIndexTrack.resize(nClusters); + result.matchDeltaPhi.resize(nClusters); + result.matchDeltaEta.resize(nClusters); + + // Build the KD-trees using vectors + // We build two trees: + // treeBase, which contains the base collection. + // treeTag, which contains the tag collection. + // The trees are built to match in two dimensions (eta, phi) + TKDTree treeTrack(trackEta.size(), 2, 1); + treeTrack.SetData(0, trackEta.data()); + treeTrack.SetData(1, trackPhi.data()); + treeTrack.Build(); + + // Find the track closest to each cluster. + for (std::size_t iCluster = 0; iCluster < nClusters; iCluster++) { + float point[2] = {clusterEta[iCluster], clusterPhi[iCluster]}; + int index[50]; // size 50 for safety + float distance[50]; // size 50 for safery + std::fill_n(index, 50, -1); + std::fill_n(distance, 50, std::numeric_limits::max()); + treeTrack.FindNearestNeighbors(point, maxNumberMatches, index, distance); + + // allocate enough memory + result.matchIndexTrack[iCluster].reserve(maxNumberMatches); + result.matchDeltaPhi[iCluster].reserve(maxNumberMatches); + result.matchDeltaEta[iCluster].reserve(maxNumberMatches); + + // test whether indices are matching: + for (int m = 0; m < maxNumberMatches; m++) { + if (index[m] >= 0 && distance[m] < maxMatchingDistance) { + result.matchIndexTrack[iCluster].push_back(index[m]); + result.matchDeltaPhi[iCluster].push_back(trackPhi[index[m]] - clusterPhi[iCluster]); + result.matchDeltaEta[iCluster].push_back(trackEta[index[m]] - clusterEta[iCluster]); + } + } + } + return result; +} +}; // namespace tmemcutilities + +#endif // PWGJE_CORE_UTILSTRACKMATCHINGEMC_H_ diff --git a/PWGJE/DataModel/EMCALClusterDefinition.h b/PWGJE/DataModel/EMCALClusterDefinition.h index d3480c29366..41e87590449 100644 --- a/PWGJE/DataModel/EMCALClusterDefinition.h +++ b/PWGJE/DataModel/EMCALClusterDefinition.h @@ -9,17 +9,14 @@ // 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_ #include -#include "Framework/AnalysisDataModel.h" namespace o2::aod { @@ -33,20 +30,22 @@ enum class ClusterAlgorithm_t { /// cell energy, gradient as well as timing cut struct EMCALClusterDefinition { ClusterAlgorithm_t algorithm; - int storageID = -1; // integer ID used to store cluster definition in a flat table - int selectedCellType = 1; // EMCal cell type (CURRENTLY NOT USED TO AVOID MULTIPLE CELL LOOPS) - 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) - bool doGradientCut = true; // apply gradient cut if true - double gradientCut = -1; // gradient cut + int storageID = -1; // integer ID used to store cluster definition in a flat table + int selectedCellType = 1; // EMCal cell type (CURRENTLY NOT USED TO AVOID MULTIPLE CELL LOOPS) + 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 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 +55,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..e28931982b5 100644 --- a/PWGJE/DataModel/EMCALClusters.h +++ b/PWGJE/DataModel/EMCALClusters.h @@ -9,17 +9,21 @@ // 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_ #define PWGJE_DATAMODEL_EMCALCLUSTERS_H_ +#include "EMCALClusterDefinition.h" + +#include +#include // IWYU pragma: keep + +#include #include #include -#include "Framework/AnalysisDataModel.h" -#include "EMCALClusterDefinition.h" namespace o2::aod { @@ -27,32 +31,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 +139,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 @@ -120,10 +162,19 @@ using EMCALClusterCell = EMCALClusterCells::iterator; using EMCALAmbiguousClusterCell = EMCALAmbiguousClusterCells::iterator; namespace emcalmatchedtrack { -DECLARE_SOA_INDEX_COLUMN(Track, track); //! linked to Track table only for tracks that were matched +DECLARE_SOA_INDEX_COLUMN(Track, track); //! linked to Track table only for tracks that were matched +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! difference between matched track and cluster azimuthal angle +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! difference between matched track and cluster pseudorapidity } // namespace emcalmatchedtrack -DECLARE_SOA_TABLE(EMCALMatchedTracks, "AOD", "EMCMATCHTRACKS", //! - o2::soa::Index<>, emcalclustercell::EMCALClusterId, emcalmatchedtrack::TrackId); //! +DECLARE_SOA_TABLE(EMCALMatchedTracks, "AOD", "EMCMATCHTRACKS", //! + o2::soa::Index<>, emcalclustercell::EMCALClusterId, emcalmatchedtrack::TrackId, + emcalmatchedtrack::DeltaPhi, emcalmatchedtrack::DeltaEta); //! using EMCALMatchedTrack = EMCALMatchedTracks::iterator; + +// table for matched secondary tracks +DECLARE_SOA_TABLE(EMCMatchSecs, "AOD", "EMCMATCHSEC", //! + o2::soa::Index<>, emcalclustercell::EMCALClusterId, emcalmatchedtrack::TrackId, + emcalmatchedtrack::DeltaPhi, emcalmatchedtrack::DeltaEta); //! +using EMCMatchSec = EMCMatchSecs::iterator; } // namespace o2::aod #endif // PWGJE_DATAMODEL_EMCALCLUSTERS_H_ diff --git a/PWGJE/DataModel/EMCALMatchedCollisions.h b/PWGJE/DataModel/EMCALMatchedCollisions.h index 8550bf2fe45..2e93a2c765b 100644 --- a/PWGJE/DataModel/EMCALMatchedCollisions.h +++ b/PWGJE/DataModel/EMCALMatchedCollisions.h @@ -1,4 +1,4 @@ -// Copyright 2019-2023 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. // @@ -18,9 +18,8 @@ #ifndef PWGJE_DATAMODEL_EMCALMATCHEDCOLLISIONS_H_ #define PWGJE_DATAMODEL_EMCALMATCHEDCOLLISIONS_H_ -#include -#include "Framework/AnalysisDataModel.h" -#include "EMCALClusterDefinition.h" +#include +#include // IWYU pragma: keep namespace o2::aod { diff --git a/PWGJE/DataModel/EMCALMatchedTracks.h b/PWGJE/DataModel/EMCALMatchedTracks.h index 1dbbfac7b7a..840a384eba8 100644 --- a/PWGJE/DataModel/EMCALMatchedTracks.h +++ b/PWGJE/DataModel/EMCALMatchedTracks.h @@ -16,9 +16,9 @@ #ifndef PWGJE_DATAMODEL_EMCALMATCHEDTRACKS_H_ #define PWGJE_DATAMODEL_EMCALMATCHEDTRACKS_H_ -#include -#include "Framework/AnalysisDataModel.h" -#include "EMCALClusterDefinition.h" +#include + +#include namespace o2::aod { diff --git a/PWGJE/DataModel/GammaJetAnalysisTree.h b/PWGJE/DataModel/GammaJetAnalysisTree.h new file mode 100644 index 00000000000..02a9602ec6e --- /dev/null +++ b/PWGJE/DataModel/GammaJetAnalysisTree.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. + +/// +/// \brief Table definitions for gamma-jet analyses +/// +/// \author Florian Jonas + +#ifndef PWGJE_DATAMODEL_GAMMAJETANALYSISTREE_H_ +#define PWGJE_DATAMODEL_GAMMAJETANALYSISTREE_H_ + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod::gjanalysis +{ +enum class ClusterOrigin { + kUnknown = 0, + kPhoton, // dominant amount of energy from the cluster is from a photon + kPromptPhoton, + kDirectPromptPhoton, + kFragmentationPhoton, + kDecayPhoton, // the particle that produced the cluster is a decay product + kDecayPhotonPi0, // the cluster was produced by a pi0 decay + kDecayPhotonEta, // the cluster was produced by a eta decay + kMergedPi0, // the cluster was produced by a merged pi0, i.e. two photons contribute to the cluster that both come from pi0 decay + kMergedEta, // the cluster was produced by a merged eta, i.e. two photons contribute to the cluster that both come from eta decay + kConvertedPhoton, // the cluster was produced by a converted photon, i.e. a photon that converted to an electron-positron pair and one of the electrons was detected in the cluster +}; +enum class ParticleOrigin { + kUnknown = 0, + kPromptPhoton, + kDirectPromptPhoton, + kFragmentationPhoton, + kDecayPhoton, + kDecayPhotonPi0, + kDecayPhotonEta, + kDecayPhotonOther, + kPi0 +}; +} // namespace o2::aod::gjanalysis +namespace o2::aod +{ + +// Collision level information +namespace gjevent +{ //! 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; + +// Information about the MC collision that was matched to the reconstructed collision +namespace gjmcevent +{ +DECLARE_SOA_INDEX_COLUMN(GjEvent, gjevent); +DECLARE_SOA_COLUMN(Weight, weight, double); +DECLARE_SOA_COLUMN(Rho, rho, float); // gen level rho +DECLARE_SOA_COLUMN(IsMultipleAssigned, isMultipleAssigned, bool); // if the corresponding MC collision matched to this rec collision was also matched to other rec collisions (allows to skip those on analysis level ) +} // namespace gjmcevent +DECLARE_SOA_TABLE(GjMCEvents, "AOD", "GJMCEVENT", gjmcevent::GjEventId, gjmcevent::Weight, gjmcevent::Rho, gjmcevent::IsMultipleAssigned) +// Information about EMCal clusters +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, float); //! 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) + +// MC information for reconstructed EMCal clusters +namespace gjgammamcinfo +{ +DECLARE_SOA_COLUMN(Origin, origin, uint16_t); +DECLARE_SOA_COLUMN(LeadingEnergyFraction, leadingEnergyFraction, float); // fraction of energy from the leading MC particle +} // namespace gjgammamcinfo +DECLARE_SOA_TABLE(GjGammaMCInfos, "AOD", "GJGAMMAMCINFO", gjgamma::GjEventId, gjgammamcinfo::Origin, gjgammamcinfo::LeadingEnergyFraction) + +// Generator level particle information from the MC collision that was matched to the reconstructed collision +namespace gjmcparticle +{ +DECLARE_SOA_INDEX_COLUMN(GjEvent, gjevent); +DECLARE_SOA_COLUMN(Energy, energy, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(PdgCode, pdgCode, ushort); // TODO also add smoe origin of particle? maybe only save original pi0 and eta and photon (not decay photons) +DECLARE_SOA_COLUMN(MCIsolation, mcIsolation, float); // isolation in cone on mc gen level +DECLARE_SOA_COLUMN(Origin, origin, uint16_t); // origin of particle +} // namespace gjmcparticle +DECLARE_SOA_TABLE(GjMCParticles, "AOD", "GJMCPARTICLE", gjmcparticle::GjEventId, gjmcparticle::Energy, gjmcparticle::Eta, gjmcparticle::Phi, gjmcparticle::Pt, gjmcparticle::PdgCode, gjmcparticle::MCIsolation, gjmcparticle::Origin) + +// Reconstructed charged jet information +namespace gjchjet +{ +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", gjgamma::GjEventId, gjchjet::Pt, gjchjet::Eta, gjchjet::Phi, gjchjet::Radius, gjchjet::Energy, gjchjet::Mass, gjchjet::Area, gjchjet::LeadingTrackPt, gjchjet::PerpConeRho, gjchjet::NConstituents) + +// MC information for reconstructed charged jet +namespace gjchjetmcinfo +{ +DECLARE_SOA_COLUMN(MatchedJetIndexGeo, matchedJetIndexGeo, int); +DECLARE_SOA_COLUMN(MatchedJetIndexPt, matchedJetIndexPt, int); +} // namespace gjchjetmcinfo +DECLARE_SOA_TABLE(GjChJetMCInfos, "AOD", "GJCHJETMCINFO", gjgamma::GjEventId, gjchjetmcinfo::MatchedJetIndexGeo, gjchjetmcinfo::MatchedJetIndexPt) + +// MC information for generator level jets of associated MC collision +namespace gjmcjet +{ +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(PerpConeRho, perpconerho, float); +} // namespace gjmcjet +DECLARE_SOA_TABLE(GjMCJets, "AOD", "GJMCJET", gjgamma::GjEventId, gjmcjet::Pt, gjmcjet::Eta, gjmcjet::Phi, gjmcjet::Radius, gjmcjet::Energy, gjmcjet::Mass, gjmcjet::Area, gjmcjet::PerpConeRho) + +} // namespace o2::aod + +#endif // PWGJE_DATAMODEL_GAMMAJETANALYSISTREE_H_ diff --git a/PWGJE/DataModel/Jet.h b/PWGJE/DataModel/Jet.h index 33b8fdb4320..f4afdc17d1f 100644 --- a/PWGJE/DataModel/Jet.h +++ b/PWGJE/DataModel/Jet.h @@ -23,19 +23,20 @@ #ifndef PWGJE_DATAMODEL_JET_H_ #define PWGJE_DATAMODEL_JET_H_ -#include -#include "Framework/AnalysisDataModel.h" -#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGHF/DataModel/DerivedTables.h" #include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataDQ.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" +#include "PWGLF/DataModel/V0SelectorTables.h" + +#include + +#include +#include namespace o2::aod { @@ -61,7 +62,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_) \ @@ -153,14 +153,14 @@ 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") + 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 @@ -176,65 +176,125 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! absolute p 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") -namespace o2::aod -{ 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(DsCharged, JTrackDsSub, HfDsBases, HfDsPBases, "DS"); +DECLARE_JET_TABLES_LEVELS(DstarCharged, JTrackDstarSub, HfDstarBases, HfDstarPBases, "DST"); +DECLARE_JET_TABLES_LEVELS(LcCharged, JTrackLcSub, HfLcBases, HfLcPBases, "Lc"); +DECLARE_JET_TABLES_LEVELS(B0Charged, JTrackB0Sub, HfB0Bases, HfB0PBases, "B0"); +DECLARE_JET_TABLES_LEVELS(BplusCharged, JTrackBplusSub, HfBplusBases, HfBplusPBases, "BP"); +DECLARE_JET_TABLES_LEVELS(XicToXiPiPiCharged, JTrackXicToXiPiPiSub, HfXicToXiPiPiBases, HfXicToXiPiPiPBases, "XICXPP"); DECLARE_JET_TABLES_LEVELS(V0Charged, JTrackSub, V0Cores, JV0Mcs, "V0"); DECLARE_JET_TABLES_LEVELS(DielectronCharged, JTrackSub, Dielectrons, JDielectronMcs, "DIEL"); // duplicate jet tables (added as needed for analyses) DECLARE_JET_DUPLICATE_TABLES_LEVELS(Charged, JTrackSub, HfD0Bases, HfD0PBases, "C", 1); -} // namespace o2::aod +#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 JetClustersMCD = o2::soa::Join; - -using JetMcCollisions = o2::aod::JMcCollisions; +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 = JMcCollisions; using JetMcCollision = JetMcCollisions::iterator; -using JetParticles = o2::aod::JMcParticles; - -using CollisionsD0 = o2::soa::Join; -using CandidatesD0Data = o2::soa::Join; -using CandidatesD0MCD = o2::soa::Join; -using JetTracksSubD0 = o2::aod::JTrackD0Subs; -using McCollisionsD0 = o2::soa::Join; -using CandidatesD0MCP = o2::soa::Join; - -using CollisionsLc = o2::soa::Join; -using CandidatesLcData = o2::soa::Join; -using CandidatesLcMCD = o2::soa::Join; -using JetTracksSubLc = o2::aod::JTrackLcSubs; -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 CandidatesBplusMCP = o2::soa::Join; - -using CandidatesV0Data = o2::soa::Join; -using CandidatesV0MCD = o2::soa::Join; -// using V0Daughters = o2::aod::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 = o2::aod::JTrackDielectronSubs; -using McCollisionsDielectron = o2::soa::Join; -using CandidatesDielectronMCP = o2::soa::Join; +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 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 CollisionsDs = o2::soa::Join; +using CandidatesDsData = o2::soa::Join; +using CandidatesDsMCD = o2::soa::Join; +using JetTracksSubDs = JTrackDsSubs; +using JetParticlesSubDs = JMcParticleDsSubs; +using McCollisionsDs = o2::soa::Join; +using CandidatesDsMCP = o2::soa::Join; + +using CollisionsDstar = o2::soa::Join; +using CandidatesDstarData = o2::soa::Join; +using CandidatesDstarMCD = o2::soa::Join; +using JetTracksSubDstar = JTrackDstarSubs; +using JetParticlesSubDstar = JMcParticleDstarSubs; +using McCollisionsDstar = o2::soa::Join; +using CandidatesDstarMCP = o2::soa::Join; + +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 CollisionsB0 = o2::soa::Join; +using CandidatesB0Data = o2::soa::Join; +using CandidatesB0MCD = o2::soa::Join; +using JetTracksSubB0 = JTrackB0Subs; +using JetParticlesSubB0 = JMcParticleB0Subs; +using McCollisionsB0 = o2::soa::Join; +using CandidatesB0MCP = o2::soa::Join; + +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 CollisionsXicToXiPiPi = o2::soa::Join; +using CandidatesXicToXiPiPiData = o2::soa::Join; +using CandidatesXicToXiPiPiMCD = o2::soa::Join; +using JetTracksSubXicToXiPiPi = JTrackXicToXiPiPiSubs; +using JetParticlesSubXicToXiPiPi = JMcParticleXicToXiPiPiSubs; +using McCollisionsXicToXiPiPi = o2::soa::Join; +using CandidatesXicToXiPiPiMCP = o2::soa::Join; + +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 b5439774663..b18565c4254 100644 --- a/PWGJE/DataModel/JetReducedData.h +++ b/PWGJE/DataModel/JetReducedData.h @@ -17,11 +17,15 @@ #ifndef PWGJE_DATAMODEL_JETREDUCEDDATA_H_ #define PWGJE_DATAMODEL_JETREDUCEDDATA_H_ +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/EMCALClusters.h" // IWYU pragma: keep + +#include +#include // IWYU pragma: keep + #include +#include #include -#include "Framework/AnalysisDataModel.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" namespace o2::aod { @@ -32,31 +36,35 @@ 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_BITMAP_COLUMN(Rct, rct, 32); +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, + jbc::Rct); 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 { @@ -65,88 +73,119 @@ DECLARE_SOA_INDEX_COLUMN(JBC, bc); DECLARE_SOA_COLUMN(PosX, posX, float); 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(MultFV0A, multFV0A, float); +DECLARE_SOA_COLUMN(MultFV0C, multFV0C, float); +DECLARE_SOA_DYNAMIC_COLUMN(MultFV0M, multFV0M, + [](float multFV0A, float multFV0C) -> float { return multFV0A + multFV0C; }); +DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); +DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); +DECLARE_SOA_DYNAMIC_COLUMN(MultFT0M, multFT0M, + [](float multFT0A, float multFT0C) -> float { return multFT0A + multFT0C; }); +DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); +DECLARE_SOA_COLUMN(CentFV0M, centFV0M, float); // only Run 2 +DECLARE_SOA_COLUMN(CentFT0A, centFT0A, float); +DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(CentFT0CVariant1, centFT0CVariant1, float); +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_BITMAP_COLUMN(Rct, rct, 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(ReadSelectedCounts, readSelectedCounts, 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); +DECLARE_SOA_COLUMN(IsOutlier, isOutlier, 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::MultFV0A, + jcollision::MultFV0C, + jcollision::MultFV0M, + jcollision::MultFT0A, + jcollision::MultFT0C, + jcollision::MultFT0M, + jcollision::CentFV0A, + jcollision::CentFV0M, + jcollision::CentFT0A, + jcollision::CentFT0C, + jcollision::CentFT0M, + jcollision::CentFT0CVariant1, + jcollision::HadronicRate, + jcollision::TrackOccupancyInTimeRange, + jcollision::Alias, + jcollision::EventSel, + jcollision::Rct, + 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(JCollisionOutliers, "JCOLLISIONOUTLR", + jcollision::IsOutlier); -DECLARE_SOA_TABLE(JCollisionPIs, "AOD", "JCOLLISIONPI", - jcollision::CollisionId); +DECLARE_SOA_TABLE_STAGED(JEMCCollisionLbs, "JEMCCOLLISIONLB", + jcollision::IsAmbiguous, + jcollision::IsEMCALReadout); +using JEMCCollisionLb = JEMCCollisionLbs::iterator; +using StoredJEMCCollisionLb = StoredJEMCCollisionLbs::iterator; -DECLARE_SOA_TABLE(StoredJCollisionPIs, "AOD1", "JCOLLISIONPI", - jcollision::CollisionId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JCollisionPIs, "JCOLLISIONPI", + jcollision::CollisionId); + +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::ReadSelectedCounts, - jcollision::WrittenCounts); - -DECLARE_SOA_TABLE(StoredCollisionCounts, "AOD1", "COLLCOUNT", - jcollision::ReadCounts, - jcollision::ReadSelectedCounts, - 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 { @@ -154,45 +193,52 @@ DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); DECLARE_SOA_COLUMN(PosX, posX, float); DECLARE_SOA_COLUMN(PosY, posY, float); DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(MultFV0A, multFV0A, float); +DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); +DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, 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); +DECLARE_SOA_COLUMN(PtHard, ptHard, float); +DECLARE_SOA_COLUMN(IsOutlier, isOutlier, bool); } // 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::MultFV0A, + jmccollision::MultFT0A, + jmccollision::MultFT0C, + jmccollision::CentFT0M, + jmccollision::Weight, + jmccollision::SubGeneratorId, + jmccollision::Accepted, + jmccollision::Attempted, + jmccollision::XsectGen, + jmccollision::XsectErr, + jmccollision::PtHard); 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_STAGED(JMcCollisionLbs, "JMCCOLLISIONLB", + jmccollisionlb::JMcCollisionId); -DECLARE_SOA_TABLE(StoredJMcCollisionLbs, "AOD1", "JMCCOLLISIONLB", - jmccollisionlb::JMcCollisionId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JMcCollisionOutliers, "JMCCOLLISIONOUTLR", + jmccollision::IsOutlier); namespace jtrack { @@ -201,8 +247,14 @@ 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(DCAXY, dcaXY, 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, @@ -216,59 +268,61 @@ 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(JTrackExtras, "AOD", "JTRACKEXTRA", - jtrack::DCAXY, - jtrack::DCAZ, - jtrack::Sigma1Pt); - -DECLARE_SOA_TABLE(StoredJTrackExtras, "AOD1", "JTRACKEXTRA", - jtrack::DCAXY, - jtrack::DCAZ, - jtrack::Sigma1Pt, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(JTrackPIs, "AOD", "JTRACKPI", - jtrack::TrackId); - -DECLARE_SOA_TABLE(StoredJTrackPIs, "AOD1", "JTRACKPI", - jtrack::TrackId, - o2::soa::Marker<1>); +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); +DECLARE_SOA_COLUMN(EtaDiff, etaDiff, float); +DECLARE_SOA_COLUMN(PhiDiff, phiDiff, float); +} // namespace jemctrack + +DECLARE_SOA_TABLE_STAGED(JEMCTracks, "JEMCTrack", + jemctrack::JTrackId, + jemctrack::EtaEMCAL, + jemctrack::PhiEMCAL, + jemctrack::EtaDiff, + jemctrack::PhiDiff); namespace jmcparticle { @@ -280,11 +334,12 @@ DECLARE_SOA_COLUMN(Phi, phi, float); DECLARE_SOA_COLUMN(Y, y, float); DECLARE_SOA_COLUMN(E, e, 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_COLUMN(StatusCode, statusCode, int); +DECLARE_SOA_COLUMN(Flags, flags, uint8_t); + DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(Daughters, daughters); + DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Py, py, @@ -295,71 +350,60 @@ DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); 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_DYNAMIC_COLUMN(ProducedByGenerator, producedByGenerator, //! True if particle produced by the generator (==TMCProcess::kPrimary); False if by the transport code + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0; }); +DECLARE_SOA_DYNAMIC_COLUMN(FromBackgroundEvent, fromBackgroundEvent, //! Particle from background event + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::FromBackgroundEvent) == o2::aod::mcparticle::enums::FromBackgroundEvent; }); +DECLARE_SOA_DYNAMIC_COLUMN(GetProcess, getProcess, //! The VMC physics code (as int) that generated this particle (see header TMCProcess.h in ROOT) + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return 0 /*TMCProcess::kPrimary*/; } else { return statusCode; } }); +DECLARE_SOA_DYNAMIC_COLUMN(GetGenStatusCode, getGenStatusCode, //! The native status code put by the generator, or -1 if a particle produced during transport + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return o2::mcgenstatus::getGenStatusCode(statusCode); } else { return -1; } }); +DECLARE_SOA_DYNAMIC_COLUMN(GetHepMCStatusCode, getHepMCStatusCode, //! The HepMC status code put by the generator, or -1 if a particle produced during transport + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return o2::mcgenstatus::getHepMCStatusCode(statusCode); } else { return -1; } }); +DECLARE_SOA_DYNAMIC_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, //! True if particle is considered a physical primary according to the ALICE definition + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::PhysicalPrimary) == o2::aod::mcparticle::enums::PhysicalPrimary; }); -using JMcParticle = JMcParticles::iterator; +} // namespace jmcparticle -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>); +DECLARE_SOA_TABLE_STAGED(JMcParticles, "JMCPARTICLE", + o2::soa::Index<>, + jmcparticle::JMcCollisionId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::StatusCode, + jmcparticle::Flags, + jmcparticle::MothersIds, + jmcparticle::DaughtersIdSlice, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, + jmcparticle::FromBackgroundEvent, + jmcparticle::GetProcess, + jmcparticle::GetGenStatusCode, + jmcparticle::GetHepMCStatusCode, + jmcparticle::IsPhysicalPrimary); +using JMcParticle = JMcParticles::iterator; 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 { @@ -387,51 +431,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(StoredJClusterPIs, "AOD1", "JCLUSTERPI", - jcluster::EMCALClusterId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JClusterPIs, "JCLUSTERPI", + jcluster::EMCALClusterId); -DECLARE_SOA_TABLE(JClusterTracks, "AOD", "JCLUSTERTRACK", //! - jcluster::JTrackIds); +DECLARE_SOA_TABLE_STAGED(JClusterTracks, "JCLUSTERTRACK", //! + jcluster::JTrackIds); -DECLARE_SOA_TABLE(StoredJClusterTracks, "AOD1", "JCLUSTERTRACK", //! - jcluster::JTrackIds, - o2::soa::Marker<1>); +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, mcParticle); +DECLARE_SOA_ARRAY_INDEX_COLUMN(JMcParticle, mcParticles); DECLARE_SOA_COLUMN(AmplitudeA, amplitudeA, std::vector); } // namespace jmcclusterlb -DECLARE_SOA_TABLE(JMcClusterLbs, "AOD", "JMCCLUSTERLB", //! - jmcclusterlb::JMcParticleIds, jmcclusterlb::AmplitudeA); - -DECLARE_SOA_TABLE(StoredJMcClusterLbs, "AOD1", "JMCCLUSTERLB", //! - jmcclusterlb::JMcParticleIds, jmcclusterlb::AmplitudeA, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JMcClusterLbs, "JMCCLUSTERLB", //! + jmcclusterlb::JMcParticleIds, jmcclusterlb::AmplitudeA); namespace jdummy { @@ -439,14 +476,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 index 3a3cbd90c06..f9395b76fba 100644 --- a/PWGJE/DataModel/JetReducedDataDQ.h +++ b/PWGJE/DataModel/JetReducedDataDQ.h @@ -17,77 +17,51 @@ #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" + +#include +#include // IWYU pragma: keep + +#include +#include namespace o2::aod { +namespace jdielectronmccollision +{ +DECLARE_SOA_COLUMN(DummyDQ, dummyDQ, bool); +} // namespace jdielectronmccollision -DECLARE_SOA_TABLE(JDielectronMcCollisions, "AOD", "JDIELMCCOLL", - o2::soa::Index<>, - jmccollision::PosX, - jmccollision::PosY, - jmccollision::PosZ, - o2::soa::Marker<3>); - -using JMcCollision = JMcCollisions::iterator; +DECLARE_SOA_TABLE_STAGED(JDielectronMcCollisions, "JDIELMCCOLL", + o2::soa::Index<>, + jmccollision::PosX, + jmccollision::PosY, + jmccollision::PosZ); -DECLARE_SOA_TABLE(StoredJDielectronMcCollisions, "AOD1", "JDIELMCCOLL", - o2::soa::Index<>, - jmccollision::PosX, - jmccollision::PosY, - jmccollision::PosZ, - o2::soa::Marker<4>); +DECLARE_SOA_TABLE_STAGED(JDielectronMcRCollDummys, "JDIELMCRCOLLDUM", + jdielectronmccollision::DummyDQ); namespace jdielectronindices { -DECLARE_SOA_INDEX_COLUMN(JCollision, collision); 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"); -DECLARE_SOA_INDEX_COLUMN(JMcCollision, mcCollision); -DECLARE_SOA_INDEX_COLUMN(JMcParticle, mcParticle); } // namespace jdielectronindices -namespace dielectroncollisioncounter -{ -DECLARE_SOA_COLUMN(ReadCounts, readCounts, std::vector); -DECLARE_SOA_COLUMN(ReadSelectedCounts, readSelectedCounts, std::vector); -DECLARE_SOA_COLUMN(WrittenCounts, writtenCounts, std::vector); -} // namespace dielectroncollisioncounter - -DECLARE_SOA_TABLE(JDielectronCollisionIds, "AOD", "JDIELCOLLID", - jdielectronindices::JCollisionId); +DECLARE_SOA_TABLE_STAGED(JDielectronCollisionIds, "JDIELCOLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); -DECLARE_SOA_TABLE(StoredJDielectronCollisionIds, "AOD1", "JDIELCOLLID", - jdielectronindices::JCollisionId, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(JDielectronMcCollisionIds, "AOD", "JDIELMCCOLLID", - jdielectronindices::JMcCollisionId); - -DECLARE_SOA_TABLE(StoredJDielectronMcCollisionIds, "AOD1", "JDIELMCCOLLID", - jdielectronindices::JMcCollisionId, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(JDielectronIds, "AOD", "JDIELID", - jdielectronindices::JCollisionId, - jdielectronindices::Prong0Id, - jdielectronindices::Prong1Id); +DECLARE_SOA_TABLE_STAGED(JDielectronMcCollisionIds, "JDIELMCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); -DECLARE_SOA_TABLE(StoredJDielectronIds, "AOD1", "JDIELID", - jdielectronindices::JCollisionId, - jdielectronindices::Prong0Id, - jdielectronindices::Prong1Id, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(DielectronCollisionCounts, "AOD", "DIELCOLLCOUNT", - dielectroncollisioncounter::ReadCounts, - dielectroncollisioncounter::ReadSelectedCounts, - dielectroncollisioncounter::WrittenCounts); +DECLARE_SOA_TABLE_STAGED(JDielectronIds, "JDIELID", + jcandidateindices::JCollisionId, + jdielectronindices::Prong0Id, + jdielectronindices::Prong1Id, + o2::soa::Marker); namespace jdielectronmc { @@ -98,9 +72,8 @@ 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_COLUMN(StatusCode, statusCode, int); +DECLARE_SOA_COLUMN(Flags, flags, uint8_t); DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(Daughters, daughters); DECLARE_SOA_COLUMN(DecayFlag, decayFlag, int8_t); @@ -113,65 +86,57 @@ 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); }); +DECLARE_SOA_DYNAMIC_COLUMN(Energy, energy, + [](float e) -> float { return e; }); + +DECLARE_SOA_DYNAMIC_COLUMN(ProducedByGenerator, producedByGenerator, //! True if particle produced by the generator (==TMCProcess::kPrimary); False if by the transport code + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0; }); +DECLARE_SOA_DYNAMIC_COLUMN(FromBackgroundEvent, fromBackgroundEvent, //! Particle from background event + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::FromBackgroundEvent) == o2::aod::mcparticle::enums::FromBackgroundEvent; }); +DECLARE_SOA_DYNAMIC_COLUMN(GetProcess, getProcess, //! The VMC physics code (as int) that generated this particle (see header TMCProcess.h in ROOT) + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return 0 /*TMCProcess::kPrimary*/; } else { return statusCode; } }); +DECLARE_SOA_DYNAMIC_COLUMN(GetGenStatusCode, getGenStatusCode, //! The native status code put by the generator, or -1 if a particle produced during transport + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return o2::mcgenstatus::getGenStatusCode(statusCode); } else { return -1; } }); +DECLARE_SOA_DYNAMIC_COLUMN(GetHepMCStatusCode, getHepMCStatusCode, //! The HepMC status code put by the generator, or -1 if a particle produced during transport + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return o2::mcgenstatus::getHepMCStatusCode(statusCode); } else { return -1; } }); +DECLARE_SOA_DYNAMIC_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, //! True if particle is considered a physical primary according to the ALICE definition + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::PhysicalPrimary) == o2::aod::mcparticle::enums::PhysicalPrimary; }); } // namespace jdielectronmc -DECLARE_SOA_TABLE(JDielectronMcs, "AOD", "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); +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::StatusCode, + jdielectronmc::Flags, + jdielectronmc::DecayFlag, + jdielectronmc::Origin, + jdielectronmc::Px, + jdielectronmc::Py, + jdielectronmc::Pz, + jdielectronmc::P, + jdielectronmc::Energy, + jdielectronmc::ProducedByGenerator, + jdielectronmc::FromBackgroundEvent, + jdielectronmc::GetProcess, + jdielectronmc::GetGenStatusCode, + jdielectronmc::GetHepMCStatusCode, + jdielectronmc::IsPhysicalPrimary); using JDielectronMc = JDielectronMcs::iterator; - -DECLARE_SOA_TABLE(StoredJDielectronMcs, "AOD1", "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, - o2::soa::Marker<1>); - using StoredJDielectronMc = StoredJDielectronMcs::iterator; -DECLARE_SOA_TABLE(JDielectronMcIds, "AOD", "JDIELMCID", - jdielectronindices::JMcCollisionId, - jdielectronindices::JMcParticleId, - jdielectronmc::MothersIds, - jdielectronmc::DaughtersIdSlice); - -DECLARE_SOA_TABLE(StoredJDielectronMcIds, "AOD1", "JDIELMCID", - jdielectronindices::JMcCollisionId, - jdielectronindices::JMcParticleId, - jdielectronmc::MothersIds, - jdielectronmc::DaughtersIdSlice, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JDielectronMcIds, "JDIELMCID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + jdielectronmc::MothersIds, + jdielectronmc::DaughtersIdSlice); namespace jdummydq { @@ -180,32 +145,26 @@ DECLARE_SOA_COLUMN(DummyDQ, dummyDQ, bool); } // namespace jdummydq DECLARE_SOA_TABLE(JDielectron1Dummys, "AOD", "JDIEL1DUMMY", - o2::soa::Index<>, jdummydq::DummyDQ, o2::soa::Marker<1>); DECLARE_SOA_TABLE(JDielectron2Dummys, "AOD", "JDIEL2DUMMY", - o2::soa::Index<>, jdummydq::DummyDQ, o2::soa::Marker<2>); DECLARE_SOA_TABLE(JDielectron3Dummys, "AOD", "JDIEL3DUMMY", - o2::soa::Index<>, jdummydq::DummyDQ, o2::soa::Marker<3>); DECLARE_SOA_TABLE(JDielectron4Dummys, "AOD", "JDIEL4DUMMY", - o2::soa::Index<>, jdummydq::DummyDQ, o2::soa::Marker<4>); DECLARE_SOA_TABLE(JDielectron5Dummys, "AOD", "JDIEL5DUMMY", - o2::soa::Index<>, jdummydq::DummyDQ, o2::soa::Marker<5>); DECLARE_SOA_TABLE(JDielectron6Dummys, "AOD", "JDIEL6DUMMY", - o2::soa::Index<>, jdummydq::DummyDQ, o2::soa::Marker<6>); diff --git a/PWGJE/DataModel/JetReducedDataHF.h b/PWGJE/DataModel/JetReducedDataHF.h index 83118732cd1..7a2f1c86cd1 100644 --- a/PWGJE/DataModel/JetReducedDataHF.h +++ b/PWGJE/DataModel/JetReducedDataHF.h @@ -17,127 +17,331 @@ #ifndef PWGJE_DATAMODEL_JETREDUCEDDATAHF_H_ #define PWGJE_DATAMODEL_JETREDUCEDDATAHF_H_ -#include -#include -#include "Framework/AnalysisDataModel.h" -#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/EMCALClusters.h" // IWYU pragma: keep #include "PWGJE/DataModel/JetReducedData.h" +#include +#include // IWYU pragma: keep + +#include + +#include + 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; +constexpr uint JMarkerDstar = 6; +constexpr uint JMarkerB0 = 7; +constexpr uint JMarkerDs = 8; +constexpr uint JMarkerXicToXiPiPi = 9; + +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 jd0indices +} // namespace jcandidateindices -namespace d0collisioncounter +namespace jd0indices { -DECLARE_SOA_COLUMN(ReadCounts, readCounts, std::vector); -DECLARE_SOA_COLUMN(ReadSelectedCounts, readSelectedCounts, std::vector); -DECLARE_SOA_COLUMN(WrittenCounts, writtenCounts, std::vector); -} // namespace d0collisioncounter +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0, prong0, int, JTracks, "_0"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1, prong1, int, JTracks, "_1"); +} // namespace jd0indices + +DECLARE_SOA_TABLE_STAGED(JD0CollisionIds, "JD0COLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); -DECLARE_SOA_TABLE(JD0CollisionIds, "AOD", "JD0COLLID", - jd0indices::JCollisionId); +DECLARE_SOA_TABLE_STAGED(JD0McCollisionIds, "JD0MCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); -DECLARE_SOA_TABLE(StoredJD0CollisionIds, "AOD1", "JD0COLLID", - jd0indices::JCollisionId, +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(DummyD0, dummyD0, bool); +} // namespace jdummyd0 + +DECLARE_SOA_TABLE(JDumD0ParDaus, "AOD", "JDUMD0PARDAU", + jdummyd0::DummyD0, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(JD0McCollisionIds, "AOD", "JD0MCCOLLID", - jd0indices::JMcCollisionId); +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_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); -DECLARE_SOA_TABLE(StoredJD0McCollisionIds, "AOD1", "JD0MCCOLLID", - jd0indices::JMcCollisionId, +} // namespace jdummydplus +DECLARE_SOA_TABLE(JDumDplusParDaus, "AOD", "JDUMDPPARDAU", + jdummydplus::DummyDplus, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(JD0Ids, "AOD", "JD0ID", - jd0indices::JCollisionId, - jd0indices::Prong0Id, - jd0indices::Prong1Id); +DECLARE_SOA_TABLE(JDumDplusMlDaus, "AOD", "JDUMDPMLDAU", + jdummydplus::DummyDplus, + o2::soa::Marker<2>); + +// might have to update!!!!!!!!!!!!!!!!!!!!!! -DECLARE_SOA_TABLE(StoredJD0Ids, "AOD1", "JD0ID", - jd0indices::JCollisionId, - jd0indices::Prong0Id, - jd0indices::Prong1Id, +namespace jdsindices +{ +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 jdsindices + +DECLARE_SOA_TABLE_STAGED(JDsCollisionIds, "JDSCOLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JDsMcCollisionIds, "JDSMCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JDsIds, "JDSID", + jcandidateindices::JCollisionId, + jdsindices::Prong0Id, + jdsindices::Prong1Id, + jdsindices::Prong2Id); + +DECLARE_SOA_TABLE_STAGED(JDsPIds, "JDSPID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + o2::soa::Marker); + +namespace jdummyds +{ + +DECLARE_SOA_COLUMN(DummyDs, dummyDs, bool); + +} // namespace jdummyds +DECLARE_SOA_TABLE(JDumDsParDaus, "AOD", "JDUMDSPARDAU", + jdummyds::DummyDs, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(JD0PIds, "AOD", "JD0PID", - jd0indices::JMcCollisionId, - jd0indices::JMcParticleId); +DECLARE_SOA_TABLE(JDumDsMlDaus, "AOD", "JDUMDSMLDAU", + jdummyds::DummyDs, + o2::soa::Marker<2>); -DECLARE_SOA_TABLE(StoredJD0PIds, "AOD1", "JD0PID", - jd0indices::JMcCollisionId, - jd0indices::JMcParticleId, +namespace jdstarindices +{ +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 jdstarindices + +DECLARE_SOA_TABLE_STAGED(JDstarCollisionIds, "JDSTCOLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JDstarMcCollisionIds, "JDSTMCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JDstarIds, "JDSTID", + jcandidateindices::JCollisionId, + jdstarindices::Prong0Id, + jdstarindices::Prong1Id, + jdstarindices::Prong2Id); + +DECLARE_SOA_TABLE_STAGED(JDstarPIds, "JDSTPID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + o2::soa::Marker); + +namespace jdummydstar +{ + +DECLARE_SOA_COLUMN(DummyDstar, dummyDstar, bool); + +} // namespace jdummydstar +DECLARE_SOA_TABLE(JDumDstarParEs, "AOD", "JDUMDSTPARE", + jdummydstar::DummyDstar, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(D0CollisionCounts, "AOD", "D0COLLCOUNT", - d0collisioncounter::ReadCounts, - d0collisioncounter::ReadSelectedCounts, - d0collisioncounter::WrittenCounts); +DECLARE_SOA_TABLE(JDumDstarMlDaus, "AOD", "JDUMDSTMLDAU", + jdummydstar::DummyDstar, + 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(ReadSelectedCounts, readSelectedCounts, std::vector); -DECLARE_SOA_COLUMN(WrittenCounts, writtenCounts, std::vector); -} // namespace lccollisioncounter -DECLARE_SOA_TABLE(JLcCollisionIds, "AOD", "JLCCOLLID", - jlcindices::JCollisionId); +DECLARE_SOA_COLUMN(DummyLc, dummyLc, bool); -DECLARE_SOA_TABLE(StoredJLcCollisionIds, "AOD1", "JLCCOLLID", - jlcindices::JCollisionId, +} // namespace jdummylc +DECLARE_SOA_TABLE(JDumLcParDaus, "AOD", "JDUMLCPARDAU", + jdummylc::DummyLc, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(JLcMcCollisionIds, "AOD", "JLCMCCOLLID", - jlcindices::JMcCollisionId); +DECLARE_SOA_TABLE(JDumLcMlDaus, "AOD", "JDUMLCMLDAU", + jdummylc::DummyLc, + o2::soa::Marker<2>); -DECLARE_SOA_TABLE(StoredJLcMcCollisionIds, "AOD1", "JLCMCCOLLID", - jlcindices::JMcCollisionId, - o2::soa::Marker<1>); +namespace jb0indices +{ +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_FULL(Prong3, prong3, int, JTracks, "_3"); +} // namespace jb0indices -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_STAGED(JB0CollisionIds, "JB0COLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); -DECLARE_SOA_TABLE(JLcPIds, "AOD", "JLCPID", - jlcindices::JMcCollisionId, - jlcindices::JMcParticleId); +DECLARE_SOA_TABLE_STAGED(JB0McCollisionIds, "JB0MCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JB0Ids, "JB0ID", + jcandidateindices::JCollisionId, + jb0indices::Prong0Id, + jb0indices::Prong1Id, + jb0indices::Prong2Id, + jb0indices::Prong3Id); + +DECLARE_SOA_TABLE_STAGED(JB0PIds, "JB0PID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + o2::soa::Marker); + +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 jxictoxipipiindices +{ +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_FULL(Prong3, prong3, int, JTracks, "_3"); +DECLARE_SOA_INDEX_COLUMN_FULL(Prong4, prong4, int, JTracks, "_4"); +} // namespace jxictoxipipiindices + +DECLARE_SOA_TABLE_STAGED(JXicToXiPiPiCollisionIds, "JXICXPPCOLLID", + jcandidateindices::JCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JXicToXiPiPiMcCollisionIds, "JXICXPPMCCOLLID", + jcandidateindices::JMcCollisionId, + o2::soa::Marker); + +DECLARE_SOA_TABLE_STAGED(JXicToXiPiPiIds, "JXICXPPID", + jcandidateindices::JCollisionId, + jxictoxipipiindices::Prong0Id, + jxictoxipipiindices::Prong1Id, + jxictoxipipiindices::Prong2Id, + jxictoxipipiindices::Prong3Id, + jxictoxipipiindices::Prong4Id); + +DECLARE_SOA_TABLE_STAGED(JXicToXiPiPiPIds, "JXICXPPPID", + jcandidateindices::JMcCollisionId, + jcandidateindices::JMcParticleId, + o2::soa::Marker); + +namespace jdummyxictoxipipi +{ +DECLARE_SOA_COLUMN(DummyXicToXiPiPi, dummyXicToXiPiPi, bool); -DECLARE_SOA_TABLE(StoredJLcPIds, "AOD1", "JLCPID", - jlcindices::JMcCollisionId, - jlcindices::JMcParticleId, +} // namespace jdummyxictoxipipi +DECLARE_SOA_TABLE(JDumXicToXiPiPiParDaus, "AOD", "JDUMXICXPPPARDAU", + jdummyxictoxipipi::DummyXicToXiPiPi, o2::soa::Marker<1>); -DECLARE_SOA_TABLE(LcCollisionCounts, "AOD", "LcCOLLCOUNT", - lccollisioncounter::ReadCounts, - lccollisioncounter::ReadSelectedCounts, - lccollisioncounter::WrittenCounts); +DECLARE_SOA_TABLE(JDumXicToXiPiPiMlDaus, "AOD", "JDUMXICXPPMLDAU", + jdummyxictoxipipi::DummyXicToXiPiPi, + o2::soa::Marker<2>); } // namespace o2::aod diff --git a/PWGJE/DataModel/JetReducedDataSelector.h b/PWGJE/DataModel/JetReducedDataSelector.h new file mode 100644 index 00000000000..9529debc58e --- /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 + +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 index 8458d739cb9..ec460d5b186 100644 --- a/PWGJE/DataModel/JetReducedDataV0.h +++ b/PWGJE/DataModel/JetReducedDataV0.h @@ -17,30 +17,23 @@ #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 -{ +#include +#include // IWYU pragma: keep -DECLARE_SOA_TABLE(JV0McCollisions, "AOD", "JV0MCCOLL", - o2::soa::Index<>, - jmccollision::PosX, - jmccollision::PosY, - jmccollision::PosZ, - o2::soa::Marker<1>); +#include +#include -using JMcCollision = JMcCollisions::iterator; +namespace o2::aod +{ -DECLARE_SOA_TABLE(StoredJV0McCollisions, "AOD1", "JV0MCCOLL", - o2::soa::Index<>, - jmccollision::PosX, - jmccollision::PosY, - jmccollision::PosZ, - o2::soa::Marker<2>); +DECLARE_SOA_TABLE_STAGED(JV0McCollisions, "JV0MCCOLL", + o2::soa::Index<>, + jmccollision::PosX, + jmccollision::PosY, + jmccollision::PosZ, + o2::soa::Marker<3>); namespace jv0indices { @@ -52,43 +45,17 @@ DECLARE_SOA_INDEX_COLUMN(JMcCollision, mcCollision); DECLARE_SOA_INDEX_COLUMN(JMcParticle, mcParticle); } // namespace jv0indices -namespace v0collisioncounter -{ -DECLARE_SOA_COLUMN(ReadCounts, readCounts, std::vector); -DECLARE_SOA_COLUMN(ReadSelectedCounts, readSelectedCounts, std::vector); -DECLARE_SOA_COLUMN(WrittenCounts, writtenCounts, std::vector); -} // namespace v0collisioncounter - -DECLARE_SOA_TABLE(JV0CollisionIds, "AOD", "JV0COLLID", - jv0indices::JCollisionId); +DECLARE_SOA_TABLE_STAGED(JV0CollisionIds, "JV0COLLID", + jv0indices::JCollisionId); -DECLARE_SOA_TABLE(StoredJV0CollisionIds, "AOD1", "JV0COLLID", - jv0indices::JCollisionId, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(JV0McCollisionIds, "AOD", "JV0MCCOLLID", - jv0indices::JMcCollisionId); - -DECLARE_SOA_TABLE(StoredJV0McCollisionIds, "AOD1", "JV0MCCOLLID", - jv0indices::JMcCollisionId, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JV0McCollisionIds, "JV0MCCOLLID", + jv0indices::JMcCollisionId); DECLARE_SOA_TABLE(JV0Ids, "AOD", "JV0ID", jv0indices::JCollisionId, jv0indices::PosTrackId, jv0indices::NegTrackId); -DECLARE_SOA_TABLE(StoredJV0Ids, "AOD1", "JV0ID", - jv0indices::JCollisionId, - jv0indices::PosTrackId, - jv0indices::NegTrackId, - o2::soa::Marker<1>); - -DECLARE_SOA_TABLE(V0CollisionCounts, "AOD", "V0COLLCOUNT", - v0collisioncounter::ReadCounts, - v0collisioncounter::ReadSelectedCounts, - v0collisioncounter::WrittenCounts); - namespace jv0mc { DECLARE_SOA_COLUMN(Pt, pt, float); @@ -98,9 +65,8 @@ 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_COLUMN(StatusCode, statusCode, int); +DECLARE_SOA_COLUMN(Flags, flags, uint8_t); DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(Daughters, daughters); DECLARE_SOA_COLUMN(DecayFlag, decayFlag, int8_t); @@ -112,63 +78,56 @@ 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); }); +DECLARE_SOA_DYNAMIC_COLUMN(Energy, energy, + [](float e) -> float { return e; }); + +DECLARE_SOA_DYNAMIC_COLUMN(ProducedByGenerator, producedByGenerator, //! True if particle produced by the generator (==TMCProcess::kPrimary); False if by the transport code + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0; }); +DECLARE_SOA_DYNAMIC_COLUMN(FromBackgroundEvent, fromBackgroundEvent, //! Particle from background event + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::FromBackgroundEvent) == o2::aod::mcparticle::enums::FromBackgroundEvent; }); +DECLARE_SOA_DYNAMIC_COLUMN(GetProcess, getProcess, //! The VMC physics code (as int) that generated this particle (see header TMCProcess.h in ROOT) + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return 0 /*TMCProcess::kPrimary*/; } else { return statusCode; } }); +DECLARE_SOA_DYNAMIC_COLUMN(GetGenStatusCode, getGenStatusCode, //! The native status code put by the generator, or -1 if a particle produced during transport + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return o2::mcgenstatus::getGenStatusCode(statusCode); } else { return -1; } }); +DECLARE_SOA_DYNAMIC_COLUMN(GetHepMCStatusCode, getHepMCStatusCode, //! The HepMC status code put by the generator, or -1 if a particle produced during transport + [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return o2::mcgenstatus::getHepMCStatusCode(statusCode); } else { return -1; } }); +DECLARE_SOA_DYNAMIC_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, //! True if particle is considered a physical primary according to the ALICE definition + [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::PhysicalPrimary) == o2::aod::mcparticle::enums::PhysicalPrimary; }); } // namespace jv0mc -DECLARE_SOA_TABLE(JV0Mcs, "AOD", "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); +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::StatusCode, + jv0mc::Flags, + jv0mc::DecayFlag, + jv0mc::Px, + jv0mc::Py, + jv0mc::Pz, + jv0mc::P, + jv0mc::Energy, + jv0mc::ProducedByGenerator, + jv0mc::FromBackgroundEvent, + jv0mc::GetProcess, + jv0mc::GetGenStatusCode, + jv0mc::GetHepMCStatusCode, + jv0mc::IsPhysicalPrimary); using JV0Mc = JV0Mcs::iterator; - -DECLARE_SOA_TABLE(StoredJV0Mcs, "AOD1", "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, - o2::soa::Marker<1>); - using StoredJV0Mc = StoredJV0Mcs::iterator; -DECLARE_SOA_TABLE(JV0McIds, "AOD", "JV0MCID", - jv0indices::JMcCollisionId, - jv0indices::JMcParticleId, - jv0mc::MothersIds, - jv0mc::DaughtersIdSlice); - -DECLARE_SOA_TABLE(StoredJV0McIds, "AOD1", "JV0MCID", - jv0indices::JMcCollisionId, - jv0indices::JMcParticleId, - jv0mc::MothersIds, - jv0mc::DaughtersIdSlice, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JV0McIds, "JV0MCID", + jv0indices::JMcCollisionId, + jv0indices::JMcParticleId, + jv0mc::MothersIds, + jv0mc::DaughtersIdSlice); } // namespace o2::aod diff --git a/PWGJE/DataModel/JetSubstructure.h b/PWGJE/DataModel/JetSubstructure.h index 8ea838bda5a..9e09948b253 100644 --- a/PWGJE/DataModel/JetSubstructure.h +++ b/PWGJE/DataModel/JetSubstructure.h @@ -17,37 +17,143 @@ #ifndef PWGJE_DATAMODEL_JETSUBSTRUCTURE_H_ #define PWGJE_DATAMODEL_JETSUBSTRUCTURE_H_ +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" // IWYU pragma: keep +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataDQ.h" + +#include + #include +#include #include -#include "Framework/AnalysisDataModel.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGJE/DataModel/Jet.h" namespace o2::aod { namespace jetcollision -{ //! -DECLARE_SOA_COLUMN(PosZ, posZ, float); //! -DECLARE_SOA_COLUMN(Centrality, centrality, float); //! -DECLARE_SOA_COLUMN(EventSel, eventSel, uint8_t); //! +{ //! +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); //! -DECLARE_SOA_COLUMN(PtLeading, ptLeading, std::vector); //! -DECLARE_SOA_COLUMN(PtSubLeading, ptSubLeading, std::vector); //! -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(PairPt, pairPt, std::vector); //! -DECLARE_SOA_COLUMN(PairEnergy, pairEnergy, std::vector); //! -DECLARE_SOA_COLUMN(PairTheta, pairTheta, std::vector); //! +{ //! +DECLARE_SOA_COLUMN(EnergyMother, energyMother, std::vector); //! +DECLARE_SOA_COLUMN(PtLeading, ptLeading, std::vector); //! +DECLARE_SOA_COLUMN(PtSubLeading, ptSubLeading, std::vector); //! +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); //! @@ -55,38 +161,54 @@ 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_, _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, _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::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::PairPt, jetsubstructure::PairEnergy, jetsubstructure::PairTheta, _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::PairPt, jetsubstructure::PairEnergy, jetsubstructure::PairTheta); \ - \ - 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 @@ -108,21 +230,43 @@ DECLARE_SOA_COLUMN(JetNConstituents, jetNConstituents, int); //! 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_, _jet_description_, _cand_type_data_, _cand_description_data_, _cand_type_ewsdata_, _cand_description_ewsdata_, _cand_type_mcd_, _cand_description_mcd_, _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") \ - 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_) \ - 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") - -JETSUBSTRUCTURE_TABLES_DEF(C, "C", CJetCOs, "CJETCO", CEWSJetCOs, "CEWSJETCO", CMCDJetCOs, "CMCDJETCO", CMCPJetCOs, "CMCPJETCO"); -JETSUBSTRUCTURE_TABLES_DEF(D0C, "D0C", HfD0Bases, "HFD0BASE", HfD0Bases, "HFD0BASE", HfD0Bases, "HFD0BASE", HfD0PBases, "HFD0PBASE"); -JETSUBSTRUCTURE_TABLES_DEF(LcC, "LCC", Hf3PBases, "HF3PBASE", Hf3PBases, "HF3PBASE", Hf3PBases, "HF3PBASE", Hf3PPBases, "HF3PPBASE"); -JETSUBSTRUCTURE_TABLES_DEF(BplusC, "BPLUSC", HfD0Bases, "HFD0BASE", HfD0Bases, "HFD0BASE", HfD0Bases, "HFD0BASE", HfD0PBases, "HFD0PBASE"); -JETSUBSTRUCTURE_TABLES_DEF(DielectronC, "DIELC", Dielectrons, "RTDIELECTRON", Dielectrons, "RTDIELECTRON", Dielectrons, "RTDIELECTRON", JDielectronMcs, "JDIELMC"); +#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(DsC, "DSC", DsCharged, dscharged, JTracks, HfDsBases, "HFDSBASE", JTrackDsSubs, HfDsBases, "HFDSBASE", JTracks, HfDsBases, "HFDSBASE", JMcParticles, HfDsPBases, "HFDSPBASE"); +JETSUBSTRUCTURE_TABLES_DEF(DstarC, "DSTC", DstarCharged, dstarcharged, JTracks, HfDstarBases, "HFDSTBASE", JTrackDstarSubs, HfDstarBases, "HFDSTBASE", JTracks, HfDstarBases, "HFDSTBASE", JMcParticles, HfDstarPBases, "HFDSTPBASE"); +JETSUBSTRUCTURE_TABLES_DEF(LcC, "LCC", LcCharged, lccharged, JTracks, HfLcBases, "HFLCBASE", JTrackLcSubs, HfLcBases, "HFLCBASE", JTracks, HfLcBases, "HFLCBASE", JMcParticles, HfLcPBases, "HFLCPBASE"); +JETSUBSTRUCTURE_TABLES_DEF(B0C, "B0C", B0Charged, b0charged, JTracks, HfB0Bases, "HFB0BASE", JTrackB0Subs, HfB0Bases, "HFB0BASE", JTracks, HfB0Bases, "HFB0BASE", JMcParticles, HfB0PBases, "HFB0PBASE"); +JETSUBSTRUCTURE_TABLES_DEF(BplusC, "BPC", BplusCharged, bpluscharged, JTracks, HfBplusBases, "HFBPBASE", JTrackBplusSubs, HfBplusBases, "HFBPBASE", JTracks, HfBplusBases, "HFBPBASE", JMcParticles, HfBplusPBases, "HFBPPBASE"); +JETSUBSTRUCTURE_TABLES_DEF(XicToXiPiPiC, "XICXPPC", XicToXiPiPiCharged, xictoxipipicharged, JTracks, HfXicToXiPiPiBases, "HFXICXPPBASE", JTrackXicToXiPiPiSubs, HfXicToXiPiPiBases, "HFXICXPPBASE", JTracks, HfXicToXiPiPiBases, "HFXICXPPBASE", JMcParticles, HfXicToXiPiPiPBases, "HFXICXPPPBASE"); +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 639049ea81a..0ca981c6e04 100644 --- a/PWGJE/DataModel/JetSubtraction.h +++ b/PWGJE/DataModel/JetSubtraction.h @@ -18,13 +18,14 @@ #ifndef PWGJE_DATAMODEL_JETSUBTRACTION_H_ #define PWGJE_DATAMODEL_JETSUBTRACTION_H_ -#include -#include "Framework/AnalysisDataModel.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGJE/DataModel/JetReducedData.h" -#include "PWGHF/DataModel/DerivedTables.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataDQ.h" + +#include + +#include namespace o2::aod { @@ -38,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 @@ -45,145 +47,610 @@ 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 bkgds +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfDsBases, "_0"); +} // namespace bkgds + +namespace bkgdsmc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfDsPBases, "_0"); +} // namespace bkgdsmc + +namespace bkgdstar +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfDstarBases, "_0"); +} // namespace bkgdstar + +namespace bkgdstarmc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfDstarPBases, "_0"); +} // namespace bkgdstarmc + 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 bkgb0 +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfB0Bases, "_0"); +} // namespace bkgb0 + +namespace bkgb0mc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfB0PBases, "_0"); +} // namespace bkgb0mc + 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 bkgxictoxipipi +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfXicToXiPiPiBases, "_0"); +} // namespace bkgxictoxipipi + +namespace bkgxictoxipipimc +{ +DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, HfXicToXiPiPiPBases, "_0"); +} // namespace bkgxictoxipipimc + namespace bkgdielectron { DECLARE_SOA_INDEX_COLUMN_FULL(Candidate, candidate, int, Dielectrons, "_0"); -// DECLARE_SOA_INDEX_COLUMN(Dielectron, candidate); } // 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>); -DECLARE_SOA_TABLE(BkgDielectronRhos, "AOD", "BkgDIELRho", +DECLARE_SOA_TABLE(BkgDplusMcRhos, "AOD", "BkgDPMcRho", o2::soa::Index<>, - bkgdielectron::CandidateId, bkgrho::Rho, - bkgrho::RhoM); + bkgrho::RhoM, + o2::soa::Marker<5>); -namespace jtracksub -{ +DECLARE_SOA_TABLE(BkgDsRhos, "AOD", "BkgDSRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<6>); + +DECLARE_SOA_TABLE(BkgDsMcRhos, "AOD", "BkgDSMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<7>); + +DECLARE_SOA_TABLE(BkgDstarRhos, "AOD", "BkgDSTRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<8>); + +DECLARE_SOA_TABLE(BkgDstarMcRhos, "AOD", "BkgDSTMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<9>); + +DECLARE_SOA_TABLE(BkgLcRhos, "AOD", "BkgLCRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<10>); + +DECLARE_SOA_TABLE(BkgLcMcRhos, "AOD", "BkgLCMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<11>); + +DECLARE_SOA_TABLE(BkgB0Rhos, "AOD", "BkgB0Rho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<12>); + +DECLARE_SOA_TABLE(BkgB0McRhos, "AOD", "BkgB0McRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<13>); + +DECLARE_SOA_TABLE(BkgBplusRhos, "AOD", "BkgBPRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<14>); + +DECLARE_SOA_TABLE(BkgBplusMcRhos, "AOD", "BkgBPMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<15>); + +DECLARE_SOA_TABLE(BkgXicToXiPiPiRhos, "AOD", "BkgXICXPPRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<16>); + +DECLARE_SOA_TABLE(BkgXicToXiPiPiMcRhos, "AOD", "BkgXICXPPMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<17>); -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(BkgDielectronRhos, "AOD", "BkgDIELRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<18>); + +DECLARE_SOA_TABLE(BkgDielectronMcRhos, "AOD", "BkgDIELMcRho", + o2::soa::Index<>, + bkgrho::Rho, + bkgrho::RhoM, + o2::soa::Marker<19>); 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::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +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::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +using JMcParticleD0Sub = JMcParticleD0Subs::iterator; + +DECLARE_SOA_TABLE(JTrackDplusSubs, "AOD", "JTrackDPSubs", + o2::soa::Index<>, + bkgdplus::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<>, + bkgdplusmc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +using JMcParticleDplusSub = JMcParticleDplusSubs::iterator; + +DECLARE_SOA_TABLE(JTrackDsSubs, "AOD", "JTrackDSSubs", + o2::soa::Index<>, + bkgds::CandidateId, + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); + +using JTrackDsSub = JTrackDsSubs::iterator; + +DECLARE_SOA_TABLE(JMcParticleDsSubs, "AOD", "JMcPartDSSubs", + o2::soa::Index<>, + bkgdsmc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +using JMcParticleDsSub = JMcParticleDsSubs::iterator; + +DECLARE_SOA_TABLE(JTrackDstarSubs, "AOD", "JTrackDSTSubs", + o2::soa::Index<>, + bkgdstar::CandidateId, + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); + +using JTrackDstarSub = JTrackDstarSubs::iterator; + +DECLARE_SOA_TABLE(JMcParticleDstarSubs, "AOD", "JMcPartDSTSubs", + o2::soa::Index<>, + bkgdstarmc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +using JMcParticleDstarSub = JMcParticleDstarSubs::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::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +using JMcParticleLcSub = JMcParticleLcSubs::iterator; + +DECLARE_SOA_TABLE(JTrackB0Subs, "AOD", "JTrackB0Subs", + o2::soa::Index<>, + bkgb0::CandidateId, + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); + +using JTrackB0Sub = JTrackB0Subs::iterator; + +DECLARE_SOA_TABLE(JMcParticleB0Subs, "AOD", "JMcPartB0Subs", + o2::soa::Index<>, + bkgb0mc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +using JMcParticleB0Sub = JMcParticleB0Subs::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::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +using JMcParticleBplusSub = JMcParticleBplusSubs::iterator; + +DECLARE_SOA_TABLE(JTrackXicToXiPiPiSubs, "AOD", "JTrackXICXPPCSubs", + o2::soa::Index<>, + bkgxictoxipipi::CandidateId, + jtrack::Pt, + jtrack::Eta, + jtrack::Phi, + jtrack::TrackSel, + jtrack::Px, + jtrack::Py, + jtrack::Pz, + jtrack::P, + jtrack::Energy); + +using JTrackXicToXiPiPiSub = JTrackXicToXiPiPiSubs::iterator; + +DECLARE_SOA_TABLE(JMcParticleXicToXiPiPiSubs, "AOD", "JMcPartXICXPPCSubs", + o2::soa::Index<>, + bkgxictoxipipimc::CandidateId, + jmcparticle::Pt, + jmcparticle::Eta, + jmcparticle::Phi, + jmcparticle::Y, + jmcparticle::E, + jmcparticle::PdgCode, + jmcparticle::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +using JMcParticleXicToXiPiPiSub = JMcParticleXicToXiPiPiSubs::iterator; + DECLARE_SOA_TABLE(JTrackDielectronSubs, "AOD", "JTrackDIELSubs", o2::soa::Index<>, bkgdielectron::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 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::StatusCode, + jmcparticle::Flags, + jmcparticle::Px, + jmcparticle::Py, + jmcparticle::Pz, + jmcparticle::P, + jmcparticle::Energy, + jmcparticle::ProducedByGenerator, // this will give a nonsensical value and should not be used + jmcparticle::FromBackgroundEvent, // this will give a nonsensical value and should not be used + jmcparticle::GetProcess, // this will give a nonsensical value and should not be used + jmcparticle::GetGenStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::GetHepMCStatusCode, // this will give a nonsensical value and should not be used + jmcparticle::IsPhysicalPrimary); + +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 c5915396d07..9d8f5eceb80 100644 --- a/PWGJE/DataModel/JetTagging.h +++ b/PWGJE/DataModel/JetTagging.h @@ -9,18 +9,27 @@ // 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_ +#include "RecoDecay.h" + +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/DataModel/Jet.h" // IWYU pragma: keep + +#include + +#include + +#include #include -#include -#include "Framework/AnalysisDataModel.h" -#include "PWGJE/DataModel/Jet.h" +#include namespace o2::aod { @@ -38,11 +47,11 @@ DECLARE_SOA_TABLE(JTracksTag, "AOD", "JTracksTag", using JTrackTag = JTracksTag::iterator; -namespace SecondaryVertexParams +namespace secondary_vertex_params { -DECLARE_SOA_COLUMN(XPrimaryVertex, xPVertex, float); -DECLARE_SOA_COLUMN(YPrimaryVertex, yPVertex, float); -DECLARE_SOA_COLUMN(ZPrimaryVertex, zPVertex, float); +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); @@ -52,6 +61,7 @@ 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); }); @@ -65,50 +75,51 @@ DECLARE_SOA_DYNAMIC_COLUMN(DecayLength, decayLength, [](float xVtxP, float yVtxP 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}); }); +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 SecondaryVertexParams - -#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, \ - SecondaryVertexParams::XPrimaryVertex, \ - SecondaryVertexParams::YPrimaryVertex, \ - SecondaryVertexParams::ZPrimaryVertex, \ - SecondaryVertexParams::XSecondaryVertex, \ - SecondaryVertexParams::YSecondaryVertex, \ - SecondaryVertexParams::ZSecondaryVertex, \ - SecondaryVertexParams::Px, \ - SecondaryVertexParams::Py, \ - SecondaryVertexParams::Pz, \ - SecondaryVertexParams::E, \ - SecondaryVertexParams::M, \ - SecondaryVertexParams::Chi2PCA, \ - SecondaryVertexParams::ErrorDecayLength, \ - SecondaryVertexParams::ErrorDecayLengthXY, \ - SecondaryVertexParams::RSecondaryVertex, \ - SecondaryVertexParams::Pt, \ - SecondaryVertexParams::P, \ - SecondaryVertexParams::PVector, \ - SecondaryVertexParams::Eta, \ - SecondaryVertexParams::Phi, \ - SecondaryVertexParams::Y, \ - SecondaryVertexParams::DecayLength, \ - SecondaryVertexParams::DecayLengthXY, \ - SecondaryVertexParams::DecayLengthNormalised, \ - SecondaryVertexParams::DecayLengthXYNormalised, \ - SecondaryVertexParams::CPA, \ - SecondaryVertexParams::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); +} // 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) \ @@ -117,20 +128,37 @@ DECLARE_SOA_DYNAMIC_COLUMN(ImpactParameterXY, impactParameterXY, [](float xVtxP, JETSV_TABLES_DEF(Charged, SecondaryVertex3Prong, "3PRONG"); JETSV_TABLES_DEF(Charged, SecondaryVertex2Prong, "2PRONG"); -// 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") \ +// 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"); diff --git a/PWGJE/DataModel/PhotonChargedTriggerCorrelation.h b/PWGJE/DataModel/PhotonChargedTriggerCorrelation.h new file mode 100644 index 00000000000..8cd65eedcb5 --- /dev/null +++ b/PWGJE/DataModel/PhotonChargedTriggerCorrelation.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. + +/// +/// \brief table definitions for photon-hadron correlation analyses +/// +/// \author Julius Kinner +/// \file PhotonChargedTriggerCorrelation.h + +#ifndef PWGJE_DATAMODEL_PHOTONCHARGEDTRIGGERCORRELATION_H_ +#define PWGJE_DATAMODEL_PHOTONCHARGEDTRIGGERCORRELATION_H_ + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ + +// basic correlation particle columns +namespace corr_particle +{ +DECLARE_SOA_INDEX_COLUMN_FULL(JetCollision, jetCollision, int, JCollisions, ""); +DECLARE_SOA_INDEX_COLUMN_FULL(JetMcCollision, jetMcCollision, int, JMcCollisions, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +} // namespace corr_particle + +// reco + +// collision extension +namespace collision_extra_corr +{ +DECLARE_SOA_COLUMN(SelEv, selEv, bool); +DECLARE_SOA_COLUMN(TrigEv, trigEv, bool); +DECLARE_SOA_COLUMN(NGlobalTracks, nGlobalTracks, int); +} // namespace collision_extra_corr +DECLARE_SOA_TABLE(CollisionsExtraCorr, "AOD", "COLLISIONSEXTRACORR", + collision_extra_corr::SelEv, collision_extra_corr::TrigEv, collision_extra_corr::NGlobalTracks); + +// trigger +namespace trigger +{ +DECLARE_SOA_INDEX_COLUMN_FULL(JetTrack, jetTrack, int, JetTracks, ""); +} // namespace trigger +DECLARE_SOA_TABLE(Triggers, "AOD", "TRIGGERS", + o2::soa::Index<>, corr_particle::JetCollisionId, trigger::JetTrackId, + corr_particle::Pt, corr_particle::Phi, corr_particle::Eta); +using Trigger = Triggers::iterator; + +// hadrons (global tracks) +namespace hadron +{ +DECLARE_SOA_INDEX_COLUMN_FULL(JetTrack, jetTrack, int, JetTracks, ""); +} // namespace hadron +DECLARE_SOA_TABLE(Hadrons, "AOD", "HADRONS", + o2::soa::Index<>, corr_particle::JetCollisionId, hadron::JetTrackId, + corr_particle::Pt, corr_particle::Phi, corr_particle::Eta); +using Hadron = Hadrons::iterator; + +// pipm +namespace pipm +{ +DECLARE_SOA_INDEX_COLUMN_FULL(JetTrack, jetTrack, int, JetTracks, ""); +} // namespace pipm +DECLARE_SOA_TABLE(Pipms, "AOD", "PIPMS", + o2::soa::Index<>, corr_particle::JetCollisionId, pipm::JetTrackId, + corr_particle::Pt, corr_particle::Phi, corr_particle::Eta); +using Pipm = Pipms::iterator; + +// photonPCM +namespace photon_pcm +{ +DECLARE_SOA_INDEX_COLUMN_FULL(V0PhotonKF, v0PhotonKF, int, V0PhotonsKF, ""); +DECLARE_SOA_COLUMN(PosTrackId, posTrackId, int); +DECLARE_SOA_COLUMN(NegTrackId, negTrackId, int); +} // namespace photon_pcm +DECLARE_SOA_TABLE(PhotonPCMs, "AOD", "PHOTONPCMS", + o2::soa::Index<>, corr_particle::JetCollisionId, photon_pcm::V0PhotonKFId, + photon_pcm::PosTrackId, photon_pcm::NegTrackId, + corr_particle::Pt, corr_particle::Phi, corr_particle::Eta); +using PhotonPCM = PhotonPCMs::iterator; + +// photonPCM pairs (pi0) +namespace photon_pcm_pair +{ +DECLARE_SOA_INDEX_COLUMN_FULL(V0PhotonKF1, v0PhotonKF1, int, V0PhotonsKF, "_1"); +DECLARE_SOA_INDEX_COLUMN_FULL(V0PhotonKF2, v0PhotonKF2, int, V0PhotonsKF, "_2"); +DECLARE_SOA_COLUMN(PosTrack1Id, posTrack1Id, int); +DECLARE_SOA_COLUMN(NegTrack1Id, negTrack1Id, int); +DECLARE_SOA_COLUMN(PosTrack2Id, posTrack2Id, int); +DECLARE_SOA_COLUMN(NegTrack2Id, negTrack2Id, int); +DECLARE_SOA_COLUMN(Mgg, mgg, float); +} // namespace photon_pcm_pair +DECLARE_SOA_TABLE(PhotonPCMPairs, "AOD", "PHOTONPCMPAIRS", + o2::soa::Index<>, corr_particle::JetCollisionId, photon_pcm_pair::V0PhotonKF1Id, photon_pcm_pair::V0PhotonKF2Id, + photon_pcm_pair::PosTrack1Id, photon_pcm_pair::NegTrack1Id, photon_pcm_pair::PosTrack2Id, photon_pcm_pair::NegTrack2Id, + corr_particle::Pt, corr_particle::Phi, corr_particle::Eta, photon_pcm_pair::Mgg); +using PhotonPCMPair = PhotonPCMPairs::iterator; + +// mc + +// mcCollision extension +namespace mc_collision_extra_corr +{ +DECLARE_SOA_COLUMN(TrigEv, trigEv, bool); +DECLARE_SOA_COLUMN(NChargedInEtaRange, nChargedInEtaRange, int); +} // namespace mc_collision_extra_corr +DECLARE_SOA_TABLE(McCollisionsExtraCorr, "AOD", "MCCOLLISIONSEXTRACORR", + mc_collision_extra_corr::TrigEv, mc_collision_extra_corr::NChargedInEtaRange); + +// trigger +namespace trigger_particle +{ +DECLARE_SOA_INDEX_COLUMN_FULL(JetMcParticle, jetMcParticle, int, JetParticles, ""); +} // namespace trigger_particle +DECLARE_SOA_TABLE(TriggerParticles, "AOD", "TRIGGERPARTICLES", + o2::soa::Index<>, corr_particle::JetMcCollisionId, trigger_particle::JetMcParticleId, + corr_particle::Pt, corr_particle::Phi, corr_particle::Eta); +using TriggerParticle = TriggerParticles::iterator; +} // namespace o2::aod + +#endif // PWGJE_DATAMODEL_PHOTONCHARGEDTRIGGERCORRELATION_H_ diff --git a/PWGJE/DataModel/TrackJetQa.h b/PWGJE/DataModel/TrackJetQa.h index 913f43c29b0..2ad30d88a51 100644 --- a/PWGJE/DataModel/TrackJetQa.h +++ b/PWGJE/DataModel/TrackJetQa.h @@ -19,18 +19,12 @@ #ifndef PWGJE_DATAMODEL_TRACKJETQA_H_ #define PWGJE_DATAMODEL_TRACKJETQA_H_ -// O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/AnalysisDataModel.h" -#include "PWGJE/DataModel/Jet.h" -#include "Framework/StaticFor.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" + +#include +#include + +#include // 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 4c63447cf36..396fe93a838 100644 --- a/PWGJE/JetFinders/CMakeLists.txt +++ b/PWGJE/JetFinders/CMakeLists.txt @@ -14,108 +14,198 @@ 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-ds-data-charged + SOURCES jetFinderDsDataCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-ds-mcd-charged + SOURCES jetFinderDsMCDCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-ds-mcp-charged + SOURCES jetFinderDsMCPCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dstar-data-charged + SOURCES jetFinderDstarDataCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dstar-mcd-charged + SOURCES jetFinderDstarMCDCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-dstar-mcp-charged + SOURCES jetFinderDstarMCPCharged.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-b0-data-charged + SOURCES jetFinderB0DataCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-b0-mcd-charged + SOURCES jetFinderB0MCDCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-b0-mcp-charged + SOURCES jetFinderB0MCPCharged.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-xictoxipipi-data-charged + SOURCES jetFinderXicToXiPiPiDataCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-xictoxipipi-mcd-charged + SOURCES jetFinderXicToXiPiPiMCDCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-finder-xictoxipipi-mcp-charged + SOURCES jetFinderXicToXiPiPiMCPCharged.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 + 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 + 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 + 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 + 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 + 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 + SOURCES jetFinderDielectronMCPCharged.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) diff --git a/PWGJE/JetFinders/Duplicates/CMakeLists.txt b/PWGJE/JetFinders/Duplicates/CMakeLists.txt index a884489b29c..4270de9f221 100644 --- a/PWGJE/JetFinders/Duplicates/CMakeLists.txt +++ b/PWGJE/JetFinders/Duplicates/CMakeLists.txt @@ -13,17 +13,17 @@ if(FastJet_FOUND) o2physics_add_dpl_workflow(jet-finder-data-charged-1 - SOURCES jetfinderdatacharged1.cxx + 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 + 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 + SOURCES jetFinderMCPCharged1.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport COMPONENT_NAME Analysis) diff --git a/PWGJE/JetFinders/Duplicates/jetfinderdatacharged1.cxx b/PWGJE/JetFinders/Duplicates/jetFinderDataCharged1.cxx similarity index 82% rename from PWGJE/JetFinders/Duplicates/jetfinderdatacharged1.cxx rename to PWGJE/JetFinders/Duplicates/jetFinderDataCharged1.cxx index d102d57c675..ac0363bf901 100644 --- a/PWGJE/JetFinders/Duplicates/jetfinderdatacharged1.cxx +++ b/PWGJE/JetFinders/Duplicates/jetFinderDataCharged1.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderDataCharged1 = JetFinderTask; diff --git a/PWGJE/JetFinders/Duplicates/jetfindermcdcharged1.cxx b/PWGJE/JetFinders/Duplicates/jetFinderMCDCharged1.cxx similarity index 83% rename from PWGJE/JetFinders/Duplicates/jetfindermcdcharged1.cxx rename to PWGJE/JetFinders/Duplicates/jetFinderMCDCharged1.cxx index 36f9412aad2..49f2ce1d957 100644 --- a/PWGJE/JetFinders/Duplicates/jetfindermcdcharged1.cxx +++ b/PWGJE/JetFinders/Duplicates/jetFinderMCDCharged1.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderMCDetectorLevelCharged1 = JetFinderTask; diff --git a/PWGJE/JetFinders/Duplicates/jetfindermcpcharged1.cxx b/PWGJE/JetFinders/Duplicates/jetFinderMCPCharged1.cxx similarity index 83% rename from PWGJE/JetFinders/Duplicates/jetfindermcpcharged1.cxx rename to PWGJE/JetFinders/Duplicates/jetFinderMCPCharged1.cxx index ff1d2a10e2b..1ae7eed6100 100644 --- a/PWGJE/JetFinders/Duplicates/jetfindermcpcharged1.cxx +++ b/PWGJE/JetFinders/Duplicates/jetFinderMCPCharged1.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderMCParticleLevelCharged1 = JetFinderTask; diff --git a/PWGJE/JetFinders/jetFinder.cxx b/PWGJE/JetFinders/jetFinder.cxx new file mode 100644 index 00000000000..5255976feb3 --- /dev/null +++ b/PWGJE/JetFinders/jetFinder.cxx @@ -0,0 +1,273 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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/JetFinder.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/EMCALClusterDefinition.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export + +#include +#include + +#include +#include + +#include +#include +#include + +using namespace o2; +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 applyTrackingEfficiency{"applyTrackingEfficiency", {false}, "configurable to decide whether to apply artificial tracking efficiency (discarding tracks) in jet finding"}; + Configurable> trackingEfficiencyPtBinning{"trackingEfficiencyPtBinning", {0., 10, 999.}, "pt binning of tracking efficiency array if applyTrackingEfficiency is true"}; + Configurable> trackingEfficiency{"trackingEfficiency", {1.0, 1.0}, "tracking efficiency array applied to jet finding if applyTrackingEfficiency is true"}; + 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); + } + 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::kTHnD, {{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::kTHnD, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + registry.add("hJetMCP", "sparse for mcp jets", {HistType::kTHnD, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + registry.add("hJetEWSMCP", "sparse for mcp event-wise subtracted jets", {HistType::kTHnD, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + } + + if (applyTrackingEfficiency) { + if (trackingEfficiencyPtBinning->size() < 2) { + LOGP(fatal, "jetFinder workflow: trackingEfficiencyPtBinning configurable should have at least two bin edges"); + } + if (trackingEfficiency->size() + 1 != trackingEfficiencyPtBinning->size()) { + LOGP(fatal, "jetFinder workflow: trackingEfficiency configurable should have exactly one less entry than the number of bin edges set in trackingEfficiencyPtBinning configurable"); + } + } + } + + aod::EMCALClusterDefinition clusterDefinition = aod::emcalcluster::getClusterDefinitionFromString(clusterDefinitionS.value); + Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < 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, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning); + 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, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning); + 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, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning); + 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, jetEWSPtMin, jetEWSPtMax, jetRadius, jetAreaFractionMin, collision, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, fillTHnSparse ? registry.get(HIST("hJetEWSMCP")) : 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/jetFinderB0DataCharged.cxx b/PWGJE/JetFinders/jetFinderB0DataCharged.cxx new file mode 100644 index 00000000000..9288465c677 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderB0DataCharged.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. + +// jet finder B0 data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderB0DataCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsData", true}}}, + TaskName{"jet-finder-b0-data-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderB0MCDCharged.cxx b/PWGJE/JetFinders/jetFinderB0MCDCharged.cxx new file mode 100644 index 00000000000..46de301e549 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderB0MCDCharged.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. + +// jet finder B0 mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderB0MCDetectorLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCD", true}}}, + TaskName{"jet-finder-b0-mcd-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderB0MCPCharged.cxx b/PWGJE/JetFinders/jetFinderB0MCPCharged.cxx new file mode 100644 index 00000000000..2966c817cef --- /dev/null +++ b/PWGJE/JetFinders/jetFinderB0MCPCharged.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. + +// jet finder B0 mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderB0MCParticleLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCP", true}}}, + TaskName{"jet-finder-b0-mcp-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderBplusDataCharged.cxx b/PWGJE/JetFinders/jetFinderBplusDataCharged.cxx new file mode 100644 index 00000000000..087fbc6b37e --- /dev/null +++ b/PWGJE/JetFinders/jetFinderBplusDataCharged.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. + +// jet finder B+ data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +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..9dba69eba51 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderBplusMCDCharged.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. + +// jet finder B+ mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +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..639b02bfe2e --- /dev/null +++ b/PWGJE/JetFinders/jetFinderBplusMCPCharged.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. + +// jet finder B+ mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +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 66% rename from PWGJE/JetFinders/jetfinderD0datacharged.cxx rename to PWGJE/JetFinders/jetFinderD0DataCharged.cxx index 7bdd6e87d9d..70e00c246d4 100644 --- a/PWGJE/JetFinders/jetfinderD0datacharged.cxx +++ b/PWGJE/JetFinders/jetFinderD0DataCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderD0DataCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderD0DataCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderD0mcdcharged.cxx b/PWGJE/JetFinders/jetFinderD0MCDCharged.cxx similarity index 64% rename from PWGJE/JetFinders/jetfinderD0mcdcharged.cxx rename to PWGJE/JetFinders/jetFinderD0MCDCharged.cxx index 1471e00ffa3..62c740a7152 100644 --- a/PWGJE/JetFinders/jetfinderD0mcdcharged.cxx +++ b/PWGJE/JetFinders/jetFinderD0MCDCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderD0MCDetectorLevelCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderD0MCDetectorLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderD0mcpcharged.cxx b/PWGJE/JetFinders/jetFinderD0MCPCharged.cxx similarity index 64% rename from PWGJE/JetFinders/jetfinderD0mcpcharged.cxx rename to PWGJE/JetFinders/jetFinderD0MCPCharged.cxx index 27764256e04..34bee4644ce 100644 --- a/PWGJE/JetFinders/jetfinderD0mcpcharged.cxx +++ b/PWGJE/JetFinders/jetFinderD0MCPCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderD0MCParticleLevelCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderD0MCParticleLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderdatacharged.cxx b/PWGJE/JetFinders/jetFinderDataCharged.cxx similarity index 82% rename from PWGJE/JetFinders/jetfinderdatacharged.cxx rename to PWGJE/JetFinders/jetFinderDataCharged.cxx index df740ad2dba..016d83611bb 100644 --- a/PWGJE/JetFinders/jetfinderdatacharged.cxx +++ b/PWGJE/JetFinders/jetFinderDataCharged.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderDataCharged = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfinderdatafull.cxx b/PWGJE/JetFinders/jetFinderDataFull.cxx similarity index 81% rename from PWGJE/JetFinders/jetfinderdatafull.cxx rename to PWGJE/JetFinders/jetFinderDataFull.cxx index a75896212be..acf33725099 100644 --- a/PWGJE/JetFinders/jetfinderdatafull.cxx +++ b/PWGJE/JetFinders/jetFinderDataFull.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderDataFull = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfinderdataneutral.cxx b/PWGJE/JetFinders/jetFinderDataNeutral.cxx similarity index 82% rename from PWGJE/JetFinders/jetfinderdataneutral.cxx rename to PWGJE/JetFinders/jetFinderDataNeutral.cxx index a325de11bbd..afb223deb74 100644 --- a/PWGJE/JetFinders/jetfinderdataneutral.cxx +++ b/PWGJE/JetFinders/jetFinderDataNeutral.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderDataNeutral = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfinderDielectrondatacharged.cxx b/PWGJE/JetFinders/jetFinderDielectronDataCharged.cxx similarity index 63% rename from PWGJE/JetFinders/jetfinderDielectrondatacharged.cxx rename to PWGJE/JetFinders/jetFinderDielectronDataCharged.cxx index 2e4e4070875..7f4657d1127 100644 --- a/PWGJE/JetFinders/jetfinderDielectrondatacharged.cxx +++ b/PWGJE/JetFinders/jetFinderDielectronDataCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderDielectronDataCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDielectronDataCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderDielectronmcdcharged.cxx b/PWGJE/JetFinders/jetFinderDielectronMCDCharged.cxx similarity index 65% rename from PWGJE/JetFinders/jetfinderDielectronmcdcharged.cxx rename to PWGJE/JetFinders/jetFinderDielectronMCDCharged.cxx index 69cca64919b..1d14666ca10 100644 --- a/PWGJE/JetFinders/jetfinderDielectronmcdcharged.cxx +++ b/PWGJE/JetFinders/jetFinderDielectronMCDCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderDielectronMCDetectorLevelCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDielectronMCDetectorLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderDielectronmcpcharged.cxx b/PWGJE/JetFinders/jetFinderDielectronMCPCharged.cxx similarity index 65% rename from PWGJE/JetFinders/jetfinderDielectronmcpcharged.cxx rename to PWGJE/JetFinders/jetFinderDielectronMCPCharged.cxx index 7a5da12fd87..b0be942e08e 100644 --- a/PWGJE/JetFinders/jetfinderDielectronmcpcharged.cxx +++ b/PWGJE/JetFinders/jetFinderDielectronMCPCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderDielectronMCParticleLevelCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDielectronMCParticleLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetFinderDplusDataCharged.cxx b/PWGJE/JetFinders/jetFinderDplusDataCharged.cxx new file mode 100644 index 00000000000..c684fbc2e8c --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDplusDataCharged.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. + +// jet finder D+ data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +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..ebdbe27c015 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDplusMCDCharged.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. + +// jet finder D+ mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +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..da79b1c2c0e --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDplusMCPCharged.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. + +// jet finder D+ mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +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/jetFinderDsDataCharged.cxx b/PWGJE/JetFinders/jetFinderDsDataCharged.cxx new file mode 100644 index 00000000000..a822389b6d4 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDsDataCharged.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. + +// jet finder Ds data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDsDataCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsData", true}}}, + TaskName{"jet-finder-ds-data-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDsMCDCharged.cxx b/PWGJE/JetFinders/jetFinderDsMCDCharged.cxx new file mode 100644 index 00000000000..004a732f9a2 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDsMCDCharged.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. + +// jet finder Ds mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDsMCDetectorLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCD", true}}}, + TaskName{"jet-finder-ds-mcd-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDsMCPCharged.cxx b/PWGJE/JetFinders/jetFinderDsMCPCharged.cxx new file mode 100644 index 00000000000..5c9b54543b2 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDsMCPCharged.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. + +// jet finder Ds mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDsMCParticleLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCP", true}}}, + TaskName{"jet-finder-ds-mcp-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDstarDataCharged.cxx b/PWGJE/JetFinders/jetFinderDstarDataCharged.cxx new file mode 100644 index 00000000000..0a1b6d104b3 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDstarDataCharged.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. + +// jet finder D* data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDstarDataCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsData", true}}}, + TaskName{"jet-finder-dstar-data-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDstarMCDCharged.cxx b/PWGJE/JetFinders/jetFinderDstarMCDCharged.cxx new file mode 100644 index 00000000000..42e9c2fb370 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDstarMCDCharged.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. + +// jet finder D+ mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDstarMCDetectorLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCD", true}}}, + TaskName{"jet-finder-dstar-mcd-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderDstarMCPCharged.cxx b/PWGJE/JetFinders/jetFinderDstarMCPCharged.cxx new file mode 100644 index 00000000000..36ce473fe3c --- /dev/null +++ b/PWGJE/JetFinders/jetFinderDstarMCPCharged.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. + +// jet finder D* mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderDstarMCParticleLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCP", true}}}, + TaskName{"jet-finder-dstar-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 3e685171fb8..9e8ad7eb1e9 100644 --- a/PWGJE/JetFinders/jetfinderhf.cxx +++ b/PWGJE/JetFinders/jetFinderHF.cxx @@ -14,36 +14,39 @@ /// \author Nima Zardoshti /// \author Jochen Klein -#include "CommonConstants/PhysicsConstants.h" - +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" #include "PWGJE/Core/JetFindingUtilities.h" -#include "Common/Core/RecoDecay.h" +#include "PWGJE/DataModel/EMCALClusterDefinition.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export + +#include +#include + +#include +#include + +#include +#include using namespace o2; -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; @@ -56,6 +59,10 @@ struct JetFinderHFTask { 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"}; @@ -64,9 +71,10 @@ 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 applyTrackingEfficiency{"applyTrackingEfficiency", {false}, "configurable to decide whether to apply artificial tracking efficiency (discarding tracks) in jet finding"}; + Configurable> trackingEfficiencyPtBinning{"trackingEfficiencyPtBinning", {0., 10, 999.}, "pt binning of tracking efficiency array if applyTrackingEfficiency is true"}; + Configurable> trackingEfficiency{"trackingEfficiency", {1.0, 1.0}, "tracking efficiency array applied to jet finding if applyTrackingEfficiency is true"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; // cluster level configurables @@ -102,22 +110,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; @@ -133,6 +146,10 @@ 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) { @@ -140,7 +157,6 @@ struct JetFinderHFTask { } 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; @@ -149,28 +165,51 @@ struct JetFinderHFTask { 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}}}); + registry.add("hJet", "sparse for data or mcd jets", {HistType::kTHnD, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + registry.add("hJetMCP", "sparse for mcp jets", {HistType::kTHnD, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + + if (applyTrackingEfficiency) { + if (trackingEfficiencyPtBinning->size() < 2) { + LOGP(fatal, "jetFinderHF workflow: trackingEfficiencyPtBinning configurable should have at least two bin edges"); + } + if (trackingEfficiency->size() + 1 != trackingEfficiencyPtBinning->size()) { + LOGP(fatal, "jetFinderHF workflow: trackingEfficiency configurable should have exactly one less entry than the number of bin edges set in trackingEfficiencyPtBinning configurable"); + } + } } 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::centFT0M >= centralityMin && aod::jcollision::centFT0M < 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> perDsCandidate = aod::bkgds::candidateId; + PresliceOptional> perDsMcCandidate = aod::bkgdsmc::candidateId; + PresliceOptional> perDstarCandidate = aod::bkgdstar::candidateId; + PresliceOptional> perDstarMcCandidate = aod::bkgdstarmc::candidateId; PresliceOptional> perLcCandidate = aod::bkglc::candidateId; + PresliceOptional> perLcMcCandidate = aod::bkglcmc::candidateId; + PresliceOptional> perB0Candidate = aod::bkgb0::candidateId; + PresliceOptional> perB0McCandidate = aod::bkgb0mc::candidateId; PresliceOptional> perBplusCandidate = aod::bkgbplus::candidateId; + PresliceOptional> perBplusMcCandidate = aod::bkgbplusmc::candidateId; + PresliceOptional> perXicToXiPiPiCandidate = aod::bkgxictoxipipi::candidateId; + PresliceOptional> perXicToXiPiPiMcCandidate = aod::bkgxictoxipipimc::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(); @@ -187,16 +226,16 @@ struct JetFinderHFTask { } } if constexpr (isEvtWiseSub) { - jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, trackingEfficiency); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning); } else { - jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, trackingEfficiency, std::optional{candidate}); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning, &candidate); } 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 - void analyseMCP(T const& collision, U const& particles, V const& candidate, int jetTypeParticleLevel, float minJetPt, float maxJetPt) + template + void analyseMCP(T const& collision, U const& particles, V const& candidate, M& jetsTableInput, N& constituentsTableInput, int jetTypeParticleLevel, float minJetPt, float maxJetPt) { 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; @@ -206,16 +245,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, registry.get(HIST("hJetMCP")), fillTHnSparse, true); + if constexpr (isEvtWiseSub) { + jetfindingutilities::analyseParticles(inputParticles, particleSelection, jetTypeParticleLevel, particles, pdgDatabase, &candidate); + } else { + jetfindingutilities::analyseParticles(inputParticles, particleSelection, jetTypeParticleLevel, particles, pdgDatabase, &candidate); + } + jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTableInput, constituentsTableInput, 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); @@ -223,15 +266,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, jetcandidateutilities::slicedPerCandidate(tracks, candidate, perD0Candidate, perLcCandidate, perBplusCandidate, perDielectronCandidate), candidate, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, tracks, jetEWSPtMin, jetEWSPtMax); + analyseCharged(collision, jetcandidateutilities::slicedPerCandidate(tracks, candidate, perD0Candidate, perDplusCandidate, perDsCandidate, perDstarCandidate, perLcCandidate, perB0Candidate, perBplusCandidate, perXicToXiPiPiCandidate, 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); @@ -239,21 +282,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, jetcandidateutilities::slicedPerCandidate(tracks, candidate, perD0Candidate, perLcCandidate, perBplusCandidate, perDielectronCandidate), candidate, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, tracks, jetEWSPtMin, jetEWSPtMax); + analyseCharged(collision, jetcandidateutilities::slicedPerCandidate(tracks, candidate, perD0Candidate, perDplusCandidate, perDsCandidate, perDstarCandidate, perLcCandidate, perB0Candidate, perBplusCandidate, perXicToXiPiPiCandidate, 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, jetsTable, constituentsTable, 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, perDsMcCandidate, perDstarMcCandidate, perLcMcCandidate, perB0McCandidate, perBplusMcCandidate, perXicToXiPiPiMcCandidate, perDielectronMcCandidate), candidate, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, 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 66% rename from PWGJE/JetFinders/jetfinderLcdatacharged.cxx rename to PWGJE/JetFinders/jetFinderLcDataCharged.cxx index 44af0addc98..37af66ca1b4 100644 --- a/PWGJE/JetFinders/jetfinderLcdatacharged.cxx +++ b/PWGJE/JetFinders/jetFinderLcDataCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderLcDataCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderLcDataCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderLcmcdcharged.cxx b/PWGJE/JetFinders/jetFinderLcMCDCharged.cxx similarity index 64% rename from PWGJE/JetFinders/jetfinderLcmcdcharged.cxx rename to PWGJE/JetFinders/jetFinderLcMCDCharged.cxx index fa5e0aa2d86..9172f395fb8 100644 --- a/PWGJE/JetFinders/jetfinderLcmcdcharged.cxx +++ b/PWGJE/JetFinders/jetFinderLcMCDCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderLcMCDetectorLevelCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderLcMCDetectorLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderLcmcpcharged.cxx b/PWGJE/JetFinders/jetFinderLcMCPCharged.cxx similarity index 64% rename from PWGJE/JetFinders/jetfinderLcmcpcharged.cxx rename to PWGJE/JetFinders/jetFinderLcMCPCharged.cxx index 4c018ce1cfe..e9a1fd14346 100644 --- a/PWGJE/JetFinders/jetfinderLcmcpcharged.cxx +++ b/PWGJE/JetFinders/jetFinderLcMCPCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderhf.cxx" +#include "PWGJE/JetFinders/jetFinderHF.cxx" -using JetFinderLcMCParticleLevelCharged = JetFinderHFTask; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderLcMCParticleLevelCharged = JetFinderHFTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfindermcdcharged.cxx b/PWGJE/JetFinders/jetFinderMCDCharged.cxx similarity index 83% rename from PWGJE/JetFinders/jetfindermcdcharged.cxx rename to PWGJE/JetFinders/jetFinderMCDCharged.cxx index 6f248edcaf8..198d1b87d98 100644 --- a/PWGJE/JetFinders/jetfindermcdcharged.cxx +++ b/PWGJE/JetFinders/jetFinderMCDCharged.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderMCDetectorLevelCharged = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcdfull.cxx b/PWGJE/JetFinders/jetFinderMCDFull.cxx similarity index 83% rename from PWGJE/JetFinders/jetfindermcdfull.cxx rename to PWGJE/JetFinders/jetFinderMCDFull.cxx index 29464e814c9..ce5b8ec42ec 100644 --- a/PWGJE/JetFinders/jetfindermcdfull.cxx +++ b/PWGJE/JetFinders/jetFinderMCDFull.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderMCDetectorLevelFull = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcdneutral.cxx b/PWGJE/JetFinders/jetFinderMCDNeutral.cxx similarity index 83% rename from PWGJE/JetFinders/jetfindermcdneutral.cxx rename to PWGJE/JetFinders/jetFinderMCDNeutral.cxx index f58cc09492d..e532c3d528b 100644 --- a/PWGJE/JetFinders/jetfindermcdneutral.cxx +++ b/PWGJE/JetFinders/jetFinderMCDNeutral.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderMCDetectorLevelNeutral = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcpcharged.cxx b/PWGJE/JetFinders/jetFinderMCPCharged.cxx similarity index 83% rename from PWGJE/JetFinders/jetfindermcpcharged.cxx rename to PWGJE/JetFinders/jetFinderMCPCharged.cxx index 41981a193f1..98538de9708 100644 --- a/PWGJE/JetFinders/jetfindermcpcharged.cxx +++ b/PWGJE/JetFinders/jetFinderMCPCharged.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderMCParticleLevelCharged = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcpfull.cxx b/PWGJE/JetFinders/jetFinderMCPFull.cxx similarity index 83% rename from PWGJE/JetFinders/jetfindermcpfull.cxx rename to PWGJE/JetFinders/jetFinderMCPFull.cxx index cd0bda48730..217a1cfe928 100644 --- a/PWGJE/JetFinders/jetfindermcpfull.cxx +++ b/PWGJE/JetFinders/jetFinderMCPFull.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderMCParticleLevelFull = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfindermcpneutral.cxx b/PWGJE/JetFinders/jetFinderMCPNeutral.cxx similarity index 83% rename from PWGJE/JetFinders/jetfindermcpneutral.cxx rename to PWGJE/JetFinders/jetFinderMCPNeutral.cxx index e4f8c00683f..b2240dbe6e4 100644 --- a/PWGJE/JetFinders/jetfindermcpneutral.cxx +++ b/PWGJE/JetFinders/jetFinderMCPNeutral.cxx @@ -13,7 +13,16 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinder.cxx" +#include "PWGJE/JetFinders/jetFinder.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include using JetFinderMCParticleLevelNeutral = JetFinderTask; diff --git a/PWGJE/JetFinders/jetfinderv0.cxx b/PWGJE/JetFinders/jetFinderV0.cxx similarity index 60% rename from PWGJE/JetFinders/jetfinderv0.cxx rename to PWGJE/JetFinders/jetFinderV0.cxx index 17dc308ddb1..75bb1071688 100644 --- a/PWGJE/JetFinders/jetfinderv0.cxx +++ b/PWGJE/JetFinders/jetFinderV0.cxx @@ -13,19 +13,35 @@ // /// \author Nima Zardoshti -#include "CommonConstants/PhysicsConstants.h" - +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" #include "PWGJE/Core/JetFindingUtilities.h" -#include "Common/Core/RecoDecay.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export + +#include +#include + +#include +#include + +#include +#include 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 { @@ -38,6 +54,10 @@ struct JetFinderV0Task { 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"}; @@ -46,9 +66,10 @@ struct JetFinderV0Task { 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 applyTrackingEfficiency{"applyTrackingEfficiency", {false}, "configurable to decide whether to apply artificial tracking efficiency (discarding tracks) in jet finding"}; + Configurable> trackingEfficiencyPtBinning{"trackingEfficiencyPtBinning", {0., 10, 999.}, "pt binning of tracking efficiency array if applyTrackingEfficiency is true"}; + Configurable> trackingEfficiency{"trackingEfficiency", {1.0, 1.0}, "tracking efficiency array applied to jet finding if applyTrackingEfficiency is true"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; // V0 candidate level configurables @@ -69,24 +90,31 @@ struct JetFinderV0Task { 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"}; + Configurable useV0SignalFlags{"useV0SignalFlags", true, "use V0 signal flags table"}; + Configurable saveJetsWithCandidatesOnly{"saveJetsWithCandidatesOnly", true, "only save jets if they contain a V0"}; Service pdgDatabase; int trackSelection = -1; - int eventSelection = -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)); - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); particleSelection = static_cast(particleSelections); jetFinder.etaMin = trackEtaMin; @@ -102,6 +130,10 @@ struct JetFinderV0Task { 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; @@ -116,7 +148,6 @@ struct JetFinderV0Task { } 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; @@ -125,25 +156,36 @@ struct JetFinderV0Task { 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}}}); + registry.add("hJet", "sparse for data or mcd jets", {HistType::kTHnD, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + registry.add("hJetMCP", "sparse for mcp jets", {HistType::kTHnD, {{jetRadiiBins, ""}, {jetPtBinNumber, jetPtMinDouble, jetPtMaxDouble}, {40, -1.0, 1.0}, {18, 0.0, 7.0}}}); + + if (applyTrackingEfficiency) { + if (trackingEfficiencyPtBinning->size() < 2) { + LOGP(fatal, "jetFinderV0 workflow: trackingEfficiencyPtBinning configurable should have at least two bin edges"); + } + if (trackingEfficiency->size() + 1 != trackingEfficiencyPtBinning->size()) { + LOGP(fatal, "jetFinderV0 workflow: trackingEfficiency configurable should have exactly one less entry than the number of bin edges set in trackingEfficiencyPtBinning configurable"); + } + } } - 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 partCuts = (aod::jmcparticle::pt >= trackPtMin && aod::jmcparticle::pt < trackPtMax); - // Filter candidateCuts = (aod::hfcand::pt >= candPtMin && aod::hfcand::pt < candPtMax && aod::hfcand::y >= candYMin && aod::hfcand::y < candYMax); + Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < 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); // 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, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { return; } inputParticles.clear(); - if (!jetfindingutilities::analyseV0s(inputParticles, candidates, candPtMin, candPtMax, candYMin, candYMax, candIndex)) { - return; + if (!jetfindingutilities::analyseV0s(inputParticles, candidates, candPtMin, candPtMax, candYMin, candYMax, candIndex, useV0SignalFlags)) { + if (saveJetsWithCandidatesOnly) { + return; + } } /* @@ -153,9 +195,9 @@ struct JetFinderV0Task { } } */ - jetfindingutilities::analyseTracksMultipleCandidates(inputParticles, tracks, trackSelection, trackingEfficiency, candidates); + jetfindingutilities::analyseTracksMultipleCandidates(inputParticles, tracks, trackSelection, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning, candidates); - jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTableInput, constituentsTableInput, registry.get(HIST("hJet")), fillTHnSparse, true); + jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTableInput, constituentsTableInput, registry.get(HIST("hJet")), fillTHnSparse, saveJetsWithCandidatesOnly); } template @@ -163,32 +205,34 @@ struct JetFinderV0Task { { inputParticles.clear(); - if (!jetfindingutilities::analyseV0s(inputParticles, candidates, candPtMin, candPtMax, candYMin, candYMax, candIndex)) { - return; + if (!jetfindingutilities::analyseV0s(inputParticles, candidates, candPtMin, candPtMax, candYMin, candYMax, candIndex, useV0SignalFlags)) { + if (saveJetsWithCandidatesOnly) { + 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); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, jetTypeParticleLevel, particles, pdgDatabase, &candidates); + jetfindingutilities::findJets(jetFinder, inputParticles, minJetPt, maxJetPt, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, registry.get(HIST("hJetMCP")), fillTHnSparse, saveJetsWithCandidatesOnly); } - void processDummy(JetCollisions const&) + 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) + 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) + 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(JetMcCollision const& collision, - soa::Filtered const& particles, + void processChargedJetsMCP(soa::Filtered::iterator const& collision, + soa::Filtered const& particles, CandidateTableMCP const& candidates) { analyseMCP(collision, particles, candidates, 1, jetPtMin, jetPtMax); diff --git a/PWGJE/JetFinders/jetfinderV0datacharged.cxx b/PWGJE/JetFinders/jetFinderV0DataCharged.cxx similarity index 72% rename from PWGJE/JetFinders/jetfinderV0datacharged.cxx rename to PWGJE/JetFinders/jetFinderV0DataCharged.cxx index 671535d635f..1b239661afd 100644 --- a/PWGJE/JetFinders/jetfinderV0datacharged.cxx +++ b/PWGJE/JetFinders/jetFinderV0DataCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderv0.cxx" +#include "PWGJE/JetFinders/jetFinderV0.cxx" -using JetFinderV0DataCharged = JetFinderV0Task; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderV0DataCharged = JetFinderV0Task; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderV0mcdcharged.cxx b/PWGJE/JetFinders/jetFinderV0MCDCharged.cxx similarity index 70% rename from PWGJE/JetFinders/jetfinderV0mcdcharged.cxx rename to PWGJE/JetFinders/jetFinderV0MCDCharged.cxx index 6c06d061aed..890b3334776 100644 --- a/PWGJE/JetFinders/jetfinderV0mcdcharged.cxx +++ b/PWGJE/JetFinders/jetFinderV0MCDCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderv0.cxx" +#include "PWGJE/JetFinders/jetFinderV0.cxx" -using JetFinderV0MCDetectorLevelCharged = JetFinderV0Task; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderV0MCDetectorLevelCharged = JetFinderV0Task; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetfinderV0mcpcharged.cxx b/PWGJE/JetFinders/jetFinderV0MCPCharged.cxx similarity index 70% rename from PWGJE/JetFinders/jetfinderV0mcpcharged.cxx rename to PWGJE/JetFinders/jetFinderV0MCPCharged.cxx index 53cc6f944f8..3704f8f67b0 100644 --- a/PWGJE/JetFinders/jetfinderV0mcpcharged.cxx +++ b/PWGJE/JetFinders/jetFinderV0MCPCharged.cxx @@ -13,9 +13,18 @@ // /// \author Nima Zardoshti -#include "PWGJE/JetFinders/jetfinderv0.cxx" +#include "PWGJE/JetFinders/jetFinderV0.cxx" -using JetFinderV0MCParticleLevelCharged = JetFinderV0Task; +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderV0MCParticleLevelCharged = JetFinderV0Task; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/JetFinders/jetFinderXicToXiPiPiDataCharged.cxx b/PWGJE/JetFinders/jetFinderXicToXiPiPiDataCharged.cxx new file mode 100644 index 00000000000..3ed339e8a32 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderXicToXiPiPiDataCharged.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. + +// jet finder XicToXiPiPi data charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderXicToXiPiPiDataCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsData", true}}}, + TaskName{"jet-finder-xictoxipipi-data-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderXicToXiPiPiMCDCharged.cxx b/PWGJE/JetFinders/jetFinderXicToXiPiPiMCDCharged.cxx new file mode 100644 index 00000000000..64c35fe78c6 --- /dev/null +++ b/PWGJE/JetFinders/jetFinderXicToXiPiPiMCDCharged.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. + +// jet finder D+ mcd charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderXicToXiPiPiMCDetectorLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCD", true}}}, + TaskName{"jet-finder-xictoxipipi-mcd-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetFinderXicToXiPiPiMCPCharged.cxx b/PWGJE/JetFinders/jetFinderXicToXiPiPiMCPCharged.cxx new file mode 100644 index 00000000000..ca4cc98938f --- /dev/null +++ b/PWGJE/JetFinders/jetFinderXicToXiPiPiMCPCharged.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. + +// jet finder D+ mcp charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/JetFinders/jetFinderHF.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include + +#include + +using JetFinderXicToXiPiPiMCParticleLevelCharged = JetFinderHFTask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{{{"processChargedJetsMCP", true}}}, + TaskName{"jet-finder-xictoxipipi-mcp-charged"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/JetFinders/jetfinder.cxx b/PWGJE/JetFinders/jetfinder.cxx deleted file mode 100644 index b5795c56b86..00000000000 --- a/PWGJE/JetFinders/jetfinder.cxx +++ /dev/null @@ -1,217 +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; - - 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"}; - - // 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 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"}; - Configurable doEMCALEventSelection{"doEMCALEventSelection", true, "apply the selection to the event alias_bit"}; - - // 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"}; - - 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; - } - - 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("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); - 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, trackingEfficiency); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, registry.get(HIST("hJet")), 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, eventSelection)) { - return; - } - inputParticles.clear(); - jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, trackingEfficiency); - jetfindingutilities::findJets(jetFinder, inputParticles, jetEWSPtMin, jetEWSPtMax, jetRadius, jetAreaFractionMin, collision, jetsEvtWiseSubTable, constituentsEvtWiseSubTable, registry.get(HIST("hJetEWS")), 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)) { - return; - } - inputParticles.clear(); - jetfindingutilities::analyseClusters(inputParticles, &clusters); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, registry.get(HIST("hJet")), 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)) { - return; - } - inputParticles.clear(); - jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, trackingEfficiency); - jetfindingutilities::analyseClusters(inputParticles, &clusters); - jetfindingutilities::findJets(jetFinder, inputParticles, jetPtMin, jetPtMax, jetRadius, jetAreaFractionMin, collision, jetsTable, constituentsTable, registry.get(HIST("hJet")), fillTHnSparse); - } - 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, registry.get(HIST("hJetMCP")), fillTHnSparse); - } - 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, registry.get(HIST("hJetMCP")), fillTHnSparse); - } - 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, registry.get(HIST("hJetMCP")), fillTHnSparse); - } - - PROCESS_SWITCH(JetFinderTask, processParticleLevelFullJets, "Particle level full jet finding", false); -}; diff --git a/PWGJE/TableProducer/CMakeLists.txt b/PWGJE/TableProducer/CMakeLists.txt index cc3dfa1135e..60689f07e65 100644 --- a/PWGJE/TableProducer/CMakeLists.txt +++ b/PWGJE/TableProducer/CMakeLists.txt @@ -9,82 +9,68 @@ # 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::AnalysisCCDB O2Physics::EventFilteringUtils 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 - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(jet-deriveddata-producer-dummy-dielectron - SOURCES jetderiveddataproducerdummydielectron.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 +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-matching-mc-sub - SOURCES jetmatchingmcsub.cxx +o2physics_add_dpl_workflow(jet-eventweight-mcd + SOURCES jetEventWeightMCD.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(jet-matching-duplicates - SOURCES jetmatchingduplicates.cxx +o2physics_add_dpl_workflow(jet-eventweight-mcp + SOURCES jetEventWeightMCP.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(jet-eventweight-mcd - SOURCES jeteventweightmcd.cxx +o2physics_add_dpl_workflow(mc-outlier-rejector + SOURCES mcOutlierRejector.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(jet-eventweight-mcp - SOURCES jeteventweightmcp.cxx +o2physics_add_dpl_workflow(jet-track-derived + SOURCES jetTrackDerived.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(jet-track-derived - SOURCES jettrackderived.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 + SOURCES jetTaggerHF.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(estimator-rho @@ -107,10 +93,15 @@ endif() o2physics_add_dpl_workflow(emcal-correction-task SOURCES emcalCorrectionTask.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2::EMCALBase O2::EMCALReconstruction + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase O2::EMCALBase O2::EMCALReconstruction O2::EMCALCalibration O2Physics::PWGJECore COMPONENT_NAME Analysis) 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..a5450dfb05e --- /dev/null +++ b/PWGJE/TableProducer/Matching/CMakeLists.txt @@ -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. + +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-ds-ch + SOURCES jetMatchingMCDsCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-dstar-ch + SOURCES jetMatchingMCDstarCharged.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-b0-ch + SOURCES jetMatchingMCB0Charged.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-xictoxipipi-ch + SOURCES jetMatchingMCXicToXiPiPiCharged.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-ds-ch + SOURCES jetMatchingMCSubDsCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-mc-sub-dstar-ch + SOURCES jetMatchingMCSubDstarCharged.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-b0-ch + SOURCES jetMatchingMCSubB0Charged.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-xictoxipipi-ch + SOURCES jetMatchingMCSubXicToXiPiPiCharged.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-ds-ch + SOURCES jetMatchingSubDsCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-sub-dstar-ch + SOURCES jetMatchingSubDstarCharged.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-b0-ch + SOURCES jetMatchingSubB0Charged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-matching-sub-xictoxipipi-ch + SOURCES jetMatchingSubXicToXiPiPiCharged.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/jetmatchingduplicates.cxx b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx similarity index 57% rename from PWGJE/TableProducer/jetmatchingduplicates.cxx rename to PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx index c56857475a8..9e7d28ef94f 100644 --- a/PWGJE/TableProducer/jetmatchingduplicates.cxx +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx @@ -13,18 +13,17 @@ /// \brief matching duplicate jets /// \author Nima Zardoshti -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGJE/Core/JetMatchingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + #include "Framework/ASoA.h" -#include "Framework/runDataProcessing.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include +#include +#include +#include // IWYU pragma: export -#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" +#include using namespace o2; using namespace o2::framework; @@ -53,12 +52,7 @@ struct JetMatchingDuplicates { { } - void processDummy(JetCollisions const&) - { - } - PROCESS_SWITCH(JetMatchingDuplicates, processDummy, "Dummy process", true); - - void processJets(JetCollisions const& collisions, + void processJets(aod::JetCollisions const& collisions, JetsBase const& jetsBase, JetsTag const& jetsTag, Tracks const& tracks, Candidates const& candidates) { @@ -79,7 +73,7 @@ struct JetMatchingDuplicates { 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, candidates, tracks, tracks, tracks, tracks, doMatchingGeo, doMatchingHf, doMatchingPt, maxMatchingDistance, minPtFraction); + 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) { @@ -89,37 +83,5 @@ struct JetMatchingDuplicates { jetsTagtoBaseMatchingTable(jetsTagtoBaseMatchingGeo[i], jetsTagtoBaseMatchingPt[i], jetsTagtoBaseMatchingHF[i]); // is (and needs to) be filled in order } } - PROCESS_SWITCH(JetMatchingDuplicates, processJets, "Perform jet matching", false); + PROCESS_SWITCH(JetMatchingDuplicates, processJets, "Perform jet matching", true); }; - -using Charged1JetDataMatching = JetMatchingDuplicates, - soa::Join, - aod::ChargedJetsMatchedToCharged1Jets, - aod::Charged1JetsMatchedToChargedJets, - aod::JTracks, - aod::JDummys>; - -using Charged1JetMCDMatching = JetMatchingDuplicates, - soa::Join, - aod::ChargedMCDetectorLevelJetsMatchedToCharged1MCDetectorLevelJets, - aod::Charged1MCDetectorLevelJetsMatchedToChargedMCDetectorLevelJets, - aod::JTracks, - aod::JDummys>; - -using Charged1JetMCPMatching = 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-data-ch-1"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mcd-ch-1"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mcp-ch-1"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedData1.cxx b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedData1.cxx new file mode 100644 index 00000000000..acf6346f615 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedData1.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. + +// jet matching duplicates charged data task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..b900fb9f0c1 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedMCD1.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. + +// jet matching duplicates charged mcd task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..f913f810191 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicatesChargedMCP1.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. + +// jet matching duplicates charged mcp task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Duplicates/jetMatchingDuplicates.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..238e84ddc91 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/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. + + +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-ds-ch + SOURCES jetSubstructureMatchingMCDsCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-mc-dstar-ch + SOURCES jetSubstructureMatchingMCDstarCharged.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-b0-ch + SOURCES jetSubstructureMatchingMCB0Charged.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-xictoxipipi-ch + SOURCES jetSubstructureMatchingMCXicToXiPiPiCharged.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-ds-ch + SOURCES jetSubstructureMatchingSubDsCharged.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2::FrameworkPhysicsSupport + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(jet-substructure-matching-sub-dstar-ch + SOURCES jetSubstructureMatchingSubDstarCharged.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-b0-ch + SOURCES jetSubstructureMatchingSubB0Charged.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-xictoxipipi-ch + SOURCES jetSubstructureMatchingSubXicToXiPiPiCharged.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..8cca2025f5e --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.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) +// +/// \author Nima Zardoshti +// + +#include "PWGJE/Core/JetMatchingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include "Framework/ASoA.h" +#include +#include +#include +#include // IWYU pragma: export + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +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 BaseSplittingsPerBaseJetDs = aod::dschargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetDs = aod::dschargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetDstar = aod::dstarchargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetDstar = aod::dstarchargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetLc = aod::lcchargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetLc = aod::lcchargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetB0 = aod::b0chargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetB0 = aod::b0chargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetBplus = aod::bpluschargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetBplus = aod::bpluschargedmcparticlelevelsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetXicToXiPiPi = aod::xictoxipipichargedmcdetectorlevelsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetXicToXiPiPi = aod::xictoxipipichargedmcparticlelevelsplitting::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 BasePairsPerBaseJetDs = aod::dschargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetDs = aod::dschargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetDstar = aod::dstarchargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetDstar = aod::dstarchargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetLc = aod::lcchargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetLc = aod::lcchargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetB0 = aod::b0chargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetB0 = aod::b0chargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetBplus = aod::bpluschargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetBplus = aod::bpluschargedmcparticlelevelpair::jetId; + PresliceOptional BasePairsPerBaseJetXicToXiPiPi = aod::xictoxipipichargedmcdetectorlevelpair::jetId; + PresliceOptional TagPairsPerTagJetXicToXiPiPi = aod::xictoxipipichargedmcparticlelevelpair::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& perDsJet, P const& perDstarJet, Q const& perLcJet, R const& perB0Jet, S const& perBplusJet, A const& perXicToXiPiPiJet, B const& perDielectronJet) + { + if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { + return jethfutilities::slicedPerHFJet(table, jet, perD0Jet, perDplusJet, perDsJet, perDstarJet, perLcJet, perB0Jet, perBplusJet, perXicToXiPiPiJet); + } 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, TagSplittingsPerTagJetDs, TagSplittingsPerTagJetDstar, TagSplittingsPerTagJetLc, TagSplittingsPerTagJetB0, TagSplittingsPerTagJetBplus, TagSplittingsPerTagJetXicToXiPiPi, 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, TagPairsPerTagJetDs, TagPairsPerTagJetDstar, TagPairsPerTagJetLc, TagPairsPerTagJetB0, TagPairsPerTagJetBplus, TagPairsPerTagJetXicToXiPiPi, 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, BaseSplittingsPerBaseJetDs, BaseSplittingsPerBaseJetDstar, BaseSplittingsPerBaseJetLc, BaseSplittingsPerBaseJetB0, BaseSplittingsPerBaseJetBplus, BaseSplittingsPerBaseJetXicToXiPiPi, 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, BasePairsPerBaseJetDs, BasePairsPerBaseJetDstar, BasePairsPerBaseJetLc, BasePairsPerBaseJetB0, BasePairsPerBaseJetBplus, BasePairsPerBaseJetXicToXiPiPi, 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/jetSubstructureMatchingMCB0Charged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCB0Charged.cxx new file mode 100644 index 00000000000..96e3e0081ec --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCB0Charged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// B0 substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +using B0ChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::B0ChargedMCDetectorLevelSPsMatchedToB0ChargedMCParticleLevelSPs, + aod::B0ChargedMCParticleLevelSPsMatchedToB0ChargedMCDetectorLevelSPs, + aod::B0ChargedMCDetectorLevelPRsMatchedToB0ChargedMCParticleLevelPRs, + aod::B0ChargedMCParticleLevelPRsMatchedToB0ChargedMCDetectorLevelPRs, + aod::B0ChargedMCDetectorLevelSPs, + aod::B0ChargedMCParticleLevelSPs, + aod::B0ChargedMCDetectorLevelPRs, + aod::B0ChargedMCParticleLevelPRs, + aod::CandidatesB0MCD, + aod::CandidatesB0MCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-b0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCBplusCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCBplusCharged.cxx new file mode 100644 index 00000000000..27bfc4ca22f --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCBplusCharged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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..e73fab8c77e --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCCharged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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..82ae0adbb91 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCD0Charged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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..395617bed72 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDielectronCharged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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..47ee3fb6757 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDplusCharged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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/jetSubstructureMatchingMCDsCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDsCharged.cxx new file mode 100644 index 00000000000..e6e76c930be --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDsCharged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Ds substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +using DsChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::DsChargedMCDetectorLevelSPsMatchedToDsChargedMCParticleLevelSPs, + aod::DsChargedMCParticleLevelSPsMatchedToDsChargedMCDetectorLevelSPs, + aod::DsChargedMCDetectorLevelPRsMatchedToDsChargedMCParticleLevelPRs, + aod::DsChargedMCParticleLevelPRsMatchedToDsChargedMCDetectorLevelPRs, + aod::DsChargedMCDetectorLevelSPs, + aod::DsChargedMCParticleLevelSPs, + aod::DsChargedMCDetectorLevelPRs, + aod::DsChargedMCParticleLevelPRs, + aod::CandidatesDsMCD, + aod::CandidatesDsMCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-ds-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDstarCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDstarCharged.cxx new file mode 100644 index 00000000000..9cff34b1ce7 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCDstarCharged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// D* substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +using DstarChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::DstarChargedMCDetectorLevelSPsMatchedToDstarChargedMCParticleLevelSPs, + aod::DstarChargedMCParticleLevelSPsMatchedToDstarChargedMCDetectorLevelSPs, + aod::DstarChargedMCDetectorLevelPRsMatchedToDstarChargedMCParticleLevelPRs, + aod::DstarChargedMCParticleLevelPRsMatchedToDstarChargedMCDetectorLevelPRs, + aod::DstarChargedMCDetectorLevelSPs, + aod::DstarChargedMCParticleLevelSPs, + aod::DstarChargedMCDetectorLevelPRs, + aod::DstarChargedMCParticleLevelPRs, + aod::CandidatesDstarMCD, + aod::CandidatesDstarMCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-dstar-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..1744d6b24fe --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCLcCharged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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/jetSubstructureMatchingMCXicToXiPiPiCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCXicToXiPiPiCharged.cxx new file mode 100644 index 00000000000..b0eea7a3e6d --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingMCXicToXiPiPiCharged.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// XicToXiPiPi substructure matching mc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatching.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +using XicToXiPiPiChargedJetSubstructureMatchingMC = JetSubstructureMatching, + soa::Join, + aod::XicToXiPiPiChargedMCDetectorLevelSPsMatchedToXicToXiPiPiChargedMCParticleLevelSPs, + aod::XicToXiPiPiChargedMCParticleLevelSPsMatchedToXicToXiPiPiChargedMCDetectorLevelSPs, + aod::XicToXiPiPiChargedMCDetectorLevelPRsMatchedToXicToXiPiPiChargedMCParticleLevelPRs, + aod::XicToXiPiPiChargedMCParticleLevelPRsMatchedToXicToXiPiPiChargedMCDetectorLevelPRs, + aod::XicToXiPiPiChargedMCDetectorLevelSPs, + aod::XicToXiPiPiChargedMCParticleLevelSPs, + aod::XicToXiPiPiChargedMCDetectorLevelPRs, + aod::XicToXiPiPiChargedMCParticleLevelPRs, + aod::CandidatesXicToXiPiPiMCD, + aod::CandidatesXicToXiPiPiMCP, + aod::JetTracksMCD, + aod::JetParticles, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-mc-xictoxipipi-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..bad062a3044 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx @@ -0,0 +1,282 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/Core/JetMatchingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include "Framework/ASoA.h" +#include +#include +#include +#include // IWYU pragma: export + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +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 BaseSplittingsPerBaseJetDs = aod::dschargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetDs = aod::dschargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetDstar = aod::dstarchargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetDstar = aod::dstarchargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetLc = aod::lcchargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetLc = aod::lcchargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetB0 = aod::b0chargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetB0 = aod::b0chargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetBplus = aod::bpluschargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetBplus = aod::bpluschargedeventwisesubtractedsplitting::jetId; + PresliceOptional BaseSplittingsPerBaseJetXicToXiPiPi = aod::xictoxipipichargedsplitting::jetId; + PresliceOptional TagSplittingsPerTagJetXicToXiPiPi = aod::xictoxipipichargedeventwisesubtractedsplitting::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 BasePairsPerBaseJetDs = aod::dschargedpair::jetId; + PresliceOptional TagPairsPerTagJetDs = aod::dschargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetDstar = aod::dstarchargedpair::jetId; + PresliceOptional TagPairsPerTagJetDstar = aod::dstarchargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetLc = aod::lcchargedpair::jetId; + PresliceOptional TagPairsPerTagJetLc = aod::lcchargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetB0 = aod::b0chargedpair::jetId; + PresliceOptional TagPairsPerTagJetB0 = aod::b0chargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetBplus = aod::bpluschargedpair::jetId; + PresliceOptional TagPairsPerTagJetBplus = aod::bpluschargedeventwisesubtractedpair::jetId; + PresliceOptional BasePairsPerBaseJetXicToXiPiPi = aod::xictoxipipichargedpair::jetId; + PresliceOptional TagPairsPerTagJetXicToXiPiPi = aod::xictoxipipichargedeventwisesubtractedpair::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& perDsJet, P const& perDstarJet, Q const& perLcJet, R const& perB0Jet, S const& perBplusJet, A const& perXicToXiPiPiJet, B const& perDielectronJet) + { + if constexpr (jethfutilities::isHFTable() || jethfutilities::isHFMcTable()) { + return jethfutilities::slicedPerHFJet(table, jet, perD0Jet, perDplusJet, perDsJet, perDstarJet, perLcJet, perB0Jet, perBplusJet, perXicToXiPiPiJet); + } 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, TagSplittingsPerTagJetDs, TagSplittingsPerTagJetDstar, TagSplittingsPerTagJetLc, TagSplittingsPerTagJetB0, TagSplittingsPerTagJetBplus, TagSplittingsPerTagJetXicToXiPiPi, 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, TagPairsPerTagJetDs, TagPairsPerTagJetDstar, TagPairsPerTagJetLc, TagPairsPerTagJetB0, TagPairsPerTagJetBplus, TagPairsPerTagJetXicToXiPiPi, 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, BaseSplittingsPerBaseJetDs, BaseSplittingsPerBaseJetDstar, BaseSplittingsPerBaseJetLc, BaseSplittingsPerBaseJetB0, BaseSplittingsPerBaseJetBplus, BaseSplittingsPerBaseJetXicToXiPiPi, 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, BasePairsPerBaseJetDs, BasePairsPerBaseJetDstar, BasePairsPerBaseJetLc, BasePairsPerBaseJetB0, BasePairsPerBaseJetBplus, BasePairsPerBaseJetXicToXiPiPi, 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/jetSubstructureMatchingSubB0Charged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubB0Charged.cxx new file mode 100644 index 00000000000..3ed89997f58 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubB0Charged.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. + +// substructure matching event-wise subtracted B0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +using B0ChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::B0ChargedSPsMatchedToB0ChargedEventWiseSubtractedSPs, + aod::B0ChargedEventWiseSubtractedSPsMatchedToB0ChargedSPs, + aod::B0ChargedPRsMatchedToB0ChargedEventWiseSubtractedPRs, + aod::B0ChargedEventWiseSubtractedPRsMatchedToB0ChargedPRs, + aod::B0ChargedSPs, + aod::B0ChargedEventWiseSubtractedSPs, + aod::B0ChargedPRs, + aod::B0ChargedEventWiseSubtractedPRs, + aod::CandidatesB0Data, + aod::JetTracks, + aod::JetTracksSubB0, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-b0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubBplusCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubBplusCharged.cxx new file mode 100644 index 00000000000..fd7fecd0264 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubBplusCharged.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. + +// substructure matching event-wise subtracted Bplus charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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..60fe610ad61 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubCharged.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. + +// substructure matching event-wise subtracted charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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..45e2bcb3ef2 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubD0Charged.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. + +// substructure matching event-wise subtracted D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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..d9f748252f5 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDielectronCharged.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. + +// substructure matching event-wise subtracted Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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..9d07e6a3bde --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDplusCharged.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. + +// substructure matching event-wise subtracted Dplus charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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/jetSubstructureMatchingSubDsCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDsCharged.cxx new file mode 100644 index 00000000000..0fa4f86388d --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDsCharged.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. + +// substructure matching event-wise subtracted Ds charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +using DsChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::DsChargedSPsMatchedToDsChargedEventWiseSubtractedSPs, + aod::DsChargedEventWiseSubtractedSPsMatchedToDsChargedSPs, + aod::DsChargedPRsMatchedToDsChargedEventWiseSubtractedPRs, + aod::DsChargedEventWiseSubtractedPRsMatchedToDsChargedPRs, + aod::DsChargedSPs, + aod::DsChargedEventWiseSubtractedSPs, + aod::DsChargedPRs, + aod::DsChargedEventWiseSubtractedPRs, + aod::CandidatesDsData, + aod::JetTracks, + aod::JetTracksSubDs, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-ds-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDstarCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDstarCharged.cxx new file mode 100644 index 00000000000..c301149c647 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubDstarCharged.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. + +// substructure matching event-wise subtracted D* charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +using DstarChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::DstarChargedSPsMatchedToDstarChargedEventWiseSubtractedSPs, + aod::DstarChargedEventWiseSubtractedSPsMatchedToDstarChargedSPs, + aod::DstarChargedPRsMatchedToDstarChargedEventWiseSubtractedPRs, + aod::DstarChargedEventWiseSubtractedPRsMatchedToDstarChargedPRs, + aod::DstarChargedSPs, + aod::DstarChargedEventWiseSubtractedSPs, + aod::DstarChargedPRs, + aod::DstarChargedEventWiseSubtractedPRs, + aod::CandidatesDstarData, + aod::JetTracks, + aod::JetTracksSubDstar, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-dstar-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..59f994282a1 --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubLcCharged.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. + +// substructure matching event-wise subtracted Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +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/Matching/Substructure/jetSubstructureMatchingSubXicToXiPiPiCharged.cxx b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubXicToXiPiPiCharged.cxx new file mode 100644 index 00000000000..e5641af7a0d --- /dev/null +++ b/PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSubXicToXiPiPiCharged.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. + +// substructure matching event-wise subtracted XicToXiPiPi charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/Substructure/jetSubstructureMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include +#include +#include +#include +#include + +#include + +using XicToXiPiPiChargedJetSubstructureMatchingSub = JetSubstructureMatchingSub, + soa::Join, + aod::XicToXiPiPiChargedSPsMatchedToXicToXiPiPiChargedEventWiseSubtractedSPs, + aod::XicToXiPiPiChargedEventWiseSubtractedSPsMatchedToXicToXiPiPiChargedSPs, + aod::XicToXiPiPiChargedPRsMatchedToXicToXiPiPiChargedEventWiseSubtractedPRs, + aod::XicToXiPiPiChargedEventWiseSubtractedPRsMatchedToXicToXiPiPiChargedPRs, + aod::XicToXiPiPiChargedSPs, + aod::XicToXiPiPiChargedEventWiseSubtractedSPs, + aod::XicToXiPiPiChargedPRs, + aod::XicToXiPiPiChargedEventWiseSubtractedPRs, + aod::CandidatesXicToXiPiPiData, + aod::JetTracks, + aod::JetTracksSubXicToXiPiPi, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-substructure-matching-sub-xictoxipipi-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMC.cxx b/PWGJE/TableProducer/Matching/jetMatchingMC.cxx new file mode 100644 index 00000000000..5faba83064e --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMC.cxx @@ -0,0 +1,99 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file jetmatchingmc.cxx +/// \brief matching detector level and generator level jets +/// +/// \author Raymond Ehlers , ORNL +/// \author Jochen Klein +/// \author Aimeric Lanodu +/// \author Nima Zardoshti + +#include "PWGJE/Core/JetMatchingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Framework/ASoA.h" +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct JetMatchingMc { + + 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; + + PresliceUnsorted CollisionsPerMcCollision = aod::jmccollisionlb::mcCollisionId; + + void init(InitContext const&) + { + } + + void processJets(aod::JetMcCollisions const& mcCollisions, aod::JetCollisionsMCD const& collisions, + JetsBase const& jetsBase, JetsTag const& jetsTag, + 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; + // 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& mcCollision : mcCollisions) { + + const auto collisionsPerMcColl = collisions.sliceBy(CollisionsPerMcCollision, mcCollision.globalIndex()); + + for (const auto& collision : collisionsPerMcColl) { + + 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, tracks, clusters, candidatesTag, particles, particles, 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(JetMatchingMc, processJets, "Perform jet matching", true); +}; diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCB0Charged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCB0Charged.cxx new file mode 100644 index 00000000000..27205e0c854 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCB0Charged.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. + +// jet matching mc B0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +using B0ChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::B0ChargedMCDetectorLevelJetsMatchedToB0ChargedMCParticleLevelJets, + aod::B0ChargedMCParticleLevelJetsMatchedToB0ChargedMCDetectorLevelJets, + aod::CandidatesB0MCD, + aod::CandidatesB0MCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-b0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCBplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCBplusCharged.cxx new file mode 100644 index 00000000000..e9066924fcc --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCBplusCharged.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. + +// jet matching mc B+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..da8a956efc6 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCCharged.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. + +// jet matching mc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..a56a9f21ff5 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCD0Charged.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. + +// jet matching mc D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..740c30d5f8b --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCDielectronCharged.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. + +// jet matching mc Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..7032c3a42e9 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCDplusCharged.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. + +// jet matching mc D+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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/jetMatchingMCDsCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCDsCharged.cxx new file mode 100644 index 00000000000..df7a49e8940 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCDsCharged.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. + +// jet matching mc Ds charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +using DsChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::DsChargedMCDetectorLevelJetsMatchedToDsChargedMCParticleLevelJets, + aod::DsChargedMCParticleLevelJetsMatchedToDsChargedMCDetectorLevelJets, + aod::CandidatesDsMCD, + aod::CandidatesDsMCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-ds-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCDstarCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCDstarCharged.cxx new file mode 100644 index 00000000000..8eca5d1908e --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCDstarCharged.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. + +// jet matching mc D* charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +using DstarChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::DstarChargedMCDetectorLevelJetsMatchedToDstarChargedMCParticleLevelJets, + aod::DstarChargedMCParticleLevelJetsMatchedToDstarChargedMCDetectorLevelJets, + aod::CandidatesDstarMCD, + aod::CandidatesDstarMCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-dstar-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCFull.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCFull.cxx new file mode 100644 index 00000000000..a98f0c7c5bb --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCFull.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. + +// jet matching mc full task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..ef10653f179 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCLcCharged.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. + +// jet matching mc Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..204d0f4afda --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCNeutral.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. + +// jet matching neutral task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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/Matching/jetMatchingMCSub.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx new file mode 100644 index 00000000000..927298a53b5 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file jetmatchingmcsub.cxx +/// \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 "PWGJE/Core/JetMatchingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Framework/ASoA.h" +#include +#include +#include +#include // IWYU pragma: export + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct JetMatchingMcSub { + + 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 = false; + static constexpr bool jetsTagIsMc = false; + + Preslice baseJetsPerCollision = aod::jet::collisionId; + Preslice tagJetsPerCollision = aod::jet::collisionId; + + void init(InitContext const&) + { + } + + void processJets(aod::JetCollisions const& collisions, + JetsBase const& jetsBase, JetsTag const& jetsTag, + aod::JetTracks const& tracks, + aod::JetTracksSub 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 + 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()); + + 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) { + 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(JetMatchingMcSub, processJets, "Perform jet matching", true); +}; diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubB0Charged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubB0Charged.cxx new file mode 100644 index 00000000000..a5de8601581 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubB0Charged.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. + +// jet matching mc subtracted B0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +using B0ChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::B0ChargedMCDetectorLevelJetsMatchedToB0ChargedMCDetectorLevelEventWiseSubtractedJets, + aod::B0ChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToB0ChargedMCDetectorLevelJets, + aod::CandidatesB0MCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-b0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubBplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubBplusCharged.cxx new file mode 100644 index 00000000000..38e0b9034d2 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubBplusCharged.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. + +// jet matching mc subtracted B+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +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..eb19ef698f3 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubCharged.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. + +// jet matching mc subtracted charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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..31313b99421 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubD0Charged.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. + +// jet matching mc subtracted D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +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..8d9082f2884 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubDielectronCharged.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. + +// jet matching mc subtracted Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +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..936b7b8d718 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubDplusCharged.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. + +// jet matching mc subtracted D+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +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/jetMatchingMCSubDsCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubDsCharged.cxx new file mode 100644 index 00000000000..2fa5d9f74d9 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubDsCharged.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. + +// jet matching mc subtracted Ds charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +using DsChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::DsChargedMCDetectorLevelJetsMatchedToDsChargedMCDetectorLevelEventWiseSubtractedJets, + aod::DsChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToDsChargedMCDetectorLevelJets, + aod::CandidatesDsMCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-ds-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubDstarCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubDstarCharged.cxx new file mode 100644 index 00000000000..f2acd7aedd0 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubDstarCharged.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. + +// jet matching mc subtracted D* charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +using DstarChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::DstarChargedMCDetectorLevelJetsMatchedToDstarChargedMCDetectorLevelEventWiseSubtractedJets, + aod::DstarChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToDstarChargedMCDetectorLevelJets, + aod::CandidatesDstarMCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-dstar-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCSubLcCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubLcCharged.cxx new file mode 100644 index 00000000000..d645f297f9c --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubLcCharged.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. + +// jet matching mc subtracted Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +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/jetMatchingMCSubXicToXiPiPiCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCSubXicToXiPiPiCharged.cxx new file mode 100644 index 00000000000..595be4a2124 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCSubXicToXiPiPiCharged.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. + +// jet matching mc subtracted XicToXiPiPi charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMCSub.cxx" + +#include "PWGJE/DataModel/Jet.h" + +#include +#include +#include +#include +#include + +#include + +using XicToXiPiPiChargedJetMatchingMCSub = JetMatchingMcSub, + soa::Join, + aod::XicToXiPiPiChargedMCDetectorLevelJetsMatchedToXicToXiPiPiChargedMCDetectorLevelEventWiseSubtractedJets, + aod::XicToXiPiPiChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToXicToXiPiPiChargedMCDetectorLevelJets, + aod::CandidatesXicToXiPiPiMCD>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-xictoxipipi-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingMCV0Charged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCV0Charged.cxx new file mode 100644 index 00000000000..35c569d4651 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCV0Charged.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. + +// jet matching V0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +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/Matching/jetMatchingMCXicToXiPiPiCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingMCXicToXiPiPiCharged.cxx new file mode 100644 index 00000000000..1d14c10bef6 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingMCXicToXiPiPiCharged.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. + +// jet matching mc XicToXiPiPi charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingMC.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include + +#include + +using XicToXiPiPiChargedJetMatchingMC = JetMatchingMc, + soa::Join, + aod::XicToXiPiPiChargedMCDetectorLevelJetsMatchedToXicToXiPiPiChargedMCParticleLevelJets, + aod::XicToXiPiPiChargedMCParticleLevelJetsMatchedToXicToXiPiPiChargedMCDetectorLevelJets, + aod::CandidatesXicToXiPiPiMCD, + aod::CandidatesXicToXiPiPiMCP, + aod::JDummys>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-xictoxipipi-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSub.cxx b/PWGJE/TableProducer/Matching/jetMatchingSub.cxx new file mode 100644 index 00000000000..97ac2461acd --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSub.cxx @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 event-wise constituent subtracted data jets and unsubtracted data jets +/// \author Nima Zardoshti + +#include "PWGJE/Core/JetMatchingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Framework/ASoA.h" +#include +#include +#include +#include // IWYU pragma: export + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +template +struct JetMatchingSub { + + 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, + 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 + 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()); + + 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) { + 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(JetMatchingSub, processJets, "Perform jet matching", true); +}; diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubB0Charged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubB0Charged.cxx new file mode 100644 index 00000000000..87598cc0cc1 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubB0Charged.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. + +// jet matching subtracted B0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using B0ChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::B0ChargedJetsMatchedToB0ChargedEventWiseSubtractedJets, + aod::B0ChargedEventWiseSubtractedJetsMatchedToB0ChargedJets, + aod::JTrackB0Subs, + aod::CandidatesB0Data>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-b0-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubBplusCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubBplusCharged.cxx new file mode 100644 index 00000000000..bd8591a4340 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubBplusCharged.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. + +// jet matching subtracted B+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..406345bc8c2 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubCharged.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. + +// jet matching subtracted charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..2912f249d37 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubD0Charged.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. + +// jet matching subtracted D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..1cdd5c20c54 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubDielectronCharged.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. + +// jet matching subtracted Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..533b129b598 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubDplusCharged.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. + +// jet matching subtracted D+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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/jetMatchingSubDsCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubDsCharged.cxx new file mode 100644 index 00000000000..d08dd8e6155 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubDsCharged.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. + +// jet matching subtracted Ds charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using DsChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::DsChargedJetsMatchedToDsChargedEventWiseSubtractedJets, + aod::DsChargedEventWiseSubtractedJetsMatchedToDsChargedJets, + aod::JTrackDsSubs, + aod::CandidatesDsData>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-ds-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubDstarCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubDstarCharged.cxx new file mode 100644 index 00000000000..e8d54a30ecb --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubDstarCharged.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. + +// jet matching subtracted D* charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using DstarChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::DstarChargedJetsMatchedToDstarChargedEventWiseSubtractedJets, + aod::DstarChargedEventWiseSubtractedJetsMatchedToDstarChargedJets, + aod::JTrackDstarSubs, + aod::CandidatesDstarData>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-dstar-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/Matching/jetMatchingSubLcCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubLcCharged.cxx new file mode 100644 index 00000000000..72ac5bd7253 --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubLcCharged.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. + +// jet matching subtracted Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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/Matching/jetMatchingSubXicToXiPiPiCharged.cxx b/PWGJE/TableProducer/Matching/jetMatchingSubXicToXiPiPiCharged.cxx new file mode 100644 index 00000000000..a2efd7f0cde --- /dev/null +++ b/PWGJE/TableProducer/Matching/jetMatchingSubXicToXiPiPiCharged.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. + +// jet matching subtracted XicToXiPiPi charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/TableProducer/Matching/jetMatchingSub.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using XicToXiPiPiChargedJetMatchingSub = JetMatchingSub, + soa::Join, + aod::XicToXiPiPiChargedJetsMatchedToXicToXiPiPiChargedEventWiseSubtractedJets, + aod::XicToXiPiPiChargedEventWiseSubtractedJetsMatchedToXicToXiPiPiChargedJets, + aod::JTrackXicToXiPiPiSubs, + aod::CandidatesXicToXiPiPiData>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-xictoxipipi-ch"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/TableProducer/derivedDataProducer.cxx b/PWGJE/TableProducer/derivedDataProducer.cxx new file mode 100644 index 00000000000..80c67d79d88 --- /dev/null +++ b/PWGJE/TableProducer/derivedDataProducer.cxx @@ -0,0 +1,858 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGJE/Core/JetDQUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetV0Utilities.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataDQ.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetReducedDataV0.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/trackUtilities.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 "CCDB/BasicCCDBManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/Vertex.h" +#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 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 jDsCollisionIdsTable; + Produces jDsMcCollisionIdsTable; + Produces jDsIdsTable; + Produces jDsParticleIdsTable; + Produces jDstarCollisionIdsTable; + Produces jDstarMcCollisionIdsTable; + Produces jDstarIdsTable; + Produces jDstarParticleIdsTable; + Produces jLcCollisionIdsTable; + Produces jLcMcCollisionIdsTable; + Produces jLcIdsTable; + Produces jLcParticleIdsTable; + Produces jB0CollisionIdsTable; + Produces jB0McCollisionIdsTable; + Produces jB0IdsTable; + Produces jB0ParticleIdsTable; + Produces jBplusCollisionIdsTable; + Produces jBplusMcCollisionIdsTable; + Produces jBplusIdsTable; + Produces jBplusParticleIdsTable; + Produces jXicToXiPiPiCollisionIdsTable; + Produces jXicToXiPiPiMcCollisionIdsTable; + Produces jXicToXiPiPiIdsTable; + Produces jXicToXiPiPiParticleIdsTable; + 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"}; + Configurable v0ChargedDecaysOnly{"v0ChargedDecaysOnly", true, "store V0s (at particle-level) only if they decay to charged particles"}; + + 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(), bc.rct_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.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), collision.centFV0A(), -1.0, collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.centFT0CVariant1(), hadronicRate, collision.trackOccupancyInTimeRange(), collision.alias_raw(), jetderiveddatautilities::setEventSelectionBit(collision), collision.rct_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.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1, collision.alias_raw(), jetderiveddatautilities::setEventSelectionBit(collision), collision.rct_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(), -1.0, -1.0, -1.0, -1.0, collision.centRun2V0A(), collision.centRun2V0M(), -1.0, -1.0, -1.0, -1.0, 1.0, -1, collision.alias_raw(), jetderiveddatautilities::setEventSelectionBit(collision), collision.rct_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.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1, -1.0, 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&) + { + products.jMcCollisionsLabelTable(collision.mcCollisionId()); // collision.mcCollisionId() returns -1 if collision has no associated mcCollision + if (collision.has_mcCollision()) { + products.jCollisionMcInfosTable(collision.mcCollision().weight(), collision.mcCollision().getSubGeneratorId()); + } else { + products.jCollisionMcInfosTable(0.0, jetderiveddatautilities::JCollisionSubGeneratorId::none); + } + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionLabels, "produces derived MC collision labels table", false); + + void processMcCollisions(soa::Join::iterator const& mcCollision) + { + products.jMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.multMCFV0A(), mcCollision.multMCFT0A(), mcCollision.multMCFT0C(), mcCollision.centFT0M(), mcCollision.weight(), mcCollision.getSubGeneratorId(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard()); + products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisions, "produces derived MC collision table", false); + + void processMcCollisionsWithoutCentralityAndMultiplicity(soa::Join::iterator const& mcCollision) + { + products.jMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), -1.0, -1.0, -1.0, -1.0, mcCollision.weight(), mcCollision.getSubGeneratorId(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard()); + products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionsWithoutCentralityAndMultiplicity, "produces derived MC collision table without centraility and multiplicity", false); + + void processMcCollisionsWithoutXsection(soa::Join::iterator const& mcCollision) + { + products.jMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.multMCFV0A(), mcCollision.multMCFT0A(), mcCollision.multMCFT0C(), mcCollision.centFT0M(), mcCollision.weight(), mcCollision.getSubGeneratorId(), 1, 1, 1.0, 1.0, 999.0); + products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionsWithoutXsection, "produces derived MC collision table without cross section information", false); + + void processMcCollisionsWithoutCentralityAndMultiplicityAndXsection(aod::McCollision const& mcCollision) + { + products.jMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), -1.0, -1.0, -1.0, -1.0, mcCollision.weight(), mcCollision.getSubGeneratorId(), 1, 1, 1.0, 1.0, 999.0); + products.jMcCollisionsParentIndexTable(mcCollision.globalIndex()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processMcCollisionsWithoutCentralityAndMultiplicityAndXsection, "produces derived MC collision table without centrality, multiplicity and 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}; + if (particle.has_daughters()) { + auto i = 0; + 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.statusCode(), particle.flags(), 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; + int leadingCellNumber = -1; + int subleadingCellNumber = -1; + for (auto const& clutserCell : clusterCells) { + float cellAmplitude = clutserCell.calo().amplitude(); + int 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(), clusterTrack.deltaEta(), clusterTrack.deltaPhi()); + } + 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& D0Candidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({D0Candidate.prong0Id(), D0Candidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({D0Candidate.prong1Id(), D0Candidate.prong1_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({D0Candidate.prong0Id(), D0Candidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({D0Candidate.prong1Id(), D0Candidate.collisionId()}); + } + products.jD0IdsTable(D0Candidate.collisionId(), JProng0ID->second, JProng1ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processD0, "produces derived index for D0 candidates", false); + + void processD0MC(aod::HfD0PIds::iterator const& D0Particle) + { + products.jD0ParticleIdsTable(D0Particle.mcCollisionId(), D0Particle.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& DplusCandidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({DplusCandidate.prong0Id(), DplusCandidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({DplusCandidate.prong1Id(), DplusCandidate.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({DplusCandidate.prong2Id(), DplusCandidate.prong2_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({DplusCandidate.prong0Id(), DplusCandidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({DplusCandidate.prong1Id(), DplusCandidate.collisionId()}); + JProng2ID = trackCollisionMapping.find({DplusCandidate.prong2Id(), DplusCandidate.collisionId()}); + } + products.jDplusIdsTable(DplusCandidate.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDplus, "produces derived index for Dplus candidates", false); + + void processDplusMC(aod::HfDplusPIds::iterator const& DplusParticle) + { + products.jDplusParticleIdsTable(DplusParticle.mcCollisionId(), DplusParticle.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDplusMC, "produces derived index for Dplus particles", false); + + void processDsCollisions(aod::HfDsCollIds::iterator const& DsCollision) + { + products.jDsCollisionIdsTable(DsCollision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDsCollisions, "produces derived index for Ds collisions", false); + + void processDsMcCollisions(aod::HfDsMcCollIds::iterator const& DsMcCollision) + { + products.jDsMcCollisionIdsTable(DsMcCollision.mcCollisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDsMcCollisions, "produces derived index for Ds MC collisions", false); + + void processDs(aod::HfDsIds::iterator const& DsCandidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({DsCandidate.prong0Id(), DsCandidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({DsCandidate.prong1Id(), DsCandidate.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({DsCandidate.prong2Id(), DsCandidate.prong2_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({DsCandidate.prong0Id(), DsCandidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({DsCandidate.prong1Id(), DsCandidate.collisionId()}); + JProng2ID = trackCollisionMapping.find({DsCandidate.prong2Id(), DsCandidate.collisionId()}); + } + products.jDsIdsTable(DsCandidate.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDs, "produces derived index for Ds candidates", false); + + void processDsMC(aod::HfDsPIds::iterator const& DsParticle) + { + products.jDsParticleIdsTable(DsParticle.mcCollisionId(), DsParticle.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDsMC, "produces derived index for Ds particles", false); + + void processDstarCollisions(aod::HfDstarCollIds::iterator const& DstarCollision) + { + products.jDstarCollisionIdsTable(DstarCollision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDstarCollisions, "produces derived index for Dstar collisions", false); + + void processDstarMcCollisions(aod::HfDstarMcCollIds::iterator const& DstarMcCollision) + { + products.jDstarMcCollisionIdsTable(DstarMcCollision.mcCollisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDstarMcCollisions, "produces derived index for Dstar MC collisions", false); + + void processDstar(aod::HfDstarIds::iterator const& DstarCandidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({DstarCandidate.prong0Id(), DstarCandidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({DstarCandidate.prong1Id(), DstarCandidate.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({DstarCandidate.prong2Id(), DstarCandidate.prong2_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({DstarCandidate.prong0Id(), DstarCandidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({DstarCandidate.prong1Id(), DstarCandidate.collisionId()}); + JProng2ID = trackCollisionMapping.find({DstarCandidate.prong2Id(), DstarCandidate.collisionId()}); + } + products.jDstarIdsTable(DstarCandidate.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDstar, "produces derived index for Dstar candidates", false); + + void processDstarMC(aod::HfDstarPIds::iterator const& DstarParticle) + { + products.jDstarParticleIdsTable(DstarParticle.mcCollisionId(), DstarParticle.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processDstarMC, "produces derived index for Dstar 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& LcCandidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({LcCandidate.prong0Id(), LcCandidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({LcCandidate.prong1Id(), LcCandidate.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({LcCandidate.prong2Id(), LcCandidate.prong2_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({LcCandidate.prong0Id(), LcCandidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({LcCandidate.prong1Id(), LcCandidate.collisionId()}); + JProng2ID = trackCollisionMapping.find({LcCandidate.prong2Id(), LcCandidate.collisionId()}); + } + products.jLcIdsTable(LcCandidate.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processLc, "produces derived index for Lc candidates", false); + + void processLcMC(aod::HfLcPIds::iterator const& LcParticle) + { + products.jLcParticleIdsTable(LcParticle.mcCollisionId(), LcParticle.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processLcMC, "produces derived index for Lc particles", false); + + void processB0Collisions(aod::HfB0CollIds::iterator const& B0Collision) + { + products.jB0CollisionIdsTable(B0Collision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processB0Collisions, "produces derived index for B0 collisions", false); + + void processB0McCollisions(aod::HfB0McCollIds::iterator const& B0McCollision) + { + products.jB0McCollisionIdsTable(B0McCollision.mcCollisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processB0McCollisions, "produces derived index for B0 MC collisions", false); + + void processB0(aod::HfB0Ids::iterator const& B0Candidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({B0Candidate.prong0Id(), B0Candidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({B0Candidate.prong1Id(), B0Candidate.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({B0Candidate.prong2Id(), B0Candidate.prong2_as().collisionId()}); + auto JProng3ID = trackCollisionMapping.find({B0Candidate.prong3Id(), B0Candidate.prong3_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({B0Candidate.prong0Id(), B0Candidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({B0Candidate.prong1Id(), B0Candidate.collisionId()}); + JProng2ID = trackCollisionMapping.find({B0Candidate.prong2Id(), B0Candidate.collisionId()}); + JProng3ID = trackCollisionMapping.find({B0Candidate.prong3Id(), B0Candidate.collisionId()}); + } + products.jB0IdsTable(B0Candidate.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second, JProng3ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processB0, "produces derived index for B0 candidates", false); + + void processB0MC(aod::HfB0PIds::iterator const& B0Particle) + { + products.jB0ParticleIdsTable(B0Particle.mcCollisionId(), B0Particle.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processB0MC, "produces derived index for B0 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& BplusCandidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({BplusCandidate.prong0Id(), BplusCandidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({BplusCandidate.prong1Id(), BplusCandidate.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({BplusCandidate.prong2Id(), BplusCandidate.prong2_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({BplusCandidate.prong0Id(), BplusCandidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({BplusCandidate.prong1Id(), BplusCandidate.collisionId()}); + JProng2ID = trackCollisionMapping.find({BplusCandidate.prong2Id(), BplusCandidate.collisionId()}); + } + products.jBplusIdsTable(BplusCandidate.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processBplus, "produces derived index for Bplus candidates", false); + + void processBplusMC(aod::HfBplusPIds::iterator const& BplusParticle) + { + products.jBplusParticleIdsTable(BplusParticle.mcCollisionId(), BplusParticle.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processBplusMC, "produces derived index for Bplus particles", false); + + void processXicToXiPiPiCollisions(aod::HfXicToXiPiPiCollIds::iterator const& XicToXiPiPiCollision) + { + products.jXicToXiPiPiCollisionIdsTable(XicToXiPiPiCollision.collisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processXicToXiPiPiCollisions, "produces derived index for XicToXiPiPi collisions", false); + + void processXicToXiPiPiMcCollisions(aod::HfXicToXiPiPiMcCollIds::iterator const& XicToXiPiPiMcCollision) + { + products.jXicToXiPiPiMcCollisionIdsTable(XicToXiPiPiMcCollision.mcCollisionId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processXicToXiPiPiMcCollisions, "produces derived index for XicToXiPiPi MC collisions", false); + + void processXicToXiPiPi(aod::HfXicToXiPiPiIds::iterator const& XicToXiPiPiCandidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong0Id(), XicToXiPiPiCandidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong1Id(), XicToXiPiPiCandidate.prong1_as().collisionId()}); + auto JProng2ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong2Id(), XicToXiPiPiCandidate.prong2_as().collisionId()}); + auto JProng3ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong3Id(), XicToXiPiPiCandidate.prong3_as().collisionId()}); + auto JProng4ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong4Id(), XicToXiPiPiCandidate.prong4_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong0Id(), XicToXiPiPiCandidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong1Id(), XicToXiPiPiCandidate.collisionId()}); + JProng2ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong2Id(), XicToXiPiPiCandidate.collisionId()}); + JProng3ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong3Id(), XicToXiPiPiCandidate.collisionId()}); + JProng4ID = trackCollisionMapping.find({XicToXiPiPiCandidate.prong4Id(), XicToXiPiPiCandidate.collisionId()}); + } + products.jXicToXiPiPiIdsTable(XicToXiPiPiCandidate.collisionId(), JProng0ID->second, JProng1ID->second, JProng2ID->second, JProng3ID->second, JProng4ID->second); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processXicToXiPiPi, "produces derived index for XicToXiPiPi candidates", false); + + void processXicToXiPiPiMC(aod::HfXicToXiPiPiPIds::iterator const& XicToXiPiPiParticle) + { + products.jXicToXiPiPiParticleIdsTable(XicToXiPiPiParticle.mcCollisionId(), XicToXiPiPiParticle.mcParticleId()); + } + PROCESS_SWITCH(JetDerivedDataProducerTask, processXicToXiPiPiMC, "produces derived index for XicToXiPiPi particles", false); + + void processV0(aod::V0Indices::iterator const& V0Candidate, aod::Tracks const&) + { + auto JPosTrackID = trackCollisionMapping.find({V0Candidate.posTrackId(), V0Candidate.posTrack_as().collisionId()}); + auto JNegTrackID = trackCollisionMapping.find({V0Candidate.negTrackId(), V0Candidate.negTrack_as().collisionId()}); + if (withCollisionAssociator) { + JPosTrackID = trackCollisionMapping.find({V0Candidate.posTrackId(), V0Candidate.collisionId()}); + JNegTrackID = trackCollisionMapping.find({V0Candidate.negTrackId(), V0Candidate.collisionId()}); + } + products.jV0IdsTable(V0Candidate.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, v0ChargedDecaysOnly)) { + 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}; + if (particle.has_daughters()) { + auto i = 0; + 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.statusCode(), particle.flags(), 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& DielectronCandidate, aod::Tracks const&) + { + auto JProng0ID = trackCollisionMapping.find({DielectronCandidate.prong0Id(), DielectronCandidate.prong0_as().collisionId()}); + auto JProng1ID = trackCollisionMapping.find({DielectronCandidate.prong1Id(), DielectronCandidate.prong1_as().collisionId()}); + if (withCollisionAssociator) { + JProng0ID = trackCollisionMapping.find({DielectronCandidate.prong0Id(), DielectronCandidate.collisionId()}); + JProng1ID = trackCollisionMapping.find({DielectronCandidate.prong1Id(), DielectronCandidate.collisionId()}); + } + products.jDielectronIdsTable(DielectronCandidate.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}; + if (particle.has_daughters()) { + auto i = 0; + 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.statusCode(), particle.flags(), 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..64f185d6c08 --- /dev/null +++ b/PWGJE/TableProducer/derivedDataSelector.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 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 "JetDerivedDataUtilities.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataSelector.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +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 thresholdChargedDsJetPtMin{"thresholdChargedDsJetPtMin", 0.0, "Minimum charged Ds jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedDsJetPtMin{"thresholdChargedEventWiseSubtractedDsJetPtMin", 0.0, "Minimum charged event-wise subtracted Ds jet pt to accept event"}; + Configurable thresholdChargedDsMCPJetPtMin{"thresholdChargedDsMCPJetPtMin", 0.0, "Minimum charged Ds mcp jet pt to accept event"}; + Configurable thresholdChargedDstarJetPtMin{"thresholdChargedDstarJetPtMin", 0.0, "Minimum charged Dstar jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedDstarJetPtMin{"thresholdChargedEventWiseSubtractedDstarJetPtMin", 0.0, "Minimum charged event-wise subtracted Dstar jet pt to accept event"}; + Configurable thresholdChargedDstarMCPJetPtMin{"thresholdChargedDstarMCPJetPtMin", 0.0, "Minimum charged Dstar 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 thresholdChargedB0JetPtMin{"thresholdChargedB0JetPtMin", 0.0, "Minimum charged B0 jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedB0JetPtMin{"thresholdChargedEventWiseSubtractedB0JetPtMin", 0.0, "Minimum charged event-wise subtracted B0 jet pt to accept event"}; + Configurable thresholdChargedB0MCPJetPtMin{"thresholdChargedB0MCPJetPtMin", 0.0, "Minimum charged B0 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 thresholdChargedXicToXiPiPiJetPtMin{"thresholdChargedXicToXiPiPiJetPtMin", 0.0, "Minimum charged XicToXiPiPi jet pt to accept event"}; + Configurable thresholdChargedEventWiseSubtractedXicToXiPiPiJetPtMin{"thresholdChargedEventWiseSubtractedXicToXiPiPiJetPtMin", 0.0, "Minimum charged event-wise subtracted XicToXiPiPi jet pt to accept event"}; + Configurable thresholdChargedXicToXiPiPiMCPJetPtMin{"thresholdChargedXicToXiPiPiMCPJetPtMin", 0.0, "Minimum charged XicToXiPiPi 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 thresholdTriggerParticlePtMin{"thresholdTriggerParticlePtMin", 0.0, "Minimum trigger particle 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.centFT0M() < config.centralityMin || collision.centFT0M() >= 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::DsChargedJets> || std::is_same_v, aod::DsChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedDsJetPtMin; + } else if constexpr (std::is_same_v, aod::DsChargedEventWiseSubtractedJets> || std::is_same_v, aod::DsChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedDsJetPtMin; + } else if constexpr (std::is_same_v, aod::DsChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedDsMCPJetPtMin; + } else if constexpr (std::is_same_v, aod::DstarChargedJets> || std::is_same_v, aod::DstarChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedDstarJetPtMin; + } else if constexpr (std::is_same_v, aod::DstarChargedEventWiseSubtractedJets> || std::is_same_v, aod::DstarChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedDstarJetPtMin; + } else if constexpr (std::is_same_v, aod::DstarChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedDstarMCPJetPtMin; + } 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::B0ChargedJets> || std::is_same_v, aod::B0ChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedB0JetPtMin; + } else if constexpr (std::is_same_v, aod::B0ChargedEventWiseSubtractedJets> || std::is_same_v, aod::B0ChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedB0JetPtMin; + } else if constexpr (std::is_same_v, aod::B0ChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedB0MCPJetPtMin; + } 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::XicToXiPiPiChargedJets> || std::is_same_v, aod::XicToXiPiPiChargedMCDetectorLevelJets>) { + selectionObjectPtMin = config.thresholdChargedXicToXiPiPiJetPtMin; + } else if constexpr (std::is_same_v, aod::XicToXiPiPiChargedEventWiseSubtractedJets> || std::is_same_v, aod::XicToXiPiPiChargedMCDetectorLevelEventWiseSubtractedJets>) { + selectionObjectPtMin = config.thresholdChargedEventWiseSubtractedXicToXiPiPiJetPtMin; + } else if constexpr (std::is_same_v, aod::XicToXiPiPiChargedMCParticleLevelJets>) { + selectionObjectPtMin = config.thresholdChargedXicToXiPiPiMCPJetPtMin; + } 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::JMcParticles>) { + selectionObjectPtMin = config.thresholdTriggerParticlePtMin; + } 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::DsChargedMCParticleLevelJets> || std::is_same_v, aod::DstarChargedMCParticleLevelJets> || std::is_same_v, aod::LcChargedMCParticleLevelJets> || std::is_same_v, aod::B0ChargedMCParticleLevelJets> || std::is_same_v, aod::BplusChargedMCParticleLevelJets> || std::is_same_v, aod::XicToXiPiPiChargedMCParticleLevelJets> || std::is_same_v, aod::DielectronChargedMCParticleLevelJets> || std::is_same_v, aod::JMcParticles>) { + 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, processSelectingDsChargedJets, "process Ds charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDsChargedEventWiseSubtractedJets, "process Ds event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDsChargedMCDJets, "process Ds charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDsChargedMCDetectorLevelEventWiseSubtractedJets, "process Ds event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDsChargedMCPJets, "process Ds charged mcp jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDstarChargedJets, "process Dstar charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDstarChargedEventWiseSubtractedJets, "process Dstar event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDstarChargedMCDJets, "process Dstar charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDstarChargedMCDetectorLevelEventWiseSubtractedJets, "process Dstar event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingDstarChargedMCPJets, "process Dstar 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, processSelectingB0ChargedJets, "process B0 charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingB0ChargedEventWiseSubtractedJets, "process B0 event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingB0ChargedMCDJets, "process B0 charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingB0ChargedMCDetectorLevelEventWiseSubtractedJets, "process B0 event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingB0ChargedMCPJets, "process B0 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, processSelectingXicToXiPiPiChargedJets, "process XicToXiPiPi charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiChargedEventWiseSubtractedJets, "process XicToXiPiPi event-wise subtracted charged jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiChargedMCDJets, "process XicToXiPiPi charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiChargedMCDetectorLevelEventWiseSubtractedJets, "process XicToXiPiPi event-wise subtracted charged mcd jets", false); + PROCESS_SWITCH_FULL(JetDerivedDataSelector, processSelectionObjects, processSelectingXicToXiPiPiChargedMCPJets, "process XicToXiPiPi 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, processSelectionObjects, processSelectingParticles, "process high pt particles", 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 69% rename from PWGJE/TableProducer/jetderiveddatatriggerproducer.cxx rename to PWGJE/TableProducer/derivedDataTriggerProducer.cxx index 4d7dcccce96..b90495d0bb6 100644 --- a/PWGJE/TableProducer/jetderiveddatatriggerproducer.cxx +++ b/PWGJE/TableProducer/derivedDataTriggerProducer.cxx @@ -13,20 +13,20 @@ // /// \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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/JetReducedData.h" #include "EventFiltering/filterTables.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; @@ -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..5f6ad60bf59 --- /dev/null +++ b/PWGJE/TableProducer/derivedDataWriter.cxx @@ -0,0 +1,1079 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "JetDerivedDataUtilities.h" + +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/Core/JetDQUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataDQ.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetReducedDataSelector.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 savePartonLevelInfo{"savePartonLevelInfo", true, "save parton level info at MCP level"}; + + 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; + + struct : ProducesGroup { + 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; + } productsD0; + + struct : ProducesGroup { + 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; + } productsDplus; + + struct : ProducesGroup { + Produces storedDsCollisionsTable; + Produces storedDsCollisionIdsTable; + Produces storedDssTable; + Produces storedDsParsTable; + Produces storedDsParExtrasTable; + Produces storedDsParDaughtersDummyTable; + Produces storedDsSelsTable; + Produces storedDsMlsTable; + Produces storedDsMlDughtersDummyTable; + Produces storedDsMcsTable; + Produces storedDsIdsTable; + Produces storedDsMcCollisionsTable; + Produces storedDsMcCollisionIdsTable; + Produces storedDsMcCollisionsMatchingTable; + Produces storedDsParticlesTable; + Produces storedDsParticleIdsTable; + } productsDs; + + struct : ProducesGroup { + Produces storedDstarCollisionsTable; + Produces storedDstarCollisionIdsTable; + Produces storedDstarsTable; + Produces storedDstarParsTable; + Produces storedDstarParExtrasDummyTable; + Produces storedDstarParD0sTable; + Produces storedDstarSelsTable; + Produces storedDstarMlsTable; + Produces storedDstarMlDaughtersDummyTable; + Produces storedDstarMcsTable; + Produces storedDstarIdsTable; + Produces storedDstarMcCollisionsTable; + Produces storedDstarMcCollisionIdsTable; + Produces storedDstarMcCollisionsMatchingTable; + Produces storedDstarParticlesTable; + Produces storedDstarParticleIdsTable; + } productsDstar; + + struct : ProducesGroup { + 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; + } productsLc; + + struct : ProducesGroup { + Produces storedB0CollisionsTable; + Produces storedB0CollisionIdsTable; + Produces storedB0sTable; + Produces storedB0ParsTable; + Produces storedB0ParExtrasTable; + Produces storedB0ParDplussTable; + Produces storedB0SelsTable; + Produces storedB0MlsTable; + Produces storedB0MlDplussTable; + Produces storedB0McsTable; + Produces storedB0IdsTable; + Produces storedB0McCollisionsTable; + Produces storedB0McCollisionIdsTable; + Produces storedB0McCollisionsMatchingTable; + Produces storedB0ParticlesTable; + Produces storedB0ParticleIdsTable; + } productsB0; + + struct : ProducesGroup { + 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; + } productsBplus; + + struct : ProducesGroup { + Produces storedXicToXiPiPiCollisionsTable; + Produces storedXicToXiPiPiCollisionIdsTable; + Produces storedXicToXiPiPisTable; + Produces storedXicToXiPiPiParsTable; + Produces storedXicToXiPiPiParExtrasTable; + Produces storedXicToXiPiPiParDaughtersDummyTable; + Produces storedXicToXiPiPiSelsTable; + Produces storedXicToXiPiPiMlsTable; + Produces storedXicToXiPiPiMlDughtersDummyTable; + Produces storedXicToXiPiPiMcsTable; + Produces storedXicToXiPiPiIdsTable; + Produces storedXicToXiPiPiMcCollisionsTable; + Produces storedXicToXiPiPiMcCollisionIdsTable; + Produces storedXicToXiPiPiMcCollisionsMatchingTable; + Produces storedXicToXiPiPiParticlesTable; + Produces storedXicToXiPiPiParticleIdsTable; + } productsXicToXiPiPi; + + struct : ProducesGroup { + Produces storedDielectronCollisionsTable; + Produces storedDielectronCollisionIdsTable; + Produces storedDielectronsTable; + Produces storedDielectronIdsTable; + Produces storedDielectronsAllTable; + Produces storedDielectronMcCollisionsTable; + Produces storedDielectronMcCollisionIdsTable; + Produces storedDielectronMcRCollDummysTable; + Produces storedDielectronParticlesTable; + Produces storedDielectronParticleIdsTable; + } productsDielectron; + + } products; + + struct : PresliceGroup { + Preslice> TracksPerCollision = aod::jtrack::collisionId; + + Preslice> ParticlesPerMcCollision = aod::jmcparticle::mcCollisionId; + Preslice D0McCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DplusMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DsMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DstarMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice LcMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice B0McCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice BplusMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice XicToXiPiPiMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DielectronMcCollisionsPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice D0ParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DplusParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DsParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice DstarParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice LcParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice B0ParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice BplusParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + Preslice XicToXiPiPiParticlesPerMcCollision = aod::jcandidateindices::mcCollisionId; + PresliceUnsorted EMCTrackPerTrack = aod::jemctrack::trackId; + } preslices; + + 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& D0Candidates) + { + + if (collision.isCollisionSelected()) { + for (const auto& D0Collision : D0Collisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(D0Collision, products.productsD0.storedD0CollisionsTable); + products.productsD0.storedD0CollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& D0Candidate : D0Candidates) { + jethfutilities::fillHFCandidateTable(D0Candidate, products.productsD0.storedD0CollisionsTable.lastIndex(), products.productsD0.storedD0sTable, products.productsD0.storedD0ParsTable, products.productsD0.storedD0ParExtrasTable, products.productsD0.storedD0ParDaughtersDummyTable, products.productsD0.storedD0SelsTable, products.productsD0.storedD0MlsTable, products.productsD0.storedD0MlDughtersDummyTable, products.productsD0.storedD0McsTable); + products.productsD0.storedD0IdsTable(collisionMapping[collision.globalIndex()], trackMapping[D0Candidate.prong0Id()], trackMapping[D0Candidate.prong1Id()]); + } + } + } + + template + void storeDplus(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsDplus const& DplusCollisions, T const& DplusCandidates) + { + if (collision.isCollisionSelected()) { + for (const auto& DplusCollision : DplusCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(DplusCollision, products.productsDplus.storedDplusCollisionsTable); + products.productsDplus.storedDplusCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& DplusCandidate : DplusCandidates) { + jethfutilities::fillHFCandidateTable(DplusCandidate, products.productsDplus.storedDplusCollisionsTable.lastIndex(), products.productsDplus.storedDplussTable, products.productsDplus.storedDplusParsTable, products.productsDplus.storedDplusParExtrasTable, products.productsDplus.storedDplusParDaughtersDummyTable, products.productsDplus.storedDplusSelsTable, products.productsDplus.storedDplusMlsTable, products.productsDplus.storedDplusMlDughtersDummyTable, products.productsDplus.storedDplusMcsTable); + products.productsDplus.storedDplusIdsTable(collisionMapping[collision.globalIndex()], trackMapping[DplusCandidate.prong0Id()], trackMapping[DplusCandidate.prong1Id()], trackMapping[DplusCandidate.prong2Id()]); + } + } + } + + template + void storeDs(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsDs const& DsCollisions, T const& DsCandidates) + { + if (collision.isCollisionSelected()) { + for (const auto& DsCollision : DsCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(DsCollision, products.productsDs.storedDsCollisionsTable); + products.productsDs.storedDsCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& DsCandidate : DsCandidates) { + jethfutilities::fillHFCandidateTable(DsCandidate, products.productsDs.storedDsCollisionsTable.lastIndex(), products.productsDs.storedDssTable, products.productsDs.storedDsParsTable, products.productsDs.storedDsParExtrasTable, products.productsDs.storedDsParDaughtersDummyTable, products.productsDs.storedDsSelsTable, products.productsDs.storedDsMlsTable, products.productsDs.storedDsMlDughtersDummyTable, products.productsDs.storedDsMcsTable); + products.productsDs.storedDsIdsTable(collisionMapping[collision.globalIndex()], trackMapping[DsCandidate.prong0Id()], trackMapping[DsCandidate.prong1Id()], trackMapping[DsCandidate.prong2Id()]); + } + } + } + + template + void storeDstar(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsDstar const& DstarCollisions, T const& DstarCandidates) + { + + if (collision.isCollisionSelected()) { + for (const auto& DstarCollision : DstarCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(DstarCollision, products.productsDstar.storedDstarCollisionsTable); + products.productsDstar.storedDstarCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& DstarCandidate : DstarCandidates) { + jethfutilities::fillHFCandidateTable(DstarCandidate, products.productsDstar.storedDstarCollisionsTable.lastIndex(), products.productsDstar.storedDstarsTable, products.productsDstar.storedDstarParsTable, products.productsDstar.storedDstarParExtrasDummyTable, products.productsDstar.storedDstarParD0sTable, products.productsDstar.storedDstarSelsTable, products.productsDstar.storedDstarMlsTable, products.productsDstar.storedDstarMlDaughtersDummyTable, products.productsDstar.storedDstarMcsTable); + products.productsDstar.storedDstarIdsTable(collisionMapping[collision.globalIndex()], trackMapping[DstarCandidate.prong0Id()], trackMapping[DstarCandidate.prong1Id()], trackMapping[DstarCandidate.prong2Id()]); + } + } + } + + template + void storeLc(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsLc const& LcCollisions, T const& LcCandidates) + { + if (collision.isCollisionSelected()) { + for (const auto& LcCollision : LcCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(LcCollision, products.productsLc.storedLcCollisionsTable); + products.productsLc.storedLcCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& LcCandidate : LcCandidates) { + jethfutilities::fillHFCandidateTable(LcCandidate, products.productsLc.storedLcCollisionsTable.lastIndex(), products.productsLc.storedLcsTable, products.productsLc.storedLcParsTable, products.productsLc.storedLcParExtrasTable, products.productsLc.storedLcParDaughtersDummyTable, products.productsLc.storedLcSelsTable, products.productsLc.storedLcMlsTable, products.productsLc.storedLcMlDughtersDummyTable, products.productsLc.storedLcMcsTable); + products.productsLc.storedLcIdsTable(collisionMapping[collision.globalIndex()], trackMapping[LcCandidate.prong0Id()], trackMapping[LcCandidate.prong1Id()], trackMapping[LcCandidate.prong2Id()]); + } + } + } + + template + void storeB0(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsB0 const& B0Collisions, T const& B0Candidates) + { + if (collision.isCollisionSelected()) { + for (const auto& B0Collision : B0Collisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(B0Collision, products.productsB0.storedB0CollisionsTable); + products.productsB0.storedB0CollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& B0Candidate : B0Candidates) { + jethfutilities::fillHFCandidateTable(B0Candidate, products.productsB0.storedB0CollisionsTable.lastIndex(), products.productsB0.storedB0sTable, products.productsB0.storedB0ParsTable, products.productsB0.storedB0ParExtrasTable, products.productsB0.storedB0ParDplussTable, products.productsB0.storedB0SelsTable, products.productsB0.storedB0MlsTable, products.productsB0.storedB0MlDplussTable, products.productsB0.storedB0McsTable); + products.productsB0.storedB0IdsTable(collisionMapping[collision.globalIndex()], trackMapping[B0Candidate.prong0Id()], trackMapping[B0Candidate.prong1Id()], trackMapping[B0Candidate.prong2Id()], trackMapping[B0Candidate.prong3Id()]); + } + } + } + + template + void storeBplus(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsBplus const& BplusCollisions, T const& BplusCandidates) + { + if (collision.isCollisionSelected()) { + for (const auto& BplusCollision : BplusCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(BplusCollision, products.productsBplus.storedBplusCollisionsTable); + products.productsBplus.storedBplusCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& BplusCandidate : BplusCandidates) { + jethfutilities::fillHFCandidateTable(BplusCandidate, products.productsBplus.storedBplusCollisionsTable.lastIndex(), products.productsBplus.storedBplussTable, products.productsBplus.storedBplusParsTable, products.productsBplus.storedBplusParExtrasTable, products.productsBplus.storedBplusParD0sTable, products.productsBplus.storedBplusSelsTable, products.productsBplus.storedBplusMlsTable, products.productsBplus.storedBplusMlD0sTable, products.productsBplus.storedBplusMcsTable); + products.productsBplus.storedBplusIdsTable(collisionMapping[collision.globalIndex()], trackMapping[BplusCandidate.prong0Id()], trackMapping[BplusCandidate.prong1Id()], trackMapping[BplusCandidate.prong2Id()]); + } + } + } + + template + void storeXicToXiPiPi(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsXicToXiPiPi const& XicToXiPiPiCollisions, T const& XicToXiPiPiCandidates) + { + if (collision.isCollisionSelected()) { + for (const auto& XicToXiPiPiCollision : XicToXiPiPiCollisions) { // should only ever be one + jethfutilities::fillHFCollisionTable(XicToXiPiPiCollision, products.productsXicToXiPiPi.storedXicToXiPiPiCollisionsTable); + products.productsXicToXiPiPi.storedXicToXiPiPiCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& XicToXiPiPiCandidate : XicToXiPiPiCandidates) { + jethfutilities::fillHFCandidateTable(XicToXiPiPiCandidate, products.productsXicToXiPiPi.storedXicToXiPiPiCollisionsTable.lastIndex(), products.productsXicToXiPiPi.storedXicToXiPiPisTable, products.productsXicToXiPiPi.storedXicToXiPiPiParsTable, products.productsXicToXiPiPi.storedXicToXiPiPiParExtrasTable, products.productsXicToXiPiPi.storedXicToXiPiPiParDaughtersDummyTable, products.productsXicToXiPiPi.storedXicToXiPiPiSelsTable, products.productsXicToXiPiPi.storedXicToXiPiPiMlsTable, products.productsXicToXiPiPi.storedXicToXiPiPiMlDughtersDummyTable, products.productsXicToXiPiPi.storedXicToXiPiPiMcsTable); + products.productsXicToXiPiPi.storedXicToXiPiPiIdsTable(collisionMapping[collision.globalIndex()], trackMapping[XicToXiPiPiCandidate.prong0Id()], trackMapping[XicToXiPiPiCandidate.prong1Id()], trackMapping[XicToXiPiPiCandidate.prong2Id()], trackMapping[XicToXiPiPiCandidate.prong3Id()], trackMapping[XicToXiPiPiCandidate.prong4Id()]); + } + } + } + + 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 dstarMcCollisionMapping; + std::vector lcMcCollisionMapping; + std::vector b0McCollisionMapping; + 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(), bc.rct_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.multFV0A(), collision.multFV0C(), collision.multFT0A(), collision.multFT0C(), collision.centFV0A(), collision.centFV0M(), collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.centFT0CVariant1(), collision.hadronicRate(), collision.trackOccupancyInTimeRange(), collision.alias_raw(), collision.eventSel(), collision.rct_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(preslices.TracksPerCollision, 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(preslices.EMCTrackPerTrack, clusterTrack.globalIndex()); + auto emcTrackPerTrack = emcTracksPerTrack.iteratorAt(0); + products.storedJTracksEMCalTable(trackMapping[clusterTrack.globalIndex()], emcTrackPerTrack.etaEmcal(), emcTrackPerTrack.phiEmcal(), emcTrackPerTrack.etaDiff(), emcTrackPerTrack.phiDiff()); + } + 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& D0Candidates) + { + storeD0(collision, tracks, D0Collisions, D0Candidates); + } + 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& D0Candidates) + { + storeD0(collision, tracks, D0Collisions, D0Candidates); + } + 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& DplusCandidates) + { + storeDplus(collision, tracks, DplusCollisions, DplusCandidates); + } + 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& DplusCandidates) + { + storeDplus(collision, tracks, DplusCollisions, DplusCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processDplusMCD, "write out mcd output tables for Dplus", false); + + void processDsData(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsDs const& DsCollisions, aod::CandidatesDsData const& DsCandidates) + { + storeDs(collision, tracks, DsCollisions, DsCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processDsData, "write out data output tables for Ds", false); + + void processDsMCD(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsDs const& DsCollisions, aod::CandidatesDsMCD const& DsCandidates) + { + storeDs(collision, tracks, DsCollisions, DsCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processDsMCD, "write out mcd output tables for Ds", false); + + void processDstarData(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsDstar const& DstarCollisions, aod::CandidatesDstarData const& DstarCandidates) + { + storeDstar(collision, tracks, DstarCollisions, DstarCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processDstarData, "write out data output tables for Dstar", false); + + void processDstarMCD(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsDstar const& DstarCollisions, aod::CandidatesDstarMCD const& DstarCandidates) + { + storeDstar(collision, tracks, DstarCollisions, DstarCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processDstarMCD, "write out mcd output tables for Dstar", false); + + void processLcData(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsLc const& LcCollisions, aod::CandidatesLcData const& LcCandidates) + { + storeLc(collision, tracks, LcCollisions, LcCandidates); + } + 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& LcCandidates) + { + storeLc(collision, tracks, LcCollisions, LcCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processLcMCD, "write out mcd output tables for Lc", false); + + void processB0Data(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsB0 const& B0Collisions, aod::CandidatesB0Data const& B0Candidates) + { + storeB0(collision, tracks, B0Collisions, B0Candidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processB0Data, "write out data output tables for B0", false); + + void processB0MCD(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsB0 const& B0Collisions, aod::CandidatesB0MCD const& B0Candidates) + { + storeB0(collision, tracks, B0Collisions, B0Candidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processB0MCD, "write out mcd output tables for B0", false); + + void processBplusData(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsBplus const& BplusCollisions, aod::CandidatesBplusData const& BplusCandidates) + { + storeBplus(collision, tracks, BplusCollisions, BplusCandidates); + } + 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& BplusCandidates) + { + storeBplus(collision, tracks, BplusCollisions, BplusCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processBplusMCD, "write out mcd output tables for bplus", false); + + void processXicToXiPiPiData(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsXicToXiPiPi const& XicToXiPiPiCollisions, aod::CandidatesXicToXiPiPiData const& XicToXiPiPiCandidates) + { + storeXicToXiPiPi(collision, tracks, XicToXiPiPiCollisions, XicToXiPiPiCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processXicToXiPiPiData, "write out data output tables for XicToXiPiPi", false); + + void processXicToXiPiPiMCD(soa::Join::iterator const& collision, aod::JTracks const& tracks, aod::CollisionsXicToXiPiPi const& XicToXiPiPiCollisions, aod::CandidatesXicToXiPiPiMCD const& XicToXiPiPiCandidates) + { + storeXicToXiPiPi(collision, tracks, XicToXiPiPiCollisions, XicToXiPiPiCandidates); + } + PROCESS_SWITCH(JetDerivedDataWriter, processXicToXiPiPiMCD, "write out mcd output tables for XicToXiPiPi", false); + + void processDielectron(soa::Join::iterator const& collision, aod::JTracks const&, aod::CollisionsDielectron const& DielectronCollisions, aod::CandidatesDielectronData const& DielectronCandidates) + { + if (collision.isCollisionSelected()) { + for (const auto& DielectronCollision : DielectronCollisions) { // should only ever be one + jetdqutilities::fillDielectronCollisionTable(DielectronCollision, products.productsDielectron.storedDielectronCollisionsTable); + products.productsDielectron.storedDielectronCollisionIdsTable(collisionMapping[collision.globalIndex()]); + } + for (const auto& DielectronCandidate : DielectronCandidates) { + jetdqutilities::fillDielectronCandidateTable(DielectronCandidate, products.productsDielectron.storedDielectronCollisionsTable.lastIndex(), products.productsDielectron.storedDielectronsTable, products.productsDielectron.storedDielectronsAllTable); + products.productsDielectron.storedDielectronIdsTable(collisionMapping[collision.globalIndex()], trackMapping[DielectronCandidate.prong0Id()], trackMapping[DielectronCandidate.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.multFV0A(), mcCollision.multFT0A(), mcCollision.multFT0C(), mcCollision.centFT0M(), mcCollision.weight(), mcCollision.subGeneratorId(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.ptHard()); + 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(preslices.ParticlesPerMcCollision, mcCollision.globalIndex()); + + for (auto particle : particlesPerMcCollision) { + particleMapping[particle.globalIndex()] = particleTableIndex; + particleTableIndex++; + } + for (auto particle : particlesPerMcCollision) { + + std::vector mothersIds; + int daughtersIds[2] = {-1, -1}; + if (config.savePartonLevelInfo) { + if (particle.has_mothers()) { + auto mothersIdTemps = particle.mothersIds(); + for (auto mothersIdTemp : mothersIdTemps) { + mothersIds.push_back(particleMapping[mothersIdTemp]); + } + } + if (particle.has_daughters()) { + auto i = 0; + for (auto daughterId : particle.daughtersIds()) { + if (i > 1) { + break; + } + daughtersIds[i] = particleMapping[daughterId]; + i++; + } + } + } else { + if (!particle.isPhysicalPrimary()) { // add outgoing partons exclusion here later + continue; + } + } + 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.statusCode(), particle.flags(), 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(preslices.D0McCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& d0McCollisionPerMcCollision : d0McCollisionsPerMcCollision) { + jethfutilities::fillHFMcCollisionTable(d0McCollisionPerMcCollision, products.productsD0.storedD0McCollisionsTable); + products.productsD0.storedD0McCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + d0McCollisionMapping[d0McCollisionPerMcCollision.globalIndex()] = products.productsD0.storedD0McCollisionsTable.lastIndex(); + } + const auto d0ParticlesPerMcCollision = D0Particles.sliceBy(preslices.D0ParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& D0Particle : d0ParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(D0Particle, products.productsD0.storedD0McCollisionsTable.lastIndex(), products.productsD0.storedD0ParticlesTable); + products.productsD0.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(preslices.DplusMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& dplusMcCollisionPerMcCollision : dplusMcCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(dplusMcCollisionPerMcCollision, products.productsDplus.storedDplusMcCollisionsTable); + products.productsDplus.storedDplusMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + dplusMcCollisionMapping[dplusMcCollisionPerMcCollision.globalIndex()] = products.productsDplus.storedDplusMcCollisionsTable.lastIndex(); + } + const auto dplusParticlesPerMcCollision = DplusParticles.sliceBy(preslices.DplusParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& DplusParticle : dplusParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(DplusParticle, products.productsDplus.storedDplusMcCollisionsTable.lastIndex(), products.productsDplus.storedDplusParticlesTable); + products.productsDplus.storedDplusParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[DplusParticle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDplusMCP, "write out Dplus mcp output tables", false); + + void processDsMCP(soa::Join const& mcCollisions, aod::McCollisionsDs const& DsMcCollisions, aod::CandidatesDsMCP const& DsParticles) + { + dplusMcCollisionMapping.clear(); + dplusMcCollisionMapping.resize(DsMcCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + const auto dplusMcCollisionsPerMcCollision = DsMcCollisions.sliceBy(preslices.DsMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& dplusMcCollisionPerMcCollision : dplusMcCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(dplusMcCollisionPerMcCollision, products.productsDs.storedDsMcCollisionsTable); + products.productsDs.storedDsMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + dplusMcCollisionMapping[dplusMcCollisionPerMcCollision.globalIndex()] = products.productsDs.storedDsMcCollisionsTable.lastIndex(); + } + const auto dplusParticlesPerMcCollision = DsParticles.sliceBy(preslices.DsParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& DsParticle : dplusParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(DsParticle, products.productsDs.storedDsMcCollisionsTable.lastIndex(), products.productsDs.storedDsParticlesTable); + products.productsDs.storedDsParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[DsParticle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDsMCP, "write out Ds mcp output tables", false); + + void processDstarMCP(soa::Join const& mcCollisions, aod::McCollisionsDstar const& DstarMcCollisions, aod::CandidatesDstarMCP const& DstarParticles) + { + dstarMcCollisionMapping.clear(); + dstarMcCollisionMapping.resize(DstarMcCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + const auto dstarMcCollisionsPerMcCollision = DstarMcCollisions.sliceBy(preslices.DstarMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& dstarMcCollisionPerMcCollision : dstarMcCollisionsPerMcCollision) { + jethfutilities::fillHFMcCollisionTable(dstarMcCollisionPerMcCollision, products.productsDstar.storedDstarMcCollisionsTable); + products.productsDstar.storedDstarMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + dstarMcCollisionMapping[dstarMcCollisionPerMcCollision.globalIndex()] = products.productsDstar.storedDstarMcCollisionsTable.lastIndex(); + } + const auto dstarParticlesPerMcCollision = DstarParticles.sliceBy(preslices.DstarParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& DstarParticle : dstarParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(DstarParticle, products.productsDstar.storedDstarMcCollisionsTable.lastIndex(), products.productsDstar.storedDstarParticlesTable); + products.productsDstar.storedDstarParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[DstarParticle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDstarMCP, "write out D* 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(preslices.LcMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& lcMcCollisionPerMcCollision : lcMcCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(lcMcCollisionPerMcCollision, products.productsLc.storedLcMcCollisionsTable); + products.productsLc.storedLcMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + lcMcCollisionMapping[lcMcCollisionPerMcCollision.globalIndex()] = products.productsLc.storedLcMcCollisionsTable.lastIndex(); + } + const auto lcParticlesPerMcCollision = LcParticles.sliceBy(preslices.LcParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& LcParticle : lcParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(LcParticle, products.productsLc.storedLcMcCollisionsTable.lastIndex(), products.productsLc.storedLcParticlesTable); + products.productsLc.storedLcParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[LcParticle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processLcMCP, "write out Lc mcp output tables", false); + + void processB0MCP(soa::Join const& mcCollisions, aod::McCollisionsB0 const& B0McCollisions, aod::CandidatesB0MCP const& B0Particles) + { + b0McCollisionMapping.clear(); + b0McCollisionMapping.resize(B0McCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + const auto b0McCollisionsPerMcCollision = B0McCollisions.sliceBy(preslices.B0McCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& b0McCollisionPerMcCollision : b0McCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(b0McCollisionPerMcCollision, products.productsB0.storedB0McCollisionsTable); + products.productsB0.storedB0McCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + b0McCollisionMapping[b0McCollisionPerMcCollision.globalIndex()] = products.productsB0.storedB0McCollisionsTable.lastIndex(); + } + const auto b0ParticlesPerMcCollision = B0Particles.sliceBy(preslices.B0ParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& B0Particle : b0ParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(B0Particle, products.productsB0.storedB0McCollisionsTable.lastIndex(), products.productsB0.storedB0ParticlesTable); + products.productsB0.storedB0ParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[B0Particle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processB0MCP, "write out B0 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(preslices.BplusMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& bplusMcCollisionPerMcCollision : bplusMcCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(bplusMcCollisionPerMcCollision, products.productsBplus.storedBplusMcCollisionsTable); + products.productsBplus.storedBplusMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + bplusMcCollisionMapping[bplusMcCollisionPerMcCollision.globalIndex()] = products.productsBplus.storedBplusMcCollisionsTable.lastIndex(); + } + const auto bplusParticlesPerMcCollision = BplusParticles.sliceBy(preslices.BplusParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& BplusParticle : bplusParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(BplusParticle, products.productsBplus.storedBplusMcCollisionsTable.lastIndex(), products.productsBplus.storedBplusParticlesTable); + products.productsBplus.storedBplusParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[BplusParticle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processBplusMCP, "write out Bplus mcp output tables", false); + + void processXicToXiPiPiMCP(soa::Join const& mcCollisions, aod::McCollisionsXicToXiPiPi const& XicToXiPiPiMcCollisions, aod::CandidatesXicToXiPiPiMCP const& XicToXiPiPiParticles) + { + dplusMcCollisionMapping.clear(); + dplusMcCollisionMapping.resize(XicToXiPiPiMcCollisions.size(), -1); + for (auto const& mcCollision : mcCollisions) { + if (mcCollision.isMcCollisionSelected()) { + const auto dplusMcCollisionsPerMcCollision = XicToXiPiPiMcCollisions.sliceBy(preslices.XicToXiPiPiMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& dplusMcCollisionPerMcCollision : dplusMcCollisionsPerMcCollision) { // should only ever be one + jethfutilities::fillHFMcCollisionTable(dplusMcCollisionPerMcCollision, products.productsXicToXiPiPi.storedXicToXiPiPiMcCollisionsTable); + products.productsXicToXiPiPi.storedXicToXiPiPiMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + dplusMcCollisionMapping[dplusMcCollisionPerMcCollision.globalIndex()] = products.productsXicToXiPiPi.storedXicToXiPiPiMcCollisionsTable.lastIndex(); + } + const auto dplusParticlesPerMcCollision = XicToXiPiPiParticles.sliceBy(preslices.XicToXiPiPiParticlesPerMcCollision, mcCollision.globalIndex()); + for (const auto& XicToXiPiPiParticle : dplusParticlesPerMcCollision) { + jethfutilities::fillHFCandidateMcTable(XicToXiPiPiParticle, products.productsXicToXiPiPi.storedXicToXiPiPiMcCollisionsTable.lastIndex(), products.productsXicToXiPiPi.storedXicToXiPiPiParticlesTable); + products.productsXicToXiPiPi.storedXicToXiPiPiParticleIdsTable(mcCollisionMapping[mcCollision.globalIndex()], particleMapping[XicToXiPiPiParticle.mcParticleId()]); + } + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processXicToXiPiPiMCP, "write out XicToXiPiPi 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(preslices.DielectronMcCollisionsPerMcCollision, mcCollision.globalIndex()); + for (const auto& dielectronMcCollisionPerMcCollision : dielectronMcCollisionsPerMcCollision) { // should only ever be one + jetdqutilities::fillDielectronMcCollisionTable(dielectronMcCollisionPerMcCollision, products.productsDielectron.storedDielectronMcCollisionsTable); + products.productsDielectron.storedDielectronMcCollisionIdsTable(mcCollisionMapping[mcCollision.globalIndex()]); + products.productsDielectron.storedDielectronMcRCollDummysTable(dielectronMcCollisionPerMcCollision.dummyDQ()); + } + for (const auto& DielectronParticle : DielectronParticles) { + jetdqutilities::fillDielectronCandidateMcTable(DielectronParticle, products.productsDielectron.storedDielectronMcCollisionsTable.lastIndex(), products.productsDielectron.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()]); + } + } + if (DielectronParticle.has_daughters()) { + auto i = 0; + for (auto const& DielectronDaughter : DielectronParticle.template daughters_as()) { + if (i > 1) { + break; + } + DielectronDaughtersId[i] = particleMapping[DielectronDaughter.globalIndex()]; + i++; + } + } + products.productsDielectron.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, aod::JMcParticles const&) + { + if (collision.isCollisionSelected()) { + for (const auto& track : tracks) { + if (!trackSelection(track)) { + continue; + } + if (track.has_mcParticle() && (config.savePartonLevelInfo || track.mcParticle().isPhysicalPrimary())) { + 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, aod::JMcParticles const& particles) + { + if (collision.isCollisionSelected()) { + for (const auto& cluster : clusters) { + std::vector clusterStoredJParticleIDs; + for (const auto& clusterParticleId : cluster.mcParticlesIds()) { + if (!config.savePartonLevelInfo) { + const auto& particle = particles.iteratorAt(clusterParticleId); + if (!particle.isPhysicalPrimary()) { + continue; + } + } + 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.productsD0.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.productsDplus.storedDplusMcCollisionsMatchingTable(dplusCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDplusMcCollisionMatch, "write out Dplus McCollision collision label output tables", false); + + void processDsMcCollisionMatch(soa::Join::iterator const& mcCollision, soa::Join const& DsMcCollisions, aod::CollisionsDs const&) + { + if (mcCollision.isMcCollisionSelected()) { + for (const auto& DsMcCollision : DsMcCollisions) { // should just be one + std::vector dplusCollisionIDs; + for (auto const& dplusCollisionPerMcCollision : DsMcCollision.hfCollBases_as()) { + dplusCollisionIDs.push_back(dplusMcCollisionMapping[dplusCollisionPerMcCollision.globalIndex()]); + } + products.productsDs.storedDsMcCollisionsMatchingTable(dplusCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDsMcCollisionMatch, "write out Ds McCollision collision label output tables", false); + + void processDstarMcCollisionMatch(soa::Join::iterator const& mcCollision, soa::Join const& DstarMcCollisions, aod::CollisionsDstar const&) + { + if (mcCollision.isMcCollisionSelected()) { + for (const auto& DstarMcCollision : DstarMcCollisions) { // should just be one + std::vector dstarCollisionIDs; + for (auto const& dstarCollisionPerMcCollision : DstarMcCollision.hfCollBases_as()) { + dstarCollisionIDs.push_back(dstarMcCollisionMapping[dstarCollisionPerMcCollision.globalIndex()]); + } + products.productsDstar.storedDstarMcCollisionsMatchingTable(dstarCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processDstarMcCollisionMatch, "write out D* 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.productsLc.storedLcMcCollisionsMatchingTable(lcCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processLcMcCollisionMatch, "write out Lc McCollision collision label output tables", false); + + void processB0McCollisionMatch(soa::Join::iterator const& mcCollision, soa::Join const& B0McCollisions, aod::CollisionsB0 const&) + { + if (mcCollision.isMcCollisionSelected()) { + for (const auto& B0McCollision : B0McCollisions) { // should just be one + std::vector b0CollisionIDs; + for (auto const& b0CollisionPerMcCollision : B0McCollision.hfCollBases_as()) { + b0CollisionIDs.push_back(b0McCollisionMapping[b0CollisionPerMcCollision.globalIndex()]); + } + products.productsB0.storedB0McCollisionsMatchingTable(b0CollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processB0McCollisionMatch, "write out B0 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.productsBplus.storedBplusMcCollisionsMatchingTable(bplusCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processBplusMcCollisionMatch, "write out Bplus McCollision collision label output tables", false); + + void processXicToXiPiPiMcCollisionMatch(soa::Join::iterator const& mcCollision, soa::Join const& XicToXiPiPiMcCollisions, aod::CollisionsXicToXiPiPi const&) + { + if (mcCollision.isMcCollisionSelected()) { + for (const auto& XicToXiPiPiMcCollision : XicToXiPiPiMcCollisions) { // should just be one + std::vector dplusCollisionIDs; + for (auto const& dplusCollisionPerMcCollision : XicToXiPiPiMcCollision.hfCollBases_as()) { + dplusCollisionIDs.push_back(dplusMcCollisionMapping[dplusCollisionPerMcCollision.globalIndex()]); + } + products.productsXicToXiPiPi.storedXicToXiPiPiMcCollisionsMatchingTable(dplusCollisionIDs); + } + } + } + PROCESS_SWITCH(JetDerivedDataWriter, processXicToXiPiPiMcCollisionMatch, "write out XicToXiPiPi 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..588030e132c --- /dev/null +++ b/PWGJE/TableProducer/emcalClusterHadronicCorrectionTask.cxx @@ -0,0 +1,291 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/DataModel/EMCALClusterDefinition.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include + +#include "TVector2.h" +#include + +#include +#include +#include + +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, {{1500, -600., 900.}}}); + 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 = std::abs(matchedTrack.p()); + registry.fill(HIST("h_matchedtracks"), 1); + + // CASE 1: skip tracks with a very low pT + constexpr double kMinMom = 1e-6; + if (mom < kMinMom) { + 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.etaDiff(); + double dPhi = emcTrack.phiDiff(); + + // 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) && std::fabs(dEta) < trackEtaMax) { + if (nMatches == 0) { + closestTrkP = mom; + } + totalTrkP += mom; + nMatches++; + } + } else { + // Do fixed dEta/dPhi matching (non-pT dependent) + if (std::fabs(dEta) >= minDEta || std::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..9a274427955 100644 --- a/PWGJE/TableProducer/emcalCorrectionTask.cxx +++ b/PWGJE/TableProducer/emcalCorrectionTask.cxx @@ -8,79 +8,118 @@ // In applying this license CERN does 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 - -#include -#include -#include -#include -#include - -#include "CCDB/BasicCCDBManager.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" - -#include "DetectorsBase/GeometryManager.h" - +/// +/// 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), Marvin Hemmer (marvin.hemmer@cern.ch) + +#include "PWGJE/Core/emcalCrossTalkEmulation.h" +#include "PWGJE/Core/utilsTrackMatchingEMC.h" +#include "PWGJE/DataModel/EMCALClusterDefinition.h" #include "PWGJE/DataModel/EMCALClusters.h" #include "PWGJE/DataModel/EMCALMatchedCollisions.h" +// +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" // for EM V0 legs +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "DataFormatsEMCAL/Cell.h" -#include "DataFormatsEMCAL/CellLabel.h" -#include "DataFormatsEMCAL/Constants.h" -#include "DataFormatsEMCAL/AnalysisCluster.h" -#include "EMCALBase/Geometry.h" -#include "EMCALBase/ClusterFactory.h" -#include "EMCALBase/NonlinearityHandler.h" -#include "EMCALReconstruction/Clusterizer.h" -#include "PWGJE/Core/JetUtilities.h" -#include "TVector2.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; -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 namespace o2::emccrosstalk; +using namespace tmemcutilities; +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 EMV0Legs = aod::V0Legs; + +enum CellScaleMode { + ModeNone = 0, + ModeSMWise = 1, + ModeColumnWise = 2, + NumberModes = 3 +}; struct EmcalCorrectionTask { Produces clusters; Produces mcclusters; Produces clustersAmbiguous; + Produces mcclustersAmbiguous; Produces clustercells; // cells belonging to given cluster Produces clustercellsambiguous; Produces matchedTracks; + Produces matchedSecondaries; 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; + PresliceUnsorted perCollisionEMV0Legs = aod::v0leg::collisionId; // 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 +127,22 @@ 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."}; + Configurable fillQA{"fillQA", false, "Switch to turn on QA histograms."}; + Configurable useCCDBAlignment{"useCCDBAlignment", false, "EXPERTS ONLY! Switch to use the alignment object stored in CCDB instead of using the default alignment from the global geometry object."}; + Configurable applyTempCalib{"applyTempCalib", false, "Switch to turn on Temperature calibration."}; + Configurable pathTempCalibCCDB{"pathTempCalibCCDB", "Users/j/jokonig/EMCalTempCalibParams", "Path in the ccdb where slope and intercept for each cell are stored"}; // change to official path as soon as it is available + Configurable useTempCalibMean{"useTempCalibMean", false, "Switch to turn on Temperature mean calculation instead of median."}; + Configurable mcCellEnergyShift{"mcCellEnergyShift", 1., "Relative shift of the MC cell energy. 1.1 for 10% shift to higher mass, etc. Only applied to MC."}; + Configurable mcCellEnergyResolutionBroadening{"mcCellEnergyResolutionBroadening", 0., "Relative widening of the MC cell energy resolution. 0 for no widening, 0.1 for 10% widening, etc. Only applied to MC."}; + Configurable applyGainCalibShift{"applyGainCalibShift", false, "Apply shift for cell gain calibration to use values before cell format change (Sept. 2023)"}; + + // cross talk emulation configs + EmcCrossTalkConf emcCrossTalkConf; + + // cross talk emulation class for handling the cross talk + emccrosstalk::EMCCrossTalk emcCrossTalk; // Require EMCAL cells (CALO type 1) Filter emccellfilter = aod::calo::caloType == selectedCellType; @@ -105,10 +160,37 @@ struct EmcalCorrectionTask { std::vector mAnalysisClusters; std::vector mClusterLabels; + // Cluster Eta and Phi used for track matching later + std::vector mClusterPhi; + std::vector mClusterEta; + std::vector mClusterDefinitions; // 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; + + // EMCal cell temperature calibrator + std::unique_ptr mTempCalibExtractor; + bool mIsTempCalibInitialized = false; + + // Gain calibration + std::array mArrGainCalibDiff; + + std::vector> mExtraTimeShiftRunRanges; + + // Current run number + int runNumber{0}; + + static constexpr float TrackNotOnEMCal = -900.f; + static constexpr int kMaxMatchesPerCluster = 20; // Maximum number of tracks to match per cluster + void init(InitContext const&) { LOG(debug) << "Start init!"; @@ -125,10 +207,22 @@ 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"; } + if (useCCDBAlignment.value) { + geometry->SetMisalMatrixFromCcdb(); + } + + if (applyTempCalib) { + mTempCalibExtractor = std::make_unique(); + } + + // gain calibration shift initialization + if (applyGainCalibShift) { + initializeGainCalibShift(); + } // read all the cluster definitions specified in the options if (clusterDefinitions->length()) { @@ -147,17 +241,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); } @@ -165,40 +260,77 @@ struct EmcalCorrectionTask { LOG(error) << "No cluster definitions specified!"; } + // 500 clusters per event is a good upper limit + mClusterPhi.reserve(500 * mClusterizers.size()); + mClusterEta.reserve(500 * mClusterizers.size()); + mNonlinearityHandler = o2::emcal::NonlinearityFactory::getInstance().getNonlinearity(static_cast(nonlinearityFunction)); LOG(info) << "Using nonlinearity parameterisation: " << nonlinearityFunction.value; LOG(info) << "Apply shaper saturation correction: " << (hasShaperCorrection.value ? "yes" : "no"); LOG(debug) << "Completed init!"; + // Define the cell energy binning + std::vector cellEnergyBins; + for (int i = 0; i < 51; i++) { // o2-linter: disable=magic-number (just numbers for binning) + 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++) { // o2-linter: disable=magic-number (just numbers for binning) + 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++) { // o2-linter: disable=magic-number (just numbers for binning) + 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)"}, - 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}); + using O2HistType = o2::framework::HistType; + o2::framework::AxisSpec energyAxis{200, 0., 100., "#it{E} (GeV)"}, + timeAxis{300, -100, 200., "#it{t} (ns)"}, + etaAxis{160, -0.8, 0.8, "#it{#eta}"}, + phiAxis{72, 0, 2 * 3.14159, "#it{#varphi} (rad)"}, + nlmAxis{50, -0.5, 49.5, "NLM"}, + fCrossAxis{100, 0., 1., "F_{+}"}, + sigmaLongAxis{100, 0., 1.0, "#sigma^{2}_{long}"}, + sigmaShortAxis{100, 0., 1.0, "#sigma^{2}_{short}"}, + nCellAxis{60, -0.5, 59.5, "#it{n}_{cells}"}, + energyDenseAxis = {7000, 0.f, 70.f, "#it{E}_{cell} (GeV)"}; + o2::framework::AxisSpec axisDeltaEta{400, -0.2, 0.2, "#Delta#eta"}; + o2::framework::AxisSpec axisDeltaPhi{400, -0.2, 0.2, "#Delta#varphi (rad)"}; + o2::framework::AxisSpec axisNCluster{1000, 0, 1000, "#it{N}_{clus.}"}; + mHistManager.add("hCellE", "hCellE", O2HistType::kTH1D, {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) + mHistManager.add("hTempCalibCorrection", "hTempCalibCorrection", O2HistType::kTH1F, {{5000, 0.5, 1.5}}); // 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::kTH1D, {energyAxis}); + mHistManager.add("hNCluster", "hNCluster", O2HistType::kTH1D, {axisNCluster}); + mHistManager.add("hClusterNLM", "hClusterNLM", O2HistType::kTH1D, {nlmAxis}); + mHistManager.add("hClusterEtaPhi", "hClusterEtaPhi", O2HistType::kTH2F, {etaAxis, phiAxis}); + mHistManager.add("hClusterTime", "hClusterTime", O2HistType::kTH1D, {timeAxis}); + mHistManager.add("hCollisionType", "hCollisionType;;#it{count}", O2HistType::kTH1D, {{3, -0.5, 2.5}}); + mHistManager.add("hMatchedPrimaryTracks", "hMatchedPrimaryTracks", O2HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}); + mHistManager.add("hMatchedSecondaries", "hMatchedSecondaries", O2HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}); 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"); @@ -208,10 +340,34 @@ struct EmcalCorrectionTask { hBC->GetXaxis()->SetBinLabel(6, "no EMCal cells and with collision"); 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}); + if (isMC.value) { + mHistManager.add("hContributors", "hContributors;contributor per cell hit;#it{counts}", O2HistType::kTH1D, {{20, 0, 20}}); + mHistManager.add("hMCParticleEnergy", "hMCParticleEnergy;#it{E} (GeV/#it{c});#it{counts}", O2HistType::kTH1D, {energyAxis}); + } + if (fillQA.value) { + mHistManager.add("hClusterNCellE", "hClusterNCellE", O2HistType::kTH2D, {energyAxis, nCellAxis}); + mHistManager.add("hClusterFCrossE", "hClusterFCrossE", O2HistType::kTH2D, {energyAxis, fCrossAxis}); + mHistManager.add("hClusterFCrossSigmaLongE", "hClusterFCrossSigmaLongE", O2HistType::kTH3F, {energyAxis, fCrossAxis, sigmaLongAxis}); + mHistManager.add("hClusterFCrossSigmaShortE", "hClusterFCrossSigmaShortE", O2HistType::kTH3F, {energyAxis, fCrossAxis, sigmaShortAxis}); + } + + if (isMC.value && emcCrossTalkConf.enableCrossTalk.value) { + emcCrossTalk.initObjects(emcCrossTalkConf); + if (emcCrossTalkConf.createHistograms.value) { + mHistManager.add("hCellEnergyDistBefore", "Cell energy before cross-talk emulation", {o2::framework::HistType::kTH1D, {energyDenseAxis}}); + mHistManager.add("hCellEnergyDistAfter", "Cell energy after cross-talk emulation", {o2::framework::HistType::kTH1D, {energyDenseAxis}}); + } } + + // For some runs, LG cells require an extra time shift of 2 * 8.8ns due to problems in the time calibration + // Affected run ranges (inclusive) are initialised here (min,max) + mExtraTimeShiftRunRanges.emplace_back(535365, 535645); // LHC23g-LHC23h + mExtraTimeShiftRunRanges.emplace_back(535725, 536126); // LHC23h-LHC23l + mExtraTimeShiftRunRanges.emplace_back(536199, 536202); // LHC23l-LHC23m + mExtraTimeShiftRunRanges.emplace_back(536239, 536346); // LHC23m-LHC23n + mExtraTimeShiftRunRanges.emplace_back(536565, 536590); // Commisioning-LHC23r + mExtraTimeShiftRunRanges.emplace_back(542280, 543854); // LHC23zv-LHC23zy + mExtraTimeShiftRunRanges.emplace_back(559544, 559856); // PbPb 2024 } // void process(aod::Collision const& collision, soa::Filtered const& fullTracks, aod::Calos const& cells) @@ -219,16 +375,26 @@ 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"; + + // get run number + runNumber = bc.runNumber(); + + if (applyTempCalib && !mIsTempCalibInitialized) { // needs to be called once + mTempCalibExtractor->InitializeFromCCDB(pathTempCalibCCDB, static_cast(runNumber)); + mIsTempCalibInitialized = true; + } + // 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 +414,25 @@ 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()); + } + if (applyGainCalibShift) { + amplitude *= mArrGainCalibDiff[cell.cellNumber()]; + } + if (applyTempCalib) { + float tempCalibFactor = mTempCalibExtractor->getGainCalibFactor(static_cast(cell.cellNumber())); + amplitude /= tempCalibFactor; + mHistManager.fill(HIST("hTempCalibCorrection"), tempCalibFactor); } cellsBC.emplace_back(cell.cellNumber(), amplitude, - cell.time(), + cell.time() + getCellTimeShift(cell.cellNumber(), amplitude, o2::emcal::intToChannelType(cell.cellType()), runNumber), o2::emcal::intToChannelType(cell.cellType())); cellIndicesBC.emplace_back(cell.globalIndex()); } @@ -267,12 +441,6 @@ struct EmcalCorrectionTask { fillQAHistogram(cellsBC); - // TODO: Helpful for now, but should be removed. - LOG(debug) << "Converted EMCAL cells"; - for (auto& cell : cellsBC) { - LOG(debug) << cell.getTower() << ": E: " << cell.getEnergy() << ", time: " << cell.getTimeStamp() << ", type: " << cell.getType(); - } - LOG(debug) << "Converted cells. Contains: " << cellsBC.size() << ". Originally " << cellsInBC.size() << ". About to run clusterizer."; // this is a test // Run the clusterizers @@ -283,20 +451,27 @@ 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}; + MatchResult indexMapPair; std::vector trackGlobalIndex; - doTrackMatching(col, tracks, IndexMapPair, vertex_pos, trackGlobalIndex); + doTrackMatching(col, tracks, indexMapPair, 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,9 +484,11 @@ struct EmcalCorrectionTask { hasCollision = true; mHistManager.fill(HIST("hCollisionType"), 2); } - FillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); + fillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); } + mClusterPhi.clear(); + mClusterEta.clear(); LOG(debug) << "Cluster loop done for clusterizer " << iClusterizer; } // end of clusterizer loop LOG(debug) << "Done with process BC."; @@ -320,7 +497,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,19 +511,163 @@ 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 processWithSecondaries(BcEvSels const& bcs, CollEventSels const& collisions, MyGlobTracks const& tracks, FilteredCells const& cells, EMV0Legs const& v0legs) { 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 (const auto& bc : bcs) { + LOG(debug) << "Next BC"; + + // get run number + runNumber = bc.runNumber(); + + if (applyTempCalib && !mIsTempCalibInitialized) { // needs to be called once + mTempCalibExtractor->InitializeFromCCDB(pathTempCalibCCDB, static_cast(runNumber)); + mIsTempCalibInitialized = true; + } + + // Convert aod::Calo to o2::emcal::Cell which can be used with the clusterizer. + // In particular, we need to filter only EMCAL cells. + + // Get the collisions matched to the BC using foundBCId of the collision + auto collisionsInFoundBC = collisions.sliceBy(collisionsPerFoundBC, bc.globalIndex()); + auto cellsInBC = cells.sliceBy(cellsPerFoundBC, bc.globalIndex()); + + numberCollsInBC.insert(std::pair(bc.globalIndex(), collisionsInFoundBC.size())); + numberCellsInBC.insert(std::pair(bc.globalIndex(), cellsInBC.size())); + + if (!cellsInBC.size()) { + LOG(debug) << "No cells found for BC"; + countBC(collisionsInFoundBC.size(), false); + continue; + } + // Counters for BCs with matched collisions + countBC(collisionsInFoundBC.size(), true); + std::vector cellsBC; + std::vector cellIndicesBC; + for (const auto& cell : cellsInBC) { + auto amplitude = cell.amplitude(); + 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()); + } + if (applyGainCalibShift) { + amplitude *= mArrGainCalibDiff[cell.cellNumber()]; + } + if (applyTempCalib) { + float tempCalibFactor = mTempCalibExtractor->getGainCalibFactor(static_cast(cell.cellNumber())); + amplitude /= tempCalibFactor; + mHistManager.fill(HIST("hTempCalibCorrection"), tempCalibFactor); + } + cellsBC.emplace_back(cell.cellNumber(), + amplitude, + cell.time() + getCellTimeShift(cell.cellNumber(), amplitude, o2::emcal::intToChannelType(cell.cellType()), runNumber), + o2::emcal::intToChannelType(cell.cellType())); + cellIndicesBC.emplace_back(cell.globalIndex()); + } + LOG(detail) << "Number of cells for BC (CF): " << cellsBC.size(); + nCellsProcessed += cellsBC.size(); + + fillQAHistogram(cellsBC); + + LOG(debug) << "Converted cells. Contains: " << cellsBC.size() << ". Originally " << cellsInBC.size() << ". About to run clusterizer."; + // this is a test + // Run the clusterizers + LOG(debug) << "Running clusterizers"; + for (size_t iClusterizer = 0; iClusterizer < mClusterizers.size(); iClusterizer++) { + cellsToCluster(iClusterizer, cellsBC); + + 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 vertexPos = {col.posX(), col.posY(), col.posZ()}; + + MatchResult indexMapPair; + std::vector trackGlobalIndex; + doTrackMatching(col, tracks, indexMapPair, trackGlobalIndex); + + MatchResult indexMapPairSecondary; + std::vector secondaryGlobalIndex; + doSecondaryTrackMatching(col, v0legs, indexMapPairSecondary, secondaryGlobalIndex, tracks); + + // Store the clusters in the table where a matching collision could + // be identified. + fillClusterTable(col, vertexPos, iClusterizer, cellIndicesBC, &indexMapPair, &trackGlobalIndex, &indexMapPairSecondary, &secondaryGlobalIndex); + } else { + mHistManager.fill(HIST("hBCMatchErrors"), 2); + } + } + } else { // ambiguous + // LOG(warning) << "No vertex found for event. Assuming (0,0,0)."; + bool hasCollision = false; + mHistManager.fill(HIST("hCollPerBC"), collisionsInFoundBC.size()); + if (collisionsInFoundBC.size() == 0) { + mHistManager.fill(HIST("hCollisionType"), 0); + } else { + hasCollision = true; + mHistManager.fill(HIST("hCollisionType"), 2); + } + fillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); + } + + mClusterPhi.clear(); + mClusterEta.clear(); + LOG(debug) << "Cluster loop done for clusterizer " << iClusterizer; + } // end of clusterizer loop + LOG(debug) << "Done with process BC."; + nBCsProcessed++; + } // end of bc loop + + // 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 foundColls = numberCollsInBC.find(globalbcid); + auto foundCells = numberCellsInBC.find(globalbcid); + if (foundColls != numberCollsInBC.end() && foundCells != numberCellsInBC.end()) { + emcalcollisionmatch(collision.globalIndex(), foundColls->second != 1, foundCells->second > 0); + } else { + LOG(warning) << "BC not found in map of number of collisions."; + } + } // end of collision loop + + LOG(detail) << "Processed " << nBCsProcessed << " BCs with " << nCellsProcessed << " cells"; + } + PROCESS_SWITCH(EmcalCorrectionTask, processWithSecondaries, "run full analysis with secondary track matching", false); + + void processMCFull(BcEvSels const& bcs, CollEventSels const& collisions, MyGlobTracks const& tracks, FilteredMcCells const& cells, aod::StoredMcParticles_001 const&) + { + LOG(debug) << "Starting processMCFull."; + + 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. + // get run number + runNumber = bc.runNumber(); + // Get the collisions matched to the BC using foundBCId of the collision auto collisionsInFoundBC = collisions.sliceBy(collisionsPerFoundBC, bc.globalIndex()); auto cellsInBC = cells.sliceBy(mcCellsPerFoundBC, bc.globalIndex()); @@ -364,33 +685,239 @@ 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) { + const auto& ids = cell.mcParticleIds(); + const auto& amps = cell.amplitudeA(); + + if (ids.empty() || amps.empty()) { + LOGF(warning, "Skipping cell with empty MC info: absId=%d", cell.cellNumber()); + continue; + } 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); } + if (mcCellEnergyShift != 1.) { + amplitude *= mcCellEnergyShift; // Fine tune the MC cell energy + } + if (mcCellEnergyResolutionBroadening != 0.) { + amplitude *= (1. + normalgaus(rdgen) * mcCellEnergyResolutionBroadening); // Fine tune the MC cell energy resolution + } cellsBC.emplace_back(cell.cellNumber(), amplitude, - cell.time(), + cell.time() + getCellTimeShift(cell.cellNumber(), amplitude, o2::emcal::intToChannelType(cell.cellType()), runNumber), o2::emcal::intToChannelType(cell.cellType())); cellIndicesBC.emplace_back(cell.globalIndex()); - cellLabels.emplace_back(cell.mcParticleIds(), cell.amplitudeA()); + cellLabels.emplace_back(std::vector{cell.mcParticleIds().begin(), cell.mcParticleIds().end()}, std::vector{cell.amplitudeA().begin(), cell.amplitudeA().end()}); + } + if (isMC.value && emcCrossTalkConf.enableCrossTalk.value) { + if (emcCrossTalkConf.createHistograms.value) { + for (const auto& cell : cellsBC) { + mHistManager.fill(HIST("hCellEnergyDistBefore"), cell.getAmplitude()); + } + } + emcCrossTalk.setCells(cellsBC, cellLabels); + bool isOkCrossTalk = emcCrossTalk.run(); + if (!isOkCrossTalk) { + LOG(info) << "Cross talk emulation failed!"; + } else { + // When we get new cells we also need to add additional entries into cellIndicesBC. + // Adding -1 and later when filling the clusterID<->cellID table skip all cases where this is -1 + if (cellIndicesBC.size() < cellsBC.size()) { + cellIndicesBC.reserve(cellsBC.size()); + size_t nMissing = cellsBC.size() - cellIndicesBC.size(); + cellIndicesBC.insert(cellIndicesBC.end(), nMissing, -1); + } + if (emcCrossTalkConf.createHistograms.value) { + for (const auto& cell : cellsBC) { + mHistManager.fill(HIST("hCellEnergyDistAfter"), cell.getAmplitude()); + } + } + } // cross talk emulation was okay + } // if (isMC.value && emcCrossTalkConf.enableCrossTalk.value) + // shaper correction has to come AFTER cross talk + for (auto& cell : cellsBC) { // o2-linter: disable=const-ref-in-for-loop (we are changing a value here) + if (cell.getLowGain()) { + cell.setAmplitude(o2::emcal::NonlinearityHandler::evaluateShaperCorrectionCellEnergy(cell.getAmplitude())); + } } LOG(detail) << "Number of cells for BC (CF): " << cellsBC.size(); nCellsProcessed += cellsBC.size(); fillQAHistogram(cellsBC); - // TODO: Helpful for now, but should be removed. - LOG(debug) << "Converted EMCAL cells"; - for (auto& cell : cellsBC) { - LOG(debug) << cell.getTower() << ": E: " << cell.getEnergy() << ", time: " << cell.getTimeStamp() << ", type: " << cell.getType(); + LOG(debug) << "Converted cells. Contains: " << cellsBC.size() << ". Originally " << cellsInBC.size() << ". About to run clusterizer."; + // this is a test + // Run the clusterizers + LOG(debug) << "Running clusterizers"; + for (size_t iClusterizer = 0; iClusterizer < mClusterizers.size(); iClusterizer++) { + cellsToCluster(iClusterizer, cellsBC, cellLabels); + + 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 vertexPos = {col.posX(), col.posY(), col.posZ()}; + + MatchResult indexMapPair; + std::vector trackGlobalIndex; + doTrackMatching(col, tracks, indexMapPair, trackGlobalIndex); + + // Store the clusters in the table where a matching collision could + // be identified. + fillClusterTable(col, vertexPos, iClusterizer, cellIndicesBC, &indexMapPair, &trackGlobalIndex); + } else { + mHistManager.fill(HIST("hBCMatchErrors"), 2); + } + } + } else { // ambiguous + // LOG(warning) << "No vertex found for event. Assuming (0,0,0)."; + bool hasCollision = false; + mHistManager.fill(HIST("hCollPerBC"), collisionsInFoundBC.size()); + if (collisionsInFoundBC.size() == 0) { + mHistManager.fill(HIST("hCollisionType"), 0); + } else { + hasCollision = true; + mHistManager.fill(HIST("hCollisionType"), 2); + } + fillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); + } + mClusterPhi.clear(); + mClusterEta.clear(); + LOG(debug) << "Cluster loop done for clusterizer " << iClusterizer; + } // end of clusterizer loop + LOG(debug) << "Done with process BC."; + nBCsProcessed++; + } // end of bc loop + + // 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 foundColls = numberCollsInBC.find(globalbcid); + auto foundCells = numberCellsInBC.find(globalbcid); + if (foundColls != numberCollsInBC.end() && foundCells != numberCellsInBC.end()) { + emcalcollisionmatch(collision.globalIndex(), foundColls->second != 1, foundCells->second > 0); + } else { + LOG(warning) << "BC not found in map of number of collisions."; + } + } // end of collision loop + + LOG(detail) << "Processed " << nBCsProcessed << " BCs with " << nCellsProcessed << " cells"; + } + PROCESS_SWITCH(EmcalCorrectionTask, processMCFull, "run full analysis with MC info", false); + + void processMCWithSecondaries(BcEvSels const& bcs, CollEventSels const& collisions, MyGlobTracks const& tracks, FilteredMcCells const& cells, aod::StoredMcParticles_001 const&, EMV0Legs const& v0legs) + { + LOG(debug) << "Starting processMCWithSecondaries."; + + 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 (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. + + // get run number + runNumber = bc.runNumber(); + + // Get the collisions matched to the BC using foundBCId of the collision + auto collisionsInFoundBC = collisions.sliceBy(collisionsPerFoundBC, bc.globalIndex()); + auto cellsInBC = cells.sliceBy(mcCellsPerFoundBC, bc.globalIndex()); + + numberCollsInBC.insert(std::pair(bc.globalIndex(), collisionsInFoundBC.size())); + numberCellsInBC.insert(std::pair(bc.globalIndex(), cellsInBC.size())); + + if (!cellsInBC.size()) { + LOG(debug) << "No cells found for BC"; + countBC(collisionsInFoundBC.size(), false); + continue; + } + // Counters for BCs with matched collisions + countBC(collisionsInFoundBC.size(), true); + std::vector cellsBC; + std::vector cellIndicesBC; + std::vector cellLabels; + for (const auto& cell : cellsInBC) { + mHistManager.fill(HIST("hContributors"), cell.mcParticle_as().size()); + auto cellParticles = cell.mcParticle_as(); + for (const auto& cellparticle : cellParticles) { + const auto& ids = cell.mcParticleIds(); + const auto& amps = cell.amplitudeA(); + + if (ids.empty() || amps.empty()) { + LOGF(warning, "Skipping cell with empty MC info: absId=%d", cell.cellNumber()); + continue; + } + mHistManager.fill(HIST("hMCParticleEnergy"), cellparticle.e()); + } + auto amplitude = cell.amplitude(); + 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 (mcCellEnergyShift != 1.) { + amplitude *= mcCellEnergyShift; // Fine tune the MC cell energy + } + if (mcCellEnergyResolutionBroadening != 0.) { + amplitude *= (1. + normalgaus(rdgen) * mcCellEnergyResolutionBroadening); // Fine tune the MC cell energy resolution + } + cellsBC.emplace_back(cell.cellNumber(), + amplitude, + cell.time() + getCellTimeShift(cell.cellNumber(), amplitude, o2::emcal::intToChannelType(cell.cellType()), runNumber), + o2::emcal::intToChannelType(cell.cellType())); + cellIndicesBC.emplace_back(cell.globalIndex()); + cellLabels.emplace_back(std::vector{cell.mcParticleIds().begin(), cell.mcParticleIds().end()}, std::vector{cell.amplitudeA().begin(), cell.amplitudeA().end()}); } + if (isMC.value && emcCrossTalkConf.enableCrossTalk.value) { + if (emcCrossTalkConf.createHistograms.value) { + for (const auto& cell : cellsBC) { + mHistManager.fill(HIST("hCellEnergyDistBefore"), cell.getAmplitude()); + } + } + emcCrossTalk.setCells(cellsBC, cellLabels); + bool isOkCrossTalk = emcCrossTalk.run(); + if (!isOkCrossTalk) { + LOG(info) << "Cross talk emulation failed!"; + } else { + // When we get new cells we also need to add additional entries into cellIndicesBC. + // Adding -1 and later when filling the clusterID<->cellID table skip all cases where this is -1 + if (cellIndicesBC.size() < cellsBC.size()) { + cellIndicesBC.reserve(cellsBC.size()); + size_t nMissing = cellsBC.size() - cellIndicesBC.size(); + cellIndicesBC.insert(cellIndicesBC.end(), nMissing, -1); + } + if (emcCrossTalkConf.createHistograms.value) { + for (const auto& cell : cellsBC) { + mHistManager.fill(HIST("hCellEnergyDistAfter"), cell.getAmplitude()); + } + } + } // cross talk emulation was okay + } // if (isMC.value && emcCrossTalkConf.enableCrossTalk.value) + // shaper correction has to come AFTER cross talk + for (auto& cell : cellsBC) { // o2-linter: disable=const-ref-in-for-loop (we are changing a value here) + if (cell.getLowGain()) { + cell.setAmplitude(o2::emcal::NonlinearityHandler::evaluateShaperCorrectionCellEnergy(cell.getAmplitude())); + } + } + LOG(detail) << "Number of cells for BC (CF): " << cellsBC.size(); + nCellsProcessed += cellsBC.size(); + + fillQAHistogram(cellsBC); LOG(debug) << "Converted cells. Contains: " << cellsBC.size() << ". Originally " << cellsInBC.size() << ". About to run clusterizer."; // this is a test @@ -402,20 +929,30 @@ 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}; + MatchResult indexMapPair; std::vector trackGlobalIndex; - doTrackMatching(col, tracks, IndexMapPair, vertex_pos, trackGlobalIndex); + doTrackMatching(col, tracks, indexMapPair, trackGlobalIndex); + + MatchResult indexMapPairSecondary; + std::vector secondaryGlobalIndex; + doSecondaryTrackMatching(col, v0legs, indexMapPairSecondary, secondaryGlobalIndex, tracks); // 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, &indexMapPairSecondary, &secondaryGlobalIndex); + } else { + mHistManager.fill(HIST("hBCMatchErrors"), 2); } } } else { // ambiguous @@ -428,8 +965,10 @@ struct EmcalCorrectionTask { hasCollision = true; mHistManager.fill(HIST("hCollisionType"), 2); } - FillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); + fillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); } + mClusterPhi.clear(); + mClusterEta.clear(); LOG(debug) << "Cluster loop done for clusterizer " << iClusterizer; } // end of clusterizer loop LOG(debug) << "Done with process BC."; @@ -438,7 +977,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()) { @@ -450,19 +989,31 @@ 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) + PROCESS_SWITCH(EmcalCorrectionTask, processMCWithSecondaries, "run full analysis with MC info", false); + + 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. // Get the collisions matched to the BC using global bc index of the collision // since we do not have event selection available here! + + // get run number + runNumber = bc.runNumber(); + + if (applyTempCalib && !mIsTempCalibInitialized) { // needs to be called once + mTempCalibExtractor->InitializeFromCCDB(pathTempCalibCCDB, static_cast(runNumber)); + mIsTempCalibInitialized = true; + } + auto collisionsInBC = collisions.sliceBy(collisionsPerBC, bc.globalIndex()); auto cellsInBC = cells.sliceBy(cellsPerFoundBC, bc.globalIndex()); @@ -475,10 +1026,22 @@ struct EmcalCorrectionTask { countBC(collisionsInBC.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) && emcal::intToChannelType(cell.cellType()) == emcal::ChannelType_t::LOW_GAIN) { // Apply shaper correction to LG cells + amplitude = o2::emcal::NonlinearityHandler::evaluateShaperCorrectionCellEnergy(amplitude); + } + if (applyGainCalibShift) { + amplitude *= mArrGainCalibDiff[cell.cellNumber()]; + } + if (applyTempCalib) { + float tempCalibFactor = mTempCalibExtractor->getGainCalibFactor(static_cast(cell.cellNumber())); + amplitude /= tempCalibFactor; + mHistManager.fill(HIST("hTempCalibCorrection"), tempCalibFactor); + } cellsBC.emplace_back(cell.cellNumber(), - cell.amplitude(), - cell.time(), + amplitude, + cell.time() + getCellTimeShift(cell.cellNumber(), amplitude, o2::emcal::intToChannelType(cell.cellType()), runNumber), o2::emcal::intToChannelType(cell.cellType())); cellIndicesBC.emplace_back(cell.globalIndex()); } @@ -487,12 +1050,6 @@ struct EmcalCorrectionTask { fillQAHistogram(cellsBC); - // TODO: Helpful for now, but should be removed. - LOG(debug) << "Converted EMCAL cells"; - for (auto& cell : cellsBC) { - LOG(debug) << cell.getTower() << ": E: " << cell.getEnergy() << ", time: " << cell.getTimeStamp() << ", type: " << cell.getType(); - } - LOG(debug) << "Converted cells. Contains: " << cellsBC.size() << ". Originally " << cellsInBC.size() << ". About to run clusterizer."; // this is a test @@ -504,13 +1061,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,9 +1085,11 @@ struct EmcalCorrectionTask { hasCollision = true; mHistManager.fill(HIST("hCollisionType"), 2); } - FillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); + fillAmbigousClusterTable(bc, iClusterizer, cellIndicesBC, hasCollision); } + mClusterPhi.clear(); + mClusterEta.clear(); LOG(debug) << "Cluster loop done for clusterizer " << iClusterizer; } // end of clusterizer loop LOG(detail) << "Processed " << nBCsProcessed << " BCs with " << nCellsProcessed << " cells"; @@ -534,7 +1099,7 @@ struct EmcalCorrectionTask { } PROCESS_SWITCH(EmcalCorrectionTask, processStandalone, "run stand alone analysis", false); - void cellsToCluster(size_t iClusterizer, const gsl::span cellsBC, std::optional> cellLabels = std::nullopt) + void cellsToCluster(size_t iClusterizer, const gsl::span cellsBC, gsl::span cellLabels = {}) { mClusterizers.at(iClusterizer)->findClusters(cellsBC); @@ -548,10 +1113,12 @@ struct EmcalCorrectionTask { mAnalysisClusters.clear(); mClusterLabels.clear(); mClusterFactories.reset(); - if (cellLabels) { - mClusterFactories.setContainer(*emcalClusters, cellsBC, *emcalClustersInputIndices, cellLabels); - } else { + // 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.empty()) { mClusterFactories.setContainer(*emcalClusters, cellsBC, *emcalClustersInputIndices); + } else { + mClusterFactories.setContainer(*emcalClusters, cellsBC, *emcalClustersInputIndices, cellLabels); } LOG(debug) << "Cluster factory set up."; @@ -561,31 +1128,43 @@ struct EmcalCorrectionTask { auto analysisCluster = mClusterFactories.buildCluster(icl, &clusterLabel); mAnalysisClusters.emplace_back(analysisCluster); mClusterLabels.push_back(clusterLabel); - LOG(debug) << "Cluster " << icl << ": E: " << analysisCluster.E() - << ", NCells " << analysisCluster.getNCells(); + auto pos = analysisCluster.getGlobalPosition(); + mClusterPhi.emplace_back(RecoDecay::constrainAngle(pos.Phi())); + mClusterEta.emplace_back(pos.Eta()); + LOG(debug) << "Cluster " << icl << ": E: " << analysisCluster.E() << ", NCells " << analysisCluster.getNCells(); } + mHistManager.fill(HIST("hNCluster"), mAnalysisClusters.size()); LOG(debug) << "Converted to analysis clusters."; } 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, MatchResult* indexMapPair = nullptr, const std::vector* trackGlobalIndex = nullptr, MatchResult* indexMapPairSecondaries = nullptr, const std::vector* secondariesGlobalIndex = nullptr) { + // average number of cells per cluster, only used the reseve a reasonable amount for the clustercells table + const size_t nAvgNcells = 3; // we found a collision, put the clusters into the none ambiguous table clusters.reserve(mAnalysisClusters.size()); - if (mClusterLabels.size() > 0) { + if (!mClusterLabels.empty()) { mcclusters.reserve(mClusterLabels.size()); } + clustercells.reserve(mAnalysisClusters.size() * nAvgNcells); + + // get the clusterType once + const auto clusterType = static_cast(mClusterDefinitions[iClusterizer]); + int cellindex = -1; unsigned int iCluster = 0; + float energy = 0.f; for (const auto& cluster : mAnalysisClusters) { + energy = cluster.E(); // 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())); + pos *= (energy / std::sqrt(pos.Mag2())); // Correct for nonlinear behaviour - float nonlinCorrEnergy = cluster.E(); + float nonlinCorrEnergy = energy; if (!disableNonLin) { try { nonlinCorrEnergy = mNonlinearityHandler.getCorrectedClusterEnergy(cluster); @@ -596,33 +1175,56 @@ struct EmcalCorrectionTask { // save to table LOG(debug) << "Writing cluster definition " - << static_cast(mClusterDefinitions.at(iClusterizer)) + << clusterType << " to table."; mHistManager.fill(HIST("hClusterType"), 1); - clusters(col, cluster.getID(), nonlinCorrEnergy, cluster.getCoreEnergy(), cluster.E(), - pos.Eta(), TVector2::Phi_0_2pi(pos.Phi()), cluster.getM02(), + clusters(col, cluster.getID(), nonlinCorrEnergy, cluster.getCoreEnergy(), energy, + pos.Eta(), RecoDecay::constrainAngle(pos.Phi()), cluster.getM02(), cluster.getM20(), cluster.getNCells(), cluster.getClusterTime(), cluster.getIsExotic(), cluster.getDistanceToBadChannel(), cluster.getNExMax(), - static_cast(mClusterDefinitions.at(iClusterizer))); - if (mClusterLabels.size() > 0) { + clusterType); + if (!mClusterLabels.empty()) { mcclusters(mClusterLabels[iCluster].getLabels(), mClusterLabels[iCluster].getEnergyFractions()); } - clustercells.reserve(cluster.getNCells()); // loop over cells in cluster and save to table for (int ncell = 0; ncell < cluster.getNCells(); ncell++) { cellindex = cluster.getCellIndex(ncell); LOG(debug) << "trying to find cell index " << cellindex << " in map"; - clustercells(clusters.lastIndex(), cellIndicesBC[cellindex]); + if (cellIndicesBC[cellindex] >= 0) { + clustercells(clusters.lastIndex(), cellIndicesBC[cellindex]); + } } // end of cells of cluser loop // fill histograms - mHistManager.fill(HIST("hClusterE"), cluster.E()); - 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]]); + mHistManager.fill(HIST("hClusterE"), energy); + mHistManager.fill(HIST("hClusterNLM"), cluster.getNExMax()); + mHistManager.fill(HIST("hClusterTime"), cluster.getClusterTime()); + mHistManager.fill(HIST("hClusterEtaPhi"), pos.Eta(), RecoDecay::constrainAngle(pos.Phi())); + if (fillQA.value) { + mHistManager.fill(HIST("hClusterNCellE"), cluster.E(), cluster.getNCells()); + mHistManager.fill(HIST("hClusterFCrossE"), cluster.E(), cluster.getFCross()); + mHistManager.fill(HIST("hClusterFCrossSigmaLongE"), cluster.E(), cluster.getFCross(), cluster.getM02()); + mHistManager.fill(HIST("hClusterFCrossSigmaShortE"), cluster.E(), cluster.getFCross(), cluster.getM20()); + } + if (indexMapPair && trackGlobalIndex) { + if (iCluster < indexMapPair->matchIndexTrack.size() && indexMapPair->matchIndexTrack.size() > 0) { + for (unsigned int iTrack = 0; iTrack < indexMapPair->matchIndexTrack[iCluster].size(); iTrack++) { + if (indexMapPair->matchIndexTrack[iCluster][iTrack] >= 0) { + LOG(debug) << "Found track " << (*trackGlobalIndex)[indexMapPair->matchIndexTrack[iCluster][iTrack]] << " in cluster " << cluster.getID(); + matchedTracks(clusters.lastIndex(), (*trackGlobalIndex)[indexMapPair->matchIndexTrack[iCluster][iTrack]], indexMapPair->matchDeltaPhi[iCluster][iTrack], indexMapPair->matchDeltaEta[iCluster][iTrack]); + mHistManager.fill(HIST("hMatchedPrimaryTracks"), indexMapPair->matchDeltaEta[iCluster][iTrack], indexMapPair->matchDeltaPhi[iCluster][iTrack]); + } + } + } + } + if (indexMapPairSecondaries && secondariesGlobalIndex) { + if (iCluster < indexMapPairSecondaries->matchIndexTrack.size() && indexMapPairSecondaries->matchIndexTrack.size() > 0) { + for (unsigned int iTrack = 0; iTrack < indexMapPairSecondaries->matchIndexTrack[iCluster].size(); iTrack++) { + if (indexMapPairSecondaries->matchIndexTrack[iCluster][iTrack] >= 0) { + LOG(debug) << "Found secondary track " << (*secondariesGlobalIndex)[indexMapPairSecondaries->matchIndexTrack[iCluster][iTrack]] << " in cluster " << cluster.getID(); + matchedSecondaries(clusters.lastIndex(), (*secondariesGlobalIndex)[indexMapPairSecondaries->matchIndexTrack[iCluster][iTrack]], indexMapPairSecondaries->matchDeltaPhi[iCluster][iTrack], indexMapPairSecondaries->matchDeltaEta[iCluster][iTrack]); + mHistManager.fill(HIST("hMatchedSecondaries"), indexMapPairSecondaries->matchDeltaEta[iCluster][iTrack], indexMapPairSecondaries->matchDeltaPhi[iCluster][iTrack]); + } } } } @@ -631,18 +1233,27 @@ 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) { + // average number of cells per cluster, only used the reseve a reasonable amount for the clustercells table + const size_t nAvgNcells = 3; int cellindex = -1; clustersAmbiguous.reserve(mAnalysisClusters.size()); + if (mClusterLabels.size() > 0) { + mcclustersAmbiguous.reserve(mClusterLabels.size()); + } + clustercellsambiguous.reserve(mAnalysisClusters.size() * nAvgNcells); + unsigned int iCluster = 0; + float energy = 0.f; for (const auto& cluster : mAnalysisClusters) { + energy = cluster.E(); auto pos = cluster.getGlobalPosition(); pos = pos - math_utils::Point3D{0., 0., 0.}; // Normalize the vector and rescale by energy. - pos *= (cluster.E() / std::sqrt(pos.Mag2())); + pos *= (energy / std::sqrt(pos.Mag2())); // Correct for nonlinear behaviour - float nonlinCorrEnergy = cluster.E(); + float nonlinCorrEnergy = energy; try { nonlinCorrEnergy = mNonlinearityHandler.getCorrectedClusterEnergy(cluster); } catch (o2::emcal::NonlinearityHandler::UninitException& e) { @@ -651,94 +1262,106 @@ struct EmcalCorrectionTask { // We have our necessary properties. Now we store outputs - // LOG(debug) << "Cluster E: " << cluster.E(); + // LOG(debug) << "Cluster E: " << energy; if (!hasCollision) { mHistManager.fill(HIST("hClusterType"), 0); } else { mHistManager.fill(HIST("hClusterType"), 2); } clustersAmbiguous( - bc, cluster.getID(), nonlinCorrEnergy, cluster.getCoreEnergy(), cluster.E(), - pos.Eta(), TVector2::Phi_0_2pi(pos.Phi()), cluster.getM02(), + bc, cluster.getID(), nonlinCorrEnergy, cluster.getCoreEnergy(), energy, + pos.Eta(), RecoDecay::constrainAngle(pos.Phi()), cluster.getM02(), cluster.getM20(), cluster.getNCells(), cluster.getClusterTime(), cluster.getIsExotic(), cluster.getDistanceToBadChannel(), cluster.getNExMax(), static_cast(mClusterDefinitions.at(iClusterizer))); - clustercellsambiguous.reserve(cluster.getNCells()); + if (mClusterLabels.size() > 0) { + mcclustersAmbiguous(mClusterLabels[iCluster].getLabels(), mClusterLabels[iCluster].getEnergyFractions()); + } 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, MatchResult& indexMapPair, std::vector& trackGlobalIndex) { auto groupedTracks = tracks.sliceBy(perCollision, col.globalIndex()); - int NTracksInCol = groupedTracks.size(); - std::vector trackPhi; - std::vector trackEta; + 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); - - int NClusterInCol = mAnalysisClusters.size(); - std::vector clusterPhi; - std::vector clusterEta; - clusterPhi.reserve(NClusterInCol); - clusterEta.reserve(NClusterInCol); - - // TODO one loop that could in principle be combined with the other - // loop to improve performance - for (const auto& cluster : mAnalysisClusters) { - // Determine the cluster eta, phi, correcting for the vertex - // position. - auto pos = cluster.getGlobalPosition(); - pos = pos - vertex_pos; - // 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()); + trackPhi.reserve(nTracksInCol); + trackEta.reserve(nTracksInCol); + trackGlobalIndex.reserve(nTracksInCol); + fillTrackInfo(groupedTracks, trackPhi, trackEta, trackGlobalIndex); + + indexMapPair = matchTracksToCluster(mClusterPhi, mClusterEta, trackPhi, trackEta, maxMatchingDistance, kMaxMatchesPerCluster); + } + + template + void doSecondaryTrackMatching(Collision const& col, EMV0Legs const& v0legs, MatchResult& indexMapPair, std::vector& trackGlobalIndex, MyGlobTracks const& tracks) + { + auto groupedV0Legs = v0legs.sliceBy(perCollisionEMV0Legs, col.globalIndex()); + int nLegsInCol = groupedV0Legs.size(); + std::vector trackPhi; + std::vector trackEta; + // reserve memory to reduce on the fly memory allocation + trackPhi.reserve(nLegsInCol); + trackEta.reserve(nLegsInCol); + trackGlobalIndex.reserve(nLegsInCol); + + float trackEtaEmcal = 0.f; + float trackPhiEmcal = 0.f; + for (const auto& leg : groupedV0Legs) { + if (leg.trackId() < 0 || leg.trackId() > tracks.size()) { + continue; + } + auto track = tracks.iteratorAt(leg.trackId()); + trackEtaEmcal = track.trackEtaEmcal(); + trackPhiEmcal = track.trackPhiEmcal(); + // 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 (trackEtaEmcal < TrackNotOnEMCal || trackPhiEmcal < TrackNotOnEMCal) { + continue; + } + if (trackMinPt > 0 && track.pt() < trackMinPt) { + continue; + } + trackPhi.emplace_back(RecoDecay::constrainAngle(trackPhiEmcal)); + trackEta.emplace_back(trackEtaEmcal); + trackGlobalIndex.emplace_back(track.globalIndex()); } - IndexMapPair = - jetutilities::MatchClustersAndTracks(clusterPhi, clusterEta, - trackPhi, trackEta, - maxMatchingDistance, 20); + indexMapPair = matchTracksToCluster(mClusterPhi, mClusterEta, trackPhi, trackEta, maxMatchingDistance, kMaxMatchesPerCluster); } 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) { - // TODO only consider tracks in current emcal/dcal acceptanc + for (const auto& track : tracks) { 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() < TrackNotOnEMCal || track.trackPhiEmcal() < TrackNotOnEMCal) { + continue; + } + if (trackMinPt > 0 && track.pt() < trackMinPt) { + continue; } + trackPhi.emplace_back(RecoDecay::constrainAngle(track.trackPhiEmcal())); + trackEta.emplace_back(track.trackEtaEmcal()); trackGlobalIndex.emplace_back(track.globalIndex()); } - 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 +1375,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,37 +1385,108 @@ 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))); + mHistManager.fill(HIST("hCellEtaPhi"), std::get<0>(res), RecoDecay::constrainAngle(std::get<1>(res))); res = mClusterizers.at(0)->getGeometry()->GlobalRowColFromIndex(cell.getTower()); // NOTE: Reversed column and row because it's more natural for presentation. mHistManager.fill(HIST("hCellRowCol"), std::get<1>(res), std::get<0>(res)); } } - 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) { + if (applyCellAbsScale == CellScaleMode::ModeSMWise) { 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) { + } else if (applyCellAbsScale == CellScaleMode::ModeColumnWise) { 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, const int runNumber) + { + if (!applyCellTimeCorrection) { + return 0.f; + } + float timeshift = 0.f; + float timesmear = 0.f; + const float minLeaderEnergy = 0.3f; + const float lowEnergyRegime = 4.f; + const float highEnergyRegime = 30.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 < minLeaderEnergy) // 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 < minLeaderEnergy) { // 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 < lowEnergyRegime) // 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 < highEnergyRegime) // 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 + } + // Temporary extra shift for bug in time calibraiton of apass4 Pb-Pb 2024, requires pos shift of 2*8.8 ns for low gain cells + if (cellType == emcal::ChannelType_t::LOW_GAIN) { + for (const auto& range : mExtraTimeShiftRunRanges) { + if (runNumber >= range.first && runNumber <= range.second) { + timeshift += 2 * 8.8; + } + } + } + LOG(debug) << "Shift the cell time by " << timeshift << " + " << timesmear << " ns"; + } + return timeshift + timesmear; + }; + + void initializeGainCalibShift() + { + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + uint64_t tsOld = 1634853602000; // timestamp corresponding to LHC22o old gain calib object + o2::emcal::GainCalibrationFactors* paramsOld = ccdbMgr.getForTimeStamp("EMC/Calib/GainCalibFactors", tsOld); + uint64_t tsNew = 1734853602000; // timestamp corresponding to new gain calib object (new cell compression) + o2::emcal::GainCalibrationFactors* paramsNew = ccdbMgr.getForTimeStamp("EMC/Calib/GainCalibFactors", tsNew); + for (uint16_t i = 0; i < mArrGainCalibDiff.size(); ++i) { + mArrGainCalibDiff[i] = paramsNew->getGainCalibFactors(i) == 0 ? 1. : paramsOld->getGainCalibFactors(i) / paramsNew->getGainCalibFactors(i); + } + } }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"emcal-correction-task"})}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGJE/TableProducer/emcalMatchedTracksTask.cxx b/PWGJE/TableProducer/emcalMatchedTracksTask.cxx index 4134b8455e3..55781eb6bc4 100644 --- a/PWGJE/TableProducer/emcalMatchedTracksTask.cxx +++ b/PWGJE/TableProducer/emcalMatchedTracksTask.cxx @@ -9,34 +9,36 @@ // 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 "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/HistogramRegistry.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/EMCALMatchedTracks.h" +#include "Common/CCDB/TriggerAliases.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "CommonDataFormat/InteractionRecord.h" #include "EMCALBase/Geometry.h" -#include "EMCALCalib/BadChannelMap.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGJE/DataModel/EMCALMatchedTracks.h" -#include "DataFormatsEMCAL/Cell.h" -#include "DataFormatsEMCAL/Constants.h" -#include "DataFormatsEMCAL/AnalysisCluster.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include +#include -#include "CommonDataFormat/InteractionRecord.h" +#include + +#include +#include +#include +#include +#include // \struct EmcalMatchedTracksTask /// \brief Simple table producer task for EMCal matched tracks diff --git a/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx b/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx index 6b0376a3e25..2f912c8ae4e 100644 --- a/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx +++ b/PWGJE/TableProducer/eventwiseConstituentSubtractor.cxx @@ -13,17 +13,27 @@ // /// \author Nima Zardoshti -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + #include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include +#include +#include -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetFindingUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetBkgSubUtils.h" -#include "Framework/runDataProcessing.h" +#include + +#include +#include using namespace o2; using namespace o2::framework; @@ -31,9 +41,27 @@ using namespace o2::framework::expressions; struct eventWiseConstituentSubtractorTask { Produces trackSubtractedTable; + Produces particleSubtractedTable; Produces trackSubtractedD0Table; + Produces particleSubtractedD0Table; + Produces trackSubtractedDplusTable; + Produces particleSubtractedDplusTable; + Produces trackSubtractedDsTable; + Produces particleSubtractedDsTable; + Produces trackSubtractedDstarTable; + Produces particleSubtractedDstarTable; Produces trackSubtractedLcTable; + Produces particleSubtractedLcTable; + Produces trackSubtractedB0Table; + Produces particleSubtractedB0Table; Produces trackSubtractedBplusTable; + Produces particleSubtractedBplusTable; + Produces trackSubtractedXicToXiPiPiTable; + Produces particleSubtractedXicToXiPiPiTable; + 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,89 +69,229 @@ 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 applyTrackingEfficiency{"applyTrackingEfficiency", {false}, "configurable to decide whether to apply artificial tracking efficiency (discarding tracks) in the collision analysed by this task"}; + Configurable> trackingEfficiencyPtBinning{"trackingEfficiencyPtBinning", {0., 10, 999.}, "pt binning of tracking efficiency array if applyTrackingEfficiency is true"}; + Configurable> trackingEfficiency{"trackingEfficiency", {1.0, 1.0}, "tracking efficiency array applied if applyTrackingEfficiency is true"}; 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"}; Configurable doRhoMassSub{"doRhoMassSub", true, "perfom mass subtraction as well"}; + Configurable ghostRapMax{"ghostRapMax", 0.9, "Ghost rapidity max"}; + Configurable ghostRepeat{"ghostRepeat", 1, "Ghost tiling repeats"}; + Configurable ghostArea{"ghostArea", 0.005, "Area per ghost"}; + Configurable ghostGridScatter{"ghostGridScatter", 1.0, "Grid scatter"}; + Configurable ghostKtScatter{"ghostKtScatter", 0.1, "kT scatter"}; + Configurable ghostMeanPt{"ghostMeanPt", 1e-100, "Mean ghost pT"}; JetBkgSubUtils eventWiseConstituentSubtractor; - float bkgPhiMax_; std::vector inputParticles; 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); eventWiseConstituentSubtractor.setMaxEtaEvent(eventEtaMax); + fastjet::GhostedAreaSpec ghostAreaSpec(ghostRapMax, ghostRepeat, ghostArea, + ghostGridScatter, ghostKtScatter, ghostMeanPt); + eventWiseConstituentSubtractor.setGhostAreaSpec(ghostAreaSpec); + + if (applyTrackingEfficiency) { + if (trackingEfficiencyPtBinning->size() < 2) { + LOGP(fatal, "eventWiseConstituentSubtractor workflow: trackingEfficiencyPtBinning configurable should have at least two bin edges"); + } + if (trackingEfficiency->size() + 1 != trackingEfficiencyPtBinning->size()) { + LOGP(fatal, "eventWiseConstituentSubtractor workflow: trackingEfficiency configurable should have exactly one less entry than the number of bin edges set in trackingEfficiencyPtBinning configurable"); + } + } } 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; - Preslice perDielectronCandidate = aod::bkgdielectron::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, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning, &candidate); - auto const bkgRhosSliced = jetcandidateutilities::slicedPerCandidate(bkgRhos, candidate, perD0Candidate, perLcCandidate, perBplusCandidate, perDielectronCandidate); - 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, trackingEfficiency, std::optional{candidate}); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, &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, 0, static_cast(o2::aod::mcparticle::enums::PhysicalPrimary)); // 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, trackingEfficiency); + jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning); 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) { - analyseHF(tracks, candidates, bkgRhos, trackSubtractedD0Table); + 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, 0, static_cast(o2::aod::mcparticle::enums::PhysicalPrimary)); // 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, 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) + { + analyseHFMc(tracks, candidates, particleSubtractedDplusTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDplusMcCollisions, "Fill table of subtracted tracks for collisions with Dplus MCP candidates", false); + + void processDsCollisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHF(tracks, candidates, trackSubtractedDsTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDsCollisions, "Fill table of subtracted tracks for collisions with Ds candidates", false); + + void processDsMcCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) { - analyseHF(tracks, candidates, bkgRhos, trackSubtractedLcTable); + analyseHFMc(tracks, candidates, particleSubtractedDsTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDsMcCollisions, "Fill table of subtracted tracks for collisions with Ds MCP candidates", false); + + void processDstarCollisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHF(tracks, candidates, trackSubtractedDstarTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDstarCollisions, "Fill table of subtracted tracks for collisions with D* candidates", false); + + void processDstarMcCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHFMc(tracks, candidates, particleSubtractedDstarTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processDstarMcCollisions, "Fill table of subtracted tracks for collisions with D* 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 processB0Collisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHF(tracks, candidates, trackSubtractedB0Table); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processB0Collisions, "Fill table of subtracted tracks for collisions with B0 candidates", false); + + void processB0McCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) { - analyseHF(tracks, candidates, bkgRhos, trackSubtractedBplusTable); + analyseHFMc(tracks, candidates, particleSubtractedB0Table); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processB0McCollisions, "Fill table of subtracted tracks for collisions with B0 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 processXicToXiPiPiCollisions(aod::JetCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHF(tracks, candidates, trackSubtractedXicToXiPiPiTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processXicToXiPiPiCollisions, "Fill table of subtracted tracks for collisions with XicToXiPiPi candidates", false); + + void processXicToXiPiPiMcCollisions(aod::JetMcCollision const&, soa::Filtered const& tracks, soa::Join const& candidates) + { + analyseHFMc(tracks, candidates, particleSubtractedXicToXiPiPiTable); + } + PROCESS_SWITCH(eventWiseConstituentSubtractorTask, processXicToXiPiPiMcCollisions, "Fill table of subtracted tracks for collisions with XicToXiPiPi 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) + { + analyseHFMc(tracks, candidates, particleSubtractedDielectronTable); + } + 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..a9f52f96a35 --- /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 "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetTagging.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include + +#include + +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 61% rename from PWGJE/TableProducer/jeteventweightmcd.cxx rename to PWGJE/TableProducer/jetEventWeightMCD.cxx index 2525c9cc0ea..ddb518e1bba 100644 --- a/PWGJE/TableProducer/jeteventweightmcd.cxx +++ b/PWGJE/TableProducer/jetEventWeightMCD.cxx @@ -13,41 +13,44 @@ // /// \author Nima Zardoshti -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + #include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include -#include "PWGJE/DataModel/Jet.h" +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -#include "Framework/runDataProcessing.h" - template 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>(); - mcDetectorLevelWeightsTable(jet.globalIndex(), collision.mcCollision().weight()); + auto collision = jet.template collision_as>(); + mcDetectorLevelWeightsTable(jet.globalIndex(), collision.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>(); - mcDetectorLevelEventWiseSubtractedWeightsTable(jet.globalIndex(), collision.mcCollision().weight()); + auto collision = jet.template collision_as>(); + mcDetectorLevelEventWiseSubtractedWeightsTable(jet.globalIndex(), collision.weight()); } PROCESS_SWITCH(JetEventWeightMCDTask, processMCDetectorLevelEventWiseSubtractedEventWeight, "Fill event weight tables for detector level MC jets", false); }; @@ -56,8 +59,13 @@ using ChargedMCJetsEventWeight = JetEventWeightMCDTask; using FullMCJetsEventWeight = JetEventWeightMCDTask; using D0ChargedMCJetsEventWeight = JetEventWeightMCDTask; +using DplusChargedMCJetsEventWeight = JetEventWeightMCDTask; +using DsChargedMCJetsEventWeight = JetEventWeightMCDTask; +using DstarChargedMCJetsEventWeight = JetEventWeightMCDTask; using LcChargedMCJetsEventWeight = JetEventWeightMCDTask; +using B0ChargedMCJetsEventWeight = JetEventWeightMCDTask; using BplusChargedMCJetsEventWeight = JetEventWeightMCDTask; +using XicToXiPiPiChargedMCJetsEventWeight = JetEventWeightMCDTask; using V0ChargedMCJetsEventWeight = JetEventWeightMCDTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) @@ -81,14 +89,34 @@ 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-ds-eventweight-mcd-charged"})); + + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-dstar-eventweight-mcd-charged"})); + tasks.emplace_back( adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-lc-eventweight-mcd-charged"})); + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-b0-eventweight-mcd-charged"})); + tasks.emplace_back( adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-bplus-eventweight-mcd-charged"})); + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-xictoxipipi-eventweight-mcd-charged"})); + tasks.emplace_back( adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-v0-eventweight-mcd-charged"})); diff --git a/PWGJE/TableProducer/jeteventweightmcp.cxx b/PWGJE/TableProducer/jetEventWeightMCP.cxx similarity index 65% rename from PWGJE/TableProducer/jeteventweightmcp.cxx rename to PWGJE/TableProducer/jetEventWeightMCP.cxx index 32083012d18..7f262e998ea 100644 --- a/PWGJE/TableProducer/jeteventweightmcp.cxx +++ b/PWGJE/TableProducer/jetEventWeightMCP.cxx @@ -13,30 +13,31 @@ // /// \author Nima Zardoshti +#include "PWGJE/DataModel/Jet.h" + #include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include -#include "PWGJE/DataModel/Jet.h" +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -#include "Framework/runDataProcessing.h" - template struct JetEventWeightMCPTask { Produces 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 +48,13 @@ using ChargedMCJetsEventWeight = JetEventWeightMCPTask; using FullMCJetsEventWeight = JetEventWeightMCPTask; using D0ChargedMCJetsEventWeight = JetEventWeightMCPTask; +using DplusChargedMCJetsEventWeight = JetEventWeightMCPTask; +using DsChargedMCJetsEventWeight = JetEventWeightMCPTask; +using DstarChargedMCJetsEventWeight = JetEventWeightMCPTask; using LcChargedMCJetsEventWeight = JetEventWeightMCPTask; +using B0ChargedMCJetsEventWeight = JetEventWeightMCPTask; using BplusChargedMCJetsEventWeight = JetEventWeightMCPTask; +using XicToXiPiPiChargedMCJetsEventWeight = JetEventWeightMCPTask; using V0ChargedMCJetsEventWeight = JetEventWeightMCPTask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) @@ -72,14 +78,34 @@ 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-ds-eventweight-mcp-charged"})); + + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-dstar-eventweight-mcp-charged"})); + tasks.emplace_back( adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-lc-eventweight-mcp-charged"})); + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-b0-eventweight-mcp-charged"})); + tasks.emplace_back( adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-bplus-eventweight-mcp-charged"})); + tasks.emplace_back( + adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, TaskName{"jet-xictoxipipi-eventweight-mcp-charged"})); + tasks.emplace_back( adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-v0-eventweight-mcp-charged"})); diff --git a/PWGJE/TableProducer/jetTaggerHF.cxx b/PWGJE/TableProducer/jetTaggerHF.cxx new file mode 100644 index 00000000000..b648929de89 --- /dev/null +++ b/PWGJE/TableProducer/jetTaggerHF.cxx @@ -0,0 +1,701 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "MlResponse.h" + +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/Core/MlResponseHfTagging.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetTagging.h" + +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include +#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; + +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> pathsCCDBforIPDataparameter{"pathsCCDBforIPDataparameter", std::vector{"Users/l/leehy/LHC24g4/f_inclusive_0"}, "Paths for fitting parameters of resolution functions of data for IP method on CCDB"}; + Configurable> pathsCCDBforIPIncparameter{"pathsCCDBforIPIncparameter", std::vector{"Users/l/leehy/LHC24g4/f_inclusive_0"}, "Paths for fitting parameters of resolution functions of inclusive for IP method on CCDB"}; + Configurable> pathsCCDBforIPBeautyparameter{"pathsCCDBforIPBeautyparameter", std::vector{"Users/l/leehy/LHC24g4/f_inclusive_0"}, "Paths for fitting parameters of resolution functions of beauty for IP method on CCDB"}; + Configurable> pathsCCDBforIPCharmparameter{"pathsCCDBforIPCharmparameter", std::vector{"Users/l/leehy/LHC24g4/f_inclusive_0"}, "Paths for fitting parameters of resolution functions of charm for IP method on CCDB"}; + Configurable> pathsCCDBforIPLfparameter{"pathsCCDBforIPLfparameter", std::vector{"Users/l/leehy/LHC24g4/f_inclusive_0"}, "Paths for fitting parameters of resolution functions of light flavour 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 useDb{"useDb", false, "Flag to use DB for ML model instead of the score"}; + + 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 jetpTMin{"jetpTMin", 5., "minimum jet pT"}; + Configurable dbMin{"dbMin", -10., "minimum GNN Db"}; + Configurable dbMax{"dbMax", 20., "maximum GNN Db"}; + 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> vecParamsDataJetCCDB; + std::vector> vecParamsIncJetMcCCDB; + std::vector> vecParamsBeautyJetMcCCDB; + std::vector> vecParamsCharmJetMcCCDB; + std::vector> vecParamsLfJetMcCCDB; + + std::vector> vecfSignImpXYSigDataJetCCDB; + std::vector> vecfSignImpXYSigIncJetMcCCDB; + std::vector> vecfSignImpXYSigCharmJetMcCCDB; + std::vector> vecfSignImpXYSigBeautyJetMcCCDB; + std::vector> vecfSignImpXYSigLfJetMcCCDB; + + 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) { + if (usepTcategorize) { + jetProb = jettaggingutilities::getJetProbability(vecfSignImpXYSigDataJetCCDB, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } else { + 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) { + if (usepTcategorize) { + jetProb = jettaggingutilities::getJetProbability(vecfSignImpXYSigCharmJetMcCCDB, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } else { + jetProb = jettaggingutilities::getJetProbability(fSignImpXYSigCharmJetMC, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } + } else if (origin == JetTaggingSpecies::beauty) { + if (usepTcategorize) { + jetProb = jettaggingutilities::getJetProbability(vecfSignImpXYSigBeautyJetMcCCDB, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } else { + jetProb = jettaggingutilities::getJetProbability(fSignImpXYSigBeautyJetMC, jet, tracks, trackDcaXYMax, trackDcaZMax, minSignImpXYSig); + } + } else { + if (usepTcategorize) { + jetProb = jettaggingutilities::getJetProbability(vecfSignImpXYSigLfJetMcCCDB, 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, isMC); + if (trackProbQA) { + evaluateTrackProbQA(origin, jet, tracks, isMC); + } + } else { + jetProb = calculateJetProbability(0, jet, tracks, isMC); + if (trackProbQA) { + evaluateTrackProbQA(0, jet, tracks, isMC); + } + } + } + if (doprocessAlgorithmGNN) { + if (jet.pt() >= jetpTMin) { + float dbRange; + if (scoreML[jet.globalIndex()] < dbMin) { + dbRange = 0.5; // underflow + } else if (scoreML[jet.globalIndex()] < dbMax) { + dbRange = 1.5; // in range + } else { + dbRange = 2.5; // overflow + } + registry.fill(HIST("h2_count_db"), 3.5, dbRange); // incl jet + if constexpr (isMC) { + switch (origin) { + case 2: + registry.fill(HIST("h_db_b"), scoreML[jet.globalIndex()]); + registry.fill(HIST("h2_count_db"), 0.5, dbRange); // b-jet + break; + case 1: + registry.fill(HIST("h_db_c"), scoreML[jet.globalIndex()]); + registry.fill(HIST("h2_count_db"), 1.5, dbRange); // c-jet + break; + case 0: + case 3: + registry.fill(HIST("h_db_lf"), scoreML[jet.globalIndex()]); + registry.fill(HIST("h2_count_db"), 2.5, dbRange); // lf-jet + 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 resoFuncDataCCDB; + std::vector resoFuncIncCCDB; + std::vector resoFuncBeautyCCDB; + std::vector resoFuncCharmCCDB; + std::vector resoFuncLfCCDB; + + ccdbApi.init(ccdbUrl); + + std::map metadata; + resoFuncMatch = resoFuncMatching; + + const int mIPmethodResolutionFunctionSize = 7; + + auto loadCCDBforIP = [&](const std::vector& paths, std::vector& targetVec, const std::string& name) { + if (paths.size() != mIPmethodResolutionFunctionSize) { + usepTcategorize.value = false; + LOG(info) << name << " does not have 7 entries. Disabling pT categorization (usepTcategorize = false)."; + resoFuncMatch = 0; + return; + } + for (int i = 0; i < mIPmethodResolutionFunctionSize; i++) { + targetVec.push_back(ccdbApi.retrieveFromTFileAny(paths[i], metadata, -1)); + } + }; + + if (usepTcategorize) { + switch (resoFuncMatch) { + case 6: + loadCCDBforIP(pathsCCDBforIPIncparameter, resoFuncIncCCDB, "pathsCCDBforIPIncparameter"); + break; + + case 7: + loadCCDBforIP(pathsCCDBforIPBeautyparameter, resoFuncBeautyCCDB, "pathsCCDBforIPBeautyparameter"); + loadCCDBforIP(pathsCCDBforIPCharmparameter, resoFuncCharmCCDB, "pathsCCDBforIPCharmparameter"); + loadCCDBforIP(pathsCCDBforIPLfparameter, resoFuncLfCCDB, "pathsCCDBforIPLfparameter"); + break; + + case 8: + loadCCDBforIP(pathsCCDBforIPDataparameter, resoFuncDataCCDB, "pathsCCDBforIPDataparameter"); + break; + + default: + LOG(info) << "resoFuncMatching is neither 6 nor 7, although usepTcategorize is set to true. Resetting resoFuncMatching to 0."; + resoFuncMatch = 0; + break; + } + } + + maxOrder = numCount + 1; // 0: untagged, >1 : N ordering + const int mIPmethodNumOfParameters = 9; + + // Set up the resolution function + 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; + for (size_t j = 0; j < resoFuncIncCCDB.size(); j++) { + std::vector params; + if (resoFuncIncCCDB[j]) { + for (int i = 0; i < mIPmethodNumOfParameters; i++) { + params.emplace_back(resoFuncIncCCDB[j]->GetParameter(i)); + } + } + vecParamsIncJetMcCCDB.emplace_back(params); + } + LOG(info) << "defined parameters of resolution function from CCDB"; + useResoFuncFromIncJet = true; + break; + case 7: // TODO + vecParamsData = (std::vector)paramsResoFuncData; + for (size_t j = 0; j < resoFuncBeautyCCDB.size(); j++) { + std::vector params; + if (resoFuncBeautyCCDB[j]) { + for (int i = 0; i < mIPmethodNumOfParameters; i++) { + params.emplace_back(resoFuncBeautyCCDB[j]->GetParameter(i)); + } + } + vecParamsBeautyJetMcCCDB.emplace_back(params); + } + for (size_t j = 0; j < resoFuncCharmCCDB.size(); j++) { + std::vector params; + if (resoFuncCharmCCDB[j]) { + for (int i = 0; i < mIPmethodNumOfParameters; i++) { + params.emplace_back(resoFuncCharmCCDB[j]->GetParameter(i)); + } + } + vecParamsCharmJetMcCCDB.emplace_back(params); + } + for (size_t j = 0; j < resoFuncLfCCDB.size(); j++) { + std::vector params; + if (resoFuncLfCCDB[j]) { + for (int i = 0; i < mIPmethodNumOfParameters; i++) { + params.emplace_back(resoFuncLfCCDB[j]->GetParameter(i)); + } + } + vecParamsLfJetMcCCDB.emplace_back(params); + } + LOG(info) << "defined parameters of resolution function from CCDB for each flavour"; + break; + case 8: + for (size_t j = 0; j < resoFuncDataCCDB.size(); j++) { + std::vector params; + if (resoFuncDataCCDB[j]) { + for (int i = 0; i < mIPmethodNumOfParameters; i++) { + params.emplace_back(resoFuncDataCCDB[j]->GetParameter(i)); + } + } + vecParamsDataJetCCDB.emplace_back(params); + } + LOG(info) << "defined parameters of resolution function from CCDB for data"; + 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 : vecParamsDataJetCCDB) { + vecfSignImpXYSigDataJetCCDB.emplace_back(jettaggingutilities::setResolutionFunction(params)); + } + for (const auto& params : vecParamsIncJetMcCCDB) { + vecfSignImpXYSigIncJetMcCCDB.emplace_back(jettaggingutilities::setResolutionFunction(params)); + } + for (const auto& params : vecParamsBeautyJetMcCCDB) { + vecfSignImpXYSigBeautyJetMcCCDB.emplace_back(jettaggingutilities::setResolutionFunction(params)); + } + for (const auto& params : vecParamsCharmJetMcCCDB) { + vecfSignImpXYSigCharmJetMcCCDB.emplace_back(jettaggingutilities::setResolutionFunction(params)); + } + for (const auto& params : vecParamsLfJetMcCCDB) { + vecfSignImpXYSigLfJetMcCCDB.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("h2_count_db", "#it{D}_{b} underflow/overflow;Jet flavour;#it{D}_{b} range", {HistType::kTH2F, {{4, 0., 4.}, {3, 0., 3.}}}); + auto h2CountDb = registry.get(HIST("h2_count_db")); + h2CountDb->GetXaxis()->SetBinLabel(1, "b-jet"); + h2CountDb->GetXaxis()->SetBinLabel(2, "c-jet"); + h2CountDb->GetXaxis()->SetBinLabel(3, "lf-jet"); + h2CountDb->GetXaxis()->SetBinLabel(4, "incl jet"); + h2CountDb->GetYaxis()->SetBinLabel(1, "underflow"); + h2CountDb->GetYaxis()->SetBinLabel(2, "in range"); + h2CountDb->GetYaxis()->SetBinLabel(3, "overflow"); + + 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, trackDcaXYMax, trackDcaZMax); + + 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); + } + + if (bMlResponse.getOutputNodes() > 1) { + auto mDb = [](const std::vector& scores, float fC) { + return std::log(scores[2] / (fC * scores[1] + (1 - fC) * scores[0])); + }; + + scoreML[analysisJet.globalIndex()] = useDb ? mDb(output, fC) : output[2]; // 2 is the b-jet index + } else { + 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, trackDcaXYMax, trackDcaZMax); + + 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 97% rename from PWGJE/TableProducer/jettrackderived.cxx rename to PWGJE/TableProducer/jetTrackDerived.cxx index 827ec6c1c15..9111ae36c3c 100644 --- a/PWGJE/TableProducer/jettrackderived.cxx +++ b/PWGJE/TableProducer/jetTrackDerived.cxx @@ -17,23 +17,32 @@ /// // O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/AnalysisDataModel.h" -#include "PWGJE/DataModel/Jet.h" -#include "Framework/StaticFor.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "PWGJE/DataModel/TrackJetQa.h" + #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "PWGJE/DataModel/TrackJetQa.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include using namespace o2; -using namespace o2::track; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/PWGJE/TableProducer/jetderiveddataproducer.cxx b/PWGJE/TableProducer/jetderiveddataproducer.cxx deleted file mode 100644 index a7dc17a1688..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducer.cxx +++ /dev/null @@ -1,392 +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" -#include "PWGJE/Core/JetHFUtilities.h" -#include "PWGJE/Core/JetV0Utilities.h" -#include "PWGJE/Core/JetDQUtilities.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 jTracksExtraTable; - 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 jLcCollisionIdsTable; - Produces jLcMcCollisionIdsTable; - Produces jLcIdsTable; - Produces jLcParticleIdsTable; - Produces jV0IdsTable; - Produces jV0McCollisionsTable; - Produces jV0McCollisionIdsTable; - Produces jV0McsTable; - Produces jV0McIdsTable; - Produces jDielectronCollisionIdsTable; - Produces jDielectronIdsTable; - Produces jDielectronMcCollisionsTable; - Produces jDielectronMcCollisionIdsTable; - Produces jDielectronMcsTable; - Produces jDielectronMcIdsTable; - - Preslice perClusterCells = aod::emcalclustercell::emcalclusterId; - Preslice perClusterTracks = aod::emcalclustercell::emcalclusterId; - - Service pdgDatabase; - - void init(InitContext const&) - { - } - - 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 processCollisionsALICE3(aod::Collision const& collision) - { - jCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), -1.0, -1.0, -1.0, 0); - jCollisionsParentIndexTable(collision.globalIndex()); - jCollisionsBunchCrossingIndexTable(-1); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processCollisionsALICE3, "produces derived collision tables for ALICE 3 simulations", 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)); - jTracksExtraTable(track.dcaXY(), track.dcaZ(), track.sigma1Pt()); // these need to be recalculated when we add the track to collision associator - 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 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)); - jMcClustersLabelTable(particleIds, amplitudeA); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processMcClusterLabels, "produces derived cluster particle label table", false); - - void processD0Collisions(aod::HfD0CollIds::iterator const& D0Collision) - { - jD0CollisionIdsTable(D0Collision.collisionId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processD0Collisions, "produces derived index for D0 collisions", false); - - void processD0McCollisions(aod::HfD0McCollIds::iterator const& D0McCollision) - { - jD0McCollisionIdsTable(D0McCollision.mcCollisionId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processD0McCollisions, "produces derived index for D0 MC collisions", false); - - void processD0(aod::HfD0Ids::iterator const& D0) - { - jD0IdsTable(D0.collisionId(), D0.prong0Id(), D0.prong1Id()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processD0, "produces derived index for D0 candidates", false); - - void processD0MC(aod::HfD0PIds::iterator const& D0) - { - jD0ParticleIdsTable(D0.mcCollisionId(), D0.mcParticleId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processD0MC, "produces derived index for D0 particles", false); - - void processLcCollisions(aod::Hf3PCollIds::iterator const& LcCollision) - { - jLcCollisionIdsTable(LcCollision.collisionId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processLcCollisions, "produces derived index for Lc collisions", false); - - void processLcMcCollisions(aod::Hf3PMcCollIds::iterator const& LcMcCollision) - { - jLcMcCollisionIdsTable(LcMcCollision.mcCollisionId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processLcMcCollisions, "produces derived index for Lc MC collisions", false); - - void processLc(aod::Hf3PIds::iterator const& Lc) - { - jLcIdsTable(Lc.collisionId(), Lc.prong0Id(), Lc.prong1Id(), Lc.prong2Id()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processLc, "produces derived index for Lc candidates", false); - - void processLcMC(aod::Hf3PPIds::iterator const& Lc) - { - jLcParticleIdsTable(Lc.mcCollisionId(), Lc.mcParticleId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processLcMC, "produces derived index for Lc particles", false); - - void processV0(aod::V0Indices::iterator const& V0) - { - jV0IdsTable(V0.collisionId(), V0.posTrackId(), V0.negTrackId()); - } - 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) { - jV0McCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); - 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()); - jV0McsTable(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)); - jV0McIdsTable(mcCollision.globalIndex(), particle.globalIndex(), mothersId, daughtersId); - } - } - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processV0MC, "produces V0 particles", false); - - void processDielectronCollisions(aod::ReducedEventsInfo::iterator const& DielectronCollision) - { - jDielectronCollisionIdsTable(DielectronCollision.collisionId()); - } - PROCESS_SWITCH(JetDerivedDataProducerTask, processDielectronCollisions, "produces derived index for Dielectron collisions", false); - - void processDielectron(aod::DielectronInfo const& Dielectron) - { - jDielectronIdsTable(Dielectron.collisionId(), Dielectron.prong0Id(), Dielectron.prong1Id()); - } - 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) { - jDielectronMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ()); - 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()); - jDielectronMcsTable(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? - jDielectronMcIdsTable(mcCollision.globalIndex(), particle.globalIndex(), mothersId, daughtersId); - } - } - } - 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/jetderiveddataproducerdummy.cxx b/PWGJE/TableProducer/jetderiveddataproducerdummy.cxx deleted file mode 100644 index efbd1fa4cf5..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducerdummy.cxx +++ /dev/null @@ -1,69 +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" -#include "PWGDQ/DataModel/ReducedInfoTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataProducerDummyTask { - - Produces d0CollisionsTable; - Produces d0CollisionsMatchingTable; - Produces d0sTable; - Produces d0ParsTable; - Produces d0ParExtrasTable; - Produces d0SelsTable; - Produces d0MlsTable; - Produces d0McsTable; - Produces d0McCollisionsTable; - Produces d0ParticlesTable; - - Produces lcCollisionsTable; - Produces lcCollisionsMatchingTable; - Produces lcsTable; - Produces lcParsTable; - Produces lcParExtrasTable; - Produces lcSelsTable; - Produces lcMlsTable; - Produces lcMcsTable; - Produces lcMcCollisionsTable; - Produces lcParticlesTable; - - Produces dielectronCollisionsTable; - Produces dielectronTable; - - 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 8b02d7cdeab..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducerdummyd0.cxx +++ /dev/null @@ -1,58 +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 and DQ tables needed when making D0 jet 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" -#include "PWGDQ/DataModel/ReducedInfoTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataProducerDummyD0Task { - - Produces lcCollisionsTable; - Produces lcCollisionsMatchingTable; - Produces lcsTable; - Produces lcParsTable; - Produces lcParExtrasTable; - Produces lcSelsTable; - Produces lcMlsTable; - Produces lcMcsTable; - Produces lcMcCollisionsTable; - Produces lcParticlesTable; - - Produces dielectronCollisionsTable; - Produces dielectronTable; - - 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/jetderiveddataproducerdummydielectron.cxx b/PWGJE/TableProducer/jetderiveddataproducerdummydielectron.cxx deleted file mode 100644 index 784fa3e4826..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducerdummydielectron.cxx +++ /dev/null @@ -1,66 +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 dielectron jet 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" -#include "PWGDQ/DataModel/ReducedInfoTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataProducerDummyDielectronTask { - - Produces d0CollisionsTable; - Produces d0CollisionsMatchingTable; - Produces d0sTable; - Produces d0ParsTable; - Produces d0ParExtrasTable; - Produces d0SelsTable; - Produces d0MlsTable; - Produces d0McsTable; - Produces d0McCollisionsTable; - Produces d0ParticlesTable; - - Produces lcCollisionsTable; - Produces lcCollisionsMatchingTable; - Produces lcsTable; - Produces lcParsTable; - Produces lcParExtrasTable; - Produces lcSelsTable; - Produces lcMlsTable; - Produces lcMcsTable; - Produces lcMcCollisionsTable; - Produces lcParticlesTable; - - void init(InitContext const&) - { - } - - void processDummy(aod::JDummys const&) - { - } - PROCESS_SWITCH(JetDerivedDataProducerDummyDielectronTask, processDummy, "leaves all tables empty", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"jet-deriveddata-producer-dummy-dielectron"})}; -} diff --git a/PWGJE/TableProducer/jetderiveddataproducerdummylc.cxx b/PWGJE/TableProducer/jetderiveddataproducerdummylc.cxx deleted file mode 100644 index 05e1384deac..00000000000 --- a/PWGJE/TableProducer/jetderiveddataproducerdummylc.cxx +++ /dev/null @@ -1,58 +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 and DQ tables needed when making Lc jet 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" -#include "PWGDQ/DataModel/ReducedInfoTables.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct JetDerivedDataProducerDummyLcTask { - - Produces d0CollisionsTable; - Produces d0CollisionsMatchingTable; - Produces d0sTable; - Produces d0ParsTable; - Produces d0ParExtrasTable; - Produces d0SelsTable; - Produces d0MlsTable; - Produces d0McsTable; - Produces d0McCollisionsTable; - Produces d0ParticlesTable; - - Produces dielectronCollisionsTable; - Produces dielectronTable; - - 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 c9c228a3601..00000000000 --- a/PWGJE/TableProducer/jetderiveddatawriter.cxx +++ /dev/null @@ -1,938 +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/Core/JetDQUtilities.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 { - - struct : ConfigurableGroup { - 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 neutral jet pt to accept event"}; - Configurable neutralMCPJetPtMin{"neutralMCPJetPtMin", 0.0, "Minimum neutal mcp jet pt to accept event"}; - Configurable fullJetPtMin{"fullJetPtMin", 0.0, "Minimum full jet pt to accept event"}; - Configurable fullMCPJetPtMin{"fullMCPJetPtMin", 0.0, "Minimum full mcp jet pt to accept event"}; - Configurable chargedD0JetPtMin{"chargedD0JetPtMin", 0.0, "Minimum charged D0 jet pt to accept event"}; - Configurable chargedEventWiseSubtractedD0JetPtMin{"chargedEventWiseSubtractedD0JetPtMin", 0.0, "Minimum charged event-wise subtracted D0 jet pt to accept event"}; - Configurable chargedD0MCPJetPtMin{"chargedD0MCPJetPtMin", 0.0, "Minimum charged D0 mcp jet pt to accept event"}; - Configurable chargedLcJetPtMin{"chargedLcJetPtMin", 0.0, "Minimum charged Lc jet pt to accept event"}; - Configurable chargedEventWiseSubtractedLcJetPtMin{"chargedEventWiseSubtractedLcJetPtMin", 0.0, "Minimum charged event-wise subtracted Lc jet pt to accept event"}; - Configurable chargedLcMCPJetPtMin{"chargedLcMCPJetPtMin", 0.0, "Minimum charged Lc mcp jet pt to accept event"}; - Configurable chargedDielectronJetPtMin{"chargedDielectronJetPtMin", 0.0, "Minimum charged Dielectron jet pt to accept event"}; - Configurable chargedEventWiseSubtractedDielectronJetPtMin{"chargedEventWiseSubtractedDielectronJetPtMin", 0.0, "Minimum charged event-wise subtracted Dielectron jet pt to accept event"}; - Configurable chargedDielectronMCPJetPtMin{"chargedDielectronMCPJetPtMin", 0.0, "Minimum charged Dielectron mcp 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"}; - Configurable saveDielectronTable{"saveDielectronTable", false, "save the Dielectron table to the output"}; - - Configurable eventSelectionForCounting{"eventSelectionForCounting", "sel8", "choose event selection for collision counter"}; - } config; - - struct : ProducesGroup { - 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 storedJTracksExtraTable; - Produces storedJTracksParentIndexTable; - Produces storedJMcTracksLabelTable; - Produces storedJMcParticlesTable; - Produces storedJParticlesParentIndexTable; - Produces storedJClustersTable; - Produces storedJClustersParentIndexTable; - Produces storedJClustersMatchedTracksTable; - Produces storedJMcClustersLabelTable; - - Produces storedD0CollisionsTable; - Produces storedD0CollisionIdsTable; - Produces storedD0sTable; - Produces storedD0ParsTable; - Produces storedD0ParExtrasTable; - Produces storedD0SelsTable; - Produces storedD0MlsTable; - Produces storedD0McsTable; - Produces storedD0IdsTable; - Produces storedD0McCollisionsTable; - Produces storedD0McCollisionIdsTable; - Produces storedD0McCollisionsMatchingTable; - Produces storedD0ParticlesTable; - Produces storedD0ParticleIdsTable; - - Produces storedLcCollisionsTable; - Produces storedLcCollisionIdsTable; - Produces storedLcsTable; - Produces storedLcParsTable; - Produces storedLcParExtrasTable; - Produces storedLcSelsTable; - Produces storedLcMlsTable; - Produces storedLcMcsTable; - Produces storedLcIdsTable; - Produces storedLcMcCollisionsTable; - Produces storedLcMcCollisionIdsTable; - Produces storedLcMcCollisionsMatchingTable; - Produces storedLcParticlesTable; - Produces storedLcParticleIdsTable; - - Produces storedDielectronCollisionsTable; - Produces storedDielectronCollisionIdsTable; - Produces storedDielectronsTable; - Produces storedDielectronIdsTable; - Produces storedDielectronMcCollisionsTable; - Produces storedDielectronMcCollisionIdsTable; - // Produces storedD0McCollisionsMatchingTable; //this doesnt exist for Dileptons yet - Produces storedDielectronParticlesTable; - Produces storedDielectronParticleIdsTable; - } products; - - PresliceUnsorted> CollisionsPerMcCollision = aod::jmccollisionlb::mcCollisionId; - PresliceUnsorted> ParticlesPerMcCollision = aod::jmcparticle::mcCollisionId; - Preslice> TracksPerCollision = aod::jtrack::collisionId; - Preslice> ClustersPerCollision = aod::jcluster::collisionId; - Preslice> D0McCollisionsPerMcCollision = aod::jd0indices::mcCollisionId; - Preslice> LcMcCollisionsPerMcCollision = aod::jlcindices::mcCollisionId; - Preslice DielectronMcCollisionsPerMcCollision = aod::jdielectronindices::mcCollisionId; - Preslice D0CollisionsPerCollision = aod::jd0indices::collisionId; - Preslice LcCollisionsPerCollision = aod::jlcindices::collisionId; - Preslice DielectronCollisionsPerCollision = aod::jdielectronindices::collisionId; - Preslice D0sPerCollision = aod::jd0indices::collisionId; - Preslice LcsPerCollision = aod::jlcindices::collisionId; - Preslice DielectronsPerCollision = aod::jdielectronindices::collisionId; - - std::vector collisionFlag; - std::vector McCollisionFlag; - std::vector bcIndicies; - - uint32_t precisionPositionMask; - uint32_t precisionMomentumMask; - - int eventSelection = -1; - 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 - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(config.eventSelectionForCounting)); - } - - bool acceptCollision(aod::JCollision const&) - { - return true; - } - - void processCollisions(aod::JCollisions const& collisions) - { - collisionFlag.clear(); - collisionFlag.resize(collisions.size()); - std::fill(collisionFlag.begin(), collisionFlag.end(), false); - } - - void processMcCollisions(aod::JMcCollisions const& Mccollisions) - { - McCollisionFlag.clear(); - 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 = config.chargedJetPtMin; - } else if constexpr (std::is_same_v, aod::ChargedEventWiseSubtractedJets> || std::is_same_v, aod::ChargedMCDetectorLevelEventWiseSubtractedJets>) { - jetPtMin = config.chargedEventWiseSubtractedJetPtMin; - } else if constexpr (std::is_same_v, aod::ChargedMCParticleLevelJets>) { - jetPtMin = config.chargedMCPJetPtMin; - } else if constexpr (std::is_same_v, aod::NeutralJets> || std::is_same_v, aod::NeutralMCDetectorLevelJets>) { - jetPtMin = config.neutralJetPtMin; - } else if constexpr (std::is_same_v, aod::NeutralMCParticleLevelJets>) { - jetPtMin = config.neutralMCPJetPtMin; - } else if constexpr (std::is_same_v, aod::FullJets> || std::is_same_v, aod::FullMCDetectorLevelJets>) { - jetPtMin = config.fullJetPtMin; - } else if constexpr (std::is_same_v, aod::FullMCParticleLevelJets>) { - jetPtMin = config.fullMCPJetPtMin; - } else if constexpr (std::is_same_v, aod::D0ChargedJets> || std::is_same_v, aod::D0ChargedMCDetectorLevelJets>) { - jetPtMin = config.chargedD0JetPtMin; - } else if constexpr (std::is_same_v, aod::D0ChargedEventWiseSubtractedJets> || std::is_same_v, aod::D0ChargedMCDetectorLevelEventWiseSubtractedJets>) { - jetPtMin = config.chargedEventWiseSubtractedD0JetPtMin; - } else if constexpr (std::is_same_v, aod::D0ChargedMCParticleLevelJets>) { - jetPtMin = config.chargedD0MCPJetPtMin; - } else if constexpr (std::is_same_v, aod::LcChargedJets> || std::is_same_v, aod::LcChargedMCDetectorLevelJets>) { - jetPtMin = config.chargedLcJetPtMin; - } else if constexpr (std::is_same_v, aod::LcChargedEventWiseSubtractedJets> || std::is_same_v, aod::LcChargedMCDetectorLevelEventWiseSubtractedJets>) { - jetPtMin = config.chargedEventWiseSubtractedLcJetPtMin; - } else if constexpr (std::is_same_v, aod::LcChargedMCParticleLevelJets>) { - jetPtMin = config.chargedLcMCPJetPtMin; - } else if constexpr (std::is_same_v, aod::DielectronChargedJets> || std::is_same_v, aod::DielectronChargedMCDetectorLevelJets>) { - jetPtMin = config.chargedDielectronJetPtMin; - } else if constexpr (std::is_same_v, aod::DielectronChargedEventWiseSubtractedJets> || std::is_same_v, aod::DielectronChargedMCDetectorLevelEventWiseSubtractedJets>) { - jetPtMin = config.chargedEventWiseSubtractedDielectronJetPtMin; - } else if constexpr (std::is_same_v, aod::DielectronChargedMCParticleLevelJets>) { - jetPtMin = config.chargedDielectronMCPJetPtMin; - } 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> || std::is_same_v, aod::DielectronChargedMCParticleLevelJets>) { - McCollisionFlag[jet.mcCollisionId()] = true; - } else { - collisionFlag[jet.collisionId()] = true; - } - } - } - } - // Todo : Check memory consumption of having so many Process Switches - 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, processChargedMCDetectorLevelEventWiseSubtractedJets, "process charged event-wise subtracted 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, processNeutralMCDJets, "process neutral mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processNeutralMCPJets, "process neutral mcp jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processFullJets, "process full jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processFullMCDJets, "process full mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processFullMCPJets, "process full mcp 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, processD0ChargedMCDJets, "process D0 charged mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processD0ChargedMCDetectorLevelEventWiseSubtractedJets, "process D0 event-wise subtracted charged mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processD0ChargedMCPJets, "process D0 charged mcp 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); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processLcChargedMCDJets, "process Lc charged mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processLcChargedMCDetectorLevelEventWiseSubtractedJets, "process Lc event-wise subtracted charged mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processLcChargedMCPJets, "process Lc charged mcp jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processDielectronChargedJets, "process Dielectron charged jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processDielectronChargedEventWiseSubtractedJets, "process Dielectron event-wise subtracted charged jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processDielectronChargedMCDJets, "process Dielectron charged mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processDielectronChargedMCDetectorLevelEventWiseSubtractedJets, "process Dielectron event-wise subtracted charged mcd jets", false); - PROCESS_SWITCH_FULL(JetDerivedDataWriter, processJets, processDielectronChargedMCPJets, "process Dielectron charged mcp jets", false); - - void processDummyTable(aod::JDummys const&) - { - products.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 readSelectedCollisionCounter = 0; - int writtenCollisionCounter = 0; - for (const auto& collision : collisions) { - readCollisionCounter++; - if (jetderiveddatautilities::selectCollision(collision, eventSelection)) { - readSelectedCollisionCounter++; - } - if (collisionFlag[collision.globalIndex()]) { - writtenCollisionCounter++; - } - } - std::vector previousReadCounts; - std::vector previousReadSelectedCounts; - std::vector previousWrittenCounts; - int iPreviousDataFrame = 0; - for (const auto& collisionCount : collisionCounts) { - auto readCollisionCounterSpan = collisionCount.readCounts(); - auto readSelectedCollisionCounterSpan = collisionCount.readSelectedCounts(); - auto writtenCollisionCounterSpan = collisionCount.writtenCounts(); - if (iPreviousDataFrame == 0) { - std::copy(readCollisionCounterSpan.begin(), readCollisionCounterSpan.end(), std::back_inserter(previousReadCounts)); - std::copy(readSelectedCollisionCounterSpan.begin(), readSelectedCollisionCounterSpan.end(), std::back_inserter(previousReadSelectedCounts)); - std::copy(writtenCollisionCounterSpan.begin(), writtenCollisionCounterSpan.end(), std::back_inserter(previousWrittenCounts)); - } else { - for (unsigned int i = 0; i < previousReadCounts.size(); i++) { - previousReadCounts[i] += readCollisionCounterSpan[i]; - previousReadSelectedCounts[i] += readSelectedCollisionCounterSpan[i]; - previousWrittenCounts[i] += writtenCollisionCounterSpan[i]; - } - } - iPreviousDataFrame++; - } - previousReadCounts.push_back(readCollisionCounter); - previousReadSelectedCounts.push_back(readSelectedCollisionCounter); - previousWrittenCounts.push_back(writtenCollisionCounter); - products.storedCollisionCountsTable(previousReadCounts, previousReadSelectedCounts, 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, CollisionsD0 const& D0Collisions, CandidatesD0Data const& D0s, CollisionsLc const& LcCollisions, CandidatesLcData const& Lcs, CollisionsDielectron const& DielectronCollisions, CandidatesDielectronData const& Dielectrons) - { - std::map bcMapping; - std::map trackMapping; - - if (collisionFlag[collision.globalIndex()]) { - if (config.saveBCsTable) { - auto bc = collision.bc_as>(); - if (std::find(bcIndicies.begin(), bcIndicies.end(), bc.globalIndex()) == bcIndicies.end()) { - products.storedJBCsTable(bc.runNumber(), bc.globalBC(), bc.timestamp()); - products.storedJBCParentIndexTable(bc.bcId()); - bcIndicies.push_back(bc.globalIndex()); - bcMapping.insert(std::make_pair(bc.globalIndex(), products.storedJBCsTable.lastIndex())); - } - } - - products.storedJCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multiplicity(), collision.centrality(), collision.eventSel(), collision.alias_raw()); - products.storedJCollisionsParentIndexTable(collision.collisionId()); - if (config.saveBCsTable) { - int32_t storedBCID = -1; - auto JBCIndex = bcMapping.find(collision.bcId()); - if (JBCIndex != bcMapping.end()) { - storedBCID = JBCIndex->second; - } - products.storedJCollisionsBunchCrossingIndexTable(storedBCID); - } - products.storedJChargedTriggerSelsTable(collision.chargedTriggerSel()); - products.storedJFullTriggerSelsTable(collision.fullTriggerSel()); - products.storedJChargedHFTriggerSelsTable(collision.chargedHFTriggerSel()); - - for (const auto& track : tracks) { - 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 - continue; - } - products.storedJTracksTable(products.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()); - products.storedJTracksExtraTable(o2::math_utils::detail::truncateFloatFraction(track.dcaXY(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.dcaZ(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.sigma1Pt(), precisionMomentumMask)); - products.storedJTracksParentIndexTable(track.trackId()); - trackMapping.insert(std::make_pair(track.globalIndex(), products.storedJTracksTable.lastIndex())); - } - if (config.saveClustersTable) { - for (const auto& cluster : clusters) { - products.storedJClustersTable(products.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()); - products.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); - } - } - products.storedJClustersMatchedTracksTable(clusterStoredJTrackIDs); - } - } - - if (config.saveD0Table) { - int32_t collisionD0Index = -1; - for (const auto& D0Collision : D0Collisions) { // should only ever be one - jethfutilities::fillD0CollisionTable(D0Collision, products.storedD0CollisionsTable, collisionD0Index); - products.storedD0CollisionIdsTable(products.storedJCollisionsTable.lastIndex()); - } - for (const auto& D0 : D0s) { - int32_t D0Index = -1; - jethfutilities::fillD0CandidateTable(D0, collisionD0Index, products.storedD0sTable, products.storedD0ParsTable, products.storedD0ParExtrasTable, products.storedD0SelsTable, products.storedD0MlsTable, products.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; - } - products.storedD0IdsTable(products.storedJCollisionsTable.lastIndex(), prong0Id, prong1Id); - } - } - - if (config.saveLcTable) { - int32_t collisionLcIndex = -1; - for (const auto& LcCollision : LcCollisions) { // should only ever be one - jethfutilities::fillLcCollisionTable(LcCollision, products.storedLcCollisionsTable, collisionLcIndex); - products.storedLcCollisionIdsTable(products.storedJCollisionsTable.lastIndex()); - } - for (const auto& Lc : Lcs) { - int32_t LcIndex = -1; - jethfutilities::fillLcCandidateTable(Lc, collisionLcIndex, products.storedLcsTable, products.storedLcParsTable, products.storedLcParExtrasTable, products.storedLcSelsTable, products.storedLcMlsTable, products.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; - } - products.storedLcIdsTable(products.storedJCollisionsTable.lastIndex(), prong0Id, prong1Id, prong2Id); - } - } - if (config.saveDielectronTable) { - int32_t collisionDielectronIndex = -1; - for (const auto& DielectronCollision : DielectronCollisions) { // should only ever be one - jetdqutilities::fillDielectronCollisionTable(DielectronCollision, products.storedDielectronCollisionsTable, collisionDielectronIndex); - products.storedDielectronCollisionIdsTable(products.storedJCollisionsTable.lastIndex()); - } - for (const auto& Dielectron : Dielectrons) { - int32_t DielectronIndex = -1; - jetdqutilities::fillDielectronCandidateTable(Dielectron, collisionDielectronIndex, products.storedDielectronsTable, DielectronIndex); - - int32_t prong0Id = -1; - int32_t prong1Id = -1; - auto JtrackIndex = trackMapping.find(Dielectron.prong0Id()); - if (JtrackIndex != trackMapping.end()) { - prong0Id = JtrackIndex->second; - } - JtrackIndex = trackMapping.find(Dielectron.prong1Id()); - if (JtrackIndex != trackMapping.end()) { - prong1Id = JtrackIndex->second; - } - products.storedDielectronIdsTable(products.storedJCollisionsTable.lastIndex(), prong0Id, prong1Id); - } - } - } - } - // 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, CollisionsD0 const& D0Collisions, CandidatesD0MCD const& D0s, soa::Join const& D0McCollisions, CandidatesD0MCP const& D0Particles, CollisionsLc const& LcCollisions, CandidatesLcMCD const& Lcs, soa::Join const& LcMcCollisions, CandidatesLcMCP const& LcParticles, CollisionsDielectron const& DielectronCollisions, CandidatesDielectronMCD const& Dielectrons, McCollisionsDielectron const& DielectronMcCollisions, CandidatesDielectronMCP const& DielectronParticles) - { - std::map bcMapping; - std::map paticleMapping; - std::map mcCollisionMapping; - std::map D0CollisionMapping; - std::map LcCollisionMapping; - 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()); - - products.storedJMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.weight()); - products.storedJMcCollisionsParentIndexTable(mcCollision.mcCollisionId()); - mcCollisionMapping.insert(std::make_pair(mcCollision.globalIndex(), products.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++; - } - } - products.storedJMcParticlesTable(products.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); - products.storedJParticlesParentIndexTable(particle.mcParticleId()); - } - - if (config.saveD0Table) { - const auto d0McCollisionsPerMcCollision = D0McCollisions.sliceBy(D0McCollisionsPerMcCollision, mcCollision.globalIndex()); - int32_t mcCollisionD0Index = -1; - for (const auto& d0McCollisionPerMcCollision : d0McCollisionsPerMcCollision) { // should only ever be one - jethfutilities::fillD0McCollisionTable(d0McCollisionPerMcCollision, products.storedD0McCollisionsTable, mcCollisionD0Index); - products.storedD0McCollisionIdsTable(products.storedJMcCollisionsTable.lastIndex()); - } - for (const auto& D0Particle : D0Particles) { - int32_t D0ParticleIndex = -1; - jethfutilities::fillD0CandidateMcTable(D0Particle, mcCollisionD0Index, products.storedD0ParticlesTable, D0ParticleIndex); - int32_t D0ParticleId = -1; - auto JParticleIndex = paticleMapping.find(D0Particle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - D0ParticleId = JParticleIndex->second; - } - products.storedD0ParticleIdsTable(products.storedJMcCollisionsTable.lastIndex(), D0ParticleId); - } - } - - if (config.saveLcTable) { - const auto lcMcCollisionsPerMcCollision = LcMcCollisions.sliceBy(LcMcCollisionsPerMcCollision, mcCollision.globalIndex()); - int32_t mcCollisionLcIndex = -1; - for (const auto& lcMcCollisionPerMcCollision : lcMcCollisionsPerMcCollision) { // should only ever be one - jethfutilities::fillLcMcCollisionTable(lcMcCollisionPerMcCollision, products.storedLcMcCollisionsTable, mcCollisionLcIndex); - products.storedLcMcCollisionIdsTable(products.storedJMcCollisionsTable.lastIndex()); - } - for (const auto& LcParticle : LcParticles) { - int32_t LcParticleIndex = -1; - jethfutilities::fillLcCandidateMcTable(LcParticle, mcCollisionLcIndex, products.storedLcParticlesTable, LcParticleIndex); - int32_t LcParticleId = -1; - auto JParticleIndex = paticleMapping.find(LcParticle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - LcParticleId = JParticleIndex->second; - } - products.storedLcParticleIdsTable(products.storedJMcCollisionsTable.lastIndex(), LcParticleId); - } - } - if (config.saveDielectronTable) { - const auto dielectronMcCollisionsPerMcCollision = DielectronMcCollisions.sliceBy(DielectronMcCollisionsPerMcCollision, mcCollision.globalIndex()); - int32_t mcCollisionDielectronIndex = -1; - for (const auto& dielectronMcCollisionPerMcCollision : dielectronMcCollisionsPerMcCollision) { // should only ever be one - jetdqutilities::fillDielectronMcCollisionTable(dielectronMcCollisionPerMcCollision, products.storedDielectronMcCollisionsTable, mcCollisionDielectronIndex); - products.storedDielectronMcCollisionIdsTable(products.storedJMcCollisionsTable.lastIndex()); - } - for (const auto& DielectronParticle : DielectronParticles) { - int32_t DielectronParticleIndex = -1; - jetdqutilities::fillDielectronCandidateMcTable(DielectronParticle, mcCollisionDielectronIndex, products.storedDielectronParticlesTable, DielectronParticleIndex); - int32_t DielectronParticleId = -1; - auto JParticleIndex = paticleMapping.find(DielectronParticle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - DielectronParticleId = JParticleIndex->second; - } - std::vector DielectronMothersId; - int DielectronDaughtersId[2]; - if (DielectronParticle.has_mothers()) { - for (auto const& DielectronMother : DielectronParticle.template mothers_as>()) { - auto JDielectronMotherIndex = paticleMapping.find(DielectronMother.globalIndex()); - if (JDielectronMotherIndex != paticleMapping.end()) { - DielectronMothersId.push_back(JDielectronMotherIndex->second); - } - } - } - auto i = 0; - if (DielectronParticle.has_daughters()) { - for (auto const& DielectronDaughter : DielectronParticle.template daughters_as>()) { - if (i > 1) { - break; - } - auto JDielectronDaughterIndex = paticleMapping.find(DielectronDaughter.globalIndex()); - if (JDielectronDaughterIndex != paticleMapping.end()) { - DielectronDaughtersId[i] = JDielectronDaughterIndex->second; - } - i++; - } - } - products.storedDielectronParticleIdsTable(products.storedJMcCollisionsTable.lastIndex(), DielectronParticleId, DielectronMothersId, DielectronDaughtersId); - } - } - } - } - - 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 (config.saveBCsTable) { - auto bc = collision.bc_as>(); - if (std::find(bcIndicies.begin(), bcIndicies.end(), bc.globalIndex()) == bcIndicies.end()) { - products.storedJBCsTable(bc.runNumber(), bc.globalBC(), bc.timestamp()); - products.storedJBCParentIndexTable(bc.bcId()); - bcIndicies.push_back(bc.globalIndex()); - bcMapping.insert(std::make_pair(bc.globalIndex(), products.storedJBCsTable.lastIndex())); - } - } - - products.storedJCollisionsTable(collision.posX(), collision.posY(), collision.posZ(), collision.multiplicity(), collision.centrality(), collision.eventSel(), collision.alias_raw()); - products.storedJCollisionsParentIndexTable(collision.collisionId()); - - auto JMcCollisionIndex = mcCollisionMapping.find(mcCollision.globalIndex()); - if (JMcCollisionIndex != mcCollisionMapping.end()) { - products.storedJMcCollisionsLabelTable(JMcCollisionIndex->second); - } - if (config.saveBCsTable) { - int32_t storedBCID = -1; - auto JBCIndex = bcMapping.find(collision.bcId()); - if (JBCIndex != bcMapping.end()) { - storedBCID = JBCIndex->second; - } - products.storedJCollisionsBunchCrossingIndexTable(storedBCID); - } - products.storedJChargedTriggerSelsTable(collision.chargedTriggerSel()); - products.storedJFullTriggerSelsTable(collision.fullTriggerSel()); - products.storedJChargedHFTriggerSelsTable(collision.chargedHFTriggerSel()); - - const auto tracksPerCollision = tracks.sliceBy(TracksPerCollision, collision.globalIndex()); - for (const auto& track : tracksPerCollision) { - 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 - continue; - } - products.storedJTracksTable(products.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()); - products.storedJTracksExtraTable(o2::math_utils::detail::truncateFloatFraction(track.dcaXY(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.dcaZ(), precisionPositionMask), o2::math_utils::detail::truncateFloatFraction(track.sigma1Pt(), precisionMomentumMask)); - products.storedJTracksParentIndexTable(track.trackId()); - - if (track.has_mcParticle()) { - auto JParticleIndex = paticleMapping.find(track.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - products.storedJMcTracksLabelTable(JParticleIndex->second); - } else { - products.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 { - products.storedJMcTracksLabelTable(-1); - } - trackMapping.insert(std::make_pair(track.globalIndex(), products.storedJTracksTable.lastIndex())); - } - if (config.saveClustersTable) { - const auto clustersPerCollision = clusters.sliceBy(ClustersPerCollision, collision.globalIndex()); - for (const auto& cluster : clustersPerCollision) { - products.storedJClustersTable(products.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()); - products.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); - } - } - products.storedJClustersMatchedTracksTable(clusterStoredJTrackIDs); - - std::vector clusterStoredJParticleIDs; - for (const auto& clusterParticleId : cluster.mcParticleIds()) { - auto JParticleIndex = paticleMapping.find(clusterParticleId); - if (JParticleIndex != paticleMapping.end()) { - clusterStoredJParticleIDs.push_back(JParticleIndex->second); - } - } - std::vector amplitudeA; - auto amplitudeASpan = cluster.amplitudeA(); - std::copy(amplitudeASpan.begin(), amplitudeASpan.end(), std::back_inserter(amplitudeA)); - products.storedJMcClustersLabelTable(clusterStoredJParticleIDs, amplitudeA); - } - } - - if (config.saveD0Table) { - const auto d0CollisionsPerCollision = D0Collisions.sliceBy(D0CollisionsPerCollision, collision.globalIndex()); - int32_t collisionD0Index = -1; - for (const auto& d0CollisionPerCollision : d0CollisionsPerCollision) { // should only ever be one - jethfutilities::fillD0CollisionTable(d0CollisionPerCollision, products.storedD0CollisionsTable, collisionD0Index); - products.storedD0CollisionIdsTable(products.storedJCollisionsTable.lastIndex()); - D0CollisionMapping.insert(std::make_pair(d0CollisionPerCollision.globalIndex(), products.storedD0CollisionsTable.lastIndex())); - } - const auto d0sPerCollision = D0s.sliceBy(D0sPerCollision, collision.globalIndex()); - for (const auto& D0 : d0sPerCollision) { - int32_t D0Index = -1; - jethfutilities::fillD0CandidateTable(D0, collisionD0Index, products.storedD0sTable, products.storedD0ParsTable, products.storedD0ParExtrasTable, products.storedD0SelsTable, products.storedD0MlsTable, products.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; - } - products.storedD0IdsTable(products.storedJCollisionsTable.lastIndex(), prong0Id, prong1Id); - } - } - - if (config.saveLcTable) { - const auto lcCollisionsPerCollision = LcCollisions.sliceBy(LcCollisionsPerCollision, collision.globalIndex()); - int32_t collisionLcIndex = -1; - for (const auto& lcCollisionPerCollision : lcCollisionsPerCollision) { // should only ever be one - jethfutilities::fillLcCollisionTable(lcCollisionPerCollision, products.storedLcCollisionsTable, collisionLcIndex); - products.storedLcCollisionIdsTable(products.storedJCollisionsTable.lastIndex()); - LcCollisionMapping.insert(std::make_pair(lcCollisionPerCollision.globalIndex(), products.storedLcCollisionsTable.lastIndex())); - } - const auto lcsPerCollision = Lcs.sliceBy(LcsPerCollision, collision.globalIndex()); - for (const auto& Lc : lcsPerCollision) { - int32_t LcIndex = -1; - jethfutilities::fillLcCandidateTable(Lc, collisionLcIndex, products.storedLcsTable, products.storedLcParsTable, products.storedLcParExtrasTable, products.storedLcSelsTable, products.storedLcMlsTable, products.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; - } - products.storedLcIdsTable(products.storedJCollisionsTable.lastIndex(), prong0Id, prong1Id, prong2Id); - } - } - - if (config.saveDielectronTable) { - const auto dielectronCollisionsPerCollision = DielectronCollisions.sliceBy(DielectronCollisionsPerCollision, collision.globalIndex()); - int32_t collisionDielectronIndex = -1; - for (const auto& dielectronCollisionPerCollision : dielectronCollisionsPerCollision) { // should only ever be one - jetdqutilities::fillDielectronCollisionTable(dielectronCollisionPerCollision, products.storedDielectronCollisionsTable, collisionDielectronIndex); - products.storedDielectronCollisionIdsTable(products.storedJCollisionsTable.lastIndex()); - // D0CollisionMapping.insert(std::make_pair(d0CollisionPerCollision.globalIndex(), products.storedD0CollisionsTable.lastIndex())); // if DielectronMCCollisions are indexed to Dielectron Collisions then this can be added - } - const auto dielectronsPerCollision = Dielectrons.sliceBy(DielectronsPerCollision, collision.globalIndex()); - for (const auto& Dielectron : dielectronsPerCollision) { - int32_t DielectronIndex = -1; - jetdqutilities::fillDielectronCandidateTable(Dielectron, collisionDielectronIndex, products.storedDielectronsTable, DielectronIndex); - - int32_t prong0Id = -1; - int32_t prong1Id = -1; - auto JtrackIndex = trackMapping.find(Dielectron.prong0Id()); - if (JtrackIndex != trackMapping.end()) { - prong0Id = JtrackIndex->second; - } - JtrackIndex = trackMapping.find(Dielectron.prong1Id()); - if (JtrackIndex != trackMapping.end()) { - prong1Id = JtrackIndex->second; - } - products.storedDielectronIdsTable(products.storedJCollisionsTable.lastIndex(), prong0Id, prong1Id); - } - } - } - - if (config.saveD0Table) { - const auto d0McCollisionsPerMcCollision = D0McCollisions.sliceBy(D0McCollisionsPerMcCollision, mcCollision.globalIndex()); - for (const auto& d0McCollisionPerMcCollision : d0McCollisionsPerMcCollision) { // should just be one - std::vector d0CollisionIDs; - for (auto const& d0CollisionPerMcCollision : d0McCollisionPerMcCollision.template hfCollBases_as()) { - auto d0CollisionIndex = D0CollisionMapping.find(d0CollisionPerMcCollision.globalIndex()); - if (d0CollisionIndex != D0CollisionMapping.end()) { - d0CollisionIDs.push_back(d0CollisionIndex->second); - } - } - products.storedD0McCollisionsMatchingTable(d0CollisionIDs); - } - } - - if (config.saveLcTable) { - const auto lcMcCollisionsPerMcCollision = LcMcCollisions.sliceBy(LcMcCollisionsPerMcCollision, mcCollision.globalIndex()); - for (const auto& lcMcCollisionPerMcCollision : lcMcCollisionsPerMcCollision) { // should just be one - std::vector lcCollisionIDs; - for (auto const& lcCollisionPerMcCollision : lcMcCollisionPerMcCollision.template hfCollBases_as()) { - auto lcCollisionIndex = LcCollisionMapping.find(lcCollisionPerMcCollision.globalIndex()); - if (lcCollisionIndex != LcCollisionMapping.end()) { - lcCollisionIDs.push_back(lcCollisionIndex->second); - } - } - products.storedLcMcCollisionsMatchingTable(lcCollisionIDs); - } - } - } - } - } - // 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, McCollisionsD0 const& D0McCollisions, CandidatesD0MCP const& D0Particles, McCollisionsLc const& LcMcCollisions, CandidatesLcMCP const& LcParticles, McCollisionsDielectron const& DielectronMcCollisions, CandidatesDielectronMCP const& DielectronParticles) - { - - 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; - - products.storedJMcCollisionsTable(mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), mcCollision.weight()); - products.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++; - } - } - products.storedJMcParticlesTable(products.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); - products.storedJParticlesParentIndexTable(particle.mcParticleId()); - } - - if (config.saveD0Table) { - const auto d0McCollisionsPerMcCollision = D0McCollisions.sliceBy(D0McCollisionsPerMcCollision, mcCollision.globalIndex()); - int32_t mcCollisionD0Index = -1; - for (const auto& d0McCollisionPerMcCollision : d0McCollisionsPerMcCollision) { // should only ever be one - jethfutilities::fillD0McCollisionTable(d0McCollisionPerMcCollision, products.storedD0McCollisionsTable, mcCollisionD0Index); - products.storedD0McCollisionIdsTable(products.storedJMcCollisionsTable.lastIndex()); - } - for (const auto& D0Particle : D0Particles) { - int32_t D0ParticleIndex = -1; - jethfutilities::fillD0CandidateMcTable(D0Particle, mcCollisionD0Index, products.storedD0ParticlesTable, D0ParticleIndex); - int32_t D0ParticleId = -1; - auto JParticleIndex = paticleMapping.find(D0Particle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - D0ParticleId = JParticleIndex->second; - } - products.storedD0ParticleIdsTable(products.storedJMcCollisionsTable.lastIndex(), D0ParticleId); - } - } - if (config.saveLcTable) { - const auto lcMcCollisionsPerMcCollision = LcMcCollisions.sliceBy(LcMcCollisionsPerMcCollision, mcCollision.globalIndex()); - int32_t mcCollisionLcIndex = -1; - for (const auto& lcMcCollisionPerMcCollision : lcMcCollisionsPerMcCollision) { // should only ever be one - jethfutilities::fillLcMcCollisionTable(lcMcCollisionPerMcCollision, products.storedLcMcCollisionsTable, mcCollisionLcIndex); - products.storedLcMcCollisionIdsTable(products.storedJMcCollisionsTable.lastIndex()); - } - for (const auto& LcParticle : LcParticles) { - int32_t LcParticleIndex = -1; - jethfutilities::fillLcCandidateMcTable(LcParticle, mcCollisionLcIndex, products.storedLcParticlesTable, LcParticleIndex); - int32_t LcParticleId = -1; - auto JParticleIndex = paticleMapping.find(LcParticle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - LcParticleId = JParticleIndex->second; - } - products.storedLcParticleIdsTable(products.storedJMcCollisionsTable.lastIndex(), LcParticleId); - } - } - if (config.saveDielectronTable) { - const auto dielectronMcCollisionsPerMcCollision = DielectronMcCollisions.sliceBy(DielectronMcCollisionsPerMcCollision, mcCollision.globalIndex()); - int32_t mcCollisionDielectronIndex = -1; - for (const auto& dielectronMcCollisionPerMcCollision : dielectronMcCollisionsPerMcCollision) { // should only ever be one - jetdqutilities::fillDielectronMcCollisionTable(dielectronMcCollisionPerMcCollision, products.storedDielectronMcCollisionsTable, mcCollisionDielectronIndex); - products.storedDielectronMcCollisionIdsTable(products.storedJMcCollisionsTable.lastIndex()); - } - for (const auto& DielectronParticle : DielectronParticles) { - int32_t DielectronParticleIndex = -1; - jetdqutilities::fillDielectronCandidateMcTable(DielectronParticle, mcCollisionDielectronIndex, products.storedDielectronParticlesTable, DielectronParticleIndex); - int32_t DielectronParticleId = -1; - auto JParticleIndex = paticleMapping.find(DielectronParticle.mcParticleId()); - if (JParticleIndex != paticleMapping.end()) { - DielectronParticleId = JParticleIndex->second; - } - std::vector DielectronMothersId; - int DielectronDaughtersId[2]; - if (DielectronParticle.has_mothers()) { - for (auto const& DielectronMother : DielectronParticle.template mothers_as>()) { - auto JDielectronMotherIndex = paticleMapping.find(DielectronMother.globalIndex()); - if (JDielectronMotherIndex != paticleMapping.end()) { - DielectronMothersId.push_back(JDielectronMotherIndex->second); - } - } - } - auto i = 0; - if (DielectronParticle.has_daughters()) { - for (auto const& DielectronDaughter : DielectronParticle.template daughters_as>()) { - if (i > 1) { - break; - } - auto JDielectronDaughterIndex = paticleMapping.find(DielectronDaughter.globalIndex()); - if (JDielectronDaughterIndex != paticleMapping.end()) { - DielectronDaughtersId[i] = JDielectronDaughterIndex->second; - } - i++; - } - } - products.storedDielectronParticleIdsTable(products.storedJMcCollisionsTable.lastIndex(), DielectronParticleId, DielectronMothersId, DielectronDaughtersId); - } - } - } - } - } - // 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/jetmatchingmc.cxx b/PWGJE/TableProducer/jetmatchingmc.cxx deleted file mode 100644 index 434b93c3309..00000000000 --- a/PWGJE/TableProducer/jetmatchingmc.cxx +++ /dev/null @@ -1,172 +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 jetmatchingmc.cxx -/// \brief matching detector level and generator level jets -/// -/// \author Raymond Ehlers , ORNL -/// \author Jochen Klein -/// \author Aimeric Lanodu -/// \author Nima Zardoshti - -#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 JetMatchingMc { - - 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; - - 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, - JetsBase const& jetsBase, JetsTag const& jetsTag, - JetTracksMCD const& tracks, - JetClustersMCD const& clusters, - 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; - // 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& mcCollision : mcCollisions) { - - const auto collisionsPerMcColl = collisions.sliceBy(CollisionsPerMcCollision, mcCollision.globalIndex()); - - for (const auto& collision : collisionsPerMcColl) { - - 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, clusters, particles, particles, 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(JetMatchingMc, processJets, "Perform jet matching", false); -}; - -using ChargedJetMatching = JetMatchingMc, - soa::Join, - aod::ChargedMCDetectorLevelJetsMatchedToChargedMCParticleLevelJets, - aod::ChargedMCParticleLevelJetsMatchedToChargedMCDetectorLevelJets, - aod::JCollisions, - aod::JMcCollisions>; -using FullJetMatching = JetMatchingMc, - soa::Join, - aod::FullMCDetectorLevelJetsMatchedToFullMCParticleLevelJets, - aod::FullMCParticleLevelJetsMatchedToFullMCDetectorLevelJets, - aod::JCollisions, - aod::JMcCollisions>; -using NeutralJetMatching = JetMatchingMc, - soa::Join, - aod::NeutralMCDetectorLevelJetsMatchedToNeutralMCParticleLevelJets, - aod::NeutralMCParticleLevelJetsMatchedToNeutralMCDetectorLevelJets, - 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>;*/ -using V0ChargedJetMatching = JetMatchingMc, - soa::Join, - aod::V0ChargedMCDetectorLevelJetsMatchedToV0ChargedMCParticleLevelJets, - aod::V0ChargedMCParticleLevelJetsMatchedToV0ChargedMCDetectorLevelJets, - CandidatesV0MCD, - CandidatesV0MCP>; - -using DielectronChargedJetMatching = JetMatchingMc, - soa::Join, - aod::DielectronChargedMCDetectorLevelJetsMatchedToDielectronChargedMCParticleLevelJets, - aod::DielectronChargedMCParticleLevelJetsMatchedToDielectronChargedMCDetectorLevelJets, - CandidatesDielectronMCD, - CandidatesDielectronMCP>; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - std::vector tasks; - - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-full"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-matching-mc-neutral"})); - 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"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-v0-ch"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-dielectron-ch"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/jetmatchingmcsub.cxx b/PWGJE/TableProducer/jetmatchingmcsub.cxx deleted file mode 100644 index 81e2b6f41ce..00000000000 --- a/PWGJE/TableProducer/jetmatchingmcsub.cxx +++ /dev/null @@ -1,134 +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 jetmatchingmcsub.cxx -/// \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 "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 JetMatchingMcSub { - - 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 = false; - static constexpr bool jetsTagIsMc = false; - - Preslice baseJetsPerCollision = aod::jet::collisionId; - Preslice tagJetsPerCollision = aod::jet::collisionId; - - void init(InitContext const&) - { - } - - void processDummy(JetCollisions const&) - { - } - PROCESS_SWITCH(JetMatchingMcSub, processDummy, "Dummy process", true); - - void processJets(JetCollisions const& collisions, - JetsBase const& jetsBase, JetsTag const& jetsTag, - JetTracks const& tracks, - JetTracksSub 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 - 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()); - - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, candidates, tracks, tracks, tracksSub, tracksSub, 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(JetMatchingMcSub, processJets, "Perform jet matching", false); -}; - -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>;*/ -using DielectronChargedJetMatching = JetMatchingMcSub, - soa::Join, - aod::DielectronChargedMCDetectorLevelJetsMatchedToDielectronChargedMCDetectorLevelEventWiseSubtractedJets, - aod::DielectronChargedMCDetectorLevelEventWiseSubtractedJetsMatchedToDielectronChargedMCDetectorLevelJets, - CandidatesDielectronMCD>; - -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"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-mc-sub-dielectron-ch"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/jetmatchingsub.cxx b/PWGJE/TableProducer/jetmatchingsub.cxx deleted file mode 100644 index 6a8b106d89a..00000000000 --- a/PWGJE/TableProducer/jetmatchingsub.cxx +++ /dev/null @@ -1,136 +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 jetmatching.cxx -/// \brief matching event-wise constituent subtracted data jets and unsubtracted data jets -/// \author Nima Zardoshti - -#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 JetMatchingSub { - - 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 processDummy(JetCollisions const&) - { - } - PROCESS_SWITCH(JetMatchingSub, processDummy, "Dummy process", true); - - void processJets(JetCollisions const& collisions, - JetsBase const& jetsBase, JetsTag const& jetsTag, - 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 - 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()); - - jetmatchingutilities::doAllMatching(jetsBasePerColl, jetsTagPerColl, jetsBasetoTagMatchingGeo, jetsBasetoTagMatchingPt, jetsBasetoTagMatchingHF, jetsTagtoBaseMatchingGeo, jetsTagtoBaseMatchingPt, jetsTagtoBaseMatchingHF, candidates, candidates, tracks, tracks, tracksSub, tracksSub, 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(JetMatchingSub, processJets, "Perform jet matching", false); -}; - -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>;*/ -using DielectronChargedJetMatching = JetMatchingSub, - soa::Join, - aod::DielectronChargedJetsMatchedToDielectronChargedEventWiseSubtractedJets, - aod::DielectronChargedEventWiseSubtractedJetsMatchedToDielectronChargedJets, - aod::JTrackDielectronSubs, - CandidatesDielectronData>; -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"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, TaskName{"jet-matching-sub-dielectron-ch"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/TableProducer/jettaggerhf.cxx b/PWGJE/TableProducer/jettaggerhf.cxx deleted file mode 100644 index 225f7919db6..00000000000 --- a/PWGJE/TableProducer/jettaggerhf.cxx +++ /dev/null @@ -1,282 +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 removeGluonShower{"removeGluonShower", true, "find jet origin removed gluon spliting"}; // true:: remove gluon spliting - 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 doSV{"doSV", false, "fill table for secondary vertex algorithm"}; - 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> paramsResoFuncData{"paramsResoFuncData", std::vector{1306800, -0.1049, 0.861425, 13.7547, 0.977967, 8.96823, 0.151595, 6.94499, 0.0250301}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7))"}; - Configurable> paramsResoFuncIncJetMC{"paramsResoFuncIncJetMC", std::vector{1908803.027, -0.059, 0.895, 13.467, 1.005, 8.867, 0.098, 6.929, 0.011}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; - Configurable> paramsResoFuncCharmJetMC{"paramsResoFuncCharmJetMC", std::vector{282119.753, -0.065, 0.893, 11.608, 0.945, 8.029, 0.131, 6.244, 0.027}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; - Configurable> paramsResoFuncBeautyJetMC{"paramsResoFuncBeautyJetMC", std::vector{74901.583, -0.082, 0.874, 10.332, 0.941, 7.352, 0.097, 6.220, 0.022}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; - Configurable> paramsResoFuncLfJetMC{"paramsResoFuncLfJetMC", std::vector{1539435.343, -0.061, 0.896, 13.272, 1.034, 5.884, 0.004, 7.843, 0.090}, "parameters of gaus(0)+expo(3)+expo(5)+expo(7)))"}; - Configurable minSignImpXYSig{"minsIPs", -40.0, "minimum of signed impact parameter significance"}; - Configurable tagPoint{"tagPoint", 2.5, "tagging working point"}; - - ConfigurableAxis binTrackProbability{"binTrackProbability", {100, 0.f, 1.f}, ""}; - ConfigurableAxis binJetFlavour{"binJetFlavour", {6, -0.5, 5.5}, ""}; - - using JetTagTracksData = soa::Join; - using JetTagTracksMCD = soa::Join; - using OriTracksData = soa::Join; - using OriTracksMCD = soa::Join; - - std::vector vecParamsData; - std::vector vecParamsIncJetMC; - std::vector vecParamsCharmJetMC; - std::vector vecParamsBeautyJetMC; - std::vector vecParamsLfJetMC; - std::vector jetProb; - 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; - - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - void init(InitContext const&) - { - maxOrder = numCount + 1; // 0: untagged, >1 : N ordering - - // Set up the resolution function - resoFuncMatch = resoFuncMatching; - switch (resoFuncMatch) { - case 0: - vecParamsData = (std::vector)paramsResoFuncData; - vecParamsIncJetMC = (std::vector)paramsResoFuncIncJetMC; - LOG(info) << "defined parameters of resolution function: custom"; - break; - case 1: - vecParamsData = (std::vector)paramsResoFuncData; - vecParamsCharmJetMC = (std::vector)paramsResoFuncCharmJetMC; - vecParamsBeautyJetMC = (std::vector)paramsResoFuncBeautyJetMC; - vecParamsLfJetMC = (std::vector)paramsResoFuncLfJetMC; - 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 = {281446.003, -0.063, 0.894, 11.598, 0.943, 8.025, 0.130, 6.227, 0.027}; - vecParamsBeautyJetMC = {74839.065, -0.081, 0.875, 10.314, 0.939, 7.326, 0.101, 6.309, 0.024}; - vecParamsLfJetMC = {1531580.038, -0.062, -0.896, 13.267, 1.034, 5.866, 0.004, 7.836, 0.090}; - LOG(info) << "defined parameters of resolution function: PYTHIA8, JJ, LHC23d4"; - break; - case 5: // TODO - vecParamsData = (std::vector)paramsResoFuncData; - vecParamsIncJetMC = {1900387.527, -0.059, 0.895, 13.461, 1.004, 8.860, 0.098, 6.931, 0.011}; - LOG(info) << "defined parameters of resolution function: PYTHIA8, JJ, LHC23d4 & use inclusive distribution"; - 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); - - // Use QA for effectivness of track probability - if (trackProbQA) { - AxisSpec trackProbabilityAxis = {binTrackProbability, "Track proability"}; - AxisSpec jetFlavourAxis = {binJetFlavour, "Jet flavour"}; - 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}}}); - } - } - - 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) { - int algorithm2 = 0; - int algorithm3 = 0; - if (useJetProb) { - jetProb.clear(); - jetProb.reserve(maxOrder); - for (int order = 0; order < maxOrder; order++) { - jetProb.push_back(jettaggingutilities::getJetProbability(fSignImpXYSigData, 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 (removeGluonShower) - origin = jettaggingutilities::mcdJetFromHFShower(mcdjet, jtracks, particles, maxDeltaR); - else - origin = jettaggingutilities::jetTrackFromHFShower(mcdjet, jtracks, particles, hftrack); - int algorithm2 = 0; - int algorithm3 = 0; - if (useJetProb) { - jetProb.clear(); - jetProb.reserve(maxOrder); - for (int order = 0; order < maxOrder; order++) { - if (useResoFuncFromIncJet) { - jetProb.push_back(jettaggingutilities::getJetProbability(fSignImpXYSigIncJetMC, collision, mcdjet, jtracks, tracks, order, tagPoint, minSignImpXYSig)); - } else { - if (origin == JetTaggingSpecies::charm) { - jetProb.push_back(jettaggingutilities::getJetProbability(fSignImpXYSigCharmJetMC, collision, mcdjet, jtracks, tracks, order, tagPoint, minSignImpXYSig)); - } - if (origin == JetTaggingSpecies::beauty) { - jetProb.push_back(jettaggingutilities::getJetProbability(fSignImpXYSigBeautyJetMC, collision, mcdjet, jtracks, tracks, order, tagPoint, minSignImpXYSig)); - } - if (origin == JetTaggingSpecies::lightflavour) { - jetProb.push_back(jettaggingutilities::getJetProbability(fSignImpXYSigLfJetMC, collision, mcdjet, jtracks, tracks, order, tagPoint, minSignImpXYSig)); - } - } - } - if (trackProbQA) { - for (auto& jtrack : mcdjet.template tracks_as()) { - auto track = jtrack.template track_as(); - auto geoSign = jettaggingutilities::getGeoSign(collision, mcdjet, track); - float probTrack = -1; - 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); - } - } - } - } - // 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..8767ae604e2 --- /dev/null +++ b/PWGJE/TableProducer/luminosityCalculator.cxx @@ -0,0 +1,123 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGJE/DataModel/JetReducedData.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include + +#include + +#include +#include + +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..ea81af2f381 --- /dev/null +++ b/PWGJE/TableProducer/luminosityProducer.cxx @@ -0,0 +1,252 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "JetDerivedDataUtilities.h" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Common/CCDB/EventSelectionParams.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 and also assumes the default RCT configuration is always used + 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/mcOutlierRejector.cxx b/PWGJE/TableProducer/mcOutlierRejector.cxx new file mode 100644 index 00000000000..8b8035a8ba7 --- /dev/null +++ b/PWGJE/TableProducer/mcOutlierRejector.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. + +// Task to produce a table joinable to the jcollision table which contains an outlier rejector +// +/// \author Nima Zardoshti + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct McOutlierRejectorTask { + Produces collisionOutliers; + Produces mcCollisionOutliers; + Preslice> perColParticle = aod::jmccollision::mcCollisionId; + + Configurable checkmcCollisionForCollision{"checkmcCollisionForCollision", true, "additionally reject collision based on mcCollision"}; + Configurable ptHatMax{"ptHatMax", 4.0, "maximum factor of pt hat the leading jet in the event is allowed"}; + Configurable ptTrackMaxMinBias{"ptTrackMaxMinBias", 20.0, "maximum pt for track originating from minimum bias event"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + std::vector collisionFlag; + std::vector mcCollisionFlag; + + int trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + void processSetupCollisionSelection(aod::JCollisions const& collisions) + { + collisionFlag.clear(); + collisionFlag.resize(collisions.size(), false); + } + PROCESS_SWITCH(McOutlierRejectorTask, processSetupCollisionSelection, "Setup collision processing", true); + + void processSetupMcCollisionSelection(aod::JMcCollisions const& mcCollisions) + { + mcCollisionFlag.clear(); + mcCollisionFlag.resize(mcCollisions.size(), false); + } + PROCESS_SWITCH(McOutlierRejectorTask, processSetupMcCollisionSelection, "Setup MC Collision processing", true); + + template + void collisionSelection(int32_t collisionIndex, int32_t mcCollisionId, T const& selectionObjects, float ptHard, std::vector& flagArray, std::optional>> mcCollisionsOpt = std::nullopt) + { + if (selectionObjects.size() != 0) { + float selectionObjectPt = 0.0; + if constexpr (std::is_same_v, aod::JetTracksMCD> || std::is_same_v, aod::JetParticles>) { + for (auto selectionObject : selectionObjects) { + selectionObjectPt = selectionObject.pt(); + // may be slow - could save only MC particle then check difference only for tracks IDd as outliers? + if constexpr (std::is_same_v, aod::JetTracksMCD>) { // tracks + if (!jetderiveddatautilities::selectTrack(selectionObject, trackSelection)) { + continue; + } + auto& mcCollisions = mcCollisionsOpt.value().get(); + auto mcParticle = selectionObject.template mcParticle_as>(); + auto mcCollision = mcCollisions.sliceBy(perColParticle, mcParticle.mcCollisionId()); + int subGenID = mcCollision.begin().subGeneratorId(); + int diffCollisionID = mcParticle.mcCollisionId() - mcCollisionId; + if (diffCollisionID != 0 && + selectionObjectPt > ptHatMax * ptHard) { + if (subGenID != jetderiveddatautilities::JCollisionSubGeneratorId::mbGap && selectionObjectPt > ptHatMax * ptHard) { + flagArray[collisionIndex] = true; + } + if (subGenID == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap && selectionObjectPt > ptTrackMaxMinBias) { + flagArray[collisionIndex] = true; + } + } + } else { // particles + if (selectionObjectPt > ptHatMax * ptHard) { + flagArray[collisionIndex] = true; + } + } + } + } else { // jets + selectionObjectPt = selectionObjects.iteratorAt(0).pt(); + if (selectionObjectPt > ptHatMax * ptHard) { + flagArray[collisionIndex] = true; // Currently if running multiple different jet finders, then a single type of jet can veto an event for others. Decide if this is the best way + } + } + } + } + + template + void processSelectionObjects(aod::JetCollisionMCD const& collision, T const& selectionObjects, aod::JetMcCollisions const&) + { + auto mcCollision = collision.mcCollision_as(); + collisionSelection(collision.globalIndex(), 1., selectionObjects, mcCollision.ptHard(), collisionFlag); + } + + template + void processSelectionObjectsTracks(aod::JetCollisionMCD const& collision, T const& selectionObjects, soa::Join const& mcCollisions, soa::Join const&) + { + auto mcCollision = collision.mcCollision_as>(); + collisionSelection(collision.globalIndex(), collision.mcCollisionId(), selectionObjects, mcCollision.ptHard(), collisionFlag, mcCollisions); + } + + template + void processSelectionMcObjects(aod::JetMcCollision const& mcCollision, T const& selectionMcObjects) + { + collisionSelection(mcCollision.globalIndex(), 1., selectionMcObjects, mcCollision.ptHard(), mcCollisionFlag); + } + + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingChargedMCDetectorLevelJets, "process mc detector level charged jets", true); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingNeutralMCDetectorLevelJets, "process mc detector level neutral jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingFullMCDetectorLevelJets, "process mc detector level full jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingD0ChargedMCDetectorLevelJets, "process mc detector level D0 charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingDplusChargedMCDetectorLevelJets, "process mc detector level Dplus charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingDsChargedMCDetectorLevelJets, "process mc detector level Ds charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingDstarChargedMCDetectorLevelJets, "process mc detector level Dstar charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingLcChargedMCDetectorLevelJets, "process mc detector level Lc charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingB0ChargedMCDetectorLevelJets, "process mc detector level B0 charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingBplusChargedMCDetectorLevelJets, "process mc detector level Bplus charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingXicToXiPiPiChargedMCDetectorLevelJets, "process mc detector level XicToXiPiPi charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjects, processSelectingDielectronChargedMCDetectorLevelJets, "process mc detector level Dielectron charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionObjectsTracks, processSelectingTracks, "process tracks", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingChargedMCParticleLevelJets, "process mc particle level charged jets", true); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingNeutralMCParticleLevelJets, "process mc particle level neutral jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingFullMCParticleLevelJets, "process mc particle level full jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingD0ChargedMCParticleLevelJets, "process mc particle level D0 charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingDplusChargedMCParticleLevelJets, "process mc particle level Dplus charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingDsChargedMCParticleLevelJets, "process mc particle level Ds charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingDstarChargedMCParticleLevelJets, "process mc particle level Dstar charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingLcChargedMCParticleLevelJets, "process mc particle level Lc charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingB0ChargedMCParticleLevelJets, "process mc particle level B0 charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingBplusChargedMCParticleLevelJets, "process mc particle level Bplus charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingXicToXiPiPiChargedMCParticleLevelJets, "process mc particle level XicToXiPiPi charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingDielectronChargedMCParticleLevelJets, "process mc particle level Dielectron charged jets", false); + PROCESS_SWITCH_FULL(McOutlierRejectorTask, processSelectionMcObjects, processSelectingParticles, "process mc particles", false); + + void processStoreCollisionDecision(aod::JetCollisionMCD const& collision) + { + bool rejectCollision = collisionFlag[collision.globalIndex()]; + if (!rejectCollision && checkmcCollisionForCollision && collision.has_mcCollision()) { + rejectCollision = mcCollisionFlag[collision.mcCollisionId()]; + } + collisionOutliers(rejectCollision); + } + PROCESS_SWITCH(McOutlierRejectorTask, processStoreCollisionDecision, "write out decision of rejecting collision", true); + + void processStoreMcCollisionDecision(aod::JetMcCollision const& mcCollision) + { + mcCollisionOutliers(mcCollisionFlag[mcCollision.globalIndex()]); + } + PROCESS_SWITCH(McOutlierRejectorTask, processStoreMcCollisionDecision, "write out decision of rejecting mcCollision", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"mc-outlier-rejector"})}; } diff --git a/PWGJE/TableProducer/rhoEstimator.cxx b/PWGJE/TableProducer/rhoEstimator.cxx index a5a543125a3..d2803ccbe49 100644 --- a/PWGJE/TableProducer/rhoEstimator.cxx +++ b/PWGJE/TableProducer/rhoEstimator.cxx @@ -13,17 +13,30 @@ // /// \author Nima Zardoshti -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + #include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include +#include -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetFindingUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetBkgSubUtils.h" -#include "Framework/runDataProcessing.h" +#include +#include + +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; @@ -31,92 +44,463 @@ using namespace o2::framework::expressions; struct RhoEstimatorTask { Produces rhoChargedTable; + Produces rhoChargedMcTable; Produces rhoD0Table; + Produces rhoD0McTable; + Produces rhoDplusTable; + Produces rhoDplusMcTable; + Produces rhoDsTable; + Produces rhoDsMcTable; + Produces rhoDstarTable; + Produces rhoDstarMcTable; Produces rhoLcTable; + Produces rhoLcMcTable; + Produces rhoB0Table; + Produces rhoB0McTable; Produces rhoBplusTable; + Produces rhoBplusMcTable; + Produces rhoXicToXiPiPiTable; + Produces rhoXicToXiPiPiMcTable; + 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 applyTrackingEfficiency{"applyTrackingEfficiency", {false}, "configurable to decide whether to apply artificial tracking efficiency (discarding tracks) in the collision analysed by this task"}; + Configurable> trackingEfficiencyPtBinning{"trackingEfficiencyPtBinning", {0., 10, 999.}, "pt binning of tracking efficiency array if applyTrackingEfficiency is true"}; + Configurable> trackingEfficiency{"trackingEfficiency", {1.0, 1.0}, "tracking efficiency array applied if applyTrackingEfficiency is true"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; + + 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", -6.283, "minimim phi for determining background density"}; + Configurable bkgPhiMax{"bkgPhiMax", 6.283, "maximum phi for determining background density"}; + Configurable doSparse{"doSparse", false, "perfom sparse estimation"}; + Configurable ghostRapMax{"ghostRapMax", 0.9, "Ghost rapidity max"}; + Configurable ghostRepeat{"ghostRepeat", 1, "Ghost tiling repeats"}; + Configurable ghostArea{"ghostArea", 0.005, "Area per ghost"}; + Configurable ghostGridScatter{"ghostGridScatter", 1.0, "Grid scatter"}; + Configurable ghostKtScatter{"ghostKtScatter", 0.1, "kT scatter"}; + Configurable ghostMeanPt{"ghostMeanPt", 1e-100, "Mean ghost pT"}; + + 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 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 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 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_); + + fastjet::GhostedAreaSpec ghostAreaSpec(config.ghostRapMax, config.ghostRepeat, config.ghostArea, + config.ghostGridScatter, config.ghostKtScatter, config.ghostMeanPt); + bkgSub.setGhostAreaSpec(ghostAreaSpec); + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(config.eventSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(config.triggerMasks); + + if (config.applyTrackingEfficiency) { + if (config.trackingEfficiencyPtBinning->size() < 2) { + LOGP(fatal, "rhoEstimator workflow: trackingEfficiencyPtBinning configurable should have at least two bin edges"); + } + if (config.trackingEfficiency->size() + 1 != config.trackingEfficiencyPtBinning->size()) { + LOGP(fatal, "rhoEstimator workflow: trackingEfficiency configurable should have exactly one less entry than the number of bin edges set in trackingEfficiencyPtBinning configurable"); + } + } } - 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 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; + } + } + + template + void processSelectionObjects(T& selectionObjects) + { + float selectionObjectPtMin = 0.0; + 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, 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.centFT0M() < config.centralityMin || collision.centFT0M() >= 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, trackingEfficiency); - auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, doSparse); - rhoChargedTable(collision.globalIndex(), rho, rhoM); + jetfindingutilities::analyseTracks, soa::Filtered::iterator>(inputParticles, tracks, trackSelection, config.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning); + 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.centFT0M() < config.centralityMin || collision.centFT0M() >= 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, trackingEfficiency, std::optional{candidate}); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &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, &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.centFT0M() < config.centralityMin || collision.centFT0M() >= 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.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &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, &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 processDsCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesDsData const& candidates) + { + for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centFT0M() < config.centralityMin || collision.centFT0M() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoDsTable(0.0, 0.0); + continue; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDsTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processDsCollisions, "Fill rho tables for collisions with Ds candidates", false); + + void processDsMcCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesDsMCP const& candidates) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDsMcTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processDsMcCollisions, "Fill rho tables for collisions with Ds MCP candidates", false); + + void processDstarCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesDstarData const& candidates) + { + for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centFT0M() < config.centralityMin || collision.centFT0M() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoDstarTable(0.0, 0.0); + continue; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDstarTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processDstarCollisions, "Fill rho tables for collisions with Dstar candidates", false); + + void processDstarMcCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesDstarMCP const& candidates) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDstarMcTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processDstarMcCollisions, "Fill rho tables for collisions with Dstar 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.centFT0M() < config.centralityMin || collision.centFT0M() >= 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, trackingEfficiency, std::optional{candidate}); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &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, &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 processB0Collisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesB0Data const& candidates) + { + for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centFT0M() < config.centralityMin || collision.centFT0M() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoB0Table(0.0, 0.0); + continue; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoB0Table(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processB0Collisions, "Fill rho tables for collisions with B0 candidates", false); + + void processB0McCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesB0MCP const& candidates) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoB0McTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processB0McCollisions, "Fill rho tables for collisions with B0 MCP candidates", false); + + void processBplusCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesBplusData const& candidates) { - inputParticles.clear(); for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centFT0M() < config.centralityMin || collision.centFT0M() >= 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, trackingEfficiency, std::optional{candidate}); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &candidate); - auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, doSparse); - rhoBplusTable(candidate.globalIndex(), rho, rhoM); + 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, &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 processXicToXiPiPiCollisions(aod::JetCollision const& collision, soa::Filtered const& tracks, aod::CandidatesXicToXiPiPiData const& candidates) + { + for (auto& candidate : candidates) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || collision.centFT0M() < config.centralityMin || collision.centFT0M() >= config.centralityMax || collision.trackOccupancyInTimeRange() > config.trackOccupancyInTimeRangeMax || std::abs(collision.posZ()) > config.vertexZCut) { + rhoXicToXiPiPiTable(0.0, 0.0); + continue; + } + inputParticles.clear(); + jetfindingutilities::analyseTracks(inputParticles, tracks, trackSelection, config.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoXicToXiPiPiTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processXicToXiPiPiCollisions, "Fill rho tables for collisions with XicToXiPiPi candidates", false); + + void processXicToXiPiPiMcCollisions(aod::JetMcCollision const&, soa::Filtered const& particles, aod::CandidatesXicToXiPiPiMCP const& candidates) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoXicToXiPiPiMcTable(rho, rhoM); + } + } + PROCESS_SWITCH(RhoEstimatorTask, processXicToXiPiPiMcCollisions, "Fill rho tables for collisions with XicToXiPiPi 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.centFT0M() < config.centralityMin || collision.centFT0M() >= 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.applyTrackingEfficiency, config.trackingEfficiency, config.trackingEfficiencyPtBinning, &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) + { + for (auto& candidate : candidates) { + inputParticles.clear(); + jetfindingutilities::analyseParticles(inputParticles, particleSelection, 1, particles, pdgDatabase, &candidate); + + auto [rho, rhoM] = bkgSub.estimateRhoAreaMedian(inputParticles, config.doSparse); + rhoDielectronMcTable(rho, rhoM); + } + } + 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 index 1a6536354a4..8bab0ea0c05 100644 --- a/PWGJE/TableProducer/secondaryVertexReconstruction.cxx +++ b/PWGJE/TableProducer/secondaryVertexReconstruction.cxx @@ -9,32 +9,46 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// Task to produce a SV indices table joinable to the jet tables and 3/2-prong SV for hf jet tagging -// +/// \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 "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetTagging.h" -#include -#include +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/TrackSelectionTables.h" #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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -62,11 +76,15 @@ struct SecondaryVertexReconstruction { 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 maxIPxy{"maxIPxy", 10, "maximum track DCA in xy plane"}; + Configurable maxIPz{"maxIPz", 10, "maximum track DCA in z direction"}; Configurable fillHistograms{"fillHistograms", true, "do validation plots"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -94,6 +112,7 @@ struct SecondaryVertexReconstruction { 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); @@ -121,9 +140,9 @@ struct SecondaryVertexReconstruction { 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 JetCollisionwPIs = soa::Join; + using JetTracksData = soa::Filtered>; + using JetTracksMCDwPIs = soa::Filtered>; using OriginalTracks = soa::Join; template @@ -163,12 +182,31 @@ struct SecondaryVertexReconstruction { // Reconstruct the secondary vertex int processResult = 0; - std::apply([&df, &processResult](const auto&... elems) { processResult = df.process(elems...); }, trackParVars); + 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.getPCACandidate(); + 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(); @@ -210,7 +248,7 @@ struct SecondaryVertexReconstruction { 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, errorDecayLength, errorDecayLengthXY); + energySV, massSV, chi2PCA, dispersion, errorDecayLength, errorDecayLengthXY); svIndices.push_back(sv3prongTableData.lastIndex()); } else if ((doprocessData2Prongs || doprocessData2ProngsExternalMagneticField) && numProngs == 2) { sv2prongTableData(analysisJet.globalIndex(), @@ -219,7 +257,7 @@ struct SecondaryVertexReconstruction { arrayMomenta[0][0] + arrayMomenta[1][0], arrayMomenta[0][1] + arrayMomenta[1][1], arrayMomenta[0][2] + arrayMomenta[1][2], - energySV, massSV, chi2PCA, errorDecayLength, errorDecayLengthXY); + energySV, massSV, chi2PCA, dispersion, errorDecayLength, errorDecayLengthXY); svIndices.push_back(sv2prongTableData.lastIndex()); } else if ((doprocessMCD3Prongs || doprocessMCD3ProngsExternalMagneticField) && numProngs == 3) { sv3prongTableMCD(analysisJet.globalIndex(), @@ -228,7 +266,7 @@ struct SecondaryVertexReconstruction { 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, errorDecayLength, errorDecayLengthXY); + energySV, massSV, chi2PCA, dispersion, errorDecayLength, errorDecayLengthXY); svIndices.push_back(sv3prongTableMCD.lastIndex()); } else if ((doprocessMCD2Prongs || doprocessMCD2ProngsExternalMagneticField) && numProngs == 2) { sv2prongTableMCD(analysisJet.globalIndex(), @@ -237,7 +275,7 @@ struct SecondaryVertexReconstruction { arrayMomenta[0][0] + arrayMomenta[1][0], arrayMomenta[0][1] + arrayMomenta[1][1], arrayMomenta[0][2] + arrayMomenta[1][2], - energySV, massSV, chi2PCA, errorDecayLength, errorDecayLengthXY); + energySV, massSV, chi2PCA, dispersion, errorDecayLength, errorDecayLengthXY); svIndices.push_back(sv2prongTableMCD.lastIndex()); } else { LOG(error) << "No process specified\n"; @@ -245,12 +283,13 @@ struct SecondaryVertexReconstruction { // 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; + 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("hDispersion"), dispersion, numProngs); registry.fill(HIST("hMassNProngs"), massSV, numProngs); - registry.fill(HIST("hLxySNProngs"), DecayLengthXYNormalised, numProngs); - registry.fill(HIST("hLSNProngs"), DecayLengthNormalised, 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); } @@ -261,7 +300,7 @@ struct SecondaryVertexReconstruction { 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) { + if (testTrack.pt() < ptMinTrack || testTrack.eta() < etaMinTrack || testTrack.eta() > etaMaxTrack || std::abs(testTrack.dcaXY()) > maxIPxy || std::abs(testTrack.dcaZ()) > maxIPz) { continue; } @@ -277,81 +316,81 @@ struct SecondaryVertexReconstruction { } PROCESS_SWITCH(SecondaryVertexReconstruction, processDummy, "Dummy process", true); - void processData3Prongs(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& jets, JetTracksData const& jtracks, OriginalTracks const& /*tracks*/, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + 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 (auto& jet : jets) { + for (const auto& jet : jets) { std::vector svIndices; - runCreatorNProng<3, false>(collision.template collision_as(), jet, jtracks, svIndices, df3); + 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& jtracks, OriginalTracks const& /*tracks*/) + void processData3ProngsExternalMagneticField(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& jets, JetTracksData const& tracks, OriginalTracks const& /*tracks*/) { - for (auto& jet : jets) { + for (const auto& jet : jets) { std::vector svIndices; - runCreatorNProng<3, true>(collision.template collision_as(), jet, jtracks, svIndices, df3); + 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& jtracks, OriginalTracks const& /*tracks*/, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + 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 (auto& jet : jets) { + for (const auto& jet : jets) { std::vector svIndices; - runCreatorNProng<2, false>(collision.template collision_as(), jet, jtracks, svIndices, df2); + 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& jtracks, OriginalTracks const& /*tracks*/) + void processData2ProngsExternalMagneticField(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& jets, JetTracksData const& tracks, OriginalTracks const& /*tracks*/) { - for (auto& jet : jets) { + for (const auto& jet : jets) { std::vector svIndices; - runCreatorNProng<2, true>(collision.template collision_as(), jet, jtracks, svIndices, df2); + 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& jtracks, OriginalTracks const& /*tracks*/, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + 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 (auto& jet : mcdjets) { + for (const auto& jet : mcdjets) { std::vector svIndices; - runCreatorNProng<3, false>(collision.template collision_as(), jet, jtracks, svIndices, df3); + 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& jtracks, OriginalTracks const& /*tracks*/) + void processMCD3ProngsExternalMagneticField(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& mcdjets, JetTracksMCDwPIs const& tracks, OriginalTracks const& /*tracks*/) { - for (auto& jet : mcdjets) { + for (const auto& jet : mcdjets) { std::vector svIndices; - runCreatorNProng<3, true>(collision.template collision_as(), jet, jtracks, svIndices, df3); + 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& jtracks, OriginalTracks const& /*tracks*/, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + 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 (auto& jet : mcdjets) { + for (const auto& jet : mcdjets) { std::vector svIndices; - runCreatorNProng<2, false>(collision.template collision_as(), jet, jtracks, svIndices, df2); + 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& jtracks, OriginalTracks const& /*tracks*/) + void processMCD2ProngsExternalMagneticField(JetCollisionwPIs::iterator const& collision, aod::Collisions const& /*realColl*/, soa::Join const& mcdjets, JetTracksMCDwPIs const& tracks, OriginalTracks const& /*tracks*/) { - for (auto& jet : mcdjets) { + for (const auto& jet : mcdjets) { std::vector svIndices; - runCreatorNProng<2, true>(collision.template collision_as(), jet, jtracks, svIndices, df2); + runCreatorNProng<2, true>(collision.template collision_as(), jet, tracks, svIndices, df2); sv2prongIndicesTableMCD(svIndices); } } @@ -360,5 +399,5 @@ struct SecondaryVertexReconstruction { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"jet-sv-reconstruction-charged"})}; + 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 050decc2ba7..6d143e82b79 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) 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,77 +35,205 @@ 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(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 + SOURCES photonIsolationQA.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(photon-charged-trigger-correlation + SOURCES photonChargedTriggerCorrelation.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-emc-extensive-mc-qa + SOURCES taskEmcExtensiveMcQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(photon-charged-trigger-producer + SOURCES photonChargedTriggerProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework 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-ds + SOURCES jetSubstructureDs.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-dstar + SOURCES jetSubstructureDstar.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-b0 + SOURCES jetSubstructureB0.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-xictoxipipi + SOURCES jetSubstructureXicToXiPiPi.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-ds-output + SOURCES jetSubstructureDsOutput.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-substructure-dstar-output + SOURCES jetSubstructureDstarOutput.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-b0-output + SOURCES jetSubstructureB0Output.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + 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-xictoxipipi-output + SOURCES jetSubstructureXicToXiPiPiOutput.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 + 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-finder-hf-qa - SOURCES jetfinderhfQA.cxx + o2physics_add_dpl_workflow(jet-outlier-qa + SOURCES jetOutlierQA.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-ds-qa + SOURCES jetFinderDsQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-finder-dstar-qa + SOURCES jetFinderDstarQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + 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-b0-qa + SOURCES jetFinderB0QA.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-xictoxipipi-qa + SOURCES jetFinderXicToXiPiPiQA.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 + 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 SOURCES triggerCorrelations.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(jet-charged-trigger-qa - SOURCES ChJetTriggerQATask.cxx + o2physics_add_dpl_workflow(jet-trigger-charged-qa + SOURCES jetTriggerChargedQa.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 @@ -113,7 +245,7 @@ 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 @@ -124,28 +256,37 @@ if(FastJet_FOUND) 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::EventFilteringUtils + O2Physics::AnalysisCCDB + 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 @@ -156,5 +297,54 @@ if(FastJet_FOUND) 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 + SOURCES fullJetSpectra.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::EventFilteringUtils + O2Physics::AnalysisCCDB + 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) + o2physics_add_dpl_workflow(jet-formationtimereclustering + SOURCES jetFormationTimeReclustering.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +endif() +if(pythia_FOUND) + if(TARGET ROOT::EGPythia8) + set_target_properties(ROOT::EGPythia8 PROPERTIES + INTERFACE_LINK_LIBRARIES "ROOT::Core;ROOT::EG;ROOT::Graf;ROOT::Physics;${pythia_LIBRARY_SHARED}" + ) + + o2physics_add_dpl_workflow(hadron-photon-correlation + SOURCES hadronPhotonCorrelation.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore ROOT::EGPythia8 + COMPONENT_NAME Analysis) + endif() endif() diff --git a/PWGJE/Tasks/ChJetTriggerQATask.cxx b/PWGJE/Tasks/ChJetTriggerQATask.cxx deleted file mode 100644 index 866bd7474bb..00000000000 --- a/PWGJE/Tasks/ChJetTriggerQATask.cxx +++ /dev/null @@ -1,311 +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 Filip Krizek -#include -#include -#include -#include -#include -#include - -#include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -#include "EventFiltering/filterTables.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/FastJetUtilities.h" -#include "PWGJE/Core/JetFindingUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGJE/DataModel/Jet.h" - -#include "Framework/HistogramRegistry.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -// What this task should do -// Event by event fill -// 1) pT spectrum of tracks in TPC volume -// 2) pT spectrum of jets in fiducial volume -// 3) leading jet pT versus leading track pT both in TPC volume -// We want output from -// a) minimum bias events -// b) from events selected by EPN -// It would be good to run it for several jet radii e.g. 0.2, 0.4, 0.6 - -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 cfgTrackPhiMinCut{"cfgTrackPhiMinCut", -999, "track min phi cut"}; - Configurable cfgTrackPhiMaxCut{"cfgTrackPhiMaxCut", 999, "track max phi cut"}; - Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; - - Configurable bLowPtTrigger{"bLowPtTrigger", false, "charged jet low pT trigger selection"}; - 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"}; - - float fiducialVolume; // 0.9 - jetR - - HistogramRegistry spectra; - - int eventSelection = -1; - int trackSelection = -1; - void init(o2::framework::InitContext&) - { - fiducialVolume = static_cast(cfgTPCVolume) - static_cast(cfgJetR); - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(evSel)); - trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - - // Basic histos - spectra.add("vertexZ", "z vertex", {HistType::kTH1F, {{400, -20., +20.}}}); - spectra.add("ptphiTrackInclGood", "pT vs phi inclusive good tracks", {HistType::kTH2F, {{100, 0., +100.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("ptetaTrackInclGood", "pT vs eta inclusive good tracks", {HistType::kTH2F, {{100, 0., +100.}, {80, -1., 1.}}}); - spectra.add("ptLeadingTrack", "pT leading track", {HistType::kTH1F, {{100, 0., +100.}}}); - spectra.add("ptJetChInclFidVol", "inclusive charged jet pT in fiducial volume", {HistType::kTH1F, {{200, 0., +200.}}}); - spectra.add("ptphiJetChInclFidVol", "inclusive charged jet pT vs phi in fiducial volume", {HistType::kTH2F, {{100, 0., +100.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("ptphiJetChInclFullVol", "inclusive charged jet pT vs phi in full TPC volume", {HistType::kTH2F, {{100, 0., +100.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("ptetaJetChInclFidVol", "inclusive charged jet pT vs eta in fiducial volume", {HistType::kTH2F, {{100, 0., +100.}, {80, -1., 1.}}}); - spectra.add("ptetaJetChInclFullVol", "inclusive charged jet pT vs eta in full TPC volume", {HistType::kTH2F, {{100, 0., +100.}, {80, -1., 1.}}}); - 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.}}}); - - // Supplementary plots - if (bAddSupplementHistosToOutput) { - spectra.add("ptJetChInclFullVol", "inclusive charged jet pT in full volume", {HistType::kTH1F, {{200, 0., +200.}}}); - spectra.add("phietaTrackAllInclGood", "phi vs eta all inclusive good tracks", {HistType::kTH2F, {{80, -1., 1.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("phietaTrackHighPtInclGood", "phi vs eta inclusive good tracks with pT > 10 GeV", {HistType::kTH2F, {{80, -1., 1.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("phietaJetChInclFidVol", "inclusive charged jet phi vs eta in fiducial volume", {HistType::kTH2F, {{80, -1., 1.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("phietaJetChInclFullVol", "inclusive charged jet phi vs eta in full TPC volume", {HistType::kTH2F, {{80, -1., 1.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("phietaJetChInclHighPtFidVol", "inclusive charged jet phi vs eta in fiducial volume", {HistType::kTH2F, {{80, -1., 1.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("phietaJetChInclHighPtFullVol", "inclusive charged jet phi vs eta in full TPC volume", {HistType::kTH2F, {{80, -1., 1.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("ptetaLeadingTrack", "pT vs eta leading tracks", {HistType::kTH2F, {{100, 0., +100.}, {80, -1., 1.}}}); - spectra.add("ptphiLeadingTrack", "pT vs phi leading tracks", {HistType::kTH2F, {{100, 0., +100.}, {60, 0, TMath::TwoPi()}}}); - spectra.add("jetAreaFullVol", "area of all jets in full TPC volume", {HistType::kTH2F, {{100, 0., +100.}, {50, 0., 2.}}}); - spectra.add("jetAreaFidVol", "area of all jets in fiducial volume", {HistType::kTH2F, {{100, 0., +100.}, {50, 0., 2.}}}); - spectra.add("fLeadJetChPtVsLeadingTrack", "inclusive charged jet pT in TPC volume", {HistType::kTH2F, {{100, 0., +100.}, {100, 0., +100.}}}); - } - } - - // declare filters on collisions - Filter collisionFilter = (nabs(aod::jcollision::posZ) < static_cast(cfgVertexCut)); - - // declare filters on tracks - 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; - - void - process(soa::Filtered>::iterator const& collision, - soa::Filtered> const& tracks, o2::soa::Filtered> const& jets, soa::Join const&) - { - - if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { - return; - } - - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { - return; - } - - bool bLowPtJet = (bLowPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)); - bool bHighPtJet = (bHighPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedHigh)); - bool bLowPtTrack = (bTrackLowPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::trackLowPt)); - bool bHighPtTrack = (bTrackHighPtTrigger && jetderiveddatautilities::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::trackHighPt)); - bool bMinimumBias = ((!bLowPtTrigger) && (!bHighPtTrigger) && (!bTrackLowPtTrigger) && (!bTrackHighPtTrigger)); - - if (bLowPtJet || bHighPtJet || bLowPtTrack || bHighPtTrack || bMinimumBias) { - // bLowPtTrigger=1 and bHighPtTrigger=0 --> fill histos with low trigger only - // bLowPtTrigger=0 and bHighPtTrigger=1 --> fill histos with high trigger only - // bLowPtTrigger=1 and bHighPtTrigger=1 --> fill histos with mixture of low and high trigger - // bTrackLowPtTrigger=1 --> fill histos for low pt track trigger - // bTrackHighPtTrigger=1 --> fill histos for high pt track trigger - // bLowPtTrigger=0 and bHighPtTrigger=0 and bTrackLowPtTrigger=0 and bTrackHighPtTrigger=0 --> fill histos with minimum bias ie. ignore trigger decision - - float leadingJetPt = -1.0; - float leadingJetEta = -2.0; - float leadingJetPhi = -1.0; - float leadingTrackPt = -1.0; - float leadingTrackEta = -2.0; - float leadingTrackPhi = -1.0; - - 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 - - auto const& originalTrack = trk.track_as>(); - spectra.fill(HIST("globalP_tpcglobalPDiff_withoutcuts"), trk.p(), trk.p() - originalTrack.tpcInnerParam()); - - if (TMath::Abs(trk.phi() - TMath::Pi()) < phiAngleRestriction) { - spectra.fill(HIST("globalP_tpcglobalPDiff_withoutcuts_phirestrict"), trk.p(), trk.p() - originalTrack.tpcInnerParam()); - } - - if (!jetderiveddatautilities::selectTrack(trk, trackSelection)) { - continue; - } - - spectra.fill(HIST("globalP_tpcglobalPDiff"), trk.p(), trk.p() - originalTrack.tpcInnerParam()); - if (trk.p() > 0 && originalTrack.tpcInnerParam() > 0) { - spectra.fill(HIST("global1overP_tpcglobalPDiff"), trk.p(), 1. / trk.p() - 1. / originalTrack.tpcInnerParam()); - } - if (TMath::Abs(trk.phi() - TMath::Pi()) < phiAngleRestriction) { - spectra.fill(HIST("globalP_tpcglobalPDiff_phirestrict"), trk.p(), trk.p() - originalTrack.tpcInnerParam()); - - if (trk.p() > 0 && originalTrack.tpcInnerParam() > 0) { - spectra.fill(HIST("global1overP_tpcglobalPDiff_phirestrict"), trk.p(), 1. / trk.p() - 1. / originalTrack.tpcInnerParam()); - } - } - - spectra.fill( - HIST("ptphiTrackInclGood"), trk.pt(), - trk.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 - - if (bAddSupplementHistosToOutput) { - spectra.fill( - HIST("phietaTrackAllInclGood"), trk.eta(), - trk.phi()); // Inclusive Track pT vs eta spectrum in TPC volume - - if (trk.pt() > 5.0) { - spectra.fill( - HIST("phietaTrackHighPtInclGood"), trk.eta(), - trk.phi()); // Inclusive Track pT vs eta spectrum in TPC volume - } - } - - if (trk.pt() > - leadingTrackPt) { // Find leading track pT in full TPC volume - leadingTrackPt = trk.pt(); - leadingTrackEta = trk.eta(); - leadingTrackPhi = trk.phi(); - } - } - - if (leadingTrackPt > -1.) { - spectra.fill(HIST("ptLeadingTrack"), leadingTrackPt); - } - - if (bAddSupplementHistosToOutput) { - if (leadingTrackPt > -1.) { - spectra.fill(HIST("ptphiLeadingTrack"), leadingTrackPt, - leadingTrackPhi); - spectra.fill(HIST("ptetaLeadingTrack"), leadingTrackPt, - leadingTrackEta); - } - } - - // Find leading jet pT in full TPC volume - for (auto& jet : jets) { - if (fabs(jet.eta()) < static_cast(cfgTPCVolume)) { - - if (jet.pt() > leadingJetPt) { - leadingJetPt = jet.pt(); - leadingJetEta = jet.eta(); - leadingJetPhi = jet.phi(); - } - } - } - - if (leadingJetPt > -1.) { - spectra.fill(HIST("ptphiLeadingJetFullVol"), leadingJetPt, leadingJetPhi); - spectra.fill(HIST("ptetaLeadingJetFullVol"), leadingJetPt, leadingJetEta); - } - - if (bAddSupplementHistosToOutput) { - if (leadingJetPt > -1. && leadingTrackPt > -1.) { - spectra.fill(HIST("fLeadJetChPtVsLeadingTrack"), leadingTrackPt, - leadingJetPt); // leading jet pT versus leading track pT - } - } - - // Inclusive Jet pT spectrum in Fiducial volume - for (auto& jet : jets) { - if (fabs(jet.eta()) < fiducialVolume) { - spectra.fill(HIST("ptJetChInclFidVol"), jet.pt()); - spectra.fill(HIST("ptphiJetChInclFidVol"), jet.pt(), jet.phi()); - spectra.fill(HIST("ptetaJetChInclFidVol"), jet.pt(), jet.eta()); - - if (bAddSupplementHistosToOutput) { - spectra.fill(HIST("phietaJetChInclFidVol"), jet.eta(), jet.phi()); - if (jet.pt() > 10.0) { - spectra.fill(HIST("phietaJetChInclHighPtFidVol"), jet.eta(), jet.phi()); - } - spectra.fill(HIST("jetAreaFidVol"), jet.pt(), jet.area()); - } - } - - if (fabs(jet.eta()) < static_cast(cfgTPCVolume)) { - spectra.fill(HIST("ptphiJetChInclFullVol"), jet.pt(), jet.phi()); - spectra.fill(HIST("ptetaJetChInclFullVol"), jet.pt(), jet.eta()); - - if (bAddSupplementHistosToOutput) { - spectra.fill(HIST("ptJetChInclFullVol"), jet.pt()); - - spectra.fill(HIST("phietaJetChInclFullVol"), jet.eta(), jet.phi()); - if (jet.pt() > 10.0) { - spectra.fill(HIST("phietaJetChInclHighPtFullVol"), jet.eta(), jet.phi()); - } - spectra.fill(HIST("jetAreaFullVol"), jet.pt(), jet.area()); - } - } - } - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - - return WorkflowSpec{adaptAnalysisTask( - cfgc, TaskName{"jet-charged-trigger-qa"})}; -} diff --git a/PWGJE/Tasks/PhotonIsolationQA.cxx b/PWGJE/Tasks/PhotonIsolationQA.cxx deleted file mode 100644 index e25d9e11094..00000000000 --- a/PWGJE/Tasks/PhotonIsolationQA.cxx +++ /dev/null @@ -1,364 +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 -#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 mcCells = o2::soa::Join; -using filteredMCCells = o2::soa::Filtered; -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; - - 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"}; - - Filter PosZFilter = nabs(aod::collision::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; // mc emcal cell - - using selectedCollisions = soa::Filtered; - using selectedClusters = soa::Filtered; - using selectedMCClusters = soa::Filtered; - - Preslice perClusterMatchedTracks = o2::aod::emcalclustercell::emcalclusterId; - - int eventSelection = -1; - int trackSelection = -1; - void init(o2::framework::InitContext&) - { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); - trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - - 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 Pt_Axis{100, 0, 100, "P_{T} (GeV/c)"}; - const o2Axis P_Axis{100, 0, 100, "P (GeV/c)"}; - const o2Axis RatioP_Axis{50, 0, 10, "E/P"}; - const o2Axis Num_Track_Axis{20, 0, 20, "N Tracks"}; - const o2Axis PtIso_Axis{100, -10, 15, "P_{T, Iso} (GeV/c)"}; - const o2Axis Rho_Axis{100, 0, 100, "#rho (#frac{GeV/c}{A})"}; - const o2Axis ABCD_Axis{5, 0, 5, "ABCD"}; - const o2Axis NLM_Axis{3, 0, 3, "NLM"}; - const o2Axis Fraction_Axis{50, 0, 2}; - - 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", "Energy of the cluster", o2HistType::kTH1F, {Energy_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::kTHnSparseL, {{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("hTrackPt", "Pt of matched track", o2HistType::kTH1F, {Pt_Axis}); - Data_Info.add("hTrackEta", "Eta of matched track", o2HistType::kTH1F, {Eta_Axis}); - Data_Info.add("hTrackPhi", "Phi of matched track", o2HistType::kTH1F, {Phi_Axis}); - Data_Info.add("hRatioClusterETrackP", "Ratio between energy of cluster and P of tracks", o2HistType::kTH1F, {RatioP_Axis}); - Data_Info.add("hRatioClusterETrackPrackPt", "Ratio between E and P vs Pt of matched tracks", o2HistType::kTH2F, {{RatioP_Axis}, {Pt_Axis}}); - - Data_Info.add("hEvsPtIso", "Pt_Iso", o2HistType::kTH2F, {{Energy_Axis}, {PtIso_Axis}}); - Data_Info.add("hRho_Perpen_Cone", "Density of perpendicular cone", o2HistType::kTH1F, {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::kTH2F, {{Shower_Shape_Long_Axis}, {PtIso_Axis}}); - Data_Info.add("hABCDControlRegion", "Yield Control Regions", o2HistType::kTH2F, {{ABCD_Axis}, {Energy_Axis}}); - Data_Info.add("hE_M02_M20_NLM_NCells_PtIso", "Energy vs M02 vs M20 vs NLM vs NCells vs PtIso", o2HistType::kTHnSparseL, {{Energy_Axis}, {Shower_Shape_Long_Axis}, {Shower_Shape_Short_Axis}, {NLM_Axis}, {NCells_Axis}, {PtIso_Axis}}); - - MC_Info.add("hPosZ", "Z Position of collision", o2HistType::kTH1F, {PosZ_Axis}); - MC_Info.add("hNumClusters", "Number of cluster per collision", o2HistType::kTH1F, {Num_Cluster_Axis}); - MC_Info.add("hClusterLocation", "Location of shower in eta phi plane", o2HistType::kTH2F, {{Eta_Axis}, {Phi_Axis}}); - MC_Info.add("hEnergy", "Energy of the cluster", o2HistType::kTH1F, {Energy_Axis}); - MC_Info.add("hEnergy_ShowerShapeLong", "Energy vs Shower shape long axis", o2HistType::kTH2F, {{Energy_Axis}, {Shower_Shape_Long_Axis}}); - MC_Info.add("hEnergy_ShowerShapeShort", "Energy vs Shower shape short axis", o2HistType::kTH2F, {{Energy_Axis}, {Shower_Shape_Short_Axis}}); - MC_Info.add("hEnergy_m02_m20", "Energy cluster Vs m02 vs m20", o2HistType::kTHnSparseL, {{Energy_Axis}, {Shower_Shape_Long_Axis}, {Shower_Shape_Short_Axis}}); - MC_Info.add("hEnergy_NCells", "Energy vs Number of cells in cluster", o2HistType::kTH2F, {{Energy_Axis}, {NCells_Axis}}); - - MC_Info.add("hEvsNumTracks", "Energy of cluster vs matched tracks", o2HistType::kTH2F, {{Energy_Axis}, {Num_Track_Axis}}); - MC_Info.add("hTrackPt", "Pt of matched track", o2HistType::kTH1F, {Pt_Axis}); - MC_Info.add("hTrackEta", "Eta of matched track", o2HistType::kTH1F, {Eta_Axis}); - MC_Info.add("hTrackPhi", "Phi of matched track", o2HistType::kTH1F, {Phi_Axis}); - MC_Info.add("hRatioClusterETrackP", "Ratio between energy of cluster and P of tracks", o2HistType::kTH1F, {RatioP_Axis}); - MC_Info.add("hRatioClusterETrackPrackPt", "Ratio between E and P vs Pt of matched tracks", o2HistType::kTH2F, {{RatioP_Axis}, {Pt_Axis}}); - MC_Info.add("hE_M02_M20_NLM_NCells_PtIso", "Energy vs M02 vs M20 vs NLM vs NCells vs PtIso", o2HistType::kTHnSparseL, {{Energy_Axis}, {Shower_Shape_Long_Axis}, {Shower_Shape_Short_Axis}, {NLM_Axis}, {NCells_Axis}, {PtIso_Axis}}); - - MC_Info.add("hEvsPtIso", "Pt_Iso", o2HistType::kTH2F, {{Energy_Axis}, {PtIso_Axis}}); - MC_Info.add("hRho_Perpen_Cone", "Density of perpendicular cone", o2HistType::kTH1F, {Rho_Axis}); - MC_Info.add("hShowerShape", "Shower shape", o2HistType::kTH2F, {{Shower_Shape_Long_Axis}, {Shower_Shape_Short_Axis}}); - MC_Info.add("hSigmaLongvsPtIso", "Long shower shape vs Pt_Iso", o2HistType::kTH2F, {{Shower_Shape_Long_Axis}, {PtIso_Axis}}); - MC_Info.add("hABCDControlRegion", "Yield Control Regions", o2HistType::kTH2F, {{ABCD_Axis}, {Energy_Axis}}); - MC_Info.add("hMcParticlesToCluster", "Energy of particles linked to mc cluster", o2HistType::kTH1F, {{100, 0, 100}}); - MC_Info.add("hMcParticleStatusCode", "generator status code of mc particle linked to mc cluster", o2HistType::kTH1F, {{200, 0, 200}}); - MC_Info.add("hMcParticleProcessCode", "physical process code of mc particle linked to mc cluster", o2HistType::kTH1F, {{200, 0, 200}}); - - 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 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) - { - registry.fill(HIST("hClusterLocation"), cluster.eta(), cluster.phi()); - registry.fill(HIST("hEnergy"), cluster.energy()); - 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()); - } - - void fillABCDHisto(HistogramRegistry registry, const auto& cluster, double Pt_iso) - { - 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()); - } - } - - void fillMatchedTrackHistos(HistogramRegistry registry, const auto& cluster, o2::aod::EMCALMatchedTracks const& matched_tracks) - { - for (const auto& match : matched_tracks) { - registry.fill(HIST("hTrackPt"), match.track_as().pt()); - registry.fill(HIST("hTrackEta"), match.track_as().eta()); - registry.fill(HIST("hTrackPhi"), match.track_as().phi()); - registry.fill(HIST("hRatioClusterETrackP"), cluster.energy() / abs(match.track_as().p())); - registry.fill(HIST("hRatioClusterETrackPrackPt"), cluster.energy() / abs(match.track_as().p()), match.track_as().pt()); - } - } - - // process monte carlo data - void processMC(selectedCollisions::iterator const& theCollision, selectedMCClusters const& mcclusters, aod::StoredMcParticles_001 const&, myGlobTracks const& tracks, o2::aod::EMCALClusterCells const& /*emccluscells*/, o2::aod::EMCALMatchedTracks const& matchedtracks) - { - MC_Info.fill(HIST("hPosZ"), theCollision.posZ()); - - if (mcclusters.size() > 0) { - MC_Info.fill(HIST("hNumClusters"), mcclusters.size()); - } - - for (auto& mccluster : mcclusters) { - auto tracksofcluster = matchedtracks.sliceBy(perClusterMatchedTracks, mccluster.globalIndex()); - fillclusterhistos(mccluster, MC_Info); - fillMatchedTrackHistos(MC_Info, mccluster, tracksofcluster); - MC_Info.fill(HIST("hEvsNumTracks"), mccluster.energy(), tracksofcluster.size()); - - if (!track_matching(mccluster, tracksofcluster)) { // no track with significant momentum is matched to cluster - double Pt_Cone = sum_Pt_tracks_in_cone(mccluster, tracks); - double Rho_Perpen_Cone = Rho_Perpendicular_Cone(mccluster, tracks); - double Pt_iso = Pt_Iso(Pt_Cone, Rho_Perpen_Cone); - - MC_Info.fill(HIST("hEvsPtIso"), mccluster.energy(), Pt_iso); - MC_Info.fill(HIST("hRho_Perpen_Cone"), Rho_Perpen_Cone); - MC_Info.fill(HIST("hShowerShape"), mccluster.m02(), mccluster.m20()); - MC_Info.fill(HIST("hSigmaLongvsPtIso"), mccluster.m02(), Pt_iso); - MC_Info.fill(HIST("hE_M02_M20_NLM_NCells_PtIso"), mccluster.energy(), mccluster.m02(), mccluster.m20(), mccluster.nlm(), mccluster.nCells(), Pt_iso); - fillABCDHisto(MC_Info, mccluster, Pt_iso); - // acces mc true info - auto ClusterParticles = mccluster.mcParticle_as(); - bool background = true; - for (auto& clusterparticle : ClusterParticles) { - if (clusterparticle.pdgCode() == 22) { - MC_Info.fill(HIST("hMcParticlesToCluster"), clusterparticle.e()); - MC_Info.fill(HIST("hMcParticleProcessCode"), clusterparticle.getProcess()); - MC_Info.fill(HIST("hMcParticleStatusCode"), clusterparticle.getGenStatusCode()); - if ((clusterparticle.getProcess() >= 21) && (clusterparticle.getProcess() <= 29)) - background = false; // Particles from the hardest subprocess - } - } - - if (background) { - if ((Pt_iso < 1.5) && (mccluster.m02() < 0.3) && (mccluster.m02() > 0.1)) { - MC_Info.fill(HIST("hABCDControlRegion"), 4.5, mccluster.energy()); - } - } - } - } - } - - PROCESS_SWITCH(PhotonIsolationQA, processMC, "proces MC data", true); - - void processData(selectedCollisions::iterator const& theCollision, selectedClusters const& clusters, o2::aod::EMCALClusterCells const& /*emccluscells*/, o2::aod::EMCALMatchedTracks const& matchedtracks, myGlobTracks const& alltracks) - { - Data_Info.fill(HIST("hPosZ"), theCollision.posZ()); - - if (clusters.size() > 0) { - Data_Info.fill(HIST("hNumClusters"), clusters.size()); - } - - for (const auto& cluster : clusters) { - auto tracksofcluster = matchedtracks.sliceBy(perClusterMatchedTracks, cluster.globalIndex()); - fillclusterhistos(cluster, Data_Info); - fillMatchedTrackHistos(Data_Info, cluster, tracksofcluster); - Data_Info.fill(HIST("hEvsNumTracks"), cluster.energy(), tracksofcluster.size()); - - if (!track_matching(cluster, tracksofcluster)) { // no track with significant momentum is matched to cluster - double Pt_Cone = sum_Pt_tracks_in_cone(cluster, alltracks); - double Rho_Perpen_Cone = Rho_Perpendicular_Cone(cluster, alltracks); - 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"), Rho_Perpen_Cone); - Data_Info.fill(HIST("hShowerShape"), cluster.m02(), cluster.m20()); - Data_Info.fill(HIST("hSigmaLongvsPtIso"), cluster.m02(), Pt_iso); - Data_Info.fill(HIST("hE_M02_M20_NLM_NCells_PtIso"), cluster.energy(), cluster.m02(), cluster.m20(), cluster.nlm(), cluster.nCells(), Pt_iso); - 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/bjetTaggingGnn.cxx b/PWGJE/Tasks/bjetTaggingGnn.cxx new file mode 100644 index 00000000000..b27100c1f84 --- /dev/null +++ b/PWGJE/Tasks/bjetTaggingGnn.cxx @@ -0,0 +1,751 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetTagging.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 eventSelectionsSel{"eventSelectionsSel", "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.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 trackPtMinGnn{"trackPtMinGnn", 0.5, "minimum track pT for GNN inputs"}; + + Configurable maxIPxy{"maxIPxy", 10, "maximum track DCA in xy plane"}; + Configurable maxIPz{"maxIPz", 10, "maximum track DCA in z direction"}; + + Configurable trackNppCrit{"trackNppCrit", 0.95, "track not physical primary ratio"}; + + // sv 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 dbMin{"dbMin", -10., "minimum GNN Db"}; + Configurable dbMax{"dbMax", 20., "maximum GNN Db"}; + Configurable dbNbins{"dbNbins", 3000, "number of bins in axisDbFine"}; + + 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"}; + + Configurable trainingDatasetRatioParam{"trainingDatasetRatioParam", 0, "Parameter for splitting training/evaluation datasets by collisionId"}; + + std::vector eventSelectionBits; + std::vector eventSelectionBitsSel; + + std::vector jetRadiiValues; + + void init(InitContext const&) + { + jetRadiiValues = (std::vector)jetRadii; + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + eventSelectionBitsSel = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelectionsSel)); + + registry.add("h_vertexZ", "Vertex Z;#it{Z} (cm)", {HistType::kTH1F, {{100, -20.0, 20.0}}}, callSumw2); + // registry.add("h_vertexZ_truth", "Vertex Z truth;#it{Z} (cm)", {HistType::kTH1F, {{100, -20.0, 20.0}}}, callSumw2); + registry.add("h_event_counter", ";Event counter", {HistType::kTH1F, {{6, 0.0, 6.0}}}, callSumw2); + auto hEventCounter = registry.get(HIST("h_event_counter")); + hEventCounter->GetXaxis()->SetBinLabel(1, "Coll+TVX"); + hEventCounter->GetXaxis()->SetBinLabel(2, "Coll+TVX+Sel8"); + hEventCounter->GetXaxis()->SetBinLabel(3, "Coll+TVX+Sel8+"); + hEventCounter->GetXaxis()->SetBinLabel(4, "McColl(INEL)"); + hEventCounter->GetXaxis()->SetBinLabel(5, "McColl(-> Coll+TVX+Sel8)"); + hEventCounter->GetXaxis()->SetBinLabel(6, "McColl(-> Coll+TVX+Sel8+)"); + registry.add("hBCCounter", "", {HistType::kTH1F, {{10, 0.0, 10.}}}, callSumw2); + auto hBCCounter = registry.get(HIST("hBCCounter")); + hBCCounter->GetXaxis()->SetBinLabel(1, "AllBC"); + hBCCounter->GetXaxis()->SetBinLabel(2, "BC+TVX"); + hBCCounter->GetXaxis()->SetBinLabel(3, "BC+TVX+NoTFB"); + hBCCounter->GetXaxis()->SetBinLabel(4, "BC+TVX+NoTFB+NoITSROFB"); + hBCCounter->GetXaxis()->SetBinLabel(5, "CollinBC"); + hBCCounter->GetXaxis()->SetBinLabel(6, "CollinBC+Sel8"); + hBCCounter->GetXaxis()->SetBinLabel(7, "CollinBC+Sel8+VtxZ"); + hBCCounter->GetXaxis()->SetBinLabel(8, "CollinBC+Sel8Full"); + hBCCounter->GetXaxis()->SetBinLabel(9, "CollinBC+Sel8Full+GoodZvtx"); + hBCCounter->GetXaxis()->SetBinLabel(10, "CollinBC+Sel8Full+VtxZ+GoodZvtx"); + + const AxisSpec axisTrackpT{200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisTrackpTFine{1000, 0., 10., "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisJetpT{200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisDb{200, dbMin, dbMax, "#it{D}_{b}"}; + const AxisSpec axisDbFine{dbNbins, dbMin, dbMax, "#it{D}_{b}"}; + 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}}, callSumw2); + registry.add("h_Db", "", {HistType::kTH1F, {axisDbFine}}); + registry.add("h2_jetpT_Db", "", {HistType::kTH2F, {axisJetpT, axisDb}}); + + if (doprocessDataTracks || doprocessMCDTracks) { + registry.add("h_trackpT", "", {HistType::kTH1F, {axisTrackpT}}, callSumw2); + registry.add("h_tracketa", "", {HistType::kTH1F, {{100, trackEtaMin, trackEtaMax, "#it{#eta}"}}}, callSumw2); + registry.add("h_trackphi", "", {HistType::kTH1F, {{100, 0.0, 2.0 * M_PI, "#it{#phi}"}}}, callSumw2); + } + + if (doprocessMCDTracks) { + registry.add("h2_trackpT_partpT", "", {HistType::kTH2F, {axisTrackpT, axisTrackpT}}, callSumw2); + registry.add("h_partpT_matched_fine", "", {HistType::kTH1F, {axisTrackpTFine}}, callSumw2); + registry.add("h_partpT", "", {HistType::kTH1F, {axisTrackpT}}, callSumw2); + registry.add("h_partpT_fine", "", {HistType::kTH1F, {axisTrackpTFine}}, callSumw2); + } + + if (doprocessDataJetsSel || doprocessMCDJetsSel) { + registry.add("h_jetpT_sel", "", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_tvx", "", {HistType::kTH1F, {axisJetpT}}, callSumw2); + } + + if (doprocessMCDJets) { + registry.add("h_jetpT_b", "b-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_c", "c-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_lf", "lf-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + 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_Response_DetjetpT_PartjetpT", "", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_b", "b-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_c", "c-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_lf", "lf-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}, callSumw2}); + registry.add("h2_jetpT_Db_lf_none", "lf-jet (none)", {HistType::kTH2F, {axisJetpT, axisDb}}, callSumw2); + registry.add("h2_jetpT_Db_lf_matched", "lf-jet (matched)", {HistType::kTH2F, {axisJetpT, axisDb}}, callSumw2); + 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("h_jetpT_matched", "", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_matched", "", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_b_matched", "b-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_b_matched", "b-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("hSparse_overflow_b", "", {HistType::kTHnSparseF, {axisJetpT, axisJetpT, axisNTracks}}); + } + + if (doprocessMCDJetsSel) { + registry.add("h_jetpT_b_sel", "b-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_sel", "", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_b_sel", "b-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); + registry.add("h_jetpT_b_tvx", "b-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_tvx", "", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_b_tvx", "b-jet", {HistType::kTH2F, {axisJetpT, axisJetpT}}, callSumw2); + } + + if (doprocessMCPJets) { + registry.add("h_jetpT_particle", "", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_b", "particle b-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_c", "particle c-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_lf", "particle lf-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_sel", "", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_b_sel", "particle b-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_tvx", "", {HistType::kTH1F, {axisJetpT}}, callSumw2); + registry.add("h_jetpT_particle_b_tvx", "particle b-jet", {HistType::kTH1F, {axisJetpT}}, callSumw2); + } + + if (doDataDriven) { + registry.add("hSparse_Incljets", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisNTracks}}, callSumw2); + if (doprocessMCDJets) { + registry.add("hSparse_bjets", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisNTracks}}, callSumw2); + registry.add("hSparse_cjets", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisNTracks}}, callSumw2); + registry.add("hSparse_lfjets", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisNTracks}}, callSumw2); + registry.add("hSparse_lfjets_none", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisNTracks}}, callSumw2); + registry.add("hSparse_lfjets_matched", "", {HistType::kTHnSparseF, {axisJetpT, axisDbFine, axisNTracks}}, callSumw2); + } + } + } + + Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter trackFilter = (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 AnalysisCollisions = soa::Join; + using FilteredCollisions = soa::Filtered; + using DataJets = soa::Join; + using FilteredDataJets = soa::Filtered; + using AnalysisTracks = soa::Join; + using FilteredTracks = soa::Filtered; + + using MCDJets = soa::Join; + using FilteredMCDJets = soa::Filtered; + using AnalysisTracksMCD = soa::Join; + using FilteredTracksMCD = soa::Filtered; + + using AnalysisCollisionsMCD = soa::Join; + using FilteredCollisionsMCD = soa::Filtered; + + Filter mccollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + using FilteredCollisionsMCP = soa::Filtered; + using MCPJets = soa::Join; + using FilteredMCPJets = soa::Filtered; + + Service pdg; + + 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 || !jettaggingutilities::trackAcceptanceWithDca(constituent, maxIPxy, maxIPz)) { + continue; + } + + // ... + + ++nTracks; + } + return nTracks; + } + + void processDummy(FilteredCollisions::iterator const& /*collision*/) + { + } + PROCESS_SWITCH(BjetTaggingGnn, processDummy, "Dummy process function turned on by default", true); + + void processDataJets(FilteredCollisions::iterator const& collision, FilteredDataJets const& alljets, FilteredTracks const& allTracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + registry.fill(HIST("h_event_counter"), 2.5); // Coll+TVX+Sel8+... + + 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); + + registry.fill(HIST("h_jetpT"), analysisJet.pt()); + registry.fill(HIST("h_Db"), analysisJet.scoreML()); + registry.fill(HIST("h2_jetpT_Db"), analysisJet.pt(), analysisJet.scoreML()); + + if (doDataDriven) { + registry.fill(HIST("hSparse_Incljets"), analysisJet.pt(), analysisJet.scoreML(), nTracks); + } + } + } + PROCESS_SWITCH(BjetTaggingGnn, processDataJets, "jet information in Data", false); + + void processDataJetsSel(AnalysisCollisions::iterator const& collision, FilteredDataJets const& alljets) + { + registry.fill(HIST("h_event_counter"), 0.5); // Coll+TVX + + 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; + } + + registry.fill(HIST("h_jetpT_tvx"), analysisJet.pt()); + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBitsSel)) { + return; + } + registry.fill(HIST("h_event_counter"), 1.5); // Coll+TVX+Sel8 + + 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; + } + + registry.fill(HIST("h_jetpT_sel"), analysisJet.pt()); + } + } + PROCESS_SWITCH(BjetTaggingGnn, processDataJetsSel, "jet information in Data (sel8)", false); + + void processDataTracks(FilteredCollisions::iterator const& collision, AnalysisTracks const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + for (const auto& track : tracks) { + if (track.eta() <= trackEtaMin || track.eta() >= trackEtaMax) { + continue; + } + registry.fill(HIST("h_trackpT"), track.pt()); + registry.fill(HIST("h_tracketa"), track.eta()); + registry.fill(HIST("h_trackphi"), track.phi()); + } + } + PROCESS_SWITCH(BjetTaggingGnn, processDataTracks, "track information in Data", false); + + void processMCDJets(FilteredCollisionsMCD::iterator const& collision, FilteredMCDJets const& MCDjets, FilteredTracksMCD const& /*allTracks*/, FilteredMCPJets const& /*MCPjets*/, aod::JetParticles const& /*MCParticles*/, FilteredCollisionsMCP const& /*mcCollisions*/) + { + float weightEvt = useEventWeight ? collision.weight() : 1.f; + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + // Uses only collisionId % trainingDatasetRaioParam != 0 for evaluation dataset + if (trainingDatasetRatioParam && collision.collisionId() % trainingDatasetRatioParam == 0) { + return; + } + registry.fill(HIST("h_event_counter"), 2.5, weightEvt); + + registry.fill(HIST("h_vertexZ"), collision.posZ(), weightEvt); + + bool matchedMcColl = collision.has_mcCollision() && std::fabs(collision.template mcCollision_as().posZ()) < vertexZCut; + + 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 pTHat = 10. / (std::pow(weightEvt, 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() < trackPtMinGnn) { + continue; + } + if (!constituent.has_mcParticle() || !constituent.template mcParticle_as().isPhysicalPrimary()) { + ++nNppTracks; + } + ++nTracks; + } + + registry.fill(HIST("h_jetpT"), analysisJet.pt(), weightEvt); + registry.fill(HIST("h_Db"), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_jetpT_Db"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_b"), analysisJet.pt(), weightEvt); + registry.fill(HIST("h_Db_b"), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_jetpT_Db_b"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h_jetpT_c"), analysisJet.pt(), weightEvt); + registry.fill(HIST("h_Db_c"), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_jetpT_Db_c"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h_jetpT_lf"), analysisJet.pt(), weightEvt); + registry.fill(HIST("h_Db_lf"), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_jetpT_Db_lf"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + if (jetFlavor == JetTaggingSpecies::none) { + registry.fill(HIST("h2_jetpT_Db_lf_none"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h2_jetpT_Db_lf_matched"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + } + } + + if (static_cast(nNppTracks) / nTracks > trackNppCrit) { + registry.fill(HIST("h_Db_npp"), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_jetpT_Db_npp"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_Db_npp_b"), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_jetpT_Db_npp_b"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h_Db_npp_c"), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_jetpT_Db_npp_c"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h_Db_npp_lf"), analysisJet.scoreML(), weightEvt); + registry.fill(HIST("h2_jetpT_Db_npp_lf"), analysisJet.pt(), analysisJet.scoreML(), weightEvt); + } + } + + if (doDataDriven) { + registry.fill(HIST("hSparse_Incljets"), analysisJet.pt(), analysisJet.scoreML(), nTracks, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("hSparse_bjets"), analysisJet.pt(), analysisJet.scoreML(), nTracks, weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("hSparse_cjets"), analysisJet.pt(), analysisJet.scoreML(), nTracks, weightEvt); + } else { + registry.fill(HIST("hSparse_lfjets"), analysisJet.pt(), analysisJet.scoreML(), nTracks, weightEvt); + if (jetFlavor == JetTaggingSpecies::none) { + registry.fill(HIST("hSparse_lfjets_none"), analysisJet.pt(), analysisJet.scoreML(), nTracks, weightEvt); + } else { + registry.fill(HIST("hSparse_lfjets_matched"), analysisJet.pt(), analysisJet.scoreML(), nTracks, weightEvt); + } + } + } + + if (!matchedMcColl) { + continue; + } + + 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(), weightEvt); + registry.fill(HIST("h_jetpT_matched"), analysisJet.pt(), weightEvt); + registry.fill(HIST("h_jetpT_particle_matched"), mcpjet.pt(), weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_b"), analysisJet.pt(), mcpjet.pt(), weightEvt); + registry.fill(HIST("h_jetpT_b_matched"), analysisJet.pt(), weightEvt); + registry.fill(HIST("h_jetpT_particle_b_matched"), mcpjet.pt(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_c"), analysisJet.pt(), mcpjet.pt(), weightEvt); + } else { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_lf"), analysisJet.pt(), mcpjet.pt(), weightEvt); + } + } + } + } + PROCESS_SWITCH(BjetTaggingGnn, processMCDJets, "jet information in MC", false); + + void processMCDJetsSel(AnalysisCollisionsMCD::iterator const& collision, FilteredMCDJets const& MCDjets, FilteredMCPJets const& /*MCPjets*/) + { + float weightEvt = useEventWeight ? collision.weight() : 1.f; + registry.fill(HIST("h_event_counter"), 0.5, weightEvt); + + 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 pTHat = 10. / (std::pow(weightEvt, 1.0 / pTHatExponent)); + if (analysisJet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + + int8_t jetFlavor = analysisJet.origin(); + + registry.fill(HIST("h_jetpT_tvx"), analysisJet.pt(), weightEvt); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_b_tvx"), analysisJet.pt(), weightEvt); + } + + for (const auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_tvx"), analysisJet.pt(), mcpjet.pt(), weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_b_tvx"), analysisJet.pt(), mcpjet.pt(), weightEvt); + } + } + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBitsSel)) { + return; + } + registry.fill(HIST("h_event_counter"), 1.5, weightEvt); + + 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 pTHat = 10. / (std::pow(weightEvt, 1.0 / pTHatExponent)); + if (analysisJet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + + int8_t jetFlavor = analysisJet.origin(); + + registry.fill(HIST("h_jetpT_sel"), analysisJet.pt(), weightEvt); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_b_sel"), analysisJet.pt(), weightEvt); + } + + for (const auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_sel"), analysisJet.pt(), mcpjet.pt(), weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_b_sel"), analysisJet.pt(), mcpjet.pt(), weightEvt); + } + } + } + } + PROCESS_SWITCH(BjetTaggingGnn, processMCDJetsSel, "jet information in MC (sel8)", false); + + PresliceUnsorted collisionsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; + Preslice mcpjetsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; + + void processMCPJets(aod::McCollisions::iterator const& mcCollision, FilteredMCPJets const& mcpjets, AnalysisCollisionsMCD const& collisions, aod::JetParticles const& /*MCParticles*/) + { + float weightEvt = useEventWeight ? mcCollision.weight() : 1.f; + registry.fill(HIST("h_event_counter"), 3.5, weightEvt); // McColl(INEL) + auto collisionspermccollision = collisions.sliceBy(collisionsPerMCPCollision, mcCollision.globalIndex()); + if (collisionspermccollision.size() >= 1) { + if (jetderiveddatautilities::selectCollision(collisionspermccollision.begin(), eventSelectionBitsSel)) { + registry.fill(HIST("h_event_counter"), 4.5, weightEvt); // McColl(-> Coll+TVX+Sel8) + } + if (jetderiveddatautilities::selectCollision(collisionspermccollision.begin(), eventSelectionBits) && std::fabs(collisionspermccollision.begin().posZ()) < vertexZCut) { + registry.fill(HIST("h_event_counter"), 5.5, weightEvt); // McColl(-> Coll+TVX+Sel8+...) + } + } + + auto mcpjetspermcpcollision = mcpjets.sliceBy(mcpjetsPerMCPCollision, mcCollision.globalIndex()); + for (const auto& mcpjet : mcpjetspermcpcollision) { + bool jetIncluded = false; + for (const auto& jetR : jetRadiiValues) { + if (mcpjet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + float pTHat = 10. / (std::pow(weightEvt, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + int8_t jetFlavor = mcpjet.origin(); + + registry.fill(HIST("h_jetpT_particle_tvx"), mcpjet.pt(), weightEvt); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_particle_b_tvx"), mcpjet.pt(), weightEvt); + } + + if (collisionspermccollision.size() >= 1) { + if (jetderiveddatautilities::selectCollision(collisionspermccollision.begin(), eventSelectionBitsSel)) { + registry.fill(HIST("h_jetpT_particle_sel"), mcpjet.pt(), weightEvt); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_particle_b_sel"), mcpjet.pt(), weightEvt); + } + } + + if (jetderiveddatautilities::selectCollision(collisionspermccollision.begin(), eventSelectionBits) && std::fabs(collisionspermccollision.begin().posZ()) < vertexZCut && std::fabs(mcCollision.posZ()) < vertexZCut) { + registry.fill(HIST("h_jetpT_particle"), mcpjet.pt(), weightEvt); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_particle_b"), mcpjet.pt(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h_jetpT_particle_c"), mcpjet.pt(), weightEvt); + } else { + registry.fill(HIST("h_jetpT_particle_lf"), mcpjet.pt(), weightEvt); + } + } + } + } + } + PROCESS_SWITCH(BjetTaggingGnn, processMCPJets, "mc collision information", false); + + Preslice mcparticlesPerMCPCollision = aod::jmcparticle::mcCollisionId; + + void processMCDTracks(FilteredCollisionsMCD::iterator const& collision, AnalysisTracksMCD const& tracks, FilteredCollisionsMCP const& /*mcCollisions*/, aod::JetParticles const& allParticles) + { + float weightEvt = useEventWeight ? collision.weight() : 1.f; + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + // Uses only collisionId % trainingDatasetRaioParam != 0 for evaluation dataset + if (trainingDatasetRatioParam && collision.collisionId() % trainingDatasetRatioParam == 0) { + return; + } + + bool matchedMcColl = collision.has_mcCollision() && std::fabs(collision.template mcCollision_as().posZ()) < vertexZCut; + + for (const auto& track : tracks) { + if (track.eta() <= trackEtaMin || track.eta() >= trackEtaMax) { + continue; + } + registry.fill(HIST("h_trackpT"), track.pt(), weightEvt); + registry.fill(HIST("h_tracketa"), track.eta(), weightEvt); + registry.fill(HIST("h_trackphi"), track.phi(), weightEvt); + + if (!matchedMcColl || !track.has_mcParticle()) { + continue; + } + auto particle = track.template mcParticle_as(); + if (particle.isPhysicalPrimary() && particle.eta() > trackEtaMin && particle.eta() < trackEtaMax) { + registry.fill(HIST("h2_trackpT_partpT"), track.pt(), particle.pt(), weightEvt); + registry.fill(HIST("h_partpT_matched_fine"), particle.pt(), weightEvt); + } + } + + if (!matchedMcColl) { + return; + } + + auto const particles = allParticles.sliceBy(mcparticlesPerMCPCollision, collision.mcCollisionId()); + + for (const auto& particle : particles) { + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0.0) { + continue; + } + if (particle.isPhysicalPrimary() && particle.eta() > trackEtaMin && particle.eta() < trackEtaMax) { + registry.fill(HIST("h_partpT"), particle.pt(), weightEvt); + registry.fill(HIST("h_partpT_fine"), particle.pt(), weightEvt); + } + } + } + PROCESS_SWITCH(BjetTaggingGnn, processMCDTracks, "track information in MCD", false); + + PresliceUnsorted> perFoundBC = aod::evsel::foundBCId; + + void processBCs(soa::Join const& bcs, soa::Join const& collisions) + { + if (bcs.size() == 0) { + return; + } + for (const auto& bc : bcs) { + registry.fill(HIST("hBCCounter"), 0.5); // All BC + if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) { + registry.fill(HIST("hBCCounter"), 1.5); // BC+TVX + if (bc.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + registry.fill(HIST("hBCCounter"), 2.5); // BC+TVX+NoTFB + if (bc.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + registry.fill(HIST("hBCCounter"), 3.5); // BC+TVX+NoTFB+NoITSROFB ----> this goes to Lumi i.e. hLumiAfterBCcuts in eventSelection task + } + } + } + auto collisionsInBC = collisions.sliceBy(perFoundBC, bc.globalIndex()); + for (const auto& collision : collisionsInBC) { + registry.fill(HIST("hBCCounter"), 4.5); // CollinBC + if (collision.sel8()) { + registry.fill(HIST("hBCCounter"), 5.5); // CollinBC+sel8 + if (std::fabs(collision.posZ()) < vertexZCut) { + registry.fill(HIST("hBCCounter"), 6.5); // CollinBC+sel8+VtxZ + } + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + registry.fill(HIST("hBCCounter"), 7.5); // CollinBC+sel8Full + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + registry.fill(HIST("hBCCounter"), 8.5); // CollinBC+sel8Full+GoodZvtx + if (std::fabs(collision.posZ()) < vertexZCut) { + registry.fill(HIST("hBCCounter"), 9.5); // CollinBC+sel8Full+VtxZ+GoodZvtx ----> this goes to my analysis task for jet events selection + } + } + } + } + } // collision loop + } // bc loop + } + PROCESS_SWITCH(BjetTaggingGnn, processBCs, "BCs for 0 vertex QA", 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..6e1b135b745 --- /dev/null +++ b/PWGJE/Tasks/bjetTaggingML.cxx @@ -0,0 +1,603 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetTagging.h" + +#include "Common/Core/RecoDecay.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct BJetTaggingML { + + HistogramRegistry registry; + + // event level configurables + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; + + 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 maxIPxy{"maxIPxy", 10, "maximum track DCA in xy plane"}; + Configurable maxIPz{"maxIPz", 10, "maximum track DCA in z direction"}; + + // 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 useDb{"useDb", false, "Flag whether to use the Db instead of the score for tagging"}; + Configurable callSumw2{"callSumw2", false, "Flag whether to use sum weight squared for THnSparse error calculation"}; + + 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)); + + const AxisSpec axisDb{300, -10., 20., "#it{D}_{b}"}; + const AxisSpec axisScore{120, -0.1, 1.1, "Score"}; + const AxisSpec axisLogScore{120, 0., 30, "-log(1-score)"}; + + 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.}, useDb ? axisDb : axisScore}}); + 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.}, axisLogScore}}); + + 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.}, useDb ? axisDb : axisScore, axisLogScore, {50, 0, 50}, {375, 0, 30}, {50, 0, 10}, {50, 0, 1}}}, callSumw2); + if (doprocessMCJets || doprocessMCJetsWeighted) { + 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.}, useDb ? axisDb : axisScore, axisLogScore, {50, 0, 50}, {375, 0, 30}, {50, 0, 10}, {50, 0, 1}}}, callSumw2); + 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.}, useDb ? axisDb : axisScore, axisLogScore, {50, 0, 50}, {375, 0, 30}, {50, 0, 10}, {50, 0, 1}}}, callSumw2); + 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.}, useDb ? axisDb : axisScore, axisLogScore, {50, 0, 50}, {375, 0, 30}, {50, 0, 10}, {50, 0, 1}}}, callSumw2); + } + } + + if (doprocessMCJets || doprocessMCJetsWeighted || doprocessMCTruthJets || doprocessMCTruthJetsWeighted) { + + registry.add("h2_score_jetpT_bjet", "ML scores for b-jets;#it{p}_{T,jet} (GeV/#it{c});Score", {HistType::kTH2F, {{200, 0., 200.}, useDb ? axisDb : axisScore}}); + 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.}, axisLogScore}}); + 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.}, useDb ? axisDb : axisScore}}); + 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.}, axisLogScore}}); + 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.}, useDb ? axisDb : axisScore}}); + 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.}, axisLogScore}}); + 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.}}}, callSumw2); + 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.}}}, callSumw2); + 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.}}}, callSumw2); + } + } + + // 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 || doprocessMCJetsWeighted) { + if (jetFlavor == JetTaggingSpecies::beauty) { + 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 == JetTaggingSpecies::charm) { + 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 || !jettaggingutilities::trackAcceptanceWithDca(constituent, maxIPxy, maxIPz)) { + 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 || doprocessMCJetsWeighted) { + if (jetFlavor == JetTaggingSpecies::beauty) { + 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 == JetTaggingSpecies::charm) { + 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 = [](const jettaggingutilities::BJetTrackParams& tr1, const 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); + } + + template + void processJetInfo(AnalysisJet const& myJet, AnyTracks const& allTracks, SecondaryVertices const& allSVs, int8_t jetFlavor = 0, double eventWeight = 1.0) + { + std::vector tracksParams; + std::vector svsParams; + + analyzeJetSVInfo(myJet, allSVs, svsParams, jetFlavor, eventWeight); + analyzeJetTrackInfo(myJet, allTracks, tracksParams, jetFlavor, eventWeight); + + int nSVs = myJet.template secondaryVertices_as().size(); + int nTracks = myJet.template tracks_as().size(); + + registry.fill(HIST("h2_nTracks_jetpT"), myJet.pt(), nTracks); + registry.fill(HIST("h2_nSV_jetpT"), myJet.pt(), nSVs < 250 ? nSVs : 249); + + registry.fill(HIST("h2_score_jetpT"), myJet.pt(), myJet.scoreML(), eventWeight); + if (!useDb) { + registry.fill(HIST("h2_logscore_jetpT"), myJet.pt(), -1 * std::log(1 - myJet.scoreML()), eventWeight); + } + registry.fill(HIST("h2_jetMass_jetpT"), myJet.pt(), myJet.mass(), eventWeight); + + if (doDataDriven) { + registry.fill(HIST("hSparse_Incljets"), myJet.pt(), myJet.scoreML(), useDb ? 0 : -1 * std::log(1 - myJet.scoreML()), myJet.mass(), -1 * std::log(myJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE, eventWeight); + if (doprocessMCJets || doprocessMCJetsWeighted) { + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("hSparse_bjets"), myJet.pt(), myJet.scoreML(), useDb ? 0 : -1 * std::log(1 - myJet.scoreML()), myJet.mass(), -1 * std::log(myJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE, eventWeight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("hSparse_cjets"), myJet.pt(), myJet.scoreML(), useDb ? 0 : -1 * std::log(1 - myJet.scoreML()), myJet.mass(), -1 * std::log(myJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE, eventWeight); + } else { + registry.fill(HIST("hSparse_lfjets"), myJet.pt(), myJet.scoreML(), useDb ? 0 : -1 * std::log(1 - myJet.scoreML()), myJet.mass(), -1 * std::log(myJet.jetProb()), svsParams[0].svMass, svsParams[0].svfE, eventWeight); + } + } + } + + if (doprocessMCJets || doprocessMCJetsWeighted) { + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_score_jetpT_bjet"), myJet.pt(), myJet.scoreML(), eventWeight); + if (!useDb) { + registry.fill(HIST("h2_logscore_jetpT_bjet"), myJet.pt(), -1 * std::log(1 - myJet.scoreML()), eventWeight); + } + registry.fill(HIST("h2_jetMass_jetpT_bjet"), myJet.pt(), myJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_bjet"), myJet.pt(), eventWeight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_score_jetpT_cjet"), myJet.pt(), myJet.scoreML(), eventWeight); + if (!useDb) { + registry.fill(HIST("h2_logscore_jetpT_cjet"), myJet.pt(), -1 * std::log(1 - myJet.scoreML()), eventWeight); + } + registry.fill(HIST("h2_jetMass_jetpT_cjet"), myJet.pt(), myJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_cjet"), myJet.pt(), eventWeight); + } else { + registry.fill(HIST("h2_score_jetpT_lfjet"), myJet.pt(), myJet.scoreML(), eventWeight); + if (!useDb) { + registry.fill(HIST("h2_logscore_jetpT_lfjet"), myJet.pt(), -1 * std::log(1 - myJet.scoreML()), eventWeight); + } + registry.fill(HIST("h2_jetMass_jetpT_lfjet"), myJet.pt(), myJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_lfjet"), myJet.pt(), eventWeight); + } + } + } + + template + void fillMCPHistograms(AnalysisJetMCP const& mcpjet, bool detColl = false, double eventWeight = 1.0) + { + int8_t jetFlavor = mcpjet.origin(); + + if (detColl) { + + registry.fill(HIST("h_jetpT_particle_DetColl"), mcpjet.pt(), eventWeight); + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_particle_DetColl_bjet"), mcpjet.pt(), eventWeight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h_jetpT_particle_DetColl_cjet"), mcpjet.pt(), eventWeight); + } else { + registry.fill(HIST("h_jetpT_particle_DetColl_lfjet"), mcpjet.pt(), eventWeight); + } + } else { + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h_jetpT_particle_bjet"), mcpjet.pt(), eventWeight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h_jetpT_particle_cjet"), mcpjet.pt(), eventWeight); + } else { + registry.fill(HIST("h_jetpT_particle_lfjet"), mcpjet.pt(), eventWeight); + } + } + } + + 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; + } + + processJetInfo(analysisJet, allTracks, allSVs); + } + } + PROCESS_SWITCH(BJetTaggingML, processDataJets, "jet information in Data", false); + + using MCDJetTableWeighted = soa::Filtered>; + using MCPJetTableWeighted = soa::Filtered>; + using FilteredCollisionMCD = soa::Filtered>; + + Preslice mcpJetsPerCollisionWeighted = aod::jet::mcCollisionId; + + void processMCJetsWeighted(FilteredCollisionMCD::iterator const& collision, MCDJetTableWeighted const& MCDjets, MCPJetTableWeighted 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(mcpJetsPerCollisionWeighted, 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 = analysisJet.eventWeight(); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (analysisJet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + + int jetFlavor = analysisJet.origin(); + + processJetInfo(analysisJet, allTracks, allSVs, jetFlavor, eventWeight); + + for (const auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_bjet"), analysisJet.pt(), mcpjet.pt(), eventWeight); + } else if (jetFlavor == JetTaggingSpecies::charm) { + 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 = mcpjet.eventWeight(); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + fillMCPHistograms(mcpjet, true, eventWeight); + } + } + PROCESS_SWITCH(BJetTaggingML, processMCJetsWeighted, "jet information in MC with event weight", false); + + using MCDJetTable = soa::Filtered>; + using MCPJetTable = 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; + } + + int jetFlavor = analysisJet.origin(); + + processJetInfo(analysisJet, allTracks, allSVs, jetFlavor); + + for (const auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_bjet"), analysisJet.pt(), mcpjet.pt()); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_cjet"), analysisJet.pt(), mcpjet.pt()); + } else { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_lfjet"), analysisJet.pt(), mcpjet.pt()); + } + } + } + + // 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; + } + + fillMCPHistograms(mcpjet, true); + } + } + PROCESS_SWITCH(BJetTaggingML, processMCJets, "jet information in MC without event weight", false); + + Filter mccollisionFilter = nabs(aod::jmccollision::posZ) < vertexZCut; + using FilteredCollisionMCP = soa::Filtered; + + void processMCTruthJetsWeighted(FilteredCollisionMCP::iterator const& /*collision*/, MCPJetTableWeighted 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 = mcpjet.eventWeight(); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + fillMCPHistograms(mcpjet, false, eventWeight); + } + } + PROCESS_SWITCH(BJetTaggingML, processMCTruthJetsWeighted, "truth jet information with event weight", false); + + 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; + } + + fillMCPHistograms(mcpjet); + } + } + PROCESS_SWITCH(BJetTaggingML, processMCTruthJets, "truth jet information without event weight", 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 index 6f51e12d3cf..884a73d0833 100644 --- a/PWGJE/Tasks/bjetTreeCreator.cxx +++ b/PWGJE/Tasks/bjetTreeCreator.cxx @@ -15,25 +15,39 @@ /// /// \author Hadi Hassan , University of Jyväskylä -#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/Core/JetUtilities.h" #include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.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" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -44,14 +58,15 @@ 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 +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 +DECLARE_SOA_COLUMN(JetEventWeight, jetEventWeight, float); //! The jet event weight for pTHat weighting } // namespace jetInfo DECLARE_SOA_TABLE(bjetParams, "AOD", "BJETPARAM", @@ -67,6 +82,12 @@ DECLARE_SOA_TABLE(bjetParams, "AOD", "BJETPARAM", using bjetParam = bjetParams::iterator; +DECLARE_SOA_TABLE(bjetParamsExtra, "AOD", "BJETPARAMSEXTRA", + // o2::soa::Index<>, + jetInfo::JetEventWeight); + +using bjetParamExtra = bjetParamsExtra::iterator; + namespace trackInfo { DECLARE_SOA_INDEX_COLUMN(bjetParam, jetindex); //! The jet index @@ -77,10 +98,20 @@ DECLARE_SOA_COLUMN(DotProdTrackJetOverJet, trackdotjetoverjet, float); //! The d 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(SignedIPz, ipz, float); //! The track signed z IP +DECLARE_SOA_COLUMN(SignedIPzSign, ipzsigma, float); //! The track signed z IP significance 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 @@ -94,13 +125,28 @@ DECLARE_SOA_TABLE(bjetTracksParams, "AOD", "BJETTRACKSPARAM", trackInfo::DeltaRJetTrack, trackInfo::SignedIP2D, trackInfo::SignedIP2DSign, - trackInfo::SignedIP3D, + trackInfo::SignedIPz, + trackInfo::SignedIPzSign, 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 @@ -111,11 +157,11 @@ DECLARE_SOA_COLUMN(SVfE, svfe, float); //! The SV energy frac 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 -// DECLARE_SOA_COLUMN(SVDispersion, svdispersion, float); //! The SV dispersion, unfortunately it cannot be calculated in O2 } // namespace SVInfo DECLARE_SOA_TABLE(bjetSVParams, "AOD", "BJETSVPARAM", @@ -128,6 +174,7 @@ DECLARE_SOA_TABLE(bjetSVParams, "AOD", "BJETSVPARAM", SVInfo::IPXY, SVInfo::CPA, SVInfo::Chi2PCA, + SVInfo::Dispersion, SVInfo::DecayLength2D, SVInfo::DecayLength2DError, SVInfo::DecayLength3D, @@ -152,7 +199,9 @@ DECLARE_SOA_TABLE(bjetConstituents, "AOD", "BJETCONSTIT", struct BJetTreeCreator { Produces bjetParamsTable; + Produces bjetParamsExtraTable; Produces bjetTracksParamsTable; + Produces bjetTracksExtraTable; Produces bjetSVParamsTable; Produces bjetConstituentsTable; @@ -162,12 +211,24 @@ struct BJetTreeCreator { 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 maxIPxy{"maxIPxy", 10, "maximum track DCA in xy plane"}; + Configurable maxIPz{"maxIPz", 10, "maximum track DCA in z direction"}; + + 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"}; @@ -177,16 +238,25 @@ struct BJetTreeCreator { 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 produceSVTree{"produceSVTree", true, "produce the SV-correlated jet TTree”"}; Configurable produceTree{"produceTree", true, "produce the jet TTree"}; - int eventSelection = -1; + Configurable vtxRes{"vtxRes", 0.01, "Vertex position resolution (cluster size) for GNN vertex predictions (cm)"}; + + Configurable trainingDatasetRatioParam{"trainingDatasetRatioParam", 0, "Parameter for splitting training/evaluation datasets by collisionId"}; + + std::vector eventSelectionBits; std::vector jetRadiiValues; + std::vector jetPtBinsReduction; + std::vector jetReductionFactorsPt; void init(InitContext const&) { @@ -194,8 +264,10 @@ struct BJetTreeCreator { std::srand(static_cast(std::time(nullptr))); jetRadiiValues = (std::vector)jetRadii; + jetPtBinsReduction = (std::vector)jetPtBins; + jetReductionFactorsPt = (std::vector)jetReductionFactors; - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); registry.add("h_vertexZ", "Vertex Z;#it{Z} (cm)", {HistType::kTH1F, {{40, -20.0, 20.0}}}); @@ -205,29 +277,29 @@ struct BJetTreeCreator { 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, 50.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) { + 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, 50.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, 50.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, 50.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}}}); @@ -243,6 +315,45 @@ struct BJetTreeCreator { 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., o2::constants::math::TwoPI}}}); + 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 hJetFlavor = registry.get(HIST("h_jet_flav")); + hJetFlavor->GetXaxis()->SetBinLabel(1, "no mcparticle"); // 0 + hJetFlavor->GetXaxis()->SetBinLabel(2, "c-jet"); // 1 + hJetFlavor->GetXaxis()->SetBinLabel(3, "b-jet"); // 2 + hJetFlavor->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., o2::constants::math::TwoPI}}}); + 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_dcaz", "trk_dcaxyz;#it{DCA}_{z} (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_sigmadcaz", "trk_sigmadcaxyz;#it{#sigma}_{#it{DCA}_{z}} (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 hTrackOrigin = registry.get(HIST("h_trk_origin")); + hTrackOrigin->GetXaxis()->SetBinLabel(1, "NotPhysPrim"); + hTrackOrigin->GetXaxis()->SetBinLabel(2, "Charm"); + hTrackOrigin->GetXaxis()->SetBinLabel(3, "Beauty"); + hTrackOrigin->GetXaxis()->SetBinLabel(4, "Primary"); + hTrackOrigin->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 @@ -251,12 +362,32 @@ struct BJetTreeCreator { 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 OriginalTracks = soa::Join; + 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) @@ -284,9 +415,9 @@ struct BJetTreeCreator { double massSV = candSV.m(); double energySV = candSV.e(); - if (svIndices.size() < (svReductionFactor * myJet.template tracks_as().size())) { - if (produceTree) { - bjetSVParamsTable(bjetParamsTable.lastIndex() + 1, candSV.pt(), deltaRJetSV, massSV, energySV / myJet.energy(), candSV.impactParameterXY(), candSV.cpa(), candSV.chi2PCA(), candSV.decayLengthXY(), candSV.errorDecayLengthXY(), candSV.decayLength(), candSV.errorDecayLength()); + if (svIndices.size() < (svReductionFactor * myJet.template tracks_as().size()) && svIndices.size() < maxConstSV) { + if (produceSVTree) { + 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()); } @@ -296,11 +427,11 @@ struct BJetTreeCreator { registry.fill(HIST("h2_SVMass_jetpT"), myJet.pt(), massSV, eventweight); if (doprocessMCJets) { - if (jetFlavor == 2) { + if (jetFlavor == JetTaggingSpecies::beauty) { 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) { + } else if (jetFlavor == JetTaggingSpecies::charm) { 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); @@ -313,51 +444,119 @@ struct BJetTreeCreator { } } + 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) + 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& jconstituent : analysisJet.template tracks_as()) { + for (const auto& constituent : analysisJet.template tracks_as()) { - if (jconstituent.pt() < trackPtMin) { + if (constituent.pt() < trackPtMin || !jettaggingutilities::trackAcceptanceWithDca(constituent, maxIPxy, maxIPz)) { continue; } - auto constituent = jconstituent.template track_as(); 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(collision, analysisJet, constituent); + int sign = jettaggingutilities::getGeoSign(analysisJet, constituent); - float RClosestSV = 10.; + float dRClosestSV = 10.; for (const auto& candSV : analysisJet.template secondaryVertices_as()) { double deltaRTrackSV = jetutilities::deltaR(constituent, candSV); - if (deltaRTrackSV < RClosestSV) { - RClosestSV = deltaRTrackSV; + if (deltaRTrackSV < dRClosestSV) { + dRClosestSV = deltaRTrackSV; } } - float dcaXYZ(0.), sigmaDcaXYZ2(0.); - dcaXYZ = getDcaXYZ(constituent, &sigmaDcaXYZ2); - // jettaggingutilities::calculateDcaXYZ(dcaXYZ, sigmaDcaXYZ2, constituent.dcaXY(), constituent.dcaZ(), constituent.cYY(), constituent.cZY(), constituent.cZZ(), constituent.sigmaDcaXY2(), constituent.sigmaDcaZ2()); - - registry.fill(HIST("h2_SIPs2D_jetpT"), analysisJet.pt(), sign * TMath::Abs(constituent.dcaXY()) / TMath::Sqrt(constituent.sigmaDcaXY2()), eventweight); - registry.fill(HIST("h2_SIPs3D_jetpT"), analysisJet.pt(), sign * dcaXYZ / TMath::Sqrt(sigmaDcaXYZ2), eventweight); + 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 * TMath::Abs(constituent.dcaXY()) / TMath::Sqrt(constituent.sigmaDcaXY2()), eventweight); - registry.fill(HIST("h2_SIPs3D_jetpT_bjet"), analysisJet.pt(), sign * dcaXYZ / TMath::Sqrt(sigmaDcaXYZ2), eventweight); - } else if (jetFlavor == 1) { - registry.fill(HIST("h2_SIPs2D_jetpT_cjet"), analysisJet.pt(), sign * TMath::Abs(constituent.dcaXY()) / TMath::Sqrt(constituent.sigmaDcaXY2()), eventweight); - registry.fill(HIST("h2_SIPs3D_jetpT_cjet"), analysisJet.pt(), sign * dcaXYZ / TMath::Sqrt(sigmaDcaXYZ2), eventweight); + if (jetFlavor == JetTaggingSpecies::beauty) { + 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 == JetTaggingSpecies::charm) { + 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 * TMath::Abs(constituent.dcaXY()) / TMath::Sqrt(constituent.sigmaDcaXY2()), eventweight); - registry.fill(HIST("h2_SIPs3D_jetpT_lfjet"), analysisJet.pt(), sign * dcaXYZ / TMath::Sqrt(sigmaDcaXYZ2), eventweight); + 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, TMath::Abs(constituent.dcaXY()) * sign, TMath::Sqrt(constituent.sigmaDcaXY2()), dcaXYZ * sign, TMath::Sqrt(sigmaDcaXYZ2), constituent.p() / analysisJet.p(), RClosestSV); + bjetTracksParamsTable(bjetParamsTable.lastIndex() + 1, constituent.pt(), constituent.eta(), dotProduct, dotProduct / analysisJet.p(), deltaRJetTrack, std::abs(constituent.dcaXY()) * sign, constituent.sigmadcaXY(), std::abs(constituent.dcaZ()) * sign, constituent.sigmadcaZ(), constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), dRClosestSV); + } + 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 (const auto& constituent : analysisJet.template tracks_as()) { + + trkIdx++; + + if (constituent.pt() < trackPtMin || !jettaggingutilities::trackAcceptanceWithDca(constituent, maxIPxy, maxIPz)) { + 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 == JetTaggingSpecies::beauty) { + 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 == JetTaggingSpecies::charm) { + 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_dcaz"), std::abs(constituent.dcaZ()) * sign, eventweight); + registry.fill(HIST("h_trk_sigmadcaxy"), constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h_trk_sigmadcaz"), constituent.sigmadcaZ(), 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.dcaZ()) * sign, constituent.sigmadcaZ(), constituent.sigmadcaXYZ(), constituent.p() / analysisJet.p(), 0.); } trackIndices.push_back(bjetTracksParamsTable.lastIndex()); } @@ -368,9 +567,9 @@ struct BJetTreeCreator { } PROCESS_SWITCH(BJetTreeCreator, processDummy, "Dummy process function turned on by default", true); - void processDataJets(FilteredCollision::iterator const& collision, DataJets const& alljets, JetTrackswID const& allTracks, OriginalTracks const& /*allOrigTracks*/, aod::DataSecondaryVertex3Prongs const& allSVs) + void processDataJets(FilteredCollision::iterator const& collision, DataJets const& alljets, JetTrackswID const& allTracks, aod::DataSecondaryVertex3Prongs const& allSVs) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection) || (static_cast(std::rand()) / RAND_MAX < eventReductionFactor)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || (static_cast(std::rand()) / RAND_MAX < eventReductionFactor)) { return; } @@ -379,7 +578,7 @@ struct BJetTreeCreator { for (const auto& analysisJet : alljets) { bool jetIncluded = false; - for (auto jetR : jetRadiiValues) { + for (const auto& jetR : jetRadiiValues) { if (analysisJet.r() == static_cast(jetR * 100)) { jetIncluded = true; break; @@ -390,47 +589,55 @@ struct BJetTreeCreator { continue; } - std::vector tracksIndices; - std::vector SVsIndices; + if (static_cast(std::rand()) / RAND_MAX < getReductionFactor(analysisJet.pt())) { + continue; + } + + std::vector indicesTracks; + std::vector indicesSVs; - analyzeJetSVInfo(analysisJet, allTracks, allSVs, SVsIndices); - analyzeJetTrackInfo(collision, analysisJet, allTracks, allSVs, tracksIndices); + analyzeJetSVInfo(analysisJet, allTracks, allSVs, indicesSVs); + analyzeJetTrackInfo(collision, analysisJet, allTracks, allSVs, indicesTracks); registry.fill(HIST("h2_jetMass_jetpT"), analysisJet.pt(), analysisJet.mass()); - registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), tracksIndices.size()); - registry.fill(HIST("h2_nSV_jetpT"), analysisJet.pt(), SVsIndices.size() < 250 ? SVsIndices.size() : 249); + int nSVs = analysisJet.template secondaryVertices_as().size(); + + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), indicesTracks.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(), SVsIndices.size(), analysisJet.mass(), 0, analysisJet.r()); + bjetConstituentsTable(bjetParamsTable.lastIndex() + 1, indicesTracks, indicesSVs); + bjetParamsTable(analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), indicesTracks.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>; + using MCDJetTable = soa::Filtered>; + using MCPJetTable = soa::Filtered>; + using FilteredCollisionMCD = soa::Filtered>; - Preslice McParticlesPerCollision = aod::jmcparticle::mcCollisionId; - Preslice McPJetsPerCollision = aod::jet::mcCollisionId; + 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, JetParticles const& MCParticles, aod::MCDSecondaryVertex3Prongs const& allSVs, OriginalTracks const& /*origTracks*/) + 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, eventSelection) || (static_cast(std::rand()) / RAND_MAX < eventReductionFactor)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || (static_cast(std::rand()) / RAND_MAX < eventReductionFactor)) { return; } + float eventWeight = collision.weight(); + registry.fill(HIST("h_vertexZ"), collision.posZ()); - auto const mcParticlesPerColl = MCParticles.sliceBy(McParticlesPerCollision, collision.mcCollisionId()); - auto const mcPJetsPerColl = MCPjets.sliceBy(McPJetsPerCollision, collision.mcCollisionId()); + 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) { + for (const auto& jetR : jetRadiiValues) { if (analysisJet.r() == static_cast(jetR * 100)) { jetIncluded = true; break; @@ -441,32 +648,47 @@ struct BJetTreeCreator { continue; } - std::vector tracksIndices; - std::vector SVsIndices; + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (analysisJet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + + std::vector indicesTracks; + std::vector indicesSVs; - float eventWeight = analysisJet.eventWeight(); 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()) { - jetFlavor = jettaggingutilities::getJetFlavor(mcpjet, mcParticlesPerColl); - // jetFlavor = jettaggingutilities::mcpJetFromHFShower(mcpjet, mcParticlesPerColl, (float)(mcpjet.r() / 100.)); + for (const 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.)); + } } - analyzeJetSVInfo(analysisJet, allTracks, allSVs, SVsIndices, jetFlavor, eventWeight); - analyzeJetTrackInfo(collision, analysisJet, allTracks, allSVs, tracksIndices, jetFlavor, eventWeight); + + if ((jetFlavor != JetTaggingSpecies::charm && jetFlavor != JetTaggingSpecies::beauty) && (static_cast(std::rand()) / RAND_MAX < getReductionFactor(analysisJet.pt()))) { + continue; + } + + analyzeJetSVInfo(analysisJet, allTracks, allSVs, indicesSVs, jetFlavor, eventWeight); + analyzeJetTrackInfo(collision, analysisJet, allTracks, allSVs, indicesTracks, 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(), SVsIndices.size() < 250 ? SVsIndices.size() : 249); + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), indicesTracks.size()); + registry.fill(HIST("h2_nSV_jetpT"), analysisJet.pt(), nSVs < 250 ? nSVs : 249); - if (jetFlavor == 2) { + if (jetFlavor == JetTaggingSpecies::beauty) { 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) { + } else if (jetFlavor == JetTaggingSpecies::charm) { registry.fill(HIST("h2_jetMass_jetpT_cjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); registry.fill(HIST("h_jetpT_detector_cjet"), analysisJet.pt(), eventWeight); } else { @@ -474,10 +696,15 @@ struct BJetTreeCreator { registry.fill(HIST("h_jetpT_detector_lfjet"), analysisJet.pt(), eventWeight); } - for (auto& mcpjet : analysisJet.template matchedJetGeo_as()) { - if (jetFlavor == 2) { + for (const auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } + + if (jetFlavor == JetTaggingSpecies::beauty) { registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_bjet"), analysisJet.pt(), mcpjet.pt(), eventWeight); - } else if (jetFlavor == 1) { + } else if (jetFlavor == JetTaggingSpecies::charm) { 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); @@ -485,23 +712,105 @@ struct BJetTreeCreator { } if (produceTree) { - bjetConstituentsTable(bjetParamsTable.lastIndex() + 1, tracksIndices, SVsIndices); - bjetParamsTable(analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), tracksIndices.size(), SVsIndices.size(), analysisJet.mass(), jetFlavor, analysisJet.r()); + bjetConstituentsTable(bjetParamsTable.lastIndex() + 1, indicesTracks, indicesSVs); + bjetParamsTable(analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), indicesTracks.size(), nSVs, analysisJet.mass(), jetFlavor, analysisJet.r()); + bjetParamsExtraTable(eventWeight); } } } 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; + } + + // Uses only collisionId % trainingDatasetRaioParam == 0 for training dataset + if (trainingDatasetRatioParam && collision.collisionId() % trainingDatasetRatioParam != 0) { + return; + } + + float eventWeight = collision.weight(); + + registry.fill(HIST("h_vertexZ"), collision.posZ(), eventWeight); + + 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 (const auto& jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + std::vector indicesTracks; + std::vector indicesSVs; + + int16_t jetFlavor = analysisJet.origin(); + + if ((jetFlavor != JetTaggingSpecies::charm && jetFlavor != JetTaggingSpecies::beauty) && (static_cast(std::rand()) / RAND_MAX < getReductionFactor(analysisJet.pt()))) { + continue; + } + + //+ + 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, indicesTracks, jetFlavor, eventWeight, &trkLabels); + + registry.fill(HIST("h2_jetMass_jetpT"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), indicesTracks.size(), eventWeight); + + //+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"), indicesTracks.size()); + registry.fill(HIST("h_jet_mass"), analysisJet.mass()); + registry.fill(HIST("h_n_vertices"), nVertices); + + if (jetFlavor == JetTaggingSpecies::beauty) { + 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 == JetTaggingSpecies::charm) { + 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, indicesTracks, indicesSVs); + bjetParamsTable(analysisJet.pt(), analysisJet.eta(), analysisJet.phi(), indicesTracks.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, JetParticles const& MCParticles) + void processMCTruthJets(FilteredCollisionMCP::iterator const& collision, MCPJetTable const& MCPjets, aod::JetParticles const& MCParticles) { + float eventWeight = collision.weight(); for (const auto& mcpjet : MCPjets) { bool jetIncluded = false; - for (auto jetR : jetRadiiValues) { + for (const auto& jetR : jetRadiiValues) { if (mcpjet.r() == static_cast(jetR * 100)) { jetIncluded = true; break; @@ -512,15 +821,22 @@ struct BJetTreeCreator { continue; } - int16_t jetFlavor = 0; - jetFlavor = jettaggingutilities::getJetFlavor(mcpjet, MCParticles); - // jetFlavor = jettaggingutilities::mcpJetFromHFShower(mcpjet, mcParticlesPerColl, (float)(mcpjet.r() / 100.)); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { + continue; + } - float eventWeight = mcpjet.eventWeight(); + 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) { + if (jetFlavor == JetTaggingSpecies::beauty) { registry.fill(HIST("h_jetpT_particle_bjet"), mcpjet.pt(), eventWeight); - } else if (jetFlavor == 1) { + } else if (jetFlavor == JetTaggingSpecies::charm) { registry.fill(HIST("h_jetpT_particle_cjet"), mcpjet.pt(), eventWeight); } else { registry.fill(HIST("h_jetpT_particle_lfjet"), mcpjet.pt(), eventWeight); diff --git a/PWGJE/Tasks/dijetFinderQA.cxx b/PWGJE/Tasks/dijetFinderQA.cxx new file mode 100644 index 00000000000..5c9f39f1a84 --- /dev/null +++ b/PWGJE/Tasks/dijetFinderQA.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. + +// dijet finder QA task +// +/// \author Dongguk Kim + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +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 checkMcCollisionIsMatched{"checkMcCollisionIsMatched", false, "0: count whole MCcollisions, 1: select MCcollisions which only have their correspond collisions"}; + 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 labelCollisionHistograms(HistogramRegistry& registry) + { + if (doprocessDijetMCP) { + auto hColCounter_MCP = registry.get(HIST("hColCounter_MCP")); + hColCounter_MCP->GetXaxis()->SetBinLabel(1, "AllMcCollisions"); + hColCounter_MCP->GetXaxis()->SetBinLabel(2, "McCollisionsWithVertexZ"); + hColCounter_MCP->GetXaxis()->SetBinLabel(3, "MatchedMcCollisions"); + } + if (doprocessDijetMCD) { + auto hColCounter_MCD = registry.get(HIST("hColCounter_MCD")); + hColCounter_MCD->GetXaxis()->SetBinLabel(1, "AllDetCollisions"); + hColCounter_MCD->GetXaxis()->SetBinLabel(2, "DetCollisionsWithVertexZ"); + hColCounter_MCD->GetXaxis()->SetBinLabel(3, "AcceptedDetCollisions"); + } + if (doprocessDijetData) { + auto hColCounter_Data = registry.get(HIST("hColCounter_Data")); + hColCounter_Data->GetXaxis()->SetBinLabel(1, "AllDataCollisions"); + hColCounter_Data->GetXaxis()->SetBinLabel(2, "DataCollisionsWithVertexZ"); + hColCounter_Data->GetXaxis()->SetBinLabel(3, "AcceptedDataCollisions"); + } + } + + void init(o2::framework::InitContext&) + { + eventSelection = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + // Add histogram for event counts + + 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}}); + registry.add("hColCounter_MCP", "event status; event status;entries", {HistType::kTH1F, {{10, 0., 10.0}}}); + } + + if (doprocessDijetMCD) { + registry.add("h_detec_dijet_mass", "Dijet invariant mass;;entries", {HistType::kTH1F, {dijetMassAxis}}); + registry.add("hColCounter_MCD", "event status; event status;entries", {HistType::kTH1F, {{10, 0., 10.0}}}); + // registry.add("hColCounter_MCD", "Event count;;entries", {HistType::kTH1F, {eventCountAxis}}); + } + + if (doprocessDijetData) { + registry.add("h_data_dijet_mass", "Dijet invariant mass;;entries", {HistType::kTH1F, {dijetMassAxis}}); + registry.add("hColCounter_Data", "event status; event status;entries", {HistType::kTH1F, {{10, 0., 10.0}}}); + // registry.add("hColCounter_Data", "Event count;;entries", {HistType::kTH1F, {eventCountAxis}}); + } + + if (doprocessDijetMCPMCDMatched) { + registry.add("h_matched_dijet_mass", "M_{jj matched};M_{jj part}; M_{jj det}", {HistType::kTH2F, {dijetMassAxis, dijetMassAxis}}); + } + + labelCollisionHistograms(registry); + } + + /****************************************************************************************************************************************************************/ + 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); + /****************************************************************************************************************************************************************/ + + 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 fillMassHistogramsMCPMCDMatched(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(aod::JetMcCollisions::iterator const& mccollision, + soa::Filtered> const& jets, + soa::SmallGroups const& collisions) + { + registry.fill(HIST("hColCounter_MCP"), 0.5); + if (fabs(mccollision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hColCounter_MCP"), 1.5); + if (checkMcCollisionIsMatched) { + if (collisions.size() == 0) { + return; + } + for (auto& collision : collisions) { + if (fabs(collision.posZ()) > vertexZCut || !jetderiveddatautilities::selectCollision(collision, eventSelection)) { + return; + } + } + registry.fill(HIST("hColCounter_MCP"), 2.5); + } + + std::vector> jetPtcuts; + for (auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + if (jet.pt() < setJetPtCut) { + continue; + } + jetPtcuts.push_back({jet.pt(), jet.eta(), jet.phi()}); + } + + if (jetPtcuts.size() >= 2) { + const auto& leading_jet = jetPtcuts[0]; + + bool found_pair = false; + + for (size_t i = 1; i < jetPtcuts.size() && !found_pair; i++) { + const 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(aod::JetCollisions::iterator const& collision, + soa::Filtered> const& jets) + { + registry.fill(HIST("hColCounter_MCD"), 0.5); + if (fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hColCounter_MCD"), 1.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + return; + } + registry.fill(HIST("hColCounter_MCD"), 2.5); + + std::vector> jetPtcuts; + for (auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + if (jet.pt() < setJetPtCut) { + continue; + } + jetPtcuts.push_back({jet.pt(), jet.eta(), jet.phi()}); + } + + if (jetPtcuts.size() >= 2) { + const auto& leading_jet = jetPtcuts[0]; + + bool found_pair = false; + + for (size_t i = 1; i < jetPtcuts.size() && !found_pair; i++) { + const 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(aod::JetCollisions::iterator const& collision, + soa::Filtered> const& jets) + { + registry.fill(HIST("hColCounter_Data"), 0.5); + if (fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hColCounter_Data"), 1.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + return; + } + registry.fill(HIST("hColCounter_Data"), 2.5); + + std::vector> jetPtcuts; + for (auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + if (jet.pt() < setJetPtCut) { + continue; + } + jetPtcuts.push_back({jet.pt(), jet.eta(), jet.phi()}); + } + + if (jetPtcuts.size() >= 2) { + const auto& leading_jet = jetPtcuts[0]; + + bool found_pair = false; + + for (size_t i = 1; i < jetPtcuts.size() && !found_pair; i++) { + const 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>; + using JetMCDTable = soa::Filtered>; + + void processDijetMCPMCDMatched(aod::JetCollisionsMCD::iterator const& collision, + JetMCDTable const& mcdjets, + JetMCPTable const&, + aod::JetTracks const&, + aod::JetParticles const&) + { + if (fabs(collision.posZ()) > vertexZCut) { + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + return; + } + + std::vector> jetPtcuts_D; + std::vector> jetPtcuts_P; + + for (auto& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (mcdjet.pt() < setJetPtCut) { + continue; + } + if (mcdjet.has_matchedJetGeo()) { + for (auto& matchedjet : mcdjet.template matchedJetPt_as()) { + if (matchedjet.pt() < setJetPtCut) { + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(matchedjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(matchedjet)) { + continue; + } + jetPtcuts_D.push_back({mcdjet.pt(), mcdjet.eta(), mcdjet.phi()}); + jetPtcuts_P.push_back({matchedjet.pt(), matchedjet.eta(), matchedjet.phi()}); + } + } + } + + if (jetPtcuts_D.size() >= 2 && jetPtcuts_P.size() >= 2) { + const auto& leading_jet_D = jetPtcuts_D[0]; + const auto& leading_jet_P = jetPtcuts_P[0]; + + std::array candidate_jet_D{}; + std::array candidate_jet_P{}; + + auto dphi_D = 0.; + auto dphi_P = 0.; + + bool found_pair_MCD = false; + bool found_pair_MCP = false; + + for (size_t i = 1; i < jetPtcuts_D.size() && !found_pair_MCD; i++) { + candidate_jet_D = jetPtcuts_D[i]; + dphi_D = fabs(leading_jet_D[2] - candidate_jet_D[2]); + Double_t condition = fabs(dphi_D - M_PI); + if (condition > setPhiCut * M_PI) { + continue; + } + found_pair_MCD = true; + } + for (size_t i = 1; i < jetPtcuts_P.size() && !found_pair_MCP; i++) { + candidate_jet_P = jetPtcuts_P[i]; + dphi_P = fabs(leading_jet_P[2] - candidate_jet_P[2]); + Double_t condition = fabs(dphi_P - M_PI); + if (condition > setPhiCut * M_PI) { + continue; + } + found_pair_MCP = true; + } + if (found_pair_MCD && found_pair_MCP) { + Double_t deta_D = fabs(leading_jet_D[1] - candidate_jet_D[1]); + Double_t deta_P = fabs(leading_jet_P[1] - candidate_jet_P[1]); + double pt1_D = leading_jet_D[0]; + double pt2_D = candidate_jet_D[0]; + double pt1_P = leading_jet_P[0]; + double pt2_P = candidate_jet_P[0]; + double dijet_mass_D = sqrt(2 * pt1_D * pt2_D * (cosh(deta_D) - cos(dphi_D))); + double dijet_mass_P = sqrt(2 * pt1_P * pt2_P * (cosh(deta_P) - cos(dphi_P))); + fillMassHistogramsMCPMCDMatched(dijet_mass_P, dijet_mass_D); + } + } + } + PROCESS_SWITCH(DijetFinderQATask, processDijetMCPMCDMatched, "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 98% rename from PWGJE/Tasks/emccellmonitor.cxx rename to PWGJE/Tasks/emcCellMonitor.cxx index bb1d8fb3f9f..880ce14e490 100644 --- a/PWGJE/Tasks/emccellmonitor.cxx +++ b/PWGJE/Tasks/emcCellMonitor.cxx @@ -9,25 +9,31 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsEMCAL/Constants.h" +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#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/ASoA.h" -#include "Framework/HistogramRegistry.h" - -#include "DataFormatsEMCAL/Constants.h" -#include "EMCALBase/Geometry.h" -#include "EMCALCalib/BadChannelMap.h" -#include "CommonDataFormat/InteractionRecord.h" - /// \struct CellMonitor /// \brief Simple monitoring task for cell related quantities /// \author Markus Fasel , Oak Ridge National Laoratory diff --git a/PWGJE/Tasks/emcclustermonitor.cxx b/PWGJE/Tasks/emcClusterMonitor.cxx similarity index 73% rename from PWGJE/Tasks/emcclustermonitor.cxx rename to PWGJE/Tasks/emcClusterMonitor.cxx index b922e4cf068..fbb8885c5be 100644 --- a/PWGJE/Tasks/emcclustermonitor.cxx +++ b/PWGJE/Tasks/emcClusterMonitor.cxx @@ -9,32 +9,39 @@ // 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 "PWGJE/DataModel/EMCALClusters.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" + +#include "CommonDataFormat/InteractionRecord.h" +#include "EMCALBase/Geometry.h" #include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include +#include +#include -#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 -#include "CommonDataFormat/InteractionRecord.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include // \struct ClusterMonitor /// \brief Simple monitoring task for EMCal clusters @@ -75,6 +82,7 @@ struct ClusterMonitor { std::vector mVetoBCIDs; std::vector mSelectBCIDs; + std::vector mCellTime; /// \brief Create output histograms and initialize geometry void init(InitContext const&) @@ -94,61 +102,37 @@ 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}}); - mHistManager.add("eventsSelected", "Number of events", o2HistType::kTH1F, {{1, 0.5, 1.5}}); - mHistManager.add("eventBCAll", "Bunch crossing ID of event (all events)", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("eventBCSelected", "Bunch crossing ID of event (selected events)", o2HistType::kTH1F, {bcAxis}); - mHistManager.add("eventVertexZAll", "z-vertex of event (all events)", o2HistType::kTH1F, {{200, -20, 20}}); - mHistManager.add("eventVertexZSelected", "z-vertex of event (selected events)", o2HistType::kTH1F, {{200, -20, 20}}); - mHistManager.add("numberOfClustersEvents", "number of clusters per event (selected events)", o2HistType::kTH1F, {numberClustersAxis}); - mHistManager.add("numberOfClustersBC", "number of clusters per bunch crossing (ambiguous BCs)", o2HistType::kTH1F, {numberClustersAxis}); - mHistManager.add("numberOfClustersEventsRejected", "number of clusters per event (rejected events)", o2HistType::kTH1F, {numberClustersAxis}); + mHistManager.add("eventsAll", "Number of events", o2HistType::kTH1D, {{1, 0.5, 1.5}}); + mHistManager.add("eventsSelected", "Number of events", o2HistType::kTH1D, {{1, 0.5, 1.5}}); + mHistManager.add("eventBCAll", "Bunch crossing ID of event (all events)", o2HistType::kTH1D, {bcAxis}); + mHistManager.add("eventBCSelected", "Bunch crossing ID of event (selected events)", o2HistType::kTH1D, {bcAxis}); + mHistManager.add("eventVertexZAll", "z-vertex of event (all events)", o2HistType::kTH1D, {{200, -20, 20}}); + mHistManager.add("eventVertexZSelected", "z-vertex of event (selected events)", o2HistType::kTH1D, {{200, -20, 20}}); + mHistManager.add("numberOfClustersEvents", "number of clusters per event (selected events)", o2HistType::kTH1D, {numberClustersAxis}); + mHistManager.add("numberOfClustersBC", "number of clusters per bunch crossing (ambiguous BCs)", o2HistType::kTH1D, {numberClustersAxis}); + mHistManager.add("numberOfClustersEventsRejected", "number of clusters per event (rejected events)", o2HistType::kTH1D, {numberClustersAxis}); mHistManager.add("numberOfClustersSMEvents", "number of clusters per supermodule per event (selected events)", o2HistType::kTH2F, {numberClustersAxis, {20, -0.5, 19.5, "SupermoduleID"}}); 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("clusterE", "Energy of cluster", o2HistType::kTH1D, {energyAxis}); + mHistManager.add("clusterEMatched", "Energy of cluster (with match)", o2HistType::kTH1D, {energyAxis}); mHistManager.add("clusterESupermodule", "Energy of the cluster vs. supermoduleID", o2HistType::kTH2F, {energyAxis, supermoduleAxis}); - mHistManager.add("clusterE_SimpleBinning", "Energy of cluster", o2HistType::kTH1F, {{2000, 0, 200}}); + mHistManager.add("clusterE_SimpleBinning", "Energy of cluster", o2HistType::kTH1D, {{2000, 0, 200}}); mHistManager.add("clusterEtaPhi", "Eta and phi of cluster", o2HistType::kTH2F, {{100, -1, 1}, {100, 0, 2 * TMath::Pi()}}); - mHistManager.add("clusterM02", "M02 of cluster", o2HistType::kTH1F, {{400, 0, 5}}); - mHistManager.add("clusterM20", "M20 of cluster", o2HistType::kTH1F, {{400, 0, 2.5}}); - mHistManager.add("clusterNLM", "Number of local maxima of cluster", o2HistType::kTH1I, {{10, 0, 10}}); - mHistManager.add("clusterNCells", "Number of cells in cluster", o2HistType::kTH1I, {{50, 0, 50}}); - mHistManager.add("clusterDistanceToBadChannel", "Distance to bad channel", o2HistType::kTH1F, {{100, 0, 100}}); + mHistManager.add("clusterM02", "M02 of cluster", o2HistType::kTH1D, {{400, 0, 5}}); + mHistManager.add("clusterM20", "M20 of cluster", o2HistType::kTH1D, {{400, 0, 2.5}}); + mHistManager.add("clusterNLM", "Number of local maxima of cluster", o2HistType::kTH1D, {{10, 0, 10}}); + mHistManager.add("clusterNCells", "Number of cells in cluster", o2HistType::kTH1D, {{50, 0, 50}}); + mHistManager.add("clusterDistanceToBadChannel", "Distance to bad channel", o2HistType::kTH1D, {{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("clusterAmpFractionLeadingCell", "Fraction of energy in leading cell", o2HistType::kTH1D, {{100, 0, 1}}); + 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 +250,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 62% rename from PWGJE/Tasks/emceventselectionqa.cxx rename to PWGJE/Tasks/emcEventSelectionQA.cxx index b373371499f..8ba3f5168c8 100644 --- a/PWGJE/Tasks/emceventselectionqa.cxx +++ b/PWGJE/Tasks/emcEventSelectionQA.cxx @@ -9,69 +9,94 @@ // 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 +#include "PWGJE/Core/utilsBcSelEMC.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include +#include +#include -#include "Common/DataModel/EventSelection.h" +#include + +#include +#include +#include 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 +111,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,10 +137,15 @@ 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)) { + if (bc.alias_bit(kTVXinEMC) || bc.alias_bit(kEMC7) || bc.alias_bit(kDMC7) || 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 { @@ -123,6 +156,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 +214,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 +241,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 53% rename from PWGJE/Tasks/emctmmonitor.cxx rename to PWGJE/Tasks/emcTmMonitor.cxx index 3b6773e7127..3d6baefda3b 100644 --- a/PWGJE/Tasks/emctmmonitor.cxx +++ b/PWGJE/Tasks/emcTmMonitor.cxx @@ -9,35 +9,7 @@ // 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 "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/EMCALClusters.h" -#include "DataFormatsEMCAL/Cell.h" -#include "DataFormatsEMCAL/Constants.h" -#include "DataFormatsEMCAL/AnalysisCluster.h" - -#include "CommonDataFormat/InteractionRecord.h" - -// \struct TrackMatchingMonitor +/// \file emcTmMonitor.cxx /// \brief Simple monitoring task for EMCal clusters /// \author Marvin Hemmer /// \since 24.02.2023 @@ -50,14 +22,41 @@ /// Simple event selection using the flag doEventSel is provided, which selects INT7 events if set to 1 /// For pilot beam data, instead of relying on the event selection, one can veto specific BC IDS using the flag /// fDoVetoBCID. + +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + using namespace o2::framework; using namespace o2::framework::expressions; -using collisionEvSelIt = o2::soa::Join::iterator; -using bcEvSelIt = o2::soa::Join::iterator; -using selectedClusters = o2::soa::Filtered; -using selectedAmbiguousClusters = o2::soa::Filtered; -using tracksPID = o2::soa::Join; -struct TrackMatchingMonitor { +using CollisionEvSelIt = o2::soa::Join::iterator; +using BcEvSelIt = o2::soa::Join::iterator; +using SelectedClusters = o2::soa::Filtered; +using TracksPID = o2::soa::Join; +struct EmcTmMonitor { HistogramRegistry mHistManager{"TrackMatchingMonitorHistograms", {}, OutputObjHandlingPolicy::AnalysisObject}; o2::emcal::Geometry* mGeometry = nullptr; @@ -65,14 +64,13 @@ struct TrackMatchingMonitor { Preslice perClusterAmb = o2::aod::emcalclustercell::emcalambiguousclusterId; Preslice perClusterMatchedTracks = o2::aod::emcalclustercell::emcalclusterId; // configurable parameters - // TODO adapt mDoEventSel switch to also allow selection of other triggers (e.g. EMC7) - Configurable mDoEventSel{"doEventSel", 0, "demand kINT7"}; - 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"}; - Configurable mClusterDefinition{"clusterDefinition", 10, "cluster definition to be selected, e.g. 10=kV3Default"}; - ConfigurableAxis mClusterTimeBinning{"clustertime-binning", {1500, -600, 900}, ""}; - Configurable hasPropagatedTracks{"hasPropagatedTracks", false, "temporary flag, only set to true when running over data which has the tracks propagated to EMCal/PHOS!"}; + // TODO adapt doEventSel switch to also allow selection of other triggers (e.g. EMC7) + Configurable doEventSel{"doEventSel", 0, "demand kINT7"}; + Configurable vetoBCID{"vetoBCID", "", "BC ID(s) to be excluded, this should be used as an alternative to the event selection"}; + Configurable selectBCID{"selectBCID", "all", "BC ID(s) to be included, this should be used as an alternative to the event selection"}; + Configurable vertexCut{"vertexCut", -1, "apply z-vertex cut with value in cm"}; + Configurable clusterDefinition{"clusterDefinition", 10, "cluster definition to be selected, e.g. 10=kV3Default"}; + ConfigurableAxis clusterTimeBinning{"clusterTimeBinning", {1500, -600, 900}, ""}; Configurable usePionRejection{"usePionRejection", false, "demand pion rection for electron signal with TPC PID"}; Configurable> tpcNsigmaElectron{"tpcNsigmaElectron", {-1., +3.}, "TPC PID NSigma range for electron signal (first <= NSigma <= second)"}; Configurable> tpcNsigmaBack{"tpcNsigmaBack", {-10., -4.}, "TPC PID NSigma range for electron background (first <= NSigma <= second)"}; @@ -82,7 +80,7 @@ struct TrackMatchingMonitor { Configurable minM02{"minM02", 0.1, "Minimum M02 for M02 cut"}; Configurable maxM02{"maxM02", 0.9, "Maximum M02 for M02 cut"}; Configurable maxM02HighPt{"maxM02HighPt", 0.6, "Maximum M02 for M02 cut for high pT"}; - Configurable M02highPt{"M02highPt", 15., "pT threshold for maxM02HighPt cut. Set to negative value to disable it!"}; + Configurable m02highPt{"m02highPt", 15., "pT threshold for maxM02HighPt cut. Set to negative value to disable it!"}; Configurable minDEta{"minDEta", 0.01, "Minimum dEta between track and cluster"}; Configurable minDPhi{"minDPhi", 0.01, "Minimum dPhi between track and cluster"}; Configurable> eOverPRange{"eOverPRange", {0.9, 1.2}, "E/p range where one would search for electrons (first <= E/p <= second)"}; @@ -94,101 +92,98 @@ struct TrackMatchingMonitor { /// \brief Create output histograms and initialize geometry void init(InitContext const&) { - // create histograms - using o2HistType = HistType; - using o2Axis = AxisSpec; - // load geometry just in case we need it mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); // create common axes LOG(info) << "Creating histograms"; - const o2Axis bcAxis{3501, -0.5, 3500.5}; - const o2Axis energyAxis{makeEnergyBinningAliPhysics(), "E_{clus} (GeV)"}; - const o2Axis amplitudeAxisLarge{1000, 0., 100., "amplitudeLarge", "Amplitude (GeV)"}; - const o2Axis dEtaAxis{100, -1.f * minDEta, minDEta, "d#it{#eta}"}; - const o2Axis dPhiAxis{100, -1.f * minDPhi, minDPhi, "d#it{#varphi} (rad)"}; - const o2Axis dRAxis{150, 0.0, 0.015, "d#it{R}"}; - const o2Axis eoverpAxis{500, 0, 10, "#it{E}_{cluster}/#it{p}_{track}"}; - const o2Axis nSigmaAxis{400, -10., +30., "N#sigma"}; - const o2Axis trackptAxis{makePtBinning(), "#it{p}_{T,track}"}; - const o2Axis trackpAxis{200, 0, 100, "#it{p}_{track}"}; - const o2Axis clusterptAxis{makePtBinning(), "#it{p}_{T}"}; - const o2Axis etaAxis{160, -0.8, 0.8, "#eta"}; - const o2Axis phiAxis{72, 0, 2 * 3.14159, "#varphi (rad)"}; - const o2Axis smAxis{20, -0.5, 19.5, "SM"}; - o2Axis timeAxis{mClusterTimeBinning, "t_{cl} (ns)"}; + const AxisSpec bcAxis{3501, -0.5, 3500.5}; + const AxisSpec energyAxis{makeEnergyBinningAliPhysics(), "E_{clus} (GeV)"}; + const AxisSpec amplitudeAxisLarge{1000, 0., 100., "amplitudeLarge", "Amplitude (GeV)"}; + const AxisSpec dEtaAxis{100, -1.f * minDEta, minDEta, "d#it{#eta}"}; + const AxisSpec dPhiAxis{100, -1.f * minDPhi, minDPhi, "d#it{#varphi} (rad)"}; + const AxisSpec dRAxis{150, 0.0, 0.015, "d#it{R}"}; + const AxisSpec eoverpAxis{500, 0, 10, "#it{E}_{cluster}/#it{p}_{track}"}; + const AxisSpec nSigmaAxis{400, -10., +30., "N#sigma"}; + const AxisSpec trackptAxis{makePtBinning(), "#it{p}_{T,track}"}; + const AxisSpec trackpAxis{200, 0, 100, "#it{p}_{track}"}; + const AxisSpec clusterptAxis{makePtBinning(), "#it{p}_{T}"}; + const AxisSpec etaAxis{160, -0.8, 0.8, "#eta"}; + const AxisSpec phiAxis{72, 0, 2 * 3.14159, "#varphi (rad)"}; + const AxisSpec smAxis{20, -0.5, 19.5, "SM"}; + AxisSpec timeAxis{clusterTimeBinning, "t_{cl} (ns)"}; - int MaxMatched = 20; // maximum number of matched tracks, hardcoded in emcalCorrectionTask.cxx! - const o2Axis nmatchedtrack{MaxMatched, -0.5, MaxMatched + 0.5}; + const int maxMatched = 20; // maximum number of matched tracks, hardcoded in emcalCorrectionTask.cxx! + const AxisSpec nmatchedtrack{maxMatched, -0.5, maxMatched + 0.5}; + // create histograms // event properties - mHistManager.add("eventsAll", "Number of events", o2HistType::kTH1F, {{1, 0.5, 1.5}}); - mHistManager.add("eventsSelected", "Number of events", o2HistType::kTH1F, {{1, 0.5, 1.5}}); - mHistManager.add("eventVertexZAll", "z-vertex of event (all events)", o2HistType::kTH1F, {{200, -20, 20}}); - mHistManager.add("eventVertexZSelected", "z-vertex of event (selected events)", o2HistType::kTH1F, {{200, -20, 20}}); + mHistManager.add("eventsAll", "Number of events", HistType::kTH1F, {{1, 0.5, 1.5}}); + mHistManager.add("eventsSelected", "Number of events", HistType::kTH1F, {{1, 0.5, 1.5}}); + mHistManager.add("eventVertexZAll", "z-vertex of event (all events)", HistType::kTH1F, {{200, -20, 20}}); + mHistManager.add("eventVertexZSelected", "z-vertex of event (selected events)", HistType::kTH1F, {{200, -20, 20}}); // cluster properties (matched clusters) - mHistManager.add("TrackEtaPhi", "#eta vs #varphi of all selected tracks", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected tracks - mHistManager.add("TrackEtaPhi_Neg", "#eta vs #varphi of all selected negative tracks", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected negative tracks - mHistManager.add("TrackEtaPhi_Pos", "#eta vs #varphi of all selected positive tracks", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected positive tracks - mHistManager.add("clusterEMatched", "Energy of cluster (with match)", o2HistType::kTH1F, {energyAxis}); // energy of matched clusters - mHistManager.add("MatchedTrackEtaPhi_BeforeCut", "#eta vs #varphi of all selected matched tracks before d#eta and #dvarphi cut", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected matched tracks before dEta and dPhi cut - mHistManager.add("MatchedTrackEtaPhi_Neg_BeforeCut", "#eta vs #varphi of all selected negative matched tracks before d#eta and #dvarphi cut", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected negative matched tracks before dEta and dPhi cut - mHistManager.add("MatchedTrackEtaPhi_Pos_BeforeCut", "#eta vs #varphi of all selected positive matched tracks before d#eta and #dvarphi cut", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected positive matched tracks before dEta and dPhi cut - mHistManager.add("MatchedTrackEtaPhi", "#eta vs #varphi of all selected matched tracks", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected matched tracks - mHistManager.add("MatchedTrackEtaPhi_Neg", "#eta vs #varphi of all selected negative matched tracks", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected negative matched tracks - mHistManager.add("MatchedTrackEtaPhi_Pos", "#eta vs #varphi of all selected positive matched tracks", o2HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected positive matched tracks - mHistManager.add("clusterTM_dEtadPhi", "cluster trackmatching dEta/dPhi", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM - mHistManager.add("clusterTM_dEtadPhi_ASide", "cluster trackmatching in A-Side dEta/dPhi", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM in A-Aside - mHistManager.add("clusterTM_dEtadPhi_CSide", "cluster trackmatching in C-Side tracks dEta/dPhi", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM in C-Side - mHistManager.add("clusterTM_PosdEtadPhi", "cluster trackmatching positive tracks dEta/dPhi", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM positive track - mHistManager.add("clusterTM_NegdEtadPhi", "cluster trackmatching negative tracks dEta/dPhi", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM negative track - mHistManager.add("clusterTM_PosdEtadPhi_Pl0_75", "cluster trackmatching positive tracks, p < 0.75 dEta/dPhi", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM positive track with p < 0.75 GeV/c - mHistManager.add("clusterTM_NegdEtadPhi_Pl0_75", "cluster trackmatching negative tracks, p < 0.75 dEta/dPhi", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM 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", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM 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", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM 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", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM positive track with p >= 1.25 GeV/c - mHistManager.add("clusterTM_NegdEtadPhi_Pgeq1_25", "cluster trackmatching negative tracks, p >= 1.25 dEta/dPhi", o2HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM 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::kTH3F, {dEtaAxis, clusterptAxis, smAxis}); // dEta vs pT per SM - mHistManager.add("clusterTM_PosdPhiPt", "cluster trackmatching positive tracks dPhi/#it{p}_{T}", o2HistType::kTH3F, {dPhiAxis, clusterptAxis, smAxis}); // dPhi vs pT per SM positive track - mHistManager.add("clusterTM_NegdPhiPt", "cluster trackmatching negative tracks dPh/#it{p}_{T}", o2HistType::kTH3F, {dPhiAxis, clusterptAxis, smAxis}); // dPhi vs pT per SM negative track - mHistManager.add("clusterTM_dEtaTN", "cluster trackmatching dEta/TN;d#it{#eta};#it{N}_{matched tracks}", o2HistType::kTH2F, {dEtaAxis, nmatchedtrack}); // 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, {dPhiAxis, nmatchedtrack}); // dPhi compared to the Nth closest track - mHistManager.add("clusterTM_dRTN", "cluster trackmatching dR/TN;d#it{R};#it{N}_{matched tracks}", o2HistType::kTH2F, {dRAxis, nmatchedtrack}); // dR compared to the Nth closest track - mHistManager.add("clusterTM_NTrack", "cluster trackmatching NMatchedTracks", o2HistType::kTH1I, {nmatchedtrack}); // how many tracks are matched - mHistManager.add("clusterTM_EoverP_E", "E/p ", o2HistType::kTH3F, {eoverpAxis, energyAxis, nmatchedtrack}); // E/p vs p for the Nth closest track - mHistManager.add("clusterTM_EoverP_Pt", "E/p vs track pT", o2HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E/p vs track pT for the Nth closest track - mHistManager.add("clusterTM_EvsP", "cluster E/track p", o2HistType::kTH3F, {energyAxis, trackpAxis, nmatchedtrack}); // E vs p for the Nth closest track - mHistManager.add("clusterTM_EoverP_ep", "cluster E/electron p", o2HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest electron/positron track - mHistManager.add("clusterTM_EoverP_e", "cluster E/electron p", o2HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest electron track - mHistManager.add("clusterTM_EoverP_p", "cluster E/electron p", o2HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest positron track - mHistManager.add("clusterTM_EoverP_electron_ASide", "cluster E/electron p in A-Side", o2HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest electron/positron track in A-Side - mHistManager.add("clusterTM_EoverP_electron_CSide", "cluster E/electron p in C-Side", o2HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest electron/positron track in C-Side - mHistManager.add("clusterTM_NSigma_BeforeCut", "electron NSigma for matched tracks before d#eta and #dvarphi cut", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest track before dEta and dPhi cut - mHistManager.add("clusterTM_NSigma_neg_BeforeCut", "electron NSigma for matched negative tracks before d#eta and #dvarphi cut", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest negative tracks before dEta and dPhi cut - mHistManager.add("clusterTM_NSigma_pos_BeforeCut", "electron NSigma for matched positive tracks before d#eta and #dvarphi cut", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest positive tracks before dEta and dPhi cut - mHistManager.add("clusterTM_NSigma", "electron NSigma for matched track", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest track - mHistManager.add("clusterTM_NSigma_neg", "electron NSigma for matched negative track", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest negative tracks - mHistManager.add("clusterTM_NSigma_pos", "electron NSigma for matched positive track", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest positive tracks - mHistManager.add("clusterTM_NSigma_cut", "electron NSigma for matched track with cuts", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest track with cuts on E/p and cluster cuts - mHistManager.add("clusterTM_NSigma_e", "NSigma electron", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest electron track - mHistManager.add("clusterTM_NSigma_p", "NSigma positron", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest positron track - mHistManager.add("clusterTM_NSigma_e_cut", "NSigma electron with E over p cut", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest electron track with E/p cut - mHistManager.add("clusterTM_NSigma_p_cut", "NSigma positron with E over p cut", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest positron track with E/p cut - mHistManager.add("TrackTM_NSigma", "electron NSigma for global tracks", o2HistType::kTH2F, {nSigmaAxis, trackptAxis}); // NSigma_electron vs track pT for global track - mHistManager.add("TrackTM_NSigma_e", "NSigma e for global negative tracks", o2HistType::kTH2F, {nSigmaAxis, trackptAxis}); // NSigma vs track pT for negative global track - mHistManager.add("TrackTM_NSigma_p", "NSigma e for global positive tracks", o2HistType::kTH2F, {nSigmaAxis, trackptAxis}); // NSigma vs track pT for positive global track - mHistManager.add("clusterTM_NSigma_electron_ASide", "NSigma electron in A-Side", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest electron/positron track in A-Side - mHistManager.add("clusterTM_NSigma_electron_CSide", "NSigma positron in C-Side", o2HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest electron/positron track in C-Side - mHistManager.add("clusterTM_EoverP_hadron", "cluster E/hadron p", o2HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest hadron track - mHistManager.add("clusterTM_EoverP_hn", "cluster E/hadron p", o2HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest negative hadron track - mHistManager.add("clusterTM_EoverP_hp", "cluster E/hadron p", o2HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest positive hadron track - mHistManager.add("clusterTM_EoverP_hadron_ASide", "cluster E/hadron p in A-Side", o2HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest hadron track in A-Side - mHistManager.add("clusterTM_EoverP_hadron_CSide", "cluster E/hadron p in C-Side", o2HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest hadron track in C-Side + mHistManager.add("TrackEtaPhi", "#eta vs #varphi of all selected tracks", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected tracks + mHistManager.add("TrackEtaPhi_Neg", "#eta vs #varphi of all selected negative tracks", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected negative tracks + mHistManager.add("TrackEtaPhi_Pos", "#eta vs #varphi of all selected positive tracks", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected positive tracks + mHistManager.add("clusterEMatched", "Energy of cluster (with match)", HistType::kTH1F, {energyAxis}); // energy of matched clusters + mHistManager.add("MatchedTrackEtaPhi_BeforeCut", "#eta vs #varphi of all selected matched tracks before d#eta and #dvarphi cut", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected matched tracks before dEta and dPhi cut + mHistManager.add("MatchedTrackEtaPhi_Neg_BeforeCut", "#eta vs #varphi of all selected negative matched tracks before d#eta and #dvarphi cut", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected negative matched tracks before dEta and dPhi cut + mHistManager.add("MatchedTrackEtaPhi_Pos_BeforeCut", "#eta vs #varphi of all selected positive matched tracks before d#eta and #dvarphi cut", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected positive matched tracks before dEta and dPhi cut + mHistManager.add("MatchedTrackEtaPhi", "#eta vs #varphi of all selected matched tracks", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected matched tracks + mHistManager.add("MatchedTrackEtaPhi_Neg", "#eta vs #varphi of all selected negative matched tracks", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected negative matched tracks + mHistManager.add("MatchedTrackEtaPhi_Pos", "#eta vs #varphi of all selected positive matched tracks", HistType::kTH2F, {etaAxis, phiAxis}); // eta vs phi of all selected positive matched tracks + mHistManager.add("clusterTM_dEtadPhi", "cluster trackmatching dEta/dPhi", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM + mHistManager.add("clusterTM_dEtadPhi_ASide", "cluster trackmatching in A-Side dEta/dPhi", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM in A-Aside + mHistManager.add("clusterTM_dEtadPhi_CSide", "cluster trackmatching in C-Side tracks dEta/dPhi", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM in C-Side + mHistManager.add("clusterTM_PosdEtadPhi", "cluster trackmatching positive tracks dEta/dPhi", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM positive track + mHistManager.add("clusterTM_NegdEtadPhi", "cluster trackmatching negative tracks dEta/dPhi", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM negative track + mHistManager.add("clusterTM_PosdEtadPhi_Pl0_75", "cluster trackmatching positive tracks, p < 0.75 dEta/dPhi", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM positive track with p < 0.75 GeV/c + mHistManager.add("clusterTM_NegdEtadPhi_Pl0_75", "cluster trackmatching negative tracks, p < 0.75 dEta/dPhi", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM 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", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM 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", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM 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", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM positive track with p >= 1.25 GeV/c + mHistManager.add("clusterTM_NegdEtadPhi_Pgeq1_25", "cluster trackmatching negative tracks, p >= 1.25 dEta/dPhi", HistType::kTH3F, {dEtaAxis, dPhiAxis, smAxis}); // dEta dPhi per SM 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})", HistType::kTH3F, {dEtaAxis, clusterptAxis, smAxis}); // dEta vs pT per SM + mHistManager.add("clusterTM_PosdPhiPt", "cluster trackmatching positive tracks dPhi/#it{p}_{T}", HistType::kTH3F, {dPhiAxis, clusterptAxis, smAxis}); // dPhi vs pT per SM positive track + mHistManager.add("clusterTM_NegdPhiPt", "cluster trackmatching negative tracks dPh/#it{p}_{T}", HistType::kTH3F, {dPhiAxis, clusterptAxis, smAxis}); // dPhi vs pT per SM negative track + mHistManager.add("clusterTM_dEtaTN", "cluster trackmatching dEta/TN;d#it{#eta};#it{N}_{matched tracks}", HistType::kTH2F, {dEtaAxis, nmatchedtrack}); // dEta compared to the Nth closest track + mHistManager.add("clusterTM_dPhiTN", "cluster trackmatching dPhi/TN;d#it{#varphi} (rad);#it{N}_{matched tracks}", HistType::kTH2F, {dPhiAxis, nmatchedtrack}); // dPhi compared to the Nth closest track + mHistManager.add("clusterTM_dRTN", "cluster trackmatching dR/TN;d#it{R};#it{N}_{matched tracks}", HistType::kTH2F, {dRAxis, nmatchedtrack}); // dR compared to the Nth closest track + mHistManager.add("clusterTM_NTrack", "cluster trackmatching NMatchedTracks", HistType::kTH1I, {nmatchedtrack}); // how many tracks are matched + mHistManager.add("clusterTM_EoverP_E", "E/p ", HistType::kTH3F, {eoverpAxis, energyAxis, nmatchedtrack}); // E/p vs p for the Nth closest track + mHistManager.add("clusterTM_EoverP_Pt", "E/p vs track pT", HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E/p vs track pT for the Nth closest track + mHistManager.add("clusterTM_EvsP", "cluster E/track p", HistType::kTH3F, {energyAxis, trackpAxis, nmatchedtrack}); // E vs p for the Nth closest track + mHistManager.add("clusterTM_EoverP_ep", "cluster E/electron p", HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest electron/positron track + mHistManager.add("clusterTM_EoverP_e", "cluster E/electron p", HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest electron track + mHistManager.add("clusterTM_EoverP_p", "cluster E/electron p", HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest positron track + mHistManager.add("clusterTM_EoverP_electron_ASide", "cluster E/electron p in A-Side", HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest electron/positron track in A-Side + mHistManager.add("clusterTM_EoverP_electron_CSide", "cluster E/electron p in C-Side", HistType::kTH3F, {eoverpAxis, trackptAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest electron/positron track in C-Side + mHistManager.add("clusterTM_NSigma_BeforeCut", "electron NSigma for matched tracks before d#eta and #dvarphi cut", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest track before dEta and dPhi cut + mHistManager.add("clusterTM_NSigma_neg_BeforeCut", "electron NSigma for matched negative tracks before d#eta and #dvarphi cut", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest negative tracks before dEta and dPhi cut + mHistManager.add("clusterTM_NSigma_pos_BeforeCut", "electron NSigma for matched positive tracks before d#eta and #dvarphi cut", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest positive tracks before dEta and dPhi cut + mHistManager.add("clusterTM_NSigma", "electron NSigma for matched track", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest track + mHistManager.add("clusterTM_NSigma_neg", "electron NSigma for matched negative track", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest negative tracks + mHistManager.add("clusterTM_NSigma_pos", "electron NSigma for matched positive track", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest positive tracks + mHistManager.add("clusterTM_NSigma_cut", "electron NSigma for matched track with cuts", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma_electron vs track pT for the Nth closest track with cuts on E/p and cluster cuts + mHistManager.add("clusterTM_NSigma_e", "NSigma electron", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest electron track + mHistManager.add("clusterTM_NSigma_p", "NSigma positron", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest positron track + mHistManager.add("clusterTM_NSigma_e_cut", "NSigma electron with E over p cut", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest electron track with E/p cut + mHistManager.add("clusterTM_NSigma_p_cut", "NSigma positron with E over p cut", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest positron track with E/p cut + mHistManager.add("TrackTM_NSigma", "electron NSigma for global tracks", HistType::kTH2F, {nSigmaAxis, trackptAxis}); // NSigma_electron vs track pT for global track + mHistManager.add("TrackTM_NSigma_e", "NSigma e for global negative tracks", HistType::kTH2F, {nSigmaAxis, trackptAxis}); // NSigma vs track pT for negative global track + mHistManager.add("TrackTM_NSigma_p", "NSigma e for global positive tracks", HistType::kTH2F, {nSigmaAxis, trackptAxis}); // NSigma vs track pT for positive global track + mHistManager.add("clusterTM_NSigma_electron_ASide", "NSigma electron in A-Side", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest electron/positron track in A-Side + mHistManager.add("clusterTM_NSigma_electron_CSide", "NSigma positron in C-Side", HistType::kTH3F, {nSigmaAxis, trackptAxis, nmatchedtrack}); // NSigma vs track pT for the Nth closest electron/positron track in C-Side + mHistManager.add("clusterTM_EoverP_hadron", "cluster E/hadron p", HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest hadron track + mHistManager.add("clusterTM_EoverP_hn", "cluster E/hadron p", HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest negative hadron track + mHistManager.add("clusterTM_EoverP_hp", "cluster E/hadron p", HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest positive hadron track + mHistManager.add("clusterTM_EoverP_hadron_ASide", "cluster E/hadron p in A-Side", HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest hadron track in A-Side + mHistManager.add("clusterTM_EoverP_hadron_CSide", "cluster E/hadron p in C-Side", HistType::kTH3F, {eoverpAxis, trackpAxis, nmatchedtrack}); // E over p vs track pT for the Nth closest hadron track in C-Side - if (mVetoBCID->length()) { - std::stringstream parser(mVetoBCID.value); + if (vetoBCID->length()) { + std::stringstream parser(vetoBCID.value); std::string token; int bcid; while (std::getline(parser, token, ',')) { @@ -197,8 +192,8 @@ struct TrackMatchingMonitor { mVetoBCIDs.push_back(bcid); } } - if (mSelectBCID.value != "all") { - std::stringstream parser(mSelectBCID.value); + if (selectBCID.value != "all") { + std::stringstream parser(selectBCID.value); std::string token; int bcid; while (std::getline(parser, token, ',')) { @@ -212,19 +207,22 @@ struct TrackMatchingMonitor { // 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 - Filter clusterDefinitionSelection = (o2::aod::emcalcluster::definition == mClusterDefinition) && (o2::aod::emcalcluster::time >= minTime) && (o2::aod::emcalcluster::time <= maxTime) && (o2::aod::emcalcluster::m02 > minM02) && (o2::aod::emcalcluster::m02 < maxM02); + Filter clusterDefinitionSelection = (o2::aod::emcalcluster::definition == clusterDefinition) && (o2::aod::emcalcluster::time >= minTime) && (o2::aod::emcalcluster::time <= maxTime) && (o2::aod::emcalcluster::m02 > minM02) && (o2::aod::emcalcluster::m02 < maxM02); /// \brief Process EMCAL clusters that are matched to a collisions - void processCollisions(collisionEvSelIt const& theCollision, selectedClusters const& clusters, o2::aod::EMCALClusterCells const&, o2::aod::Calos const&, o2::aod::EMCALMatchedTracks const& matchedtracks, tracksPID const& alltracks) + void processCollisions(CollisionEvSelIt const& theCollision, SelectedClusters const& clusters, o2::aod::EMCALClusterCells const&, o2::aod::Calos const&, o2::aod::EMCALMatchedTracks const& matchedtracks, TracksPID const& alltracks) { mHistManager.fill(HIST("eventsAll"), 1); - // do event selection if mDoEventSel is specified + // do event selection if doEventSel is specified // currently the event selection is hard coded to kINT7 // but other selections are possible that are defined in TriggerAliases.h bool isSelected = true; - if (mDoEventSel) { - if (theCollision.bc().runNumber() < 300000) { + const int beginningRun3 = 300000; + float lowP = 0.75f; + float midP = 1.25f; + if (doEventSel) { + if (theCollision.bc().runNumber() < beginningRun3) { if (!theCollision.alias_bit(kINT7)) { isSelected = false; } @@ -239,8 +237,8 @@ struct TrackMatchingMonitor { return; } mHistManager.fill(HIST("eventVertexZAll"), theCollision.posZ()); - if (mVertexCut > 0 && TMath::Abs(theCollision.posZ()) > mVertexCut) { - LOG(debug) << "Event not selected because of z-vertex cut z= " << theCollision.posZ() << " > " << mVertexCut << " cm, skipping"; + if (vertexCut > 0 && std::abs(theCollision.posZ()) > vertexCut) { + LOG(debug) << "Event not selected because of z-vertex cut z= " << theCollision.posZ() << " > " << vertexCut << " cm, skipping"; return; } mHistManager.fill(HIST("eventsSelected"), 1); @@ -248,13 +246,8 @@ struct TrackMatchingMonitor { for (const auto& alltrack : alltracks) { double trackEta, trackPhi; - if (hasPropagatedTracks) { // only temporarily while not every data has the tracks propagated to EMCal/PHOS - trackEta = alltrack.trackEtaEmcal(); - trackPhi = alltrack.trackPhiEmcal(); - } else { - trackEta = alltrack.eta(); - trackPhi = alltrack.phi(); - } + trackEta = alltrack.trackEtaEmcal(); + trackPhi = alltrack.trackPhiEmcal(); if (alltrack.isGlobalTrack()) { // NSigma of all global tracks without matching mHistManager.fill(HIST("TrackTM_NSigma"), alltrack.tpcNSigmaEl(), alltrack.pt()); mHistManager.fill(HIST("TrackEtaPhi"), trackEta, trackPhi); @@ -291,7 +284,7 @@ struct TrackMatchingMonitor { // match.track_as() with // using globTracks = o2::soa::Join; // In this example the counter t is just used to only look at the closest match - double dEta, dPhi, pT, abs_p, trackEta, trackPhi, NSigmaEl; + float dEta, dPhi, pT, abs_p, trackEta, trackPhi, nSigmaEl; int supermoduleID; try { supermoduleID = mGeometry->SuperModuleNumberFromEtaPhi(cluster.eta(), cluster.phi()); @@ -301,40 +294,35 @@ struct TrackMatchingMonitor { continue; } - pT = cluster.energy() / cosh(cluster.eta()); - if (M02highPt > 0. && cluster.m02() >= maxM02HighPt && pT >= M02highPt) { // high pT M02 cut + pT = cluster.energy() / std::cosh(cluster.eta()); + if (m02highPt > 0. && cluster.m02() >= maxM02HighPt && pT >= m02highPt) { // high pT M02 cut continue; } auto tracksofcluster = matchedtracks.sliceBy(perClusterMatchedTracks, cluster.globalIndex()); int t = 0; for (const auto& match : tracksofcluster) { - NSigmaEl = match.track_as().tpcNSigmaEl(); + nSigmaEl = match.track_as().tpcNSigmaEl(); // exmple of how to access any property of the matched tracks (tracks are sorted by how close they are to cluster) - LOG(debug) << "Pt of match" << match.track_as().pt(); - abs_p = abs(match.track_as().p()); + LOG(debug) << "Pt of match" << match.track_as().pt(); + abs_p = std::abs(match.track_as().p()); // only consider closest match - if (hasPropagatedTracks) { // only temporarily while not every data has the tracks propagated to EMCal/PHOS - trackEta = match.track_as().trackEtaEmcal(); - trackPhi = match.track_as().trackPhiEmcal(); - } else { - trackEta = match.track_as().eta(); - trackPhi = match.track_as().phi(); - } - dPhi = trackPhi - cluster.phi(); - dEta = trackEta - cluster.eta(); + trackEta = match.track_as().trackEtaEmcal(); + trackPhi = match.track_as().trackPhiEmcal(); + dPhi = match.deltaPhi(); + dEta = match.deltaEta(); mHistManager.fill(HIST("MatchedTrackEtaPhi_BeforeCut"), trackEta, trackPhi); - mHistManager.fill(HIST("clusterTM_NSigma_BeforeCut"), NSigmaEl, match.track_as().pt(), t); - if (match.track_as().sign() == -1) { + mHistManager.fill(HIST("clusterTM_NSigma_BeforeCut"), nSigmaEl, match.track_as().pt(), t); + if (match.track_as().sign() == -1) { mHistManager.fill(HIST("MatchedTrackEtaPhi_Neg_BeforeCut"), trackEta, trackPhi); - mHistManager.fill(HIST("clusterTM_NSigma_neg_BeforeCut"), NSigmaEl, match.track_as().pt(), t); - } else if (match.track_as().sign() == 1) { + mHistManager.fill(HIST("clusterTM_NSigma_neg_BeforeCut"), nSigmaEl, match.track_as().pt(), t); + } else if (match.track_as().sign() == 1) { mHistManager.fill(HIST("MatchedTrackEtaPhi_Pos_BeforeCut"), trackEta, trackPhi); - mHistManager.fill(HIST("clusterTM_NSigma_pos_BeforeCut"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_pos_BeforeCut"), nSigmaEl, match.track_as().pt(), t); } - if (fabs(dEta) >= minDEta || fabs(dPhi) >= minDPhi) { // dEta and dPhi cut + if (std::abs(dEta) >= minDEta || std::abs(dPhi) >= minDPhi) { // dEta and dPhi cut continue; } - if (hasTRD && !(match.track_as().hasTRD())) { // request TRD hit cut + if (hasTRD && !(match.track_as().hasTRD())) { // request TRD hit cut continue; } // only fill these for the first matched track: @@ -349,107 +337,106 @@ 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); + mHistManager.fill(HIST("clusterTM_EoverP_Pt"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma"), nSigmaEl, match.track_as().pt(), t); mHistManager.fill(HIST("MatchedTrackEtaPhi"), trackEta, trackPhi); if (eOverPRange->at(0) <= eOverP && eOverP <= eOverPRange->at(1)) { - mHistManager.fill(HIST("clusterTM_NSigma_cut"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_cut"), nSigmaEl, match.track_as().pt(), t); } // A- and C-side - if (match.track_as().eta() > 0.0 && t == 0) { + if (match.track_as().eta() > 0.0 && t == 0) { mHistManager.fill(HIST("clusterTM_dEtadPhi_ASide"), dEta, dPhi, supermoduleID); - } else if (match.track_as().eta() < 0.0 && t == 0) { + } else if (match.track_as().eta() < 0.0 && t == 0) { mHistManager.fill(HIST("clusterTM_dEtadPhi_CSide"), dEta, dPhi, supermoduleID); } // positive and negative tracks seperate, with three different track momentum ranges - if (match.track_as().sign() == 1) { - mHistManager.fill(HIST("clusterTM_NSigma_pos"), NSigmaEl, match.track_as().pt(), t); + if (match.track_as().sign() == 1) { + mHistManager.fill(HIST("clusterTM_NSigma_pos"), nSigmaEl, match.track_as().pt(), t); mHistManager.fill(HIST("MatchedTrackEtaPhi_Pos"), trackEta, trackPhi); if (t == 0) { mHistManager.fill(HIST("clusterTM_PosdPhiPt"), dPhi, pT, supermoduleID); mHistManager.fill(HIST("clusterTM_PosdEtadPhi"), dEta, dPhi, supermoduleID); - if (abs_p < 0.75) { + if (abs_p < lowP) { mHistManager.fill(HIST("clusterTM_PosdEtadPhi_Pl0_75"), dEta, dPhi, supermoduleID); - } else if (abs_p >= 1.25) { + } else if (abs_p >= midP) { mHistManager.fill(HIST("clusterTM_PosdEtadPhi_Pgeq1_25"), dEta, dPhi, supermoduleID); } else { mHistManager.fill(HIST("clusterTM_PosdEtadPhi_0_75leqPl1_25"), dEta, dPhi, supermoduleID); } } - } else if (match.track_as().sign() == -1) { - mHistManager.fill(HIST("clusterTM_NSigma_neg"), NSigmaEl, match.track_as().pt(), t); + } else if (match.track_as().sign() == -1) { + mHistManager.fill(HIST("clusterTM_NSigma_neg"), nSigmaEl, match.track_as().pt(), t); mHistManager.fill(HIST("MatchedTrackEtaPhi_Neg"), trackEta, trackPhi); if (t == 0) { mHistManager.fill(HIST("clusterTM_NegdPhiPt"), dPhi, pT, supermoduleID); mHistManager.fill(HIST("clusterTM_NegdEtadPhi"), dEta, dPhi, supermoduleID); - if (abs_p < 0.75) { + if (abs_p < lowP) { mHistManager.fill(HIST("clusterTM_NegdEtadPhi_Pl0_75"), dEta, dPhi, supermoduleID); - } else if (abs_p >= 1.25) { + } else if (abs_p >= midP) { mHistManager.fill(HIST("clusterTM_NegdEtadPhi_Pgeq1_25"), dEta, dPhi, supermoduleID); } else { mHistManager.fill(HIST("clusterTM_NegdEtadPhi_0_75leqPl1_25"), dEta, dPhi, supermoduleID); } } } - if (tpcNsigmaElectron->at(0) <= NSigmaEl && NSigmaEl <= tpcNsigmaElectron->at(1)) { // E/p for e+/e- - if (usePionRejection && (tpcNsigmaPion->at(0) <= match.track_as().tpcNSigmaPi() || match.track_as().tpcNSigmaPi() <= tpcNsigmaPion->at(1))) { // with pion rejection - mHistManager.fill(HIST("clusterTM_EoverP_ep"), eOverP, match.track_as().pt(), t); - if (match.track_as().eta() >= 0.) { - mHistManager.fill(HIST("clusterTM_EoverP_electron_ASide"), eOverP, match.track_as().pt(), t); - mHistManager.fill(HIST("clusterTM_NSigma_electron_ASide"), NSigmaEl, match.track_as().pt(), t); + if (tpcNsigmaElectron->at(0) <= nSigmaEl && nSigmaEl <= tpcNsigmaElectron->at(1)) { // E/p for e+/e- + if (usePionRejection && (tpcNsigmaPion->at(0) <= match.track_as().tpcNSigmaPi() || match.track_as().tpcNSigmaPi() <= tpcNsigmaPion->at(1))) { // with pion rejection + mHistManager.fill(HIST("clusterTM_EoverP_ep"), eOverP, match.track_as().pt(), t); + if (match.track_as().eta() >= 0.) { + mHistManager.fill(HIST("clusterTM_EoverP_electron_ASide"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_electron_ASide"), nSigmaEl, match.track_as().pt(), t); } else { - mHistManager.fill(HIST("clusterTM_EoverP_electron_CSide"), eOverP, match.track_as().pt(), t); - mHistManager.fill(HIST("clusterTM_NSigma_electron_CSide"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_EoverP_electron_CSide"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_electron_CSide"), nSigmaEl, match.track_as().pt(), t); } - if (match.track_as().sign() == -1) { - mHistManager.fill(HIST("clusterTM_EoverP_e"), eOverP, match.track_as().pt(), t); - mHistManager.fill(HIST("clusterTM_NSigma_e"), NSigmaEl, match.track_as().pt(), t); + if (match.track_as().sign() == -1) { + mHistManager.fill(HIST("clusterTM_EoverP_e"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_e"), nSigmaEl, match.track_as().pt(), t); if (eOverPRange->at(0) <= eOverP && eOverP <= eOverPRange->at(1)) { - mHistManager.fill(HIST("clusterTM_NSigma_e_cut"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_e_cut"), nSigmaEl, match.track_as().pt(), t); } - } else if (match.track_as().sign() == +1) { - mHistManager.fill(HIST("clusterTM_EoverP_p"), eOverP, match.track_as().pt(), t); - mHistManager.fill(HIST("clusterTM_NSigma_p"), NSigmaEl, match.track_as().pt(), t); + } else if (match.track_as().sign() == +1) { + mHistManager.fill(HIST("clusterTM_EoverP_p"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_p"), nSigmaEl, match.track_as().pt(), t); if (eOverPRange->at(0) <= eOverP && eOverP <= eOverPRange->at(1)) { - mHistManager.fill(HIST("clusterTM_NSigma_p_cut"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_p_cut"), nSigmaEl, match.track_as().pt(), t); } } } else { // without pion rejection - mHistManager.fill(HIST("clusterTM_EoverP_ep"), eOverP, match.track_as().pt(), t); - if (match.track_as().eta() >= 0.) { - mHistManager.fill(HIST("clusterTM_EoverP_electron_ASide"), eOverP, match.track_as().pt(), t); - mHistManager.fill(HIST("clusterTM_NSigma_electron_ASide"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_EoverP_ep"), eOverP, match.track_as().pt(), t); + if (match.track_as().eta() >= 0.) { + mHistManager.fill(HIST("clusterTM_EoverP_electron_ASide"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_electron_ASide"), nSigmaEl, match.track_as().pt(), t); } else { - mHistManager.fill(HIST("clusterTM_EoverP_electron_CSide"), eOverP, match.track_as().pt(), t); - mHistManager.fill(HIST("clusterTM_NSigma_electron_CSide"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_EoverP_electron_CSide"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_electron_CSide"), nSigmaEl, match.track_as().pt(), t); } - if (match.track_as().sign() == -1) { - mHistManager.fill(HIST("clusterTM_EoverP_e"), eOverP, match.track_as().pt(), t); - mHistManager.fill(HIST("clusterTM_NSigma_e"), NSigmaEl, match.track_as().pt(), t); + if (match.track_as().sign() == -1) { + mHistManager.fill(HIST("clusterTM_EoverP_e"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_e"), nSigmaEl, match.track_as().pt(), t); if (eOverPRange->at(0) <= eOverP && eOverP <= eOverPRange->at(1)) { - mHistManager.fill(HIST("clusterTM_NSigma_e_cut"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_e_cut"), nSigmaEl, match.track_as().pt(), t); } - } else if (match.track_as().sign() == +1) { - mHistManager.fill(HIST("clusterTM_EoverP_p"), eOverP, match.track_as().pt(), t); - mHistManager.fill(HIST("clusterTM_NSigma_p"), NSigmaEl, match.track_as().pt(), t); + } else if (match.track_as().sign() == +1) { + mHistManager.fill(HIST("clusterTM_EoverP_p"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_p"), nSigmaEl, match.track_as().pt(), t); if (eOverPRange->at(0) <= eOverP && eOverP <= eOverPRange->at(1)) { - mHistManager.fill(HIST("clusterTM_NSigma_p_cut"), NSigmaEl, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_NSigma_p_cut"), nSigmaEl, match.track_as().pt(), t); } } } - } else if (tpcNsigmaBack->at(0) <= NSigmaEl && NSigmaEl <= tpcNsigmaBack->at(1)) { // E/p for hadrons / background - mHistManager.fill(HIST("clusterTM_EoverP_hadron"), eOverP, match.track_as().pt(), t); - if (match.track_as().eta() >= 0.) { - mHistManager.fill(HIST("clusterTM_EoverP_hadron_ASide"), eOverP, match.track_as().pt(), t); + } else if (tpcNsigmaBack->at(0) <= nSigmaEl && nSigmaEl <= tpcNsigmaBack->at(1)) { // E/p for hadrons / background + mHistManager.fill(HIST("clusterTM_EoverP_hadron"), eOverP, match.track_as().pt(), t); + if (match.track_as().eta() >= 0.) { + mHistManager.fill(HIST("clusterTM_EoverP_hadron_ASide"), eOverP, match.track_as().pt(), t); } else { - mHistManager.fill(HIST("clusterTM_EoverP_hadron_CSide"), eOverP, match.track_as().pt(), t); + mHistManager.fill(HIST("clusterTM_EoverP_hadron_CSide"), eOverP, match.track_as().pt(), t); } - if (match.track_as().sign() == -1) { - mHistManager.fill(HIST("clusterTM_EoverP_hn"), eOverP, match.track_as().pt(), t); - } else if (match.track_as().sign() == +1) { - mHistManager.fill(HIST("clusterTM_EoverP_hp"), eOverP, match.track_as().pt(), t); + if (match.track_as().sign() == -1) { + mHistManager.fill(HIST("clusterTM_EoverP_hn"), eOverP, match.track_as().pt(), t); + } else if (match.track_as().sign() == +1) { + mHistManager.fill(HIST("clusterTM_EoverP_hp"), eOverP, match.track_as().pt(), t); } } t++; @@ -457,12 +444,11 @@ struct TrackMatchingMonitor { mHistManager.fill(HIST("clusterTM_NTrack"), t); } } - PROCESS_SWITCH(TrackMatchingMonitor, processCollisions, "Process clusters from collision", true); + PROCESS_SWITCH(EmcTmMonitor, processCollisions, "Process clusters from collision", true); /// \brief Create binning for cluster energy axis (variable bin size) /// \return vector with bin limits - std::vector - makeEnergyBinning() const + std::vector makeEnergyBinning() const { auto fillBinLimits = [](std::vector& binlimits, double max, double binwidth) { auto current = *binlimits.rbegin(); @@ -489,26 +475,27 @@ struct TrackMatchingMonitor { { std::vector result; - Int_t nBinsClusterE = 235; - for (Int_t i = 0; i < nBinsClusterE + 1; i++) { - if (i < 1) + int nBinsClusterE = 235; + for (int i = 0; i < nBinsClusterE + 1; i++) { + if (i < 1) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(0.3 * i); - else if (i < 55) + } else if (i < 55) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(0.3 + 0.05 * (i - 1)); - else if (i < 105) + } else if (i < 105) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(3. + 0.1 * (i - 55)); - else if (i < 140) + } else if (i < 140) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(8. + 0.2 * (i - 105)); - else if (i < 170) + } else if (i < 170) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(15. + 0.5 * (i - 140)); - else if (i < 190) + } else if (i < 190) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(30. + 1.0 * (i - 170)); - else if (i < 215) + } else if (i < 215) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(50. + 2.0 * (i - 190)); - else if (i < 235) + } else if (i < 235) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(100. + 5.0 * (i - 215)); - else if (i < 245) + } else if (i < 245) { // o2-linter: disable=magic-number (just numbers for binning) result.emplace_back(200. + 10.0 * (i - 235)); + } } return result; } @@ -522,20 +509,21 @@ struct TrackMatchingMonitor { result.reserve(1000); double epsilon = 1e-6; double valGammaPt = 0; - for (int i = 0; i < 1000; ++i) { + for (int i = 0; i < 1000; ++i) { // o2-linter: disable=magic-number (just numbers for binning) result.push_back(valGammaPt); - if (valGammaPt < 1.0 - epsilon) + if (valGammaPt < 1.0 - epsilon) { // o2-linter: disable=magic-number (just numbers for binning) valGammaPt += 0.1; - else if (valGammaPt < 5 - epsilon) + } else if (valGammaPt < 5 - epsilon) { // o2-linter: disable=magic-number (just numbers for binning) valGammaPt += 0.2; - else if (valGammaPt < 10 - epsilon) + } else if (valGammaPt < 10 - epsilon) { // o2-linter: disable=magic-number (just numbers for binning) valGammaPt += 0.5; - else if (valGammaPt < 50 - epsilon) + } else if (valGammaPt < 50 - epsilon) { // o2-linter: disable=magic-number (just numbers for binning) valGammaPt += 1; - else if (valGammaPt < 100 - epsilon) + } else if (valGammaPt < 100 - epsilon) { // o2-linter: disable=magic-number (just numbers for binning) valGammaPt += 5; - else + } else { break; + } } return result; } @@ -544,6 +532,6 @@ struct TrackMatchingMonitor { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{ - adaptAnalysisTask(cfgc, TaskName{"emc-tmmonitor"})}; + adaptAnalysisTask(cfgc)}; return workflow; } diff --git a/PWGJE/Tasks/emcvertexselectionqa.cxx b/PWGJE/Tasks/emcVertexSelectionQA.cxx similarity index 76% rename from PWGJE/Tasks/emcvertexselectionqa.cxx rename to PWGJE/Tasks/emcVertexSelectionQA.cxx index 9d3a33a2443..eb579326966 100644 --- a/PWGJE/Tasks/emcvertexselectionqa.cxx +++ b/PWGJE/Tasks/emcVertexSelectionQA.cxx @@ -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. // @@ -13,18 +13,26 @@ // /// \author Nicolas Strangmann , Goethe University Frankfurt / Oak Ridge National Laoratory -#include -#include -#include +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include +#include +#include +#include -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; @@ -37,6 +45,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 +83,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 +105,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 +114,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 +159,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 +217,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..d9674888aed --- /dev/null +++ b/PWGJE/Tasks/emcalGammaGammaBcWise.cxx @@ -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 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 "PWGJE/DataModel/EMCALClusters.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" + +#include "EMCALBase/Geometry.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TLorentzVector.h" +#include "TVector3.h" + +#include +#include + +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..273907b8056 100644 --- a/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx +++ b/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx @@ -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. // @@ -9,35 +9,40 @@ // 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 "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/HistogramRegistry.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/EMCALMatchedCollisions.h" +#include "Common/CCDB/TriggerAliases.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" #include "EMCALBase/Geometry.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGJE/DataModel/EMCALMatchedCollisions.h" -#include "DataFormatsEMCAL/Cell.h" -#include "DataFormatsEMCAL/Constants.h" -#include "DataFormatsEMCAL/AnalysisCluster.h" - -#include "CommonDataFormat/InteractionRecord.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include #include "TLorentzVector.h" #include "TVector3.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /// \brief Simple pi0 reconstruction task used to scale the cell energy based on the difference in mass position in data and MC /// \author Nicolas Strangmann , Goethe University Frankfurt / Oak Ridge National Laoratory @@ -201,7 +206,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 +218,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/fullJetSpectra.cxx b/PWGJE/Tasks/fullJetSpectra.cxx new file mode 100644 index 00000000000..345f3268bd8 --- /dev/null +++ b/PWGJE/Tasks/fullJetSpectra.cxx @@ -0,0 +1,2902 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file fullJetSpectra.cxx +/// \brief Task for full jet spectra studies in pp collisions. +/// \author Archita Rani Dash + +/// TO DO : include histograms for cluster correction modes in the MC Mult processes. + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/EMCALClusterDefinition.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using ClusterWithCorrections = soa::Join; + +struct FullJetSpectra { + + HistogramRegistry registry; + + // MC Sample split configurables + /* Configurable mcSplitSeed{"mcSplitSeed", 12345, "Seed for reproducible MC event splitting"}; + Configurable mcClosureSplitFrac{"mcClosureSplitFrac", 0.2f, "Fraction of MC events for closure test (MCD)"}; + Configurable doMcClosure{"doMcClosure", false, "Enable random splitting for MC closure test"}; + */ + // 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", false, "set to true only when using MB-Gap Trigger JJ MC to reject MB events at the collision and track level"}; + + // Software Trigger configurables + Configurable doSoftwareTriggerSelection{"doSoftwareTriggerSelection", false, "set to true when using triggered datasets"}; + Configurable triggerMasks{"triggerMasks", "fJetFullHighPt", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt"}; + + // 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"}; + + // Leading track and cluster pT configurables + Configurable leadingTrackPtMin{"leadingTrackPtMin", -99.0, "minimum pT selection on jet tracks"}; + Configurable leadingTrackPtMax{"leadingTrackPtMax", 999.0, "maximum pT selection on jet tracks"}; + Configurable leadingClusterPtMin{"leadingClusterPtMin", -99.0, "minimum pT selection on jet clusters"}; + Configurable leadingClusterPtMax{"leadingClusterPtMax", 999.0, "maximum pT selection on jet clusters"}; + + // 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", "selMCFull", "choose event selection"}; + Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; + + // Cluster configurables + Configurable clusterDefinitionS{"clusterDefinitionS", "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", -15., "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 pTHeventSelectionBitsat"}; // 6 for MB MC and 4 for JJ MC + Configurable pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"}; + + int trackSelection = -1; + // const float kJetAreaFractionMinThreshold = -98.0f; + const float kLeadingTrackPtMinThreshold = -98.0f; + const float kLeadingTrackPtMaxThreshold = 9998.0f; + const float kLeadingClusterPtMinThreshold = -98.0f; + const float kLeadingClusterPtMaxThreshold = 9998.0f; + + std::vector eventSelectionBits; + std::vector filledJetR; + std::vector jetRadiiValues; + std::vector triggerMaskBits; + std::string particleSelection; + + Service pdgDatabase; + Service ccdb; + + // Instantiate the Zorro processor for skimmed data and define an output object + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + bool doSumw2 = false; + + // Multiplicity Utilities + // struct CentClass { + // const char* name; + // float min; + // float max; + // }; + // // Define multiplicity classes here (example: MB(0-100), HM(0-1), 1-10, 10-20, 20-40, 40-60, 60-100) + // static constexpr int nCentClasses = 4; + // CentClass centClasses[nCentClasses] = { + // {"MB", 0.0, 100.0}, + // {"HM", 0.0, 1.0}, + // {"1_10", 1.0, 10.0}, + // {"10_20", 10.0, 20.0}, + // {"20_40", 20.0, 40.0}, + // {"40_60", 40.0, 60.0}, + // {"60_100", 60.0, 100.0} + // }; + + // Random splitter instance + /* TRandom3 randGen; + // float eventRandomValue = -1.0; // default invalid + // Cache to store random values per MC collision ID + std::unordered_map mcCollisionRandomValues; + */ + /* + MC CLOSURE SPLITTING LOGIC -> still not working across different process functions. Not so trivial in O2Physics Framework! + -------------------------- + • doMcClosure=true activates MC sample splitting. + • Each event gets ONE random value in [0, 1), stored in eventRandomValue. + • Events are split as: + - ≤ mcClosureSplitFrac -> Closure (MCD) + - > mcClosureSplitFrac -> Response (MCP + Matched) + • This ensures mutually exclusive processing — NO double-counting. + • eventRandomValue is reset to -1 after each event -> this is done by the `endOfEvent` defined at the end + */ + + // Add Collision Histograms' Bin Labels for clarity + void labelCollisionHistograms(HistogramRegistry& registry) + { + if (doprocessBCs) { + auto hBCCounter = registry.get(HIST("hBCCounter")); + hBCCounter->GetXaxis()->SetBinLabel(1, "AllBC"); + hBCCounter->GetXaxis()->SetBinLabel(2, "BC+kTVXinEMC"); + hBCCounter->GetXaxis()->SetBinLabel(3, "BC+kTVXinEMC+NoTFB"); + hBCCounter->GetXaxis()->SetBinLabel(4, "BC+kTVXinEMC+NoTFB+NoITSROFB"); + hBCCounter->GetXaxis()->SetBinLabel(5, "kTVXinEMC+CollinBC"); + hBCCounter->GetXaxis()->SetBinLabel(6, "kTVXinEMC+CollinBC+Sel8"); + hBCCounter->GetXaxis()->SetBinLabel(7, "kTVXinEMC+CollinBC+Sel8Full"); + hBCCounter->GetXaxis()->SetBinLabel(8, "kTVXinEMC+CollinBC+Sel8Full+GoodZvtx"); + hBCCounter->GetXaxis()->SetBinLabel(9, "kTVXinEMC+CollinBC+Sel8Full+VtxZ+GoodZvtx"); + } + + if (doprocessDataTracks || doprocessMCTracks) { + auto hCollisionsUnweighted = registry.get(HIST("hCollisionsUnweighted")); + hCollisionsUnweighted->GetXaxis()->SetBinLabel(1, "allDetColl"); + hCollisionsUnweighted->GetXaxis()->SetBinLabel(2, "DetCollWithVertexZ"); + hCollisionsUnweighted->GetXaxis()->SetBinLabel(3, "MBRejectedDetEvents"); + hCollisionsUnweighted->GetXaxis()->SetBinLabel(4, "EventsNotSatisfyingEventSelection"); + hCollisionsUnweighted->GetXaxis()->SetBinLabel(5, "EMCreadoutDetEventsWithkTVXinEMC"); + hCollisionsUnweighted->GetXaxis()->SetBinLabel(6, "AllRejectedEventsAfterEMCEventSelection"); + hCollisionsUnweighted->GetXaxis()->SetBinLabel(7, "EMCAcceptedDetColl"); + hCollisionsUnweighted->GetXaxis()->SetBinLabel(8, "EMCAcceptedCollAfterTrackSel"); + } + + if (doprocessTracksWeighted) { + auto hCollisionsWeighted = registry.get(HIST("hCollisionsWeighted")); + hCollisionsWeighted->GetXaxis()->SetBinLabel(1, "AllWeightedDetColl"); + hCollisionsWeighted->GetXaxis()->SetBinLabel(2, "WeightedCollWithVertexZ"); + hCollisionsWeighted->GetXaxis()->SetBinLabel(3, "MBRejectedDetEvents"); + hCollisionsWeighted->GetXaxis()->SetBinLabel(4, "EventsNotSatisfyingEventSelection"); + hCollisionsWeighted->GetXaxis()->SetBinLabel(5, "EMCreadoutDetJJEventsWithkTVXinEMC"); + hCollisionsWeighted->GetXaxis()->SetBinLabel(6, "AllRejectedEventsAfterEMCEventSelection"); + hCollisionsWeighted->GetXaxis()->SetBinLabel(7, "EMCAcceptedWeightedDetColl"); + hCollisionsWeighted->GetXaxis()->SetBinLabel(8, "EMCAcceptedWeightedCollAfterTrackSel"); + } + + if (doprocessJetsData || doprocessJetsMCD || doprocessJetsMCDWeighted) { + auto hDetcollisionCounter = registry.get(HIST("hDetcollisionCounter")); + hDetcollisionCounter->GetXaxis()->SetBinLabel(1, "allDetColl"); + hDetcollisionCounter->GetXaxis()->SetBinLabel(2, "DetCollWithVertexZ"); + hDetcollisionCounter->GetXaxis()->SetBinLabel(3, "RejectedDetCollWithOutliers"); + hDetcollisionCounter->GetXaxis()->SetBinLabel(4, "MBRejectedDetEvents"); + hDetcollisionCounter->GetXaxis()->SetBinLabel(5, "EventsNotSatisfyingEventSelection"); + hDetcollisionCounter->GetXaxis()->SetBinLabel(6, "EMCreadoutDetEventsWithkTVXinEMC"); + hDetcollisionCounter->GetXaxis()->SetBinLabel(7, "AllRejectedEventsAfterEMCEventSelection"); + hDetcollisionCounter->GetXaxis()->SetBinLabel(8, "EMCAcceptedDetColl"); + } + + if (doprocessJetsTriggeredData) { + auto hDetTrigcollisionCounter = registry.get(HIST("hDetTrigcollisionCounter")); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(1, "allDetTrigColl"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(2, "DetTrigCollAfterZorroSelection"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(3, "DetTrigCollWithVertexZ"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(4, "EventsNotSatisfyingEvent+TriggerSelection"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(5, "OnlyFullJetHighPt+NoFullJetLowPt"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(6, "OnlyFullJetLowPt"); + // hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(7, "OnlyLowPt+NoMB"); + // hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(8, "OnlyMB"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(7, "FullJetHighPt+FullJetLowPt"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(8, "FullJetHighPt+MB"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(9, "FullJetLowPt+MB"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(10, "AllRejectedTrigOverlaps"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(11, "EMCAcceptedDetTrigCollAfterTrigOverlapChecks"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(12, "AllRejectedDetTrigEventsAfterEMCEventSelection"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(13, "EMCAcceptedDetTrigColl"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(14, "EMCAcceptedDetTrigCollWithLowChargedJetTriggers"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(15, "EMCAcceptedDetTrigCollWithHighChargedJetTriggers"); + hDetTrigcollisionCounter->GetXaxis()->SetBinLabel(16, "EMCAcceptedDetTrigCollWithLow+HighFullJetTriggers"); + } + + if (doprocessJetsMCP || doprocessJetsMCPWeighted) { + auto hPartcollisionCounter = registry.get(HIST("hPartcollisionCounter")); + hPartcollisionCounter->GetXaxis()->SetBinLabel(1, "allMcColl"); + hPartcollisionCounter->GetXaxis()->SetBinLabel(2, "McCollWithVertexZ"); + hPartcollisionCounter->GetXaxis()->SetBinLabel(3, "PartCollWithSize>1"); + hPartcollisionCounter->GetXaxis()->SetBinLabel(4, "RejectedPartCollForDetCollWithSize0"); + hPartcollisionCounter->GetXaxis()->SetBinLabel(5, "RejectedPartCollWithOutliers"); + hPartcollisionCounter->GetXaxis()->SetBinLabel(6, "MBRejectedPartEvents"); + hPartcollisionCounter->GetXaxis()->SetBinLabel(7, "EMCreadoutDetJJEventsWithkTVXinEMC"); + hPartcollisionCounter->GetXaxis()->SetBinLabel(8, "AllRejectedPartEventsAfterEMCEventSelection"); + hPartcollisionCounter->GetXaxis()->SetBinLabel(9, "EMCAcceptedPartColl"); + } + + if (doprocessJetsMCPMCDMatched || doprocessJetsMCPMCDMatchedWeighted) { + auto hMatchedcollisionCounter = registry.get(HIST("hMatchedcollisionCounter")); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(1, "allDetColl"); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(2, "DetCollWithVertexZ"); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(3, "RejectedDetCollWithOutliers"); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(4, "RejectedPartCollWithOutliers"); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(5, "EMCMBRejectedDetColl"); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(6, "EventsNotSatisfyingEventSelection"); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(7, "EMCreadoutDetJJEventsWithkTVXinEMC"); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(8, "AllRejectedDetEventsAfterEMCEventSelection"); + hMatchedcollisionCounter->GetXaxis()->SetBinLabel(9, "EMCAcceptedDetColl"); + } + + if (doprocessMBCollisionsDATAWithMultiplicity || doprocessMBMCDCollisionsWithMultiplicity) { + auto hEventmultiplicityCounter = registry.get(HIST("hEventmultiplicityCounter")); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(1, "allDetColl"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(2, "DetCollWithVertexZ"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(3, "EventsNotSatisfyingEventSelection"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(4, "EMCreadoutDetEventsWithkTVXinEMC"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(5, "AllRejectedEventsAfterEMCEventSelection"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(6, "EMCAcceptedDetColl"); + } + + if (doprocessMCDCollisionsWeightedWithMultiplicity) { + auto hEventmultiplicityCounter = registry.get(HIST("hEventmultiplicityCounter")); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(1, "allWeightedDetColl"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(2, "WeightedDetCollWithVertexZ"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(3, "MBRejectedDetEvents"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(4, "WeightedEventsNotSatisfyingEventSelection"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(5, "EMCreadoutWeightedDetEventsWithkTVXinEMC"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(6, "AllRejectedWeightedEventsAfterEMCEventSelection"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(7, "EMCAcceptedWeightedDetColl"); + hEventmultiplicityCounter->GetXaxis()->SetBinLabel(8, "EMCAcceptedWeightedCollAfterTrackSel"); + } + + if (doprocessMBMCPCollisionsWithMultiplicity) { + auto hPartEventmultiplicityCounter = registry.get(HIST("hPartEventmultiplicityCounter")); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(1, "allMcColl"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(2, "McCollWithVertexZ"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(3, "RejectedPartCollWithOutliers"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(4, "MBRejectedPartEvents"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(5, "RejectedPartCollForDetCollWithSize0or<1"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(6, "AcceptedPartCollWithSize>=1"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(7, "EMCreadoutDetEventsWithkTVXinEMC"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(8, "AllRejectedPartEventsAfterEMCEventSelection"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(9, "EMCAcceptedPartColl"); + } + + if (doprocessMBMCPCollisionsWeightedWithMultiplicity) { + auto hPartEventmultiplicityCounter = registry.get(HIST("hPartEventmultiplicityCounter")); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(1, "allWeightedMcColl"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(2, "WeightedMcCollWithVertexZ"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(3, "RejectedWeightedPartCollWithOutliers"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(4, "MBRejectedPartEvents"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(5, "RejectedWeightedPartCollForDetCollWithSize0or<1"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(6, "AcceptedWeightedPartCollWithSize>=1"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(7, "EMCreadoutDetEventsWithkTVXinEMC"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(8, "AllRejectedWeightedPartEventsAfterEMCEventSelection"); + hPartEventmultiplicityCounter->GetXaxis()->SetBinLabel(9, "EMCAcceptedWeightedPartColl"); + } + } + + // Add Bin Labels for the MC Split Event Counter + /* void labelMCSplitHistogram(HistogramRegistry& registry) { + auto hSpliteventSelector = registry.get(HIST("hSpliteventSelector")); + hSpliteventSelector->GetXaxis()->SetBinLabel(1, "MCD"); + hSpliteventSelector->GetXaxis()->SetBinLabel(2, "MCP"); + hSpliteventSelector->GetXaxis()->SetBinLabel(3, "MatchedforRM"); +} +*/ + void init(o2::framework::InitContext&) + { + + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + particleSelection = static_cast(particleSelections); + jetRadiiValues = (std::vector)jetRadii; + doSumw2 = doMBGapTrigger; + /* if (doMcClosure) { + // randGen.SetSeed(mcSplitSeed); + // randGen.SetSeed(static_cast(std::time(nullptr))); + // int seed = mcSplitSeed >= 0 ? mcSplitSeed : static_cast(std::time(nullptr)); + // randGen.SetSeed(seed); + // LOGF(info, "MC closure seed = %d", seed); + + int seed = mcSplitSeed >= 0 ? mcSplitSeed : static_cast(std::time(nullptr)); + randGen.SetSeed(seed); + LOGF(info, "MC closure splitting enabled with seed = %d, split fraction = %.2f", seed, static_cast(mcClosureSplitFrac)); + + registry.add("hSpliteventSelector", "Random MC Split Selector;Split Type;Entries",{HistType::kTH1F, {{3, 0.0, 3.0}}}); // 0=MCD, 1=MCP, 2=RM + + //individual processes' event counters for sanity checks + registry.add("h_MCD_splitevent_counter", "Events into MCD split", {HistType::kTH1F, {{1, 0.0, 1.0}}}); + registry.add("h_MCP_splitevent_counter", "Events into MCP split", {HistType::kTH1F, {{1, 0.0, 1.0}}}); + registry.add("h_Matched_splitevent_counter", "Events into Matched split", {HistType::kTH1F, {{1, 0.0, 1.0}}}); + registry.add("hRandomValueDebug", "Random values for debugging;Random Value;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}); + + // DEBUG: Add counters for total events processed (before splitting) + registry.add("h_MCD_total_events", "Total MCD events processed", {HistType::kTH1F, {{1, 0.0, 1.0}}}); + registry.add("h_MCP_total_events", "Total MCP events processed", {HistType::kTH1F, {{1, 0.0, 1.0}}}); + registry.add("h_Matched_total_events", "Total Matched events processed", {HistType::kTH1F, {{1, 0.0, 1.0}}}); + registry.add("hMCCollisionIdDebug_MCP", "MC Collision Ids being processed", {HistType::kTH1F, {{100000, 0.0, 100000.0}}}); + + } + */ + 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] + (std::abs(jetRadiiBins[jetRadiiBins.size() - 1] - jetRadiiBins[jetRadiiBins.size() - 2]))); + } else { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); + } + + // Sanity Log check + if (doSumw2) { + LOGF(info, "HistogramRegistry initialized with Sumw2 = ON (weighted JJ MC mode)."); + } else { + LOGF(info, "HistogramRegistry initialized with Sumw2 = OFF (unweighted mode)."); + } + + if (doprocessBCs) { + registry.add("hBCCounter", "", {HistType::kTH1F, {{10, 0.0, 10.}}}, doSumw2); + } + + // Track QA histograms + if (doprocessDataTracks || doprocessMCTracks || doprocessTracksWeighted) { + registry.add("hCollisionsUnweighted", "event status; event status;entries", {HistType::kTH1F, {{12, 0., 12.0}}}, doSumw2); + + registry.add("h_track_pt", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_track_eta", "track #eta;#eta_{track};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_track_phi", "track #varphi;#varphi_{track};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + registry.add("h_track_energy", "track energy;Energy of tracks;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_track_energysum", "track energy sum;Sum of track energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + + // Cluster QA histograms + registry.add("h_clusterTime", "Time of cluster", HistType::kTH1F, {{500, -250, 250, "#it{t}_{cls} (ns)"}}, doSumw2); + registry.add("h_cluster_pt", "cluster pT;#it{p}_{T_cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}, doSumw2); + registry.add("h_cluster_eta", "cluster #eta;#eta_{cluster};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_cluster_phi", "cluster #varphi;#varphi_{cluster};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + registry.add("h_cluster_energysum_uncorr", "cluster energy sum;Sum of cluster energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_cluster_energysum_corr_oneTrack100", "cluster energy sum;Sum of cluster energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_cluster_energysum_corr_oneTrack70", "cluster energy sum;Sum of cluster energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_cluster_energysum_corr_allTracks100", "cluster energy sum;Sum of cluster energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_cluster_energysum_corr_allTracks70", "cluster energy sum;Sum of cluster energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + + registry.add("h_cluster_energy_uncorr", "Cluster Energy (uncorrected); E_{cluster} [GeV]; N_{clusters}", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_cluster_energy_corr_oneTrack100", "Cluster Energy (HadCorr, 1track, 100%); E_{cluster}^{corr,1,100} [GeV]; N_{clusters}", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_cluster_energy_corr_oneTrack70", "Cluster Energy (HadCorr, 1track, 70%); E_{cluster}^{corr,1,70} [GeV]; N_{clusters}", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_cluster_energy_corr_allTracks100", "Cluster Energy (HadCorr, alltracks, 100%); E_{cluster}^{corr,all,100} [GeV]; N_{clusters}", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_cluster_energy_corr_allTracks70", "Cluster Energy (HadCorr, alltracks, 70%); E_{cluster}^{corr,all,70} [GeV]; N_{clusters}", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + + if (doprocessTracksWeighted) { + registry.add("hCollisionsWeighted", "event status;event status;entries", {HistType::kTH1F, {{12, 0.0, 12.0}}}, doSumw2); + } + } + + // Jet QA histograms + if (doprocessJetsData || doprocessJetsMCD || doprocessJetsMCDWeighted || doprocessJetsTriggeredData) { + + registry.add("hDetcollisionCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.}}}, doSumw2); + + registry.add("h_full_jet_pt", "#it{p}_{T,jet};#it{p}_{T_jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_full_jet_pt_pTHatcut", "#it{p}_{T,jet};#it{p}_{T_jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_full_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_full_jet_phi", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + registry.add("h_full_jet_clusterTime", "Time of cluster", HistType::kTH1F, {{500, -250, 250, "#it{t}_{cls} (ns)"}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + + registry.add("h_Detjet_ntracks", "#it{p}_{T,track};#it{p}_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + registry.add("h_full_jet_chargedconstituents_pt", "track pT;#it{p}^{T,jet}_{track} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_full_jet_chargedconstituents_eta", "track #eta;#eta^{jet}_{track};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_full_jet_chargedconstituents_phi", "track #varphi;#varphi^{jet}_{track};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + registry.add("h_full_jet_chargedconstituents_energy", "track energy;Energy of tracks;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_full_jet_chargedconstituents_energysum", "track energy sum;Sum of track energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + + registry.add("h_full_jet_neutralconstituents_pt_uncorr", "cluster pT;#it{p}^{T,jet}_{cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_pt_corr_oneTrack100", "cluster pT;#it{p}^{T,jet}_{cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_pt_corr_oneTrack70", "cluster pT;#it{p}^{T,jet}_{cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_pt_corr_allTracks100", "cluster pT;#it{p}^{T,jet}_{cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_pt_corr_allTracks70", "cluster pT;#it{p}^{T,jet}_{cluster} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}, doSumw2); + + registry.add("h_full_jet_neutralconstituents_eta", "cluster #eta;#eta^{jet}_{cluster};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_phi", "cluster #varphi;#varphi^{jet}_{cluster};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_energy", "cluster energy;Energy of cluster;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_energysum", "cluster energy sum;Sum of cluster energy per event;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + 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.}}}, doSumw2); + registry.add("h2_full_jettrack_eta", "jet #eta vs jet_track #eta; #eta_{jet};#eta_{track}", {HistType::kTH2F, {{100, -1., 1.}, {500, -5., 5.}}}, doSumw2); + registry.add("h2_full_jettrack_phi", "jet #varphi vs jet_track #varphi; #varphi_{jet}; #varphi_{track}", {HistType::kTH2F, {{160, 0., 7.}, {160, -1., 7.}}}, doSumw2); + + registry.add("h2_track_etaphi", "jet_track #eta vs jet_track #varphi; #eta_{track};#varphi_{track}", {HistType::kTH2F, {{500, -5., 5.}, {160, -1., 7.}}}, doSumw2); + registry.add("h2_jet_etaphi", "jet #eta vs jet #varphi; #eta_{jet};#varphi_{jet}", {HistType::kTH2F, {{100, -1., 1.}, {160, -1., 7.}}}, doSumw2); + + // NEW: Jet constituent histograms for each hadronic correction mode + registry.add("h_full_jet_neutralconstituents_energy_uncorr", "Jet neutral cluster energy (uncorr)", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_energy_corr_oneTrack100", "Jet neutral cluster energy (corr 1track100)", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_energy_corr_oneTrack70", "Jet neutral cluster energy (corr 1track70)", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_energy_corr_allTracks100", "Jet neutral cluster energy (corr alltracks100)", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_energy_corr_allTracks70", "Jet neutral cluster energy (corr alltracks70)", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + // Corrected NEF histograms for the corresponding correction mode + registry.add("h2_full_jet_nef_uncorr", "Jet pT vs NEF (uncorr); p_{T,jet}; NEF", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 1.}}}, doSumw2); + registry.add("h2_full_jet_nef_corr_oneTrack100", "Jet pT vs NEF (corr, 1track100); p_{T,jet}; NEF", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 1.}}}, doSumw2); + registry.add("h2_full_jet_nef_corr_oneTrack70", "Jet pT vs NEF (corr, 1track70); p_{T,jet}; NEF", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 1.}}}, doSumw2); + registry.add("h2_full_jet_nef_corr_allTracks100", "Jet pT vs NEF (corr, alltracks100); p_{T,jet}; NEF", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 1.}}}, doSumw2); + registry.add("h2_full_jet_nef_corr_allTracks70", "Jet pT vs NEF (corr, alltracks70); p_{T,jet}; NEF", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 1.}}}, doSumw2); + } + if (doprocessJetsTriggeredData) { + registry.add("hDetTrigcollisionCounter", "event status;;entries", {HistType::kTH1F, {{17, 0.0, 17.}}}, doSumw2); + // 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}}}, doSumw2); + } + if (doprocessJetsMCP || doprocessJetsMCPWeighted) { + registry.add("hPartcollisionCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}, doSumw2); + registry.add("hRecoMatchesPerMcCollision", "split vertices QA;;entries", {HistType::kTH1F, {{5, 0.0, 5.0}}}, doSumw2); + + registry.add("h_full_mcpjet_tablesize", "", {HistType::kTH1F, {{4, 0., 5.}}}, doSumw2); + registry.add("h_full_mcpjet_ntracks", "", {HistType::kTH1F, {{200, -0.5, 200.}}}, doSumw2); + registry.add("h_full_jet_pt_part", "jet pT;#it{p}_{T_jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_full_jet_eta_part", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_full_jet_phi_part", "jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + 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}}}, doSumw2); + + registry.add("h_Partjet_ntracks", "#it{p}_{T,constituent};#it{p}_{T_constituent} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_eta_part", "#eta of neutral constituents at Part Level;#eta_{ne};entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_phi_part", "#varphi of neutral constituents at Part Level;#varphi_{ne};entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_full_jet_neutralconstituents_energy_part", "neutral constituents' energy;Energy of neutral constituents;entries", {HistType::kTH1F, {{400, 0., 400.}}}, doSumw2); + 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.}}}, doSumw2); + + 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.}}}, doSumw2); + registry.add("h2_jettrack_eta_part", "jet #eta vs jet_track #eta; #eta_{jet};#eta_{track}", {HistType::kTH2F, {{100, -1., 1.}, {500, -5., 5.}}}, doSumw2); + registry.add("h2_jettrack_phi_part", "jet #varphi vs jet_track #varphi; #varphi_{jet}; #varphi_{track}", {HistType::kTH2F, {{160, 0., 7.}, {160, -1., 7.}}}, doSumw2); + + 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.}}}, doSumw2); + registry.add("h2_jet_etaphi_part", "jet #eta vs jet #varphi; #eta_{jet};#varphi_{jet}", {HistType::kTH2F, {{100, -1., 1.}, {160, -1., 7.}}}, doSumw2); + + registry.add("h2_full_mcpjetOutsideFiducial_pt", "MCP jet outside EMC Fiducial Acceptance #it{p}_{T,part};#it{p}_{T,part} (GeV/c); Ncounts", {HistType::kTH2F, {{350, 0., 350.}, {10000, 0., 10000.}}}, doSumw2); + registry.add("h_full_mcpjetOutside_eta_part", "MCP jet #eta outside EMC Fiducial Acceptance;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_full_mcpjetOutside_phi_part", "MCP jet #varphi outside EMC Fiducial Acceptance;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + registry.add("h2_full_mcpjetInsideFiducial_pt", "MCP jet #it{p}_{T,part} inside EMC Fiducial Acceptance;#it{p}_{T,part} (GeV/c); Ncounts", {HistType::kTH2F, {{350, 0., 350.}, {10000, 0., 10000.}}}, doSumw2); + registry.add("h_full_mcpjetInside_eta_part", "MCP jet #eta inside EMC Fiducial Acceptance;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_full_mcpjetInside_phi_part", "MCP jet #varphi inside EMC Fiducial Acceptance;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + } + + if (doprocessJetsMCPMCDMatched || doprocessJetsMCPMCDMatchedWeighted) { + registry.add("hMatchedcollisionCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}, doSumw2); + + registry.add("h_full_matchedmcdjet_tablesize", "", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_full_matchedmcpjet_tablesize", "", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_full_matchedmcdjet_ntracks", "", {HistType::kTH1F, {{200, -0.5, 200.}}}, doSumw2); + registry.add("h_full_matchedmcpjet_ntracks", "", {HistType::kTH1F, {{200, -0.5, 200.}}}, doSumw2); + registry.add("h_full_matchedmcdjet_eta", "Matched MCD jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_full_matchedmcdjet_phi", "Matched MCD jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + registry.add("h_full_matchedmcpjet_eta", "Matched MCP jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1., 1.}}}, doSumw2); + registry.add("h_full_matchedmcpjet_phi", "Matched MCP jet #varphi;#varphi_{jet};entries", {HistType::kTH1F, {{160, 0., 7.}}}, doSumw2); + registry.add("h_full_jet_deltaR", "Distance between matched Det Jet and Part Jet; #Delta R; entries", {HistType::kTH1F, {{100, 0., 1.}}}, doSumw2); + + 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.}}}, doSumw2); + + registry.add("h2_matchedjet_etaphiDet", "Det jet #eta vs jet #varphi; #eta_{jet};#varphi_{jet}", {HistType::kTH2F, {{100, -1., 1.}, {160, -1., 7.}}}, doSumw2); + registry.add("h2_matchedjet_etaphiPart", "Part jet #eta vs jet #varphi; #eta_{jet};#varphi_{jet}", {HistType::kTH2F, {{100, -1., 1.}, {160, -1., 7.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + + 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.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + 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.}}}, doSumw2); + registry.add("h2_full_fakemcdjets", "Fake MCD Jets; p_{T,det} (GeV/c); NCounts", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 100.}}}, doSumw2); + registry.add("h2_full_fakemcpjets", "Fake MCP Jets; p_{T,part} (GeV/c); NCounts", {HistType::kTH2F, {{350, 0., 350.}, {100, 0., 100.}}}, doSumw2); + registry.add("h2_full_matchedmcpjet_pt", "Matched MCP jet in EMC Fiducial Acceptance #it{p}_{T,part};#it{p}_{T,part} (GeV/c); Ncounts", {HistType::kTH2F, {{350, 0., 350.}, {10000, 0., 10000.}}}, doSumw2); + + // Response Matrix + registry.add("h_full_jet_ResponseMatrix", "Full Jets Response Matrix; p_{T,det} (GeV/c); p_{T,part} (GeV/c)", {HistType::kTH2F, {{500, 0., 500.}, {500, 0., 500.}}}, doSumw2); + } + + if (doprocessMBCollisionsDATAWithMultiplicity || doprocessMBMCDCollisionsWithMultiplicity || doprocessMCDCollisionsWeightedWithMultiplicity) { + registry.add("hEventmultiplicityCounter", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}, doSumw2); + registry.add("h_FT0Mults_occupancy", "", {HistType::kTH1F, {{3500, 0., 3500.}}}, doSumw2); + + registry.add("h_all_fulljet_Njets", "Full Jet Multiplicity (per Event)", {HistType::kTH1F, {{20, 0., 20.}}}, doSumw2); + registry.add("h_Leading_full_jet_pt", "#it{p}_{T,leading jet};#it{p}_{T_leading jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h2_full_jet_leadingJetPt_vs_counts", ";#it{p}_{T_leading jet} (GeV/#it{c}); Counts", {HistType::kTH2F, {{350, 0., 350.}, {20, 0., 20.}}}, doSumw2); + registry.add("h_SubLeading_full_jet_pt", "#it{p}_{T,leading jet};#it{p}_{T_leading jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h2_full_jet_subLeadingJetPt_vs_counts", ";#it{p}_{T_leading jet} (GeV/#it{c}); Counts", {HistType::kTH2F, {{350, 0., 350.}, {20, 0., 20.}}}, doSumw2); + // Inside Jet Loop: + // CASE 1: + registry.add("h_all_fulljet_pt", "#it{p}_{T,fulljet};#it{p}_{T_fulljet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_all_fulljet_Nch", ";N_{ch};", {HistType::kTH1F, {{50, 0., 50.}}}, doSumw2); + registry.add("h_all_fulljet_NEF_uncorr", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h_all_fulljet_NEF_corr_oneTrack100", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h_all_fulljet_NEF_corr_oneTrack70", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h_all_fulljet_NEF_corr_allTracks100", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h_all_fulljet_NEF_corr_allTracks70", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + + registry.add("h2_all_fulljet_jetpTDet_vs_FT0Mults", "; p_{T,det} (GeV/c); FT0M Multiplicity", {HistType::kTH2F, {{350, 0., 350.}, {3500, 0., 3500.}}}, doSumw2); + registry.add("h2_all_fulljet_jetpTDet_vs_Nch", ";#it{p}_{T_fulljet} (GeV/#it{c}); N_{ch}", {HistType::kTH2F, {{350, 0., 350.}, {50, 0., 50.}}}, doSumw2); + registry.add("h3_full_jet_jetpTDet_FT0Mults_nef_uncorr", "; p_{T,det} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + registry.add("h3_full_jet_jetpTDet_FT0Mults_nef_corr_oneTrack100", "; p_{T,det} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + registry.add("h3_full_jet_jetpTDet_FT0Mults_nef_corr_oneTrack70", "; p_{T,det} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + registry.add("h3_full_jet_jetpTDet_FT0Mults_nef_corr_allTracks100", "; p_{T,det} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + registry.add("h3_full_jet_jetpTDet_FT0Mults_nef_corr_allTracks70", "; p_{T,det} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + // CASE 2: + registry.add("h_leading_fulljet_pt", "#it{p}_{T,Leading fulljet};#it{p}_{T_Leadingfulljet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_leading_fulljet_Nch", ";N_{ch};", {HistType::kTH1F, {{50, 0., 50.}}}, doSumw2); + registry.add("h_leading_fulljet_NEF", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h2_leading_fulljet_jetpTDet_vs_FT0Mults", ";Leading p_{T,det} (GeV/c); FT0M Multiplicity", {HistType::kTH2F, {{350, 0., 350.}, {3500, 0., 3500.}}}, doSumw2); + registry.add("h2_leading_fulljet_jetpTDet_vs_Nch", ";#it{p}_{T_Leadingfulljet} (GeV/#it{c}); N_{ch}", {HistType::kTH2F, {{350, 0., 350.}, {50, 0., 50.}}}, doSumw2); + registry.add("h3_leading_fulljet_jetpTDet_FT0Mults_nef", "; Leading p_{T,det} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + // CASE 3: + registry.add("h_subleading_fulljet_pt", "#it{p}_{T,SubLeading fulljet};#it{p}_{T_SubLeadingfulljet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_subleading_fulljet_Nch", ";N_{ch};", {HistType::kTH1F, {{50, 0., 50.}}}, doSumw2); + registry.add("h_subleading_fulljet_NEF", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h2_subleading_fulljet_jetpTDet_vs_FT0Mults", ";SubLeading p_{T,det} (GeV/c); FT0M Multiplicity", {HistType::kTH2F, {{350, 0., 350.}, {3500, 0., 3500.}}}, doSumw2); + registry.add("h2_subleading_fulljet_jetpTDet_vs_Nch", ";#it{p}_{T_SubLeadingfulljet} (GeV/#it{c}); N_{ch}", {HistType::kTH2F, {{350, 0., 350.}, {50, 0., 50.}}}, doSumw2); + registry.add("h3_subleading_fulljet_jetpTDet_FT0Mults_nef", "; SubLeading p_{T,det} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + } + + if (doprocessMBMCPCollisionsWithMultiplicity || doprocessMBMCPCollisionsWeightedWithMultiplicity) { + registry.add("hPartEventmultiplicityCounter", "event status;event status;entries", {HistType::kTH1F, {{11, 0.0, 11.0}}}, doSumw2); + registry.add("hRecoMatchesPerMcCollisionMult", "split vertices QA;;entries", {HistType::kTH1F, {{5, 0.0, 5.0}}}, doSumw2); + registry.add("hMCCollMatchedFT0Mult", "", {HistType::kTH1F, {{3500, 0., 3500.}}}, doSumw2); + registry.add("hMCCollMatchedFT0Cent", "", {HistType::kTH1F, {{105, 0., 105.}}}, doSumw2); + + registry.add("h_all_fulljet_Njets_part", "Full Jet Multiplicity (per Event)", {HistType::kTH1F, {{20, 0., 20.}}}, doSumw2); + registry.add("h_Leading_full_jet_pt_part", "#it{p}_{T,leading jet};#it{p}_{T_leading jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h2_full_jet_leadingJetPt_vs_counts_part", ";#it{p}_{T_leading jet} (GeV/#it{c}); Counts", {HistType::kTH2F, {{350, 0., 350.}, {20, 0., 20.}}}, doSumw2); + registry.add("h_SubLeading_full_jet_pt_part", "#it{p}_{T,leading jet};#it{p}_{T_leading jet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h2_full_jet_subLeadingJetPt_vs_counts_part", ";#it{p}_{T_leading jet} (GeV/#it{c}); Counts", {HistType::kTH2F, {{350, 0., 350.}, {20, 0., 20.}}}, doSumw2); + + // Inside Jet Loop: + // CASE 1: + registry.add("h_all_fulljet_pt_part", "#it{p}_{T,fulljet};#it{p}_{T_fulljet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_all_fulljet_Nch_part", ";N_{ch};", {HistType::kTH1F, {{50, 0., 50.}}}, doSumw2); + registry.add("h_all_fulljet_Nne_part", ";N_{ne};", {HistType::kTH1F, {{100, 0., 100.}}}, doSumw2); + registry.add("h_all_fulljet_NEF_part", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h2_all_fulljet_jetpT_vs_FT0Mults_part", "; p_{T,part} (GeV/c); FT0M Multiplicity", {HistType::kTH2F, {{350, 0., 350.}, {3500, 0., 3500.}}}, doSumw2); + registry.add("h2_all_fulljet_jetpT_vs_Nch_part", ";#it{p}_{T_fulljet} (GeV/#it{c}); N_{ch}", {HistType::kTH2F, {{350, 0., 350.}, {50, 0., 50.}}}, doSumw2); + registry.add("h3_full_jet_jetpT_FT0Mults_nef_part", "; p_{T,part} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + // CASE 2: + registry.add("h_leading_fulljet_pt_part", "#it{p}_{T,Leading fulljet};#it{p}_{T_Leadingfulljet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_leading_fulljet_Nch_part", ";N_{ch};", {HistType::kTH1F, {{50, 0., 50.}}}, doSumw2); + registry.add("h_leading_fulljet_Nne_part", ";N_{ne};", {HistType::kTH1F, {{100, 0., 100.}}}, doSumw2); + registry.add("h_leading_fulljet_NEF_part", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h2_leading_fulljet_jetpT_vs_FT0Mults_part", ";Leading p_{T,part} (GeV/c); FT0M Multiplicity", {HistType::kTH2F, {{350, 0., 350.}, {3500, 0., 3500.}}}, doSumw2); + registry.add("h2_leading_fulljet_jetpT_vs_Nch_part", ";#it{p}_{T_Leadingfulljet} (GeV/#it{c}); N_{ch}", {HistType::kTH2F, {{350, 0., 350.}, {50, 0., 50.}}}, doSumw2); + registry.add("h3_leading_fulljet_jetpT_FT0Mults_nef_part", "; Leading p_{T,part} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + // CASE 3: + registry.add("h_subleading_fulljet_pt_part", "#it{p}_{T,SubLeading fulljet};#it{p}_{T_SubLeadingfulljet} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0., 350.}}}, doSumw2); + registry.add("h_subleading_fulljet_Nch_part", ";N_{ch};", {HistType::kTH1F, {{50, 0., 50.}}}, doSumw2); + registry.add("h_subleading_fulljet_Nne_part", ";N_{ne};", {HistType::kTH1F, {{100, 0., 100.}}}, doSumw2); + registry.add("h_subleading_fulljet_NEF_part", ";NEF;", {HistType::kTH1F, {{105, 0., 1.05}}}, doSumw2); + registry.add("h2_subleading_fulljet_jetpT_vs_FT0Mults_part", ";SubLeading p_{T,part} (GeV/c); FT0M Multiplicity", {HistType::kTH2F, {{350, 0., 350.}, {3500, 0., 3500.}}}, doSumw2); + registry.add("h2_subleading_fulljet_jetpT_vs_Nch_part", ";#it{p}_{T_SubLeadingfulljet} (GeV/#it{c}); N_{ch}", {HistType::kTH2F, {{350, 0., 350.}, {50, 0., 50.}}}, doSumw2); + registry.add("h3_subleading_fulljet_jetpT_FT0Mults_nef_part", "; SubLeading p_{T,part} (GeV/c); FT0M Multiplicity, nef", {HistType::kTH3F, {{350, 0., 350.}, {50, 0., 50.}, {105, 0.0, 1.05}}}, doSumw2); + } + + // Label the histograms + labelCollisionHistograms(registry); + // labelMCSplitHistogram(registry); + } // init + + // Initialize CCDB access and histogram registry for Zorro processing + template + void initCCDB(const BCType& bc) + { + if (doSoftwareTriggerSelection) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerMasks.value); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + } + + // Get or generate random value for a specific MC collision + /* float getMCCollisionRandomValue(int64_t mcCollisionId) { + if (!doMcClosure) return 0.0f; + + // Check if I already have a random value for this MC collision + auto it = mcCollisionRandomValues.find(mcCollisionId); + if (it != mcCollisionRandomValues.end()) { + LOGF(debug, "Using cached random value %.4f for MC collision %lld", it->second, mcCollisionId); + return it->second; + } + + // Generate new random value for this MC collision + float randomVal = randGen.Uniform(0.0, 1.0); + mcCollisionRandomValues[mcCollisionId] = randomVal; + + // Debug histogram + registry.fill(HIST("hRandomValueDebug"), randomVal); + + LOGF(info, "Generated NEW random value %.4f for MC collision %lld", randomVal, mcCollisionId); + return randomVal; + } + */ + using EMCCollisionsData = o2::soa::Join; // JetCollisions with EMCAL Collision Labels + using EMCCollisionsTriggeredData = o2::soa::Join; + + using EMCCollisionsMCD = o2::soa::Join; // where, JetCollisionsMCD = JetCollisions+JMcCollisionLbs + + 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 jetMcpPerMcCollision = 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::centFT0M >= centralityMin && aod::jcollision::centFT0M < 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; + PresliceUnsorted> CollisionsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; + PresliceUnsorted> perFoundBC = aod::evsel::foundBCId; + + template + bool isAcceptedRecoJet(U const& jet) + { + // if (jetAreaFractionMin > kJetAreaFractionMinThreshold) { + // if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + // return false; + // } + // } + + // --- Track cuts: ALL tracks must satisfy 0.15 <= pT <= 200 or 150 GeV/c--- + if (leadingTrackPtMin > kLeadingTrackPtMinThreshold || leadingTrackPtMax < kLeadingTrackPtMaxThreshold) { + bool hasValidTrack = false; + for (const auto& constituent : jet.template tracks_as()) { + const float pt = constituent.pt(); + // Reject if ANY track fails min or max cut + if ((leadingTrackPtMin > kLeadingTrackPtMinThreshold && pt < leadingTrackPtMin) || + (leadingTrackPtMax < kLeadingTrackPtMaxThreshold && pt > leadingTrackPtMax)) { + return false; + } + hasValidTrack = true; // At least one track exists (if needed) + } + // Reject if no tracks exist (edge case) + if (leadingTrackPtMin > kLeadingTrackPtMinThreshold && !hasValidTrack) { + return false; + } + } + + // --- Cluster cuts: ALL clusters must satisfy min <= pT <= max == 0.3 <= pT <= 250 + if (leadingClusterPtMin > kLeadingClusterPtMinThreshold || leadingClusterPtMax < kLeadingClusterPtMaxThreshold) { + bool hasValidCluster = false; + for (const auto& cluster : jet.template clusters_as()) { + const double pt = cluster.energy() / std::cosh(cluster.eta()); + // Reject if ANY cluster fails min or max cut + if ((leadingClusterPtMin > kLeadingClusterPtMinThreshold && pt < leadingClusterPtMin) || + (leadingClusterPtMax < kLeadingClusterPtMaxThreshold && pt > leadingClusterPtMax)) { + return false; + } + hasValidCluster = true; // At least one cluster exists + } + // Reject if no clusters exist (edge case) + if (leadingClusterPtMin > kLeadingClusterPtMinThreshold && !hasValidCluster) { + return false; + } + } + return true; + } // isAcceptedRecoJet ends + + template + bool isAcceptedPartJet(U const& jet) + { + // if (jetAreaFractionMin > kJetAreaFractionMinThreshold) { + // if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + // return false; + // } + // } + // track pt Min cut at the Part level: 0 < pT <= 200 or 150 GeV/c + if (leadingTrackPtMin > kLeadingTrackPtMinThreshold || leadingTrackPtMax < kLeadingTrackPtMaxThreshold) { + bool hasValidParticle = false; + for (const auto& constituent : jet.template tracks_as()) { + const float pt = constituent.pt(); + // Reject if ANY particle fails min or max cut + if ((leadingTrackPtMin > kLeadingTrackPtMinThreshold && pt < leadingTrackPtMin) || + (leadingTrackPtMax < kLeadingTrackPtMaxThreshold && pt > leadingTrackPtMax)) { + return false; + } + hasValidParticle = true; // At least one track exists (if needed) + } + // Reject if no particle exist (edge case) + if (leadingTrackPtMin > kLeadingTrackPtMinThreshold && !hasValidParticle) { + return false; + } + } + return true; + } + + template + void fillJetHistograms(T const& jet, float weight = 1.0) + { + // float neutralEnergy = 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); + + // Sums for each correction mode + double neutralEnergy_uncorr = 0.0; + double neutralEnergy_corr_oneTrack100 = 0.0; + double neutralEnergy_corr_oneTrack70 = 0.0; + double neutralEnergy_corr_allTracks100 = 0.0; + double neutralEnergy_corr_allTracks70 = 0.0; + + for (const auto& cluster : jet.template clusters_as()) { + registry.fill(HIST("h2_full_jet_neutralconstituents"), jet.pt(), jet.clustersIds().size(), weight); + + // Sum energies for NEF calculation for each correction mode + neutralEnergy_uncorr += cluster.energy(); + neutralEnergy_corr_oneTrack100 += cluster.energyCorrectedOneTrack1(); + neutralEnergy_corr_oneTrack70 += cluster.energyCorrectedOneTrack2(); + neutralEnergy_corr_allTracks100 += cluster.energyCorrectedAllTracks1(); + neutralEnergy_corr_allTracks70 += cluster.energyCorrectedAllTracks2(); + + // neutralEnergy += cluster.energy(); + double clusterpt_uncorr = cluster.energy() / std::cosh(cluster.eta()); + double clusterpt_corr_oneTrack100 = cluster.energyCorrectedOneTrack1() / std::cosh(cluster.eta()); + double clusterpt_corr_oneTrack70 = cluster.energyCorrectedOneTrack2() / std::cosh(cluster.eta()); + double clusterpt_corr_allTracks100 = cluster.energyCorrectedAllTracks1() / std::cosh(cluster.eta()); + double clusterpt_corr_allTracks70 = cluster.energyCorrectedAllTracks2() / std::cosh(cluster.eta()); + + registry.fill(HIST("h_full_jet_clusterTime"), cluster.time(), weight); + registry.fill(HIST("h_full_jet_neutralconstituents_pt_uncorr"), clusterpt_uncorr, weight); + registry.fill(HIST("h_full_jet_neutralconstituents_pt_corr_oneTrack100"), clusterpt_corr_oneTrack100, weight); + registry.fill(HIST("h_full_jet_neutralconstituents_pt_corr_oneTrack70"), clusterpt_corr_oneTrack70, weight); + registry.fill(HIST("h_full_jet_neutralconstituents_pt_corr_allTracks100"), clusterpt_corr_allTracks100, weight); + registry.fill(HIST("h_full_jet_neutralconstituents_pt_corr_allTracks70"), clusterpt_corr_allTracks70, 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_energysum"), neutralEnergy_uncorr, weight); + + registry.fill(HIST("h_full_jet_neutralconstituents_energy_uncorr"), cluster.energy(), weight); + + if (cluster.energyCorrectedOneTrack1()) { + registry.fill(HIST("h_full_jet_neutralconstituents_energy_corr_oneTrack100"), cluster.energyCorrectedOneTrack1(), weight); + } + if (cluster.energyCorrectedOneTrack2()) { + registry.fill(HIST("h_full_jet_neutralconstituents_energy_corr_oneTrack70"), cluster.energyCorrectedOneTrack2(), weight); + } + if (cluster.energyCorrectedAllTracks1()) { + registry.fill(HIST("h_full_jet_neutralconstituents_energy_corr_allTracks100"), cluster.energyCorrectedAllTracks1(), weight); + } + if (cluster.energyCorrectedAllTracks2()) { + registry.fill(HIST("h_full_jet_neutralconstituents_energy_corr_allTracks70"), cluster.energyCorrectedAllTracks2(), weight); + } + } + // auto nef = neutralEnergy / jet.energy(); + // registry.fill(HIST("h2_full_jet_nef"), jet.pt(), nef, weight); + auto jetEnergy = jet.energy(); + + auto nef_uncorr = neutralEnergy_uncorr / jetEnergy; + auto nef_corr_oneTrack100 = neutralEnergy_corr_oneTrack100 / jetEnergy; + auto nef_corr_oneTrack70 = neutralEnergy_corr_oneTrack70 / jetEnergy; + auto nef_corr_allTracks100 = neutralEnergy_corr_allTracks100 / jetEnergy; + auto nef_corr_allTracks70 = neutralEnergy_corr_allTracks70 / jetEnergy; + + registry.fill(HIST("h2_full_jet_nef_uncorr"), jet.pt(), nef_uncorr, weight); + registry.fill(HIST("h2_full_jet_nef_corr_oneTrack100"), jet.pt(), nef_corr_oneTrack100, weight); + registry.fill(HIST("h2_full_jet_nef_corr_oneTrack70"), jet.pt(), nef_corr_oneTrack70, weight); + registry.fill(HIST("h2_full_jet_nef_corr_allTracks100"), jet.pt(), nef_corr_allTracks100, weight); + registry.fill(HIST("h2_full_jet_nef_corr_allTracks70"), jet.pt(), nef_corr_allTracks70, weight); + double sumtrackE = 0; + for (const 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) + { + if (jet.r() == round(selectedJetsRadius * 100.0f)) { + float neutralEnergy = 0.0; + for (const 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) + { + auto isInFiducial = [&](auto const& jet) { + return jet.eta() >= jetEtaMin && jet.eta() <= jetEtaMax && + jet.phi() >= jetPhiMin && jet.phi() <= jetPhiMax; + }; + + 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); + + if (!isInFiducial(jet)) { + // jet is outside + registry.fill(HIST("h2_full_mcpjetOutsideFiducial_pt"), jet.pt(), 1, weight); + registry.fill(HIST("h_full_mcpjetOutside_eta_part"), jet.eta(), weight); + registry.fill(HIST("h_full_mcpjetOutside_phi_part"), jet.phi(), weight); + } else { + // jet is inside + registry.fill(HIST("h2_full_mcpjetInsideFiducial_pt"), jet.pt(), 1, weight); + registry.fill(HIST("h_full_mcpjetInside_eta_part"), jet.eta(), weight); + registry.fill(HIST("h_full_mcpjetInside_phi_part"), jet.phi(), weight); + } + + float neutralEnergy = 0.0; + int neutralconsts = 0; + int chargedconsts = 0; + for (const 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); + } // jet.r() + } + + template + void fillTrackHistograms(T const& tracks, U const& clusters, float weight = 1.0) + { + double sumtrackE = 0.0; + + 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_uncorr = 0.0; + double sumclusterE_corr_oneTrack100 = 0.0; + double sumclusterE_corr_oneTrack70 = 0.0; + double sumclusterE_corr_allTracks100 = 0.0; + double sumclusterE_corr_allTracks70 = 0.0; + + for (auto const& cluster : clusters) { + + double clusterpt = cluster.energy() / std::cosh(cluster.eta()); + sumclusterE_uncorr += cluster.energy(); + sumclusterE_corr_oneTrack100 += cluster.energyCorrectedOneTrack1(); + sumclusterE_corr_oneTrack70 += cluster.energyCorrectedOneTrack2(); + sumclusterE_corr_allTracks100 += cluster.energyCorrectedAllTracks1(); + sumclusterE_corr_allTracks70 += cluster.energyCorrectedAllTracks2(); + + registry.fill(HIST("h_cluster_energy_uncorr"), cluster.energy(), weight); + if (cluster.energyCorrectedOneTrack1()) { + registry.fill(HIST("h_cluster_energy_corr_oneTrack100"), cluster.energyCorrectedOneTrack1(), weight); + } + if (cluster.energyCorrectedOneTrack2()) { + registry.fill(HIST("h_cluster_energy_corr_oneTrack70"), cluster.energyCorrectedOneTrack2(), weight); + } + if (cluster.energyCorrectedAllTracks1()) { + registry.fill(HIST("h_cluster_energy_corr_allTracks100"), cluster.energyCorrectedAllTracks1(), weight); + } + if (cluster.energyCorrectedAllTracks2()) { + registry.fill(HIST("h_cluster_energy_corr_allTracks70"), cluster.energyCorrectedAllTracks2(), weight); + } + + registry.fill(HIST("h_clusterTime"), cluster.time(), weight); + 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_energysum_uncorr"), sumclusterE_uncorr, weight); + registry.fill(HIST("h_cluster_energysum_corr_oneTrack100"), sumclusterE_corr_oneTrack100, weight); + registry.fill(HIST("h_cluster_energysum_corr_oneTrack70"), sumclusterE_corr_oneTrack70, weight); + registry.fill(HIST("h_cluster_energysum_corr_allTracks100"), sumclusterE_corr_allTracks100, weight); + registry.fill(HIST("h_cluster_energysum_corr_allTracks70"), sumclusterE_corr_allTracks70, weight); + } + } + + template + void fillMatchedHistograms(T const& jetBase, float weight = 1.0) + { + 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 (const auto& jetTag : jetBase.template matchedJetGeo_as>()) { + 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(FullJetSpectra, processDummy, "dummy task", true); + + void processBCs(o2::soa::Join const& bcs, o2::soa::Join const& collisions) + { + if (bcs.size() == 0) { + return; + } + for (auto bc : bcs) { + registry.fill(HIST("hBCCounter"), 0.5); // All BC + if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) { + registry.fill(HIST("hBCCounter"), 1.5); // BC+TVX + if (bc.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + registry.fill(HIST("hBCCounter"), 2.5); // BC+TVX+NoTFB + if (bc.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + registry.fill(HIST("hBCCounter"), 3.5); // BC+TVX+NoTFB+NoITSROFB ----> this goes to Lumi i.e. hLumiAfterBCcuts in eventSelection task + } + } + } + auto collisionsInBC = collisions.sliceBy(perFoundBC, bc.globalIndex()); + for (auto collision : collisionsInBC) { + registry.fill(HIST("hBCCounter"), 4.5); // CollinBC + if (collision.sel8()) { + registry.fill(HIST("hBCCounter"), 5.5); // CollinBC+sel8 + if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + registry.fill(HIST("hBCCounter"), 6.5); // CollinBC+sel8Full + if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + registry.fill(HIST("hBCCounter"), 7.5); // CollinBC+sel8Full+GoodZvtx + if (std::fabs(collision.posZ()) < vertexZCut) { + registry.fill(HIST("hBCCounter"), 8.5); // CollinBC+sel8Full+VtxZ+GoodZvtx ----> this goes to my analysis task for jet events selection + } + } + } + } + } // collision loop + } // bc loop + } + PROCESS_SWITCH(FullJetSpectra, processBCs, "BCs for 0 vertex QA", false); + + void processJetsData(soa::Filtered::iterator const& collision, FullJetTableDataJoined const& jets, + aod::JetTracks const&, ClusterWithCorrections const&) + { + bool eventAccepted = false; + + registry.fill(HIST("hDetcollisionCounter"), 0.5); // allDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hDetcollisionCounter"), 1.5); // DetCollWithVertexZ + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hDetcollisionCounter"), 4.5); // EventsNotSatisfyingEventSelection + 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("hDetcollisionCounter"), 5.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("hDetcollisionCounter"), 5.5); // EMCreadoutDetEventsWithkTVXinEMC + eventAccepted = true; + } + } + + if (!eventAccepted) { + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax) || !isAcceptedRecoJet(jet)) { + fillRejectedJetHistograms(jet, 1.0); + } + } + registry.fill(HIST("hDetcollisionCounter"), 6.5); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hDetcollisionCounter"), 7.5); // EMCAcceptedDetColl + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) { + continue; + } + if (!isAcceptedRecoJet(jet)) { + continue; + } + fillJetHistograms(jet); + } + } + PROCESS_SWITCH(FullJetSpectra, processJetsData, "Full Jets Data", false); + + void processJetsTriggeredData(soa::Filtered::iterator const& collision, FullJetTableDataJoined const& jets, + aod::JetTracks const&, ClusterWithCorrections const&, aod::JBCs const&) + { + bool eventAccepted = false; + + registry.fill(HIST("hDetTrigcollisionCounter"), 0.5); // allDetTrigColl + + // Get BC info associated with the collision before applying any event selections + auto bc = collision.bc_as(); + // Initialize CCDB objects using the BC info + initCCDB(bc); + // If SoftwareTriggerSelection (i.e. skimming) is enabled, skip this event unless it passes Zorro selection + if (doSoftwareTriggerSelection && !zorro.isSelected(bc.globalBC())) { + return; + } + registry.fill(HIST("hDetTrigcollisionCounter"), 1.5); // DetTrigCollAfterZorroSelection + + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hDetTrigcollisionCounter"), 2.5); // DetTrigCollWithVertexZ + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || !jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + registry.fill(HIST("hDetTrigcollisionCounter"), 3.5); // EventsNotSatisfyingEvent+TriggerSelection + return; + } + //- should this kTVX HW trigger be still in place? - Removing it for now; probably not needed if we are only interested in SW triggers + /*if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + // eventAccepted = true; + registry.fill(HIST("hDetTrigcollisionCounter"), 4.5); // EMCreadoutDetTrigEventsWithkTVXinEMC + }*/ + // split event selections based on selected triggers - + // make sure there're no trigger overlaps: when analysing JetFullHighPt-> check no JetFullLowPt and kTVXinEMC are fired + // when analysing JetFullLowPt, check kTVXinEMC isn't fired! + // apply exclusive trigger bit selections for event selection + // use a flag and fill QA for trigger overlap - + // - how often you reject a higher pT trig because lower trigs were fired : 5 cases -> 2D hist as a funtn of jet pT + // - check how often the ChJet Trigs were fired for every fullJetTrig fired.(don't reject these events but only for QA) + + // Get trigger status + bool hasFullJetHighPt = jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetFullHighPt); + bool hasFullJetLowPt = jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetFullLowPt); + bool hasMB = jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::EMCALReadout); + + //*****Step 1: Check for pure triggers (NO overlaps)***** + + // Case 1: hasFullJetHighPt && !hasFullJetLowPt && !hasMB : Pure FullJetHighPt + // i.e. for every JetFullHighPt trig that was fired, check the low triggers weren't fired + if (hasFullJetHighPt && !hasFullJetLowPt) { + registry.fill(HIST("hDetTrigcollisionCounter"), 4.5); // FullJetHighPt+FullJetLowPt + eventAccepted = true; + } + // Case 2: hasFullJetLowPt && !hasMB : Pure FullJetLowPt + // i.e. for every hasFullJetLowPt trig that was fired, check the MB trig wasn't fired + if (hasFullJetLowPt) { + registry.fill(HIST("hDetTrigcollisionCounter"), 5.5); // FullJetLowPt + eventAccepted = true; + } + // // Case 3: hasMB && !hasFullJetLowPt && !hasFullJetHighPt : Pure MB + // // i.e. for every MB trig that was fired, check the higher trigs weren't fired + // if (hasMB && !hasFullJetLowPt && !hasFullJetHighPt) { + // registry.fill(HIST("hDetTrigcollisionCounter"), 7.5); // OnlyMB + // } + + //*****Step 2: Check for trigger overlap cases (for QA):***** + + if (hasFullJetHighPt && hasFullJetLowPt) { + registry.fill(HIST("hDetTrigcollisionCounter"), 6.5); // FullJetHighPt+FullJetLowPt + eventAccepted = true; + } + if (hasFullJetHighPt && hasMB) { + registry.fill(HIST("hDetTrigcollisionCounter"), 7.5); // FullJetHighPt+MB + eventAccepted = true; + } + if (hasFullJetLowPt && hasMB) { + registry.fill(HIST("hDetTrigcollisionCounter"), 8.5); // FullJetLowPt+MB + eventAccepted = true; + } + + //*****Step 3: Reject ALL overlapping events by applying EXCLUSIVE Trigger Selections ***** + // Skip further processing if ANY overlaps exist + // if ((hasFullJetHighPt && (hasFullJetLowPt || hasMB)) || (hasFullJetLowPt && hasMB)) { + // registry.fill(HIST("hDetTrigcollisionCounter"), 11.5); // AllRejectedTrigOverlaps + // return; + // } + if ((hasFullJetHighPt && hasFullJetLowPt)) { + registry.fill(HIST("hDetTrigcollisionCounter"), 9.5); // AllRejectedTrigOverlaps + return; + } + registry.fill(HIST("hDetTrigcollisionCounter"), 10.5); // EMCAcceptedDetTrigCollAfterTrigOverlapChecks + + if (!eventAccepted) { + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax) || !isAcceptedRecoJet(jet)) { + fillRejectedJetHistograms(jet, 1.0); + } + } + registry.fill(HIST("hDetTrigcollisionCounter"), 11.5); // AllRejectedDetTrigEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hDetTrigcollisionCounter"), 12.5); // EMCAcceptedDetTrigColl + + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChLowPt)) { + registry.fill(HIST("hDetTrigcollisionCounter"), 13.5); // EMCAcceptedDetTrigCollWithLowChargedJetTriggers + eventAccepted = true; + } + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetChHighPt)) { + registry.fill(HIST("hDetTrigcollisionCounter"), 14.5); // EMCAcceptedDetTrigCollWithHighChargedJetTriggers + eventAccepted = true; + } + + if (jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetFullLowPt) && jetderiveddatautilities::selectTrigger(collision, jetderiveddatautilities::JTrigSel::JetFullHighPt)) { + registry.fill(HIST("hDetTrigcollisionCounter"), 15.5); // EMCAcceptedDetTrigCollWithLow+HighFullJetTriggers + eventAccepted = true; + } + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) { + continue; + } + if (!isAcceptedRecoJet(jet)) { + continue; + } + fillJetHistograms(jet); + } + } + PROCESS_SWITCH(FullJetSpectra, processJetsTriggeredData, "Full Jets Triggered Data", false); + + void processJetsMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, + aod::JetTracks const&, ClusterWithCorrections const&) + { + bool eventAccepted = false; + double weight = 1.0; + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + + /* if (doMcClosure) { + // Count total events processed (before splitting decision) + registry.fill(HIST("h_MCD_total_events"), 0.5); + + // DEBUG: Let's verify what collision IDs we're actually seeing + LOGF(info, "[MCD DEBUG] Processing MC collision ID: %lld", collision.mcCollisionId()); + + // Get random value for this MC collision + float eventRandomValue = getMCCollisionRandomValue(collision.mcCollisionId()); + + // MCD gets events with random value <= split fraction (20%) + if (eventRandomValue > mcClosureSplitFrac) { + LOGF(debug, "[MCD] Event REJECTED: rand = %.4f > split = %.2f (MC collision %d)", + eventRandomValue, static_cast(mcClosureSplitFrac), collision.mcCollisionId()); + return; // This event goes to MCP & Matched processes + } + + LOGF(info, "[MCD] Event ACCEPTED: rand = %.4f <= split = %.2f (MC collision %d)", + eventRandomValue, static_cast(mcClosureSplitFrac), collision.mcCollisionId()); + + registry.fill(HIST("hSpliteventSelector"), 0.5); // 20% Closure input for the measured spectra (reco) + registry.fill(HIST("h_MCD_splitevent_counter"), 0.5); +} +*/ + registry.fill(HIST("hDetcollisionCounter"), 0.5); // allDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hDetcollisionCounter"), 1.5); // DetCollWithVertexZ + + // outlier check: for every outlier jet, reject the whole event + for (auto const& jet : jets) { + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { // for MCD jets only to remove outliers; setting pTHatMaxMCD = 1 improves purity + registry.fill(HIST("hDetcollisionCounter"), 2.5); // RejectedDetCollWithOutliers + return; + } + // 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 + if (jet.pt() > 1 * pTHat) { + registry.fill(HIST("h_full_jet_pt_pTHatcut"), jet.pt(), weight); + } + } + if (doMBGapTrigger && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + registry.fill(HIST("hDetcollisionCounter"), 3.5); // MBRejectedDetEvents + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hDetcollisionCounter"), 4.5); // EventsNotSatisfyingEventSelection + return; + } + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hDetcollisionCounter"), 5.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hDetcollisionCounter"), 5.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + + if (!eventAccepted) { + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax) || !isAcceptedRecoJet(jet)) { + fillRejectedJetHistograms(jet, 1.0); + } + } + registry.fill(HIST("hDetcollisionCounter"), 6.5); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hDetcollisionCounter"), 7.5); // EMCAcceptedDetColl + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) { + continue; + } + if (!isAcceptedRecoJet(jet)) { + continue; + } + fillJetHistograms(jet); + } + } + PROCESS_SWITCH(FullJetSpectra, processJetsMCD, "Full Jets at Detector Level", false); + + void processJetsMCDWeighted(soa::Filtered::iterator const& collision, JetTableMCDWeightedJoined const& jets, aod::JMcCollisions const&, + aod::JetTracks const&, ClusterWithCorrections const&) + { + bool eventAccepted = false; + double pTHat = 10. / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); + + /* if (doMcClosure) { + // Count total events processed (before splitting decision) + registry.fill(HIST("h_MCD_total_events"), 0.5); + + // DEBUG: Let's verify what collision IDs we're actually seeing + LOGF(info, "[MCD DEBUG] Processing MC collision ID: %lld", collision.mcCollisionId()); + + // Get random value for this MC collision + float eventRandomValue = getMCCollisionRandomValue(collision.mcCollisionId()); + + // MCD gets events with random value <= split fraction (20%) + if (eventRandomValue > mcClosureSplitFrac) { + LOGF(debug, "[MCD] Event REJECTED: rand = %.4f > split = %.2f (MC collision %d)", + eventRandomValue, static_cast(mcClosureSplitFrac), collision.mcCollisionId()); + return; // This event goes to MCP & Matched processes + } + + LOGF(info, "[MCD] Event ACCEPTED: rand = %.4f <= split = %.2f (MC collision %d)", + eventRandomValue, static_cast(mcClosureSplitFrac), collision.mcCollisionId()); + + registry.fill(HIST("hSpliteventSelector"), 0.5); // 20% Closure input for the measured spectra (reco) + registry.fill(HIST("h_MCD_splitevent_counter"), 0.5); + } + */ + registry.fill(HIST("hDetcollisionCounter"), 0.5, collision.mcCollision().weight()); // allDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hDetcollisionCounter"), 1.5, collision.mcCollision().weight()); // DetCollWithVertexZ + // outlier check: for every outlier jet, reject the whole event + for (auto const& jet : jets) { + if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { // for MCD jets only to remove outliers; setting pTHatMaxMCD = 1 improves purity + registry.fill(HIST("hDetcollisionCounter"), 2.5, collision.mcCollision().weight()); // RejectedDetCollWithOutliers + return; + } + // 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 + if (jet.pt() > 1 * pTHat) { + registry.fill(HIST("h_full_jet_pt_pTHatcut"), jet.pt(), collision.mcCollision().weight()); + } + } + if (doMBGapTrigger && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + registry.fill(HIST("hDetcollisionCounter"), 3.5, collision.mcCollision().weight()); // MBRejectedDetEvents + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hDetcollisionCounter"), 4.5, collision.mcCollision().weight()); // EventsNotSatisfyingEventSelection + return; + } + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hDetcollisionCounter"), 5.5, collision.mcCollision().weight()); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hDetcollisionCounter"), 5.5, collision.mcCollision().weight()); // EMCreadoutDetEventsWithkTVXinEMC + } + } + + if (!eventAccepted) { + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax) || !isAcceptedRecoJet(jet)) { + fillRejectedJetHistograms(jet, collision.mcCollision().weight()); + } + } + registry.fill(HIST("hDetcollisionCounter"), 6.5, collision.mcCollision().weight()); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hDetcollisionCounter"), 7.5, collision.mcCollision().weight()); // EMCAcceptedDetColl + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) { + continue; + } + if (!isAcceptedRecoJet(jet)) { + continue; + } + fillJetHistograms(jet, collision.mcCollision().weight()); + } + } + PROCESS_SWITCH(FullJetSpectra, processJetsMCDWeighted, "Full Jets at Detector Level on weighted events", false); + + void processJetsMCP(aod::JetMcCollision const& mccollision, JetTableMCPJoined const& jets, aod::JetParticles const&, soa::SmallGroups const& collisions) + { + bool eventAccepted = false; + double weight = 1.0; + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + + /* if (doMcClosure) { + // Count total events processed (before splitting decision) + registry.fill(HIST("h_MCP_total_events"), 0.5); + + // DEBUG: Let's verify what collision IDs we're actually seeing + LOGF(info, "[MCP DEBUG] Processing MC collision ID: %lld", mccollision.globalIndex()); + + // Get random value for this MC collision + float eventRandomValue = getMCCollisionRandomValue(mccollision.globalIndex()); + + // DEBUG: Track which MC collisions we're processing + registry.fill(HIST("hMCCollisionIdDebug_MCP"), static_cast(mccollision.globalIndex() % 100000)); + + // MCP gets events with random value > split fraction (80%) + if (eventRandomValue <= mcClosureSplitFrac) { + LOGF(debug, "[MCP] Event REJECTED: rand = %.4f <= split = %.2f (MC collision %lld)", + eventRandomValue, static_cast(mcClosureSplitFrac), mccollision.globalIndex()); + return; // This event goes to MCD only + } + + LOGF(info, "[MCP] Event ACCEPTED: rand = %.4f > split = %.2f (MC collision %lld)", + eventRandomValue, static_cast(mcClosureSplitFrac), mccollision.globalIndex()); + + registry.fill(HIST("hSpliteventSelector"), 1.5); // remaining 80% input for MCP + registry.fill(HIST("h_MCP_splitevent_counter"), 0.5); + } + */ + registry.fill(HIST("hPartcollisionCounter"), 0.5); // allMcColl + if (std::fabs(mccollision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hPartcollisionCounter"), 1.5); // McCollWithVertexZ + + // outlier check: for every outlier jet, reject the whole event + for (auto const& jet : jets) { + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + registry.fill(HIST("hPartcollisionCounter"), 2.5); // RejectedPartCollWithOutliers + return; + } + } + + if (doMBGapTrigger && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + // Fill rejected MB events; + registry.fill(HIST("hPartcollisionCounter"), 3.5); // MBRejectedPartEvents + return; + } + + auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, mccollision.globalIndex()); + registry.fill(HIST("hRecoMatchesPerMcCollision"), collisionspermcpjet.size()); // for split vertices QA + + if (collisionspermcpjet.size() == 0 || collisionspermcpjet.size() < 1) { + registry.fill(HIST("hPartcollisionCounter"), 4.5); // RejectedPartCollForDetCollWithSize0or<1 + return; + } + registry.fill(HIST("hPartcollisionCounter"), 5.5); // AcceptedPartCollWithSize>=1 + + for (auto const& collision : collisionspermcpjet) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + continue; + } + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hPartcollisionCounter"), 6.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hPartcollisionCounter"), 6.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } + if (!eventAccepted) { + registry.fill(HIST("hPartcollisionCounter"), 7.5); // AllRejectedPartEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hPartcollisionCounter"), 8.5); // EMCAcceptedPartColl + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedPartJet(jet)) { + continue; + } + fillMCPHistograms(jet); + } + } + PROCESS_SWITCH(FullJetSpectra, processJetsMCP, "Full Jets at Particle Level", false); + + void processJetsMCPWeighted(aod::JetMcCollision const& mccollision, JetTableMCPWeightedJoined const& jets, aod::JetParticles const&, soa::SmallGroups const& collisions) + { + bool eventAccepted = false; + float pTHat = 10. / (std::pow(mccollision.weight(), 1.0 / pTHatExponent)); + + /* if (doMcClosure) { + // Count total events processed (before splitting decision) + registry.fill(HIST("h_MCP_total_events"), 0.5); + + // DEBUG: Let's verify what collision IDs we're actually seeing + LOGF(info, "[MCP DEBUG] Processing MC collision ID: %lld", mccollision.globalIndex()); + + // Get random value for this MC collision + float eventRandomValue = getMCCollisionRandomValue(mccollision.globalIndex()); + + // DEBUG: Track which MC collisions we're processing + registry.fill(HIST("hMCCollisionIdDebug_MCP"), static_cast(mccollision.globalIndex() % 100000)); + + // MCP gets events with random value > split fraction (80%) + if (eventRandomValue <= mcClosureSplitFrac) { + LOGF(debug, "[MCP] Event REJECTED: rand = %.4f <= split = %.2f (MC collision %lld)", + eventRandomValue, static_cast(mcClosureSplitFrac), mccollision.globalIndex()); + return; // This event goes to MCD only + } + + LOGF(info, "[MCP] Event ACCEPTED: rand = %.4f > split = %.2f (MC collision %lld)", + eventRandomValue, static_cast(mcClosureSplitFrac), mccollision.globalIndex()); + + registry.fill(HIST("hSpliteventSelector"), 1.5); // remaining 80% input for MCP + registry.fill(HIST("h_MCP_splitevent_counter"), 0.5); + } + */ + registry.fill(HIST("hPartcollisionCounter"), 0.5, mccollision.weight()); // allMcColl + if (std::fabs(mccollision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hPartcollisionCounter"), 1.5, mccollision.weight()); // McCollWithVertexZ + + // outlier check: for every outlier jet, reject the whole event + for (auto const& jet : jets) { + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + registry.fill(HIST("hPartcollisionCounter"), 2.5, mccollision.weight()); // RejectedPartCollWithOutliers + return; + } + } + + if (doMBGapTrigger && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + // Fill rejected MB events + registry.fill(HIST("hPartcollisionCounter"), 3.5, mccollision.weight()); // MBRejectedPartEvents + return; + } + + auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, mccollision.globalIndex()); + registry.fill(HIST("hRecoMatchesPerMcCollision"), collisionspermcpjet.size(), mccollision.weight()); // for split vertices QA + + if (collisionspermcpjet.size() == 0 || collisionspermcpjet.size() < 1) { + registry.fill(HIST("hPartcollisionCounter"), 4.5, mccollision.weight()); // RejectedPartCollForDetCollWithSize0or<1 + return; + } + registry.fill(HIST("hPartcollisionCounter"), 5.5, mccollision.weight()); // AcceptedPartCollWithSize>=1 + + for (auto const& collision : collisionspermcpjet) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + continue; + } + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hPartcollisionCounter"), 6.5, mccollision.weight()); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hPartcollisionCounter"), 6.5, mccollision.weight()); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } + if (!eventAccepted) { + registry.fill(HIST("hPartcollisionCounter"), 7.5, mccollision.weight()); // AllRejectedPartEventsAfterEMCEventSelection + return; + } + // Fill EMCAL JJ Part events + registry.fill(HIST("hPartcollisionCounter"), 8.5, mccollision.weight()); // EMCAcceptedWeightedPartColl + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + return; + } + if (!isAcceptedPartJet(jet)) { + return; + } + if (doMBGapTrigger && jet.eventWeight() == 1) { + return; + } + fillMCPHistograms(jet, jet.eventWeight()); + } + } + PROCESS_SWITCH(FullJetSpectra, processJetsMCPWeighted, "Full Jets at Particle Level on weighted events", false); + + void processJetsMCPMCDMatched(soa::Filtered::iterator const& collision, JetTableMCDMatchedJoined const& mcdjets, jetMcpPerMcCollision const& mcpjets, aod::JMcCollisions const&, + aod::JetTracks const&, ClusterWithCorrections const&, aod::JetParticles const&) + { + bool eventAccepted = false; + int fakeMcdJet = 0; + int fakeMcpJet = 0; + double weight = 1.0; + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + const auto mcpJetsPerMcCollision = mcpjets.sliceBy(JetMCPPerMcCollision, collision.mcCollisionId()); + + /* if (doMcClosure) { + // Count total events processed (before splitting decision) + registry.fill(HIST("h_Matched_total_events"), 0.5); + + // Use consistent MC collision ID - same as MCD + int64_t mcCollisionId = collision.mcCollisionId(); + + // DEBUG: Let's verify what collision IDs we're actually seeing + LOGF(info, "[Matched DEBUG] Processing MC collision ID: %lld", mcCollisionId); + float eventRandomValue = getMCCollisionRandomValue(mcCollisionId); + + // Matched gets events with random value > split fraction (80%) - same as MCP + if (eventRandomValue <= mcClosureSplitFrac) { + LOGF(debug, "[Matched] Event REJECTED: rand = %.4f <= split = %.2f (MC collision %lld)", + eventRandomValue, static_cast(mcClosureSplitFrac), mcCollisionId); + return; // This event goes to MCD only + } + + LOGF(info, "[Matched] Event ACCEPTED: rand = %.4f > split = %.2f (MC collision %lld)", + eventRandomValue, static_cast(mcClosureSplitFrac), mcCollisionId); + + registry.fill(HIST("hSpliteventSelector"), 2.5); // Bin for Response Matrix + registry.fill(HIST("h_Matched_splitevent_counter"), 0.5); + } + */ + registry.fill(HIST("hMatchedcollisionCounter"), 0.5); // allDetColl + + if (std::fabs(collision.posZ()) > vertexZCut) { // making double sure this condition is satisfied + return; + } + registry.fill(HIST("hMatchedcollisionCounter"), 1.5); // DetCollWithVertexZ + + // outlier check: for every outlier jet, reject the whole event + for (auto const& mcdjet : mcdjets) { + if (mcdjet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { + registry.fill(HIST("hMatchedcollisionCounter"), 2.5); // RejectedDetCollWithOutliers + return; + } + } + // //outlier check for Part collisions: commenting out this for now otherwise this rejects all Det Colls + // for (auto const& mcpjet : mcpjets) { + // if (mcpjet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + // registry.fill(HIST("hMatchedcollisionCounter"),3.5); //RejectedPartCollWithOutliers + // return; + // } + // } + + if (doMBGapTrigger && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + registry.fill(HIST("hMatchedcollisionCounter"), 4.5); // EMCMBRejectedDetColl + return; + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hMatchedcollisionCounter"), 5.5); // EventsNotSatisfyingEventSelection + return; + } + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hMatchedcollisionCounter"), 6.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hMatchedcollisionCounter"), 6.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + if (!eventAccepted) { + registry.fill(HIST("hMatchedcollisionCounter"), 7.5); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hMatchedcollisionCounter"), 8.5); // EMCAcceptedDetColl + + for (const auto& mcdjet : mcdjets) { + if (!isAcceptedRecoJet(mcdjet)) { + continue; + } + 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("h2_full_fakemcdjets"), mcdjet.pt(), fakeMcdJet, 1.0); + continue; + } + + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + if (!isAcceptedPartJet(mcpjet)) { + return; + } + // 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("h2_full_fakemcpjets"), mcpjet.pt(), fakeMcpJet, 1.0); + continue; + } + } // mcpjet loop + fillMatchedHistograms(mcdjet); + } // mcdjet loop + } + PROCESS_SWITCH(FullJetSpectra, 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&, ClusterWithCorrections const&, aod::JetParticles const&) + { + bool eventAccepted = false; + int fakeMcdJet = 0; + int fakeMcpJet = 0; + int NPartJetFid = 0; + float eventWeight = collision.mcCollision().weight(); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + const auto mcpJetsPerMcCollision = mcpjets.sliceBy(JetMCPPerMcCollision, collision.mcCollisionId()); + + /* if (doMcClosure) { + // Count total events processed (before splitting decision) + registry.fill(HIST("h_Matched_total_events"), 0.5); + + // Use consistent MC collision ID - same as MCD + int64_t mcCollisionId = collision.mcCollisionId(); + + // DEBUG: Let's verify what collision IDs we're actually seeing + LOGF(info, "[Matched DEBUG] Processing MC collision ID: %lld", mcCollisionId); + float eventRandomValue = getMCCollisionRandomValue(mcCollisionId); + + // Matched gets events with random value > split fraction (80%) - same as MCP + if (eventRandomValue <= mcClosureSplitFrac) { + LOGF(debug, "[Matched] Event REJECTED: rand = %.4f <= split = %.2f (MC collision %lld)", + eventRandomValue, static_cast(mcClosureSplitFrac), mcCollisionId); + return; // This event goes to MCD only + } + + LOGF(info, "[Matched] Event ACCEPTED: rand = %.4f > split = %.2f (MC collision %lld)", + eventRandomValue, static_cast(mcClosureSplitFrac), mcCollisionId); + + registry.fill(HIST("hSpliteventSelector"), 2.5); // Bin for Response Matrix + registry.fill(HIST("h_Matched_splitevent_counter"), 0.5); + } + */ + registry.fill(HIST("hMatchedcollisionCounter"), 0.5, eventWeight); // allDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { // making double sure this condition is satisfied + return; + } + registry.fill(HIST("hMatchedcollisionCounter"), 1.5, eventWeight); // DetCollWithVertexZ + + // outlier check: for every outlier jet, reject the whole event + for (auto const& mcdjet : mcdjets) { + if (mcdjet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { + registry.fill(HIST("hMatchedcollisionCounter"), 2.5, eventWeight); // RejectedDetCollWithOutliers + return; + } + } + // outlier check for Part collisions: commenting out this for now otherwise this rejects all Det Colls + // for (auto const& mcpjet : mcpjets) { + // if (mcpjet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + // registry.fill(HIST("hMatchedcollisionCounter"),3.5, eventWeight); //RejectedPartCollWithOutliers + // return; + // } + // } + + if (doMBGapTrigger && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + registry.fill(HIST("hMatchedcollisionCounter"), 4.5, eventWeight); // EMCMBRejectedDetColl + return; + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hMatchedcollisionCounter"), 5.5, eventWeight); // EventsNotSatisfyingEventSelection + return; + } + + for (auto const& mcpjet : mcpJetsPerMcCollision) { + if (mcpjet.pt() > pTHatMaxMCP * pTHat) { // outlier rejection for MCP: Should I remove this cut as I'm already doing MC outlier rejection @L1071? + return; + } + } + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hMatchedcollisionCounter"), 6.5, eventWeight); // EMCreadoutDetJJEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hMatchedcollisionCounter"), 6.5, eventWeight); // EMCreadoutDetJJEventsWithkTVXinEMC + } + } + if (!eventAccepted) { + registry.fill(HIST("hMatchedcollisionCounter"), 7.5, eventWeight); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hMatchedcollisionCounter"), 8.5, eventWeight); // EMCAcceptedDetColl + + for (const auto& mcdjet : mcdjets) { + if (!isAcceptedRecoJet(mcdjet)) { + 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("h2_full_fakemcdjets"), mcdjet.pt(), fakeMcdJet, eventWeight); + continue; + } + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + if (!isAcceptedPartJet(mcpjet)) { + return; + } + // apply emcal fiducial cuts to the matched particle level jets - if the matched mcp jet lies outside of the EMCAL fiducial, flag it as a fake jet + if (mcpjet.eta() > jetEtaMax || mcpjet.eta() < jetEtaMin || mcpjet.phi() > jetPhiMax || mcpjet.phi() < jetPhiMin) { + fakeMcpJet++; + registry.fill(HIST("h2_full_fakemcpjets"), mcpjet.pt(), fakeMcpJet, eventWeight); + continue; + } else { + NPartJetFid++; + // // If both MCD-MCP matched jet pairs are within the EMCAL fiducial region, fill these histos + registry.fill(HIST("h2_full_matchedmcpjet_pt"), mcpjet.pt(), NPartJetFid, eventWeight); + registry.fill(HIST("h_full_matchedmcpjet_eta"), mcpjet.eta(), eventWeight); + registry.fill(HIST("h_full_matchedmcpjet_phi"), mcpjet.phi(), eventWeight); + } + } // mcpjet + fillMatchedHistograms(mcdjet, eventWeight); + } // mcdjet + } + PROCESS_SWITCH(FullJetSpectra, processJetsMCPMCDMatchedWeighted, "Full Jet finder MCP matched to MCD on weighted events", false); + + // Periodic cleanup to prevent unbounded memory growth + /*void processCleanup(aod::Collision const&) { + static int callCount = 0; + callCount++; + + // Clean up cache every 50000 calls to prevent memory issues + if (doMcClosure && callCount % 50000 == 0 && mcCollisionRandomValues.size() > 20000) { + LOGF(info, "Cleaning up MC collision random values cache (size: %zu)", mcCollisionRandomValues.size()); + mcCollisionRandomValues.clear(); + + // IMPROVEMENT: Add logging to verify our split ratios + float mcdCount = registry.get(HIST("h_MCD_splitevent_counter"))->GetBinContent(1); + float mcpCount = registry.get(HIST("h_MCP_splitevent_counter"))->GetBinContent(1); + float matchedCount = registry.get(HIST("h_Matched_splitevent_counter"))->GetBinContent(1); + + float totalEvents = mcdCount + mcpCount; // MCP and Matched should be the same, so don't double count + float actualSplitFrac = totalEvents > 0 ? mcdCount / totalEvents : 0.0f; + + LOGF(info, "Current split statistics: MCD=%.1f, MCP=%.1f, Matched=%.1f", mcdCount, mcpCount, matchedCount); + LOGF(info, "Actual split fraction: %.3f (target: %.3f)", actualSplitFrac, static_cast(mcClosureSplitFrac)); + } + } + PROCESS_SWITCH(FullJetSpectra, processCleanup, "Periodic cleanup", true); + */ + void processDataTracks(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, + ClusterWithCorrections const& clusters) // replaced "soa::Filtered" with ClusterWithCorrections to include the hadcorr tables + { + bool eventAccepted = false; + + registry.fill(HIST("hCollisionsUnweighted"), 0.5); // allDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hCollisionsUnweighted"), 1.5); // DetCollWithVertexZ + + if (doMBGapTrigger && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + registry.fill(HIST("hCollisionsUnweighted"), 2.5); // MBRejectedDetEvents + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hCollisionsUnweighted"), 3.5); // EventsNotSatisfyingEventSelection + 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 + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hCollisionsUnweighted"), 4.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } 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("hCollisionsUnweighted"), 4.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("hCollisionsUnweighted"), 5.5); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hCollisionsUnweighted"), 6.5); // EMCAcceptedDetColl + + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + } + fillTrackHistograms(tracks, clusters, 1.0); + registry.fill(HIST("hCollisionsUnweighted"), 7.5); // EMCAcceptedCollAfterTrackSel + } + PROCESS_SWITCH(FullJetSpectra, processDataTracks, "Full Jet tracks for Data", false); + + void processMCTracks(soa::Filtered::iterator const& collision, soa::Filtered const& tracks, soa::Filtered const& clusters) + { + bool eventAccepted = false; + double weight = 1.0; + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + + registry.fill(HIST("hCollisionsUnweighted"), 0.5); // allDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hCollisionsUnweighted"), 1.5); // DetCollWithVertexZ + + // for (auto const& track : tracks) { + if (pTHat < pTHatAbsoluteMin) { // Track outlier rejection: should this be for every track iteration or for every collision? + return; + } + // } + if (doMBGapTrigger && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + registry.fill(HIST("hCollisionsUnweighted"), 2.5); // MBRejectedDetEvents + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hCollisionsUnweighted"), 3.5); // EventsNotSatisfyingEventSelection + return; + } + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hCollisionsUnweighted"), 4.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hCollisionsUnweighted"), 4.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("hCollisionsUnweighted"), 5.5); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hCollisionsUnweighted"), 6.5); // EMCAcceptedDetColl + + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + } + fillTrackHistograms(tracks, clusters, 1.0); + registry.fill(HIST("hCollisionsUnweighted"), 7.5); // EMCAcceptedCollAfterTrackSel + } + PROCESS_SWITCH(FullJetSpectra, processMCTracks, "Full Jet tracks for MC", 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(); + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + + registry.fill(HIST("hCollisionsWeighted"), 0.5, eventWeight); // AllWeightedDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hCollisionsWeighted"), 1.5, eventWeight); // WeightedCollWithVertexZ + + if (pTHat < pTHatAbsoluteMin) { // Track outlier rejection: should this be for every track iteration or for every collision? + return; + } + + if (doMBGapTrigger && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + registry.fill(HIST("hCollisionsWeighted"), 2.5, eventWeight); // MBRejectedDetEvents + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hCollisionsWeighted"), 3.5, eventWeight); // EventsNotSatisfyingEventSelection + return; + } + if (doMBGapTrigger && eventWeight == 1) { + registry.fill(HIST("hCollisionsWeighted"), 2.5, eventWeight); // MBRejectedDetEvents + return; + } + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + fillTrackHistograms(tracks, clusters, eventWeight); + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hCollisionsWeighted"), 4.5, eventWeight); // EMCreadoutDetJJEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hCollisionsWeighted"), 4.5, eventWeight); // EMCreadoutDetJJEventsWithkTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("hCollisionsWeighted"), 5.5, eventWeight); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hCollisionsWeighted"), 6.5); // EMCAcceptedWeightedDetColl + + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + } + fillTrackHistograms(tracks, clusters, eventWeight); + registry.fill(HIST("hCollisionsWeighted"), 7.5, eventWeight); // EMCAcceptedWeightedCollAfterTrackSel + } + PROCESS_SWITCH(FullJetSpectra, processTracksWeighted, "Full Jet tracks weighted", false); + + void processMBCollisionsDATAWithMultiplicity(soa::Filtered::iterator const& collision, + FullJetTableDataJoined const& jets, aod::JetTracks const& /*tracks*/, ClusterWithCorrections const& /*clusters*/) + { + bool eventAccepted = false; + + registry.fill(HIST("hEventmultiplicityCounter"), 0.5); // allDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hEventmultiplicityCounter"), 1.5); // DetCollWithVertexZ + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hEventmultiplicityCounter"), 2.5); // EventsNotSatisfyingEventSelection + return; + } + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hEventmultiplicityCounter"), 3.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hEventmultiplicityCounter"), 3.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("hEventmultiplicityCounter"), 4.5); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hEventmultiplicityCounter"), 5.5); // EMCAcceptedDetColl + + registry.fill(HIST("h_FT0Mults_occupancy"), collision.multFT0M()); + + // Jet processing - NEW IMPLEMENTATION + std::vector::iterator> selectedJets; + // static int eventCounter = 0; + int nJetsThisEvent = 0; + // Debug output + // std::cout << "===== Event " << ++eventCounter << " (Collision ID: " << collision.globalIndex() << ") =====" << std::endl; + + // Verify jet-collision association + for (auto const& jet : jets) { + if (jet.collisionId() != collision.globalIndex()) { + LOGF(warn, "Jet with pT %.2f belongs to collision %d but processing collision %d", jet.pt(), jet.collisionId(), collision.globalIndex()); + continue; + } + + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) + continue; + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) + continue; + if (!isAcceptedRecoJet(jet)) + continue; + + selectedJets.push_back(jet); + nJetsThisEvent++; + // std::cout << "Selected jet pT: " << jet.pt() << " (collision ID: " << jet.collisionId() << ")" << std::endl; + } + // 1. Sort selected jets by pT before processing + std::sort(selectedJets.begin(), selectedJets.end(), + [](auto const& a, auto const& b) { return (*a).pt() > (*b).pt(); }); + + // std::cout << "Number of selected jets: " << selectedJets.size() << std::endl; + + // // 2. Reset counters for each event + // int numberOfChargedParticles = 0; + // int totalNumberOfChargedParticles = 0; + // int leadingJetCount = 0; + // + // std::cout << "Number of selected jets per event: " << selectedJets.size() << std::endl; + // for (const auto& jetIter : selectedJets) { + // std::cout << "Jet pT of selectedJets: " << (*jetIter).pt() << std::endl; + // } + // //Checking Event Counter + // static int eventCounter = 0; + // std::cout << "===== Event " << ++eventCounter << " =====" << std::endl; + // std::cout << "******************************************** " << std::endl; + if (selectedJets.size() == 0) { // no jets = no leading jet + return; + } else { + // Jet multiplicity per event + registry.fill(HIST("h_all_fulljet_Njets"), selectedJets.size(), 1.0); + + // Select Leading Jet for N_ch calculation (for every leading jet that is found). There's always one leading jet per event! + auto const& leadingJet = *selectedJets[0]; + auto const& leadingJetPt = leadingJet.pt(); // jet pT distribution of the leading jet + // std::cout << "Leading Jet pT: " << leadingJetPt << std::endl; + registry.fill(HIST("h_Leading_full_jet_pt"), leadingJetPt, 1.0); + registry.fill(HIST("h2_full_jet_leadingJetPt_vs_counts"), leadingJetPt, nJetsThisEvent, 1.0); + } + + if (selectedJets.size() > 1) { + auto const& subLeadingJet = *selectedJets[1]; + auto const& subLeadingJetPt = subLeadingJet.pt(); // jet pT distribution of the subleading jet i.e. 2nd leading jet + registry.fill(HIST("h_SubLeading_full_jet_pt"), subLeadingJetPt, 1.0); + registry.fill(HIST("h2_full_jet_subLeadingJetPt_vs_counts"), subLeadingJetPt, nJetsThisEvent, 1.0); + } + // Process ALL selected jets (not just leading) + for (size_t i = 0; i < selectedJets.size(); i++) { + auto const& jet = *selectedJets[i]; + float jetPt = jet.pt(); + bool isLeading = (i == 0); + bool isSubLeading = (i == 1 && selectedJets.size() > 1); // first sub-leading jet + + // Count charged particles(NCh) for this jet + int numberOfChargedParticles = 0; + for (const auto& jettrack : jet.tracks_as()) { + if (jetderiveddatautilities::selectTrack(jettrack, trackSelection)) { + numberOfChargedParticles++; + } else { + continue; + } + } + + // Calculate neutral energy fraction for this jet + // float neutralEnergy = 0.0; + double neutralEnergy_uncorr = 0.0; + double neutralEnergy_corr_oneTrack100 = 0.0; + double neutralEnergy_corr_oneTrack70 = 0.0; + double neutralEnergy_corr_allTracks100 = 0.0; + double neutralEnergy_corr_allTracks70 = 0.0; + + for (const auto& jetcluster : jet.clusters_as()) { + // Sum energies for NEF calculation for each correction mode + neutralEnergy_uncorr += jetcluster.energy(); + neutralEnergy_corr_oneTrack100 += jetcluster.energyCorrectedOneTrack1(); + neutralEnergy_corr_oneTrack70 += jetcluster.energyCorrectedOneTrack2(); + neutralEnergy_corr_allTracks100 += jetcluster.energyCorrectedAllTracks1(); + neutralEnergy_corr_allTracks70 += jetcluster.energyCorrectedAllTracks2(); + } + auto jetEnergy = jet.energy(); + + auto nef_uncorr = neutralEnergy_uncorr / jetEnergy; + auto nef_corr_oneTrack100 = neutralEnergy_corr_oneTrack100 / jetEnergy; + auto nef_corr_oneTrack70 = neutralEnergy_corr_oneTrack70 / jetEnergy; + auto nef_corr_allTracks100 = neutralEnergy_corr_allTracks100 / jetEnergy; + auto nef_corr_allTracks70 = neutralEnergy_corr_allTracks70 / jetEnergy; + + // CASE 1: Fill histograms for ALL selected jets + registry.fill(HIST("h_all_fulljet_pt"), jetPt, 1.0); + registry.fill(HIST("h_all_fulljet_Nch"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_all_fulljet_NEF_uncorr"), nef_uncorr, 1.0); + registry.fill(HIST("h_all_fulljet_NEF_corr_oneTrack100"), nef_corr_oneTrack100, 1.0); + registry.fill(HIST("h_all_fulljet_NEF_corr_oneTrack70"), nef_corr_oneTrack70, 1.0); + registry.fill(HIST("h_all_fulljet_NEF_corr_allTracks100"), nef_corr_allTracks100, 1.0); + registry.fill(HIST("h_all_fulljet_NEF_corr_allTracks70"), nef_corr_allTracks70, 1.0); + + registry.fill(HIST("h2_all_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), 1.0); + registry.fill(HIST("h2_all_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_full_jet_jetpTDet_FT0Mults_nef_uncorr"), jetPt, collision.multFT0M(), nef_uncorr, 1.0); + registry.fill(HIST("h3_full_jet_jetpTDet_FT0Mults_nef_corr_oneTrack100"), jetPt, collision.multFT0M(), nef_corr_oneTrack100, 1.0); + registry.fill(HIST("h3_full_jet_jetpTDet_FT0Mults_nef_corr_oneTrack70"), jetPt, collision.multFT0M(), nef_corr_oneTrack70, 1.0); + registry.fill(HIST("h3_full_jet_jetpTDet_FT0Mults_nef_corr_allTracks100"), jetPt, collision.multFT0M(), nef_corr_allTracks100, 1.0); + registry.fill(HIST("h3_full_jet_jetpTDet_FT0Mults_nef_corr_allTracks70"), jetPt, collision.multFT0M(), nef_corr_allTracks70, 1.0); + + // CASE 2: Additional leading jet processing + if (isLeading) { + registry.fill(HIST("h_leading_fulljet_pt"), jetPt, 1.0); + registry.fill(HIST("h_leading_fulljet_Nch"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_leading_fulljet_NEF"), nef_uncorr, 1.0); + registry.fill(HIST("h2_leading_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), 1.0); + registry.fill(HIST("h2_leading_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_leading_fulljet_jetpTDet_FT0Mults_nef"), jetPt, collision.multFT0M(), nef_uncorr, 1.0); + } + + // CASE 3: Additional first sub-leading jet processing + if (isSubLeading) { + registry.fill(HIST("h_subleading_fulljet_pt"), jetPt, 1.0); + registry.fill(HIST("h_subleading_fulljet_Nch"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_subleading_fulljet_NEF"), nef_uncorr, 1.0); + registry.fill(HIST("h2_subleading_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), 1.0); + registry.fill(HIST("h2_subleading_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_subleading_fulljet_jetpTDet_FT0Mults_nef"), jetPt, collision.multFT0M(), nef_uncorr, 1.0); + } + } + } + PROCESS_SWITCH(FullJetSpectra, processMBCollisionsDATAWithMultiplicity, "MB DATA Collisions for Full Jets Multiplicity Studies", false); + + void processMBMCDCollisionsWithMultiplicity(soa::Filtered::iterator const& collision, JetTableMCDJoined const& mcdjets, aod::JMcCollisions const&, aod::JetTracks const& /*tracks*/, ClusterWithCorrections const& /*clusters*/) + { + bool eventAccepted = false; + + registry.fill(HIST("hEventmultiplicityCounter"), 0.5); // allDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hEventmultiplicityCounter"), 1.5); // DetCollWithVertexZ + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hEventmultiplicityCounter"), 2.5); // EventsNotSatisfyingEventSelection + return; + } + + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + eventAccepted = true; + // fillTrackHistograms(tracks, clusters, 1.0); + if (collision.alias_bit(kTVXinEMC)) { + registry.fill(HIST("hEventmultiplicityCounter"), 3.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hEventmultiplicityCounter"), 3.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("hEventmultiplicityCounter"), 4.5); // AllRejectedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hEventmultiplicityCounter"), 5.5); // EMCAcceptedDetColl + + registry.fill(HIST("h_FT0Mults_occupancy"), collision.multFT0M()); + + std::vector::iterator> selectedJets; + // static int eventCounter = 0; + int nJetsThisEvent = 0; + // Debug output + // std::cout << "===== Event " << ++eventCounter << " (Collision ID: " << collision.globalIndex() << ") =====" << std::endl; + + // Verify jet-collision association + for (auto const& mcdjet : mcdjets) { + if (mcdjet.collisionId() != collision.globalIndex()) { + LOGF(warn, "Jet with pT %.2f belongs to collision %d but processing collision %d", mcdjet.pt(), mcdjet.collisionId(), collision.globalIndex()); + continue; + } + + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) + continue; + if (mcdjet.phi() < jetPhiMin || mcdjet.phi() > jetPhiMax) + continue; + if (!isAcceptedRecoJet(mcdjet)) + continue; + + selectedJets.push_back(mcdjet); + nJetsThisEvent++; + // std::cout << "Selected jet pT: " << jet.pt() << " (collision ID: " << jet.collisionId() << ")" << std::endl; + } + // 1. Sort selected jets by pT before processing + std::sort(selectedJets.begin(), selectedJets.end(), + [](auto const& a, auto const& b) { return (*a).pt() > (*b).pt(); }); + + if (selectedJets.size() == 0) { // no jets = no leading jet + return; + } else { + // Jet multiplicity per event + registry.fill(HIST("h_all_fulljet_Njets"), selectedJets.size(), 1.0); + + // Select Leading Jet for N_ch calculation (for every leading jet that is found). There's always one leading jet per event! + auto const& leadingJet = *selectedJets[0]; + auto const& leadingJetPt = leadingJet.pt(); // jet pT distribution of the leading jet + // std::cout << "Leading Jet pT: " << leadingJetPt << std::endl; + registry.fill(HIST("h_Leading_full_jet_pt"), leadingJetPt, 1.0); + registry.fill(HIST("h2_full_jet_leadingJetPt_vs_counts"), leadingJetPt, nJetsThisEvent, 1.0); + } + + if (selectedJets.size() > 1) { + auto const& subLeadingJet = *selectedJets[1]; + auto const& subLeadingJetPt = subLeadingJet.pt(); // jet pT distribution of the subleading jet i.e. 2nd leading jet + registry.fill(HIST("h_SubLeading_full_jet_pt"), subLeadingJetPt, 1.0); + registry.fill(HIST("h2_full_jet_subLeadingJetPt_vs_counts"), subLeadingJetPt, nJetsThisEvent, 1.0); + } + // Process ALL selected jets (not just leading) + for (size_t i = 0; i < selectedJets.size(); i++) { + auto const& jet = *selectedJets[i]; + float jetPt = jet.pt(); + bool isLeading = (i == 0); + bool isSubLeading = (i == 1 && selectedJets.size() > 1); // first sub-leading jet + + // Count charged particles(NCh) for this jet + int numberOfChargedParticles = 0; + for (const auto& jettrack : jet.tracks_as()) { + if (jetderiveddatautilities::selectTrack(jettrack, trackSelection)) { + numberOfChargedParticles++; + } else { + continue; + } + } + + // Calculate neutral energy fraction for this jet + float neutralEnergy = 0.0; + for (const auto& jetcluster : jet.clusters_as()) { + neutralEnergy += jetcluster.energy(); + } + float nef = neutralEnergy / jet.energy(); + + // CASE 1: Fill histograms for ALL selected jets + registry.fill(HIST("h_all_fulljet_pt"), jetPt, 1.0); + registry.fill(HIST("h_all_fulljet_Nch"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_all_fulljet_NEF"), nef, 1.0); + registry.fill(HIST("h2_all_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), 1.0); + registry.fill(HIST("h2_all_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_full_jet_jetpTDet_FT0Mults_nef"), jetPt, collision.multFT0M(), nef, 1.0); + + // CASE 2: Additional leading jet processing + if (isLeading) { + registry.fill(HIST("h_leading_fulljet_pt"), jetPt, 1.0); + registry.fill(HIST("h_leading_fulljet_Nch"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_leading_fulljet_NEF"), nef, 1.0); + registry.fill(HIST("h2_leading_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), 1.0); + registry.fill(HIST("h2_leading_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_leading_fulljet_jetpTDet_FT0Mults_nef"), jetPt, collision.multFT0M(), nef, 1.0); + } + + // CASE 3: Additional first sub-leading jet processing + if (isSubLeading) { + registry.fill(HIST("h_subleading_fulljet_pt"), jetPt, 1.0); + registry.fill(HIST("h_subleading_fulljet_Nch"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_subleading_fulljet_NEF"), nef, 1.0); + registry.fill(HIST("h2_subleading_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), 1.0); + registry.fill(HIST("h2_subleading_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_subleading_fulljet_jetpTDet_FT0Mults_nef"), jetPt, collision.multFT0M(), nef, 1.0); + } + } + } + PROCESS_SWITCH(FullJetSpectra, processMBMCDCollisionsWithMultiplicity, "MB MCD Collisions for Full Jets Multiplicity Studies", false); + + void processMCDCollisionsWeightedWithMultiplicity(soa::Filtered::iterator const& collision, JetTableMCDWeightedJoined const& mcdjets, aod::JMcCollisions const&, aod::JetTracks const& tracks, ClusterWithCorrections const& clusters) + { + bool eventAccepted = false; + float eventWeight = collision.mcCollision().weight(); + + registry.fill(HIST("hEventmultiplicityCounter"), 0.5, eventWeight); // allWeightedDetColl + if (std::fabs(collision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hEventmultiplicityCounter"), 1.5, eventWeight); // WeightedDetCollWithVertexZ + + if (doMBGapTrigger && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + registry.fill(HIST("hEventmultiplicityCounter"), 2.5, eventWeight); // MBRejectedDetEvents + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + registry.fill(HIST("hEventmultiplicityCounter"), 3.5, eventWeight); // WeightedEventsNotSatisfyingEventSelection + return; + } + if (doMBGapTrigger && eventWeight == 1) { + registry.fill(HIST("hEventmultiplicityCounter"), 2.5, eventWeight); // MBRejectedDetEvents + return; + } + + 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("hEventmultiplicityCounter"), 4.5, eventWeight); // EMCreadoutWeightedDetJJEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hEventmultiplicityCounter"), 4.5, eventWeight); // EMCreadoutWeightedDetJJEventsWithkTVXinEMC + } + } + + if (!eventAccepted) { + registry.fill(HIST("hEventmultiplicityCounter"), 5.5, eventWeight); // AllRejectedWeightedDetEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hEventmultiplicityCounter"), 6.5, eventWeight); // EMCAcceptedWeightedDetColl + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + } + registry.fill(HIST("hEventmultiplicityCounter"), 7.5, eventWeight); // EMCAcceptedWeightedCollAfterTrackSel + + registry.fill(HIST("h_FT0Mults_occupancy"), collision.multFT0M(), eventWeight); + + std::vector::iterator> selectedJets; + int nJetsThisEvent = 0; + + for (auto const& mcdjet : mcdjets) { + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + + if (mcdjet.collisionId() != collision.globalIndex()) { + LOGF(warn, "Jet with pT %.2f belongs to collision %d but processing collision %d", mcdjet.pt(), mcdjet.collisionId(), collision.globalIndex()); + continue; + } + + if (mcdjet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { // MCD jets outlier rejection + return; + } + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (mcdjet.phi() < jetPhiMin || mcdjet.phi() > jetPhiMax) { + continue; + } + if (!isAcceptedRecoJet(mcdjet)) { + continue; + } + selectedJets.push_back(mcdjet); + nJetsThisEvent++; + } + // 1. Sort selected jets by pT before processing + std::sort(selectedJets.begin(), selectedJets.end(), + [](auto const& a, auto const& b) { return (*a).pt() > (*b).pt(); }); + + if (selectedJets.size() == 0) { // no jets = no leading jet + return; + } else { + // Jet multiplicity per event + registry.fill(HIST("h_all_fulljet_Njets"), selectedJets.size(), eventWeight); + + // Select Leading Jet for N_ch calculation (for every leading jet that is found). There's always one leading jet per event! + auto const& leadingJet = *selectedJets[0]; + auto const& leadingJetPt = leadingJet.pt(); // jet pT distribution of the leading jet + registry.fill(HIST("h_Leading_full_jet_pt"), leadingJetPt, eventWeight); + registry.fill(HIST("h2_full_jet_leadingJetPt_vs_counts"), leadingJetPt, nJetsThisEvent, eventWeight); + } + + if (selectedJets.size() > 1) { + auto const& subLeadingJet = *selectedJets[1]; + auto const& subLeadingJetPt = subLeadingJet.pt(); // jet pT distribution of the subleading jet i.e. 2nd leading jet + registry.fill(HIST("h_SubLeading_full_jet_pt"), subLeadingJetPt, eventWeight); + registry.fill(HIST("h2_full_jet_subLeadingJetPt_vs_counts"), subLeadingJetPt, nJetsThisEvent, eventWeight); + } + // Process ALL selected jets (not just leading) + for (size_t i = 0; i < selectedJets.size(); i++) { + auto const& jet = *selectedJets[i]; + float jetPt = jet.pt(); + bool isLeading = (i == 0); + bool isSubLeading = (i == 1 && selectedJets.size() > 1); // first sub-leading jet + + // Count charged particles(NCh) for this jet + int numberOfChargedParticles = 0; + for (const auto& jettrack : jet.tracks_as()) { + if (jetderiveddatautilities::selectTrack(jettrack, trackSelection)) { + numberOfChargedParticles++; + } else { + continue; + } + } + + // Calculate neutral energy fraction for this jet + float neutralEnergy = 0.0; + for (const auto& jetcluster : jet.clusters_as()) { + neutralEnergy += jetcluster.energy(); + } + float nef = neutralEnergy / jet.energy(); + + // CASE 1: Fill histograms for ALL selected jets + registry.fill(HIST("h_all_fulljet_pt"), jetPt, eventWeight); + registry.fill(HIST("h_all_fulljet_Nch"), numberOfChargedParticles, eventWeight); + registry.fill(HIST("h_all_fulljet_NEF"), nef, eventWeight); + registry.fill(HIST("h2_all_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), eventWeight); + registry.fill(HIST("h2_all_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, eventWeight); + registry.fill(HIST("h3_full_jet_jetpTDet_FT0Mults_nef"), jetPt, collision.multFT0M(), nef, eventWeight); + + // CASE 2: Additional leading jet processing + if (isLeading) { + registry.fill(HIST("h_leading_fulljet_pt"), jetPt, eventWeight); + registry.fill(HIST("h_leading_fulljet_Nch"), numberOfChargedParticles, eventWeight); + registry.fill(HIST("h_leading_fulljet_NEF"), nef, eventWeight); + registry.fill(HIST("h2_leading_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), eventWeight); + registry.fill(HIST("h2_leading_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, eventWeight); + registry.fill(HIST("h3_leading_fulljet_jetpTDet_FT0Mults_nef"), jetPt, collision.multFT0M(), nef, eventWeight); + } + + // CASE 3: Additional first sub-leading jet processing + if (isSubLeading) { + registry.fill(HIST("h_subleading_fulljet_pt"), jetPt, eventWeight); + registry.fill(HIST("h_subleading_fulljet_Nch"), numberOfChargedParticles, eventWeight); + registry.fill(HIST("h_subleading_fulljet_NEF"), nef, eventWeight); + registry.fill(HIST("h2_subleading_fulljet_jetpTDet_vs_FT0Mults"), jetPt, collision.multFT0M(), eventWeight); + registry.fill(HIST("h2_subleading_fulljet_jetpTDet_vs_Nch"), jetPt, numberOfChargedParticles, eventWeight); + registry.fill(HIST("h3_subleading_fulljet_jetpTDet_FT0Mults_nef"), jetPt, collision.multFT0M(), nef, eventWeight); + } + } + } + PROCESS_SWITCH(FullJetSpectra, processMCDCollisionsWeightedWithMultiplicity, "Weighted MCD Collisions for Full Jets Multiplicity Studies", false); + + void processMBMCPCollisionsWithMultiplicity(aod::JetMcCollision const& mccollision, + JetTableMCPJoined const& jets, aod::JetParticles const& /*particles*/, + soa::SmallGroups const& collisions) + { + bool eventAccepted = false; + double weight = 1.0; + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + float mcpMult = 0.0f; + float mcpCent = 0.0f; + + registry.fill(HIST("hPartEventmultiplicityCounter"), 0.5); // allMcColl + if (std::fabs(mccollision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hPartEventmultiplicityCounter"), 1.5); // McCollWithVertexZ + + // outlier check: for every outlier jet, reject the whole event + for (auto const& jet : jets) { + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + registry.fill(HIST("hPartEventmultiplicityCounter"), 2.5); // RejectedPartCollWithOutliers + return; + } + } + + if (doMBGapTrigger && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + // Fill rejected MB events; + registry.fill(HIST("hPartEventmultiplicityCounter"), 3.5); // MBRejectedPartEvents + return; + } + + // Perform MC Collision matching, i.e. match the current MC collision to its associated reco (MCD) collision + // to get the corresponding FT0M component at the particle level + auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, mccollision.globalIndex()); + registry.fill(HIST("hRecoMatchesPerMcCollisionMult"), collisionspermcpjet.size()); // for split vertices QA + + if (collisionspermcpjet.size() == 0 || collisionspermcpjet.size() < 1) { + registry.fill(HIST("hPartEventmultiplicityCounter"), 4.5); // RejectedPartCollForDetCollWithSize0or<1 + return; + } + registry.fill(HIST("hPartEventmultiplicityCounter"), 5.5); // AcceptedPartCollWithSize>1 + + for (auto const& collision : collisionspermcpjet) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + continue; + } + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hPartEventmultiplicityCounter"), 6.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hPartEventmultiplicityCounter"), 6.5); // EMCreadoutDetEventsWithkTVXinEMC + } + } + mcpMult += collision.multFT0M(); + mcpCent += collision.centFT0M(); + } // collision loop ends + + if (!eventAccepted) { + registry.fill(HIST("hPartEventmultiplicityCounter"), 7.5); // AllRejectedPartEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hPartEventmultiplicityCounter"), 8.5); // EMCAcceptedPartColl + registry.fill(HIST("hMCCollMatchedFT0Mult"), mcpMult); + registry.fill(HIST("hMCCollMatchedFT0Cent"), mcpCent); + + std::vector::iterator> selectedJets; + int nJetsThisEvent = 0; + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) + continue; + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) + continue; + if (!isAcceptedPartJet(jet)) + continue; + + selectedJets.push_back(jet); + nJetsThisEvent++; + } + // 1. Sort selected jets by pT before processing + std::sort(selectedJets.begin(), selectedJets.end(), + [](auto const& a, auto const& b) { return (*a).pt() > (*b).pt(); }); + + if (selectedJets.size() == 0) { // no jets = no leading jet + return; + } else { + // Jet multiplicity per event + registry.fill(HIST("h_all_fulljet_Njets_part"), selectedJets.size(), 1.0); + + // Select Leading Jet for N_ch calculation (for every leading jet that is found). There's always one leading jet per event! + auto const& leadingJet = *selectedJets[0]; + auto const& leadingJetPt = leadingJet.pt(); // jet pT distribution of the leading jet + registry.fill(HIST("h_Leading_full_jet_pt_part"), leadingJetPt, 1.0); + registry.fill(HIST("h2_full_jet_leadingJetPt_vs_counts_part"), leadingJetPt, nJetsThisEvent, 1.0); + } + + if (selectedJets.size() > 1) { + auto const& subLeadingJet = *selectedJets[1]; + auto const& subLeadingJetPt = subLeadingJet.pt(); // jet pT distribution of the subleading jet i.e. 2nd leading jet + registry.fill(HIST("h_SubLeading_full_jet_pt_part"), subLeadingJetPt, 1.0); + registry.fill(HIST("h2_full_jet_subLeadingJetPt_vs_counts_part"), subLeadingJetPt, nJetsThisEvent, 1.0); + } + // Process ALL selected jets (not just leading) + for (size_t i = 0; i < selectedJets.size(); i++) { + auto const& jet = *selectedJets[i]; + float jetPt = jet.pt(); + bool isLeading = (i == 0); + bool isSubLeading = (i == 1 && selectedJets.size() > 1); // first sub-leading jet + + // Count charged particles(NCh) and neutral particles (NNe) for this jet + int numberOfChargedParticles = 0; + int numberOfNeutralParticles = 0; + float neutralEnergy = 0.0f; + for (const auto& constituent : jet.tracks_as()) { + auto pdgParticle = pdgDatabase->GetParticle(constituent.pdgCode()); + if (pdgParticle->Charge() == 0) { + numberOfNeutralParticles++; + neutralEnergy += constituent.e(); + } else { + numberOfChargedParticles++; + } + } + float nef = neutralEnergy / jet.energy(); + + // CASE 1: Fill histograms for ALL selected jets + registry.fill(HIST("h_all_fulljet_pt_part"), jetPt, 1.0); + registry.fill(HIST("h_all_fulljet_Nch_part"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_all_fulljet_Nne_part"), numberOfNeutralParticles, 1.0); + registry.fill(HIST("h_all_fulljet_NEF_part"), nef, 1.0); + registry.fill(HIST("h2_all_fulljet_jetpT_vs_FT0Mults_part"), jetPt, mcpMult, 1.0); + registry.fill(HIST("h2_all_fulljet_jetpT_vs_Nch_part"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_full_jet_jetpT_FT0Mults_nef_part"), jetPt, mcpMult, nef, 1.0); + + // CASE 2: Additional leading jet processing + if (isLeading) { + registry.fill(HIST("h_leading_fulljet_pt_part"), jetPt, 1.0); + registry.fill(HIST("h_leading_fulljet_Nch_part"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_leading_fulljet_Nne_part"), numberOfNeutralParticles, 1.0); + registry.fill(HIST("h_leading_fulljet_NEF_part"), nef, 1.0); + registry.fill(HIST("h2_leading_fulljet_jetpT_vs_FT0Mults_part"), jetPt, mcpMult, 1.0); + registry.fill(HIST("h2_leading_fulljet_jetpT_vs_Nch_part"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_leading_fulljet_jetpT_FT0Mults_nef_part"), jetPt, mcpMult, nef, 1.0); + } + + // CASE 3: Additional first sub-leading jet processing + if (isSubLeading) { + registry.fill(HIST("h_subleading_fulljet_pt_part"), jetPt, 1.0); + registry.fill(HIST("h_subleading_fulljet_Nch_part"), numberOfChargedParticles, 1.0); + registry.fill(HIST("h_subleading_fulljet_Nne_part"), numberOfNeutralParticles, 1.0); + registry.fill(HIST("h_subleading_fulljet_NEF_part"), nef, 1.0); + registry.fill(HIST("h2_subleading_fulljet_jetpT_vs_FT0Mults_part"), jetPt, mcpMult, 1.0); + registry.fill(HIST("h2_subleading_fulljet_jetpT_vs_Nch_part"), jetPt, numberOfChargedParticles, 1.0); + registry.fill(HIST("h3_subleading_fulljet_jetpT_FT0Mults_nef_part"), jetPt, mcpMult, nef, 1.0); + } + } + } + PROCESS_SWITCH(FullJetSpectra, processMBMCPCollisionsWithMultiplicity, "MB MCP Collisions for Full Jets Multiplicity Studies", false); + + void processMBMCPCollisionsWeightedWithMultiplicity(aod::JetMcCollision const& mccollision, + JetTableMCPWeightedJoined const& jets, aod::JetParticles const& /*particles*/, + soa::SmallGroups const& collisions) + { + bool eventAccepted = false; + float pTHat = 10. / (std::pow(mccollision.weight(), 1.0 / pTHatExponent)); + float mcpMult = 0.0f; + float mcpCent = 0.0f; + + registry.fill(HIST("hPartEventmultiplicityCounter"), 0.5, mccollision.weight()); // allWeightedMcColl + if (std::fabs(mccollision.posZ()) > vertexZCut) { + return; + } + registry.fill(HIST("hPartEventmultiplicityCounter"), 1.5, mccollision.weight()); // WeightedMcCollWithVertexZ + + // outlier check: for every outlier jet, reject the whole event + for (auto const& jet : jets) { + if (jet.pt() > pTHatMaxMCP * pTHat || pTHat < pTHatAbsoluteMin) { + registry.fill(HIST("hPartEventmultiplicityCounter"), 2.5, mccollision.weight()); // RejectedWeightedPartCollWithOutliers + return; + } + } + + if (doMBGapTrigger && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + // Fill rejected MB events; + registry.fill(HIST("hPartEventmultiplicityCounter"), 3.5, mccollision.weight()); // MBRejectedPartEvents + return; + } + + // Perform MC Collision matching, i.e. match the current MC collision to its associated reco (MCD) collision + // to get the corresponding FT0M component at the particle level + auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, mccollision.globalIndex()); + registry.fill(HIST("hRecoMatchesPerMcCollisionMult"), collisionspermcpjet.size(), mccollision.weight()); // for split vertices QA + + if (collisionspermcpjet.size() == 0 || collisionspermcpjet.size() < 1) { + registry.fill(HIST("hPartEventmultiplicityCounter"), 4.5, mccollision.weight()); // RejectedWeightedPartCollForDetCollWithSize0or<1 + return; + } + registry.fill(HIST("hPartEventmultiplicityCounter"), 5.5, mccollision.weight()); // AcceptedWeightedPartCollWithSize>1 + + for (auto const& collision : collisionspermcpjet) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, doMBGapTrigger)) { + continue; + } + if (doEMCALEventWorkaround) { + if (collision.isEmcalReadout() && !collision.isAmbiguous()) { // i.e. EMCAL has a cell content + if (collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hPartEventmultiplicityCounter"), 6.5, mccollision.weight()); // EMCreadoutDetEventsWithkTVXinEMC + } + } + } else { + if (!collision.isAmbiguous() && jetderiveddatautilities::eventEMCAL(collision) && collision.alias_bit(kTVXinEMC)) { + eventAccepted = true; + registry.fill(HIST("hPartEventmultiplicityCounter"), 6.5, mccollision.weight()); // EMCreadoutDetEventsWithkTVXinEMC + } + } + mcpMult += collision.multFT0M(); + mcpCent += collision.centFT0M(); + } // collision loop ends + + if (!eventAccepted) { + registry.fill(HIST("hPartEventmultiplicityCounter"), 7.5, mccollision.weight()); // AllRejectedWeightedPartEventsAfterEMCEventSelection + return; + } + registry.fill(HIST("hPartEventmultiplicityCounter"), 8.5, mccollision.weight()); // EMCAcceptedWeightedPartColl + registry.fill(HIST("hMCCollMatchedFT0Mult"), mcpMult, mccollision.weight()); + registry.fill(HIST("hMCCollMatchedFT0Cent"), mcpCent, mccollision.weight()); + + std::vector::iterator> selectedJets; + int nJetsThisEvent = 0; + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) + continue; + if (jet.phi() < jetPhiMin || jet.phi() > jetPhiMax) + continue; + if (!isAcceptedPartJet(jet)) + continue; + + selectedJets.push_back(jet); + nJetsThisEvent++; + } + // 1. Sort selected jets by pT before processing + std::sort(selectedJets.begin(), selectedJets.end(), + [](auto const& a, auto const& b) { return (*a).pt() > (*b).pt(); }); + + if (selectedJets.size() == 0) { // no jets = no leading jet + return; + } else { + // Jet multiplicity per event + registry.fill(HIST("h_all_fulljet_Njets_part"), selectedJets.size(), mccollision.weight()); + + // Select Leading Jet for N_ch calculation (for every leading jet that is found). There's always one leading jet per event! + auto const& leadingJet = *selectedJets[0]; + auto const& leadingJetPt = leadingJet.pt(); // jet pT distribution of the leading jet + registry.fill(HIST("h_Leading_full_jet_pt_part"), leadingJetPt, mccollision.weight()); + registry.fill(HIST("h2_full_jet_leadingJetPt_vs_counts_part"), leadingJetPt, nJetsThisEvent, mccollision.weight()); + } + + if (selectedJets.size() > 1) { + auto const& subLeadingJet = *selectedJets[1]; + auto const& subLeadingJetPt = subLeadingJet.pt(); // jet pT distribution of the subleading jet i.e. 2nd leading jet + registry.fill(HIST("h_SubLeading_full_jet_pt_part"), subLeadingJetPt, mccollision.weight()); + registry.fill(HIST("h2_full_jet_subLeadingJetPt_vs_counts_part"), subLeadingJetPt, nJetsThisEvent, mccollision.weight()); + } + // Process ALL selected jets (not just leading) + for (size_t i = 0; i < selectedJets.size(); i++) { + auto const& jet = *selectedJets[i]; + float jetPt = jet.pt(); + bool isLeading = (i == 0); + bool isSubLeading = (i == 1 && selectedJets.size() > 1); // first sub-leading jet + + // Count charged particles(NCh) and neutral particles (NNe) for this jet + int numberOfChargedParticles = 0; + int numberOfNeutralParticles = 0; + float neutralEnergy = 0.0f; + for (const auto& constituent : jet.tracks_as()) { + auto pdgParticle = pdgDatabase->GetParticle(constituent.pdgCode()); + if (pdgParticle->Charge() == 0) { + numberOfNeutralParticles++; + neutralEnergy += constituent.e(); + } else { + numberOfChargedParticles++; + } + } + float nef = neutralEnergy / jet.energy(); + + // CASE 1: Fill histograms for ALL selected jets + registry.fill(HIST("h_all_fulljet_pt_part"), jetPt, mccollision.weight()); + registry.fill(HIST("h_all_fulljet_Nch_part"), numberOfChargedParticles, mccollision.weight()); + registry.fill(HIST("h_all_fulljet_Nne_part"), numberOfNeutralParticles, mccollision.weight()); + registry.fill(HIST("h_all_fulljet_NEF_part"), nef, mccollision.weight()); + registry.fill(HIST("h2_all_fulljet_jetpT_vs_FT0Mults_part"), jetPt, mcpMult, mccollision.weight()); + registry.fill(HIST("h2_all_fulljet_jetpT_vs_Nch_part"), jetPt, numberOfChargedParticles, mccollision.weight()); + registry.fill(HIST("h3_full_jet_jetpT_FT0Mults_nef_part"), jetPt, mcpMult, nef, mccollision.weight()); + + // CASE 2: Additional leading jet processing + if (isLeading) { + registry.fill(HIST("h_leading_fulljet_pt_part"), jetPt, mccollision.weight()); + registry.fill(HIST("h_leading_fulljet_Nch_part"), numberOfChargedParticles, mccollision.weight()); + registry.fill(HIST("h_leading_fulljet_Nne_part"), numberOfNeutralParticles, mccollision.weight()); + registry.fill(HIST("h_leading_fulljet_NEF_part"), nef, mccollision.weight()); + registry.fill(HIST("h2_leading_fulljet_jetpT_vs_FT0Mults_part"), jetPt, mcpMult, mccollision.weight()); + registry.fill(HIST("h2_leading_fulljet_jetpT_vs_Nch_part"), jetPt, numberOfChargedParticles, mccollision.weight()); + registry.fill(HIST("h3_leading_fulljet_jetpT_FT0Mults_nef_part"), jetPt, mcpMult, nef, mccollision.weight()); + } + + // CASE 3: Additional first sub-leading jet processing + if (isSubLeading) { + registry.fill(HIST("h_subleading_fulljet_pt_part"), jetPt, mccollision.weight()); + registry.fill(HIST("h_subleading_fulljet_Nch_part"), numberOfChargedParticles, mccollision.weight()); + registry.fill(HIST("h_subleading_fulljet_Nne_part"), numberOfNeutralParticles, mccollision.weight()); + registry.fill(HIST("h_subleading_fulljet_NEF_part"), nef, mccollision.weight()); + registry.fill(HIST("h2_subleading_fulljet_jetpT_vs_FT0Mults_part"), jetPt, mcpMult, mccollision.weight()); + registry.fill(HIST("h2_subleading_fulljet_jetpT_vs_Nch_part"), jetPt, numberOfChargedParticles, mccollision.weight()); + registry.fill(HIST("h3_subleading_fulljet_jetpT_FT0Mults_nef_part"), jetPt, mcpMult, nef, mccollision.weight()); + } + } + } + PROCESS_SWITCH(FullJetSpectra, processMBMCPCollisionsWeightedWithMultiplicity, "MB MCP Weighted Collisions for Full Jets Multiplicity Studies", false); + +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/FullJetTriggerQATask.cxx b/PWGJE/Tasks/fullJetTriggerQATask.cxx similarity index 50% rename from PWGJE/Tasks/FullJetTriggerQATask.cxx rename to PWGJE/Tasks/fullJetTriggerQATask.cxx index 9dad8d604b5..88255a2dda7 100644 --- a/PWGJE/Tasks/FullJetTriggerQATask.cxx +++ b/PWGJE/Tasks/fullJetTriggerQATask.cxx @@ -13,32 +13,48 @@ // /// \author Gijs van Weelden // -#include -#include +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/EMCALClusterDefinition.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" -#include "TH1F.h" -#include "TTree.h" +#include "Common/CCDB/TriggerAliases.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" -#include "Framework/RunningWorkflowInfo.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include +#include -#include "Common/DataModel/EventSelection.h" +#include "TTree.h" +#include +#include +#include +#include -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include +#include -#include "EventFiltering/filterTables.h" +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; 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; @@ -88,13 +104,11 @@ struct JetTriggerQA { Configurable b_DoFiducialCut{"b_DoFiducialCut", false, "do a fiducial cut on jets to check if they are in the emcal"}; Configurable b_RejectExoticClusters{"b_RejectExoticClusters", true, "Reject exotic clusters"}; Configurable f_GammaObservable{"f_gammaObservable", 0, "Observable for gamma trigger (0 - energy, 1 - pt)"}; + Configurable b_doLightOutput{"b_doLightOutput", true, "do light output (disables most histograms not needed for QA)"}; Configurable cfgVertexCut{"cfgVertexCut", 10.0f, "Accepted z-vertex range"}; Configurable mClusterDefinition{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"}; - std::vector jetConstituents; - std::vector jetClusterConstituents; - std::vector jetReclustered; JetFinder jetReclusterer; void init(InitContext&) @@ -103,18 +117,18 @@ struct JetTriggerQA { jetReclusterer.algorithm = fastjet::JetAlgorithm::cambridge_algorithm; jetReclusterer.jetR = f_jetR * 2.5; // Use larger R for CA reclustering to prevent losing particles - Int_t nPtBins = 200; - Float_t kMinPt = 0.; - Float_t kMaxPt = 201.; - Int_t nPhiBins = 18 * 8; - Float_t kMinPhi = 0.; - Float_t kMaxPhi = 2. * TMath::Pi(); - Int_t nEtaBins = 100; - Float_t kMinEta = -1.; - Float_t kMaxEta = 1.; - Int_t nRBins = 6; - Float_t kMinR = 0.05; - Float_t kMaxR = 0.65; + int nPtBins = 200; + float kMinPt = 0.; + float kMaxPt = 201.; + int nPhiBins = 18 * 8; + float kMinPhi = 0.; + float kMaxPhi = o2::constants::math::TwoPI; + int nEtaBins = 100; + float kMinEta = -1.; + float kMaxEta = 1.; + int nRBins = 6; + float kMinR = 0.05; + float kMaxR = 0.65; // EMCAL gamma observables (for histogram and axis title) std::string observableName = (f_GammaObservable == 0) ? "Energy" : "#it{p}_{T}", @@ -137,9 +151,11 @@ struct JetTriggerQA { HistogramConfigSpec hJetRMaxPtEtaPhiNoFiducial({HistType::kTHnF, {rAxis, jetPtAxis, etaAxis, phiAxis}}); registry.add("jetRPtEtaPhi", "JetRPtEtaPhi", hJetRPtEtaPhi); - registry.add("jetRMaxPtEtaPhi", "JetRMaxPtEtaPhi", hJetRMaxPtEtaPhi); + if (!b_doLightOutput) + registry.add("jetRMaxPtEtaPhi", "JetRMaxPtEtaPhi", hJetRMaxPtEtaPhi); registry.add("jetRPtEtaPhiNoFiducial", "JetRPtEtaPhiNoFiducial", hJetRPtEtaPhiNoFiducial); - registry.add("jetRMaxPtEtaPhiNoFiducial", "JetRMaxPtEtaPhiNoFiducial", hJetRMaxPtEtaPhiNoFiducial); + if (!b_doLightOutput) + registry.add("jetRMaxPtEtaPhiNoFiducial", "JetRMaxPtEtaPhiNoFiducial", hJetRMaxPtEtaPhiNoFiducial); registry.add("hProcessedEvents", "Processed events", HistType::kTH1D, {{15, -0.5, 14.5, "Trigger type"}}); auto histProcessed = registry.get(HIST("hProcessedEvents")); @@ -170,156 +186,192 @@ struct JetTriggerQA { // Histograms for events where the EMCAL is live registry.add("hJetRPtEta", "Jets #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); registry.add("hJetRPtPhi", "Jets #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); - registry.add("hJetRMaxPtEta", "Leading jets #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); - registry.add("hJetRMaxPtPhi", "Leading jets #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); - registry.add("hJetRMaxPtEtaMinBias", "Leading jets #it{p}_{T} and #eta (min. bias)", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); - registry.add("hJetRMaxPtPhiMinBias", "Leading jets #it{p}_{T} and #phi (min. bias)", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); - registry.add("hJetRMaxPtEtaLevel0", "Leading jets #it{p}_{T} and #eta (level0)", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); - registry.add("hJetRMaxPtPhiLevel0", "Leading jets #it{p}_{T} and #phi (level0)", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); + if (!b_doLightOutput) { + registry.add("hJetRMaxPtEta", "Leading jets #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); + registry.add("hJetRMaxPtPhi", "Leading jets #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); + registry.add("hJetRMaxPtEtaMinBias", "Leading jets #it{p}_{T} and #eta (min. bias)", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); + registry.add("hJetRMaxPtPhiMinBias", "Leading jets #it{p}_{T} and #phi (min. bias)", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); + registry.add("hJetRMaxPtEtaLevel0", "Leading jets #it{p}_{T} and #eta (level0)", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); + registry.add("hJetRMaxPtPhiLevel0", "Leading jets #it{p}_{T} and #phi (level0)", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); + } registry.add("hClusterPtEtaPhi", Form("Cluster %s, #eta and #phi", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); registry.add("hClusterPtEtaPhiMinBias", Form("Cluster %s (Min. bias trigger), #eta and #phi", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); registry.add("hClusterPtEtaPhiLevel0", Form("Cluster %s (Level-0 trigger), #eta and #phi", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hClusterEMCALMaxPtEtaPhi", Form("Leading cluster %s, #eta and #phi (EMCAL)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hClusterEMCALMaxPtEtaPhiMinBias", Form("Leading cluster %s, #eta and #phi (EMCAL, min. bias trigger)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hClusterEMCALMaxPtEtaPhiLevel0", Form("Leading cluster %s, #eta and #phi (EMCAL, Level-0 trigger)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hClusterDCALMaxPtEtaPhi", Form("Leading cluster %s, #eta and #phi (DCAL)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hClusterDCALMaxPtEtaPhiMinBias", Form("Leading cluster %s, #eta and #phi (DCAL, min, bias trigger)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hClusterDCALMaxPtEtaPhiLevel0", Form("Leading cluster %s, #eta and #phi (DCAL, Level-0 trigger)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hEventsNoMaxClusterEMCAL", "Events with no max. cluster in EMCAL", HistType::kTH1D, {{1, 0.5, 1.5}}); - registry.add("hEventsNoMaxClusterEMCALMinBias", "Events with no max. cluster in EMCAL (min. bias trigger)", HistType::kTH1D, {{1, 0.5, 1.5}}); - registry.add("hEventsNoMaxClusterEMCALLevel0", "Events with no max. cluster in EMCAL (level0 trigger)", HistType::kTH1D, {{1, 0.5, 1.5}}); - registry.add("hEventsNoMaxClusterDCAL", ("Events with no max. cluster in DCAL"), HistType::kTH1D, {{1, 0.5, 1.5}}); - registry.add("hEventsNoMaxClusterDCALMinBias", "Events with no max. cluster in DCAL (min. bias trigger)", HistType::kTH1D, {{1, 0.5, 1.5}}); - registry.add("hEventsNoMaxClusterDCALLevel0", "Events with no max. cluster in DCAL (level0 trigger)", HistType::kTH1D, {{1, 0.5, 1.5}}); - registry.add("hEventsNoMaxJet", "Events with no max. jet", HistType::kTH1D, {{rAxis}}); - registry.add("hEventsNoMaxJetMinBias", "Events with no max. jet (min. bias trigger)", HistType::kTH1D, {{rAxis}}); - registry.add("hEventsNoMaxJetLevel0", "Events with no max. jet (level0 trigger)", HistType::kTH1D, {{rAxis}}); - registry.add("hJetRPtTrackPt", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisTrackInJet}); - registry.add("hJetRPtClusterPt", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisClusterInJet}); - registry.add("hJetRPtPtd", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "p_{t,D}"}}); - registry.add("hJetRPtChargeFrag", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z"}}); - registry.add("hJetRPtNEF", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "NEF"}}); - registry.add("hJetRPtZTheta", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z#theta"}}); - registry.add("hJetRPtZSqTheta", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z^{2} #theta"}}); - registry.add("hJetRPtZThetaSq", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z #theta^{2}"}}); - registry.add("hJetRMaxPtClusterMaxPt", "Leading jets and clusters", HistType::kTH3F, {rAxis, jetPtAxis, observableAxisCluster}); + + if (!b_doLightOutput) { + registry.add("hClusterEMCALMaxPtEtaPhi", Form("Leading cluster %s, #eta and #phi (EMCAL)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + registry.add("hClusterEMCALMaxPtEtaPhiMinBias", Form("Leading cluster %s, #eta and #phi (EMCAL, min. bias trigger)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + registry.add("hClusterEMCALMaxPtEtaPhiLevel0", Form("Leading cluster %s, #eta and #phi (EMCAL, Level-0 trigger)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + registry.add("hClusterDCALMaxPtEtaPhi", Form("Leading cluster %s, #eta and #phi (DCAL)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + registry.add("hClusterDCALMaxPtEtaPhiMinBias", Form("Leading cluster %s, #eta and #phi (DCAL, min, bias trigger)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + registry.add("hClusterDCALMaxPtEtaPhiLevel0", Form("Leading cluster %s, #eta and #phi (DCAL, Level-0 trigger)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + registry.add("hEventsNoMaxClusterEMCAL", "Events with no max. cluster in EMCAL", HistType::kTH1D, {{1, 0.5, 1.5}}); + registry.add("hEventsNoMaxClusterEMCALMinBias", "Events with no max. cluster in EMCAL (min. bias trigger)", HistType::kTH1D, {{1, 0.5, 1.5}}); + registry.add("hEventsNoMaxClusterEMCALLevel0", "Events with no max. cluster in EMCAL (level0 trigger)", HistType::kTH1D, {{1, 0.5, 1.5}}); + registry.add("hEventsNoMaxClusterDCAL", ("Events with no max. cluster in DCAL"), HistType::kTH1D, {{1, 0.5, 1.5}}); + registry.add("hEventsNoMaxClusterDCALMinBias", "Events with no max. cluster in DCAL (min. bias trigger)", HistType::kTH1D, {{1, 0.5, 1.5}}); + registry.add("hEventsNoMaxClusterDCALLevel0", "Events with no max. cluster in DCAL (level0 trigger)", HistType::kTH1D, {{1, 0.5, 1.5}}); + registry.add("hEventsNoMaxJet", "Events with no max. jet", HistType::kTH1D, {{rAxis}}); + registry.add("hEventsNoMaxJetMinBias", "Events with no max. jet (min. bias trigger)", HistType::kTH1D, {{rAxis}}); + registry.add("hEventsNoMaxJetLevel0", "Events with no max. jet (level0 trigger)", HistType::kTH1D, {{rAxis}}); + + registry.add("hJetRPtTrackPt", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisTrackInJet}); + registry.add("hJetRPtClusterPt", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisClusterInJet}); + registry.add("hJetRPtPtd", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "p_{t,D}"}}); + registry.add("hJetRPtChargeFrag", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z"}}); + registry.add("hJetRPtNEF", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "NEF"}}); + registry.add("hJetRPtZTheta", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z#theta"}}); + registry.add("hJetRPtZSqTheta", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z^{2} #theta"}}); + registry.add("hJetRPtZThetaSq", "Jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z #theta^{2}"}}); + + registry.add("hJetRMaxPtClusterMaxPt", "Leading jets and clusters", HistType::kTH3F, {rAxis, jetPtAxis, observableAxisCluster}); + } // Histograms for triggered events registry.add("hSelectedClusterPtEtaPhi", Form("Selected cluster %s, #eta and #phi", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedClusterMaxPtEtaPhi", Form("Leading Selected cluster %s, #eta and #phi", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + + if (!b_doLightOutput) { + registry.add("hSelectedClusterMaxPtEtaPhi", Form("Leading Selected cluster %s, #eta and #phi", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + } // Jet high trigger - registry.add("hSelectedJetRMaxPtEta", "Leading selected jets #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); - registry.add("hSelectedJetRMaxPtPhi", "Leading selected jets #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); + if (!b_doLightOutput) { + registry.add("hSelectedJetRMaxPtEta", "Leading selected jets #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); + registry.add("hSelectedJetRMaxPtPhi", "Leading selected jets #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); + } registry.add("hSelectedJetRPtEta", "Selected jets #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); registry.add("hSelectedJetRPtPhi", "Selected jets #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); - registry.add("hSelectedJetRPtTrackPt", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisTrackInJet}); - registry.add("hSelectedJetRPtClusterPt", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisClusterInJet}); - registry.add("hSelectedJetRPtPtd", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "p_{t,D}"}}); - registry.add("hSelectedJetRPtChargeFrag", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z"}}); - registry.add("hSelectedJetRPtNEF", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "NEF"}}); - registry.add("hSelectedJetRPtZTheta", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z#theta"}}); - registry.add("hSelectedJetRPtZSqTheta", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z^{2} #theta"}}); - registry.add("hSelectedJetRPtZThetaSq", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z #theta^{2}"}}); + if (!b_doLightOutput) { + registry.add("hSelectedJetRPtTrackPt", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisTrackInJet}); + registry.add("hSelectedJetRPtClusterPt", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisClusterInJet}); + registry.add("hSelectedJetRPtPtd", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "p_{t,D}"}}); + registry.add("hSelectedJetRPtChargeFrag", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z"}}); + registry.add("hSelectedJetRPtNEF", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "NEF"}}); + registry.add("hSelectedJetRPtZTheta", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z#theta"}}); + registry.add("hSelectedJetRPtZSqTheta", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z^{2} #theta"}}); + registry.add("hSelectedJetRPtZThetaSq", "Selected jets", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z #theta^{2}"}}); + } // Jet low trigger - registry.add("hSelectedJetLowRMaxPtEta", "Leading selected jets (low threshold) #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); - registry.add("hSelectedJetLowRMaxPtPhi", "Leading selected jets (low threshold) #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); + if (!b_doLightOutput) { + registry.add("hSelectedJetLowRMaxPtEta", "Leading selected jets (low threshold) #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); + registry.add("hSelectedJetLowRMaxPtPhi", "Leading selected jets (low threshold) #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); + } registry.add("hSelectedJetLowRPtEta", "Selected jets (low threshold) #it{p}_{T} and #eta", HistType::kTH3F, {rAxis, jetPtAxis, etaAxis}); registry.add("hSelectedJetLowRPtPhi", "Selected jets (low threshold) #it{p}_{T} and #phi", HistType::kTH3F, {rAxis, jetPtAxis, phiAxis}); - registry.add("hSelectedJetLowRPtTrackPt", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisTrackInJet}); - registry.add("hSelectedJetLowRPtClusterPt", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisClusterInJet}); - registry.add("hSelectedJetLowRPtPtd", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "p_{t,D}"}}); - registry.add("hSelectedJetLowRPtChargeFrag", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z"}}); - registry.add("hSelectedJetLowRPtNEF", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "NEF"}}); - registry.add("hSelectedJetLowRPtZTheta", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z#theta"}}); - registry.add("hSelectedJetLowRPtZSqTheta", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z^{2} #theta"}}); - registry.add("hSelectedJetLowRPtZThetaSq", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z #theta^{2}"}}); + + if (!b_doLightOutput) { + registry.add("hSelectedJetLowRPtTrackPt", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisTrackInJet}); + registry.add("hSelectedJetLowRPtClusterPt", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, ptAxisClusterInJet}); + registry.add("hSelectedJetLowRPtPtd", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "p_{t,D}"}}); + registry.add("hSelectedJetLowRPtChargeFrag", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z"}}); + registry.add("hSelectedJetLowRPtNEF", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "NEF"}}); + registry.add("hSelectedJetLowRPtZTheta", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z#theta"}}); + registry.add("hSelectedJetLowRPtZSqTheta", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z^{2} #theta"}}); + registry.add("hSelectedJetLowRPtZThetaSq", "Selected jets (low threshold)", HistType::kTH3F, {rAxis, jetPtAxis, {nPtBins / 2, 0., 1., "z #theta^{2}"}}); + } // EMCAL gamma very-high trigger registry.add("hSelectedGammaEMCALPtEtaPhiVeryHigh", Form("Selected Gamma %s, #eta and #phi (EMCAL, very high threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedGammaEMCALMaxPtEtaPhiVeryHigh", Form("Leading selected gamma %s, #eta and #phi (EMCAL, very high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + if (!b_doLightOutput) + registry.add("hSelectedGammaEMCALMaxPtEtaPhiVeryHigh", Form("Leading selected gamma %s, #eta and #phi (EMCAL, very high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); // DCAL gamma very-high trigger registry.add("hSelectedGammaDCALPtEtaPhiVeryHigh", Form("Selected gamma %s, #eta and #phi (DCAL, very high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedGammaDCALMaxPtEtaPhiVeryHigh", Form("Leading selected gamma %s, #eta and #phi (DCAL, very high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + if (!b_doLightOutput) + registry.add("hSelectedGammaDCALMaxPtEtaPhiVeryHigh", Form("Leading selected gamma %s, #eta and #phi (DCAL, very high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); // EG1 trigger registry.add("hSelectedGammaEMCALPtEtaPhi", Form("Selected Gamma %s, #eta and #phi (EMCAL, high threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedGammaEMCALMaxPtEtaPhi", Form("Leading selected gamma %s, #eta and #phi (EMCAL, high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + if (!b_doLightOutput) + registry.add("hSelectedGammaEMCALMaxPtEtaPhi", Form("Leading selected gamma %s, #eta and #phi (EMCAL, high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); // DG1 trigger registry.add("hSelectedGammaDCALPtEtaPhi", Form("Selected gamma %s, #eta and #phi (DCAL, high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedGammaDCALMaxPtEtaPhi", Form("Leading selected gamma %s, #eta and #phi (DCAL, high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + if (!b_doLightOutput) + registry.add("hSelectedGammaDCALMaxPtEtaPhi", Form("Leading selected gamma %s, #eta and #phi (DCAL, high treshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); // EG2 trigger registry.add("hSelectedGammaEMCALPtEtaPhiLow", Form("Selected gamma %s, #eta and #phi (EMCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedGammaEMCALMaxPtEtaPhiLow", Form("Leading selected gamma %s, #eta and #phi (EMCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + if (!b_doLightOutput) + registry.add("hSelectedGammaEMCALMaxPtEtaPhiLow", Form("Leading selected gamma %s, #eta and #phi (EMCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); // DG2 trigger registry.add("hSelectedGammaDCALPtEtaPhiLow", Form("Selected gamma %s, #eta and #phi (DCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedGammaDCALMaxPtEtaPhiLow", Form("Leading selected gamma %s, #eta and #phi (DCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + if (!b_doLightOutput) + registry.add("hSelectedGammaDCALMaxPtEtaPhiLow", Form("Leading selected gamma %s, #eta and #phi (DCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); // EMCAL gamma very-low trigger registry.add("hSelectedGammaEMCALPtEtaPhiVeryLow", Form("Selected gamma %s, #eta and #phi (EMCAL, very low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedGammaEMCALMaxPtEtaPhiVeryLow", Form("Leading selected gamma %s, #eta and #phi (EMCAL, very low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + if (!b_doLightOutput) + registry.add("hSelectedGammaEMCALMaxPtEtaPhiVeryLow", Form("Leading selected gamma %s, #eta and #phi (EMCAL, very low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); // DCAL gamma very-low trigger registry.add("hSelectedGammaDCALPtEtaPhiVeryLow", Form("Selected gamma %s, #eta and #phi (DCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - registry.add("hSelectedGammaDCALMaxPtEtaPhiVeryLow", Form("Leading selected gamma %s, #eta and #phi (DCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); - - registry.add("hSelectedJetRMaxPtClusterMaxPt", "Leading selected jets and clusters", HistType::kTH3F, {rAxis, jetPtAxis, observableAxisCluster}); - registry.add("hJetRMaxPtJetPt", "Leading jet #it{p}_{T} vs jet #it{p}_{T}", HistType::kTH3F, {rAxis, jetMaxPtAxis, jetPtAxis}); - registry.add("hJetRMaxPtJetPtNoFiducial", "Leading jet #it{p}_{T} vs jet #it{p}_{T} (no fiducial cut)", HistType::kTH3F, {rAxis, jetMaxPtAxis, jetPtAxis}); - registry.add("hClusterEMCALMaxPtClusterEMCALPt", Form("Leading clusterEMCAL %s vs clusterEMCAL %s", observableName.data(), observableName.data()), HistType::kTH2F, {observableAxisMaxCluster, observableAxisCluster}); - registry.add("hClusterDCALMaxPtClusterDCALPt", Form("Leading clusterDCAL %s vs clusterDCAL %s", observableName.data(), observableName.data()), HistType::kTH2F, {observableAxisMaxCluster, observableAxisCluster}); + if (!b_doLightOutput) + registry.add("hSelectedGammaDCALMaxPtEtaPhiVeryLow", Form("Leading selected gamma %s, #eta and #phi (DCAL, low threshold)", observableName.data()), HistType::kTH3F, {observableAxisCluster, etaAxis, phiAxis}); + + if (!b_doLightOutput) { + registry.add("hSelectedJetRMaxPtClusterMaxPt", "Leading selected jets and clusters", HistType::kTH3F, {rAxis, jetPtAxis, observableAxisCluster}); + registry.add("hJetRMaxPtJetPt", "Leading jet #it{p}_{T} vs jet #it{p}_{T}", HistType::kTH3F, {rAxis, jetMaxPtAxis, jetPtAxis}); + registry.add("hJetRMaxPtJetPtNoFiducial", "Leading jet #it{p}_{T} vs jet #it{p}_{T} (no fiducial cut)", HistType::kTH3F, {rAxis, jetMaxPtAxis, jetPtAxis}); + registry.add("hClusterEMCALMaxPtClusterEMCALPt", Form("Leading clusterEMCAL %s vs clusterEMCAL %s", observableName.data(), observableName.data()), HistType::kTH2F, {observableAxisMaxCluster, observableAxisCluster}); + registry.add("hClusterDCALMaxPtClusterDCALPt", Form("Leading clusterDCAL %s vs clusterDCAL %s", observableName.data(), observableName.data()), HistType::kTH2F, {observableAxisMaxCluster, observableAxisCluster}); + } if (b_JetsInEmcalOnly) { registry.get(HIST("hJetRPtEta"))->SetTitle("Jets (in emcal only) #it{p}_{T} and #eta"); registry.get(HIST("hJetRPtPhi"))->SetTitle("Jets (in emcal only) #it{p}_{T} and #phi"); - registry.get(HIST("hJetRPtTrackPt"))->SetTitle("Jets (in emcal only)"); - registry.get(HIST("hJetRPtClusterPt"))->SetTitle("Jets (in emcal only)"); - registry.get(HIST("hJetRPtPtd"))->SetTitle("Jets (in emcal only)"); - registry.get(HIST("hJetRPtChargeFrag"))->SetTitle("Jets (in emcal only)"); - registry.get(HIST("hJetRPtNEF"))->SetTitle("Jets (in emcal only)"); - registry.get(HIST("hJetRPtZTheta"))->SetTitle("Jets (in emcal only)"); - registry.get(HIST("hJetRPtZSqTheta"))->SetTitle("Jets (in emcal only)"); - registry.get(HIST("hJetRPtZThetaSq"))->SetTitle("Jets (in emcal only)"); - registry.get(HIST("hJetRMaxPtEta"))->SetTitle("Leading jets (in emcal only) #it{p}_{T} and #eta"); - registry.get(HIST("hJetRMaxPtPhi"))->SetTitle("Leading jets (in emcal only) #it{p}_{T} and #phi"); - registry.get(HIST("hJetRMaxPtEtaMinBias"))->SetTitle("Leading jets (in emcal only, min. bias) #it{p}_{T} and #eta"); - registry.get(HIST("hJetRMaxPtPhiMinBias"))->SetTitle("Leading jets (in emcal only, min. bias) #it{p}_{T} and #phi"); - registry.get(HIST("hJetRMaxPtEtaLevel0"))->SetTitle("Leading jets (in emcal only, level-0) #it{p}_{T} and #eta"); - registry.get(HIST("hJetRMaxPtPhiLevel0"))->SetTitle("Leading jets (in emcal only, level-0) #it{p}_{T} and #phi"); - registry.get(HIST("hJetRMaxPtClusterMaxPt"))->SetTitle("Leading jets (in emcal only) and clusters"); + if (!b_doLightOutput) { + registry.get(HIST("hJetRPtTrackPt"))->SetTitle("Jets (in emcal only)"); + registry.get(HIST("hJetRPtClusterPt"))->SetTitle("Jets (in emcal only)"); + registry.get(HIST("hJetRPtPtd"))->SetTitle("Jets (in emcal only)"); + registry.get(HIST("hJetRPtChargeFrag"))->SetTitle("Jets (in emcal only)"); + registry.get(HIST("hJetRPtNEF"))->SetTitle("Jets (in emcal only)"); + registry.get(HIST("hJetRPtZTheta"))->SetTitle("Jets (in emcal only)"); + registry.get(HIST("hJetRPtZSqTheta"))->SetTitle("Jets (in emcal only)"); + registry.get(HIST("hJetRPtZThetaSq"))->SetTitle("Jets (in emcal only)"); + + registry.get(HIST("hJetRMaxPtEta"))->SetTitle("Leading jets (in emcal only) #it{p}_{T} and #eta"); + registry.get(HIST("hJetRMaxPtPhi"))->SetTitle("Leading jets (in emcal only) #it{p}_{T} and #phi"); + registry.get(HIST("hJetRMaxPtEtaMinBias"))->SetTitle("Leading jets (in emcal only, min. bias) #it{p}_{T} and #eta"); + registry.get(HIST("hJetRMaxPtPhiMinBias"))->SetTitle("Leading jets (in emcal only, min. bias) #it{p}_{T} and #phi"); + registry.get(HIST("hJetRMaxPtEtaLevel0"))->SetTitle("Leading jets (in emcal only, level-0) #it{p}_{T} and #eta"); + registry.get(HIST("hJetRMaxPtPhiLevel0"))->SetTitle("Leading jets (in emcal only, level-0) #it{p}_{T} and #phi"); + registry.get(HIST("hJetRMaxPtClusterMaxPt"))->SetTitle("Leading jets (in emcal only) and clusters"); + } registry.get(HIST("hSelectedJetRPtEta"))->SetTitle("Selected jets (in emcal only) #it{p}_{T} and #eta"); registry.get(HIST("hSelectedJetRPtPhi"))->SetTitle("Selected jets (in emcal only) #it{p}_{T} and #phi"); - registry.get(HIST("hSelectedJetRPtTrackPt"))->SetTitle("Selected jets (in emcal only)"); - registry.get(HIST("hSelectedJetRPtClusterPt"))->SetTitle("Selected jets (in emcal only)"); - registry.get(HIST("hSelectedJetRPtPtd"))->SetTitle("Selected jets (in emcal only)"); - registry.get(HIST("hSelectedJetRPtChargeFrag"))->SetTitle("Selected jets (in emcal only)"); - registry.get(HIST("hSelectedJetRPtNEF"))->SetTitle("Selected jets (in emcal only)"); - registry.get(HIST("hSelectedJetRPtZTheta"))->SetTitle("Selected jets (in emcal only)"); - registry.get(HIST("hSelectedJetRPtZSqTheta"))->SetTitle("Selected jets (in emcal only)"); - registry.get(HIST("hSelectedJetRPtZThetaSq"))->SetTitle("Selected jets (in emcal only)"); + if (!b_doLightOutput) { + registry.get(HIST("hSelectedJetRPtTrackPt"))->SetTitle("Selected jets (in emcal only)"); + registry.get(HIST("hSelectedJetRPtClusterPt"))->SetTitle("Selected jets (in emcal only)"); + registry.get(HIST("hSelectedJetRPtPtd"))->SetTitle("Selected jets (in emcal only)"); + registry.get(HIST("hSelectedJetRPtChargeFrag"))->SetTitle("Selected jets (in emcal only)"); + registry.get(HIST("hSelectedJetRPtNEF"))->SetTitle("Selected jets (in emcal only)"); + registry.get(HIST("hSelectedJetRPtZTheta"))->SetTitle("Selected jets (in emcal only)"); + registry.get(HIST("hSelectedJetRPtZSqTheta"))->SetTitle("Selected jets (in emcal only)"); + registry.get(HIST("hSelectedJetRPtZThetaSq"))->SetTitle("Selected jets (in emcal only)"); + } registry.get(HIST("hSelectedJetLowRPtEta"))->SetTitle("Selected jets (low threshold, in emcal only) #it{p}_{T} and #eta"); registry.get(HIST("hSelectedJetLowRPtPhi"))->SetTitle("Selected jets (low threshold, in emcal only) #it{p}_{T} and #phi"); - registry.get(HIST("hSelectedJetLowRPtTrackPt"))->SetTitle("Selected jets (low threshold, in emcal only)"); - registry.get(HIST("hSelectedJetLowRPtClusterPt"))->SetTitle("Selected jets (low threshold, in emcal only)"); - registry.get(HIST("hSelectedJetLowRPtPtd"))->SetTitle("Selected jets (low threshold, in emcal only)"); - registry.get(HIST("hSelectedJetLowRPtChargeFrag"))->SetTitle("Selected jets (low threshold, in emcal only)"); - registry.get(HIST("hSelectedJetLowRPtNEF"))->SetTitle("Selected jets (low threshold, in emcal only)"); - registry.get(HIST("hSelectedJetLowRPtZTheta"))->SetTitle("Selected jets (low threshold, in emcal only)"); - registry.get(HIST("hSelectedJetLowRPtZSqTheta"))->SetTitle("Selected jets (low threshold, in emcal only)"); - registry.get(HIST("hSelectedJetLowRPtZThetaSq"))->SetTitle("Selected jets (low threshold, in emcal only)"); - - registry.get(HIST("hSelectedJetRMaxPtEta"))->SetTitle("Leading selected jets (in emcal only) #it{p}_{T} and #eta"); - registry.get(HIST("hSelectedJetRMaxPtPhi"))->SetTitle("Leading selected jets (in emcal only) #it{p}_{T} and #phi"); - registry.get(HIST("hSelectedJetRMaxPtClusterMaxPt"))->SetTitle("Leading selected jets (in emcal only) and clusters"); - - registry.get(HIST("hJetRMaxPtJetPt"))->SetTitle("Leading jet #it{p}_{T} vs jet #it{p}_{T} (in emcal only)"); + if (!b_doLightOutput) { + registry.get(HIST("hSelectedJetLowRPtTrackPt"))->SetTitle("Selected jets (low threshold, in emcal only)"); + registry.get(HIST("hSelectedJetLowRPtClusterPt"))->SetTitle("Selected jets (low threshold, in emcal only)"); + registry.get(HIST("hSelectedJetLowRPtPtd"))->SetTitle("Selected jets (low threshold, in emcal only)"); + registry.get(HIST("hSelectedJetLowRPtChargeFrag"))->SetTitle("Selected jets (low threshold, in emcal only)"); + registry.get(HIST("hSelectedJetLowRPtNEF"))->SetTitle("Selected jets (low threshold, in emcal only)"); + registry.get(HIST("hSelectedJetLowRPtZTheta"))->SetTitle("Selected jets (low threshold, in emcal only)"); + registry.get(HIST("hSelectedJetLowRPtZSqTheta"))->SetTitle("Selected jets (low threshold, in emcal only)"); + registry.get(HIST("hSelectedJetLowRPtZThetaSq"))->SetTitle("Selected jets (low threshold, in emcal only)"); + + registry.get(HIST("hSelectedJetRMaxPtEta"))->SetTitle("Leading selected jets (in emcal only) #it{p}_{T} and #eta"); + registry.get(HIST("hSelectedJetRMaxPtPhi"))->SetTitle("Leading selected jets (in emcal only) #it{p}_{T} and #phi"); + registry.get(HIST("hSelectedJetRMaxPtClusterMaxPt"))->SetTitle("Leading selected jets (in emcal only) and clusters"); + + registry.get(HIST("hJetRMaxPtJetPt"))->SetTitle("Leading jet #it{p}_{T} vs jet #it{p}_{T} (in emcal only)"); + } } } // init @@ -328,16 +380,16 @@ struct JetTriggerQA { double check_dphi(double dphi) const { - if (dphi > TMath::Pi()) { - dphi -= TMath::Pi(); - } else if (dphi <= -1 * TMath::Pi()) { - dphi += TMath::Pi(); + if (dphi > o2::constants::math::PI) { + dphi -= o2::constants::math::PI; + } else if (dphi <= -1 * o2::constants::math::PI) { + dphi += o2::constants::math::PI; } return dphi; } template - Bool_t isJetInEmcal(T const& jet) + bool isJetInEmcal(T const& jet) { double emcalEtaMin = -0.7, emcalEtaMax = 0.7, emcalPhiMin = 1.40, emcalPhiMax = 3.26; // Phi: 80 - 187 deg double R = jet.r() * 1e-2; // Jet R is saved as round(100*R) @@ -351,7 +403,7 @@ struct JetTriggerQA { { std::array selectAliases = {{triggerAliases::kTVXinEMC, triggerAliases::kEMC7, triggerAliases::kDMC7, triggerAliases::kEG1, triggerAliases::kEG2, triggerAliases::kDG1, triggerAliases::kDG2, triggerAliases::kEJ1, triggerAliases::kEJ2, triggerAliases::kDJ1, triggerAliases::kDJ2}}; bool found = false; - for (auto alias : selectAliases) { + for (const auto& alias : selectAliases) { if (collision.alias_bit(alias)) { found = true; break; @@ -360,7 +412,7 @@ struct JetTriggerQA { return found; } - Bool_t isClusterInEmcal(selectedClusters::iterator const& cluster) + bool isClusterInEmcal(selectedClusters::iterator const& cluster) { if (cluster.phi() < f_PhiEmcalOrDcal) { return true; @@ -395,7 +447,7 @@ struct JetTriggerQA { registry.fill(HIST("hTriggerCorrelation"), mainTrigger, assocTrigger); } - std::pair fillGammaQA(const selectedClusters& clusters, std::bitset hwtrg, const std::bitset& triggerstatus) + std::pair fillGammaQA(const selectedClusters& clusters, const std::bitset& hwtrg, const std::bitset& triggerstatus) { auto isTrigger = [&triggerstatus](TriggerType_t triggertype) -> bool { return triggerstatus.test(triggertype); @@ -406,8 +458,6 @@ struct JetTriggerQA { struct ClusterData { float mTriggerObservable; - float mEta; - float mPhi; bool mEMCALcluster; }; std::vector analysedClusters; @@ -421,7 +471,7 @@ struct JetTriggerQA { } bool emcalCluster = isClusterInEmcal(cluster); double clusterObservable = (f_GammaObservable == 0) ? cluster.energy() : cluster.energy() / std::cosh(cluster.eta()); - analysedClusters.push_back({static_cast(clusterObservable), cluster.eta(), cluster.phi(), emcalCluster}); + analysedClusters.push_back({static_cast(clusterObservable), emcalCluster}); if (emcalCluster && (clusterObservable > maxClusterObservableEMCAL)) { maxClusterObservableEMCAL = clusterObservable; @@ -466,85 +516,86 @@ struct JetTriggerQA { registry.fill(HIST("hSelectedGammaDCALPtEtaPhiVeryLow"), clusterObservable, cluster.eta(), cluster.phi()); } } // for clusters - - if (maxClusterObservableEMCAL > 0) { - registry.fill(HIST("hClusterEMCALMaxPtEtaPhi"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); - if (hwtrg.test(EMCALHardwareTrigger::TRG_MB)) { - registry.fill(HIST("hClusterEMCALMaxPtEtaPhiMinBias"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); - } - if (hwtrg.test(EMCALHardwareTrigger::TRG_EMC7)) { - registry.fill(HIST("hClusterEMCALMaxPtEtaPhiLevel0"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); - } - for (const auto& cluster : analysedClusters) { - if (cluster.mEMCALcluster) { - registry.fill(HIST("hClusterEMCALMaxPtClusterEMCALPt"), maxClusterObservableEMCAL, cluster.mTriggerObservable); + if (!b_doLightOutput) { + if (maxClusterObservableEMCAL > 0) { + registry.fill(HIST("hClusterEMCALMaxPtEtaPhi"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); + if (hwtrg.test(EMCALHardwareTrigger::TRG_MB)) { + registry.fill(HIST("hClusterEMCALMaxPtEtaPhiMinBias"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); } - } - if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { - registry.fill(HIST("hSelectedClusterMaxPtEtaPhi"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); - } - if (isTrigger(TriggerType_t::kEmcalGammaVeryHigh)) { - registry.fill(HIST("hSelectedGammaEMCALMaxPtEtaPhiVeryHigh"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); - } - if (isTrigger(TriggerType_t::kEmcalGammaHigh)) { - registry.fill(HIST("hSelectedGammaEMCALMaxPtEtaPhi"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); - } - if (isTrigger(TriggerType_t::kEmcalGammaLow)) { - registry.fill(HIST("hSelectedGammaEMCALMaxPtEtaPhiLow"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); - } - if (isTrigger(TriggerType_t::kEmcalGammaVeryLow)) { - registry.fill(HIST("hSelectedGammaEMCALMaxPtEtaPhiVeryLow"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); - } - } else { - // count events where max. cluster has not been found - registry.fill(HIST("hEventsNoMaxClusterEMCAL"), 1.); - if (hwtrg.test(EMCALHardwareTrigger::TRG_MB)) { - registry.fill(HIST("hEventsNoMaxClusterEMCALMinBias"), 1.); - } - if (hwtrg.test(EMCALHardwareTrigger::TRG_EMC7)) { - registry.fill(HIST("hEventsNoMaxClusterEMCALLevel0"), 1.); - } - } - if (maxClusterObservableDCAL > 0) { - registry.fill(HIST("hClusterDCALMaxPtEtaPhi"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); - if (hwtrg.test(EMCALHardwareTrigger::TRG_MB)) { - registry.fill(HIST("hClusterDCALMaxPtEtaPhiMinBias"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); - } - if (hwtrg.test(EMCALHardwareTrigger::TRG_DMC7)) { - registry.fill(HIST("hClusterDCALMaxPtEtaPhiLevel0"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); - } - for (const auto& cluster : analysedClusters) { - if (!cluster.mEMCALcluster) { - registry.fill(HIST("hClusterDCALMaxPtClusterDCALPt"), maxClusterObservableDCAL, cluster.mTriggerObservable); + if (hwtrg.test(EMCALHardwareTrigger::TRG_EMC7)) { + registry.fill(HIST("hClusterEMCALMaxPtEtaPhiLevel0"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); + } + for (const auto& cluster : analysedClusters) { + if (cluster.mEMCALcluster) { + registry.fill(HIST("hClusterEMCALMaxPtClusterEMCALPt"), maxClusterObservableEMCAL, cluster.mTriggerObservable); + } + } + if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { + registry.fill(HIST("hSelectedClusterMaxPtEtaPhi"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); + } + if (isTrigger(TriggerType_t::kEmcalGammaVeryHigh)) { + registry.fill(HIST("hSelectedGammaEMCALMaxPtEtaPhiVeryHigh"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); + } + if (isTrigger(TriggerType_t::kEmcalGammaHigh)) { + registry.fill(HIST("hSelectedGammaEMCALMaxPtEtaPhi"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); + } + if (isTrigger(TriggerType_t::kEmcalGammaLow)) { + registry.fill(HIST("hSelectedGammaEMCALMaxPtEtaPhiLow"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); + } + if (isTrigger(TriggerType_t::kEmcalGammaVeryLow)) { + registry.fill(HIST("hSelectedGammaEMCALMaxPtEtaPhiVeryLow"), maxClusterObservableEMCAL, maxClusterEMCAL.eta(), maxClusterEMCAL.phi()); + } + } else { + // count events where max. cluster has not been found + registry.fill(HIST("hEventsNoMaxClusterEMCAL"), 1.); + if (hwtrg.test(EMCALHardwareTrigger::TRG_MB)) { + registry.fill(HIST("hEventsNoMaxClusterEMCALMinBias"), 1.); + } + if (hwtrg.test(EMCALHardwareTrigger::TRG_EMC7)) { + registry.fill(HIST("hEventsNoMaxClusterEMCALLevel0"), 1.); } } - if (isTrigger(TriggerType_t::kDcalGammaVeryHigh)) { - registry.fill(HIST("hSelectedGammaDCALMaxPtEtaPhiVeryHigh"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); - } - if (isTrigger(TriggerType_t::kDcalGammaHigh)) { - registry.fill(HIST("hSelectedGammaDCALMaxPtEtaPhi"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); - } - if (isTrigger(TriggerType_t::kDcalGammaLow)) { - registry.fill(HIST("hSelectedGammaDCALMaxPtEtaPhiLow"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); - } - if (isTrigger(TriggerType_t::kDcalGammaVeryLow)) { - registry.fill(HIST("hSelectedGammaDCALMaxPtEtaPhiVeryLow"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); - } - } else { - registry.fill(HIST("hEventsNoMaxClusterDCAL"), 1.); - // count events where max. cluster has not been found - if (hwtrg.test(EMCALHardwareTrigger::TRG_MB)) { - registry.fill(HIST("hEventsNoMaxClusterDCALMinBias"), 1.); - } - if (hwtrg.test(EMCALHardwareTrigger::TRG_DMC7)) { - registry.fill(HIST("hEventsNoMaxClusterDCALLevel0"), 1.); + if (maxClusterObservableDCAL > 0) { + registry.fill(HIST("hClusterDCALMaxPtEtaPhi"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); + if (hwtrg.test(EMCALHardwareTrigger::TRG_MB)) { + registry.fill(HIST("hClusterDCALMaxPtEtaPhiMinBias"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); + } + if (hwtrg.test(EMCALHardwareTrigger::TRG_DMC7)) { + registry.fill(HIST("hClusterDCALMaxPtEtaPhiLevel0"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); + } + for (const auto& cluster : analysedClusters) { + if (!cluster.mEMCALcluster) { + registry.fill(HIST("hClusterDCALMaxPtClusterDCALPt"), maxClusterObservableDCAL, cluster.mTriggerObservable); + } + } + if (isTrigger(TriggerType_t::kDcalGammaVeryHigh)) { + registry.fill(HIST("hSelectedGammaDCALMaxPtEtaPhiVeryHigh"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); + } + if (isTrigger(TriggerType_t::kDcalGammaHigh)) { + registry.fill(HIST("hSelectedGammaDCALMaxPtEtaPhi"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); + } + if (isTrigger(TriggerType_t::kDcalGammaLow)) { + registry.fill(HIST("hSelectedGammaDCALMaxPtEtaPhiLow"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); + } + if (isTrigger(TriggerType_t::kDcalGammaVeryLow)) { + registry.fill(HIST("hSelectedGammaDCALMaxPtEtaPhiVeryLow"), maxClusterObservableDCAL, maxClusterDCAL.eta(), maxClusterDCAL.phi()); + } + } else { + registry.fill(HIST("hEventsNoMaxClusterDCAL"), 1.); + // count events where max. cluster has not been found + if (hwtrg.test(EMCALHardwareTrigger::TRG_MB)) { + registry.fill(HIST("hEventsNoMaxClusterDCALMinBias"), 1.); + } + if (hwtrg.test(EMCALHardwareTrigger::TRG_DMC7)) { + registry.fill(HIST("hEventsNoMaxClusterDCALLevel0"), 1.); + } } } return std::make_pair(maxClusterObservableEMCAL, maxClusterObservableDCAL); } 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,91 +619,101 @@ 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()) { - auto trackPt = track.pt(); - auto chargeFrag = track.px() * jet.px() + track.py() * jet.py() + track.pz() * jet.pz(); - chargeFrag /= (jet.p() * jet.p()); - auto z = trackPt / jetPt; - auto dphi = jet.phi() - track.phi(); - dphi = check_dphi(dphi); - auto dR = TMath::Sqrt(dphi * dphi + TMath::Power(jet.eta() - track.eta(), 2)); - zTheta += z * dR / jetR; - zSqTheta += z * z * dR / jetR; - zThetaSq += z * dR * dR / (jetR * jetR); - ptD += z * z; - registry.fill(HIST("hJetRPtTrackPt"), jetR, jetPt, trackPt); - registry.fill(HIST("hJetRPtChargeFrag"), jetR, jetPt, chargeFrag); - if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { - registry.fill(HIST("hSelectedJetRPtTrackPt"), jetR, jetPt, trackPt); - registry.fill(HIST("hSelectedJetRPtChargeFrag"), jetR, jetPt, chargeFrag); - } - if (isTrigger(TriggerType_t::kEmcalJetFullLow) || isTrigger(TriggerType_t::kEmcalJetNeutralLow)) { - registry.fill(HIST("hSelectedJetLowRPtTrackPt"), jetR, jetPt, trackPt); - registry.fill(HIST("hSelectedJetLowRPtChargeFrag"), jetR, jetPt, chargeFrag); - } - } // for tracks in jet + if (!b_doLightOutput) { + for (const 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()); + auto z = trackPt / jetPt; + auto dphi = jet.phi() - track.phi(); + dphi = check_dphi(dphi); + auto dR = std::sqrt(dphi * dphi + std::pow(jet.eta() - track.eta(), 2)); + zTheta += z * dR / jetR; + zSqTheta += z * z * dR / jetR; + zThetaSq += z * dR * dR / (jetR * jetR); + ptD += z * z; + registry.fill(HIST("hJetRPtTrackPt"), jetR, jetPt, trackPt); + registry.fill(HIST("hJetRPtChargeFrag"), jetR, jetPt, chargeFrag); + if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { + registry.fill(HIST("hSelectedJetRPtTrackPt"), jetR, jetPt, trackPt); + registry.fill(HIST("hSelectedJetRPtChargeFrag"), jetR, jetPt, chargeFrag); + } + if (isTrigger(TriggerType_t::kEmcalJetFullLow) || isTrigger(TriggerType_t::kEmcalJetNeutralLow)) { + registry.fill(HIST("hSelectedJetLowRPtTrackPt"), jetR, jetPt, trackPt); + registry.fill(HIST("hSelectedJetLowRPtChargeFrag"), jetR, jetPt, chargeFrag); + } + } // for tracks in jet + } // auto clustersInJet = jetClusterConstituents.sliceBy(perJetClusterConstituents, jet.globalIndex()); // for (const auto& clusterList : clustersInJet) { - for (auto& cluster : jet.template clusters_as()) { - auto clusterPt = cluster.energy() / std::cosh(cluster.eta()); - neutralEnergyFraction += cluster.energy(); - auto z = clusterPt / jetPt; - auto dphi = jet.phi() - cluster.phi(); - dphi = check_dphi(dphi); - auto dR = TMath::Sqrt(dphi * dphi + TMath::Power(jet.eta() - cluster.eta(), 2)); - zTheta += z * dR / jetR; - zSqTheta += z * z * dR / jetR; - zThetaSq += z * dR * dR / (jetR * jetR); - ptD += z * z; - registry.fill(HIST("hJetRPtClusterPt"), jetR, jetPt, clusterPt); - if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { - registry.fill(HIST("hSelectedJetRPtClusterPt"), jetR, jetPt, clusterPt); - } - if (isTrigger(TriggerType_t::kEmcalJetFullLow) || isTrigger(TriggerType_t::kEmcalJetNeutralLow)) { - registry.fill(HIST("hSelectedJetLowRPtClusterPt"), jetR, jetPt, clusterPt); - } - } // for clusters in jet + if (!b_doLightOutput) { + for (const auto& cluster : jet.template clusters_as()) { + auto clusterPt = cluster.energy() / std::cosh(cluster.eta()); + neutralEnergyFraction += cluster.energy(); + auto z = clusterPt / jetPt; + auto dphi = jet.phi() - cluster.phi(); + dphi = check_dphi(dphi); + auto dR = std::sqrt(dphi * dphi + std::pow(jet.eta() - cluster.eta(), 2)); + zTheta += z * dR / jetR; + zSqTheta += z * z * dR / jetR; + zThetaSq += z * dR * dR / (jetR * jetR); + ptD += z * z; + registry.fill(HIST("hJetRPtClusterPt"), jetR, jetPt, clusterPt); + if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { + registry.fill(HIST("hSelectedJetRPtClusterPt"), jetR, jetPt, clusterPt); + } + if (isTrigger(TriggerType_t::kEmcalJetFullLow) || isTrigger(TriggerType_t::kEmcalJetNeutralLow)) { + registry.fill(HIST("hSelectedJetLowRPtClusterPt"), jetR, jetPt, clusterPt); + } + } // for clusters in jet + } neutralEnergyFraction /= jet.energy(); - ptD = TMath::Sqrt(ptD); + ptD = std::sqrt(ptD); // Fillng histograms registry.fill(HIST("hJetRPtEta"), jetR, jetPt, jet.eta()); registry.fill(HIST("hJetRPtPhi"), jetR, jetPt, jet.phi()); - registry.fill(HIST("hJetRPtPtd"), jetR, jetPt, ptD); - registry.fill(HIST("hJetRPtNEF"), jetR, jetPt, neutralEnergyFraction); - registry.fill(HIST("hJetRPtZTheta"), jetR, jetPt, zTheta); - registry.fill(HIST("hJetRPtZSqTheta"), jetR, jetPt, zSqTheta); - registry.fill(HIST("hJetRPtZThetaSq"), jetR, jetPt, zThetaSq); + if (!b_doLightOutput) { + registry.fill(HIST("hJetRPtPtd"), jetR, jetPt, ptD); + registry.fill(HIST("hJetRPtNEF"), jetR, jetPt, neutralEnergyFraction); + registry.fill(HIST("hJetRPtZTheta"), jetR, jetPt, zTheta); + registry.fill(HIST("hJetRPtZSqTheta"), jetR, jetPt, zSqTheta); + registry.fill(HIST("hJetRPtZThetaSq"), jetR, jetPt, zThetaSq); + } registry.get(HIST("jetRPtEtaPhi"))->Fill(jetR, jetPt, jet.eta(), jet.phi()); if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { registry.fill(HIST("hSelectedJetRPtEta"), jetR, jetPt, jet.eta()); registry.fill(HIST("hSelectedJetRPtPhi"), jetR, jetPt, jet.phi()); - registry.fill(HIST("hSelectedJetRPtPtd"), jetR, jetPt, ptD); - registry.fill(HIST("hSelectedJetRPtNEF"), jetR, jetPt, neutralEnergyFraction); - registry.fill(HIST("hSelectedJetRPtZTheta"), jetR, jetPt, zTheta); - registry.fill(HIST("hSelectedJetRPtZSqTheta"), jetR, jetPt, zSqTheta); - registry.fill(HIST("hSelectedJetRPtZThetaSq"), jetR, jetPt, zThetaSq); + if (!b_doLightOutput) { + registry.fill(HIST("hSelectedJetRPtPtd"), jetR, jetPt, ptD); + registry.fill(HIST("hSelectedJetRPtNEF"), jetR, jetPt, neutralEnergyFraction); + registry.fill(HIST("hSelectedJetRPtZTheta"), jetR, jetPt, zTheta); + registry.fill(HIST("hSelectedJetRPtZSqTheta"), jetR, jetPt, zSqTheta); + registry.fill(HIST("hSelectedJetRPtZThetaSq"), jetR, jetPt, zThetaSq); + } } if (isTrigger(TriggerType_t::kEmcalJetFullLow) || isTrigger(TriggerType_t::kEmcalJetNeutralLow)) { registry.fill(HIST("hSelectedJetLowRPtEta"), jetR, jetPt, jet.eta()); registry.fill(HIST("hSelectedJetLowRPtPhi"), jetR, jetPt, jet.phi()); - registry.fill(HIST("hSelectedJetLowRPtPtd"), jetR, jetPt, ptD); - registry.fill(HIST("hSelectedJetLowRPtNEF"), jetR, jetPt, neutralEnergyFraction); - registry.fill(HIST("hSelectedJetLowRPtZTheta"), jetR, jetPt, zTheta); - registry.fill(HIST("hSelectedJetLowRPtZSqTheta"), jetR, jetPt, zSqTheta); - registry.fill(HIST("hSelectedJetLowRPtZThetaSq"), jetR, jetPt, zThetaSq); + if (!b_doLightOutput) { + registry.fill(HIST("hSelectedJetLowRPtPtd"), jetR, jetPt, ptD); + registry.fill(HIST("hSelectedJetLowRPtNEF"), jetR, jetPt, neutralEnergyFraction); + registry.fill(HIST("hSelectedJetLowRPtZTheta"), jetR, jetPt, zTheta); + registry.fill(HIST("hSelectedJetLowRPtZSqTheta"), jetR, jetPt, zSqTheta); + registry.fill(HIST("hSelectedJetLowRPtZThetaSq"), jetR, jetPt, zThetaSq); + } } } // for jets 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 +749,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); } @@ -765,72 +822,78 @@ struct JetTriggerQA { std::array foundMaxJet; std::fill(foundMaxJet.begin(), foundMaxJet.end(), false); - for (auto maxJet : vecMaxJet) { - double jetR = maxJet.r() * 1e-2, jetPt = maxJet.pt(), jetEta = maxJet.eta(), jetPhi = maxJet.phi(); - foundMaxJet[static_cast(maxJet.r() * 1e-1) - 2] = true; - registry.fill(HIST("hJetRMaxPtEta"), jetR, jetPt, jetEta); - registry.fill(HIST("hJetRMaxPtPhi"), jetR, jetPt, jetPhi); - if (hardwaretriggers.test(EMCALHardwareTrigger::TRG_MB)) { - registry.fill(HIST("hJetRMaxPtEtaMinBias"), jetR, jetPt, jetEta); - registry.fill(HIST("hJetRMaxPtPhiMinBias"), jetR, jetPt, jetPhi); - } - if (hardwaretriggers.test(EMCALHardwareTrigger::TRG_EMC7)) { - registry.fill(HIST("hJetRMaxPtEtaLevel0"), jetR, jetPt, jetEta); - registry.fill(HIST("hJetRMaxPtPhiLevel0"), jetR, jetPt, jetPhi); - } - // hJetRMaxPtEtaPhi->Fill(jetR, jetPt, jetEta, jetPhi); - registry.get(HIST("jetRMaxPtEtaPhi"))->Fill(jetR, jetPt, jetEta, jetPhi); - if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { - registry.fill(HIST("hSelectedJetRMaxPtEta"), jetR, jetPt, jetEta); - registry.fill(HIST("hSelectedJetRMaxPtPhi"), jetR, jetPt, jetPhi); - } - if (isTrigger(TriggerType_t::kEmcalJetFullLow) || isTrigger(TriggerType_t::kEmcalJetNeutralLow)) { - registry.fill(HIST("hSelectedJetLowRMaxPtEta"), jetR, jetPt, jetEta); - registry.fill(HIST("hSelectedJetLowRMaxPtPhi"), jetR, jetPt, jetPhi); - } - if (maxClusterObservableEMCAL > 0) { - registry.fill(HIST("hJetRMaxPtClusterMaxPt"), jetR, jetPt, maxClusterObservableEMCAL); + if (!b_doLightOutput) { + for (const auto& maxJet : vecMaxJet) { + double jetR = maxJet.r() * 1e-2, jetPt = maxJet.pt(), jetEta = maxJet.eta(), jetPhi = maxJet.phi(); + foundMaxJet[static_cast(maxJet.r() * 1e-1) - 2] = true; + registry.fill(HIST("hJetRMaxPtEta"), jetR, jetPt, jetEta); + registry.fill(HIST("hJetRMaxPtPhi"), jetR, jetPt, jetPhi); + if (hardwaretriggers.test(EMCALHardwareTrigger::TRG_MB)) { + registry.fill(HIST("hJetRMaxPtEtaMinBias"), jetR, jetPt, jetEta); + registry.fill(HIST("hJetRMaxPtPhiMinBias"), jetR, jetPt, jetPhi); + } + if (hardwaretriggers.test(EMCALHardwareTrigger::TRG_EMC7)) { + registry.fill(HIST("hJetRMaxPtEtaLevel0"), jetR, jetPt, jetEta); + registry.fill(HIST("hJetRMaxPtPhiLevel0"), jetR, jetPt, jetPhi); + } + // hJetRMaxPtEtaPhi->Fill(jetR, jetPt, jetEta, jetPhi); + registry.get(HIST("jetRMaxPtEtaPhi"))->Fill(jetR, jetPt, jetEta, jetPhi); if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { - registry.fill(HIST("hSelectedJetRMaxPtClusterMaxPt"), jetR, jetPt, maxClusterObservableEMCAL); + registry.fill(HIST("hSelectedJetRMaxPtEta"), jetR, jetPt, jetEta); + registry.fill(HIST("hSelectedJetRMaxPtPhi"), jetR, jetPt, jetPhi); + } + if (isTrigger(TriggerType_t::kEmcalJetFullLow) || isTrigger(TriggerType_t::kEmcalJetNeutralLow)) { + registry.fill(HIST("hSelectedJetLowRMaxPtEta"), jetR, jetPt, jetEta); + registry.fill(HIST("hSelectedJetLowRMaxPtPhi"), jetR, jetPt, jetPhi); } - } // if maxClusterPt - if (maxJet.r() == std::round(f_jetR * 100)) { - for (const auto& jet : jets) { - if (isJetInEmcal(jet)) { - registry.fill(HIST("hJetRMaxPtJetPt"), jet.r() * 1e-2, jetPt, jet.pt()); + if (maxClusterObservableEMCAL > 0) { + registry.fill(HIST("hJetRMaxPtClusterMaxPt"), jetR, jetPt, maxClusterObservableEMCAL); + if (isTrigger(TriggerType_t::kEmcalJetFull) || isTrigger(TriggerType_t::kEmcalJetNeutral)) { + registry.fill(HIST("hSelectedJetRMaxPtClusterMaxPt"), jetR, jetPt, maxClusterObservableEMCAL); } - } // for jets - } // if maxJet.r() == std::round(f_jetR * 100) - } // for maxJet + } // if maxClusterPt + if (maxJet.r() == std::round(f_jetR * 100)) { + for (const auto& jet : jets) { + if (isJetInEmcal(jet)) { + registry.fill(HIST("hJetRMaxPtJetPt"), jet.r() * 1e-2, jetPt, jet.pt()); + } + } // for jets + } // 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]) { - double rval = static_cast(ir) / 10.; - registry.fill(HIST("hEventsNoMaxJet"), rval); - if (hardwaretriggers.test(EMCALHardwareTrigger::TRG_MB)) { - registry.fill(HIST("hEventsNoMaxJetMinBias"), rval); - } - if (hardwaretriggers.test(EMCALHardwareTrigger::TRG_EMC7)) { - registry.fill(HIST("hEventsNoMaxJetLevel0"), rval); + if (!b_doLightOutput) { + for (std::size_t ir = 0; ir < foundMaxJet.size(); ir++) { + if (!foundMaxJet[ir]) { + double rval = static_cast(ir) / 10.; + registry.fill(HIST("hEventsNoMaxJet"), rval); + if (hardwaretriggers.test(EMCALHardwareTrigger::TRG_MB)) { + registry.fill(HIST("hEventsNoMaxJetMinBias"), rval); + } + if (hardwaretriggers.test(EMCALHardwareTrigger::TRG_EMC7)) { + registry.fill(HIST("hEventsNoMaxJetLevel0"), rval); + } } } } - for (auto maxJet : vecMaxJetNoFiducial) { - double jetR = maxJet.r() * 1e-2, jetPt = maxJet.pt(), jetEta = maxJet.eta(), jetPhi = maxJet.phi(); - // hJetRMaxPtEtaPhiNoFiducial->Fill(jetR, jetPt, jetEta, jetPhi); - registry.get(HIST("jetRMaxPtEtaPhiNoFiducial"))->Fill(jetR, jetPt, jetEta, jetPhi); - if (maxJet.r() == std::round(f_jetR * 100)) { - 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 (!b_doLightOutput) { + for (const auto& maxJet : vecMaxJetNoFiducial) { + double jetR = maxJet.r() * 1e-2, jetPt = maxJet.pt(), jetEta = maxJet.eta(), jetPhi = maxJet.phi(); + // hJetRMaxPtEtaPhiNoFiducial->Fill(jetR, jetPt, jetEta, jetPhi); + registry.get(HIST("jetRMaxPtEtaPhiNoFiducial"))->Fill(jetR, jetPt, jetEta, jetPhi); + if (maxJet.r() == std::round(f_jetR * 100)) { + 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 + } } // 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 +902,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..3f31fbb244e --- /dev/null +++ b/PWGJE/Tasks/gammaJetTreeProducer.cxx @@ -0,0 +1,1313 @@ +// 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 gammaJetTreeProducer.cxx +/// \brief Task to produce a tree for gamma-jet analysis, including photons (and information of isolation) and charged jets +/// \author Florian Jonas , UC Berkeley/LBNL +/// \since 02.08.2024 + +// C++ system headers first +#include + +#include +#include +#include + +// Framework and other headers after +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/GammaJetAnalysisTree.h" +#include "PWGJE/DataModel/Jet.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 "EventFiltering/filterTables.h" + +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsEMCAL/AnalysisCluster.h" +#include "DataFormatsEMCAL/Cell.h" +#include "DataFormatsEMCAL/Constants.h" +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "TVector2.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; +using emcMCClusters = o2::soa::Join; + +#include "Framework/runDataProcessing.h" + +struct GammaJetTreeProducer { + // analysis tree + // charged jets + // photon candidates + Produces chargedJetsTable; // detector level jets + Produces eventsTable; // rec events + Produces gammasTable; // detector level clusters + Produces mcEventsTable; // mc collisions information + Produces mcParticlesTable; // gen level particles (photons and pi0) + Produces gammaMCInfosTable; // detector level clusters MC information + Produces chJetMCInfosTable; // detector level charged jets MC information + Produces mcJetsTable; // gen level jets + + HistogramRegistry mHistograms{"GammaJetTreeProducerHisto"}; + + Service pdg; + + // --------------- + // 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"}; + Configurable minMCGenPt{"minMCGenPt", 0.0, "minimum pt of mc gen particles to store"}; + + int mRunNumber = 0; + std::vector eventSelectionBits; + int trackSelection = -1; + const int kMaxRecursionDepth = 100; + + std::unordered_map collisionMapping; + std::unordered_map mcJetIndexMapping; // maps the global index to the index in the mc jets table (per event). This is because later we want to later construct all trees on a per event level, and we need to know at what position in the table per event this is stored + std::vector triggerMaskBits; + std::vector mcCollisionsMultiRecCollisions; // used for MC. global index of MC collisions that have multiple matched rec collisions + + // kd tree for tracks and mc particles (used for fast isolation calculation) + std::vector trackEta; + std::vector trackPhi; + std::vector trackPt; + std::vector mcParticleEta; + std::vector mcParticlePhi; + std::vector mcParticlePt; + TKDTree* trackTree = nullptr; + TKDTree* mcParticleTree = nullptr; + + 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 ptRecAxis{100, 0, 200, "p_{T}^{rec} (GeV/c)"}; + const o2Axis ptGenAxis{100, 0, 200, "p_{T}^{gen} (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, o2::constants::math::TwoPI, "#phi"}; + const o2Axis dRAxis{100, 0, 1, "dR"}; + const o2Axis occupancyAxis{300, 0, 30000, "occupancy"}; + const o2Axis nCollisionsAxis{10, -0.5, 9.5, "nCollisions"}; + 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, {ptRecAxis, ptGenAxis}); + + // 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}); + + // QA for MC collisions to rec collision matching + // number of reconstructed and matched collisions for each MC collision vs mc gen photon energy + mHistograms.add("numberRecCollisionsVsPhotonPt", "Number of rec collisions vs photon energy", o2HistType::kTH2F, {nCollisionsAxis, energyAxis}); + + // Cluster MC histograms + mHistograms.add("clusterMC_E_All", "Cluster energy for photons", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_Photon", "Cluster energy for photons", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_PromptPhoton", "Cluster energy for prompt photons", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_DirectPromptPhoton", "Cluster energy for direct prompt photons", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_FragmentationPhoton", "Cluster energy for fragmentation photons", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_DecayPhoton", "Cluster energy for decay photons", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_DecayPhotonPi0", "Cluster energy for decay photons from pi0", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_DecayPhotonEta", "Cluster energy for decay photons from eta", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_MergedPi0", "Cluster energy for merged pi0s", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_MergedEta", "Cluster energy for merged etas", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_E_ConvertedPhoton", "Cluster energy for converted photons", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("clusterMC_m02_Photon", "M02 for photons", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_PromptPhoton", "M02 for prompt photons", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_DirectPromptPhoton", "M02 for direct prompt photons", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_FragmentationPhoton", "M02 for fragmentation photons", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_DecayPhoton", "M02 for decay photons", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_DecayPhotonPi0", "M02 for decay photons from pi0", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_DecayPhotonEta", "M02 for decay photons from eta", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_MergedPi0", "M02 for merged pi0s", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_MergedEta", "M02 for merged etas", o2HistType::kTH1F, {m02Axis}); + mHistograms.add("clusterMC_m02_ConvertedPhoton", "M02 for converted photons", o2HistType::kTH1F, {m02Axis}); + + // MC Gen trigger particle histograms + mHistograms.add("mcGenTrigger_Eta", "eta of mc gen trigger particle", o2HistType::kTH1F, {etaAxis}); + mHistograms.add("mcGenTrigger_Phi", "phi of mc gen trigger particle", o2HistType::kTH1F, {phiAxis}); + mHistograms.add("mcGenTrigger_Pt", "pT of mc gen trigger particle", o2HistType::kTH1F, {ptAxis}); + mHistograms.add("mcGenTrigger_E", "E of mc gen trigger particle", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("mcGenTrigger_E_PromptPhoton", "E of mc gen trigger prompt photon", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("mcGenTrigger_E_DirectPromptPhoton", "E of mc gen trigger direct prompt photon", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("mcGenTrigger_E_FragmentationPhoton", "E of mc gen trigger fragmentation photon", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("mcGenTrigger_E_DecayPhoton", "E of mc gen trigger decay photon", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("mcGenTrigger_E_DecayPhotonPi0", "E of mc gen trigger decay photon from pi0", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("mcGenTrigger_E_DecayPhotonEta", "E of mc gen trigger decay photon from eta", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("mcGenTrigger_E_DecayPhotonOther", "E of mc gen trigger decay photon from other", o2HistType::kTH1F, {energyAxis}); + mHistograms.add("mcGenTrigger_E_Pi0", "E of mc gen trigger pi0", o2HistType::kTH1F, {energyAxis}); + + // MC Particle level jet histograms + mHistograms.add("mcpJetPt", "pT of mc particle level jet", o2HistType::kTH1F, {ptAxis}); + + // MC Detector level jet matching jet histograms + mHistograms.add("mcdJetPtVsTrueJetPtMatchingGeo", "pT rec (x-axis) of detector level jets vs pT true (y-axis) of mc particle level jet (geo matching)", o2HistType::kTH2F, {ptRecAxis, ptGenAxis}); + mHistograms.add("mcdJetPtVsTrueJetPtMatchingPt", "pT rec (x-axis) of detector level jets vs pT true (y-axis) of mc particle level jet (pt matching)", o2HistType::kTH2F, {ptRecAxis, ptGenAxis}); + + // Event QA histogram + const int nEventBins = 8; + const TString eventLabels[nEventBins] = {"All", "AfterVertexCut", "AfterCollisionSelection", "AfterTriggerSelection", "AfterEMCALSelection", "AfterClusterESelection", "Has MC collision", "is not MB Gap"}; + mHistograms.add("eventQA", "Event QA", o2HistType::kTH1F, {{nEventBins, -0.5, 7.5}}); + for (int iBin = 0; iBin < nEventBins; iBin++) { + mHistograms.get(HIST("eventQA"))->GetXaxis()->SetBinLabel(iBin + 1, eventLabels[iBin]); + } + + // MC collisions QA histograms) + const int nRecCollisionBins = 4; + const TString recCollisionLabels[nRecCollisionBins] = {"All", "1 Rec collision", "More than 1 rec collisions", "No rec collisions"}; + mHistograms.add("mcCollisionsWithRecCollisions", "MC collisions with rec collisions", o2HistType::kTH1F, {{nRecCollisionBins, -0.5, 3.5}}); + for (int iBin = 0; iBin < nRecCollisionBins; iBin++) { + mHistograms.get(HIST("mcCollisionsWithRecCollisions"))->GetXaxis()->SetBinLabel(iBin + 1, recCollisionLabels[iBin]); + } + } + + // --------------------- + // Helper functions + // --------------------- + + /// \brief Builds the kd tree for the tracks or mc particles (used for fast isolation calculation) + /// \param objects The objects to build the kd tree for (tracks or mc particles) + template + void buildKdTree(const T& objects) + { + trackEta.clear(); + trackPhi.clear(); + trackPt.clear(); + mcParticleEta.clear(); + mcParticlePhi.clear(); + mcParticlePt.clear(); + + // if the track type is aod::JetTracks, we need to build the kd tree for the tracks + if constexpr (std::is_same_v, aod::JetTracks>) { + for (const auto& track : objects) { + if (!isTrackSelected(track)) { + continue; + } + trackEta.push_back(track.eta()); + trackPhi.push_back(track.phi()); + trackPt.push_back(track.pt()); + } + if (trackEta.size() > 0) { + delete trackTree; + trackTree = new TKDTree(trackEta.size(), 2, 1); + trackTree->SetData(0, trackEta.data()); + trackTree->SetData(1, trackPhi.data()); + trackTree->Build(); + } + } + // if the track type is aod::JetParticles, we need to build the kd tree for the mc particles + if constexpr (std::is_same_v, aod::JetParticles>) { + for (const auto& particle : objects) { + if (!particle.isPhysicalPrimary()) { + continue; + } + if (!isCharged(particle)) { + continue; + } + if (particle.pt() < trackMinPt) { + continue; + } + mcParticleEta.push_back(particle.eta()); + mcParticlePhi.push_back(particle.phi()); + mcParticlePt.push_back(particle.pt()); + } + if (mcParticleEta.size() > 0) { + delete mcParticleTree; + mcParticleTree = new TKDTree(mcParticleEta.size(), 2, 1); + mcParticleTree->SetData(0, mcParticleEta.data()); + mcParticleTree->SetData(1, mcParticlePhi.data()); + mcParticleTree->Build(); + } + } + } + /// \brief Checks if a track passes the selection criteria + /// \param track The track to be checked + /// \return true if track passes all selection criteria, false otherwise + bool isTrackSelected(const auto& track) + { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + return false; + } + if (track.pt() < trackMinPt) { + return false; + } + + return true; + } + + /// \brief Gets the stored collision index from the collision mapping + /// \param collision The collision to look up + /// \return The stored collision index, or -1 if not found + int getStoredColIndex(const auto& collision) + { + int32_t storedColIndex = -1; + if (auto foundCol = collisionMapping.find(collision.globalIndex()); foundCol != collisionMapping.end()) { + storedColIndex = foundCol->second; + } + return storedColIndex; + } + + /// \brief Checks if an event passes all selection criteria + /// \param collision The collision to check + /// \param clusters The EMCAL clusters in the event + /// \return true if event passes all selection criteria, false otherwise + bool isEventAccepted(const auto& collision, const auto& clusters) + { + mHistograms.fill(HIST("eventQA"), 0); + + if (collision.posZ() > mVertexCut) { + return false; + } + mHistograms.fill(HIST("eventQA"), 1); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return false; + } + mHistograms.fill(HIST("eventQA"), 2); + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return false; + } + mHistograms.fill(HIST("eventQA"), 3); + if (!jetderiveddatautilities::eventEMCAL(collision)) { + return false; + } + mHistograms.fill(HIST("eventQA"), 4); + + // Check if event contains a cluster with energy > minClusterETrigger + for (const auto& cluster : clusters) { + if (cluster.energy() > minClusterETrigger) { + mHistograms.fill(HIST("eventQA"), 5); + return true; + } + } + return false; + } + + /// \brief Checks if a particle is charged + /// \param particle The MC particle to check + /// \return true if particle has non-zero charge, false otherwise + bool isCharged(const auto& particle) + { + return std::abs(pdg->GetParticle(particle.pdgCode())->Charge()) >= 1.; + } + + /// \brief Calculates the charged particle isolation in a cone of given size using a pre-built kd tree + /// \param particle The particle to calculate the isolation for + /// \param radius The cone radius + /// \param mcGenIso Whether to use the mc gen particle tree (if false, use the track tree) + /// \return The charged particle isolation + template + double ch_iso_in_cone(const T& particle, float radius = 0.4, bool mcGenIso = false) + { + double iso = 0; + float point[2] = {particle.eta(), particle.phi()}; + std::vector indices; + + if (!mcGenIso) { + if (trackTree) { + trackTree->FindInRange(point, radius, indices); + for (const auto& index : indices) { + iso += trackPt[index]; + } + } else { + LOG(error) << "Track tree not found"; + return 0; + } + } else { + if (mcParticleTree) { + mcParticleTree->FindInRange(point, radius, indices); + for (const auto& index : indices) { + iso += mcParticlePt[index]; + } + } else { + LOG(error) << "MC particle tree not found"; + return 0; + } + } + return iso; + } + + /// \brief Calculates the charged particle density in perpendicular cones + /// \param object The reference object (cluster or jet) + /// \param tracks The tracks to check + /// \param radius The cone radius for density calculation + /// \return The average charged particle density in the perpendicular cones + template + double ch_perp_cone_rho(const T& object, float radius = 0.4, bool mcGenIso = false) + { + double ptSumLeft = 0; + double ptSumRight = 0; + + double cPhi = TVector2::Phi_0_2pi(object.phi()); + + // rotate cone left by 90 degrees + float cPhiLeft = cPhi - o2::constants::math::PIHalf; + float cPhiRight = cPhi + o2::constants::math::PIHalf; + + float pointLeft[2] = {object.eta(), cPhiLeft}; + float pointRight[2] = {object.eta(), cPhiRight}; + + std::vector indicesLeft; + std::vector indicesRight; + + if (!mcGenIso) { + if (trackTree) { + trackTree->FindInRange(pointLeft, radius, indicesLeft); + trackTree->FindInRange(pointRight, radius, indicesRight); + } else { + LOG(error) << "Track tree not found"; + return 0; + } + + for (const auto& index : indicesLeft) { + ptSumLeft += trackPt[index]; + } + for (const auto& index : indicesRight) { + ptSumRight += trackPt[index]; + } + } else { + if (mcParticleTree) { + mcParticleTree->FindInRange(pointLeft, radius, indicesLeft); + mcParticleTree->FindInRange(pointRight, radius, indicesRight); + } else { + LOG(error) << "MC particle tree not found"; + return 0; + } + for (const auto& index : indicesLeft) { + ptSumLeft += mcParticlePt[index]; + } + for (const auto& index : indicesRight) { + ptSumRight += mcParticlePt[index]; + } + } + + float rho = (ptSumLeft + ptSumRight) / (o2::constants::math::TwoPI * radius * radius); + return rho; + } + + /// \brief Fills track QA histograms for a given collision + /// \param collision The collision containing the tracks + /// \param tracks The tracks to analyze + void runTrackQA(const auto& collision, aod::JetTracks const& tracks) + { + for (const 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()); + } + } + + /// \brief Finds the top-most copy of a particle in the decay chain (following carbon copies) + /// \param particle The particle to start from + /// \return The top-most copy of the particle + template + T iTopCopy(const T& particle) const + { + int iUp = particle.globalIndex(); + T currentParticle = particle; + int pdgCode = particle.pdgCode(); + auto mothers = particle.template mothers_as(); + while (iUp > 0 && mothers.size() == 1 && mothers[0].globalIndex() > 0 && mothers[0].pdgCode() == pdgCode) { + iUp = mothers[0].globalIndex(); + currentParticle = mothers[0]; + mothers = currentParticle.template mothers_as(); + } + return currentParticle; + } + + /// \brief Checks if a particle is a prompt photon + /// \param particle The MC particle to check + /// \return true if particle is a prompt photon, false otherwise + bool isPromptPhoton(const auto& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) < 90) { + return true; + } + return false; + } + /// \brief Checks if a particle is a direct prompt photon + /// \param particle The particle to check + /// \return true if particle is a direct prompt photon, false otherwise + bool isDirectPromptPhoton(const auto& particle) + { + // check if particle isa prompt photon + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) < 90) { + // find the top carbon copy + auto topCopy = iTopCopy(particle); + if (topCopy.pdgCode() == PDG_t::kGamma && std::abs(topCopy.getGenStatusCode()) < 40) { // < 40 is particle directly produced in hard scattering + return true; + } + } + return false; + } + /// \brief Checks if a particle is a fragmentation photon + /// \param particle The particle to check + /// \return true if particle is a fragmentation photon, false otherwise + bool isFragmentationPhoton(const auto& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) < 90) { + // find the top carbon copy + auto topCopy = iTopCopy(particle); + if (topCopy.pdgCode() == PDG_t::kGamma && std::abs(topCopy.getGenStatusCode()) >= 40) { // frag photon + return true; + } + } + return false; + } + /// \brief Checks if a particle is a decay photon + /// \param particle The particle to check + /// \return true if particle is a decay photon, false otherwise + bool isDecayPhoton(const auto& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) >= 90) { + return true; + } + return false; + } + /// \brief Checks if a particle is a decay photon from pi0 + /// \param particle The particle to check + /// \return true if particle is a decay photon from pi0, false otherwise + template + bool isDecayPhotonPi0(const T& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) >= 90) { + // check if it has mothers that are pi0s + const auto& mothers = particle.template mothers_as(); + for (const auto& mother : mothers) { + if (mother.pdgCode() == PDG_t::kPi0) { + return true; + } + } + } + return false; + } + /// \brief Checks if a particle is a decay photon from eta + /// \param particle The particle to check + /// \return true if particle is a decay photon from eta, false otherwise + template + bool isDecayPhotonEta(const T& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) >= 90) { + // check if it has mothers that are etas + const auto& mothers = particle.template mothers_as(); + for (const auto& mother : mothers) { + if (mother.pdgCode() == 221) { + return true; + } + } + } + return false; + } + /// \brief Checks if a particle is a decay photon from other sources + /// \param particle The particle to check + /// \return true if particle is a decay photon from other sources, false otherwise + template + bool isDecayPhotonOther(const T& particle) + { + if (particle.pdgCode() == PDG_t::kGamma && particle.isPhysicalPrimary() && std::abs(particle.getGenStatusCode()) >= 90) { + // check if you find a pi0 mother or a eta mother + const auto& mothers = particle.template mothers_as(); + for (const auto& mother : mothers) { + if (mother.pdgCode() == PDG_t::kPi0 || mother.pdgCode() == 221) { + return false; + } + } + return true; + } + return false; + } + /// \brief Checks if a particle is a pi0 + /// \param particle The particle to check + /// \return true if particle is a pi0, false otherwise + bool isPi0(const auto& particle) + { + if (particle.pdgCode() == PDG_t::kPi0) { + return true; + } + return false; + } + + /// \brief Gets the bitmap for a MC particle that indicated what type of particle it is + /// \param particle The particle to check + /// \return A bitmap indicating the particle's origin + uint16_t getMCParticleOrigin(const auto& particle) + { + uint16_t origin = 0; + if (isPromptPhoton(particle)) { + SETBIT(origin, static_cast(gjanalysis::ParticleOrigin::kPromptPhoton)); + } + if (isDirectPromptPhoton(particle)) { + SETBIT(origin, static_cast(gjanalysis::ParticleOrigin::kDirectPromptPhoton)); + } + if (isFragmentationPhoton(particle)) { + SETBIT(origin, static_cast(gjanalysis::ParticleOrigin::kFragmentationPhoton)); + } + if (isDecayPhoton(particle)) { + SETBIT(origin, static_cast(gjanalysis::ParticleOrigin::kDecayPhoton)); + } + if (isDecayPhotonPi0(particle)) { + SETBIT(origin, static_cast(gjanalysis::ParticleOrigin::kDecayPhotonPi0)); + } + if (isDecayPhotonEta(particle)) { + SETBIT(origin, static_cast(gjanalysis::ParticleOrigin::kDecayPhotonEta)); + } + if (isDecayPhotonOther(particle)) { + SETBIT(origin, static_cast(gjanalysis::ParticleOrigin::kDecayPhotonOther)); + } + if (isPi0(particle)) { + SETBIT(origin, static_cast(gjanalysis::ParticleOrigin::kPi0)); + } + return origin; + } + + /// \brief Gets the index of a mother particle with specific PDG code in the decay chain (upwards) + /// \param particle The particle to start from + /// \param mcParticles The MC particles collection + /// \param pdgCode The PDG code to search for + /// \return The index of the mother particle, or -1 if not found + template + int getIndexMotherChain(const T& particle, aod::JMcParticles const& mcParticles, int pdgCode, int depth = 0) + { + // Limit recursion depth to avoid infinite loops + if (depth > kMaxRecursionDepth) { // 100 generations should be more than enough + return -1; + } + const auto& mothers = particle.template mothers_as(); + for (const auto& mother : mothers) { + if (mother.pdgCode() == pdgCode) { + return mother.globalIndex(); + } else { + return getIndexMotherChain(mother, mcParticles, pdgCode, depth + 1); + } + } + return -1; + } + // return recursive list of all daughter IDs + /// \brief Gets all daughter particle IDs in the decay chain + /// \param particle The particle to start from + /// \return Vector of daughter particle IDs + template + void getDaughtersInChain(const T& particle, std::vector& daughters, int depth = 0) + { + // Limit recursion depth to avoid infinite loops + if (depth > kMaxRecursionDepth) { // 100 generations should be more than enough + return; + } + + if (!particle.has_daughters()) { + return; + } + + const auto& daughterParticles = particle.template daughters_as(); + for (const auto& daughter : daughterParticles) { + daughters.push_back(daughter.globalIndex()); + getDaughtersInChain(daughter, daughters, depth + 1); + } + return; + } + /// \brief Finds the first physical primary particle in the decay chain (upwards) + /// \param particle The particle to start from + /// \return The index of the first physical primary particle, or -1 if not found + template + int findPhysicalPrimaryInChain(const T& particle, int depth = 0) + { + // Limit recursion depth to avoid infinite loops + if (depth > kMaxRecursionDepth) { // 100 generations should be more than enough + return -1; + } + + // first check if current particle is physical primary + if (particle.isPhysicalPrimary()) { + return particle.globalIndex(); + } + + // check if the particle has mothers + if (!particle.has_mothers()) + return -1; + + // now get mothers + const auto mothers = particle.template mothers_as(); + if (mothers.size() == 0) + return -1; + + // get first mother + for (const auto& mother : mothers) { + int primaryIndex = findPhysicalPrimaryInChain(mother, depth + 1); + if (primaryIndex >= 0) { + return primaryIndex; + } + break; // only check first mother + } + + return -1; + } + + /// \brief Checks if a cluster is merged from particles of a specific PDG decay to two gammas. A cluster is considered merged if the leading and subleading contribution to a cluster come from two photons that are part of a pi0 decay + /// \param cluster The cluster to check + /// \param mcParticles The MC particles collection + /// \param pdgCode The PDG code to check for + /// \return true if cluster is merged from the specified decay, false otherwise + template + bool isMergedFromPDGDecay(const T& cluster, U const& mcParticles, int pdgCode) + { + auto inducerIDs = cluster.mcParticlesIds(); + if (inducerIDs.size() < 2) { // it can not me "merged" if it has less than 2 inducers + return false; + } + + bool isMerged = false; + int motherIndex = getIndexMotherChain(mcParticles.iteratorAt(inducerIDs[0]), mcParticles, pdgCode); + if (motherIndex != -1) { + const auto& mother = mcParticles.iteratorAt(motherIndex); + + // get daughters of pi0 mother + auto daughtersMother = mother.template daughters_as(); + // check if there are two daughters that are both photons + if (daughtersMother.size() == 2) { + const auto& daughter1 = daughtersMother.iteratorAt(0); + const auto& daughter2 = daughtersMother.iteratorAt(1); + if (daughter1.pdgCode() == PDG_t::kGamma && daughter2.pdgCode() == PDG_t::kGamma) { + // get the full stack of particles that these daughters create + std::vector fullDecayChain1; + std::vector fullDecayChain2; + getDaughtersInChain(daughter1, fullDecayChain1); + getDaughtersInChain(daughter2, fullDecayChain2); + bool photon1Found = false; + bool photon2Found = false; + + // check if any of the particles in the fullDecayChain are leading or subleading in the cluster + for (const auto& particleID : fullDecayChain1) { + if (particleID == inducerIDs[0] || particleID == inducerIDs[1]) { + photon1Found = true; + } + } + for (const auto& particleID : fullDecayChain2) { + if (particleID == inducerIDs[0] || particleID == inducerIDs[1]) { + photon2Found = true; + } + } + if (photon1Found && photon2Found) { + isMerged = true; + } + } + } + } + return isMerged; + } + + // determine cluster origin + /// \brief Gets the origin bitmap for a cluster + /// \param cluster The cluster to check + /// \param mcParticles The MC particles collection + /// \return A bitmap indicating the cluster's origin + template + uint16_t getClusterOrigin(const T& cluster, U const& mcParticles) + { + uint16_t origin = 0; + auto inducerIDs = cluster.mcParticlesIds(); + if (inducerIDs.size() == 0) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kUnknown)); + return origin; + } + + // loop over all inducers and print their energy + LOG(debug) << "Cluster with energy: " << cluster.energy() << " and nInducers: " << inducerIDs.size(); + LOG(debug) << "Number of stored amplitudes: " << cluster.amplitudeA().size(); + int aCounter = 0; + for (const auto& inducerID : inducerIDs) { + const auto& inducer = mcParticles.iteratorAt(inducerID); + int motherPDG = -1; + if (inducer.has_mothers()) { + motherPDG = inducer.template mothers_as()[0].pdgCode(); + } + LOG(debug) << "Inducer energy: " << inducer.energy() << " amplitude: " << cluster.amplitudeA()[aCounter] << " and PDG: " << inducer.pdgCode() << " isPhysicalPrimary: " << inducer.isPhysicalPrimary() << " motherPDG: " << motherPDG; + aCounter++; + } + + // check if leading energy contribution is from a photon + const auto& leadingParticle = mcParticles.iteratorAt(inducerIDs[0]); + LOG(debug) << "Leading particle: PDG" << leadingParticle.pdgCode(); + // leading particle primary ID + int leadingParticlePrimaryID = findPhysicalPrimaryInChain(leadingParticle); + LOG(debug) << "Leading particle primary ID: " << leadingParticlePrimaryID; + if (leadingParticlePrimaryID == -1) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kUnknown)); + return origin; + } + const auto& leadingParticlePrimary = mcParticles.iteratorAt(leadingParticlePrimaryID); + LOG(debug) << "Leading particle primary PDG: " << leadingParticlePrimary.pdgCode(); + if (leadingParticlePrimary.pdgCode() == PDG_t::kGamma) { + LOG(debug) << "Leading particle primary is a photon"; + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kPhoton)); + } + if (isPromptPhoton(leadingParticlePrimary)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kPromptPhoton)); + LOG(debug) << "Leading particle primary is a prompt photon"; + } + if (isDirectPromptPhoton(leadingParticlePrimary)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kDirectPromptPhoton)); + LOG(debug) << "Leading particle primary is a direct prompt photon"; + } + if (isFragmentationPhoton(leadingParticlePrimary)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kFragmentationPhoton)); + LOG(debug) << "Leading particle primary is a fragmentation photon"; + } + if (isDecayPhoton(leadingParticlePrimary)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kDecayPhoton)); + LOG(debug) << "Leading particle primary is a decay photon"; + } + if (isDecayPhotonPi0(leadingParticlePrimary)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kDecayPhotonPi0)); + LOG(debug) << "Leading particle primary is a decay photon from pi0"; + } + if (isDecayPhotonEta(leadingParticlePrimary)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kDecayPhotonEta)); + LOG(debug) << "Leading particle primary is a decay photon from eta"; + } + + // Do checks if a cluster is a merged pi0 decay + // we classify a cluster as merged pi0 if the leading and subleading contribution to a cluster come from two photons that are part of a pi0 decay + if (isMergedFromPDGDecay(cluster, mcParticles, PDG_t::kPi0)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kMergedPi0)); + LOG(debug) << "Cluster is a merged pi0"; + } + if (isMergedFromPDGDecay(cluster, mcParticles, 221)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kMergedEta)); + LOG(debug) << "Cluster is a merged eta"; + } + + // check if photon conversion + // check that leading contribution is an electron or positron + LOG(debug) << "Checking if cluster is a converted photon"; + if (std::abs(leadingParticle.pdgCode()) == PDG_t::kElectron) { + // make sure this electron is not a physicsl primary and has mothers + if (!leadingParticle.isPhysicalPrimary() && leadingParticle.has_mothers()) { + const auto mothers = leadingParticle.template mothers_as(); + if (mothers.size() > 0) { + LOG(debug) << "Got the mother"; + const auto& mother = mothers[0]; + if (mother.pdgCode() == PDG_t::kGamma && mother.has_daughters()) { + LOG(debug) << "Got the mother with PDG 22 and daughters"; + const auto& daughters = mother.template daughters_as(); + // check that mother has exactly two daughters which are e+ and e- + if (daughters.size() == 2) { + LOG(debug) << "Got the daughters"; + if ((daughters.iteratorAt(0).pdgCode() == PDG_t::kElectron && daughters.iteratorAt(1).pdgCode() == PDG_t::kPositron) || (daughters.iteratorAt(0).pdgCode() == -PDG_t::kPositron && daughters.iteratorAt(1).pdgCode() == PDG_t::kElectron)) { + SETBIT(origin, static_cast(gjanalysis::ClusterOrigin::kConvertedPhoton)); + LOG(debug) << "Cluster is a converted photon"; + } + } + } + } + } + } + // display bit origin + LOG(debug) << "Origin bits: " << std::bitset<16>(origin); + return origin; + } + + // --------------------- + // Processing functions + // --------------------- + // WARNING: This function always has to run first in the processing chain + /// \brief Clears collision mapping at the start of each dataframe + /// \param collisions The collisions collection + void processClearMaps(aod::JetCollisions const&) + { + collisionMapping.clear(); + mcCollisionsMultiRecCollisions.clear(); + mcJetIndexMapping.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 + /// \brief Processes MC event matching QA + /// \param mcCollision The MC collision to process + /// \param collisions The rec collisions collection + /// \param mcgenparticles The MC particles collection + void processMCCollisionsMatching(aod::JetMcCollision const& mcCollision, soa::SmallGroups const& collisions, aod::JetParticles const& mcgenparticles) + { + if (mcCollision.weight() == 0) { + return; + } + + // determine number of rec collisions + int nRecCollisions = 0; + mHistograms.fill(HIST("mcCollisionsWithRecCollisions"), 0); + for (auto const& collision : collisions) { + if (collision.posZ() > mVertexCut) { + continue; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + continue; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + continue; + } + if (!jetderiveddatautilities::eventEMCAL(collision)) { + continue; + } + nRecCollisions++; + } + if (nRecCollisions == 0) { + mHistograms.fill(HIST("mcCollisionsWithRecCollisions"), 3); + } + if (nRecCollisions == 1) { + mHistograms.fill(HIST("mcCollisionsWithRecCollisions"), 1); + } + if (nRecCollisions > 1) { + mHistograms.fill(HIST("mcCollisionsWithRecCollisions"), 2); + mcCollisionsMultiRecCollisions.push_back(mcCollision.globalIndex()); + } + + // loop over mcgenparticles + for (auto const& particle : mcgenparticles) { + if (!particle.isPhysicalPrimary()) { + continue; + } + if (particle.pdgCode() != PDG_t::kGamma) { + continue; + } + mHistograms.fill(HIST("numberRecCollisionsVsPhotonPt"), nRecCollisions, particle.pt()); + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processMCCollisionsMatching, "Process MC event matching QA", false); + + /// \brief Processes data events in data fill event table + /// \param collision The collision to process + /// \param clusters The EMCAL clusters in the event + void processEventData(soa::Join::iterator const& collision, emcClusters const& clusters) + { + if (!isEventAccepted(collision, clusters)) { + return; + } + + eventsTable(collision.multFT0M(), collision.centFT0M(), collision.rho(), collision.eventSel(), collision.trackOccupancyInTimeRange(), collision.alias_raw()); + collisionMapping[collision.globalIndex()] = eventsTable.lastIndex(); + } + PROCESS_SWITCH(GammaJetTreeProducer, processEventData, "Process event data", true); + + using MCCol = o2::soa::Join; + + /// \brief Processes MC events and fills rec and MC event tables (disable processEventData) + /// \param collision The collision to process + /// \param clusters The EMCAL clusters in the event + /// \param mcCollisions The MC collisions collection + void processEventMC(soa::Join::iterator const& collision, emcClusters const& clusters, MCCol const&) + { + if (!isEventAccepted(collision, clusters)) { + return; + } + + // check that this event has a MC collision + if (!collision.has_mcCollision()) { + return; + } + mHistograms.fill(HIST("eventQA"), 6); + + // check if this event is not MB gap event + if (collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + mHistograms.fill(HIST("eventQA"), 7); + + // fill rec collision table + eventsTable(collision.multFT0M(), collision.centFT0M(), collision.rho(), collision.eventSel(), collision.trackOccupancyInTimeRange(), collision.alias_raw()); + + // fill collision mapping + collisionMapping[collision.globalIndex()] = eventsTable.lastIndex(); + + auto mcCollision = collision.mcCollision_as(); + + bool isMultipleAssigned = false; + // check if we are dealing with a rec collision matched to a MC collision that was matched to multiple rec collisions + if (std::find(mcCollisionsMultiRecCollisions.begin(), mcCollisionsMultiRecCollisions.end(), mcCollision.globalIndex()) != mcCollisionsMultiRecCollisions.end()) { + isMultipleAssigned = true; + } + mcEventsTable(eventsTable.lastIndex(), mcCollision.weight(), mcCollision.rho(), isMultipleAssigned); + } + PROCESS_SWITCH(GammaJetTreeProducer, processEventMC, "Process MC event MC", false); + + // --------------------- + // 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 + /// \brief Processes clusters and fills cluster table + /// \param collision The collision to process + /// \param clusters The EMCAL clusters to process + /// \param tracks The tracks collection + /// \param emctracks The EMCAL tracks collection from track matching + 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; + + // loop over tracks one time for QA + runTrackQA(collision, tracks); + + // build kd tree for tracks and mc particles + buildKdTree(tracks); + + // loop over clusters + for (const auto& cluster : clusters) { + + // fill histograms + mHistograms.fill(HIST("clusterE"), cluster.energy()); + + double isoraw = ch_iso_in_cone(cluster, isoR, false); + double perpconerho = ch_perp_cone_rho(cluster, isoR, false); + + // 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 (const 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(), -o2::constants::math::PI) - RecoDecay::constrainAngle(cluster.phi(), -o2::constants::math::PI), -o2::constants::math::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 (const auto& track : tracks) { + mHistograms.fill(HIST("trackPt"), track.pt()); + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processClusters, "Process EMCal clusters", true); + + /// \brief Processes MC cluster information (rec level) + /// \param collision The collision to process + /// \param mcClusters The MC clusters to process + /// \param mcParticles The MC particles collection + void processClustersMCInfo(soa::Join::iterator const& collision, emcMCClusters const& mcClusters, aod::JMcParticles const& mcParticles) + { + // event selection + int32_t storedColIndex = getStoredColIndex(collision); + if (storedColIndex == -1) + return; + // loop over mcClusters + // TODO: add weights + for (const auto& mcCluster : mcClusters) { + mHistograms.fill(HIST("clusterMC_E_All"), mcCluster.energy()); + uint16_t origin = getClusterOrigin(mcCluster, mcParticles); + float leadingEnergyFraction = mcCluster.amplitudeA()[0] / mcCluster.energy(); + // Fill MC origin QA histograms + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kPhoton))) { + mHistograms.fill(HIST("clusterMC_E_Photon"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_Photon"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kPromptPhoton))) { + mHistograms.fill(HIST("clusterMC_E_PromptPhoton"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_PromptPhoton"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kDirectPromptPhoton))) { + mHistograms.fill(HIST("clusterMC_E_DirectPromptPhoton"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_DirectPromptPhoton"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kFragmentationPhoton))) { + mHistograms.fill(HIST("clusterMC_E_FragmentationPhoton"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_FragmentationPhoton"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kDecayPhoton))) { + mHistograms.fill(HIST("clusterMC_E_DecayPhoton"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_DecayPhoton"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kDecayPhotonPi0))) { + mHistograms.fill(HIST("clusterMC_E_DecayPhotonPi0"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_DecayPhotonPi0"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kDecayPhotonEta))) { + mHistograms.fill(HIST("clusterMC_E_DecayPhotonEta"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_DecayPhotonEta"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kMergedPi0))) { + mHistograms.fill(HIST("clusterMC_E_MergedPi0"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_MergedPi0"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kMergedEta))) { + mHistograms.fill(HIST("clusterMC_E_MergedEta"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_MergedEta"), mcCluster.m02()); + } + if (origin & (1 << static_cast(gjanalysis::ClusterOrigin::kConvertedPhoton))) { + mHistograms.fill(HIST("clusterMC_E_ConvertedPhoton"), mcCluster.energy()); + mHistograms.fill(HIST("clusterMC_m02_ConvertedPhoton"), mcCluster.m02()); + } + // fill table + gammaMCInfosTable(storedColIndex, origin, leadingEnergyFraction); + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processClustersMCInfo, "Process MC cluster information", false); + + /// \brief Fills the charged jet table with jet information and calculates jet properties + /// \param storedColIndex The stored collision index + /// \param jet The jet to process + /// \param tracks The tracks collection + template + void fillChargedJetTable(int32_t storedColIndex, T const& jet, U const& /*tracks*/) + { + if (jet.pt() < jetPtMin) { + return; + } + ushort nconst = 0; + float leadingTrackPt = 0; + for (const auto& constituent : jet.template tracks_as()) { + mHistograms.fill(HIST("chjetpt_vs_constpt"), jet.pt(), constituent.pt()); + nconst++; + if (constituent.pt() > leadingTrackPt) { + leadingTrackPt = constituent.pt(); + } + } + double perpconerho = ch_perp_cone_rho(jet, perpConeJetR, false); + chargedJetsTable(storedColIndex, jet.pt(), jet.eta(), jet.phi(), jet.r(), jet.energy(), jet.mass(), jet.area(), leadingTrackPt, perpconerho, nconst); + mHistograms.fill(HIST("chjetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + mHistograms.fill(HIST("chjetPt"), jet.pt()); + } + + Filter jetCuts = aod::jet::pt > jetPtMin; + /// \brief Processes charged jets and fills jet table + /// \param collision The collision to process + /// \param chargedJets The charged jets to process + /// \param tracks The tracks collection + void processChargedJetsData(soa::Join::iterator const& collision, soa::Filtered> const& chargedJets, aod::JetTracks const& tracks) + { + // event selection + int32_t storedColIndex = getStoredColIndex(collision); + if (storedColIndex == -1) + return; + // loop over charged jets + for (const auto& jet : chargedJets) { + fillChargedJetTable(storedColIndex, jet, tracks); + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processChargedJetsData, "Process charged jets", true); + + Preslice ParticlesPerMCCollisions = aod::jmcparticle::mcCollisionId; + /// \brief Processes MC particles and fills MC particle table + /// \param collision The collision to process + /// \param mcgenparticles The MC particles to process + void processMCParticles(soa::Join::iterator const& collision, aod::JetParticles const& mcgenparticles, MCCol const&) + { + // event selection + int32_t storedColIndex = getStoredColIndex(collision); + if (storedColIndex == -1) + return; + + if (!collision.has_mcCollision()) { + return; + } + + // only storing MC particles if we found a reconstructed collision + auto particlesPerMcCollision = mcgenparticles.sliceBy(ParticlesPerMCCollisions, collision.mcCollisionId()); + + // build kd tree for mc particles + buildKdTree(particlesPerMcCollision); + + // Now we want to store every pi0 and every prompt photon that we find on generator level + for (const auto& particle : particlesPerMcCollision) { + // only store particles above a given threshold + if (particle.pt() < minMCGenPt) { + continue; + } + // Test if a particle is a physical primary according to the following definition: + // Particles produced in the collision including products of strong and + // electromagnetic decay and excluding feed-down from weak decays of strange + // particles. + if (!(particle.isPhysicalPrimary() || particle.pdgCode() == PDG_t::kPi0)) { + continue; + } + + // only store photons and pi0s in mcgen stack + if (particle.pdgCode() != PDG_t::kPi0 && particle.pdgCode() != PDG_t::kGamma) { + continue; + } + // check the origin of the particle + uint16_t origin = getMCParticleOrigin(particle); + double mcIsolation = ch_iso_in_cone(particle, isoR, true); + mcParticlesTable(storedColIndex, particle.energy(), particle.eta(), particle.phi(), particle.pt(), particle.pdgCode(), mcIsolation, origin); + + // fill mc gen trigger particle histograms + mHistograms.fill(HIST("mcGenTrigger_E"), particle.energy()); + mHistograms.fill(HIST("mcGenTrigger_Eta"), particle.eta()); + mHistograms.fill(HIST("mcGenTrigger_Phi"), particle.phi()); + mHistograms.fill(HIST("mcGenTrigger_Pt"), particle.pt()); + if (origin & (1 << static_cast(gjanalysis::ParticleOrigin::kPromptPhoton))) { + mHistograms.fill(HIST("mcGenTrigger_E_PromptPhoton"), particle.energy()); + } + if (origin & (1 << static_cast(gjanalysis::ParticleOrigin::kDirectPromptPhoton))) { + mHistograms.fill(HIST("mcGenTrigger_E_DirectPromptPhoton"), particle.energy()); + } + if (origin & (1 << static_cast(gjanalysis::ParticleOrigin::kFragmentationPhoton))) { + mHistograms.fill(HIST("mcGenTrigger_E_FragmentationPhoton"), particle.energy()); + } + if (origin & (1 << static_cast(gjanalysis::ParticleOrigin::kDecayPhoton))) { + mHistograms.fill(HIST("mcGenTrigger_E_DecayPhoton"), particle.energy()); + } + if (origin & (1 << static_cast(gjanalysis::ParticleOrigin::kDecayPhotonPi0))) { + mHistograms.fill(HIST("mcGenTrigger_E_DecayPhotonPi0"), particle.energy()); + } + if (origin & (1 << static_cast(gjanalysis::ParticleOrigin::kDecayPhotonEta))) { + mHistograms.fill(HIST("mcGenTrigger_E_DecayPhotonEta"), particle.energy()); + } + if (origin & (1 << static_cast(gjanalysis::ParticleOrigin::kDecayPhotonOther))) { + mHistograms.fill(HIST("mcGenTrigger_E_DecayPhotonOther"), particle.energy()); + } + if (origin & (1 << static_cast(gjanalysis::ParticleOrigin::kPi0))) { + mHistograms.fill(HIST("mcGenTrigger_E_Pi0"), particle.energy()); + } + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processMCParticles, "Process MC particles", false); + + // NOTE: It is important that this function runs after the processMCParticles function (where the isolation tree is built ) + Preslice PJetsPerMCCollisions = aod::jmcparticle::mcCollisionId; + /// \brief Processes MC particle level charged jets and fills MC jet table + /// \param collision The collision to process + /// \param chargedJets The MC particle level charged jets to process + /// \param mcCollisions The MC collisions collection + void processChargedJetsMCP(soa::Join::iterator const& collision, soa::Filtered> const& chargedJets, MCCol const&) + { + // event selection + int32_t storedColIndex = getStoredColIndex(collision); + if (storedColIndex == -1) + return; + // loop over charged jets + if (!collision.has_mcCollision()) { + return; + } + int localIndex = 0; + auto pjetsPerMcCollision = chargedJets.sliceBy(PJetsPerMCCollisions, collision.mcCollisionId()); + for (const auto& pjet : pjetsPerMcCollision) { + // fill MC particle level jet table + float perpconerho = ch_perp_cone_rho(pjet, perpConeJetR, true); + mcJetsTable(storedColIndex, pjet.pt(), pjet.eta(), pjet.phi(), pjet.r(), pjet.energy(), pjet.mass(), pjet.area(), perpconerho); + mcJetIndexMapping[pjet.globalIndex()] = localIndex; + localIndex++; + mHistograms.fill(HIST("mcpJetPt"), pjet.pt()); + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processChargedJetsMCP, "Process MC particle level jets", false); + + // NOTE: It is important that this function runs after the processChargedJetsMCP function (where the mc jet index mapping is built) + using JetMCPTable = soa::Filtered>; + Filter jetCutsMCD = aod::jet::pt > jetPtMin; + /// \brief Processes MC detector level charged jets and fills jet matching information + /// \param collision The collision to process + /// \param chargedJets The MC detector level charged jets to process + /// \param tracks The tracks collection + /// \param pjets The MC particle level jets collection (just loaded to have subscription to the table) + void processChargedJetsMCD(soa::Join::iterator const& collision, soa::Filtered> const& chargedJets, aod::JetTracks const& tracks, JetMCPTable const& /*pjets*/) + { + // event selection + int32_t storedColIndex = getStoredColIndex(collision); + if (storedColIndex == -1) + return; + // loop over charged jets + for (const auto& jet : chargedJets) { + fillChargedJetTable(storedColIndex, jet, tracks); + + // Fill Matching information + int iLocalIndexGeo = -1; + int iLocalIndexPt = -1; + // We will always store the information for both in our tree + if (jet.has_matchedJetGeo()) { + const auto& pjet = jet.template matchedJetGeo_first_as(); + iLocalIndexGeo = mcJetIndexMapping[pjet.globalIndex()]; + mHistograms.fill(HIST("mcdJetPtVsTrueJetPtMatchingGeo"), jet.pt(), pjet.pt()); + } + if (jet.has_matchedJetPt()) { + const auto& pjet = jet.template matchedJetPt_first_as(); + iLocalIndexPt = mcJetIndexMapping[pjet.globalIndex()]; + mHistograms.fill(HIST("mcdJetPtVsTrueJetPtMatchingPt"), jet.pt(), pjet.pt()); + } + chJetMCInfosTable(storedColIndex, iLocalIndexGeo, iLocalIndexPt); + } + } + PROCESS_SWITCH(GammaJetTreeProducer, processChargedJetsMCD, "Process MC detector level jets", false); +}; + +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..a1592a587c6 --- /dev/null +++ b/PWGJE/Tasks/hadronPhotonCorrelation.cxx @@ -0,0 +1,1180 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" +#include "Framework/InitContext.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include +#include // o2-linter: disable= root/lorentz-vector (TLorentzVector is needed for TPythia8Decayer) +#include +#include +#include + +#include +#include +#include +#include +#include + +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 subGeneratorIdSelections{"subGeneratorIdSelections", -1, "set sub generator id"}; + Configurable hardQCDgg2gg{"hardQCDgg2gg", true, "include gg2gg process in hardQCD"}; + + Configurable tpcNClsCrossedRows{"tpcNClsCrossedRows", 70, "tpcNClsCrossedRows"}; + Configurable tpcCrossedRowsOverFindableCls{"tpcCrossedRowsOverFindableCls", 0.8, "tpcCrossedRowsOverFindableCls"}; + Configurable tpcNSigmaPi{"tpcNSigmaPi", 2., "tpcNSigmaPi"}; + + Configurable pTHatMin{"pTHatMin", 5, "minimum pTHat cut"}; + Configurable pTHatMax{"pTHatMax", 600, "minimum pTHat cut"}; + + const int pidCodeHadronCut = 100; + const int pythiaCodeIncomingHard = 21; + const int pythiaCodeOutgoingHard = 23; + const int pythiaCodeOutgoingDiff = 15; + + Configurable etaMaxTrig{"etaMaxTrig", 0.8, "maximum eta cut for triggers"}; + Configurable etaMaxAssoc{"etaMaxAssoc", 0.8, "maximum eta cut for associateds"}; + Configurable etaBinsTrig{"etaBinsTrig", 40, "number of eta bins for triggers"}; + Configurable etaBinsAssoc{"etaBinsAssoc", 40, "number of eta bins for associateds"}; + Configurable phiBins{"phiBins", 72, "number of phi bins"}; + + // remove this comment + AxisSpec axisEventStats = {6, -.5, 5.5, "Stats"}; + ConfigurableAxis axisPtHat = {"axisPtHat", + {VARIABLE_WIDTH, 0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, + 1., 2., 3., 4., 5., 6., 7., 8., 9., + 10., 20., 30., 40., 50., 60., 70., 80., 90., + 100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.}, + "p_{T}^{#hat}"}; + 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 + ConfigurableAxis axisDeltaPt = {"axisDeltaPt", {200, 0., 1.2}, "#Delta p_T"}; // Axis for pt ratio between neutral hadrons and decay photons + int nHadrons = 6; + AxisSpec axisPid = {10, -3.5, nHadrons + 0.5, "pid"}; // Axis for PID of neutral hadrons + ConfigurableAxis axisMult = {"axisMult", {100, 0., 99.}, "N_{ch}"}; // Axis for mutplipicity + AxisSpec axisAlpha = {100, 0., 1., "alpha"}; // Axis for decay photon pt assymetry + ConfigurableAxis axisDeltaRDecay = {"axisDeltaRDecay", {400, 0., 3.2}, "#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; + + TPythia8Decayer* decayer = new TPythia8Decayer; + TLorentzVector* motherLV = new TLorentzVector(); // o2-linter: disable= root/lorentz-vector (TLorentzVector is needed for TPythia8Decayer) + TClonesArray* decayParticles = new TClonesArray("TParticle", 10); + + 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 + {"Sigma0", 6}, // Sigma + {"Sigma0_bar", 6}}; + + std::map pidToPdg = { + {1, 111}, // pi0 + {2, 221}, // eta + {3, 331}, // eta' + {4, 333}, // phi + {5, 223}, // omega + {6, 3212}}; // Sigma + + 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(); + + AxisSpec axisPhi = {phiBins, 0., TwoPI, "#phi"}; // Axis for phi distribution + AxisSpec axisDeltaPhi = {phiBins, -PIHalf, 3 * PIHalf, "#Delta #phi"}; // Axis for Delta phi in correlations + AxisSpec axisEtaTrig = {etaBinsTrig, -etaMaxTrig, etaMaxTrig, "#eta"}; // Axis for eta distribution + AxisSpec axisEtaAssoc = {etaBinsAssoc, -etaMaxAssoc, etaMaxAssoc, "#eta"}; // Axis for eta distribution + AxisSpec axisDeltaEta = {etaBinsTrig + etaBinsAssoc, -(etaMaxTrig + etaMaxAssoc), etaMaxTrig + etaMaxAssoc, "#Delta #eta"}; // Axis for Delta eta in correlations + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + // Generated histograms + registry.add("generated/events/hEventStats", "Event statistics", kTH1F, {axisEventStats}); + registry.get(HIST("generated/events/hEventStats"))->Sumw2(); + registry.add("generated/events/hPtHat", "pT of hard collision", kTH1F, {axisPtHat}); + registry.get(HIST("generated/events/hPtHat"))->Sumw2(); + + // Triggers + registry.add("generated/triggers/hTrigMultGen", "Generated Trigger Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("generated/triggers/hTrigMultGen"))->Sumw2(); + registry.add("generated/triggers/hTrigSpectrumGen", "Generated Trigger Spectrum", kTHnSparseF, {axisPtTrig, axisEtaTrig, axisPhi}); + registry.get(HIST("generated/triggers/hTrigSpectrumGen"))->Sumw2(); + + // Hadrons + registry.add("generated/hadrons/hHadronCorrelGen", "Generated Trigger-Hadron Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.get(HIST("generated/hadrons/hHadronCorrelGen"))->Sumw2(); + registry.add("generated/hadrons/hHadronMultGen", "Generated Hadron Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("generated/hadrons/hHadronMultGen"))->Sumw2(); + registry.add("generated/hadrons/hHadronSpectrumGen", "Generated Hadron Spectrum", kTHnSparseF, {axisPtAssoc, axisEtaAssoc, axisPhi}); + registry.get(HIST("generated/hadrons/hHadronSpectrumGen"))->Sumw2(); + + // Photons + registry.add("generated/photons/hPhotonCorrelGen", "Generated Trigger-Photon Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi, axisPid}); + registry.get(HIST("generated/photons/hPhotonCorrelGen"))->Sumw2(); + registry.add("generated/photons/hPhotonMultGen", "Generated Photon Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("generated/photons/hPhotonMultGen"))->Sumw2(); + registry.add("generated/photons/hPhotonSpectrumGen", "Generated Photon Spectrum", kTHnSparseF, {axisPtAssoc, axisEtaAssoc, axisPhi, axisPid}); + registry.get(HIST("generated/photons/hPhotonSpectrumGen"))->Sumw2(); + + // Charged pions + registry.add("generated/charged/hPionCorrelGen", "Generated Trigger-Pion Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.get(HIST("generated/charged/hPionCorrelGen"))->Sumw2(); + registry.add("generated/charged/hPionMultGen", "Generated Pion Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("generated/charged/hPionMultGen"))->Sumw2(); + registry.add("generated/charged/hPionSpectrumGen", "Generated Pion Spectrum", kTHnSparseF, {axisPtAssoc, axisEtaAssoc, axisPhi}); + registry.get(HIST("generated/charged/hPionSpectrumGen"))->Sumw2(); + registry.add("generated/charged/hCocktailPhotonCorrelGen", "Cocktail Photon from Pion-Hadron Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisPtAssoc, axisDeltaEta, axisDeltaPhi, axisPid}); + registry.get(HIST("generated/charged/hCocktailPhotonCorrelGen"))->Sumw2(); + registry.add("generated/charged/hCocktailPhotonSpectrumGen", "Cocktail Photon from Pion Spectrum", kTHnSparseF, {axisPtAssoc, axisPtAssoc, axisEtaAssoc, axisPhi, axisPid}); + registry.get(HIST("generated/charged/hCocktailPhotonSpectrumGen"))->Sumw2(); + + ////Neutral particles + registry.add("generated/neutral/hNeutralCorrelGen", "Generated Trigger-Neutral Hadron Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi, axisPid}); + registry.get(HIST("generated/neutral/hNeutralCorrelGen"))->Sumw2(); + registry.add("generated/neutral/hNeutralMultGen", "Generated Neutral Hadron Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("generated/neutral/hNeutralMultGen"))->Sumw2(); + registry.add("generated/neutral/hNeutralSpectrumGen", "Generated Neutral Hadron Spectrum", kTHnSparseF, {axisPtAssoc, axisEtaAssoc, axisPhi, axisPid}); + registry.get(HIST("generated/neutral/hNeutralSpectrumGen"))->Sumw2(); + registry.add("generated/neutral/hNeutralDecayGen", "Generated Neutral Hadron-Decay Photon Correlation", kTHnSparseF, {axisPtAssoc, axisDeltaPt, axisDeltaRDecay, axisAlpha, axisPid}); // Correlation with decay photons + registry.get(HIST("generated/neutral/hNeutralDecayGen"))->Sumw2(); + registry.add("generated/neutral/hCocktailPhotonCorrelGen", "Cocktail Photon from Hadron-Hadron Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisPtAssoc, axisDeltaEta, axisDeltaPhi, axisPid}); + registry.get(HIST("generated/neutral/hCocktailPhotonCorrelGen"))->Sumw2(); + registry.add("generated/neutral/hCocktailPhotonSpectrumGen", "Cocktail Photon from Hadron Spectrum", kTHnSparseF, {axisPtAssoc, axisPtAssoc, axisEtaAssoc, axisPhi, axisPid}); + registry.get(HIST("generated/neutral/hCocktailPhotonSpectrumGen"))->Sumw2(); + + // Reconstructed histograms + registry.add("reconstructed/events/hEventStats", "Event statistics", kTH1F, {axisEventStats}); + registry.get(HIST("reconstructed/events/hEventStats"))->Sumw2(); + + // Triggers + registry.add("reconstructed/triggers/hTrigMultReco", "Reconstructed Trigger Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("reconstructed/triggers/hTrigMultReco"))->Sumw2(); + registry.add("reconstructed/triggers/hTrigSpectrumReco", "Reconstructed Trigger Spectrum", kTHnSparseF, {axisPtTrig, axisEtaTrig, axisPhi}); + registry.get(HIST("reconstructed/triggers/hTrigSpectrumReco"))->Sumw2(); + + // Hadrons + registry.add("reconstructed/hadrons/hHadronCorrelReco", "Reconstructed Trigger-Hadron Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.get(HIST("reconstructed/hadrons/hHadronCorrelReco"))->Sumw2(); + registry.add("reconstructed/hadrons/hHadronMultReco", "Reconstructed Hadron Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("reconstructed/hadrons/hHadronMultReco"))->Sumw2(); + registry.add("reconstructed/hadrons/hHadronSpectrumReco", "Reconstructed Hadron Spectrum", kTHnSparseF, {axisPtAssoc, axisEtaAssoc, axisPhi}); + registry.get(HIST("reconstructed/hadrons/hHadronSpectrumReco"))->Sumw2(); + registry.add("reconstructed/hadrons/hHadronPtPrimReco", "Reconstructed Primaries Spectrum", kTH1F, {axisPtAssoc}); // Primary hadron spectrum + registry.get(HIST("reconstructed/hadrons/hHadronPtPrimReco"))->Sumw2(); + registry.add("reconstructed/hadrons/hHadronPtSecReco", "Reconstructed Secondaries Spectrum", kTH1F, {axisPtAssoc}); // Secondary hadron spectrum + registry.get(HIST("reconstructed/hadrons/hHadronPtSecReco"))->Sumw2(); + + // Photons + registry.add("reconstructed/photons/hPhotonCorrelReco", "Reconstructed Trigger-Photon Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.get(HIST("reconstructed/photons/hPhotonCorrelReco"))->Sumw2(); + registry.add("reconstructed/photons/hPhotonMultReco", "Reconstructed Photon Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("reconstructed/photons/hPhotonMultReco"))->Sumw2(); + registry.add("reconstructed/photons/hPhotonSpectrumReco", "Reconstructed Photon Spectrum", kTHnSparseF, {axisPtAssoc, axisEtaAssoc, axisPhi}); + registry.get(HIST("reconstructed/photons/hPhotonSpectrumReco"))->Sumw2(); + + // Charged Pions + registry.add("reconstructed/charged/hPionCorrelReco", "Reconstructed Trigger-Pion Correlation", kTHnSparseF, {axisPtTrig, axisPtAssoc, axisDeltaEta, axisDeltaPhi}); + registry.get(HIST("reconstructed/charged/hPionCorrelReco"))->Sumw2(); + registry.add("reconstructed/charged/hPionMultReco", "Reconstructed Pion Multiplicity", kTH1F, {axisMult}); + registry.get(HIST("reconstructed/charged/hPionMultReco"))->Sumw2(); + registry.add("reconstructed/charged/hPionSpectrumReco", "Reconstructed Pion Spectrum", kTHnSparseF, {axisPtAssoc, axisEtaAssoc, axisPhi}); + registry.get(HIST("reconstructed/charged/hPionSpectrumReco"))->Sumw2(); + } + + // Get pTHat of the event + template + double getCollisionPtHat(const P& particles) + { + double pTHat = 0; + bool isDiffractive = false; + + for (const auto& particle : particles) { + + if (std::abs(particle.getGenStatusCode()) == pythiaCodeOutgoingHard && !isDiffractive) { + if (particle.pt() > pTHat) { + pTHat = particle.pt(); + } + } + if (std::abs(particle.getGenStatusCode()) == pythiaCodeOutgoingDiff) { + if (isDiffractive) { + if (particle.pt() > pTHat) { + pTHat = particle.pt(); + } + } else { + pTHat = particle.pt(); + isDiffractive = true; + } + } + } + + return pTHat; + } + + template + bool rejectOutliers(const P& particles, double pTHat) + { + if (subGeneratorIdSelections == 0) { + return false; + } + + for (const auto& particle : particles) { + if (particle.getGenStatusCode() > 0 && particle.pt() > pTHat) { + return true; + } + } + + return false; + } + + // If event is a HardQCD gg->gg event (which is not implemented in POWHEG directphoton) + template + bool isHardQCDgg2gg(const P& particles) + { + for (const auto& particle : particles) { + if (std::abs(particle.getGenStatusCode()) == pythiaCodeIncomingHard && (PDG_t)std::abs(particle.pdgCode()) != kGluon) { + return false; + } + if (std::abs(particle.getGenStatusCode()) == pythiaCodeOutgoingHard && (PDG_t)std::abs(particle.pdgCode()) != kGluon) { + return false; + } + } + return true; + } + + // Initialize collision + template + bool initCollisionMC(const C& collision, const P& particles) + { + if (collision.subGeneratorId() != subGeneratorIdSelections) { + return false; + } + + double pTHat = getCollisionPtHat(particles); + if (pTHat < pTHatMin || pTHat > pTHatMax) { + return false; + } + + if (rejectOutliers(particles, pTHat)) { + return false; + } + + if (!hardQCDgg2gg && isHardQCDgg2gg(particles)) { + return false; + } + + return true; + } + + // 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()) > etaMaxAssoc) { + 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 (particle.getGenStatusCode() == -1) { + return false; + } + + if (std::abs(particle.eta()) > etaMaxAssoc) { + return false; + } + + if (particle.pt() < ptMinAssoc || particle.pt() > ptMaxAssoc) { + return false; + } + + return true; + } + + // Initialize Pythia8 decay particle + bool initDecayParticle(const TParticle* particle) + { + + if (particle->GetMother(0) != 0) { + return false; + } + + if ((PDG_t)std::abs(particle->GetPdgCode()) != kGamma) { + return false; + } + + if (std::abs(particle->Eta()) > etaMaxAssoc) { + 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()) > etaMaxTrig) { + 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()) > etaMaxTrig) { + 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() < tpcNClsCrossedRows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < tpcCrossedRowsOverFindableCls) { + return false; + } + + return true; + } + + /**************************************************************************************************** + ************************************************ EVENTS ******************************************** + ****************************************************************************************************/ + void processEventsMCGen(JetMcCollision const& collision, + JetParticles const& particles) + { + if (collision.subGeneratorId() == subGeneratorIdSelections) { + registry.fill(HIST("generated/events/hEventStats"), 0); + registry.fill(HIST("generated/events/hEventStats"), 2, collision.weight()); + registry.fill(HIST("generated/events/hEventStats"), 4, collision.xsectGen()); + } + + if (!initCollisionMC(collision, particles)) { + return; + } + + registry.fill(HIST("generated/events/hEventStats"), 1); + registry.fill(HIST("generated/events/hEventStats"), 3, collision.weight()); + registry.fill(HIST("generated/events/hEventStats"), 5, collision.xsectGen()); + + registry.fill(HIST("generated/events/hPtHat"), getCollisionPtHat(particles)); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processEventsMCGen, "event stats MC gen", true); + + void processEventsMCReco(JetCollisionMCD const& collision, + JetMcCollisions const&, + JetParticles const&) + { + if (collision.subGeneratorId() != subGeneratorIdSelections) { + return; + } + registry.fill(HIST("reconstructed/events/hEventStats"), 0); + registry.fill(HIST("reconstructed/events/hEventStats"), 2, collision.mcCollision().weight()); + registry.fill(HIST("reconstructed/events/hEventStats"), 4, collision.mcCollision().xsectGen()); + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, false)) { + return; + } + + registry.fill(HIST("reconstructed/events/hEventStats"), 1); + registry.fill(HIST("reconstructed/events/hEventStats"), 3, collision.mcCollision().weight()); + registry.fill(HIST("reconstructed/events/hEventStats"), 5, collision.mcCollision().xsectGen()); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processEventsMCReco, "event stats MC reco", 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(JetCollisionMCD const& collision, + JetMcCollisions const&, + Join const& tracks, + JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, false)) { + return; + } + if (collision.subGeneratorId() != subGeneratorIdSelections) { + 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(), collision.mcCollision().weight()); + nTrigs++; + } + registry.fill(HIST("reconstructed/triggers/hTrigMultReco"), nTrigs, collision.mcCollision().weight()); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processTrigsMCReco, "trigger particle mc properties", true); + + void processTrigsMCGen(JetMcCollision const& collision, + JetParticles const& particles) + { + if (!initCollisionMC(collision, particles)) { + return; + } + + int nTrigs = 0; + for (const auto& particle : particles) { + if (!initTrigParticle(particle)) { + continue; + } + registry.fill(HIST("generated/triggers/hTrigSpectrumGen"), particle.pt(), particle.eta(), particle.phi(), collision.weight()); + nTrigs++; + } + registry.fill(HIST("generated/triggers/hTrigMultGen"), nTrigs, collision.weight()); + } + 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(v0.phi() - track.phi(), -PIHalf); + registry.fill(HIST("reconstructed/photons/hPhotonCorrelReco"), track.pt(), v0.pt(), v0.eta() - track.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, false)) { + return; + } + if (collision_reco.mcCollision().subGeneratorId() != subGeneratorIdSelections) { + 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(), collision_reco.mcCollision().weight()); + nPhotons++; + + for (const auto& track : tracks_reco) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + + if (!initTrig(track)) { + continue; + } + float dphi = RecoDecay::constrainAngle(v0.phi() - track.phi(), -PIHalf); + registry.fill(HIST("reconstructed/photons/hPhotonCorrelReco"), track.pt(), v0.pt(), v0.eta() - track.eta(), dphi, collision_reco.mcCollision().weight()); + } + } + registry.fill(HIST("reconstructed/photons/hPhotonMultReco"), nPhotons, collision_reco.mcCollision().weight()); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPhotonCorrelationsMCReco, "hadron-photon correlation", true); + + void processPhotonCorrelationsMCGen(JetMcCollision const& collision, + JetParticles const& tracks_true) + { + if (!initCollisionMC(collision, tracks_true)) { + return; + } + + 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, collision.weight()); + + nPhotons++; + + 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/photons/hPhotonCorrelGen"), track_trig.pt(), track_assoc.pt(), track_assoc.eta() - track_trig.eta(), dphi, photonGeneration, collision.weight()); + } + } + + registry.fill(HIST("generated/photons/hPhotonMultGen"), nPhotons, collision.weight()); + } + 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_assoc.phi() - track_trig.phi(), -PIHalf); + registry.fill(HIST("reconstructed/hadrons/hHadronCorrelReco"), track_trig.pt(), track_assoc.pt(), track_assoc.eta() - track_trig.eta(), dphi); + } + } + registry.fill(HIST("reconstructed/hadrons/hHadronMultReco"), nHadrons); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processHadronCorrelations, "hadron-hadron correlation", true); + + /*********************************************** MC ************************************************/ + + void processHadronCorrelationsMCGen(JetMcCollision const& collision, + JetParticles const& tracks_true) + { + if (!initCollisionMC(collision, tracks_true)) { + return; + } + + 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()) < pidCodeHadronCut) { + continue; + } + + registry.fill(HIST("generated/hadrons/hHadronSpectrumGen"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi(), collision.weight()); + nHadrons++; + + for (const auto& track_trig : tracks_true) { + if (!initTrigParticle(track_trig)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_assoc.phi() - track_trig.phi(), -PIHalf); + + registry.fill(HIST("generated/hadrons/hHadronCorrelGen"), track_trig.pt(), track_assoc.pt(), track_assoc.eta() - track_trig.eta(), dphi, collision.weight()); + } + } + registry.fill(HIST("generated/hadrons/hHadronMultGen"), nHadrons, collision.weight()); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processHadronCorrelationsMCGen, "mc hadron-hadron correlation", true); + + void processHadronCorrelationsMCReco(JetCollisionMCD const& collision_reco, + JetMcCollisions const&, + JetTracksMCD const& tracks_reco, + JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision_reco, eventSelectionBits, false)) { + return; + } + if (collision_reco.mcCollision().subGeneratorId() != subGeneratorIdSelections) { + 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()) < pidCodeHadronCut) { + continue; + } + + registry.fill(HIST("reconstructed/hadrons/hHadronSpectrumReco"), track_assoc.pt(), track_assoc.eta(), track_assoc.phi(), collision_reco.mcCollision().weight()); + + if (particle.isPhysicalPrimary()) { + registry.fill(HIST("reconstructed/hadrons/hHadronPtPrimReco"), track_assoc.pt(), collision_reco.mcCollision().weight()); + } else { + registry.fill(HIST("reconstructed/hadrons/hHadronPtSecReco"), track_assoc.pt(), collision_reco.mcCollision().weight()); + } + 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_assoc.phi() - track_trig.phi(), -PIHalf); + + registry.fill(HIST("reconstructed/hadrons/hHadronCorrelReco"), track_trig.pt(), track_assoc.pt(), track_assoc.eta() - track_trig.eta(), dphi, collision_reco.mcCollision().weight()); + } + } + registry.fill(HIST("reconstructed/hadrons/hHadronMultReco"), nHadrons, collision_reco.mcCollision().weight()); + } + 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()) > tpcNSigmaPi) { + 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_assoc.phi() - track_trig.phi(), -PIHalf); + registry.fill(HIST("reconstructed/charged/hPionCorrelReco"), track_trig.pt(), track_assoc.pt(), track_assoc.eta() - track_trig.eta(), dphi); + } + } + registry.fill(HIST("reconstructed/charged/hPionMultReco"), nPions); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPionCorrelations, "hadron-pion correlation", true); + + /*********************************************** MC ************************************************/ + + void processPionCorrelationsMCGen(JetMcCollision const& collision, + JetParticles const& tracks_true) + { + if (!initCollisionMC(collision, tracks_true)) { + return; + } + + 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(), collision.weight()); + nPions++; + + // Get correlations + for (const auto& track_trig : tracks_true) { + if (!initTrigParticle(track_trig)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + float dphi = RecoDecay::constrainAngle(track_assoc.phi() - track_trig.phi(), -PIHalf); + + registry.fill(HIST("generated/charged/hPionCorrelGen"), track_trig.pt(), track_assoc.pt(), track_assoc.eta() - track_trig.eta(), dphi, collision.weight()); + } + + // Use PYTHIA to simulate decay + decayer->Init(); + for (int pid = 1; pid <= nHadrons; pid++) { + TParticlePDG* pdgParticle = nullptr; + + auto it = pidToPdg.find(pid); + if (it != pidToPdg.end()) { + pdgParticle = pdg->GetParticle(it->second); + } else { + continue; + } + + motherLV->SetPtEtaPhiM(track_assoc.pt(), track_assoc.eta(), track_assoc.phi(), pdgParticle->Mass()); + decayer->Decay(pdgParticle->PdgCode(), motherLV); + decayer->ImportParticles(decayParticles); + for (int i = 0; i < decayParticles->GetEntriesFast(); ++i) { + TParticle* daughter = static_cast(decayParticles->At(i)); + + if (!initDecayParticle(daughter)) { + continue; + } + + registry.fill(HIST("generated/charged/hCocktailPhotonSpectrumGen"), track_assoc.pt(), daughter->Pt(), daughter->Eta(), daughter->Phi(), pidCodes[pdgParticle->GetName()], collision.weight()); + + for (const auto& track_trig : tracks_true) { + if (!initTrigParticle(track_trig)) { + continue; + } + if (track_trig == track_assoc) { + continue; + } + float dphi = RecoDecay::constrainAngle(daughter->Phi() - track_trig.phi(), -PIHalf); + registry.fill(HIST("generated/charged/hCocktailPhotonCorrelGen"), track_trig.pt(), track_assoc.pt(), daughter->Pt(), daughter->Eta() - track_trig.eta(), dphi, pidCodes[pdgParticle->GetName()], collision.weight()); + } + } + } + } + registry.fill(HIST("generated/charged/hPionMultGen"), nPions, collision.weight()); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPionCorrelationsMCGen, "mc hadron-pion correlation", true); + + void processPionCorrelationsMCReco(JetCollisionMCD const& collision_reco, + JetMcCollisions const&, + JetTracksMCD const& tracks_reco, + JetParticles const&) + { + if (!jetderiveddatautilities::selectCollision(collision_reco, eventSelectionBits, false)) { + return; + } + if (collision_reco.mcCollision().subGeneratorId() != subGeneratorIdSelections) { + 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(), collision_reco.mcCollision().weight()); + 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_assoc.phi() - track_trig.phi(), -PIHalf); + registry.fill(HIST("reconstructed/charged/hPionCorrelReco"), track_trig.pt(), track_assoc.pt(), track_assoc.eta() - track_trig.eta(), dphi, collision_reco.mcCollision().weight()); + } + } + registry.fill(HIST("reconstructed/charged/hPionMultReco"), nPions, collision_reco.mcCollision().weight()); + } + PROCESS_SWITCH(HadronPhotonCorrelation, processPionCorrelationsMCReco, "mc hadron-pion correlation", true); + + /**************************************************************************************************** + ****************************************** NEUTRALS ************************************************* + ****************************************************************************************************/ + + /*********************************************** MC ************************************************/ + + void processNeutralCorrelationsMCGen(JetMcCollision const& collision, + JetParticles const& tracks_true) + { + if (!initCollisionMC(collision, tracks_true)) { + return; + } + + 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 (std::abs(track_assoc.pdgCode()) < pidCodeHadronCut || (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()], collision.weight()); + nNeutrals++; + + // Get correlations between neutral hadrons and their respective decay photons + auto daughters = track_assoc.daughters_as(); + double alpha = -1; + int nPhotonsPionDecay = 2; + if (daughters.size() == nPhotonsPionDecay) { + 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 (!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()], collision.weight()); + } + + // 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()], collision.weight()); + } + + // Use PYTHIA to simulate decay + decayer->Init(); + motherLV->SetPtEtaPhiM(track_assoc.pt(), track_assoc.eta(), track_assoc.phi(), pdgParticle->Mass()); + decayer->Decay(track_assoc.pdgCode(), motherLV); + decayer->ImportParticles(decayParticles); + for (int i = 0; i < decayParticles->GetEntriesFast(); ++i) { + TParticle* daughter = static_cast(decayParticles->At(i)); + + if (!initDecayParticle(daughter)) { + continue; + } + + registry.fill(HIST("generated/neutral/hCocktailPhotonSpectrumGen"), track_assoc.pt(), daughter->Pt(), daughter->Eta(), daughter->Phi(), pidCodes[pdgParticle->GetName()], collision.weight()); + + for (const auto& track_trig : tracks_true) { + if (!initTrigParticle(track_trig)) { + continue; + } + float dphi = RecoDecay::constrainAngle(daughter->Phi() - track_trig.phi(), -PIHalf); + registry.fill(HIST("generated/neutral/hCocktailPhotonCorrelGen"), track_trig.pt(), track_assoc.pt(), daughter->Pt(), daughter->Eta() - track_trig.eta(), dphi, pidCodes[pdgParticle->GetName()], collision.weight()); + } + } + } + registry.fill(HIST("generated/neutral/hNeutralMultGen"), nNeutrals, collision.weight()); + } + 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..b3790cda8cd --- /dev/null +++ b/PWGJE/Tasks/hfFragmentationFunction.cxx @@ -0,0 +1,463 @@ +// 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 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +// +#include "PWGHF/Core/DecayChannels.h" + +#include "Common/Core/RecoDecay.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include +#include + +#include "TVector3.h" +#include + +#include + +#include +#include +#include + +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 = o2::hf_decay::hf_cand_2prong::DecayChannelMain::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 = o2::hf_decay::hf_cand_2prong::DecayChannelMain::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 b080485d2ea..00000000000 --- a/PWGJE/Tasks/hffragmentationfunction.cxx +++ /dev/null @@ -1,312 +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. - -/// \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 "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" - -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(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(MCJetHfDist, mcjethfdist, float); -DECLARE_SOA_COLUMN(MCJetPt, mcjetpt, float); -DECLARE_SOA_COLUMN(MCJetEta, mcjeteta, float); -DECLARE_SOA_COLUMN(MCJetPhi, mcjetphi, 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::HfPt, - jet_distance::HfEta, - jet_distance::HfPhi, - jet_distance::HfMass, - jet_distance::HfY); -DECLARE_SOA_TABLE(MCPJetDistanceTable, "AOD", "MCPJETDISTTABLE", - jet_distance::MCJetHfDist, - jet_distance::MCJetPt, - jet_distance::MCJetEta, - jet_distance::MCJetPhi, - 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::HfPt, - jet_distance::HfEta, - jet_distance::HfPhi, - jet_distance::HfMass, - jet_distance::HfY, - jet_distance::HfPrompt, - jet_distance::HfMatch); -DECLARE_SOA_TABLE(MatchJetDistanceTable, "AOD", "MATCHTABLE", - jet_distance::MCJetHfDist, - jet_distance::MCJetPt, - jet_distance::MCJetEta, - jet_distance::MCJetPhi, - 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::HfPt, - jet_distance::HfEta, - jet_distance::HfPhi, - jet_distance::HfMass, - jet_distance::HfY, - jet_distance::HfPrompt); -} // namespace o2::aod - -struct HfFragmentationFunctionTask { - // 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 CollisionsPerMCCollision = aod::jmccollisionlb::mcCollisionId; - Preslice D0MCDJetsPerCollision = aod::jet::collisionId; - Preslice D0MCPJetsPerMCCollision = aod::jet::mcCollisionId; - - // Histogram registry: an object to hold your histograms - HistogramRegistry registry{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - void init(InitContext const&) - { - - // create histograms - // collision system histograms - registry.add("h_collision_counter", ";# collisions;", {HistType::kTH1F, {{2, 0., 1.}}}); - // D0 candidate histograms from data - 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", true); - - void processDataChargedSubstructure(JetCollision const&, - soa::Join const& jets, - CandidatesD0Data const&) - { - - 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.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 z_parallel = (jetVector * d0Vector) / (jetVector * jetVector); - - // calculating angular distance in eta-phi plane - axisDistance = RecoDecay::sqrtSumOfSquares(jet.eta() - d0Candidate.eta(), deltaPhi(jet.phi(), d0Candidate.phi())); - - // 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", false); - - void processMcEfficiency(JetMcCollisions const& mccollisions, - JetCollisionsMCD const& collisions, - JetMCDTable const& mcdjets, - JetMCPTable const& mcpjets, - CandidatesD0MCD const&, - CandidatesD0MCP const&) - { - for (const auto& mccollision : mccollisions) { - - // reconstructed collisions associated to same mccollision - const auto collisionsPerMCCollision = collisions.sliceBy(CollisionsPerMCCollision, mccollision.globalIndex()); - for (const auto& collision : collisionsPerMCCollision) { - // d0 detector level jets associated to the current same collision - const auto d0mcdJetsPerCollision = mcdjets.sliceBy(D0MCDJetsPerCollision, collision.globalIndex()); - for (const auto& mcdjet : d0mcdJetsPerCollision) { - - // obtain leading HF candidate in jet - auto mcdd0cand = mcdjet.candidates_first_as(); - - // store data in MC detector level table - mcddistJetTable(RecoDecay::sqrtSumOfSquares(mcdjet.eta() - mcdd0cand.eta(), deltaPhi(mcdjet.phi(), mcdd0cand.phi())), - mcdjet.pt(), mcdjet.eta(), mcdjet.phi(), // 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()); - } - } - - // d0 particle level jets associated to same mccollision - const auto d0mcpJetsPerMCCollision = mcpjets.sliceBy(D0MCPJetsPerMCCollision, mccollision.globalIndex()); - for (const auto& mcpjet : d0mcpJetsPerMCCollision) { - - // obtain leading HF particle in jet - auto mcpd0cand = mcpjet.candidates_first_as(); - - // store data in MC detector level table (calculate angular distance in eta-phi plane on the fly) - mcpdistJetTable(RecoDecay::sqrtSumOfSquares(mcpjet.eta() - mcpd0cand.eta(), deltaPhi(mcpjet.phi(), mcpd0cand.phi())), - mcpjet.pt(), mcpjet.eta(), mcpjet.phi(), // particle level jet - mcpd0cand.pt(), mcpd0cand.eta(), mcpd0cand.phi(), mcpd0cand.y(), (mcpd0cand.originMcGen() == RecoDecay::OriginType::Prompt), // particle level D0 - mcpjet.has_matchedJetCand()); - } - } - } - PROCESS_SWITCH(HfFragmentationFunctionTask, processMcEfficiency, "non-matched and matched MC HF and jets", false); - - void processMcChargedMatched(JetMcCollision const&, - JetMCDTable const&, - JetMCPTable const& mcpjets, - CandidatesD0MCD const&, - CandidatesD0MCP const&) - { - // fill jet counter histogram - registry.fill(HIST("h_collision_counter"), 0.5); - - // d0 particle level jets associated to same mccollision - for (const auto& mcpjet : mcpjets) { - - // obtain leading HF particle in jet - auto mcpd0cand = mcpjet.candidates_first_as(); - - // loop through detector level matched to current particle level - for (auto& mcdjet : mcpjet.matchedJetCand_as()) { - - // obtain leading HF candidate in jet - auto mcdd0cand = mcdjet.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(RecoDecay::sqrtSumOfSquares(mcpjet.eta() - mcpd0cand.eta(), deltaPhi(mcpjet.phi(), mcpd0cand.phi())), mcpjet.pt(), mcpjet.eta(), mcpjet.phi(), // particle level jet - mcpd0cand.pt(), mcpd0cand.eta(), mcpd0cand.phi(), mcpd0cand.y(), (mcpd0cand.originMcGen() == RecoDecay::OriginType::Prompt), // particle level D0 - RecoDecay::sqrtSumOfSquares(mcdjet.eta() - mcdd0cand.eta(), deltaPhi(mcdjet.phi(), mcdd0cand.phi())), mcdjet.pt(), mcdjet.eta(), mcdjet.phi(), // detector level jet - mcdd0cand.pt(), mcdd0cand.eta(), mcdd0cand.phi(), mcdd0cand.m(), mcdd0cand.y(), (mcdd0cand.originMcRec() == RecoDecay::OriginType::Prompt)); // detector level D0 - } - } - } - PROCESS_SWITCH(HfFragmentationFunctionTask, processMcChargedMatched, "matched MC HF and jets", false); -}; - -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..8e93fc305d0 --- /dev/null +++ b/PWGJE/Tasks/jetBackgroundAnalysis.cxx @@ -0,0 +1,244 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "RecoDecay.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +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::centFT0M >= centralityMin && aod::jcollision::centFT0M < 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.centFT0M(), 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.centFT0M(), 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.centFT0M(), 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.centFT0M(), randomConePtWithoutOneLeadJet - M_PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), collision.centFT0M(), 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.centFT0M(), 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.centFT0M(), collision.rho()); + registry.fill(HIST("h2_centrality_rhom"), collision.centFT0M(), 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..e9a4a937334 100644 --- a/PWGJE/Tasks/jetChCorr.cxx +++ b/PWGJE/Tasks/jetChCorr.cxx @@ -14,38 +14,35 @@ /// Mriganka Mouli Mondal originally modified from Nima Zardoshti // -#include -#include -#include -#include -#include -#include -#include - -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" -#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include +#include +#include -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/JetSubstructure.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/FastJetUtilities.h" +#include "fastjet/ClusterSequenceArea.hh" +#include "fastjet/PseudoJet.hh" +#include -#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include +#include +#include // #include "PWGLF/DataModel/LFResonanceTables.h" -#include "Framework/runDataProcessing.h" +#include +#include +#include +#include +#include using namespace std; using namespace o2; @@ -177,8 +174,6 @@ struct JetChCorr { fastjet::PseudoJet parentSubJet2; bool softDropped = false; auto nsd = 0.0; - auto zg = -1.0; - auto rg = -1.0; // std::vector energyMotherVec; // std::vector ptLeadingVec; @@ -222,8 +217,8 @@ struct JetChCorr { if (z >= zCut * TMath::Power(theta / (jet.r() / 100.f), beta)) { if (found1 == true && found2 == true) { // found leading and next-to-leading in seperate prongs if (!softDropped) { - zg = z; - rg = theta; + auto zg = z; + auto 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); @@ -242,7 +237,7 @@ struct JetChCorr { v2.SetXYZ(parentSubJet2.px(), parentSubJet2.py(), parentSubJet2.pz()); vR = v1 + v2; - float z = v2.Perp(vR.Orthogonal()) / (v1.Perp(vR.Orthogonal()) + v2.Perp(vR.Orthogonal())); + float z = v2.Perp(vR.Orthogonal()) / (v1.Perp(vR.Orthogonal()) + v2.Perp(vR.Orthogonal())); // you redefine z here, please check! float fT = ((2. * z * (1 - z) * vR.Mag()) / v1.Perp2(vR)) / 6.; float kt_p = v1.Perp(vR); @@ -394,36 +389,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..bd5fbe25107 --- /dev/null +++ b/PWGJE/Tasks/jetChargedV2.cxx @@ -0,0 +1,1963 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "EventFiltering/filterTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetChargedV2 { + using McParticleCollision = soa::Join; + using ChargedMCDMatchedJets = soa::Join; + using ChargedMCPMatchedJets = soa::Join; + + 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 nBinsEta{"nBinsEta", 200, "number of bins for eta axes"}; + Configurable jetRadius{"jetRadius", 0.2, "jet resolution parameters"}; + 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 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; + + //=====================< jetSpectraConfig to this analysis >=====================// + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + 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 pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"}; + 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 checkMcCollisionIsMatched{"checkMcCollisionIsMatched", false, "0: count whole MCcollisions, 1: select MCcollisions which only have their correspond collisions"}; + 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 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"}; + Configurable cfgChkFitQuality{"cfgChkFitQuality", false, "check fit quality"}; + Configurable subtractMCPBackground{"subtractMCPBackground", true, "subtract MCP Background with General Purpose anchored MC"}; + Configurable useMedianRho{"useMedianRho", false, "use median rho for subtract MCP Background"}; + Configurable useLocalRho{"useLocalRho", false, "use local rho for subtract MCP Background"}; + + 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 p615ln | 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; + float collQvecAmpDetId = 1e-8; + TH1F* hPtsumSumptFit = nullptr; + TH1F* hPtsumSumptFitMCP = nullptr; + TF1* fFitModulationV2v3 = 0x0; + TF1* fFitModulationV2v3P = 0x0; + TH1F* hPtsumSumptFitRM = nullptr; + TF1* fFitModulationRM = 0x0; + + 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 jetRadiiBins = (std::vector)jetRadii; + if (jetRadiiBins.size() > 1) { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + (std::abs(jetRadiiBins[jetRadiiBins.size() - 1] - jetRadiiBins[jetRadiiBins.size() - 2]))); + } else { + jetRadiiBins.push_back(jetRadiiBins[jetRadiiBins.size() - 1] + 0.1); + } + + 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()); + + //< MCAxis >// + 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"}; + + 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)); + + 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 (doprocessInOutJetV2 || doprocessInOutJetV2MCD || doprocessSigmaPt || doprocessSigmaPtMCD) { + //=====================< evt pln plot >=====================// + AxisSpec axisCent{cfgAxisCent, "centrality"}; + AxisSpec axisQvec{cfgAxisQvec, "Q"}; + AxisSpec axisQvecF{cfgAxisQvecF, "Q"}; + AxisSpec axisEvtPl{360, -constants::math::PI, constants::math::PI}; + 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}}); + } + histosQA.add("histCent", "Centrality TrkProcess", HistType::kTH1F, {axisCent}); + //< Track efficiency plots >// + registry.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h_collisions_Zvertex", "position of collision ;#it{Z} (cm)", {HistType::kTH1F, {{300, -15.0, 15.0}}}); + //< 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("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_NTrk", "eventNumber vs Number of Track ; #eventNumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + + 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_evtnum_centrlity", "eventNumber vs centrality ; #eventNumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + + 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_rholocal_cent", "#varphi vs #rho(#varphi); #cent; #rho(#varphi) ", {HistType::kTH2F, {{100, 0., 100}, {210, -10.0, 200.0}}}); + //< \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("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("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}}); + //< 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_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_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}}); + } + + if (doprocessSigmaPtMCP || doprocessSigmaPtAreaSubMCP) { + 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("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("leadJetPtMCP", "MCP leadJet Pt ", {HistType::kTH1F, {{200, 0., 200.0}}}); + registry.add("leadJetPhiMCP", "MCP leadJet constituent #phi ", {HistType::kTH1F, {{80, -1.0, 7.}}}); + registry.add("leadJetEtaMCP", "MCP leadJet constituent #eta ", {HistType::kTH1F, {{100, -1.0, 1.0}}}); + + registry.add("h_mcp_v2obs_centrality", "fitparameter v2obs vs centrality ; #centrality", {HistType::kTProfile, {cfgAxisVnCent}}); + registry.add("h_mcp_v3obs_centrality", "fitparameter v3obs vs centrality ; #centrality", {HistType::kTProfile, {cfgAxisVnCent}}); + registry.add("h_mcp_fitparaRho_evtnum", "fitparameter #rho_{0} vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_mcp_fitparaPsi2_evtnum", "fitparameter #Psi_{2} vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_mcp_fitparaPsi3_evtnum", "fitparameter #Psi_{3} vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + + registry.add("h2_mcp_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_mcp_centrality_rholocal", "#varphi vs #rho(#varphi); #varphi - #Psi_{EP,2}; #rho(#varphi) ", {HistType::kTH2F, {{120, -10.0, 110.0}, {210, -10.0, 200.0}}}); + registry.add("h_mcp_jet_pt_rhoareasubtracted", "jet pT rholocal;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_mcp_jet_pt_rholocal", "jet pT rholocal;#it{p}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + //< MCP fit test >// + registry.add("h_mcp_evtnum_centrlity", "eventNumber vs centrality ; #eventNumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_ep2_evtnum", "fitparameter #rho_{0} vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + registry.add("h_ep3_evtnum", "fitparameter #Psi_{2} vs evtnum ; #eventnumber", {HistType::kTH1F, {{1000, 0.0, 1000}}}); + + registry.add("h_mcp_jet_pt_in_plane_v2_rho", "jet pT;#it{p}^{in-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_mcp_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_mcp_jet_pt_in_plane_v3_rho", "jet pT;#it{p}^{in-plane}_{T,jet} (GeV/#it{c});entries", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}); + registry.add("h_mcp_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_mcp_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_mcp_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_mcp_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_mcp_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}}); + + registry.add("h3_mcp_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("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, "splitColl"); + registry.get(HIST("h_mcColl_counts"))->GetXaxis()->SetBinLabel(5, "recoEvtSel"); + registry.get(HIST("h_mcColl_counts"))->GetXaxis()->SetBinLabel(6, "centralitycut"); + registry.get(HIST("h_mcColl_counts"))->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_mc_zvertex", "position of collision ;#it{Z} (cm)", {HistType::kTH1F, {{300, -15.0, 15.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, {{6, 0.0, 6.0}}}); + registry.add("h_mc_rho_matched", "mc collision rho;#rho (GeV/#it{c}); counts", {HistType::kTH1F, {{500, -100.0, 500.0}}}); + registry.add("h_accept_Track_Match", "all and accept track;Track;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + + if (useMedianRho) { + 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, {jetPtAxisRhoAreaSub, jetPtAxisRhoAreaSub}}); + 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, {jetPtAxisRhoAreaSub, jetPtAxisRhoAreaSub}}); + 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}}}); + + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_in_mcdetaconstraint", "corr pT mcd vs. corr cpT mcp in-plane;#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_in_mcpetaconstraint", "corr pT mcd vs. corr cpT mcp in-plane;#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_in", "jet mcp corr pT vs. corr delta pT / jet mcp corr pt in-plane;#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_in", "jet mcd corr pT vs. corr delta pT / jet mcd corr pt in-plane;#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_in", "jet mcp corr pT vs. jet mcd corr pT / jet mcp corr pt in-plane;#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_mcp_matchedgeo_out_mcdetaconstraint", "corr pT mcd vs. corr cpT mcp out-of-plane;#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_out_mcpetaconstraint", "corr pT mcd vs. corr cpT mcp out-of-plane;#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_out", "jet mcp corr pT vs. corr delta pT / jet mcp corr pt out-of-plane;#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_out", "jet mcd corr pT vs. corr delta pT / jet mcd corr pt out-of-plane;#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_out", "jet mcp corr pT vs. jet mcd corr pT / jet mcp corr pt out-of-plane;#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}}}); + } + + if (useLocalRho) { + registry.add("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_incl_rhoareasubtracted_mcdetaconstraint", "corr pT mcd vs. corr cpT mcp in-plane;#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_incl_rhoareasubtracted_mcpetaconstraint", "corr pT mcd vs. corr cpT mcp in-plane;#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_incl_rhoareasubtracted", "jet mcp corr pT vs. corr delta pT / jet mcp corr pt in-plane;#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_incl_rhoareasubtracted", "jet mcd corr pT vs. corr delta pT / jet mcd corr pt in-plane;#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_incl_rhoareasubtracted", "jet mcp corr pT vs. jet mcd corr pT / jet mcp corr pt in-plane;#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_mcp_matchedgeo_in_rhoareasubtracted_mcdetaconstraint", "corr pT mcd vs. corr cpT mcp in-plane;#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_in_rhoareasubtracted_mcpetaconstraint", "corr pT mcd vs. corr cpT mcp in-plane;#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_in_rhoareasubtracted", "jet mcp corr pT vs. corr delta pT / jet mcp corr pt in-plane;#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_in_rhoareasubtracted", "jet mcd corr pT vs. corr delta pT / jet mcd corr pt in-plane;#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_in_rhoareasubtracted", "jet mcp corr pT vs. jet mcd corr pT / jet mcp corr pt in-plane;#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_mcp_matchedgeo_out_rhoareasubtracted_mcdetaconstraint", "corr pT mcd vs. corr cpT mcp out-of-plane;#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_out_rhoareasubtracted_mcpetaconstraint", "corr pT mcd vs. corr cpT mcp out-of-plane;#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_out_rhoareasubtracted", "jet mcp corr pT vs. corr delta pT / jet mcp corr pt out-of-plane;#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_out_rhoareasubtracted", "jet mcd corr pT vs. corr delta pT / jet mcd corr pt out-of-plane;#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_out_rhoareasubtracted", "jet mcp corr pT vs. jet mcd corr pT / jet mcp corr pt out-of-plane;#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("h_accept_Track", "all and accept track;Track;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}); + registry.get(HIST("h_accept_Track"))->GetXaxis()->SetBinLabel(1, "acceptTrk"); + registry.get(HIST("h_accept_Track"))->GetXaxis()->SetBinLabel(2, "acceptTrkInFit"); + registry.get(HIST("h_accept_Track"))->GetXaxis()->SetBinLabel(3, "beforeSumptFit"); + registry.get(HIST("h_accept_Track"))->GetXaxis()->SetBinLabel(4, "afterSumptFit"); + registry.get(HIST("h_accept_Track"))->GetXaxis()->SetBinLabel(5, "getNtrk"); + registry.get(HIST("h_accept_Track"))->GetXaxis()->SetBinLabel(6, "getNtrkMCP"); + + //< track test >// + 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}}); + } + 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::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); + Preslice tracksPerJCollision = o2::aod::jtrack::collisionId; + Preslice mcdjetsPerJCollision = o2::aod::jet::collisionId; + PresliceUnsorted> collisionsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; + + template + bool isAcceptedJet(TJets const& jet, bool mcLevelIsParticleLevel = false) + { + double jetAreaFractionMinAcc = -98.0; + double leadingConstituentPtMinAcc = -98.0; + double leadingConstituentPtMaxAcc = 9998.0; + if (jetAreaFractionMin > jetAreaFractionMinAcc) { + if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > leadingConstituentPtMinAcc); + bool checkConstituentMaxPt = (leadingConstituentPtMax < leadingConstituentPtMaxAcc); + 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; + } + + double chiSquareCDF(int nDF, double x) + { + return TMath::Gamma(nDF / 2., x / 2.); + } + + // leading jet fill + template + void fillLeadingJetQA(T const& jets, double& leadingJetPt, double& leadingJetPhi, double& leadingJetEta) + { + for (const auto& jet : jets) { + if (jet.pt() > leadingJetPt) { + leadingJetPt = jet.pt(); + leadingJetEta = jet.eta(); + leadingJetPhi = jet.phi(); + } + } + registry.fill(HIST("leadJetPt"), leadingJetPt); + registry.fill(HIST("leadJetPhi"), leadingJetPhi); + registry.fill(HIST("leadJetEta"), leadingJetEta); + } + + // create h_ptsum_sumpt_fit, with number of Track + template + void getNtrk(T const& tracks, U const& jets, int& nTrk, double& evtnum, double& leadingJetEta) + { + 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"), 4.5); + nTrk += 1; + } + } + registry.fill(HIST("h_evtnum_NTrk"), evtnum, nTrk); + } + } + + // fill nTrk plot for fit rho(varphi) + template + void fillNtrkCheck(U const& tracks, J const& jets, TH1F* hPtsumSumptFit, double& leadingJetEta) + { + 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"), 1.5); + } + } + + for (auto const& track : tracks) { + registry.fill(HIST("h_accept_Track"), 2.5); + if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > jetRadius) && track.pt() >= localRhoFitPtMin && track.pt() <= localRhoFitPtMax) { + registry.fill(HIST("h_accept_Track"), 3.5); + hPtsumSumptFit->Fill(track.phi(), track.pt()); + } + } + } + } + + // MCP leading jet fill + template + void fillLeadingJetQAMCP(T const& jets, double& leadingJetPt, double& leadingJetPhi, double& leadingJetEta) + { + for (const auto& jet : jets) { + if (jet.pt() > leadingJetPt) { + leadingJetPt = jet.pt(); + leadingJetEta = jet.eta(); + leadingJetPhi = jet.phi(); + } + } + registry.fill(HIST("leadJetPtMCP"), leadingJetPt); + registry.fill(HIST("leadJetPhiMCP"), leadingJetPhi); + registry.fill(HIST("leadJetEtaMCP"), leadingJetEta); + } + + // Run General_Purpose MC MCP + template + void fitFncAreaSubMCP(U const& collision, J const& jets, TH1F* hPtsumSumptFitMCP, bool mcLevelIsParticleLevel, float weight = 1.0) + { + 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] > collQvecAmpDetId) { + ep2 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } else if (nmode == cfgNmodB) { + if (collision.qvecAmp()[detId] > collQvecAmpDetId) { + ep3 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } + } + + const char* fitFunctionV2v3P = "[0] * (1. + 2. * ([1] * std::cos(2. * (x - [2])) + [3] * std::cos(3. * (x - [4]))))"; + fFitModulationV2v3P = new TF1("fit_kV3", fitFunctionV2v3P, 0, o2::constants::math::TwoPI); + //=========================< set parameter >=========================// + fFitModulationV2v3P->SetParameter(0, 1.); + fFitModulationV2v3P->SetParameter(1, 0.01); + fFitModulationV2v3P->SetParameter(3, 0.01); + + if (ep2 < 0) { + double ep2fix = RecoDecay::constrainAngle(ep2); + fFitModulationV2v3P->FixParameter(2, ep2fix); + } else { + fFitModulationV2v3P->FixParameter(2, ep2); + } + if (ep3 < 0) { + double ep3fix = RecoDecay::constrainAngle(ep3); + fFitModulationV2v3P->FixParameter(4, ep3fix); + } else { + fFitModulationV2v3P->FixParameter(4, ep3); + } + + hPtsumSumptFitMCP->Fit(fFitModulationV2v3P, "Q", "ep", 0, o2::constants::math::TwoPI); + + double temppara[5]; + temppara[0] = fFitModulationV2v3P->GetParameter(0); + temppara[1] = fFitModulationV2v3P->GetParameter(1); + temppara[2] = fFitModulationV2v3P->GetParameter(2); + temppara[3] = fFitModulationV2v3P->GetParameter(3); + temppara[4] = fFitModulationV2v3P->GetParameter(4); + if (temppara[0] == 0) { + return; + } + registry.fill(HIST("h_mcp_fitparaRho_evtnum"), evtnum, temppara[0]); + registry.fill(HIST("h_mcp_fitparaPsi2_evtnum"), evtnum, temppara[2]); + registry.fill(HIST("h_mcp_fitparaPsi3_evtnum"), evtnum, temppara[4]); + registry.fill(HIST("h_mcp_v2obs_centrality"), collision.centFT0M(), temppara[1]); + registry.fill(HIST("h_mcp_v3obs_centrality"), collision.centFT0M(), temppara[3]); + registry.fill(HIST("h_mcp_evtnum_centrlity"), evtnum, collision.centFT0M()); + + 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, mcLevelIsParticleLevel)) { + continue; + } + if (jet.r() != round(selectedJetsRadius * 100.0f)) { + continue; + } + + double integralValue = fFitModulationV2v3P->Integral(jet.phi() - jetRadius, jet.phi() + jetRadius); + double rholocal = collision.rho() / (2 * jetRadius * temppara[0]) * integralValue; + registry.fill(HIST("h2_mcp_phi_rholocal"), jet.phi() - ep2, rholocal, weight); + registry.fill(HIST("h2_mcp_centrality_rholocal"), collision.centFT0M(), rholocal, weight); + if (nmode == cfgNmodA) { + registry.fill(HIST("h_mcp_jet_pt_rholocal"), jet.pt() - (rholocal * jet.area()), weight); + + double phiMinusPsi2; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + continue; + } + 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_mcp_jet_pt_in_plane_v2_rho"), jet.pt() - (rholocal * jet.area()), weight); + registry.fill(HIST("h2_mcp_centrality_jet_pt_in_plane_v2_rho"), collision.centFT0M(), jet.pt() - (rholocal * jet.area()), weight); + } else { + registry.fill(HIST("h_mcp_jet_pt_out_of_plane_v2_rho"), jet.pt() - (rholocal * jet.area()), weight); + registry.fill(HIST("h2_mcp_centrality_jet_pt_out_of_plane_v2_rho"), collision.centFT0M(), jet.pt() - (rholocal * jet.area()), weight); + } + } else if (nmode == cfgNmodB) { + double phiMinusPsi3; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + 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_mcp_jet_pt_in_plane_v3_rho"), jet.pt() - (rholocal * jet.area()), weight); + registry.fill(HIST("h2_mcp_centrality_jet_pt_in_plane_v3_rho"), collision.centFT0M(), jet.pt() - (rholocal * jet.area()), weight); + } else { + registry.fill(HIST("h_mcp_jet_pt_out_of_plane_v3_rho"), jet.pt() - (rholocal * jet.area()), weight); + registry.fill(HIST("h2_mcp_centrality_jet_pt_out_of_plane_v3_rho"), collision.centFT0M(), jet.pt() - (rholocal * jet.area()), weight); + } + } + } + } + } + + // Run jet-jet MC MCP leading jet fill + template + void fitFncMCP(U const& collision, J const& jets, bool mcLevelIsParticleLevel, float weight = 1.0) + { + 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] > collQvecAmpDetId) { + ep2 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } else if (nmode == cfgNmodB) { + if (collision.qvecAmp()[detId] > collQvecAmpDetId) { + ep3 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } + } + registry.fill(HIST("h_mcp_evtnum_centrlity"), evtnum, collision.centFT0M()); + registry.fill(HIST("h_ep2_evtnum"), evtnum, ep2); + registry.fill(HIST("h_ep3_evtnum"), evtnum, ep3); + + 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, mcLevelIsParticleLevel)) { + continue; + } + if (jet.r() != round(selectedJetsRadius * 100.0f)) { + continue; + } + + if (nmode == cfgNmodA) { + registry.fill(HIST("h_mcp_jet_pt_rhoareasubtracted"), jet.pt(), weight); + + double phiMinusPsi2; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + continue; + } + 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_mcp_jet_pt_in_plane_v2_rho"), jet.pt(), weight); + registry.fill(HIST("h2_mcp_centrality_jet_pt_in_plane_v2_rho"), collision.centFT0M(), jet.pt(), weight); + } else { + registry.fill(HIST("h_mcp_jet_pt_out_of_plane_v2_rho"), jet.pt(), weight); + registry.fill(HIST("h2_mcp_centrality_jet_pt_out_of_plane_v2_rho"), collision.centFT0M(), jet.pt(), weight); + } + } else if (nmode == cfgNmodB) { + double phiMinusPsi3; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + 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_mcp_jet_pt_in_plane_v3_rho"), jet.pt(), weight); + registry.fill(HIST("h2_mcp_centrality_jet_pt_in_plane_v3_rho"), collision.centFT0M(), jet.pt(), weight); + } else { + registry.fill(HIST("h_mcp_jet_pt_out_of_plane_v3_rho"), jet.pt(), weight); + registry.fill(HIST("h2_mcp_centrality_jet_pt_out_of_plane_v3_rho"), collision.centFT0M(), jet.pt(), weight); + } + } + } + } + } + + // Run General_Purpose MC MCP + 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); + 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); + } + } + } + + // Run jet-jet MC MCP + 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); + } + } + + 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 fillGeoMatchedHistograms(TBase const& jetMCD, double ep2, 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)) { + int evtPlnAngleA = 7; + int evtPlnAngleB = 3; + int evtPlnAngleC = 5; + double phiMinusPsi2 = jetMCD.phi() - ep2; + 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_mcdetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeo"), corrBasejetpt, dcorrpt / corrBasejetpt, weight); + 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("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_in_mcdetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeo_in"), corrBasejetpt, dcorrpt / corrBasejetpt, weight); + } else { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_out_mcdetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeo_out"), corrBasejetpt, dcorrpt / corrBasejetpt, weight); + } + } + if (jetfindingutilities::isInEtaAcceptance(jetMCP, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_mcpetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeo"), corrTagjetpt, dcorrpt / corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo"), corrTagjetpt, corrBasejetpt / corrTagjetpt, weight); + 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("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_in_mcpetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeo_in"), corrTagjetpt, dcorrpt / corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo_in"), corrTagjetpt, corrBasejetpt / corrTagjetpt, weight); + } else { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_out_mcpetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeo_out"), corrTagjetpt, dcorrpt / corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo_out"), corrTagjetpt, corrBasejetpt / corrTagjetpt, weight); + } + } + } + } + } + } + + template + void fillGeoMatchedCorrHistograms(TBase const& jetMCD, TF1* fFitModulationRM, float tempparaA, double ep2, float rho, bool subtractMCPBackground, float mcrho, 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)) { + int evtPlnAngleA = 7; + int evtPlnAngleB = 3; + int evtPlnAngleC = 5; + double integralValue = fFitModulationRM->Integral(jetMCD.phi() - jetRadius, jetMCD.phi() + jetRadius); + double rholocal = rho / (2 * jetRadius * tempparaA) * integralValue; + double corrBasejetpt = jetMCD.pt() - (rholocal * jetMCD.area()); + double corrTagjetpt; + if (subtractMCPBackground) { + double integralValueMCP = fFitModulationRM->Integral(jetMCP.phi() - jetRadius, jetMCP.phi() + jetRadius); + double rholocalMCP = mcrho / (2 * jetRadius * tempparaA) * integralValueMCP; + corrTagjetpt = jetMCP.pt() - (rholocalMCP * jetMCP.area()); + } else { + corrTagjetpt = jetMCP.pt(); + } + double dcorrpt = corrTagjetpt - corrBasejetpt; + double phiMinusPsi2 = jetMCD.phi() - ep2; + if (jetfindingutilities::isInEtaAcceptance(jetMCD, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_incl_rhoareasubtracted_mcdetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeo_incl_rhoareasubtracted"), corrBasejetpt, dcorrpt / corrBasejetpt, weight); + 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("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_in_rhoareasubtracted_mcdetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeo_in_rhoareasubtracted"), corrBasejetpt, dcorrpt / corrBasejetpt, weight); + } else { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_out_rhoareasubtracted_mcdetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_diff_matchedgeo_out_rhoareasubtracted"), corrBasejetpt, dcorrpt / corrBasejetpt, weight); + } + } + if (jetfindingutilities::isInEtaAcceptance(jetMCP, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_incl_rhoareasubtracted_mcpetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeo_incl_rhoareasubtracted"), corrTagjetpt, dcorrpt / corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo_incl_rhoareasubtracted"), corrTagjetpt, corrBasejetpt / corrTagjetpt, weight); + 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("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_in_rhoareasubtracted_mcpetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeo_in_rhoareasubtracted"), corrTagjetpt, dcorrpt / corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo_in_rhoareasubtracted"), corrTagjetpt, corrBasejetpt / corrTagjetpt, weight); + } else { + registry.fill(HIST("h2_jet_pt_mcd_jet_pt_mcp_matchedgeo_out_rhoareasubtracted_mcpetaconstraint"), corrBasejetpt, corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_diff_matchedgeo_out_rhoareasubtracted"), corrTagjetpt, dcorrpt / corrTagjetpt, weight); + registry.fill(HIST("h2_jet_pt_mcp_jet_pt_ratio_matchedgeo_out_rhoareasubtracted"), corrTagjetpt, corrBasejetpt / corrTagjetpt, weight); + } + } + } + } + } + } + + //=======================================[ process area ]=============================================// + 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()); + + //=====================< evt pln [n=2->\Psi_2, n=3->\Psi_3] >=====================// + int cfgNmodA = 2; + int cfgNmodB = 3; + 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); + + if (nmode == cfgNmodA) { + if (collision.qvecAmp()[detId] > collQvecAmpDetId || collision.qvecAmp()[refAId] < collQvecAmpDetId || collision.qvecAmp()[refBId] < collQvecAmpDetId) { + 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()); + } + } + + 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) { + double phiMinusPsi2; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + 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); + + 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.centFT0M(), 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.centFT0M(), 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); + } else { + registry.fill(HIST("h_jet_pt_out_of_plane_v3"), jet.pt() - (collision.rho() * jet.area()), 1.0); + } + } + } + } + } + PROCESS_SWITCH(JetChargedV2, processInOutJetV2, "Jet V2 in and out of plane", false); + + void processInOutJetV2MCD(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()); + //=====================< evt pln [n=2->\Psi_2, n=3->\Psi_3] >=====================// + int cfgNmodA = 2; + int cfgNmodB = 3; + 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); + + if (nmode == cfgNmodA) { + if (collision.qvecAmp()[detId] > collQvecAmpDetId || collision.qvecAmp()[refAId] < collQvecAmpDetId || collision.qvecAmp()[refBId] < collQvecAmpDetId) { + 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()); + } + } + + 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) { + double phiMinusPsi2; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + 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); + + 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.centFT0M(), 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.centFT0M(), 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); + } else { + registry.fill(HIST("h_jet_pt_out_of_plane_v3"), jet.pt() - (collision.rho() * jet.area()), 1.0); + } + } + } + } + } + PROCESS_SWITCH(JetChargedV2, processInOutJetV2MCD, "Jet V2 in and out of plane MCD", false); + + 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); + registry.fill(HIST("h_collisions_Zvertex"), collision.posZ()); + double leadingJetPt = -1; + double leadingJetPhi = -1; + double leadingJetEta = -1; + fillLeadingJetQA(jets, leadingJetPt, leadingJetPhi, leadingJetEta); + + int nTrk = 0; + getNtrk(tracks, jets, nTrk, evtnum, leadingJetEta); + 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); + + fillNtrkCheck(tracks, jets, hPtsumSumptFit, leadingJetEta); + + 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] > collQvecAmpDetId) { + ep2 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } else if (nmode == cfgNmodB) { + if (collision.qvecAmp()[detId] > collQvecAmpDetId) { + ep3 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } + } + + 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); + + if (ep2 < 0) { + double ep2fix = RecoDecay::constrainAngle(ep2); + fFitModulationV2v3->FixParameter(2, ep2fix); + } else { + fFitModulationV2v3->FixParameter(2, ep2); + } + if (ep3 < 0) { + double 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); + + registry.fill(HIST("h_fitparaRho_evtnum"), evtnum, temppara[0]); + registry.fill(HIST("h_fitparaPsi2_evtnum"), evtnum, temppara[2]); + registry.fill(HIST("h_fitparaPsi3_evtnum"), evtnum, temppara[4]); + registry.fill(HIST("h_v2obs_centrality"), collision.centFT0M(), temppara[1]); + registry.fill(HIST("h_v3obs_centrality"), collision.centFT0M(), temppara[3]); + registry.fill(HIST("h_evtnum_centrlity"), evtnum, collision.centFT0M()); + + if (temppara[0] == 0) { + return; + } + + 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); + + double evtcent = collision.centFT0M(); + if (cfgChkFitQuality) { + int evtCentAreaMin = 0; + int evtCentAreaMax = 5; + int evtMidAreaMin = 30; + int evtMidAreaMax = 50; + registry.fill(HIST("h_PvalueCDF_CombinFit"), cDF); + registry.fill(HIST("h2_PvalueCDFCent_CombinFit"), collision.centFT0M(), cDF); + registry.fill(HIST("h2_Chi2Cent_CombinFit"), collision.centFT0M(), chiSqr / (static_cast(nDF))); + registry.fill(HIST("h2_PChi2_CombinFit"), cDF, chiSqr / (static_cast(nDF))); + 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))); + } + 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_rholocal_cent"), collision.centFT0M(), rholocal, 1.0); + + if (nmode == cfgNmodA) { + double phiMinusPsi2; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + 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.centFT0M(), 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.centFT0M(), jet.pt() - (rholocal * jet.area()), 1.0); + } + } else if (nmode == cfgNmodB) { + double phiMinusPsi3; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + 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); + } else { + registry.fill(HIST("h_jet_pt_out_of_plane_v3_rho"), 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); + 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; + float randomConePt = 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("h3_centrality_deltapT_RandomCornPhi_localrhovsphi"), collision.centFT0M(), 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 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 ((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, 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) && (std::fabs(track.eta() - leadingJetEta) > randomConeR)) { // 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.centFT0M(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, rcPhiPsi2, 1.0); + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet"), collision.centFT0M(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), rcPhiPsi2, 1.0); + } else if (nmode == cfgNmodB) { + continue; + } + } + delete hPtsumSumptFit; + delete fFitModulationV2v3; + evtnum += 1; + } + PROCESS_SWITCH(JetChargedV2, processSigmaPt, "Sigma pT and bkg as fcn of phi", false); + + void processSigmaPtMCD(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, skipMBGapEvents)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + } + + double leadingJetPt = -1; + double leadingJetPhi = -1; + double leadingJetEta = -1; + fillLeadingJetQA(jets, leadingJetPt, leadingJetPhi, leadingJetEta); + + int nTrk = 0; + getNtrk(tracks, jets, nTrk, evtnum, leadingJetEta); + 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); + + fillNtrkCheck(tracks, jets, hPtsumSumptFit, leadingJetEta); + + 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] > collQvecAmpDetId) { + ep2 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } else if (nmode == cfgNmodB) { + if (collision.qvecAmp()[detId] > collQvecAmpDetId) { + ep3 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } + } + + 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); + + if (ep2 < 0) { + double ep2fix = RecoDecay::constrainAngle(ep2); + fFitModulationV2v3->FixParameter(2, ep2fix); + } else { + fFitModulationV2v3->FixParameter(2, ep2); + } + if (ep3 < 0) { + double 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); + + registry.fill(HIST("h_fitparaRho_evtnum"), evtnum, temppara[0]); + registry.fill(HIST("h_fitparaPsi2_evtnum"), evtnum, temppara[2]); + registry.fill(HIST("h_fitparaPsi3_evtnum"), evtnum, temppara[4]); + registry.fill(HIST("h_v2obs_centrality"), collision.centFT0M(), temppara[1]); + registry.fill(HIST("h_v3obs_centrality"), collision.centFT0M(), temppara[3]); + registry.fill(HIST("h_evtnum_centrlity"), evtnum, collision.centFT0M()); + + if (temppara[0] == 0) { + return; + } + + 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); + + double evtcent = collision.centFT0M(); + if (cfgChkFitQuality) { + int evtCentAreaMin = 0; + int evtCentAreaMax = 5; + int evtMidAreaMin = 30; + int evtMidAreaMax = 50; + registry.fill(HIST("h_PvalueCDF_CombinFit"), cDF); + registry.fill(HIST("h2_PvalueCDFCent_CombinFit"), collision.centFT0M(), cDF); + registry.fill(HIST("h2_Chi2Cent_CombinFit"), collision.centFT0M(), chiSqr / (static_cast(nDF))); + registry.fill(HIST("h2_PChi2_CombinFit"), cDF, chiSqr / (static_cast(nDF))); + 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_rholocal_cent"), collision.centFT0M(), rholocal, 1.0); + + if (nmode == cfgNmodA) { + double phiMinusPsi2; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + 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.centFT0M(), 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.centFT0M(), jet.pt() - (rholocal * jet.area()), 1.0); + } + } else if (nmode == cfgNmodB) { + double phiMinusPsi3; + if (collision.qvecAmp()[detId] < collQvecAmpDetId) { + 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); + } else { + registry.fill(HIST("h_jet_pt_out_of_plane_v3_rho"), 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); + 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; + float randomConePt = 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("h3_centrality_deltapT_RandomCornPhi_localrhovsphi"), collision.centFT0M(), 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 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 ((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, 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) && (std::fabs(track.eta() - leadingJetEta) > randomConeR)) { // 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.centFT0M(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rholocalRC, rcPhiPsi2, 1.0); + registry.fill(HIST("h3_centrality_deltapT_RandomCornPhi_rhorandomconewithoutleadingjet"), collision.centFT0M(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), rcPhiPsi2, 1.0); + } else if (nmode == cfgNmodB) { + continue; + } + } + delete hPtsumSumptFit; + delete fFitModulationV2v3; + evtnum += 1; + } + PROCESS_SWITCH(JetChargedV2, processSigmaPtMCD, "jet spectra with rho-area subtraction for MCD", false); + + void processSigmaPtAreaSubMCP(McParticleCollision::iterator const& mccollision, + soa::SmallGroups> const& collisions, + soa::Join const& jets, + aod::JetTracks const& tracks, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + int acceptSplitCollInMCP = 2; + + 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); + if (acceptSplitCollisions == 0 && collisions.size() > 1) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 3.5); + + bool hasSel8Coll = false; + bool centralityIsGood = false; + bool occupancyIsGood = false; + if (acceptSplitCollisions == acceptSplitCollInMCP) { + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((centralityMin < collisions.begin().centFT0M()) && (collisions.begin().centFT0M() < 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.centFT0M()) && (collision.centFT0M() < centralityMax)) { + centralityIsGood = true; + } + if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + } + } + if (!hasSel8Coll) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 4.5); + + if (!centralityIsGood) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 5.5); + + if (!occupancyIsGood) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 6.5); + registry.fill(HIST("h_mcColl_rho"), mccollision.rho()); + 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; + } + fillMCPAreaSubHistograms(jet, mccollision.rho()); + } + + double leadingJetPt = -1; + double leadingJetPhi = -1; + double leadingJetEta = -1; + int nTrk = 0; + for (auto const& collision : collisions) { + auto collTracks = tracks.sliceBy(tracksPerJCollision, collision.globalIndex()); + fillLeadingJetQAMCP(jets, leadingJetPt, leadingJetPhi, leadingJetEta); + + if (jets.size() > 0) { + for (auto const& track : collTracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > jetRadius) && track.pt() >= localRhoFitPtMin && track.pt() <= localRhoFitPtMax) { + nTrk += 1; + } + } + } + if (nTrk <= 0) { + return; + } + hPtsumSumptFitMCP = 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& track : collTracks) { + if (jetderiveddatautilities::selectTrack(track, trackSelection) && (std::fabs(track.eta() - leadingJetEta) > jetRadius) && track.pt() >= localRhoFitPtMin && track.pt() <= localRhoFitPtMax) { + hPtsumSumptFitMCP->Fill(track.phi(), track.pt()); + } + } + } + fitFncAreaSubMCP(collision, jets, hPtsumSumptFitMCP, mcLevelIsParticleLevel); + } + + delete hPtsumSumptFitMCP; + delete fFitModulationV2v3P; + evtnum += 1; + } + PROCESS_SWITCH(JetChargedV2, processSigmaPtAreaSubMCP, "jet spectra with area-based subtraction for MC particle level", false); + + void processSigmaPtMCP(aod::JMcCollisions::iterator const& mccollision, + soa::SmallGroups> const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + int acceptSplitCollInMCP = 2; + + 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); + if (acceptSplitCollisions == 0 && collisions.size() > 1) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 3.5); + + bool hasSel8Coll = false; + bool centralityIsGood = false; + bool occupancyIsGood = false; + if (acceptSplitCollisions == acceptSplitCollInMCP) { + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((centralityMin < collisions.begin().centFT0M()) && (collisions.begin().centFT0M() < 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.centFT0M()) && (collision.centFT0M() < centralityMax)) { + centralityIsGood = true; + } + if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + } + } + if (!hasSel8Coll) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 4.5); + + if (!centralityIsGood) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 5.5); + + if (!occupancyIsGood) { + return; + } + registry.fill(HIST("h_mcColl_counts"), 6.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); + } + for (auto const& collision : collisions) { + fitFncMCP(collision, jets, mcLevelIsParticleLevel); + } + evtnum += 1; + } + PROCESS_SWITCH(JetChargedV2, processSigmaPtMCP, "jet spectra with area-based subtraction for MC particle level", false); + + void processJetsMatchedSubtracted(McParticleCollision::iterator const& mccollision, + soa::SmallGroups> const& collisions, + ChargedMCDMatchedJets const& mcdjets, + ChargedMCPMatchedJets const&, + aod::JetTracks const& tracks, 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.centFT0M() < centralityMin || collision.centFT0M() > 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; + } + + double leadingJetPt = -1; + double leadingJetEta = -1; + + if (mcdjet.pt() > leadingJetPt) { + leadingJetPt = mcdjet.pt(); + leadingJetEta = mcdjet.eta(); + } + int nTrk = 0; + if (mcdjet.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"), 4.5); + nTrk += 1; + } + } + } + if (nTrk <= 0) { + return; + } + hPtsumSumptFitRM = new TH1F("h_ptsum_sumpt_fit_RM", "h_ptsum_sumpt_RM fit use", TMath::CeilNint(std::sqrt(nTrk)), 0., o2::constants::math::TwoPI); + 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_Match"), 0.5); + hPtsumSumptFitRM->Fill(track.phi(), track.pt()); + } + } + + double ep2 = 0.; + double ep3 = 0.; + int cfgNmodA = 2; + int cfgNmodB = 3; + + 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] > collQvecAmpDetId) { + ep2 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } else if (nmode == cfgNmodB) { + if (collision.qvecAmp()[detId] > collQvecAmpDetId) { + ep3 = helperEP.GetEventPlane(collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3], nmode); + } + } + } + + const char* fitFunctionRM = "[0] * (1. + 2. * ([1] * std::cos(2. * (x - [2])) + [3] * std::cos(3. * (x - [4]))))"; + fFitModulationRM = new TF1("fit_kV3", fitFunctionRM, 0, o2::constants::math::TwoPI); + //=========================< set parameter >=========================// + fFitModulationRM->SetParameter(0, 1.); + fFitModulationRM->SetParameter(1, 0.01); + fFitModulationRM->SetParameter(3, 0.01); + + if (ep2 < 0) { + double ep2fix = RecoDecay::constrainAngle(ep2); + fFitModulationRM->FixParameter(2, ep2fix); + } else { + fFitModulationRM->FixParameter(2, ep2); + } + if (ep3 < 0) { + double ep3fix = RecoDecay::constrainAngle(ep3); + fFitModulationRM->FixParameter(4, ep3fix); + } else { + fFitModulationRM->FixParameter(4, ep3); + } + + hPtsumSumptFitRM->Fit(fFitModulationRM, "Q", "ep", 0, o2::constants::math::TwoPI); + + float tempparaA; + tempparaA = fFitModulationRM->GetParameter(0); + + if (tempparaA == 0) { + return; + } + if (useMedianRho) { + fillGeoMatchedHistograms(mcdjet, ep2, collision.rho(), mcrho); + } + if (useLocalRho) { + fillGeoMatchedCorrHistograms(mcdjet, fFitModulationRM, tempparaA, ep2, collision.rho(), subtractMCPBackground, collision.rho()); + } + delete hPtsumSumptFitRM; + delete fFitModulationRM; + evtnum += 1; + } + } + } + PROCESS_SWITCH(JetChargedV2, processJetsMatchedSubtracted, "matched mcp and mcd jets", false); + + void processTracksQA(soa::Filtered>::iterator const& collision, + soa::Filtered> const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + fillTrackHistograms(track); + } + } + PROCESS_SWITCH(JetChargedV2, processTracksQA, "QA for charged tracks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/jetFinderB0QA.cxx b/PWGJE/Tasks/jetFinderB0QA.cxx new file mode 100644 index 00000000000..8935968ac5b --- /dev/null +++ b/PWGJE/Tasks/jetFinderB0QA.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. + +// jet finder B0 charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +using JetFinderB0QATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-b0-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetFinderBplusQA.cxx b/PWGJE/Tasks/jetFinderBplusQA.cxx new file mode 100644 index 00000000000..a713c3a767e --- /dev/null +++ b/PWGJE/Tasks/jetFinderBplusQA.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. + +// jet finder B+ charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +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..1ebe0ec649b --- /dev/null +++ b/PWGJE/Tasks/jetFinderD0QA.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. + +// jet finder D0 charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +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..296ede5979a --- /dev/null +++ b/PWGJE/Tasks/jetFinderDielectronQA.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. + +// jet finder Dielectron charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +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..877cbf60d8a --- /dev/null +++ b/PWGJE/Tasks/jetFinderDplusQA.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. + +// jet finder D+ charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +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/jetFinderDsQA.cxx b/PWGJE/Tasks/jetFinderDsQA.cxx new file mode 100644 index 00000000000..e04915fb975 --- /dev/null +++ b/PWGJE/Tasks/jetFinderDsQA.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. + +// jet finder Ds charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +using JetFinderDsQATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-ds-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetFinderDstarQA.cxx b/PWGJE/Tasks/jetFinderDstarQA.cxx new file mode 100644 index 00000000000..b8fc0808521 --- /dev/null +++ b/PWGJE/Tasks/jetFinderDstarQA.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. + +// jet finder D* charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +using JetFinderDstarQATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-dstar-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetfinderfullQA.cxx b/PWGJE/Tasks/jetFinderFullQA.cxx similarity index 91% rename from PWGJE/Tasks/jetfinderfullQA.cxx rename to PWGJE/Tasks/jetFinderFullQA.cxx index b5ea2f3d80f..85989036f3e 100644 --- a/PWGJE/Tasks/jetfinderfullQA.cxx +++ b/PWGJE/Tasks/jetFinderFullQA.cxx @@ -13,28 +13,35 @@ // /// \author Nima Zardoshti -#include "CommonConstants/PhysicsConstants.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/EMCALClusterDefinition.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + #include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" +#include +#include +#include +#include +#include +#include +#include -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include -#include "PWGHF/Core/HfHelper.h" +#include +#include +#include +#include +#include -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/Core/JetFindingUtilities.h" - -#include "EventFiltering/filterTables.h" +#include using namespace o2; -using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; @@ -74,6 +81,8 @@ 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; @@ -160,7 +169,7 @@ struct JetFinderFullQATask { 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, {{350, 0, 350}}}); + registry.add("h_jet_phat_part_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}); } if (doprocessJetsMCPMCDMatched || doprocessJetsMCPMCDMatchedWeighted) { @@ -243,7 +252,7 @@ struct JetFinderFullQATask { 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); + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); 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)); @@ -277,7 +286,7 @@ 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); @@ -304,14 +313,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); @@ -327,7 +336,7 @@ 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); @@ -345,7 +354,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(); @@ -362,7 +371,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; } @@ -435,6 +444,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; @@ -453,90 +466,90 @@ 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()); + fillHistograms(jet, collision.centFT0M()); } } 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()); + fillHistograms(jet, collision.centFT0M()); } } 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()); + fillHistograms(jet, collision.centFT0M(), jet.eventWeight()); } } 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); @@ -544,19 +557,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()); @@ -564,34 +577,42 @@ 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); + registry.fill(HIST("h_centrality_collisions"), collision.centFT0M(), 0.5); if (!jetderiveddatautilities::eventEMCAL(collision)) { return; } registry.fill(HIST("h_collisions"), 1.5); - registry.fill(HIST("h_centrality_collisions"), collision.centrality(), 1.5); + registry.fill(HIST("h_centrality_collisions"), collision.centFT0M(), 1.5); fillTrackHistograms(tracks, clusters); } 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 85% rename from PWGJE/Tasks/jetfinderhfQA.cxx rename to PWGJE/Tasks/jetFinderHFQA.cxx index 111868cfdca..b82a5943265 100644 --- a/PWGJE/Tasks/jetfinderhfQA.cxx +++ b/PWGJE/Tasks/jetFinderHFQA.cxx @@ -13,31 +13,34 @@ // /// \author Nima Zardoshti -#include +#include "RecoDecay.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" -#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 +#include +#include -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" - -#include "PWGJE/DataModel/Jet.h" +#include +#include +#include -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/Core/JetHFUtilities.h" -#include "PWGJE/Core/JetFindingUtilities.h" +#include +#include +#include +#include +#include +#include -#include "EventFiltering/filterTables.h" +#include using namespace o2; using namespace o2::analysis; @@ -68,7 +71,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; @@ -79,7 +84,7 @@ struct JetFinderHFQATask { std::vector filledJetHFR_High; std::vector jetRadiiValues; - int eventSelection = -1; + std::vector eventSelectionBits; int trackSelection = -1; std::vector jetPtBins; @@ -87,7 +92,7 @@ struct JetFinderHFQATask { 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; @@ -240,7 +245,7 @@ struct JetFinderHFQATask { 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, {{350, 0, 350}}}); + 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) { @@ -437,21 +442,18 @@ struct JetFinderHFQATask { 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}, {500, -5.0, 5.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}, {500, -5.0, 5.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) { @@ -483,23 +485,22 @@ 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 eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); // Filter candidateCutsD0 = (aod::hf_sel_candidate_d0::isSelD0 >= selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= selectionFlagD0bar); // Filter candidateCutsLc = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLcToPKPi || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLcToPiPK); // Filter candidateCutsBplus = (aod::hf_sel_candidate_bplus::isSelBplusToD0Pi >= selectionFlagBplus); PresliceOptional> perD0CandidateTracks = aod::bkgd0::candidateId; + PresliceOptional> perDplusCandidateTracks = aod::bkgdplus::candidateId; + PresliceOptional> perDsCandidateTracks = aod::bkgds::candidateId; + PresliceOptional> perDstarCandidateTracks = aod::bkgdstar::candidateId; PresliceOptional> perLcCandidateTracks = aod::bkglc::candidateId; + PresliceOptional> perB0CandidateTracks = aod::bkgb0::candidateId; PresliceOptional> perBplusCandidateTracks = aod::bkgbplus::candidateId; + PresliceOptional> perXicToXiPiPiCandidateTracks = aod::bkgxictoxipipi::candidateId; PresliceOptional> perDielectronCandidateTracks = aod::bkgdielectron::candidateId; - PresliceOptional perD0CandidateRhos = aod::bkgd0::candidateId; - PresliceOptional perLcCandidateRhos = aod::bkglc::candidateId; - PresliceOptional perBplusCandidateRhos = aod::bkgbplus::candidateId; - PresliceOptional perDielectronCandidateRhos = aod::bkgdielectron::candidateId; - template bool isAcceptedJet(V const& jet) { @@ -535,7 +536,7 @@ 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); @@ -558,7 +559,7 @@ struct JetFinderHFQATask { 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); @@ -608,7 +609,7 @@ struct JetFinderHFQATask { 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); @@ -664,7 +665,7 @@ 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); @@ -706,7 +707,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; @@ -938,26 +939,28 @@ 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.centFT0M(), track.pt(), track.phi(), weight); + registry.fill(HIST("h3_centrality_track_pt_track_eta"), collision.centFT0M(), track.pt(), track.eta(), 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& candidates, M const& bkgRhos, N const& tracks) + template + void randomCone(T const& collision, U const& jets, V const& candidates, M const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } for (auto const& candidate : candidates) { - auto bkgRho = jetcandidateutilities::slicedPerCandidate(bkgRhos, candidate, perD0CandidateRhos, perLcCandidateRhos, perBplusCandidateRhos, perDielectronCandidateRhos).iteratorAt(0); TRandom3 randomNumber(0); float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); float randomConePhi = randomNumber.Uniform(0.0, 2 * M_PI); @@ -971,7 +974,7 @@ struct JetFinderHFQATask { } } } - registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * bkgRho.rho()); + registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centFT0M(), 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 @@ -999,71 +1002,67 @@ struct JetFinderHFQATask { } } } - registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * bkgRho.rho()); + registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centFT0M(), 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(JetCollisions const&) + 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()); + fillHistograms(jet, collision.centFT0M()); } } 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 candidates_first_as(); - auto bkgRho = jetcandidateutilities::slicedPerCandidate(bkgRhos, jetCandidate, perD0CandidateRhos, perLcCandidateRhos, perBplusCandidateRhos, perDielectronCandidateRhos).iteratorAt(0); - fillRhoAreaSubtractedHistograms(jet, collision.centrality(), bkgRho.rho()); + auto const candidate = jet.template candidates_first_as>(); + fillRhoAreaSubtractedHistograms(jet, collision.centFT0M(), candidate.rho()); } } PROCESS_SWITCH(JetFinderHFQATask, processJetsRhoAreaSubData, "jet finder HF QA for rho-area subtracted jets", false); - void processJetsRhoAreaSubMCD(soa::Filtered::iterator const& collision, - BkgRhoTable const& bkgRhos, + void processJetsRhoAreaSubMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, - CandidateTableMCD 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 candidates_first_as(); - auto bkgRho = jetcandidateutilities::slicedPerCandidate(bkgRhos, jetCandidate, perD0CandidateRhos, perLcCandidateRhos, perBplusCandidateRhos, perDielectronCandidateRhos).iteratorAt(0); - fillRhoAreaSubtractedHistograms(jet, collision.centrality(), bkgRho.rho()); + auto const candidate = jet.template candidates_first_as>(); + fillRhoAreaSubtractedHistograms(jet, collision.centFT0M(), 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&) + 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)) { @@ -1072,21 +1071,21 @@ struct JetFinderHFQATask { if (!isAcceptedJet(jet)) { continue; } - fillEventWiseConstituentSubtractedHistograms(jet, collision.centrality()); + fillEventWiseConstituentSubtractedHistograms(jet, collision.centFT0M()); } } 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); @@ -1094,63 +1093,63 @@ 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()); + fillHistograms(jet, collision.centFT0M()); } } 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()); + fillHistograms(jet, collision.centFT0M(), jet.eventWeight()); } } 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&) { @@ -1158,7 +1157,7 @@ struct JetFinderHFQATask { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(mcdjet)) { + if (!isAcceptedJet(mcdjet)) { continue; } fillMatchedHistograms(mcdjet); @@ -1166,11 +1165,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&) { @@ -1178,7 +1177,7 @@ struct JetFinderHFQATask { if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } - if (!isAcceptedJet(mcdjet)) { + if (!isAcceptedJet(mcdjet)) { continue; } fillMatchedHistograms(mcdjet, mcdjet.eventWeight()); @@ -1186,33 +1185,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 } @@ -1224,19 +1226,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); @@ -1253,38 +1255,38 @@ 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()); @@ -1297,19 +1299,19 @@ struct JetFinderHFQATask { 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::selectChargedTrigger(collision, jetderiveddatautilities::JTrigSelCh::chargedLow)) { + 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)) { + 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)) { + 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()); @@ -1326,17 +1328,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()); @@ -1346,21 +1348,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 @@ -1368,32 +1370,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 } @@ -1405,13 +1407,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); @@ -1434,17 +1436,17 @@ 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); @@ -1457,13 +1459,13 @@ struct JetFinderHFQATask { 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)) { + 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)) { + 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()); @@ -1475,28 +1477,34 @@ 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)) { + registry.fill(HIST("h2_centrality_collisions"), collision.centFT0M(), 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); + registry.fill(HIST("h2_centrality_collisions"), collision.centFT0M(), 1.5); fillTrackHistograms(collision, tracks); } 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); @@ -1505,98 +1513,80 @@ 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 : jetcandidateutilities::slicedPerCandidate(tracks, candidate, perD0CandidateTracks, perLcCandidateTracks, perBplusCandidateTracks, perDielectronCandidateTracks)) { - 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, perDsCandidateTracks, perDstarCandidateTracks, perLcCandidateTracks, perB0CandidateTracks, perBplusCandidateTracks, perXicToXiPiPiCandidateTracks, perDielectronCandidateTracks)) { + registry.fill(HIST("h3_centrality_track_pt_track_phi_eventwiseconstituentsubtracted"), collision.centFT0M(), track.pt(), track.phi()); + registry.fill(HIST("h3_centrality_track_pt_track_eta_eventwiseconstituentsubtracted"), collision.centFT0M(), 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 = jetcandidateutilities::slicedPerCandidate(bkgRhos, candidate, perD0CandidateRhos, perLcCandidateRhos, perBplusCandidateRhos, perDielectronCandidateRhos).iteratorAt(0); 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, 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_centrality_ntracks"), collision.centFT0M(), nTracks); + 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.centFT0M(), candidate.rho()); + registry.fill(HIST("h2_centrality_rhom"), collision.centFT0M(), 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 processRandomConeData(soa::Filtered::iterator const& collision, JetTableDataJoined 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) { - randomCone(collision, jets, candidates, bkgRhos, tracks); + randomCone(collision, jets, candidates, tracks); } PROCESS_SWITCH(JetFinderHFQATask, processRandomConeData, "QA for random cone estimation of background fluctuations in data", false); - void processRandomConeMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, CandidateTableMCD const& candidates, BkgRhoTable const& bkgRhos, soa::Filtered const& tracks) + void processRandomConeMCD(soa::Filtered::iterator const& collision, JetTableMCDJoined const& jets, soa::Join const& candidates, soa::Filtered const& tracks) { - randomCone(collision, jets, candidates, bkgRhos, tracks); + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + randomCone(collision, jets, candidates, tracks); } 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"), jetcandidateutilities::getCandidateInvariantMass(candidate)); 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()); + registry.fill(HIST("h2_centrality_ncandidates"), collision.centFT0M(), candidates.size()); } PROCESS_SWITCH(JetFinderHFQATask, processCandidates, "HF candidate QA", false); }; - -using JetFinderD0QATask = JetFinderHFQATask; -using JetFinderLcQATask = JetFinderHFQATask; -// using JetFinderBplusQATask = JetFinderHFQATask; -using JetFinderDielectronQATask = 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-dielectron-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..4986d583707 --- /dev/null +++ b/PWGJE/Tasks/jetFinderLcQA.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. + +// jet finder Lc charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +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 57% rename from PWGJE/Tasks/jetfinderQA.cxx rename to PWGJE/Tasks/jetFinderQA.cxx index 099fc130926..6ae115a963e 100644 --- a/PWGJE/Tasks/jetfinderQA.cxx +++ b/PWGJE/Tasks/jetFinderQA.cxx @@ -13,30 +13,34 @@ // /// \author Nima Zardoshti -#include -#include +#include "RecoDecay.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.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 +#include +#include +#include -#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 +#include +#include -#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include +#include +#include +#include +#include +#include -#include "EventFiltering/filterTables.h" +#include using namespace o2; using namespace o2::framework; @@ -60,20 +64,29 @@ 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; @@ -81,7 +94,7 @@ struct JetFinderQATask { 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; @@ -111,7 +124,6 @@ struct JetFinderQATask { jetPtBins.push_back(jetPtTemp); jetPtBinsRhoAreaSub.push_back(jetPtTemp); jetPtBinsRhoAreaSub.push_back(-jetPtTemp); - } else { jetPtTemp += 10.0; jetPtBins.push_back(jetPtTemp); @@ -124,70 +136,81 @@ struct JetFinderQATask { 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, {jetPtAxis}}); - registry.add("h_jet_eta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + 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}, 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_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, ""}, 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_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, ""}, {500, -5.0, 5.0}, {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, {500, -5.0, 5.0}}}); + 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, {{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}}}); - registry.add("h_jet_phat_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0, 350}}}); + 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, {{500, -5.0, 5.0}}}); + 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}, 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_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, ""}, 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_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, ""}, {500, -5.0, 5.0}, {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, {500, -5.0, 5.0}}}); + 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) { + 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, {{500, -5.0, 5.0}}}); + 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}, 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_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, ""}, 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_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, ""}, {500, -5.0, 5.0}, {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, {500, -5.0, 5.0}}}); + 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) { @@ -200,124 +223,158 @@ struct JetFinderQATask { 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, {jetPtAxis}}); - registry.add("h_jet_eta_part", "jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + 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, ""}, jetPtAxis, {500, -5.0, 5.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, 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, ""}, {500, -5.0, 5.0}, {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, {500, -5.0, 5.0}}}); + 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, {{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("h_jet_phat_part_weighted", "jet #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{350, 0, 350}}}); + 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, ""}, {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, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + 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, ""}, 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_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, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + 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, ""}, 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_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, ""}, {500, -5.0, 5.0}, {500, -5.0, 5.0}}}); + 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, ""}, 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_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, {{500, -5.0, 5.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, {{500, -5.0, 5.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, {{500, -5.0, 5.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, {{500, -5.0, 5.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, ""}, 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_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, ""}, 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_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, {500, -5.0, 5.0}}}); + 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, {500, -5.0, 5.0}}}); + 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, {500, -5.0, 5.0}}}); + 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("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{5, 0.0, 5.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}, {500, -5.0, 5.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}}}); + registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{5, 0.0, 5.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}, {500, -5.0, 5.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; + Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); + PresliceUnsorted> CollisionsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; + PresliceUnsorted> McCollisionsPerMCPCollision = aod::jmccollision::mcCollisionId; template bool isAcceptedJet(U const& jet) @@ -328,27 +385,49 @@ 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 hadronicRate, float weight = 1.0, float pTHat = 999.) { - 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); @@ -363,6 +442,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"), hadronicRate, jet.pt(), weight); } registry.fill(HIST("h3_jet_r_jet_pt_centrality"), jet.r() / 100.0, jet.pt(), centrality, weight); @@ -372,7 +453,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); @@ -381,7 +462,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); @@ -389,11 +470,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); @@ -404,7 +487,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); @@ -424,6 +507,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); @@ -433,7 +517,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); @@ -442,11 +526,10 @@ struct JetFinderQATask { } template - void fillMCPHistograms(T const& jet, float weight = 1.0) + void fillMCPHistograms(T const& jet, float weight = 1.0, float pTHat = 999.) { - 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); @@ -464,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); @@ -473,10 +556,9 @@ 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 = 999.) { - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jetBase.pt() > pTHatMaxMCD * pTHat) { + if (jetBase.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } @@ -490,13 +572,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); } } } @@ -510,13 +608,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); } } } @@ -534,13 +642,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); } } } @@ -548,23 +666,29 @@ struct JetFinderQATask { } template - void fillTrackHistograms(T const& collision, U const& tracks, float weight = 1.0) + void fillTrackHistograms(T const& collision, U const& tracks, float weight = 1.0, float pTHat = 999.) { + 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.centFT0M(), track.pt(), track.phi(), weight); + registry.fill(HIST("h3_centrality_track_pt_track_eta"), collision.centFT0M(), track.pt(), track.eta(), weight); + registry.fill(HIST("h3_centrality_track_pt_track_dcaxy"), collision.centFT0M(), 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, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { return; } TRandom3 randomNumber(0); @@ -580,7 +704,20 @@ struct JetFinderQATask { } } } - registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("h2_centrality_rhorandomcone"), collision.centFT0M(), 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.centFT0M(), 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 @@ -588,7 +725,7 @@ struct JetFinderQATask { float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; bool jetWasInCone = false; - while (TMath::Sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR) { + 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); @@ -609,224 +746,327 @@ struct JetFinderQATask { } } - registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centrality(), randomConePt - M_PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("h2_centrality_rhorandomconewithoutleadingjet"), collision.centFT0M(), 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.centFT0M(), randomConePtWithoutOneLeadJet - M_PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), collision.centFT0M(), 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.centFT0M(), collision.trackOccupancyInTimeRange(), collision.hadronicRate()); } } 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.centFT0M(), collision.trackOccupancyInTimeRange(), collision.rho()); } } PROCESS_SWITCH(JetFinderQATask, processJetsRhoAreaSubData, "jet finder QA for rho-area subtracted jets", false); - void processJetsRhoAreaSubMCD(soa::Filtered>::iterator const& collision, + void processJetsRhoAreaSubMCD(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.centFT0M(), 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, JetTracksSub const&) + 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()); + fillEventWiseConstituentSubtractedHistograms(jet, collision.centFT0M()); } } 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.centFT0M()); + } + } + 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, aod::JetMcCollisions const&, 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.centFT0M(), collision.trackOccupancyInTimeRange(), collision.hadronicRate(), 1., collision.mcCollision().ptHard()); } } 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, aod::JetMcCollisions const&, soa::Join const& jets, aod::JetTracks const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + if (collision.isOutlier()) { + 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)); 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()); + if (jet.pt() < N * 0.25 * collision.mcCollision().ptHard() && jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h_jet_ptcut"), jet.pt(), N * 0.25, collision.weight()); } } - fillHistograms(jet, collision.centrality(), jet.eventWeight()); + fillHistograms(jet, collision.centFT0M(), collision.trackOccupancyInTimeRange(), collision.hadronicRate(), collision.weight(), collision.mcCollision().ptHard()); } } PROCESS_SWITCH(JetFinderQATask, processJetsMCDWeighted, "jet finder QA mcd with weighted events", false); - void processJetsMCP(soa::Join::iterator const& jet, JetParticles const&, JetMcCollisions const&, soa::Filtered const& collisions) + void processJetsMCP(soa::Join::iterator const& jet, aod::JetParticles const&, soa::Join const& mcCollisions, soa::Filtered const& collisions) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { return; } - if (!isAcceptedJet(jet)) { + if (!isAcceptedJet(jet)) { return; } + auto mcCollision = mcCollisions.sliceBy(McCollisionsPerMCPCollision, jet.mcCollisionId()); if (checkMcCollisionIsMatched) { auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, jet.mcCollisionId()); - if (collisionspermcpjet.size() >= 1) { - fillMCPHistograms(jet); + if (collisionspermcpjet.size() >= 1 && jetderiveddatautilities::selectCollision(collisionspermcpjet.begin(), eventSelectionBits)) { + fillMCPHistograms(jet, 1., mcCollision.begin().ptHard()); } } else { - fillMCPHistograms(jet); + fillMCPHistograms(jet, 1., mcCollision.begin().ptHard()); } } PROCESS_SWITCH(JetFinderQATask, processJetsMCP, "jet finder QA mcp", false); - void processJetsMCPWeighted(soa::Join::iterator const& jet, JetParticles const&, JetMcCollisions const&, soa::Filtered const& collisions) + void processJetsMCPWeighted(soa::Join::iterator const& jet, aod::JetParticles const&, soa::Join const& mcCollisions, 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)); - 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()); + auto mcCollision = mcCollisions.sliceBy(McCollisionsPerMCPCollision, jet.mcCollisionId()); + if (mcCollision.size() == 1) { + for (int N = 1; N < 21; N++) { + if (jet.pt() < N * 0.25 * mcCollision.begin().ptHard() && jet.r() == round(selectedJetsRadius * 100.0f)) { + registry.fill(HIST("h_jet_ptcut_part"), jet.pt(), N * 0.25, mcCollision.begin().weight()); + } } - } - if (checkMcCollisionIsMatched) { - auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, jet.mcCollisionId()); - if (collisionspermcpjet.size() >= 1) { - fillMCPHistograms(jet, jet.eventWeight()); + if (checkMcCollisionIsMatched) { + auto collisionspermcpjet = collisions.sliceBy(CollisionsPerMCPCollision, jet.mcCollisionId()); + if (collisionspermcpjet.size() >= 1 && jetderiveddatautilities::selectCollision(collisionspermcpjet.begin(), eventSelectionBits) && !collisionspermcpjet.begin().isOutlier()) { + fillMCPHistograms(jet, mcCollision.begin().weight(), mcCollision.begin().ptHard()); + } + } else { + fillMCPHistograms(jet, mcCollision.begin().weight(), mcCollision.begin().ptHard()); } - } 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, + aod::JetMcCollisions const&, 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, 1., collision.mcCollision().ptHard()); } } PROCESS_SWITCH(JetFinderQATask, processJetsMCPMCDMatched, "jet finder QA matched mcp and mcd", false); - void processJetsMCPMCDMatchedWeighted(soa::Filtered::iterator const&, - soa::Join const& mcdjets, - soa::Join const&, - JetTracks const&, JetParticles const&) + void processJetsMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, + aod::JetMcCollisions const&, + soa::Join const& mcdjets, + soa::Join const&, + aod::JetTracks const&, aod::JetParticles const&) { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + if (collision.isOutlier()) { + 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, collision.weight(), collision.mcCollision().ptHard()); } } 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 } @@ -838,19 +1078,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); @@ -867,38 +1107,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()); @@ -914,17 +1154,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()); @@ -933,54 +1173,87 @@ 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, + aod::JetMcCollisions const&, + 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)) { + registry.fill(HIST("h2_centrality_collisions"), collision.centFT0M(), 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); + registry.fill(HIST("h2_centrality_collisions"), collision.centFT0M(), 1.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_collisions"), collision.centFT0M(), 2.5); + fillTrackHistograms(collision, tracks, 1., collision.mcCollision().ptHard()); } 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(); + float eventWeight = collision.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); - fillTrackHistograms(collision, tracks, 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); + if (collision.isOutlier()) { + return; + } + registry.fill(HIST("h_collisions"), 3.5); + registry.fill(HIST("h_collisions_weighted"), 3.5, eventWeight); + fillTrackHistograms(collision, tracks, eventWeight, collision.mcCollision().ptHard()); } 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.centFT0M(), track.pt(), track.phi()); + registry.fill(HIST("h3_centrality_track_pt_track_eta_eventwiseconstituentsubtracted"), collision.centFT0M(), 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; @@ -989,25 +1262,60 @@ struct JetFinderQATask { nTracks++; } } - registry.fill(HIST("h2_centrality_ntracks"), collision.centrality(), nTracks); + registry.fill(HIST("h2_centrality_ntracks"), collision.centFT0M(), 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()); + registry.fill(HIST("h2_centrality_rho"), collision.centFT0M(), collision.rho()); + registry.fill(HIST("h2_centrality_rhom"), collision.centFT0M(), collision.rhoM()); } PROCESS_SWITCH(JetFinderQATask, processRho, "QA for rho-area subtracted jets", false); - void processRandomConeData(soa::Filtered>::iterator const& collision, soa::Join const& jets, soa::Filtered 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) + void processRandomConeMCD(soa::Filtered>::iterator const& collision, soa::Join const& jets, soa::Filtered const& tracks) { + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } 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)) { + nTracksAllAcceptanceAndSelected += 1; + if (track.pt() >= trackPtMin && track.pt() < trackPtMax && track.eta() > trackEtaMin && track.eta() < trackEtaMax) { + nTracksInAcceptanceAndSelected += 1; + } + } + } + + 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); + } + } + 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"})}; } +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"jet-finder-charged-qa"})}; // o2-linter: disable=name/o2-task,name/workflow-file +} diff --git a/PWGJE/Tasks/jetfinderv0QA.cxx b/PWGJE/Tasks/jetFinderV0QA.cxx similarity index 87% rename from PWGJE/Tasks/jetfinderv0QA.cxx rename to PWGJE/Tasks/jetFinderV0QA.cxx index 8f0152db0ee..a80ee0eea25 100644 --- a/PWGJE/Tasks/jetfinderv0QA.cxx +++ b/PWGJE/Tasks/jetFinderV0QA.cxx @@ -13,35 +13,30 @@ // /// \author Nima Zardoshti -#include +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" -#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 +#include +#include +#include +#include -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include -#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 +#include +#include +#include -#include "EventFiltering/filterTables.h" +#include using namespace o2; -using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; @@ -68,12 +63,12 @@ struct JetFinderV0QATask { 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"}; - int eventSelection = -1; + std::vector eventSelectionBits; int trackSelection = -1; void init(o2::framework::InitContext&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); auto jetRadiiBins = (std::vector)jetRadii; @@ -164,8 +159,7 @@ struct JetFinderV0QATask { 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 eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); template bool isAcceptedJet(V const& jet) @@ -224,7 +218,7 @@ struct JetFinderV0QATask { 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); @@ -298,112 +292,112 @@ struct JetFinderV0QATask { 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("h2_centrality_track_pt"), collision.centFT0M(), track.pt(), weight); + registry.fill(HIST("h2_centrality_track_eta"), collision.centFT0M(), track.eta(), weight); + registry.fill(HIST("h2_centrality_track_phi"), collision.centFT0M(), track.phi(), weight); + registry.fill(HIST("h2_centrality_track_energy"), collision.centFT0M(), track.energy(), weight); } } - void processDummy(JetCollisions const&) + void processDummy(aod::JetCollisions const&) { } PROCESS_SWITCH(JetFinderV0QATask, 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()); + fillHistograms(jet, collision.centFT0M()); } } PROCESS_SWITCH(JetFinderV0QATask, processJetsData, "jet finder HF QA data", 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()); + fillHistograms(jet, collision.centFT0M()); } } PROCESS_SWITCH(JetFinderV0QATask, 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()); + fillHistograms(jet, collision.centFT0M(), jet.eventWeight()); } } PROCESS_SWITCH(JetFinderV0QATask, 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(JetFinderV0QATask, 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(JetFinderV0QATask, processJetsMCPWeighted, "jet finder HF QA mcp on weighted events", false); - void processMCCollisionsWeighted(JetMcCollision const& collision) + 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) + 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, eventSelection)) { + registry.fill(HIST("h2_centrality_collisions"), collision.centFT0M(), 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); + registry.fill(HIST("h2_centrality_collisions"), collision.centFT0M(), 1.5); fillTrackHistograms(collision, tracks); } PROCESS_SWITCH(JetFinderV0QATask, 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(); 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); @@ -412,7 +406,7 @@ struct JetFinderV0QATask { } PROCESS_SWITCH(JetFinderV0QATask, processTracksWeighted, "QA for charged tracks weighted", false); - void processCandidates(soa::Filtered::iterator const& collision, CandidateTableData const& candidates) + void processCandidates(soa::Filtered::iterator const& collision, CandidateTableData const& candidates) { for (auto const& candidate : candidates) { @@ -422,12 +416,12 @@ struct JetFinderV0QATask { 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()); + registry.fill(HIST("h2_centrality_ncandidates"), collision.centFT0M(), candidates.size()); } PROCESS_SWITCH(JetFinderV0QATask, processCandidates, "HF candidate QA", false); }; -using JetFinderV0QA = JetFinderV0QATask; +using JetFinderV0QA = JetFinderV0QATask; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGJE/Tasks/jetFinderXicToXiPiPiQA.cxx b/PWGJE/Tasks/jetFinderXicToXiPiPiQA.cxx new file mode 100644 index 00000000000..a86a40f0d67 --- /dev/null +++ b/PWGJE/Tasks/jetFinderXicToXiPiPiQA.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. + +// jet finder XicToXiPiPi charged QA task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetFinderHFQA.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include + +#include + +using JetFinderXicToXiPiPiQATask = JetFinderHFQATask; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-finder-charged-xictoxipipi-qa"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetFormationTimeReclustering.cxx b/PWGJE/Tasks/jetFormationTimeReclustering.cxx new file mode 100644 index 00000000000..f3f2348f7d5 --- /dev/null +++ b/PWGJE/Tasks/jetFormationTimeReclustering.cxx @@ -0,0 +1,433 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 Morgan Knuesel & Johanna Lömker +// + +//********************************************************* +// * +// Table definitions * +// * +//********************************************************* + +#ifndef PWGJE_TASKS_JETFORMATIONTIMERECLUSTERING_H_ +#define PWGJE_TASKS_JETFORMATIONTIMERECLUSTERING_H_ + +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" // IWYU pragma: keep +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataDQ.h" + +#include + +#include +#include +#include + +namespace o2::aod +{ + +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); //! +DECLARE_SOA_COLUMN(PtLeading, ptLeading, std::vector); //! +DECLARE_SOA_COLUMN(PtSubLeading, ptSubLeading, std::vector); //! +DECLARE_SOA_COLUMN(Theta, theta, std::vector); //! +DECLARE_SOA_COLUMN(PtLeadingConstituent, ptLeadingConstituent, float); //! +DECLARE_SOA_COLUMN(TauForm, tauForm, std::vector); //! + +DECLARE_SOA_COLUMN(Z, z, std::vector); //! +DECLARE_SOA_COLUMN(Ptg, ptg, std::vector); //! +DECLARE_SOA_COLUMN(Thetag, thetag, std::vector); //! +DECLARE_SOA_COLUMN(Zg, zg, std::vector); //! +DECLARE_SOA_COLUMN(TauFormg, tauFormg, 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); + +namespace jetoutput +{ +DECLARE_SOA_COLUMN(JetPt, jetPt, float); //! +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_, _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", jetoutput::JetPt, jetoutput::JetPhi, jetoutput::JetEta, jetsubstructure::EnergyMother, jetsubstructure::PtLeading, jetsubstructure::PtSubLeading, jetsubstructure::Theta, jetsubstructure::PtLeadingConstituent, jetsubstructure::TauForm, jetsubstructure::Z, jetsubstructure::Ptg, jetsubstructure::Thetag, jetsubstructure::Zg, jetsubstructure::TauFormg, _name_##substructure::Dummy##_jet_type_<>); \ + DECLARE_SOA_TABLE(_jet_type_##SSOs, "AOD", _jet_description_ "SSO", _name_##substructure::_jet_type_##OId, jetoutput::JetPt, jetoutput::JetPhi, jetoutput::JetEta, jetsubstructure::EnergyMother, jetsubstructure::PtLeading, jetsubstructure::PtSubLeading, jetsubstructure::Theta, jetsubstructure::PtLeadingConstituent, jetsubstructure::TauForm, jetsubstructure::Z, jetsubstructure::Ptg, jetsubstructure::Thetag, jetsubstructure::Zg, jetsubstructure::TauFormg); \ + \ + using _jet_type_##O = _jet_type_##Os::iterator; \ + using _jet_type_##SSO = _jet_type_##SSOs::iterator; + +#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_) \ + 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_) \ + 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) \ + 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_) + +JETSUBSTRUCTURE_TABLES_DEF(C, "C", Charged, charged, JTracks, CJetCOs, "CJETCO", JTrackSubs, CEWSJetCOs, "CEWSJETCO", JTracks, CMCDJetCOs, "CMCDJETCO", JMcParticles, CMCPJetCOs, "CMCPJETCO"); + +} // namespace o2::aod + +#endif // PWGJE_DATAMODEL_JETFORMATIONTIMERECLUSTERING_H_ + +//********************************************************* +// * +// Begin of the task * +// * +//********************************************************* + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetSubstructureUtilities.h" +#include "PWGJE/Core/JetUtilities.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include +#include + +#include + +#include "fastjet/ClusterSequenceArea.hh" +#include "fastjet/PseudoJet.hh" +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct FormationTimeReclustering { + + Produces jetSubstructureDataTable; + Produces jetSubstructureMCDTable; + Produces jetSubstructureMCPTable; + Produces jetSubstructureDataSubTable; + + Produces jetSplittingsDataTable; + Produces jetSplittingsMCDTable; + Produces jetSplittingsMCPTable; + Produces jetSplittingsDataSubTable; + + Configurable zCut{"zCut", 0.1, "soft drop z cut"}; + Configurable beta{"beta", 0.0, "soft drop beta"}; + Configurable genKTp{"genKTp", 0., "select p value for generalized kT alogrithm"}; // CA: p=0, tau: p=0.5 + + Service pdg; + std::vector jetConstituents; + std::vector jetReclustered; + JetFinder jetReclusterer; + + std::vector energyMotherVec; + std::vector ptLeadingVec; + std::vector ptSubLeadingVec; + std::vector thetaVec; + std::vector zVec; + std::vector tauFormVec; + + // groomed vectors: + std::vector ptgVec; + std::vector thetagVec; + std::vector zgVec; + std::vector taugVec; + + float leadingConstituentPt; + float ptJet; + float phiJet; + float etaJet; + 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_tg", ";#it{p}_{T,jet} (GeV/#it{c});#it{#tau}_{g} (fm/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {20, 0.0, 10}}}); + 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_tg_part", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{#tau}_{g}^{part} (fm/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {20, 0.0, 10}}}); + 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_tg_eventwiseconstituentsubtracted", ";#it{p}_{T,jet} (GeV/#it{c});#it{#tau}_{g} (fm/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {20, 0.0, 10}}}); + 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.fastjetExtraParam = genKTp; // in jetfinder we use p = -1 for anti kt jetfinding. Then we do time recl. with p=0.5, kt p =1, ca p=0 + jetReclusterer.algorithm = fastjet::JetAlgorithm::genkt_algorithm; // gen kt is enum 3 in jetfinder setup + } + + 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(); + tauFormVec.clear(); + zVec.clear(); + // groomed + ptgVec.clear(); + thetagVec.clear(); + zgVec.clear(); + taugVec.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; + + 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); + auto tau = (parentSubJet1.perp() + parentSubJet2.perp()) / (parentSubJet1.perp() * parentSubJet2.perp() * theta * theta); // as in run2 aliphysics + energyMotherVec.push_back(daughterSubJet.e()); + ptLeadingVec.push_back(parentSubJet1.pt()); + ptSubLeadingVec.push_back(parentSubJet2.pt()); + thetaVec.push_back(theta); + tauFormVec.push_back(tau); + zVec.push_back(z); + + if (z >= zCut * TMath::Power(theta / (jet.r() / 100.f), beta)) { + if (!softDropped) { + auto zg = z; + auto rg = theta; + auto tg = tau; + ptgVec.push_back(jet.pt()); + thetagVec.push_back(rg); + taugVec.push_back(tg); + zgVec.push_back(zg); + 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); + registry.fill(HIST("h2_jet_pt_jet_tg"), jet.pt(), tg); + } + 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); + registry.fill(HIST("h2_jet_pt_part_jet_tg_part"), jet.pt(), tg); + } + 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); + registry.fill(HIST("h2_jet_pt_jet_tg_eventwiseconstituentsubtracted"), jet.pt(), tg); + } + 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 analyseCharged(T const& jet, U const&, V const&, M& outputTable, N& splittingTable) + { + jetConstituents.clear(); + ptJet = jet.pt(); + phiJet = jet.phi(); + etaJet = jet.eta(); + for (auto& jetConstituent : jet.template tracks_as()) { + fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex()); + } + jetReclustering(jet, splittingTable); + outputTable(ptJet, phiJet, etaJet, energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, leadingConstituentPt, tauFormVec, zVec, ptgVec, thetagVec, zgVec, taugVec); + } + + void processDummy(aod::JetTracks const&) + { + } + PROCESS_SWITCH(FormationTimeReclustering, 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); + } + PROCESS_SWITCH(FormationTimeReclustering, processChargedJetsData, "charged jet substructure", false); + + void processChargedJetsEventWiseSubData(soa::Join::iterator const& jet, + aod::JetTracksSub const& tracks) + { + analyseCharged(jet, tracks, TracksPerCollisionDataSub, jetSubstructureDataSubTable, jetSplittingsDataSubTable); + } + PROCESS_SWITCH(FormationTimeReclustering, 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); + } + PROCESS_SWITCH(FormationTimeReclustering, processChargedJetsMCD, "charged jet substructure", false); + + void processChargedJetsMCP(typename soa::Join::iterator const& jet) + { + jetConstituents.clear(); + ptJet = jet.pt(); + phiJet = jet.phi(); + etaJet = jet.eta(); + for (auto& jetConstituent : jet.template tracks_as()) { + fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex(), static_cast(JetConstituentStatus::track), pdg->Mass(jetConstituent.pdgCode())); + } + jetReclustering(jet, jetSplittingsMCPTable); + jetSubstructureMCPTable(ptJet, phiJet, etaJet, energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, leadingConstituentPt, tauFormVec, zVec, ptgVec, thetagVec, zgVec, taugVec); + } + PROCESS_SWITCH(FormationTimeReclustering, processChargedJetsMCP, "charged jet substructure on MC particle level", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + + return WorkflowSpec{adaptAnalysisTask( + cfgc, TaskName{"jet-formationtimereclustering"})}; +} diff --git a/PWGJE/Tasks/jetFragmentation.cxx b/PWGJE/Tasks/jetFragmentation.cxx new file mode 100644 index 00000000000..9abaccdfaa2 --- /dev/null +++ b/PWGJE/Tasks/jetFragmentation.cxx @@ -0,0 +1,2948 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "JetDerivedDataUtilities.h" +#include "RecoDecay.h" + +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using DataV0JetsWithConstituents = soa::Join; + +using CandidatesV0MCDWithLabels = soa::Join; +using MatchedMCDV0Jets = soa::Join; +using MatchedMCDV0JetsWithConstituents = 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 fillHistsInclusiveV0s{"fillHistsInclusiveV0s", true, "Fill hists for inclusive V0s"}; + Configurable fillHistsJets{"fillHistsJets", true, "Fill hists for jets"}; + + Configurable> ptBinsK0S{"ptBinsK0S", {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0}, "K0S pt Vals"}; + Configurable> ptBinsLambda{"ptBinsLambda", {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0, 25.0}, "Lambda pt Vals"}; + Configurable> ptBinsAntiLambda{"ptBinsAntiLambda", {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0, 25.0}, "AntiLambda pt Vals"}; + + // NB: these must be one shorter than ptbin vectors! + Configurable> signalProbK0S{"signalProbK0S", {0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9}, "K0S signal probability per pt bin"}; + Configurable> signalProbLambda{"signalProbLambda", {0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9}, "Lambda signal probability per pt bin"}; + Configurable> signalProbAntiLambda{"signalProbAntiLambda", {0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9}, "AntiLambda signal probability per pt bin"}; + + 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.075f, 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{z}^{det} - #it{z}^{part})/#it{z}^{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/hEvents", "hEvents", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + 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}); + + // Jets + registry.add("data/jets/jetPtEtaPhi", "Jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {jetPtAxis, etaAxis, phiAxis}); + registry.add("data/jets/inclJetPtEtaPhi", "incljetPtEtaPhi", 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); + + // Perp Cone + 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}); + } // doprocessDataV0 + + if (doprocessMcV0) { + registry.add("matching/hEvents", "hEvents", {HistType::kTH1D, {{3, 0.0f, 3.0f}}}); + // 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); + + // Matching - Jets + registry.add("mcp/jets/inclPartJetPtEtaPhi", "inclPartJetPtEtaPhi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}, true); + registry.add("mcp/jets/partJetPtEtaPhi", "Particle level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}, true); + registry.add("mcd/jets/inclDetJetPtEtaPhi", "inclDetJetPtEtaPhi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}, true); + registry.add("mcd/jets/detJetPtEtaPhi", "Detector level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}, true); + + registry.add("matching/jets/fakeJetPtEtaPhi", "fakeJetPtEtaPhi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}, true); + registry.add("matching/jets/inclFakeJetPtEtaPhi", "inclFakeJetPtEtaPhi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}, true); + registry.add("matching/jets/inclMissJetPtEtaPhi", "inclMissJetPtEtaPhi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}, true); + registry.add("matching/jets/missJetPtEtaPhi", "missJetPtEtaPhi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}, 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/inclMatchDetJetPtEtaPhi", "inclMatchDetJetPtEtaPhi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtEtaPhi", "inclMatchPartJetPtEtaPhi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtEtaPhiMatchDist", "matchJetMatchDist", HistType::kTHnSparseD, {partJetPtAxis, partEtaAxis, partPhiAxis, matchDistAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtEnergyScale", "jetEnergyScale", HistType::kTH2D, {partJetPtAxis, ptRatioAxis}, true); + registry.add("matching/jets/inclMatchDetJetPtPartJetPt", "matchDetJetPtPartJetPt", HistType::kTH2D, {detJetPtAxis, partJetPtAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtDetJetEtaPartJetEta", "matchPartJetPtDetJetEtaPartJetEta", HistType::kTH3D, {partJetPtAxis, detEtaAxis, partEtaAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtDetJetPhiPartJetPhi", "matchPartJetPtDetJetPhiPartJetPhi", HistType::kTH3D, {partJetPtAxis, detPhiAxis, partPhiAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtResolutionPt", "inclMatchPartJetPtResolutionPt", HistType::kTH2D, {partJetPtAxis, ptDiffAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtResolutionEta", "inclMatchPartJetPtResolutionEta", HistType::kTH3D, {partJetPtAxis, partEtaAxis, etaDiffAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtResolutionPhi", "inclMatchPartJetPtResolutionPhi", HistType::kTH3D, {partJetPtAxis, partPhiAxis, phiDiffAxis}, true); + registry.add("matching/jets/inclMatchPartJetPtRelDiffPt", "inclMatchPartJetPtRelDiffPt", 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); + registry.add("matching/jets/V0/partJetPtDetJetPtPartV0PtRelDiffPt", "V0PartPtRelDiffPt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, v0partPtAxis, v0PtRelDiffAxis}, true); + registry.add("matching/jets/V0/partJetPtDetJetPtPartV0ZRelDiffZ", "V0PartPtRelDiffZ", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, partZAxis, zRelDiffAxis}, 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/partJetPtK0SPtDetJetPtK0SPt", "Matched Pt and pt", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProj", "Matched pt and z", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, true); + + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtRightCollision", "Matched Pt, right collision", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjRightCollision", "Matched pt and z, right collision", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, true); + + registry.add("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtWrongCollision", "Matched Pt, wrong collision", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjWrongCollision", "Matched pt and z, wrong collision", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, 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/partJetPtLambdaPtDetJetPtLambdaPt", "matched Pt", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProj", "Matched pt and z", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, true); + + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtRightCollision", "matched Pt, right collision", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjRightCollision", "Matched pt and z, right collision", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, true); + + registry.add("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtWrongCollision", "matched Pt, Wrong collision", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjWrongCollision", "Matched pt and z, Wrong collision", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, 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/partJetPtAntiLambdaPtDetJetPtAntiLambdaPt", "matched Pt", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProj", "Matched pt and z", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, true); + + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtRightCollision", "matched Pt, right collision", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjRightCollision", "Matched pt and z, right collision", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, true); + + registry.add("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtWrongCollision", "matched Pt, Wrong collision", HistType::kTHnSparseD, {partJetPtAxis, v0PtAxis, detJetPtAxis, v0PtAxis}, true); + registry.add("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjWrongCollision", "Matched pt and z, Wrong collision", HistType::kTHnSparseD, {partJetPtAxis, partZAxis, detJetPtAxis, detZAxis}, 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); + + 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); + } // doprocessMcV0 + } // init + + // --------------------------------------------------- + // Implementation of background subtraction at runtime + // --------------------------------------------------- + + int getPtBin(float pt, const 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; + } + + // Return probability for a V0 to be signal + // Assumes V0 can only be of one type! + // Assumes V0 is not rejected! + template + float getV0SignalProb(V const& v0) + { + double purity = 0.; + if (v0.isK0SCandidate()) { + int ptBin = getPtBin(v0.pt(), ptBinsK0S); + if (ptBin >= 0) { + purity = signalProbK0S->at(ptBin); + } + } else if (v0.isLambdaCandidate()) { + int ptBin = getPtBin(v0.pt(), ptBinsLambda); + if (ptBin >= 0) { + purity = signalProbLambda->at(ptBin); + } + } else if (v0.isAntiLambdaCandidate()) { + int ptBin = getPtBin(v0.pt(), ptBinsAntiLambda); + if (ptBin >= 0) { + purity = signalProbAntiLambda->at(ptBin); + } + } + return purity; + } + // 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) + { + 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(const std::vector& state, const 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(const std::vector& state, const 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(const 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*/) + bool v0sAreMatched(U const& v0, V const& particle) + { + 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 + float negM = (isLambda ? constants::physics::MassProton : constants::physics::MassPionCharged); + float posM = (isLambda ? constants::physics::MassPionCharged : constants::physics::MassProton); + std::array, 2> momenta = {std::array{v0.pxpos(), v0.pypos(), v0.pzpos()}, std::array{v0.pxneg(), v0.pyneg(), v0.pzneg()}}; + std::array masses = {posM, negM}; + return RecoDecay::m(momenta, masses); + } + template + double getMomFrac(Jet const& jet, Constituent const& constituent) + { + double divByZeroProtect = 1e-5; + if (jet.pt() < divByZeroProtect) + return -1.; + else + return constituent.pt() / jet.pt(); + } + template + double getMomProj(Jet const& jet, Constituent const& constituent) + { + double divByZeroProtect = 1e-5; + if (jet.p() < divByZeroProtect) + 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 fillDataV0sInclusive(CollisionType const& coll, 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(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("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 fillDataJet(T const& jet) + { + registry.fill(HIST("data/jets/inclJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + if (jetContainsV0s(jet)) + registry.fill(HIST("data/jets/jetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + } + void fillDataJetWeighted(double jetpt, double jeteta, double jetphi, double weight = 1.) + { + registry.fill(HIST("data/jets/weighted/jetPtEtaPhi"), jetpt, jeteta, jetphi, weight); + } + template + void fillDataV0sInJet(CollisionType const& coll, JetType const& jet, V0Type const& v0) + { + double trackProj = getMomFrac(jet, v0); + 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("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 fillDataV0sInPerpCone(T const& coll, U const& jet, V const& v0s) + { + const int nCones = 2; + double perpConeR = jet.r() * 1e-2; + double conePhi[nCones] = {RecoDecay::constrainAngle(jet.phi() - constants::math::PIHalf, -constants::math::PI), + RecoDecay::constrainAngle(jet.phi() + constants::math::PIHalf, -constants::math::PI)}; + double conePt[nCones] = {0., 0.}; + int nV0sinCone[nCones] = {0, 0}; + for (const auto& v0 : v0s) { + if (v0.isRejectedCandidate()) + continue; + + bool v0InCones = false; + double dEta = v0.eta() - jet.eta(); + double dPhi[nCones] = {RecoDecay::constrainAngle(v0.phi() - conePhi[0], -constants::math::PI), + RecoDecay::constrainAngle(v0.phi() - conePhi[1], -constants::math::PI)}; + for (int i = 0; i < nCones; 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 < nCones; 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 fillDataV0sInclusiveWeighted(CollisionType const& coll, 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(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("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); + } + template + void fillDataV0sInJetWeighted(C const& coll, J const& jet, const std::vector& state, const 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(coll.posX(), coll.posY(), coll.posZ()) * constants::physics::MassK0Short; + 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 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 fillMcpV0sInclusive(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) == PDG_t::kK0Short) + registry.fill(HIST("mcp/V0/K0SPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + + if (pdg == PDG_t::kLambda0) + registry.fill(HIST("mcp/V0/LambdaPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + + if (pdg == PDG_t::kLambda0Bar) + 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 fillMcpJet(T const& jet, double weight = 1.) + { + registry.fill(HIST("mcp/jets/inclPartJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + if (jetContainsV0s(jet)) { + registry.fill(HIST("mcp/jets/partJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + } + template + void fillMcdV0sInclusive(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 fillMatchingV0sInclusive(V const& coll, W const& V0s, X const& pV0s, double weight = 1.) + { + float nV0s = 0; + for (const auto& v0 : V0s) { + if (v0.isRejectedCandidate()) + continue; + + if (!v0.has_mcParticle()) { + fillFakeV0Inclusive(coll, v0, weight); + fillFakeV0DaughtersInclusive(v0, weight); + fillFakeV0DecayedInclusive(v0, weight); + continue; + } + for (const auto& pv0 : pV0s) { + if (v0sAreMatched(v0, pv0)) { + nV0s += 1; + fillMatchedV0Inclusive(coll, v0, pv0, weight); + fillMatchedV0DaughtersInclusive(v0, pv0, weight); + } + } + } // Reconstructed V0s + for (const auto& pv0 : pV0s) { + for (const auto& v0 : V0s) { + if (v0sAreMatched(v0, pv0)) + continue; + + fillMissV0Inclusive(pv0); + } + } + registry.fill(HIST("matching/V0/nV0sEventAcc"), nV0s); + registry.fill(HIST("matching/V0/nV0sEventAccWeighted"), nV0s, weight); + } + template + void fillMcdJet(T const& jet, double weight = 1.) + { + registry.fill(HIST("mcd/jets/inclDetJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + if (jetContainsV0s(jet)) { + registry.fill(HIST("mcd/jets/detJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + } + // Reconstructed V0s in the cone of MCD jets + template + void fillMcV0sInPerpCone(T const& coll, U const& mcdjet, V const& v0s, W const& /* V0 particles */, double weight = 1.) + { + const int nCones = 2; + double perpConeR = mcdjet.r() * 1e-2; + double conePhi[nCones] = {RecoDecay::constrainAngle(mcdjet.phi() - constants::math::PIHalf, -constants::math::PI), + RecoDecay::constrainAngle(mcdjet.phi() + constants::math::PIHalf, -constants::math::PI)}; + double coneMatchedPt[nCones] = {0., 0.}; + double coneFakePt[nCones] = {0., 0.}; + int nMatchedV0sinCone[nCones] = {0, 0}; + int nFakeV0sinCone[nCones] = {0, 0}; + + for (const auto& v0 : v0s) { + double dEta = v0.eta() - mcdjet.eta(); + double dPhi[nCones] = {RecoDecay::constrainAngle(v0.phi() - conePhi[0], -constants::math::PI), + RecoDecay::constrainAngle(v0.phi() - conePhi[1], -constants::math::PI)}; + for (int i = 0; i < nCones; 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()) == PDG_t::kK0Short) { // K0S + registry.fill(HIST("mcd/PC/matchedJetPtK0SPtMass"), mcdjet.pt(), v0.pt(), v0.mK0Short(), weight); + } else if (particle.pdgCode() == PDG_t::kLambda0) { // Lambda + registry.fill(HIST("mcd/PC/matchedJetPtLambdaPtMass"), mcdjet.pt(), v0.pt(), v0.mLambda(), weight); + } else if (particle.pdgCode() == PDG_t::kLambda0Bar) { + 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 < nCones; 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 fillMcV0sInMatchedPerpCone(T const& coll, U const& mcdjet, V const& mcpjet, W const& v0s, X const& /* V0 particles */, double weight = 1.) + { + const int nCones = 2; + double perpConeR = mcdjet.r() * 1e-2; + double conePhi[nCones] = {RecoDecay::constrainAngle(mcdjet.phi() - constants::math::PIHalf, -constants::math::PI), + RecoDecay::constrainAngle(mcdjet.phi() + constants::math::PIHalf, -constants::math::PI)}; + double coneMatchedPt[nCones] = {0., 0.}; + double coneFakePt[nCones] = {0., 0.}; + int nMatchedV0sinCone[nCones] = {0, 0}; + int nFakeV0sinCone[nCones] = {0, 0}; + + for (const auto& v0 : v0s) { + double dEta = v0.eta() - mcdjet.eta(); + double dPhi[nCones] = {RecoDecay::constrainAngle(v0.phi() - conePhi[0], -constants::math::PI), + RecoDecay::constrainAngle(v0.phi() - conePhi[1], -constants::math::PI)}; + for (int i = 0; i < nCones; 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()) == PDG_t::kK0Short) { // 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() == PDG_t::kLambda0) { // 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() == PDG_t::kLambda0Bar) { + 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 < nCones; 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 fillMatchedV0Inclusive(CollisionType const& coll, V0Type const& v0, particleType const& particle, 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; + + 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()) == PDG_t::kK0Short) { // 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() == PDG_t::kLambda0) { // 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() == PDG_t::kLambda0Bar) { // 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 fillMatchedV0DaughtersInclusive(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()) == PDG_t::kK0Short) { // K0S + registry.fill(HIST("matching/V0/K0SPosNegPtMass"), pv0.pt(), posPart.pt(), negPart.pt(), v0.mK0Short(), weight); + } else if (v0.pdgCode() == PDG_t::kLambda0) { // Lambda + registry.fill(HIST("matching/V0/LambdaPosNegPtMass"), pv0.pt(), posPart.pt(), negPart.pt(), v0.mLambda(), weight); + } else if (v0.pdgCode() == PDG_t::kLambda0Bar) { // AntiLambda + registry.fill(HIST("matching/V0/AntiLambdaPosNegPtMass"), pv0.pt(), posPart.pt(), negPart.pt(), v0.mAntiLambda(), weight); + } + } + template // Reconstructed jets + void fillMatchedJet(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/inclMatchDetJetPtEtaPhi"), detJet.pt(), detJet.eta(), detJet.phi(), weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtEtaPhi"), partJet.pt(), partJet.eta(), partJet.phi(), weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtEtaPhiMatchDist"), partJet.pt(), partJet.eta(), partJet.phi(), dR, weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtEnergyScale"), partJet.pt(), detJet.pt() / partJet.pt(), weight); + registry.fill(HIST("matching/jets/inclMatchDetJetPtPartJetPt"), detJet.pt(), partJet.pt(), weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtDetJetEtaPartJetEta"), partJet.pt(), detJet.eta(), partJet.eta(), weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtDetJetPhiPartJetPhi"), partJet.pt(), detJet.phi(), partJet.phi(), weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtResolutionPt"), partJet.pt(), (detJet.pt() - partJet.pt()), weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtResolutionEta"), partJet.pt(), partJet.eta(), deltaEta, weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtResolutionPhi"), partJet.pt(), partJet.phi(), deltaPhi, weight); + registry.fill(HIST("matching/jets/inclMatchPartJetPtRelDiffPt"), partJet.pt(), (detJet.pt() - partJet.pt()) / partJet.pt(), weight); + + if (!jetContainsV0s(detJet)) + return; + + 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 fillMatchedV0InJet(CollisionType const& coll, DetJetType const& detJet, PartJetType const& partJet, V0Type const& v0, ParticleType const& particle, double weight = 1.) + { + bool correctCollision = (coll.mcCollisionId() == particle.mcCollisionId()); + double detTrackProj = getMomFrac(detJet, v0); + double partTrackProj = getMomFrac(partJet, particle); + + 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("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/partJetPtDetJetPtPartV0PtRelDiffPt"), partJet.pt(), detJet.pt(), particle.pt(), (v0.pt() - particle.pt()) / particle.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtDetJetPtPartV0ZRelDiffZ"), partJet.pt(), detJet.pt(), partTrackProj, (detTrackProj - partTrackProj) / partTrackProj, 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()) == PDG_t::kK0Short) { // K0S + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProj"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, weight); + if (correctCollision) { + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtRightCollision"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjRightCollision"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, weight); + } else { + registry.fill(HIST("matching/jets/V0/partJetPtK0SPtDetJetPtK0SPtWrongCollision"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtK0STrackProjDetJetPtK0STrackProjWrongCollision"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, 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() == PDG_t::kLambda0) { // Lambda + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProj"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, weight); + if (correctCollision) { + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtRightCollision"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjRightCollision"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, weight); + } else { + registry.fill(HIST("matching/jets/V0/partJetPtLambdaPtDetJetPtLambdaPtWrongCollision"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtLambdaTrackProjDetJetPtLambdaTrackProjWrongCollision"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, 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() == PDG_t::kLambda0Bar) { // AntiLambda + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPt"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProj"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, weight); + if (correctCollision) { + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtRightCollision"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjRightCollision"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, weight); + } else { + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaPtDetJetPtAntiLambdaPtWrongCollision"), partJet.pt(), particle.pt(), detJet.pt(), v0.pt(), weight); + registry.fill(HIST("matching/jets/V0/partJetPtAntiLambdaTrackProjDetJetPtAntiLambdaTrackProjWrongCollision"), partJet.pt(), partTrackProj, detJet.pt(), detTrackProj, 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 fillMatchedV0DaughtersInJet(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 + void fillMissV0Inclusive(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) == PDG_t::kK0Short) { // K0S + registry.fill(HIST("matching/V0/missK0SPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + } else if (pdg == PDG_t::kLambda0) { // Lambda + registry.fill(HIST("matching/V0/missLambdaPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + } else if (pdg == PDG_t::kLambda0Bar) { // AntiLambda + registry.fill(HIST("matching/V0/missAntiLambdaPtEtaPhi"), pv0.pt(), pv0.eta(), pv0.phi(), weight); + } + } + template + void fillMissJet(T const& jet, double weight = 1.) + { + registry.fill(HIST("matching/jets/inclMissJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + if (!jetContainsV0s(jet)) + return; + + registry.fill(HIST("matching/jets/missJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + template + void fillMissV0InJet(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()) == PDG_t::kK0Short) { // 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() == PDG_t::kLambda0) { // 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() == PDG_t::kLambda0Bar) { // 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 + void fillFakeV0Inclusive(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 + void fillFakeV0DaughtersInclusive(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 fillFakeV0DecayedInclusive(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) == PDG_t::kK0Short) { + registry.fill(HIST("matching/V0/decayedK0SV0PtMass"), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } else if (pdg == PDG_t::kLambda0) { + registry.fill(HIST("matching/V0/decayedLambdaV0PtMass"), pt, v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), weight); + } else if (pdg == PDG_t::kLambda0Bar) { + 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 + void fillFakeJet(T const& jet, double weight = 1.) + { + registry.fill(HIST("matching/jets/fakeJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + if (!jetContainsV0s(jet)) + return; + + registry.fill(HIST("matching/jets/inclFakeJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); + } + template + void fillFakeV0InJet(CollisionType const& coll, JetType const& jet, V0Type const& v0, double weight = 1.) + { + double trackProj = getMomFrac(jet, v0); + 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/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 fillFakeV0DecayedInJet(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) == PDG_t::kK0Short) { + 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 == PDG_t::kLambda0) { + 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 == PDG_t::kLambda0Bar) { + 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); + + void processDataV0(soa::Filtered::iterator const& coll, DataV0JetsWithConstituents const& jets, aod::CandidatesV0Data const& V0s, aod::JetTracks const&) + { + registry.fill(HIST("data/hEvents"), 0.5); + if (!jetderiveddatautilities::selectCollision(coll, eventSelectionBits)) + return; + + registry.fill(HIST("data/hEvents"), 1.5); + registry.fill(HIST("data/V0/nV0sEvent"), V0s.size()); + + if (fillHistsInclusiveV0s) { + fillDataV0sInclusive(coll, V0s); + fillDataV0sInclusiveWeighted(coll, V0s); + } + + if (!fillHistsJets) + return; + + for (const auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, -99., -99., v0EtaMin, v0EtaMax)) + continue; + + fillDataJet(jet); + fillDataV0sInPerpCone(coll, jet, V0s); + + 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 signalProb = getV0SignalProb(v0); + nV0inJet++; + wV0inJet += signalProb; + if (v0.isK0SCandidate()) { + nK0SinJet++; + wK0SinJet += signalProb; + } + if (v0.isLambdaCandidate()) { + nLambdainJet++; + wLambdainJet += signalProb; + } + if (v0.isAntiLambdaCandidate()) { + nAntiLambdainJet++; + wAntiLambdainJet += signalProb; + } + + fillDataV0sInJet(coll, 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); + + if (nV0inJet == 0) + continue; + + 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 = correctedValuesPlusTracks(state, jet); + else + corrected = correctedValues(state, values); + + double ws = stateWeight(state, weights); + double jetpt = corrected[nV0inJet]; + fillDataJetWeighted(jetpt, jet.eta(), jet.phi(), ws); + fillDataV0sInJetWeighted(coll, jet, state, corrected, ws); + } + } + } + PROCESS_SWITCH(JetFragmentation, processDataV0, "Data V0", false); + + void processMcV0(soa::Filtered::iterator const& coll, aod::JetMcCollisions const&, MatchedMCDV0JetsWithConstituents const& v0jetsMCD, MatchedMCPV0JetsWithConstituents const& v0jetsMCP, CandidatesV0MCDWithLabels const& V0s, aod::CandidatesV0MCP const& pV0s, aod::JetTracksMCD const&, aod::JetParticles const&, aod::McParticles const& particles) + { + registry.fill(HIST("matching/hEvents"), 0.5); + if (!coll.has_mcCollision()) + return; + if (!jetderiveddatautilities::selectCollision(coll, eventSelectionBits)) + return; + + registry.fill(HIST("matching/hEvents"), 1.5); + double weight = coll.mcCollision().weight(); + registry.fill(HIST("matching/hEvents"), 2.5, weight); + registry.fill(HIST("matching/V0/nV0sEvent"), V0s.size()); + registry.fill(HIST("matching/V0/nV0sEventWeighted"), V0s.size(), weight); + + if (fillHistsInclusiveV0s) { + fillMcdV0sInclusive(coll, V0s, weight); + fillMcpV0sInclusive(pV0s, weight); + fillMatchingV0sInclusive(coll, V0s, pV0s, weight); + } + + if (!fillHistsJets) + return; + + for (const auto& detJet : v0jetsMCD) { + if (!jetfindingutilities::isInEtaAcceptance(detJet, -99., -99., v0EtaMin, v0EtaMax)) + continue; + + fillMcdJet(detJet, weight); + fillMcV0sInPerpCone(coll, detJet, V0s, particles, weight); + + int nV0inJet = 0, nLambdainJet = 0, nAntiLambdainJet = 0, nK0SinJet = 0; + if (!detJet.has_matchedJetGeo()) { + fillFakeJet(detJet, weight); + for (const auto& v0 : detJet.candidates_as()) { + fillFakeV0InJet(coll, detJet, v0, weight); + } + continue; + } // if jet not matched + + for (const auto& partJet : detJet.template matchedJetGeo_as()) { + fillMatchedJet(detJet, partJet, weight); + fillMcV0sInMatchedPerpCone(coll, detJet, partJet, V0s, particles, weight); + + for (const auto& detV0 : detJet.candidates_as()) { + if (!detV0.has_mcParticle()) { + fillFakeV0InJet(coll, detJet, detV0, weight); + fillFakeV0DecayedInJet(partJet, detJet, detV0, weight); + continue; + } + + bool isV0Matched = false; + for (const auto& partV0 : partJet.template candidates_as()) { + if (!v0sAreMatched(detV0, partV0)) + continue; + + isV0Matched = true; + nV0inJet++; + fillMatchedV0InJet(coll, detJet, partJet, detV0, partV0, weight); + fillMatchedV0DaughtersInJet(detJet, partJet, detV0, partV0, weight); + + if (std::abs(partV0.pdgCode()) == PDG_t::kK0Short) { + nK0SinJet++; + } else if (partV0.pdgCode() == PDG_t::kLambda0) { + nLambdainJet++; + } else if (partV0.pdgCode() == PDG_t::kLambda0Bar) { + nAntiLambdainJet++; + } + break; + } // partV0 loop + + if (!isV0Matched) { + fillFakeV0InJet(coll, 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) { + fillMcpJet(partJet, weight); + + if (!partJet.has_matchedJetGeo()) { + fillMissJet(partJet, weight); + for (const auto& partV0 : partJet.candidates_as()) { + fillMissV0InJet(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)) { + isV0Matched = true; + break; + } + } // detV0 loop + + // If V0 is matched, it has already been filled in the mcdjet loop + if (!isV0Matched) + fillMissV0InJet(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()) { + fillMissV0InJet(partJet, partV0, weight); + } + } + } // partJet loop + } + PROCESS_SWITCH(JetFragmentation, processMcV0, "MC V0", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/jetHadronRecoil.cxx b/PWGJE/Tasks/jetHadronRecoil.cxx index 99a7a9cf3b1..259d35ef33b 100644 --- a/PWGJE/Tasks/jetHadronRecoil.cxx +++ b/PWGJE/Tasks/jetHadronRecoil.cxx @@ -8,440 +8,1132 @@ // In applying this license CERN does 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 "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" -#include "TRandom3.h" +#include "Common/Core/RecoDecay.h" +#include "CommonConstants/MathConstants.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 "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include +#include +#include -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetFindingUtilities.h" -#include "PWGJE/DataModel/Jet.h" +#include "TRandom3.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include +#include +#include -#include "EventFiltering/filterTables.h" +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -struct hJetAnalysis { +struct JetHadronRecoil { + + std::vector jetConstituents; + std::vector jetReclustered; + JetFinder jetReclusterer; - 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", 6.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"}; - - Preslice> PartJetsPerCollision = aod::jet::mcCollisionId; + Configurable pTHatTrackMaxMCD{"pTHatTrackMaxMCD", 999.0, "maximum fraction of hard scattering for track acceptance in detector MC"}; + Configurable pTHatTrackMaxMCP{"pTHatTrackMaxMCP", 999.0, "maximum fraction of hard scattering for track acceptance in particle MC"}; + Configurable pTHatMinEvent{"pTHatMinEvent", -1.0, "minimum absolute event pTHat"}; + 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"}; + Configurable outlierRejectEvent{"outlierRejectEvent", true, "where outliers are found, reject event (true) or just reject the single track/jet (false)"}; + Configurable doSumw{"doSumw", false, "enable sumw2 for weighted histograms"}; 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; - - HistogramRegistry registry{"registry", - {{"hNtrig", "number of triggers;trigger type;entries", {HistType::kTH1F, {{2, 0, 2}}}}, - {"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 * o2::constants::math::PI}, {150, 0, 150}}}}, - {"hSignalPtDPhi", "jet p_{T} vs DPhi;#Delta#phi;p_{T,jet}", {HistType::kTH2F, {{100, 0, 2 * o2::constants::math::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 * o2::constants::math::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 * o2::constants::math::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 * o2::constants::math::PI}, {50, 0, 50}}}}, - {"hJetReferenceConstituentMultiplicity", "jet constituent multiplicity;p_{T,jet};#Delta#phi;N_{constituents}", {HistType::kTH3F, {{150, 0, 150}, {100, 0, 2 * o2::constants::math::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 * o2::constants::math::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 * o2::constants::math::PI}, {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}}}}, - {"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}}}}, - {"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}}}}, - {"hDeltaR", "#DeltaR;#DeltaR;#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {{50, 0.0, 0.15}}}}, - {"hDeltaRPart", "Particle #DeltaR;#DeltaR;#frac{1}{N_{jets}}#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {{50, 0.0, 0.15}}}}, - {"hDeltaRpT", "jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{200, 0, 200}, {50, 0.0, 0.15}}}}, - {"hDeltaRpTPart", "Particle jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{200, 0, 200}, {50, 0.0, 0.15}}}}, - {"hDeltaRSignal", "#DeltaR;#DeltaR;#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {{50, 0.0, 0.15}}}}, - {"hDeltaRPartSignal", "Particle #DeltaR;#DeltaR;#frac{1}{N_{jets}}#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {{50, 0.0, 0.15}}}}, - {"hDeltaRpTSignal", "jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{200, 0, 200}, {50, 0.0, 0.15}}}}, - {"hDeltaRpTPartSignal", "Particle jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{200, 0, 200}, {50, 0.0, 0.15}}}}, - {"hDeltaRpTDPhiSignal", "jet p_{T} vs #DeltaR vs #Delta#phi;p_{T,jet};#Delta#phi;#DeltaR", {HistType::kTH3F, {{200, 0, 200}, {100, 0, 2 * o2::constants::math::PI}, {50, 0.0, 0.15}}}}, - {"hDeltaRpTDPhiSignalPart", "Particle jet p_{T} vs #DeltaR vs #Delta#phi;p_{T,jet};#Delta#phi;#DeltaR", {HistType::kTH3F, {{200, 0, 200}, {100, 0, 2 * o2::constants::math::PI}, {50, 0.0, 0.15}}}}, - {"hDeltaRReference", "#DeltaR;#DeltaR;#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {{50, 0.0, 0.15}}}}, - {"hDeltaRPartReference", "Particle #DeltaR;#DeltaR;#frac{1}{N_{jets}}#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {{50, 0.0, 0.15}}}}, - {"hDeltaRpTReference", "jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{200, 0, 200}, {50, 0.0, 0.15}}}}, - {"hDeltaRpTPartReference", "Particle jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{200, 0, 200}, {50, 0.0, 0.15}}}}, - {"hDeltaRpTDPhiReference", "jet p_{T} vs #DeltaR vs #Delta#phi;p_{T,jet};#Delta#phi;#DeltaR", {HistType::kTH3F, {{200, 0, 200}, {100, 0, 2 * o2::constants::math::PI}, {50, 0.0, 0.15}}}}, - {"hDeltaRpTDPhiReferencePart", "jet p_{T} vs #DeltaR vs #Delta#phi;p_{T,jet};#Delta#phi;#DeltaR", {HistType::kTH3F, {{200, 0, 200}, {100, 0, 2 * o2::constants::math::PI}, {50, 0.0, 0.15}}}}, - {"hPtMatched", "p_{T} matching;p_{T,det};p_{T,part}", {HistType::kTH2F, {{200, 0, 200}, {200, 0, 200}}}}, - {"hPhiMatched", "#phi matching;#phi_{det};#phi_{part}", {HistType::kTH2F, {{160, -1.0, 7.0}, {160, -1.0, 7.0}}}}, - {"hDeltaRMatched", "#DeltaR matching;#DeltaR_{det};#DeltaR_{part}", {HistType::kTH2F, {{50, 0.0, 0.15}, {50, 0.0, 0.15}}}}, - {"hPtResolution", "p_{T} resolution;p_{T,part};Relative Resolution", {HistType::kTH2F, {{200, 0, 200}, {1000, -5.0, 5.0}}}}, - {"hPhiResolution", "#phi resolution;#p{T,part};Resolution", {HistType::kTH2F, {{200, 0, 200}, {1000, -7.0, 7.0}}}}, - {"hDeltaRResolution", "#DeltaR Resolution;p_{T,part};Resolution", {HistType::kTH2F, {{200, 0, 200}, {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, {{200, 0, 200}, {200, 0, 200}, {160, -1.0, 7.0}, {160, -1.0, 7.0}, {50, 0.0, 0.15}, {50, 0.0, 0.15}}}}}}; - - int eventSelection = -1; + 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::centFT0M >= centralityMin && aod::jcollision::centFT0M < 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, 0.27, 0.30, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48, 0.51, 0.54, + 0.57, 0.60}; + std::vector pThatBinning = {0.0, 0.25, 0.5, 0.75, 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.25, 4.5, 4.75, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 20.0, 30.0}; + + 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}"}; + AxisSpec pThatAxis = {pThatBinning, "#hat{p_{T}}"}; + + HistogramRegistry registry; + + 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); + + jetReclusterer.isReclustering = true; + jetReclusterer.algorithm = fastjet::JetAlgorithm::cambridge_algorithm; + jetReclusterer.jetR = 2 * jetR; + jetReclusterer.ghostRepeatN = 0; + jetReclusterer.recombScheme = fastjet::WTA_pt_scheme; + + registry.add("hZvtxSelected", "Z vertex position;Z_{vtx};entries", {HistType::kTH1F, {{80, -20, 20}}}, doSumw); + + if (doprocessData || doprocessDataWithRhoSubtraction || doprocessMCD || doprocessMCDWithRhoSubtraction || doprocessMCDWeighted || doprocessMCDWeightedWithRhoSubtraction || doprocessMCP || doprocessMCPWeighted) { + registry.add("hNtrig", "number of triggers;trigger type;entries", {HistType::kTH1F, {{2, 0, 2}}}, doSumw); + registry.add("hSignalTriggersPtHard", "Signal triggers vs PtHard", {HistType::kTH1F, {pThatAxis}}, doSumw); + registry.add("hReferenceTriggersPtHard", "Reference triggers vs PtHard", {HistType::kTH1F, {pThatAxis}}, doSumw); + registry.add("hConstituents3D", "3D constituents histogram;p_{T};#eta;#phi", {HistType::kTH3F, {{200, 0, 200}, {100, -1.0, 1.0}, {100, 0.0, o2::constants::math::TwoPI}}}, doSumw); + registry.add("hReferencePtDPhi", "jet p_{T} vs DPhi;#Delta#phi;p_{T,jet}", {HistType::kTH2F, {{100, 0, o2::constants::math::TwoPI}, {500, -100, 400}}}, doSumw); + registry.add("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}}}, doSumw); + registry.add("hSignalPtDPhi", "jet p_{T} vs DPhi;#Delta#phi;p_{T,jet}", {HistType::kTH2F, {{100, 0, o2::constants::math::TwoPI}, {500, -100, 400}}}, doSumw); + registry.add("hReferencePt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{500, -100, 400}}}, doSumw); + registry.add("hSignalPt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{500, -100, 400}}}, doSumw); + registry.add("hSignalTriggers", "trigger p_{T};p_{T,trig};entries", {HistType::kTH1F, {{150, 0, 150}}}, doSumw); + registry.add("hSignalPtHard", "jet p_{T} vs #hat{p};p_{T,jet};#frac{p_{T,trig}}{#hat{p}}", {HistType::kTH2F, {{500, -100, 400}, pThatAxis}}, doSumw); + registry.add("hReferenceTriggers", "trigger p_{T};p_{T,trig};entries", {HistType::kTH1F, {{150, 0, 150}}}, doSumw); + registry.add("hReferencePtHard", "jet p_{T} vs #hat{p};p_{T,jet};#frac{p_{T,trig}}{#hat{p}}", {HistType::kTH2F, {{500, -100, 400}, pThatAxis}}, doSumw); + registry.add("hSigEventTriggers", "N_{triggers};events", {HistType::kTH1F, {{10, 0, 10}}}, doSumw); + registry.add("hRefEventTriggers", "N_{triggers};events", {HistType::kTH1F, {{10, 0, 10}}}, doSumw); + registry.add("hJetPt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{500, -100, 400}}}, doSumw); + registry.add("hJetEta", "jet #eta;#eta_{jet};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}, doSumw); + registry.add("hJetPhi", "jet #phi;#phi_{jet};entries", {HistType::kTH1F, {{100, 0.0, o2::constants::math::TwoPI}}}, doSumw); + registry.add("hJet3D", "3D jet distribution;p_{T};#eta;#phi", {HistType::kTH3F, {{500, -100, 400}, {100, -1.0, 1.0}, {100, 0.0, o2::constants::math::TwoPI}}}, doSumw); + } - 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); + if (doprocessData || doprocessDataWithRhoSubtraction || doprocessMCD || doprocessMCDWithRhoSubtraction || doprocessMCDWeighted || doprocessMCDWeightedWithRhoSubtraction) { + registry.add("hPtTrack", "Track p_{T};p_{T};entries", {HistType::kTH1F, {{200, 0, 200}}}, doSumw); + registry.add("hEtaTrack", "Track #eta;#eta;entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}, doSumw); + registry.add("hPhiTrack", "Track #phi;#phi;entries", {HistType::kTH1F, {{100, 0.0, o2::constants::math::TwoPI}}}, doSumw); + registry.add("hTrack3D", "3D tracks histogram;p_{T};#eta;#phi", {HistType::kTH3F, {{200, 0, 200}, {100, -1.0, 1.0}, {100, 0.0, o2::constants::math::TwoPI}}}, doSumw); + registry.add("hPtTrackPtHard", "Tracks vs pThard;#frac{p_{T}}{#hat{p}};p_{T}", {HistType::kTH2F, {pThatAxis, {200, 0, 200}}}, doSumw); + registry.add("hTracksvsJets", "comparing leading tracks and jets;p_{T,track};p_{T,jet};#hat{p}", {HistType::kTH3F, {{200, 0, 200}, {500, -100, 400}, {195, 5, 200}}}, doSumw); + registry.add("hRhoSignal", "Signal Rho bkg;#rho;entries", {HistType::kTH1F, {{220, 0, 220}}}, doSumw); + registry.add("hRhoReference", "Reference Rho bkg;#rho;entries", {HistType::kTH1F, {{220, 0, 220}}}, doSumw); + registry.add("hRhoReferenceShift", "Testing reference shifts;#rho;shift", {HistType::kTH2F, {{220, 0, 220}, {20, 0.0, 2.0}}}, doSumw); + registry.add("hDeltaRSignal", "#DeltaR;#DeltaR;#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}, doSumw); + registry.add("hDeltaRpTSignal", "jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{500, -100, 400}, dRAxis}}, doSumw); + registry.add("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}}, doSumw); + registry.add("hDeltaRReference", "#DeltaR;#DeltaR;#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}, doSumw); + registry.add("hDeltaRpTReference", "jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{500, -100, 400}, dRAxis}}, doSumw); + registry.add("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}}, doSumw); + registry.add("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}}}, doSumw); + registry.add("hPtTrackMatched", "Track p_{T};p_{T};entries", {HistType::kTH1F, {{200, 0, 200}}}, doSumw); + registry.add("hPtTrackMatchedToCollisions", "Track p_{T};p_{T};entries", {HistType::kTH1F, {{200, 0, 200}}}, doSumw); + } + + if (doprocessMCP || doprocessMCPWeighted) { + registry.add("hPartvsJets", "comparing leading particles and jets;p_{T,part};p_{T,jet};#hat{p}", {HistType::kTH3F, {{200, 0, 200}, {500, -100, 400}, {195, 5, 200}}}, doSumw); + registry.add("hPtPart", "Particle p_{T};p_{T};entries", {HistType::kTH1F, {{200, 0, 200}}}, doSumw); + registry.add("hEtaPart", "Particle #eta;#eta;entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}, doSumw); + registry.add("hPhiPart", "Particle #phi;#phi;entries", {HistType::kTH1F, {{100, 0.0, o2::constants::math::TwoPI}}}, doSumw); + registry.add("hPart3D", "3D tracks histogram;p_{T};#eta;#phi", {HistType::kTH3F, {{200, 0, 200}, {100, -1.0, 1.0}, {100, 0.0, o2::constants::math::TwoPI}}}, doSumw); + registry.add("hPtPartPtHard", "Track p_{T} vs #hat{p};p_{T};#frac{p_{T}}{#hat{p}}", {HistType::kTH2F, {{200, 0, 200}, pThatAxis}}, doSumw); + registry.add("hDeltaRSignalPart", "Particle #DeltaR;#DeltaR;#frac{1}{N_{jets}}#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}, doSumw); + registry.add("hDeltaRpTSignalPart", "Particle jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{400, 0, 400}, dRAxis}}, doSumw); + registry.add("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}}, doSumw); + registry.add("hDeltaRPartReference", "Particle #DeltaR;#DeltaR;#frac{1}{N_{jets}}#frac{dN_{jets}}{d#DeltaR}", {HistType::kTH1F, {dRAxis}}, doSumw); + registry.add("hDeltaRpTPartReference", "Particle jet p_{T} vs #DeltaR;p_{T,jet};#DeltaR", {HistType::kTH2F, {{400, 0, 400}, dRAxis}}, doSumw); + registry.add("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}}, doSumw); + } + + if (doprocessJetsMCPMCDMatched || doprocessJetsMCPMCDMatchedWithRhoSubtraction || doprocessJetsMCPMCDMatchedWeighted || doprocessJetsMCPMCDMatchedWeightedWithRhoSubtraction || doprocessRecoilJetsMCPMCDMatched || doprocessRecoilJetsMCPMCDMatchedWeighted || doprocessRecoilJetsMCPMCDMatchedWeightedWithRhoSubtraction) { + registry.add("hPtMatched", "p_{T} matching;p_{T,det};p_{T,part}", {HistType::kTH2F, {{500, -100, 400}, {400, 0, 400}}}, doSumw); + registry.add("hPhiMatched", "#phi matching;#phi_{det};#phi_{part}", {HistType::kTH2F, {{100, 0.0, o2::constants::math::TwoPI}, {100, 0.0, o2::constants::math::TwoPI}}}, doSumw); + registry.add("hPhiMatched2d", "#phi matching 2d;#phi;p_{T}", {HistType::kTH2F, {{100, 0.0, o2::constants::math::TwoPI}, {400, 0, 400}}}, doSumw); + registry.add("hDeltaRMatched", "#DeltaR matching;#DeltaR_{det};#DeltaR_{part}", {HistType::kTH2F, {dRAxisDet, dRAxisPart}}, doSumw); + registry.add("hPtMatched1d", "p_{T} matching 1d;p_{T,part}", {HistType::kTH1F, {{400, 0, 400}}}, doSumw); + registry.add("hDeltaRMatched1d", "#DeltaR matching 1d;#DeltaR_{part}", {HistType::kTH1F, {dRAxisPart}}, doSumw); + registry.add("hPtResolution", "p_{T} resolution;p_{T,part};Relative Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -5.0, 5.0}}}, doSumw); + registry.add("hPhiResolution", "#phi resolution;#p_{T,part};Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -7.0, 7.0}}}, doSumw); + registry.add("hDeltaRResolution", "#DeltaR Resolution;p_{T,part};Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -0.15, 0.15}}}, doSumw); + registry.add("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}}, doSumw); + } } - template - void fillHistograms(T const& jets, W const& /*jetsWTA*/, U const& tracks) + template + void fillHistograms(T const& jets, U const& tracks, float weight = 1.0, float rho = 0.0, float pTHat = 999.0) { - bool is_sig_col; - std::vector phi_TT_ar; - double phi_TT = 0; - int trig_number = 0; - int n_TT = 0; + bool isSigCol; + std::vector phiTTAr; + std::vector ptTTAr; + double phiTT = 0; + double ptTT = 0; + int nTT = 0; double leadingPT = 0; + double leadingTrackPt = 0; + double leadingJetPt = 0; + 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 (!is_sig_col && track.pt() < pt_TTref_max && track.pt() > pt_TTref_min) { - phi_TT_ar.push_back(track.phi()); - n_TT++; - } - 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); - } - if (!is_sig_col) { - registry.fill(HIST("hNtrig"), 0.5); - registry.fill(HIST("hJetReferenceMultiplicity"), jets.size()); - registry.fill(HIST("hRefEventTriggers"), n_TT); - } - } - - for (auto& jet : jets) { - registry.fill(HIST("hJetPt"), jet.pt()); - registry.fill(HIST("hJetEta"), jet.eta()); - registry.fill(HIST("hJetPhi"), jet.phi()); - for (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); - registry.fill(HIST("hDeltaRpT"), jet.pt(), dR); - } - if (n_TT > 0) { - float dphi = RecoDecay::constrainAngle(jet.phi() - phi_TT); - if (is_sig_col) { - for (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(), dR); - registry.fill(HIST("hDeltaRSignal"), dR); - } - registry.fill(HIST("hDeltaRpTDPhiSignal"), jet.pt(), dphi, dR); - } - registry.fill(HIST("hSignalPtDPhi"), dphi, jet.pt()); + if (track.pt() > leadingTrackPt) { + leadingTrackPt = track.pt(); + } + if (track.pt() > pTHatTrackMaxMCD * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + if (isSigCol && track.pt() < ptTTsigMax && track.pt() > ptTTsigMin) { + phiTTAr.push_back(track.phi()); + ptTTAr.push_back(track.pt()); + registry.fill(HIST("hSignalTriggers"), track.pt(), weight); + nTT++; + } + if (!isSigCol && track.pt() < ptTTrefMax && track.pt() > ptTTrefMin) { + phiTTAr.push_back(track.phi()); + ptTTAr.push_back(track.pt()); + registry.fill(HIST("hReferenceTriggers"), track.pt(), weight); + nTT++; + } + registry.fill(HIST("hPtTrack"), track.pt(), weight); + registry.fill(HIST("hEtaTrack"), track.eta(), weight); + registry.fill(HIST("hPhiTrack"), track.phi(), weight); + registry.fill(HIST("hTrack3D"), track.pt(), track.eta(), track.phi(), weight); + registry.fill(HIST("hPtTrackPtHard"), track.pt() / pTHat, track.pt(), weight); + } + if (nTT > 0) { + int trigNumber = rand->Integer(nTT); + phiTT = phiTTAr[trigNumber]; + ptTT = ptTTAr[trigNumber]; + if (isSigCol) { + registry.fill(HIST("hNtrig"), 1.5, weight); + registry.fill(HIST("hSigEventTriggers"), nTT, weight); + registry.fill(HIST("hRhoSignal"), rho, weight); + registry.fill(HIST("hSignalTriggersPtHard"), ptTT / pTHat, weight); + } + 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); + } + registry.fill(HIST("hReferenceTriggersPtHard"), ptTT / pTHat, weight); + } + } + for (const auto& jet : jets) { + if (jet.pt() > leadingJetPt) { + leadingJetPt = jet.pt(); + } + if (jet.pt() > pTHatMaxMCD * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + for (const auto& constituent : jet.template tracks_as()) { + if (constituent.pt() > leadingPT) { + leadingPT = constituent.pt(); + } + registry.fill(HIST("hConstituents3D"), constituent.pt(), constituent.eta(), constituent.phi()); + } + 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); + registry.fill(HIST("hJet3D"), jet.pt() - (rho * jet.area()), jet.eta(), jet.phi(), weight); + + if (nTT > 0) { + float dphi = RecoDecay::constrainAngle(jet.phi() - phiTT); + double dR = getWTAaxisDifference(jet, tracks); + if (isSigCol) { if (std::abs(dphi - o2::constants::math::PI) < 0.6) { - registry.fill(HIST("hSignalPt"), jet.pt()); + registry.fill(HIST("hDeltaRpTSignal"), jet.pt() - (rho * jet.area()), dR, weight); + registry.fill(HIST("hDeltaRSignal"), 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("hJetSignalConstituentPt"), jet.pt(), dphi, constituent.pt()); + registry.fill(HIST("hDeltaRpTDPhiSignal"), jet.pt() - (rho * jet.area()), dphi, dR, weight); + 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("hSignalPtHard"), jet.pt() - (rho * jet.area()), ptTT / pTHat, weight); } - registry.fill(HIST("hSignalLeadingTrack"), jet.pt(), dphi, leadingPT); } - if (!is_sig_col) { - for (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(), dR); - registry.fill(HIST("hDeltaRReference"), dR); - } - registry.fill(HIST("hDeltaRpTDPhiReference"), jet.pt(), dphi, dR); - } - registry.fill(HIST("hReferencePtDPhi"), dphi, jet.pt()); + if (!isSigCol) { if (std::abs(dphi - o2::constants::math::PI) < 0.6) { - registry.fill(HIST("hReferencePt"), jet.pt()); + registry.fill(HIST("hDeltaRpTReference"), jet.pt() - (rhoReference * jet.area()), dR, weight); + registry.fill(HIST("hDeltaRReference"), dR, 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(); - } - registry.fill(HIST("hJetReferenceConstituentPt"), jet.pt(), dphi, constituent.pt()); + 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("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); + registry.fill(HIST("hReferencePtHard"), jet.pt() - (rhoReference * jet.area()), ptTT / pTHat, weight); } - registry.fill(HIST("hReferenceLeadingTrack"), jet.pt(), dphi, leadingPT); } } } + registry.fill(HIST("hTracksvsJets"), leadingTrackPt, leadingJetPt, pTHat, weight); } template - void fillMCPHistograms(T const& jets, U const& particles) + void fillHistogramsMCD(T const& jets, U const& tracks, float weight = 1.0, float rho = 0.0, float pTHat = 999.0, auto collisionID = 0) { - bool is_sig_col; - std::vector phi_TT_ar; - double phi_TT = 0; - int trig_number = 0; - int n_TT = 0; + bool isSigCol; + std::vector phiTTAr; + std::vector ptTTAr; + double phiTT = 0; + double ptTT = 0; + int nTT = 0; double leadingPT = 0; + double leadingTrackPt = 0; + double leadingJetPt = 0; + 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& 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& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + if (track.pt() > leadingTrackPt) { + leadingTrackPt = track.pt(); + } + if (track.pt() > pTHatTrackMaxMCD * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + if (isSigCol && track.pt() < ptTTsigMax && track.pt() > ptTTsigMin) { + phiTTAr.push_back(track.phi()); + ptTTAr.push_back(track.pt()); + registry.fill(HIST("hSignalTriggers"), track.pt(), weight); + nTT++; } - if (!is_sig_col && particle.pt() < pt_TTref_max && particle.pt() > pt_TTref_min) { - phi_TT_ar.push_back(particle.phi()); - n_TT++; + if (!isSigCol && track.pt() < ptTTrefMax && track.pt() > ptTTrefMin) { + phiTTAr.push_back(track.phi()); + ptTTAr.push_back(track.pt()); + registry.fill(HIST("hReferenceTriggers"), track.pt(), weight); + nTT++; + } + registry.fill(HIST("hPtTrack"), track.pt(), weight); + registry.fill(HIST("hEtaTrack"), track.eta(), weight); + registry.fill(HIST("hPhiTrack"), track.phi(), weight); + registry.fill(HIST("hTrack3D"), track.pt(), track.eta(), track.phi(), weight); + registry.fill(HIST("hPtTrackPtHard"), track.pt() / pTHat, track.pt(), weight); + if (track.has_mcParticle()) { + registry.fill(HIST("hPtTrackMatched"), track.pt(), weight); + auto mcParticle = track.mcParticle(); + if (mcParticle.mcCollisionId() == collisionID) { + registry.fill(HIST("hPtTrackMatchedToCollisions"), track.pt(), weight); + } } - 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 (nTT > 0) { + int trigNumber = rand->Integer(nTT); + phiTT = phiTTAr[trigNumber]; + ptTT = ptTTAr[trigNumber]; + if (isSigCol) { + registry.fill(HIST("hNtrig"), 1.5, weight); + registry.fill(HIST("hSigEventTriggers"), nTT, weight); + registry.fill(HIST("hRhoSignal"), rho, weight); + registry.fill(HIST("hSignalTriggersPtHard"), ptTT / pTHat, 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); + } + registry.fill(HIST("hReferenceTriggersPtHard"), ptTT / pTHat, weight); } } + for (const auto& jet : jets) { + if (jet.pt() > leadingJetPt) { + leadingJetPt = jet.pt(); + } + if (jet.pt() > pTHatMaxMCD * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + for (const auto& constituent : jet.template tracks_as()) { + if (constituent.pt() > leadingPT) { + leadingPT = constituent.pt(); + } + registry.fill(HIST("hConstituents3D"), constituent.pt(), constituent.eta(), constituent.phi()); + } + 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); + registry.fill(HIST("hJet3D"), jet.pt() - (rho * jet.area()), jet.eta(), jet.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 = RecoDecay::constrainAngle(jet.phi() - phi_TT); - if (is_sig_col) { - registry.fill(HIST("hSignalPtDPhi"), dphi, jet.pt()); + if (nTT > 0) { + float dphi = RecoDecay::constrainAngle(jet.phi() - phiTT); + double dR = getWTAaxisDifference(jet, tracks); + if (isSigCol) { if (std::abs(dphi - o2::constants::math::PI) < 0.6) { - registry.fill(HIST("hSignalPt"), jet.pt()); + registry.fill(HIST("hDeltaRpTSignal"), jet.pt() - (rho * jet.area()), dR, weight); + registry.fill(HIST("hDeltaRSignal"), 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("hJetSignalConstituentPt"), jet.pt(), dphi, constituent.pt()); + registry.fill(HIST("hDeltaRpTDPhiSignal"), jet.pt() - (rho * jet.area()), dphi, dR, weight); + 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("hSignalPtHard"), jet.pt() - (rho * jet.area()), ptTT / pTHat, weight); } - registry.fill(HIST("hSignalLeadingTrack"), jet.pt(), dphi, leadingPT); } - if (!is_sig_col) { - registry.fill(HIST("hReferencePtDPhi"), dphi, jet.pt()); + if (!isSigCol) { if (std::abs(dphi - o2::constants::math::PI) < 0.6) { - registry.fill(HIST("hReferencePt"), jet.pt()); + registry.fill(HIST("hDeltaRpTReference"), jet.pt() - (rhoReference * jet.area()), dR, weight); + registry.fill(HIST("hDeltaRReference"), dR, 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(); - } - registry.fill(HIST("hJetReferenceConstituentPt"), jet.pt(), dphi, constituent.pt()); + 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("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); + registry.fill(HIST("hReferencePtHard"), jet.pt() - (rhoReference * jet.area()), ptTT / pTHat, weight); } - registry.fill(HIST("hReferenceLeadingTrack"), jet.pt(), dphi, leadingPT); } } } + registry.fill(HIST("hTracksvsJets"), leadingTrackPt, leadingJetPt, pTHat, weight); } - template - void fillMatchedHistograms(T const& jetBase, V const& mcdjetsWTA, W const& mcpjetsWTA, U const&, float weight = 1.0) + template + void fillMCPHistograms(T const& jets, U const& particles, float weight = 1.0, float pTHat = 999.0) { - double dR = 0; - double dRp = 0; + bool isSigCol; + std::vector phiTTAr; + std::vector ptTTAr; + double phiTT = 0; + double ptTT = 0; + int nTT = 0; + double leadingPartPt = 0; + double leadingJetPt = 0; + float dice = rand->Rndm(); + if (dice < fracSig) + isSigCol = true; + else + isSigCol = false; - float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); - if (jetBase.pt() > pTHatMaxMCD * pTHat) { - return; + for (const auto& particle : particles) { + if (particle.pt() > leadingPartPt) { + leadingPartPt = particle.pt(); + } + if (particle.pt() > pTHatTrackMaxMCD * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle) { + continue; + } + if ((pdgParticle->Charge() == 0.0) || (!particle.isPhysicalPrimary())) { + continue; + } + if (isSigCol && particle.pt() < ptTTsigMax && particle.pt() > ptTTsigMin) { + phiTTAr.push_back(particle.phi()); + ptTTAr.push_back(particle.pt()); + nTT++; + registry.fill(HIST("hSignalTriggers"), particle.pt(), weight); + } + if (!isSigCol && particle.pt() < ptTTrefMax && particle.pt() > ptTTrefMin) { + phiTTAr.push_back(particle.phi()); + ptTTAr.push_back(particle.pt()); + nTT++; + registry.fill(HIST("hReferenceTriggers"), particle.pt(), weight); + } + registry.fill(HIST("hPtPart"), particle.pt(), weight); + registry.fill(HIST("hEtaPart"), particle.eta(), weight); + registry.fill(HIST("hPhiPart"), particle.phi(), weight); + registry.fill(HIST("hPart3D"), particle.pt(), particle.eta(), particle.phi(), weight); + registry.fill(HIST("hPtPartPtHard"), particle.pt(), particle.pt() / pTHat, weight); } - for (const auto& mcdjetWTA : mcdjetsWTA) { - double djet = RecoDecay::sqrtSumOfSquares(RecoDecay::constrainAngle(jetBase.phi() - mcdjetWTA.phi(), -o2::constants::math::PI), jetBase.eta() - mcdjetWTA.eta()); - if (djet < 0.6 * jetR) { - dR = djet; - break; + if (nTT > 0) { + int trigNumber = rand->Integer(nTT); + phiTT = phiTTAr[trigNumber]; + ptTT = ptTTAr[trigNumber]; + if (isSigCol) { + registry.fill(HIST("hNtrig"), 1.5, weight); + registry.fill(HIST("hSigEventTriggers"), nTT, weight); + registry.fill(HIST("hSignalTriggersPtHard"), ptTT / pTHat, weight); + } + if (!isSigCol) { + registry.fill(HIST("hNtrig"), 0.5, weight); + registry.fill(HIST("hRefEventTriggers"), nTT, weight); + registry.fill(HIST("hReferenceTriggersPtHard"), ptTT / pTHat, weight); } } - if (jetBase.has_matchedJetGeo()) { - for (auto& jetTag : jetBase.template matchedJetGeo_as>()) { - if (jetTag.pt() > pTHatMaxMCP * pTHat) { + for (const auto& jet : jets) { + if (jet.pt() > leadingJetPt) { + leadingJetPt = jet.pt(); + } + if (jet.pt() > pTHatMaxMCP * pTHat) { + if (outlierRejectEvent) { + return; + } else { continue; } - for (const auto& mcpjetWTA : mcpjetsWTA) { - double djetp = RecoDecay::sqrtSumOfSquares(RecoDecay::constrainAngle(jetTag.phi() - mcpjetWTA.phi(), -o2::constants::math::PI), jetTag.eta() - mcpjetWTA.eta()); - if (djetp < 0.6 * jetR) { - dRp = djetp; - break; + } + for (const auto& constituent : jet.template tracks_as()) { + registry.fill(HIST("hConstituents3D"), constituent.pt(), constituent.eta(), constituent.phi()); + } + registry.fill(HIST("hJetPt"), jet.pt(), weight); + registry.fill(HIST("hJetEta"), jet.eta(), weight); + registry.fill(HIST("hJetPhi"), jet.phi(), weight); + registry.fill(HIST("hJet3D"), jet.pt(), jet.eta(), jet.phi(), weight); + + if (nTT > 0) { + float dphi = RecoDecay::constrainAngle(jet.phi() - phiTT); + double dR = getWTAaxisDifference(jet, particles); + if (isSigCol) { + 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("hSignalPtDPhi"), dphi, jet.pt(), weight); + if (std::abs(dphi - o2::constants::math::PI) < 0.6) { + registry.fill(HIST("hSignalPt"), jet.pt(), weight); + registry.fill(HIST("hSignalPtHard"), jet.pt(), ptTT / pTHat, weight); + } + } + if (!isSigCol) { + 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("hDeltaRpTDPhiReferencePart"), jet.pt(), dphi, dR, weight); + 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); + registry.fill(HIST("hReferencePtHard"), jet.pt(), ptTT / pTHat, weight); } } - registry.fill(HIST("hPtMatched"), jetBase.pt(), jetTag.pt(), weight); - registry.fill(HIST("hPhiMatched"), jetBase.phi(), jetTag.phi(), weight); - registry.fill(HIST("hPtResolution"), jetTag.pt(), (jetTag.pt() - jetBase.pt()) / jetTag.pt(), weight); - registry.fill(HIST("hPhiResolution"), jetTag.pt(), jetTag.phi() - jetBase.phi(), weight); - if (jetBase.pt() > 5 || jetTag.pt() > 5) { + } + } + registry.fill(HIST("hPartvsJets"), leadingPartPt, leadingJetPt, pTHat, weight); + } + + template + void fillMatchedHistograms(T const& jetsBase, U const&, X const& tracks, Y const& particles, float weight = 1.0, float rho = 0.0, float pTHat = 999.0) + { + for (const auto& jetBase : jetsBase) { + + if (jetBase.pt() > pTHatMaxMCD * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + + double dR = getWTAaxisDifference(jetBase, tracks); + + if (jetBase.has_matchedJetGeo()) { + for (const auto& jetTag : jetBase.template matchedJetGeo_as>()) { + if (jetTag.pt() > pTHatMaxMCP * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + + double dRp = getWTAaxisDifference(jetTag, particles); + + 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(), jetTag.pt(), jetBase.phi(), jetTag.phi(), dR, dRp, 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& jetsWTA, - soa::Filtered const& tracks) + template + void fillRecoilJetMatchedHistograms(T const&, U const& jetsTag, X const& tracks, Y const& particles, float weight = 1.0, float rho = 0.0, float pTHat = 999.0) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + std::vector phiTTAr; + double phiTT = 0; + int nTT = 0; + + for (const auto& particle : particles) { + if (particle.pt() > pTHatTrackMaxMCP * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle) { + continue; + } + if ((pdgParticle->Charge() == 0.0) || (!particle.isPhysicalPrimary())) { + continue; + } + if (particle.pt() < ptTTsigMax && particle.pt() > ptTTsigMin) { + nTT++; + phiTTAr.push_back(particle.phi()); + } + } + + if (nTT > 0) { + int trigNumber = rand->Integer(nTT); + phiTT = phiTTAr[trigNumber]; + } else { return; } - fillHistograms(jets, jetsWTA, tracks); + + for (const auto& jetTag : jetsTag) { + + if (jetTag.pt() > pTHatMaxMCP * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + + float dphip = RecoDecay::constrainAngle(jetTag.phi() - phiTT); + double dRp = getWTAaxisDifference(jetTag, particles); + + if (jetTag.has_matchedJetGeo() && jetTag.has_matchedJetPt()) { + for (const auto& jetBase : jetTag.template matchedJetGeo_as>()) { + if (jetTag.template matchedJetGeo_first_as>().globalIndex() == jetTag.template matchedJetPt_first_as>().globalIndex()) { + if (jetBase.pt() > pTHatMaxMCD * pTHat) { + if (outlierRejectEvent) { + return; + } else { + continue; + } + } + + float dphi = RecoDecay::constrainAngle(jetBase.phi() - phiTT); + double dR = getWTAaxisDifference(jetBase, tracks); + registry.fill(HIST("hPhiMatched"), dphi, dphip, weight); + registry.fill(HIST("hPhiMatched2d"), jetTag.phi(), jetTag.pt(), weight); + registry.fill(HIST("hPhiResolution"), jetTag.pt(), dphip - dphi, weight); + registry.fill(HIST("hFullMatching"), jetBase.pt() - (rho * jetBase.area()), jetTag.pt(), dphi, dphip, dR, dRp, weight); + if ((std::abs(dphip - o2::constants::math::PI) < 0.6)) { + registry.fill(HIST("hPtMatched1d"), jetTag.pt(), weight); + registry.fill(HIST("hDeltaRMatched1d"), dRp, weight); + registry.fill(HIST("hPtMatched"), jetBase.pt() - (rho * jetBase.area()), jetTag.pt(), weight); + registry.fill(HIST("hPtResolution"), jetTag.pt(), (jetTag.pt() - (jetBase.pt() - (rho * jetBase.area()))) / jetTag.pt(), weight); + registry.fill(HIST("hDeltaRMatched"), dR, dRp, weight); + registry.fill(HIST("hDeltaRResolution"), jetTag.pt(), dRp - dR, weight); + } + } + } + } + } } - PROCESS_SWITCH(hJetAnalysis, processData, "process data", true); - void processMCD(soa::Filtered::iterator const& collision, - soa::Filtered> const& jets, - soa::Filtered> const& jetsWTA, - soa::Filtered const& tracks) + void processData(soa::Filtered::iterator const& collision, + soa::Filtered> const& jets, + soa::Filtered const& tracks) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { return; } - fillHistograms(jets, jetsWTA, tracks); + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillHistograms(jets, tracks); } - PROCESS_SWITCH(hJetAnalysis, processMCD, "process MC detector level", false); + PROCESS_SWITCH(JetHadronRecoil, processData, "process data", true); - void processMCP(JetMcCollision const& /*collision*/, + void processDataWithRhoSubtraction(soa::Filtered>::iterator const& collision, + soa::Filtered> const& jets, + soa::Filtered const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillHistograms(jets, tracks, 1.0, collision.rho()); + } + PROCESS_SWITCH(JetHadronRecoil, processDataWithRhoSubtraction, "process data with rho subtraction", false); + + void processMCD(soa::Filtered>::iterator const& collision, + aod::JMcCollisions const&, + soa::Filtered> const& jets, + soa::Filtered> const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + if (collision.mcCollision().ptHard() < pTHatMinEvent) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillHistogramsMCD(jets, tracks, 1.0, 0.0, collision.mcCollision().ptHard(), collision.mcCollisionId()); + } + PROCESS_SWITCH(JetHadronRecoil, processMCD, "process MC detector level", false); + + void processMCDWithRhoSubtraction(soa::Filtered>::iterator const& collision, + aod::JMcCollisions const&, + soa::Filtered> const& jets, + soa::Filtered> const& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + if (collision.mcCollision().ptHard() < pTHatMinEvent) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillHistogramsMCD(jets, tracks, 1.0, collision.rho(), collision.mcCollision().ptHard(), collision.mcCollisionId()); + } + 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& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + if (collision.mcCollision().ptHard() < pTHatMinEvent) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ(), collision.mcCollision().weight()); + fillHistogramsMCD(jets, tracks, collision.mcCollision().weight(), 0.0, collision.mcCollision().ptHard(), collision.mcCollisionId()); + } + 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& tracks) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (skipMBGapEvents && collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + if (collision.mcCollision().ptHard() < pTHatMinEvent) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ(), collision.mcCollision().weight()); + fillHistogramsMCD(jets, tracks, collision.mcCollision().weight(), collision.rho(), collision.mcCollision().ptHard(), collision.mcCollisionId()); + } + PROCESS_SWITCH(JetHadronRecoil, processMCDWeightedWithRhoSubtraction, "process MC detector level with event weights and rho subtraction", false); + + void processMCP(aod::JetMcCollision const& mccollision, + soa::SmallGroups const& collisions, soa::Filtered> const& jets, - JetParticles const& particles) + soa::Filtered const& particles) + { + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + if (skipMBGapEvents && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (mccollision.ptHard() < pTHatMinEvent) { + return; + } + if (collisions.size() < 1) { + return; + } + for (auto const& collision : collisions) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + } + registry.fill(HIST("hZvtxSelected"), mccollision.posZ()); + fillMCPHistograms(jets, particles, 1.0, mccollision.ptHard()); + } + PROCESS_SWITCH(JetHadronRecoil, processMCP, "process MC particle level", false); + + void processMCPWeighted(aod::JetMcCollision const& mccollision, + soa::SmallGroups const& collisions, + soa::Filtered> const& jets, + soa::Filtered const& particles) { - fillMCPHistograms(jets, particles); + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + if (skipMBGapEvents && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (mccollision.ptHard() < pTHatMinEvent) { + return; + } + if (collisions.size() < 1) { + return; + } + for (auto const& collision : collisions) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + } + registry.fill(HIST("hZvtxSelected"), mccollision.posZ(), mccollision.weight()); + fillMCPHistograms(jets, particles, mccollision.weight(), mccollision.ptHard()); } - PROCESS_SWITCH(hJetAnalysis, processMCP, "process MC particle level", false); + PROCESS_SWITCH(JetHadronRecoil, processMCPWeighted, "process MC particle level with event weights", false); - void processJetsMCPMCDMatched(soa::Filtered::iterator const& collision, + void processJetsMCPMCDMatched(soa::Filtered>::iterator const& collision, soa::Filtered> const& mcdjets, - soa::Filtered> const& mcdjetsWTA, - soa::Filtered> const& mcpjetsWTA, - JetTracks const&, - JetParticles const&, - JetMcCollisions const&, + aod::JetTracks const& tracks, + aod::JetParticles const& particles, + aod::JetMcCollisions const&, soa::Filtered> const& mcpjets) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { return; } - const auto& mcpjetsWTACut = mcpjetsWTA.sliceBy(PartJetsPerCollision, collision.mcCollisionId()); - for (const auto& mcdjet : mcdjets) { - fillMatchedHistograms(mcdjet, mcdjetsWTA, mcpjetsWTACut, mcpjets); + if (!collision.has_mcCollision()) { + return; + } + if (collision.mcCollision().ptHard() < pTHatMinEvent) { + return; } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillMatchedHistograms(mcdjets, mcpjets, tracks, particles); } - PROCESS_SWITCH(hJetAnalysis, processJetsMCPMCDMatched, "process MC matched", false); - - void processJetsMCPMCDMatchedWeighted(soa::Filtered::iterator const& collision, - soa::Filtered> const& mcdjets, - soa::Filtered> const& mcdjetsWTA, - soa::Filtered> const& mcpjetsWTA, - JetTracks const&, - JetParticles const&, - JetMcCollisions const&, - soa::Filtered> const& mcpjets) + PROCESS_SWITCH(JetHadronRecoil, processJetsMCPMCDMatched, "process MC matched (inc jets)", false); + + void processJetsMCPMCDMatchedWithRhoSubtraction(soa::Filtered>::iterator const& collision, + soa::Filtered> const& mcdjets, + aod::JetTracks const& tracks, + aod::JetParticles const& particles, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) { - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + if (!collision.has_mcCollision()) { return; } - const auto& mcpjetsWTACut = mcpjetsWTA.sliceBy(PartJetsPerCollision, collision.mcCollisionId()); - for (const auto& mcdjet : mcdjets) { - fillMatchedHistograms(mcdjet, mcdjetsWTA, mcpjetsWTACut, mcpjets, mcdjet.eventWeight()); + if (collision.mcCollision().ptHard() < pTHatMinEvent) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillMatchedHistograms(mcdjets, mcpjets, tracks, particles, 1.0, 0.0, collision.mcCollision().ptHard()); + } + PROCESS_SWITCH(JetHadronRecoil, processJetsMCPMCDMatchedWithRhoSubtraction, "process MC matched (inc jets) with rho subtraction", false); + + void processJetsMCPMCDMatchedWeighted(soa::Filtered>::iterator const& collision, + soa::Filtered> const& mcdjets, + aod::JetTracks const& tracks, + aod::JetParticles const& particles, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + if (collision.mcCollision().ptHard() < pTHatMinEvent) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillMatchedHistograms(mcdjets, mcpjets, tracks, particles, collision.mcCollision().weight(), 0.0, collision.mcCollision().ptHard()); + } + PROCESS_SWITCH(JetHadronRecoil, processJetsMCPMCDMatchedWeighted, "process MC matched with event weights (inc jets)", false); + + void processJetsMCPMCDMatchedWeightedWithRhoSubtraction(soa::Filtered>::iterator const& collision, + soa::Filtered> const& mcdjets, + aod::JetTracks const& tracks, + aod::JetParticles const& particles, + aod::JetMcCollisions const&, + soa::Filtered> const& mcpjets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + if (collision.mcCollision().ptHard() < pTHatMinEvent) { + return; + } + registry.fill(HIST("hZvtxSelected"), collision.posZ()); + fillMatchedHistograms(mcdjets, mcpjets, tracks, particles, collision.mcCollision().weight(), collision.rho(), collision.mcCollision().ptHard()); + } + PROCESS_SWITCH(JetHadronRecoil, processJetsMCPMCDMatchedWeightedWithRhoSubtraction, "process MC matched with event weights (inc jets) and rho subtraction", false); + + void processRecoilJetsMCPMCDMatched(aod::JetMcCollisions::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Filtered> const& mcdjets, + soa::Filtered const& particles, + soa::Filtered const& tracks, + soa::Filtered> const& mcpjets) + { + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + if (skipMBGapEvents && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; } + if (mccollision.ptHard() < pTHatMinEvent) { + return; + } + if (collisions.size() < 1) { + return; + } + for (auto const& collision : collisions) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + } + registry.fill(HIST("hZvtxSelected"), mccollision.posZ(), mccollision.weight()); + fillRecoilJetMatchedHistograms(mcdjets, mcpjets, tracks, particles, 1.0, 0.0, mccollision.ptHard()); + } + PROCESS_SWITCH(JetHadronRecoil, processRecoilJetsMCPMCDMatched, "process MC matched (recoil jets)", false); + + void processRecoilJetsMCPMCDMatchedWeighted(aod::JetMcCollisions::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Filtered> const& mcdjets, + soa::Filtered const& tracks, + soa::Filtered const& particles, + soa::Filtered> const& mcpjets) + { + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + if (skipMBGapEvents && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (mccollision.ptHard() < pTHatMinEvent) { + return; + } + if (collisions.size() < 1) { + return; + } + for (auto const& collision : collisions) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + } + registry.fill(HIST("hZvtxSelected"), mccollision.posZ(), mccollision.weight()); + fillRecoilJetMatchedHistograms(mcdjets, mcpjets, tracks, particles, mccollision.weight(), 0.0, mccollision.ptHard()); + } + PROCESS_SWITCH(JetHadronRecoil, processRecoilJetsMCPMCDMatchedWeighted, "process MC matched with event weights (recoil jets)", false); + + void processRecoilJetsMCPMCDMatchedWeightedWithRhoSubtraction(soa::Join::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Filtered> const& mcdjets, + soa::Filtered const& tracks, + soa::Filtered const& particles, + soa::Filtered> const& mcpjets) + { + if (std::abs(mccollision.posZ()) > vertexZCut) { + return; + } + if (skipMBGapEvents && mccollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (mccollision.ptHard() < pTHatMinEvent) { + return; + } + if (collisions.size() < 1) { + return; + } + for (auto const& collision : collisions) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + } + registry.fill(HIST("hZvtxSelected"), mccollision.posZ(), mccollision.weight()); + fillRecoilJetMatchedHistograms(mcdjets, mcpjets, tracks, particles, mccollision.weight(), mccollision.rho(), mccollision.ptHard()); + } + PROCESS_SWITCH(JetHadronRecoil, processRecoilJetsMCPMCDMatchedWeightedWithRhoSubtraction, "process MC matched with event weights (recoil jets) and rho subtraction", false); + + template + double getWTAaxisDifference(T const& jet, X const& /*tracks or particles*/) + { + double deltaPhi = -1; + double deltaY = -1; + double dR = -1; + jetConstituents.clear(); + for (auto& jetConstituent : jet.template tracks_as()) { + fastjetutilities::fillTracks(jetConstituent, jetConstituents, jetConstituent.globalIndex()); + } + jetReclustered.clear(); + fastjet::ClusterSequenceArea clusterSeq(jetReclusterer.findJets(jetConstituents, jetReclustered)); + jetReclustered = sorted_by_pt(jetReclustered); + + deltaPhi = RecoDecay::constrainAngle(jet.phi() - jetReclustered[0].phi(), -o2::constants::math::PI); + deltaY = jet.y() - jetReclustered[0].rap(); + dR = RecoDecay::sqrtSumOfSquares(deltaPhi, deltaY); + return dR; } - PROCESS_SWITCH(hJetAnalysis, processJetsMCPMCDMatchedWeighted, "process MC matched with event weights", 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..b78c6f2b6ef 100644 --- a/PWGJE/Tasks/jetLundReclustering.cxx +++ b/PWGJE/Tasks/jetLundReclustering.cxx @@ -17,34 +17,30 @@ // Task performing jet reclustering and producing primary Lund Plane histograms // -#include -#include -#include -#include - -#include "fastjet/contrib/LundGenerator.hh" -#include "fastjet/PseudoJet.hh" -#include "fastjet/ClusterSequenceArea.hh" +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoA.h" -#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "TDatabasePDG.h" +#include +#include +#include +#include -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "fastjet/ClusterSequenceArea.hh" +#include "fastjet/PseudoJet.hh" +#include -#include "Common/Core/RecoDecay.h" +#include +#include +#include +#include -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/DataModel/JetSubstructure.h" -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include using namespace o2; using namespace o2::track; @@ -67,11 +63,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 +108,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 91% rename from PWGJE/Tasks/jetmatchingqa.cxx rename to PWGJE/Tasks/jetMatchingQA.cxx index 3dc888f0933..6770d42e47e 100644 --- a/PWGJE/Tasks/jetmatchingqa.cxx +++ b/PWGJE/Tasks/jetMatchingQA.cxx @@ -15,14 +15,21 @@ /// \author Jochen Klein /// \author Aimeric Lanodu -#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 "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include +#include + +#include + +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -42,6 +49,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 +84,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 +113,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 +135,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 +168,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(); } @@ -176,7 +185,7 @@ struct JetMatchingQA { } 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) { diff --git a/PWGJE/Tasks/jetOutlierQA.cxx b/PWGJE/Tasks/jetOutlierQA.cxx new file mode 100644 index 00000000000..526ace8e383 --- /dev/null +++ b/PWGJE/Tasks/jetOutlierQA.cxx @@ -0,0 +1,775 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// QA task for MC-based outliers +// +/// \author Jaime Norman + +#include "RecoDecay.h" + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#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 JetOutlierQATask { + + HistogramRegistry registry; + + using JetParticlesWithOriginal = soa::Join; + + Preslice perColTrack = aod::jtrack::collisionId; + Preslice> perColParticle = aod::jmccollision::mcCollisionId; + Preslice> perColJets = aod::jet::collisionId; + Preslice> perColJetsMatched = aod::jet::collisionId; + + 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 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 pTHatMaxMCDOutlier{"pTHatMaxMCDOutlier", 3.0, "maximum fraction of hard scattering for jet acceptance in detector MC for outlier studies"}; + 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"}; + 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 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 splitCollisionsDeltaZ{"splitCollisionsDeltaZ", 0.2, "threshold in delta z to assign as split collision"}; + Configurable splitCollisionsDeltaZPart{"splitCollisionsDeltaZPart", 0.2, "threshold in delta z to assign as split collision particle level"}; + Configurable splitCollisionsDeltaBC{"splitCollisionsDeltaBC", 5, "threshold in BC to assign as split collision"}; + Configurable mergeCollisionsDeltaMin{"mergeCollisionsDeltaMin", -10, "number of prior collisions to search for close Z position"}; + Configurable mergeCollisionsDeltaMax{"mergeCollisionsDeltaMax", 10, "number of following collisions to search for close Z position"}; + Configurable maxNTracksJJdifferent{"maxNTracksJJdifferent", 10, "maximum number of tracks from different JJ collision to be considered for track rejection"}; + + std::map> fBCCollMap; // key: global BC, value: vector of reduced event global indices + + std::vector eventSelectionBits; + int trackSelection = -1; + + std::vector jetPtBins; + std::vector jetPtBinsRhoAreaSub; + + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + 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); + } + } + std::vector pThatBinning = {0.0, 0.25, 0.5, 0.75, 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.25, 4.5, 4.75, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 20.0, 30.0}; + + AxisSpec jetPtAxis = {jetPtBins, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pThatAxis = {pThatBinning, "p_{T} / #hat{p_{T}}"}; + + if (doprocessJetsAmbiguous) { + // outliers + registry.add("h3_pthat_jet_pt_jet_ntracks_outliers", "#it#hat{p} (GeV/#it{c});#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{100, 0, 200}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_pt_track_dEta_track_dPhi_outliers", "#it{p}_{T,jet} (GeV/#it{c});#Delta#eta;#Delta#phi", {HistType::kTH3F, {jetPtAxis, {100, -0.5, 0.5}, {100, -0.5, 0.5}}}); + registry.add("h3_pthat_jet_pt_jet_ntracks_all", "it#hat{p} (GeV/#it{c});#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{100, 0, 200}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_pt_track_dEta_track_dPhi_all", "#it{p}_{T,jet} (GeV/#it{c});#Delta#eta;#Delta#phi", {HistType::kTH3F, {jetPtAxis, {100, -0.5, 0.5}, {100, -0.5, 0.5}}}); + + registry.add("h3_pthat_jet_pt_jet_ntracks_outliers_noweight", "#it#hat{p} (GeV/#it{c});#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{100, 0, 200}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_pt_track_dEta_track_dPhi_outliers_noweight", "#it{p}_{T,jet} (GeV/#it{c});#Delta#eta;#Delta#phi", {HistType::kTH3F, {jetPtAxis, {100, -0.5, 0.5}, {100, -0.5, 0.5}}}); + registry.add("h2_jet_pt_Dz_outliers_noweight", "#it{p}_{T,jet} (GeV/#it{c});z = #it{p}_{T,track} / #it{p}_{T,jet}", {HistType::kTH2F, {jetPtAxis, {30, 0, 1}}}); + registry.add("h3_pthat_jet_pt_jet_ntracks_all_noweight", "it#hat{p} (GeV/#it{c});#it{p}_{T,jet} (GeV/#it{c});N_{jet tracks}", {HistType::kTH3F, {{100, 0, 200}, jetPtAxis, {200, -0.5, 199.5}}}); + registry.add("h3_jet_pt_track_dEta_track_dPhi_all_noweight", "#it{p}_{T,jet} (GeV/#it{c});#Delta#eta;#Delta#phi", {HistType::kTH3F, {jetPtAxis, {100, -0.5, 0.5}, {100, -0.5, 0.5}}}); + registry.add("h2_jet_pt_Dz_all_noweight", "#it{p}_{T,jet} (GeV/#it{c});z = #it{p}_{T,track} / #it{p}_{T,jet}", {HistType::kTH2F, {jetPtAxis, {30, 0, 1}}}); + + registry.add("h3_jet_pt_track_pt_pt_hat_ambiguous", "ambiguous;#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,track} (GeV/#it{c}); #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH3F, {{150, 0, 300}, {100, 0, 100}, {200, 0, 600}}}); + registry.add("h3_jet_pt_track_pt_pt_hat_unambiguous", "matched;#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,track} (GeV/#it{c}); #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH3F, {{150, 0, 300}, {100, 0, 100}, {200, 0, 600}}}); + registry.add("h3_jet_pt_frac_pt_ambiguous_pt_hat", "fraction pT;#it{p}_{T,jet} (GeV/#it{c});fraction of #it{p}_{T,track} unmatched; #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH3F, {{150, 0, 300}, {40, 0, 1.1}, {200, 0, 600}}}); + registry.add("h3_jet_pt_frac_constituents_ambiguous_pt_hat", "fraction const;#it{p}_{T,jet} (GeV/#it{c});fraction of constituents matched; #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH3F, {{150, 0, 300}, {40, 0, 1.1}, {200, 0, 600}}}); + registry.add("h3_jet_pt_track_pt_pt_hat_no_particle", "no matching particle;#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,track} (GeV/#it{c}); #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH3F, {{150, 0, 300}, {100, 0, 100}, {200, 0, 600}}}); + registry.add("h3_jet_pt_track_pt_pt_hat_with_particle", "with matching particle;#it{p}_{T,jet} (GeV/#it{c});#it{p}_{T,track} (GeV/#it{c}); #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH3F, {{150, 0, 300}, {100, 0, 100}, {200, 0, 600}}}); + registry.add("h3_jet_pt_frac_pt_unmatched_particle_pt_hat", "fraction pT;#it{p}_{T,jet} (GeV/#it{c});fraction of #it{p}_{T,track} unmatched; #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH3F, {{150, 0, 300}, {40, 0, 1.1}, {200, 0, 600}}}); + registry.add("h3_jet_pt_frac_constituents_unmatched_particle_pt_hat", "fraction const;#it{p}_{T,jet} (GeV/#it{c});fraction of constituents unmatched; #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH3F, {{150, 0, 300}, {40, 0, 1.1}, {200, 0, 600}}}); + + // collision-level properties + registry.add("h_collision_multiplicity_outlier", "multiplicity", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_collision_pTHat_multiplicity_outlier", "multiplicity", {HistType::kTH2F, {{100, 0, 500}, {200, 0, 200}}}); + registry.add("h_collision_multiplicity_all", "multiplicity", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_collision_pTHat_multiplicity_all", "multiplicity", {HistType::kTH2F, {{100, 0, 500}, {200, 0, 200}}}); + registry.add("h_collision_trackOccupancyInTimeRange_outlier", "track occupancy", {HistType::kTH1F, {{1000, 0, 10000}}}); + registry.add("h_collision_trackOccupancyInTimeRange_all", "track occupancy", {HistType::kTH1F, {{1000, 0, 10000}}}); + registry.add("h_collision_multFV0A_outlier", "mult V0A", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h_collision_multFV0A_all", "mult V0A", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h_collision_multFV0C_outlier", "mult V0A", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h_collision_multFV0C_all", "mult V0A", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h_collision_multFV0M_outlier", "mult V0A", {HistType::kTH1F, {{1000, 0, 1000}}}); + registry.add("h_collision_multFV0M_all", "mult V0A", {HistType::kTH1F, {{1000, 0, 1000}}}); + } + if (doprocessCollisionsBC) { + // delta Z checks + registry.add("h_DeltaZ_InBunch", "Delta Z between two events in bunch", {HistType::kTH1F, {{1200, -30, 30}}}); + registry.add("h_DeltaZ_Z1_InBunch", "Delta Z between two events in bunch vs Z1", {HistType::kTH2F, {{1200, 30, 30}, {400, -12, 12}}}); + registry.add("h_Z1_Z2_InBunch", "Z1 vs Z2 between two events in bunch", {HistType::kTH2F, {{400, -12, 12}, {400, -12, 12}}}); + registry.add("h_DeltaZ_OutOfBunch", "Delta Z between two events out of bunch", {HistType::kTH1F, {{1200, -30, 30}}}); + registry.add("h_DeltaZ_Z1_OutOfBunch", "Delta Z between two events out of bunch vs Z1", {HistType::kTH2F, {{1200, 30, 30}, {400, -12, 12}}}); + registry.add("h_Z1_Z2_OutOfBunch", "Z1 vs Z2 between two events out of bunch", {HistType::kTH2F, {{400, -12, 12}, {400, -12, 12}}}); + registry.add("h_DeltaZ_InBunch_JJ", "Delta Z between two events in bunch", {HistType::kTH1F, {{1200, -30, 30}}}); + registry.add("h_DeltaZ_Z1_InBunch_JJ", "Delta Z between two events in bunch vs Z1", {HistType::kTH2F, {{1200, 30, 30}, {400, -12, 12}}}); + registry.add("h_Z1_Z2_InBunch_JJ", "Z1 vs Z2 between two events in bunch", {HistType::kTH2F, {{400, -12, 12}, {400, -12, 12}}}); + registry.add("h_DeltaZ_OutOfBunch_JJ", "Delta Z between two events out of bunch", {HistType::kTH1F, {{1200, -30, 30}}}); + registry.add("h_DeltaZ_Z1_OutOfBunch_JJ", "Delta Z between two events out of bunch vs Z1", {HistType::kTH2F, {{1200, 30, 30}, {400, -12, 12}}}); + registry.add("h_Z1_Z2_OutOfBunch_JJ", "Z1 vs Z2 between two events out of bunch", {HistType::kTH2F, {{400, -12, 12}, {400, -12, 12}}}); + registry.add("h_Z", "Delta Z between two events", {HistType::kTH1F, {{400, -12, 12}}}); + } + if (doprocessTracksBC) { + // track checks based on z position + registry.add("h_Z_resolution", "Z resolution", {HistType::kTH1F, {{200, -0.05, 0.05}}}); + registry.add("h_Z_resolution_wide", "Z resolution", {HistType::kTH1F, {{200, -1, 1}}}); + registry.add("h_Z_reco_rejected", "Z position reconstructed rejected", {HistType::kTH1F, {{400, -12, 12}}}); + registry.add("h_Z_true_rejected", "Z position particle rejected", {HistType::kTH1F, {{400, -12, 12}}}); + registry.add("h_Z_reco_accepted", "Z position reconstructed accepted", {HistType::kTH1F, {{400, -12, 12}}}); + registry.add("h_Z_true_accepted", "Z position particle accepted", {HistType::kTH1F, {{400, -12, 12}}}); + + registry.add("h_track_pt", "track pt;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, -5, 5}}}); + registry.add("h_track_phi", "track phi;#varphi_{track} (rad);entries", {HistType::kTH1F, {{160, -1.0, 7.0}}}); + registry.add("h_track_pt_eta", "track pt vs eta;p_{T,track} (GeV/#it{c});#eta_{track};entries", {HistType::kTH2F, {{200, 0, 200}, {100, -5, 5}}}); + registry.add("h_track_pt_phi", "track pt vs phi;p_{T,track} (GeV/#it{c});#varphi_{track} (rad);entries", {HistType::kTH2F, {{200, 0, 200}, {160, -1.0, 7.0}}}); + registry.add("h_pt_hard_track_pt", "Tracks vs pThard;#frac{p_{T}}{#hat{p}};p_{T}", {HistType::kTH2F, {pThatAxis, {200, 0, 200}}}); + + registry.add("h_track_pt_accepted", "track pt accepted;p_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_eta_accepted", "track eta accepted;#eta_{track};entries", {HistType::kTH1F, {{100, -5, 5}}}); + registry.add("h_track_phi_accepted", "track phi accepted;#varphi_{track} (rad);entries", {HistType::kTH1F, {{160, -1.0, 7.0}}}); + registry.add("h_track_pt_eta_accepted", "track pt vs eta accepted;p_{T,track} (GeV/#it{c});#eta_{track};entries", {HistType::kTH2F, {{200, 0, 200}, {100, -5, 5}}}); + registry.add("h_track_pt_phi_accepted", "track pt vs phi accepted;p_{T,track} (GeV/#it{c});#varphi_{track} (rad);entries", {HistType::kTH2F, {{200, 0, 200}, {160, -1.0, 7.0}}}); + registry.add("h_pt_hard_track_pt_accepted", "Tracks vs pThard;#frac{p_{T}}{#hat{p}};p_{T}", {HistType::kTH2F, {pThatAxis, {200, 0, 200}}}); + registry.add("h_track_pt_accepted_no_JJ_outlier", "track pT with no JJ outlier", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_pt_eta_accepted_no_JJ_outlier", "track pT vs eta with no JJ outlier;p_{T,track} (GeV/#it{c});#eta_{track};entries", {HistType::kTH2F, {{200, 0, 200}, {100, -5, 5}}}); + registry.add("h_track_pt_phi_accepted_no_JJ_outlier", "track pT vs phi with no JJ outlier;p_{T,track} (GeV/#it{c});#varphi_{track} (rad);entries", {HistType::kTH2F, {{200, 0, 200}, {160, -1.0, 7.0}}}); + registry.add("h_pt_hard_track_pt_accepted_no_JJ_outlier", "Tracks vs pThard;#frac{p_{T}}{#hat{p}};p_{T}", {HistType::kTH2F, {pThatAxis, {200, 0, 200}}}); + registry.add("h_track_pt_with_JJ_outlier", "track pT with JJ outlier", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_pt_eta_with_JJ_outlier", "track pT vs eta with JJ outlier;p_{T,track} (GeV/#it{c});#eta_{track};entries", {HistType::kTH2F, {{200, 0, 200}, {100, -5, 5}}}); + registry.add("h_track_pt_phi_with_JJ_outlier", "track pT vs phi with JJ outlier;p_{T,track} (GeV/#it{c});#varphi_{track} (rad);entries", {HistType::kTH2F, {{200, 0, 200}, {160, -1.0, 7.0}}}); + registry.add("h_pt_hard_track_pt_with_JJ_outlier", "Tracks vs pThard;#frac{p_{T}}{#hat{p}};p_{T}", {HistType::kTH2F, {pThatAxis, {200, 0, 200}}}); + registry.add("h_track_pt_with_MB_outlier", "track pT with MB outlier", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_pt_eta_with_MB_outlier", "track pT vs eta with MB outlier;p_{T,track} (GeV/#it{c});#eta_{track};entries", {HistType::kTH2F, {{200, 0, 200}, {100, -5, 5}}}); + registry.add("h_track_pt_phi_with_MB_outlier", "track pT vs phi with MB outlier;p_{T,track} (GeV/#it{c});#varphi_{track} (rad);entries", {HistType::kTH2F, {{200, 0, 200}, {160, -1.0, 7.0}}}); + registry.add("h_pt_hard_track_pt_with_MB_outlier", "Tracks vs pThard;#frac{p_{T}}{#hat{p}};p_{T}", {HistType::kTH2F, {pThatAxis, {200, 0, 200}}}); + + registry.add("h_track_pt_no_collision", "track pt no collision;p_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_pt_collision", "track pt collision;p_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h2_track_pt_pt_hat_no_particle", "track pt vs pt hat no particle;p_{T,track} (GeV/#it{c});#hat{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0, 200}, {600, 0, 600}}}); + registry.add("h2_track_pt_pt_hat_particle", "track pt vs pt hat particle;p_{T,track} (GeV/#it{c});#hat{p}_{T} (GeV/#it{c});entries", {HistType::kTH2F, {{200, 0, 200}, {600, 0, 600}}}); + + registry.add("h_track_pt_outlier", "weight track pt", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h2_pt_hat_track_pt", "track; #hat{#it{p}_{T}} (GeV/#it{c});#it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{600, 0, 600}, {200, 0, 200}}}); + registry.add("h2_pt_hat_track_pt_outlier", "track; #hat{#it{p}_{T}} (GeV/#it{c});#it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{600, 0, 600}, {200, 0, 200}}}); + registry.add("h2_neighbour_pt_hat_outlier", "neighbour; distance from collision; #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH2F, {{15, -7.5, 7.5}, {600, 0, 600}}}); + registry.add("h2_neighbour_track_pt_outlier", "neighbour; distance from collision; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{15, -7.5, 7.5}, {200, 0, 100}}}); + registry.add("h2_neighbour_pt_hat_all", "neighbour; distance from collision; #hat{#it{p}_{T}} (GeV/#it{c})", {HistType::kTH2F, {{15, -7.5, 7.5}, {600, 0, 600}}}); + registry.add("h2_neighbour_track_pt_all", "neighbour; distance from collision; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{15, -7.5, 7.5}, {200, 0, 100}}}); + + registry.add("h_track_pt_outlier_same_collision", "weight track pt same collision", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_pt_outlier_different_collision_JJ", "weight track pt different jet-jet collision", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_pt_outlier_different_collision_MB", "weight track pt different MB collision", {HistType::kTH1F, {{200, 0, 200}}}); + + registry.add("h2_outlier_event_Ntracks_different_selected_JJ", "number of selected tracks from different jet-jet events", {HistType::kTH2F, {{600, 0, 600}, {200, 0, 200}}}); + registry.add("h2_outlier_event_Ntracks_different_selected_MB", "number of selected tracks from different MB events", {HistType::kTH2F, {{600, 0, 600}, {200, 0, 200}}}); + registry.add("h2_outlier_event_Ntracks_same_selected_JJ", "number of selected tracks from same jet-jet events", {HistType::kTH2F, {{600, 0, 600}, {200, 0, 200}}}); + registry.add("h2_outlier_event_tracks_frac_different_JJ", "fraction of tracks from different jet-jet events", {HistType::kTH2F, {{600, 0, 600}, {100, 0, 1}}}); + registry.add("h2_outlier_event_tracks_frac_different_MB", "fraction of tracks from different MB events", {HistType::kTH2F, {{600, 0, 600}, {100, 0, 1}}}); + registry.add("h2_outlier_event_tracks_frac_different_selected_JJ", "fraction of selected tracks from different jet-jet events", {HistType::kTH2F, {{600, 0, 600}, {100, 0, 1}}}); + registry.add("h2_outlier_event_tracks_frac_different_selected_MB", "fraction of selected tracks from different MB events", {HistType::kTH2F, {{600, 0, 600}, {100, 0, 1}}}); + registry.add("h2_outlier_collision_ID_difference", "difference in collision ID between outlier collision and analysed collision", {HistType::kTH2F, {{600, 0, 600}, {200, -100, 100}}}); + registry.add("h_DeltaZ_Outlier", "Delta Z between outlier collision and analysed collision", {HistType::kTH1F, {{1200, -30, 30}}}); + registry.add("h2_DeltaZ_Outlier_difference", "Delta Z between outlier collision and analysed collision vs difference in collision ID", {HistType::kTH2F, {{1200, -30, 30}, {200, -100, 100}}}); + + registry.add("h_track_pt_same_collision", "track pt from same collision or different MB collision;p_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_pt_eta_same_collision", "track pt vs eta from same collision or different MB collision;p_{T,track} (GeV/#it{c});#eta_{track};entries", {HistType::kTH2F, {{200, 0, 200}, {100, -5, 5}}}); + registry.add("h_track_pt_phi_same_collision", "track pt vs phi from same collision or different MB collision;p_{T,track} (GeV/#it{c});#varphi_{track} (rad);entries", {HistType::kTH2F, {{200, 0, 200}, {160, -1.0, 7.0}}}); + registry.add("h2_collision_ID_difference_same_collision", "difference in collision ID between outlier collision and analysed collision", {HistType::kTH2F, {{600, 0, 600}, {200, -100, 100}}}); + registry.add("h_pt_hard_track_pt_same_collision", "Tracks vs pThard;#frac{p_{T}}{#hat{p}};p_{T}", {HistType::kTH2F, {pThatAxis, {200, 0, 200}}}); + registry.add("h_track_pt_same_collision_cut_particle", "track pt from same collision or different MB collision;p_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_pt_hard_track_pt_same_collision_cut_particle", "Tracks vs pThard;#frac{p_{T}}{#hat{p}};p_{T}", {HistType::kTH2F, {pThatAxis, {200, 0, 200}}}); + registry.add("h_track_pt_same_collision_rejected", "rejected track pt from same collision or different MB collision;p_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0, 200}}}); + + registry.add("h_track_pt_no_JJ_different", "track pt from same collision or different MB collision;p_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0, 200}}}); + registry.add("h_track_pt_eta_no_JJ_different", "track pt vs eta from same collision or different MB collision;p_{T,track} (GeV/#it{c});#eta_{track};entries", {HistType::kTH2F, {{200, 0, 200}, {100, -5, 5}}}); + registry.add("h_track_pt_phi_no_JJ_different", "track pt vs phi from same collision or different MB collision;p_{T,track} (GeV/#it{c});#varphi_{track} (rad);entries", {HistType::kTH2F, {{200, 0, 200}, {160, -1.0, 7.0}}}); + registry.add("h2_collision_ID_difference_no_JJ_different", "difference in collision ID between outlier collision and analysed collision", {HistType::kTH2F, {{600, 0, 600}, {200, -100, 100}}}); + registry.add("h_track_pt_no_JJ_different_rejected", "rejected track pt from same collision or different MB collision;p_{T,track} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0, 200}}}); + } + } + + 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::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); + + 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; + } + + void fillHistogramsAmbiguous(soa::Join::iterator const& jet, + float weight, + aod::AmbiguousTracks const& tracksAmbiguous) + { + + float pTHat = 10. / (std::pow(weight, 1.0 / pTHatExponent)); + if (jet.pt() > pTHatMaxMCD * pTHat) { + return; + } + // outlier ID checks + if (jet.pt() > pTHatMaxMCDOutlier * pTHat) { + registry.fill(HIST("h3_pthat_jet_pt_jet_ntracks_outliers"), pTHat, jet.pt(), jet.tracksIds().size(), weight); + registry.fill(HIST("h3_pthat_jet_pt_jet_ntracks_outliers_noweight"), pTHat, jet.pt(), jet.tracksIds().size()); + } else { + registry.fill(HIST("h3_pthat_jet_pt_jet_ntracks_all"), pTHat, jet.pt(), jet.tracksIds().size(), weight); + registry.fill(HIST("h3_pthat_jet_pt_jet_ntracks_all_noweight"), pTHat, jet.pt(), jet.tracksIds().size()); + } + for (auto& constituent : jet.template tracks_as()) { + if (jet.pt() > pTHatMaxMCDOutlier * pTHat) { + registry.fill(HIST("h3_jet_pt_track_dEta_track_dPhi_outliers"), jet.pt(), jet.eta() - constituent.eta(), jet.phi() - constituent.phi(), weight); + registry.fill(HIST("h3_jet_pt_track_dEta_track_dPhi_outliers_noweight"), jet.pt(), jet.eta() - constituent.eta(), jet.phi() - constituent.phi()); + registry.fill(HIST("h2_jet_pt_Dz_outliers_noweight"), jet.pt(), constituent.pt() / jet.pt()); + } else { + registry.fill(HIST("h3_jet_pt_track_dEta_track_dPhi_all"), jet.pt(), jet.eta() - constituent.eta(), jet.phi() - constituent.phi(), weight); + registry.fill(HIST("h3_jet_pt_track_dEta_track_dPhi_all_noweight"), jet.pt(), jet.eta() - constituent.eta(), jet.phi() - constituent.phi()); + registry.fill(HIST("h2_jet_pt_Dz_all_noweight"), jet.pt(), constituent.pt() / jet.pt()); + } + } + + // ambiguous/unmatched track checks + auto iterAmbiguous = tracksAmbiguous.begin(); + int nAmbTracks = 0; + int nUnmatchedTracks = 0; + double pt_total = 0; + double pt_amb = 0; + double pt_unmatched = 0; + for (auto& constituent : jet.template tracks_as()) { + pt_total += constituent.pt(); + bool has_MCparticle = constituent.has_mcParticle(); + if (!has_MCparticle) { + // LOG(info) << "constituent NO MC PARTICLE: track.index()=" << constituent.index() << " track.globalIndex()=" << constituent.globalIndex(); + registry.fill(HIST("h3_jet_pt_track_pt_pt_hat_no_particle"), jet.pt(), constituent.pt(), pTHat, weight); + pt_unmatched += constituent.pt(); + nUnmatchedTracks++; + } else { + registry.fill(HIST("h3_jet_pt_track_pt_pt_hat_with_particle"), jet.pt(), constituent.pt(), pTHat, weight); + } + + bool goFillHisto = (iterAmbiguous != tracksAmbiguous.end()); + if (goFillHisto) { + while (constituent.globalIndex() > iterAmbiguous.trackId()) { + iterAmbiguous++; + if (iterAmbiguous == tracksAmbiguous.end()) { /// all ambiguous tracks found + goFillHisto = false; + break; + } + } + } + if (goFillHisto) { + if (constituent.globalIndex() == iterAmbiguous.trackId()) { + nAmbTracks++; + registry.fill(HIST("h3_jet_pt_track_pt_pt_hat_ambiguous"), jet.pt(), constituent.pt(), pTHat, weight); + pt_amb += constituent.pt(); + nAmbTracks++; + } else { + registry.fill(HIST("h3_jet_pt_track_pt_pt_hat_unambiguous"), jet.pt(), constituent.pt(), pTHat, weight); + } + } + } + registry.fill(HIST("h3_jet_pt_frac_pt_ambiguous_pt_hat"), jet.pt(), pt_amb / pt_total, pTHat, weight); + registry.fill(HIST("h3_jet_pt_frac_constituents_ambiguous_pt_hat"), jet.pt(), double(nAmbTracks) / double(jet.template tracks_as().size()), pTHat, weight); + + registry.fill(HIST("h3_jet_pt_frac_pt_unmatched_particle_pt_hat"), jet.pt(), pt_unmatched / pt_total, pTHat, weight); + registry.fill(HIST("h3_jet_pt_frac_constituents_unmatched_particle_pt_hat"), jet.pt(), double(nUnmatchedTracks) / double(jet.template tracks_as().size()), pTHat, weight); + } + + void processJetsAmbiguous(soa::Filtered>::iterator const& collision, + aod::JetMcCollisions const&, + soa::Join const& jets, + aod::JetTracksMCD const&, + const aod::AmbiguousTracks& tracksAmbiguous) + { + // + // jet-based outlier checks based on ambiguous tracks + // + if (collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + bool isOutlierEvent = false; + int nTracksJet = 0; + float pTHat = collision.mcCollision().ptHard(); + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistogramsAmbiguous(jet, collision.weight(), tracksAmbiguous); + nTracksJet += jet.tracksIds().size(); + if (jet.pt() > pTHatMaxMCDOutlier * pTHat) { + isOutlierEvent = true; + } + } + if (isOutlierEvent) { + registry.fill(HIST("h_collision_pTHat_multiplicity_outlier"), pTHat, nTracksJet, collision.weight()); + registry.fill(HIST("h_collision_multiplicity_outlier"), nTracksJet, collision.weight()); + registry.fill(HIST("h_collision_trackOccupancyInTimeRange_outlier"), collision.trackOccupancyInTimeRange(), collision.weight()); + registry.fill(HIST("h_collision_multFV0A_outlier"), collision.multFV0A(), collision.weight()); + registry.fill(HIST("h_collision_multFV0C_outlier"), collision.multFV0C(), collision.weight()); + registry.fill(HIST("h_collision_multFV0M_outlier"), collision.multFV0M(), collision.weight()); + } else { + registry.fill(HIST("h_collision_multiplicity_all"), nTracksJet, collision.weight()); + registry.fill(HIST("h_collision_pTHat_multiplicity_all"), pTHat, nTracksJet, collision.weight()); + registry.fill(HIST("h_collision_trackOccupancyInTimeRange_all"), collision.trackOccupancyInTimeRange(), collision.weight()); + registry.fill(HIST("h_collision_multFV0A_all"), collision.multFV0A(), collision.weight()); + registry.fill(HIST("h_collision_multFV0C_all"), collision.multFV0C(), collision.weight()); + registry.fill(HIST("h_collision_multFV0M_all"), collision.multFV0M(), collision.weight()); + } + } + PROCESS_SWITCH(JetOutlierQATask, processJetsAmbiguous, "jet finder QA mcd with weighted events", false); + + void processCollisionsBC(soa::Join const& collisions, + aod::JetMcCollisions const&) + { + // + // collision-based outlier checks based on BC and z position + // based on 2-event correlation checks in PWGDQ/Tasks/tableReader_withAssoc.cxx + // + + fBCCollMap.clear(); + for (auto const& collision : collisions) { + // Fill the BC map of events + if (fBCCollMap.find(collision.bcId()) == fBCCollMap.end()) { + std::vector evIndices = {collision.globalIndex()}; + fBCCollMap[collision.bcId()] = evIndices; + } else { + auto& evIndices = fBCCollMap[collision.bcId()]; + evIndices.push_back(collision.globalIndex()); + } + registry.fill(HIST("h_Z"), collision.posZ()); + } + + // Create a map for collisions which are candidate of being split + // key: event global index, value: whether pileup event is a possible splitting + // (not used ATM, but could be used to flag events in the future) + std::map collisionSplittingMap; + + // 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 = collisions.rawIteratorAt(*ev1It); + for (auto ev2It = std::next(ev1It); ev2It != bc1Events.end(); ++ev2It) { + auto ev2 = collisions.rawIteratorAt(*ev2It); + // compute 2-event quantities and mark the candidate split collisions + float deltaZ = ev1.posZ() - ev2.posZ(); + if (TMath::Abs(deltaZ) < splitCollisionsDeltaZ) { // this is a possible collision split + collisionSplittingMap[*ev1It] = true; + collisionSplittingMap[*ev2It] = true; + } + registry.fill(HIST("h_DeltaZ_InBunch"), deltaZ); + registry.fill(HIST("h_DeltaZ_Z1_InBunch"), deltaZ, ev1.posZ()); + registry.fill(HIST("h_Z1_Z2_InBunch"), ev1.posZ(), ev2.posZ()); + if (ev1.subGeneratorId() != jetderiveddatautilities::JCollisionSubGeneratorId::mbGap && + ev2.subGeneratorId() != jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { // both are non-gap events + registry.fill(HIST("h_DeltaZ_InBunch_JJ"), deltaZ); + registry.fill(HIST("h_DeltaZ_Z1_InBunch_JJ"), deltaZ, ev1.posZ()); + registry.fill(HIST("h_Z1_Z2_InBunch_JJ"), ev1.posZ(), ev2.posZ()); + } + } // 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) > splitCollisionsDeltaBC) { + break; + } + auto bc2Events = bc2It->second; + + // loop over events in the first BC + for (auto ev1It : bc1Events) { + auto ev1 = collisions.rawIteratorAt(ev1It); + // loop over events in the second BC + for (auto ev2It : bc2Events) { + auto ev2 = collisions.rawIteratorAt(ev2It); + // compute 2-event quantities and mark the candidate split collisions + float deltaZ = ev1.posZ() - ev2.posZ(); + if (TMath::Abs(deltaZ) < splitCollisionsDeltaZ) { // this is a possible collision split + collisionSplittingMap[ev1It] = true; + collisionSplittingMap[ev2It] = true; + } + registry.fill(HIST("h_DeltaZ_OutOfBunch"), deltaZ); + registry.fill(HIST("h_DeltaZ_Z1_OutOfBunch"), deltaZ, ev1.posZ()); + registry.fill(HIST("h_Z1_Z2_OutOfBunch"), ev1.posZ(), ev2.posZ()); + if (ev1.subGeneratorId() != jetderiveddatautilities::JCollisionSubGeneratorId::mbGap && + ev2.subGeneratorId() != jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { // both are non-gap events + registry.fill(HIST("h_DeltaZ_OutOfBunch_JJ"), deltaZ); + registry.fill(HIST("h_DeltaZ_Z1_OutOfBunch_JJ"), deltaZ, ev1.posZ()); + registry.fill(HIST("h_Z1_Z2_OutOfBunch_JJ"), ev1.posZ(), ev2.posZ()); + } + } + } + } + } + } + PROCESS_SWITCH(JetOutlierQATask, processCollisionsBC, "jet finder QA outliers", false); + + void processTracksBC(soa::Filtered> const& collisions, + soa::Join const&, + aod::JetMcCollisions const& collisionsMC, + aod::JetTracksMCD const& tracks, + JetParticlesWithOriginal const&) + { + // + // track-based outlier checks + // + + // first check for collisions occuring close by in time and z in MC + std::set closeByCollisionIDs; + for (auto const& collisionMC : collisionsMC) { + if (collisionMC.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + continue; + } + float posZtrue = collisionMC.posZ(); + for (auto const& collisionCloseMC : collisionsMC) { // check for closeby collisions in MC + int diffColl = collisionCloseMC.globalIndex() - collisionMC.globalIndex(); + if (diffColl >= mergeCollisionsDeltaMin && diffColl <= mergeCollisionsDeltaMax) { // check if n collisions prior or after + if (collisionCloseMC.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + continue; + } + if (diffColl == 0) { + continue; + } + if (TMath::Abs(collisionCloseMC.posZ() - posZtrue) < splitCollisionsDeltaZPart) { + closeByCollisionIDs.insert(collisionMC.globalIndex()); // Save the ID of the close-by collision + break; // closeby collision in MC, don't use this event + } + } + } + } + // now make reconstructed-level checks + for (auto const& collision : collisions) { // loop over reconstructed collisions + if (collision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + continue; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + continue; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + continue; + } + float weight = collision.weight(); + float pTHat = collision.mcCollision().ptHard(); + bool isOutlierEventDifferentJJCollision = false; + bool isOutlierEventDifferentMBCollision = false; + + const auto tracksColl = tracks.sliceBy(perColTrack, collision.globalIndex()); + // fill track histograms for all collisions + for (auto const& track : tracksColl) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + 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_pt_eta"), track.pt(), track.eta(), weight); + registry.fill(HIST("h_track_pt_phi"), track.pt(), track.phi(), weight); + registry.fill(HIST("h_pt_hard_track_pt"), pTHat != 0.0 ? track.pt() / pTHat : 0.0, track.pt(), weight); + // checks on track distributions with/without collision and with/without MC particle + if (!track.has_collision() || track.collisionId() != collision.globalIndex()) { + registry.fill(HIST("h_track_pt_no_collision"), track.pt(), weight); + } else { + registry.fill(HIST("h_track_pt_collision"), track.pt(), weight); + } + bool has_MCparticle = track.has_mcParticle(); + if (!has_MCparticle) { + registry.fill(HIST("h2_track_pt_pt_hat_no_particle"), track.pt(), collision.mcCollision().ptHard(), weight); + } else { + registry.fill(HIST("h2_track_pt_pt_hat_particle"), track.pt(), collision.mcCollision().ptHard(), weight); + } + // check outlier tracks and neighbouring collisions + registry.fill(HIST("h2_pt_hat_track_pt"), pTHat, track.pt()); + // get MC info about track and collision + auto mcParticleOutlier = track.mcParticle_as(); + auto collisionMCOutlier = collisionsMC.sliceBy(perColParticle, mcParticleOutlier.mcCollisionId()); + if (collisionMCOutlier.size() != 1) { + LOG(info) << "size of collision outlier not expected"; + return; + } + int mcCollisionIDcoll = collision.mcCollisionId(); // Get the corresponding MC collision ID from the reco collision + int mcCollisionIDOutlier = mcParticleOutlier.mcCollisionId(); + int subGenIDOutlier = collisionMCOutlier.begin().subGeneratorId(); + int outlierCollisionIDDifference = mcCollisionIDOutlier - mcCollisionIDcoll; + + int nMBdifferent = 0; + int nMBdifferentSelected = 0; + int nJJdifferent = 0; + int nJJdifferentSelected = 0; + int nJJsame = 0; + int nJJsameSelected = 0; + // ID outlier based on track pT relative to pTHat + if (track.pt() > pTHatMaxMCDOutlier * pTHat) { // high weight outlier track + registry.fill(HIST("h_track_pt_outlier"), track.pt()); + registry.fill(HIST("h2_pt_hat_track_pt_outlier"), pTHat, track.pt()); + for (auto const& collisionOutlier : collisions) { // find collisions closeby + int diffColl = collision.globalIndex() - collisionOutlier.globalIndex(); + if (abs(diffColl) < 6) { + float eventWeightOutlier = collisionOutlier.mcCollision().weight(); + double pTHatOutlier = collisionOutlier.mcCollision().ptHard(); + registry.fill(HIST("h2_neighbour_pt_hat_outlier"), float(diffColl + 0.1), pTHatOutlier, eventWeightOutlier); + registry.fill(HIST("h2_neighbour_track_pt_outlier"), float(diffColl + 0.1), track.pt(), eventWeightOutlier); + } + } + // now match tracks to their MC particle, check the MC collision ID of this particle, and + // check what fraction of tracks in this event are associated to this MC collision + // LOG(info) << "--- Loop over tracks in outlier event with pT/pThat = " << track.pt() / pTHat << "---"; + // LOG(info) << "N tracks in outlier event = " << tracksColl.size() << " pTHat = " << pTHat << " collisionID = " << collision.globalIndex() << " mcCollisionID = " << collision.mcCollisionId(); + for (auto const& trackOutlier : tracksColl) { + if (!trackOutlier.has_mcParticle()) { + continue; + } + bool isTrackSelected = false; + if (jetderiveddatautilities::selectTrack(trackOutlier, trackSelection)) { + isTrackSelected = true; + } + auto mcParticle = trackOutlier.mcParticle_as(); + auto collisionMC = collisionsMC.sliceBy(perColParticle, mcParticle.mcCollisionId()); + if (collisionMC.size() == 0) { + LOG(info) << "no collision found for mcCollisionID = " << mcParticle.mcCollisionId(); + continue; + } + int mcCollisionIDtrack = mcParticle.mcCollisionId(); // Get the corresponding MC collision ID + int subGenID = collisionMC.begin().subGeneratorId(); + if (mcCollisionIDtrack == mcCollisionIDcoll) { + nJJsame++; + if (isTrackSelected) { + registry.fill(HIST("h_track_pt_outlier_same_collision"), trackOutlier.pt()); + nJJsameSelected++; + } + } else { + if (subGenID == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { // MB-gap + nMBdifferent++; + if (isTrackSelected) { + registry.fill(HIST("h_track_pt_outlier_different_collision_MB"), trackOutlier.pt()); + nMBdifferentSelected++; + } + } else { // jet-jet + nJJdifferent++; + if (isTrackSelected) { + registry.fill(HIST("h_track_pt_outlier_different_collision_JJ"), trackOutlier.pt()); + nJJdifferentSelected++; + } + } + } + } + // LOG(info) << "nJJsame = " << nJJsame << " nJJdifferent = " << nJJdifferent << " nMBdifferent = " << nMBdifferent; + // LOG(info) << "nJJsameSelected = " << nJJsameSelected << " nJJdifferentSelected = " << nJJdifferentSelected << " nMBdifferentSelected = " << nMBdifferentSelected; + registry.fill(HIST("h2_outlier_event_Ntracks_different_selected_JJ"), pTHat, nJJdifferentSelected); + registry.fill(HIST("h2_outlier_event_Ntracks_different_selected_MB"), pTHat, nMBdifferentSelected); + registry.fill(HIST("h2_outlier_event_Ntracks_same_selected_JJ"), pTHat, nJJsameSelected); + registry.fill(HIST("h2_outlier_event_tracks_frac_different_selected_MB"), pTHat, float(nMBdifferentSelected) / float(nJJdifferentSelected + nJJsameSelected + nMBdifferentSelected)); + registry.fill(HIST("h2_outlier_event_tracks_frac_different_JJ"), pTHat, float(nJJdifferent) / float(nJJdifferent + nJJsame + nMBdifferent)); + registry.fill(HIST("h2_outlier_event_tracks_frac_different_MB"), pTHat, float(nMBdifferent) / float(nJJdifferent + nJJsame + nMBdifferent)); + registry.fill(HIST("h2_outlier_event_tracks_frac_different_selected_JJ"), pTHat, float(nJJdifferentSelected) / float(nJJdifferentSelected + nJJsameSelected + nMBdifferentSelected)); + registry.fill(HIST("h2_outlier_event_tracks_frac_different_selected_MB"), pTHat, float(nMBdifferentSelected) / float(nJJdifferentSelected + nJJsameSelected + nMBdifferentSelected)); + // now check where outlier comes from + // LOG(info) <<"outlier comes from " << (mcCollisionIDOutlier == mcCollisionIDcoll ? "same" : "different") << " event which is a " << (subGenIDOutlier == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap ? " MB-gap" : " jet-jet") << " collision with mcCollisionID = " << mcCollisionIDOutlier; + registry.fill(HIST("h2_outlier_collision_ID_difference"), pTHat, float(outlierCollisionIDDifference)); + // if outlier comes from different collision, check which type and set flags + if (mcCollisionIDOutlier != mcCollisionIDcoll && subGenIDOutlier != jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + isOutlierEventDifferentJJCollision = true; + float deltaZ = collisionMCOutlier.begin().posZ() - collision.mcCollision().posZ(); + registry.fill(HIST("h_DeltaZ_Outlier"), deltaZ); + registry.fill(HIST("h2_DeltaZ_Outlier_difference"), deltaZ, float(outlierCollisionIDDifference)); + } else if (mcCollisionIDOutlier != mcCollisionIDcoll && subGenIDOutlier == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + isOutlierEventDifferentMBCollision = true; + } + } + // fill for tracks from same collision or different MB collision in collisions that likely aren't fully merged + if (nJJdifferentSelected < maxNTracksJJdifferent && + (subGenIDOutlier == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap || + mcCollisionIDOutlier == mcCollisionIDcoll)) { + registry.fill(HIST("h_track_pt_same_collision"), track.pt(), weight); + registry.fill(HIST("h_track_pt_eta_same_collision"), track.pt(), track.eta(), weight); + registry.fill(HIST("h_track_pt_phi_same_collision"), track.pt(), track.phi(), weight); + registry.fill(HIST("h2_collision_ID_difference_same_collision"), pTHat, float(outlierCollisionIDDifference)); + registry.fill(HIST("h_pt_hard_track_pt_same_collision"), pTHat != 0.0 ? track.pt() / pTHat : 0.0, track.pt(), weight); + + // include selection on pThat of particle + if (mcParticleOutlier.pt() < pTHatMaxMCP * pTHat) { + registry.fill(HIST("h_track_pt_same_collision_cut_particle"), track.pt(), weight); + registry.fill(HIST("h_pt_hard_track_pt_same_collision_cut_particle"), pTHat != 0.0 ? track.pt() / pTHat : 0.0, track.pt(), weight); + } + } else { + registry.fill(HIST("h_track_pt_same_collision_rejected"), track.pt(), weight); + } + // fill tracks for events which have no JJ outlier tracks from different events + if (nJJdifferentSelected == 0) { + registry.fill(HIST("h_track_pt_no_JJ_different"), track.pt(), weight); + registry.fill(HIST("h_track_pt_eta_no_JJ_different"), track.pt(), track.eta(), weight); + registry.fill(HIST("h_track_pt_phi_no_JJ_different"), track.pt(), track.phi(), weight); + registry.fill(HIST("h2_collision_ID_difference_no_JJ_different"), pTHat, float(outlierCollisionIDDifference)); + } else { + registry.fill(HIST("h_track_pt_no_JJ_different_rejected"), track.pt(), weight); + } + // collision checks for all tracks + for (auto const& collisionOutlier : collisions) { // find collisions closeby + float eventWeightOutlier = collisionOutlier.mcCollision().weight(); + double pTHatOutlier = collisionOutlier.mcCollision().ptHard(); + int diffColl = collision.globalIndex() - collisionOutlier.globalIndex(); + + if (abs(diffColl) < 6) { + // LOG(info) << "pThat = " << pTHat << "pThat neighbour = "<(cfgc, TaskName{"jet-outlier-qa"})}; // o2-linter: disable=name/o2-task,name/workflow-file +} diff --git a/PWGJE/Tasks/jetplanarflow.cxx b/PWGJE/Tasks/jetPlanarFlow.cxx similarity index 90% rename from PWGJE/Tasks/jetplanarflow.cxx rename to PWGJE/Tasks/jetPlanarFlow.cxx index 03ba20f5031..1edf34d8396 100644 --- a/PWGJE/Tasks/jetplanarflow.cxx +++ b/PWGJE/Tasks/jetPlanarFlow.cxx @@ -14,25 +14,30 @@ /// \author Nima Zardoshti // -#include +#include "JetDerivedDataUtilities.h" -#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 "Framework/Logger.h" -#include "Framework/HistogramRegistry.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetUtilities.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/FastJetUtilities.h" #include "PWGJE/Core/JetFindingUtilities.h" #include "PWGJE/Core/JetSubstructureUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include + +#include + #include "fastjet/contrib/AxesDefinition.hh" -#include "fastjet/contrib/MeasureDefinition.hh" + +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -106,7 +111,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,13 +125,13 @@ 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; } // jet pT, tau2/tau1, jetdR, track pt, phi', eta', dR, isInJet - Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); template void fillHistograms(T const& collision, U const& jet, V const& tracks) @@ -238,7 +243,7 @@ struct JetPlanarFlowTask { } uint8_t isInJet = 0; - for (auto& jetConstituentId : jet.tracksIds()) { + for (const auto& jetConstituentId : jet.tracksIds()) { if (track.globalIndex() == jetConstituentId) { isInJet = 1; break; @@ -273,16 +278,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 +301,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 +319,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 +337,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 +355,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..88de8265f58 --- /dev/null +++ b/PWGJE/Tasks/jetShape.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 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 "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGLF/DataModel/mcCentrality.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 "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetShapeTask { + + Configurable nBinsNSigma{"nBinsNSigma", 101, "Number of nsigma bins"}; + Configurable nSigmaMin{"nSigmaMin", -10.1f, "Min value of nsigma"}; + Configurable nSigmaMax{"nSigmaMax", 10.1f, "Max value of nsigma"}; + Configurable nBinsPForDedx{"nBinsPForDedx", 700, "Number of p bins"}; + Configurable nBinsPForBeta{"nBinsPForBeta", 500, "Number of pT bins"}; + Configurable nBinsTpcDedx{"nBinsTpcDedx", 500, "Number of DEdx bins"}; + Configurable nBinsTofBeta{"nBinsTofBeta", 350, "Number of Beta bins"}; + Configurable pMax{"pMax", 7.0f, "Max value of p"}; + Configurable ptMax{"ptMax", 5.0f, "Max value of pT"}; + Configurable jetPtMinForCut{"jetPtMinForCut", 0.0f, "Minimum value of jet pT cut"}; + Configurable jetPtMaxForCut{"jetPtMaxForCut", 200.0f, "Maximum value of the jet pT cut"}; + Configurable centralityMinForCut{"centralityMinForCut", 0.0f, "Minimum value of ce cut"}; + Configurable centralityMaxForCut{"centralityMaxForCut", 100.0f, "Maximum value of the jet pT cut"}; + Configurable nBinsP{"nBinsP", 70, "Number of p bins"}; + Configurable nBinsPt{"nBinsPt", 50, "Number of pT bins"}; + Configurable nBinsJetPt{"nBinsJetPt", 10, "Number of jet pT bins"}; + Configurable nBinsCentrality{"nBinsCentrality", 20, "Number of centrality bins"}; + Configurable nBinsDistance{"nBinsDistance", 7, "Number of distance bins"}; + Configurable distanceMax{"distanceMax", 0.7f, "Max value of distance"}; + Configurable nSigmaTofCut{"nSigmaTofCut", 2.0f, "Number of sigma cut for TOF PID"}; + Configurable tpcNSigmaPrMin{"tpcNSigmaPrMin", -3.5f, "Min value of tpcNsigmaProton"}; + Configurable tpcNSigmaPrMax{"tpcNSigmaPrMax", 0.5f, "Max value of tpcNsigmaProton"}; + Configurable tpcNSigmaPiMin{"tpcNSigmaPiMin", -0.5f, "Min value of tpcNsigmaPion"}; + Configurable tpcNSigmaPiMax{"tpcNSigmaPiMax", 3.5f, "Max value of tpcNsigmaPion"}; + + HistogramRegistry registry{"registry", + {{"tpcTofPi", "tpcTofPi", {HistType::kTHnSparseD, {{35, 0, pMax}, {nBinsNSigma, nSigmaMin, nSigmaMax}, {nBinsDistance, 0, distanceMax}, {nBinsJetPt, jetPtMinForCut, jetPtMaxForCut}, {nBinsCentrality, centralityMinForCut, centralityMaxForCut}}}}, + {"tpcTofPr", "tpcTofPr", {HistType::kTHnSparseD, {{35, 0, pMax}, {nBinsNSigma, nSigmaMin, nSigmaMax}, {nBinsDistance, 0, distanceMax}, {nBinsJetPt, jetPtMinForCut, jetPtMaxForCut}, {nBinsCentrality, centralityMinForCut, centralityMaxForCut}}}}, + {"tpcTofPiOutOfJet", "tpcTofPiOutOfJet", {HistType::kTHnSparseD, {{35, 0, pMax}, {nBinsNSigma, nSigmaMin, nSigmaMax}, {nBinsJetPt, jetPtMinForCut, jetPtMaxForCut}, {nBinsCentrality, centralityMinForCut, centralityMaxForCut}}}}, + {"tpcTofPrOutOfJet", "tpcTofPrOutOfJet", {HistType::kTHnSparseD, {{35, 0, pMax}, {nBinsNSigma, nSigmaMin, nSigmaMax}, {nBinsJetPt, jetPtMinForCut, jetPtMaxForCut}, {nBinsCentrality, centralityMinForCut, centralityMaxForCut}}}}, + {"tpcPi", "tpcPi", {HistType::kTH2F, {{nBinsP, 0, pMax}, {nBinsNSigma, nSigmaMin, nSigmaMax}}}}, + {"tofPi", "tofPi", {HistType::kTH2F, {{nBinsPt, 0, ptMax}, {nBinsNSigma, nSigmaMin, nSigmaMax}}}}, + {"tpcPr", "tpcPr", {HistType::kTH2F, {{nBinsP, 0, pMax}, {nBinsNSigma, nSigmaMin, nSigmaMax}}}}, + {"tofPr", "tofPr", {HistType::kTH2F, {{nBinsPt, 0, ptMax}, {nBinsNSigma, nSigmaMin, nSigmaMax}}}}, + {"tpcDedx", "tpcDedx", {HistType::kTHnSparseD, {{nBinsPForDedx, 0, pMax}, {nBinsTpcDedx, 0, 1000}, {nBinsDistance, 0, distanceMax}}}}, + {"tpcDedxOutOfJet", "tpcDedxOutOfJet", {HistType::kTH2F, {{nBinsPForDedx, 0, pMax}, {nBinsTpcDedx, 0, 1000}}}}, + {"tofBeta", "tofBeta", {HistType::kTH2F, {{nBinsPForBeta, 0, pMax}, {nBinsTofBeta, 0.4, 1.1}}}}, + {"pVsPtForPr", "pVsPtForPr", {HistType::kTHnSparseD, {{nBinsP, 0, pMax}, {nBinsPt, 0, ptMax}, {nBinsDistance, 0, distanceMax}, {nBinsJetPt, jetPtMinForCut, jetPtMaxForCut}, {nBinsCentrality, centralityMinForCut, centralityMaxForCut}}}}, + {"pVsPtForPi", "pVsPtPi", {HistType::kTHnSparseD, {{nBinsP, 0, pMax}, {nBinsPt, 0, ptMax}, {nBinsDistance, 0, distanceMax}, {nBinsJetPt, jetPtMinForCut, jetPtMaxForCut}, {nBinsCentrality, centralityMinForCut, centralityMaxForCut}}}}, + {"pVsPtForPrOutOfJet", "pVsPtForPrOutOfJet", {HistType::kTHnSparseD, {{nBinsP, 0, pMax}, {nBinsPt, 0, ptMax}, {nBinsJetPt, jetPtMinForCut, jetPtMaxForCut}, {nBinsCentrality, centralityMinForCut, centralityMaxForCut}}}}, + {"pVsPtForPiOutOfJet", "pVsPtPionOutOfJet", {HistType::kTHnSparseD, {{nBinsP, 0, pMax}, {nBinsPt, 0, ptMax}, {nBinsJetPt, jetPtMinForCut, jetPtMaxForCut}, {nBinsCentrality, centralityMinForCut, centralityMaxForCut}}}}, + {"tofMass", "tofMass", {HistType::kTH1F, {{300, 0, 3}}}}, + {"trackPhi", "trackPhi", {HistType::kTH1F, {{80, -1, 7}}}}, + {"trackEta", "trackEta", {HistType::kTH1F, {{100, -1, 1}}}}, + {"trackTpcNClsCrossedRows", "trackTpcNClsCrossedRows", {HistType::kTH1F, {{50, 0, 200}}}}, + {"trackDcaXY", "trackDcaXY", {HistType::kTH1F, {{40, -10, 10}}}}, + {"trackItsChi2NCl", "trackItsChi2NCl", {HistType::kTH1F, {{60, 0, 30}}}}, + {"trackTpcChi2NCl", "trackTpcChi2NCl", {HistType::kTH1F, {{100, 0, 50}}}}, + {"trackTpcNClsFound", "trackTpcNClsFound", {HistType::kTH1F, {{100, 0, 200}}}}, + {"trackItsNCls", "trackItsNCls", {HistType::kTH1F, {{10, 0, 10}}}}, + {"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}}}}, + {"event/vertexz", ";Vtx_{z} (cm);Entries", {HistType::kTH1F, {{100, -20, 20}}}}, + {"eventCounter", "eventCounter", {HistType::kTH1F, {{1, 0, +1, ""}}}}, + {"ptVsCentrality", "ptvscentrality", {HistType::kTH2F, {{100, 0, 100}, {300, 0, 300}}}}, + {"ptResolution", "ptResolution", {HistType::kTH2F, {{nBinsPt, 0, ptMax}, {100, -1.0, +1.0}}}}, + {"mcCentralityReco", "mcCentralityReco", {HistType::kTH1F, {{100, 0, 100}}}}, + {"mcCentralitySim", "mcCentralitySim", {HistType::kTH1F, {{100, 0, 100}}}}, + {"ptHistogramPion", "ptHistogramPion", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}, + {"ptHistogramKaon", "ptHistogramKaon", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}, + {"ptHistogramProton", "ptHistogramProton", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}, + {"ptHistogramPionTof", "ptHistogramPionTof", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}, + {"ptHistogramKaonTof", "ptHistogramKaonTof", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}, + {"ptHistogramProtonTof", "ptHistogramProtonTof", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}, + {"ptGeneratedPion", "ptGeneratedPion", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}, + {"ptGeneratedKaon", "ptGeneratedKaon", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}, + {"ptGeneratedProton", "ptGeneratedProton", {HistType::kTH1F, {{nBinsPt, 0, ptMax}}}}}}; + + 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 etaTrUp{"etaTrUp", 0.7f, "maximum track eta"}; + Configurable dcaxyMax{"dcaxyMax", 2.0f, "mximum DCA xy"}; + Configurable chi2ItsMax{"chi2ItsMax", 15.0f, "its chi2 cut"}; + 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", 70.0f, "tpc # of crossedRows cut"}; + Configurable mcRapidityMax{"mcRapidityMax", 0.5f, "maximum mctrack y"}; + + 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 JetAreaFractionMinValue = -98.0; + if (jetAreaFractionMin > JetAreaFractionMinValue) { + 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 LeadingConstituentPtMinValue = 5.0; + static constexpr double LeadingConstituentPtMaxValue = 9998.0; + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > LeadingConstituentPtMinValue); + bool checkConstituentMaxPt = (leadingConstituentPtMax < LeadingConstituentPtMaxValue); + 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) + { + + std::vector ptDensity(distanceCategory->size() - 1, 0.f); + std::vector ptDensityBg1(distanceCategory->size() - 1, 0.f); + std::vector ptDensityBg2(distanceCategory->size() - 1, 0.f); + + 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.centFT0M(), track.pt()); + + // calculate compornents of jetshapefunction rho(r) + std::vector trackPtSum(distanceCategory->size() - 1, 0.f); + std::vector trackPtSumBg1(distanceCategory->size() - 1, 0.f); + std::vector trackPtSumBg2(distanceCategory->size() - 1, 0.f); + + 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, -o2::constants::math::PI); + float deltaPhiBg2 = RecoDecay::constrainAngle(preDeltaPhiBg2, -o2::constants::math::PI); + + 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 (distanceCategory->at(i) <= distance && distance < distanceCategory->at(i + 1)) + trackPtSum[i] += track.pt(); + if (distanceCategory->at(i) <= distanceBg1 && distanceBg1 < distanceCategory->at(i + 1)) + trackPtSumBg1[i] += track.pt(); + if (distanceCategory->at(i) <= distanceBg2 && 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("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]; + double jetShapeFunctionBg1 = ptDensityBg1[i]; + double jetShapeFunctionBg2 = ptDensityBg2[i]; + registry.fill(HIST("ptSum"), jetX, jetShapeFunction); + registry.fill(HIST("ptSumBg1"), jetX, jetShapeFunctionBg1); + registry.fill(HIST("ptSumBg2"), jetX, jetShapeFunctionBg2); + } + } + } + PROCESS_SWITCH(JetShapeTask, processJetShape, "JetShape", false); + + void processProductionRatio(soa::Filtered::iterator const& collision, soa::Join const& tracks, soa::Join const& jets) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + registry.fill(HIST("event/vertexz"), collision.posZ()); + + for (auto const& jet : jets) { + if (!isAcceptedJet(jet)) { + continue; + } + + registry.fill(HIST("jetPt"), jet.pt()); + registry.fill(HIST("jetEta"), jet.eta()); + registry.fill(HIST("jetPhi"), jet.phi()); + + // tracks conditions + for (const auto& track : tracks) { + registry.fill(HIST("trackTpcNClsCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("trackDcaXY"), track.dcaXY()); + registry.fill(HIST("trackItsChi2NCl"), track.itsChi2NCl()); + registry.fill(HIST("trackTpcChi2NCl"), track.tpcChi2NCl()); + registry.fill(HIST("trackTpcNClsFound"), track.tpcNClsFound()); + registry.fill(HIST("trackItsNCls"), track.itsNCls()); + registry.fill(HIST("trackEta"), track.eta()); + registry.fill(HIST("trackPhi"), track.phi()); + + 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; + + // PID check + registry.fill(HIST("tofMass"), track.mass()); + registry.fill(HIST("tpcPi"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("tofPi"), track.pt(), track.tofNSigmaPi()); + registry.fill(HIST("tpcPr"), track.p(), 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); + + // Define perpendicular cone axes in phi + float phiBg1 = jet.phi() + (o2::constants::math::PIHalf); + float phiBg2 = jet.phi() - (o2::constants::math::PIHalf); + + // Calculate delta phi for background cones + float preDeltaPhiBg1 = track.phi() - phiBg1; + float preDeltaPhiBg2 = track.phi() - phiBg2; + float deltaPhiBg1 = RecoDecay::constrainAngle(preDeltaPhiBg1, -o2::constants::math::PI); + float deltaPhiBg2 = RecoDecay::constrainAngle(preDeltaPhiBg2, -o2::constants::math::PI); + + // Calculate distance to background cone axes + float distanceBg1 = std::sqrt(deltaEta * deltaEta + deltaPhiBg1 * deltaPhiBg1); + float distanceBg2 = std::sqrt(deltaEta * deltaEta + deltaPhiBg2 * deltaPhiBg2); + + // Fill histogram if track is inside one of the perpendicular cones + if (distanceBg1 < jetR || distanceBg2 < jetR) { + registry.fill(HIST("tpcDedxOutOfJet"), track.p(), track.tpcSignal()); + + if (std::abs(track.tofNSigmaPi()) < nSigmaTofCut) { + registry.fill(HIST("tpcTofPiOutOfJet"), track.p(), track.tpcNSigmaPi(), jet.pt(), collision.centFT0M()); + if (track.tpcNSigmaPi() > tpcNSigmaPiMin && track.tpcNSigmaPi() < tpcNSigmaPiMax) { + registry.fill(HIST("pVsPtForPiOutOfJet"), track.p(), track.pt(), jet.pt(), collision.centFT0M()); + } + } + if (std::abs(track.tofNSigmaPr()) < nSigmaTofCut) { + registry.fill(HIST("tpcTofPrOutOfJet"), track.p(), track.tpcNSigmaPr(), jet.pt(), collision.centFT0M()); + if (track.tpcNSigmaPr() > tpcNSigmaPrMin && track.tpcNSigmaPr() < tpcNSigmaPrMax) { + registry.fill(HIST("pVsPtForPrOutOfJet"), track.p(), track.pt(), jet.pt(), collision.centFT0M()); + } + } + } + + registry.fill(HIST("distanceVsTrackpt"), distance, track.pt()); + registry.fill(HIST("tpcDedx"), track.p(), track.tpcSignal(), distance); + registry.fill(HIST("tofBeta"), track.p(), track.beta()); + + if (std::abs(track.tofNSigmaPr()) < nSigmaTofCut) { + registry.fill(HIST("tpcTofPr"), track.p(), track.tpcNSigmaPr(), distance, jet.pt(), collision.centFT0M()); + if (track.tpcNSigmaPr() > tpcNSigmaPrMin && track.tpcNSigmaPr() < tpcNSigmaPrMax) { + registry.fill(HIST("pVsPtForPr"), track.p(), track.pt(), distance, jet.pt(), collision.centFT0M()); + } + } + + if (std::abs(track.tofNSigmaPi()) < nSigmaTofCut) { + registry.fill(HIST("tpcTofPi"), track.p(), track.tpcNSigmaPi(), distance, jet.pt(), collision.centFT0M()); + if (track.tpcNSigmaPi() > tpcNSigmaPiMin && track.tpcNSigmaPi() < tpcNSigmaPiMax) { + registry.fill(HIST("pVsPtForPi"), track.p(), track.pt(), distance, jet.pt(), collision.centFT0M()); + } + } + } + } + } + PROCESS_SWITCH(JetShapeTask, processProductionRatio, "production ratio", false); + + void processReco(soa::Join const& tracks, aod::McParticles const&) + { + registry.fill(HIST("eventCounter"), 0.5); + + for (const auto& track : tracks) { + if (track.has_mcParticle()) { + auto mcParticle = track.mcParticle(); + registry.fill(HIST("ptResolution"), track.pt(), track.pt() - mcParticle.pt()); + + 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 (mcParticle.isPhysicalPrimary() && std::fabs(mcParticle.y()) < mcRapidityMax) { + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus) + registry.fill(HIST("ptHistogramPion"), mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus) + registry.fill(HIST("ptHistogramKaon"), mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kProton) + registry.fill(HIST("ptHistogramProton"), mcParticle.pt()); + } + + if (track.hasTOF()) { + if (mcParticle.isPhysicalPrimary() && std::fabs(mcParticle.y()) < mcRapidityMax) { + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus) + registry.fill(HIST("ptHistogramPionTof"), mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus) + registry.fill(HIST("ptHistogramKaonTof"), mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kProton) + registry.fill(HIST("ptHistogramProtonTof"), mcParticle.pt()); + } + } + } + } + } + PROCESS_SWITCH(JetShapeTask, processReco, "process reconstructed information", true); + + void processSim(soa::Join::iterator const& mcCollision, aod::McParticles const& mcParticles) + { + + registry.fill(HIST("mcCentralitySim"), mcCollision.centFT0M()); + + for (const auto& mcParticle : mcParticles) { + + if (mcParticle.isPhysicalPrimary() && std::fabs(mcParticle.y()) < mcRapidityMax) { + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus) + registry.fill(HIST("ptGeneratedPion"), mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus) + registry.fill(HIST("ptGeneratedKaon"), mcParticle.pt()); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kProton) + registry.fill(HIST("ptGeneratedProton"), mcParticle.pt()); + } + } + } + PROCESS_SWITCH(JetShapeTask, processSim, "process pure simulation information", 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..6a2fbe52ed6 --- /dev/null +++ b/PWGJE/Tasks/jetSpectraCharged.cxx @@ -0,0 +1,1351 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 , Joonsuk Bae + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct JetSpectraCharged { + + using JetBkgRhoMcCollisions = soa::Join; + using ChargedMCDMatchedJets = soa::Join; + using ChargedMCPMatchedJets = 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 checkCentFT0M{"checkCentFT0M", false, "0: centFT0C as default, 1: use centFT0M estimator"}; + 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; + + bool doSumw2 = false; + + float configSwitchLow = -98.0; + float configSwitchHigh = 9998.0; + enum AcceptSplitCollisionsOptions { + NonSplitOnly = 0, + SplitOkCheckAnyAssocColl, // 1 + SplitOkCheckFirstAssocCollOnly // 2 + }; + + void init(o2::framework::InitContext&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + doSumw2 = skipMBGapEvents; + + 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 (doprocessTracksQC || doprocessTracksQCWeighted) { + registry.add("h_track_pt", "track #it{p}_{T} ; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH1F, {trackPtAxis}}, doSumw2); + registry.add("h2_track_eta_track_phi", "track eta vs. track phi; #eta; #phi; counts", {HistType::kTH2F, {trackEtaAxis, phiAxis}}, doSumw2); + } + + if (doprocessCollisions || doprocessCollisionsWeighted) { + registry.add("h_collisions", "number of events;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}, doSumw2); + registry.get(HIST("h_collisions"))->GetXaxis()->SetBinLabel(1, "allColl"); + registry.get(HIST("h_collisions"))->GetXaxis()->SetBinLabel(2, "qualitySel"); + registry.get(HIST("h_collisions"))->GetXaxis()->SetBinLabel(3, "centralitycut"); + registry.get(HIST("h_collisions"))->GetXaxis()->SetBinLabel(4, "occupancycut"); + if (doprocessCollisionsWeighted) { + registry.add("h_collisions_weighted", "number of events;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}, doSumw2); + registry.get(HIST("h_collisions_weighted"))->GetXaxis()->SetBinLabel(1, "allColl"); + registry.get(HIST("h_collisions_weighted"))->GetXaxis()->SetBinLabel(2, "qualitySel"); + registry.get(HIST("h_collisions_weighted"))->GetXaxis()->SetBinLabel(3, "centralitycut"); + registry.get(HIST("h_collisions_weighted"))->GetXaxis()->SetBinLabel(4, "occupancycut"); + if (doprocessSpectraMCDWeighted) { + registry.add("h_coll_phat", "collision #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}, doSumw2); + registry.add("h_coll_phat_weighted", "collision #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}, doSumw2); + } + } + registry.add("h_collisions_zvertex", "position of collision ;#it{Z} (cm)", {HistType::kTH1F, {{300, -15.0, 15.0}}}, doSumw2); + registry.add("h_fakecollisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}, doSumw2); // is not filled if running on data + registry.add("h2_centrality_collisions", "event status vs. centrality;entries;centrality", {HistType::kTH2F, {centralityAxis, {4, 0.0, 4.0}}}, doSumw2); + registry.add("h2_centrality_occupancy", "centrality vs occupancy; centrality; occupancy", {HistType::kTH2F, {centralityAxis, {60, 0, 30000}}}, doSumw2); + } + if (doprocessMCCollisions || doprocessMCCollisionsWeighted) { + registry.add("h_mccollisions", "number of mc events; event status; entries", {HistType::kTH1F, {{10, 0.0, 10}}}, doSumw2); + registry.get(HIST("h_mccollisions"))->GetXaxis()->SetBinLabel(1, "allMcColl"); + registry.get(HIST("h_mccollisions"))->GetXaxis()->SetBinLabel(2, "noRecoColl"); + registry.get(HIST("h_mccollisions"))->GetXaxis()->SetBinLabel(3, "splitColl"); + registry.get(HIST("h_mccollisions"))->GetXaxis()->SetBinLabel(4, "recoEvtSel"); + registry.get(HIST("h_mccollisions"))->GetXaxis()->SetBinLabel(5, "centralitycut"); + registry.get(HIST("h_mccollisions"))->GetXaxis()->SetBinLabel(6, "occupancycut"); + if (doprocessMCCollisionsWeighted) { + registry.add("h_mccollisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{10, 0.0, 10.0}}}, doSumw2); + registry.get(HIST("h_mccollisions_weighted"))->GetXaxis()->SetBinLabel(1, "allMcColl"); + registry.get(HIST("h_mccollisions_weighted"))->GetXaxis()->SetBinLabel(2, "noRecoColl"); + registry.get(HIST("h_mccollisions_weighted"))->GetXaxis()->SetBinLabel(3, "splitColl"); + registry.get(HIST("h_mccollisions_weighted"))->GetXaxis()->SetBinLabel(4, "recoEvtSel"); + registry.get(HIST("h_mccollisions_weighted"))->GetXaxis()->SetBinLabel(5, "centralitycut"); + registry.get(HIST("h_mccollisions_weighted"))->GetXaxis()->SetBinLabel(6, "occupancycut"); + registry.add("h_mccoll_phat", "mc collision #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}, doSumw2); + registry.add("h_mccoll_phat_weighted", "mc collision #hat{p};#hat{p} (GeV/#it{c});entries", {HistType::kTH1F, {{1000, 0, 1000}}}, doSumw2); + } + registry.add("h2_centrality_mccollisions", "mc event status vs. centrality;entries;centrality", {HistType::kTH2F, {centralityAxis, {4, 0.0, 4.0}}}, doSumw2); + } + if (doprocessSpectraMCP || doprocessSpectraMCPWeighted || doprocessMCCollisions || doprocessMCCollisionsWeighted) { + registry.add("h_mccollisions_zvertex", "position of mc collision ;#it{Z} (cm)", {HistType::kTH1F, {{300, -15.0, 15.0}}}, doSumw2); + } + + if (doprocessSpectraData || doprocessSpectraMCD || doprocessSpectraMCDWeighted) { + registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxis}}, doSumw2); + registry.add("h_jet_eta", "jet eta;#eta; counts", {HistType::kTH1F, {jetEtaAxis}}, doSumw2); + registry.add("h_jet_phi", "jet phi;#phi; counts", {HistType::kTH1F, {phiAxis}}, doSumw2); + registry.add("h2_centrality_jet_pt", "centrality vs. jet pT;centrality; #it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH2F, {centralityAxis, jetPtAxis}}, doSumw2); + registry.add("h2_centrality_jet_eta", "centrality vs. jet eta;centrality; #eta; counts", {HistType::kTH2F, {centralityAxis, jetEtaAxis}}, doSumw2); + registry.add("h2_centrality_jet_phi", "centrality vs. jet phi;centrality; #varphi; counts", {HistType::kTH2F, {centralityAxis, phiAxis}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}, doSumw2); + registry.add("h3_jet_pt_jet_eta_jet_phi", "jet pt vs. eta vs. phi", {HistType::kTH3F, {jetPtAxis, jetEtaAxis, phiAxis}}, doSumw2); + } + + if (doprocessSpectraAreaSubData || doprocessSpectraAreaSubMCD || doprocessSpectraAreaSubMCDWeighted) { + registry.add("h_jet_pt_rhoareasubtracted", "jet pT;#it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}, doSumw2); + registry.add("h_jet_eta_rhoareasubtracted", "jet eta;#eta; counts", {HistType::kTH1F, {jetEtaAxis}}, doSumw2); + registry.add("h_jet_phi_rhoareasubtracted", "jet phi;#phi; counts", {HistType::kTH1F, {phiAxis}}, doSumw2); + registry.add("h2_centrality_jet_pt_rhoareasubtracted", "centrality vs. jet pT;centrality; #it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH2F, {centralityAxis, jetPtAxisRhoAreaSub}}, doSumw2); + registry.add("h2_centrality_jet_eta_rhoareasubtracted", "centrality vs. jet eta;centrality; #eta; counts", {HistType::kTH2F, {centralityAxis, jetEtaAxis}}, doSumw2); + registry.add("h2_centrality_jet_phi_rhoareasubtracted", "centrality vs. jet phi;centrality; #varphi; counts", {HistType::kTH2F, {centralityAxis, phiAxis}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + registry.add("h3_jet_pt_jet_eta_jet_phi_rhoareasubtracted", "jet_pt_eta_phi_rhoareasubtracted", {HistType::kTH3F, {jetPtAxisRhoAreaSub, jetEtaAxis, phiAxis}}, doSumw2); + } + + if (doprocessSpectraMCP || doprocessSpectraMCPWeighted) { + registry.add("h_jet_pt_part", "partvjet pT;#it{p}_{T,jet}^{part} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxis}}, doSumw2); + registry.add("h_jet_eta_part", "part jet #eta;#eta^{part}; counts", {HistType::kTH1F, {jetEtaAxis}}, doSumw2); + registry.add("h_jet_phi_part", "part jet #varphi;#phi^{part}; counts", {HistType::kTH1F, {phiAxis}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}, doSumw2); + registry.add("h3_jet_pt_jet_eta_jet_phi_part", "part jet pt vs. eta vs. phi", {HistType::kTH3F, {jetPtAxis, jetEtaAxis, phiAxis}}, doSumw2); + if (doprocessSpectraMCPWeighted) { + 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}}}, doSumw2); + } + } + + if (doprocessCrossSectionEfficiency || doprocessCrossSectionEfficiencyWeighted) { + AxisSpec eventSelectionAxis = {7, 0.5, 7.5, "event selection"}; + registry.add("h2_jet_pt_part_eventselection", "part jet pT vs event selection;#it{p}_{T,jet}^{part} (GeV/#it{c});event selection;counts", {HistType::kTH2F, {jetPtAxis, eventSelectionAxis}}, doSumw2); + registry.get(HIST("h2_jet_pt_part_eventselection"))->GetYaxis()->SetBinLabel(1, "INEL"); + registry.get(HIST("h2_jet_pt_part_eventselection"))->GetYaxis()->SetBinLabel(2, "zvtx"); + registry.get(HIST("h2_jet_pt_part_eventselection"))->GetYaxis()->SetBinLabel(3, "noRecoColl"); + registry.get(HIST("h2_jet_pt_part_eventselection"))->GetYaxis()->SetBinLabel(4, "splitColl"); + registry.get(HIST("h2_jet_pt_part_eventselection"))->GetYaxis()->SetBinLabel(5, "recoEvtSel"); + registry.get(HIST("h2_jet_pt_part_eventselection"))->GetYaxis()->SetBinLabel(6, "centralitycut"); + registry.get(HIST("h2_jet_pt_part_eventselection"))->GetYaxis()->SetBinLabel(7, "occupancycut"); + } + + if (doprocessSpectraAreaSubMCP || doprocessSpectraAreaSubMCPWeighted) { + registry.add("h_mccollisions_rho", "mc collision rho;#rho (GeV/#it{c}); counts", {HistType::kTH1F, {{500, 0.0, 500.0}}}, doSumw2); + registry.add("h_jet_pt_part_rhoareasubtracted", "part jet corr pT;#it{p}_{T,jet}^{part} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxisRhoAreaSub}}, doSumw2); + registry.add("h_jet_eta_part_rhoareasubtracted", "part jet #eta;#eta^{part}; counts", {HistType::kTH1F, {jetEtaAxis}}, doSumw2); + registry.add("h_jet_phi_part_rhoareasubtracted", "part jet #varphi;#varphi^{part}; counts", {HistType::kTH1F, {phiAxis}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + registry.add("h3_jet_pt_jet_eta_jet_phi_part_rhoareasubtracted", "part jet pt vs. eta vs.phi", {HistType::kTH3F, {jetPtAxisRhoAreaSub, jetEtaAxis, phiAxis}}, doSumw2); + } + + 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}}, doSumw2); + registry.add("jet_observables_eventwiseconstituentsubtracted", "jet_observables_eventwiseconstituentsubtracted", HistType::kTHnSparseF, {jetPtAxis, jetEtaAxis, phiAxis}, doSumw2); + } + + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + } + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + } + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + } + } + + if (doprocessJetsMatchedAreaSub || doprocessJetsMatchedAreaSubWeighted) { + 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}}, doSumw2); + 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}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + 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}}}, doSumw2); + } + + if (!(acceptSplitCollisions == NonSplitOnly || acceptSplitCollisions == SplitOkCheckAnyAssocColl || acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly)) { + LOGF(fatal, "Configurable acceptSplitCollisions has wrong input value; stopping workflow"); + } + } + + 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 mcEventCuts = (nabs(aod::jmccollision::posZ) < vertexZCut); + + template + bool isAcceptedJet(TJets const& jet, bool mcLevelIsParticleLevel = false) + { + if (jetAreaFractionMin > configSwitchLow) { + if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > configSwitchLow); + bool checkConstituentMaxPt = (leadingConstituentPtMax < configSwitchHigh); + 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 + bool applyMCCollisionCuts(TMCColl const& mccollision, TCollisions const& collisions, bool fillHistograms = false, bool isWeighted = false, float eventWeight = 1.0) + { + float centrality = -1.0; + // checkCentFT0M ? centrality = mccollision.centFT0M() : centrality = mccollision.centFT0C(); + centrality = mccollision.centFT0M(); + + if (fillHistograms) { + registry.fill(HIST("h_mccollisions"), 0.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 0.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_mccollisions_weighted"), 0.5, eventWeight); + } + + if (collisions.size() < 1) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_mccollisions"), 1.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 1.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_mccollisions_weighted"), 1.5, eventWeight); + } + + if (acceptSplitCollisions == NonSplitOnly && collisions.size() > 1) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_mccollisions"), 2.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 2.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_mccollisions_weighted"), 2.5, eventWeight); + } + + bool hasSel8Coll = false; + bool centralityIsGood = false; + bool occupancyIsGood = false; + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly) { + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + + if ((centralityMin < centrality) && (centrality < centralityMax)) { + centralityIsGood = true; + } + } else { + for (auto const& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + if ((centralityMin < centrality) && (centrality < centralityMax)) { + centralityIsGood = true; + } + } + } + + if (!hasSel8Coll) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_mccollisions"), 3.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 3.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_mccollisions_weighted"), 3.5, eventWeight); + } + + if (!centralityIsGood) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_mccollisions"), 4.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 4.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_mccollisions_weighted"), 4.5, eventWeight); + } + + if (!occupancyIsGood) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_mccollisions"), 5.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 5.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_mccollisions_weighted"), 5.5, eventWeight); + } + + return true; + } + + template + bool applyCollisionCuts(TColl const& collision, bool fillHistograms = false, bool isWeighted = false, float eventWeight = 1.0) + { + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + if (fillHistograms) { + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 0.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_collisions_weighted"), 0.5, eventWeight); + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 1.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_collisions_weighted"), 1.5, eventWeight); + } + + if (centrality < centralityMin || centralityMax < centrality) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 2.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_collisions_weighted"), 2.5, eventWeight); + } + + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return false; + } + if (fillHistograms) { + registry.fill(HIST("h_collisions"), 3.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 3.5, eventWeight); + if (isWeighted) + registry.fill(HIST("h_collisions_weighted"), 3.5, eventWeight); + } + + 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 = jetMCD.pt() - jetMCP.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 = jetMCD.pt() - jetMCP.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 = jetMCD.pt() - jetMCP.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 fillGeoMatchedAreaSubHistograms(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 = corrBasejetpt - corrTagjetpt; + 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 processTracksQC(soa::Filtered::iterator const& collision, + soa::Filtered> const& tracks) + { + if (!applyCollisionCuts(collision)) { + return; + } + + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + fillTrackHistograms(track); + } + } + PROCESS_SWITCH(JetSpectraCharged, processTracksQC, "collisions and track QC for Data and MCD", false); + + void processTracksQCWeighted(soa::Filtered>::iterator const& collision, + aod::JetMcCollisions const&, + soa::Filtered> const& tracks) + { + bool fillHistograms = false; + bool isWeighted = true; + float eventWeight = collision.weight(); + if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { + return; + } + + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { + continue; + } + fillTrackHistograms(track, eventWeight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processTracksQCWeighted, "weighted collsions and tracks QC for MC", false); + + void processCollisions(soa::Filtered::iterator const& collision) + { + bool fillHistograms = true; + bool isWeighted = false; + if (!applyCollisionCuts(collision, fillHistograms, isWeighted)) { + return; + } + + registry.fill(HIST("h_collisions_zvertex"), collision.posZ()); + } + PROCESS_SWITCH(JetSpectraCharged, processCollisions, "collisions Data and MCD", true); + + void processCollisionsWeighted(soa::Filtered>::iterator const& collision, + aod::JetMcCollisions const&) + { + if (!collision.has_mcCollision()) { + registry.fill(HIST("h_fakecollisions"), 0.5); + } + bool fillHistograms = true; + bool isWeighted = true; + float eventWeight = collision.weight(); + if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { + return; + } + + registry.fill(HIST("h_collisions_zvertex"), collision.posZ(), eventWeight); + + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + registry.fill(HIST("h_coll_phat"), pTHat); + registry.fill(HIST("h_coll_phat_weighted"), pTHat, eventWeight); + } + PROCESS_SWITCH(JetSpectraCharged, processCollisionsWeighted, "weighted collisions for MCD", false); + + void processMCCollisions(soa::Filtered::iterator const& mccollision, soa::SmallGroups const& collisions) + { + bool fillHistograms = true; + bool isWeighted = false; + if (!applyMCCollisionCuts(mccollision, collisions, fillHistograms, isWeighted)) { + return; + } + + registry.fill(HIST("h_mccollisions_zvertex"), mccollision.posZ()); + } + PROCESS_SWITCH(JetSpectraCharged, processMCCollisions, "collisions MCP", false); + + void processMCCollisionsWeighted(soa::Filtered::iterator const& mccollision, soa::SmallGroups const& collisions) + { + bool fillHistograms = true; + bool isWeighted = true; + float eventWeight = mccollision.weight(); + if (!applyMCCollisionCuts(mccollision, collisions, fillHistograms, isWeighted, eventWeight)) { + return; + } + + registry.fill(HIST("h_mccollisions_zvertex"), mccollision.posZ(), eventWeight); + + float pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + registry.fill(HIST("h_mccoll_phat"), pTHat); + registry.fill(HIST("h_mccoll_phat_weighted"), pTHat, eventWeight); + } + PROCESS_SWITCH(JetSpectraCharged, processMCCollisionsWeighted, "weighted collisions for MCP", false); + + void processSpectraData(soa::Filtered::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + if (!applyCollisionCuts(collision)) { + return; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetHistograms(jet, 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 (!applyCollisionCuts(collision)) { + return; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetHistograms(jet, 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 (!applyCollisionCuts(collision)) { + return; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetAreaSubHistograms(jet, 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 (!applyCollisionCuts(collision)) { + return; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetAreaSubHistograms(jet, 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&) + { + bool fillHistograms = false; + bool isWeighted = true; + float eventWeight = collision.weight(); + if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { + return; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetHistograms(jet, centrality, eventWeight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraMCDWeighted, "jet finder QA mcd with weighted events", false); + + void processSpectraAreaSubMCDWeighted(soa::Filtered>::iterator const& collision, + soa::Join const& jets, + aod::JetTracks const&) + { + bool fillHistograms = false; + bool isWeighted = true; + float eventWeight = collision.weight(); + if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { + return; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillJetAreaSubHistograms(jet, centrality, collision.rho(), eventWeight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraAreaSubMCDWeighted, "jet spectra with rho-area subtraction for MCD", false); + + void processSpectraMCP(soa::Filtered::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + + if (!applyMCCollisionCuts(mccollision, collisions)) { + return; + } + registry.fill(HIST("h_mccollisions_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 processCrossSectionEfficiency(aod::JetMcCollisions::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + + bool hasRecoColl = (collisions.size() >= 1); + bool passesZvtxCut = (std::abs(mccollision.posZ()) <= vertexZCut); + bool passesSplitCollCut = !(acceptSplitCollisions == NonSplitOnly && collisions.size() > 1); + + bool hasSel8Coll = false; + bool centralityIsGood = false; + bool occupancyIsGood = false; + float centrality = mccollision.centFT0M(); + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly) { + if (hasRecoColl && jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if (hasRecoColl && (trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + if ((centralityMin < centrality) && (centrality < centralityMax)) { + centralityIsGood = true; + } + } else { + for (auto const& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + if ((centralityMin < centrality) && (centrality < centralityMax)) { + centralityIsGood = true; + } + } + } + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 1.0); // INEL + + if (!passesZvtxCut) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 2.0); // zvtx + + if (!hasRecoColl) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 3.0); // noRecoColl + + if (!passesSplitCollCut) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 4.0); // splitColl + + if (!hasSel8Coll) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 5.0); // recoEvtSel + + if (!centralityIsGood) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 6.0); // centralitycut + + if (!occupancyIsGood) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 7.0); // occupancycut + } + } + PROCESS_SWITCH(JetSpectraCharged, processCrossSectionEfficiency, "jet spectra QC for MC particle level with step-by-step cuts", false); + + void processCrossSectionEfficiencyWeighted(aod::JetMcCollisions::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + + bool hasRecoColl = (collisions.size() >= 1); + bool passesZvtxCut = (std::abs(mccollision.posZ()) <= vertexZCut); + bool passesSplitCollCut = !(acceptSplitCollisions == NonSplitOnly && collisions.size() > 1); + + bool hasSel8Coll = false; + bool centralityIsGood = false; + bool occupancyIsGood = false; + float centrality = mccollision.centFT0M(); + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly) { + if (hasRecoColl && jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if (hasRecoColl && (trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + if ((centralityMin < centrality) && (centrality < centralityMax)) { + centralityIsGood = true; + } + } else { + for (auto const& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + hasSel8Coll = true; + } + if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { + occupancyIsGood = true; + } + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + if ((centralityMin < centrality) && (centrality < centralityMax)) { + centralityIsGood = true; + } + } + } + + float eventWeight = mccollision.weight(); + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 1.0, eventWeight); // INEL + + if (!passesZvtxCut) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 2.0, eventWeight); // zvtx + + if (!hasRecoColl) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 3.0, eventWeight); // noRecoColl + + if (!passesSplitCollCut) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 4.0, eventWeight); // splitColl + + if (!hasSel8Coll) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 5.0, eventWeight); // recoEvtSel + + if (!centralityIsGood) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 6.0, eventWeight); // centralitycut + + if (!occupancyIsGood) { + continue; + } + registry.fill(HIST("h2_jet_pt_part_eventselection"), jet.pt(), 7.0, eventWeight); // occupancycut + } + } + PROCESS_SWITCH(JetSpectraCharged, processCrossSectionEfficiencyWeighted, "jet spectra QC for MC particle level with step-by-step cuts (weighted)", false); + + void processSpectraAreaSubMCP(soa::Filtered::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + + if (!applyMCCollisionCuts(mccollision, collisions)) { + return; + } + registry.fill(HIST("h_mccollisions_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 processSpectraMCPWeighted(soa::Filtered::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + + bool fillHistograms = false; + bool isWeighted = true; + float eventWeight = mccollision.weight(); + if (!applyMCCollisionCuts(mccollision, collisions, fillHistograms, isWeighted, eventWeight)) { + return; + } + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { + continue; + } + double pTHat = 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + int Nmax = 21; + for (int N = 1; N < Nmax; 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, eventWeight); + } + } + fillMCPHistograms(jet, eventWeight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraMCPWeighted, "jet spectra for MC particle level weighted", false); + + void processSpectraAreaSubMCPWeighted(soa::Filtered::iterator const& mccollision, + soa::SmallGroups const& collisions, + soa::Join const& jets, + aod::JetParticles const&) + { + bool mcLevelIsParticleLevel = true; + + bool fillHistograms = false; + bool isWeighted = true; + float eventWeight = mccollision.weight(); + if (!applyMCCollisionCuts(mccollision, collisions, fillHistograms, isWeighted, eventWeight)) { + return; + } + registry.fill(HIST("h_mccollisions_rho"), mccollision.rho(), eventWeight); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { + continue; + } + fillMCPAreaSubHistograms(jet, mccollision.rho(), eventWeight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processSpectraAreaSubMCPWeighted, "jet spectra with area-based subtraction for MC particle level", false); + + void processEvtWiseConstSubJetsData(soa::Filtered::iterator const& collision, + soa::Join const& jets, + aod::JetTracksSub const&) + { + if (!applyCollisionCuts(collision)) { + return; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillEventWiseConstituentSubtractedHistograms(jet, 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 (!applyCollisionCuts(collision)) { + return; + } + + float centrality = -1.0; + checkCentFT0M ? centrality = collision.centFT0M() : centrality = collision.centFT0C(); + + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillEventWiseConstituentSubtractedHistograms(jet, 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 (!applyCollisionCuts(collision)) { + 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, + ChargedMCDMatchedJets const& mcdjets, + ChargedMCPMatchedJets const&, + aod::JetTracks const&, aod::JetParticles const&) + { + bool fillHistograms = false; + bool isWeighted = true; + float eventWeight = collision.weight(); + if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { + return; + } + + for (const auto& mcdjet : mcdjets) { + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillMatchedHistograms(mcdjet, eventWeight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processJetsMatchedWeighted, "matched mcp and mcd jets with weighted events", false); + + void processJetsMatchedAreaSub(soa::Filtered>::iterator const& collision, + JetBkgRhoMcCollisions const&, + ChargedMCDMatchedJets const& mcdjets, + ChargedMCPMatchedJets const&, + aod::JetTracks const&, aod::JetParticles const&) + { + if (!applyCollisionCuts(collision)) { + return; + } + + double mcrho = collision.has_mcCollision() ? collision.mcCollision_as().rho() : -1; + + for (const auto& mcdjet : mcdjets) { + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillGeoMatchedAreaSubHistograms(mcdjet, collision.rho(), mcrho); + } + } + PROCESS_SWITCH(JetSpectraCharged, processJetsMatchedAreaSub, "matched mcp and mcd jets after area-based pt subtraction", false); + + void processJetsMatchedAreaSubWeighted(soa::Filtered>::iterator const& collision, + JetBkgRhoMcCollisions const&, + ChargedMCDMatchedJets const& mcdjets, + ChargedMCPMatchedJets const&, + aod::JetTracks const&, aod::JetParticles const&) + { + bool fillHistograms = false; + bool isWeighted = true; + float eventWeight = collision.weight(); + if (!applyCollisionCuts(collision, fillHistograms, isWeighted, eventWeight)) { + return; + } + + double mcrho = collision.has_mcCollision() ? collision.mcCollision_as().rho() : -1; + + for (const auto& mcdjet : mcdjets) { + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillGeoMatchedAreaSubHistograms(mcdjet, collision.rho(), mcrho, eventWeight); + } + } + PROCESS_SWITCH(JetSpectraCharged, processJetsMatchedAreaSubWeighted, "matched mcp and mcd jets after area-based pt subtraction with weighted events", 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..7c64a6d5f44 --- /dev/null +++ b/PWGJE/Tasks/jetSpectraEseTask.cxx @@ -0,0 +1,992 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EseTable.h" +#include "Common/DataModel/Qvectors.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#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 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.centFT0CVariant1() : collision.centFT0M(); + 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.centFT0M(), 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.centFT0M(), track.pt(), qPerc[0], occupancy); + if (track.pt() < cfgOccupancyPtCut->at(0) || track.pt() > cfgOccupancyPtCut->at(1)) + continue; + registry.fill(HIST("hTrackEta"), collision.centFT0M(), track.eta(), occupancy); + registry.fill(HIST("hTrackPhi"), collision.centFT0M(), 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.centFT0M(); + 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.centFT0M() : -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.centFT0M() : -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](const 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.centFT0M(), Corr[0], col.qPERCFT0C()[0]); + registry.fill(HIST("hCosPsi2AmB"), col.centFT0M(), Corr[1], col.qPERCFT0C()[0]); + registry.fill(HIST("hCosPsi2BmC"), col.centFT0M(), 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.centFT0M(), epMap.at("FT0A")); + registry.fill(HIST("hPsi2FV0A"), col.centFT0M(), epMap.at("FV0A")); + registry.fill(HIST("hPsi2FT0C"), col.centFT0M(), epMap.at("FT0C")); + registry.fill(HIST("hPsi2TPCpos"), col.centFT0M(), epMap.at("TPCpos")); + registry.fill(HIST("hPsi2TPCneg"), col.centFT0M(), 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.centFT0M(), collision.qvecRe()[detInd], collision.qvecIm()[detInd]); + registry.fill(HIST("hQvecRectrV2"), collision.centFT0M(), collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1]); + registry.fill(HIST("hQvecTwistV2"), collision.centFT0M(), collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2]); + registry.fill(HIST("hQvecFinalV2"), collision.centFT0M(), collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3]); + registry.fill(HIST("hEPUncorV2"), collision.centFT0M(), 0.5 * std::atan2(collision.qvecIm()[detInd], collision.qvecRe()[detInd])); + registry.fill(HIST("hEPRectrV2"), collision.centFT0M(), 0.5 * std::atan2(collision.qvecIm()[detInd + 1], collision.qvecRe()[detInd + 1])); + registry.fill(HIST("hEPTwistV2"), collision.centFT0M(), 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.centFT0M(), modulationFit->GetParameter(0)); + registry.fill(HIST("hfitPar1"), col.centFT0M(), modulationFit->GetParameter(1)); + registry.fill(HIST("hfitPar2"), col.centFT0M(), modulationFit->GetParameter(2)); + registry.fill(HIST("hfitPar3"), col.centFT0M(), modulationFit->GetParameter(3)); + registry.fill(HIST("hfitPar4"), col.centFT0M(), 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.centFT0M(), cDF); + registry.fill(HIST("hCentChi2Ndf"), col.centFT0M(), 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.centFT0M(), 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.centFT0M(), 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.centFT0M(), 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.centFT0M(), randomConePtWithoutOneLeadJet - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhi, qPerc[0]); + registry.fill(HIST("hCentRhoRandomConeRndTrackDirwoTwoLeadingJet"), collision.centFT0M(), 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..4f22831fe49 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructure.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. + +// jet analysis tasks (subscribing to jet finder task) +// +/// \author Nima Zardoshti +// + +#include "PWGJE/DataModel/JetSubstructure.h" + +#include "RecoDecay.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetSubstructureUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include +#include + +#include + +#include "fastjet/ClusterSequenceArea.hh" +#include "fastjet/PseudoJet.hh" +#include + +#include +#include +#include +#include + +#include +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +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"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable applyTrackingEfficiency{"applyTrackingEfficiency", {false}, "configurable to decide whether to apply artificial tracking efficiency (discarding tracks) in jet finding"}; + Configurable> trackingEfficiencyPtBinning{"trackingEfficiencyPtBinning", {0., 10, 999.}, "pt binning of tracking efficiency array if applyTrackingEfficiency is true"}; + Configurable> trackingEfficiency{"trackingEfficiency", {1.0, 1.0}, "tracking efficiency array applied to jet finding if applyTrackingEfficiency is true"}; + + 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; + + int trackSelection = -1; + + 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; + jetReclusterer.ghostRepeatN = 0; + + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + if (applyTrackingEfficiency) { + if (trackingEfficiencyPtBinning->size() < 2) { + LOGP(fatal, "jetFinder workflow: trackingEfficiencyPtBinning configurable should have at least two bin edges"); + } + if (trackingEfficiency->size() + 1 != trackingEfficiencyPtBinning->size()) { + LOGP(fatal, "jetFinder workflow: trackingEfficiency configurable should have exactly one less entry than the number of bin edges set in trackingEfficiencyPtBinning configurable"); + } + } + } + + 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; + + 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) { + auto zg = z; + auto 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) { + if (!jetderiveddatautilities::applyTrackKinematics(track)) { + continue; + } + + if constexpr (!std::is_same_v, aod::JetParticles>) { + if (!jetfindingutilities::isTrackSelected(track, trackSelection, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning)) { + continue; + } + } + + 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/jetSubstructureB0.cxx b/PWGJE/Tasks/jetSubstructureB0.cxx new file mode 100644 index 00000000000..aedac757bf8 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureB0.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. + +// jet substructure B0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using JetSubstructureB0 = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesB0Data, aod::CandidatesB0MCP, aod::B0CJetSSs, aod::B0ChargedSPs, aod::B0ChargedPRs, aod::B0CMCDJetSSs, aod::B0ChargedMCDetectorLevelSPs, aod::B0ChargedMCDetectorLevelPRs, aod::B0CMCPJetSSs, aod::B0ChargedMCParticleLevelSPs, aod::B0ChargedMCParticleLevelPRs, aod::B0CEWSJetSSs, aod::B0ChargedEventWiseSubtractedSPs, aod::B0ChargedEventWiseSubtractedPRs, aod::JTrackB0Subs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-b0"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureB0Output.cxx b/PWGJE/Tasks/jetSubstructureB0Output.cxx new file mode 100644 index 00000000000..4cac5ffcf2c --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureB0Output.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. + +// jet substructure output B0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using JetSubstructureOutputB0 = JetSubstructureHFOutputTask, aod::McCollisionsB0, aod::CandidatesB0Data, aod::CandidatesB0MCD, aod::CandidatesB0MCP, aod::BkgB0Rhos, aod::BkgB0McRhos, aod::JTrackB0Subs, soa::Join, soa::Join, soa::Join, soa::Join, aod::B0CJetCOs, aod::B0CJetOs, aod::B0CJetSSOs, aod::B0CJetMOs, soa::Join, soa::Join, soa::Join, aod::B0CMCDJetCOs, aod::B0CMCDJetOs, aod::B0CMCDJetSSOs, aod::B0CMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::B0CMCPJetCOs, aod::B0CMCPJetMCCOs, aod::B0CMCPJetOs, aod::B0CMCPJetSSOs, aod::B0CMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::B0CEWSJetCOs, aod::B0CEWSJetOs, aod::B0CEWSJetSSOs, aod::B0CEWSJetMOs, aod::StoredHfB0CollBase, aod::StoredHfB0Bases, aod::StoredHfB0Pars, aod::StoredHfB0ParEs, aod::StoredHfB0ParDpluss, aod::StoredHfB0Sels, aod::StoredHfB0Mls, aod::StoredHfB0MlDpluss, aod::StoredHfB0Mcs, aod::StoredHfB0McCollBases, aod::StoredHfB0McRCollIds, aod::StoredHfB0PBases>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-b0-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureBplus.cxx b/PWGJE/Tasks/jetSubstructureBplus.cxx new file mode 100644 index 00000000000..527429af742 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureBplus.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. + +// jet substructure B+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..04a2585d5bc --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureBplusOutput.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. + +// jet substructure output B+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..cf77baa7ffd --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureD0.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. + +// jet substructure D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..d8bdaaf06d1 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureD0Output.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. + +// jet substructure output D0 charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..5ba3468727c --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDielectron.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. + +// jet substructure Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..3ad3afad83e --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDielectronOutput.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. + +// jet substructure output Dielectron charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedDataDQ.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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::StoredDielectronsAll, aod::JDielectron1Dummys, aod::JDielectron2Dummys, aod::JDielectron3Dummys, aod::JDielectron4Dummys, aod::JDielectron5Dummys, aod::JDielectron6Dummys, 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..e1550673039 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDplus.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. + +// jet substructure D+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..22a869bfcfa --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDplusOutput.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. + +// jet substructure output D+ charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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/jetSubstructureDs.cxx b/PWGJE/Tasks/jetSubstructureDs.cxx new file mode 100644 index 00000000000..3207ba667e3 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDs.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. + +// jet substructure Ds charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using JetSubstructureDs = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesDsData, aod::CandidatesDsMCP, aod::DsCJetSSs, aod::DsChargedSPs, aod::DsChargedPRs, aod::DsCMCDJetSSs, aod::DsChargedMCDetectorLevelSPs, aod::DsChargedMCDetectorLevelPRs, aod::DsCMCPJetSSs, aod::DsChargedMCParticleLevelSPs, aod::DsChargedMCParticleLevelPRs, aod::DsCEWSJetSSs, aod::DsChargedEventWiseSubtractedSPs, aod::DsChargedEventWiseSubtractedPRs, aod::JTrackDsSubs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-ds"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureDsOutput.cxx b/PWGJE/Tasks/jetSubstructureDsOutput.cxx new file mode 100644 index 00000000000..91f0ae4b54d --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDsOutput.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. + +// jet substructure output Ds charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using JetSubstructureOutputDs = JetSubstructureHFOutputTask, aod::McCollisionsDs, aod::CandidatesDsData, aod::CandidatesDsMCD, aod::CandidatesDsMCP, aod::BkgDsRhos, aod::BkgDsMcRhos, aod::JTrackDsSubs, soa::Join, soa::Join, soa::Join, soa::Join, aod::DsCJetCOs, aod::DsCJetOs, aod::DsCJetSSOs, aod::DsCJetMOs, soa::Join, soa::Join, soa::Join, aod::DsCMCDJetCOs, aod::DsCMCDJetOs, aod::DsCMCDJetSSOs, aod::DsCMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::DsCMCPJetCOs, aod::DsCMCPJetMCCOs, aod::DsCMCPJetOs, aod::DsCMCPJetSSOs, aod::DsCMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::DsCEWSJetCOs, aod::DsCEWSJetOs, aod::DsCEWSJetSSOs, aod::DsCEWSJetMOs, aod::StoredHfDsCollBase, aod::StoredHfDsBases, aod::StoredHfDsPars, aod::StoredHfDsParEs, aod::JDumDsParDaus, aod::StoredHfDsSels, aod::StoredHfDsMls, aod::JDumDsMlDaus, aod::StoredHfDsMcs, aod::StoredHfDsMcCollBases, aod::StoredHfDsMcRCollIds, aod::StoredHfDsPBases>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-ds-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureDstar.cxx b/PWGJE/Tasks/jetSubstructureDstar.cxx new file mode 100644 index 00000000000..02c95adbbda --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDstar.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. + +// jet substructure D* charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using JetSubstructureDstar = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesDstarData, aod::CandidatesDstarMCP, aod::DstarCJetSSs, aod::DstarChargedSPs, aod::DstarChargedPRs, aod::DstarCMCDJetSSs, aod::DstarChargedMCDetectorLevelSPs, aod::DstarChargedMCDetectorLevelPRs, aod::DstarCMCPJetSSs, aod::DstarChargedMCParticleLevelSPs, aod::DstarChargedMCParticleLevelPRs, aod::DstarCEWSJetSSs, aod::DstarChargedEventWiseSubtractedSPs, aod::DstarChargedEventWiseSubtractedPRs, aod::JTrackDstarSubs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-dstar"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureDstarOutput.cxx b/PWGJE/Tasks/jetSubstructureDstarOutput.cxx new file mode 100644 index 00000000000..d7ced94f0ad --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureDstarOutput.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. + +// jet substructure output D* charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using JetSubstructureOutputDstar = JetSubstructureHFOutputTask, aod::McCollisionsDstar, aod::CandidatesDstarData, aod::CandidatesDstarMCD, aod::CandidatesDstarMCP, aod::BkgDstarRhos, aod::BkgDstarMcRhos, aod::JTrackDstarSubs, soa::Join, soa::Join, soa::Join, soa::Join, aod::DstarCJetCOs, aod::DstarCJetOs, aod::DstarCJetSSOs, aod::DstarCJetMOs, soa::Join, soa::Join, soa::Join, aod::DstarCMCDJetCOs, aod::DstarCMCDJetOs, aod::DstarCMCDJetSSOs, aod::DstarCMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::DstarCMCPJetCOs, aod::DstarCMCPJetMCCOs, aod::DstarCMCPJetOs, aod::DstarCMCPJetSSOs, aod::DstarCMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::DstarCEWSJetCOs, aod::DstarCEWSJetOs, aod::DstarCEWSJetSSOs, aod::DstarCEWSJetMOs, aod::StoredHfDstarCollBase, aod::StoredHfDstarBases, aod::StoredHfDstarPars, aod::JDumDstarParEs, aod::HfDstarParD0s, aod::StoredHfDstarSels, aod::StoredHfDstarMls, aod::JDumDstarMlDaus, aod::StoredHfDstarMcs, aod::StoredHfDstarMcCollBases, aod::StoredHfDstarMcRCollIds, aod::StoredHfDstarPBases>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-dstar-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureHF.cxx b/PWGJE/Tasks/jetSubstructureHF.cxx new file mode 100644 index 00000000000..ac7be7a4be3 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureHF.cxx @@ -0,0 +1,517 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "RecoDecay.h" + +#include "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDQUtilities.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetHFUtilities.h" +#include "PWGJE/Core/JetSubstructureUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Framework/ASoA.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include + +#include + +#include "fastjet/ClusterSequenceArea.hh" +#include "fastjet/PseudoJet.hh" +#include + +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// NB: runDataProcessing.h must be included after customize! + +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"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + Configurable applyTrackingEfficiency{"applyTrackingEfficiency", {false}, "configurable to decide whether to apply artificial tracking efficiency (discarding tracks) in jet finding"}; + Configurable> trackingEfficiencyPtBinning{"trackingEfficiencyPtBinning", {0., 10, 999.}, "pt binning of tracking efficiency array if applyTrackingEfficiency is true"}; + Configurable> trackingEfficiency{"trackingEfficiency", {1.0, 1.0}, "tracking efficiency array applied to jet finding if applyTrackingEfficiency is true"}; + + 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; + + int trackSelection = -1; + + 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; + jetReclusterer.ghostRepeatN = 0; + + candMass = jetcandidateutilities::getTablePDGMass(); + + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + if (applyTrackingEfficiency) { + if (trackingEfficiencyPtBinning->size() < 2) { + LOGP(fatal, "jetFinder workflow: trackingEfficiencyPtBinning configurable should have at least two bin edges"); + } + if (trackingEfficiency->size() + 1 != trackingEfficiencyPtBinning->size()) { + LOGP(fatal, "jetFinder workflow: trackingEfficiency configurable should have exactly one less entry than the number of bin edges set in trackingEfficiencyPtBinning configurable"); + } + } + } + + Preslice TracksPerCollision = aod::jtrack::collisionId; + PresliceOptional TracksPerD0DataSub = aod::bkgd0::candidateId; + PresliceOptional TracksPerDplusDataSub = aod::bkgdplus::candidateId; + PresliceOptional TracksPerDsDataSub = aod::bkgds::candidateId; + PresliceOptional TracksPerDstarDataSub = aod::bkgdstar::candidateId; + PresliceOptional TracksPerLcDataSub = aod::bkglc::candidateId; + PresliceOptional TracksPerB0DataSub = aod::bkgb0::candidateId; + PresliceOptional TracksPerBplusDataSub = aod::bkgbplus::candidateId; + PresliceOptional TracksPerXicToXiPiPiDataSub = aod::bkgxictoxipipi::candidateId; + PresliceOptional TracksPerDielectronDataSub = aod::bkgdielectron::candidateId; + Preslice ParticlesPerMcCollision = aod::jmcparticle::mcCollisionId; + + template + auto selectSlicer(T const& D0Slicer, U const& DplusSlicer, V const& DsSlicer, M const& DstarSlicer, N const& LcSlicer, O const& B0Slicer, P const& BplusSlicer, Q const& XicToXiPiPiSlicer, R const& DielectronSlicer) + { + if constexpr (jethfutilities::isD0Table()) { + return D0Slicer; + } else if constexpr (jethfutilities::isDplusTable()) { + return DplusSlicer; + } else if constexpr (jethfutilities::isDsTable()) { + return DsSlicer; + } else if constexpr (jethfutilities::isDstarTable()) { + return DstarSlicer; + } else if constexpr (jethfutilities::isLcTable()) { + return LcSlicer; + } else if constexpr (jethfutilities::isB0Table()) { + return B0Slicer; + } else if constexpr (jethfutilities::isBplusTable()) { + return BplusSlicer; + } else if constexpr (jethfutilities::isXicToXiPiPiTable()) { + return XicToXiPiPiSlicer; + } 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; + 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) { + auto zg = z; + auto 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) { + if (!jetderiveddatautilities::applyTrackKinematics(track)) { + continue; + } + + if constexpr (!std::is_same_v, aod::JetParticles>) { + if (!jetfindingutilities::isTrackSelected(track, trackSelection, applyTrackingEfficiency, trackingEfficiency, trackingEfficiencyPtBinning)) { + continue; + } + } + bool isdaughterTrack = false; + for (auto& candidate : jet.template candidates_as()) { + if (jetcandidateutilities::isDaughterTrack(track, candidate)) { + isdaughterTrack = true; + break; + } + } + if (isdaughterTrack) { + continue; + } + 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, TracksPerDsDataSub, TracksPerDstarDataSub, TracksPerLcDataSub, TracksPerB0DataSub, TracksPerBplusDataSub, TracksPerXicToXiPiPiDataSub, 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..0a77074c8ce --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureHFOutput.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. + +// heavy-flavour jet substructure tree filling task (subscribing to jet finder hf and jet substructure hf tasks) +// +/// \author Nima Zardoshti +// + +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetSubstructure.h" + +#include "Framework/ASoA.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// NB: runDataProcessing.h must be included after customize! + +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; + } + + struct : PresliceGroup { + 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> DsSplittingsPerJetData = aod::dschargedsplitting::jetId; + PresliceOptional> DsSplittingsPerJetDataSub = aod::dschargedeventwisesubtractedsplitting::jetId; + PresliceOptional> DsSplittingsPerJetMCD = aod::dschargedmcdetectorlevelsplitting::jetId; + PresliceOptional> DsSplittingsPerJetMCP = aod::dschargedmcparticlelevelsplitting::jetId; + + PresliceOptional> DsPairsPerJetData = aod::dschargedpair::jetId; + PresliceOptional> DsPairsPerJetDataSub = aod::dschargedeventwisesubtractedpair::jetId; + PresliceOptional> DsPairsPerJetMCD = aod::dschargedmcdetectorlevelpair::jetId; + PresliceOptional> DsPairsPerJetMCP = aod::dschargedmcparticlelevelpair::jetId; + + PresliceOptional> DstarSplittingsPerJetData = aod::dstarchargedsplitting::jetId; + PresliceOptional> DstarSplittingsPerJetDataSub = aod::dstarchargedeventwisesubtractedsplitting::jetId; + PresliceOptional> DstarSplittingsPerJetMCD = aod::dstarchargedmcdetectorlevelsplitting::jetId; + PresliceOptional> DstarSplittingsPerJetMCP = aod::dstarchargedmcparticlelevelsplitting::jetId; + + PresliceOptional> DstarPairsPerJetData = aod::dstarchargedpair::jetId; + PresliceOptional> DstarPairsPerJetDataSub = aod::dstarchargedeventwisesubtractedpair::jetId; + PresliceOptional> DstarPairsPerJetMCD = aod::dstarchargedmcdetectorlevelpair::jetId; + PresliceOptional> DstarPairsPerJetMCP = aod::dstarchargedmcparticlelevelpair::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> B0SplittingsPerJetData = aod::b0chargedsplitting::jetId; + PresliceOptional> B0SplittingsPerJetDataSub = aod::b0chargedeventwisesubtractedsplitting::jetId; + PresliceOptional> B0SplittingsPerJetMCD = aod::b0chargedmcdetectorlevelsplitting::jetId; + PresliceOptional> B0SplittingsPerJetMCP = aod::b0chargedmcparticlelevelsplitting::jetId; + + PresliceOptional> B0PairsPerJetData = aod::b0chargedpair::jetId; + PresliceOptional> B0PairsPerJetDataSub = aod::b0chargedeventwisesubtractedpair::jetId; + PresliceOptional> B0PairsPerJetMCD = aod::b0chargedmcdetectorlevelpair::jetId; + PresliceOptional> B0PairsPerJetMCP = aod::b0chargedmcparticlelevelpair::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> XicToXiPiPiSplittingsPerJetData = aod::xictoxipipichargedsplitting::jetId; + PresliceOptional> XicToXiPiPiSplittingsPerJetDataSub = aod::xictoxipipichargedeventwisesubtractedsplitting::jetId; + PresliceOptional> XicToXiPiPiSplittingsPerJetMCD = aod::xictoxipipichargedmcdetectorlevelsplitting::jetId; + PresliceOptional> XicToXiPiPiSplittingsPerJetMCP = aod::xictoxipipichargedmcparticlelevelsplitting::jetId; + + PresliceOptional> XicToXiPiPiPairsPerJetData = aod::xictoxipipichargedpair::jetId; + PresliceOptional> XicToXiPiPiPairsPerJetDataSub = aod::xictoxipipichargedeventwisesubtractedpair::jetId; + PresliceOptional> XicToXiPiPiPairsPerJetMCD = aod::xictoxipipichargedmcdetectorlevelpair::jetId; + PresliceOptional> XicToXiPiPiPairsPerJetMCP = aod::xictoxipipichargedmcparticlelevelpair::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; + + } preslices; + + 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.centFT0M(); + 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& DsSplittingsPerJet, P const DstarSplittingsPerJet, Q const& LcSplittingsPerJet, R const& B0SplittingsPerJet, S const& BplusSplittingsPerJet, A const& XicToXiPiPiSplittingsPerJet, B const& DielectronSplittingsPerJet, C const& D0PairsPerJet, D const DplusPairsPerJet, E const& DsPairsPerJet, F const& DstarPairsPerJet, G const& LcPairsPerJet, H const& B0PairsPerJet, I const& BplusPairsPerJet, J const& XicToXiPiPiPairsPerJet, K 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, DsSplittingsPerJet, DstarSplittingsPerJet, LcSplittingsPerJet, B0SplittingsPerJet, BplusSplittingsPerJet, XicToXiPiPiSplittingsPerJet, DielectronSplittingsPerJet); + fillSplittingMatchingVectors(splittings, jet.globalIndex(), splittingMatchesGeoVecVec, splittingMatchesPtVecVec, splittingMatchesHFVecVec); + auto pairs = jetcandidateutilities::slicedPerJet(allPairs, jet, D0PairsPerJet, DplusPairsPerJet, DsPairsPerJet, DstarPairsPerJet, LcPairsPerJet, B0PairsPerJet, BplusPairsPerJet, XicToXiPiPiPairsPerJet, 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(preslices.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(preslices.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(preslices.CandidateMcCollisionsPerMcCollision, preslices.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, preslices.D0SplittingsPerJetData, preslices.DplusSplittingsPerJetData, preslices.DsSplittingsPerJetData, preslices.DstarSplittingsPerJetData, preslices.LcSplittingsPerJetData, preslices.B0SplittingsPerJetData, preslices.BplusSplittingsPerJetData, preslices.XicToXiPiPiSplittingsPerJetData, preslices.DielectronSplittingsPerJetData, preslices.D0PairsPerJetData, preslices.DplusPairsPerJetData, preslices.DsPairsPerJetData, preslices.DstarPairsPerJetData, preslices.LcPairsPerJetData, preslices.B0PairsPerJetData, preslices.BplusPairsPerJetData, preslices.XicToXiPiPiPairsPerJetData, preslices.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, preslices.D0SplittingsPerJetDataSub, preslices.DplusSplittingsPerJetDataSub, preslices.DsSplittingsPerJetDataSub, preslices.DstarSplittingsPerJetDataSub, preslices.LcSplittingsPerJetDataSub, preslices.B0SplittingsPerJetDataSub, preslices.BplusSplittingsPerJetDataSub, preslices.XicToXiPiPiSplittingsPerJetDataSub, preslices.DielectronSplittingsPerJetDataSub, preslices.D0PairsPerJetDataSub, preslices.DplusPairsPerJetDataSub, preslices.DsPairsPerJetDataSub, preslices.DstarPairsPerJetDataSub, preslices.LcPairsPerJetDataSub, preslices.B0PairsPerJetDataSub, preslices.BplusPairsPerJetDataSub, preslices.XicToXiPiPiPairsPerJetDataSub, preslices.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, preslices.D0SplittingsPerJetMCD, preslices.DplusSplittingsPerJetMCD, preslices.DsSplittingsPerJetMCD, preslices.DstarSplittingsPerJetMCD, preslices.LcSplittingsPerJetMCD, preslices.B0SplittingsPerJetMCD, preslices.BplusSplittingsPerJetMCD, preslices.XicToXiPiPiSplittingsPerJetMCD, preslices.DielectronSplittingsPerJetMCD, preslices.D0PairsPerJetMCD, preslices.DplusPairsPerJetMCD, preslices.DsPairsPerJetMCD, preslices.DstarPairsPerJetMCD, preslices.LcPairsPerJetMCD, preslices.B0PairsPerJetMCD, preslices.BplusPairsPerJetMCD, preslices.XicToXiPiPiPairsPerJetMCD, preslices.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, preslices.D0SplittingsPerJetMCP, preslices.DplusSplittingsPerJetMCP, preslices.DsSplittingsPerJetMCP, preslices.DstarSplittingsPerJetMCP, preslices.LcSplittingsPerJetMCP, preslices.B0SplittingsPerJetMCP, preslices.BplusSplittingsPerJetMCP, preslices.XicToXiPiPiSplittingsPerJetMCP, preslices.DielectronSplittingsPerJetMCP, preslices.D0PairsPerJetMCP, preslices.DplusPairsPerJetMCP, preslices.DsPairsPerJetMCP, preslices.DstarPairsPerJetMCP, preslices.LcPairsPerJetMCP, preslices.B0PairsPerJetMCP, preslices.BplusPairsPerJetMCP, preslices.XicToXiPiPiPairsPerJetMCP, preslices.DielectronPairsPerJetMCP, splittingMatchesGeoVecVecMCP, splittingMatchesPtVecVecMCP, splittingMatchesHFVecVecMCP, pairMatchesVecVecMCP, configs.jetPtMinMCP); + } + PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputSubstructureMatchingMC, "jet substructure matching output MC", false); + + void processOutputJetsMCD(aod::JetCollisionMCD const& collision, + 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.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..6f8260ab2c5 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureLc.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. + +// jet substructure Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..e25c204b580 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureLcOutput.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. + +// jet substructure output Lc charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +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..39f1e1518cd --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureOutput.cxx @@ -0,0 +1,408 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// NB: runDataProcessing.h must be included after customize! + +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.centFT0M(); + 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, + soa::Join const& jets) + { + analyseCharged(collision, jets, collisionOutputTableMCD, jetOutputTableMCD, jetSubstructureOutputTableMCD, splittingMatchesGeoVecVecMCD, splittingMatchesPtVecVecMCD, splittingMatchesHFVecVecMCD, pairMatchesVecVecMCD, jetMappingMCD, jetPtMinMCD, collision.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/jetSubstructureXicToXiPiPi.cxx b/PWGJE/Tasks/jetSubstructureXicToXiPiPi.cxx new file mode 100644 index 00000000000..ca58df3a425 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureXicToXiPiPi.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. + +// jet substructure XicToXiPiPi charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHF.cxx" + +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using JetSubstructureXicToXiPiPi = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, aod::CandidatesXicToXiPiPiData, aod::CandidatesXicToXiPiPiMCP, aod::XicToXiPiPiCJetSSs, aod::XicToXiPiPiChargedSPs, aod::XicToXiPiPiChargedPRs, aod::XicToXiPiPiCMCDJetSSs, aod::XicToXiPiPiChargedMCDetectorLevelSPs, aod::XicToXiPiPiChargedMCDetectorLevelPRs, aod::XicToXiPiPiCMCPJetSSs, aod::XicToXiPiPiChargedMCParticleLevelSPs, aod::XicToXiPiPiChargedMCParticleLevelPRs, aod::XicToXiPiPiCEWSJetSSs, aod::XicToXiPiPiChargedEventWiseSubtractedSPs, aod::XicToXiPiPiChargedEventWiseSubtractedPRs, aod::JTrackXicToXiPiPiSubs>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, + SetDefaultProcesses{}, + TaskName{"jet-substructure-xictoxipipi"})); + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetSubstructureXicToXiPiPiOutput.cxx b/PWGJE/Tasks/jetSubstructureXicToXiPiPiOutput.cxx new file mode 100644 index 00000000000..93d3f884090 --- /dev/null +++ b/PWGJE/Tasks/jetSubstructureXicToXiPiPiOutput.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. + +// jet substructure output XicToXiPiPi charged task +// +/// \author Nima Zardoshti + +#include "PWGJE/Tasks/jetSubstructureHFOutput.cxx" + +#include "PWGHF/DataModel/DerivedTables.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedDataHF.h" +#include "PWGJE/DataModel/JetSubstructure.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include +#include +#include +#include +#include + +#include + +using JetSubstructureOutputXicToXiPiPi = JetSubstructureHFOutputTask, aod::McCollisionsXicToXiPiPi, aod::CandidatesXicToXiPiPiData, aod::CandidatesXicToXiPiPiMCD, aod::CandidatesXicToXiPiPiMCP, aod::BkgXicToXiPiPiRhos, aod::BkgXicToXiPiPiMcRhos, aod::JTrackXicToXiPiPiSubs, soa::Join, soa::Join, soa::Join, soa::Join, aod::XicToXiPiPiCJetCOs, aod::XicToXiPiPiCJetOs, aod::XicToXiPiPiCJetSSOs, aod::XicToXiPiPiCJetMOs, soa::Join, soa::Join, soa::Join, aod::XicToXiPiPiCMCDJetCOs, aod::XicToXiPiPiCMCDJetOs, aod::XicToXiPiPiCMCDJetSSOs, aod::XicToXiPiPiCMCDJetMOs, soa::Join, soa::Join, soa::Join, soa::Join, aod::XicToXiPiPiCMCPJetCOs, aod::XicToXiPiPiCMCPJetMCCOs, aod::XicToXiPiPiCMCPJetOs, aod::XicToXiPiPiCMCPJetSSOs, aod::XicToXiPiPiCMCPJetMOs, soa::Join, soa::Join, soa::Join, aod::XicToXiPiPiCEWSJetCOs, aod::XicToXiPiPiCEWSJetOs, aod::XicToXiPiPiCEWSJetSSOs, aod::XicToXiPiPiCEWSJetMOs, aod::StoredHfXicToXiPiPiCollBase, aod::StoredHfXicToXiPiPiBases, aod::StoredHfXicToXiPiPiPars, aod::StoredHfXicToXiPiPiParEs, aod::JDumXicToXiPiPiParDaus, aod::StoredHfXicToXiPiPiSels, aod::StoredHfXicToXiPiPiMls, aod::JDumXicToXiPiPiMlDaus, aod::StoredHfXicToXiPiPiMcs, aod::StoredHfXicToXiPiPiMcCollBases, aod::StoredHfXicToXiPiPiMcRCollIds, aod::StoredHfXicToXiPiPiPBases>; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + std::vector tasks; + tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-xictoxipipi-output"})); + + return WorkflowSpec{tasks}; +} diff --git a/PWGJE/Tasks/jetTaggerHFQA.cxx b/PWGJE/Tasks/jetTaggerHFQA.cxx new file mode 100644 index 00000000000..37ac50220e9 --- /dev/null +++ b/PWGJE/Tasks/jetTaggerHFQA.cxx @@ -0,0 +1,1934 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetTagging.h" + +#include "Common/DataModel/Multiplicity.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#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; + +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"}; + Configurable fillSVxyz{"fillSVxyz", true, "process of decay lenngth of xyz for sv"}; + + // Cut configuration + Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; + Configurable> trackCuts{"trackCuts", std::vector{0.15, 100.0, -0.9, 0.9}, "Track cuts: ptMin, ptMax, etaMin, etaMax"}; + 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> jetEtaCuts{"jetEtaCuts", std::vector{-99.0, 99.0}, "Jet cuts: etaMin, etaMax"}; + Configurable> prongCuts{"prongCuts", std::vector{1, 100, 100, 100, 0.008, 1}, "prong cuts: chi2PCAMin, chi2PCAMax, sigmaLxyMax, sigmaLxyzMax, IPxyMin, IPxyMax"}; + 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 meanFT0A{"meanFT0A", -1., "Mean value of FT0A signal"}; + Configurable meanFT0C{"meanFT0C", -1., "Mean value of FT0C signal"}; + + 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}, ""}; + ConfigurableAxis binMultScaledFT0M{"binMultScaledFT0M", {VARIABLE_WIDTH, 0, 0.2, 0.3, 0.4, 0.6, 0.8, 1., 1.4, 1.8, 2.4, 3.6, 5., 20.}, "Percentiles of scaled FT0M: 100-90%, 90-80%, 80-70%, 70-60%, 60-50%, 50-40%, 40-30%, 30-20%, 20-10%, 10-1%, 1-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 axisMCDJetPt = {binJetPt, "#it{p}_{T, jet}^{rec}"}; + AxisSpec axisMCPJetPt = {binJetPt, "#it{p}_{T, jet}^{gen}"}; + 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]"}; + AxisSpec axisFracSecPt = {100, 0, 1, "#frac{#Sigma#it{p}_{T}^{secondary track}}{#it{p}_{T, jet}}"}; + AxisSpec axisMultScaledFT0M = {binMultScaledFT0M, "Multiplicity classes"}; + + if (doprocessTracksDca) { + if (fillIPxy) { + registry.add("h_impact_parameter_xy", "", {HistType::kTH1F, {{axisImpactParameterXY}}}); + registry.add("h_impact_parameter_xy_significance", "", {HistType::kTH1F, {{axisImpactParameterXYSignificance}}}); + } + if (fillIPz) { + registry.add("h_impact_parameter_z", "", {HistType::kTH1F, {{axisImpactParameterZ}}}); + registry.add("h_impact_parameter_z_significance", "", {HistType::kTH1F, {{axisImpactParameterZSignificance}}}); + } + if (fillIPxyz) { + registry.add("h_impact_parameter_xyz", "", {HistType::kTH1F, {{axisImpactParameterXYZ}}}); + registry.add("h_impact_parameter_xyz_significance", "", {HistType::kTH1F, {{axisImpactParameterXYZSignificance}}}); + } + } + if (doprocessTracksInJetsData) { + registry.add("h2_track_pt_impact_parameter_xy", "", {HistType::kTH2F, {{axisTrackPt}, {axisImpactParameterXY}}}); + } + if (doprocessSecondaryContaminationMCD) { + registry.add("hn_jet_pt_track_pt_impact_parameter_xy_physical_primary_flavour", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisTrackPt}, {axisImpactParameterXY}, {axisJetFlavour}}}); + registry.add("hn_jet_pt_track_pt_impact_parameter_xy_secondary_flavour", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisTrackPt}, {axisImpactParameterXY}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_frac_secondary_pt_per_jet_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisFracSecPt}, {axisJetFlavour}}}); + } + if (doprocessValFlavourDefMCD) { + registry.add("h3_jet_pt_flavour_dist_quark_flavour_dist_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_flavour_const_quark_flavour_const_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_flavour_const_hadron_flavour_dist_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_jet_pt_flavour_const_quark_flavour_dist_quark", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + } + if (doprocessValFlavourDefMCP) { + registry.add("h3_part_jet_pt_flavour_dist_quark_part_flavour_dist_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_part_jet_pt_flavour_const_quark_part_flavour_const_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_part_jet_pt_flavour_const_hadron_part_flavour_dist_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_part_jet_pt_flavour_const_quark_part_flavour_dist_quark", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + } + 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("h3_part_jet_pt_flavour_dist_quark_part_flavour_dist_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_part_jet_pt_flavour_const_quark_part_flavour_const_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_part_jet_pt_flavour_const_hadron_part_flavour_dist_hadron", "", {HistType::kTH3F, {{axisJetPt}, {axisJetFlavour}, {axisJetFlavour}}}); + registry.add("h3_part_jet_pt_flavour_const_quark_part_flavour_dist_quark", "", {HistType::kTH3F, {{axisJetPt}, {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) { + if (fillIPxy) { + 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("h3_jet_pt_sign_impact_parameter_xy_significance_tc", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYSignificance}, {axisNumOrder}}}); + registry.add("h3_track_pt_sign_impact_parameter_xy_significance_tc", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterXYSignificance}, {axisNumOrder}}}); + } + if (fillIPz) { + 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("h3_jet_pt_sign_impact_parameter_z_significance_tc", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterZSignificance}, {axisNumOrder}}}); + registry.add("h3_track_pt_sign_impact_parameter_z_significance_tc", "", {HistType::kTH3F, {{axisTrackPt}, {axisImpactParameterZSignificance}, {axisNumOrder}}}); + } + if (fillIPxyz) { + 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_xyz_significance_tc", "", {HistType::kTH3F, {{axisJetPt}, {axisImpactParameterXYZSignificance}, {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) { + if (fillIPxy) { + 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_sign_impact_parameter_xy_significance_tc_flavour", "", {HistType::kTH3F, {{axisImpactParameterXYSignificance}, {axisNumOrder}, {axisJetFlavour}}}); + } + if (fillIPz) { + 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_sign_impact_parameter_z_significance_tc_flavour", "", {HistType::kTH3F, {{axisImpactParameterZSignificance}, {axisNumOrder}, {axisJetFlavour}}}); + } + if (fillIPxyz) { + 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_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, {{axisMCDJetPt}, {axisMCPJetPt}, {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 (doprocessSV3ProngDataMult) { + registry.add("h_event_mult", "", {HistType::kTH1F, {{axisMultScaledFT0M}}}); + registry.add("h2_jet_pt_mult", "", {HistType::kTH2F, {{axisJetPt}, {axisMultScaledFT0M}}}); + registry.add("h2_jet_eta_mult", "", {HistType::kTH2F, {{axisEta}, {axisMultScaledFT0M}}}); + registry.add("h2_jet_phi_mult", "", {HistType::kTH2F, {{axisPhi}, {axisMultScaledFT0M}}}); + if (fillGeneralSVQA) { + registry.add("h2_3prong_nprongs_mult", "", {HistType::kTH2F, {{axisNprongs}, {axisMultScaledFT0M}}}); + registry.add("hn_jet_3prong_Sxy_mult", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisLxy}, {axisSigmaLxy}, {axisSxy}, {axisMultScaledFT0M}}}); + if (fillSVxyz) { + registry.add("hn_jet_3prong_Sxyz_mult", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisLxyz}, {axisSigmaLxyz}, {axisSxyz}, {axisMultScaledFT0M}}}); + } + } + registry.add("hn_jet_3prong_Sxy_N1_mult", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisSxy}, {axisMass}, {axisMultScaledFT0M}}}); + registry.add("hn_taggedjet_3prong_Sxy_N1_mult", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisSxy}, {axisMass}, {axisMultScaledFT0M}}}); + if (fillSVxyz) { + registry.add("hn_jet_3prong_Sxyz_N1_mult", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisSxyz}, {axisMass}, {axisMultScaledFT0M}}}); + registry.add("hn_taggedjet_3prong_Sxyz_N1_mult", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisSxyz}, {axisMass}, {axisMultScaledFT0M}}}); + } + } + 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}}}); + } + if (doprocessSV3ProngMCDMult || doprocessSV3ProngMCDMultWeighted || doprocessSV3ProngMCPMCDMatchedMult || doprocessSV3ProngMCPMCDMatchedMultWeighted) { + registry.add("h_event_mult", "", {HistType::kTH1F, {{axisMultScaledFT0M}}}); + registry.add("h3_jet_pt_mult_flavour", "", {HistType::kTH3F, {{axisJetPt}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + registry.add("h3_jet_eta_mult_flavour", "", {HistType::kTH3F, {{axisEta}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + registry.add("h3_jet_phi_mult_flavour", "", {HistType::kTH3F, {{axisPhi}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + if (fillGeneralSVQA) { + registry.add("h3_3prong_nprongs_mult_flavour", "", {HistType::kTH3F, {{axisNprongs}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + registry.add("hn_jet_3prong_Sxy_mult_flavour", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisLxy}, {axisSigmaLxy}, {axisSxy}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + if (fillSVxyz) { + registry.add("hn_jet_3prong_Sxyz_mult_flavour", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisLxyz}, {axisSigmaLxyz}, {axisSxyz}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + } + } + registry.add("hn_jet_3prong_Sxy_N1_mult_flavour", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisSxy}, {axisMass}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + registry.add("hn_taggedjet_3prong_Sxy_N1_mult_flavour", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisSxy}, {axisSxyz}, {axisMass}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + if (fillSVxyz) { + registry.add("hn_jet_3prong_Sxyz_N1_mult_flavour", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisSxyz}, {axisMass}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + registry.add("hn_taggedjet_3prong_Sxyz_N1_mult_flavour", "", {HistType::kTHnSparseF, {{axisJetPt}, {axisSxy}, {axisSxyz}, {axisMass}, {axisMultScaledFT0M}, {axisJetFlavour}}}); + } + } + } + + // Filter trackCuts = (aod::jtrack::pt >= trackCuts->at(0) && aod::jtrack::pt < trackCuts->at(1) && aod::jtrack::eta > trackCuts->at(2) && aod::jtrack::eta < trackCuts->at(3)); + 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) + { + const float noJetAreaFractionFilter = -98.0; + const float noConstituentPtMinFilter = -98.0; + const float noConstituentPtMaxFilter = 9998.0; + if (jetAreaFractionMin > noJetAreaFractionFilter) { + if (jet.area() < jetAreaFractionMin * o2::constants::math::PI * (jet.r() / 100.0) * (jet.r() / 100.0)) { + return false; + } + } + bool checkConstituentPt = true; + bool checkConstituentMinPt = (leadingConstituentPtMin > noConstituentPtMinFilter); + bool checkConstituentMaxPt = (leadingConstituentPtMax < noConstituentPtMaxFilter); + 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() < trackCuts->at(0) || track.pt() > trackCuts->at(1)) + return false; + + return true; + } + + float getScaledFT0A(const float multFT0A) + { + return multFT0A / meanFT0A; + } + + float getScaledFT0C(const float multFT0C) + { + return multFT0C / meanFT0C; + } + + float getScaledFT0M(const float multFT0A, const float multFT0C) + { + return 0.5 * (getScaledFT0A(multFT0A) + getScaledFT0C(multFT0C)); + } + + 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("h3_jet_pt_flavour_dist_quark_flavour_dist_hadron"), mcdjet.pt(), jetflavourDistQuark, jetflavourDistHadron, eventWeight); + registry.fill(HIST("h3_jet_pt_flavour_const_quark_flavour_const_hadron"), mcdjet.pt(), jetflavourConstQuark, jetflavourConstHadron, eventWeight); + registry.fill(HIST("h3_jet_pt_flavour_const_hadron_flavour_dist_hadron"), mcdjet.pt(), jetflavourConstHadron, jetflavourDistHadron, eventWeight); + registry.fill(HIST("h3_jet_pt_flavour_const_quark_flavour_dist_quark"), mcdjet.pt(), 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("h3_part_jet_pt_flavour_dist_quark_part_flavour_dist_hadron"), mcpjet.pt(), jetflavourDistQuark, jetflavourDistHadron, eventWeight); + registry.fill(HIST("h3_part_jet_pt_flavour_const_quark_part_flavour_const_hadron"), mcpjet.pt(), jetflavourConstQuark, jetflavourConstHadron, eventWeight); + registry.fill(HIST("h3_part_jet_pt_flavour_const_hadron_part_flavour_dist_hadron"), mcpjet.pt(), jetflavourConstHadron, jetflavourDistHadron, eventWeight); + registry.fill(HIST("h3_part_jet_pt_flavour_const_quark_part_flavour_dist_quark"), mcpjet.pt(), jetflavourConstQuark, jetflavourDistQuark, eventWeight); + } + + template + void fillHistogramIPsData(T const& jet, U const& /*tracks*/) + { + std::size_t firstTaggerForTrackCounting = 0; + std::size_t secondTaggerForTrackCounting = 1; + std::size_t thirdTaggerForTrackCounting = 2; + 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() > firstTaggerForTrackCounting) { // 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() > secondTaggerForTrackCounting) { // 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() > thirdTaggerForTrackCounting) { // 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) + { + std::size_t firstTaggerForTrackCounting = 0; + std::size_t secondTaggerForTrackCounting = 1; + std::size_t thirdTaggerForTrackCounting = 2; + 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() > firstTaggerForTrackCounting) { // 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() > secondTaggerForTrackCounting) { // 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() > thirdTaggerForTrackCounting) { // 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_sigmaLxy"), jet.pt(), prong.errorDecayLengthXY()); + registry.fill(HIST("h2_jet_pt_2prong_Sxy"), jet.pt(), prong.decayLengthXY() / prong.errorDecayLengthXY()); + if (fillSVxyz) { + registry.fill(HIST("h2_jet_pt_2prong_Lxyz"), jet.pt(), prong.decayLength()); + registry.fill(HIST("h2_jet_pt_2prong_sigmaLxyz"), jet.pt(), prong.errorDecayLength()); + registry.fill(HIST("h2_jet_pt_2prong_Sxyz"), jet.pt(), prong.decayLength() / prong.errorDecayLength()); + } + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(2), prongCuts->at(4), prongCuts->at(5), 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); + } + } + if (fillSVxyz) { + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(3), prongCuts->at(4), prongCuts->at(5), true, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCandXYZ, 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_sigmaLxy"), jet.pt(), prong.errorDecayLengthXY()); + registry.fill(HIST("h2_jet_pt_3prong_Sxy"), jet.pt(), prong.decayLengthXY() / prong.errorDecayLengthXY()); + if (fillSVxyz) { + registry.fill(HIST("h2_jet_pt_3prong_Lxyz"), jet.pt(), prong.decayLength()); + registry.fill(HIST("h2_jet_pt_3prong_sigmaLxyz"), jet.pt(), prong.errorDecayLength()); + registry.fill(HIST("h2_jet_pt_3prong_Sxyz"), jet.pt(), prong.decayLength() / prong.errorDecayLength()); + } + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(2), prongCuts->at(4), prongCuts->at(5), 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); + } + } + if (fillSVxyz) { + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(3), prongCuts->at(4), prongCuts->at(5), 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 fillHistogramSV3ProngDataMult(T const& collision, U const& jet, V const& /*prongs*/) + { + if (jet.template secondaryVertices_as().size() < 1) + return; + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float scaledFT0M = getScaledFT0M(multFT0A, multFT0C); + registry.fill(HIST("h2_jet_pt_mult"), jet.pt(), scaledFT0M); + registry.fill(HIST("h2_jet_eta_mult"), jet.eta(), scaledFT0M); + registry.fill(HIST("h2_jet_phi_mult"), jet.phi(), scaledFT0M); + if (fillGeneralSVQA) { + registry.fill(HIST("h2_3prong_nprongs_mult"), jet.template secondaryVertices_as().size(), scaledFT0M); + for (const auto& prong : jet.template secondaryVertices_as()) { + registry.fill(HIST("hn_jet_3prong_Sxy_mult"), jet.pt(), prong.decayLengthXY(), prong.errorDecayLengthXY(), prong.decayLengthXY() / prong.errorDecayLengthXY(), scaledFT0M); + if (fillSVxyz) { + registry.fill(HIST("hn_jet_3prong_Sxyz_mult"), jet.pt(), prong.decayLength(), prong.errorDecayLength(), prong.decayLength() / prong.errorDecayLength(), scaledFT0M); + } + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(2), prongCuts->at(4), prongCuts->at(5), false, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCand, svDispersionMax)) { + auto maxSxy = bjetCand.decayLengthXY() / bjetCand.errorDecayLengthXY(); + auto massSV = bjetCand.m(); + registry.fill(HIST("hn_jet_3prong_Sxy_N1_mult"), jet.pt(), maxSxy, massSV, scaledFT0M); + if (jet.isTagged(BJetTaggingMethod::SV)) { + registry.fill(HIST("hn_taggedjet_3prong_Sxy_N1_mult"), jet.pt(), maxSxy, massSV, scaledFT0M); + } + } + if (fillSVxyz) { + checkSv = false; + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(jet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(3), prongCuts->at(4), prongCuts->at(5), true, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCandXYZ, svDispersionMax)) { + auto maxSxyz = bjetCandXYZ.decayLength() / bjetCandXYZ.errorDecayLength(); + auto massSV = bjetCandXYZ.m(); + registry.fill(HIST("hn_jet_3prong_Sxyz_N1_mult"), jet.pt(), maxSxyz, massSV, scaledFT0M); + if (jet.isTagged(BJetTaggingMethod::SV3D)) { + registry.fill(HIST("hn_taggedjet_3prong_Sxyz_N1_mult"), jet.pt(), maxSxyz, massSV, scaledFT0M); + } + } + } + } + + 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_sigmaLxy_flavour"), mcdjet.pt(), prong.errorDecayLengthXY(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_Sxy_flavour"), mcdjet.pt(), prong.decayLengthXY() / prong.errorDecayLengthXY(), origin, eventWeight); + if (fillSVxyz) { + registry.fill(HIST("h3_jet_pt_2prong_Lxyz_flavour"), mcdjet.pt(), prong.decayLength(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_sigmaLxyz_flavour"), mcdjet.pt(), prong.errorDecayLength(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_2prong_Sxyz_flavour"), mcdjet.pt(), prong.decayLength() / prong.errorDecayLength(), origin, eventWeight); + } + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(2), prongCuts->at(4), prongCuts->at(5), 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); + } + } + if (fillSVxyz) { + checkSv = false; + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(3), prongCuts->at(4), prongCuts->at(5), 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_sigmaLxy_flavour"), mcdjet.pt(), prong.errorDecayLengthXY(), origin, eventWeight); + registry.fill(HIST("h3_jet_pt_3prong_Sxy_flavour"), mcdjet.pt(), prong.decayLengthXY() / prong.errorDecayLengthXY(), origin, eventWeight); + if (fillSVxyz) { + 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_sigmaLxyz_flavour"), mcdjet.pt(), prong.errorDecayLength(), origin, eventWeight); + } + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(2), prongCuts->at(4), prongCuts->at(5), 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); + } + } + if (fillSVxyz) { + checkSv = false; + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(3), prongCuts->at(4), prongCuts->at(5), true, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCandXYZ, 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); + } + } + } + } + + template + void fillHistogramSV3ProngMCDMult(T const& collision, U const& mcdjet, V 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(); + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float scaledFT0M = getScaledFT0M(multFT0A, multFT0C); + if (mcdjet.template secondaryVertices_as().size() < 1) + return; + registry.fill(HIST("h3_jet_pt_mult_flavour"), mcdjet.pt(), scaledFT0M, origin, eventWeight); + registry.fill(HIST("h3_jet_eta_mult_flavour"), mcdjet.eta(), scaledFT0M, origin, eventWeight); + registry.fill(HIST("h3_jet_phi_mult_flavour"), mcdjet.phi(), scaledFT0M, origin, eventWeight); + if (fillGeneralSVQA) { + registry.fill(HIST("h3_3prong_nprongs_mult_flavour"), mcdjet.template secondaryVertices_as().size(), scaledFT0M, origin, eventWeight); + for (const auto& prong : mcdjet.template secondaryVertices_as()) { + registry.fill(HIST("hn_jet_3prong_Sxy_mult_flavour"), mcdjet.pt(), prong.decayLengthXY(), prong.errorDecayLengthXY(), prong.decayLengthXY() / prong.errorDecayLengthXY(), scaledFT0M, origin, eventWeight); + if (fillSVxyz) { + registry.fill(HIST("hn_jet_3prong_Sxyz_mult_flavour"), mcdjet.pt(), prong.decayLength(), prong.errorDecayLength(), prong.decayLength() / prong.errorDecayLength(), scaledFT0M, origin, eventWeight); + } + } + } + bool checkSv = false; + auto bjetCand = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(2), prongCuts->at(4), prongCuts->at(5), false, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCand, svDispersionMax)) { + auto maxSxy = bjetCand.decayLengthXY() / bjetCand.errorDecayLengthXY(); + auto massSV = bjetCand.m(); + registry.fill(HIST("hn_jet_3prong_Sxy_N1_mult_flavour"), mcdjet.pt(), maxSxy, massSV, scaledFT0M, origin, eventWeight); + if (mcdjet.isTagged(BJetTaggingMethod::SV)) { + registry.fill(HIST("hn_taggedjet_3prong_Sxy_N1_mult_flavour"), mcdjet.pt(), maxSxy, massSV, scaledFT0M, origin, eventWeight); + } + } + if (fillSVxyz) { + auto bjetCandXYZ = jettaggingutilities::jetFromProngMaxDecayLength(mcdjet, prongCuts->at(0), prongCuts->at(1), prongCuts->at(3), prongCuts->at(4), prongCuts->at(5), true, &checkSv); + if (checkSv && jettaggingutilities::svAcceptance(bjetCandXYZ, svDispersionMax)) { + auto maxSxyz = bjetCandXYZ.decayLength() / bjetCandXYZ.errorDecayLength(); + auto massSV = bjetCandXYZ.m(); + registry.fill(HIST("hn_jet_3prong_Sxyz_N1_mult_flavour"), mcdjet.pt(), maxSxyz, massSV, scaledFT0M, origin, eventWeight); + if (mcdjet.isTagged(BJetTaggingMethod::SV3D)) { + registry.fill(HIST("hn_taggedjet_3prong_Sxyz_N1_mult_flavour"), mcdjet.pt(), maxSxyz, massSV, scaledFT0M, 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; + + if (fillIPxy) { + registry.fill(HIST("h_impact_parameter_xy"), varImpXY); + registry.fill(HIST("h_impact_parameter_xy_significance"), varImpXYSig); + } + if (fillIPz) { + registry.fill(HIST("h_impact_parameter_z"), varImpZ); + registry.fill(HIST("h_impact_parameter_z_significance"), varImpZSig); + } + if (fillIPxyz) { + 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 processTracksInJetsData(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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + for (auto const& track : jet.template tracks_as()) { + float varImpXY = track.dcaXY() * jettaggingutilities::cmTomum; + registry.fill(HIST("h2_track_pt_impact_parameter_xy"), track.pt(), varImpXY); + } + } + } + PROCESS_SWITCH(JetTaggerHFQA, processTracksInJetsData, "Fill QA comtamination of secondary-track inside jets for data jets", false); + + void processSecondaryContaminationMCD(soa::Filtered>::iterator const& collision, soa::Join const& mcdjets, JetTagTracksMCD const& /*tracks*/, aod::JetParticles const& /*particles*/) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + float pTHat = 10. / (std::pow(mcdjet.eventWeight(), 1.0 / pTHatExponent)); + if (mcdjet.pt() > pTHatMaxMCD * pTHat) { + continue; + } + int jetflavour = mcdjet.origin(); + float secondaryPt = 0; + float totalJetPt = 0; + for (auto const& track : mcdjet.template tracks_as()) { + float varImpXY = track.dcaXY() * jettaggingutilities::cmTomum; + if (!track.has_mcParticle()) + continue; + auto mcParticle = track.mcParticle(); + totalJetPt += track.pt(); + if (mcParticle.isPhysicalPrimary()) { + registry.fill(HIST("hn_jet_pt_track_pt_impact_parameter_xy_physical_primary_flavour"), mcdjet.pt(), track.pt(), varImpXY, jetflavour, mcdjet.eventWeight()); + } else { + registry.fill(HIST("hn_jet_pt_track_pt_impact_parameter_xy_secondary_flavour"), mcdjet.pt(), track.pt(), varImpXY, jetflavour, mcdjet.eventWeight()); + secondaryPt += track.pt(); + } + } + if (totalJetPt > 0) { + float fracSecondary = secondaryPt / totalJetPt; + registry.fill(HIST("h3_jet_pt_frac_secondary_pt_per_jet_flavour"), mcdjet.pt(), fracSecondary, jetflavour, mcdjet.eventWeight()); + } + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSecondaryContaminationMCD, "Fill QA comtamination of secondary-track inside jets for mcd jets", 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistogramSV3ProngData(jet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngData, "Fill 3prong imformation for data jets", false); + + void processSV3ProngDataMult(soa::Filtered::iterator const& collision, soa::Join const& jets, aod::DataSecondaryVertex3Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float scaledFT0M = getScaledFT0M(multFT0A, multFT0C); + registry.fill(HIST("h_event_mult"), scaledFT0M); + for (auto const& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + continue; + } + if (!isAcceptedJet(jet)) { + continue; + } + fillHistogramSV3ProngDataMult(collision, jet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngDataMult, "Fill 3prong 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + 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); + + void processSV3ProngMCDMult(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, aod::MCDSecondaryVertex3Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float scaledFT0M = getScaledFT0M(multFT0A, multFT0C); + registry.fill(HIST("h_event_mult"), scaledFT0M); + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramSV3ProngMCDMult(collision, mcdjet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCDMult, "Fill 3prong imformation for mcd jets with multiplicity", false); + + void processSV3ProngMCDMultWeighted(soa::Filtered::iterator const& collision, soa::Join const& mcdjets, aod::MCDSecondaryVertex3Prongs const& prongs) + { + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float scaledFT0M = getScaledFT0M(multFT0A, multFT0C); + registry.fill(HIST("h_event_mult"), scaledFT0M); + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + fillHistogramSV3ProngMCDMult(collision, mcdjet, prongs, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCDMultWeighted, "Fill 3prong imformation for mcd jets with multiplicity weighted", false); + + void processSV3ProngMCPMCDMatchedMult(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; + } + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float scaledFT0M = getScaledFT0M(multFT0A, multFT0C); + registry.fill(HIST("h_event_mult"), scaledFT0M); + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) { + continue; + } + if (!doprocessSV3ProngMCDMult) + fillHistogramSV3ProngMCDMult(collision, mcdjet, prongs); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCPMCDMatchedMult, "Fill 3prong imformation for mcd jets matched with multiplicity", false); + + void processSV3ProngMCPMCDMatchedMultWeighted(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; + } + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float scaledFT0M = getScaledFT0M(multFT0A, multFT0C); + registry.fill(HIST("h_event_mult"), scaledFT0M); + for (auto const& mcdjet : mcdjets) { + if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaCuts->at(0), jetEtaCuts->at(1), trackCuts->at(2), trackCuts->at(3))) { + continue; + } + if (!isAcceptedJet(mcdjet)) { + continue; + } + if (!mcdjet.has_matchedJetGeo()) { + continue; + } + if (!doprocessSV3ProngMCDMultWeighted) + fillHistogramSV3ProngMCDMult(collision, mcdjet, prongs, mcdjet.eventWeight()); + } + } + PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCPMCDMatchedMultWeighted, "Fill 3prong imformation for mcd jets matched with multiplicity weightd", 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 (templated struct) +} diff --git a/PWGJE/Tasks/jetTriggerChargedQa.cxx b/PWGJE/Tasks/jetTriggerChargedQa.cxx new file mode 100644 index 00000000000..d8b795aa1d6 --- /dev/null +++ b/PWGJE/Tasks/jetTriggerChargedQa.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. + +/// \author Filip Krizek +/// \author Kotliarov Artem +/// \file jetTriggerChargedQa.cxx +/// \brief QA of trigger performance for charged jets + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/EventSelection.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include + +#include +#include +#include + +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 / std::pow(tracPt, 1.1f); +} + +// What this task should do +// Event by event fill +// 1) pT spectrum of tracks in TPC volume +// 2) pT spectrum of jets in fiducial volume +// 3) leading jet pT versus leading track pT both in TPC volume +// We want output from +// a) minimum bias events +// b) from events selected by EPN +// It would be good to run it for several jet radii e.g. 0.2, 0.4, 0.6 + +struct JetTriggerChargedQa { + + 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 cfgTrackPhiMinCut{"cfgTrackPhiMinCut", -999, "track min phi cut"}; + Configurable cfgTrackPhiMaxCut{"cfgTrackPhiMaxCut", 999, "track max phi cut"}; + Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; + + Configurable bLowPtTrigger{"bLowPtTrigger", false, "charged jet low pT trigger selection"}; + 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{"bAddSupplementHistosToOutput", false, "add supplementary histos to the output"}; + Configurable bStudyPhiTrack{"bStudyPhiTrack", false, "add histos for detailed study of track phi distribution"}; + + Configurable phiAngleRestriction{"phiAngleRestriction", 0.3, "angle to restrict track phi for plotting tpc momentum"}; + Configurable dcaXYMultFact{"dcaXYMultFact", 3., "mult factor to relax pT dependent dcaXY cut for quality tracks"}; + Configurable dcaZCut{"dcaZCut", 3., "cut on dcaZ for quality tracks"}; + + float twoPi = constants::math::TwoPI; + ConfigurableAxis dcaXYBinning{"dcaXYBinning", {100, -5., 5.}, ""}; + ConfigurableAxis dcaZBinning{"dcaZBinning", {100, -3., 3.}, ""}; + + ConfigurableAxis xPhiAxis{"xPhiAxis", {40, 0., twoPi}, ""}; + ConfigurableAxis yQ1pTAxis{"yQ1pTAxis", {200, -0.5, 0.5}, ""}; + + float fiducialVolume = 0.0; // 0.9 - jetR + + HistogramRegistry spectra; + + std::vector eventSelectionBits; + int trackSelection = -1; + + void init(InitContext&) + { + fiducialVolume = static_cast(cfgTPCVolume) - static_cast(cfgJetR); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(evSel)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + + // Basic histos + spectra.add("vertexZ", "z vertex", kTH1F, {{60, -12., 12.}}); + spectra.add("ptphiTrackInclGood", "pT vs phi inclusive good tracks", kTH2F, {{100, 0., 100.}, {40, 0, twoPi}}); + spectra.add("ptetaTrackInclGood", "pT vs eta inclusive good tracks", kTH2F, {{100, 0., 100.}, {40, -1., 1.}}); + spectra.add("ptLeadingTrack", "pT leading track", kTH1F, {{100, 0., 100.}}); + spectra.add("ptJetChInclFidVol", "inclusive charged jet pT in fiducial volume", kTH1F, {{200, 0., 200.}}); + spectra.add("ptphiJetChInclFidVol", "inclusive charged jet pT vs phi in fiducial volume", kTH2F, {{100, 0., 100.}, {40, 0, twoPi}}); + spectra.add("ptphiJetChInclFullVol", "inclusive charged jet pT vs phi in full TPC volume", kTH2F, {{100, 0., 100.}, {40, 0, twoPi}}); + spectra.add("ptetaJetChInclFidVol", "inclusive charged jet pT vs eta in fiducial volume", kTH2F, {{100, 0., 100.}, {40, -1., 1.}}); + spectra.add("ptetaJetChInclFullVol", "inclusive charged jet pT vs eta in full TPC volume", kTH2F, {{100, 0., 100.}, {40, -1., 1.}}); + spectra.add("ptetaLeadingJetFullVol", "pT vs eta leading jet", kTH2F, {{100, 0., 100.}, {40, -1., 1.}}); + spectra.add("ptphiLeadingJetFullVol", "pT vs phi leading jet", kTH2F, {{100, 0., 100.}, {40, 0, twoPi}}); + + // Supplementary plots + if (bAddSupplementHistosToOutput) { + spectra.add("ptJetChInclFullVol", "inclusive charged jet pT in full volume", kTH1F, {{200, 0., 200.}}); + spectra.add("phietaTrackAllInclGood", "phi vs eta all inclusive good tracks", kTH2F, {{80, -1., 1.}, {40, 0, twoPi}}); + spectra.add("phietaTrackHighPtInclGood", "phi vs eta inclusive good tracks with pT > 10 GeV", kTH2F, {{40, -1., 1.}, {40, 0, twoPi}}); + spectra.add("phietaJetChInclFidVol", "inclusive charged jet phi vs eta in fiducial volume", kTH2F, {{40, -1., 1.}, {40, 0, twoPi}}); + spectra.add("phietaJetChInclFullVol", "inclusive charged jet phi vs eta in full TPC volume", kTH2F, {{40, -1., 1.}, {40, 0, twoPi}}); + spectra.add("phietaJetChInclHighPtFidVol", "inclusive charged jet phi vs eta in fiducial volume", kTH2F, {{40, -1., 1.}, {40, 0, twoPi}}); + spectra.add("phietaJetChInclHighPtFullVol", "inclusive charged jet phi vs eta in full TPC volume", kTH2F, {{40, -1., 1.}, {40, 0, twoPi}}); + spectra.add("ptetaLeadingTrack", "pT vs eta leading tracks", kTH2F, {{100, 0., 100.}, {40, -1., 1.}}); + spectra.add("ptphiLeadingTrack", "pT vs phi leading tracks", kTH2F, {{100, 0., 100.}, {40, 0, twoPi}}); + spectra.add("jetAreaFullVol", "area of all jets in full TPC volume", kTH2F, {{100, 0., 100.}, {50, 0., 2.}}); + spectra.add("jetAreaFidVol", "area of all jets in fiducial volume", kTH2F, {{100, 0., 100.}, {50, 0., 2.}}); + spectra.add("fLeadJetChPtVsLeadingTrack", "inclusive charged jet pT in TPC volume", kTH2F, {{100, 0., 100.}, {100, 0., 100.}}); + } + + // Study of non-uniformity of phi distribution of tracks + if (bStudyPhiTrack) { + spectra.add("globalP_tpcglobalPDiff_withoutcuts", "difference of global and TPC inner momentum vs global momentum without any selection applied", kTH2F, {{100, 0., 100.}, {200, -100., 100.}}); + spectra.add("globalP_tpcglobalPDiff", "difference of global and TPC inner momentum vs global momentum with selection applied", kTH2F, {{100, 0., 100.}, {200, -100., 100.}}); + spectra.add("global1overP_tpcglobalPDiff", "difference of global and TPC inner momentum vs global momentum with selection applied", kTH2F, {{100, 0., 100.}, {125, -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", 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", 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", 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, {dcaXYBinning, {40, 0., twoPi}, {100, 0., 100.}}); + spectra.add("DCAz_track_Phi_pT", "track DCAz vs phi & pT of tracks w. nITSClusters #geq 4", kTH3F, {dcaZBinning, {40, 0., twoPi}, {100, 0., 100.}}); + spectra.add("nITSClusters_TrackPt", "Number of ITS hits vs phi & pT of tracks", kTH3F, {{7, 1., 8.}, {40, 0., twoPi}, {100, 0., 100.}}); + spectra.add("ptphiQualityTracks", "pT vs phi of quality tracks", kTH2F, {{100, 0., 100.}, {40, 0, twoPi}}); + spectra.add("ptphiAllTracks", "pT vs phi of all tracks", kTH2F, {{100, 0., 100.}, {40, 0, twoPi}}); + spectra.add("phi_Q1pT", "Track phi vs. q/pT", kTH2F, {xPhiAxis, yQ1pTAxis}); + } + } + + // declare filters on collisions + Filter collisionFilter = (nabs(aod::jcollision::posZ) < static_cast(cfgVertexCut)); + + // declare filters on tracks + 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 = (aod::jet::r == nround(cfgJetR.node() * 100.0f)); + + void process(FilteredColl const& collision, FilteredJTracks const& tracks, FilteredJets const& jets, JoinedTracks const&) + { + + if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits(static_cast("NoTimeFrameBorder")))) { + return; + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { + return; + } + + 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)); + + if (bLowPtJet || bHighPtJet || bLowPtTrack || bHighPtTrack || bMinimumBias) { + // bLowPtTrigger=1 and bHighPtTrigger=0 --> fill histos with low trigger only + // bLowPtTrigger=0 and bHighPtTrigger=1 --> fill histos with high trigger only + // bLowPtTrigger=1 and bHighPtTrigger=1 --> fill histos with mixture of low and high trigger + // bTrackLowPtTrigger=1 --> fill histos for low pt track trigger + // bTrackHighPtTrigger=1 --> fill histos for high pt track trigger + // bLowPtTrigger=0 and bHighPtTrigger=0 and bTrackLowPtTrigger=0 and bTrackHighPtTrigger=0 --> fill histos with minimum bias ie. ignore trigger decision + + float leadingJetPt = -1.0; + float leadingJetEta = -2.0; + float leadingJetPhi = -1.0; + float leadingTrackPt = -1.0; + float leadingTrackEta = -2.0; + float leadingTrackPhi = -1.0; + + spectra.fill(HIST("vertexZ"), collision.posZ()); // Inclusive Track Cross TPC Rows + + // loop over filtered tracks in full TPC volume having pT > 100 MeV + for (auto const& track : tracks) { + + auto const& originalTrack = track.track_as(); + + if (bStudyPhiTrack) { + + spectra.fill(HIST("globalP_tpcglobalPDiff_withoutcuts"), track.p(), track.p() - originalTrack.tpcInnerParam()); + spectra.fill(HIST("ptphiAllTracks"), track.pt(), track.phi()); + + if (std::fabs(track.phi() - constants::math::PI) < phiAngleRestriction) { + spectra.fill(HIST("globalP_tpcglobalPDiff_withoutcuts_phirestrict"), track.p(), track.p() - originalTrack.tpcInnerParam()); + } + } + + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) + continue; + + spectra.fill(HIST("ptphiTrackInclGood"), track.pt(), track.phi()); // Inclusive Track pT vs phi spectrum in TPC volume + spectra.fill(HIST("ptetaTrackInclGood"), track.pt(), track.eta()); // Inclusive Track pT vs eta spectrum in TPC volume + + if (bAddSupplementHistosToOutput) { + spectra.fill(HIST("phietaTrackAllInclGood"), track.eta(), track.phi()); // Inclusive Track pT vs eta spectrum in TPC volume + + float trackPtCut = 5.0; + if (track.pt() > trackPtCut) { + spectra.fill(HIST("phietaTrackHighPtInclGood"), track.eta(), track.phi()); // Inclusive Track pT vs eta spectrum in TPC volume + } + } + + if (track.pt() > leadingTrackPt) { // Find leading track pT in full TPC volume + leadingTrackPt = track.pt(); + leadingTrackEta = track.eta(); + leadingTrackPhi = track.phi(); + } + + if (bStudyPhiTrack) { + spectra.fill(HIST("phi_Q1pT"), originalTrack.phi(), originalTrack.sign() / originalTrack.pt()); + spectra.fill(HIST("ptphiQualityTracks"), track.pt(), track.phi()); + + bool bDcaCondition = (std::fabs(track.dcaZ()) < dcaZCut) && (std::fabs(track.dcaXY()) < dcaXYMultFact * dcaXYPtCut(track.pt())); + + int nITSClusters = 4; + if (originalTrack.itsNCls() >= nITSClusters && 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 (std::fabs(track.phi() - constants::math::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()); + } + } + } + } + + if (leadingTrackPt > -1.) { + spectra.fill(HIST("ptLeadingTrack"), leadingTrackPt); + } + + if (bAddSupplementHistosToOutput) { + if (leadingTrackPt > -1.) { + spectra.fill(HIST("ptphiLeadingTrack"), leadingTrackPt, leadingTrackPhi); + spectra.fill(HIST("ptetaLeadingTrack"), leadingTrackPt, leadingTrackEta); + } + } + + // Find leading jet pT in full TPC volume + for (const auto& jet : jets) { + if (std::fabs(jet.eta()) < static_cast(cfgTPCVolume)) { + + if (jet.pt() > leadingJetPt) { + leadingJetPt = jet.pt(); + leadingJetEta = jet.eta(); + leadingJetPhi = jet.phi(); + } + } + } + + if (leadingJetPt > -1.) { + spectra.fill(HIST("ptphiLeadingJetFullVol"), leadingJetPt, leadingJetPhi); + spectra.fill(HIST("ptetaLeadingJetFullVol"), leadingJetPt, leadingJetEta); + } + + if (bAddSupplementHistosToOutput) { + if (leadingJetPt > -1. && leadingTrackPt > -1.) { + spectra.fill(HIST("fLeadJetChPtVsLeadingTrack"), leadingTrackPt, leadingJetPt); // leading jet pT versus leading track pT + } + } + + // Inclusive Jet pT spectrum in Fiducial volume + for (const auto& jet : jets) { + if (std::fabs(jet.eta()) < fiducialVolume) { + spectra.fill(HIST("ptJetChInclFidVol"), jet.pt()); + spectra.fill(HIST("ptphiJetChInclFidVol"), jet.pt(), jet.phi()); + spectra.fill(HIST("ptetaJetChInclFidVol"), jet.pt(), jet.eta()); + + if (bAddSupplementHistosToOutput) { + spectra.fill(HIST("phietaJetChInclFidVol"), jet.eta(), jet.phi()); + + float jetPtCut = 10.0; + if (jet.pt() > jetPtCut) { + spectra.fill(HIST("phietaJetChInclHighPtFidVol"), jet.eta(), jet.phi()); + } + spectra.fill(HIST("jetAreaFidVol"), jet.pt(), jet.area()); + } + } + + if (std::fabs(jet.eta()) < static_cast(cfgTPCVolume)) { + spectra.fill(HIST("ptphiJetChInclFullVol"), jet.pt(), jet.phi()); + spectra.fill(HIST("ptetaJetChInclFullVol"), jet.pt(), jet.eta()); + + if (bAddSupplementHistosToOutput) { + spectra.fill(HIST("ptJetChInclFullVol"), jet.pt()); + + spectra.fill(HIST("phietaJetChInclFullVol"), jet.eta(), jet.phi()); + + float jetPtCut = 10.0; + if (jet.pt() > jetPtCut) { + spectra.fill(HIST("phietaJetChInclHighPtFullVol"), jet.eta(), jet.phi()); + } + spectra.fill(HIST("jetAreaFullVol"), jet.pt(), jet.area()); + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGJE/Tasks/jetTutorial.cxx b/PWGJE/Tasks/jetTutorial.cxx index 0065726bae2..48742399bf7 100644 --- a/PWGJE/Tasks/jetTutorial.cxx +++ b/PWGJE/Tasks/jetTutorial.cxx @@ -9,32 +9,39 @@ // 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include -#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/DataModel/Jet.h" +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -#include "Framework/runDataProcessing.h" - struct JetTutorialTask { HistogramRegistry registry{"registry", {{"h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}}, @@ -45,12 +52,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 +75,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 +122,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 +143,168 @@ 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& 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_eta"), jet.eta()); + registry.fill(HIST("h_jet_phi"), jet.phi()); + } + } + PROCESS_SWITCH(JetTutorialTask, processDataCharged, "charged jets in data", false); - void processDataCharged(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, processDataCharged, "jets data", true); + PROCESS_SWITCH(JetTutorialTask, processMCDetectorLevelCharged, "charged jets in detector level MC", false); - void processMCDetectorLevelCharged(soa::Filtered::iterator const& jet) + void processMCDetectorLevelWeightedCharged(soa::Filtered::iterator const& collision, aod::JetMcCollisions const&, 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(), 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, processMCDetectorLevelCharged, "jets on detector level MC", false); + PROCESS_SWITCH(JetTutorialTask, processMCDetectorLevelWeightedCharged, "charged jets in weighted detector level MC", false); - void processMCParticleLevel(soa::Filtered::iterator const& jet) + void processMCParticleLevelCharged(soa::Filtered::iterator const& mcCollision, 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()); + 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, processMCParticleLevel, "jets on particle level MC", false); + PROCESS_SWITCH(JetTutorialTask, processMCParticleLevelCharged, "charged jets in particle level MC", false); - void processMCCharged(JetCollision const&, soa::Filtered const& mcdjets, soa::Filtered const& mcpjets) + 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, + aod::JetMcCollisions const&, 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_phi"), mcpjet.phi(), mcdjet.phi(), collision.mcCollision().weight()); + registry.fill(HIST("h_matched_jets_eta"), 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 +312,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 +328,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..eeccd409d26 100644 --- a/PWGJE/Tasks/jetTutorialSkeleton.cxx +++ b/PWGJE/Tasks/jetTutorialSkeleton.cxx @@ -9,32 +9,29 @@ // 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + #include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include +#include +#include +#include -#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/DataModel/Jet.h" - +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -#include "Framework/runDataProcessing.h" - struct JetTutorialSkeletonTask { HistogramRegistry registry{"registry", {{"h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}}, @@ -45,12 +42,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 +65,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 94% rename from PWGJE/Tasks/jetvalidationqa.cxx rename to PWGJE/Tasks/jetValidationQA.cxx index 1ef731bad09..4ccd260f47e 100644 --- a/PWGJE/Tasks/jetvalidationqa.cxx +++ b/PWGJE/Tasks/jetValidationQA.cxx @@ -12,18 +12,23 @@ /// \author Johanna Lömker // \since Dec 2022 -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include +#include +#include +#include -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" - -#include "Common/DataModel/EventSelection.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" +#include +#include using namespace o2; using namespace o2::framework; @@ -169,13 +174,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 +244,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 +309,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 +442,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 +478,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,28 +496,28 @@ struct mcJetTrackCollisionQa { for (const auto& genJet : mcPartJets) { if (genJet.mcCollisionId() == collision.globalIndex()) { fillMcPartJets(genJet); - for (auto& mcParticle : genJet.tracks_as()) { + for (const 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()) { fillMcDetJets(detJet); - for (auto& detConst : detJet.tracks_as()) { + for (const auto& detConst : detJet.tracks_as()) { fillMcDetJetConstituents(detConst); } } } // 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,26 +530,26 @@ struct mcJetTrackCollisionQa { for (const auto& genJet : mcPartJets) { if (genJet.mcCollisionId() == collision.globalIndex()) { fillMcPartJets(genJet); - for (auto& mcParticle : genJet.tracks_as()) { + for (const 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()) { fillMcDetJets(detJet); - for (auto& detConst : detJet.tracks_as()) { + for (const auto& detConst : detJet.tracks_as()) { fillMcDetJetConstituents(detConst); } } } // 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 d08a3935431..00000000000 --- a/PWGJE/Tasks/jetfragmentation.cxx +++ /dev/null @@ -1,2140 +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 V0 fragmentation -// -/// \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" -#include "PWGJE/Core/JetFindingUtilities.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 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"}; - - Configurable evSel{"evSel", "sel8WithoutTimeFrameBorderCut", "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) { - 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}); - } - if (doprocessDataRun3 || doprocessDataV0Frag || doprocessDataV0JetsFrag) { - registry.add("data/jets/jetPtEtaPhi", "Jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {jetPtAxis, etaAxis, phiAxis}); - } - if (doprocessDataRun3 || doprocessDataV0Frag) { - 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 || doprocessDataV0JetsFrag) { - 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 || doprocessDataV0JetsFrag - - 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}); - } - - if (doprocessDataV0Frag || doprocessDataV0JetsFrag) { - 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 || doprocessDataV0JetsFrag - - if (doprocessMcP || doprocessMcMatchedV0JetsFrag) { - registry.add("particle-level/jets/partJetPtEtaPhi", "Particle level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {partJetPtAxis, partEtaAxis, partPhiAxis}); - } - 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/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 || doprocessMcMatchedV0JetsFrag) { - registry.add("detector-level/jets/detJetPtEtaPhi", "Detector level jet #it{p}_{T}, #eta, #phi", HistType::kTH3D, {detJetPtAxis, detEtaAxis, detPhiAxis}); - } - 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/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 || doprocessMcMatchedV0JetsFrag) { - 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 || doprocessMcMatchedV0JetsFrag) { - registry.add("matching/V0/nV0sEvent", "nV0sDet per event", HistType::kTH1D, {v0Count}); - } // doprocessMcMatchedV0 || doprocessMcMatchedV0Frag - - if (doprocessMcMatchedV0 || doprocessMcMatchedV0JetsFrag) { - 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}); - } - if (doprocessMcMatchedV0Frag || doprocessMcMatchedV0JetsFrag) { - 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 - - if (doprocessMcMatchedV0JetsFrag) { - registry.add("matching/V0/V0PosPartPtRatioPtRelDiffPt", "V0PosPartPtRatioRelDiffPt", HistType::kTH3D, {trackPtAxis, ptRatioAxis, ptTrackRelDiffAxis}); - registry.add("matching/V0/V0NegPartPtRatioPtRelDiffPt", "V0NegPartPtRatioRelDiffPt", HistType::kTH3D, {trackPtAxis, ptRatioAxis, ptTrackRelDiffAxis}); - - registry.add("matching/jets/V0/partJetPtDetJetPtPartV0PtPosPtRatioPtRelDiffPt", "V0PtPosPartPtRatioRelDiffPt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, V0PtAxis, trackPtAxis, ptRatioAxis, ptTrackRelDiffAxis}); - registry.add("matching/jets/V0/partJetPtDetJetPtPartV0PtNegPtRatioPtRelDiffPt", "V0PtNegPartPtRatioRelDiffPt", HistType::kTHnSparseD, {partJetPtAxis, detJetPtAxis, V0PtAxis, trackPtAxis, ptRatioAxis, ptTrackRelDiffAxis}); - } - } // init - - template - bool JetContainsV0s(JetType const& jet) - { - return (jet.candidatesIds().size() > 0); - } - template - bool V0sAreMatched(T const& v0, U const& particle, V const& /*tracks*/) - { - 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 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; - } - - // TODO: Can probably be made simpler/shorter by using V0MCLabels - 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 fillDataJetHistograms(T const& jet) - { - registry.fill(HIST("data/jets/jetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); - } - template - void fillDataFragHistograms(T const& jet) - { - 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) - { - 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 fillMatchingV0Histograms(CollisionType const& collision, V0Type const& v0, particleType const& particle, double weight = 1.) - { - 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/V0/V0PartPtDetPt"), particle.pt(), v0.pt()); - registry.fill(HIST("matching/V0/V0PartPtRatioPtRelDiffPt"), particle.pt(), v0.pt() / particle.pt(), (v0.pt() - particle.pt()) / particle.pt()); - - if (TMath::Abs(particle.pdgCode()) == 310) { // K0S - registry.fill(HIST("matching/V0/K0SPtEtaPhi"), particle.pt(), v0.pt(), v0.eta(), v0.phi()); - 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()); - 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 = ReflectedMass(v0, true); - registry.fill(HIST("matching/V0/Lambda0Reflection"), 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()); - 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 = ReflectedMass(v0, false); - registry.fill(HIST("matching/V0/antiLambda0Reflection"), particle.pt(), v0.pt(), v0.mK0Short(), v0.mLambda(), v0.mAntiLambda(), reflectedMass, weight); - } - } - - template - void fillMatchingV0DauHistograms(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/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); - } - template - 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(), posTrack.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(), negTrack.pt(), negTrack.pt() / negPart.pt(), (negTrack.pt() - negPart.pt()) / negPart.pt(), weight); - } - - template - void fillMatchingV0FragHistograms(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 fillMCDJetHistograms(T const& jet, double weight = 1.) - { - registry.fill(HIST("detector-level/jets/detJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); - } - template - void fillMCDFragHistograms(Jet const& jet, double weight = 1.) - { - 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 fillMCPJetHistograms(T const& jet, double weight = 1.) - { - registry.fill(HIST("particle-level/jets/partJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi(), weight); - } - template - void fillMCPFragHistograms(Jet const& jet, double weight = 1.) - { - 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&, - MCDJetsWithConstituents 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++; - fillMCDJetHistograms(jet, weight); - fillMCDFragHistograms(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, - MCPJetsWithConstituents 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++; - fillMCPJetHistograms(jet, weight); - fillMCPFragHistograms(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 (!jetfindingutilities::isInEtaAcceptance(jet, dataJetEtaMin, dataJetEtaMax)) { - continue; - } - nJets++; - fillDataJetHistograms(jet); - fillDataFragHistograms(jet); - } - registry.fill(HIST("data/nJetsnTracks"), nJets, nTracks); - registry.fill(HIST("data/collision/collisionVtxZ"), collision.posZ()); - } - PROCESS_SWITCH(JetFragmentation, processDataRun3, "Run 3 Data", false); - - void processMcMatched(soa::Filtered::iterator const& collision, - MatchedMCDJetsWithConstituents const&, - JetTracksMCD const&, - JetMcCollisions const&, - MatchedMCPJetsWithConstituents 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); - - // Should take in JCollisions? - 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 (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { - // 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, - MatchedMCDJetsWithConstituents const&, - JetTracksMCD const&, - soa::Join const& allV0s, - JetMcCollisions const&, - MatchedMCPJetsWithConstituents 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 (!((TMath::Abs(particle.pdgCode()) == 310) || (TMath::Abs(particle.pdgCode()) == 3122))) { - fillMatchingV0Fake(collision, detJet, v0, weight); - continue; - } - // Found a matched V0 in the jet - nV0inJet++; - fillMatchingV0FragHistograms(collision, detJet, partJet, v0, particle, weight); - if (TMath::Abs(particle.pdgCode()) == 310) { - nK0SinJet++; - } else if (particle.pdgCode() == 3122) { - nLambdainJet++; - } else if (particle.pdgCode() == -3122) { - nAntiLambdainJet++; - } - } // v0 loop - registry.fill(HIST("matching/jets/V0/jetPtnV0Matched"), partJet.pt(), nV0inJet, weight); - registry.fill(HIST("matching/jets/V0/jetPtnV0MatchednK0SnLambdanAntiLambda"), partJet.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 (!((TMath::Abs(particle.pdgCode()) == 310) || TMath::Abs((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) - { - if (!collision.sel8()) { - return; - } - registry.fill(HIST("data/V0/nV0sEvent"), V0s.size()); - fillDataV0Histograms(collision, V0s); - } - 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) - { - 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& 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); - for (const auto& jet : jets) { - if ((jet.eta() < v0EtaMin + jet.r() * 1e-2) || (jet.eta() > v0EtaMax - jet.r() * 1e-2)) { - continue; - } - fillDataJetHistograms(jet); - fillDataFragHistograms(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); - - // ---------------- V0 jets ---------------- - void processDataV0JetsFrag(soa::Filtered::iterator const& jcoll, soa::Join const& v0jets, CandidatesV0Data const& v0s) - { - if (!jetderiveddatautilities::selectCollision(jcoll, eventSelection)) { - return; - } - registry.fill(HIST("data/V0/nV0sEvent"), v0s.size()); - fillDataV0Histograms(jcoll, v0s); - - for (const auto& jet : v0jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, -99., -99., v0EtaMin, v0EtaMax)) { - continue; - } - // Double check if the jet contains V0s - if (!JetContainsV0s(jet)) { - continue; - } - fillDataJetHistograms(jet); - - int nV0inJet = 0, nLambdainJet = 0, nAntiLambdainJet = 0, nK0SinJet = 0; - for (const auto& v0 : jet.candidates_as()) { - nV0inJet++; - fillDataV0FragHistograms(jcoll, jet, v0); - if (IsK0SCandidate(jcoll, v0)) { - nK0SinJet++; - } - if (IsLambdaCandidate(jcoll, v0)) { - nLambdainJet++; - } - if (IsAntiLambdaCandidate(jcoll, v0)) { - nAntiLambdainJet++; - } - } - registry.fill(HIST("data/jets/V0/jetPtnV0nK0SnLambdanAntiLambda"), jet.pt(), nV0inJet, nK0SinJet, nLambdainJet, nAntiLambdainJet); - } // Jet loop - } - PROCESS_SWITCH(JetFragmentation, processDataV0JetsFrag, "Data V0 jets fragmentation", false); - - void processMcMatchedV0JetsFrag(soa::Filtered::iterator const& jcoll, JetMcCollisions const&, MatchedMCDV0JetsWithConstituents const& v0jetsMCD, MatchedMCPV0JetsWithConstituents const& v0jetsMCP, soa::Join const& v0s, CandidatesV0MCP const& pv0s, JetTracksMCD const& jTracks, JetParticles const&) - { - if (!jcoll.has_mcCollision()) { - return; - } - if (!jetderiveddatautilities::selectCollision(jcoll, eventSelection)) { - return; - } - double weight = jcoll.mcCollision().weight(); - registry.fill(HIST("matching/V0/nV0sEvent"), v0s.size()); - - // TODO: This is not very efficient - for (const auto& v0 : v0s) { - for (const auto& pv0 : pv0s) { - if (V0sAreMatched(v0, pv0, jTracks)) { - fillMatchingV0Histograms(jcoll, v0, pv0, weight); - fillMatchingV0DauHistograms(v0, pv0, 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>()) { - fillMatchingV0Fake(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()) { - fillMatchingV0Fake(jcoll, 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 (TMath::Abs(partV0.pdgCode()) == 310) { - nK0SinJet++; - } else if (partV0.pdgCode() == 3122) { - nLambdainJet++; - } else if (partV0.pdgCode() == -3122) { - nAntiLambdainJet++; - } - break; - } // if matched - } // partV0 loop - - if (!isV0Matched) { - fillMatchingV0Fake(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); -}; - -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 bd564e4bc65..00000000000 --- a/PWGJE/Tasks/jetsubstructure.cxx +++ /dev/null @@ -1,232 +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/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; - - Configurable zCut{"zCut", 0.1, "soft drop z cut"}; - Configurable beta{"beta", 0.0, "soft drop beta"}; - 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 pairPtVec; - std::vector pairEnergyVec; - std::vector pairThetaVec; - - 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) - { - 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); - } - 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*/) - { - pairPtVec.clear(); - pairEnergyVec.clear(); - pairThetaVec.clear(); - std::vector tracksVec; - for (auto const& constituent : jet.template tracks_as()) { - if (constituent.pt() >= pairConstituentPtMin) { - tracksVec.push_back(constituent); - } - } - if (tracksVec.size() >= 2) { - for (typename std::vector::size_type track1Index = 0; track1Index < tracksVec.size() - 1; track1Index++) { - for (typename std::vector::size_type track2Index = track1Index + 1; track2Index < tracksVec.size(); track2Index++) { - pairPtVec.push_back(tracksVec.at(track1Index).pt() * tracksVec.at(track2Index).pt()); - pairEnergyVec.push_back(tracksVec.at(track1Index).energy() * tracksVec.at(track2Index).energy()); - pairThetaVec.push_back(jetutilities::deltaR(tracksVec.at(track1Index), tracksVec.at(track2Index))); - } - } - } - } - - 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); - jetPairing(jet, tracks); - outputTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2], pairPtVec, pairEnergyVec, pairThetaVec); - } - - 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); - jetPairing(jet, particles); - jetSubstructureMCPTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2], pairPtVec, pairEnergyVec, pairThetaVec); - } - 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 07eb5b9120b..00000000000 --- a/PWGJE/Tasks/jetsubstructurehf.cxx +++ /dev/null @@ -1,301 +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 "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; - -// 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"}; - 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 pairPtVec; - std::vector pairEnergyVec; - std::vector pairThetaVec; - - 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(); - } - - template - void jetReclustering(T const& jet) - { - 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); - } - 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*/) - { - pairPtVec.clear(); - pairEnergyVec.clear(); - pairThetaVec.clear(); - std::vector> tracksVec; - std::vector> candidatesVec; - for (auto& constituent : jet.template tracks_as()) { - if (constituent.pt() >= pairConstituentPtMin) { - tracksVec.push_back(constituent); - } - } - for (auto& candidate : jet.template candidates_as()) { - candidatesVec.push_back(candidate); - } - if (tracksVec.size() >= 2) { - for (typename std::vector>::size_type track1Index = 0; track1Index < tracksVec.size() - 1; track1Index++) { - for (typename std::vector>::size_type track2Index = track1Index + 1; track2Index < tracksVec.size(); track2Index++) { - pairPtVec.push_back(tracksVec.at(track1Index).pt() * tracksVec.at(track2Index).pt()); - pairEnergyVec.push_back(tracksVec.at(track1Index).energy() * tracksVec.at(track2Index).energy()); - pairThetaVec.push_back(jetutilities::deltaR(tracksVec.at(track1Index), tracksVec.at(track2Index))); - } - } - } - if (candidatesVec.size() >= 2) { - for (typename std::vector>::size_type candidate1Index = 0; candidate1Index < candidatesVec.size() - 1; candidate1Index++) { - for (typename std::vector>::size_type candidate2Index = candidate1Index + 1; candidate2Index < candidatesVec.size(); candidate2Index++) { - pairPtVec.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)); - pairEnergyVec.push_back(candidate1Energy * candidate2Energy); - pairThetaVec.push_back(jetutilities::deltaR(candidatesVec.at(candidate1Index), candidatesVec.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++) { - pairPtVec.push_back(candidatesVec.at(candidateIndex).pt() * tracksVec.at(trackIndex).pt()); - auto candidateEnergy = std::sqrt((candidatesVec.at(candidateIndex).p() * candidatesVec.at(candidateIndex).p()) + (candMass * candMass)); - pairEnergyVec.push_back(candidateEnergy * tracksVec.at(trackIndex).energy()); - pairThetaVec.push_back(jetutilities::deltaR(candidatesVec.at(candidateIndex), tracksVec.at(trackIndex))); - } - } - } - } - - 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 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); - jetPairing(jet, tracks, candidates); - outputTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2], pairPtVec, pairEnergyVec, pairThetaVec); - } - - 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 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); - jetPairing(jet, particles, candidates); - jetSubstructureMCPTable(energyMotherVec, ptLeadingVec, ptSubLeadingVec, thetaVec, nSub[0], nSub[1], nSub[2], pairPtVec, pairEnergyVec, pairThetaVec); - } - 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>; -using JetSubstructureDielectron = JetSubstructureHFTask, soa::Join, soa::Join, soa::Join, CandidatesDielectronData, CandidatesDielectronMCP, aod::DielectronCJetSSs, aod::DielectronCMCDJetSSs, aod::DielectronCMCPJetSSs, aod::DielectronCEWSJetSSs, aod::JTrackDielectronSubs>; - -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-dielectron"})); - /* - - 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 dafa4d7bf1f..00000000000 --- a/PWGJE/Tasks/jetsubstructurehfoutput.cxx +++ /dev/null @@ -1,556 +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" -#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 { - 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 hfMcCollisionsTable; - Produces hfMcCollisionsMatchingTable; - 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"}; - - Configurable eventSelectionForCounting{"eventSelectionForCounting", "sel8", "choose event selection for collision counter"}; - - 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 jetRadiiValues; - - std::vector collisionFlag; - std::vector mcCollisionFlag; - - PresliceUnsorted> CollisionsPerMcCollision = aod::jmccollisionlb::mcCollisionId; - PresliceOptional D0CollisionsPerCollision = aod::jd0indices::collisionId; - PresliceOptional LcCollisionsPerCollision = aod::jlcindices::collisionId; - PresliceOptional DielectronCollisionsPerCollision = aod::jdielectronindices::collisionId; - PresliceOptional> D0McCollisionsPerMcCollision = aod::jd0indices::mcCollisionId; - PresliceOptional> LcMcCollisionsPerMcCollision = aod::jlcindices::mcCollisionId; - PresliceOptional DielectronMcCollisionsPerMcCollision = aod::jdielectronindices::mcCollisionId; - - int eventSelection = -1; - void init(InitContext const&) - { - jetRadiiValues = (std::vector)jetRadii; - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelectionForCounting)); - } - - template - void fillJetTables(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; - std::vector pairPtVec; - std::vector pairEnergyVec; - std::vector pairThetaVec; - auto energyMotherSpan = jet.energyMother(); - auto ptLeadingSpan = jet.ptLeading(); - auto ptSubLeadingSpan = jet.ptSubLeading(); - auto thetaSpan = jet.theta(); - auto pairPtSpan = jet.pairPt(); - auto pairEnergySpan = jet.pairEnergy(); - auto pairThetaSpan = jet.pairTheta(); - 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(pairPtSpan.begin(), pairPtSpan.end(), std::back_inserter(pairPtVec)); - std::copy(pairEnergySpan.begin(), pairEnergySpan.end(), std::back_inserter(pairEnergyVec)); - std::copy(pairThetaSpan.begin(), pairThetaSpan.end(), std::back_inserter(pairThetaVec)); - jetOutputTable(collisionIndex, candidateIndex, jet.pt(), jet.phi(), jet.eta(), jet.y(), jet.r(), 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(), pairPtVec, pairEnergyVec, pairThetaVec); - 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 candidates_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++; - } - fillJetTables(jet, candidate, collisionIndex, candidateIndex, jetOutputTable, jetSubstructureOutputTable, 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, jetEtaMin, jetEtaMax, trackEtaMin, 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; - int32_t candidateIndex = -1; - if constexpr (isMCP) { - auto hfMcCollisionIndex = candidateMcCollisionMapping.find(jetcandidateutilities::getMcCandidateCollisionId(candidate)); - if (hfMcCollisionIndex != candidateMcCollisionMapping.end()) { - candidateCollisionIndex = hfMcCollisionIndex->second; - } - jetcandidateutilities::fillCandidateMcTable(candidate, candidateCollisionIndex, hfParticlesTable, candidateIndex); - } else { - auto hfCollisionIndex = candidateCollisionMapping.find(jetcandidateutilities::getCandidateCollisionId(candidate)); - if (hfCollisionIndex != candidateCollisionMapping.end()) { - candidateCollisionIndex = hfCollisionIndex->second; - } - jetcandidateutilities::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); - } - } - } - } - - 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, jetEtaMin, jetEtaMax, trackEtaMin, 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, jetEtaMin, jetEtaMax, trackEtaMin, 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 = jetcandidateutilities::slicedPerCandidateCollision(hfCollisions, candidates, collision, D0CollisionsPerCollision, LcCollisionsPerCollision, D0CollisionsPerCollision, DielectronCollisionsPerCollision); // add Bplus later - int32_t candidateCollisionIndex = -1; - 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, hfCollisionsTable, candidateCollisionIndex); - candidateCollisionMapping.insert(std::make_pair(hfCollisionPerCollision.globalIndex(), hfCollisionsTable.lastIndex())); - } - } - } - } - if constexpr (isMC) { - for (const auto& mcCollision : mcCollisions) { - if (mcCollisionFlag[mcCollision.globalIndex()]) { - const auto hfMcCollisionsPerMcCollision = jetcandidateutilities::slicedPerCandidateCollision(hfMcCollisions, candidatesMCP, mcCollision, D0McCollisionsPerMcCollision, LcMcCollisionsPerMcCollision, D0McCollisionsPerMcCollision, DielectronMcCollisionsPerMcCollision); // add Bplus later - int32_t candidateMcCollisionIndex = -1; - 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, hfMcCollisionsTable, candidateMcCollisionIndex); - candidateMcCollisionMapping.insert(std::make_pair(hfMcCollisionPerMcCollision.globalIndex(), 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); - } - } - hfMcCollisionsMatchingTable(hfCollisionIDs); - } - } - } - } - } - } - - void processClearMaps(JetCollisions const&) - { - candidateMapping.clear(); - candidateCollisionMapping.clear(); - candidateMappingMCP.clear(); - jetMappingData.clear(); - jetMappingDataSub.clear(); - jetMappingMCD.clear(); - jetMappingMCP.clear(); - candidateCollisionMapping.clear(); - candidateMcCollisionMapping.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 readSelectedCollisionCounter = 0; - int writtenCollisionCounter = -1; - for (auto const& collision : collisions) { - readCollisionCounter++; - if (jetderiveddatautilities::selectCollision(collision, eventSelection)) { - readSelectedCollisionCounter++; - } - } - std::vector previousReadCounts; - std::vector previousReadSelectedCounts; - std::vector previousWrittenCounts; - int iPreviousDataFrame = 0; - for (const auto& collisionCount : collisionCounts) { - auto readCollisionCounterSpan = collisionCount.readCounts(); - auto readSelectedCollisionCounterSpan = collisionCount.readSelectedCounts(); - auto writtenCollisionCounterSpan = collisionCount.writtenCounts(); - if (iPreviousDataFrame == 0) { - std::copy(readCollisionCounterSpan.begin(), readCollisionCounterSpan.end(), std::back_inserter(previousReadCounts)); - std::copy(readSelectedCollisionCounterSpan.begin(), readSelectedCollisionCounterSpan.end(), std::back_inserter(previousReadSelectedCounts)); - std::copy(writtenCollisionCounterSpan.begin(), writtenCollisionCounterSpan.end(), std::back_inserter(previousWrittenCounts)); - } else { - for (unsigned int i = 0; i < previousReadCounts.size(); i++) { - previousReadCounts[i] += readCollisionCounterSpan[i]; - previousReadSelectedCounts[i] += readSelectedCollisionCounterSpan[i]; - previousWrittenCounts[i] += writtenCollisionCounterSpan[i]; - } - } - iPreviousDataFrame++; - } - previousReadCounts.push_back(readCollisionCounter); - previousReadSelectedCounts.push_back(readSelectedCollisionCounter); - previousWrittenCounts.push_back(writtenCollisionCounter); - storedCollisionCountsTable(previousReadCounts, previousReadSelectedCounts, previousWrittenCounts); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processCountCollisions, "process function that counts read in collisions", false); - - void processOutputCollisionsData(JetCollisions const& collisions, - JetTableData const& jets, - CandidateCollisionTable const& canidateCollisions, - CandidateTable const& candidates) - { - analyseHFCollisions(collisions, collisions, canidateCollisions, canidateCollisions, jets, jets, candidates, candidates, jetPtMinData); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCollisionsData, "hf collision output data", false); - - void processOutputCollisionsDataSub(JetCollisions const& collisions, - JetTableDataSub const& jets, - CandidateCollisionTable const& canidateCollisions, - CandidateTable const& candidates) - { - analyseHFCollisions(collisions, collisions, canidateCollisions, canidateCollisions, jets, jets, candidates, candidates, jetPtMinDataSub); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCollisionsDataSub, "hf collision output data eventwise constituent subtracted", false); - - void processOutputCollisionsMc(soa::Join const& collisions, - JetMcCollisions const& mcCollisions, - JetTableMCD const& jetsMCD, - JetTableMCP const& jetsMCP, - CandidateCollisionTable const& canidateCollisions, - CandidateMcCollisionTable const& canidateMcCollisions, - CandidateTableMCD const& candidatesMCD, - CandidateTableMCP const& candidatesMCP) - { - analyseHFCollisions(collisions, mcCollisions, canidateCollisions, canidateMcCollisions, jetsMCD, jetsMCP, candidatesMCD, candidatesMCP, jetPtMinMCD, jetPtMinMCP); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCollisionsMc, "hf collision output MC", false); - - void processOutputCollisionsMCPOnly(JetMcCollisions const& mcCollisions, - JetTableMCP const& jetsMCP, - CandidateMcCollisionTable const& canidateMcCollisions, - CandidateTableMCP const& candidatesMCP) - { - analyseHFCollisions(mcCollisions, mcCollisions, canidateMcCollisions, canidateMcCollisions, jetsMCP, jetsMCP, candidatesMCP, candidatesMCP, 0.0, jetPtMinMCP); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCollisionsMCPOnly, "hf collision output MCP only", false); - - void processOutputCandidatesData(JetCollision const&, - JetTableData const& jets, - CandidateTable const& candidates) - { - analyseCandidates(jets, candidates, candidateMapping, jetPtMinData); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesData, "hf candidate output data", false); - - void processOutputCandidatesDataSub(JetCollision const&, - JetTableDataSub const& jets, - CandidateTable const& candidates) - { - analyseCandidates(jets, candidates, candidateMapping, jetPtMinDataSub); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesDataSub, "hf candidate output data eventwise constituent subtracted", false); - - void processOutputCandidatesMCD(JetCollision const&, - JetTableMCD const& jets, - CandidateTableMCD const& candidates) - { - - analyseCandidates(jets, candidates, candidateMapping, jetPtMinMCD); - } - PROCESS_SWITCH(JetSubstructureHFOutputTask, processOutputCandidatesMCD, "hf candidate output MCD", false); - - void processOutputCandidatesMCP(JetMcCollision const&, - JetTableMCP const& jets, - CandidateTableMCP const& candidates) - { - analyseCandidates(jets, 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, CandidatesD0Data, CandidatesD0MCD, CandidatesD0MCP, aod::JTrackD0Subs, soa::Join, 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::StoredHfD0McCollBases, aod::StoredHfD0McRCollIds, aod::StoredHfD0PBases, aod::D0CollisionCounts>; -using JetSubstructureOutputLc = JetSubstructureHFOutputTask, CandidatesLcData, CandidatesLcMCD, CandidatesLcMCP, aod::JTrackLcSubs, soa::Join, 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::StoredHf3PMcCollBases, aod::StoredHf3PMcRCollIds, aod::StoredHf3PPBases, aod::LcCollisionCounts>; -// using JetSubstructureOutputBplus = JetSubstructureHFOutputTask, CandidatesBplusData, CandidatesBplusMCD, CandidatesBplusMCP, aod::JTrackBplusSubs, soa::Join, 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>; -using JetSubstructureOutputDielectron = JetSubstructureHFOutputTask, soa::Join, aod::DielectronCJetCOs, aod::DielectronCJetOs, aod::DielectronCJetSSOs, aod::DielectronCJetMOs, soa::Join, aod::DielectronCMCDJetCOs, aod::DielectronCMCDJetOs, aod::DielectronCMCDJetSSOs, aod::DielectronCMCDJetMOs, soa::Join, aod::DielectronCMCPJetCOs, aod::DielectronCMCPJetOs, aod::DielectronCMCPJetSSOs, aod::DielectronCMCPJetMOs, 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::StoredJDielectronMcCollisions, aod::JDielectron6Dummys, aod::StoredJDielectronMcs, aod::DielectronCollisionCounts>; - -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"})); - tasks.emplace_back(adaptAnalysisTask(cfgc, SetDefaultProcesses{}, TaskName{"jet-substructure-dielectron-output"})); - - return WorkflowSpec{tasks}; -} diff --git a/PWGJE/Tasks/jetsubstructureoutput.cxx b/PWGJE/Tasks/jetsubstructureoutput.cxx deleted file mode 100644 index fed22a1b826..00000000000 --- a/PWGJE/Tasks/jetsubstructureoutput.cxx +++ /dev/null @@ -1,284 +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" -#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 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"}; - - Configurable eventSelectionForCounting{"eventSelectionForCounting", "sel8", "choose event selection for collision counter"}; - - std::map jetMappingData; - std::map jetMappingDataSub; - std::map jetMappingMCD; - std::map jetMappingMCP; - - std::vector jetRadiiValues; - - int eventSelection = -1; - void init(InitContext const&) - { - jetRadiiValues = (std::vector)jetRadii; - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelectionForCounting)); - } - - template - void fillJetTables(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; - std::vector pairPtVec; - std::vector pairEnergyVec; - std::vector pairThetaVec; - auto energyMotherSpan = jet.energyMother(); - auto ptLeadingSpan = jet.ptLeading(); - auto ptSubLeadingSpan = jet.ptSubLeading(); - auto thetaSpan = jet.theta(); - auto pairPtSpan = jet.pairPt(); - auto pairEnergySpan = jet.pairEnergy(); - auto pairThetaSpan = jet.pairTheta(); - 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(pairPtSpan.begin(), pairPtSpan.end(), std::back_inserter(pairPtVec)); - std::copy(pairEnergySpan.begin(), pairEnergySpan.end(), std::back_inserter(pairEnergyVec)); - std::copy(pairThetaSpan.begin(), pairThetaSpan.end(), std::back_inserter(pairThetaVec)); - 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(), pairPtVec, pairEnergyVec, pairThetaVec); - 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++; - } - fillJetTables(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 readSelectedCollisionCounter = 0; - int writtenCollisionCounter = -1; - for (auto const& collision : collisions) { - readCollisionCounter++; - if (jetderiveddatautilities::selectCollision(collision, eventSelection)) { - readSelectedCollisionCounter++; - } - } - std::vector previousReadCounts; - std::vector previousReadSelectedCounts; - std::vector previousWrittenCounts; - int iPreviousDataFrame = 0; - for (const auto& collisionCount : collisionCounts) { - auto readCollisionCounterSpan = collisionCount.readCounts(); - auto readSelectedCollisionCounterSpan = collisionCount.readSelectedCounts(); - auto writtenCollisionCounterSpan = collisionCount.writtenCounts(); - if (iPreviousDataFrame == 0) { - std::copy(readCollisionCounterSpan.begin(), readCollisionCounterSpan.end(), std::back_inserter(previousReadCounts)); - std::copy(readSelectedCollisionCounterSpan.begin(), readSelectedCollisionCounterSpan.end(), std::back_inserter(previousReadSelectedCounts)); - std::copy(writtenCollisionCounterSpan.begin(), writtenCollisionCounterSpan.end(), std::back_inserter(previousWrittenCounts)); - } else { - for (unsigned int i = 0; i < previousReadCounts.size(); i++) { - previousReadCounts[i] += readCollisionCounterSpan[i]; - previousReadSelectedCounts[i] += readSelectedCollisionCounterSpan[i]; - previousWrittenCounts[i] += writtenCollisionCounterSpan[i]; - } - } - iPreviousDataFrame++; - } - previousReadCounts.push_back(readCollisionCounter); - previousReadSelectedCounts.push_back(readSelectedCollisionCounter); - previousWrittenCounts.push_back(writtenCollisionCounter); - storedCollisionCountsTable(previousReadCounts, previousReadSelectedCounts, 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 c12115ff89e..00000000000 --- a/PWGJE/Tasks/jettaggerhfQA.cxx +++ /dev/null @@ -1,945 +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 { - - // 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"}; - - // 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 prong2sigmaLxyMax{"prong2simgaLxyMax", 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 prong2sigmaLxyzMax{"prong2sigmaLxyzMax", 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 prong3sigmaLxyMax{"prong3sigmaLxyMax", 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 prong3sigmaLxyzMax{"prong3sigmaLxyzMax", 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 binSigmaImpactParameterXY{"binImpactSigmaParameterXY", {800, 0.f, 100.f}, ""}; - 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; - float maxSigmaLxy2Prong = 0.; - float minSxy2Prong = 0.; - float maxSigmaLxyz2Prong = 0.; - float minSxyz2Prong = 0.; - float maxSigmaLxy3Prong = 0.; - float minSxy3Prong = 0.; - float maxSigmaLxyz3Prong = 0.; - float minSxyz3Prong = 0.; - - 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 sigmaImpactParameterXYAxis = {binSigmaImpactParameterXY, "#sigma_{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, "#sigma_{L_{XY}} [cm]"}; - AxisSpec sigmaLxyzAxis = {binSigmaLxyz, "#sigma_{L_{XYZ}} [cm]"}; - - numberOfJetFlavourSpecies = static_cast(numFlavourSpecies); - maxSigmaLxy2Prong = static_cast(prong2sigmaLxyMax); - minSxy2Prong = static_cast(prong2SxyMin); - maxSigmaLxyz2Prong = static_cast(prong2sigmaLxyzMax); - minSxyz2Prong = static_cast(prong2SxyzMin); - maxSigmaLxy3Prong = static_cast(prong3sigmaLxyMax); - minSxy3Prong = static_cast(prong3SxyMin); - maxSigmaLxyz3Prong = static_cast(prong3sigmaLxyzMax); - minSxyz3Prong = static_cast(prong3SxyzMin); - - 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}}}); - if (fillIPxy) { - 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}}}); - } - if (fillIPz) { - 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}}}); - } - if (fillIPxyz) { - 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}}}); - } - if (fillTrackCounting) { - 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}}}); - if (fillIPxy) { - registry.add("h3_jet_pt_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {impactParameterXYAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_sigma_impact_parameter_xy_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {sigmaImpactParameterXYAxis}, {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_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}}}); - } - if (fillIPz) { - 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_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}}}); - } - if (fillIPxyz) { - 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_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}}}); - } - if (fillTrackCounting) { - 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 (doprocessSV2ProngData) { - registry.add("h_2prong_nprongs", "", {HistType::kTH1F, {{nprongsAxis}}}); - registry.add("h2_jet_pt_2prong_Lxy", "", {HistType::kTH2F, {{jetPtAxis}, {LxyAxis}}}); - registry.add("h2_jet_pt_2prong_Sxy", "", {HistType::kTH2F, {{jetPtAxis}, {SxyAxis}}}); - registry.add("h2_jet_pt_2prong_Lxyz", "", {HistType::kTH2F, {{jetPtAxis}, {LxyzAxis}}}); - registry.add("h2_jet_pt_2prong_Sxyz", "", {HistType::kTH2F, {{jetPtAxis}, {SxyzAxis}}}); - registry.add("h2_jet_pt_2prong_Sxy_N1", "", {HistType::kTH2F, {{jetPtAxis}, {SxyAxis}}}); - registry.add("h2_jet_pt_2prong_Sxyz_N1", "", {HistType::kTH2F, {{jetPtAxis}, {SxyzAxis}}}); - registry.add("h2_2prong_Sxy_sigmaLxy", "", {HistType::kTH2F, {{SxyAxis}, {sigmaLxyAxis}}}); - registry.add("h2_2prong_Sxyz_sigmaLxyz", "", {HistType::kTH2F, {{SxyzAxis}, {sigmaLxyzAxis}}}); - registry.add("h2_jet_pt_2prong_sigmaLxy", "", {HistType::kTH2F, {{jetPtAxis}, {sigmaLxyAxis}}}); - registry.add("h2_jet_pt_2prong_sigmaLxyz", "", {HistType::kTH2F, {{jetPtAxis}, {sigmaLxyzAxis}}}); - registry.add("h2_jet_pt_2prong_Sxy_cutSxyAndsigmaLxy", "", {HistType::kTH2F, {{jetPtAxis}, {SxyAxis}}}); - registry.add("h2_jet_pt_2prong_Sxyz_cutSxyzAndsigmaLxyz", "", {HistType::kTH2F, {{jetPtAxis}, {SxyzAxis}}}); - registry.add("h2_jet_pt_2prong_Sxy_N1_cutSxyAndsigmaLxy", "", {HistType::kTH2F, {{jetPtAxis}, {SxyAxis}}}); - registry.add("h2_jet_pt_2prong_Sxyz_N1_cutSxyzAndsigmaLxyz", "", {HistType::kTH2F, {{jetPtAxis}, {SxyzAxis}}}); - } - if (doprocessSV3ProngData) { - registry.add("h_3prong_nprongs", "", {HistType::kTH1F, {{nprongsAxis}}}); - registry.add("h2_jet_pt_3prong_Lxy", "", {HistType::kTH2F, {{jetPtAxis}, {LxyAxis}}}); - registry.add("h2_jet_pt_3prong_Sxy", "", {HistType::kTH2F, {{jetPtAxis}, {SxyAxis}}}); - registry.add("h2_jet_pt_3prong_Lxyz", "", {HistType::kTH2F, {{jetPtAxis}, {LxyzAxis}}}); - registry.add("h2_jet_pt_3prong_Sxyz", "", {HistType::kTH2F, {{jetPtAxis}, {SxyzAxis}}}); - registry.add("h2_jet_pt_3prong_Sxy_N1", "", {HistType::kTH2F, {{jetPtAxis}, {SxyAxis}}}); - registry.add("h2_jet_pt_3prong_Sxyz_N1", "", {HistType::kTH2F, {{jetPtAxis}, {SxyzAxis}}}); - registry.add("h2_3prong_Sxy_sigmaLxy", "", {HistType::kTH2F, {{SxyAxis}, {sigmaLxyAxis}}}); - registry.add("h2_3prong_Sxyz_sigmaLxyz", "", {HistType::kTH2F, {{SxyzAxis}, {sigmaLxyzAxis}}}); - registry.add("h2_jet_pt_3prong_sigmaLxy", "", {HistType::kTH2F, {{jetPtAxis}, {sigmaLxyAxis}}}); - registry.add("h2_jet_pt_3prong_sigmaLxyz", "", {HistType::kTH2F, {{jetPtAxis}, {sigmaLxyzAxis}}}); - registry.add("h2_jet_pt_3prong_Sxy_cutSxyAndsigmaLxy", "", {HistType::kTH2F, {{jetPtAxis}, {SxyAxis}}}); - registry.add("h2_jet_pt_3prong_Sxyz_cutSxyzAndsigmaLxyz", "", {HistType::kTH2F, {{jetPtAxis}, {SxyzAxis}}}); - registry.add("h2_jet_pt_3prong_Sxy_N1_cutSxyAndsigmaLxy", "", {HistType::kTH2F, {{jetPtAxis}, {SxyAxis}}}); - registry.add("h2_jet_pt_3prong_Sxyz_N1_cutSxyzAndsigmaLxyz", "", {HistType::kTH2F, {{jetPtAxis}, {SxyzAxis}}}); - } - if (doprocessSV2ProngMCD) { - registry.add("h2_2prong_nprongs_flavour", "", {HistType::kTH2F, {{nprongsAxis}, {jetFlavourAxis}}}); - 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_N1_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Sxyz_N1_flavour", "", {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}}}); - registry.add("h3_jet_pt_2prong_Sxy_flavour_cutSxyAndsigmaLxy", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Sxyz_flavour_cutSxyzAndsigmaLxyz", "", {HistType::kTH3F, {{jetPtAxis}, {SxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Sxy_N1_flavour_cutSxyAndsigmaLxy", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_2prong_Sxyz_N1_flavour_cutSxyzAndsigmaLxyz", "", {HistType::kTH3F, {{jetPtAxis}, {SxyzAxis}, {jetFlavourAxis}}}); - } - if (doprocessSV3ProngMCD) { - registry.add("h2_3prong_nprongs_flavour", "", {HistType::kTH2F, {{nprongsAxis}, {jetFlavourAxis}}}); - 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_N1_flavour", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Sxyz_N1_flavour", "", {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}}}); - registry.add("h3_jet_pt_3prong_Sxy_flavour_cutSxyAndsigmaLxy", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Sxyz_flavour_cutSxyzAndsigmaLxyz", "", {HistType::kTH3F, {{jetPtAxis}, {SxyzAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Sxy_N1_flavour_cutSxyAndsigmaLxy", "", {HistType::kTH3F, {{jetPtAxis}, {SxyAxis}, {jetFlavourAxis}}}); - registry.add("h3_jet_pt_3prong_Sxyz_N1_flavour_cutSxyzAndsigmaLxyz", "", {HistType::kTH3F, {{jetPtAxis}, {SxyzAxis}, {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 false; - - return true; - } - - bool prongAcceptance(float sigmaDecayLength, float decayLengthSig, float maxSigmaDecayLength, float minDecayLengthSig) - { - if ((sigmaDecayLength < maxSigmaDecayLength) && (decayLengthSig > minDecayLengthSig)) - return true; - - return false; - } - - template - std::tuple getMaxSxyForJet(const JetType& mcdjet) - { - float maxSxy = 0; - float correspondingErrorDecayLengthXY = 0; - - for (const auto& prong : mcdjet.template secondaryVertices_as()) { - float Sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); - if (maxSxy < Sxy) { - maxSxy = Sxy; - correspondingErrorDecayLengthXY = prong.errorDecayLengthXY(); - } - } - return std::make_tuple(maxSxy, correspondingErrorDecayLengthXY); - } - - template - std::tuple getMaxSxyzForJet(const JetType& mcdjet) - { - float maxSxyz = 0; - float correspondingErrorDecayLength = 0; - - for (const auto& prong : mcdjet.template secondaryVertices_as()) { - float Sxyz = prong.decayLength() / prong.errorDecayLength(); - if (maxSxyz < Sxyz) { - maxSxyz = Sxyz; - correspondingErrorDecayLength = prong.errorDecayLength(); - } - } - return std::make_tuple(maxSxyz, correspondingErrorDecayLength); - } - - 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()); - int geoSign = jettaggingutilities::getGeoSign(collision, 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() / std::sqrt(track.sigmaDcaXY2()); - varSignImpXYSig = geoSign * std::abs(track.dcaXY()) / std::sqrt(track.sigmaDcaXY2()); - 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() / std::sqrt(track.sigmaDcaZ2()); - varSignImpZSig = geoSign * std::abs(track.dcaZ()) / std::sqrt(track.sigmaDcaZ2()); - 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; - float dcaXYZ = jtrack.dcaXYZ(); - float sigmaDcaXYZ2 = jtrack.sigmaDcaXYZ2(); - varImpXYZ = dcaXYZ * jettaggingutilities::cmTomum; - varSignImpXYZ = geoSign * std::abs(dcaXYZ) * jettaggingutilities::cmTomum; - varImpXYZSig = dcaXYZ / std::sqrt(sigmaDcaXYZ2); - varSignImpXYZSig = geoSign * std::abs(dcaXYZ) / std::sqrt(sigmaDcaXYZ2); - 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) - continue; - 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 (fillIPxy && vecSignImpXYSig.empty()) - continue; - if (fillIPz && vecSignImpZSig.empty()) - continue; - if (fillIPxyz && vecSignImpXYZSig.empty()) - continue; - 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 && static_cast>::size_type>(order) < vecSignImpZSig.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 && static_cast>::size_type>(order) < vecSignImpXYZSig.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& 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; - // 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); - int geoSign = jettaggingutilities::getGeoSign(collision, 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 = std::abs(track.dcaXY()) / std::sqrt(track.sigmaDcaXY2()); - varSignImpXYSig = geoSign * std::abs(track.dcaXY()) / std::sqrt(track.sigmaDcaXY2()); - registry.fill(HIST("h3_jet_pt_impact_parameter_xy_flavour"), mcdjet.pt(), varImpXY, jetflavour); - registry.fill(HIST("h3_jet_pt_sigma_impact_parameter_xy_flavour"), mcdjet.pt(), varSigmaImpXY, 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_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); - vecImpXY[jetflavour].push_back(varImpXY); - vecSignImpXY[jetflavour].push_back(varSignImpXY); - vecImpXYSig[jetflavour].push_back(varImpXYSig); - vecSignImpXYSig[jetflavour].push_back(varSignImpXYSig); - vecSignImpXYSigTC.push_back({varSignImpXYSig, jtrack.pt()}); - } - if (fillIPz) { - float varImpZ, varSignImpZ, varImpZSig, varSignImpZSig; - varImpZ = track.dcaZ() * jettaggingutilities::cmTomum; - varSignImpZ = geoSign * std::abs(track.dcaZ()) * jettaggingutilities::cmTomum; - varImpZSig = track.dcaZ() / std::sqrt(track.sigmaDcaZ2()); - varSignImpZSig = geoSign * std::abs(track.dcaZ()) / std::sqrt(track.sigmaDcaZ2()); - 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_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); - vecImpZ[jetflavour].push_back(varImpZ); - vecSignImpZ[jetflavour].push_back(varSignImpZ); - vecImpZSig[jetflavour].push_back(varImpZSig); - vecSignImpZSig[jetflavour].push_back(varSignImpZSig); - vecSignImpZSigTC.push_back({varSignImpZSig, jtrack.pt()}); - } - if (fillIPxyz) { - float varImpXYZ, varSignImpXYZ, varImpXYZSig, varSignImpXYZSig; - float dcaXYZ = jtrack.dcaXYZ(); - float sigmaDcaXYZ2 = jtrack.sigmaDcaXYZ2(); - varImpXYZ = dcaXYZ * jettaggingutilities::cmTomum; - varSignImpXYZ = geoSign * std::abs(dcaXYZ) * jettaggingutilities::cmTomum; - varImpXYZSig = dcaXYZ / std::sqrt(sigmaDcaXYZ2); - varSignImpXYZSig = geoSign * std::abs(dcaXYZ) / std::sqrt(sigmaDcaXYZ2); - 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_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); - vecImpXYZ[jetflavour].push_back(varImpXYZ); - vecSignImpXYZ[jetflavour].push_back(varSignImpXYZ); - vecImpXYZSig[jetflavour].push_back(varImpXYZSig); - vecSignImpXYZSig[jetflavour].push_back(varSignImpXYZSig); - vecSignImpXYZSigTC.push_back({varSignImpXYZSig, jtrack.pt()}); - } - } - - if (!fillTrackCounting) - continue; - 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 - if (fillIPxy) - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N1"), mcdjet.pt(), vecSignImpXYSig[jetflavour][0], jetflavour); - if (fillIPz) - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N1"), mcdjet.pt(), vecSignImpZSig[jetflavour][0], jetflavour); - if (fillIPxyz) - 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 - if (fillIPxy) - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N2"), mcdjet.pt(), vecSignImpXYSig[jetflavour][1], jetflavour); - if (fillIPz) - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N2"), mcdjet.pt(), vecSignImpZSig[jetflavour][1], jetflavour); - if (fillIPxyz) - 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 - if (fillIPxy) - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_xy_significance_flavour_N3"), mcdjet.pt(), vecSignImpXYSig[jetflavour][2], jetflavour); - if (fillIPz) - registry.fill(HIST("h3_jet_pt_sign_impact_parameter_z_significance_flavour_N3"), mcdjet.pt(), vecSignImpZSig[jetflavour][2], jetflavour); - if (fillIPxyz) - 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()) - continue; - 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); - } - } - if (vecSignImpZSigTC.empty()) - continue; - for (int order = 1; order <= numOrder; order++) { - if (fillIPxy && static_cast>::size_type>(order) < vecSignImpZSigTC.size()) { - registry.fill(HIST("h3_sign_impact_parameter_z_significance_tc_flavour"), vecSignImpZSigTC[order - 1][0], order, jetflavour); - } - } - - if (vecSignImpXYZSigTC.empty()) - continue; - for (int order = 1; order <= numOrder; order++) { - if (fillIPxy && static_cast>::size_type>(order) < vecSignImpXYZSigTC.size()) { - registry.fill(HIST("h3_sign_impact_parameter_xyz_significance_tc_flavour"), vecSignImpXYZSigTC[order - 1][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 * std::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()); - } - } - - template - void fillHistogramSV2ProngData(T const& /*collision*/, U const& jets, V const& /*prongs*/) - { - for (const auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - auto [maxSxy, sigmaLxy] = getMaxSxyForJet(jet); - auto [maxSxyz, sigmaLxyz] = getMaxSxyzForJet(jet); - registry.fill(HIST("h_2prong_nprongs"), jet.template secondaryVertices_as().size()); - for (const auto& prong : jet.template secondaryVertices_as()) { - auto Lxy = prong.decayLengthXY(); - auto Sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); - auto Lxyz = prong.decayLength(); - auto Sxyz = prong.decayLength() / prong.errorDecayLength(); - registry.fill(HIST("h2_jet_pt_2prong_Lxy"), jet.pt(), Lxy); - registry.fill(HIST("h2_jet_pt_2prong_Sxy"), jet.pt(), Sxy); - registry.fill(HIST("h2_jet_pt_2prong_Lxyz"), jet.pt(), Lxyz); - registry.fill(HIST("h2_jet_pt_2prong_Sxyz"), jet.pt(), Sxyz); - registry.fill(HIST("h2_2prong_Sxy_sigmaLxy"), Sxy, prong.errorDecayLengthXY()); - registry.fill(HIST("h2_2prong_Sxyz_sigmaLxyz"), Sxyz, 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()); - if (prongAcceptance(prong.errorDecayLengthXY(), Sxy, maxSigmaLxy2Prong, minSxy2Prong)) { - registry.fill(HIST("h2_jet_pt_2prong_Sxy_cutSxyAndsigmaLxy"), jet.pt(), Sxy); - } - if (prongAcceptance(prong.errorDecayLength(), Sxyz, maxSigmaLxyz2Prong, minSxyz2Prong)) { - registry.fill(HIST("h2_jet_pt_2prong_Sxyz_cutSxyzAndsigmaLxyz"), jet.pt(), Sxyz); - } - } - registry.fill(HIST("h2_jet_pt_2prong_Sxy_N1"), jet.pt(), maxSxy); - registry.fill(HIST("h2_jet_pt_2prong_Sxyz_N1"), jet.pt(), maxSxyz); - if (prongAcceptance(sigmaLxy, maxSxy, maxSigmaLxy2Prong, minSxy2Prong)) { - registry.fill(HIST("h2_jet_pt_2prong_Sxy_N1_cutSxyAndsigmaLxy"), jet.pt(), maxSxy); - } - if (prongAcceptance(sigmaLxy, maxSxy, maxSigmaLxy2Prong, minSxy2Prong)) { - registry.fill(HIST("h2_jet_pt_2prong_Sxyz_N1_cutSxyzAndsigmaLxyz"), jet.pt(), maxSxyz); - } - } - } - - template - void fillHistogramSV3ProngData(T const& /*collision*/, U const& jets, V const& /*prongs*/) - { - for (const auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - auto [maxSxy, sigmaLxy] = getMaxSxyForJet(jet); - auto [maxSxyz, sigmaLxyz] = getMaxSxyzForJet(jet); - registry.fill(HIST("h_3prong_nprongs"), jet.template secondaryVertices_as().size()); - for (const auto& prong : jet.template secondaryVertices_as()) { - auto Lxy = prong.decayLengthXY(); - auto Sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); - auto Lxyz = prong.decayLength(); - auto Sxyz = prong.decayLength() / prong.errorDecayLength(); - registry.fill(HIST("h2_jet_pt_3prong_Lxy"), jet.pt(), Lxy); - registry.fill(HIST("h2_jet_pt_3prong_Sxy"), jet.pt(), Sxy); - registry.fill(HIST("h2_jet_pt_3prong_Lxyz"), jet.pt(), Lxyz); - registry.fill(HIST("h2_jet_pt_3prong_Sxyz"), jet.pt(), Sxyz); - registry.fill(HIST("h2_3prong_Sxy_sigmaLxy"), Sxy, prong.errorDecayLengthXY()); - registry.fill(HIST("h2_3prong_Sxyz_sigmaLxyz"), Sxyz, 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()); - if (prongAcceptance(prong.errorDecayLengthXY(), Sxy, maxSigmaLxy3Prong, minSxy3Prong)) { - registry.fill(HIST("h2_jet_pt_3prong_Sxy_cutSxyAndsigmaLxy"), jet.pt(), Sxy); - } - if (prongAcceptance(prong.errorDecayLength(), Sxyz, maxSigmaLxyz3Prong, minSxyz3Prong)) { - registry.fill(HIST("h2_jet_pt_3prong_Sxyz_cutSxyzAndsigmaLxyz"), jet.pt(), Sxyz); - } - } - registry.fill(HIST("h2_jet_pt_3prong_Sxy_N1"), jet.pt(), maxSxy); - registry.fill(HIST("h2_jet_pt_3prong_Sxyz_N1"), jet.pt(), maxSxyz); - if (prongAcceptance(sigmaLxy, maxSxy, maxSigmaLxy3Prong, minSxy3Prong)) { - registry.fill(HIST("h2_jet_pt_3prong_Sxy_N1_cutSxyAndsigmaLxy"), jet.pt(), maxSxy); - } - if (prongAcceptance(sigmaLxy, maxSxy, maxSigmaLxy3Prong, minSxy3Prong)) { - registry.fill(HIST("h2_jet_pt_3prong_Sxyz_N1_cutSxyzAndsigmaLxyz"), jet.pt(), maxSxyz); - } - } - } - - template - void fillHistogramSV2ProngMCD(T const& /*collision*/, U const& mcdjets, V const& /*prongs*/) - { - for (const auto& mcdjet : mcdjets) { - if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - auto origin = mcdjet.origin(); - auto [maxSxy, sigmaLxy] = getMaxSxyForJet(mcdjet); - auto [maxSxyz, sigmaLxyz] = getMaxSxyzForJet(mcdjet); - registry.fill(HIST("h2_2prong_nprongs_flavour"), mcdjet.template secondaryVertices_as().size(), origin); - for (const auto& prong : mcdjet.template secondaryVertices_as()) { - auto Lxy = prong.decayLengthXY(); - auto Sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); - auto Lxyz = prong.decayLength(); - auto Sxyz = prong.decayLength() / prong.errorDecayLength(); - 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); - if (prongAcceptance(prong.errorDecayLengthXY(), Sxy, maxSigmaLxy2Prong, minSxy2Prong)) { - registry.fill(HIST("h3_jet_pt_2prong_Sxy_flavour_cutSxyAndsigmaLxy"), mcdjet.pt(), Sxy, origin); - } - if (prongAcceptance(prong.errorDecayLength(), Sxyz, maxSigmaLxyz2Prong, minSxyz2Prong)) { - registry.fill(HIST("h3_jet_pt_2prong_Sxyz_flavour_cutSxyzAndsigmaLxyz"), mcdjet.pt(), Sxyz, origin); - } - } - registry.fill(HIST("h3_jet_pt_2prong_Sxy_N1_flavour"), mcdjet.pt(), maxSxy, origin); - registry.fill(HIST("h3_jet_pt_2prong_Sxyz_N1_flavour"), mcdjet.pt(), maxSxyz, origin); - if (prongAcceptance(sigmaLxy, maxSxy, maxSigmaLxy2Prong, minSxy2Prong)) { - registry.fill(HIST("h3_jet_pt_2prong_Sxy_N1_flavour_cutSxyAndsigmaLxy"), mcdjet.pt(), maxSxy, origin); - } - if (prongAcceptance(sigmaLxy, maxSxy, maxSigmaLxy2Prong, minSxy2Prong)) { - registry.fill(HIST("h3_jet_pt_2prong_Sxyz_N1_flavour_cutSxyzAndsigmaLxyz"), mcdjet.pt(), maxSxyz, origin); - } - } - } - - template - void fillHistogramSV3ProngMCD(T const& /*collision*/, U const& mcdjets, V const& /*prongs*/) - { - for (const auto& mcdjet : mcdjets) { - if (!jetfindingutilities::isInEtaAcceptance(mcdjet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { - continue; - } - auto origin = mcdjet.origin(); - auto [maxSxy, sigmaLxy] = getMaxSxyForJet(mcdjet); - auto [maxSxyz, sigmaLxyz] = getMaxSxyzForJet(mcdjet); - registry.fill(HIST("h2_3prong_nprongs_flavour"), mcdjet.template secondaryVertices_as().size(), origin); - for (const auto& prong : mcdjet.template secondaryVertices_as()) { - auto Lxy = prong.decayLengthXY(); - auto Sxy = prong.decayLengthXY() / prong.errorDecayLengthXY(); - auto Lxyz = prong.decayLength(); - auto Sxyz = prong.decayLength() / prong.errorDecayLength(); - 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); - if (prongAcceptance(prong.errorDecayLengthXY(), Sxy, maxSigmaLxy3Prong, minSxy3Prong)) { - registry.fill(HIST("h3_jet_pt_3prong_Sxy_flavour_cutSxyAndsigmaLxy"), mcdjet.pt(), Sxy, origin); - } - if (prongAcceptance(prong.errorDecayLength(), Sxyz, maxSigmaLxyz3Prong, minSxyz3Prong)) { - registry.fill(HIST("h3_jet_pt_3prong_Sxyz_flavour_cutSxyzAndsigmaLxyz"), mcdjet.pt(), Sxyz, origin); - } - } - registry.fill(HIST("h3_jet_pt_3prong_Sxy_N1_flavour"), mcdjet.pt(), maxSxy, origin); - registry.fill(HIST("h3_jet_pt_3prong_Sxyz_N1_flavour"), mcdjet.pt(), maxSxyz, origin); - if (prongAcceptance(sigmaLxy, maxSxy, maxSigmaLxy3Prong, minSxy3Prong)) { - registry.fill(HIST("h3_jet_pt_3prong_Sxy_N1_flavour_cutSxyAndsigmaLxy"), mcdjet.pt(), maxSxy, origin); - } - if (prongAcceptance(sigmaLxy, maxSxy, maxSigmaLxy3Prong, minSxy3Prong)) { - registry.fill(HIST("h3_jet_pt_3prong_Sxyz_N1_flavour_cutSxyzAndsigmaLxyz"), mcdjet.pt(), maxSxyz, origin); - } - } - } - - 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() / std::sqrt(track.sigmaDcaXY2()); - varImpZ = track.dcaZ() * jettaggingutilities::cmTomum; - varImpZSig = track.dcaZ() / std::sqrt(track.sigmaDcaZ2()); - float dcaXYZ = jtrack.dcaXYZ(); - float sigmaDcaXYZ2 = jtrack.sigmaDcaXYZ2(); - varImpXYZ = dcaXYZ * jettaggingutilities::cmTomum; - varImpXYZSig = dcaXYZ / std::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' imformation 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 imformation 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 imformation 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 processSV2ProngData(soa::Filtered::iterator const& jcollision, soa::Join const& jets, aod::DataSecondaryVertex2Prongs const& prongs) - { - fillHistogramSV2ProngData(jcollision, jets, prongs); - } - PROCESS_SWITCH(JetTaggerHFQA, processSV2ProngData, "Fill 2prong imformation for data jets", false); - - void processSV3ProngData(soa::Filtered::iterator const& jcollision, soa::Join const& jets, aod::DataSecondaryVertex3Prongs const& prongs) - { - fillHistogramSV3ProngData(jcollision, jets, prongs); - } - PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngData, "Fill 2prong imformation for data jets", false); - - void processSV2ProngMCD(soa::Filtered::iterator const& jcollision, soa::Join const& mcdjets, aod::MCDSecondaryVertex2Prongs const& prongs) - { - fillHistogramSV2ProngMCD(jcollision, mcdjets, prongs); - } - PROCESS_SWITCH(JetTaggerHFQA, processSV2ProngMCD, "Fill 2prong imformation for mcd jets", false); - - void processSV3ProngMCD(soa::Filtered::iterator const& jcollision, soa::Join const& mcdjets, aod::MCDSecondaryVertex3Prongs const& prongs) - { - fillHistogramSV3ProngMCD(jcollision, mcdjets, prongs); - } - PROCESS_SWITCH(JetTaggerHFQA, processSV3ProngMCD, "Fill 3prong imformation 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..8310b03c25a --- /dev/null +++ b/PWGJE/Tasks/mcGeneratorStudies.cxx @@ -0,0 +1,314 @@ +// 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. + +// 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 "PWGJE/DataModel/EMCALMatchedCollisions.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/EventSelection.h" + +#include "EMCALBase/Geometry.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include + +#include "TDatabasePDG.h" +#include +#include + +#include +#include + +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)"}; + Configurable mRequireEMCReadoutInL0{"mRequireEMCReadoutInL0", false, "require the EMC to be read out by L0 trigger"}; + + 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 (std::abs(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 (std::abs(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 (std::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))) { + if (!mRequireEMCReadoutInL0 || (collision.alias_bit(kEMC7) || collision.alias_bit(kDMC7))) { + 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 (const 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 (std::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 (std::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))) { + if (!mRequireEMCReadoutInL0 || (collision.alias_bit(kEMC7) || collision.alias_bit(kDMC7))) { + 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 1362ed572a5..00000000000 --- a/PWGJE/Tasks/mcgeneratorstudies.cxx +++ /dev/null @@ -1,222 +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 "DetectorsBase/GeometryManager.h" -#include "EMCALBase/Geometry.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"}; - 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"}; - - 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"); - hCollisionCounter->GetXaxis()->SetBinLabel(3, "T zSmall"); - hCollisionCounter->GetXaxis()->SetBinLabel(4, "Tz zGood"); - hCollisionCounter->GetXaxis()->SetBinLabel(5, "Tzz EMCal"); - hCollisionCounter->GetXaxis()->SetBinLabel(6, "TzzE Sel8"); - hCollisionCounter->GetXaxis()->SetBinLabel(7, "TzzES Unique"); - TString mesonLatexString = (TString)mSelectedParticleCode; - switch (mSelectedParticleCode) { - case 111: - mesonLatexString = "#pi^{0}"; - break; - case 221: - mesonLatexString = "#eta"; - break; - } - mHistManager.add("hpT_all", Form("Generated %s in all collisions", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_TVX", Form("Generated %s in TVX triggered collisions", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_T_zsmall", Form("Generated %s in TVX collisions with z < 10cm", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_T_z_zGood", Form("Generated %s in TVX collisions with good z < 10cm", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - mHistManager.add("hpTAccepted_T_z_z", Form("Accepted (EMCal) %s in TVX collisions with good z < 10cm", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_T_z_z_EMCal", Form("Generated %s in TVXinEMC collisions with good z < 10cm", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_T_z_z_E_Sel8", Form("Generated %s in TVXinEMC collisions with good z < 10cm and Sel8", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - mHistManager.add("hpT_T_z_z_E_S_Unique", Form("Generated %s in unique TVXinEMC collisions with good z < 10cm and Sel8", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - mHistManager.add("hpTAccepted_T_z_z_E_S_U", Form("Accepted %s in unique TVXinEMC collisions with good z < 10cm and Sel8", mesonLatexString.Data()), HistType::kTH1F, {pTAxis}); - - 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 perMcCollision = aod::mcparticle::mcCollisionId; - - void process(MyMCCollisions::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) - { - fillEventHistogram(&mHistManager, collision); - - auto mcCollision = collision.mcCollision(); - auto mcParticles_inColl = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); - - for (auto& mcParticle : mcParticles_inColl) { - if (mcParticle.pdgCode() != mSelectedParticleCode || fabs(mcParticle.y()) > mRapidityCut) - continue; - if (!mcParticle.isPhysicalPrimary() && !mcParticle.producedByGenerator()) - continue; - if (mRequireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) - continue; - - mHistManager.fill(HIST("hpT_all"), mcParticle.pt()); - if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { - mHistManager.fill(HIST("hpT_TVX"), mcParticle.pt()); - if (abs(collision.posZ()) < mVertexCut) { - mHistManager.fill(HIST("hpT_T_zsmall"), mcParticle.pt()); - if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - mHistManager.fill(HIST("hpT_T_z_zGood"), mcParticle.pt()); - if (isAccepted(mcParticle, mcParticles)) - mHistManager.fill(HIST("hpTAccepted_T_z_z"), mcParticle.pt()); - if (mRequireEMCCellContent ? collision.isemcreadout() : collision.alias_bit(kTVXinEMC)) { - mHistManager.fill(HIST("hpT_T_z_z_EMCal"), mcParticle.pt()); - if (collision.sel8()) { - mHistManager.fill(HIST("hpT_T_z_z_E_Sel8"), mcParticle.pt()); - if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - mHistManager.fill(HIST("hpT_T_z_z_E_S_Unique"), mcParticle.pt()); - if (isAccepted(mcParticle, mcParticles)) - mHistManager.fill(HIST("hpTAccepted_T_z_z_E_S_U"), 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 (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { - fRegistry->fill(HIST("hCollisionCounter"), 2); - if (abs(collision.posZ()) < mVertexCut) { - fRegistry->fill(HIST("hCollisionCounter"), 3); - if (collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) - fRegistry->fill(HIST("hCollisionCounter"), 4); - if (mRequireEMCCellContent ? collision.isemcreadout() : collision.alias_bit(kTVXinEMC)) { - fRegistry->fill(HIST("hCollisionCounter"), 5); - if (collision.sel8()) { - fRegistry->fill(HIST("hCollisionCounter"), 6); - if (collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - fRegistry->fill(HIST("hCollisionCounter"), 7); - } - } - } - } - } - } -}; - -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 88% rename from PWGJE/Tasks/nSubjettiness.cxx rename to PWGJE/Tasks/nsubjettiness.cxx index b1a695bd9f7..133e1e6323b 100644 --- a/PWGJE/Tasks/nSubjettiness.cxx +++ b/PWGJE/Tasks/nsubjettiness.cxx @@ -15,23 +15,27 @@ /// \author Aimeric Landou /// \author Nima Zardoshti -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGJE/Core/JetFinder.h" +#include "PWGJE/Core/JetSubstructureUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + #include "Framework/ASoA.h" -#include "Framework/runDataProcessing.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/Logger.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include + +#include +#include -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetUtilities.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetFindingUtilities.h" -#include "PWGJE/Core/JetSubstructureUtilities.h" #include "fastjet/contrib/AxesDefinition.hh" -#include "fastjet/contrib/MeasureDefinition.hh" +#include + +#include using namespace o2; using namespace o2::framework; @@ -177,7 +181,7 @@ struct NSubjettinessTask { } Filter jetCuts = aod::jet::r == nround(jetR.node() * 100.0f); - Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); + Filter collisionFilter = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centFT0M >= centralityMin && aod::jcollision::centFT0M < centralityMax); template void processJet(T const& jet, U const& tracks, float weight = 1.0) @@ -227,7 +231,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 +240,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 +249,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 +258,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 +267,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 +276,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..2b38d73f9f5 --- /dev/null +++ b/PWGJE/Tasks/nucleiInJets.cxx @@ -0,0 +1,2766 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include +#include + +#include "TDatabasePDG.h" +#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; +using namespace o2::constants::physics; +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 Pdg::kDeuteron: // Deuteron + return Particle::kDeuteron; + case -Pdg::kDeuteron: // AntiDeuteron + return -Particle::kDeuteron; + + case Pdg::kTriton: // Triton + return Particle::kTriton; + case -Pdg::kTriton: // AntiTriton + return -Particle::kTriton; + + case Pdg::kHelium3: // Helium + return Particle::kHelium; + case -Pdg::kHelium3: // 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 centralityType{"centralityType", 0, "0: FT0M, 1: FT0C, 2: FV0A"}; + Configurable> cfgOccupancyRange{"cfgOccupancyRange", {0, 1000}, "Occupancy selection"}; + Configurable useOccupancy{"useOccupancy", true, "Events with custom occupancy selection"}; + Configurable useEtaSelForEffDen{"useEtaSelForEffDen", false, "eta selection for gen particles"}; + + 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 useTOFVeto{"useTOFVeto", false, "true: use TOF veto, false: no TOF veto"}; + Configurable isRequireHitsInITSLayers{"isRequireHitsInITSLayers", true, "true: at least one hit in the its inner layes"}; + Configurable useMcC{"useMcC", true, "use mcC"}; + Configurable useRapidityCutForPID{"useRapidityCutForPID", false, "true: use rapidity cut for PID, false: no rapidity cut for PID"}; + + 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"}; + Configurable sel8Coll{"sel8Coll", true, "sel8Coll for collisions"}; + Configurable selNoSameBunchPileup{"selNoSameBunchPileup", false, "selNoSameBunchPileup for collisions"}; + Configurable cfgMaxZVertex{"cfgMaxZVertex", 10.0, "Maximum Z vertex selection in cm"}; + Configurable selIsGoodZvtxFT0vsPV{"selIsGoodZvtxFT0vsPV", false, "selIsGoodZvtxFT0vsPV for collisions"}; + + // using EventTable = soa::Join; + using EventTable = aod::JetCollisions; + using EventTableMC = soa::Join; + using JetCollWithLabel = o2::soa::Join::iterator; + using TrackCandidates = soa::Join; + using TrackCandidatesLfPid = soa::Join; + using TrackCandidatesMC = soa::Join; + + using TrackCandidatesIncMC = 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; + Service pdgDB; + 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 CentAxis = {100, 0, 100}; + 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 vzAxis{300, -15.f, 15.f, "Vz (cm)"}; + + 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, ""}; + + 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"); + + jetHist.add("hNEventsInc", "hNEventsInc", {HistType::kTH1D, {{6, 0.f, 6.f}}}); + jetHist.get(HIST("hNEventsInc"))->GetXaxis()->SetBinLabel(1, "All"); + jetHist.get(HIST("hNEventsInc"))->GetXaxis()->SetBinLabel(2, "Sel8"); + jetHist.get(HIST("hNEventsInc"))->GetXaxis()->SetBinLabel(3, "|Vz|<10"); + jetHist.get(HIST("hNEventsInc"))->GetXaxis()->SetBinLabel(4, "noSameBunchPileup"); + jetHist.get(HIST("hNEventsInc"))->GetXaxis()->SetBinLabel(5, "isGoodZvtxFT0vsPV"); + jetHist.get(HIST("hNEventsInc"))->GetXaxis()->SetBinLabel(6, "OccupancySel"); + + jetHist.add("hNEventsIncVsCent", "hNEventsIncVsCent", {HistType::kTH2D, {{vzAxis}, {CentAxis}}}); + + // TPC nSigma vs pT (inclusive) + jetHist.add("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt", "pT(p) vs NSigmaTPC (p) vs centrality; #it{p}_{T} (GeV/#it{c}); NSigmaTPC; centrality", HistType::kTH3F, {PtAxis, {200, -10, 10}, CentAxis}); + jetHist.add("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt", "pT(#bar{p}) vs NSigmaTPC (#bar{p}) vs centrality; #it{p}_{T} (GeV/#it{c}); NSigmaTPC; centrality", HistType::kTH3F, {PtAxis, {200, -10, 10}, CentAxis}); + jetHist.add("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt", "pT(d) vs NSigmaTPC (d) vs centrality; #it{p}_{T} (GeV/#it{c}); NSigmaTPC; centrality", HistType::kTH3F, {PtAxis, {200, -10, 10}, CentAxis}); + jetHist.add("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt", "pT(#bar{d}) vs NSigmaTPC (#bar{d}) vs centrality; #it{p}_{T} (GeV/#it{c}); NSigmaTPC; centrality", HistType::kTH3F, {PtAxis, {200, -10, 10}, CentAxis}); + + // jet property + jetHist.add("jet/h1JetPt", "jet_{p_{T}}", kTH1F, {PtJetAxis}); + jetHist.add("jet/h1JetPtBkgSub", "jet_{p_{T}} background subtracted", kTH1F, {PtJetAxis}); + jetHist.add("jet/h2JetPtVsBkgRho", "jet_{p_{T}} vs background #rho; jet_{p_{T}} (GeV/c); #rho (GeV/c/area)", kTH2F, {PtJetAxis, {100, 0, 20}}); + jetHist.add("jet/h1BkgRho", "Background #rho; #rho (GeV/c/area); Entries", kTH1F, {{100, 0, 20}}); + 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, {{vzAxis}}); + jetHist.add("vertexZ", "vertexZ (all)", kTH1F, {{vzAxis}}); + jetHist.add("jetOut/vertexZ", "vertexZ (without z-flag)", kTH1F, {{vzAxis}}); + //////////////////////////// + // 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, {{vzAxis}}); + jetHist.add("mcdJet/vertexZ", "vertexZ (All)", kTH1F, {{vzAxis}}); + 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, {{vzAxis}}); + jetHist.add("genmatched/vertexZ", "vertexZ (All)", kTH1F, {{vzAxis}}); + + ////////////////////////////////////////////// + // 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}}); + + // Background subtracted versions + jetHist.add("tracks/pion/h3PtVsPionNSigmaTPCVsPtJetBkgSub_jet", "pT(p) vs NSigmaTPC (p) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiPion/h3PtVsPionNSigmaTPCVsPtJetBkgSub_jet", "pT(p) vs NSigmaTPC (p) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/kaon/h3PtVsKaonNSigmaTPCVsPtJetBkgSub_jet", "pT(p) vs NSigmaTPC (p) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiKaon/h3PtVsKaonNSigmaTPCVsPtJetBkgSub_jet", "pT(p) vs NSigmaTPC (p) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", 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}}); + + // Background subtracted versions + jetHist.add("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub_jet", "pT(p) vs NSigmaTPC (p) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub_jet", "pT(#bar{p}) vs NSigmaTPC (#bar{p}) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub_jet", "pT(d) vs NSigmaTPC (d) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub_jet", "pT(#bar{d}) vs NSigmaTPC (#bar{d}) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub_jet", "pT(He) vs NSigmaTPC (He) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub_jet", "pT(#bar{He}) vs NSigmaTPC (#bar{He}) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub_jet", "pT(Tr) vs NSigmaTPC (Tr) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", HistType::kTH3F, {{PtAxis}, {200, -10, 10}, {PtJetAxis}}); + jetHist.add("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub_jet", "pT(#bar{Tr}) vs NSigmaTPC (#bar{Tr}) vs jet pT (Bkg Sub); #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} (Bkg Sub)", 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/h3TOFmassProtonVsPtVsJetPt_jet", "h3TOFmassProtonVsPtVsJetPt_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiProton/h3TOFmassantiProtonVsPtVsJetPt_jet", "h3TOFmassantiProtonVsPtVsJetPt_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/proton/h3TOFmass2ProtonVsPtVsJetPt_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{massPrAxis}, {250, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiProton/h3TOFmass2antiProtonVsPtVsJetPt_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{massPrAxis}, {250, 0., 5.}, {PtJetAxis}}); + + jetHist.add("tracks/deuteron/h3TOFmassDeuteronVsPtVsJetPt_jet", "h3TOFmassDeuteronVsPtVsJetPt_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiDeuteron/h3TOFmassantiDeuteronVsPtVsJetPt_jet", "h3TOFmassantiDeuteronVsPtVsJetPt_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/deuteron/h3TOFmass2DeuteronVsPtVsJetPt_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{massDeAxis}, {250, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiDeuteron/h3TOFmass2antiDeuteronVsPtVsJetPt_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{massDeAxis}, {250, 0., 5.}, {PtJetAxis}}); + + jetHist.add("tracks/triton/h3TOFmassTritonVsPtVsJetPt_jet", "h3TOFmassTritonVsPtVsJetPt_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiTriton/h3TOFmassantiTritonVsPtVsJetPt_jet", "h3TOFmassantiTritonVsPtVsJetPt_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/triton/h3TOFmass2TritonVsPtVsJetPt_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{massTrAxis}, {250, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiTriton/h3TOFmass2antiTritonVsPtVsJetPt_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{massTrAxis}, {250, 0., 5.}, {PtJetAxis}}); + + jetHist.add("tracks/helium/h3TOFmassHeliumVsPtVsJetPt_jet", "h3TOFmassHeliumVsPtVsJetPt_jet; TOFmass; #it{p}_{T}/z (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{180, 0.4, 4.}, {ptZHeAxis}, {PtJetAxis}}); + jetHist.add("tracks/antiHelium/h3TOFmassantiHeliumVsPtVsJetPt_jet", "h3TOFmassantiHeliumVsPtVsJetPt_jet; TOFmass; #it{p}_{T}/z (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{180, 0.4, 4.}, {ptZHeAxis}, {PtJetAxis}}); + jetHist.add("tracks/helium/h3TOFmass2HeliumVsPtVsJetPt_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T}; TOFmass2; #it{p}_{T}/z (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{massHeAxis}, {ptZHeAxis}, {PtJetAxis}}); + jetHist.add("tracks/antiHelium/h3TOFmass2antiHeliumVsPtVsJetPt_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T}; TOFmass2; #it{p}_{T}/z (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{massHeAxis}, {ptZHeAxis}, {PtJetAxis}}); + + // Background subtracted versions + jetHist.add("tracks/proton/h3TOFmassProtonVsPtVsJetPtBkgSub_jet", "h3TOFmassProtonVsPtVsJetPtBkgSub_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiProton/h3TOFmassantiProtonVsPtVsJetPtBkgSub_jet", "h3TOFmassantiProtonVsPtVsJetPtBkgSub_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/proton/h3TOFmass2ProtonVsPtVsJetPtBkgSub_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T} (Bkg Sub); TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{massPrAxis}, {250, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiProton/h3TOFmass2antiProtonVsPtVsJetPtBkgSub_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T} (Bkg Sub); TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{massPrAxis}, {250, 0., 5.}, {PtJetAxis}}); + + jetHist.add("tracks/deuteron/h3TOFmassDeuteronVsPtVsJetPtBkgSub_jet", "h3TOFmassDeuteronVsPtVsJetPtBkgSub_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiDeuteron/h3TOFmassantiDeuteronVsPtVsJetPtBkgSub_jet", "h3TOFmassantiDeuteronVsPtVsJetPtBkgSub_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/deuteron/h3TOFmass2DeuteronVsPtVsJetPtBkgSub_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T} (Bkg Sub); TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{massDeAxis}, {250, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiDeuteron/h3TOFmass2antiDeuteronVsPtVsJetPtBkgSub_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T} (Bkg Sub); TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{massDeAxis}, {250, 0., 5.}, {PtJetAxis}}); + + jetHist.add("tracks/triton/h3TOFmassTritonVsPtVsJetPtBkgSub_jet", "h3TOFmassTritonVsPtVsJetPtBkgSub_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiTriton/h3TOFmassantiTritonVsPtVsJetPtBkgSub_jet", "h3TOFmassantiTritonVsPtVsJetPtBkgSub_jet; TOFmass; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/triton/h3TOFmass2TritonVsPtVsJetPtBkgSub_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T} (Bkg Sub); TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{massTrAxis}, {250, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/antiTriton/h3TOFmass2antiTritonVsPtVsJetPtBkgSub_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T} (Bkg Sub); TOFmass2; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{massTrAxis}, {250, 0., 5.}, {PtJetAxis}}); + + jetHist.add("tracks/helium/h3TOFmassHeliumVsPtVsJetPtBkgSub_jet", "h3TOFmassHeliumVsPtVsJetPtBkgSub_jet; TOFmass; #it{p}_{T}/z (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{180, 0.4, 4.}, {ptZHeAxis}, {PtJetAxis}}); + jetHist.add("tracks/antiHelium/h3TOFmassantiHeliumVsPtVsJetPtBkgSub_jet", "h3TOFmassantiHeliumVsPtVsJetPtBkgSub_jet; TOFmass; #it{p}_{T}/z (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{180, 0.4, 4.}, {ptZHeAxis}, {PtJetAxis}}); + jetHist.add("tracks/helium/h3TOFmass2HeliumVsPtVsJetPtBkgSub_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T} (Bkg Sub); TOFmass2; #it{p}_{T}/z (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{massHeAxis}, {ptZHeAxis}, {PtJetAxis}}); + jetHist.add("tracks/antiHelium/h3TOFmass2antiHeliumVsPtVsJetPtBkgSub_jet", "#Delta M^{2} (t) vs #it{p}_{T} vs jet #it{p}_{T} (Bkg Sub); TOFmass2; #it{p}_{T}/z (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{massHeAxis}, {ptZHeAxis}, {PtJetAxis}}); + + // 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 + ///////////// + // 3D TOF NSigma histograms with jet pt + jetHist.add("tracks/perpCone/proton/h3TofNsigmaProtonVsPtVsJetPt", "h3TofNsigmaProtonVsPtVsJetPt; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiProton/h3TofNsigmaantiProtonVsPtVsJetPt", "h3TofNsigmaantiProtonVsPtVsJetPt; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/deuteron/h3TofNsigmaDeuteronVsPtVsJetPt", "h3TofNsigmaDeuteronVsPtVsJetPt; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiDeuteron/h3TofNsigmaantiDeuteronVsPtVsJetPt", "h3TofNsigmaantiDeuteronVsPtVsJetPt; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/triton/h3TofNsigmaTritonVsPtVsJetPt", "h3TofNsigmaTritonVsPtVsJetPt; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiTriton/h3TofNsigmaantiTritonVsPtVsJetPt", "h3TofNsigmaantiTritonVsPtVsJetPt; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/helium/h3TofNsigmaHeliumVsPtVsJetPt", "h3TofNsigmaHeliumVsPtVsJetPt; TofNsigma; #it{p}_{T}/z (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiHelium/h3TofNsigmaantiHeliumVsPtVsJetPt", "h3TofNsigmaantiHeliumVsPtVsJetPt; TofNsigma; #it{p}_{T}/z (GeV); jet #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + + // 3D TOF NSigma histograms with background subtracted jet pt + jetHist.add("tracks/perpCone/proton/h3TofNsigmaProtonVsPtVsJetPtBkgSub", "h3TofNsigmaProtonVsPtVsJetPtBkgSub; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiProton/h3TofNsigmaantiProtonVsPtVsJetPtBkgSub", "h3TofNsigmaantiProtonVsPtVsJetPtBkgSub; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/deuteron/h3TofNsigmaDeuteronVsPtVsJetPtBkgSub", "h3TofNsigmaDeuteronVsPtVsJetPtBkgSub; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiDeuteron/h3TofNsigmaantiDeuteronVsPtVsJetPtBkgSub", "h3TofNsigmaantiDeuteronVsPtVsJetPtBkgSub; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/triton/h3TofNsigmaTritonVsPtVsJetPtBkgSub", "h3TofNsigmaTritonVsPtVsJetPtBkgSub; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiTriton/h3TofNsigmaantiTritonVsPtVsJetPtBkgSub", "h3TofNsigmaantiTritonVsPtVsJetPtBkgSub; TofNsigma; #it{p}_{T} (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/helium/h3TofNsigmaHeliumVsPtVsJetPtBkgSub", "h3TofNsigmaHeliumVsPtVsJetPtBkgSub; TofNsigma; #it{p}_{T}/z (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + jetHist.add("tracks/perpCone/antiHelium/h3TofNsigmaantiHeliumVsPtVsJetPtBkgSub", "h3TofNsigmaantiHeliumVsPtVsJetPtBkgSub; TofNsigma; #it{p}_{T}/z (GeV); jet #it{p}_{T} (Bkg Sub) (GeV)", HistType::kTH3F, {{100, -5, 5}, {50, 0., 5.}, {PtJetAxis}}); + + ////////////////////////////////////////////// + // 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/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub", "pT(p) vs NSigmaTPC (p) vs jet pT BkgSub; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} BkgSub", 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/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub", "pT(#bar{p}) vs NSigmaTPC (#bar{p}) vs jet pT BkgSub; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} BkgSub", 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/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub", "pT(d) vs NSigmaTPC (d) vs jet pT BkgSub; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} BkgSub", 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/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub", "pT(#bar{d}) vs NSigmaTPC (#bar{d}) vs jet pT BkgSub; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} BkgSub", 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/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub", "pT(He) vs NSigmaTPC (He) vs jet pT BkgSub; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} BkgSub", 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/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub", "pT(#bar{He}) vs NSigmaTPC (#bar{He}) vs jet pT BkgSub; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} BkgSub", 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/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub", "pT(Tr) vs NSigmaTPC (Tr) vs jet pT BkgSub; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} BkgSub", 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}}); + jetHist.add("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub", "pT(#bar{Tr}) vs NSigmaTPC (#bar{Tr}) vs jet pT BkgSub; #it{p}_{T} (GeV/#it{c}; NSigmaTPC; p^{jet}_{T} BkgSub", 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("tracksInc/proton/dca/after/hDCAxyVsPtProton", "DCAxy vs Pt (p)", HistType::kTH3F, {{dcaxyAxis}, {PtAxis}, {CentAxis}}); + 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("tracksInc/proton/dca/after/hDCAzVsPtProton", "DCAz vs Pt (p)", HistType::kTH3F, {{dcazAxis}, {PtAxis}, {CentAxis}}); + 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("tracksInc/deuteron/dca/after/hDCAxyVsPtDeuteron", "DCAxy vs Pt (d)", HistType::kTH3F, {{dcaxyAxis}, {PtAxis}, {CentAxis}}); + 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("tracksInc/deuteron/dca/after/hDCAzVsPtDeuteron", "DCAz vs Pt (d)", HistType::kTH3F, {{dcazAxis}, {PtAxis}, {CentAxis}}); + 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}}); + + jetHist.add("tracksInc/proton/h2TOFmassProtonVsPt", "h2TOFmassProtonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {CentAxis}}); + jetHist.add("tracksInc/antiProton/h2TOFmassantiProtonVsPt", "h2TOFmassantiProtonVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {CentAxis}}); + jetHist.add("tracksInc/deuteron/h2TOFmassDeuteronVsPt", "h2TOFmassDeuteronVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {CentAxis}}); + jetHist.add("tracksInc/antiDeuteron/h2TOFmassantiDeuteronVsPt", "h2TOFmassantiDeuteronVsPt; TOFmass; #it{p}_{T} (GeV)", HistType::kTH3F, {{80, 0.4, 4.}, {50, 0., 5.}, {CentAxis}}); + + jetHist.add("tracksInc/proton/h2TOFmass2ProtonVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH3F, {{massPrAxis}, {250, 0., 5.}, {CentAxis}}); + jetHist.add("tracksInc/antiProton/h2TOFmass2antiProtonVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH3F, {{massPrAxis}, {250, 0., 5.}, {CentAxis}}); + jetHist.add("tracksInc/deuteron/h2TOFmass2DeuteronVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH3F, {{massDeAxis}, {250, 0., 5.}, {CentAxis}}); + jetHist.add("tracksInc/antiDeuteron/h2TOFmass2antiDeuteronVsPt", "#Delta M^{2} (t) vs #it{p}_{T}; TOFmass2; #it{p}_{T} (GeV)", HistType::kTH3F, {{massDeAxis}, {250, 0., 5.}, {CentAxis}}); + + jetHist.add("tracksInc/proton/h2TofNsigmaProtonVsPt", "h2TofNsigmaProtonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {100, 0., 10.}, {CentAxis}}); + jetHist.add("tracksInc/antiProton/h2TofNsigmaantiProtonVsPt", "h2TofNsigmaantiProtonVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {100, 0., 10.}, {CentAxis}}); + jetHist.add("tracksInc/deuteron/h2TofNsigmaDeuteronVsPt", "h2TofNsigmaDeuteronVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {100, 0., 10.}, {CentAxis}}); + jetHist.add("tracksInc/antiDeuteron/h2TofNsigmaantiDeuteronVsPt", "h2TofNsigmaantiDeuteronVsPt; TofNsigma; #it{p}_{T} (GeV)", HistType::kTH3F, {{100, -5, 5}, {100, 0., 10.}, {CentAxis}}); + + // 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.}}); + + // tracksInc/dcaxy/rec histograms for each particle type + std::vector particles = {"proton", "antiProton", "deuteron", "antiDeuteron", "triton", "antiTriton", "helium", "antiHelium"}; + for (const auto& particle : particles) { + jetHist.add(("tracksInc/dcaxy/rec/" + particle + "/tpcPtVsDcaxy3D").c_str(), "pT vs Dcaxy vs Centrality", HistType::kTH3F, {{100, 0.f, 10.f}, {100, 0, 100}, dcaxyAxis}); + jetHist.add(("tracksInc/dcaxy/rec/" + particle + "/tpcPtVsDcaxy3DPIDVeto").c_str(), "pT vs Dcaxy vs Centrality (PID Veto)", HistType::kTH3F, {{100, 0.f, 10.f}, {100, 0, 100}, dcaxyAxis}); + jetHist.add(("tracksInc/dcaxy/rec/" + particle + "/tpcPtVsDcaxy3DPIDTOF").c_str(), "pT vs Dcaxy vs Centrality (PID TOF)", HistType::kTH3F, {{100, 0.f, 10.f}, {100, 0, 100}, dcaxyAxis}); + } + + if (isMC) { + // inc + jetHist.add("recInc/eventStat", "Event statistics (inclusive)", HistType::kTH1F, {{6, 0.f, 6.f}}); + jetHist.get(HIST("recInc/eventStat"))->GetXaxis()->SetBinLabel(1, "All"); + jetHist.get(HIST("recInc/eventStat"))->GetXaxis()->SetBinLabel(2, "Sel8"); + jetHist.get(HIST("recInc/eventStat"))->GetXaxis()->SetBinLabel(3, "|Vz|<10"); + jetHist.get(HIST("recInc/eventStat"))->GetXaxis()->SetBinLabel(4, "noSameBunchPileup"); + jetHist.get(HIST("recInc/eventStat"))->GetXaxis()->SetBinLabel(5, "isGoodZvtxFT0vsPV"); + jetHist.get(HIST("recInc/eventStat"))->GetXaxis()->SetBinLabel(6, "OccupancySel"); + + jetHist.add("recInc/vertexZ", "vertexZ (inclusive)", HistType::kTH2F, {{vzAxis}, {CentAxis}}); + jetHist.add("recInc/pt/PtParticleTypeTPC", "Pt vs ParticleType vs Centrality (TPC)", HistType::kTH3F, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}}); + jetHist.add("recInc/pt/PtParticleTypeTPCTOF", "Pt vs ParticleType vs Centrality (TPC+TOF)", HistType::kTH3F, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}}); + jetHist.add("recInc/pt/PtParticleTypeTPCTOFVeto", "Pt vs ParticleType vs Centrality (TPC+TOF Veto)", HistType::kTH3F, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}}); + jetHist.add("genInc/pt/PtParticleType", "Pt vs ParticleType vs Centrality (gen)", HistType::kTH3F, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}}); + + // Event and signal loss analysis histograms (inclusive) + jetHist.add("eventLoss/hEventStatistics", "Event Statistics for Loss Analysis", kTH1F, {{10, 0.f, 10.f}}); + jetHist.get(HIST("eventLoss/hEventStatistics"))->GetXaxis()->SetBinLabel(1, "All Generated"); + jetHist.get(HIST("eventLoss/hEventStatistics"))->GetXaxis()->SetBinLabel(2, "Gen |Vz|<10"); + jetHist.get(HIST("eventLoss/hEventStatistics"))->GetXaxis()->SetBinLabel(3, "Gen True INEL>0"); + jetHist.get(HIST("eventLoss/hEventStatistics"))->GetXaxis()->SetBinLabel(4, "Has Reco Coll"); + jetHist.get(HIST("eventLoss/hEventStatistics"))->GetXaxis()->SetBinLabel(5, "Pass Sel8"); + jetHist.get(HIST("eventLoss/hEventStatistics"))->GetXaxis()->SetBinLabel(6, "Pass |Vz|<10"); + jetHist.get(HIST("eventLoss/hEventStatistics"))->GetXaxis()->SetBinLabel(7, "Pass rec INEL>0"); + jetHist.get(HIST("eventLoss/hEventStatistics"))->GetXaxis()->SetBinLabel(8, "EvSelPassedRecINELgt0"); + + // Signal loss histograms (only the ones that are actually used) + jetHist.add("eventLoss/signalLoss/h3GenParticlesPtVsEtaVsCent_INELgt0", "Generated Particles p_{T} vs #eta vs Centrality", HistType::kTH3F, {{100, 0.f, 10.f}, {100, -1.5f, 1.5f}, {100, 0, 100}}); + jetHist.add("eventLoss/signalLoss/h3GenParticleTypeVsPtVsCent_INELgt0", "Generated Particle Type vs p_{T} vs Centrality", HistType::kTH3F, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}}); + jetHist.add("eventLoss/signalLoss/h3GenParticlesPtVsEtaVsCent_TrueINELgt0", "Generated Particles p_{T} vs #eta vs Centrality (INEL>0)", HistType::kTH3F, {{100, 0.f, 10.f}, {100, -1.5f, 1.5f}, {100, 0, 100}}); + jetHist.add("eventLoss/signalLoss/h3GenParticleTypeVsPtVsCent_TrueINELgt0", "Generated Particle Type vs p_{T} vs Centrality (INEL>0)", HistType::kTH3F, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}}); + + jetHist.add("recInc/eff/tpcTrack3D", "Pt vs ParticleType vs Centrality (tpc)", HistType::kTH3F, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}}); + jetHist.add("recInc/eff/tpcTofTrack3D", "Pt vs ParticleType vs Centrality (tpc-tof)", HistType::kTH3F, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}}); + + jetHist.add("recInc/dcaxy/rec/tpcPtVsDcaxy3D", "pT(p) vs ParticleType (p) vs Dcaxy", HistType::kTHnSparseF, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}, dcaxyAxis, {4, 0, 4}}); // pt, parttype, cent, dcaxy, partOrigin + jetHist.add("recInc/dcaxy/rec/tpcPtVsDcaxy3DPIDselected", "pT(p) vs ParticleType (p) vs Dcaxy", HistType::kTHnSparseF, {{100, 0.f, 10.f}, {14, -7, 7}, {100, 0, 100}, dcaxyAxis, {4, 0, 4}}); // pt, parttype, cent, dcaxy, partOrigin + + // 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/pt/PtParticleTypeTPCTOFVeto", "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/perpCone/pt/PtParticleTypeTPCTOFVeto", "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 + (o2::constants::math::PIHalf)); // This will contrain the angel between 0-2Pi + PerpendicularConeAxisPhi[1] = RecoDecay::constrainAngle(jetPhi - (o2::constants::math::PIHalf)); // 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 isTrackSelectedWithoutDcaxy(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.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; + } + + template + bool isTrackSelected(const TrackType track) + { + if (!isTrackSelectedWithoutDcaxy(track)) + return false; + if (std::fabs(track.dcaXY()) > cfgMaxDCArToPVcut && !useDcaxyPtDepCut) + return false; + if (std::fabs(track.dcaXY()) > dcaXYPtDepCut(track.pt()) && useDcaxyPtDepCut) + return false; + + return true; + } + + template + bool isOccupancyAccepted(const coll& collision) + { + auto occupancy{collision.trackOccupancyInTimeRange()}; + if (occupancy < cfgOccupancyRange->at(0) || occupancy > cfgOccupancyRange->at(1)) + return false; + else + return true; + } + + int nEvents = 0; + template + void fillTrackInfo(const TracksType& trk, const JetType& jets, std::vector& leadingJetPtEtaPhi, float backgroundRho = -1.0f) + { + 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 = RecoDecay::sumOfSquares(delEta, 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 = RecoDecay::sumOfSquares(delEta, delPhiPerpCone1); + double RPerpCone2 = RecoDecay::sumOfSquares(delEta, 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 = RecoDecay::sumOfSquares(delEta, delPhi); + if (R < cfgjetR) + jetFlag = true; + jetPt = jet.pt(); + break; + } + } + // tof + float massTOF = -999; + if (trk.hasTOF()) { + massTOF = trk.p() * std::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()); + } + + // Calculate background subtracted jet pt (needed for both jetFlag and perpCone) + float jetArea = M_PI * cfgjetR * cfgjetR; + float jetPtBkgSub = jetPt; + if (backgroundRho > 0) { + jetPtBkgSub = jetPt - backgroundRho * jetArea; + } + + 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); + // Background subtracted versions + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/pion/h3PtVsPionNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPi(), jetPtBkgSub); + jetHist.fill(HIST("tracks/kaon/h3PtVsKaonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaKa(), jetPtBkgSub); + } + } + + if (useTOFNsigmaPreSel && trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else if (!useTOFNsigmaPreSel && !useTOFVeto) { + 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); + // Background subtracted versions + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else if (!useTOFNsigmaPreSel && useTOFVeto) { + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } + + 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.tpcNSigmaTr()) < 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/h3TOFmassProtonVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/proton/h3TOFmass2ProtonVsPtVsJetPt_jet"), massTOF * massTOF - MassProton * MassProton, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/deuteron/h3TOFmassDeuteronVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/deuteron/h3TOFmass2DeuteronVsPtVsJetPt_jet"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/triton/h3TOFmassTritonVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/triton/h3TOFmass2TritonVsPtVsJetPt_jet"), massTOF * massTOF - MassTriton * MassTriton, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/helium/h3TOFmassHeliumVsPtVsJetPt_jet"), massTOF, trk.pt() / 2.0, jetPt); + jetHist.fill(HIST("tracks/helium/h3TOFmass2HeliumVsPtVsJetPt_jet"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt() / 2.0, jetPt); + // Background subtracted versions + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/proton/h3TOFmassProtonVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/proton/h3TOFmass2ProtonVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassProton * MassProton, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/deuteron/h3TOFmassDeuteronVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/deuteron/h3TOFmass2DeuteronVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/triton/h3TOFmassTritonVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/triton/h3TOFmass2TritonVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassTriton * MassTriton, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/helium/h3TOFmassHeliumVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt() / 2.0, jetPtBkgSub); + jetHist.fill(HIST("tracks/helium/h3TOFmass2HeliumVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt() / 2.0, jetPtBkgSub); + } + 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 (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracks/proton/h3TOFmassProtonVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/proton/h3TOFmass2ProtonVsPtVsJetPt_jet"), massTOF * massTOF - MassProton * MassProton, trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/proton/h3TOFmassProtonVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/proton/h3TOFmass2ProtonVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassProton * MassProton, trk.pt(), jetPtBkgSub); + } + 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 (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracks/deuteron/h3TOFmassDeuteronVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/deuteron/h3TOFmass2DeuteronVsPtVsJetPt_jet"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/deuteron/h3TOFmassDeuteronVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/deuteron/h3TOFmass2DeuteronVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), jetPtBkgSub); + } + 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 (std::abs(trk.tpcNSigmaTr()) < cfgnTPCPIDTr) { + jetHist.fill(HIST("tracks/triton/h3TOFmassTritonVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/triton/h3TOFmass2TritonVsPtVsJetPt_jet"), massTOF * massTOF - MassTriton * MassTriton, trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/triton/h3TOFmassTritonVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/triton/h3TOFmass2TritonVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassTriton * MassTriton, trk.pt(), jetPtBkgSub); + } + jetHist.fill(HIST("tracks/triton/h2TofNsigmaTritonVsPt_jet"), trk.tofNSigmaTr(), trk.pt()); + } + if (std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/helium/h3TOFmassHeliumVsPtVsJetPt_jet"), massTOF, trk.pt() / 2.0, jetPt); + jetHist.fill(HIST("tracks/helium/h3TOFmass2HeliumVsPtVsJetPt_jet"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt() / 2.0, jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/helium/h3TOFmassHeliumVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt() / 2.0, jetPtBkgSub); + jetHist.fill(HIST("tracks/helium/h3TOFmass2HeliumVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt() / 2.0, jetPtBkgSub); + } + 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); + // Background subtracted versions + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/antiPion/h3PtVsPionNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPi(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiKaon/h3PtVsKaonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaKa(), jetPtBkgSub); + } + } + + if (useTOFNsigmaPreSel && trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else if (!useTOFNsigmaPreSel && !useTOFVeto) { + 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); + // Background subtracted versions + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else if (!useTOFNsigmaPreSel && useTOFVeto) { + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub_jet"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } + + 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.tpcNSigmaTr()) < cfgnTPCPIDTr) { + 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/h3TOFmassantiProtonVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/antiProton/h3TOFmass2antiProtonVsPtVsJetPt_jet"), massTOF * massTOF - MassProton * MassProton, trk.pt(), jetPt); + 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/h3TOFmassantiDeuteronVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/antiDeuteron/h3TOFmass2antiDeuteronVsPtVsJetPt_jet"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), jetPt); + 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/h3TOFmassantiTritonVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/antiTriton/h3TOFmass2antiTritonVsPtVsJetPt_jet"), massTOF * massTOF - MassTriton * MassTriton, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/antiTriton/h2TofNsigmaantiTritonVsPt_jet"), trk.tofNSigmaTr(), trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h3TOFmassantiHeliumVsPtVsJetPt_jet"), massTOF, trk.pt() / 2.0, jetPt); + jetHist.fill(HIST("tracks/antiHelium/h3TOFmass2antiHeliumVsPtVsJetPt_jet"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt() / 2.0, jetPt); + jetHist.fill(HIST("tracks/antiHelium/h2TofNsigmaantiHeliumVsPt_jet"), trk.tofNSigmaHe(), trk.pt()); + // Background subtracted versions + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/antiProton/h3TOFmassantiProtonVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiProton/h3TOFmass2antiProtonVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassProton * MassProton, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiDeuteron/h3TOFmassantiDeuteronVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiDeuteron/h3TOFmass2antiDeuteronVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiTriton/h3TOFmassantiTritonVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiTriton/h3TOFmass2antiTritonVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassTriton * MassTriton, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiHelium/h3TOFmassantiHeliumVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt() / 2.0, jetPtBkgSub); + jetHist.fill(HIST("tracks/antiHelium/h3TOFmass2antiHeliumVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt() / 2.0, jetPtBkgSub); + } + } else { + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracks/antiProton/h3TOFmassantiProtonVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/antiProton/h3TOFmass2antiProtonVsPtVsJetPt_jet"), massTOF * massTOF - MassProton * MassProton, trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/antiProton/h3TOFmassantiProtonVsPtVsJetPtBkgSub_jet"), massTOF, trk.pt(), jetPtBkgSub); + jetHist.fill(HIST("tracks/antiProton/h3TOFmass2antiProtonVsPtVsJetPtBkgSub_jet"), massTOF * massTOF - MassProton * MassProton, trk.pt(), jetPtBkgSub); + } + 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 (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracks/antiDeuteron/h3TOFmassantiDeuteronVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/antiDeuteron/h3TOFmass2antiDeuteronVsPtVsJetPt_jet"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), jetPt); + 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 (std::abs(trk.tpcNSigmaTr()) < cfgnTPCPIDTr) { + jetHist.fill(HIST("tracks/antiTriton/h3TOFmassantiTritonVsPtVsJetPt_jet"), massTOF, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/antiTriton/h3TOFmass2antiTritonVsPtVsJetPt_jet"), massTOF * massTOF - MassTriton * MassTriton, trk.pt(), jetPt); + jetHist.fill(HIST("tracks/antiTriton/h2TofNsigmaantiTritonVsPt_jet"), trk.tofNSigmaTr(), trk.pt()); + } + if (std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/antiHelium/h3TOFmassantiHeliumVsPtVsJetPt_jet"), massTOF, trk.pt() / 2.0, jetPt); + jetHist.fill(HIST("tracks/antiHelium/h3TOFmass2antiHeliumVsPtVsJetPt_jet"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt() / 2.0, jetPt); + 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 (std::abs(trk.tpcNSigmaPi()) < useTPCpreSel) { + jetHist.fill(HIST("tracks/antiPion/h2TofNsigmaantiPionVsPt_jet"), trk.tofNSigmaPi(), trk.pt()); + } + if (std::abs(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 (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else if (!useTOFNsigmaPreSel && !useTOFVeto) { + 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 + // Background subtracted versions + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else if (!useTOFNsigmaPreSel && useTOFVeto) { + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + jetHist.fill(HIST("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); // Pr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); // Pr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/proton/h3PtVsProtonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/deuteron/h3PtVsDeuteronNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/helium/h3PtVsHeliumNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/triton/h3PtVsTritonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } + } + + 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.tpcNSigmaTr()) < 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 - MassProton * MassProton, 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 - MassDeuteron * MassDeuteron, 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 - MassTriton * MassTriton, 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 - MassHelium3 * MassHelium3, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TofNsigmaTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + } else { + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracks/proton/h2TOFmassProtonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt()); + jetHist.fill(HIST("tracks/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/proton/h3TofNsigmaProtonVsPtVsJetPt"), trk.tofNSigmaPr(), trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/proton/h3TofNsigmaProtonVsPtVsJetPtBkgSub"), trk.tofNSigmaPr(), trk.pt(), jetPtBkgSub); + } + } + } + if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/deuteron/h3TofNsigmaDeuteronVsPtVsJetPt"), trk.tofNSigmaDe(), trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/deuteron/h3TofNsigmaDeuteronVsPtVsJetPtBkgSub"), trk.tofNSigmaDe(), trk.pt(), jetPtBkgSub); + } + } + } + if (std::abs(trk.tpcNSigmaTr()) < cfgnTPCPIDTr) { + jetHist.fill(HIST("tracks/triton/h2TOFmassTritonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt"), massTOF * massTOF - MassTriton * MassTriton, trk.pt()); + jetHist.fill(HIST("tracks/triton/h2TofNsigmaTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/triton/h3TofNsigmaTritonVsPtVsJetPt"), trk.tofNSigmaTr(), trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/triton/h3TofNsigmaTritonVsPtVsJetPtBkgSub"), trk.tofNSigmaTr(), trk.pt(), jetPtBkgSub); + } + } + } + if (std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/helium/h2TOFmassHeliumVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt()); + jetHist.fill(HIST("tracks/helium/h2TofNsigmaHeliumVsPt"), trk.tofNSigmaHe(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/helium/h3TofNsigmaHeliumVsPtVsJetPt"), trk.tofNSigmaHe(), trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/helium/h3TofNsigmaHeliumVsPtVsJetPtBkgSub"), trk.tofNSigmaHe(), trk.pt(), jetPtBkgSub); + } + } + } + } + } // 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 (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else if (!useTOFNsigmaPreSel && !useTOFVeto) { + 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 + // Background subtracted versions + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else if (!useTOFNsigmaPreSel && useTOFVeto) { + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + jetHist.fill(HIST("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); // Pr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaPr(), jetPt); // Pr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiProton/h3PtVsantiProtonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaPr(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaDe(), jetPt); // De + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaDe(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaHe(), jetPt); // He + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3PtVsantiHeliumNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaHe(), jetPtBkgSub); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } else { + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJet"), trk.pt(), trk.tpcNSigmaTr(), jetPt); // Tr + if (backgroundRho > 0) + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3PtVsantiTritonNSigmaTPCVsPtJetBkgSub"), trk.pt(), trk.tpcNSigmaTr(), jetPtBkgSub); + } + } + } + + 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 - MassProton * MassProton, 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 - MassDeuteron * MassDeuteron, 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 - MassTriton * MassTriton, 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 - MassHelium3 * MassHelium3, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TofNsigmaantiTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + } else { + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracks/antiProton/h2TOFmassantiProtonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt()); + jetHist.fill(HIST("tracks/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/antiProton/h3TofNsigmaantiProtonVsPtVsJetPt"), trk.tofNSigmaPr(), trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/antiProton/h3TofNsigmaantiProtonVsPtVsJetPtBkgSub"), trk.tofNSigmaPr(), trk.pt(), jetPtBkgSub); + } + } + } + if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmassantiDeuteronVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt()); + jetHist.fill(HIST("tracks/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3TofNsigmaantiDeuteronVsPtVsJetPt"), trk.tofNSigmaDe(), trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/antiDeuteron/h3TofNsigmaantiDeuteronVsPtVsJetPtBkgSub"), trk.tofNSigmaDe(), trk.pt(), jetPtBkgSub); + } + } + } + if (std::abs(trk.tpcNSigmaTr()) < cfgnTPCPIDTr) { + jetHist.fill(HIST("tracks/antiTriton/h2TOFmassantiTritonVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TOFmass2antiTritonVsPt"), massTOF * massTOF - MassTriton * MassTriton, trk.pt()); + jetHist.fill(HIST("tracks/antiTriton/h2TofNsigmaantiTritonVsPt"), trk.tofNSigmaTr(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3TofNsigmaantiTritonVsPtVsJetPt"), trk.tofNSigmaTr(), trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/antiTriton/h3TofNsigmaantiTritonVsPtVsJetPtBkgSub"), trk.tofNSigmaTr(), trk.pt(), jetPtBkgSub); + } + } + } + if (std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracks/antiHelium/h2TOFmassantiHeliumVsPt"), massTOF, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TOFmass2antiHeliumVsPt"), massTOF * massTOF - MassHelium3 * MassHelium3, trk.pt()); + jetHist.fill(HIST("tracks/antiHelium/h2TofNsigmaantiHeliumVsPt"), trk.tofNSigmaHe(), trk.pt()); + if (jetFlagPerpCone && isWithLeadingJet) { + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3TofNsigmaantiHeliumVsPtVsJetPt"), trk.tofNSigmaHe(), trk.pt(), jetPt); + if (backgroundRho > 0) { + jetHist.fill(HIST("tracks/perpCone/antiHelium/h3TofNsigmaantiHeliumVsPtVsJetPtBkgSub"), trk.tofNSigmaHe(), trk.pt(), jetPtBkgSub); + } + } + } + } + } + } + } //////////////////////////////////////// + // 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 (std::abs(collision.posZ()) > cfgMaxZVertex) + 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; + float backgroundRho = collision.rho(); // Get background rho from collision + + // Fill background rho histogram once per event + jetHist.fill(HIST("jet/h1BkgRho"), backgroundRho); + + 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()); + + // Calculate background subtracted jet pt + float jetArea = M_PI * cfgjetR * cfgjetR; // Assuming circular jet area + float jetPtBkgSub = chargedjet.pt() - backgroundRho * jetArea; + + // Fill background corrected histograms + jetHist.fill(HIST("jet/h1JetPtBkgSub"), jetPtBkgSub); + jetHist.fill(HIST("jet/h2JetPtVsBkgRho"), chargedjet.pt(), backgroundRho); + + 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 (const auto& track : tracks) { + auto trk = track.track_as(); + fillTrackInfo(trk, chargedjets, leadingJetWithPtEtaPhi, backgroundRho); + } + } + + 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 (std::abs(collision.posZ()) > cfgMaxZVertex) + 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; + float backgroundRho = collision.rho(); // Get background rho from collision + + // Fill background rho histogram once per event + jetHist.fill(HIST("jet/h1BkgRho"), backgroundRho); + + 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()); + + // Calculate background subtracted jet pt + float jetArea = M_PI * cfgjetR * cfgjetR; // Assuming circular jet area + float jetPtBkgSub = chargedjet.pt() - backgroundRho * jetArea; + + // Fill background corrected histograms + jetHist.fill(HIST("jet/h1JetPtBkgSub"), jetPtBkgSub); + jetHist.fill(HIST("jet/h2JetPtVsBkgRho"), chargedjet.pt(), backgroundRho); + + 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, backgroundRho); + } + } + + void processDataInc(EventTable::iterator const& coll, soa::Join const& tracks, TrackCandidates const&) + { + jetHist.fill(HIST("hNEventsInc"), 0.5); + + bool isSel8 = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("sel8")); + bool isSelNoSameBunchPileup = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("NoSameBunchPileup")); + bool isSelIsGoodZvtxFT0vsPV = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("IsGoodZvtxFT0vsPV")); + + if (sel8Coll && !isSel8) + return; + jetHist.fill(HIST("hNEventsInc"), 1.5); + + if (std::abs(coll.posZ()) > 10) // bad vertex + return; + jetHist.fill(HIST("hNEventsInc"), 2.5); + if (selNoSameBunchPileup && !isSelNoSameBunchPileup) + return; + jetHist.fill(HIST("hNEventsInc"), 3.5); + if (selIsGoodZvtxFT0vsPV && !isSelIsGoodZvtxFT0vsPV) + return; + jetHist.fill(HIST("hNEventsInc"), 4.5); + + if (useOccupancy && !isOccupancyAccepted(coll)) + return; + jetHist.fill(HIST("hNEventsInc"), 5.5); + + float centrality = -999; + switch (centralityType) { + case 0: // FT0M + centrality = coll.centFT0M(); + break; + case 1: // FT0C + centrality = coll.centFT0C(); + break; + case 2: // V0A + centrality = coll.centFV0A(); + break; + default: + centrality = -999; + } + jetHist.fill(HIST("hNEventsIncVsCent"), coll.posZ(), centrality); + for (const auto& track : tracks) { + auto trk = track.track_as(); + if (!isTrackSelectedWithoutDcaxy(trk)) { + continue; + } + + auto rapidityData = [&](float m2z) { + const float rap = trk.rapidity(m2z); + return rap < std::abs(cfgtrkMaxRap); + }; + + auto prRapidityWithinRange = rapidityData(o2::constants::physics::MassProton); + auto deRapidityWithinRange = rapidityData(o2::constants::physics::MassDeuteron); + + if (std::fabs(trk.eta()) > cfgtrkMaxEta) + continue; + + bool hasTOF = trk.hasTOF(); + + if (trk.sign() > 0) { // particles + + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/proton/tpcPtVsDcaxy3D"), trk.pt(), centrality, trk.dcaXY()); + if (useTOFVeto && hasTOF) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/proton/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + jetHist.fill(HIST("tracksInc/dcaxy/rec/proton/tpcPtVsDcaxy3DPIDTOF"), trk.pt(), centrality, trk.dcaXY()); + } + } else { + jetHist.fill(HIST("tracksInc/dcaxy/rec/proton/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + } + } // proton + + if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/deuteron/tpcPtVsDcaxy3D"), trk.pt(), centrality, trk.dcaXY()); + if (useTOFVeto && hasTOF) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/deuteron/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + jetHist.fill(HIST("tracksInc/dcaxy/rec/deuteron/tpcPtVsDcaxy3DPIDTOF"), trk.pt(), centrality, trk.dcaXY()); + } + } else { + jetHist.fill(HIST("tracksInc/dcaxy/rec/deuteron/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + } + } // Deuteron + + if (std::abs(trk.tpcNSigmaTr()) < cfgnTPCPIDTr) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/triton/tpcPtVsDcaxy3D"), trk.pt(), centrality, trk.dcaXY()); + if (useTOFVeto && hasTOF) { + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/triton/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + jetHist.fill(HIST("tracksInc/dcaxy/rec/triton/tpcPtVsDcaxy3DPIDTOF"), trk.pt(), centrality, trk.dcaXY()); + } + } else { + jetHist.fill(HIST("tracksInc/dcaxy/rec/triton/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + } + } // Triton + + if (std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/helium/tpcPtVsDcaxy3D"), trk.pt(), centrality, trk.dcaXY()); + if (useTOFVeto && hasTOF) { + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/helium/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + jetHist.fill(HIST("tracksInc/dcaxy/rec/helium/tpcPtVsDcaxy3DPIDTOF"), trk.pt(), centrality, trk.dcaXY()); + } + } else { + jetHist.fill(HIST("tracksInc/dcaxy/rec/helium/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + } + } // Helium + + } else { // antiparticles + + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiProton/tpcPtVsDcaxy3D"), trk.pt(), centrality, trk.dcaXY()); + if (useTOFVeto && hasTOF) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiProton/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiProton/tpcPtVsDcaxy3DPIDTOF"), trk.pt(), centrality, trk.dcaXY()); + } + } else { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiProton/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + } + } // proton + + if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiDeuteron/tpcPtVsDcaxy3D"), trk.pt(), centrality, trk.dcaXY()); + if (useTOFVeto && hasTOF) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiDeuteron/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiDeuteron/tpcPtVsDcaxy3DPIDTOF"), trk.pt(), centrality, trk.dcaXY()); + } + } else { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiDeuteron/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + } + } // Deuteron + + if (std::abs(trk.tpcNSigmaTr()) < cfgnTPCPIDTr) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiTriton/tpcPtVsDcaxy3D"), trk.pt(), centrality, trk.dcaXY()); + if (useTOFVeto && hasTOF) { + if (std::abs(trk.tofNSigmaTr()) < cfgnTPCPIDTrTOF) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiTriton/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiTriton/tpcPtVsDcaxy3DPIDTOF"), trk.pt(), centrality, trk.dcaXY()); + } + } else { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiTriton/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + } + } // Triton + + if (std::abs(trk.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiHelium/tpcPtVsDcaxy3D"), trk.pt(), centrality, trk.dcaXY()); + if (useTOFVeto && hasTOF) { + if (std::abs(trk.tofNSigmaHe()) < cfgnTPCPIDHeTOF) { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiHelium/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiHelium/tpcPtVsDcaxy3DPIDTOF"), trk.pt(), centrality, trk.dcaXY()); + } + } else { + jetHist.fill(HIST("tracksInc/dcaxy/rec/antiHelium/tpcPtVsDcaxy3DPIDVeto"), trk.pt(), centrality, trk.dcaXY()); + } + } // Helium + + } // antiparticles + + // DCAxy selection for rest of the analysis + if (std::fabs(trk.dcaXY()) > cfgMaxDCArToPVcut && !useDcaxyPtDepCut) + continue; + if (std::fabs(trk.dcaXY()) > dcaXYPtDepCut(trk.pt()) && useDcaxyPtDepCut) + continue; + + if (trk.sign() > 0) { // particle info + if (useTOFNsigmaPreSel && trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF && (!useRapidityCutForPID || prRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + } + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF && (!useRapidityCutForPID || deRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } + } else if (!useTOFNsigmaPreSel && !useTOFVeto) { + if (!useRapidityCutForPID || prRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + } + if (!useRapidityCutForPID || deRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } + } else if (!useTOFNsigmaPreSel && useTOFVeto) { + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + if (!useRapidityCutForPID || prRapidityWithinRange) + jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + } + } else { + if (!useRapidityCutForPID || prRapidityWithinRange) + jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + if (!useRapidityCutForPID || deRapidityWithinRange) + jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } + } else { + if (!useRapidityCutForPID || deRapidityWithinRange) + jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } + } + if (addTOFplots && trk.hasTOF()) { + float massTOF = trk.p() * std::sqrt(1.f / (trk.beta() * trk.beta()) - 1.f); + if (!useTPCpreSel) { + if (!useRapidityCutForPID || prRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/proton/h2TOFmassProtonVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); + } + if (!useRapidityCutForPID || deRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/deuteron/h2TOFmassDeuteronVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); + } + } else { + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr && (!useRapidityCutForPID || prRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/proton/h2TOFmassProtonVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); + } + if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe && (!useRapidityCutForPID || deRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/deuteron/h2TOFmassDeuteronVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); + } + } + } + + if (cEnableProtonQA && std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr && (!useRapidityCutForPID || prRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/proton/dca/after/hDCAxyVsPtProton"), trk.dcaXY(), trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/proton/dca/after/hDCAzVsPtProton"), trk.dcaZ(), trk.pt(), centrality); + } + if (cEnableDeuteronQA && std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe && (!useRapidityCutForPID || deRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/deuteron/dca/after/hDCAxyVsPtDeuteron"), trk.dcaXY(), trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/deuteron/dca/after/hDCAzVsPtDeuteron"), trk.dcaZ(), trk.pt(), centrality); + } + + } else { // anti-particle info + if (useTOFNsigmaPreSel && trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF && (!useRapidityCutForPID || prRapidityWithinRange)) + jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF && (!useRapidityCutForPID || deRapidityWithinRange)) + jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } else if (!useTOFNsigmaPreSel && !useTOFVeto) { + if (!useRapidityCutForPID || prRapidityWithinRange) + jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + if (!useRapidityCutForPID || deRapidityWithinRange) + jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } else if (!useTOFNsigmaPreSel && useTOFVeto) { + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF && (!useRapidityCutForPID || prRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + } + } else { + if (!useRapidityCutForPID || prRapidityWithinRange) + jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + } + if (trk.hasTOF()) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF && (!useRapidityCutForPID || deRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } + } else { + if (!useRapidityCutForPID || deRapidityWithinRange) + jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } + } + if (addTOFplots && trk.hasTOF()) { + float massTOF = trk.p() * std::sqrt(1.f / (trk.beta() * trk.beta()) - 1.f); + if (!useTPCpreSel) { + if (!useRapidityCutForPID || prRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/antiProton/h2TOFmassantiProtonVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiProton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); + } + if (!useRapidityCutForPID || deRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmassantiDeuteronVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); + } + } else { + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr && (!useRapidityCutForPID || prRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/antiProton/h2TOFmassantiProtonVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiProton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); + } + if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe && (!useRapidityCutForPID || deRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmassantiDeuteronVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); + } + } + } + } // anti-particle info end + } // track + } + + 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 (std::abs(collision.posZ()) > cfgMaxZVertex) // bad vertex + return; + + jetHist.fill(HIST("mcpJet/eventStat"), 2.5); + + jetHist.fill(HIST("mcpJet/vertexZ"), collision.posZ()); + + // Use PWGLF INEL>0 functionality + if (!o2::pwglf::isINELgt0mc(mcParticles, pdgDB)) + return; + jetHist.fill(HIST("mcpJet/eventStat"), 3.5); + + int nJets = 0; + for (const 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 (std::fabs(mcParticle.eta()) > cfgtrkMaxEta) + continue; + if (std::fabs(mcParticle.y()) > cfgtrkMaxRap) + continue; + + bool jetFlag = false; + // float jetPt = -999.; + for (const auto& mcpjet : mcpjets) { + double delPhi = TVector2::Phi_mpi_pi(mcpjet.phi() - mcParticle.phi()); + double delEta = mcpjet.eta() - mcParticle.eta(); + double R = RecoDecay::sqrtSumOfSquares(delEta, 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 (std::abs(collisionJet.posZ()) > 10) + return; + + jetHist.fill(HIST("mcdJet/eventStat"), 2.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 (const auto& track : tracks) { + auto fullTrack = track.track_as(); + if (!isTrackSelected(fullTrack)) + continue; + if (!track.has_mcParticle()) + continue; + auto mcTrack = track.mcParticle_as(); + if (std::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 = RecoDecay::sqrtSumOfSquares(delEta, 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 = RecoDecay::sqrtSumOfSquares(delEta, delPhiPerpCone1); + double RPerpCone2 = RecoDecay::sqrtSumOfSquares(delEta, delPhiPerpCone2); + if (RPerpCone1 < cfgjetR || RPerpCone2 < cfgjetR) + jetFlagPerpCone = true; + } else { + for (const auto& mcdjet : mcdjets) { + double delPhi = TVector2::Phi_mpi_pi(mcdjet.phi() - track.phi()); + double delEta = mcdjet.eta() - track.eta(); + double R = RecoDecay::sqrtSumOfSquares(delEta, 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(JetCollWithLabel const& collision, JetMCDetTable const& mcdjets, + soa::Join const& tracks, + JetMCPartTable const&, TrackCandidatesMC const&, aod::JetParticles const& particleTracks, aod::JMcCollisions const&) + { + if (std::abs(collision.posZ()) > cfgMaxZVertex) + return; + if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) + return; + + jetHist.fill(HIST("recmatched/vertexZ"), collision.posZ()); + + 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 (const auto& mcdjet : mcdjets) { + if (!mcdjet.has_matchedJetGeo()) + continue; + for (const 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 (std::fabs(completeTrack.eta()) > cfgtrkMaxEta) + continue; + if (!isTrackSelected(completeTrack)) + continue; + if (!track.has_mcParticle()) + continue; + auto mcTrack = track.mcParticle_as(); + if (!mcTrack.isPhysicalPrimary()) + continue; + if (std::fabs(mcTrack.y()) > cfgtrkMaxRap) + continue; + + bool isTof(completeTrack.hasTOF()); + bool isTOFAndTPCPreSel(completeTrack.hasTOF() && + (std::abs(completeTrack.tpcNSigmaPr()) < cfgnTPCPIDPrTOF || std::abs(completeTrack.tpcNSigmaDe()) < cfgnTPCPIDDeTOF || + std::abs(completeTrack.tpcNSigmaHe()) < cfgnTPCPIDHeTOF || std::abs(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 = RecoDecay::sqrtSumOfSquares(delEta, 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 = RecoDecay::sqrtSumOfSquares(delEta, delPhiPerpCone1); + double RPerpCone2 = RecoDecay::sqrtSumOfSquares(delEta, 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 = RecoDecay::sqrtSumOfSquares(delEta, delPhi); + + if (R < cfgjetR) { + jetFlag = true; + break; + } + } + } // jet + + if (mapPDGToValue(mcTrack.pdgCode()) != 0) { + bool isTpcPassed(true); // why is this always true? + 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())); + jetHist.fill(HIST("eff/recmatched/pt/PtParticleTypeTPCTOFVeto"), mcTrack.pt(), jetFlag, mapPDGToValue(mcTrack.pdgCode())); + } else { + jetHist.fill(HIST("eff/recmatched/pt/PtParticleTypeTPCTOFVeto"), 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())); + jetHist.fill(HIST("eff/recmatched/perpCone/pt/PtParticleTypeTPCTOFVeto"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode())); + } + } else { + jetHist.fill(HIST("eff/recmatched/perpCone/pt/PtParticleTypeTPCTOFVeto"), 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 (std::fabs(mcParticle.eta()) > cfgtrkMaxEta) + continue; + if (std::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 = RecoDecay::sqrtSumOfSquares(delEta, 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 = RecoDecay::sqrtSumOfSquares(delEta, delPhiPerpCone1); + double RPerpCone2 = RecoDecay::sqrtSumOfSquares(delEta, 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 = RecoDecay::sqrtSumOfSquares(delEta, 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 (std::abs(collision.posZ()) > cfgMaxZVertex) + return; + jetHist.fill(HIST("genmatched/vertexZ"), collision.posZ()); + + 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()); + std::vector mcdJetPt{}; + std::vector mcdJetPhi{}; + std::vector mcdJetEta{}; + for (const 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 (std::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 = RecoDecay::sqrtSumOfSquares(delEta, 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 + + void processRecInc(EventTableMC::iterator const& coll, TrackCandidatesIncMC const& tracks, aod::JetParticles const& particleTracks, aod::JMcCollisions const&) + { + jetHist.fill(HIST("recInc/eventStat"), 0.5); + + bool isSel8 = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("sel8")); + bool isSelNoSameBunchPileup = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("NoSameBunchPileup")); + bool isSelIsGoodZvtxFT0vsPV = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("IsGoodZvtxFT0vsPV")); + + if (sel8Coll && !isSel8) + return; + jetHist.fill(HIST("recInc/eventStat"), 1.5); + + if (std::abs(coll.posZ()) > 10) // bad vertex + return; + jetHist.fill(HIST("recInc/eventStat"), 2.5); + if (selNoSameBunchPileup && !isSelNoSameBunchPileup) + return; + jetHist.fill(HIST("recInc/eventStat"), 3.5); + if (selIsGoodZvtxFT0vsPV && !isSelIsGoodZvtxFT0vsPV) + return; + jetHist.fill(HIST("recInc/eventStat"), 4.5); + + if (useOccupancy && !isOccupancyAccepted(coll)) + return; + jetHist.fill(HIST("recInc/eventStat"), 5.5); + + // if (!jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) + // return; + + float centrality = -999; + switch (centralityType) { + case 0: // FT0M + centrality = coll.centFT0M(); + break; + case 1: // FT0C + centrality = coll.centFT0C(); + break; + case 2: // FV0A + centrality = coll.centFV0A(); + break; + default: + centrality = -999; + } + jetHist.fill(HIST("recInc/vertexZ"), coll.posZ(), centrality); + + for (const auto& track : tracks) { + if (!isTrackSelectedWithoutDcaxy(track)) { + continue; + } + if (!track.has_mcParticle()) + continue; + if (std::fabs(track.eta()) > cfgtrkMaxEta) + continue; + + auto mcTrack = track.mcParticle_as(); + + // require mc getProcess to get Decay and Material secondaries + int particleOriginType = 0; + auto isMcPrimary = false; + auto isProdByGen = false; + auto isFromWeakDecay = false; + + isMcPrimary = mcTrack.isPhysicalPrimary(); + isProdByGen = mcTrack.producedByGenerator(); + isFromWeakDecay = mcTrack.getProcess() == TMCProcess::kPDecay; + + if (isMcPrimary) { + particleOriginType = 1; + } else if (!isProdByGen) { + particleOriginType = 2; // from transport + if (isFromWeakDecay) { + particleOriginType = 3; // from weak decay + } + } + + // Fill DCAxy histograms + jetHist.fill(HIST("recInc/dcaxy/rec/tpcPtVsDcaxy3D"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality, track.dcaXY(), particleOriginType); + if (std::abs(track.tpcNSigmaPr()) < cfgnTPCPIDPr) + jetHist.fill(HIST("recInc/dcaxy/rec/tpcPtVsDcaxy3DPIDselected"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality, track.dcaXY(), particleOriginType); + + if (!isMcPrimary) + continue; + + // DCAxy selection for rest of the analysis + if (std::fabs(track.dcaXY()) > cfgMaxDCArToPVcut && !useDcaxyPtDepCut) + continue; + if (std::fabs(track.dcaXY()) > dcaXYPtDepCut(track.pt()) && useDcaxyPtDepCut) + continue; + + // auto mass = TDatabasePDG::Instance()->GetParticle(abs(mcTrack.pdgCode()))->Mass(); + // auto rapidity = RecoDecay::y(std::array{track.px(), track.py(), track.pz()}, mass); + auto rapidity = mcTrack.y(); + + if (std::abs(rapidity) > cfgtrkMaxRap) + continue; + // Proton + if (std::abs(mcTrack.pdgCode()) == 2212) { // Proton + jetHist.fill(HIST("recInc/eff/tpcTrack3D"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (track.hasTOF()) + jetHist.fill(HIST("recInc/eff/tpcTofTrack3D"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (std::abs(track.tpcNSigmaPr()) < cfgnTPCPIDPr) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPC"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } + // Deuteron + if (std::abs(mcTrack.pdgCode()) == Pdg::kDeuteron) { // Deuteron + jetHist.fill(HIST("recInc/eff/tpcTrack3D"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (track.hasTOF()) + jetHist.fill(HIST("recInc/eff/tpcTofTrack3D"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (std::abs(track.tpcNSigmaDe()) < cfgnTPCPIDDe) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPC"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } + // Helium + if (std::abs(mcTrack.pdgCode()) == Pdg::kHelium3) { // Helium-3 + jetHist.fill(HIST("recInc/eff/tpcTrack3D"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (track.hasTOF()) + jetHist.fill(HIST("recInc/eff/tpcTofTrack3D"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (std::abs(track.tpcNSigmaHe()) < cfgnTPCPIDHe) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPC"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } + + // TPCTOF and TPCTOFVeto histograms + // Proton + if (std::abs(track.tpcNSigmaPr()) < cfgnTPCPIDPr && track.hasTOF()) { + if (std::abs(mcTrack.pdgCode()) == 2212) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOF"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (std::abs(track.tofNSigmaPr()) < cfgnTPCPIDPrTOF) + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOFVeto"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } else { + if (std::abs(track.tpcNSigmaPr()) < cfgnTPCPIDPr) { + if (std::abs(mcTrack.pdgCode()) == 2212) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOFVeto"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } + } + // Deuteron + if (std::abs(track.tpcNSigmaDe()) < cfgnTPCPIDDe && track.hasTOF()) { + if (std::abs(mcTrack.pdgCode()) == Pdg::kDeuteron) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOF"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (std::abs(track.tofNSigmaDe()) < cfgnTPCPIDDeTOF) + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOFVeto"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } else { + if (std::abs(track.tpcNSigmaDe()) < cfgnTPCPIDDe) { + if (std::abs(mcTrack.pdgCode()) == Pdg::kDeuteron) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOFVeto"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } + } + // Helium + if (std::abs(track.tpcNSigmaHe()) < cfgnTPCPIDHe && track.hasTOF()) { + if (std::abs(mcTrack.pdgCode()) == Pdg::kHelium3) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOF"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + if (std::abs(track.tofNSigmaHe()) < cfgnTPCPIDHeTOF) + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOFVeto"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } else { + if (std::abs(track.tpcNSigmaHe()) < cfgnTPCPIDHe) { + if (std::abs(mcTrack.pdgCode()) == Pdg::kHelium3) { + jetHist.fill(HIST("recInc/pt/PtParticleTypeTPCTOFVeto"), mcTrack.pt(), mapPDGToValue(mcTrack.pdgCode()), centrality); + } + } + } + } // track + + // loop over particles + auto mcParticles_per_coll = particleTracks.sliceBy(perMCCol, coll.mcCollision().globalIndex()); + for (const auto& mcParticle : mcParticles_per_coll) { + if (!mcParticle.isPhysicalPrimary()) + continue; + if (std::fabs(mcParticle.eta()) > cfgtrkMaxEta && useEtaSelForEffDen) + continue; + if (std::fabs(mcParticle.y()) > cfgtrkMaxRap) + continue; + + if (mapPDGToValue(mcParticle.pdgCode()) != 0) { + jetHist.fill(HIST("genInc/pt/PtParticleType"), mcParticle.pt(), mapPDGToValue(mcParticle.pdgCode()), centrality); + } + } // mc particles + } + + // Process function for event and signal loss analysis (inclusive) + void processEventSignalLoss(aod::JetMcCollision const& mcCollision, + soa::SmallGroups> const& recoColls, + aod::JetParticles const& mcParticles, + TrackCandidates const&) + { + + // Fill generated event statistics + jetHist.fill(HIST("eventLoss/hEventStatistics"), 0.5); // All Generated + + // Check if we have a reconstructed collision + bool hasRecoColl = false; + bool passSel8 = false; + bool passVz = false; + bool passINELgt0 = false; + bool isSel8 = false; + + float centrality = -999; + switch (centralityType) { + case 0: // FT0M + centrality = mcCollision.centFT0M(); + break; + case 1: // FT0C + centrality = mcCollision.multFT0C(); + break; + case 2: // V0A + centrality = mcCollision.multFV0A(); + break; + default: + centrality = -999; + } + + // Check INEL>0 at MC level using PWGLF functionality + bool mcINELgt0 = o2::pwglf::isINELgt0mc(mcParticles, pdgDB); + if (mcCollision.posZ() < 10) { + jetHist.fill(HIST("eventLoss/hEventStatistics"), 1.5); + if (mcINELgt0) { + jetHist.fill(HIST("eventLoss/hEventStatistics"), 2.5); + } + } + + for (const auto& recoColl : recoColls) { + hasRecoColl = true; + if (jetderiveddatautilities::selectCollision(recoColl, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) + isSel8 = true; + jetHist.fill(HIST("eventLoss/hEventStatistics"), 3.5); // Has Reco Coll + + if (isSel8) { + passSel8 = true; + jetHist.fill(HIST("eventLoss/hEventStatistics"), 4.5); // Pass Sel8 + } + + if (std::abs(recoColl.posZ()) < 10.0) { + passVz = true; + jetHist.fill(HIST("eventLoss/hEventStatistics"), 5.5); // Pass |Vz|<10 + } + + if (mcINELgt0) { + passINELgt0 = true; + jetHist.fill(HIST("eventLoss/hEventStatistics"), 6.5); // Pass rec INEL>0 + } + + break; // Only first reco collision + } + + // Final selection (all cuts passed) + if (hasRecoColl && passSel8 && passVz && passINELgt0) { + jetHist.fill(HIST("eventLoss/hEventStatistics"), 7.5); // Final Selection + } + + auto mcParticles_perColl = mcParticles.sliceBy(perMCCol, mcCollision.globalIndex()); + for (const auto& mcParticle : mcParticles_perColl) { + if (!mcParticle.isPhysicalPrimary()) + continue; + + // Apply kinematic cuts similar to track selection + if (std::fabs(mcParticle.eta()) > cfgtrkMaxEta) + continue; + + int particleType = mapPDGToValue(mcParticle.pdgCode()); + if (particleType == 0) + continue; // Only interested particles + + // Fill INEL>0 specific histograms + if (mcINELgt0) { + jetHist.fill(HIST("eventLoss/signalLoss/h3GenParticlesPtVsEtaVsCent_TrueINELgt0"), mcParticle.pt(), mcParticle.eta(), centrality); + jetHist.fill(HIST("eventLoss/signalLoss/h3GenParticleTypeVsPtVsCent_TrueINELgt0"), mcParticle.pt(), particleType, centrality); + } + + // Fill generated particle histograms (rec events) + if (hasRecoColl && passSel8 && passVz && passINELgt0) { + jetHist.fill(HIST("eventLoss/signalLoss/h3GenParticlesPtVsEtaVsCent_INELgt0"), mcParticle.pt(), mcParticle.eta(), centrality); + jetHist.fill(HIST("eventLoss/signalLoss/h3GenParticleTypeVsPtVsCent_INELgt0"), mcParticle.pt(), particleType, centrality); + } + } + } + + PROCESS_SWITCH(nucleiInJets, processJetTracksData, "nuclei in Jets data", true); + PROCESS_SWITCH(nucleiInJets, processJetTracksDataLfPid, "nuclei in Jets data", false); + PROCESS_SWITCH(nucleiInJets, processDataInc, "nuclei-data", false); + PROCESS_SWITCH(nucleiInJets, processRecInc, "nuclei MC", 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); + PROCESS_SWITCH(nucleiInJets, processEventSignalLoss, "Event and signal loss analysis (inclusive)", 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 cec6faae811..8571b76b880 100644 --- a/PWGJE/Tasks/phiInJets.cxx +++ b/PWGJE/Tasks/phiInJets.cxx @@ -15,31 +15,46 @@ /// /// \author Adrian Fereydon Nassirpour -#include -#include +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#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 "ReconstructionDataFormats/Track.h" +#include +#include +#include +#include +#include +#include + +#include "TRandom.h" +#include +#include +#include +#include -#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 -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/DataModel/Jet.h" +#include +#include +#include +#include +#include +#include +#include +#include -#include "PWGLF/DataModel/LFResonanceTables.h" +#include using namespace o2; using namespace o2::framework; @@ -76,14 +91,25 @@ struct phiInJets { 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 cfgPIDQAHists{"cfgPIDQAHists", false, "Enables PIDQA Hists"}; + Configurable cfgDaughterQAHists{"cfgDaughterQAHists", false, "Enables DaughterQA Hists"}; + Configurable cfgJetQAHists{"cfgJetQAHists", false, "Enables JetQA Hists"}; + Configurable cfgMCGenHists{"cfgMCGenHists", false, "Enables MCGenHists"}; Configurable cfgMCGenMATCHEDHists{"cfgMCGenMATCHEDHists", false, "Enables MCGenMATCHEDHists"}; Configurable cfgMCRecMATCHEDHists{"cfgMCRecMATCHEDHists", false, "Enables MCRecMATCHEDHists"}; + Configurable cfgMinvNBins{"cfgMinvNBins", 300, "Number of bins for Minv axis"}; + Configurable cfgMinvMin{"cfgMinvMin", 0.60, "Minimum Minv value"}; + Configurable cfgMinvMax{"cfgMinvMax", 1.20, "Maximum Minv value"}; + // CONFIG DONE ///////////////////////////////////////// //INIT - int eventSelection = -1; + std::vector eventSelectionBits; void init(o2::framework::InitContext&) { @@ -91,7 +117,7 @@ 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 = {500, 0.75, 1.25}; + const AxisSpec MinvAxis = {cfgMinvNBins, cfgMinvMin, cfgMinvMax}; const AxisSpec PtAxis = {200, 0, 20.0}; const AxisSpec MultAxis = {100, 0, 100}; const AxisSpec dRAxis = {100, 0, 100}; @@ -100,7 +126,6 @@ struct phiInJets { 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}}); @@ -125,42 +150,70 @@ struct phiInJets { JEhistos.add("FJptHistogram", "FJptHistogram", kTH1F, {axisPt}); JEhistos.add("nJetsPerEvent", "nJetsPerEvent", kTH1F, {{10, 0.0, 10.0}}); - JEhistos.add("hUSS", "hUSS", kTH3F, {dRAxis, PtAxis, MinvAxis}); + 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", kTH3F, {dRAxis, PtAxis, 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", kTH3F, {dRAxis, PtAxis, 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", kTH3F, {dRAxis, PtAxis, 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}}); + if (cfgJetQAHists) { + 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.}}}); + } + if (cfgPIDQAHists) { + 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}); + } + if (cfgDaughterQAHists) { + 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}); + } + // 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}); + } + + if (cfgMCRecRotationalHists) { + 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}}); + 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}}); + } - 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("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}}); - - JEhistos.add("hMCRec_nonmatch_hUSS_INSIDE", "hMCRec_nonmatch_hUSS_INSIDE", kTH3F, {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}); + // 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("hMCRec_nonmatch_hUSS_INSIDE", "hMCRec_nonmatch_hUSS_INSIDE", kTHnSparseF, {dRAxis, PtAxis, MinvAxis}); + JEhistos.add("JetVsPhi_REC", "JetVsPhi_REC", kTH2F, {{4000, 0., 200.}, {200, 0, 20.0}}); + JEhistos.add("minvJEHistogramPhi", "minvJEHistogramPhi", kTH1F, {MinvAxis}); + } } if (cfgMCGenHists) { @@ -183,7 +236,7 @@ struct phiInJets { 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", kTH3F, {dRAxis, PtAxis, MinvAxis}); + 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}); } @@ -197,7 +250,11 @@ struct phiInJets { JEhistos.add("2DGenToRec", "2DGenToRec", kTH2F, {PtAxis, axisPt}); JEhistos.add("2DGenToRec_constrained", "2DGenToRec_constrained", kTH2F, {PtAxis, axisPt}); - JEhistos.add("hMCTrue_hUSS_INSIDE", "hMCTrue_hUSS_INSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); + 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}); } @@ -216,55 +273,12 @@ struct phiInJets { JEhistos.add("2DRecToGen", "2DRecToGen", kTH2F, {PtAxis, axisPt}); JEhistos.add("2DRecToGen_constrained", "2DRecToGen_constrained", kTH2F, {PtAxis, axisPt}); - JEhistos.add("hMCRec_hUSS_INSIDE", "hMCRec_hUSS_INSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); + 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}); } - // 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("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_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("hMCTrue_hUSS_OUTSIDE_TRIG", "hMCTrue_hUSS_OUTSIDE_TRIG", kTH3F, {dRAxis, PtAxis, MinvAxis}); - // JEhistos.add("hMCTrue_hUSS_OUTSIDE_TRIG_1D", "hMCTrue_hUSS_OUTSIDE_TRIG_1D", kTH1F, {MinvAxis}); - // JEhistos.add("hMCTrue_hUSS_OUTSIDE_TRIG_1D_2_3", "hMCTrue_hUSS_OUTSIDE_TRIG_1D_2_3", kTH1F, {MinvAxis}); - // JEhistos.add("hMCTrue_nonmatch_hUSS_OUTSIDE", "hMCTrue_nonmatch_hUSS_OUTSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - // JEhistos.add("hMCTrue_nonmatch_hUSS_OUTSIDE_1D", "hMCTrue_nonmatch_hUSS_OUTSIDE_1D", kTH1F, {MinvAxis}); - // JEhistos.add("hMCTrue_nonmatch_hUSS_OUTSIDE_1D_2_3", "hMCTrue_nonmatch_hUSS_OUTSIDE_1D_2_3", kTH1F, {MinvAxis}); - // JEhistos.add("hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG", "hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG", kTH3F, {dRAxis, PtAxis, MinvAxis}); - // JEhistos.add("hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG_1D", "hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG_1D", kTH1F, {MinvAxis}); - // JEhistos.add("hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG_1D_2_3", "hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG_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_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}); - // JEhistos.add("hMCRec_hUSS_OUTSIDE_TRIG", "hMCRec_hUSS_OUTSIDE_TRIG", kTH3F, {dRAxis, PtAxis, MinvAxis}); - // JEhistos.add("hMCRec_hUSS_OUTSIDE_TRIG_1D", "hMCRec_hUSS_OUTSIDE_TRIG_1D", kTH1F, {MinvAxis}); - // JEhistos.add("hMCRec_hUSS_OUTSIDE_TRIG_1D_2_3", "hMCRec_hUSS_OUTSIDE_TRIG_1D_2_3", kTH1F, {MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS", "hMCRec_nonmatch_hUSS", kTH3F, {dRAxis, PtAxis, MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS_1D", "hMCRec_nonmatch_hUSS_1D", kTH1F, {MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS_1D_2_3", "hMCRec_nonmatch_hUSS_1D_2_3", kTH1F, {MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS_OUTSIDE", "hMCRec_nonmatch_hUSS_OUTSIDE", kTH3F, {dRAxis, PtAxis, MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS_OUTSIDE_1D", "hMCRec_nonmatch_hUSS_OUTSIDE_1D", kTH1F, {MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS_OUTSIDE_1D_2_3", "hMCRec_nonmatch_hUSS_OUTSIDE_1D_2_3", kTH1F, {MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS_OUTSIDE_TRIG", "hMCRec_nonmatch_hUSS_OUTSIDE_TRIG", kTH3F, {dRAxis, PtAxis, MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS_OUTSIDE_TRIG_1D", "hMCRec_nonmatch_hUSS_OUTSIDE_TRIG_1D", kTH1F, {MinvAxis}); - // JEhistos.add("hMCRec_nonmatch_hUSS_OUTSIDE_TRIG_1D_2_3", "hMCRec_nonmatch_hUSS_OUTSIDE_TRIG_1D_2_3", kTH1F, {MinvAxis}); - // EVENT SELECTION - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(cfgeventSelections)); + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(cfgeventSelections)); } // end of init @@ -412,7 +426,7 @@ struct phiInJets { double best_R = 0; double best_jetpt = 0; - for (int i = 0; i < jet_pt.size(); i++) { + 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)); @@ -432,7 +446,9 @@ struct phiInJets { template int minvReconstruction(double mult, const TracksType& trk1, const TracksType& trk2, const JetType& jets) { + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + //==================================================== if (!trackSelection(trk1) || !trackSelection(trk2)) return -1; @@ -456,6 +472,8 @@ struct phiInJets { lResonance = lDecayDaughter1 + lDecayDaughter2; + //================================================== + if (std::abs(lResonance.Eta()) > cfgtrkMaxEta) return -1; @@ -490,10 +508,11 @@ struct phiInJets { } } - if (cfgSingleJet) - if (goodjets > 1) + if (cfgSingleJet) { + if (goodjets > 1) { jetpt = DistinguishJets(jets, lResonance); - + } + } ///////////////////////////////////////////////////////////////////////////// // Fill inside Jet if (jetFlag) { @@ -513,33 +532,6 @@ struct phiInJets { } // 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"), jetpt, 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"), jetpt, 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"), jetpt, lResonance.Pt(), lResonance.M()); - } - } //! jetflag*/ - ///////////////////////////////////////////////////////////////////////////// if (!cfgIsKstar) { if (lResonance.M() > 1.005 && lResonance.M() < 1.035) { if (jetFlag) @@ -566,22 +558,19 @@ struct phiInJets { ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// 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 << "Ay Lmao" << std::endl; - double histmem = JEhistos.getSize(); - std::cout << histmem << std::endl; std::cout << "Processed Data Events: " << nEvents << std::endl; } } JEhistos.fill(HIST("nEvents"), 0.5); - if (fabs(collision.posZ()) > cfgVtxCut) + if (std::fabs(collision.posZ()) > cfgVtxCut) return; - if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::JCollisionSel::sel8)) + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) return; int nReso = 0; @@ -648,10 +637,10 @@ struct phiInJets { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// using myCompleteTracks = soa::Join; - using myCompleteJetTracks = soa::Join; + using myCompleteJetTracks = soa::Join; int nJEEvents = 0; int nprocessRecEvents = 0; - void processRec(o2::aod::JCollision const& collision, myCompleteJetTracks const& tracks, soa::Filtered const& mcdjets, aod::McParticles const&, myCompleteTracks const& /*originalTracks*/) + void processRec(o2::aod::JetCollision const& collision, myCompleteJetTracks const& tracks, soa::Filtered const& mcdjets, aod::McParticles const&, myCompleteTracks const& /*originalTracks*/) { if (cDebugLevel > 0) { nprocessRecEvents++; @@ -661,16 +650,18 @@ struct phiInJets { std::cout << "processRec: " << nprocessRecEvents << std::endl; } } - + //================= + // # of Events + //================= JEhistos.fill(HIST("nEvents_MCRec"), 0.5); - if (fabs(collision.posZ()) > cfgVtxCut) + if (std::fabs(collision.posZ()) > cfgVtxCut) return; - if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::JCollisionSel::sel8)) + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) return; bool INELgt0 = false; for (const auto& track : tracks) { - if (fabs(track.eta()) < cfgtrkMaxEta) { + if (std::fabs(track.eta()) < cfgtrkMaxEta) { INELgt0 = true; break; } @@ -690,14 +681,21 @@ struct phiInJets { 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 (cfgJetQAHists) { + 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); - // Track Eff + 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)) @@ -708,14 +706,15 @@ struct phiInJets { if (track.has_mcParticle()) { auto mcParticle = track.mcParticle(); - - if (mcParticle.isPhysicalPrimary() && fabs(mcParticle.eta()) <= cfgtrkMaxEta) { - if (abs(mcParticle.pdgCode()) == 211) - JEhistos.fill(HIST("ptJEHistogramPion"), mcParticle.pt()); - if (abs(mcParticle.pdgCode()) == 321) - JEhistos.fill(HIST("ptJEHistogramKaon"), mcParticle.pt()); - if (abs(mcParticle.pdgCode()) == 2212) - JEhistos.fill(HIST("ptJEHistogramProton"), mcParticle.pt()); + if (cfgPIDQAHists) { + if (mcParticle.isPhysicalPrimary() && std::fabs(mcParticle.eta()) <= cfgtrkMaxEta) { + if (abs(mcParticle.pdgCode()) == 211) + JEhistos.fill(HIST("ptJEHistogramPion"), mcParticle.pt()); + if (abs(mcParticle.pdgCode()) == 321) + JEhistos.fill(HIST("ptJEHistogramKaon"), mcParticle.pt()); + if (abs(mcParticle.pdgCode()) == 2212) + JEhistos.fill(HIST("ptJEHistogramProton"), mcParticle.pt()); + } } } for (const auto& track2 : tracks) { @@ -732,21 +731,138 @@ struct phiInJets { if (originalTrack.globalIndex() == originalTrack2.globalIndex()) continue; } - if (fabs(originalTrack.eta()) > cfgtrkMaxEta || fabs(originalTrack2.eta()) > cfgtrkMaxEta) + if (std::fabs(originalTrack.eta()) > cfgtrkMaxEta || std::fabs(originalTrack2.eta()) > cfgtrkMaxEta) continue; - // check PID + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance, lRotationalTrack, lRotationalResonance; + lDecayDaughter1.SetXYZM(originalTrack.px(), originalTrack.py(), originalTrack.pz(), massKa); + + if (cfgMCRecRotationalHists) { + 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; + + //----------------------------------------------------------------------- + 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); + } + lRotationalTrack = lDecayDaughter2; + lRotationalTrack.RotateZ(shift); + + double dPhi_rot = TVector2::Phi_mpi_pi(lDecayDaughter1.Phi() - lRotationalTrack.Phi()); + double dEta_rot = lDecayDaughter1.Eta() - lRotationalTrack.Eta(); + double dEta_rot_qa = TMath::Abs(lDecayDaughter2.Eta()) - TMath::Abs(lRotationalTrack.Eta()); + + dR_rot = TMath::Sqrt(dPhi_rot * dPhi_rot + dEta_rot * dEta_rot); + JEhistos.fill(HIST("hMCRec_dPhi_rot_distribution"), dPhi_rot); + JEhistos.fill(HIST("hMCRec_dEta_rot_distribution"), dEta_rot); + JEhistos.fill(HIST("hMCRec_dEta_qa_rot_distribution"), dEta_rot_qa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + + if (cfgIsKstar) { + lRotationalResonance = lDecayDaughter1 + lRotationalTrack; + JEhistos.fill(HIST("hMCRec_R_distribution"), dR); + JEhistos.fill(HIST("hMCRec_hUSS_Rotational"), 1.0, lRotationalResonance.Pt(), lResonance.M()); + JEhistos.fill(HIST("hMCRec_R_Rotation_distribution"), dR_rot); + } + } + //----------------------------------------------------------------------- + if (!cfgIsKstar) { + lDecayDaughter2.SetXYZM(originalTrack2.px(), originalTrack2.py(), originalTrack2.pz(), massKa); + } else { + lDecayDaughter2.SetXYZM(originalTrack2.px(), originalTrack2.py(), originalTrack2.pz(), massPi); + } + lResonance = lDecayDaughter1 + lDecayDaughter2; + + if (std::fabs(lResonance.Eta()) > cfgtrkMaxEta) + continue; + + if (cfgDaughterQAHists) { + 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()); + + } 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 (cfgDaughterQAHists) { + 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 (cfgDaughterQAHists && R < cfgjetR) { + 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)); + + 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) + if (std::fabs(part1.pdgCode()) != 321) continue; // Not Kaon if (!cfgIsKstar) { - if (fabs(part2.pdgCode()) != 321) + if (std::fabs(part2.pdgCode()) != 321) continue; // Not Kaon } else { - if (fabs(part2.pdgCode()) != 211) + if (std::fabs(part2.pdgCode()) != 211) continue; // Not Kaon } @@ -783,87 +899,78 @@ struct phiInJets { if (mothers1[0] != mothers2[0]) continue; // Kaons not from the same phi - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; - lDecayDaughter1.SetXYZM(originalTrack.px(), originalTrack.py(), originalTrack.pz(), massKa); - if (!cfgIsKstar) - lDecayDaughter2.SetXYZM(originalTrack2.px(), originalTrack2.py(), originalTrack2.pz(), massKa); - else - lDecayDaughter2.SetXYZM(originalTrack2.px(), originalTrack2.py(), originalTrack2.pz(), massPi); - lResonance = lDecayDaughter1 + lDecayDaughter2; - - 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)); - if (fabs(lResonance.Eta()) > cfgtrkMaxEta) - continue; - JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_KtoKangle_v_pt"), R_Kaons, lResonance.Pt()); - JEhistos.fill(HIST("ptJEHistogramPhi"), lResonance.Pt()); - - // Now we do jets - bool jetFlag = false; - int goodjets = 0; - double jetpt = 0; - for (int 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 (cfgDaughterQAHists) { + 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()); + } - 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 (cfgPIDQAHists) { + 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()); } - if (R < cfgjetR) { - jetFlag = true; - jetpt = mcd_pt[i]; - goodjets++; + } + //=========================== + // 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()); + } } } + if (cfgDaughterQAHists) { + 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 (cfgSingleJet) - if (goodjets > 1) - jetpt = DistinguishJetsMC(mcd_pt, mcd_phi, mcd_eta, lResonance); - - if (jetFlag) { - 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()); - - } /* else if (!jetFlag && mcd_pt.size() > 0) { - JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_OUTSIDE_TRIG_1D"), lResonance.M()); - - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_OUTSIDE_TRIG_1D_2_3"), lResonance.M()); - - JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_OUTSIDE_TRIG"), jetpt, lResonance.Pt(), lResonance.M()); - - } else if (!jetFlag) { - JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_OUTSIDE_1D"), lResonance.M()); - - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_OUTSIDE_1D_2_3"), lResonance.M()); + if (jetFlag) { + if (cfgDaughterQAHists) { + if (lResonance.M() > 1.005 && lResonance.M() < 1.035) { + RealPhiCandInJet++; + } + JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_INSIDE_pt_v_eta"), lResonance.Pt(), lResonance.Eta()); + // 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()); + } + } - JEhistos.fill(HIST("hMCRec_nonmatch_hUSS_OUTSIDE"), jetpt, lResonance.Pt(), lResonance.M()); - }*/ - //! jetflag + if (hasJets) { + if (cfgPIDQAHists) + JEhistos.fill(HIST("ptJEHistogramPhi_JetTrigger"), lResonance.Pt()); - 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()); + auto triggerjet = std::min_element(mcd_pt.begin(), mcd_pt.end()); + double triggerjet_pt = *triggerjet; + if (!cfgIsKstar) { + JEhistos.fill(HIST("JetVsPhi_REC"), triggerjet_pt, lResonance.Pt()); + } + } + if (cfgDaughterQAHists) { + JEhistos.fill(HIST("minvJEHistogramPhi"), lResonance.M()); + } } - JEhistos.fill(HIST("minvJEHistogramPhi"), lResonance.M()); } // mcpart check - } // tracks2 - } // tracks1 + } // tracks2 + } // tracks1 + if (cfgDaughterQAHists) { + JEhistos.fill(HIST("hNRealPhiVPhiCand"), PhiCand, RealPhiCand); + JEhistos.fill(HIST("hNRealPhiWithJetVPhiCand"), PhiCand, RealPhiCandWithJet); + JEhistos.fill(HIST("hNRealPhiInJetVPhiCand"), PhiCand, RealPhiCandInJet); + } // Jet Eff } PROCESS_SWITCH(phiInJets, processRec, "pikp detector level MC JE", true); @@ -872,7 +979,7 @@ struct phiInJets { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int nprocessSimEvents = 0; // Preslice slice = o2::aod::JCollision::collisionId; - void processSim(o2::aod::JMcCollision const& collision, soa::SmallGroups> const& recocolls, aod::JMcParticles const& mcParticles, soa::Filtered const& mcpjets) + void processSim(o2::aod::JetMcCollision const& collision, soa::SmallGroups> const& recocolls, aod::JetParticles const& mcParticles, soa::Filtered const& mcpjets) { if (cDebugLevel > 0) { nprocessSimEvents++; @@ -889,15 +996,15 @@ struct phiInJets { return; for (auto& recocoll : recocolls) { // poorly reconstructed - if (!jetderiveddatautilities::selectCollision(recocoll, jetderiveddatautilities::JCollisionSel::sel8)) + if (!jetderiveddatautilities::selectCollision(recocoll, eventSelectionBits)) return; } - if (fabs(collision.posZ()) > cfgVtxCut) // bad vertex + if (std::fabs(collision.posZ()) > cfgVtxCut) // bad vertex return; bool INELgt0 = false; for (const auto& mcParticle : mcParticles) { - if (fabs(mcParticle.eta()) < cfgtrkMaxEta) { + if (std::fabs(mcParticle.eta()) < cfgtrkMaxEta) { INELgt0 = true; break; } @@ -927,7 +1034,7 @@ struct phiInJets { // Check pikp and phi for (const auto& mcParticle : mcParticles) { - if (mcParticle.isPhysicalPrimary() && fabs(mcParticle.eta()) <= cfgtrkMaxEta) { // watch out for context!!! + if (mcParticle.isPhysicalPrimary() && std::fabs(mcParticle.eta()) <= cfgtrkMaxEta) { // watch out for context!!! if (abs(mcParticle.pdgCode()) == 211) JEhistos.fill(HIST("ptGeneratedPion"), mcParticle.pt()); if (abs(mcParticle.pdgCode()) == 321) @@ -935,7 +1042,7 @@ struct phiInJets { if (abs(mcParticle.pdgCode()) == 2212) JEhistos.fill(HIST("ptGeneratedProton"), mcParticle.pt()); } - if (fabs(mcParticle.eta()) <= cfgtrkMaxEta) { // watch out for context!!! + if (std::fabs(mcParticle.eta()) <= cfgtrkMaxEta) { // watch out for context!!! TLorentzVector lResonance; lResonance.SetPxPyPzE(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); @@ -954,13 +1061,13 @@ struct phiInJets { // if we check for Phi if (!cfgIsKstar) { if (mcParticle.has_daughters()) - for (auto& dgth : mcParticle.daughters_as()) - if (fabs(dgth.pdgCode()) != 321) + for (auto& dgth : mcParticle.daughters_as()) + if (std::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) + for (auto& dgth : mcParticle.daughters_as()) + if (std::fabs(dgth.pdgCode()) != 321 || std::fabs(dgth.pdgCode()) != 211) skip = true; } @@ -976,12 +1083,12 @@ struct phiInJets { TLorentzVector lResonance; lResonance.SetPxPyPzE(mcParticle.px(), mcParticle.py(), mcParticle.pz(), mcParticle.e()); bool jetFlag = false; - for (int i = 0; i < mcp_pt.size(); i++) { + 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()) { + 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)); @@ -1005,24 +1112,7 @@ struct phiInJets { 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()); - - } /* else if (!jetFlag && mcp_pt.size() > 0) { - JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG_1D"), lResonance.M()); - - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG_1D_2_3"), lResonance.M()); - - JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_OUTSIDE_TRIG"), jetpt, lResonance.Pt(), lResonance.M()); - - } else if (!jetFlag) { - JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_OUTSIDE_1D"), lResonance.M()); - - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_OUTSIDE_1D_2_3"), lResonance.M()); - - JEhistos.fill(HIST("hMCTrue_nonmatch_hUSS_OUTSIDE"), jetpt, lResonance.Pt(), lResonance.M()); - - }*/ //! jetflag + } ////////////////////////////Phi found if (hasJets) { @@ -1033,9 +1123,9 @@ struct phiInJets { } // check for jets } // check for phi - } // check for rapidity - } // loop over particles - } // process switch + } // check for rapidity + } // loop over particles + } // process switch PROCESS_SWITCH(phiInJets, processSim, "pikp particle level MC", true); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1045,13 +1135,14 @@ struct phiInJets { using JetMCDTable = soa::Filtered>; int nprocessSimJEEvents = 0; - void processMatchedGen(aod::JMcCollision const& collision, - soa::SmallGroups> const& recocolls, + void processMatchedGen(aod::JetMcCollision const& collision, + soa::SmallGroups> const& recocolls, JetMCDTable const& /*mcdjets*/, JetMCPTable const& mcpjets, myCompleteJetTracks const& tracks, myCompleteTracks const&, - aod::JMcParticles const& mcParticles) + aod::JetParticles const& mcParticles, + aod::McParticles const&) { if (cDebugLevel > 0) { @@ -1065,13 +1156,13 @@ struct phiInJets { JEhistos.fill(HIST("nEvents_MCGen_MATCHED"), 0.5); - if (fabs(collision.posZ()) > cfgVtxCut) + if (std::fabs(collision.posZ()) > cfgVtxCut) return; if (recocolls.size() <= 0) // not reconstructed return; for (auto& recocoll : recocolls) { // poorly reconstructed - if (!jetderiveddatautilities::selectCollision(recocoll, jetderiveddatautilities::JCollisionSel::sel8)) + if (!jetderiveddatautilities::selectCollision(recocoll, eventSelectionBits)) return; } @@ -1115,14 +1206,14 @@ 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.eta()) > cfgtrkMaxEta) + if (std::fabs(mcParticle.eta()) > cfgtrkMaxEta) continue; int GenPID = 0; @@ -1132,19 +1223,23 @@ struct phiInJets { else GenPID = 313; - if (fabs(mcParticle.pdgCode()) == GenPID) { + if (std::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) { + int dgth_index = 0; + for (auto& dgth : mcParticle.daughters_as()) { + if (std::fabs(dgth.pdgCode()) != 321) { skip = true; break; } @@ -1152,24 +1247,38 @@ struct phiInJets { auto trk = track.track_as(); if (!trackSelection(trk)) continue; + if (std::fabs(trk.eta()) > cfgtrkMaxEta) + continue; if (cfgSimPID) { if (!trackPID(trk, true)) continue; } - if (track.globalIndex() == dgth.globalIndex()) { - phi_dgth_px[dgth_index] = track.px(); - phi_dgth_py[dgth_index] = track.py(); - phi_dgth_pz[dgth_index] = track.pz(); + 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++; - } - } - } - } - } else { + 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) + for (auto& dgth : mcParticle.daughters_as()) + if (std::fabs(dgth.pdgCode()) != 321 || std::fabs(dgth.pdgCode()) != 211) skip = true; } @@ -1187,12 +1296,9 @@ struct phiInJets { 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; - if (cDebugLevel > 0) - if (good_daughter[0] && good_daughter[1]) - std::cout << "Reconstructed level phi pT: " << lResonance_REC.Pt() << std::endl; bool jetFlag = false; - for (int i = 0; i < mcp_pt.size(); i++) { + 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)); @@ -1211,6 +1317,25 @@ struct phiInJets { } 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 @@ -1221,35 +1346,17 @@ struct phiInJets { 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"), jetpt_mcp, lResonance.Pt(), lResonance.M()); - - } /* else if (!jetFlag && mcp_pt.size() > 0) { - JEhistos.fill(HIST("hMCTrue_hUSS_OUTSIDE_TRIG_1D"), lResonance.M()); - - if (lResonance.Pt() > 2.0 && lResonance.Pt() < 3) - JEhistos.fill(HIST("hMCTrue_hUSS_OUTSIDE_TRIG_1D_2_3"), lResonance.M()); - - JEhistos.fill(HIST("hMCTrue_hUSS_OUTSIDE_TRIG"), jetpt_mcp, lResonance.Pt(), lResonance.M()); - - } else 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"), jetpt_mcp, lResonance.Pt(), lResonance.M()); - - }*/ - //! jetflag - } // chech for phi - } // MC Particles - } // main fcn + } + } // 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, @@ -1262,19 +1369,19 @@ struct phiInJets { if ((nprocessRecJEEvents + 1) % 10000 == 0) { double histmem = JEhistos.getSize(); std::cout << histmem << std::endl; - std::cout << "processMatched Rec Events: " << nprocessRecJEEvents << std::endl; + std::cout << "processMatchedRec: " << nprocessRecEvents << std::endl; } } JEhistos.fill(HIST("nEvents_MCRec_MATCHED"), 0.5); - if (fabs(collision.posZ()) > cfgVtxCut) + if (std::fabs(collision.posZ()) > cfgVtxCut) return; - if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::JCollisionSel::sel8)) + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) return; bool INELgt0 = false; for (const auto& track : tracks) { - if (fabs(track.eta()) < cfgtrkMaxEta) { + if (std::fabs(track.eta()) < cfgtrkMaxEta) { INELgt0 = true; break; } @@ -1310,7 +1417,7 @@ struct phiInJets { mcp_eta.push_back(mcpjet.eta()); mcp_phi.push_back(mcpjet.phi()); } // mcpjets - } // mcdjets + } // mcdjets // Now we do REC part if (hasJets) JEhistos.fill(HIST("nEvents_MCRec_MATCHED"), 2.5); @@ -1326,7 +1433,7 @@ struct phiInJets { if (trk1.globalIndex() == trk2.globalIndex()) continue; } - if (fabs(trk1.eta()) > cfgtrkMaxEta || fabs(trk2.eta()) > cfgtrkMaxEta) + if (std::fabs(trk1.eta()) > cfgtrkMaxEta || std::fabs(trk2.eta()) > cfgtrkMaxEta) continue; if ((trk1.sign() * trk2.sign()) > 0) continue; // Not K+K- @@ -1340,13 +1447,13 @@ struct phiInJets { if (track1.has_mcParticle() && track2.has_mcParticle()) { auto part1 = track1.mcParticle(); auto part2 = track2.mcParticle(); - if (fabs(part1.pdgCode()) != 321) + if (std::fabs(part1.pdgCode()) != 321) continue; // Not Kaon if (!cfgIsKstar) { - if (fabs(part2.pdgCode()) != 321) + if (std::fabs(part2.pdgCode()) != 321) continue; // Not Kaon } else { - if (fabs(part2.pdgCode()) != 211) + if (std::fabs(part2.pdgCode()) != 211) continue; // Not Kaon } if (!part1.has_mothers()) @@ -1393,14 +1500,14 @@ struct phiInJets { lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massPi); lResonance = lDecayDaughter1 + lDecayDaughter2; - if (fabs(lResonance.Eta()) > cfgtrkMaxEta) + if (std::fabs(lResonance.Eta()) > cfgtrkMaxEta) continue; bool jetFlag = false; int goodjets = 0; double jetpt_mcp = 0; double jetpt_mcd = 0; - for (int i = 0; i < mcd_pt.size(); i++) { + 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)); @@ -1421,6 +1528,7 @@ struct phiInJets { 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; @@ -1447,32 +1555,32 @@ struct phiInJets { 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()); - } /* 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()); + // 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()); + // 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()); + // } 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()); + // 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()); + // JEhistos.fill(HIST("hMCRec_hUSS_OUTSIDE"), jetpt_mcd, lResonance.Pt(), lResonance.M()); - }*/ //! jetflag + // } //! jetflag } // pass track cut - } // has mc particle + } // has mc particle } // tracks 2 - } // tracks 1 + } // tracks 1 // } // tracks - } // main fcn + } // main fcn PROCESS_SWITCH(phiInJets, processMatchedRec, "phi matched Rec level MC", true); }; // end of main struct diff --git a/PWGJE/Tasks/photonChargedTriggerCorrelation.cxx b/PWGJE/Tasks/photonChargedTriggerCorrelation.cxx new file mode 100644 index 00000000000..0f4dbf82e41 --- /dev/null +++ b/PWGJE/Tasks/photonChargedTriggerCorrelation.cxx @@ -0,0 +1,1475 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file photonChargedTriggerCorrelation.cxx +/// \author Julius Kinner +/// \brief photon-jet angular correlation analysis +/// +/// Analysis for angular correlations between jets and photons via two-particle correlations with charged high-pt triggers +/// Associated hadrons (tracks), pipm, photons (PCM), pi0 (PCM) +/// Also contains checks and monte-carlo (efficiency, purity, mc-true correlation,...) +/// End goal of studying correlations between direct photons and jets + +#include "PWGJE/DataModel/PhotonChargedTriggerCorrelation.h" + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGJE/DataModel/Jet.h" + +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TMath.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +const double absEtaMaxDefault = 0.8; +#define DPHI_SCALE constants::math::TwoPI - constants::math::PIHalf +#define DETA_SCALE 4 * absEtaMaxDefault - 2 * absEtaMaxDefault + +using namespace o2; +using namespace o2::framework; + +using CorrCollisions = soa::Join; +using CorrCollision = CorrCollisions::iterator; +using CorrMcDCollisions = soa::Join; +using CorrMcDCollision = CorrMcDCollisions::iterator; +using CorrMcCollisions = soa::Join; +using CorrMcCollision = CorrMcCollisions::iterator; + +using BinningZPvMult = ColumnBinningPolicy; + +// correlation analysis ======================================================================================================================================================================= + +struct PhotonChargedTriggerCorrelation { + // configurables + + // general (kenobi) + Configurable pathCcdbEff{"pathCcdbEff", "Users/j/jkinner/efficiency/set_in_config", "base path to the ccdb efficiencies"}; + Configurable urlCcdb{"urlCcdb", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable noLaterThanCcdbConfig{"noLaterThanCcdbConfig", -1, "latest acceptable timestamp of creation for the object (-1 for task start time)"}; + + // analysis + Configurable doEffCorrectionTrigger{"doEffCorrectionTrigger", false, "whether to do on-the-fly mixing correction for triggers"}; + Configurable doEffCorrectionHadron{"doEffCorrectionHadron", false, "whether to do on-the-fly mixing correction for hadrons"}; + Configurable doEffCorrectionPipm{"doEffCorrectionPipm", false, "whether to do on-the-fly mixing correction for pipm"}; + Configurable doEffCorrectionPhotonPCM{"doEffCorrectionPhotonPCM", false, "whether to do on-the-fly mixing correction for photonPCM"}; + + Configurable doTrigEvMixing{"doTrigEvMixing", false, "whether to use trigger events for trigger mixing"}; + Configurable nTriggerSavedForMixing{"nTriggerSavedForMixing", 2048, "number of triggers that are saved for mixing with other events"}; + Configurable nTriggerMixingMcTrue{"nTriggerMixingMcTrue", 8, "number of triggers that are used for mc true mixing"}; + Configurable nTriggerMixingHadron{"nTriggerMixingHadron", 64, "number of triggers that are used for hadron mixing"}; + Configurable nTriggerMixingPipm{"nTriggerMixingPipm", 64, "number of triggers that are used for pipm mixing"}; + Configurable nTriggerMixingPhotonPCM{"nTriggerMixingPhotonPCM", 256, "number of triggers that are saved for photonPCM mixing"}; + Configurable nTriggerMixingH0PCM{"nTriggerMixingH0PCM", 256, "number of triggers that are saved for h0PCM (pi0, eta) mixing"}; + Configurable nNeighboursMixingPhotonPCMPair{"nNeighboursMixingPhotonPCMPair", 32, "number neighbours used for for photonPCM pair mixing"}; + Configurable> pi0PCMPeakMassRange{"pi0PCMPeakMassRange", {0.10, 0.15}, "photon-pair mass integration range for pi0PCM"}; + Configurable> pi0PCMSideMassRange{"pi0PCMSideMassRange", {0.16, 0.24}, "photon-pair mass integration range outside pi0PCM region"}; + Configurable> etaPCMPeakMassRange{"etaPCMPeakMassRange", {0.51, 0.56}, "photon-pair mass integration range for etaPCM"}; + Configurable> etaPCMLowSideMassRange{"etaPCMLowSideMassRange", {0.45, 0.50}, "photon-pair mass integration range below etaPCM region"}; + Configurable> etaPCMHighSideMassRange{"etaPCMHighSideMassRange", {0.56, 0.65}, "photon-pair mass integration range above etaPCM region"}; + + Configurable doTrigEvEff{"doTrigEvEff", false, "whether to use trigger events for efficiency histograms"}; + Configurable ptCutTrigEvEff{"ptCutTrigEvEff", 4, "pT cut for efficieny calculation in trigger events (to avoid trigger bias)"}; + Configurable requireSingleCollisionPurity{"requireSingleCollisionPurity", true, "whether particle from single chosen MC-col associated to reco-col (else just type/kin match)"}; + + // for histograms + Configurable nBinsZPv{"nBinsZPv", 100, "number zPv bins in histos for QA"}; + Configurable nBinsZPvSmol{"nBinsZPvSmol", 28, "number zPv bins but smaller"}; + Configurable nBinsMult{"nBinsMult", 200, "number multiplicity bins in histos for QA"}; + Configurable nBinsMultSmol{"nBinsMultSmol", 20, "number multiplicity bins but smaller"}; + Configurable nBinsOccupancy{"nBinsOccupancy", 2000, "number occupancy bins in histos for QA"}; + + Configurable nBinsPhi{"nBinsPhi", 72, "number phi bins"}; + Configurable nBinsEta{"nBinsEta", 40, "number eta bins"}; + Configurable nBinsMgg{"nBinsMgg", 160, "number mass-photon-pair bins"}; + + Configurable> binsPtTrig{"binsPtTrig", {5, 10, 25, 50}, "correlation ptTrig bins"}; + Configurable> binsPtAssoc{"binsPtAssoc", + {0.2, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 7.0, 8.0, 9.0, 10, 12.5, 15, 17.5, 20, 30, 40}, + "correlation ptAssoc bins"}; + Configurable> binsDPhi{"binsDPhi", + {0.00 * DPHI_SCALE, + 0.04 * DPHI_SCALE, 0.08 * DPHI_SCALE, 0.11 * DPHI_SCALE, 0.14 * DPHI_SCALE, + 0.16 * DPHI_SCALE, 0.18 * DPHI_SCALE, 0.20 * DPHI_SCALE, 0.22 * DPHI_SCALE, + 0.23 * DPHI_SCALE, 0.24 * DPHI_SCALE, 0.25 * DPHI_SCALE, 0.26 * DPHI_SCALE, 0.27 * DPHI_SCALE, 0.28 * DPHI_SCALE, + 0.30 * DPHI_SCALE, 0.32 * DPHI_SCALE, 0.34 * DPHI_SCALE, 0.36 * DPHI_SCALE, + 0.39 * DPHI_SCALE, 0.42 * DPHI_SCALE, 0.46 * DPHI_SCALE, 0.50 * DPHI_SCALE, + 0.54 * DPHI_SCALE, 0.58 * DPHI_SCALE, 0.61 * DPHI_SCALE, 0.64 * DPHI_SCALE, + 0.66 * DPHI_SCALE, 0.68 * DPHI_SCALE, 0.70 * DPHI_SCALE, 0.72 * DPHI_SCALE, + 0.74 * DPHI_SCALE, 0.76 * DPHI_SCALE, 0.78 * DPHI_SCALE, + 0.80 * DPHI_SCALE, 0.82 * DPHI_SCALE, 0.84 * DPHI_SCALE, 0.86 * DPHI_SCALE, + 0.89 * DPHI_SCALE, 0.92 * DPHI_SCALE, 0.96 * DPHI_SCALE, 1.00 * DPHI_SCALE}, + "correlation bins DeltaPhi"}; + Configurable> binsDEta{"binsDEta", + {0 / 32. * DETA_SCALE, + 1 / 32. * DETA_SCALE, 2 / 32. * DETA_SCALE, 3 / 32. * DETA_SCALE, 4 / 32. * DETA_SCALE, + 5 / 32. * DETA_SCALE, 6 / 32. * DETA_SCALE, 7 / 32. * DETA_SCALE, 8 / 32. * DETA_SCALE, + 9 / 32. * DETA_SCALE, 10 / 32. * DETA_SCALE, 11 / 32. * DETA_SCALE, 12 / 32. * DETA_SCALE, 13 / 32. * DETA_SCALE, 14 / 32. * DETA_SCALE, + 59 / 128. * DETA_SCALE, 62 / 128. * DETA_SCALE, 64 / 128. * DETA_SCALE, 66 / 128. * DETA_SCALE, 69 / 128. * DETA_SCALE, 18 / 32. * DETA_SCALE, + 19 / 32. * DETA_SCALE, 20 / 32. * DETA_SCALE, 21 / 32. * DETA_SCALE, 22 / 32. * DETA_SCALE, 23 / 32. * DETA_SCALE, 24 / 32. * DETA_SCALE, + 25 / 32. * DETA_SCALE, 26 / 32. * DETA_SCALE, 27 / 32. * DETA_SCALE, 28 / 32. * DETA_SCALE, + 29 / 32. * DETA_SCALE, 30 / 32. * DETA_SCALE, 31 / 32. * DETA_SCALE, 32 / 32. * DETA_SCALE}, + "correlation bins DeltaEta"}; + Configurable> binsZPv{"binsZPv", + {-7, -5, -3, -1, 1, 3, 5, 7}, + "zPv mixing bins"}; + Configurable> binsMult{"binsMult", + {-0.5, 9.5, 14.5, 19.5, 25.5, 32}, + "multiplicity mixing bins for mc true"}; + Configurable> binsZPvMcTrue{"binsZPvMcTrue", + {-10000, 10000}, + "zPv mixing bins"}; + Configurable> binsMultMcTrue{"binsMultMcTrue", + {-0.5, 10.5, 15.5, 20.5, 25.5, 30.5, 35.5, 40.5, 50.5, 64}, + "multiplicity mixing bins for mc true"}; + + // configurables from other tasks + + double etaMax; + + // objects to hold histograms + HistogramRegistry histos{"histogramRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + // ccdb calls + const int64_t noLaterThanCcdb = noLaterThanCcdbConfig == -1 ? std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count() : noLaterThanCcdbConfig; + Service ccdb; + // for mc + Service pdg; + + // random number generation + static constexpr unsigned int SeedRandomEngine = 12345; + std::mt19937 randomEngine{SeedRandomEngine}; + + // partitions + SliceCache cache; + + // prepare for per collision slicing + Preslice perColTracks = aod::jtrack::collisionId; + Preslice perColTriggers = aod::corr_particle::jetCollisionId; + Preslice perColHadrons = aod::corr_particle::jetCollisionId; + Preslice perColPipms = aod::corr_particle::jetCollisionId; + Preslice perColPhotonPCMs = aod::corr_particle::jetCollisionId; + Preslice perColPhotonPCMPairs = aod::corr_particle::jetCollisionId; + Preslice perColMcParticles = aod::jmcparticle::mcCollisionId; + Preslice perColTriggerParticles = aod::corr_particle::jetMcCollisionId; + + // combinations binning + // cumbersome, but still better than having extra configurable or figuring out how to init binningZPvMult later while declaring it here + std::function(std::vector const&, double)> prependValueToVector = + [](std::vector const& vec, double const value) { + std::vector resultVec = {value}; + resultVec.insert(resultVec.end(), vec.begin(), vec.end()); + return resultVec; + }; + BinningZPvMult binningZPvMult{{prependValueToVector(binsZPv.value, VARIABLE_WIDTH), prependValueToVector(binsMult.value, VARIABLE_WIDTH)}, true}; + + // declare analysis variables + + // efficiency histograms + TH1D* h1PtInvEffTrigger; + TH1D* h1PtInvEffHadron; + TH1D* h1PtInvEffPipm; + TH1D* h1PtInvEffPhotonPCM; + + // mixing trigger memory + struct MixingTrigger { + float fPt, fPhi, fEta; + float pt() const { return fPt; } + float phi() const { return fPhi; } + float eta() const { return fEta; } + }; + // class to handle trigger info from previous collisions (beyond single dataframe) + // organised as zPv- and mult-bin matrix of deque (pt, phi, eta) to save trigger info beyond single dataframe + // extra bin for mult overflow + // with adjusted zVtx (see triggerBinValuesZPv in init) and mult overflow -> all events accounted for + // (possibly replace by some advanced derived data method and O2 event mixing in future?) + class MixingTriggerMemory + { + public: + // finds bin that value belongs to (assumes ordered bins) (starts at 0; includes underflow (return -1) and overlflow (return bins.size() - 1)) + // should be faster than some std binary search due to small number of bins (zPv, mult) + static int findIntervalBin(double value, const std::vector& bins) + { + const int n = bins.size() - 1; + if (value < bins[0]) + return -1; // underflow + for (int i_bin = 0; i_bin < n; i_bin++) + if (value < bins[i_bin + 1]) + return i_bin; + return n; // overflow + } + + MixingTriggerMemory(int const nTriggerSavedForMixingIn, std::vector binsZPv, std::vector binsMult) + { + nTriggerSavedForMixing = nTriggerSavedForMixingIn; + triggerBinValuesZPv = binsZPv; + triggerBinValuesMult = binsMult; + // prevent rounding errors in bin finding (multiplicity accounted for by it going to 0 and already considering overflow separately) + triggerBinValuesZPv.front() *= zPvRoundingErrorAdjust; + triggerBinValuesZPv.back() *= zPvRoundingErrorAdjust; + // init correct size of zPv-mult matrix + savedTriggersZPvMult.resize(binsZPv.size() - 1); + for (size_t i_zPv = 0; i_zPv < binsZPv.size() - 1; i_zPv++) { + savedTriggersZPvMult[i_zPv].resize(binsMult.size()); + } + } + + // save trigger for mixing + // up to nTriggerSavedForMixing stored (LIFO) + void saveTrigger(float const pt, float const phi, float const eta, double const zPv, double const mult) + { + int const iBinCorrZPv = findIntervalBin(zPv, triggerBinValuesZPv); + int const iBinCorrMult = findIntervalBin(mult, triggerBinValuesMult); + // special cases (floating point precision errors, mult overflow) should be taken care of by triggerBinValuesZPv and triggerBinValuesMult + savedTriggersZPvMult[iBinCorrZPv][iBinCorrMult].push_front(MixingTrigger{pt, phi, eta}); + if (static_cast(savedTriggersZPvMult[iBinCorrZPv][iBinCorrMult].size()) > nTriggerSavedForMixing) { + savedTriggersZPvMult[iBinCorrZPv][iBinCorrMult].pop_back(); + } + } + + // return deques of trigger pt, phi, eta in the given zPv/mult bin + std::deque const& getTriggers(double const zPv, double const mult) const + { + int const iBinCorrZPv = findIntervalBin(zPv, triggerBinValuesZPv); + int const iBinCorrMult = findIntervalBin(mult, triggerBinValuesMult); + return savedTriggersZPvMult[iBinCorrZPv][iBinCorrMult]; + } + + private: + double const zPvRoundingErrorAdjust = 1.0001; + int nTriggerSavedForMixing; + std::vector triggerBinValuesZPv; + std::vector triggerBinValuesMult; + std::vector>> savedTriggersZPvMult; + }; + + MixingTriggerMemory mixingTriggerMemoryReco{nTriggerSavedForMixing.value, binsZPv.value, binsMult.value}; + MixingTriggerMemory mixingTriggerMemoryTrue{nTriggerSavedForMixing.value, binsZPvMcTrue.value, binsMult.value}; + MixingTriggerMemory mixingTriggerMemoryRecoColTrue{nTriggerSavedForMixing.value, binsZPvMcTrue.value, binsMult.value}; + + // functions ================================================================================================================================================================================ + + // general (kenobi) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // get histograms from ccdb + // save efficiencies from ccdb in histogram registry + void initCcdbHistograms() + { + // trigger + h1PtInvEffTrigger = nullptr; + if (doEffCorrectionTrigger) { + h1PtInvEffTrigger = ccdb->getForTimeStamp(pathCcdbEff.value + "/trigger", noLaterThanCcdb); + + const double* effBinsTrigger = h1PtInvEffTrigger->GetXaxis()->GetXbins()->GetArray(); + const AxisSpec axisPtEffTrigger{std::vector(effBinsTrigger, effBinsTrigger + h1PtInvEffTrigger->GetNbinsX() + 1), "#it{p}_{T}"}; + histos.add("usedEff/h1_pt_invEff_trigger_ccdb", "h1_pt_invEff_trigger_ccdb", kTH1D, {axisPtEffTrigger}, true); + for (int iBin = 1; iBin <= h1PtInvEffTrigger->GetNbinsX(); iBin++) { + histos.get(HIST("usedEff/h1_pt_invEff_trigger_ccdb"))->SetBinContent(iBin, h1PtInvEffTrigger->GetBinContent(iBin)); + histos.get(HIST("usedEff/h1_pt_invEff_trigger_ccdb"))->SetBinError(iBin, h1PtInvEffTrigger->GetBinError(iBin)); + } + } + // hadron + h1PtInvEffHadron = nullptr; + if (doEffCorrectionHadron) { + h1PtInvEffHadron = ccdb->getForTimeStamp(pathCcdbEff.value + "/hadron", noLaterThanCcdb); + + const double* effBinsHadron = h1PtInvEffHadron->GetXaxis()->GetXbins()->GetArray(); + const AxisSpec axisPtEffHadron{std::vector(effBinsHadron, effBinsHadron + h1PtInvEffHadron->GetNbinsX() + 1), "#it{p}_{T}"}; + histos.add("usedEff/h1_pt_invEff_hadron_ccdb", "h1_pt_invEff_hadron_ccdb", kTH1D, {axisPtEffHadron}, true); + for (int iBin = 1; iBin <= h1PtInvEffHadron->GetNbinsX(); iBin++) { + histos.get(HIST("usedEff/h1_pt_invEff_hadron_ccdb"))->SetBinContent(iBin, h1PtInvEffHadron->GetBinContent(iBin)); + histos.get(HIST("usedEff/h1_pt_invEff_hadron_ccdb"))->SetBinError(iBin, h1PtInvEffHadron->GetBinError(iBin)); + } + } + // pipm + h1PtInvEffPipm = nullptr; + if (doEffCorrectionPipm) { + h1PtInvEffPipm = ccdb->getForTimeStamp(pathCcdbEff.value + "/pipm", noLaterThanCcdb); + + const double* effBinsPipm = h1PtInvEffPipm->GetXaxis()->GetXbins()->GetArray(); + const AxisSpec axisPtEffPipm{std::vector(effBinsPipm, effBinsPipm + h1PtInvEffPipm->GetNbinsX() + 1), "#it{p}_{T}"}; + histos.add("usedEff/h1_pt_invEff_pipm_ccdb", "h1_pt_invEff_pipm_ccdb", kTH1D, {axisPtEffPipm}, true); + for (int iBin = 1; iBin <= h1PtInvEffPipm->GetNbinsX(); iBin++) { + histos.get(HIST("usedEff/h1_pt_invEff_pipm_ccdb"))->SetBinContent(iBin, h1PtInvEffPipm->GetBinContent(iBin)); + histos.get(HIST("usedEff/h1_pt_invEff_pipm_ccdb"))->SetBinError(iBin, h1PtInvEffPipm->GetBinError(iBin)); + } + } + // photonPCM + h1PtInvEffPhotonPCM = nullptr; + if (doEffCorrectionPhotonPCM) { + h1PtInvEffPhotonPCM = ccdb->getForTimeStamp(pathCcdbEff.value + "/photonPCM", noLaterThanCcdb); + + const double* effBinsPhotonPCM = h1PtInvEffPhotonPCM->GetXaxis()->GetXbins()->GetArray(); + const AxisSpec axisPtEffPhotonPCM{std::vector(effBinsPhotonPCM, effBinsPhotonPCM + h1PtInvEffPhotonPCM->GetNbinsX() + 1), "#it{p}_{T}"}; + histos.add("usedEff/h1_pt_invEff_photonPCM_ccdb", "h1_pt_invEff_photonPCM_ccdb", kTH1D, {axisPtEffPhotonPCM}, true); + for (int iBin = 1; iBin <= h1PtInvEffPhotonPCM->GetNbinsX(); iBin++) { + histos.get(HIST("usedEff/h1_pt_invEff_photonPCM_ccdb"))->SetBinContent(iBin, h1PtInvEffPhotonPCM->GetBinContent(iBin)); + histos.get(HIST("usedEff/h1_pt_invEff_photonPCM_ccdb"))->SetBinError(iBin, h1PtInvEffPhotonPCM->GetBinError(iBin)); + } + } + } + + // create histograms + void initHistograms() + { + // define axes + const AxisSpec axisN{1, 0., 1., "#it{N}_{something}"}; + const AxisSpec axisCategories{16, 0., 16., "categories"}; + + const AxisSpec axisZPv{nBinsZPv, -10, 10, "#it{z}_{pv}"}; + const AxisSpec axisZPvSmol{nBinsZPvSmol, -7, 7, "#it{z}_{pv}"}; + const AxisSpec axisMult{nBinsMult + 1, -0.5, nBinsMult + 0.5, "multiplicity"}; + const AxisSpec axisMultSmol{nBinsMultSmol + 1, -0.5, nBinsMultSmol + 0.5, "multiplicity"}; + const AxisSpec axisOccupancy{nBinsOccupancy + 1, -0.5, nBinsOccupancy + 0.5, "occupancy"}; + + const AxisSpec axisPhi{nBinsPhi, 0, constants::math::TwoPI, "#it{#varphi}"}; + const AxisSpec axisEta{nBinsEta, -etaMax, etaMax, "#it{#eta}"}; + const AxisSpec axisMgg{nBinsMgg, 0, 0.8, "#it{m}_{#gamma#gamma}"}; + + const AxisSpec axisPtTrig{binsPtTrig, "#it{p}_{T}^{trig}"}; + const AxisSpec axisPtAssoc{binsPtAssoc, "#it{p}_{T}^{assoc}"}; + const AxisSpec axisDPhi{binsDPhi, "#Delta#it{#varphi}"}; + const AxisSpec axisDEta{binsDEta, "#Delta#it{#eta}"}; + const AxisSpec axisZPvBinning{binsZPv, "#it{z}_{pv} correlation binning"}; + const AxisSpec axisMultBinning{binsMult, "multiplicity correlation binning"}; + const AxisSpec axisZPvBinningMcTrue{binsZPvMcTrue, "#it{z}_{pv} correlation binning for mc true"}; + const AxisSpec axisMultBinningMcTrue{binsMultMcTrue, "multiplicity correlation binning for mc true"}; + + // reco info + histos.add("reco/info/h1_nEvents", "h1_nEvents", kTH1D, {axisCategories}); + histos.get(HIST("reco/info/h1_nEvents"))->GetXaxis()->SetBinLabel(1, "#it{N}_{ev}^{sel}"); + histos.get(HIST("reco/info/h1_nEvents"))->GetXaxis()->SetBinLabel(2, "#it{N}_{ev}"); + histos.get(HIST("reco/info/h1_nEvents"))->GetXaxis()->SetBinLabel(3, "#it{N}_{ev}^{trig}"); + + histos.add("reco/info/h2_zPvMult", "h2_zPvMult", kTHnSparseD, {axisZPv, axisMult}, true); + histos.add("reco/info/h1_occupancy", "h1_occupancy", kTH1D, {axisOccupancy}, true); + histos.add("reco/info/h2_zPvMult_trigEv", "h2_zPvMult_trigEv", kTHnSparseD, {axisZPv, axisMult}, true); + histos.add("reco/info/h1_occupancy_trigEv", "h1_occupancy_trigEv", kTH1D, {axisOccupancy}, true); + + // reco (correlation) analysis + histos.add("reco/corr/h3_ptPhiEta_trig", "h3_ptPhiEta_trig", kTHnSparseD, {axisPtAssoc, axisPhi, axisEta}, true); + + std::function add_corrHists = + [&](std::string const name_id) { + histos.add(std::format("reco/corr/h3_ptPhiEta_assoc_{}", name_id).data(), std::format("h3_ptPhiEta_assoc_{}", name_id).data(), + kTHnSparseD, {axisPtAssoc, axisPhi, axisEta}, true); + histos.add(std::format("reco/corr/h6_corr_{}", name_id).data(), std::format("h6_corr_{}", name_id).data(), + kTHnSparseF, {axisDPhi, axisDEta, axisPtTrig, axisPtAssoc, axisZPvBinning, axisMultBinning}, true); + histos.add(std::format("reco/corr/h6_mix_{}", name_id).data(), std::format("h6_mix_{}", name_id).data(), + kTHnSparseF, {axisDPhi, axisDEta, axisPtTrig, axisPtAssoc, axisZPvBinning, axisMultBinning}, true); + }; + // hadron + histos.add("reco/plain/h3_ptPhiEta_hadron", "h3_ptPhiEta_hadron", kTHnSparseD, {axisPtAssoc, axisPhi, axisEta}, true); + add_corrHists("hadron"); + // pipm + histos.add("reco/plain/h3_ptPhiEta_pipm", "h3_ptPhiEta_pipm", kTHnSparseD, {axisPtAssoc, axisPhi, axisEta}, true); + add_corrHists("pipm"); + // photonPCM + histos.add("reco/plain/h3_ptPhiEta_photonPCM", "h3_ptPhiEta_photonPCM", kTHnSparseD, {axisPtAssoc, axisPhi, axisEta}, true); + add_corrHists("photonPCM"); + // photonPCM pairs + histos.add("reco/plain/h4_ptMggZPvMult_photonPCMPair", "h4_ptMggZPvMult_photonPCMPair", kTHnSparseD, {axisPtAssoc, axisMgg, axisZPvBinning, axisMultBinning}, true); + histos.add("reco/plain/h4_ptMggZPvMult_trigEv_photonPCMPair", "h4_ptMggZPvMult_trigEv_photonPCMPair", kTHnSparseD, {axisPtAssoc, axisMgg, axisZPvBinning, axisMultBinning}, true); + histos.add("reco/corr/h5_ptTrigPtAssocMggZPvMult_assoc_photonPCMPair", "h5_ptTrigPtAssocMggZPvMult_assoc_photonPCMPair", kTHnSparseD, {axisPtTrig, axisPtAssoc, axisMgg, axisZPvBinning, axisMultBinning}, true); + // pi0PCM + add_corrHists("pi0PCMPeak"); + add_corrHists("pi0PCMSide"); + // etaPCM + add_corrHists("etaPCMPeak"); + add_corrHists("etaPCMSide"); + + // event mixing for photon pairs + histos.add("reco/plain/h2_zPvMult_photonPCMPair_evMix", "h2_zPvMult_photonPCMPair_evMix", kTHnSparseD, {axisZPv, axisMult}, true); + histos.add("reco/plain/h4_ptMggZPvMult_photonPCMPair_evMix", "h4_ptMggZPvMult_photonPCMPair_evMix", kTHnSparseD, {axisPtAssoc, axisMgg, axisZPvBinning, axisMultBinning}, true); + histos.add("reco/plain/h4_ptMggZPvMult_trigEv_photonPCMPair_evMix", "h4_ptMggZPvMult_trigEv_photonPCMPair_evMix", kTHnSparseD, {axisPtAssoc, axisMgg, axisZPvBinning, axisMultBinning}, true); + + // mc info + histos.add("mc/info/h1_nEvents_mcTrue", "h1_nEvents_mcTrue", kTH1D, {axisN}); + histos.add("mc/info/h2_zPvMult_mcTrue", "h2_zPvMult_mcTrue", kTHnSparseD, {axisZPv, axisMult}, true); + histos.add("mc/info/h1_nTrigEv_mcTrue", "h1_nTrigEv_mcTrue", kTH1D, {axisN}); + histos.add("mc/info/h2_zPvMult_trigEv_mcTrue", "h2_zPvMult_trigEv_mcTrue", kTHnSparseD, {axisZPv, axisMult}, true); + histos.add("mc/info/h1_nRecoCol_mcTrue", "h1_nRecoCol_mcTrue", kTH1D, {axisN}); + histos.add("mc/info/h2_zPvMult_recoCol_mcTrue", "h2_zPvMult_recoCol_mcTrue", kTHnSparseD, {axisZPv, axisMult}, true); + + // reco and true collision correlations + const std::vector assocMcCorrHistNames = {"hadron", "pipm", "photon", "pi0", "eta"}; + for (auto const& collision_type : {"true", "recoCol_true"}) { + histos.add(std::format("mc/{}/corr/h3_ptPhiEta_trig", collision_type).data(), "h3_ptPhiEta_trig", kTHnSparseD, {axisPtAssoc, axisPhi, axisEta}, true); + for (auto const& assocName : assocMcCorrHistNames) { + histos.add(std::format("mc/{}/corr/h6_corr_{}", collision_type, assocName).data(), std::format("h6_corr_{}", assocName).data(), + kTHnSparseD, {axisDPhi, axisDEta, axisPtTrig, axisPtAssoc, axisZPvBinningMcTrue, axisMultBinningMcTrue}, true); + histos.add(std::format("mc/{}/corr/h6_mix_{}", collision_type, assocName).data(), std::format("h6_mix_{}", assocName).data(), + kTHnSparseD, {axisDPhi, axisDEta, axisPtTrig, axisPtAssoc, axisZPvBinningMcTrue, axisMultBinningMcTrue}, true); + } + } + + // mc efficiency/purity + std::function add_effHists = + [&](std::string const name_id) { + histos.add(std::format("mc/eff/h3_ptPhiEta_{}", name_id).data(), std::format("h3_ptPhiEta_{}", name_id).data(), + kTHnSparseD, {axisPtAssoc, axisPhi, axisEta}, true); + histos.add(std::format("mc/eff/h3_ptZPvMult_{}", name_id).data(), std::format("h3_ptZPvMult_{}", name_id).data(), + kTHnSparseD, {axisPtAssoc, axisZPvSmol, axisMultSmol}, true); + }; + // mc tracks + add_effHists("mcReco_hadron"); + add_effHists("mcReco_hasCorrectMc_hadron"); + add_effHists("mcTrue_recoCol_hadron"); + // mc pipm PID + add_effHists("mcReco_pipm"); + add_effHists("mcReco_hasCorrectMc_pipm"); + add_effHists("mcTrue_recoCol_pipm"); + // mc photonPCM + add_effHists("mcReco_photonPCM"); + add_effHists("mcReco_hasCorrectMc_photonPCM"); + add_effHists("mcTrue_recoCol_photon"); + // mc pi0 + add_effHists("mcTrue_recoCol_pi0"); + // mc eta + add_effHists("mcTrue_recoCol_eta"); + + // test of the test while testing another test. featuring a test + histos.add("test/h2_mult_comp", "h2_mult_comp", kTH2D, {axisMult, axisMult}, true); + histos.add("test/h2_tracks_zPvMultDep", "h2_tracks_zPvMultDep", kTH2D, {axisZPv, axisMult}, true); + histos.add("test/h2_globalTracks_zPvMultDep", "h2_globalTracks_zPvMultDep", kTH2D, {axisZPv, axisMult}, true); + } + + // selections /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // checks if mcParticle is charged + template + bool checkChargedMc(T_mcParticle const& mcParticle) + { + auto const pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0) + return false; + return true; + } + // checks if mcParticle should be detected (physicalPrimary, |eta|) + template + bool checkPrimaryEtaMc(T_mcParticle const& mcParticle) + { + if (!mcParticle.isPhysicalPrimary()) + return false; + if (std::abs(mcParticle.eta()) > etaMax) + return false; + return true; + } + // checks if mcParticle should be detected as primary track (physicalPrimary, charge, |eta|) + template + bool checkPrimaryTrackMc(T_mcParticle const& mcParticle) + { + if (!checkPrimaryEtaMc(mcParticle)) + return false; + if (!checkChargedMc(mcParticle)) + return false; + return true; + } + // checks if mcParticle should be detected as 'primary' (|eta| not checked) + template + bool checkH0Primary(T_mcParticle const& mcParticle, int const pdg) + { + if (mcParticle.pdgCode() != pdg) + return false; + const auto& h0Daughters = mcParticle.template daughters_as(); + // identify primary h0 (account for 0 daughters for some reason) + if (h0Daughters.size() == 0) + return false; + for (auto const& h0_daughter : h0Daughters) { + if (!h0_daughter.isPhysicalPrimary()) + return false; + } + return true; + } + // checks if mcParticle should be detected as 'primary' pi0->gammagamma (|eta| not checked) + template + bool checkH0ToGG(T_mcParticle const& mcParticle, int const pdg) + { + if (!checkH0Primary(mcParticle, pdg)) + return false; + // select h0 -> gg + constexpr int NDaughtersH0ToGG = 2; + if (mcParticle.template daughters_as().size() != NDaughtersH0ToGG) + return false; + return true; + } + + // checks if tracks come from photon conversion + template + bool isConversionPhoton(T_track const& posTrack, T_track const& negTrack) + { + // check same mother + auto const& posMothers = posTrack.mcParticle().template mothers_as(); + auto const& negMothers = negTrack.mcParticle().template mothers_as(); + if (posMothers.size() != 1 || negMothers.size() != 1) + return false; + if (posMothers.begin()->globalIndex() != negMothers.begin()->globalIndex()) + return false; + // check photon + if (posMothers.begin()->pdgCode() != PDG_t::kGamma) + return false; + + return true; + }; + // checks if tracks come from pi0 double conversion + template + bool isGGFromPi0(T_track const& posTrack1, T_track const& negTrack1, T_track const& posTrack2, T_track const& negTrack2) + { + if (!isConversionPhoton(posTrack1, negTrack1) || !isConversionPhoton(posTrack2, negTrack2)) + return false; + // check same mother + auto const& mothers1 = (*(posTrack1.mcParticle().template mothers_as().begin())).template mothers_as(); + auto const& mothers2 = (*(posTrack2.mcParticle().template mothers_as().begin())).template mothers_as(); + constexpr int NMothersPhotonFromPi0 = 2; // for some reason two mothers (same particle) for pi0 decays (contradicts PYTHIA documentation, but whatever) + if (mothers1.size() != NMothersPhotonFromPi0 || mothers2.size() != NMothersPhotonFromPi0) + return false; + if (mothers1.begin()->globalIndex() != mothers2.begin()->globalIndex()) + return false; + // check pi0 + if (mothers1.begin()->pdgCode() != PDG_t::kPi0) + return false; + + return true; + }; + + // analysis helpers ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + template + double getH1ValueAt(T_h1 const* const h1, double const value) + { + return h1->GetBinContent(h1->FindFixBin(value)); + } + // efficiency helpers + enum class EffParticleType { Trigger, + Hadron, + Pipm, + PhotonPCM }; + // efficiency function + template + double getInvEff(double const value) + { + if constexpr (T_effParticleType == EffParticleType::Trigger) { + return doEffCorrectionTrigger ? getH1ValueAt(h1PtInvEffTrigger, value) : 1; + } else if constexpr (T_effParticleType == EffParticleType::Hadron) { + return doEffCorrectionHadron ? getH1ValueAt(h1PtInvEffHadron, value) : 1; + } else if constexpr (T_effParticleType == EffParticleType::Pipm) { + return doEffCorrectionPipm ? getH1ValueAt(h1PtInvEffPipm, value) : 1; + } else if constexpr (T_effParticleType == EffParticleType::PhotonPCM) { + return doEffCorrectionPhotonPCM ? getH1ValueAt(h1PtInvEffPhotonPCM, value) : 1; + } else { + return 1; + } + } + + // performs 'phi1 - phi2' and pushes it into the interval [-pi/2, 3pi/2] + inline double getDeltaPhi(double const phi1, double const phi2) + { + return RecoDecay::constrainAngle(phi1 - phi2, -1 * constants::math::PIHalf); + } + + // finds bin that value belongs to (assumes ordered bins) (starts at 0; includes underflow (return -1) and overlflow (return bins.size() - 1)) + // should be faster than some std binary search due to small number of bins (zPv, mult) + int findIntervalBin(double value, const std::vector& bins) + { + const int n = bins.size() - 1; + if (value < bins[0]) + return -1; // underflow + for (int i_bin = 0; i_bin < n; i_bin++) + if (value < bins[i_bin + 1]) + return i_bin; + return n; // overflow + } + + // checks that two values belong to the same category (assumes ordered bins) + // returns -1 for negative result (also for under/overflow values) and bin number (starting at 0) otherwise + int checkSameBin(double const value1, double const value2, std::vector const& bins) + { + // reject underflow + if (value1 < bins[0]) + return -1; + // loop over bins + const int n = bins.size() - 1; + for (int i_bin = 0; i_bin < n; i_bin++) { + if (value1 < bins[i_bin + 1]) { + if (value2 < bins[i_bin + 1] && value2 >= bins[i_bin]) { + return i_bin; + } + return -1; + } + } + // reject overflow + return -1; + } + + // check if invariant mass range + enum class MassRange { pi0PCMPeak, + pi0PCMSide, + etaPCMPeak, + etaPCMSide }; + + template + bool checkMassRange(double const mgg) + { + if constexpr (T_massRange == MassRange::pi0PCMPeak) { + return mgg > pi0PCMPeakMassRange.value[0] && mgg < pi0PCMPeakMassRange.value[1]; + } else if constexpr (T_massRange == MassRange::pi0PCMSide) { + return mgg > pi0PCMSideMassRange.value[0] && mgg < pi0PCMSideMassRange.value[1]; + } else if constexpr (T_massRange == MassRange::etaPCMPeak) { + return mgg > etaPCMPeakMassRange.value[0] && mgg < etaPCMPeakMassRange.value[1]; + } else if constexpr (T_massRange == MassRange::etaPCMSide) { + return (mgg > etaPCMLowSideMassRange.value[0] && mgg < etaPCMLowSideMassRange.value[1]) || + (mgg > etaPCMHighSideMassRange.value[0] && mgg < etaPCMHighSideMassRange.value[1]); + } + return false; + } + + // analysis ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // generalised correlation functions + // per collision + + // plain info + template + void corrProcessPlain(T_collision const& collision, T_associatedThisEvent const& associatedThisEvent, + T_funcPlain&& funcPlain) + { + // normal spectra (per event - not per trigger) + for (auto const& associated : associatedThisEvent) { + funcPlain(collision, associated); + } + } + + // correlation + template + void corrProcessCorrelation(T_collision const& collision, T_triggersThisEvent const& triggersThisEvent, T_associatedThisEvent const& associatedThisEvent, + T_funcCorrelation&& funcCorrelation) + { + // correlation combinations + for (auto const& [trigger, associated] : soa::combinations(soa::CombinationsFullIndexPolicy(triggersThisEvent, associatedThisEvent))) { + funcCorrelation(collision, trigger, associated); + } + } + + // mixing + template + void corrProcessMixing(T_collision const& collision, T_associatedThisEvent const& associatedThisEvent, + T_funcMixing&& funcMixing, + size_t const nTriggerMixing, size_t const nTriggersThisDataFrame) + { + // skip if event does not contain valid trigger + if (doTrigEvMixing && !collision.trigEv()) + return; + + // mixing loops (more efficient than O2 mixing (for now)) + auto savedTriggers = mixingTriggerMemoryReco.getTriggers(collision.posZ(), collision.nGlobalTracks()); + // number of triggers + const size_t mixUpToTriggerN = std::min(savedTriggers.size(), nTriggerMixing + nTriggersThisDataFrame); + const float perTriggerWeight = 1. / (mixUpToTriggerN - nTriggersThisDataFrame); // mixUpToTriggerN <= nTriggersThisDataFrame not problematic since no loop then + // mixing loops + for (size_t i_mixingTrigger = nTriggersThisDataFrame; i_mixingTrigger < mixUpToTriggerN; i_mixingTrigger++) { + for (auto const& associated : associatedThisEvent) { + funcMixing(collision, savedTriggers[i_mixingTrigger].pt(), savedTriggers[i_mixingTrigger].phi(), savedTriggers[i_mixingTrigger].eta(), associated, perTriggerWeight); + } + } + } + + void init(InitContext& initContext) + { + // analysis info + ccdb->setURL(urlCcdb.value); + // enabling object caching (otherwise each call goes to CCDB server) + ccdb->setCaching(true); + // ccdb->setLocalObjectValidityChecking(); + // not later than (avoids replacing objects while a train is running) + ccdb->setCreatedNotAfter(noLaterThanCcdb); + + // init analysis variables + + // get variables from other tasks + getTaskOptionValue(initContext, "photon-charged-trigger-producer", "etaMax", etaMax, false); + + // histograms from ccdb + initCcdbHistograms(); + + // create analysis histograms + initHistograms(); + } + + // reconstructed //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void processInfo(CorrCollision const& collision) + { + // all events + histos.fill(HIST("reco/info/h1_nEvents"), 1.5); + + // event selection + if (!collision.selEv()) + return; + histos.fill(HIST("reco/info/h1_nEvents"), 0.5); + + histos.fill(HIST("reco/info/h2_zPvMult"), collision.posZ(), collision.nGlobalTracks()); + histos.fill(HIST("reco/info/h1_occupancy"), collision.trackOccupancyInTimeRange()); + + // trigger events + if (!collision.trigEv()) + return; + histos.fill(HIST("reco/info/h1_nEvents"), 2.5); + + histos.fill(HIST("reco/info/h2_zPvMult_trigEv"), collision.posZ(), collision.nGlobalTracks()); + histos.fill(HIST("reco/info/h1_occupancy_trigEv"), collision.trackOccupancyInTimeRange()); + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processInfo, "process general info on collisions and tracks for analysis and qa", false); + + void processCorrFirst(CorrCollisions const& collisions, aod::Triggers const& triggers) + { + // do at beginning of each data frame (before other reco correlation process functions) + // (PROCESS_SWITCH of this process has to be declared first) + + // [wow, such empty] + + for (auto const& collision : collisions) { + // event selection + if (!collision.selEv()) + continue; + + // group collision + auto const triggersThisEvent = triggers.sliceBy(perColTriggers, collision.globalIndex()); + + // trigger loop + for (auto const& trigger : triggersThisEvent) { + // trigger info + histos.fill(HIST("reco/corr/h3_ptPhiEta_trig"), trigger.pt(), trigger.phi(), trigger.eta(), + getInvEff(trigger.pt())); + + // save trigger for mixing + mixingTriggerMemoryReco.saveTrigger(trigger.pt(), trigger.phi(), trigger.eta(), collision.posZ(), collision.nGlobalTracks()); + } + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processCorrFirst, "process to gather info before correlation processes", false); + + void processCorrHadron(CorrCollisions const& collisions, aod::Triggers const& triggers, aod::Hadrons const& hadrons) + { + size_t const nTriggersThisDataFrame = triggers.size(); + + for (auto const& collision : collisions) { + // event selection + if (!collision.selEv()) + continue; + + // group collision + auto const triggersThisEvent = triggers.sliceBy(perColTriggers, collision.globalIndex()); + auto const hadronsThisEvent = hadrons.sliceBy(perColHadrons, collision.globalIndex()); + + auto const funcPlain = [this]([[maybe_unused]] auto const& collision, auto const& associated) { + histos.fill(HIST("reco/plain/h3_ptPhiEta_hadron"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(associated.pt())); + }; + corrProcessPlain(collision, hadronsThisEvent, funcPlain); + + auto const funcCorrelation = [this](auto const& collision, auto const& trigger, auto const& associated) { + // exclude self correlation + if (trigger.jetTrackId() == associated.jetTrackId()) + return; + + histos.fill(HIST("reco/corr/h3_ptPhiEta_assoc_hadron"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(trigger.pt()) * getInvEff(associated.pt())); + histos.fill(HIST("reco/corr/h6_corr_hadron"), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), collision.posZ(), collision.nGlobalTracks(), + getInvEff(trigger.pt()) * getInvEff(associated.pt())); + }; + corrProcessCorrelation(collision, triggersThisEvent, hadronsThisEvent, funcCorrelation); + + auto const funcMixing = [this](auto const& collision, + float const mixingTriggerPt, float const mixingTriggerPhi, float const mixingTriggerEta, auto const& associated, auto const perTriggerWeight) { + histos.fill(HIST("reco/corr/h6_mix_hadron"), + getDeltaPhi(mixingTriggerPhi, associated.phi()), + mixingTriggerEta - associated.eta(), + mixingTriggerPt, associated.pt(), collision.posZ(), collision.nGlobalTracks(), + perTriggerWeight * getInvEff(mixingTriggerPt) * getInvEff(associated.pt())); + }; + corrProcessMixing(collision, hadronsThisEvent, funcMixing, nTriggerMixingHadron, nTriggersThisDataFrame); + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processCorrHadron, "process standard correlation for associated hardons", false); + + void processCorrPipm(CorrCollisions const& collisions, aod::Triggers const& triggers, aod::Pipms const& pipms) + { + size_t const nTriggersThisDataFrame = triggers.size(); + + for (auto const& collision : collisions) { + // event selection + if (!collision.selEv()) + continue; + + // group collision + auto const triggersThisEvent = triggers.sliceBy(perColTriggers, collision.globalIndex()); + auto const pipmsThisEvent = pipms.sliceBy(perColPipms, collision.globalIndex()); + + auto const funcPlain = [this]([[maybe_unused]] auto const& collision, auto const& associated) { + histos.fill(HIST("reco/plain/h3_ptPhiEta_pipm"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(associated.pt())); + }; + corrProcessPlain(collision, pipmsThisEvent, funcPlain); + + auto const funcCorrelation = [this](auto const& collision, auto const& trigger, auto const& associated) { + // exclude self correlation + if (trigger.jetTrackId() == associated.jetTrackId()) + return; + + histos.fill(HIST("reco/corr/h3_ptPhiEta_assoc_pipm"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(trigger.pt()) * getInvEff(associated.pt())); + histos.fill(HIST("reco/corr/h6_corr_pipm"), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), collision.posZ(), collision.nGlobalTracks(), + getInvEff(trigger.pt()) * getInvEff(associated.pt())); + }; + corrProcessCorrelation(collision, triggersThisEvent, pipmsThisEvent, funcCorrelation); + + auto const funcMixing = [this](auto const& collision, + float const mixingTriggerPt, float const mixingTriggerPhi, float const mixingTriggerEta, auto const& associated, auto const perTriggerWeight) { + histos.fill(HIST("reco/corr/h6_mix_pipm"), + getDeltaPhi(mixingTriggerPhi, associated.phi()), + mixingTriggerEta - associated.eta(), + mixingTriggerPt, associated.pt(), collision.posZ(), collision.nGlobalTracks(), + perTriggerWeight * getInvEff(mixingTriggerPt) * getInvEff(associated.pt())); + }; + corrProcessMixing(collision, pipmsThisEvent, funcMixing, nTriggerMixingPipm, nTriggersThisDataFrame); + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processCorrPipm, "process standard correlation for associated pipm", false); + + void processCorrPhotonPCM(CorrCollisions const& collisions, aod::Triggers const& triggers, aod::PhotonPCMs const& photonPCMs) + { + size_t const nTriggersThisDataFrame = triggers.size(); + + for (auto const& collision : collisions) { + // event selection + if (!collision.selEv()) + continue; + + // group collision + auto const triggersThisEvent = triggers.sliceBy(perColTriggers, collision.globalIndex()); + auto const photonPCMsThisEvent = photonPCMs.sliceBy(perColPhotonPCMs, collision.globalIndex()); + + auto const funcPlain = [this]([[maybe_unused]] auto const& collision, auto const& associated) { + histos.fill(HIST("reco/plain/h3_ptPhiEta_photonPCM"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(associated.pt())); + }; + corrProcessPlain(collision, photonPCMsThisEvent, funcPlain); + + auto const funcCorrelation = [this](auto const& collision, auto const& trigger, auto const& associated) { + // exclude self correlation + if (trigger.jetTrackId() == associated.posTrackId() || trigger.jetTrackId() == associated.negTrackId()) + return; + + histos.fill(HIST("reco/corr/h3_ptPhiEta_assoc_photonPCM"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(trigger.pt()) * getInvEff(associated.pt())); + histos.fill(HIST("reco/corr/h6_corr_photonPCM"), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), collision.posZ(), collision.nGlobalTracks(), + getInvEff(trigger.pt()) * getInvEff(associated.pt())); + }; + corrProcessCorrelation(collision, triggersThisEvent, photonPCMsThisEvent, funcCorrelation); + + auto const funcMixing = [this](auto const& collision, + float const mixingTriggerPt, float const mixingTriggerPhi, float const mixingTriggerEta, auto const& associated, auto const perTriggerWeight) { + histos.fill(HIST("reco/corr/h6_mix_photonPCM"), + getDeltaPhi(mixingTriggerPhi, associated.phi()), + mixingTriggerEta - associated.eta(), + mixingTriggerPt, associated.pt(), collision.posZ(), collision.nGlobalTracks(), + perTriggerWeight * getInvEff(mixingTriggerPt) * getInvEff(associated.pt())); + }; + corrProcessMixing(collision, photonPCMsThisEvent, funcMixing, nTriggerMixingPhotonPCM, nTriggersThisDataFrame); + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processCorrPhotonPCM, "process standard correlation for associated photonPCM", false); + + void processCorrPhotonPCMPair(CorrCollisions const& collisions, aod::Triggers const& triggers, aod::PhotonPCMPairs const& photonPCMPairs) + { + size_t const nTriggersThisDataFrame = triggers.size(); + + for (auto const& collision : collisions) { + // event selection + if (!collision.selEv()) + continue; + + // group collision + auto const triggersThisEvent = triggers.sliceBy(perColTriggers, collision.globalIndex()); + auto const photonPCMPairsThisEvent = photonPCMPairs.sliceBy(perColPhotonPCMPairs, collision.globalIndex()); + + auto const funcPlain = [this](auto const& collision, auto const& associated) { + histos.fill(HIST("reco/plain/h4_ptMggZPvMult_photonPCMPair"), associated.pt(), associated.mgg(), collision.posZ(), collision.nGlobalTracks()); + }; + corrProcessPlain(collision, photonPCMPairsThisEvent, funcPlain); + + auto const funcPlainTrigEv = [this](auto const& collision, auto const& associated) { + histos.fill(HIST("reco/plain/h4_ptMggZPvMult_trigEv_photonPCMPair"), associated.pt(), associated.mgg(), collision.posZ(), collision.nGlobalTracks()); + }; + if (collision.trigEv()) + corrProcessPlain(collision, photonPCMPairsThisEvent, funcPlainTrigEv); + + auto const funcCorrelation = [this](auto const& collision, auto const& trigger, auto const& associated) { + // exclude self correlation + if (trigger.jetTrackId() == associated.posTrack1Id() || trigger.jetTrackId() == associated.negTrack1Id() || + trigger.jetTrackId() == associated.negTrack2Id() || trigger.jetTrackId() == associated.posTrack2Id()) + return; + + histos.fill(HIST("reco/corr/h5_ptTrigPtAssocMggZPvMult_assoc_photonPCMPair"), + trigger.pt(), associated.pt(), associated.mgg(), collision.posZ(), collision.nGlobalTracks(), + getInvEff(trigger.pt())); + + // pi0 + if (checkMassRange(associated.mgg())) { + histos.fill(HIST("reco/corr/h3_ptPhiEta_assoc_pi0PCMPeak"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(trigger.pt())); + histos.fill(HIST("reco/corr/h6_corr_pi0PCMPeak"), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), collision.posZ(), collision.nGlobalTracks(), + getInvEff(trigger.pt())); + return; + } + if (checkMassRange(associated.mgg())) { + histos.fill(HIST("reco/corr/h3_ptPhiEta_assoc_pi0PCMSide"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(trigger.pt())); + histos.fill(HIST("reco/corr/h6_corr_pi0PCMSide"), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), collision.posZ(), collision.nGlobalTracks(), + getInvEff(trigger.pt())); + return; + } + // eta + if (checkMassRange(associated.mgg())) { + histos.fill(HIST("reco/corr/h3_ptPhiEta_assoc_etaPCMPeak"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(trigger.pt())); + histos.fill(HIST("reco/corr/h6_corr_etaPCMPeak"), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), collision.posZ(), collision.nGlobalTracks(), + getInvEff(trigger.pt())); + return; + } + if (checkMassRange(associated.mgg())) { + histos.fill(HIST("reco/corr/h3_ptPhiEta_assoc_etaPCMSide"), + associated.pt(), associated.phi(), associated.eta(), + getInvEff(trigger.pt())); + histos.fill(HIST("reco/corr/h6_corr_etaPCMSide"), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), collision.posZ(), collision.nGlobalTracks(), + getInvEff(trigger.pt())); + return; + } + }; + corrProcessCorrelation(collision, triggersThisEvent, photonPCMPairsThisEvent, funcCorrelation); + + auto const funcMixing = [this](auto const& collision, + float const mixingTriggerPt, float const mixingTriggerPhi, float const mixingTriggerEta, auto const& associated, auto const perTriggerWeight) { + // pi0 + if (checkMassRange(associated.mgg())) { + histos.fill(HIST("reco/corr/h6_mix_pi0PCMPeak"), + getDeltaPhi(mixingTriggerPhi, associated.phi()), + mixingTriggerEta - associated.eta(), + mixingTriggerPt, associated.pt(), collision.posZ(), collision.nGlobalTracks(), + perTriggerWeight * getInvEff(mixingTriggerPt)); + return; + } + if (checkMassRange(associated.mgg())) { + histos.fill(HIST("reco/corr/h6_mix_pi0PCMSide"), + getDeltaPhi(mixingTriggerPhi, associated.phi()), + mixingTriggerEta - associated.eta(), + mixingTriggerPt, associated.pt(), collision.posZ(), collision.nGlobalTracks(), + perTriggerWeight * getInvEff(mixingTriggerPt)); + return; + } + // eta + if (checkMassRange(associated.mgg())) { + histos.fill(HIST("reco/corr/h6_mix_etaPCMPeak"), + getDeltaPhi(mixingTriggerPhi, associated.phi()), + mixingTriggerEta - associated.eta(), + mixingTriggerPt, associated.pt(), collision.posZ(), collision.nGlobalTracks(), + perTriggerWeight * getInvEff(mixingTriggerPt)); + return; + } + if (checkMassRange(associated.mgg())) { + histos.fill(HIST("reco/corr/h6_mix_etaPCMSide"), + getDeltaPhi(mixingTriggerPhi, associated.phi()), + mixingTriggerEta - associated.eta(), + mixingTriggerPt, associated.pt(), collision.posZ(), collision.nGlobalTracks(), + perTriggerWeight * getInvEff(mixingTriggerPt)); + return; + } + }; + corrProcessMixing(collision, photonPCMPairsThisEvent, funcMixing, nTriggerMixingH0PCM, nTriggersThisDataFrame); + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processCorrPhotonPCMPair, "process standard correlation for associated pi0PCM", false); + + void processCorrPhotonPCMPairMix(CorrCollisions const& collisions, aod::PhotonPCMs const& photonPCMs) + { + auto photonPCMsTuple = std::make_tuple(photonPCMs); + SameKindPair pairs{binningZPvMult, nNeighboursMixingPhotonPCMPair, -1, collisions, photonPCMsTuple, &cache}; + + // mixed events + for (auto pair = pairs.begin(); pair != pairs.end(); pair++) { + auto const& [collision1, photonPCMs1, collision2, photonPCMs2] = *pair; + + // // check that current und mixing-trigger event are from the same zPv/mult bins + // if (checkSameBin(collision1.posZ(), collision2.posZ(), binsZPv) == -1) { + // std::printf("ERROR: zPv bins do not match\n"); continue; + // } + // if (checkSameBin(collision1.nGlobalTracks(), collision2.nGlobalTracks(), binsMult) == -1) { + // std::printf("ERROR: multiplicity bins do not match\n"); continue; + // } + + // event selection + if (!collision1.selEv() || !collision2.selEv()) + continue; + // event info + histos.fill(HIST("reco/plain/h2_zPvMult_photonPCMPair_evMix"), collision1.posZ(), collision1.nGlobalTracks()); + // mixing loop + for (auto const& [photonPCM1, photonPCM2] : soa::combinations(soa::CombinationsFullIndexPolicy(photonPCMs1, photonPCMs2))) { + ROOT::Math::PtEtaPhiMVector const p4photonPCM1(photonPCM1.pt(), photonPCM1.eta(), photonPCM1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector const p4photonPCM2(photonPCM2.pt(), photonPCM2.eta(), photonPCM2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector const p4photonPCMPair = p4photonPCM1 + p4photonPCM2; + + histos.fill(HIST("reco/plain/h4_ptMggZPvMult_photonPCMPair_evMix"), p4photonPCMPair.pt(), p4photonPCMPair.M(), collision1.posZ(), collision1.nGlobalTracks()); + } + + // trigger events + if (!collision1.trigEv() || !collision2.trigEv()) + continue; + // mixing loop + for (auto const& [photonPCM1, photonPCM2] : soa::combinations(soa::CombinationsFullIndexPolicy(photonPCMs1, photonPCMs2))) { + ROOT::Math::PtEtaPhiMVector const p4photonPCM1(photonPCM1.pt(), photonPCM1.eta(), photonPCM1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector const p4photonPCM2(photonPCM2.pt(), photonPCM2.eta(), photonPCM2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector const p4photonPCMPair = p4photonPCM1 + p4photonPCM2; + + histos.fill(HIST("reco/plain/h4_ptMggZPvMult_trigEv_photonPCMPair_evMix"), p4photonPCMPair.pt(), p4photonPCMPair.M(), collision1.posZ(), collision1.nGlobalTracks()); + } + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processCorrPhotonPCMPairMix, "process gamma-gamma mixing for photonPCM", false); + + // mc /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void processMcInfo(CorrMcCollisions const& mcCollisions, CorrMcDCollisions const& collisions) + { + for (auto const& mcCollision : mcCollisions) { + // all events + histos.fill(HIST("mc/info/h1_nEvents_mcTrue"), 0.5); + histos.fill(HIST("mc/info/h2_zPvMult_mcTrue"), mcCollision.posZ(), mcCollision.nChargedInEtaRange()); + + // trigger events + if (!mcCollision.trigEv()) + continue; + histos.fill(HIST("mc/info/h1_nTrigEv_mcTrue"), 0.5); + histos.fill(HIST("mc/info/h2_zPvMult_trigEv_mcTrue"), mcCollision.posZ(), mcCollision.nChargedInEtaRange()); + } + for (auto const& collision : collisions) { + // event selection + if (!collision.selEv()) + continue; + histos.fill(HIST("mc/info/h1_nRecoCol_mcTrue"), 0.5); + histos.fill(HIST("mc/info/h2_zPvMult_recoCol_mcTrue"), collision.mcCollision_as().posZ(), collision.mcCollision_as().nChargedInEtaRange()); + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processMcInfo, "process general info on mc collisions and tracks for analysis and qa", false); + + // (sad) attempt at reducing code duplication + enum class McCorrEventType : int { True = 0, + RecoColTrue = 1 }; + enum class McCorrCorrelationType : int { Correlation = 0, + Mixing = 1 }; + enum class McCorrAssociatedType : int { Hadron = 0, + Pipm = 1, + Photon = 2, + Pi0 = 3, + Eta = 4 }; + static constexpr const char* McHistPaths[2][2][5] = { + {{"mc/true/corr/h6_corr_hadron", "mc/true/corr/h6_corr_pipm", "mc/true/corr/h6_corr_photon", + "mc/true/corr/h6_corr_pi0", "mc/true/corr/h6_corr_eta"}, + {"mc/true/corr/h6_mix_hadron", "mc/true/corr/h6_mix_pipm", "mc/true/corr/h6_mix_photon", + "mc/true/corr/h6_mix_pi0", "mc/true/corr/h6_mix_eta"}}, + {{"mc/recoCol_true/corr/h6_corr_hadron", "mc/recoCol_true/corr/h6_corr_pipm", "mc/recoCol_true/corr/h6_corr_photon", + "mc/recoCol_true/corr/h6_corr_pi0", "mc/recoCol_true/corr/h6_corr_eta"}, + {"mc/recoCol_true/corr/h6_mix_hadron", "mc/recoCol_true/corr/h6_mix_pipm", "mc/recoCol_true/corr/h6_mix_photon", + "mc/recoCol_true/corr/h6_mix_pi0", "mc/recoCol_true/corr/h6_mix_eta"}}}; + static constexpr const char* getMcHistPath(McCorrEventType eventType, McCorrCorrelationType correlationType, McCorrAssociatedType associatedType) + { + return McHistPaths[static_cast(eventType)][static_cast(correlationType)][static_cast(associatedType)]; + } + + // fill mc correaltion histograms based on given associated mc particle + template + void fillMcCorrHists(auto const& mcCollision, auto const& trigger, auto const& associated, double const weight) + { + // standard particles (marked physical primary) + if (checkPrimaryEtaMc(associated)) { + // charged primary ('hadron') selection + if (checkChargedMc(associated)) { + histos.fill(HIST(getMcHistPath(eventType, correlationType, McCorrAssociatedType::Hadron)), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), mcCollision.posZ(), mcCollision.nChargedInEtaRange(), + weight); + } + // pipm selection + if (std::abs(associated.pdgCode()) == PDG_t::kPiPlus) { + histos.fill(HIST(getMcHistPath(eventType, correlationType, McCorrAssociatedType::Pipm)), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), mcCollision.posZ(), mcCollision.nChargedInEtaRange(), + weight); + return; + } + // photon selection + if (associated.pdgCode() == PDG_t::kGamma) { + histos.fill(HIST(getMcHistPath(eventType, correlationType, McCorrAssociatedType::Photon)), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), mcCollision.posZ(), mcCollision.nChargedInEtaRange(), + weight); + return; + } + return; + } + // decaying particles (not marked physical primary) + if ((std::abs(associated.eta()) < etaMax)) { + // pi0 selection + if (checkH0Primary(associated, PDG_t::kPi0)) { + histos.fill(HIST(getMcHistPath(eventType, correlationType, McCorrAssociatedType::Pi0)), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), mcCollision.posZ(), mcCollision.nChargedInEtaRange(), + weight); + return; + } + // eta selection + if (checkH0Primary(associated, 221)) { + histos.fill(HIST(getMcHistPath(eventType, correlationType, McCorrAssociatedType::Eta)), + getDeltaPhi(trigger.phi(), associated.phi()), + trigger.eta() - associated.eta(), + trigger.pt(), associated.pt(), mcCollision.posZ(), mcCollision.nChargedInEtaRange(), + weight); + return; + } + } + } + + void processMcTrueCorr(CorrMcCollisions const& mcCollisions, aod::TriggerParticles const& triggerParticles, aod::JetParticles const& mcParticles) + { + for (auto const& mcCollision : mcCollisions) { + // group collision + auto const triggerParticlesThisEvent = triggerParticles.sliceBy(perColTriggerParticles, mcCollision.globalIndex()); + auto const mcParticlesThisEvent = mcParticles.sliceBy(perColMcParticles, mcCollision.globalIndex()); + + // trigger pairing loop + for (auto const& trigger : triggerParticlesThisEvent) { + // trigger info + histos.fill(HIST("mc/true/corr/h3_ptPhiEta_trig"), trigger.pt(), trigger.phi(), trigger.eta()); + + // save trigger for mixing + mixingTriggerMemoryTrue.saveTrigger(trigger.pt(), trigger.phi(), trigger.eta(), mcCollision.posZ(), mcCollision.nChargedInEtaRange()); + + for (auto const& associated : mcParticlesThisEvent) { + // exclude self correlation + if (trigger.jetMcParticleId() == associated.globalIndex()) + continue; + + fillMcCorrHists(mcCollision, trigger, associated, 1); + } + } + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processMcTrueCorr, "process mc-true (all collisions) correlation for multiple associated particles", false); + + void processMcTrueMix(CorrMcCollisions const& mcCollisions, aod::TriggerParticles const& triggerParticles, aod::JetParticles const& mcParticles) + { + for (auto const& mcCollision : mcCollisions) { + // group collision + auto const triggerParticlesThisEvent = triggerParticles.sliceBy(perColTriggerParticles, mcCollision.globalIndex()); + auto const mcParticlesThisEvent = mcParticles.sliceBy(perColMcParticles, mcCollision.globalIndex()); + + const size_t nTriggerParticlesThisDataFrame = triggerParticles.size(); + auto savedTriggers = mixingTriggerMemoryTrue.getTriggers(mcCollision.posZ(), mcCollision.nChargedInEtaRange()); + const size_t mixUpToTriggerN = std::min(savedTriggers.size(), static_cast(nTriggerMixingMcTrue) + nTriggerParticlesThisDataFrame); + const float perTriggerWeight = 1. / (mixUpToTriggerN - nTriggerParticlesThisDataFrame); + + // trigger loop + for (size_t i_mixingTrigger = nTriggerParticlesThisDataFrame; i_mixingTrigger < mixUpToTriggerN; i_mixingTrigger++) { + MixingTrigger const& mixingTrigger = savedTriggers[i_mixingTrigger]; + for (auto const& associated : mcParticlesThisEvent) { + fillMcCorrHists(mcCollision, mixingTrigger, associated, perTriggerWeight); + } + } + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processMcTrueMix, "process mc-true (all collisions) correlation mixing for multiple associated particles", false); + + void processMcRecoColTrueCorr(CorrMcDCollisions const& collisions, CorrMcCollisions const&, aod::TriggerParticles const& triggerParticles, aod::JetParticles const& mcParticles) + { + for (auto const& collision : collisions) { + // event selection + if (!collision.selEv()) + continue; + + // group collision + auto const triggerParticlesThisEvent = triggerParticles.sliceBy(perColTriggerParticles, collision.mcCollisionId()); + auto const mcParticlesThisEvent = mcParticles.sliceBy(perColMcParticles, collision.mcCollisionId()); + + auto const& mcCollision = collision.mcCollision_as(); + + // trigger pairing loop + for (auto const& trigger : triggerParticlesThisEvent) { + // trigger info + histos.fill(HIST("mc/recoCol_true/corr/h3_ptPhiEta_trig"), trigger.pt(), trigger.phi(), trigger.eta()); + + // save trigger for mixing + mixingTriggerMemoryRecoColTrue.saveTrigger(trigger.pt(), trigger.phi(), trigger.eta(), mcCollision.posZ(), mcCollision.nChargedInEtaRange()); + + // hadrons (tracks) and pipm + for (auto const& associated : mcParticlesThisEvent) { + // exclude self correlation + if (trigger.jetMcParticleId() == associated.globalIndex()) + continue; + + fillMcCorrHists(mcCollision, trigger, associated, 1); + } + } + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processMcRecoColTrueCorr, "process mc-true (reco collisions) correlation for multiple associated particles", false); + + void processMcRecoColTrueMix(CorrMcDCollisions const& collisions, CorrMcCollisions const&, aod::TriggerParticles const& triggerParticles, aod::JetParticles const& mcParticles) + { + for (auto const& collision : collisions) { + // event selection + if (!collision.selEv()) + continue; + + // group collision + auto const triggerParticlesThisEvent = triggerParticles.sliceBy(perColTriggerParticles, collision.mcCollisionId()); + auto const mcParticlesThisEvent = mcParticles.sliceBy(perColMcParticles, collision.mcCollisionId()); + + auto const& mcCollision = collision.mcCollision_as(); + + const size_t nTriggerParticlesThisDataFrame = triggerParticles.size(); + auto savedTriggers = mixingTriggerMemoryRecoColTrue.getTriggers(mcCollision.posZ(), mcCollision.nChargedInEtaRange()); + const size_t mixUpToTriggerN = std::min(savedTriggers.size(), static_cast(nTriggerMixingMcTrue) + nTriggerParticlesThisDataFrame); + const float perTriggerWeight = 1. / (mixUpToTriggerN - nTriggerParticlesThisDataFrame); + + // trigger loop + for (size_t i_mixingTrigger = nTriggerParticlesThisDataFrame; i_mixingTrigger < mixUpToTriggerN; i_mixingTrigger++) { + MixingTrigger const& mixingTrigger = savedTriggers[i_mixingTrigger]; + for (auto const& associated : mcParticlesThisEvent) { + fillMcCorrHists(mcCollision, mixingTrigger, associated, perTriggerWeight); + } + } + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processMcRecoColTrueMix, "process mc-true (reco collisions) correlation mixing for multiple associated particles", false); + + void processMcRecoColEff(CorrMcDCollision const& collision, aod::JetTracksMCD const& tracks, + aod::Hadrons const& hadrons, aod::Pipms const& pipms, aod::PhotonPCMs const& photonPCMs, + CorrMcCollisions const&, aod::JetParticles const& mcParticles, aod::TriggerParticles const& triggerParticles) + { + // event selection + if (!collision.selEv()) + return; + + auto const mcParticlesThisEvent = mcParticles.sliceBy(perColMcParticles, collision.mcCollisionId()); + auto const triggerParticlesThisEvent = triggerParticles.sliceBy(perColTriggerParticles, collision.mcCollisionId()); + + // hadrons + for (auto const& hadron : hadrons) { + if (doTrigEvEff && !collision.trigEv() && hadron.pt() < ptCutTrigEvEff) + continue; + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcReco_hadron"), hadron.pt(), hadron.phi(), hadron.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcReco_hadron"), hadron.pt(), collision.posZ(), collision.nGlobalTracks()); + // purity + if (!hadron.jetTrack_as().has_mcParticle()) + continue; + auto const hadronParticle = hadron.jetTrack_as().mcParticle(); + if (!checkPrimaryTrackMc(hadronParticle)) + continue; + if (requireSingleCollisionPurity && hadronParticle.mcCollisionId() != collision.mcCollisionId()) + continue; + + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcReco_hasCorrectMc_hadron"), hadron.pt(), hadron.phi(), hadron.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcReco_hasCorrectMc_hadron"), hadron.pt(), collision.posZ(), collision.nGlobalTracks()); + } + + // pipm + for (auto const& pipm : pipms) { + if (doTrigEvEff && !collision.trigEv() && pipm.pt() < ptCutTrigEvEff) + continue; + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcReco_pipm"), pipm.pt(), pipm.phi(), pipm.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcReco_pipm"), pipm.pt(), collision.posZ(), collision.nGlobalTracks()); + // purity + if (!pipm.jetTrack_as().has_mcParticle()) + continue; + auto const pipmParticle = pipm.jetTrack_as().mcParticle(); + if (std::abs(pipmParticle.pdgCode()) != PDG_t::kPiPlus || !checkPrimaryEtaMc(pipmParticle)) + continue; + if (requireSingleCollisionPurity && pipmParticle.mcCollisionId() != collision.mcCollisionId()) + continue; + + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcReco_hasCorrectMc_pipm"), pipm.pt(), pipm.phi(), pipm.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcReco_hasCorrectMc_pipm"), pipm.pt(), collision.posZ(), collision.nGlobalTracks()); + } + + // photonPCM + for (auto const& photonPCM : photonPCMs) { + if (doTrigEvEff && !collision.trigEv()) + continue; + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcReco_photonPCM"), photonPCM.pt(), photonPCM.phi(), photonPCM.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcReco_photonPCM"), photonPCM.pt(), collision.posZ(), collision.nGlobalTracks()); + + // purity + // (V0Legs does not have the tracks reference as index column (just int)??) + auto const& posTrack = tracks.rawIteratorAt(photonPCM.posTrackId() - tracks.offset()); + auto const& negTrack = tracks.rawIteratorAt(photonPCM.negTrackId() - tracks.offset()); + if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) + continue; + if (!isConversionPhoton(posTrack, negTrack) || !checkPrimaryEtaMc(*(posTrack.mcParticle().mothers_as().begin()))) + continue; + if (requireSingleCollisionPurity && posTrack.mcParticle().mcCollisionId() != collision.mcCollisionId()) + continue; + + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcReco_hasCorrectMc_photonPCM"), photonPCM.pt(), photonPCM.phi(), photonPCM.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcReco_hasCorrectMc_photonPCM"), photonPCM.pt(), collision.posZ(), collision.nGlobalTracks()); + } + + // mcParticle loop + for (auto const& mcParticle : mcParticlesThisEvent) { + bool const countChargedTrigEvEff = !doTrigEvEff || collision.trigEv() || mcParticle.pt() > ptCutTrigEvEff; + bool const countOtherTrigEvEff = !doTrigEvEff || collision.trigEv(); + + // standard particles (marked physical primary) + if (checkPrimaryEtaMc(mcParticle)) { + // hadrons + if (checkChargedMc(mcParticle) && countChargedTrigEvEff) { + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcTrue_recoCol_hadron"), mcParticle.pt(), mcParticle.phi(), mcParticle.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcTrue_recoCol_hadron"), mcParticle.pt(), collision.mcCollision_as().posZ(), collision.nGlobalTracks()); + } + // pipm + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus && countChargedTrigEvEff) { + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcTrue_recoCol_pipm"), mcParticle.pt(), mcParticle.phi(), mcParticle.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcTrue_recoCol_pipm"), mcParticle.pt(), collision.mcCollision_as().posZ(), collision.nGlobalTracks()); + } + // photons + if (mcParticle.pdgCode() == PDG_t::kGamma && countOtherTrigEvEff) { + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcTrue_recoCol_photon"), mcParticle.pt(), mcParticle.phi(), mcParticle.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcTrue_recoCol_photon"), mcParticle.pt(), collision.mcCollision_as().posZ(), collision.nGlobalTracks()); + } + } + + // decaying particles (not marked physical primary) + if ((std::abs(mcParticle.eta()) < etaMax)) { + // pi0 + if (checkH0ToGG(mcParticle, PDG_t::kPi0) && countOtherTrigEvEff) { + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcTrue_recoCol_pi0"), mcParticle.pt(), mcParticle.phi(), mcParticle.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcTrue_recoCol_pi0"), mcParticle.pt(), collision.mcCollision_as().posZ(), collision.nGlobalTracks()); + } + // eta + if (checkH0ToGG(mcParticle, 221) && countOtherTrigEvEff) { + histos.fill(HIST("mc/eff/h3_ptPhiEta_mcTrue_recoCol_eta"), mcParticle.pt(), mcParticle.phi(), mcParticle.eta()); + histos.fill(HIST("mc/eff/h3_ptZPvMult_mcTrue_recoCol_eta"), mcParticle.pt(), collision.mcCollision_as().posZ(), collision.nGlobalTracks()); + } + } + } + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processMcRecoColEff, "process MC data to calculate efficiencies and purities", false); + + // test ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void processTest(CorrCollision const& collision, + soa::Join const& tracks, soa::Join const&, + aod::Hadrons const& hadrons) + { + // event selection + if (!collision.selEv()) + return; + + histos.fill(HIST("test/h2_mult_comp"), collision.nGlobalTracks(), hadrons.size()); + + for (auto const& track : tracks) { + auto const fullTrack = track.track_as>(); + + constexpr float Mincrossedrows = 40; + constexpr float Maxchi2tpc = 5.0; + constexpr float Maxchi2its = 6.0; + constexpr float MaxR = 83.1; + constexpr float MinPtTrackiu = 0.1; + + if (!fullTrack.hasITS() && !fullTrack.hasTPC()) + continue; + if (fullTrack.x() * fullTrack.x() + fullTrack.y() * fullTrack.y() > MaxR * MaxR || fullTrack.pt() < MinPtTrackiu) + continue; + if (fullTrack.hasTPC()) { + if (fullTrack.tpcNClsCrossedRows() < Mincrossedrows || fullTrack.tpcChi2NCl() > Maxchi2tpc) + continue; + } + if (fullTrack.hasITS()) { + if (fullTrack.itsChi2NCl() > Maxchi2its) + continue; + } + + histos.fill(HIST("test/h2_tracks_zPvMultDep"), collision.posZ(), collision.nGlobalTracks()); + } + + histos.fill(HIST("test/h2_globalTracks_zPvMultDep"), collision.posZ(), collision.nGlobalTracks(), hadrons.size()); + } + PROCESS_SWITCH(PhotonChargedTriggerCorrelation, processTest, "process just to test things", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& configContext) +{ + return WorkflowSpec{adaptAnalysisTask(configContext)}; +} diff --git a/PWGJE/Tasks/photonChargedTriggerProducer.cxx b/PWGJE/Tasks/photonChargedTriggerProducer.cxx new file mode 100644 index 00000000000..d600ca43c03 --- /dev/null +++ b/PWGJE/Tasks/photonChargedTriggerProducer.cxx @@ -0,0 +1,348 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file photonChargedTriggerProducer.cxx +/// \author Julius Kinner +/// \brief photon-jet angular correlation table producer +/// +/// Table producer for photon-jet angular correlation analysis (see photonChargedTriggerCorrelation.cxx) + +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/PhotonChargedTriggerCorrelation.h" + +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TMath.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +// correlation derived data =================================================================================================================================================================== + +struct PhotonChargedTriggerProducer { + // reco + Produces collisionExtraCorrTable; + Produces triggerTable; + Produces hadronTable; + Produces pipmTable; + Produces photonPCMTable; + Produces photonPCMPairTable; + // mc + Produces mcCollisionExtraCorrTable; + Produces triggerParticleTable; + + Configurable zPvMax{"zPvMax", 7, "maximum absZ primary-vertex cut"}; + Configurable occupancyMin{"occupancyMin", 0, "minimum occupancy cut"}; + Configurable occupancyMax{"occupancyMax", 2000, "maximum occupancy cut"}; + Configurable etaMax{"etaMax", 0.8, "maximum absEta cut"}; + + Configurable eventSelections{"eventSelections", "sel8", "JE framework - event selection"}; + Configurable trackSelections{"trackSelections", "globalTracks", "JE framework - track selections"}; + Configurable triggerMasks{"triggerMasks", "", "JE framework - skimmed data trigger masks (relevent for correlation: fTrackLowPt,fTrackHighPt)"}; + + Configurable piPIDLowPt{"piPIDLowPt", 0.5, "max pt value for pipm PID without tof"}; + Configurable piPIDHighPt{"piPIDHighPt", 2.5, "min pt value for pipm PID without tof in relativistic rise of Bethe-Bloch"}; + Configurable> nSigmaPiTpcLowPt{"nSigmaPiTpcLowPt", {-2, 2}, "minimum-maximum nSigma for pipm in tpc at low pt"}; + Configurable> nSigmaPiTpcMidPt{"nSigmaPiTpcMidPt", {-1, 1}, "minimum-maximum nSigma for pipm in tpc at mid pt"}; + Configurable> nSigmaPiTof{"nSigmaPiTof", {-1, 2}, "minimum-maximum nSigma for pipm in tof"}; + Configurable> nSigmaPiRelRise{"nSigmaPiRelRise", {0, 2}, "minimum-maximum nSigma pipm tpc at high pt"}; + + Configurable ptTrigMin{"ptTrigMin", 5, "minimum pT of triggers"}; + + // derivatives of configurables + + std::vector eventSelectionBits; + int trackSelection = -1; + std::vector triggerMaskBits; + + // for mc + Service pdg; + + // partitions++ + SliceCache cache; + + Preslice perColTracks = aod::jtrack::collisionId; + Preslice perColMcParticles = aod::jmcparticle::mcCollisionId; + + Preslice perColV0Photons = aod::v0photonkf::collisionId; + + // functions ================================================================================================================================================================================ + + // selections /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // event selection + template + bool checkEventSelection(T_collision const& collision) + { + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) + return false; + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) + return false; + if (std::abs(collision.posZ()) > zPvMax) + return false; + if (collision.trackOccupancyInTimeRange() < occupancyMin || collision.trackOccupancyInTimeRange() > occupancyMax) + return false; + return true; + } + + // checks global track cuts + template + bool checkGlobalTrackEta(T_track const& track) + { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) + return false; + if (!jetderiveddatautilities::applyTrackKinematics(track, 0.1, 1000, -1 * etaMax, etaMax)) + return false; + return true; + } + + // checks pipm selection (just PID (no additional track cuts)) + template + bool checkPipmTPCTOF(T_track const& track) + { + // too low for tof + if (track.pt() < piPIDLowPt) { + if (track.tpcNSigmaPi() > nSigmaPiTpcLowPt.value[0] && track.tpcNSigmaPi() < nSigmaPiTpcLowPt.value[1]) { + return true; + } + return false; + } + // Bethe-Bloch overlap (-> tpc + tof) + if (track.pt() < piPIDHighPt) { + if (track.hasTOF()) { // has to stay inside pt-if due to return-layout of function + if (track.tpcNSigmaPi() > nSigmaPiTpcMidPt.value[0] && track.tpcNSigmaPi() < nSigmaPiTpcMidPt.value[1] && + track.tofNSigmaPi() > nSigmaPiTof.value[0] && track.tofNSigmaPi() < nSigmaPiTof.value[1]) { + return true; + } + } + return false; + } + // Bethe-Bloch rel rise (too high for tof) + if (track.tpcNSigmaPi() > nSigmaPiRelRise.value[0] && track.tpcNSigmaPi() < nSigmaPiRelRise.value[1]) { + return true; + } + return false; + } + + // checks pipm selection (just PID (no additional track cuts)) + template + bool checkPipmTPC(T_track const& track) + { + // Bethe-Bloch rel rise + if (track.pt() > piPIDHighPt) { + if (track.tpcNSigmaPi() > nSigmaPiRelRise.value[0] && track.tpcNSigmaPi() < nSigmaPiRelRise.value[1]) { + return true; + } + } + return false; + } + + // analysis ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void init(InitContext const&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + } + + void processRecoCollisionTrigger(aod::JetCollision const& collision, aod::JetTracks const& tracks) + { + // event selection + const bool isSelectedEvent = checkEventSelection(collision); + // trigger event check + bool isTriggerEvent = false; + // number global tracks + int nGlobalTracks = 0; + + // count global tracks (for independence of multiplicity task (uses only JE derieved data)) + for (auto const& track : tracks) { + // track selection + if (!checkGlobalTrackEta(track)) + continue; + + nGlobalTracks++; + + if (!isSelectedEvent) + continue; + if (track.pt() < ptTrigMin) + continue; + + isTriggerEvent = true; + + // trigger info + triggerTable(track.collisionId(), track.globalIndex(), track.pt(), track.phi(), track.eta()); + } + + // collision info + collisionExtraCorrTable(isSelectedEvent, isTriggerEvent, nGlobalTracks); + } + PROCESS_SWITCH(PhotonChargedTriggerProducer, processRecoCollisionTrigger, "process correlation collision_extra and trigger table (reconstructed)", false); + + void processRecoPipmTPCTOF(aod::JetCollision const& collision, + soa::Join const& tracks, soa::Join const&) + { + // event selection + if (!checkEventSelection(collision)) + return; + + // hadron/pipm + for (auto const& track : tracks) { + // track selection + if (!checkGlobalTrackEta(track)) + continue; + + // hadron + hadronTable(track.collisionId(), track.globalIndex(), track.pt(), track.phi(), track.eta()); + + // pipm selection + auto const& trackPID = track.track_as>(); + if (!checkPipmTPCTOF(trackPID)) + continue; + + // pipm + pipmTable(track.collisionId(), track.globalIndex(), track.pt(), track.phi(), track.eta()); + } + } + PROCESS_SWITCH(PhotonChargedTriggerProducer, processRecoPipmTPCTOF, "process pipm (TPC-TOF) table (reconstructed)", false); + + void processRecoPipmTPC(aod::JetCollision const& collision, + soa::Join const& tracks, soa::Join const&) + { + // event selection + if (!checkEventSelection(collision)) + return; + + // hadron/pipm + for (auto const& track : tracks) { + // track selection + if (!checkGlobalTrackEta(track)) + continue; + + // hadron + hadronTable(track.collisionId(), track.globalIndex(), track.pt(), track.phi(), track.eta()); + + // pipm selection + auto const& trackPID = track.track_as>(); + if (!checkPipmTPC(trackPID)) + continue; + + // pipm + pipmTable(track.collisionId(), track.globalIndex(), track.pt(), track.phi(), track.eta()); + } + } + PROCESS_SWITCH(PhotonChargedTriggerProducer, processRecoPipmTPC, "process pipm (TPC) table (reconstructed)", false); + + void processRecoPhotonPCM(soa::Join::iterator const& collision, + aod::V0PhotonsKF const& v0Photons, aod::V0Legs const&) + { + // event selection + if (!checkEventSelection(collision)) + return; + + // photonsPCM (for some reason collsionId not an index column (?)) + auto const v0PhotonsThisEvent = v0Photons.sliceBy(perColV0Photons, collision.collisionId()); + + // photonPCM + for (auto const& v0Photon : v0PhotonsThisEvent) { + // photon selection + if (std::abs(v0Photon.eta()) > etaMax) + continue; + + // photon PCM + photonPCMTable(v0Photon.collisionId(), v0Photon.globalIndex(), + v0Photon.posTrack().trackId(), v0Photon.negTrack().trackId(), v0Photon.pt(), v0Photon.phi(), v0Photon.eta()); + } + + // photonPCm pairs + for (auto const& [v0Photon1, v0Photon2] : soa::combinations(soa::CombinationsStrictlyUpperIndexPolicy(v0PhotonsThisEvent, v0PhotonsThisEvent))) { + // get kinematics + ROOT::Math::PtEtaPhiMVector const p4V0PCM1(v0Photon1.pt(), v0Photon1.eta(), v0Photon1.phi(), 0.); + ROOT::Math::PtEtaPhiMVector const p4V0PCM2(v0Photon2.pt(), v0Photon2.eta(), v0Photon2.phi(), 0.); + ROOT::Math::PtEtaPhiMVector const p4V0PCMPair = p4V0PCM1 + p4V0PCM2; + + // pi0 selection + if (std::abs(p4V0PCMPair.Eta()) > etaMax) + continue; + + // save info + photonPCMPairTable(v0Photon1.collisionId(), v0Photon1.globalIndex(), v0Photon2.globalIndex(), + v0Photon1.posTrack().trackId(), v0Photon1.negTrack().trackId(), v0Photon2.posTrack().trackId(), v0Photon2.negTrack().trackId(), + p4V0PCMPair.Pt(), RecoDecay::constrainAngle(p4V0PCMPair.Phi(), 0), p4V0PCMPair.Eta(), p4V0PCMPair.M()); + } + } + PROCESS_SWITCH(PhotonChargedTriggerProducer, processRecoPhotonPCM, "process photonPCM table (reconstructed)", false); + + void processMcCorrTables(aod::JetMcCollision const&, aod::JetParticles const& mcParticles) + { + // trigger event check + bool isTriggerEvent = false; + // number charged particles in eta range + int nCharged = 0; + + // particle loop + for (auto const& mcParticle : mcParticles) { + // track selection + auto const pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + if (std::abs(mcParticle.eta()) > etaMax) + continue; + + nCharged++; + + // trigger selection + if (mcParticle.pt() < ptTrigMin) + continue; + + isTriggerEvent = true; + + // trigger info + triggerParticleTable(mcParticle.mcCollisionId(), mcParticle.globalIndex(), mcParticle.pt(), mcParticle.phi(), mcParticle.eta()); + } + + // collision info + mcCollisionExtraCorrTable(isTriggerEvent, nCharged); + } + PROCESS_SWITCH(PhotonChargedTriggerProducer, processMcCorrTables, "process table production (mc)", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& configContext) +{ + return WorkflowSpec{adaptAnalysisTask(configContext)}; +} diff --git a/PWGJE/Tasks/photonIsolationQA.cxx b/PWGJE/Tasks/photonIsolationQA.cxx new file mode 100644 index 00000000000..1738fef952f --- /dev/null +++ b/PWGJE/Tasks/photonIsolationQA.cxx @@ -0,0 +1,511 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/EMCALClusters.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// \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..89163899b78 --- /dev/null +++ b/PWGJE/Tasks/recoilJets.cxx @@ -0,0 +1,1376 @@ +// 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. + +/// \author Kotliarov Artem +/// \file recoilJets.cxx +/// \brief hadron-jet correlation analysis + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetSubtraction.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Multiplicity.h" + +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include +#include +#include + +#include "TRandom3.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +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 FilteredEventMultiplicity = soa::Filtered>::iterator; +using FilteredEventMultiplicityDetLevelGetWeight = soa::Filtered>::iterator; +using FilteredEventMultiplicityPartLevel = 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; +using FilteredParticles = soa::Filtered; + +using ColEvSelEA = soa::Filtered>::iterator; +using BCsRun3 = soa::Join; // aod::Run3MatchedToBCExclusive + +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 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 maxJetConstituentPt{"maxJetConstituentPt", 100., "Remove jets with constituent above this pT cut"}; + + 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"}; + + Configurable meanFT0A{"meanFT0A", -1., "Mean value of FT0A signal"}; + Configurable meanFT0C{"meanFT0C", -1., "Mean value of FT0C signal"}; + + Configurable meanZeqFT0A{"meanZeqFT0A", -1., "Mean value of equalized FT0A signal"}; + Configurable meanZeqFT0C{"meanZeqFT0C", -1., "Mean value of equalized FT0C signal"}; + + Configurable meanFT0APartLevel{"meanFT0APartLevel", -1., "Mean number of charged part. within FT0A acceptance"}; + Configurable meanFT0CPartLevel{"meanFT0CPartLevel", -1., "Mean number of charged part. within FT0C acceptance"}; + + // Parameters for recoil jet selection + Configurable> ptTTref{"ptTTref", {5., 7}, "Transverse momentum (min, max) range for reference TT"}; + Configurable> ptTTsig{"ptTTsig", {20., 50}, "Transverse momentum (min, max) range for signal TT"}; + Configurable recoilRegion{"recoilRegion", 0.6, "Width of recoil acceptance"}; + Configurable> phiRestrTTSelection{"phiRestrTTSelection", {0., 6.3}, "Restriction on phi angle (min, max) to search for TT"}; + + // Leading track and associated track + Configurable> pTLeadTrack{"pTLeadTrack", {1., 3.}, "Transverse momenturm range (min, max) for leading tracks"}; + Configurable> pTAssociatTrack{"pTAssociatTrack", {1., 3.}, "Transverse momenturm range (min, max) for associated tracks"}; + + // List of configurable parameters for histograms + Configurable histJetPt{"histJetPt", 100, "Maximum value of jet pT stored in histograms"}; + Configurable histMultBins{"histMultBins", 1000, "Number of bins for scaled FT0M multiplicity"}; + Configurable histZDCTimeBins{"histZDCTimeBins", 240, "Number of bins for ZDC timing histograms"}; + + // Axes specification + ConfigurableAxis multFT0CThresh{"multFT0CThresh", {VARIABLE_WIDTH, 0.0, 0.133, 0.233, 0.367, 0.567, 0.767, 1.067, 1.4, 1.867, 2.5, 3.9, 5.4, 6.9, 20.}, "Percentiles of scaled FT0C: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 1%, 0.1%, 0.01%"}; // default values for raw data + ConfigurableAxis multFT0MThresh{"multFT0MThresh", {VARIABLE_WIDTH, 0.0, 0.167, 0.267, 0.4, 0.567, 0.8, 1.067, 1.4, 1.833, 2.433, 3.667, 5.1, 6.433, 20.}, "Percentiles of scaled FT0M: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 1%, 0.1%, 0.01%"}; // default values for raw data + + ConfigurableAxis multFT0CThreshPartLevel{"multFT0CThreshPartLevel", {VARIABLE_WIDTH, 0.0, 0.133, 0.233, 0.367, 0.567, 0.767, 1.067, 1.4, 1.867, 2.5, 3.9, 5.4, 6.9, 20.}, "Percentiles of scaled FT0C: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 1%, 0.1%, 0.01%"}; + ConfigurableAxis multFT0MThreshPartLevel{"multFT0MThreshPartLevel", {VARIABLE_WIDTH, 0.0, 0.167, 0.267, 0.4, 0.567, 0.8, 1.067, 1.4, 1.833, 2.433, 3.667, 5.1, 6.433, 20.}, "Percentiles of scaled FT0M: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 1%, 0.1%, 0.01%"}; + + // Auxiliary variables + TRandom3* rand = new TRandom3(0); + + // Declare filter on collision Z vertex + Filter jCollisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + Filter jCollisionFilterMC = nabs(aod::jmccollision::posZ) < vertexZCut; + Filter collisionFilter = nabs(aod::collision::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; + Preslice partJetsPerCollision = aod::jet::mcCollisionId; + + void init(InitContext const&) + { + // Initialize histogram axes + AxisSpec pT{histJetPt, 0.0, histJetPt * 1., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec jetPTcorr{histJetPt + 20, -20., histJetPt * 1.0, "#it{p}_{T, jet}^{ch, corr} (GeV/#it{c})"}; + AxisSpec scaledFT0A{histMultBins, 0.0, 20., "FT0A / #LT FT0A #GT"}; + AxisSpec scaledFT0C{histMultBins, 0.0, 20., "FT0C / #LT FT0C #GT"}; + AxisSpec scaledFT0M{histMultBins, 0.0, 20., "FT0M^{*}"}; + AxisSpec zdcTiming{histZDCTimeBins, -30., 30., ""}; + + 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 rho{50, 0.0, 50., "#it{#rho}"}; + + std::string nameFT0Caxis = "FT0C / #LT FT0C #GT"; + std::string nameFT0Maxis = "FT0M^{*}"; + + // Convert configurable strings to std::string + std::string evSelToString = static_cast(evSel); + std::string trkSelToString = static_cast(trkSel); + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(evSelToString); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(trkSelToString); + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(triggerMasks); + + // List of raw and MC det. distributions + if (doprocessData || doprocessMCDetLevel || doprocessMCDetLevelWeighted) { + spectra.add("hEventSelectionCount", "Count # of events in the analysis", kTH1F, {{6, 0.0, 6.}}); + spectra.get(HIST("hEventSelectionCount"))->GetXaxis()->SetBinLabel(1, "Total # of events"); + spectra.get(HIST("hEventSelectionCount"))->GetXaxis()->SetBinLabel(2, Form("# of events after sel. %s", evSelToString.data())); + spectra.get(HIST("hEventSelectionCount"))->GetXaxis()->SetBinLabel(3, "# of events skipMBGap"); + spectra.get(HIST("hEventSelectionCount"))->GetXaxis()->SetBinLabel(4, "# of events w. outlier"); + spectra.get(HIST("hEventSelectionCount"))->GetXaxis()->SetBinLabel(5, "# of events w/o assoc MC."); + spectra.get(HIST("hEventSelectionCount"))->GetXaxis()->SetBinLabel(6, "# of selected events"); + + spectra.add("hScaledFT0C_vertexZ", "Z vertex of collisions", kTH2F, {{multFT0CThresh, nameFT0Caxis}, {60, -12., 12., "#it{z}_{vertex}"}}); + spectra.add("hScaledFT0M_vertexZ", "Z vertex of collisions", kTH2F, {{multFT0MThresh, nameFT0Maxis}, {60, -12., 12., "#it{z}_{vertex}"}}); + + spectra.add("hTrackSelectionCount", "Count # of tracks in the analysis", kTH1F, {{2, 0.0, 2.}}); + spectra.get(HIST("hTrackSelectionCount"))->GetXaxis()->SetBinLabel(1, "Total # of tracks"); + spectra.get(HIST("hTrackSelectionCount"))->GetXaxis()->SetBinLabel(2, Form("# of tracks after sel. %s", trkSelToString.data())); + + spectra.add("hScaledFT0CTrackPtEtaPhi", "Charact. of tracks", kTHnSparseF, {{multFT0CThresh, nameFT0Caxis}, pT, pseudorap, phiAngle}); + spectra.add("hScaledFT0MTrackPtEtaPhi", "Charact. of tracks", kTHnSparseF, {{multFT0MThresh, nameFT0Maxis}, 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("hScaledFT0C_Ntrig", "Total number of selected triggers per class vs scaled FT0C", kTH2F, {{multFT0CThresh, nameFT0Caxis}, {2, 0.0, 2.}}); + spectra.get(HIST("hScaledFT0C_Ntrig"))->GetYaxis()->SetBinLabel(1, "TT_{ref}"); + spectra.get(HIST("hScaledFT0C_Ntrig"))->GetYaxis()->SetBinLabel(2, "TT_{sig}"); + + spectra.add("hScaledFT0M_Ntrig", "Total number of selected triggers per class vs scaled FT0M", kTH2F, {{multFT0MThresh, nameFT0Maxis}, {2, 0.0, 2.}}); + spectra.get(HIST("hScaledFT0M_Ntrig"))->GetYaxis()->SetBinLabel(1, "TT_{ref}"); + spectra.get(HIST("hScaledFT0M_Ntrig"))->GetYaxis()->SetBinLabel(2, "TT_{sig}"); + + spectra.add("hScaledFT0C_TTRef_per_event", "Number of TT_{Ref} per event vs scaled FT0C", kTH2F, {{multFT0CThresh, nameFT0Caxis}, {15, 0.5, 15.5, "# of TT_{Ref}"}}); + spectra.add("hScaledFT0M_TTRef_per_event", "Number of TT_{Ref} per event vs scaled FT0M", kTH2F, {{multFT0MThresh, nameFT0Maxis}, {15, 0.5, 15.5, "# of TT_{Ref}"}}); + + spectra.add("hScaledFT0C_TTSig_per_event", "Number of TT_{Sig} per event vs scaled FT0C", kTH2F, {{multFT0CThresh, nameFT0Caxis}, {10, 0.5, 10.5, "# of TT_{Sig}"}}); + spectra.add("hScaledFT0M_TTSig_per_event", "Number of TT_{Sig} per event vs scaled FT0M", kTH2F, {{multFT0MThresh, nameFT0Maxis}, {10, 0.5, 10.5, "# of TT_{Sig}"}}); + + spectra.add("hJetPtEtaPhiRhoArea", "Charact. of inclusive jets", kTHnSparseF, {pT, pseudorapJets, phiAngle, rho, jetArea}); + + spectra.add("hScaledFT0C_DPhi_JetPt_Corr_TTRef", "Events w. TT_{Ref}: scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0CThresh, nameFT0Caxis}, deltaPhiAngle, jetPTcorr}); + spectra.add("hScaledFT0M_DPhi_JetPt_Corr_TTRef", "Events w. TT_{Ref}: scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0MThresh, nameFT0Maxis}, deltaPhiAngle, jetPTcorr}); + + spectra.add("hScaledFT0C_DPhi_JetPt_Corr_TTSig", "Events w. TT_{Sig}: scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0CThresh, nameFT0Caxis}, deltaPhiAngle, jetPTcorr}); + spectra.add("hScaledFT0M_DPhi_JetPt_Corr_TTSig", "Events w. TT_{Sig}: scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0MThresh, nameFT0Maxis}, deltaPhiAngle, jetPTcorr}); + + spectra.add("hScaledFT0C_DPhi_JetPt_TTRef", "Events w. TT_{Ref}: scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0CThresh, nameFT0Caxis}, deltaPhiAngle, pT}); + spectra.add("hScaledFT0M_DPhi_JetPt_TTRef", "Events w. TT_{Ref}: scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0MThresh, nameFT0Maxis}, deltaPhiAngle, pT}); + + spectra.add("hScaledFT0C_DPhi_JetPt_TTSig", "Events w. TT_{Sig}: scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0CThresh, nameFT0Caxis}, deltaPhiAngle, pT}); + spectra.add("hScaledFT0M_DPhi_JetPt_TTSig", "Events w. TT_{Sig}: scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0MThresh, nameFT0Maxis}, deltaPhiAngle, pT}); + + spectra.add("hScaledFT0C_Recoil_JetPt_Corr_TTRef", "Events w. TT_{Ref}: scaled FT0C & #it{p}_{T} of recoil jets", kTH2F, {{multFT0CThresh, nameFT0Caxis}, jetPTcorr}); + spectra.add("hScaledFT0M_Recoil_JetPt_Corr_TTRef", "Events w. TT_{Ref}: scaled FT0M & #it{p}_{T} of recoil jets", kTH2F, {{multFT0MThresh, nameFT0Maxis}, jetPTcorr}); + + spectra.add("hScaledFT0C_Recoil_JetPt_Corr_TTSig", "Events w. TT_{Sig}: scaled FT0C & #it{p}_{T} of recoil jets", kTH2F, {{multFT0CThresh, nameFT0Caxis}, jetPTcorr}); + spectra.add("hScaledFT0M_Recoil_JetPt_Corr_TTSig", "Events w. TT_{Sig}: scaled FT0M & #it{p}_{T} of recoil jets", kTH2F, {{multFT0MThresh, nameFT0Maxis}, jetPTcorr}); + + spectra.add("hScaledFT0C_Recoil_JetPt_TTRef", "Events w. TT_{Ref}: scaled FT0C & #it{p}_{T} of recoil jets", kTH2F, {{multFT0CThresh, nameFT0Caxis}, pT}); + spectra.add("hScaledFT0M_Recoil_JetPt_TTRef", "Events w. TT_{Ref}: scaled FT0M & #it{p}_{T} of recoil jets", kTH2F, {{multFT0MThresh, nameFT0Maxis}, pT}); + + spectra.add("hScaledFT0C_Recoil_JetPt_TTSig", "Events w. TT_{Sig}: scaled FT0C & #it{p}_{T} of recoil jets", kTH2F, {{multFT0CThresh, nameFT0Caxis}, pT}); + spectra.add("hScaledFT0M_Recoil_JetPt_TTSig", "Events w. TT_{Sig}: scaled FT0M & #it{p}_{T} of recoil jets", kTH2F, {{multFT0MThresh, nameFT0Maxis}, 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}); + + spectra.add("hScaledFT0C_Rho", "Scaled FT0C & #rho", kTH2F, {{multFT0CThresh, nameFT0Caxis}, rho}); + spectra.add("hScaledFT0M_Rho", "Scaled FT0M & #rho", kTH2F, {{multFT0MThresh, nameFT0Maxis}, rho}); + + spectra.add("hScaledFT0C_Rho_TTRef", "Events w. TT_{Ref}: scaled FT0C & #rho", kTH2F, {{multFT0CThresh, nameFT0Caxis}, rho}); + spectra.add("hScaledFT0M_Rho_TTRef", "Events w. TT_{Ref}: scaled FT0M & #rho", kTH2F, {{multFT0MThresh, nameFT0Maxis}, rho}); + + spectra.add("hScaledFT0C_Rho_TTSig", "Events w. TT_{Sig}: scaled FT0C & #rho", kTH2F, {{multFT0CThresh, nameFT0Caxis}, rho}); + spectra.add("hScaledFT0M_Rho_TTSig", "Events w. TT_{Sig}: scaled FT0M & #rho", kTH2F, {{multFT0MThresh, nameFT0Maxis}, rho}); + + spectra.add("hScaledFT0C_TTRef", "Events w. TT_{Ref}: scaled FT0C", kTH1F, {scaledFT0C}); + spectra.add("hScaledFT0M_TTRef", "Events w. TT_{Ref}: scaled FT0M", kTH1F, {scaledFT0M}); + + spectra.add("hScaledFT0C_TTSig", "Events w. TT_{Sig}: scaled FT0C", kTH1F, {scaledFT0C}); + spectra.add("hScaledFT0M_TTSig", "Events w. TT_{Sig}: scaled FT0M", kTH1F, {scaledFT0M}); + + // Rectricted phi range for TT selection + spectra.add("hScaledFT0C_DPhi_JetPt_Corr_TTRef_RectrictedPhi", Form("Events w. TT_{Ref} #in #varphi (%.2f, %.2f): scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", phiRestrTTSelection->at(0), phiRestrTTSelection->at(1)), kTH3F, {{multFT0CThresh, nameFT0Caxis}, deltaPhiAngle, jetPTcorr}); + spectra.add("hScaledFT0M_DPhi_JetPt_Corr_TTRef_RectrictedPhi", Form("Events w. TT_{Ref} #in #varphi (%.2f, %.2f): scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", phiRestrTTSelection->at(0), phiRestrTTSelection->at(1)), kTH3F, {{multFT0MThresh, nameFT0Maxis}, deltaPhiAngle, jetPTcorr}); + + spectra.add("hScaledFT0C_DPhi_JetPt_Corr_TTSig_RectrictedPhi", Form("Events w. TT_{Sig} #in #varphi (%.2f, %.2f): scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", phiRestrTTSelection->at(0), phiRestrTTSelection->at(1)), kTH3F, {{multFT0CThresh, nameFT0Caxis}, deltaPhiAngle, jetPTcorr}); + spectra.add("hScaledFT0M_DPhi_JetPt_Corr_TTSig_RectrictedPhi", Form("Events w. TT_{Sig} #in #varphi (%.2f, %.2f): scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", phiRestrTTSelection->at(0), phiRestrTTSelection->at(1)), kTH3F, {{multFT0MThresh, nameFT0Maxis}, deltaPhiAngle, jetPTcorr}); + } + + // List of MC particle level distributions + if (doprocessMCPartLevel || doprocessMCPartLevelWeighted) { + spectra.add("hScaledFT0C_vertexZMC", "Z vertex of MCcollision", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, {60, -12., 12., "#it{z}_{vertex}"}}); + spectra.add("hScaledFT0M_vertexZMC", "Z vertex of MCcollision", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, {60, -12., 12., "#it{z}_{vertex}"}}); + spectra.add("ptHat", "Distribution of pT hat", kTH1F, {{5000, 0.0, 1000.}}); + + spectra.add("hEventSelectionCountPartLevel", "Count # of events in the part. level analysis", kTH1F, {{4, 0.0, 4.}}); + spectra.get(HIST("hEventSelectionCountPartLevel"))->GetXaxis()->SetBinLabel(1, "Total # of events"); + spectra.get(HIST("hEventSelectionCountPartLevel"))->GetXaxis()->SetBinLabel(2, "# of events skipMB gap"); + spectra.get(HIST("hEventSelectionCountPartLevel"))->GetXaxis()->SetBinLabel(3, "# of events w. outlier"); + spectra.get(HIST("hEventSelectionCountPartLevel"))->GetXaxis()->SetBinLabel(4, "# of selected events"); + + spectra.add("hScaledFT0CPartPtEtaPhi", "Charact. of particles", kTHnSparseF, {{multFT0CThreshPartLevel, nameFT0Caxis}, pT, pseudorap, phiAngle}); + spectra.add("hScaledFT0MPartPtEtaPhi", "Charact. of particles", kTHnSparseF, {{multFT0MThreshPartLevel, nameFT0Maxis}, pT, pseudorap, phiAngle}); + + spectra.add("hScaledFT0C_Ntrig_Part", "Total number of selected triggers per class vs scaled FT0C", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, {2, 0.0, 2.}}); + spectra.get(HIST("hScaledFT0C_Ntrig_Part"))->GetXaxis()->SetBinLabel(1, "TT_{ref}"); + spectra.get(HIST("hScaledFT0C_Ntrig_Part"))->GetXaxis()->SetBinLabel(2, "TT_{sig}"); + + spectra.add("hScaledFT0M_Ntrig_Part", "Total number of selected triggers per class vs scaled FT0M", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, {2, 0.0, 2.}}); + spectra.get(HIST("hScaledFT0M_Ntrig_Part"))->GetXaxis()->SetBinLabel(1, "TT_{ref}"); + spectra.get(HIST("hScaledFT0M_Ntrig_Part"))->GetXaxis()->SetBinLabel(2, "TT_{sig}"); + + spectra.add("hScaledFT0C_TTRef_per_event_Part", "Number of TT_{Ref} per event vs scaled FT0C", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, {15, 0.5, 15.5, "# of TT_{Ref}"}}); + spectra.add("hScaledFT0M_TTRef_per_event_Part", "Number of TT_{Ref} per event vs scaled FT0M", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, {15, 0.5, 15.5, "# of TT_{Ref}"}}); + + spectra.add("hScaledFT0C_TTSig_per_event_Part", "Number of TT_{Sig} per event vs scaled FT0C", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, {10, 0.5, 10.5, "# of TT_{Sig}"}}); + spectra.add("hScaledFT0M_TTSig_per_event_Part", "Number of TT_{Sig} per event vs scaled FT0M", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, {10, 0.5, 10.5, "# of TT_{Sig}"}}); + + spectra.add("hJetPtEtaPhiRhoArea_Part", "Charact. of inclusive part. level jets", kTHnSparseF, {pT, pseudorapJets, phiAngle, rho, jetArea}); + + spectra.add("hScaledFT0C_DPhi_JetPt_Corr_TTRef_Part", "Events w. TT_{Ref}: scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0CThreshPartLevel, nameFT0Caxis}, deltaPhiAngle, jetPTcorr}); + spectra.add("hScaledFT0M_DPhi_JetPt_Corr_TTRef_Part", "Events w. TT_{Ref}: scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0MThreshPartLevel, nameFT0Maxis}, deltaPhiAngle, jetPTcorr}); + + spectra.add("hScaledFT0C_DPhi_JetPt_Corr_TTSig_Part", "Events w. TT_{Sig}: scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0CThreshPartLevel, nameFT0Caxis}, deltaPhiAngle, jetPTcorr}); + spectra.add("hScaledFT0M_DPhi_JetPt_Corr_TTSig_Part", "Events w. TT_{Sig}: scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0MThreshPartLevel, nameFT0Maxis}, deltaPhiAngle, jetPTcorr}); + + spectra.add("hScaledFT0C_DPhi_JetPt_TTRef_Part", "Events w. TT_{Ref}: scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0CThreshPartLevel, nameFT0Caxis}, deltaPhiAngle, pT}); + spectra.add("hScaledFT0M_DPhi_JetPt_TTRef_Part", "Events w. TT_{Ref}: scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0MThreshPartLevel, nameFT0Maxis}, deltaPhiAngle, pT}); + + spectra.add("hScaledFT0C_DPhi_JetPt_TTSig_Part", "Events w. TT_{Sig}: scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0CThreshPartLevel, nameFT0Caxis}, deltaPhiAngle, pT}); + spectra.add("hScaledFT0M_DPhi_JetPt_TTSig_Part", "Events w. TT_{Sig}: scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", kTH3F, {{multFT0MThreshPartLevel, nameFT0Maxis}, deltaPhiAngle, pT}); + + spectra.add("hScaledFT0C_Recoil_JetPt_Corr_TTRef_Part", "Events w. TT_{Ref}: scaled FT0C & #it{p}_{T} of recoil jets", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, jetPTcorr}); + spectra.add("hScaledFT0M_Recoil_JetPt_Corr_TTRef_Part", "Events w. TT_{Ref}: scaled FT0M & #it{p}_{T} of recoil jets", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, jetPTcorr}); + + spectra.add("hScaledFT0C_Recoil_JetPt_Corr_TTSig_Part", "Events w. TT_{Sig}: scaled FT0C & #it{p}_{T} of recoil jets", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, jetPTcorr}); + spectra.add("hScaledFT0M_Recoil_JetPt_Corr_TTSig_Part", "Events w. TT_{Sig}: scaled FT0M & #it{p}_{T} of recoil jets", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, jetPTcorr}); + + spectra.add("hScaledFT0C_Recoil_JetPt_TTRef_Part", "Events w. TT_{Ref}: scaled FT0C & #it{p}_{T} of recoil jets", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, pT}); + spectra.add("hScaledFT0M_Recoil_JetPt_TTRef_Part", "Events w. TT_{Ref}: scaled FT0M & #it{p}_{T} of recoil jets", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, pT}); + + spectra.add("hScaledFT0C_Recoil_JetPt_TTSig_Part", "Events w. TT_{Sig}: scaled FT0C & #it{p}_{T} of recoil jets", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, pT}); + spectra.add("hScaledFT0M_Recoil_JetPt_TTSig_Part", "Events w. TT_{Sig}: scaled FT0M & #it{p}_{T} of recoil jets", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, 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}); + + spectra.add("hScaledFT0C_Rho_Part", "Scaled FT0C & #rho", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, rho}); + spectra.add("hScaledFT0M_Rho_Part", "Scaled FT0M & #rho", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, rho}); + + spectra.add("hScaledFT0C_Rho_TTRef_Part", "Events w. TT_{Ref}: scaled FT0C & #rho", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, rho}); + spectra.add("hScaledFT0M_Rho_TTRef_Part", "Events w. TT_{Ref}: scaled FT0M & #rho", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, rho}); + + spectra.add("hScaledFT0C_Rho_TTSig_Part", "Events w. TT_{Sig}: scaled FT0C & #rho", kTH2F, {{multFT0CThreshPartLevel, nameFT0Caxis}, rho}); + spectra.add("hScaledFT0M_Rho_TTSig_Part", "Events w. TT_{Sig}: scaled FT0M & #rho", kTH2F, {{multFT0MThreshPartLevel, nameFT0Maxis}, rho}); + + spectra.add("hScaledFT0C_TTRef_Part", "Events w. TT_{Ref}: scaled FT0C", kTH1F, {scaledFT0C}); + spectra.add("hScaledFT0M_TTRef_Part", "Events w. TT_{Ref}: scaled FT0M", kTH1F, {scaledFT0M}); + + spectra.add("hScaledFT0C_TTSig_Part", "Events w. TT_{Sig}: scaled FT0C", kTH1F, {scaledFT0C}); + spectra.add("hScaledFT0M_TTSig_Part", "Events w. TT_{Sig}: scaled FT0M", kTH1F, {scaledFT0M}); + + // Rectricted phi range for TT selection + spectra.add("hScaledFT0C_DPhi_JetPt_Corr_TTRef_RectrictedPhi_Part", Form("Events w. TT_{Ref} #in #varphi (%.2f, %.2f): scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", phiRestrTTSelection->at(0), phiRestrTTSelection->at(1)), kTH3F, {{multFT0CThreshPartLevel, nameFT0Caxis}, deltaPhiAngle, jetPTcorr}); + spectra.add("hScaledFT0M_DPhi_JetPt_Corr_TTRef_RectrictedPhi_Part", Form("Events w. TT_{Ref} #in #varphi (%.2f, %.2f): scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", phiRestrTTSelection->at(0), phiRestrTTSelection->at(1)), kTH3F, {{multFT0MThreshPartLevel, nameFT0Maxis}, deltaPhiAngle, jetPTcorr}); + + spectra.add("hScaledFT0C_DPhi_JetPt_Corr_TTSig_RectrictedPhi_Part", Form("Events w. TT_{Sig} #in #varphi (%.2f, %.2f): scaled FT0C & #Delta#varphi & #it{p}_{T, jet}^{ch}", phiRestrTTSelection->at(0), phiRestrTTSelection->at(1)), kTH3F, {{multFT0CThreshPartLevel, nameFT0Caxis}, deltaPhiAngle, jetPTcorr}); + spectra.add("hScaledFT0M_DPhi_JetPt_Corr_TTSig_RectrictedPhi_Part", Form("Events w. TT_{Sig} #in #varphi (%.2f, %.2f): scaled FT0M & #Delta#varphi & #it{p}_{T, jet}^{ch}", phiRestrTTSelection->at(0), phiRestrTTSelection->at(1)), kTH3F, {{multFT0MThreshPartLevel, nameFT0Maxis}, deltaPhiAngle, jetPTcorr}); + } + + // 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}); + + 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}); + + 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 tagged jets per 1 base jet vs. jet pT", kTH2F, {{10, 0.5, 10.5}, {100, 0.0, 100.}}); + } + + // Multiplicity for raw data and detector level MC + if (doprocessMultiplicityOO || doprocessMultiplicityMCDetLevelWeightedOO) { + spectra.add("hMultFT0A", "Mult. signal from FTOA", kTH1F, {{2000, 0.0, 40000., "FT0A"}}); + spectra.add("hMultFT0C", "Mult. signal from FTOC", kTH1F, {{2000, 0.0, 40000., "FT0C"}}); + spectra.add("hMultFT0M", "Total mult. signal from FT0A & FTOC", kTH1F, {{3000, 0.0, 60000., "FT0M"}}); + + spectra.add("hScaleMultFT0A", "Scaled mult. signal from FTOA", kTH1F, {scaledFT0A}); + spectra.add("hScaleMultFT0C", "Scaled mult. signal from FTOC", kTH1F, {scaledFT0C}); + spectra.add("hScaleMultFT0M", "Scaled total mult. signal from FT0A & FTOC", kTH1F, {scaledFT0M}); + + spectra.add("hMultZNA", "Mult. signal from ZDC A-side", kTH1F, {{1000, 0.0, 5000., "ZNA"}}); + spectra.add("hMultZNC", "Mult. signal from ZDC C-side", kTH1F, {{1000, 0.0, 5000., "ZNC"}}); + spectra.add("hMultZNM", "Total mult. signal from ZDCs for neutrons", kTH1F, {{4000, 0.0, 8000., "ZNM"}}); + + spectra.add("hMultZPA", "Mult. signal from ZDC A-side", kTH1F, {{1000, 0.0, 5000., "ZPA"}}); + spectra.add("hMultZPC", "Mult. signal from ZDC C-side", kTH1F, {{1000, 0.0, 5000., "ZPC"}}); + spectra.add("hMultZPM", "Total mult. signal from ZDCs for protons", kTH1F, {{4000, 0.0, 8000., "ZPM"}}); + + // Correlations + spectra.add("hZPA_vs_ZNA", "Correlation of signals ZPA vs ZNA", kTH2F, {{1000, 0.0, 5000., "ZPA"}, {1000, 0.0, 5000., "ZNA"}}); + spectra.add("hZPC_vs_ZNC", "Correlation of signals ZPC vs ZNC", kTH2F, {{1000, 0.0, 5000., "ZPC"}, {1000, 0.0, 5000., "ZNC"}}); + + spectra.add("hMultFT0A_vs_ZNA", "Correlation of signals FTOA vs ZNA", kTH2F, {{2000, 0.0, 40000., "FT0A"}, {1000, 0.0, 5000., "ZNA"}}); + spectra.add("hMultFT0C_vs_ZNC", "Correlation of signals FTOC vs ZNC", kTH2F, {{2000, 0.0, 40000., "FT0C"}, {1000, 0.0, 5000., "ZNC"}}); + spectra.add("hMultFT0M_vs_ZNM", "Correlation of signals FTOM vs ZNM", kTH2F, {{3000, 0.0, 60000., "FT0M"}, {4000, 0.0, 8000., "ZNM"}}); + + spectra.add("hScaleMultFT0A_vs_ZNA", "Correlation of signals FT0A/meanFT0A vs ZNA", kTH2F, {{scaledFT0A}, {1000, 0.0, 5000., "ZNA"}}); + spectra.add("hScaleMultFT0C_vs_ZNC", "Correlation of signals FT0C/meanFT0C vs ZNC", kTH2F, {{scaledFT0C}, {1000, 0.0, 5000., "ZNC"}}); + spectra.add("hScaleMultFT0M_vs_ZNM", "Correlation of signals FT0M^{*} vs ZNM", kTH2F, {{scaledFT0M}, {4000, 0.0, 8000., "ZNM"}}); + + spectra.add("hScaleMultFT0A_vs_ZPA", "Correlation of signals FT0A/meanFT0A vs ZPA", kTH2F, {{scaledFT0A}, {1000, 0.0, 5000., "ZPA"}}); + spectra.add("hScaleMultFT0C_vs_ZPC", "Correlation of signals FT0C/meanFT0C vs ZPC", kTH2F, {{scaledFT0C}, {1000, 0.0, 5000., "ZPC"}}); + spectra.add("hScaleMultFT0M_vs_ZPM", "Correlation of signals FT0M^{*} vs ZPM", kTH2F, {{scaledFT0M}, {4000, 0.0, 8000., "ZPM"}}); + + spectra.add("hScaleMultFT0M_vs_ZNA_vs_ZNC", "Correlation of signals FT0M^{*} vs ZNA vs ZNC", kTH3F, {{scaledFT0M}, {600, 0.0, 3000., "ZNA"}, {600, 0.0, 3000., "ZNC"}}); + spectra.add("hScaleMultFT0M_vs_ZPA_vs_ZPC", "Correlation of signals FT0M^{*} vs ZPA vs ZPC", kTH3F, {{scaledFT0M}, {600, 0.0, 3000., "ZPA"}, {600, 0.0, 3000., "ZPC"}}); + } + + // Multiplicity for particle level MC + if (doprocessMultiplicityPartLevelMC || doprocessMultiplicityPartLevelMCWeighted) { + spectra.add("hMultFT0APartLevel", "# of primary particles within FTOA acceptance", kTH1F, {{2000, 0.0, 500., "FT0A"}}); + spectra.add("hMultFT0CPartLevel", "# of primary particles within FTOC acceptance", kTH1F, {{2000, 0.0, 500., "FT0C"}}); + spectra.add("hMultFT0MPartLevel", "Total # of primary particles from FT0A & FTOC", kTH1F, {{4000, 0.0, 1000., "FT0M"}}); + + spectra.add("hScaleMultFT0APartLevel", "Scaled # of primary particles within FTOA acceptance", kTH1F, {scaledFT0A}); + spectra.add("hScaleMultFT0CPartLevel", "Scaled # of primary particles within FTOC acceptance", kTH1F, {scaledFT0C}); + spectra.add("hScaleMultFT0MPartLevel", "Scaled total # of primary particles from FT0A & FTOC", kTH1F, {scaledFT0M}); + } + + if (doprocessMultiplicityQA) { + + // ZNC timing QA + spectra.add("hTimeCorrZnaZnc", "Correlat. #it{t}_{ZNA} - #it{t}_{ZNC} vs. #it{t}_{ZNA} + #it{t}_{ZNC}", kTH2F, {{1000, -10., 10., "#it{t}_{ZNA} - #it{t}_{ZNC} (ns)"}, {1000, -10., 10., "#it{t}_{ZNA} + #it{t}_{ZNC} (ns)"}}); + spectra.add("hTimeZnaVsZncVsFT0C", "Correlat. #it{t}_{ZNA} (ns) vs. #it{t}_{ZNC} (ns) vs. FT0C/meanFT0C", kTH3F, {{zdcTiming}, {zdcTiming}, {scaledFT0C}}); + spectra.add("hTimeZnaVsZncVsFT0M", "Correlat. #it{t}_{ZNA} (ns) vs. #it{t}_{ZNC} (ns) vs. FT0M^{*}", kTH3F, {{zdcTiming}, {zdcTiming}, {scaledFT0M}}); + + // Number of tracks from PV within acceptance |eta| < 0.8 + spectra.add("hScaledFT0C_TracksPV", "Correlat. FT0C/meanFT0C vs. PV tracks", kTH2F, {{scaledFT0C}, {5000, 0., 5000.}}); + spectra.add("hScaledFT0M_TracksPV", "Correlat. FT0M^{*} vs. PV tracks", kTH2F, {{scaledFT0M}, {5000, 0., 5000.}}); + + // ITS-only tracks + spectra.add("hScaledFT0C_ITStracks", "Correlat. FT0C/meanFT0C vs. number of ITS tracks", kTH2F, {{scaledFT0C}, {5000, 0., 5000.}}); + spectra.add("hScaledFT0M_ITStracks", "Correlat. FT0M^{*} vs. number of ITS tracks", kTH2F, {{scaledFT0M}, {5000, 0., 5000.}}); + + // Multiplicity equalized for the vertex position with FT0 detector + spectra.add("hMultZeqFT0A", "Equalized mult. FT0A", kTH1F, {{{2000, 0.0, 40000., "FT0A"}}}); + spectra.add("hMultZeqFT0C", "Equalized mult. FT0C", kTH1F, {{{2000, 0.0, 40000., "FT0C"}}}); + spectra.add("hMultZeqFT0M", "Equalized mult. FT0M", kTH1F, {{{3000, 0.0, 60000., "FT0M"}}}); + + spectra.add("hScaledZeqFT0A", "Equalized FT0A/meanFT0A", kTH1F, {{scaledFT0A}}); + spectra.add("hScaledZeqFT0C", "Equalized FT0C/meanFT0C", kTH1F, {{scaledFT0C}}); + spectra.add("hScaledZeqFT0M", "Equalized FT0M^{*}", kTH1F, {{scaledFT0M}}); + + // Run-by-run study of EA + std::vector runNumbersOO = { + "564356", "564359", "564373", "564374", "564387", "564400", "564414", "564430", "564445"}; + const int nRunsOO = runNumbersOO.size(); + + std::vector evSelFlags = { + "sel8", "sel8 + IsGoodZvtxFT0vsPV", "sel8 + NoSameBunchPileup", "sel8 + IsGoodZvtxFT0vsPV + NoSameBunchPileup"}; + const int nEvSelFlags = evSelFlags.size(); + + // Scaled FT0 signal + spectra.add("hScaledFT0APerRunPerSetOfFlags", "FT0A/meanFT0A signal per run per set of ev. sel. flags", kTH3F, {{scaledFT0A}, {nRunsOO, 0., nRunsOO * 1.}, {nEvSelFlags, 0., nEvSelFlags * 1.}}); + spectra.add("hScaledFT0CPerRunPerSetOfFlags", "FT0C/meanFT0C signal per run per set of ev. sel. flags", kTH3F, {{scaledFT0C}, {nRunsOO, 0., nRunsOO * 1.}, {nEvSelFlags, 0., nEvSelFlags * 1.}}); + spectra.add("hScaledFT0MPerRunPerSetOfFlags", "FT0M^{*} signal per run per set of ev. sel. flags", kTH3F, {{scaledFT0M}, {nRunsOO, 0., nRunsOO * 1.}, {nEvSelFlags, 0., nEvSelFlags * 1.}}); + + // Unscaled FT0 signal; check whether mean value is the same for all runs + spectra.add("hFT0APerRunPerSetOfFlags", "FT0A signal per run per set of ev. sel. flags", kTH3F, {{2000, 0.0, 40000., "FT0A"}, {nRunsOO, 0., nRunsOO * 1.}, {nEvSelFlags, 0., nEvSelFlags * 1.}}); + spectra.add("hFT0CPerRunPerSetOfFlags", "FT0C signal per run per set of ev. sel. flags", kTH3F, {{2000, 0.0, 40000., "FT0C"}, {nRunsOO, 0., nRunsOO * 1.}, {nEvSelFlags, 0., nEvSelFlags * 1.}}); + spectra.add("hFT0MPerRunPerSetOfFlags", "FT0M signal per run per set of ev. sel. flags", kTH3F, {{3000, 0.0, 60000., "FT0M"}, {nRunsOO, 0., nRunsOO * 1.}, {nEvSelFlags, 0., nEvSelFlags * 1.}}); + + // Check whether each BC has FT0 signal + spectra.add("hIsFT0SignalComeFromCollPerRun", "", kTH2F, {{4, 0., 4.}, {nRunsOO, 0., nRunsOO * 1.}}); + spectra.get(HIST("hIsFT0SignalComeFromCollPerRun"))->GetXaxis()->SetBinLabel(1, "BC has FT0"); + spectra.get(HIST("hIsFT0SignalComeFromCollPerRun"))->GetXaxis()->SetBinLabel(2, "BC has not FT0"); + spectra.get(HIST("hIsFT0SignalComeFromCollPerRun"))->GetXaxis()->SetBinLabel(3, "Coll. w. BC"); + spectra.get(HIST("hIsFT0SignalComeFromCollPerRun"))->GetXaxis()->SetBinLabel(4, "Coll. w/o BC"); + + // FT0 signal for the case when there is no associated BC + spectra.add("hFT0AsignalWithoutBC", "", kTH2F, {{2000, 0.0, 40000., "FT0A"}, {nRunsOO, 0., nRunsOO * 1.}}); + spectra.add("hFT0CsignalWithoutBC", "", kTH2F, {{2000, 0.0, 40000., "FT0C"}, {nRunsOO, 0., nRunsOO * 1.}}); + spectra.add("hFT0MsignalWithoutBC", "", kTH2F, {{2000, 0.0, 40000., "FT0M"}, {nRunsOO, 0., nRunsOO * 1.}}); + + // Rename Y axis with Run numbers + for (int iRun = 0; iRun < nRunsOO; ++iRun) { + spectra.get(HIST("hScaledFT0APerRunPerSetOfFlags"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + spectra.get(HIST("hScaledFT0CPerRunPerSetOfFlags"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + spectra.get(HIST("hScaledFT0MPerRunPerSetOfFlags"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + + spectra.get(HIST("hFT0APerRunPerSetOfFlags"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + spectra.get(HIST("hFT0CPerRunPerSetOfFlags"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + spectra.get(HIST("hFT0MPerRunPerSetOfFlags"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + + spectra.get(HIST("hIsFT0SignalComeFromCollPerRun"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + + spectra.get(HIST("hFT0AsignalWithoutBC"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + spectra.get(HIST("hFT0CsignalWithoutBC"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + spectra.get(HIST("hFT0MsignalWithoutBC"))->GetYaxis()->SetBinLabel(iRun + 1, runNumbersOO[iRun]); + } + + // Rename Z axis with event selection flags + for (int iFlag = 0; iFlag < nEvSelFlags; ++iFlag) { + spectra.get(HIST("hScaledFT0APerRunPerSetOfFlags"))->GetZaxis()->SetBinLabel(iFlag + 1, evSelFlags[iFlag]); + spectra.get(HIST("hScaledFT0CPerRunPerSetOfFlags"))->GetZaxis()->SetBinLabel(iFlag + 1, evSelFlags[iFlag]); + spectra.get(HIST("hScaledFT0MPerRunPerSetOfFlags"))->GetZaxis()->SetBinLabel(iFlag + 1, evSelFlags[iFlag]); + + spectra.get(HIST("hFT0APerRunPerSetOfFlags"))->GetZaxis()->SetBinLabel(iFlag + 1, evSelFlags[iFlag]); + spectra.get(HIST("hFT0CPerRunPerSetOfFlags"))->GetZaxis()->SetBinLabel(iFlag + 1, evSelFlags[iFlag]); + spectra.get(HIST("hFT0MPerRunPerSetOfFlags"))->GetZaxis()->SetBinLabel(iFlag + 1, evSelFlags[iFlag]); + } + } + + if (doprocessLeadingAndAssociatedTracksTask) { + spectra.add("hScaledFT0C_Correlation_LeadTrack_AssociatTracks", Form("Leading track #it{p}_{T} #in (%.2f, %.2f); Associated track #it{p}_{T} #in (%.2f, %.2f)", pTLeadTrack->at(0), pTLeadTrack->at(1), pTAssociatTrack->at(0), pTAssociatTrack->at(1)), kTH2F, {{multFT0CThresh, nameFT0Caxis}, {120, -1.28, 5.0, "#it{#varphi} (rad)"}}); + spectra.add("hScaledFT0M_Correlation_LeadTrack_AssociatTracks", Form("Leading track #it{p}_{T} #in (%.2f, %.2f); Associated track #it{p}_{T} #in (%.2f, %.2f)", pTLeadTrack->at(0), pTLeadTrack->at(1), pTAssociatTrack->at(0), pTAssociatTrack->at(1)), kTH2F, {{multFT0MThresh, nameFT0Maxis}, {120, -1.28, 5.0, "#it{#varphi} (rad)"}}); + } + } + + // Fill histograms with raw or MC det. level data + template + void fillHistograms(JCollision const& collision, Jets const& jets, + JTracks const& tracks, float weight = 1.) + { + bool bSigEv = false; + std::vector vPhiOfTT; + double phiTT = 0.; + int nTT = 0; + float rho = collision.rho(); + float scaledFT0C = getScaledFT0(collision.multFT0C(), meanFT0C); + float scaledFT0M = getScaledFT0M(getScaledFT0(collision.multFT0A(), meanFT0A), scaledFT0C); + + auto dice = rand->Rndm(); + if (dice < fracSig) + bSigEv = true; + + spectra.fill(HIST("hScaledFT0C_vertexZ"), scaledFT0C, collision.posZ(), weight); + spectra.fill(HIST("hScaledFT0M_vertexZ"), scaledFT0M, collision.posZ(), weight); + + spectra.fill(HIST("hScaledFT0C_Rho"), scaledFT0C, rho, weight); + spectra.fill(HIST("hScaledFT0M_Rho"), scaledFT0M, rho, weight); + + for (const auto& track : tracks) { + spectra.fill(HIST("hTrackSelectionCount"), 0.5); + + if (skipTrack(track)) + continue; + + float trackPt = track.pt(); + float trackPhi = track.phi(); + + spectra.fill(HIST("hTrackSelectionCount"), 1.5); + spectra.fill(HIST("hScaledFT0CTrackPtEtaPhi"), scaledFT0C, trackPt, track.eta(), trackPhi, weight); + spectra.fill(HIST("hScaledFT0MTrackPtEtaPhi"), scaledFT0M, trackPt, track.eta(), trackPhi, weight); + + // Search for TT candidate + if (bSigEv && (trackPt > ptTTsig->at(0) && trackPt < ptTTsig->at(1))) { + vPhiOfTT.push_back(trackPhi); + spectra.fill(HIST("hTTSig_pT"), trackPt, weight); + ++nTT; + } + + if (!bSigEv && (trackPt > ptTTref->at(0) && trackPt < ptTTref->at(1))) { + vPhiOfTT.push_back(trackPhi); + ++nTT; + } + } + + if (nTT > 0) { // at least 1 TT + + phiTT = getPhiTT(vPhiOfTT); + + if (bSigEv) { + spectra.fill(HIST("hScaledFT0C_Ntrig"), scaledFT0C, 1.5, weight); + spectra.fill(HIST("hScaledFT0M_Ntrig"), scaledFT0M, 1.5, weight); + spectra.fill(HIST("hScaledFT0C_TTSig_per_event"), scaledFT0C, nTT, weight); + spectra.fill(HIST("hScaledFT0M_TTSig_per_event"), scaledFT0M, nTT, weight); + + spectra.fill(HIST("hScaledFT0C_TTSig"), scaledFT0C, weight); + spectra.fill(HIST("hScaledFT0M_TTSig"), scaledFT0M, weight); + + spectra.fill(HIST("hScaledFT0C_Rho_TTSig"), scaledFT0C, rho, weight); + spectra.fill(HIST("hScaledFT0M_Rho_TTSig"), scaledFT0M, rho, weight); + } else { + spectra.fill(HIST("hScaledFT0C_Ntrig"), scaledFT0C, 0.5, weight); + spectra.fill(HIST("hScaledFT0M_Ntrig"), scaledFT0M, 0.5, weight); + spectra.fill(HIST("hScaledFT0C_TTRef_per_event"), scaledFT0C, nTT, weight); + spectra.fill(HIST("hScaledFT0M_TTRef_per_event"), scaledFT0M, nTT, weight); + + spectra.fill(HIST("hScaledFT0C_TTRef"), scaledFT0C, weight); + spectra.fill(HIST("hScaledFT0M_TTRef"), scaledFT0M, weight); + + spectra.fill(HIST("hScaledFT0C_Rho_TTRef"), scaledFT0C, rho, weight); + spectra.fill(HIST("hScaledFT0M_Rho_TTRef"), scaledFT0M, rho, weight); + } + } + + for (const auto& jet : jets) { + // skip jets which have a constituent with pT above specified cut + if (isJetWithHighPtConstituent(jet, tracks)) + continue; + + float jetPt = jet.pt(); + float jetArea = jet.area(); + float jetPtCorr = jetPt - rho * jetArea; + + spectra.fill(HIST("hJetPtEtaPhiRhoArea"), jetPt, jet.eta(), jet.phi(), rho, jetArea, weight); + + if (nTT > 0) { + auto [dphi, bRecoilJet] = isRecoilJet(jet, phiTT); + + if (bSigEv) { + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_Corr_TTSig"), scaledFT0C, dphi, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_Corr_TTSig"), scaledFT0M, dphi, jetPtCorr, weight); + + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_TTSig"), scaledFT0C, dphi, jetPt, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_TTSig"), scaledFT0M, dphi, jetPt, weight); + spectra.fill(HIST("hJetArea_JetPt_Rho_TTSig"), jetArea, jetPt, rho, weight); + + if (phiTT > phiRestrTTSelection->at(0) && phiTT < phiRestrTTSelection->at(1)) { + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_Corr_TTSig_RectrictedPhi"), scaledFT0C, dphi, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_Corr_TTSig_RectrictedPhi"), scaledFT0M, dphi, jetPtCorr, weight); + } + + if (bRecoilJet) { + spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_Corr_TTSig"), scaledFT0C, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_Corr_TTSig"), scaledFT0M, jetPtCorr, weight); + + spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_TTSig"), scaledFT0C, jetPt, weight); + spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_TTSig"), scaledFT0M, jetPt, weight); + } + } else { + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_Corr_TTRef"), scaledFT0C, dphi, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_Corr_TTRef"), scaledFT0M, dphi, jetPtCorr, weight); + + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_TTRef"), scaledFT0C, dphi, jetPt, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_TTRef"), scaledFT0M, dphi, jetPt, weight); + spectra.fill(HIST("hJetArea_JetPt_Rho_TTRef"), jetArea, jetPt, rho, weight); + + if (phiTT > phiRestrTTSelection->at(0) && phiTT < phiRestrTTSelection->at(1)) { + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_Corr_TTRef_RectrictedPhi"), scaledFT0C, dphi, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_Corr_TTRef_RectrictedPhi"), scaledFT0M, dphi, jetPtCorr, weight); + } + + if (bRecoilJet) { + spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_Corr_TTRef"), scaledFT0C, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_Corr_TTRef"), scaledFT0M, jetPtCorr, weight); + + spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_TTRef"), scaledFT0C, jetPt, weight); + spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_TTRef"), scaledFT0M, jetPt, weight); + } + } + } + } + } + + template + void fillMCPHistograms(JCollision const& collision, Jets const& jets, + JParticles const& particles, float weight = 1.) + { + bool bSigEv = false; + std::vector vPhiOfTT; + double phiTT = 0.; + int nTT = 0; + float rho = collision.rho(); + float scaledFT0C = getScaledFT0(collision.multFT0C(), meanFT0CPartLevel); + float scaledFT0M = getScaledFT0M(getScaledFT0(collision.multFT0A(), meanFT0APartLevel), scaledFT0C); + + auto dice = rand->Rndm(); + if (dice < fracSig) + bSigEv = true; + + spectra.fill(HIST("hScaledFT0C_vertexZMC"), scaledFT0C, collision.posZ(), weight); + spectra.fill(HIST("hScaledFT0M_vertexZMC"), scaledFT0M, collision.posZ(), weight); + + spectra.fill(HIST("hScaledFT0C_Rho_Part"), scaledFT0C, rho, weight); + spectra.fill(HIST("hScaledFT0M_Rho_Part"), scaledFT0M, rho, weight); + + for (const auto& particle : particles) { + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle) + continue; + + float particlePt = particle.pt(); + float particlePhi = particle.phi(); + + // Need charge and physical primary particles + bool bParticleNeutral = (static_cast(pdgParticle->Charge()) == 0); + if (bParticleNeutral || !particle.isPhysicalPrimary()) + continue; + + spectra.fill(HIST("hScaledFT0CPartPtEtaPhi"), scaledFT0C, particlePt, particle.eta(), particlePhi, weight); + spectra.fill(HIST("hScaledFT0MPartPtEtaPhi"), scaledFT0M, particlePt, particle.eta(), particlePhi, weight); + + if (bSigEv && (particlePt > ptTTsig->at(0) && particlePt < ptTTsig->at(1))) { + vPhiOfTT.push_back(particlePhi); + ++nTT; + } + + if (!bSigEv && (particlePt > ptTTref->at(0) && particlePt < ptTTref->at(1))) { + vPhiOfTT.push_back(particlePhi); + ++nTT; + } + } + + if (nTT > 0) { + + phiTT = getPhiTT(vPhiOfTT); + + if (bSigEv) { + spectra.fill(HIST("hScaledFT0C_Ntrig_Part"), scaledFT0C, 1.5, weight); + spectra.fill(HIST("hScaledFT0M_Ntrig_Part"), scaledFT0M, 1.5, weight); + spectra.fill(HIST("hScaledFT0C_TTSig_per_event_Part"), scaledFT0C, nTT, weight); + spectra.fill(HIST("hScaledFT0M_TTSig_per_event_Part"), scaledFT0M, nTT, weight); + + spectra.fill(HIST("hScaledFT0C_TTSig_Part"), scaledFT0C, weight); + spectra.fill(HIST("hScaledFT0M_TTSig_Part"), scaledFT0M, weight); + + spectra.fill(HIST("hScaledFT0C_Rho_TTSig_Part"), scaledFT0C, rho, weight); + spectra.fill(HIST("hScaledFT0M_Rho_TTSig_Part"), scaledFT0M, rho, weight); + } else { + spectra.fill(HIST("hScaledFT0C_Ntrig_Part"), scaledFT0C, 0.5, weight); + spectra.fill(HIST("hScaledFT0M_Ntrig_Part"), scaledFT0M, 0.5, weight); + spectra.fill(HIST("hScaledFT0C_TTRef_per_event_Part"), scaledFT0C, nTT, weight); + spectra.fill(HIST("hScaledFT0M_TTRef_per_event_Part"), scaledFT0M, nTT, weight); + + spectra.fill(HIST("hScaledFT0C_TTRef_Part"), scaledFT0C, weight); + spectra.fill(HIST("hScaledFT0M_TTRef_Part"), scaledFT0M, weight); + + spectra.fill(HIST("hScaledFT0C_Rho_TTRef_Part"), scaledFT0C, rho, weight); + spectra.fill(HIST("hScaledFT0M_Rho_TTRef_Part"), scaledFT0M, rho, weight); + } + } + + for (const auto& jet : jets) { + float jetPt = jet.pt(); + float jetArea = jet.area(); + float jetPtCorr = jetPt - rho * jetArea; + + spectra.fill(HIST("hJetPtEtaPhiRhoArea_Part"), jetPt, jet.eta(), jet.phi(), rho, jetArea, weight); + + if (nTT > 0) { + + auto [dphi, bRecoilJet] = isRecoilJet(jet, phiTT); + + if (bSigEv) { + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_Corr_TTSig_Part"), scaledFT0C, dphi, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_Corr_TTSig_Part"), scaledFT0M, dphi, jetPtCorr, weight); + + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_TTSig_Part"), scaledFT0C, dphi, jetPt, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_TTSig_Part"), scaledFT0M, dphi, jetPt, weight); + + spectra.fill(HIST("hJetArea_JetPt_Rho_TTSig_Part"), jetArea, jetPt, rho, weight); + + if (phiTT > phiRestrTTSelection->at(0) && phiTT < phiRestrTTSelection->at(1)) { + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_Corr_TTSig_RectrictedPhi_Part"), scaledFT0C, dphi, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_Corr_TTSig_RectrictedPhi_Part"), scaledFT0M, dphi, jetPtCorr, weight); + } + + if (bRecoilJet) { + spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_Corr_TTSig_Part"), scaledFT0C, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_Corr_TTSig_Part"), scaledFT0M, jetPtCorr, weight); + + spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_TTSig_Part"), scaledFT0C, jetPt, weight); + spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_TTSig_Part"), scaledFT0M, jetPt, weight); + } + + } else { + + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_Corr_TTRef_Part"), scaledFT0C, dphi, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_Corr_TTRef_Part"), scaledFT0M, dphi, jetPtCorr, weight); + + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_TTRef_Part"), scaledFT0C, dphi, jetPt, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_TTRef_Part"), scaledFT0M, dphi, jetPt, weight); + + spectra.fill(HIST("hJetArea_JetPt_Rho_TTRef_Part"), jetArea, jetPt, rho, weight); + + if (phiTT > phiRestrTTSelection->at(0) && phiTT < phiRestrTTSelection->at(1)) { + spectra.fill(HIST("hScaledFT0C_DPhi_JetPt_Corr_TTRef_RectrictedPhi_Part"), scaledFT0C, dphi, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_DPhi_JetPt_Corr_TTRef_RectrictedPhi_Part"), scaledFT0M, dphi, jetPtCorr, weight); + } + + if (bRecoilJet) { + spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_Corr_TTRef_Part"), scaledFT0C, jetPtCorr, weight); + spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_Corr_TTRef_Part"), scaledFT0M, jetPtCorr, weight); + + spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_TTRef_Part"), scaledFT0C, jetPt, weight); + spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_TTRef_Part"), scaledFT0M, jetPt, weight); + } + } + } + } + } + + template + void fillMatchedHistograms(JTracksTable const& tracks, + JetsBase const& jetsBase, JetsTag const& jetsTag, + float weight = 1.) + { + std::vector vPhiOfTT; + double phiTTSig = 0.; + + for (const auto& track : tracks) { + if (skipTrack(track)) + continue; + + if (track.pt() > ptTTsig->at(0) && track.pt() < ptTTsig->at(1)) { + vPhiOfTT.push_back(track.phi()); + } + } + + bool bIsThereTTSig = vPhiOfTT.size() > 0; + + if (bIsThereTTSig) + phiTTSig = getPhiTT(vPhiOfTT); + + for (const auto& jetBase : jetsBase) { + bool bIsBaseJetRecoil = + get<1>(isRecoilJet(jetBase, phiTTSig)) && bIsThereTTSig; + dataForUnfolding(jetBase, jetsTag, bIsBaseJetRecoil, tracks, weight); + } + } + + template + void fillMultiplicityHistogramsOO(JCollision const& collision, + float weight = 1.) + { + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float multFT0M = collision.multFT0M(); + float scaledFT0A = getScaledFT0(multFT0A, meanFT0A); + float scaledFT0C = getScaledFT0(multFT0C, meanFT0C); + float scaledFT0M = getScaledFT0M(scaledFT0A, scaledFT0C); + + float multZNA = collision.multZNA(); + float multZNC = collision.multZNC(); + float multZNM = multZNA + multZNC; + + float multZPA = collision.multZPA(); + float multZPC = collision.multZPC(); + float multZPM = multZPA + multZPC; + + // Individual distributions + spectra.fill(HIST("hMultFT0A"), multFT0A, weight); + spectra.fill(HIST("hMultFT0C"), multFT0C, weight); + spectra.fill(HIST("hMultFT0M"), multFT0M, weight); + + spectra.fill(HIST("hScaleMultFT0A"), scaledFT0A, weight); + spectra.fill(HIST("hScaleMultFT0C"), scaledFT0C, weight); + spectra.fill(HIST("hScaleMultFT0M"), scaledFT0M, weight); + + spectra.fill(HIST("hMultZNA"), multZNA, weight); + spectra.fill(HIST("hMultZNC"), multZNC, weight); + spectra.fill(HIST("hMultZNM"), multZNM, weight); + + spectra.fill(HIST("hMultZPA"), multZPA, weight); + spectra.fill(HIST("hMultZPC"), multZPC, weight); + spectra.fill(HIST("hMultZPM"), multZPM, weight); + + // Correlations + spectra.fill(HIST("hZPA_vs_ZNA"), multZPA, multZNA, weight); + spectra.fill(HIST("hZPC_vs_ZNC"), multZPC, multZNC, weight); + + spectra.fill(HIST("hMultFT0A_vs_ZNA"), multFT0A, multZNA, weight); + spectra.fill(HIST("hMultFT0C_vs_ZNC"), multFT0C, multZNC, weight); + spectra.fill(HIST("hMultFT0M_vs_ZNM"), multFT0M, multZNM, weight); + + spectra.fill(HIST("hScaleMultFT0A_vs_ZNA"), scaledFT0A, multZNA, weight); + spectra.fill(HIST("hScaleMultFT0C_vs_ZNC"), scaledFT0C, multZNC, weight); + spectra.fill(HIST("hScaleMultFT0M_vs_ZNM"), scaledFT0M, multZNM, weight); + + spectra.fill(HIST("hScaleMultFT0A_vs_ZPA"), scaledFT0A, multZPA, weight); + spectra.fill(HIST("hScaleMultFT0C_vs_ZPC"), scaledFT0C, multZPC, weight); + spectra.fill(HIST("hScaleMultFT0M_vs_ZPM"), scaledFT0M, multZPM, weight); + + spectra.fill(HIST("hScaleMultFT0M_vs_ZNA_vs_ZNC"), scaledFT0M, multZNA, multZNC, weight); + spectra.fill(HIST("hScaleMultFT0M_vs_ZPA_vs_ZPC"), scaledFT0M, multZPA, multZPC, weight); + } + + template + void fillMultiplicityHistogramsPartLevelMC(JCollisionMC const& collision, + float weight = 1.) + { + spectra.fill(HIST("hMultFT0APartLevel"), collision.multFT0A(), weight); + spectra.fill(HIST("hMultFT0CPartLevel"), collision.multFT0C(), weight); + spectra.fill(HIST("hMultFT0MPartLevel"), collision.multFT0A() + collision.multFT0C(), weight); + + auto scaledFT0A = getScaledFT0(collision.multFT0A(), meanFT0APartLevel); + auto scaledFT0C = getScaledFT0(collision.multFT0C(), meanFT0CPartLevel); + spectra.fill(HIST("hScaleMultFT0APartLevel"), scaledFT0A, weight); + spectra.fill(HIST("hScaleMultFT0CPartLevel"), scaledFT0C, weight); + spectra.fill(HIST("hScaleMultFT0MPartLevel"), getScaledFT0M(scaledFT0A, scaledFT0C), weight); + } + + template + void fillMultiplicityQA(Collision const& collision, BC const&, + ZDC const&, float weight = 1.) + { + int runNumber = collision.multRunNumber(); + int fillNumber = getBinNumberOnYaxisForGivenRun(spectra.get(HIST("hScaledFT0CPerRunPerSetOfFlags")), runNumber) - 0.5; // Same for FT0M distrib. + + // FT0 Signal + float multFT0A = collision.multFT0A(); + float multFT0C = collision.multFT0C(); + float multFT0M = collision.multFT0M(); + float scaledFT0A = getScaledFT0(multFT0A, meanFT0A); + float scaledFT0C = getScaledFT0(multFT0C, meanFT0C); + float scaledFT0M = getScaledFT0M(scaledFT0A, scaledFT0C); + + // Event with flag Sel8 + spectra.fill(HIST("hFT0APerRunPerSetOfFlags"), multFT0A, fillNumber, 0.5, weight); + spectra.fill(HIST("hFT0CPerRunPerSetOfFlags"), multFT0C, fillNumber, 0.5, weight); + spectra.fill(HIST("hFT0MPerRunPerSetOfFlags"), multFT0M, fillNumber, 0.5, weight); + + spectra.fill(HIST("hScaledFT0APerRunPerSetOfFlags"), scaledFT0A, fillNumber, 0.5, weight); + spectra.fill(HIST("hScaledFT0CPerRunPerSetOfFlags"), scaledFT0C, fillNumber, 0.5, weight); + spectra.fill(HIST("hScaledFT0MPerRunPerSetOfFlags"), scaledFT0M, fillNumber, 0.5, weight); + + bool isGoodZvtxFT0vsPV = collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV); + if (isGoodZvtxFT0vsPV) { + spectra.fill(HIST("hFT0APerRunPerSetOfFlags"), multFT0A, fillNumber, 1.5, weight); + spectra.fill(HIST("hFT0CPerRunPerSetOfFlags"), multFT0C, fillNumber, 1.5, weight); + spectra.fill(HIST("hFT0MPerRunPerSetOfFlags"), multFT0M, fillNumber, 1.5, weight); + + spectra.fill(HIST("hScaledFT0APerRunPerSetOfFlags"), scaledFT0A, fillNumber, 1.5, weight); + spectra.fill(HIST("hScaledFT0CPerRunPerSetOfFlags"), scaledFT0C, fillNumber, 1.5, weight); + spectra.fill(HIST("hScaledFT0MPerRunPerSetOfFlags"), scaledFT0M, fillNumber, 1.5, weight); + } + + bool isNoSameBunchPileup = collision.selection_bit(aod::evsel::kNoSameBunchPileup); + if (isNoSameBunchPileup) { + spectra.fill(HIST("hFT0APerRunPerSetOfFlags"), multFT0A, fillNumber, 2.5, weight); + spectra.fill(HIST("hFT0CPerRunPerSetOfFlags"), multFT0C, fillNumber, 2.5, weight); + spectra.fill(HIST("hFT0MPerRunPerSetOfFlags"), multFT0M, fillNumber, 2.5, weight); + + spectra.fill(HIST("hScaledFT0APerRunPerSetOfFlags"), scaledFT0A, fillNumber, 2.5, weight); + spectra.fill(HIST("hScaledFT0CPerRunPerSetOfFlags"), scaledFT0C, fillNumber, 2.5, weight); + spectra.fill(HIST("hScaledFT0MPerRunPerSetOfFlags"), scaledFT0M, fillNumber, 2.5, weight); + } + + if (isGoodZvtxFT0vsPV && isNoSameBunchPileup) { + spectra.fill(HIST("hFT0APerRunPerSetOfFlags"), multFT0A, fillNumber, 3.5, weight); + spectra.fill(HIST("hFT0CPerRunPerSetOfFlags"), multFT0C, fillNumber, 3.5, weight); + spectra.fill(HIST("hFT0MPerRunPerSetOfFlags"), multFT0M, fillNumber, 3.5, weight); + + spectra.fill(HIST("hScaledFT0APerRunPerSetOfFlags"), scaledFT0A, fillNumber, 3.5, weight); + spectra.fill(HIST("hScaledFT0CPerRunPerSetOfFlags"), scaledFT0C, fillNumber, 3.5, weight); + spectra.fill(HIST("hScaledFT0MPerRunPerSetOfFlags"), scaledFT0M, fillNumber, 3.5, weight); + } else { + return; + } + + // Investigate other EA variables + //____________________________________________________________________________________ + + // Multiplicity equalized for the vertex position with FT0 detector + float multZeqFT0A = collision.multZeqFT0A(); + float multZeqFT0C = collision.multZeqFT0C(); + float multZeqFT0M = multZeqFT0A + multZeqFT0C; + float scaledZeqFT0A = getScaledFT0(multZeqFT0A, meanZeqFT0A); + float scaledZeqFT0C = getScaledFT0(multZeqFT0C, meanZeqFT0C); + float scaledZeqFT0M = getScaledFT0M(scaledZeqFT0A, scaledZeqFT0C); + + spectra.fill(HIST("hMultZeqFT0A"), multZeqFT0A, weight); + spectra.fill(HIST("hMultZeqFT0C"), multZeqFT0C, weight); + spectra.fill(HIST("hMultZeqFT0M"), multZeqFT0M, weight); + spectra.fill(HIST("hScaledZeqFT0A"), scaledZeqFT0A, weight); + spectra.fill(HIST("hScaledZeqFT0C"), scaledZeqFT0C, weight); + spectra.fill(HIST("hScaledZeqFT0M"), scaledZeqFT0M, weight); + + // ZDC timing info + auto const& foundBC = collision.template foundBC_as(); + float timeZNA = foundBC.has_zdc() ? foundBC.zdc().timeZNA() : -999.f; + float timeZNC = foundBC.has_zdc() ? foundBC.zdc().timeZNC() : -999.f; + float timeDiffZDC = timeZNA - timeZNC; + float timeSumZDC = timeZNA + timeZNC; + + spectra.fill(HIST("hTimeCorrZnaZnc"), timeDiffZDC, timeSumZDC, weight); + spectra.fill(HIST("hTimeZnaVsZncVsFT0C"), timeZNA, timeZNC, scaledFT0C, weight); + spectra.fill(HIST("hTimeZnaVsZncVsFT0M"), timeZNA, timeZNC, scaledFT0M, weight); + + // ITS only tracks + int nITSonly = collision.multNTracksITSOnly(); + + spectra.fill(HIST("hScaledFT0C_ITStracks"), scaledFT0C, nITSonly, weight); + spectra.fill(HIST("hScaledFT0M_ITStracks"), scaledFT0M, nITSonly, weight); + + // Global tracks from PV within |eta| < 0.8 + int multNContribs = collision.multNTracksPV(); + + spectra.fill(HIST("hScaledFT0C_TracksPV"), scaledFT0C, multNContribs, weight); + spectra.fill(HIST("hScaledFT0M_TracksPV"), scaledFT0M, multNContribs, weight); + + if (foundBC.foundFT0Id() > 0) // -1 if does not + { + spectra.fill(HIST("hIsFT0SignalComeFromCollPerRun"), 0.5, fillNumber, weight); + } else { + spectra.fill(HIST("hIsFT0SignalComeFromCollPerRun"), 1.5, fillNumber, weight); + spectra.fill(HIST("hFT0AsignalWithoutBC"), multFT0A, fillNumber, weight); + spectra.fill(HIST("hFT0CsignalWithoutBC"), multFT0C, fillNumber, weight); + spectra.fill(HIST("hFT0MsignalWithoutBC"), multFT0M, fillNumber, weight); + } + + if (collision.foundBCId() > 0) + spectra.fill(HIST("hIsFT0SignalComeFromCollPerRun"), 2.5, fillNumber, weight); + else + spectra.fill(HIST("hIsFT0SignalComeFromCollPerRun"), 3.5, fillNumber, weight); + } + + template + void fillLeadingAndAssociatedTracksTask(JCollision const& collision, JTracks const& tracks, float weight = 1.) + { + std::vector vPhiOfLeadingTracks; + std::vector vPhiOfAssociatedTracks; + + float scaledFT0C = getScaledFT0(collision.multFT0C(), meanFT0C); + float scaledFT0M = getScaledFT0M(getScaledFT0(collision.multFT0A(), meanFT0A), scaledFT0C); + + for (const auto& track : tracks) { + if (skipTrack(track)) + continue; + + float trackPt = track.pt(); + float trackPhi = track.phi(); + + // Search for leading tracks + if (trackPt > pTLeadTrack->at(0) && trackPt < pTLeadTrack->at(1)) { + vPhiOfLeadingTracks.push_back(trackPhi); + } + + // Search for associated tracks + if (trackPt > pTAssociatTrack->at(0) && trackPt < pTAssociatTrack->at(1)) { + vPhiOfAssociatedTracks.push_back(trackPhi); + } + } + + int nLeadingTracks = vPhiOfLeadingTracks.size(); + + if (nLeadingTracks > 0) { + double phiLeadingTrack = getPhiTT(vPhiOfLeadingTracks); + + for (const auto& phiAssociatTrack : vPhiOfAssociatedTracks) { + double dphi = RecoDecay::constrainAngle(phiLeadingTrack - phiAssociatTrack, -1.3); + spectra.fill(HIST("hScaledFT0C_Correlation_LeadTrack_AssociatTracks"), scaledFT0C, dphi, weight); + spectra.fill(HIST("hScaledFT0M_Correlation_LeadTrack_AssociatTracks"), scaledFT0M, dphi, weight); + } + } + } + + //------------------------------------------------------------------------------ + // Process functions + void processData(FilteredColl const& collision, FilteredTracks const& tracks, + FilteredJets const& jets) + { + spectra.fill(HIST("hEventSelectionCount"), 0.5); + + if (skipEvent(collision)) + return; + + spectra.fill(HIST("hEventSelectionCount"), 1.5); // number of events selected for analysis + + fillHistograms(collision, jets, tracks); + } + PROCESS_SWITCH(RecoilJets, processData, "process raw data", true); + + void processMCDetLevel(FilteredColl const& collision, + FilteredTracks const& tracks, + FilteredJetsDetLevel const& jets) + { + spectra.fill(HIST("hEventSelectionCount"), 0.5); + if (skipEvent(collision)) + return; + + spectra.fill(HIST("hEventSelectionCount"), 1.5); + + if (skipMBGapEvent(collision)) { + spectra.fill(HIST("hEventSelectionCount"), 2.5); + return; + } + + spectra.fill(HIST("hEventSelectionCount"), 5.5); // number of events selected for analysis + fillHistograms(collision, jets, tracks); + } + PROCESS_SWITCH(RecoilJets, processMCDetLevel, "process MC detector level data (no weight)", false); + + void processMCDetLevelWeighted(FilteredCollDetLevelGetWeight const& collision, + aod::JetMcCollisions const&, + FilteredTracks const& tracks, + FilteredJetsDetLevel const& jets) + { + spectra.fill(HIST("hEventSelectionCount"), 0.5); + if (skipEvent(collision)) + return; + + spectra.fill(HIST("hEventSelectionCount"), 1.5); + + if (skipMBGapEvent(collision)) { + spectra.fill(HIST("hEventSelectionCount"), 2.5); + return; + } + + if (collision.isOutlier()) { + spectra.fill(HIST("hEventSelectionCount"), 3.5); + return; + } + + if (!collision.has_mcCollision()) { + spectra.fill(HIST("hEventSelectionCount"), 4.5); + return; + } + + spectra.fill(HIST("hEventSelectionCount"), 5.5); // number of events selected for analysis + auto weight = collision.mcCollision().weight(); + fillHistograms(collision, jets, tracks, weight); + } + PROCESS_SWITCH(RecoilJets, processMCDetLevelWeighted, "process MC detector level data (weighted)", false); + + void processMCPartLevel(FilteredCollPartLevel const& collision, + FilteredParticles const& particles, + FilteredJetsPartLevel const& jets) + { + spectra.fill(HIST("hEventSelectionCountPartLevel"), 0.5); + + if (skipMBGapEvent(collision)) { + spectra.fill(HIST("hEventSelectionCountPartLevel"), 1.5); + return; + } + + spectra.fill(HIST("hEventSelectionCountPartLevel"), 3.5); // number of events selected for analysis + fillMCPHistograms(collision, jets, particles); + } + PROCESS_SWITCH(RecoilJets, processMCPartLevel, "process MC particle level data (no weight)", false); + + void processMCPartLevelWeighted(FilteredCollPartLevel const& collision, + FilteredParticles const& particles, + FilteredJetsPartLevel const& jets) + { + spectra.fill(HIST("hEventSelectionCountPartLevel"), 0.5); + + if (skipMBGapEvent(collision)) { + spectra.fill(HIST("hEventSelectionCountPartLevel"), 1.5); + return; + } + + if (collision.isOutlier()) { + spectra.fill(HIST("hEventSelectionCountPartLevel"), 2.5); + return; + } + + spectra.fill(HIST("hEventSelectionCountPartLevel"), 3.5); // number of events selected for analysis + + auto weight = collision.weight(); + spectra.fill(HIST("ptHat"), collision.ptHard(), weight); + fillMCPHistograms(collision, jets, particles, weight); + } + PROCESS_SWITCH(RecoilJets, processMCPartLevelWeighted, "process MC particle level data (weighted)", false); + + void processJetsMatched(FilteredCollDetLevelGetWeight const& collision, + aod::JetMcCollisions const&, + FilteredTracks const& tracks, + FilteredMatchedJetsDetLevel const& mcdjets, + FilteredMatchedJetsPartLevel const& mcpjets) + { + if (skipEvent(collision) || skipMBGapEvent(collision) || collision.isOutlier()) + return; + + auto mcpjetsPerMCCollision = mcpjets.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + + fillMatchedHistograms(tracks, mcpjetsPerMCCollision, mcdjets); + } + 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) || collision.isOutlier()) + return; + + auto mcpjetsPerMCCollision = mcpjets.sliceBy(partJetsPerCollision, collision.mcCollisionId()); + auto weight = collision.mcCollision().weight(); + + fillMatchedHistograms(tracks, mcpjetsPerMCCollision, mcdjets, weight); + } + PROCESS_SWITCH(RecoilJets, processJetsMatchedWeighted, "process matching of MC jets (weighted)", false); + + void processMultiplicityOO(FilteredEventMultiplicity const& collision) + { + if (skipEvent(collision)) + return; + + fillMultiplicityHistogramsOO(collision); + } + PROCESS_SWITCH(RecoilJets, processMultiplicityOO, "process multiplicity for OO collisions and MC detector level (no weight)", false); + + void processMultiplicityMCDetLevelWeightedOO(FilteredEventMultiplicityDetLevelGetWeight const& collision) + { + if (skipEvent(collision) || collision.isOutlier() || !collision.has_mcCollision()) + return; + + auto weight = collision.mcCollision().weight(); + fillMultiplicityHistogramsOO(collision, weight); + } + PROCESS_SWITCH(RecoilJets, processMultiplicityMCDetLevelWeightedOO, "process multiplicity for MC detector level OO collisions (weighted)", false); + + void processMultiplicityPartLevelMC(FilteredEventMultiplicityPartLevel const& collision) + { + if (skipMBGapEvent(collision)) + return; + + fillMultiplicityHistogramsPartLevelMC(collision); + } + PROCESS_SWITCH(RecoilJets, processMultiplicityPartLevelMC, "process multiplicity for MC particle level events (no weight)", false); + + void processMultiplicityPartLevelMCWeighted(FilteredEventMultiplicityPartLevel const& collision) + { + if (skipMBGapEvent(collision) || collision.isOutlier()) + return; + + auto weight = collision.weight(); + fillMultiplicityHistogramsPartLevelMC(collision, weight); + } + PROCESS_SWITCH(RecoilJets, processMultiplicityPartLevelMCWeighted, "process multiplicity for MC particle level events (weighted)", false); + + void processMultiplicityQA(ColEvSelEA const& collision, + BCsRun3 const& BCs, + aod::Zdcs const& ZDCs) + { + // Base flag for event selection + if (!collision.sel8()) + return; + + fillMultiplicityQA(collision, BCs, ZDCs); + } + PROCESS_SWITCH(RecoilJets, processMultiplicityQA, "process function for EA QA purposes", false); + + void processLeadingAndAssociatedTracksTask(soa::Filtered::iterator const& collision, + soa::Filtered const& tracks) + { + if (skipEvent(collision)) + return; + fillLeadingAndAssociatedTracksTask(collision, tracks); + } + PROCESS_SWITCH(RecoilJets, processLeadingAndAssociatedTracksTask, "process function for correlation between leading and associated tracks", 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 getScaledFT0(const float& multFT0, const float& meanFT0) + { + return multFT0 / meanFT0; + } + + float getScaledFT0M(const float& scaledMultFT0A, const float& scaledMultFT0C) + { + return 0.5 * (scaledMultFT0A + scaledMultFT0C); + } + + template + bool isJetWithHighPtConstituent(Jet const& jet, Tracks const&) + { + bool bIsJetWithHighPtConstituent = false; + for (const auto& jetConstituent : jet.template tracks_as()) { + if (jetConstituent.pt() > maxJetConstituentPt) { + bIsJetWithHighPtConstituent = true; + break; + } + } + return bIsJetWithHighPtConstituent; + } + + template + int getBinNumberOnYaxisForGivenRun(std::shared_ptr histogram, int runNumber) + { + int nBins = histogram->GetYaxis()->GetNbins(); + int binNumber = -1; + + for (int iBin = 1; iBin <= nBins; ++iBin) { + const char* binLabel = histogram->GetYaxis()->GetBinLabel(iBin); + if (std::stoi(binLabel) == runNumber) { + binNumber = iBin; + break; + } + } + + if (binNumber == -1) // No bin found + return 0; + + return binNumber; + } + + template + void dataForUnfolding(PartJet const& partJet, DetJet const& detJets, + bool bIsBaseJetRecoil, TracksTable const& tracks, float weight = 1.) + { + + float partJetPt = partJet.pt(); + bool bIsThereMatchedJet = partJet.has_matchedJetGeo(); + + if (bIsThereMatchedJet) { + const auto& jetsMatched = partJet.template matchedJetGeo_as>(); + + for (const auto& jetMatched : jetsMatched) { + + // skip matches where detector level jets have a constituent with pT above specified cut + bool skipMatchedDetJet = isJetWithHighPtConstituent(jetMatched, tracks); + + if (skipMatchedDetJet) { + // Miss jets + spectra.fill(HIST("hMissedJets_pT"), partJetPt, weight); + if (bIsBaseJetRecoil) + spectra.fill(HIST("hMissedJets_pT_RecoilJets"), partJetPt, weight); + } else { + float detJetPt = jetMatched.pt(); + + spectra.fill(HIST("hNumberMatchedJetsPerOneBaseJet"), jetsMatched.size(), detJetPt, weight); + spectra.fill(HIST("hJetPt_DetLevel_vs_PartLevel"), detJetPt, partJetPt, weight); + spectra.fill(HIST("hJetPt_resolution"), (partJetPt - detJetPt) / partJetPt, partJetPt, weight); + spectra.fill(HIST("hJetPhi_resolution"), partJet.phi() - jetMatched.phi(), partJetPt, weight); + + if (bIsBaseJetRecoil) { + spectra.fill(HIST("hJetPt_DetLevel_vs_PartLevel_RecoilJets"), detJetPt, partJetPt, weight); + spectra.fill(HIST("hJetPt_resolution_RecoilJets"), (partJetPt - detJetPt) / partJetPt, partJetPt, weight); + spectra.fill(HIST("hJetPhi_resolution_RecoilJets"), partJet.phi() - jetMatched.phi(), partJetPt, weight); + } + } + } + } else { + // Miss jets + spectra.fill(HIST("hMissedJets_pT"), partJetPt, weight); + if (bIsBaseJetRecoil) + spectra.fill(HIST("hMissedJets_pT_RecoilJets"), partJetPt, weight); + } + + // Fake jets + for (const auto& detJet : detJets) { + if (isJetWithHighPtConstituent(detJet, tracks)) + continue; + + bIsThereMatchedJet = detJet.has_matchedJetGeo(); + if (!bIsThereMatchedJet) { + spectra.fill(HIST("hFakeJets_pT"), detJet.pt(), weight); + if (bIsBaseJetRecoil) + spectra.fill(HIST("hFakeJets_pT_RecoilJets"), detJet.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..ebf50c2ad9d --- /dev/null +++ b/PWGJE/Tasks/statPromptPhoton.cxx @@ -0,0 +1,1372 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGJE/Core/FastJetUtilities.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/EMCALClusters.h" +#include "PWGJE/DataModel/Jet.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/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsEMCAL/AnalysisCluster.h" +#include "DataFormatsEMCAL/Cell.h" +#include "DataFormatsEMCAL/Constants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/Propagator.h" +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/BadChannelMap.h" +#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 + +#include +#include + +#include +#include +#include +#include + +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 cfgTriggerMasks{"cfgTriggerMasks", "", "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 cfgDebug{"cfgDebug", false, "Enables debug information for local running"}; + + int trackFilter = -1; + std::vector triggerMaskBits; + + // 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]"}; + + triggerMaskBits = jetderiveddatautilities::initialiseTriggerMaskBits(cfgTriggerMasks); + 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 jselectedDataCollisions = soa::Join; + // using jselectedDataCollisions = soa::Join; + using jfilteredCollisions = soa::Filtered; + using jfilteredDataCollisions = 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, aod::JetMcCollisions const&) + { + + 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); + + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + + histos.fill(HIST("REC_nEvents"), 3.5); + + double weight = 1; + if (collision.has_mcCollision()) { + weight = collision.mcCollision().weight(); + } + + 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, weight); + histos.fill(HIST("REC_PtHadSum_Photon"), pthadsum, weight); + histos.fill(HIST("REC_Trigger_Energy"), mccluster.energy(), weight); + } + + auto ClusterParticles = mccluster.mcParticles_as(); + + // now we check the realness of our prompt photons + bool goodgentrigger = true; + double chPe = 0; + for (auto& clusterparticle : ClusterParticles) { + 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()); + 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()); + 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(), weight); + 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, weight); + } + } // 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 + + // 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; + } + + phiPrime = phiPrime + TMath::Pi() / 18.; + phiPrime = fmod(phiPrime, 2 * TMath::Pi() / 18.); + histos.fill(HIST("REC_Track_PhiPrime_Pt"), phiPrime, track.pt()); + 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, weight); + if (sterntrigger) { + bool doStern = true; + double sterncount = 1.0; + while (doStern) { + histos.fill(HIST("REC_Trigger_V_PtHadSum_Stern"), sterncount, pthadsum, (2.0 / sternPt) * weight); + 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(jfilteredDataCollisions::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; + std::cout << "Events Trigger Bit: " << collision.triggerSel() << std::endl; + std::cout << "Trigger Mask Bit: " << triggerMaskBits[0] << std::endl; + std::cout << "Trigger Mask Cfg Line: " << cfgTriggerMasks << 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); + + if (!jetderiveddatautilities::selectTrigger(collision, triggerMaskBits)) { + return; + } + + histos.fill(HIST("DATA_nEvents"), 3.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; + } + + 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/taskEmcExtensiveMcQa.cxx b/PWGJE/Tasks/taskEmcExtensiveMcQa.cxx new file mode 100644 index 00000000000..f9845724101 --- /dev/null +++ b/PWGJE/Tasks/taskEmcExtensiveMcQa.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. + +/// \file taskEmcExtensiveMcQa.cxx +/// \brief Exensive monitoring task for EMCal clusters in MC +/// \author Marvin Hemmer , Goethe University Frankfurt +/// \since 31.07.2025 + +#include "PWGJE/DataModel/EMCALClusters.h" +// HF headers for event selection +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants; +using namespace o2::hf_evsel; +using namespace o2::hf_centrality; +using CollisionEvSels = o2::soa::Join; +using BcEvSelIt = o2::soa::Join::iterator; +using SelectedClusters = o2::soa::Filtered>; + +namespace poi +{ +enum PoI { + kPhoton = 0, + kElectronPrim = 1, + kElectronSec = 2, + kMuon = 3, + kHadronCharge = 4, + kHadronNeutral = 5, + kNPoI = 6 +}; +} // namespace poi + +/// \struct TaskEmcExtensiveMcQa +struct TaskEmcExtensiveMcQa { + + static constexpr int NSM = 20; // there 20 supermodlues for the EMCal + std::array arrPDGHadronNeutral = {kNeutron, kK0Short, kK0Long, kLambda0, physics::kXi0, kSigma0}; + + SliceCache cache; + Preslice psClusterPerCollision = o2::aod::emcalcluster::collisionId; + Preslice perCluster = o2::aod::emcalclustercell::emcalclusterId; + + HistogramRegistry mHistManager{"EMCalExtensiveMCQAHistograms"}; + + o2::emcal::Geometry* mGeometry = nullptr; + o2::framework::Service ccdb; + + o2::ctpRateFetcher rateFetcher; + HfEventSelection hfEvSel; + HfEventSelectionMc hfEvSelMc; + + // configurable parameters + Configurable applyEvSels{"applyEvSels", true, "Flag to apply event selection."}; + Configurable clusterDefinition{"clusterDefinition", 10, "cluster definition to be selected, e.g. 10=kV3Default"}; + Configurable ctpFetcherSource{"ctpFetcherSource", "T0VTX", "Source for CTP rate fetching, e.g. T0VTX, T0CE, T0SC, ZNC (hadronic)"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // configurable axis + ConfigurableAxis nClustersBinning{"nClustersBinning", {201, -0.5, 200.5}, "binning for the number of clusters"}; + + ConfigurableAxis clusterEnergy{"clusterEnergy", {100, 0., 10}, "binning for the cluster energy in GeV"}; + ConfigurableAxis clusterM02{"clusterM02", {100, 0., 2.0}, "binning for the cluster M02"}; + ConfigurableAxis clusterM20{"clusterM20", {100, 0., 2.0}, "binning for the cluster M20"}; + ConfigurableAxis clusterNCellBinning{"clusterNCellBinning", {100, 0.5, 100.5}, "binning for the number of cells per cluster"}; + ConfigurableAxis clusterOriginRadius{"clusterOriginRadius", {225, 0., 450}, "binning for the radial original point of the main contributor of a cluster"}; + ConfigurableAxis clusterNContributor{"clusterNContributor", {20, 0.5, 20.5}, "binning for the number of contributor of a cluster"}; + ConfigurableAxis clusterEnergyRatio{"clusterEnergyRatio", {100, 0., 10.}, "binning for ratio of the deposited energy of the leading particle to its generated momentum cluster"}; + ConfigurableAxis collisionCent{"collisionCent", {10, 0., 100.}, "binning for the event centrality"}; + ConfigurableAxis clusterEtaReso{"clusterEtaReso", {100, -0.1, 0.1}, "binning for cluster position resolution in eta"}; + ConfigurableAxis clusterPhiReso{"clusterPhiReso", {100, -0.1, 0.1}, "binning for cluster position resolution in phi"}; + + std::vector mCellTime; + + /// \brief Create output histograms and initialize geometry + void init(InitContext const&) + { + // load geometry just in case we need it + mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + + // create common axes + const AxisSpec numberClustersAxis{nClustersBinning, "#it{N}_{cl}/ #it{N}_{event}"}; + const AxisSpec axisParticle = {poi::kNPoI, -0.5f, +poi::kNPoI - 0.5f, ""}; + const AxisSpec axisEnergy{clusterEnergy, "#it{E}_{cl} (GeV)"}; + const AxisSpec axisM02{clusterM02, "#it{M}_{02}"}; + const AxisSpec axisM20{clusterM20, "#it{M}_{20}"}; + const AxisSpec axisNCell{clusterNCellBinning, "#it{N}_{cells}"}; + const AxisSpec axisRadius{clusterOriginRadius, "#it{R}_{origin} (cm)"}; + const AxisSpec axisNContributor{clusterNContributor, "#it{N}_{particles}"}; + const AxisSpec axisCent{collisionCent, "cent (%)"}; + const AxisSpec axisLeadingEnergy{clusterEnergy, "#it{E}_{lead} (GeV)"}; + const AxisSpec axisLeadingGenMomentum{clusterEnergy, "#it{p}_{lead, gen} (GeV/#it{c})"}; + const AxisSpec axisLeadingRatio{clusterEnergy, "#it{E}_{lead}/#it{p}_{lead, gen} (#it{c})"}; + const AxisSpec axisEtaReso{clusterEtaReso, "#Delta#eta"}; + const AxisSpec axisPhiReso{clusterPhiReso, "#Delta#varphi (rad)"}; + + const AxisSpec axisSM{{20, -0.5, 19.5}, "SM"}; + + // create histograms + + // event properties + mHistManager.add("numberOfClustersEvents", "number of clusters per event (selected events)", HistType::kTH1D, {numberClustersAxis}); + + // cluster properties (matched clusters) + mHistManager.add("hSparseClusterQA", "THnSparse for Cluster QA", HistType::kTHnSparseF, {axisEnergy, axisM02, axisM20, axisNCell, axisRadius, axisParticle, axisNContributor, axisCent}); + mHistManager.add("hSparseClusterContributors", "THnSparse with cluster contributors and energies", HistType::kTHnSparseF, {axisEnergy, axisParticle, axisNContributor, axisLeadingEnergy, axisLeadingGenMomentum, axisLeadingRatio, axisCent}); + mHistManager.add("clusterEtaPhi", "Eta and phi of cluster", HistType::kTH2F, {{140, -0.7, 0.7}, {360, 0, o2::constants::math::TwoPI}}); + + mHistManager.add("hSparsePosReso", "THnSparse for cluster position resolution", HistType::kTHnSparseF, {axisEnergy, axisEtaReso, axisPhiReso, axisNCell, axisSM, axisParticle, axisNContributor, axisCent}); + + hfEvSel.addHistograms(mHistManager); + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + } + + template + bool isCollSelected(const Coll& coll, float& cent) + { + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(coll, cent, ccdb, mHistManager); + /// monitor the satisfied event selections + hfEvSel.fillHistograms(coll, rejectionMask, cent); + return rejectionMask == 0; + } + + /// \brief returns the PoI type of a mcparticle + /// \param mcparticle is the mcparticle we want to find the PoI type + /// \param mcparticles table containing the mcparticles + /// \return PoI type of the given mcparticle + template + int findPoIType(T const& mcparticle) + { + auto pdgValue = std::abs(mcparticle.pdgCode()); + switch (pdgValue) { + case kGamma: { + return poi::kPhoton; + } + case kElectron: { + if (mcparticle.isPhysicalPrimary()) { + return poi::kElectronPrim; + } else { + return poi::kElectronSec; + } + } + case kMuonMinus: { + return poi::kMuon; + } + default: { + auto it = std::find(arrPDGHadronNeutral.begin(), arrPDGHadronNeutral.end(), pdgValue); + if (it != arrPDGHadronNeutral.end()) { + return poi::kHadronNeutral; + } + return poi::kHadronCharge; + } + } + } + + Filter clusterDefinitionSelection = (o2::aod::emcalcluster::definition == clusterDefinition); + + /// \brief Process EMCAL clusters that are matched to a collisions + void processCollisions(CollisionEvSels const& collisions, SelectedClusters const& clusters, McParticles const& /*mcparticles*/) + { + + for (const auto& collision : collisions) { + float cent = -1.f; + if (applyEvSels && !isCollSelected(collision, cent)) { + continue; + } + + auto groupedClusters = clusters.sliceBy(psClusterPerCollision, collision.globalIndex()); + mHistManager.fill(HIST("numberOfClustersEvents"), groupedClusters.size()); + + for (const auto& cluster : groupedClusters) { + mHistManager.fill(HIST("clusterEtaPhi"), cluster.eta(), cluster.phi()); + // axisEnergy, axisTime, axisM02, axisNCell, axisRadius, axisParticle + if (cluster.mcParticle().size() == 0) { + LOG(info) << "Somehow cluster.mcParticle().size() == 0!"; + continue; + } + auto mainMcParticle = cluster.mcParticle_as()[0]; + float radius = std::hypot(mainMcParticle.vx(), mainMcParticle.vy()); + float momentum = mainMcParticle.p(); + float leadingEnergy = cluster.energy() * cluster.amplitudeA()[0]; + float leadingFraction = leadingEnergy / momentum; + float dEta = cluster.eta() - mainMcParticle.eta(); + float dPhi = cluster.phi() - mainMcParticle.phi(); + int iSM = mGeometry->SuperModuleNumberFromEtaPhi(cluster.eta(), cluster.phi()); + mHistManager.fill(HIST("hSparseClusterQA"), cluster.energy(), cluster.m02(), cluster.m20(), cluster.nCells(), radius, findPoIType(mainMcParticle), cluster.mcParticle().size(), cent); + mHistManager.fill(HIST("hSparseClusterContributors"), cluster.energy(), findPoIType(mainMcParticle), cluster.mcParticle().size(), leadingEnergy, momentum, leadingFraction, cent); + mHistManager.fill(HIST("hSparsePosReso"), cluster.energy(), dEta, dPhi, cluster.nCells(), iSM, findPoIType(mainMcParticle), cluster.mcParticle().size(), cent); + } + } + } + PROCESS_SWITCH(TaskEmcExtensiveMcQa, processCollisions, "Process clusters from collision", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{ + adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGJE/Tasks/trackEfficiency.cxx b/PWGJE/Tasks/trackEfficiency.cxx index 9b869da6557..5ca8c4816d4 100644 --- a/PWGJE/Tasks/trackEfficiency.cxx +++ b/PWGJE/Tasks/trackEfficiency.cxx @@ -9,101 +9,227 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// track efficiency task (global tracks) -// +/// \file trackEfficiency.cxx /// \author Aimeric Landou +/// \brief task that creates the histograms necessary for computation of efficiency and purity functions in offline postprocess macros; also can make mcparticle and track QC histograms -#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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include +#include +#include +#include +#include +#include -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetFindingUtilities.h" -#include "PWGJE/DataModel/Jet.h" +#include -#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -struct TrackEfficiencyJets { +struct TrackEfficiency { Service pdg; - using JetParticlesWithOriginal = soa::Join; + 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 cutCentrality{"cutCentrality", false, ""}; + Configurable checkCentFT0M{"checkCentFT0M", false, "0: centFT0C as default, 1: use centFT0M estimator"}; + Configurable checkOccupancy{"checkOccupancy", false, "check occupancy only in general purpose Pb-Pb MC, default as 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{"trackEtaMin", -0.9, "minimum eta acceptance for tracks in the processTracks QA"}; - Configurable trackQAEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks in the processTracks QA"}; - Configurable trackQAPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks in the processTracks QA"}; - Configurable trackQAPtMax{"trackPtMax", 100.0, "maximum pT acceptance for tracks in the processTracks QA"}; - - int eventSelection = -1; + 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., 100}, "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"}; + Configurable phiEffNBins{"phiEffNBins", 200, "number of bins for phi axis in efficiency plots"}; + Configurable etaEffNBins{"etaEffNBins", 200, "number of bins for eta axis in efficiency plots"}; + + Configurable ptHatMin{"ptHatMin", 5, "min pT hat of collisions"}; + Configurable ptHatMax{"ptHatMax", 300, "max pT hat of collisions"}; + Configurable pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"}; + Configurable pTHatMaxFractionMCD{"pTHatMaxFractionMCD", 999.0, "maximum fraction of hard scattering for reconstructed track acceptance in MC"}; + + Configurable getPtHatFromHepMCXSection{"getPtHatFromHepMCXSection", true, "test configurable, configurable should be removed once well tested"}; + Configurable useTrueTrackWeight{"useTrueTrackWeight", true, "test configurable, should be set to 1 then config removed once well tested"}; + + // systematics variation - Run 2 guidelines: https://twiki.cern.ch/twiki/bin/view/ALICE/AliDPGtoolsTrackSystematicUncertainty + TrackSelection customTrackSelection; + Configurable useCustomTrackSelection{"useCustomTrackSelection", false, "whether to use the custom cuts (used for cut variation for tracking efficiency systematics)"}; + Configurable effSystMinNCrossedRowsTPC{"effSystMinNCrossedRowsTPC", 70, "min number of crossed rows TPC"}; + Configurable effSystMinNCrossedRowsOverFindableClustersTPC{"effSystMinNCrossedRowsOverFindableClustersTPC", 0.8, "min ratio of crossed rows over findable clusters TPC"}; + Configurable effSystMaxChi2PerClusterTPC{"effSystMaxChi2PerClusterTPC", 4.0, "max chi2 per cluster TPC"}; + Configurable effSystMaxChi2PerClusterITS{"effSystMaxChi2PerClusterITS", 36.0, "max chi2 per cluster ITS"}; + // Configurable effSystMaxDcaXY{"effSystMaxDcaXY", 0.0105 * 0.035 / pT^1.1 ????, "max DCA to vertex xy"}; not including this for now as it's a function with 3 parameters + Configurable effSystMaxDcaZ{"effSystMaxDcaZ", 2.0, "max DCA to vertex z"}; + Configurable effSystMinNrequiredHits{"effSystMinNrequiredHits", 1, "minimum number of hits among the 3 innermost layers of the ITS"}; + + std::vector eventSelectionBits; int trackSelection = -1; + float simPtRef = 10.; + + enum AcceptSplitCollisionsOptions { + NonSplitOnly = 0, + SplitOkCheckAnyAssocColl, // 1 + SplitOkCheckFirstAssocCollOnly // 2 + }; + + template + bool isAcceptedTrack(TJetTrack const& jetTrack) + { + if (!useCustomTrackSelection) { + if (jetderiveddatautilities::selectTrack(jetTrack, trackSelection) && jetderiveddatautilities::selectTrackDcaZ(jetTrack, 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 + return true; + } + } else { + const auto& aodTrack = jetTrack.template track_as>(); + if (customTrackSelection.IsSelected(aodTrack)) { + return true; + } + } + return false; + } bool isChargedParticle(int code) { + const float chargeUnit = 3.; auto p = pdg->GetParticle(code); auto charge = 0.; if (p != nullptr) { charge = p->Charge(); } - return std::abs(charge) >= 3.; + return std::abs(charge) >= chargeUnit; } - template - void fillTrackHistograms(T const& collision, U const& tracks, float weight = 1.0) + template + void fillTrackHistograms(TCollision const& collision, TJetTracks const& jetTracks, float weight = 1.0) { - for (auto const& track : tracks) { - if (!(jetderiveddatautilities::selectTrack(track, trackSelection) && jetderiveddatautilities::selectTrackDcaZ(track, trackDcaZmax))) { + for (auto const& track : jetTracks) { + if (!isAcceptedTrack(track)) { 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); + + float pTHat = simPtRef / (std::pow(weight, 1.0 / pTHatExponent)); + if (track.pt() > pTHatMaxFractionMCD * pTHat) { + continue; + } + + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + + registry.fill(HIST("h2_centrality_track_pt"), centrality, track.pt(), weight); + registry.fill(HIST("h2_centrality_track_eta"), centrality, track.eta(), weight); + registry.fill(HIST("h2_centrality_track_phi"), centrality, track.phi(), weight); + registry.fill(HIST("h2_centrality_track_energy"), 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(), centrality, track.pt(), weight); + } + } + + template + void fillParticlesHistograms(TMCCollision const& /*mcCollision*/, TCollisions const& collisions, TParticles const& mcparticles, TTracks tracks, float weight = 1.0) + { + // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + float centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); + + for (auto const& mcparticle : mcparticles) { + registry.fill(HIST("h2_centrality_particle_pt"), centrality, mcparticle.pt(), weight); + registry.fill(HIST("h2_centrality_particle_eta"), centrality, mcparticle.eta(), weight); + registry.fill(HIST("h2_centrality_particle_phi"), centrality, mcparticle.phi(), weight); + registry.fill(HIST("h2_centrality_particle_energy"), centrality, mcparticle.energy(), weight); + registry.fill(HIST("h3_intrate_centrality_particle_pt"), collisions.begin().hadronicRate(), centrality, mcparticle.pt(), weight); + auto partTracks = tracks.sliceBy(tracksPerJParticles, mcparticle.globalIndex()); + for (auto const& track : partTracks) { + registry.fill(HIST("h2_particle_pt_track_pt_deltapt"), mcparticle.pt(), mcparticle.pt() - track.pt(), weight); + registry.fill(HIST("h2_particle_pt_track_pt_deltaptoverparticlept"), mcparticle.pt(), (mcparticle.pt() - track.pt()) / mcparticle.pt(), weight); + } } } void init(o2::framework::InitContext&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(eventSelections)); + if (!(acceptSplitCollisions == NonSplitOnly || acceptSplitCollisions == SplitOkCheckAnyAssocColl || acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly)) { + LOGP(fatal, "Configurable acceptSplitCollisions has wrong input value; stopping workflow"); + } + + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast(eventSelections)); trackSelection = jetderiveddatautilities::initialiseTrackSelection(static_cast(trackSelections)); - if (doprocessEFficiencyPurity) { + if (useCustomTrackSelection) { + // Custom track cuts + LOGP(info, "Using custom track selection from values:"); + LOGP(info, "\tminNCrossedRowsTPC= %f", effSystMinNCrossedRowsTPC.value); + LOGP(info, "\tminNCrossedRowsOverFindableClustersTPC= %f", effSystMinNCrossedRowsOverFindableClustersTPC.value); + LOGP(info, "\tmaxChi2PerClusterTPC= %f", effSystMaxChi2PerClusterTPC.value); + LOGP(info, "\tmaxChi2PerClusterITS= %f", effSystMaxChi2PerClusterITS.value); + // LOGP(info, "\tmaxDcaXY= %f", effSystMaxDcaXY.value); + LOGP(info, "\tmaxDcaZ= %f", effSystMaxDcaZ.value); + LOGP(info, "\tRequireHitsInITSLayers= %i", effSystMinNrequiredHits.value); + + LOGP(info, "\trequireITS= true"); + LOGP(info, "\trequireTPC= true"); + + LOGP(info, "Customizing track selection:"); + int dcaSetup = 0; // default dca setup + customTrackSelection = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, dcaSetup); // takes global tracks configuration, then some of the cuts are edited in the lines below + customTrackSelection.SetEtaRange(-999, 999); + customTrackSelection.SetPtRange(0, 1e10f); + + customTrackSelection.SetMinNCrossedRowsTPC(effSystMinNCrossedRowsTPC.value); + customTrackSelection.SetMinNCrossedRowsOverFindableClustersTPC(effSystMinNCrossedRowsOverFindableClustersTPC.value); + customTrackSelection.SetMaxChi2PerClusterTPC(effSystMaxChi2PerClusterTPC.value); + customTrackSelection.SetMaxChi2PerClusterITS(effSystMaxChi2PerClusterITS.value); + // customTrackSelection.SetMaxDcaXY(effSystMaxDcaXY.value); + customTrackSelection.SetMaxDcaZ(effSystMaxDcaZ.value); + customTrackSelection.SetRequireHitsInITSLayers(effSystMinNrequiredHits.value, {0, 1, 2}); // one hit in any SPD layer (#hits, {layer0, layer1,...}) + + // customTrackSelection.SetRequireITSRefit(true); already set by default + // customTrackSelection.SetRequireTPCRefit(true); already set by default + // customTrackSelection.SetRequireGoldenChi2(requireGoldenChi2.value); already set by default + + customTrackSelection.print(); + } else { + LOGP(info, "Using standard track selection: %s", trackSelections.value); + } + + if (doprocessEFficiencyPurity || doprocessEFficiencyPurityWeighted) { registry.add("hMcCollCutsCounts", "McColl cuts count checks", {HistType::kTH1F, {{10, 0., 10.}}}); registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(1, "allMcColl"); @@ -112,6 +238,10 @@ struct TrackEfficiencyJets { 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.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(7, "ptHatCut"); + if (checkOccupancy) { + registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(8, "occupancyCut"); + } registry.add("hMcPartCutsCounts", "McPart cuts count checks", {HistType::kTH1F, {{10, 0., 10.}}}); registry.get(HIST("hMcPartCutsCounts"))->GetXaxis()->SetBinLabel(1, "allPartsInSelMcColl"); @@ -123,52 +253,59 @@ struct TrackEfficiencyJets { 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 = {500, 0., 10., "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec ptAxisHigh = {18, 10., 100., "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec etaAxis = {100, -1.0, 1.0, "#eta"}; - AxisSpec phiAxis = {200, -1.0, 7., "#phi"}; + if (doprocessEFficiencyPurity) { + 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 + } + if (doprocessEFficiencyPurityWeighted) { + registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(4, "ptHatMaxFraction"); + registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(5, "mcPartIsPrimary"); + registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(6, "etaAcc"); // not actually applied here but it will give an idea of what will be done in the post processing + } + + AxisSpec ptAxisEff = {nBinsLowPt, 0., 10., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptAxisHighEff = {18, 10., 100., "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec etaAxisEff = {etaEffNBins, -1.0, 1.0, "#eta"}; + AxisSpec phiAxisEff = {phiEffNBins, -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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); + registry.add("h3_particle_pt_particle_eta_particle_phi_mcpartofinterest", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); + registry.add("h3_particle_pt_particle_eta_particle_phi_mcpart_nonprimary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); - registry.add("h3_track_pt_track_eta_track_phi_nonassociatedtrack", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxis, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); + registry.add("h3_track_pt_track_eta_track_phi_nonassociatedtrack", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); + registry.add("h3_track_pt_track_eta_track_phi_associatedtrack_primary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); + registry.add("h3_track_pt_track_eta_track_phi_associatedtrack_nonprimary", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisEff, etaAxisEff, phiAxisEff}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); + registry.add("h3_particle_pt_particle_eta_particle_phi_associatedtrack_primary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); + registry.add("h3_particle_pt_particle_eta_particle_phi_associatedtrack_nonprimary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisEff, etaAxisEff, phiAxisEff}}); - 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, {200, -1., 1.}}}); + 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, {ptAxisEff, {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, etaAxis, phiAxis}}); + registry.add("h3_particle_pt_high_particle_eta_particle_phi_mcpartofinterest", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); + registry.add("h3_track_pt_high_track_eta_track_phi_nonassociatedtrack", "#it{p}_{T, track} (GeV/#it{c}); #eta_{track}; #phi_{track}", {HistType::kTH3F, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); - 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, etaAxis, phiAxis}}); + 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, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); + 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, {ptAxisHighEff, etaAxisEff, phiAxisEff}}); - 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, {200, -1., 1.}}}); + 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, {ptAxisHighEff, {200, -1., 1.}}}); } - if (doprocessTracks || doprocessTracksWeighted) { - AxisSpec centAxis = {101, 0., 101., "centrality (%)"}; - 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, {centAxis, {4, 0.0, 4.0}}}); + if (doprocessTracksFromData || doprocessTracksFromMc || doprocessTracksFromMcWeighted) { + 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.}}}); @@ -177,32 +314,89 @@ struct TrackEfficiencyJets { 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}}}); - if (doprocessTracksWeighted) { - registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.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.}}}); + + registry.add("h2_particle_pt_track_pt_deltapt", "track pt vs delta pT; pT; #it{p}_{T, part} - #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {200, -1., 1.}}}); + registry.add("h2_particle_pt_track_pt_deltaptoverparticlept", "track vs delta pT / MC pT ; pT; #frac{#it{p}_{T, part} - #it{p}_{T,track}}{#it{p}_{T,part}}", {HistType::kTH2F, {{200, 0., 200.}, {200, -1., 1.}}}); + } + + if (doprocessCollisionsFromData || doprocessCollisionsFromMc || doprocessCollisionsFromMcWeighted) { + AxisSpec centAxis = {centralityBinning, "centrality (%)"}; + 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, {centAxis, {4, 0.0, 4.0}}}); + } + if (doprocessMcCollisions || doprocessMcCollisionsWeighted) { + 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}}}); + registry.add("h2_mccollision_pthardfromweight_pthardfromhepmcxsection", "ptHard from weight vs ptHard from HepMCXSections; ptHard_weight; ptHard_hepmcxsections", {HistType::kTH2F, {{200, 0.0, 200.0}, {200, 0.0, 200.0}}}); + } + + if (doprocessCollisionsFromMc || doprocessCollisionsFromMcWeighted) { + registry.add("h_fakecollisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + } + if (doprocessCollisionsFromMcWeighted) { + AxisSpec centAxis = {centralityBinning, "centrality (%)"}; + registry.add("h_collisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h2_centrality_collisions_weighted", "centrality vs mccollisions; centrality; collisions", {HistType::kTH2F, {centAxis, {4, 0.0, 4.0}}}); + } + if (doprocessMcCollisionsWeighted) { + AxisSpec centAxis = {centralityBinning, "centrality (%)"}; + registry.add("h_mccollisions_weighted", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); + registry.add("h2_centrality_mccollisions_weighted", "centrality vs mccollisions; centrality; collisions", {HistType::kTH2F, {centAxis, {4, 0.0, 4.0}}}); + registry.add("h2_mccollision_pthardfromweight_pthardfromhepmcxsection_weighted", "ptHard from weight vs ptHard from HepMCXSections; ptHard_weight; ptHard_hepmcxsections", {HistType::kTH2F, {{200, 0.0, 200.0}, {200, 0.0, 200.0}}}); + } + + if (doprocessTrackSelectionHistograms) { + registry.add("h_trackselplot_tpccrossedrows", "track selection variable: number of tpc crossed rows", {HistType::kTH1F, {{165, -0.5, 164.5}}}); + registry.add("h_trackselplot_tpccrossedrowsoverfindable", "track selection variable: ratio of of tpc crossed rows over number of findable clusters", {HistType::kTH1F, {{120, 0.0, 1.2}}}); + registry.add("h_trackselplot_chi2ncls_tpc", "track selection variable: Chi2 / cluster for the TPC track segment", {HistType::kTH1F, {{100, 0.0, 10.0}}}); + registry.add("h_trackselplot_chi2ncls_its", "track selection variable: Chi2 / cluster for the ITS track segment", {HistType::kTH1F, {{200, 0.0, 40.0}}}); + registry.add("h_trackselplot_dcaxy", "track selection variable: dca XY", {HistType::kTH1F, {{1000, -1.0, 1.0}}}); + registry.add("h_trackselplot_dcaz", "track selection variable: dca Z", {HistType::kTH1F, {{4000, -4.0, 4.0}}}); + + registry.add("h2_trackselplot_pt_tpccrossedrows", "track selection variable: pt vs number of tpc crossed rows", {HistType::kTH2F, {{200, 0., 200.}, {165, -0.5, 164.5}}}); + registry.add("h2_trackselplot_pt_tpccrossedrowsoverfindable", "track selection variable: pt vs ratio of of tpc crossed rows over number of findable clusters", {HistType::kTH2F, {{200, 0., 200.}, {120, 0.0, 1.2}}}); + registry.add("h2_trackselplot_pt_chi2ncls_tpc", "track selection variable: pt vs Chi2 / cluster for the TPC track segment", {HistType::kTH2F, {{200, 0., 200.}, {100, 0.0, 10.0}}}); + registry.add("h2_trackselplot_pt_chi2ncls_its", "track selection variable: pt vs Chi2 / cluster for the ITS track segment", {HistType::kTH2F, {{200, 0., 200.}, {200, 0.0, 40.0}}}); + registry.add("h2_trackselplot_pt_dcaxy", "track selection variable: pt vs dca XY", {HistType::kTH2F, {{200, 0., 200.}, {1000, -1.0, 1.0}}}); + registry.add("h2_trackselplot_pt_dcaz", "track selection variable: pt vs dca Z", {HistType::kTH2F, {{200, 0., 200.}, {4000, -4.0, 4.0}}}); } } - Preslice tracksPerJCollision = o2::aod::jtrack::collisionId; + Preslice tracksPerJCollision = o2::aod::jtrack::collisionId; + PresliceUnsorted tracksPerJParticles = o2::aod::jmctracklb::mcParticleId; // 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 eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut && aod::jcollision::centrality >= centralityMin && aod::jcollision::centrality < centralityMax); - - void processEFficiencyPurity(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, + 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); + + void processEFficiencyPurity(soa::Join::iterator const& mcCollision, + soa::Join const&, + 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, + soa::Join const&, 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) + // At the moment, are only counted mc particles from mc collisions that have at least one reconstructed collision that passes the chosen event selection. Thus, the reconstruction efficiency of mccollision is not counted in this tracking efficiency. registry.fill(HIST("hMcCollCutsCounts"), 0.5); // all mcCollisions - if (!(abs(mcCollision.posZ()) < vertexZCut)) { + if (!(std::abs(mcCollision.posZ()) < vertexZCut)) { return; } registry.fill(HIST("hMcCollCutsCounts"), 1.5); // mcCollision.posZ() condition @@ -212,26 +406,36 @@ struct TrackEfficiencyJets { } registry.fill(HIST("hMcCollCutsCounts"), 2.5); // mcCollisions with at least one reconstructed collision - if (acceptSplitCollisions == 0 && collisions.size() > 1) { + if (acceptSplitCollisions == NonSplitOnly && collisions.size() > 1) { return; } registry.fill(HIST("hMcCollCutsCounts"), 3.5); // split mcCollisions condition + float centrality = -1; bool hasSel8Coll = false; bool centralityCheck = false; - if (acceptSplitCollisions == 2) { // check only that the first reconstructed collision passes the check - if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelection)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + bool occupancyCheck = false; + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed hasSel8Coll = true; } - if (!checkCentrality || ((centralityMin < collisions.begin().centrality()) && (collisions.begin().centrality() < centralityMax))) { // effect unclear if mcColl is split + if (!checkOccupancy || ((trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax))) { // check occupancy only in GP Pb-Pb MC + occupancyCheck = true; + } + centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics centralityCheck = true; } - } else { // check that at least one of the reconstructed collisions passes the checks - for (auto& collision : collisions) { - if (jetderiveddatautilities::selectCollision(collision, eventSelection)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks + for (auto const& 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 + if (!checkOccupancy || ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax))) { // check occupancy only in GP Pb-Pb MC + occupancyCheck = true; + } + centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // effect unclear if mcColl is split centralityCheck = true; } } @@ -241,12 +445,29 @@ struct TrackEfficiencyJets { } registry.fill(HIST("hMcCollCutsCounts"), 4.5); // at least one of the reconstructed collisions associated with this mcCollision is selected + // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + // if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + // return; + // } 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) { + float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 6.5); // ptHat condition + + if (checkOccupancy) { + if (!occupancyCheck) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 7.5); + } + + for (auto const& jMcParticle : jMcParticles) { registry.fill(HIST("hMcPartCutsCounts"), 0.5); // allPartsInSelMcColl if (!isChargedParticle(jMcParticle.pdgCode())) { @@ -265,29 +486,29 @@ struct TrackEfficiencyJets { 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 + if ((std::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) { + for (auto const& collision : collisions) { splitCollCounter++; - if (acceptSplitCollisions == 2 && splitCollCounter > 1) { + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly && splitCollCounter > 1) { return; } - if (!jetderiveddatautilities::selectCollision(collision, eventSelection) || !(abs(collision.posZ()) < vertexZCut)) { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents) || !(std::abs(collision.posZ()) < vertexZCut)) { continue; } auto collTracks = jetTracks.sliceBy(tracksPerJCollision, collision.globalIndex()); - for (auto& track : collTracks) { + for (auto const& 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 + if (!isAcceptedTrack(track)) { continue; } registry.fill(HIST("hTrackCutsCounts"), 1.5); @@ -341,43 +562,682 @@ struct TrackEfficiencyJets { 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 + if (std::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); + PROCESS_SWITCH(TrackEfficiency, processEFficiencyPurity, "Histograms for efficiency and purity quantities", true); + + void processEFficiencyPurityWeighted(soa::Join::iterator const& mcCollision, + soa::Join const&, + 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, + soa::Join const&, + JetParticlesWithOriginal const& jMcParticles) + { + // missing: + // * constexpr auto hasCentrality = CollisionMCRecTableCentFT0C::template contains(); + // if constexpr (hasCentrality) { + // At the moment, are only counted mc particles from mc collisions that have at least one reconstructed collision that passes the chosen event selection. Thus, the reconstruction efficiency of mccollision is not counted in this tracking efficiency. + + registry.fill(HIST("hMcCollCutsCounts"), 0.5, mcCollision.weight()); // all mcCollisions + + if (!(std::abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 1.5, mcCollision.weight()); // mcCollision.posZ() condition - void processTracks(soa::Filtered::iterator const& collision, - soa::Filtered> const& tracks) + if (collisions.size() < 1) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 2.5, mcCollision.weight()); // mcCollisions with at least one reconstructed collision + + if (acceptSplitCollisions == NonSplitOnly && collisions.size() > 1) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 3.5, mcCollision.weight()); // split mcCollisions condition + + float centrality = -1; + bool hasSel8Coll = false; + bool centralityCheck = false; + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + hasSel8Coll = true; + } + centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks + for (auto const& 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; + } + centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } + } + if (!hasSel8Coll) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 4.5, mcCollision.weight()); // at least one of the reconstructed collisions associated with this mcCollision is selected + + // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + // if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + // return; + // } + if (!centralityCheck) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 5.5, mcCollision.weight()); // centrality condition + + float mcCollEventWeight = mcCollision.weight(); + float pTHat = simPtRef / (std::pow(mcCollEventWeight, 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 6.5, mcCollision.weight()); // ptHat condition + + for (auto const& jMcParticle : jMcParticles) { + registry.fill(HIST("hMcPartCutsCounts"), 0.5, mcCollision.weight()); // allPartsInSelMcColl + + if (!isChargedParticle(jMcParticle.pdgCode())) { + continue; + } + registry.fill(HIST("hMcPartCutsCounts"), 1.5, mcCollision.weight()); // isCharged + + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_mcpart_nonprimary"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi(), mcCollEventWeight); + + if (checkPrimaryPart && !jMcParticle.isPhysicalPrimary()) { // global tracks should be mostly primaries + continue; + } + registry.fill(HIST("hMcPartCutsCounts"), 2.5, mcCollision.weight()); // isPrimary + + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_mcpartofinterest"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi(), mcCollEventWeight); + + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_mcpartofinterest"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi(), mcCollEventWeight); + + if ((std::abs(jMcParticle.eta()) < trackEtaAcceptanceCountQA)) { // removed from actual cuts for now because all the histograms have an eta axis + registry.fill(HIST("hMcPartCutsCounts"), 3.5, mcCollision.weight()); // 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 const& collision : collisions) { + splitCollCounter++; + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly && splitCollCounter > 1) { + return; + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents) || !(std::abs(collision.posZ()) < vertexZCut)) { + continue; + } + + auto collTracks = jetTracks.sliceBy(tracksPerJCollision, collision.globalIndex()); + for (auto const& track : collTracks) { + registry.fill(HIST("hTrackCutsCounts"), 0.5, mcCollision.weight()); + + if (!isAcceptedTrack(track)) { + continue; + } + registry.fill(HIST("hTrackCutsCounts"), 1.5, mcCollision.weight()); + + if (!track.has_mcParticle()) { + registry.fill(HIST("h3_track_pt_track_eta_track_phi_nonassociatedtrack"), track.pt(), track.eta(), track.phi(), mcCollEventWeight); // weight attribution here not trivial; I use the one of the current mcCollision, but track belongs to no collision; what should be its weight? could be a moot point but algo has complained about invalid index for mcParticle if I put th etrueTrackCollEventWeight before this cut + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_nonassociatedtrack"), track.pt(), track.eta(), track.phi(), mcCollEventWeight); + continue; + } + registry.fill(HIST("hTrackCutsCounts"), 2.5, mcCollision.weight()); + + if (track.pt() > pTHatMaxFractionMCD * pTHat) { + continue; + } + registry.fill(HIST("hTrackCutsCounts"), 3.5, mcCollision.weight()); + + auto mcParticle = track.mcParticle_as(); + auto trueTrackMcCollision = mcParticle.mcCollision_as>(); + float trueTrackCollEventWeight = useTrueTrackWeight ? trueTrackMcCollision.weight() : mcCollEventWeight; + + 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(), trueTrackCollEventWeight); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_nonprimary"), track.pt(), track.eta(), track.phi(), trueTrackCollEventWeight); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); + + 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(), trueTrackCollEventWeight); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_split_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_split_nonprimary"), track.pt(), track.eta(), track.phi(), trueTrackCollEventWeight); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_split_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); + } else { + seenMcParticlesVector.push_back(jMcParticleFromTrack.globalIndex()); + } + + continue; + } + + registry.fill(HIST("hTrackCutsCounts"), 4.5, mcCollision.weight()); + + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_primary"), track.pt(), track.eta(), track.phi(), trueTrackCollEventWeight); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); + registry.fill(HIST("h2_particle_pt_track_pt_residual_associatedtrack_primary"), jMcParticleFromTrack.pt(), (jMcParticleFromTrack.pt() - track.pt()) / jMcParticleFromTrack.pt(), trueTrackCollEventWeight); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_primary"), track.pt(), track.eta(), track.phi(), trueTrackCollEventWeight); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); + registry.fill(HIST("h2_particle_pt_high_track_pt_high_residual_associatedtrack_primary"), jMcParticleFromTrack.pt(), (jMcParticleFromTrack.pt() - track.pt()) / jMcParticleFromTrack.pt(), trueTrackCollEventWeight); + + 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(), trueTrackCollEventWeight); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_split_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_split_primary"), track.pt(), track.eta(), track.phi(), trueTrackCollEventWeight); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_split_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi(), trueTrackCollEventWeight); + } else { + seenMcParticlesVector.push_back(jMcParticleFromTrack.globalIndex()); + } + + if (std::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"), 5.5, mcCollision.weight()); + } + } + } + } + PROCESS_SWITCH(TrackEfficiency, processEFficiencyPurityWeighted, "Histograms for efficiency and purity quantities for weighted simulations", false); + + void processTracksFromData(soa::Filtered::iterator const& collision, + soa::Filtered> const& jetTracks, + soa::Join const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + + fillTrackHistograms(collision, jetTracks); + } + PROCESS_SWITCH(TrackEfficiency, processTracksFromData, "QA for charged tracks in data", false); + + void processTracksFromMc(soa::Filtered>::iterator const& collision, + soa::Join const&, + soa::Join const&, + soa::Filtered> const& jetTracks, + soa::Join const&) { + if (!collision.has_mcCollision()) { // the collision is fake and has no associated mc coll; skip as .mccollision() cannot be called + return; + } + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + + float pTHat = getPtHatFromHepMCXSection ? collision.mcCollision_as>().mcCollision_as>().ptHard() : 10. / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + + fillTrackHistograms(collision, jetTracks); + } + PROCESS_SWITCH(TrackEfficiency, processTracksFromMc, "QA for charged tracks in MC without weights", false); + + void processTracksFromMcWeighted(soa::Filtered>::iterator const& collision, + soa::Join const&, + soa::Join const&, + soa::Filtered> const& jetTracks, + soa::Join const&) + { + 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_as>().weight(); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + + float pTHat = getPtHatFromHepMCXSection ? collision.mcCollision_as>().mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + + fillTrackHistograms(collision, jetTracks, eventWeight); + } + PROCESS_SWITCH(TrackEfficiency, processTracksFromMcWeighted, "QA for charged tracks in weighted MC", false); + + void processParticles(soa::Join::iterator const& mcCollision, + soa::Join const&, + soa::SmallGroups const& collisions, + soa::Filtered const& mcparticles, + soa::Filtered const& tracks) + { + + if (!(std::abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + if (collisions.size() < 1) { + return; + } + if (acceptSplitCollisions == NonSplitOnly && collisions.size() > 1) { + return; + } + + float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + + float centrality = -1; + bool hasSel8Coll = false; + bool centralityCheck = false; + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + hasSel8Coll = true; + } + centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks + for (auto const& 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; + } + centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } + } + if (!hasSel8Coll) { + return; + } + // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + // if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + // return; + // } + if (!centralityCheck) { + return; + } + + fillParticlesHistograms(mcCollision, collisions, mcparticles, tracks); + } + PROCESS_SWITCH(TrackEfficiency, processParticles, "QA for charged particles", false); + + void processParticlesWeighted(soa::Join::iterator const& mcCollision, + soa::Join const&, + soa::SmallGroups const& collisions, + soa::Filtered const& mcparticles, + soa::Filtered const& tracks) + { + if (skipMBGapEvents && mcCollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + + float eventWeight = mcCollision.weight(); + + if (!(std::abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + if (collisions.size() < 1) { + return; + } + if (acceptSplitCollisions == NonSplitOnly && collisions.size() > 1) { + return; + } + + float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + + float centrality = -1; + bool hasSel8Coll = false; + bool centralityCheck = false; + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + hasSel8Coll = true; + } + centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks + for (auto const& 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; + } + centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } + } + if (!hasSel8Coll) { + return; + } + + // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + // if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + // return; + // } + if (!centralityCheck) { + return; + } + + fillParticlesHistograms(mcCollision, collisions, mcparticles, tracks, eventWeight); + } + PROCESS_SWITCH(TrackEfficiency, processParticlesWeighted, "QA for charged particles weighted", false); + + void processCollisionsFromData(soa::Filtered::iterator const& collision) + { + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + registry.fill(HIST("h_collisions"), 0.5); - registry.fill(HIST("h2_centrality_collisions"), collision.centrality(), 0.5); - if (!jetderiveddatautilities::selectCollision(collision, eventSelection)) { + registry.fill(HIST("h2_centrality_collisions"), 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); - fillTrackHistograms(collision, tracks); + registry.fill(HIST("h2_centrality_collisions"), centrality, 1.5); + if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 2.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 3.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 3.5); + } + PROCESS_SWITCH(TrackEfficiency, processCollisionsFromData, "QA for reconstructed collisions in data", false); + + void processCollisionsFromMc(soa::Filtered>::iterator const& collision, + soa::Join const&, + soa::Join const&) + { + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + + 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; + } + registry.fill(HIST("h_collisions"), 0.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 0.5); + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + registry.fill(HIST("h_collisions"), 1.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 1.5); + if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 2.5); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 3.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 3.5); + + float pTHat = getPtHatFromHepMCXSection ? collision.mcCollision_as>().mcCollision_as>().ptHard() : 10. / (std::pow(collision.mcCollision().weight(), 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + registry.fill(HIST("h_collisions"), 4.5); + registry.fill(HIST("h2_centrality_collisions"), centrality, 4.5); } - PROCESS_SWITCH(TrackEfficiencyJets, processTracks, "QA for charged tracks", false); + PROCESS_SWITCH(TrackEfficiency, processCollisionsFromMc, "QA for reconstructed collisions in MC without weights", false); - void processTracksWeighted(soa::Join::iterator const& collision, - JetMcCollisions const&, - soa::Filtered> const& tracks) + void processCollisionsFromMcWeighted(soa::Filtered>::iterator const& collision, + soa::Join const&, + soa::Join const&) { - float eventWeight = collision.mcCollision().weight(); + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + + 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_as>().weight(); 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, skipMBGapEvents)) { return; } registry.fill(HIST("h_collisions"), 1.5); registry.fill(HIST("h_collisions_weighted"), 1.5, eventWeight); - fillTrackHistograms(collision, tracks, eventWeight); + if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + return; + } + registry.fill(HIST("h_collisions"), 2.5); + registry.fill(HIST("h_collisions_weighted"), 2.5, eventWeight); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + registry.fill(HIST("h_collisions"), 3.5); + registry.fill(HIST("h_collisions_weighted"), 3.5, eventWeight); + + float pTHat = getPtHatFromHepMCXSection ? collision.mcCollision_as>().mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + registry.fill(HIST("h_collisions"), 4.5); + registry.fill(HIST("h_collisions_weighted"), 4.5, eventWeight); + } + PROCESS_SWITCH(TrackEfficiency, processCollisionsFromMcWeighted, "QA for reconstructed collisions in weighted MC", false); + + void processMcCollisions(soa::Join::iterator const& mcCollision, + soa::Join const&, + soa::SmallGroups const& collisions) + { + // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + + float eventWeight = mcCollision.weight(); + float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.mcCollision_as>().ptHard()); + + float centrality = -1; + bool hasSel8Coll = false; + bool centralityCheck = false; + if (collisions.size() > 1) { // remove and move the if block below under if (collisions.size() < 1) { when mccoll.centFt0C has been fixed + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + hasSel8Coll = true; + } + centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks + for (auto const& 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; + } + centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } + } + } + + registry.fill(HIST("h_mccollisions"), 0.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 0.5); + + if (!(std::abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + if (collisions.size() < 1) { + return; + } + if (acceptSplitCollisions == NonSplitOnly && collisions.size() > 1) { + return; + } + + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + registry.fill(HIST("h_mccollisions"), 1.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 1.5); + + if (!hasSel8Coll) { + return; + } + // if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + // return; + // } + if (!centralityCheck) { + return; + } + + registry.fill(HIST("h_mccollisions"), 2.5); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 2.5); + } + PROCESS_SWITCH(TrackEfficiency, processMcCollisions, "QA for McCollisions in MC without weights", false); + + void processMcCollisionsWeighted(soa::Join::iterator const& mcCollision, + soa::Join const&, + soa::SmallGroups const& collisions) + { + if (skipMBGapEvents && mcCollision.subGeneratorId() == jetderiveddatautilities::JCollisionSubGeneratorId::mbGap) { + return; + } + + // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + + float eventWeight = mcCollision.weight(); + float pTHat = getPtHatFromHepMCXSection ? mcCollision.mcCollision_as>().ptHard() : 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)); + registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.mcCollision_as>().ptHard()); + registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection_weighted"), 10. / (std::pow(eventWeight, 1.0 / pTHatExponent)), mcCollision.mcCollision_as>().ptHard(), eventWeight); + + float centrality = -1; + bool hasSel8Coll = false; + bool centralityCheck = false; + if (collisions.size() > 1) { // remove and move the if block below under if (collisions.size() < 1) { when mccoll.centFt0C has been fixed + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents)) { // Skipping MC events that have their first associated collision not reconstructed + hasSel8Coll = true; + } + centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks + for (auto const& 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; + } + centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } + } + } + + registry.fill(HIST("h_mccollisions"), 0.5); + registry.fill(HIST("h_mccollisions_weighted"), 0.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 0.5); + registry.fill(HIST("h2_centrality_mccollisions_weighted"), centrality, 0.5, eventWeight); + + if (!(std::abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + if (collisions.size() < 1) { + return; + } + if (acceptSplitCollisions == NonSplitOnly && collisions.size() > 1) { + return; + } + + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + registry.fill(HIST("h_mccollisions"), 1.5); + registry.fill(HIST("h_mccollisions_weighted"), 1.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 1.5); + registry.fill(HIST("h2_centrality_mccollisions_weighted"), centrality, 1.5, eventWeight); + + if (!hasSel8Coll) { + return; + } + // if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + // return; + // } + if (!centralityCheck) { + return; + } + registry.fill(HIST("h_mccollisions"), 2.5); + registry.fill(HIST("h_mccollisions_weighted"), 2.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), centrality, 2.5); + registry.fill(HIST("h2_centrality_mccollisions_weighted"), centrality, 2.5, eventWeight); + } + PROCESS_SWITCH(TrackEfficiency, processMcCollisionsWeighted, "QA for McCollisions in weighted MC", false); + + void processTrackSelectionHistograms(soa::Filtered::iterator const& collision, soa::Join const& jetTracks, soa::Join const&) + { + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { + return; + } + float centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + return; + } + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + + for (auto const& jetTrack : jetTracks) { + const auto& aodTrack = jetTrack.track_as>(); + + registry.fill(HIST("h_trackselplot_tpccrossedrows"), aodTrack.tpcNClsCrossedRows()); + registry.fill(HIST("h_trackselplot_tpccrossedrowsoverfindable"), aodTrack.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("h_trackselplot_chi2ncls_tpc"), aodTrack.tpcChi2NCl()); + registry.fill(HIST("h_trackselplot_chi2ncls_its"), aodTrack.itsChi2NCl()); + registry.fill(HIST("h_trackselplot_dcaxy"), aodTrack.dcaXY()); + registry.fill(HIST("h_trackselplot_dcaz"), aodTrack.dcaZ()); + + registry.fill(HIST("h2_trackselplot_pt_tpccrossedrows"), aodTrack.pt(), aodTrack.tpcNClsCrossedRows()); + registry.fill(HIST("h2_trackselplot_pt_tpccrossedrowsoverfindable"), aodTrack.pt(), aodTrack.tpcCrossedRowsOverFindableCls()); + registry.fill(HIST("h2_trackselplot_pt_chi2ncls_tpc"), aodTrack.pt(), aodTrack.tpcChi2NCl()); + registry.fill(HIST("h2_trackselplot_pt_chi2ncls_its"), aodTrack.pt(), aodTrack.itsChi2NCl()); + registry.fill(HIST("h2_trackselplot_pt_dcaxy"), aodTrack.pt(), aodTrack.dcaXY()); + registry.fill(HIST("h2_trackselplot_pt_dcaz"), aodTrack.pt(), aodTrack.dcaZ()); + } } - PROCESS_SWITCH(TrackEfficiencyJets, processTracksWeighted, "QA for charged tracks weighted", false); + PROCESS_SWITCH(TrackEfficiency, processTrackSelectionHistograms, "plots distributions of variables that are cut on during track selection", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"track-efficiency"})}; } +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/Tasks/trackJetqa.cxx b/PWGJE/Tasks/trackJetQA.cxx similarity index 85% rename from PWGJE/Tasks/trackJetqa.cxx rename to PWGJE/Tasks/trackJetQA.cxx index 9477f88d66e..60c099bf7a3 100644 --- a/PWGJE/Tasks/trackJetqa.cxx +++ b/PWGJE/Tasks/trackJetQA.cxx @@ -15,27 +15,29 @@ /// \since 2023-10-02 /// \brief Task producing jet tracking qa histograms /// -#include - -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" -#include "Framework/ASoA.h" +#include "PWGJE/DataModel/TrackJetQa.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" - -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/DataModel/TrackJetQa.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" - #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#include +#include +#include +#include +#include + +#include using namespace o2; -using namespace o2::track; using namespace o2::framework; using namespace o2::framework::expressions; @@ -82,6 +84,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 +176,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 +185,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}); @@ -264,11 +274,6 @@ struct TrackJetQa { histos.fill(HIST("TrackPar/signed1Pt"), track.pt(), track.sigma1Pt() * track.pt(), track.signed1Pt(), collision.centFT0A(), collision.centFT0C()); histos.fill(HIST("TrackPar/snp"), track.pt(), track.sigma1Pt() * track.pt(), track.snp(), collision.centFT0A(), collision.centFT0C()); histos.fill(HIST("TrackPar/tgl"), track.pt(), track.sigma1Pt() * track.pt(), track.tgl(), collision.centFT0A(), collision.centFT0C()); - for (unsigned int i = 0; i < 64; i++) { - if (track.flags() & (1 << i)) { - histos.fill(HIST("TrackPar/flags"), track.pt(), track.sigma1Pt() * track.pt(), i); - } - } histos.fill(HIST("TrackPar/dcaXY"), track.pt(), track.sigma1Pt() * track.pt(), track.dcaXY(), collision.centFT0A(), collision.centFT0C()); histos.fill(HIST("TrackPar/dcaZ"), track.pt(), track.sigma1Pt() * track.pt(), track.dcaZ(), collision.centFT0A(), collision.centFT0C()); histos.fill(HIST("TrackPar/length"), track.pt(), track.sigma1Pt() * track.pt(), track.length(), collision.centFT0A(), collision.centFT0C()); @@ -276,17 +281,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 +305,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 +355,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..c0c272d39c7 100644 --- a/PWGJE/Tasks/triggerCorrelations.cxx +++ b/PWGJE/Tasks/triggerCorrelations.cxx @@ -13,120 +13,97 @@ // /// \author Nima Zardoshti -#include +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/JetReducedData.h" -#include "EMCALBase/Geometry.h" #include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" -#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/HistogramRegistry.h" +#include +#include +#include +#include -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/CCDB/TriggerAliases.h" +#include -#include "PWGJE/Core/FastJetUtilities.h" -#include "PWGJE/Core/JetDerivedDataUtilities.h" -#include "PWGJE/DataModel/EMCALClusters.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/DataModel/Jet.h" +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -#include "Framework/runDataProcessing.h" - struct TriggerCorrelationsTask { HistogramRegistry registry; - int nChTrigs; - int nFullTrigs; - int nChHFTrigs; - int nAllTrigs; - - int chTrigOffset; - int fullTrigOffset; - int chHFTrigOffset; - + std::vector triggerMaskBits; + long unsigned int nChargedTriggers = 4; + long unsigned int nChargedHFTriggers = 4; + long unsigned int nFullTriggers = 13; 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 fillOnlineCorrelationsHistogram(T const& collision, bool fill = false, int iCurrentTrig = -1) { - - for (auto iChTrigs = 0; iChTrigs < nChTrigs; iChTrigs++) { + for (std::vector::size_type iTrig = 0; iTrig < triggerMaskBits.size(); iTrig++) { if (fill) { - if (jetderiveddatautilities::selectChargedTrigger(collision, iChTrigs + 1)) { - registry.fill(HIST("triggerCorrelations"), iTrig, iChTrigs + chTrigOffset); + if (iTrig < nChargedTriggers && jetderiveddatautilities::selectChargedTrigger(collision, iTrig + 1)) { + registry.fill(HIST("triggerCorrelations"), iCurrentTrig, iTrig); } - } else { - if (jetderiveddatautilities::selectChargedTrigger(collision, iChTrigs + 1)) { - fillCorrelationsHistogram(collision, true, iChTrigs + chTrigOffset); + if (iTrig >= nChargedTriggers && iTrig < (nChargedTriggers + nChargedHFTriggers) && jetderiveddatautilities::selectChargedHFTrigger(collision, iTrig - nChargedTriggers + 1)) { + registry.fill(HIST("triggerCorrelations"), iCurrentTrig, iTrig); } - } - } - - for (auto iFullTrigs = 0; iFullTrigs < nFullTrigs; iFullTrigs++) { - if (fill) { - if (jetderiveddatautilities::selectFullTrigger(collision, iFullTrigs + 1)) { - registry.fill(HIST("triggerCorrelations"), iTrig, iFullTrigs + fullTrigOffset); + if (iTrig >= (nChargedTriggers + nChargedHFTriggers) && iTrig < (nChargedTriggers + nChargedHFTriggers + nFullTriggers) && jetderiveddatautilities::selectFullTrigger(collision, iTrig - (nChargedTriggers + nChargedHFTriggers) + 1)) { + registry.fill(HIST("triggerCorrelations"), iCurrentTrig, iTrig); } + } else { - if (jetderiveddatautilities::selectFullTrigger(collision, iFullTrigs + 1)) { - fillCorrelationsHistogram(collision, true, iFullTrigs + fullTrigOffset); + if (jetderiveddatautilities::selectTrigger(collision, triggerMaskBits[iTrig])) { + fillOnlineCorrelationsHistogram(collision, true, iTrig); } } } + } - for (auto iChHFTrigs = 0; iChHFTrigs < nFullTrigs; iChHFTrigs++) { + template + void fillOfflineCorrelationsHistogram(T const& collision, bool fill = false, int iCurrentTrig = -1) + { + 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])) { + fillOfflineCorrelationsHistogram(collision, true, iTrig); } } } } - void processTriggeredCorrelations(soa::Join::iterator const& collision) + void processTriggeredCorrelationsOnline(soa::Join::iterator const& collision) + { + fillOnlineCorrelationsHistogram(collision); + } + PROCESS_SWITCH(TriggerCorrelationsTask, processTriggeredCorrelationsOnline, "QA for online trigger correlations", true); + + void processTriggeredCorrelationsOffline(aod::JCollision const& collision) { - fillCorrelationsHistogram(collision); + fillOfflineCorrelationsHistogram(collision); } - PROCESS_SWITCH(TriggerCorrelationsTask, processTriggeredCorrelations, "QA for trigger correlations", true); + PROCESS_SWITCH(TriggerCorrelationsTask, processTriggeredCorrelationsOffline, "QA for offline trigger correlations", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGJE/Tasks/v0jetspectra.cxx b/PWGJE/Tasks/v0JetSpectra.cxx similarity index 80% rename from PWGJE/Tasks/v0jetspectra.cxx rename to PWGJE/Tasks/v0JetSpectra.cxx index dad55b12e52..95081bad725 100644 --- a/PWGJE/Tasks/v0jetspectra.cxx +++ b/PWGJE/Tasks/v0JetSpectra.cxx @@ -9,29 +9,28 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// jet spectra for v0 fragmentation study -// +/// \brief Jet spectra for ch+V0 jets +/// /// \author Gijs van Weelden // -#include "TH1F.h" -#include "TTree.h" +#include "JetDerivedDataUtilities.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoA.h" -#include "Framework/RunningWorkflowInfo.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include -#include "CommonConstants/PhysicsConstants.h" +#include -#include "PWGJE/DataModel/Jet.h" -#include "PWGJE/Core/JetFinder.h" -#include "PWGJE/Core/JetUtilities.h" -#include "PWGJE/Core/JetFindingUtilities.h" +#include +#include using namespace o2; using namespace o2::framework; @@ -63,13 +62,13 @@ struct V0JetSpectra { Configurable evSel{"evSel", "sel8WithoutTimeFrameBorderCut", "choose event selection"}; Configurable vertexZCut{"vertexZCut", 10.f, "vertex z cut"}; - int eventSelection = -1; + std::vector eventSelectionBits; Filter jetCollisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; void init(InitContext&) { - eventSelection = jetderiveddatautilities::initialiseEventSelection(static_cast(evSel)); + 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()}}); } @@ -89,9 +88,9 @@ struct V0JetSpectra { } } - void processData(soa::Filtered::iterator const& jcoll, aod::ChargedJets const& chjets, aod::V0ChargedJets const& v0jets) + void processData(soa::Filtered::iterator const& jcoll, aod::ChargedJets const& chjets, aod::V0ChargedJets const& v0jets) { - if (!jetderiveddatautilities::selectCollision(jcoll, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { return; } if (v0jets.size() == 0) { @@ -100,12 +99,12 @@ struct V0JetSpectra { } 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, JetMcCollisions const&, MCDJets const& chjets, MCDV0Jets const& v0jets) + 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, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { return; } double weight = jcoll.mcCollision().weight(); @@ -115,7 +114,7 @@ struct V0JetSpectra { } PROCESS_SWITCH(V0JetSpectra, processMCD, "Jet spectra for V0 jets or Ch jets if no V0s", false); - void processMCP(JetMcCollision const& jcoll, MCPJets const& chjets, MCPV0Jets const& v0jets) + void processMCP(aod::JetMcCollision const& jcoll, MCPJets const& chjets, MCPV0Jets const& v0jets) { double weight = jcoll.weight(); if (v0jets.size() == 0) { @@ -124,9 +123,9 @@ struct V0JetSpectra { } PROCESS_SWITCH(V0JetSpectra, processMCP, "Jet spectra for V0 jets or Ch jets if no V0s", false); - void processMcMatched(soa::Filtered::iterator const& jcoll, JetMcCollisions const&, MatchedMCDJets const& chjetsMCD, MatchedMCPJets const& chjetsMCP, MatchedMCDV0Jets const& v0jetsMCD, MatchedMCPV0Jets const& v0jetsMCP) + 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, eventSelection)) { + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) { return; } // TODO: Need to add checker to only count matched jets (?) diff --git a/PWGJE/Tasks/v0QA.cxx b/PWGJE/Tasks/v0QA.cxx new file mode 100644 index 00000000000..353869e4644 --- /dev/null +++ b/PWGJE/Tasks/v0QA.cxx @@ -0,0 +1,1868 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "JetDerivedDataUtilities.h" + +#include "PWGJE/Core/JetFindingUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/V0SelectorTables.h" + +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// V0 jets +using V0ChargedJetsWithConstituents = soa::Join; +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; + +using JetMcCollisionsWithPIs = soa::Join; + +// Tracks +using DaughterJTracks = soa::Join; +using DaughterTracks = soa::Join; + +struct V0QA { + HistogramRegistry registry{"registry"}; + + Configurable evSel{"evSel", "sel8WithoutTimeFrameBorderCut", "choose event selection"}; + Configurable yPartMax{"yPartMax", 0.5, "Maximum rapidity of particles"}; + Configurable etaV0Max{"etaV0Max", 0.75, "Maximum pseudorapidity of V0s"}; + Configurable vertexZCut{"vertexZCut", 10.0, "Vertex Z cut"}; + Configurable v0Fraction{"v0Fraction", 1.0, "Fraction of V0s to be kept inside jets"}; + + Filter jetCollisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; + + ConfigurableAxis binPtJet{"binPtJet", {100., 0.0f, 50.0f}, ""}; + ConfigurableAxis binPtV0{"binPtV0", {100., 0.0f, 50.0f}, ""}; + ConfigurableAxis binZV0{"binZV0", {100., 1e-3f, 1 + 1e-3f}, ""}; + 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{"binV0Radius", {100., 0.0f, 50.0f}, ""}; + ConfigurableAxis binV0CosPA{"binV0CosPA", {50., 0.95f, 1.0f}, ""}; + + ConfigurableAxis binsDcaXY{"binsDcaXY", {100, -0.5f, 0.5f}, ""}; + ConfigurableAxis binsDcaZ{"binsDcaZ", {100, -5.f, 5.f}, ""}; + ConfigurableAxis binPtDiff{"binPtDiff", {200., -49.5f, 50.5f}, ""}; + ConfigurableAxis binPtRelDiff{"binPtRelDiff", {100., -1.0f, 1.0f}, ""}; + ConfigurableAxis binITSNCl{"binITSNCl", {8, -0.5, 7.5}, ""}; + ConfigurableAxis binITSChi2NCl{"binITSChi2NCl", {100, 0, 40}, ""}; + + ConfigurableAxis binTPCNCl{"binTPCNCl", {165, -0.5, 164.5}, ""}; + ConfigurableAxis binTPCChi2NCl{"binTPCChi2NCl", {100, 0, 10}, ""}; + ConfigurableAxis binTPCNClSharedFraction{"binTPCNClSharedFraction", {100, 0., 1.}, ""}; + ConfigurableAxis binTPCCrossedRowsOverFindableCl{"binTPCCrossedRowsOverFindableCl", {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 axisV0Z{binZV0, "z_{V0} = #it{p}_{T, V0} / #it{p}_{T, jet}"}; + 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"}; + + const bool doSumw2 = true; + + 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, {{3, 0.0f, 3.0f}}}, doSumw2); + + registry.add("inclusive/K0SPtEtaMass", "K0S Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisK0SM}, doSumw2); + registry.add("inclusive/InvMassK0STrue", "Invariant mass of K0S", HistType::kTH3D, {axisV0Pt, axisV0Radius, axisK0SM}, doSumw2); + registry.add("inclusive/K0SPtEtaMassWrongCollision", "K0S Pt, Eta, Mass (Wrong Collision)", HistType::kTH3D, {axisV0Pt, axisEta, axisK0SM}, doSumw2); + registry.add("inclusive/LambdaPtEtaMass", "Lambda Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisLambdaM}, doSumw2); + registry.add("inclusive/InvMassLambdaTrue", "Invariant mass of Lambda", HistType::kTH3D, {axisV0Pt, axisV0Radius, axisLambdaM}, doSumw2); + registry.add("inclusive/LambdaPtEtaMassWrongCollision", "Lambda Pt, Eta, Mass (Wrong Collision)", HistType::kTH3D, {axisV0Pt, axisEta, axisLambdaM}, doSumw2); + registry.add("inclusive/AntiLambdaPtEtaMass", "AntiLambda Pt, Eta, Mass", HistType::kTH3D, {axisV0Pt, axisEta, axisAntiLambdaM}, doSumw2); + registry.add("inclusive/InvMassAntiLambdaTrue", "Invariant mass of AntiLambda", HistType::kTH3D, {axisV0Pt, axisV0Radius, axisAntiLambdaM}, doSumw2); + registry.add("inclusive/AntiLambdaPtEtaMassWrongCollision", "AntiLambda Pt, Eta, Mass (Wrong Collision)", HistType::kTH3D, {axisV0Pt, axisEta, axisAntiLambdaM}, doSumw2); + + registry.add("jets/JetPtEtaPhi", "Jet Pt, Eta, Phi", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}, doSumw2); + registry.add("jets/JetPtEtaK0SPt", "Jet Pt, Eta, K0S Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetPtEtaK0SZ", "Jet Pt, Eta, K0S Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetPtEtaK0SPtWrongCollision", "Jet Pt, Eta, K0S Pt (Wrong Collision)", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetPtEtaK0SZWrongCollision", "Jet Pt, Eta, K0S Z (Wrong Collision)", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetPtEtaLambdaPt", "Jet Pt, Eta, Lambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetPtEtaLambdaZ", "Jet Pt, Eta, Lambda Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetPtEtaLambdaPtWrongCollision", "Jet Pt, Eta, Lambda Pt (Wrong Collision)", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetPtEtaLambdaZWrongCollision", "Jet Pt, Eta, Lambda Z (Wrong Collision)", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetPtEtaAntiLambdaPt", "Jet Pt, Eta, AntiLambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetPtEtaAntiLambdaZ", "Jet Pt, Eta, AntiLambda Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetPtEtaAntiLambdaPtWrongCollision", "Jet Pt, Eta, AntiLambda Pt (Wrong Collision)", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetPtEtaAntiLambdaZWrongCollision", "Jet Pt, Eta, AntiLambda Z (Wrong Collision)", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + + registry.add("jets/JetsPtEta", "Matched Jet Pt, Eta", HistType::kTH3D, {axisJetPt, axisJetPt, axisEta}, doSumw2); + registry.add("jets/JetsPtEtaK0SPt", "Matched Jet Pt, Eta, K0S Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetsPtEtaK0SZ", "Matched Jet Pt, Eta, K0S Z", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetsPtEtaK0SPtWrongCollision", "Matched Jet Pt, Eta, K0S Pt (Wrong Collision)", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetsPtEtaK0SZWrongCollision", "Matched Jet Pt, Eta, K0S Z (Wrong Collision)", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetsPtEtaLambdaPt", "Matched Jet Pt, Eta, Lambda Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetsPtEtaLambdaZ", "Matched Jet Pt, Eta, Lambda Z", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetsPtEtaLambdaPtWrongCollision", "Matched Jet Pt, Eta, Lambda Pt (Wrong Collision)", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetsPtEtaLambdaZWrongCollision", "Matched Jet Pt, Eta, Lambda Z (Wrong Collision)", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetsPtEtaAntiLambdaPt", "Matched Jet Pt, Eta, AntiLambda Pt", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetsPtEtaAntiLambdaZ", "Matched Jet Pt, Eta, AntiLambda Z", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/JetsPtEtaAntiLambdaPtWrongCollision", "Matched Jet Pt, Eta, AntiLambda Pt (Wrong Collision)", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/JetsPtEtaAntiLambdaZWrongCollision", "Matched Jet Pt, Eta, AntiLambda Z (Wrong Collision)", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z}, doSumw2); + } + if (doprocessMcP) { + registry.add("inclusive/hMcEvents", "MC Events", {HistType::kTH1D, {{3, 0.0f, 3.0f}}}, doSumw2); + registry.add("inclusive/GeneratedK0S", "Generated K0S", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Radius}, doSumw2); + registry.add("inclusive/GeneratedLambda", "Generated Lambda", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Radius}, doSumw2); + registry.add("inclusive/GeneratedAntiLambda", "Generated AntiLambda", HistType::kTH3D, {axisV0Pt, axisEta, axisV0Radius}, doSumw2); + + registry.add("jets/GeneratedJets", "Generated Jets", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}, doSumw2); + registry.add("jets/GeneratedJetK0S", "Generated Jet K0S", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/GeneratedJetK0SFrag", "Generated Jet K0S", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/GeneratedJetLambda", "Generated Jet Lambda", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/GeneratedJetLambdaFrag", "Generated Jet Lambda", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + registry.add("jets/GeneratedJetAntiLambda", "Generated Jet AntiLambda", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}, doSumw2); + registry.add("jets/GeneratedJetAntiLambdaFrag", "Generated Jet AntiLambda", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}, doSumw2); + } + 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/JetPtEtaK0SFragMass", "Jet Pt, Eta, K0S Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Z, axisK0SM}); + registry.add("collisions/JetPtEtaK0SPtMassWrongColl", "Jet Pt, Eta, K0S Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisK0SM}); + registry.add("collisions/JetPtEtaK0SFragMassWrongColl", "Jet Pt, Eta, K0S Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Z, axisK0SM}); + registry.add("collisions/JetPtEtaLambdaPtMass", "Jet Pt, Eta, Lambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisLambdaM}); + registry.add("collisions/JetPtEtaLambdaFragMass", "Jet Pt, Eta, Lambda Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Z, axisLambdaM}); + registry.add("collisions/JetPtEtaLambdaPtMassWrongColl", "Jet Pt, Eta, Lambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisLambdaM}); + registry.add("collisions/JetPtEtaLambdaFragMassWrongColl", "Jet Pt, Eta, Lambda Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Z, axisLambdaM}); + registry.add("collisions/JetPtEtaAntiLambdaPtMass", "Jet Pt, Eta, AntiLambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisAntiLambdaM}); + registry.add("collisions/JetPtEtaAntiLambdaFragMass", "Jet Pt, Eta, AntiLambda Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Z, axisAntiLambdaM}); + registry.add("collisions/JetPtEtaAntiLambdaPtMassWrongColl", "Jet Pt, Eta, AntiLambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisAntiLambdaM}); + registry.add("collisions/JetPtEtaAntiLambdaFragMassWrongColl", "Jet Pt, Eta, AntiLambda Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Z, 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/JetsPtEtaK0SFragMass", "Jets Pt, Eta, K0S Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z, axisK0SM}); + registry.add("collisions/JetsPtEtaK0SFragMassWrongColl", "Jets Pt, Eta, K0S Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z, axisK0SM}); + registry.add("collisions/JetsPtEtaLambdaPtMass", "Jets Pt, Eta, Lambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisLambdaM}); + registry.add("collisions/JetsPtEtaLambdaFragMass", "Jets Pt, Eta, Lambda Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z, axisLambdaM}); + registry.add("collisions/JetsPtEtaLambdaPtMassWrongColl", "Jets Pt, Eta, Lambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisLambdaM}); + registry.add("collisions/JetsPtEtaLambdaFragMassWrongColl", "Jets Pt, Eta, Lambda Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z, axisLambdaM}); + registry.add("collisions/JetsPtEtaAntiLambdaPtMass", "Jets Pt, Eta, AntiLambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisAntiLambdaM}); + registry.add("collisions/JetsPtEtaAntiLambdaFragMass", "Jets Pt, Eta, AntiLambda Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z, axisAntiLambdaM}); + registry.add("collisions/JetsPtEtaAntiLambdaPtMassWrongColl", "Jets Pt, Eta, AntiLambda Pt Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Pt, axisAntiLambdaM}); + registry.add("collisions/JetsPtEtaAntiLambdaFragMassWrongColl", "Jets Pt, Eta, AntiLambda Frag Mass", HistType::kTHnSparseD, {axisJetPt, axisJetPt, axisEta, axisV0Z, 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 (doprocessTestWeightedJetFinder) { + registry.add("tests/weighted/hEvents", "Events", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("tests/weighted/V0PtEtaPhi", "V0 Pt Eta Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/weighted/K0SPtEtaPhi", "K0S Pt Eta Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/weighted/LambdaPtEtaPhi", "Lambda Pt Eta Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/weighted/AntiLambdaPtEtaPhi", "AntiLambda Pt Eta Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + + registry.add("tests/weighted/JetPtEtaPhi", "Jet Pt, Eta, Phi", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("tests/weighted/inclJetPtEtaPhi", "Jet Pt, Eta, Phi, inclusive jets", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("tests/weighted/JetPtEtaV0Pt", "Jet Pt, Eta, V0 Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/weighted/JetPtEtaV0Z", "Jet Pt, Eta, V0 Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/weighted/JetPtEtaK0SPt", "Jet Pt, Eta, K0S Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/weighted/JetPtEtaK0SZ", "Jet Pt, Eta, K0S Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/weighted/JetPtEtaLambdaPt", "Jet Pt, Eta, Lambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/weighted/JetPtEtaLambdaZ", "Jet Pt, Eta, Lambda Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/weighted/JetPtEtaAntiLambdaPt", "Jet Pt, Eta, AntiLambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/weighted/JetPtEtaAntiLambdaZ", "Jet Pt, Eta, AntiLambda Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + } + if (doprocessTestSubtractedJetFinder) { + registry.add("tests/hEvents", "Events", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("tests/nosub/V0PtEtaPhi", "V0 Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/nosub/K0SPtEtaPhi", "K0S Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/nosub/LambdaPtEtaPhi", "Lambda Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/nosub/AntiLambdaPtEtaPhi", "AntiLambda Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/sub/V0PtEtaPhi", "V0 Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/sub/K0SPtEtaPhi", "K0S Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/sub/LambdaPtEtaPhi", "Lambda Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("tests/sub/AntiLambdaPtEtaPhi", "AntiLambda Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + + registry.add("tests/nosub/JetPtEtaPhi", "Jet Pt, Eta, Phi", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("tests/nosub/inclJetPtEtaPhi", "Jet Pt, Eta, Phi, inclusive jets", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("tests/nosub/JetPtEtaV0Pt", "Jet Pt, Eta, V0 Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/nosub/JetPtEtaV0Z", "Jet Pt, Eta, V0 Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/nosub/JetPtEtaK0SPt", "Jet Pt, Eta, K0S Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/nosub/JetPtEtaK0SZ", "Jet Pt, Eta, K0S Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/nosub/JetPtEtaLambdaPt", "Jet Pt, Eta, Lambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/nosub/JetPtEtaLambdaZ", "Jet Pt, Eta, Lambda Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/nosub/JetPtEtaAntiLambdaPt", "Jet Pt, Eta, AntiLambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/nosub/JetPtEtaAntiLambdaZ", "Jet Pt, Eta, AntiLambda Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + + registry.add("tests/sub/JetPtEtaPhi", "Jet Pt, Eta, Phi", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("tests/sub/JetPtEtaPhiAllV0sSubtracted", "Jet Pt, Eta, Phi (All V0s Subtracted)", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("tests/sub/JetPtEtaV0Pt", "Jet Pt, Eta, V0 Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/sub/JetPtEtaV0Z", "Jet Pt, Eta, V0 Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/sub/JetPtEtaK0SPt", "Jet Pt, Eta, K0S Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/sub/JetPtEtaK0SZ", "Jet Pt, Eta, K0S Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/sub/JetPtEtaLambdaPt", "Jet Pt, Eta, Lambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/sub/JetPtEtaLambdaZ", "Jet Pt, Eta, Lambda Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("tests/sub/JetPtEtaAntiLambdaPt", "Jet Pt, Eta, AntiLambda Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("tests/sub/JetPtEtaAntiLambdaZ", "Jet Pt, Eta, AntiLambda Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + } + if (doprocessTestV0DaughterSharing) { + registry.add("sharing/hEvents", "Events", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + registry.add("sharing/V0PtEtaPhi", "V0 Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("sharing/K0SPtEtaPhi", "K0S Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("sharing/LambdaPtEtaPhi", "Lambda Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + registry.add("sharing/AntiLambdaPtEtaPhi", "AntiLambda Pt, Eta, Phi", HistType::kTH3D, {axisV0Pt, axisEta, axisPhi}); + + registry.add("sharing/V0PtEtaPt", "V0s w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/V0PtEtaPtDaughterPt", "V0s w shared daughter and daughter pt", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/K0SK0S", "K0S-K0S w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/K0SLambda", "K0S-Lambda w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/K0SAntiLambda", "K0S-AntiLambda w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/LambdaK0S", "Lambda-K0S w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/LambdaLambda", "Lambda-Lambda w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/LambdaAntiLambda", "Lambda-AntiLambda w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/AntiLambdaK0S", "AntiLambda-K0S w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/AntiLambdaLambda", "AntiLambda-Lambda w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + registry.add("sharing/AntiLambdaAntiLambda", "AntiLambda-AntiLambda w shared daughter", HistType::kTHnSparseD, {axisV0Pt, axisEta, axisV0Pt}); + + registry.add("sharing/JetPtEtaPhi", "JetPtEtaPhi", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("sharing/JetPtEtaPhiNone", "JetPtEtaPhiNone", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("sharing/JetPtEtaPhiSingle", "JetPtEtaPhiSingle", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("sharing/JetPtEtaPhiMultiple", "JetPtEtaPhiMultiple", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("sharing/JetPtEtaPhiShared", "JetPtEtaPhiShared", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + registry.add("sharing/JetPtEtaPhiNoShared", "JetPtEtaPhiNoShared", HistType::kTH3D, {axisJetPt, axisEta, axisPhi}); + + registry.add("sharing/JetPtEtaV0Pt", "JetPtEtaV0Pt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("sharing/JetPtEtaK0SPt", "JetPtEtaK0SPt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("sharing/JetPtEtaLambdaPt", "JetPtEtaLambdaPt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("sharing/JetPtEtaAntiLambdaPt", "JetPtEtaAntiLambdaPt", HistType::kTH3D, {axisJetPt, axisEta, axisV0Pt}); + registry.add("sharing/JetPtEtaV0PtPt", "JetPtEtaV0PtPt", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetPtEtaV0PtPtDaughterPt", "JetPtEtaV0PtPtDaughterPt", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt, axisV0Pt}); + + registry.add("sharing/JetPtEtaV0Z", "JetPtEtaV0Z", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("sharing/JetPtEtaK0SZ", "JetPtEtaK0SZ", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("sharing/JetPtEtaLambdaZ", "JetPtEtaLambdaZ", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("sharing/JetPtEtaAntiLambdaZ", "JetPtEtaAntiLambdaZ", HistType::kTH3D, {axisJetPt, axisEta, axisV0Z}); + registry.add("sharing/JetPtEtaV0ZZ", "JetPtEtaV0ZZ", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Z, axisV0Z}); + registry.add("sharing/JetPtEtaV0ZZDaughterPt", "JetPtEtaV0ZZDaughterPt", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Z, axisV0Z, axisV0Pt}); + + registry.add("sharing/JetK0SK0S", "JetK0SK0S", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetK0SLambda", "JetK0SLambda", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetK0SAntiLambda", "JetK0SAntiLambda", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetLambdaK0S", "JetLambdaK0S", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetLambdaLambda", "JetLambdaLambda", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetLambdaAntiLambda", "JetLambdaAntiLambda", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetAntiLambdaK0S", "JetAntiLambdaK0S", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetAntiLambdaLambda", "JetAntiLambdaLambda", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + registry.add("sharing/JetAntiLambdaAntiLambda", "JetAntiLambdaAntiLambda", HistType::kTHnSparseD, {axisJetPt, axisEta, axisV0Pt, axisV0Pt}); + } + if (doprocessV0TrackQA) { + registry.add("tracks/hEvents", "evts", {HistType::kTH1D, {{2, 0.0f, 2.0f}}}); + 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 v0sShareDaughter(U const& trigger, U const& associate) + { + // LOGF(info, "Checking if V0s share daughter"); + auto trigNeg = trigger.template negTrack_as(); + auto trigPos = trigger.template posTrack_as(); + auto assocNeg = associate.template negTrack_as(); + auto assocPos = associate.template posTrack_as(); + return (trigNeg == assocNeg || trigNeg == assocPos || trigPos == assocNeg || trigPos == assocPos); + } + template + bool genV0PassesEfficiencyCuts(T const& pv0) + { + if (!pv0.has_daughters() || !pv0.isPhysicalPrimary()) + return false; + if (std::abs(pv0.y()) > yPartMax) + return false; + + return true; + } + template + bool recV0PassesEfficiencyCuts(T const& v0) + { + if (!v0.has_mcParticle() || v0.isRejectedCandidate()) + return false; + + return true; + } + + template + bool hasITSHit(T const& track, int layer) + { + int ibit = layer - 1; + return (track.itsClusterMap() & (1 << ibit)); + } + + bool isV0RandomlyRejected() + { + return (gRandom->Uniform() > v0Fraction); + } + + template + void fillMcDV0(T const& v0, U const& pv0, bool correctCollision, double weight) + { + int pdg = pv0.pdgCode(); + double pt = pv0.pt(); + double eta = v0.eta(); + double radius = v0.v0radius(); + + if (std::abs(pdg) == PDG_t::kK0Short) { + registry.fill(HIST("inclusive/K0SPtEtaMass"), pt, eta, v0.mK0Short(), weight); + registry.fill(HIST("inclusive/InvMassK0STrue"), pt, radius, v0.mK0Short(), weight); + if (!correctCollision) + registry.fill(HIST("inclusive/K0SPtEtaMassWrongCollision"), pt, eta, v0.mK0Short(), weight); + } else if (pdg == PDG_t::kLambda0) { + registry.fill(HIST("inclusive/LambdaPtEtaMass"), pt, eta, v0.mLambda(), weight); + registry.fill(HIST("inclusive/InvMassLambdaTrue"), pt, radius, v0.mLambda(), weight); + if (!correctCollision) + registry.fill(HIST("inclusive/LambdaPtEtaMassWrongCollision"), pt, eta, v0.mLambda(), weight); + } else if (pdg == PDG_t::kLambda0Bar) { + registry.fill(HIST("inclusive/AntiLambdaPtEtaMass"), pt, eta, v0.mAntiLambda(), weight); + registry.fill(HIST("inclusive/InvMassAntiLambdaTrue"), pt, radius, v0.mAntiLambda(), weight); + if (!correctCollision) + registry.fill(HIST("inclusive/AntiLambdaPtEtaMassWrongCollision"), pt, eta, v0.mAntiLambda(), weight); + } + } + + template + void fillMcDJets(U const& mcdjet, double weight) + { + registry.fill(HIST("jets/JetPtEtaPhi"), mcdjet.pt(), mcdjet.eta(), mcdjet.phi(), weight); + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + registry.fill(HIST("jets/JetsPtEta"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), weight); + } + } + template + void fillMcDV0InJets(T const& mcdjet, U const& v0, V const& pv0, bool correctCollision, double weight) + { + int pdg = v0.mcParticle().pdgCode(); + double pt = pv0.pt(); + double ptjet = mcdjet.pt(); + double eta = mcdjet.eta(); + double z = pt / ptjet; + + if (std::abs(pdg) == PDG_t::kK0Short) { + registry.fill(HIST("jets/JetPtEtaK0SPt"), ptjet, eta, pt, weight); + registry.fill(HIST("jets/JetPtEtaK0SZ"), ptjet, eta, z, weight); + if (!correctCollision) { + registry.fill(HIST("jets/JetPtEtaK0SPtWrongCollision"), ptjet, eta, pt, weight); + registry.fill(HIST("jets/JetPtEtaK0SZWrongCollision"), ptjet, eta, z, weight); + } + } else if (pdg == PDG_t::kLambda0) { + registry.fill(HIST("jets/JetPtEtaLambdaPt"), ptjet, eta, pt, weight); + registry.fill(HIST("jets/JetPtEtaLambdaZ"), ptjet, eta, z, weight); + if (!correctCollision) { + registry.fill(HIST("jets/JetPtEtaLambdaPtWrongCollision"), ptjet, eta, pt, weight); + registry.fill(HIST("jets/JetPtEtaLambdaZWrongCollision"), ptjet, eta, z, weight); + } + } else if (pdg == PDG_t::kLambda0Bar) { + registry.fill(HIST("jets/JetPtEtaAntiLambdaPt"), ptjet, eta, pt, weight); + registry.fill(HIST("jets/JetPtEtaAntiLambdaZ"), ptjet, eta, z, weight); + if (!correctCollision) { + registry.fill(HIST("jets/JetPtEtaAntiLambdaPtWrongCollision"), ptjet, eta, pt, weight); + registry.fill(HIST("jets/JetPtEtaAntiLambdaZWrongCollision"), ptjet, eta, z, weight); + } + } + } + + template + void fillMcDV0InMatchedJets(T const& mcpjet, U const& mcdjet, V const& v0, W const& pv0, bool correctCollision, double weight) + { + int pdg = v0.mcParticle().pdgCode(); + double ptjetmcp = mcpjet.pt(); + double ptjetmcd = mcdjet.pt(); + double eta = mcdjet.eta(); + double pt = pv0.pt(); + double z = pt / ptjetmcp; + + if (std::abs(pdg) == PDG_t::kK0Short) { + registry.fill(HIST("jets/JetsPtEtaK0SPt"), ptjetmcp, ptjetmcd, eta, pt, weight); + registry.fill(HIST("jets/JetsPtEtaK0SZ"), ptjetmcp, ptjetmcd, eta, z, weight); + if (!correctCollision) { + registry.fill(HIST("jets/JetsPtEtaK0SPtWrongCollision"), ptjetmcp, ptjetmcd, eta, pt, weight); + registry.fill(HIST("jets/JetsPtEtaK0SZWrongCollision"), ptjetmcp, ptjetmcd, eta, z, weight); + } + } else if (pdg == PDG_t::kLambda0) { + registry.fill(HIST("jets/JetsPtEtaLambdaPt"), ptjetmcp, ptjetmcd, eta, pt, weight); + registry.fill(HIST("jets/JetsPtEtaLambdaZ"), ptjetmcp, ptjetmcd, eta, z, weight); + if (!correctCollision) { + registry.fill(HIST("jets/JetsPtEtaLambdaPtWrongCollision"), ptjetmcp, ptjetmcd, eta, pt, weight); + registry.fill(HIST("jets/JetsPtEtaLambdaZWrongCollision"), ptjetmcp, ptjetmcd, eta, z, weight); + } + } else if (pdg == PDG_t::kLambda0Bar) { + registry.fill(HIST("jets/JetsPtEtaAntiLambdaPt"), ptjetmcp, ptjetmcd, eta, pt, weight); + registry.fill(HIST("jets/JetsPtEtaAntiLambdaZ"), ptjetmcp, ptjetmcd, eta, z, weight); + if (!correctCollision) { + registry.fill(HIST("jets/JetsPtEtaAntiLambdaPtWrongCollision"), ptjetmcp, ptjetmcd, eta, pt, weight); + registry.fill(HIST("jets/JetsPtEtaAntiLambdaZWrongCollision"), ptjetmcp, ptjetmcd, eta, z, weight); + } + } + } + + template + void fillMcPV0(T const& pv0, double weight) + { + // Can calculate this from aod::CandidatesV0MCD (contains decay vertex) + double rDecay = 1.0; + + if (pv0.pdgCode() == PDG_t::kK0Short) { + registry.fill(HIST("inclusive/GeneratedK0S"), pv0.pt(), pv0.eta(), rDecay, weight); + } + if (pv0.pdgCode() == PDG_t::kLambda0) { + registry.fill(HIST("inclusive/GeneratedLambda"), pv0.pt(), pv0.eta(), rDecay, weight); + } + if (pv0.pdgCode() == PDG_t::kLambda0Bar) { + registry.fill(HIST("inclusive/GeneratedAntiLambda"), pv0.pt(), pv0.eta(), rDecay, weight); + } + } + + template + void fillMcPJets(T const& jet, double weight) + { + registry.fill(HIST("jets/GeneratedJets"), jet.pt(), jet.eta(), jet.phi(), weight); + } + + template + void fillMcPV0InJets(T const& jet, U const& pv0, double weight) + { + double z = pv0.pt() / jet.pt(); + if (pv0.pdgCode() == PDG_t::kK0Short) { + registry.fill(HIST("jets/GeneratedJetK0S"), jet.pt(), jet.eta(), pv0.pt(), weight); + registry.fill(HIST("jets/GeneratedJetK0SFrag"), jet.pt(), jet.eta(), z, weight); + } + if (pv0.pdgCode() == PDG_t::kLambda0) { + registry.fill(HIST("jets/GeneratedJetLambda"), jet.pt(), jet.eta(), pv0.pt(), weight); + registry.fill(HIST("jets/GeneratedJetLambdaFrag"), jet.pt(), jet.eta(), z, weight); + } + if (pv0.pdgCode() == PDG_t::kLambda0Bar) { + registry.fill(HIST("jets/GeneratedJetAntiLambda"), jet.pt(), jet.eta(), pv0.pt(), weight); + registry.fill(HIST("jets/GeneratedJetAntiLambdaFrag"), jet.pt(), jet.eta(), z, weight); + } + } + + template + void fillWeightedJetFinderInclusiveV0(T const& v0) + { + registry.fill(HIST("tests/weighted/V0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (v0.isK0SCandidate()) + registry.fill(HIST("tests/weighted/K0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (v0.isLambdaCandidate()) + registry.fill(HIST("tests/weighted/LambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (v0.isAntiLambdaCandidate()) + registry.fill(HIST("tests/weighted/AntiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + } + + template + void fillWeightedJetFinderJet(T const& jet) + { + registry.fill(HIST("tests/weighted/inclJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + if (jet.candidatesIds().size() > 0) + registry.fill(HIST("tests/weighted/JetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + } + + template + void fillWeightedJetFinderV0InJet(T const& jet, U const& v0) + { + double z = v0.pt() / jet.pt(); + registry.fill(HIST("tests/weighted/JetPtEtaV0Pt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("tests/weighted/JetPtEtaV0Z"), jet.pt(), jet.eta(), z); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("tests/weighted/JetPtEtaK0SPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("tests/weighted/JetPtEtaK0SZ"), jet.pt(), jet.eta(), z); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("tests/weighted/JetPtEtaLambdaPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("tests/weighted/JetPtEtaLambdaZ"), jet.pt(), jet.eta(), z); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("tests/weighted/JetPtEtaAntiLambdaPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("tests/weighted/JetPtEtaAntiLambdaZ"), jet.pt(), jet.eta(), z); + } + } + + template + void fillSubtractedJetFinderInclusiveV0(T const& v0) + { + bool randomlyRejected = isV0RandomlyRejected(); + + registry.fill(HIST("tests/nosub/V0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (!randomlyRejected) + registry.fill(HIST("tests/sub/V0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + + if (v0.isK0SCandidate()) { + registry.fill(HIST("tests/nosub/K0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (!randomlyRejected) + registry.fill(HIST("tests/sub/K0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("tests/nosub/LambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (!randomlyRejected) + registry.fill(HIST("tests/sub/LambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("tests/nosub/AntiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (!randomlyRejected) + registry.fill(HIST("tests/sub/AntiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + } + } + + template + void fillSubtractedJetFinderJetNoSubtraction(T const& jet) + { + registry.fill(HIST("tests/nosub/inclJetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + if (jet.candidatesIds().size() > 0) + registry.fill(HIST("tests/nosub/JetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + } + + template + void fillSubtractedJetFinderV0InJetNoSubtraction(T const& jet, U const& v0) + { + double z = v0.pt() / jet.pt(); + registry.fill(HIST("tests/nosub/JetPtEtaV0Pt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("tests/nosub/JetPtEtaV0Z"), jet.pt(), jet.eta(), z); + if (v0.isK0SCandidate()) { + registry.fill(HIST("tests/nosub/JetPtEtaK0SPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("tests/nosub/JetPtEtaK0SZ"), jet.pt(), jet.eta(), z); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("tests/nosub/JetPtEtaLambdaPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("tests/nosub/JetPtEtaLambdaZ"), jet.pt(), jet.eta(), z); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("tests/nosub/JetPtEtaAntiLambdaPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("tests/nosub/JetPtEtaAntiLambdaZ"), jet.pt(), jet.eta(), z); + } + } + + template + void fillSubtractedJetFinderJetSubtracted(T const& jet, double ptjetsub, bool allV0sSubtracted) + { + registry.fill(HIST("tests/sub/JetPtEtaPhi"), ptjetsub, jet.eta(), jet.phi()); + if (allV0sSubtracted) + registry.fill(HIST("tests/sub/JetPtEtaPhiAllV0sSubtracted"), ptjetsub, jet.eta(), jet.phi()); + } + + void fillSubtractedJetFinderV0InJetSubtracted(const double ptjetsub, const double etajet, const double v0Pt, const int v0Type) + { + double z = v0Pt / ptjetsub; + registry.fill(HIST("tests/sub/JetPtEtaV0Pt"), ptjetsub, etajet, v0Pt); + registry.fill(HIST("tests/sub/JetPtEtaV0Z"), ptjetsub, etajet, z); + + if (v0Type == PDG_t::kK0Short) { + registry.fill(HIST("tests/sub/JetPtEtaK0SPt"), ptjetsub, etajet, v0Pt); + registry.fill(HIST("tests/sub/JetPtEtaK0SZ"), ptjetsub, etajet, z); + } else if (v0Type == PDG_t::kLambda0) { + registry.fill(HIST("tests/sub/JetPtEtaLambdaPt"), ptjetsub, etajet, v0Pt); + registry.fill(HIST("tests/sub/JetPtEtaLambdaZ"), ptjetsub, etajet, z); + } else if (v0Type == PDG_t::kLambda0Bar) { + registry.fill(HIST("tests/sub/JetPtEtaAntiLambdaPt"), ptjetsub, etajet, v0Pt); + registry.fill(HIST("tests/sub/JetPtEtaAntiLambdaZ"), ptjetsub, etajet, z); + } + } + + template + void fillV0DaughterSharingInclusive(T const& v0) + { + registry.fill(HIST("sharing/V0PtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (v0.isK0SCandidate()) + registry.fill(HIST("sharing/K0SPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (v0.isLambdaCandidate()) + registry.fill(HIST("sharing/LambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + if (v0.isAntiLambdaCandidate()) + registry.fill(HIST("sharing/AntiLambdaPtEtaPhi"), v0.pt(), v0.eta(), v0.phi()); + } + + template + void fillV0DaughterSharingInclusive(V const& trigger, V const& associate) + { + double weight = 0.5; // To correct for double-counting + double pthard, etahard, ptsoft; + if (trigger.pt() > associate.pt()) { + pthard = trigger.pt(); + etahard = trigger.eta(); + ptsoft = associate.pt(); + } else { + pthard = associate.pt(); + etahard = associate.eta(); + ptsoft = trigger.pt(); + } + + registry.fill(HIST("sharing/V0PtEtaPt"), pthard, etahard, ptsoft, weight); + // Tried to get this in a function, but couldn't make it work + auto trigNeg = trigger.template negTrack_as().template track_as(); + auto trigPos = trigger.template posTrack_as().template track_as(); + auto assocNeg = associate.template negTrack_as().template track_as(); + auto assocPos = associate.template posTrack_as().template track_as(); + double sharedDaughterPt; + if (trigNeg == assocNeg || trigNeg == assocPos) + sharedDaughterPt = trigNeg.pt(); + else + sharedDaughterPt = trigPos.pt(); + registry.fill(HIST("sharing/V0PtEtaPtDaughterPt"), pthard, etahard, ptsoft, sharedDaughterPt, weight); + + if (trigger.isK0SCandidate() && associate.isK0SCandidate()) + registry.fill(HIST("sharing/K0SK0S"), pthard, etahard, ptsoft, weight); + if (trigger.isK0SCandidate() && associate.isLambdaCandidate()) + registry.fill(HIST("sharing/K0SLambda"), pthard, etahard, ptsoft, weight); + if (trigger.isK0SCandidate() && associate.isAntiLambdaCandidate()) + registry.fill(HIST("sharing/K0SAntiLambda"), pthard, etahard, ptsoft, weight); + + if (trigger.isLambdaCandidate() && associate.isK0SCandidate()) + registry.fill(HIST("sharing/LambdaK0S"), pthard, etahard, ptsoft, weight); + if (trigger.isLambdaCandidate() && associate.isLambdaCandidate()) + registry.fill(HIST("sharing/LambdaLambda"), pthard, etahard, ptsoft, weight); + if (trigger.isLambdaCandidate() && associate.isAntiLambdaCandidate()) + registry.fill(HIST("sharing/LambdaAntiLambda"), pthard, etahard, ptsoft, weight); + + if (trigger.isAntiLambdaCandidate() && associate.isK0SCandidate()) + registry.fill(HIST("sharing/AntiLambdaK0S"), pthard, etahard, ptsoft, weight); + if (trigger.isAntiLambdaCandidate() && associate.isLambdaCandidate()) + registry.fill(HIST("sharing/AntiLambdaLambda"), pthard, etahard, ptsoft, weight); + if (trigger.isAntiLambdaCandidate() && associate.isAntiLambdaCandidate()) + registry.fill(HIST("sharing/AntiLambdaAntiLambda"), pthard, etahard, ptsoft, weight); + } + + template + void fillV0DaughterSharingJet(T const& jet, bool jetContainsSharedDaughters) + { + registry.fill(HIST("sharing/JetPtEtaPhi"), jet.pt(), jet.eta(), jet.phi()); + if (jet.candidatesIds().size() == 0) + registry.fill(HIST("sharing/JetPtEtaPhiNone"), jet.pt(), jet.eta(), jet.phi()); + else if (jet.candidatesIds().size() == 1) + registry.fill(HIST("sharing/JetPtEtaPhiSingle"), jet.pt(), jet.eta(), jet.phi()); + else + registry.fill(HIST("sharing/JetPtEtaPhiMultiple"), jet.pt(), jet.eta(), jet.phi()); + + if (jetContainsSharedDaughters) + registry.fill(HIST("sharing/JetPtEtaPhiShared"), jet.pt(), jet.eta(), jet.phi()); + else + registry.fill(HIST("sharing/JetPtEtaPhiNoShared"), jet.pt(), jet.eta(), jet.phi()); + } + + template + void fillV0DaughterSharingJet(T const& jet, U const& v0) + { + double z = v0.pt() / jet.pt(); + registry.fill(HIST("sharing/JetPtEtaV0Pt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("sharing/JetPtEtaV0Z"), jet.pt(), jet.eta(), z); + if (v0.isK0SCandidate()) { + registry.fill(HIST("sharing/JetPtEtaK0SPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("sharing/JetPtEtaK0SZ"), jet.pt(), jet.eta(), z); + } + if (v0.isLambdaCandidate()) { + registry.fill(HIST("sharing/JetPtEtaLambdaPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("sharing/JetPtEtaLambdaZ"), jet.pt(), jet.eta(), z); + } + if (v0.isAntiLambdaCandidate()) { + registry.fill(HIST("sharing/JetPtEtaAntiLambdaPt"), jet.pt(), jet.eta(), v0.pt()); + registry.fill(HIST("sharing/JetPtEtaAntiLambdaZ"), jet.pt(), jet.eta(), z); + } + } + + template + void fillV0DaughterSharingJet(V const& jet, W const& trigger, W const& associate) + { + double weight = 0.5; // To correct for double-counting + double pthard, ptsoft; + if (trigger.pt() > associate.pt()) { + pthard = trigger.pt(); + ptsoft = associate.pt(); + } else { + pthard = associate.pt(); + ptsoft = trigger.pt(); + } + + double zhard = pthard / jet.pt(); + double zsoft = ptsoft / jet.pt(); + + registry.fill(HIST("sharing/JetPtEtaV0PtPt"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + registry.fill(HIST("sharing/JetPtEtaV0ZZ"), jet.pt(), jet.eta(), zhard, zsoft, weight); + auto trigNeg = trigger.template negTrack_as().template track_as(); + auto trigPos = trigger.template posTrack_as().template track_as(); + auto assocNeg = associate.template negTrack_as().template track_as(); + auto assocPos = associate.template posTrack_as().template track_as(); + double sharedDaughterPt; + if (trigNeg == assocNeg || trigNeg == assocPos) + sharedDaughterPt = trigNeg.pt(); + else + sharedDaughterPt = trigPos.pt(); + + registry.fill(HIST("sharing/JetPtEtaV0PtPtDaughterPt"), jet.pt(), jet.eta(), pthard, ptsoft, sharedDaughterPt, weight); + registry.fill(HIST("sharing/JetPtEtaV0ZZDaughterPt"), jet.pt(), jet.eta(), zhard, zsoft, sharedDaughterPt, weight); + + if (trigger.isK0SCandidate() && associate.isK0SCandidate()) + registry.fill(HIST("sharing/JetK0SK0S"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + if (trigger.isK0SCandidate() && associate.isLambdaCandidate()) + registry.fill(HIST("sharing/JetK0SLambda"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + if (trigger.isK0SCandidate() && associate.isAntiLambdaCandidate()) + registry.fill(HIST("sharing/JetK0SAntiLambda"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + + if (trigger.isLambdaCandidate() && associate.isK0SCandidate()) + registry.fill(HIST("sharing/JetLambdaK0S"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + if (trigger.isLambdaCandidate() && associate.isLambdaCandidate()) + registry.fill(HIST("sharing/JetLambdaLambda"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + if (trigger.isLambdaCandidate() && associate.isAntiLambdaCandidate()) + registry.fill(HIST("sharing/JetLambdaAntiLambda"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + + if (trigger.isAntiLambdaCandidate() && associate.isK0SCandidate()) + registry.fill(HIST("sharing/JetAntiLambdaK0S"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + if (trigger.isAntiLambdaCandidate() && associate.isLambdaCandidate()) + registry.fill(HIST("sharing/JetAntiLambdaLambda"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + if (trigger.isAntiLambdaCandidate() && associate.isAntiLambdaCandidate()) + registry.fill(HIST("sharing/JetAntiLambdaAntiLambda"), jet.pt(), jet.eta(), pthard, ptsoft, weight); + } + + 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, CandidatesV0MCDWithFlags const& v0s, aod::McParticles const&, MatchedMCDV0JetsWithConstituents const& mcdjets, MatchedMCPV0JetsWithConstituents const&, aod::CandidatesV0MCP const&, aod::JetTracksMCD const& jTracks, JetMcCollisionsWithPIs const&, aod::McCollisions const&) + { + registry.fill(HIST("inclusive/hEvents"), 0.5); + if (!isCollisionReconstructed(jcoll, eventSelectionBits)) { + return; + } + registry.fill(HIST("inclusive/hEvents"), 1.5); + auto mcColl = jcoll.template mcCollision_as(); + double weight = mcColl.weight(); + registry.fill(HIST("inclusive/hEvents"), 2.5, weight); + + for (const auto& v0 : v0s) { + if (!recV0PassesEfficiencyCuts(v0)) + continue; + + auto pv0 = v0.mcParticle(); + if (!genV0PassesEfficiencyCuts(pv0)) + continue; + + bool correctCollision = (mcColl.mcCollisionId() == v0.mcParticle().mcCollisionId()); + fillMcDV0(v0, pv0, correctCollision, weight); + } // v0 loop + + for (const auto& mcdjet : mcdjets) { + fillMcDJets(mcdjet, weight); + + for (const auto& v0 : mcdjet.template candidates_as()) { + if (!recV0PassesEfficiencyCuts(v0)) + continue; + + auto pv0 = v0.mcParticle(); + if (!genV0PassesEfficiencyCuts(pv0)) + continue; + + bool correctCollision = (mcColl.mcCollisionId() == v0.mcParticle().mcCollisionId()); + fillMcDV0InJets(mcdjet, v0, pv0, correctCollision, weight); + + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + for (const auto& pv0injet : mcpjet.template candidates_as()) { + if (!genV0PassesEfficiencyCuts(pv0injet)) + continue; + if (!v0sAreMatched(v0, pv0injet, jTracks)) + continue; + + fillMcDV0InMatchedJets(mcpjet, mcdjet, v0, pv0, correctCollision, weight); + } // v0 particle loop + } // mcpjet loop + } // v0 loop + } // mcd jet loop + } + PROCESS_SWITCH(V0QA, processMcD, "Reconstructed true V0s", false); + + void processMcP(aod::JetMcCollision const& mccoll, soa::SmallGroups const& collisions, MCPV0JetsWithConstituents const& jets, aod::CandidatesV0MCP const& pv0s) + { + 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(); + registry.fill(HIST("inclusive/hMcEvents"), 2.5, weight); + + for (const auto& pv0 : pv0s) { + if (!genV0PassesEfficiencyCuts(pv0)) + continue; + + fillMcPV0(pv0, weight); + } + + for (const auto& jet : jets) { + if (!jetfindingutilities::isInEtaAcceptance(jet, -99., -99., -1. * yPartMax, yPartMax)) + continue; + + fillMcPJets(jet, weight); + + for (const auto& pv0 : jet.template candidates_as()) { + if (!genV0PassesEfficiencyCuts(pv0)) + continue; + + fillMcPV0InJets(jet, pv0, weight); + } + } + } + PROCESS_SWITCH(V0QA, processMcP, "Particle level V0s", false); + + void processCollisionAssociation(soa::Filtered::iterator const& jcoll, CandidatesV0MCDWithFlags const& v0s, JetMcCollisionsWithPIs 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) == PDG_t::kK0Short) { + 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 == PDG_t::kLambda0) { + 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 == PDG_t::kLambda0Bar) { + 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 == PDG_t::kXiMinus) { + 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 == PDG_t::kXiPlusBar) { + 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&, JetMcCollisionsWithPIs const&, aod::McCollisions const&, aod::McParticles const&) + { + if (!isCollisionReconstructed(jcoll, eventSelectionBits)) + 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(); + double z = v0.pt() / mcdjet.pt(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + + registry.fill(HIST("collisions/JetPtEtaV0Pt"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaV0PtWrongColl"), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + } + if (std::abs(pdg) == PDG_t::kK0Short) { + registry.fill(HIST("collisions/JetPtEtaK0SPtMass"), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("collisions/JetPtEtaK0SFragMass"), mcdjet.pt(), mcdjet.eta(), z, v0.mK0Short(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaK0SPtMassWrongColl"), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("collisions/JetPtEtaK0SFragMassWrongColl"), mcdjet.pt(), mcdjet.eta(), z, v0.mK0Short(), weight); + } + } + if (pdg == PDG_t::kLambda0) { + registry.fill(HIST("collisions/JetPtEtaLambdaPtMass"), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("collisions/JetPtEtaLambdaFragMass"), mcdjet.pt(), mcdjet.eta(), z, v0.mLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaLambdaPtMassWrongColl"), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("collisions/JetPtEtaLambdaFragMassWrongColl"), mcdjet.pt(), mcdjet.eta(), z, v0.mLambda(), weight); + } + } + if (pdg == PDG_t::kLambda0Bar) { + registry.fill(HIST("collisions/JetPtEtaAntiLambdaPtMass"), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("collisions/JetPtEtaAntiLambdaFragMass"), mcdjet.pt(), mcdjet.eta(), z, v0.mAntiLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaAntiLambdaPtMassWrongColl"), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("collisions/JetPtEtaAntiLambdaFragMassWrongColl"), mcdjet.pt(), mcdjet.eta(), z, v0.mAntiLambda(), weight); + } + } + + if (!v0.has_mcMotherParticle()) + continue; + + auto mother = v0.mcMotherParticle(); + pdg = mother.pdgCode(); + correctCollision = (mcColl.mcCollisionId() == mother.mcCollisionId()); + if (pdg == PDG_t::kXiMinus) { + registry.fill(HIST("collisions/JetPtEtaXiMinusPtLambdaPt"), mcdjet.pt(), mcdjet.eta(), mother.pt(), v0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaXiMinusPtLambdaPtWrongColl"), mcdjet.pt(), mcdjet.eta(), mother.pt(), v0.pt(), weight); + } + } + if (pdg == PDG_t::kXiPlusBar) { + registry.fill(HIST("collisions/JetPtEtaXiPlusPtAntiLambdaPt"), mcdjet.pt(), mcdjet.eta(), mother.pt(), v0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetPtEtaXiPlusPtAntiLambdaPtWrongColl"), mcdjet.pt(), mcdjet.eta(), mother.pt(), v0.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&, JetMcCollisionsWithPIs 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()); + double z = v0.pt() / mcdjet.pt(); + + // Check V0 decay kinematics + if (v0.isRejectedCandidate()) + continue; + + registry.fill(HIST("collisions/JetsPtEtaV0Pt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaV0PtWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), weight); + } + if (std::abs(pdg) == PDG_t::kK0Short) { + registry.fill(HIST("collisions/JetsPtEtaK0SPtMass"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("collisions/JetsPtEtaK0SFragMass"), mcpjet.pt(), mcdjet.eta(), z, v0.mK0Short(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaK0SPtMassWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mK0Short(), weight); + registry.fill(HIST("collisions/JetsPtEtaK0SFragMassWrongColl"), mcpjet.pt(), mcdjet.eta(), z, v0.mK0Short(), weight); + } + } + if (pdg == PDG_t::kLambda0) { + registry.fill(HIST("collisions/JetsPtEtaLambdaPtMass"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("collisions/JetsPtEtaLambdaFragMass"), mcpjet.pt(), mcdjet.eta(), z, v0.mLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaLambdaPtMassWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mLambda(), weight); + registry.fill(HIST("collisions/JetsPtEtaLambdaFragMassWrongColl"), mcpjet.pt(), mcdjet.eta(), z, v0.mLambda(), weight); + } + } + if (pdg == PDG_t::kLambda0Bar) { + registry.fill(HIST("collisions/JetsPtEtaAntiLambdaPtMass"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("collisions/JetsPtEtaAntiLambdaFragMass"), mcpjet.pt(), mcdjet.eta(), z, v0.mAntiLambda(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaAntiLambdaPtMassWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), v0.pt(), v0.mAntiLambda(), weight); + registry.fill(HIST("collisions/JetsPtEtaAntiLambdaFragMassWrongColl"), mcpjet.pt(), mcdjet.eta(), z, v0.mAntiLambda(), weight); + } + } + + if (!v0.has_mcMotherParticle()) + continue; + + auto mother = v0.mcMotherParticle(); + pdg = mother.pdgCode(); + correctCollision = (mcColl.mcCollisionId() == mother.mcCollisionId()); + if (pdg == PDG_t::kXiMinus) { + registry.fill(HIST("collisions/JetsPtEtaXiMinusPtLambdaPt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), mother.pt(), v0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaXiMinusPtLambdaPtWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), mother.pt(), v0.pt(), weight); + } + } + if (pdg == PDG_t::kXiPlusBar) { + registry.fill(HIST("collisions/JetsPtEtaXiPlusPtAntiLambdaPt"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), mother.pt(), v0.pt(), weight); + if (!correctCollision) { + registry.fill(HIST("collisions/JetsPtEtaXiPlusPtAntiLambdaPtWrongColl"), mcpjet.pt(), mcdjet.pt(), mcdjet.eta(), mother.pt(), v0.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&, JetMcCollisionsWithPIs 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 == PDG_t::kXiMinus) { + registry.fill(HIST("feeddown/XiMinusPtYLambdaPt"), mother.pt(), mother.y(), pv0.pt(), weight); + } + if (pdg == PDG_t::kXiPlusBar) { + 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&, JetMcCollisionsWithPIs 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 == PDG_t::kXiMinus) { + registry.fill(HIST("feeddown/JetPtXiMinusPtLambdaPt"), mcdjet.pt(), mother.pt(), pv0.pt(), weight); + } + if (pdg == PDG_t::kXiPlusBar) { + 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&, JetMcCollisionsWithPIs 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 == PDG_t::kXiMinus) { + registry.fill(HIST("feeddown/JetsPtXiMinusPtLambdaPt"), mcpjet.pt(), mcdjet.pt(), mother.pt(), pv0.pt(), weight); + } + if (pdg == PDG_t::kXiPlusBar) { + registry.fill(HIST("feeddown/JetsPtXiPlusPtAntiLambdaPt"), mcpjet.pt(), mcdjet.pt(), mother.pt(), pv0.pt(), weight); + } + } + } + } + } + } + PROCESS_SWITCH(V0QA, processFeeddownMatchedJets, "Jets feeddown", false); + + // Test the difference between excluding V0s from jet finding and subtracting V0s from jets afterwards + void processTestWeightedJetFinder(soa::Filtered::iterator const& jcoll, V0ChargedJetsWithConstituents const& jets, aod::CandidatesV0Data const& v0s) + { + registry.fill(HIST("tests/weighted/hEvents"), 0.5); + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) + return; + + registry.fill(HIST("tests/weighted/hEvents"), 1.5); + + for (const auto& v0 : v0s) { + if (v0.isRejectedCandidate()) + continue; + + fillWeightedJetFinderInclusiveV0(v0); + } + + for (const auto& jet : jets) { + fillWeightedJetFinderJet(jet); + + for (const auto& v0 : jet.template candidates_as()) { + if (v0.isRejectedCandidate()) + continue; + + fillWeightedJetFinderV0InJet(jet, v0); + } + } + } + PROCESS_SWITCH(V0QA, processTestWeightedJetFinder, "Test weighted jet finder", false); + + void processTestSubtractedJetFinder(soa::Filtered::iterator const& jcoll, V0ChargedJetsWithConstituents const& jets, aod::CandidatesV0Data const& v0s) + { + registry.fill(HIST("tests/hEvents"), 0.5); + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) + return; + + registry.fill(HIST("tests/hEvents"), 1.5); + + for (const auto& v0 : v0s) { + if (v0.isRejectedCandidate()) + continue; + + fillSubtractedJetFinderInclusiveV0(v0); + } + + for (const auto& jet : jets) { + fillSubtractedJetFinderJetNoSubtraction(jet); + + std::vector v0Pt; + std::vector v0Type; + double ptjetsub = jet.pt(); + + for (const auto& v0 : jet.template candidates_as()) { + fillSubtractedJetFinderV0InJetNoSubtraction(jet, v0); + + if (isV0RandomlyRejected()) { + ptjetsub -= v0.pt(); + } else { // Accepted V0 + v0Pt.push_back(v0.pt()); + if (v0.isK0SCandidate()) { + v0Type.push_back(PDG_t::kK0Short); + } else if (v0.isLambdaCandidate()) { + v0Type.push_back(PDG_t::kLambda0); + } else if (v0.isAntiLambdaCandidate()) { + v0Type.push_back(PDG_t::kLambda0Bar); + } + } + } // V0s in jet loop + + bool allV0sSubtracted = (v0Pt.size() == 0); + fillSubtractedJetFinderJetSubtracted(jet, ptjetsub, allV0sSubtracted); + for (unsigned int i = 0; i < v0Pt.size(); ++i) { + fillSubtractedJetFinderV0InJetSubtracted(ptjetsub, jet.eta(), v0Pt[i], v0Type[i]); + } // Accepted V0s in jet loop + } // Jets loop + } + PROCESS_SWITCH(V0QA, processTestSubtractedJetFinder, "Test subtracted jet finder", false); + + void processTestV0DaughterSharing(soa::Filtered::iterator const& jcoll, V0ChargedJetsWithConstituents const& jets, aod::CandidatesV0Data const& v0s, DaughterJTracks const&, DaughterTracks const&) + { + registry.fill(HIST("sharing/hEvents"), 0.5); + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) + return; + registry.fill(HIST("sharing/hEvents"), 1.5); + + // Check if V0s within the same event share daughters + for (const auto& trigger : v0s) { + if (trigger.isRejectedCandidate()) + continue; + + if (abs(trigger.eta()) > etaV0Max) + continue; + + fillV0DaughterSharingInclusive(trigger); + + for (const auto& associate : v0s) { + if (associate.isRejectedCandidate()) + continue; + + if (abs(associate.eta()) > etaV0Max) + continue; + + if (trigger == associate) + continue; + + // Double-counting accounted for by filling histograms with weight 0.5 + if (v0sShareDaughter(trigger, associate)) { + fillV0DaughterSharingInclusive(trigger, associate); + } + } + } + + // Check if V0s within the same jet share daughters + for (const auto& jet : jets) { + bool jetContainsSharedDaughters = false; + + for (const auto& trigger : jet.template candidates_as()) { + if (trigger.isRejectedCandidate()) + continue; + + fillV0DaughterSharingJet(jet, trigger); + + for (const auto& associate : jet.template candidates_as()) { + if (associate.isRejectedCandidate()) + continue; + + if (trigger == associate) + continue; + + // Double-counting accounted for by filling histograms with weight 0.5 + if (v0sShareDaughter(trigger, associate)) { + jetContainsSharedDaughters = true; + fillV0DaughterSharingJet(jet, trigger, associate); + } + } + } + fillV0DaughterSharingJet(jet, jetContainsSharedDaughters); + } + } + PROCESS_SWITCH(V0QA, processTestV0DaughterSharing, "Test V0s with shared daughters", false); + + void processV0TrackQA(aod::JetCollision const& jcoll, aod::CandidatesV0Data const& v0s, DaughterJTracks const&, DaughterTracks const&) + { + registry.fill(HIST("tracks/hEvents"), 0.5); + if (!jetderiveddatautilities::selectCollision(jcoll, eventSelectionBits)) + return; + + registry.fill(HIST("tracks/hEvents"), 1.5); + + 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/DataModel/LFAntinCexTables.h b/PWGLF/DataModel/LFAntinCexTables.h new file mode 100644 index 00000000000..9e8f4ce1ca8 --- /dev/null +++ b/PWGLF/DataModel/LFAntinCexTables.h @@ -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 LFAntinCexTables.h +/// \brief Slim tables for nucleiAntineutronCex +/// \author Fabiola Lugo +/// + +#ifndef PWGLF_DATAMODEL_LFANTINCEXTABLES_H_ +#define PWGLF_DATAMODEL_LFANTINCEXTABLES_H_ + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace antin_cex +{ +// Metadata +DECLARE_SOA_COLUMN(IsCex, isCex, bool); // 1=CEX (from antin), 0=BG +DECLARE_SOA_COLUMN(MotherPdg, motherPdg, int32_t); // mother PDG +DECLARE_SOA_COLUMN(ColId, colId, int32_t); // mcCollisionId +DECLARE_SOA_COLUMN(PId, pId, int32_t); // proton MC id +DECLARE_SOA_COLUMN(AntipId, antipId, int32_t); // antiproton MC id + +// MC (pair) +DECLARE_SOA_COLUMN(McPairP, mcPairP, float); +DECLARE_SOA_COLUMN(McPairPt, mcPairPt, float); +DECLARE_SOA_COLUMN(McPairPz, mcPairPz, float); +DECLARE_SOA_COLUMN(McDplane, mcDplane, float); +DECLARE_SOA_COLUMN(McAngleDeg, mcAngleDeg, float); +DECLARE_SOA_COLUMN(McVtxX, mcVtxX, float); +DECLARE_SOA_COLUMN(McVtxY, mcVtxY, float); +DECLARE_SOA_COLUMN(McVtxZ, mcVtxZ, float); + +// Tracks (pair, fitter) +DECLARE_SOA_COLUMN(TrkPairP, trkPairP, float); +DECLARE_SOA_COLUMN(TrkPairPt, trkPairPt, float); +DECLARE_SOA_COLUMN(TrkPairPz, trkPairPz, float); +DECLARE_SOA_COLUMN(TrkAngleDeg, trkAngleDeg, float); +DECLARE_SOA_COLUMN(TrkVtxfitDcaPair, trkVtxfitDcaPair, float); +DECLARE_SOA_COLUMN(TrkVtxfitR, trkVtxfitR, float); +DECLARE_SOA_COLUMN(TrkVtxfitDistToPv, trkVtxfitDistToPv, float); +DECLARE_SOA_COLUMN(TrkVtxfitSecVtxX, trkVtxfitSecVtxX, float); +DECLARE_SOA_COLUMN(TrkVtxfitSecVtxY, trkVtxfitSecVtxY, float); +DECLARE_SOA_COLUMN(TrkVtxfitSecVtxZ, trkVtxfitSecVtxZ, float); + +// Fit quality (fit − MC) +DECLARE_SOA_COLUMN(VtxfitChi2, vtxfitChi2, float); +DECLARE_SOA_COLUMN(VtxfitStatus, vtxfitStatus, int32_t); +DECLARE_SOA_COLUMN(NCand, nCand, int32_t); +DECLARE_SOA_COLUMN(VtxfitDX, vtxfitDX, float); +DECLARE_SOA_COLUMN(VtxfitDY, vtxfitDY, float); +DECLARE_SOA_COLUMN(VtxfitDZ, vtxfitDZ, float); +DECLARE_SOA_COLUMN(VtxfitD3D, vtxfitD3D, float); + +// Proton track +DECLARE_SOA_COLUMN(PTrkP, pTrkP, float); +DECLARE_SOA_COLUMN(PTrkPx, pTrkPx, float); +DECLARE_SOA_COLUMN(PTrkPy, pTrkPy, float); +DECLARE_SOA_COLUMN(PTrkPz, pTrkPz, float); +DECLARE_SOA_COLUMN(PTrkEta, pTrkEta, float); +DECLARE_SOA_COLUMN(PTrkTpcSignal, pTrkTpcSignal, float); +DECLARE_SOA_COLUMN(PTrkNClsIts, pTrkNClsIts, int16_t); + +// Antiproton track +DECLARE_SOA_COLUMN(AntipTrkP, antipTrkP, float); +DECLARE_SOA_COLUMN(AntipTrkPx, antipTrkPx, float); +DECLARE_SOA_COLUMN(AntipTrkPy, antipTrkPy, float); +DECLARE_SOA_COLUMN(AntipTrkPz, antipTrkPz, float); +DECLARE_SOA_COLUMN(AntipTrkEta, antipTrkEta, float); +DECLARE_SOA_COLUMN(AntipTrkTpcSignal, antipTrkTpcSignal, float); +DECLARE_SOA_COLUMN(AntipTrkNClsIts, antipTrkNClsIts, int16_t); + +// Cuts Mask +DECLARE_SOA_COLUMN(SelMask, selMask, uint32_t); + +DECLARE_SOA_COLUMN(PairPointingAngleDeg, pairPointingAngleDeg, float); +DECLARE_SOA_COLUMN(PairPBalance, pairPBalance, float); +DECLARE_SOA_COLUMN(PairPtBalance, pairPtBalance, float); +DECLARE_SOA_COLUMN(PairQ, pairQ, float); + +DECLARE_SOA_COLUMN(DPairP, dPairP, float); +DECLARE_SOA_COLUMN(DPairPt, dPairPt, float); +DECLARE_SOA_COLUMN(DPairPz, dPairPz, float); +DECLARE_SOA_COLUMN(DOpenAngle, dOpenAngle, float); + +DECLARE_SOA_COLUMN(SVNearestLayerId, svNearestLayerId, int16_t); +DECLARE_SOA_COLUMN(SVDeltaRToLayer, svDeltaRToLayer, float); + +DECLARE_SOA_COLUMN(PTrkItsHitMap, pTrkItsHitMap, uint16_t); +DECLARE_SOA_COLUMN(APTrkItsHitMap, apTrkItsHitMap, uint16_t); +DECLARE_SOA_COLUMN(PLayersOk, pLayersOk, int8_t); +DECLARE_SOA_COLUMN(APLayersOk, apLayersOk, int8_t); + +DECLARE_SOA_COLUMN(PVtxZ, pVtxZ, float); + +// Proton ITS PID +DECLARE_SOA_COLUMN(PTrkItsNSigmaPr, pTrkItsNSigmaPr, float); +DECLARE_SOA_COLUMN(PTrkItsPidValid, pTrkItsPidValid, int8_t); +DECLARE_SOA_COLUMN(PTrkTgl, pTrkTgl, float); + +// Antiproton ITS PID +DECLARE_SOA_COLUMN(AntipTrkItsNSigmaPr, antipTrkItsNSigmaPr, float); +DECLARE_SOA_COLUMN(AntipTrkItsPidValid, antipTrkItsPidValid, int8_t); +DECLARE_SOA_COLUMN(AntipTrkTgl, antipTrkTgl, float); +} // namespace antin_cex + +// Table +DECLARE_SOA_TABLE(AntinCexPairs, "AOD", "ANTINCEX", + antin_cex::IsCex, + antin_cex::MotherPdg, antin_cex::ColId, antin_cex::PId, antin_cex::AntipId, + antin_cex::McPairP, antin_cex::McPairPt, antin_cex::McPairPz, + antin_cex::McDplane, antin_cex::McAngleDeg, antin_cex::McVtxX, antin_cex::McVtxY, antin_cex::McVtxZ, + antin_cex::TrkPairP, antin_cex::TrkPairPt, antin_cex::TrkPairPz, antin_cex::TrkAngleDeg, + antin_cex::TrkVtxfitDcaPair, antin_cex::TrkVtxfitR, antin_cex::TrkVtxfitDistToPv, + antin_cex::TrkVtxfitSecVtxX, antin_cex::TrkVtxfitSecVtxY, antin_cex::TrkVtxfitSecVtxZ, + antin_cex::VtxfitChi2, antin_cex::VtxfitStatus, antin_cex::NCand, + antin_cex::VtxfitDX, antin_cex::VtxfitDY, antin_cex::VtxfitDZ, antin_cex::VtxfitD3D, + antin_cex::PTrkP, antin_cex::PTrkPx, antin_cex::PTrkPy, antin_cex::PTrkPz, antin_cex::PTrkEta, antin_cex::PTrkTpcSignal, antin_cex::PTrkNClsIts, + antin_cex::AntipTrkP, antin_cex::AntipTrkPx, antin_cex::AntipTrkPy, antin_cex::AntipTrkPz, antin_cex::AntipTrkEta, antin_cex::AntipTrkTpcSignal, antin_cex::AntipTrkNClsIts, + antin_cex::SelMask, + antin_cex::PairPointingAngleDeg, antin_cex::PairPBalance, antin_cex::PairPtBalance, antin_cex::PairQ, + antin_cex::DPairP, antin_cex::DPairPt, antin_cex::DPairPz, antin_cex::DOpenAngle, + antin_cex::SVNearestLayerId, antin_cex::SVDeltaRToLayer, + antin_cex::PTrkItsHitMap, antin_cex::APTrkItsHitMap, antin_cex::PLayersOk, antin_cex::APLayersOk, + antin_cex::PVtxZ, + antin_cex::PTrkItsNSigmaPr, antin_cex::PTrkItsPidValid, antin_cex::PTrkTgl, + antin_cex::AntipTrkItsNSigmaPr, antin_cex::AntipTrkItsPidValid, antin_cex::AntipTrkTgl); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFANTINCEXTABLES_H_ diff --git a/PWGLF/DataModel/LFCKSSpinalignmentTables.h b/PWGLF/DataModel/LFCKSSpinalignmentTables.h new file mode 100644 index 00000000000..6593d22fe6b --- /dev/null +++ b/PWGLF/DataModel/LFCKSSpinalignmentTables.h @@ -0,0 +1,108 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file LFCKSSpinalignmentTables.h +/// \brief DataModel for Charged KStar spin alignment +/// +/// \author Prottay Das + +#ifndef PWGLF_DATAMODEL_LFCKSSPINALIGNMENTTABLES_H_ +#define PWGLF_DATAMODEL_LFCKSSPINALIGNMENTTABLES_H_ + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" + +#include + +namespace o2::aod +{ +namespace kshortpionevent +{ +DECLARE_SOA_COLUMN(Cent, cent, float); +DECLARE_SOA_COLUMN(Posz, posz, float); +DECLARE_SOA_COLUMN(CollIndex, collIndex, float); +DECLARE_SOA_COLUMN(PsiFT0C, psiFT0C, float); +DECLARE_SOA_COLUMN(PsiFT0A, psiFT0A, float); +DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); +} // namespace kshortpionevent +DECLARE_SOA_TABLE(KShortpionEvents, "AOD", "KSHORTPIONEVENT", + o2::soa::Index<>, + kshortpionevent::Cent, + kshortpionevent::Posz, + kshortpionevent::CollIndex, + kshortpionevent::PsiFT0C, + kshortpionevent::PsiFT0A, + kshortpionevent::PsiTPC) +using KShortpionEvent = KShortpionEvents::iterator; + +namespace kshortpionpair +{ +DECLARE_SOA_INDEX_COLUMN(KShortpionEvent, kshortpionevent); +DECLARE_SOA_COLUMN(V0Cospa, v0Cospa, float); //! V0 Cospa +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); //! V0 Radius +DECLARE_SOA_COLUMN(DcaPositive, dcaPositive, float); //! DCA Positive +DECLARE_SOA_COLUMN(DcaNegative, dcaNegative, float); //! DCA Negative +DECLARE_SOA_COLUMN(DcaBetweenDaughter, dcaBetweenDaughter, float); //! DCA between daughters +DECLARE_SOA_COLUMN(V0Lifetime, v0Lifetime, float); //! KShort lifetime +DECLARE_SOA_COLUMN(KShortPx, kShortPx, float); //! KShort Px +DECLARE_SOA_COLUMN(KShortPy, kShortPy, float); //! KShort Py +DECLARE_SOA_COLUMN(KShortPz, kShortPz, float); //! KShort Pz +DECLARE_SOA_COLUMN(KShortMass, kShortMass, float); //! KShort Mass +DECLARE_SOA_COLUMN(PionBachPx, pionBachPx, float); //! Bachelor Pion Px +DECLARE_SOA_COLUMN(PionBachPy, pionBachPy, float); //! Bachelor Pion Py +DECLARE_SOA_COLUMN(PionBachPz, pionBachPz, float); //! Bachelor Pion Pz +DECLARE_SOA_COLUMN(PionBachTPC, pionBachTPC, float); //! Bachelor Pion nsigmatpc +DECLARE_SOA_COLUMN(PionBachTOFHit, pionBachTOFHit, int); //! Bachelor Pion tof hit availability +DECLARE_SOA_COLUMN(PionBachTOF, pionBachTOF, float); //! Bachelor Pion nsigmatof +DECLARE_SOA_COLUMN(PionBachIndex, pionBachIndex, int); //! Bachelor Pion index +DECLARE_SOA_COLUMN(PionIndex1, pionIndex1, int); //! Daughter Pion index1 +DECLARE_SOA_COLUMN(PionIndex2, pionIndex2, int); //! Daughter Pion index2 +} // namespace kshortpionpair +DECLARE_SOA_TABLE(KShortTracks, "AOD", "KSHORTTRACK", + o2::soa::Index<>, + kshortpionpair::KShortpionEventId, + kshortpionpair::V0Cospa, + kshortpionpair::V0Radius, + kshortpionpair::DcaPositive, + kshortpionpair::DcaNegative, + kshortpionpair::DcaBetweenDaughter, + kshortpionpair::V0Lifetime, + // kshortpionpair::Armenteros, + kshortpionpair::KShortPx, + kshortpionpair::KShortPy, + kshortpionpair::KShortPz, + kshortpionpair::KShortMass, + kshortpionpair::PionIndex1, + kshortpionpair::PionIndex2); + +using KShortTrack = KShortTracks::iterator; + +DECLARE_SOA_TABLE(PionTracks, "AOD", "PIONTRACK", + o2::soa::Index<>, + kshortpionpair::KShortpionEventId, + kshortpionpair::PionBachPx, + kshortpionpair::PionBachPy, + kshortpionpair::PionBachPz, + // kshortpionpair::PionBachSign, + kshortpionpair::PionBachTPC, + kshortpionpair::PionBachTOFHit, + kshortpionpair::PionBachTOF, + kshortpionpair::PionBachIndex); + +using PionTrack = PionTracks::iterator; +} // namespace o2::aod +#endif // PWGLF_DATAMODEL_LFCKSSPINALIGNMENTTABLES_H_ diff --git a/PWGLF/DataModel/LFClusterStudiesTable.h b/PWGLF/DataModel/LFClusterStudiesTable.h index 88ca35a85d3..c19cccc5174 100644 --- a/PWGLF/DataModel/LFClusterStudiesTable.h +++ b/PWGLF/DataModel/LFClusterStudiesTable.h @@ -11,8 +11,8 @@ // // Author: Giorgio Alberto Lucia -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" #ifndef PWGLF_DATAMODEL_LFCLUSTERSTUDIESTABLE_H_ #define PWGLF_DATAMODEL_LFCLUSTERSTUDIESTABLE_H_ @@ -67,6 +67,8 @@ DECLARE_SOA_COLUMN(Chi2tpc, chi2tpc, float); DECLARE_SOA_COLUMN(HasTPC, hasTPC, bool); DECLARE_SOA_COLUMN(McPdgCode, mcPdgCode, int); +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); + } // namespace LFClusterStudiesTables DECLARE_SOA_TABLE( @@ -79,20 +81,10 @@ DECLARE_SOA_TABLE( 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, @@ -102,20 +94,8 @@ DECLARE_SOA_TABLE( 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); + ClStTableColl, "AOD", "CLSTTABLECOLL", + LFClusterStudiesTables::RunNumber); } // namespace o2::aod 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 index 00f6c732d44..59876ae59c1 100644 --- a/PWGLF/DataModel/LFEbyeTables.h +++ b/PWGLF/DataModel/LFEbyeTables.h @@ -22,6 +22,10 @@ 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(CBMultiplicity, cbMultiplicity, uint8_t); +DECLARE_SOA_COLUMN(Ntracks, ntracks, uint8_t); } // namespace LFEbyeCollTable DECLARE_SOA_TABLE(CollEbyeTables, "AOD", "COLLEBYETABLE", @@ -30,9 +34,19 @@ DECLARE_SOA_TABLE(CollEbyeTables, "AOD", "COLLEBYETABLE", LFEbyeCollTable::Zvtx); using CollEbyeTable = CollEbyeTables::iterator; +DECLARE_SOA_TABLE(MiniCollTables, "AOD", "MINICOLLTABLE", + o2::soa::Index<>, + LFEbyeCollTable::ZvtxMask, + LFEbyeCollTable::TriggerMask, + LFEbyeCollTable::CBMultiplicity, + LFEbyeCollTable::Centrality, + LFEbyeCollTable::Ntracks); +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); @@ -53,6 +67,10 @@ 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", @@ -120,6 +138,27 @@ DECLARE_SOA_TABLE(McLambdaEbyeTables, "AOD", "MCLAMBEBYETABLE", 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 b9db0bb6c77..3d54170252a 100644 --- a/PWGLF/DataModel/LFHStrangeCorrelationTables.h +++ b/PWGLF/DataModel/LFHStrangeCorrelationTables.h @@ -22,10 +22,15 @@ #ifndef PWGLF_DATAMODEL_LFHSTRANGECORRELATIONTABLES_H_ #define PWGLF_DATAMODEL_LFHSTRANGECORRELATIONTABLES_H_ -#include -#include "Framework/AnalysisDataModel.h" +/// this data model uses the LF one, add here +#include "PWGLF/DataModel/LFStrangenessTables.h" + #include "Common/Core/RecoDecay.h" + #include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisDataModel.h" + +#include // Simple checker #define bitcheck(var, nbit) ((var) & (1 << (nbit))) @@ -39,36 +44,60 @@ 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::MCPhysicalPrimary, 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 +DECLARE_SOA_COLUMN(PDGCode, pdgCode, float); // pdg code of the MC particle +} // namespace assocHadrons +DECLARE_SOA_TABLE(AssocHadrons, "AOD", "ASSOCHADRONS", o2::soa::Index<>, assocHadrons::CollisionId, assocHadrons::MCPhysicalPrimary, assocHadrons::TrackId, assocHadrons::MCOriginalPt, assocHadrons::PDGCode); +/// _________________________________________ +/// 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_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(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) +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; @@ -78,25 +107,15 @@ DECLARE_SOA_DYNAMIC_COLUMN(Compatible, compatible, //! check 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) - return true; - if (value == 1 && rLambda == region) - return true; - if (value == 2 && rAntiLambda == region) - 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 { @@ -118,19 +137,18 @@ DECLARE_SOA_TABLE(AssocV0s, "AOD", "ASSOCV0S", o2::soa::Index<>, assocV0s::MCTrueLambda, assocV0s::MCTrueAntiLambda, assocV0s::MCPhysicalPrimary, - assocV0s::MassRegionK0Short, - assocV0s::MassRegionLambda, - assocV0s::MassRegionAntiLambda, + 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_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 @@ -138,14 +156,14 @@ DECLARE_SOA_COLUMN(CompatibleXiPlus, compatibleXiPlus, int); // compatib 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(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) +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; @@ -157,25 +175,13 @@ DECLARE_SOA_DYNAMIC_COLUMN(Compatible, compatible, //! check return true; return false; }); -DECLARE_SOA_DYNAMIC_COLUMN(InvMassRegionCheck, invMassRegionCheck, - [](int rXi, int rOmega, int value, int region) -> bool { - if (value == 0 && rXi == region) - return true; - if (value == 1 && rXi == region) - return true; - if (value == 2 && rOmega == region) - return true; - if (value == 3 && rOmega == region) - 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 { @@ -200,11 +206,10 @@ DECLARE_SOA_TABLE(AssocCascades, "AOD", "ASSOCCASCADES", o2::soa::Index<>, assoc assocCascades::MCTrueOmegaMinus, assocCascades::MCTrueOmegaPlus, assocCascades::MCPhysicalPrimary, - assocCascades::MassRegionXi, - assocCascades::MassRegionOmega, + assocCascades::NSigmaMassXi, + assocCascades::NSigmaMassOmega, + assocCascades::InvMassNSigma, assocCascades::Compatible, - assocCascades::InvMassRegionCheck, - assocCascades::InvMassRegion, assocCascades::MCTrue); } // namespace o2::aod diff --git a/PWGLF/DataModel/LFHyperNucleiKinkTables.h b/PWGLF/DataModel/LFHyperNucleiKinkTables.h new file mode 100644 index 00000000000..f36cc896ed8 --- /dev/null +++ b/PWGLF/DataModel/LFHyperNucleiKinkTables.h @@ -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. +// +/// \file LFHyperNucleiKinkTables.h +/// \brief Slim hypernuclei kink tables +/// \author Yuanzhe Wang + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +#ifndef PWGLF_DATAMODEL_LFHYPERNUCLEIKINKTABLES_H_ +#define PWGLF_DATAMODEL_LFHYPERNUCLEIKINKTABLES_H_ + +namespace o2::aod +{ + +namespace hyperkink +{ +DECLARE_SOA_COLUMN(MagPolarity, magPolarity, int8_t); //! Magnetic field polarity +DECLARE_SOA_COLUMN(XPV, xPV, float); //! Primary vertex of the candidate (x direction) +DECLARE_SOA_COLUMN(YPV, yPV, float); //! Primary vertex of the candidate (y direction) +DECLARE_SOA_COLUMN(ZPV, zPV, float); //! Primary vertex of the candidate (z direction) +DECLARE_SOA_COLUMN(XSV, xSV, float); //! Decay vertex of the candidate (x direction) +DECLARE_SOA_COLUMN(YSV, ySV, float); //! Decay vertex of the candidate (y direction) +DECLARE_SOA_COLUMN(ZSV, zSV, float); //! Decay vertex of the candidate (z direction) +DECLARE_SOA_COLUMN(XMothIU, xMothIU, float); //! X of the mother track at the radii of ITS layer which has the outermost update +DECLARE_SOA_COLUMN(YMothIU, yMothIU, float); //! Y of the mother track at the radii of ITS layer which has the outermost update +DECLARE_SOA_COLUMN(ZMothIU, zMothIU, float); //! Z of the mother track at the radii of ITS layer which has the outermost update +DECLARE_SOA_COLUMN(PxMothSV, pxMothSV, float); //! Px of the mother track at the decay vertex +DECLARE_SOA_COLUMN(PyMothSV, pyMothSV, float); //! Py of the mother track at the decay vertex +DECLARE_SOA_COLUMN(PzMothSV, pzMothSV, float); //! Pz of the mother track at the decay vertex +DECLARE_SOA_COLUMN(PxDaugSV, pxDaugSV, float); //! Px of the daughter track at the decay vertex +DECLARE_SOA_COLUMN(PyDaugSV, pyDaugSV, float); //! Py of the daughter track at the decay vertex +DECLARE_SOA_COLUMN(PzDaugSV, pzDaugSV, float); //! Pz of the daughter track at the decay vertex +DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); //! bool: true for matter +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 +DECLARE_SOA_COLUMN(ItsChi2Moth, itsChi2Moth, float); //! ITS chi2 of the mother track +DECLARE_SOA_COLUMN(ItsClusterSizesMoth, itsClusterSizesMoth, uint32_t); //! ITS cluster size of the mother track +DECLARE_SOA_COLUMN(ItsClusterSizesDaug, itsClusterSizesDaug, uint32_t); //! ITS cluster size of the daughter track +DECLARE_SOA_COLUMN(TpcMomDaug, tpcMomDaug, float); //! TPC momentum of the daughter track +DECLARE_SOA_COLUMN(TpcSignalDaug, tpcSignalDaug, float); //! TPC signal of the daughter track +DECLARE_SOA_COLUMN(TpcNClsPIDDaug, tpcNClsPIDDaug, int16_t); //! Number of TPC clusters used for PID of the daughter track +DECLARE_SOA_COLUMN(NSigmaTPCDaug, nSigmaTPCDaug, float); //! Number of tpc sigmas of the daughter track +DECLARE_SOA_COLUMN(NSigmaITSDaug, nSigmaITSDaug, float); //! Number of ITS sigmas of the daughter track +DECLARE_SOA_COLUMN(NSigmaTOFDaug, nSigmaTOFDaug, float); //! Number of TOF sigmas of the daughter track + +DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); //! bool: true for hyperhelium4signal +DECLARE_SOA_COLUMN(IsSignalReco, isSignalReco, bool); //! bool: true if the signal is reconstructed +DECLARE_SOA_COLUMN(IsCollReco, isCollReco, bool); //! bool: true if the collision is reconstructed +DECLARE_SOA_COLUMN(IsSurvEvSelection, isSurvEvSelection, bool); //! bool: true for the collision passed the event selection +DECLARE_SOA_COLUMN(TrueXSV, trueXSV, float); //! true x decay vertex +DECLARE_SOA_COLUMN(TrueYSV, trueYSV, float); //! true y decay vertex +DECLARE_SOA_COLUMN(TrueZSV, trueZSV, float); //! true z decay vertex +DECLARE_SOA_COLUMN(TruePxMothPV, truePxMothPV, float); //! Generated px of the mother track +DECLARE_SOA_COLUMN(TruePyMothPV, truePyMothPV, float); //! Generated py of the mother track +DECLARE_SOA_COLUMN(TruePzMothPV, truePzMothPV, float); //! Generated pz of the mother track +DECLARE_SOA_COLUMN(TruePxMothSV, truePxMothSV, float); //! true px of the mother track at the decay vertex +DECLARE_SOA_COLUMN(TruePyMothSV, truePyMothSV, float); //! true py of the mother track at the decay vertex +DECLARE_SOA_COLUMN(TruePzMothSV, truePzMothSV, float); //! true pz of the mother track at the decay vertex +DECLARE_SOA_COLUMN(TruePxDaugSV, truePxDaugSV, float); //! true px of the daughter track at the decay vertex +DECLARE_SOA_COLUMN(TruePyDaugSV, truePyDaugSV, float); //! true py of the daughter track at the decay vertex +DECLARE_SOA_COLUMN(TruePzDaugSV, truePzDaugSV, float); //! true pz of the daughter track at the decay vertex +DECLARE_SOA_COLUMN(IsMothReco, isMothReco, bool); //! bool: true if the mother track is reconstructed +DECLARE_SOA_COLUMN(PxMothPV, pxMothPV, float); //! reconstructed px of the mother track at the primary vertex +DECLARE_SOA_COLUMN(PyMothPV, pyMothPV, float); //! reconstructed py of the mother track at the primary vertex +DECLARE_SOA_COLUMN(PzMothPV, pzMothPV, float); //! reconstructed pz of the mother track at the primary vertex +DECLARE_SOA_COLUMN(UpdatePxMothPV, updatePxMothPV, float); //! updated px of the mother track at the primary vertex after update using PV +DECLARE_SOA_COLUMN(UpdatePyMothPV, updatePyMothPV, float); //! updated py of the mother track at the primary vertex after update using PV +DECLARE_SOA_COLUMN(UpdatePzMothPV, updatePzMothPV, float); //! updated pz of the mother track at the primary vertex after update using PV +} // namespace hyperkink + +DECLARE_SOA_TABLE(HypKinkCand, "AOD", "HYPKINKCANDS", + o2::soa::Index<>, + hyperkink::MagPolarity, + hyperkink::XPV, hyperkink::YPV, hyperkink::ZPV, + hyperkink::XSV, hyperkink::YSV, hyperkink::ZSV, + hyperkink::IsMatter, + hyperkink::XMothIU, hyperkink::YMothIU, hyperkink::ZMothIU, + hyperkink::PxMothSV, hyperkink::PyMothSV, hyperkink::PzMothSV, + hyperkink::PxDaugSV, hyperkink::PyDaugSV, hyperkink::PzDaugSV, + hyperkink::DcaMothPv, hyperkink::DcaDaugPv, hyperkink::DcaKinkTopo, + hyperkink::ItsChi2Moth, hyperkink::ItsClusterSizesMoth, hyperkink::ItsClusterSizesDaug, + hyperkink::TpcMomDaug, hyperkink::TpcSignalDaug, hyperkink::TpcNClsPIDDaug, + hyperkink::NSigmaTPCDaug, hyperkink::NSigmaITSDaug, hyperkink::NSigmaTOFDaug, + hyperkink::PxMothPV, hyperkink::PyMothPV, hyperkink::PzMothPV, + hyperkink::UpdatePxMothPV, hyperkink::UpdatePyMothPV, hyperkink::UpdatePzMothPV); + +DECLARE_SOA_TABLE(MCHypKinkCand, "AOD", "MCHYPKINKCANDS", + o2::soa::Index<>, + hyperkink::MagPolarity, + hyperkink::XPV, hyperkink::YPV, hyperkink::ZPV, + hyperkink::XSV, hyperkink::YSV, hyperkink::ZSV, + hyperkink::IsMatter, + hyperkink::XMothIU, hyperkink::YMothIU, hyperkink::ZMothIU, + hyperkink::PxMothSV, hyperkink::PyMothSV, hyperkink::PzMothSV, + hyperkink::PxDaugSV, hyperkink::PyDaugSV, hyperkink::PzDaugSV, + hyperkink::DcaMothPv, hyperkink::DcaDaugPv, hyperkink::DcaKinkTopo, + hyperkink::ItsChi2Moth, hyperkink::ItsClusterSizesMoth, hyperkink::ItsClusterSizesDaug, + hyperkink::TpcMomDaug, hyperkink::TpcSignalDaug, hyperkink::TpcNClsPIDDaug, + hyperkink::NSigmaTPCDaug, hyperkink::NSigmaITSDaug, hyperkink::NSigmaTOFDaug, + hyperkink::IsSignal, hyperkink::IsSignalReco, hyperkink::IsCollReco, hyperkink::IsSurvEvSelection, + hyperkink::TrueXSV, hyperkink::TrueYSV, hyperkink::TrueZSV, + hyperkink::TruePxMothPV, hyperkink::TruePyMothPV, hyperkink::TruePzMothPV, + hyperkink::TruePxMothSV, hyperkink::TruePyMothSV, hyperkink::TruePzMothSV, + hyperkink::TruePxDaugSV, hyperkink::TruePyDaugSV, hyperkink::TruePzDaugSV, + hyperkink::IsMothReco, hyperkink::PxMothPV, hyperkink::PyMothPV, hyperkink::PzMothPV, + hyperkink::UpdatePxMothPV, hyperkink::UpdatePyMothPV, hyperkink::UpdatePzMothPV); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFHYPERNUCLEIKINKTABLES_H_ diff --git a/PWGLF/DataModel/LFHypernucleiKfTables.h b/PWGLF/DataModel/LFHypernucleiKfTables.h new file mode 100644 index 00000000000..b4fff4db1a2 --- /dev/null +++ b/PWGLF/DataModel/LFHypernucleiKfTables.h @@ -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. + +/// \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 "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include + +#include + +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_COLUMN(RunNumber, runNumber, 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, + hykfmc::RunNumber); +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 < 0x08; i++) { + if (itsClusterSizes >> (4 * i) & 15) + n++; + } + return n; +}); +DECLARE_SOA_DYNAMIC_COLUMN(ItsFirstLayer, itsFirstLayer, [](uint32_t itsClusterSizes) { + for (int i = 0; i < 0x08; 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 < 0x08; 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 ba81c59b502..ca389cf928b 100644 --- a/PWGLF/DataModel/LFHypernucleiTables.h +++ b/PWGLF/DataModel/LFHypernucleiTables.h @@ -14,8 +14,8 @@ /// \brief Slim hypernuclei tables /// -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" #ifndef PWGLF_DATAMODEL_LFHYPERNUCLEITABLES_H_ #define PWGLF_DATAMODEL_LFHYPERNUCLEITABLES_H_ @@ -30,51 +30,63 @@ 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(CollisionId, collisionId, int64_t); // CollisionID + +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); // Run number +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(NTPCpidClusHe, nTPCpidClusHe, uint8_t); // Number of TPC clusters with PID information of the He daughter +DECLARE_SOA_COLUMN(NTPCpidClusPi, nTPCpidClusPi, uint8_t); // Number of TPC clusters with PID information 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(ITSChi2He, itsChi2He, float); // ITS chi2 of the He daughter +DECLARE_SOA_COLUMN(ITSChi2Pi, itsChi2Pi, float); // ITS chi2 of the Pi 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(IsFakeHeOnITSLayer, isFakeHeOnITSLayer, uint8_t); // uint8_t: bit map for fake He on ITS layers +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(IsTwoBodyDecay, isTwoBodyDecay, bool); // bool: true for two body decay } // namespace hyperrec DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", @@ -82,48 +94,51 @@ DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, - hyperrec::IsMatter, + hyperrec::RunNumber, hyperrec::IsMatter, hyperrec::PtHe3, hyperrec::PhiHe3, hyperrec::EtaHe3, hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, 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::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, + hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, + 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, - hyperrec::IsMatter, + hyperrec::RunNumber, hyperrec::IsMatter, hyperrec::PtHe3, hyperrec::PhiHe3, hyperrec::EtaHe3, hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, 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::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, + hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, + hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, - hyperrec::Flags, hyperrec::Tracked); + hyperrec::Flags, hyperrec::TrackedClSize); DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", o2::soa::Index<>, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, - hyperrec::IsMatter, + hyperrec::RunNumber, hyperrec::IsMatter, hyperrec::PtHe3, hyperrec::PhiHe3, hyperrec::EtaHe3, hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, 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::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, + hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, + hyperrec::TOFMass, hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, - hyperrec::Flags, hyperrec::Tracked, + hyperrec::Flags, hyperrec::TrackedClSize, hyperrec::GenPt, hyperrec::GenPhi, hyperrec::GenEta, @@ -132,13 +147,32 @@ DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", hyperrec::GenYDecVtx, hyperrec::GenZDecVtx, hyperrec::IsReco, + hyperrec::IsFakeHeOnITSLayer, hyperrec::IsSignal, hyperrec::IsRecoMCCollision, - hyperrec::IsSurvEvSel); + hyperrec::IsSurvEvSel, + hyperrec::IsTwoBodyDecay, aod::mcparticle::StatusCode); + +DECLARE_SOA_TABLE(DataHypCandsWColl, "AOD", "HYPCANDSWCOLL", + o2::soa::Index<>, + hyperrec::CollisionId, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, + + hyperrec::RunNumber, hyperrec::IsMatter, + hyperrec::PtHe3, hyperrec::PhiHe3, hyperrec::EtaHe3, + hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, + hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, + hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, + hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, + hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, + hyperrec::TOFMass, + hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::Flags, hyperrec::TrackedClSize); using DataHypCand = DataHypCands::iterator; using DataHypCandFlow = DataHypCandsFlow::iterator; using MCHypCand = MCHypCands::iterator; +using DataHypCandWColl = DataHypCandsWColl::iterator; namespace hyperkink { diff --git a/PWGLF/DataModel/LFInJets.h b/PWGLF/DataModel/LFInJets.h new file mode 100644 index 00000000000..532c43c1e1f --- /dev/null +++ b/PWGLF/DataModel/LFInJets.h @@ -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. +/// +/// \brief Derived Data table for LF in jets analysis +/// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) +/// \author Sara Pucillo (sara.pucillo@cern.ch) + +#ifndef PWGLF_DATAMODEL_LFINJETS_H_ +#define PWGLF_DATAMODEL_LFINJETS_H_ + +#include + +namespace o2::aod +{ + +namespace lfinjets +{ + +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Sign, sign, int); +DECLARE_SOA_COLUMN(MassLambda, masslambda, float); +DECLARE_SOA_COLUMN(MassAntiLambda, massantilambda, float); +DECLARE_SOA_COLUMN(MassK0Short, massk0short, float); +DECLARE_SOA_COLUMN(V0Radius, v0radius, float); +DECLARE_SOA_COLUMN(V0CosPA, v0cospa, float); +DECLARE_SOA_COLUMN(V0DCAPosToPV, v0dcapostopv, float); +DECLARE_SOA_COLUMN(V0DCANegToPV, v0dcanegtopv, float); +DECLARE_SOA_COLUMN(V0DCAV0Daughters, v0dcav0daughters, float); +DECLARE_SOA_COLUMN(NTPCSigmaNegPr, ntpcsigmanegpr, float); +DECLARE_SOA_COLUMN(NTPCSigmaPosPr, ntpcsigmapospr, float); +DECLARE_SOA_COLUMN(NTPCSigmaNegPi, ntpcsigmanegpi, float); +DECLARE_SOA_COLUMN(NTPCSigmaPosPi, ntpcsigmapospi, float); +DECLARE_SOA_COLUMN(NTOFSigmaNegPr, ntofsigmanegpr, float); +DECLARE_SOA_COLUMN(NTOFSigmaPosPr, ntofsigmapospr, float); +DECLARE_SOA_COLUMN(NTOFSigmaNegPi, ntofsigmanegpi, float); +DECLARE_SOA_COLUMN(NTOFSigmaPosPi, ntofsigmapospi, float); +DECLARE_SOA_COLUMN(MultFT0M, multft0m, float); +DECLARE_SOA_COLUMN(V0PosTPCCrossedRows, v0postpcCrossedRows, float); +DECLARE_SOA_COLUMN(V0NegTPCCrossedRows, v0negtpcCrossedRows, float); +DECLARE_SOA_COLUMN(V0NegTPCChi2, v0negTPCChi2, float); +DECLARE_SOA_COLUMN(V0NegITSlayers, v0negITSlayers, int); +DECLARE_SOA_COLUMN(V0PosTPCChi2, v0posTPCChi2, float); +DECLARE_SOA_COLUMN(V0PosITSlayers, v0posITSlayers, int); +DECLARE_SOA_COLUMN(MassXi, massxi, float); +DECLARE_SOA_COLUMN(MassOmega, massomega, float); +DECLARE_SOA_COLUMN(CascRadius, cascradius, float); +DECLARE_SOA_COLUMN(CascCosPA, casccospa, float); +DECLARE_SOA_COLUMN(DCABachToPV, dcabachtopv, float); +DECLARE_SOA_COLUMN(DCACascDaughters, dcacascdaughters, float); +DECLARE_SOA_COLUMN(DCAV0ToPV, dcav0topv, float); +DECLARE_SOA_COLUMN(NTPCSigmaBachPi, ntpcsigmabachpi, float); +DECLARE_SOA_COLUMN(NTPCSigmaBachKa, ntpcsigmabachka, float); +DECLARE_SOA_COLUMN(NTOFSigmaBachPi, ntofsigmabachpi, float); +DECLARE_SOA_COLUMN(NTOFSigmaBachKa, ntofsigmabachka, float); +DECLARE_SOA_COLUMN(BachTPCCrossedRows, bachtpcCrossedRows, float); +DECLARE_SOA_COLUMN(BachTPCChi2, bachTPCChi2, float); +DECLARE_SOA_COLUMN(BachITSlayers, bachITSlayers, int); +DECLARE_SOA_COLUMN(IsUE, isUE, bool); +DECLARE_SOA_COLUMN(IsJC, isJC, bool); + +} // namespace lfinjets + +DECLARE_SOA_TABLE(V0InJets, "AOD", "V0INJETS", + lfinjets::Pt, lfinjets::MassLambda, lfinjets::MassAntiLambda, lfinjets::MassK0Short, + lfinjets::V0Radius, lfinjets::V0CosPA, lfinjets::V0DCAPosToPV, + lfinjets::V0DCANegToPV, lfinjets::V0DCAV0Daughters, + lfinjets::NTPCSigmaNegPr, lfinjets::NTPCSigmaPosPr, lfinjets::NTPCSigmaNegPi, lfinjets::NTPCSigmaPosPi, + lfinjets::NTOFSigmaNegPr, lfinjets::NTOFSigmaPosPr, lfinjets::NTOFSigmaNegPi, lfinjets::NTOFSigmaPosPi, + lfinjets::MultFT0M, lfinjets::V0PosTPCCrossedRows, lfinjets::V0NegTPCCrossedRows, + lfinjets::V0NegTPCChi2, lfinjets::V0NegITSlayers, lfinjets::V0PosTPCChi2, lfinjets::V0PosITSlayers, + lfinjets::IsUE, lfinjets::IsJC); + +DECLARE_SOA_TABLE(CascInJets, "AOD", "CASCINJETS", + lfinjets::Pt, lfinjets::Sign, lfinjets::MassXi, lfinjets::MassOmega, lfinjets::MassLambda, + lfinjets::CascRadius, lfinjets::CascCosPA, lfinjets::V0Radius, lfinjets::V0CosPA, + lfinjets::V0DCAPosToPV, lfinjets::V0DCANegToPV, lfinjets::DCABachToPV, + lfinjets::DCACascDaughters, lfinjets::V0DCAV0Daughters, lfinjets::DCAV0ToPV, + lfinjets::NTPCSigmaNegPr, lfinjets::NTPCSigmaPosPr, lfinjets::NTPCSigmaNegPi, lfinjets::NTPCSigmaPosPi, + lfinjets::NTPCSigmaBachPi, lfinjets::NTPCSigmaBachKa, + lfinjets::NTOFSigmaNegPr, lfinjets::NTOFSigmaPosPr, lfinjets::NTOFSigmaNegPi, lfinjets::NTOFSigmaPosPi, + lfinjets::NTOFSigmaBachPi, lfinjets::NTOFSigmaBachKa, lfinjets::MultFT0M, + lfinjets::V0PosTPCCrossedRows, lfinjets::V0NegTPCCrossedRows, lfinjets::BachTPCCrossedRows, + lfinjets::V0NegTPCChi2, lfinjets::V0NegITSlayers, lfinjets::V0PosTPCChi2, lfinjets::V0PosITSlayers, + lfinjets::BachTPCChi2, lfinjets::BachITSlayers, + lfinjets::IsUE, lfinjets::IsJC); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFINJETS_H_ diff --git a/PWGLF/DataModel/LFKinkDecayTables.h b/PWGLF/DataModel/LFKinkDecayTables.h new file mode 100644 index 00000000000..4337fe99f1c --- /dev/null +++ b/PWGLF/DataModel/LFKinkDecayTables.h @@ -0,0 +1,161 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Common/Core/RecoDecay.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.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 + +DECLARE_SOA_COLUMN(NSigmaTPCPi, nSigmaTPCPi, float); //! Number of sigmas for the pion candidate from Sigma kink in TPC +DECLARE_SOA_COLUMN(NSigmaTPCPr, nSigmaTPCPr, float); //! Number of sigmas for the proton candidate from Sigma kink in TPC +DECLARE_SOA_COLUMN(NSigmaTPCKa, nSigmaTPCKa, float); //! Number of sigmas for the kaon candidate from Sigma kink in TPC +DECLARE_SOA_COLUMN(NSigmaTOFPi, nSigmaTOFPi, float); //! Number of sigmas for the pion candidate from Sigma kink in TOF +DECLARE_SOA_COLUMN(NSigmaTOFPr, nSigmaTOFPr, float); //! Number of sigmas for the proton candidate from Sigma kink in TOF +DECLARE_SOA_COLUMN(NSigmaTOFKa, nSigmaTOFKa, float); //! Number of sigmas for the kaon candidate from Sigma kink in TOF + +// MC Columns +DECLARE_SOA_COLUMN(MothPdgCode, mothPdgCode, int); //! PDG code of the Sigma daughter +DECLARE_SOA_COLUMN(DaugPdgCode, daugPdgCode, int); //! PDG code of the kink daughter +DECLARE_SOA_COLUMN(PtMC, ptMC, float); //! pT of the candidate in MC +DECLARE_SOA_COLUMN(PzMC, pzMC, float); //! pZ of the candidate in MC +DECLARE_SOA_COLUMN(MassMC, massMC, float); //! Invariant mass of the candidate in MC +DECLARE_SOA_COLUMN(DecayRadiusMC, decayRadiusMC, float); //! Decay radius of the candidate in MC +DECLARE_SOA_COLUMN(CollisionIdCheck, collisionIdCheck, bool); //! Check if mcDaughter collision ID matches the reconstructed collision ID + +// 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}); }); + +DECLARE_SOA_DYNAMIC_COLUMN(MXiMinus, mXiMinus, //! mass under Xi 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::MassLambda}); }); + +} // 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, + kinkcand::MXiMinus); + +DECLARE_SOA_TABLE(KinkCandsUnbound, "AOD", "UBKINKCANDS", + o2::soa::Index<>, 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, + kinkcand::MXiMinus); + +DECLARE_SOA_TABLE(SlimKinkCands, "AOD", "SLIMKINKCANDS", + kinkcand::XDecVtx, kinkcand::YDecVtx, kinkcand::ZDecVtx, + kinkcand::PxMoth, kinkcand::PyMoth, kinkcand::PzMoth, + kinkcand::PxDaug, kinkcand::PyDaug, kinkcand::PzDaug, + kinkcand::DcaMothPv, kinkcand::DcaDaugPv, kinkcand::DcaKinkTopo, + kinkcand::MothSign, + kinkcand::NSigmaTPCPi, kinkcand::NSigmaTPCPr, kinkcand::NSigmaTPCKa, + kinkcand::NSigmaTOFPi, kinkcand::NSigmaTOFPr, kinkcand::NSigmaTOFKa); + +DECLARE_SOA_TABLE(SlimKinkCandsMC, "AOD", "SLIMKINKCANDSMC", + kinkcand::XDecVtx, kinkcand::YDecVtx, kinkcand::ZDecVtx, + kinkcand::PxMoth, kinkcand::PyMoth, kinkcand::PzMoth, + kinkcand::PxDaug, kinkcand::PyDaug, kinkcand::PzDaug, + kinkcand::DcaMothPv, kinkcand::DcaDaugPv, kinkcand::DcaKinkTopo, + kinkcand::MothSign, + kinkcand::NSigmaTPCPi, kinkcand::NSigmaTPCPr, kinkcand::NSigmaTPCKa, + kinkcand::NSigmaTOFPi, kinkcand::NSigmaTOFPr, kinkcand::NSigmaTOFKa, + kinkcand::MothPdgCode, kinkcand::DaugPdgCode, + kinkcand::PtMC, kinkcand::PzMC, kinkcand::MassMC, kinkcand::DecayRadiusMC, kinkcand::CollisionIdCheck); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFKINKDECAYTABLES_H_ diff --git a/PWGLF/DataModel/LFLambda1405Table.h b/PWGLF/DataModel/LFLambda1405Table.h new file mode 100644 index 00000000000..1425a345375 --- /dev/null +++ b/PWGLF/DataModel/LFLambda1405Table.h @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file LFLambda1405Tables.h +/// \brief Slim tables for Lambda(1405) candidates +/// \author Francesco Mazzaschi +/// + +#include "Common/Core/RecoDecay.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +#ifndef PWGLF_DATAMODEL_LFLAMBDA1405TABLES_H_ +#define PWGLF_DATAMODEL_LFLAMBDA1405TABLES_H_ + +namespace o2::aod +{ + +namespace lambda1405 +{ + +DECLARE_SOA_COLUMN(Px, px, float); //! Px of the candidate +DECLARE_SOA_COLUMN(Py, py, float); //! Py of the candidate +DECLARE_SOA_COLUMN(Pz, pz, float); //! Pz of the candidate +DECLARE_SOA_COLUMN(Mass, mass, float); //! Invariant mass of the candidate +DECLARE_SOA_COLUMN(MassXi1530, massXi1530, float); //! Invariant mass of the Xi(1530) candidate +DECLARE_SOA_COLUMN(SigmaMinusMass, sigmaMinusMass, float); //! Invariant mass of the Sigma- candidate +DECLARE_SOA_COLUMN(SigmaPlusMass, sigmaPlusMass, float); //! Invariant mass of the Sigma+ candidate +DECLARE_SOA_COLUMN(XiMinusMass, xiMinusMass, float); //! Invariant mass of the Xi- candidate +DECLARE_SOA_COLUMN(PtSigma, ptSigma, float); //! Signed pT of the Sigma daughter +DECLARE_SOA_COLUMN(AlphaAPSigma, alphaAPSigma, float); //! Alpha of the Sigma +DECLARE_SOA_COLUMN(QtAPSigma, qtAPSigma, float); //! qT of the Sigma +DECLARE_SOA_COLUMN(RadiusSigma, radiusSigma, float); //! Radius of the Sigma decay vertex +DECLARE_SOA_COLUMN(PtKink, ptKink, float); //! pT of the kink daughter +DECLARE_SOA_COLUMN(NSigmaTPCPiKink, nSigmaTPCPiKink, float); //! Number of sigmas for the pion candidate from Sigma kink in TPC +DECLARE_SOA_COLUMN(NSigmaTOFPiKink, nSigmaTOFPiKink, float); //! Number of sigmas for the pion candidate from Sigma kink in TOF +DECLARE_SOA_COLUMN(NSigmaTPCPrKink, nSigmaTPCPrKink, float); //! Number of sigmas for the proton candidate from Sigma kink in TPC +DECLARE_SOA_COLUMN(NSigmaTOFPrKink, nSigmaTOFPrKink, float); //! Number of sigmas for the proton candidate from Sigma kink in TOF +DECLARE_SOA_COLUMN(DCAKinkDauToPV, dcaKinkDauToPV, float); //! DCA of the kink daughter to the primary vertex +DECLARE_SOA_COLUMN(NSigmaTPCPiDau, nSigmaTPCPiDau, float); //! Number of sigmas for the lambda1405 pion daughter in TPC +DECLARE_SOA_COLUMN(NSigmaTOFPiDau, nSigmaTOFPiDau, float); //! Number of sigmas for the lambda1405 pion daughter in TOF + +// MC Columns +DECLARE_SOA_COLUMN(PtMC, ptMC, float); //! pT of the candidate in MC +DECLARE_SOA_COLUMN(MassMC, massMC, float); //! Invariant mass of the candidate in MC +DECLARE_SOA_COLUMN(SigmaPdgCode, sigmaPdgCode, int); //! PDG code of the Sigma daughter +DECLARE_SOA_COLUMN(KinkDauPdgCode, kinkDauPdgCode, int); //! PDG code of the kink daughter + +} // namespace lambda1405 + +DECLARE_SOA_TABLE(Lambda1405Cands, "AOD", "LAMBDA1405", + o2::soa::Index<>, + lambda1405::Px, lambda1405::Py, lambda1405::Pz, + lambda1405::Mass, lambda1405::MassXi1530, + lambda1405::SigmaMinusMass, lambda1405::SigmaPlusMass, lambda1405::XiMinusMass, + lambda1405::PtSigma, lambda1405::AlphaAPSigma, lambda1405::QtAPSigma, lambda1405::RadiusSigma, + lambda1405::PtKink, + lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, + lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, + lambda1405::DCAKinkDauToPV, + lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau); + +DECLARE_SOA_TABLE(Lambda1405CandsMC, "AOD", "MCLAMBDA1405", + o2::soa::Index<>, + lambda1405::Px, lambda1405::Py, lambda1405::Pz, + lambda1405::Mass, lambda1405::MassXi1530, + lambda1405::SigmaMinusMass, lambda1405::SigmaPlusMass, lambda1405::XiMinusMass, + lambda1405::PtSigma, lambda1405::AlphaAPSigma, lambda1405::QtAPSigma, lambda1405::RadiusSigma, + lambda1405::PtKink, + lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, + lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, + lambda1405::DCAKinkDauToPV, + lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau, + lambda1405::PtMC, lambda1405::MassMC, lambda1405::SigmaPdgCode, lambda1405::KinkDauPdgCode); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFLAMBDA1405TABLES_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 324d4e1e375..d9ed41fe6bf 100644 --- a/PWGLF/DataModel/LFNonPromptCascadeTables.h +++ b/PWGLF/DataModel/LFNonPromptCascadeTables.h @@ -25,15 +25,23 @@ namespace o2::aod namespace NPCascadeTable { DECLARE_SOA_COLUMN(MatchingChi2, matchingChi2, float); +DECLARE_SOA_COLUMN(DeltaPtITSCascade, deltaPtITSCascade, float); +DECLARE_SOA_COLUMN(DeltaPtCascade, deltaPtCascade, 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(PdgCodePrimary, pdgCodePrimary, int); +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); @@ -67,16 +75,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); @@ -85,8 +91,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); @@ -96,12 +101,40 @@ DECLARE_SOA_COLUMN(BachPionTOFNSigma, bachPionTOFNSigma, float); DECLARE_SOA_COLUMN(gPt, genPt, float); DECLARE_SOA_COLUMN(gEta, genEta, float); DECLARE_SOA_COLUMN(gPhi, genPhi, float); +DECLARE_SOA_COLUMN(gVx, genVx, float); +DECLARE_SOA_COLUMN(gVy, genVy, float); +DECLARE_SOA_COLUMN(gVz, genVz, 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(HasFakeReassociation, hasFakeReassociation, bool); +DECLARE_SOA_COLUMN(MotherDecayDaughters, motherDecayDaughters, int8_t); + +DECLARE_SOA_COLUMN(Sel8, sel8, bool); +DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); +DECLARE_SOA_COLUMN(MultFV0A, multFV0A, float); +DECLARE_SOA_COLUMN(MultFT0M, multFT0M, float); +DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); +DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(MultNTracksGlobal, multNTracksGlobal, int); +DECLARE_SOA_COLUMN(ToiMask, toiMask, uint32_t); +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); +DECLARE_SOA_COLUMN(NoSameBunchPileup, noSameBunchPileup, bool); } // namespace NPCascadeTable DECLARE_SOA_TABLE(NPCascTable, "AOD", "NPCASCTABLE", + NPCascadeTable::RunNumber, NPCascadeTable::MatchingChi2, + NPCascadeTable::DeltaPtITSCascade, + NPCascadeTable::DeltaPtCascade, NPCascadeTable::ITSClusSize, + NPCascadeTable::HasReassociatedCluster, + aod::collision::NumContrib, + NPCascadeTable::CascPVContribs, + aod::collision::CollisionTimeRes, NPCascadeTable::PvX, NPCascadeTable::PvY, NPCascadeTable::PvZ, @@ -134,31 +167,203 @@ 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::MultFV0A, + NPCascadeTable::MultFT0M, + NPCascadeTable::CentFT0C, + NPCascadeTable::CentFV0A, + NPCascadeTable::CentFT0M, + NPCascadeTable::MultNTracksGlobal, + NPCascadeTable::ToiMask, + NPCascadeTable::NoSameBunchPileup) + +DECLARE_SOA_TABLE(NPCascTableNT, "AOD", "NPCASCTABLENT", + NPCascadeTable::RunNumber, + NPCascadeTable::MatchingChi2, + NPCascadeTable::DeltaPtITSCascade, + NPCascadeTable::DeltaPtCascade, + 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::MultFV0A, + NPCascadeTable::MultFT0M, + NPCascadeTable::CentFT0C, + NPCascadeTable::CentFV0A, + NPCascadeTable::CentFT0M, + NPCascadeTable::MultNTracksGlobal, + NPCascadeTable::ToiMask, + NPCascadeTable::NoSameBunchPileup) DECLARE_SOA_TABLE(NPCascTableMC, "AOD", "NPCASCTABLEMC", + NPCascadeTable::RunNumber, + NPCascadeTable::MatchingChi2, + NPCascadeTable::DeltaPtITSCascade, + NPCascadeTable::DeltaPtCascade, + 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::Sel8, + NPCascadeTable::MultFT0C, + NPCascadeTable::MultFV0A, + NPCascadeTable::MultFT0M, + NPCascadeTable::CentFT0C, + NPCascadeTable::CentFV0A, + NPCascadeTable::CentFT0M, + NPCascadeTable::gPt, + NPCascadeTable::gEta, + NPCascadeTable::gPhi, + NPCascadeTable::gVx, + NPCascadeTable::gVy, + NPCascadeTable::gVz, + NPCascadeTable::PDGcode, + NPCascadeTable::DCAxMC, + NPCascadeTable::DCAyMC, + NPCascadeTable::DCAzMC, + NPCascadeTable::MCcollisionMatch, + NPCascadeTable::HasFakeReassociation, + NPCascadeTable::MotherDecayDaughters, + NPCascadeTable::MultNTracksGlobal, + NPCascadeTable::ToiMask, + NPCascadeTable::NoSameBunchPileup) + +DECLARE_SOA_TABLE(NPCascTableMCNT, "AOD", "NPCASCTABLEMCNT", + NPCascadeTable::RunNumber, NPCascadeTable::MatchingChi2, + NPCascadeTable::DeltaPtITSCascade, + NPCascadeTable::DeltaPtCascade, NPCascadeTable::ITSClusSize, + NPCascadeTable::HasReassociatedCluster, NPCascadeTable::IsGoodMatch, NPCascadeTable::IsGoodCascade, - NPCascadeTable::PdgCodePrimary, + NPCascadeTable::PdgCodeMom, + NPCascadeTable::PdgCodeITStrack, + NPCascadeTable::IsFromBeauty, + NPCascadeTable::IsFromCharm, + aod::collision::NumContrib, + NPCascadeTable::CascPVContribs, + aod::collision::CollisionTimeRes, NPCascadeTable::PvX, NPCascadeTable::PvY, NPCascadeTable::PvZ, @@ -191,28 +396,57 @@ 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, NPCascadeTable::BachPionTOFNSigma, + NPCascadeTable::Sel8, + NPCascadeTable::MultFT0C, + NPCascadeTable::MultFV0A, + NPCascadeTable::MultFT0M, + NPCascadeTable::CentFT0C, + NPCascadeTable::CentFV0A, + NPCascadeTable::CentFT0M, + NPCascadeTable::gPt, + NPCascadeTable::gEta, + NPCascadeTable::gPhi, + NPCascadeTable::gVx, + NPCascadeTable::gVy, + NPCascadeTable::gVz, + NPCascadeTable::PDGcode, + NPCascadeTable::DCAxMC, + NPCascadeTable::DCAyMC, + NPCascadeTable::DCAzMC, + NPCascadeTable::MCcollisionMatch, + NPCascadeTable::HasFakeReassociation, + NPCascadeTable::MotherDecayDaughters, + NPCascadeTable::MultNTracksGlobal, + NPCascadeTable::ToiMask, + NPCascadeTable::NoSameBunchPileup) + +DECLARE_SOA_TABLE(NPCascTableGen, "AOD", "NPCASCTABLEGen", NPCascadeTable::gPt, NPCascadeTable::gEta, NPCascadeTable::gPhi, - NPCascadeTable::PDGcode) + NPCascadeTable::PDGcode, + NPCascadeTable::PdgCodeMom, + NPCascadeTable::DCAxMC, + NPCascadeTable::DCAyMC, + NPCascadeTable::DCAzMC, + NPCascadeTable::IsFromBeauty, + NPCascadeTable::IsFromCharm, + NPCascadeTable::MotherDecayDaughters) } // namespace o2::aod diff --git a/PWGLF/DataModel/LFNucleiTables.h b/PWGLF/DataModel/LFNucleiTables.h index dd7b72abb67..1cd9ba76c93 100644 --- a/PWGLF/DataModel/LFNucleiTables.h +++ b/PWGLF/DataModel/LFNucleiTables.h @@ -62,6 +62,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(Rapidity, rapidity, const auto energy = sqrt(p * p + mass * mass); return 0.5f * log((energy + pz) / (energy - pz)); }); +// ITS +DECLARE_SOA_COLUMN(ITSClusterSizes, itsClusterSizes, uint32_t); //! ITS cluster sizes per layer // TPC DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); DECLARE_SOA_COLUMN(TPCNSigmaKa, tpcNSigmaKa, float); @@ -181,48 +183,50 @@ DECLARE_SOA_TABLE(LfCandNucleus, "AOD", "LFNUCL", full::IsPVContributor, full::P, full::Rapidity, + full::ITSClusterSizes, track::TPCNClsFound, 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, + full::ITSClusterSizes, + 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/LFPIDTOFGenericTables.h b/PWGLF/DataModel/LFPIDTOFGenericTables.h new file mode 100644 index 00000000000..3a52a8a8ca5 --- /dev/null +++ b/PWGLF/DataModel/LFPIDTOFGenericTables.h @@ -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 LFPIDTOFGenericTables.h +/// \brief Table for event time without remving track bias +/// \author Yuanzhe Wang + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +#ifndef PWGLF_DATAMODEL_LFPIDTOFGENERICTABLES_H_ +#define PWGLF_DATAMODEL_LFPIDTOFGENERICTABLES_H_ +#include "Common/Core/PID/PIDTOF.h" + +#include "CommonDataFormat/InteractionRecord.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 o2::aod + +#endif // PWGLF_DATAMODEL_LFPIDTOFGENERICTABLES_H_ diff --git a/PWGLF/DataModel/LFResonanceTables.h b/PWGLF/DataModel/LFResonanceTables.h index 18658529dda..b8f60a6fc7a 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" @@ -53,13 +57,14 @@ enum { kAllCutsINELg010, kECend, }; -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 +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 @@ -76,16 +81,15 @@ DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOLLISION", collision::PosY, collision::PosZ, resocollision::Cent, - resocollision::Spherocity, - resocollision::EvtPl, - resocollision::EvtPlResAB, - resocollision::EvtPlResAC, - resocollision::EvtPlResBC, - resocollision::BMagField, - timestamp::Timestamp); + resocollision::BMagField); using ResoCollision = ResoCollisions::iterator; -DECLARE_SOA_TABLE(ResoMCCollisions, "AOD", "RESOMCCOL", +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, @@ -94,111 +98,533 @@ DECLARE_SOA_TABLE(ResoMCCollisions, "AOD", "RESOMCCOL", 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, + collision::PosY, + collision::PosZ, + resocollision::Cent, + resocollision::Spherocity, + resocollision::EvtPl, + resocollision::EvtPlResAB, + resocollision::EvtPlResAC, + resocollision::EvtPlResBC, + resocollision::BMagField, + 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(HasITS, hasITS, bool); //! Has ITS -DECLARE_SOA_COLUMN(HasTPC, hasTPC, bool); //! Has TPC -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 resomicrodaughter +{ +// 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) + { + const float x = std::abs(nSigma); + if (x <= 1.5) + return 0; // Return 0 when absolute nSigma is smaller than 1.5 + float t = (x - 1.5) / 0.2; + int encoded = static_cast(std::ceil(t)); // (1.5,1.7]->1, ..., (3.3,3.5]->10 + if (encoded < 1) + encoded = 1; + if (encoded > 10) + encoded = 10; + return static_cast(encoded); + } + + /// @brief Decode 0~10 value to original 1.5~3.5 sigma range + static float decodeNSigma(uint8_t encoded) + { + if (encoded == 0) + return 1.5; + if (encoded > 10) + encoded = 10; + return 1.5 + static_cast(encoded) * 0.2; + } + + /// @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 (|DCA|<0.1 is saved in 0) + static uint8_t encodeDCA(float DCA) + { + float x = std::fabs(DCA); + if (x < 0.1) + return 0; + int encoded = static_cast(std::ceil((x - 0.1) / 0.1)); // (0.1, 0.2] -> 1, ..., (1.4, 1.5] -> 14 + if (encoded < 1) + encoded = 1; + if (encoded > 14) + encoded = 15; + return static_cast(encoded); + } + + /// @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 resomicrodaughter + +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::HasITS, - resodaughter::HasTPC, - resodaughter::HasTOF, - o2::aod::pidtpc::TPCNSigmaPi, - o2::aod::pidtpc::TPCNSigmaKa, - o2::aod::pidtpc::TPCNSigmaPr, - o2::aod::pidtpc::TPCNSigmaEl, - o2::aod::pidtof::TOFNSigmaPi, - o2::aod::pidtof::TOFNSigmaKa, - o2::aod::pidtof::TOFNSigmaPr, - o2::aod::pidtof::TOFNSigmaEl, - 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, + resomicrodaughter::PidNSigmaPiFlag, + resomicrodaughter::PidNSigmaKaFlag, + resomicrodaughter::PidNSigmaPrFlag, + resomicrodaughter::TrackSelectionFlags, + resodaughter::TrackFlags, + // Dynamic columns + resomicrodaughter::Pt, + resodaughter::Eta, + resodaughter::Phi, + resodaughter::PassedITSRefit, + resodaughter::PassedTPCRefit, + resodaughter::IsGlobalTrackWoDCA, + resodaughter::IsGlobalTrack, + resodaughter::IsPrimaryTrack, + resodaughter::IsPVContributor, + resomicrodaughter::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, @@ -210,19 +636,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, @@ -234,26 +695,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, @@ -263,9 +817,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, @@ -275,7 +829,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, @@ -288,15 +842,30 @@ 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 using Reso2TracksMC = soa::Join; -using Reso2TracksPID = 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 bceb237faff..00000000000 --- a/PWGLF/DataModel/LFResonanceTablesMergeDF.h +++ /dev/null @@ -1,156 +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 - -#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", "RESOCOLLISIONDF", - 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(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(HasITS, hasITS, bool); -DECLARE_SOA_COLUMN(HasTPC, hasTPC, bool); -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, - resodaughterdf::TPCNClsFound, - resodaughterdf::ITSNCls, - o2::aod::track::DcaXY, - o2::aod::track::DcaZ, - o2::aod::track::X, - o2::aod::track::Alpha, - resodaughterdf::HasITS, - resodaughterdf::HasTPC, - resodaughterdf::HasTOF, - o2::aod::pidtpc::TPCNSigmaPi, - o2::aod::pidtpc::TPCNSigmaKa, - o2::aod::pidtpc::TPCNSigmaPr, - o2::aod::pidtpc::TPCNSigmaEl, - o2::aod::pidtof::TOFNSigmaPi, - o2::aod::pidtof::TOFNSigmaKa, - o2::aod::pidtof::TOFNSigmaPr, - o2::aod::pidtof::TOFNSigmaEl, - o2::aod::track::TPCSignal, - o2::aod::track::PassedITSRefit, - o2::aod::track::PassedTPCRefit, - resodaughterdf::IsGlobalTrackWoDCA, - resodaughterdf::IsGlobalTrack, - 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 b5a909733c7..fdeab068f44 100644 --- a/PWGLF/DataModel/LFSigmaTables.h +++ b/PWGLF/DataModel/LFSigmaTables.h @@ -9,203 +9,848 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + #include "Common/Core/RecoDecay.h" -#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Qvectors.h" + #include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +#include "Math/Vector3D.h" +#include "TVector3.h" + +#include +#include #ifndef PWGLF_DATAMODEL_LFSIGMATABLES_H_ #define PWGLF_DATAMODEL_LFSIGMATABLES_H_ +using std::array; + // Creating output TTree for sigma analysis namespace o2::aod { -DECLARE_SOA_TABLE(Sigma0Collisions, "AOD", "SIGMA0COLLISION", //! basic collision properties: position - o2::soa::Index<>, collision::PosX, collision::PosY, collision::PosZ, - cent::CentFT0M, cent::CentFT0A, cent::CentFT0C, cent::CentFV0A); -using Sigma0Collision = Sigma0Collisions::iterator; - -namespace v0SigmaCandidate +// for real data +namespace sigma0Core { +DECLARE_SOA_COLUMN(X, x, float); +DECLARE_SOA_COLUMN(Y, y, float); +DECLARE_SOA_COLUMN(Z, z, float); +DECLARE_SOA_COLUMN(DCADaughters, dcadaughters, float); + +DECLARE_SOA_COLUMN(PhotonPx, photonPx, float); +DECLARE_SOA_COLUMN(PhotonPy, photonPy, float); +DECLARE_SOA_COLUMN(PhotonPz, photonPz, float); +DECLARE_SOA_COLUMN(PhotonMass, photonMass, float); + +DECLARE_SOA_COLUMN(LambdaPx, lambdaPx, float); +DECLARE_SOA_COLUMN(LambdaPy, lambdaPy, float); +DECLARE_SOA_COLUMN(LambdaPz, lambdaPz, float); +DECLARE_SOA_COLUMN(LambdaMass, lambdaMass, float); +DECLARE_SOA_COLUMN(AntiLambdaMass, antilambdaMass, float); + //______________________________________________________ -// REGULAR COLUMNS FOR INDEXING -// FOR DERIVED -DECLARE_SOA_INDEX_COLUMN(Sigma0Collision, sigma0Collision); //! -} // namespace v0SigmaCandidate +// DYNAMIC COLUMNS +// Sigma0 +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! Sigma0 px + [](float photonPx, float lambdaPx) -> float { return photonPx + lambdaPx; }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! Sigma0 py + [](float photonPy, float lambdaPy) -> float { return photonPy + lambdaPy; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! Sigma0 pz + [](float photonPz, float lambdaPz) -> float { return photonPz + lambdaPz; }); -// for real data -namespace v0SigmaCandidate -{ -DECLARE_SOA_COLUMN(SigmapT, sigmapT, float); -DECLARE_SOA_COLUMN(SigmaMass, sigmaMass, float); -DECLARE_SOA_COLUMN(SigmaRapidity, sigmaRapidity, float); -// DECLARE_SOA_COLUMN(SigmaDCAz, sigmaDCAz, float); -// DECLARE_SOA_COLUMN(SigmaDCAxy, sigmaDCAxy, float); -// DECLARE_SOA_COLUMN(SigmaDCADau, sigmaDCADau, float); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, + [](float photonPx, float photonPy, float lambdaPx, float lambdaPy) -> float { + return RecoDecay::pt(array{photonPx + lambdaPx, photonPy + lambdaPy}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! Total momentum in GeV/c + [](float photonPx, float photonPy, float photonPz, float lambdaPx, float lambdaPy, float lambdaPz) -> float { + return RecoDecay::sqrtSumOfSquares(photonPx + lambdaPx, photonPy + lambdaPy, photonPz + lambdaPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Sigma0Mass, sigma0Mass, + [](float photonPx, float photonPy, float photonPz, float lambdaPx, float lambdaPy, float lambdaPz) -> float { + std::array pVecPhotons{photonPx, photonPy, photonPz}; + std::array pVecLambda{lambdaPx, lambdaPy, lambdaPz}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + return RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Sigma0Y, sigma0Y, + [](float photonPx, float photonPy, float photonPz, float lambdaPx, float lambdaPy, float lambdaPz) -> float { + return RecoDecay::y(std::array{photonPx + lambdaPx, photonPy + lambdaPy, photonPz + lambdaPz}, o2::constants::physics::MassSigma0); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! Phi in the range [0, 2pi) + [](float photonPx, float photonPy, float lambdaPx, float lambdaPy) -> float { return RecoDecay::phi(photonPx + lambdaPx, photonPy + lambdaPy); }); + +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! Pseudorapidity + [](float photonPx, float photonPy, float photonPz, float lambdaPx, float lambdaPy, float lambdaPz) -> float { + return RecoDecay::eta(std::array{photonPx + lambdaPx, photonPy + lambdaPy, photonPz + lambdaPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Radius, radius, //! Sigma0 decay radius (2D, centered at zero) + [](float x, float y) -> float { return RecoDecay::sqrtSumOfSquares(x, y); }); + +DECLARE_SOA_DYNAMIC_COLUMN(OPAngle, opAngle, + [](float photonPx, float photonPy, float photonPz, float lambdaPx, float lambdaPy, float lambdaPz) { + TVector3 v1(photonPx, photonPy, photonPz); + TVector3 v2(lambdaPx, lambdaPy, lambdaPz); + return v1.Angle(v2); + }); + +// Photon +DECLARE_SOA_DYNAMIC_COLUMN(PhotonPt, photonPt, //! Transverse momentum in GeV/c + [](float photonPx, float photonPy) -> float { + return RecoDecay::sqrtSumOfSquares(photonPx, photonPy); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(PhotonP, photonp, //! Total momentum in GeV/c + [](float photonPx, float photonPy, float photonPz) -> float { + return RecoDecay::sqrtSumOfSquares(photonPx, photonPy, photonPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(PhotonEta, photonEta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float photonPx, float photonPy, float photonPz) -> float { + return RecoDecay::eta(std::array{photonPx, photonPy, photonPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(PhotonY, photonY, //! Rapidity + [](float photonPx, float photonPy, float photonPz) -> float { + return RecoDecay::y(std::array{photonPx, photonPy, photonPz}, o2::constants::physics::MassGamma); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(PhotonPhi, photonPhi, //! Phi in the range [0, 2pi) + [](float photonPx, float photonPy) -> float { return RecoDecay::phi(photonPx, photonPy); }); + +// Lambda/ALambda +DECLARE_SOA_DYNAMIC_COLUMN(LambdaPt, lambdaPt, //! Transverse momentum in GeV/c + [](float lambdaPx, float lambdaPy) -> float { + return RecoDecay::sqrtSumOfSquares(lambdaPx, lambdaPy); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(LambdaP, lambdap, //! Total momentum in GeV/c + [](float lambdaPx, float lambdaPy, float lambdaPz) -> float { + return RecoDecay::sqrtSumOfSquares(lambdaPx, lambdaPy, lambdaPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(LambdaEta, lambdaEta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float lambdaPx, float lambdaPy, float lambdaPz) -> float { + return RecoDecay::eta(std::array{lambdaPx, lambdaPy, lambdaPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(LambdaY, lambdaY, //! Rapidity + [](float lambdaPx, float lambdaPy, float lambdaPz) -> float { + return RecoDecay::y(std::array{lambdaPx, lambdaPy, lambdaPz}, o2::constants::physics::MassLambda); + }); -} // namespace v0SigmaCandidate +DECLARE_SOA_DYNAMIC_COLUMN(LambdaPhi, lambdaPhi, //! Phi in the range [0, 2pi) + [](float lambdaPx, float lambdaPy) -> float { return RecoDecay::phi(lambdaPx, lambdaPy); }); -DECLARE_SOA_TABLE(V0SigmaCandidates, "AOD", "V0SIGMAS", - v0SigmaCandidate::SigmapT, - v0SigmaCandidate::SigmaMass, - v0SigmaCandidate::SigmaRapidity); +} // namespace sigma0Core -DECLARE_SOA_TABLE(V0Sigma0CollRefs, "AOD", "V0SIGMA0COLLREF", //! optional table to refer back to a collision - o2::soa::Index<>, v0SigmaCandidate::Sigma0CollisionId); +DECLARE_SOA_TABLE(Sigma0Cores, "AOD", "SIGMA0CORES", + // Basic properties + sigma0Core::X, sigma0Core::Y, sigma0Core::Z, sigma0Core::DCADaughters, + sigma0Core::PhotonPx, sigma0Core::PhotonPy, sigma0Core::PhotonPz, sigma0Core::PhotonMass, + sigma0Core::LambdaPx, sigma0Core::LambdaPy, sigma0Core::LambdaPz, sigma0Core::LambdaMass, sigma0Core::AntiLambdaMass, + + // Dynamic columns + sigma0Core::Px, + sigma0Core::Py, + sigma0Core::Pz, + sigma0Core::Pt, + sigma0Core::P, + sigma0Core::Sigma0Mass, + sigma0Core::Sigma0Y, + sigma0Core::Phi, + sigma0Core::Eta, + sigma0Core::Radius, + sigma0Core::OPAngle, + + sigma0Core::PhotonPt, + sigma0Core::PhotonP, + sigma0Core::PhotonEta, + sigma0Core::PhotonY, + sigma0Core::PhotonPhi, + + sigma0Core::LambdaPt, + sigma0Core::LambdaP, + sigma0Core::LambdaEta, + sigma0Core::LambdaY, + sigma0Core::LambdaPhi); // For Photon extra info -namespace v0SigmaPhotonExtras +namespace sigma0PhotonExtra { -DECLARE_SOA_COLUMN(PhotonPt, photonPt, float); -DECLARE_SOA_COLUMN(PhotonMass, photonMass, float); +//______________________________________________________ +// REGULAR COLUMNS FOR SIGMA0PHOTON DECLARE_SOA_COLUMN(PhotonQt, photonQt, float); DECLARE_SOA_COLUMN(PhotonAlpha, photonAlpha, float); -DECLARE_SOA_COLUMN(PhotonRadius, photonRadius, float); DECLARE_SOA_COLUMN(PhotonCosPA, photonCosPA, float); DECLARE_SOA_COLUMN(PhotonDCADau, photonDCADau, float); DECLARE_SOA_COLUMN(PhotonDCANegPV, photonDCANegPV, float); DECLARE_SOA_COLUMN(PhotonDCAPosPV, photonDCAPosPV, float); +DECLARE_SOA_COLUMN(PhotonRadius, photonRadius, float); DECLARE_SOA_COLUMN(PhotonZconv, photonZconv, float); -DECLARE_SOA_COLUMN(PhotonEta, photonEta, float); -DECLARE_SOA_COLUMN(PhotonY, photonY, float); -DECLARE_SOA_COLUMN(PhotonPosTPCNSigma, photonPosTPCNSigma, float); -DECLARE_SOA_COLUMN(PhotonNegTPCNSigma, photonNegTPCNSigma, float); +DECLARE_SOA_COLUMN(PhotonPosTPCNSigmaEl, photonPosTPCNSigmaEl, float); +DECLARE_SOA_COLUMN(PhotonNegTPCNSigmaEl, photonNegTPCNSigmaEl, 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(PhotonPosITSClSize, photonPosITSClSize, uint32_t); -DECLARE_SOA_COLUMN(PhotonNegITSClSize, photonNegITSClSize, uint32_t); +DECLARE_SOA_COLUMN(PhotonPosITSChi2PerNcl, photonPosITSChi2PerNcl, float); +DECLARE_SOA_COLUMN(PhotonNegITSChi2PerNcl, photonNegITSChi2PerNcl, float); +DECLARE_SOA_COLUMN(PhotonPosTrackCode, photonPosTrackCode, uint8_t); +DECLARE_SOA_COLUMN(PhotonNegTrackCode, photonNegTrackCode, uint8_t); DECLARE_SOA_COLUMN(PhotonV0Type, photonV0Type, uint8_t); -DECLARE_SOA_COLUMN(GammaBDTScore, gammaBDTScore, float); - -} // namespace v0SigmaPhotonExtras - -DECLARE_SOA_TABLE(V0SigmaPhotonExtras, "AOD", "V0SIGMAPHOTON", - v0SigmaPhotonExtras::PhotonMass, - v0SigmaPhotonExtras::PhotonPt, - v0SigmaPhotonExtras::PhotonQt, - v0SigmaPhotonExtras::PhotonAlpha, - v0SigmaPhotonExtras::PhotonRadius, - v0SigmaPhotonExtras::PhotonCosPA, - v0SigmaPhotonExtras::PhotonDCADau, - v0SigmaPhotonExtras::PhotonDCANegPV, - v0SigmaPhotonExtras::PhotonDCAPosPV, - v0SigmaPhotonExtras::PhotonZconv, - v0SigmaPhotonExtras::PhotonEta, - v0SigmaPhotonExtras::PhotonY, - v0SigmaPhotonExtras::PhotonPosTPCNSigma, - v0SigmaPhotonExtras::PhotonNegTPCNSigma, - v0SigmaPhotonExtras::PhotonPosTPCCrossedRows, - v0SigmaPhotonExtras::PhotonNegTPCCrossedRows, - v0SigmaPhotonExtras::PhotonPosPt, - v0SigmaPhotonExtras::PhotonNegPt, - v0SigmaPhotonExtras::PhotonPosEta, - v0SigmaPhotonExtras::PhotonNegEta, - v0SigmaPhotonExtras::PhotonPosY, - v0SigmaPhotonExtras::PhotonNegY, - v0SigmaPhotonExtras::PhotonPsiPair, - v0SigmaPhotonExtras::PhotonPosITSCls, - v0SigmaPhotonExtras::PhotonNegITSCls, - v0SigmaPhotonExtras::PhotonPosITSClSize, - v0SigmaPhotonExtras::PhotonNegITSClSize, - v0SigmaPhotonExtras::PhotonV0Type, - v0SigmaPhotonExtras::GammaBDTScore); + +} // namespace sigma0PhotonExtra + +DECLARE_SOA_TABLE(Sigma0PhotonExtras, "AOD", "SIGMA0PHOTON", + sigma0PhotonExtra::PhotonQt, + sigma0PhotonExtra::PhotonAlpha, + sigma0PhotonExtra::PhotonCosPA, + sigma0PhotonExtra::PhotonDCADau, + sigma0PhotonExtra::PhotonDCANegPV, + sigma0PhotonExtra::PhotonDCAPosPV, + sigma0PhotonExtra::PhotonRadius, + sigma0PhotonExtra::PhotonZconv, + sigma0PhotonExtra::PhotonPosTPCNSigmaEl, + sigma0PhotonExtra::PhotonNegTPCNSigmaEl, + sigma0PhotonExtra::PhotonPosTPCCrossedRows, + sigma0PhotonExtra::PhotonNegTPCCrossedRows, + sigma0PhotonExtra::PhotonPosEta, + sigma0PhotonExtra::PhotonNegEta, + sigma0PhotonExtra::PhotonPsiPair, + sigma0PhotonExtra::PhotonPosITSCls, + sigma0PhotonExtra::PhotonNegITSCls, + sigma0PhotonExtra::PhotonPosITSChi2PerNcl, + sigma0PhotonExtra::PhotonNegITSChi2PerNcl, + sigma0PhotonExtra::PhotonPosTrackCode, + sigma0PhotonExtra::PhotonNegTrackCode, + sigma0PhotonExtra::PhotonV0Type); // For Lambda extra info -namespace v0SigmaLambdaExtras +namespace sigma0LambdaExtra { -DECLARE_SOA_COLUMN(LambdaPt, lambdaPt, float); -DECLARE_SOA_COLUMN(LambdaMass, lambdaMass, 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(LambdaEta, lambdaEta, float); -DECLARE_SOA_COLUMN(LambdaY, lambdaY, 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(LambdaPosITSClSize, lambdaPosITSClSize, uint32_t); -DECLARE_SOA_COLUMN(LambdaNegITSClSize, lambdaNegITSClSize, uint32_t); +DECLARE_SOA_COLUMN(LambdaPosITSChi2PerNcl, lambdaPosChi2PerNcl, float); +DECLARE_SOA_COLUMN(LambdaNegITSChi2PerNcl, lambdaNegChi2PerNcl, float); +DECLARE_SOA_COLUMN(LambdaPosTrackCode, lambdaPosTrackCode, uint8_t); +DECLARE_SOA_COLUMN(LambdaNegTrackCode, lambdaNegTrackCode, uint8_t); DECLARE_SOA_COLUMN(LambdaV0Type, lambdaV0Type, uint8_t); -DECLARE_SOA_COLUMN(LambdaBDTScore, lambdaBDTScore, float); -DECLARE_SOA_COLUMN(AntiLambdaBDTScore, antilambdaBDTScore, float); - -} // namespace v0SigmaLambdaExtras - -DECLARE_SOA_TABLE(V0SigmaLambdaExtras, "AOD", "V0SIGMALAMBDA", - v0SigmaLambdaExtras::LambdaPt, - v0SigmaLambdaExtras::LambdaMass, - v0SigmaLambdaExtras::LambdaQt, - v0SigmaLambdaExtras::LambdaAlpha, - v0SigmaLambdaExtras::LambdaRadius, - v0SigmaLambdaExtras::LambdaCosPA, - v0SigmaLambdaExtras::LambdaDCADau, - v0SigmaLambdaExtras::LambdaDCANegPV, - v0SigmaLambdaExtras::LambdaDCAPosPV, - v0SigmaLambdaExtras::LambdaEta, - v0SigmaLambdaExtras::LambdaY, - v0SigmaLambdaExtras::LambdaPosPrTPCNSigma, - v0SigmaLambdaExtras::LambdaPosPiTPCNSigma, - v0SigmaLambdaExtras::LambdaNegPrTPCNSigma, - v0SigmaLambdaExtras::LambdaNegPiTPCNSigma, - v0SigmaLambdaExtras::LambdaPosTPCCrossedRows, - v0SigmaLambdaExtras::LambdaNegTPCCrossedRows, - v0SigmaLambdaExtras::LambdaPosPt, - v0SigmaLambdaExtras::LambdaNegPt, - v0SigmaLambdaExtras::LambdaPosEta, - v0SigmaLambdaExtras::LambdaNegEta, - v0SigmaLambdaExtras::LambdaPosPrY, - v0SigmaLambdaExtras::LambdaPosPiY, - v0SigmaLambdaExtras::LambdaNegPrY, - v0SigmaLambdaExtras::LambdaNegPiY, - v0SigmaLambdaExtras::LambdaPosITSCls, - v0SigmaLambdaExtras::LambdaNegITSCls, - v0SigmaLambdaExtras::LambdaPosITSClSize, - v0SigmaLambdaExtras::LambdaNegITSClSize, - v0SigmaLambdaExtras::LambdaV0Type, - v0SigmaLambdaExtras::LambdaBDTScore, - v0SigmaLambdaExtras::AntiLambdaBDTScore); - -// for MC data -namespace v0SigmaMCCandidate + +} // namespace sigma0LambdaExtra + +DECLARE_SOA_TABLE(Sigma0LambdaExtras, "AOD", "SIGMA0LAMBDA", + sigma0LambdaExtra::LambdaQt, + sigma0LambdaExtra::LambdaAlpha, + sigma0LambdaExtra::LambdaLifeTime, + sigma0LambdaExtra::LambdaRadius, + sigma0LambdaExtra::LambdaCosPA, + sigma0LambdaExtra::LambdaDCADau, + sigma0LambdaExtra::LambdaDCANegPV, + sigma0LambdaExtra::LambdaDCAPosPV, + sigma0LambdaExtra::LambdaPosPrTPCNSigma, + sigma0LambdaExtra::LambdaPosPiTPCNSigma, + sigma0LambdaExtra::LambdaNegPrTPCNSigma, + sigma0LambdaExtra::LambdaNegPiTPCNSigma, + sigma0LambdaExtra::LambdaPrTOFNSigma, + sigma0LambdaExtra::LambdaPiTOFNSigma, + sigma0LambdaExtra::ALambdaPrTOFNSigma, + sigma0LambdaExtra::ALambdaPiTOFNSigma, + sigma0LambdaExtra::LambdaPosTPCCrossedRows, + sigma0LambdaExtra::LambdaNegTPCCrossedRows, + sigma0LambdaExtra::LambdaPosEta, + sigma0LambdaExtra::LambdaNegEta, + sigma0LambdaExtra::LambdaPosITSCls, + sigma0LambdaExtra::LambdaNegITSCls, + sigma0LambdaExtra::LambdaPosITSChi2PerNcl, + sigma0LambdaExtra::LambdaNegITSChi2PerNcl, + sigma0LambdaExtra::LambdaPosTrackCode, + sigma0LambdaExtra::LambdaNegTrackCode, + sigma0LambdaExtra::LambdaV0Type); + +// for MC +namespace sigma0MCCore +{ +DECLARE_SOA_COLUMN(MCradius, mcradius, float); +DECLARE_SOA_COLUMN(PDGCode, pdgCode, int); +DECLARE_SOA_COLUMN(PDGCodeMother, pdgCodeMother, int); +DECLARE_SOA_COLUMN(MCprocess, mcprocess, int); +DECLARE_SOA_COLUMN(IsProducedByGenerator, isProducedByGenerator, bool); + +DECLARE_SOA_COLUMN(PhotonMCPx, photonmcpx, float); +DECLARE_SOA_COLUMN(PhotonMCPy, photonmcpy, float); +DECLARE_SOA_COLUMN(PhotonMCPz, photonmcpz, float); +DECLARE_SOA_COLUMN(IsPhotonPrimary, isPhotonPrimary, bool); +DECLARE_SOA_COLUMN(PhotonPDGCode, photonPDGCode, int); +DECLARE_SOA_COLUMN(PhotonPDGCodeMother, photonPDGCodeMother, int); +DECLARE_SOA_COLUMN(PhotonIsCorrectlyAssoc, photonIsCorrectlyAssoc, bool); + +DECLARE_SOA_COLUMN(LambdaMCPx, lambdamcpx, float); +DECLARE_SOA_COLUMN(LambdaMCPy, lambdamcpy, float); +DECLARE_SOA_COLUMN(LambdaMCPz, lambdamcpz, float); +DECLARE_SOA_COLUMN(IsLambdaPrimary, isLambdaPrimary, bool); +DECLARE_SOA_COLUMN(LambdaPDGCode, lambdaPDGCode, int); +DECLARE_SOA_COLUMN(LambdaPDGCodeMother, lambdaPDGCodeMother, int); +DECLARE_SOA_COLUMN(LambdaIsCorrectlyAssoc, lambdaIsCorrectlyAssoc, bool); + +DECLARE_SOA_DYNAMIC_COLUMN(IsSigma0, isSigma0, //! IsSigma0 + [](int pdgCode) -> bool { return pdgCode == 3212; }); + +DECLARE_SOA_DYNAMIC_COLUMN(IsAntiSigma0, isAntiSigma0, //! IsASigma0 + [](int pdgCode) -> bool { return pdgCode == -3212; }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCPx, mcpx, //! Sigma0 px + [](float photonMCPx, float lambdaMCPx) -> float { return photonMCPx + lambdaMCPx; }); +DECLARE_SOA_DYNAMIC_COLUMN(MCPy, mcpy, //! Sigma0 py + [](float photonMCPy, float lambdaMCPy) -> float { return photonMCPy + lambdaMCPy; }); +DECLARE_SOA_DYNAMIC_COLUMN(MCPz, mcpz, //! Sigma0 pz + [](float photonMCPz, float lambdaMCPz) -> float { return photonMCPz + lambdaMCPz; }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCPt, mcpt, + [](float photonMCPx, float photonMCPy, float lambdaMCPx, float lambdaMCPy) -> float { + return RecoDecay::pt(array{photonMCPx + lambdaMCPx, photonMCPy + lambdaMCPy}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCP, mcp, //! Total momentum in GeV/c + [](float photonMCPx, float photonMCPy, float photonMCPz, float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) -> float { + return RecoDecay::sqrtSumOfSquares(photonMCPx + lambdaMCPx, photonMCPy + lambdaMCPy, photonMCPz + lambdaMCPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Sigma0MCMass, sigma0MCMass, + [](float photonMCPx, float photonMCPy, float photonMCPz, float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) -> float { + std::array pVecPhotons{photonMCPx, photonMCPy, photonMCPz}; + std::array pVecLambda{lambdaMCPx, lambdaMCPy, lambdaMCPz}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + return RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Sigma0MCY, sigma0MCY, + [](float photonMCPx, float photonMCPy, float photonMCPz, float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) -> float { + return RecoDecay::y(std::array{photonMCPx + lambdaMCPx, photonMCPy + lambdaMCPy, photonMCPz + lambdaMCPz}, o2::constants::physics::MassSigma0); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCPhi, mcphi, //! Phi in the range [0, 2pi) + [](float photonMCPx, float photonMCPy, float lambdaMCPx, float lambdaMCPy) -> float { return RecoDecay::phi(photonMCPx + lambdaMCPx, photonMCPy + lambdaMCPy); }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCEta, mceta, //! Pseudorapidity + [](float photonMCPx, float photonMCPy, float photonMCPz, float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) -> float { + return RecoDecay::eta(std::array{photonMCPx + lambdaMCPx, photonMCPy + lambdaMCPy, photonMCPz + lambdaMCPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCOPAngle, mcopAngle, + [](float photonMCPx, float photonMCPy, float photonMCPz, float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) { + TVector3 v1(photonMCPx, photonMCPy, photonMCPz); + TVector3 v2(lambdaMCPx, lambdaMCPy, lambdaMCPz); + return v1.Angle(v2); + }); + +// Photon +DECLARE_SOA_DYNAMIC_COLUMN(PhotonMCPt, photonmcpt, //! Transverse momentum in GeV/c + [](float photonMCPx, float photonMCPy) -> float { + return RecoDecay::sqrtSumOfSquares(photonMCPx, photonMCPy); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(PhotonMCP, photonmcp, //! Total momentum in GeV/c + [](float photonMCPx, float photonMCPy, float photonMCPz) -> float { + return RecoDecay::sqrtSumOfSquares(photonMCPx, photonMCPy, photonMCPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(PhotonMCEta, photonMCEta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float photonMCPx, float photonMCPy, float photonMCPz) -> float { + return RecoDecay::eta(std::array{photonMCPx, photonMCPy, photonMCPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(PhotonMCY, photonMCY, //! Rapidity + [](float photonMCPx, float photonMCPy, float photonMCPz) -> float { + return RecoDecay::y(std::array{photonMCPx, photonMCPy, photonMCPz}, o2::constants::physics::MassGamma); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(PhotonMCPhi, photonMCPhi, //! Phi in the range [0, 2pi) + [](float photonMCPx, float photonMCPy) -> float { return RecoDecay::phi(photonMCPx, photonMCPy); }); + +// Lambda/ALambda +DECLARE_SOA_DYNAMIC_COLUMN(LambdaMCPt, lambdamcpt, //! Transverse momentum in GeV/c + [](float lambdaMCPx, float lambdaMCPy) -> float { + return RecoDecay::sqrtSumOfSquares(lambdaMCPx, lambdaMCPy); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(LambdaMCP, lambdamcp, //! Total momentum in GeV/c + [](float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) -> float { + return RecoDecay::sqrtSumOfSquares(lambdaMCPx, lambdaMCPy, lambdaMCPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(LambdaMCEta, lambdaMCEta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) -> float { + return RecoDecay::eta(std::array{lambdaMCPx, lambdaMCPy, lambdaMCPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(LambdaMCY, lambdaMCY, //! Rapidity + [](float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) -> float { + return RecoDecay::y(std::array{lambdaMCPx, lambdaMCPy, lambdaMCPz}, o2::constants::physics::MassLambda); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(LambdaMCPhi, lambdaMCPhi, //! Phi in the range [0, 2pi) + [](float lambdaMCPx, float lambdaMCPy) -> float { return RecoDecay::phi(lambdaMCPx, lambdaMCPy); }); + +} // namespace sigma0MCCore + +DECLARE_SOA_TABLE(Sigma0MCCores, "AOD", "SIGMA0MCCORES", + // Basic properties + sigma0MCCore::MCradius, sigma0MCCore::PDGCode, sigma0MCCore::PDGCodeMother, sigma0MCCore::MCprocess, sigma0MCCore::IsProducedByGenerator, + + sigma0MCCore::PhotonMCPx, sigma0MCCore::PhotonMCPy, sigma0MCCore::PhotonMCPz, + sigma0MCCore::IsPhotonPrimary, sigma0MCCore::PhotonPDGCode, sigma0MCCore::PhotonPDGCodeMother, sigma0MCCore::PhotonIsCorrectlyAssoc, + + sigma0MCCore::LambdaMCPx, sigma0MCCore::LambdaMCPy, sigma0MCCore::LambdaMCPz, + sigma0MCCore::IsLambdaPrimary, sigma0MCCore::LambdaPDGCode, sigma0MCCore::LambdaPDGCodeMother, sigma0MCCore::LambdaIsCorrectlyAssoc, + + // Dynamic columns + sigma0MCCore::IsSigma0, + sigma0MCCore::IsAntiSigma0, + + sigma0MCCore::MCPx, + sigma0MCCore::MCPy, + sigma0MCCore::MCPz, + sigma0MCCore::MCPt, + sigma0MCCore::MCP, + sigma0MCCore::Sigma0MCMass, + sigma0MCCore::Sigma0MCY, + sigma0MCCore::MCPhi, + sigma0MCCore::MCEta, + sigma0MCCore::MCOPAngle, + + sigma0MCCore::PhotonMCPt, + sigma0MCCore::PhotonMCP, + sigma0MCCore::PhotonMCEta, + sigma0MCCore::PhotonMCY, + sigma0MCCore::PhotonMCPhi, + + sigma0MCCore::LambdaMCPt, + sigma0MCCore::LambdaMCP, + sigma0MCCore::LambdaMCEta, + sigma0MCCore::LambdaMCY, + sigma0MCCore::LambdaMCPhi); + +namespace sigma0Gen +{ +DECLARE_SOA_COLUMN(IsSigma0, isSigma0, bool); // true: sigma0, false: antisigma0 +DECLARE_SOA_COLUMN(ProducedByGenerator, producedByGenerator, bool); +DECLARE_SOA_COLUMN(Sigma0MCPt, sigma0MCPt, float); // MC pT + +} // namespace sigma0Gen + +DECLARE_SOA_TABLE(Sigma0Gens, "AOD", "SIGMA0GENS", + sigma0Gen::IsSigma0, + sigma0Gen::ProducedByGenerator, + sigma0Gen::Sigma0MCPt); + +DECLARE_SOA_TABLE(SigmaCollRef, "AOD", "SIGMACOLLREF", //! optional table to refer back to a collision + o2::soa::Index<>, v0data::StraCollisionId); + +DECLARE_SOA_TABLE(SigmaGenCollRef, "AOD", "SIGMAGENCOLLREF", //! optional table to refer back to a collision + o2::soa::Index<>, v0data::StraMCCollisionId); + +// ___________________________________________________________________________ +// pi0 QA +namespace Pi0Core { -DECLARE_SOA_COLUMN(IsSigma, isSigma, bool); -} // namespace v0SigmaMCCandidate +DECLARE_SOA_COLUMN(X, x, float); +DECLARE_SOA_COLUMN(Y, y, float); +DECLARE_SOA_COLUMN(Z, z, float); +DECLARE_SOA_COLUMN(DCADaughters, dcadaughters, float); +DECLARE_SOA_COLUMN(CosPA, cospa, float); + +DECLARE_SOA_COLUMN(Photon1Px, photon1Px, float); +DECLARE_SOA_COLUMN(Photon1Py, photon1Py, float); +DECLARE_SOA_COLUMN(Photon1Pz, photon1Pz, float); +DECLARE_SOA_COLUMN(Photon1Mass, photon1Mass, float); +DECLARE_SOA_COLUMN(Photon1Qt, photon1Qt, float); +DECLARE_SOA_COLUMN(Photon1Alpha, photon1Alpha, float); +DECLARE_SOA_COLUMN(Photon1DCAPosPV, photon1DCAPosPV, float); +DECLARE_SOA_COLUMN(Photon1DCANegPV, photon1DCANegPV, float); +DECLARE_SOA_COLUMN(Photon1DCADau, photon1DCADau, float); +DECLARE_SOA_COLUMN(Photon1NegEta, photon1NegEta, float); +DECLARE_SOA_COLUMN(Photon1PosEta, photon1PosEta, float); +DECLARE_SOA_COLUMN(Photon1CosPA, photon1CosPA, float); +DECLARE_SOA_COLUMN(Photon1Radius, photon1Radius, float); +DECLARE_SOA_COLUMN(Photon1Zconv, photon1Zconv, float); +DECLARE_SOA_COLUMN(Photon1PosTPCCrossedRows, photon1PosTPCCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(Photon1NegTPCCrossedRows, photon1NegTPCCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(Photon1PosTPCNSigmaEl, photon1PosTPCNSigmaEl, float); +DECLARE_SOA_COLUMN(Photon1NegTPCNSigmaEl, photon1NegTPCNSigmaEl, float); +DECLARE_SOA_COLUMN(Photon1V0Type, photon1V0Type, uint8_t); + +DECLARE_SOA_COLUMN(Photon2Px, photon2Px, float); +DECLARE_SOA_COLUMN(Photon2Py, photon2Py, float); +DECLARE_SOA_COLUMN(Photon2Pz, photon2Pz, float); +DECLARE_SOA_COLUMN(Photon2Mass, photon2Mass, float); +DECLARE_SOA_COLUMN(Photon2Qt, photon2Qt, float); +DECLARE_SOA_COLUMN(Photon2Alpha, photon2Alpha, float); +DECLARE_SOA_COLUMN(Photon2DCAPosPV, photon2DCAPosPV, float); +DECLARE_SOA_COLUMN(Photon2DCANegPV, photon2DCANegPV, float); +DECLARE_SOA_COLUMN(Photon2DCADau, photon2DCADau, float); +DECLARE_SOA_COLUMN(Photon2NegEta, photon2NegEta, float); +DECLARE_SOA_COLUMN(Photon2PosEta, photon2PosEta, float); +DECLARE_SOA_COLUMN(Photon2CosPA, photon2CosPA, float); +DECLARE_SOA_COLUMN(Photon2Radius, photon2Radius, float); +DECLARE_SOA_COLUMN(Photon2Zconv, photon2Zconv, float); +DECLARE_SOA_COLUMN(Photon2PosTPCCrossedRows, photon2PosTPCCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(Photon2NegTPCCrossedRows, photon2NegTPCCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(Photon2PosTPCNSigmaEl, photon2PosTPCNSigmaEl, float); +DECLARE_SOA_COLUMN(Photon2NegTPCNSigmaEl, photon2NegTPCNSigmaEl, float); +DECLARE_SOA_COLUMN(Photon2V0Type, photon2V0Type, uint8_t); + +//______________________________________________________ +// DYNAMIC COLUMNS +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! Pi0 px + [](float photon1Px, float photon2Px) -> float { return photon1Px + photon2Px; }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! Pi0 py + [](float photon1Py, float photon2Py) -> float { return photon1Py + photon2Py; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! Pi0 pz + [](float photon1Pz, float photon2Pz) -> float { return photon1Pz + photon2Pz; }); + +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, + [](float photon1Px, float photon1Py, float photon2Px, float photon2Py) -> float { + return RecoDecay::pt(array{photon1Px + photon2Px, photon1Py + photon2Py}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! Total momentum in GeV/c + [](float photon1Px, float photon1Py, float photon1Pz, float photon2Px, float photon2Py, float photon2Pz) -> float { + return RecoDecay::sqrtSumOfSquares(photon1Px + photon2Px, photon1Py + photon2Py, photon1Pz + photon2Pz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Pi0Mass, pi0Mass, + [](float photon1Px, float photon1Py, float photon1Pz, float photon2Px, float photon2Py, float photon2Pz) -> float { + std::array pVecPhoton1{photon1Px, photon1Py, photon1Pz}; + std::array pVecPhoton2{photon2Px, photon2Py, photon2Pz}; + auto arrMom = std::array{pVecPhoton1, pVecPhoton2}; + return RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Pi0Y, pi0Y, + [](float photon1Px, float photon1Py, float photon1Pz, float photon2Px, float photon2Py, float photon2Pz) -> float { + return RecoDecay::y(std::array{photon1Px + photon2Px, photon1Py + photon2Py, photon1Pz + photon2Pz}, o2::constants::physics::MassPi0); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! Phi in the range [0, 2pi) + [](float photon1Px, float photon1Py, float photon2Px, float photon2Py) -> float { return RecoDecay::phi(photon1Px + photon2Px, photon1Py + photon2Py); }); + +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! Pseudorapidity + [](float photon1Px, float photon1Py, float photon1Pz, float photon2Px, float photon2Py, float photon2Pz) -> float { + return RecoDecay::eta(std::array{photon1Px + photon2Px, photon1Py + photon2Py, photon1Pz + photon2Pz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Radius, radius, //! Pi0 decay radius (2D, centered at zero) + [](float x, float y) -> float { return RecoDecay::sqrtSumOfSquares(x, y); }); + +DECLARE_SOA_DYNAMIC_COLUMN(OPAngle, opAngle, + [](float photon1Px, float photon1Py, float photon1Pz, float photon2Px, float photon2Py, float photon2Pz) { + TVector3 v1(photon1Px, photon1Py, photon1Pz); + TVector3 v2(photon2Px, photon2Py, photon2Pz); + return v1.Angle(v2); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1Pt, photon1Pt, //! Transverse momentum in GeV/c + [](float photon1Px, float photon1Py) -> float { + return RecoDecay::sqrtSumOfSquares(photon1Px, photon1Py); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1P, photon1p, //! Total momentum in GeV/c + [](float photon1Px, float photon1Py, float photon1Pz) -> float { + return RecoDecay::sqrtSumOfSquares(photon1Px, photon1Py, photon1Pz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1Eta, photon1Eta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float photon1Px, float photon1Py, float photon1Pz) -> float { + return RecoDecay::eta(std::array{photon1Px, photon1Py, photon1Pz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1Y, photon1Y, //! Rapidity + [](float photon1Px, float photon1Py, float photon1Pz) -> float { + return RecoDecay::y(std::array{photon1Px, photon1Py, photon1Pz}, o2::constants::physics::MassGamma); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1Phi, photon1Phi, //! Phi in the range [0, 2pi) + [](float photon1Px, float photon1Py) -> float { return RecoDecay::phi(photon1Px, photon1Py); }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2Pt, photon2Pt, //! Transverse momentum in GeV/c + [](float photon2Px, float photon2Py) -> float { + return RecoDecay::sqrtSumOfSquares(photon2Px, photon2Py); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2P, photon2p, //! Total momentum in GeV/c + [](float photon2Px, float photon2Py, float photon2Pz) -> float { + return RecoDecay::sqrtSumOfSquares(photon2Px, photon2Py, photon2Pz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2Eta, photon2Eta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float photon2Px, float photon2Py, float photon2Pz) -> float { + return RecoDecay::eta(std::array{photon2Px, photon2Py, photon2Pz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2Y, photon2Y, //! Rapidity + [](float photon2Px, float photon2Py, float photon2Pz) -> float { + return RecoDecay::y(std::array{photon2Px, photon2Py, photon2Pz}, o2::constants::physics::MassGamma); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2Phi, photon2Phi, //! Phi in the range [0, 2pi) + [](float photon2Px, float photon2Py) -> float { return RecoDecay::phi(photon2Px, photon2Py); }); + +} // namespace Pi0Core + +DECLARE_SOA_TABLE(Pi0Cores, "AOD", "PI0CORES", + Pi0Core::X, Pi0Core::Y, Pi0Core::Z, Pi0Core::DCADaughters, Pi0Core::CosPA, + + // Photon 1 base properties + Pi0Core::Photon1Px, Pi0Core::Photon1Py, Pi0Core::Photon1Pz, + Pi0Core::Photon1Mass, Pi0Core::Photon1Qt, Pi0Core::Photon1Alpha, Pi0Core::Photon1DCAPosPV, Pi0Core::Photon1DCANegPV, Pi0Core::Photon1DCADau, + Pi0Core::Photon1NegEta, Pi0Core::Photon1PosEta, Pi0Core::Photon1CosPA, Pi0Core::Photon1Radius, Pi0Core::Photon1Zconv, + Pi0Core::Photon1PosTPCCrossedRows, Pi0Core::Photon1NegTPCCrossedRows, Pi0Core::Photon1PosTPCNSigmaEl, Pi0Core::Photon1NegTPCNSigmaEl, Pi0Core::Photon1V0Type, + + // Photon 2 base properties + Pi0Core::Photon2Px, Pi0Core::Photon2Py, Pi0Core::Photon2Pz, + Pi0Core::Photon2Mass, Pi0Core::Photon2Qt, Pi0Core::Photon2Alpha, Pi0Core::Photon2DCAPosPV, Pi0Core::Photon2DCANegPV, Pi0Core::Photon2DCADau, + Pi0Core::Photon2NegEta, Pi0Core::Photon2PosEta, Pi0Core::Photon2CosPA, Pi0Core::Photon2Radius, Pi0Core::Photon2Zconv, + Pi0Core::Photon2PosTPCCrossedRows, Pi0Core::Photon2NegTPCCrossedRows, Pi0Core::Photon2PosTPCNSigmaEl, Pi0Core::Photon2NegTPCNSigmaEl, Pi0Core::Photon2V0Type, + + // Dynamic columns + Pi0Core::Px, + Pi0Core::Py, + Pi0Core::Pz, + Pi0Core::Pt, + Pi0Core::P, + Pi0Core::Pi0Mass, + Pi0Core::Pi0Y, + Pi0Core::Phi, + Pi0Core::Eta, + Pi0Core::Radius, + Pi0Core::OPAngle, + + Pi0Core::Photon1Pt, + Pi0Core::Photon1P, + Pi0Core::Photon1Eta, + Pi0Core::Photon1Y, + Pi0Core::Photon1Phi, + + Pi0Core::Photon2Pt, + Pi0Core::Photon2P, + Pi0Core::Photon2Eta, + Pi0Core::Photon2Y, + Pi0Core::Photon2Phi); + +// for MC +namespace Pi0CoreMC +{ + +DECLARE_SOA_COLUMN(MCradius, mcradius, float); +DECLARE_SOA_COLUMN(PDGCode, pdgCode, int); +DECLARE_SOA_COLUMN(PDGCodeMother, pdgCodeMother, int); +DECLARE_SOA_COLUMN(MCprocess, mcprocess, int); +DECLARE_SOA_COLUMN(IsProducedByGenerator, isProducedByGenerator, bool); + +DECLARE_SOA_COLUMN(Photon1MCPx, photon1mcpx, float); +DECLARE_SOA_COLUMN(Photon1MCPy, photon1mcpy, float); +DECLARE_SOA_COLUMN(Photon1MCPz, photon1mcpz, float); +DECLARE_SOA_COLUMN(IsPhoton1Primary, isPhoton1Primary, bool); +DECLARE_SOA_COLUMN(Photon1PDGCode, photon1PDGCode, int); +DECLARE_SOA_COLUMN(Photon1PDGCodeMother, photon1PDGCodeMother, int); +DECLARE_SOA_COLUMN(Photon1IsCorrectlyAssoc, photon1IsCorrectlyAssoc, bool); + +DECLARE_SOA_COLUMN(Photon2MCPx, photon2mcpx, float); +DECLARE_SOA_COLUMN(Photon2MCPy, photon2mcpy, float); +DECLARE_SOA_COLUMN(Photon2MCPz, photon2mcpz, float); +DECLARE_SOA_COLUMN(IsPhoton2Primary, isPhoton2Primary, bool); +DECLARE_SOA_COLUMN(Photon2PDGCode, photon2PDGCode, int); +DECLARE_SOA_COLUMN(Photon2PDGCodeMother, photon2PDGCodeMother, int); +DECLARE_SOA_COLUMN(Photon2IsCorrectlyAssoc, photon2IsCorrectlyAssoc, bool); + +DECLARE_SOA_DYNAMIC_COLUMN(IsPi0, isPi0, //! IsPi0 + [](int pdgCode) -> bool { return pdgCode == 111; }); + +DECLARE_SOA_DYNAMIC_COLUMN(IsFromXi0, isFromXi0, //! Pi0 from Xi0 + [](int pdgCodeMother) -> bool { return pdgCodeMother == 3322; }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCPx, mcpx, //! Pi0 MC px + [](float photon1MCPx, float photon2MCPx) -> float { return photon1MCPx + photon2MCPx; }); +DECLARE_SOA_DYNAMIC_COLUMN(MCPy, mcpy, //! Pi0 MC py + [](float photon1MCPy, float photon2MCPy) -> float { return photon1MCPy + photon2MCPy; }); +DECLARE_SOA_DYNAMIC_COLUMN(MCPz, mcpz, //! Pi0 MC pz + [](float photon1MCPz, float photon2MCPz) -> float { return photon1MCPz + photon2MCPz; }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCPt, mcpt, + [](float photon1MCPx, float photon1MCPy, float photon2MCPx, float photon2MCPy) -> float { + return RecoDecay::pt(array{photon1MCPx + photon2MCPx, photon1MCPy + photon2MCPy}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCP, mcp, //! Total momentum in GeV/c + [](float photon1MCPx, float photon1MCPy, float photon1MCPz, float photon2MCPx, float photon2MCPy, float photon2MCPz) -> float { + return RecoDecay::sqrtSumOfSquares(photon1MCPx + photon2MCPx, photon1MCPy + photon2MCPy, photon1MCPz + photon2MCPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Pi0MCMass, pi0MCMass, + [](float photon1MCPx, float photon1MCPy, float photon1MCPz, float photon2MCPx, float photon2MCPy, float photon2MCPz) -> float { + std::array pVecPhoton1{photon1MCPx, photon1MCPy, photon1MCPz}; + std::array pVecPhoton2{photon2MCPx, photon2MCPy, photon2MCPz}; + auto arrMom = std::array{pVecPhoton1, pVecPhoton2}; + return RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Pi0MCY, pi0MCY, + [](float photon1MCPx, float photon1MCPy, float photon1MCPz, float photon2MCPx, float photon2MCPy, float photon2MCPz) -> float { + return RecoDecay::y(std::array{photon1MCPx + photon2MCPx, photon1MCPy + photon2MCPy, photon1MCPz + photon2MCPz}, o2::constants::physics::MassPi0); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCPhi, mcphi, //! Phi in the range [0, 2pi) + [](float photon1MCPx, float photon1MCPy, float photon2MCPx, float photon2MCPy) -> float { return RecoDecay::phi(photon1MCPx + photon2MCPx, photon1MCPy + photon2MCPy); }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCEta, mceta, //! Pseudorapidity + [](float photon1MCPx, float photon1MCPy, float photon1MCPz, float photon2MCPx, float photon2MCPy, float photon2MCPz) -> float { + return RecoDecay::eta(std::array{photon1MCPx + photon2MCPx, photon1MCPy + photon2MCPy, photon1MCPz + photon2MCPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(MCOPAngle, mcopAngle, + [](float photon1MCPx, float photon1MCPy, float photon1MCPz, float photon2MCPx, float photon2MCPy, float photon2MCPz) { + TVector3 v1(photon1MCPx, photon1MCPy, photon1MCPz); + TVector3 v2(photon2MCPx, photon2MCPy, photon2MCPz); + return v1.Angle(v2); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1MCPt, photon1MCPt, //! Transverse momentum in GeV/c + [](float photon1MCPx, float photon1MCPy) -> float { + return RecoDecay::sqrtSumOfSquares(photon1MCPx, photon1MCPy); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1MCP, photon1MCp, //! Total momentum in GeV/c + [](float photon1MCPx, float photon1MCPy, float photon1MCPz) -> float { + return RecoDecay::sqrtSumOfSquares(photon1MCPx, photon1MCPy, photon1MCPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1MCEta, photon1MCEta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float photon1MCPx, float photon1MCPy, float photon1MCPz) -> float { + return RecoDecay::eta(std::array{photon1MCPx, photon1MCPy, photon1MCPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1MCY, photon1MCY, //! Rapidity + [](float photon1MCPx, float photon1MCPy, float photon1MCPz) -> float { + return RecoDecay::y(std::array{photon1MCPx, photon1MCPy, photon1MCPz}, o2::constants::physics::MassGamma); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon1MCPhi, photon1MCPhi, //! Phi in the range [0, 2pi) + [](float photon1MCPx, float photon1MCPy) -> float { return RecoDecay::phi(photon1MCPx, photon1MCPy); }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2MCPt, photon2MCPt, //! Transverse momentum in GeV/c + [](float photon2MCPx, float photon2MCPy) -> float { + return RecoDecay::sqrtSumOfSquares(photon2MCPx, photon2MCPy); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2MCP, photon2MCp, //! Total momentum in GeV/c + [](float photon2MCPx, float photon2MCPy, float photon2MCPz) -> float { + return RecoDecay::sqrtSumOfSquares(photon2MCPx, photon2MCPy, photon2MCPz); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2MCEta, photon2MCEta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float photon2MCPx, float photon2MCPy, float photon2MCPz) -> float { + return RecoDecay::eta(std::array{photon2MCPx, photon2MCPy, photon2MCPz}); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2MCY, photon2MCY, //! Rapidity + [](float photon2MCPx, float photon2MCPy, float photon2MCPz) -> float { + return RecoDecay::y(std::array{photon2MCPx, photon2MCPy, photon2MCPz}, o2::constants::physics::MassGamma); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(Photon2MCPhi, photon2MCPhi, //! Phi in the range [0, 2pi) + [](float photon2MCPx, float photon2MCPy) -> float { return RecoDecay::phi(photon2MCPx, photon2MCPy); }); + +} // namespace Pi0CoreMC + +DECLARE_SOA_TABLE(Pi0CoresMC, "AOD", "PI0CORESMC", + // Basic properties + Pi0CoreMC::MCradius, Pi0CoreMC::PDGCode, Pi0CoreMC::PDGCodeMother, Pi0CoreMC::MCprocess, Pi0CoreMC::IsProducedByGenerator, + + Pi0CoreMC::Photon1MCPx, Pi0CoreMC::Photon1MCPy, Pi0CoreMC::Photon1MCPz, + Pi0CoreMC::IsPhoton1Primary, Pi0CoreMC::Photon1PDGCode, Pi0CoreMC::Photon1PDGCodeMother, Pi0CoreMC::Photon1IsCorrectlyAssoc, + + Pi0CoreMC::Photon2MCPx, Pi0CoreMC::Photon2MCPy, Pi0CoreMC::Photon2MCPz, + Pi0CoreMC::IsPhoton2Primary, Pi0CoreMC::Photon2PDGCode, Pi0CoreMC::Photon2PDGCodeMother, Pi0CoreMC::Photon2IsCorrectlyAssoc, + + // Dynamic columns + Pi0CoreMC::IsPi0, + Pi0CoreMC::IsFromXi0, + + Pi0CoreMC::MCPx, + Pi0CoreMC::MCPy, + Pi0CoreMC::MCPz, + Pi0CoreMC::MCPt, + Pi0CoreMC::MCP, + Pi0CoreMC::Pi0MCMass, + Pi0CoreMC::Pi0MCY, + Pi0CoreMC::MCPhi, + Pi0CoreMC::MCEta, + Pi0CoreMC::MCOPAngle, + + Pi0CoreMC::Photon1MCPt, + Pi0CoreMC::Photon1MCP, + Pi0CoreMC::Photon1MCEta, + Pi0CoreMC::Photon1MCY, + Pi0CoreMC::Photon1MCPhi, + + Pi0CoreMC::Photon2MCPt, + Pi0CoreMC::Photon2MCP, + Pi0CoreMC::Photon2MCEta, + Pi0CoreMC::Photon2MCY, + Pi0CoreMC::Photon2MCPhi); + +DECLARE_SOA_TABLE(Pi0CollRef, "AOD", "PI0COLLREF", //! optional table to refer back to a collision + o2::soa::Index<>, v0data::StraCollisionId); + +namespace pi0Gen +{ +DECLARE_SOA_COLUMN(ProducedByGenerator, producedByGenerator, bool); +DECLARE_SOA_COLUMN(Pi0MCPt, pi0MCPt, float); // MC pT +} // namespace pi0Gen + +DECLARE_SOA_TABLE(Pi0Gens, "AOD", "PI0GENS", + pi0Gen::ProducedByGenerator, + pi0Gen::Pi0MCPt); + +DECLARE_SOA_TABLE(Pi0GenCollRef, "AOD", "PI0GENCOLLREF", //! optional table to refer back to a collision + o2::soa::Index<>, v0data::StraMCCollisionId); -DECLARE_SOA_TABLE(V0SigmaMCCandidates, "AOD", "V0MCSIGMAS", - v0SigmaMCCandidate::IsSigma); } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFSIGMATABLES_H_ diff --git a/PWGLF/DataModel/LFSlimHeLambda.h b/PWGLF/DataModel/LFSlimHeLambda.h new file mode 100644 index 00000000000..8745ac1838a --- /dev/null +++ b/PWGLF/DataModel/LFSlimHeLambda.h @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file LFSlimNucleiTables.h +/// \brief Slim nuclei tables +/// + +#ifndef PWGLF_DATAMODEL_LFSLIMNUCLEITABLES_H_ +#define PWGLF_DATAMODEL_LFSLIMNUCLEITABLES_H_ + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +#include + +namespace o2::aod +{ +namespace lfv0he3 +{ +DECLARE_SOA_COLUMN(Z, z, float); +DECLARE_SOA_COLUMN(CentT0C, centT0C, float); +} // namespace lfv0he3 +DECLARE_SOA_TABLE(LFEvents, "AOD", "LFEVENT", o2::soa::Index<>, lfv0he3::Z, lfv0he3::CentT0C); + +namespace lfv0he3 +{ +DECLARE_SOA_INDEX_COLUMN(LFEvent, lfEvent); // Collision ID for the event +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(CosPA, cosPA, float); +DECLARE_SOA_COLUMN(DCAxy, dcaXY, float); +DECLARE_SOA_COLUMN(DCAz, dcaZ, float); +DECLARE_SOA_COLUMN(TPCnCls, tpcNCls, int); +DECLARE_SOA_COLUMN(TPCnClsPID, tpcNClsPID, int); +DECLARE_SOA_COLUMN(ITSClusterSizes, itsClusterSizes, uint32_t); +DECLARE_SOA_COLUMN(NsigmaTPCPion, nSigmaTPCPion, float); +DECLARE_SOA_COLUMN(NsigmaTPCProton, nSigmaTPCProton, float); +DECLARE_SOA_COLUMN(NsigmaTPC, nSigmaTPC, float); +DECLARE_SOA_COLUMN(DCAdaughters, dcaDaughters, float); +DECLARE_SOA_COLUMN(DCAPVProton, dcaPVProton, float); +DECLARE_SOA_COLUMN(DCAPVPion, dcaPVPion, float); +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(Sign, sign, int8_t); +} // namespace lfv0he3 +DECLARE_SOA_TABLE_VERSIONED(LFHe3_000, "AOD", "LFHE3V0", 0, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::DCAxy, lfv0he3::DCAz, lfv0he3::TPCnCls, lfv0he3::ITSClusterSizes, lfv0he3::NsigmaTPC, lfv0he3::Sign); +DECLARE_SOA_TABLE_VERSIONED(LFLambda_000, "AOD", "LFLAMBDA", 0, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::Mass, lfv0he3::CosPA, lfv0he3::DCAdaughters, lfv0he3::DCAPVProton, lfv0he3::DCAPVPion, lfv0he3::V0Radius, lfv0he3::Sign); + +DECLARE_SOA_TABLE_VERSIONED(LFHe3_001, "AOD", "LFHE3V0", 1, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::DCAxy, lfv0he3::DCAz, lfv0he3::TPCnCls, lfv0he3::TPCnClsPID, lfv0he3::ITSClusterSizes, lfv0he3::NsigmaTPC, lfv0he3::Sign); +DECLARE_SOA_TABLE_VERSIONED(LFLambda_001, "AOD", "LFLAMBDA", 1, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::Mass, lfv0he3::CosPA, lfv0he3::DCAdaughters, lfv0he3::DCAPVProton, lfv0he3::DCAPVPion, lfv0he3::V0Radius, lfv0he3::NsigmaTPCProton, lfv0he3::NsigmaTPCPion, lfv0he3::Sign); +} // namespace o2::aod + +struct he3Candidate { + ROOT::Math::LorentzVector> momentum; // 4-momentum of the He3 candidate + float nSigmaTPC = -999.f; // TPC nSigma for He3 + float dcaXY = -999.f; + float dcaZ = -999.f; + int tpcNClsFound = 0; // Number of TPC clusters found + int tpcNClsPID = 0; // Number of TPC clusters used for PID + int itsNCls = 0; // Number of ITS clusters + uint32_t itsClusterSizes = 0; // ITS cluster sizes + int8_t sign = 0; // Charge sign of the He3 candidate +}; + +struct lambdaCandidate { + ROOT::Math::LorentzVector> momentum; + float mass = -1.f; // Lambda mass + float cosPA = -2.f; // Cosine of pointing angle + float dcaV0Daughters = -999.f; // DCA between V0 daughters + float dcaProtonToPV = -999.f; // DCA of the proton to primary vertex + float dcaPionToPV = -999.f; // DCA of the pion to primary vertex + float v0Radius = -1.f; // V0 radius + float protonNSigmaTPC = -999.f; // Proton TPC nSigma + float pionNSigmaTPC = -999.f; // Pion TPC nSigma + int8_t sign = 0; // Charge sign of the Lambda candidate +}; + +#endif // PWGLF_DATAMODEL_LFSLIMNUCLEITABLES_H_ diff --git a/PWGLF/DataModel/LFSlimNucleiTables.h b/PWGLF/DataModel/LFSlimNucleiTables.h index c61c1b25a7b..6a8725aa876 100644 --- a/PWGLF/DataModel/LFSlimNucleiTables.h +++ b/PWGLF/DataModel/LFSlimNucleiTables.h @@ -14,10 +14,11 @@ /// \brief Slim nuclei tables /// -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" #include "Common/DataModel/Centrality.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + #ifndef PWGLF_DATAMODEL_LFSLIMNUCLEITABLES_H_ #define PWGLF_DATAMODEL_LFSLIMNUCLEITABLES_H_ @@ -31,25 +32,54 @@ DECLARE_SOA_COLUMN(Phi, phi, float); DECLARE_SOA_COLUMN(TPCInnerParam, tpcInnerParam, float); DECLARE_SOA_COLUMN(Beta, beta, float); DECLARE_SOA_COLUMN(Zvertex, zVertex, float); +DECLARE_SOA_COLUMN(NContrib, nContrib, int); DECLARE_SOA_COLUMN(DCAxy, dcaxy, float); 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(SurvivedEventSelection, survivedEventSelection, bool); 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(SurvivedEventSelection, survivedEventSelection, bool); +DECLARE_SOA_COLUMN(MotherPDGcode, MotherpdgCode, int); +DECLARE_SOA_COLUMN(MotherDecRad, motherDecRad, float); DECLARE_SOA_COLUMN(AbsoDecL, absoDecL, float); +DECLARE_SOA_COLUMN(McProcess, mcProcess, uint64_t); } // namespace NucleiTableNS + +namespace NucleiPairTableNS +{ +DECLARE_SOA_COLUMN(Pt1, pt1, float); // first particle pt +DECLARE_SOA_COLUMN(Eta1, eta1, float); // first particle eta +DECLARE_SOA_COLUMN(Phi1, phi1, float); // first particle phi +DECLARE_SOA_COLUMN(TPCInnerParam1, tpcInnerParam1, float); // first particle TPC inner param +DECLARE_SOA_COLUMN(TPCsignal1, tpcSignal1, float); // first particle TPC signal +DECLARE_SOA_COLUMN(DCAxy1, dcaxy1, float); // first particle DCA xy +DECLARE_SOA_COLUMN(DCAz1, dcaz1, float); // first particle DCA z +DECLARE_SOA_COLUMN(ClusterSizesITS1, clusterSizesITS1, uint32_t); // first particle ITS cluster sizes +DECLARE_SOA_COLUMN(Flags1, flags1, uint16_t); // first particle flags +DECLARE_SOA_COLUMN(Pt2, pt2, float); // second particle pt +DECLARE_SOA_COLUMN(Eta2, eta2, float); // second particle eta +DECLARE_SOA_COLUMN(Phi2, phi2, float); // second particle phi +DECLARE_SOA_COLUMN(TPCInnerParam2, tpcInnerParam2, float); // second particle TPC inner param +DECLARE_SOA_COLUMN(TPCsignal2, tpcSignal2, float); // second particle TPC signal +DECLARE_SOA_COLUMN(DCAxy2, dcaxy2, float); // second particle DCA xy +DECLARE_SOA_COLUMN(DCAz2, dcaz2, float); // second particle DCA z +DECLARE_SOA_COLUMN(ClusterSizesITS2, clusterSizesITS2, uint32_t); // second particle ITS cluster sizes +DECLARE_SOA_COLUMN(Flags2, flags2, uint16_t); // second particle flags +} // namespace NucleiPairTableNS + namespace NucleiFlowTableNS { DECLARE_SOA_COLUMN(CentFV0A, centFV0A, float); // centrality with FT0A estimator @@ -57,13 +87,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", @@ -73,16 +105,19 @@ DECLARE_SOA_TABLE(NucleiTable, "AOD", "NUCLEITABLE", NucleiTableNS::TPCInnerParam, NucleiTableNS::Beta, NucleiTableNS::Zvertex, + NucleiTableNS::NContrib, NucleiTableNS::DCAxy, NucleiTableNS::DCAz, 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 +126,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, @@ -106,24 +143,65 @@ DECLARE_SOA_TABLE(NucleiTableMC, "AOD", "NUCLEITABLEMC", NucleiTableNS::TPCInnerParam, NucleiTableNS::Beta, NucleiTableNS::Zvertex, + NucleiTableNS::NContrib, NucleiTableNS::DCAxy, NucleiTableNS::DCAz, NucleiTableNS::TPCsignal, NucleiTableNS::ITSchi2, NucleiTableNS::TPCchi2, + NucleiTableNS::TOFchi2, NucleiTableNS::Flags, NucleiTableNS::TPCfindableCls, NucleiTableNS::TPCcrossedRows, NucleiTableNS::ITSclsMap, NucleiTableNS::TPCnCls, + NucleiTableNS::TPCnClsShared, NucleiTableNS::ITSclusterSizes, + NucleiTableNS::SurvivedEventSelection, NucleiTableNS::gPt, NucleiTableNS::gEta, NucleiTableNS::gPhi, NucleiTableNS::PDGcode, - NucleiTableNS::SurvivedEventSelection, + NucleiTableNS::MotherPDGcode, + NucleiTableNS::MotherDecRad, NucleiTableNS::AbsoDecL); +DECLARE_SOA_TABLE(NucleiPairTable, "AOD", "NUCLEIPAIRTABLE", + NucleiPairTableNS::Pt1, + NucleiPairTableNS::Eta1, + NucleiPairTableNS::Phi1, + NucleiPairTableNS::TPCInnerParam1, + NucleiPairTableNS::TPCsignal1, + NucleiPairTableNS::DCAxy1, + NucleiPairTableNS::DCAz1, + NucleiPairTableNS::ClusterSizesITS1, + NucleiPairTableNS::Flags1, + NucleiPairTableNS::Pt2, + NucleiPairTableNS::Eta2, + NucleiPairTableNS::Phi2, + NucleiPairTableNS::TPCInnerParam2, + NucleiPairTableNS::TPCsignal2, + NucleiPairTableNS::DCAxy2, + NucleiPairTableNS::DCAz2, + NucleiPairTableNS::ClusterSizesITS2, + NucleiPairTableNS::Flags2); + +// Reduced table +DECLARE_SOA_TABLE(NucleiTableRed, "AOD", "NUCLEITABLERED", + NucleiTableNS::Pt, + NucleiTableNS::Eta, + NucleiTableNS::Phi, + NucleiTableNS::TPCInnerParam, + NucleiTableNS::ITSclusterSizes, + NucleiTableNS::TPCsignal, + NucleiTableNS::Beta, + NucleiTableNS::DCAxy, + NucleiTableNS::DCAz, + NucleiTableNS::Flags, + NucleiTableNS::McProcess, + NucleiTableNS::PDGcode, + NucleiTableNS::MotherPDGcode); + } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFSLIMNUCLEITABLES_H_ diff --git a/PWGLF/DataModel/LFSlimStrangeTables.h b/PWGLF/DataModel/LFSlimStrangeTables.h index 659e0fcb280..423a412bb6d 100644 --- a/PWGLF/DataModel/LFSlimStrangeTables.h +++ b/PWGLF/DataModel/LFSlimStrangeTables.h @@ -41,6 +41,12 @@ 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); @@ -125,6 +131,12 @@ DECLARE_SOA_TABLE(McV0TableAP, "AOD", "MCV0TABLEAP", SlimLambdaTables::PxNeg, SlimLambdaTables::PyNeg, SlimLambdaTables::PzNeg, + SlimLambdaTables::PxPosMC, + SlimLambdaTables::PyPosMC, + SlimLambdaTables::PzPosMC, + SlimLambdaTables::PxNegMC, + SlimLambdaTables::PyNegMC, + SlimLambdaTables::PzNegMC, SlimLambdaTables::Radius, SlimLambdaTables::DcaV0PV, SlimLambdaTables::DcaPosPV, diff --git a/PWGLF/DataModel/LFSpincorrelationTables.h b/PWGLF/DataModel/LFSpincorrelationTables.h new file mode 100644 index 00000000000..f875736d794 --- /dev/null +++ b/PWGLF/DataModel/LFSpincorrelationTables.h @@ -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. + +/// +/// \author Sourav Kundu + +#ifndef PWGLF_DATAMODEL_LFSPINCORRELATIONTABLES_H_ +#define PWGLF_DATAMODEL_LFSPINCORRELATIONTABLES_H_ + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" + +#include + +namespace o2::aod +{ +namespace lambdaevent +{ +DECLARE_SOA_COLUMN(Cent, cent, float); +DECLARE_SOA_COLUMN(Posz, posz, float); +} // namespace lambdaevent +DECLARE_SOA_TABLE(LambdaEvents, "AOD", "LAMBDAEVENT", + o2::soa::Index<>, + lambdaevent::Cent, + lambdaevent::Posz) +using LambdaEvent = LambdaEvents::iterator; + +namespace lambdapair +{ +DECLARE_SOA_INDEX_COLUMN(LambdaEvent, lambdaevent); +DECLARE_SOA_COLUMN(V0Status, v0Status, int); //! Lambda or Anti-Lambda status +DECLARE_SOA_COLUMN(DoubleStatus, doubleStatus, bool); //! Double status +DECLARE_SOA_COLUMN(V0Cospa, v0Cospa, float); //! V0 Cospa +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); //! V0 Radius +DECLARE_SOA_COLUMN(DcaPositive, dcaPositive, float); //! DCA Positive +DECLARE_SOA_COLUMN(DcaNegative, dcaNegative, float); //! DCA Negative +DECLARE_SOA_COLUMN(DcaBetweenDaughter, dcaBetweenDaughter, float); //! DCA between daughters +DECLARE_SOA_COLUMN(LambdaPt, lambdaPt, float); //! Lambda Pt +DECLARE_SOA_COLUMN(LambdaEta, lambdaEta, float); //! Lambda Eta +DECLARE_SOA_COLUMN(LambdaPhi, lambdaPhi, float); //! Lambda Phi +DECLARE_SOA_COLUMN(LambdaMass, lambdaMass, float); //! Lambda Mass +DECLARE_SOA_COLUMN(ProtonPt, protonPt, float); //! Proton Pt +DECLARE_SOA_COLUMN(ProtonEta, protonEta, float); //! Proton Eta +DECLARE_SOA_COLUMN(ProtonPhi, protonPhi, float); //! Proton Phi +DECLARE_SOA_COLUMN(ProtonIndex, protonIndex, int); //! Proton index +DECLARE_SOA_COLUMN(PionIndex, pionIndex, int); //! Pion index +} // namespace lambdapair +DECLARE_SOA_TABLE(LambdaPairs, "AOD", "LAMBDAPAIR", + o2::soa::Index<>, + lambdapair::LambdaEventId, + lambdapair::V0Status, + lambdapair::DoubleStatus, + lambdapair::V0Cospa, + lambdapair::V0Radius, + lambdapair::DcaPositive, + lambdapair::DcaNegative, + lambdapair::DcaBetweenDaughter, + lambdapair::LambdaPt, + lambdapair::LambdaEta, + lambdapair::LambdaPhi, + lambdapair::LambdaMass, + lambdapair::ProtonPt, + lambdapair::ProtonEta, + lambdapair::ProtonPhi, + lambdapair::ProtonIndex, + lambdapair::PionIndex); + +using LambdaPair = LambdaPairs::iterator; + +namespace lambdaeventmc +{ +DECLARE_SOA_COLUMN(Centmc, centmc, float); +DECLARE_SOA_COLUMN(Poszmc, poszmc, float); +} // namespace lambdaeventmc +DECLARE_SOA_TABLE(LambdaEventmcs, "AOD", "LAMBDAEVENTMC", + o2::soa::Index<>, + lambdaeventmc::Centmc, + lambdaeventmc::Poszmc) +using LambdaEventmc = LambdaEventmcs::iterator; + +namespace lambdapairmc +{ +DECLARE_SOA_INDEX_COLUMN(LambdaEventmc, lambdaeventmc); +DECLARE_SOA_COLUMN(V0Statusmc, v0Statusmc, int); //! Lambda or Anti-Lambda status in montecarlo +DECLARE_SOA_COLUMN(DoubleStatusmc, doubleStatusmc, bool); //! Double status in montecarlo +DECLARE_SOA_COLUMN(V0Cospamc, v0Cospamc, float); //! V0 Cospa in montecarlo +DECLARE_SOA_COLUMN(V0Radiusmc, v0Radiusmc, float); //! V0 Radius in montecarlo +DECLARE_SOA_COLUMN(DcaPositivemc, dcaPositivemc, float); //! DCA Positive in montecarlo +DECLARE_SOA_COLUMN(DcaNegativemc, dcaNegativemc, float); //! DCA Negative in montecarlo +DECLARE_SOA_COLUMN(DcaBetweenDaughtermc, dcaBetweenDaughtermc, float); //! DCA between daughters in montecarlo +DECLARE_SOA_COLUMN(LambdaPtmc, lambdaPtmc, float); //! Lambda Pt in montecarlo +DECLARE_SOA_COLUMN(LambdaEtamc, lambdaEtamc, float); //! Lambda Eta in montecarlo +DECLARE_SOA_COLUMN(LambdaPhimc, lambdaPhimc, float); //! Lambda Phi in montecarlo +DECLARE_SOA_COLUMN(LambdaMassmc, lambdaMassmc, float); //! Lambda Mass in montecarlo +DECLARE_SOA_COLUMN(ProtonPtmc, protonPtmc, float); //! Proton Pt in montecarlo +DECLARE_SOA_COLUMN(ProtonEtamc, protonEtamc, float); //! Proton Eta in montecarlo +DECLARE_SOA_COLUMN(ProtonPhimc, protonPhimc, float); //! Proton Phi in montecarlo +DECLARE_SOA_COLUMN(ProtonIndexmc, protonIndexmc, int); //! Proton index in montecarlo +DECLARE_SOA_COLUMN(PionIndexmc, pionIndexmc, int); //! Pion index in montecarlo +} // namespace lambdapairmc +DECLARE_SOA_TABLE(LambdaPairmcs, "AOD", "LAMBDAPAIRMC", + o2::soa::Index<>, + lambdapairmc::LambdaEventmcId, + lambdapairmc::V0Statusmc, + lambdapairmc::DoubleStatusmc, + lambdapairmc::V0Cospamc, + lambdapairmc::V0Radiusmc, + lambdapairmc::DcaPositivemc, + lambdapairmc::DcaNegativemc, + lambdapairmc::DcaBetweenDaughtermc, + lambdapairmc::LambdaPtmc, + lambdapairmc::LambdaEtamc, + lambdapairmc::LambdaPhimc, + lambdapairmc::LambdaMassmc, + lambdapairmc::ProtonPtmc, + lambdapairmc::ProtonEtamc, + lambdapairmc::ProtonPhimc, + lambdapairmc::ProtonIndexmc, + lambdapairmc::PionIndexmc); + +using LambdaPairmc = LambdaPairmcs::iterator; + +} // namespace o2::aod +#endif // PWGLF_DATAMODEL_LFSPINCORRELATIONTABLES_H_ diff --git a/PWGLF/DataModel/LFStrangenessFinderTables.h b/PWGLF/DataModel/LFStrangenessFinderTables.h index 6bff37f12fd..823fb196abd 100644 --- a/PWGLF/DataModel/LFStrangenessFinderTables.h +++ b/PWGLF/DataModel/LFStrangenessFinderTables.h @@ -13,12 +13,16 @@ // finders. These are cross-check tasks that are not meant to do final analyses // as finding will be extremely slow and complex at the AO2D level. -#ifndef O2_ANALYSIS_STRANGENESSFINDERTABLES_H_ -#define O2_ANALYSIS_STRANGENESSFINDERTABLES_H_ +#ifndef PWGLF_DATAMODEL_LFSTRANGENESSFINDERTABLES_H_ +#define PWGLF_DATAMODEL_LFSTRANGENESSFINDERTABLES_H_ + +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Framework/AnalysisDataModel.h" #include "Common/Core/RecoDecay.h" -#include "CommonConstants/PhysicsConstants.h" + +#include +#include + #include // V0 auxiliary tables @@ -84,4 +88,4 @@ DECLARE_SOA_TABLE(CascGoodAntiLambdas, "AOD", "CASCGOODALAM", o2::soa::Index<>, } // namespace o2::aod -#endif // O2_ANALYSIS_STRANGENESSFINDERTABLES_H_ +#endif // PWGLF_DATAMODEL_LFSTRANGENESSFINDERTABLES_H_ diff --git a/PWGLF/DataModel/LFStrangenessMLTables.h b/PWGLF/DataModel/LFStrangenessMLTables.h index fdb97e1ca1b..abae8814856 100644 --- a/PWGLF/DataModel/LFStrangenessMLTables.h +++ b/PWGLF/DataModel/LFStrangenessMLTables.h @@ -235,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..c815ece9653 100644 --- a/PWGLF/DataModel/LFStrangenessPIDTables.h +++ b/PWGLF/DataModel/LFStrangenessPIDTables.h @@ -9,44 +9,176 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +//********************************************************************** // Defines TOF PID tables for strangeness. // Entries calculated per candidate, tables are joinable with v0/cascdata tables. +//********************************************************************** + +//********************************************************************** +// Nota bene: when using, do not check track.hasTOF! That conditional may not match +// the calculation of strangeness TOF, which requires e.g. a successful calculation +// of the collision time for the reassociated collision +//********************************************************************** #ifndef PWGLF_DATAMODEL_LFSTRANGENESSPIDTABLES_H_ #define PWGLF_DATAMODEL_LFSTRANGENESSPIDTABLES_H_ -#include -#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + #include "Common/Core/RecoDecay.h" + #include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisDataModel.h" + +#include namespace o2::aod { namespace dautrack { -// ==== TPC INFORMATION === -DECLARE_SOA_COLUMN(TPCSignal, tpcSignal, float); //! track TPC signal +// ==== define packing helpers === +namespace packing +{ +// define variables for packing +static constexpr int nbins = (1 << 8 * sizeof(int8_t)) - 2; +static constexpr int8_t overflowBin = nbins >> 1; +static constexpr int8_t underflowBin = -(nbins >> 1); +static constexpr float binned_max = 6.35; +static constexpr float binned_min = -6.35; +static constexpr float bin_width = (binned_max - binned_min) / nbins; +static constexpr float underflow_return = -100.0f; +static constexpr float overflow_return = +100.0f; + +// define helper function to do packing +int8_t packInInt8(float nSigma) +{ + // calculate + if (nSigma <= binned_min) + return underflowBin; + if (nSigma >= binned_max) + return overflowBin; + if (nSigma >= 0) { + return static_cast((nSigma / bin_width) + 0.5f); + } + // automatic: this is the case in which nSigma < 0 + return static_cast((nSigma / bin_width) - 0.5f); +} + +// define helper function to do unpacking +float unpackInt8(int8_t nSigma) +{ + if (nSigma == underflowBin) { + return underflow_return; + } + if (nSigma == overflowBin) { + return overflow_return; + } + return bin_width * nSigma; +} + +} // namespace packing +} // namespace dautrack + +namespace dautrack_legacy +{ +// ==== LEGACY TPC INFORMATION (full size tables) === DECLARE_SOA_COLUMN(TPCNSigmaEl, tpcNSigmaEl, float); //! Nsigma proton DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); //! Nsigma proton DECLARE_SOA_COLUMN(TPCNSigmaKa, tpcNSigmaKa, float); //! Nsigma proton DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNSigmaPr, float); //! Nsigma proton DECLARE_SOA_COLUMN(TPCNSigmaHe, tpcNSigmaHe, float); //! Nsigma proton +} // namespace dautrack_legacy + +namespace dautrack +{ +// ==== COMPACT TPC INFORMATION (full size tables) === +DECLARE_SOA_COLUMN(TPCSignal, tpcSignal, float); //! track TPC signal +DECLARE_SOA_COLUMN(PackedTPCNSigmaEl, packedTpcNSigmaEl, int8_t); //! Nsigma proton +DECLARE_SOA_COLUMN(PackedTPCNSigmaPi, packedTpcNSigmaPi, int8_t); //! Nsigma proton +DECLARE_SOA_COLUMN(PackedTPCNSigmaKa, packedTpcNSigmaKa, int8_t); //! Nsigma proton +DECLARE_SOA_COLUMN(PackedTPCNSigmaPr, packedTpcNSigmaPr, int8_t); //! Nsigma proton + +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaEl, tpcNSigmaEl, //! unpacked TPC nsigma + [](int8_t nsigma_packed) -> float { return o2::aod::dautrack::packing::unpackInt8(nsigma_packed); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaPi, tpcNSigmaPi, //! unpacked TPC nsigma + [](int8_t nsigma_packed) -> float { return o2::aod::dautrack::packing::unpackInt8(nsigma_packed); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaKa, tpcNSigmaKa, //! unpacked TPC nsigma + [](int8_t nsigma_packed) -> float { return o2::aod::dautrack::packing::unpackInt8(nsigma_packed); }); +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigmaPr, tpcNSigmaPr, //! unpacked TPC nsigma + [](int8_t nsigma_packed) -> float { return o2::aod::dautrack::packing::unpackInt8(nsigma_packed); }); // ==== TOF INFORMATION === +DECLARE_SOA_INDEX_COLUMN(DauTrackExtra, dauTrackExtra); //! point to daughter this TOF info belongs to +DECLARE_SOA_INDEX_COLUMN(StraCollision, straCollision); //! point to collision associated with this track (not the V0/Casc) DECLARE_SOA_COLUMN(TOFSignal, tofSignal, float); //! track TOF signal -DECLARE_SOA_COLUMN(TOFEvTime, tofEvTime, float); //! track TOF signal -DECLARE_SOA_COLUMN(Length, length, float); //! track TOF signal +DECLARE_SOA_COLUMN(TOFEvTime, tofEvTime, float); //! event time +DECLARE_SOA_COLUMN(Length, length, float); //! track length (to assigned PV) +DECLARE_SOA_COLUMN(TOFExpMom, tofExpMom, float); //! tof Exp Mom (to assigned PV) + +// dynamics with expected times +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpTimeEl, tofExpTimeEl, //! Expected time for the track to reach the TOF under the electron hypothesis + [](float length, float tofExpMom) -> float { + constexpr float massSquared = o2::constants::physics::MassElectron * o2::constants::physics::MassElectron; + return o2::framework::pid::tof::MassToExpTime(tofExpMom, length, massSquared); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpTimePi, tofExpTimePi, //! Expected time for the track to reach the TOF under the pion hypothesis + [](float length, float tofExpMom) -> float { + constexpr float massSquared = o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged; + return o2::framework::pid::tof::MassToExpTime(tofExpMom, length, massSquared); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpTimeKa, tofExpTimeKa, //! Expected time for the track to reach the TOF under the kaon hypothesis + [](float length, float tofExpMom) -> float { + constexpr float massSquared = o2::constants::physics::MassKaonCharged * o2::constants::physics::MassKaonCharged; + return o2::framework::pid::tof::MassToExpTime(tofExpMom, length, massSquared); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(TOFExpTimePr, tofExpTimePr, //! Expected time for the track to reach the TOF under the proton hypothesis + [](float length, float tofExpMom) -> float { + constexpr float massSquared = o2::constants::physics::MassProton * o2::constants::physics::MassProton; + return o2::framework::pid::tof::MassToExpTime(tofExpMom, length, massSquared); + }); + } // namespace dautrack -DECLARE_SOA_TABLE(DauTrackTPCPIDs, "AOD", "DAUTRACKTPCPID", // nsigma table (for analysis) - dautrack::TPCSignal, dautrack::TPCNSigmaEl, - dautrack::TPCNSigmaPi, dautrack::TPCNSigmaKa, - dautrack::TPCNSigmaPr, dautrack::TPCNSigmaHe); -DECLARE_SOA_TABLE(DauTrackTOFPIDs, "AOD", "DAUTRACKTOFPID", // raw table (for posterior TOF calculation) +DECLARE_SOA_TABLE(DauTrackTPCPIDs_000, "AOD", "DAUTRACKTPCPID", // nsigma table (for analysis) + dautrack::TPCSignal, dautrack_legacy::TPCNSigmaEl, + dautrack_legacy::TPCNSigmaPi, dautrack_legacy::TPCNSigmaKa, + dautrack_legacy::TPCNSigmaPr, dautrack_legacy::TPCNSigmaHe); + +DECLARE_SOA_TABLE_VERSIONED(DauTrackTPCPIDs_001, "AOD", "DAUTRACKTPCPID", 1, // nsigma table (for analysis) + dautrack::TPCSignal, + dautrack::PackedTPCNSigmaEl, dautrack::PackedTPCNSigmaPi, + dautrack::PackedTPCNSigmaKa, dautrack::PackedTPCNSigmaPr, + dautrack::TPCNSigmaEl, + dautrack::TPCNSigmaPi, + dautrack::TPCNSigmaKa, + dautrack::TPCNSigmaPr); + +using DauTrackTPCPIDs = DauTrackTPCPIDs_001; // second gen: packed Nsigma, no He + +DECLARE_SOA_TABLE(DauTrackTOFPIDs_000, "AOD", "DAUTRACKTOFPID", // raw table (for posterior TOF calculation) dautrack::TOFSignal, dautrack::TOFEvTime, dautrack::Length); +DECLARE_SOA_TABLE_VERSIONED(DauTrackTOFPIDs_001, "AOD", "DAUTRACKTOFPID", 1, // raw table (for posterior TOF calculation) + o2::soa::Index<>, + dautrack::StraCollisionId, dautrack::DauTrackExtraId, + dautrack::TOFSignal, dautrack::TOFEvTime, + dautrack::Length, dautrack::TOFExpMom, + dautrack::TOFExpTimeEl, + dautrack::TOFExpTimePi, + dautrack::TOFExpTimeKa, + dautrack::TOFExpTimePr); + +using DauTrackTOFPIDs = DauTrackTOFPIDs_001; // second gen: with collision Id, with TOFExpMom + namespace v0data { +// define constants for NSigma operation +const float kNoTOFValue = -1e+6; +const float kEpsilon = 1e-4; + // ==== TOF INFORMATION === // lengths as stored in the AO2D for TOF calculations DECLARE_SOA_COLUMN(PosTOFLengthToPV, posTOFLengthToPV, float); //! positive track length to PV @@ -79,6 +211,64 @@ DECLARE_SOA_COLUMN(TOFNSigmaALaPi, tofNSigmaALaPi, float); //! positive DECLARE_SOA_COLUMN(TOFNSigmaK0PiPlus, tofNSigmaK0PiPlus, float); //! positive track NSigma from pion <- k0short expectation DECLARE_SOA_COLUMN(TOFNSigmaK0PiMinus, tofNSigmaK0PiMinus, float); //! negative track NSigma from pion <- k0short expectation +// dynamics to replace hasTOF (note: that condition does not match track hasTOF!) +// note: only single hypothesis check necessary; other hypotheses will always be valid +DECLARE_SOA_DYNAMIC_COLUMN(PositiveHasTOF, positiveHasTOF, //! positive daughter TOF calculation valid + [](float TOFNSigmaLaPr) -> bool { + bool returnStatus = true; + if (std::abs(TOFNSigmaLaPr - kNoTOFValue) < kEpsilon) { + returnStatus = false; + } + return returnStatus; + }); +DECLARE_SOA_DYNAMIC_COLUMN(NegativeHasTOF, negativeHasTOF, //! negative daughter TOF calculation valid + [](float TOFNSigmaALaPr) -> bool { + bool returnStatus = true; + if (std::abs(TOFNSigmaALaPr - kNoTOFValue) < kEpsilon) { + returnStatus = false; + } + return returnStatus; + }); + +// dynamics based on n-sigmas with use-only-if-tof-present logic +DECLARE_SOA_DYNAMIC_COLUMN(TofLambdaCompatibility, tofLambdaCompatibility, //! compatibility with being lambda, checked only if TOF present. Argument: number of sigmas + [](float tofNSigmaLaPr, float tofNSigmaLaPi, float nsigma) -> float { + bool compatible = true; + if (std::abs(tofNSigmaLaPr - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaLaPr) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + if (std::abs(tofNSigmaLaPi - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaLaPi) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + return compatible; + }); + +// dynamics based on n-sigmas with use-only-if-tof-present logic +DECLARE_SOA_DYNAMIC_COLUMN(TofAntiLambdaCompatibility, tofAntiLambdaCompatibility, //! compatibility with being lambda, checked only if TOF present. Argument: number of sigmas + [](float tofNSigmaALaPr, float tofNSigmaALaPi, float nsigma) -> float { + bool compatible = true; + if (std::abs(tofNSigmaALaPr - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaALaPr) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + if (std::abs(tofNSigmaALaPi - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaALaPi) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + return compatible; + }); + +// dynamics based on n-sigmas with use-only-if-tof-present logic +DECLARE_SOA_DYNAMIC_COLUMN(TofK0ShortCompatibility, tofK0ShortCompatibility, //! compatibility with being lambda, checked only if TOF present. Argument: number of sigmas + [](float tofNSigmaK0PiPlus, float tofNSigmaK0PiMinus, float nsigma) -> float { + bool compatible = true; + if (std::abs(tofNSigmaK0PiPlus - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaK0PiPlus) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + if (std::abs(tofNSigmaK0PiMinus - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaK0PiMinus) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + return compatible; + }); + // beta values DECLARE_SOA_COLUMN(TofBetaLambda, tofBetaLambda, float); //! beta value with Lambda hypothesis DECLARE_SOA_COLUMN(TofBetaAntiLambda, tofBetaAntiLambda, float); //! beta value with AntiLambda hypothesis @@ -120,10 +310,19 @@ DECLARE_SOA_TABLE(V0TOFBetas, "AOD", "V0TOFBETA", // processed info table (for a DECLARE_SOA_TABLE(V0TOFNSigmas, "AOD", "V0TOFNSIGMA", // processed NSigma table (for analysis) v0data::TOFNSigmaLaPr, v0data::TOFNSigmaLaPi, v0data::TOFNSigmaALaPr, v0data::TOFNSigmaALaPi, - v0data::TOFNSigmaK0PiPlus, v0data::TOFNSigmaK0PiMinus); + v0data::TOFNSigmaK0PiPlus, v0data::TOFNSigmaK0PiMinus, + v0data::PositiveHasTOF, + v0data::NegativeHasTOF, + v0data::TofLambdaCompatibility, + v0data::TofAntiLambdaCompatibility, + v0data::TofK0ShortCompatibility); namespace cascdata { +// define constants for NSigma operation +const float kNoTOFValue = -1e+6; +const float kEpsilon = 1e-4; + // lengths as stored in the AO2D for TOF calculations DECLARE_SOA_COLUMN(PosTOFLengthToPV, posTOFLengthToPV, float); //! positive track length DECLARE_SOA_COLUMN(NegTOFLengthToPV, negTOFLengthToPV, float); //! negative track length @@ -137,15 +336,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 @@ -154,6 +353,65 @@ DECLARE_SOA_COLUMN(TOFNSigmaXiPi, tofNSigmaXiPi, float); //! bachelor track DECLARE_SOA_COLUMN(TOFNSigmaOmLaPi, tofNSigmaOmLaPi, float); //! meson track NSigma from pion <- lambda <- om expectation DECLARE_SOA_COLUMN(TOFNSigmaOmLaPr, tofNSigmaOmLaPr, float); //! baryon track NSigma from proton <- lambda <- om expectation DECLARE_SOA_COLUMN(TOFNSigmaOmKa, tofNSigmaOmKa, float); //! bachelor track NSigma from kaon <- om expectation + +// dynamics to replace hasTOF (note: that condition does not match track hasTOF!) +// note: only single hypothesis check necessary; other hypotheses will always be valid +DECLARE_SOA_DYNAMIC_COLUMN(PositiveHasTOF, positiveHasTOF, //! positive daughter TOF calculation valid + [](float PosTOFDeltaTXiPr) -> bool { + bool returnStatus = true; + if (std::abs(PosTOFDeltaTXiPr - kNoTOFValue) < kEpsilon) { + returnStatus = false; + } + return returnStatus; + }); +DECLARE_SOA_DYNAMIC_COLUMN(NegativeHasTOF, negativeHasTOF, //! positive daughter TOF calculation valid + [](float NegTOFDeltaTXiPr) -> bool { + bool returnStatus = true; + if (std::abs(NegTOFDeltaTXiPr - kNoTOFValue) < kEpsilon) { + returnStatus = false; + } + return returnStatus; + }); +DECLARE_SOA_DYNAMIC_COLUMN(BachelorHasTOF, bachelorHasTOF, //! bachelor daughter TOF calculation valid + [](float BachTOFDeltaTXiPi) -> bool { + bool returnStatus = true; + if (std::abs(BachTOFDeltaTXiPi - kNoTOFValue) < kEpsilon) { + returnStatus = false; + } + return returnStatus; + }); + +// dynamics based on n-sigmas with use-only-if-tof-present logic +DECLARE_SOA_DYNAMIC_COLUMN(TofXiCompatibility, tofXiCompatibility, //! compatibility with being lambda, checked only if TOF present. Argument: number of sigmas + [](float tofNSigmaXiLaPr, float tofNSigmaXiLaPi, float tofNSigmaXiPi, float nsigma) -> float { + bool compatible = true; + if (std::abs(tofNSigmaXiLaPr - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaXiLaPr) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + if (std::abs(tofNSigmaXiLaPi - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaXiLaPi) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + if (std::abs(tofNSigmaXiPi - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaXiPi) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + return compatible; + }); + +DECLARE_SOA_DYNAMIC_COLUMN(TofOmegaCompatibility, tofOmegaCompatibility, //! compatibility with being lambda, checked only if TOF present. Argument: number of sigmas + [](float tofNSigmaOmLaPr, float tofNSigmaOmLaPi, float tofNSigmaOmKa, float nsigma) -> float { + bool compatible = true; + if (std::abs(tofNSigmaOmLaPr - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaOmLaPr) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + if (std::abs(tofNSigmaOmLaPi - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaOmLaPi) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + if (std::abs(tofNSigmaOmKa - kNoTOFValue) > kEpsilon && std::abs(tofNSigmaOmKa) > nsigma) { + compatible = false; // reject only if info present and incompatible + } + return compatible; + }); + } // namespace cascdata // /-|-\-|-/-|-\-|-/-|-\-|-/-|-\-|-/-|-\-|-/-|-\-|-/-|-\-|-/-|-\-|-/-|-\-|-/-|-\-|-/ @@ -170,10 +428,15 @@ 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); + cascdata::TOFNSigmaOmLaPi, cascdata::TOFNSigmaOmLaPr, cascdata::TOFNSigmaOmKa, + cascdata::PositiveHasTOF, + cascdata::NegativeHasTOF, + cascdata::BachelorHasTOF, + cascdata::TofXiCompatibility, + cascdata::TofOmegaCompatibility); } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFSTRANGENESSPIDTABLES_H_ diff --git a/PWGLF/DataModel/LFStrangenessTables.h b/PWGLF/DataModel/LFStrangenessTables.h index 3ab94c27276..bc7fd7d3aaa 100644 --- a/PWGLF/DataModel/LFStrangenessTables.h +++ b/PWGLF/DataModel/LFStrangenessTables.h @@ -8,39 +8,95 @@ // In applying this license CERN does 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_LFSTRANGENESSTABLES_H_ #define PWGLF_DATAMODEL_LFSTRANGENESSTABLES_H_ -#include -#include -#include "Framework/AnalysisDataModel.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/SPCalibrationTables.h" +#include "PWGUD/DataModel/UDTables.h" + #include "Common/Core/RecoDecay.h" -#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" // IWYU pragma: keep (FIXME: not used, remove asap) #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" #include "Common/DataModel/Qvectors.h" -#include "PWGLF/DataModel/EPCalibrationTables.h" + +#include +#include +#include +#include + +#include +#include +#include +#include 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; }); + +// event time +DECLARE_SOA_COLUMN(EventTime, eventTime, float); //! event time (FT0, TOF) for TOF PID (stored once per event) +} // 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 @@ -48,6 +104,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 @@ -58,6 +115,7 @@ 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); +// !!! 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 @@ -69,8 +127,170 @@ DECLARE_SOA_TABLE_VERSIONED(StraRawCents_004, "AOD", "STRARAWCENTS", 4, //! mult::MultZNA, mult::MultZNC, mult::MultZEM1, // ZDC signals mult::MultZEM2, mult::MultZPA, mult::MultZPC, evsel::NumTracksInTimeRange); // add occupancy as extra -DECLARE_SOA_TABLE(StraEvSels, "AOD", "STRAEVSELS", //! event selection: sel8 +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 @@ -84,28 +304,56 @@ DECLARE_SOA_TABLE(StraTPCQVs, "AOD", "STRATPCQVS", //! tpc Qvec qvec::QvecBPosRe, qvec::QvecBPosIm, epcalibrationtable::QTPCR); DECLARE_SOA_TABLE(StraFT0CQVsEv, "AOD", "STRAFT0CQVSEv", //! events used to compute t0c Qvec epcalibrationtable::TriggerEventEP); -DECLARE_SOA_TABLE(StraStamps, "AOD", "STRASTAMPS", //! information for ID-ing mag field if needed +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); +DECLARE_SOA_TABLE(StraEvTimes, "AOD", "STRAEVTIMES", //! event time (FT0, TOF) + stracollision::EventTime); 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 @@ -150,6 +398,18 @@ DECLARE_SOA_DYNAMIC_COLUMN(HasITSTracker, hasITSTracker, //! Flag to check if tr [](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_000, "AOD", "DAUTRACKEXTRA", //! detector properties of decay daughters @@ -181,10 +441,77 @@ DECLARE_SOA_TABLE_VERSIONED(DauTrackExtras_001, "AOD", "DAUTRACKEXTRA", 1, //! d 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_001; +using DauTrackExtras = DauTrackExtras_003; using DauTrackExtra = DauTrackExtras::iterator; namespace motherParticle @@ -261,7 +588,7 @@ 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. @@ -294,6 +621,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 @@ -301,42 +631,28 @@ DECLARE_SOA_COLUMN(GeneratedK0Short, generatedK0Short, std::vector); DECLARE_SOA_COLUMN(GeneratedLambda, generatedLambda, std::vector); //! Lambda binned generated data DECLARE_SOA_COLUMN(GeneratedAntiLambda, generatedAntiLambda, std::vector); //! AntiLambda binned generated data -//______________________________________________________ -// EXPRESSION COLUMNS -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, //! V0 px - float, 1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, //! V0 py - float, 1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, //! V0 pz - float, 1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg); -DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, //! Transverse momentum in GeV/c - nsqrt((1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) * - (1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) + - (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) * (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg))); -DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! Total momentum in GeV/c - nsqrt((1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) * - (1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) + - (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) * (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) + - (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg) * (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg))); -DECLARE_SOA_EXPRESSION_COLUMN(Phi, phi, float, //! Phi in the range [0, 2pi) - o2::constants::math::PI + natan2(-1.0f * (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg), -1.0f * (1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg))); -DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! Pseudorapidity, conditionally defined to avoid FPEs - ifnode((nsqrt((1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) * (1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) + - (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) * (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) + - (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg) * (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg)) - - (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg)) < static_cast(1e-7), - ifnode((1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg) < 0.f, -100.f, 100.f), - 0.5f * nlog((nsqrt((1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) * (1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) + - (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) * (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) + - (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg) * (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg)) + - (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg)) / - (nsqrt((1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) * (1.f * aod::v0data::pxpos + 1.f * aod::v0data::pxneg) + - (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) * (1.f * aod::v0data::pypos + 1.f * aod::v0data::pyneg) + - (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg) * (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg)) - - (1.f * aod::v0data::pzpos + 1.f * aod::v0data::pzneg))))); - //______________________________________________________ // DYNAMIC COLUMNS +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! V0 px + [](float pxPos, float pxNeg) -> float { return pxPos + pxNeg; }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! V0 py + [](float pyPos, float pyNeg) -> float { return pyPos + pyNeg; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! V0 pz + [](float pzPos, float pzNeg) -> float { return pzPos + pzNeg; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! Transverse momentum in GeV/c + [](float pxPos, float pyPos, float pxNeg, float pyNeg) -> float { + return RecoDecay::sqrtSumOfSquares(pxPos + pxNeg, pyPos + pyNeg); + }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! Total momentum in GeV/c + [](float pxPos, float pyPos, float pzPos, float pxNeg, float pyNeg, float pzNeg) -> float { + return RecoDecay::sqrtSumOfSquares(pxPos + pxNeg, pyPos + pyNeg, pzPos + pzNeg); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! Phi in the range [0, 2pi) + [](float pxPos, float pyPos, float pxNeg, float pyNeg) -> float { return RecoDecay::phi(pxPos + pxNeg, pyPos + pyNeg); }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! Pseudorapidity, conditionally defined to avoid FPEs + [](float pxPos, float pyPos, float pzPos, float pxNeg, float pyNeg, float pzNeg) -> float { + return RecoDecay::eta(std::array{pxPos + pxNeg, pyPos + pyNeg, pzPos + pzNeg}); + }); // Account for rigidity in case of hypertriton DECLARE_SOA_DYNAMIC_COLUMN(PtHypertriton, ptHypertriton, //! V0 pT [](float pxpos, float pypos, float pxneg, float pyneg) -> float { return RecoDecay::sqrtSumOfSquares(2.0f * pxpos + pxneg, 2.0f * pypos + pyneg); }); @@ -349,8 +665,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(V0Radius, v0radius, //! V0 decay radius (2D, centered // Distance Over To Mom DECLARE_SOA_DYNAMIC_COLUMN(DistOverTotMom, distovertotmom, //! PV to V0decay distance over total momentum - [](float X, float Y, float Z, float Px, float Py, float Pz, float pvX, float pvY, float pvZ) { - float P = RecoDecay::sqrtSumOfSquares(Px, Py, Pz); + [](float X, float Y, float Z, float pxPos, float pyPos, float pzPos, float pxNeg, float pyNeg, float pzNeg, float pvX, float pvY, float pvZ) { + float P = RecoDecay::sqrtSumOfSquares(pxPos + pxNeg, pyPos + pyNeg, pzPos + pzNeg); return std::sqrt(std::pow(X - pvX, 2) + std::pow(Y - pvY, 2) + std::pow(Z - pvZ, 2)) / (P + 1E-10); }); @@ -399,11 +715,38 @@ DECLARE_SOA_DYNAMIC_COLUMN(PFracNeg, pfracneg, // Calculated on the fly with mass assumption + dynamic tables DECLARE_SOA_DYNAMIC_COLUMN(MLambda, mLambda, //! 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}); }); + [](int v0type, float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { + if ((v0type & (0x1 << o2::dataformats::V0Index::kPhotonOnly)) != 0) { + return 0.0f; // provide mass only if NOT a photon with TPC-only tracks (special handling) + } + 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(MAntiLambda, mAntiLambda, //! 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}); }); + [](int v0type, float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { + if ((v0type & (0x1 << o2::dataformats::V0Index::kPhotonOnly)) != 0) { + return 0.0f; // provide mass only if NOT a photon with TPC-only tracks (special handling) + } + 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(MK0Short, mK0Short, //! 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}); }); + [](int v0type, float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { + if ((v0type & (0x1 << o2::dataformats::V0Index::kPhotonOnly)) != 0) { + return 0.0f; // provide mass only if NOT a photon with TPC-only tracks (special handling) + } + 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(MLambda_unchecked, mLambda_unchecked, //! mass under lambda hypothesis without v0 type check (will include TPC only and potentially duplicates! use with care) + [](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(MAntiLambda_unchecked, mAntiLambda_unchecked, //! mass under antilambda hypothesis without v0 type check (will include TPC only and potentially duplicates! use with care) + [](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(MK0Short_unchecked, mK0Short_unchecked, //! mass under K0short hypothesis without v0 type check (will include TPC only and potentially duplicates! use with care) + [](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(MGamma, mGamma, //! mass under gamma 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::MassElectron, o2::constants::physics::MassElectron}); }); // Account for rigidity in case of hypertriton @@ -429,19 +772,23 @@ DECLARE_SOA_DYNAMIC_COLUMN(M, m, //! mass under a certain hypothesis (0:K0, 1:L, }); DECLARE_SOA_DYNAMIC_COLUMN(YK0Short, yK0Short, //! V0 y with K0short hypothesis - [](float Px, float Py, float Pz) -> float { return RecoDecay::y(std::array{Px, Py, Pz}, o2::constants::physics::MassKaonNeutral); }); + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { + return RecoDecay::y(std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}, o2::constants::physics::MassKaonNeutral); + }); DECLARE_SOA_DYNAMIC_COLUMN(YLambda, yLambda, //! V0 y with lambda or antilambda hypothesis - [](float Px, float Py, float Pz) -> float { return RecoDecay::y(std::array{Px, Py, Pz}, o2::constants::physics::MassLambda); }); + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { + return RecoDecay::y(std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}, o2::constants::physics::MassLambda); + }); DECLARE_SOA_DYNAMIC_COLUMN(YHypertriton, yHypertriton, //! V0 y with hypertriton hypothesis [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { return RecoDecay::y(std::array{2.0f * pxpos + pxneg, 2.0f * pypos + pyneg, 2.0f * pzpos + pzneg}, o2::constants::physics::MassHyperTriton); }); DECLARE_SOA_DYNAMIC_COLUMN(YAntiHypertriton, yAntiHypertriton, //! V0 y with antihypertriton hypothesis [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) -> float { return RecoDecay::y(std::array{pxpos + 2.0f * pxneg, pypos + 2.0f * pyneg, pzpos + 2.0f * pzneg}, o2::constants::physics::MassHyperTriton); }); DECLARE_SOA_DYNAMIC_COLUMN(Rapidity, rapidity, //! rapidity (0:K0, 1:L, 2:Lbar) - [](float Px, float Py, float Pz, int value) -> float { + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg, int value) -> float { if (value == 0) - return RecoDecay::y(std::array{Px, Py, Pz}, o2::constants::physics::MassKaonNeutral); + return RecoDecay::y(std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}, o2::constants::physics::MassKaonNeutral); if (value == 1 || value == 2) - return RecoDecay::y(std::array{Px, Py, Pz}, o2::constants::physics::MassLambda); + return RecoDecay::y(std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}, o2::constants::physics::MassLambda); return 0.0f; }); @@ -458,12 +805,46 @@ DECLARE_SOA_DYNAMIC_COLUMN(PositiveEta, positiveeta, //! positive daughter eta DECLARE_SOA_DYNAMIC_COLUMN(PositivePhi, positivephi, //! positive daughter phi [](float PxPos, float PyPos) -> float { return RecoDecay::phi(PxPos, PyPos); }); -DECLARE_SOA_DYNAMIC_COLUMN(IsStandardV0, isStandardV0, //! is standard V0 - [](uint8_t V0Type) -> bool { return V0Type == 1; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsStandardV0, isStandardV0, //! is standard V0 - note: photons excluded via '==' + [](uint8_t V0Type) -> bool { return V0Type == o2::dataformats::V0Index::kStandaloneV0; }); DECLARE_SOA_DYNAMIC_COLUMN(IsPhotonTPConly, isPhotonTPConly, //! is tpc-only photon V0 - [](uint8_t V0Type) -> bool { return V0Type & (1 << 1); }); + [](uint8_t V0Type) -> bool { return V0Type & (1 << o2::dataformats::V0Index::kPhotonOnly); }); DECLARE_SOA_DYNAMIC_COLUMN(IsCollinear, isCollinear, //! is collinear V0 - [](uint8_t V0Type) -> bool { return V0Type & (1 << 2); }); + [](uint8_t V0Type) -> bool { return V0Type & (1 << o2::dataformats::V0Index::kCollinear); }); + +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); }); + +// declare legacy mass getters in v0data legacy name space +// caution: these do not have intrinsic protection against photon candidates +namespace legacy +{ +DECLARE_SOA_DYNAMIC_COLUMN(MLambda, mLambda, //! mass under lambda hypothesis without v0 type check (will include TPC only and potentially duplicates! use with care) + [](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(MAntiLambda, mAntiLambda, //! mass under antilambda hypothesis without v0 type check (will include TPC only and potentially duplicates! use with care) + [](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(MK0Short, mK0Short, //! mass under K0short hypothesis without v0 type check (will include TPC only and potentially duplicates! use with care) + [](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}); + }); +} // namespace legacy } // namespace v0data DECLARE_SOA_TABLE(V0Indices, "AOD", "V0INDEX", //! index table when using AO2Ds @@ -472,110 +853,72 @@ 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(StoredV0Extras, "AOD1", "V0EXTRA", //! optional table to refer to custom track extras - o2::soa::Index<>, v0data::PosTrackExtraId, v0data::NegTrackExtraId, soa::Marker<1>); +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(V0CoresBase, "V0Cores", "AOD", "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, - 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::Px, + v0data::Py, + v0data::Pz, + v0data::Pt, + v0data::P, + v0data::Phi, + v0data::Eta, + 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::MLambda_unchecked, + v0data::MAntiLambda_unchecked, + v0data::MK0Short_unchecked, + 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, 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 - -DECLARE_SOA_TABLE_FULL(StoredV0CoresBase, "V0Cores", "AOD1", "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, +// 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 - // 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<3>); - -// 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 +// // 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, @@ -609,10 +952,17 @@ DECLARE_SOA_TABLE_FULL(StoredV0fCCores, "V0fCCores", "AOD", "V0FCCORE", //! core v0data::V0CosPA, v0data::DCAV0ToPV, v0data::V0Type, // Dynamic columns + v0data::Px, + v0data::Py, + v0data::Pz, + v0data::Pt, + v0data::P, + v0data::Phi, + v0data::Eta, v0data::PtHypertriton, v0data::PtAntiHypertriton, v0data::V0Radius, - v0data::DistOverTotMom, + v0data::DistOverTotMom, v0data::Alpha, v0data::QtArm, v0data::PsiPair, @@ -620,20 +970,20 @@ DECLARE_SOA_TABLE_FULL(StoredV0fCCores, "V0fCCores", "AOD", "V0FCCORE", //! core v0data::PFracNeg, // 24 // Invariant masses - v0data::MLambda, - v0data::MAntiLambda, - v0data::MK0Short, + v0data::MLambda, + v0data::MAntiLambda, + v0data::MK0Short, v0data::MGamma, v0data::MHypertriton, v0data::MAntiHypertriton, v0data::M, // Longitudinal - v0data::YK0Short, - v0data::YLambda, + v0data::YK0Short, + v0data::YLambda, v0data::YHypertriton, v0data::YAntiHypertriton, - v0data::Rapidity, + v0data::Rapidity, v0data::NegativePt, v0data::PositivePt, v0data::NegativeEta, @@ -645,43 +995,66 @@ DECLARE_SOA_TABLE_FULL(StoredV0fCCores, "V0fCCores", "AOD", "V0FCCORE", //! core o2::soa::Marker<2>); // extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(V0fCCores, StoredV0fCCores, "V0FCCOREEXT", //! - 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 +// DECLARE_SOA_EXTENDED_TABLE_USER(V0fCCores, StoredV0fCCores, "V0FCCOREEXT", //! +// 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 DECLARE_SOA_TABLE_FULL(V0fCCovs, "V0fCCovs", "AOD", "V0FCCOVS", //! V0 covariance matrices v0data::PositionCovMat, v0data::MomentumCovMat, o2::soa::Marker<2>); -DECLARE_SOA_TABLE(V0MCCores_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); - -DECLARE_SOA_TABLE_VERSIONED(V0MCCores_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); - -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_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>); @@ -690,14 +1063,14 @@ 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); -DECLARE_SOA_TABLE(StoredV0MCMothers, "AOD1", "V0MCMOTHER", //! optional table for MC mothers - o2::soa::Index<>, v0data::MotherMCPartId, o2::soa::Marker<1>); +using V0fCCores = StoredV0fCCores; +using V0Cores = V0CoresBase; -using V0MCCores = V0MCCores_001; -using StoredV0MCCores = StoredV0MCCores_001; +using V0MCCores = V0MCCores_002; +using StoredV0MCCores = StoredV0MCCores_002; using V0Index = V0Indices::iterator; using V0Core = V0Cores::iterator; @@ -708,6 +1081,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 @@ -862,13 +1236,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 @@ -948,11 +1331,20 @@ 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}); }); + [](float Xlambda, float Ylambda, float Zlambda, float pxPos, float pyPos, float pzPos, float pxNeg, float pyNeg, float pzNeg, float pvX, float pvY, float pvZ) -> float { + return RecoDecay::cpa(std::array{pvX, pvY, pvZ}, std::array{Xlambda, Ylambda, Zlambda}, std::array{pxPos + pxNeg, pyPos + pyNeg, pzPos + pzNeg}); + }); +// 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)); }); + [](float X, float Y, float Z, float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg, float pvX, float pvY, float pvZ) -> float { + float px = pxpos + pxneg; + float py = pypos + pyneg; + float pz = pzpos + pzneg; + 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)); + }); // Calculated on the fly with mass assumption + dynamic tables DECLARE_SOA_DYNAMIC_COLUMN(MLambda, mLambda, //! @@ -997,42 +1389,102 @@ 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); }); -} // namespace cascdata -//______________________________________________________ -// EXPRESSION COLUMNS FOR TRACASCCORES -namespace cascdataext -{ -DECLARE_SOA_EXPRESSION_COLUMN(PxLambda, pxlambda, //! - float, 1.f * aod::cascdata::pxpos + 1.f * aod::cascdata::pxneg); -DECLARE_SOA_EXPRESSION_COLUMN(PyLambda, pylambda, //! - float, 1.f * aod::cascdata::pypos + 1.f * aod::cascdata::pyneg); -DECLARE_SOA_EXPRESSION_COLUMN(PzLambda, pzlambda, //! - float, 1.f * aod::cascdata::pzpos + 1.f * aod::cascdata::pzneg); -DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, //! Transverse momentum in GeV/c - nsqrt(aod::cascdata::px* aod::cascdata::px + - aod::cascdata::py * aod::cascdata::py)); -DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! Total momentum in GeV/c - nsqrt(aod::cascdata::px* aod::cascdata::px + - aod::cascdata::py * aod::cascdata::py + - aod::cascdata::pz * aod::cascdata::pz)); -DECLARE_SOA_EXPRESSION_COLUMN(Phi, phi, float, //! Phi in the range [0, 2pi) - o2::constants::math::PI + natan2(-1.0f * aod::cascdata::py, -1.0f * aod::cascdata::px)); -DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! Pseudorapidity, conditionally defined to avoid FPEs - ifnode((nsqrt(aod::cascdata::px * aod::cascdata::px + - aod::cascdata::py * aod::cascdata::py + - aod::cascdata::pz * aod::cascdata::pz) - - aod::cascdata::pz) < static_cast(1e-7), - ifnode(aod::cascdata::pz < 0.f, -100.f, 100.f), - 0.5f * nlog((nsqrt(aod::cascdata::px * aod::cascdata::px + - aod::cascdata::py * aod::cascdata::py + - aod::cascdata::pz * aod::cascdata::pz) + - aod::cascdata::pz) / - (nsqrt(aod::cascdata::px * aod::cascdata::px + - aod::cascdata::py * aod::cascdata::py + - aod::cascdata::pz * aod::cascdata::pz) - - aod::cascdata::pz)))); -} // namespace cascdataext +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); }); + +DECLARE_SOA_DYNAMIC_COLUMN(PxLambda, pxlambda, //! Lambda daughter px + [](float pxPos, float pxNeg) -> float { return pxPos + pxNeg; }); +DECLARE_SOA_DYNAMIC_COLUMN(PyLambda, pylambda, //! Lambda daughter py + [](float pyPos, float pyNeg) -> float { return pyPos + pyNeg; }); +DECLARE_SOA_DYNAMIC_COLUMN(PzLambda, pzlambda, //! Lambda daughter pz + [](float pzPos, float pzNeg) -> float { return pzPos + pzNeg; }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! Cascade transverse momentum in GeV/c + [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! Cascade total momentum in GeV/c + [](float px, float py, float pz) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! Cascade phi in the range [0, 2pi) + [](float px, float py) -> float { return RecoDecay::phi(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! Cascade pseudorapidity + [](float px, float py, float pz) -> float { return RecoDecay::eta(std::array{px, py, pz}); }); + +// Armenteros-Podolanski variables +DECLARE_SOA_DYNAMIC_COLUMN(Alpha, alpha, //! Armenteros Alpha + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg, float pxbach, float pybach, float pzbach, int sign) { + const float pxv0 = pxpos + pxneg; + const float pyv0 = pypos + pyneg; + const float pzv0 = pzpos + pzneg; + + // No need to divide by momentum of the cascade (as in the v0data namespace) since the ratio of lQl is evaluated + const float lQlBach = RecoDecay::dotProd(std::array{pxbach, pybach, pzbach}, std::array{pxv0 + pxbach, pyv0 + pybach, pzv0 + pzbach}); + const float lQlV0 = RecoDecay::dotProd(std::array{pxv0, pyv0, pzv0}, std::array{pxv0 + pxbach, pyv0 + pybach, pzv0 + pzbach}); + float alpha = (lQlBach - lQlV0) / (lQlV0 + lQlBach); // alphacascade + if (sign < 0) { + alpha = -alpha; + } + return alpha; + }); + +DECLARE_SOA_DYNAMIC_COLUMN(QtArm, qtarm, //! Armenteros Qt + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg, float pxbach, float pybach, float pzbach) { + const float pxv0 = pxpos + pxneg; + const float pyv0 = pypos + pyneg; + const float pzv0 = pzpos + pzneg; + + const float momTot2 = RecoDecay::p2(pxv0 + pxbach, pyv0 + pybach, pzv0 + pzbach); + const float dp = RecoDecay::dotProd(std::array{pxbach, pybach, pzbach}, std::array{pxv0 + pxbach, pyv0 + pybach, pzv0 + pzbach}); + return std::sqrt(RecoDecay::p2(pxbach, pybach, pzbach) - dp * dp / momTot2); // qtarm + }); + +// Psi pair angle: angle between the plane defined by the v0 and bachelor momenta and the xy plane +DECLARE_SOA_DYNAMIC_COLUMN(PsiPair, psipair, //! psi pair angle + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg, float pxbach, float pybach, float pzbach, int sign) { + auto clipToPM1 = [](float x) { return x < -1.f ? -1.f : (x > 1.f ? 1.f : x); }; + const float pxv0 = pxpos + pxneg; + const float pyv0 = pypos + pyneg; + const float pzv0 = pzpos + pzneg; + + const float ptot2 = RecoDecay::p2(pxbach, pybach, pzbach) * RecoDecay::p2(pxv0, pyv0, pzv0); + const float argcos = RecoDecay::dotProd(std::array{pxbach, pybach, pzbach}, std::array{pxv0, pyv0, pzv0}) / std::sqrt(ptot2); + const float thetaV0 = std::atan2(RecoDecay::sqrtSumOfSquares(pxv0, pyv0), pzv0); + const float thetaBach = std::atan2(RecoDecay::sqrtSumOfSquares(pxbach, pybach), pzbach); + float argsin = (thetaV0 - thetaBach) / std::acos(clipToPM1(argcos)); + if (sign < 0) { + argsin = -argsin; + } + return std::asin(clipToPM1(argsin)); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(V0Alpha, v0Alpha, //! Armenteros Alpha + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { + // No need to divide by momentum of the v0 (as in the v0data namespace) since the ratio of lQl is evaluated + const float lQlPos = RecoDecay::dotProd(std::array{pxpos, pypos, pzpos}, std::array{pxneg + pxpos, pyneg + pypos, pzneg + pzpos}); + const float lQlNeg = RecoDecay::dotProd(std::array{pxneg, pyneg, pzneg}, std::array{pxneg + pxpos, pyneg + pypos, pzneg + pzpos}); + return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(V0QtArm, v0Qtarm, //! Armenteros Qt + [](float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { + const float momTot2 = RecoDecay::p2(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); + const 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 / momTot2); // qtarm + }); +} // namespace cascdata //______________________________________________________ // Cascade data model: @@ -1078,11 +1530,18 @@ DECLARE_SOA_TABLE(StoredCascCores, "AOD", "CASCCORE", //! core information about cascdata::DCAPosToPV, cascdata::DCANegToPV, cascdata::DCABachToPV, cascdata::DCAXYCascToPV, cascdata::DCAZCascToPV, // Dynamic columns + cascdata::PxLambda, + cascdata::PyLambda, + cascdata::PzLambda, + cascdata::Pt, + cascdata::P, + cascdata::Phi, + cascdata::Eta, cascdata::V0Radius, cascdata::CascRadius, - cascdata::V0CosPA, - cascdata::CascCosPA, - cascdata::DCAV0ToPV, + cascdata::V0CosPA, + cascdata::CascCosPA, + cascdata::DCAV0ToPV, // Invariant masses cascdata::MLambda, @@ -1101,7 +1560,14 @@ DECLARE_SOA_TABLE(StoredCascCores, "AOD", "CASCCORE", //! core information about cascdata::PositiveEta, cascdata::PositivePhi, cascdata::BachelorEta, - cascdata::BachelorPhi); + cascdata::BachelorPhi, + + // Armenteros-Podolanski and psi-pair + cascdata::Alpha, + cascdata::QtArm, + cascdata::PsiPair, + cascdata::V0Alpha, + cascdata::V0QtArm); DECLARE_SOA_TABLE(StoredKFCascCores, "AOD", "KFCASCCORE", //! cascdata::Sign, cascdata::MXi, cascdata::MOmega, @@ -1121,11 +1587,18 @@ DECLARE_SOA_TABLE(StoredKFCascCores, "AOD", "KFCASCCORE", //! kfcascdata::MLambda, cascdata::KFV0Chi2, cascdata::KFCascadeChi2, // Dynamic columns + cascdata::PxLambda, + cascdata::PyLambda, + cascdata::PzLambda, + cascdata::Pt, + cascdata::P, + cascdata::Phi, + cascdata::Eta, cascdata::V0Radius, cascdata::CascRadius, - cascdata::V0CosPA, - cascdata::CascCosPA, - cascdata::DCAV0ToPV, + cascdata::V0CosPA, + cascdata::CascCosPA, + cascdata::DCAV0ToPV, // Invariant masses cascdata::M, @@ -1159,11 +1632,18 @@ DECLARE_SOA_TABLE(StoredTraCascCores, "AOD", "TRACASCCORE", //! cascdata::MatchingChi2, cascdata::TopologyChi2, cascdata::ItsClsSize, // Dynamic columns + cascdata::PxLambda, + cascdata::PyLambda, + cascdata::PzLambda, + cascdata::Pt, + cascdata::P, + cascdata::Phi, + cascdata::Eta, cascdata::V0Radius, cascdata::CascRadius, - cascdata::V0CosPA, - cascdata::CascCosPA, - cascdata::DCAV0ToPV, + cascdata::V0CosPA, + cascdata::CascCosPA, + cascdata::DCAV0ToPV, // Invariant masses cascdata::MLambda, @@ -1190,7 +1670,12 @@ 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 { @@ -1213,25 +1698,24 @@ 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_FULL(KFCascCovs, "KFCascCovs", "AOD", "KFCASCCOVS", //! - cascdata::KFTrackCovMat, cascdata::KFTrackCovMatV0, cascdata::KFTrackCovMatV0DauPos, cascdata::KFTrackCovMatV0DauNeg); +DECLARE_SOA_TABLE(CascCovs, "AOD", "CASCCOVS", //! + cascdata::CovMat, + cascdata::PositionCovMat, + cascdata::MomentumCovMat, + o2::soa::Marker<1>); -// extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(CascCores, StoredCascCores, "CascDATAEXT", //! - cascdataext::PxLambda, cascdataext::PyLambda, cascdataext::PzLambda, cascdataext::Pt, cascdataext::P, cascdataext::Eta, cascdataext::Phi); +DECLARE_SOA_TABLE(KFCascCovs, "AOD", "KFCASCCOVS", //! + cascdata::KFTrackCovMat, cascdata::KFTrackCovMatV0, cascdata::KFTrackCovMatV0DauPos, cascdata::KFTrackCovMatV0DauNeg); -// extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(KFCascCores, StoredKFCascCores, "KFCascDATAEXT", //! - cascdataext::PxLambda, cascdataext::PyLambda, cascdataext::PzLambda, - cascdataext::Pt, cascdataext::P, cascdataext::Eta, cascdataext::Phi); +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(TraCascCores, StoredTraCascCores, "TraCascDATAEXT", //! - cascdataext::PxLambda, cascdataext::PyLambda, cascdataext::PzLambda, - cascdataext::Pt, cascdataext::P, cascdataext::Eta, cascdataext::Phi); +using CascCores = StoredCascCores; +using KFCascCores = StoredKFCascCores; +using TraCascCores = StoredTraCascCores; namespace cascdata { @@ -1293,6 +1777,8 @@ 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 { @@ -1411,6 +1897,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..005af9c518c --- /dev/null +++ b/PWGLF/DataModel/LFhe3HadronTables.h @@ -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. + +/// +/// \file LFhe3HadronTables.h +/// \brief Slim tables for he3Hadron +/// + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.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(DCApair, dcapair, 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(NSigmaTPCHadPi, nSigmaTPCHadPi, float); +DECLARE_SOA_COLUMN(NSigmaTPCHadKa, nSigmaTPCHadKa, float); +DECLARE_SOA_COLUMN(NSigmaTPCHadPr, nSigmaTPCHadPr, float); +DECLARE_SOA_COLUMN(NSigmaTOFHadPi, nSigmaTOFHadPi, float); +DECLARE_SOA_COLUMN(NSigmaTOFHadKa, nSigmaTOFHadKa, float); +DECLARE_SOA_COLUMN(NSigmaTOFHadPr, nSigmaTOFHadPr, 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(TrackIDHe3, trackIDHe3, int); +DECLARE_SOA_COLUMN(TrackIDHad, trackIDHad, int); + +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); + +/* Flags: 0 - both primary, + 1 - both from Li4, + 2 - both from hypertriton, + 3 - mixed pair (a primary and one from Li4/hypertriton/material/other decays or any other combination) +*/ +DECLARE_SOA_COLUMN(Flags, flags, uint8_t); + +} // 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::DCApair, + he3HadronTablesNS::SignalTPCHe3, + he3HadronTablesNS::InnerParamTPCHe3, + he3HadronTablesNS::SignalTPCHad, + he3HadronTablesNS::InnerParamTPCHad, + he3HadronTablesNS::NClsTPCHe3, + he3HadronTablesNS::NSigmaTPCHe3, + he3HadronTablesNS::NSigmaTPCHadPi, + he3HadronTablesNS::NSigmaTPCHadKa, + he3HadronTablesNS::NSigmaTPCHadPr, + he3HadronTablesNS::NSigmaTOFHadPi, + he3HadronTablesNS::NSigmaTOFHadKa, + he3HadronTablesNS::NSigmaTOFHadPr, + he3HadronTablesNS::Chi2TPCHe3, + he3HadronTablesNS::Chi2TPCHad, + he3HadronTablesNS::MassTOFHe3, + he3HadronTablesNS::MassTOFHad, + he3HadronTablesNS::PIDtrkHe3, + he3HadronTablesNS::PIDtrkHad, + he3HadronTablesNS::ItsClusterSizeHe3, + he3HadronTablesNS::ItsClusterSizeHad, + he3HadronTablesNS::SharedClustersHe3, + he3HadronTablesNS::SharedClustersHad) +DECLARE_SOA_TABLE(he3HadronTableMC, "AOD", "HE3HADTABLEMC", + he3HadronTablesNS::PtMCHe3, + he3HadronTablesNS::EtaMCHe3, + he3HadronTablesNS::PhiMCHe3, + he3HadronTablesNS::PtMCHad, + he3HadronTablesNS::EtaMCHad, + he3HadronTablesNS::PhiMCHad, + he3HadronTablesNS::SignedPtMC, + he3HadronTablesNS::MassMC, + he3HadronTablesNS::Flags) +DECLARE_SOA_TABLE(he3HadronMult, "AOD", "HE3HADMULT", + he3HadronTablesNS::CollisionId, + he3HadronTablesNS::ZVertex, + he3HadronTablesNS::Multiplicity, + he3HadronTablesNS::CentralityFT0C, + he3HadronTablesNS::MultiplicityFT0C) +DECLARE_SOA_TABLE(he3HadronQa, "AOD", "HE3HADQA", + he3HadronTablesNS::TrackIDHe3, + he3HadronTablesNS::TrackIDHad) + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFHE3HADRONTABLES_H_ diff --git a/PWGLF/DataModel/Reduced3BodyTables.h b/PWGLF/DataModel/Reduced3BodyTables.h new file mode 100644 index 00000000000..3b221d17539 --- /dev/null +++ b/PWGLF/DataModel/Reduced3BodyTables.h @@ -0,0 +1,144 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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::HasITS, + track::HasTPC, + track::HasTOF, + track::HasTRD, + 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(RadiusKF, radiusKF, float); //! phi of momentum of mother particle calculated by KF +DECLARE_SOA_COLUMN(PhiKF, phiKF, float); //! SV radius in x-y plane calculated by KF +DECLARE_SOA_COLUMN(PosZKF, poszKF, float); //! z position of SV calculated by KF +DECLARE_SOA_COLUMN(RadiusDCA, radiusDCA, float); //! phi of momentum of mother particle calculated by dcaFitter +DECLARE_SOA_COLUMN(PhiDCA, phiDCA, float); //! SV radius in x-y plane calculated by dcaFitter +DECLARE_SOA_COLUMN(PosZDCA, poszDCA, float); //! z position of SV calculated by dcaFitter +DECLARE_SOA_COLUMN(TrackedClSize, trackedClSize, float); //! average ITS cluster size (if tracked) +} // namespace reduceddecay3body + +DECLARE_SOA_TABLE(RedDecay3Bodys, "AOD", "REDDECAY3BODY", //! reduced 3-body decay table + o2::soa::Index<>, reduceddecay3body::CollisionId, reduceddecay3body::Track0Id, reduceddecay3body::Track1Id, reduceddecay3body::Track2Id); + +DECLARE_SOA_TABLE(Red3BodyInfo, "AOD", "RED3BODYINFO", //! joinable with RedDecay3Bodys + reduceddecay3body::RadiusKF, reduceddecay3body::PhiKF, reduceddecay3body::PosZKF, + reduceddecay3body::RadiusDCA, reduceddecay3body::PhiDCA, reduceddecay3body::PosZDCA, + reduceddecay3body::TrackedClSize); + +} // 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 0e74ec86372..a6ed064a763 100644 --- a/PWGLF/DataModel/Vtx3BodyTables.h +++ b/PWGLF/DataModel/Vtx3BodyTables.h @@ -9,57 +9,149 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file Vtx3BodyTables.h +/// \brief Definitions of analysis tables for 3body decayed hypertriton +/// \author Yuanzhe Wang +/// \author Carolina Reetz + #ifndef PWGLF_DATAMODEL_VTX3BODYTABLES_H_ #define PWGLF_DATAMODEL_VTX3BODYTABLES_H_ -#include -#include "Framework/AnalysisDataModel.h" #include "Common/Core/RecoDecay.h" + #include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisDataModel.h" + +#include namespace o2::aod { namespace vtx3body { -DECLARE_SOA_INDEX_COLUMN_FULL(Track0, track0, int, Tracks, "_0"); //! -DECLARE_SOA_INDEX_COLUMN_FULL(Track1, track1, int, Tracks, "_1"); //! -DECLARE_SOA_INDEX_COLUMN_FULL(Track2, track2, int, Tracks, "_2"); //! -DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! -DECLARE_SOA_INDEX_COLUMN(Decay3Body, decay3body); //! - -// General 3 body Vtx properties: position, momentum -DECLARE_SOA_COLUMN(PxTrack0, pxtrack0, float); //! track0 px at min -DECLARE_SOA_COLUMN(PyTrack0, pytrack0, float); //! track0 py at min -DECLARE_SOA_COLUMN(PzTrack0, pztrack0, float); //! track0 pz at min -DECLARE_SOA_COLUMN(PxTrack1, pxtrack1, float); //! track1 px at min -DECLARE_SOA_COLUMN(PyTrack1, pytrack1, float); //! track1 py at min -DECLARE_SOA_COLUMN(PzTrack1, pztrack1, float); //! track1 pz at min -DECLARE_SOA_COLUMN(PxTrack2, pxtrack2, float); //! track2 px at min -DECLARE_SOA_COLUMN(PyTrack2, pytrack2, float); //! track2 py at min -DECLARE_SOA_COLUMN(PzTrack2, pztrack2, float); //! track2 pz at min -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 - -// Saved from finding: DCAs -DECLARE_SOA_COLUMN(DCAVtxDaughters, dcaVtxdaughters, float); //! DCA among daughters -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 +// indices +DECLARE_SOA_INDEX_COLUMN_FULL(TrackPr, trackPr, int, Tracks, "_pr"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(TrackPi, trackPi, int, Tracks, "_pi"); //! +DECLARE_SOA_INDEX_COLUMN_FULL(TrackDe, trackDe, int, Tracks, "_de"); //! +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_INDEX_COLUMN(Decay3Body, decay3body); //! + +// General 3 body Vtx properties +DECLARE_SOA_COLUMN(Mass, mass, float); //! candidate mass (with H3L or Anti-H3L mass hypothesis depending on deuteron charge) +DECLARE_SOA_COLUMN(Sign, sign, float); //! candidate sign +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(Px, px, float); //! momentum X +DECLARE_SOA_COLUMN(Py, py, float); //! momentum Y +DECLARE_SOA_COLUMN(Pz, pz, float); //! momentum Z +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! KFParticle: chi2geo/ndf or chi2topo/ndf of vertex fit, DCA fitter: Chi2AtPCACandidate value + +// daughter properties +DECLARE_SOA_COLUMN(MassV0, massV0, float); //! V0 mass (with H3L or Anti-H3L mass hypothesis depending on deuteron charge) +DECLARE_SOA_COLUMN(PxTrackPr, pxTrackPr, float); //! track0 px at min +DECLARE_SOA_COLUMN(PyTrackPr, pyTrackPr, float); //! track0 py at min +DECLARE_SOA_COLUMN(PzTrackPr, pzTrackPr, float); //! track0 pz at min +DECLARE_SOA_COLUMN(PxTrackPi, pxTrackPi, float); //! track1 px at min +DECLARE_SOA_COLUMN(PyTrackPi, pyTrackPi, float); //! track1 py at min +DECLARE_SOA_COLUMN(PzTrackPi, pzTrackPi, float); //! track1 pz at min +DECLARE_SOA_COLUMN(PxTrackDe, pxTrackDe, float); //! track2 px at min +DECLARE_SOA_COLUMN(PyTrackDe, pyTrackDe, float); //! track2 py at min +DECLARE_SOA_COLUMN(PzTrackDe, pzTrackDe, float); //! track2 pz at min + +// DCAs to PV +DECLARE_SOA_COLUMN(DCAXYTrackPrToPV, dcaXYtrackPrToPv, float); //! DCAXY of proton to PV (computed with KFParticle) +DECLARE_SOA_COLUMN(DCAXYTrackPiToPV, dcaXYtrackPiToPv, float); //! DCAXY of pion to PV (computed with KFParticle) +DECLARE_SOA_COLUMN(DCAXYTrackDeToPV, dcaXYtrackDeToPv, float); //! DCAXY of deuteron to PV (computed with KFParticle) +DECLARE_SOA_COLUMN(DCATrackPrToPV, dcaTrackPrToPv, float); //! DCA of proton to PV (computed with KFParticle) +DECLARE_SOA_COLUMN(DCATrackPiToPV, dcaTrackPiToPv, float); //! DCA of pion to PV (computed with KFParticle) +DECLARE_SOA_COLUMN(DCATrackDeToPV, dcaTrackDeToPv, float); //! DCA of deuteron to PV (computed with KFParticle) +DECLARE_SOA_COLUMN(DCAXYTrackPrToPVProp, dcaXYtrackPrToPvProp, float); //! DCAXY of proton to PV (propagated with O2 Propagator) +DECLARE_SOA_COLUMN(DCAXYTrackPiToPVProp, dcaXYtrackPiToPvProp, float); //! DCAXY of pion to PV (propagated with O2 Propagator) +DECLARE_SOA_COLUMN(DCAXYTrackDeToPVProp, dcaXYtrackDeToPvProp, float); //! DCAXY of deuteron to PV (propagated with O2 Propagator) +DECLARE_SOA_COLUMN(DCATrackPrToPVProp, dcaTrackPrToPvProp, float); //! DCA of proton to PV (propagated with O2 Propagator) +DECLARE_SOA_COLUMN(DCATrackPiToPVProp, dcaTrackPiToPvProp, float); //! DCA of pion to PV (propagated with O2 Propagator) +DECLARE_SOA_COLUMN(DCATrackDeToPVProp, dcaTrackDeToPvProp, float); //! DCA of deuteron to PV (propagated with O2 Propagator) + +// DCAs to SV +DECLARE_SOA_COLUMN(DCATrackPrToSV, dcaTrackPrToSv, float); //! DCA of proton to SV +DECLARE_SOA_COLUMN(DCATrackPiToSV, dcaTrackPiToSv, float); //! DCA of pion to SV +DECLARE_SOA_COLUMN(DCATrackDeToSV, dcaTrackDeToSv, float); //! DCA of deuteron to SV +DECLARE_SOA_COLUMN(DCAVtxToDaughtersAv, dcaVtxToDaughtersAv, float); //! Quadratic sum of DCA between daughters at SV + +// CosPA +DECLARE_SOA_COLUMN(CosPA, cosPA, float); //! Cosine of pointing angle of the 3body candidate + +// Ct +DECLARE_SOA_COLUMN(Ct, ct, float); //! Reconstruction Ct of 3body candidate + +// Strangeness tracking +DECLARE_SOA_COLUMN(TrackedClSize, trackedClSize, float); //! Average ITS cluster size of strangeness tracked 3body + +// PID +DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNSigmaPr, float); //! nsigma proton of TPC PID of the proton daughter +DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, float); //! nsigma pion of TPC PID of the pion daughter +DECLARE_SOA_COLUMN(TPCNSigmaDe, tpcNSigmaDe, float); //! nsigma deuteron of TPC PID of the bachelor daughter +DECLARE_SOA_COLUMN(TPCNSigmaPiBach, tpcNSigmaPiBach, float); //! nsigma pion of TPC PID of the bachelor daughter +DECLARE_SOA_COLUMN(TOFNSigmaDe, tofNSigmaDe, float); //! nsigma deuteron of TOF PID of the bachelor daughter +DECLARE_SOA_COLUMN(PIDTrackingDe, pidTrackingDe, uint32_t); //! PID during tracking of bachelor daughter + +// Daughter track quality +DECLARE_SOA_COLUMN(TPCNClTrackPr, tpcNClTrackPr, int); //! Number of TPC clusters of proton daughter +DECLARE_SOA_COLUMN(TPCNClTrackPi, tpcNClTrackPi, int); //! Number of TPC clusters of pion daughter +DECLARE_SOA_COLUMN(TPCNClTrackDe, tpcNClTrackDe, int); //! Number of TPC clusters of deuteron daughter +DECLARE_SOA_COLUMN(ITSClSizePr, itsClsizePr, double); //! average ITS cluster size of proton daughter +DECLARE_SOA_COLUMN(ITSClSizePi, itsClsizePi, double); //! average ITS cluster size of pion daughter +DECLARE_SOA_COLUMN(ITSClSizeDe, itsClsizeDe, double); //! average ITS cluster size of deuteron daughter + +// Covariance matrices +DECLARE_SOA_COLUMN(CovProton, covProton, float[21]); //! covariance matrix elements of proton daughter track +DECLARE_SOA_COLUMN(CovPion, covPion, float[21]); //! covariance matrix elements of pion daughter track +DECLARE_SOA_COLUMN(CovDeuteron, covDeuteron, float[21]); //! covariance matrix elements of deuteron daughter track +DECLARE_SOA_COLUMN(VtxCovMat, vtxCovMat, float[21]); //! covariance matrix elements of candidate + +// Monte Carlo info +DECLARE_SOA_COLUMN(GenPx, genPx, float); // generated Px of the hypertriton in GeV/c +DECLARE_SOA_COLUMN(GenPy, genPy, float); // generated Py of the hypertriton in GeV/c +DECLARE_SOA_COLUMN(GenPz, genPz, float); // generated Pz of the hypertriton in GeV/c +DECLARE_SOA_COLUMN(GenX, genX, float); // generated decay vtx position X of the hypertriton +DECLARE_SOA_COLUMN(GenY, genY, float); // generated decay vtx position Y of the hypertriton +DECLARE_SOA_COLUMN(GenZ, genZ, float); // generated decay vtx position Z of the hypertriton +DECLARE_SOA_COLUMN(GenCt, genCt, float); // generated Ct of the hypertriton +DECLARE_SOA_COLUMN(GenPhi, genPhi, float); // generated Phi of the hypertriton +DECLARE_SOA_COLUMN(GenEta, genEta, float); // Eta of the hypertriton +DECLARE_SOA_COLUMN(GenRap, genRap, float); // generated rapidity of the hypertriton +DECLARE_SOA_COLUMN(GenPPr, genPPr, float); //! generated momentum proton daughter particle +DECLARE_SOA_COLUMN(GenPPi, genPPi, float); //! generated momentum pion daughter particle +DECLARE_SOA_COLUMN(GenPDe, genPDe, float); //! generated momentum deuteron daughter particle +DECLARE_SOA_COLUMN(GenPtPr, genPtPr, float); //! generated transverse momentum proton daughter particle +DECLARE_SOA_COLUMN(GenPtPi, genPtPi, float); //! generated transverse momentum pion daughter particle +DECLARE_SOA_COLUMN(GenPtDe, genPtDe, float); //! generated transverse momentum deuteron 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(MotherPdgCode, motherPdgCode, int); //! PDG code of the mother particle +DECLARE_SOA_COLUMN(PrPdgCode, prPdgCode, int); //! MC particle proton PDG code +DECLARE_SOA_COLUMN(PiPdgCode, piPdgCode, int); //! MC particle pion PDG code +DECLARE_SOA_COLUMN(DePdgCode, dePdgCode, int); //! MC particle deuteron PDG code +DECLARE_SOA_COLUMN(IsDePrimary, isDePrimary, bool); //! flag for deuteron daughter primary +DECLARE_SOA_COLUMN(IsSurvEvSel, isSurvEvSel, int); //! flag if reco collision survived event selection +DECLARE_SOA_COLUMN(IsReco, isreco, int); //! flag if candidate was reconstructed // Derived expressions // Momenta -DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! 3 body p - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack0 + pxtrack1 + pxtrack2, pytrack0 + pytrack1 + pytrack2, pztrack0 + pztrack1 + pztrack2); }); -DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! 3 body pT - [](float pxtrack0, float pytrack0, float pxtrack1, float pytrack1, float pxtrack2, float pytrack2) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack0 + pxtrack1 + pxtrack2, pytrack0 + pytrack1 + pytrack2); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! 3 body pT in GeV/c + [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! 3 body total momentum in GeV/c + [](float px, float py, float pz) -> float { return RecoDecay::sqrtSumOfSquares(px, py, pz); }); +DECLARE_SOA_DYNAMIC_COLUMN(GenPt, genPt, //! 3 body pT in GeV/c + [](float genPx, float genPy) -> float { return RecoDecay::sqrtSumOfSquares(genPx, genPy); }); +DECLARE_SOA_DYNAMIC_COLUMN(GenP, genP, //! 3 body total momentum in GeV/c + [](float genPx, float genPy, float genPz) -> float { return RecoDecay::sqrtSumOfSquares(genPx, genPy, genPz); }); // Length quantities DECLARE_SOA_DYNAMIC_COLUMN(VtxRadius, vtxradius, //! 3 body decay radius (2D, centered at zero) [](float x, float y) -> float { return RecoDecay::sqrtSumOfSquares(x, y); }); +DECLARE_SOA_DYNAMIC_COLUMN(GenRadius, genRadius, //! 3 body decay radius (2D, centered at zero) + [](float genX, float genY) -> float { return RecoDecay::sqrtSumOfSquares(genX, genY); }); // Distance Over To Mom DECLARE_SOA_DYNAMIC_COLUMN(DistOverTotMom, distovertotmom, //! PV to 3 body decay distance over total momentum @@ -68,9 +160,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(DistOverTotMom, distovertotmom, //! PV to 3 body deca return std::sqrt(std::pow(X - pvX, 2) + std::pow(Y - pvY, 2) + std::pow(Z - pvZ, 2)) / (P + 1E-10); }); -// CosPA -DECLARE_SOA_DYNAMIC_COLUMN(VtxCosPA, vtxcosPA, //! 3 body vtx CosPA - [](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}); }); // Dca to PV DECLARE_SOA_DYNAMIC_COLUMN(DCAVtxToPV, dcavtxtopv, //! DCA of 3 body vtx to PV [](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)); }); @@ -81,351 +170,155 @@ DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, //! 3 body vtx eta DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, //! 3 body vtx phi [](float Px, float Py) -> float { return RecoDecay::phi(Px, Py); }); -// Calculated on the fly with mother particle hypothesis -DECLARE_SOA_DYNAMIC_COLUMN(MHypertriton, mHypertriton, //! mass under Hypertriton hypothesis - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::m(std::array{std::array{pxtrack0, pytrack0, pztrack0}, std::array{pxtrack1, pytrack1, pztrack1}, std::array{pxtrack2, pytrack2, pztrack2}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); }); -DECLARE_SOA_DYNAMIC_COLUMN(MAntiHypertriton, mAntiHypertriton, //! mass under antiHypertriton hypothesis - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::m(std::array{std::array{pxtrack0, pytrack0, pztrack0}, std::array{pxtrack1, pytrack1, pztrack1}, std::array{pxtrack2, pytrack2, pztrack2}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}); }); - -DECLARE_SOA_DYNAMIC_COLUMN(MHyperHelium4, mHyperHelium4, //! mass under HyperHelium4 hypothesis - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::m(std::array{std::array{pxtrack0, pytrack0, pztrack0}, std::array{pxtrack1, pytrack1, pztrack1}, std::array{pxtrack2, pytrack2, pztrack2}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassHelium3}); }); -DECLARE_SOA_DYNAMIC_COLUMN(MAntiHyperHelium4, mAntiHyperHelium4, //! mass under antiHyperHelium4 hypothesis - [](float pxtrack0, float pytrack0, float pztrack0, float pxtrack1, float pytrack1, float pztrack1, float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::m(std::array{std::array{pxtrack0, pytrack0, pztrack0}, std::array{pxtrack1, pytrack1, pztrack1}, std::array{pxtrack2, pytrack2, pztrack2}}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassHelium3}); }); - -DECLARE_SOA_DYNAMIC_COLUMN(YHypertriton, yHypertriton, //! 3 body vtx y with hypertriton or antihypertriton hypothesis +// Rapidity +DECLARE_SOA_DYNAMIC_COLUMN(Rap, rap, //! 3 body vtx y with hypertriton or antihypertriton hypothesis [](float Px, float Py, float Pz) -> float { return RecoDecay::y(std::array{Px, Py, Pz}, o2::constants::physics::MassHyperTriton); }); -DECLARE_SOA_DYNAMIC_COLUMN(YHyperHelium4, yHyperHelium4, //! 3 body vtx y with hyperhelium4 or antihyperhelium4 hypothesis - [](float Px, float Py, float Pz) -> float { return RecoDecay::y(std::array{Px, Py, Pz}, o2::constants::physics::MassHyperHelium4); }); - -// kinematic information of daughter tracks -DECLARE_SOA_DYNAMIC_COLUMN(Track0Pt, track0pt, //! daughter0 pT - [](float pxtrack0, float pytrack0) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack0, pytrack0); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track1Pt, track1pt, //! daughter1 pT - [](float pxtrack1, float pytrack1) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack1, pytrack1); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track2Pt, track2pt, //! daughter2 pT - [](float pxtrack2, float pytrack2) -> float { return RecoDecay::sqrtSumOfSquares(pxtrack2, pytrack2); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track0Eta, track0eta, //! daughter0 eta - [](float pxtrack0, float pytrack0, float pztrack0) -> float { return RecoDecay::eta(std::array{pxtrack0, pytrack0, pztrack0}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track0Phi, track0phi, //! daughter0 phi - [](float pxtrack0, float pytrack0) -> float { return RecoDecay::phi(pxtrack0, pytrack0); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track1Eta, track1eta, //! daughter1 eta - [](float pxtrack1, float pytrack1, float pztrack1) -> float { return RecoDecay::eta(std::array{pxtrack1, pytrack1, pztrack1}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track1Phi, track1phi, //! daughter1 phi - [](float pxtrack1, float pytrack1) -> float { return RecoDecay::phi(pxtrack1, pytrack1); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track2Eta, track2eta, //! daughter2 eta - [](float pxtrack2, float pytrack2, float pztrack2) -> float { return RecoDecay::eta(std::array{pxtrack2, pytrack2, pztrack2}); }); -DECLARE_SOA_DYNAMIC_COLUMN(Track2Phi, track2phi, //! daughter2 phi - [](float pxtrack2, float pytrack2) -> float { return RecoDecay::phi(pxtrack2, pytrack2); }); - -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, //! 3 body vtx px - float, 1.f * aod::vtx3body::pxtrack0 + 1.f * aod::vtx3body::pxtrack1 + 1.f * aod::vtx3body::pxtrack2); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, //! 3 body vtx py - float, 1.f * aod::vtx3body::pytrack0 + 1.f * aod::vtx3body::pytrack1 + 1.f * aod::vtx3body::pytrack2); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, //! 3 body vtx pz - float, 1.f * aod::vtx3body::pztrack0 + 1.f * aod::vtx3body::pztrack1 + 1.f * aod::vtx3body::pztrack2); -} // namespace vtx3body -DECLARE_SOA_TABLE_FULL(StoredVtx3BodyDatas, "Vtx3BodyDatas", "AOD", "Vtx3BodyDATA", //! - o2::soa::Index<>, vtx3body::Track0Id, vtx3body::Track1Id, vtx3body::Track2Id, vtx3body::CollisionId, vtx3body::Decay3BodyId, - vtx3body::X, vtx3body::Y, vtx3body::Z, - vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, - vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, - vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, - vtx3body::DCAVtxDaughters, - vtx3body::DCATrack0ToPV, vtx3body::DCATrack1ToPV, vtx3body::DCATrack2ToPV, - vtx3body::TOFNSigmaBachDe, - - // Dynamic columns - vtx3body::P, - vtx3body::Pt, - vtx3body::VtxRadius, - vtx3body::DistOverTotMom, - vtx3body::VtxCosPA, - vtx3body::DCAVtxToPV, - - // Invariant masses - vtx3body::MHypertriton, - vtx3body::MAntiHypertriton, - vtx3body::MHyperHelium4, - vtx3body::MAntiHyperHelium4, - - // Longitudinal - vtx3body::YHypertriton, - vtx3body::YHyperHelium4, - vtx3body::Eta, - vtx3body::Phi, - vtx3body::Track0Pt, - vtx3body::Track0Eta, - vtx3body::Track0Phi, - vtx3body::Track1Pt, - vtx3body::Track1Eta, - vtx3body::Track1Phi, - vtx3body::Track2Pt, - vtx3body::Track2Eta, - vtx3body::Track2Phi); - -// extended table with expression columns that can be used as arguments of dynamic columns -DECLARE_SOA_EXTENDED_TABLE_USER(Vtx3BodyDatas, StoredVtx3BodyDatas, "Vtx3BodyDATAEXT", //! - vtx3body::Px, vtx3body::Py, vtx3body::Pz); - -using Vtx3BodyData = Vtx3BodyDatas::iterator; -namespace vtx3body -{ -DECLARE_SOA_INDEX_COLUMN(Vtx3BodyData, vtx3BodyData); //! Index to Vtx3BodyData entry -} - -DECLARE_SOA_TABLE(Decay3BodyDataLink, "AOD", "DECAY3BODYLINK", //! Joinable table with Decay3bodys which links to Vtx3BodyData which is not produced for all entries - vtx3body::Vtx3BodyDataId); - -using Decay3BodysLinked = soa::Join; -using Decay3BodyLinked = Decay3BodysLinked::iterator; - -// Definition of labels for Vtx3BodyDatas -namespace mcvtx3bodylabel -{ -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for Vtx3BodyDatas -} // namespace mcvtx3bodylabel - -DECLARE_SOA_TABLE(McVtx3BodyLabels, "AOD", "MCVTXLABEL", //! Table joinable with Vtx3BodyData containing the MC labels - mcvtx3bodylabel::McParticleId); -using McVtx3BodyLabel = McVtx3BodyLabels::iterator; - -// Definition of labels for Decay3Bodys // Full table, joinable with Decay3Bodys (CAUTION: NOT WITH Vtx3BodyDATA) -namespace mcfullvtx3bodylabel -{ -DECLARE_SOA_INDEX_COLUMN(McParticle, mcParticle); //! MC particle for Decay3Bodys -} // namespace mcfullvtx3bodylabel - -DECLARE_SOA_TABLE(McFullVtx3BodyLabels, "AOD", "MCFULLVTXLABEL", //! Table joinable with Decay3Bodys - mcfullvtx3bodylabel::McParticleId); -using McFullVtx3BodyLabel = McFullVtx3BodyLabels::iterator; +// Kinematic information of daughter tracks +DECLARE_SOA_DYNAMIC_COLUMN(TrackPrPt, trackPrPt, //! daughter0 pT + [](float pxTrackPr, float pyTrackPr) -> float { return RecoDecay::sqrtSumOfSquares(pxTrackPr, pyTrackPr); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPiPt, trackPiPt, //! daughter1 pT + [](float pxTrackPi, float pyTrackPi) -> float { return RecoDecay::sqrtSumOfSquares(pxTrackPi, pyTrackPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackDePt, trackDePt, //! daughter2 pT + [](float pxTrackDe, float pyTrackDe) -> float { return RecoDecay::sqrtSumOfSquares(pxTrackDe, pyTrackDe); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPrEta, trackPrEta, //! daughter0 eta + [](float pxTrackPr, float pyTrackPr, float pzTrackPr) -> float { return RecoDecay::eta(std::array{pxTrackPr, pyTrackPr, pzTrackPr}); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPrPhi, trackPrPhi, //! daughter0 phi + [](float pxTrackPr, float pyTrackPr) -> float { return RecoDecay::phi(pxTrackPr, pyTrackPr); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPiEta, trackPiEta, //! daughter1 eta + [](float pxTrackPi, float pyTrackPi, float pzTrackPi) -> float { return RecoDecay::eta(std::array{pxTrackPi, pyTrackPi, pzTrackPi}); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackPiPhi, trackPiPhi, //! daughter1 phi + [](float pxTrackPi, float pyTrackPi) -> float { return RecoDecay::phi(pxTrackPi, pyTrackPi); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackDeEta, trackDeEta, //! daughter2 eta + [](float pxTrackDe, float pyTrackDe, float pzTrackDe) -> float { return RecoDecay::eta(std::array{pxTrackDe, pyTrackDe, pzTrackDe}); }); +DECLARE_SOA_DYNAMIC_COLUMN(TrackDePhi, trackDePhi, //! daughter2 phi + [](float pxTrackDe, float pyTrackDe) -> float { return RecoDecay::phi(pxTrackDe, pyTrackDe); }); +} // namespace vtx3body -// output table for ML studies -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 -// 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 -// 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 -DECLARE_SOA_COLUMN(TPCNclusBachelor, tpcNclusBachelor, uint8_t); //! number of TPC clusters of the bachelor daughter -DECLARE_SOA_COLUMN(ITSNclusSizeProton, itsNclusSizeProton, uint8_t); //! average ITS cluster size of the proton daughter -DECLARE_SOA_COLUMN(ITSNclusSizePion, itsNclusSizePion, uint8_t); //! average ITS cluster size of the pion daughter -DECLARE_SOA_COLUMN(ITSNclusSizeBachelor, itsNclusSizeBachelor, uint8_t); //! average ITS cluster size of the bachelor daughter -// PID -DECLARE_SOA_COLUMN(TPCNSigmaProton, tpcNSigmaProton, float); //! nsigma of TPC PID of the proton daughter -DECLARE_SOA_COLUMN(TPCNSigmaPion, tpcNSigmaPion, float); //! nsigma of TPC PID of the pion daughter -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 -// 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(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 -DECLARE_SOA_COLUMN(SurvivedEventSelection, survivedEventSelection, bool); // bool: true for survived event selection -} // namespace hyp3body - -// output table for data -DECLARE_SOA_TABLE(Hyp3BodyCands, "AOD", "HYP3BODYCANDS", +// index table +DECLARE_SOA_TABLE(Decay3BodyIndices, "AOD", "3BodyINDEX", //! 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, - // 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::TPCNclusProton, hyp3body::TPCNclusPion, hyp3body::TPCNclusBachelor, - hyp3body::ITSNclusSizeProton, hyp3body::ITSNclusSizePion, hyp3body::ITSNclusSizeBachelor, - hyp3body::TPCNSigmaProton, hyp3body::TPCNSigmaPion, hyp3body::TPCNSigmaBachelor, - hyp3body::TOFNSigmaBachelor, - hyp3body::DCAProtonToPV, hyp3body::DCAPionToPV, hyp3body::DCABachelorToPV); - -// output table for MC -DECLARE_SOA_TABLE(MCHyp3BodyCands, "AOD", "MCHYP3BODYCANDS", + vtx3body::Decay3BodyId, + vtx3body::TrackPrId, vtx3body::TrackPiId, vtx3body::TrackDeId, + vtx3body::CollisionId); + +// reconstructed candidate table for analysis +DECLARE_SOA_TABLE(Vtx3BodyDatas, "AOD", "VTX3BODYDATA", //! 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, - // 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::TPCNclusProton, hyp3body::TPCNclusPion, hyp3body::TPCNclusBachelor, - hyp3body::ITSNclusSizeProton, hyp3body::ITSNclusSizePion, hyp3body::ITSNclusSizeBachelor, - hyp3body::TPCNSigmaProton, hyp3body::TPCNSigmaPion, hyp3body::TPCNSigmaBachelor, - hyp3body::TOFNSigmaBachelor, - hyp3body::DCAProtonToPV, hyp3body::DCAPionToPV, hyp3body::DCABachelorToPV, - // MC information - hyp3body::GenP, - hyp3body::GenPt, - hyp3body::GenCt, - hyp3body::GenPhi, - hyp3body::GenEta, - 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(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(Sign, sign, float); //! candidate sign + vtx3body::Sign, + vtx3body::Mass, vtx3body::MassV0, + vtx3body::X, vtx3body::Y, vtx3body::Z, + vtx3body::Px, vtx3body::Py, vtx3body::Pz, + vtx3body::Chi2, + vtx3body::TrackedClSize, + vtx3body::PxTrackPr, vtx3body::PyTrackPr, vtx3body::PzTrackPr, + vtx3body::PxTrackPi, vtx3body::PyTrackPi, vtx3body::PzTrackPi, + vtx3body::PxTrackDe, vtx3body::PyTrackDe, vtx3body::PzTrackDe, + vtx3body::DCAXYTrackPrToPV, vtx3body::DCAXYTrackPiToPV, vtx3body::DCAXYTrackDeToPV, + vtx3body::DCATrackPrToPV, vtx3body::DCATrackPiToPV, vtx3body::DCATrackDeToPV, + vtx3body::DCAXYTrackPrToPVProp, vtx3body::DCAXYTrackPiToPVProp, vtx3body::DCAXYTrackDeToPVProp, + vtx3body::DCATrackPrToPVProp, vtx3body::DCATrackPiToPVProp, vtx3body::DCATrackDeToPVProp, + vtx3body::DCATrackPrToSV, vtx3body::DCATrackPiToSV, vtx3body::DCATrackDeToSV, + vtx3body::DCAVtxToDaughtersAv, + vtx3body::CosPA, vtx3body::Ct, + vtx3body::TPCNSigmaPr, vtx3body::TPCNSigmaPi, vtx3body::TPCNSigmaDe, vtx3body::TPCNSigmaPiBach, + vtx3body::TOFNSigmaDe, + vtx3body::ITSClSizePr, vtx3body::ITSClSizePi, vtx3body::ITSClSizeDe, + vtx3body::TPCNClTrackPr, vtx3body::TPCNClTrackPi, vtx3body::TPCNClTrackDe, + vtx3body::PIDTrackingDe, + + // Dynamic columns + vtx3body::P, + vtx3body::Pt, + vtx3body::VtxRadius, + vtx3body::DistOverTotMom, + vtx3body::DCAVtxToPV, -// 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) - -// 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(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(DCAxyTrack0ToTrack1, dcaxytrack0totrack1kf, float); //! DCAxy of proton prong to pion from KFParticle -DECLARE_SOA_COLUMN(DCAxyTrack0ToTrack2, dcaxytrack0totrack2kf, float); //! DCAxy of proton prong to deuteron from KFParticle -DECLARE_SOA_COLUMN(DCAxyTrack1ToTrack2, dcaxytrack1totrack2kf, 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 - -// 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 - -} // namespace kfvtx3body - -DECLARE_SOA_TABLE(StoredKFVtx3BodyDatas, "AOD", "KFVTX3BODYDATA", //! - // indices - o2::soa::Index<>, vtx3body::CollisionId, vtx3body::Track0Id, vtx3body::Track1Id, vtx3body::Track2Id, vtx3body::Decay3BodyId, - - // hypertriton candidate - kfvtx3body::Mass, + // Longitudinal + vtx3body::Rap, + vtx3body::Eta, + vtx3body::Phi, + vtx3body::TrackPrPt, + vtx3body::TrackPrEta, + vtx3body::TrackPrPhi, + vtx3body::TrackPiPt, + vtx3body::TrackPiEta, + vtx3body::TrackPiPhi, + vtx3body::TrackDePt, + vtx3body::TrackDeEta, + vtx3body::TrackDePhi); + +// covariance matrix table +DECLARE_SOA_TABLE(Vtx3BodyCovs, "AOD", "VTX3BODYCOV", //! + vtx3body::CovProton, vtx3body::CovPion, vtx3body::CovDeuteron, + vtx3body::VtxCovMat); + +// MC candidate table for analysis +DECLARE_SOA_TABLE(McVtx3BodyDatas, "AOD", "MC3BODYDATA", //! + o2::soa::Index<>, + vtx3body::Sign, + vtx3body::Mass, vtx3body::MassV0, 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::VtxCosPAKFtopo, kfvtx3body::VtxCosXYPAKFtopo, - kfvtx3body::DecayLKF, kfvtx3body::DecayLXYKF, kfvtx3body::DecayLDeltaL, - kfvtx3body::Chi2geoNDF, kfvtx3body::Chi2topoNDF, - - // V0 - kfvtx3body::MassV0, kfvtx3body::Chi2MassV0, - - // daughters - vtx3body::PxTrack0, vtx3body::PyTrack0, vtx3body::PzTrack0, // proton - vtx3body::PxTrack1, vtx3body::PyTrack1, vtx3body::PzTrack1, // pion - vtx3body::PxTrack2, vtx3body::PyTrack2, vtx3body::PzTrack2, // deuteron - kfvtx3body::DCATrack0ToPVKF, kfvtx3body::DCATrack1ToPVKF, kfvtx3body::DCATrack2ToPVKF, kfvtx3body::DCAxyTrack0ToPVKF, kfvtx3body::DCAxyTrack1ToPVKF, kfvtx3body::DCAxyTrack2ToPVKF, - kfvtx3body::DCAxyTrack0ToSVKF, kfvtx3body::DCAxyTrack1ToSVKF, kfvtx3body::DCAxyTrack2ToSVKF, - kfvtx3body::DCAxyTrack0ToTrack1, kfvtx3body::DCAxyTrack0ToTrack2, kfvtx3body::DCAxyTrack1ToTrack2, - kfvtx3body::DCAVtxDaughtersKF, - vtx3body::DCATrack0ToPV, vtx3body::DCATrack1ToPV, vtx3body::DCATrack2ToPV, - kfvtx3body::Track0Sign, kfvtx3body::Track1Sign, kfvtx3body::Track2Sign, // track sing: proton, pion, deuteron - vtx3body::TOFNSigmaBachDe, - - // dynamic columns + vtx3body::Px, vtx3body::Py, vtx3body::Pz, + vtx3body::Chi2, + vtx3body::TrackedClSize, + vtx3body::PxTrackPr, vtx3body::PyTrackPr, vtx3body::PzTrackPr, + vtx3body::PxTrackPi, vtx3body::PyTrackPi, vtx3body::PzTrackPi, + vtx3body::PxTrackDe, vtx3body::PyTrackDe, vtx3body::PzTrackDe, + vtx3body::DCAXYTrackPrToPV, vtx3body::DCAXYTrackPiToPV, vtx3body::DCAXYTrackDeToPV, + vtx3body::DCATrackPrToPV, vtx3body::DCATrackPiToPV, vtx3body::DCATrackDeToPV, + vtx3body::DCAXYTrackPrToPVProp, vtx3body::DCAXYTrackPiToPVProp, vtx3body::DCAXYTrackDeToPVProp, + vtx3body::DCATrackPrToPVProp, vtx3body::DCATrackPiToPVProp, vtx3body::DCATrackDeToPVProp, + vtx3body::DCATrackPrToSV, vtx3body::DCATrackPiToSV, vtx3body::DCATrackDeToSV, + vtx3body::DCAVtxToDaughtersAv, + vtx3body::CosPA, vtx3body::Ct, + vtx3body::TPCNSigmaPr, vtx3body::TPCNSigmaPi, vtx3body::TPCNSigmaDe, vtx3body::TPCNSigmaPiBach, + vtx3body::TOFNSigmaDe, + vtx3body::ITSClSizePr, vtx3body::ITSClSizePi, vtx3body::ITSClSizeDe, + vtx3body::TPCNClTrackPr, vtx3body::TPCNClTrackPi, vtx3body::TPCNClTrackDe, + vtx3body::PIDTrackingDe, + + // Monte Carlo information + vtx3body::GenPx, vtx3body::GenPy, vtx3body::GenPz, + vtx3body::GenX, vtx3body::GenY, vtx3body::GenZ, + vtx3body::GenCt, + vtx3body::GenPhi, vtx3body::GenEta, vtx3body::GenRap, + vtx3body::GenPPr, vtx3body::GenPPi, vtx3body::GenPDe, + vtx3body::GenPtPr, vtx3body::GenPtPi, vtx3body::GenPtDe, + vtx3body::IsTrueH3L, vtx3body::IsTrueAntiH3L, + vtx3body::IsReco, + vtx3body::MotherPdgCode, + vtx3body::PrPdgCode, vtx3body::PiPdgCode, vtx3body::DePdgCode, + vtx3body::IsDePrimary, + vtx3body::IsSurvEvSel, + + // Dynamic columns + vtx3body::P, + vtx3body::Pt, + vtx3body::GenP, + vtx3body::GenPt, vtx3body::VtxRadius, - vtx3body::DistOverTotMom, - vtx3body::VtxCosPA, - vtx3body::DCAVtxToPV, + vtx3body::GenRadius, + vtx3body::DistOverTotMom, + vtx3body::DCAVtxToPV, // Longitudinal - vtx3body::YHypertriton, - vtx3body::Eta, - vtx3body::Phi, - vtx3body::Track0Pt, // proton pT - vtx3body::Track0Eta, // proton eta - vtx3body::Track0Phi, // proton phi - vtx3body::Track1Pt, // pion pT - vtx3body::Track1Eta, // pion eta - vtx3body::Track1Phi, // pion phi - vtx3body::Track2Pt, // deuteron pT - vtx3body::Track2Eta, // deuteron eta - vtx3body::Track2Phi); // deuteron phi - -using StoredKFVtx3BodyData = StoredKFVtx3BodyDatas::iterator; -namespace kfvtx3body -{ -DECLARE_SOA_INDEX_COLUMN(StoredKFVtx3BodyData, storedkfvtx3BodyData); //! Index to KFVtx3BodyData entry -} + vtx3body::Rap, + vtx3body::Eta, + vtx3body::Phi, + vtx3body::TrackPrPt, + vtx3body::TrackPrEta, + vtx3body::TrackPrPhi, + vtx3body::TrackPiPt, + vtx3body::TrackPiEta, + vtx3body::TrackPiPhi, + vtx3body::TrackDePt, + vtx3body::TrackDeEta, + vtx3body::TrackDePhi); + +// Define joins +using Vtx3BodyDatasCovs = soa::Join; +using Vtx3BodyDatasCovsIndexed = soa::Join; } // namespace o2::aod diff --git a/PWGLF/DataModel/cascqaanalysis.h b/PWGLF/DataModel/cascqaanalysis.h index 5bc77d96d10..4cb9176f99e 100644 --- a/PWGLF/DataModel/cascqaanalysis.h +++ b/PWGLF/DataModel/cascqaanalysis.h @@ -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,21 +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(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(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); - +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(DcaPosToPV, dcaPosToPV, float); +DECLARE_SOA_COLUMN(DcaNegToPV, dcaNegToPV, float); +DECLARE_SOA_COLUMN(V0CosPA, v0CosPA, double); +DECLARE_SOA_COLUMN(DcaV0Daughters, dcaV0Daughters, float); +DECLARE_SOA_COLUMN(Pzs2Lambda, pzs2Lambda, double); +DECLARE_SOA_COLUMN(Cos2ThetaLambda, cos2ThetaLambda, double); +DECLARE_SOA_COLUMN(CosThetaLambda, cosThetaLambda, double); } // namespace cascadesflow DECLARE_SOA_TABLE(MyCascades, "AOD", "MYCASCADES", o2::soa::Index<>, @@ -151,6 +167,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); @@ -160,7 +178,10 @@ 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::Phi, cascadesflow::MassXi, cascadesflow::MassOmega, cascadesflow::V2CSP, cascadesflow::V2CEP, cascadesflow::PsiT0C, cascadesflow::BDTResponseXi, cascadesflow::BDTResponseOmega, cascadesflow::CosThetaStarLambdaFromOmega, cascadesflow::CosThetaStarLambdaFromXi, cascadesflow::CosThetaStarProton); + 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); + +DECLARE_SOA_TABLE(LambdaAnalysis, "AOD", "LambdaAnalysis", o2::soa::Index<>, + cascadesflow::CentFT0C, cascadesflow::HasEventPlane, cascadesflow::HasSpectatorPlane, cascadesflow::Sign, cascadesflow::Pt, cascadesflow::Phi, cascadesflow::Eta, cascadesflow::MassLambda, cascadesflow::V0Radius, cascadesflow::DcaPosToPV, cascadesflow::DcaNegToPV, cascadesflow::V0CosPA, cascadesflow::DcaV0Daughters, cascadesflow::V2CEP, cascadesflow::PsiT0C, cascadesflow::Pzs2Lambda, cascadesflow::Cos2ThetaLambda, cascadesflow::CosThetaLambda); namespace myMCcascades { 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 index 86e97eb8c33..fdbe1426e52 100644 --- a/PWGLF/DataModel/mcCentrality.h +++ b/PWGLF/DataModel/mcCentrality.h @@ -21,9 +21,10 @@ #define PWGLF_DATAMODEL_MCCENTRALITY_H_ // O2 includes +#include "Common/DataModel/Centrality.h" + #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/Centrality.h" #include "Framework/Logger.h" namespace o2::aod diff --git a/PWGLF/DataModel/particleCompositionCorrectionTable.h b/PWGLF/DataModel/particleCompositionCorrectionTable.h new file mode 100644 index 00000000000..f57d2165e76 --- /dev/null +++ b/PWGLF/DataModel/particleCompositionCorrectionTable.h @@ -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. + +/// +/// \file ParticleCompositionCorrectionTable.h +/// \brief Table for scaling MC particle abundances to match measurements +/// \author Mario Krüger +/// + +#ifndef PWGLF_DATAMODEL_PARTICLECOMPOSITIONCORRECTIONTABLE_H_ +#define PWGLF_DATAMODEL_PARTICLECOMPOSITIONCORRECTIONTABLE_H_ + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace PCC +{ +DECLARE_SOA_COLUMN(PccWeight, pccWeight, float); +DECLARE_SOA_COLUMN(PccWeightSysUp, pccWeightSysUp, float); +DECLARE_SOA_COLUMN(PccWeightSysDown, pccWeightSysDown, float); +} // namespace PCC +DECLARE_SOA_TABLE(ParticleCompositionCorrection, "AOD", "PARTICLECOMPOSITIONCORRECTION", PCC::PccWeight, PCC::PccWeightSysUp, PCC::PccWeightSysDown); +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_PARTICLECOMPOSITIONCORRECTIONTABLE_H_ diff --git a/PWGLF/DataModel/spectraTOF.h b/PWGLF/DataModel/spectraTOF.h index 00b9e60ee26..9cf4b789295 100644 --- a/PWGLF/DataModel/spectraTOF.h +++ b/PWGLF/DataModel/spectraTOF.h @@ -48,6 +48,8 @@ static constexpr const char* pN[Np] = {"el", "mu", "pi", "ka", "pr", "de", "tr", 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}; @@ -398,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); diff --git a/PWGLF/DataModel/v0qaanalysis.h b/PWGLF/DataModel/v0qaanalysis.h index 05c90791bde..18cb449fbea 100644 --- a/PWGLF/DataModel/v0qaanalysis.h +++ b/PWGLF/DataModel/v0qaanalysis.h @@ -10,20 +10,22 @@ // 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_ +#include + 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); @@ -36,8 +38,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); @@ -54,26 +54,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/Common/CMakeLists.txt b/PWGLF/TableProducer/Common/CMakeLists.txt index a3c26273a81..5f1df4b5202 100644 --- a/PWGLF/TableProducer/Common/CMakeLists.txt +++ b/PWGLF/TableProducer/Common/CMakeLists.txt @@ -15,6 +15,11 @@ o2physics_add_dpl_workflow(epvector 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 @@ -28,4 +33,9 @@ o2physics_add_dpl_workflow(zdcsp o2physics_add_dpl_workflow(mc-centrality SOURCES mcCentrality.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) \ No newline at end of file + 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/Common/epvector.cxx b/PWGLF/TableProducer/Common/epvector.cxx index 25823ef6edd..ce5d470122a 100644 --- a/PWGLF/TableProducer/Common/epvector.cxx +++ b/PWGLF/TableProducer/Common/epvector.cxx @@ -18,43 +18,39 @@ /// (with or without corrections) and save the results in a dedicated table. /// -// C++/ROOT includes. -#include -#include -#include -#include -#include -#include +#include "PWGLF/DataModel/EPCalibrationTables.h" -// o2Physics includes. -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.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/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.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 "Common/DataModel/FT0Corrected.h" -#include "FT0Base/Geometry.h" -#include "FV0Base/Geometry.h" -#include "PWGLF/DataModel/EPCalibrationTables.h" -#include "TF1.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" -// #include "Common/Core/EventPlaneHelper.h" -// #include "Common/DataModel/Qvectors.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -// o2 includes. -#include "CCDB/CcdbApi.h" -#include "CCDB/BasicCCDBManager.h" -#include "DetectorsCommonDataFormats/AlignParam.h" +#include +#include +#include +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -92,12 +88,24 @@ struct epvector { Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; Configurable cfgITScluster{"cfgITScluster", 4, "Number of ITS cluster"}; // Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable cfgHarmonic{"cfgHarmonic", 2, "Harmonic for event plane calculation"}; 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 useEventSelection{"useEventSelection", true, "Apply event selection centrality wise"}; + Configurable useTimeFrameCut{"useTimeFrameCut", true, "Reject Time Frame border events"}; + Configurable useITSFrameCut{"useITSFrameCut", true, "Reject ITS RO Frame border events"}; + Configurable usePileupCut{"usePileupCut", false, "Reject same bunch pileup"}; + Configurable useITSLayerCut{"useITSLayerCut", false, "Require good ITS layers"}; + Configurable useGoodZvtx{"useGoodZvtx", false, "Require good vertex from FT0 and PV"}; 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; @@ -108,6 +116,8 @@ struct epvector { void init(o2::framework::InitContext&) { + 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"}; @@ -117,9 +127,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}}); @@ -139,11 +152,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) { @@ -196,26 +230,28 @@ struct epvector { return TMath::ATan2(chPos.Y() + offsetY, chPos.X() + offsetX); } - double GetPhiInRange(double phi) + double GetPhiInRange(double phi, double harmonic = 2) { double result = phi; + double period = 2. * TMath::Pi() / harmonic; while (result < 0) { - result = result + 2. * TMath::Pi() / 2; + result = result + period; } - while (result > 2. * TMath::Pi() / 2) { - result = result - 2. * TMath::Pi() / 2; + while (result > period) { + result = result - period; } return result; } - double GetDeltaPsiSubInRange(double psi1, double psi2) + double GetDeltaPsiSubInRange(double psi1, double psi2, double harmonic = 2) { double delta = psi1 - psi2; - if (TMath::Abs(delta) > TMath::Pi() / 2) { + double period = TMath::Pi() / harmonic; + if (TMath::Abs(delta) > period) { if (delta > 0.) - delta -= 2. * TMath::Pi() / 2; + delta -= 2. * period; else - delta += 2. * TMath::Pi() / 2; + delta += 2. * period; } return delta; } @@ -232,6 +268,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); @@ -261,12 +301,12 @@ struct epvector { auto qyTPCL = 0.0; auto qxTPCR = 0.0; auto qyTPCR = 0.0; - if (coll.sel8() && centrality < cfgCutCentrality && TMath::Abs(vz) < cfgCutVertex && coll.has_foundFT0() && eventSelected(coll, centrality) && coll.selection_bit(aod::evsel::kNoTimeFrameBorder) && coll.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + if (coll.sel8() && centrality < cfgCutCentrality && TMath::Abs(vz) < cfgCutVertex && coll.has_foundFT0() && (!useEventSelection || eventSelected(coll, centrality)) && (!useTimeFrameCut || coll.selection_bit(aod::evsel::kNoTimeFrameBorder)) && (!useITSFrameCut || coll.selection_bit(aod::evsel::kNoITSROFrameBorder)) && (!usePileupCut || coll.selection_bit(aod::evsel::kNoSameBunchPileup)) && (!useITSLayerCut || coll.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) && (!useGoodZvtx || coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))) { triggerevent = true; 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); @@ -284,12 +324,11 @@ struct epvector { float ampl = gainequal * ft0.amplitudeA()[iChA]; histos.fill(HIST("FT0Amp"), chanelid, ampl); auto phiA = GetPhiFT0(chanelid, offsetFT0Ax, offsetFT0Ay); - qxFT0A = qxFT0A + ampl * TMath::Cos(2.0 * phiA); - qyFT0A = qyFT0A + ampl * TMath::Sin(2.0 * phiA); + qxFT0A = qxFT0A + ampl * TMath::Cos(cfgHarmonic.value * phiA); + qyFT0A = qyFT0A + ampl * TMath::Sin(cfgHarmonic.value * phiA); } for (std::size_t iChC = 0; iChC < ft0.channelC().size(); iChC++) { auto chanelid = ft0.channelC()[iChC] + 96; - // printf("Offset for FT0A: x = %d y = %d\n", chanelid, chanelid-96); auto gainequal = 1.0; if (useGainCallib) { gainequal = 1 / gainprofile->GetBinContent(gainprofile->FindBin(chanelid)); @@ -297,23 +336,23 @@ struct epvector { float ampl = gainequal * ft0.amplitudeC()[iChC]; histos.fill(HIST("FT0Amp"), chanelid, ampl); auto phiC = GetPhiFT0(chanelid, offsetFT0Cx, offsetFT0Cy); - qxFT0C = qxFT0C + ampl * TMath::Cos(2.0 * phiC); - qyFT0C = qyFT0C + ampl * TMath::Sin(2.0 * phiC); + qxFT0C = qxFT0C + ampl * TMath::Cos(cfgHarmonic.value * phiC); + qyFT0C = qyFT0C + ampl * TMath::Sin(cfgHarmonic.value * phiC); } 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()); - qyTPC = qyTPC + trk.pt() * TMath::Sin(2.0 * trk.phi()); + qxTPC = qxTPC + trk.pt() * TMath::Cos(cfgHarmonic.value * trk.phi()); + qyTPC = qyTPC + trk.pt() * TMath::Sin(cfgHarmonic.value * trk.phi()); if (trk.eta() < 0.0) { - qxTPCL = qxTPCL + trk.pt() * TMath::Cos(2.0 * trk.phi()); - qyTPCL = qyTPCL + trk.pt() * TMath::Sin(2.0 * trk.phi()); + qxTPCL = qxTPCL + trk.pt() * TMath::Cos(cfgHarmonic.value * trk.phi()); + qyTPCL = qyTPCL + trk.pt() * TMath::Sin(cfgHarmonic.value * trk.phi()); } if (trk.eta() > 0.0) { - qxTPCR = qxTPCR + trk.pt() * TMath::Cos(2.0 * trk.phi()); - qyTPCR = qyTPCR + trk.pt() * TMath::Sin(2.0 * trk.phi()); + qxTPCR = qxTPCR + trk.pt() * TMath::Cos(cfgHarmonic.value * trk.phi()); + qyTPCR = qyTPCR + trk.pt() * TMath::Sin(cfgHarmonic.value * trk.phi()); } } if (useRecentere && (currentRunNumber != lastRunNumber)) { @@ -331,23 +370,54 @@ struct epvector { qxTPCR = (qxTPCR - hrecentere->GetBinContent(hrecentere->FindBin(centrality, 8.5))) / hrecentere->GetBinError(hrecentere->FindBin(centrality, 8.5)); qyTPCR = (qyTPCR - hrecentere->GetBinContent(hrecentere->FindBin(centrality, 9.5))) / hrecentere->GetBinError(hrecentere->FindBin(centrality, 9.5)); } - psiFT0C = 0.5 * TMath::ATan2(qyFT0C, qxFT0C); - psiFT0A = 0.5 * TMath::ATan2(qyFT0A, qxFT0A); - psiTPC = 0.5 * TMath::ATan2(qyTPC, qxTPC); - psiTPCL = 0.5 * TMath::ATan2(qyTPCL, qxTPCL); - psiTPCR = 0.5 * TMath::ATan2(qyTPCR, qxTPCR); + psiFT0C = (1.0 / cfgHarmonic.value) * TMath::ATan2(qyFT0C, qxFT0C); + psiFT0A = (1.0 / cfgHarmonic.value) * TMath::ATan2(qyFT0A, qxFT0A); + psiTPC = (1.0 / cfgHarmonic.value) * TMath::ATan2(qyTPC, qxTPC); + psiTPCL = (1.0 / cfgHarmonic.value) * TMath::ATan2(qyTPCL, qxTPCL); + psiTPCR = (1.0 / cfgHarmonic.value) * TMath::ATan2(qyTPCR, qxTPCR); 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))); + deltapsiFT0C = deltapsiFT0C + ((1 / (1.0 * ishift)) * (-coeffshiftxFT0C * TMath::Cos(ishift * cfgHarmonic.value * psiFT0C) + coeffshiftyFT0C * TMath::Sin(ishift * cfgHarmonic.value * 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 * cfgHarmonic.value * psiFT0A) + coeffshiftyFT0A * TMath::Sin(ishift * cfgHarmonic.value * psiFT0A))); + deltapsiTPC = deltapsiTPC + ((1 / (1.0 * ishift)) * (-coeffshiftxTPC * TMath::Cos(ishift * cfgHarmonic.value * psiTPC) + coeffshiftyTPC * TMath::Sin(ishift * cfgHarmonic.value * psiTPC))); + deltapsiTPCL = deltapsiTPCL + ((1 / (1.0 * ishift)) * (-coeffshiftxTPCL * TMath::Cos(ishift * cfgHarmonic.value * psiTPCL) + coeffshiftyTPCL * TMath::Sin(ishift * cfgHarmonic.value * psiTPCL))); + deltapsiTPCR = deltapsiTPCR + ((1 / (1.0 * ishift)) * (-coeffshiftxTPCR * TMath::Cos(ishift * cfgHarmonic.value * psiTPCR) + coeffshiftyTPCR * TMath::Sin(ishift * cfgHarmonic.value * 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); @@ -365,13 +435,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(cfgHarmonic.value * (psiFT0C - psiFT0A)), occupancy); + histos.fill(HIST("ResFT0CTPC"), centrality, TMath::Cos(cfgHarmonic.value * (psiFT0C - psiTPC)), occupancy); + histos.fill(HIST("ResFT0ATPC"), centrality, TMath::Cos(cfgHarmonic.value * (psiFT0A - psiTPC)), occupancy); + histos.fill(HIST("ResFT0CTPCL"), centrality, TMath::Cos(cfgHarmonic.value * (psiFT0C - psiTPCL)), occupancy); + histos.fill(HIST("ResFT0CTPCR"), centrality, TMath::Cos(cfgHarmonic.value * (psiFT0C - psiTPCR)), occupancy); + histos.fill(HIST("ResTPCRTPCL"), centrality, TMath::Cos(cfgHarmonic.value * (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(cfgHarmonic.value * (psiFT0C - psiFT0A)), occupancy); + histos.fill(HIST("ResFT0CTPCSP"), centrality, qFT0Cmag * qTPCmag * TMath::Cos(cfgHarmonic.value * (psiFT0C - psiTPC)), occupancy); + histos.fill(HIST("ResFT0ATPCSP"), centrality, qFT0Amag * qTPCmag * TMath::Cos(cfgHarmonic.value * (psiFT0A - psiTPC)), occupancy); + histos.fill(HIST("ResFT0CTPCLSP"), centrality, qFT0Cmag * qTPCLmag * TMath::Cos(cfgHarmonic.value * (psiFT0C - psiTPCL)), occupancy); + histos.fill(HIST("ResFT0CTPCRSP"), centrality, qFT0Cmag * qTPCRmag * TMath::Cos(cfgHarmonic.value * (psiFT0C - psiTPCR)), occupancy); + histos.fill(HIST("ResTPCRTPCLSP"), centrality, qTPCRmag * qTPCLmag * TMath::Cos(cfgHarmonic.value * (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("ShiftFT0C"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * cfgHarmonic.value * psiFT0C)); + histos.fill(HIST("ShiftFT0C"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * cfgHarmonic.value * psiFT0C)); + + histos.fill(HIST("ShiftFT0A"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * cfgHarmonic.value * psiFT0A)); + histos.fill(HIST("ShiftFT0A"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * cfgHarmonic.value * psiFT0A)); + + histos.fill(HIST("ShiftTPC"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * cfgHarmonic.value * psiTPC)); + histos.fill(HIST("ShiftTPC"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * cfgHarmonic.value * psiTPC)); + + histos.fill(HIST("ShiftTPCL"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * cfgHarmonic.value * psiTPCL)); + histos.fill(HIST("ShiftTPCL"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * cfgHarmonic.value * psiTPCL)); + + histos.fill(HIST("ShiftTPCR"), centrality, 0.5, ishift - 0.5, TMath::Sin(ishift * cfgHarmonic.value * psiTPCR)); + histos.fill(HIST("ShiftTPCR"), centrality, 1.5, ishift - 0.5, TMath::Cos(ishift * cfgHarmonic.value * psiTPCR)); } lastRunNumber = currentRunNumber; } diff --git a/PWGLF/TableProducer/Common/kinkBuilder.cxx b/PWGLF/TableProducer/Common/kinkBuilder.cxx new file mode 100644 index 00000000000..eb68fe85b39 --- /dev/null +++ b/PWGLF/TableProducer/Common/kinkBuilder.cxx @@ -0,0 +1,475 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/Utils/svPoolCreator.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include + +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 h2MothMassPt; +} // 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 { + + enum PartType { kSigmaMinus = 0, + kHypertriton, + kHyperhelium4sigma }; + + Produces outputDataTable; + Produces outputDataTableUB; + + Service ccdb; + + Configurable hypoMoth{"hypoMoth", kSigmaMinus, "Mother particle hypothesis"}; + Configurable fillDebugTable{"fillDebugTable", false, "If true, fill the debug table with all candidates unbound"}; + // 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"}; + Configurable doSVRadiusCut{"doSVRadiusCut", true, "If true, apply the cut on the radius of the secondary vertex and tracksIU"}; + Configurable updateMothTrackUsePV{"updateMothTrackUsePV", false, "If true, update the mother track parameters using the primary vertex"}; + + o2::vertexing::DCAFitterN<2> fitter; + o2::base::MatLayerCylSet* lut = nullptr; + + // constants + float radToDeg = o2::constants::math::Rad2Deg; + 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 ccdbPath{"ccdbPath", "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"}; + + // 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; + + // mother and daughter tracks' properties (absolute charge and mass) + int charge = 1; + float mothMass = o2::constants::physics::MassSigmaMinus; + float chargedDauMass = o2::constants::physics::MassPiMinus; + float neutDauMass = o2::constants::physics::MassNeutron; + + void init(InitContext const&) + { + if (hypoMoth == kSigmaMinus) { + charge = 1; + mothMass = o2::constants::physics::MassSigmaMinus; + chargedDauMass = o2::constants::physics::MassPiMinus; + neutDauMass = o2::constants::physics::MassNeutron; + } else if (hypoMoth == kHypertriton) { + charge = 1; + mothMass = o2::constants::physics::MassHyperTriton; + chargedDauMass = o2::constants::physics::MassTriton; + neutDauMass = o2::constants::physics::MassPi0; + } else if (hypoMoth == kHyperhelium4sigma) { + charge = 2; + mothMass = o2::constants::physics::MassHyperHelium4; + chargedDauMass = o2::constants::physics::MassAlpha; + neutDauMass = o2::constants::physics::MassPi0; + } + + // dummy values, 1 for mother, 0 for daughter + svCreator.setPDGs(1, 0); + + mRunNumber = 0; + mBz = 0; + + ccdb->setURL(ccdbPath); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + + 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 kinkAngleAxis{100, 0, 180, "#theta_{kink} (deg)"}; + const AxisSpec dedxAxis{dedxBins, "d#it{E}/d#it{x}"}; + + AxisSpec massAxis(100, 1.1, 1.4, "m (GeV/#it{c}^{2})"); + if (hypoMoth == kSigmaMinus) { + massAxis = AxisSpec{100, 1.1, 1.4, "m (GeV/#it{c}^{2})"}; + } else if (hypoMoth == kHypertriton) { + massAxis = AxisSpec{100, 2.94, 3.2, "m (GeV/#it{c}^{2})"}; + } else if (hypoMoth == kHyperhelium4sigma) { + massAxis = AxisSpec{100, 3.85, 4.25, "m (GeV/#it{c}^{2})"}; + } + + 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}); + h2MothMassPt = qaRegistry.add("h2MothMassPt", "; p_{T} (GeV/#it{c}); m (GeV/#it{c}^{2})", HistType::kTH2F, {ptAxis, massAxis}); + 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}); + + for (int i = 0; i < 5; i++) { + mBBparamsDaug[i] = cfgBetheBlochParams->get("Daughter", Form("p%i", i)); + } + mBBparamsDaug[5] = cfgBetheBlochParams->get("Daughter", "resolution"); + } + + 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::BCs const& bcs) + { + svCreator.clearPools(); + svCreator.fillBC2Coll(collisions, bcs); + + for (const 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 (const 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::track::TrackParCov trackParCovMothPV{trackParCovMoth}; + o2::base::Propagator::Instance()->PropagateToXBxByBz(trackParCovMoth, LayerRadii[trackMoth.itsNCls() - 1]); + + std::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 + std::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; + } + + if (updateMothTrackUsePV) { + // update the mother track parameters using the primary vertex + trackParCovMoth = trackParCovMothPV; + if (!trackParCovMoth.update(primaryVertex)) { + 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 (doSVRadiusCut && 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 (doSVRadiusCut && lastLayerMoth >= firstLayerDaug) { + continue; + } + + if (doSVRadiusCut && 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); + for (int i = 0; i < 3; i++) { + kinkCand.momMoth[i] *= charge; + kinkCand.momDaug[i] *= charge; + } + float pMoth = propMothTrack.getP() * charge; + float pDaug = propDaugTrack.getP() * charge; + 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 chargedDauE = std::sqrt(pDaug * pDaug + chargedDauMass * chargedDauMass); + float neutE = std::sqrt(neutDauMom[0] * neutDauMom[0] + neutDauMom[1] * neutDauMom[1] + neutDauMom[2] * neutDauMom[2] + neutDauMass * neutDauMass); + float invMass = std::sqrt((chargedDauE + neutE) * (chargedDauE + neutE) - (pMoth * pMoth)); + + h2DeDxDaugSel->Fill(trackDaug.tpcInnerParam() * trackDaug.sign(), trackDaug.tpcSignal()); + h2KinkAnglePt->Fill(trackMoth.pt() * charge * trackMoth.sign(), kinkCand.kinkAngle * radToDeg); + h2MothMassPt->Fill(trackMoth.pt() * charge * trackMoth.sign(), invMass); + h2ClsMapPtMoth->Fill(trackMoth.pt() * charge * trackMoth.sign(), trackMoth.itsClusterMap()); + h2ClsMapPtDaug->Fill(trackDaug.pt() * charge * 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::BCs::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + LOG(info) << "Initializing CCDB for run " << mRunNumber; + o2::parameters::GRPMagField* grpmag = ccdb->getForRun(grpmagPath, mRunNumber); + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = grpmag->getNominalL3Field(); + fitter.setBz(mBz); + + if (!lut) { + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + int mat{static_cast(cfgMaterialCorrection)}; + fitter.setMatCorrType(static_cast(mat)); + } + 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::BCs 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 (const auto& kinkCand : kinkCandidates) { + if (fillDebugTable) { + outputDataTableUB(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); + } else { + 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/Common/lfTPCPID.cxx b/PWGLF/TableProducer/Common/lfTPCPID.cxx index e812633a604..5cdae2c8935 100644 --- a/PWGLF/TableProducer/Common/lfTPCPID.cxx +++ b/PWGLF/TableProducer/Common/lfTPCPID.cxx @@ -694,8 +694,8 @@ struct lfTpcPid { bb = BetheBlochNeg##Particle(trk); \ expSigma = BetheBlochResNeg##Particle(trk, bb); \ } \ - aod::pidutils::packInTable((trk.tpcSignal() - bb) / expSigma, \ - tablePID##Particle); \ + aod::pidtpc_tiny::binning::packInTable((trk.tpcSignal() - bb) / expSigma, \ + tablePID##Particle); \ } \ } \ } \ diff --git a/PWGLF/TableProducer/Common/mcCentrality.cxx b/PWGLF/TableProducer/Common/mcCentrality.cxx index 690d049af4d..1dec9b7fb28 100644 --- a/PWGLF/TableProducer/Common/mcCentrality.cxx +++ b/PWGLF/TableProducer/Common/mcCentrality.cxx @@ -17,30 +17,35 @@ /// \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 "TableHelper.h" + #include "PWGLF/Utils/inelGt.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::track; /// Task to produce the response table -struct mcCentrality { +struct McCentrality { // Tables to produce Produces centFV0A; @@ -52,27 +57,30 @@ struct mcCentrality { // 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 ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbTimestamp{"ccdbTimestamp", -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"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {1000, 0, 5000}, "Binning of the multiplicity axis"}; + Configurable fillFt0A{"fillFt0A", false, "Fills the FT0A histogram"}; + Configurable fillFt0C{"fillFt0C", false, "Fills the FT0C histogram"}; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; TH1F* h1dFT0M; - /*TH1F* h1dFT0A; + TH1F* h1dFT0A; TH1F* h1dFT0C; - TH1F* h1dFDD; - TH1F* h1dNTP;*/ + // TH1F* h1dFDD; + // TH1F* h1dNTP; o2::pwglf::ParticleCounter mCounter; void init(o2::framework::InitContext& /*initContext*/) { // Set up the CCDB - ccdb->setURL(url.value); + ccdb->setURL(ccdbUrl.value); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); @@ -81,7 +89,15 @@ struct mcCentrality { 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."}}); + histos.add("FT0M/percentilevsMult", "FT0M percentile.", HistType::kTH2D, {{binsPercentile, "FT0M percentile"}, {binsMultiplicity, "FT0M mult."}}); + if (fillFt0A) { + histos.add("FT0A/percentile", "FT0A percentile.", HistType::kTH1D, {{binsPercentile, "FT0A percentile"}}); + histos.add("FT0A/percentilevsMult", "FT0A percentile.", HistType::kTH2D, {{binsPercentile, "FT0A percentile"}, {binsMultiplicity, "FT0A mult."}}); + } + if (fillFt0C) { + histos.add("FT0C/percentile", "FT0C percentile.", HistType::kTH1D, {{binsPercentile, "FT0C percentile"}}); + histos.add("FT0C/percentilevsMult", "FT0C percentile.", HistType::kTH2D, {{binsPercentile, "FT0C percentile"}, {binsMultiplicity, "FT0C mult."}}); + } TList* lOfInput; if (path.value.rfind("ccdb://", 0) == 0) { // Getting post calib. from CCDB @@ -105,11 +121,20 @@ struct mcCentrality { 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; + auto getHist = [lOfInput](const char* name) -> TH1F* { + auto hist = static_cast(lOfInput->FindObject(name)); + if (!hist) { + lOfInput->ls(); + LOG(fatal) << "Could not open histogram " << name << " from TList"; + } + return hist; + }; + h1dFT0M = getHist("h1dFT0M"); + if (fillFt0A) { + h1dFT0A = getHist("h1dFT0A"); + } + if (fillFt0C) { + h1dFT0C = getHist("h1dFT0C"); } } @@ -117,23 +142,27 @@ struct mcCentrality { 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 nFT0A = mCounter.countFT0A(mcParticles); const float nFT0C = mCounter.countFT0C(mcParticles); - const float nFV0A = mCounter.countFV0A(mcParticles);*/ + const float nFT0M = nFT0A + nFT0C; + // 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));*/ + if (fillFt0A) { + const float valueCentFT0A = h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFT0A)); + centFT0A(valueCentFT0A); + } + if (fillFt0C) { + const float valueCentFT0C = h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFT0C)); + centFT0C(valueCentFT0C); + } + // const float valueCentFV0A = h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFV0A)); centFT0M(valueCentFT0M); - /*centFT0A(valueCentFT0A); - centFT0C(valueCentFT0C); - centFV0A(valueCentFV0A);*/ + // centFV0A(valueCentFV0A); histos.fill(HIST("FT0M/percentile"), valueCentFT0M); histos.fill(HIST("FT0M/percentilevsMult"), valueCentFT0M, nFT0M); } }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } +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..5689a5e13ef --- /dev/null +++ b/PWGLF/TableProducer/Common/spvector.cxx @@ -0,0 +1,774 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 + +#include "PWGLF/DataModel/SPCalibrationTables.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; +using namespace o2::constants::physics; +using namespace o2::aod::rctsel; + +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 additionalEvSel{"additionalEvSel", false, "additionalEvSel"}; + Configurable usemem{"usemem", true, "usemem"}; + + struct : ConfigurableGroup { + 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"}; + } configbins; + + 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 fine6{"fine6", false, "REfine6"}; + 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 ConfRecenterecentSp6{"ConfRecenterecentSp6", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for cent recentere6"}; + Configurable ConfRecenterevxSp6{"ConfRecenterevxSp6", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vx recentere6"}; + Configurable ConfRecenterevySp6{"ConfRecenterevySp6", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vy recentere6"}; + Configurable ConfRecenterevzSp6{"ConfRecenterevzSp6", "Users/p/prottay/My/Object/Testingwithsparse/NewPbPbpass4_17092024/recenter", "Sparse or THn Path for vz recentere6"}; + 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; + } + */ + + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", true, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + + RCTFlagsChecker rctChecker; + + void init(o2::framework::InitContext&) + { + + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + AxisSpec channelZDCAxis = {8, 0.0, 8.0, "ZDC tower"}; + AxisSpec qxZDCAxis = {configbins.QxyNbins, configbins.lbinQxy, configbins.hbinQxy, "Qx"}; + AxisSpec phiAxis = {configbins.PhiNbins, -6.28, 6.28, "phi"}; + AxisSpec vzAxis = {configbins.VzNbins, configbins.lbinVz, configbins.hbinVz, "vz"}; + AxisSpec vxAxis = {configbins.VxNbins, configbins.lbinVx, configbins.hbinVx, "vx"}; + AxisSpec vyAxis = {configbins.VyNbins, configbins.lbinVy, configbins.hbinVy, "vy"}; + AxisSpec centAxis = {configbins.CentNbins, configbins.lbinCent, configbins.hbinCent, "V0M (%)"}; + AxisSpec vzfineAxis = {configbins.VzfineNbins, configbins.lfinebinVz, configbins.hfinebinVz, "vzfine"}; + AxisSpec vxfineAxis = {configbins.VxfineNbins, configbins.lfinebinVx, configbins.hfinebinVx, "vxfine"}; + AxisSpec vyfineAxis = {configbins.VyfineNbins, configbins.lfinebinVy, configbins.hfinebinVy, "vyfine"}; + AxisSpec centfineAxis = {configbins.CentfineNbins, configbins.lfinebinCent, configbins.hfinebinCent, "V0M (%) fine"}; + AxisSpec shiftAxis = {10, 0, 10, "shift"}; + AxisSpec basisAxis = {2, 0, 2, "basis"}; + AxisSpec VxyAxis = {2, 0, 2, "Vxy"}; + + histos.add("htpcnsigmapi", "htpcnsigmapi", kTH1F, {{50, -10, 10.0}}); + histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{10, 0, 10.0}}); + 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 + 0.00001); // Centrality + binCoords[1] = vxAxis->FindBin(vx + 0.00001); // vx + binCoords[2] = vyAxis->FindBin(vy + 0.00001); // vy + binCoords[3] = vzAxis->FindBin(vz + 0.00001); // 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.00001, 0.5)); + double meanyAcent = hrecenterecentSp->GetBinContent(hrecenterecentSp->FindBin(centrality + 0.00001, 1.5)); + double meanxCcent = hrecenterecentSp->GetBinContent(hrecenterecentSp->FindBin(centrality + 0.00001, 2.5)); + double meanyCcent = hrecenterecentSp->GetBinContent(hrecenterecentSp->FindBin(centrality + 0.00001, 3.5)); + + double meanxAvx = hrecenterevxSp->GetBinContent(hrecenterevxSp->FindBin(vx + 0.00001, 0.5)); + double meanyAvx = hrecenterevxSp->GetBinContent(hrecenterevxSp->FindBin(vx + 0.00001, 1.5)); + double meanxCvx = hrecenterevxSp->GetBinContent(hrecenterevxSp->FindBin(vx + 0.00001, 2.5)); + double meanyCvx = hrecenterevxSp->GetBinContent(hrecenterevxSp->FindBin(vx + 0.00001, 3.5)); + + double meanxAvy = hrecenterevySp->GetBinContent(hrecenterevySp->FindBin(vy + 0.00001, 0.5)); + double meanyAvy = hrecenterevySp->GetBinContent(hrecenterevySp->FindBin(vy + 0.00001, 1.5)); + double meanxCvy = hrecenterevySp->GetBinContent(hrecenterevySp->FindBin(vy + 0.00001, 2.5)); + double meanyCvy = hrecenterevySp->GetBinContent(hrecenterevySp->FindBin(vy + 0.00001, 3.5)); + + double meanxAvz = hrecenterevzSp->GetBinContent(hrecenterevzSp->FindBin(vz + 0.00001, 0.5)); + double meanyAvz = hrecenterevzSp->GetBinContent(hrecenterevzSp->FindBin(vz + 0.00001, 1.5)); + double meanxCvz = hrecenterevzSp->GetBinContent(hrecenterevzSp->FindBin(vz + 0.00001, 2.5)); + double meanyCvz = hrecenterevzSp->GetBinContent(hrecenterevzSp->FindBin(vz + 0.00001, 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; + using AllTrackCandidates = 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&, AllTrackCandidates const& tracks) + { + + if (usemem) { + for (const auto& track : tracks) { + histos.fill(HIST("htpcnsigmapi"), track.tpcNSigmaPi()); + } + } + + histos.fill(HIST("hEvtSelInfo"), 0.5); + 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; + } + + histos.fill(HIST("hEvtSelInfo"), 1.5); + + 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; + } + + histos.fill(HIST("hEvtSelInfo"), 2.5); + + 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; + } + histos.fill(HIST("hEvtSelInfo"), 3.5); + + 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; + } + + histos.fill(HIST("hEvtSelInfo"), 4.5); + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + 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("hEvtSelInfo"), 5.5); + + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + 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("hEvtSelInfo"), 6.5); + + 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()); + } + + histos.fill(HIST("hEvtSelInfo"), 7.5); + + 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 + 0.00001, 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("hEvtSelInfo"), 8.5); + 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; + Int_t check = 1; + + 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 (fine6) { + if (useRecenterefineSp && (currentRunNumber != lastRunNumber)) { + hrecenterecentSpA[5] = ccdb->getForTimeStamp(ConfRecenterecentSp6.value, bc.timestamp()); + hrecenterevxSpA[5] = ccdb->getForTimeStamp(ConfRecenterevxSp6.value, bc.timestamp()); + hrecenterevySpA[5] = ccdb->getForTimeStamp(ConfRecenterevySp6.value, bc.timestamp()); + hrecenterevzSpA[5] = ccdb->getForTimeStamp(ConfRecenterevzSp6.value, bc.timestamp()); + } + resfine = Correctfine(hrecenterecentSpA[5], hrecenterevxSpA[5], hrecenterevySpA[5], hrecenterevzSpA[5], centrality, vx, vy, vz, qxZDCA, qyZDCA, qxZDCC, qyZDCC); + } + + if (res == 0 && resfine == 0 && check == 0) { + LOG(info) << "Histograms are null"; + } + 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/Common/zdcSP.cxx b/PWGLF/TableProducer/Common/zdcSP.cxx index 783526e1400..211d0bf7316 100644 --- a/PWGLF/TableProducer/Common/zdcSP.cxx +++ b/PWGLF/TableProducer/Common/zdcSP.cxx @@ -12,42 +12,37 @@ // Minimal example to run this task: // o2-analysis-centrality-table -b --configuration json://configuration.json | o2-analysis-timestamp -b --configuration json://configuration.json | o2-analysis-event-selection -b --configuration json://configuration.json | o2-analysis-multiplicity-table -b --configuration json://configuration.json | o2-analysis-lf-zdcsp -b --configuration json://configuration.json --aod-file @input_data.txt --aod-writer-json OutputDirector.json -#include -#include - -#include "Math/Vector4D.h" - -#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/DataModel/LFzdcSPtables.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/EventPlaneHelper.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.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 "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/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - -#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGLF/DataModel/LFzdcSPtables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include -#include "TRandom3.h" +#include +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/TableProducer/Nuspex/CMakeLists.txt b/PWGLF/TableProducer/Nuspex/CMakeLists.txt index 4c06534b713..d8aab98b59b 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 KFParticle::KFParticle O2Physics::AnalysisCore O2::TOFBase + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2::TOFBase O2::DetectorsVertexing O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hyhefour-builder @@ -19,11 +19,6 @@ 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 O2Physics::EventFilteringUtils @@ -34,19 +29,14 @@ o2physics_add_dpl_workflow(lnn-reco-task PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(hypertriton3bodyfinder - SOURCES hypertriton3bodyfinder.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - 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 @@ -64,11 +54,6 @@ o2physics_add_dpl_workflow(threebodymcfinder PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(threebody-reco-task - SOURCES threebodyRecoTask.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(ebye-maker SOURCES ebyeMaker.cxx PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore @@ -78,3 +63,53 @@ 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(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 O2::TOFBase O2Physics::EventFilteringUtils + 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) + +o2physics_add_dpl_workflow(hyperkink-reco-task + SOURCES hyperkinkRecoTask.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFBase + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(he3-lambda-analysis + SOURCES he3LambdaAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(nuclei-antineutron-cex + SOURCES nucleiAntineutronCex.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(particle-composition-correction + SOURCES particleCompositionCorrection.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx b/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx index c87f8845e57..6dd3954f43f 100644 --- a/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx +++ b/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx @@ -14,52 +14,57 @@ // // Author: Giorgio Alberto Lucia -#include -#include -#include -#include -#include -#include -#include +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGLF/DataModel/LFClusterStudiesTable.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#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/PID/PIDTOF.h" +#include "Common/Core/PID/TPCPIDResponse.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.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/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/TableProducer/PID/pidTOFBase.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "Common/DataModel/PIDResponse.h" -#include "DCAFitter/DCAFitterN.h" -#include "PWGLF/DataModel/LFClusterStudiesTable.h" +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" #include "TDatabasePDG.h" #include "TPDGCode.h" +#include +#include +#include +#include +#include +#include +#include +#include + 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 TracksFullIU = soa::Join; +using TracksFullIUMc = soa::Join; + using CollisionsCustom = soa::Join; +using CollisionsCustomMc = soa::Join; namespace BetheBloch { @@ -73,7 +78,7 @@ enum V0Type : uint8_t { K0s = 0, Lambda, AntiLambda, - Photon, + Photon, // deprecated, electrons are now selected from pi0 photons V0TypeAll }; @@ -92,39 +97,35 @@ enum Selections { enum V0Selections { kV0NoCut = 0, kV0DaughterQuality, - kV0DaughterDCA, - // kV0DCA, - kV0Radius, - kV0CosPA, + kV0Topology, kV0PID, - kV0DaughterDCAtoPV, kV0All }; enum CascSelections { kCascNoCut = 0, - kCascDCA, - kCascCosPA, - kAcceptedOmega, + kCascTopology, kRejectedXi, + kAcceptedOmega, kNSigmaTPC, kCascAll }; -enum DeSelections { - kDeNoCut = 0, - kDeNClsIts, - kDePIDtpc, - kDePIDtof, - kDeAll +enum NucleiSelections { + kNucleiNoCut = 0, + kNucleiNClsIts, + kNucleiPIDtpc, + kNucleiPIDtof, + kNucleiAll }; -enum He3Selections { - kHe3NoCut = 0, - kHe3NClsIts, - kHe3PIDtpc, - kHe3PIDtof, - kHe3All +enum ESelections { + kENoCut = 0, + kETrackQuality, + kEPrimary, + kEPid, + kEPi0, + kEAll }; enum PartID { @@ -134,87 +135,40 @@ enum PartID { ka, pr, de, - he -}; - -struct CandidateV0 { - float p_pos = -999.f; - float eta_pos = -999.f; - float phi_pos = -999.f; - uint32_t itsClsize_pos = 0xFFFFF; - uint8_t partID_pos = 0; - float pTPC_pos = -999.f; // extra - uint32_t pidInTrk_pos = 0; // extra - int partIDMc_pos = 0; // mc - - float p_neg = -999.f; - float eta_neg = -999.f; - float phi_neg = -999.f; - uint32_t itsClsize_neg = 0xFFFFF; - uint8_t partID_neg = 0; - float pTPC_neg = -999.f; // extra - uint32_t pidInTrk_neg = 0; // extra - int partIDMc_neg = 0; // mc - - float cosPA = -999.f; // extra - float massV0 = -999.f; // extra + he, + all }; -struct CandidateK { - float p_K = -999.f; - float eta_K = -999.f; - float phi_K = -999.f; - uint32_t itsClsize_K = 0xFFFFF; - uint8_t partID_K = 0; - float pTPC_K = -999.f; // extra - uint32_t pidInTrk_K = 0; // extra - float tpcNSigma_K = -999.f; // extra - int partIDMc_K = 0; // mc - - float cosPA = -999.f; // extra - float massOmega = -999.f; // extra -}; - -struct candidateDe { - float p_de = -999.f; - float eta_de = -999.f; - float phi_de = -999.f; - uint32_t itsClsize_de = 0xFFFFF; - uint8_t partID_de = 0; - float pTPC_de = -999.f; // extra - uint32_t pidInTrk_de = 0; // extra - float tpcNSigma_de = -999.f; // extra - float tofNSigma_de = -999.f; // extra - int partIDMc_de = 0; // mc -}; - -struct candidateHe { - float p_he = -999.f; - float eta_he = -999.f; - float phi_he = -999.f; - uint32_t itsClsize_he = 0xFFFFF; - uint8_t partID_he = 0; - float pTPC_he = -999.f; // extra - uint32_t pidInTrk_he = 0; // extra - float tpcNSigma_he = -999.f; // extra - float tofNSigma_he = -999.f; // extra - float massTOF_he = -999.f; // extra - int partIDMc_he = 0; // mc +static constexpr std::string_view cNames[] = {"none", "electron", "pion", "kaon", "proton", "deuteron", "He3"}; + +struct Candidate { + float p = -999.f; // momentum * charge + float eta = -999.f; + float phi = -999.f; + uint32_t itsClusterSize = 0; + uint8_t partID = PartID::none; + float pTPC = -999.f; + uint32_t pidInTrk = 0; // PID in tracking + float nsigmaTPC = -999.f; + float nsigmaTOF = -999.f; + float tofMass = -999.f; + float cosPAMother = -999.f; // Cosine of the pointing angle of the mother + float massMother = -999.f; // Invariant mass of the mother + int pdgCode = 0; }; struct LfTreeCreatorClusterStudies { Service m_ccdb; + SliceCache m_cache; 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_smallTable{"smallTable", true, "Use a small table for testing"}; + Configurable setting_fillExtraTable{"fillExtraTable", false, "Fill the extra table"}; + Configurable setting_fillCollTable{"fillCollTable", false, "Fill the collision table"}; Configurable setting_materialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; @@ -223,32 +177,51 @@ struct LfTreeCreatorClusterStudies { Configurable setting_downscaleFactor{"downscaleFactor", 1.f, "Downscale factor for the V0 candidates"}; Configurable setting_applyAdditionalEvSel{"applyAdditionalEvSel", false, "Apply additional event selection"}; - Configurable v0track_nClsItsMin{"v0track_NclsItsMin", 0.f, "Minimum number of ITS clusters for the V0 daughters"}; - Configurable v0track_nClsTpcMin{"v0track_NclsTpcMin", 100.f, "Minimum number of TPC clusters for the V0 daughters"}; - Configurable v0track_nClsTpcMaxShared{"v0track_NclsTpcMaxShared", 5.f, "Maximum number of shared TPC clusters for the V0 daughters"}; + 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 track_etaMax{"etaMax", 0.8f, "Maximum eta"}; + Configurable track_tpcChi2Min{"track_tpcChi2Min", 0.5f, "Minimum TPC chi2 per cluster"}; // 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_dcaV0daughters{"v0setting_dcaV0daughters", 1.f, "DCA between the V0 daughters"}; + Configurable v0setting_dcaMinV0DaughterToPv{"v0setting_dcaMinV0DaughterToPv", 0.06f, "DCA of the daughters to the primary vertex"}; + Configurable v0setting_radiusV0{"v0setting_radiusV0", 0.5f, "Maximum radius of the V0 accepted"}; + Configurable v0setting_cosPA{"v0setting_cosPA", 0.98f, "Cosine of the pointing angle of the V0"}; 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 cascsetting_dcaMinV0DaughterToPv{"cascsetting_dcaMinV0DaughterToPv", 0.03f, "DCA of one of the daugthers of Lambda to pv"}; + Configurable cascsetting_dcaMinProtonToPv{"cascsetting_dcaMinProtonToPv", 0.03f, "DCA of the proton coming from Lambda to pv"}; + Configurable cascsetting_dcaMinBachelorToPv{"cascsetting_dcaMinBachelorToPv", 0.04f, "DCA of the bachelor to pv"}; + Configurable cascsetting_dcaMinV0ToPv{"cascsetting_dcaMinV0ToPv", 0.04f, "DCA of the V0 to pv"}; + Configurable cascsetting_dcaV0Daughters{"cascsetting_dcaV0daughters", 0.4f, "DCA between the V0 daughters"}; + Configurable cascsetting_cascCosPA{"cascsetting_cascCosPA", 0.99f, "Minimum cCosine of the pointing angle of the cascade"}; + Configurable cascsetting_v0cosPA{"cascsetting_v0cosPA", 0.97f, "Minimum cCosine of the pointing angle of the v0"}; + Configurable cascsetting_dcaMaxBachelorToV0{"cascsetting_dcaMaxBachelorToV0", 0.8f, "DCA of the bachelor to V0"}; + // Configurable cascsetting_dcaMinBachelorToProton{"cascsetting_dcaMinBachelorToProton", 0.015f, "DCA of the bachelor to proton"}; + Configurable cascsetting_radiusV0{"cascsetting_radiusV0", 1.2f, "Minimum radius of the V0 accepted"}; + Configurable cascsetting_radiusCasc{"cascsetting_radiusCasc", 0.5f, "Minimum radius of the cascade accepted"}; + + Configurable cascsetting_massWindowOmega{"cascsetting_massWindowOmega", 0.01f, "Mass window for the Omega"}; + Configurable cascsetting_massWindowXi{"cascsetting_massWindowXi", 0.01f, "Mass window for the Xi"}; + Configurable cascsetting_nsigmatpc{"cascsetting_nsigmaTPC", 3.f, "Number of sigmas for the TPC PID"}; + + Configurable electronsetting_conversion_rmin{"electron_conversion_rmin", 1.76f, "Minimum radius for the photon conversion (cm)"}; + Configurable electronsetting_conversion_rmax{"electron_conversion_rmax", 19.77f, "Maximum radius for the photon conversion (cm)"}; + Configurable electronsetting_maxDcaxy{"electronsetting_maxDcaxy", 0.1f, "Maximum value for the DCAxy"}; + Configurable electronsetting_maxDcaz{"electronsetting_maxDcaz", 0.5f, "Maximum value for the DCAz"}; + Configurable electronsetting_minNsigmatpcEl{"electronsetting_minNsigmaTPCEl", -2.5f, "Minimum value for the number of sigmas for the TPC PID for electrons"}; + Configurable electronsetting_maxNsigmatpcEl{"electronsetting_maxNsigmaTPCEl", 3.5f, "Maximum number for the number of sigmas for the TPC PID for electrons"}; + Configurable electronsetting_maxNsigmatpcPi{"electronsetting_maxNsigmaTPCPi", 2.f, "Maximum number for the number of sigmas for pi rejection for the TPC PID for electrons"}; + Configurable electronsetting_maxNsigmatpcKa{"electronsetting_maxNsigmaTPCKa", 2.f, "Maximum number for the number of sigmas for K rejection for the TPC PID for electrons"}; + Configurable electronsetting_maxNsigmatpcPr{"electronsetting_maxNsigmaTPCPr", 2.f, "Maximum number for the number of sigmas for p rejection for the TPC PID for electrons"}; + Configurable electronsetting_maxNsigmatofEl{"electronsetting_maxNsigmaTOFEl", 4.f, "Minimum value for the number of sigmas for the TPC PID for electrons"}; + Configurable electronsetting_minPt{"electronsetting_minPt", 0.f, "Minimum pT accepted for electrons"}; 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"}; @@ -270,141 +243,48 @@ struct LfTreeCreatorClusterStudies { 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}}}}, - {"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}}}}}, + { + {"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}}}}, + {"e_selections", "e^{#pm} selection; selection; counts", {HistType::kTH1F, {{ESelections::kEAll, -0.5, static_cast(ESelections::kEAll) - 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}_{T} (GeV/#it{c}); #it{m}_{#Lambda} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {200, 1.08f, 1.18f}}}}, + {"massLambdaMc", "#Lambda invariant mass (MC); signed #it{p}_{T} (GeV/#it{c}); #it{m}_{#Lambda} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {200, 1.08f, 1.18f}}}}, + {"Lambda_vs_K0s", "Mass #Lambda vs K^{0}_s; #it{m}_{K^{0}_{s}} (GeV/#it{c}^{2}); #it{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; #it{q}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1.f, 1.f}, {100, 0.f, 0.3f}}}}, + {"armenteros_plot", "Armenteros-Podolanski plot; #alpha; #it{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; #it{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; #it{q}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, -1.f, 1.f}, {100, 0.f, 0.3f}}}}, + {"photon_radiusV0", "Photon conversion radius (xy) V0; #it{r} (cm); counts", {HistType::kTH1F, {{100, 0., 100.}}}}, + {"photon_conversion_position", "Photon conversion position; #it{x} (cm); #it{y} (cm)", {HistType::kTH2F, {{250, -5.f, 5.f}, {250, -5.f, 5.f}}}}, + {"photon_conversion_position_layer", "Photon conversion position (ITS layers); #it{x} (cm); #it{y} (cm)", {HistType::kTH2F, {{100, -5.f, 5.f}, {100, -5.f, 5.f}}}}, + {"casc_dca_daughter_pairs", "DCA (xy) for cascade daughter pairs; DCA_{#it{xy}} (cm); counts", {HistType::kTH1F, {{100, -0.1, 0.1}}}}, + {"Xi_vs_Omega", "Mass Xi vs Omega; mass Omega (GeV/#it{c}^{2}); #it{m}_#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}); #it{m}_{#Omega} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {400, 1.62f, 1.72f}}}}, + {"massOmegaMc", "Mass #Omega (MC); signed #it{p}_{T} (GeV/#it{c}); #it{m}_{#Omega} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {400, 1.62f, 1.72f}}}}, + {"massPi0", "Mass #pi^{0}; #it{m}_{#pi^{0}} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"massPi0Mc", "Mass #pi^{0} (MC); #it{m}_{#pi^{0}} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"massPi0WithBkg", "Mass #pi^{0} with Background; #it{m}_{#pi^{0}} (GeV/#it{c}^{2}); counts", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"zVtx", "Binning for the vertex z in cm; #it{z}_{vertex} (cm)", {HistType::kTH1F, {{100, -20.f, 20.f}}}}, + {"isPositive", "is the candidate positive?; isPositive; counts", {HistType::kTH1F, {{2, -0.5f, 1.5f}}}}, + + {"electron/DCAxyBeforeSelection", "DCA (xy) for cascade daughter pairs; DCA_{#it{xy}} (cm); counts", {HistType::kTH1F, {{100, -0.1, 0.1}}}}, + {"electron/DCAzBeforeSelection", "DCA (z) for cascade daughter pairs; DCA_{#it{z}} (cm); counts", {HistType::kTH1F, {{200, -0.2, 0.2}}}}, + }, OutputObjHandlingPolicy::AnalysisObject, - false, - true}; // check histograms + false}; Produces m_ClusterStudiesTable; Produces m_ClusterStudiesTableExtra; + Produces m_ClusterStudiesTableCollision; Produces m_ClusterStudiesTableMc; - Produces m_ClusterStudiesTableMcExtra; - - struct V0TrackParCov { - int64_t globalIndex; - Track trackParCov; - }; - std::vector m_v0TrackParCovs; - - o2::vertexing::DCAFitterN<2> m_fitter; - o2::pid::tof::Beta m_responseBeta; - o2::pid::tof::Beta m_responseBetaMc; - - 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; - } + o2::aod::ITSResponse m_responseITS; - 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) + template + bool collisionSelection(const Tcollision& collision) { m_hAnalysis.fill(HIST("collision_selections"), Selections::kNoCut); if (!collision.sel8()) { @@ -426,103 +306,326 @@ struct LfTreeCreatorClusterStudies { /** * Select the V0 daughters based on the quality cuts */ - template - bool qualitySelectionV0Daughter(const T& track) + template + bool qualityTrackSelection(const Track& track) { - if (std::abs(track.eta()) > v0setting_etaMaxV0dau) { - return false; - } - if (track.itsNCls() < v0track_nClsItsMin || - track.tpcNClsFound() < v0track_nClsTpcMin || - track.tpcNClsCrossedRows() < v0track_nClsTpcMin || + if (std::abs(track.eta()) > track_etaMax || + track.itsNCls() < track_nClsItsMin || + track.tpcNClsFound() < track_nClsTpcMin || + track.tpcNClsCrossedRows() < track_nClsTpcMin || track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || - track.tpcNClsShared() > v0track_nClsTpcMaxShared) { + track.tpcNClsShared() > track_nClsTpcMaxShared || + track.tpcChi2NCl() < track_tpcChi2Min || + track.tpcChi2NCl() > 4.0f) { return false; } return true; } - bool qualitySelectionV0(const double /*dcaV0toPV*/, const double dcaV0daughters, const double radiusV0, const double cosPA) + bool qualitySelectionV0(aod::V0Datas::iterator const& v0) { - if (std::abs(dcaV0daughters) > v0setting_dcaV0daughters) { + if (std::abs(v0.dcapostopv()) < v0setting_dcaMinV0DaughterToPv) return false; - } - m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0DaughterDCA); - if (radiusV0 > v0setting_radiusMax || radiusV0 < v0setting_radiusMin) { + if (std::abs(v0.dcanegtopv()) < v0setting_dcaMinV0DaughterToPv) return false; - } - m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0Radius); - if (std::abs(cosPA) < v0setting_cosPA) { + if (std::abs(v0.dcaV0daughters()) > v0setting_dcaV0daughters) return false; - } - m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0CosPA); + if (v0.v0radius() < v0setting_radiusV0) + return false; + if (std::abs(v0.v0cosPA()) < v0setting_cosPA) + return false; + return true; } - bool qualitySelectionCascade(const double dcaCascDaughters, const double cosPA) + bool qualitySelectionCascade(aod::CascDatas::iterator const& cascade, const std::array& pv) { - if (std::abs(dcaCascDaughters) > cascsetting_dcaCascDaughters) { + if (std::abs(cascade.dcapostopv()) < cascsetting_dcaMinV0DaughterToPv) return false; - } - m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kCascDCA); - if (std::abs(cosPA) < cascsetting_cosPA) { + if (std::abs(cascade.dcanegtopv()) < cascsetting_dcaMinV0DaughterToPv) return false; - } - m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kCascCosPA); + if (std::abs(cascade.dcabachtopv()) < cascsetting_dcaMinBachelorToPv) + return false; + if (std::abs(cascade.dcav0topv(pv[0], pv[1], pv[2])) < cascsetting_dcaMinV0ToPv) + return false; + if (std::abs(cascade.dcaV0daughters()) > cascsetting_dcaV0Daughters) + return false; + if (std::abs(cascade.casccosPA(pv[0], pv[1], pv[2])) < cascsetting_cascCosPA) + return false; + if (std::abs(cascade.v0cosPA(pv[0], pv[1], pv[2])) < cascsetting_v0cosPA) + return false; + if (std::abs(cascade.v0radius()) < cascsetting_radiusV0) + return false; + if (std::abs(cascade.cascradius()) < cascsetting_radiusCasc) + return false; + + m_hAnalysis.fill(HIST("casc_dca_daughter_pairs"), cascade.dcacascdaughters()); + if (std::abs(cascade.dcacascdaughters()) > cascsetting_dcaMaxBachelorToV0) + return false; + return true; } - // ========================================================================================================= + uint8_t selectV0MotherHypothesis(aod::V0Datas::iterator const& v0) + { + uint8_t v0Bitmask(0); + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0setting_massWindowK0s) { + SETBIT(v0Bitmask, K0s); + } + if ((std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0setting_massWindowLambda) && (v0.alpha() > 0)) { + SETBIT(v0Bitmask, Lambda); + } + if ((std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < v0setting_massWindowLambda) && (v0.alpha() < 0)) { + SETBIT(v0Bitmask, AntiLambda); + } + return v0Bitmask; + } - template - bool nucleiTrackSelection(const T& track) + template + bool selectPidV0Daughters(Candidate& candidatePos, Candidate& candidateNeg, + aod::V0Datas::iterator const& v0, const Track& posTrack, const Track& negTrack, uint8_t v0Bitmask) { - if (track.tpcNClsFound() < 90) { + if (TESTBIT(v0Bitmask, Lambda)) { + if (v0.qtarm() < lambdasetting_qtAPcut) + return false; + if (std::abs(posTrack.tpcNSigmaPr()) > v0setting_nsigmatpcPr || std::abs(negTrack.tpcNSigmaPi()) > v0setting_nsigmatpcPi) + return false; + if (v0.p() < lambdasetting_pmin) + return false; + candidatePos.partID = PartID::pr; + candidateNeg.partID = PartID::pi; + candidatePos.nsigmaTPC = posTrack.tpcNSigmaPr(); + candidateNeg.nsigmaTPC = negTrack.tpcNSigmaPi(); + m_hAnalysis.fill(HIST("v0_type"), V0Type::Lambda); + + } else if (TESTBIT(v0Bitmask, AntiLambda)) { + if (v0.qtarm() < lambdasetting_qtAPcut) + return false; + if (std::abs(posTrack.tpcNSigmaPi()) > v0setting_nsigmatpcPi || std::abs(negTrack.tpcNSigmaPr()) > v0setting_nsigmatpcPr) + return false; + if (v0.p() < lambdasetting_pmin) + return false; + candidatePos.partID = PartID::pi; + candidateNeg.partID = PartID::pr; + candidatePos.nsigmaTPC = posTrack.tpcNSigmaPi(); + candidateNeg.nsigmaTPC = negTrack.tpcNSigmaPr(); + m_hAnalysis.fill(HIST("v0_type"), V0Type::AntiLambda); + + } else { return false; } + return true; } - // ========================================================================================================= + /** + * Fill the histograms for the V0 candidate and return the mass of the V0 + */ + template + float fillHistogramsV0(aod::V0Datas::iterator const& v0, const Track& trackPos, const Track& trackNeg, const uint8_t v0Bitmask) + { + float massV0{0.f}; + if (TESTBIT(v0Bitmask, Lambda)) { + massV0 = v0.mLambda(); + m_hAnalysis.fill(HIST("massLambda"), v0.pt(), v0.mLambda()); + fillHistogramsParticle(trackPos); + fillHistogramsParticle(trackNeg); + } else if (TESTBIT(v0Bitmask, AntiLambda)) { + massV0 = v0.mAntiLambda(); + m_hAnalysis.fill(HIST("massLambda"), v0.pt() * -1.f, v0.mAntiLambda()); + fillHistogramsParticle(trackPos); + fillHistogramsParticle(trackNeg); + } + + m_hAnalysis.fill(HIST("radiusV0"), v0.v0radius()); + m_hAnalysis.fill(HIST("armenteros_plot_lambda"), v0.alpha(), v0.qtarm()); + m_hAnalysis.fill(HIST("armenteros_plot"), v0.alpha(), v0.qtarm()); - template - float computeNSigmaDe(const T& candidate) + return massV0; + } + + template + void fillHistogramsParticle(const Track& track) { - 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); + float nsigmaTpc = -999.f; + switch (partID) { + case PartID::el: + nsigmaTpc = track.tpcNSigmaEl(); + break; + case PartID::pi: + nsigmaTpc = track.tpcNSigmaPi(); + break; + case PartID::ka: + nsigmaTpc = track.tpcNSigmaKa(); + break; + case PartID::pr: + nsigmaTpc = track.tpcNSigmaPr(); + break; + case PartID::de: + nsigmaTpc = track.tpcNSigmaDe(); + break; + case PartID::he: + nsigmaTpc = computeNSigmaTPCHe3(track); + break; + default: + nsigmaTpc = -999.f; + break; + } + + float nsigmaTof = -999.f; + switch (partID) { + case PartID::el: + nsigmaTof = track.tofNSigmaEl(); + break; + case PartID::de: + nsigmaTof = track.tofNSigmaDe(); + break; + default: + nsigmaTof = -999.f; + break; + } + + float massTof = -999.f; + if (track.hasTOF()) { + switch (partID) { + case PartID::de: + massTof = computeTOFmassDe(track); + break; + case PartID::he: + massTof = computeTOFmassHe3(track); + break; + default: + massTof = -999.f; + break; + } + } + + float nsigmaIts = -999.f; + switch (partID) { + case PartID::el: + nsigmaIts = m_responseITS.nSigmaITS(track); + break; + case PartID::pi: + nsigmaIts = m_responseITS.nSigmaITS(track); + break; + case PartID::ka: + nsigmaIts = m_responseITS.nSigmaITS(track); + break; + case PartID::pr: + nsigmaIts = m_responseITS.nSigmaITS(track); + break; + case PartID::de: + nsigmaIts = m_responseITS.nSigmaITS(track); + break; + case PartID::he: + nsigmaIts = m_responseITS.nSigmaITS(track); + break; + default: + nsigmaIts = -999.f; + break; + } + + float correctedTpcInnerParam = track.tpcInnerParam(); + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + correctedTpcInnerParam = (partID == PartID::he && he3setting_compensatePIDinTracking && heliumPID) ? track.tpcInnerParam() / 2.f : track.tpcInnerParam(); + + m_hAnalysis.fill(HIST(cNames[partID]) + HIST("/nSigmaTPC"), track.p() * track.sign(), nsigmaTpc); + m_hAnalysis.fill(HIST(cNames[partID]) + HIST("/nSigmaITS"), track.p() * track.sign(), nsigmaIts); + m_hAnalysis.fill(HIST(cNames[partID]) + HIST("/nSigmaTOF"), track.p() * track.sign(), nsigmaTof); + if (partID == static_cast(PartID::de) || partID == static_cast(PartID::he)) + m_hAnalysis.fill(HIST(cNames[partID]) + HIST("/TOFmass"), track.p() * track.sign(), massTof); + m_hAnalysis.fill(HIST(cNames[partID]) + HIST("/pmatching"), correctedTpcInnerParam * track.sign(), (correctedTpcInnerParam - track.p()) / correctedTpcInnerParam); } - template - bool selectionPIDtpcDe(const T& candidate) + template + void fillMcHistogramsV0(aod::V0Datas::iterator const& v0, const McPart& posDaughter, const McPart& negDaughter) { - auto nSigmaDe = computeNSigmaDe(candidate); - if (std::abs(nSigmaDe) < desetting_nsigmatpc) { - return true; + if ((std::abs(posDaughter.pdgCode()) != PDG_t::kProton && std::abs(posDaughter.pdgCode()) != PDG_t::kPiPlus) || + (std::abs(negDaughter.pdgCode()) != PDG_t::kProton && std::abs(negDaughter.pdgCode()) != PDG_t::kPiPlus)) { + return; + } + + int motherPdgCode = 0; + for (const auto& posMother : posDaughter.template mothers_as()) { + for (const auto& negMother : negDaughter.template mothers_as()) { + if (negMother.globalIndex() == posMother.globalIndex()) { + motherPdgCode = posMother.pdgCode(); + } + } + } + + if (motherPdgCode == PDG_t::kLambda0) { + m_hAnalysis.fill(HIST("massLambdaMc"), v0.pt(), v0.mLambda()); + } else if (motherPdgCode == PDG_t::kLambda0Bar) { + m_hAnalysis.fill(HIST("massLambdaMc"), v0.pt() * -1.f, v0.mAntiLambda()); } - return false; } - template - float computeTOFmassDe(const T& candidate) + template + void fillMcHistogramsCascade(aod::CascDatas::iterator const& cascade, + const McPart& bachelorDaughter, const McPart& posV0Daughter) { - float beta = m_responseBeta.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); + McPart v0Daughter; + for (const auto& iterV0Daughter : posV0Daughter.template mothers_as()) { + if (std::abs(iterV0Daughter.pdgCode()) != PDG_t::kLambda0) { + continue; + } + v0Daughter = iterV0Daughter; + } + if (std::abs(bachelorDaughter.pdgCode()) != PDG_t::kKPlus) { + return; + } + + int motherPdgCode = 0; + for (const auto& bachelorMother : bachelorDaughter.template mothers_as()) { + for (const auto& v0Mother : v0Daughter.template mothers_as()) { + if (v0Mother.globalIndex() == bachelorMother.globalIndex()) { + motherPdgCode = bachelorMother.pdgCode(); + } + } + } + + if (motherPdgCode == PDG_t::kOmegaMinus) { + m_hAnalysis.fill(HIST("massOmegaMc"), cascade.pt(), cascade.mOmega()); + } else if (motherPdgCode == -PDG_t::kOmegaMinus) { + m_hAnalysis.fill(HIST("massOmegaMc"), cascade.pt() * -1.f, cascade.mOmega()); + } } - template - float computeTOFmassDeMc(const T& candidate) + template + void fillTable(const Candidate& candidate) { - float beta = m_responseBetaMc.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); + m_ClusterStudiesTable( + candidate.p, candidate.eta, candidate.phi, + candidate.itsClusterSize, static_cast(candidate.partID)); + if (setting_fillExtraTable) { + m_ClusterStudiesTableExtra( + candidate.pTPC, candidate.pidInTrk, + candidate.nsigmaTPC, candidate.nsigmaTOF, candidate.tofMass, + candidate.cosPAMother, candidate.massMother); + } + if (setting_fillCollTable) { + m_ClusterStudiesTableCollision( + m_runNumber); + } + + if constexpr (isMC) { + m_ClusterStudiesTableMc( + candidate.pdgCode); + } } // ========================================================================================================= - template - float computeNSigmaHe3(const T& candidate) + template + float computeTOFmassDe(const T& candidate) + { + float beta = o2::pid::tof::Beta::GetBeta(candidate); + return candidate.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); + } + + template + float computeNSigmaTPCHe3(const Track& 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(); @@ -531,34 +634,45 @@ struct LfTreeCreatorClusterStudies { return static_cast((candidate.tpcSignal() - expTPCSignal) / resoTPC); } - template - bool selectionPIDtpcHe3(const T& candidate) + template + float computeTOFmassHe3(const Track& candidate) { - auto nSigmaHe3 = computeNSigmaHe3(candidate); - if (std::abs(nSigmaHe3) < he3setting_nsigmatpc) { - return true; - } - return false; - } - - template - float computeTOFmassHe3(const T& candidate) - { - float beta = m_responseBeta.GetBeta(candidate); - beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + float beta = o2::pid::tof::Beta::GetBeta(candidate); 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 - float computeTOFmassHe3Mc(const T& candidate) + // ========================================================================================================= + + template + bool electronPrimarySelection(const Track& track) + { + m_hAnalysis.fill(HIST("electron/DCAxyBeforeSelection"), track.dcaXY()); + m_hAnalysis.fill(HIST("electron/DCAzBeforeSelection"), track.dcaZ()); + + if (track.dcaXY() > electronsetting_maxDcaxy || + track.dcaZ() > electronsetting_maxDcaz) { + return false; + } + return true; + } + + template + bool electronPidSelection(const Track& track) { - float beta = m_responseBetaMc.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); + if (track.tpcNSigmaEl() < electronsetting_minNsigmatpcEl || + electronsetting_maxNsigmatpcEl < track.tpcNSigmaEl() || + std::abs(track.tpcNSigmaPi()) < electronsetting_maxNsigmatpcPi || + std::abs(track.tpcNSigmaKa()) < electronsetting_maxNsigmatpcKa || + std::abs(track.tpcNSigmaPr()) < electronsetting_maxNsigmatpcPr) + return false; + + if (electronsetting_maxNsigmatofEl != 0 && + std::abs(track.tofNSigmaEl()) < electronsetting_maxNsigmatofEl) + return false; + + return true; } // ========================================================================================================= @@ -570,7 +684,7 @@ struct LfTreeCreatorClusterStudies { return; } - auto timestamp = bc.timestamp(); + const auto& timestamp = bc.timestamp(); o2::parameters::GRPMagField* grpmag = 0x0; auto grpmagPath{"GLO/Config/GRPMagField"}; @@ -584,7 +698,6 @@ struct LfTreeCreatorClusterStudies { 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); } @@ -596,21 +709,28 @@ struct LfTreeCreatorClusterStudies { 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)); + for (int ipartid = 0; ipartid < static_cast(PartID::all); ipartid++) { + if (ipartid == 0) + continue; + + m_hAnalysis.add(fmt::format("{}/nSigmaITS", cNames[ipartid]).c_str(), (fmt::format("nSigma ITS {};", cNames[ipartid]) + std::string("signed #it{p} (GeV/#it{c}); n#sigma_{ITS}")).c_str(), HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -5.0f, 5.0f}}); + m_hAnalysis.add(fmt::format("{}/nSigmaTPC", cNames[ipartid]).c_str(), (fmt::format("nSigma TPC {};", cNames[ipartid]) + std::string("signed #it{p} (GeV/#it{c}); n#sigma_{TPC}")).c_str(), HistType::kTH2F, {{100, -5.0f, 5.0f}, {60, -3.0f, 3.0f}}); + m_hAnalysis.add(fmt::format("{}/nSigmaTOF", cNames[ipartid]).c_str(), (fmt::format("nSigma TOF {};", cNames[ipartid]) + std::string("signed #it{p} (GeV/#it{c}); n#sigma_{TOF}")).c_str(), HistType::kTH2F, {{100, -5.0f, 5.0f}, {60, -3.0f, 3.0f}}); + if (ipartid == static_cast(PartID::de) || ipartid == static_cast(PartID::he)) { + m_hAnalysis.add(fmt::format("{}/TOFmass", cNames[ipartid]).c_str(), (fmt::format("TOF mass {};", cNames[ipartid]) + std::string("signed #it{p} (GeV/#it{c}); #it{m}_{TOF} (GeV/#it{c}^{2})")).c_str(), HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, 1.0f, 5.0f}}); + m_hAnalysis.add(fmt::format("{}/trackSelections", cNames[ipartid]).c_str(), (fmt::format("track selections {};", cNames[ipartid]) + std::string("Selections; Counts")).c_str(), HistType::kTH1F, {{NucleiSelections::kNucleiAll, -0.5, static_cast(NucleiSelections::kNucleiAll) - 0.5}}); + } + m_hAnalysis.add(fmt::format("{}/pmatching", cNames[ipartid]).c_str(), (fmt::format("p matching {};", cNames[ipartid]) + std::string("signed #it{p}_{TPC} (GeV/#it{c}); #frac{#it{p}_{TPC} - #it{p}}{#it{p}_{TPC}}")).c_str(), HistType::kTH2F, {{100, -5.0f, 5.0f}, {100, -0.5f, 0.5f}}); + } + + std::vector trackSelectionLabels = {"All", "n clusters ITS", "TPC", "TOF"}; + for (int i = 0; i < NucleiSelections::kNucleiAll; i++) { + m_hAnalysis.get(HIST(cNames[static_cast(PartID::de)]) + HIST("/trackSelections"))->GetXaxis()->SetBinLabel(i + 1, trackSelectionLabels[i].c_str()); + m_hAnalysis.get(HIST(cNames[static_cast(PartID::he)]) + HIST("/trackSelections"))->GetXaxis()->SetBinLabel(i + 1, trackSelectionLabels[i].c_str()); + } LOG(info) << "Bethe-Bloch parameters for He3:"; for (int i = 0; i < 5; i++) { @@ -632,816 +752,507 @@ struct LfTreeCreatorClusterStudies { 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"}; + std::vector V0_selection_labels = {"All", "daughter track quality", "V0 topology", "V0 mass selection"}; 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"}; + std::vector Casc_selection_labels = {"All", "Topology", "Veto Xi", "Accepted Omega", "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 E_selections_labels = {"All", "Track quality", "Primary", "Pid", "#pi^{0}"}; + for (int i = 0; i < ESelections::kEAll; i++) + m_hAnalysis.get(HIST("e_selections"))->GetXaxis()->SetBinLabel(i + 1, E_selections_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 - bool fillV0Cand(const std::array& PV, const aod::V0s::iterator& v0, CandidateV0& candV0, const Track&) + template + void fillV0Cand(const std::array& /*pv*/, const aod::V0Datas::iterator& v0, const Tracks&) { m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0NoCut); - auto posTrack = v0.posTrack_as(); - auto negTrack = v0.negTrack_as(); - if (!qualitySelectionV0Daughter(posTrack) || !qualitySelectionV0Daughter(negTrack)) { - return false; - } + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template 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 false; - } + if (!qualitySelectionV0(v0)) + return; + m_hAnalysis.fill(HIST("v0_selections"), V0Selections::kV0Topology); - 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 false; - } + std::array momPos{v0.pxpos(), v0.pypos(), v0.pzpos()}, + momNeg{v0.pxneg(), v0.pyneg(), v0.pzneg()}; - // 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); + m_hAnalysis.fill(HIST("armenteros_plot_before_selections"), v0.alpha(), v0.qtarm()); + m_hAnalysis.fill(HIST("Lambda_vs_K0s"), v0.mK0Short(), v0.mAntiLambda()); - 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 false; - } + uint8_t v0Bitmask = selectV0MotherHypothesis(v0); + 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 false; - if (std::abs(posTrack.tpcNSigmaPr()) > v0setting_nsigmatpcPr || std::abs(negTrack.tpcNSigmaPi()) > v0setting_nsigmatpcPi) - return false; - if (std::hypot(momMother[0], momMother[1], momMother[2]) < lambdasetting_pmin) - return false; - 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 false; - if (std::abs(posTrack.tpcNSigmaPi()) > v0setting_nsigmatpcPr || std::abs(negTrack.tpcNSigmaPr()) > v0setting_nsigmatpcPi) - return false; - if (std::hypot(momMother[0], momMother[1], momMother[2]) < lambdasetting_pmin) - return false; - 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 false; // 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 false; - if (std::abs(posTrack.tpcNSigmaEl()) > v0setting_nsigmatpcEl || std::abs(negTrack.tpcNSigmaEl()) > v0setting_nsigmatpcEl) - return false; - 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 false; - } - - float dcaToPVpos = dcaToPV(PV, daughterTrackCovarianceA, dcaInfo); - if (std::abs(dcaToPVpos) < v0setting_dcaDaughtersToPV /*&& std::abs(dcaInfo[0]) < v0setting_dcaDaughtersToPV*/) { - return false; - } - float dcaToPVneg = dcaToPV(PV, daughterTrackCovarianceB, dcaInfo); - if (std::abs(dcaToPVneg) < v0setting_dcaDaughtersToPV /*&& std::abs(dcaInfo[0]) < v0setting_dcaDaughtersToPV*/) { - return false; - } - - 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("nSigmaTPCPi"), std::hypot(momNeg[0], momNeg[1], momNeg[2]) * -1.f, negTrack.tpcNSigmaPi()); - 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("nSigmaTPCPi"), std::hypot(momNeg[0], momNeg[1], momNeg[2]) * -1.f, negTrack.tpcNSigmaPr()); - 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("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); - - candV0.p_pos = std::hypot(momPos[0], momPos[1], momPos[2]) * posTrack.sign(); - candV0.eta_pos = RecoDecay::eta(momPos); - candV0.phi_pos = RecoDecay::phi(momPos); - candV0.itsClsize_pos = posTrack.itsClusterSizes(); - candV0.partID_pos = partID_pos; - candV0.pTPC_pos = posTrack.tpcInnerParam() * posTrack.sign(); - candV0.pidInTrk_pos = posTrack.pidForTracking(); - - candV0.p_neg = std::hypot(momNeg[0], momNeg[1], momNeg[2]) * negTrack.sign(); - candV0.eta_neg = RecoDecay::eta(momNeg); - candV0.phi_neg = RecoDecay::phi(momNeg); - candV0.itsClsize_neg = negTrack.itsClusterSizes(); - candV0.partID_neg = partID_neg; - candV0.pTPC_neg = negTrack.tpcInnerParam() * negTrack.sign(); - candV0.pidInTrk_pos = posTrack.pidForTracking(); - - candV0.cosPA = cosPA; - candV0.massV0 = massV0; + Candidate candidatePos(std::hypot(momPos[0], momPos[1], momPos[2]) * posTrack.sign(), + RecoDecay::eta(momPos), RecoDecay::phi(momPos), posTrack.itsClusterSizes(), + 0, posTrack.tpcInnerParam() * posTrack.sign(), posTrack.pidForTracking(), + -999.f, -999.f, -999.f, v0.v0cosPA(), -999.f, 0); + Candidate candidateNeg(std::hypot(momNeg[0], momNeg[1], momNeg[2]) * negTrack.sign(), + RecoDecay::eta(momNeg), RecoDecay::phi(momNeg), negTrack.itsClusterSizes(), + 0, negTrack.tpcInnerParam() * negTrack.sign(), negTrack.pidForTracking(), + -999.f, -999.f, -999.f, v0.v0cosPA(), -999.f, 0); - return true; - } + if (!selectPidV0Daughters(candidatePos, candidateNeg, v0, posTrack, negTrack, v0Bitmask)) + return; - bool fillV0CandMc(const aod::V0s::iterator& v0, CandidateV0& candV0) - { - auto posTrack = v0.posTrack_as(); - auto negTrack = v0.negTrack_as(); + const float massV0 = fillHistogramsV0(v0, posTrack, negTrack, v0Bitmask); + candidatePos.massMother = massV0; + candidateNeg.massMother = massV0; - if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) { - return false; - } + if (!setting_fillV0) + return; - auto posMcParticle = posTrack.mcParticle(); - auto negMcParticle = negTrack.mcParticle(); + if constexpr (isMC) { // MC + if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) + return; - candV0.partIDMc_pos = posMcParticle.pdgCode(); - candV0.partIDMc_neg = negMcParticle.pdgCode(); + const auto& posMcParticle = posTrack.mcParticle(); + const auto& negMcParticle = negTrack.mcParticle(); - return true; - } + candidatePos.pdgCode = posMcParticle.pdgCode(); + candidateNeg.pdgCode = negMcParticle.pdgCode(); - void fillV0Table(const CandidateV0& candV0) - { - if (setting_smallTable) { - m_ClusterStudiesTable( - candV0.p_pos, // p_pos - candV0.eta_pos, // eta_pos - candV0.phi_pos, // phi_pos - candV0.itsClsize_pos, // itsClsize_pos - candV0.partID_pos); // partID_pos - m_ClusterStudiesTable( - candV0.p_neg, // p_neg - candV0.eta_neg, // eta_neg - candV0.phi_neg, // phi_neg - candV0.itsClsize_neg, // itsClsize_neg - candV0.partID_neg); // partID_neg - } else { - m_ClusterStudiesTableExtra( - candV0.p_pos, // p_pos - candV0.eta_pos, // eta_pos - candV0.phi_pos, // phi_pos - candV0.itsClsize_pos, // itsClsize_pos - candV0.partID_pos, // partID_pos - candV0.pTPC_pos, // pTPC_pos - candV0.pidInTrk_pos, // pidInTrk_pos - -999.f, // TpcNSigma_pos - -999.f, // TofNSigma_pos - -999.f, // TofMass_pos - candV0.cosPA, // cosPA - candV0.massV0); // massV0 - m_ClusterStudiesTableExtra( - candV0.p_neg, // p_neg - candV0.eta_neg, // eta_neg - candV0.phi_neg, // phi_neg - candV0.itsClsize_neg, // itsClsize_neg - candV0.partID_neg, // partID_neg - candV0.pTPC_neg, // pTPC_neg - candV0.pidInTrk_neg, // pidInTrk_neg - -999.f, // TpcNSigma_neg - -999.f, // TofNSigma_neg - -999.f, // TofMass_neg - candV0.cosPA, // cosPA - candV0.massV0); // massV0 + fillMcHistogramsV0(v0, posMcParticle, negMcParticle); } - m_hAnalysis.fill(HIST("isPositive"), true); - m_hAnalysis.fill(HIST("isPositive"), false); - } - - void fillV0TableMc(const CandidateV0& candV0) - { - if (setting_smallTable) { - m_ClusterStudiesTableMc( - candV0.p_pos, // p_pos - candV0.eta_pos, // eta_pos - candV0.phi_pos, // phi_pos - candV0.itsClsize_pos, // itsClsize_pos - candV0.partID_pos, // partID_pos - candV0.partIDMc_pos); // pdgCode_pos - m_ClusterStudiesTableMc( - candV0.p_neg, // p_neg - candV0.eta_neg, // eta_neg - candV0.phi_neg, // phi_neg - candV0.itsClsize_neg, // itsClsize_neg - candV0.partID_neg, // partID_neg - candV0.partIDMc_neg); // pdgCode_neg - } else { - m_ClusterStudiesTableMcExtra( - candV0.p_pos, // p_pos - candV0.eta_pos, // eta_pos - candV0.phi_pos, // phi_pos - candV0.itsClsize_pos, // itsClsize_pos - candV0.partID_pos, // partID_pos - candV0.partIDMc_pos, // pdgCode_neg - candV0.pTPC_pos, // pTPC_pos - candV0.pidInTrk_pos, // pidInTrk_pos - -999.f, // TpcNSigma_pos - -999.f, // TofNSigma_pos - -999.f, // TofMass_pos - candV0.cosPA, // cosPA - candV0.massV0); // massV0 - m_ClusterStudiesTableMcExtra( - candV0.p_neg, // p_neg - candV0.eta_neg, // eta_neg - candV0.phi_neg, // phi_neg - candV0.itsClsize_neg, // itsClsize_neg - candV0.partID_neg, // partID_neg - candV0.partIDMc_neg, // pdgCode_neg - candV0.pTPC_neg, // pTPC_neg - candV0.pidInTrk_neg, // pidInTrk_neg - -999.f, // TpcNSigma_neg - -999.f, // TofNSigma_neg - -999.f, // TofMass_neg - candV0.cosPA, // cosPA - candV0.massV0); // massV0 - } + fillTable(candidatePos); + fillTable(candidateNeg); m_hAnalysis.fill(HIST("isPositive"), true); m_hAnalysis.fill(HIST("isPositive"), false); } - template - bool fillKCand(const std::array& PV, const aod::Cascades::iterator& cascade, CandidateK& candK, const Track&) + template + void fillKCand(const std::array& pv, aod::CascDatas::iterator const& cascade, const Track&) { m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kCascNoCut); + const auto& bachelorTrack = cascade.template bachelor_as(); - auto v0Track = cascade.template v0_as(); - auto bachelorTrack = cascade.template bachelor_as(); + std::array momBachelor{cascade.pxbach(), cascade.pybach(), cascade.pzbach()}; - 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 false; - } - - auto v0TrackCovariance = itv0->trackParCov; - auto bachelorTrackCovariance = getTrackParCov(bachelorTrack); - if (!initializeFitter(v0TrackCovariance, bachelorTrackCovariance)) { - return false; + if (!qualitySelectionCascade(cascade, pv)) { + return; } + m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kCascTopology); - 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); + const float& massXi = cascade.mXi(); + const float& massOmega = cascade.mOmega(); + m_hAnalysis.fill(HIST("Xi_vs_Omega"), massOmega, massXi); - if (!qualitySelectionCascade(dcaV0daughters, cosPA)) { - return false; + if (std::abs(massXi - o2::constants::physics::MassXiMinus) < cascsetting_massWindowXi) { + return; } - // gpu::gpustd::array dcaInfo; - // float dcaToPVbachelor = dcaToPV(PV, bachelorTrackCovariance, dcaInfo); + m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kRejectedXi); - 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); + m_hAnalysis.fill(HIST("massOmega"), cascade.pt() * bachelorTrack.sign(), massOmega); if (std::abs(massOmega - o2::constants::physics::MassOmegaMinus) > cascsetting_massWindowOmega) { - return false; + 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 false; - } // enhance purity by rejecting Xi background - m_hAnalysis.fill(HIST("casc_selections"), CascSelections::kRejectedXi); + if (std::abs(bachelorTrack.tpcNSigmaKa()) > cascsetting_nsigmatpc) { - return false; + 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; - - candK.p_K = std::hypot(momBachelor[0], momBachelor[1], momBachelor[2]) * bachelorTrack.sign(); - candK.eta_K = RecoDecay::eta(momBachelor); - candK.phi_K = RecoDecay::phi(momBachelor); - candK.itsClsize_K = bachelorTrack.itsClusterSizes(); - candK.partID_K = partID_bachelor; - candK.pTPC_K = bachelorTrack.tpcInnerParam() * bachelorTrack.sign(); - candK.pidInTrk_K = bachelorTrack.pidForTracking(); - candK.cosPA = cosPA; - candK.massOmega = massOmega; - return true; - } - - bool fillKCandMc(const aod::Cascades::iterator& cascade, CandidateK& candK) - { - auto bachelorTrack = cascade.template bachelor_as(); + fillHistogramsParticle(bachelorTrack); - if (!bachelorTrack.has_mcParticle()) { - return false; + m_ClusterStudiesTable( + std::hypot(momBachelor[0], momBachelor[1], momBachelor[2]) * bachelorTrack.sign(), + RecoDecay::eta(momBachelor), RecoDecay::phi(momBachelor), + bachelorTrack.itsClusterSizes(), PartID::ka); + if (setting_fillExtraTable) { + m_ClusterStudiesTableExtra( + bachelorTrack.tpcInnerParam() * bachelorTrack.sign(), + bachelorTrack.pidForTracking(), + bachelorTrack.tpcNSigmaKa(), /*TOF nsigma*/ -999.f, /*TOF mass*/ -999.f, + cascade.casccosPA(pv[0], pv[1], pv[2]), massOmega); + } + if (setting_fillCollTable) { + m_ClusterStudiesTableCollision( + m_runNumber); } - auto bachelorMcParticle = bachelorTrack.mcParticle(); - candK.partIDMc_K = bachelorMcParticle.pdgCode(); + if constexpr (isMC) { + if (!bachelorTrack.has_mcParticle()) { + return; + } + const auto& mcParticle = bachelorTrack.mcParticle(); - return true; - } + m_ClusterStudiesTableMc( + mcParticle.pdgCode()); - void fillKTable(const CandidateK& candK) - { - if (setting_smallTable) { - m_ClusterStudiesTable( - candK.p_K, // p_K - candK.eta_K, // eta_K - candK.phi_K, // phi_K - candK.itsClsize_K, // itsClSize_K - candK.partID_K); // pdgCode_K - } else { - m_ClusterStudiesTableExtra( - candK.p_K, // p_K - candK.eta_K, // eta_K - candK.phi_K, // phi_K - candK.itsClsize_K, // itsClSize_K - candK.partID_K, // pdgCode_K - candK.pTPC_K, // pTPC_K - candK.pidInTrk_K, // PIDinTrk_K - -999.f, // TpcNSigma_K - -999.f, // TofNSigma_K - -999.f, // TofMass_K - candK.cosPA, // cosPA - candK.massOmega); // massMother - } - - m_hAnalysis.fill(HIST("isPositive"), candK.p_K > 0); - } + const auto& posV0Daughter = cascade.template posTrack_as(); + if (!posV0Daughter.has_mcParticle()) { + return; + } + const auto& mcPosParticleV0 = posV0Daughter.mcParticle(); + fillMcHistogramsCascade(cascade, mcParticle, mcPosParticleV0); + } - void fillKTableMc(const CandidateK& candK) - { - if (setting_smallTable) { - m_ClusterStudiesTableMc( - candK.p_K, // p_K - candK.eta_K, // eta_K - candK.phi_K, // phi_K - candK.itsClsize_K, // itsClSize_K - candK.partID_K, // pdgCode_K - candK.partIDMc_K); // pdgCode_K - } else { - m_ClusterStudiesTableMcExtra( - candK.p_K, // p_K - candK.eta_K, // eta_K - candK.phi_K, // phi_K - candK.itsClsize_K, // itsClSize_K - candK.partID_K, // pdgCode_K - candK.partIDMc_K, // pdgCode_K - candK.pTPC_K, // pTPC_K - candK.pidInTrk_K, // PIDinTrk_K - -999.f, // TpcNSigma_K - -999.f, // TofNSigma_K - -999.f, // TofMass_K - candK.cosPA, // cosPA - candK.massOmega); // massMother - } - - m_hAnalysis.fill(HIST("isPositive"), candK.p_K > 0); + m_hAnalysis.fill(HIST("isPositive"), bachelorTrack.sign() > 0); } - void fillDeTable(const TracksFullIU::iterator& track) + template + void fillNucleusTable(const Track& track) { - if (track.sign() > 0) { - return; - } - m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDeNoCut); - if (track.itsNCls() < desetting_nClsIts) { + constexpr int kPartID = partID; + + if (kPartID == static_cast(PartID::de) && track.sign() > 0) return; - } - m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDeNClsIts); - if (!selectionPIDtpcDe(track)) { + m_hAnalysis.fill(HIST(cNames[kPartID]) + HIST("/trackSelections"), NucleiSelections::kNucleiNoCut); + + if (track.itsNCls() < desetting_nClsIts) return; - } - m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDePIDtpc); - if (!track.hasTOF() || std::abs(track.tofNSigmaDe()) > desetting_nsigmatof) { + m_hAnalysis.fill(HIST(cNames[kPartID]) + HIST("/trackSelections"), NucleiSelections::kNucleiNClsIts); + + const float tpcNsigma = kPartID == static_cast(PartID::de) ? track.tpcNSigmaDe() : computeNSigmaTPCHe3(track); + const float tpcNsigmaMax = kPartID == static_cast(PartID::de) ? desetting_nsigmatpc : he3setting_nsigmatpc; + if (std::abs(tpcNsigma) > tpcNsigmaMax) return; - } - m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDePIDtof); - m_hAnalysis.fill(HIST("nSigmaTPCDe"), track.p() * track.sign(), computeNSigmaDe(track)); - 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 (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 + m_hAnalysis.fill(HIST(cNames[kPartID]) + HIST("/trackSelections"), NucleiSelections::kNucleiPIDtpc); + + const float tofMass = track.hasTOF() ? (kPartID == static_cast(PartID::de) ? computeTOFmassDe(track) : computeTOFmassHe3(track)) : -999.f; + const float tofNsigma = kPartID == static_cast(PartID::de) ? track.tofNSigmaDe() : -999.f; + float correctedTPCinnerParam = track.tpcInnerParam(); + + if (kPartID == static_cast(PartID::de)) { + if (!track.hasTOF() || std::abs(tofNsigma) > desetting_nsigmatof) + return; } else { + if (track.hasTOF() && (tofMass < he3setting_tofmasslow || tofMass > he3setting_tofmasshigh)) + return; + + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + correctedTPCinnerParam = (heliumPID && he3setting_compensatePIDinTracking) ? track.tpcInnerParam() / 2.f : track.tpcInnerParam(); + } + m_hAnalysis.fill(HIST(cNames[kPartID]) + HIST("/trackSelections"), NucleiSelections::kNucleiPIDtof); + + fillHistogramsParticle(track); + + m_ClusterStudiesTable( + track.p() * track.sign(), track.eta(), track.phi(), + track.itsClusterSizes(), kPartID); + if (setting_fillExtraTable) { 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, - -999.f, // TofMass_De, - -999.f, // cosPA, - -999.f); // massMother + correctedTPCinnerParam * track.sign(), track.pidForTracking(), + tpcNsigma, tofNsigma, tofMass, + /*cosPA*/ -999.f, /*mass mother*/ -999.f); + } + if (setting_fillCollTable) { + m_ClusterStudiesTableCollision( + m_runNumber); + } + + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return; + } + + const auto& mcParticle = track.mcParticle(); + + m_ClusterStudiesTableMc( + mcParticle.pdgCode()); } m_hAnalysis.fill(HIST("isPositive"), track.sign() > 0); } - void fillDeTableMc(const TracksFullIUMc::iterator& track) + void fillPKPiTable(const TracksFullIU::iterator& track) { - if (!track.has_mcParticle() || track.sign() > 0) { + 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; } - auto mcParticle = track.mcParticle(); - m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDeNoCut); - if (track.itsNCls() < desetting_nClsIts) { - return; + m_ClusterStudiesTable( + track.p() * track.sign(), track.eta(), track.phi(), + track.itsClusterSizes(), partID); + if (setting_fillExtraTable) { + m_ClusterStudiesTableExtra( + track.tpcInnerParam() * track.sign(), track.pidForTracking(), + tpcNSigma, /*TOF nsigma*/ -999.f, /*TOF mass*/ -999.f, + /*cosPA*/ -999.f, /*mass mother*/ -999.f); } - m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDeNClsIts); - if (!selectionPIDtpcDe(track)) { - return; + if (setting_fillCollTable) { + m_ClusterStudiesTableCollision( + m_runNumber); } - m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDePIDtpc); - if (!track.hasTOF() || std::abs(track.tofNSigmaDe()) > desetting_nsigmatof) { + } + + template + void fillElectronTable(const Track& posTrack, const Track& negTrack) + { + m_hAnalysis.fill(HIST("e_selections"), ESelections::kENoCut); + if (!qualityTrackSelection(posTrack) || !qualityTrackSelection(negTrack)) { return; } - m_hAnalysis.fill(HIST("de_selections"), DeSelections::kDePIDtof); - m_hAnalysis.fill(HIST("nSigmaTPCDe"), track.p() * track.sign(), computeNSigmaDe(track)); - m_hAnalysis.fill(HIST("nSigmaTOFDe"), track.p() * track.sign(), track.tofNSigmaDe()); - m_hAnalysis.fill(HIST("TOFmassDe"), track.p() * track.sign(), computeTOFmassDeMc(track)); - m_hAnalysis.fill(HIST("pmatchingDe"), track.sign() * track.tpcInnerParam(), (track.tpcInnerParam() - track.p()) / track.tpcInnerParam()); + m_hAnalysis.fill(HIST("e_selections"), ESelections::kETrackQuality); - uint8_t partID = PartID::de; + if (!electronPrimarySelection(posTrack) || !electronPrimarySelection(negTrack)) { + return; + } + m_hAnalysis.fill(HIST("e_selections"), ESelections::kEPrimary); - 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, - -999.f, // TofMass_De, - -999.f, // cosPA, - -999.f); // massMother + if (!electronPidSelection(posTrack) || !electronPidSelection(negTrack)) { + return; } - } + m_hAnalysis.fill(HIST("e_selections"), ESelections::kEPid); - void fillHe3Table(const TracksFullIU::iterator& track) - { - m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3NoCut); + const float invariantMass = std::sqrt(RecoDecay::m2<2>(std::array, 2>{ + std::array{posTrack.px(), posTrack.py(), posTrack.pz()}, + std::array{negTrack.px(), negTrack.py(), negTrack.pz()}}, + std::array{o2::constants::physics::MassElectron, o2::constants::physics::MassElectron})); - if (track.itsNCls() < he3setting_nClsIts) { + m_hAnalysis.fill(HIST("massPi0WithBkg"), invariantMass); + if (invariantMass > o2::constants::physics::MassPi0) { return; } - m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3NClsIts); - if (!selectionPIDtpcHe3(track)) { - return; + m_hAnalysis.fill(HIST("e_selections"), ESelections::kEPi0); + m_hAnalysis.fill(HIST("massPi0"), invariantMass); + fillHistogramsParticle(posTrack); + fillHistogramsParticle(negTrack); + + // 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(), m_d_bz); + // float opangle = o2::aod::pwgem::dilepton::utils::pairutil::getOpeningAngle(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz()); + + m_ClusterStudiesTable( + posTrack.p(), posTrack.eta(), posTrack.phi(), + posTrack.itsClusterSizes(), PartID::el); + if (setting_fillExtraTable) { + m_ClusterStudiesTableExtra( + posTrack.tpcInnerParam(), posTrack.pidForTracking(), + posTrack.tpcNSigmaEl(), posTrack.tofNSigmaEl(), -999.f /* TofMass */, + -999.f /* cosPA */, invariantMass); } - 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; + if (setting_fillCollTable) { + m_ClusterStudiesTableCollision( + m_runNumber); } - 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("TOFmassHe"), track.p() * track.sign(), tofMass); - m_hAnalysis.fill(HIST("pmatchingHe"), track.sign() * correctedTPCinnerParam, (correctedTPCinnerParam - track.p()) / correctedTPCinnerParam); - - 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_ClusterStudiesTable( + negTrack.p(), negTrack.eta(), negTrack.phi(), + negTrack.itsClusterSizes(), PartID::el); + if (setting_fillExtraTable) { 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 + negTrack.tpcInnerParam(), negTrack.pidForTracking(), + negTrack.tpcNSigmaEl(), negTrack.tofNSigmaEl(), -999.f /* TofMass */, + -999.f /* cosPA */, invariantMass); + } + if (setting_fillCollTable) { + m_ClusterStudiesTableCollision( + m_runNumber); } - m_hAnalysis.fill(HIST("isPositive"), track.sign() > 0); + if constexpr (isMC) { + const auto& posMcParticle = posTrack.mcParticle(); + const auto& negMcParticle = negTrack.mcParticle(); + + m_ClusterStudiesTableMc( + posMcParticle.pdgCode()); + m_ClusterStudiesTableMc( + negMcParticle.pdgCode()); + + if (!posMcParticle.has_mothers() || !negMcParticle.has_mothers()) + return; + + for (const auto& posMother : posMcParticle.template mothers_as()) { + for (const auto& negMother : negMcParticle.template mothers_as()) { + if (posMother.globalIndex() != negMother.globalIndex() || std::abs(posMother.pdgCode()) != PDG_t::kPi0) + return; + m_hAnalysis.fill(HIST("massPi0Mc"), std::sqrt((posMcParticle.e() + negMcParticle.e()) * (posMcParticle.e() + negMcParticle.e()) - + (posMcParticle.p() + negMcParticle.p()) * (posMcParticle.p() + posMcParticle.p()))); + break; + } + } + } } - void fillHe3TableMc(const TracksFullIUMc::iterator& track) + // ========================================================================================================= + + void processDataV0Casc(CollisionsCustom::iterator const& collision /*s*/, TracksFullIU const& tracks, aod::V0Datas const& v0s, aod::CascDatas const& cascades, aod::BCsWithTimestamps const&) { - if (!track.has_mcParticle()) { + if (!collisionSelection(collision)) { return; } - auto mcParticle = track.mcParticle(); - m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3NoCut); - if (track.itsNCls() < he3setting_nClsIts) { - return; + const auto& bc = collision.bc_as(); + initCCDB(bc); + + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + std::array PV = {collision.posX(), collision.posY(), collision.posZ()}; + + for (const auto& v0 : v0s) { + fillV0Cand(PV, v0, tracks); } - m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3NClsIts); - if (!selectionPIDtpcHe3(track)) { - return; + + for (const auto& cascade : cascades) { + fillKCand(PV, cascade, tracks); } - m_hAnalysis.fill(HIST("he3_selections"), He3Selections::kHe3PIDtpc); - float tofMass = track.hasTOF() ? computeTOFmassHe3Mc(track) : -999.f; - if (track.hasTOF() && (tofMass < he3setting_tofmasslow || tofMass > he3setting_tofmasshigh)) { + } + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processDataV0Casc, "process Data V0 and cascade", false); + + Partition posTracks = o2::aod::track::signed1Pt > 0.f; + Partition negTracks = o2::aod::track::signed1Pt < 0.f; + void processDataElectrons(CollisionsCustom::iterator const& collision, TracksFullIU const& /*tracks*/, aod::BCsWithTimestamps const&) + { + if (!collisionSelection(collision)) { 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("TOFmassHe"), track.p() * track.sign(), tofMass); - m_hAnalysis.fill(HIST("pmatchingHe"), track.sign() * correctedTPCinnerParam, (correctedTPCinnerParam - track.p()) / correctedTPCinnerParam); + const auto& bc = collision.bc_as(); + initCCDB(bc); - 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 + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + + const auto& posTracks_thisCollision = posTracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), m_cache); + const auto& negTracks_thisCollision = negTracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), m_cache); + + for (const auto& [posTrack, negTrack] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posTracks_thisCollision, negTracks_thisCollision))) { + fillElectronTable(posTrack, negTrack); } } + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processDataElectrons, "process Data Electrons", false); - void processDataV0Casc(CollisionsCustom const& collisions, TracksFullIU const& tracks, aod::V0s const& v0s, aod::Cascades const& cascades, aod::BCsWithTimestamps const&) + void processDataNuclei(CollisionsCustom::iterator const& collision, TracksFullIU const& tracks, aod::BCsWithTimestamps const&) { - for (const auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); + if (!collisionSelection(collision)) { + return; + } - m_collisionCounter++; - if (m_collisionCounter % static_cast(1e3) == 0) - LOG(info) << "Processing collision " << m_collisionCounter << " with zVtx = " << collision.posZ(); + const auto& bc = collision.bc_as(); + initCCDB(bc); - if (!collisionSelection(collision)) { - continue; - } + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); - 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) { - m_v0TrackParCovs.clear(); - for (auto& v0 : v0Table_thisCollision) { - CandidateV0 candV0; - if (fillV0Cand(PV, v0, candV0, tracks)) - fillV0Table(candV0); - } - } - if (setting_fillK && setting_fillV0) { // the v0 loops are needed for the Ks - for (auto& cascade : cascTable_thisCollision) { - CandidateK candK; - if (fillKCand(PV, cascade, candK, tracks)) - fillKTable(candK); - } + for (const auto& track : tracks) { + if (!qualityTrackSelection(track)) { + return; } + + fillNucleusTable(track); + fillNucleusTable(track); } } - PROCESS_SWITCH(LfTreeCreatorClusterStudies, processDataV0Casc, "process Data V0 and cascade", false); + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processDataNuclei, "process Data Nuclei", false); - void processDataNuclei(CollisionsCustom const& collisions, TracksFullIU const& tracks) + /** + * @brief Produce a dataset with high purity p, K, #pi + */ + void processDataPKPi(CollisionsCustom::iterator const& collision, TracksFullIU const& tracks) { - for (const auto& collision : collisions) { - m_collisionCounter++; - if (m_collisionCounter % static_cast(1e3) == 0) - LOG(info) << "Processing collision " << m_collisionCounter << " with zVtx = " << collision.posZ(); - - if (!collisionSelection(collision)) { - continue; - } - - m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + if (!collisionSelection(collision)) { + return; + } - const uint64_t collIdx = collision.globalIndex(); - auto TrackTable_thisCollision = tracks.sliceBy(m_perCol, collIdx); - TrackTable_thisCollision.bindExternalIndices(&tracks); + const auto& bc = collision.bc_as(); + initCCDB(bc); - for (auto track : TrackTable_thisCollision) { - if (!nucleiTrackSelection(track)) { - continue; - } + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); - if (setting_fillDe) - fillDeTable(track); - if (setting_fillHe3) - fillHe3Table(track); + for (const auto& track : tracks) { + if (!qualityTrackSelection(track)) { + return; } + + fillPKPiTable(track); } } - PROCESS_SWITCH(LfTreeCreatorClusterStudies, processDataNuclei, "process Data Nuclei", false); + 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&) + void processMcV0Casc(CollisionsCustomMc::iterator const& collision /*s*/, TracksFullIUMc const& tracks, aod::V0Datas const& v0s, aod::CascDatas const& cascades, aod::BCsWithTimestamps const&, aod::McParticles const&, aod::McCollisions const&) { - for (const auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); + if (!collisionSelection(collision)) { + return; + } - m_collisionCounter++; - if (m_collisionCounter % static_cast(1e3) == 0) - LOG(info) << "Processing collision " << m_collisionCounter << " with zVtx = " << collision.posZ(); + const auto& bc = collision.template bc_as(); + initCCDB(bc); - if (!collisionSelection(collision)) { - continue; - } + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + std::array PV = {collision.posX(), collision.posY(), collision.posZ()}; - 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) { - m_v0TrackParCovs.clear(); - for (auto& v0 : v0Table_thisCollision) { - CandidateV0 candV0; - if (fillV0Cand(PV, v0, candV0, tracks)) { - if (fillV0CandMc(v0, candV0)) { - fillV0TableMc(candV0); - } - } - } - } - if (setting_fillK && setting_fillV0) { // the v0 loops are needed for the Ks - for (auto& cascade : cascTable_thisCollision) { - CandidateK candK; - if (fillKCand(PV, cascade, candK, tracks)) { - if (fillKCandMc(cascade, candK)) { - fillKTableMc(candK); - } - } - } - } + for (const auto& v0 : v0s) { + fillV0Cand(PV, v0, tracks); + } + + for (const auto& cascade : cascades) { + 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&) + Partition posTracksMc = o2::aod::track::signed1Pt > 0.f; + Partition negTracksMc = o2::aod::track::signed1Pt < 0.f; + void processMcElectrons(CollisionsCustomMc::iterator const& collision, TracksFullIUMc const& /*tracks*/, aod::BCsWithTimestamps const&, aod::McParticles const&, aod::McCollisions const&) { - for (const auto& collision : collisions) { - m_collisionCounter++; - if (m_collisionCounter % static_cast(1e3) == 0) - LOG(info) << "Processing collision " << m_collisionCounter << " with zVtx = " << collision.posZ(); + if (!collision.has_mcCollision()) { + return; + } + if (!collisionSelection(collision)) { + return; + } - if (!collisionSelection(collision)) { - continue; - } + const auto& bc = collision.template bc_as(); + initCCDB(bc); + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); - m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + const auto& posTracks_thisCollision = posTracksMc.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), m_cache); + const auto& negTracks_thisCollision = negTracksMc.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), m_cache); - const uint64_t collIdx = collision.globalIndex(); - auto TrackTable_thisCollision = tracks.sliceBy(m_perColMC, collIdx); - TrackTable_thisCollision.bindExternalIndices(&tracks); + for (const auto& [posTrack, negTrack] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posTracks_thisCollision, negTracks_thisCollision))) { + if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) + continue; - for (auto track : TrackTable_thisCollision) { - if (!nucleiTrackSelection(track)) { - continue; - } + fillElectronTable(posTrack, negTrack); + } + } + PROCESS_SWITCH(LfTreeCreatorClusterStudies, processMcElectrons, "process Mc Electrons", false); - if (setting_fillDe) { - fillDeTableMc(track); - } - if (setting_fillHe3) { - fillHe3TableMc(track); - } + void processMcNuclei(CollisionsCustomMc::iterator const& collision, TracksFullIUMc const& tracks, aod::BCsWithTimestamps const&, aod::McParticles const&, aod::McCollisions const&) + { + if (!collision.has_mcCollision()) { + return; + } + if (!collisionSelection(collision)) { + return; + } + const auto& bc = collision.template bc_as(); + initCCDB(bc); + m_hAnalysis.fill(HIST("zVtx"), collision.posZ()); + + for (const auto& track : tracks) { + if (!qualityTrackSelection(track)) { + return; } + + fillNucleusTable(track); + fillNucleusTable(track); } } PROCESS_SWITCH(LfTreeCreatorClusterStudies, processMcNuclei, "process Mc Nuclei", false); diff --git a/PWGLF/TableProducer/Nuspex/LFTreeCreatorNuclei.cxx b/PWGLF/TableProducer/Nuspex/LFTreeCreatorNuclei.cxx index dda78a26c64..c32d68a539a 100644 --- a/PWGLF/TableProducer/Nuspex/LFTreeCreatorNuclei.cxx +++ b/PWGLF/TableProducer/Nuspex/LFTreeCreatorNuclei.cxx @@ -20,26 +20,27 @@ #include "PWGLF/DataModel/LFNucleiTables.h" #include "PWGLF/DataModel/LFParticleIdentification.h" -#include -#include -#include -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" - -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.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 "ReconstructionDataFormats/Track.h" + +#include +#include +#include // #include @@ -249,6 +250,7 @@ struct LfTreeCreatorNuclei { track.tpcSignal(), track.pt(), track.eta(), track.phi(), track.sign(), + track.itsClusterSizes(), track.itsNCls(), track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index b56614499f0..024ad6fb6f7 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -8,577 +8,651 @@ // In applying this license CERN does 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 Builder task for 3-body decay reconstruction (p + pion + bachelor) +// ======================== +/// \file decay3bodybuilder.cxx +/// \brief Builder task for 3-body hypertriton decay reconstruction (proton + pion + deuteron) /// \author Yuanzhe Wang -/// \author Carolina Reetz (KFParticle specific part) +/// \author Carolina Reetz +// ======================== -#include -#include -#include +#include "TableHelper.h" -#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 "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "PWGLF/DataModel/Reduced3BodyTables.h" +#include "PWGLF/DataModel/Vtx3BodyTables.h" +#include "PWGLF/Utils/decay3bodyBuilderHelper.h" +#include "PWGLF/Utils/pidTOFGeneric.h" + +#include "Common/Core/PID/PIDTOF.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.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 "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/PID/PIDTOF.h" -#include "TableHelper.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Tools/KFparticle/KFUtilities.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 "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include +#include #ifndef HomogeneousField #define HomogeneousField #endif // includes KFParticle -#include "KFParticle.h" #include "KFPTrack.h" #include "KFPVertex.h" +#include "KFParticle.h" #include "KFParticleBase.h" #include "KFVertex.h" using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using std::array; -using MyCollisions = soa::Join; -using FullTracksExtIU = soa::Join; -using FullTracksExtPIDIU = soa::Join; -using MCLabeledTracksIU = soa::Join; +o2::common::core::MetadataHelper metadataInfo; -struct decay3bodyBuilder { +static constexpr int nParameters = 1; +static const std::vector tableNames{ + "Decay3BodyIndices", + "Vtx3BodyDatas", + "Vtx3BodyCovs", + "McVtx3BodyDatas"}; - Produces vtx3bodydata; - Produces kfvtx3bodydata; - Service ccdb; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; +static constexpr int nTablesConst = 4; - // Configurables - Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; - - enum vtxstep { kVtxAll = 0, - kVtxTPCNcls, - kVtxhasSV, - kVtxDcaDau, - kVtxCosPA, - kNVtxSteps }; - - enum kfvtxstep { kKfVtxAll = 0, - kKfVtxCollIds, - kKfVtxCharge, - kKfVtxEta, - kKfVtxTPCPID, - kKfVtxTPCNcls, - kKfVtxTPCRows, - kKfVtxDCAxyPV, - kKfVtxDCAzPV, - kKfVtxTrackPt, - kKfVtxNoV0, - kKfVtxhasSV, - kKfVtxDcaDau, - kKfVtxDcaDauVtx, - kKfVtxPt, - kKfVtxMass, - kKfVtxCosPA, - kKfVtxCosPAXY, - kKfVtxChi2geo, - kKfVtxChi2topo, - kKfNVtxSteps }; - - HistogramRegistry registry{ - "registry", - {{"hEventCounter", "hEventCounter", {HistType::kTH1F, {{1, 0.0f, 1.0f}}}}, - {"hVtx3BodyCounter", "hVtx3BodyCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, - {"hVtx3BodyCounterKFParticle", "hVtx3BodyCounterKFParticle", {HistType::kTH1F, {{20, 0.0f, 20.0f}}}}, - {"hBachelorTOFNSigmaDe", "", {HistType::kTH2F, {{40, -10.0f, 10.0f, "p/z (GeV/c)"}, {40, -10.0f, 10.0f, "TOF n#sigma"}}}}, - {"QA/Tracks/hTrackPosTPCNcls", "hTrackPosTPCNcls", {HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}}}, - {"QA/Tracks/hTrackNegTPCNcls", "hTrackNegTPCNcls", {HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}}}, - {"QA/Tracks/hTrackBachTPCNcls", "hTrackBachTPCNcls", {HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}}}, - {"QA/Tracks/hTrackPosHasTPC", "hTrackPosHasTPC", {HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}}}, - {"QA/Tracks/hTrackNegHasTPC", "hTrackNegHasTPC", {HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}}}, - {"QA/Tracks/hTrackBachHasTPC", "hTrackBachHasTPC", {HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}}}, - {"QA/Tracks/hTrackProtonTPCPID", "hTrackProtonTPCPID", {HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}}}, - {"QA/Tracks/hTrackPionTPCPID", "hTrackPionTPCPID", {HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}}}, - {"QA/Tracks/hTrackBachTPCPID", "hTrackBachTPCPID", {HistType::kTH2F, {{100, -10.0f, 10.0f, "p/z (GeV/c)"}, {100, -10.0f, 10.0f, "TPC n#sigma"}}}}, - {"QA/Tracks/hTrackProtonPt", "hTrackProtonPt", {HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"QA/Tracks/hTrackPionPt", "hTrackPionPt", {HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"QA/Tracks/hTrackBachPt", "hTrackBachPt", {HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"QA/Event/hVtxXKF", "hVtxXKF", {HistType::kTH1F, {{500, -0.5f, 0.5f, "PV X (cm)"}}}}, - {"QA/Event/hVtxYKF", "hVtxYKF", {HistType::kTH1F, {{500, -0.5f, 0.5f, "PV Y (cm)"}}}}, - {"QA/Event/hVtxZKF", "hVtxZKF", {HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}}}, - {"QA/Event/hVtxCovXXKF", "hVtxCovXXKF", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(XX) (cm^{2})"}}}}, - {"QA/Event/hVtxCovYYKF", "hVtxCovYYKF", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(YY) (cm^{2})"}}}}, - {"QA/Event/hVtxCovZZKF", "hVtxCovZZKF", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(ZZ) (cm^{2})"}}}}, - {"QA/Event/hVtxCovXYKF", "hVtxCovXYKF", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(XY) (cm^{2})"}}}}, - {"QA/Event/hVtxCovXZKF", "hVtxCovXZKF", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(XZ) (cm^{2})"}}}}, - {"QA/Event/hVtxCovYZKF", "hVtxCovYZKF", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(YZ) (cm^{2})"}}}}, - {"QA/Event/hVtxX", "hVtxX", {HistType::kTH1F, {{500, -0.5f, 0.5f, "PV X (cm)"}}}}, - {"QA/Event/hVtxY", "hVtxY", {HistType::kTH1F, {{500, -0.5f, 0.5f, "PV Y (cm)"}}}}, - {"QA/Event/hVtxZ", "hVtxZ", {HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}}}, - {"QA/Event/hVtxCovXX", "hVtxCovXX", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(XX) (cm^{2})"}}}}, - {"QA/Event/hVtxCovYY", "hVtxCovYY", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(YY) (cm^{2})"}}}}, - {"QA/Event/hVtxCovZZ", "hVtxCovZZ", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(ZZ) (cm^{2})"}}}}, - {"QA/Event/hVtxCovXY", "hVtxCovXY", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(XY) (cm^{2})"}}}}, - {"QA/Event/hVtxCovXZ", "hVtxCovXZ", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(XZ) (cm^{2})"}}}}, - {"QA/Event/hVtxCovYZ", "hVtxCovYZ", {HistType::kTH1F, {{200, -0.005f, 0.005f, "PV cov(YZ) (cm^{2})"}}}}}, - }; +static const std::vector parameterNames{"enable"}; +static const int defaultParameters[nTablesConst][nParameters]{ + {0}, // Decay3BodyIndices + {0}, // Vtx3BodyDatas + {0}, // Vtx3BodyCovs + {0} // McVtx3BodyDatas +}; + +using TracksExtPIDIUwithEvTimes = soa::Join; +using TracksExtPIDIUwithEvTimesLabeled = soa::Join; - // hypothesis - Configurable bachelorcharge{"bachelorcharge", 1, "charge of the bachelor track"}; - // 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"}; +using ColswithEvTimes = o2::soa::Join; +using ColswithEvTimesLabeled = o2::soa::Join; +struct decay3bodyBuilder { + + // helper object + o2::pwglf::decay3bodyBuilderHelper helper; + + // table index : match order above + enum tableIndex { kDecay3BodyIndices = 0, + kVtx3BodyDatas, + kVtx3BodyCovs, + kMcVtx3BodyDatas, + nTables }; + + struct : ProducesGroup { + Produces decay3bodyindices; + Produces vtx3bodydatas; + Produces vtx3bodycovs; + Produces mcvtx3bodydatas; + } products; + + // enablde tables + Configurable> enabledTables{"enabledTables", + {defaultParameters[0], nTables, nParameters, tableNames, parameterNames}, + "Produce this table: 0 - false, 1 - true"}; + std::vector mEnabledTables; // Vector of enabled tables + + // general options Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; + Configurable doTrackQA{"doTrackQA", false, "Flag to fill QA histograms for daughter tracks of (selected) decay3body candidates."}; + Configurable doVertexQA{"doVertexQA", false, "Flag to fill QA histograms for PV of (selected) events."}; + Configurable disableITSROFCut{"disableITSROFCut", false, "Disable ITS ROF border cut"}; + + // data processing options + Configurable doSkimmedProcessing{"doSkimmedProcessing", false, "Apply Zoroo counting in case of skimmed data input"}; + 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 onlyKeepInterestedTrigger{"onlyKeepInterestedTrigger", false, "Flag to keep only interested trigger"}; + Configurable doLikeSign{"doLikeSign", false, "Flag to produce like-sign background. If true, require the sign of pion is as same as deuteron but not proton."}; + // 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"}; - // CCDB TOF PID paras - 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 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"}; - // for KFParticle reconstruction struct : ConfigurableGroup { - Configurable kfDoDCAFitterPreMinimum{"kfDoDCAFitterPreMinimum", false, "KF: do DCAFitter pre-optimization before KF fit to include material corrections for decay3body vertex"}; - Configurable doTrackQA{"doTrackQA", false, "Flag to fill QA histograms for daughter tracks."}; - Configurable doVertexQA{"doVertexQA", false, "Flag to fill QA histograms for KFParticle PV."}; - Configurable maxEta{"maxEta", 0.9, "Maximum eta for daughter tracks"}; - Configurable mintpcNClsTrack{"mintpcNClsTrack", 70, "Minimum number of TPC clusters for proton and deuteron track"}; - Configurable mintpcNClsPion{"mintpcNClsPion", 70, "Minimum number of TPC clusters for pion track"}; - Configurable mintpcCrossedRows{"mintpcCrossedRows", 70, "Minimum number of TPC crossed rows for proton and deuteron track"}; - Configurable mintpcCrossedRowsPion{"mintpcCrossedRowsPion", 70, "Minimum number of TPC crossed rows for pion track"}; - Configurable mindcaXYPionPV{"mindcaXYPionPV", 0.1, "Minimum DCA XY of the pion daughter track to the PV"}; - Configurable mindcaXYProtonPV{"mindcaXYProtonPV", 0.1, "Minimum DCA XY of the proton daughter track to the PV"}; - Configurable mindcaZPionPV{"mindcaZPionPV", 0.1, "Minimum DCA Z of the pion daughter track to the PV"}; - Configurable mindcaZProtonPV{"mindcaZProtonPV", 0.1, "Minimum DCA Z of the proton daughter track to the PV"}; - Configurable maxtpcnSigma{"maxtpcnSigma", 5., "Maximum nSigma TPC for daughter tracks"}; - Configurable maxPionPt{"maxPionPt", 1.2, "Maximum pion pT"}; - Configurable minProtonPt{"minProtonPt", 1.2, "Maximum pion pT"}; - Configurable minDeuteronPt{"minDeuteronPt", 1.2, "Maximum pion pT"}; - Configurable lambdaMassWindow{"lambdaMassWindow", 0.01, "Window cut around lambda mass for proton-pion vertex with KFParticle"}; - Configurable maxDcaProDeu{"maxDcaProDeu", 1000., "Maximum geometrical distance between proton and deuteron at the SV in 3D with KFParticle"}; - Configurable maxDcaProPi{"maxDcaProPi", 1000., "Maximum geometrical distance between proton and pion at the SV in 3D with KFParticle"}; - Configurable maxDcaPiDe{"maxDcaPiDe", 1000., "Maximum geometrical distance between pion and deuteron at the SV in 3D with KFParticle"}; - Configurable maxDcaXYSVDau{"maxDcaXYSVDau", 1.0, "Maximum geometrical distance of daughter tracks from the SV in XY with KFParticle"}; - Configurable maxDcaXYSVPion{"maxDcaXYSVPion", 1.0, "Maximum geometrical distance of daughter tracks from the SV in XY with KFParticle"}; - Configurable minPtHt{"minPtHt", 0., "Minimum momentum for Hypertriton candidates with KFParticle"}; - Configurable maxPtHt{"maxPtHt", 36., "Maximum momentum for Hypertriton candidates with KFParticle"}; - Configurable minMassHt{"minMassHt", 2.96, "Minimum candidate mass with KFParticle"}; - Configurable maxMassHt{"maxMassHt", 3.05, "Maximum candidate mass with KFParticle"}; - Configurable maxChi2geo{"maxChi2geo", 1000., "Maximum chi2 geometrical with KFParticle"}; - Configurable minCosPA{"minCosPA", 0.5, "Minimum cosine pointing angle with KFParticle"}; - Configurable minCosPAxy{"minCosPAxy", 0.5, "Minimum cosine pointing angle in xy with KFParticle"}; - Configurable applyTopoSels{"applyTopoSels", false, "Apply selections constraining the mother to the PV with KFParticle"}; - Configurable maxChi2topo{"maxChi2topo", 1000., "Maximum chi2 topological with KFParticle"}; - } kfparticleConfigurations; - - // Filters and slices - Filter collisionFilter = (aod::evsel::sel8 == true && nabs(aod::collision::posZ) < 10.f); - Preslice perCollision = o2::aod::decay3body::collisionId; + 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; + + // Decay3body building options + struct : ConfigurableGroup { + std::string prefix = "decay3bodyBuilderOpts"; + // building options + Configurable useKFParticle{"useKFParticle", false, "Use KFParticle for decay3body building"}; + Configurable kfSetTopologicalConstraint{"kfSetTopologicalConstraint", false, "Set topological vertex constraint in case of KFParticle reconstruction"}; + Configurable buildOnlyTracked{"buildOnlyTracked", false, "Build only tracked decay3bodys"}; + Configurable useSelections{"useSelections", true, "Apply selections during decay3body building"}; + Configurable useChi2Selection{"useChi2Selection", true, "Apply chi2 selection during decay3body building"}; + Configurable useTPCforPion{"useTPCforPion", false, "Flag to ask for TPC info for pion track (PID, nClusters), false: pion track can be ITS only"}; + Configurable acceptTPCOnly{"acceptTPCOnly", false, "Accept TPC only tracks as daughters"}; + Configurable askOnlyITSMatch{"askOnlyITSMatch", true, "ask only ITS match to distinguish TPC only tracks"}; + Configurable calculateCovariance{"calculateCovariance", true, "Calculate candidate and daughter covariance matrices"}; + // daughter track selections + Configurable maxEtaDaughters{"maxEtaDaughters", 0.9, "Max eta of daughters"}; + Configurable minTPCNClProton{"minTPCNClProton", 90, "Min TPC NClusters of proton daughter"}; + Configurable minTPCNClPion{"minTPCNClPion", 70, "Min TPC NClusters of pion daughter"}; + Configurable minTPCNClDeuteron{"minTPCNClDeuteron", 100, "Min TPC NClusters of deuteron daughter"}; + Configurable minDCAProtonToPV{"minDCAProtonToPV", 0.1, "Min DCA of proton to PV"}; + Configurable minDCAPionToPV{"minDCAPionToPV", 0.1, "Min DCA of pion to PV"}; + Configurable minDCADeuteronToPV{"minDCADeuteronToPV", 0.1, "Min DCA of deuteron to PV"}; + Configurable minPtProton{"minPtProton", 0.3, "Min Pt of proton daughter"}; + Configurable minPtPion{"minPtPion", 0.1, "Min Pt of pion daughter"}; + Configurable minPtDeuteron{"minPtDeuteron", 0.6, "Min Pt of deuteron daughter"}; + Configurable maxPtProton{"maxPtProton", 5.0, "Max Pt of proton daughter"}; + Configurable maxPtPion{"maxPtPion", 1.2, "Max Pt of pion daughter"}; + Configurable maxPtDeuteron{"maxPtDeuteron", 10.0, "Max Pt of deuteron daughter"}; + Configurable maxTPCnSigma{"maxTPCnSigma", 5.0, "Min/max TPC nSigma of daughter tracks"}; + Configurable minTOFnSigmaDeuteron{"minTOFnSigmaDeuteron", -5.0, "Min TOF nSigma of deuteron daughter"}; + Configurable maxTOFnSigmaDeuteron{"maxTOFnSigmaDeuteron", 5.0, "Max TOF nSigma of deuteron daughter"}; + Configurable minPDeuteronUseTOF{"minPDeuteronUseTOF", 1.0, "Min P of deuteron to use TOF PID"}; + Configurable maxDCADauToSVaverage{"maxDCADauToSVaverage", 0.5, "Max DCA of daughters to SV (quadratic sum of daughter DCAs to SV / 3)"}; + // candidate selections + Configurable maxRapidity{"maxRapidity", 1.0, "Max rapidity of decay3body vertex"}; + Configurable minPt{"minPt", 2.0, "Min Pt of decay3body candidate"}; + Configurable maxPt{"maxPt", 5.0, "Max Pt of decay3body candidate"}; + Configurable minMass{"minMass", 2.96, "Min mass of decay3body candidate"}; + Configurable maxMass{"maxMass", 3.04, "Max mass of decay3body candidate"}; + Configurable minCtau{"minCtau", 0.0, "Min ctau of decay3body candidate"}; + Configurable maxCtau{"maxCtau", 100.0, "Max ctau of decay3body candidate"}; + Configurable minCosPA{"minCosPA", 0.9, "Min cosPA of decay3body candidate"}; + Configurable maxChi2{"maxChi2", 100.0, "Max chi2 of decay3body candidate"}; + } decay3bodyBuilderOpts; + + struct : ConfigurableGroup { + std::string prefix = "mixingOpts"; + Configurable n3bodyMixing{"n3bodyMixing", 0, "Number of decay3bodys to mix: 0 - value set to maximum bin entry in hDecay3BodyRadiusPhi, > 0 - manual setting"}; + Configurable mixingType{"mixingType", 0, "0: mix V0 from one event with bachelor from another, 1: mix pion and bachelor from one event with proton from another, 1: mix proton and bachelor from one event with pion from another "}; + ConfigurableAxis bins3BodyRadius{"mixingOpts.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{"mixingOpts.bins3BodyPhi", {VARIABLE_WIDTH, -180 * o2::constants::math::Deg2Rad, -120 * o2::constants::math::Deg2Rad, -60 * o2::constants::math::Deg2Rad, 0, 60 * o2::constants::math::Deg2Rad, 120 * o2::constants::math::Deg2Rad, 180 * o2::constants::math::Deg2Rad}, "Mixing bins - 3body phi (rad)"}; + ConfigurableAxis bins3BodyPhiDegree{"mixingOpts.bins3BodyPhiDegree", {VARIABLE_WIDTH, -180, -120, -60, 0, 60, 120, 180}, "Mixing bins - 3body phi (degree)"}; + ConfigurableAxis bins3BodyPosZ{"mixingOpts.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{"selectPVPosZ3bodyMixing", true, "Select same pvPosZ events in case of 3body mixing"}; + Configurable maxDeltaPVPosZ3bodyMixing{"maxDeltaPVPosZ3bodyMixing", 1., "max difference between PV z position in case of 3body mixing"}; + // SVertexer selections + Configurable doApplySVertexerCuts{"doApplySVertexerCuts", false, "Apply SVertexer selections during event mixing"}; + Configurable minPt2V0{"minPt2V0", 0.5, "Min Pt squared of V0"}; + Configurable maxTgl2V0{"maxTgl2V0", 4, "Max tgl squared of V0"}; + Configurable maxDCAXY2ToMeanVertex3bodyV0{"maxDCAXY2ToMeanVertex3bodyV0", 4, "Max DCA XY squared of V0 to mean vertex"}; + Configurable minCosPAXYMeanVertex3bodyV0{"minCosPAXYMeanVertex3bodyV0", 0.9, "Min cosPA XY of V0 to mean vertex"}; + Configurable minCosPA3bodyV0{"minCosPA3bodyV0", 0.8, "Min cosPA of V0"}; + Configurable maxRDiffV03body{"maxRDiffV03body", 3, "Max RDiff of V0 to 3body"}; + Configurable minPt3Body{"minPt3Body", 0.5, "Min Pt of 3body"}; + Configurable maxTgl3Body{"maxTgl3Body", 0.01, "Max tgl of 3body"}; + Configurable maxDCAXY3Body{"maxDCAXY3Body", 0.5, "Max DCA XY of 3body"}; + Configurable maxDCAZ3Body{"maxDCAZ3Body", 1.0, "Max DCA Z of 3body"}; + } mixingOpts; + + // Helper struct to contain MC information prior to filling + struct mc3Bodyinfo { + int label; + std::array genDecVtx{0.f}; + std::array genMomentum{0.f}; + float genCt; + float genPhi; + float genEta; + float genRapidity; + float genMomProton; + float genMomPion; + float genMomDeuteron; + float genPtProton; + float genPtPion; + float genPtDeuteron; + bool isTrueH3L; + bool isTrueAntiH3L; + bool isReco; + int motherPdgCode; + int daughterPrPdgCode; + int daughterPiPdgCode; + int daughterDePdgCode; + bool isDeuteronPrimary; + bool survivedEventSel; + }; + mc3Bodyinfo this3BodyMCInfo; + // CCDB and magnetic field 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::USEMatCorrNONE; + std::unordered_map ccdbCache; // Maps runNumber -> d_bz o2::base::MatLayerCylSet* lut = nullptr; - o2::vertexing::DCAFitterN<3> fitter3body; - o2::pid::tof::TOFResoParamsV2 mRespParamsV2; - void init(InitContext&) + // histogram registry + HistogramRegistry registry{"Registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // bachelor TOF PID + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; // to be updated in Init based on the hypothesis + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPIDLabeled; // to be updated in Init based on the hypothesis + // TOF response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + o2::aod::pidtofgeneric::TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + // 3body mixing + using Binning3BodyKF = ColumnBinningPolicy; + using Binning3BodyDCAfitter = ColumnBinningPolicy; + + // skimmed processing + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // tracked cluster size + std::vector fTrackedClSizeVector; + + // trigger info + std::vector isTriggeredCollision; + // MC info + std::vector isGoodCollision; + + void init(InitContext& initContext) { + zorroSummary.setObject(zorro.getZorroSummary()); + mRunNumber = 0; d_bz = 0; - maxSnp = 0.85f; // could be changed later - maxStep = 2.00f; // could be changed later - fitter3body.setPropagateToPCA(true); - fitter3body.setMaxR(200.); //->maxRIni3body - fitter3body.setMinParamChange(1e-3); - fitter3body.setMinRelChi2Change(0.9); - fitter3body.setMaxDZIni(1e9); - fitter3body.setMaxChi2(1e9); - fitter3body.setUseAbsDCA(d_UseAbsDCA); - - // Material correction in the DCA fitter - ccdb->setURL(ccdburl); + + mEnabledTables.resize(nTables, 0); + + // CCDB options + ccdb->setURL(ccdbConfigurations.ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); + // TOF PID parameters initialization + if (doprocessRealData == true || doprocessMonteCarlo == true) { + mTOFCalibConfig.metadataInfo = metadataInfo; + mTOFCalibConfig.inheritFromBaseTask(initContext); + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); + } + + // Set material correction if (useMatCorrType == 1) { LOGF(info, "TGeo correction requested, loading geometry"); if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); + ccdb->get(ccdbConfigurations.geoPath); } + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; } if (useMatCorrType == 2) { LOGF(info, "LUT correction requested, loading LUT"); - 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"); - - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(2, "CollIds"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(3, "Charge"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(4, "Eta"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(5, "TPCpid"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(6, "TPCNcls"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(7, "TPCRows"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(8, "DCAxyPV"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(9, "DCAzPV"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(10, "TrackPt"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(11, "NoV0"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(12, "HasSV"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(13, "DcaDau"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(14, "DCADauVtx"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(15, "Pt"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(16, "Mass"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(17, "CosPA"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(18, "CosPAxy"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(19, "Chi2geo"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->GetXaxis()->SetBinLabel(20, "Chi2topo"); - registry.get(HIST("hVtx3BodyCounterKFParticle"))->LabelsOption("v"); - - // Material correction in the DCA fitter - if (useMatCorrType == 1) - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - if (useMatCorrType == 2) + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(ccdbConfigurations.lutPath)); matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + } - fitter3body.setMatCorrType(matCorr); - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; + helper.fitterV0.setMatCorrType(matCorr); + helper.fitter3body.setMatCorrType(matCorr); + + // set bachelor PID + bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + bachelorTOFPIDLabeled.SetPidType(o2::track::PID::Deuteron); + + // set decay3body parameters in the helper + helper.decay3bodyselections.maxEtaDaughters = decay3bodyBuilderOpts.maxEtaDaughters; + helper.decay3bodyselections.minTPCNClProton = decay3bodyBuilderOpts.minTPCNClProton; + helper.decay3bodyselections.minTPCNClPion = decay3bodyBuilderOpts.minTPCNClPion; + helper.decay3bodyselections.minTPCNClDeuteron = decay3bodyBuilderOpts.minTPCNClDeuteron; + helper.decay3bodyselections.minDCAProtonToPV = decay3bodyBuilderOpts.minDCAProtonToPV; + helper.decay3bodyselections.minDCAPionToPV = decay3bodyBuilderOpts.minDCAPionToPV; + helper.decay3bodyselections.minDCADeuteronToPV = decay3bodyBuilderOpts.minDCADeuteronToPV; + helper.decay3bodyselections.minPtProton = decay3bodyBuilderOpts.minPtProton; + helper.decay3bodyselections.minPtPion = decay3bodyBuilderOpts.minPtPion; + helper.decay3bodyselections.minPtDeuteron = decay3bodyBuilderOpts.minPtDeuteron; + helper.decay3bodyselections.maxPtProton = decay3bodyBuilderOpts.maxPtProton; + helper.decay3bodyselections.maxPtPion = decay3bodyBuilderOpts.maxPtPion; + helper.decay3bodyselections.maxPtDeuteron = decay3bodyBuilderOpts.maxPtDeuteron; + helper.decay3bodyselections.maxTPCnSigma = decay3bodyBuilderOpts.maxTPCnSigma; + helper.decay3bodyselections.minTOFnSigmaDeuteron = decay3bodyBuilderOpts.minTOFnSigmaDeuteron; + helper.decay3bodyselections.maxTOFnSigmaDeuteron = decay3bodyBuilderOpts.maxTOFnSigmaDeuteron; + helper.decay3bodyselections.minPDeuteronUseTOF = decay3bodyBuilderOpts.minPDeuteronUseTOF; + helper.decay3bodyselections.maxDCADauToSVaverage = decay3bodyBuilderOpts.maxDCADauToSVaverage; + helper.decay3bodyselections.maxRapidity = decay3bodyBuilderOpts.maxRapidity; + helper.decay3bodyselections.minPt = decay3bodyBuilderOpts.minPt; + helper.decay3bodyselections.maxPt = decay3bodyBuilderOpts.maxPt; + helper.decay3bodyselections.minMass = decay3bodyBuilderOpts.minMass; + helper.decay3bodyselections.maxMass = decay3bodyBuilderOpts.maxMass; + helper.decay3bodyselections.minCtau = decay3bodyBuilderOpts.minCtau; + helper.decay3bodyselections.maxCtau = decay3bodyBuilderOpts.maxCtau; + helper.decay3bodyselections.minCosPA = decay3bodyBuilderOpts.minCosPA; + helper.decay3bodyselections.maxChi2 = decay3bodyBuilderOpts.maxChi2; + + // set SVertexer selection parameters in the helper + helper.svertexerselections.minPt2V0 = mixingOpts.minPt2V0; + helper.svertexerselections.maxTgl2V0 = mixingOpts.maxTgl2V0; + helper.svertexerselections.maxDCAXY2ToMeanVertex3bodyV0 = mixingOpts.maxDCAXY2ToMeanVertex3bodyV0; + helper.svertexerselections.minCosPAXYMeanVertex3bodyV0 = mixingOpts.minCosPAXYMeanVertex3bodyV0; + helper.svertexerselections.minCosPA3bodyV0 = mixingOpts.minCosPA3bodyV0; + helper.svertexerselections.maxRDiffV03body = mixingOpts.maxRDiffV03body; + helper.svertexerselections.minPt3Body = mixingOpts.minPt3Body; + helper.svertexerselections.maxTgl3Body = mixingOpts.maxTgl3Body; + helper.svertexerselections.maxDCAXY3Body = mixingOpts.maxDCAXY3Body; + helper.svertexerselections.maxDCAZ3Body = mixingOpts.maxDCAZ3Body; + + // list enabled process functions + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, " Decay3body builder: basic configuration listing"); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + if (doprocessRealData) { + LOGF(info, " ===> process function enabled: processRealData"); + } + if (doprocessRealDataReduced) { + LOGF(info, " ===> process function enabled: processRealDataReduced"); + } + if (doprocessRealDataReduced3bodyMixing) { + LOGF(info, " ===> process function enabled: processRealDataReduced3bodyMixing"); + } + if (doprocessMonteCarlo) { + LOGF(info, " ===> process function enabled: processMonteCarlo"); } - // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { - d_bz = d_bz_input; - fitter3body.setBz(d_bz); -#ifdef HomogeneousField - KFParticle::SetField(d_bz); -#endif - o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + // list enabled tables + for (int i = 0; i < nTables; i++) { + if (mEnabledTables[i]) { + LOGF(info, " -~> Table enabled: %s", tableNames[i]); } - 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; + // print base cuts + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, "-~> max daughter eta ..............: %f", decay3bodyBuilderOpts.maxEtaDaughters.value); + LOGF(info, "-~> min TPC ncls proton ...........: %i", decay3bodyBuilderOpts.minTPCNClProton.value); + LOGF(info, "-~> min TPC ncls pion .............: %i", decay3bodyBuilderOpts.minTPCNClPion.value); + LOGF(info, "-~> min TPC ncls bach .............: %i", decay3bodyBuilderOpts.minTPCNClDeuteron.value); + LOGF(info, "-~> min DCA proton to PV ..........: %f", decay3bodyBuilderOpts.minDCAProtonToPV.value); + LOGF(info, "-~> min DCA pion to PV ............: %f", decay3bodyBuilderOpts.minDCAPionToPV.value); + LOGF(info, "-~> min DCA bach to PV ............: %f", decay3bodyBuilderOpts.minDCADeuteronToPV.value); + LOGF(info, "-~> min pT proton .................: %f", decay3bodyBuilderOpts.minPtProton.value); + LOGF(info, "-~> min pT pion ...................: %f", decay3bodyBuilderOpts.minPtPion.value); + LOGF(info, "-~> min pT bach ...................: %f", decay3bodyBuilderOpts.minPtDeuteron.value); + LOGF(info, "-~> max pT proton .................: %f", decay3bodyBuilderOpts.maxPtProton.value); + LOGF(info, "-~> max pT pion ...................: %f", decay3bodyBuilderOpts.maxPtPion.value); + LOGF(info, "-~> max pT bach ...................: %f", decay3bodyBuilderOpts.maxPtDeuteron.value); + LOGF(info, "-~> max TPC nSigma ...............: %f", decay3bodyBuilderOpts.maxTPCnSigma.value); + LOGF(info, "-~> min TOF nSigma deuteron ......: %f", decay3bodyBuilderOpts.minTOFnSigmaDeuteron.value); + LOGF(info, "-~> max TOF nSigma deuteron ......: %f", decay3bodyBuilderOpts.maxTOFnSigmaDeuteron.value); + LOGF(info, "-~> min p bach use TOF ...........: %f", decay3bodyBuilderOpts.minPDeuteronUseTOF.value); + LOGF(info, "-~> max DCA dau at SV ............: %f", decay3bodyBuilderOpts.maxDCADauToSVaverage.value); + LOGF(info, "-~> max rapidity .................: %f", decay3bodyBuilderOpts.maxRapidity.value); + LOGF(info, "-~> min pT .......................: %f", decay3bodyBuilderOpts.minPt.value); + LOGF(info, "-~> max pT .......................: %f", decay3bodyBuilderOpts.maxPt.value); + LOGF(info, "-~> min mass .....................: %f", decay3bodyBuilderOpts.minMass.value); + LOGF(info, "-~> max mass .....................: %f", decay3bodyBuilderOpts.maxMass.value); + LOGF(info, "-~> min ctau .....................: %f", decay3bodyBuilderOpts.minCtau.value); + LOGF(info, "-~> max ctau .....................: %f", decay3bodyBuilderOpts.maxCtau.value); + LOGF(info, "-~> min cosPA ....................: %f", decay3bodyBuilderOpts.minCosPA.value); + LOGF(info, "-~> max chi2 .....................: %f", decay3bodyBuilderOpts.maxChi2.value); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + // bookkeeping histograms + auto h = registry.add("Counters/hTableBuildingStatistics", "hTableBuildingStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + auto h2 = registry.add("Counters/hInputStatistics", "hInputStatistics", kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + h2->SetTitle("Input table sizes"); + + // configure tables to generate + for (int i = 0; i < nTables; i++) { + h->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); + h2->GetXaxis()->SetBinLabel(i + 1, tableNames[i].c_str()); + h->SetBinContent(i + 1, 0); // mark all as disabled to start + + int f = enabledTables->get(tableNames[i].c_str(), "enable"); + if (f == 1) { + mEnabledTables[i] = 1; + h->SetBinContent(i + 1, 1); // mark enabled } - 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"; } - mRunNumber = bc.runNumber(); - // Set magnetic field value once known - 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); + if (mEnabledTables[kVtx3BodyDatas] && mEnabledTables[kMcVtx3BodyDatas]) { + LOG(fatal) << "Tables Vtx3BodyDatas and McVtx3BodyDatas cannot both be enabled at the same time. Choose one!"; } - // Initial TOF PID Paras, copied from PIDTOF.h - ccdb->setTimestamp(bc.timestamp()); - // 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 << "'"; + // Add histograms separately for different process functions + if (doprocessRealData == true || doprocessMonteCarlo == true) { + auto hEventCounter = registry.add("Counters/hEventCounter", "hEventCounter", HistType::kTH1D, {{2, 0.0f, 2.0f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "selected"); + hEventCounter->LabelsOption("v"); } - 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); + + if (doprocessMonteCarlo == true) { + auto hMcEventCounter = registry.add("Counters/hMcEventCounter", "hMcEventCounter", HistType::kTH1D, {{2, 0.0f, 2.0f}}); + hMcEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hMcEventCounter->GetXaxis()->SetBinLabel(2, "reconstructed"); + hMcEventCounter->LabelsOption("v"); + } + + if (doprocessRealData == true || doprocessRealDataReduced == true || doprocessMonteCarlo == true) { + if (doTrackQA) { // histograms for all daughter tracks of (selected) 3body candidates + registry.add("QA/Tracks/hTrackProtonTPCNcls", "hTrackProtonTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackPionTPCNcls", "hTrackPionTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackDeuteronTPCNcls", "hTrackDeuteronTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); + registry.add("QA/Tracks/hTrackProtonHasTPC", "hTrackProtonHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackPionHasTPC", "hTrackPionHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackDeuteronHasTPC", "hTrackDeuteronHasTPC", HistType::kTH1F, {{2, -0.5, 1.5, "has TPC"}}); + registry.add("QA/Tracks/hTrackDeuteronITSClusSizes", "hTrackDeuteronITSClusSizes", 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/hTrackDeuteronTPCPID", "hTrackDeuteronTPCPID", 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/hTrackDeuteronPt", "hTrackDeuteronPt", HistType::kTH1F, {{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}); } - } else if (loadResponseFromCCDB) { // Loading it from CCDB - LOG(info) << "Loading exp. sigma parametrization from CCDB, using path: " << parametrizationPath.value << " for timestamp " << bc.timestamp(); - o2::tof::ParameterCollection* paramCollection = ccdb->getForTimeStamp(parametrizationPath.value, bc.timestamp()); - 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(); + if (doVertexQA) { + registry.add("QA/Event/hAllSelEventsVtxZ", "hAllSelEventsVtxZ", HistType::kTH1F, {{500, -15.0f, 15.0f, "PV Z (cm)"}}); + 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})"}}); } } - 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()), bc.timestamp()), true); - mRespParamsV2.setTimeShiftParameters(ccdb->getForTimeStamp(Form("%s/neg", timeShiftCCDBPath.value.c_str()), bc.timestamp()), false); - } + + if (doprocessRealDataReduced3bodyMixing == true) { + auto h3bodyCombinationCounter = registry.add("Mixing/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("Mixing/hDecay3BodyRadiusPhi", "hDecay3BodyRadiusPhi", HistType::kTH2F, {mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}); + registry.add("Mixing/hDecay3BodyPosZ", "hDecay3BodyPosZ", HistType::kTH1F, {mixingOpts.bins3BodyPosZ}); } } - //------------------------------------------------------------------ - // Recalculate TOF PID for bachelors (deuteron), copied from PIDTOF.h - template - static float GetExpectedSigma(const o2::pid::tof::TOFResoParamsV2& parameters, const TrackType& track, const float tofSignal, const float collisionTimeRes, double mMassZ) + template + bool initCCDB(aod::BCsWithTimestamps const& bcs, TCollisions const& collisions) { - const float& mom = track.p(); - if (mom <= 0) { - return -999.f; + 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 } - const float dpp = parameters[9] + parameters[10] * mom + parameters[11] * mMassZ / mom; // mean relative pt resolution; - const float sigma = dpp * tofSignal / (1. + mom * mom / (mMassZ * mMassZ)); - return std::sqrt(sigma * sigma + parameters[12] * parameters[12] / mom / mom + parameters[4] * parameters[4] + collisionTimeRes * collisionTimeRes); - } - //------------------------------------------------------------------ - // function to select daughter track PID - template - bool selectTPCPID(TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackDeuteron) - { - if (abs(trackProton.tpcNSigmaPr()) > kfparticleConfigurations.maxtpcnSigma) { - return false; + if (mRunNumber == bc.runNumber()) { + return true; } - if (abs(trackPion.tpcNSigmaPi()) > kfparticleConfigurations.maxtpcnSigma) { - return false; + + if (doSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + zorro.populateHistRegistry(registry, bc.runNumber()); } - if (abs(trackDeuteron.tpcNSigmaDe()) > kfparticleConfigurations.maxtpcnSigma) { - return false; + + auto timestamp = bc.timestamp(); + o2::parameters::GRPMagField* grpmag = 0x0; + ccdb->clearCache(ccdbConfigurations.grpmagPath); + grpmag = ccdb->getSpecific(ccdbConfigurations.grpmagPath, timestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField for timestamp " << timestamp; } - return true; - } + o2::base::Propagator::initFieldFromGRP(grpmag); + // Fetch magnetic field from ccdb for current collision + auto d_bz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << d_bz << " kG"; + + // set magnetic field value for DCA fitter + helper.fitterV0.setBz(d_bz); + helper.fitter3body.setBz(d_bz); +// Set magnetic field for KF vertexing +#ifdef HomogeneousField + KFParticle::SetField(d_bz); +#endif - //------------------------------------------------------------------ - // 3body candidate builder - template - void buildVtx3BodyDataTable(TCollisionTable const& collision, TTrackTable const& /*tracks*/, aod::Decay3Bodys const& decay3bodys, int bachelorcharge = 1) - { + if (useMatCorrType == 2) { + // 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); + } - for (auto& vtx3body : decay3bodys) { + // mark run as configured + mRunNumber = bc.runNumber(); - registry.fill(HIST("hVtx3BodyCounter"), kVtxAll); + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bc); - auto t0 = vtx3body.template track0_as(); - auto t1 = vtx3body.template track1_as(); - auto t2 = vtx3body.template track2_as(); + return true; + } - if (t0.tpcNClsFound() < mintpcNCls && t1.tpcNClsFound() < mintpcNCls && t2.tpcNClsFound() < mintpcNCls) { - continue; + float getMagFieldFromRunNumber(int runNumber) + { + float magField; + // 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; + magField = ccdbCache[runNumber]; + // if not, retrieve it from CCDB + } else { + std::shared_ptr grpmag = std::make_shared(*ccdb->getForRun(ccdbConfigurations.grpmagPath, runNumber)); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField and " << ccdbConfigurations.grpPath << " of object GRPObject for run number " << runNumber; } - 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]; + o2::base::Propagator::initFieldFromGRP(grpmag.get()); + // Fetch magnetic field from ccdb for current collision + magField = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for run number " << runNumber << " with magnetic field of " << d_bz << " kZG"; - 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]; + // cache magnetic field info + ccdbCache[runNumber] = magField; + } + return magField; + } - 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]; + void initFittersWithMagField(int runNumber, float magField) + { + // 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 - 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; - } - registry.fill(HIST("hVtx3BodyCounter"), kVtxhasSV); + // update propagator + o2::base::Propagator::Instance()->setNominalBz(magField); - std::array pos = {0.}; - const auto& vtxXYZ = fitter3body.getPCACandidate(); - for (int i = 0; i < 3; i++) { - pos[i] = vtxXYZ[i]; - } + // Set magnetic field for KF vertexing +#ifdef HomogeneousField + KFParticle::SetField(magField); +#endif + // Set field for DCAfitter + helper.fitterV0.setBz(magField); + helper.fitter3body.setBz(magField); - 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 (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); + } + } - if (fitter3body.getChi2AtPCACandidate() > dcavtxdau) { - continue; - } - registry.fill(HIST("hVtx3BodyCounter"), kVtxDcaDau); + // ______________________________________________________________ + // function to build decay3body candidates + template + void buildCandidates(TBCs const&, + TCollisions const& collisions, + T3Bodys const& decay3bodys, + TMCParticles const& mcParticles, + TMCCollisions const& mcCollisions) + { + if (!(mEnabledTables[kVtx3BodyDatas] || mEnabledTables[kMcVtx3BodyDatas])) { + LOG(info) << "No request for candidate analysis table in place, skipping candidate building." << std::endl; + return; // don't do if no request for decay3bodys in place + } - 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) { - continue; - } - registry.fill(HIST("hVtx3BodyCounter"), kVtxCosPA); + // prepare MC container (not necessarily used) + std::vector mcParticleIsReco; - // Recalculate the TOF PID - double tofNsigmaDe = -999; - static constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f; // c in cm/ps + if constexpr (soa::is_table) { + isTriggeredCollision.clear(); + isTriggeredCollision.resize(collisions.size(), false); + } + // clear and reserve size for MC info vectors + if constexpr (soa::is_table) { + isGoodCollision.clear(); + mcParticleIsReco.clear(); + isGoodCollision.resize(mcCollisions.size(), false); + mcParticleIsReco.resize(mcParticles.size(), false); + } - if (t2.hasTOF()) { - double bachExpTime = t2.length() * sqrt((o2::constants::physics::MassDeuteron * o2::constants::physics::MassDeuteron) + (t2.tofExpMom() * t2.tofExpMom())) / (kCSPEED * t2.tofExpMom()); // L*E/(p*c) = L/v - double tofsignal = t2.trackTime() * 1000 + bachExpTime; - // double bachtime = t2.trackTime() * 1000 + bachExpTime - collision.collisionTime(); // in ps + // Loop over collisions for vertex QA + for (const auto& collision : collisions) { + if constexpr (soa::is_table) { // only do if NOT running over reduced data (already done in reducedCreator) - double expSigma = GetExpectedSigma(mRespParamsV2, t2, tofsignal, collision.collisionTimeRes(), o2::constants::physics::MassDeuteron); - double corrTofMom = t2.tofExpMom() / (1.f + t2.sign() * mRespParamsV2.getShift(t2.eta())); - double corrSignal = t2.length() * sqrt((o2::constants::physics::MassDeuteron * o2::constants::physics::MassDeuteron) + (corrTofMom * corrTofMom)) / (kCSPEED * corrTofMom) + mRespParamsV2.getTimeShift(t2.eta(), t2.sign()); - tofNsigmaDe = (tofsignal - collision.collisionTime() - corrSignal) / expSigma; - } + // all events + registry.fill(HIST("Counters/hEventCounter"), 0.5); - registry.fill(HIST("hBachelorTOFNSigmaDe"), t2.sign() * t2.p(), tofNsigmaDe); + // ITS ROF boarder cut if not disabled + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && !disableITSROFCut) { + continue; + } - 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, - tofNsigmaDe); - } - } + // Zorro event counting + bool isZorroSelected = false; + if (doSkimmedProcessing) { + isZorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); + if (isZorroSelected) { + isTriggeredCollision[collision.globalIndex()] = true; + } + } - //------------------------------------------------------------------ - // 3body candidate builder with KFParticle - template - void buildVtx3BodyDataTableKFParticle(TCollision const& collision, aod::Decay3Bodys const& decay3bodys, int bachelorcharge) - { - LOG(debug) << "buildVtx3BodyDataTableKFParticle called."; - for (auto& vtx3body : decay3bodys) { - LOG(debug) << "Entered decay3bodys loop."; - - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxAll); - - auto trackPos = vtx3body.template track0_as(); - auto trackNeg = vtx3body.template track1_as(); - auto trackBach = vtx3body.template track2_as(); - auto trackParCovPos = getTrackParCov(trackPos); - auto trackParCovNeg = getTrackParCov(trackNeg); - auto trackParCovBach = getTrackParCov(trackBach); - LOG(debug) << "Got all daughter tracks."; - - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - KFParticle kfpv(kfpVertex); - LOG(debug) << "Created KF PV."; - - bool isMatter = trackBach.sign() > 0 ? true : false; - - // ---------- fill trackQA and vertexQA 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()); - 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()); + // event selection + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { + continue; } - registry.fill(HIST("QA/Tracks/hTrackBachTPCPID"), trackBach.sign() * trackBach.tpcInnerParam(), trackBach.tpcNSigmaDe()); - registry.fill(HIST("QA/Tracks/hTrackBachPt"), trackBach.pt()); + + // selected events + registry.fill(HIST("Counters/hEventCounter"), 1.5); } - 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)); + // vertex QA and counting + if (doVertexQA) { + registry.fill(HIST("QA/Event/hAllSelEventsVtxZ"), collision.posZ()); registry.fill(HIST("QA/Event/hVtxX"), collision.posX()); registry.fill(HIST("QA/Event/hVtxY"), collision.posY()); registry.fill(HIST("QA/Event/hVtxZ"), collision.posZ()); @@ -590,488 +664,705 @@ struct decay3bodyBuilder { registry.fill(HIST("QA/Event/hVtxCovYZ"), collision.covYZ()); } - // -------- 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; - // } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxCollIds); - // 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) { - continue; + // In case of MC: reco collision survived event selection filter --> fill value for MC collision if collision is "true" MC collision + if constexpr (soa::is_table) { + if (collision.has_mcCollision()) { + isGoodCollision[collision.mcCollisionId()] = true; + } } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxCharge); - - // track eta - if (trackPos.eta() > kfparticleConfigurations.maxEta || trackNeg.eta() > kfparticleConfigurations.maxEta || trackBach.eta() > kfparticleConfigurations.maxEta) { + } // loop over collisions + + // Loop over all decay3bodys in same time frame + registry.fill(HIST("Counters/hInputStatistics"), kVtx3BodyDatas, decay3bodys.size()); + int lastRunNumber = -1; + for (const auto& decay3body : decay3bodys) { + // only build tracked decay3body if aksed + if (decay3bodyBuilderOpts.buildOnlyTracked && fTrackedClSizeVector[decay3body.globalIndex()] == 0) { continue; } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxEta); - // TPC PID - if (isMatter && !selectTPCPID(trackPos, trackNeg, trackBach)) { // hypertriton (proton, pi-, deuteron) - continue; - } else if (!isMatter && !selectTPCPID(trackNeg, trackPos, trackBach)) { // anti-hypertriton (anti-proton, pi+, deuteron) + // skip decay3body without assigned collision + /// TODO: do we want this?? + if (decay3body.collisionId() < 0) { continue; } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxTPCPID); - // number of TPC clusters - if (trackBach.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsTrack) { - continue; - } - if (isMatter && (trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion || trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsTrack)) { - continue; - } else if (!isMatter && (trackPos.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsPion || trackNeg.tpcNClsFound() <= kfparticleConfigurations.mintpcNClsTrack)) { - continue; - } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxTPCNcls); + // aquire collision + auto const& collision = collisions.rawIteratorAt(decay3body.collisionId()); - // number of TPC crossed rows - if (trackBach.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows) { - continue; + // event selection + if constexpr (soa::is_table) { // only when NOT running over reduced data + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && !disableITSROFCut) { // ITS ROF boarder cut if not disabled + continue; + } + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { + continue; + } + // Zorro + if (doSkimmedProcessing && onlyKeepInterestedTrigger && !isTriggeredCollision[collision.globalIndex()]) { + continue; + } } - if (isMatter && (trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion || trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { - continue; - } else if (!isMatter && (trackPos.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRowsPion || trackNeg.tpcNClsCrossedRows() <= kfparticleConfigurations.mintpcCrossedRows)) { - continue; + + // initialise CCDB from run number saved in reduced collisions table when running over reduced data + if constexpr (!soa::is_table) { // only do if running over reduced data (otherwise CCDB is initialised in process function) + if (collision.runNumber() != lastRunNumber) { + initFittersWithMagField(collision.runNumber(), getMagFieldFromRunNumber(collision.runNumber())); + lastRunNumber = collision.runNumber(); // Update the last run number + LOG(debug) << "CCDB initialized for run " << lastRunNumber; + } } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxTPCRows); - LOG(debug) << "Basic track selections done."; - - // 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.covXX(), 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(); - if (isMatter && (fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { - continue; - } else if (!isMatter && (fabs(TrackPosDcaXY) <= kfparticleConfigurations.mindcaXYPionPV || fabs(TrackNegDcaXY) <= kfparticleConfigurations.mindcaXYProtonPV)) { - continue; + + // aquire tracks + auto trackPos = decay3body.template track0_as(); + auto trackNeg = decay3body.template track1_as(); + auto trackDeuteron = decay3body.template track2_as(); + int protonSign = doLikeSign ? -trackDeuteron.sign() : trackDeuteron.sign(); + auto trackProton = protonSign > 0 ? trackPos : trackNeg; + auto trackPion = protonSign > 0 ? trackNeg : trackPos; + + // get deuteron TOF PID + float tofNSigmaDeuteron; + if constexpr (!soa::is_table) { // running over derived data + tofNSigmaDeuteron = trackDeuteron.tofNSigmaDe(); + } else if constexpr (soa::is_table) { // running over AO2Ds + if constexpr (soa::is_table) { // running over MC (track table with labels) + tofNSigmaDeuteron = getTOFnSigma(mRespParamsV3, collision, trackDeuteron); + } else { // running over real data + tofNSigmaDeuteron = getTOFnSigma(mRespParamsV3, collision, trackDeuteron); + } } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxDCAxyPV); - if (isMatter && (fabs(mDcaInfoCovNeg.getZ()) <= kfparticleConfigurations.mindcaZPionPV || fabs(mDcaInfoCovPos.getZ()) <= kfparticleConfigurations.mindcaZProtonPV)) { - continue; - } else if (!isMatter && (fabs(mDcaInfoCovPos.getZ()) <= kfparticleConfigurations.mindcaZPionPV || fabs(mDcaInfoCovNeg.getZ()) <= kfparticleConfigurations.mindcaZProtonPV)) { + + /// build Decay3body candidate + if (!helper.buildDecay3BodyCandidate(collision, + trackProton, + trackPion, + trackDeuteron, + decay3body.globalIndex(), + tofNSigmaDeuteron, + fTrackedClSizeVector[decay3body.globalIndex()], + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useChi2Selection, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.askOnlyITSMatch, + decay3bodyBuilderOpts.calculateCovariance, + false /*isEventMixing*/, + false /*applySVertexerCuts*/)) { continue; } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxDCAzPV); - // pT selection - if (trackBach.pt() <= kfparticleConfigurations.minDeuteronPt) { - continue; + // fill QA histograms + if (doTrackQA) { // histograms filled for daughter tracks of (selected) 3body candidates + registry.fill(HIST("QA/Tracks/hTrackProtonTPCNcls"), trackProton.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackPionTPCNcls"), trackPion.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronTPCNcls"), trackDeuteron.tpcNClsFound()); + registry.fill(HIST("QA/Tracks/hTrackProtonHasTPC"), trackProton.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackPionHasTPC"), trackPion.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronHasTPC"), trackDeuteron.hasTPC()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronITSClusSizes"), trackDeuteron.itsClusterSizes()); + registry.fill(HIST("QA/Tracks/hTrackProtonTPCPID"), trackProton.sign() * trackProton.tpcInnerParam(), trackProton.tpcNSigmaPr()); + registry.fill(HIST("QA/Tracks/hTrackPionTPCPID"), trackPion.sign() * trackPion.tpcInnerParam(), trackPion.tpcNSigmaPi()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronTPCPID"), trackDeuteron.sign() * trackDeuteron.tpcInnerParam(), trackDeuteron.tpcNSigmaDe()); + registry.fill(HIST("QA/Tracks/hTrackProtonPt"), trackProton.pt()); + registry.fill(HIST("QA/Tracks/hTrackPionPt"), trackPion.pt()); + registry.fill(HIST("QA/Tracks/hTrackDeuteronPt"), trackDeuteron.pt()); } - if (isMatter && (trackNeg.pt() > kfparticleConfigurations.maxPionPt || trackPos.pt() <= kfparticleConfigurations.minProtonPt)) { - continue; - } else if (!isMatter && (trackPos.pt() > kfparticleConfigurations.maxPionPt || trackNeg.pt() <= kfparticleConfigurations.minProtonPt)) { - continue; + + // generate analysis tables with current candidate (only Vtx3BodyDatas is filled here, McVtx3BodyDatas table is filled later) + if (!mEnabledTables[kMcVtx3BodyDatas]) { + fillAnalysisTables(); } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxTrackPt); - - // -------- STEP 2: fit vertex with proton and pion -------- - // Fit vertex with DCA fitter to find minimization point --> uses material corrections implicitly - if (kfparticleConfigurations.kfDoDCAFitterPreMinimum) { - 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!"; + + // ___________________________________________________________ + // MC handling part: matching of reconstructed candidates + // ___________________________________________________________ + // fill MC table with reco MC candidate information and gen information if matched to MC particle + if constexpr (soa::is_table) { + // MC info + resetMCInfo(this3BodyMCInfo); + this3BodyMCInfo.isReco = true; + + // set flag if selected reco collision has matched gen collision + if (collision.has_mcCollision()) { // reco collision is matched to gen collision + this3BodyMCInfo.survivedEventSel = isGoodCollision[collision.mcCollisionId()]; + } else { + this3BodyMCInfo.survivedEventSel = false; // false if reco collision not matched to gen collision + } + + // check if daughters have MC particle + if (!trackProton.has_mcParticle() || !trackPion.has_mcParticle() || !trackDeuteron.has_mcParticle()) { continue; } - // 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."; - } + // get MC daughter particles + auto mcTrackProton = trackProton.template mcParticle_as(); + auto mcTrackPion = trackPion.template mcParticle_as(); + auto mcTrackDeuteron = trackDeuteron.template mcParticle_as(); + + // set daughter MC info (also for non-matched candidates) + this3BodyMCInfo.daughterPrPdgCode = mcTrackProton.pdgCode(); + this3BodyMCInfo.daughterPiPdgCode = mcTrackPion.pdgCode(); + this3BodyMCInfo.daughterDePdgCode = mcTrackDeuteron.pdgCode(); + this3BodyMCInfo.isDeuteronPrimary = mcTrackDeuteron.isPhysicalPrimary(); + this3BodyMCInfo.genMomProton = mcTrackProton.p(); + this3BodyMCInfo.genMomPion = mcTrackPion.p(); + this3BodyMCInfo.genMomDeuteron = mcTrackDeuteron.p(); + this3BodyMCInfo.genPtProton = mcTrackProton.pt(); + this3BodyMCInfo.genPtPion = mcTrackPion.pt(); + this3BodyMCInfo.genPtDeuteron = mcTrackDeuteron.pt(); + + // check if reco mother is true H3L/Anti-H3l + bool isMuonReco; + int motherID = checkH3LTruth(mcTrackProton, mcTrackPion, mcTrackDeuteron, isMuonReco); + + // get generated mother MC info + if (motherID > 0) { + auto mcTrackH3L = mcParticles.rawIteratorAt(motherID); + this3BodyMCInfo.motherPdgCode = mcTrackH3L.pdgCode(); + this3BodyMCInfo.label = motherID; + this3BodyMCInfo.genMomentum = {mcTrackH3L.px(), mcTrackH3L.py(), mcTrackH3L.pz()}; + this3BodyMCInfo.genDecVtx = {mcTrackProton.vx(), mcTrackProton.vy(), mcTrackProton.vz()}; + this3BodyMCInfo.genCt = RecoDecay::sqrtSumOfSquares(mcTrackProton.vx() - mcTrackH3L.vx(), mcTrackProton.vy() - mcTrackH3L.vy(), mcTrackProton.vz() - mcTrackH3L.vz()) * o2::constants::physics::MassHyperTriton / mcTrackH3L.p(); + this3BodyMCInfo.genPhi = mcTrackH3L.phi(); + this3BodyMCInfo.genEta = mcTrackH3L.eta(); + this3BodyMCInfo.genRapidity = mcTrackH3L.y(); + this3BodyMCInfo.isTrueH3L = this3BodyMCInfo.motherPdgCode > 0 ? true : false; + this3BodyMCInfo.isTrueAntiH3L = this3BodyMCInfo.motherPdgCode < 0 ? true : false; + } - // 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 - KFParticle KFV0; - int nDaughters = 2; - const KFParticle* Daughters[2] = {&kfpProton, &kfpPion}; - KFV0.SetConstructMethod(2); - try { - KFV0.Construct(Daughters, nDaughters); - } catch (std::runtime_error& e) { - LOG(debug) << "Failed to create V0 vertex from daughter tracks." << e.what(); - continue; - } - KFV0.TransportToDecayVertex(); - LOG(debug) << "V0 constructed."; + // fill analysis tables (only McVtx3BodyDatas is filled here) + fillAnalysisTables(); - // check V0 mass and set mass constraint - float massV0, sigmaMassV0; - KFV0.GetMass(massV0, sigmaMassV0); - if (abs(massV0 - constants::physics::MassLambda) <= kfparticleConfigurations.lambdaMassWindow) { - continue; - } - KFParticle KFV0Mass = KFV0; - KFV0Mass.SetNonlinearMassConstraint(o2::constants::physics::MassLambda); - float chi2massV0 = KFV0Mass.GetChi2() / KFV0Mass.GetNDF(); - LOG(debug) << "V0 mass constraint applied."; - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxNoV0); - - // -------- STEP 3: fit vertex with V0 and deuteron -------- - // Create KFParticle object from deuteron track - KFParticle kfpDeuteron; - kfpDeuteron = createKFParticleFromTrackParCov(trackParCovBach, trackBach.sign() * bachelorcharge, constants::physics::MassDeuteron); - LOG(debug) << "KFParticle created from deuteron track."; - // Add deuteron to V0 vertex - KFParticle KFHt; - KFHt = KFV0; - KFHt.SetConstructMethod(2); - try { - KFHt.AddDaughter(kfpDeuteron); - } catch (std::runtime_error& e) { - LOG(debug) << "Failed to create Hyper triton from V0 and deuteron." << e.what(); - continue; + // mark mcParticle as reconstructed + if (this3BodyMCInfo.label > -1) { + mcParticleIsReco[this3BodyMCInfo.label] = true; + } + } // constexpr requires mcParticles check + } // decay3body loop + + // ____________________________________________________________________ + // MC handling part: generated information of non-reco candidates + // ____________________________________________________________________ + if constexpr (soa::is_table) { + for (const auto& mcparticle : mcParticles) { + // MC info + resetMCInfo(this3BodyMCInfo); + + // skip MC particle if reconstructed and already filled previously + if (mcParticleIsReco[mcparticle.globalIndex()] == true) { + continue; + } + this3BodyMCInfo.isReco = false; + + // set flag if corresponding MC collision has matched reconstructed collision which passed event selection + this3BodyMCInfo.survivedEventSel = isGoodCollision[mcparticle.mcCollisionId()]; + + // check if MC particle is hypertriton + if (std::abs(mcparticle.pdgCode()) != o2::constants::physics::Pdg::kHyperTriton) { + continue; + } + + // check daughter identities + bool haveProton = false, havePion = false, haveDeuteron = false; + bool haveAntiProton = false, haveAntiPion = false, haveAntiDeuteron = false; + for (const auto& mcparticleDaughter : mcparticle.template daughters_as()) { + if (mcparticleDaughter.pdgCode() == PDG_t::kProton) + haveProton = true; + if (mcparticleDaughter.pdgCode() == PDG_t::kProtonBar) + haveAntiProton = true; + if (mcparticleDaughter.pdgCode() == PDG_t::kPiPlus) + havePion = true; + if (mcparticleDaughter.pdgCode() == PDG_t::kPiMinus) + haveAntiPion = true; + if (mcparticleDaughter.pdgCode() == o2::constants::physics::Pdg::kDeuteron) + haveDeuteron = true; + if (mcparticleDaughter.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) + haveAntiDeuteron = true; + } + + // check if hypertriton decayed via 3-body decay and is particle or anti-particle + if ((haveProton && haveAntiPion && haveDeuteron && !(haveAntiProton || havePion || haveAntiDeuteron)) || (haveAntiProton && havePion && haveAntiDeuteron && !(haveProton || haveAntiPion || haveDeuteron))) { + if (mcparticle.pdgCode() > 0) { + this3BodyMCInfo.isTrueH3L = true; + } else if (mcparticle.pdgCode() < 0) { + this3BodyMCInfo.isTrueAntiH3L = true; + } + // get daughters + for (const auto& mcparticleDaughter : mcparticle.template daughters_as()) { + if (std::abs(mcparticleDaughter.pdgCode()) == PDG_t::kProton) { // proton + this3BodyMCInfo.genMomProton = mcparticleDaughter.p(); + this3BodyMCInfo.genPtProton = mcparticleDaughter.pt(); + this3BodyMCInfo.daughterPrPdgCode = mcparticleDaughter.pdgCode(); + this3BodyMCInfo.genDecVtx = {mcparticleDaughter.vx(), mcparticleDaughter.vy(), mcparticleDaughter.vz()}; + } else if (std::abs(mcparticleDaughter.pdgCode()) == PDG_t::kPiPlus) { // pion + this3BodyMCInfo.genMomPion = mcparticleDaughter.p(); + this3BodyMCInfo.genPtPion = mcparticleDaughter.pt(); + this3BodyMCInfo.daughterPiPdgCode = mcparticleDaughter.pdgCode(); + } else if (std::abs(mcparticleDaughter.pdgCode()) == o2::constants::physics::Pdg::kDeuteron) { // deuteron + this3BodyMCInfo.genMomDeuteron = mcparticleDaughter.p(); + this3BodyMCInfo.genPtDeuteron = mcparticleDaughter.pt(); + this3BodyMCInfo.daughterDePdgCode = mcparticleDaughter.pdgCode(); + this3BodyMCInfo.isDeuteronPrimary = mcparticleDaughter.isPhysicalPrimary(); + } + } + } else { + continue; // stop if particle is not decayed via 3-body decay + } + + // calculate ctau + this3BodyMCInfo.genCt = RecoDecay::sqrtSumOfSquares(this3BodyMCInfo.genDecVtx[0] - mcparticle.vx(), this3BodyMCInfo.genDecVtx[1] - mcparticle.vy(), this3BodyMCInfo.genDecVtx[2] - mcparticle.vz()) * o2::constants::physics::MassHyperTriton / mcparticle.p(); + + // fill MCDecay3BodyCores table if requested + if (mEnabledTables[kMcVtx3BodyDatas]) { + products.mcvtx3bodydatas(-1, // sign + -1., -1., // mass, massV0 + -1., -1., -1., // position + -1., -1., -1., // momentum + -1., // chi2 + -1., // trackedClSize + -1., -1., -1., // momProton + -1., -1., -1., // momPion + -1., -1., -1., // momDeuteron + -1., -1., -1., // trackDCAxyToPV: 0 - proton, 1 - pion, 2 - deuteron + -1., -1., -1., // trackDCAToPV: 0 - proton, 1 - pion, 2 - deuteron + -1., -1., -1., // trackDCAxyToPVprop: 0 - proton, 1 - pion, 2 - deuteron + -1., -1., -1., // trackDCAToPVprop: 0 - proton, 1 - pion, 2 - deuteron + -1., -1., -1., // daughterDCAtoSV: 0 - proton, 1 - pion, 2 - deuteron + -1., // daughterDCAtoSVaverage + -1., -1., // cosPA, ctau + -1., -1., -1., -1., // tpcNsigma: 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + -1., // tofNsigmaDeuteron + -1., -1., -1., // average ITS cluster sizes: proton, pion, deuteron + -1., -1., -1., // TPCNCl: proton, pion, deuteron + -1., // pidForTrackingDeuteron + // MC information + mcparticle.px(), mcparticle.py(), mcparticle.pz(), + this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], + this3BodyMCInfo.genCt, + mcparticle.phi(), mcparticle.eta(), mcparticle.y(), + this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, + this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, + this3BodyMCInfo.isTrueH3L, this3BodyMCInfo.isTrueAntiH3L, + this3BodyMCInfo.isReco, + mcparticle.pdgCode(), + this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, + this3BodyMCInfo.isDeuteronPrimary, + this3BodyMCInfo.survivedEventSel); + } // enabled table check + } // mcParticles loop + } // constexpr requires mcParticles check + } + + // ______________________________________________________________ + // function to build mixed decay3body candidates + template + void buildMixedCandidates(TRedDecay3Bodys const& decay3bodys, TBinningType const& binningType) + { + if (!mEnabledTables[kVtx3BodyDatas]) { + return; // don't do if no request for decay3bodys in place + } + + // Strictly upper index policy for decay3body objects binned by radius, phi + for (const auto& [decay3body0, decay3body1] : selfPairCombinations(binningType, mixingOpts.n3bodyMixing, -1, decay3bodys)) { + auto trackPos0 = decay3body0.template track0_as(); + auto trackNeg0 = decay3body0.template track1_as(); + auto trackDeuteron0 = decay3body0.template track2_as(); + auto trackPos1 = decay3body1.template track0_as(); + auto trackNeg1 = decay3body1.template track1_as(); + auto trackDeuteron1 = decay3body1.template track2_as(); + + // assign tracks + auto trackProton0 = trackPos0; + auto trackPion0 = trackNeg0; + auto trackProton1 = trackPos1; + auto trackPion1 = trackNeg1; + if (trackDeuteron0.sign() < 0) { + trackProton0 = trackNeg0; + trackPion0 = trackPos0; } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxhasSV); - LOG(debug) << "Hypertriton vertex constructed."; - - // -------- STEP 4: selections after geometrical vertex fit -------- - // Get updated daughter tracks - kfpProton.SetProductionVertex(KFHt); - kfpPion.SetProductionVertex(KFHt); - kfpDeuteron.SetProductionVertex(KFHt); - LOG(debug) << "Topo constraint applied to daughters."; - // daughter DCAs - if ((kfpProton.GetDistanceFromParticle(kfpPion) >= kfparticleConfigurations.maxDcaProPi) || (kfpProton.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaProDeu) || (kfpPion.GetDistanceFromParticle(kfpDeuteron) >= kfparticleConfigurations.maxDcaPiDe)) { - continue; + if (trackDeuteron1.sign() < 0) { + trackProton1 = trackNeg1; + trackPion1 = trackPos1; } - float DCAvtxDaughters3D = kfpProton.GetDistanceFromParticle(kfpPion) + kfpProton.GetDistanceFromParticle(kfpDeuteron) + kfpPion.GetDistanceFromParticle(kfpDeuteron); - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxDcaDau); - LOG(debug) << "DCA selection after vertex fit applied."; - // daughter DCAs to vertex - if (kfpProton.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau || kfpPion.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVPion || kfpDeuteron.GetDistanceFromVertexXY(KFHt) >= kfparticleConfigurations.maxDcaXYSVDau) { - continue; - } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxDcaDauVtx); - LOG(debug) << "DCA to vertex selection after vertex fit applied."; + registry.fill(HIST("Mixing/h3bodyCombinationCounter"), 0.5); - // -------- STEP 5: candidate selection after geometrical vertex fit -------- - // Pt selection - if (KFHt.GetPt() <= kfparticleConfigurations.minPtHt || KFHt.GetPt() >= kfparticleConfigurations.maxPtHt) { + // only combine if from different event + if (decay3body0.collisionId() == decay3body1.collisionId()) { continue; } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxPt); + registry.fill(HIST("Mixing/h3bodyCombinationCounter"), 1.5); + + // collision vertex selection + auto collision0 = decay3body0.template collision_as(); + auto collision1 = decay3body1.template collision_as(); - // Mass window - float massHt, sigmaMassHt; - KFHt.GetMass(massHt, sigmaMassHt); - if (massHt <= kfparticleConfigurations.minMassHt || massHt >= kfparticleConfigurations.maxMassHt) { + // get b_z value for each collision (from CCDB or cache) and cache it for that run number + float magFieldCol0 = getMagFieldFromRunNumber(collision0.runNumber()); + float magFieldCol1 = getMagFieldFromRunNumber(collision1.runNumber()); + + // only combine if collision similar in VtxZ + if (mixingOpts.selectPVPosZ3bodyMixing && std::abs(collision0.posZ() - collision1.posZ()) > mixingOpts.maxDeltaPVPosZ3bodyMixing) { continue; } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxMass); + registry.fill(HIST("Mixing/h3bodyCombinationCounter"), 2.5); - // cos(PA) to PV - if (abs(cpaFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPA) { - continue; + // Charge selections + // same magnetic fields --> mix matter with matter + if ((magFieldCol0 / std::abs(magFieldCol0)) == (magFieldCol1 / std::abs(magFieldCol1))) { + if (trackDeuteron0.sign() != trackDeuteron1.sign()) { + continue; + } + } + // opposite magnetic fields --> mix matter with anti-matter + if ((magFieldCol0 / std::abs(magFieldCol0)) != (magFieldCol1 / std::abs(magFieldCol1))) { + if (trackDeuteron0.sign() == trackDeuteron1.sign()) { + continue; + } } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxCosPA); - // cos(PA) xy to PV - if (abs(cpaXYFromKF(KFHt, kfpv)) <= kfparticleConfigurations.minCosPAxy) { + // don't mix 3body with itself + if ((trackDeuteron0.globalIndex() == trackDeuteron1.globalIndex()) || (trackProton0.globalIndex() == trackProton1.globalIndex()) || (trackPion0.globalIndex() == trackPion1.globalIndex())) { continue; } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxCosPAXY); + registry.fill(HIST("Mixing/h3bodyCombinationCounter"), 3.5); - // chi2 geometrical - float chi2geoNDF = KFHt.GetChi2() / KFHt.GetNDF(); - if (chi2geoNDF >= kfparticleConfigurations.maxChi2geo) { - continue; + // candidate analysis + // mix deuteron + if (mixingOpts.mixingType == 0) { + doMixing(collision0, trackProton0, trackPion0, trackDeuteron1, magFieldCol0); + doMixing(collision1, trackProton1, trackPion1, trackDeuteron0, magFieldCol1); } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxChi2geo); - LOG(debug) << "Basic selections after vertex fit done."; - - // -------- STEP 6: topological constraint -------- - /// Set vertex constraint and topological selection - KFParticle KFHtPV = KFHt; - KFHtPV.SetProductionVertex(kfpv); - KFHtPV.TransportToDecayVertex(); - float chi2topoNDF = KFHtPV.GetChi2() / KFHtPV.GetNDF(); - if (kfparticleConfigurations.applyTopoSels && chi2topoNDF >= kfparticleConfigurations.maxChi2topo) { - continue; + // mix proton + if (mixingOpts.mixingType == 1) { + doMixing(collision0, trackProton1, trackPion0, trackDeuteron0, magFieldCol0); + doMixing(collision1, trackProton0, trackPion1, trackDeuteron1, magFieldCol1); } - registry.fill(HIST("hVtx3BodyCounterKFParticle"), kKfVtxChi2topo); - LOG(debug) << "Topological constraint applied."; - - //------------------------------------------------------------------ - // Recalculate the bachelor TOF PID - double tofNsigmaDe = -999; - static constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f; // c in cm/ps - if (trackBach.hasTOF()) { - double bachExpTime = trackBach.length() * sqrt((o2::constants::physics::MassDeuteron * o2::constants::physics::MassDeuteron) + (trackBach.tofExpMom() * trackBach.tofExpMom())) / (kCSPEED * trackBach.tofExpMom()); // L*E/(p*c) = L/v - double tofsignal = trackBach.trackTime() * 1000 + bachExpTime; - // double bachtime = trackBach.trackTime() * 1000 + bachExpTime - collision.collisionTime(); // in ps - - double expSigma = GetExpectedSigma(mRespParamsV2, trackBach, tofsignal, collision.collisionTimeRes(), o2::constants::physics::MassDeuteron); - double corrTofMom = trackBach.tofExpMom() / (1.f + trackBach.sign() * mRespParamsV2.getShift(trackBach.eta())); - double corrSignal = trackBach.length() * sqrt((o2::constants::physics::MassDeuteron * o2::constants::physics::MassDeuteron) + (corrTofMom * corrTofMom)) / (kCSPEED * corrTofMom) + mRespParamsV2.getTimeShift(trackBach.eta(), trackBach.sign()); - tofNsigmaDe = (tofsignal - collision.collisionTime() - corrSignal) / expSigma; + // mix pion + if (mixingOpts.mixingType == 2) { + doMixing(collision0, trackProton0, trackPion1, trackDeuteron0, magFieldCol0); + doMixing(collision1, trackProton1, trackPion0, trackDeuteron1, magFieldCol1); } - registry.fill(HIST("hBachelorTOFNSigmaDe"), trackBach.sign() * trackBach.p(), tofNsigmaDe); - LOG(debug) << "Bachelor TOF info calculated."; - - //------------------------------------------------------------------ - // table filling - kfvtx3bodydata( - collision.globalIndex(), trackPos.globalIndex(), trackNeg.globalIndex(), trackBach.globalIndex(), vtx3body.globalIndex(), - // hypertriton - massHt, - KFHt.GetX(), KFHt.GetY(), KFHt.GetZ(), - KFHt.GetPx(), KFHt.GetPy(), KFHt.GetPz(), KFHt.GetPt(), - KFHt.GetQ(), - KFHt.GetDistanceFromVertex(kfpv), KFHt.GetDistanceFromVertexXY(kfpv), - cpaFromKF(KFHt, kfpv), // before topo constraint - cpaXYFromKF(KFHt, kfpv), - cpaFromKF(KFHtPV, kfpv), // after topo constraint - cpaXYFromKF(KFHtPV, kfpv), - KFHtPV.GetDecayLength(), KFHtPV.GetDecayLengthXY(), // decay length defined after topological constraint - KFHtPV.GetDecayLength() / KFHtPV.GetErrDecayLength(), // ldl - chi2geoNDF, chi2topoNDF, - // V0 - massV0, chi2massV0, - // daughter momenta - kfpProton.GetPx(), kfpProton.GetPy(), kfpProton.GetPz(), - kfpPion.GetPx(), kfpPion.GetPy(), kfpPion.GetPz(), - kfpDeuteron.GetPx(), kfpDeuteron.GetPy(), kfpDeuteron.GetPz(), - // daughter DCAs KF - kfpProton.GetDistanceFromVertex(kfpv), - kfpPion.GetDistanceFromVertex(kfpv), - kfpDeuteron.GetDistanceFromVertex(kfpv), - kfpProton.GetDistanceFromVertexXY(kfpv), - kfpPion.GetDistanceFromVertexXY(kfpv), - kfpDeuteron.GetDistanceFromVertexXY(kfpv), - kfpProton.GetDistanceFromVertexXY(KFHt), - kfpPion.GetDistanceFromVertexXY(KFHt), - kfpDeuteron.GetDistanceFromVertexXY(KFHt), - kfpProton.GetDistanceFromParticle(kfpPion), - kfpProton.GetDistanceFromParticle(kfpDeuteron), - kfpPion.GetDistanceFromParticle(kfpDeuteron), - DCAvtxDaughters3D, - // daughter DCAs to PV propagated with material - TrackPosDcaXY, TrackNegDcaXY, TrackBachDcaXY, - // daughter signs - trackPos.sign(), - trackNeg.sign(), - trackBach.sign(), - // bachelor TOF PID - tofNsigmaDe); - LOG(debug) << "Table filled."; - } + } // end decay3body combinations loop } - //------------------------------------------------------------------ - void processRun3(aod::Collision const& collision, FullTracksExtIU const& tracksIU, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) + // ______________________________________________________________ + // function to calculate correct TOF nSigma for deuteron track + template + double getTOFnSigma(o2::pid::tof::TOFResoParamsV3 const& parameters, TCollision const& collision, TTrack const& track) { - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - buildVtx3BodyDataTable(collision, tracksIU, decay3bodys, bachelorcharge); + // TOF PID of deuteron + if (track.has_collision() && track.hasTOF()) { + auto originalcol = track.template collision_as(); + if constexpr (isMC) { + return bachelorTOFPIDLabeled.GetTOFNSigma(parameters, track, originalcol, collision); + } else { + return bachelorTOFPID.GetTOFNSigma(parameters, track, originalcol, collision); + } + } + return -999; } - PROCESS_SWITCH(decay3bodyBuilder, processRun3, "Produce DCA fitter decay3body tables", true); - void processRun3withKFParticle(soa::Filtered::iterator const& collision, FullTracksExtPIDIU const& /*tracksIU*/, aod::Decay3Bodys const& decay3bodys, aod::BCsWithTimestamps const&) + // ______________________________________________________________ + // function to fill analysis tables + void fillAnalysisTables() { - // for (const auto& collision : collisions) { - LOG(debug) << "Start of processRun3withKFParticle."; - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - LOG(debug) << "CCDB initialised."; - - // slice Decay3Body table by collision - // const uint64_t collIdx = collision.globalIndex(); - // LOG(debug) << "Collision index: " << collIdx; - // auto Decay3BodyTable_thisCollision = decay3bodys.sliceBy(perCollision, collIdx); - // LOG(debug) << "Decay3Body tables sliced per collision. Calling buildVtx3BodyDataTableKFParticle function..."; - buildVtx3BodyDataTableKFParticle(collision, decay3bodys, bachelorcharge); - LOG(debug) << "End of processKFParticle."; - // } + // generate analysis tables + if (mEnabledTables[kDecay3BodyIndices]) { + products.decay3bodyindices(helper.decay3body.decay3bodyID, + helper.decay3body.protonID, helper.decay3body.pionID, helper.decay3body.deuteronID, + helper.decay3body.collisionID); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kDecay3BodyIndices); + } + if (mEnabledTables[kVtx3BodyDatas]) { + products.vtx3bodydatas(helper.decay3body.sign, + helper.decay3body.mass, helper.decay3body.massV0, + helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], + helper.decay3body.momentum[0], helper.decay3body.momentum[1], helper.decay3body.momentum[2], + helper.decay3body.chi2, + helper.decay3body.trackedClSize, + helper.decay3body.momProton[0], helper.decay3body.momProton[1], helper.decay3body.momProton[2], + helper.decay3body.momPion[0], helper.decay3body.momPion[1], helper.decay3body.momPion[2], + helper.decay3body.momDeuteron[0], helper.decay3body.momDeuteron[1], helper.decay3body.momDeuteron[2], + helper.decay3body.trackDCAxyToPV[0], helper.decay3body.trackDCAxyToPV[1], helper.decay3body.trackDCAxyToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAToPV[0], helper.decay3body.trackDCAToPV[1], helper.decay3body.trackDCAToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAxyToPVprop[0], helper.decay3body.trackDCAxyToPVprop[1], helper.decay3body.trackDCAxyToPVprop[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAToPVprop[0], helper.decay3body.trackDCAToPVprop[1], helper.decay3body.trackDCAToPVprop[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAtoSV[0], helper.decay3body.daughterDCAtoSV[1], helper.decay3body.daughterDCAtoSV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAtoSVaverage, + helper.decay3body.cosPA, helper.decay3body.ctau, + helper.decay3body.tpcNsigma[0], helper.decay3body.tpcNsigma[1], helper.decay3body.tpcNsigma[2], helper.decay3body.tpcNsigma[2], // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + helper.decay3body.tofNsigmaDeuteron, + helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.pidForTrackingDeuteron); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kVtx3BodyDatas); + } + if (mEnabledTables[kVtx3BodyCovs]) { + products.vtx3bodycovs(helper.decay3body.covProton, + helper.decay3body.covPion, + helper.decay3body.covDeuteron, + helper.decay3body.covariance); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kVtx3BodyCovs); + } + if (mEnabledTables[kMcVtx3BodyDatas]) { + products.mcvtx3bodydatas(helper.decay3body.sign, + helper.decay3body.mass, helper.decay3body.massV0, + helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], + helper.decay3body.momentum[0], helper.decay3body.momentum[1], helper.decay3body.momentum[2], + helper.decay3body.chi2, + helper.decay3body.trackedClSize, + helper.decay3body.momProton[0], helper.decay3body.momProton[1], helper.decay3body.momProton[2], + helper.decay3body.momPion[0], helper.decay3body.momPion[1], helper.decay3body.momPion[2], + helper.decay3body.momDeuteron[0], helper.decay3body.momDeuteron[1], helper.decay3body.momDeuteron[2], + helper.decay3body.trackDCAxyToPV[0], helper.decay3body.trackDCAxyToPV[1], helper.decay3body.trackDCAxyToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAToPV[0], helper.decay3body.trackDCAToPV[1], helper.decay3body.trackDCAToPV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAxyToPVprop[0], helper.decay3body.trackDCAxyToPVprop[1], helper.decay3body.trackDCAxyToPVprop[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.trackDCAToPVprop[0], helper.decay3body.trackDCAToPVprop[1], helper.decay3body.trackDCAToPVprop[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAtoSV[0], helper.decay3body.daughterDCAtoSV[1], helper.decay3body.daughterDCAtoSV[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.daughterDCAtoSVaverage, + helper.decay3body.cosPA, helper.decay3body.ctau, + helper.decay3body.tpcNsigma[0], helper.decay3body.tpcNsigma[1], helper.decay3body.tpcNsigma[2], helper.decay3body.tpcNsigma[2], // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + helper.decay3body.tofNsigmaDeuteron, + helper.decay3body.averageITSClSize[0], helper.decay3body.averageITSClSize[1], helper.decay3body.averageITSClSize[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.tpcNCl[0], helper.decay3body.tpcNCl[1], helper.decay3body.tpcNCl[2], // 0 - proton, 1 - pion, 2 - deuteron + helper.decay3body.pidForTrackingDeuteron, + // MC information + this3BodyMCInfo.genMomentum[0], this3BodyMCInfo.genMomentum[1], this3BodyMCInfo.genMomentum[2], + this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], + this3BodyMCInfo.genCt, + this3BodyMCInfo.genPhi, this3BodyMCInfo.genEta, this3BodyMCInfo.genRapidity, + this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, + this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, + this3BodyMCInfo.isTrueH3L, this3BodyMCInfo.isTrueAntiH3L, + this3BodyMCInfo.isReco, + this3BodyMCInfo.motherPdgCode, + this3BodyMCInfo.daughterPrPdgCode, this3BodyMCInfo.daughterPiPdgCode, this3BodyMCInfo.daughterDePdgCode, + this3BodyMCInfo.isDeuteronPrimary, + this3BodyMCInfo.survivedEventSel); + registry.fill(HIST("Counters/hTableBuildingStatistics"), kMcVtx3BodyDatas); + } } - PROCESS_SWITCH(decay3bodyBuilder, processRun3withKFParticle, "Produce KFParticle decay3body tables", false); -}; -struct decay3bodyDataLinkBuilder { - Produces vtxdataLink; - - void init(InitContext const&) {} + // ______________________________________________________________ + // function to build mixed 3body candidate from selected tracks + template + void doMixing(TCollision const& collision, TTrack const& trackProton, TTrack const& trackPion, TTrack const& trackDeuteron, float magField) + { + // set vertexers and propagator with correct mag field of this collision (only if run number changed compared to previous candidate build) + initFittersWithMagField(collision.runNumber(), magField); + if (helper.buildDecay3BodyCandidate(collision, trackProton, trackPion, trackDeuteron, + -1 /*decay3bodyIndex*/, + trackDeuteron.tofNSigmaDe(), + 0 /*trackedClSize*/, + decay3bodyBuilderOpts.useKFParticle, + decay3bodyBuilderOpts.kfSetTopologicalConstraint, + decay3bodyBuilderOpts.useSelections, + decay3bodyBuilderOpts.useChi2Selection, + decay3bodyBuilderOpts.useTPCforPion, + decay3bodyBuilderOpts.acceptTPCOnly, + decay3bodyBuilderOpts.askOnlyITSMatch, + decay3bodyBuilderOpts.calculateCovariance, + true, /*isEventMixing*/ + mixingOpts.doApplySVertexerCuts /*applySVertexerCuts*/)) { + // fill analysis tables with built candidate + fillAnalysisTables(); + return; + } else { + return; + } + } - void process(aod::Decay3Bodys const& decay3bodytable, aod::Vtx3BodyDatas const& vtxdatatable) + // ______________________________________________________________ + // function to check if a reconstructed mother is a true H3L/Anti-H3L (returns -1 if not) + template + int checkH3LTruth(MCTrack3B const& mcParticlePr, MCTrack3B const& mcParticlePi, MCTrack3B const& mcParticleDe, bool& isMuonReco) { - 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 (std::abs(mcParticlePr.pdgCode()) != PDG_t::kProton || std::abs(mcParticleDe.pdgCode()) != o2::constants::physics::Pdg::kDeuteron) { + 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()) == o2::constants::physics::Pdg::kHyperTriton) { + prDeMomID = motherPr.globalIndex(); + break; + } + } + } + if (prDeMomID == -1) { + return -1; + } + if (std::abs(mcParticlePi.pdgCode()) != PDG_t::kPiPlus && std::abs(mcParticlePi.pdgCode()) != PDG_t::kMuonMinus) { + 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()) == PDG_t::kMuonMinus) { + for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { + if (std::abs(motherPi.pdgCode()) == PDG_t::kPiPlus) { + mcParticlePiTmp = motherPi; + isMuonReco = true; + break; + } + } } - for (int ii = 0; ii < decay3bodytable.size(); ii++) { - vtxdataLink(lIndices[ii]); + // now loop over the pion mother + for (const auto& motherPi : mcParticlePiTmp.template mothers_as()) { + if (motherPi.globalIndex() == prDeMomID) { + return motherPi.globalIndex(); + } } + return -1; } -}; - -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)"}}}}, - }, - }; - void init(InitContext const&) + // ______________________________________________________________ + // function to reset MCInfo + void resetMCInfo(mc3Bodyinfo& mcInfo) { - 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"); + mcInfo.label = -1; + mcInfo.genMomentum[0] = -1., mcInfo.genMomentum[1] = -1., mcInfo.genMomentum[2] = -1.; + mcInfo.genDecVtx[0] = -1., mcInfo.genDecVtx[1] = -1., mcInfo.genDecVtx[2] = -1.; + mcInfo.genCt = -1.; + mcInfo.genPhi = -1., mcInfo.genEta = -1., mcInfo.genRapidity = -1.; + mcInfo.genMomProton = -1., mcInfo.genMomPion = -1., mcInfo.genMomDeuteron = -1.; + mcInfo.genPtProton = -1., mcInfo.genPtPion = -1., mcInfo.genPtDeuteron = -1.; + mcInfo.isTrueH3L = false, mcInfo.isTrueAntiH3L = false; + mcInfo.isReco = false; + mcInfo.motherPdgCode = -1; + mcInfo.daughterPrPdgCode = -1, mcInfo.daughterPiPdgCode = -1, mcInfo.daughterDePdgCode = -1; + mcInfo.isDeuteronPrimary = false; + return; } - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - - void processDoNotBuildLabels(aod::Collisions::iterator const&) + // ______________________________________________________________ + // process functions + void processRealData(ColswithEvTimes const& collisions, + aod::Decay3Bodys const& decay3bodys, + aod::Tracked3Bodys const& tracked3bodys, + TracksExtPIDIUwithEvTimes const&, + aod::BCsWithTimestamps const& bcs) { - // dummy process function - should not be required in the future + // initialise CCDB from BCs + if (!initCCDB(bcs, collisions)) { + LOG(info) << "CCDB initialisation failed, skipping candidate building." << std::endl; + return; + } + + // get tracked cluster size info + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& tvtx3body : tracked3bodys) { + fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); + } + + // do candidate analysis without MC processing + buildCandidates(bcs, // bc table + collisions, // collision table + decay3bodys, // decay3body table + static_cast(nullptr), // MC particle table + static_cast(nullptr)); // MC collision table } - 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&) + void processRealDataReduced(aod::RedCollisions const& collisions, + soa::Join const& decay3bodys, + aod::RedIUTracks const&) { - std::vector lIndices; - lIndices.reserve(vtx3bodydatas.size()); - for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { - lIndices[ii] = -1; + // get tracked cluster size info (saved in aod::Red3BodyInfo) + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& vtx3body : decay3bodys) { + fTrackedClSizeVector[vtx3body.globalIndex()] = vtx3body.trackedClSize(); } - for (auto& decay3body : decay3bodys) { + // do candidate analysis without MC processing + buildCandidates(static_cast(nullptr), // bc table + collisions, // collision table + decay3bodys, // decay3body table + static_cast(nullptr), // MC particle table + static_cast(nullptr)); // MC collision table + } - int lLabel = -1; - int lPDG = -1; - float lPt = -1; - double MClifetime = -1; - bool is3bodyDecay = false; - int lGlobalIndex = -1; + void processRealDataReduced3bodyMixing(aod::RedCollisions const&, + soa::Join const& decay3bodys, + aod::RedIUTracks const&) + { + auto xAxis = registry.get(HIST("Mixing/hDecay3BodyRadiusPhi"))->GetXaxis(); + auto yAxis = registry.get(HIST("Mixing/hDecay3BodyRadiusPhi"))->GetYaxis(); + + for (const auto& decay3body : decay3bodys) { + int bin_Radius, bin_Phi; + if (decay3bodyBuilderOpts.useKFParticle) { + bin_Radius = xAxis->FindBin(decay3body.radiusKF()); + bin_Phi = yAxis->FindBin(decay3body.phiKF()); + registry.fill(HIST("Mixing/hDecay3BodyPosZ"), decay3body.poszKF()); + } else { + bin_Radius = xAxis->FindBin(decay3body.radiusDCA()); + bin_Phi = yAxis->FindBin(decay3body.phiDCA()); + registry.fill(HIST("Mixing/hDecay3BodyPosZ"), decay3body.poszDCA()); + } + registry.fill(HIST("Mixing/hDecay3BodyRadiusPhi"), xAxis->GetBinCenter(bin_Radius), yAxis->GetBinCenter(bin_Phi)); + } - auto lTrack0 = decay3body.track0_as(); - auto lTrack1 = decay3body.track1_as(); - auto lTrack2 = decay3body.track2_as(); - registry.fill(HIST("hLabelCounter"), 0.5); + if (decay3bodyBuilderOpts.useKFParticle) { + Binning3BodyKF binningOnRadPhiKF{{mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}, true}; + buildMixedCandidates(decay3bodys, binningOnRadPhiKF); + } else { + Binning3BodyDCAfitter binningOnRadPhiDCA{{mixingOpts.bins3BodyRadius, mixingOpts.bins3BodyPhi}, true}; + buildMixedCandidates(decay3bodys, binningOnRadPhiDCA); + } + } - // Association check - // There might be smarter ways of doing this in the future - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - vtxfulllabels(-1); - continue; - } - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - vtxfulllabels(-1); - continue; - } + void processMonteCarlo(ColswithEvTimesLabeled const& collisions, + aod::Decay3Bodys const& decay3bodys, + aod::Tracked3Bodys const& tracked3bodys, + TracksExtPIDIUwithEvTimesLabeled const&, + aod::BCsWithTimestamps const& bcs, + aod::McParticles const& mcParticles, + aod::McCollisions const& mcCollisions) + { + // initialise CCDB from BCs + if (!initCCDB(bcs, collisions)) { + LOG(info) << "CCDB initialisation failed, skipping candidate building." << std::endl; + return; + } - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - lGlobalIndex = lMother1.globalIndex(); - lPt = lMother1.pt(); - lPDG = lMother1.pdgCode(); - MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); // only for hypertriton - is3bodyDecay = true; // vtxs with the same mother - } - } - } - } // end association check - if (!is3bodyDecay) { - vtxfulllabels(-1); - continue; - } - registry.fill(HIST("hLabelCounter"), 1.5); - - // 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}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hHypertritonMCPt"), lPt); - registry.fill(HIST("hHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hHypertritonMCMass"), hypertritonMCMass); - } - 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}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hAntiHypertritonMCPt"), lPt); - registry.fill(HIST("hAntiHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hAntiHypertritonMCMass"), antiHypertritonMCMass); - } + // get tracked cluster size info + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& tvtx3body : tracked3bodys) { + fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); + } - // Construct label table, only vtx which corresponds to true mother and true daughters with a specified order is labeled - // for matter: track0->p, track1->pi, track2->bachelor - // for antimatter: track0->pi, track1->p, track2->bachelor - vtxfulllabels(lLabel); - if (decay3body.vtx3BodyDataId() != -1) { - lIndices[decay3body.vtx3BodyDataId()] = lLabel; + // MC collision counting for event loss + registry.fill(HIST("Counters/hMcEventCounter"), 0.5, mcCollisions.size()); + for (const auto& collision : collisions) { + if (collision.has_mcCollision()) { + registry.fill(HIST("Counters/hMcEventCounter"), 1.5); } } - for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { - vtxlabels(lIndices[ii]); - } + + // do candidate analysis with MC processing + buildCandidates(bcs, // bc table + collisions, // collision table + decay3bodys, // decay3body table + mcParticles, // MC particle table + mcCollisions); // MC collision table } - PROCESS_SWITCH(decay3bodyLabelBuilder, processBuildLabels, "Produce MC label tables", false); -}; -struct decay3bodyInitializer { - Spawns vtx3bodydatas; - void init(InitContext const&) {} + PROCESS_SWITCH(decay3bodyBuilder, processRealData, "process real data", true); + PROCESS_SWITCH(decay3bodyBuilder, processRealDataReduced, "process real reduced data", false); + PROCESS_SWITCH(decay3bodyBuilder, processRealDataReduced3bodyMixing, "process real reduced data", false); + PROCESS_SWITCH(decay3bodyBuilder, processMonteCarlo, "process monte carlo", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { + metadataInfo.initMetadata(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 index 8e2733a8f24..86b0513ef07 100644 --- a/PWGLF/TableProducer/Nuspex/ebyeMaker.cxx +++ b/PWGLF/TableProducer/Nuspex/ebyeMaker.cxx @@ -9,75 +9,80 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include -#include +/// \file ebyeMaker.cxx +/// \brief table producer for e-by-e analysis in LF +/// \author Mario Ciacco -#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 "PWGLF/DataModel/LFEbyeTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/TPCPIDResponse.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.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/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/TableProducer/PID/pidTOFBase.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "Common/DataModel/PIDResponse.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" #include "DCAFitter/DCAFitterN.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" -#include "PWGLF/DataModel/LFEbyeTables.h" +#include "TFormula.h" -#include "TDatabasePDG.h" +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using TracksFull = soa::Join; -using TracksFullIU = soa::Join; +using TracksFullPID = soa::Join; +using TracksFullIUPID = soa::Join; using BCsWithRun2Info = soa::Join; namespace { constexpr int kNpart = 2; -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 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}; +constexpr float kTrackSels[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 kDcaSelsParam[3][3]{{-1.e32, -1.e32, -1.e32}, {-1.e32, -1.e32, -1.e32}, {-1.e32, -1.e32, -1.e32}}; +constexpr double kBetheBlochDefault[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 kBetheBlochDefaultITS[6]{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}; +constexpr double kEstimatorsCorrelationCoef[2]{-0.669108, 1.04489}; +constexpr double kEstimatorsSigmaPars[4]{0.933321, 0.0416976, -0.000936344, 8.92179e-06}; +constexpr double kDeltaEstimatorNsigma[2]{5.5, 5.}; +constexpr double kPartMass[kNpart]{o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron}; +constexpr double kPartPdg[kNpart]{PDG_t::kProton, o2::constants::physics::kDeuteron}; static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; -static const std::vector particleNamesBB{"p", "d"}; -std::array, kNpart> tofMass; +static const std::vector dcaParNames{"p0", "p1", "p2"}; +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"}; void momTotXYZ(std::array& momA, std::array const& momB, std::array const& momC) { - for (int i = 0; i < 3; ++i) { + for (uint64_t i = 0; i < momA.size(); ++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.)); @@ -85,27 +90,7 @@ float alphaAP(std::array const& momA, std::array const& momB 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) +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)); } @@ -136,40 +121,80 @@ struct CandidateTrack { 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; }; -struct ebyeMaker { +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), + kPhysPrim = BIT(22) +}; + +enum TracksCharge { + kAll = 0, + kNegative = 1, + kPositive = 2 +}; + +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; - // o2::base::MatLayerCylSet* lut = nullptr; + float dBz; + uint8_t nTrackletsColl; + uint8_t nTracksColl; + uint8_t nChPartGen; 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> cfgBetheBlochParams{"cfgBetheBlochParams", {kBetheBlochDefault[0], 2, 6, particleNamesPar, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for deuteron"}; + Configurable> cfgBetheBlochParamsITS{"cfgBetheBlochParamsITS", {kBetheBlochDefaultITS, 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"}; + const AxisSpec centAxis{106, 0, 106, "centrality"}; + const AxisSpec zVtxAxis{100, -20.f, 20.f, "vertex z in cm"}; + const AxisSpec nTpcAxis{160, 0, 160, "N TPC"}; + const AxisSpec dcaAxis{2000, -1., 1., "DCA in cm"}; // 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"}; @@ -177,18 +202,21 @@ struct ebyeMaker { // 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 countOnlyLSTrk{"countOnlyLSTrk", 0, "count only like sign tracks in Ntracks: 0 -> +ve and -ve; 1 -> -ve; 2 -> +ve"}; + Configurable useAllEvSel{"useAllEvSel", false, "use additional event selections fo run 3 analyses"}; + 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 kUseTPCPileUpCut{"kUseTPCPileUpCut", false, "toggle strong correlation cuts (Run 2)"}; + 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 kCentCutMax{"kCentCutMax", 100, "maximum accepted centrality"}; + 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)"}; @@ -203,7 +231,7 @@ struct ebyeMaker { 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 trackDcaCut{"trackDcaCut", 0.1f, "DCA antid to PV"}; + Configurable trackChi2Cut{"trackChi2Cut", 4.f, "Maximum chi2/ncls in TPC"}; 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"}; @@ -215,56 +243,78 @@ struct ebyeMaker { 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 v0settingDcaV0Dau{"v0setting_dcav0dau", 0.5f, "DCA V0 Daughters"}; + Configurable v0settingDcaV0Pv{"v0setting_dcav0pv", 1.f, "DCA V0 to Pv"}; + Configurable v0settingDcaDaughToPv{"v0setting_dcadaughtopv", 0.1f, "DCA Pos To PV"}; + Configurable v0settingCosPa{"v0setting_cospa", 0.99f, "V0 CosPA"}; + Configurable v0settingRadius{"v0setting_radius", 5.f, "v0radius"}; + Configurable v0settingLifetime{"v0setting_lifetime", 40.f, "v0 lifetime cut"}; + Configurable v0settingNSigmaTpc{"v0setting_nsigmatpc", 4.f, "nsigmatpc"}; Configurable lambdaMassCut{"lambdaMassCut", 0.02f, "maximum deviation from PDG mass (for QA histograms)"}; - 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", {kTrackSels, 1, 12, particleName, trackSelsNames}, "Track selections"}; + Configurable> cfgDcaSelsParam{"cfgDcaSelsParam", {kDcaSelsParam[0], 3, 3, dcaSelsNames, dcaParNames}, "DCA threshold settings"}; 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 perCollisionTracksFullIU = o2::aod::track::collisionId; + Preslice perCollisionTracksFullPID = o2::aod::track::collisionId; + Preslice perCollisionTracksFullIUPID = o2::aod::track::collisionId; Preslice perCollisionV0 = o2::aod::v0::collisionId; Preslice perCollisionMcParts = o2::aod::mcparticle::mcCollisionId; + template + int getPartTypeMother(P const& mcPart) + { + for (const auto& mother : mcPart.template mothers_as()) { + if (!mother.isPhysicalPrimary()) + return -1; + int pdgCode = mother.pdgCode(); + switch (std::abs(pdgCode)) { + case PDG_t::kLambda0: { + int foundPi = 0; + for (const auto& mcDaught : mother.template daughters_as()) { + if (std::abs(mcDaught.pdgCode()) == PDG_t::kPiPlus) { + foundPi = mcDaught.pdgCode(); + break; + } + } + if (foundPi * mcPart.pdgCode() < 0) + return PartTypes::kLa; + return -1; + } + default: + return -1; + } + } + return -1; + } + template bool selectV0Daughter(T const& track) { + const float defNClCROverFind = 0.8f; 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.tpcNClsCrossedRows() < defNClCROverFind * track.tpcNClsFindable() || track.tpcNClsShared() > v0trackNsharedClusTpc) { return false; } - if (doprocessRun2 || doprocessMcRun2) { + if (doprocessRun2 || doprocessMiniRun2 || doprocessMcRun2 || doprocessMiniMcRun2) { if (!(track.trackType() & o2::aod::track::Run2Track) || !(track.flags() & o2::aod::track::TPCrefit)) { return false; @@ -279,6 +329,9 @@ struct ebyeMaker { template bool selectTrack(T const& track) { + const float defItsChi2NClCut = 36.f; + const float defNClCROverFind = 0.8f; + const float defMinChi2Cut = 0.f; if (std::abs(track.eta()) > etaMax) { return false; } @@ -286,14 +339,13 @@ struct ebyeMaker { return false; } if (track.itsNCls() < trackNclusItsCut || - track.tpcNClsFound() < trackNclusTpcCut || - track.tpcNClsCrossedRows() < trackNcrossedRows || - track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || - track.tpcChi2NCl() > 4.f || - track.itsChi2NCl() > 36.f) { + track.tpcNClsCrossedRows() < defNClCROverFind * track.tpcNClsFindable() || + track.tpcChi2NCl() > trackChi2Cut || + track.tpcChi2NCl() < defMinChi2Cut || + track.itsChi2NCl() > defItsChi2NClCut) { return false; } - if (doprocessRun2 || doprocessMcRun2) { + if (doprocessRun2 || doprocessMiniRun2 || doprocessMcRun2 || doprocessMiniMcRun2) { if (!(track.trackType() & o2::aod::track::Run2Track) || !(track.flags() & o2::aod::track::TPCrefit) || !(track.flags() & o2::aod::track::ITSrefit)) { @@ -303,14 +355,9 @@ struct ebyeMaker { return true; } - template - float getITSClSize(T const& track) + float dcaSigma(float const& pt, const char* var) { - float sum{0.f}; - for (int iL{0}; iL < 6; ++iL) { - sum += (track.itsClusterSizes() >> (iL * 4)) & 0xf; - } - return sum / track.itsNCls(); + return cfgDcaSelsParam->get(var, "p0") + cfgDcaSelsParam->get(var, "p1") / std::pow(std::abs(pt), cfgDcaSelsParam->get(var, "p2")); } template @@ -319,11 +366,11 @@ struct ebyeMaker { if (mRunNumber == bc.runNumber()) { return; } - + classIds.clear(); auto timestamp = bc.timestamp(); o2::parameters::GRPObject* grpo = 0x0; o2::parameters::GRPMagField* grpmag = 0x0; - if (doprocessRun2 || doprocessMcRun2) { + if (doprocessRun2 || doprocessMcRun2 || doprocessMiniRun2 || doprocessMiniMcRun2) { auto grpPath{"GLO/GRP/GRP"}; grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", timestamp); if (!grpo) { @@ -339,25 +386,95 @@ struct ebyeMaker { 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"; + dBz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << dBz << " kG"; mRunNumber = bc.runNumber(); - fitter.setBz(d_bz); + if (doprocessMiniRun2) { // get class id for HMV0M trigger classes + 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(dBz); + } - // 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() / kPartMass[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); } - void init(o2::framework::InitContext&) + template + float getCustomTPCPID(T const& track, float const mass, int const ip = 0) + { + double expBethe{tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() / mass), 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")}; + return static_cast((track.tpcSignal() - expBethe) / expSigma); + } + + template + float getOuterPID(T const& track) { + if (!(doprocessRun2 || doprocessMcRun2) && track.hasTOF() && track.pt() > antipPtTof) + return track.tofNSigmaPr(); + return -999.f; + } + 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") * dcaSigma(track.pt, "dcaxy")) + mask |= kDCAxyTight; + else if (std::abs(track.dcaxypv) < cfgTrackSels->get("dcaxyMid") * dcaSigma(track.pt, "dcaxy")) + mask |= kDCAxyMid; + if (std::abs(track.dcazpv) < cfgTrackSels->get("dcazTight") * dcaSigma(track.pt, "dcaz")) + mask |= kDCAzTight; + else if (std::abs(track.dcazpv) < cfgTrackSels->get("dcazMid") * dcaSigma(track.pt, "dcaz")) + 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; + dBz = 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.); @@ -375,8 +492,7 @@ struct ebyeMaker { 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) { + } 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}); } @@ -386,8 +502,13 @@ struct ebyeMaker { // 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}); - 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}); + 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}); + + // tracking variables QA + histos.add("QA/tpcCRvsCls", ";#it{N}_{TPCCR};#it{N}_{TPCcls}", HistType::kTH2F, {nTpcAxis, nTpcAxis}); + histos.add("QA/dcaxyVsPt", ";#it{p}_{T} (GeV/#it{c});DCA_{#it{xy}} (cm)", HistType::kTH2F, {momAxis, dcaAxis}); + histos.add("QA/dcazVsPt", ";#it{p}_{T} (GeV/#it{c});DCA_{#it{z}} (cm)", HistType::kTH2F, {momAxis, dcaAxis}); ptMin = std::array{antipPtMin, antidPtMin}; ptMax = std::array{antipPtMax, antidPtMax}; @@ -395,252 +516,266 @@ struct ebyeMaker { 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(perCollisionTracksFullIUPID, 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 = (doprocessRun3 || doprocessMcRun3) ? tracksAll.sliceBy(perCollisionTracksFullIU, collision.globalIndex()) : tracksAll.sliceBy(perCollisionTracksFull, collision.globalIndex()); + auto tracks = tracksSlice(tracksAll, collision.globalIndex()); candidateTracks[0].clear(); candidateTracks[1].clear(); candidateV0s.clear(); + nTrackletsColl = 0u; + nTracksColl = 0u; - gpu::gpustd::array dcaInfo; + std::array dcaInfo; for (const auto& track : tracks) { - + if (track.trackType() == o2::aod::track::TrackTypeEnum::Run2Tracklet && std::abs(track.eta()) < etaMax && !(doprocessRun3 || doprocessMcRun3)) { // tracklet + nTrackletsColl++; + } else if (std::abs(track.eta()) < etaMax && track.itsNCls() > 3 && (doprocessRun3 || doprocessMcRun3)) { // ITS only + global tracks + nTrackletsColl++; + } if (!selectTrack(track)) { continue; } + histos.fill(HIST("QA/tpcCRvsCls"), track.tpcNClsCrossedRows(), track.tpcNClsFound()); + if (track.tpcNClsFound() < trackNclusTpcCut || track.tpcNClsCrossedRows() < trackNcrossedRows) + 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 > trackDcaCut) { + histos.fill(HIST("QA/dcaxyVsPt"), track.pt(), dcaInfo[0]); + histos.fill(HIST("QA/dcazVsPt"), track.pt(), dcaInfo[1]); + if (std::abs(dcaInfo[0]) > dcaSigma(track.pt(), "dcaxy") || std::abs(dcaInfo[1]) > dcaSigma(track.pt(), "dcaz") || dca > dcaSigma(track.pt(), "dca")) { // dcaxy continue; } histos.fill(HIST("QA/tpcSignal"), track.tpcInnerParam(), track.tpcSignal()); + if (trackPt > ptMin[0] && trackPt < ptMax[0] && ((track.sign() < 0 && countOnlyLSTrk == TracksCharge::kNegative) || (track.sign() > 0 && countOnlyLSTrk == TracksCharge::kPositive) || (countOnlyLSTrk == TracksCharge::kAll))) + nTracksColl++; 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); + auto nSigmaTPC = getCustomTPCPID(track, kPartMass[iP], iP); - 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 (nSigmaTPC > nSigmaTpcCutLow[iP] && nSigmaTPC < nSigmaTpcCutUp[iP]) { - tofMass[iP]->Fill(centrality, trackPt, mass); - } - } + const float maxTofChi2 = 3.f; // TODO: check if this is still needed + bool hasTof = track.hasTOF() && track.tofChi2() < maxTofChi2; 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])) { + if (trackPt <= ptTof[iP] || (trackPt > ptTof[iP] && hasTof)) { 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); } } } - std::vector trkId; - for (const auto& v0 : V0s) { - auto posTrack = v0.posTrack_as(); - auto negTrack = v0.negTrack_as(); + 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; + bool posSelect = selectV0Daughter(posTrack); + bool negSelect = selectV0Daughter(negTrack); + if (!posSelect || !negSelect) + continue; - if (doprocessRun2 || doprocessMcRun2) { - bool checkPosPileUp = posTrack.hasTOF() || (posTrack.flags() & o2::aod::track::ITSrefit); - bool checkNegPileUp = negTrack.hasTOF() || (negTrack.flags() & o2::aod::track::ITSrefit); - if (!checkPosPileUp && !checkNegPileUp) { + 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 posTrackCov = getTrackParCov(posTrack); - auto negTrackCov = getTrackParCov(negTrack); + auto& posPropTrack = fitter.getTrack(0); + auto& negPropTrack = fitter.getTrack(1); - int nCand = 0; - try { - nCand = fitter.process(posTrackCov, negTrackCov); - } catch (...) { - LOG(error) << "Exception caught in DCA fitter process call!"; - continue; - } - if (nCand == 0) { - continue; - } + std::array momPos; + std::array momNeg; + std::array momV0; + posPropTrack.getPxPyPzGlo(momPos); + negPropTrack.getPxPyPzGlo(momNeg); + momTotXYZ(momV0, momPos, momNeg); - auto& posPropTrack = fitter.getTrack(0); - auto& negPropTrack = fitter.getTrack(1); + auto ptV0 = std::hypot(momV0[0], momV0[1]); + if (ptV0 < lambdaPtMin || ptV0 > lambdaPtMax) { + continue; + } - std::array momPos; - std::array momNeg; - std::array momV0; - posPropTrack.getPxPyPzGlo(momPos); - negPropTrack.getPxPyPzGlo(momNeg); - momTotXYZ(momV0, momPos, momNeg); + auto etaV0 = RecoDecay::eta(momV0); + if (std::abs(etaV0) > etaMax) { + continue; + } - auto ptV0 = std::hypot(momV0[0], momV0[1]); - if (ptV0 < lambdaPtMin || ptV0 > lambdaPtMax) { - 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 = RecoDecay::m(std::array, 2>{momPos, momNeg}, std::array{massPos, massNeg}); + auto mK0Short = RecoDecay::m(std::array, 2>{momPos, momNeg}, std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); - auto etaV0 = etaFromMom(momPos, momNeg); - if (std::abs(etaV0) > etaMax) { - continue; - } + // pid selections + float nSigmaTPCPos = getCustomTPCPID(posTrack, massPos); + float nSigmaTPCNeg = getCustomTPCPID(negTrack, massNeg); + float tpcSigPr = matter ? posTrack.tpcSignal() : negTrack.tpcSignal(); - 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); - - if (std::abs(nSigmaTPCPos) > v0setting_nsigmatpc || std::abs(nSigmaTPCNeg) > v0setting_nsigmatpc) { - continue; - } + if (std::abs(nSigmaTPCPos) > v0settingNSigmaTpc || std::abs(nSigmaTPCNeg) > v0settingNSigmaTpc) { + continue; + } - // veto on K0s mass - if (std::abs(mK0Short - o2::constants::physics::MassK0Short) < vetoMassK0Short) { - 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; - } + float dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); + if (dcaV0dau > v0settingDcaV0Dau) { + continue; + } - std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; - const auto& vtx = fitter.getPCACandidate(); + 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 radiusV0 = std::hypot(vtx[0], vtx[1]); + if (radiusV0 < v0settingRadius || 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; - } + 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) > v0settingDcaV0Pv) { + continue; + } - double cosPA = RecoDecay::cpa(primVtx, vtx, momV0); - if (cosPA < v0setting_cospa) { - continue; - } + double cosPA = RecoDecay::cpa(primVtx, vtx, momV0); + if (cosPA < v0settingCosPa) { + 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; - } + 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 mL2PLambda = o2::constants::physics::MassLambda * lengthTraveled / ptotal; + if (mL2PLambda > v0settingLifetime) { + 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()}, posTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); + auto posDcaToPv = std::hypot(dcaInfo[0], dcaInfo[1]); + 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 ((posDcaToPv < v0settingDcaDaughToPv && std::abs(dcaInfo[0]) < v0settingDcaDaughToPv) || (negDcaToPv < v0settingDcaDaughToPv && std::abs(dcaInfo[0]) < v0settingDcaDaughToPv)) { + 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); - if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCut) { // for QA histograms - continue; + 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); } - histos.fill(HIST("QA/massLambda"), centrality, ptV0, mLambda); - - 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&, aod::McTrackLabels const& mcLabels) + 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]) { + for (auto& candidateTrack : candidateTracks[iP]) { // o2-linter: disable=const-ref-in-for-loop (not a const ref) 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]) + if (std::abs(mcTrack.pdgCode()) != kPartPdg[iP]) continue; - if (((mcTrack.flags() & 0x8) && doprocessMcRun2) || (mcTrack.flags() & 0x2) || (mcTrack.flags() & 0x1)) + if ((((mcTrack.flags() & 0x8) || (mcTrack.flags() & 0x2)) && (doprocessMcRun2 || doprocessMiniMcRun2)) || ((mcTrack.flags() & 0x1) && !doprocessMiniMcRun2)) continue; - if (!mcTrack.isPhysicalPrimary()) + + 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(); @@ -650,7 +785,7 @@ struct ebyeMaker { } } } - for (auto& candidateV0 : candidateV0s) { + for (auto& candidateV0 : candidateV0s) { // o2-linter: disable=const-ref-in-for-loop (not a const ref) candidateV0.isreco = true; auto mcLabPos = mcLabels.rawIteratorAt(candidateV0.globalIndexPos); auto mcLabNeg = mcLabels.rawIteratorAt(candidateV0.globalIndexNeg); @@ -659,18 +794,18 @@ struct ebyeMaker { 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()) { + for (const auto& negMother : mcTrackNeg.template mothers_as()) { + for (const 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))) + if (!((mcTrackPos.pdgCode() == PDG_t::kProton && mcTrackNeg.pdgCode() == PDG_t::kPiMinus) || (mcTrackPos.pdgCode() == PDG_t::kPiPlus && mcTrackNeg.pdgCode() == PDG_t::kProtonBar))) continue; - if (std::abs(posMother.pdgCode()) != 3122) { + if (std::abs(posMother.pdgCode()) != PDG_t::kLambda0) { continue; } if (!posMother.isPhysicalPrimary() && !posMother.has_mothers()) continue; - if (((posMother.flags() & 0x8) && doprocessMcRun2) || (posMother.flags() & 0x2) || (posMother.flags() & 0x1)) + if (((posMother.flags() & 0x8) || (posMother.flags() & 0x2) || (posMother.flags() & 0x1)) && (doprocessMcRun2 || doprocessMiniMcRun2)) continue; auto genPt = std::hypot(posMother.px(), posMother.py()); @@ -687,21 +822,28 @@ struct ebyeMaker { 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) { + nChPartGen = 0u; + auto mcParticlesThisCollision = mcParticles.sliceBy(perCollisionMcParts, collisionId); + for (const auto& mcPart : mcParticlesThisCollision) { auto genEta = mcPart.eta(); if (std::abs(genEta) > etaMax) { continue; } - if (((mcPart.flags() & 0x8) && doprocessMcRun2) || (mcPart.flags() & 0x2) || (mcPart.flags() & 0x1)) + if ((((mcPart.flags() & 0x8) || (mcPart.flags() & 0x2)) && (doprocessMcRun2 || doprocessMiniMcRun2)) || ((mcPart.flags() & 0x1) && !doprocessMiniMcRun2)) continue; auto pdgCode = mcPart.pdgCode(); - if (std::abs(pdgCode) == 3122) { + auto genPt = std::hypot(mcPart.px(), mcPart.py()); + if ((std::abs(pdgCode) == PDG_t::kPiPlus || std::abs(pdgCode) == PDG_t::kElectron || std::abs(pdgCode) == PDG_t::kMuonMinus || std::abs(pdgCode) == PDG_t::kKPlus || std::abs(pdgCode) == PDG_t::kProton) && mcPart.isPhysicalPrimary() && genPt > ptMin[0] && genPt < ptMax[0]) { + int ch = (pdgCode == PDG_t::kPiPlus || pdgCode == -PDG_t::kElectron || pdgCode == -PDG_t::kMuonMinus || pdgCode == PDG_t::kKPlus || pdgCode == PDG_t::kProton) ? 1 : -1; + if ((ch < 0 && countOnlyLSTrk == TracksCharge::kNegative) || (ch > 0 && countOnlyLSTrk == TracksCharge::kPositive) || (countOnlyLSTrk == TracksCharge::kAll)) + nChPartGen++; + } + if (std::abs(pdgCode) == PDG_t::kLambda0) { if (!mcPart.isPhysicalPrimary() && !mcPart.has_mothers()) continue; bool foundPr = false; - for (auto& mcDaught : mcPart.daughters_as()) { - if (std::abs(mcDaught.pdgCode()) == 2212) { + for (const auto& mcDaught : mcPart.daughters_as()) { + if (std::abs(mcDaught.pdgCode()) == PDG_t::kProton) { foundPr = true; break; } @@ -709,7 +851,6 @@ struct ebyeMaker { if (!foundPr) { continue; } - auto genPt = std::hypot(mcPart.px(), mcPart.py()); CandidateV0 candV0; candV0.genpt = genPt; candV0.geneta = mcPart.eta(); @@ -718,21 +859,26 @@ struct ebyeMaker { if (it != candidateV0s.end()) { continue; } else { - LOGF(info, "not found!"); + LOGF(debug, "not found!"); candidateV0s.emplace_back(candV0); } - } else if (std::abs(pdgCode) == partPdg[0] || std::abs(pdgCode) == partPdg[1]) { + } else if (std::abs(pdgCode) == kPartPdg[0] || std::abs(pdgCode) == kPartPdg[1]) { int iP = 1; - if (std::abs(pdgCode) == partPdg[0]) { + if (std::abs(pdgCode) == kPartPdg[0]) { iP = 0; } - if (!mcPart.isPhysicalPrimary() && !mcPart.has_mothers()) + 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; @@ -743,67 +889,48 @@ struct ebyeMaker { } } - void processRun3(soa::Join const& collisions, TracksFullIU const& tracks, aod::V0s const& V0s, aod::BCsWithTimestamps const&) + void processRun3(soa::Join const& collisions, TracksFullIUPID 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) + if (std::abs(collision.posZ()) > zVtxMax || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kIsTriggerTVX) || ((!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && useAllEvSel)) 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)) + auto centrality = collision.centFT0C(); + if (centrality > kCentCutMax) 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); + auto v0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); + v0TableThisCollision.bindExternalIndices(&tracks); histos.fill(HIST("QA/PvMultVsCent"), centrality, collision.numContrib()); - histos.fill(HIST("QA/MultVsCent"), centrality, multiplicity); + fillRecoEvent(collision, tracks, v0TableThisCollision, centrality); - 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); - } + miniCollTable(static_cast(collision.posZ() * 10), 0x0, nTrackletsColl, centrality, nTracksColl); - for (auto& candidateTrack : candidateTracks[1]) { // deuterons - nucleiEbyeTable( - collisionEbyeTable.lastIndex(), + for (auto& candidateTrack : candidateTracks[0]) { // o2-linter: disable=const-ref-in-for-loop (not a const ref) + auto tk = tracks.rawIteratorAt(candidateTrack.globalIndex); + float outerPID = getOuterPID(tk); + candidateTrack.itsnsigma = -999.f; + candidateTrack.outerPID = tk.pt() < antipPtTof ? candidateTrack.outerPID : outerPID; + int selMask = getTrackSelMask(candidateTrack); + if (candidateTrack.outerPID < outerPIDMin) + continue; + miniTrkTable( + miniCollTable.lastIndex(), candidateTrack.pt, - candidateTrack.eta, - candidateTrack.mass, - candidateTrack.dcapv, - candidateTrack.tpcncls, - candidateTrack.tpcnsigma, - candidateTrack.tofmass); + static_cast(candidateTrack.eta * 100), + selMask, + candidateTrack.outerPID); } } } - PROCESS_SWITCH(ebyeMaker, processRun3, "process (Run 3)", false); + PROCESS_SWITCH(EbyeMaker, processRun3, "process (Run 3)", false); void processRun2(soa::Join const& collisions, TracksFull const& tracks, aod::V0s const& V0s, BCsWithRun2Info const&) { @@ -817,19 +944,20 @@ struct ebyeMaker { if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) continue; - if (kUseTPCPileUpCut && !(bc.eventCuts() & BIT(aod::Run2EventCuts::kTPCPileUp))) + if (kUsePileUpCut && !(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)))) + float centrality = collision.centRun2V0M(); + const float centTriggerEdges[]{10.f, 30.f, 50.f}; + if (!(collision.sel7() && collision.alias_bit(kINT7)) && (!kINT7Intervals || (kINT7Intervals && ((centrality >= centTriggerEdges[0] && centrality < centTriggerEdges[1]) || centrality > centTriggerEdges[2])))) continue; - auto centralityCl0 = collision.centRun2CL0(); + float centralityCl0 = collision.centRun2CL0(); 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 (centrality < center - deltaEstimatorNsigma[0] * sigma || centrality > center + deltaEstimatorNsigma[1] * sigma) { + const double center = kEstimatorsCorrelationCoef[0] + kEstimatorsCorrelationCoef[1] * x; + const double sigma = kEstimatorsSigmaPars[0] + kEstimatorsSigmaPars[1] * x + kEstimatorsSigmaPars[2] * std::pow(x, 2) + kEstimatorsSigmaPars[3] * std::pow(x, 3); + if (centrality < center - kDeltaEstimatorNsigma[0] * sigma || centrality > center + kDeltaEstimatorNsigma[1] * sigma) { continue; } } @@ -837,120 +965,165 @@ struct ebyeMaker { 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 v0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); + v0TableThisCollision.bindExternalIndices(&tracks); auto multTracklets = collision.multTracklets(); - fillRecoEvent(collision, tracks, V0Table_thisCollision, centrality); + fillRecoEvent(collision, tracks, v0TableThisCollision, centrality); histos.fill(HIST("QA/V0MvsCL0"), centralityCl0, centrality); histos.fill(HIST("QA/trackletsVsV0M"), centrality, multTracklets); collisionEbyeTable(centrality, collision.posZ()); - for (auto& candidateV0 : candidateV0s) { + for (const 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 (auto& candidateTrack : candidateTracks[1]) { // deuterons - nucleiEbyeTable( - collisionEbyeTable.lastIndex(), - candidateTrack.pt, - candidateTrack.eta, - candidateTrack.mass, - candidateTrack.dcapv, - candidateTrack.tpcncls, - candidateTrack.tpcnsigma, - candidateTrack.tofmass); + for (int iP{0}; iP < kNpart; ++iP) { + for (const 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); + PROCESS_SWITCH(EbyeMaker, processRun2, "process (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&) + void processMiniRun2(soa::Join const& collisions, TracksFullPID const& tracks, aod::Run2TrackExtras const& trackExtraRun2, aod::V0s const& V0s, BCsWithRun2Info const&) { - for (auto& collision : collisions) { - auto bc = collision.bc_as(); + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); initCCDB(bc); - if (!collision.sel8()) + 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)) + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kINELgtZERO))) continue; - if (std::abs(collision.posZ()) > zVtxMax) + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) continue; - auto centrality = collision.centFT0C(); + if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kPileUpMV) || bc.eventCuts() & BIT(aod::Run2EventCuts::kTPCPileUp)) && kUsePileUpCut) + continue; + float centrality = collision.centRun2V0M(); 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()); + auto v0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); + v0TableThisCollision.bindExternalIndices(&tracks); - collisionEbyeTable(centrality, collision.posZ()); + fillRecoEvent(collision, tracks, v0TableThisCollision, centrality); - 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); + uint8_t trigger = collision.alias_bit(kINT7) ? 0x1 : 0x0; + for (const auto& classId : classIds) { + if (bc.triggerMask() & BIT(classId)) { + trigger |= 0x2; + centrality = centrality * 100.; + break; + } + } + if (trigger == 0x0) { + continue; } + if (triggerCut != 0x0 && (trigger & triggerCut) != triggerCut) { + continue; + } + miniCollTable(static_cast(collision.posZ() * 10), trigger, nTrackletsColl, centrality, nTracksColl); + + for (auto& candidateTrack : candidateTracks[0]) { // o2-linter: disable=const-ref-in-for-loop (not a const ref) + 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); - for (auto& candidateTrack : candidateTracks[1]) { // deuterons - mcNucleiEbyeTable( - collisionEbyeTable.lastIndex(), + void processMcRun3(soa::Join const& collisions, aod::McCollisions const& /*mcCollisions*/, TracksFullIUPID const& tracks, aod::V0s const& V0s, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLab, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + + if (std::abs(collision.posZ()) > zVtxMax || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kIsTriggerTVX) || ((!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && useAllEvSel)) + continue; + + auto centrality = collision.centFT0C(); + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto v0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); + v0TableThisCollision.bindExternalIndices(&tracks); + + fillMcEvent(collision, tracks, v0TableThisCollision, centrality, mcParticles, mcLab); + fillMcGen(mcParticles, mcLab, collision.mcCollisionId()); + + miniCollTable(static_cast(collision.posZ() * 10), nChPartGen, nTrackletsColl, centrality, nTracksColl); + + for (auto& candidateTrack : candidateTracks[0]) { // o2-linter: disable=const-ref-in-for-loop (not a const ref) + int selMask = -1; + if (candidateTrack.isreco) { + auto tk = tracks.rawIteratorAt(candidateTrack.globalIndex); + float outerPID = getOuterPID(tk); + candidateTrack.itsnsigma = -999.f; + candidateTrack.outerPID = tk.pt() < antipPtTof ? candidateTrack.outerPID : outerPID; + selMask = getTrackSelMask(candidateTrack); + if (candidateTrack.pdgcodemoth > 0) + selMask |= candidateTrack.pdgcodemoth; + } else if (candidateTrack.pdgcodemoth > 0) { + selMask = candidateTrack.pdgcodemoth; + } + if (selMask < 0) + continue; + mcMiniTrkTable( + miniCollTable.lastIndex(), candidateTrack.pt, - candidateTrack.eta, - candidateTrack.mass, - candidateTrack.dcapv, - candidateTrack.tpcncls, - candidateTrack.tpcnsigma, - candidateTrack.tofmass, - candidateTrack.genpt, - candidateTrack.geneta, - candidateTrack.pdgcode, + 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, processMcRun3, "process MC (Run 3)", false); + 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::McParticles const& mcParticles, aod::McTrackLabels const& mcLab, BCsWithRun2Info const&) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { auto bc = collision.bc_as(); initCCDB(bc); @@ -960,32 +1133,27 @@ struct ebyeMaker { if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) continue; - auto centrality = collision.centRun2V0M(); - + float centrality = collision.centRun2V0M(); 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 v0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); + v0TableThisCollision.bindExternalIndices(&tracks); - fillMcEvent(collision, tracks, V0Table_thisCollision, centrality, mcParticles, mcLab); + fillMcEvent(collision, tracks, v0TableThisCollision, centrality, mcParticles, mcLab); fillMcGen(mcParticles, mcLab, collision.mcCollisionId()); collisionEbyeTable(centrality, collision.posZ()); - for (auto& candidateV0 : candidateV0s) { + for (const 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, @@ -994,28 +1162,85 @@ struct ebyeMaker { candidateV0.isreco); } - for (auto& candidateTrack : candidateTracks[1]) { // deuterons - mcNucleiEbyeTable( - collisionEbyeTable.lastIndex(), + for (int iP{0}; iP < kNpart; ++iP) { + for (const 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::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 centrality = collision.centRun2V0M(); + histos.fill(HIST("QA/zVtx"), collision.posZ()); + + const uint64_t collIdx = collision.globalIndex(); + auto v0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); + v0TableThisCollision.bindExternalIndices(&tracks); + + fillMcEvent(collision, tracks, v0TableThisCollision, centrality, mcParticles, mcLab); + fillMcGen(mcParticles, mcLab, collision.mcCollisionId()); + + miniCollTable(static_cast(collision.posZ() * 10), nChPartGen, nTrackletsColl, centrality, nTracksColl); + + for (auto& candidateTrack : candidateTracks[0]) { // o2-linter: disable=const-ref-in-for-loop (not a const ref) + 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.pdgcodemoth > 0) + selMask |= candidateTrack.pdgcodemoth; + } else if (candidateTrack.pdgcodemoth > 0) { + selMask = candidateTrack.pdgcodemoth; + } + if (selMask < 0) + continue; + mcMiniTrkTable( + miniCollTable.lastIndex(), candidateTrack.pt, - candidateTrack.eta, - candidateTrack.mass, - candidateTrack.dcapv, - candidateTrack.tpcncls, - candidateTrack.tpcnsigma, - candidateTrack.tofmass, - candidateTrack.genpt, - candidateTrack.geneta, - candidateTrack.pdgcode, + 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, processMcRun2, "process MC (Run 2)", false); + PROCESS_SWITCH(EbyeMaker, processMiniMcRun2, "process mini tables for mc(Run 2)", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx new file mode 100644 index 00000000000..3defa321251 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx @@ -0,0 +1,1357 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 + +/// \file he3HadronFemto.cxx +/// \brief Femto analysis task for He3-hadron correlation +/// \author Your Name (your.email@cern.ch) +/// \since April 2025 + +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFhe3HadronTables.h" +#include "PWGLF/Utils/svPoolCreator.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/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "CCDB/BasicCCDBManager.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include // std::prev +#include +#include +#include + +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 int Li4PDG = o2::constants::physics::Pdg::kLithium4; +constexpr int H3LPDG = o2::constants::physics::Pdg::kHyperTriton; +constexpr int ProtonPDG = PDG_t::kProton; +constexpr int He3PDG = o2::constants::physics::Pdg::kHelium3; +constexpr float CommonInite = 0.0f; + +enum Selections { + kNoCuts = 0, + kTrackCuts, + kPID, + kAll +}; + +enum Flags { + kBothPrimaries = BIT(0), + kBothFromLi4 = BIT(1), + kBothFromHypertriton = BIT(2), + kMixedPair = BIT(3), // a primary and one from Li4/hypertriton/material/other decays (or any other combination) +}; + +enum Species { + kHe3 = 0, + kHad, + kAllSpecies +}; + +enum ParticleFlags { + kPhysicalPrimary = BIT(0), // primary particle + kFromLi4 = BIT(1), // from Li4 decay + kFromHypertriton = BIT(2), // from hypertriton decay + kFromMaterial = BIT(3), // from material + kFromOtherDecays = BIT(4), // from other decays +}; + +std::array kDCAxyResolutionParams[static_cast(Species::kAllSpecies)] = { + {0.0118, 0.6889, 0.0017}, // He3 + {0.0032, 0.5206, 0.0012} // Pr +}; +std::array kDCAzResolutionParams[static_cast(Species::kAllSpecies)] = { + {0.1014, 1.7512, 0.0024}, // He3 + {0.0021, 1.1122, 0.0021} // Pr +}; + +} // 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; + float dcaPair = -10.f; // DCA between the two tracks + + 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 nSigmaTPCHadPi = -10.f; + float nSigmaTPCHadKa = -10.f; + float nSigmaTPCHadPr = -10.f; + float nSigmaTOFHadPi = -10.f; + float nSigmaTOFHadKa = -10.f; + float nSigmaTOFHadPr = -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; + + uint8_t flagsHe3 = 0; // flags for He3 + uint8_t flagsHad = 0; // flags for hadron + uint8_t flags = 0; // flags for the pair + + // collision information + int32_t collisionID = 0; +}; + +struct he3HadronFemto { + + Produces outputDataTable; + Produces outputMcTable; + Produces outputMultiplicityTable; + Produces outputQaTable; + + // Selections + Configurable settingHadPDGCode{"settingHadPDGCode", 211, "Hadron - PDG code"}; + + Configurable settingCutVertex{"settingCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable settingCutRigidityMinHe3{"settingCutRigidityMinHe3", 0.8f, "Minimum rigidity for He3"}; + Configurable settingCutEta{"settingCutEta", 0.9f, "Eta cut on daughter track"}; + Configurable settingCutDCAxy{"settingCutDCAxy", 2.0f, "DCAxy range for tracks"}; + Configurable settingCutDCAz{"settingCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable settingCutNClsTPC{"settingCutNClsTPC", 90, "number of TPC clusters for a generic track"}; + Configurable settingCutNClsTPCHe3{"settingCutNClsTPCHe3", 110.0f, "number of TPC clusters for a He3 track"}; + Configurable settingCutChi2tpcLow{"settingCutChi2tpcLow", 0.f, "Low cut on TPC chi2"}; + Configurable settingCutChi2tpcLowHe3{"settingCutChi2tpcLowHe3", 0.5f, "Low cut on TPC chi2 for He3"}; + Configurable settingCutInvMass{"settingCutInvMass", 0.0f, "Invariant mass upper limit"}; + Configurable settingCutPtMinhe3Had{"settingCutPtMinhe3Had", 0.0f, "Minimum PT cut on he3Had4"}; + Configurable settingCutClSizeItsHe3{"settingCutClSizeItsHe3", 4.0f, "Minimum ITS cluster size for He3"}; + Configurable settingCutNCls{"settingCutNCls", 5.0f, "Minimum ITS Ncluster for tracks"}; + Configurable settingCutChi2NClITS{"settingCutChi2NClITS", 36.f, "Maximum ITS Chi2 for tracks"}; + Configurable settingCutNsigmaDcaXy{"settingCutNsigmaDcaXy", 3.0f, "Value of the DCA xy Nsigma cut"}; + Configurable settingCutNsigmaDcaZ{"settingCutNsigmaDcaZ", 3.0f, "Value of the DCA z Nsigma cut"}; + Configurable settingCutNsigmaTPC{"settingCutNsigmaTPC", 3.0f, "Value of the TPC Nsigma cut"}; + Configurable settingCutNsigmaITSHad{"settingCutNsigmaITSHad", -2.f, "Value of the ITS Nsigma cutfor Had"}; + Configurable settingCutNsigmaITSHe3{"settingCutNsigmaITSHe3", -1.5f, "Value of the ITS Nsigma cutfor He3"}; + Configurable settingCutPtMinTOFHad{"settingCutPtMinTOFHad", 0.4f, "Minimum pT to apply the TOF cut on hadrons"}; + Configurable settingCutNsigmaTOF{"settingCutNsigmaTOF", 3.0f, "Value of the TOF Nsigma cut"}; + + Configurable settingNoMixedEvents{"settingNoMixedEvents", 5, "Number of mixed events per event"}; + Configurable settingEnableBkgUS{"settingEnableBkgUS", false, "Enable US background"}; + Configurable settingEnableDCAfitter{"settingEnableDCAfitter", false, "Enable DCA fitter"}; + Configurable settingSaveUSandLS{"settingSaveUSandLS", true, "Save All Pairs"}; + Configurable settingIsMC{"settingIsMC", false, "Run MC"}; + + Configurable settingFillMultiplicity{"settingFillMultiplicity", false, "Fill multiplicity table"}; + Configurable settingFillQa{"settingFillQa", false, "Fill QA table"}; + Configurable settingFillPrimariesAndMixedMc{"settingFillPrimariesAndMixedMc", false, "Fill primary MC tracks and mixed tracks (e.g. a primary track and one from Li4)"}; + + // Zorro + Configurable settingSkimmedProcessing{"settingSkimmedProcessing", false, "Skimmed dataset processing"}; + + // svPool + Configurable settingSkipAmbiTracks{"settingSkipAmbiTracks", false, "Skip ambiguous tracks"}; + Configurable settingCustomVertexerTimeMargin{"settingCustomVertexerTimeMargin", 800, "Time margin for custom vertexer (ns)"}; + + // CCDB options + Configurable settingDbz{"settingDbz", -999, "bz field, -999 is automatic"}; + Configurable settingCcdburl{"settingCcdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable settingGrpPath{"settingGrpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable settingGrpmagPath{"settingGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable settingLutPath{"settingLutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable settingGeoPath{"settingGeoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable settingPidPath{"settingPidPath", "", "Path to the PID response object"}; + + Configurable> settingBetheBlochParams{"settingBetheBlochParams", {betheBlochDefault[0], 1, 6, {"He3"}, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; + Configurable settingCompensatePIDinTracking{"settingCompensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; + Configurable settingMaterialCorrection{"settingMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Material correction type"}; + + Preslice mPerCol = aod::track::collisionId; + Preslice mPerColMC = 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 mPair{binningPolicy, settingNoMixedEvents, -1, &cache}; + + std::array mBBparamsHe; + + std::vector mRecoCollisionIDs; + std::vector mGoodCollisions; + std::vector mTrackPairs; + o2::vertexing::DCAFitterN<2> mFitter; + svPoolCreator mSvPoolCreator{He3PDG, ProtonPDG}; + int mRunNumber; + float mDbz; + Service mCcdb; + Zorro mZorro; + OutputObj mZorroSummary{"zorroSummary"}; + + HistogramRegistry mQaRegistry{ + "QA", + { + {"hVtxZBefore", "Vertex distribution in Z before selections;Z (cm)", {HistType::kTH1F, {{400, -20.0, 20.0}}}}, + {"hVtxZ", "Vertex distribution in Z;Z (cm)", {HistType::kTH1F, {{400, -20.0, 20.0}}}}, + {"hCentralityFT0A", ";Centrality FT0A (%)", {HistType::kTH1F, {{100, 0, 100.0}}}}, + {"hCentralityFT0C", ";Centrality FT0C (%)", {HistType::kTH1F, {{100, 0, 100.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}}}}, + {"hhe3HadtInvMass", "; M(^{3}He + p) (GeV/#it{c}^{2})", {HistType::kTH1F, {{300, 3.74f, 4.34f}}}}, + + {"He3/hDCAxyHe3", "^{3}He;DCA_{xy} (cm)", {HistType::kTH1F, {{200, -0.5f, 0.5f}}}}, + {"He3/hDCAzHe3", "^{3}He;DCA_{z} (cm)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, + {"He3/hNClsHe3ITS", "^{3}He;N_{ITS} Cluster", {HistType::kTH1F, {{20, -10.0f, 10.0f}}}}, + {"He3/hChi2NClHe3ITS", "^{3}He;Chi2_{ITS} Ncluster", {HistType::kTH1F, {{100, 0, 100.0f}}}}, + {"He3/hHe3Pt", "^{3}He; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{240, -6.0f, 6.0f}}}}, + {"He3/h2dEdxHe3candidates", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, + {"He3/h2NsigmaHe3TPC", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(^{3}He)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"He3/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}}}}, + {"He3/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}}}}, + {"He3/h2NSigmaHe3ITS", "NsigmaHe3 ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} ^{3}He", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {120, -3.0f, 3.0f}}}}, + + {"Had/hNClsHadITS", "had;N_{ITS} Cluster", {HistType::kTH1F, {{20, -10.0f, 10.0f}}}}, + {"Had/hChi2NClHadITS", "had;Chi2_{ITS} Ncluster", {HistType::kTH1F, {{100, 0, 100.0f}}}}, + {"Had/hHadronPt", "had; #it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{120, -3.0f, 3.0f}}}}, + {"Had/h2NsigmaHadronTPC", "NsigmaHadron TPC distribution; #it{p}_{T}(GeV/#it{c}); n#sigma_{TPC}(had)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"Had/h2NsigmaHadronTPC_preselection", "NsigmaHe3 TPC distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}(had)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + {"Had/h2NsigmaHadronTOF", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {200, -5.0f, 5.0f}}}}, + {"Had/h2NsigmaHadronTOF_preselection", "NsigmaHadron TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(had)", {HistType::kTH2F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}}}}, + }, + OutputObjHandlingPolicy::AnalysisObject, + false, + true}; + + void init(o2::framework::InitContext&) + { + mZorroSummary.setObject(mZorro.getZorroSummary()); + mRunNumber = 0; + + mCcdb->setURL(settingCcdburl); + mCcdb->setCaching(true); + mCcdb->setLocalObjectValidityChecking(); + mCcdb->setFatalWhenNull(false); + + mFitter.setPropagateToPCA(true); + mFitter.setMaxR(200.); + mFitter.setMinParamChange(1e-3); + mFitter.setMinRelChi2Change(0.9); + mFitter.setMaxDZIni(1e9); + mFitter.setMaxChi2(1e9); + mFitter.setUseAbsDCA(true); + int mat{static_cast(settingMaterialCorrection)}; + mFitter.setMatCorrType(static_cast(mat)); + + mSvPoolCreator.setTimeMargin(settingCustomVertexerTimeMargin); + if (settingSkipAmbiTracks) { + mSvPoolCreator.setSkipAmbiTracks(); + } + const int numberParticle = 5; + for (int i = 0; i < numberParticle; i++) { + mBBparamsHe[i] = settingBetheBlochParams->get("He3", Form("p%i", i)); + } + mBBparamsHe[5] = settingBetheBlochParams->get("He3", "resolution"); + + std::vector selectionLabels = {"All", "Track selection", "PID"}; + for (int i = 0; i < Selections::kAll; i++) { + mQaRegistry.get(HIST("hTrackSel"))->GetXaxis()->SetBinLabel(i + 1, selectionLabels[i].c_str()); + } + + std::vector eventsLabels = {"All", "Selected", "Zorro He events"}; + for (int i = 0; i < Selections::kAll; i++) { + mQaRegistry.get(HIST("hEvents"))->GetXaxis()->SetBinLabel(i + 1, eventsLabels[i].c_str()); + } + + mQaRegistry.get(HIST("hEmptyPool"))->GetXaxis()->SetBinLabel(1, "False"); + mQaRegistry.get(HIST("hEmptyPool"))->GetXaxis()->SetBinLabel(2, "True"); + } + + void initCCDB(const aod::BCsWithTimestamps::iterator& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + if (settingSkimmedProcessing) { + mZorro.initCCDB(mCcdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + mZorro.populateHistRegistry(mQaRegistry, bc.runNumber()); + } + mRunNumber = bc.runNumber(); + const float defaultBzValue = -999.0f; + auto run3GrpTimestamp = bc.timestamp(); + o2::parameters::GRPObject* grpo = mCcdb->getForTimeStamp(settingGrpPath, run3GrpTimestamp); + o2::parameters::GRPMagField* grpmag = 0x0; + if (grpo) { + o2::base::Propagator::initFieldFromGRP(grpo); + if (settingDbz < defaultBzValue) { + // Fetch magnetic field from ccdb for current collision + mDbz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << mDbz << " kZG"; + } else { + mDbz = settingDbz; + } + } else { + grpmag = mCcdb->getForTimeStamp(settingGrpmagPath, run3GrpTimestamp); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << settingGrpmagPath << " of object GRPMagField and " << settingGrpPath << " of object GRPObject for timestamp " << run3GrpTimestamp; + } + o2::base::Propagator::initFieldFromGRP(grpmag); + if (settingDbz < defaultBzValue) { + // Fetch magnetic field from ccdb for current collision + mDbz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << mDbz << " kZG"; + } else { + mDbz = settingDbz; + } + } + } + + // ================================================================================================================== + + template + bool selectCollision(const Tcollision& collision, const aod::BCsWithTimestamps&) + { + mQaRegistry.fill(HIST("hEvents"), 0); + mQaRegistry.fill(HIST("hVtxZBefore"), collision.posZ()); + + auto bc = collision.template bc_as(); + initCCDB(bc); + + if constexpr (isMC) { + if (/*!collision.sel8() ||*/ std::abs(collision.posZ()) > settingCutVertex) { + return false; + } + } else { + + if (!collision.sel8() || std::abs(collision.posZ()) > settingCutVertex) { + return false; + } + if (settingSkimmedProcessing) { + bool zorroSelected = mZorro.isSelected(collision.template bc_as().globalBC()); + if (zorroSelected) { + mQaRegistry.fill(HIST("hEvents"), 2); + } + } + } + + mQaRegistry.fill(HIST("hEvents"), 1); + mQaRegistry.fill(HIST("hNcontributor"), collision.numContrib()); + mQaRegistry.fill(HIST("hVtxZ"), collision.posZ()); + mQaRegistry.fill(HIST("hCentralityFT0A"), collision.centFT0A()); + mQaRegistry.fill(HIST("hCentralityFT0C"), collision.centFT0C()); + return true; + } + + template + bool selectTrack(const Ttrack& candidate, const int ispecies) + { + if (std::abs(candidate.eta()) > settingCutEta) { + return false; + } + const int minTPCNClsFound = ispecies == Species::kHe3 ? static_cast(settingCutNClsTPCHe3) : static_cast(settingCutNClsTPCHe3); + const int minTPCNClsCrossedRows = 70; + const float crossedRowsToFindableRatio = 0.8f; + const float minChi2NCl = ispecies == Species::kHe3 ? static_cast(settingCutChi2tpcLowHe3) : static_cast(settingCutChi2tpcLow); + const float maxChi2NCl = 4.f; + if (candidate.itsNCls() < settingCutNCls || + candidate.tpcNClsFound() < minTPCNClsFound || + candidate.tpcNClsCrossedRows() < minTPCNClsCrossedRows || + candidate.tpcNClsCrossedRows() < crossedRowsToFindableRatio * candidate.tpcNClsFindable() || + candidate.tpcChi2NCl() > maxChi2NCl || + candidate.tpcChi2NCl() < minChi2NCl || + candidate.itsChi2NCl() > settingCutChi2NClITS) { + return false; + } + + return true; + } + + float computeNsigmaDCA(const float pt, const float dca, const int iSpecies, const char* dcaType = "xy") + { + + std::array parameters; + if (std::strcmp(dcaType, "xy") == 0) { + parameters = kDCAxyResolutionParams[iSpecies]; + } else if (std::strcmp(dcaType, "z") == 0) { + parameters = kDCAzResolutionParams[iSpecies]; + } else { + LOG(error) << "Invalid dcaType. Accepted types are 'xy' 'z'"; + parameters = {0., 0., 0.}; + } + const float sigma = parameters[0] * + std::exp(-std::abs(pt) * parameters[1]) + + parameters[2]; + return dca / sigma; + } + + template + bool selectDcaNsigmaCut(const Ttrack& candidate, const int ispecies) + { + const float pt = ispecies == Species::kHe3 ? 2. * candidate.pt() : candidate.pt(); + const float nsigmaDcaXy = computeNsigmaDCA(pt, candidate.dcaXY(), ispecies, "xy"); + const float nsigmaDcaZ = computeNsigmaDCA(pt, candidate.dcaZ(), ispecies, "z"); + + if (std::abs(nsigmaDcaXy) > settingCutNsigmaDcaXy || + std::abs(nsigmaDcaZ) > settingCutNsigmaDcaZ) + return false; + + return true; + } + + template + float computeTPCNSigmaHadron(const Ttrack& candidate) + { + float tpcNSigmaHad = CommonInite; + if (settingHadPDGCode == PDG_t::kPiPlus) { + tpcNSigmaHad = candidate.tpcNSigmaPi(); + } else if (settingHadPDGCode == PDG_t::kProton) { + tpcNSigmaHad = candidate.tpcNSigmaPr(); + } else { + LOG(info) << "invalid PDG code for TPC"; + } + return tpcNSigmaHad; + } + + template + float computeTOFNSigmaHadron(const Ttrack& candidate) + { + float tofNSigmaHad = CommonInite; + if (settingHadPDGCode == PDG_t::kPiPlus) { + tofNSigmaHad = candidate.tofNSigmaPi(); + } else if (settingHadPDGCode == PDG_t::kProton) { + tofNSigmaHad = candidate.tofNSigmaPr(); + } else { + LOG(info) << "invalid PDG code for TOF"; + } + return tofNSigmaHad; + } + + template + bool selectionPIDHadron(const Ttrack& candidate) + { + auto tpcNSigmaHad = computeTPCNSigmaHadron(candidate); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_preselection"), candidate.sign() * candidate.tpcInnerParam(), tpcNSigmaHad); + if (candidate.hasTOF() && candidate.pt() > settingCutPtMinTOFHad) { + auto tofNSigmaHad = computeTOFNSigmaHadron(candidate); + + if (std::abs(tpcNSigmaHad) > settingCutNsigmaTPC) { + return false; + } + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_preselection"), candidate.sign() * candidate.pt(), tofNSigmaHad); + if (std::abs(tofNSigmaHad) > settingCutNsigmaTOF) { + return false; + } + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC"), candidate.sign() * candidate.pt(), tpcNSigmaHad); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF"), candidate.sign() * candidate.pt(), tofNSigmaHad); + return true; + } else if (std::abs(tpcNSigmaHad) < settingCutNsigmaTPC) { + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC"), candidate.sign() * 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 && settingCompensatePIDinTracking) ? 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); + } + + template + bool selectionPIDHe3(const Ttrack& candidate) + { + bool heliumPID = candidate.pidForTracking() == o2::track::PID::Helium3 || candidate.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParam = (heliumPID && settingCompensatePIDinTracking) ? candidate.tpcInnerParam() / 2.f : candidate.tpcInnerParam(); + + if (correctedTPCinnerParam < settingCutRigidityMinHe3) { + return false; + } + + auto nSigmaHe3 = computeNSigmaHe3(candidate); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC_preselection"), candidate.sign() * 2 * candidate.pt(), nSigmaHe3); + if (std::abs(nSigmaHe3) > settingCutNsigmaTPC) { + return false; + } + // + o2::aod::ITSResponse mResponseITS; + auto itsNsigmaHe3 = mResponseITS.nSigmaITS(candidate.itsClusterSizes(), 2 * candidate.p(), candidate.eta()); + // + mQaRegistry.fill(HIST("He3/h2NSigmaHe3ITS_preselection"), candidate.sign() * 2 * candidate.pt(), itsNsigmaHe3); + if (itsNsigmaHe3 < settingCutNsigmaITSHe3) { + return false; + } + + mQaRegistry.fill(HIST("He3/h2dEdxHe3candidates"), candidate.sign() * correctedTPCinnerParam, candidate.tpcSignal()); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC"), candidate.sign() * 2 * candidate.pt(), nSigmaHe3); + mQaRegistry.fill(HIST("He3/h2NSigmaHe3ITS"), candidate.sign() * 2 * candidate.pt(), itsNsigmaHe3); + return true; + } + + // ================================================================================================================== + + template + std::array getCollisionVertex(const Tcollisions& collisions, int32_t collisionID) + { + auto collision = collisions.rawIteratorAt(collisionID); + std::array collisionVertex = {collision.posX(), collision.posY(), collision.posZ()}; + return collisionVertex; + } + + template + int32_t getCollisionID(const Ttrack& trackHe3, const Ttrack& trackHad, const CollBracket& collBracket, const Tcollisions& collisions, bool isMixedEvent) + { + if (isMixedEvent) { + return collBracket.getMin(); + } + + auto trackCovHe3 = getTrackParCov(trackHe3); + auto trackCovHad = getTrackParCov(trackHad); + int nCand = CommonInite; + try { + nCand = mFitter.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; + const float defaultTodistance = 0.0f; + for (int collIdx = collBracket.getMin(); collIdx <= collBracket.getMax(); collIdx++) { + std::array collisionVertex = getCollisionVertex(collisions, collIdx); + const auto& pca = mFitter.getPCACandidate(); + float distance = defaultTodistance; + for (int i = 0; i < 3; i++) { + distance += (pca[i] - collisionVertex[i]) * (pca[i] - collisionVertex[i]); + } + if (distanceMin < 0 || distance < distanceMin) { + distanceMin = distance; + collIdxMin = collIdx; + } + } + + if (!mGoodCollisions[collIdxMin]) { + return false; + } + return collIdxMin; + } + + template + bool fillCandidateInfo(const Ttrack& trackHe3, const Ttrack& trackHad, const CollBracket& collBracket, const Tcollisions& collisions, He3HadCandidate& he3Hadcand, const Ttracks& /*trackTable*/, bool isMixedEvent) + { + he3Hadcand.collisionID = getCollisionID(trackHe3, trackHad, collBracket, collisions, isMixedEvent); + std::array collisionVertex = getCollisionVertex(collisions, he3Hadcand.collisionID); + + 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 = CommonInite; + if (settingHadPDGCode == PDG_t::kPiPlus) { + invMass = RecoDecay::m(std::array{he3Hadcand.momHe3, he3Hadcand.momHad}, std::array{o2::constants::physics::MassHelium3, o2::constants::physics::MassPiPlus}); + } else if (settingHadPDGCode == PDG_t::kProton) { + 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"; + } + + if (settingCutInvMass > 0 && invMass > settingCutInvMass) { + return false; + } + float pthe3Had = std::hypot(he3Hadcand.momHe3[0] + he3Hadcand.momHad[0], he3Hadcand.momHe3[1] + he3Hadcand.momHad[1]); + if (pthe3Had < settingCutPtMinhe3Had) { + return false; + } + + he3Hadcand.signHe3 = trackHe3.sign(); + he3Hadcand.signHad = trackHad.sign(); + if (!settingEnableDCAfitter) { + he3Hadcand.dcaxyHe3 = trackHe3.dcaXY(); + he3Hadcand.dcaxyHad = trackHad.dcaXY(); + he3Hadcand.dcazHe3 = trackHe3.dcaZ(); + he3Hadcand.dcazHad = trackHad.dcaZ(); + } else { + auto trackCovHe3 = getTrackParCov(trackHe3); + auto trackCovHad = getTrackParCov(trackHad); + std::array dcaInfo; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collisionVertex[0], collisionVertex[1], collisionVertex[2]}, trackCovHe3, 2.f, mFitter.getMatCorrType(), &dcaInfo); + he3Hadcand.dcaxyHe3 = dcaInfo[0]; + he3Hadcand.dcazHe3 = dcaInfo[1]; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collisionVertex[0], collisionVertex[1], collisionVertex[2]}, trackCovHad, 2.f, mFitter.getMatCorrType(), &dcaInfo); + he3Hadcand.dcaxyHad = dcaInfo[0]; + he3Hadcand.dcazHad = dcaInfo[1]; + he3Hadcand.dcaPair = std::sqrt(std::abs(mFitter.getChi2AtPCACandidate())); + } + + he3Hadcand.tpcSignalHe3 = trackHe3.tpcSignal(); + bool heliumPID = trackHe3.pidForTracking() == o2::track::PID::Helium3 || trackHe3.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParamHe3 = (heliumPID && settingCompensatePIDinTracking) ? 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.nSigmaTPCHadPi = trackHad.tpcNSigmaPi(); + he3Hadcand.nSigmaTPCHadKa = trackHad.tpcNSigmaKa(); + he3Hadcand.nSigmaTPCHadPr = trackHad.tpcNSigmaPr(); + he3Hadcand.nSigmaTOFHadPi = trackHad.tofNSigmaPi(); + he3Hadcand.nSigmaTOFHadKa = trackHad.tofNSigmaKa(); + he3Hadcand.nSigmaTOFHadPr = trackHad.tofNSigmaPr(); + + 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 && settingCompensatePIDinTracking) ? 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, 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(); + } + + template + void fillMotherInfoMC(const Mc& mctrackHe3, const Mc& mctrackHad, const Mc& mctrackMother, He3HadCandidate& he3Hadcand) + { + 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 (const auto& track0 : tracks) { + + mQaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); + + if (!selectTrack(track0, Species::kHe3)) { + continue; + } + mQaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); + + if (!selectionPIDHe3(track0)) { + continue; + } + mQaRegistry.fill(HIST("hTrackSel"), Selections::kPID); + + for (const auto& track1 : tracks) { + + if (track0 == track1) { + continue; + } + + if (!settingSaveUSandLS) { + if (!settingEnableBkgUS && (track0.sign() * track1.sign() < 0)) { + continue; + } + if (settingEnableBkgUS && (track0.sign() * track1.sign() > 0)) { + continue; + } + } + + if (!selectTrack(track1, Species::kHad) || !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; + mTrackPairs.push_back(trackPair); + } + } + } + + template + void pairTracksEventMixing(T& he3Cands, T& hadronCands) + { + for (const auto& he3Cand : he3Cands) { + if (!selectTrack(he3Cand, Species::kHe3) || !selectionPIDHe3(he3Cand)) { + continue; + } + for (const auto& hadronCand : hadronCands) { + if (!selectTrack(hadronCand, Species::kHad) || !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; + mTrackPairs.push_back(trackPair); + } + } + } + + template + void fillTable(const He3HadCandidate& he3Hadcand, const Tcoll& collision, bool isMC = false) + { + outputDataTable( + he3Hadcand.recoPtHe3(), + he3Hadcand.recoEtaHe3(), + he3Hadcand.recoPhiHe3(), + he3Hadcand.recoPtHad(), + he3Hadcand.recoEtaHad(), + he3Hadcand.recoPhiHad(), + he3Hadcand.dcaxyHe3, + he3Hadcand.dcazHe3, + he3Hadcand.dcaxyHad, + he3Hadcand.dcazHad, + he3Hadcand.dcaPair, + he3Hadcand.tpcSignalHe3, + he3Hadcand.momHe3TPC, + he3Hadcand.tpcSignalHad, + he3Hadcand.momHadTPC, + he3Hadcand.nTPCClustersHe3, + he3Hadcand.nSigmaHe3, + he3Hadcand.nSigmaTPCHadPi, + he3Hadcand.nSigmaTPCHadKa, + he3Hadcand.nSigmaTPCHadPr, + he3Hadcand.nSigmaTOFHadPi, + he3Hadcand.nSigmaTOFHadKa, + he3Hadcand.nSigmaTOFHadPr, + he3Hadcand.chi2TPCHe3, + he3Hadcand.chi2TPCHad, + he3Hadcand.massTOFHe3, + he3Hadcand.massTOFHad, + he3Hadcand.pidtrkHe3, + he3Hadcand.pidtrkHad, + he3Hadcand.itsClSizeHe3, + he3Hadcand.itsClSizeHad, + he3Hadcand.sharedClustersHe3, + he3Hadcand.sharedClustersHad); + if (isMC) { + outputMcTable( + he3Hadcand.momHe3MC, + he3Hadcand.etaHe3MC, + he3Hadcand.phiHe3MC, + he3Hadcand.momHadMC, + he3Hadcand.etaHadMC, + he3Hadcand.phiHadMC, + he3Hadcand.l4PtMC, + he3Hadcand.l4MassMC, + he3Hadcand.flags); + } + if (settingFillMultiplicity) { + outputMultiplicityTable( + collision.globalIndex(), + collision.posZ(), + collision.numContrib(), + collision.centFT0C(), + collision.multFT0C()); + } + if (settingFillQa) { + outputQaTable( + he3Hadcand.trackIDHe3, + he3Hadcand.trackIDHad); + } + } + + void fillHistograms(const He3HadCandidate& he3Hadcand) + { + mQaRegistry.fill(HIST("He3/hHe3Pt"), he3Hadcand.recoPtHe3()); + mQaRegistry.fill(HIST("Had/hHadronPt"), he3Hadcand.recoPtHad()); + mQaRegistry.fill(HIST("hhe3HadtInvMass"), he3Hadcand.invMass); + mQaRegistry.fill(HIST("He3/hDCAxyHe3"), he3Hadcand.dcaxyHe3); + mQaRegistry.fill(HIST("He3/hDCAzHe3"), he3Hadcand.dcazHe3); + mQaRegistry.fill(HIST("He3/hNClsHe3ITS"), he3Hadcand.nclsITSHe3); + mQaRegistry.fill(HIST("Had/hNClsHadITS"), he3Hadcand.nclsITSHad); + mQaRegistry.fill(HIST("He3/hChi2NClHe3ITS"), he3Hadcand.chi2nclITSHe3); + mQaRegistry.fill(HIST("Had/hChi2NClHadITS"), he3Hadcand.chi2nclITSHad); + } + + // ================================================================================================================== + + template + void fillPairs(const Tcollisions& collisions, const Ttracks& tracks, const bool isMixedEvent) + { + for (const auto& trackPair : mTrackPairs) { + + 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 setMcParticleFlag(const TmcParticle& mcParticle, std::vector& mothers, uint8_t& flag) + { + if (mcParticle.isPhysicalPrimary()) { + + flag |= ParticleFlags::kPhysicalPrimary; + if (!mcParticle.has_mothers()) { + return; + } + + for (const auto& mother : mcParticle.template mothers_as()) { + mothers.push_back(mother.globalIndex()); + if (std::abs(mother.pdgCode()) == Li4PDG) { + flag |= ParticleFlags::kFromLi4; + } else if (std::abs(mother.pdgCode()) == H3LPDG) { + flag |= ParticleFlags::kFromHypertriton; + } else { + flag |= ParticleFlags::kFromOtherDecays; + } + } + + } else { + + if (!mcParticle.has_mothers()) { + flag |= ParticleFlags::kFromMaterial; + return; + } + + for (const auto& mother : mcParticle.template mothers_as()) { + mothers.push_back(mother.globalIndex()); + if (std::abs(mother.pdgCode()) == Li4PDG) { + flag |= ParticleFlags::kFromLi4; + } else if (std::abs(mother.pdgCode()) == H3LPDG) { + flag |= ParticleFlags::kFromHypertriton; + } else { + flag |= ParticleFlags::kFromOtherDecays; + } + } + } + } + + void searchForCommonMotherTrack(const std::vector& motherHe3Idxs, const std::vector& motherHadIdxs, const aod::McParticles& mcParticles, McIter& motherParticle, He3HadCandidate& he3Hadcand, bool& isMixedPair, const int motherPdgCode) + { + std::unordered_set motherHe3SetIdxs(motherHe3Idxs.begin(), motherHe3Idxs.end()); + for (const auto& motherHadIdx : motherHadIdxs) { + if (!motherHe3SetIdxs.contains(motherHadIdx)) { + continue; + } + + motherParticle = mcParticles.rawIteratorAt(motherHadIdx); + if (std::abs(motherParticle.pdgCode()) != motherPdgCode || std::abs(motherParticle.y()) > 1) { + continue; + } + isMixedPair = false; + break; + } + if (!isMixedPair) { + he3Hadcand.flags |= Flags::kBothFromLi4; + } + } + + template + void fillMcParticles(const Tcollisions& collisions, const TmcParticles& mcParticles, std::vector& filledMothers) + { + for (const 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 (const auto& kCurrentDaughter : kDaughters) { + if (std::abs(kCurrentDaughter.pdgCode()) == He3PDG) { + daughtHe3 = true; + mcHe3 = kCurrentDaughter; + } else if (std::abs(kCurrentDaughter.pdgCode()) == ProtonPDG) { + daughtHad = true; + mcHad = kCurrentDaughter; + } + } + if (daughtHe3 && daughtHad) { + He3HadCandidate he3Hadcand; + fillCandidateInfoMC(mcHe3, mcHad, he3Hadcand); + fillMotherInfoMC(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) + { + mGoodCollisions.clear(); + mGoodCollisions.resize(collisions.size(), false); + + for (const auto& collision : collisions) { + + mTrackPairs.clear(); + + if (!selectCollision(collision, bcs)) { + continue; + } + + mGoodCollisions[collision.globalIndex()] = true; + const uint64_t collIdx = collision.globalIndex(); + auto trackTableThisCollision = tracks.sliceBy(mPerCol, collIdx); + trackTableThisCollision.bindExternalIndices(&tracks); + + pairTracksSameEvent(trackTableThisCollision); + + if (mTrackPairs.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"; + mTrackPairs.clear(); + + for (const auto& [c1, tracks1, c2, tracks2] : mPair) { + if (!c1.sel8() || !c2.sel8()) { + continue; + } + + mQaRegistry.fill(HIST("hNcontributor"), c1.numContrib()); + mQaRegistry.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; + + mGoodCollisions.clear(); + mGoodCollisions.resize(collisions.size(), false); + + for (const auto& collision : collisions) { + + mTrackPairs.clear(); + + if (!selectCollision(collision, bcs)) { + continue; + } + + const uint64_t collIdx = collision.globalIndex(); + mGoodCollisions[collIdx] = true; + auto trackTableThisCollision = tracks.sliceBy(mPerColMC, collIdx); + trackTableThisCollision.bindExternalIndices(&tracks); + + pairTracksSameEvent(trackTableThisCollision); + + for (const auto& trackPair : mTrackPairs) { + + 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()) != He3PDG || std::abs(mctrackHad.pdgCode()) != settingHadPDGCode) { + continue; + } + + He3HadCandidate he3Hadcand; + McIter motherParticle; + std::vector motherHe3Idxs, motherHadIdxs; + setMcParticleFlag(mctrackHe3, motherHe3Idxs, he3Hadcand.flagsHe3); + setMcParticleFlag(mctrackHad, motherHadIdxs, he3Hadcand.flagsHad); + + bool isMixedPair = true; + + if ((he3Hadcand.flagsHe3 == ParticleFlags::kPhysicalPrimary && he3Hadcand.flagsHad == ParticleFlags::kPhysicalPrimary)) { + he3Hadcand.flags |= Flags::kBothPrimaries; + isMixedPair = false; + + } else if ((he3Hadcand.flagsHe3 & ParticleFlags::kFromLi4) && (he3Hadcand.flagsHad & ParticleFlags::kFromLi4)) { + + searchForCommonMotherTrack(motherHe3Idxs, motherHadIdxs, mcParticles, motherParticle, he3Hadcand, isMixedPair, Li4PDG); + if (!isMixedPair) { + he3Hadcand.flags |= Flags::kBothFromLi4; + } + + } else if ((he3Hadcand.flagsHe3 & ParticleFlags::kFromHypertriton) && (he3Hadcand.flagsHad & ParticleFlags::kFromHypertriton)) { + + searchForCommonMotherTrack(motherHe3Idxs, motherHadIdxs, mcParticles, motherParticle, he3Hadcand, isMixedPair, H3LPDG); + if (!isMixedPair) { + he3Hadcand.flags |= Flags::kBothFromHypertriton; + } + } + + if (isMixedPair) { + he3Hadcand.flags |= Flags::kMixedPair; + } + + if (!settingFillPrimariesAndMixedMc && ((he3Hadcand.flags == Flags::kMixedPair) || he3Hadcand.flags == Flags::kBothPrimaries)) { + continue; + } + + if (!fillCandidateInfo(heTrack, prTrack, collBracket, collisions, he3Hadcand, tracks, /*mix*/ false)) { + continue; + } + fillCandidateInfoMC(mctrackHe3, mctrackHad, he3Hadcand); + + if ((he3Hadcand.flags == Flags::kBothFromLi4) || (he3Hadcand.flags == Flags::kBothFromHypertriton)) { + fillMotherInfoMC(mctrackHe3, mctrackHad, motherParticle, he3Hadcand); + filledMothers.push_back(motherParticle.globalIndex()); + } + + fillHistograms(he3Hadcand); + auto collision = collisions.rawIteratorAt(he3Hadcand.collisionID); + fillTable(he3Hadcand, collision, /*isMC*/ true); + } + } + + 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) + { + mGoodCollisions.clear(); + mGoodCollisions.resize(collisions.size(), false); + + for (const auto& collision : collisions) { + if (selectCollision(collision, bcs)) { + mGoodCollisions[collision.globalIndex()] = true; + } + } + + mSvPoolCreator.clearPools(); + mSvPoolCreator.fillBC2Coll(collisions, bcs); + + for (const auto& track : tracks) { + + mQaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); + if (!selectTrack(track, Species::kHad)) // specific he3 cuts skipped here, might need to refactor this + continue; + mQaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); + + bool selHad = selectionPIDHadron(track); + bool selHe = selectionPIDHe3(track); + if ((!selHad && !selHe) || (selHad && selHe)) { + continue; + } + mQaRegistry.fill(HIST("hTrackSel"), Selections::kPID); + + int pdgHypo = selHe ? He3PDG : ProtonPDG; + + mSvPoolCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); + } + + mTrackPairs = mSvPoolCreator.getSVCandPool(collisions, true); + if (mTrackPairs.size() == 0) { + mQaRegistry.fill(HIST("hEmptyPool"), 1); + return; + } + mQaRegistry.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; + + mGoodCollisions.clear(); + mGoodCollisions.resize(collisions.size(), false); + + for (const auto& collision : collisions) { + if (selectCollision(collision, bcs)) { + mGoodCollisions[collision.globalIndex()] = true; + } + } + + mSvPoolCreator.clearPools(); + mSvPoolCreator.fillBC2Coll(collisions, bcs); + + for (const auto& track : tracks) { + + mQaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); + if (!selectTrack(track, Species::kHad)) // specific he3 cuts skipped here, might need to refactor this + continue; + mQaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); + + bool selHad = selectionPIDHadron(track); + bool selHe = selectionPIDHe3(track); + if ((!selHad && !selHe) || (selHad && selHe)) + continue; + mQaRegistry.fill(HIST("hTrackSel"), Selections::kPID); + + int pdgHypo = selHe ? He3PDG : ProtonPDG; + + mSvPoolCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); + } + + auto& svPool = mSvPoolCreator.getSVCandPool(collisions, true); + if (svPool.size() == 0) { + mQaRegistry.fill(HIST("hEmptyPool"), 1); + return; + } + mQaRegistry.fill(HIST("hEmptyPool"), 0); + + for (const 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()) != He3PDG || std::abs(mctrackHad.pdgCode()) != ProtonPDG || !mctrackHe3.has_mothers() || !mctrackHad.has_mothers()) { + continue; + } + + for (const auto& mothertrackHe : mctrackHe3.mothers_as()) { + for (const 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, he3Hadcand); + fillMotherInfoMC(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); + + void processPurity(const CollisionsFull::iterator& collision, const TrackCandidates& tracks, const aod::BCsWithTimestamps& bcs) + { + if (!selectCollision(collision, bcs)) + return; + + for (const auto& track : tracks) { + + if (!selectTrack(track, Species::kHad)) + continue; + + if (selectDcaNsigmaCut(track, Species::kHad)) { + mQaRegistry.fill(HIST("Had/hHadronPt"), track.pt()); + + const float tpcNSigmaHad = computeTPCNSigmaHadron(track); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTPC_preselection"), track.sign() * track.tpcInnerParam(), tpcNSigmaHad); + + if (track.hasTOF()) { + const float tofNSigmaHad = computeTOFNSigmaHadron(track); + mQaRegistry.fill(HIST("Had/h2NsigmaHadronTOF_preselection"), track.sign() * track.pt(), tofNSigmaHad); + } + } + + if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(track, Species::kHe3)) + continue; + + mQaRegistry.fill(HIST("He3/hHe3Pt"), track.pt() * 2.f); + mQaRegistry.fill(HIST("He3/hDCAxyHe3"), track.dcaXY()); + mQaRegistry.fill(HIST("He3/hDCAzHe3"), track.dcaZ()); + + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; + float correctedTPCinnerParam = (heliumPID && settingCompensatePIDinTracking) ? track.tpcInnerParam() / 2.f : track.tpcInnerParam(); + if (correctedTPCinnerParam < settingCutRigidityMinHe3) { + continue; + } + + const float nSigmaHe3 = computeNSigmaHe3(track); + mQaRegistry.fill(HIST("He3/h2NsigmaHe3TPC_preselection"), track.sign() * 2 * track.pt(), nSigmaHe3); + } + } + PROCESS_SWITCH(he3HadronFemto, processPurity, "Process for purity studies", false); +}; + +WorkflowSpec defineDataProcessing(const ConfigContext& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Nuspex/he3LambdaAnalysis.cxx b/PWGLF/TableProducer/Nuspex/he3LambdaAnalysis.cxx new file mode 100644 index 00000000000..65ce28fa5db --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/he3LambdaAnalysis.cxx @@ -0,0 +1,401 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFSlimHeLambda.h" + +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#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; +using namespace o2::constants::physics; +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 particleName{"He3"}; +o2::base::MatLayerCylSet* matLUT = nullptr; + +float alphaAP(std::array const& momA, std::array const& momB, std::array const& momC) +{ + const float lQlPos = (momB[0] * momA[0] + momB[1] * momA[1] + momB[2] * momA[2]); + const float lQlNeg = (momC[0] * momA[0] + momC[1] * momA[1] + momC[2] * momA[2]); + return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); +} + +float qtAP(std::array const& momA, std::array const& momB) +{ + const float dp = momA[0] * momB[0] + momA[1] * momB[1] + momA[2] * momB[2]; + const float p2A = momA[0] * momA[0] + momA[1] * momA[1] + momA[2] * momA[2]; + const float p2B = momB[0] * momB[0] + momB[1] * momB[1] + momB[2] * momB[2]; + return std::sqrt(p2B - dp * dp / p2A); +} + +std::shared_ptr hTPCsignalAll; +std::shared_ptr hTPCsignalHe3; +std::shared_ptr hTPCnSigmaAll; +std::shared_ptr hTPCnSigmaHe3; +std::shared_ptr hArmenterosPodolanskiAll; +std::shared_ptr hArmenterosPodolanskiSelected; +std::shared_ptr hInvariantMassUS; +std::shared_ptr hInvariantMassLS; + +}; // namespace + +using TracksFull = soa::Join; +using CollisionsFull = soa::Join; + +struct he3LambdaAnalysis { + + // Services + Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + o2::vertexing::DCAFitterN<2> fitter; + + Produces lfHe3V0Collision; + Produces lfHe3; + Produces lfLambda; + + // Configurables for event selection + struct : ConfigurableGroup { + std::string prefix = "cfgEventSelection"; + Configurable zVertexMax{"zVertexMax", 10.0f, "Accepted z-vertex range"}; + Configurable useSel8{"useSel8", true, "Use Sel8 event selection"}; + Configurable skimmedProcessing{"skimmedProcessing", false, "Skimmed dataset processing"}; + } cfgEventSelection; + + // He3 selection criteria + struct : ConfigurableGroup { + std::string prefix = "cfgHe3"; + Configurable ptMin{"ptMin", 1.0f, "Minimum He3 pT"}; + Configurable ptMax{"ptMax", 10.0f, "Maximum He3 pT"}; + Configurable etaMax{"etaMax", 0.9f, "Maximum He3 pseudorapidity"}; + Configurable minTPCrigidity{"minTPCrigidity", 0.5f, "Minimum He3 rigidity"}; + Configurable nSigmaTPCMax{"nSigmaTPCMax", 4.0f, "Maximum He3 TPC nSigma"}; + Configurable dcaxyMax{"dcaxyMax", 0.5f, "Maximum He3 DCA xy"}; + Configurable dcazMax{"dcazMax", 0.5f, "Maximum He3 DCA z"}; + Configurable tpcClusMin{"tpcClusMin", 100, "Minimum He3 TPC clusters"}; + Configurable itsClusMin{"itsClusMin", 5, "Minimum He3 ITS clusters"}; + Configurable> betheBlochParams{"betheBlochParams", {betheBlochDefault[0], 1, 6, particleName, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; + } cfgHe3; + + // Lambda selection criteria + struct : ConfigurableGroup { + std::string prefix = "cfgLambda"; + Configurable ptMin{"ptMin", 0.5f, "Minimum Lambda pT"}; + Configurable ptMax{"ptMax", 10.0f, "Maximum Lambda pT"}; + Configurable massWindow{"massWindow", 0.015f, "Lambda mass window"}; + Configurable cosPAMin{"cosPAMin", 0.99f, "Minimum Lambda cosPA"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum Lambda DCA V0 daughters"}; + Configurable v0RadiusMin{"v0RadiusMin", 0.5f, "Minimum Lambda V0 radius"}; + Configurable v0RadiusMax{"v0RadiusMax", 35.0f, "Maximum Lambda V0 radius"}; + Configurable tpcNClsMin{"tpcNClsMin", 70, "Minimum TPC clusters for Lambda daughters"}; + Configurable protonNSigmaTPCMax{"protonNSigmaTPCMax", 4.0f, "Maximum proton TPC nSigma"}; + Configurable pionNSigmaTPCMax{"pionNSigmaTPCMax", 4.0f, "Maximum pion TPC nSigma"}; + } cfgLambda; + + // Pair selection criteria + struct : ConfigurableGroup { + std::string prefix = "cfgPair"; + Configurable ptMin{"PtMin", 1.0f, "Minimum pair pT"}; + Configurable ptMax{"PtMax", 20.0f, "Maximum pair pT"}; + Configurable rapidityMax{"RapidityMax", 0.5f, "Maximum pair rapidity"}; + } cfgPair; + + // CCDB options + struct : ConfigurableGroup { + std::string prefix = "ccdb"; + Configurable url{"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"}; + } ccdbOptions; + + std::array mBBparamsHe; + float mBz = 0.0f; // Magnetic field in T + HistogramRegistry mRegistry{"He3LambdaAnalysis"}; + int mRunNumber = 0; // Current run number + + void init(InitContext const&) + { + // Initialize CCDB + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(true); + + for (int i = 0; i < 5; i++) { + mBBparamsHe[i] = cfgHe3.betheBlochParams->get("He3", Form("p%i", i)); + } + mBBparamsHe[5] = cfgHe3.betheBlochParams->get("He3", "resolution"); + matLUT = 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(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrLUT); + + zorroSummary.setObject(zorro.getZorroSummary()); + + mRegistry.add("hEventSelection", "Event Selection", {HistType::kTH1L, {{6, -.5, 5.5}}}); + std::vector labels{"Total Events", "Sel8 Events", "Z-Vertex OK", "Additional Event Selections", "He3 Candidates Found", "He3 and Lambda Candidates Found"}; + for (size_t i = 1; i <= labels.size(); ++i) { + mRegistry.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, labels[i - 1].c_str()); + } + + mRegistry.add("hCentralityAll", "Centrality All", {HistType::kTH1L, {{100, 0., 100.}}}); + mRegistry.add("hCentralitySelected", "Centrality Selected", {HistType::kTH1L, {{100, 0., 100.}}}); + + hTPCsignalAll = mRegistry.add("hTPCsignalAll", "TPC Signal All", {HistType::kTH2D, {{400, -10, 10}, {1000, 0, 2000}}}); + hTPCsignalHe3 = mRegistry.add("hTPCsignalHe3", "TPC Signal He3", {HistType::kTH2D, {{400, -10, 10}, {1000, 0, 2000}}}); + + hTPCnSigmaAll = mRegistry.add("hTPCnSigmaAll", "TPC nSigma All", {HistType::kTH2D, {{400, -10, 10}, {100, -5., 5.}}}); + hTPCnSigmaHe3 = mRegistry.add("hTPCnSigmaHe3", "TPC nSigma He3", {HistType::kTH2D, {{400, -10, 10}, {100, -5., 5.}}}); + + hArmenterosPodolanskiAll = mRegistry.add("hArmenterosPodolanskiAll", "Armenteros-Podolanski All", {HistType::kTH2D, {{100, -1., 1.}, {100, 0., 0.5}}}); + hArmenterosPodolanskiSelected = mRegistry.add("hArmenterosPodolanskiSelected", "Armenteros-Podolanski Selected", {HistType::kTH2D, {{100, -1., 1.}, {100, 0., 0.5}}}); + + constexpr double ConstituentsMass = o2::constants::physics::MassProton + o2::constants::physics::MassNeutron * 2 + o2::constants::physics::MassSigmaPlus; + hInvariantMassUS = mRegistry.add("hInvariantMassUS", "Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); + hInvariantMassLS = mRegistry.add("hInvariantMassLS", "Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); + + LOGF(info, "He3-Lambda analysis initialized"); + } + + void initCCDB(const auto& bc) + { + int runNumber = bc.runNumber(); + if (runNumber == mRunNumber) { + return; // Already initialized for this run + } + mRunNumber = runNumber; + if (cfgEventSelection.skimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + zorro.populateHistRegistry(mRegistry, bc.runNumber()); + } + o2::parameters::GRPMagField* grpmag = ccdb->getForRun("GLO/Config/GRPMagField", runNumber); + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = static_cast(grpmag->getNominalL3Field()); + fitter.setBz(mBz); + o2::base::Propagator::Instance()->setMatLUT(matLUT); + } + + void processData(CollisionsFull::iterator const& collision, + TracksFull const& tracks, + aod::V0s const& v0s, + aod::BCsWithTimestamps const&) + { + const auto& bc = collision.bc_as(); + initCCDB(bc); + + mRegistry.get(HIST("hEventSelection"))->Fill(0); // Total events + mRegistry.get(HIST("hCentralityAll"))->Fill(collision.centFT0C()); + if (cfgEventSelection.useSel8 && !collision.sel8()) { + return; // Skip events not passing Sel8 selection + } + mRegistry.get(HIST("hEventSelection"))->Fill(1); // Sel8 events + if (std::abs(collision.posZ()) > cfgEventSelection.zVertexMax) { + return; // Skip events with z-vertex outside range + } + mRegistry.get(HIST("hEventSelection"))->Fill(2); // Z-vertex OK + + // Additional event selections not implemented, but can be added here + if (cfgEventSelection.skimmedProcessing) { + if (!zorro.isSelected(bc.globalBC())) { + return; // Skip events not passing Zorro selection + } + } + mRegistry.get(HIST("hEventSelection"))->Fill(3); // Additional event selections + + // Process He3 candidates + std::vector he3Candidates; + o2::track::TrackParCov trackParCov; + trackParCov.setPID(o2::track::PID::Helium3); + const o2::math_utils::Point3D collVtx{collision.posX(), collision.posY(), collision.posZ()}; + + for (auto const& track : tracks) { + if (track.tpcNClsFound() < cfgHe3.tpcClusMin || track.itsNCls() < cfgHe3.itsClusMin) { + continue; // Skip tracks with insufficient clusters + } + hTPCsignalAll->Fill(track.tpcInnerParam() * track.sign(), track.tpcSignal()); + const float pt = track.pt() * 2.0f; + float expTPCSignal = o2::tpc::BetheBlochAleph(track.tpcInnerParam() * 2.0f / constants::physics::MassHelium3, mBBparamsHe[0], mBBparamsHe[1], mBBparamsHe[2], mBBparamsHe[3], mBBparamsHe[4]); + double nSigmaTPC = (track.tpcSignal() - expTPCSignal) / (expTPCSignal * mBBparamsHe[5]); + hTPCnSigmaAll->Fill(track.tpcInnerParam() * track.sign(), nSigmaTPC); + if (pt < cfgHe3.ptMin || pt > cfgHe3.ptMax || std::abs(track.eta()) > cfgHe3.etaMax || track.tpcInnerParam() < cfgHe3.minTPCrigidity || std::abs(nSigmaTPC) > cfgHe3.nSigmaTPCMax) { + continue; // Skip tracks outside He3 PID+kinematics selection criteria + } + setTrackParCov(track, trackParCov); + std::array dcaInfo; + o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParCov, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfo); + if (std::abs(dcaInfo[0]) > cfgHe3.dcaxyMax || std::abs(dcaInfo[1]) > cfgHe3.dcazMax) { + continue; // Skip tracks with DCA outside range + } + hTPCsignalHe3->Fill(track.tpcInnerParam() * track.sign(), track.tpcSignal()); + hTPCnSigmaHe3->Fill(track.tpcInnerParam() * track.sign(), nSigmaTPC); + he3Candidate candidate; + candidate.momentum.SetCoordinates(track.pt() * 2.0f, track.eta(), track.phi(), o2::constants::physics::MassHelium3); + candidate.nSigmaTPC = nSigmaTPC; + candidate.dcaXY = dcaInfo[0]; + candidate.dcaZ = dcaInfo[1]; + candidate.tpcNClsFound = track.tpcNClsFound(); + candidate.tpcNClsPID = track.tpcNClsPID(); + candidate.itsNCls = track.itsNCls(); + candidate.itsClusterSizes = track.itsClusterSizes(); + candidate.sign = track.sign() > 0 ? 1 : -1; + he3Candidates.push_back(candidate); + } + if (he3Candidates.empty()) { + return; // No valid He3 candidates found + } + mRegistry.get(HIST("hEventSelection"))->Fill(4); // He3 candidates found + + // Process Lambda candidates + std::vector lambdaCandidates; + for (auto const& v0 : v0s) { + if (v0.v0Type() != 1) { + continue; + } + const auto posTrack = v0.posTrack_as(); + const auto negTrack = v0.negTrack_as(); + + if (posTrack.tpcNClsFound() < cfgLambda.tpcNClsMin || negTrack.tpcNClsFound() < cfgLambda.tpcNClsMin) { + continue; // Skip V0s with insufficient TPC clusters + } + auto trackParPos = getTrackParCov(posTrack); + auto trackParNeg = getTrackParCov(negTrack); + int nCand = 0; + try { + nCand = fitter.process(trackParPos, trackParNeg); + } catch (...) { + LOG(error) << "Exception caught in DCA fitter process call!"; + return; + } + if (nCand == 0) { + continue; + } + auto& propParPos = fitter.getTrack(0); + auto& propParNeg = fitter.getTrack(1); + std::array momPos, momNeg; + propParPos.getPxPyPzGlo(momPos); + propParNeg.getPxPyPzGlo(momNeg); + const std::array momV0{momPos[0] + momNeg[0], momPos[1] + momNeg[1], momPos[2] + momNeg[2]}; + float alpha = alphaAP(momV0, momPos, momNeg); + float qt = qtAP(momV0, momPos); + hArmenterosPodolanskiAll->Fill(alpha, qt); + + bool matter = alpha > 0; + const auto& protonTrack = matter ? posTrack : negTrack; + const auto& pionTrack = matter ? negTrack : posTrack; + const auto& protonMom = matter ? momPos : momNeg; + const auto& pionMom = matter ? momNeg : momPos; + + if (std::abs(protonTrack.tpcNSigmaPr()) > cfgLambda.protonNSigmaTPCMax || + std::abs(pionTrack.tpcNSigmaPi()) > cfgLambda.pionNSigmaTPCMax) { + continue; // Skip V0s with TPC nSigma outside range + } + ROOT::Math::LorentzVector> protonMom4D(protonMom[0], protonMom[1], protonMom[2], o2::constants::physics::MassProton); + ROOT::Math::LorentzVector> pionMom4D(pionMom[0], pionMom[1], pionMom[2], o2::constants::physics::MassPionCharged); + auto lambdaMom4D = protonMom4D + pionMom4D; + float massLambda = lambdaMom4D.M(); + + if (std::abs(massLambda - o2::constants::physics::MassLambda0) > cfgLambda.massWindow) { + continue; // Skip V0s outside mass window + } + hArmenterosPodolanskiSelected->Fill(alpha, qt); + + std::array dcaInfoProton, dcaInfoPion; + o2::base::Propagator::Instance()->propagateToDCA(collVtx, matter ? trackParPos : trackParNeg, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoProton); + o2::base::Propagator::Instance()->propagateToDCA(collVtx, matter ? trackParNeg : trackParPos, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoPion); + + const auto sv = fitter.getPCACandidate(0); + + lambdaCandidate candidate; + candidate.momentum.SetCoordinates(lambdaMom4D.Pt(), lambdaMom4D.Eta(), lambdaMom4D.Phi(), o2::constants::physics::MassLambda0); + candidate.mass = massLambda; + candidate.cosPA = (sv[0] - collVtx.x()) * lambdaMom4D.Px() + + (sv[1] - collVtx.y()) * lambdaMom4D.Py() + + (sv[2] - collVtx.z()) * lambdaMom4D.Pz(); + candidate.cosPA /= std::hypot(sv[0] - collVtx.x(), sv[1] - collVtx.y(), sv[2] - collVtx.z()) * lambdaMom4D.P(); + candidate.dcaV0Daughters = std::sqrt(fitter.getChi2AtPCACandidate(0)); + candidate.dcaProtonToPV = std::hypot(dcaInfoProton[0], dcaInfoProton[1]); + candidate.dcaPionToPV = std::hypot(dcaInfoPion[0], dcaInfoPion[1]); + candidate.v0Radius = std::hypot(sv[0], sv[1]); + candidate.protonNSigmaTPC = protonTrack.tpcNSigmaPr(); + candidate.pionNSigmaTPC = pionTrack.tpcNSigmaPi(); + candidate.sign = matter ? 1 : -1; // Positive sign for Lambda, negative for anti-Lambda + lambdaCandidates.push_back(candidate); + } + if (lambdaCandidates.empty()) { + return; // No valid Lambda candidates found + } + mRegistry.get(HIST("hEventSelection"))->Fill(5); // He3 and Lambda candidates found + mRegistry.get(HIST("hCentralitySelected"))->Fill(collision.centFT0C()); + + // Fill output tables + lfHe3V0Collision(collision.posZ(), collision.centFT0C()); + for (const auto& he3 : he3Candidates) { + lfHe3(lfHe3V0Collision.lastIndex(), he3.momentum.Pt(), he3.momentum.Eta(), he3.momentum.Phi(), + he3.dcaXY, he3.dcaZ, he3.tpcNClsFound, he3.tpcNClsPID, he3.itsClusterSizes, he3.nSigmaTPC, he3.sign); + } + for (const auto& lambda : lambdaCandidates) { + lfLambda(lfHe3V0Collision.lastIndex(), lambda.momentum.Pt(), lambda.momentum.Eta(), lambda.momentum.Phi(), + lambda.mass, lambda.cosPA, lambda.dcaV0Daughters, lambda.dcaProtonToPV, lambda.dcaPionToPV, lambda.v0Radius, lambda.protonNSigmaTPC, lambda.pionNSigmaTPC, lambda.sign); + } + + for (const auto& he3 : he3Candidates) { + for (const auto& lambda : lambdaCandidates) { + auto pairMomentum = lambda.momentum + he3.momentum; // Calculate invariant mass + (he3.sign * lambda.sign > 0 ? hInvariantMassLS : hInvariantMassUS)->Fill(pairMomentum.Pt(), pairMomentum.M()); + } + } + } + PROCESS_SWITCH(he3LambdaAnalysis, processData, "Process data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Nuspex/hyhe4builder.cxx b/PWGLF/TableProducer/Nuspex/hyhe4builder.cxx index ea733209de8..66fe812f7a2 100644 --- a/PWGLF/TableProducer/Nuspex/hyhe4builder.cxx +++ b/PWGLF/TableProducer/Nuspex/hyhe4builder.cxx @@ -249,7 +249,7 @@ struct hyhefourbuilder { //---/---/---/---/---/---/---/---/---/---/---/---/---/ // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo; + std::array dcaInfo; o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, lHelium3TrackForDCA, 2.f, fitter.getMatCorrType(), &dcaInfo); hyHe4Candidate.dcaXY3He = dcaInfo[0]; o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, lProtonTrackForDCA, 2.f, fitter.getMatCorrType(), &dcaInfo); diff --git a/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx new file mode 100644 index 00000000000..7085e1082a2 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx @@ -0,0 +1,1374 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "MetadataHelper.h" + +#include "PWGLF/DataModel/LFHypernucleiKfTables.h" + +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTPCBase.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include "TRandom3.h" + +#include +#include +#include +#include + +// KFParticle +#ifndef HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (Name is defined in KFParticle package) +#endif +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticle.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; + +o2::common::core::MetadataHelper metadataInfo; // Metadata helper +//---------------------------------------------------------------------------------------------------------------- + +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}, + {1120020040}, + {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::array 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"); + for (unsigned int i = 0; i < betheParams.size(); i++) + betheParams[i] = bethe.get(name, i); + } + int getCentralPIDIndex() { return getPIDIndex(pdgCode); } +}; // struct DaughterParticle + +struct HyperNucleus { + TString name; + int pdgCode; + bool active, savePrimary; + std::vector daughters, daughterTrackSigns; + HyperNucleus(std::string name_, int pdgCode_, bool active_, std::vector daughters_, std::vector daughterTrackSigns_) : pdgCode(pdgCode_), active(active_), savePrimary(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_), savePrimary(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 species, hypNucId; + KFParticle daughterKfp; + float dcaToPv, dcaToPvXY, dcaToPvZ, tpcNsigma, tpcNsigmaNLP, tpcNsigmaNHP; + bool active; + std::vector vtx; + DaughterKf(int species_, int64_t daughterTrackId_, std::vector vtx_, float tpcNsigma_, float tpcNsigmaNLP_, float tpcNsigmaNHP_) : daughterTrackId(daughterTrackId_), species(species_), hypNucId(-1), tpcNsigma(tpcNsigma_), tpcNsigmaNLP(tpcNsigmaNLP_), tpcNsigmaNHP(tpcNsigmaNHP_), vtx(vtx_) {} + DaughterKf(int species_, KFParticle daughterKfp_, int hypNucId_) : daughterTrackId(-999), species(species_), hypNucId(hypNucId_), daughterKfp(daughterKfp_), dcaToPv(-999), dcaToPvXY(-999), dcaToPvZ(-999) {} + void addKfp(KFParticle daughterKfp_) + { + daughterKfp = daughterKfp_; + dcaToPvXY = daughterKfp.GetDistanceFromVertexXY(&vtx[0]); + dcaToPv = daughterKfp.GetDistanceFromVertex(&vtx[0]); + dcaToPvZ = std::sqrt(dcaToPv * dcaToPv - dcaToPvXY * dcaToPvXY); + } + + bool isTrack() { return daughterTrackId >= 0; } +}; // 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) // o2-linter: disable=magic-number (To be checked) + 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) + { + return calcSubDaughterMass(daughters.at(d1)->daughterKfp, daughters.at(d2)->daughterKfp); + } + float getSubDaughterMassCascade(int d1, int d2) + { + if (!isCascade()) { + LOGF(warning, "Primary hypernucleus has no hypernucleus daughter!"); + return -999; + } + return calcSubDaughterMass(daughters.at(d1)->daughterKfp, hypNucDaughter->daughters.at(d2)->daughterKfp); + } + float calcSubDaughterMass(KFParticle d1, KFParticle d2) + { + KFParticle subDaughter; + subDaughter.SetConstructMethod(2); + subDaughter.AddDaughter(d1); + subDaughter.AddDaughter(d2); + 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; + } + bool hasIndex(int64_t a) + { + for (const auto& pair : pairs) { + if (pair.first == a) + 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"}; + + // TPC PID Response + bool usePidResponse; + o2::pid::tpc::Response* response; + std::map metadata; + std::array betheParams; + + // 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", "Analysis/PID/TPC/Response", "Path to the PID response object"}; + + std::vector activePdgs; + std::vector daughterParticles; + 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, isMC; + int64_t mcCollTableIndex; + int mRunNumber, occupancy; + float dBz; + TRandom3 rand; + //---------------------------------------------------------------------------------------------------------------- + + void init(InitContext const&) + { + isMC = false; + mRunNumber = 0; + dBz = 0; + rand.SetSeed(0); + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + usePidResponse = false; + for (unsigned 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)); + if (cfgTrackPIDsettings->get(i, "useBBparams") == 2 || cfgTrackPIDsettings->get(i, "useBBparams") == 0) // o2-linter: disable=magic-number (To be checked) + usePidResponse = true; + } + + for (unsigned int i = 0; i < nHyperNuclei; i++) { // create hypernuclei + auto active = cfgHyperNucsActive->get(i, 0u); + auto pdg = cfgHyperNucPdg->get(i, 0u); + singleHyperNuclei.push_back(HyperNucleus(hyperNucNames.at(i), pdg, active, getDaughterVec(i, cfgHyperNucDaughters), getDaughterSignVec(i, cfgHyperNucSigns))); + if (active) + activePdgs.push_back(pdg); + } + + activeCascade = false; + for (unsigned int i = 0; i < nCascades; i++) { // create cascades + auto active = cfgCascadesActive->get(i, 0u); + auto pdg = cfgCascadesPdg->get(i, 0u); + auto hypDaughter = getHypDaughterVec(i, cfgCascadeHypDaughter); + cascadeHyperNuclei.push_back(HyperNucleus(cascadeNames.at(i), pdg, active, hypDaughter, getDaughterVec(i, cfgCascadeDaughters), getDaughterSignVec(i, cfgCascadeSigns))); + if (active) { + activePdgs.push_back(pdg); + if (!singleHyperNuclei.at(hypDaughter).active) { + singleHyperNuclei.at(hypDaughter).active = true; + activePdgs.push_back(singleHyperNuclei.at(hypDaughter).pdgCode); + } + 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, CollisionsFull::iterator const& coll) + { + // 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 (getRigidity(track) < cfgTrackPIDsettings->get(i, "minRigidity") || getRigidity(track) > cfgTrackPIDsettings->get(i, "maxRigidity")) + continue; + float tpcNsigma = getTPCnSigma(track, coll, daughterParticles.at(i)); + if (std::abs(tpcNsigma) > 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 (cfgTrackPIDsettings->get(i, "TOFrequiredabove") >= 0 && getRigidity(track) > cfgTrackPIDsettings->get(i, "TOFrequiredabove") && (track.mass() < cfgTrackPIDsettings->get(i, "minTOFmass") || track.mass() > cfgTrackPIDsettings->get(i, "maxTOFmass"))) + continue; + float tpcNsigmaNHP = (i == kAlpha ? -999 : getTPCnSigma(track, coll, daughterParticles.at(i + 1))); + float tpcNsigmaNLP = (i == kPion ? 999 : getTPCnSigma(track, coll, daughterParticles.at(i - 1))); + foundDaughterKfs.at(i).push_back(DaughterKf(i, track.globalIndex(), primVtx, tpcNsigma, tpcNsigmaNLP, tpcNsigmaNHP)); + } + } // track loop + } + //---------------------------------------------------------------------------------------------------------------- + + void checkMCTrueTracks(aod::McTrackLabels const& trackLabels, aod::McParticles const&, TracksFull const& tracks, CollisionsFull::iterator const& coll) + { + for (int i = 0; i < nDaughterParticles; i++) { + auto& daughterVec = foundDaughterKfs.at(i); + if (!daughterVec.size()) + continue; + for (auto it = daughterVec.end() - 1; it >= daughterVec.begin(); it--) { + const auto& mcLab = trackLabels.rawIteratorAt(it->daughterTrackId); + if (!mcLab.has_mcParticle()) { + daughterVec.erase(it); + continue; + } + const auto& mcPart = mcLab.mcParticle_as(); + if (cfgSaveOnlyMcTrue) { + 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; + } + } + if (cfgTrackPIDsettings->get(i, "useBBparams") == 0) { + const auto& trk = tracks.rawIteratorAt(it->daughterTrackId); + const auto tpcNsigmaMC = getTPCnSigmaMC(trk, coll, daughterParticles.at(i), daughterParticles.at(i)); + if (std::abs(tpcNsigmaMC) <= cfgTrackPIDsettings->get(i, "maxTPCnSigma")) { + it->tpcNsigma = tpcNsigmaMC; + it->tpcNsigmaNHP = (i == kAlpha ? -999 : getTPCnSigmaMC(trk, coll, daughterParticles.at(i), daughterParticles.at(i + 1))); + it->tpcNsigmaNLP = (i == kPion ? 999 : getTPCnSigmaMC(trk, coll, daughterParticles.at(i), daughterParticles.at(i - 1))); + } else { + daughterVec.erase(it); + } + } + } + } + } + //---------------------------------------------------------------------------------------------------------------- + void createKFDaughters(TracksFull const& tracks) + { + for (size_t daughterCount = 0; daughterCount < daughterParticles.size(); daughterCount++) { + daughterParticles.at(daughterCount).active = false; + } + std::vector*> hypNucVectors = {&singleHyperNuclei, &cascadeHyperNuclei}; + bool singleHypNucActive = false; + for (size_t vec = 0; vec < hypNucVectors.size(); vec++) { + for (const auto& hyperNuc : *(hypNucVectors.at(vec))) { + if (!hyperNuc.active) + continue; + for (size_t i = vec; i < hyperNuc.daughters.size(); i++) { + if (foundDaughterKfs.at(hyperNuc.daughters.at(i)).size() > 0) + daughterParticles.at(hyperNuc.daughters.at(i)).active = true; + else + break; + if (i == hyperNuc.daughters.size() - 1) + singleHypNucActive = true; + } + } + if (!singleHypNucActive) + break; + } + + for (size_t daughterCount = 0; daughterCount < daughterParticles.size(); daughterCount++) { + const auto& daughterParticle = daughterParticles.at(daughterCount); + if (!daughterParticle.active) { + foundDaughterKfs.at(daughterCount).clear(); + continue; + } + const auto& daughterMass = daughterParticle.mass; + const auto& daughterCharge = daughterParticle.charge; + auto& daughterVec = foundDaughterKfs.at(daughterCount); + for (auto it = daughterVec.end() - 1; it >= daughterVec.begin(); it--) { + const auto& daughterTrack = tracks.rawIteratorAt(it->daughterTrackId); + it->addKfp(createKFParticle(daughterTrack, daughterMass, daughterCharge)); + if (std::abs(it->dcaToPvXY) < cfgTrackPIDsettings->get(daughterCount, "minDcaToPvXY") || std::abs(it->dcaToPvZ) < cfgTrackPIDsettings->get(daughterCount, "minDcaToPvZ")) + daughterVec.erase(it); + } + } + } + //---------------------------------------------------------------------------------------------------------------- + + 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 && hyperNuc->savePrimary) || (candidate.isSecondaryCandidate && activeCascade)) + 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(hyperNuc->daughters.at(0), 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] (Object is non const and modified in loop) + std::vector motherIds; + 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; + } + } + } + for (const auto& daughter : hypCand.daughters) { + if (!daughter->isTrack()) + 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(daughter->species).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 (!mcPartIndices.hasIndex(motherIds.front())) + 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, mRunNumber); + + std::vector*> hypNucVectors = {&singleHyperNuclei, &cascadeHyperNuclei}; + std::vector>*> candidateVectors = {&singleHyperNucCandidates, &cascadeHyperNucCandidates}; + + for (unsigned int vec = 0; vec < candidateVectors.size(); 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 (Object is non const and modified in 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; + for (const auto& daughter : hypCand.daughters) { + if (!daughter->isTrack()) + continue; + const auto& daughterTrackId = daughter->daughterTrackId; + int trackTableId; + if (!trackIndices.getIndex(daughterTrackId, trackTableId)) { + const auto& track = tracks.rawIteratorAt(daughterTrackId); + outputTrackTable( + daughter->species * track.sign(), track.pt(), track.eta(), track.phi(), daughter->dcaToPvXY, daughter->dcaToPvZ, track.tpcNClsFound(), track.tpcChi2NCl(), + track.itsClusterSizes(), track.itsChi2NCl(), getRigidity(track), track.tpcSignal(), daughter->tpcNsigma, daughter->tpcNsigmaNHP, daughter->tpcNsigmaNLP, + track.mass(), track.isPVContributor()); + trackTableId = outputTrackTable.lastIndex(); + trackIndices.add(daughterTrackId, trackTableId); + } + vecDaugtherTracks.push_back(trackTableId); + } + 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) { // o2-linter: disable=magic-number (To be checked) + 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()); + } + } + } + if (hypCand.isCascade()) { + for (int i = 1; i < hypCand.getNdaughters(); i++) { + for (int j = 0; j < hypCand.hypNucDaughter->getNdaughters(); j++) { + outputSubDaughterTable(hypCand.getSubDaughterMassCascade(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, CollisionsFull const& colls) + { + isMC = true; + 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) // o2-linter: disable=magic-number (To be checked) + mcCollInfos.at(collision.mcCollisionId()).passedEvSel = true; + } + std::vector*> hypNucVectors = {&singleHyperNuclei, &cascadeHyperNuclei}; + for (const auto& mcPart : particlesMC) { + if (!mcCollInfos.at(mcPart.mcCollisionId()).passedEvSel) + continue; + for (unsigned int vec = 0; vec < hypNucVectors.size(); 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 = vec ? singleHyperNuclei.at(hyperNuc->daughters.at(0)).pdgCode : daughterParticles.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); + if (!collision.has_mcCollision() || !mcCollInfos.at(collision.mcCollisionId()).passedEvSel) + continue; + + const uint64_t collIdx = collision.globalIndex(); + auto tracksByColl = tracksColl.sliceBy(perCollision, collIdx); + findDaughterParticles(tracksByColl, tracks, colls.rawIteratorAt(collision.globalIndex())); + if (cfgSaveOnlyMcTrue || usePidResponse) + checkMCTrueTracks(trackLabelsMC, particlesMC, tracks, colls.rawIteratorAt(collision.globalIndex())); + 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 = 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, collision); + 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) { // o2-linter: disable=magic-number (To be checked) + // 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) { // o2-linter: disable=magic-number (To be checked) + // 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); + + // PID response + if (!usePidResponse) + return; + if (metadataInfo.isFullyDefined()) { + metadata["RecoPassName"] = metadataInfo.get("RecoPassName"); + LOGP(info, "Automatically setting reco pass for TPC Response to {} from AO2D", metadata["RecoPassName"]); + } else { + LOG(info) << "Setting reco pass for TPC response to default name"; + metadata["RecoPassName"] = "apass5"; + } + const std::string path = pidPath.value; + ccdb->setTimestamp(run3grpTimestamp); + response = ccdb->getSpecific(path, run3grpTimestamp, metadata); + if (!response) { + LOGF(warning, "Unable to find TPC parametrisation for specified pass name - falling back to latest object"); + response = ccdb->getForTimeStamp(path, run3grpTimestamp); + if (!response) { + LOGF(fatal, "Unable to find any TPC object corresponding to timestamp {}!", run3grpTimestamp); + } + } + LOG(info) << "Successfully retrieved TPC PID object from CCDB for timestamp " << run3grpTimestamp << ", recoPass " << metadata["RecoPassName"]; + response->PrintAll(); + betheParams = response->GetBetheBlochParams(); + } + //---------------------------------------------------------------------------------------------------------------- + template + void initCollision(const T& collision) + { + 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; // o2-linter: disable=magic-number (To be checked) + 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) // o2-linter: disable=magic-number (To be checked) + return; + hDeDx[2 * species + 1]->Fill(track.sign() * rigidity, track.tpcSignal()); + } + //---------------------------------------------------------------------------------------------------------------- + + template + float getTPCnSigma(T const& track, C const& coll, DaughterParticle& particle) + { + const float rigidity = getRigidity(track); + if (!track.hasTPC()) + return -999; + float mMip = 1, chargeFactor = 1; + float* parBB; + + switch (static_cast(cfgTrackPIDsettings->get(particle.name, "useBBparams"))) { + case -1: + return 0; + case 0: + return isMC ? 0 : response->GetNumberOfSigma(coll, track, particle.getCentralPIDIndex()); + case 1: + parBB = &particle.betheParams[0]; + break; + case 2: + mMip = response->GetMIP(); + chargeFactor = std::pow(particle.charge, response->GetChargeFactor()); + parBB = &betheParams[0]; + break; + default: + return -999; + } + double expBethe{mMip * chargeFactor * o2::tpc::BetheBlochAleph(static_cast(particle.charge * rigidity / particle.mass), parBB[0], parBB[1], parBB[2], parBB[3], parBB[4])}; + double expSigma{expBethe * particle.resolution}; + float sigmaTPC = static_cast((track.tpcSignal() - expBethe) / expSigma); + return sigmaTPC; + } + //---------------------------------------------------------------------------------------------------------------- + + template + float getTPCnSigmaMC(T const& trk, C const& coll, DaughterParticle& particle1, DaughterParticle& particle2) + { + const float pidval1 = particle1.getCentralPIDIndex(); + const float pidval2 = particle2.getCentralPIDIndex(); + const auto expSignal = response->GetExpectedSignal(trk, pidval2); + const auto expSigma = response->GetExpectedSigma(coll, trk, pidval2); + const auto mcTunedTPCSignal = gRandom->Gaus(expSignal, expSigma); + return response->GetNumberOfSigmaMCTuned(coll, trk, pidval1, mcTunedTPCSignal); + } + //---------------------------------------------------------------------------------------------------------------- + + template + float getMeanItsClsSize(T const& track) + { + int sum = 0, n = 0; + for (int i = 0; i < 0x08; i++) { + sum += (track.itsClusterSizes() >> (0x04 * i) & 0x0f); + if (track.itsClusterSizes() >> (0x04 * i) & 0x0f) + 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 < 0x03; 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 < 0x04; 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 < 0x04; 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) +{ + metadataInfo.initMetadata(cfgc); // Parse AO2D metadata + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} +//---------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------- diff --git a/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx b/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx new file mode 100644 index 00000000000..bae25b5272c --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx @@ -0,0 +1,812 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFHypernucleiKfTables.h" + +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include + +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), speciesMC(0), isPrimaryCandidate(0), isMatter(0), isCascade(0), isCascadeMC(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, speciesMC; + bool isPrimaryCandidate, isMatter, isCascade, isCascadeMC, 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, runNumber; + 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(RunNumber, runNumber, int); +DECLARE_SOA_COLUMN(PassedEvSelMC, passedEvSelMC, bool); +DECLARE_SOA_COLUMN(SpeciesMC, speciesMC, int8_t); //! +DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); +DECLARE_SOA_COLUMN(IsMatterGen, isMatterGen, bool); +DECLARE_SOA_COLUMN(IsReconstructed, isReconstructed, int); +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); +DECLARE_SOA_COLUMN(D1sd1Mass, d1sd1Mass, float); +DECLARE_SOA_COLUMN(D1sd2Mass, d1sd2Mass, float); +DECLARE_SOA_COLUMN(D1sd3Mass, d1sd3Mass, float); +} // namespace hypkftree + +#define HYPKFGENBASE hypkftree::SpeciesMC, 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, hypkftree::RunNumber, 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 +#define HYPKFCSDMASS hypkftree::D1sd1Mass, hypkftree::D1sd2Mass, hypkftree::D1sd3Mass + +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, HYPKFCSDMASS); +using HypKfCascadeTwoThreeCandidate = HypKfCascadeTwoThreeCandidates::iterator; + +DECLARE_SOA_TABLE(HypKfMcCascadeTwoThreeCandidates, "AOD", "HYPKFMCCAND23", HYPKFGENBASE, HYPKFGENEXT, HYPKFHYPNUC, HYPKFD0, HYPKFD1, HYPKFSD1, HYPKFSD2, HYPKFSD3, HYPKFSSDMASS, HYPKFCSDMASS); +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.speciesMC, 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(8); + } + + if (cfgNprimDaughters == 2 && cfgNsecDaughters == 0) { // o2-linter: disable=magic-number (To be checked) + 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.runNumber, 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.speciesMC, 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.runNumber, 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 (((!isMC && cand.isPrimaryCandidate) || (isMC && cand.isPhysicalPrimary)) && ((cfgNprimDaughters == 3 && cfgNsecDaughters == 0) || (cfgNsecDaughters == 3 && cfgSpecies == 0))) { // o2-linter: disable=magic-number (To be checked) + 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.runNumber, 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.speciesMC, 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.runNumber, 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 ((!isMC && !cand.isCascade) || (isMC && !cand.isCascadeMC)) + return; + if (cfgNprimDaughters == 2 && cfgNsecDaughters == 3) { // o2-linter: disable=magic-number (To be checked) + 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.runNumber, 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, cand.subDaughterMassVec.at(0), cand.subDaughterMassVec.at(1), cand.subDaughterMassVec.at(2)); + if (isMC && cfgMCCombined) + outputTableMcTwoThree( + cand.speciesMC, 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.runNumber, 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, cand.subDaughterMassVec.at(0), cand.subDaughterMassVec.at(1), cand.subDaughterMassVec.at(2)); + } + if (cfgNprimDaughters == 3 && cfgNsecDaughters == 1) { // o2-linter: disable=magic-number (To be checked) + 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.runNumber, 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.speciesMC, 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.runNumber, 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.mcTrue = hypNuc.mcTrue(); + cand.isCascade = cand.species > 10; // o2-linter: disable=magic-number (To be checked) + cand.cent = coll.centFT0C(); + cand.occu = coll.occupancy(); + cand.runNumber = coll.runNumber(); + 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.pz(); + trackCount++; + } + + if (cand.isCascade) { + auto subDaughters = hypNuc.hypKfSubD_as(); + for (const auto& subDaughter : subDaughters) { + cand.subDaughterMassVec.push_back(subDaughter.subMass()); + } + } + + cand.nSingleDaughters = trackCount; + if (cand.nSingleDaughters < 3) // o2-linter: disable=magic-number (To be checked) + 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.speciesMC = mcHypNuc.species(); + candidate.isCascadeMC = candidate.speciesMC > 10; // o2-linter: disable=magic-number (To be checked) + candidate.pdgCode = mcHypNuc.pdgCode(); + candidate.isMatterMC = mcHypNuc.isMatter(); + candidate.isPhysicalPrimary = mcHypNuc.isPhysicalPrimary(); + candidate.mcPhysicalPrimary = 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 658ab180d67..00000000000 --- a/PWGLF/TableProducer/Nuspex/hyperKinkRecoTask.cxx +++ /dev/null @@ -1,688 +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/Utils/svPoolCreator.h" -#include "PWGLF/DataModel/LFHypernucleiTables.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; -using CollisionsFull = soa::Join; -using CollisionsFullMC = 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 isRecoMCCollision = false; // true if the corresponding MC collision has been reconstructed - bool isSurvEvSelection = false; // true if the corresponding event passed the event selection - int pdgCode = 0; // pdg code of the mother particle -}; - -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"}; - - svPoolCreator svCreator{hyperPdg, tritDauPdg}; - - // 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"}; - 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 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 recoCollisionIds; - std::vector isSurvEvSelCollision; - std::vector goodCollision; - // std vector of candidates - std::vector kinkCandidates; - // 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 - 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)); - - 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)"}; - 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}}); - } - - template - void selectGoodCollisions(const Tcoll& collisions) - { - for (const auto& collision : collisions) { - auto bc = collision.template bc_as(); - initCCDB(bc); - hEvents->Fill(0.); - - if (!collision.sel8() || std::abs(collision.posZ()) > 10) { - continue; - } - - goodCollision[collision.globalIndex()] = true; - hEvents->Fill(1.); - hZvtx->Fill(collision.posZ()); - 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 (!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()); - } - } - - 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; - } - - 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 isTrit = selectTritTrack(track); - bool isHyp = selectHyperTrack(track); - - if (!isTrit && !isHyp) - continue; - - if (isHyp && !track.has_collision()) - continue; - - int pdgHypo = isHyp ? hyperPdg : tritDauPdg; - svCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); - } - auto& kinkPool = svCreator.getSVCandPool(collisions, !unlikeSignBkg); - LOG(debug) << "SV pool size: " << kinkPool.size(); - - for (auto& svCand : kinkPool) { - - kinkCandidate kinkCand; - - auto trackHyper = tracks.rawIteratorAt(svCand.tr0Idx); - auto trackTrit = tracks.rawIteratorAt(svCand.tr1Idx); - - auto const& collision = trackHyper.template 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()); - kinkCand.primVtx = {primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}; - - 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; - } - - 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 = trackHyper.globalIndex(); - kinkCand.hypDCAXY = dcaInfoHyp[0]; - kinkCand.clusterSizeITSHyp = trackHyper.itsClusterSizes(); - kinkCand.isMatter = trackHyper.sign() > 0; - kinkCand.tritTrackID = trackTrit.globalIndex(); - 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; - kinkCandidates.push_back(kinkCand); - } - } - - void fillMCinfo(aod::McTrackLabels const& trackLabels, aod::McParticles const&) - { - - for (auto& kinkCand : kinkCandidates) { - 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, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) - { - if (mBBparamsTrit[5] < 0) { - LOG(info) << "Bethe-Bloch parameters for Triton not set, using default nSigma"; - } - goodCollision.clear(); - goodCollision.resize(collisions.size(), false); - kinkCandidates.clear(); - selectGoodCollisions(collisions); - fillCandidateData(collisions, tracks, ambiTracks, bcs); - for (auto& kinkCand : kinkCandidates) { - 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(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) - { - filledMothers.clear(); - recoCollisionIds.clear(); - recoCollisionIds.resize(mcCollisions.size(), -1); - isSurvEvSelCollision.clear(); - isSurvEvSelCollision.resize(mcCollisions.size(), false); - goodCollision.clear(); - goodCollision.resize(collisions.size(), false); - kinkCandidates.clear(); - - selectGoodCollisionsMC(collisions); - fillCandidateData(collisions, tracks, ambiTracks, bcs); - fillMCinfo(trackLabelsMC, particlesMC); - - 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(); - kinkCand.isRecoMCCollision = recoCollisionIds[mcPart.mcCollisionId()] > 0; - kinkCand.isSurvEvSelection = isSurvEvSelCollision[mcPart.mcCollisionId()]; - 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; - kinkCandidates.push_back(kinkCand); - mcToKinkCandidates[hyperMCIndex] = kinkCandidates.size() - 1; - } - - // look for hypertriton or triton tracks, findable part! - 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 = kinkCandidates[mcToKinkCandidates[mcTrack.globalIndex()]]; - kinkCand.mcMask = mcLabel.mcMask(); - kinkCand.itsPt = track.pt(); - } - } - - for (auto& kinkCand : kinkCandidates) { - 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, - kinkCand.isRecoMCCollision, kinkCand.isSurvEvSelection); - } - } - 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 6c73c12ff6b..eaf10bb9bbd 100644 --- a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx @@ -11,38 +11,45 @@ // // Build hypertriton candidates from V0s and tracks -#include +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFHypernucleiTables.h" +#include "PWGLF/Utils/svPoolCreator.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/TPCPIDResponse.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "PWGLF/DataModel/EPCalibrationTables.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" +#include "Common/TableProducer/PID/pidTOFBase.h" -#include "EventFiltering/Zorro.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "DataFormatsTPC/BetheBlochAleph.h" +#include "CCDB/BasicCCDBManager.h" #include "DCAFitter/DCAFitterN.h" -#include "PWGLF/Utils/svPoolCreator.h" -#include "PWGLF/DataModel/LFHypernucleiTables.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using std::array; using CollBracket = o2::math_utils::Bracket; -using TracksFull = soa::Join; +using TracksFull = soa::Join; using CollisionsFull = soa::Join; using CollisionsFullMC = soa::Join; @@ -52,8 +59,9 @@ 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; @@ -82,7 +90,7 @@ struct hyperCandidate { float genPhi() const { return std::atan2(gMom[1], gMom[0]); } float genEta() const { return std::asinh(gMom[2] / genPt()); } - int v0ID; + int v0ID = -1; int heTrackID; int piTrackID; float dcaV0dau = -10; @@ -100,17 +108,25 @@ struct hyperCandidate { std::array gDecVtx; uint16_t tpcSignalHe3 = 0u; uint16_t tpcSignalPi = 0u; + float tpcChi2He3 = 0.f; + float itsChi2He3 = 0.f; + float itsChi2Pi = 0.f; + float massTOFHe3 = 0.f; uint8_t nTPCClustersHe3 = 0u; uint8_t nTPCClustersPi = 0u; + uint8_t nTPCpidClusHe3 = 0u; + uint8_t nTPCpidClusPi = 0u; uint32_t clusterSizeITSHe3 = 0u; uint32_t clusterSizeITSPi = 0u; // collision information - unsigned int collisionID = 0; + int64_t collisionID = 0; bool isMatter = false; - bool isSignal = false; // true MC signal - bool isReco = false; // true if the candidate is actually reconstructed + bool isSignal = false; // true MC signal + bool isReco = false; // true if the candidate is actually reconstructed + uint8_t isFakeHeOnITSLayer = 0u; // bit map for fake He on ITS layers + bool isRecoMCCollision = false; // true if the corresponding MC collision has been reconstructed bool isSurvEvSelection = false; // true if the corresponding event passed the event selection int pdgCode = 0; // PDG code of the hypernucleus @@ -122,8 +138,10 @@ struct hyperRecoTask { Produces outputDataTable; Produces outputDataTableWithFlow; Produces outputMCTable; + Produces outputDataTableWithCollID; Service ccdb; Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; // PDG codes Configurable hyperPdg{"hyperPDG", 1010010030, "PDG code of the hyper-mother (could be 3LamH or 4LamH)"}; @@ -133,6 +151,7 @@ struct hyperRecoTask { 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"}; @@ -142,10 +161,11 @@ struct hyperRecoTask { 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}; + svPoolCreator svCreator{heDauPdg, PDG_t::kPiPlus}; // daughter masses float he3Mass = o2::constants::physics::MassHelium3; @@ -154,8 +174,9 @@ struct hyperRecoTask { Configurable useCustomVertexer{"useCustomVertexer", false, "Use custom vertexer"}; Configurable skipAmbiTracks{"skipAmbiTracks", false, "Skip ambiguous tracks"}; + Configurable disableITSROFCut{"disableITSROFCut", false, "Disable ITS ROC cut for event selection"}; Configurable customVertexerTimeMargin{"customVertexerTimeMargin", 800, "Time margin for custom vertexer (ns)"}; - Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {betheBlochDefault[0], 1, 6, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; + 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"}; @@ -183,7 +204,7 @@ struct hyperRecoTask { std::vector recoCollisionIds; std::vector isSurvEvSelCollision; std::vector goodCollision; - std::vector isTracked; + std::vector trackedClSize; Preslice perCollision = o2::aod::v0::collisionId; @@ -196,6 +217,8 @@ struct hyperRecoTask { void init(InitContext const&) { + zorroSummary.setObject(zorro.getZorroSummary()); + mRunNumber = 0; d_bz = 0; @@ -233,11 +256,15 @@ struct hyperRecoTask { hH4LMassBefSel = qaRegistry.add("hH4LMassBefSel", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 3.76, 3.84}}); hH4LMassTracked = qaRegistry.add("hH4LMassTracked", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 3.76, 3.84}}); - hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{3, -0.5, 2.5}}); + hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hEvents->GetXaxis()->SetBinLabel(1, "All"); hEvents->GetXaxis()->SetBinLabel(2, "Selected"); - hEvents->GetXaxis()->SetBinLabel(3, "Zorro He events"); - 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"); @@ -261,6 +288,7 @@ struct hyperRecoTask { } if (cfgSkimmedProcessing) { zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fHe"); + zorro.populateHistRegistry(qaRegistry, bc.runNumber()); } auto run3grp_timestamp = bc.timestamp(); @@ -320,17 +348,27 @@ struct hyperRecoTask { initCCDB(bc); hEvents->Fill(0.); - if (!collision.sel8() || std::abs(collision.posZ()) > 10) { + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && !disableITSROFCut) { continue; } + bool zorroSelected = false; if (cfgSkimmedProcessing) { - bool zorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); /// Just let Zorro do the accounting + // accounting done after ITS border cut, to properly correct with the MC + zorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); if (zorroSelected) { - hEvents->Fill(2.); + hEventsZorro->Fill(0.); } } + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || std::abs(collision.posZ()) > 10) { + continue; + } + + if (zorroSelected) { + hEventsZorro->Fill(1.); + } + goodCollision[collision.globalIndex()] = true; hEvents->Fill(1.); hZvtx->Fill(collision.posZ()); @@ -373,12 +411,19 @@ struct hyperRecoTask { hypCand.nSigmaHe3 = computeNSigmaHe3(heTrack); hypCand.nTPCClustersHe3 = heTrack.tpcNClsFound(); hypCand.tpcSignalHe3 = heTrack.tpcSignal(); + hypCand.nTPCpidClusHe3 = static_cast(heTrack.tpcNClsFindable()) - heTrack.tpcNClsFindableMinusPID(); hypCand.clusterSizeITSHe3 = heTrack.itsClusterSizes(); hypCand.nTPCClustersPi = piTrack.tpcNClsFound(); + hypCand.nTPCpidClusPi = static_cast(piTrack.tpcNClsFindable()) - piTrack.tpcNClsFindableMinusPID(); hypCand.tpcSignalPi = piTrack.tpcSignal(); + hypCand.tpcChi2He3 = heTrack.tpcChi2NCl(); + hypCand.itsChi2He3 = heTrack.itsChi2NCl(); + hypCand.itsChi2Pi = piTrack.itsChi2NCl(); 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()); @@ -434,7 +479,7 @@ struct hyperRecoTask { hH3LMassBefSel->Fill(massH3L); hH4LMassBefSel->Fill(massH4L); - if (!isTracked.empty() && isTracked[hypCand.v0ID]) { + if (!trackedClSize.empty() && trackedClSize[hypCand.v0ID] > 0) { hH3LMassTracked->Fill(massH3L); hH4LMassTracked->Fill(massH4L); } @@ -473,13 +518,13 @@ struct hyperRecoTask { } // if survived all selections, propagate decay daughters to PV - gpu::gpustd::array dcaInfo; + std::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 (abs(hypCand.piDCAXY) < dcaToPvPion) { + if (std::abs(hypCand.piDCAXY) < dcaToPvPion || std::abs(hypCand.he3DCAXY) < dcaToPvHe) { return; } @@ -489,6 +534,12 @@ struct hyperRecoTask { 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); @@ -500,7 +551,7 @@ struct hyperRecoTask { if (mBBparamsHe[5] < 0) { LOG(fatal) << "Bethe-Bloch parameters for He3 not set, please check your CCDB and configuration"; } - for (auto& v0 : V0s) { + for (const auto& v0 : V0s) { // if(v0.isStandardV0()) // continue; auto posTrack = tracks.rawIteratorAt(v0.posTrackId()); @@ -541,7 +592,7 @@ struct hyperRecoTask { svCreator.clearPools(); svCreator.fillBC2Coll(collisions, bcs); - for (auto& track : tracks) { + for (const auto& track : tracks) { if (std::abs(track.eta()) > etaMax) continue; @@ -551,7 +602,7 @@ struct hyperRecoTask { auto nSigmaHe = computeNSigmaHe3(track); bool isHe = nSigmaHe > -1 * nSigmaMaxHe; - int pdgHypo = isHe ? heDauPdg : 211; + int pdgHypo = isHe ? heDauPdg : PDG_t::kPiPlus; // LOG(info) << "ncls found: " << track.tpcNClsFound(); if (isHe && track.tpcNClsFound() < nTPCClusMinHe) continue; @@ -563,7 +614,7 @@ struct hyperRecoTask { auto& svPool = svCreator.getSVCandPool(collisions); LOG(debug) << "SV pool size: " << svPool.size(); - for (auto& svCand : svPool) { + for (const auto& svCand : svPool) { auto heTrack = tracks.rawIteratorAt(svCand.tr0Idx); auto piTrack = tracks.rawIteratorAt(svCand.tr1Idx); auto collIdxs = svCand.collBracket; @@ -582,23 +633,24 @@ struct hyperRecoTask { 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()) { + for (const auto& heMother : mcTrackHe.mothers_as()) { + for (const auto& piMother : mcTrackPi.mothers_as()) { if (heMother.globalIndex() != piMother.globalIndex()) continue; - if (abs(mcTrackHe.pdgCode()) != heDauPdg || abs(mcTrackPi.pdgCode()) != 211) + if (std::abs(mcTrackHe.pdgCode()) != heDauPdg || std::abs(mcTrackPi.pdgCode()) != PDG_t::kPiPlus) continue; if (std::abs(heMother.pdgCode()) != hyperPdg) continue; - 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()}; + auto primVtx = std::array{heMother.vx(), heMother.vy(), heMother.vz()}; + auto secVtx = std::array{mcTrackHe.vx(), mcTrackHe.vy(), mcTrackHe.vz()}; + hypCand.gMom = std::array{heMother.px(), heMother.py(), heMother.pz()}; + hypCand.gMomHe3 = std::array{mcTrackHe.px(), mcTrackHe.py(), mcTrackHe.pz()}; for (int i = 0; i < 3; i++) { hypCand.gDecVtx[i] = secVtx[i] - primVtx[i]; } hypCand.isSignal = true; + hypCand.isFakeHeOnITSLayer = mcLabHe.mcMask() & 0x7F; // check if any of the first 7 bits is set hypCand.pdgCode = heMother.pdgCode(); hypCand.isRecoMCCollision = recoCollisionIds[heMother.mcCollisionId()] > 0; hypCand.isSurvEvSelection = isSurvEvSelCollision[heMother.mcCollisionId()]; @@ -612,10 +664,10 @@ struct hyperRecoTask { 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, ambiTracks, bcs); } @@ -630,18 +682,21 @@ struct hyperRecoTask { selectGoodCollisions(collisions); useCustomVertexer ? fillCustomV0s(collisions, tracks, ambiTracks, bcs) : fillV0s(collisions, tracks, V0s); - for (auto& hypCand : hyperCandidates) { + for (const 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, + mRunNumber, 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]); + hypCand.nTPCpidClusHe3, hypCand.nTPCpidClusPi, + hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, hypCand.itsChi2He3, hypCand.itsChi2Pi, + hypCand.massTOFHe3, + hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } PROCESS_SWITCH(hyperRecoTask, processData, "Data analysis", true); @@ -656,25 +711,59 @@ struct hyperRecoTask { selectGoodCollisions(collisions); useCustomVertexer ? fillCustomV0s(collisions, tracks, ambiTracks, bcs) : fillV0s(collisions, tracks, V0s); - for (auto& hypCand : hyperCandidates) { + for (const 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.psiFT0C(), collision.multFT0C(), collision.qFT0C(), collision.psiTPC(), collision.multTPC(), collision.posX(), collision.posY(), collision.posZ(), - hypCand.isMatter, + mRunNumber, 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]); + hypCand.nTPCpidClusHe3, hypCand.nTPCpidClusPi, + hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, hypCand.itsChi2He3, hypCand.itsChi2Pi, + hypCand.massTOFHe3, + hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } PROCESS_SWITCH(hyperRecoTask, processDataWithFlow, "Data analysis with flow", false); + void processDataWithCollID(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) + { + goodCollision.clear(); + goodCollision.resize(collisions.size(), false); + hyperCandidates.clear(); + + selectGoodCollisions(collisions); + useCustomVertexer ? fillCustomV0s(collisions, tracks, ambiTracks, bcs) : fillV0s(collisions, tracks, V0s); + + for (const auto& hypCand : hyperCandidates) { + auto collision = collisions.rawIteratorAt(hypCand.collisionID); + float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; + outputDataTableWithCollID(hypCand.collisionID, collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.posX(), collision.posY(), collision.posZ(), + mRunNumber, 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.nTPCpidClusHe3, hypCand.nTPCpidClusPi, + hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, hypCand.itsChi2He3, hypCand.itsChi2Pi, + hypCand.massTOFHe3, + hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); + } + } + PROCESS_SWITCH(hyperRecoTask, processDataWithCollID, "Data analysis with collision ID", false); + 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(); @@ -689,28 +778,30 @@ struct hyperRecoTask { selectGoodCollisionsMC(collisions); useCustomVertexer ? fillCustomV0s(collisions, tracks, ambiTracks, bcs) : fillV0s(collisions, tracks, V0s); fillMCinfo(trackLabelsMC, particlesMC); - for (auto& hypCand : hyperCandidates) { + for (const auto& hypCand : hyperCandidates) { auto collision = collisions.rawIteratorAt(hypCand.collisionID); if (!hypCand.isSignal && mcSignalOnly) continue; 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, + mRunNumber, 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], + hypCand.nSigmaHe3, hypCand.nTPCClustersHe3, hypCand.nTPCClustersPi, hypCand.nTPCpidClusHe3, hypCand.nTPCpidClusPi, + hypCand.momHe3TPC, hypCand.momPiTPC, hypCand.tpcSignalHe3, hypCand.tpcSignalPi, hypCand.tpcChi2He3, hypCand.itsChi2He3, hypCand.itsChi2Pi, + 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); + hypCand.isReco, hypCand.isFakeHeOnITSLayer, hypCand.isSignal, hypCand.isRecoMCCollision, hypCand.isSurvEvSelection, 1, 0); } // now we fill only the signal candidates that were not reconstructed - for (auto& mcPart : particlesMC) { + for (const auto& mcPart : particlesMC) { if (std::abs(mcPart.pdgCode()) != hyperPdg) continue; @@ -719,12 +810,15 @@ struct hyperRecoTask { std::array momMother = {mcPart.px(), mcPart.py(), mcPart.pz()}; std::array momHe3; bool isHeFound = false; - for (auto& mcDaught : mcPart.daughters_as()) { + int mcProcess = {0}; + for (const auto& mcDaught : mcPart.daughters_as()) { if (std::abs(mcDaught.pdgCode()) == heDauPdg) { secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; momHe3 = {mcDaught.px(), mcDaught.py(), mcDaught.pz()}; isHeFound = true; - break; + } + if (mcDaught.pdgCode() != PDG_t::kElectron) { // we do not care about delta electrons + mcProcess = mcDaught.getProcess(); } } if (mcPart.pdgCode() > 0) { @@ -734,7 +828,6 @@ struct hyperRecoTask { } if (!isHeFound) { hDecayChannel->Fill(1.); - continue; } hDecayChannel->Fill(0.); if (mcPart.pdgCode() > 0) { @@ -768,28 +861,28 @@ struct hyperRecoTask { } outputMCTable(centFT0A, centFT0C, centFT0M, - -1, -1, -1, + mRunNumber, -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, -1, 0, 0, 0, 0, -1, -1, -1, false, 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); + hypCand.isReco, -1, hypCand.isSignal, hypCand.isRecoMCCollision, hypCand.isSurvEvSelection, isHeFound, mcProcess); } } 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::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, ambiTracks, bcs, trackLabelsMC, particlesMC); } diff --git a/PWGLF/TableProducer/Nuspex/hyperkinkRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperkinkRecoTask.cxx new file mode 100644 index 00000000000..2fc2f0167bf --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/hyperkinkRecoTask.cxx @@ -0,0 +1,1421 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file hyperkinkRecoTask.cxx +/// \brief QA and analysis task for kink decay of hypernuclei +/// \author Yuanzhe Wang + +#include "PWGLF/DataModel/LFHyperNucleiKinkTables.h" +#include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "PWGLF/Utils/pidTOFGeneric.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +o2::common::core::MetadataHelper metadataInfo; + +using CollisionsFull = soa::Join; +using MCLabeledCollisionsFull = soa::Join; +using FullTracksExtIU = soa::Join; +using MCLabeledTracksIU = soa::Join; + +enum PartType { + kHypertriton = 0, + kHyperhelium4sigma +}; + +enum DaughterType { + kDaugCharged = 0, + kDaugNeutral, + kNDaughterType +}; + +namespace +{ +constexpr std::array LayerRadii{2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; +constexpr int kITSLayers = 7; +constexpr int kITSInnerBarrelLayers = 3; +// constexpr int kITSOuterBarrelLayers = 4; + +std::shared_ptr hMothCounter; +std::shared_ptr hDaugCounter; +std::shared_ptr hDaugTPCNSigma; +std::shared_ptr hRecoMothCounter; +std::shared_ptr hRecoDaugCounter; +} // namespace + +//-------------------------------------------------------------- +struct H3LDecay { + enum Channel { + k2bodyNeutral = 0, // triton, pion0 + k2bodyCharged, + k3bodyCharged, + kNChannel + }; + + template + static Channel getDecayChannel(TMCParticle const& particle, std::vector& list) + { + if (std::abs(particle.pdgCode()) != o2::constants::physics::Pdg::kHyperTriton) { + return kNChannel; + } + + list.clear(); + list.resize(2, -1); + + bool haveHelium3 = false, haveAntiHelium3 = false, haveDeuteron = false, haveAntiDeuteron = false; + bool haveProton = false, haveAntiProton = false, havePionPlus = false, havePionMinus = false; + bool haveTriton = false, haveAntiTriton = false, havePion0 = false; + for (const auto& mcDaughter : particle.template daughters_as()) { + if (mcDaughter.pdgCode() == o2::constants::physics::Pdg::kTriton) { + haveTriton = true; + list[0] = mcDaughter.globalIndex(); + } + if (mcDaughter.pdgCode() == -o2::constants::physics::Pdg::kTriton) { + haveAntiTriton = true; + list[0] = mcDaughter.globalIndex(); + } + if (mcDaughter.pdgCode() == PDG_t::kPi0) { + havePion0 = true; + list[1] = mcDaughter.globalIndex(); + } + if (mcDaughter.pdgCode() == o2::constants::physics::Pdg::kHelium3) { + haveHelium3 = true; + } + if (mcDaughter.pdgCode() == -o2::constants::physics::Pdg::kHelium3) { + haveAntiHelium3 = true; + } + if (mcDaughter.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { + haveDeuteron = true; + } + if (mcDaughter.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) { + haveAntiDeuteron = true; + } + if (mcDaughter.pdgCode() == PDG_t::kProton) { + haveProton = true; + } + if (mcDaughter.pdgCode() == -PDG_t::kProton) { + haveAntiProton = true; + } + if (mcDaughter.pdgCode() == PDG_t::kPiPlus) { + havePionPlus = true; + } + if (mcDaughter.pdgCode() == -PDG_t::kPiPlus) { + havePionMinus = true; + } + } + + if ((haveTriton && havePion0) || (haveAntiTriton && havePion0)) { + return H3LDecay::k2bodyNeutral; + } else if ((haveHelium3 && havePionMinus) || (haveAntiHelium3 && havePionPlus)) { + return H3LDecay::k2bodyCharged; + } else if ((haveDeuteron && haveProton && havePionMinus) || (haveAntiDeuteron && haveAntiProton && havePionPlus)) { + return H3LDecay::k3bodyCharged; + } else { + return kNChannel; + } + } +}; + +//-------------------------------------------------------------- +// Check the decay channel of hyperhelium4sigma +struct He4SDecay { + enum Channel { + k2body = 0, // helium4, pion0 + k3body_p, // triton, proton, pion0 + k3body_n, // triton, neutron, pion+ + kNChannel + }; + + template + static Channel getDecayChannel(TMCParticle const& particle, std::vector& list) + { + if (std::abs(particle.pdgCode()) != o2::constants::physics::Pdg::kHyperHelium4Sigma) { + return kNChannel; + } + + list.clear(); + list.resize(2, -1); + + bool haveAlpha = false, haveTriton = false, haveProton = false, haveNeuteron = false; + bool haveAntiAlpha = false, haveAntiTriton = false, haveAntiProton = false, haveAntiNeuteron = false; + bool havePionPlus = false, havePionMinus = false, havePion0 = false; + for (const auto& mcDaughter : particle.template daughters_as()) { + if (mcDaughter.pdgCode() == o2::constants::physics::Pdg::kAlpha) { + haveAlpha = true; + list[0] = mcDaughter.globalIndex(); + } + if (mcDaughter.pdgCode() == -o2::constants::physics::Pdg::kAlpha) { + haveAntiAlpha = true; + list[0] = mcDaughter.globalIndex(); + } + if (mcDaughter.pdgCode() == o2::constants::physics::Pdg::kTriton) { + haveTriton = true; + } + if (mcDaughter.pdgCode() == -o2::constants::physics::Pdg::kTriton) { + haveAntiTriton = true; + } + if (mcDaughter.pdgCode() == PDG_t::kProton) { + haveProton = true; + } + if (mcDaughter.pdgCode() == -PDG_t::kProton) { + haveAntiProton = true; + } + if (mcDaughter.pdgCode() == PDG_t::kNeutron) { + haveNeuteron = true; + } + if (mcDaughter.pdgCode() == -PDG_t::kNeutron) { + haveAntiNeuteron = true; + } + if (mcDaughter.pdgCode() == PDG_t::kPiPlus) { + havePionPlus = true; + } + if (mcDaughter.pdgCode() == -PDG_t::kPiPlus) { + havePionMinus = true; + } + if (mcDaughter.pdgCode() == PDG_t::kPi0) { + havePion0 = true; + list[1] = mcDaughter.globalIndex(); + } + } + + if ((haveAlpha && havePion0) || (haveAntiAlpha && havePion0)) { + return He4SDecay::k2body; + } else if ((haveTriton && haveProton && havePion0) || (haveAntiTriton && haveAntiProton && havePion0)) { + return He4SDecay::k3body_p; + } else if ((haveTriton && haveNeuteron && havePionPlus) || (haveAntiTriton && haveAntiNeuteron && havePionMinus)) { + return He4SDecay::k3body_n; + } + + return kNChannel; + } +}; + +//-------------------------------------------------------------- +// Extract track parameters from a mcparticle, use global coordinates as the local one +template +o2::track::TrackParametrization getTrackParFromMC(const T& mcparticle, int charge = 1) +{ + int sign = mcparticle.pdgCode() > 0 ? 1 : -1; // ok for hypernuclei + TrackPrecision snp = mcparticle.py() / (mcparticle.pt() + 1.e-10f); + TrackPrecision tgl = mcparticle.pz() / (mcparticle.pt() + 1.e-10f); + std::array arraypar = {mcparticle.vy(), mcparticle.vz(), snp, + tgl, charge * sign / (mcparticle.pt() + 1.e-10f)}; + return o2::track::TrackParametrization(mcparticle.vx(), 0, std::move(arraypar)); +} + +//-------------------------------------------------------------- +// construct index array from mcParticle to track +template +void setTrackIDForMC(std::vector& mcPartIndices, 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(); + } + } + } + } +} + +//-------------------------------------------------------------- +// get ITSNSigma for daughter track +template +float getITSNSigma(const TTrack& track, o2::aod::ITSResponse& itsResponse, o2::track::PID partType) +{ + float nSigma = -999.f; + switch (partType) { + case o2::track::PID::Alpha: + nSigma = itsResponse.nSigmaITS(track); + break; + case o2::track::PID::Triton: + nSigma = itsResponse.nSigmaITS(track); + break; + default: + break; + } + return nSigma; +} + +//-------------------------------------------------------------- +// get default TOFNSigma for daughter track +template +float getDefaultTOFNSigma(const TTrack& track, o2::track::PID partType) +{ + float nSigma = -999.f; + switch (partType) { + case o2::track::PID::Alpha: + nSigma = track.tofNSigmaAl(); + break; + case o2::track::PID::Triton: + nSigma = track.tofNSigmaTr(); + break; + default: + break; + } + return nSigma; +} + +//-------------------------------------------------------------- +// get TPCNSigma for daughter track +template +float getTPCNSigma(const TTrack& track, o2::track::PID partType) +{ + float nSigma = -999.f; + switch (partType) { + case o2::track::PID::Alpha: + nSigma = track.tpcNSigmaAl(); + break; + case o2::track::PID::Triton: + nSigma = track.tpcNSigmaTr(); + break; + default: + break; + } + return nSigma; +} + +//-------------------------------------------------------------- +struct HypKinkCandidate { + + bool isMatter = false; + + std::array posPV = {0.0f, 0.0f, 0.0f}; + std::array posSV = {0.0f, 0.0f, 0.0f}; + std::array lastPosMoth = {0.0f, 0.0f, 0.0f}; // last position of mother track at the radii of ITS layer which has the outermost update + std::array momMothSV = {0.0f, 0.0f, 0.0f}; + std::array momDaugSV = {0.0f, 0.0f, 0.0f}; + + float dcaXYMothPv = -999.f; + float dcaXYDaugPv = -999.f; + float dcaKinkTopo = -999.f; + + float chi2ITSMoth = 0.0f; + uint32_t itsClusterSizeMoth = 0u; + uint32_t itsClusterSizeDaug = 0u; + float tpcMomDaug = -999.f; + float tpcSignalDaug = -999.f; + int16_t tpcNClsPIDDaug = 0u; + float nSigmaTPCDaug = -999.f; + float nSigmaITSDaug = -999.f; + float nSigmaTOFDaug = -999.f; // recalculated TOF NSigma + + // mc information + bool isSignal = false; + bool isSignalReco = false; + bool isCollReco = false; + bool isSurvEvSelection = false; + + std::array truePosSV = {0.0f, 0.0f, 0.0f}; + std::array trueMomMothPV = {0.0f, 0.0f, 0.0f}; // generated mother momentum at primary vertex + std::array trueMomMothSV = {0.0f, 0.0f, 0.0f}; // true mother momentum at decay vertex + std::array trueMomDaugSV = {0.0f, 0.0f, 0.0f}; // true daughter momentum at decay vertex + + bool isMothReco = false; + std::array momMothPV = {0.0f, 0.0f, 0.0f}; + std::array updateMomMothPV = {0.0f, 0.0f, 0.0f}; // mother momentum at primary vertex after update using PV +}; + +//-------------------------------------------------------------- +// analysis task for 2-body kink decay +struct HyperkinkRecoTask { + + Produces outputDataTable; + Produces outputMCTable; + + Service ccdb; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + + // Histograms are defined with HistogramRegistry + HistogramRegistry registry{"registry", {}}; + + Configurable hypoMoth{"hypoMoth", kHypertriton, "Mother particle hypothesis"}; + // Configurable for event selection + Configurable doEventCut{"doEventCut", true, "Apply event selection"}; + Configurable maxZVertex{"maxZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cutTPCNSigmaDaug{"cutTPCNSigmaDaug", 5, "TPC NSigma cut for daughter tracks"}; + Configurable cutTOFNSigmaDaug{"cutTOFNSigmaDaug", 1000, "TOF NSigma cut for daughter tracks"}; + Configurable askTOFForDaug{"askTOFForDaug", false, "If true, ask for TOF signal"}; + Configurable minDaugPt{"minDaugPt", 1.0f, "Minimum pT of daughter track (GeV/c)"}; + Configurable minDCADaugToPV{"minDCADaugToPV", 0.f, "Minimum DCA of daughter track to primary vertex (cm)"}; + Configurable maxDCADaugToPV{"maxDCADaugToPV", 999.0f, "Maximum DCA of daughter track to primary vertex (cm)"}; + Configurable maxQtAP{"maxQtAP", 1.f, "Maximum qT of Armenteros-Podolanski Plot"}; + Configurable maxDCAKinkTopo{"maxDCAKinkTopo", 1.f, "Maximum DCA of kink topology (cm)"}; + + // 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 grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + + int mRunNumber; + float mBz; + o2::base::MatLayerCylSet* lut = nullptr; + + o2::aod::ITSResponse itsResponse; + + float massMoth = 999.f; + float massChargedDaug = 999.f; + float massNeutralDaug = 999.f; + int pdgMoth = 0; + std::array pdgDaug = {o2::constants::physics::Pdg::kTriton, PDG_t::kPi0}; // pdgcode of charged (0) and neutral (1) daughter particles + o2::track::PID pidTypeDaug = o2::track::PID::Triton; + + // secondary TOF PID + o2::aod::pidtofgeneric::TofPidNewCollision secondaryTOFPID; // to be updated in Init based on the hypothesis + o2::aod::pidtofgeneric::TofPidNewCollision secondaryTOFPIDLabeled; // to be updated in Init based on the hypothesis + // TOF response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + o2::aod::pidtofgeneric::TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + void init(InitContext& initContext) + { + if (hypoMoth == kHypertriton) { + massMoth = o2::constants::physics::MassHyperTriton; + massChargedDaug = o2::constants::physics::MassTriton; + massNeutralDaug = o2::constants::physics::MassPi0; + pdgMoth = o2::constants::physics::Pdg::kHyperTriton; + pdgDaug[kDaugCharged] = o2::constants::physics::Pdg::kTriton; + pdgDaug[kDaugNeutral] = PDG_t::kPi0; + pidTypeDaug = o2::track::PID::Triton; + } else if (hypoMoth == kHyperhelium4sigma) { + massMoth = o2::constants::physics::MassHyperHelium4Sigma; + massChargedDaug = o2::constants::physics::MassAlpha; + massNeutralDaug = o2::constants::physics::MassPi0; + pdgMoth = o2::constants::physics::Pdg::kHyperHelium4Sigma; + pdgDaug[kDaugCharged] = o2::constants::physics::Pdg::kAlpha; + pdgDaug[kDaugNeutral] = PDG_t::kPi0; + pidTypeDaug = o2::track::PID::Alpha; + } else { + LOG(fatal) << "Unknown mother particle hypothesis"; + } + + // Axes + const AxisSpec vertexZAxis{100, -15., 15., "vtx_{Z} [cm]"}; + const AxisSpec ptAxis{50, -10, 10, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec nSigmaAxis{120, -6.f, 6.f, "n#sigma"}; + AxisSpec massAxis(100, 2.94, 3.2, "m (GeV/#it{c}^{2})"); + if (hypoMoth == kHyperhelium4sigma) { + massAxis = AxisSpec{100, 3.85, 4.25, "m (GeV/#it{c}^{2})"}; + } + const AxisSpec deltaPtAxis{200, -10.f, 10.f, "#Delta #it{p}_{T} (GeV/#it{c})"}; + const AxisSpec deltaPzAxis{200, -10.f, 10.f, "#Delta #it{p}_{z} (GeV/#it{c})"}; + const AxisSpec recRadiusAxis{40, 0.f, 40.f, "Rec SV R (cm)"}; + + registry.add("hEventCounter", "hEventCounter", HistType::kTH1F, {{2, 0, 2}}); + registry.add("hVertexZCollision", "hVertexZCollision", HistType::kTH1F, {vertexZAxis}); + registry.add("hCandidateCounter", "hCandidateCounter", HistType::kTH1F, {{8, 0, 8}}); + + if (doprocessMC == true) { + itsResponse.setMCDefaultParameters(); + + registry.add("hTrueCandidateCounter", "hTrueCandidateCounter", HistType::kTH1F, {{8, 0, 8}}); + registry.add("hDeltaSVx", ";#Delta x (cm);", HistType::kTH1F, {{200, -2, 2}}); + registry.add("hDeltaSVy", ";#Delta y (cm);", HistType::kTH1F, {{200, -2, 2}}); + registry.add("hDeltaSVz", ";#Delta z (cm);", HistType::kTH1F, {{200, -2, 2}}); + registry.add("hDeltaSVRVsTrueSVR", ";True SVR (cm);#Delta R (cm)", HistType::kTH2F, {{200, 0, 40}, {200, -2, 2}}); + registry.add("h2RecSVRVsTrueSVR", ";Rec SV R (cm);True SV R (cm);", HistType::kTH2F, {recRadiusAxis, {40, 0, 40}}); + registry.add("h2TrueMotherDeltaPtVsRecSVR", ";Rec SV R (cm);#Delta #it{p}_{T} (GeV/#it{c});", HistType::kTH2F, {recRadiusAxis, deltaPtAxis}); + registry.add("h2TrueMotherDeltaEtaVsRecSVR", ";Rec SV R (cm);#Delta #eta;", HistType::kTH2F, {recRadiusAxis, {200, -0.1, 0.1}}); + registry.add("hDeltaDauPx", ";#Delta p_{x} (GeV/#it{c}); ", HistType::kTH1F, {{200, -2, 2}}); + registry.add("hDeltaDauPy", ";#Delta p_{y} (GeV/#it{c}); ", HistType::kTH1F, {{200, -2, 2}}); + registry.add("hDeltaDauPz", ";#Delta p_{z} (GeV/#it{c}); ", HistType::kTH1F, {{200, -2, 2}}); + registry.add("h2TrueSignalMassPt", "h2TrueSignalMassPt", HistType::kTH2F, {{ptAxis, massAxis}}); + registry.add("h2TrueDaugTPCNSigmaPt", "h2TrueDaugTPCNSigmaPt", HistType::kTH2F, {{ptAxis, nSigmaAxis}}); + + registry.add("hDCAXYMothToRecSV", "hDCAXYMothToRecSV", HistType::kTH1F, {{200, -10, 10}}); + registry.add("hDCAZMothToRecSV", "hDCAZMothToRecSV", HistType::kTH1F, {{200, -10, 10}}); + + registry.add("hDaugOldTOFNSigma_CorrectCol", "hDaugOldTOFNSigma_CorrectCol", HistType::kTH1F, {{600, -300, 300}}); + registry.add("hDaugOldTOFNSigma_WrongCol", "hDaugOldTOFNSigma_WrongCol", HistType::kTH1F, {{600, -300, 300}}); + registry.add("hDaugNewTOFNSigma_CorrectCol", "hDaugNewTOFNSigma_CorrectCol", HistType::kTH1F, {{600, -300, 300}}); + registry.add("hDaugNewTOFNSigma_WrongCol", "hDaugNewTOFNSigma_WrongCol", HistType::kTH1F, {{600, -300, 300}}); + + registry.add("hTrueSignalInvMassNegNeutDaugE", "hTrueSignalInvMassNegNeutDaugE", HistType::kTH1F, {{1000, 2.8, 4, "m (GeV/#it{c}^{2})"}}); + } + + registry.add("h2MothMassPt", "h2MothMassPt", HistType::kTH2F, {{ptAxis, massAxis}}); + registry.add("h2DaugTPCNSigmaPt", "h2DaugTPCNSigmaPt", HistType::kTH2F, {{ptAxis, nSigmaAxis}}); + + registry.add("hInvMassNegNeutDaugE", "hInvMassNegNeutDaugE", HistType::kTH1F, {{1000, 2.8, 4, "m (GeV/#it{c}^{2})"}}); + + ccdb->setURL(ccdbPath); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + mTOFCalibConfig.metadataInfo = metadataInfo; + mTOFCalibConfig.inheritFromBaseTask(initContext); + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); + secondaryTOFPID.SetPidType(pidTypeDaug); + secondaryTOFPIDLabeled.SetPidType(pidTypeDaug); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + ccdb->clearCache(grpmagPath.value.data()); + LOG(info) << "Initializing CCDB for run " << mRunNumber; + o2::parameters::GRPMagField* grpmag = ccdb->getForRun(grpmagPath, mRunNumber); + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = grpmag->getNominalL3Field(); + + if (!lut) { + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + } + o2::base::Propagator::Instance()->setMatLUT(lut); + LOG(info) << "Task initialized for run " << mRunNumber << " with magnetic field " << mBz << " kZG"; + + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bc); + } + + // ______________________________________________________________ + // get recalulate TOFNSigma for daughter track + template + double getTOFNSigma(o2::pid::tof::TOFResoParamsV3 const& parameters, TTrack const& track, TCollision const& collision, TCollision const& originalcol) + { + // TOF PID of deuteron + if (track.has_collision() && track.hasTOF()) { + if constexpr (isMC) { + return secondaryTOFPIDLabeled.GetTOFNSigma(parameters, track, originalcol, collision); + } else { + return secondaryTOFPID.GetTOFNSigma(parameters, track, originalcol, collision); + } + } + return -999; + } + + template + void fillCandidate(HypKinkCandidate& hypkinkCand, TCollision const& collision, TKindCandidate const& kinkCand, TTrack const& trackMoth, TTrack const& trackDaug) + { + hypkinkCand.isMatter = kinkCand.mothSign() > 0; + hypkinkCand.posPV[0] = collision.posX(); + hypkinkCand.posPV[1] = collision.posY(); + hypkinkCand.posPV[2] = collision.posZ(); + hypkinkCand.posSV[0] = kinkCand.xDecVtx() + collision.posX(); + hypkinkCand.posSV[1] = kinkCand.yDecVtx() + collision.posY(); + hypkinkCand.posSV[2] = kinkCand.zDecVtx() + collision.posZ(); + + hypkinkCand.momMothSV[0] = kinkCand.pxMoth(); + hypkinkCand.momMothSV[1] = kinkCand.pyMoth(); + hypkinkCand.momMothSV[2] = kinkCand.pzMoth(); + hypkinkCand.momDaugSV[0] = kinkCand.pxDaug(); + hypkinkCand.momDaugSV[1] = kinkCand.pyDaug(); + hypkinkCand.momDaugSV[2] = kinkCand.pzDaug(); + + hypkinkCand.dcaXYMothPv = kinkCand.dcaMothPv(); + hypkinkCand.dcaXYDaugPv = kinkCand.dcaDaugPv(); + hypkinkCand.dcaKinkTopo = kinkCand.dcaKinkTopo(); + + fillCandidateRecoMoth(hypkinkCand, collision, trackMoth); + + hypkinkCand.itsClusterSizeDaug = trackDaug.itsClusterSizes(); + hypkinkCand.tpcMomDaug = trackDaug.tpcInnerParam() * trackDaug.sign(); + hypkinkCand.tpcSignalDaug = trackDaug.tpcSignal(); + hypkinkCand.tpcNClsPIDDaug = trackDaug.tpcNClsPID(); + hypkinkCand.nSigmaTPCDaug = getTPCNSigma(trackDaug, pidTypeDaug); + hypkinkCand.nSigmaITSDaug = getITSNSigma(trackDaug, itsResponse, pidTypeDaug); + + int lastLayerMoth = 0; + for (int i = 6; i >= 0; i--) { + if (trackMoth.itsClusterMap() & (1 << i)) { + lastLayerMoth = i; + break; + } + } + auto trackparMother = getTrackParCov(trackMoth); + o2::base::Propagator::Instance()->PropagateToXBxByBz(trackparMother, LayerRadii[lastLayerMoth]); + std::array posLastHit{-999.f}; + trackparMother.getXYZGlo(posLastHit); + hypkinkCand.lastPosMoth[0] = posLastHit[0]; + hypkinkCand.lastPosMoth[1] = posLastHit[1]; + hypkinkCand.lastPosMoth[2] = posLastHit[2]; + } + + template + void fillCandidateRecoMoth(HypKinkCandidate& hypkinkCand, TCollision const& collision, TTrack const& trackMoth) + { + hypkinkCand.isMothReco = true; + hypkinkCand.chi2ITSMoth = trackMoth.itsChi2NCl(); + hypkinkCand.itsClusterSizeMoth = trackMoth.itsClusterSizes(); + + auto motherTrackPar = getTrackParCov(trackMoth); + o2::dataformats::VertexBase primaryVtx = {{collision.posX(), collision.posY(), collision.posZ()}, {collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}}; + std::array pMotherPv = {-999.f}; + std::array updatePMotherPv = {-999.f}; + if (o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVtx, motherTrackPar, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT)) { + motherTrackPar.getPxPyPzGlo(pMotherPv); + if (motherTrackPar.update(primaryVtx)) { + motherTrackPar.getPxPyPzGlo(updatePMotherPv); + } + } + + hypkinkCand.momMothPV[0] = pMotherPv[0]; + hypkinkCand.momMothPV[1] = pMotherPv[1]; + hypkinkCand.momMothPV[2] = pMotherPv[2]; + hypkinkCand.updateMomMothPV[0] = updatePMotherPv[0]; + hypkinkCand.updateMomMothPV[1] = updatePMotherPv[1]; + hypkinkCand.updateMomMothPV[2] = updatePMotherPv[2]; + } + + template + void fillCandidateMCInfo(HypKinkCandidate& hypkinkCand, TMCParticle const& mcMothTrack, TMCParticle const& mcDaugTrack, TMCParticle const& mcNeutDaugTrack) + { + hypkinkCand.truePosSV[0] = mcDaugTrack.vx(); + hypkinkCand.truePosSV[1] = mcDaugTrack.vy(); + hypkinkCand.truePosSV[2] = mcDaugTrack.vz(); + hypkinkCand.trueMomMothPV[0] = mcMothTrack.px(); + hypkinkCand.trueMomMothPV[1] = mcMothTrack.py(); + hypkinkCand.trueMomMothPV[2] = mcMothTrack.pz(); + hypkinkCand.trueMomMothSV[0] = mcDaugTrack.px() + mcNeutDaugTrack.px(); + hypkinkCand.trueMomMothSV[1] = mcDaugTrack.py() + mcNeutDaugTrack.py(); + hypkinkCand.trueMomMothSV[2] = mcDaugTrack.pz() + mcNeutDaugTrack.pz(); + hypkinkCand.trueMomDaugSV[0] = mcDaugTrack.px(); + hypkinkCand.trueMomDaugSV[1] = mcDaugTrack.py(); + hypkinkCand.trueMomDaugSV[2] = mcDaugTrack.pz(); + } + + void processData(CollisionsFull const& collisions, aod::KinkCands const& KinkCands, FullTracksExtIU const&, aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + registry.fill(HIST("hEventCounter"), 0); + if (doEventCut && (std::abs(collision.posZ()) > maxZVertex || !collision.sel8())) { + continue; + } + registry.fill(HIST("hEventCounter"), 1); + registry.fill(HIST("hVertexZCollision"), collision.posZ()); + } + + for (const auto& kinkCand : KinkCands) { + registry.fill(HIST("hCandidateCounter"), 0); + auto collision = kinkCand.collision_as(); + if (doEventCut && (std::abs(collision.posZ()) > maxZVertex || !collision.sel8())) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 1); + + auto daugTrack = kinkCand.trackDaug_as(); + float tpcNSigmaDaug = getTPCNSigma(daugTrack, pidTypeDaug); + if (std::abs(tpcNSigmaDaug) > cutTPCNSigmaDaug) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 2); + + auto bc = collision.bc_as(); + initCCDB(bc); + auto motherTrack = kinkCand.trackMoth_as(); + float nSigmaTOF = -999.f; + if (daugTrack.hasTOF() && daugTrack.has_collision()) { + auto originalDaugCol = daugTrack.collision_as(); + nSigmaTOF = getTOFNSigma(mRespParamsV3, daugTrack, collision, originalDaugCol); + } + if ((daugTrack.hasTOF() || askTOFForDaug) && std::abs(nSigmaTOF) > cutTOFNSigmaDaug) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 3); + + if (kinkCand.ptDaug() < minDaugPt) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 4); + + if (std::abs(kinkCand.dcaDaugPv()) < minDCADaugToPV || std::abs(kinkCand.dcaDaugPv()) > maxDCADaugToPV) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 5); + + if (kinkCand.dcaKinkTopo() > maxDCAKinkTopo) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 6); + + float p2Moth = kinkCand.pxMoth() * kinkCand.pxMoth() + kinkCand.pyMoth() * kinkCand.pyMoth() + kinkCand.pzMoth() * kinkCand.pzMoth(); + float p2Daug = kinkCand.pxDaug() * kinkCand.pxDaug() + kinkCand.pyDaug() * kinkCand.pyDaug() + kinkCand.pzDaug() * kinkCand.pzDaug(); + float sqKink = kinkCand.pxMoth() * kinkCand.pxDaug() + kinkCand.pyMoth() * kinkCand.pyDaug() + kinkCand.pzMoth() * kinkCand.pzDaug(); + float qt = std::sqrt(p2Daug - sqKink * sqKink / p2Moth); + if (qt > maxQtAP) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 7); + + float invMass = RecoDecay::m(std::array{std::array{kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug()}, std::array{kinkCand.pxDaugNeut(), kinkCand.pyDaugNeut(), kinkCand.pzDaugNeut()}}, std::array{massChargedDaug, massNeutralDaug}); + registry.fill(HIST("h2MothMassPt"), kinkCand.mothSign() * kinkCand.ptMoth(), invMass); + registry.fill(HIST("h2DaugTPCNSigmaPt"), kinkCand.mothSign() * kinkCand.ptDaug(), tpcNSigmaDaug); + + HypKinkCandidate hypkinkCand; + fillCandidate(hypkinkCand, collision, kinkCand, motherTrack, daugTrack); + hypkinkCand.nSigmaTOFDaug = nSigmaTOF; + + outputDataTable( + mBz > 0 ? 1 : -1, + hypkinkCand.posPV[0], hypkinkCand.posPV[1], hypkinkCand.posPV[2], + hypkinkCand.posSV[0], hypkinkCand.posSV[1], hypkinkCand.posSV[2], + hypkinkCand.isMatter, + hypkinkCand.lastPosMoth[0], hypkinkCand.lastPosMoth[1], hypkinkCand.lastPosMoth[2], + hypkinkCand.momMothSV[0], hypkinkCand.momMothSV[1], hypkinkCand.momMothSV[2], + hypkinkCand.momDaugSV[0], hypkinkCand.momDaugSV[1], hypkinkCand.momDaugSV[2], + hypkinkCand.dcaXYMothPv, hypkinkCand.dcaXYDaugPv, hypkinkCand.dcaKinkTopo, + hypkinkCand.chi2ITSMoth, hypkinkCand.itsClusterSizeMoth, hypkinkCand.itsClusterSizeDaug, + hypkinkCand.tpcMomDaug, hypkinkCand.tpcSignalDaug, hypkinkCand.tpcNClsPIDDaug, + hypkinkCand.nSigmaTPCDaug, hypkinkCand.nSigmaITSDaug, hypkinkCand.nSigmaTOFDaug, + hypkinkCand.momMothPV[0], hypkinkCand.momMothPV[1], hypkinkCand.momMothPV[2], + hypkinkCand.updateMomMothPV[0], hypkinkCand.updateMomMothPV[1], hypkinkCand.updateMomMothPV[2]); + } + } + PROCESS_SWITCH(HyperkinkRecoTask, processData, "process data", true); + + void processMC(MCLabeledCollisionsFull const& collisions, aod::KinkCands const& KinkCands, MCLabeledTracksIU const& tracks, aod::McParticles const& particlesMC, aod::McCollisions const& mcCollisions, aod::BCsWithTimestamps const&) + { + std::vector mcPartIndices; + setTrackIDForMC(mcPartIndices, particlesMC, tracks); + std::vector signalIndicesPool; + std::vector isReconstructedMCCollisions(mcCollisions.size(), false); + std::vector isSelectedMCCollisions(mcCollisions.size(), false); + std::vector isGoodCollisions(collisions.size(), false); + std::vector dauIDList(2, -1); + + for (const auto& collision : collisions) { + if (collision.has_mcCollision()) { + isReconstructedMCCollisions[collision.mcCollisionId()] = true; + } + registry.fill(HIST("hEventCounter"), 0); + if (doEventCut && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || std::abs(collision.posZ()) > maxZVertex)) { + continue; + } + registry.fill(HIST("hEventCounter"), 1); + registry.fill(HIST("hVertexZCollision"), collision.posZ()); + if (collision.has_mcCollision()) { + isSelectedMCCollisions[collision.mcCollisionId()] = true; + } + isGoodCollisions[collision.globalIndex()] = true; + } + + for (const auto& kinkCand : KinkCands) { + auto motherTrack = kinkCand.trackMoth_as(); + auto daugTrack = kinkCand.trackDaug_as(); + + bool isKinkSignal = false; + if (motherTrack.has_mcParticle() && daugTrack.has_mcParticle()) { + auto mcMothTrack = motherTrack.mcParticle_as(); + auto mcDaugTrack = daugTrack.mcParticle_as(); + if (hypoMoth == kHypertriton) { + auto dChannel = H3LDecay::getDecayChannel(mcMothTrack, dauIDList); + if (dChannel == H3LDecay::k2bodyNeutral && dauIDList[0] == mcDaugTrack.globalIndex()) { + isKinkSignal = true; + } + } else if (hypoMoth == kHyperhelium4sigma) { + auto dChannel = He4SDecay::getDecayChannel(mcMothTrack, dauIDList); + if (dChannel == He4SDecay::k2body && dauIDList[0] == mcDaugTrack.globalIndex()) { + isKinkSignal = true; + } + } + } + + registry.fill(HIST("hCandidateCounter"), 0); + if (isKinkSignal) { + registry.fill(HIST("hTrueCandidateCounter"), 0); + } + auto collision = kinkCand.collision_as(); + if (!isGoodCollisions[collision.globalIndex()]) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 1); + if (isKinkSignal) { + registry.fill(HIST("hTrueCandidateCounter"), 1); + } + + float tpcNSigmaDaug = getTPCNSigma(daugTrack, pidTypeDaug); + if (std::abs(tpcNSigmaDaug) > cutTPCNSigmaDaug) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 2); + if (isKinkSignal) { + registry.fill(HIST("hTrueCandidateCounter"), 2); + } + + auto bc = collision.bc_as(); + initCCDB(bc); + float nSigmaTOF = -999.f; + if (daugTrack.hasTOF() && daugTrack.has_collision()) { + auto originalDaugCol = daugTrack.collision_as(); + float defaultNSigmaTOF = getDefaultTOFNSigma(daugTrack, pidTypeDaug); + nSigmaTOF = getTOFNSigma(mRespParamsV3, daugTrack, collision, originalDaugCol); + if (originalDaugCol.globalIndex() == collision.globalIndex()) { + registry.fill(HIST("hDaugOldTOFNSigma_CorrectCol"), defaultNSigmaTOF); + registry.fill(HIST("hDaugNewTOFNSigma_CorrectCol"), nSigmaTOF); + } else { + registry.fill(HIST("hDaugOldTOFNSigma_WrongCol"), defaultNSigmaTOF); + registry.fill(HIST("hDaugNewTOFNSigma_WrongCol"), nSigmaTOF); + } + } + if ((daugTrack.hasTOF() || askTOFForDaug) && std::abs(nSigmaTOF) > cutTOFNSigmaDaug) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 3); + if (isKinkSignal) { + registry.fill(HIST("hTrueCandidateCounter"), 3); + } + + if (kinkCand.ptDaug() < minDaugPt) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 4); + if (isKinkSignal) { + registry.fill(HIST("hTrueCandidateCounter"), 4); + } + + if (std::abs(kinkCand.dcaDaugPv()) < minDCADaugToPV || std::abs(kinkCand.dcaDaugPv()) > maxDCADaugToPV) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 5); + if (isKinkSignal) { + registry.fill(HIST("hTrueCandidateCounter"), 5); + } + + if (kinkCand.dcaKinkTopo() > maxDCAKinkTopo) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 6); + if (isKinkSignal) { + registry.fill(HIST("hTrueCandidateCounter"), 6); + } + + float p2Moth = kinkCand.pxMoth() * kinkCand.pxMoth() + kinkCand.pyMoth() * kinkCand.pyMoth() + kinkCand.pzMoth() * kinkCand.pzMoth(); + float p2Daug = kinkCand.pxDaug() * kinkCand.pxDaug() + kinkCand.pyDaug() * kinkCand.pyDaug() + kinkCand.pzDaug() * kinkCand.pzDaug(); + float sqKink = kinkCand.pxMoth() * kinkCand.pxDaug() + kinkCand.pyMoth() * kinkCand.pyDaug() + kinkCand.pzMoth() * kinkCand.pzDaug(); + float qt = std::sqrt(p2Daug - sqKink * sqKink / p2Moth); + if (qt > maxQtAP) { + continue; + } + registry.fill(HIST("hCandidateCounter"), 7); + if (isKinkSignal) { + registry.fill(HIST("hTrueCandidateCounter"), 7); + } + + float invMass = RecoDecay::m(std::array{std::array{kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug()}, std::array{kinkCand.pxDaugNeut(), kinkCand.pyDaugNeut(), kinkCand.pzDaugNeut()}}, std::array{massChargedDaug, massNeutralDaug}); + registry.fill(HIST("h2MothMassPt"), kinkCand.mothSign() * kinkCand.ptMoth(), invMass); + registry.fill(HIST("h2DaugTPCNSigmaPt"), kinkCand.mothSign() * kinkCand.ptDaug(), tpcNSigmaDaug); + + // qa for energy of charged daughter greater than the mother track with mass hypothesis + float pCharDaug = std::hypot(kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug()); + float pMoth = std::hypot(kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth()); + float chargedDauE = std::hypot(pCharDaug, massChargedDaug); + float motherE = std::hypot(pMoth, massMoth); + if (chargedDauE < motherE) { + registry.fill(HIST("hInvMassNegNeutDaugE"), invMass); + if (isKinkSignal) { + registry.fill(HIST("hTrueSignalInvMassNegNeutDaugE"), invMass); + } + } + + HypKinkCandidate hypkinkCand; + fillCandidate(hypkinkCand, collision, kinkCand, motherTrack, daugTrack); + hypkinkCand.nSigmaTOFDaug = nSigmaTOF; + + std::array posDecVtx = {kinkCand.xDecVtx() + collision.posX(), kinkCand.yDecVtx() + collision.posY(), kinkCand.zDecVtx() + collision.posZ()}; + float recSVR = std::hypot(posDecVtx[0], posDecVtx[1]); + + // QA, store mcInfo for true signals + if (isKinkSignal) { + auto mcMothTrack = motherTrack.mcParticle_as(); + auto mcDaugTrack = daugTrack.mcParticle_as(); + auto mcNeutTrack = particlesMC.rawIteratorAt(dauIDList[1]); + float trueSVR = std::hypot(mcDaugTrack.vx(), mcDaugTrack.vy()); + registry.fill(HIST("hDeltaSVx"), posDecVtx[0] - mcDaugTrack.vx()); + registry.fill(HIST("hDeltaSVy"), posDecVtx[1] - mcDaugTrack.vy()); + registry.fill(HIST("hDeltaSVz"), posDecVtx[2] - mcDaugTrack.vz()); + registry.fill(HIST("hDeltaSVRVsTrueSVR"), trueSVR, recSVR - trueSVR); + registry.fill(HIST("h2RecSVRVsTrueSVR"), recSVR, trueSVR); + registry.fill(HIST("h2TrueMotherDeltaPtVsRecSVR"), recSVR, mcMothTrack.pt() - kinkCand.ptMoth()); + registry.fill(HIST("h2TrueMotherDeltaEtaVsRecSVR"), recSVR, mcMothTrack.eta() - motherTrack.eta()); + registry.fill(HIST("hDeltaDauPx"), kinkCand.pxDaug() - mcDaugTrack.px()); + registry.fill(HIST("hDeltaDauPy"), kinkCand.pyDaug() - mcDaugTrack.py()); + registry.fill(HIST("hDeltaDauPz"), kinkCand.pzDaug() - mcDaugTrack.pz()); + registry.fill(HIST("h2TrueSignalMassPt"), kinkCand.mothSign() * kinkCand.ptMoth(), invMass); + registry.fill(HIST("h2TrueDaugTPCNSigmaPt"), kinkCand.mothSign() * kinkCand.ptDaug(), tpcNSigmaDaug); + + hypkinkCand.isSignal = true; + hypkinkCand.isSignalReco = true; + fillCandidateMCInfo(hypkinkCand, mcMothTrack, mcDaugTrack, mcNeutTrack); + signalIndicesPool.push_back(mcMothTrack.globalIndex()); + + std::array dcaInfo; + auto mcMothTrackPar = getTrackParFromMC(mcMothTrack, 2); + o2::base::Propagator::Instance()->propagateToDCABxByBz({posDecVtx[0], posDecVtx[1], posDecVtx[2]}, mcMothTrackPar, 2.f, matCorr, &dcaInfo); + registry.fill(HIST("hDCAXYMothToRecSV"), dcaInfo[0]); + registry.fill(HIST("hDCAZMothToRecSV"), dcaInfo[1]); + } + + hypkinkCand.isCollReco = true; + hypkinkCand.isSurvEvSelection = true; + + outputMCTable( + mBz > 0 ? 1 : -1, + hypkinkCand.posPV[0], hypkinkCand.posPV[1], hypkinkCand.posPV[2], + hypkinkCand.posSV[0], hypkinkCand.posSV[1], hypkinkCand.posSV[2], + hypkinkCand.isMatter, + hypkinkCand.lastPosMoth[0], hypkinkCand.lastPosMoth[1], hypkinkCand.lastPosMoth[2], + hypkinkCand.momMothSV[0], hypkinkCand.momMothSV[1], hypkinkCand.momMothSV[2], + hypkinkCand.momDaugSV[0], hypkinkCand.momDaugSV[1], hypkinkCand.momDaugSV[2], + hypkinkCand.dcaXYMothPv, hypkinkCand.dcaXYDaugPv, hypkinkCand.dcaKinkTopo, + hypkinkCand.chi2ITSMoth, hypkinkCand.itsClusterSizeMoth, hypkinkCand.itsClusterSizeDaug, + hypkinkCand.tpcMomDaug, hypkinkCand.tpcSignalDaug, hypkinkCand.tpcNClsPIDDaug, + hypkinkCand.nSigmaTPCDaug, hypkinkCand.nSigmaITSDaug, hypkinkCand.nSigmaTOFDaug, + hypkinkCand.isSignal, hypkinkCand.isSignalReco, hypkinkCand.isCollReco, hypkinkCand.isSurvEvSelection, + hypkinkCand.truePosSV[0], hypkinkCand.truePosSV[1], hypkinkCand.truePosSV[2], + hypkinkCand.trueMomMothPV[0], hypkinkCand.trueMomMothPV[1], hypkinkCand.trueMomMothPV[2], + hypkinkCand.trueMomMothSV[0], hypkinkCand.trueMomMothSV[1], hypkinkCand.trueMomMothSV[2], + hypkinkCand.trueMomDaugSV[0], hypkinkCand.trueMomDaugSV[1], hypkinkCand.trueMomDaugSV[2], + hypkinkCand.isMothReco, hypkinkCand.momMothPV[0], hypkinkCand.momMothPV[1], hypkinkCand.momMothPV[2], + hypkinkCand.updateMomMothPV[0], hypkinkCand.updateMomMothPV[1], hypkinkCand.updateMomMothPV[2]); + } + + // fill kink signals which are not reconstructed + for (auto const& mcparticle : particlesMC) { + bool isKinkSignal = false; + if (hypoMoth == kHypertriton) { + auto dChannel = H3LDecay::getDecayChannel(mcparticle, dauIDList); + if (dChannel == H3LDecay::k2bodyNeutral) { + isKinkSignal = true; + } + } else if (hypoMoth == kHyperhelium4sigma) { + auto dChannel = He4SDecay::getDecayChannel(mcparticle, dauIDList); + if (dChannel == He4SDecay::k2body) { + isKinkSignal = true; + } + } + if (!isKinkSignal) { + continue; + } + + if (std::find(signalIndicesPool.begin(), signalIndicesPool.end(), mcparticle.globalIndex()) != signalIndicesPool.end()) { + continue; + } + + HypKinkCandidate hypkinkCand; + auto mcDaugTrack = particlesMC.rawIteratorAt(dauIDList[0]); + auto mcNeutTrack = particlesMC.rawIteratorAt(dauIDList[1]); + fillCandidateMCInfo(hypkinkCand, mcparticle, mcDaugTrack, mcNeutTrack); + + if (mcPartIndices[mcparticle.globalIndex()] != -1) { + auto mothTrack = tracks.rawIteratorAt(mcPartIndices[mcparticle.globalIndex()]); + if (mothTrack.has_collision()) { + auto collision = mothTrack.collision_as(); + auto bc = collision.template bc_as(); + initCCDB(bc); + fillCandidateRecoMoth(hypkinkCand, collision, mothTrack); + } + } + + outputMCTable( + mBz > 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, + -1, -1, -1, + -1, -1, -1, + true, false, isReconstructedMCCollisions[mcparticle.mcCollisionId()], isSelectedMCCollisions[mcparticle.mcCollisionId()], + hypkinkCand.truePosSV[0], hypkinkCand.truePosSV[1], hypkinkCand.truePosSV[2], + hypkinkCand.trueMomMothPV[0], hypkinkCand.trueMomMothPV[1], hypkinkCand.trueMomMothPV[2], + hypkinkCand.trueMomMothSV[0], hypkinkCand.trueMomMothSV[1], hypkinkCand.trueMomMothSV[2], + hypkinkCand.trueMomDaugSV[0], hypkinkCand.trueMomDaugSV[1], hypkinkCand.trueMomDaugSV[2], + hypkinkCand.isMothReco, hypkinkCand.momMothPV[0], hypkinkCand.momMothPV[1], hypkinkCand.momMothPV[2], + hypkinkCand.updateMomMothPV[0], hypkinkCand.updateMomMothPV[1], hypkinkCand.updateMomMothPV[2]); + } + } + PROCESS_SWITCH(HyperkinkRecoTask, processMC, "process MC", false); +}; + +//-------------------------------------------------------------- +// check the performance of mcparticle +struct HyperkinkQa { + + Configurable hypoMoth{"hypoMoth", kHypertriton, "Mother particle hypothesis"}; + + HistogramRegistry genQAHist{"genQAHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry recoQAHist{"recoQAHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + ConfigurableAxis ptBins{"ptBins", {200, 0.f, 10.f}, "Binning for #it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis ctBins{"ctBins", {100, 0.f, 25.f}, "Binning for c#it{t} (cm)"}; + ConfigurableAxis rigidityBins{"rigidityBins", {200, -10.f, 10.f}, "Binning for #it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis nsigmaBins{"nsigmaBins", {120, -6.f, 6.f}, "Binning for n sigma"}; + ConfigurableAxis invMassBins{"invMassBins", {100, 3.85f, 4.15f}, "Binning for invariant mass (GeV/#it{c}^{2})"}; + ConfigurableAxis radiusBins{"radiusBins", {40, 0.f, 40.f}, "Binning for radius in xy plane (cm)"}; + + o2::aod::ITSResponse itsResponse; + + int charge = 1; + float massMoth = 999.f; + float massChargedDaug = 999.f; + float massNeutralDaug = 999.f; + int pdgMoth = 0; + std::array pdgDaug = {o2::constants::physics::Pdg::kTriton, PDG_t::kPi0}; // pdgcode of charged (0) and neutral (1) daughter particles + o2::track::PID pidTypeDaug = o2::track::PID::Triton; + + void init(InitContext&) + { + if (doprocessMC == true) { + itsResponse.setMCDefaultParameters(); + + if (hypoMoth == kHypertriton) { + charge = 1; + massMoth = o2::constants::physics::MassHyperTriton; + massChargedDaug = o2::constants::physics::MassTriton; + massNeutralDaug = o2::constants::physics::MassPi0; + pdgMoth = o2::constants::physics::Pdg::kHyperTriton; + pdgDaug[kDaugCharged] = o2::constants::physics::Pdg::kTriton; + pdgDaug[kDaugNeutral] = PDG_t::kPi0; + pidTypeDaug = o2::track::PID::Triton; + } else if (hypoMoth == kHyperhelium4sigma) { + charge = 2; + massMoth = o2::constants::physics::MassHyperHelium4Sigma; + massChargedDaug = o2::constants::physics::MassAlpha; + massNeutralDaug = o2::constants::physics::MassPi0; + pdgMoth = o2::constants::physics::Pdg::kHyperHelium4Sigma; + pdgDaug[kDaugCharged] = o2::constants::physics::Pdg::kAlpha; + pdgDaug[kDaugNeutral] = PDG_t::kPi0; + pidTypeDaug = o2::track::PID::Alpha; + } else { + LOG(fatal) << "Unknown mother particle hypothesis"; + } + + const AxisSpec pAxis{ptBins, "#it{p} (GeV/#it{c})"}; + const AxisSpec ptAxis{ptBins, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ctAxis{ctBins, "c#it{t} (cm)"}; + const AxisSpec rigidityAxis{rigidityBins, "p/z (GeV/#it{c})"}; + const AxisSpec nsigmaAxis{nsigmaBins, "TPC n#sigma"}; + const AxisSpec itsnsigmaAxis{nsigmaBins, "ITS n#sigma"}; + const AxisSpec invMassAxis{invMassBins, "Inv Mass (GeV/#it{c}^{2})"}; + const AxisSpec deltaPtAxis{200, -10.f, 10.f, "#Delta p_{T} (GeV/#it{c})"}; + const AxisSpec deltaPzAxis{200, -10.f, 10.f, "#Delta p_{z} (GeV/#it{c})"}; + const AxisSpec itsRadiusAxis{radiusBins, "ITS R (cm)"}; + const AxisSpec svRadiuAxis{radiusBins, "Decay Vertex R (cm)"}; + + auto hCollCounter = genQAHist.add("hCollCounter", "hCollCounter", HistType::kTH1F, {{2, 0.0f, 2.0f}}); + hCollCounter->GetXaxis()->SetBinLabel(1, "Reconstructed Collisions"); + hCollCounter->GetXaxis()->SetBinLabel(2, "Selected"); + auto hMcCollCounter = genQAHist.add("hMcCollCounter", "hMcCollCounter", HistType::kTH1F, {{2, 0.0f, 2.0f}}); + hMcCollCounter->GetXaxis()->SetBinLabel(1, "MC Collisions"); + hMcCollCounter->GetXaxis()->SetBinLabel(2, "Reconstructed"); + + if (hypoMoth == kHypertriton) { + auto hGenHyperMothCounter = genQAHist.add("hGenHyperMothCounter", "", HistType::kTH1F, {{10, 0.f, 10.f}}); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(1, "H3L All"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(2, "Matter"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(3, "AntiMatter"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(4, "t + #pi^{0}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(5, "#bar{t} + #pi^{0}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(6, "{}^{3}He + #pi^{-}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(7, "{}^{3}#bar{He} + #pi^{+}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(8, "d + p + #pi^{-}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(9, "#bar{d} + #bar{p} + #pi^{+}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(10, "Others"); + } else if (hypoMoth == kHyperhelium4sigma) { + auto hGenHyperMothCounter = genQAHist.add("hGenHyperMothCounter", "", HistType::kTH1F, {{10, 0.f, 10.f}}); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(1, "He4S All"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(2, "Matter"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(3, "AntiMatter"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(4, "#alpha + #pi^{0}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(5, "#bar{#alpha} + #pi^{0}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(6, "t + p + #pi^{0}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(7, "#bar{t} + #bar{p} + #pi^{0}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(8, "t + n + #pi^{+}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(9, "#bar{t} + #bar{n} + #pi^{+}"); + hGenHyperMothCounter->GetXaxis()->SetBinLabel(10, "Others"); + } + + auto hEvtSelectedHyperMothCounter = genQAHist.add("hEvtSelectedHyperMothCounter", "", HistType::kTH1F, {{2, 0.f, 2.f}}); + hEvtSelectedHyperMothCounter->GetXaxis()->SetBinLabel(1, "Generated"); + hEvtSelectedHyperMothCounter->GetXaxis()->SetBinLabel(2, "Survived"); + + genQAHist.add("hGenHyperMothP", "", HistType::kTH1F, {pAxis}); + genQAHist.add("hGenHyperMothPt", "", HistType::kTH1F, {ptAxis}); + genQAHist.add("hGenHyperMothCt", "", HistType::kTH1F, {ctAxis}); + genQAHist.add("hMcRecoInvMass", "", HistType::kTH1F, {invMassAxis}); + + // efficiency/criteria studies for tracks which are true candidates + hMothCounter = recoQAHist.add("hMothCounter", "", HistType::kTH1F, {{9, 0.f, 9.f}}); + hMothCounter->GetXaxis()->SetBinLabel(1, "Generated"); + hMothCounter->GetXaxis()->SetBinLabel(2, "Reconstructed"); + hMothCounter->GetXaxis()->SetBinLabel(3, "eta"); + hMothCounter->GetXaxis()->SetBinLabel(4, "has collision"); + hMothCounter->GetXaxis()->SetBinLabel(5, "ITSonly"); + hMothCounter->GetXaxis()->SetBinLabel(6, "ITS hits"); + hMothCounter->GetXaxis()->SetBinLabel(7, "ITS IR"); + hMothCounter->GetXaxis()->SetBinLabel(8, "ITS chi2"); + hMothCounter->GetXaxis()->SetBinLabel(9, "pt"); + recoQAHist.add("h2TrueMotherDeltaPtVsTrueSVR", ";Decay Vertex R (cm);#Delta p_{T} (GeV/#it{c});", HistType::kTH2F, {svRadiuAxis, deltaPtAxis}); + recoQAHist.add("h2TrueMotherDeltaEtaVsTrueSVR", ";Decay Vertex R (cm);#Delta #eta;", HistType::kTH2F, {svRadiuAxis, {200, -1.f, 1.f}}); + recoQAHist.add("h2GoodMotherDeltaPtVsTrueSVR", ";Decay Vertex R (cm);#Delta p_{T} (GeV/#it{c});", HistType::kTH2F, {svRadiuAxis, deltaPtAxis}); + + hDaugCounter = recoQAHist.add("hDaugCounter", "", HistType::kTH1F, {{9, 0.f, 9.f}}); + hDaugTPCNSigma = recoQAHist.add("hDaugTPCNSigma", "", HistType::kTH2F, {rigidityAxis, nsigmaAxis}); + + hRecoMothCounter = recoQAHist.add("hRecoMothCounter", "", HistType::kTH1F, {{9, 0.f, 9.f}}); + hRecoDaugCounter = recoQAHist.add("hRecoDaugCounter", "", HistType::kTH1F, {{9, 0.f, 9.f}}); + for (const auto& hist : {hDaugCounter, hRecoMothCounter, hRecoDaugCounter}) { + hist->GetXaxis()->SetBinLabel(1, "Generated"); + hist->GetXaxis()->SetBinLabel(2, "Reconstructed"); + hist->GetXaxis()->SetBinLabel(3, "eta"); + hist->GetXaxis()->SetBinLabel(4, "has ITS&TPC"); + hist->GetXaxis()->SetBinLabel(5, "TPC crossed rows"); + hist->GetXaxis()->SetBinLabel(6, "TPC Ncls"); + hist->GetXaxis()->SetBinLabel(7, "TPC n#sigma"); + hist->GetXaxis()->SetBinLabel(8, "ITS hits"); + hist->GetXaxis()->SetBinLabel(9, "has TOF"); + } + + recoQAHist.add("hMothIsPVContributer", "", HistType::kTH1F, {{2, 0.f, 2.f}}); + recoQAHist.add("hMothITSCls", "", HistType::kTH1F, {{8, 0.f, 8.f}}); + recoQAHist.add("hDaugIsPVContributer", "", HistType::kTH1F, {{2, 0.f, 2.f}}); + recoQAHist.add("hDaugITSCls", "", HistType::kTH1F, {{8, 0.f, 8.f}}); + recoQAHist.add("hDaugITSNSigma", "", HistType::kTH2F, {rigidityAxis, itsnsigmaAxis}); + recoQAHist.add("hRecoDaugPVsITSNSigma", "", HistType::kTH2F, {rigidityAxis, itsnsigmaAxis}); + recoQAHist.add("hRecoCandidateCount", "", HistType::kTH1F, {{4, 0.f, 4.f}}); + + recoQAHist.add("hDiffZTracks", "", HistType::kTH1F, {{200, -100.f, 100.f}}); + recoQAHist.add("hDiffAbsZTracks", "", HistType::kTH1F, {{200, -100.f, 100.f}}); + recoQAHist.add("hDiffXTracks", "", HistType::kTH1F, {{200, -100.f, 100.f}}); + } + } + + Configurable skipRejectedEvents{"skipRejectedEvents", false, "Flag to skip events that fail event selection cuts"}; + Configurable doEventCut{"doEventCut", true, "Apply event selection"}; + Configurable maxZVertex{"maxZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + + Configurable etaMax{"etaMax", 1., "eta cut for tracks"}; + Configurable minPtMoth{"minPtMoth", 0.5, "Minimum pT/z of the mother track"}; + Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + Configurable nTPCClusMinDaug{"nTPCClusMinDaug", 80, "daug NTPC clusters cut"}; + Configurable itsMaxChi2{"itsMaxChi2", 36, "max chi2 for ITS"}; + Configurable minRatioTPCNCls{"minRatioTPCNCls", 0.8, "min ratio of TPC crossed rows to findable clusters"}; + + Preslice permcCollision = o2::aod::mcparticle::mcCollisionId; + + // QA for mother track selection + template + bool motherTrackCheck(const TTrack& track, const std::shared_ptr hist) + { + hist->Fill(1); + + if (std::abs(track.eta()) > etaMax) { + return false; + } + hist->Fill(2); + + if (!track.has_collision()) { + return false; + } + hist->Fill(3); + + if (!track.hasITS() || track.hasTPC() || track.hasTOF()) { + return false; + } + hist->Fill(4); + + if (track.itsNCls() >= kITSLayers - 1) { + return false; + } + hist->Fill(5); + + if (track.itsNClsInnerBarrel() != kITSInnerBarrelLayers) { + return false; + } + hist->Fill(6); + + if (track.itsChi2NCl() >= itsMaxChi2) { + return false; + } + hist->Fill(7); + + if (track.pt() <= minPtMoth) { + return false; + } + hist->Fill(8); + + return true; + } + + // qa for daughter track selection + template + bool daughterTrackCheck(const TTrack& track, const std::shared_ptr hist, float tpcNSigma) + { + hist->Fill(1); + + if (std::abs(track.eta()) > etaMax) { + return false; + } + hist->Fill(2); + + if (!track.hasITS() || !track.hasTPC()) { + return false; + } + hist->Fill(3); + + if (track.tpcNClsCrossedRows() <= minRatioTPCNCls * track.tpcNClsFindable()) { + return false; + } + hist->Fill(4); + + if (track.tpcNClsFound() <= nTPCClusMinDaug) { + return false; + } + hist->Fill(5); + + if (std::abs(tpcNSigma) > tpcPidNsigmaCut) { + return false; + } + hist->Fill(6); + + if (track.itsNClsInnerBarrel() != 0 || track.itsNCls() > kITSInnerBarrelLayers) { + return false; + } + hist->Fill(7); + + if (track.hasTOF()) { + return false; + } + hist->Fill(8); + + return true; + } + + void processData(o2::aod::Collisions const&) + { + // dummy process function; + } + PROCESS_SWITCH(HyperkinkQa, processData, "process data", true); + + void processMC(aod::McCollisions const& mcCollisions, aod::McParticles const& particlesMC, MCLabeledCollisionsFull const& collisions, MCLabeledTracksIU const& tracks, aod::BCsWithTimestamps const&) + { + std::vector mcPartIndices; + setTrackIDForMC(mcPartIndices, particlesMC, tracks); + std::vector isSelectedMCCollisions(mcCollisions.size(), false); + std::vector dauIDList(2, -1); + + for (const auto& collision : collisions) { + genQAHist.fill(HIST("hCollCounter"), 0.5); + if (doEventCut && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || std::abs(collision.posZ()) > maxZVertex)) { + continue; + } + genQAHist.fill(HIST("hCollCounter"), 1.5); + if (collision.has_mcCollision()) { + isSelectedMCCollisions[collision.mcCollisionId()] = true; + } + } + + for (const auto& mcCollision : mcCollisions) { + genQAHist.fill(HIST("hMcCollCounter"), 0.5); + if (isSelectedMCCollisions[mcCollision.globalIndex()]) { // Check that the event is reconstructed and that the reconstructed events pass the selection + genQAHist.fill(HIST("hMcCollCounter"), 1.5); + } else { + if (skipRejectedEvents) { + continue; + } + } + + const auto& dparticlesMC = particlesMC.sliceBy(permcCollision, mcCollision.globalIndex()); + + for (const auto& mcparticle : dparticlesMC) { + if (std::abs(mcparticle.pdgCode()) != pdgMoth) { + continue; + } + bool isMatter = mcparticle.pdgCode() > 0; + genQAHist.fill(HIST("hGenHyperMothCounter"), 0.5); + genQAHist.fill(HIST("hGenHyperMothCounter"), isMatter ? 1.5 : 2.5); + + // QA for decay channels + bool isKinkSignal = false; + if (hypoMoth == kHypertriton) { + auto dChannel = H3LDecay::getDecayChannel(mcparticle, dauIDList); + if (dChannel == H3LDecay::k2bodyNeutral) { + genQAHist.fill(HIST("hGenHyperMothCounter"), isMatter ? 3.5 : 4.5); + isKinkSignal = true; + } else if (dChannel == H3LDecay::k2bodyCharged) { + genQAHist.fill(HIST("hGenHyperMothCounter"), isMatter ? 5.5 : 6.5); + } else if (dChannel == H3LDecay::k3bodyCharged) { + genQAHist.fill(HIST("hGenHyperMothCounter"), isMatter ? 7.5 : 8.5); + } else if (dChannel == H3LDecay::kNChannel) { + genQAHist.fill(HIST("hGenHyperMothCounter"), 9.5); + continue; + } + } else if (hypoMoth == kHyperhelium4sigma) { + auto dChannel = He4SDecay::getDecayChannel(mcparticle, dauIDList); + if (dChannel == He4SDecay::k2body) { + genQAHist.fill(HIST("hGenHyperMothCounter"), isMatter ? 3.5 : 4.5); + isKinkSignal = true; + } else if (dChannel == He4SDecay::k3body_p) { + genQAHist.fill(HIST("hGenHyperMothCounter"), isMatter ? 5.5 : 6.5); + } else if (dChannel == He4SDecay::k3body_n) { + genQAHist.fill(HIST("hGenHyperMothCounter"), isMatter ? 7.5 : 8.5); + } else if (dChannel == He4SDecay::kNChannel) { + genQAHist.fill(HIST("hGenHyperMothCounter"), 9.5); + continue; + } + } + + if (!isKinkSignal) { + continue; + } + recoQAHist.fill(HIST("hMothCounter"), 0); + + genQAHist.fill(HIST("hEvtSelectedHyperMothCounter"), 0.5); + if (isSelectedMCCollisions[mcCollision.globalIndex()]) { + genQAHist.fill(HIST("hEvtSelectedHyperMothCounter"), 1.5); + } + + float svPos[3] = {-999, -999, -999}; + std::vector> dauMom(kNDaughterType, std::vector(3, -999.0f)); + for (const auto& mcparticleDaughter : mcparticle.daughters_as()) { + for (int type = 0; type < kNDaughterType; type++) { + if (std::abs(mcparticleDaughter.pdgCode()) == pdgDaug[type]) { + dauMom[type][0] = mcparticleDaughter.px(); + dauMom[type][1] = mcparticleDaughter.py(); + dauMom[type][2] = mcparticleDaughter.pz(); + + if (type == kDaugCharged) { + svPos[0] = mcparticleDaughter.vx(); + svPos[1] = mcparticleDaughter.vy(); + svPos[2] = mcparticleDaughter.vz(); + + // if daughter track is reconstructed + if (mcPartIndices[mcparticleDaughter.globalIndex()] != -1) { + hDaugCounter->Fill(0.f); + auto track = tracks.rawIteratorAt(mcPartIndices[mcparticleDaughter.globalIndex()]); + float tpcNSigma = getTPCNSigma(track, pidTypeDaug); + daughterTrackCheck(track, hDaugCounter, tpcNSigma); + if (track.hasTPC()) { + hDaugTPCNSigma->Fill(track.p() * track.sign(), tpcNSigma); + } + } + } + } + } + } + + genQAHist.fill(HIST("hGenHyperMothP"), mcparticle.p()); + genQAHist.fill(HIST("hGenHyperMothPt"), mcparticle.pt()); + float ct = RecoDecay::sqrtSumOfSquares(svPos[0] - mcparticle.vx(), svPos[1] - mcparticle.vy(), svPos[2] - mcparticle.vz()) * massMoth / mcparticle.p(); + genQAHist.fill(HIST("hGenHyperMothCt"), ct); + float hypermothMCMass = RecoDecay::m(std::array{std::array{dauMom[kDaugCharged][0], dauMom[kDaugCharged][1], dauMom[kDaugCharged][2]}, std::array{dauMom[kDaugNeutral][0], dauMom[kDaugNeutral][1], dauMom[kDaugNeutral][2]}}, std::array{massChargedDaug, massNeutralDaug}); + genQAHist.fill(HIST("hMcRecoInvMass"), hypermothMCMass); + + // if mother track is reconstructed + if (mcPartIndices[mcparticle.globalIndex()] != -1) { + auto motherTrack = tracks.rawIteratorAt(mcPartIndices[mcparticle.globalIndex()]); + bool isGoodMother = motherTrackCheck(motherTrack, hMothCounter); + float svR = RecoDecay::sqrtSumOfSquares(svPos[0], svPos[1]); + float deltapt = mcparticle.pt() - charge * motherTrack.pt(); + + recoQAHist.fill(HIST("h2TrueMotherDeltaPtVsTrueSVR"), svR, deltapt); + recoQAHist.fill(HIST("h2TrueMotherDeltaEtaVsTrueSVR"), svR, mcparticle.eta() - motherTrack.eta()); + if (isGoodMother) { + recoQAHist.fill(HIST("h2GoodMotherDeltaPtVsTrueSVR"), svR, deltapt); + } + + // if mother track and charged daughters are all reconstructed + bool isDauReconstructed = mcPartIndices[dauIDList[0]] != -1; + if (isDauReconstructed) { + auto daughterTrack = tracks.rawIteratorAt(mcPartIndices[dauIDList[0]]); + bool isMoth = motherTrackCheck(motherTrack, hRecoMothCounter); + bool isDaug = daughterTrackCheck(daughterTrack, hRecoDaugCounter, getTPCNSigma(daughterTrack, pidTypeDaug)); + + recoQAHist.fill(HIST("hRecoCandidateCount"), 0.5); + recoQAHist.fill(HIST("hRecoMothCounter"), 0.5); + recoQAHist.fill(HIST("hMothITSCls"), motherTrack.itsNCls()); + recoQAHist.fill(HIST("hRecoDaugCounter"), 0.5); + recoQAHist.fill(HIST("hMothIsPVContributer"), motherTrack.isPVContributor() ? 1.5 : 0.5); + recoQAHist.fill(HIST("hDaugIsPVContributer"), daughterTrack.isPVContributor() ? 1.5 : 0.5); + + if (svR > LayerRadii[3]) { + recoQAHist.fill(HIST("hDiffZTracks"), daughterTrack.z() - motherTrack.z()); + recoQAHist.fill(HIST("hDiffAbsZTracks"), std::abs(daughterTrack.z()) - std::abs(motherTrack.z())); + recoQAHist.fill(HIST("hDiffXTracks"), daughterTrack.x() - motherTrack.x()); + } + + float itsNSigma = getITSNSigma(daughterTrack, itsResponse, pidTypeDaug); + if (daughterTrack.hasITS()) { + recoQAHist.fill(HIST("hDaugITSNSigma"), daughterTrack.sign() * daughterTrack.p(), itsNSigma); + recoQAHist.fill(HIST("hDaugITSCls"), daughterTrack.itsNCls()); + } + + if (motherTrack.has_collision() && daughterTrack.has_collision()) { + recoQAHist.fill(HIST("hRecoCandidateCount"), 1.5); + if (motherTrack.collisionId() == daughterTrack.collisionId()) { + recoQAHist.fill(HIST("hRecoCandidateCount"), 2.5); + } + } + + if (isMoth && isDaug) { + recoQAHist.fill(HIST("hRecoCandidateCount"), 3.5); + recoQAHist.fill(HIST("hRecoDaugPVsITSNSigma"), daughterTrack.sign() * daughterTrack.p(), itsNSigma); + } + } + } + } + } + } + PROCESS_SWITCH(HyperkinkQa, processMC, "do QA for MC prodcutions", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{ + // Parse the metadata + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx b/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx deleted file mode 100644 index 52f038356dc..00000000000 --- a/PWGLF/TableProducer/Nuspex/hypertriton3bodyfinder.cxx +++ /dev/null @@ -1,1193 +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 3-body method is not recommended due to high cost of computing resources -// 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 "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/Vtx3BodyTables.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 "EventFiltering/filterTables.h" - -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.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 FullTracksExtIU = soa::Join; -using MCLabeledTracksIU = soa::Join; - -template -bool is3bodyDecayedH3L(TMCParticle const& particle) -{ - if (particle.pdgCode() != 1010010030 && particle.pdgCode() != -1010010030) { - return false; - } - bool haveProton = false, havePionPlus = false, haveDeuteron = false; - bool haveAntiProton = false, havePionMinus = false, haveAntiDeuteron = false; - for (auto& mcparticleDaughter : particle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == 2212) - haveProton = true; - if (mcparticleDaughter.pdgCode() == -2212) - haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == 211) - havePionPlus = true; - if (mcparticleDaughter.pdgCode() == -211) - havePionMinus = true; - if (mcparticleDaughter.pdgCode() == 1000010020) - haveDeuteron = true; - if (mcparticleDaughter.pdgCode() == -1000010020) - haveAntiDeuteron = true; - } - if (haveProton && havePionMinus && haveDeuteron && particle.pdgCode() == 1010010030) { - return true; - } else if (haveAntiProton && havePionPlus && haveAntiDeuteron && particle.pdgCode() == -1010010030) { - return true; - } - return false; -} - -namespace o2::aod -{ -namespace v0goodpostrack -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodTrack, goodTrack, int, Tracks, "_GoodTrack"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace v0goodpostrack -DECLARE_SOA_TABLE(V0GoodPosTracks, "AOD", "V0GOODPOSTRACKS", o2::soa::Index<>, v0goodpostrack::GoodTrackId, v0goodpostrack::CollisionId); -namespace v0goodnegtrack -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodTrack, goodTrack, int, Tracks, "_GoodTrack"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace v0goodnegtrack -DECLARE_SOA_TABLE(V0GoodNegTracks, "AOD", "V0GOODNEGTRACKS", o2::soa::Index<>, v0goodnegtrack::GoodTrackId, v0goodnegtrack::CollisionId); -namespace v0goodtrack -{ -DECLARE_SOA_INDEX_COLUMN_FULL(GoodTrack, goodTrack, int, Tracks, "_GoodTrack"); -DECLARE_SOA_INDEX_COLUMN(Collision, collision); -} // namespace v0goodtrack -DECLARE_SOA_TABLE(V0GoodTracks, "AOD", "V0GOODTRACKS", o2::soa::Index<>, v0goodtrack::GoodTrackId, v0goodtrack::CollisionId); -} // namespace o2::aod - -struct trackprefilter { - HistogramRegistry registry{ - "registry", - { - {"hCrossedRows", "hCrossedRows", {HistType::kTH1F, {{50, 0.0f, 200.0f}}}}, - {"hGoodTrackCount", "hGoodTrackCount", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, - {"hGoodPosTrackCount", "hGoodPosTrackCount", {HistType::kTH1F, {{1, 0.0f, 1.0f}}}}, - {"hGoodNegTrackCount", "hGoodNegTrackCount", {HistType::kTH1F, {{1, 0.0f, 1.0f}}}}, - {"h3bodyCounter", "h3bodyCounter", {HistType::kTH1F, {{6, 0.0f, 6.0f}}}}, - }, - }; - - // change the dca cut for helium3 - Configurable mintpcNCls{"mintpcNCls", 70, "min tpc Nclusters"}; - Configurable tpcrefit{"tpcrefit", 0, "demand TPC refit"}; - - Produces v0GoodPosTracks; - Produces v0GoodNegTracks; - Produces v0GoodTracks; - - // Fix: Add PID and pt cuts to tracks - void processDefault(aod::Collision const& /*collision*/, - FullTracksExtIU const& tracks) - { - for (auto& t0 : tracks) { - registry.fill(HIST("hGoodTrackCount"), 0.5); - registry.fill(HIST("hCrossedRows"), t0.tpcNClsCrossedRows()); - if (tpcrefit) { - if (!(t0.trackType() & o2::aod::track::TPCrefit)) { - continue; // TPC refit - } - } - registry.fill(HIST("hGoodTrackCount"), 1.5); - if (t0.tpcNClsFound() < mintpcNCls) { - continue; - } - registry.fill(HIST("hGoodTrackCount"), 2.5); - if (t0.signed1Pt() > 0.0f) { - v0GoodPosTracks(t0.globalIndex(), t0.collisionId()); - registry.fill(HIST("hGoodPosTrackCount"), 0.5); - registry.fill(HIST("hGoodTrackCount"), 3.5); - } - if (t0.signed1Pt() < 0.0f) { - v0GoodNegTracks(t0.globalIndex(), t0.collisionId()); - registry.fill(HIST("hGoodNegTrackCount"), 0.5); - registry.fill(HIST("hGoodTrackCount"), 3.5); - } - v0GoodTracks(t0.globalIndex(), t0.collisionId()); - } - } - PROCESS_SWITCH(trackprefilter, processDefault, "Default process function", true); - - // process function for MC d3body check - // void processCheck(aod::Collision const& collision, aod::Decay3Bodys const& decay3bodys, - void processCheck(aod::Decay3Bodys const& decay3bodys, - MCLabeledTracksIU const& /*tracks*/, aod::McParticles const& /*particlesMC*/) - { - for (auto& d3body : decay3bodys) { - registry.fill(HIST("h3bodyCounter"), 0.5); - auto lTrack0 = d3body.track0_as(); - auto lTrack1 = d3body.track1_as(); - auto lTrack2 = d3body.track2_as(); - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 1.5); - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 2.5); - - int lPDG = -1; - bool is3bodyDecay = false; - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - lPDG = lMother1.pdgCode(); - if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { - is3bodyDecay = true; // vtxs with the same mother - } - if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { - is3bodyDecay = true; // vtxs with the same mother - } - } - } - } - } // end association check - - if (!is3bodyDecay || std::abs(lPDG) != 1010010030) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 3.5); - if (lTrack0.collisionId() != lTrack1.collisionId() || lTrack0.collisionId() != lTrack2.collisionId()) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 4.5); - - if (lTrack0.collisionId() != d3body.collisionId()) { - continue; - } - registry.fill(HIST("h3bodyCounter"), 5.5); - - // LOG(info) << "; Track0ID: " << lTrack0.globalIndex() << "; Track1ID:" << lTrack1.globalIndex() << "; Track2ID:" << lTrack2.globalIndex(); - v0GoodPosTracks(lTrack0.globalIndex(), lTrack0.collisionId()); - v0GoodNegTracks(lTrack1.globalIndex(), lTrack1.collisionId()); - v0GoodTracks(lTrack2.globalIndex(), lTrack2.collisionId()); - } - } - PROCESS_SWITCH(trackprefilter, processCheck, "Check specific paired tracks", false); -}; - -struct hypertriton3bodyFinder { - - Produces vtx3bodydata; - Service ccdb; - - // Configurables - Configurable UseCFFilter{"UseCFFilter", true, "Reject event without CF LD trigger"}; - Configurable RejectBkgInMC{"RejectBkgInMC", false, "Reject fake 3-body pairs in MC check"}; - - Configurable d_UseAbsDCA{"d_UseAbsDCA", true, "Use Abs DCAs"}; - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - - // Selection criteria - Configurable minRToMeanVertex = {"minRToMeanVertex", 0.5, ""}; ///< min radial distance of V0 from beam line (mean vertex) - // Configurable causalityRTolerance = {"causalityRTolerance", 1., ""}; ///< V0 radius cannot exceed its contributors minR by more than this value - Configurable maxV0ToProngsRDiff = {"maxV0ToProngsRDiff", 50., ""}; ///< V0 radius cannot be lower than this ammount wrt minR of contributors - Configurable minPtV0 = {"minPtV0", 0.5, ""}; ///< v0 minimum pT - Configurable maxTglV0 = {"maxTglV0", 2., ""}; ///< maximum tgLambda of V0 - Configurable maxDCAXY2ToMeanVertex3bodyV0 = {"maxDCAXY2ToMeanVertex3bodyV0", 2 * 2, ""}; - Configurable minCosPAXYMeanVertex3bodyV0 = {"minCosPAXYMeanVertex3bodyV0", 0.9, ""}; ///< min cos of PA to beam line (mean vertex) in tr. plane for 3body V0 cand. - Configurable minCosPA3bodyV0 = {"minCosPA3bodyV0", 0.8, ""}; // min cos of PA to PV for 3body V0 - - // for 3 body reconstructed Vertex - Configurable minbachPt = {"minbachPt", 0.6, ""}; ///< Minimum bachelor Pt - Configurable maxRDiff3bodyV0 = {"maxRDiff3bodyV0", 3, ""}; ///< Maximum difference between V0 and 3body radii - Configurable minPt3Body = {"minPt3Body", 0.01, ""}; // minimum pT of 3body Vertex - Configurable maxTgl3Body = {"maxTgl3Body", 2, ""}; // maximum tgLambda of 3body Vertex - Configurable minCosPA3body = {"minCosPA3body", 0.8, ""}; // min cos of PA to PV for 3body Vertex - - // for DCA - Configurable dcavtxdau{"dcavtxdau", 2.0, "DCA Vtx Daughters"}; - Configurable d_UseH3LDCACut{"d_UseH3LDCACut", true, "Use Cuts for H3L DCA to PV"}; - Configurable maxDCAXY3Body{"maxDCAXY3Body", 0.5, "DCAXY H3L to PV"}; // max DCA of 3 body decay to PV in XY - Configurable maxDCAZ3Body{"maxDCAZ3Body", 1.0, "DCAZ H3L to PV"}; // max DCA of 3 body decay to PV in Z - - Configurable useMatCorrType{"useMatCorrType", 2, "0: none, 1: TGeo, 2: LUT"}; - // 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"}; - - Preslice perCollisionGoodPosTracks = o2::aod::v0goodpostrack::collisionId; - Preslice perCollisionGoodNegTracks = o2::aod::v0goodnegtrack::collisionId; - Preslice perCollisionGoodTracks = o2::aod::v0goodtrack::collisionId; - Preslice perCollisionV0s = o2::aod::v0::collisionId; - Preslice perCollisionV0Datas = o2::aod::v0data::collisionId; - - // Helper struct to pass V0 information - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - {"hDauTrackCounter", "hDauTrackCounter", {HistType::kTH1F, {{3, 0.0f, 3.0f}}}}, - {"hV0Counter", "hV0Counter", {HistType::kTH1F, {{8, -0.5f, 7.5f}}}}, - {"hTrueV0Counter", "hTrueV0Counter", {HistType::kTH1F, {{8, -0.5f, 7.5f}}}}, - {"hVtx3BodyCounter", "hVtx3BodyCounter", {HistType::kTH1F, {{9, -0.5f, 8.5f}}}}, - {"hTrueVtx3BodyCounter", "hTrueVtx3BodyCounter", {HistType::kTH1F, {{9, -0.5f, 8.5f}}}}, - {"hVirtLambaCounter", "hVirtualLambaCounter", {HistType::kTH1F, {{6, -0.5f, 5.5f}}}}, - {"hCFFilteredVirtLambaCounter", "hCFFilteredVirtLambaCounter", {HistType::kTH1F, {{6, -0.5f, 5.5f}}}}, - }, - }; - - //------------------------------------------------------------------ - // Fill stats histograms - enum v0step { kV0All = 0, - kV0hasSV, - kV0Radius, - kV0Pt, - kV0TgLamda, - kV0InvMass, - kV0DcaXY, - kV0CosPA, - kNV0Steps }; - enum vtxstep { kVtxAll = 0, - kVtxbachPt, - kVtxhasSV, - kVtxRadius, - kVtxPt, - kVtxTgLamda, - kVtxCosPA, - kVtxDcaDau, - kVtxDcaH3L, - kNVtxSteps }; - - // Helper struct to do bookkeeping of building parameters - struct { - std::array v0stats; - std::array truev0stats; - std::array vtxstats; - std::array truevtxstats; - std::array virtLambdastats; - } statisticsRegistry; - - void resetHistos() - { - for (Int_t ii = 0; ii < kNV0Steps; ii++) { - statisticsRegistry.v0stats[ii] = 0; - statisticsRegistry.truev0stats[ii] = 0; - } - for (Int_t ii = 0; ii < kNVtxSteps; ii++) { - statisticsRegistry.vtxstats[ii] = 0; - statisticsRegistry.truevtxstats[ii] = 0; - } - for (Int_t ii = 0; ii < 12; ii++) { - statisticsRegistry.virtLambdastats[ii] = 0; - } - } - - void fillHistos() - { - for (Int_t ii = 0; ii < kNV0Steps; ii++) { - registry.fill(HIST("hV0Counter"), ii, statisticsRegistry.v0stats[ii]); - registry.fill(HIST("hTrueV0Counter"), ii, statisticsRegistry.truev0stats[ii]); - } - for (Int_t ii = 0; ii < kNVtxSteps; ii++) { - registry.fill(HIST("hVtx3BodyCounter"), ii, statisticsRegistry.vtxstats[ii]); - registry.fill(HIST("hTrueVtx3BodyCounter"), ii, statisticsRegistry.truevtxstats[ii]); - } - for (Int_t ii = 0; ii < 3; ii++) { - registry.fill(HIST("hVirtLambaCounter"), ii, statisticsRegistry.virtLambdastats[ii]); - registry.fill(HIST("hVirtLambaCounter"), ii + 3, statisticsRegistry.virtLambdastats[ii + 3]); - registry.fill(HIST("hCFFilteredVirtLambaCounter"), ii, statisticsRegistry.virtLambdastats[ii + 6]); - registry.fill(HIST("hCFFilteredVirtLambaCounter"), ii + 3, statisticsRegistry.virtLambdastats[ii + 9]); - } - } - - // v0, vtx, and virtual Lambda statiscs - void FillV0Counter(int kn, bool istrue = false) - { - statisticsRegistry.v0stats[kn]++; - if (istrue) { - statisticsRegistry.truev0stats[kn]++; - } - } - void FillVtxCounter(int kn, bool istrue = false) - { - statisticsRegistry.vtxstats[kn]++; - if (istrue) { - statisticsRegistry.truevtxstats[kn]++; - } - } - //------------------------------------------------------------------ - - 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> fitter; - o2::vertexing::DCAFitterN<3> fitter3body; - - void init(InitContext&) - { - resetHistos(); - mRunNumber = 0; - d_bz = 0; - maxSnp = 0.85f; // could be changed later - maxStep = 2.00f; // could be changed later - - TString DauCounterbinLabel[3] = {"Proton", "Pion", "Deuteron"}; - TString V0CounterbinLabel[8] = {"Total", "hasSV", "V0R", "V0Pt", "TgLambda", "V0Mass", "DcaXY", "CosPA"}; - TString VtxCounterbinLabel[9] = {"Total", "bachPt", "hasSV", "VtxR", "VtxPt", "TgLambda", "CosPA", "DcaDau", "DcaH3L"}; - for (int i{0}; i < 3; i++) { - registry.get(HIST("hDauTrackCounter"))->GetXaxis()->SetBinLabel(i + 1, DauCounterbinLabel[i]); - } - for (int i{0}; i < kNV0Steps; i++) { - registry.get(HIST("hV0Counter"))->GetXaxis()->SetBinLabel(i + 1, V0CounterbinLabel[i]); - registry.get(HIST("hTrueV0Counter"))->GetXaxis()->SetBinLabel(i + 1, V0CounterbinLabel[i]); - } - for (int i{0}; i < kNVtxSteps; i++) { - registry.get(HIST("hVtx3BodyCounter"))->GetXaxis()->SetBinLabel(i + 1, VtxCounterbinLabel[i]); - registry.get(HIST("hTrueVtx3BodyCounter"))->GetXaxis()->SetBinLabel(i + 1, VtxCounterbinLabel[i]); - } - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - // Set 2-body fitter and 3-body fitter3body - fitter.setPropagateToPCA(true); - fitter.setMaxR(200.); //->maxRIni3body - fitter.setMinParamChange(1e-3); - fitter.setMinRelChi2Change(0.9); - fitter.setMaxDZIni(1e9); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(d_UseAbsDCA); - fitter3body.setPropagateToPCA(true); - fitter3body.setMaxR(200.); //->maxRIni3body - fitter3body.setMinParamChange(1e-3); - fitter3body.setMinRelChi2Change(0.9); - fitter3body.setMaxDZIni(1e9); - fitter3body.setMaxChi2(1e9); - fitter3body.setUseAbsDCA(d_UseAbsDCA); - - // Material correction in the DCA fitter - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - if (useMatCorrType == 1) { - LOGF(info, "TGeo correction requested, loading geometry"); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); - } - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - } - if (useMatCorrType == 2) { - LOGF(info, "LUT correction requested, loading LUT"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - } - fitter.setMatCorrType(matCorr); - fitter3body.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 (d_bz_input > -990) { - d_bz = d_bz_input; - fitter.setBz(d_bz); - fitter3body.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(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 - fitter.setBz(d_bz); - fitter3body.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); - } - } - - //------------------------------------------------------------------ - // Check the info of good tracks - template - void CheckGoodTracks(TGoodTrackTable const& dGoodtracks, aod::McParticles const& /*particlesMC*/) - { - for (auto& goodtrackid : dGoodtracks) { - auto goodtrack = goodtrackid.template goodTrack_as(); - if (!goodtrack.has_mcParticle()) { - continue; - } - auto mcgoodtrack = goodtrack.template mcParticle_as(); - if (!mcgoodtrack.has_mothers()) { - continue; - } - bool flag_H3L = false; - for (auto& mothertrack : mcgoodtrack.template mothers_as()) { - if (is3bodyDecayedH3L(mothertrack)) { - flag_H3L = true; - } - } - if (flag_H3L && std::abs(mcgoodtrack.pdgCode()) == 2212) { - registry.fill(HIST("hDauTrackCounter"), 0.5); - } - if (flag_H3L && std::abs(mcgoodtrack.pdgCode()) == 211) { - registry.fill(HIST("hDauTrackCounter"), 1.5); - } - if (flag_H3L && std::abs(mcgoodtrack.pdgCode()) == 1000010020) { - registry.fill(HIST("hDauTrackCounter"), 2.5); - } - } - } - - o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; - //------------------------------------------------------------------ - // Virtual Lambda V0 finder - template - bool DecayV0Finder(TCollisionTable const& dCollision, TTrackTable const& dPtrack, TTrackTable const& dNtrack, float& rv0, bool isTrue3bodyV0 = false) - { - if (dPtrack.collisionId() != dNtrack.collisionId()) { - return false; - } - FillV0Counter(kV0All, isTrue3bodyV0); - if (!isTrue3bodyV0 && RejectBkgInMC) { - return false; - } - - auto Track0 = getTrackParCov(dPtrack); - auto Track1 = getTrackParCov(dNtrack); - int nCand = fitter.process(Track0, Track1); - if (nCand == 0) { - return false; - } - FillV0Counter(kV0hasSV, isTrue3bodyV0); - - // validate V0 radial position - // First check closeness to the beam-line as same as SVertexer - const auto& v0XYZ = fitter.getPCACandidate(); - float dxv0 = v0XYZ[0] - mMeanVertex.getX(), dyv0 = v0XYZ[1] - mMeanVertex.getY(), r2v0 = dxv0 * dxv0 + dyv0 * dyv0; - // float rv0 = std::sqrt(r2v0); - rv0 = std::sqrt(r2v0); - if (rv0 < minRToMeanVertex) { - return false; - } - FillV0Counter(kV0Radius, isTrue3bodyV0); - - // Not involved: Get minR with same way in SVertexer - // float drv0P = rv0 - Track0minR, drv0N = rv0 - Track1minR; - - // check: if the process function finish the propagation - if (!fitter.isPropagateTracksToVertexDone() && !fitter.propagateTracksToVertex()) { - return false; - } - - auto& trPProp = fitter.getTrack(0); - auto& trNProp = fitter.getTrack(1); - std::array pP, pN; - trPProp.getPxPyPzGlo(pP); - trNProp.getPxPyPzGlo(pN); - // estimate DCA of neutral V0 track to beamline: straight line with parametric equation - // x = X0 + pV0[0]*t, y = Y0 + pV0[1]*t reaches DCA to beamline (Xv, Yv) at - // t = -[ (x0-Xv)*pV0[0] + (y0-Yv)*pV0[1]) ] / ( pT(pV0)^2 ) - // Similar equation for 3D distance involving pV0[2] - std::array pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; - float pt2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1], prodXYv0 = dxv0 * pV0[0] + dyv0 * pV0[1], tDCAXY = prodXYv0 / pt2V0; - float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); - if (ptV0 < minPtV0) { // pt cut - return false; - } - FillV0Counter(kV0Pt, isTrue3bodyV0); - - if (pV0[2] / ptV0 > maxTglV0) { // tgLambda cut - return false; - } - FillV0Counter(kV0TgLamda, isTrue3bodyV0); - - // apply mass selections - float massV0LambdaHyp = RecoDecay::m(array{array{pP[0], pP[1], pP[2]}, array{pN[0], pN[1], pN[2]}}, array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); - float massV0AntiLambdaHyp = RecoDecay::m(array{array{pP[0], pP[1], pP[2]}, array{pN[0], pN[1], pN[2]}}, array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton}); - float massMargin = 20 * (0.001 * (1. + 0.5 * ptV0)) + 0.07; - if (massV0LambdaHyp - o2::constants::physics::MassLambda > massMargin && massV0AntiLambdaHyp - o2::constants::physics::MassLambda > massMargin) { - return false; - } - FillV0Counter(kV0InvMass, isTrue3bodyV0); - - float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; - float cosPAXY = prodXYv0 / std::sqrt(r2v0 * pt2V0); - if (dca2 > maxDCAXY2ToMeanVertex3bodyV0) { - return false; - } - FillV0Counter(kV0DcaXY, isTrue3bodyV0); - - if (cosPAXY < minCosPAXYMeanVertex3bodyV0) { - return false; - } - float dx = v0XYZ[0] - dCollision.posX(), dy = v0XYZ[1] - dCollision.posY(), dz = v0XYZ[2] - dCollision.posZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; - float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); - if (cosPA < minCosPA3bodyV0) { - return false; - } - FillV0Counter(kV0CosPA, isTrue3bodyV0); - return true; - } - //------------------------------------------------------------------ - // 3body decay vertex finder - template - void Decay3bodyFinder(TCollisionTable const& dCollision, TTrackTable const& dPtrack, TTrackTable const& dNtrack, TTrackTable const& dBachtrack, float const& rv0, bool isTrue3bodyVtx = false) - { - if (dPtrack.collisionId() != dBachtrack.collisionId()) { - return; - } - if (dPtrack.globalIndex() == dBachtrack.globalIndex()) { - return; // skip the track used by V0 - } - FillVtxCounter(kVtxAll, isTrue3bodyVtx); - if (!isTrue3bodyVtx && RejectBkgInMC) { - return; - } - - auto track0 = getTrackParCov(dPtrack); - auto track1 = getTrackParCov(dNtrack); - auto bach = getTrackParCov(dBachtrack); - - if (bach.getPt() < minbachPt) { - return; - } - FillVtxCounter(kVtxbachPt, isTrue3bodyVtx); - - int n3bodyVtx = fitter3body.process(track0, track1, bach); - if (n3bodyVtx == 0) { // discard this pair - return; - } - FillVtxCounter(kVtxhasSV, isTrue3bodyVtx); - - const auto& vertexXYZ = fitter3body.getPCACandidatePos(); - // make sure the cascade radius is smaller than that of the vertex - float dxc = vertexXYZ[0] - dCollision.posX(), dyc = vertexXYZ[1] - dCollision.posY(), dzc = vertexXYZ[2] - dCollision.posZ(), r2vertex = dxc * dxc + dyc * dyc; - float rvertex = std::sqrt(r2vertex); - if (std::abs(rv0 - rvertex) > maxRDiff3bodyV0 || rvertex < minRToMeanVertex) { - return; - } - FillVtxCounter(kVtxRadius, isTrue3bodyVtx); - - // Not involved: bach.minR - rveretx check - - // check: if the process function finish the propagation - if (!fitter3body.isPropagateTracksToVertexDone() && !fitter3body.propagateTracksToVertex()) { - return; - } - - auto& tr0 = fitter3body.getTrack(0); - auto& tr1 = fitter3body.getTrack(1); - auto& tr2 = fitter3body.getTrack(2); - std::array p0, p1, p2; - tr0.getPxPyPzGlo(p0); - tr1.getPxPyPzGlo(p1); - tr2.getPxPyPzGlo(p2); - std::array p3B = {p0[0] + p1[0] + p2[0], p0[1] + p1[1] + p2[1], p0[2] + p1[2] + p2[2]}; - - float pt2 = p3B[0] * p3B[0] + p3B[1] * p3B[1], p2candidate = pt2 + p3B[2] * p3B[2]; - float pt = std::sqrt(pt2); - if (pt < minPt3Body) { // pt cut - return; - } - FillVtxCounter(kVtxPt, isTrue3bodyVtx); - - if (p3B[2] / pt > maxTgl3Body) { // tgLambda cut - return; - } - FillVtxCounter(kVtxTgLamda, isTrue3bodyVtx); - - float cosPA = (p3B[0] * dxc + p3B[1] * dyc + p3B[2] * dzc) / std::sqrt(p2candidate * (r2vertex + dzc * dzc)); - if (cosPA < minCosPA3body) { - return; - } - FillVtxCounter(kVtxCosPA, isTrue3bodyVtx); - - if (fitter3body.getChi2AtPCACandidate() > dcavtxdau) { - return; - } - FillVtxCounter(kVtxDcaDau, isTrue3bodyVtx); - - // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo; - - 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 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 Track2Par = getTrackPar(dBachtrack); - o2::base::Propagator::Instance()->propagateToDCABxByBz({dCollision.posX(), dCollision.posY(), dCollision.posZ()}, Track2Par, 2.f, fitter3body.getMatCorrType(), &dcaInfo); - auto Track2dcaXY = dcaInfo[0]; - - // H3L DCA Check - // auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, fitter3body.calcPCACovMatrixFlat(), t2.sign()); - auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, dBachtrack.sign()); - o2::dataformats::DCA dca; - if (d_UseH3LDCACut && (!track3B.propagateToDCA({{dCollision.posX(), dCollision.posY(), dCollision.posZ()}, {dCollision.covXX(), dCollision.covXY(), dCollision.covYY(), dCollision.covXZ(), dCollision.covYZ(), dCollision.covZZ()}}, fitter3body.getBz(), &dca, 5.) || - std::abs(dca.getY()) > maxDCAXY3Body || std::abs(dca.getZ()) > maxDCAZ3Body)) { - return; - } - FillVtxCounter(kVtxDcaH3L, isTrue3bodyVtx); - - vtx3bodydata( - dPtrack.globalIndex(), dNtrack.globalIndex(), dBachtrack.globalIndex(), dCollision.globalIndex(), 0, - 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, - 0); // To be fixed - } - //------------------------------------------------------------------ - // 3body decay finder for a collsion - template - void DecayFinder(TCollisionTable const& dCollision, TPosTrackTable const& dPtracks, TNegTrackTable const& dNtracks, TGoodTrackTable const& dGoodtracks) - { - for (auto& t0id : dPtracks) { // FIXME: turn into combination(...) - auto t0 = t0id.template goodTrack_as(); - - for (auto& t1id : dNtracks) { - auto t1 = t1id.template goodTrack_as(); - float rv0; - if (!DecayV0Finder(dCollision, t0, t1, rv0)) { - continue; - } - - for (auto& t2id : dGoodtracks) { - auto t2 = t2id.template goodTrack_as(); - Decay3bodyFinder(dCollision, t0, t1, t2, rv0); - } - } - } - fillHistos(); - resetHistos(); - } - //------------------------------------------------------------------ - // MC 3body decay vertex finder - template - void DecayFinderMC(TCollisionTable const& dCollision, TPosTrackTable const& dPtracks, TNegTrackTable const& dNtracks, TGoodTrackTable const& dGoodtracks) - { - for (auto& t0id : dPtracks) { // FIXME: turn into combination(...) - auto t0 = t0id.template goodTrack_as(); - for (auto& t1id : dNtracks) { - auto t1 = t1id.template goodTrack_as(); - if (t0.collisionId() != t1.collisionId()) { - continue; - } - - bool isTrue3bodyV0 = false; - if (t0.has_mcParticle() && t1.has_mcParticle()) { - auto t0mc = t0.template mcParticle_as(); - auto t1mc = t1.template mcParticle_as(); - if ((t0mc.pdgCode() == 2212 && t1mc.pdgCode() == -211) || (t0mc.pdgCode() == 211 && t1mc.pdgCode() == -2212)) { - if (t0mc.has_mothers() && t1mc.has_mothers()) { - for (auto& t0mother : t0mc.template mothers_as()) { - for (auto& t1mother : t1mc.template mothers_as()) { - if (t0mother.globalIndex() == t1mother.globalIndex() && std::abs(t0mother.pdgCode()) == 1010010030) { - isTrue3bodyV0 = true; - } - } - } - } - } - } - - float rv0; - if (!DecayV0Finder(dCollision, t0, t1, rv0, isTrue3bodyV0)) { - continue; - } - - for (auto& t2id : dGoodtracks) { - auto t2 = t2id.template goodTrack_as(); - - bool isTrue3bodyVtx = false; - if (t0.has_mcParticle() && t1.has_mcParticle() && t2.has_mcParticle()) { - auto t0mc = t0.template mcParticle_as(); - auto t1mc = t1.template mcParticle_as(); - auto t2mc = t2.template mcParticle_as(); - if ((t0mc.pdgCode() == 2212 && t1mc.pdgCode() == -211 && t2mc.pdgCode() == 1000010020) || (t0mc.pdgCode() == 211 && t1mc.pdgCode() == -2212 && t2mc.pdgCode() == -1000010020)) { - if (t0mc.has_mothers() && t1mc.has_mothers() && t2mc.has_mothers()) { - for (auto& t0mother : t0mc.template mothers_as()) { - for (auto& t1mother : t1mc.template mothers_as()) { - for (auto& t2mother : t2mc.template mothers_as()) { - if (t0mother.globalIndex() == t1mother.globalIndex() && t0mother.globalIndex() == t2mother.globalIndex() && std::abs(t0mother.pdgCode()) == 1010010030) { - isTrue3bodyVtx = true; - } - } - } - } - } - } - } - - Decay3bodyFinder(dCollision, t0, t1, t2, rv0, isTrue3bodyVtx); - } - } - } - fillHistos(); - resetHistos(); - } - //------------------------------------------------------------------ - // MC virtual lambda check - template - void VirtualLambdaCheck(TCollisionTable const& /*dCollision*/, TV0DataTable const& fullV0s, int bin) - { - for (auto& v0 : fullV0s) { - statisticsRegistry.virtLambdastats[bin]++; - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - if (postrack.has_mcParticle() && negtrack.has_mcParticle()) { - auto postrackmc = postrack.template mcParticle_as(); - auto negtrackmc = negtrack.template mcParticle_as(); - - if ((postrackmc.pdgCode() == 2212 && negtrackmc.pdgCode() == -211) || (postrackmc.pdgCode() == 211 && negtrackmc.pdgCode() == -2212)) { - if (postrackmc.has_mothers() && negtrackmc.has_mothers()) { - for (auto& posmother : postrackmc.template mothers_as()) { - for (auto& negmother : negtrackmc.template mothers_as()) { - if (posmother.globalIndex() == negmother.globalIndex()) { - if (posmother.pdgCode() == 1010010030) - statisticsRegistry.virtLambdastats[bin + 1]++; - else if (posmother.pdgCode() == -1010010030) - statisticsRegistry.virtLambdastats[bin + 2]++; - } - } - } - } - } - } - } - fillHistos(); - resetHistos(); - } - - //------------------------------------------------------------------ - // Process Function - void processData(aod::Collision const& collision, aod::V0GoodPosTracks const& ptracks, aod::V0GoodNegTracks const& ntracks, aod::V0GoodTracks const& goodtracks, FullTracksExtIU const&, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - DecayFinder(collision, ptracks, ntracks, goodtracks); - } - PROCESS_SWITCH(hypertriton3bodyFinder, processData, "Produce StoredVtx3BodyDatas with data", true); - - void processCFFilteredData(aod::Collisions const& collisions, aod::CFFilters const& cffilters, aod::V0GoodPosTracks const& Ptracks, aod::V0GoodNegTracks const& Ntracks, aod::V0GoodTracks const& Goodtracks, FullTracksExtIU const&, aod::BCsWithTimestamps const&) - { - for (int i{0}; i < collisions.size(); i++) { - auto collision = collisions.iteratorAt(i); - auto cffilter = cffilters.iteratorAt(i); - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - auto ptracks = Ptracks.sliceBy(perCollisionGoodPosTracks, collision.globalIndex()); - auto ntracks = Ntracks.sliceBy(perCollisionGoodNegTracks, collision.globalIndex()); - auto goodtracks = Goodtracks.sliceBy(perCollisionGoodTracks, collision.globalIndex()); - - if (!cffilter.hasLD() && UseCFFilter) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - - DecayFinder(collision, ptracks, ntracks, goodtracks); - } - } - PROCESS_SWITCH(hypertriton3bodyFinder, processCFFilteredData, "Produce StoredVtx3BodyDatas with data using CFtriggers", false); - - void processMC(aod::Collision const& collision, aod::V0GoodPosTracks const& ptracks, aod::V0GoodNegTracks const& ntracks, aod::V0GoodTracks const& goodtracks, aod::McParticles const& particlesMC, MCLabeledTracksIU const&, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - CheckGoodTracks(goodtracks, particlesMC); - DecayFinderMC(collision, ptracks, ntracks, goodtracks); - } - PROCESS_SWITCH(hypertriton3bodyFinder, processMC, "Produce StoredVtx3BodyDatas with MC", false); - - void processCFFilteredMC(aod::Collisions const& collisions, aod::CFFilters const& cffilters, aod::V0GoodPosTracks const& Ptracks, aod::V0GoodNegTracks const& Ntracks, aod::V0GoodTracks const& Goodtracks, aod::V0s const& V0s, aod::V0Datas const& fullV0s, aod::McParticles const& particlesMC, MCLabeledTracksIU const&, aod::BCsWithTimestamps const&) - { - for (int i{0}; i < collisions.size(); i++) { - auto collision = collisions.iteratorAt(i); - auto cffilter = cffilters.iteratorAt(i); - auto bc = collision.bc_as(); - initCCDB(bc); - registry.fill(HIST("hEventCounter"), 0.5); - - auto goodtracks = Goodtracks.sliceBy(perCollisionGoodTracks, collision.globalIndex()); - CheckGoodTracks(goodtracks, particlesMC); - auto v0s = V0s.sliceBy(perCollisionV0s, collision.globalIndex()); - auto fullv0s = fullV0s.sliceBy(perCollisionV0Datas, collision.globalIndex()); - VirtualLambdaCheck(collision, v0s, 0); - VirtualLambdaCheck(collision, fullv0s, 3); - - if (!cffilter.hasLD() && UseCFFilter) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - - auto ptracks = Ptracks.sliceBy(perCollisionGoodPosTracks, collision.globalIndex()); - auto ntracks = Ntracks.sliceBy(perCollisionGoodNegTracks, collision.globalIndex()); - - VirtualLambdaCheck(collision, v0s, 6); - VirtualLambdaCheck(collision, fullv0s, 9); - DecayFinderMC(collision, ptracks, ntracks, goodtracks); - } - } - PROCESS_SWITCH(hypertriton3bodyFinder, processCFFilteredMC, "Produce StoredVtx3BodyDatas with MC using CFtriggers", false); -}; - -struct hypertriton3bodyLabelBuilder { - - Produces vtxlabels; - - // 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)"}}}}, - }, - }; - - void init(InitContext const&) - { - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(2, "Same MotherParticle"); - registry.get(HIST("hLabelCounter"))->GetXaxis()->SetBinLabel(3, "True H3L"); - } - - Configurable TpcPidNsigmaCut{"TpcPidNsigmaCut", 5, "TpcPidNsigmaCut"}; - - void processDoNotBuildLabels(aod::Collisions::iterator const&) - { - // dummy process function - should not be required in the future - } - PROCESS_SWITCH(hypertriton3bodyLabelBuilder, processDoNotBuildLabels, "Do not produce MC label tables", true); - - void processBuildLabels(aod::Vtx3BodyDatas const& vtx3bodydatas, MCLabeledTracksIU const&, aod::McParticles const& /*particlesMC*/) - { - std::vector lIndices; - lIndices.reserve(vtx3bodydatas.size()); - for (int ii = 0; ii < vtx3bodydatas.size(); ii++) { - lIndices[ii] = -1; - } - - for (auto& vtx3body : vtx3bodydatas) { - - int lLabel = -1; - int lPDG = -1; - float lPt = -1; - double MClifetime = -1; - bool is3bodyDecay = false; - int lGlobalIndex = -1; - - auto lTrack0 = vtx3body.track0_as(); - auto lTrack1 = vtx3body.track1_as(); - auto lTrack2 = vtx3body.track2_as(); - registry.fill(HIST("hLabelCounter"), 0.5); - - // Association check - // There might be smarter ways of doing this in the future - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - vtxlabels(-1); - continue; - } - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - vtxlabels(-1); - continue; - } - - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - lGlobalIndex = lMother1.globalIndex(); - lPt = lMother1.pt(); - lPDG = lMother1.pdgCode(); - MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); - is3bodyDecay = true; // vtxs with the same mother - } - } - } - } // end association check - if (!is3bodyDecay) { - vtxlabels(-1); - continue; - } - registry.fill(HIST("hLabelCounter"), 1.5); - - // Intended for cross-checks only - // N.B. no rapidity cut! - 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}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hHypertritonMCPt"), lPt); - registry.fill(HIST("hHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hHypertritonMCMass"), hypertritonMCMass); - } - 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}); - registry.fill(HIST("hLabelCounter"), 2.5); - registry.fill(HIST("hAntiHypertritonMCPt"), lPt); - registry.fill(HIST("hAntiHypertritonMCLifetime"), MClifetime); - registry.fill(HIST("hAntiHypertritonMCMass"), antiHypertritonMCMass); - } - - // Construct label table, only true hypertriton and true daughters with a specified order is labeled - // for matter: track0->p, track1->pi, track2->d - // for antimatter: track0->pi, track1->p, track2->d - vtxlabels(lLabel); - } - } - PROCESS_SWITCH(hypertriton3bodyLabelBuilder, processBuildLabels, "Produce MC label tables", false); -}; - -struct hypertriton3bodyComparewithDecay3body { - - HistogramRegistry registry{ - "registry", - { - {"hMCInfoCounter", "hMCInfoCounter", {HistType::kTH1F, {{8, 0.0f, 8.0f}}}}, - {"hCheckCounter", "hCheckCounter", {HistType::kTH1F, {{5, 0.0f, 5.0f}}}}, - {"hHypertritonMCPtTotal", "hHypertritonMCPtTotal", {HistType::kTH1F, {{20, 0.0f, 10.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}}}}, - {"hAntiHypertritonMCMass", "hAntiHypertritonMCMass", {HistType::kTH1F, {{40, 2.95f, 3.05f}}}}, - {"hPairedHypertritonMCPt", "hPairedHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hPairedAntiHypertritonMCPt", "hPairedAntiHypertritonMCPt", {HistType::kTH1F, {{100, 0.0f, 10.0f}}}}, - {"hSameMcIndexCounter", "hSameMcIndexCounter", {HistType::kTH1F, {{2, 0.0f, 2.0f}}}}, - }, - }; - - void init(InitContext const&) - { - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(2, "Sig in Decay3body"); - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(3, "Sig SameCol"); - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(4, "Sig contained by finder"); - registry.get(HIST("hCheckCounter"))->GetXaxis()->SetBinLabel(5, "Sig SameIndex"); - } - 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 processDoNotCompare(aod::Collisions::iterator const&) - { - // dummy process function - should not be required in the future - } - PROCESS_SWITCH(hypertriton3bodyComparewithDecay3body, processDoNotCompare, "Do not do comparison", true); - - void processDoComparison(aod::Decay3Bodys const& decay3bodytable, soa::Join const& vtx3bodydatas, MCLabeledTracksIU const&, aod::McParticles const& /*particlesMC*/) - { - std::vector set_pair; - for (auto d3body : decay3bodytable) { - registry.fill(HIST("hCheckCounter"), 0.5); - registry.fill(HIST("hMCInfoCounter"), 0.5); - auto lTrack0 = d3body.track0_as(); - auto lTrack1 = d3body.track1_as(); - auto lTrack2 = d3body.track2_as(); - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - continue; - } - registry.fill(HIST("hMCInfoCounter"), 1.5); - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (lMCTrack0.isPhysicalPrimary() || lMCTrack1.isPhysicalPrimary() || lMCTrack2.isPhysicalPrimary()) { - continue; - } - if (lMCTrack0.producedByGenerator() || lMCTrack1.producedByGenerator() || lMCTrack2.producedByGenerator()) { - continue; - } - registry.fill(HIST("hMCInfoCounter"), 2.5); - - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - continue; - } - registry.fill(HIST("hMCInfoCounter"), 3.5); - - int lPDG = -1; - float lPt = -1; - bool is3bodyDecayedH3L = false; - int lGlobalIndex = -1; - - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { - registry.fill(HIST("hMCInfoCounter"), 4.5); - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { // vtxs with the same mother - registry.fill(HIST("hMCInfoCounter"), 7.5); - lGlobalIndex = lMother1.globalIndex(); - lPDG = lMother1.pdgCode(); - lPt = lMother1.pt(); - if (lPDG == 1010010030 && lMCTrack0.pdgCode() == 2212 && lMCTrack1.pdgCode() == -211 && lMCTrack2.pdgCode() == 1000010020) { - is3bodyDecayedH3L = true; - 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}); - registry.fill(HIST("hHypertritonMCPt"), lPt); - registry.fill(HIST("hHypertritonMCMass"), hypertritonMCMass); - } - if (lPDG == -1010010030 && lMCTrack0.pdgCode() == 211 && lMCTrack1.pdgCode() == -2212 && lMCTrack2.pdgCode() == -1000010020) { - is3bodyDecayedH3L = true; - 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}); - registry.fill(HIST("hAntiHypertritonMCPt"), lPt); - registry.fill(HIST("hAntiHypertritonMCMass"), antiHypertritonMCMass); - } - } - } - } - } // end association check - - if (!is3bodyDecayedH3L) { - continue; - } - - registry.fill(HIST("hCheckCounter"), 1.5); - registry.fill(HIST("hMCInfoCounter"), 5.5); - // for check - registry.fill(HIST("hHypertritonMCPtTotal"), lPt); - - Indexdaughters temp = {lMCTrack0.globalIndex(), lMCTrack1.globalIndex(), lMCTrack2.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("hMCInfoCounter"), 6.5); - } - - if (lTrack0.collisionId() != lTrack1.collisionId() || lTrack0.collisionId() != lTrack2.collisionId()) { - continue; - } - registry.fill(HIST("hCheckCounter"), 2.5); - - for (auto vtx : vtx3bodydatas) { - if (vtx.mcParticleId() == -1) { - continue; - } - auto mcparticle = vtx.mcParticle_as(); - if (mcparticle.globalIndex() == lGlobalIndex) { - registry.fill(HIST("hCheckCounter"), 4.5); // rare case check: if motherId matches but daughters not - if (lTrack0.globalIndex() == vtx.track0Id() && lTrack1.globalIndex() == vtx.track1Id() && lTrack2.globalIndex() == vtx.track2Id()) { - registry.fill(HIST("hCheckCounter"), 3.5); - if (lPDG > 0) { - registry.fill(HIST("hPairedHypertritonMCPt"), lPt); - } else { - registry.fill(HIST("hPairedAntiHypertritonMCPt"), lPt); - } - break; - } - } - } - } - } - PROCESS_SWITCH(hypertriton3bodyComparewithDecay3body, processDoComparison, "Compare decay3bodys and finder method with MC", false); -}; - -struct hypertriton3bodyInitializer { - Spawns vtx3bodydatas; - void init(InitContext const&) {} -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/TableProducer/Nuspex/lithium4analysis.cxx b/PWGLF/TableProducer/Nuspex/lithium4analysis.cxx deleted file mode 100644 index 20e717836a1..00000000000 --- a/PWGLF/TableProducer/Nuspex/lithium4analysis.cxx +++ /dev/null @@ -1,681 +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 sign = 0.f; - - float recoPtHe3() const { return sign * 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 sign * 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}; - - 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}; - Configurable cfgCompensatePIDinTracking{"cfgCompensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; - // 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("h2dEdxHe3candidates", "dEdx distribution; Signed #it{p} (GeV/#it{c}); dE/dx (a.u.)", kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.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() < 90 || // 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) - { - 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); - } - - 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.sign = candidateHe3.sign(); - - l4Cand.isBkgUS = candidateHe3.sign() * candidatePr.sign() < 0; - l4Cand.isBkgEM = mix; - - l4Cand.DCAxyHe3 = candidateHe3.dcaXY(); - l4Cand.DCAzHe3 = candidateHe3.dcaZ(); - l4Cand.DCAxyPr = candidatePr.dcaXY(); - l4Cand.DCAzPr = candidatePr.dcaZ(); - - bool heliumPID = candidateHe3.pidForTracking() == o2::track::PID::Helium3 || candidateHe3.pidForTracking() == o2::track::PID::Alpha; - float correctedTPCinnerParamHe3 = (heliumPID && cfgCompensatePIDinTracking) ? candidateHe3.tpcInnerParam() / 2.f : candidateHe3.tpcInnerParam(); - - l4Cand.tpcSignalHe3 = candidateHe3.tpcSignal(); - l4Cand.momHe3TPC = correctedTPCinnerParamHe3; - 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.sign; - 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); - bool heliumPID = track1.pidForTracking() == o2::track::PID::Helium3 || track1.pidForTracking() == o2::track::PID::Alpha; - - float correctedTPCinnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track1.tpcInnerParam() / 2.f : track1.tpcInnerParam(); - histos.fill(HIST("h2dEdxHe3candidates"), correctedTPCinnerParam * 2.f, track1.tpcSignal()); - - 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 - bool heliumPID = track1.pidForTracking() == o2::track::PID::Helium3 || track1.pidForTracking() == o2::track::PID::Alpha; - float correctedTPCinnerParamHe3 = (heliumPID && cfgCompensatePIDinTracking) ? track1.tpcInnerParam() / 2.f : track1.tpcInnerParam(); - cand.massTOFHe3 = correctedTPCinnerParamHe3 * 2.f * 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; - } - - bool heliumPID = he3Cand.pidForTracking() == o2::track::PID::Helium3 || he3Cand.pidForTracking() == o2::track::PID::Alpha; - float correctedTPCinnerParam = (heliumPID && cfgCompensatePIDinTracking) ? he3Cand.tpcInnerParam() / 2.f : he3Cand.tpcInnerParam(); - histos.fill(HIST("h2dEdxHe3candidates"), correctedTPCinnerParam * 2.f, he3Cand.tpcSignal()); - - 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 - - bool heliumPID = t1.pidForTracking() == o2::track::PID::Helium3 || he3Cand.pidForTracking() == o2::track::PID::Alpha; - float correctedTPCinnerParamHe3 = (heliumPID && cfgCompensatePIDinTracking) ? he3Cand.tpcInnerParam() / 2.f : he3Cand.tpcInnerParam(); - cand.massTOFHe3 = correctedTPCinnerParamHe3 * 2.f * 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 - bool heliumPID = track1.pidForTracking() == o2::track::PID::Helium3 || track1.pidForTracking() == o2::track::PID::Alpha; - float correctedTPCinnerParamHe3 = (heliumPID && cfgCompensatePIDinTracking) ? track1.tpcInnerParam() / 2.f : track1.tpcInnerParam(); - cand.massTOFHe3 = correctedTPCinnerParamHe3 * 2.f * 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 9053cb2ff44..87e7471e222 100644 --- a/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx @@ -11,36 +11,47 @@ // // Build \Lambda-n-n candidates from V0s and tracks // ============================================================================== -#include +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFLnnTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/TPCPIDResponse.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "PWGLF/DataModel/EPCalibrationTables.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "DataFormatsTPC/BetheBlochAleph.h" +#include "CCDB/BasicCCDBManager.h" #include "DCAFitter/DCAFitterN.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" -#include "PWGLF/DataModel/LFLnnTables.h" +#include + +#include +#include +#include +#include +#include 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; @@ -48,8 +59,7 @@ 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"}; - +static const std::vector NucleiName{"3H"}; std::shared_ptr hEvents; std::shared_ptr hZvtx; std::shared_ptr hCentFT0A; @@ -57,12 +67,27 @@ 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 hdEdx3HTPCMom; +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 @@ -87,6 +112,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; @@ -115,15 +145,22 @@ struct lnnRecoTask { // Selection criteria Configurable v0cospa{"lnncospa", 0.95, "V0 CosPA"}; - Configurable masswidth{"lnnmasswidth", 0.006, "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", 1, "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"}; - // Configurable RMSMean{"RMSMean", 0.07, "RMS Mean"}; // Define o2 fitter, 2-prong, active memory (no need to redefine per event) o2::vertexing::DCAFitterN<2> fitter; @@ -133,7 +170,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 @@ -151,11 +188,16 @@ struct lnnRecoTask { // 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{"TritMom", {100, 0.f, 20.f}, "Binning for Triton TPC momentum"}; + 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; @@ -163,6 +205,7 @@ 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; @@ -199,16 +242,36 @@ struct lnnRecoTask { const AxisSpec nSigma3HAxis{nSigmaBins, "n_{#sigma}({}^{3}H)"}; const AxisSpec zVtxAxis{zVtxBins, "z_{vtx} (cm)"}; const AxisSpec centAxis{centBins, "Centrality"}; - const AxisSpec TritMomAxis{TritMomBins, "#it{p}^{TPC}({}^{3}H)"}; - - 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}); - hdEdx3HTPCMom = qaRegistry.add("hdEdx3HTPCMom", "; #it{p}^{TPC}({}^{3}H); dE/dx", HistType::kTH2F, {TritMomAxis, 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}); + 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"); + 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"); @@ -279,21 +342,20 @@ 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; } float posRigidity = posTrack.tpcInnerParam(); float negRigidity = negTrack.tpcInnerParam(); - hdEdxTot->Fill(posRigidity, posTrack.tpcSignal()); - hdEdxTot->Fill(-negRigidity, negTrack.tpcSignal()); - // 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])}; @@ -302,29 +364,53 @@ struct lnnRecoTask { 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; @@ -333,6 +419,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 { @@ -368,24 +469,26 @@ struct lnnRecoTask { float lnnPt = std::hypot(lnnMom[0], lnnMom[1]); if (lnnPt < ptMin) { + hLnnCandLoss->Fill(3.); continue; } // Definition of lnn mass - float mLNN_HypHI = 2.994; // value in GeV, but 2993.7 MeV/c**2 - + 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 > mLNN_HypHI - masswidth && massLNNL < mLNN_HypHI + masswidth) { isLNNMass = true; } 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; } @@ -393,6 +496,7 @@ struct lnnRecoTask { double cosPA = RecoDecay::cpa(primVtx, lnnCand.decVtx, lnnMom); if (cosPA < v0cospa) { + hLnnCandLoss->Fill(6.); continue; } @@ -401,27 +505,28 @@ 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()}, posTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); - lnnCand.isMatter ? lnnCand.h3DCAXY = dcaInfo[0] : lnnCand.piDCAXY = dcaInfo[0]; + std::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()}, 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; - hdEdx3HSel->Fill(chargeFactor * lnnCand.mom3HTPC, h3track.tpcSignal()); - hNsigma3HSel->Fill(chargeFactor * lnnCand.mom3HTPC, lnnCand.nSigma3H); lnnCandidates.push_back(lnnCand); - if (is3H) { - - hdEdx3HTPCMom->Fill(lnnCand.mom3HTPC, h3track.tpcSignal()); + // Fill QA histograms + hdEdx3HSel->Fill(chargeFactor * lnnCand.mom3HTPC, h3track.tpcSignal()); + hNsigma3HSel->Fill(chargeFactor * lnnCand.mom3HTPC, lnnCand.nSigma3H); + 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); } } } @@ -437,6 +542,7 @@ 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()) { @@ -462,7 +568,6 @@ struct lnnRecoTask { lnnCand.isSignal = true; lnnCand.pdgCode = posMother.pdgCode(); lnnCand.survEvSelection = isGoodCollision[posMother.mcCollisionId()]; - filledMothers.push_back(posMother.globalIndex()); } } @@ -506,6 +611,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); } } @@ -513,12 +619,14 @@ struct lnnRecoTask { 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(); @@ -527,7 +635,7 @@ struct lnnRecoTask { hEvents->Fill(0.); - if ((collision.posZ()) > 10) { + if (std::abs(collision.posZ()) > 10) { continue; } hEvents->Fill(1.); @@ -539,6 +647,7 @@ struct lnnRecoTask { if (collision.has_mcCollision()) { isGoodCollision[collision.mcCollisionId()] = true; + collisionFT0Ccent[collision.mcCollisionId()] = collision.centFT0C(); } const uint64_t collIdx = collision.globalIndex(); @@ -562,6 +671,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); @@ -622,7 +732,7 @@ struct lnnRecoTask { lnnCand.posTrackID = -1; lnnCand.negTrackID = -1; lnnCand.isSignal = true; - outputMCTable(-1, -1, -1, + outputMCTable(-1, collisionFT0Ccent[mcPart.mcCollisionId()], -1, -1, -1, -1, 0, -1, -1, -1, @@ -631,6 +741,7 @@ struct lnnRecoTask { -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/nucleiAntineutronCex.cxx b/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx new file mode 100644 index 00000000000..3f5b35f4c89 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx @@ -0,0 +1,859 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file nucleiAntineutronCex.cxx +/// \brief Analysis task for antineutron detection through cex interactions +/// \author Fabiola Lugo +/// + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using o2::constants::math::Rad2Deg; + +struct NucleiAntineutronCex { + // Slicing per colision + Preslice perMcByColl = aod::mcparticle::mcCollisionId; + // Check available tables in the AOD, specifically TracksIU, TracksCovIU + using TracksWCovMc = soa::Join; + + // === Cut values === + static constexpr double kIts2MinR = 2.2; // ITS2 min radius [cm] + static constexpr double kIts2MaxR = 39.0; // ITS2 max radius [cm] + static constexpr double kIts2MaxVz = 39.0; // ITS2 max |vz| [cm] + static constexpr double kAccMaxEta = 1.2; // acceptance |eta| + static constexpr double kAccMaxVz = 5.3; // acceptance |vz| [cm] + static constexpr double kStrictEta = 0.9; // tighter eta cut + static constexpr double kInitDplane = 10.0; // init dplane + static constexpr double kHuge = 1e9; // fallback for bad denom + static constexpr int kMinItsHits = 2; + static constexpr double kVtxTol = 1e-4; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Produces outPairs; + + void init(InitContext const&) + { + // Primary vertex + histos.add("hVx", "Primary vertex X;X (cm);Entries", kTH1F, {{100, -5., 5.}}); + histos.add("hVy", "Primary vertex Y;Y (cm);Entries", kTH1F, {{100, -5., 5.}}); + histos.add("hVz", "Primary vertex Z;Z (cm);Entries", kTH1F, {{200, -20., 20.}}); + + // Primary antineutrons + histos.add("antin_p", "Total momentum;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("antin_px", "p_{x};p_{x} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("antin_py", "p_{y};p_{y} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("antin_pz", "p_{z};p_{z} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("antin_eta", "Pseudorapidity;#eta;Entries", kTH1F, {{100, -10., 10.}}); + histos.add("antin_p_ITScuts", "Momentum with ITS cuts;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + + // Primary neutrons + histos.add("n_p", "Total momentum;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("n_px", "p_{x};p_{x} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("n_py", "p_{y};p_{y} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("n_pz", "p_{z};p_{z} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("n_eta", "Pseudorapidity;#eta;Entries", kTH1F, {{100, -10., 10.}}); + histos.add("n_p_ITScuts", "Momentum with ITS cuts;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + + // Primary antiprotons + histos.add("antipP", "Total momentum;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("antipPx", "p_{x};p_{x} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("antipPy", "p_{y};p_{y} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("antipPz", "p_{z};p_{z} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("antipEta", "Pseudorapidity;#eta;Entries", kTH1F, {{100, -10., 10.}}); + histos.add("antipP_ITScuts", "Momentum with ITS cuts;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + + // Primary protons + histos.add("pP", "Total momentum;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("pPx", "p_{x};p_{x} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("pPy", "p_{y};p_{y} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("pPz", "p_{z};p_{z} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("pEta", "Pseudorapidity;#eta;Entries", kTH1F, {{100, -10., 10.}}); + histos.add("pP_ITScuts", "Momentum with ITS cuts;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + + // test (MC) + histos.add("antip_test", "Secondary antiprotons;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + + // CEX pair from antineutron (MC) + histos.add("cexPairMcP", "CEX pair total momentum;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexPairMcPt", "CEX pair p_{T};p_{T} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexPairMcPz", "CEX pair p_{z};p_{z} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("cex_pairmcDplane", "CEX pair d_{plane};d_{plane} (cm);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cex_pairmc_angle", "Pair opening angle;Angle (°);Entries", kTH1F, {{180, 0., 180.}}); + histos.add("cex_pairmc_vtx", "MC CEX pair vertex;X (cm);Y (cm)", kTH2F, {{100, -50., 50.}, {100, -50., 50.}}); + histos.add("cex_pairmc_vtxz", "MC secondary vertex Z;Z (cm);Entries", kTH1F, {{200, -60., 60.}}); + histos.add("cexPairMcPITScuts", "CEX pair momentum (ITS cuts);|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + + // CEX pair normalized to antineutron (MC) + histos.add("cexn_pairmc_p", "Pair p / antineutron p;p/p_{#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + histos.add("cexn_pairmc_pt", "Pair p_{T} / antineutron p_{T};p_{T}/p_{T,#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + histos.add("cexn_pairmc_pz", "Pair p_{z} / antineutron p_{z};p_{z}/p_{z,#bar{n}};Entries", kTH1F, {{100, -2., 2.}}); + + // BG pair (not from antineutron) (MC) + histos.add("cexbg_pairmc_p", "Background pair momentum;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexbg_pairmc_pt", "Background pair p_{T};p_{T} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexbg_pairmc_pz", "Background pair p_{z};p_{z} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("cexbg_pairmcDplane", "Background d_{plane};d_{plane} (cm);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexbg_pairmc_angle", "Background opening angle;Angle (°);Entries", kTH1F, {{180, 0., 180.}}); + histos.add("cexbg_pairmc_vtx", "Background pair vertex;X (cm);Y (cm)", kTH2F, {{100, -50., 50.}, {100, -50., 50.}}); + histos.add("cexbg_pairmc_vtxz", "Background secondary vertex Z;Z (cm);Entries", kTH1F, {{200, -60., 60.}}); + histos.add("cexbg_pairmc_pITScuts", "Background momentum (ITS cuts);|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + + // CEX pair from antineutron (TRK) + histos.add("cex_pairtrk_angle", "Pair opening angle (tracks);Angle (°);Entries", kTH1F, {{180, 0., 180.}}); + histos.add("cexPairTrkP", "Pair momentum (tracks);|p| (GeV/c);Entries", kTH1F, {{120, 0., 12.}}); + histos.add("cexPairTrkPt", "Pair p_{T} (tracks);p_{T} (GeV/c);Entries", kTH1F, {{120, 0., 12.}}); + histos.add("cexPairTrkPz", "Pair p_{z} (tracks);p_{z} (GeV/c);Entries", kTH1F, {{120, -12., 12.}}); + histos.add("cex_pairtrkVtxfitDcaPair", "DCA between tracks at PCA;DCA (cm);Entries", kTH1F, {{200, 0., 10.}}); + histos.add("cex_pairtrkVtxfitR", "Secondary-vertex radius (PCA);R (cm);Entries", kTH1F, {{200, 0., 60.}}); + histos.add("cex_pairtrkVtxfitDistToPv", "Distance from secondary vertex to PV;dist (cm);Entries", kTH1F, {{240, 0., 120.}}); + histos.add("cex_pairtrk_vtxfit_secVtxXY", "Secondary vertex (PCA);X (cm);Y (cm)", kTH2F, {{200, -60., 60.}, {200, -60., 60.}}); + histos.add("cex_pairtrk_vtxfit_secVtxZ", "Secondary vertex Z (PCA);Z (cm);Entries", kTH1F, {{240, -60., 60.}}); + + // BG pair (not from antineutron) (TRK) + histos.add("cexbg_pairtrk_angle", "Background opening angle (tracks);Angle (°);Entries", kTH1F, {{180, 0., 180.}}); + histos.add("cexbg_pairtrk_p", "Pair momentum (tracks);|p| (GeV/c);Entries", kTH1F, {{120, 0., 12.}}); + histos.add("cexbg_pairtrk_pt", "Pair p_{T} (tracks);p_{T} (GeV/c);Entries", kTH1F, {{120, 0., 12.}}); + histos.add("cexbg_pairtrk_pz", "Pair p_{z} (tracks);p_{z} (GeV/c);Entries", kTH1F, {{120, -12., 12.}}); + histos.add("cexbg_pairtrkVtxfitDcaPair", "DCA between tracks at PCA;DCA (cm);Entries", kTH1F, {{200, 0., 10.}}); + histos.add("cexbg_pairtrkVtxfitR", "Secondary-vertex radius (PCA);R (cm);Entries", kTH1F, {{200, 0., 60.}}); + histos.add("cexbg_pairtrkVtxfitDistToPv", "Distance from secondary vertex to PV;dist (cm);Entries", kTH1F, {{240, 0., 120.}}); + histos.add("cexbg_pairtrk_vtxfit_secVtxXY", "Secondary vertex (PCA);X (cm);Y (cm)", kTH2F, {{200, -60., 60.}, {200, -60., 60.}}); + histos.add("cexbg_pairtrk_vtxfit_secVtxZ", "Secondary vertex Z (PCA);Z (cm);Entries", kTH1F, {{240, -60., 60.}}); + + // Vertex fit (DCAFitter2 / PCA) + histos.add("vtxfitChi2", "DCAFitter2 #chi^{2};#chi^{2};Entries", kTH1F, {{200, 0., 100.}}); + histos.add("vtxfitStatus", "Fit status (0=OK);code;Entries", kTH1I, {{10, 0., 10.}}); + histos.add("vtxfit_mc_dX", "SV residual X (fit - MC);#Delta X (cm);Entries", kTH1F, {{400, -20., 20.}}); + histos.add("vtxfit_mc_dY", "SV residual Y (fit - MC);#Delta Y (cm);Entries", kTH1F, {{400, -20., 20.}}); + histos.add("vtxfit_mc_dZ", "SV residual Z (fit - MC);#Delta Z (cm);Entries", kTH1F, {{400, -20., 20.}}); + histos.add("vtxfit_mc_d3D", "SV distance |fit - MC|;#Delta r (cm);Entries", kTH1F, {{300, 0., 30.}}); + + // ITS PID (protons / antiprotons, reconstructed tracks) + histos.add("pItsNsigmaPr", "ITS n#sigma (p hyp., proton);n#sigma_{ITS}(p);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("apItsNsigmaPr", "ITS n#sigma (p hyp., antiproton);n#sigma_{ITS}(p);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("pItsPidValid", "ITS PID valid flag (proton);PidValid;Entries", kTH1F, {{2, 0., 2.}}); + histos.add("apItsPidValid", "ITS PID valid flag (antiproton);PidValid;Entries", kTH1F, {{2, 0., 2.}}); + histos.add("pTgl", "tgl (proton track);tgl;Entries", kTH1F, {{100, -2., 2.}}); + histos.add("apTgl", "tgl (antiproton track);tgl;Entries", kTH1F, {{100, -2., 2.}}); + histos.add("pItsNsigmaPr_bg", "ITS n#sigma (p hyp., proton);n#sigma_{ITS}(p);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("apItsNsigmaPr_bg", "ITS n#sigma (p hyp., antiproton);n#sigma_{ITS}(p);Entries", kTH1F, {{100, -10., 10.}}); + histos.add("pItsPidValid_bg", "ITS PID valid flag (proton);PidValid;Entries", kTH1F, {{2, 0., 2.}}); + histos.add("apItsPidValid_bg", "ITS PID valid flag (antiproton);PidValid;Entries", kTH1F, {{2, 0., 2.}}); + histos.add("pTgl_bg", "tgl (proton track);tgl;Entries", kTH1F, {{100, -2., 2.}}); + histos.add("apTgl_bg", "tgl (antiproton track);tgl;Entries", kTH1F, {{100, -2., 2.}}); + } + + static o2::track::TrackParCov makeTPCovFromAOD(const TracksWCovMc::iterator& tr) + { + using o2::track::TrackParCov; + TrackParCov tpcov; + // Local state: x, alpha, y, z, snp, tgl, q/pt + float par[5] = {tr.y(), tr.z(), tr.snp(), tr.tgl(), tr.signed1Pt()}; + tpcov.set(tr.x(), tr.alpha(), par); + + // Covariance matrix (15 terms) in O2 order + std::array cov = { + tr.cYY(), tr.cZY(), tr.cZZ(), + tr.cSnpY(), tr.cSnpZ(), tr.cSnpSnp(), + tr.cTglY(), tr.cTglZ(), tr.cTglSnp(), + tr.cTglTgl(), tr.c1PtY(), tr.c1PtZ(), + tr.c1PtSnp(), tr.c1PtTgl(), tr.c1Pt21Pt2()}; + tpcov.setCov(cov); + return tpcov; + } + + void process(aod::McCollisions const& cols, aod::McParticles const& particles, TracksWCovMc const& tracks) + { + double pvtxX = 0; + double pvtxY = 0; + double pvtxZ = 0; + for (auto const& col : cols) { + const auto colId = col.globalIndex(); + auto mcPartsThis = particles.sliceBy(perMcByColl, colId); + + if (std::isfinite(col.posX()) && std::isfinite(col.posY()) && std::isfinite(col.posZ())) { + pvtxX = col.posX(); + pvtxY = col.posY(); + pvtxZ = col.posZ(); + histos.fill(HIST("hVx"), pvtxX); + histos.fill(HIST("hVy"), pvtxY); + histos.fill(HIST("hVz"), pvtxZ); + } + + for (const auto& particle : mcPartsThis) { + + // Primary antineutrons + if (particle.pdgCode() == -kNeutron && particle.isPhysicalPrimary()) { + histos.fill(HIST("antin_p"), particle.p()); + histos.fill(HIST("antin_px"), particle.px()); + histos.fill(HIST("antin_py"), particle.py()); + histos.fill(HIST("antin_pz"), particle.pz()); + histos.fill(HIST("antin_eta"), particle.eta()); + if (std::abs(particle.eta()) < kAccMaxEta && std::abs(particle.vz()) < kAccMaxVz) + histos.fill(HIST("antin_p_ITScuts"), particle.p()); + } + // Primary neutrons + if (particle.pdgCode() == kNeutron && particle.isPhysicalPrimary()) { + histos.fill(HIST("n_p"), particle.p()); + histos.fill(HIST("n_px"), particle.px()); + histos.fill(HIST("n_py"), particle.py()); + histos.fill(HIST("n_pz"), particle.pz()); + histos.fill(HIST("n_eta"), particle.eta()); + if (std::abs(particle.eta()) < kAccMaxEta && std::abs(particle.vz()) < kAccMaxVz) + histos.fill(HIST("n_p_ITScuts"), particle.p()); + } + // Primary antiprotons + if (particle.pdgCode() == -kProton && particle.isPhysicalPrimary()) { + histos.fill(HIST("antipP"), particle.p()); + histos.fill(HIST("antipPx"), particle.px()); + histos.fill(HIST("antipPy"), particle.py()); + histos.fill(HIST("antipPz"), particle.pz()); + histos.fill(HIST("antipEta"), particle.eta()); + if (std::abs(particle.eta()) < kAccMaxEta && std::abs(particle.vz()) < kAccMaxVz) + histos.fill(HIST("antipP_ITScuts"), particle.p()); + } + // Primary protons + if (particle.pdgCode() == kProton && particle.isPhysicalPrimary()) { + histos.fill(HIST("pP"), particle.p()); + histos.fill(HIST("pPx"), particle.px()); + histos.fill(HIST("pPy"), particle.py()); + histos.fill(HIST("pPz"), particle.pz()); + histos.fill(HIST("pEta"), particle.eta()); + if (std::abs(particle.eta()) < kAccMaxEta && std::abs(particle.vz()) < kAccMaxVz) + histos.fill(HIST("pP_ITScuts"), particle.p()); + } + + // Seconday antiprotons from material + const auto procEnum = particle.getProcess(); + const bool isSecondaryFromMaterial = (!particle.producedByGenerator()) && (procEnum == kPHadronic || procEnum == kPHInhelastic); + if (particle.pdgCode() != -kProton || !isSecondaryFromMaterial || particle.mothersIds().empty()) + continue; + histos.fill(HIST("antip_test"), particle.p()); + + // Primary mother + bool hasPrimaryMotherAntip = false; + double motherPt = 0.0; + double motherPz = 0.0; + double motherVz = 0.0; + double motherP = 0.0; + double motherEta = 0.0; + int motherPdg = 0; + + for (const auto& mother : particle.mothers_as()) { + if (mother.isPhysicalPrimary()) { + hasPrimaryMotherAntip = true; + motherPt = mother.pt(); + motherPz = mother.pz(); + motherVz = mother.vz(); + motherP = mother.p(); + motherEta = mother.eta(); + motherPdg = mother.pdgCode(); + break; + } + } + if (!hasPrimaryMotherAntip) + continue; + + double antipVx = particle.vx(); + double antipVy = particle.vy(); + double antipVz = particle.vz(); + double antipPx = particle.px(); + double antipPy = particle.py(); + double antipPz = particle.pz(); + double antipE = particle.e(); + int antipId = particle.globalIndex(); + + // Selection conditions: Produced in the ITS + const double r = std::sqrt(antipVx * antipVx + antipVy * antipVy); + // Config for ITS + // if(3.9<=r && r<=43.0 && std::abs(antipVz)<=48.9){ + // Config for ITS2 + if (r < kIts2MinR || r > kIts2MaxR || std::abs(antipVz) > kIts2MaxVz) + continue; + if (std::abs(motherEta) >= kAccMaxEta || std::abs(motherVz) >= kAccMaxVz) + continue; + + // Pion minus veto + bool pionMinus = false; + for (const auto& particle1 : mcPartsThis) { + const auto proc1Enum = particle1.getProcess(); + const bool isSecondaryFromMaterial1 = (!particle1.producedByGenerator()) && (proc1Enum == kPHadronic || proc1Enum == kPHInhelastic); + if (particle1.mcCollisionId() != colId) + continue; + if (particle1.pdgCode() != kPiMinus || !isSecondaryFromMaterial1 || particle1.mothersIds().empty()) + continue; + bool hasPrimaryMotherPim = false; + for (const auto& mother : particle1.mothers_as()) { + if (mother.isPhysicalPrimary()) { + hasPrimaryMotherPim = true; + break; + } + } + if (!hasPrimaryMotherPim) + continue; + double pimVx = particle1.vx(); + double pimVy = particle1.vy(); + double pimVz = particle1.vz(); + if (std::abs(pimVx - antipVx) < kVtxTol && std::abs(pimVy - antipVy) < kVtxTol && std::abs(pimVz - antipVz) < kVtxTol) { + pionMinus = true; + break; + } + } + + // Pion plus veto + bool pionPlus = false; + for (const auto& particle2 : mcPartsThis) { + if (particle2.mcCollisionId() != colId) + continue; + const auto proc2Enum = particle2.getProcess(); + const bool isSecondaryFromMaterial2 = (!particle2.producedByGenerator()) && (proc2Enum == kPHadronic || proc2Enum == kPHInhelastic); + if (particle2.pdgCode() != kPiPlus || !isSecondaryFromMaterial2 || particle2.mothersIds().empty()) + continue; + bool hasPrimaryMotherPip = false; + for (const auto& mother : particle2.mothers_as()) { + if (mother.isPhysicalPrimary()) { + hasPrimaryMotherPip = true; + break; + } + } + if (!hasPrimaryMotherPip) + continue; + double pipVx = particle2.vx(); + double pipVy = particle2.vy(); + double pipVz = particle2.vz(); + if (std::abs(pipVx - antipVx) < kVtxTol && std::abs(pipVy - antipVy) < kVtxTol && std::abs(pipVz - antipVz) < kVtxTol) { + pionPlus = true; + break; + } + } + + if (pionPlus || pionMinus) + continue; + + // CEX selection + double dplane = kInitDplane; + double dplaneTmp = 0; + double p = 0; + double pTmp = 0; + double pcexPx = 0; + double pcexPy = 0; + double pcexPz = 0; + double e = 0; + double eTmp = 0; + int k_plane = -1; + int k_e = -1; + int k_p = -1; + + // Secondary proton from material + for (const auto& particle3 : mcPartsThis) { + if (particle3.mcCollisionId() != colId) + continue; + const auto proc3Enum = particle3.getProcess(); + const bool isSecondaryFromMaterial3 = (!particle3.producedByGenerator()) && (proc3Enum == kPHadronic || proc3Enum == kPHInhelastic); + if (particle3.pdgCode() != kProton || !isSecondaryFromMaterial3 || particle3.mothersIds().empty()) + continue; + bool hasPrimaryMotherP = false; + for (const auto& mother : particle3.mothers_as()) { + if (mother.isPhysicalPrimary()) { + hasPrimaryMotherP = true; + break; + } + } + if (!hasPrimaryMotherP) + continue; + double protonVx = particle3.vx(); + double protonVy = particle3.vy(); + double protonVz = particle3.vz(); + double pPx = particle3.px(); + double pPy = particle3.py(); + double pPz = particle3.pz(); + double pE = particle3.e(); + if (std::abs(protonVx - antipVx) < kVtxTol && std::abs(protonVy - antipVy) < kVtxTol && std::abs(protonVz - antipVz) < kVtxTol) { + // Same mother + bool shareMother = false; + const auto& momsAp = particle.mothersIds(); // antiproton + const auto& momsP = particle3.mothersIds(); // proton + for (const auto& ida : momsAp) { + for (const auto& idp : momsP) { + if (ida == idp) { + shareMother = true; + break; + } + } + if (shareMother) + break; + } + if (!shareMother) + continue; + + // CEX proton selection + // dplaneTmp = (pPy*antipPz - pPz*antipPy)*(pvtxX-antipVx) + (pPz*antipPx - pPx*antipPz)*(pvtxY-antipVy) + (pPx*antipPy - pPy*antipPx)*(pvtxZ-antipVz); + double nx = (pPy * antipPz - pPz * antipPy); + double ny = (pPz * antipPx - pPx * antipPz); + double nz = (pPx * antipPy - pPy * antipPx); + double rx = (pvtxX - antipVx); + double ry = (pvtxY - antipVy); + double rz = (pvtxZ - antipVz); + double denom = nx * nx + ny * ny + nz * nz; + if (denom > 0.) { + dplaneTmp = std::abs(nx * rx + ny * ry + nz * rz) / std::sqrt(denom); + } else { + dplaneTmp = kHuge; + } + if (std::abs(dplaneTmp) < std::abs(dplane)) { + k_plane = particle3.globalIndex(); + dplane = dplaneTmp; + } + + eTmp = antipE + pE; + if (std::abs(eTmp) > std::abs(e)) { + k_e = particle3.globalIndex(); + e = eTmp; + } + + pTmp = std::sqrt(std::pow((pPx + antipPx), 2) + std::pow((pPy + antipPy), 2) + std::pow((pPz + antipPz), 2)); + if (std::abs(pTmp) > std::abs(p)) { + k_p = particle3.globalIndex(); + p = pTmp; + pcexPx = pPx; + pcexPy = pPy; + pcexPz = pPz; + } + } + } + + if (k_plane == k_e && k_plane == k_p && k_plane >= 0) { + int pId = k_plane; + TVector3 pVecProton = TVector3(pcexPx, pcexPy, pcexPz); + TVector3 pVecAntiproton = TVector3(antipPx, antipPy, antipPz); + TVector3 total_mc_pVec = pVecProton + pVecAntiproton; + double cexPairMcP = total_mc_pVec.Mag(); + double cexPairMcPt = total_mc_pVec.Pt(); + double cexPairMcPz = pcexPz + antipPz; + double mcangleRad = pVecProton.Angle(pVecAntiproton); + double mcangleDeg = mcangleRad * Rad2Deg; + + // Antineutron mother + if (motherPdg == -kNeutron) { + // CEX pair + histos.fill(HIST("cexPairMcP"), cexPairMcP); + histos.fill(HIST("cexPairMcPt"), cexPairMcPt); + histos.fill(HIST("cexPairMcPz"), cexPairMcPz); + histos.fill(HIST("cex_pairmcDplane"), dplane); + histos.fill(HIST("cex_pairmc_angle"), mcangleDeg); + histos.fill(HIST("cex_pairmc_vtx"), antipVx, antipVy); + histos.fill(HIST("cex_pairmc_vtxz"), antipVz); + if (std::abs(motherEta) < kStrictEta && std::abs(motherVz) < kAccMaxVz) + histos.fill(HIST("cexPairMcPITScuts"), cexPairMcP); + // CEX pair normalized + if (motherP != 0) + histos.fill(HIST("cexn_pairmc_p"), cexPairMcP / motherP); + if (motherPt != 0) + histos.fill(HIST("cexn_pairmc_pt"), cexPairMcPt / motherPt); + if (motherPz != 0) + histos.fill(HIST("cexn_pairmc_pz"), cexPairMcPz / motherPz); + } + // BG mother + if (motherPdg != -kNeutron) { + // CEX pair + histos.fill(HIST("cexbg_pairmc_p"), cexPairMcP); + histos.fill(HIST("cexbg_pairmc_pt"), cexPairMcPt); + histos.fill(HIST("cexbg_pairmc_pz"), cexPairMcPz); + histos.fill(HIST("cexbg_pairmcDplane"), dplane); + histos.fill(HIST("cexbg_pairmc_angle"), mcangleDeg); + histos.fill(HIST("cexbg_pairmc_vtx"), antipVx, antipVy); + histos.fill(HIST("cexbg_pairmc_vtxz"), antipVz); + if (std::abs(motherEta) < kStrictEta && std::abs(motherVz) < kAccMaxVz) + histos.fill(HIST("cexbg_pairmc_pITScuts"), cexPairMcP); + } + + // Detector signal + bool antipLayers = false; + bool antipHasTrack = false; + double antipTrkPx = 0.; + double antipTrkPy = 0.; + double antipTrkPz = 0.; + double antipTrkP = 0.; + double antipTrkEta = 0.; + double antipTrkTpcSignal = 0; + // int antip_trk_nClsTPC = 0; + int antipTrkNClsIts = 0; + uint16_t apItsMap = 0; + float pTrkItsNSigmaPr = -999.f; + int8_t pTrkItsPidValid = 0; + float pTrkTgl = 0.f; + + bool pLayers = false; + bool pHasTrack = false; + double pTrkPx = 0.; + double pTrkPy = 0.; + double pTrkPz = 0.; + double pTrkP = 0.; + double pTrkEta = 0.; + double pTrkTpcSignal = 0; + // int p_trk_nClsTPC = 0; + int pTrkNClsIts = 0; + uint16_t pItsMap = 0; + float antipTrkItsNSigmaPr = -999.f; + int8_t antipTrkItsPidValid = 0; + float antipTrkTgl = 0.f; + + o2::aod::ITSResponse itsResponse; + + for (const auto& track : tracks) { + if (!track.has_mcParticle()) + continue; + const auto& mc = track.mcParticle(); + if (mc.mcCollisionId() != colId) + continue; + uint8_t itsMap = track.itsClusterMap(); + // Config for ITS1 + /*bool hitSPD = (itsMap & 0x3) != 0; // bits 0 (SPD L1) & 1 (SPD L2) + bool hitSDD = (itsMap & 0xC) != 0; // bits 2–3 + bool hitSSD = (itsMap & 0x30) != 0; // bits 4–5 + bool layerCondition = (hitSDD || hitSSD) && !hitSPD;*/ + // Config for ITS2 + bool hitL0 = (itsMap & (1u << 0)) != 0; + bool hitL1 = (itsMap & (1u << 1)) != 0; + bool hitL2 = (itsMap & (1u << 2)) != 0; + bool hitL3 = (itsMap & (1u << 3)) != 0; + bool hitL4 = (itsMap & (1u << 4)) != 0; + bool hitL5 = (itsMap & (1u << 5)) != 0; + bool hitL6 = (itsMap & (1u << 6)) != 0; + bool hitIB = (hitL0 || hitL1 || hitL2); + bool hitOuter = (hitL3 || hitL4 || hitL5 || hitL6); + int nITS = track.itsNCls(); + bool layerCondition = (!hitIB) && hitOuter && (nITS >= kMinItsHits); + + if (mc.globalIndex() == antipId) { + antipTrkP = track.p(); + antipTrkPx = track.px(); + antipTrkPy = track.py(); + antipTrkPz = track.pz(); + antipTrkEta = track.eta(); + antipTrkTpcSignal = track.tpcSignal(); + // antip_trk_nClsTPC = track.tpcNCls(); + antipTrkNClsIts = track.itsNCls(); + antipTrkTgl = track.tgl(); + const auto nsigmaITSantip = itsResponse.nSigmaITS(track); + antipTrkItsNSigmaPr = static_cast(nsigmaITSantip); + antipTrkItsPidValid = std::isfinite(nsigmaITSantip) ? 1 : 0; + antipHasTrack = true; + apItsMap = static_cast(track.itsClusterMap()); + antipLayers = (apItsMap != 0); + if (layerCondition) + antipLayers = true; + if (motherPdg == -kNeutron) { + histos.fill(HIST("apItsNsigmaPr"), antipTrkItsNSigmaPr); + histos.fill(HIST("apItsPidValid"), antipTrkItsPidValid); + histos.fill(HIST("apTgl"), antipTrkTgl); + } + if (motherPdg != -kNeutron) { + histos.fill(HIST("apItsNsigmaPr_bg"), antipTrkItsNSigmaPr); + histos.fill(HIST("apItsPidValid_bg"), antipTrkItsPidValid); + histos.fill(HIST("apTgl_bg"), antipTrkTgl); + } + } else if (mc.globalIndex() == pId) { + pTrkP = track.p(); + pTrkPx = track.px(); + pTrkPy = track.py(); + pTrkPz = track.pz(); + pTrkEta = track.eta(); + pTrkTpcSignal = track.tpcSignal(); + // p_trk_nClsTPC = track.tpcNCls(); + pTrkNClsIts = track.itsNCls(); + pTrkTgl = track.tgl(); + const auto nsigmaITSp = + itsResponse.nSigmaITS(track); + pTrkItsNSigmaPr = static_cast(nsigmaITSp); + pTrkItsPidValid = std::isfinite(nsigmaITSp) ? 1 : 0; + pHasTrack = true; + pItsMap = static_cast(track.itsClusterMap()); + pLayers = (pItsMap != 0); + if (layerCondition) + pLayers = true; + if (motherPdg == -kNeutron) { + histos.fill(HIST("pItsNsigmaPr"), pTrkItsNSigmaPr); + histos.fill(HIST("pItsPidValid"), pTrkItsPidValid); + histos.fill(HIST("pTgl"), pTrkTgl); + } + if (motherPdg != -kNeutron) { + histos.fill(HIST("pItsNsigmaPr_bg"), pTrkItsNSigmaPr); + histos.fill(HIST("pItsPidValid_bg"), pTrkItsPidValid); + histos.fill(HIST("pTgl_bg"), pTrkTgl); + } + } + } + if (!(pHasTrack && antipHasTrack)) + continue; + + TVector3 pVecProton_trk(pTrkPx, pTrkPy, pTrkPz); + TVector3 AntipVecProton_trk(antipTrkPx, antipTrkPy, antipTrkPz); + TVector3 total_trk_pVec = pVecProton_trk + AntipVecProton_trk; + double trkangleRad = AntipVecProton_trk.Angle(pVecProton_trk); + double trkangleDeg = trkangleRad * Rad2Deg; + if (motherPdg == -kNeutron) + histos.fill(HIST("cex_pairtrk_angle"), trkangleDeg); + if (motherPdg != -kNeutron) + histos.fill(HIST("cexbg_pairtrk_angle"), trkangleDeg); + + // ==== Secondary vertex via central DCA vertexer (DCAFitter2) ==== + using o2::vertexing::DCAFitter2; + constexpr float kBzTesla = 0.5f; + DCAFitter2 fitter(/*bz=*/kBzTesla, /*useAbsDCA=*/true, /*propagateToPCA=*/true); + fitter.setBz(kBzTesla); + // float bz = o2::base::Propagator::Instance()->getNominalBz(); // en kGauss + // DCAFitter2 fitter(bz, /*useAbsDCA=*/true, /*propagateToPCA=*/true); + fitter.setMaxR(45.f); // cm + fitter.setMaxDZIni(4.f); // cm + fitter.setMaxDXYIni(4.f); // cm + fitter.setMaxChi2(50.f); + fitter.setPropagateToPCA(true); + std::optional pRow, apRow; + for (const auto& tr : tracks) { + if (!tr.has_mcParticle()) + continue; + const auto& mc = tr.mcParticle(); + if (mc.globalIndex() == antipId) + apRow = tr; + if (mc.globalIndex() == pId) + pRow = tr; + if (pRow && apRow) + break; + } + if (pRow && apRow) { + // TrackParCov + auto trP = makeTPCovFromAOD(*pRow); + auto trAP = makeTPCovFromAOD(*apRow); + int nCand = fitter.process(trP, trAP); + auto status = fitter.getFitStatus(); + histos.fill(HIST("vtxfitStatus"), static_cast(status)); + if (nCand > 0 && (status == DCAFitter2::FitStatus::Converged || status == DCAFitter2::FitStatus::MaxIter)) { + // Secondary vertex (commom PCA) [x,y,z] cm + auto vtx = fitter.getPCACandidatePos(); + const double secX = vtx[0]; + const double secY = vtx[1]; + const double secZ = vtx[2]; + // DCA of the pair in the PCA (equivalent to minDCA) + fitter.propagateTracksToVertex(); + auto tp0 = fitter.getTrackParamAtPCA(0); + auto tp1 = fitter.getTrackParamAtPCA(1); + const auto p0 = tp0.getXYZGlo(); + const auto p1 = tp1.getXYZGlo(); + const double x0 = p0.X(), y0 = p0.Y(), z0 = p0.Z(); + const double x1 = p1.X(), y1 = p1.Y(), z1 = p1.Z(); + const double dcaPair = std::sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1) + (z0 - z1) * (z0 - z1)); + + if (motherPdg == -kNeutron) + histos.fill(HIST("cex_pairtrkVtxfitDcaPair"), dcaPair); + if (motherPdg != -kNeutron) + histos.fill(HIST("cexbg_pairtrkVtxfitDcaPair"), dcaPair); + + if (!(antipLayers && pLayers)) + continue; + double cexPairTrkP = total_trk_pVec.Mag(); + double cexPairTrkPt = total_trk_pVec.Pt(); + double cexPairTrkPz = pTrkPz + antipTrkPz; + const double radius = std::hypot(secX, secY); + const double dxPv = secX - pvtxX; + const double dyPv = secY - pvtxY; + const double dzPv = secZ - pvtxZ; + const double distToPrimary = std::sqrt(dxPv * dxPv + dyPv * dyPv + dzPv * dzPv); + + const TVector3 pv2sv(secX - pvtxX, secY - pvtxY, secZ - pvtxZ); + const double pairPointingAngleDeg = pv2sv.Angle(total_trk_pVec) * Rad2Deg; + + const double pP = pVecProton_trk.Mag(); + const double pAP = AntipVecProton_trk.Mag(); + const double ptP = pVecProton_trk.Pt(); + const double ptAP = AntipVecProton_trk.Pt(); + + const double denomP = std::max(1e-9, pP + pAP); + const double denomPt = std::max(1e-9, ptP + ptAP); + + const float pairPBalance = std::abs(pP - pAP) / denomP; + const float pairPtBalance = std::abs(ptP - ptAP) / denomPt; + + const float pairQ = (pVecProton_trk - AntipVecProton_trk).Mag(); + + // Trk - MC + const float dPairP = cexPairTrkP - cexPairMcP; + const float dPairPt = cexPairTrkPt - cexPairMcPt; + const float dPairPz = cexPairTrkPz - cexPairMcPz; + const float dOpenAngle = trkangleDeg - mcangleDeg; + + // Closest ITS layer: Radius need to be checked + static const std::array rLayers = {2.2, 2.8, 3.6, 19.6, 24.0, 29.0, 35.0}; + int16_t svNearestLayerId = -1; + float svDeltaRToLayer = 1e9f; + for (int i = 0; i < static_cast(rLayers.size()); ++i) { + const float dR = static_cast(std::abs(radius - rLayers[i])); + if (dR < svDeltaRToLayer) { + svDeltaRToLayer = dR; + svNearestLayerId = static_cast(i); + } + } + + if (motherPdg == -kNeutron) { + histos.fill(HIST("cexPairTrkP"), cexPairTrkP); + histos.fill(HIST("cexPairTrkPt"), cexPairTrkPt); + histos.fill(HIST("cexPairTrkPz"), cexPairTrkPz); + histos.fill(HIST("cex_pairtrkVtxfitR"), radius); + histos.fill(HIST("cex_pairtrkVtxfitDistToPv"), distToPrimary); + histos.fill(HIST("cex_pairtrk_vtxfit_secVtxXY"), secX, secY); + histos.fill(HIST("cex_pairtrk_vtxfit_secVtxZ"), secZ); + } else { + histos.fill(HIST("cexbg_pairtrk_p"), cexPairTrkP); + histos.fill(HIST("cexbg_pairtrk_pt"), cexPairTrkPt); + histos.fill(HIST("cexbg_pairtrk_pz"), cexPairTrkPz); + histos.fill(HIST("cexbg_pairtrkVtxfitR"), radius); + histos.fill(HIST("cexbg_pairtrkVtxfitDistToPv"), distToPrimary); + histos.fill(HIST("cexbg_pairtrk_vtxfit_secVtxXY"), secX, secY); + histos.fill(HIST("cexbg_pairtrk_vtxfit_secVtxZ"), secZ); + } + + const float chi2 = fitter.getChi2AtPCACandidate(); + histos.fill(HIST("vtxfitChi2"), chi2); + const double dx = secX - antipVx; + const double dy = secY - antipVy; + const double dz = secZ - antipVz; + const double d3d = std::sqrt(dx * dx + dy * dy + dz * dz); + histos.fill(HIST("vtxfit_mc_dX"), dx); + histos.fill(HIST("vtxfit_mc_dY"), dy); + histos.fill(HIST("vtxfit_mc_dZ"), dz); + histos.fill(HIST("vtxfit_mc_d3D"), d3d); + + const bool isCex = (motherPdg == -kNeutron); + + const float vtxfitDX = secX - antipVx; + const float vtxfitDY = secY - antipVy; + const float vtxfitDZ = secZ - antipVz; + const float vtxfitD3D = std::sqrt(vtxfitDX * vtxfitDX + vtxfitDY * vtxfitDY + vtxfitDZ * vtxfitDZ); + + const uint32_t selMask = 0u; + + outPairs( + isCex, + motherPdg, + colId, + pId, + antipId, + + cexPairMcP, + cexPairMcPt, + cexPairMcPz, + dplane, + mcangleDeg, + antipVx, + antipVy, + antipVz, + + cexPairTrkP, + cexPairTrkPt, + cexPairTrkPz, + trkangleDeg, + dcaPair, + radius, + distToPrimary, + secX, + secY, + secZ, + + chi2, + static_cast(status), + nCand, + vtxfitDX, + vtxfitDY, + vtxfitDZ, + vtxfitD3D, + + pTrkP, + pTrkPx, + pTrkPy, + pTrkPz, + pTrkEta, + pTrkTpcSignal, + pTrkNClsIts, + + antipTrkP, + antipTrkPx, + antipTrkPy, + antipTrkPz, + antipTrkEta, + antipTrkTpcSignal, + antipTrkNClsIts, + + selMask, + + pairPointingAngleDeg, + pairPBalance, + pairPtBalance, + pairQ, + + dPairP, + dPairPt, + dPairPz, + dOpenAngle, + + svNearestLayerId, + svDeltaRToLayer, + + pItsMap, + apItsMap, + static_cast(pLayers ? 1 : 0), + static_cast(antipLayers ? 1 : 0), + + pvtxZ, + + pTrkItsNSigmaPr, + pTrkItsPidValid, + pTrkTgl, + + antipTrkItsNSigmaPr, + antipTrkItsPidValid, + antipTrkTgl); + } + } + // ==== end DCAFitter2 ==== + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& ctx) +{ + return WorkflowSpec{adaptAnalysisTask(ctx)}; +} diff --git a/PWGLF/TableProducer/Nuspex/nucleiFlowTree.cxx b/PWGLF/TableProducer/Nuspex/nucleiFlowTree.cxx new file mode 100644 index 00000000000..43476353c4c --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/nucleiFlowTree.cxx @@ -0,0 +1,483 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFSlimNucleiTables.h" +#include "PWGLF/Utils/nucleiUtils.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/Tools/TrackTuner.h" + +#include "CCDB/BasicCCDBManager.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/Vector4D.h" +#include "TRandom3.h" + +#include +#include +#include +#include +#include + +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::kNspecies; ++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::kNspecies; ++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()); + + std::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::kNspecies; ++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]), + std::hypot(collision.qvecFT0AImVec()[cfgHarmonics - 2], collision.qvecFT0AReVec()[cfgHarmonics - 2]), + std::hypot(collision.qvecFT0CImVec()[cfgHarmonics - 2], collision.qvecFT0CReVec()[cfgHarmonics - 2]), + std::hypot(collision.qvecTPCallImVec()[cfgHarmonics - 2], collision.qvecTPCallReVec()[cfgHarmonics - 2]), + std::hypot(collision.qvecTPCnegImVec()[cfgHarmonics - 2], collision.qvecTPCnegReVec()[cfgHarmonics - 2]), + std::hypot(collision.qvecTPCposImVec()[cfgHarmonics - 2], collision.qvecTPCposReVec()[cfgHarmonics - 2])}); + } + 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(), collision.numContrib(), 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.nContrib, 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.nContrib, 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 e883d135114..90dfcee5aed 100644 --- a/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx +++ b/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx @@ -19,44 +19,48 @@ // 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 "Math/Vector4D.h" - -#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFSlimNucleiTables.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.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/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/Qvectors.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 "CCDB/BasicCCDBManager.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 "Framework/ASoAHelpers.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 +#include +#include // for PDG codes +#include -#include "TRandom3.h" +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -65,26 +69,33 @@ using namespace o2::constants::physics; struct NucleusCandidate { int globalIndex; + int collTrackIndex; float pt; float eta; float phi; float tpcInnerParam; float beta; float zVertex; + int nContrib; 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; }; @@ -95,17 +106,20 @@ 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 { +constexpr int nITSlayers = 7; constexpr double bbMomScalingDefault[5][2]{ {1., 1.}, {1., 1.}, @@ -167,6 +181,7 @@ 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 hfMothCodes{511, 521, 531, 541, 5122}; // b-mesons + Lambda_b 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"}; @@ -191,6 +206,8 @@ 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; @@ -204,6 +221,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 { @@ -223,33 +265,51 @@ struct nucleiSpectra { }; Produces nucleiTable; + Produces nucleiPairTable; Produces nucleiTableMC; Produces nucleiTableFlow; Service ccdb; Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; Configurable cfgCompensatePIDinTracking{"cfgCompensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; + struct : o2::framework::ConfigurableGroup { + std::string prefix{"cfgTrackCut"}; + Configurable> DcaMax{"DcaMax", {nuclei::DCAcutDefault[0], 5, 2, nuclei::names, nuclei::nDCAConfigName}, "Max DCAxy and DCAz for light nuclei"}; + Configurable EtaMax{"EtaMax", 0.8f, "Max Eta for tracks"}; + Configurable ITSnClusMin{"ITSnClsMin", 5, "Minimum number of ITS clusters"}; + Configurable ITSchi2ClusMax{"ITSchi2ClusMax", 36.f, "Max ITS Chi2 per cluster"}; + Configurable RapidityMax{"RapidityMax", 1.f, "Maximum rapidity for tracks"}; + Configurable RapidityMin{"RapidityMin", -1.f, "Minimum rapidity for tracks"}; + Configurable RapidityToggle{"RapidityToggle", false, "If true, use rapidity cuts"}; + Configurable TPCchi2ClusMax{"TPCchi2ClusMax", 4.f, "Max TPC Chi2 per cluster"}; + Configurable TPCnCrossedRowsMin{"TPCnCrossedRowsMin", 70, "Minimum number of TPC crossed rows"}; + Configurable TPCnCrossedRowsOverFindableMin{"TPCnCrossedRowsOverFindableMin", 0.8f, "Minimum ratio of crossed rows over findable clusters"}; + Configurable TPCnClsMin{"TPCnClsMin", 80, "Minimum number of TPC clusters"}; + Configurable TPCrigidityMin{"TPCrigidityMin", 0.5f, "Minimum TPC rigidity for tracks"}; + Configurable> TPCnSigmaMax{"TPCnSigmaMax", {nuclei::nSigmaTPCdefault[0], 5, 2, nuclei::names, nuclei::nSigmaConfigName}, "TPC nsigma selection for light nuclei"}; + + } cfgTrackCut; 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"}; + Configurable cfgFillPairTree{"cfgFillPairTree", true, "Fill trees for pairs of light nuclei"}; + Configurable cfgFillGenSecondaries{"cfgFillGenSecondaries", 0, "Fill generated secondaries (0: no, 1: only weak decays, 2: all of them)"}; 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"}; @@ -273,38 +333,29 @@ struct nucleiSpectra { Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + // 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", "EventFiltering/Zorro/", "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; + using CollWithCent = soa::Join::iterator; // Flow analysis - using CollWithEP = soa::Join::iterator; + using CollWithEP = soa::Join::iterator; - using CollWithQvec = soa::Join::iterator; + using CollWithQvec = soa::Join::iterator; HistogramRegistry spectra{"spectra", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - o2::pid::tof::Beta responseBeta; - - 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; - } double computeAbsoDecL(aod::McParticles::iterator particle) { @@ -315,7 +366,7 @@ struct nucleiSpectra { float dauVtx[3]{0.f, 0.f, 0.f}; auto daughters = particle.daughters_as(); for (const auto& dau : daughters) { - if (abs(dau.pdgCode()) != 22 && abs(dau.pdgCode()) != 11) { + if (std::abs(dau.pdgCode()) != PDG_t::kGamma && std::abs(dau.pdgCode()) != PDG_t::kElectron) { dauVtx[0] = dau.vx(); dauVtx[1] = dau.vy(); dauVtx[2] = dau.vz(); @@ -336,6 +387,59 @@ struct nucleiSpectra { 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) { if (mRunNumber == bc.runNumber()) { @@ -350,12 +454,15 @@ struct nucleiSpectra { 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(); @@ -369,6 +476,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})"}, @@ -390,6 +500,17 @@ 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)"}}); @@ -398,14 +519,15 @@ struct nucleiSpectra { 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 iC{0}; iC < 2; ++iC) { + + for (unsigned int iC{0}; iC < nuclei::matter.size(); ++iC) { nuclei::hGloTOFtracks[iC] = spectra.add(fmt::format("hTPCTOFtracks{}", nuclei::matter[iC]).data(), fmt::format("Global vs TOF matched {} tracks in a collision", nuclei::chargeLabelNames[iC]).data(), HistType::kTH2D, {{300, -0.5, 300.5, "Number of global tracks"}, {300, -0.5, 300.5, "Number of TOF matched tracks"}}); for (int iS{0}; iS < nuclei::species; ++iS) { nuclei::hNsigma[0][iS][iC] = spectra.add(fmt::format("h{}nsigma{}_{}", nuclei::pidName[0], nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("n#sigma_{{}} {} {}", nuclei::pidName[0], nuclei::matter[iC], nuclei::names[iS]).data(), HistType::kTH3D, {centAxis, ptAxes[iS], nSigmaAxes[0]}); nuclei::hNsigmaEta[0][iS][iC] = spectra.add(fmt::format("h{}nsigmaEta{}_{}", nuclei::pidName[0], nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("n#sigma_{{}} {} {} vs #eta", nuclei::pidName[0], nuclei::matter[iC], nuclei::names[iS]).data(), HistType::kTH3D, {etaAxis, ptAxes[iS], nSigmaAxes[0]}); - for (int iPID{0}; iPID < 2; ++iPID) { + for (unsigned int iPID{0}; iPID < nuclei::matter.size(); ++iPID) { nuclei::hDCAxy[iPID][iS][iC] = spectra.add(fmt::format("hDCAxy{}_{}_{}", nuclei::pidName[iPID], nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("DCAxy {} {} {}", nuclei::pidName[iPID], nuclei::matter[iC], nuclei::names[iS]).data(), HistType::kTH3D, {centAxis, ptAxes[iS], dcaxyAxes[iS]}); nuclei::hDCAz[iPID][iS][iC] = spectra.add(fmt::format("hDCAz{}_{}_{}", nuclei::pidName[iPID], nuclei::matter[iC], nuclei::names[iS]).data(), fmt::format("DCAz {} {} {}", nuclei::pidName[iPID], nuclei::matter[iC], nuclei::names[iS]).data(), HistType::kTH3D, {centAxis, ptAxes[iS], dcazAxes[iS]}); } @@ -415,31 +537,41 @@ 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}); + 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}); } - 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}); } } for (int iS{0}; iS < nuclei::species; ++iS) { - for (int iMax{0}; iMax < 2; ++iMax) { - nuclei::pidCuts[0][iS][iMax] = cfgNsigmaTPC->get(iS, iMax); + for (unsigned int iMax{0}; iMax < nuclei::pidName.size(); ++iMax) { + nuclei::pidCuts[0][iS][iMax] = cfgTrackCut.TPCnSigmaMax->get(iS, iMax); + } + } + + 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 (unsigned int iC{0}; iC < nuclei::matter.size(); ++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); } template float getCentrality(Tcoll const& collision) { float centrality = 1.; - if constexpr (std::is_same::value || 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) { @@ -460,6 +592,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()); @@ -480,16 +615,17 @@ struct nucleiSpectra { {nuclei::charges[4] * cfgMomentumScalingBetheBloch->get(3u, 0u) / nuclei::masses[4], nuclei::charges[4] * cfgMomentumScalingBetheBloch->get(3u, 1u) / nuclei::masses[4]}}; int nGloTracks[2]{0, 0}, nTOFTracks[2]{0, 0}; - for (auto& track : tracks) { // start loop over tracks - if (track.itsNCls() < cfgCutNclusITS || - track.tpcNClsFound() < cfgCutNclusTPC || - track.tpcNClsCrossedRows() < 70 || - track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || - track.tpcChi2NCl() > 4.f || - track.itsChi2NCl() > 36.f) { + for (const auto& track : tracks) { // start loop over tracks + if (std::abs(track.eta()) > cfgTrackCut.EtaMax || + track.tpcInnerParam() < cfgTrackCut.TPCrigidityMin || + track.itsNCls() < cfgTrackCut.ITSnClusMin || + track.tpcNClsFound() < cfgTrackCut.TPCnClsMin || + track.tpcNClsCrossedRows() < cfgTrackCut.TPCnCrossedRowsMin || + track.tpcNClsCrossedRows() < cfgTrackCut.TPCnCrossedRowsOverFindableMin * track.tpcNClsFindable() || + track.tpcChi2NCl() > cfgTrackCut.TPCchi2ClusMax || + track.itsChi2NCl() > cfgTrackCut.ITSchi2ClusMax) { 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(); @@ -523,11 +659,13 @@ struct nucleiSpectra { continue; } - auto trackParCov = getTrackParCov(track); // should we set the charge according to the nucleus? - gpu::gpustd::array dcaInfo; - o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParCov, mBz, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfo); + mDcaInfoCov.set(999, 999, 999, 999, 999); + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + std::array 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 @@ -535,6 +673,9 @@ struct nucleiSpectra { 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; @@ -547,44 +688,49 @@ struct nucleiSpectra { } for (int iS{0}; iS < nuclei::species; ++iS) { bool selectedTOF{false}; - if (std::abs(dcaInfo[1]) > cfgDCAcut->get(iS, 1)) { + if (std::abs(dcaInfo[1]) > cfgTrackCut.DcaMax->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 (unsigned int iPID{0}; iPID < nuclei::pidName.size(); ++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(dcaInfo[0]) < cfgDCAcut->get(iS, 0u)) { + if (!cfgTrackCut.RapidityToggle || (y > cfgTrackCut.RapidityMin && y < cfgTrackCut.RapidityMax)) { + 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]) < cfgTrackCut.DcaMax->get(iS, 0u)) { 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) { - float charge{1}; - if (iS == 3 || iS == 4) - charge = 2; - tofMasses[iS] = correctedTpcInnerParam * charge * std::sqrt(1.f / (beta * beta) - 1.f) - nuclei::masses[iS]; 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()); + 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 (std::is_same::value) { - auto deltaPhiInRange = getPhiInRange(fvector.phi() - computeEventPlane(collision.qvecFT0CIm(), collision.qvecFT0CRe())); + 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()); } @@ -609,40 +755,55 @@ struct nucleiSpectra { } } 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()}); - } else if constexpr (std::is_same::value) { + 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()), - collision.multFT0A(), computeEventPlane(collision.qvecFT0CIm(), collision.qvecFT0CRe()), - collision.multFT0C(), - -999., + computeEventPlane(collision.qvecBTotIm(), collision.qvecBTotRe()), computeEventPlane(collision.qvecBNegIm(), collision.qvecBNegRe()), computeEventPlane(collision.qvecBPosIm(), collision.qvecBPosRe()), - collision.multTPC()}); + 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(), - nSigmaTPC, tofMasses, fillTree, fillDCAHist, flag, track.tpcNClsFindable(), static_cast(track.tpcNClsCrossedRows()), track.itsClusterMap(), - static_cast(track.tpcNClsFound()), static_cast(track.itsNCls()), static_cast(track.itsClusterSizes())}); + static_cast(track.globalIndex()), static_cast(track.collisionId()), (1 - 2 * iC) * mTrackParCov.getPt(), mTrackParCov.getEta(), mTrackParCov.getPhi(), + correctedTpcInnerParam, beta, collision.posZ(), collision.numContrib(), 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 @@ -656,19 +817,26 @@ struct nucleiSpectra { if (!eventSelection(collision)) { return; } - if (cfgSkimmedProcessing) { - zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting - } 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.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.clusterSizesITS); + for (size_t i1{0}; i1 < nuclei::candidates.size(); ++i1) { + auto& c1 = nuclei::candidates[i1]; + if (c1.fillTree) { + nucleiTable(c1.pt, c1.eta, c1.phi, c1.tpcInnerParam, c1.beta, c1.zVertex, c1.nContrib, c1.DCAxy, c1.DCAz, c1.TPCsignal, c1.ITSchi2, c1.TPCchi2, c1.TOFchi2, c1.flags, c1.TPCfindableCls, c1.TPCcrossedRows, c1.ITSclsMap, c1.TPCnCls, c1.TPCnClsShared, c1.clusterSizesITS); + if (cfgFillPairTree) { + for (size_t i2{i1 + 1}; i2 < nuclei::candidates.size(); ++i2) { + auto& c2 = nuclei::candidates[i2]; + if (!c2.fillTree || ((c1.flags & c2.flags) & 0x1F) == 0) { + continue; + } + nucleiPairTable(c1.pt, c1.eta, c1.phi, c1.tpcInnerParam, c1.TPCsignal, c1.DCAxy, c1.DCAz, c1.clusterSizesITS, c1.flags, c2.pt, c2.eta, c2.phi, c2.tpcInnerParam, c2.TPCsignal, c2.DCAxy, c2.DCAz, c2.clusterSizesITS, c2.flags); + } + } } - if (c.fillDCAHist) { + if (c1.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); + if (c1.flags & BIT(iS)) { + nuclei::hDCAHists[c1.pt < 0][iS]->Fill(std::abs(c1.pt), c1.DCAxy, c1.DCAz, c1.nSigmaTPC[iS], c1.tofMasses[iS], c1.ITSnCls, c1.TPCnCls); } } } @@ -680,7 +848,7 @@ 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)) { @@ -689,7 +857,7 @@ struct nucleiSpectra { 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.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.clusterSizesITS); + nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.nContrib, 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) { @@ -699,8 +867,8 @@ struct nucleiSpectra { } } } - 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); + for (const 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, processDataFlow, "Data analysis with flow", false); @@ -709,16 +877,16 @@ struct nucleiSpectra { { nuclei::candidates.clear(); nuclei::candidates_flow.clear(); - if (!eventSelection(collision)) { + if (!eventSelectionWithHisto(collision)) { return; } if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return; } fillDataInfo(collision, tracks); - for (auto& c : nuclei::candidates) { + for (const 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.flags, c.TPCfindableCls, c.TPCcrossedRows, c.ITSclsMap, c.TPCnCls, c.clusterSizesITS); + nucleiTable(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.nContrib, 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) { @@ -728,21 +896,21 @@ struct nucleiSpectra { } } } - 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); + for (const 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) { + for (const auto& c : mcCollisions) { spectra.fill(HIST("hGenVtxZ"), c.posZ()); } std::vector goodCollisions(mcCollisions.size(), false); - for (auto& collision : collisions) { + for (const auto& collision : collisions) { if (!eventSelection(collision)) { continue; } @@ -752,7 +920,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; } @@ -764,45 +932,106 @@ struct nucleiSpectra { 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 } - if (c.fillDCAHist && cfgDCAHists->get(iS, c.pt < 0) && particle.isPhysicalPrimary()) { - 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); + auto coll = collisions.iteratorAt(c.collTrackIndex); + int collMCGlobId = coll.mcCollisionId(); + if (particle.mcCollisionId() == collMCGlobId) { + c.correctPV = true; + } + if (!c.correctPV) { + c.flags |= kIsAmbiguous; + } + 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; } + if (particle.y() < cfgTrackCut.RapidityMin || particle.y() > cfgTrackCut.RapidityMax) { + continue; + } + + int motherPdgCode = 0; + float motherDecRadius = -1; isReconstructed[particle.globalIndex()] = true; if (particle.isPhysicalPrimary()) { c.flags |= kIsPhysicalPrimary; + if (particle.has_mothers()) { + for (const auto& motherparticle : particle.mothers_as()) { + if (std::find(nuclei::hfMothCodes.begin(), nuclei::hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != nuclei::hfMothCodes.end()) { + c.flags |= kIsSecondaryFromWeakDecay; + motherPdgCode = motherparticle.pdgCode(); + motherDecRadius = std::hypot(particle.vx() - motherparticle.vx(), particle.vy() - motherparticle.vy()); + break; + } + } + } } else if (particle.has_mothers()) { c.flags |= kIsSecondaryFromWeakDecay; + for (const auto& motherparticle : particle.mothers_as()) { + motherPdgCode = motherparticle.pdgCode(); + motherDecRadius = std::hypot(particle.vx() - motherparticle.vx(), particle.vy() - motherparticle.vy()); + } } else { c.flags |= kIsSecondaryFromMaterial; } + + isReconstructed[particle.globalIndex()] = true; 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.nContrib, 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, goodCollisions[particle.mcCollisionId()], particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), motherPdgCode, motherDecRadius, absoDecL); } int index{0}; - for (auto& particle : particlesMC) { + for (const auto& particle : particlesMC) { int pdg{std::abs(particle.pdgCode())}; for (int iS{0}; iS < nuclei::species; ++iS) { if (pdg != nuclei::codes[iS]) { continue; } - uint16_t flags{kIsPhysicalPrimary}; + if (particle.y() < cfgTrackCut.RapidityMin || particle.y() > cfgTrackCut.RapidityMax) { + continue; + } + + uint16_t flags = 0; + int motherPdgCode = 0; + float motherDecRadius = -1; if (particle.isPhysicalPrimary()) { - if (particle.y() > cfgCutRapidityMin && particle.y() < cfgCutRapidityMax) { - nuclei::hGenNuclei[iS][particle.pdgCode() < 0]->Fill(1., particle.pt()); + flags |= kIsPhysicalPrimary; + nuclei::hGenNuclei[iS][particle.pdgCode() < 0]->Fill(1., particle.pt()); + // antinuclei from B hadrons are classified as physical primaries + if (particle.has_mothers()) { + for (auto& motherparticle : particle.mothers_as()) { + if (std::find(nuclei::hfMothCodes.begin(), nuclei::hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != nuclei::hfMothCodes.end()) { + flags |= kIsSecondaryFromWeakDecay; + motherPdgCode = motherparticle.pdgCode(); + motherDecRadius = std::hypot(particle.vx() - motherparticle.vx(), particle.vy() - motherparticle.vy()); + break; + } + } + } + } else if (particle.getProcess() == TMCProcess::kPDecay) { + if (!particle.has_mothers()) { + continue; // skip secondaries from weak decay without mothers + } + flags |= kIsSecondaryFromWeakDecay; + for (const auto& motherparticle : particle.mothers_as()) { + motherPdgCode = motherparticle.pdgCode(); + motherDecRadius = std::hypot(particle.vx() - motherparticle.vx(), particle.vy() - motherparticle.vy()); } } else { - continue; /// for not-reconstructed particles we store only the primaries + flags |= kIsSecondaryFromMaterial; } if (!isReconstructed[index] && (cfgTreeConfig->get(iS, 0u) || cfgTreeConfig->get(iS, 1u))) { + if ((flags & kIsPhysicalPrimary) == 0 && cfgFillGenSecondaries == 0) { + continue; // skip secondaries if not requested + } + if ((flags & (kIsPhysicalPrimary | kIsSecondaryFromWeakDecay)) == 0 && cfgFillGenSecondaries == 1) { + continue; // skip secondaries from material if not requested + } 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., -1, 999., 999., -1, -1, -1, -1, flags, 0, 0, 0, 0, 0, 0, goodCollisions[particle.mcCollisionId()], particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), motherPdgCode, motherDecRadius, absDecL); } break; } @@ -810,6 +1039,89 @@ 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()) > cfgTrackCut.EtaMax || + track.itsNCls() < nuclei::nITSlayers || + track.itsChi2NCl() > cfgTrackCut.ITSchi2ClusMax) { + 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); + + void processMCasData(soa::Join const& collisions, aod::McCollisions const& mcCollisions, soa::Join const& tracks, aod::McParticles const& particlesMC, aod::BCsWithTimestamps const&) + { + nuclei::candidates.clear(); + std::vector goodCollisions(mcCollisions.size(), false); + for (const auto& collision : collisions) { + if (!eventSelection(collision)) { + continue; + } + goodCollisions[collision.mcCollisionId()] = true; + const auto& slicedTracks = tracks.sliceBy(tracksPerCollisions, collision.globalIndex()); + fillDataInfo(collision, slicedTracks); + } + std::vector isReconstructed(particlesMC.size(), false); + for (size_t i{0}; i < nuclei::candidates.size(); ++i) { + auto& c = nuclei::candidates[i]; + if (c.fillTree) { + auto label = tracks.iteratorAt(c.globalIndex); + if (label.mcParticleId() < -1 || label.mcParticleId() >= particlesMC.size()) { + continue; + } + auto particle = particlesMC.iteratorAt(label.mcParticleId()); + int motherPdgCode = 0; + float motherDecRadius = -1; + isReconstructed[particle.globalIndex()] = true; + if (particle.isPhysicalPrimary()) { + c.flags |= kIsPhysicalPrimary; + if (particle.has_mothers()) { + for (const auto& motherparticle : particle.mothers_as()) { + if (std::find(nuclei::hfMothCodes.begin(), nuclei::hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != nuclei::hfMothCodes.end()) { + c.flags |= kIsSecondaryFromWeakDecay; + motherPdgCode = motherparticle.pdgCode(); + motherDecRadius = std::hypot(particle.vx() - motherparticle.vx(), particle.vy() - motherparticle.vy()); + break; + } + } + } + } else if (particle.has_mothers()) { + c.flags |= kIsSecondaryFromWeakDecay; + for (const auto& motherparticle : particle.mothers_as()) { + motherPdgCode = motherparticle.pdgCode(); + motherDecRadius = std::hypot(particle.vx() - motherparticle.vx(), particle.vy() - motherparticle.vy()); + } + } else { + c.flags |= kIsSecondaryFromMaterial; + } + + isReconstructed[particle.globalIndex()] = true; + float absoDecL = computeAbsoDecL(particle); + + nucleiTableMC(c.pt, c.eta, c.phi, c.tpcInnerParam, c.beta, c.zVertex, c.nContrib, 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, goodCollisions[particle.mcCollisionId()], particle.pt(), particle.eta(), particle.phi(), particle.pdgCode(), motherPdgCode, motherDecRadius, absoDecL); + } + } + } + PROCESS_SWITCH(nucleiSpectra, processMCasData, "MC as data analysis", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Nuspex/particleCompositionCorrection.cxx b/PWGLF/TableProducer/Nuspex/particleCompositionCorrection.cxx new file mode 100644 index 00000000000..8e09bd645c2 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/particleCompositionCorrection.cxx @@ -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. + +/// \file particleCompositionCorrection.cxx +/// \brief Task to generate a table of dNdEta, pt and PID dependent weigths for MC particles to reflect the measured particle abundances +/// \author Mario Krüger + +#include + +#include "Tools/ML/model.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::ml; + +struct ParticleCompositionCorrection { + // produces table of (dNdEta, pt, PID)-dependent weights for adjusting the particle composition in MC to better match the measured particle chemistry + // applying these weights in the analysis allows mitigating on event-by-event basis the corresponding biases in efficiency and contamination of unidentified particles + // weights are determined using measured pi,K,p,labda(as basis for sigma) spectra togehter with their counterpart from pythia simulations + // they are interpolated in dNdEta and pt dimension using DNNs, which then provide particle fractions in data and MC and are stored as .onnx in the CCDB + // weigths are assigned to the primary generated particle as well as its daughter particles (both from decay and material interactions) + // weights are calculated only for particles within the configured kineamatic range and only for a distinct set of mother particles (see code) + // assumes neutral particles require the same scaling as their charged counterparts (e.g. pi0 is scaled the same as pi+) + // multi-strange baryons are assigned scaling factors of the sigma, which should be better than no scaling at all + + /* + backlog: + - support collision systems beyond pp + - add QA task illustrating improved mc/data matching of DCA distributions after scaling of secondaries + - extend PCC weight table by columns with systematic variations (up/down) + */ + + Service pdg; + o2::ccdb::CcdbApi ccdbApi; + + Configurable skipAll{"skipAll", false, "run table producer in dummy mode, i.e. skip all computations and fill with 1"}; + Configurable skipSec{"skipSec", false, "dont calculate weights for secondaries"}; + Configurable skipNonPhysicalPrim{"skipNonPhysicalPrim", true, "dont calculate weights for particles that are not (originating from) physical primaries; i.e. reject (decays of) pi0 etc."}; + Configurable etaCut{"etaCut", 0.8f, "eta cut"}; + Configurable ptMinCut{"ptMinCut", 0.15f, "pt min cut"}; + Configurable ptMaxCut{"ptMaxCut", 10.f, "pt max cut"}; + Configurable enableQAHistos{"enableQAHistos", true, "enable qa histograms showing the effect of the PCC"}; + + Configurable ccdbBasePath{"ccdbBasePath", "/Users/m/makruger/", "ccdb directory contianing the particle fraction networks"}; + Configurable modelPathData{"modelPathData", "PCC/data/pp", "Path to the .onnx file containing the particle fractions in data"}; + Configurable modelPathMC{"modelPathMC", "PCC/pythia/pp", "Path to the .onnx file containing the particle fractions in MC"}; + + OnnxModel particleFractionsData; + OnnxModel particleFractionsMC; + + Produces pccTable; + void init(InitContext const& cfgc); + void process(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& particles); + + std::tuple getWeights(aod::McParticles const& particles, aod::McParticles::iterator const& particle, std::map>& storedWeights, float dNdEta); + + HistogramRegistry histos; +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} + +void ParticleCompositionCorrection::init(InitContext const&) +{ + if (skipAll) { + return; + } + if (!ccdbBasePath.value.empty()) { + ccdbApi.init("http://ccdb-test.cern.ch:8080"); + static const int64_t dummyTimeStamp = 2; + if (!ccdbApi.retrieveBlob(ccdbBasePath.value + modelPathData.value, modelPathData.value, {}, dummyTimeStamp, false, "ParticleFractions_Data.onnx") || !ccdbApi.retrieveBlob(ccdbBasePath.value + modelPathMC.value, modelPathMC.value, {}, dummyTimeStamp, false, "ParticleFractions_MC.onnx")) { + LOGP(fatal, "Could not download particle fraction networks!"); + } + } + particleFractionsData.initModel(modelPathData.value + "/ParticleFractions_Data.onnx", true); + particleFractionsMC.initModel(modelPathMC.value + "/ParticleFractions_MC.onnx", true); + + if (enableQAHistos) { + std::vector ptBinEdges = {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}; + const AxisSpec ptAxis{ptBinEdges, "#it{p}_{T} (GeV/#it{c})", "pt"}; + + histos.add("frac/data/pion", "", kTProfile, {ptAxis}); + histos.add("frac/data/kaon", "", kTProfile, {ptAxis}); + histos.add("frac/data/proton", "", kTProfile, {ptAxis}); + histos.add("frac/data/sigma", "", kTProfile, {ptAxis}); + histos.addClone("frac/data/", "frac/mc/"); + + histos.add("weight/pion", "", kTProfile, {ptAxis}); + histos.add("weight/kaon", "", kTProfile, {ptAxis}); + histos.add("weight/proton", "", kTProfile, {ptAxis}); + histos.add("weight/sigma", "", kTProfile, {ptAxis}); + + histos.add("weight/secDec", "", kTProfile, {ptAxis}); + histos.add("weight/secMat", "", kTProfile, {ptAxis}); + } +} + +std::tuple ParticleCompositionCorrection::getWeights(aod::McParticles const& particles, aod::McParticles::iterator const& particle, std::map>& storedWeights, float dNdEta) +{ + static const std::tuple noWeights = {1.f, 1.f, 1.f}; + + if (skipAll || std::abs(particle.eta()) > etaCut || particle.pt() < ptMinCut || particle.pt() > ptMaxCut) { + return noWeights; + } + + if (particle.producedByGenerator()) { + if (skipNonPhysicalPrim && !particle.isPhysicalPrimary()) { + return noWeights; + } + auto absPDGCode = std::abs(particle.pdgCode()); + // translate abs PDG code to PID variable of neural networks (0: pion, 1: kaon, 2: proton, 3: sigma) + static const std::map mapPID = { + {PDG_t::kPiPlus, 0.f}, + {PDG_t::kPi0, 0.f}, + {PDG_t::kKPlus, 1.f}, + {PDG_t::kK0Short, 1.f}, + {PDG_t::kK0Long, 1.f}, + {PDG_t::kProton, 2.f}, + {PDG_t::kNeutron, 2.f}, + {PDG_t::kSigmaPlus, 3.f}, + {PDG_t::kSigmaMinus, 3.f}, + {PDG_t::kLambda0, 3.f}, + {PDG_t::kSigma0, 3.f}, + {PDG_t::kXiMinus, 3.f}, + // TODO: potentially extend by xi0/eta/omega/rho/phi/Delta... + // pdg codes defined in AliceO2/Common/Constants/include/CommonConstants/PhysicsConstants.h + // e.g. o2::constants::physics::Pdg::kEta + }; + + if (auto iterMapPID = mapPID.find(absPDGCode); iterMapPID != mapPID.end()) { + // LOGP(info, "scaling a {} with status code {} from process {}", particle.pdgCode(), particle.getGenStatusCode(), particle.getProcess()); + float pt = particle.pt(); + + // calculate particle fractions and corresponding weight for given reference particle + std::vector> input = {{dNdEta}, {pt}, {iterMapPID->second}}; + float fracData = particleFractionsData.evalModel(input)[0]; + float fracMC = particleFractionsMC.evalModel(input)[0]; + float weight = (fracMC) ? fracData / fracMC : 1.f; + std::tuple weights = {weight, weight, weight}; + if (!skipSec && particle.has_daughters()) { + storedWeights[particle.index()] = weights; + } + if (enableQAHistos && particle.isPhysicalPrimary() && std::abs(particle.eta()) < 0.8) { // o2-linter: disable=magic-number (usual range of charged-partilce measurements) + if (iterMapPID->first == PDG_t::kPiPlus) { + histos.fill(HIST("frac/data/pion"), pt, fracData); + histos.fill(HIST("frac/mc/pion"), pt, fracMC); + histos.fill(HIST("weight/pion"), pt, weight); + } + if (iterMapPID->first == PDG_t::kKPlus) { + histos.fill(HIST("frac/data/kaon"), pt, fracData); + histos.fill(HIST("frac/mc/kaon"), pt, fracMC); + histos.fill(HIST("weight/kaon"), pt, weight); + } + if (iterMapPID->first == PDG_t::kProton) { + histos.fill(HIST("frac/data/proton"), pt, fracData); + histos.fill(HIST("frac/mc/proton"), pt, fracMC); + histos.fill(HIST("weight/proton"), pt, weight); + } + if (iterMapPID->first == PDG_t::kSigmaPlus || iterMapPID->first == PDG_t::kSigmaMinus) { + histos.fill(HIST("frac/data/sigma"), pt, fracData); + histos.fill(HIST("frac/mc/sigma"), pt, fracMC); + histos.fill(HIST("weight/sigma"), pt, weight); + } + } + return weights; + } + } else if (!skipSec) { + auto refParticleID = particle.index(); + // LOGP(error, "Particle [{}] {} from process {}", refParticleID, particle.pdgCode(), particle.getProcess()); + while (!particles.iteratorAt(refParticleID).producedByGenerator() && particles.iteratorAt(refParticleID).has_mothers()) { + auto motherID = particles.iteratorAt(refParticleID).mothersIds()[0] - particles.offset(); + // LOGP(error, "-> mom [{}] {} from process {}", motherID, particles.iteratorAt(motherID).pdgCode(), particles.iteratorAt(motherID).getProcess()); + refParticleID = motherID; + } + + if (storedWeights.find(refParticleID) == storedWeights.end()) { + // LOGP(error, " no ref particle stored for particle {} from process {}!!", particle.pdgCode(), particle.getProcess()); + return noWeights; + } + + if (enableQAHistos) { + float weight = get<0>(storedWeights.at(refParticleID)); + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle && pdgParticle->Charge() != 0.) { + if (particle.getProcess() == TMCProcess::kPDecay) { + histos.fill(HIST("weight/secDec"), particle.pt(), weight); + } else if (particle.getProcess() == TMCProcess::kPHInhelastic || particle.getProcess() == TMCProcess::kPHadronic || particle.getProcess() == TMCProcess::kPHElastic) { + histos.fill(HIST("weight/secMat"), particle.pt(), weight); + } + } + } + return storedWeights.at(refParticleID); + } + return noWeights; +} + +void ParticleCompositionCorrection::process(aod::McCollisions::iterator const&, aod::McParticles const& particles) +{ + // determine dNdEta of the collision + float dNdEta = 0.f; + for (const auto& particle : particles) { + if (!particle.isPhysicalPrimary()) { + continue; + } + auto pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0.) { + continue; + } + if (std::abs(particle.eta()) >= 0.5) { // o2-linter: disable=magic-number (particle density at mid-rapidity) + continue; + } + ++dNdEta; + } + + std::map> storedWeights; + for (const auto& particle : particles) { + auto [weight, weightSysUp, weightSysDown] = getWeights(particles, particle, storedWeights, dNdEta); + pccTable(weight, weightSysUp, weightSysDown); + } +} diff --git a/PWGLF/TableProducer/Nuspex/pidTOFGeneric.cxx b/PWGLF/TableProducer/Nuspex/pidTOFGeneric.cxx new file mode 100644 index 00000000000..7c085599976 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/pidTOFGeneric.cxx @@ -0,0 +1,353 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 pidTOFMerged.cxx +/// \brief Task to produce event Time obtained from TOF and FT0. +/// In order to redo TOF PID for secondary tracks which are linked to wrong collisions +/// \author Yuanzhe Wang +/// + +#include +#include +#include + +// O2 includes +#include "CCDB/BasicCCDBManager.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include "TOFBase/EventTimeMaker.h" + +// O2Physics includes +#include "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "PWGLF/Utils/pidTOFGeneric.h" + +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "PID/PIDTOF.h" +#include "PID/ParamBase.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::pid; +using namespace o2::framework::expressions; +using namespace o2::track; + +o2::common::core::MetadataHelper metadataInfo; + +/// 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, + bool isFast = false) +{ + return o2::tof::evTimeMakerFromParam(tracks, responseParameters, diamond, isFast); +} + +/// Task to produce the event time tables for generic TOF PID +/// Modified based on pidTOFMerge.cxx +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 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 enableTable = false; + + Configurable fastTOFPID{"fastTOFPID", false, "Flag to enable computeEvTimeFast for evTimeMaker"}; + // 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"}; + + // TOF response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + Service ccdb; + o2::aod::pidtofgeneric::TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + void init(o2::framework::InitContext& initContext) + { + mTOFCalibConfig.metadataInfo = metadataInfo; + mTOFCalibConfig.inheritFromBaseTask(initContext); + // 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; //TODO: uncomment this line + } + enableTable = true; // Force enabling the table for now + LOG(info) << "Table EvTimeTOFFT0 enabled!"; + + if (mTOFCalibConfig.autoSetProcessFunctions()) { + LOG(info) << "Autodetecting process functions"; + if (metadataInfo.isFullyDefined()) { + if (metadataInfo.isRun3()) { + doprocessRun3.value = true; + } + } + } + + if (metadataInfo.isFullyDefined()) { + if (!metadataInfo.isRun3()) { + LOG(fatal) << "Run3 process not supported in pidTOFGeneric task"; + } + } + + 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(); + } + + void process(aod::BCs const&) {} + + /// + /// Process function to prepare the event for each track on Run 3 data without the FT0 + // Define slice per collision + using Run3Cols = aod::Collisions; + using EvTimeCollisions = soa::Join; + using EvTimeCollisionsFT0 = soa::Join; + using Run3Trks = o2::soa::Join; + using Run3TrksWtof = soa::Join; + Preslice perCollision = aod::track::collisionId; + template + using ResponseImplementationEvTime = o2::pid::tof::ExpTimes; + + void processRun3(Run3TrksWtof const& tracks, + aod::FT0s const&, + EvTimeCollisionsFT0 const& collisions, + aod::BCsWithTimestamps const& bcs) + { + if (!enableTable) { + return; + } + LOG(debug) << "Processing Run3 data for TOF event time"; + + tableEvTime.reserve(collisions.size()); + tableEvTimeForTrack.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 + tableEvTimeForTrack(0.f, 999.f); + 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, fastTOFPID); + + 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 + + int nGoodTracksForTOF = 0; + float eventTime = 0.f; + float sumOfWeights = 0.f; + float weight = 0.f; + + if (t0TOF[1] < kErrDiamond && (maxEvTimeTOF <= 0 || std::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; + } + + tableEvTime(eventTime / sumOfWeights, std::sqrt(1. / sumOfWeights), t0TOF[0], t0TOF[1], t0AC[0], t0AC[1]); + + for (auto const& trk : tracksInCollision) { // Loop on Tracks + // 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)) { + 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 < kWeightDiamond) { // avoiding sumOfWeights = 0 or worse that kDiamond + eventTime = 0; + sumOfWeights = kWeightDiamond; + } + tableEvTimeForTrack(eventTime / sumOfWeights, std::sqrt(1. / sumOfWeights)); + } + } + } 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 + tableEvTimeForTrack(0.f, 999.f); + 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, fastTOFPID); + int nGoodTracksForTOF = 0; + float et = evTimeMakerTOF.mEventTime; + float erret = evTimeMakerTOF.mEventTimeError; + + if (erret < kErrDiamond && (maxEvTimeTOF <= 0.f || std::abs(et) < maxEvTimeTOF)) { + } else { + et = 0.f; + erret = kErrDiamond; + } + tableEvTime(et, erret, et, erret, 0.f, 999.f); + + for (auto const& trk : tracksInCollision) { // Loop on Tracks + if constexpr (kRemoveTOFEvTimeBias) { + evTimeMakerTOF.removeBias(trk, nGoodTracksForTOF, et, erret, 2); + } + if (erret < kErrDiamond && (maxEvTimeTOF <= 0.f || std::abs(et) < maxEvTimeTOF)) { + } else { + et = 0.f; + erret = kErrDiamond; + } + tableEvTimeForTrack(et, erret); + } + } + } else if (mComputeEvTimeWithTOF == 0 && mComputeEvTimeWithFT0 == 1) { + for (const 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 < tracksInCollision.size(); i++) { + tableEvTimeForTrack(collision.t0AC() * 1000.f, collision.t0resolution() * 1000.f); + } + continue; + } + } + 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); + } + } + } else { + LOG(fatal) << "Invalid configuration for TOF event time computation"; + } + } + PROCESS_SWITCH(pidTOFGeneric, processRun3, "Process the Run3 data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(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..8e13e91a04e --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/reduced3bodyCreator.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. + +/// \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 "TableHelper.h" + +#include "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "PWGLF/DataModel/Reduced3BodyTables.h" +#include "PWGLF/Utils/pidTOFGeneric.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +#ifndef HomogeneousField +#define HomogeneousField +#endif + +// includes KFParticle +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticle.h" +#include "KFParticleBase.h" +#include "KFVertex.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +o2::common::core::MetadataHelper metadataInfo; + +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; + + Service ccdb; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + o2::vertexing::DCAFitterN<3> fitter3body; + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; + + Configurable disableITSROFCut{"disableITSROFCut", false, "Disable ITS ROF border 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 mBz; + // TOF response and input parameters + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + o2::aod::pidtofgeneric::TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + // tracked cluster size + std::vector fTrackedClSizeVector; + + HistogramRegistry registry{"registry", {}}; + + void init(InitContext& initContext) + { + mRunNumber = 0; + zorroSummary.setObject(zorro.getZorroSummary()); + bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // TOF PID parameters initialization + mTOFCalibConfig.metadataInfo = metadataInfo; + mTOFCalibConfig.inheritFromBaseTask(initContext); + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); + + 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, {{3, 0.0f, 3.0f}}); + hEventCounter->GetXaxis()->SetBinLabel(1, "all"); + hEventCounter->GetXaxis()->SetBinLabel(2, "selected"); + hEventCounter->GetXaxis()->SetBinLabel(3, "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(); + ccdb->clearCache(grpmagPath); + o2::parameters::GRPMagField* grpmag = ccdb->getSpecific(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 + // 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"; +// Set magnetic field for KF vertexing +#ifdef HomogeneousField + KFParticle::SetField(mBz); +#endif + + fitter3body.setBz(mBz); + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bc); + } + + //------------------------------------------------------------------ + // 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 + bool 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 false; + } + LOG(debug) << "Hypertriton vertex constructed."; + return true; + } + + void process(ColwithEvTimesMultsCents const& collisions, TrackExtPIDIUwithEvTimes const&, aod::Decay3Bodys const& decay3bodys, aod::Tracked3Bodys const& tracked3bodys, aod::BCsWithTimestamps const&) + { + std::vector isTriggeredCollision(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 + } + + // all events + registry.fill(HIST("hEventCounter"), 0.5); + + // ITS ROF boarder cut if not disabled + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && !disableITSROFCut) { + continue; + } + + // Zorro event counting + bool isZorroSelected = false; + if (cfgSkimmedProcessing) { + isZorroSelected = zorro.isSelected(bc.globalBC()); + if (isZorroSelected) { + registry.fill(HIST("hEventCounterZorro"), 0.5); + isTriggeredCollision[collision.globalIndex()] = true; + } + } + + // event selection + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { + continue; + } + + // selected events + registry.fill(HIST("hEventCounter"), 1.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. + + // get tracked cluster size info + fTrackedClSizeVector.clear(); + fTrackedClSizeVector.resize(decay3bodys.size(), 0); + for (const auto& tvtx3body : tracked3bodys) { + fTrackedClSizeVector[tvtx3body.decay3BodyId()] = tvtx3body.itsClsSize(); + } + + // Create reduced table + for (const auto& d3body : decay3bodys) { + + auto collision = d3body.template collision_as(); + + // event selection + if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && !disableITSROFCut) { // ITS ROF boarder cut if not disabled + continue; + } + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || (collision.posZ() >= 10.0f || collision.posZ() <= -10.0f)) { + continue; + } + + auto bc = collision.bc_as(); + initCCDB(bc); + if (cfgSkimmedProcessing && cfgOnlyKeepInterestedTrigger && !isTriggeredCollision[collision.globalIndex()]) { + 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(mRespParamsV3, 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); + + // -------- get decay3body info with KF -------- + // 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 and caclulate radius, phi, z position + float radius, phi, posZ; + KFParticle KFHt; + if (fit3bodyVertex(kfpProton, kfpPion, kfpDeuteron, KFHt)) { + radius = std::hypot(KFHt.GetX(), KFHt.GetY()); + phi = std::atan2(KFHt.GetPx(), KFHt.GetPy()); + posZ = KFHt.GetZ(); + } else { + radius = -999.; + phi = -999.; + posZ = -999.; + } + + // -------- get decay3body info with DCA fitter -------- + auto Track0 = getTrackParCov(daughter0); + auto Track1 = getTrackParCov(daughter1); + auto Track2 = getTrackParCov(daughter2); + int n3bodyVtx = fitter3body.process(Track0, Track1, Track2); + float phiVtx, rVtx, zVtx; + if (n3bodyVtx == 0) { // discard this pair + phiVtx = -999.; + rVtx = -999.; + zVtx = -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]}; + phiVtx = std::atan2(p3B[1], p3B[0]); + rVtx = std::hypot(vtxXYZ[0], vtxXYZ[1]); + zVtx = vtxXYZ[2]; + } + + // fill 3body info table (KF and DCA fitter info) + reduced3BodyInfo(radius, phi, posZ, rVtx, phiVtx, zVtx, fTrackedClSizeVector[d3body.globalIndex()]); + } // end decay3body loop + + registry.fill(HIST("hEventCounter"), 2.5, reducedCollisions.lastIndex() + 1); + } +}; + +struct reduced3bodyInitializer { + Spawns reducedTracksIU; + void init(InitContext const&) {} +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/TableProducer/Nuspex/spectraDerivedMaker.cxx b/PWGLF/TableProducer/Nuspex/spectraDerivedMaker.cxx index c96b8b1fbb6..f1e24f4573e 100644 --- a/PWGLF/TableProducer/Nuspex/spectraDerivedMaker.cxx +++ b/PWGLF/TableProducer/Nuspex/spectraDerivedMaker.cxx @@ -18,20 +18,23 @@ /// // O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/spectraTOF.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" #include "Framework/StaticFor.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "PWGLF/DataModel/spectraTOF.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" #include "TPDGCode.h" @@ -178,7 +181,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 +238,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 +391,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/threebodyRecoTask.cxx b/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx deleted file mode 100644 index 337d87223ad..00000000000 --- a/PWGLF/TableProducer/Nuspex/threebodyRecoTask.cxx +++ /dev/null @@ -1,668 +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. -// -// StoredVtx3BodyDatas analysis task -// ======================== - -#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/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; - -struct Candidate3body { - 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]; - bool isMatter; - float invmass; - float ct; - float cosPA; - float dcadaughters; - float dcacandtopv; - float bachelortofNsigma; - TLorentzVector lgencand = {0, 0, 0, 0}; - float genct = -1; - bool isSignal = false; - bool isReco = false; - int pdgCode = -1; - bool SurvivedEventSelection = false; -}; - -struct threebodyRecoTask { - - Produces outputDataTable; - Produces outputMCTable; - std::vector Candidates3body; - std::vector filledMothers; - std::vector isGoodCollision; - - // 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 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 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"}; - - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, - {"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"}}}}, - {"hProtonTPCVsPt", "hProtonTPCVsPt", {HistType::kTH2F, {{50, 0.0f, 5.0f, "#it{p}_{T} (GeV/c)"}, {240, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hPionTPCVsPt", "hPionTPCVsPt", {HistType::kTH2F, {{20, 0.0f, 2.0f, "#it{p}_{T} (GeV/c)"}, {240, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"hDeuteronTPCVsPt", "hDeuteronTPCVsPt", {HistType::kTH2F, {{80, 0.0f, 8.0f, "#it{p}_{T} (GeV/c)"}, {240, -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"}}}}, - - {"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, - kCandDauEta, - kCandRapidity, - kCandct, - kCandDcaDau, - kCandTOFPID, - kCandTPCPID, - kCandTPCNcls, - kCandDauPt, - kCandDcaToPV, - kCandInvMass, - kNCandSteps }; - - struct { - std::array candstats; - std::array truecandstats; - } statisticsRegistry; - - void resetHistos() - { - for (Int_t ii = 0; ii < kNCandSteps; ii++) { - statisticsRegistry.candstats[ii] = 0; - statisticsRegistry.truecandstats[ii] = 0; - } - } - void FillCandCounter(int kn, bool istrue = false) - { - statisticsRegistry.candstats[kn]++; - if (istrue) { - statisticsRegistry.truecandstats[kn]++; - } - } - void fillHistos() - { - for (Int_t ii = 0; ii < kNCandSteps; ii++) { - registry.fill(HIST("hCandidatesCounter"), ii, statisticsRegistry.candstats[ii]); - 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}, ""}; - - 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"}; - 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("hGeneratedHypertritonCounter"))->GetXaxis()->SetBinLabel(1, "Total"); - registry.get(HIST("hGeneratedHypertritonCounter"))->GetXaxis()->SetBinLabel(2, "3-body decay"); - } - - //------------------------------------------------------------------ - Preslice perCollisionVtx3BodyDatas = o2::aod::vtx3body::collisionId; - //------------------------------------------------------------------ - template - bool is3bodyDecayed(TMCParticle const& particle) - { - if (std::abs(particle.pdgCode()) != motherPdgCode) { - return false; - } - 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) - 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; - } - if (haveProton && haveAntiPion && haveBachelor && particle.pdgCode() > 0) { - return true; - } else if (haveAntiProton && havePion && haveAntiBachelor && particle.pdgCode() < 0) { - return true; - } - return false; - } - - //------------------------------------------------------------------ - // 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) - { - - 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(), candData.tofNSigmaBachDe()); - if (isTrueCand) { - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - } - if ((candData.tofNSigmaBachDe() < TofPidNsigmaMin || candData.tofNSigmaBachDe() > TofPidNsigmaMax) && trackDeuteron.p() > minDeuteronPUseTOF) { - return; - } - FillCandCounter(kCandTOFPID, isTrueCand); - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - if (isTrueCand) { - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - } - - if (TMath::Abs(trackProton.tpcNSigmaPr()) > TpcPidNsigmaCut || TMath::Abs(trackPion.tpcNSigmaPi()) > TpcPidNsigmaCut || TMath::Abs(trackDeuteron.tpcNSigmaDe()) > TpcPidNsigmaCut) { - return; - } - FillCandCounter(kCandTPCPID, isTrueCand); - - if (trackProton.tpcNClsFound() < mintpcNClsproton || trackPion.tpcNClsFound() < mintpcNClspion || trackDeuteron.tpcNClsFound() < mintpcNClsdeuteron) { - return; - } - FillCandCounter(kCandTPCNcls, isTrueCand); - - if (trackProton.pt() < minProtonPt || trackProton.pt() > maxProtonPt || trackPion.pt() < minPionPt || trackPion.pt() > maxPionPt || trackDeuteron.pt() < minDeuteronPt || trackDeuteron.pt() > maxDeuteronPt) { - return; - } - FillCandCounter(kCandDauPt, isTrueCand); - - double dcapion = (track2.sign() > 0) ? candData.dcatrack1topv() : candData.dcatrack0topv(); - if (TMath::Abs(dcapion) < dcapiontopv) { - return; - } - FillCandCounter(kCandDcaToPV, isTrueCand); - - // 3sigma region for Dalitz plot - double lowersignallimit = o2::constants::physics::MassHyperTriton - 3 * mcsigma; - double uppersignallimit = o2::constants::physics::MassHyperTriton + 3 * mcsigma; - - 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.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; - 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.invmass = cand3body.isMatter ? candData.mHypertriton() : candData.mAntiHypertriton(); - cand3body.posSV[0] = candData.x(); - cand3body.posSV[1] = candData.y(); - cand3body.posSV[2] = candData.z(); - 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.dautpcNsigma[0] = trackProton.tpcNSigmaPr(); - cand3body.dautpcNsigma[1] = trackPion.tpcNSigmaPi(); - cand3body.dautpcNsigma[2] = trackDeuteron.tpcNSigmaDe(); - 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 = candData.tofNSigmaBachDe(); - if (isTrueCand) { - cand3body.mcmotherId = lLabel; - cand3body.lgencand = lmother; - cand3body.genct = MClifetime; - cand3body.isSignal = true; - cand3body.isReco = true; - cand3body.pdgCode = cand3body.isMatter ? motherPdgCode : -motherPdgCode; - cand3body.SurvivedEventSelection = true; - filledMothers.push_back(lLabel); - } - - 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"), candData.tofNSigmaBachDe()); - } - - //------------------------------------------------------------------ - // collect information for generated hypertriton (should be called after event selection) - void GetGeneratedH3LInfo(aod::McParticles const& particlesMC) - { - for (auto& mcparticle : particlesMC) { - if (mcparticle.pdgCode() != motherPdgCode && 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) - haveProton = true; - if (mcparticleDaughter.pdgCode() == -2212) - haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == 211) - havePionPlus = true; - if (mcparticleDaughter.pdgCode() == -211) - 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(); - } - 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() == 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() == -motherPdgCode) { - registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); - registry.fill(HIST("hPtGeneratedAntiHypertriton"), mcparticle.pt()); - registry.fill(HIST("hctGeneratedAntiHypertriton"), MClifetime); - registry.fill(HIST("hEtaGeneratedAntiHypertriton"), mcparticle.eta()); - registry.fill(HIST("hRapidityGeneratedAntiHypertriton"), mcparticle.y()); - } - } - } - - //------------------------------------------------------------------ - // process real data analysis - void processData(soa::Join::iterator const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const& /*tracks*/) - { - 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); - - bool if_hasvtx = false; - - for (auto& vtx : vtx3bodydatas) { - CandidateAnalysis(collision, vtx, if_hasvtx); - } - - if (if_hasvtx) - registry.fill(HIST("hEventCounter"), 3.5); - fillHistos(); - resetHistos(); - - 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]); - } - } - PROCESS_SWITCH(threebodyRecoTask, processData, "Real data reconstruction", true); - - //------------------------------------------------------------------ - // 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); - isGoodCollision.resize(mcCollisions.size(), false); - - for (const auto& collision : collisions) { - registry.fill(HIST("hEventCounter"), 0.5); - if (event_sel8_selection && !collision.sel8()) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm - continue; - } - registry.fill(HIST("hEventCounter"), 2.5); - if (collision.mcCollisionId() >= 0) { - isGoodCollision[collision.mcCollisionId()] = true; - } - - bool if_hasvtx = false; - auto vtxsthiscol = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); - - for (auto& vtx : vtxsthiscol) { - int lLabel = -1; - int lPDG = -1; - double MClifetime = -1; - TLorentzVector lmother; - bool isTrueCand = false; - auto track0 = vtx.track0_as(); - auto track1 = vtx.track1_as(); - auto track2 = vtx.track2_as(); - if (track0.has_mcParticle() && track1.has_mcParticle() && track2.has_mcParticle()) { - auto lMCTrack0 = track0.mcParticle_as(); - 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()) { - 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)) { - isTrueCand = true; - 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); - } - } - } - } - } - } - } - - CandidateAnalysis(collision, vtx, if_hasvtx, isTrueCand, lLabel, lmother, MClifetime); - } - - if (if_hasvtx) - registry.fill(HIST("hEventCounter"), 3.5); - fillHistos(); - resetHistos(); - - for (auto& cand3body : Candidates3body) { - outputMCTable(collision.centFT0C(), collision.posX(), collision.posY(), collision.posZ(), // centV0M() instead of 0. once available - 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], - cand3body.lgencand.P(), cand3body.lgencand.Pt(), cand3body.genct, cand3body.lgencand.Phi(), cand3body.lgencand.Eta(), - cand3body.isSignal, cand3body.isReco, cand3body.pdgCode, cand3body.SurvivedEventSelection); - } - } - - // now we fill only the signal candidates that were not reconstructed - for (auto& mcparticle : particlesMC) { - if (!is3bodyDecayed(mcparticle)) { - continue; - } - if (std::find(filledMothers.begin(), filledMothers.end(), mcparticle.globalIndex()) != std::end(filledMothers)) { - continue; - } - bool isSurEvSelection = isGoodCollision[mcparticle.mcCollisionId()]; - std::array posSV{0.f}; - for (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, - -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, - mcparticle.p(), mcparticle.pt(), MClifetime, mcparticle.phi(), mcparticle.eta(), - true, false, mcparticle.pdgCode(), isSurEvSelection); - } - } - PROCESS_SWITCH(threebodyRecoTask, processMC, "MC reconstruction", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/TableProducer/Nuspex/threebodymcfinder.cxx b/PWGLF/TableProducer/Nuspex/threebodymcfinder.cxx index 875128758b8..ab13c4e55eb 100644 --- a/PWGLF/TableProducer/Nuspex/threebodymcfinder.cxx +++ b/PWGLF/TableProducer/Nuspex/threebodymcfinder.cxx @@ -25,36 +25,37 @@ // david.dobrigkeit.chinellato@cern.ch // -#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 "PWGLF/DataModel/LFStrangenessTables.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/McCollisionExtra.h" -#include "Common/DataModel/PIDResponse.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 "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" + #include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include #include -#include #include #include -#include -#include +#include #include -#include -#include +#include + #include +#include #include using namespace o2; diff --git a/PWGLF/TableProducer/Nuspex/trHeAnalysis.cxx b/PWGLF/TableProducer/Nuspex/trHeAnalysis.cxx new file mode 100644 index 00000000000..c1363bf8d20 --- /dev/null +++ b/PWGLF/TableProducer/Nuspex/trHeAnalysis.cxx @@ -0,0 +1,766 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFNucleiTables.h" +#include "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/Utils/pidTOFGeneric.h" + +#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/PIDResponseTOF.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 "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include + +#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); +DECLARE_SOA_COLUMN(THasTof, tHasTof, bool); +DECLARE_SOA_COLUMN(TDetectorMap, tDetectorMap, int8_t); +} // 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, h3_data::THasTof, h3_data::TDetectorMap); +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); +DECLARE_SOA_COLUMN(THasTof, tHasTof, bool); +DECLARE_SOA_COLUMN(TDetectorMap, tDetectorMap, int8_t); +} // 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, he_data::THasTof, he_data::TDetectorMap); +} // 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 particleChargeFactor{2.3, 2.55}; +static const std::vector betheBlochParNames{ + "p0", "p1", "p2", "p3", "p4", "resolution"}; +constexpr float BetheBlochDefault[nParticles][nBetheParams]{ + {0.248753, 3.58634, 0.0167065, 2.29194, 0.774344, + 0.07}, // triton + {0.0274556, 18.3054, 3.99987e-05, 3.17219, 11.1775, + 0.07}}; // 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; + float chargeFactor; + std::vector betheParams; + static constexpr int NNumBetheParams = 5; + + Particle(const std::string name_, int pdgCode_, float mass_, int charge_, + LabeledArray bethe, float chargeFactor_) + { + name = TString(name_); + pdgCode = pdgCode_; + mass = mass_; + charge = charge_; + chargeFactor = chargeFactor_; + + resolution = + bethe.get(name, "resolution"); // Access the "resolution" parameter + + betheParams.clear(); + for (int i = 0; i < NNumBetheParams; ++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."}; + Configurable cfgRigidityCorrection{"cfgRigidityCorrection", true, "Enable Rigidity correction"}; + 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 + Configurable cfgMassMethod{"cfgMassMethod", 0, "0: Using built in 1: mass calculated with beta 2: mass calculated with the event time"}; + Configurable cfgEnableItsClusterSizeCut{"cfgEnableItsClusterSizeCut", false, "Enable ITS cluster size cut"}; + Configurable cfgEnableTofMassCut{"cfgEnableTofMassCut", false, "Enable TOF mass cut"}; + Configurable cfgTofMassCutPt{"cfgTofMassCutPt", 1.6f, "Pt value for which the TOF-cut starts to be used"}; + // 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", 5.f, "Minimum Tof mass H3"}; + Configurable cfgCutMaxTofMassH3{"cfgCutMaxTofMassH3", 11.f, "Maximum TOF mass H3"}; + Configurable cfgMaxRigidity{"cfgMaxRigidity", 10.f, "Maximum rigidity value"}; + Configurable cfgMaxPt{"cfgMaxPt", 10.f, "Maximum pT value"}; + + // Set the kinematic and PID cuts for tracks + struct : ConfigurableGroup { + Configurable pCut{"pCut", 0.6f, "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, particleChargeFactor.at(i))); + } + } + 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.p()) < 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.pt() > cfgMaxPt || getRigidity(track) > cfgMaxRigidity) { + 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"), + getRigidity(track) * track.sign(), + track.tpcSignal()); + histos.fill(HIST("histogram/TOFbetaVsP"), + getRigidity(track) * 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 (cfgEnableItsClusterSizeCut) { + if (getMeanItsClsSize(track) / std::cosh(track.eta()) <= cfgCutMinItsClusterSizeHe || + getMeanItsClsSize(track) / std::cosh(track.eta()) >= cfgCutMaxItsClusterSizeHe) { + histos.fill(HIST("histogram/cuts"), 12); + continue; + } + } + if (cfgEnableTofMassCut && track.pt() > cfgTofMassCutPt) { + if (getMass(track) < cfgCutMinTofMassH3 || getMass(track) > cfgCutMaxTofMassH3) { + histos.fill(HIST("histogram/cuts"), 13); + continue; + } + } + histos.fill(HIST("histogram/H3/H3-TPCsignVsTPCmomentum"), + getRigidity(track) * track.sign(), + track.tpcSignal()); + histos.fill(HIST("histogram/H3/H3-TOFbetaVsP"), + getRigidity(track) * 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 = getTPCnSigma(track, particles.at(0)); + float tTofSignalH3 = getMass(track); + 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 = getRigidity(track); + float tItsClusterSize = + getMeanItsClsSize(track) / std::cosh(track.eta()); + bool tHasTof = track.hasTOF(); + int8_t tDetectorMap = track.detectorMap(); + h3Data(tPt, tEta, tPhi, tCharge, tH3DeDx, tnSigmaTpc, tTofSignalH3, + tDcaXY, tDcaZ, tSigmaYX, tSigmaXYZ, tSigmaZ, tnTpcCluster, + tnItsCluster, tTpcChi2NCl, tItsChi2NCl, tRigidity, + tItsClusterSize, tHasTof, tDetectorMap); + } + } + 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 (cfgEnableItsClusterSizeCut) { + 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"), + getRigidity(track) * track.sign(), + track.tpcSignal()); + histos.fill(HIST("histogram/He/He-TOFbetaVsP"), + getRigidity(track) * 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 = getTPCnSigma(track, particles.at(1)); + float tTofSignalHe = getMass(track); + 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 = getRigidity(track); + float tItsClusterSize = + getMeanItsClsSize(track) / std::cosh(track.eta()); + bool tHasTof = track.hasTOF(); + int8_t tDetectorMap = track.detectorMap(); + heData(tPt, tEta, tPhi, tCharge, tHeDeDx, tnSigmaTpc, tTofSignalHe, + tDcaXY, tDcaZ, tSigmaYX, tSigmaXYZ, tSigmaZ, tnTpcCluster, + tnItsCluster, tTpcChi2NCl, tItsChi2NCl, tRigidity, + tItsClusterSize, tHasTof, tDetectorMap); + } + } + } + } + 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.p()) < 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.pt() > cfgMaxPt || getRigidity(track) > cfgMaxRigidity) { + 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"), + getRigidity(track) * (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 (cfgEnableItsClusterSizeCut) { + if (getMeanItsClsSize(track) / std::cosh(track.eta()) <= cfgCutMinItsClusterSizeH3 || + getMeanItsClsSize(track) / std::cosh(track.eta()) >= cfgCutMaxItsClusterSizeH3) { + histos.fill(HIST("histogram/cuts"), 12); + continue; + } + } + if (cfgEnableTofMassCut && track.pt() > cfgTofMassCutPt) { + if (getMass(track) < cfgCutMinTofMassH3 || getMass(track) > cfgCutMaxTofMassH3) { + histos.fill(HIST("histogram/cuts"), 13); + continue; + } + } + histos.fill(HIST("histogram/H3/H3-TPCsignVsTPCmomentum"), + getRigidity(track) * (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 = getMass(track); + 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 = getRigidity(track); + float tItsClusterSize = + getMeanItsClsSize(track) / std::cosh(track.eta()); + bool tHasTof = track.hasTOF(); + int8_t tDetectorMap = track.detectorMap(); + h3Data(tPt, tEta, tPhi, tCharge, tH3DeDx, tnSigmaTpc, tTofSignalH3, + tDcaXY, tDcaZ, tSigmaYX, tSigmaXYZ, tSigmaZ, tnTpcCluster, + tnItsCluster, tTpcChi2NCl, tItsChi2NCl, tRigidity, + tItsClusterSize, tHasTof, tDetectorMap); + } + } + 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 (cfgEnableItsClusterSizeCut) { + 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"), + getRigidity(track) * track.sign(), + track.tpcSignal()); + histos.fill(HIST("histogram/He/He-TOFbetaVsP"), + getRigidity(track) * 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 = getMass(track); + 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 = getRigidity(track); + float tItsClusterSize = + getMeanItsClsSize(track) / std::cosh(track.eta()); + bool tHasTof = track.hasTOF(); + int8_t tDetectorMap = track.detectorMap(); + heData(tPt, tEta, tPhi, tCharge, tHeDeDx, tnSigmaTpc, tTofSignalHe, + tDcaXY, tDcaZ, tSigmaYX, tSigmaXYZ, tSigmaZ, tnTpcCluster, + tnItsCluster, tTpcChi2NCl, tItsChi2NCl, tRigidity, + tItsClusterSize, tHasTof, tDetectorMap); + } + } + } + } + } + + template + float getTPCnSigma(T const& track, Particle const& particle) + { + const float rigidity = getRigidity(track); + if (!track.hasTPC()) + return -999; + + float expBethe{betheBlochAleph(particle, rigidity)}; + float expSigma{expBethe * particle.resolution}; + float sigmaTPC = + static_cast((track.tpcSignal() - expBethe) / expSigma); + return sigmaTPC; + } + + template + float betheBlochAleph(Particle const& particle, T const& rigidity) + { + double bg = particle.charge * rigidity / particle.mass; + double beta = bg / std::sqrt(1. + bg * bg); + double aa = std::pow(beta, particle.betheParams[3]); + double bb = std::pow(1. / bg, particle.betheParams[4]); + if ((particle.betheParams[2] + bb) <= 0) + return 0; + bb = std::log(particle.betheParams[2] + bb); + return std::pow(particle.charge, particle.chargeFactor) * 50 * (particle.betheParams[1] - aa - bb) * particle.betheParams[0] / aa; + } + + template + float getMeanItsClsSize(T const& track) + { + constexpr int NNumLayers = 8; + constexpr int NBitsPerLayer = 4; + constexpr int NBitMask = (1 << NBitsPerLayer) - 1; + + int sum = 0, n = 0; + for (int i = 0; i < NNumLayers; i++) { + int clsSize = (track.itsClusterSizes() >> (NBitsPerLayer * i)) & NBitMask; + sum += clsSize; + if (clsSize) { + 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 getMass(const T& track) + { + if (cfgMassMethod == 0) { + float m = track.mass(); + return m * m; + } + if (cfgMassMethod == 1) { + const float beta = track.beta(); + const float rigidity = getRigidity(track); + float gamma = 1.f / std::sqrt(1.f - beta * beta); + float mass = rigidity / std::sqrt(gamma * gamma - 1.f); + return mass * mass; + } + if (cfgMassMethod == 2) { + const float rigidity = getRigidity(track); + float tofStartTime = track.evTimeForTrack(); + float tofTime = track.tofSignal(); + constexpr float CInCmPs = 2.99792458e-2f; + float length = track.length(); + float time = tofTime - tofStartTime; + if (time > 0.f && length > 0.f) { + float beta = length / (CInCmPs * time); + float gamma = 1.f / std::sqrt(1.f - beta * beta); + float mass = rigidity / std::sqrt(gamma * gamma - 1.f); + return mass * mass; + } + return -1.f; + } + return -1.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 db3fdb4876b..79501158034 100644 --- a/PWGLF/TableProducer/QC/CMakeLists.txt +++ b/PWGLF/TableProducer/QC/CMakeLists.txt @@ -18,3 +18,8 @@ o2physics_add_dpl_workflow(flow-qc SOURCES flowQC.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(nucleiqc + SOURCES nucleiQC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/QC/flowQC.cxx b/PWGLF/TableProducer/QC/flowQC.cxx index 9dab0a906f0..9a120e1afe8 100644 --- a/PWGLF/TableProducer/QC/flowQC.cxx +++ b/PWGLF/TableProducer/QC/flowQC.cxx @@ -19,34 +19,32 @@ // o2-analysis-multiplicity-table, o2-analysis-ft0-corrected-table, o2-analysis-track-propagation, // o2-analysis-trackselection, o2-analysis-qvector-table, o2-analysis-lf-flow-qc -#include - -#include "Math/Vector4D.h" - -#include "CCDB/BasicCCDBManager.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "Common/Core/EventPlaneHelper.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/EventSelection.h" -#include "Common/Core/EventPlaneHelper.h" -#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Qvectors.h" +#include "CCDB/BasicCCDBManager.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 "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "Math/Vector4D.h" #include "TRandom3.h" +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -67,9 +65,10 @@ enum qVecDetectors { kFT0A, kTPCl, kTPCr, + kTPC, kNqVecDetectors }; -static const std::vector qVecDetectorNames{"FT0C", "FT0A", "TPCl", "TPCr"}; +static const std::vector qVecDetectorNames{"FT0C", "FT0A", "TPCl", "TPCr", "TPC"}; enum methods { kEP = 0, @@ -110,9 +109,11 @@ struct flowQC { int mRunNumber = 0; float mBz = 0.f; + Configurable cfgHarmonic{"cfgHarmonic", 2.f, "Harmonics for flow analysis"}; + // Flow analysis using CollWithEPandQvec = soa::Join::iterator; + aod::EvSels, aod::CentFT0As, aod::CentFT0Cs, aod::CentFT0Ms, aod::CentFV0As, aod::FT0Mults, aod::FV0Mults, aod::TPCMults, aod::EPCalibrationTables, aod::QvectorFT0CVecs, aod::QvectorFT0AVecs, aod::QvectorFT0MVecs, aod::QvectorFV0AVecs, aod::QvectorTPCallVecs, aod::QvectorTPCposVecs, aod::QvectorTPCnegVecs>::iterator; HistogramRegistry general{"general", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry flow_ep{"flow_ep", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; @@ -170,15 +171,15 @@ struct flowQC { const AxisSpec centAxis{cfgCentralityBins, fmt::format("{} percentile", (std::string)centDetectorNames[cfgCentralityEstimator])}; - const AxisSpec QxAxis{cfgQvecBins, "Q_{2,x}"}; - const AxisSpec QyAxis{cfgQvecBins, "Q_{2,y}"}; + const AxisSpec QxAxis{cfgQvecBins, Form("Q_{%.0f,x}", cfgHarmonic.value)}; + const AxisSpec QyAxis{cfgQvecBins, Form("Q_{%.0f,y}", cfgHarmonic.value)}; - const AxisSpec NormQxAxis{cfgQvecBins, "#frac{Q_{2,x}}{||#vec{Q_{2}}||}"}; - const AxisSpec NormQyAxis{cfgQvecBins, "#frac{Q_{2,y}}{||#vec{Q_{2}}||}"}; + const AxisSpec NormQxAxis{cfgQvecBins, Form("#frac{Q_{%.0f,x}}{||#vec{Q_{%.0f}}||}", cfgHarmonic.value, cfgHarmonic.value)}; + const AxisSpec NormQyAxis{cfgQvecBins, Form("#frac{Q_{%.0f,y}}{||#vec{Q_{%.0f}}||}", cfgHarmonic.value, cfgHarmonic.value)}; - 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})]"}; + const AxisSpec psiAxis{cfgPhiBins, Form("#psi_{%.0f}", cfgHarmonic.value)}; + const AxisSpec psiCompAxis{cfgPhiBins, Form("#psi_{%.0f}^{EP} - #psi_{%.0f}^{Qvec}", cfgHarmonic.value, cfgHarmonic.value)}; + const AxisSpec cosPsiCompAxis{cfgCosPhiBins, Form("cos[2(#psi_{%.0f}^{EP} - #psi_{%.0f}^{Qvec})]", cfgHarmonic.value, cfgHarmonic.value)}; // z vertex histogram general.add("hRecVtxZData", "collision z position", HistType::kTH1F, {{200, -20., +20., "z position (cm)"}}); @@ -202,12 +203,12 @@ struct flowQC { 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()); + auto spLabel = Form("#vec{Q}_{%.0f}^{%s} #upoint #vec{Q}_{%.0f}^{%s}", cfgHarmonic.value, qVecDetectorNames[iQvecDet].c_str(), cfgHarmonic.value, qVecDetectorNames[jQvecDet].c_str()); 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()); + auto normSpLabel = Form("#frac{#vec{Q}_{%.0f}^{%s} #upoint #vec{Q}_{%.0f}^{%s}}{||#vec{Q}_{%.0f}^{%s}|| ||#vec{Q}_{%.0f}^{%s}||}", cfgHarmonic.value, qVecDetectorNames[iQvecDet].c_str(), cfgHarmonic.value, qVecDetectorNames[jQvecDet].c_str(), cfgHarmonic.value, qVecDetectorNames[iQvecDet].c_str(), cfgHarmonic.value, qVecDetectorNames[jQvecDet].c_str()); 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}}); } @@ -258,51 +259,61 @@ struct flowQC { float centrality = getCentrality(collision); // EP method + float QmodFT0A_EP = collision.qFT0A(); float psiFT0A_EP = collision.psiFT0A(); - float QxFT0A_EP = std::cos(2 * psiFT0A_EP); - float QyFT0A_EP = std::sin(2 * psiFT0A_EP); - float QmodFT0A_EP = std::hypot(QxFT0A_EP, QyFT0A_EP); + float QxFT0A_EP = QmodFT0A_EP * std::cos(cfgHarmonic.value * psiFT0A_EP); + float QyFT0A_EP = QmodFT0A_EP * std::sin(cfgHarmonic.value * psiFT0A_EP); + float QmodFT0C_EP = collision.qFT0C(); float psiFT0C_EP = collision.psiFT0C(); - float QxFT0C_EP = std::cos(2 * psiFT0C_EP); - float QyFT0C_EP = std::sin(2 * psiFT0C_EP); - float QmodFT0C_EP = std::hypot(QxFT0C_EP, QyFT0C_EP); + float QxFT0C_EP = QmodFT0C_EP * std::cos(cfgHarmonic.value * psiFT0C_EP); + float QyFT0C_EP = QmodFT0C_EP * std::sin(cfgHarmonic.value * psiFT0C_EP); + float QmodTPCl_EP = collision.qTPCL(); float psiTPCl_EP = collision.psiTPCL(); - float QxTPCl_EP = std::cos(2 * psiTPCl_EP); - float QyTPCl_EP = std::sin(2 * psiTPCl_EP); - float QmodTPCl_EP = std::hypot(QxTPCl_EP, QyTPCl_EP); + float QxTPCl_EP = QmodTPCl_EP * std::cos(cfgHarmonic.value * psiTPCl_EP); + float QyTPCl_EP = QmodTPCl_EP * std::sin(cfgHarmonic.value * psiTPCl_EP); + float QmodTPCr_EP = collision.qTPCR(); float psiTPCr_EP = collision.psiTPCR(); - float QxTPCr_EP = std::cos(2 * psiTPCr_EP); - float QyTPCr_EP = std::sin(2 * psiTPCr_EP); - float QmodTPCr_EP = std::hypot(QxTPCr_EP, QyTPCr_EP); + float QxTPCr_EP = QmodTPCr_EP * std::cos(cfgHarmonic.value * psiTPCr_EP); + float QyTPCr_EP = QmodTPCr_EP * std::sin(cfgHarmonic.value * psiTPCr_EP); + + float QmodTPC_EP = collision.qTPC(); + float psiTPC_EP = collision.psiTPC(); + float QxTPC_EP = QmodTPC_EP * std::cos(cfgHarmonic.value * psiTPC_EP); + float QyTPC_EP = QmodTPC_EP * std::sin(cfgHarmonic.value * psiTPC_EP); // Qvec method - float QxFT0A_Qvec = collision.qvecFT0ARe(); - float QyFT0A_Qvec = collision.qvecFT0AIm(); + float QxFT0A_Qvec = collision.qvecFT0AReVec()[cfgHarmonic.value - 2]; + float QyFT0A_Qvec = collision.qvecFT0AImVec()[cfgHarmonic.value - 2]; 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 QxFT0C_Qvec = collision.qvecFT0CReVec()[cfgHarmonic.value - 2]; + float QyFT0C_Qvec = collision.qvecFT0CImVec()[cfgHarmonic.value - 2]; float QmodFT0C_Qvec = std::hypot(QxFT0C_Qvec, QyFT0C_Qvec); - float psiFT0C_Qvec = computeEventPlane(QyFT0C_Qvec, QxFT0A_Qvec); + float psiFT0C_Qvec = computeEventPlane(QyFT0C_Qvec, QxFT0C_Qvec); - float QxTPCl_Qvec = collision.qvecBNegRe(); - float QyTPCl_Qvec = collision.qvecBNegIm(); + float QxTPCl_Qvec = collision.qvecTPCnegReVec()[cfgHarmonic.value - 2]; + float QyTPCl_Qvec = collision.qvecTPCnegImVec()[cfgHarmonic.value - 2]; 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 QxTPCr_Qvec = collision.qvecTPCposReVec()[cfgHarmonic.value - 2]; + float QyTPCr_Qvec = collision.qvecTPCposImVec()[cfgHarmonic.value - 2]; float QmodTPCr_Qvec = std::hypot(QxTPCr_Qvec, QyTPCr_Qvec); float psiTPCr_Qvec = computeEventPlane(QyTPCr_Qvec, QxTPCr_Qvec); - std::array vec_Qx[2] = {{QxFT0C_EP, QxFT0A_EP, QxTPCl_EP, QxTPCr_EP}, {QxFT0C_Qvec, QxFT0A_Qvec, QxTPCl_Qvec, QxTPCr_Qvec}}; - std::array vec_Qy[2] = {{QyFT0C_EP, QyFT0A_EP, QyTPCl_EP, QyTPCr_EP}, {QyFT0C_Qvec, QyFT0A_Qvec, QyTPCl_Qvec, QyTPCr_Qvec}}; - std::array vec_Qmod[2] = {{QmodFT0C_EP, QmodFT0A_EP, QmodTPCl_EP, QmodTPCr_EP}, {QmodFT0C_Qvec, QmodFT0A_Qvec, QmodTPCl_Qvec, QmodTPCr_Qvec}}; - std::array vec_Qpsi[2] = {{psiFT0C_EP, psiFT0A_EP, psiTPCl_EP, psiTPCr_EP}, {psiFT0C_Qvec, psiFT0A_Qvec, psiTPCl_Qvec, psiTPCr_Qvec}}; + float QxTPC_Qvec = collision.qvecTPCallReVec()[cfgHarmonic.value - 2]; + float QyTPC_Qvec = collision.qvecTPCallImVec()[cfgHarmonic.value - 2]; + 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++) { @@ -327,7 +338,7 @@ struct flowQC { } 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]))); + hCosPsiComp[iQvecDet]->Fill(centrality, std::cos(cfgHarmonic.value * (vec_Qpsi[methods::kEP][iQvecDet] - vec_Qpsi[methods::kQvec][iQvecDet]))); } } }; diff --git a/PWGLF/TableProducer/QC/nucleiQC.cxx b/PWGLF/TableProducer/QC/nucleiQC.cxx new file mode 100644 index 00000000000..0c329807f5e --- /dev/null +++ b/PWGLF/TableProducer/QC/nucleiQC.cxx @@ -0,0 +1,507 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 TableProducer/Task for nuclei QC. The produced table can be disabled with a configurable. +/// +/// \author Giorgio Alberto Lucia (giorgio.alberto.lucia@cern.ch) +/// + +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFSlimNucleiTables.h" +#include "PWGLF/Utils/nucleiUtils.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Common/Tools/TrackTuner.h" + +#include "CCDB/BasicCCDBManager.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/Vector4D.h" +#include "TMCProcess.h" +#include "TRandom3.h" + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +struct nucleiQC { + + using TrackCandidates = soa::Join; + using TrackCandidatesMC = soa::Join; + using Collision = soa::Join::iterator; + Preslice mMcParticlesPerCollision = o2::aod::mcparticle::mcCollisionId; + + Configurable cfgFillTable{"cfgFillTable", true, "Fill output tree"}; + Configurable cfgDoCheckPdgCode{"cfgDoCheckPdgCode", true, "Should you only select tracks associated to a mc particle with the correct PDG code?"}; + Configurable cfgFillOnlyPhysicalPrimaries{"cfgFillOnlyPhysicalPrimaries", true, "Should you only select physical primary particles?"}; + Configurable> cfgSpeciesToProcess{"cfgSpeciesToProcess", {nuclei::speciesToProcessDefault[0], nuclei::Species::kNspecies, 1, nuclei::names, {"processNucleus"}}, "Nuclei to process"}; + Configurable> cfgEventSelections{"cfgEventSelections", {nuclei::EvSelDefault[0], 8, 1, nuclei::eventSelectionLabels, nuclei::eventSelectionTitle}, "Event selections"}; + Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 0, "Centrality estimator (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3)"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {nuclei::betheBlochDefault[0], nuclei::Species::kNspecies, 6, nuclei::names, nuclei::betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; + Configurable> cfgUseCentralTpcCalibration{"cfgUseCentralTpcCalibration", {nuclei::useCentralTpcCalibrationDefault[0], nuclei::Species::kNspecies, 1, nuclei::names, {"UseCentralTpcCalibration"}}, "Use central TPC calibration"}; + + Configurable cfgRapidityMin{"cfgRapidityMin", -1., "Minimum rapidity value"}; + Configurable cfgRapidityMax{"cfgRapidityMax", 1., "Maximum rapidity value"}; + Configurable cfgRapidityCenterMass{"cfgRapidityCenterMass", 0.0f, "Center of mass rapidity"}; + + 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 cfgCutNclusITS{"cfgCutNclusITS", 5, "Minimum number of ITS clusters"}; + Configurable cfgCutNclusTPC{"cfgCutNclusTPC", 70, "Minimum number of TPC clusters"}; + + Configurable> cfgNsigmaTPC{"cfgNsigmaTPC", {nuclei::nSigmaTPCdefault[0], nuclei::Species::kNspecies, 2, nuclei::names, nuclei::nSigmaConfigName}, "TPC nsigma selection for light nuclei"}; + Configurable> cfgNsigmaTOF{"cfgNsigmaTOF", {nuclei::nSigmaTOFdefault[0], nuclei::Species::kNspecies, 2, nuclei::names, nuclei::nSigmaConfigName}, "TPC nsigma selection for light nuclei"}; + + // 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"}; + Service mCcdb; + int mRunNumber = 0; + float mBz = 0.f; + + HistogramRegistry mHistograms{ + "histos", + { + {"hEventSelections", "Event selections; Selection step; Counts", {HistType::kTH1D, {{nuclei::evSel::kNevSels + 1, -0.5f, static_cast(nuclei::evSel::kNevSels) + 0.5f}}}}, + {"hVtxZBefore", "Vertex distribution in Z before selections;Z (cm)", {HistType::kTH1F, {{400, -20.0, 20.0}}}}, + {"hVtxZ", "Vertex distribution in Z;Z (cm)", {HistType::kTH1F, {{400, -20.0, 20.0}}}}, + }, + OutputObjHandlingPolicy::AnalysisObject, + false, + true}; + std::vector mSpeciesToProcess; + Produces mNucleiTableRed; + + std::vector mNucleiCandidates; + std::vector mFilledMcParticleIds; + + o2::dataformats::DCA mDcaInfoCov; + o2::track::TrackParametrizationWithError mTrackParCov; + std::array(nuclei::Species::kNspecies)> mPidManagers; + + void init(o2::framework::InitContext&) + { + + mCcdb->setURL(cfgCCDBurl); + mCcdb->setCaching(true); + mCcdb->setLocalObjectValidityChecking(); + mCcdb->setFatalWhenNull(false); + nuclei::lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(mCcdb->get("GLO/Param/MatLUT")); + + for (int iSel = 0; iSel < nuclei::evSel::kNevSels; iSel++) { + mHistograms.get(HIST("hEventSelections"))->GetXaxis()->SetBinLabel(iSel + 1, nuclei::eventSelectionLabels[iSel].c_str()); + } + + for (int iSpecies = 0; iSpecies < static_cast(nuclei::Species::kNspecies); iSpecies++) { + if (cfgSpeciesToProcess->get(iSpecies) == 1) + mSpeciesToProcess.emplace_back(iSpecies); + } + + static_for<0, nuclei::kNspecies - 1>([&](auto iSpecies) { + constexpr int kSpeciesCt = decltype(iSpecies)::value; + const int kSpeciesRt = kSpeciesCt; + + if (std::find(mSpeciesToProcess.begin(), mSpeciesToProcess.end(), kSpeciesCt) == mSpeciesToProcess.end()) + return; + + float tpcBetheBlochParams[6]; + for (int iParam = 0; iParam < 6; iParam++) { + tpcBetheBlochParams[iParam] = cfgBetheBlochParams->get(kSpeciesRt, iParam); + } + + nuclei::createHistogramRegistryNucleus(mHistograms); + + if (cfgUseCentralTpcCalibration->get(static_cast(kSpeciesRt), static_cast(0)) == 0) { + mPidManagers[kSpeciesRt] = nuclei::PidManager(kSpeciesRt, tpcBetheBlochParams); + } else { + mPidManagers[kSpeciesRt] = nuclei::PidManager(kSpeciesRt); + } + }); + } + + void initCCDB(const aod::BCsWithTimestamps::iterator& bc) + { + if (mRunNumber == bc.runNumber()) + return; + + auto timestamp = bc.timestamp(); + mRunNumber = bc.runNumber(); + + o2::parameters::GRPMagField* grpmag = mCcdb->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); + } + + template + bool trackSelection(const Ttrack& track) + { + 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) { + return false; + } + return true; + } + + template + bool pidSelection(const Ttrack& track, const Tcollision& collision) + { + constexpr int kIndex = iSpecies; + if (!nuclei::checkSpeciesValidity(kIndex)) + std::runtime_error("species contains invalid nucleus kIndex"); + + float centrality = nuclei::getCentrality(collision, cfgCentralityEstimator); + float nsigmaTPC = mPidManagers[kIndex].getNSigmaTPC(track); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3NsigmaTPC_preselectionVsCentrality"), track.pt() * track.sign(), nsigmaTPC, centrality); + if (std::abs(nsigmaTPC) > cfgNsigmaTPC->get(kIndex, 1)) + return false; + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3NsigmaTPCVsCentrality"), track.pt() * track.sign(), nsigmaTPC, centrality); + + float nsigmaITS = mPidManagers[kIndex].getNSigmaITS(track); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3NsigmaITS_preselectionVsCentrality"), track.sign() * track.pt(), nsigmaITS, centrality); + // add nsigmaITS cut ? + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3NsigmaITSVsCentrality"), track.sign() * track.pt(), nsigmaITS, centrality); + + float nsigmaTOF = mPidManagers[kIndex].getNSigmaTOF(track); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3NsigmaTOF_preselectionVsCentrality"), track.sign() * track.pt(), nsigmaTOF, centrality); + if (std::abs(nsigmaTOF) > cfgNsigmaTOF->get(kIndex, 1) && track.hasTOF()) + return false; + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3NsigmaTOFVsCentrality"), track.sign() * track.pt(), nsigmaTOF, centrality); + + return true; + } + + template + void fillNucleusFlagsPdgsMc(const Tparticle& particle, nuclei::SlimCandidate& candidate) + { + candidate.pdgCode = particle.pdgCode(); + candidate.mcProcess = particle.getProcess(); + + if (particle.has_mothers()) { + for (const auto& motherparticle : particle.template mothers_as()) { + candidate.motherPdgCode = motherparticle.pdgCode(); + } + } + + if (particle.isPhysicalPrimary()) { + candidate.flags |= nuclei::Flags::kIsPhysicalPrimary; + + ///< heavy flavour mother + /*if (particle.has_mothers()) { + for (const auto& motherparticle : particle.mothers_as()) { + if (std::find(nuclei::hfMothCodes.begin(), nuclei::hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != nuclei::hfMothCodes.end()) { + flags |= kIsSecondaryFromWeakDecay; + motherPdgCode = motherparticle.pdgCode(); + break; + } + } + }*/ + + } else if (particle.getProcess() == TMCProcess::kPDecay) { + ///< assuming that strong decays are included in the previous step + candidate.flags |= nuclei::Flags::kIsSecondaryFromWeakDecay; + } else { + candidate.flags |= nuclei::Flags::kIsSecondaryFromMaterial; + } + } + + template + void fillNucleusFlagsPdgs(const int iSpecies, const Tcollision& collision, const Ttrack& track, nuclei::SlimCandidate& candidate) + { + candidate.flags = static_cast((track.pidForTracking() & 0xF) << 12); + + switch (iSpecies) { + case nuclei::Species::kPr: + candidate.flags |= nuclei::Flags::kProton; + break; + case nuclei::Species::kDe: + candidate.flags |= nuclei::Flags::kDeuteron; + break; + case nuclei::Species::kTr: + candidate.flags |= nuclei::Flags::kTriton; + break; + case nuclei::Species::kHe: + candidate.flags |= nuclei::Flags::kHe3; + break; + case nuclei::Species::kAl: + candidate.flags |= nuclei::Flags::kHe4; + break; + default: + candidate.flags |= 0; + break; + } + + if (track.hasTOF()) + candidate.flags |= nuclei::Flags::kHasTOF; + + if (track.hasTRD()) + candidate.flags |= nuclei::Flags::kHasTRD; + + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + candidate.flags |= nuclei::Flags::kITSrof; + } + + template + void fillNucleusGeneratedVariables(const Tparticle& particle, nuclei::SlimCandidate& candidate) + { + candidate.ptGenerated = particle.pt() * (particle.pdgCode() > 0 ? 1.f : -1.f); + candidate.etaGenerated = particle.eta(); + candidate.phiGenerated = particle.phi(); + } + + template + void fillDcaInformation(const Tcollision& collision, const Ttrack& track, nuclei::SlimCandidate& candidate) + { + + const o2::math_utils::Point3D collisionVertex{collision.posX(), collision.posY(), collision.posZ()}; + + mDcaInfoCov.set(999, 999, 999, 999, 999); + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + std::array dcaInfo; + o2::base::Propagator::Instance()->propagateToDCA(collisionVertex, mTrackParCov, mBz, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfo); + + candidate.DCAxy = dcaInfo[0]; + candidate.DCAz = dcaInfo[1]; + } + + template + nuclei::SlimCandidate fillCandidate(const int iSpecies, Tcollision const& collision, Ttrack const& track) + { + if (!nuclei::checkSpeciesValidity(iSpecies)) + std::runtime_error("species contains invalid nucleus index"); + + nuclei::SlimCandidate candidate = {.pt = track.pt() * track.sign(), + .eta = track.eta(), + .phi = track.phi(), + .tpcInnerParam = track.tpcInnerParam(), + .clusterSizesITS = track.itsClusterSizes(), + .TPCsignal = track.tpcSignal(), + .beta = mPidManagers[iSpecies].getBetaTOF(track), + .DCAxy = 0.f, + .DCAz = 0.f, + .flags = 0, + .pdgCode = 0, + .motherPdgCode = 0, + .ptGenerated = 0.f, // to be filled for mc + .etaGenerated = 0.f, + .phiGenerated = 0.f, + .centrality = nuclei::getCentrality(collision, cfgCentralityEstimator), + .mcProcess = TMCProcess::kPNoProcess}; + + fillDcaInformation(collision, track, candidate); + fillNucleusFlagsPdgs(iSpecies, collision, track, candidate); + + if constexpr (isMc) { + if (track.has_mcParticle()) { + + const auto& particle = track.mcParticle(); + fillNucleusFlagsPdgsMc(particle, candidate); + fillNucleusGeneratedVariables(particle, candidate); + } + } + + return candidate; + } + + template + void dispatchFillHistograms(const int iSpecies, const nuclei::SlimCandidate& candidate) + { + switch (iSpecies) { + case nuclei::Species::kPr: + return fillHistograms(candidate); + case nuclei::Species::kDe: + return fillHistograms(candidate); + case nuclei::Species::kTr: + return fillHistograms(candidate); + case nuclei::Species::kHe: + return fillHistograms(candidate); + case nuclei::Species::kAl: + return fillHistograms(candidate); + default: + return; + } + } + + template + void fillHistograms(const nuclei::SlimCandidate& candidate) + { + constexpr int kIndex = iSpecies; + if (!nuclei::checkSpeciesValidity(kIndex)) + std::runtime_error("species contains invalid nucleus kIndex"); + + if (isGenerated) { + const float ptGenerated = (kIndex == nuclei::Species::kPr || kIndex == nuclei::Species::kDe || kIndex == nuclei::Species::kTr) ? candidate.ptGenerated : candidate.ptGenerated / 2.f; + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/hPtGenerated"), ptGenerated); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3PtVsEtaVsCentralityGenerated"), ptGenerated, candidate.etaGenerated, candidate.centrality); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3PhiVsEtaVsCentralityGenerated"), candidate.phiGenerated, candidate.etaGenerated, candidate.centrality); + } else { + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/hPtReconstructed"), candidate.pt); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3PtVsEtaVsCentralityReconstructed"), candidate.pt, candidate.eta, candidate.centrality); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3PhiVsEtaVsCentralityReconstructed"), candidate.phi, candidate.eta, candidate.centrality); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3DCAxyVsPtVsCentrality"), candidate.pt, candidate.DCAxy, candidate.centrality); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3DCAzVsPtVsCentrality"), candidate.pt, candidate.DCAz, candidate.centrality); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3BetaVsPtVsCentrality"), candidate.pt, candidate.beta, candidate.centrality); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3dEdxVsPVsCentrality"), candidate.pt, candidate.TPCsignal, candidate.centrality); + mHistograms.fill(HIST(nuclei::cNames[kIndex]) + HIST("/h3ClusterSizeVsPtVsCentrality"), candidate.pt, mPidManagers[kIndex].getClusterSizeCosLambdaITS(candidate.clusterSizesITS, candidate.eta), candidate.centrality); + } + } + + void processMc(const Collision& collision, const TrackCandidatesMC& tracks, const aod::BCsWithTimestamps&, const aod::McParticles& mcParticles) + { + mNucleiCandidates.clear(); + mFilledMcParticleIds.clear(); + + auto bc = collision.template bc_as(); + initCCDB(bc); + + if (!nuclei::eventSelection(collision, mHistograms, cfgEventSelections, cfgCutVertex)) + return; + + for (const auto& track : tracks) { + + static_for<0, nuclei::kNspecies - 1>([&](auto iSpecies) { + constexpr int kSpeciesCt = decltype(iSpecies)::value; + const int kSpeciesRt = kSpeciesCt; + + if (std::find(mSpeciesToProcess.begin(), mSpeciesToProcess.end(), kSpeciesRt) == mSpeciesToProcess.end()) + return; + + if (!track.has_mcParticle()) + return; + + const auto& particle = track.mcParticle(); + if (cfgDoCheckPdgCode) { + if (std::abs(particle.pdgCode()) != nuclei::pdgCodes[kSpeciesRt]) + return; + } + + if ((particle.y() - cfgRapidityCenterMass) < cfgRapidityMin || (particle.y() - cfgRapidityCenterMass) > cfgRapidityMax) + return; + + if (cfgFillOnlyPhysicalPrimaries && !particle.isPhysicalPrimary()) + return; + + mHistograms.fill(HIST(nuclei::cNames[kSpeciesCt]) + HIST("/hTrackSelections"), nuclei::trackSelection::kNoCuts); + if (!trackSelection(track)) + return; + mHistograms.fill(HIST(nuclei::cNames[kSpeciesCt]) + HIST("/hTrackSelections"), nuclei::trackSelection::kTrackCuts); + + if (!pidSelection(track, collision)) + return; + mHistograms.fill(HIST(nuclei::cNames[kSpeciesCt]) + HIST("/hTrackSelections"), nuclei::trackSelection::kPidCuts); + + nuclei::SlimCandidate candidate; + candidate = fillCandidate(kSpeciesCt, collision, track); + + mNucleiCandidates.emplace_back(candidate); + mFilledMcParticleIds.emplace_back(particle.globalIndex()); + dispatchFillHistograms(kSpeciesRt, candidate); + dispatchFillHistograms(kSpeciesRt, candidate); + }); + } + + const int mcCollisionId = collision.mcCollisionId(); + auto mcParticlesThisCollision = mcParticles.sliceBy(mMcParticlesPerCollision, mcCollisionId); + mcParticlesThisCollision.bindExternalIndices(&mcParticles); + + for (const auto& particle : mcParticlesThisCollision) { + + if (std::find(mFilledMcParticleIds.begin(), mFilledMcParticleIds.end(), particle.globalIndex()) != mFilledMcParticleIds.end()) + continue; + + if (cfgFillOnlyPhysicalPrimaries && !particle.isPhysicalPrimary()) + continue; + + if ((particle.y() - cfgRapidityCenterMass) < cfgRapidityMin || (particle.y() - cfgRapidityCenterMass) > cfgRapidityMax) + continue; + + int iSpecies = nuclei::getSpeciesFromPdg(particle.pdgCode()); + if (std::find(mSpeciesToProcess.begin(), mSpeciesToProcess.end(), iSpecies) == mSpeciesToProcess.end()) + continue; + + nuclei::SlimCandidate candidate; + fillNucleusFlagsPdgsMc(particle, candidate); + fillNucleusGeneratedVariables(particle, candidate); + + mNucleiCandidates.emplace_back(candidate); + mFilledMcParticleIds.emplace_back(particle.globalIndex()); + dispatchFillHistograms(iSpecies, candidate); + } + + if (!cfgFillTable) + return; + + for (const auto& candidate : mNucleiCandidates) { + mNucleiTableRed( + candidate.pt, + candidate.eta, + candidate.phi, + candidate.tpcInnerParam, + candidate.clusterSizesITS, + candidate.TPCsignal, + candidate.beta, + candidate.DCAxy, + candidate.DCAz, + candidate.flags, + candidate.mcProcess, + candidate.pdgCode, + candidate.motherPdgCode); + } + } + PROCESS_SWITCH(nucleiQC, processMc, "Mc analysis", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/QC/strangenessQC.cxx b/PWGLF/TableProducer/QC/strangenessQC.cxx index f35ad82899c..215eb99796d 100644 --- a/PWGLF/TableProducer/QC/strangenessQC.cxx +++ b/PWGLF/TableProducer/QC/strangenessQC.cxx @@ -14,15 +14,17 @@ /// In case of questions please write to: /// \author Roman Nepeivoda (roman.nepeivoda@cern.ch) -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/EventSelection.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/QC/strangenessTablesQC.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/PWGLF/TableProducer/Resonances/CMakeLists.txt b/PWGLF/TableProducer/Resonances/CMakeLists.txt index baa9b98325a..a3e59673293 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,32 @@ 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) + +o2physics_add_dpl_workflow(cksspinalignment + SOURCES cksspinalignment.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(resonance-tree-creator + SOURCES resonanceTreeCreator.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx b/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx new file mode 100644 index 00000000000..c8892d3ec39 --- /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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/ReducedHeptaQuarkTables.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +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/LFResonanceMergeDF.cxx b/PWGLF/TableProducer/Resonances/LFResonanceMergeDF.cxx deleted file mode 100644 index 9668afc3e01..00000000000 --- a/PWGLF/TableProducer/Resonances/LFResonanceMergeDF.cxx +++ /dev/null @@ -1,315 +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"}; - 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"}; - - 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) { - 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.tpcNSigmaEl()) && std::abs(track.tpcNSigmaKa()) > std::abs(track.tpcNSigmaEl())) || (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.tofNSigmaEl()) && std::abs(track.tofNSigmaKa()) > std::abs(track.tofNSigmaEl())) || (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.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.hasITS(), - track.hasTPC(), - track.hasTOF(), - track.tpcNSigmaPi(), - track.tpcNSigmaKa(), - track.tpcNSigmaPr(), - track.tpcNSigmaEl(), - track.tofNSigmaPi(), - track.tofNSigmaKa(), - track.tofNSigmaPr(), - track.tofNSigmaEl(), - track.tpcSignal(), - track.passedITSRefit(), - track.passedTPCRefit(), - track.isGlobalTrackWoDCA(), - track.isGlobalTrack(), - 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), - std::get<28>(tuple), - std::get<29>(tuple), - std::get<30>(tuple), - std::get<31>(tuple), - std::get<32>(tuple), - std::get<33>(tuple), - std::get<34>(tuple)); - } - } - - vecOfTuples.clear(); - vecOfVecOfTuples.clear(); // - } - - PROCESS_SWITCH(reso2dfmerged, processTrackDataDF, "Process for data merged DF", true); - - void processLambdaStarCandidate(resoCols::iterator const& collision, resoTracks const& - tracks) - { - - if (doprocessTrackDataDF) - LOG(fatal) << "Disable processTrackDataDF first!"; - histos.fill(HIST("Event/h1d_ft0_mult_percentile"), collision.cent()); - - resoCollisionsdf(collision.posX(), collision.posY(), collision.posZ(), collision.cent(), collision.spherocity(), collision.evtPl(), 0., 0., 0., 0., 0); - - for (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.tpcNSigmaEl()) && std::abs(track.tpcNSigmaKa()) > std::abs(track.tpcNSigmaEl())) || (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.tofNSigmaEl()) && std::abs(track.tofNSigmaKa()) > std::abs(track.tofNSigmaEl())) || (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.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.hasITS(), - track.hasTPC(), - track.hasTOF(), - track.tpcNSigmaPi(), - track.tpcNSigmaKa(), - track.tpcNSigmaPr(), - track.tpcNSigmaEl(), - track.tofNSigmaPi(), - track.tofNSigmaKa(), - track.tofNSigmaPr(), - track.tofNSigmaEl(), - track.tpcSignal(), - track.passedITSRefit(), - track.passedTPCRefit(), - track.isGlobalTrackWoDCA(), - track.isGlobalTrack(), - track.isPrimaryTrack(), - track.isPVContributor(), - track.tpcCrossedRowsOverFindableCls(), - track.itsChi2NCl(), - track.tpcChi2NCl()); - } - } - PROCESS_SWITCH(reso2dfmerged, processLambdaStarCandidate, "Process for lambda star candidate", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/Resonances/cksspinalignment.cxx b/PWGLF/TableProducer/Resonances/cksspinalignment.cxx new file mode 100644 index 00000000000..b76c9382798 --- /dev/null +++ b/PWGLF/TableProducer/Resonances/cksspinalignment.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. + +/// \file cksspinalignment.cxx +/// \brief Table producer for Charged KStar spin alignment +/// +/// \author prottay.das@cern.ch + +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFCKSSpinalignmentTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector2D.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" + +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using namespace o2::aod::rctsel; + +struct cksspinalignment { + + Produces kshortpionEvent; + Produces kshortTrack; + Produces pionTrack; + + Service ccdb; + + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + + Configurable cfgCutOccupancy{"cfgCutOccupancy", 2000, "Occupancy cut"}; + + // events + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 80.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 0.0f, "Accepted minimum Centrality"}; + + // Configs for track + Configurable cfgCutPt{"cfgCutPt", 0.2, "Pt cut on daughter track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + + // Configs for pion + struct : ConfigurableGroup { + Configurable itsPIDSelection{"itsPIDSelection", true, "PID ITS"}; + Configurable lowITSPIDNsigma{"lowITSPIDNsigma", -3.0, "lower cut on PID nsigma for ITS"}; + Configurable highITSPIDNsigma{"highITSPIDNsigma", 3.0, "higher cut on PID nsigma for ITS"}; + Configurable itsclusterPiMeson{"itsclusterPiMeson", 5, "Minimum number of ITS cluster for pi meson track"}; + Configurable tpcCrossedRowsPiMeson{"tpcCrossedRowsPiMeson", 80, "Minimum number of TPC Crossed Rows for pi meson track"}; + Configurable cutDCAxyPiMeson{"cutDCAxyPiMeson", 0.1, "Maximum DCAxy for pi meson track"}; + Configurable cutDCAzPiMeson{"cutDCAzPiMeson", 0.1, "Maximum DCAz for pi meson track"}; + Configurable cutEtaPiMeson{"cutEtaPiMeson", 0.8, "Maximum eta for pi meson track"}; + Configurable cutPTPiMeson{"cutPTPiMeson", 0.8, "Maximum pt for pi meson track"}; + Configurable usePID{"usePID", true, "Flag for using PID selection for pi meson track"}; + Configurable nsigmaCutTPCPiMeson{"nsigmaCutTPCPiMeson", 3.0, "Maximum nsigma cut TPC for pi meson track"}; + Configurable nsigmaCutTOFPiMeson{"nsigmaCutTOFPiMeson", 3.0, "Maximum nsigma cut TOF for pi meson track"}; + Configurable cutTOFBetaPiMeson{"cutTOFBetaPiMeson", 3.0, "Maximum beta cut for pi meson track"}; + } grpPion; + + // Configs for V0 + Configurable confV0PtMin{"confV0PtMin", 0.f, "Minimum transverse momentum of V0"}; + Configurable confV0PtMax{"confV0PtMax", 1000.f, "Maximum transverse momentum of V0"}; + Configurable confV0Rap{"confV0Rap", 0.8f, "Rapidity range of V0"}; + Configurable confV0DCADaughMax{"confV0DCADaughMax", 1.0f, "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 cMinV0DCAPi{"cMinV0DCAPi", 0.05, "Minimum V0 daughters DCA to PV for Pi"}; + Configurable cMaxV0LifeTime{"cMaxV0LifeTime", 50, "Maximum V0 life time"}; + Configurable qtArmenterosMin{"qtArmenterosMin", 0.2, "Minimum armenteros cut for K0s"}; + // config for V0 daughters + Configurable confDaughEta{"confDaughEta", 0.8f, "V0 Daugh sel: max eta"}; + Configurable cfgDaughPiPt{"cfgDaughPiPt", 0.2, "minimum daughter pion pt"}; + Configurable confDaughTPCnclsMin{"confDaughTPCnclsMin", 50.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable confDaughTPCncrwsMin{"confDaughTPCncrwsMin", 70.f, "V0 Daugh sel: Min. nCrws TPC"}; + Configurable confDaughPIDCuts{"confDaughPIDCuts", 3, "PID selections for Kshortpion daughters"}; + + Configurable iMNbins{"iMNbins", 50, "Number of bins in invariant mass"}; + Configurable lbinIM{"lbinIM", 1.09, "lower bin value in IM histograms"}; + Configurable hbinIM{"hbinIM", 1.14, "higher bin value in IM histograms"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + RCTFlagsChecker rctChecker; + void init(o2::framework::InitContext&) + { + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + AxisSpec thnAxisInvMass{iMNbins, lbinIM, hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{5, 0, 5.0}}); + histos.add("hTrkSelInfo", "hTrkSelInfo", kTH1F, {{5, 0, 5.0}}); + histos.add("hKShortMass", "hKShortMass", kTH1F, {thnAxisInvMass}); + histos.add("hV0Info", "hV0Info", kTH1F, {{5, 0, 5.0}}); + } + + template + bool selectionTrack(const T& candidate) + { + if (candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() >= grpPion.itsclusterPiMeson && candidate.tpcNClsCrossedRows() > grpPion.tpcCrossedRowsPiMeson && std::abs(candidate.dcaXY()) <= grpPion.cutDCAxyPiMeson && std::abs(candidate.dcaZ()) <= grpPion.cutDCAzPiMeson && std::abs(candidate.eta()) <= grpPion.cutEtaPiMeson && candidate.pt() >= grpPion.cutPTPiMeson) { + return true; + } + return false; + } + + template + bool selectionPID(const T& candidate) + { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < grpPion.nsigmaCutTPCPiMeson) { + return true; + } + if (candidate.hasTOF() && candidate.beta() > grpPion.cutTOFBetaPiMeson && std::abs(candidate.tpcNSigmaPi()) < grpPion.nsigmaCutTPCPiMeson && std::abs(candidate.tofNSigmaPi()) < grpPion.nsigmaCutTOFPiMeson) { + return true; + } + return false; + } + + 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 ctauKShort = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * (o2::constants::physics::MassK0); + + if (pT < confV0PtMin) { + return false; + } + if (pT > confV0PtMax) { + 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(ctauKShort) > cMaxV0LifeTime) { + return false; + } + if ((candidate.qtarm() / std::abs(candidate.alpha())) < qtArmenterosMin) { + return false; + } + if (std::abs(candidate.yK0Short()) > confV0Rap) { // use full rapidity 0.8 for K0s + return false; + } + return true; + } + + template + bool isSelectedV0Daughter(V0 const& candidate) + { + auto postrack = candidate.template posTrack_as(); + auto negtrack = candidate.template negTrack_as(); + + const auto ncrfc = 0.8; + + if (postrack.sign() < 0 || negtrack.sign() > 0) { + return false; + } + if (postrack.tpcNClsCrossedRows() < confDaughTPCncrwsMin || negtrack.tpcNClsCrossedRows() < confDaughTPCncrwsMin) { + return false; + } + if (postrack.tpcNClsFound() < confDaughTPCnclsMin || negtrack.tpcNClsFound() < confDaughTPCnclsMin) { + return false; + } + if (postrack.tpcCrossedRowsOverFindableCls() < ncrfc || negtrack.tpcCrossedRowsOverFindableCls() < ncrfc) { + return false; + } + if (std::abs(postrack.tpcNSigmaPi()) > confDaughPIDCuts || std::abs(negtrack.tpcNSigmaPi()) > confDaughPIDCuts) { + return false; + } + if (candidate.positivept() < cfgDaughPiPt || candidate.negativept() < cfgDaughPiPt) { + return false; + } + if (std::abs(candidate.positiveeta()) > confDaughEta || std::abs(candidate.negativeeta()) > confDaughEta) { + return false; + } + if (std::abs(candidate.dcapostopv()) < cMinV0DCAPi || std::abs(candidate.dcanegtopv()) < cMinV0DCAPi) { + return false; + } + + return true; + } + + std::tuple getK0sTags(const auto& v0, const auto& collision) + { + // auto postrack = v0.template posTrack_as(); + // auto negtrack = v0.template negTrack_as(); + + int kshortTag = 0; + + if (isSelectedV0Daughter(v0) && v0.mK0Short() > lbinIM && v0.mK0Short() < hbinIM) { + kshortTag = 1; + } + + if (!kshortTag) { + return {0, false}; // No valid tags + } + + if (!selectionV0(collision, v0)) { + return {0, false}; // Fails selection + } + + return {kshortTag, true}; // Valid candidate + } + + ROOT::Math::PxPyPzMVector kshort, pion, pionbach, antiPion; + ROOT::Math::PxPyPzMVector kshortDummy, pionDummy; + + 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 && (aod::track::pt) > cfgCutPt); + + using EventCandidates = soa::Filtered>; + using AllTrackCandidates = soa::Filtered>; + using ResoV0s = aod::V0Datas; + void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& tracks, ResoV0s const& V0s) + { + o2::aod::ITSResponse itsResponse; + std::vector kshortMother, pionBachelor; + std::vector v0Cospa = {}; + std::vector v0Radius = {}; + std::vector dcaPositive = {}; + std::vector dcaNegative = {}; + std::vector positiveIndex = {}; + std::vector negativeIndex = {}; + std::vector dcaBetweenDaughter = {}; + std::vector v0Lifetime = {}; + // std::vector armenteros = {}; + std::vector pionBachelorIndex = {}; + // std::vector pionBachelorSign = {}; + std::vector pionBachelorTPC = {}; + std::vector pionBachelorTOF = {}; + std::vector pionBachelorTOFHit = {}; + + int numbV0 = 0; + auto centrality = collision.centFT0C(); + auto vz = collision.posZ(); + int occupancy = collision.trackOccupancyInTimeRange(); + auto psiFT0C = collision.psiFT0C(); + auto psiFT0A = collision.psiFT0A(); + auto psiTPC = collision.psiTPC(); + // auto psiTPCR = collision.psiTPCR(); + // auto psiTPCL = collision.psiTPCL(); + histos.fill(HIST("hEvtSelInfo"), 0.5); + if ((rctCut.requireRCTFlagChecker && rctChecker(collision)) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) && collision.sel8() && collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) && occupancy < cfgCutOccupancy) { + histos.fill(HIST("hEvtSelInfo"), 1.5); + if (collision.triggereventep()) { + histos.fill(HIST("hEvtSelInfo"), 2.5); + + for (const auto& track1 : tracks) { + histos.fill(HIST("hTrkSelInfo"), 0.5); + if (!selectionTrack(track1)) { + continue; + } + histos.fill(HIST("hTrkSelInfo"), 1.5); + + if (grpPion.itsPIDSelection && !(itsResponse.nSigmaITS(track1) > grpPion.lowITSPIDNsigma && itsResponse.nSigmaITS(track1) < grpPion.highITSPIDNsigma)) { + continue; + } + histos.fill(HIST("hTrkSelInfo"), 2.5); + + if (grpPion.usePID && !selectionPID(track1)) { + continue; + } + histos.fill(HIST("hTrkSelInfo"), 3.5); + + auto track1ID = track1.globalIndex(); + auto track1sign = track1.sign(); + if (track1sign == 0) + continue; + auto track1nsigTPC = track1.tpcNSigmaPi(); + auto track1nsigTOF = -999.9; + auto track1TOFHit = -1; + if (track1.hasTOF()) { + track1TOFHit = 1; + track1nsigTOF = track1.tofNSigmaPi(); + histos.fill(HIST("hTrkSelInfo"), 4.5); + } + pionbach = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassPionCharged); + pionBachelor.push_back(pionbach); + pionBachelorIndex.push_back(track1ID); + // pionBachelorSign.push_back(track1sign); + pionBachelorTPC.push_back(track1nsigTPC); + pionBachelorTOF.push_back(track1nsigTOF); + pionBachelorTOFHit.push_back(track1TOFHit); + } + for (const auto& v0 : V0s) { + histos.fill(HIST("hV0Info"), 0.5); + auto [kshortTag, isValid] = getK0sTags(v0, collision); + if (kshortTag && isValid) { + histos.fill(HIST("hV0Info"), 1.5); + auto postrack1 = v0.template posTrack_as(); + auto negtrack1 = v0.template negTrack_as(); + positiveIndex.push_back(postrack1.globalIndex()); + negativeIndex.push_back(negtrack1.globalIndex()); + v0Cospa.push_back(v0.v0cosPA()); + v0Radius.push_back(v0.v0radius()); + dcaPositive.push_back(std::abs(v0.dcapostopv())); + dcaNegative.push_back(std::abs(v0.dcanegtopv())); + dcaBetweenDaughter.push_back(std::abs(v0.dcaV0daughters())); + v0Lifetime.push_back(v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * (o2::constants::physics::MassK0)); + // armenteros.push_back((v0.qtarm() / std::abs(v0.alpha()))); + + pion = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), o2::constants::physics::MassPionCharged); + antiPion = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), o2::constants::physics::MassPionCharged); + kshort = pion + antiPion; + // chargedkstar = kshort + pionbach; + kshortMother.push_back(kshort); + // chargedkstarMother.push_back(chargedkstar); + histos.fill(HIST("hKShortMass"), kshort.M()); + } + numbV0 = numbV0 + 1; + } + if (numbV0 > 1 && v0Cospa.size() > 1) { + histos.fill(HIST("hEvtSelInfo"), 3.5); + kshortpionEvent(centrality, vz, collision.index(), psiFT0C, psiFT0A, psiTPC); + auto indexEvent = kshortpionEvent.lastIndex(); + //// Fill track table for Charged KStar////////////////// + for (auto icks = kshortMother.begin(); icks != kshortMother.end(); ++icks) { + auto iter = std::distance(kshortMother.begin(), icks); + kshortDummy = kshortMother.at(iter); + // chargedkstarDummy = chargedkstarMother.at(iter); + + kshortTrack(indexEvent, v0Cospa.at(iter), v0Radius.at(iter), dcaPositive.at(iter), dcaNegative.at(iter), dcaBetweenDaughter.at(iter), v0Lifetime.at(iter), kshortDummy.Px(), kshortDummy.Py(), kshortDummy.Pz(), kshortDummy.M(), positiveIndex.at(iter), negativeIndex.at(iter)); + } + for (auto ipi = pionBachelor.begin(); ipi != pionBachelor.end(); ++ipi) { + auto iterpi = std::distance(pionBachelor.begin(), ipi); + pionDummy = pionBachelor.at(iterpi); + + pionTrack(indexEvent, pionDummy.Px(), pionDummy.Py(), pionDummy.Pz(), pionBachelorTPC.at(iterpi), pionBachelorTOFHit.at(iterpi), pionBachelorTOF.at(iterpi), pionBachelorIndex.at(iterpi)); + } + } + } + } + } + PROCESS_SWITCH(cksspinalignment, processData, "Process data", 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..7079cf2f294 --- /dev/null +++ b/PWGLF/TableProducer/Resonances/doublephitable.cxx @@ -0,0 +1,289 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/ReducedDoublePhiTables.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include + +#include +#include +#include // FIXME +#include +#include // FIXME + +#include + +#include +#include +#include +#include + +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/f1protonInitializer.cxx b/PWGLF/TableProducer/Resonances/f1protonInitializer.cxx index e7240c72f90..c65adab98f0 100644 --- a/PWGLF/TableProducer/Resonances/f1protonInitializer.cxx +++ b/PWGLF/TableProducer/Resonances/f1protonInitializer.cxx @@ -12,39 +12,41 @@ /// \file f1protonInitializer.cxx /// check if the event have f1-p candidate /// \author Sourav Kundu -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include "PWGLF/DataModel/LFF1Tables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" #include "Common/Core/trackUtilities.h" -#include "CommonConstants/PhysicsConstants.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFF1Tables.h" -#include "PWGLF/Utils/collisionCuts.h" #include "ReconstructionDataFormats/Track.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx b/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx index 30082692386..237b13e25e4 100644 --- a/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx +++ b/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx @@ -14,34 +14,42 @@ /// /// \author Sourav Kundu, sourav.kundu@cern.ch +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/ReducedF1ProtonTables.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" #include + #include #include +#include // FIXME #include +#include // FIXME + #include -#include // FIXME -#include // FIXME #include #include #include - -#include "PWGLF/DataModel/ReducedF1ProtonTables.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 "PWGLF/DataModel/LFStrangenessTables.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" +#include using namespace o2; using namespace o2::framework; @@ -57,6 +65,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 +77,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 +147,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 +161,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 +176,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 +252,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) { @@ -378,7 +403,7 @@ struct f1protonreducedtable { std::vector setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) { - map metadata; + std::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) { @@ -481,6 +506,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 +527,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 +562,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 +589,232 @@ 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 (!selectionGlobalTrack(track)) { + continue; } - if (track.sign() < 0) { - qaRegistry.fill(HIST("hNsigmaPtpionTPC"), nTPCSigmaN[0], track.pt()); + 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 (track.hasTOF()) { - qaRegistry.fill(HIST("hNsigmaPtpionTOF"), track.tofNSigmaPi(), track.pt()); - PionTOF = 1; + 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) - continue; - F1Vector = KKs0Vector + pions.at(i1); - if (F1Vector.M() > cMaxMassF1) - continue; - if (F1Vector.Pt() < cMinF1Pt) + 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; - - // 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 + 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 = 100; + if (PionCharge.at(i1) * KaonCharge.at(i2) > 0) { + qaRegistry.fill(HIST("hInvMassf1Like"), F1Vector.M(), F1Vector.Pt()); + pairsign = -1; + } else if (PionCharge.at(i1) * KaonCharge.at(i2) < 0) { + if (KaonCharge.at(i2) > 0) { + pairsign = 1; } - - 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; + if (KaonCharge.at(i2) < 0) { + pairsign = 2; } - - kstar = getkstar(F1Vector, *iproton); - qaRegistry.fill(HIST("hkstarDist"), kstar); - if (kstar > cMaxRelMom) - continue; - qaRegistry.fill(HIST("hInvMassf1kstar"), F1Vector.M(), F1Vector.Pt(), kstar); - keepEventF1Proton = true; } + 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 > 0) { + 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 +826,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 +838,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/filterf1proton.cxx b/PWGLF/TableProducer/Resonances/filterf1proton.cxx index 831209b0905..6db99210f32 100644 --- a/PWGLF/TableProducer/Resonances/filterf1proton.cxx +++ b/PWGLF/TableProducer/Resonances/filterf1proton.cxx @@ -14,33 +14,38 @@ /// /// \author Sourav Kundu, sourav.kundu@cern.ch +#include "PWGLF/DataModel/FilterF1ProtonTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" #include + #include #include #include + #include + #include #include #include -#include "PWGLF/DataModel/FilterF1ProtonTables.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 "PWGLF/DataModel/LFStrangenessTables.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" -#include "CommonConstants/PhysicsConstants.h" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -368,7 +373,7 @@ struct filterf1proton { std::vector setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) { - map metadata; + std::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) { diff --git a/PWGLF/TableProducer/Resonances/LFResonanceInitializer.cxx b/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx similarity index 57% rename from PWGLF/TableProducer/Resonances/LFResonanceInitializer.cxx rename to PWGLF/TableProducer/Resonances/resonanceInitializer.cxx index a453b6edeb5..79514728d10 100644 --- a/PWGLF/TableProducer/Resonances/LFResonanceInitializer.cxx +++ b/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx @@ -8,75 +8,93 @@ // In applying this license CERN does not 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 -/// /// +/// \file resonanceInitializer.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 "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.h" + +#include "Common/Core/EventPlaneHelper.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/TrackSelectionTables.h" #include "Common/DataModel/Qvectors.h" -#include "Common/Core/EventPlaneHelper.h" -#include "Framework/ASoAHelpers.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.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/Utils/collisionCuts.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" + +#include +#include 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 reso2initializer { +struct ResonanceInitializer { SliceCache cache; - float cXiMass; int mRunNumber; int multEstimator; - float d_bz; + 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{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + 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 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. + 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"}; @@ -88,22 +106,33 @@ struct reso2initializer { /// Event cuts o2::analysis::CollisonCuts colCuts; - Configurable ConfEvtZvtx{"ConfEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; - Configurable ConfEvtOccupancyInTimeRange{"ConfEvtOccupancyInTimeRange", -1, "Evt sel: maximum track occupancy"}; - 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 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", 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"}; + + 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 ConfBypassQvec{"ConfBypassQvec", true, "Bypass for qvector task"}; + 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 @@ -125,7 +154,7 @@ struct reso2initializer { 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 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"}; @@ -138,24 +167,62 @@ struct reso2initializer { 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 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 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; + 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* @@ -177,7 +244,7 @@ struct reso2initializer { || (nabs(aod::mcparticle::pdgCode) == 123314) // Xi(1820)0 || (nabs(aod::mcparticle::pdgCode) == 123324); // Xi(1820)-0 - using ResoEvents = soa::Join; + using ResoEvents = soa::Join; using ResoRun2Events = soa::Join; using ResoEventsMC = soa::Join; using ResoRun2EventsMC = soa::Join; @@ -187,40 +254,180 @@ struct reso2initializer { 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) + bool isTrackSelected(CollisionType const&, TrackType const& track) { // Track selection - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodTrackIndices"), 0.5); // MC case can be handled here if constexpr (isMC) { // MC check - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodMCTrackIndices"), 0.5); } // DCAxy cut - if (fabs(track.dcaXY()) > cMaxDCArToPVcut) + if (std::fabs(track.dcaXY()) > cMaxDCArToPVcut) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodTrackIndices"), 1.5); // DCAz cut - if (fabs(track.dcaZ()) > cMaxDCAzToPVcut || fabs(track.dcaZ()) < cMinDCAzToPVcut) + if (std::fabs(track.dcaZ()) > cMaxDCAzToPVcut || std::fabs(track.dcaZ()) < cMinDCAzToPVcut) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodTrackIndices"), 2.5); - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodTrackIndices"), 7.5); return true; } template - bool IsV0Selected(CollisionType const&, V0Type const& v0, TrackType const&) + bool isV0Selected(CollisionType const&, V0Type const& v0, TrackType const&) { // V0 selection - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodV0Indices"), 0.5); auto postrack = v0.template posTrack_as(); @@ -230,39 +437,39 @@ struct reso2initializer { return false; if (negtrack.tpcNClsCrossedRows() < mincrossedrows) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodV0Indices"), 1.5); - if (fabs(postrack.dcaXY()) < cMinV0PosDCArToPVcut) + if (std::fabs(postrack.dcaXY()) < cMinV0PosDCArToPVcut) return false; - if (fabs(negtrack.dcaXY()) < cMinV0NegDCArToPVcut) + if (std::fabs(negtrack.dcaXY()) < cMinV0NegDCArToPVcut) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodV0Indices"), 2.5); if ((v0.v0radius() > cMaxV0Radius) || (v0.v0radius() < cMinV0Radius)) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodV0Indices"), 3.5); if (v0.v0cosPA() < cMinV0CosPA) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodV0Indices"), 4.5); // MC case can be handled here if constexpr (isMC) { // MC check - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodMCV0Indices"), 0.5); } return true; } template - bool IsCascSelected(CollisionType const& collision, CascType const& casc, TrackType const&) + bool isCascSelected(CollisionType const& collision, CascType const& casc, TrackType const&) { // V0 selection - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodCascIndices"), 0.5); auto trackBach = casc.template bachelor_as(); @@ -270,16 +477,16 @@ struct reso2initializer { // auto trackNeg = casc.template negTrack_as(); // track cuts - if (trackBach.tpcNClsCrossedRows() < mincrossedrows_cascbach) + if (trackBach.tpcNClsCrossedRows() < cfgMinCrossedRowsCascBach) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodCascIndices"), 1.5); - if (fabs(trackBach.dcaXY()) < cMinCascBachDCArToPVcut) + if (std::fabs(trackBach.dcaXY()) < cMinCascBachDCArToPVcut) return false; - if (fabs(trackBach.dcaXY()) > cMaxCascBachDCArToPVcut) + if (std::fabs(trackBach.dcaXY()) > cMaxCascBachDCArToPVcut) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodCascIndices"), 2.5); // DCA daugthers @@ -287,7 +494,7 @@ struct reso2initializer { return false; if (casc.dcacascdaughters() > cMaxCascDCACascDaughters) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodCascIndices"), 3.5); // CPA cuts @@ -295,34 +502,34 @@ struct reso2initializer { return false; if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < cMinCascV0CosPA) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodCascIndices"), 4.5); // V0 radius auto v0radius = casc.v0radius(); if ((v0radius > cMaxCascV0Radius) || (v0radius < cMinCascV0Radius)) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodCascIndices"), 5.5); // Casc radius auto cascradius = casc.cascradius(); if ((cascradius > cMaxCascRadius) || (cascradius < cMinCascRadius)) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodCascIndices"), 6.5); // Casc mass auto cascMass = casc.mXi(); - if (abs(cascMass - cXiMass) > cCascMassResol) + if (std::abs(cascMass - MassXiMinus) > cCascMassResol) return false; - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodCascIndices"), 7.5); // MC case can be handled here if constexpr (isMC) { // MC check - if (ConfFillQA) + if (cfgFillQA) qaRegistry.fill(HIST("hGoodMCCascIndices"), 0.5); } return true; @@ -330,9 +537,9 @@ struct reso2initializer { // Check if the collision is INEL>0 template - bool IsTrueINEL0(MCColl const& /*mccoll*/, MCPart const& mcparts) + bool isTrueINEL0(MCColl const& /*mccoll*/, MCPart const& mcparts) { - for (auto& mcparticle : mcparts) { + for (auto const& mcparticle : mcparts) { if (!mcparticle.isPhysicalPrimary()) continue; auto p = pdg->GetParticle(mcparticle.pdgCode()); @@ -348,7 +555,7 @@ struct reso2initializer { // Centralicity estimator selection template - float CentEst(ResoColl ResoEvents) + float centEst(ResoColl ResoEvents) { float returnValue = -999.0; switch (multEstimator) { @@ -361,9 +568,6 @@ struct reso2initializer { case 2: returnValue = ResoEvents.centFT0A(); break; - case 99: - returnValue = ResoEvents.centFV0A(); - break; default: returnValue = ResoEvents.centFT0M(); break; @@ -378,7 +582,7 @@ struct reso2initializer { /// \param tracks All tracks /// \return value of the spherocity of the event template - float ComputeSpherocity(T const& tracks, int nTracksMin, int spdef) + float computeSpherocity(T const& tracks, int nTracksMin, int spdef) { // if number of tracks is not enough for spherocity estimation. int ntrks = tracks.size(); @@ -389,7 +593,7 @@ struct reso2initializer { float ptSum = 0.; for (auto const& track : tracks) { - if (ConfFillQA) { + if (cfgFillQA) { qaRegistry.fill(HIST("Phi"), track.phi()); } if (spdef == 0) { @@ -402,39 +606,39 @@ struct reso2initializer { 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); + 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 * TMath::Cos(phi); - float py = pt * TMath::Sin(phi); + float px = pt * std::cos(phi); + float py = pt * std::sin(phi); // sum += pt * abs(sin(phiparm - phi)); - sum += TMath::Abs(px * ny - py * nx); + sum += std::abs(px * ny - py * nx); } - float sph = TMath::Power((sum / ptSum), 2); + float sph = std::pow((sum / ptSum), 2); if (sph < tempSph) tempSph = sph; } - return TMath::Power(TMath::Pi() / 2., 2) * tempSph; + return std::pow(PIHalf, 2) * tempSph; } template - float GetEvtPl(ResoColl ResoEvents) + 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); + 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 getEvtPlRes(ResoColl ResoEvents, int a, int b) { float returnValue = -999.0; if (ResoEvents.qvecAmp()[a] < 1e-8 || ResoEvents.qvecAmp()[b] < 1e-8) @@ -442,51 +646,85 @@ struct reso2initializer { 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::resomicrodaughter::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::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaPi()), std::abs(track.tofNSigmaPi()), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaKa()), std::abs(track.tofNSigmaKa()), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter::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& track : tracks) { - if (!IsTrackSelected(collision, track)) + 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(), - 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.hasITS(), - track.hasTPC(), - track.hasTOF(), - track.tpcNSigmaPi(), - track.tpcNSigmaKa(), - track.tpcNSigmaPr(), - track.tpcNSigmaEl(), - track.tofNSigmaPi(), - track.tofNSigmaKa(), - track.tofNSigmaPr(), - track.tofNSigmaEl(), - track.tpcSignal(), - track.passedITSRefit(), - track.passedTPCRefit(), - track.isGlobalTrackWoDCA(), - track.isGlobalTrack(), - track.isPrimaryTrack(), - track.isPVContributor(), - track.tpcCrossedRowsOverFindableCls(), - track.itsChi2NCl(), - track.tpcChi2NCl()); + 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); } @@ -498,19 +736,31 @@ struct reso2initializer { 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)) + 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(), - v0.eta(), - v0.phi(), 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(), @@ -520,6 +770,9 @@ struct reso2initializer { v0.mAntiLambda(), v0.mK0Short(), v0.v0radius(), v0.x(), v0.y(), v0.z()); + if (!cfgBypassTrackIndexFill) { + resoV0V0s(v0.globalIndex()); + } if constexpr (isMC) { fillMCV0(v0); } @@ -531,20 +784,38 @@ struct reso2initializer { 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)) + 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(), - casc.eta(), - casc.phi(), 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(), @@ -556,8 +827,12 @@ struct reso2initializer { 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); } @@ -570,7 +845,7 @@ struct reso2initializer { // ------ Temporal lambda function to prevent error in build auto getMothersIndeces = [&](auto const& theMcParticle) { std::vector lMothersIndeces{}; - for (auto& lMother : theMcParticle.template mothers_as()) { + for (auto const& lMother : theMcParticle.template mothers_as()) { LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); lMothersIndeces.push_back(lMother.globalIndex()); } @@ -578,7 +853,7 @@ struct reso2initializer { }; auto getMothersPDGCodes = [&](auto const& theMcParticle) { std::vector lMothersPDGs{}; - for (auto& lMother : theMcParticle.template mothers_as()) { + for (auto const& lMother : theMcParticle.template mothers_as()) { LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); lMothersPDGs.push_back(lMother.pdgCode()); } @@ -586,9 +861,9 @@ struct reso2initializer { }; auto getSiblingsIndeces = [&](auto const& theMcParticle) { std::vector lSiblingsIndeces{}; - for (auto& lMother : theMcParticle.template mothers_as()) { + for (auto const& lMother : theMcParticle.template mothers_as()) { LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); - for (auto& lDaughter : lMother.template daughters_as()) { + 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()); @@ -601,7 +876,7 @@ struct reso2initializer { std::vector mothers = {-1, -1}; std::vector motherPDGs = {-1, -1}; int siblings[2] = {0, 0}; - std::vector siblings_temp = {-1, -1}; + std::vector siblingsTemp = {-1, -1}; if (track.has_mcParticle()) { // // Get the MC particle @@ -609,16 +884,16 @@ struct reso2initializer { if (particle.has_mothers()) { mothers = getMothersIndeces(particle); motherPDGs = getMothersPDGCodes(particle); - siblings_temp = getSiblingsIndeces(particle); + siblingsTemp = 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]; + if (siblingsTemp.size() > 0) + siblings[0] = siblingsTemp[0]; + if (siblingsTemp.size() > 1) + siblings[1] = siblingsTemp[1]; reso2mctracks(particle.pdgCode(), mothers[0], motherPDGs[0], @@ -642,7 +917,7 @@ struct reso2initializer { // ------ Temporal lambda function to prevent error in build auto getMothersIndeces = [&](auto const& theMcParticle) { std::vector lMothersIndeces{}; - for (auto& lMother : theMcParticle.template mothers_as()) { + for (auto const& lMother : theMcParticle.template mothers_as()) { LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); lMothersIndeces.push_back(lMother.globalIndex()); } @@ -650,7 +925,7 @@ struct reso2initializer { }; auto getMothersPDGCodes = [&](auto const& theMcParticle) { std::vector lMothersPDGs{}; - for (auto& lMother : theMcParticle.template mothers_as()) { + for (auto const& lMother : theMcParticle.template mothers_as()) { LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); lMothersPDGs.push_back(lMother.pdgCode()); } @@ -658,7 +933,7 @@ struct reso2initializer { }; auto getDaughtersIndeces = [&](auto const& theMcParticle) { std::vector lDaughtersIndeces{}; - for (auto& lDaughter : theMcParticle.template daughters_as()) { + 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()); @@ -668,7 +943,7 @@ struct reso2initializer { }; auto getDaughtersPDGCodes = [&](auto const& theMcParticle) { std::vector lDaughtersPDGs{}; - for (auto& lDaughter : theMcParticle.template daughters_as()) { + 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()); @@ -728,7 +1003,7 @@ struct reso2initializer { // ------ Temporal lambda function to prevent error in build auto getMothersIndeces = [&](auto const& theMcParticle) { std::vector lMothersIndeces{}; - for (auto& lMother : theMcParticle.template mothers_as()) { + for (auto const& lMother : theMcParticle.template mothers_as()) { LOGF(debug, " mother index lMother: %d", lMother.globalIndex()); lMothersIndeces.push_back(lMother.globalIndex()); } @@ -736,7 +1011,7 @@ struct reso2initializer { }; auto getMothersPDGCodes = [&](auto const& theMcParticle) { std::vector lMothersPDGs{}; - for (auto& lMother : theMcParticle.template mothers_as()) { + for (auto const& lMother : theMcParticle.template mothers_as()) { LOGF(debug, " mother pdgcode lMother: %d", lMother.pdgCode()); lMothersPDGs.push_back(lMother.pdgCode()); } @@ -744,7 +1019,7 @@ struct reso2initializer { }; auto getDaughtersIndeces = [&](auto const& theMcParticle) { std::vector lDaughtersIndeces{}; - for (auto& lDaughter : theMcParticle.template daughters_as()) { + 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()); @@ -754,7 +1029,7 @@ struct reso2initializer { }; auto getDaughtersPDGCodes = [&](auto const& theMcParticle) { std::vector lDaughtersPDGs{}; - for (auto& lDaughter : theMcParticle.template daughters_as()) { + 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()); @@ -811,7 +1086,7 @@ struct reso2initializer { template void fillMCParticles(SelectedMCPartType const& mcParts, TotalMCParts const& mcParticles) { - for (auto& mcPart : mcParts) { + for (auto const& mcPart : mcParts) { std::vector daughterPDGs; if (mcPart.has_daughters()) { auto daughter01 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[0] - mcParticles.offset()); @@ -830,9 +1105,9 @@ struct reso2initializer { mcPart.px(), mcPart.py(), mcPart.pz(), - mcPart.eta(), - mcPart.phi(), - mcPart.y()); + mcPart.y(), + mcPart.e(), + mcPart.statusCode()); daughterPDGs.clear(); } } @@ -842,11 +1117,11 @@ struct reso2initializer { { auto centrality = 0.0; if constexpr (!isRun2) - centrality = CentEst(mccol); + centrality = centEst(mccol); else centrality = mccol.centRun2V0M(); - bool inVtx10 = (abs(mccol.mcCollision().posZ()) > 10.) ? false : true; - bool isTrueINELgt0 = IsTrueINEL0(mccol, mcparts); + 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); @@ -894,9 +1169,8 @@ struct reso2initializer { void init(InitContext&) { - cXiMass = pdg->GetParticle(3312)->Mass(); mRunNumber = 0; - d_bz = 0; + dBz = 0; // Multiplicity estimator selection (0: FT0M, 1: FT0C, 2: FT0A, 99: FV0A) if (cfgMultName.value == "FT0M") { multEstimator = 0; @@ -922,19 +1196,26 @@ struct reso2initializer { // Case selector based on the process. if (doprocessTrackDataRun2 || doprocessTrackV0DataRun2 || doprocessTrackV0CascDataRun2 || doprocessTrackMCRun2 || doprocessTrackV0MCRun2 || doprocessTrackV0CascMCRun2) { - colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtTriggerSel, ConfEvtOfflineCheck, false); + colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, false); } else if (doprocessTrackData || doprocessTrackV0Data || doprocessTrackV0CascData || doprocessTrackMC || doprocessTrackV0MC || doprocessTrackV0CascMC || doprocessTrackEPData) { - colCuts.setCuts(ConfEvtZvtx, ConfEvtTriggerCheck, ConfEvtTriggerSel, ConfEvtOfflineCheck, true, false, ConfEvtOccupancyInTimeRange); + colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, EventCuts.cfgEvtOccupancyInTimeRangeMax, EventCuts.cfgEvtOccupancyInTimeRangeMin); } colCuts.init(&qaRegistry); - colCuts.setTriggerTVX(ConfEvtTriggerTVXSel); - colCuts.setApplyTFBorderCut(ConfEvtTFBorderCut); - colCuts.setApplyITSTPCvertex(ConfEvtUseITSTPCvertex); - colCuts.setApplyZvertexTimedifference(ConfEvtZvertexTimedifference); - colCuts.setApplyPileupRejection(ConfEvtPileupRejection); - colCuts.setApplyNoITSROBorderCut(ConfEvtNoITSROBorderCut); - if (!ConfBypassCCDB) { - ccdb->setURL(ccdburl.value); + 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); @@ -949,7 +1230,7 @@ struct reso2initializer { qaRegistry.add("Event/hMCEventIndices", "hMCEventIndices", kTH2D, {centAxis, idxMCAxis}); } AxisSpec idxAxis = {8, 0, 8, "Index"}; - if (ConfFillQA) { + if (cfgFillQA) { qaRegistry.add("hGoodTrackIndices", "hGoodTrackIndices", kTH1F, {idxAxis}); qaRegistry.add("hGoodMCTrackIndices", "hGoodMCTrackIndices", kTH1F, {idxAxis}); qaRegistry.add("hGoodV0Indices", "hGoodV0Indices", kTH1F, {idxAxis}); @@ -962,47 +1243,52 @@ struct reso2initializer { void initCCDB(aod::BCsWithTimestamps::iterator const& bc) // Simple copy from LambdaKzeroFinder.cxx { - if (ConfBypassCCDB) + if (cfgBypassCCDB) 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; + if (dBzInput > -990) { + dBz = dBzInput; ; o2::parameters::GRPMagField grpmag; - if (fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + if (std::fabs(dBz) > 1e-5) { + grpmag.setL3Current(30000.f / (dBz / 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); + 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 - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3GRPTimestamp << " with magnetic field of " << dBz << " kZG"; } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + 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 " << run3grp_timestamp; + 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 - 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"; + 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: ", d_bz, mRunNumber); + 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, @@ -1013,30 +1299,49 @@ struct reso2initializer { // 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), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); + 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(reso2initializer, processTrackData, "Process for data", true); + PROCESS_SWITCH(ResonanceInitializer, processTrackData, "Process for data", false); void processTrackDataRun2(ResoRun2Events::iterator const& collision, soa::Filtered const& tracks, - aod::BCsWithTimestamps const&) + BCsWithRun2Info const&) { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); + // 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(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); + 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(reso2initializer, processTrackDataRun2, "Process for data", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackDataRun2, "Process for data", false); void processTrackEPData(soa::Join::iterator const& collision, soa::Filtered const& tracks, @@ -1047,13 +1352,22 @@ struct reso2initializer { // 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), ComputeSpherocity(tracks, trackSphMin, trackSphDef), GetEvtPl(collision), GetEvtPlRes(collision, EvtPlDetId, EvtPlRefAId), GetEvtPlRes(collision, EvtPlDetId, EvtPlRefBId), GetEvtPlRes(collision, EvtPlRefAId, EvtPlRefBId), d_bz, bc.timestamp()); - + 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(reso2initializer, processTrackEPData, "Process for data and ep ana", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackEPData, "Process for data and ep ana", false); void processTrackV0Data(ResoEvents::iterator const& collision, soa::Filtered const& tracks, @@ -1065,33 +1379,50 @@ struct reso2initializer { // 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), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); + 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(reso2initializer, processTrackV0Data, "Process for data", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackV0Data, "Process for data", false); void processTrackV0DataRun2(ResoRun2Events::iterator const& collision, soa::Filtered const& tracks, ResoV0s const& V0s, - aod::BCsWithTimestamps const&) + BCsWithRun2Info const&) { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); + // 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(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); + 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(reso2initializer, processTrackV0DataRun2, "Process for data", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackV0DataRun2, "Process for data", false); void processTrackV0CascData(ResoEvents::iterator const& collision, soa::Filtered const& tracks, @@ -1104,36 +1435,52 @@ struct reso2initializer { // 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), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - + 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(reso2initializer, processTrackV0CascData, "Process for data", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackV0CascData, "Process for data", false); void processTrackV0CascDataRun2(ResoRun2Events::iterator const& collision, soa::Filtered const& tracks, ResoV0s const& V0s, ResoCascades const& Cascades, - aod::BCsWithTimestamps const&) + BCsWithRun2Info const&) { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); + // 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(), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); + 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(reso2initializer, processTrackV0CascDataRun2, "Process for data", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackV0CascDataRun2, "Process for data", false); Preslice perMcCollision = aod::mcparticle::mcCollisionId; void processTrackMC(soa::Join::iterator const& collision, @@ -1142,22 +1489,31 @@ struct reso2initializer { { 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), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); - + 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(reso2initializer, processTrackMC, "Process for MC", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackMC, "Process for MC", false); void processTrackEPMC(soa::Join::iterator const& collision, aod::McCollisions const&, soa::Filtered const& tracks, @@ -1165,39 +1521,55 @@ struct reso2initializer { { 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), ComputeSpherocity(tracks, trackSphMin, trackSphDef), GetEvtPl(collision), GetEvtPlRes(collision, EvtPlDetId, EvtPlRefAId), GetEvtPlRes(collision, EvtPlDetId, EvtPlRefBId), GetEvtPlRes(collision, EvtPlRefAId, EvtPlRefBId), d_bz, bc.timestamp()); + 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(reso2initializer, processTrackEPMC, "Process for MC and ep ana", false); + 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, aod::BCsWithTimestamps const&) + aod::McParticles const& mcParticles, BCsWithRun2Info const&) { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); + // auto bc = collision.bc_as(); 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()); + 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(reso2initializer, processTrackMCRun2, "Process for MC", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackMCRun2, "Process for MC", false); void processTrackV0MC(soa::Join::iterator const& collision, aod::McCollisions const&, soa::Filtered const& tracks, @@ -1206,42 +1578,59 @@ struct reso2initializer { { 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), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); + 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(reso2initializer, processTrackV0MC, "Process for MC", false); + 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, aod::BCsWithTimestamps const&) + aod::McParticles const& mcParticles, BCsWithRun2Info const&) { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); + // auto bc = collision.bc_as(); 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()); + 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(reso2initializer, processTrackV0MCRun2, "Process for MC", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackV0MCRun2, "Process for MC", false); void processTrackV0CascMC(soa::Join::iterator const& collision, aod::McCollisions const&, soa::Filtered const& tracks, @@ -1251,14 +1640,23 @@ struct reso2initializer { { 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), ComputeSpherocity(tracks, trackSphMin, trackSphDef), 0., 0., 0., 0., d_bz, bc.timestamp()); + 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); - fillV0s(collision, V0s, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } fillV0s(collision, V0s, tracks); fillCascades(collision, Cascades, tracks); @@ -1266,24 +1664,30 @@ struct reso2initializer { auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); fillMCParticles(mcParts, mcParticles); } - PROCESS_SWITCH(reso2initializer, processTrackV0CascMC, "Process for MC", false); + 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, aod::BCsWithTimestamps const&) + aod::McParticles const& mcParticles, BCsWithRun2Info const&) { - auto bc = collision.bc_as(); /// adding timestamp to access magnetic field later - initCCDB(bc); + // auto bc = collision.bc_as(); 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()); + 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); - fillV0s(collision, V0s, tracks); + if (cfgFillMicroTracks) { + fillMicroTracks(collision, tracks); + } fillV0s(collision, V0s, tracks); fillCascades(collision, Cascades, tracks); @@ -1291,12 +1695,12 @@ struct reso2initializer { auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); fillMCParticles(mcParts, mcParticles); } - PROCESS_SWITCH(reso2initializer, processTrackV0CascMCRun2, "Process for MC", false); + PROCESS_SWITCH(ResonanceInitializer, processTrackV0CascMCRun2, "Process for MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"lf-reso2initializer"}), + adaptAnalysisTask(cfgc), }; } diff --git a/PWGLF/TableProducer/Resonances/resonanceMergeDF.cxx b/PWGLF/TableProducer/Resonances/resonanceMergeDF.cxx new file mode 100644 index 00000000000..50315d864cd --- /dev/null +++ b/PWGLF/TableProducer/Resonances/resonanceMergeDF.cxx @@ -0,0 +1,585 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.h" + +#include "Common/Core/EventPlaneHelper.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/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include + +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; + std::vector>> + vecOfVecOfTuplesCasc; + 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(), + (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 processTrackDataDFCasc(aod::ResoCollisions::iterator const& collision, aod::ResoTracks const& tracks, aod::ResoCascades const& trackCascs) + { + + int nCollisions = nDF; + vecOfTuples.push_back(std::make_tuple(collision.posX(), collision.posY(), collision.posZ(), collision.cent(), 0, 0, 0)); + std::vector> + innerVector; + std::vector> + innerVectorCasc; + 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(), + (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())); + } + + for (const auto& trackCasc : trackCascs) { + innerVectorCasc.push_back(std::make_tuple( + trackCasc.pt(), + trackCasc.px(), + trackCasc.py(), + trackCasc.pz(), + const_cast(trackCasc.cascadeIndices()), + (int8_t)(trackCasc.daughterTPCNSigmaPosPi() * 10), + (int8_t)(trackCasc.daughterTPCNSigmaPosKa() * 10), + (int8_t)(trackCasc.daughterTPCNSigmaPosPr() * 10), + (int8_t)(trackCasc.daughterTPCNSigmaNegPi() * 10), + (int8_t)(trackCasc.daughterTPCNSigmaNegKa() * 10), + (int8_t)(trackCasc.daughterTPCNSigmaNegPr() * 10), + (int8_t)(trackCasc.daughterTPCNSigmaBachPi() * 10), + (int8_t)(trackCasc.daughterTPCNSigmaBachKa() * 10), + (int8_t)(trackCasc.daughterTPCNSigmaBachPr() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaPosPi() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaPosKa() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaPosPr() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaNegPi() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaNegKa() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaNegPr() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaBachPi() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaBachKa() * 10), + (int8_t)(trackCasc.daughterTOFNSigmaBachPr() * 10), + trackCasc.v0CosPA(), + trackCasc.cascCosPA(), + trackCasc.daughDCA(), + trackCasc.cascDaughDCA(), + trackCasc.dcapostopv(), + trackCasc.dcanegtopv(), + trackCasc.dcabachtopv(), + trackCasc.dcav0topv(), + trackCasc.dcaXYCascToPV(), + trackCasc.dcaZCascToPV(), + trackCasc.sign(), + trackCasc.mLambda(), + trackCasc.mXi(), + trackCasc.transRadius(), trackCasc.cascTransRadius(), trackCasc.decayVtxX(), trackCasc.decayVtxY(), trackCasc.decayVtxZ())); + } + + vecOfVecOfTuples.push_back(innerVector); + vecOfVecOfTuplesCasc.push_back(innerVectorCasc); + innerVector.clear(); + innerVectorCasc.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]; + const auto& innerVectorCasc = vecOfVecOfTuplesCasc[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)); + } + + for (const auto& tuple : innerVectorCasc) { + reso2cascadesdf(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), + std::get<28>(tuple), + std::get<29>(tuple), + std::get<30>(tuple), + std::get<31>(tuple), + std::get<32>(tuple), + std::get<33>(tuple), + std::get<34>(tuple), + std::get<35>(tuple), + std::get<36>(tuple), + std::get<37>(tuple), + std::get<38>(tuple), + std::get<39>(tuple), + std::get<40>(tuple)); + } + } + + vecOfTuples.clear(); + vecOfVecOfTuples.clear(); + vecOfVecOfTuplesCasc.clear(); // + } + + PROCESS_SWITCH(ResonanceMergeDF, processTrackDataDFCasc, "Process for data merged DF for cascade", false); + + 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..a1ade00c627 --- /dev/null +++ b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx @@ -0,0 +1,1413 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/collisionCuts.h" + +#include "Common/Core/EventPlaneHelper.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/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include + +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::resomicrodaughter::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::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaPi()), std::abs(track.tofNSigmaPi()), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaKa()), std::abs(track.tofNSigmaKa()), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter::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/Resonances/resonanceTreeCreator.cxx b/PWGLF/TableProducer/Resonances/resonanceTreeCreator.cxx new file mode 100644 index 00000000000..5e40583229a --- /dev/null +++ b/PWGLF/TableProducer/Resonances/resonanceTreeCreator.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 resonanceTreeCreator.cxx +/// \brief Produces a TTree with machine learning variables for resonances in the LF group +/// \author Stefano Cannito (stefano.cannito@cern.ch) + +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace resomlcandidates +{ +// Multiplicity class +DECLARE_SOA_COLUMN(MultClass, multClass, float); //! Event multiplicity class +// Daughter 1 +DECLARE_SOA_COLUMN(PtDaughter1, ptdaughter1, float); //! Transverse momentum of daughter1 (GeV/c) +DECLARE_SOA_COLUMN(PDaughter1, pdaughter1, float); //! Momentum of daughter1 (GeV/c) +DECLARE_SOA_COLUMN(PhiDaughter1, phiDaughter1, float); //! Azimuthal angle of daughter1 (rad) +DECLARE_SOA_COLUMN(EtaDaughter1, etaDaughter1, float); //! Pseudorapidity of daughter1 +DECLARE_SOA_COLUMN(YDaughter1, yDaughter1, float); //! Rapidity of daughter1 +DECLARE_SOA_COLUMN(DCAxyDaughter1, dcaDaughter1, float); //! DCA of daughter1 to primary vertex (cm) +DECLARE_SOA_COLUMN(DCAzDaughter1, dcaZDaughter1, float); //! DCA of daughter1 to primary vertex in z (cm) +DECLARE_SOA_COLUMN(NSigTpcPi1, nSigTpcPi1, float); //! TPC Nsigma separation for daughter1 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcKa1, nSigTpcKa1, float); //! TPC Nsigma separation for daughter1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPi1, nSigTofPi1, float); //! TOF Nsigma separation for daughter1 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofKa1, nSigTofKa1, float); //! TOF Nsigma separation for daughter1 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPi1, nSigTpcTofPi1, float); //! TPC and TOF combined Nsigma separation for daughter1 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofKa1, nSigTpcTofKa1, float); //! TPC and TOF combined Nsigma separation for daughter1 with kaon mass hypothesis +// Daughter 2 +DECLARE_SOA_COLUMN(PtDaughter2, ptdaughter2, float); //! Transverse momentum of daughter2 (GeV/c) +DECLARE_SOA_COLUMN(PDaughter2, pdaughter2, float); //! Momentum of daughter2 (in GeV/c) +DECLARE_SOA_COLUMN(PhiDaughter2, phiDaughter2, float); //! Azimuthal angle of daughter2 (rad) +DECLARE_SOA_COLUMN(EtaDaughter2, etaDaughter2, float); //! Pseudorapidity of daughter2 +DECLARE_SOA_COLUMN(YDaughter2, yDaughter2, float); //! Rapidity of daughter2 +DECLARE_SOA_COLUMN(DCAxyDaughter2, dcaDaughter2, float); //! DCA of daughter2 to primary vertex (cm) +DECLARE_SOA_COLUMN(DCAzDaughter2, dcaZDaughter2, float); //! DCA of daughter2 to primary vertex in z (cm) +DECLARE_SOA_COLUMN(NSigTpcPi2, nSigTpcPi2, float); //! TPC Nsigma separation for daughter2 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcKa2, nSigTpcKa2, float); //! TPC Nsigma separation for daughter2 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTofPi2, nSigTofPi2, float); //! TOF Nsigma separation for daughter2 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTofKa2, nSigTofKa2, float); //! TOF Nsigma separation for daughter2 with kaon mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofPi2, nSigTpcTofPi2, float); //! TPC and TOF combined Nsigma separation for daughter2 with pion mass hypothesis +DECLARE_SOA_COLUMN(NSigTpcTofKa2, nSigTpcTofKa2, float); //! TPC and TOF combined Nsigma separation for daughter2 with kaon mass hypothesis +// Candidate +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(Phi, phi, float); //! Azimuth angle of candidate +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate +DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate +DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign of the candidate +DECLARE_SOA_COLUMN(IsTruePhi, isTruePhi, bool); //! Flag to indicate if the candidate is a phi meson +} // namespace resomlcandidates + +DECLARE_SOA_TABLE(ResoCandidates, "AOD", "RESOCANDIDATES", + resomlcandidates::M, + resomlcandidates::Pt, + resomlcandidates::P, + resomlcandidates::Phi, + resomlcandidates::Eta, + resomlcandidates::Y, + resomlcandidates::Sign, + resomlcandidates::IsTruePhi); + +DECLARE_SOA_TABLE(ResoMLCandidates, "AOD", "RESOMLCANDIDATES", + resomlcandidates::MultClass, + resomlcandidates::PtDaughter1, + resomlcandidates::PDaughter1, + resomlcandidates::PhiDaughter1, + resomlcandidates::EtaDaughter1, + resomlcandidates::YDaughter1, + resomlcandidates::DCAxyDaughter1, + resomlcandidates::DCAzDaughter1, + resomlcandidates::NSigTpcPi1, + resomlcandidates::NSigTpcKa1, + resomlcandidates::NSigTofPi1, + resomlcandidates::NSigTofKa1, + resomlcandidates::NSigTpcTofPi1, + resomlcandidates::NSigTpcTofKa1, + resomlcandidates::PtDaughter2, + resomlcandidates::PDaughter2, + resomlcandidates::PhiDaughter2, + resomlcandidates::EtaDaughter2, + resomlcandidates::YDaughter2, + resomlcandidates::DCAxyDaughter2, + resomlcandidates::DCAzDaughter2, + resomlcandidates::NSigTpcPi2, + resomlcandidates::NSigTpcKa2, + resomlcandidates::NSigTofPi2, + resomlcandidates::NSigTofKa2, + resomlcandidates::NSigTpcTofPi2, + resomlcandidates::NSigTpcTofKa2, + resomlcandidates::M, + resomlcandidates::Pt, + resomlcandidates::P, + resomlcandidates::Phi, + resomlcandidates::Eta, + resomlcandidates::Y, + resomlcandidates::Sign); + +namespace resomlselection +{ +DECLARE_SOA_COLUMN(PhiBDTScore, gammaBDTScore, float); +} // namespace resomlselection + +DECLARE_SOA_TABLE(ResoPhiMLSelection, "AOD", "RESOPHIMLSELECTION", + resomlselection::PhiBDTScore); +} // namespace o2::aod + +struct resonanceTreeCreator { + // Production of the TTree + Produces resoCandidates; + Produces resoMLCandidates; + + // Configurables for track selection + Configurable cfgCutCharge{"cfgCutCharge", 0.0f, "Cut on the signed transverse momentum to select positive or negative tracks"}; + + // Configurables 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", 0.5f, "Fraction of background candidates to keep for ML trainings"}; + Configurable ptMaxForDownSample{"ptMaxForDownSample", 10.0f, "Maximum pt for the application of the downsampling factor"}; + + // Defining the type of the collisions for data and MC + using SelCollisions = soa::Join; + using SimCollisions = soa::Join; + + // Defining the type of the tracks for data and MC + using FullTracks = soa::Join; + using FullMCTracks = soa::Join; + + Partition posTracks = aod::track::signed1Pt > cfgCutCharge; + Partition negTracks = aod::track::signed1Pt < cfgCutCharge; + + Partition posMCTracks = aod::track::signed1Pt > cfgCutCharge; + Partition negMCTracks = aod::track::signed1Pt < cfgCutCharge; + + Preslice perColl = aod::track::collisionId; + Preslice perMCColl = aod::mcparticle::mcCollisionId; + + // Necessary to flag INEL>0 events in GenMC + Service pdgDB; + + // Cache for manual slicing + SliceCache cache; + + enum ParticleType { + Pi, + Ka, + Pr + }; + + // Constants + double massPi = o2::constants::physics::MassPiPlus; + double massKa = o2::constants::physics::MassKPlus; + + void init(InitContext&) + { + } + + // Combine Nsigma values from TPC and TOF + template + float combineNSigma(const T& track) + { + float nSigmaTPC, nSigmaTOF; + switch (massHypo) { + case Pi: + nSigmaTPC = track.tpcNSigmaPi(); + nSigmaTOF = track.tofNSigmaPi(); + break; + case Ka: + nSigmaTPC = track.tpcNSigmaKa(); + nSigmaTOF = track.tofNSigmaKa(); + break; + case Pr: + nSigmaTPC = track.tpcNSigmaPr(); + nSigmaTOF = track.tofNSigmaPr(); + break; + default: + break; + } + + static constexpr float defaultNSigmaTolerance = .1f; + static constexpr float defaultNSigma = -999.f + defaultNSigmaTolerance; + + if (nSigmaTPC > defaultNSigma && nSigmaTOF > defaultNSigma) + return std::sqrt(0.5f * std::pow(nSigmaTPC, 2) + std::pow(nSigmaTOF, 2)); + if (nSigmaTPC > defaultNSigma) + return std::abs(nSigmaTPC); + if (nSigmaTOF > defaultNSigma) + return std::abs(nSigmaTOF); + return nSigmaTPC; + } + + // Reconstruct the candidate 4-momentum from two daughter tracks + template + ROOT::Math::PxPyPzMVector recMother(const T& track1, const T& track2, float masstrack1, float masstrack2) + { + ROOT::Math::PxPyPzMVector daughter1(track1.px(), track1.py(), track1.pz(), masstrack1); // set the daughter1 4-momentum + ROOT::Math::PxPyPzMVector daughter2(track2.px(), track2.py(), track2.pz(), masstrack2); // set the daughter2 4-momentum + ROOT::Math::PxPyPzMVector mother = daughter1 + daughter2; // calculate the mother 4-momentum + + return mother; + } + + template + void fillCandidateTree4ML(const T1& collision, const T2& track1, const T2& track2, float masstrack1, float masstrack2 + /*std::optional> mcParticles = std::nullopt*/) + { + auto tpctofPi1 = combineNSigma(track1); + auto tpctofKa1 = combineNSigma(track1); + auto tpctofPi2 = combineNSigma(track2); + auto tpctofKa2 = combineNSigma(track2); + + ROOT::Math::PxPyPzMVector recCandidate = recMother(track1, track2, masstrack1, masstrack2); + + if (downSampleBkgFactor < 1.) { + float pseudoRndm = track1.pt() * 1000. - static_cast(track1.pt() * 1000); + if (recCandidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) + return; + } + + resoMLCandidates(collision.centFT0M(), + track1.pt(), track1.p(), track1.phi(), track1.eta(), track1.rapidity(masstrack1), track1.dcaXY(), track1.dcaZ(), + track1.tpcNSigmaPi(), track1.tpcNSigmaKa(), track1.tofNSigmaPi(), track1.tofNSigmaKa(), tpctofPi1, tpctofKa1, + track2.pt(), track2.p(), track2.phi(), track2.eta(), track2.rapidity(masstrack2), track2.dcaXY(), track2.dcaZ(), + track2.tpcNSigmaPi(), track2.tpcNSigmaKa(), track2.tofNSigmaPi(), track2.tofNSigmaKa(), tpctofPi2, tpctofKa2, + recCandidate.M(), recCandidate.Pt(), recCandidate.P(), recCandidate.Phi(), + recCandidate.Eta(), recCandidate.Rapidity(), track1.sign() + track2.sign()); + } + + template + bool isMCPhi(const T& track1, const T& track2, const aod::McParticles& mcParticles) + { + if (!track1.has_mcParticle() || !track2.has_mcParticle()) + return false; // Skip filling if no MC truth is available for both tracks + + auto mcTrack1 = mcParticles.rawIteratorAt(track1.mcParticleId()); + auto mcTrack2 = mcParticles.rawIteratorAt(track2.mcParticleId()); + + if (mcTrack1.pdgCode() != PDG_t::kKPlus || !mcTrack1.isPhysicalPrimary()) + return false; // Skip filling if the first track is not a primary K+ + if (mcTrack2.pdgCode() != PDG_t::kKMinus || !mcTrack2.isPhysicalPrimary()) + return false; // Skip filling if the second track is not a primary K- + + const auto mcTrack1MotherIndexes = mcTrack1.mothersIds(); + const auto mcTrack2MotherIndexes = mcTrack2.mothersIds(); + + for (const auto& mcTrack1MotherIndex : mcTrack1MotherIndexes) { + for (const auto& mcTrack2MotherIndex : mcTrack2MotherIndexes) { + if (mcTrack1MotherIndex != mcTrack2MotherIndex) + continue; + + const auto mother = mcParticles.rawIteratorAt(mcTrack1MotherIndex); + if (mother.pdgCode() == o2::constants::physics::Pdg::kPhi) + return true; + } + } + return false; + } + + void processData4ML(SelCollisions::iterator const& collision, FullTracks const&) + { + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + for (const auto& track1 : posThisColl) { + for (const auto& track2 : negThisColl) { + // Fill the ResoMLCandidates table with candidates in Data + fillCandidateTree4ML(collision, track1, track2, massKa, massKa); + } + } + } + + PROCESS_SWITCH(resonanceTreeCreator, processData4ML, "Fill ResoMLCandidates in Data", true); + + void processMC4ML(SimCollisions::iterator const& collision, FullMCTracks const&, aod::McParticles const& mcParticles) + { + auto posThisColl = posMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negMCTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + for (const auto& track1 : posThisColl) { + for (const auto& track2 : negThisColl) { + if (fillOnlySignal && !isMCPhi(track1, track2, mcParticles)) + return; // Skip filling if only signal is requested and not a phi in MC truth + if (fillOnlyBackground && isMCPhi(track1, track2, mcParticles)) + return; // Skip filling if only background is requested and a phi in MC truth + + // Fill the ResoMLCandidates table with candidates in MC + fillCandidateTree4ML(collision, track1, track2, massKa, massKa); + } + } + } + + PROCESS_SWITCH(resonanceTreeCreator, processMC4ML, "Fill ResoMLCandidates in MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/CMakeLists.txt b/PWGLF/TableProducer/Strangeness/CMakeLists.txt index a4f8061f68d..a6e7b8d94a1 100644 --- a/PWGLF/TableProducer/Strangeness/CMakeLists.txt +++ b/PWGLF/TableProducer/Strangeness/CMakeLists.txt @@ -36,8 +36,8 @@ o2physics_add_dpl_workflow(cascademcfinder PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(cascadepid - SOURCES cascadepid.cxx +o2physics_add_dpl_workflow(strangenesstofpid + SOURCES strangenesstofpid.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) @@ -53,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::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(lambdakzerobuilder @@ -76,18 +81,18 @@ o2physics_add_dpl_workflow(lambdakzeromcfinder PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(lambdakzeropid - SOURCES lambdakzeropid.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(lambdakzerospawner SOURCES lambdakzerospawner.cxx 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(strange-tree-creator - SOURCES LFStrangeTreeCreator.cxx + SOURCES strangeTreeCreator.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -101,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 O2Physics::MLCore + 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 @@ -122,7 +142,34 @@ 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) \ No newline at end of file + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore O2Physics::AnalysisCCDB + 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) + +o2physics_add_dpl_workflow(lambdaspincorrelation + SOURCES lambdaspincorrelation.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +if(FastJet_FOUND) + o2physics_add_dpl_workflow(lfinjets + SOURCES lfinjets.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) +endif() diff --git a/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt b/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt index 660365da5ac..e0ebdb862f9 100644 --- a/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt +++ b/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt @@ -9,11 +9,31 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +o2physics_add_dpl_workflow(stradautrackstpcpidconverter + SOURCES stradautrackstpcpidconverter.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(stradautrackstofpidconverter SOURCES stradautrackstofpidconverter.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(stradautrackstofpidconverter2 + SOURCES stradautrackstofpidconverter2.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 @@ -24,7 +44,87 @@ o2physics_add_dpl_workflow(strarawcentsconverter2v4 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::ReconstructionDataFormats + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter3 + SOURCES straevselsconverter3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::ReconstructionDataFormats + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter4 + SOURCES straevselsconverter4.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(straevselsconverter5 + SOURCES straevselsconverter5.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB + 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) \ No newline at end of file + 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) + +o2physics_add_dpl_workflow(zdcneutronsconverter + SOURCES zdcneutronsconverter.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/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 index 8731939ca53..26cefdf2485 100644 --- a/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter.cxx +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter.cxx @@ -53,7 +53,7 @@ struct stradautrackstofpidconverter { lTOFEvTimes[casc.bachTrackExtraId()] = casc.bachTOFEventTime(); } for (int ii = 0; ii < dauTracks.size(); ii++) { - dautracktofpids(lTOFSignals[ii], lTOFEvTimes[ii], lLengths[ii]); + dautracktofpids(-1, -1, lTOFSignals[ii], lTOFEvTimes[ii], lLengths[ii], 0.0f); } } }; diff --git a/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter2.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter2.cxx new file mode 100644 index 00000000000..371c5c133d3 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter2.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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; + +// converts DauTrackTOFPIDs_000 to _001 +struct stradautrackstofpidconverter2 { + Produces dautracktofpids; + Produces straEvTimes; + + void process(aod::StraCollisions const& collisions, soa::Join const& dauTracks, soa::Join const& v0s) + { + // create new TOFPIDs + for (int ii = 0; ii < dauTracks.size(); ii++) { + auto dauTrack = dauTracks.rawIteratorAt(ii); + dautracktofpids(-1, -1, dauTrack.tofSignal(), dauTrack.tofEvTime(), dauTrack.length(), 0.0f); + } + + // fill EvTimes (created simultaneously, so done in the same converter) + // recover as much as possible from the previous format + std::vector collisionEventTime(collisions.size(), 0.0); + std::vector collisionNtracks(collisions.size(), 0); + + for (const auto& v0 : v0s) { + auto posTrackTOF = dauTracks.rawIteratorAt(v0.posTrackExtraId()); + auto negTrackTOF = dauTracks.rawIteratorAt(v0.negTrackExtraId()); + if (posTrackTOF.hasTOF()) { + collisionEventTime[v0.straCollisionId()] += posTrackTOF.tofEvTime(); + collisionNtracks[v0.straCollisionId()]++; + } + if (negTrackTOF.hasTOF()) { + collisionEventTime[v0.straCollisionId()] += negTrackTOF.tofEvTime(); + collisionNtracks[v0.straCollisionId()]++; + } + } + for (const auto& collision : collisions) { + if (collisionNtracks[collision.globalIndex()] > 0) { + collisionEventTime[collision.globalIndex()] /= static_cast(collisionNtracks[collision.globalIndex()]); + } else { + collisionEventTime[collision.globalIndex()] = -1e+6; // undefined + } + straEvTimes(collisionEventTime[collision.globalIndex()]); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/Converters/stradautrackstpcpidconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstpcpidconverter.cxx new file mode 100644 index 00000000000..627872555bc --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstpcpidconverter.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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; + +// converts DauTrackTOFPIDs_000 to _001 +struct stradautrackstpcpidconverter { + Produces dautrackpcpids; + + void process(aod::DauTrackTPCPIDs_000 const& v000s) + { + for (int ii = 0; ii < v000s.size(); ii++) { + auto dauTrackTPCPID = v000s.rawIteratorAt(ii); + dautrackpcpids(dauTrackTPCPID.tpcSignal(), + aod::dautrack::packing::packInInt8(dauTrackTPCPID.tpcNSigmaEl()), + aod::dautrack::packing::packInInt8(dauTrackTPCPID.tpcNSigmaPi()), + aod::dautrack::packing::packInInt8(dauTrackTPCPID.tpcNSigmaKa()), + aod::dautrack::packing::packInInt8(dauTrackTPCPID.tpcNSigmaPr())); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} 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..fd3ccad4ee4 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter2.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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Vertex.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::dataformats::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..ac209c26fe7 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter3.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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Vertex.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::dataformats::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..2dc55f365c9 --- /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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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..0ba066f99b3 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/straevselsconverter5.cxx @@ -0,0 +1,125 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::evsel; + +static const int32_t nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; + +// Converts Stra Event selections from 004 to 005 +struct straevselsconverter5 { + Produces straEvSels_005; + + Service ccdb; + + 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 3 + std::map* mapRCT = nullptr; + + uint32_t getRctRaw(int run, uint64_t timestamp, uint64_t globalBC) + { + 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; + // 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)); + } + } + + // store rct flags + uint32_t rct = lastRCT; + int64_t thisTF = (globalBC - bcSOR) / nBCsPerTF; + if (mapRCT != nullptr && thisTF != lastTF) { // skip for unanchored runs; do it once per TF + auto itrct = mapRCT->upper_bound(timestamp); + if (itrct != mapRCT->begin()) + itrct--; + rct = itrct->second; + LOGP(debug, "sor={} eor={} ts={} rct={}", sorTimestamp, eorTimestamp, timestamp, rct); + lastRCT = rct; + lastTF = thisTF; + } + return rct; + } + + void process(soa::Join 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*/, + getRctRaw(values.runNumber(), values.timestamp(), values.globalBC()) /* 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/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/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/Converters/zdcneutronsconverter.cxx b/PWGLF/TableProducer/Strangeness/Converters/zdcneutronsconverter.cxx new file mode 100644 index 00000000000..ad081a43052 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/zdcneutronsconverter.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" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" + +using namespace o2; +using namespace o2::framework; + +// +struct zdcneutronsconverter { + Produces zdcNeutrons; // Primary neutrons within ZDC acceptance + Produces zdcNeutronsMCCollRefs; // references collisions from ZDCNeutrons + + void process(aod::StraEvSels const&) + { + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/LambdaLambdatable.cxx b/PWGLF/TableProducer/Strangeness/LambdaLambdatable.cxx new file mode 100644 index 00000000000..8a2a62cf968 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/LambdaLambdatable.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. +/// +/// \author Junlee Kim, (junlee.kim@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/ReducedLambdaLambdaTables.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +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/cascadeMLSelectionTreeCreator.cxx b/PWGLF/TableProducer/Strangeness/cascadeMLSelectionTreeCreator.cxx index f3bfc813c89..e6f73a15bb9 100644 --- a/PWGLF/TableProducer/Strangeness/cascadeMLSelectionTreeCreator.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadeMLSelectionTreeCreator.cxx @@ -23,37 +23,39 @@ // david.dobrigkeit.chinellato@cern.ch // -#include // C system -#include // C++ system -#include // C++ system -#include // C++ system +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/AnalysisTask.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/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" -#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include // C system +#include #include #include -#include #include #include -#include +#include + +#include // C++ system +#include // C++ system +#include // C++ system using namespace o2; using namespace o2::framework; diff --git a/PWGLF/TableProducer/Strangeness/cascadebuilder.cxx b/PWGLF/TableProducer/Strangeness/cascadebuilder.cxx index e1c0cfed9e3..b4a19e6660b 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" @@ -123,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 @@ -194,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"}; @@ -531,8 +543,7 @@ 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 && doprocessFindableRun3 == false) { @@ -744,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); } } @@ -849,8 +862,8 @@ struct cascadeBuilder { // from Carolina Reetz (thank you!) 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; + std::array xyz, pxpypz; + std::array cv; // get parameters from kfParticle xyz[0] = kfParticle.GetX(); @@ -896,7 +909,7 @@ struct cascadeBuilder { // Calculate DCAxy of the cascade (with bending) o2::track::TrackPar wrongV0 = fitter.createParentTrackPar(); wrongV0.setAbsCharge(0); // charge zero - gpu::gpustd::array dcaInfo; + std::array dcaInfo; dcaInfo[0] = 999; dcaInfo[1] = 999; @@ -976,7 +989,7 @@ struct cascadeBuilder { // bachelor DCA track to PV // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo; + std::array dcaInfo; auto bachTrackPar = getTrackPar(bachTrack); o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, bachTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo); @@ -1118,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()]++; @@ -1219,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); //*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<* @@ -1228,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) { @@ -1253,7 +1273,7 @@ struct cascadeBuilder { // bachelor DCA track to PV // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo; + std::array dcaInfo; auto bachTrackPar = getTrackPar(bachTrack); o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, bachTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo); @@ -1394,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; @@ -1498,14 +1514,14 @@ struct cascadeBuilder { cascadecandidate.yOmega = KFOmega.GetRapidity(); // KF Cascade covariance matrix - o2::gpu::gpustd::array covCascKF; + std::array covCascKF; for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) covCascKF[i] = KFXi.GetCovariance(i); cascadecandidate.kfCascadeCov[i] = covCascKF[i]; } // KF V0 covariance matrix - o2::gpu::gpustd::array covV0KF; + std::array covV0KF; for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) covV0KF[i] = KFV0.GetCovariance(i); cascadecandidate.kfV0Cov[i] = covV0KF[i]; @@ -1555,9 +1571,7 @@ struct cascadeBuilder { 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.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 @@ -1565,6 +1579,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) { @@ -1581,56 +1602,58 @@ 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); } } - template - void buildStrangenessTables(TCascTable 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 - - auto v0index = cascade.template v0_as(); - processCascadeCandidate(v0index, cascade); - } - // En masse filling at end of process call - fillHistos(); - resetHistos(); - } - - template - void buildFindableStrangenessTables(TCascTable const& cascades) + 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 - auto v0index = cascade.template findableV0_as(); - processCascadeCandidate(v0index, cascade); + if constexpr (requires { cascade.v0(); }) { + auto v0index = cascade.template v0_as(); + processCascadeCandidate(v0index, cascade); + } + if constexpr (requires { cascade.findableV0(); }) { + auto v0index = cascade.template findableV0_as(); + processCascadeCandidate(v0index, cascade); + } } // En masse filling at end of process call fillHistos(); 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 @@ -1735,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) { @@ -1751,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; @@ -1803,9 +1837,9 @@ 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; + std::array dcaInfo; lCascadeTrack.setPID(o2::track::PID::XiMinus); // FIXME: not OK for omegas o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, cascadeTrackPar, 2.f, matCorrCascade, &dcaInfo); @@ -1883,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 @@ -1927,12 +1974,12 @@ struct cascadeBuilder { // Do analysis with collision-grouped V0s, retain full collision information const uint64_t collIdx = collision.globalIndex(); auto CascadeTable_thisCollision = cascades.sliceBy(perCollisionFindable, collIdx); - buildFindableStrangenessTables(CascadeTable_thisCollision); + 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::V0s const&) + 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 @@ -1946,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) { @@ -2207,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) { @@ -2327,14 +2388,6 @@ struct cascadePreselector { //*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<*>-~-<* }; -/// Extends the cascdata table with expression columns -struct cascadeInitializer { - Spawns cascdataext; - Spawns kfcascdataext; - Spawns tracascdataext; - void init(InitContext const&) {} -}; - struct cascadeLinkBuilder { Produces cascdataLink; @@ -2421,7 +2474,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) return WorkflowSpec{ adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; diff --git a/PWGLF/TableProducer/Strangeness/cascadefinder.cxx b/PWGLF/TableProducer/Strangeness/cascadefinder.cxx index ae4cc41802a..7967ab9ebbb 100644 --- a/PWGLF/TableProducer/Strangeness/cascadefinder.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadefinder.cxx @@ -28,33 +28,35 @@ // david.dobrigkeit.chinellato@cern.ch // -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "DCAFitter/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/LFStrangenessFinderTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DCAFitter/DCAFitterN.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include #include -#include #include #include -#include -#include +#include #include -#include -#include +#include + #include +#include #include using namespace o2; @@ -244,7 +246,7 @@ struct cascadefinder { auto lCascadeTrack = fitterCasc.createParentTrackPar(); lCascadeTrack.setAbsCharge(-1); // to be sure lCascadeTrack.setPID(o2::track::PID::XiMinus); // FIXME: not OK for omegas - gpu::gpustd::array dcaInfo; + std::array dcaInfo; dcaInfo[0] = 999; dcaInfo[1] = 999; @@ -270,9 +272,9 @@ struct cascadefinder { t0id.dcaXY(), dcaInfo[0], dcaInfo[1]); } // end if cascade recoed - } // end loop over bachelor - } // end if v0 recoed - } // end loop over cascades + } // end loop over bachelor + } // end if v0 recoed + } // end loop over cascades // Anticascades for (auto& v0id : antiLambdas) { @@ -334,7 +336,7 @@ struct cascadefinder { auto lCascadeTrack = fitterCasc.createParentTrackPar(); lCascadeTrack.setAbsCharge(+1); // to be sure lCascadeTrack.setPID(o2::track::PID::XiMinus); // FIXME: not OK for omegas - gpu::gpustd::array dcaInfo; + std::array dcaInfo; dcaInfo[0] = 999; dcaInfo[1] = 999; @@ -361,9 +363,9 @@ struct cascadefinder { t0id.dcaXY(), dcaInfo[0], dcaInfo[1]); } // end if cascade recoed - } // end loop over bachelor - } // end if v0 recoed - } // end loop over anticascades + } // end loop over bachelor + } // end if v0 recoed + } // end loop over anticascades hCandPerEvent->Fill(lNCand); } @@ -430,17 +432,10 @@ struct cascadefinderQA { } }; -/// Extends the cascdata table with expression columns -struct cascadeinitializer { - Spawns cascdataext; - void init(InitContext const&) {} -}; - WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc, TaskName{"lf-cascadeprefilter"}), adaptAnalysisTask(cfgc, TaskName{"lf-cascadefinder"}), - adaptAnalysisTask(cfgc, TaskName{"lf-cascadefinderQA"}), - adaptAnalysisTask(cfgc, TaskName{"lf-cascadeinitializer"})}; + adaptAnalysisTask(cfgc, TaskName{"lf-cascadefinderQA"})}; } diff --git a/PWGLF/TableProducer/Strangeness/cascadeflow.cxx b/PWGLF/TableProducer/Strangeness/cascadeflow.cxx index c3a1060f3cf..1a076783d13 100644 --- a/PWGLF/TableProducer/Strangeness/cascadeflow.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadeflow.cxx @@ -9,24 +9,34 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// +/// \file cascadeflow.cxx +/// /// \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) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) +/// \author Maximiliano Puccio (maximiliano.puccio@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/cascqaanalysis.h" -#include "Math/Vector3D.h" -#include "TRandom3.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/AnalysisTask.h" +#include "Tools/ML/MlResponse.h" + +#include "CCDB/BasicCCDBManager.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/cascqaanalysis.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFStrangenessPIDTables.h" -#include "Tools/ML/MlResponse.h" + +#include "Math/Vector3D.h" +#include "TRandom3.h" + +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -35,30 +45,55 @@ using namespace o2::framework::expressions; using std::array; using DauTracks = soa::Join; -using CollEventPlane = soa::Join::iterator; -using CollEventPlaneCentralFW = soa::Join::iterator; +using CollEventPlane = soa::Join::iterator; +using CollEventPlaneCentralFW = soa::Join::iterator; +using CollEventPlaneCentralFWOnlyFT0C = soa::Join::iterator; +using CollEventAndSpecPlane = soa::Join::iterator; +using CollEventAndSpecPlaneCentralFW = soa::Join::iterator; +using MCCollisionsStra = soa::Join; +using V0Candidates = soa::Join; +using CascCandidates = soa::Join; +using CascMCCandidates = soa::Join; + +const int nParticles = 2; // Xi, Omega +const int nCharges = 2; // Lambda, AntiLambda +const int nParameters = 4; namespace cascadev2 { enum species { Xi = 0, Omega = 1 }; -constexpr double massSigmaParameters[4][2]{ +constexpr double massSigmaParameters[nParameters][nParticles]{ {4.9736e-3, 0.006815}, {-2.39594, -2.257}, {1.8064e-3, 0.00138}, {1.03468e-1, 0.1898}}; static const std::vector massSigmaParameterNames{"p0", "p1", "p2", "p3"}; static const std::vector speciesNames{"Xi", "Omega"}; - -std::shared_ptr hMassBeforeSelVsPt[2]; -std::shared_ptr hMassAfterSelVsPt[2]; -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]; +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[nParticles]; +std::shared_ptr hMassAfterSelVsPt[nParticles]; +std::shared_ptr hSignalScoreBeforeSel[nParticles]; +std::shared_ptr hBkgScoreBeforeSel[nParticles]; +std::shared_ptr hSignalScoreAfterSel[nParticles]; +std::shared_ptr hBkgScoreAfterSel[nParticles]; +std::shared_ptr hSparseV2C[nParticles]; } // namespace cascadev2 +namespace lambdav2 +{ +enum species { Lambda = 0, + AntiLambda = 1 }; +static const std::vector speciesNames{"Lambda", "AntiLambda"}; +const double AlphaLambda[2] = {0.747, -0.757}; // decay parameter of Lambda and AntiLambda + +std::shared_ptr hMassBeforeSelVsPt[nCharges]; +std::shared_ptr hMassAfterSelVsPt[nCharges]; +} // namespace lambdav2 + namespace cascade_flow_cuts_ml { // direction of the cut @@ -118,23 +153,118 @@ static const std::vector labelsCutScore = {"Background score", "Sig struct cascadeFlow { + Configurable isQVecT0C{"isQVecT0C", 1, ""}; + Configurable isQVecT0A{"isQVecT0A", 0, ""}; + Configurable isQVecT0M{"isQVecT0M", 0, ""}; + Configurable isQVecV0A{"isQVecV0A", 0, ""}; + Configurable isCollisionCentrality{"isCollisionCentrality", 0, ""}; // 0: FT0C, 1: FT0M (implemented only for Lambda analysis in OO) + + // 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 isFillTHNLambda{"isFillTHNLambda", 1, ""}; + Configurable isFillTHNLambda_PzVsPsi{"isFillTHNLambda_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"}; + // Configurable for shift correction + struct : ConfigurableGroup { + Configurable cfgShiftCorr{"cfgShiftCorr", 0, ""}; + Configurable cfgShiftPathFT0C{"cfgShiftPathFT0C", "Users/c/chdemart/OOpass2Shift/ShiftFT0C", "Path for Shift"}; + Configurable cfgShiftPathFV0A{"cfgShiftPathFV0A", "Users/c/chdemart/OOpass2Shift/ShiftFV0A", "Path for Shift"}; + Configurable cfgShiftPathFT0A{"cfgShiftPathFT0A", "Users/c/chdemart/OOpass2Shift/ShiftFT0A", "Path for Shift"}; + Configurable cfgShiftPathTPCL{"cfgShiftPathTPCL", "Users/c/chdemart/OOpass2Shift/ShiftTPCL", "Path for Shift"}; + Configurable cfgShiftPathTPCR{"cfgShiftPathTPCR", "Users/c/chdemart/OOpass2Shift/ShiftTPCR", "Path for Shift"}; + } ShiftConfigs; + // Configurable cfgHarmonic{"cfgHarmonic", 2, "Harmonic for event plane calculation"}; + + // THN axes + struct : ConfigurableGroup { + 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, o2::constants::math::TwoPI}, ""}; + 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}, ""}; + } thnAxisConfigs; + // 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 isCollInStandardTimeRange{"isCollInStandardTimeRange", 1, "To remove collisions in +-10 micros time range"}; - Configurable isCollInNarrowTimeRange{"isCollInNarrowTimeRange", 0, "To remove collisions in +-4 micros time range"}; + 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; + + struct : ConfigurableGroup { + Configurable MinPtV0{"MinPtV0", 0.2, "Min pt of v0"}; + Configurable MaxPtV0{"MaxPtV0", 10, "Max pt of v0"}; + Configurable MinMassLambda{"MinMassLambda", 1.105, ""}; + Configurable MaxMassLambda{"MaxMassLambda", 1.125, ""}; + Configurable MinMassLambdaInTree{"MinMassLambdaInTree", 1.09, ""}; + Configurable MaxMassLambdaInTree{"MaxMassLambdaInTree", 1.14, ""}; + Configurable etaV0{"etaV0", 0.8, "etaV0"}; + 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)"}; + Configurable rapidityLambda{"rapidityLambda", 0.5, "rapidityLambda"}; + Configurable etaLambda{"etaLambda", 0.8, "etaLambda"}; + Configurable dauTrackV0Eta{"dauTrackV0Eta", 0.8, "dauTrackV0Eta"}; + } V0Configs; - Configurable MinPt{"MinPt", 0.6, "Min pt of cascade"}; - Configurable MaxPt{"MaxPt", 10, "Max pt of cascade"}; 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"}; @@ -143,6 +273,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"}; @@ -150,71 +284,115 @@ 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 acceptancePathsCCDBPrimaryLambda{"acceptancePathsCCDBPrimaryLambda", "Users/c/chdemart/AcceptanceLambda", "Paths of PrimaryLambda acceptance on CCDB"}; + Configurable acceptanceHistoNameCasc{"acceptanceHistoNameCasc", "histoCos2ThetaNoFit2D", "Histo name of acceptance on CCDB"}; + Configurable acceptanceHistoNameLambda{"acceptanceHistoNameLambda", "histoCos2ThetaLambdaFromCNoFit2D", "Histo name of acceptance on CCDB"}; + Configurable acceptanceHistoNamePrimaryLambda{"acceptanceHistoNamePrimaryLambda", "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 AcceptEvent(TCollision const& collision, bool 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()); + 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; } - histos.fill(HIST("hNEvents"), 1.5); + if (isFillHisto) + histos.fill(HIST("hNEvents"), 1.5); // Z vertex selection - if (TMath::Abs(collision.posZ()) > cutzvertex) { + if (std::abs(collision.posZ()) > cutzvertex) { return false; } - histos.fill(HIST("hNEvents"), 2.5); + if (isFillHisto) + histos.fill(HIST("hNEvents"), 2.5); // kNoSameBunchPileup selection if (isNoSameBunchPileupCut && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; } - histos.fill(HIST("hNEvents"), 3.5); + if (isFillHisto) + histos.fill(HIST("hNEvents"), 3.5); // kIsGoodZvtxFT0vsPV selection if (isGoodZvtxFT0vsPVCut && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; } - histos.fill(HIST("hNEvents"), 4.5); + if (isFillHisto) + histos.fill(HIST("hNEvents"), 4.5); // occupancy cut int occupancy = collision.trackOccupancyInTimeRange(); - if (occupancy < MinOccupancy || occupancy > MaxOccupancy) { + if (isTrackOccupancySel && (occupancy < MinOccupancy || occupancy > MaxOccupancy)) { return false; } - histos.fill(HIST("hNEvents"), 5.5); + // 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); - if (isCollInStandardTimeRange && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // 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 (isCollInNarrowTimeRange && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + if (isFillHisto) + histos.fill(HIST("hNEvents"), 6.5); + + // In-ROF event selection + if (isNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { return false; } - histos.fill(HIST("hNEvents"), 6.5); - histos.fill(HIST("hEventNchCorrelation"), collision.multNTracksPVeta1(), collision.multNTracksGlobal()); - histos.fill(HIST("hEventPVcontributorsVsCentrality"), collision.centFT0C(), collision.multNTracksPVeta1()); - histos.fill(HIST("hEventGlobalTracksVsCentrality"), collision.centFT0C(), collision.multNTracksGlobal()); + 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; } @@ -241,32 +419,175 @@ struct cascadeFlow { return true; } + template + bool isLambdaAccepted(TDaughter negExtra, TDaughter posExtra, int& counter) // loose cuts on topological selections of v0s + { + // TPC cuts as those implemented for the training of the signal + if (doNTPCSigmaCut) { + if (std::abs(posExtra.tpcNSigmaPr()) > nsigmatpcPr || std::abs(negExtra.tpcNSigmaPi()) > nsigmatpcPi) + return false; + } + counter++; + + if (posExtra.tpcCrossedRows() < mintpccrrows || negExtra.tpcCrossedRows() < mintpccrrows) + return false; + + counter++; + + // eta daughters) + // if (abs(posExtra.eta()) > V0Configs.dauTrackV0Eta || abs(negExtra.y()) > V0Configs.dauTrackV0Eta) return false; + + return true; + } + template + bool isAntiLambdaAccepted(TDaughter negExtra, TDaughter posExtra, int& counter) // loose cuts on topological selections of v0s + { + // TPC cuts as those implemented for the training of the signal + if (doNTPCSigmaCut) { + if (std::abs(negExtra.tpcNSigmaPr()) > nsigmatpcPr || std::abs(posExtra.tpcNSigmaPi()) > nsigmatpcPi) + return false; + } + counter++; + + if (posExtra.tpcCrossedRows() < mintpccrrows || negExtra.tpcCrossedRows() < mintpccrrows) + return false; + + counter++; + return true; + } + + template + bool isV0TopoAccepted(TV0 v0) + { + // topological selections + if (v0.v0radius() < V0Configs.v0radius) + return false; + if (v0.v0radius() > V0Configs.v0radiusMax) + return false; + if (std::abs(v0.dcapostopv()) < V0Configs.dcapostopv) + return false; + if (std::abs(v0.dcanegtopv()) < V0Configs.dcanegtopv) + return false; + if (v0.v0cosPA() < V0Configs.v0cospa) + return false; + if (v0.dcaV0daughters() > V0Configs.dcav0dau) + return false; + // rapidity selection + if (std::abs(v0.yLambda()) > V0Configs.rapidityLambda) + return false; + if (std::abs(v0.eta()) > V0Configs.etaLambda) + return false; + + return true; + } + double GetPhiInRange(double phi) { while (phi < 0) { - phi += TMath::Pi(); + phi += o2::constants::math::PI; } - while (phi > TMath::Pi()) { - phi -= TMath::Pi(); + while (phi > o2::constants::math::PI) { + phi -= o2::constants::math::PI; } return phi; } - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry resolution{"resolution", {}, OutputObjHandlingPolicy::AnalysisObject}; + int currentRunNumber = -999; + int lastRunNumber = -999; + TProfile3D* shiftprofile; + TProfile3D* shiftprofileFT0C; + TProfile3D* shiftprofileFV0A; + TProfile3D* shiftprofileFT0A; + TProfile3D* shiftprofileTPCL; + TProfile3D* shiftprofileTPCR; + std::string fullCCDBShiftCorrPath; + std::string fullCCDBShiftCorrPathFT0C; + std::string fullCCDBShiftCorrPathFV0A; + std::string fullCCDBShiftCorrPathFT0A; + std::string fullCCDBShiftCorrPathTPCL; + std::string fullCCDBShiftCorrPathTPCR; + + template + double ApplyShiftCorrection(TCollision coll, double psiT0C, TProfile3D* shiftprofile) + { + auto deltapsiFT0C = 0.0; + int nmode = 2; + + for (int ishift = 1; ishift <= 10; ishift++) { + auto coeffshiftxFT0C = shiftprofile->GetBinContent(shiftprofile->FindBin(coll.centFT0C(), 0.5, ishift - 0.5)); + auto coeffshiftyFT0C = shiftprofile->GetBinContent(shiftprofile->FindBin(coll.centFT0C(), 1.5, ishift - 0.5)); + + deltapsiFT0C += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0C * std::cos(ishift * static_cast(nmode) * psiT0C) + coeffshiftyFT0C * TMath::Sin(ishift * static_cast(nmode) * psiT0C))); + } + return psiT0C + deltapsiFT0C; + } + + template + double ComputeEPResolutionwShifts(TCollision coll, double psiT0C, double psiV0A, double psiT0A, double psiTPCA, double psiTPCC, TProfile3D* shiftprofileA, TProfile3D* shiftprofileB, TProfile3D* shiftprofileC, TProfile3D* shiftprofileD, TProfile3D* shiftprofileE) + { + int nmode = 2; + auto deltapsiFT0C = 0.0; + auto deltapsiFV0A = 0.0; + auto deltapsiFT0A = 0.0; + auto deltapsiTPCA = 0.0; + auto deltapsiTPCC = 0.0; + for (int ishift = 1; ishift <= 10; ishift++) { + auto coeffshiftxFT0C = shiftprofileA->GetBinContent(shiftprofileA->FindBin(coll.centFT0C(), 0.5, ishift - 0.5)); + auto coeffshiftyFT0C = shiftprofileA->GetBinContent(shiftprofileA->FindBin(coll.centFT0C(), 1.5, ishift - 0.5)); + auto coeffshiftxTPCA = shiftprofileB->GetBinContent(shiftprofileB->FindBin(coll.centFT0C(), 0.5, ishift - 0.5)); + auto coeffshiftyTPCA = shiftprofileB->GetBinContent(shiftprofileB->FindBin(coll.centFT0C(), 1.5, ishift - 0.5)); + auto coeffshiftxTPCC = shiftprofileC->GetBinContent(shiftprofileC->FindBin(coll.centFT0C(), 0.5, ishift - 0.5)); + auto coeffshiftyTPCC = shiftprofileC->GetBinContent(shiftprofileC->FindBin(coll.centFT0C(), 1.5, ishift - 0.5)); + auto coeffshiftxFV0A = shiftprofileD->GetBinContent(shiftprofileD->FindBin(coll.centFT0C(), 0.5, ishift - 0.5)); + auto coeffshiftyFV0A = shiftprofileD->GetBinContent(shiftprofileD->FindBin(coll.centFT0C(), 1.5, ishift - 0.5)); + auto coeffshiftxFT0A = shiftprofileE->GetBinContent(shiftprofileE->FindBin(coll.centFT0C(), 0.5, ishift - 0.5)); + auto coeffshiftyFT0A = shiftprofileE->GetBinContent(shiftprofileE->FindBin(coll.centFT0C(), 1.5, ishift - 0.5)); + deltapsiFT0C += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0C * std::cos(ishift * static_cast(nmode) * psiT0C) + coeffshiftyFT0C * TMath::Sin(ishift * static_cast(nmode) * psiT0C))); + deltapsiFV0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFV0A * std::cos(ishift * static_cast(nmode) * psiV0A) + coeffshiftyFV0A * TMath::Sin(ishift * static_cast(nmode) * psiV0A))); + deltapsiFT0A += ((1 / (1.0 * ishift)) * (-coeffshiftxFT0A * std::cos(ishift * static_cast(nmode) * psiT0A) + coeffshiftyFT0A * TMath::Sin(ishift * static_cast(nmode) * psiT0A))); + deltapsiTPCA += ((1 / (1.0 * ishift)) * (-coeffshiftxTPCA * std::cos(ishift * static_cast(nmode) * psiTPCA) + coeffshiftyTPCA * TMath::Sin(ishift * static_cast(nmode) * psiTPCA))); + deltapsiTPCC += ((1 / (1.0 * ishift)) * (-coeffshiftxTPCC * std::cos(ishift * static_cast(nmode) * psiTPCC) + coeffshiftyTPCC * TMath::Sin(ishift * static_cast(nmode) * psiTPCC))); + } + histos.fill(HIST("Psi_EP_FT0C_shifted"), coll.centFT0C(), psiT0C + deltapsiFT0C); + histos.fill(HIST("Psi_EP_FV0A_shifted"), coll.centFT0C(), psiV0A + deltapsiFV0A); + histos.fill(HIST("Psi_EP_FT0A_shifted"), coll.centFT0C(), psiT0A + deltapsiFT0A); + histos.fill(HIST("Psi_EP_TPCA_shifted"), coll.centFT0C(), psiTPCA + deltapsiTPCA); + histos.fill(HIST("Psi_EP_TPCC_shifted"), coll.centFT0C(), psiTPCC + deltapsiTPCC); + resolution.fill(HIST("QVectorsT0CTPCA_Shifted"), std::cos(static_cast(nmode) * (psiT0C + deltapsiFT0C - psiTPCA - deltapsiTPCA)), coll.centFT0C()); + resolution.fill(HIST("QVectorsT0CTPCC_Shifted"), std::cos(static_cast(nmode) * (psiT0C + deltapsiFT0C - psiTPCC - deltapsiTPCC)), coll.centFT0C()); + resolution.fill(HIST("QVectorsT0CV0A_Shifted"), std::cos(static_cast(nmode) * (psiT0C + deltapsiFT0C - psiV0A - deltapsiFV0A)), coll.centFT0C()); + resolution.fill(HIST("QVectorsT0CT0A_Shifted"), std::cos(static_cast(nmode) * (psiT0C + deltapsiFT0C - psiT0A - deltapsiFT0A)), coll.centFT0C()); + resolution.fill(HIST("QVectorsV0ATPCC_Shifted"), std::cos(static_cast(nmode) * (psiV0A + deltapsiFV0A - psiTPCC - deltapsiTPCC)), coll.centFT0C()); + resolution.fill(HIST("QVectorsV0ATPCA_Shifted"), std::cos(static_cast(nmode) * (psiV0A + deltapsiFV0A - psiTPCA - deltapsiTPCA)), coll.centFT0C()); + resolution.fill(HIST("QVectorsT0ATPCC_Shifted"), std::cos(static_cast(nmode) * (psiT0A + deltapsiFT0A - psiTPCC - deltapsiTPCC)), coll.centFT0C()); + resolution.fill(HIST("QVectorsT0ATPCA_Shifted"), std::cos(static_cast(nmode) * (psiT0A + deltapsiFT0A - psiTPCA - deltapsiTPCA)), coll.centFT0C()); + resolution.fill(HIST("QVectorsTPCAC_Shifted"), std::cos(static_cast(nmode) * (psiTPCA + deltapsiTPCA - psiTPCC - deltapsiTPCC)), coll.centFT0C()); + return true; + } + + // objects to use for acceptance correction + TH2F* hAcceptanceXi; + TH2F* hAcceptanceOmega; + TH2F* hAcceptanceLambda; + TH2F* hAcceptancePrimaryLambda; + + 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; Produces analysisSample; + Produces analysisLambdaSample; Configurable> parSigmaMass{ "parSigmaMass", - {cascadev2::massSigmaParameters[0], 4, 2, + {cascadev2::massSigmaParameters[0], nParameters, nParticles, cascadev2::massSigmaParameterNames, cascadev2::speciesNames}, "Mass resolution parameters: [0]*exp([1]*x)+[2]*exp([3]*x)"}; float getNsigmaMass(const cascadev2::species s, const float pt, const float nsigma = 6) { - const auto sigma = parSigmaMass->get(0u, s) * exp(parSigmaMass->get(1, s) * pt) + parSigmaMass->get(2, s) * exp(parSigmaMass->get(3, s) * pt); + const auto sigma = parSigmaMass->get(0u, s) * std::exp(parSigmaMass->get(1, s) * pt) + parSigmaMass->get(2, s) * std::exp(parSigmaMass->get(3, s) * pt); return nsigma * sigma; } @@ -296,42 +617,133 @@ struct cascadeFlow { } template - void fillAnalysedTable(collision_t coll, cascade_t casc, float v2CSP, float v2CEP, float PsiT0C, 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; + double masses[nParticles]{o2::constants::physics::MassXiMinus, o2::constants::physics::MassOmegaMinus}; + ROOT::Math::PxPyPzMVector cascadeVector[nParticles], lambdaVector, protonVector; + float cosThetaStarLambda[nParticles], cosThetaStarProton; lambdaVector.SetCoordinates(casc.pxlambda(), casc.pylambda(), casc.pzlambda(), o2::constants::physics::MassLambda); ROOT::Math::Boost lambdaBoost{lambdaVector.BoostToCM()}; - if (casc.sign() < 0) { + 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) { + for (int i{0}; i < nParticles; ++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(), v2CSP, v2CEP, + v1SP_ZDCA, + v1SP_ZDCC, PsiT0C, BDTresponseXi, BDTresponseOmega, cosThetaStarLambda[0], cosThetaStarLambda[1], - cosThetaStarProton); + cosThetaStarProton, + pdgCode); + } + + template + void fillAnalysedLambdaTable(collision_t coll, bool hasEventPlane, bool hasSpectatorPlane, int chargeIndex, v0_t v0, float v2CEP, float psiT0C, double pzs2Lambda, double cos2ThetaLambda, double cosThetaLambda) + { + double invMassLambda = 0; + if (chargeIndex == 0) + invMassLambda = v0.mLambda(); + else if (chargeIndex == 1) + invMassLambda = v0.mAntiLambda(); + else + invMassLambda = v0.mLambda(); + analysisLambdaSample(coll.centFT0C(), + hasEventPlane, + hasSpectatorPlane, + chargeIndex, + v0.pt(), + v0.phi(), + v0.eta(), + invMassLambda, + v0.v0radius(), + v0.dcapostopv(), + v0.dcanegtopv(), + v0.v0cosPA(), + v0.dcaV0daughters(), + v2CEP, + psiT0C, + pzs2Lambda, + cos2ThetaLambda, + cosThetaLambda); + } + + 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!"; + TList* listAcceptancePrimaryLambda = ccdb->get(acceptancePathsCCDBPrimaryLambda); + if (!listAcceptancePrimaryLambda) + LOG(fatal) << "Problem getting TList object with acceptance for Primary 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"); + hAcceptancePrimaryLambda = static_cast(listAcceptancePrimaryLambda->FindObject(Form("%s", acceptanceHistoNamePrimaryLambda->data()))); + if (!hAcceptancePrimaryLambda) { + LOG(fatal) << "The histogram for Primary Lambda is not there!"; + } + hAcceptancePrimaryLambda->SetName("hAcceptancePrimaryLambda"); + LOG(info) << "Acceptance now loaded"; } void init(InitContext const&) @@ -339,28 +751,86 @@ struct cascadeFlow { float minMass[2]{1.28, 1.6}; float maxMass[2]{1.36, 1.73}; + float minMassLambda[2]{1.09, 1.09}; + float maxMassLambda[2]{1.14, 1.14}; + const AxisSpec shiftAxis = {10, 0, 10, "shift"}; + const AxisSpec basisAxis = {2, 0, 2, "basis"}; 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 massLambdaAxis[2]{{static_cast((maxMassLambda[0] - minMassLambda[0]) / 0.001f), minMassLambda[0], maxMassLambda[0], "#Lambda candidate mass (GeV/c^{2})"}, + {static_cast((maxMassLambda[1] - minMassLambda[1]) / 0.001f), minMassLambda[1], maxMassLambda[1], "#bar{#Lambda} candidate mass (GeV/c^{2})"}}; + const AxisSpec ptAxisCasc{static_cast((CandidateConfigs.MaxPt - CandidateConfigs.MinPt) / 0.2), CandidateConfigs.MinPt, CandidateConfigs.MaxPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ptAxisLambda{static_cast((V0Configs.MaxPtV0 - V0Configs.MinPtV0) / 0.2), V0Configs.MinPtV0, V0Configs.MaxPtV0, "#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[8] = {"All", "sel8", "z vrtx", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "trackOccupancyInTimeRange", "kNoCollInTimeRange", "kIsGoodEventEP"}; - - 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}); - - histos.add("hNEvents", "hNEvents", {HistType::kTH1F, {{8, 0.f, 8.f}}}); + const AxisSpec CentAxis{20, 0., 100., "FT0C centrality percentile"}; + const AxisSpec CentAxisPerCent{100, 0., 100., "Percent 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, CentAxisPerCent}); + resolution.add("QVectorsT0CTPCC", "QVectorsT0CTPCC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsTPCAC", "QVectorsTPCAC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0CV0A", "QVectorsT0CV0A", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsV0ATPCC", "QVectorsV0ATPCC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsV0ATPCA", "QVectorsV0ATPCA", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0CT0A", "QVectorsT0CT0A", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0ATPCC", "QVectorsT0ATPCC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0ATPCA", "QVectorsT0ATPCA", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_T0CTPCA", "EP_T0CTPCA", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_T0CTPCC", "EP_T0CTPCC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_TPCAC", "EP_TPCAC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_T0CV0A", "EP_T0CV0A", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_V0ATPCC", "EP_V0ATPCC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_V0ATPCA", "EP_V0ATPCA", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_T0CT0A", "EP_T0CT0A", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_T0ATPCC", "EP_T0ATPCC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("EP_T0ATPCA", "EP_T0ATPCA", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsNormT0CTPCA", "QVectorsNormT0CTPCA", HistType::kTH2F, {axisQVsNorm, CentAxisPerCent}); + resolution.add("QVectorsNormT0CTPCC", "QVectorsNormT0CTPCC", HistType::kTH2F, {axisQVsNorm, CentAxisPerCent}); + resolution.add("QVectorsNormTPCAC", "QVectorsNormTPCCB", HistType::kTH2F, {axisQVsNorm, CentAxisPerCent}); + resolution.add("QVectorsNormT0CV0A", "QVectorsNormT0CV0A", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsNormV0ATPCC", "QVectorsNormV0ATPCC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsNormV0ATPCA", "QVectorsNormV0ATPCA", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsNormT0CT0A", "QVectorsNormT0CT0A", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsNormT0ATPCC", "QVectorsNormT0ATPCC", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsNormT0ATPCA", "QVectorsNormT0ATPCA", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsSpecPlane", "QVectorsSpecPlane", HistType::kTH2F, {axisQVsNorm, CentAxisPerCent}); + resolution.add("QVectorsT0CTPCA_Shifted", "QVectorsT0CTPCA_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0CTPCC_Shifted", "QVectorsT0CTPCC_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsTPCAC_Shifted", "QVectorsTPCAC_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0CV0A_Shifted", "QVectorsT0CV0A_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsV0ATPCC_Shifted", "QVectorsV0ATPCC_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsV0ATPCA_Shifted", "QVectorsV0ATPCA_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0CT0A_Shifted", "QVectorsT0CT0A_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0ATPCC_Shifted", "QVectorsT0ATPCC_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + resolution.add("QVectorsT0ATPCA_Shifted", "QVectorsT0ATPCA_Shifted", HistType::kTH2F, {axisQVs, CentAxisPerCent}); + + histos.add("ShiftFT0C", "ShiftFT0C", kTProfile3D, {CentAxis, basisAxis, shiftAxis}); + histos.add("ShiftFV0A", "ShiftFV0A", kTProfile3D, {CentAxis, basisAxis, shiftAxis}); + histos.add("ShiftFT0A", "ShiftFT0A", kTProfile3D, {CentAxis, basisAxis, shiftAxis}); + histos.add("ShiftTPCL", "ShiftTPCL", kTProfile3D, {CentAxis, basisAxis, shiftAxis}); + histos.add("ShiftTPCR", "ShiftTPCR", kTProfile3D, {CentAxis, basisAxis, shiftAxis}); + + histos.add("hNEvents", "hNEvents", {HistType::kTH1D, {{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, -TMath::Pi(), TMath::Pi()}}); - histos.add("hPsiT0CvsCentFT0C", "hPsiT0CvsCentFT0C", HistType::kTH2D, {CentAxis, {100, -TMath::Pi(), TMath::Pi()}}); + histos.add("hEventCentralityBefEvSel", "hEventCentralityBefEvSel", kTH1F, {{101, 0, 101}}); + histos.add("hEventCentralityBefEPSel", "hEventCentralityBefEPSel", kTH1F, {{101, 0, 101}}); + histos.add("hEventCentralityT0M", "hEventCentralityT0M", kTH1F, {{101, 0, 101}}); + histos.add("hEventCentralityBefEvSelT0M", "hEventCentralityBefEvSelT0M", kTH1F, {{101, 0, 101}}); + histos.add("hEventCentralityBefEPSelT0M", "hEventCentralityBefEPSelT0M", kTH1F, {{101, 0, 101}}); + histos.add("hPsiT0C", "hPsiT0C", HistType::kTH1D, {{100, -o2::constants::math::PI, o2::constants::math::PI}}); + histos.add("hPsiT0CvsCentFT0C", "hPsiT0CvsCentFT0C", HistType::kTH2D, {CentAxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); + histos.add("Psi_EP_FT0C_shifted", "Psi_EP_FT0C_shifted", HistType::kTH2D, {CentAxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); + histos.add("Psi_EP_FV0A_shifted", "Psi_EP_FT0C_shifted", HistType::kTH2D, {CentAxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); + histos.add("Psi_EP_FT0A_shifted", "Psi_EP_FT0C_shifted", HistType::kTH2D, {CentAxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); + histos.add("Psi_EP_TPCA_shifted", "Psi_EP_FT0C_shifted", HistType::kTH2D, {CentAxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); + histos.add("Psi_EP_TPCC_shifted", "Psi_EP_FT0C_shifted", HistType::kTH2D, {CentAxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); + histos.add("hPsiZDCA_vs_ZDCC", "hPsiZDCA_vs_ZDCC", HistType::kTH2D, {{100, -o2::constants::math::PI, o2::constants::math::PI}, {100, -o2::constants::math::PI, o2::constants::math::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}}); @@ -370,23 +840,150 @@ struct cascadeFlow { 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("hLambdaCandidate", "hLambdaCandidate", HistType::kTH1F, {{5, -0.5, 4.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("hCascadePhi", "hCascadePhi", HistType::kTH1F, {{100, 0, 2 * TMath::Pi()}}); - histos.add("hcascminuspsiT0C", "hcascminuspsiT0C", HistType::kTH1F, {{100, 0, TMath::Pi()}}); + histos.add("hCascadeDauSel", "hCascadeDauSel", HistType::kTH1F, {{2, -0.5, 1.5}}); + histos.add("hLambdaDauSel", "hLambdaDauSel", HistType::kTH1F, {{3, -0.5, 2.5}}); + histos.add("hALambdaDauSel", "hALambdaDauSel", HistType::kTH1F, {{3, -0.5, 2.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, o2::constants::math::TwoPI}}); + histos.add("hcascminuspsiT0C", "hcascminuspsiT0C", HistType::kTH1F, {{100, 0, o2::constants::math::PI}}); + histos.add("hLambdaPhi", "hLambdaPhi", HistType::kTH1F, {{100, 0, o2::constants::math::TwoPI}}); + histos.add("hlambdaminuspsiT0C", "hlambdaminuspsiT0C", HistType::kTH1F, {{100, 0, o2::constants::math::PI}}); histos.add("hv2CEPvsFT0C", "hv2CEPvsFT0C", HistType::kTH2F, {CentAxis, {100, -1, 1}}); histos.add("hv2CEPvsv2CSP", "hv2CEPvsV2CSP", HistType::kTH2F, {{100, -1, 1}, {100, -1, 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}); + 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{thnAxisConfigs.thnConfigAxisFT0C, "FT0C (%)"}; + const AxisSpec thnAxisEta{thnAxisConfigs.thnConfigAxisEta, "#eta"}; + const AxisSpec thnAxisPt{thnAxisConfigs.thnConfigAxisPt, "p_{T}"}; + const AxisSpec thnAxisPtLambda{thnAxisConfigs.thnConfigAxisPtLambda, "p_{T, #Lambda}"}; + const AxisSpec thnAxisCharge{thnAxisConfigs.thnConfigAxisCharge, "Charge"}; + const AxisSpec thnAxisPsiDiff{thnAxisConfigs.thnConfigAxisPsiDiff, "2(phi-Psi)"}; + const AxisSpec thnAxisMassXi{thnAxisConfigs.thnConfigAxisMassXi, "inv. mass (#Lambda #pi) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisMassOmega{thnAxisConfigs.thnConfigAxisMassOmega, "inv. mass (#Lambda K) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisMassLambda{thnAxisConfigs.thnConfigAxisMassLambda, "inv. mass (p #pi) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisBDTScore{thnAxisConfigs.thnConfigAxisBDTScore, "BDT score"}; + const AxisSpec thnAxisV2{thnAxisConfigs.thnConfigAxisV2, "v_{2}"}; + const AxisSpec thnAxisPzs2Xi{thnAxisConfigs.thnConfigAxisPzs2Xi, "Pzs2Xi"}; + const AxisSpec thnAxisPzs2Omega{thnAxisConfigs.thnConfigAxisPzs2Omega, "Pzs2Omega"}; + const AxisSpec thnAxisPzs2Lambda{thnAxisConfigs.thnConfigAxisPzs2Lambda, "Pzs2Lambda"}; + const AxisSpec thnAxisCos2Theta{thnAxisConfigs.thnConfigAxisCos2Theta, "Cos2Theta"}; + const AxisSpec thnAxisCos2ThetaL{thnAxisConfigs.thnConfigAxisCos2ThetaL, "Cos2ThetaL"}; + const AxisSpec thnAxisCosThetaXiAlpha{thnAxisConfigs.thnConfigAxisCosThetaXiAlpha, "CosThetaXiWithAlpha"}; + const AxisSpec thnAxisCosThetaOmegaAlpha{thnAxisConfigs.thnConfigAxisCosThetaOmegaAlpha, "CosThetaOmegaWithAlpha"}; + const AxisSpec thnAxisCosThetaProtonAlpha{thnAxisConfigs.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}); + } + if (fillingConfigs.isFillTHNLambda) { + if (fillingConfigs.isFillTHN_V2) + histos.add("hLambdaV2", "THn for v2 of Lambda", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPtLambda, thnAxisMassLambda, thnAxisV2}); + if (fillingConfigs.isFillTHN_Pz) + histos.add("hLambdaPzs2", "THn for Pzs2 of Lambda", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPtLambda, thnAxisMassLambda, thnAxisPzs2Lambda}); + if (fillingConfigs.isFillTHN_Acc) + histos.add("hLambdaCos2Theta", "THn for Cos2Theta of Lambda", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPtLambda, thnAxisMassLambda, thnAxisCos2Theta}); + } + if (fillingConfigs.isFillTHNLambda_PzVsPsi) { + if (fillingConfigs.isFillTHN_Pz) + histos.add("hLambdaPzVsPsi", "THn for cosTheta of Lambda", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisPtLambda, thnAxisMassLambda, thnAxisCosThetaProtonAlpha, thnAxisPsiDiff}); + if (fillingConfigs.isFillTHN_Acc) + histos.add("hLambdaCos2ThetaVsPsi", "THn for cos2Theta of Lambda", HistType::kTHnF, {thnAxisFT0C, thnAxisCharge, thnAxisEta, thnAxisPtLambda, thnAxisMassLambda, thnAxisCos2Theta, 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 < nParticles; ++iS) { + cascadev2::hMassBeforeSelVsPt[iS] = histos.add(Form("hMassBeforeSelVsPt%s", cascadev2::speciesNames[iS].data()), "hMassBeforeSelVsPt", HistType::kTH2F, {massCascAxis[iS], ptAxisCasc}); + cascadev2::hMassAfterSelVsPt[iS] = histos.add(Form("hMassAfterSelVsPt%s", cascadev2::speciesNames[iS].data()), "hMassAfterSelVsPt", HistType::kTH2F, {massCascAxis[iS], ptAxisCasc}); cascadev2::hSignalScoreBeforeSel[iS] = histos.add(Form("hSignalScoreBeforeSel%s", cascadev2::speciesNames[iS].data()), "Signal score before selection;BDT first score;entries", HistType::kTH1F, {{100, 0., 1.}}); 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], ptAxisCasc, v2Axis, CentAxis}); } + for (int iS{0}; iS < nCharges; ++iS) { + lambdav2::hMassBeforeSelVsPt[iS] = histos.add(Form("hMassBeforeSelVsPt%s", lambdav2::speciesNames[iS].data()), "hMassBeforeSelVsPt", HistType::kTH2F, {massLambdaAxis[iS], ptAxisLambda}); + lambdav2::hMassAfterSelVsPt[iS] = histos.add(Form("hMassAfterSelVsPt%s", lambdav2::speciesNames[iS].data()), "hMassAfterSelVsPt", HistType::kTH2F, {massLambdaAxis[iS], ptAxisLambda}); + } + if (isApplyML) { // Configure and initialise the ML class mlResponseXi.configure(binsPtMl, cutsMl, cutDirMl, nClassesMl); @@ -403,21 +1000,28 @@ 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&) + void processTrainingBackground(soa::Join::iterator const& coll, soa::Join const& Cascades, DauTracks const&) { int counter = 0; - if (!AcceptEvent(coll)) { + if (!AcceptEvent(coll, 1)) { return; } histos.fill(HIST("hEventCentrality"), coll.centFT0C()); histos.fill(HIST("hEventVertexZ"), coll.posZ()); - for (auto& casc : Cascades) { + for (auto const& casc : Cascades) { if (gRandom->Uniform() > downsample) { continue; } @@ -458,19 +1062,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 (!AcceptEvent(coll)) { + 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 + for (auto const& casc : Cascades) { + if (!casc.has_cascMCCore()) + continue; + + auto cascMC = casc.cascMCCore_as>(); + int pdgCode{cascMC.pdgCode()}; + if (!(std::abs(pdgCode) == PDG_t::kXiMinus && std::abs(cascMC.pdgCodeV0()) == PDG_t::kLambda0 && std::abs(cascMC.pdgCodeBachelor()) == PDG_t::kPiPlus) // Xi + && !(std::abs(pdgCode) == PDG_t::kOmegaMinus && std::abs(cascMC.pdgCodeV0()) == PDG_t::kLambda0 && std::abs(cascMC.pdgCodeBachelor()) == kKPlus)) // Omega continue; auto negExtra = casc.negTrackExtra_as(); @@ -478,18 +1086,20 @@ struct cascadeFlow { auto bachExtra = casc.bachTrackExtra_as(); int counter = 0; - IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); + bool isCascCandidate = 0; + isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); histos.fill(HIST("hCascadeSignal"), counter); // PDG cascades - fillTrainingTable(coll, casc, pdgCode); + if (isCascCandidate) + fillTrainingTable(coll, casc, pdgCode); // I only store cascades that passed PID and track quality selections } } - void processAnalyseData(CollEventPlane const& coll, soa::Join const& Cascades, DauTracks const&) + void processAnalyseData(CollEventAndSpecPlane const& coll, CascCandidates const& Cascades, DauTracks const&) { - if (!AcceptEvent(coll)) { + if (!AcceptEvent(coll, 1)) { return; } @@ -497,7 +1107,18 @@ struct cascadeFlow { if (isGoodEventEP && !coll.triggereventep()) { return; } - histos.fill(HIST("hNEvents"), 7.5); + + // 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()); @@ -508,20 +1129,60 @@ struct cascadeFlow { 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; + const float psiTPCA = std::atan2(coll.qvecBPosIm(), coll.qvecBPosRe()) * 0.5f; + const float psiTPCC = std::atan2(coll.qvecBNegIm(), coll.qvecBNegRe()) * 0.5f; + float psiT0CCorr = psiT0C; + + for (int ishift = 1; ishift <= 10; ishift++) { + histos.fill(HIST("ShiftFT0C"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiT0C)); + histos.fill(HIST("ShiftFT0C"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiT0C)); + + histos.fill(HIST("ShiftTPCL"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiTPCA)); + histos.fill(HIST("ShiftTPCL"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiTPCA)); + + histos.fill(HIST("ShiftTPCR"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiTPCC)); + histos.fill(HIST("ShiftTPCR"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiTPCC)); + } - const float PsiT0C = std::atan2(coll.qvecFT0CIm(), coll.qvecFT0CRe()) * 0.5f; - histos.fill(HIST("hPsiT0C"), PsiT0C); - histos.fill(HIST("hPsiT0CvsCentFT0C"), coll.centFT0C(), PsiT0C); + if (ShiftConfigs.cfgShiftCorr) { + currentRunNumber = coll.runNumber(); + if (currentRunNumber != lastRunNumber) { + fullCCDBShiftCorrPathFT0C = ShiftConfigs.cfgShiftPathFT0C; + fullCCDBShiftCorrPathTPCL = ShiftConfigs.cfgShiftPathTPCL; + fullCCDBShiftCorrPathTPCR = ShiftConfigs.cfgShiftPathTPCR; + shiftprofileFT0C = ccdb->getForTimeStamp(fullCCDBShiftCorrPathFT0C, coll.timestamp()); + shiftprofileTPCL = ccdb->getForTimeStamp(fullCCDBShiftCorrPathTPCL, coll.timestamp()); + shiftprofileTPCR = ccdb->getForTimeStamp(fullCCDBShiftCorrPathTPCR, coll.timestamp()); + lastRunNumber = currentRunNumber; + } + } + + if (ShiftConfigs.cfgShiftCorr) { + psiT0CCorr = ApplyShiftCorrection(coll, psiT0C, shiftprofileFT0C); + ComputeEPResolutionwShifts(coll, psiT0C, psiT0C, psiT0C, psiTPCA, psiTPCC, shiftprofileFT0C, shiftprofileTPCL, shiftprofileTPCR, shiftprofileFT0C, shiftprofileFT0C); + } + + histos.fill(HIST("hPsiT0C"), psiT0CCorr); + histos.fill(HIST("hPsiZDCA_vs_ZDCC"), coll.psiZDCC(), coll.psiZDCA()); + histos.fill(HIST("hPsiT0CvsCentFT0C"), coll.centFT0C(), psiT0CCorr); 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("EP_T0CTPCA"), std::cos(2 * (psiT0C - psiTPCA)), coll.centFT0C()); + resolution.fill(HIST("EP_T0CTPCC"), std::cos(2 * (psiT0C - psiTPCC)), coll.centFT0C()); + resolution.fill(HIST("EP_TPCAC"), std::cos(2 * (psiTPCA - psiTPCC)), 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) { + std::vector bdtScore[nParticles]; + for (auto const& casc : Cascades) { /// Add some minimal cuts for single track variables (min number of TPC clusters) auto negExtra = casc.negTrackExtra_as(); @@ -529,8 +1190,12 @@ struct cascadeFlow { auto bachExtra = casc.bachTrackExtra_as(); int counter = 0; - IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); + bool isCascCandidate = 0; + isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); histos.fill(HIST("hCascade"), counter); + histos.fill(HIST("hCascadeDauSel"), (int)isCascCandidate); + if (!isCascCandidate) + continue; // ML selections bool isSelectedCasc[2]{false, false}; @@ -550,8 +1215,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; } @@ -563,7 +1228,7 @@ struct cascadeFlow { 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) { + for (int iS{0}; iS < nParticles; ++iS) { // Fill BDT score histograms before selection cascadev2::hSignalScoreBeforeSel[iS]->Fill(bdtScore[0][1]); cascadev2::hBkgScoreBeforeSel[iS]->Fill(bdtScore[1][0]); @@ -582,13 +1247,80 @@ struct cascadeFlow { ROOT::Math::XYZVector cascQvec{std::cos(2 * casc.phi()), std::sin(2 * casc.phi()), 0}; auto v2CSP = cascQvec.Dot(eventplaneVecT0C); // not normalised by amplitude - auto cascminuspsiT0C = GetPhiInRange(casc.phi() - PsiT0C); - auto v2CEP = TMath::Cos(2.0 * cascminuspsiT0C); + auto cascminuspsiT0C = GetPhiInRange(casc.phi() - psiT0CCorr); + auto v2CEP = std::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 = std::cos(casc.phi() - coll.psiZDCA()); + auto v1EP_ZDCC = std::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 < nParticles; ++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 = std::sqrt(std::pow(casc.pxlambda(), 2) + std::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() - psiT0CCorr)) / cascadev2::AlphaXi[chargeIndex] / meanCos2ThetaLambdaFromXi; + double pzs2Omega = cosThetaStarLambda[1] * std::sin(2 * (casc.phi() - psiT0CCorr)) / cascadev2::AlphaOmega[chargeIndex] / meanCos2ThetaLambdaFromOmega; + double cos2ThetaXi = cosThetaStarLambda[0] * cosThetaStarLambda[0]; + double cos2ThetaOmega = cosThetaStarLambda[1] * cosThetaStarLambda[1]; + double pzs2LambdaFromCasc = cosThetaStarProton * std::sin(2 * (casc.phi() - psiT0CCorr)) / 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); @@ -598,31 +1330,114 @@ struct cascadeFlow { cascadev2::hSparseV2C[0]->Fill(values); } - float BDTresponse[2]{0.f, 0.f}; + float BDTresponse[nParticles]{0.f, 0.f}; if (isApplyML) { BDTresponse[0] = bdtScore[0][1]; BDTresponse[1] = bdtScore[1][1]; } - if (isSelectedCasc[0] || isSelectedCasc[1]) - fillAnalysedTable(coll, casc, v2CSP, v2CEP, PsiT0C, BDTresponse[0], BDTresponse[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, psiT0CCorr, BDTresponse[0], BDTresponse[1], 0); + } } } - void processAnalyseDataEPCentralFW(CollEventPlaneCentralFW const& coll, soa::Join const& Cascades, DauTracks const&) + void processAnalyseDataEP2CentralFW(CollEventPlaneCentralFWOnlyFT0C const& coll, CascCandidates const& Cascades, DauTracks const&) { - if (!AcceptEvent(coll)) { + 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) { + if (std::abs(coll.qvecFT0CRe()) > 990 || std::abs(coll.qvecFT0CIm()) > 990 || std::abs(coll.qvecBNegRe()) > 990 || std::abs(coll.qvecBNegIm()) > 990 || std::abs(coll.qvecBPosRe()) > 990 || std::abs(coll.qvecBPosIm()) > 990) { return; } } - histos.fill(HIST("hNEvents"), 7.5); + // event has FT0C event plane + bool hasEventPlane = 0; + if (std::abs(coll.qvecFT0CRe()) < 990 && std::abs(coll.qvecFT0CIm()) < 990) + hasEventPlane = 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()); @@ -633,23 +1448,661 @@ struct cascadeFlow { 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}; - 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); + const float psiT0C = std::atan2(coll.qvecFT0CIm(), coll.qvecFT0CRe()) * 0.5f; + const float psiTPCA = std::atan2(coll.qvecBPosIm(), coll.qvecBPosRe()) * 0.5f; + const float psiTPCC = std::atan2(coll.qvecBNegIm(), coll.qvecBNegRe()) * 0.5f; + float psiT0CCorr = psiT0C; + for (int ishift = 1; ishift <= 10; ishift++) { + histos.fill(HIST("ShiftFT0C"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiT0C)); + histos.fill(HIST("ShiftFT0C"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiT0C)); + + histos.fill(HIST("ShiftTPCL"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiTPCA)); + histos.fill(HIST("ShiftTPCL"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiTPCA)); + + histos.fill(HIST("ShiftTPCR"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiTPCC)); + histos.fill(HIST("ShiftTPCR"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiTPCC)); + } + + if (ShiftConfigs.cfgShiftCorr) { + currentRunNumber = coll.runNumber(); + if (currentRunNumber != lastRunNumber) { + fullCCDBShiftCorrPathFT0C = ShiftConfigs.cfgShiftPathFT0C; + fullCCDBShiftCorrPathTPCL = ShiftConfigs.cfgShiftPathTPCL; + fullCCDBShiftCorrPathTPCR = ShiftConfigs.cfgShiftPathTPCR; + shiftprofileFT0C = ccdb->getForTimeStamp(fullCCDBShiftCorrPathFT0C, coll.timestamp()); + shiftprofileTPCL = ccdb->getForTimeStamp(fullCCDBShiftCorrPathTPCL, coll.timestamp()); + shiftprofileTPCR = ccdb->getForTimeStamp(fullCCDBShiftCorrPathTPCR, coll.timestamp()); + lastRunNumber = currentRunNumber; + } + } + + if (ShiftConfigs.cfgShiftCorr) { + psiT0CCorr = ApplyShiftCorrection(coll, psiT0C, shiftprofileFT0C); + ComputeEPResolutionwShifts(coll, psiT0C, psiT0C, psiT0C, psiTPCA, psiTPCC, shiftprofileFT0C, shiftprofileTPCL, shiftprofileTPCR, shiftprofileFT0C, shiftprofileFT0C); + } + + histos.fill(HIST("hPsiT0C"), psiT0CCorr); + histos.fill(HIST("hPsiT0CvsCentFT0C"), coll.centFT0C(), psiT0CCorr); 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("EP_T0CTPCA"), std::cos(2 * (psiT0C - psiTPCA)), coll.centFT0C()); + resolution.fill(HIST("EP_T0CTPCC"), std::cos(2 * (psiT0C - psiTPCC)), coll.centFT0C()); + resolution.fill(HIST("EP_TPCAC"), std::cos(2 * (psiTPCA - psiTPCC)), 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()); + + std::vector bdtScore[nParticles]; + for (auto const& 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; + bool isCascCandidate = 0; + isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); + histos.fill(HIST("hCascade"), counter); + histos.fill(HIST("hCascadeDauSel"), (int)isCascCandidate); + if (!isCascCandidate) + continue; + + // ML selections + bool isSelectedCasc[nParticles]{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[nParticles]{casc.mXi(), casc.mOmega()}; + + // pt 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 < nParticles; ++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); // not normalised by amplitude + auto cascminuspsiT0C = GetPhiInRange(casc.phi() - psiT0CCorr); + auto v2CEP = std::cos(2.0 * cascminuspsiT0C); + ROOT::Math::XYZVector cascUvec{std::cos(casc.phi()), std::sin(casc.phi()), 0}; + + // polarization variables + double masses[nParticles]{o2::constants::physics::MassXiMinus, o2::constants::physics::MassOmegaMinus}; + ROOT::Math::PxPyPzMVector cascadeVector[nParticles], lambdaVector, protonVector; + float cosThetaStarLambda[nParticles], 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 < nParticles; ++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 = std::sqrt(std::pow(casc.pxlambda(), 2) + std::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() - psiT0CCorr)) / cascadev2::AlphaXi[chargeIndex] / meanCos2ThetaLambdaFromXi; + double pzs2Omega = cosThetaStarLambda[1] * std::sin(2 * (casc.phi() - psiT0CCorr)) / cascadev2::AlphaOmega[chargeIndex] / meanCos2ThetaLambdaFromOmega; + double cos2ThetaXi = cosThetaStarLambda[0] * cosThetaStarLambda[0]; + double cos2ThetaOmega = cosThetaStarLambda[1] * cosThetaStarLambda[1]; + double pzs2LambdaFromCasc = cosThetaStarProton * std::sin(2 * (casc.phi() - psiT0CCorr)) / 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("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[nParticles]{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, 0, casc, v2CSP, v2CEP, 0, 0, psiT0CCorr, BDTresponse[0], BDTresponse[1], 0); + } + } + } + + void processAnalyseLambdaEP2CentralFW(CollEventPlaneCentralFW const& coll, V0Candidates const& V0s, DauTracks const&) + { + + histos.fill(HIST("hEventCentralityBefEvSel"), coll.centFT0C()); + histos.fill(HIST("hEventCentralityBefEvSelT0M"), coll.centFT0M()); + + Float_t collisionCentrality = 0; + if (isCollisionCentrality == 0) { // T0C + collisionCentrality = coll.centFT0C(); + } else if (isCollisionCentrality == 1) { // T0M + collisionCentrality = coll.centFT0M(); + } + + if (!AcceptEvent(coll, 1)) { + return; + } + + double qvecRe = 0; + double qvecIm = 0; + + if (isQVecT0C) { + qvecRe = coll.qvecFT0CRe(); + qvecIm = coll.qvecFT0CIm(); + } else if (isQVecT0A) { + qvecRe = coll.qvecFT0ARe(); + qvecIm = coll.qvecFT0AIm(); + } else if (isQVecT0M) { + qvecRe = coll.qvecFT0MRe(); + qvecIm = coll.qvecFT0MIm(); + } else if (isQVecV0A) { + qvecRe = coll.qvecFV0ARe(); + qvecIm = coll.qvecFV0AIm(); + } + + double qvecReV0A = coll.qvecFV0ARe(); + double qvecImV0A = coll.qvecFV0AIm(); + double qvecReT0A = coll.qvecFT0ARe(); + double qvecImT0A = coll.qvecFT0AIm(); + + histos.fill(HIST("hEventCentralityBefEPSel"), collisionCentrality); + histos.fill(HIST("hEventCentralityBefEPSelT0M"), coll.centFT0M()); + // select only events used for the calibration of the event plane + if (isGoodEventEP) { + if (std::abs(qvecRe) > 990 || std::abs(qvecIm) > 990 || std::abs(coll.qvecBNegRe()) > 990 || std::abs(coll.qvecBNegIm()) > 990 || std::abs(coll.qvecBPosRe()) > 990 || std::abs(coll.qvecBPosIm()) > 990) { + return; + } + } + + bool hasSpectatorPlane = 0; + bool hasEventPlane = 1; + + histos.fill(HIST("hNEvents"), 9.5); + histos.fill(HIST("hEventNchCorrelationAfterEP"), coll.multNTracksPVeta1(), coll.multNTracksGlobal()); + histos.fill(HIST("hEventPVcontributorsVsCentralityAfterEP"), collisionCentrality, coll.multNTracksPVeta1()); + histos.fill(HIST("hEventGlobalTracksVsCentralityAfterEP"), collisionCentrality, coll.multNTracksGlobal()); + + histos.fill(HIST("hEventCentrality"), collisionCentrality); + histos.fill(HIST("hEventCentralityT0M"), coll.centFT0M()); + histos.fill(HIST("hEventVertexZ"), coll.posZ()); + + ROOT::Math::XYZVector eventplaneVecT0C{qvecRe, qvecIm, 0}; + ROOT::Math::XYZVector eventplaneVecV0A{qvecReV0A, qvecImV0A, 0}; + ROOT::Math::XYZVector eventplaneVecT0A{qvecReT0A, qvecImT0A, 0}; + ROOT::Math::XYZVector eventplaneVecTPCA{coll.qvecBPosRe(), coll.qvecBPosIm(), 0}; + ROOT::Math::XYZVector eventplaneVecTPCC{coll.qvecBNegRe(), coll.qvecBNegIm(), 0}; + + const float psiT0C = std::atan2(qvecIm, qvecRe) * 0.5f; + const float psiV0A = std::atan2(qvecImV0A, qvecReV0A) * 0.5f; + const float psiT0A = std::atan2(qvecImT0A, qvecReT0A) * 0.5f; + const float psiTPCA = std::atan2(coll.qvecBPosIm(), coll.qvecBPosRe()) * 0.5f; + const float psiTPCC = std::atan2(coll.qvecBNegIm(), coll.qvecBNegRe()) * 0.5f; + float psiT0CCorr = psiT0C; + for (int ishift = 1; ishift <= 10; ishift++) { + histos.fill(HIST("ShiftFT0C"), collisionCentrality, 0.5, ishift - 0.5, std::sin(ishift * 2 * psiT0C)); + histos.fill(HIST("ShiftFT0C"), collisionCentrality, 1.5, ishift - 0.5, std::cos(ishift * 2 * psiT0C)); + + histos.fill(HIST("ShiftFV0A"), collisionCentrality, 0.5, ishift - 0.5, std::sin(ishift * 2 * psiV0A)); + histos.fill(HIST("ShiftFV0A"), collisionCentrality, 1.5, ishift - 0.5, std::cos(ishift * 2 * psiV0A)); + + histos.fill(HIST("ShiftFT0A"), collisionCentrality, 0.5, ishift - 0.5, std::sin(ishift * 2 * psiT0A)); + histos.fill(HIST("ShiftFT0A"), collisionCentrality, 1.5, ishift - 0.5, std::cos(ishift * 2 * psiT0A)); + + histos.fill(HIST("ShiftTPCL"), collisionCentrality, 0.5, ishift - 0.5, std::sin(ishift * 2 * psiTPCA)); + histos.fill(HIST("ShiftTPCL"), collisionCentrality, 1.5, ishift - 0.5, std::cos(ishift * 2 * psiTPCA)); + + histos.fill(HIST("ShiftTPCR"), collisionCentrality, 0.5, ishift - 0.5, std::sin(ishift * 2 * psiTPCC)); + histos.fill(HIST("ShiftTPCR"), collisionCentrality, 1.5, ishift - 0.5, std::cos(ishift * 2 * psiTPCC)); + } + + if (ShiftConfigs.cfgShiftCorr) { + currentRunNumber = coll.runNumber(); + if (currentRunNumber != lastRunNumber) { + fullCCDBShiftCorrPathFT0C = ShiftConfigs.cfgShiftPathFT0C; + fullCCDBShiftCorrPathTPCL = ShiftConfigs.cfgShiftPathTPCL; + fullCCDBShiftCorrPathTPCR = ShiftConfigs.cfgShiftPathTPCR; + fullCCDBShiftCorrPathFV0A = ShiftConfigs.cfgShiftPathFV0A; + fullCCDBShiftCorrPathFT0A = ShiftConfigs.cfgShiftPathFT0A; + shiftprofileFT0C = ccdb->getForTimeStamp(fullCCDBShiftCorrPathFT0C, coll.timestamp()); + shiftprofileTPCL = ccdb->getForTimeStamp(fullCCDBShiftCorrPathTPCL, coll.timestamp()); + shiftprofileTPCR = ccdb->getForTimeStamp(fullCCDBShiftCorrPathTPCR, coll.timestamp()); + shiftprofileFV0A = ccdb->getForTimeStamp(fullCCDBShiftCorrPathFV0A, coll.timestamp()); + shiftprofileFT0A = ccdb->getForTimeStamp(fullCCDBShiftCorrPathFT0A, coll.timestamp()); + lastRunNumber = currentRunNumber; + } + } + + if (ShiftConfigs.cfgShiftCorr) { + psiT0CCorr = ApplyShiftCorrection(coll, psiT0C, shiftprofileFT0C); + ComputeEPResolutionwShifts(coll, psiT0C, psiV0A, psiT0A, psiTPCA, psiTPCC, shiftprofileFT0C, shiftprofileTPCL, shiftprofileTPCR, shiftprofileFV0A, shiftprofileFT0A); + } + + histos.fill(HIST("hPsiT0C"), psiT0CCorr); + histos.fill(HIST("hPsiT0CvsCentFT0C"), collisionCentrality, psiT0CCorr); + + resolution.fill(HIST("QVectorsT0CTPCA"), eventplaneVecT0C.Dot(eventplaneVecTPCA), collisionCentrality); + resolution.fill(HIST("QVectorsT0CTPCC"), eventplaneVecT0C.Dot(eventplaneVecTPCC), collisionCentrality); + resolution.fill(HIST("QVectorsTPCAC"), eventplaneVecTPCA.Dot(eventplaneVecTPCC), collisionCentrality); + resolution.fill(HIST("QVectorsT0CV0A"), eventplaneVecT0C.Dot(eventplaneVecV0A), collisionCentrality); + resolution.fill(HIST("QVectorsV0ATPCC"), eventplaneVecV0A.Dot(eventplaneVecTPCC), collisionCentrality); + resolution.fill(HIST("QVectorsV0ATPCA"), eventplaneVecV0A.Dot(eventplaneVecTPCA), collisionCentrality); + resolution.fill(HIST("QVectorsT0CT0A"), eventplaneVecT0C.Dot(eventplaneVecT0A), collisionCentrality); + resolution.fill(HIST("QVectorsT0ATPCC"), eventplaneVecT0A.Dot(eventplaneVecTPCC), collisionCentrality); + resolution.fill(HIST("QVectorsT0ATPCA"), eventplaneVecT0A.Dot(eventplaneVecTPCA), collisionCentrality); + + resolution.fill(HIST("EP_T0CTPCA"), std::cos(2 * (psiT0C - psiTPCA)), coll.centFT0C()); + resolution.fill(HIST("EP_T0CTPCC"), std::cos(2 * (psiT0C - psiTPCC)), coll.centFT0C()); + resolution.fill(HIST("EP_TPCAC"), std::cos(2 * (psiTPCA - psiTPCC)), coll.centFT0C()); + resolution.fill(HIST("EP_T0CV0A"), std::cos(2 * (psiT0C - psiV0A)), coll.centFT0C()); + resolution.fill(HIST("EP_V0ATPCC"), std::cos(2 * (psiV0A - psiTPCC)), coll.centFT0C()); + resolution.fill(HIST("EP_V0ATPCA"), std::cos(2 * (psiV0A - psiTPCA)), coll.centFT0C()); + resolution.fill(HIST("EP_T0CT0A"), std::cos(2 * (psiT0C - psiT0A)), coll.centFT0C()); + resolution.fill(HIST("EP_T0ATPCC"), std::cos(2 * (psiT0A - psiTPCC)), coll.centFT0C()); + resolution.fill(HIST("EP_T0ATPCA"), std::cos(2 * (psiT0A - psiTPCA)), coll.centFT0C()); + + resolution.fill(HIST("QVectorsNormT0CTPCA"), eventplaneVecT0C.Dot(eventplaneVecTPCA) / (coll.qTPCR() * coll.sumAmplFT0C()), collisionCentrality); + resolution.fill(HIST("QVectorsNormT0CTPCC"), eventplaneVecT0C.Dot(eventplaneVecTPCC) / (coll.qTPCL() * coll.sumAmplFT0C()), collisionCentrality); + resolution.fill(HIST("QVectorsNormTPCAC"), eventplaneVecTPCA.Dot(eventplaneVecTPCC) / (coll.qTPCR() * coll.qTPCL()), collisionCentrality); + resolution.fill(HIST("QVectorsNormT0CV0A"), eventplaneVecT0C.Dot(eventplaneVecV0A) / (coll.sumAmplFT0C() * coll.sumAmplFV0A()), collisionCentrality); + resolution.fill(HIST("QVectorsNormV0ATPCC"), eventplaneVecV0A.Dot(eventplaneVecTPCC) / (coll.qTPCL() * coll.sumAmplFV0A()), collisionCentrality); + resolution.fill(HIST("QVectorsNormV0ATPCA"), eventplaneVecV0A.Dot(eventplaneVecTPCA) / (coll.qTPCR() * coll.sumAmplFV0A()), collisionCentrality); + resolution.fill(HIST("QVectorsNormT0CT0A"), eventplaneVecT0C.Dot(eventplaneVecT0A) / (coll.sumAmplFT0C() * coll.sumAmplFT0A()), collisionCentrality); + resolution.fill(HIST("QVectorsNormT0ATPCC"), eventplaneVecT0A.Dot(eventplaneVecTPCC) / (coll.qTPCL() * coll.sumAmplFT0A()), collisionCentrality); + resolution.fill(HIST("QVectorsNormT0ATPCA"), eventplaneVecT0A.Dot(eventplaneVecTPCA) / (coll.qTPCR() * coll.sumAmplFT0A()), collisionCentrality); + + std::vector bdtScore[nParticles]; + for (auto const& v0 : V0s) { + + /// Add some minimal cuts for single track variables (min number of TPC clusters) + auto negExtra = v0.negTrackExtra_as(); + auto posExtra = v0.posTrackExtra_as(); + + int counterLambda = 0; + int counterALambda = 0; + bool isLambdaCandidate = 0; + bool isALambdaCandidate = 0; + if (isLambdaAccepted(negExtra, posExtra, counterLambda)) + isLambdaCandidate = 1; + if (isAntiLambdaAccepted(negExtra, posExtra, counterALambda)) + isALambdaCandidate = 1; + histos.fill(HIST("hLambdaDauSel"), counterLambda); + histos.fill(HIST("hALambdaDauSel"), counterALambda); + + // pt cut + if (v0.pt() < V0Configs.MinPtV0 || v0.pt() > V0Configs.MaxPtV0) { + continue; + } + + float massV0[nCharges]{v0.mLambda(), v0.mAntiLambda()}; + lambdav2::hMassBeforeSelVsPt[0]->Fill(massV0[0], v0.pt()); + lambdav2::hMassBeforeSelVsPt[1]->Fill(massV0[1], v0.pt()); + + bool isSelectedV0[2]{false, false}; + if (isV0TopoAccepted(v0) && isLambdaCandidate) + isSelectedV0[0] = true; + if (isV0TopoAccepted(v0) && isALambdaCandidate) + isSelectedV0[1] = true; + + int chargeIndex = -1; + if (isSelectedV0[0] && !isSelectedV0[1]) { // Lambdas + histos.fill(HIST("hLambdaCandidate"), 0); + chargeIndex = 0; + } + if (isSelectedV0[1] && !isSelectedV0[0]) { // AntiLambdas + histos.fill(HIST("hLambdaCandidate"), 1); + chargeIndex = 1; + } + if (isSelectedV0[0] && isSelectedV0[1]) { + histos.fill(HIST("hLambdaCandidate"), 2); + if (v0.mLambda() > V0Configs.MinMassLambda && v0.mLambda() < V0Configs.MaxMassLambda && v0.mAntiLambda() > V0Configs.MinMassLambda && v0.mAntiLambda() < V0Configs.MaxMassLambda) { + histos.fill(HIST("hLambdaCandidate"), 3); + continue; // in case of ambiguity between Lambda and AntiLambda, I skip the particle; checked to be zero in range 1.105 - 1.125 + } + if (v0.mLambda() > V0Configs.MinMassLambda && v0.mLambda() < V0Configs.MaxMassLambda) + chargeIndex = 0; + else if (v0.mAntiLambda() > V0Configs.MinMassLambda && v0.mAntiLambda() < V0Configs.MaxMassLambda) + chargeIndex = 1; + else { + chargeIndex = 2; // these are bkg candidates + histos.fill(HIST("hLambdaCandidate"), 4); + } + } + if (!isSelectedV0[0] && !isSelectedV0[1]) + continue; + + ROOT::Math::XYZVector lambdaQvec{std::cos(2 * v0.phi()), std::sin(2 * v0.phi()), 0}; + auto v2CSP = lambdaQvec.Dot(eventplaneVecT0C); // not normalised by amplitude + auto lambdaminuspsiT0C = GetPhiInRange(v0.phi() - psiT0CCorr); + auto v2CEP = std::cos(2.0 * lambdaminuspsiT0C); + ROOT::Math::XYZVector lambdaUvec{std::cos(v0.phi()), std::sin(v0.phi()), 0}; + + // polarization variables + double massLambda = o2::constants::physics::MassLambda; + float cosThetaStarProton[nCharges]; + ROOT::Math::PxPyPzMVector lambdaVector, protonVector[nCharges]; + lambdaVector.SetCoordinates(v0.px(), v0.py(), v0.pz(), massLambda); + ROOT::Math::Boost lambdaBoost{lambdaVector.BoostToCM()}; + for (int i{0}; i < nCharges; ++i) { + if (i == 0) + protonVector[i].SetCoordinates(v0.pxpos(), v0.pypos(), v0.pzpos(), o2::constants::physics::MassProton); + else + protonVector[i].SetCoordinates(v0.pxneg(), v0.pyneg(), v0.pzneg(), o2::constants::physics::MassProton); + auto boostedProton{lambdaBoost(protonVector[i])}; + cosThetaStarProton[i] = boostedProton.Pz() / boostedProton.P(); + } + + // acceptance values if requested + double meanCos2ThetaProtonFromLambda = 1; + if (applyAcceptanceCorrection) { + int bin2DLambda = hAcceptanceLambda->FindBin(v0.pt(), v0.eta()); + meanCos2ThetaProtonFromLambda = hAcceptancePrimaryLambda->GetBinContent(bin2DLambda); + } + + double pzs2Lambda = 0; + double cos2ThetaLambda = 0; + double cosThetaLambda = 0; + if (chargeIndex == 0) { + pzs2Lambda = cosThetaStarProton[0] * std::sin(2 * (v0.phi() - psiT0CCorr)) / lambdav2::AlphaLambda[0] / meanCos2ThetaProtonFromLambda; + cos2ThetaLambda = cosThetaStarProton[0] * cosThetaStarProton[0]; + cosThetaLambda = cosThetaStarProton[0] / cascadev2::AlphaLambda[0] / meanCos2ThetaProtonFromLambda; + } else if (chargeIndex == 1) { + pzs2Lambda = cosThetaStarProton[1] * std::sin(2 * (v0.phi() - psiT0CCorr)) / lambdav2::AlphaLambda[1] / meanCos2ThetaProtonFromLambda; + cos2ThetaLambda = cosThetaStarProton[1] * cosThetaStarProton[1]; + cosThetaLambda = cosThetaStarProton[1] / cascadev2::AlphaLambda[1] / meanCos2ThetaProtonFromLambda; + } else { // I treat these bkg candidates as Lambdas for the purpose of calculating Pz + pzs2Lambda = cosThetaStarProton[0] * std::sin(2 * (v0.phi() - psiT0CCorr)) / lambdav2::AlphaLambda[0] / meanCos2ThetaProtonFromLambda; + cos2ThetaLambda = cosThetaStarProton[0] * cosThetaStarProton[0]; + cosThetaLambda = cosThetaStarProton[0] / cascadev2::AlphaLambda[0] / meanCos2ThetaProtonFromLambda; + } + + histos.fill(HIST("hv2CEPvsFT0C"), collisionCentrality, v2CEP); + histos.fill(HIST("hv2CEPvsv2CSP"), v2CSP, v2CEP); + histos.fill(HIST("hLambdaPhi"), v0.phi()); + histos.fill(HIST("hlambdaminuspsiT0C"), lambdaminuspsiT0C); + + if (fillingConfigs.isFillTHNLambda) { + if (fillingConfigs.isFillTHN_V2) + histos.get(HIST("hLambdaV2"))->Fill(collisionCentrality, chargeIndex, v0.pt(), v0.mLambda(), v2CEP); + if (fillingConfigs.isFillTHN_Pz) { + histos.get(HIST("hLambdaPzs2"))->Fill(collisionCentrality, chargeIndex, v0.pt(), v0.mLambda(), pzs2Lambda); + } + if (fillingConfigs.isFillTHN_Acc) + histos.get(HIST("hLambdaCos2Theta"))->Fill(collisionCentrality, chargeIndex, v0.eta(), v0.pt(), v0.mLambda(), cos2ThetaLambda); + } + if (fillingConfigs.isFillTHNLambda_PzVsPsi) { + if (fillingConfigs.isFillTHN_Pz) + histos.get(HIST("hLambdaPzVsPsi"))->Fill(collisionCentrality, chargeIndex, v0.pt(), v0.mLambda(), cosThetaLambda, 2 * lambdaminuspsiT0C); + if (fillingConfigs.isFillTHN_Acc) + histos.get(HIST("hLambdaCos2ThetaVsPsi"))->Fill(collisionCentrality, chargeIndex, v0.eta(), v0.pt(), v0.mLambda(), cos2ThetaLambda, 2 * lambdaminuspsiT0C); + } + + double invMassLambda = 0; + if (chargeIndex == 0) + invMassLambda = v0.mLambda(); + else if (chargeIndex == 1) + invMassLambda = v0.mAntiLambda(); + else + invMassLambda = v0.mLambda(); + + // mass selection + if (invMassLambda < V0Configs.MinMassLambdaInTree || invMassLambda > V0Configs.MaxMassLambdaInTree) + continue; + + if (fillingConfigs.isFillTree) + fillAnalysedLambdaTable(coll, hasEventPlane, hasSpectatorPlane, chargeIndex, v0, v2CEP, psiT0CCorr, pzs2Lambda, cos2ThetaLambda, cosThetaLambda); + } + } + + void processAnalyseDataEPCentralFW(CollEventAndSpecPlaneCentralFW 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 (std::abs(coll.qvecFT0CRe()) > 990 || std::abs(coll.qvecFT0CIm()) > 990 || std::abs(coll.qvecBNegRe()) > 990 || std::abs(coll.qvecBNegIm()) > 990 || std::abs(coll.qvecBPosRe()) > 990 || std::abs(coll.qvecBPosIm()) > 990) { + return; + } + } + + // event has FT0C event plane + bool hasEventPlane = 0; + if (std::abs(coll.qvecFT0CRe()) < 990 && std::abs(coll.qvecFT0CIm()) < 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 = std::sqrt(eventplaneVecT0C.Dot(eventplaneVecT0C)); + float NormQvTPCA = std::sqrt(eventplaneVecTPCA.Dot(eventplaneVecTPCA)); + float NormQvTPCC = std::sqrt(eventplaneVecTPCC.Dot(eventplaneVecTPCC)); + + const float psiT0C = std::atan2(coll.qvecFT0CIm(), coll.qvecFT0CRe()) * 0.5f; + const float psiTPCA = std::atan2(coll.qvecBPosIm(), coll.qvecBPosRe()) * 0.5f; + const float psiTPCC = std::atan2(coll.qvecBNegIm(), coll.qvecBNegRe()) * 0.5f; + float psiT0CCorr = psiT0C; + for (int ishift = 1; ishift <= 10; ishift++) { + histos.fill(HIST("ShiftFT0C"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiT0C)); + histos.fill(HIST("ShiftFT0C"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiT0C)); + + histos.fill(HIST("ShiftTPCL"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiTPCA)); + histos.fill(HIST("ShiftTPCL"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiTPCA)); + + histos.fill(HIST("ShiftTPCR"), coll.centFT0C(), 0.5, ishift - 0.5, std::sin(ishift * 2 * psiTPCC)); + histos.fill(HIST("ShiftTPCR"), coll.centFT0C(), 1.5, ishift - 0.5, std::cos(ishift * 2 * psiTPCC)); + } + if (ShiftConfigs.cfgShiftCorr) { + currentRunNumber = coll.runNumber(); + if (currentRunNumber != lastRunNumber) { + fullCCDBShiftCorrPathFT0C = ShiftConfigs.cfgShiftPathFT0C; + fullCCDBShiftCorrPathTPCL = ShiftConfigs.cfgShiftPathTPCL; + fullCCDBShiftCorrPathTPCR = ShiftConfigs.cfgShiftPathTPCR; + shiftprofileFT0C = ccdb->getForTimeStamp(fullCCDBShiftCorrPathFT0C, coll.timestamp()); + shiftprofileTPCL = ccdb->getForTimeStamp(fullCCDBShiftCorrPathTPCL, coll.timestamp()); + shiftprofileTPCR = ccdb->getForTimeStamp(fullCCDBShiftCorrPathTPCR, coll.timestamp()); + lastRunNumber = currentRunNumber; + } + } + + if (ShiftConfigs.cfgShiftCorr) { + psiT0CCorr = ApplyShiftCorrection(coll, psiT0C, shiftprofileFT0C); + ComputeEPResolutionwShifts(coll, psiT0C, psiT0C, psiT0C, psiTPCA, psiTPCC, shiftprofileFT0C, shiftprofileTPCL, shiftprofileTPCR, shiftprofileFT0C, shiftprofileFT0C); + } + + histos.fill(HIST("hpsiT0C"), psiT0CCorr); + histos.fill(HIST("hpsiT0CvsCentFT0C"), coll.centFT0C(), psiT0CCorr); + + 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("EP_T0CTPCA"), std::cos(2 * (psiT0C - psiTPCA)), coll.centFT0C()); + resolution.fill(HIST("EP_T0CTPCC"), std::cos(2 * (psiT0C - psiTPCC)), coll.centFT0C()); + resolution.fill(HIST("EP_TPCAC"), std::cos(2 * (psiTPCA - psiTPCC)), 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) { + std::vector bdtScore[nParticles]; + for (auto const& casc : Cascades) { /// Add some minimal cuts for single track variables (min number of TPC clusters) auto negExtra = casc.negTrackExtra_as(); @@ -657,11 +2110,15 @@ struct cascadeFlow { auto bachExtra = casc.bachTrackExtra_as(); int counter = 0; - IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); + bool isCascCandidate = 0; + isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); histos.fill(HIST("hCascade"), counter); + histos.fill(HIST("hCascadeDauSel"), (int)isCascCandidate); + if (!isCascCandidate) + continue; // ML selections - bool isSelectedCasc[2]{false, false}; + bool isSelectedCasc[nParticles]{false, false}; std::vector inputFeaturesCasc{casc.cascradius(), casc.v0radius(), @@ -676,10 +2133,10 @@ struct cascadeFlow { casc.bachBaryonCosPA(), casc.bachBaryonDCAxyToPV()}; - float massCasc[2]{casc.mXi(), casc.mOmega()}; + float massCasc[nParticles]{casc.mXi(), casc.mOmega()}; // inv mass loose cut - if (casc.pt() < MinPt || casc.pt() > MaxPt) { + if (casc.pt() < CandidateConfigs.MinPt || casc.pt() > CandidateConfigs.MaxPt) { continue; } @@ -691,7 +2148,7 @@ struct cascadeFlow { 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) { + for (int iS{0}; iS < nParticles; ++iS) { // Fill BDT score histograms before selection cascadev2::hSignalScoreBeforeSel[iS]->Fill(bdtScore[0][1]); cascadev2::hBkgScoreBeforeSel[iS]->Fill(bdtScore[1][0]); @@ -710,11 +2167,20 @@ struct cascadeFlow { 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); + auto cascminuspsiT0C = GetPhiInRange(casc.phi() - psiT0CCorr); + auto v2CEP = std::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 = std::cos(casc.phi() - coll.psiZDCA()); + auto v1EP_ZDCC = std::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(), v2CSP, coll.centFT0C()}; @@ -726,20 +2192,251 @@ struct cascadeFlow { cascadev2::hSparseV2C[0]->Fill(values); } - float BDTresponse[2]{0.f, 0.f}; + float BDTresponse[nParticles]{0.f, 0.f}; + if (isApplyML) { + BDTresponse[0] = bdtScore[0][1]; + BDTresponse[1] = bdtScore[1][1]; + } + if (isSelectedCasc[0] || isSelectedCasc[1]) + if (fillingConfigs.isFillTree) + fillAnalysedTable(coll, hasEventPlane, hasSpectatorPlane, casc, v2CSP, v2CEP, v1SP_ZDCA, v1SP_ZDCC, psiT0CCorr, 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 info 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[nParticles]; + for (auto const& casc : Cascades) { + + if (!casc.has_cascMCCore()) + continue; + + auto cascMC = casc.cascMCCore_as>(); + + int pdgCode{cascMC.pdgCode()}; + if (!(std::abs(pdgCode) == PDG_t::kXiMinus && std::abs(cascMC.pdgCodeV0()) == PDG_t::kLambda0 && std::abs(cascMC.pdgCodeBachelor()) == PDG_t::kPiPlus) // Xi + && !(std::abs(pdgCode) == PDG_t::kOmegaMinus && std::abs(cascMC.pdgCodeV0()) == PDG_t::kLambda0 && std::abs(cascMC.pdgCodeBachelor()) == PDG_t::kKPlus)) // 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) == PDG_t::kXiMinus && std::abs(cascMC.pdgCodeV0()) == PDG_t::kLambda0 && std::abs(cascMC.pdgCodeBachelor()) == PDG_t::kPiPlus) { + 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) == PDG_t::kOmegaMinus && std::abs(cascMC.pdgCodeV0()) == PDG_t::kLambda0 && std::abs(cascMC.pdgCodeBachelor()) == PDG_t::kKPlus) { + 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; + bool isCascCandidate = 0; + isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); + histos.fill(HIST("hCascade"), counter); + histos.fill(HIST("hCascadeDauSel"), (int)isCascCandidate); + if (!isCascCandidate) + continue; + + // ML selections + bool isSelectedCasc[nParticles]{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[nParticles]{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 < nParticles; ++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[nParticles]{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, casc, v2CSP, v2CEP, PsiT0C, BDTresponse[0], BDTresponse[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 (std::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 (std::abs(cascmc.pdgCode()) == PDG_t::kXiMinus) + histosMCGen.fill(HIST("hNCascGen"), 0.5); + else if (std::abs(cascmc.pdgCode()) == PDG_t::kOmegaMinus) + histosMCGen.fill(HIST("hNCascGen"), 1.5); + if (!cascmc.has_straMCCollision()) + continue; + if (std::abs(cascmc.pdgCode()) == PDG_t::kXiMinus) + histosMCGen.fill(HIST("hNCascGen"), 2.5); + else if (std::abs(cascmc.pdgCode()) == PDG_t::kOmegaMinus) + histosMCGen.fill(HIST("hNCascGen"), 3.5); + if (!cascmc.isPhysicalPrimary()) + continue; + if (std::abs(cascmc.pdgCode()) == PDG_t::kXiMinus) + histosMCGen.fill(HIST("hNCascGen"), 4.5); + else if (std::abs(cascmc.pdgCode()) == PDG_t::kOmegaMinus) + 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 = o2::constants::math::PI + theta; // pi/2 < theta1 < pi --> pi/4 < theta1/2 < pi/2 --> 1 < tan (theta1/2) --> negative eta + + float cascMCeta = -std::log(std::tan(theta1 / 2)); + float cascMCy = 0; + if (std::abs(cascmc.pdgCode()) == PDG_t::kXiMinus) { + cascMCy = RecoDecay::y(std::array{cascmc.pxMC(), cascmc.pyMC(), cascmc.pzMC()}, constants::physics::MassXiMinus); + if (std::abs(cascMCeta) < etaCascMCGen) { + histosMCGen.fill(HIST("h2DGenXiEta08"), centrality, ptmc); + histosMCGen.fill(HIST("hNCascGen"), 6.5); + } + if (std::abs(cascMCy) < yCascMCGen) + histosMCGen.fill(HIST("h2DGenXiY05"), centrality, ptmc); + histosMCGen.fill(HIST("hGenXiY"), cascMCy); + } else if (std::abs(cascmc.pdgCode()) == PDG_t::kOmegaMinus) { + cascMCy = RecoDecay::y(std::array{cascmc.pxMC(), cascmc.pyMC(), cascmc.pzMC()}, constants::physics::MassOmegaMinus); + if (std::abs(cascMCeta) < etaCascMCGen) { + histosMCGen.fill(HIST("h2DGenOmegaEta08"), centrality, ptmc); + histosMCGen.fill(HIST("hNCascGen"), 7.5); + } + if (std::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, processAnalyseDataEP2CentralFW, "Process to apply ML model to the data - second order event plane calibration from central framework", false); PROCESS_SWITCH(cascadeFlow, processAnalyseDataEPCentralFW, "Process to apply ML model to the data - event plane calibration from central framework", false); + PROCESS_SWITCH(cascadeFlow, processAnalyseLambdaEP2CentralFW, "Process to measure flow and polarization of Lambda - 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 4084afdcae4..3d4a5642004 100644 --- a/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx @@ -61,6 +61,8 @@ struct cascademcbuilder { 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"}; //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -76,6 +78,9 @@ struct cascademcbuilder { int pdgCodeNegative; int pdgCodeBachelor; bool isPhysicalPrimary; + int processPositive = -1; + int processNegative = -1; + int processBachelor = -1; std::array xyz; std::array lxyz; std::array posP; @@ -89,7 +94,35 @@ struct cascademcbuilder { mcCascinfo thisInfo; //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - void init(InitContext const&) {} + // 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; + } template void generateCascadeMCinfo(TCascadeTable cascTable, TMCParticleTable mcParticles) @@ -142,60 +175,64 @@ struct cascademcbuilder { 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 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 (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 + } - // Step 1: check if the mother is the same, go up a level - if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { - for (auto& lNegMother : lMCNegTrack.template mothers_as()) { - for (auto& lPosMother : lMCPosTrack.template mothers_as()) { - if (lNegMother == lPosMother) { - // acquire information - thisInfo.lxyz[0] = lMCPosTrack.vx(); - thisInfo.lxyz[1] = lMCPosTrack.vy(); - thisInfo.lxyz[2] = lMCPosTrack.vz(); - thisInfo.pdgCodeV0 = lNegMother.pdgCode(); - - // 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 - if (lNegMother.has_mothers() && lMCBachTrack.has_mothers()) { - for (auto& lV0Mother : lNegMother.template mothers_as()) { - for (auto& lBachMother : lMCBachTrack.template mothers_as()) { - if (lV0Mother == lBachMother) { - 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] = lMCBachTrack.vx(); - thisInfo.xyz[1] = lMCBachTrack.vy(); - thisInfo.xyz[2] = lMCBachTrack.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 has mothers - } // end neg = pos mother conditional - } - } // end loop neg/pos mothers - } // end conditional of mothers existing + 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 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( thisInfo.label, thisInfo.motherLabel); // Mark mcParticle as recoed (no searching necessary afterwards) - if (thisInfo.motherLabel > -1) { - mcParticleIsReco[thisInfo.motherLabel] = true; + if (thisInfo.label > -1) { + mcParticleIsReco[thisInfo.label] = true; } if (populateCascMCCoresSymmetric) { @@ -216,10 +253,7 @@ struct cascademcbuilder { // 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.mcParticlePositive == mcCascinfos[ii].mcParticlePositive && mcCascinfos[ii].mcParticlePositive > 0 && - thisInfo.mcParticleNegative == mcCascinfos[ii].mcParticleNegative && mcCascinfos[ii].mcParticleNegative > 0 && - thisInfo.mcParticleBachelor == mcCascinfos[ii].mcParticleBachelor && mcCascinfos[ii].mcParticleBachelor > 0) { + if (thisInfo.label == mcCascinfos[ii].label && mcCascinfos[ii].label > -1) { thisCascMCCoreIndex = ii; break; // this exists already in list } @@ -272,6 +306,54 @@ struct cascademcbuilder { 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); diff --git a/PWGLF/TableProducer/Strangeness/cascademcfinder.cxx b/PWGLF/TableProducer/Strangeness/cascademcfinder.cxx index 8d26f0ea33c..9eab47336f0 100644 --- a/PWGLF/TableProducer/Strangeness/cascademcfinder.cxx +++ b/PWGLF/TableProducer/Strangeness/cascademcfinder.cxx @@ -24,37 +24,38 @@ // david.dobrigkeit.chinellato@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessTables.h" -#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/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/McCollisionExtra.h" -#include "Common/DataModel/PIDResponse.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 "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" + #include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include #include -#include #include #include -#include +#include #include -#include +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/TableProducer/Strangeness/cascademlselection.cxx b/PWGLF/TableProducer/Strangeness/cascademlselection.cxx new file mode 100644 index 00000000000..14d87bbaa90 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/cascademlselection.cxx @@ -0,0 +1,325 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.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/TrackSelectionTables.h" +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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; + + // Custom grouping + std::vector> cascadesGrouped; + + 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 const& collisions, CascDerivedDatas const& cascades) + { + // Custom grouping + cascadesGrouped.clear(); + cascadesGrouped.resize(collisions.size()); + + for (const auto& cascade : cascades) { + cascadesGrouped[cascade.straCollisionId()].push_back(cascade.globalIndex()); + } + + for (const auto& collision : collisions) { + initCCDB(collision); + + histos.fill(HIST("hEventVertexZ"), collision.posZ()); + for (std::size_t i = 0; i < cascadesGrouped[collision.globalIndex()].size(); i++) { + auto casc = cascades.rawIteratorAt(cascadesGrouped[collision.globalIndex()][i]); + nCandidates++; + if (nCandidates % 50000 == 0) { + LOG(info) << "Candidates processed: " << nCandidates; + } + processCandidate(casc); + } + } + } + void processStandardData(aod::Collisions const& collisions, CascOriginalDatas const& cascades) + { + // Custom grouping + cascadesGrouped.clear(); + cascadesGrouped.resize(collisions.size()); + + for (const auto& cascade : cascades) { + cascadesGrouped[cascade.collisionId()].push_back(cascade.globalIndex()); + } + + for (const auto& collision : collisions) { + initCCDB(collision); + + histos.fill(HIST("hEventVertexZ"), collision.posZ()); + for (std::size_t i = 0; i < cascadesGrouped[collision.globalIndex()].size(); i++) { + auto casc = cascades.rawIteratorAt(cascadesGrouped[collision.globalIndex()][i]); + 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 deleted file mode 100644 index c9faa24a4ed..00000000000 --- a/PWGLF/TableProducer/Strangeness/cascadepid.cxx +++ /dev/null @@ -1,619 +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. -// -// *+-+*+-+*+-+*+-+*+-+*+-+* -// Cascade PID tables -// *+-+*+-+*+-+*+-+*+-+*+-+* -// -/// \author Nicolò Jacazio -/// \author David Dobrigkeit Chinellato -/// \since 22/11/2023 -/// \brief Table producer for Casc daughter PID info -// -// This task produces daughter PID information for strange daughters -// taking into account the (candidate-by-candidate) time spent as a heavier -// (strange, weakly-decaying) particle. This task is meant to be a test, as -// it hasn't been fully tested yet! Use at your own peril for now :-) - -#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 "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" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -// For original data loops -using CascOriginalDatas = soa::Join; -using TracksWithAllExtras = soa::Join; - -// Cores with references and TOF pid -using dauTracks = soa::Join; -using CascDerivedDatas = soa::Join; - -struct cascadepid { - // TOF pid for strangeness (recalculated with topology) - Produces casctofpids; // table with base info - Produces casctofnsigmas; // table with Nsigmas - - Service ccdb; - - // For manual sliceBy - Preslice perCollisionOriginal = o2::aod::cascdata::collisionId; - ; - Preslice perCollisionDerived = o2::aod::cascdata::straCollisionId; - - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - // Operation and minimisation criteria - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable tofPosition{"tofPosition", 377.934f, "TOF effective (inscribed) radius"}; - Configurable doQA{"doQA", true, "create QA histos"}; - Configurable qaV0DCADau{"qaV0DCADau", 0.5, "DCA daughters (cm) for QA plots"}; - Configurable qaCascDCADau{"qaCascDCADau", 0.5, "DCA daughters (cm) for QA plots"}; - Configurable qaV0CosPA{"qaV0CosPA", 0.995, "CosPA for QA plots"}; - Configurable qaCascCosPA{"qaCascCosPA", 0.995, "CosPA for QA plots"}; - Configurable qaMassWindow{"qaMassWindow", 0.005, "Mass window around expected (in GeV/c2) for QA plots"}; - Configurable qaTPCNSigma{"qaTPCNSigma", 5, "TPC N-sigma to apply for qa plots"}; - Configurable doNSigmas{"doNSigmas", false, "calculate TOF N-sigma"}; - Configurable doQANSigma{"doQANSigma", false, "create QA of Nsigma histos"}; - - // 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 nSigmaPath{"nSigmaPath", "Users/d/ddobrigk/stratof", "Path of information for n-sigma calculation"}; - - 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)"}; - ConfigurableAxis axisTime{"axisTime", {200, 0.0f, +20000.0f}, "T (ps)"}; - 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)"}; - - bool nSigmaCalibLoaded; - TList* nSigmaCalibObjects; - TH1 *hMeanPosXiPi, *hSigmaPosXiPi; - TH1 *hMeanPosXiPr, *hSigmaPosXiPr; - TH1 *hMeanNegXiPi, *hSigmaNegXiPi; - TH1 *hMeanNegXiPr, *hSigmaNegXiPr; - TH1 *hMeanBachXiPi, *hSigmaBachXiPi; - TH1 *hMeanPosOmPi, *hSigmaPosOmPi; - TH1 *hMeanPosOmPr, *hSigmaPosOmPr; - TH1 *hMeanNegOmPi, *hSigmaNegOmPi; - TH1 *hMeanNegOmPr, *hSigmaNegOmPr; - TH1 *hMeanBachOmKa, *hSigmaBachOmKa; - - int mRunNumber; - float d_bz; - float maxSnp; // max sine phi for propagation - float maxStep; // max step size (cm) for propagation - - /// function to calculate track length of this track up to a certain segment of a detector - /// to be used internally in another funcrtion that calculates length until it finds the proper one - /// warning: this could be optimised further for speed - /// \param track the input track - /// \param x1 x of the first point of the detector segment - /// \param y1 y of the first point of the detector segment - /// \param x2 x of the first point of the detector segment - /// \param y2 y of the first point of the detector segment - /// \param magneticField the magnetic field to use when propagating - float trackLengthToSegment(o2::track::TrackPar track, float x1, float y1, float x2, float y2, float magneticField) - { - // don't make use of the track parametrization - float length = -104; - - // causality protection - std::array mom; - track.getPxPyPzGlo(mom); - // get start point - std::array startPoint; - track.getXYZGlo(startPoint); - - // better replaced with scalar momentum check later - // if (((x1 + x2) * mom[0] + (y1 + y2) * mom[1]) < 0.0f) - // return -101; - - // get circle X, Y please - o2::math_utils::CircleXYf_t trcCircle; - float sna, csa; - track.getCircleParams(magneticField, trcCircle, sna, csa); - - // Calculate necessary inner product - float segmentModulus = std::hypot(x2 - x1, y2 - y1); - float alongSegment = ((trcCircle.xC - x1) * (x2 - x1) + (trcCircle.yC - y1) * (y2 - y1)) / segmentModulus; - - // find point of closest approach between segment and circle center - float pcaX = (x2 - x1) * alongSegment / segmentModulus + x1; - float pcaY = (y2 - y1) * alongSegment / segmentModulus + y1; - - float centerDistToPC = std::hypot(pcaX - trcCircle.xC, pcaY - trcCircle.yC); - - // distance pca-to-intercept in multiples of segment modulus (for convenience) - if (centerDistToPC > trcCircle.rC) - return -103; - - float pcaToIntercept = TMath::Sqrt(TMath::Abs(trcCircle.rC * trcCircle.rC - centerDistToPC * centerDistToPC)); - - float interceptX1 = pcaX + (x2 - x1) / segmentModulus * pcaToIntercept; - float interceptY1 = pcaY + (y2 - y1) / segmentModulus * pcaToIntercept; - float interceptX2 = pcaX - (x2 - x1) / segmentModulus * pcaToIntercept; - float interceptY2 = pcaY - (y2 - y1) / segmentModulus * pcaToIntercept; - - float scalarCheck1 = ((x2 - x1) * (interceptX1 - x1) + (y2 - y1) * (interceptY1 - y1)) / segmentModulus; - float scalarCheck2 = ((x2 - x1) * (interceptX2 - x1) + (y2 - y1) * (interceptY2 - y1)) / segmentModulus; - - float cosAngle1 = -1000, sinAngle1 = -1000, modulus1 = -1000; - float cosAngle2 = -1000, sinAngle2 = -1000, modulus2 = -1000; - float length1 = -1000, length2 = -1000; - - modulus1 = std::hypot(interceptX1 - trcCircle.xC, interceptY1 - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); - cosAngle1 = (interceptX1 - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (interceptY1 - trcCircle.yC) * (startPoint[1] - trcCircle.yC); - sinAngle1 = (interceptX1 - trcCircle.xC) * (startPoint[1] - trcCircle.yC) - (interceptY1 - trcCircle.yC) * (startPoint[0] - trcCircle.xC); - cosAngle1 /= modulus1; - sinAngle1 /= modulus1; - length1 = trcCircle.rC * TMath::ACos(cosAngle1); - length1 *= sqrt(1.0f + track.getTgl() * track.getTgl()); - - modulus2 = std::hypot(interceptX2 - trcCircle.xC, interceptY2 - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); - cosAngle2 = (interceptX2 - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (interceptY2 - trcCircle.yC) * (startPoint[1] - trcCircle.yC); - sinAngle2 = (interceptX2 - trcCircle.xC) * (startPoint[1] - trcCircle.yC) - (interceptY2 - trcCircle.yC) * (startPoint[0] - trcCircle.xC); - cosAngle2 /= modulus2; - sinAngle2 /= modulus2; - length2 = trcCircle.rC * TMath::ACos(cosAngle2); - length2 *= sqrt(1.0f + track.getTgl() * track.getTgl()); - - // rotate transverse momentum vector such that it is at intercepts - float angle1 = TMath::ACos(cosAngle1); - if (sinAngle1 < 0) - angle1 *= -1.0f; - float px1 = +TMath::Cos(angle1) * mom[0] + TMath::Sin(angle1) * mom[1]; - float py1 = -TMath::Sin(angle1) * mom[0] + TMath::Cos(angle1) * mom[1]; - - float angle2 = TMath::ACos(cosAngle2); - if (sinAngle2 < 0) - angle2 *= -1.0f; - float px2 = +TMath::Cos(angle2) * mom[0] + TMath::Sin(angle2) * mom[1]; - float py2 = -TMath::Sin(angle2) * mom[0] + TMath::Cos(angle2) * mom[1]; - - float midSegX = 0.5f * (x2 + x1); - float midSegY = 0.5f * (y2 + y1); - - float scalarMomentumCheck1 = px1 * midSegX + py1 * midSegY; - float scalarMomentumCheck2 = px2 * midSegX + py2 * midSegY; - - if (scalarCheck1 > 0.0f && scalarCheck1 < segmentModulus && scalarMomentumCheck1 > 0.0f) { - length = length1; - // X = interceptX1; Y = interceptY1; - } - if (scalarCheck2 > 0.0f && scalarCheck2 < segmentModulus && scalarMomentumCheck2 > 0.0f) { - length = length2; - // X = interceptX2; Y = interceptY2; - } - return length; - } - - /// function to calculate track length of this track up to a certain segmented detector - /// \param track the input track - /// \param magneticField the magnetic field to use when propagating - float findInterceptLength(o2::track::TrackPar track, float magneticField) - { - float length = 1e+6; - for (int iSeg = 0; iSeg < 18; iSeg++) { - // Detector segmentation loop - float segmentAngle = 20.0f / 180.0f * TMath::Pi(); - float theta = static_cast(iSeg) * 20.0f / 180.0f * TMath::Pi(); - float halfWidth = tofPosition * TMath::Tan(0.5f * segmentAngle); - float x1 = TMath::Cos(theta) * (-halfWidth) + TMath::Sin(theta) * tofPosition; - float y1 = -TMath::Sin(theta) * (-halfWidth) + TMath::Cos(theta) * tofPosition; - float x2 = TMath::Cos(theta) * (+halfWidth) + TMath::Sin(theta) * tofPosition; - float y2 = -TMath::Sin(theta) * (+halfWidth) + TMath::Cos(theta) * tofPosition; - float thisLength = trackLengthToSegment(track, x1, y1, x2, y2, magneticField); - if (thisLength < length && thisLength > 0) - length = thisLength; - } - if (length > 1e+5) - length = -100; // force negative to avoid misunderstandings - return length; - } - - void init(InitContext&) - { - 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); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - nSigmaCalibLoaded = false; - nSigmaCalibObjects = nullptr; - - // measured vs expected total time QA - if (doQA) { - // standard deltaTime values - histos.add("hArcDebug", "hArcDebug", kTH2F, {axisPt, {500, -5.0f, 10.0f}}); - histos.add("h2dposDeltaTimeAsXiPi", "h2dposDeltaTimeAsXiPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dposDeltaTimeAsXiPr", "h2dposDeltaTimeAsXiPr", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dnegDeltaTimeAsXiPi", "h2dnegDeltaTimeAsXiPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dnegDeltaTimeAsXiPr", "h2dnegDeltaTimeAsXiPr", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dbachDeltaTimeAsXiPi", "h2dbachDeltaTimeAsXiPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - - histos.add("h2dposDeltaTimeAsOmPi", "h2dposDeltaTimeAsOmPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dposDeltaTimeAsOmPr", "h2dposDeltaTimeAsOmPr", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dnegDeltaTimeAsOmPi", "h2dnegDeltaTimeAsOmPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dnegDeltaTimeAsOmPr", "h2dnegDeltaTimeAsOmPr", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dbachDeltaTimeAsOmKa", "h2dbachDeltaTimeAsOmKa", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - } - - if (doQANSigma) { - // standard NSigma values - histos.add("h2dNSigmaXiLaPi", "h2dNSigmaXiLaPi", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaXiLaPr", "h2dNSigmaXiLaPr", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaXiPi", "h2dNSigmaXiPi", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaOmLaPi", "h2dNSigmaOmLaPi", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaOmLaPr", "h2dNSigmaOmLaPr", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaOmKa", "h2dNSigmaOmKa", {HistType::kTH2F, {axisPt, axisNSigma}}); - } - } - - template - void initCCDB(TInformationClass const& infoObject) - { - if (mRunNumber == infoObject.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 = infoObject.runNumber(); - return; - } - - auto run3grp_timestamp = infoObject.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"; - } - - // if TOF Nsigma desired - if (doNSigmas) { - nSigmaCalibObjects = ccdb->getForTimeStamp(nSigmaPath, infoObject.timestamp()); - if (nSigmaCalibObjects) { - LOGF(info, "loaded TList with this many objects: %i", nSigmaCalibObjects->GetEntries()); - - hMeanPosXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosXiPi")); - hMeanPosXiPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosXiPr")); - hMeanNegXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegXiPi")); - hMeanNegXiPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegXiPr")); - hMeanBachXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanBachXiPi")); - hMeanPosOmPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosOmPi")); - hMeanPosOmPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosOmPr")); - hMeanNegOmPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegOmPi")); - hMeanNegOmPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegOmPr")); - hMeanBachOmKa = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanBachOmKa")); - - hSigmaPosXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosXiPi")); - hSigmaPosXiPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosXiPr")); - hSigmaNegXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegXiPi")); - hSigmaNegXiPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegXiPr")); - hSigmaBachXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaBachXiPi")); - hSigmaPosOmPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosOmPi")); - hSigmaPosOmPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosOmPr")); - hSigmaNegOmPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegOmPi")); - hSigmaNegOmPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegOmPr")); - hSigmaBachOmKa = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaBachOmKa")); - - if (!hMeanPosXiPi || !hMeanPosXiPr || !hMeanNegXiPi || !hMeanNegXiPr || !hMeanBachXiPi) - LOG(info) << "Problems finding xi mean histograms!"; - if (!hMeanPosOmPi || !hMeanPosOmPr || !hMeanNegOmPi || !hMeanNegOmPr || !hMeanBachOmKa) - LOG(info) << "Problems finding omega sigma histograms!"; - if (!hSigmaPosXiPi || !hSigmaPosXiPr || !hSigmaNegXiPi || !hSigmaNegXiPr || !hSigmaBachXiPi) - LOG(info) << "Problems finding xi sigma histograms!"; - if (!hSigmaPosOmPi || !hSigmaPosOmPr || !hSigmaNegOmPi || !hSigmaNegOmPr || !hSigmaBachOmKa) - LOG(info) << "Problems finding omega sigma histograms!"; - } - } - mRunNumber = infoObject.runNumber(); - } - - float velocity(float lMomentum, float lMass) - { - // Momentum p and mass m -> returns speed in centimeters per picosecond - // Useful for TOF calculations - float lA = (lMomentum / lMass) * (lMomentum / lMass); - return 0.0299792458 * TMath::Sqrt(lA / (1 + lA)); - } - - template - void processCascadeCandidate(TCollision const& collision, TCascade const& cascade, TTrack const& pTra, TTrack const& nTra, TTrack const& bTra) - { - // initialize from positions and momenta as needed - o2::track::TrackPar posTrack = o2::track::TrackPar({cascade.xlambda(), cascade.ylambda(), cascade.zlambda()}, {cascade.pxpos(), cascade.pypos(), cascade.pzpos()}, +1); - o2::track::TrackPar negTrack = o2::track::TrackPar({cascade.xlambda(), cascade.ylambda(), cascade.zlambda()}, {cascade.pxneg(), cascade.pyneg(), cascade.pzneg()}, -1); - o2::track::TrackPar bachTrack = o2::track::TrackPar({cascade.x(), cascade.y(), cascade.z()}, {cascade.pxbach(), cascade.pybach(), cascade.pzbach()}, cascade.sign()); - o2::track::TrackPar cascTrack = o2::track::TrackPar({cascade.x(), cascade.y(), cascade.z()}, {cascade.px(), cascade.py(), cascade.pz()}, cascade.sign()); - - // start calculation: calculate velocities - float velocityPositivePr = velocity(posTrack.getP(), o2::constants::physics::MassProton); - float velocityPositivePi = velocity(posTrack.getP(), o2::constants::physics::MassPionCharged); - float velocityNegativePr = velocity(negTrack.getP(), o2::constants::physics::MassProton); - float velocityNegativePi = velocity(negTrack.getP(), o2::constants::physics::MassPionCharged); - float velocityBachelorPi = velocity(bachTrack.getP(), o2::constants::physics::MassPionCharged); - float velocityBachelorKa = velocity(bachTrack.getP(), o2::constants::physics::MassKaonCharged); - float velocityXi = velocity(cascTrack.getP(), o2::constants::physics::MassXiMinus); - float velocityOm = velocity(cascTrack.getP(), o2::constants::physics::MassOmegaMinus); - float velocityLa = velocity(std::hypot(cascade.pxlambda(), cascade.pylambda(), cascade.pzlambda()), o2::constants::physics::MassLambda); - - // calculate daughter length to TOF intercept - float lengthPositive = findInterceptLength(posTrack, d_bz); // FIXME: tofPosition ok? adjust? - float lengthNegative = findInterceptLength(negTrack, d_bz); // FIXME: tofPosition ok? adjust? - float lengthBachelor = findInterceptLength(bachTrack, d_bz); // FIXME: tofPosition ok? adjust? - - // calculate mother lengths - float lengthV0 = std::hypot(cascade.xlambda() - cascade.x(), cascade.ylambda() - cascade.y(), cascade.zlambda() - cascade.z()); - float lengthCascade = -1e+6; - const o2::math_utils::Point3D collVtx{collision.posX(), collision.posY(), collision.posZ()}; - bool successPropag = o2::base::Propagator::Instance()->propagateToDCA(collVtx, cascTrack, d_bz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrNONE); - float d = -1.0f, d3d = 0.0f; - float linearToPV = std::hypot(cascade.x() - collision.posX(), cascade.y() - collision.posY(), cascade.z() - collision.posZ()); - if (successPropag) { - std::array cascCloseToPVPosition; - cascTrack.getXYZGlo(cascCloseToPVPosition); - o2::math_utils::CircleXYf_t trcCircleCascade; - float sna, csa; - cascTrack.getCircleParams(d_bz, trcCircleCascade, sna, csa); - - // calculate 2D distance between two points - d = std::hypot(cascade.x() - cascCloseToPVPosition[0], cascade.y() - cascCloseToPVPosition[1]); - d3d = std::hypot(cascade.x() - cascCloseToPVPosition[0], cascade.y() - cascCloseToPVPosition[1], cascade.z() - cascCloseToPVPosition[2]); // cross-check variable - float sinThetaOverTwo = d / (2.0f * trcCircleCascade.rC); - lengthCascade = 2.0f * trcCircleCascade.rC * TMath::ASin(sinThetaOverTwo); - lengthCascade *= sqrt(1.0f + cascTrack.getTgl() * cascTrack.getTgl()); - } - - if (!successPropag) { - lengthCascade = linearToPV; // if propagation failed, use linear estimate (optional: actually do not define?) - } - - // lambda, xi and omega flight time is always defined - float lambdaFlight = lengthV0 / velocityLa; - float xiFlight = lengthCascade / velocityXi; - float omFlight = lengthCascade / velocityOm; - float posFlightPi = lengthPositive / velocityPositivePi; - float posFlightPr = lengthPositive / velocityPositivePr; - float negFlightPi = lengthNegative / velocityNegativePi; - float negFlightPr = lengthNegative / velocityNegativePr; - float bachFlightPi = lengthBachelor / velocityBachelorPi; - float bachFlightKa = lengthBachelor / velocityBachelorKa; - - // initialize delta-times (actual PID variables) - float posDeltaTimeAsXiPi = -1e+6, posDeltaTimeAsXiPr = -1e+6; - float negDeltaTimeAsXiPi = -1e+6, negDeltaTimeAsXiPr = -1e+6; - float bachDeltaTimeAsXiPi = -1e+6; - float posDeltaTimeAsOmPi = -1e+6, posDeltaTimeAsOmPr = -1e+6; - float negDeltaTimeAsOmPi = -1e+6, negDeltaTimeAsOmPr = -1e+6; - float bachDeltaTimeAsOmKa = -1e+6; - - if (pTra.hasTOF()) { - posDeltaTimeAsXiPi = (pTra.tofSignal() - pTra.tofEvTime()) - (xiFlight + lambdaFlight + posFlightPi); - posDeltaTimeAsXiPr = (pTra.tofSignal() - pTra.tofEvTime()) - (xiFlight + lambdaFlight + posFlightPr); - posDeltaTimeAsOmPi = (pTra.tofSignal() - pTra.tofEvTime()) - (omFlight + lambdaFlight + posFlightPi); - posDeltaTimeAsOmPr = (pTra.tofSignal() - pTra.tofEvTime()) - (omFlight + lambdaFlight + posFlightPr); - } - if (nTra.hasTOF()) { - negDeltaTimeAsXiPi = (nTra.tofSignal() - nTra.tofEvTime()) - (xiFlight + lambdaFlight + negFlightPi); - negDeltaTimeAsXiPr = (nTra.tofSignal() - nTra.tofEvTime()) - (xiFlight + lambdaFlight + negFlightPr); - negDeltaTimeAsOmPi = (nTra.tofSignal() - nTra.tofEvTime()) - (omFlight + lambdaFlight + negFlightPi); - negDeltaTimeAsOmPr = (nTra.tofSignal() - nTra.tofEvTime()) - (omFlight + lambdaFlight + negFlightPr); - } - if (bTra.hasTOF()) { - bachDeltaTimeAsXiPi = (bTra.tofSignal() - bTra.tofEvTime()) - (xiFlight + bachFlightPi); - bachDeltaTimeAsOmKa = (bTra.tofSignal() - bTra.tofEvTime()) - (omFlight + bachFlightKa); - } - - casctofpids( - posDeltaTimeAsXiPi, posDeltaTimeAsXiPr, negDeltaTimeAsXiPi, negDeltaTimeAsXiPr, bachDeltaTimeAsXiPi, - posDeltaTimeAsOmPi, posDeltaTimeAsOmPr, negDeltaTimeAsOmPi, negDeltaTimeAsOmPr, bachDeltaTimeAsOmKa); - - float nSigmaXiLaPr = -1e+6; - float nSigmaXiLaPi = -1e+6; - float nSigmaXiPi = -1e+6; - float nSigmaOmLaPr = -1e+6; - float nSigmaOmLaPi = -1e+6; - float nSigmaOmKa = -1e+6; - - // go for Nsigma values if requested - if (doNSigmas) { - // Xi hypothesis ________________________ - if (cascade.sign() < 0) { // XiMinus - if (posDeltaTimeAsXiPr > -1e+5) // proton from Lambda from XiMinus has signal - nSigmaXiLaPr = (posDeltaTimeAsXiPr - hMeanPosXiPr->Interpolate(cascade.pt())) / hSigmaPosXiPr->Interpolate(cascade.pt()); - if (negDeltaTimeAsXiPi > -1e+5) // pion from Lambda from XiMinus has signal - nSigmaXiLaPi = (negDeltaTimeAsXiPi - hMeanNegXiPi->Interpolate(cascade.pt())) / hSigmaNegXiPi->Interpolate(cascade.pt()); - if (bachDeltaTimeAsXiPi > -1e+5) // pion from XiMinus has signal - nSigmaXiPi = (bachDeltaTimeAsXiPi - hMeanBachXiPi->Interpolate(cascade.pt())) / hSigmaBachXiPi->Interpolate(cascade.pt()); - if (posDeltaTimeAsOmPr > -1e+5) // proton from Lambda from OmegaMinus has signal - nSigmaOmLaPr = (posDeltaTimeAsOmPr - hMeanPosOmPr->Interpolate(cascade.pt())) / hSigmaPosOmPr->Interpolate(cascade.pt()); - if (negDeltaTimeAsOmPi > -1e+5) // pion from Lambda from OmegaMinus has signal - nSigmaOmLaPi = (negDeltaTimeAsOmPi - hMeanNegOmPi->Interpolate(cascade.pt())) / hSigmaNegOmPi->Interpolate(cascade.pt()); - if (bachDeltaTimeAsOmKa > -1e+5) // kaon from OmegaMinus has signal - nSigmaOmKa = (bachDeltaTimeAsOmKa - hMeanBachOmKa->Interpolate(cascade.pt())) / hSigmaBachOmKa->Interpolate(cascade.pt()); - } else { - if (posDeltaTimeAsXiPi > -1e+5) // proton from Lambda from XiMinus has signal - nSigmaXiLaPi = (posDeltaTimeAsXiPi - hMeanPosXiPi->Interpolate(cascade.pt())) / hSigmaPosXiPi->Interpolate(cascade.pt()); - if (negDeltaTimeAsXiPr > -1e+5) // pion from Lambda from XiMinus has signal - nSigmaXiLaPr = (negDeltaTimeAsXiPr - hMeanNegXiPr->Interpolate(cascade.pt())) / hSigmaNegXiPr->Interpolate(cascade.pt()); - if (bachDeltaTimeAsXiPi > -1e+5) // pion from XiMinus has signal - nSigmaXiPi = (bachDeltaTimeAsXiPi - hMeanBachXiPi->Interpolate(cascade.pt())) / hSigmaBachXiPi->Interpolate(cascade.pt()); - if (posDeltaTimeAsOmPi > -1e+5) // proton from Lambda from OmegaMinus has signal - nSigmaOmLaPi = (posDeltaTimeAsOmPi - hMeanPosOmPi->Interpolate(cascade.pt())) / hSigmaPosOmPi->Interpolate(cascade.pt()); - if (negDeltaTimeAsOmPr > -1e+5) // pion from Lambda from OmegaMinus has signal - nSigmaOmLaPr = (negDeltaTimeAsOmPr - hMeanNegOmPr->Interpolate(cascade.pt())) / hSigmaNegOmPr->Interpolate(cascade.pt()); - if (bachDeltaTimeAsOmKa > -1e+5) // kaon from OmegaMinus has signal - nSigmaOmKa = (bachDeltaTimeAsOmKa - hMeanBachOmKa->Interpolate(cascade.pt())) / hSigmaBachOmKa->Interpolate(cascade.pt()); - } - casctofnsigmas(nSigmaXiLaPi, nSigmaXiLaPr, nSigmaXiPi, nSigmaOmLaPi, nSigmaOmLaPr, nSigmaOmKa); - } - - if (doQA) { - // fill QA histograms for cross-checking - histos.fill(HIST("hArcDebug"), cascade.pt(), lengthCascade - d3d); // for debugging purposes - - if (cascade.dcaV0daughters() < qaV0DCADau && cascade.dcacascdaughters() < qaCascDCADau && cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) > qaV0CosPA && cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > qaCascCosPA) { - if (cascade.sign() < 0) { - if (std::abs(cascade.mXi() - 1.32171) < qaMassWindow && fabs(pTra.tpcNSigmaPr()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPi()) < qaTPCNSigma && fabs(bTra.tpcNSigmaPi()) < qaTPCNSigma) { - histos.fill(HIST("h2dposDeltaTimeAsXiPr"), cascade.pt(), cascade.eta(), posDeltaTimeAsXiPr); - histos.fill(HIST("h2dnegDeltaTimeAsXiPi"), cascade.pt(), cascade.eta(), negDeltaTimeAsXiPi); - histos.fill(HIST("h2dbachDeltaTimeAsXiPi"), cascade.pt(), cascade.eta(), bachDeltaTimeAsXiPi); - if (doQANSigma) { - histos.fill(HIST("h2dNSigmaXiLaPi"), cascade.pt(), nSigmaXiLaPi); - histos.fill(HIST("h2dNSigmaXiLaPr"), cascade.pt(), nSigmaXiLaPr); - histos.fill(HIST("h2dNSigmaXiPi"), cascade.pt(), nSigmaXiPi); - } - } - if (std::abs(cascade.mOmega() - 1.67245) < qaMassWindow && fabs(pTra.tpcNSigmaPr()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPi()) < qaTPCNSigma && fabs(bTra.tpcNSigmaKa()) < qaTPCNSigma) { - histos.fill(HIST("h2dposDeltaTimeAsOmPr"), cascade.pt(), cascade.eta(), posDeltaTimeAsOmPr); - histos.fill(HIST("h2dnegDeltaTimeAsOmPi"), cascade.pt(), cascade.eta(), negDeltaTimeAsOmPi); - histos.fill(HIST("h2dbachDeltaTimeAsOmKa"), cascade.pt(), cascade.eta(), bachDeltaTimeAsOmKa); - if (doQANSigma) { - histos.fill(HIST("h2dNSigmaOmLaPi"), cascade.pt(), nSigmaOmLaPi); - histos.fill(HIST("h2dNSigmaOmLaPr"), cascade.pt(), nSigmaOmLaPr); - histos.fill(HIST("h2dNSigmaOmKa"), cascade.pt(), nSigmaOmKa); - } - } - } else { - if (std::abs(cascade.mXi() - 1.32171) < qaMassWindow && fabs(pTra.tpcNSigmaPi()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPr()) < qaTPCNSigma && fabs(bTra.tpcNSigmaPi()) < qaTPCNSigma) { - histos.fill(HIST("h2dposDeltaTimeAsXiPi"), cascade.pt(), cascade.eta(), posDeltaTimeAsXiPi); - histos.fill(HIST("h2dnegDeltaTimeAsXiPr"), cascade.pt(), cascade.eta(), negDeltaTimeAsXiPr); - histos.fill(HIST("h2dbachDeltaTimeAsXiPi"), cascade.pt(), cascade.eta(), bachDeltaTimeAsXiPi); - if (doQANSigma) { - histos.fill(HIST("h2dNSigmaXiLaPi"), cascade.pt(), nSigmaXiLaPi); - histos.fill(HIST("h2dNSigmaXiLaPr"), cascade.pt(), nSigmaXiLaPr); - histos.fill(HIST("h2dNSigmaXiPi"), cascade.pt(), nSigmaXiPi); - } - } - if (std::abs(cascade.mOmega() - 1.67245) < qaMassWindow && fabs(pTra.tpcNSigmaPi()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPr()) < qaTPCNSigma && fabs(bTra.tpcNSigmaKa()) < qaTPCNSigma) { - histos.fill(HIST("h2dposDeltaTimeAsOmPi"), cascade.pt(), cascade.eta(), posDeltaTimeAsOmPi); - histos.fill(HIST("h2dnegDeltaTimeAsOmPr"), cascade.pt(), cascade.eta(), negDeltaTimeAsOmPr); - histos.fill(HIST("h2dbachDeltaTimeAsOmKa"), cascade.pt(), cascade.eta(), bachDeltaTimeAsOmKa); - if (doQANSigma) { - histos.fill(HIST("h2dNSigmaOmLaPi"), cascade.pt(), nSigmaOmLaPi); - histos.fill(HIST("h2dNSigmaOmLaPr"), cascade.pt(), nSigmaOmLaPr); - histos.fill(HIST("h2dNSigmaOmKa"), cascade.pt(), nSigmaOmKa); - } - } - } - } - } - } - - 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); - for (const auto& collision : collisions) { - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = collision.globalIndex(); - auto CascTable_thisCollision = Cascades.sliceBy(perCollisionOriginal, collIdx); - // cascade table sliced - for (auto const& cascade : CascTable_thisCollision) { - // de-reference interlinks by hand for derived data - auto pTra = cascade.posTrack_as(); - auto nTra = cascade.negTrack_as(); - auto bTra = cascade.bachelor_as(); - - processCascadeCandidate(collision, cascade, pTra, nTra, bTra); - } - } - } - - void processDerivedData(soa::Join const& collisions, CascDerivedDatas const& Cascades, 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 CascTable_thisCollision = Cascades.sliceBy(perCollisionDerived, collIdx); - // cascade table sliced - for (auto const& cascade : CascTable_thisCollision) { - // de-reference interlinks by hand for derived data - auto pTra = cascade.posTrackExtra_as(); - auto nTra = cascade.negTrackExtra_as(); - auto bTra = cascade.bachTrackExtra_as(); - - processCascadeCandidate(collision, cascade, pTra, nTra, bTra); - } - } - } - - PROCESS_SWITCH(cascadepid, processStandardData, "Process standard data", true); - PROCESS_SWITCH(cascadepid, processDerivedData, "Process derived data", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/Strangeness/cascadespawner.cxx b/PWGLF/TableProducer/Strangeness/cascadespawner.cxx index 4e2d0c68a44..ab3f4cb7c3d 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 0f8659fac38..e32ebd8a9db 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,38 +8,46 @@ // In applying this license CERN does 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 "PWGLF/DataModel/cascqaanalysis.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "PWGLF/DataModel/cascqaanalysis.h" -#include "TRandom2.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "PWGLF/Utils/inelGt.h" -#include "PWGLF/DataModel/mcCentrality.h" +#include "Framework/runDataProcessing.h" + +#include "TRandom2.h" +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; // using DauTracks = soa::Join; using TrkPidInfo = soa::Join; using DauTracks = soa::Join; using LabeledCascades = soa::Join; -struct cascqaanalysis { +struct Cascqaanalysis { // Tables to produce Produces mycascades; @@ -47,6 +55,25 @@ struct cascqaanalysis { HistogramRegistry registry{"registry"}; + // Axes + ConfigurableAxis ptAxis{"ptAxis", {200, 0.0f, 10.0f}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis rapidityAxis{"rapidityAxis", {200, -2.0f, 2.0f}, "y"}; + 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{"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 (%)"}; + ConfigurableAxis eventTypeAxis{"eventTypeAxis", {3, -0.5f, 2.5f}, "Event Type"}; + + ConfigurableAxis nAssocCollAxis{"nAssocCollAxis", {5, -0.5f, 4.5f}, "N_{assoc.}"}; + ConfigurableAxis nChargedFT0MGenAxis{"nChargedFT0MGenAxis", {300, 0, 300}, "N_{FT0M, gen.}"}; + ConfigurableAxis nChargedFV0AGenAxis{"nChargedFV0AGenAxis", {300, 0, 300}, "N_{FV0A, gen.}"}; + ConfigurableAxis multNTracksAxis{"multNTracksAxis", {500, 0, 500}, "N_{tracks}"}; + ConfigurableAxis signalFT0MAxis{"signalFT0MAxis", {10000, 0, 40000}, "FT0M amplitude"}; + ConfigurableAxis signalFV0AAxis{"signalFV0AAxis", {10000, 0, 40000}, "FV0A amplitude"}; + ConfigurableAxis nCandidates{"nCandidates", {30, -0.5, 29.5}, "N_{cand.}"}; + // Event selection criteria Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; Configurable isVertexITSTPC{"isVertexITSTPC", 0, "Select collisions with at least one ITS-TPC track"}; @@ -57,6 +84,15 @@ struct cascqaanalysis { 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"}; + + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerFV0Check{"cfgEvtRCTFlagCheckerFV0Check", false, "Evt sel: RCT flag checker FV0 check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + + RCTFlagsChecker rctChecker; // Cascade selection criteria Configurable scalefactor{"scalefactor", 1.0, "Scaling factor"}; @@ -96,74 +132,62 @@ struct cascqaanalysis { 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", - {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", - {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"}; - AxisSpec nAssocCollAxis = {5, -0.5f, 4.5f, "N_{assoc.}"}; - AxisSpec nChargedFT0MGenAxis = {500, 0, 500, "N_{FT0M, gen.}"}; - AxisSpec nChargedFV0AGenAxis = {500, 0, 500, "N_{FV0A, gen.}"}; - 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[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[12] = {"All", "kIsTriggerTVX", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kIsVertexITSTPC", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "isVertexTOFmatched", "z vrtx", "INEL", "INEL>0", "INEL>1"}; + TString hNEventsLabels[14] = {"All", "kIsTriggerTVX", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kIsVertexITSTPC", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "isVertexTOFmatched", "kNoCollInTimeRangeNarrow", "z vrtx", "RCTFlagsChecker", "INEL", "INEL>0", "INEL>1"}; - registry.add("hNEvents", "hNEvents", {HistType::kTH1F, {{12, 0.f, 12.f}}}); + registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{14, 0.f, 14.f}}}); - for (Int_t n = 1; n <= registry.get(HIST("hNEvents"))->GetNbinsX(); n++) { + 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("hZCollision", "hZCollision", {HistType::kTH1D, {{200, -20.f, 20.f}}}); - registry.add("hCandidateCounter", "hCandidateCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}); - for (Int_t n = 1; n <= registry.get(HIST("hCandidateCounter"))->GetNbinsX(); n++) { + registry.add("hCandidateCounter", "hCandidateCounter", {HistType::kTH1D, {{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++) { + registry.add("hNEventsMC", "hNEventsMC", {HistType::kTH1D, {{6, 0.0f, 6.0f}}}); + 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}}}); - registry.add("hNchFT0MNAssocMCCollisions", "hNchFT0MNAssocMCCollisions", {HistType::kTH3F, {nChargedFT0MGenAxis, nAssocCollAxis, eventTypeAxis}}); - registry.add("hNchFT0MNAssocMCCollisionsSameType", "hNchFT0MNAssocMCCollisionsSameType", {HistType::kTH3F, {nChargedFT0MGenAxis, nAssocCollAxis, eventTypeAxis}}); + registry.add("hZCollisionGen", "hZCollisionGen", {HistType::kTH1D, {{200, -20.f, 20.f}}}); + registry.add("hNchFT0MNAssocMCCollisions", "hNchFT0MNAssocMCCollisions", {HistType::kTH3D, {nChargedFT0MGenAxis, nAssocCollAxis, eventTypeAxis}}); + registry.add("hNchFT0MNAssocMCCollisionsSameType", "hNchFT0MNAssocMCCollisionsSameType", {HistType::kTH3D, {nChargedFT0MGenAxis, nAssocCollAxis, eventTypeAxis}}); 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}}); - registry.add("hCentFT0M_genMC", "hCentFT0M_genMC", {HistType::kTH2F, {centFT0MAxis, eventTypeAxis}}); + registry.add("hNchFT0MGenEvType", "hNchFT0MGenEvType", {HistType::kTH2D, {nChargedFT0MGenAxis, eventTypeAxis}}); + registry.add("hNchFV0AGenEvType", "hNchFV0AGenEvType", {HistType::kTH2D, {nChargedFV0AGenAxis, eventTypeAxis}}); + registry.add("hCentFT0M_genMC", "hCentFT0M_genMC", {HistType::kTH2D, {centFT0MAxis, eventTypeAxis}}); } - registry.add("hCentFT0M_rec", "hCentFT0M_rec", {HistType::kTH2F, {centFT0MAxis, eventTypeAxis}}); + registry.add("hCentFT0M_rec", "hCentFT0M_rec", {HistType::kTH2D, {centFT0MAxis, eventTypeAxis}}); if (candidateQA) { - registry.add("hNcandidates", "hNcandidates", {HistType::kTH3F, {nCandidates, centFT0MAxis, {2, -0.5f, 1.5f}}}); + registry.add("hNcandidates", "hNcandidates", {HistType::kTH3D, {nCandidates, centFT0MAxis, {2, -0.5f, 1.5f}}}); } if (multQA) { if (isMC) { // Rec. lvl - registry.add("hNchFT0Mglobal", "hNchFT0Mglobal", {HistType::kTH3F, {nChargedFT0MGenAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hNchFT0Mglobal", "hNchFT0Mglobal", {HistType::kTH3D, {nChargedFT0MGenAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hNchFT0MPVContr", "hNchFT0MPVContr", {HistType::kTH3D, {nChargedFT0MGenAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hNchFV0APVContr", "hNchFV0APVContr", {HistType::kTH3D, {nChargedFV0AGenAxis, multNTracksAxis, 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}}); + registry.add("hFT0MpvContr", "hFT0MpvContr", {HistType::kTH3D, {centFT0MAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFV0ApvContr", "hFV0ApvContr", {HistType::kTH3D, {centFV0AAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFT0Mglobal", "hFT0Mglobal", {HistType::kTH3D, {centFT0MAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFV0AFT0M", "hFV0AFT0M", {HistType::kTH3D, {centFV0AAxis, centFT0MAxis, eventTypeAxis}}); + registry.add("hFT0MFV0Asignal", "hFT0MFV0Asignal", {HistType::kTH2D, {signalFT0MAxis, signalFV0AAxis}}); + registry.add("hFT0MsignalPVContr", "hFT0MsignalPVContr", {HistType::kTH3D, {signalFT0MAxis, multNTracksAxis, eventTypeAxis}}); + } + + rctChecker.init(cfgEvtRCTFlagCheckerLabel, cfgEvtRCTFlagCheckerZDCCheck, cfgEvtRCTFlagCheckerLimitAcceptAsBad); + if (cfgEvtRCTFlagCheckerFV0Check) { + rctChecker.set(o2::aod::rctsel::kFV0Bad); } } @@ -174,11 +198,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(); @@ -190,9 +214,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; @@ -200,11 +224,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; } @@ -224,11 +248,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; } @@ -248,24 +272,24 @@ struct cascqaanalysis { } template - int GetEventTypeFlag(TCollision const& collision) + int getEventTypeFlag(TCollision const& collision) { // 0 - INEL, 1 - INEL>0, 2 - INEL>1 int evFlag = 0; - registry.fill(HIST("hNEvents"), 9.5); // INEL + registry.fill(HIST("hNEvents"), 11.5); // INEL if (collision.isInelGt0()) { evFlag += 1; - registry.fill(HIST("hNEvents"), 10.5); // INEL>0 + registry.fill(HIST("hNEvents"), 12.5); // INEL>0 } if (collision.isInelGt1()) { evFlag += 1; - registry.fill(HIST("hNEvents"), 11.5); // INEL>1 + registry.fill(HIST("hNEvents"), 13.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); @@ -326,16 +350,31 @@ struct cascqaanalysis { 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); + } // Z vertex selection - if (TMath::Abs(collision.posZ()) > cutzvertex) { + if (std::fabs(collision.posZ()) > cutzvertex) { return false; } if (isFillEventSelectionQA) { - registry.fill(HIST("hNEvents"), 8.5); + registry.fill(HIST("hNEvents"), 9.5); registry.fill(HIST("hZCollision"), collision.posZ()); } + // RCTFlagChecker selection + if (requireRCTFlagChecker && !rctChecker(collision)) { + return false; + } + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 10.5); + } + return true; } @@ -346,11 +385,11 @@ struct cascqaanalysis { aod::V0Datas const&, DauTracks const&) { - if (!AcceptEvent(collision, 1)) { + if (!acceptEvent(collision, 1)) { return; } - int evType = GetEventTypeFlag(collision); + int evType = getEventTypeFlag(collision); auto tracksGroupedPVcontr = pvContribTracksIUEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); int nTracksPVcontr = tracksGroupedPVcontr.size(); @@ -376,7 +415,7 @@ struct cascqaanalysis { for (const auto& casc : Cascades) { // loop over Cascades registry.fill(HIST("hCandidateCounter"), 0.5); // all candidates nCandAll++; - if (AcceptCascCandidate(casc, collision.posX(), collision.posY(), collision.posZ())) { + if (acceptCascCandidate(casc, collision.posX(), collision.posY(), collision.posZ())) { registry.fill(HIST("hCandidateCounter"), 1.5); // passed topo cuts nCandSel++; // Fill table @@ -411,8 +450,8 @@ 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(), @@ -427,7 +466,7 @@ 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); } } } @@ -449,7 +488,7 @@ struct cascqaanalysis { soa::Join const&, // aod::McCentFV0As to be added aod::McParticles const& mcParticles) { - if (!AcceptEvent(collision, 1)) { + if (!acceptEvent(collision, 1)) { return; } @@ -468,19 +507,19 @@ struct cascqaanalysis { // N charged in FT0M region in corresponding gen. MC collision auto mcPartSlice = mcParticles.sliceBy(perMcCollision, collision.mcCollision_as>().globalIndex()); // mcCollision.centFV0A() to be added - uint16_t nchFT0 = GetGenNchInFT0Mregion(mcPartSlice); - uint16_t nchFV0 = GetGenNchInFV0Aregion(mcPartSlice); + uint16_t nchFT0 = getGenNchInFT0Mregion(mcPartSlice); + uint16_t nchFV0 = getGenNchInFV0Aregion(mcPartSlice); int evType = 0; - registry.fill(HIST("hNEvents"), 9.5); // INEL + registry.fill(HIST("hNEvents"), 11.5); // INEL // Rec. collision associated with INEL>0 gen. one if (pwglf::isINELgtNmc(mcPartSlice, 0, pdgDB)) { - registry.fill(HIST("hNEvents"), 10.5); // INEL + registry.fill(HIST("hNEvents"), 12.5); // INEL evType++; } // Rec. collision associated with INEL>1 gen. one if (pwglf::isINELgtNmc(mcPartSlice, 1, pdgDB)) { - registry.fill(HIST("hNEvents"), 11.5); // INEL + registry.fill(HIST("hNEvents"), 13.5); // INEL evType++; } @@ -505,19 +544,23 @@ struct cascqaanalysis { for (const auto& casc : Cascades) { // loop over Cascades registry.fill(HIST("hCandidateCounter"), 0.5); // all candidates nCandAll++; - if (AcceptCascCandidate(casc, collision.posX(), collision.posY(), collision.posZ())) { + 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"), 2.5); // has associated MC particle auto cascmc = casc.mcParticle(); - if (TMath::Abs(cascmc.pdgCode()) == 3312 || TMath::Abs(cascmc.pdgCode()) == 3334) { + 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) { @@ -553,8 +596,8 @@ 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(), mcCollision.centFT0M(), 0, // mcCollision.centFV0A() to be added @@ -569,7 +612,7 @@ 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); } } } @@ -589,7 +632,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()); @@ -615,18 +658,18 @@ struct cascqaanalysis { registry.fill(HIST("hCentFT0M_genMC"), mcCollision.centFT0M(), evType); - uint16_t nchFT0 = GetGenNchInFT0Mregion(mcParticles); - uint16_t nchFV0 = GetGenNchInFV0Aregion(mcParticles); + 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(); // mcCollision.centFV0A() to be added @@ -639,30 +682,30 @@ struct cascqaanalysis { collWithType.typeFlag |= o2::aod::myMCcascades::EvFlags::EvINELgt1; } - SelectedEvents[nevts++] = collWithType; + 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: { @@ -696,9 +739,9 @@ 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; @@ -713,12 +756,12 @@ struct cascqaanalysis { } } - 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"}; @@ -727,7 +770,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}}}); @@ -758,8 +801,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}}}); @@ -768,7 +811,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()); @@ -802,8 +845,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 } @@ -815,6 +858,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..a12bd5c4c36 --- /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 "PWGLF/DataModel/LFDoubleCascTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "TDatabasePDG.h" + +#include +#include +#include + +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 a21d97e3329..b9a789e47b0 100644 --- a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx +++ b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx @@ -12,199 +12,511 @@ /// \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) /// \author Zhongbao Yin (Zhong-Bao.Yin@cern.ch) -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/LFHStrangeCorrelationTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" -#include "Framework/ASoAHelpers.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + #include "TF1.h" +#include + +#include using namespace o2; +using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; -#define bitset(var, nbit) ((var) |= (1 << (nbit))) -#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 { + const float ctauxiPDG = 4.91; // from PDG + const float ctauomegaPDG = 2.461; // from PDG + + Service ccdb; -struct hstrangecorrelationfilter { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // master analysis switches + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + Configurable useParameterization{"useParameterization", true, "ture for parameterization method, false for hist method"}; // Operational Configurable fillTableOnlyWithCompatible{"fillTableOnlyWithCompatible", true, "pre-apply dE/dx, broad mass window in table filling"}; 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"}; + Configurable zorroMask{"zorroMask", "", "zorro trigger class to select on (empty: none)"}; + Configurable nSigmaNearXiMassCenter{"nSigmaNearXiMassCenter", 0, "for Oemga analysis only, to check if candidate mass is around Xi"}; + + // used for event selections in Pb-Pb + Configurable cfgCutOccupancyHigh{"cfgCutOccupancyHigh", 3000, "High cut on TPC occupancy"}; + Configurable cfgCutOccupancyLow{"cfgCutOccupancyLow", 0, "Low cut on TPC occupancy"}; - // Trigger particle selections in phase space - Configurable triggerEtaMin{"triggerEtaCutMin", -0.8, "triggeretamin"}; - Configurable triggerEtaMax{"triggerEtaCutMax", 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 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 assocPtCutMin{"assocPtCutMin", 0.2, "assocptmin"}; - Configurable assocPtCutMax{"assocPtCutMax", 10, "assocptmax"}; - - // Associated pion identification - Configurable pionMinBayesProb{"pionMinBayesProb", 0.95, "minimal Bayesian probability for pion ID"}; - Configurable assocPionNSigmaTPCFOF{"assocPionNSigmaTPCFOF", 3, "minimal n sigma in TOF and TPC for Pion ID"}; - 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"}; - - // specific selections - Configurable lambdaCospa{"lambdaCospa", 0.995, "CosPA for lambda"}; // allows for tighter selection for Lambda - - // primary particle DCAxy selections - // 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"}; - - // 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"}; - - // 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> 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> 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> 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)"}; - - // 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)"}; + struct : ConfigurableGroup { + // event filtering + Configurable zVertexCut{"zVertexCut", 10, "Cut on PV position"}; + Configurable selectINELgtZERO{"selectINELgtZERO", true, "select INEL>0 events"}; + Configurable requireAllGoodITSLayers{"requireAllGoodITSLayers", false, " require that in the event all ITS are good"}; + } eventSelections; + + struct : ConfigurableGroup { + // Trigger particle selections in phase space + 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{"assocEtaMin", -0.8, "triggeretamin"}; + Configurable assocEtaMax{"assocEtaMax", 0.8, "triggeretamax"}; + Configurable assocPtCutMin{"assocPtCutMin", 0.2, "assocptmin"}; + Configurable assocPtCutMax{"assocPtCutMax", 10, "assocptmax"}; + + // Associated pion identification + Configurable pionMinBayesProb{"pionMinBayesProb", 0.95, "minimal Bayesian probability for pion ID"}; + Configurable assocPionNSigmaTPCFOF{"assocPionNSigmaTPCFOF", 3, "minimal n sigma in TOF and TPC for Pion ID"}; + 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"}; + // more V0 selections in PbPb + Configurable lifetimecutK0S{"lifetimecutK0S", 20, "lifetimecutK0S"}; + Configurable lifetimecutLambda{"lifetimecutLambda", 30, "lifetimecutLambda"}; + Configurable dcanegtopvK0S{"dcanegtopvK0S", 0.1, "DCA Neg To PV"}; + Configurable dcapostopvK0S{"dcapostopvK0S", 0.1, "DCA Pos To PV"}; + Configurable dcanegtopvLambda{"dcanegtopvLambda", 0.05, "DCA Neg To PV"}; + Configurable dcapostopvLambda{"dcapostopvLambda", 0.2, "DCA Pos To PV"}; + Configurable dcanegtopvAntiLambda{"dcanegtopvAntiLambda", 0.2, "DCA Neg To PV"}; + Configurable dcapostopvAntiLambda{"dcapostopvAntiLambda", 0.05, "DCA Pos To PV"}; + // original equation: lArmPt*2>TMath::Abs(lArmAlpha) only for K0S + Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + + // specific selections + Configurable lambdaCospa{"lambdaCospa", 0.995, "CosPA for lambda"}; // allows for tighter selection for Lambda + + // primary particle DCAxy selections + // 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"}; + + // cascade selections + Configurable cascCospa{"cascCospa", 0.95, "cascCospa"}; + Configurable cascRadius{"cascRadius", 0.5, "cascRadius"}; + Configurable dcaCascdau{"dcaCascdau", 1.0, "dcaCascdau"}; + Configurable dcaBachtopv{"dcaBachtopv", 0.1, "dcaBachtopv"}; + Configurable cascV0masswindow{"cascV0masswindow", 0.01, "cascV0masswindow"}; + Configurable cascMindcav0topv{"cascMindcav0topv", 0.01, "cascMindcav0topv"}; + } systCuts; + struct : ConfigurableGroup { + // cascade selections in PbPb + Configurable cascDcacascdau{"cascDcacascdau", 1.0, "cascDcacascdau"}; + Configurable cascDcabachtopv{"cascDcabachtopv", 0.1, "cascDcabachtopv"}; + Configurable bachBaryonCosPA{"bachBaryonCosPA", 0.9999, "Bachelor baryon CosPA"}; + Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; + 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.07, "DCA Bach To PV"}; + Configurable cascdcaV0dau{"cascdcaV0dau", 0.5, "DCA V0 Daughters"}; + 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 cascdcaV0ToPV{"cascdcaV0ToPV", 0.06, "DCA V0 To PV"}; + Configurable cascv0cospa{"cascv0cospa", 0.98, "V0 CosPA"}; + Configurable cascv0RadiusMin{"cascv0RadiusMin", 2.5, "v0radius"}; + Configurable proplifetime{"proplifetime", 3, "ctau/"}; + Configurable lambdaMassWin{"lambdaMassWin", 0.005, "V0 Mass window limit"}; + Configurable rejcomp{"rejcomp", 0.008, "Competing Cascade rejection"}; + Configurable rapCut{"rapCut", 0.8, "Rapidity acceptance"}; + } MorePbPbsystCuts; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository to use"}; + Configurable parameterCCDBPath{"parameterCCDBPath", "Users/k/kcui/LHC25b4a/parameter", "Path of the mean and sigma"}; + + // 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"}; - ConfigurableAxis axisK0ShortMass{"axisK0ShortMass", {200, 0.400f, 0.600f}, "Inv. Mass (GeV/c^{2})"}; - ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.01f, 1.21f}, "Inv. Mass (GeV/c^{2})"}; - ConfigurableAxis axisXiMass{"axisXiMass", {200, 1.22f, 1.42f}, "Inv. Mass (GeV/c^{2})"}; - 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"}; + struct : ConfigurableGroup { + 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 axisK0ShortMass{"axisK0ShortMass", {200, 0.400f, 0.600f}, "Inv. Mass (GeV/c^{2})"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.01f, 1.21f}, "Inv. Mass (GeV/c^{2})"}; + ConfigurableAxis axisXiMass{"axisXiMass", {200, 1.22f, 1.42f}, "Inv. Mass (GeV/c^{2})"}; + 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"}; + } axesConfigurations; + // 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 preFilterTracks = nabs(aod::track::dcaXY) < systCuts.dcaXYconstant + systCuts.dcaXYpTdep * nabs(aod::track::signed1Pt); + Filter preFilterV0 = nabs(aod::v0data::dcapostopv) > systCuts.dcaPostopv&& + nabs(aod::v0data::dcanegtopv) > systCuts.dcaNegtopv&& aod::v0data::dcaV0daughters < systCuts.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) > systCuts.dcaPostopv&& nabs(aod::cascdata::dcanegtopv) > systCuts.dcaNegtopv&& nabs(aod::cascdata::dcabachtopv) > systCuts.dcaBachtopv&& aod::cascdata::dcaV0daughters < systCuts.dcaV0dau&& aod::cascdata::dcacascdaughters < systCuts.dcaCascdau; + + // 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; + Produces assocHadrons; + Produces assocPID; + struct : ConfigurableGroup { + // invariant mass parametrizations + Configurable> massParsK0Mean{"massParsK0Mean", {0.495967, 0.000095, 0.001120, 0.800000}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + Configurable> massParsK0Width{"massParsK0Width", {0.002324, 0.000600, 0.005076, 1.644687}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; - 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)"); + Configurable> massParsLambdaMean{"massParsLambdaMean", {1.115554, 0.000002, -0.000311, 1.303969}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + Configurable> massParsLambdaWidth{"massParsLambdaWidth", {0.001066, 0.000168, 0.001893, 1.407199}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + + Configurable> massParsCascadeMean{"massParsCascadeMean", {1.322150, -0.000087, -0.000761, 0.316391}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + Configurable> massParsCascadeWidth{"massParsCascadeWidth", {0.001269, 0.000249, 0.002790, 1.128544}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + + Configurable> massParsOmegaMean{"massParsOmegaMean", {1.671908, -0.000000, 0.001027, 2.263832}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + Configurable> massParsOmegaWidth{"massParsOmegaWidth", {0.001223, 0.000300, 0.040718, 2.826750}, "pars in [0]+[1]*x+[2]*std::exp(-[3]*x)"}; + } parameters; + 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)"); + TH1F* hK0ShortMean; + TH1F* hK0ShortWidth; + TH1F* hLambdaMean; + TH1F* hLambdaWidth; + TH1F* hXiMean; + TH1F* hXiWidth; + TH1F* hOmegaMean; + TH1F* hOmegaWidth; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + int mRunNumber; void init(InitContext const&) { - 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)); - fLambdaWidth->SetParameters(massParsLambdaWidth->at(0), massParsLambdaWidth->at(1), massParsLambdaWidth->at(2), massParsLambdaWidth->at(3)); - fXiMean->SetParameters(massParsCascadeMean->at(0), massParsCascadeMean->at(1), massParsCascadeMean->at(2), massParsCascadeMean->at(3)); - fXiWidth->SetParameters(massParsCascadeWidth->at(0), massParsCascadeWidth->at(1), massParsCascadeWidth->at(2), massParsCascadeWidth->at(3)); - fOmegaMean->SetParameters(massParsOmegaMean->at(0), massParsOmegaMean->at(1), massParsOmegaMean->at(2), massParsOmegaMean->at(3)); - fOmegaWidth->SetParameters(massParsOmegaWidth->at(0), massParsOmegaWidth->at(1), massParsOmegaWidth->at(2), massParsOmegaWidth->at(3)); - - histos.add("h3dMassK0Short", "h3dMassK0Short", kTH3F, {axisPtQA, axisK0ShortMass, axisMult}); - histos.add("h3dMassLambda", "h3dMassLambda", kTH3F, {axisPtQA, axisLambdaMass, axisMult}); - histos.add("h3dMassAntiLambda", "h3dMassAntiLambda", kTH3F, {axisPtQA, axisLambdaMass, axisMult}); - histos.add("h3dMassXiMinus", "h3dMassXiMinus", kTH3F, {axisPtQA, axisXiMass, axisMult}); - histos.add("h3dMassXiPlus", "h3dMassXiPlus", kTH3F, {axisPtQA, axisXiMass, axisMult}); - histos.add("h3dMassOmegaMinus", "h3dMassOmegaMinus", kTH3F, {axisPtQA, axisOmegaMass, axisMult}); - histos.add("h3dMassOmegaPlus", "h3dMassOmegaPlus", kTH3F, {axisPtQA, axisOmegaMass, axisMult}); + zorroSummary.setObject(zorro.getZorroSummary()); + mRunNumber = -1; + if (useParameterization) { + fK0Mean->SetParameters(parameters.massParsK0Mean->at(0), parameters.massParsK0Mean->at(1), parameters.massParsK0Mean->at(2), parameters.massParsK0Mean->at(3)); + fK0Width->SetParameters(parameters.massParsK0Width->at(0), parameters.massParsK0Width->at(1), parameters.massParsK0Width->at(2), parameters.massParsK0Width->at(3)); + fLambdaMean->SetParameters(parameters.massParsLambdaMean->at(0), parameters.massParsLambdaMean->at(1), parameters.massParsLambdaMean->at(2), parameters.massParsLambdaMean->at(3)); + fLambdaWidth->SetParameters(parameters.massParsLambdaWidth->at(0), parameters.massParsLambdaWidth->at(1), parameters.massParsLambdaWidth->at(2), parameters.massParsLambdaWidth->at(3)); + fXiMean->SetParameters(parameters.massParsCascadeMean->at(0), parameters.massParsCascadeMean->at(1), parameters.massParsCascadeMean->at(2), parameters.massParsCascadeMean->at(3)); + fXiWidth->SetParameters(parameters.massParsCascadeWidth->at(0), parameters.massParsCascadeWidth->at(1), parameters.massParsCascadeWidth->at(2), parameters.massParsCascadeWidth->at(3)); + fOmegaMean->SetParameters(parameters.massParsOmegaMean->at(0), parameters.massParsOmegaMean->at(1), parameters.massParsOmegaMean->at(2), parameters.massParsOmegaMean->at(3)); + fOmegaWidth->SetParameters(parameters.massParsOmegaWidth->at(0), parameters.massParsOmegaWidth->at(1), parameters.massParsOmegaWidth->at(2), parameters.massParsOmegaWidth->at(3)); + } else { + hK0ShortMean = 0x0; + hK0ShortWidth = 0x0; + hLambdaMean = 0x0; + hLambdaWidth = 0x0; + hXiMean = 0x0; + hXiWidth = 0x0; + hOmegaMean = 0x0; + hOmegaWidth = 0x0; + } + if (doprocessV0s || doprocessV0sMC) { + histos.add("h3dMassK0Short", "h3dMassK0Short", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisK0ShortMass, axesConfigurations.axisMult}); + histos.add("h3dMassLambda", "h3dMassLambda", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisLambdaMass, axesConfigurations.axisMult}); + histos.add("h3dMassAntiLambda", "h3dMassAntiLambda", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisLambdaMass, axesConfigurations.axisMult}); + } + if (doprocessCascades || doprocessCascadesMC) { + histos.add("h3dMassXiMinus", "h3dMassXiMinus", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisXiMass, axesConfigurations.axisMult}); + histos.add("h3dMassXiPlus", "h3dMassXiPlus", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisXiMass, axesConfigurations.axisMult}); + histos.add("h3dMassOmegaMinus", "h3dMassOmegaMinus", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisOmegaMass, axesConfigurations.axisMult}); + histos.add("h3dMassOmegaPlus", "h3dMassOmegaPlus", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisOmegaMass, axesConfigurations.axisMult}); + } + } + + 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(); + } + + void initParametersFromCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + LOG(info) << "Loading mean and sigma from CCDB for run " << mRunNumber << " now..."; + auto timeStamp = bc.timestamp(); + + TList* listParameters = ccdb->getForTimeStamp(parameterCCDBPath, timeStamp); + + if (!listParameters) { + LOG(fatal) << "Problem getting TList object with parameters!"; + } + if (doprocessV0s || doprocessV0sMC) { + hK0ShortMean = static_cast(listParameters->FindObject("hK0ShortMean")); + hK0ShortWidth = static_cast(listParameters->FindObject("hK0ShortWidth")); + hLambdaMean = static_cast(listParameters->FindObject("hLambdaMean")); + hLambdaWidth = static_cast(listParameters->FindObject("hLambdaWidth")); + } + if (doprocessCascades || doprocessCascadesMC) { + hXiMean = static_cast(listParameters->FindObject("hXiMean")); + hXiWidth = static_cast(listParameters->FindObject("hXiWidth")); + hOmegaMean = static_cast(listParameters->FindObject("hOmegaMean")); + hOmegaWidth = static_cast(listParameters->FindObject("hOmegaWidth")); + } + LOG(info) << "parameters now loaded for " << mRunNumber; + } + + // 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()) > eventSelections.zVertexCut) { + return false; + } + if (collision.centFT0M() > 100 || collision.centFT0M() < 0) { + return false; + } + if (!collision.isInelGt0() && eventSelections.selectINELgtZERO) { + return false; + } + if (!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) && eventSelections.requireAllGoodITSLayers) { + return false; + } + if (zorroMask.value != "") { + auto bc = collision.template bc_as(); + initCCDB(bc); + bool zorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); /// Just let Zorro do the accounting + if (!zorroSelected) { + return false; + } + } + return true; + } + + // more event selections in Pb-Pb + template + bool isCollisionSelectedPbPb(TCollision collision) + { + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX)) /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */ + return false; + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) // cut time intervals with dead ITS staves + 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 + return false; + auto occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) /* Below min occupancy and Above max occupancy*/ + return false; + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) // reject collisions close to Time Frame borders + return false; + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) // reject events affected by the ITS ROF border + return false; + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) // rejects collisions which are associated with the same "found-by-T0" bunch crossing + return false; + return true; } // reco-level trigger quality checks (N.B.: DCA is filtered, not selected) template bool isValidTrigger(TTrack track) { - if (track.eta() > triggerEtaMax || track.eta() < triggerEtaMin) { + if (track.eta() > systCuts.triggerEtaMax || track.eta() < systCuts.triggerEtaMin) { return false; } // if (track.sign()= 1 ) {continue;} - if (track.pt() > triggerPtCutMax || track.pt() < triggerPtCutMin) { + if (track.pt() > systCuts.triggerPtCutMax || track.pt() < systCuts.triggerPtCutMin) { return false; } - if (track.tpcNClsCrossedRows() < minTPCNCrossedRows) { + if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) { return false; // crossed rows } - if (!track.hasITS() && triggerRequireITS) { + if (!track.hasITS() && systCuts.triggerRequireITS) { return false; // skip, doesn't have ITS signal (skips lots of TPC-only!) } - if (track.tpcNClsShared() > triggerMaxTPCSharedClusters) { + if (track.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) { return false; // skip, has shared clusters } - if (!(bitcheck(track.itsClusterMap(), 0)) && triggerRequireL0) { + if (!(BIT_CHECK(track.itsClusterMap(), 0)) && systCuts.triggerRequireL0) { return false; // skip, doesn't have cluster in ITS L0 } return true; } + template + bool isValidAssocTrack(TTrack assoc) + { + if (assoc.eta() > systCuts.assocEtaMax || assoc.eta() < systCuts.assocEtaMin) { + return false; + } + if (assoc.pt() > systCuts.assocPtCutMax || assoc.pt() < systCuts.assocPtCutMin) { + return false; + } + if (assoc.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) { + return false; // crossed rows + } + if (!assoc.hasITS() && systCuts.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(); } && !requires { assoc.mcParticle(); }) { + if (assoc.tofSignal() > 0) { + if (std::sqrt(assoc.tofNSigmaPi() * assoc.tofNSigmaPi() + assoc.tpcNSigmaPi() * assoc.tpcNSigmaPi()) > systCuts.assocPionNSigmaTPCFOF) + return false; + if (assoc.tofNSigmaPr() < systCuts.rejectSigma) + return false; + if (assoc.tpcNSigmaPr() < systCuts.rejectSigma) + return false; + if (assoc.tofNSigmaKa() < systCuts.rejectSigma) + return false; + if (assoc.tpcNSigmaKa() < systCuts.rejectSigma) + return false; + nSigmaTPCTOF[4] = assoc.tofNSigmaPi(); + nSigmaTPCTOF[5] = assoc.tofNSigmaKa(); + nSigmaTPCTOF[6] = assoc.tofNSigmaPr(); + nSigmaTPCTOF[7] = assoc.tofNSigmaEl(); + } else { + if (assoc.tpcNSigmaPi() > systCuts.assocPionNSigmaTPCFOF) + return false; + if (assoc.tpcNSigmaPr() < systCuts.rejectSigma) + return false; + if (assoc.tpcNSigmaKa() < systCuts.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; + float pdgCode = -9999; + if constexpr (requires { assoc.mcParticle(); }) { + if (assoc.has_mcParticle()) { + auto mcParticle = assoc.mcParticle(); + physicalPrimary = mcParticle.isPhysicalPrimary(); + origPt = mcParticle.pt(); + pdgCode = mcParticle.pdgCode(); + } + } + + assocHadrons( + assoc.collisionId(), + physicalPrimary, + assoc.globalIndex(), + origPt, + pdgCode); + assocPID( + nSigmaTPCTOF[0], + nSigmaTPCTOF[1], + nSigmaTPCTOF[2], + nSigmaTPCTOF[3], + nSigmaTPCTOF[4], + nSigmaTPCTOF[5], + nSigmaTPCTOF[6], + nSigmaTPCTOF[7]); + return true; + } + + // cascadeselection in PbPb + template + bool CascadeSelectedPbPb(TCascade casc, float pvx, float pvy, float pvz) + { + // bachBaryonCosPA + if (casc.bachBaryonCosPA() < MorePbPbsystCuts.bachBaryonCosPA) + return false; + // bachBaryonDCAxyToPV + if (std::abs(casc.bachBaryonDCAxyToPV()) > MorePbPbsystCuts.bachBaryonDCAxyToPV) + return false; + // casccosPA + if (casc.casccosPA(pvx, pvy, pvz) < systCuts.cascCospa) + return false; + // dcacascdaughters + float ptDepCut = MorePbPbsystCuts.dcaCacsDauPar0; + if (casc.pt() > 1 && casc.pt() < 4) + ptDepCut = MorePbPbsystCuts.dcaCacsDauPar1; + else if (casc.pt() > 4) + ptDepCut = MorePbPbsystCuts.dcaCacsDauPar2; + if (casc.dcacascdaughters() > ptDepCut) + return false; + // dcaV0daughters + if (casc.dcaV0daughters() > systCuts.dcaV0dau) + return false; + // dcav0topv + if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < MorePbPbsystCuts.cascdcaV0ToPV) + return false; + // cascradius + if (casc.cascradius() < systCuts.cascRadius) + return false; + // v0radius + if (casc.v0radius() < MorePbPbsystCuts.cascv0RadiusMin) + return false; + // v0cosPA + if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < MorePbPbsystCuts.cascv0cospa) + return false; + // lambdaMassWin + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > MorePbPbsystCuts.lambdaMassWin) + return false; + return true; + } // for real data processing - void processTriggers(soa::Join::iterator const& collision, soa::Filtered const& tracks) + 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 (((doPPAnalysis && !isCollisionSelected(collision))) || (!doPPAnalysis && !isCollisionSelectedPbPb(collision))) { return; } @@ -216,19 +528,16 @@ struct hstrangecorrelationfilter { triggerTrack( track.collisionId(), false, // if you decide to check real data for primaries, you'll have a hard time - track.globalIndex()); + track.globalIndex(), + 0); + triggerTrackExtra(1); } } // for MC processing - void processTriggersMC(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::McParticles const&) + 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 (TMath::Abs(collision.posZ()) > 10.0) { + if (((doPPAnalysis && !isCollisionSelected(collision))) || (!doPPAnalysis && !isCollisionSelectedPbPb(collision))) { return; } @@ -238,97 +547,146 @@ struct hstrangecorrelationfilter { if (!isValidTrigger(track)) continue; bool physicalPrimary = false; + float origPt = -1; if (track.has_mcParticle()) { auto mcParticle = track.mcParticle(); physicalPrimary = mcParticle.isPhysicalPrimary(); + origPt = mcParticle.pt(); } triggerTrack( track.collisionId(), physicalPrimary, - track.globalIndex()); + 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&) { + // Load parameters for sideband subtraction + auto bc = collision.bc_as(); // 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 != "") { + 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::McParticles const&, aod::BCsWithTimestamps const&) + { + // Load parameters for sideband subtraction + auto bc = collision.bc_as(); + // 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 != "") { + 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&) + { + // Load parameters for sideband subtraction + auto bc = collision.bc_as(); + // 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 != "") { + 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; - } + } - 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 processAssocHadronsMC(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::McParticles const&, aod::BCsWithTimestamps const&) { + // Load parameters for sideband subtraction + auto bc = collision.bc_as(); // 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 != "") { + 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 (!isValidAssocTrack(track)) + continue; + } + } + + void processV0s(soa::Join::iterator const& collision, DauTracks const&, soa::Filtered const& V0s, aod::BCsWithTimestamps const&) + { + auto bc = collision.bc_as(); + double cent = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + if (((doPPAnalysis && !isCollisionSelected(collision))) || (!doPPAnalysis && !isCollisionSelectedPbPb(collision))) { 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) { + if (v0.v0radius() < systCuts.v0RadiusMin || v0.v0radius() > systCuts.v0RadiusMax || v0.eta() > systCuts.assocEtaMax || v0.eta() < systCuts.assocEtaMin || v0.v0cosPA() < systCuts.v0Cospa) { + continue; + } + if (v0.pt() > systCuts.assocPtCutMax || v0.pt() < systCuts.assocPtCutMin) { continue; } // check dE/dx compatibility @@ -338,239 +696,649 @@ struct hstrangecorrelationfilter { auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); - auto origV0entry = v0.v0_as(); // retrieve tags - if (negdau.tpcNClsCrossedRows() < minTPCNCrossedRows) + if (negdau.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) continue; - if (posdau.tpcNClsCrossedRows() < minTPCNCrossedRows) + if (posdau.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) continue; - if (TMath::Abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && TMath::Abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) - bitset(compatibleK0Short, 0); - if (TMath::Abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) - bitset(compatibleK0Short, 1); - if (TMath::Abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && TMath::Abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) - bitset(compatibleK0Short, 2); - - if (TMath::Abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && TMath::Abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) - if (v0.v0cosPA() > lambdaCospa) - bitset(compatibleLambda, 0); - if (TMath::Abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) - if (v0.v0cosPA() > lambdaCospa) - bitset(compatibleLambda, 1); - if (TMath::Abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && TMath::Abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) - if (v0.v0cosPA() > lambdaCospa) - bitset(compatibleLambda, 2); - - if (TMath::Abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && TMath::Abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) - if (v0.v0cosPA() > lambdaCospa) - bitset(compatibleAntiLambda, 0); - if (TMath::Abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) - if (v0.v0cosPA() > lambdaCospa) - bitset(compatibleAntiLambda, 1); - if (TMath::Abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && TMath::Abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) - if (v0.v0cosPA() > lambdaCospa) - bitset(compatibleAntiLambda, 2); - - // 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 (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && + v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + BIT_SET(compatibleK0Short, 0); + } } - 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 (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && + v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + BIT_SET(compatibleK0Short, 1); + } } - 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 (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && + v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + BIT_SET(compatibleK0Short, 2); + } } - if (v0.mK0Short() > fK0Mean->Eval(v0.pt()) + backgroundNsigma * fK0Width->Eval(v0.pt())) { - massRegK0Short = 4; + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + BIT_SET(compatibleLambda, 0); + } + } } - if (v0.mK0Short() < fK0Mean->Eval(v0.pt()) - backgroundNsigma * fK0Width->Eval(v0.pt())) { - massRegK0Short = 0; + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + BIT_SET(compatibleLambda, 1); + } + } } - - int massRegLambda = -1; - if (TMath::Abs(v0.mLambda() - fLambdaMean->Eval(v0.pt()) < peakNsigma * fLambdaWidth->Eval(v0.pt()))) { - massRegLambda = 2; + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + BIT_SET(compatibleLambda, 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 (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + BIT_SET(compatibleAntiLambda, 0); + } + } } - 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 (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + BIT_SET(compatibleAntiLambda, 1); + } + } } - if (v0.mLambda() > fLambdaMean->Eval(v0.pt()) + backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegLambda = 4; + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + BIT_SET(compatibleAntiLambda, 2); + } + } } - if (v0.mLambda() < fLambdaMean->Eval(v0.pt()) - backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegLambda = 0; + float massNSigmaK0Short = -20.0f; + float massNSigmaLambda = -20.0f; + float massNSigmaAntiLambda = -20.0f; + if (useParameterization) { + massNSigmaK0Short = (v0.mK0Short() - fK0Mean->Eval(v0.pt())) / (fK0Width->Eval(v0.pt()) + 1e-6); + massNSigmaLambda = (v0.mLambda() - fLambdaMean->Eval(v0.pt())) / (fLambdaWidth->Eval(v0.pt()) + 1e-6); + massNSigmaAntiLambda = (v0.mAntiLambda() - fLambdaMean->Eval(v0.pt())) / (fLambdaWidth->Eval(v0.pt()) + 1e-6); + } else { + // Load parameters for sideband subtraction + initParametersFromCCDB(bc); + // simplified handling: calculate NSigma in mass here + if (v0.pt() < 0.2f || v0.pt() > 14.5f) { + massNSigmaK0Short = (v0.mK0Short() - hK0ShortMean->GetBinContent(hK0ShortMean->FindBin(v0.pt()))) / (hK0ShortWidth->GetBinContent(hK0ShortWidth->FindBin(v0.pt())) + 1e-6); + massNSigmaLambda = (v0.mLambda() - hLambdaMean->GetBinContent(hLambdaMean->FindBin(v0.pt()))) / (hLambdaWidth->GetBinContent(hLambdaMean->FindBin(v0.pt())) + 1e-6); + massNSigmaAntiLambda = (v0.mAntiLambda() - hLambdaMean->GetBinContent(hLambdaMean->FindBin(v0.pt()))) / (hLambdaWidth->GetBinContent(hLambdaMean->FindBin(v0.pt())) + 1e-6); + } else { + massNSigmaK0Short = (v0.mK0Short() - hK0ShortMean->Interpolate(v0.pt())) / (hK0ShortWidth->Interpolate(v0.pt()) + 1e-6); + massNSigmaLambda = (v0.mLambda() - hLambdaMean->Interpolate(v0.pt())) / (hLambdaWidth->Interpolate(v0.pt()) + 1e-6); + massNSigmaAntiLambda = (v0.mAntiLambda() - hLambdaMean->Interpolate(v0.pt())) / (hLambdaWidth->Interpolate(v0.pt()) + 1e-6); + } } + if (compatibleK0Short) + histos.fill(HIST("h3dMassK0Short"), v0.pt(), v0.mK0Short(), cent); + if (compatibleLambda) + histos.fill(HIST("h3dMassLambda"), v0.pt(), v0.mLambda(), cent); + if (compatibleAntiLambda) + histos.fill(HIST("h3dMassAntiLambda"), v0.pt(), v0.mAntiLambda(), cent); - int massRegAntiLambda = -1; - if (TMath::Abs(v0.mAntiLambda() - fLambdaMean->Eval(v0.pt()) < peakNsigma * fLambdaWidth->Eval(v0.pt()))) { - massRegAntiLambda = 2; + 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 = 3; + } + } + + void processV0sMC(soa::Join::iterator const& collision, DauTracksMC const&, soa::Filtered const& V0s, aod::McParticles const&, aod::BCsWithTimestamps const&) + { + double cent = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + auto bc = collision.bc_as(); + if (((doPPAnalysis && !isCollisionSelected(collision))) || (!doPPAnalysis && !isCollisionSelectedPbPb(collision))) { + return; + } + /// _________________________________________________ + /// Populate table with associated V0s + + for (auto const& v0 : V0s) { + if (v0.v0radius() < systCuts.v0RadiusMin || v0.v0radius() > systCuts.v0RadiusMax || v0.eta() > systCuts.assocEtaMax || v0.eta() < systCuts.assocEtaMin || v0.v0cosPA() < systCuts.v0Cospa) { + continue; } - 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; + if (v0.pt() > systCuts.assocPtCutMax || v0.pt() < systCuts.assocPtCutMin) { + continue; } - if (v0.mAntiLambda() > fLambdaMean->Eval(v0.pt()) + backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegAntiLambda = 4; + // check dE/dx compatibility + int compatibleK0Short = 0; + int compatibleLambda = 0; + int compatibleAntiLambda = 0; + + auto posdau = v0.posTrack_as(); + auto negdau = v0.negTrack_as(); + + if (negdau.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + continue; + if (posdau.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + continue; + + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && + v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + BIT_SET(compatibleK0Short, 0); + } + } + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && + v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + BIT_SET(compatibleK0Short, 1); + } + } + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && + v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha()))) { + BIT_SET(compatibleK0Short, 2); + } + } + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + BIT_SET(compatibleLambda, 0); + } + } + } + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + BIT_SET(compatibleLambda, 1); + } + } } - if (v0.mAntiLambda() < fLambdaMean->Eval(v0.pt()) - backgroundNsigma * fLambdaWidth->Eval(v0.pt())) { - massRegAntiLambda = 0; + if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda)) { + BIT_SET(compatibleLambda, 2); + } + } + } + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + BIT_SET(compatibleAntiLambda, 0); + } + } + } + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + BIT_SET(compatibleAntiLambda, 1); + } + } + } + if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { + if (v0.v0cosPA() > systCuts.lambdaCospa) { + if (doPPAnalysis || (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < systCuts.lifetimecutLambda && + std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda)) { + BIT_SET(compatibleAntiLambda, 2); + } + } } - 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()); + float massNSigmaK0Short = -20.0f; + float massNSigmaLambda = -20.0f; + float massNSigmaAntiLambda = -20.0f; + if (useParameterization) { + massNSigmaK0Short = (v0.mK0Short() - fK0Mean->Eval(v0.pt())) / (fK0Width->Eval(v0.pt()) + 1e-6); + massNSigmaLambda = (v0.mLambda() - fLambdaMean->Eval(v0.pt())) / (fLambdaWidth->Eval(v0.pt()) + 1e-6); + massNSigmaAntiLambda = (v0.mAntiLambda() - fLambdaMean->Eval(v0.pt())) / (fLambdaWidth->Eval(v0.pt()) + 1e-6); + } else { + // Load parameters for sideband subtraction + initParametersFromCCDB(bc); + // simplified handling: calculate NSigma in mass here + if (v0.pt() < 0.2f || v0.pt() > 14.5f) { + massNSigmaK0Short = (v0.mK0Short() - hK0ShortMean->GetBinContent(hK0ShortMean->FindBin(v0.pt()))) / (hK0ShortWidth->GetBinContent(hK0ShortWidth->FindBin(v0.pt())) + 1e-6); + massNSigmaLambda = (v0.mLambda() - hLambdaMean->GetBinContent(hLambdaMean->FindBin(v0.pt()))) / (hLambdaWidth->GetBinContent(hLambdaMean->FindBin(v0.pt())) + 1e-6); + massNSigmaAntiLambda = (v0.mAntiLambda() - hLambdaMean->GetBinContent(hLambdaMean->FindBin(v0.pt()))) / (hLambdaWidth->GetBinContent(hLambdaMean->FindBin(v0.pt())) + 1e-6); + } else { + massNSigmaK0Short = (v0.mK0Short() - hK0ShortMean->Interpolate(v0.pt())) / (hK0ShortWidth->Interpolate(v0.pt()) + 1e-6); + massNSigmaLambda = (v0.mLambda() - hLambdaMean->Interpolate(v0.pt())) / (hLambdaWidth->Interpolate(v0.pt()) + 1e-6); + massNSigmaAntiLambda = (v0.mAntiLambda() - hLambdaMean->Interpolate(v0.pt())) / (hLambdaWidth->Interpolate(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(), cent); + if (compatibleLambda && (!doTrueSelectionInMass || (trueLambda && v0PhysicalPrimary))) + histos.fill(HIST("h3dMassLambda"), v0.pt(), v0.mLambda(), cent); + if (compatibleAntiLambda && (!doTrueSelectionInMass || (trueAntiLambda && v0PhysicalPrimary))) + histos.fill(HIST("h3dMassAntiLambda"), v0.pt(), v0.mAntiLambda(), cent); if (!fillTableOnlyWithCompatible || ( // start major condition check - (compatibleK0Short > 0 && massRegK0Short > 0 && massRegK0Short < 4) || - (compatibleLambda > 0 && massRegLambda > 0 && massRegLambda < 4) || - (compatibleAntiLambda > 0 && 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(), origV0entry.isPhysicalPrimary(), - 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) { + double cent = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + auto bc = collision.bc_as(); + if (((doPPAnalysis && !isCollisionSelected(collision))) || (!doPPAnalysis && !isCollisionSelectedPbPb(collision))) { return; } /// _________________________________________________ /// Step 3: Populate table with associated Cascades for (auto const& casc : Cascades) { + if (casc.eta() > systCuts.assocEtaMax || casc.eta() < systCuts.assocEtaMin) { + continue; + } + if (casc.pt() > systCuts.assocPtCutMax || casc.pt() < systCuts.assocPtCutMin) { + continue; + } + if (doPPAnalysis && (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.v0Cospa || + casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.cascCospa || + casc.cascradius() < systCuts.cascRadius || + std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < systCuts.cascMindcav0topv || + std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > systCuts.cascV0masswindow)) + 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) + if (bachTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) continue; - if (posTrackCast.tpcNClsCrossedRows() < minTPCNCrossedRows) + if (posTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) continue; - if (negTrackCast.tpcNClsCrossedRows() < minTPCNCrossedRows) + if (negTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + continue; + if (!doPPAnalysis && !CascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) continue; - // check dE/dx compatibility int compatibleXiMinus = 0; int compatibleXiPlus = 0; int compatibleOmegaMinus = 0; int compatibleOmegaPlus = 0; + 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 = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxiPDG); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomegaPDG); - if (TMath::Abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && TMath::Abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && TMath::Abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) - bitset(compatibleXiMinus, 0); - if (TMath::Abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) - bitset(compatibleXiMinus, 1); - if (TMath::Abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && TMath::Abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && TMath::Abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) - bitset(compatibleXiMinus, 2); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiMinus, 0); + } + } + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiMinus, 1); + } + } + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiMinus, 2); + } + } - if (TMath::Abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && TMath::Abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && TMath::Abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) - bitset(compatibleXiPlus, 0); - if (TMath::Abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) - bitset(compatibleXiPlus, 1); - if (TMath::Abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && TMath::Abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && TMath::Abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) - bitset(compatibleXiPlus, 2); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiPlus, 0); + } + } + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiPlus, 1); + } + } + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiPlus, 2); + } + } - if (TMath::Abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && TMath::Abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && TMath::Abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) - bitset(compatibleOmegaMinus, 0); - if (TMath::Abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) - bitset(compatibleOmegaMinus, 1); - if (TMath::Abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && TMath::Abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && TMath::Abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) - bitset(compatibleOmegaMinus, 2); + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaMinus, 0); + } + } + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaMinus, 1); + } + } + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaMinus, 2); + } + } - if (TMath::Abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && TMath::Abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && TMath::Abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) - bitset(compatibleOmegaPlus, 0); - if (TMath::Abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && TMath::Abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && TMath::Abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) - bitset(compatibleOmegaPlus, 1); - if (TMath::Abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && TMath::Abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && TMath::Abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) - bitset(compatibleOmegaPlus, 2); + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaPlus, 0); + } + } + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaPlus, 1); + } + } + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaPlus, 2); + } + } + float massNSigmaXi = -20.0f; + float massNSigmaOmega = -20.0f; + if (useParameterization) { + massNSigmaXi = (casc.mXi() - fXiMean->Eval(casc.pt())) / (fXiWidth->Eval(casc.pt()) + 1e-6); + massNSigmaOmega = (casc.mOmega() - fOmegaMean->Eval(casc.pt())) / (fOmegaWidth->Eval(casc.pt()) + 1e-6); + } else { + // Load parameters for sideband subtraction + initParametersFromCCDB(bc); + if (casc.pt() < 0.2f || casc.pt() > 14.5f) { + massNSigmaXi = (casc.mXi() - hXiMean->GetBinContent(hXiMean->FindBin(casc.pt()))) / (hXiWidth->GetBinContent(hXiWidth->FindBin(casc.pt())) + 1e-6); + massNSigmaOmega = (casc.mOmega() - hOmegaMean->GetBinContent(hOmegaMean->FindBin(casc.pt()))) / (hOmegaWidth->GetBinContent(hOmegaWidth->FindBin(casc.pt())) + 1e-6); + } else { + massNSigmaXi = (casc.mXi() - hXiMean->Interpolate(casc.pt())) / (hXiWidth->Interpolate(casc.pt()) + 1e-6); + massNSigmaOmega = (casc.mOmega() - hOmegaMean->Interpolate(casc.pt())) / (hOmegaWidth->Interpolate(casc.pt()) + 1e-6); + } + } + if (compatibleXiMinus) + histos.fill(HIST("h3dMassXiMinus"), casc.pt(), casc.mXi(), cent); + if (compatibleXiPlus) + histos.fill(HIST("h3dMassXiPlus"), casc.pt(), casc.mXi(), cent); + if (compatibleOmegaMinus && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + histos.fill(HIST("h3dMassOmegaMinus"), casc.pt(), casc.mOmega(), cent); + if (compatibleOmegaPlus && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + histos.fill(HIST("h3dMassOmegaPlus"), casc.pt(), casc.mOmega(), cent); - int massRegXi = -1; - if (TMath::Abs(casc.mXi() - fXiMean->Eval(casc.pt()) < peakNsigma * fXiWidth->Eval(casc.pt()))) { - massRegXi = 2; + if (!fillTableOnlyWithCompatible || + ( // start major condition check + ((compatibleXiMinus > 0 || compatibleXiPlus > 0) && std::abs(massNSigmaXi) < maxMassNSigma) || + ((compatibleOmegaMinus > 0 || compatibleOmegaPlus > 0) && std::abs(massNSigmaOmega) < maxMassNSigma && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter)) // end major condition check + ) { + assocCascades(casc.collisionId(), casc.globalIndex(), + compatibleXiMinus, compatibleXiPlus, compatibleOmegaMinus, compatibleOmegaPlus, + false, false, false, false, false, + massNSigmaXi, massNSigmaOmega); } - 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; + } + } + + void processCascadesMC(soa::Join::iterator const& collision, DauTracks const&, soa::Filtered const& /*V0s*/, soa::Filtered const& Cascades, aod::McParticles const&, aod::BCsWithTimestamps const&) + { + double cent = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + auto bc = collision.bc_as(); + // Perform basic event selection + if (((doPPAnalysis && !isCollisionSelected(collision))) || (!doPPAnalysis && !isCollisionSelectedPbPb(collision))) { + return; + } + /// _________________________________________________ + /// Step 3: Populate table with associated Cascades + for (auto const& casc : Cascades) { + if (casc.eta() > systCuts.assocEtaMax || casc.eta() < systCuts.assocEtaMin) { + continue; } - 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.pt() > systCuts.assocPtCutMax || casc.pt() < systCuts.assocPtCutMin) { + continue; } - if (casc.mXi() > fXiMean->Eval(casc.pt()) + backgroundNsigma * fXiWidth->Eval(casc.pt())) { - massRegXi = 4; + if (doPPAnalysis && (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.v0Cospa || + casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.cascCospa || + casc.cascradius() < systCuts.cascRadius || + std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < systCuts.cascMindcav0topv || + std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > systCuts.cascV0masswindow)) + continue; + + auto bachTrackCast = casc.bachelor_as(); + auto posTrackCast = casc.posTrack_as(); + auto negTrackCast = casc.negTrack_as(); + + // minimum TPC crossed rows + if (bachTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + continue; + if (posTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + continue; + if (negTrackCast.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) + continue; + if (!doPPAnalysis && !CascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) + continue; + + // check dE/dx compatibility + int compatibleXiMinus = 0; + int compatibleXiPlus = 0; + int compatibleOmegaMinus = 0; + int compatibleOmegaPlus = 0; + 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 = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxiPDG); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomegaPDG); + + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiMinus, 0); + } + } + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiMinus, 1); + } + } + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiMinus, 2); + } + } + + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiPlus, 0); + } + } + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiPlus, 1); + } } - if (casc.mXi() < fXiMean->Eval(casc.pt()) - backgroundNsigma * fXiWidth->Eval(casc.pt())) { - massRegXi = 0; + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > MorePbPbsystCuts.rejcomp && + ctauXi < MorePbPbsystCuts.proplifetime && std::abs(casc.yXi()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleXiPlus, 2); + } } - int massRegOmega = -1; - if (TMath::Abs(casc.mOmega() - fOmegaMean->Eval(casc.pt()) < peakNsigma * fOmegaWidth->Eval(casc.pt()))) { - massRegOmega = 2; + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaMinus, 0); + } } - 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 (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaMinus, 1); + } } - 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; + if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaMesonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaMinus, 2); + } } - if (casc.mOmega() > fOmegaMean->Eval(casc.pt()) + backgroundNsigma * fOmegaWidth->Eval(casc.pt())) { - massRegOmega = 4; + + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaPlus, 0); + } } - if (casc.mOmega() < fOmegaMean->Eval(casc.pt()) - backgroundNsigma * fOmegaWidth->Eval(casc.pt())) { - massRegOmega = 0; + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaPlus, 1); + } + } + if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) { + if (doPPAnalysis || (std::abs(casc.dcabachtopv()) > MorePbPbsystCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > MorePbPbsystCuts.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > MorePbPbsystCuts.dcaBaryonToPV && std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > MorePbPbsystCuts.rejcomp && + ctauOmega < MorePbPbsystCuts.proplifetime && std::abs(casc.yOmega()) < MorePbPbsystCuts.rapCut)) { + BIT_SET(compatibleOmegaPlus, 2); + } + } + float massNSigmaXi = 20.0f; + float massNSigmaOmega = 20.0f; + if (useParameterization) { + massNSigmaXi = (casc.mXi() - fXiMean->Eval(casc.pt())) / (fXiWidth->Eval(casc.pt()) + 1e-6); + massNSigmaOmega = (casc.mOmega() - fOmegaMean->Eval(casc.pt())) / (fOmegaWidth->Eval(casc.pt()) + 1e-6); + } else { + // Load parameters for sideband subtraction + initParametersFromCCDB(bc); + if (casc.pt() < 0.2f || casc.pt() > 14.5f) { + massNSigmaXi = (casc.mXi() - hXiMean->GetBinContent(hXiMean->FindBin(casc.pt()))) / (hXiWidth->GetBinContent(hXiWidth->FindBin(casc.pt())) + 1e-6); + massNSigmaOmega = (casc.mOmega() - hOmegaMean->GetBinContent(hOmegaMean->FindBin(casc.pt()))) / (hOmegaWidth->GetBinContent(hOmegaWidth->FindBin(casc.pt())) + 1e-6); + } else { + massNSigmaXi = (casc.mXi() - hXiMean->Interpolate(casc.pt())) / (hXiWidth->Interpolate(casc.pt()) + 1e-6); + massNSigmaOmega = (casc.mOmega() - hOmegaMean->Interpolate(casc.pt())) / (hOmegaWidth->Interpolate(casc.pt()) + 1e-6); + } } - 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()); + 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(), cent); + if (compatibleXiPlus && (!doTrueSelectionInMass || (trueXiPlus && cascPhysicalPrimary))) + histos.fill(HIST("h3dMassXiPlus"), casc.pt(), casc.mXi(), cent); + if (compatibleOmegaMinus && (!doTrueSelectionInMass || (trueOmegaMinus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + histos.fill(HIST("h3dMassOmegaMinus"), casc.pt(), casc.mOmega(), cent); + if (compatibleOmegaPlus && (!doTrueSelectionInMass || (trueOmegaPlus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + histos.fill(HIST("h3dMassOmegaPlus"), casc.pt(), casc.mOmega(), cent); if (!fillTableOnlyWithCompatible || ( // start major condition check - ((compatibleXiMinus > 0 || compatibleXiPlus > 0) && massRegXi > 0 && massRegXi < 4) || - ((compatibleOmegaMinus > 0 || compatibleOmegaPlus > 0) && massRegOmega > 0 && massRegOmega < 4)) // end major condition check + ((compatibleXiMinus > 0 || compatibleXiPlus > 0) && std::abs(massNSigmaXi) < maxMassNSigma) || + ((compatibleOmegaMinus > 0 || compatibleOmegaPlus > 0) && std::abs(massNSigmaOmega) < maxMassNSigma && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter)) // end major condition check ) { assocCascades(casc.collisionId(), casc.globalIndex(), compatibleXiMinus, compatibleXiPlus, compatibleOmegaMinus, compatibleOmegaPlus, - origCascadeEntry.isTrueXiMinus(), origCascadeEntry.isTrueXiPlus(), - origCascadeEntry.isTrueOmegaMinus(), origCascadeEntry.isTrueOmegaPlus(), - origCascadeEntry.isPhysicalPrimary(), - massRegXi, massRegOmega); + trueXiMinus, trueXiPlus, + trueOmegaMinus, trueOmegaPlus, + cascPhysicalPrimary, + massNSigmaXi, massNSigmaOmega); } } } - - 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, 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..491cf1c6699 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/lambdaJetpolarizationbuilder.cxx @@ -0,0 +1,693 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/lambdaJetpolarization.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +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 Lambda"}; + Configurable v0rejK0s{"v0rejK0s", 0.075, "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(); + maxJetPt = maxJetpT; + } + } + 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 d70552c4c71..ec4b8183b4e 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeroMLSelectionTreeCreator.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeroMLSelectionTreeCreator.cxx @@ -24,37 +24,39 @@ // david.dobrigkeit.chinellato@cern.ch // -#include // C system -#include // C++ system -#include // C++ system -#include // C++ system +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/RunningWorkflowInfo.h" -#include "Framework/AnalysisTask.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/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" -#include "Common/TableProducer/PID/pidTOFBase.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include // C system +#include #include #include -#include #include #include -#include +#include + +#include // C++ system +#include // C++ system +#include // C++ system using namespace o2; using namespace o2::framework; diff --git a/PWGLF/TableProducer/Strangeness/lambdakzerobuilder.cxx b/PWGLF/TableProducer/Strangeness/lambdakzerobuilder.cxx index cffe2c54282..7b898bfa98e 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 @@ -263,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"}; @@ -540,9 +543,7 @@ 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 && doprocessFindableRun3 == false) { @@ -736,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); } } @@ -835,7 +838,7 @@ struct lambdakzeroBuilder { statisticsRegistry.v0statsUnassociated[kV0TPCrefit]++; // Calculate DCA with respect to the collision associated to the V0, not individual tracks - gpu::gpustd::array dcaInfo; + std::array dcaInfo; auto posTrackPar = getTrackPar(posTrack); o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, posTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo); @@ -977,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 @@ -993,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; @@ -1004,6 +1011,8 @@ struct lambdakzeroBuilder { keepCandidate = true; if (passML2P_Lambda && dEdxAntiLambda && desiredMassAntiLambda) keepCandidate = true; + if (dEdxGamma && desiredMassGamma) + keepCandidate = true; if (!keepCandidate) return false; @@ -1182,16 +1191,11 @@ 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]++; @@ -1213,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); @@ -1376,6 +1380,9 @@ 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; enum v0bit { bitInteresting = 0, @@ -1415,6 +1422,30 @@ 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"); + } } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -1463,9 +1494,11 @@ struct lambdakzeroPreselector { //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* /// function to check PDG association template - void checkPDG(TV0Object const& lV0Candidate, uint32_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(); @@ -1480,7 +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) { @@ -1498,14 +1533,40 @@ 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) @@ -1560,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) { @@ -1618,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) @@ -1640,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()]); } @@ -1745,18 +1808,10 @@ struct lambdakzeroV0DataLinkBuilder { PROCESS_SWITCH(lambdakzeroV0DataLinkBuilder, processFindable, "process findable V0s", false); }; -// Extends the v0data table with expression columns -struct lambdakzeroInitializer { - Spawns v0cores; - Spawns v0fccores; - void init(InitContext const&) {} -}; - WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Strangeness/lambdakzerofinder.cxx b/PWGLF/TableProducer/Strangeness/lambdakzerofinder.cxx index c1085762b6f..c706c207df7 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzerofinder.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzerofinder.cxx @@ -28,37 +28,39 @@ // david.dobrigkeit.chinellato@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessFinderTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.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/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#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 "DCAFitter/DCAFitterN.h" -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFStrangenessFinderTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "CCDB/BasicCCDBManager.h" +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -270,11 +272,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) @@ -429,17 +431,10 @@ struct lambdakzerofinderQa { PROCESS_SWITCH(lambdakzerofinderQa, processRun2, "Process Run 2 data", false); }; -/// Extends the v0data table with expression columns -struct lambdakzeroinitializer { - Spawns v0cores; - void init(InitContext const&) {} -}; - WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc, TaskName{"lf-lambdakzeroprefilter"}), adaptAnalysisTask(cfgc, TaskName{"lf-lambdakzerofinder"}), - adaptAnalysisTask(cfgc, TaskName{"lf-lambdakzerofinderQA"}), - adaptAnalysisTask(cfgc, TaskName{"lf-lambdakzeroinitializer"})}; + adaptAnalysisTask(cfgc, TaskName{"lf-lambdakzerofinderQA"})}; } diff --git a/PWGLF/TableProducer/Strangeness/lambdakzeromcbuilder.cxx b/PWGLF/TableProducer/Strangeness/lambdakzeromcbuilder.cxx index 8fe57bc144f..1d7b1c29490 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeromcbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeromcbuilder.cxx @@ -55,6 +55,8 @@ struct lambdakzeromcbuilder { 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}; @@ -77,31 +79,72 @@ struct lambdakzeromcbuilder { 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; - int motherLabel; - int pdgCode; - int pdgCodeMother; - int pdgCodePositive; - int pdgCodeNegative; - int mcCollision; - bool isPhysicalPrimary; + 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; - uint64_t packedMcParticleIndices; + std::array momentum; }; mcV0info thisInfo; //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* - // prong index combiner - uint64_t combineProngIndices(uint32_t low, uint32_t high) + // kink handling + template + int getOriginatingParticle(mcpart const& part, int& indexForPositionOfDecay) { - return (((uint64_t)high) << 32) | ((uint64_t)low); + 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; } //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -113,7 +156,6 @@ struct lambdakzeromcbuilder { std::vector mcParticleIsReco(mcParticles.size(), false); // mc Particle not recoed by V0s for (auto& v0 : v0table) { - thisInfo.packedMcParticleIndices = 0; // not de-referenced properly yet thisInfo.label = -1; thisInfo.motherLabel = -1; thisInfo.pdgCode = 0; @@ -124,57 +166,99 @@ struct lambdakzeromcbuilder { 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(); // Association check // There might be smarter ways of doing this in the future if (lNegTrack.has_mcParticle() && lPosTrack.has_mcParticle()) { - thisInfo.packedMcParticleIndices = combineProngIndices(lPosTrack.mcParticleId(), lNegTrack.mcParticleId()); auto lMCNegTrack = lNegTrack.mcParticle_as(); auto lMCPosTrack = lPosTrack.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(); - if (lMCNegTrack.has_mothers() && lMCPosTrack.has_mothers()) { - for (auto& lNegMother : lMCNegTrack.mothers_as()) { - for (auto& lPosMother : lMCPosTrack.mothers_as()) { - if (lNegMother.globalIndex() == lPosMother.globalIndex()) { - thisInfo.label = lNegMother.globalIndex(); - - if (lNegMother.has_mcCollision()) { - thisInfo.mcCollision = lNegMother.mcCollisionId(); // save this reference, please - } - // acquire information - thisInfo.xyz[0] = lMCPosTrack.vx(); - thisInfo.xyz[1] = lMCPosTrack.vy(); - thisInfo.xyz[2] = lMCPosTrack.vz(); - thisInfo.pdgCode = lNegMother.pdgCode(); - thisInfo.isPhysicalPrimary = lNegMother.isPhysicalPrimary(); - if (lNegMother.has_mothers()) { - for (auto& lNegGrandMother : lNegMother.mothers_as()) { - thisInfo.pdgCodeMother = lNegGrandMother.pdgCode(); - thisInfo.motherLabel = lNegGrandMother.globalIndex(); - } - } - } + // 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( thisInfo.label, thisInfo.motherLabel); // Mark mcParticle as recoed (no searching necessary afterwards) - if (thisInfo.motherLabel > -1) { - mcParticleIsReco[thisInfo.motherLabel] = true; + if (thisInfo.label > -1) { + mcParticleIsReco[thisInfo.label] = true; } // ---] Symmetric populate [--- @@ -187,7 +271,8 @@ struct lambdakzeromcbuilder { 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.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 @@ -204,17 +289,45 @@ struct lambdakzeromcbuilder { // 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.packedMcParticleIndices == mcV0infos[ii].packedMcParticleIndices && mcV0infos[ii].packedMcParticleIndices > 0) { + 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) { + 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 } @@ -224,17 +337,17 @@ struct lambdakzeromcbuilder { if (populateV0MCCoresAsymmetric) { // first step: add any un-recoed v0mmcores that were requested for (auto& mcParticle : mcParticles) { - thisInfo.packedMcParticleIndices = 0; thisInfo.label = -1; thisInfo.motherLabel = -1; thisInfo.pdgCode = 0; - thisInfo.pdgCodeMother = 0; - thisInfo.pdgCodePositive = 0; - thisInfo.pdgCodeNegative = 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 @@ -249,16 +362,65 @@ struct lambdakzeromcbuilder { (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 } - // guarantee compressibility: keep momentum entirely in the positive prong - // WARNING: THIS IS AS ARBITRARY AS IT GETS but should be ok - thisInfo.posP[0] = mcParticle.px(); - thisInfo.posP[1] = mcParticle.py(); - thisInfo.posP[2] = mcParticle.pz(); + // + 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); @@ -271,8 +433,9 @@ struct lambdakzeromcbuilder { 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]); - v0mccollref(thisInfo.mcCollision); + info.negP[0], info.negP[1], info.negP[2], + info.momentum[0], info.momentum[1], info.momentum[2]); + v0mccollref(info.mcCollision); } } diff --git a/PWGLF/TableProducer/Strangeness/lambdakzeromcfinder.cxx b/PWGLF/TableProducer/Strangeness/lambdakzeromcfinder.cxx index 86e71a80ae2..3d948a8ff26 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeromcfinder.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeromcfinder.cxx @@ -24,39 +24,40 @@ // david.dobrigkeit.chinellato@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table -#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/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/McCollisionExtra.h" -#include "Common/DataModel/PIDResponse.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 "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" + #include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" -#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include "Math/Vector4D.h" #include -#include #include #include -#include +#include #include -#include +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -228,7 +229,7 @@ struct lambdakzeromcfinder { nPosReco++; } } // end track list loop - } // end positive pdg check + } // end positive pdg check if (daughter.pdgCode() == negativePdg) { auto const& thisDaughterTracks = daughter.template tracks_as(); bool tpcOnlyFound = false; @@ -245,7 +246,7 @@ struct lambdakzeromcfinder { nNegReco++; } } // end track list loop - } // end negative pdg check + } // end negative pdg check } } } @@ -351,7 +352,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 412161ebe52..10d9418c82e 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzeromlselection.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzeromlselection.cxx @@ -20,37 +20,39 @@ // david.dobrigkeit.chinellato@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#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/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + #include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include #include #include -#include #include #include -#include -#include "Tools/ML/MlResponse.h" -#include "Tools/ML/model.h" +#include + +#include +#include +#include using namespace o2; using namespace o2::analysis; @@ -75,8 +77,8 @@ struct lambdakzeromlselection { std::map metadata; - 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 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) diff --git a/PWGLF/TableProducer/Strangeness/lambdakzeropid.cxx b/PWGLF/TableProducer/Strangeness/lambdakzeropid.cxx deleted file mode 100644 index 8871c983668..00000000000 --- a/PWGLF/TableProducer/Strangeness/lambdakzeropid.cxx +++ /dev/null @@ -1,657 +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. -// -// *+-+*+-+*+-+*+-+*+-+*+-+* -// Lambdakzero PID -// *+-+*+-+*+-+*+-+*+-+*+-+* -// -/// \author Nicolò Jacazio -/// \author David Dobrigkeit Chinellato -/// \since 11/05/2023 -/// \brief Table producer for V0 daughter PID info -// -// This task produces daughter PID information for strange daughters -// taking into account the (candidate-by-candidate) time spent as a heavier -// (strange, weakly-decaying) particle. This task is meant to be a test, as -// it hasn't been fully tested yet! Use at your own peril for now :-) - -#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 "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 "CommonConstants/PhysicsConstants.h" -#include "Common/TableProducer/PID/pidTOFBase.h" -#include "Common/DataModel/PIDResponse.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using std::array; - -// For original data loops -using V0OriginalDatas = soa::Join; -using TracksWithAllExtras = soa::Join; - -// For derived data analysis -using dauTracks = soa::Join; -using V0DerivedDatas = soa::Join; - -struct lambdakzeropid { - // TOF pid for strangeness (recalculated with topology) - Produces v0tofpid; // table with Nsigmas - Produces v0tofbeta; // table with betas - Produces v0tofdebugs; // table with extra debug information - Produces v0tofnsigmas; // table with nsigmas - - 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; - ; - Preslice perCollisionDerived = o2::aod::v0data::straCollisionId; - - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - // Operation and minimisation criteria - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable tofPosition{"tofPosition", 377.934f, "TOF effective (inscribed) radius"}; - Configurable doQA{"doQA", true, "create QA histos"}; - Configurable doQANSigma{"doQANSigma", true, "create QA of Nsigma histos"}; - Configurable qaDCADau{"qaDCADau", 0.5, "DCA daughters (cm) for QA plots"}; - Configurable qaCosPA{"qaCosPA", 0.999, "CosPA for QA plots"}; - Configurable qaMassWindow{"qaMassWindow", 0.005, "Mass window around expected (in GeV/c2) for QA plots"}; - Configurable qaTPCNSigma{"qaTPCNSigma", 5, "TPC N-sigma to apply for qa plots"}; - Configurable doNSigmas{"doNSigmas", false, "calculate TOF N-sigma"}; - - // 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 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 manualRunNumber{"manualRunNumber", 544122, "manual run number if no collisions saved"}; - Configurable manualTimeStamp{"manualTimeStamp", 1696549226920, "manual time stamp 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 axisTime{"axisTime", {200, 0.0f, +20000.0f}, "T (ps)"}; - ConfigurableAxis axisNSigma{"axisNSigma", {200, -10.0f, +10.0f}, "N(#sigma)"}; - 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)"}; - - // for n-sigma calibration - bool nSigmaCalibLoaded; - TList* nSigmaCalibObjects; - TH1 *hMeanPosLaPi, *hSigmaPosLaPi; - TH1 *hMeanPosLaPr, *hSigmaPosLaPr; - TH1 *hMeanNegLaPi, *hSigmaNegLaPi; - TH1 *hMeanNegLaPr, *hSigmaNegLaPr; - TH1 *hMeanPosK0Pi, *hSigmaPosK0Pi; - TH1 *hMeanNegK0Pi, *hSigmaNegK0Pi; - - int mRunNumber; - float d_bz; - float maxSnp; // max sine phi for propagation - float maxStep; // max step size (cm) for propagation - - // enum to keep track of the TOF-related properties for V0s - enum tofEnum { kLength = 0, - kHasTOF, - kNEnums }; - - /// function to calculate track length of this track up to a certain segment of a detector - /// to be used internally in another funcrtion that calculates length until it finds the proper one - /// warning: this could be optimised further for speed - /// \param track the input track - /// \param x1 x of the first point of the detector segment - /// \param y1 y of the first point of the detector segment - /// \param x2 x of the first point of the detector segment - /// \param y2 y of the first point of the detector segment - /// \param magneticField the magnetic field to use when propagating - float trackLengthToSegment(o2::track::TrackPar track, float x1, float y1, float x2, float y2, float magneticField) - { - // don't make use of the track parametrization - float length = -104; - - // causality protection - std::array mom; - track.getPxPyPzGlo(mom); - // get start point - std::array startPoint; - track.getXYZGlo(startPoint); - - // better replaced with scalar momentum check later - // if (((x1 + x2) * mom[0] + (y1 + y2) * mom[1]) < 0.0f) - // return -101; - - // get circle X, Y please - o2::math_utils::CircleXYf_t trcCircle; - float sna, csa; - track.getCircleParams(magneticField, trcCircle, sna, csa); - - // Calculate necessary inner product - float segmentModulus = std::hypot(x2 - x1, y2 - y1); - float alongSegment = ((trcCircle.xC - x1) * (x2 - x1) + (trcCircle.yC - y1) * (y2 - y1)) / segmentModulus; - - // find point of closest approach between segment and circle center - float pcaX = (x2 - x1) * alongSegment / segmentModulus + x1; - float pcaY = (y2 - y1) * alongSegment / segmentModulus + y1; - - float centerDistToPC = std::hypot(pcaX - trcCircle.xC, pcaY - trcCircle.yC); - - // distance pca-to-intercept in multiples of segment modulus (for convenience) - if (centerDistToPC > trcCircle.rC) - return -103; - - float pcaToIntercept = TMath::Sqrt(TMath::Abs(trcCircle.rC * trcCircle.rC - centerDistToPC * centerDistToPC)); - - float interceptX1 = pcaX + (x2 - x1) / segmentModulus * pcaToIntercept; - float interceptY1 = pcaY + (y2 - y1) / segmentModulus * pcaToIntercept; - float interceptX2 = pcaX - (x2 - x1) / segmentModulus * pcaToIntercept; - float interceptY2 = pcaY - (y2 - y1) / segmentModulus * pcaToIntercept; - - float scalarCheck1 = ((x2 - x1) * (interceptX1 - x1) + (y2 - y1) * (interceptY1 - y1)) / segmentModulus; - float scalarCheck2 = ((x2 - x1) * (interceptX2 - x1) + (y2 - y1) * (interceptY2 - y1)) / segmentModulus; - - float cosAngle1 = -1000, sinAngle1 = -1000, modulus1 = -1000; - float cosAngle2 = -1000, sinAngle2 = -1000, modulus2 = -1000; - float length1 = -1000, length2 = -1000; - - modulus1 = std::hypot(interceptX1 - trcCircle.xC, interceptY1 - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); - cosAngle1 = (interceptX1 - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (interceptY1 - trcCircle.yC) * (startPoint[1] - trcCircle.yC); - sinAngle1 = (interceptX1 - trcCircle.xC) * (startPoint[1] - trcCircle.yC) - (interceptY1 - trcCircle.yC) * (startPoint[0] - trcCircle.xC); - cosAngle1 /= modulus1; - sinAngle1 /= modulus1; - length1 = trcCircle.rC * TMath::ACos(cosAngle1); - length1 *= sqrt(1.0f + track.getTgl() * track.getTgl()); - - modulus2 = std::hypot(interceptX2 - trcCircle.xC, interceptY2 - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); - cosAngle2 = (interceptX2 - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (interceptY2 - trcCircle.yC) * (startPoint[1] - trcCircle.yC); - sinAngle2 = (interceptX2 - trcCircle.xC) * (startPoint[1] - trcCircle.yC) - (interceptY2 - trcCircle.yC) * (startPoint[0] - trcCircle.xC); - cosAngle2 /= modulus2; - sinAngle2 /= modulus2; - length2 = trcCircle.rC * TMath::ACos(cosAngle2); - length2 *= sqrt(1.0f + track.getTgl() * track.getTgl()); - - // rotate transverse momentum vector such that it is at intercepts - float angle1 = TMath::ACos(cosAngle1); - if (sinAngle1 < 0) - angle1 *= -1.0f; - float px1 = +TMath::Cos(angle1) * mom[0] + TMath::Sin(angle1) * mom[1]; - float py1 = -TMath::Sin(angle1) * mom[0] + TMath::Cos(angle1) * mom[1]; - - float angle2 = TMath::ACos(cosAngle2); - if (sinAngle2 < 0) - angle2 *= -1.0f; - float px2 = +TMath::Cos(angle2) * mom[0] + TMath::Sin(angle2) * mom[1]; - float py2 = -TMath::Sin(angle2) * mom[0] + TMath::Cos(angle2) * mom[1]; - - float midSegX = 0.5f * (x2 + x1); - float midSegY = 0.5f * (y2 + y1); - - float scalarMomentumCheck1 = px1 * midSegX + py1 * midSegY; - float scalarMomentumCheck2 = px2 * midSegX + py2 * midSegY; - - if (scalarCheck1 > 0.0f && scalarCheck1 < segmentModulus && scalarMomentumCheck1 > 0.0f) { - length = length1; - // X = interceptX1; Y = interceptY1; - } - if (scalarCheck2 > 0.0f && scalarCheck2 < segmentModulus && scalarMomentumCheck2 > 0.0f) { - length = length2; - // X = interceptX2; Y = interceptY2; - } - return length; - } - - /// function to calculate track length of this track up to a certain segmented detector - /// \param track the input track - /// \param magneticField the magnetic field to use when propagating - float findInterceptLength(o2::track::TrackPar track, float magneticField) - { - float length = 1e+6; - for (int iSeg = 0; iSeg < 18; iSeg++) { - // Detector segmentation loop - float segmentAngle = 20.0f / 180.0f * TMath::Pi(); - float theta = static_cast(iSeg) * 20.0f / 180.0f * TMath::Pi(); - float halfWidth = tofPosition * TMath::Tan(0.5f * segmentAngle); - float x1 = TMath::Cos(theta) * (-halfWidth) + TMath::Sin(theta) * tofPosition; - float y1 = -TMath::Sin(theta) * (-halfWidth) + TMath::Cos(theta) * tofPosition; - float x2 = TMath::Cos(theta) * (+halfWidth) + TMath::Sin(theta) * tofPosition; - float y2 = -TMath::Sin(theta) * (+halfWidth) + TMath::Cos(theta) * tofPosition; - float thisLength = trackLengthToSegment(track, x1, y1, x2, y2, magneticField); - if (thisLength < length && thisLength > 0) - length = thisLength; - } - if (length > 1e+5) - length = -100; // force negative to avoid misunderstandings - return length; - } - - void init(InitContext&) - { - nSigmaCalibLoaded = false; - nSigmaCalibObjects = nullptr; - - // for n-sigma calibration - hMeanPosLaPi = nullptr; - hSigmaPosLaPi = nullptr; - hMeanPosLaPr = nullptr; - hSigmaPosLaPr = nullptr; - hMeanNegLaPi = nullptr; - hSigmaNegLaPi = nullptr; - hMeanNegLaPr = nullptr; - hSigmaNegLaPr = nullptr; - hMeanPosK0Pi = nullptr; - hSigmaNegK0Pi = nullptr; - hMeanNegK0Pi = nullptr; - hSigmaNegK0Pi = nullptr; - - 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); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - // per event - histos.add("hCandidateCounter", "hCandidateCounter", kTH1F, {{500, -0.5f, 499.5f}}); - - // measured vs expected total time QA - if (doQA) { - histos.add("h2dProtonMeasuredVsExpected", "h2dProtonMeasuredVsExpected", {HistType::kTH2F, {axisTime, axisTime}}); - histos.add("h2dPionMeasuredVsExpected", "h2dPionMeasuredVsExpected", {HistType::kTH2F, {axisTime, axisTime}}); - - // standard deltaTime values - histos.add("h2dDeltaTimePositiveLambdaPi", "h2dDeltaTimePositiveLambdaPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dDeltaTimeNegativeLambdaPi", "h2dDeltaTimeNegativeLambdaPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dDeltaTimePositiveLambdaPr", "h2dDeltaTimePositiveLambdaPr", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dDeltaTimeNegativeLambdaPr", "h2dDeltaTimeNegativeLambdaPr", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dDeltaTimePositiveK0ShortPi", "h2dDeltaTimePositiveK0ShortPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - histos.add("h2dDeltaTimeNegativeK0ShortPi", "h2dDeltaTimeNegativeK0ShortPi", {HistType::kTH3F, {axisPt, axisEta, axisDeltaTime}}); - - histos.add("h2dPositiveTOFProperties", "h2dPositiveTOFProperties", {HistType::kTH2F, {axisPt, {4, -0.5, 3.5f}}}); - histos.add("h2dNegativeTOFProperties", "h2dNegativeTOFProperties", {HistType::kTH2F, {axisPt, {4, -0.5, 3.5f}}}); - - if (doQANSigma) { - // standard NSigma values - histos.add("h2dNSigmaPositiveLambdaPi", "h2dNSigmaPositiveLambdaPi", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaNegativeLambdaPi", "h2dNSigmaNegativeLambdaPi", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaPositiveLambdaPr", "h2dNSigmaPositiveLambdaPr", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaNegativeLambdaPr", "h2dNSigmaNegativeLambdaPr", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaPositiveK0ShortPi", "h2dNSigmaPositiveK0ShortPi", {HistType::kTH2F, {axisPt, axisNSigma}}); - histos.add("h2dNSigmaNegativeK0ShortPi", "h2dNSigmaNegativeK0ShortPi", {HistType::kTH2F, {axisPt, axisNSigma}}); - } - - // delta lambda decay time - histos.add("h2dLambdaDeltaDecayTime", "h2dLambdaDeltaDecayTime", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - } - } - - void initCCDB(int runNumber, uint64_t timeStamp) - { - if (mRunNumber == 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); - mVtx = ccdb->getForTimeStamp(mVtxPath, timeStamp); - mRunNumber = runNumber; - return; - } - - auto run3grp_timestamp = 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); - mVtx = ccdb->getForTimeStamp(mVtxPath, timeStamp); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } - - // if TOF Nsigma desired - if (doNSigmas) { - nSigmaCalibObjects = ccdb->getForTimeStamp(nSigmaPath, timeStamp); - if (nSigmaCalibObjects) { - LOGF(info, "loaded TList with this many objects: %i", nSigmaCalibObjects->GetEntries()); - - hMeanPosLaPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosLaPi")); - hMeanPosLaPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosLaPr")); - hMeanNegLaPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegLaPi")); - hMeanNegLaPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegLaPr")); - hMeanPosK0Pi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosK0Pi")); - hMeanNegK0Pi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegK0Pi")); - - hSigmaPosLaPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosLaPi")); - hSigmaPosLaPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosLaPr")); - hSigmaNegLaPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegLaPi")); - hSigmaNegLaPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegLaPr")); - hSigmaPosK0Pi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosK0Pi")); - hSigmaNegK0Pi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegK0Pi")); - - if (!hMeanPosLaPi) - LOG(info) << "Problems finding mean histogram hMeanPosLaPi!"; - if (!hMeanPosLaPr) - LOG(info) << "Problems finding mean histogram hMeanPosLaPr!"; - if (!hMeanNegLaPi) - LOG(info) << "Problems finding mean histogram hMeanNegLaPi!"; - if (!hMeanNegLaPr) - LOG(info) << "Problems finding mean histogram hMeanNegLaPr!"; - if (!hMeanPosK0Pi) - LOG(info) << "Problems finding mean histogram hMeanPosK0Pi!"; - if (!hMeanNegK0Pi) - LOG(info) << "Problems finding mean histogram hMeanNegK0Pi!"; - if (!hSigmaPosK0Pi || !hSigmaNegK0Pi || !hSigmaPosLaPi || !hSigmaPosLaPr || !hSigmaNegLaPi || !hSigmaNegLaPr) { - LOG(info) << "Problems finding sigma histograms!"; - } - } - } - mRunNumber = runNumber; - } - - float velocity(float lMomentum, float lMass) - { - // Momentum p and mass m -> returns speed in centimeters per picosecond - // Useful for TOF calculations - float lA = (lMomentum / lMass) * (lMomentum / lMass); - return 0.0299792458 * TMath::Sqrt(lA / (1 + lA)); - } - - // templatized process function for symmetric operation in derived and original AO2D - template - 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.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 - float timeLambda = lengthV0 / velocityLambda; // in picoseconds - - // initialize from V0 position and momenta - o2::track::TrackPar posTrack = o2::track::TrackPar({v0.x(), v0.y(), v0.z()}, {v0.pxpos(), v0.pypos(), v0.pzpos()}, +1); - o2::track::TrackPar negTrack = o2::track::TrackPar({v0.x(), v0.y(), v0.z()}, {v0.pxneg(), v0.pyneg(), v0.pzneg()}, -1); - - float deltaTimePositiveLambdaPi = -1e+6; - float deltaTimeNegativeLambdaPi = -1e+6; - float deltaTimePositiveLambdaPr = -1e+6; - float deltaTimeNegativeLambdaPr = -1e+6; - float deltaTimePositiveK0ShortPi = -1e+6; - float deltaTimeNegativeK0ShortPi = -1e+6; - - float nSigmaPositiveLambdaPi = -1e+3; - float nSigmaPositiveLambdaPr = -1e+3; - float nSigmaNegativeLambdaPi = -1e+3; - float nSigmaNegativeLambdaPr = -1e+3; - float nSigmaPositiveK0ShortPi = -1e+3; - float nSigmaNegativeK0ShortPi = -1e+3; - - float velocityPositivePr = velocity(posTrack.getP(), o2::constants::physics::MassProton); - float velocityPositivePi = velocity(posTrack.getP(), o2::constants::physics::MassPionCharged); - float velocityNegativePr = velocity(negTrack.getP(), o2::constants::physics::MassProton); - float velocityNegativePi = velocity(negTrack.getP(), o2::constants::physics::MassPionCharged); - - float lengthPositive = findInterceptLength(posTrack, d_bz); // FIXME: tofPosition ok? adjust? - float lengthNegative = findInterceptLength(negTrack, d_bz); // FIXME: tofPosition ok? adjust? - float timePositivePr = lengthPositive / velocityPositivePr; - float timePositivePi = lengthPositive / velocityPositivePi; - float timeNegativePr = lengthNegative / velocityNegativePr; - float timeNegativePi = lengthNegative / velocityNegativePi; - - if (pTra.hasTOF() && lengthPositive > 0) { - deltaTimePositiveLambdaPr = (pTra.tofSignal() - pTra.tofEvTime()) - (timeLambda + timePositivePr); - deltaTimePositiveLambdaPi = (pTra.tofSignal() - pTra.tofEvTime()) - (timeLambda + timePositivePi); - deltaTimePositiveK0ShortPi = (pTra.tofSignal() - pTra.tofEvTime()) - (timeK0Short + timePositivePi); - } - if (nTra.hasTOF() && lengthNegative > 0) { - deltaTimeNegativeLambdaPr = (nTra.tofSignal() - nTra.tofEvTime()) - (timeLambda + timeNegativePr); - deltaTimeNegativeLambdaPi = (nTra.tofSignal() - nTra.tofEvTime()) - (timeLambda + timeNegativePi); - deltaTimeNegativeK0ShortPi = (nTra.tofSignal() - nTra.tofEvTime()) - (timeK0Short + timeNegativePi); - } - - if (doQA) { - // calculate and pack properties for QA purposes - int posProperties = 0; - if (lengthPositive > 0) - posProperties = posProperties | (static_cast(1) << kLength); - if (pTra.hasTOF()) - posProperties = posProperties | (static_cast(1) << kHasTOF); - int negProperties = 0; - if (lengthNegative > 0) - negProperties = negProperties | (static_cast(1) << kLength); - if (nTra.hasTOF()) - negProperties = negProperties | (static_cast(1) << kHasTOF); - - histos.fill(HIST("h2dPositiveTOFProperties"), v0.pt(), posProperties); - histos.fill(HIST("h2dNegativeTOFProperties"), v0.pt(), negProperties); - } - - float deltaDecayTimeLambda = -10e+4; - float deltaDecayTimeAntiLambda = -10e+4; - float deltaDecayTimeK0Short = -10e+4; - if (nTra.hasTOF() && pTra.hasTOF() > 0 && lengthPositive > 0 && lengthNegative > 0) { // does not depend on event time - deltaDecayTimeLambda = (pTra.tofSignal() - timePositivePr) - (nTra.tofSignal() - timeNegativePi); - deltaDecayTimeAntiLambda = (pTra.tofSignal() - timePositivePi) - (nTra.tofSignal() - timeNegativePr); - deltaDecayTimeK0Short = (pTra.tofSignal() - timePositivePi) - (nTra.tofSignal() - timeNegativePi); - } - - // calculate betas - - float evTimeMean = 0.5f * (pTra.tofEvTime() + nTra.tofEvTime()); - float decayTimeLambda = 0.5f * ((pTra.tofSignal() - timePositivePr) + (nTra.tofSignal() - timeNegativePi)) - evTimeMean; - float decayTimeAntiLambda = 0.5f * ((pTra.tofSignal() - timePositivePi) + (nTra.tofSignal() - timeNegativePr)) - evTimeMean; - float decayTimeK0Short = 0.5f * ((pTra.tofSignal() - timePositivePi) + (nTra.tofSignal() - timeNegativePi)) - evTimeMean; - - float betaLambda = -1e+6; - float betaAntiLambda = -1e+6; - float betaK0Short = -1e+6; - - if (nTra.hasTOF() && pTra.hasTOF()) { - betaLambda = (lengthV0 / decayTimeLambda) / 0.0299792458; - betaAntiLambda = (lengthV0 / decayTimeAntiLambda) / 0.0299792458; - betaK0Short = (lengthV0 / decayTimeK0Short) / 0.0299792458; - } - - v0tofpid(deltaTimePositiveLambdaPi, deltaTimePositiveLambdaPr, - deltaTimeNegativeLambdaPi, deltaTimeNegativeLambdaPr, - deltaTimePositiveK0ShortPi, deltaTimeNegativeK0ShortPi, - deltaDecayTimeLambda, deltaDecayTimeAntiLambda, deltaDecayTimeK0Short); - v0tofbeta(betaLambda, betaAntiLambda, betaK0Short); - v0tofdebugs(timeLambda, timeK0Short, timePositivePr, timePositivePi, timeNegativePr, timeNegativePi); - - // do Nsigmas if requested - if (doNSigmas) { - // sweep through all viable hypotheses and produce N-sigma - - if (deltaTimePositiveLambdaPi > -1e+5) - nSigmaPositiveLambdaPi = (deltaTimePositiveLambdaPi - hMeanPosLaPi->Interpolate(v0.pt())) / hSigmaPosLaPi->Interpolate(v0.pt()); - if (deltaTimePositiveLambdaPr > -1e+5) - nSigmaPositiveLambdaPr = (deltaTimePositiveLambdaPr - hMeanPosLaPr->Interpolate(v0.pt())) / hSigmaPosLaPr->Interpolate(v0.pt()); - if (deltaTimeNegativeLambdaPi > -1e+5) - nSigmaNegativeLambdaPi = (deltaTimeNegativeLambdaPi - hMeanNegLaPi->Interpolate(v0.pt())) / hSigmaNegLaPi->Interpolate(v0.pt()); - if (deltaTimeNegativeLambdaPr > -1e+5) - nSigmaNegativeLambdaPr = (deltaTimeNegativeLambdaPr - hMeanNegLaPr->Interpolate(v0.pt())) / hSigmaNegLaPr->Interpolate(v0.pt()); - if (deltaTimePositiveK0ShortPi > -1e+5) - nSigmaPositiveK0ShortPi = (deltaTimePositiveK0ShortPi - hMeanPosK0Pi->Interpolate(v0.pt())) / hSigmaPosK0Pi->Interpolate(v0.pt()); - if (deltaTimeNegativeK0ShortPi > -1e+5) - nSigmaNegativeK0ShortPi = (deltaTimeNegativeK0ShortPi - hMeanNegK0Pi->Interpolate(v0.pt())) / hSigmaNegK0Pi->Interpolate(v0.pt()); - - v0tofnsigmas( - nSigmaPositiveLambdaPr, nSigmaNegativeLambdaPi, - nSigmaNegativeLambdaPr, nSigmaPositiveLambdaPi, - nSigmaPositiveK0ShortPi, nSigmaNegativeK0ShortPi); - } - - if (doQA) { - if (pTra.hasTOF()) { - histos.fill(HIST("h2dProtonMeasuredVsExpected"), - (timeLambda + timePositivePr), - (pTra.tofSignal() - pTra.tofEvTime())); - if (v0.v0cosPA() > qaCosPA && v0.dcaV0daughters() < qaDCADau) { - if (std::abs(v0.mLambda() - 1.115683) < qaMassWindow && fabs(pTra.tpcNSigmaPr()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPi()) < qaTPCNSigma) { - histos.fill(HIST("h2dDeltaTimePositiveLambdaPr"), v0.pt(), v0.eta(), deltaTimePositiveLambdaPr); - if (doQANSigma) - histos.fill(HIST("h2dNSigmaPositiveLambdaPr"), v0.pt(), nSigmaPositiveLambdaPr); - } - if (std::abs(v0.mAntiLambda() - 1.115683) < qaMassWindow && fabs(pTra.tpcNSigmaPi()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPr()) < qaTPCNSigma) { - histos.fill(HIST("h2dDeltaTimePositiveLambdaPi"), v0.pt(), v0.eta(), deltaTimePositiveLambdaPi); - if (doQANSigma) - histos.fill(HIST("h2dNSigmaPositiveLambdaPi"), v0.pt(), nSigmaPositiveLambdaPi); - } - if (std::abs(v0.mK0Short() - 0.497) < qaMassWindow && fabs(pTra.tpcNSigmaPi()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPi()) < qaTPCNSigma) { - histos.fill(HIST("h2dDeltaTimePositiveK0ShortPi"), v0.pt(), v0.eta(), deltaTimePositiveK0ShortPi); - if (doQANSigma) - histos.fill(HIST("h2dNSigmaPositiveK0ShortPi"), v0.pt(), nSigmaPositiveK0ShortPi); - } - } - } - - if (nTra.hasTOF()) { - histos.fill(HIST("h2dPionMeasuredVsExpected"), - (timeLambda + timeNegativePi), - (nTra.tofSignal() - nTra.tofEvTime())); - if (v0.v0cosPA() > qaCosPA && v0.dcaV0daughters() < qaDCADau) { - if (std::abs(v0.mLambda() - 1.115683) < qaMassWindow && fabs(pTra.tpcNSigmaPr()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPi()) < qaTPCNSigma) { - histos.fill(HIST("h2dDeltaTimeNegativeLambdaPi"), v0.pt(), v0.eta(), deltaTimeNegativeLambdaPi); - if (doQANSigma) - histos.fill(HIST("h2dNSigmaNegativeLambdaPi"), v0.pt(), nSigmaNegativeLambdaPi); - } - if (std::abs(v0.mAntiLambda() - 1.115683) < qaMassWindow && fabs(pTra.tpcNSigmaPi()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPr()) < qaTPCNSigma) { - histos.fill(HIST("h2dDeltaTimeNegativeLambdaPr"), v0.pt(), v0.eta(), deltaTimeNegativeLambdaPr); - if (doQANSigma) - histos.fill(HIST("h2dNSigmaNegativeLambdaPr"), v0.pt(), nSigmaNegativeLambdaPr); - } - if (std::abs(v0.mK0Short() - 0.497) < qaMassWindow && fabs(pTra.tpcNSigmaPi()) < qaTPCNSigma && fabs(nTra.tpcNSigmaPi()) < qaTPCNSigma) { - histos.fill(HIST("h2dDeltaTimeNegativeK0ShortPi"), v0.pt(), v0.eta(), deltaTimeNegativeK0ShortPi); - if (doQANSigma) - histos.fill(HIST("h2dNSigmaNegativeK0ShortPi"), v0.pt(), nSigmaNegativeK0ShortPi); - } - } - } - // delta lambda decay time - histos.fill(HIST("h2dLambdaDeltaDecayTime"), v0.pt(), deltaDecayTimeLambda); - } - } - - void processStandardData(aod::Collisions const& collisions, V0OriginalDatas const& V0s, TracksWithAllExtras const&, aod::BCsWithTimestamps const& /*bcs*/) - { - // Fire up CCDB with first collision in record. If no collisions, bypass - if (collisions.size() > 0) { - auto collision = collisions.begin(); - auto bc = collision.bc_as(); - initCCDB(bc.runNumber(), bc.timestamp()); - } else { - initCCDB(manualRunNumber, manualTimeStamp); - } - - 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&) - { - // Fire up CCDB with first collision in record. If no collisions, bypass - if (collisions.size() > 0) { - auto collision = collisions.begin(); - initCCDB(collision.runNumber(), collision.timestamp()); - } else { - initCCDB(manualRunNumber, manualTimeStamp); - } - - 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); - } - } - - PROCESS_SWITCH(lambdakzeropid, processStandardData, "Process standard data", true); - PROCESS_SWITCH(lambdakzeropid, processDerivedData, "Process derived data", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/Strangeness/lambdakzerospawner.cxx b/PWGLF/TableProducer/Strangeness/lambdakzerospawner.cxx index 7ec0b4cc010..19c174aef7f 100644 --- a/PWGLF/TableProducer/Strangeness/lambdakzerospawner.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdakzerospawner.cxx @@ -35,7 +35,7 @@ using namespace o2::framework::expressions; // Extends the v0data table with expression columns struct lambdakzerospawner { - Spawns v0cores; + // Spawns v0cores; void init(InitContext const&) {} }; diff --git a/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx b/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx new file mode 100644 index 00000000000..103f515ce4c --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx @@ -0,0 +1,456 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 +/// \author sourav.kundu@cern.ch + +#include "PWGLF/DataModel/LFSpincorrelationTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector2D.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" + +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using namespace o2::aod::rctsel; + +struct lambdaspincorrelation { + + Produces lambdaEvent; + Produces lambdaPair; + Produces lambdaEventmc; + Produces lambdaPairmc; + + Service ccdb; + + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + Configurable useNoCollInTimeRangeStandard{"useNoCollInTimeRangeStandard", false, "Apply kNoCollInTimeRangeStandard selection bit"}; + Configurable useGoodITSLayersAll{"useGoodITSLayersAll", true, "Apply kIsGoodITSLayersAll selection bit"}; + // mixing + // Produce derived tables + Configurable cfgCutOccupancy{"cfgCutOccupancy", 2000, "Occupancy cut"}; + ConfigurableAxis axisVertex{"axisVertex", {5, -10, 10}, "vertex axis for bin"}; + ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {8, 0, 80}, "multiplicity percentile for bin"}; + + // events + Configurable cfgEventTypepp{"cfgEventTypepp", false, "Type of collisions"}; + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 80.0f, "Accepted maximum Centrality"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 0.0f, "Accepted minimum Centrality"}; + + // Configs for track + Configurable cfgCutPt{"cfgCutPt", 0.2, "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 confV0PtMax{"confV0PtMax", 1000.f, "Maximum transverse momentum of V0"}; + Configurable confV0Rap{"confV0Rap", 0.8f, "Rapidity range of V0"}; + Configurable confV0DCADaughMax{"confV0DCADaughMax", 1.0f, "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", 50, "Maximum V0 life time"}; + + // config for V0 daughters + Configurable confDaughEta{"confDaughEta", 0.8f, "V0 Daugh sel: max eta"}; + Configurable cfgDaughPrPt{"cfgDaughPrPt", 0.2, "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 iMNbins{"iMNbins", 50, "Number of bins in invariant mass"}; + Configurable lbinIM{"lbinIM", 1.09, "lower bin value in IM histograms"}; + Configurable hbinIM{"hbinIM", 1.14, "higher bin value in IM histograms"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + RCTFlagsChecker rctChecker; + void init(o2::framework::InitContext&) + { + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + AxisSpec thnAxisInvMass{iMNbins, lbinIM, hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{5, 0, 5.0}}); + histos.add("hLambdaMass", "hLambdaMass", kTH1F, {thnAxisInvMass}); + histos.add("hV0Info", "hV0Info", kTH1F, {{5, 0, 5.0}}); + } + + 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 (pT > confV0PtMax) { + 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; + } + + 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) && v0.mLambda() > lbinIM && v0.mLambda() < hbinIM) { + lambdaTag = 1; + } + if (isSelectedV0Daughter(v0, negtrack, 0) && isSelectedV0Daughter(v0, postrack, 1) && v0.mAntiLambda() > lbinIM && v0.mAntiLambda() < hbinIM) { + aLambdaTag = 1; + } + + if (!lambdaTag && !aLambdaTag) { + return {0, 0, false}; // No valid tags + } + + if (!selectionV0(collision, v0)) { + return {0, 0, false}; // Fails selection + } + + return {lambdaTag, aLambdaTag, true}; // Valid candidate + } + + ROOT::Math::PxPyPzMVector lambda, antiLambda, proton, pion, antiProton, antiPion; + ROOT::Math::PxPyPzMVector lambdaDummy, pionDummy, protonDummy; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter centralityFilter = (nabs(aod::cent::centFT0C) < cfgCutCentralityMax && nabs(aod::cent::centFT0C) > cfgCutCentralityMin); + + using EventCandidates = soa::Filtered>; + using AllTrackCandidates = soa::Join; + using ResoV0s = aod::V0Datas; + + void processData(EventCandidates::iterator const& collision, AllTrackCandidates const&, ResoV0s const& V0s) + { + std::vector lambdaMother, protonDaughter, pionDaughter; + std::vector v0Status = {}; + std::vector doubleStatus = {}; + std::vector v0Cospa = {}; + std::vector v0Radius = {}; + std::vector dcaPositive = {}; + std::vector dcaNegative = {}; + std::vector positiveIndex = {}; + std::vector negativeIndex = {}; + std::vector dcaBetweenDaughter = {}; + int numbV0 = 0; + // LOGF(info, "event collisions: (%d)", collision.index()); + auto centrality = collision.centFT0C(); + if (cfgEventTypepp) + centrality = collision.centFT0M(); + auto vz = collision.posZ(); + int occupancy = collision.trackOccupancyInTimeRange(); + histos.fill(HIST("hEvtSelInfo"), 0.5); + // if ((!rctCut.requireRCTFlagChecker || rctChecker(collision)) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) && collision.sel8() && collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) && occupancy < cfgCutOccupancy) { + if ((!rctCut.requireRCTFlagChecker || rctChecker(collision)) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && (!useNoCollInTimeRangeStandard || collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) && collision.sel8() && (!useGoodITSLayersAll || collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) && occupancy < cfgCutOccupancy) { + histos.fill(HIST("hEvtSelInfo"), 1.5); + for (const auto& v0 : V0s) { + // LOGF(info, "v0 index 0 : (%d)", v0.index()); + auto [lambdaTag, aLambdaTag, isValid] = getLambdaTags(v0, collision); + if (isValid) { + // LOGF(info, "v0 index 1 : (%d)", v0.index()); + if (lambdaTag) { + histos.fill(HIST("hV0Info"), 0.5); + } + if (aLambdaTag) { + histos.fill(HIST("hV0Info"), 1.5); + } + if (lambdaTag && aLambdaTag) { + doubleStatus.push_back(true); + if (std::abs(v0.mLambda() - 1.1154) < std::abs(v0.mAntiLambda() - 1.1154)) { + lambdaTag = true; + aLambdaTag = false; + } else { + lambdaTag = false; + aLambdaTag = true; + } + } else { + doubleStatus.push_back(false); + } + if (lambdaTag) { + histos.fill(HIST("hV0Info"), 2.5); + } + if (aLambdaTag) { + histos.fill(HIST("hV0Info"), 3.5); + } + // LOGF(info, "v0 index2: (%d)", v0.index()); + auto postrack1 = v0.template posTrack_as(); + auto negtrack1 = v0.template negTrack_as(); + positiveIndex.push_back(postrack1.globalIndex()); + negativeIndex.push_back(negtrack1.globalIndex()); + v0Cospa.push_back(v0.v0cosPA()); + v0Radius.push_back(v0.v0radius()); + dcaPositive.push_back(std::abs(v0.dcapostopv())); + dcaNegative.push_back(std::abs(v0.dcanegtopv())); + dcaBetweenDaughter.push_back(std::abs(v0.dcaV0daughters())); + if (lambdaTag) { + v0Status.push_back(0); + 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); + lambda = proton + antiPion; + lambdaMother.push_back(lambda); + protonDaughter.push_back(proton); + pionDaughter.push_back(antiPion); + histos.fill(HIST("hLambdaMass"), lambda.M()); + } else if (aLambdaTag) { + v0Status.push_back(1); + 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); + antiLambda = antiProton + pion; + lambdaMother.push_back(antiLambda); + protonDaughter.push_back(antiProton); + pionDaughter.push_back(pion); + histos.fill(HIST("hLambdaMass"), lambda.M()); + } + numbV0 = numbV0 + 1; + } + } + if (numbV0 > 1 && v0Cospa.size() > 1) { + histos.fill(HIST("hEvtSelInfo"), 2.5); + lambdaEvent(centrality, vz); + auto indexEvent = lambdaEvent.lastIndex(); + //// Fill track table for V0////////////////// + for (auto if1 = lambdaMother.begin(); if1 != lambdaMother.end(); ++if1) { + auto i5 = std::distance(lambdaMother.begin(), if1); + lambdaDummy = lambdaMother.at(i5); + protonDummy = protonDaughter.at(i5); + pionDummy = pionDaughter.at(i5); + lambdaPair(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5)); + } + } + } + } + PROCESS_SWITCH(lambdaspincorrelation, processData, "Process data", false); + + void processMc(EventCandidates::iterator const& collision, AllTrackCandidates const&, ResoV0s const& V0s) + { + std::vector lambdaMother, protonDaughter, pionDaughter; + std::vector v0Status = {}; + std::vector doubleStatus = {}; + std::vector v0Cospa = {}; + std::vector v0Radius = {}; + std::vector dcaPositive = {}; + std::vector dcaNegative = {}; + std::vector positiveIndex = {}; + std::vector negativeIndex = {}; + std::vector dcaBetweenDaughter = {}; + int numbV0 = 0; + // LOGF(info, "event collisions: (%d)", collision.index()); + auto centrality = collision.centFT0C(); + if (cfgEventTypepp) + centrality = collision.centFT0M(); + auto vz = collision.posZ(); + int occupancy = collision.trackOccupancyInTimeRange(); + histos.fill(HIST("hEvtSelInfo"), 0.5); + if ((rctCut.requireRCTFlagChecker && rctChecker(collision)) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) && collision.sel8() && collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) && occupancy < cfgCutOccupancy) { + histos.fill(HIST("hEvtSelInfo"), 1.5); + for (const auto& v0 : V0s) { + // LOGF(info, "v0 index 0 : (%d)", v0.index()); + auto [lambdaTag, aLambdaTag, isValid] = getLambdaTags(v0, collision); + if (isValid) { + // LOGF(info, "v0 index 1 : (%d)", v0.index()); + if (lambdaTag) { + histos.fill(HIST("hV0Info"), 0.5); + } + if (aLambdaTag) { + histos.fill(HIST("hV0Info"), 1.5); + } + if (lambdaTag && aLambdaTag) { + doubleStatus.push_back(true); + if (std::abs(v0.mLambda() - 1.1154) < std::abs(v0.mAntiLambda() - 1.1154)) { + lambdaTag = true; + aLambdaTag = false; + } else { + lambdaTag = false; + aLambdaTag = true; + } + } else { + doubleStatus.push_back(false); + } + if (lambdaTag) { + histos.fill(HIST("hV0Info"), 2.5); + } + if (aLambdaTag) { + histos.fill(HIST("hV0Info"), 3.5); + } + // LOGF(info, "v0 index2: (%d)", v0.index()); + auto postrack1 = v0.template posTrack_as(); + auto negtrack1 = v0.template negTrack_as(); + positiveIndex.push_back(postrack1.globalIndex()); + negativeIndex.push_back(negtrack1.globalIndex()); + v0Cospa.push_back(v0.v0cosPA()); + v0Radius.push_back(v0.v0radius()); + dcaPositive.push_back(std::abs(v0.dcapostopv())); + dcaNegative.push_back(std::abs(v0.dcanegtopv())); + dcaBetweenDaughter.push_back(std::abs(v0.dcaV0daughters())); + if (lambdaTag) { + v0Status.push_back(0); + 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); + lambda = proton + antiPion; + lambdaMother.push_back(lambda); + protonDaughter.push_back(proton); + pionDaughter.push_back(antiPion); + histos.fill(HIST("hLambdaMass"), lambda.M()); + } else if (aLambdaTag) { + v0Status.push_back(1); + 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); + antiLambda = antiProton + pion; + lambdaMother.push_back(antiLambda); + protonDaughter.push_back(antiProton); + pionDaughter.push_back(pion); + histos.fill(HIST("hLambdaMass"), lambda.M()); + } + numbV0 = numbV0 + 1; + } + } + if (numbV0 > 1 && v0Cospa.size() > 1) { + histos.fill(HIST("hEvtSelInfo"), 2.5); + lambdaEventmc(centrality, vz); + auto indexEvent = lambdaEventmc.lastIndex(); + //// Fill track table for V0////////////////// + for (auto if1 = lambdaMother.begin(); if1 != lambdaMother.end(); ++if1) { + auto i5 = std::distance(lambdaMother.begin(), if1); + lambdaDummy = lambdaMother.at(i5); + protonDummy = protonDaughter.at(i5); + pionDummy = pionDaughter.at(i5); + lambdaPairmc(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5)); + } + } + } + } + PROCESS_SWITCH(lambdaspincorrelation, processMc, "Process montecarlo", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/lfinjets.cxx b/PWGLF/TableProducer/Strangeness/lfinjets.cxx new file mode 100644 index 00000000000..7b518ab2884 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/lfinjets.cxx @@ -0,0 +1,1884 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file lfinjets.cxx +/// +/// \brief task for analysis of strangeness in jets +/// \author Alberto Calivà (alberto.caliva@cern.ch) +/// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) +/// \author Nicolò Jacazio (nicolo.jacazio@cern.ch) +/// \author Sara Pucillo (sara.pucillo@cern.ch) +/// +/// \since May 22, 2024 + +#include "PWGLF/DataModel/LFInJets.h" + +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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::math; +using std::array; + +// Define convenient aliases for joined AOD tables +using SelCollisions = soa::Join; +using SimCollisions = soa::Join; +using DaughterTracks = soa::Join; +using DaughterTracksMC = soa::Join; + +struct LFInJets { + + Produces tableV0s; + Produces tableCascades; + + // Instantiate the CCDB service and API interface + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + // Instantiate the Zorro processor for skimmed data and define an output object + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // Define histogram registries + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Global analysis parameters + enum ParticleOfInterest { kV0Particles = 0, + kCascades, + kPions, + kKaons, + kProtons, + kParticles }; + Configurable> enabledSignals{"enabledSignals", {1, 0, 0, 0, 0}, "Enable particles"}; + Configurable minJetPt{"minJetPt", 10.0, "Minimum reconstructed pt of the jet (GeV/c)"}; + Configurable rJet{"rJet", 0.3, "Jet resolution parameter (R)"}; + Configurable zVtx{"zVtx", 10.0, "Maximum z-vertex position"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "eta gap from detector edge"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Enable processing of skimmed data"}; + Configurable triggerName{"triggerName", "fOmega", "Software trigger name"}; + + // Track analysis parameters + Configurable minITSnCls{"minITSnCls", 4, "Minimum number of ITS clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80, "Minimum number of TPC crossed rows"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "Maximum chi2 per cluster TPC"}; + Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; + Configurable etaMax{"etaMax", +0.8f, "Maximum eta"}; + Configurable ptMinV0Proton{"ptMinV0Proton", 0.3f, "Minimum pt of protons from V0"}; + Configurable ptMaxV0Proton{"ptMaxV0Proton", 10.0f, "Maximum pt of protons from V0"}; + Configurable ptMinV0Pion{"ptMinV0Pion", 0.1f, "Minimum pt of pions from V0"}; + Configurable ptMaxV0Pion{"ptMaxV0Pion", 1.5f, "Maximum pt of pions from V0"}; + Configurable ptMinK0Pion{"ptMinK0Pion", 0.3f, "Minimum pt of pions from K0"}; + Configurable ptMaxK0Pion{"ptMaxK0Pion", 10.0f, "Maximum pt of pions 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 requireITS{"requireITS", false, "Require ITS hit"}; + Configurable requireTOF{"requireTOF", false, "Require TOF hit"}; + + // V0 analysis parameters + Configurable minimumV0Radius{"minimumV0Radius", 0.5f, "Minimum V0 Radius"}; + Configurable maximumV0Radius{"maximumV0Radius", 40.0f, "Maximum V0 Radius"}; + Configurable dcanegtoPVmin{"dcanegtoPVmin", 0.1f, "Minimum DCA of negative track to primary vertex"}; + Configurable dcapostoPVmin{"dcapostoPVmin", 0.1f, "Minimum DCA of positive track to primary vertex"}; + Configurable v0cospaMin{"v0cospaMin", 0.99f, "Minimum V0 cosine of pointing angle"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum DCA between V0 daughters"}; + + // Cascade analysis parameters + Configurable minimumCascRadius{"minimumCascRadius", 0.1f, "Minimum cascade radius"}; + Configurable maximumCascRadius{"maximumCascRadius", 40.0f, "Maximum cascade radius"}; + Configurable casccospaMin{"casccospaMin", 0.99f, "Minimum cascade cosine of pointing angle"}; + Configurable dcabachtopvMin{"dcabachtopvMin", 0.1f, "Minimum DCA of bachelor to primary vertex"}; + Configurable dcaV0topvMin{"dcaV0topvMin", 0.1f, "Minimum DCA of V0 to primary vertex"}; + Configurable dcaCascDaughtersMax{"dcaCascDaughtersMax", 0.5f, "Maximum DCA between daughters"}; + Configurable deltaMassXi{"deltaMassXi", 0.02f, "Mass window for Xi rejection"}; + Configurable deltaMassOmega{"deltaMassOmega", 0.02f, "Mass window for Omega rejection"}; + Configurable deltaMassLambda{"deltaMassLambda", 0.02f, "Mass window for Lambda inclusion"}; + + struct : ConfigurableGroup { + ConfigurableAxis longLivedBinsNsigma{"longLivedBinsNsigma", {200, -10.f, 10.f}, "Binning of nSigma axis"}; + ConfigurableAxis longLivedBinsPt{"longLivedBinsPt", {VARIABLE_WIDTH, -5.0, -4.8, -4.6, -4.4, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1.0, -0.95, -0.9, -0.85, -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.18, -0.16, -0.14, -0.12, -0.1, 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 longLivedBinsDca{"longLivedBinsDca", {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"}; + } longLivedOptions; + + // Instantiate utility class for jet background subtraction + JetBkgSubUtils backgroundSub; + + // Initialize CCDB access and histogram registry for Zorro processing + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerName.value); + zorro.populateHistRegistry(registryData, bc.runNumber()); + } + } + + void init(InitContext const&) + { + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + int enabled = 0; + auto checkEnabled = [&](const ParticleOfInterest particle) { + LOG(info) << "Checking if " << particle << " are enabled"; + if (enabledSignals.value[particle]) { + LOG(info) << particle << " are enabled"; + return 1; + } + return 0; + }; + enabled += checkEnabled(ParticleOfInterest::kV0Particles); + enabled += checkEnabled(ParticleOfInterest::kCascades); + enabled += checkEnabled(ParticleOfInterest::kPions); + enabled += checkEnabled(ParticleOfInterest::kKaons); + enabled += checkEnabled(ParticleOfInterest::kProtons); + if (enabled == 0) { + LOG(fatal) << "At least one particle species must be enabled for the analysis. Please check the configuration of the task." << endl; + } + + // Define binning and axis specifications for multiplicity, eta, pT, PID, and invariant mass histograms + std::vector multBinning = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; + AxisSpec multAxis = {multBinning, "FT0C percentile"}; + const AxisSpec ptAxis{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}; + 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})"}; + const AxisSpec ptAxisLongLived{longLivedOptions.longLivedBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec nsigmaTOFAxis{longLivedOptions.longLivedBinsNsigma, "n#sigma_{TOF}"}; + const AxisSpec nsigmaTPCAxis{longLivedOptions.longLivedBinsNsigma, "n#sigma_{TPC}"}; + const AxisSpec dcaAxis{longLivedOptions.longLivedBinsDca, "DCA_{xy} (cm)"}; + + // Histograms for real data + if (doprocessData) { + + // Event counters + 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"}}); + + // Histograms for analysis of strange hadrons + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + 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}); + 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}); + } + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + 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}); + 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}); + } + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryData.add("Pion_in_jet", "Pion_in_jet", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Pion_in_ue", "Pion_in_ue", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryData.add("Kaon_in_jet", "Kaon_in_jet", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Kaon_in_ue", "Kaon_in_ue", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryData.add("Proton_in_jet", "Proton_in_jet", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Proton_in_ue", "Proton_in_ue", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + } + + // Histograms for mc generated + if (doprocessMCgenerated) { + + // Event counter + registryMC.add("number_of_events_mc_gen", "number of gen events in mc", HistType::kTH1D, {{10, 0, 10, "Event Cuts"}}); + registryMC.add("number_of_events_vsmultiplicity_gen", "number of events vs multiplicity", HistType::kTH1D, {{101, 0, 101, "Multiplicity percentile"}}); + + // Histograms for analysis + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + 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}); + } + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.add("XiPos_generated_jet", "XiPos_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiPos_generated_ue", "XiPos_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_generated_jet", "XiNeg_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_generated_ue", "XiNeg_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_generated_jet", "OmegaPos_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_generated_ue", "OmegaPos_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_generated_jet", "OmegaNeg_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_generated_ue", "OmegaNeg_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + } + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.add("Pion_generated_in_jet", "Pion_generated_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Pion_generated_in_ue", "Pion_generated_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.add("Kaon_generated_in_jet", "Kaon_generated_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Kaon_generated_in_ue", "Kaon_generated_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.add("Proton_generated_in_jet", "Proton_generated_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Proton_generated_in_ue", "Proton_generated_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + } + + // Histograms for mc reconstructed + if (doprocessMCreconstructed) { + + // Event counter + registryMC.add("number_of_events_mc_rec", "number of rec events in mc", HistType::kTH1D, {{10, 0, 10, "Event Cuts"}}); + registryMC.add("number_of_events_vsmultiplicity_rec", "number of events vs multiplicity", HistType::kTH1D, {{101, 0, 101, "Multiplicity percentile"}}); + + // Histograms for analysis + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + 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}); + // Histograms for secondary hadrons + registryMC.add("K0s_reconstructed_jet_incl", "K0s_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("K0s_reconstructed_ue_incl", "K0s_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_jet_incl", "Lambda_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_ue_incl", "Lambda_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_jet_incl", "AntiLambda_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_ue_incl", "AntiLambda_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + } + + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.add("XiPos_reconstructed_jet", "XiPos_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiPos_reconstructed_ue", "XiPos_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_reconstructed_jet", "XiNeg_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_reconstructed_ue", "XiNeg_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_reconstructed_jet", "OmegaPos_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_reconstructed_ue", "OmegaPos_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_reconstructed_jet", "OmegaNeg_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_reconstructed_ue", "OmegaNeg_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + } + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.add("Pion_reconstructed_in_jet", "Pion_reconstructed_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Pion_reconstructed_in_ue", "Pion_reconstructed_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.add("Kaon_reconstructed_in_jet", "Kaon_reconstructed_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Kaon_reconstructed_in_ue", "Kaon_reconstructed_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.add("Proton_reconstructed_in_jet", "Proton_reconstructed_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Proton_reconstructed_in_ue", "Proton_reconstructed_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + } + } + + /* + // Calculation of perpendicular axes + void getPerpendicularAxis(TVector3 p, TVector3& u, double sign) + { + // initialization + double ux(0), uy(0), uz(0); + + // components of vector p + const double px = p.X(); + const double py = p.Y(); + const 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 + const double a = px * px + py * py; + const double b = 2.0 * px * pz * pz; + const double c = pz * pz * pz * pz - py * py * py * py - px * px * py * py; + const 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; + } + */ + + // Delta phi calculation + 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; + } + + // Check if particle is a physical primary or a decay product of a heavy-flavor hadron + bool isPhysicalPrimaryOrFromHF(aod::McParticle const& particle, aod::McParticles const& mcParticles) + { + // Keep only pi, K, p, e, mu + int pdg = std::abs(particle.pdgCode()); + if (!(pdg == PDG_t::kPiPlus || pdg == PDG_t::kKPlus || pdg == PDG_t::kProton || pdg == PDG_t::kElectron || pdg == PDG_t::kMuonMinus)) + return false; + + // Constants for identifying heavy-flavor (charm and bottom) content from PDG codes + static constexpr int kCharmQuark = 4; + static constexpr int kBottomQuark = 5; + static constexpr int hundreds = 100; + static constexpr int thousands = 1000; + + // Check if particle is from heavy-flavor decay + bool fromHF = false; + if (particle.has_mothers()) { + auto mother = mcParticles.iteratorAt(particle.mothersIds()[0]); + int motherPdg = std::abs(mother.pdgCode()); + fromHF = (motherPdg / hundreds == kCharmQuark || motherPdg / hundreds == kBottomQuark || motherPdg / thousands == kCharmQuark || motherPdg / thousands == kBottomQuark); + } + + // Select only physical primary particles or from heavy-flavor + return (particle.isPhysicalPrimary() || fromHF); + } + + // Compute two transverse directions orthogonal to vector p + void getPerpendicularDirections(const TVector3& p, TVector3& u1, TVector3& u2) + { + // Get momentum components + double px = p.X(); + double py = p.Y(); + double pz = p.Z(); + + // Precompute squared terms + double px2 = px * px; + double py2 = py * py; + double pz2 = pz * pz; + double pz4 = pz2 * pz2; + + // Case 1: vector along z-axis -> undefined perpendiculars + if (px == 0 && py == 0) { + u1.SetXYZ(0, 0, 0); + u2.SetXYZ(0, 0, 0); + return; + } + + // Case 2: px = 0 -> avoid division by zero + if (px == 0 && py != 0) { + double ux = std::sqrt(py2 - pz4 / py2); + double uy = -pz2 / py; + u1.SetXYZ(ux, uy, pz); + u2.SetXYZ(-ux, uy, pz); + return; + } + + // Case 3: py = 0 -> avoid division by zero + if (py == 0 && px != 0) { + double ux = -pz2 / px; + double uy = std::sqrt(px2 - pz4 / px2); + u1.SetXYZ(ux, uy, pz); + u2.SetXYZ(ux, -uy, pz); + return; + } + + // General case: solve quadratic for perpendicular vectors + 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; + + // Invalid or degenerate solutions + if (delta < 0 || a == 0) { + u1.SetXYZ(0, 0, 0); + u2.SetXYZ(0, 0, 0); + return; + } + + // Solution 1 + double u1x = (-b + std::sqrt(delta)) / (2.0 * a); + double u1y = (-pz2 - px * u1x) / py; + u1.SetXYZ(u1x, u1y, pz); + + // Solution 2 + double u2x = (-b - std::sqrt(delta)) / (2.0 * a); + double u2y = (-pz2 - px * u2x) / py; + u2.SetXYZ(u2x, u2y, pz); + } + + // Find ITS hit + template + bool hasITSHitOnLayer(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 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 ((!hasITSHitOnLayer(track, 1)) && (!hasITSHitOnLayer(track, 2)) && (!hasITSHitOnLayer(track, 3))) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minTpcCr) + return false; + if (track.tpcChi2NCl() > maxChi2Tpc) + return false; + if (track.itsChi2NCl() > maxChi2Its) + return false; + if (std::fabs(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; + } + + // Lambda selections + template + bool passedLambdaSelection(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + // Single-track selections + if (!passedSingleTrackSelection(ptrack) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum of lambda daughters + TVector3 proton(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pion(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selection on pt of Lambda daughters + if (proton.Pt() < ptMinV0Proton || proton.Pt() > ptMaxV0Proton) + return false; + if (pion.Pt() < ptMinV0Pion || 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): positive track = proton, negative track = pion + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID selections (TOF): positive track = proton, negative track = pion + 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) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum AntiLambda daughters + TVector3 pion(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 proton(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selections on pt of Antilambda daughters + if (proton.Pt() < ptMinV0Proton || proton.Pt() > ptMaxV0Proton) + return false; + if (pion.Pt() < ptMinV0Pion || 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): negative track = proton, positive track = pion + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + + // PID selections (TOF): negative track = proton, positive track = pion + 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) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum of K0s daughters + TVector3 pionPos(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pionNeg(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selections on pt of K0s daughters + if (pionPos.Pt() < ptMinK0Pion || pionPos.Pt() > ptMaxK0Pion) + return false; + if (pionNeg.Pt() < ptMinK0Pion || 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; + } + + // V0s selections + template + bool passedV0Selection(const V0Type& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum of K0s daughters + TVector3 pionPos(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pionNeg(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // 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; + + return true; + } + + template + bool passedCascadeSelection(const Cascade& casc, const TrackPos& ptrack, const TrackNeg& ntrack, const TrackBac& btrack, const Coll& coll) + { + // Single-track selections on cascade daughters + if (!passedSingleTrackSelection(ptrack)) + return false; + if (!passedSingleTrackSelection(ntrack)) + return false; + if (!passedSingleTrackSelection(btrack)) + 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; + + return true; + } + + // Xi Selections + template + bool passedXiSelection(const Xi& casc, const TrackPos& ptrack, const TrackNeg& ntrack, const TrackBac& btrack, const Coll& coll) + { + // Single-track selections on cascade daughters + 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 || ntrack.pt() > ptMaxV0Proton) + return false; + if (ptrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + return false; + } + + // Xi- selection (Xi- -> L + pi-) + if (btrack.sign() < 0) { + if (ptrack.pt() < ptMinV0Proton || ptrack.pt() > ptMaxV0Proton) + return false; + if (ntrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassPionCharged); + const double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + 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; + } + + // Reject candidates compatible with Omega + if (std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < deltaMassOmega) + return false; + return true; + } + + // Omega selections + template + bool passedOmegaSelection(const Omega& casc, const TrackPos& ptrack, const TrackNeg& ntrack, const TrackBac& btrack, const Coll& coll) + { + // Single-track selections on cascade daughters + 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 || ntrack.pt() > ptMaxV0Proton) + return false; + if (ptrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + return false; + } + + // Omega- selection (Omega- -> L + K-) + if (btrack.sign() < 0) { + if (ptrack.pt() < ptMinV0Proton || ptrack.pt() > ptMaxV0Proton) + return false; + if (ntrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + 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; + } + + // Reject candidates compatible with Xi + if (std::fabs(casc.mXi() - o2::constants::physics::MassXiMinus) < deltaMassXi) + 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.tpcNClsCrossedRows() < minNCrossedRowsTPC) + 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; + } + + // Process data + void processData(SelCollisions::iterator const& collision, aod::V0Datas const& fullV0s, + aod::CascDataExt const& Cascades, DaughterTracks const& tracks, + aod::BCsWithTimestamps const&) + { + // Fill event counter before event selection + registryData.fill(HIST("number_of_events_data"), 0.5); + + // Get the bunch crossing (BC) information associated with the collision + auto bc = collision.template bc_as(); + + // Initialize CCDB objects using the BC info + initCCDB(bc); + + // If skimmed processing is enabled, skip this event unless it passes Zorro selection + if (cfgSkimmedProcessing && !zorro.isSelected(collision.template bc_as().globalBC())) { + return; + } + + // Fill event counter after zorro selection + registryData.fill(HIST("number_of_events_data"), 1.5); + + // Event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // Fill event counter after event selection + registryData.fill(HIST("number_of_events_data"), 2.5); + + // Loop over reconstructed tracks + std::vector fjParticles; + for (auto const& track : tracks) { + + // Require that tracks pass selection criteria + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + + // Reject empty events + if (fjParticles.size() < 1) + return; + registryData.fill(HIST("number_of_events_data"), 3.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] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Jet selection + bool isAtLeastOneJetSelected = false; + std::vector selectedJet; + std::vector ue1; + std::vector ue2; + + // Loop over reconstructed jets + for (const auto& jet : jets) { + + // Jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - 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; + isAtLeastOneJetSelected = true; + + // Calculation of perpendicular cones + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Store jet and UE axes + selectedJet.emplace_back(jetAxis); + ue1.emplace_back(ueAxis1); + ue2.emplace_back(ueAxis2); + } + if (!isAtLeastOneJetSelected) + return; + + // Fill event counter with events with at least one jet + registryData.fill(HIST("number_of_events_data"), 4.5); + + // Event multiplicity + const float multiplicity = collision.centFT0M(); + + // Fill event multiplicity + registryData.fill(HIST("number_of_events_vsmultiplicity"), multiplicity); + + // Loop over selected jets + for (int i = 0; i < static_cast(selectedJet.size()); i++) { + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + for (const auto& v0 : fullV0s) { + // Get V0 daughters + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + TVector3 v0dir(v0.px(), v0.py(), v0.pz()); + + // Calculate distance from jet and UE axes + const float deltaEtaJet = v0dir.Eta() - selectedJet[i].Eta(); + const float deltaPhiJet = getDeltaPhi(v0dir.Phi(), selectedJet[i].Phi()); + const float deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const float deltaEtaUe1 = v0dir.Eta() - ue1[i].Eta(); + const float deltaPhiUe1 = getDeltaPhi(v0dir.Phi(), ue1[i].Phi()); + const float deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const float deltaEtaUe2 = v0dir.Eta() - ue2[i].Eta(); + const float deltaPhiUe2 = getDeltaPhi(v0dir.Phi(), ue2[i].Phi()); + const float deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + bool isUE = false, isInJC = false; + + if (deltaRjet < rJet && passedV0Selection(v0, pos, neg)) { + + if (passedK0ShortSelection(v0, pos, neg)) + registryData.fill(HIST("K0s_in_jet"), multiplicity, v0.pt(), v0.mK0Short()); + if (passedLambdaSelection(v0, pos, neg)) + registryData.fill(HIST("Lambda_in_jet"), multiplicity, v0.pt(), v0.mLambda()); + if (passedAntiLambdaSelection(v0, pos, neg)) + registryData.fill(HIST("AntiLambda_in_jet"), multiplicity, v0.pt(), v0.mAntiLambda()); + + isInJC = true; + } else if ((deltaRue1 < rJet || deltaRue2 < rJet) && passedV0Selection(v0, pos, neg)) { + + if (passedK0ShortSelection(v0, pos, neg)) + registryData.fill(HIST("K0s_in_ue"), multiplicity, v0.pt(), v0.mK0Short()); + if (passedLambdaSelection(v0, pos, neg)) + registryData.fill(HIST("Lambda_in_ue"), multiplicity, v0.pt(), v0.mLambda()); + if (passedAntiLambdaSelection(v0, pos, neg)) + registryData.fill(HIST("AntiLambda_in_ue"), multiplicity, v0.pt(), v0.mAntiLambda()); + + isUE = true; + } + + // Fill table + tableV0s(v0.pt(), + v0.mLambda(), + v0.mAntiLambda(), + v0.mK0Short(), + v0.v0radius(), + v0.v0cosPA(), + v0.dcapostopv(), + v0.dcanegtopv(), + v0.dcaV0daughters(), + neg.tpcNSigmaPr(), + pos.tpcNSigmaPr(), + neg.tpcNSigmaPi(), + pos.tpcNSigmaPi(), + neg.tofNSigmaPr(), + pos.tofNSigmaPr(), + neg.tofNSigmaPi(), + pos.tofNSigmaPi(), + collision.centFT0M(), + pos.tpcNClsCrossedRows(), + neg.tpcNClsCrossedRows(), + neg.tpcChi2NCl(), + neg.itsNCls(), + pos.tpcChi2NCl(), + pos.itsNCls(), + isUE, + isInJC); + } + } + + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + for (const auto& casc : Cascades) { + // Get cascade daughters + const auto& bach = casc.bachelor_as(); + const auto& pos = casc.posTrack_as(); + const auto& neg = casc.negTrack_as(); + TVector3 cascadeDir(casc.px(), casc.py(), casc.pz()); + + // Calculate distance from jet and UE axes + const double deltaEtaJet = cascadeDir.Eta() - selectedJet[i].Eta(); + const double deltaPhiJet = getDeltaPhi(cascadeDir.Phi(), selectedJet[i].Phi()); + const double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const double deltaEtaUe1 = cascadeDir.Eta() - ue1[i].Eta(); + const double deltaPhiUe1 = getDeltaPhi(cascadeDir.Phi(), ue1[i].Phi()); + const double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const double deltaEtaUe2 = cascadeDir.Eta() - ue2[i].Eta(); + const double deltaPhiUe2 = getDeltaPhi(cascadeDir.Phi(), ue2[i].Phi()); + const double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + bool isUE = false, isInJC = false; + + if (deltaRjet < rJet && passedCascadeSelection(casc, pos, neg, bach, collision)) { + + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() > 0) + registryData.fill(HIST("XiPos_in_jet"), multiplicity, casc.pt(), casc.mXi()); + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() < 0) + registryData.fill(HIST("XiNeg_in_jet"), multiplicity, casc.pt(), casc.mXi()); + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() > 0) + registryData.fill(HIST("OmegaPos_in_jet"), multiplicity, casc.pt(), casc.mOmega()); + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() < 0) + registryData.fill(HIST("OmegaNeg_in_jet"), multiplicity, casc.pt(), casc.mOmega()); + + isInJC = true; + } else if ((deltaRue1 < rJet || deltaRue2 < rJet) && passedCascadeSelection(casc, pos, neg, bach, collision)) { + + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() > 0) + registryData.fill(HIST("XiPos_in_ue"), multiplicity, casc.pt(), casc.mXi()); + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() < 0) + registryData.fill(HIST("XiNeg_in_ue"), multiplicity, casc.pt(), casc.mXi()); + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() > 0) + registryData.fill(HIST("OmegaPos_in_ue"), multiplicity, casc.pt(), casc.mOmega()); + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() < 0) + registryData.fill(HIST("OmegaNeg_in_ue"), multiplicity, casc.pt(), casc.mOmega()); + + isUE = true; + } + + tableCascades(casc.pt(), + casc.sign(), + casc.mXi(), + casc.mOmega(), + casc.mLambda(), + casc.cascradius(), + casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), + casc.v0radius(), + 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()), + neg.tpcNSigmaPr(), + pos.tpcNSigmaPr(), + neg.tpcNSigmaPi(), + pos.tpcNSigmaPi(), + bach.tpcNSigmaPi(), + bach.tpcNSigmaKa(), + neg.tofNSigmaPr(), + pos.tofNSigmaPr(), + neg.tofNSigmaPi(), + pos.tofNSigmaPi(), + bach.tofNSigmaPi(), + bach.tofNSigmaKa(), + collision.centFT0M(), + pos.tpcNClsCrossedRows(), + neg.tpcNClsCrossedRows(), + bach.tpcNClsCrossedRows(), + neg.tpcChi2NCl(), + neg.itsNCls(), + pos.tpcChi2NCl(), + pos.itsNCls(), + bach.tpcChi2NCl(), + bach.itsNCls(), + isUE, + isInJC); + } + } + if (enabledSignals.value[ParticleOfInterest::kPions] || enabledSignals.value[ParticleOfInterest::kKaons] || enabledSignals.value[ParticleOfInterest::kProtons]) { + for (const auto& trk : tracks) { + + if (!passedSingleTrackSelection(trk)) { + continue; + } + + const double deltaEtaJet = trk.eta() - selectedJet[i].Eta(); + const double deltaPhiJet = getDeltaPhi(trk.phi(), selectedJet[i].Phi()); + const double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const double deltaEtaUe1 = trk.eta() - ue1[i].Eta(); + const double deltaPhiUe1 = getDeltaPhi(trk.phi(), ue1[i].Phi()); + const double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const double deltaEtaUe2 = trk.eta() - ue2[i].Eta(); + const double deltaPhiUe2 = getDeltaPhi(trk.phi(), ue2[i].Phi()); + const double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + if (deltaRjet < rJet) { + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryData.fill(HIST("Pion_in_jet"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.dcaXY()); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryData.fill(HIST("Kaon_in_jet"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.dcaXY()); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryData.fill(HIST("Proton_in_jet"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.dcaXY()); + } + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryData.fill(HIST("Pion_in_ue"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.dcaXY()); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryData.fill(HIST("Kaon_in_ue"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.dcaXY()); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryData.fill(HIST("Proton_in_ue"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.dcaXY()); + } + } + } + } + } + } + PROCESS_SWITCH(LFInJets, processData, "Process data", true); + + // Define per-collision preslices for V0s, cascades, MC particles, and daughter tracks + Preslice perCollisionV0 = o2::aod::v0data::collisionId; + Preslice perCollisionCasc = o2::aod::cascade::collisionId; + Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; + Preslice perCollisionTrk = o2::aod::track::collisionId; + + // Generated MC events + void processMCgenerated(soa::Join const& collisions, aod::McParticles const& mcParticles) + { + // Define per-event particle containers + std::vector fjParticles; + std::vector strHadronMomentum; + std::vector pdg; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Loop over all simulated collision events + for (const auto& collision : collisions) { + + // Clear containers at the start of the event loop + fjParticles.clear(); + strHadronMomentum.clear(); + pdg.clear(); + + // Fill event counter before any selection + registryMC.fill(HIST("number_of_events_mc_gen"), 0.5); + + // Need to apply event selection to simulated events + registryMC.fill(HIST("number_of_events_mc_gen"), 1.5); + + // Require vertex position within the allowed z range + if (std::fabs(collision.posZ()) > zVtx) + continue; + + // Fill event counter after selection on z-vertex + registryMC.fill(HIST("number_of_events_mc_gen"), 2.5); + + // Multiplicity of generated event + double genMultiplicity = collision.centFT0M(); + + // MC particles per collision + auto mcParticlesPerColl = mcParticles.sliceBy(perMCCollision, collision.globalIndex()); + + // Loop over all MC particles and select physical primaries within acceptance + for (const auto& particle : mcParticlesPerColl) { + + // Store properties of strange hadrons + int pdgAbs = std::abs(particle.pdgCode()); + if (particle.isPhysicalPrimary() && (pdgAbs == kK0Short || pdgAbs == kLambda0 || pdgAbs == kXiMinus || pdgAbs == kOmegaMinus)) { + pdg.emplace_back(particle.pdgCode()); + strHadronMomentum.emplace_back(particle.px(), particle.py(), particle.pz()); + } + + // Select physical primary particles or HF decay products + if (!isPhysicalPrimaryOrFromHF(particle, mcParticles)) + continue; + + double minPtParticle = 0.1; + if (particle.eta() < etaMin || particle.eta() > etaMax || particle.pt() < minPtParticle) + continue; + + // Build 4-momentum assuming charged pion mass + static constexpr float kMassPionChargedSquared = o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged; + const double energy = std::sqrt(particle.p() * particle.p() + kMassPionChargedSquared); + fastjet::PseudoJet fourMomentum(particle.px(), particle.py(), particle.pz(), energy); + fourMomentum.set_user_index(particle.pdgCode()); + fjParticles.emplace_back(fourMomentum); + } + + // Skip events with no particles + if (fjParticles.size() < 1) + continue; + registryMC.fill(HIST("number_of_events_mc_gen"), 3.5); + + // Cluster MC particles into jets using anti-kt algorithm + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + + // Estimate background energy density (rho) in perpendicular cone + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Loop over clustered jets + for (const auto& jet : jets) { + + // Jet must be fully contained in acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - deltaEtaEdge)) + continue; + + // Subtract background energy from jet + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + + // Apply jet pT threshold + if (jetMinusBkg.pt() < minJetPt) + continue; + registryMC.fill(HIST("number_of_events_mc_gen"), 4.5); + registryMC.fill(HIST("number_of_events_vsmultiplicity_gen"), genMultiplicity); + + // Set up two perpendicular cone axes for underlying event estimation + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Loop over strange hadrons + int index = -1; + for (const auto& hadron : strHadronMomentum) { + + // Particle index + index++; + + // Compute distance of particles from jet and UE axes + double deltaEtaJet = hadron.Eta() - jetAxis.Eta(); + double deltaPhiJet = getDeltaPhi(hadron.Phi(), jetAxis.Phi()); + double deltaRJet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = hadron.Eta() - ueAxis1.Eta(); + double deltaPhiUe1 = getDeltaPhi(hadron.Phi(), ueAxis1.Phi()); + double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = hadron.Eta() - ueAxis2.Eta(); + double deltaPhiUe2 = getDeltaPhi(hadron.Phi(), ueAxis2.Phi()); + double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Select particles inside jet + if (deltaRJet < coneRadius) { + switch (pdg[index]) { + case kK0Short: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0Bar: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kXiMinus: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiNeg_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kXiPlusBar: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiPos_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaMinus: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaNeg_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaPlusBar: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaPos_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kPiPlus: + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kKPlus: + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kProton: + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kPiMinus: + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kKMinus: + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kProtonBar: + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + default: + break; + } + } + + // Select particles inside UE cones + if (deltaRUe1 < coneRadius || deltaRUe2 < coneRadius) { + switch (pdg[index]) { + case kK0Short: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0Bar: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kXiMinus: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiNeg_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kXiPlusBar: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiPos_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaMinus: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaNeg_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaPlusBar: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaPos_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kPiPlus: + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kKPlus: + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kProton: + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kPiMinus: + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kKMinus: + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kProtonBar: + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + default: + break; + } + } + } + } + } + } + PROCESS_SWITCH(LFInJets, processMCgenerated, "process generated events", false); + + // Reconstructed MC events + void processMCreconstructed(SimCollisions const& collisions, soa::Join const&, + DaughterTracksMC const& mcTracks, aod::V0Datas const& fullV0s, + aod::CascDataExt const& Cascades, const aod::McParticles&) + { + // Define per-event containers + std::vector fjParticles; + std::vector selectedJet; + std::vector ue1; + std::vector ue2; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Loop over reconstructed collisions + for (const auto& collision : collisions) { + + if (!collision.has_mcCollision()) { + continue; + } + + const auto& mcCollision = collision.mcCollision_as>(); + + // Clear containers at the start of the event loop + fjParticles.clear(); + selectedJet.clear(); + ue1.clear(); + ue2.clear(); + + // Fill event counter before any selection + registryMC.fill(HIST("number_of_events_mc_rec"), 0.5); + if (!collision.sel8()) + continue; + + // Fill event counter after event selection + registryMC.fill(HIST("number_of_events_mc_rec"), 1.5); + if (std::fabs(collision.posZ()) > zVtx) + continue; + + // Fill event counter after selection on z-vertex + registryMC.fill(HIST("number_of_events_mc_rec"), 2.5); + + // Event multiplicity + const float multiplicity = mcCollision.centFT0M(); + + // Number of V0 and cascades per collision + auto v0sPerColl = fullV0s.sliceBy(perCollisionV0, collision.globalIndex()); + auto cascPerColl = Cascades.sliceBy(perCollisionCasc, collision.globalIndex()); + auto tracksPerColl = mcTracks.sliceBy(perCollisionTrk, collision.globalIndex()); + + // Loop over reconstructed tracks + for (auto const& track : tracksPerColl) { + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + + // Reject empty events + if (fjParticles.size() < 1) + continue; + registryMC.fill(HIST("number_of_events_mc_rec"), 3.5); + + // Cluster particles using the anti-kt algorithm + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Jet selection + bool isAtLeastOneJetSelected = false; + + // Loop over clustered jets + for (const auto& jet : jets) { + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - 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; + isAtLeastOneJetSelected = true; + + // Perpendicular cones + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Store selected jet and UE cone axes + selectedJet.emplace_back(jetAxis); + ue1.emplace_back(ueAxis1); + ue2.emplace_back(ueAxis2); + } + if (!isAtLeastOneJetSelected) + continue; + + // Fill event counter for events with at least one selected jet + registryMC.fill(HIST("number_of_events_mc_rec"), 4.5); + registryMC.fill(HIST("number_of_events_vsmultiplicity_rec"), multiplicity); + + // Loop over selected jets + for (int i = 0; i < static_cast(selectedJet.size()); i++) { + + // V0 particles + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + for (const auto& v0 : v0sPerColl) { + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + TVector3 v0dir(v0.px(), v0.py(), v0.pz()); + + // Get MC particles + if (!pos.has_mcParticle() || !neg.has_mcParticle()) + continue; + auto posParticle = pos.mcParticle_as(); + auto negParticle = neg.mcParticle_as(); + if (!posParticle.has_mothers() || !negParticle.has_mothers()) + continue; + + // Select particles originating from the same parent + 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; + + // Compute distance from jet and UE axes + double deltaEtaJet = v0dir.Eta() - selectedJet[i].Eta(); + double deltaPhiJet = getDeltaPhi(v0dir.Phi(), selectedJet[i].Phi()); + double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = v0dir.Eta() - ue1[i].Eta(); + double deltaPhiUe1 = getDeltaPhi(v0dir.Phi(), ue1[i].Phi()); + double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = v0dir.Eta() - ue2[i].Eta(); + double deltaPhiUe2 = getDeltaPhi(v0dir.Phi(), ue2[i].Phi()); + double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // K0s + if (passedK0ShortSelection(v0, pos, neg) && pdgParent == kK0Short && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("K0s_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("K0s_reconstructed_ue"), multiplicity, v0.pt()); + } + } + // Lambda + if (passedLambdaSelection(v0, pos, neg) && pdgParent == kLambda0 && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_ue"), multiplicity, v0.pt()); + } + } + // AntiLambda + if (passedAntiLambdaSelection(v0, pos, neg) && pdgParent == kLambda0Bar && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_ue"), multiplicity, v0.pt()); + } + } + + // Fill inclusive spectra + // K0s + if (passedK0ShortSelection(v0, pos, neg) && pdgParent == kK0Short) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("K0s_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("K0s_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + // Lambda + if (passedLambdaSelection(v0, pos, neg) && pdgParent == kLambda0) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + // AntiLambda + if (passedAntiLambdaSelection(v0, pos, neg) && pdgParent == kLambda0Bar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + } + } + + // Cascades + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + for (const auto& casc : cascPerColl) { + auto bach = casc.bachelor_as(); + auto pos = casc.posTrack_as(); + auto neg = casc.negTrack_as(); + + // Get MC particles + if (!bach.has_mcParticle() || !pos.has_mcParticle() || !neg.has_mcParticle()) + continue; + auto posParticle = pos.mcParticle_as(); + auto negParticle = neg.mcParticle_as(); + auto bachParticle = bach.mcParticle_as(); + if (!posParticle.has_mothers() || !negParticle.has_mothers() || !bachParticle.has_mothers()) + continue; + + // Select particles originating from the same parent + int pdgParent(0); + bool isPhysPrim = false; + 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; + isPhysPrim = particleMotherOfBach.isPhysicalPrimary(); + pdgParent = particleMotherOfBach.pdgCode(); + } + } + } + if (pdgParent == 0) + continue; + if (!isPhysPrim) + continue; + + // Compute distances from jet and UE axes + TVector3 cascadeDir(casc.px(), casc.py(), casc.pz()); + double deltaEtaJet = cascadeDir.Eta() - selectedJet[i].Eta(); + double deltaPhiJet = getDeltaPhi(cascadeDir.Phi(), selectedJet[i].Phi()); + double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = cascadeDir.Eta() - ue1[i].Eta(); + double deltaPhiUe1 = getDeltaPhi(cascadeDir.Phi(), ue1[i].Phi()); + double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = cascadeDir.Eta() - ue2[i].Eta(); + double deltaPhiUe2 = getDeltaPhi(cascadeDir.Phi(), ue2[i].Phi()); + double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Xi+ + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() > 0 && pdgParent == kXiPlusBar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("XiPos_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("XiPos_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Xi- + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() < 0 && pdgParent == kXiMinus) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("XiNeg_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("XiNeg_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Omega+ + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() > 0 && pdgParent == kOmegaPlusBar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("OmegaPos_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("OmegaPos_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Omega- + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() < 0 && pdgParent == kOmegaMinus) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("OmegaNeg_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("OmegaNeg_reconstructed_ue"), multiplicity, casc.pt()); + } + } + } + } + } + } + } + PROCESS_SWITCH(LFInJets, processMCreconstructed, "process reconstructed events", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index 19a0dbd77ae..b60eecf399f 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -20,389 +20,1087 @@ // gianni.shigeru.setoue.liveraro@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFSigmaTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/ASoA.h" -#include "ReconstructionDataFormats/Track.h" +#include "Common/CCDB/ctpRateFetcher.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/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/Vector3D.h" +#include +#include #include #include -#include #include #include -#include +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; -using std::cout; -using std::endl; using dauTracks = soa::Join; -using V0DerivedMCDatas = soa::Join; -using V0MLDerivedDatas = soa::Join; -using V0StandardDerivedDatas = soa::Join; +using V0StandardDerivedDatas = soa::Join; +using V0DerivedMCDatas = soa::Join; +using V0TOFStandardDerivedDatas = soa::Join; +using V0TOFDerivedMCDatas = soa::Join; struct sigma0builder { - SliceCache cache; + Service ccdb; + ctpRateFetcher rateFetcher; + + //__________________________________________________ + // Sigma0 specific + Produces sigma0cores; // sigma0 candidates info for analysis + Produces sigmaPhotonExtras; // photons from sigma0 candidates info + Produces sigmaLambdaExtras; // lambdas from sigma0 candidates info + Produces sigma0CollRefs; // references collisions from Sigma0Cores + Produces sigma0mccores; // Reco sigma0 MC properties + Produces sigma0Gens; // Generated sigma0s + Produces sigma0GenCollRefs; // references collisions from sigma0Gens - Produces v0sigma0Coll; // characterises collisions - Produces v0Sigma0CollRefs; // characterises collisions - Produces v0Sigmas; // save sigma0 candidates for analysis - Produces v0SigmaPhotonExtras; // save sigma0 candidates for analysis - Produces v0SigmaLambdaExtras; // save sigma0 candidates for analysis - Produces v0MCSigmas; + //__________________________________________________ + // Pi0 specific + Produces pi0cores; // pi0 candidates info for analysis + Produces pi0coresRefs; // references collisions from photonpair + Produces pi0coresmc; // Reco pi0 MC properties + Produces pi0Gens; // Generated pi0s + Produces pi0GenCollRefs; // references collisions from pi0Gens - // For manual sliceBy - Preslice perCollisionMCDerived = o2::aod::v0data::straCollisionId; - Preslice perCollisionSTDDerived = o2::aod::v0data::straCollisionId; - Preslice perCollisionMLDerived = o2::aod::v0data::straCollisionId; + //__________________________________________________ + // pack track quality but separte also afterburner + // dynamic range: 0-31 + enum selection : int { hasTPC = 0, + hasITSTracker, + hasITSAfterburner, + hasTRD, + hasTOF }; // Histogram registry HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable doAssocStudy{"doAssocStudy", false, "Do v0 to collision association study."}; + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + + Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; + Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + // Tables to fill + Configurable fillPi0Tables{"fillPi0Tables", false, "fill pi0 tables for QA"}; + Configurable fillSigma0Tables{"fillSigma0Tables", true, "fill sigma0 tables for analysis"}; + // 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.0, "Max pseudorapidity of daughter tracks"}; - Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", .01, "min DCA Neg To PV (cm)"}; - Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", .01, "min DCA Pos To PV (cm)"}; + Configurable V0Rapidity{"V0Rapidity", 0.5, "v0 rapidity"}; + + 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.1, "Min V0 radius (cm)"}; - Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 200, "Max V0 radius (cm)"}; - Configurable LambdaWindow{"LambdaWindow", 0.01, "Mass window around expected (in GeV/c2)"}; - - //// Photon criteria: - Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.0, "Max pseudorapidity of daughter tracks"}; - Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.001, "Min DCA daughter To PV (cm)"}; - Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.0, "Max DCA V0 Daughters (cm)"}; - Configurable PhotonMinRadius{"PhotonMinRadius", 0.5, "Min photon conversion radius (cm)"}; - Configurable PhotonMaxRadius{"PhotonMaxRadius", 250, "Max photon conversion radius (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 (for sigma0s and pi0s): + 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.05, "Mass window around expected (in GeV/c2)"}; + Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; + Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; + + //// Pi0 criteria:: + Configurable Pi0MaxRap{"Pi0MaxRap", 0.8, "Max Pi0 Rapidity"}; + Configurable Pi0MassWindow{"Pi0MassWindow", 0.115, "Mass window around expected (in GeV/c2)"}; + + //// Generated particles criteria: + struct : ConfigurableGroup { + Configurable doQA{"doQA", true, "If True, fill QA histos"}; + Configurable mc_keepOnlyFromGenerator{"mc_keepOnlyFromGenerator", false, "Keep only mcparticles from the generator"}; + Configurable mc_keepOnlyFromTransport{"mc_keepOnlyFromTransport", false, "Keep only mcparticles from the transport code"}; + Configurable mc_selectMCProcess{"mc_selectMCProcess", -1, "Keep only mcparticles produced in the selected MC process"}; + Configurable mc_rapidityWindow{"mc_rapidityWindow", 0.5, "Max generated particle rapidity"}; + } genSelections; // 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"}; + + // Invariant Mass + ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 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", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; + ConfigurableAxis axisK0SMass{"axisK0SMass", {200, 0.4f, 0.6f}, "M_{K^{0}}"}; + + // topological variable QA axes + ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {500, 0.0f, 50.0f}, "DCA (cm)"}; + ConfigurableAxis axisXY{"axisXY", {120, -120.0f, 120.0f}, "XY axis"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {50, 0.0f, 5.0f}, "DCA (cm)"}; + ConfigurableAxis axisRadius{"axisRadius", {240, 0.0f, 120.0f}, "V0 radius (cm)"}; + ConfigurableAxis axisPA{"axisPA", {100, 0.0f, 1}, "Pointing angle"}; + ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; + ConfigurableAxis axisCandSel{"axisCandSel", {7, 0.5f, +7.5f}, "Candidate Selection"}; + ConfigurableAxis axisIRBinning{"axisIRBinning", {151, -10, 1500}, "Binning for the interaction rate (kHz)"}; - int nSigmaCandidates = 0; void init(InitContext const&) { - // Event counter - histos.add("hEventVertexZ", "hEventVertexZ", kTH1F, {vertexZ}); - histos.add("hCandidateBuilderSelection", "hCandidateBuilderSelection", kTH1F, {{11, -0.5f, +10.5f}}); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(1, "Photon Mass Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(2, "Photon DauEta Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(3, "Photon DCAToPV Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(4, "Photon DCADau Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(5, "Photon Radius Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(6, "Lambda Mass Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(7, "Lambda DauEta Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(8, "Lambda DCAToPV Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(9, "Lambda Radius Cut"); - histos.get(HIST("hCandidateBuilderSelection"))->GetXaxis()->SetBinLabel(10, "Lambda DCADau Cut"); + LOGF(info, "Initializing now: cross-checking correctness..."); + if (doprocessRealData + + doprocessRealDataWithTOF + + doprocessMonteCarlo + + doprocessMonteCarloWithTOF > + 1) { + LOGF(fatal, "You have enabled more than one process function. Please check your configuration! Aborting now."); + } + + // setting CCDB service + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisCentrality}); + + histos.add("PhotonSel/h2dMassGammaVsK0S", "h2dMassGammaVsK0S", kTH2D, {axisPhotonMass, axisK0SMass}); + histos.add("PhotonSel/h2dMassGammaVsLambda", "h2dMassGammaVsLambda", kTH2D, {axisPhotonMass, axisLambdaMass}); + histos.add("PhotonSel/h2dV0XY", "h2dV0XY", kTH2F, {axisXY, axisXY}); + + histos.add("PhotonSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Photon Mass Cut"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Photon Eta/Y Cut"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(4, "Photon DCAToPV Cut"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(5, "Photon DCADau Cut"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(6, "Photon Radius Cut"); + + histos.add("PhotonSel/hPhotonMass", "hPhotonMass", kTH1F, {axisPhotonMass}); + histos.add("PhotonSel/hPhotonNegEta", "hPhotonNegEta", kTH1F, {axisRapidity}); + histos.add("PhotonSel/hPhotonPosEta", "hPhotonPosEta", kTH1F, {axisRapidity}); + histos.add("PhotonSel/hPhotonY", "hPhotonY", kTH1F, {axisRapidity}); + histos.add("PhotonSel/hPhotonDCANegToPV", "hPhotonDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("PhotonSel/hPhotonDCAPosToPV", "hPhotonDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("PhotonSel/hPhotonDCADau", "hPhotonDCADau", kTH1F, {axisDCAdau}); + histos.add("PhotonSel/hPhotonRadius", "hPhotonRadius", kTH1F, {axisRadius}); + histos.add("PhotonSel/h3dPhotonMass", "h3dPhotonMass", kTH3D, {axisCentrality, axisPt, axisPhotonMass}); + + histos.add("LambdaSel/h2dMassLambdaVsK0S", "h2dMassLambdaVsK0S", kTH2D, {axisLambdaMass, axisK0SMass}); + histos.add("LambdaSel/h2dMassLambdaVsGamma", "h2dMassLambdaVsGamma", kTH2D, {axisLambdaMass, axisPhotonMass}); + histos.add("LambdaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Lambda Mass Cut"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Lambda Eta/Y Cut"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(4, "Lambda DCAToPV Cut"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(5, "Lambda Radius Cut"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(6, "Lambda DCADau Cut"); + + histos.add("LambdaSel/hLambdaMass", "hLambdaMass", kTH1F, {axisLambdaMass}); + histos.add("LambdaSel/hAntiLambdaMass", "hAntiLambdaMass", kTH1F, {axisLambdaMass}); + histos.add("LambdaSel/hLambdaNegEta", "hLambdaNegEta", kTH1F, {axisRapidity}); + histos.add("LambdaSel/hLambdaPosEta", "hLambdaPosEta", kTH1F, {axisRapidity}); + histos.add("LambdaSel/hLambdaY", "hLambdaY", kTH1F, {axisRapidity}); + histos.add("LambdaSel/hLambdaDCANegToPV", "hLambdaDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("LambdaSel/hLambdaDCAPosToPV", "hLambdaDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("LambdaSel/hLambdaDCADau", "hLambdaDCADau", kTH1F, {axisDCAdau}); + histos.add("LambdaSel/hLambdaRadius", "hLambdaRadius", kTH1F, {axisRadius}); + histos.add("LambdaSel/h3dLambdaMass", "h3dLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("LambdaSel/h3dALambdaMass", "h3dALambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + + histos.add("SigmaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Sigma Mass Window"); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Sigma Y Window"); + + // For selection: + histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", kTH1F, {axisSigmaMass}); + + if (doAssocStudy && (doprocessMonteCarlo || doprocessMonteCarloWithTOF)) { + histos.add("V0AssoQA/h2dIRVsPt_TrueGamma", "h2dIRVsPt_TrueGamma", kTH2F, {axisIRBinning, axisPt}); + histos.add("V0AssoQA/h3dPAVsIRVsPt_TrueGamma", "h3dPAVsIRVsPt_TrueGamma", kTH3F, {axisPA, axisIRBinning, axisPt}); + histos.add("V0AssoQA/h2dIRVsPt_TrueGamma_BadCollAssig", "h2dIRVsPt_TrueGamma_BadCollAssig", kTH2F, {axisIRBinning, axisPt}); + histos.add("V0AssoQA/h3dPAVsIRVsPt_TrueGamma_BadCollAssig", "h3dPAVsIRVsPt_TrueGamma_BadCollAssig", kTH3F, {axisPA, axisIRBinning, axisPt}); + + histos.add("V0AssoQA/h2dIRVsPt_TrueLambda", "h2dIRVsPt_TrueLambda", kTH2F, {axisIRBinning, axisPt}); + histos.add("V0AssoQA/h3dPAVsIRVsPt_TrueLambda", "h3dPAVsIRVsPt_TrueLambda", kTH3F, {axisPA, axisIRBinning, axisPt}); + histos.add("V0AssoQA/h2dIRVsPt_TrueLambda_BadCollAssig", "h2dIRVsPt_TrueLambda_BadCollAssig", kTH2F, {axisIRBinning, axisPt}); + histos.add("V0AssoQA/h3dPAVsIRVsPt_TrueLambda_BadCollAssig", "h3dPAVsIRVsPt_TrueLambda_BadCollAssig", kTH3F, {axisPA, axisIRBinning, axisPt}); + } + + // MC + if (doprocessMonteCarlo || doprocessMonteCarloWithTOF) { + histos.add("MC/h2dGammaXYConversion", "h2dGammaXYConversion", kTH2F, {axisXY, axisXY}); + histos.add("MC/h2dPtVsCentrality_MCAssocGamma", "h2dPtVsCentrality_MCAssocGamma", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_MCAssocLambda", "h2dPtVsCentrality_MCAssocLambda", kTH2D, {axisCentrality, axisPt}); + histos.add("MC/h2dPtVsCentrality_MCAssocALambda", "h2dPtVsCentrality_MCAssocALambda", kTH2D, {axisCentrality, axisPt}); + } + + if (doprocessGeneratedRun3 && genSelections.doQA) { + + // Pi0s + histos.add("GenQA/hGenPi0", "hGenPi0", kTH1D, {axisPt}); + + auto hPrimaryPi0s = histos.add("GenQA/hPrimaryPi0s", "hPrimaryPi0s", kTH1D, {{2, -0.5f, 1.5f}}); + hPrimaryPi0s->GetXaxis()->SetBinLabel(1, "All Pi0s"); + hPrimaryPi0s->GetXaxis()->SetBinLabel(2, "Primary Pi0s"); + + histos.add("GenQA/h2dPi0MCSourceVsPDGMother", "h2dPi0MCSourceVsPDGMother", kTHnSparseD, {{2, -0.5f, 1.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add("GenQA/h2dPi0NDaughtersVsPDG", "h2dPi0NDaughtersVsPDG", kTHnSparseD, {{10, -0.5f, +9.5f}, {10001, -5000.5f, +5000.5f}}); + + auto h2DGenPi0TypeVsProducedByGen = histos.add("GenQA/h2DGenPi0TypeVsProducedByGen", "h2DGenPi0TypeVsProducedByGen", kTH2D, {{2, -0.5f, 1.5f}, {2, -0.5f, 1.5f}}); + h2DGenPi0TypeVsProducedByGen->GetXaxis()->SetBinLabel(1, "Sterile"); + h2DGenPi0TypeVsProducedByGen->GetXaxis()->SetBinLabel(2, "Non-Sterile"); + h2DGenPi0TypeVsProducedByGen->GetYaxis()->SetBinLabel(1, "Generator"); + h2DGenPi0TypeVsProducedByGen->GetYaxis()->SetBinLabel(2, "Transport"); + + // ______________________________________________________ + // Sigma0s + histos.add("GenQA/hGenSigma0", "hGenSigma0", kTH1D, {axisPt}); + histos.add("GenQA/hGenAntiSigma0", "hGenAntiSigma0", kTH1D, {axisPt}); + + histos.add("GenQA/h2dGenSigma0xy_Generator", "hGenSigma0xy_Generator", kTH2D, {axisXY, axisXY}); + histos.add("GenQA/h2dGenSigma0xy_Transport", "hGenSigma0xy_Transport", kTH2D, {axisXY, axisXY}); + histos.add("GenQA/hGenSigma0Radius_Generator", "hGenSigma0Radius_Generator", kTH1D, {axisRadius}); + histos.add("GenQA/hGenSigma0Radius_Transport", "hGenSigma0Radius_Transport", kTH1D, {axisRadius}); + + histos.add("GenQA/h2dSigma0MCSourceVsPDGMother", "h2dSigma0MCSourceVsPDGMother", kTHnSparseD, {{2, -0.5f, 1.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add("GenQA/h2dSigma0NDaughtersVsPDG", "h2dSigma0NDaughtersVsPDG", kTHnSparseD, {{10, -0.5f, +9.5f}, {10001, -5000.5f, +5000.5f}}); + + auto hPrimarySigma0s = histos.add("GenQA/hPrimarySigma0s", "hPrimarySigma0s", kTH1D, {{2, -0.5f, 1.5f}}); + hPrimarySigma0s->GetXaxis()->SetBinLabel(1, "All Sigma0s"); + hPrimarySigma0s->GetXaxis()->SetBinLabel(2, "Primary Sigma0s"); + + auto hGenSpecies = histos.add("GenQA/hGenSpecies", "hGenSpecies", kTH1D, {{4, -0.5f, 3.5f}}); + hGenSpecies->GetXaxis()->SetBinLabel(1, "All Prim. Lambda"); + hGenSpecies->GetXaxis()->SetBinLabel(2, "All Prim. ALambda"); + hGenSpecies->GetXaxis()->SetBinLabel(5, "All Sigma0s"); + hGenSpecies->GetXaxis()->SetBinLabel(6, "All ASigma0s"); + + histos.add("GenQA/hSigma0NDau", "hSigma0NDau", kTH1D, {{10, -0.5f, +9.5f}}); + histos.add("GenQA/h2dSigma0NDauVsProcess", "h2dSigma0NDauVsProcess", kTH2D, {{10, -0.5f, +9.5f}, {50, -0.5f, 49.5f}}); + + auto h2DGenSigma0TypeVsProducedByGen = histos.add("GenQA/h2DGenSigma0TypeVsProducedByGen", "h2DGenSigma0TypeVsProducedByGen", kTH2D, {{2, -0.5f, 1.5f}, {2, -0.5f, 1.5f}}); + h2DGenSigma0TypeVsProducedByGen->GetXaxis()->SetBinLabel(1, "Sterile"); + h2DGenSigma0TypeVsProducedByGen->GetXaxis()->SetBinLabel(2, "Non-Sterile"); + h2DGenSigma0TypeVsProducedByGen->GetYaxis()->SetBinLabel(1, "Generator"); + h2DGenSigma0TypeVsProducedByGen->GetYaxis()->SetBinLabel(2, "Transport"); + } + } + + // ______________________________________________________ + // Struct to store V0Pair properties + struct V0PairTopoInfo { + float X = -999.f; + float Y = -999.f; + float Z = -999.f; + float DCADau = -999.f; + float CosPA = -1.f; + }; + + // ______________________________________________________ + // Struct to store V0Pair MC properties + struct V0PairMCInfo { + bool fIsV01CorrectlyAssign = false; + bool fIsV02CorrectlyAssign = false; + bool fIsV01Primary = false; + bool fIsV02Primary = false; + bool fV0PairProducedByGenerator = false; + int V01PDGCode = 0; + int V02PDGCode = 0; + int V01PDGCodeMother = 0; + int V02PDGCodeMother = 0; + int V0PairPDGCode = 0; + int V0PairPDGCodeMother = 0; + int V0PairMCProcess = -1; + int V0PairMCParticleID = -1; + float V01MCpx = -999.f; + float V01MCpy = -999.f; + float V01MCpz = -999.f; + float V02MCpx = -999.f; + float V02MCpy = -999.f; + float V02MCpz = -999.f; + float V0PairMCRadius = -999.f; + }; + + // ______________________________________________________ + // Struct to store V0Pair Generated properties + struct V0PairGenInfo { + bool IsPrimary = false; + bool IsV0Lambda = false; + bool IsV0AntiLambda = false; + bool IsPi0 = false; + bool IsSigma0 = false; + bool IsAntiSigma0 = false; + bool IsProducedByGenerator = false; + bool IsSterile = false; + int MCProcess = -1; + int MCCollId = -1; + int PDGCodeMother = 0; + int NDaughters = -1; + float MCPt = -999.f; + float MCvx = 999.f; + float MCvy = 999.f; + }; + + template + V0PairTopoInfo propagateV0PairToDCA(TV01 const& v01, TV02 const& v02) + { + V0PairTopoInfo info; + + // Positions + ROOT::Math::XYZVector v01position(v01.x(), v01.y(), v01.z()); + ROOT::Math::XYZVector v02position(v02.x(), v02.y(), v02.z()); + + // Momenta + ROOT::Math::XYZVector v01momentum(v01.px(), v01.py(), v01.pz()); + ROOT::Math::XYZVector v02momentum(v02.px(), v02.py(), v02.pz()); + + // Momenta (normalized) + ROOT::Math::XYZVector v01momentumNorm(v01.px() / v01.p(), v01.py() / v01.p(), v01.pz() / v01.p()); + ROOT::Math::XYZVector v02momentumNorm(v02.px() / v02.p(), v02.py() / v02.p(), v02.pz() / v02.p()); + + // DCADau calculation (using full momenta for precision) + ROOT::Math::XYZVector posdiff = v02position - v01position; + ROOT::Math::XYZVector cross = v01momentum.Cross(v02momentum); + + float d = 1.0f - TMath::Power(v01momentumNorm.Dot(v02momentumNorm), 2); + float t = posdiff.Dot(v01momentumNorm - v01momentumNorm.Dot(v02momentumNorm) * v02momentumNorm) / d; + float s = -posdiff.Dot(v02momentumNorm - v01momentumNorm.Dot(v02momentumNorm) * v01momentumNorm) / d; + + ROOT::Math::XYZVector pointOn1 = v01position + t * v01momentumNorm; + ROOT::Math::XYZVector pointOn2 = v02position + s * v02momentumNorm; + ROOT::Math::XYZVector PCA = 0.5 * (pointOn1 + pointOn2); + + // Calculate properties and fill struct + info.DCADau = (cross.Mag2() > 0) ? std::abs(posdiff.Dot(cross)) / cross.R() : 999.f; + info.CosPA = v01momentumNorm.Dot(v02momentumNorm); + + if (d < 1e-5f) { // Parallel or nearly parallel lines + info.X = info.Y = info.Z = 0.f; // should we use another dummy value? Perhaps 999.f? + return info; + } + + info.X = PCA.X(); + info.Y = PCA.Y(); + info.Z = PCA.Z(); + + return info; } - // Process sigma candidate and store properties in object - template - bool processSigmaCandidate(TV0Object const& lambda, TV0Object const& gamma) + template + V0PairMCInfo getV0PairMCInfo(TV01 const& v01, TV02 const& v02, TCollision const& collision, TMCParticles const& mcparticles) { - if ((lambda.v0Type() == 0) || (gamma.v0Type() == 0)) + V0PairMCInfo MCinfo; + + if (!v01.has_v0MCCore() || !v02.has_v0MCCore()) + return MCinfo; + + auto v01MC = v01.template v0MCCore_as>(); + auto v02MC = v02.template v0MCCore_as>(); + + if (collision.has_straMCCollision()) { + auto MCCollision = collision.template straMCCollision_as>(); + MCinfo.fIsV01CorrectlyAssign = (v01MC.straMCCollisionId() == MCCollision.globalIndex()); + MCinfo.fIsV02CorrectlyAssign = (v02MC.straMCCollisionId() == MCCollision.globalIndex()); + } + + MCinfo.V01MCpx = v01MC.pxMC(); + MCinfo.V01MCpy = v01MC.pyMC(); + MCinfo.V01MCpz = v01MC.pzMC(); + MCinfo.V02MCpx = v02MC.pxMC(); + MCinfo.V02MCpy = v02MC.pyMC(); + MCinfo.V02MCpz = v02MC.pzMC(); + + // Get corresponding entries in MCParticles table + auto MCParticle_v01 = mcparticles.rawIteratorAt(v01MC.particleIdMC()); + auto MCParticle_v02 = mcparticles.rawIteratorAt(v02MC.particleIdMC()); + + // Get MC Mothers + auto const& MCMothersList_v01 = MCParticle_v01.template mothers_as(); + auto const& MCMothersList_v02 = MCParticle_v02.template mothers_as(); + + if (!MCMothersList_v01.empty() && !MCMothersList_v02.empty()) { // Are there mothers? + + auto const& MCMother_v01 = MCMothersList_v01.front(); // First mother + auto const& MCMother_v02 = MCMothersList_v02.front(); // First mother + + if (MCMother_v01.globalIndex() == MCMother_v02.globalIndex()) { // Is it the same mother? + + MCinfo.fV0PairProducedByGenerator = MCMother_v01.producedByGenerator(); + MCinfo.V0PairPDGCode = MCMother_v01.pdgCode(); + MCinfo.V0PairMCProcess = MCMother_v01.getProcess(); + MCinfo.V0PairMCParticleID = MCMother_v01.globalIndex(); + MCinfo.V0PairMCRadius = std::hypot(MCMother_v01.vx(), MCMother_v01.vy()); // production position radius + + auto const& v0pairmothers = MCMother_v01.template mothers_as(); // Get mothers + if (!v0pairmothers.empty()) { + auto& v0PairMother = v0pairmothers.front(); // V0Pair mother, V0s grandmother + MCinfo.V0PairPDGCodeMother = v0PairMother.pdgCode(); + } + } + } + + MCinfo.fIsV01Primary = v01MC.isPhysicalPrimary(); + MCinfo.fIsV02Primary = v02MC.isPhysicalPrimary(); + MCinfo.V01PDGCode = v01MC.pdgCode(); + MCinfo.V02PDGCode = v02MC.pdgCode(); + MCinfo.V01PDGCodeMother = v01MC.pdgCodeMother(); + MCinfo.V02PDGCodeMother = v02MC.pdgCodeMother(); + + return MCinfo; + } + + // ______________________________________________________ + // MC-specific + // Analyze v0-to-collision association + template + void analyzeV0CollAssoc(TCollision const& collision, TV0Object const& fullv0s, std::vector selV0Indices, bool isPhotonAnalysis) + { + auto v0MCCollision = collision.template straMCCollision_as>(); + float IR = (fGetIR) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource, fIRCrashOnNull) * 1.e-3 : -1; + + for (size_t i = 0; i < selV0Indices.size(); ++i) { + auto v0 = fullv0s.rawIteratorAt(selV0Indices[i]); + auto v0MC = v0.template v0MCCore_as>(); + + float V0MCpT = RecoDecay::pt(array{v0MC.pxMC(), v0MC.pyMC()}); + float V0PA = TMath::ACos(v0.v0cosPA()); + bool fIsV0CorrectlyAssigned = (v0MC.straMCCollisionId() == v0MCCollision.globalIndex()); + bool isPrimary = v0MC.isPhysicalPrimary(); + + if ((v0MC.pdgCode() == 22) && isPhotonAnalysis && isPrimary) { // True Gamma + histos.fill(HIST("V0AssoQA/h2dIRVsPt_TrueGamma"), IR, V0MCpT); + histos.fill(HIST("V0AssoQA/h3dPAVsIRVsPt_TrueGamma"), V0PA, IR, V0MCpT); + + if (!fIsV0CorrectlyAssigned) { + histos.fill(HIST("V0AssoQA/h2dIRVsPt_TrueGamma_BadCollAssig"), IR, V0MCpT); + histos.fill(HIST("V0AssoQA/h3dPAVsIRVsPt_TrueGamma_BadCollAssig"), V0PA, IR, V0MCpT); + } + } + if ((v0MC.pdgCode() == 3122) && !isPhotonAnalysis && isPrimary) { // True Lambda + histos.fill(HIST("V0AssoQA/h2dIRVsPt_TrueLambda"), IR, V0MCpT); + histos.fill(HIST("V0AssoQA/h3dPAVsIRVsPt_TrueLambda"), V0PA, IR, V0MCpT); + + if (!fIsV0CorrectlyAssigned) { + histos.fill(HIST("V0AssoQA/h2dIRVsPt_TrueLambda_BadCollAssig"), IR, V0MCpT); + histos.fill(HIST("V0AssoQA/h3dPAVsIRVsPt_TrueLambda_BadCollAssig"), V0PA, IR, V0MCpT); + } + } + } + } + + template + V0PairGenInfo getV0PairGenInfo(TMCParticle const& mcParticle) + { + V0PairGenInfo GenInfo; // auxiliary struct to store info + + // Fill with properties + GenInfo.IsPrimary = mcParticle.isPhysicalPrimary(); + GenInfo.IsV0Lambda = mcParticle.pdgCode() == 3122; + GenInfo.IsV0AntiLambda = mcParticle.pdgCode() == -3122; + GenInfo.IsPi0 = mcParticle.pdgCode() == 111; + GenInfo.IsSigma0 = mcParticle.pdgCode() == 3212; + GenInfo.IsAntiSigma0 = mcParticle.pdgCode() == -3212; + GenInfo.IsProducedByGenerator = mcParticle.producedByGenerator(); + GenInfo.MCProcess = mcParticle.getProcess(); + GenInfo.MCPt = mcParticle.pt(); + GenInfo.MCvx = mcParticle.vx(); // production position X + GenInfo.MCvy = mcParticle.vy(); // production position Y + + if (mcParticle.has_mcCollision()) + GenInfo.MCCollId = mcParticle.mcCollisionId(); // save this reference, please + + // Checking decay mode if sigma0 + if (GenInfo.IsSigma0 || GenInfo.IsAntiSigma0 || GenInfo.IsPi0) { + + // This is a costly operation, so we do it only for pi0s and sigma0s + auto const& daughters = mcParticle.template daughters_as(); + GenInfo.NDaughters = daughters.size(); + GenInfo.IsSterile = daughters.size() == 0; + + auto const& GenMothersList = mcParticle.template mothers_as(); + GenInfo.PDGCodeMother = (!GenMothersList.empty()) ? GenMothersList.front().pdgCode() : 0; + + if ((GenInfo.IsSigma0 || GenInfo.IsAntiSigma0) && genSelections.doQA) { + histos.fill(HIST("GenQA/h2dSigma0MCSourceVsPDGMother"), GenInfo.IsProducedByGenerator, GenInfo.PDGCodeMother); + for (auto& daughter : daughters) // checking decay modes + histos.fill(HIST("GenQA/h2dSigma0NDaughtersVsPDG"), daughters.size(), daughter.pdgCode()); + } + + if (GenInfo.IsPi0 && genSelections.doQA) { + histos.fill(HIST("GenQA/h2dPi0MCSourceVsPDGMother"), GenInfo.IsProducedByGenerator, GenInfo.PDGCodeMother); + for (auto& daughter : daughters) // checking decay modes + histos.fill(HIST("GenQA/h2dPi0NDaughtersVsPDG"), daughters.size(), daughter.pdgCode()); + } + } + return GenInfo; + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + void fillGenQAHistos(V0PairGenInfo const& GenInfo) + { + if (GenInfo.IsPi0) { + histos.fill(HIST("GenQA/hGenPi0"), GenInfo.MCPt); + histos.fill(HIST("GenQA/hPrimaryPi0s"), 0); + if (GenInfo.IsPrimary) + histos.fill(HIST("GenQA/hPrimaryPi0s"), 1); + + if (GenInfo.IsSterile) { + if (GenInfo.IsProducedByGenerator) + histos.fill(HIST("GenQA/h2DGenPi0TypeVsProducedByGen"), 0, 0); + else + histos.fill(HIST("GenQA/h2DGenPi0TypeVsProducedByGen"), 0, 1); + } else { + if (GenInfo.IsProducedByGenerator) + histos.fill(HIST("GenQA/h2DGenPi0TypeVsProducedByGen"), 1, 0); + else + histos.fill(HIST("GenQA/h2DGenPi0TypeVsProducedByGen"), 1, 1); + } + } + + if (GenInfo.IsV0Lambda && GenInfo.IsPrimary) + histos.fill(HIST("GenQA/hGenSpecies"), 0); + if (GenInfo.IsV0AntiLambda && GenInfo.IsPrimary) + histos.fill(HIST("GenQA/hGenSpecies"), 1); + + // Checking decay mode + if (GenInfo.IsSigma0 || GenInfo.IsAntiSigma0) { + histos.fill(HIST("GenQA/hSigma0NDau"), GenInfo.NDaughters); + histos.fill(HIST("GenQA/h2dSigma0NDauVsProcess"), GenInfo.NDaughters, GenInfo.MCProcess); + + const auto radius = std::hypot(GenInfo.MCvx, GenInfo.MCvy); + // Sigma0 XY and radius (separate histos for Gen/Transport) + if (GenInfo.IsProducedByGenerator) { + histos.fill(HIST("GenQA/h2dGenSigma0xy_Generator"), GenInfo.MCvx, GenInfo.MCvy); + histos.fill(HIST("GenQA/hGenSigma0Radius_Generator"), radius); + } else { + histos.fill(HIST("GenQA/h2dGenSigma0xy_Transport"), GenInfo.MCvx, GenInfo.MCvy); + histos.fill(HIST("GenQA/hGenSigma0Radius_Transport"), radius); + } + + // Sigma0 type vs origin (single 2D histo) + const int genIndex = GenInfo.IsProducedByGenerator ? 0 : 1; // 0 = Generator, 1 = Transport + const int typeIndex = GenInfo.IsSterile ? 0 : 1; // 0 = Sterile, 1 = Normal + histos.fill(HIST("GenQA/h2DGenSigma0TypeVsProducedByGen"), typeIndex, genIndex); + + // Fill histograms + if (GenInfo.IsSigma0) { + histos.fill(HIST("GenQA/hGenSpecies"), 2); + histos.fill(HIST("GenQA/hGenSigma0"), GenInfo.MCPt); + + histos.fill(HIST("GenQA/hPrimarySigma0s"), 0); + if (GenInfo.IsPrimary) + histos.fill(HIST("GenQA/hPrimarySigma0s"), 1); + } + if (GenInfo.IsAntiSigma0) { + histos.fill(HIST("GenQA/hGenSpecies"), 3); + histos.fill(HIST("GenQA/hGenAntiSigma0"), GenInfo.MCPt); + } + } + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + template + void genProcess(TMCParticles const& mcParticles) + { + for (auto& mcParticle : mcParticles) { + // Rapidity selection + if (TMath::Abs(mcParticle.y()) > genSelections.mc_rapidityWindow) + continue; + + // Selection on the source (generator/transport) + if (genSelections.mc_keepOnlyFromGenerator && !genSelections.mc_keepOnlyFromTransport) { + if (!mcParticle.producedByGenerator()) + continue; + } + + if (genSelections.mc_keepOnlyFromTransport && !genSelections.mc_keepOnlyFromGenerator) { + if (mcParticle.producedByGenerator()) + continue; + } + + // MC Process selection + if ((genSelections.mc_selectMCProcess >= 0) && (genSelections.mc_selectMCProcess != mcParticle.getProcess())) + continue; + + // Get generated particle info + auto MCGenInfo = getV0PairGenInfo(mcParticle); + + // Fill QA histos + if (genSelections.doQA) + fillGenQAHistos(MCGenInfo); + + // Fill tables + // Pi0 + if (fillPi0Tables && MCGenInfo.IsPi0) { + pi0Gens(MCGenInfo.IsProducedByGenerator, MCGenInfo.MCPt); // optional table to store generated pi0 candidates. Be careful, this is a large table! + pi0GenCollRefs(MCGenInfo.MCCollId); // link to stramccollision table + } + + // Sigma0/ASigma0 + if (fillSigma0Tables && (MCGenInfo.IsSigma0 || MCGenInfo.IsAntiSigma0)) { + sigma0Gens(MCGenInfo.IsSigma0, MCGenInfo.IsProducedByGenerator, MCGenInfo.MCPt); + sigma0GenCollRefs(MCGenInfo.MCCollId); // link to stramccollision table + } + } + } + + //_______________________________________________ + // Process photon candidate + template + bool processPhotonCandidate(TV0Object const& gamma, TCollision const& collision) + { + // V0 type selection + if (gamma.v0Type() == 0) return false; - if constexpr ( - requires { gamma.gammaBDTScore(); } && - requires { lambda.lambdaBDTScore(); } && - requires { lambda.antiLambdaBDTScore(); }) { + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); + histos.fill(HIST("PhotonSel/h2dMassGammaVsK0S"), gamma.mGamma(), gamma.mK0Short()); + histos.fill(HIST("PhotonSel/h2dMassGammaVsLambda"), gamma.mGamma(), gamma.mLambda()); - LOGF(info, "X-check: ML Selection is on!"); - // Gamma selection: + if (useMLScores) { 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: - if (TMath::Abs(gamma.mGamma()) > PhotonMaxMass) + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 1.); + histos.fill(HIST("PhotonSel/hPhotonMass"), gamma.mGamma()); + if ((gamma.mGamma() < 0) || (gamma.mGamma() > PhotonMaxMass)) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 0.); - if ((TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) + histos.fill(HIST("PhotonSel/hPhotonNegEta"), gamma.negativeeta()); + histos.fill(HIST("PhotonSel/hPhotonPosEta"), gamma.positiveeta()); + histos.fill(HIST("PhotonSel/hPhotonY"), PhotonY); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 2.); + if ((TMath::Abs(PhotonY) > V0Rapidity) || (TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 1.); + histos.fill(HIST("PhotonSel/hPhotonDCANegToPV"), TMath::Abs(gamma.dcanegtopv())); + histos.fill(HIST("PhotonSel/hPhotonDCAPosToPV"), TMath::Abs(gamma.dcapostopv())); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 3.); if ((TMath::Abs(gamma.dcapostopv()) < PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < PhotonMinDCAToPv)) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 2.); + histos.fill(HIST("PhotonSel/hPhotonDCADau"), TMath::Abs(gamma.dcaV0daughters())); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 4.); if (TMath::Abs(gamma.dcaV0daughters()) > PhotonMaxDCAV0Dau) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 3.); + histos.fill(HIST("PhotonSel/hPhotonRadius"), gamma.v0radius()); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 5.); if ((gamma.v0radius() < PhotonMinRadius) || (gamma.v0radius() > PhotonMaxRadius)) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 4.); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 6.); + } + + histos.fill(HIST("PhotonSel/h2dV0XY"), gamma.x(), gamma.y()); + histos.fill(HIST("PhotonSel/h3dPhotonMass"), centrality, gamma.pt(), gamma.mGamma()); + + //_______________________________________________ + // MC Processing + if constexpr (requires { gamma.motherMCPartId(); }) { + if (gamma.has_v0MCCore()) { + auto gammaMC = gamma.template v0MCCore_as>(); + if (gammaMC.pdgCode() == 22) { + histos.fill(HIST("MC/h2dGammaXYConversion"), gamma.x(), gamma.y()); + histos.fill(HIST("MC/h2dPtVsCentrality_MCAssocGamma"), centrality, gamma.pt()); + } + } + } + + return true; + } + + //_______________________________________________ + // Process lambda candidate + template + bool processLambdaCandidate(TV0Object const& lambda, TCollision const& collision) + { + // V0 type selection + if (lambda.v0Type() != 1) + return false; + + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("LambdaSel/h2dMassLambdaVsK0S"), lambda.mLambda(), lambda.mK0Short()); + histos.fill(HIST("LambdaSel/h2dMassLambdaVsGamma"), lambda.mLambda(), lambda.mGamma()); + + if (useMLScores) { + if ((lambda.lambdaBDTScore() <= Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= AntiLambda_MLThreshold)) + return false; + } else { // Lambda basic selection criteria: - if (TMath::Abs(lambda.mLambda() - 1.115683) > LambdaWindow) + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 1.); + histos.fill(HIST("LambdaSel/hLambdaMass"), lambda.mLambda()); + histos.fill(HIST("LambdaSel/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("hCandidateBuilderSelection"), 5.); - if ((TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) + histos.fill(HIST("LambdaSel/hLambdaNegEta"), lambda.negativeeta()); + histos.fill(HIST("LambdaSel/hLambdaPosEta"), lambda.positiveeta()); + histos.fill(HIST("LambdaSel/hLambdaY"), lambda.yLambda()); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 2.); + if ((TMath::Abs(lambda.yLambda()) > V0Rapidity) || (TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 6.); + histos.fill(HIST("LambdaSel/hLambdaDCANegToPV"), lambda.dcanegtopv()); + histos.fill(HIST("LambdaSel/hLambdaDCAPosToPV"), lambda.dcapostopv()); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 3.); if ((TMath::Abs(lambda.dcapostopv()) < LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < LambdaMinDCANegToPv)) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 7.); + histos.fill(HIST("LambdaSel/hLambdaRadius"), lambda.v0radius()); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 4.); if ((lambda.v0radius() < LambdaMinv0radius) || (lambda.v0radius() > LambdaMaxv0radius)) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 8.); - if (lambda.dcaV0daughters() > LambdaMaxDCAV0Dau) + histos.fill(HIST("LambdaSel/hLambdaDCADau"), lambda.dcaV0daughters()); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 5.); + if (TMath::Abs(lambda.dcaV0daughters()) > LambdaMaxDCAV0Dau) return false; - histos.fill(HIST("hCandidateBuilderSelection"), 9.); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 6.); } - // 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}); - if (TMath::Abs(sigmamass - 1.192642) > Sigma0Window) - return false; + histos.fill(HIST("LambdaSel/h3dLambdaMass"), centrality, lambda.pt(), lambda.mLambda()); + histos.fill(HIST("LambdaSel/h3dALambdaMass"), centrality, lambda.pt(), lambda.mAntiLambda()); + + //_______________________________________________ + // MC Processing (if available) + if constexpr (requires { lambda.motherMCPartId(); }) { + if (lambda.has_v0MCCore()) { + auto lambdaMC = lambda.template v0MCCore_as>(); + if (lambdaMC.pdgCode() == 3122) // Is Lambda + histos.fill(HIST("MC/h2dPtVsCentrality_MCAssocLambda"), centrality, lambda.pt()); + if (lambdaMC.pdgCode() == -3122) // Is AntiLambda + histos.fill(HIST("MC/h2dPtVsCentrality_MCAssocALambda"), centrality, lambda.pt()); + } + } return true; } - // Helper struct to pass v0 information - struct { - float mass; - float pT; - float Rapidity; - } sigmaCandidate; - - // Fill tables with reconstructed sigma0 candidate - template - void fillTables(TV0Object const& lambda, TV0Object const& gamma) + + //_______________________________________________ + // Build pi0 candidate for QA + template + bool buildPi0(TV0Object const& gamma1, TV0Object const& gamma2, TCollision const& collision, TMCParticles const& mcparticles) { + //_______________________________________________ + // Check if both V0s are made of the same tracks + if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || + gamma1.negTrackExtraId() == gamma2.negTrackExtraId()) { + return false; + } - float GammaBDTScore = -1; - float LambdaBDTScore = -1; - float AntiLambdaBDTScore = -1; + //_______________________________________________ + // 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 pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); + + //_______________________________________________ + // Pi0-specific selections: + if (TMath::Abs(pi0Y) > Pi0MaxRap) + return false; + + if (TMath::Abs(pi0Mass - o2::constants::physics::MassPi0) > Pi0MassWindow) + return false; - if constexpr ( - requires { gamma.gammaBDTScore(); } && - requires { lambda.lambdaBDTScore(); } && - requires { lambda.antiLambdaBDTScore(); }) { + // Fill optional tables for QA + // Define the table! + auto posTrackGamma1 = gamma1.template posTrackExtra_as(); + auto negTrackGamma1 = gamma1.template negTrackExtra_as(); + auto posTrackGamma2 = gamma2.template posTrackExtra_as(); + auto negTrackGamma2 = gamma2.template negTrackExtra_as(); - GammaBDTScore = gamma.gammaBDTScore(); - LambdaBDTScore = lambda.lambdaBDTScore(); - AntiLambdaBDTScore = lambda.antiLambdaBDTScore(); + // Calculate Pi0 topological info + auto pi0TopoInfo = propagateV0PairToDCA(gamma1, gamma2); + + // Check if MC data and populate corresponding table + if constexpr (requires { gamma1.motherMCPartId(); gamma2.motherMCPartId(); }) { + auto pi0MCInfo = getV0PairMCInfo(gamma1, gamma2, collision, mcparticles); + + pi0coresmc(pi0MCInfo.V0PairMCRadius, pi0MCInfo.V0PairPDGCode, pi0MCInfo.V0PairPDGCodeMother, pi0MCInfo.V0PairMCProcess, pi0MCInfo.fV0PairProducedByGenerator, + pi0MCInfo.V01MCpx, pi0MCInfo.V01MCpy, pi0MCInfo.V01MCpz, + pi0MCInfo.fIsV01Primary, pi0MCInfo.V01PDGCode, pi0MCInfo.V01PDGCodeMother, pi0MCInfo.fIsV01CorrectlyAssign, + pi0MCInfo.V02MCpx, pi0MCInfo.V02MCpy, pi0MCInfo.V02MCpz, + pi0MCInfo.fIsV02Primary, pi0MCInfo.V02PDGCode, pi0MCInfo.V02PDGCodeMother, pi0MCInfo.fIsV02CorrectlyAssign); } - // Sigma0 candidate properties + pi0cores(pi0TopoInfo.X, pi0TopoInfo.Y, pi0TopoInfo.Z, pi0TopoInfo.DCADau, pi0TopoInfo.CosPA, + gamma1.px(), gamma1.py(), gamma1.pz(), + gamma1.mGamma(), gamma1.qtarm(), gamma1.alpha(), gamma1.dcapostopv(), gamma1.dcanegtopv(), gamma1.dcaV0daughters(), + gamma1.negativeeta(), gamma1.positiveeta(), gamma1.v0cosPA(), gamma1.v0radius(), gamma1.z(), + posTrackGamma1.tpcCrossedRows(), negTrackGamma1.tpcCrossedRows(), posTrackGamma1.tpcNSigmaEl(), negTrackGamma1.tpcNSigmaEl(), gamma1.v0Type(), + gamma2.px(), gamma2.py(), gamma2.pz(), + gamma2.mGamma(), gamma2.qtarm(), gamma2.alpha(), gamma2.dcapostopv(), gamma2.dcanegtopv(), gamma2.dcaV0daughters(), + gamma2.negativeeta(), gamma2.positiveeta(), gamma2.v0cosPA(), gamma2.v0radius(), gamma2.z(), + posTrackGamma2.tpcCrossedRows(), negTrackGamma2.tpcCrossedRows(), posTrackGamma2.tpcNSigmaEl(), negTrackGamma2.tpcNSigmaEl(), gamma2.v0Type()); + + pi0coresRefs(collision.globalIndex()); + + return true; + } + + //_______________________________________________ + // Build sigma0 candidate + template + bool buildSigma0(TV0Object const& lambda, TV0Object const& gamma, TCollision const& collision, TMCParticles const& mcparticles) + { + //_______________________________________________ + // Checking if both V0s are made of the very same tracks + if (gamma.posTrackExtraId() == lambda.posTrackExtraId() || + gamma.negTrackExtraId() == lambda.negTrackExtraId()) { + return false; + } + + //_______________________________________________ + // Sigma0 pre-selections 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()}); - sigmaCandidate.Rapidity = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); + float sigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float sigmaY = -999.f; + + if constexpr (requires { gamma.pxMC(); lambda.pxMC(); }) // If MC + sigmaY = RecoDecay::y(std::array{gamma.pxMC() + lambda.pxMC(), gamma.pyMC() + lambda.pyMC(), gamma.pzMC() + lambda.pzMC()}, o2::constants::physics::MassSigma0); + else // If DATA + sigmaY = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); + + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 1.); + if (TMath::Abs(sigmaMass - o2::constants::physics::MassSigma0) > Sigma0Window) + return false; + + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 2.); + if (TMath::Abs(sigmaY) > SigmaMaxRap) + return false; - // Sigma related - float fSigmapT = sigmaCandidate.pT; - float fSigmaMass = sigmaCandidate.mass; - float fSigmaRap = sigmaCandidate.Rapidity; + histos.fill(HIST("SigmaSel/hSigmaMassSelected"), sigmaMass); + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 3.); + //_______________________________________________ + // Calculate properties & Fill tables - // Daughters related - /// Photon + // Sigma0 topological info + auto sigma0TopoInfo = propagateV0PairToDCA(gamma, lambda); + + sigma0cores(sigma0TopoInfo.X, sigma0TopoInfo.Y, sigma0TopoInfo.Z, sigma0TopoInfo.DCADau, + gamma.px(), gamma.py(), gamma.pz(), gamma.mGamma(), lambda.px(), lambda.py(), lambda.pz(), lambda.mLambda(), lambda.mAntiLambda()); + + // MC properties + if constexpr (requires { gamma.motherMCPartId(); lambda.motherMCPartId(); }) { + auto sigma0MCInfo = getV0PairMCInfo(gamma, lambda, collision, mcparticles); + + sigma0mccores(sigma0MCInfo.V0PairMCRadius, sigma0MCInfo.V0PairPDGCode, sigma0MCInfo.V0PairPDGCodeMother, sigma0MCInfo.V0PairMCProcess, sigma0MCInfo.fV0PairProducedByGenerator, + sigma0MCInfo.V01MCpx, sigma0MCInfo.V01MCpy, sigma0MCInfo.V01MCpz, + sigma0MCInfo.fIsV01Primary, sigma0MCInfo.V01PDGCode, sigma0MCInfo.V01PDGCodeMother, sigma0MCInfo.fIsV01CorrectlyAssign, + sigma0MCInfo.V02MCpx, sigma0MCInfo.V02MCpy, sigma0MCInfo.V02MCpz, + sigma0MCInfo.fIsV02Primary, sigma0MCInfo.V02PDGCode, sigma0MCInfo.V02PDGCodeMother, sigma0MCInfo.fIsV02CorrectlyAssign); + } + + // Sigma0s -> stracollisions link + sigma0CollRefs(collision.globalIndex()); + + //_______________________________________________ + // Photon extra properties 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 fPhotonPosTPCNSigma = posTrackGamma.tpcNSigmaEl(); - float fPhotonNegTPCNSigma = negTrackGamma.tpcNSigmaEl(); - 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(); - uint32_t fPhotonPosITSClSize = posTrackGamma.itsClusterSizes(); - uint32_t fPhotonNegITSClSize = negTrackGamma.itsClusterSizes(); - uint8_t fPhotonV0Type = gamma.v0Type(); - - // Lambda + uint8_t fPhotonPosTrackCode = ((uint8_t(posTrackGamma.hasTPC()) << hasTPC) | + (uint8_t(posTrackGamma.hasITSTracker()) << hasITSTracker) | + (uint8_t(posTrackGamma.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(posTrackGamma.hasTRD()) << hasTRD) | + (uint8_t(posTrackGamma.hasTOF()) << hasTOF)); + + uint8_t fPhotonNegTrackCode = ((uint8_t(negTrackGamma.hasTPC()) << hasTPC) | + (uint8_t(negTrackGamma.hasITSTracker()) << hasITSTracker) | + (uint8_t(negTrackGamma.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(negTrackGamma.hasTRD()) << hasTRD) | + (uint8_t(negTrackGamma.hasTOF()) << hasTOF)); + + sigmaPhotonExtras(gamma.qtarm(), gamma.alpha(), gamma.v0cosPA(), gamma.dcaV0daughters(), gamma.dcanegtopv(), gamma.dcapostopv(), gamma.v0radius(), gamma.z(), + posTrackGamma.tpcNSigmaEl(), negTrackGamma.tpcNSigmaEl(), posTrackGamma.tpcCrossedRows(), negTrackGamma.tpcCrossedRows(), + gamma.positiveeta(), gamma.negativeeta(), gamma.psipair(), posTrackGamma.itsNCls(), negTrackGamma.itsNCls(), posTrackGamma.itsChi2PerNcl(), negTrackGamma.itsChi2PerNcl(), + fPhotonPosTrackCode, fPhotonNegTrackCode, gamma.v0Type()); + + //_______________________________________________ + // Lambda extra properties auto posTrackLambda = lambda.template posTrackExtra_as(); auto negTrackLambda = lambda.template negTrackExtra_as(); - 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(); - float fLambdaEta = lambda.eta(); - float fLambdaY = lambda.yLambda(); - float fLambdaPosPrTPCNSigma = posTrackLambda.tpcNSigmaPr(); - float fLambdaPosPiTPCNSigma = posTrackLambda.tpcNSigmaPi(); - float fLambdaNegPrTPCNSigma = negTrackLambda.tpcNSigmaPr(); - float fLambdaNegPiTPCNSigma = negTrackLambda.tpcNSigmaPi(); - 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(); - uint32_t fLambdaPosITSClSize = posTrackLambda.itsClusterSizes(); - uint32_t fLambdaNegITSClSize = negTrackLambda.itsClusterSizes(); - uint8_t fLambdaV0Type = lambda.v0Type(); - - // Filling TTree for ML analysis - v0Sigmas(fSigmapT, fSigmaMass, fSigmaRap); - - v0SigmaPhotonExtras(fPhotonPt, fPhotonMass, fPhotonQt, fPhotonAlpha, fPhotonRadius, - fPhotonCosPA, fPhotonDCADau, fPhotonDCANegPV, fPhotonDCAPosPV, fPhotonZconv, - fPhotonEta, fPhotonY, fPhotonPosTPCNSigma, fPhotonNegTPCNSigma, fPhotonPosTPCCrossedRows, - fPhotonNegTPCCrossedRows, fPhotonPosPt, fPhotonNegPt, fPhotonPosEta, - fPhotonNegEta, fPhotonPosY, fPhotonNegY, fPhotonPsiPair, - fPhotonPosITSCls, fPhotonNegITSCls, fPhotonPosITSClSize, fPhotonNegITSClSize, - fPhotonV0Type, GammaBDTScore); - - v0SigmaLambdaExtras(fLambdaPt, fLambdaMass, fLambdaQt, fLambdaAlpha, - fLambdaRadius, fLambdaCosPA, fLambdaDCADau, fLambdaDCANegPV, - fLambdaDCAPosPV, fLambdaEta, fLambdaY, fLambdaPosPrTPCNSigma, - fLambdaPosPiTPCNSigma, fLambdaNegPrTPCNSigma, fLambdaNegPiTPCNSigma, fLambdaPosTPCCrossedRows, - fLambdaNegTPCCrossedRows, fLambdaPosPt, fLambdaNegPt, fLambdaPosEta, - fLambdaNegEta, fLambdaPosPrY, fLambdaPosPiY, fLambdaNegPrY, fLambdaNegPiY, - fLambdaPosITSCls, fLambdaNegITSCls, fLambdaPosITSClSize, fLambdaNegITSClSize, - fLambdaV0Type, LambdaBDTScore, AntiLambdaBDTScore); + uint8_t fLambdaPosTrackCode = ((uint8_t(posTrackLambda.hasTPC()) << hasTPC) | + (uint8_t(posTrackLambda.hasITSTracker()) << hasITSTracker) | + (uint8_t(posTrackLambda.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(posTrackLambda.hasTRD()) << hasTRD) | + (uint8_t(posTrackLambda.hasTOF()) << hasTOF)); + + uint8_t fLambdaNegTrackCode = ((uint8_t(negTrackLambda.hasTPC()) << hasTPC) | + (uint8_t(negTrackLambda.hasITSTracker()) << hasITSTracker) | + (uint8_t(negTrackLambda.hasITSAfterburner()) << hasITSAfterburner) | + (uint8_t(negTrackLambda.hasTRD()) << hasTRD) | + (uint8_t(negTrackLambda.hasTOF()) << hasTOF)); + + float fLambdaLifeTime = lambda.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + float fLambdaPrTOFNSigma = -999.f; + float fLambdaPiTOFNSigma = -999.f; + float fALambdaPrTOFNSigma = -999.f; + float fALambdaPiTOFNSigma = -999.f; + + if constexpr (requires { lambda.tofNSigmaLaPr(); }) { // If TOF info avaiable + fLambdaPrTOFNSigma = lambda.tofNSigmaLaPr(); + fLambdaPiTOFNSigma = lambda.tofNSigmaLaPi(); + fALambdaPrTOFNSigma = lambda.tofNSigmaALaPr(); + fALambdaPiTOFNSigma = lambda.tofNSigmaALaPi(); + } + + sigmaLambdaExtras(lambda.qtarm(), lambda.alpha(), fLambdaLifeTime, lambda.v0radius(), lambda.v0cosPA(), lambda.dcaV0daughters(), lambda.dcanegtopv(), lambda.dcapostopv(), + posTrackLambda.tpcNSigmaPr(), posTrackLambda.tpcNSigmaPi(), negTrackLambda.tpcNSigmaPr(), negTrackLambda.tpcNSigmaPi(), + fLambdaPrTOFNSigma, fLambdaPiTOFNSigma, fALambdaPrTOFNSigma, fALambdaPiTOFNSigma, + posTrackLambda.tpcCrossedRows(), negTrackLambda.tpcCrossedRows(), + lambda.positiveeta(), lambda.negativeeta(), + posTrackLambda.itsNCls(), negTrackLambda.itsNCls(), posTrackLambda.itsChi2PerNcl(), negTrackLambda.itsChi2PerNcl(), + fLambdaPosTrackCode, fLambdaNegTrackCode, lambda.v0Type()); + + return true; } - void processMonteCarlo(aod::StraCollisions const& collisions, V0DerivedMCDatas const& V0s, dauTracks const&) + // Process photon and lambda candidates to build sigma0 candidates + template + void dataProcess(TCollision const& collisions, TV0s const& fullV0s, TMCParticles const& mcparticles) { + //_______________________________________________ + // Initial setup + // Auxiliary vectors to store best candidates + std::vector bestGammasArray; + std::vector bestLambdasArray; + + // Custom grouping + std::vector> v0grouped(collisions.size()); + + for (const auto& v0 : fullV0s) { + v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + + //_______________________________________________ + // Collisions loop for (const auto& coll : collisions) { - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = coll.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollisionMCDerived, collIdx); + // Clear vectors + bestGammasArray.clear(); + bestLambdasArray.clear(); - // V0 table sliced - for (auto& gamma : V0Table_thisCollision) { // selecting photons from Sigma0 - for (auto& lambda : V0Table_thisCollision) { // selecting lambdas from Sigma0 - if (!processSigmaCandidate(lambda, gamma)) - continue; + float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); + histos.fill(HIST("hEventCentrality"), centrality); - bool fIsSigma = false; - if ((gamma.pdgCode() == 22) && (gamma.pdgCodeMother() == 3212) && (lambda.pdgCode() == 3122) && (lambda.pdgCodeMother() == 3212) && (gamma.motherMCPartId() == lambda.motherMCPartId())) - fIsSigma = true; + //_______________________________________________ + // V0s loop + for (size_t i = 0; i < v0grouped[coll.globalIndex()].size(); i++) { + auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); - v0MCSigmas(fIsSigma); + if (processPhotonCandidate(v0, coll)) // selecting photons + bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates + } + + //_______________________________________________ + // Wrongly collision association study (MC-specific) + if constexpr (requires { coll.StraMCCollisionId(); }) { + if (doAssocStudy) { + analyzeV0CollAssoc(coll, fullV0s, bestGammasArray, true); // Photon-analysis + analyzeV0CollAssoc(coll, fullV0s, bestLambdasArray, false); // Lambda-analysis } } - } - } - void processSTDSelection(soa::Join const& collisions, V0StandardDerivedDatas const& V0s, dauTracks const&) - { - for (const auto& coll : collisions) { - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = coll.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollisionSTDDerived, collIdx); - - histos.fill(HIST("hEventVertexZ"), coll.posZ()); - v0sigma0Coll(coll.posX(), coll.posY(), coll.posZ(), coll.centFT0M(), coll.centFT0A(), coll.centFT0C(), coll.centFV0A()); - - // V0 table sliced - for (auto& gamma : V0Table_thisCollision) { // selecting photons from Sigma0 - for (auto& lambda : V0Table_thisCollision) { // selecting lambdas from Sigma0 - if (!processSigmaCandidate(lambda, gamma)) // applying selection for reconstruction - continue; - - nSigmaCandidates++; - if (nSigmaCandidates % 5000 == 0) { - LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; + //_______________________________________________ + // V0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + + //_______________________________________________ + // Sigma0 loop + if (fillSigma0Tables) { + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate & filling tables + if (!buildSigma0(lambda, gamma1, coll, mcparticles)) + continue; } - v0Sigma0CollRefs(v0sigma0Coll.lastIndex()); - fillTables(lambda, gamma); // filling tables with accepted candidates } - } - } - } - void processMLSelection(soa::Join const& collisions, V0MLDerivedDatas const& V0s, dauTracks const&) - { - for (const auto& coll : collisions) { - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = coll.globalIndex(); - auto V0Table_thisCollision = V0s.sliceBy(perCollisionMLDerived, collIdx); - - histos.fill(HIST("hEventVertexZ"), coll.posZ()); - v0sigma0Coll(coll.posX(), coll.posY(), coll.posZ(), coll.centFT0M(), coll.centFT0A(), coll.centFT0C(), coll.centFV0A()); - - // V0 table sliced - for (auto& gamma : V0Table_thisCollision) { // selecting photons from Sigma0 - for (auto& lambda : V0Table_thisCollision) { // selecting lambdas from Sigma0 - if (!processSigmaCandidate(lambda, gamma)) - continue; - - nSigmaCandidates++; - if (nSigmaCandidates % 5000 == 0) { - LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; + //_______________________________________________ + // pi0 loop + if (fillPi0Tables) { + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + + // Building pi0 candidate & filling tables + if (!buildPi0(gamma1, gamma2, coll, mcparticles)) + continue; } - v0Sigma0CollRefs(v0sigma0Coll.lastIndex()); - fillTables(lambda, gamma); // filling tables with accepted candidates } } } } - PROCESS_SWITCH(sigma0builder, processMonteCarlo, "Fill sigma0 MC table", false); - PROCESS_SWITCH(sigma0builder, processSTDSelection, "Select gammas and lambdas with standard cuts", true); - PROCESS_SWITCH(sigma0builder, processMLSelection, "Select gammas and lambdas with ML", false); + + void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + dataProcess(collisions, fullV0s, nullptr); + } + + void processRealDataWithTOF(soa::Join const& collisions, V0TOFStandardDerivedDatas const& fullV0s, dauTracks const&) + { + dataProcess(collisions, fullV0s, nullptr); + } + + void processMonteCarlo(soa::Join const& collisions, V0DerivedMCDatas const& fullV0s, aod::McParticles const& mcParticles, dauTracks const&, aod::MotherMCParts const&, soa::Join const&, soa::Join const&) + { + dataProcess(collisions, fullV0s, mcParticles); + } + + void processMonteCarloWithTOF(soa::Join const& collisions, V0TOFDerivedMCDatas const& fullV0s, aod::McParticles const& mcParticles, dauTracks const&, aod::MotherMCParts const&, soa::Join const&, soa::Join const&) + { + dataProcess(collisions, fullV0s, mcParticles); + } + + // Simulated processing in Run 3 - run this over original AO2Ds + void processGeneratedRun3(aod::McParticles const& mcParticles) + { + genProcess(mcParticles); + } + + PROCESS_SWITCH(sigma0builder, processRealData, "process as if real data", true); + PROCESS_SWITCH(sigma0builder, processRealDataWithTOF, "process as if real data", false); + PROCESS_SWITCH(sigma0builder, processMonteCarlo, "process as if MC data", false); + PROCESS_SWITCH(sigma0builder, processMonteCarloWithTOF, "process as if MC data, uses TOF PID info", false); + PROCESS_SWITCH(sigma0builder, processGeneratedRun3, "process generated MC info", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/TableProducer/Strangeness/sigmaminustask.cxx b/PWGLF/TableProducer/Strangeness/sigmaminustask.cxx new file mode 100644 index 00000000000..d2b3e92ea22 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/sigmaminustask.cxx @@ -0,0 +1,765 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFKinkDecayTables.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using TracksFull = soa::Join; +using CollisionsFull = soa::Join; +using CollisionsFullMC = soa::Join; + +struct sigmaminustask { + + // Output Tables + Produces outputDataTable; + Produces outputDataTableMC; + + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rSigmaMinus{"sigmaminus", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rFindable{"findable", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cutNSigmaPi{"cutNSigmaPi", 4, "NSigmaTPCPion"}; + Configurable cutRapMotherMC{"cutRapMotherMC", 1.0f, "Rapidity cut for mother Sigma in MC"}; + Configurable cutMinQtAP{"cutMinQtAP", 0.15f, "Minimum Qt for Armenteros-Podolanski cut"}; + Configurable cutMaxQtAP{"cutMaxQtAP", 0.20f, "Maximum Qt for Armenteros-Podolanski cut"}; + Configurable cutPtGen{"cutPtGen", 0.5f, "Minimum pT for generated sigma particles"}; + + Configurable> mothPdgCodes{"mothPdgCodes", std::vector{3112, 3222}, "PDG codes of the selected mother particles"}; + Configurable> daugPdgCodes{"daugPdgCodes", std::vector{211, 2212}, "PDG codes of the selected charged daughter particles"}; + + Configurable fillOutputTree{"fillOutputTree", true, "If true, fill the output tree with Kink candidates"}; + + // Configurables for findable tracks (kinkBuilder.cxx efficiency) + Configurable minPtMothKB{"minPtMothKB", 0.5f, "Minimum pT of the mother"}; + Configurable maxPhiDiffKB{"maxPhiDiffKB", 100.0f, "Max phi difference between the kink daughter and the mother"}; + Configurable maxZDiffKB{"maxZDiffKB", 20.0f, "Max z difference between the kink daughter and the mother"}; + Configurable etaMaxKB{"etaMaxKB", 1.0f, "Max eta for both mother and daughter"}; + Configurable nTPCClusMinDaugKB{"nTPCClusMinDaugKB", 80, "Min daug NTPC clusters"}; + Configurable radiusCutKB{"radiusCutKB", 19.6213f, "Min reconstructed decay radius of the mother"}; + Configurable maxDcaMothPvKB{"maxDcaMothPvKB", 0.1f, "Max DCA of the mother to PV"}; + Configurable minDcaDaugPvKB{"minDcaDaugPvKB", 0.1f, "Min DCA of the daughter to PV"}; + + Preslice mPerCol = aod::track::collisionId; + + // Constants and castings + float radToDeg = o2::constants::math::Rad2Deg; + std::vector cast_mothPdgCodes, cast_daugPdgCodes; + + // Services CCDB + Service ccdb; + Configurable ccdbPath{"ccdbPath", "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 cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; + + // Runtime variables + int mRunNumber = 0; + float mBz = 0.0f; + o2::base::MatLayerCylSet* matLUT = nullptr; + + void init(InitContext const&) + { + // Initialize CCDB + ccdb->setURL(ccdbPath); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(true); + + matLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + + // Axes + const AxisSpec ptAxis{100, -10, 10, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ptUnsignedAxis{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec nSigmaPiAxis{60, -30, 30, "n#sigma_{#pi}"}; + const AxisSpec nSigmaPrAxis{60, -30, 30, "n#sigma_{p}"}; + const AxisSpec sigmaMassAxis{100, 1.1, 1.4, "m (GeV/#it{c}^{2})"}; + const AxisSpec xiMassAxis{100, 1.2, 1.6, "m_{#Xi} (GeV/#it{c}^{2})"}; + const AxisSpec pdgAxis{10001, -5000, 5000, "PDG code"}; + const AxisSpec vertexZAxis{100, -15., 15., "vrtx_{Z} [cm]"}; + const AxisSpec dcaMothAxis{800, 0, 200, "DCA [#mu m]"}; + const AxisSpec dcaDaugAxis{200, 0, 20, "DCA [cm]"}; + const AxisSpec radiusAxis{100, -1, 40, "Decay radius [cm]"}; + const AxisSpec alphaAPAxis{200, -1.0, 1.0, "#alpha_{AP}"}; + const AxisSpec qtAPAxis{200, 0.0, 0.5, "q_{T,AP}"}; + const AxisSpec cosPointingAngleAxis{100, -1.0, 1.0, "Cos#theta_{PA}"}; + const AxisSpec kinkAngleAxis{100, 0, 100, "Kink angle (deg)"}; + + const AxisSpec ptResolutionAxis{100, -1.0, 1.0, "(#it{p}_{T}^{rec} - #it{p}_{T}^{gen}) / #it{p}_{T}^{gen}"}; + const AxisSpec massResolutionAxis{100, -0.5, 0.5, "(m_{rec} - m_{gen}) / m_{gen}"}; + const AxisSpec radiusResolutionAxis{100, -0.5, 0.5, "(r_{rec} - r_{gen}) / r_{gen}"}; + + const AxisSpec boolAxis{2, -0.5, 1.5, "Boolean value"}; + const AxisSpec filtersAxis{12, -0.5, 11.5, "Filter index"}; + const AxisSpec fakeITSAxis{8, -1.5, 6.5, "Fake ITS cluster layer"}; + + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + // Sigma-minus reconstruction + rSigmaMinus.add("h2MassSigmaMinusPt", "h2MassSigmaMinusPt", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); + rSigmaMinus.add("h2SigmaMassVsXiMass", "h2SigmaMassVsXiMass", {HistType::kTH2F, {xiMassAxis, sigmaMassAxis}}); + rSigmaMinus.add("h2NSigmaTPCPiPt", "h2NSigmaTPCPiPt", {HistType::kTH2F, {ptAxis, nSigmaPiAxis}}); + rSigmaMinus.add("h2DCAMothPt", "h2DCAMothPt", {HistType::kTH2F, {ptAxis, dcaMothAxis}}); + rSigmaMinus.add("h2DCADaugPt", "h2DCADaugPt", {HistType::kTH2F, {ptAxis, dcaDaugAxis}}); + rSigmaMinus.add("h2ArmenterosPreCuts", "h2ArmenterosPreCuts", {HistType::kTH2F, {alphaAPAxis, qtAPAxis}}); + rSigmaMinus.add("h2ArmenterosPostCuts", "h2ArmenterosPostCuts", {HistType::kTH2F, {alphaAPAxis, qtAPAxis}}); + rSigmaMinus.add("h2CosPointingAnglePt", "h2CosPointingAnglePt", {HistType::kTH2F, {ptAxis, cosPointingAngleAxis}}); + + if (doprocessMC) { + // Add MC histograms if needed + rSigmaMinus.add("h2MassPtMCRec", "h2MassPtMCRec", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); + rSigmaMinus.add("h2MassPtMCGen", "h2MassPtMCGen", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); + rSigmaMinus.add("h2KinkAngleVsPtMothMC", "h2KinkAngleVsPtMothMC", {HistType::kTH2F, {ptAxis, kinkAngleAxis}}); + + rSigmaMinus.add("h2MassResolution", "h2MassResolution", {HistType::kTH2F, {ptAxis, massResolutionAxis}}); + rSigmaMinus.add("h2PtResolution", "h2PtResolution", {HistType::kTH2F, {ptAxis, ptResolutionAxis}}); + rSigmaMinus.add("h2RadiusResolution", "h2RadiusResolution", {HistType::kTH2F, {ptAxis, radiusResolutionAxis}}); + + rSigmaMinus.add("h2NSigmaTOFPiPt", "h2NSigmaTOFPiPt", {HistType::kTH2F, {ptAxis, nSigmaPiAxis}}); + rSigmaMinus.add("h2NSigmaTOFPrPt", "h2NSigmaTOFPrPt", {HistType::kTH2F, {ptAxis, nSigmaPrAxis}}); + + // BC ID comparison histograms + rSigmaMinus.add("hMcCollIdCoherence", "McCollId (coll == daug)", {HistType::kTH1F, {boolAxis}}); + rSigmaMinus.add("h2CollId_BCId", "(McCollId coherence) vs (EvSelBC == McBC)", {HistType::kTH2F, {boolAxis, boolAxis}}); + rSigmaMinus.add("h2BCId_comp", "(McBC == EvSelBC) vs (BC == EvSelBC)", {HistType::kTH2F, {boolAxis, boolAxis}}); + } + + if (doprocessFindable) { + std::vector filterLabels = {"Initial", "ITS/TPC present", "ITS/TPC quality", "Moth p_{T}", "max #eta", "max #Delta#phi", "max #Delta Z", "max DCAmoth", "min DCAdaug", "min Radius", "sel8 coll", "Daug TOF"}; + + // Add findable Sigma histograms + rFindable.add("hfakeITSfindable", "hfakeITSfindable", {HistType::kTH1F, {fakeITSAxis}}); + rFindable.add("hFilterIndex", "hFilterIndex", {HistType::kTH1F, {filtersAxis}}); + rFindable.add("h2MCRadiusFilterIndex", "h2MCRadiusFilterIndex", {HistType::kTH2F, {filtersAxis, radiusAxis}}); + rFindable.add("h2RecRadiusFilterIndex", "h2RecRadiusFilterIndex", {HistType::kTH2F, {filtersAxis, radiusAxis}}); + + auto hFilterIndex = rFindable.get(HIST("hFilterIndex")); + auto h2MCRadiusFilterIndex = rFindable.get(HIST("h2MCRadiusFilterIndex")); + auto h2RecRadiusFilterIndex = rFindable.get(HIST("h2RecRadiusFilterIndex")); + for (size_t i = 0; i < filterLabels.size(); ++i) { + hFilterIndex->GetXaxis()->SetBinLabel(i + 1, filterLabels[i].c_str()); + h2MCRadiusFilterIndex->GetXaxis()->SetBinLabel(i + 1, filterLabels[i].c_str()); + h2RecRadiusFilterIndex->GetXaxis()->SetBinLabel(i + 1, filterLabels[i].c_str()); + } + + // Sigma minus and plus specific histograms + rFindable.add("h2MCRadiusFilter_sigmaplus_protonkink", "h2MCRadiusFilter_sigmaplus_protonkink", {HistType::kTH2F, {filtersAxis, radiusAxis}}); + rFindable.add("h2MCRadiusFilter_sigmaplus_pikink", "h2MCRadiusFilter_sigmaplus_pikink", {HistType::kTH2F, {filtersAxis, radiusAxis}}); + rFindable.add("h2MCRadiusFilter_sigmaminus_pikink", "h2MCRadiusFilter_sigmaminus_pikink", {HistType::kTH2F, {filtersAxis, radiusAxis}}); + + rFindable.add("h2PtFilter_sigmaplus_protonkink", "h2PtFilter_sigmaplus_protonkink", {HistType::kTH2F, {filtersAxis, ptUnsignedAxis}}); + rFindable.add("h2PtFilter_sigmaplus_pikink", "h2PtFilter_sigmaplus_pikink", {HistType::kTH2F, {filtersAxis, ptUnsignedAxis}}); + rFindable.add("h2PtFilter_sigmaminus_pikink", "h2PtFilter_sigmaminus_pikink", {HistType::kTH2F, {filtersAxis, ptUnsignedAxis}}); + + rFindable.add("h2PtDaugFilter_sigmaplus_protonkink", "h2PtDaugFilter_sigmaplus_protonkink", {HistType::kTH2F, {filtersAxis, ptUnsignedAxis}}); + rFindable.add("h2PtDaugFilter_sigmaplus_pikink", "h2PtDaugFilter_sigmaplus_pikink", {HistType::kTH2F, {filtersAxis, ptUnsignedAxis}}); + rFindable.add("h2PtDaugFilter_sigmaminus_pikink", "h2PtDaugFilter_sigmaminus_pikink", {HistType::kTH2F, {filtersAxis, ptUnsignedAxis}}); + + rFindable.add("h2DCAMothPt_protonkink", "h2DCAMothPt_protonkink", {HistType::kTH2F, {ptUnsignedAxis, dcaMothAxis}}); + rFindable.add("h2DCADaugPt_protonkink", "h2DCADaugPt_protonkink", {HistType::kTH2F, {ptUnsignedAxis, dcaDaugAxis}}); + rFindable.add("h2DCAMothPt_pikink", "h2DCAMothPt_pikink", {HistType::kTH2F, {ptUnsignedAxis, dcaMothAxis}}); + rFindable.add("h2DCADaugPt_pikink", "h2DCADaugPt_pikink", {HistType::kTH2F, {ptUnsignedAxis, dcaDaugAxis}}); + } + + // Cast configurables to std::vector + cast_mothPdgCodes = (std::vector)mothPdgCodes; + cast_daugPdgCodes = (std::vector)daugPdgCodes; + } + + void initCCDB(aod::BCs::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + LOG(info) << "Initializing CCDB for run " << mRunNumber; + o2::parameters::GRPMagField* grpmag = ccdb->getForRun(grpmagPath, mRunNumber); + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = grpmag->getNominalL3Field(); + if (!matLUT) { + matLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + } + o2::base::Propagator::Instance()->setMatLUT(matLUT); + LOG(info) << "Task initialized for run " << mRunNumber << " with magnetic field " << mBz << " kZG"; + } + + float alphaAP(const std::array& momMother, const std::array& momKink) + { + std::array momMissing = {momMother[0] - momKink[0], momMother[1] - momKink[1], momMother[2] - momKink[2]}; + float lQlP = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); + float lQlN = std::inner_product(momMother.begin(), momMother.end(), momMissing.begin(), 0.f); + return (lQlP - lQlN) / (lQlP + lQlN); + } + + float qtAP(const std::array& momMother, const std::array& momKink) + { + float dp = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); + float p2V0 = std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f); + float p2A = std::inner_product(momKink.begin(), momKink.end(), momKink.begin(), 0.f); + return std::sqrt(p2A - dp * dp / p2V0); + } + + float cosPAngle(const std::array& momMother, const std::array& posMother, const std::array& posKink) + { + std::array vMother = {posKink[0] - posMother[0], posKink[1] - posMother[1], posKink[2] - posMother[2]}; + float pMother = std::sqrt(std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f)); + float vMotherNorm = std::sqrt(std::inner_product(vMother.begin(), vMother.end(), vMother.begin(), 0.f)); + return (std::inner_product(momMother.begin(), momMother.end(), vMother.begin(), 0.f)) / (pMother * vMotherNorm); + } + + float kinkAngle(std::array const& p_moth, std::array const& p_daug) + { + float dotProduct = std::inner_product(p_moth.begin(), p_moth.end(), p_daug.begin(), 0.0f); + float magMoth = std::hypot(p_moth[0], p_moth[1], p_moth[2]); + float magDaug = std::hypot(p_daug[0], p_daug[1], p_daug[2]); + return std::acos(dotProduct / (magMoth * magDaug)) * radToDeg; + } + + void processData(CollisionsFull::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 (std::abs(dauTrack.tpcNSigmaPi()) > cutNSigmaPi) { + continue; + } + + float alphaAPValue = alphaAP(std::array{kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth()}, std::array{kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug()}); + float qtValue = qtAP(std::array{kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth()}, std::array{kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug()}); + rSigmaMinus.fill(HIST("h2ArmenterosPreCuts"), alphaAPValue, qtValue); + + if (qtValue < cutMinQtAP || qtValue > cutMaxQtAP) { + continue; + } + float cosPointingAngleRec = cosPAngle(std::array{kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth()}, + std::array{0.0f, 0.0f, 0.0f}, + std::array{kinkCand.xDecVtx(), kinkCand.yDecVtx(), kinkCand.zDecVtx()}); + rSigmaMinus.fill(HIST("h2CosPointingAnglePt"), kinkCand.mothSign() * kinkCand.ptMoth(), cosPointingAngleRec); + rSigmaMinus.fill(HIST("h2ArmenterosPostCuts"), alphaAPValue, qtValue); + rSigmaMinus.fill(HIST("h2MassSigmaMinusPt"), kinkCand.mothSign() * kinkCand.ptMoth(), kinkCand.mSigmaMinus()); + rSigmaMinus.fill(HIST("h2SigmaMassVsXiMass"), kinkCand.mXiMinus(), kinkCand.mSigmaMinus()); + rSigmaMinus.fill(HIST("h2NSigmaTPCPiPt"), kinkCand.mothSign() * kinkCand.ptMoth(), dauTrack.tpcNSigmaPi()); + rSigmaMinus.fill(HIST("h2DCAMothPt"), kinkCand.mothSign() * kinkCand.ptMoth(), kinkCand.dcaMothPv()); + rSigmaMinus.fill(HIST("h2DCADaugPt"), kinkCand.mothSign() * kinkCand.ptDaug(), kinkCand.dcaDaugPv()); + + if (fillOutputTree) { + outputDataTable(kinkCand.xDecVtx(), kinkCand.yDecVtx(), kinkCand.zDecVtx(), + kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth(), + kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug(), + kinkCand.dcaMothPv(), kinkCand.dcaDaugPv(), kinkCand.dcaKinkTopo(), + kinkCand.mothSign(), + dauTrack.tpcNSigmaPi(), dauTrack.tpcNSigmaPr(), dauTrack.tpcNSigmaKa(), + dauTrack.tofNSigmaPi(), dauTrack.tofNSigmaPr(), dauTrack.tofNSigmaKa()); + } + } + } + PROCESS_SWITCH(sigmaminustask, processData, "Data processing", true); + + void processMC(CollisionsFullMC const& collisions, aod::KinkCands const& KinkCands, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC, TracksFull const&, aod::McCollisions const&) + { + for (const auto& collision : collisions) { + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { + continue; + } + + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + auto kinkCandPerColl = KinkCands.sliceBy(mPerCol, collision.globalIndex()); + + for (const auto& kinkCand : kinkCandPerColl) { + + auto dauTrack = kinkCand.trackDaug_as(); + auto mothTrack = kinkCand.trackMoth_as(); + if (dauTrack.sign() != mothTrack.sign()) { + LOG(info) << "Skipping kink candidate with opposite sign daughter and mother: " << kinkCand.globalIndex(); + continue; // Skip if the daughter has the opposite sign as the mother + } + if (std::abs(dauTrack.tpcNSigmaPi()) > cutNSigmaPi) { + continue; + } + + // histograms filled with all kink candidates + float alphaAPValue = alphaAP(std::array{kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth()}, std::array{kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug()}); + float qtValue = qtAP(std::array{kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth()}, std::array{kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug()}); + rSigmaMinus.fill(HIST("h2ArmenterosPreCuts"), alphaAPValue, qtValue); + rSigmaMinus.fill(HIST("h2MassSigmaMinusPt"), kinkCand.mothSign() * kinkCand.ptMoth(), kinkCand.mSigmaMinus()); + rSigmaMinus.fill(HIST("h2SigmaMassVsXiMass"), kinkCand.mXiMinus(), kinkCand.mSigmaMinus()); + rSigmaMinus.fill(HIST("h2NSigmaTPCPiPt"), kinkCand.mothSign() * kinkCand.ptMoth(), dauTrack.tpcNSigmaPi()); + + // do MC association + auto mcLabMoth = trackLabelsMC.rawIteratorAt(mothTrack.globalIndex()); + auto mcLabDaug = trackLabelsMC.rawIteratorAt(dauTrack.globalIndex()); + if (mcLabMoth.has_mcParticle() && mcLabDaug.has_mcParticle()) { + auto mcTrackMoth = mcLabMoth.mcParticle_as(); + auto mcTrackDaug = mcLabDaug.mcParticle_as(); + if (!mcTrackDaug.has_mothers()) { + continue; + } + + for (const auto& mcMother : mcTrackDaug.mothers_as()) { + if (mcMother.globalIndex() != mcTrackMoth.globalIndex()) { + continue; + } + + // Select only valid mother and daughter + bool isValidMother = false; + bool isValidDaughter = false; + for (const int pdgCode : cast_mothPdgCodes) { + if (std::abs(mcTrackMoth.pdgCode()) == pdgCode) { + isValidMother = true; + break; + } + } + + for (const int pdgCode : cast_daugPdgCodes) { + if (std::abs(mcTrackDaug.pdgCode()) == pdgCode) { + isValidDaughter = true; + break; + } + } + + if (!isValidMother || !isValidDaughter) { + continue; + } + + float motherMassMC = std::sqrt(mcMother.e() * mcMother.e() - mcMother.p() * mcMother.p()); + float motherPtMC = mcMother.pt(); + float motherPzMC = mcMother.pz(); + float deltaXMother = mcTrackDaug.vx() - mcMother.vx(); + float deltaYMother = mcTrackDaug.vy() - mcMother.vy(); + float decayRadiusMC = std::sqrt(deltaXMother * deltaXMother + deltaYMother * deltaYMother); + float decayRadiusRec = std::sqrt(kinkCand.xDecVtx() * kinkCand.xDecVtx() + kinkCand.yDecVtx() * kinkCand.yDecVtx()); + float cosPointingAngleRec = cosPAngle(std::array{kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth()}, + std::array{0.0f, 0.0f, 0.0f}, + std::array{kinkCand.xDecVtx(), kinkCand.yDecVtx(), kinkCand.zDecVtx()}); + + // Check coherence of MCcollision Id for daughter MCparticle and reconstructed collision + bool mcCollisionIdCheck = false; + if (collision.has_mcCollision()) { + mcCollisionIdCheck = collision.mcCollision().globalIndex() == mcTrackDaug.mcCollisionId(); + } + + // Check bunch crossing ID coherence + auto mcCollision = mcTrackDaug.template mcCollision_as(); + bool bcIdVsEvSel = (collision.bcId() == collision.foundBCId()); + bool evSelVsMcbcId = (collision.foundBCId() == mcCollision.bcId()); + + rSigmaMinus.fill(HIST("hMcCollIdCoherence"), static_cast(mcCollisionIdCheck)); + rSigmaMinus.fill(HIST("h2CollId_BCId"), static_cast(mcCollisionIdCheck), static_cast(evSelVsMcbcId)); + rSigmaMinus.fill(HIST("h2BCId_comp"), static_cast(evSelVsMcbcId), static_cast(bcIdVsEvSel)); + + rSigmaMinus.fill(HIST("h2MassPtMCRec"), kinkCand.mothSign() * kinkCand.ptMoth(), kinkCand.mSigmaMinus()); + rSigmaMinus.fill(HIST("h2MassResolution"), kinkCand.mothSign() * kinkCand.ptMoth(), (kinkCand.mSigmaMinus() - motherMassMC) / motherMassMC); + rSigmaMinus.fill(HIST("h2PtResolution"), kinkCand.mothSign() * kinkCand.ptMoth(), (kinkCand.ptMoth() - motherPtMC) / motherPtMC); + rSigmaMinus.fill(HIST("h2RadiusResolution"), kinkCand.mothSign() * kinkCand.ptMoth(), (decayRadiusRec - decayRadiusMC) / decayRadiusMC); + rSigmaMinus.fill(HIST("h2DCAMothPt"), kinkCand.mothSign() * kinkCand.ptMoth(), kinkCand.dcaMothPv()); + rSigmaMinus.fill(HIST("h2DCADaugPt"), kinkCand.mothSign() * kinkCand.ptMoth(), kinkCand.dcaDaugPv()); + rSigmaMinus.fill(HIST("h2CosPointingAnglePt"), kinkCand.mothSign() * kinkCand.ptMoth(), cosPointingAngleRec); + rSigmaMinus.fill(HIST("h2ArmenterosPostCuts"), alphaAPValue, qtValue); + + rSigmaMinus.fill(HIST("h2NSigmaTOFPiPt"), kinkCand.mothSign() * kinkCand.ptMoth(), dauTrack.tofNSigmaPi()); + rSigmaMinus.fill(HIST("h2NSigmaTOFPrPt"), kinkCand.mothSign() * kinkCand.ptMoth(), dauTrack.tofNSigmaPr()); + + // fill the output table with Mc information + if (fillOutputTree) { + outputDataTableMC(kinkCand.xDecVtx(), kinkCand.yDecVtx(), kinkCand.zDecVtx(), + kinkCand.pxMoth(), kinkCand.pyMoth(), kinkCand.pzMoth(), + kinkCand.pxDaug(), kinkCand.pyDaug(), kinkCand.pzDaug(), + kinkCand.dcaMothPv(), kinkCand.dcaDaugPv(), kinkCand.dcaKinkTopo(), + kinkCand.mothSign(), + dauTrack.tpcNSigmaPi(), dauTrack.tpcNSigmaPr(), dauTrack.tpcNSigmaKa(), + dauTrack.tofNSigmaPi(), dauTrack.tofNSigmaPr(), dauTrack.tofNSigmaKa(), + mcTrackMoth.pdgCode(), mcTrackDaug.pdgCode(), + motherPtMC, motherPzMC, motherMassMC, decayRadiusMC, mcCollisionIdCheck); + } + } + } // MC association and selection + } // kink cand loop + } // collision loop + + // Loop over all generated particles to fill MC histograms + for (const auto& mcPart : particlesMC) { + if (std::abs(mcPart.y()) > cutRapMotherMC) { // rapidity cut + continue; + } + + bool isValidMother = false; + for (const int pdgCode : cast_mothPdgCodes) { + if (std::abs(mcPart.pdgCode()) == pdgCode) { + isValidMother = true; + break; + } + } + if (!isValidMother) { + continue; // Skip if not a valid mother + } + + if (mcPart.pt() < cutPtGen) { + continue; // Skip if pT is below threshold + } + + if (!mcPart.has_daughters()) { + continue; // Skip if no daughters + } + + bool hasValidDaughter = false; + int daugPdg = 0; + std::array secVtx; + std::array momDaug; + for (const auto& daughter : mcPart.daughters_as()) { + for (const int pdgCode : cast_daugPdgCodes) { + if (std::abs(daughter.pdgCode()) == pdgCode) { + hasValidDaughter = true; + secVtx = {daughter.vx(), daughter.vy(), daughter.vz()}; + momDaug = {daughter.px(), daughter.py(), daughter.pz()}; + daugPdg = daughter.pdgCode(); + break; // Found a daughter, exit loop + } + } + if (hasValidDaughter) { + break; // Exit outer loop if a valid daughter is found + } + } + if (!hasValidDaughter) { + continue; // Skip if no good daughter found + } + + float mcMass = std::sqrt(mcPart.e() * mcPart.e() - mcPart.p() * mcPart.p()); + float mcDecayRadius = std::sqrt((secVtx[0] - mcPart.vx()) * (secVtx[0] - mcPart.vx()) + (secVtx[1] - mcPart.vy()) * (secVtx[1] - mcPart.vy())); + int mothSign = mcPart.pdgCode() > 0 ? 1 : -1; // Determine the sign of the Sigma + float kinkAngleMC = kinkAngle({mcPart.px(), mcPart.py(), mcPart.pz()}, momDaug); + rSigmaMinus.fill(HIST("h2MassPtMCGen"), mothSign * mcPart.pt(), mcMass); + rSigmaMinus.fill(HIST("h2KinkAngleVsPtMothMC"), mothSign * mcPart.pt(), kinkAngleMC); + + // Fill output table with non reconstructed MC candidates + if (fillOutputTree) { + outputDataTableMC(-999, -999, -999, + -999, -999, -999, + -999, -999, -999, + -999, -999, -999, + mothSign, + -999, -999, -999, + -999, -999, -999, + mcPart.pdgCode(), daugPdg, + mcPart.pt(), mcPart.pz(), mcMass, mcDecayRadius, false); + } + } + } + PROCESS_SWITCH(sigmaminustask, processMC, "MC processing", false); + + void fillFindableHistograms(int filterIndex, float mcRadius, float recRadius, float ptMoth, float ptDaug, int mothPdgCode, int daugPdgCode) + { + rFindable.fill(HIST("hFilterIndex"), filterIndex); + rFindable.fill(HIST("h2MCRadiusFilterIndex"), filterIndex, mcRadius); + rFindable.fill(HIST("h2RecRadiusFilterIndex"), filterIndex, recRadius); + + if (std::abs(mothPdgCode) == PDG_t::kSigmaMinus && std::abs(daugPdgCode) == PDG_t::kPiMinus) { + rFindable.fill(HIST("h2MCRadiusFilter_sigmaminus_pikink"), filterIndex, mcRadius); + rFindable.fill(HIST("h2PtFilter_sigmaminus_pikink"), filterIndex, ptMoth); + rFindable.fill(HIST("h2PtDaugFilter_sigmaminus_pikink"), filterIndex, ptDaug); + } else if (std::abs(mothPdgCode) == PDG_t::kSigmaPlus && std::abs(daugPdgCode) == PDG_t::kPiPlus) { + rFindable.fill(HIST("h2MCRadiusFilter_sigmaplus_pikink"), filterIndex, mcRadius); + rFindable.fill(HIST("h2PtFilter_sigmaplus_pikink"), filterIndex, ptMoth); + rFindable.fill(HIST("h2PtDaugFilter_sigmaplus_pikink"), filterIndex, ptDaug); + } else if (std::abs(mothPdgCode) == PDG_t::kSigmaPlus && std::abs(daugPdgCode) == PDG_t::kProton) { + rFindable.fill(HIST("h2MCRadiusFilter_sigmaplus_protonkink"), filterIndex, mcRadius); + rFindable.fill(HIST("h2PtFilter_sigmaplus_protonkink"), filterIndex, ptMoth); + rFindable.fill(HIST("h2PtDaugFilter_sigmaplus_protonkink"), filterIndex, ptDaug); + } + } + + void processFindable(aod::KinkCands const& kinkCands, aod::McTrackLabels const& trackLabelsMC, + TracksFull const& tracks, aod::McParticles const&, CollisionsFullMC const&, aod::BCs const&) + { + // A - generated findable track pairs map: mcMother.globalIndex() -> (motherTrack.globalIndex(), daughterTrack.globalIndex()) + std::unordered_map> allCandsIndices; + + for (const auto& track : tracks) { + auto mcLabel = trackLabelsMC.rawIteratorAt(track.globalIndex()); + if (!mcLabel.has_mcParticle()) { + continue; + } + auto mcParticle = mcLabel.mcParticle_as(); + bool isValidMother = false; + for (const int pdgCode : cast_mothPdgCodes) { + if (std::abs(mcParticle.pdgCode()) == pdgCode) { + isValidMother = true; + break; + } + } + if (mcParticle.has_daughters() && isValidMother) { + allCandsIndices[mcParticle.globalIndex()] = {track.globalIndex(), -1}; + } + } + + for (const auto& track : tracks) { + auto mcLabel = trackLabelsMC.rawIteratorAt(track.globalIndex()); + if (!mcLabel.has_mcParticle()) { + continue; + } + auto mcParticle = mcLabel.mcParticle_as(); + bool isValidDaughter = false; + for (const int pdgCode : cast_daugPdgCodes) { + if (std::abs(mcParticle.pdgCode()) == pdgCode) { + isValidDaughter = true; + break; + } + } + + if (mcParticle.has_mothers() && isValidDaughter) { + for (const auto& mother : mcParticle.mothers_as()) { + auto it = allCandsIndices.find(mother.globalIndex()); + if (it != allCandsIndices.end()) { + it->second.second = track.globalIndex(); + break; + } + } + } + } + + // B - reconstructed kinkcands map: mcMother.globalIndex() -> kinkCand.globalIndex() + std::unordered_map findableToKinkCand; + for (const auto& kinkCand : kinkCands) { + auto motherTrack = kinkCand.trackMoth_as(); + auto daughterTrack = kinkCand.trackDaug_as(); + + auto mcLabMoth = trackLabelsMC.rawIteratorAt(motherTrack.globalIndex()); + auto mcLabDaug = trackLabelsMC.rawIteratorAt(daughterTrack.globalIndex()); + if (!mcLabMoth.has_mcParticle() || !mcLabDaug.has_mcParticle()) { + continue; + } + auto mcMother = mcLabMoth.mcParticle_as(); + auto mcDaughter = mcLabDaug.mcParticle_as(); + + bool isValidMother = false; + for (const int pdgCode : cast_mothPdgCodes) { + if (std::abs(mcMother.pdgCode()) == pdgCode) { + isValidMother = true; + break; + } + } + bool isValidDaughter = false; + for (const int pdgCode : cast_daugPdgCodes) { + if (std::abs(mcDaughter.pdgCode()) == pdgCode) { + isValidDaughter = true; + break; + } + } + if (!isValidDaughter || !isValidMother) { + continue; + } + + auto findableIt = allCandsIndices.find(mcMother.globalIndex()); + if (findableIt != allCandsIndices.end() && + findableIt->second.first == motherTrack.globalIndex() && + findableIt->second.second == daughterTrack.globalIndex()) { + + findableToKinkCand[mcMother.globalIndex()] = kinkCand.globalIndex(); + } + } + + // C - loop on valid pairs for findable analysis + for (const auto& [mcMotherIndex, trackIndices] : allCandsIndices) { + if (trackIndices.second == -1 || trackIndices.first == -1) { + continue; + } + + // Retrieve mother and daughter tracks and mcParticles + auto motherTrack = tracks.rawIteratorAt(trackIndices.first); + auto daughterTrack = tracks.rawIteratorAt(trackIndices.second); + auto mcLabMoth = trackLabelsMC.rawIteratorAt(motherTrack.globalIndex()); + auto mcLabDaug = trackLabelsMC.rawIteratorAt(daughterTrack.globalIndex()); + auto mcMother = mcLabMoth.mcParticle_as(); + auto mcDaughter = mcLabDaug.mcParticle_as(); + + // Compute useful quantities for histograms + int mothPdg = mcMother.pdgCode(); + int daugPdg = mcDaughter.pdgCode(); + + float recPtDaughter = daughterTrack.pt(); + float recPtMother = motherTrack.pt(); + float mcRadius = std::sqrt((mcMother.vx() - mcDaughter.vx()) * (mcMother.vx() - mcDaughter.vx()) + (mcMother.vy() - mcDaughter.vy()) * (mcMother.vy() - mcDaughter.vy())); + float recRadius = -1.0; + if (findableToKinkCand.find(mcMother.globalIndex()) != findableToKinkCand.end()) { + auto kinkCand = kinkCands.rawIteratorAt(findableToKinkCand[mcMother.globalIndex()]); + recRadius = std::sqrt(kinkCand.xDecVtx() * kinkCand.xDecVtx() + kinkCand.yDecVtx() * kinkCand.yDecVtx()); + } + + // Check for detector mismatches in ITS mother tracks + auto maskValue = mcLabMoth.mcMask(); + int mismatchITSIndex = -1; + + for (int i = 0; i < 7; ++i) { // ITS has layers 0-6, bit ON means mismatch + if ((maskValue & (1 << i)) != 0) { + mismatchITSIndex = i; + break; + } + } + + // Define filter index and progressively apply kinkbuilder cuts to track pairs + int filterIndex = 0; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + + // 1 - tracks with right ITS, TPC, TOF signals + if (motherTrack.has_collision() && motherTrack.hasITS() && !motherTrack.hasTPC() && !motherTrack.hasTOF() && + daughterTrack.hasITS() && daughterTrack.hasTPC()) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + rFindable.fill(HIST("hfakeITSfindable"), mismatchITSIndex); + } else { + continue; + } + + // 2 - moth+daug track quality cuts + bool motherGoodITS = motherTrack.hasITS() && motherTrack.itsNCls() < 6 && motherTrack.itsNClsInnerBarrel() == 3 && motherTrack.itsChi2NCl() < 36; + bool daughterGoodITSTPC = daughterTrack.hasITS() && daughterTrack.hasTPC() && daughterTrack.itsNClsInnerBarrel() == 0 && + daughterTrack.itsNCls() < 4 && daughterTrack.tpcNClsCrossedRows() > 0.8 * daughterTrack.tpcNClsFindable() && daughterTrack.tpcNClsFound() > nTPCClusMinDaugKB; + if (motherGoodITS && daughterGoodITSTPC) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // 3 - mother track min pT + if (motherTrack.pt() > minPtMothKB) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // 4 - geometric cuts: eta + if (std::abs(motherTrack.eta()) < etaMaxKB && std::abs(daughterTrack.eta()) < etaMaxKB) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // 5 - geometric cuts: phi difference + if (std::abs(motherTrack.phi() - daughterTrack.phi()) * radToDeg < maxPhiDiffKB) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // DCA calculation: initialization CCDB + auto collision = motherTrack.template collision_as(); + auto bc = collision.template bc_as(); + initCCDB(bc); + const o2::math_utils::Point3D collVtx{collision.posX(), collision.posY(), collision.posZ()}; + o2::track::TrackParCov trackParCovMoth = getTrackParCov(motherTrack); + o2::track::TrackParCov trackParCovDaug = getTrackParCov(daughterTrack); + + // get DCA to PV for mother and daughter tracks + std::array dcaInfoMoth; + o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParCovMoth, mBz, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoMoth); + std::array dcaInfoDaug; + o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParCovDaug, mBz, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoDaug); + float dcaXYMother = std::abs(dcaInfoMoth[0]); + float dcaXYDaughter = std::abs(dcaInfoDaug[0]); + + if (std::abs(daugPdg) == PDG_t::kPiMinus) { + rFindable.fill(HIST("h2DCAMothPt_pikink"), recPtMother, dcaXYMother * 1.e4); + rFindable.fill(HIST("h2DCADaugPt_pikink"), recPtDaughter, dcaXYDaughter); + } else if (std::abs(daugPdg) == PDG_t::kProton) { + rFindable.fill(HIST("h2DCAMothPt_protonkink"), recPtMother, dcaXYMother * 1.e4); + rFindable.fill(HIST("h2DCADaugPt_protonkink"), recPtDaughter, dcaXYDaughter); + } + + // 6 - max Z difference + if (std::abs(trackParCovMoth.getZ() - trackParCovDaug.getZ()) < maxZDiffKB) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // 7 - DCA mother + if (dcaXYMother < maxDcaMothPvKB) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // 8 - DCA daughter + if (dcaXYDaughter > minDcaDaugPvKB) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // 9 - radius cut + if (recRadius > radiusCutKB) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // 10 - collision selection + if (!(std::abs(collision.posZ()) > cutzvertex || !collision.sel8())) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } else { + continue; + } + + // 11 - TOF daughter presence + if (daughterTrack.hasTOF()) { + filterIndex += 1; + fillFindableHistograms(filterIndex, mcRadius, recRadius, recPtMother, recPtDaughter, mothPdg, daugPdg); + } + } + } + + PROCESS_SWITCH(sigmaminustask, processFindable, "Findable Sigma processing", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(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..ce5597563da --- /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; + +o2::common::core::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/LFStrangeTreeCreator.cxx b/PWGLF/TableProducer/Strangeness/strangeTreeCreator.cxx similarity index 67% rename from PWGLF/TableProducer/Strangeness/LFStrangeTreeCreator.cxx rename to PWGLF/TableProducer/Strangeness/strangeTreeCreator.cxx index 61e8e2fa143..dd4634d3f73 100644 --- a/PWGLF/TableProducer/Strangeness/LFStrangeTreeCreator.cxx +++ b/PWGLF/TableProducer/Strangeness/strangeTreeCreator.cxx @@ -9,35 +9,37 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include -#include +/// \file strangeTreeCreator.cxx +/// \brief table producer for strangeness studies +/// \author Mario Ciacco -#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 "PWGLF/DataModel/LFSlimStrangeTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/PID/TPCPIDResponse.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.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/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "Common/DataModel/PIDResponse.h" +#include "CCDB/BasicCCDBManager.h" #include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" -#include "PWGLF/DataModel/LFSlimStrangeTables.h" - -#include "TDatabasePDG.h" +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -49,7 +51,7 @@ namespace { void momTotXYZ(std::array& momA, std::array const& momB, std::array const& momC) { - for (int i = 0; i < 3; ++i) { + for (unsigned int i{0}; i < momA.size(); ++i) { momA[i] = momB[i] + momC[i]; } } @@ -99,10 +101,27 @@ 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) +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)); } +float kineFactor(std::array const& momA, std::array const& momB, std::array const& momC, float const& massB, float const& massC, bool const& reso) +{ + float invMass = invMass2Body(momA, momC, momB, massC, massB); + float ptC = std::hypot(momC[0], momC[1]); + float ptB = std::hypot(momB[0], momB[1]); + float p2C = momC[0] * momC[0] + momC[1] * momC[1] + momC[2] * momC[2]; + float p2B = momB[0] * momB[0] + momB[1] * momB[1] + momB[2] * momB[2]; + float eC = RecoDecay::sqrtSumOfSquares(momC[0], momC[1], momC[2], massC); + float eB = RecoDecay::sqrtSumOfSquares(momB[0], momB[1], momB[2], massB); + float pCpB = momC[0] * momB[0] + momC[1] * momB[1] + momC[2] * momB[2]; + float kineC = (eB * p2C / eC / ptC) - pCpB / ptC; + float kineB = (eC * p2B / eB / ptB) - pCpB / ptB; + if (reso) { + return std::hypot(kineC, kineB) / invMass; + } + return (kineC + kineB) / invMass; +} } // namespace struct CandidateV0 { @@ -119,6 +138,8 @@ struct CandidateV0 { 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; @@ -143,7 +164,7 @@ struct CandidateV0 { int64_t globalIndexNeg = -999; }; -struct LFStrangeTreeCreator { +struct StrangeTreeCreator { Produces lambdaTableML; Produces v0TableAP; Produces mcLambdaTableML; @@ -154,18 +175,19 @@ struct LFStrangeTreeCreator { o2::vertexing::DCAFitterN<2> fitter; int mRunNumber; - float d_bz; - // o2::base::MatLayerCylSet* lut = nullptr; - Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Type of material correction"}; + float mBz; + o2::base::MatLayerCylSet* lut = nullptr; + Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Type of material correction"}; 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"}; + ConfigurableAxis etaAxis{"etaAxis", {8, -0.8f, 0.8f}, "binning for pseudorapidity"}; + ConfigurableAxis massKineAxis{"kineAxis", {3000, -3.f, 3.f}, "binning for the kinematic-transofrmed mass shift distributions"}; // 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"}; + ConfigurableAxis massK0sAxis{"massK0sAxis", {400, o2::constants::physics::MassK0 - 0.1f, o2::constants::physics::MassK0 + 0.1f}, "binning for the K0s invariant-mass"}; Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; Configurable etaMax{"etaMax", 0.8f, "maximum eta"}; @@ -184,20 +206,24 @@ struct LFStrangeTreeCreator { 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 v0alphaMax{"v0alphaMax", 10.f, "maximum Armenteros alpha (longitdinal momentum asymmetry)"}; + Configurable v0qtMin{"v0qtMin", 0.f, "minimum Armenteros qt (transverse momentum)"}; + + Configurable v0settingDcav0dau{"v0setting_dcav0dau", 0.5f, "DCA V0 Daughters"}; + Configurable v0settingDcav0pv{"v0setting_dcav0pv", 1.f, "DCA V0 to Pv"}; + Configurable v0settingDcadaughtopv{"v0setting_dcadaughtopv", 0.1f, "DCA Pos To PV"}; + Configurable v0settingCospa{"v0setting_cospa", 0.99f, "V0 CosPA"}; + Configurable v0settingRadius{"v0setting_radius", 5.f, "v0radius"}; + Configurable v0settingLifetime{"v0setting_lifetime", 40.f, "v0 lifetime cut"}; + Configurable v0settingNsigmatpc{"v0setting_nsigmatpc", 4.f, "nsigmatpc"}; + Configurable cascsettingDcabachpv{"cascsetting_dcabachpv", 0.1f, "cascdcabachpv"}; + Configurable cascsettingCospa{"cascsetting_cospa", 0.99f, "casc cospa cut"}; + Configurable cascsettingDcav0bach{"cascsetting_dcav0bach", 1.0f, "dcav0bach"}; + Configurable cascsettingVetoOm{"cascsetting_vetoOm", 0.01f, "vetoOm"}; + Configurable cascsettingMXi{"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 tpcFindableClsOverCR{"tpcFindableClsOverCR", 0.8, "fraction of findable clusters over crossed rows in TPC"}; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -217,7 +243,7 @@ struct LFStrangeTreeCreator { if (track.itsNCls() < v0trackNclusItsCut || track.tpcNClsFound() < v0trackNclusTpcCut || track.tpcNClsCrossedRows() < v0trackNclusTpcCut || - track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || + track.tpcNClsCrossedRows() < tpcFindableClsOverCR * track.tpcNClsFindable() || track.tpcNClsShared() > v0trackNsharedClusTpc) { return false; } @@ -242,25 +268,28 @@ struct LFStrangeTreeCreator { 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"; + mBz = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << mBz << " kG"; mRunNumber = bc.runNumber(); - fitter.setBz(d_bz); + fitter.setBz(mBz); + + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); + o2::base::Propagator::Instance()->setMatLUT(lut); - // o2::base::Propagator::Instance()->setMatLUT(lut); + int mat{static_cast(cfgMaterialCorrection)}; + fitter.setMatCorrType(static_cast(mat)); } void init(o2::framework::InitContext&) { mRunNumber = 0; - d_bz = 0; + mBz = 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.); @@ -271,17 +300,18 @@ struct LFStrangeTreeCreator { 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}); - 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}); // 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}); + histos.add("QA/massK0s", ";#it{p}_{T} (GeV/#it{c});#it{M}(#pi^{+} + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massK0sAxis}); + + // histograms for momentum shift/resolution extraction + histos.add("massKineBias", ";#eta;#it{p}_{T} (GeV/#it{c});#delta#it{M}/#Sigma_{i}#partial#it{M}/#partial#it{p}^{i}_{T}", HistType::kTH3F, {etaAxis, momAxis, massKineAxis}); + histos.add("massKineReso", ";#eta;#it{p}_{T} (GeV/#it{c});#delta#it{M}/#Sigma_{i}(#partial#it{M}/#partial#it{p}^{i}_{T})^{2}", HistType::kTH3F, {etaAxis, momAxis, massKineAxis}); } template @@ -289,7 +319,7 @@ struct LFStrangeTreeCreator { { candidateV0s.clear(); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; for (const auto& v0 : V0s) { auto posTrack = v0.posTrack_as(); @@ -317,9 +347,9 @@ struct LFStrangeTreeCreator { auto& posPropTrack = fitter.getTrack(0); auto& negPropTrack = fitter.getTrack(1); - std::array momPos; - std::array momNeg; - std::array momV0; + 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); @@ -335,27 +365,41 @@ struct LFStrangeTreeCreator { } auto alpha = alphaAP(momV0, momPos, momNeg); + if (std::abs(alpha) > v0alphaMax) { + continue; + } + 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); + auto qt = qtAP(momV0, momPos); + if (std::abs(qt) < v0qtMin) { + continue; + } + // 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(); + } - if (std::abs(nSigmaTPCPos) > v0setting_nsigmatpc || std::abs(nSigmaTPCNeg) > v0setting_nsigmatpc) { + if (std::abs(nSigmaTPCPos) > v0settingNsigmatpc || std::abs(nSigmaTPCNeg) > v0settingNsigmatpc) { continue; } - // veto on K0s mass - if (std::abs(mK0Short - o2::constants::physics::MassK0Short) < vetoMassK0Short) { + // 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) { + if (dcaV0dau > v0settingDcav0dau) { continue; } @@ -363,59 +407,77 @@ struct LFStrangeTreeCreator { const auto& vtx = fitter.getPCACandidate(); float radiusV0 = std::hypot(vtx[0], vtx[1]); - if (radiusV0 < v0setting_radius || radiusV0 > v0radiusMax) { + if (radiusV0 < v0settingRadius || radiusV0 > v0radiusMax) { continue; } - float dcaV0Pv = CalculateDCAStraightToPV( + 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) { + if (std::abs(dcaV0Pv) > v0settingDcav0pv) { continue; } double cosPA = RecoDecay::cpa(primVtx, vtx, momV0); - if (cosPA < v0setting_cospa) { + if (cosPA < v0settingCospa) { 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) { + // 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 > v0settingLifetime) { 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) { + if (posDcaToPv < v0settingDcadaughtopv && std::abs(dcaInfo[0]) < v0settingDcadaughtopv) { 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) { + if (negDcaToPv < v0settingDcadaughtopv && std::abs(dcaInfo[0]) < v0settingDcadaughtopv) { continue; } if (std::abs(mLambda - o2::constants::physics::MassLambda0) > lambdaMassCut) { // for QA histograms continue; } + + float ptPos = std::hypot(momPos[0], momPos[1]); + float pPos = std::hypot(momPos[0], momPos[1], momPos[2]); + float etaPos = 0.5 * std::log((pPos + momPos[2]) / (pPos - momPos[2])); + float deltaMass = mK0Short - o2::constants::physics::MassK0; + float massKineBias = deltaMass / kineFactor(momV0, momPos, momNeg, o2::constants::physics::MassPiMinus, o2::constants::physics::MassPiMinus, false); + float massKineReso = deltaMass / kineFactor(momV0, momPos, momNeg, o2::constants::physics::MassPiMinus, o2::constants::physics::MassPiMinus, true); + histos.fill(HIST("QA/massLambda"), centrality, ptV0, mLambda); + histos.fill(HIST("QA/massK0s"), ptV0, mK0Short); + histos.fill(HIST("massKineBias"), etaPos, ptPos, massKineBias); + histos.fill(HIST("massKineReso"), etaPos, ptPos, massKineReso); CandidateV0 candV0; candV0.pt = matter > 0. ? ptV0 : -ptV0; candV0.eta = etaV0; - candV0.ct = ML2P_Lambda; + candV0.ct = mL2P; candV0.len = lengthTraveled; candV0.mass = mLambda; candV0.radius = radiusV0; candV0.cpa = cosPA; candV0.alphaAP = alpha; - candV0.qtAP = qtAP(momV0, momPos); + candV0.qtAP = qt; candV0.trackv0 = fitter.createParentTrackParCov(); candV0.mompos = std::array{momPos[0], momPos[1], momPos[2]}; candV0.momneg = std::array{momNeg[0], momNeg[1], momNeg[2]}; @@ -431,7 +493,7 @@ struct LFStrangeTreeCreator { candidateV0s.push_back(candV0); } - for (auto& casc : cascades) { + for (const 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()) { @@ -441,7 +503,7 @@ struct LFStrangeTreeCreator { 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) + if (std::abs(dcaInfo[0]) < cascsettingDcabachpv) continue; auto bachelorTrack = getTrackParCov(bachTrack); @@ -465,23 +527,23 @@ struct LFStrangeTreeCreator { bachelorTrack.getPxPyPzGlo(momBach); momTotXYZ(momCasc, momV0, momBach); - auto dcacascv0bach = TMath::Sqrt(fitter.getChi2AtPCACandidate()); - if (dcacascv0bach > cascsetting_dcav0bach) + auto dcacascv0bach = std::sqrt(fitter.getChi2AtPCACandidate()); + if (dcacascv0bach > cascsettingDcav0bach) 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) + if (cosPA < cascsettingCospa) 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) + if (std::abs(mOm - o2::constants::physics::MassOmegaMinus) < cascsettingVetoOm) continue; - if (std::abs(mXi - o2::constants::physics::MassXiMinus) > cascsetting_mXi) + if (std::abs(mXi - o2::constants::physics::MassXiMinus) > cascsettingMXi) continue; histos.fill(HIST("QA/massXi"), centrality, std::hypot(momCasc[0], momCasc[1]), mXi); @@ -494,7 +556,7 @@ struct LFStrangeTreeCreator { { fillRecoEvent(collision, tracks, V0s, V0s_all, cascades, centrality); - for (auto& candidateV0 : candidateV0s) { + for (auto& candidateV0 : candidateV0s) { // o2-linter disable=const-red-in-for-loops (non const) candidateV0.isreco = true; auto mcLabPos = mcLabels.rawIteratorAt(candidateV0.globalIndexPos); auto mcLabNeg = mcLabels.rawIteratorAt(candidateV0.globalIndexNeg); @@ -508,23 +570,23 @@ struct LFStrangeTreeCreator { 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()) { + for (const auto& negMother : mcTrackNeg.template mothers_as()) { + for (const auto& posMother : mcTrackPos.template mothers_as()) { if (posMother.globalIndex() != negMother.globalIndex()) { pdgCodeMotherDauPos = posMother.pdgCode(); pdgCodeMotherDauNeg = negMother.pdgCode(); - if (negMother.pdgCode() == -211) { + if (negMother.pdgCode() == PDG_t::kPiMinus) { if (negMother.has_mothers()) { - for (auto& negSecondMother : negMother.template mothers_as()) { + for (const auto& negSecondMother : negMother.template mothers_as()) { if (negSecondMother.globalIndex() == posMother.globalIndex()) { pdgMatchMotherSecondMother = negSecondMother.pdgCode(); } } } } - if (posMother.pdgCode() == 211) { + if (posMother.pdgCode() == PDG_t::kPiPlus) { if (posMother.has_mothers()) { - for (auto& posSecondMother : posMother.template mothers_as()) { + for (const auto& posSecondMother : posMother.template mothers_as()) { if (posSecondMother.globalIndex() == negMother.globalIndex()) { pdgMatchMotherSecondMother = posSecondMother.pdgCode(); } @@ -535,11 +597,23 @@ struct LFStrangeTreeCreator { candidateV0.pdgcode = posMother.pdgCode(); pdgCodeMotherDauPos = posMother.pdgCode(); pdgCodeMotherDauNeg = negMother.pdgCode(); - if (!((mcTrackPos.pdgCode() == 2212 && mcTrackNeg.pdgCode() == -211) || (mcTrackPos.pdgCode() == 211 && mcTrackNeg.pdgCode() == -2212))) - continue; - if (std::abs(posMother.pdgCode()) != 3122) { + // build conditions for mother/daughter for k0short or lambda + bool mother; + bool daughter; + if (k0short) { + // mother is k0short and daughters are pions + mother = posMother.pdgCode() == PDG_t::kK0Short; + daughter = (mcTrackPos.pdgCode() == PDG_t::kPiPlus && mcTrackNeg.pdgCode() == PDG_t::kPiMinus); + } else { + // mother is lambda and daughters are proton and pion + mother = posMother.pdgCode() == PDG_t::kLambda0; + daughter = ((mcTrackPos.pdgCode() == PDG_t::kProton && mcTrackNeg.pdgCode() == PDG_t::kPiMinus) || (mcTrackPos.pdgCode() == PDG_t::kPiPlus && mcTrackNeg.pdgCode() == PDG_t::kProtonBar)); + } + // check conditions + if (!mother || !daughter) { continue; } + if (!posMother.isPhysicalPrimary() && !posMother.has_mothers()) continue; @@ -547,8 +621,9 @@ struct LFStrangeTreeCreator { if (posMother.isPhysicalPrimary()) { pdgCodeMother = 0; } else if (posMother.has_mothers()) { - for (auto& mcMother : posMother.mothers_as()) { - if (std::abs(mcMother.pdgCode()) == 3322 || std::abs(mcMother.pdgCode()) == 3312 || std::abs(mcMother.pdgCode()) == 3334) { + for (const auto& mcMother : posMother.mothers_as()) { + // feed-down: xi and omega decaying to lambda, ignore for k0 + if (!k0short && (std::abs(mcMother.pdgCode()) == o2::constants::physics::Pdg::kXi0 || std::abs(mcMother.pdgCode()) == PDG_t::kXiMinus || std::abs(mcMother.pdgCode()) == PDG_t::kOmegaMinus)) { pdgCodeMother = mcMother.pdgCode(); break; } @@ -571,13 +646,13 @@ struct LFStrangeTreeCreator { } if ((!mcTrackPos.has_mothers()) && mcTrackNeg.has_mothers()) { pdgCodeMotherDauPos = -999; - for (auto& negMother : mcTrackNeg.template mothers_as()) { + for (const 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()) { + for (const auto& posMother : mcTrackPos.template mothers_as()) { pdgCodeMotherDauPos = posMother.pdgCode(); } } @@ -588,14 +663,25 @@ struct LFStrangeTreeCreator { 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 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 mcParticlesThisCollision = mcParticles.sliceBy(perCollisionMcParts, collisionId); + for (const auto& mcPart : mcParticlesThisCollision) { auto genEta = mcPart.eta(); if (std::abs(genEta) > etaMax) { continue; @@ -603,26 +689,54 @@ struct LFStrangeTreeCreator { auto pdgCode = mcPart.pdgCode(); std::array secVtx; - if (std::abs(pdgCode) == 3122) { + 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.)}; + + // look for lambda or k0short + int pdg_test = PDG_t::kLambda0; + if (k0short) + pdg_test = PDG_t::kK0Short; + + if (std::abs(pdgCode) == pdg_test) { if (!mcPart.isPhysicalPrimary() && !mcPart.has_mothers()) continue; - bool foundPr = false; - for (auto& mcDaught : mcPart.daughters_as()) { - if (std::abs(mcDaught.pdgCode()) == 2212) { - foundPr = true; + // check if its the right decay containing proton for lambda and charged pion for k0short + int pdg_particle; + if (k0short) { + pdg_particle = PDG_t::kPiPlus; + } else { + pdg_particle = PDG_t::kProton; + } + bool foundParticle = false; + for (const auto& mcDaught : mcPart.daughters_as()) { + if (std::abs(mcDaught.pdgCode()) == pdg_particle) { + foundParticle = true; secVtx = std::array{mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; break; } } - if (!foundPr) { + // momentum of daughters + for (const 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()) { - if (std::abs(mcMother.pdgCode()) == 3322 || std::abs(mcMother.pdgCode()) == 3312 || std::abs(mcMother.pdgCode()) == 3334) { + for (const auto& mcMother : mcPart.mothers_as()) { + // feed-down: xi and omega decaying to lambda, ignore for k0 + if (!k0short && (std::abs(mcMother.pdgCode()) == o2::constants::physics::Pdg::kXi0 || std::abs(mcMother.pdgCode()) == PDG_t::kXiMinus || std::abs(mcMother.pdgCode()) == PDG_t::kOmegaMinus)) { pdgCodeMother = mcMother.pdgCode(); break; } @@ -640,6 +754,8 @@ struct LFStrangeTreeCreator { 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); @@ -675,20 +791,16 @@ struct LFStrangeTreeCreator { histos.fill(HIST("QA/zVtx"), collision.posZ()); 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); + auto V0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); + auto CascTableThisCollision = cascades.sliceBy(perCollisionCasc, collIdx); + V0TableThisCollision.bindExternalIndices(&tracks); + CascTableThisCollision.bindExternalIndices(&tracks); + CascTableThisCollision.bindExternalIndices(&V0s); - auto multiplicity = collision.multFT0C(); auto centrality = collision.centFT0C(); - fillRecoEvent(collision, tracks, V0Table_thisCollision, V0s, CascTable_thisCollision, centrality); + fillRecoEvent(collision, tracks, V0TableThisCollision, V0s, CascTableThisCollision, centrality); - histos.fill(HIST("QA/PvMultVsCent"), centrality, collision.numContrib()); - histos.fill(HIST("QA/MultVsCent"), centrality, multiplicity); - - for (auto& candidateV0 : candidateV0s) { + for (const auto& candidateV0 : candidateV0s) { lambdaTableML( candidateV0.pt, candidateV0.eta, @@ -724,11 +836,11 @@ struct LFStrangeTreeCreator { } } } - PROCESS_SWITCH(LFStrangeTreeCreator, processRun3, "process (Run 3)", false); + PROCESS_SWITCH(StrangeTreeCreator, processRun3, "process (Run 3)", false); 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) { + for (const auto& collision : collisions) { auto bc = collision.bc_as(); initCCDB(bc); @@ -746,16 +858,16 @@ struct LFStrangeTreeCreator { histos.fill(HIST("QA/zVtx"), collision.posZ()); 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); + auto V0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); + auto CascTableThisCollision = cascades.sliceBy(perCollisionCasc, collIdx); + V0TableThisCollision.bindExternalIndices(&tracks); + CascTableThisCollision.bindExternalIndices(&tracks); + CascTableThisCollision.bindExternalIndices(&V0s); - fillMcEvent(collision, tracks, V0Table_thisCollision, V0s, CascTable_thisCollision, centrality, mcParticles, mcLab); + fillMcEvent(collision, tracks, V0TableThisCollision, V0s, CascTableThisCollision, centrality, mcParticles, mcLab); fillMcGen(mcParticles, mcLab, collision.mcCollisionId()); - for (auto& candidateV0 : candidateV0s) { + for (const auto& candidateV0 : candidateV0s) { mcLambdaTableML( candidateV0.pt, candidateV0.eta, @@ -792,6 +904,12 @@ struct LFStrangeTreeCreator { 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, @@ -805,11 +923,11 @@ struct LFStrangeTreeCreator { } } } - PROCESS_SWITCH(LFStrangeTreeCreator, processMcRun3, "process MC (Run 3)", false); + PROCESS_SWITCH(StrangeTreeCreator, processMcRun3, "process MC (Run 3)", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx index e6bfeee0ced..a68b06b4b79 100644 --- a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx @@ -15,49 +15,58 @@ // It is meant to help with providing auxiliary information // when dealing with derived data. -#include -#include -#include -#include -#include -#include +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#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 "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" +#include "Common/TableProducer/PID/pidTOFBase.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 "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/RunningWorkflowInfo.h" #include "Framework/StaticFor.h" -#include "Common/DataModel/McCollisionExtra.h" -#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include +#include using namespace o2; 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; + +using BCsWithTimestampsAndRun2Infos = soa::Join; // simple bit checkers #define bitset(var, nbit) ((var) |= (1 << (nbit))) @@ -66,68 +75,77 @@ using FullCollisions = soa::Join strangeColl; // characterises collisions - 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 strangeStamps; // provides timestamps, run numbers - Produces v0collref; // references collisions from V0s - Produces casccollref; // references collisions from cascades - 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 - Produces cascExtras; // references DauTracks from cascades - Produces straTrackExtras; // references DauTracks from tracked cascades - - //__________________________________________________ - // cascade interlinks - Produces cascToTraRefs; // cascades -> tracked - Produces cascToKFRefs; // cascades -> KF - Produces traToCascRefs; // tracked -> cascades - Produces kfToCascRefs; // KF -> cascades - - //__________________________________________________ - // mother information - Produces v0mothers; // V0 mother references - Produces cascmothers; // casc mother references - Produces motherMCParts; // mc particles for mothers - - //__________________________________________________ - // Q-vectors - 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) - - //__________________________________________________ - // Generated binned data - // this is a hack while the system does not do better - Produces geK0Short; - Produces geLambda; - Produces geAntiLambda; - Produces geXiMinus; - Produces geXiPlus; - Produces geOmegaMinus; - Produces geOmegaPlus; - - //__________________________________________________ - // Found tags for findable exercise - Produces v0FoundTags; - Produces cascFoundTags; + struct : ProducesGroup { + //__________________________________________________ + // fundamental building blocks of derived data + Produces strangeColl; // characterises collisions + Produces strangeCollLabels; // characterises collisions + Produces strangeMCColl; // characterises collisions / MC + Produces strangeMCMults; // characterises collisions / MC mults + 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 straEvTimes; // provides event times (FT0, TOF) + Produces v0collref; // references collisions from V0s + Produces casccollref; // references collisions from cascades + 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 + Produces cascExtras; // references DauTracks from cascades + Produces straTrackExtras; // references DauTracks from tracked cascades + + //__________________________________________________ + // cascade interlinks + Produces cascToTraRefs; // cascades -> tracked + Produces cascToKFRefs; // cascades -> KF + Produces traToCascRefs; // tracked -> cascades + Produces kfToCascRefs; // KF -> cascades + + //__________________________________________________ + // mother information + Produces v0mothers; // V0 mother references + 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 StraTPCQVs; // TPC Q-vector + Produces StraFT0CQVsEv; // events used to compute FT0C Q-vector (LF) + Produces StraZDCSP; // ZDC Sums and Products + + //__________________________________________________ + // Generated binned data + // this is a hack while the system does not do better + Produces geK0Short; + Produces geLambda; + Produces geAntiLambda; + Produces geXiMinus; + Produces geXiPlus; + Produces geOmegaMinus; + Produces geOmegaPlus; + + //__________________________________________________ + // Debug + Produces straOrigin; + } products; // histogram registry for bookkeeping HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -164,15 +182,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; @@ -180,6 +215,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; @@ -200,6 +238,144 @@ 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 + + doprocessTrackExtrasMCNoPID > + 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"); + } + if (doprocessTrackExtrasMCNoPID) { + 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; @@ -211,25 +387,24 @@ 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}); - - if (doprocessV0FoundTags || doprocessCascFoundTags) { - auto h = histos.add("hFoundTagsCounters", "hFoundTagsCounters", kTH1D, {{6, -0.5f, 5.5f}}); - h->GetXaxis()->SetBinLabel(1, "Found V0s"); - h->GetXaxis()->SetBinLabel(2, "Findable V0s"); - h->GetXaxis()->SetBinLabel(3, "Findable & found V0s"); - h->GetXaxis()->SetBinLabel(4, "Found Cascades"); - h->GetXaxis()->SetBinLabel(5, "Findable Cascades"); - h->GetXaxis()->SetBinLabel(6, "Findable & found Cascades"); - } + histos.add("h2dCollisionTimesVsNTracks", "h2dCollisionTimesVsNTracks", kTH2D, {{100, -0.5f, 99.5}, {2000, -1000.0f, 1000.0f}}); // 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); @@ -237,7 +412,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); @@ -250,46 +425,9 @@ struct strangederivedbuilder { } } - void processCollisionsV0sOnly(soa::Join const& collisions, aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) - { - 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), - collision.trackOccupancyInTimeRange()); - } - } - for (int i = 0; i < V0Table_thisColl.size(); i++) - v0collref(strangeColl.lastIndex()); - } - } - - 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&) + // 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*/) { // create collision indices beforehand std::vector V0CollIndices(V0s.size(), -1); // index -1: no collision @@ -297,15 +435,10 @@ struct strangederivedbuilder { std::vector KFCascadeCollIndices(KFCascades.size(), -1); // index -1: no collision std::vector TraCascadeCollIndices(TraCascades.size(), -1); // index -1: no collision + // +-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+-<*>-+ 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); @@ -314,144 +447,241 @@ struct strangederivedbuilder { 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()); - 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), - collision.trackOccupancyInTimeRange()); + + 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) { + products.strangeStamps(bc.runNumber(), bc.timestamp(), bc.globalBC()); + products.strangeColl(collision.posX(), collision.posY(), collision.posZ()); + if constexpr (requires { collision.mcCollisionId(); }) { // check if MC information is available and if so fill labels + products.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())); + } + + products.strangeCents(collision.centFT0M(), collision.centFT0A(), + centrality, collision.centFV0A(), collision.centFT0CVariant1(), + collision.centMFT(), collision.centNGlobal()); + products.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 + products.strangeCentsRun2(collision.centRun2V0M(), collision.centRun2V0A(), + collision.centRun2SPDTracklets(), collision.centRun2SPDClusters()); + products.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 (const auto& v0 : V0Table_thisColl) - V0CollIndices[v0.globalIndex()] = strangeColl.lastIndex(); + V0CollIndices[v0.globalIndex()] = products.strangeColl.lastIndex(); for (const auto& casc : CascTable_thisColl) - CascadeCollIndices[casc.globalIndex()] = strangeColl.lastIndex(); + CascadeCollIndices[casc.globalIndex()] = products.strangeColl.lastIndex(); for (const auto& casc : KFCascTable_thisColl) - KFCascadeCollIndices[casc.globalIndex()] = strangeColl.lastIndex(); + KFCascadeCollIndices[casc.globalIndex()] = products.strangeColl.lastIndex(); for (const auto& casc : TraCascTable_thisColl) - TraCascadeCollIndices[casc.globalIndex()] = strangeColl.lastIndex(); + TraCascadeCollIndices[casc.globalIndex()] = products.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 : KFCascades) - tracasccollref(TraCascadeCollIndices[casc.globalIndex()]); + for (const auto& v0 : V0s) { + products.v0collref(V0CollIndices[v0.globalIndex()]); + } + for (const auto& casc : Cascades) { + products.casccollref(CascadeCollIndices[casc.globalIndex()]); + } + for (const auto& casc : KFCascades) { + products.kfcasccollref(KFCascadeCollIndices[casc.globalIndex()]); + } + for (const auto& casc : TraCascades) { + products.tracasccollref(TraCascadeCollIndices[casc.globalIndex()]); + } } - void processCollisionsMC(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&, soa::Join const& mcCollisions, aod::McParticles const&) + // helper function to estimate collision time + template + void populateEventTimes(coll const& collisions, TTracks const& tracks) { - // create collision indices beforehand - std::vector V0CollIndices(V0s.size(), -1); // index -1: no collision - std::vector V0MCCollIndices(V0s.size(), -1); // index -1: no collision - std::vector CascadeCollIndices(Cascades.size(), -1); // index -1: no collision - std::vector CascadeMCCollIndices(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 + std::vector collisionEventTime(collisions.size(), 0.0); + std::vector collisionNtracks(collisions.size(), 0); + for (const auto& track : tracks) { + if (track.hasTOF() && track.collisionId() >= 0) { + collisionEventTime[track.collisionId()] += track.tofEvTime(); + collisionNtracks[track.collisionId()]++; + } + } + for (const auto& collision : collisions) { + if (collisionNtracks[collision.globalIndex()] > 0) { + collisionEventTime[collision.globalIndex()] /= static_cast(collisionNtracks[collision.globalIndex()]); + } else { + collisionEventTime[collision.globalIndex()] = -1e+6; // undefined + } + histos.fill(HIST("h2dCollisionTimesVsNTracks"), collisionNtracks[collision.globalIndex()], collisionEventTime[collision.globalIndex()]); + products.straEvTimes(collisionEventTime[collision.globalIndex()]); + } + } + // 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()); - strangeMCMults(mccollision.multMCFT0A(), mccollision.multMCFT0C(), - mccollision.multMCNParticlesEta05(), - mccollision.multMCNParticlesEta08(), - mccollision.multMCNParticlesEta10()); - } - - // ______________________________________________ - for (const auto& collision : collisions) { - const uint64_t collIdx = collision.globalIndex(); + const uint64_t mcCollIndex = mccollision.globalIndex(); + auto mcParticles = mcParticlesEntireTable.sliceBy(mcParticlePerMcCollision, mcCollIndex); - float centrality = collision.centFT0C(); - if (qaCentrality) { - auto hRawCentrality = histos.get(HIST("hRawCentrality")); - centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); - } + // 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 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), - collision.trackOccupancyInTimeRange()); + 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++; } - 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()]); + products.strangeMCColl(mccollision.posX(), mccollision.posY(), mccollision.posZ(), + mccollision.impactParameter(), mccollision.eventPlaneAngle(), mccollision.generatorsID()); + products.strangeMCMults(mccollision.multMCFT0A(), mccollision.multMCFT0C(), + mccollision.multMCNParticlesEta05(), + mccollision.multMCNParticlesEta08(), + mccollision.multMCNParticlesEta10(), + totalMult); } - for (const auto& casc : Cascades) { - casccollref(CascadeCollIndices[casc.globalIndex()]); - } - for (const auto& casc : KFCascades) - kfcasccollref(KFCascadeCollIndices[casc.globalIndex()]); - for (const auto& casc : KFCascades) - tracasccollref(TraCascadeCollIndices[casc.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); + } + + 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); + } + + 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) @@ -470,7 +700,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++; } @@ -480,16 +710,21 @@ struct strangederivedbuilder { for (auto const& v0 : V0s) { auto const& posTrack = v0.posTrack_as(); auto const& negTrack = v0.negTrack_as(); - v0Extras(trackMap[posTrack.globalIndex()], - trackMap[negTrack.globalIndex()]); // joinable with V0Datas + products.v0Extras(trackMap[posTrack.globalIndex()], + trackMap[negTrack.globalIndex()]); // joinable with V0Datas } //__________________________________________________ // circle back and populate actual DauTrackExtra table for (auto const& tr : tracksExtra) { if (trackMap[tr.globalIndex()] >= 0) { - dauTrackExtras(tr.itsChi2NCl(), - tr.detectorMap(), tr.itsClusterSizes(), - tr.tpcNClsFound(), tr.tpcNClsCrossedRows()); + products.dauTrackExtras(tr.itsChi2NCl(), + tr.tpcChi2NCl(), + tr.detectorMap(), + tr.itsClusterSizes(), + tr.tpcNClsFindable(), + tr.tpcNClsFindableMinusFound(), + tr.tpcNClsFindableMinusCrossedRows(), + tr.tpcNClsShared()); } } // done! @@ -545,7 +780,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++; } @@ -555,8 +790,8 @@ struct strangederivedbuilder { for (auto const& v0 : V0s) { auto const& posTrack = v0.template posTrack_as(); auto const& negTrack = v0.template negTrack_as(); - v0Extras(trackMap[posTrack.globalIndex()], - trackMap[negTrack.globalIndex()]); // joinable with V0Datas + products.v0Extras(trackMap[posTrack.globalIndex()], + trackMap[negTrack.globalIndex()]); // joinable with V0Datas } //__________________________________________________ // populate track references @@ -564,61 +799,79 @@ struct strangederivedbuilder { 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 + products.cascExtras(trackMap[posTrack.globalIndex()], + trackMap[negTrack.globalIndex()], + trackMap[bachTrack.globalIndex()]); // joinable with CascDatas } //__________________________________________________ // populate track references for (auto const& casc : TraCascades) { auto strangeTrack = casc.template strangeTrack_as(); - straTrackExtras(trackMap[strangeTrack.globalIndex()]); // joinable with TraCascDatas + products.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.itsChi2NCl(), - tr.detectorMap(), tr.itsClusterSizes(), - tr.tpcNClsFound(), tr.tpcNClsCrossedRows()); - + products.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 + products.dauTrackMCIds(tr.mcParticleId()); // joinable with dauTrackExtras } - // 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)); + if constexpr (requires { tr.tpcNSigmaEl(); }) { + products.dauTrackTPCPIDs(tr.tpcSignal(), + aod::dautrack::packing::packInInt8(tr.tpcNSigmaEl()), + aod::dautrack::packing::packInInt8(tr.tpcNSigmaPi()), + aod::dautrack::packing::packInInt8(tr.tpcNSigmaKa()), + aod::dautrack::packing::packInInt8(tr.tpcNSigmaPr())); + // populate daughter-level TOF information + if (tr.hasTOF()) { + products.dauTrackTOFPIDs(tr.collisionId(), products.dauTrackExtras.lastIndex(), tr.tofSignal(), tr.tofEvTime(), tr.length(), tr.tofExpMom()); + } } else { - dauTrackTPCPIDs(tr.tpcSignal(), tr.tpcNSigmaEl(), - tr.tpcNSigmaPi(), tr.tpcNSigmaKa(), - tr.tpcNSigmaPr(), tr.tpcNSigmaHe()); + // populate with empty fully-compatible Nsigmas if no corresponding table available + products.dauTrackTPCPIDs(0.0f, 0, 0, 0, 0); } - - // populate daughter-level TOF information - dauTrackTOFPIDs(tr.tofSignal(), tr.tofEvTime(), tr.length()); } } // 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&) + void processPopulateEventTimes(aod::Collisions const& collisions, soa::Join const& tracks) + { + populateEventTimes(collisions, tracks); + } + + 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); - // done! } - 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&) + // 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 processTrackExtrasMCNoPID(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); - // done! } void processStrangeMothers(soa::Join const& V0s, soa::Join const& Cascades, aod::McParticles const& mcParticles) @@ -627,32 +880,44 @@ struct strangederivedbuilder { //__________________________________________________ // mark mcParticles for referencing - for (auto const& v0 : V0s) + for (auto const& v0 : V0s) { if (v0.has_mcMotherParticle()) motherReference[v0.mcMotherParticleId()] = 0; - for (auto const& ca : Cascades) + } + for (auto const& ca : Cascades) { if (ca.has_mcMotherParticle()) motherReference[ca.mcMotherParticleId()] = 0; + } //__________________________________________________ // 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 } } //__________________________________________________ // populate track references - for (auto const& v0 : V0s) - v0mothers(motherReference[v0.mcMotherParticleId()]); // joinable with V0Datas - for (auto const& ca : Cascades) - cascmothers(motherReference[ca.mcMotherParticleId()]); // joinable with CascDatas + for (auto const& v0 : V0s) { + if (v0.mcMotherParticleId() > -1) { + products.v0mothers(motherReference[v0.mcMotherParticleId()]); // joinable with V0Datas + } else { + products.v0mothers(-1); // joinable with V0Datas + } + } + for (auto const& ca : Cascades) { + if (ca.mcMotherParticleId() > -1) { + products.cascmothers(motherReference[ca.mcMotherParticleId()]); // joinable with CascDatas + } else { + products.cascmothers(-1); // joinable with CascDatas + } + } //__________________________________________________ // populate motherMCParticles for (auto const& tr : mcParticles) { if (motherReference[tr.globalIndex()] >= 0) { - motherMCParts(tr.px(), tr.py(), tr.pz(), tr.pdgCode(), tr.isPhysicalPrimary()); + products.motherMCParts(tr.px(), tr.py(), tr.pz(), tr.pdgCode(), tr.isPhysicalPrimary()); } } } @@ -668,7 +933,7 @@ struct strangederivedbuilder { auto cascade = c.cascade_as(); indexTracked = cascade.traCascDataId(); } - cascToTraRefs(indexTracked); + products.cascToTraRefs(indexTracked); } // Tracked to standard for (auto const& c : TraCascades) { @@ -677,7 +942,7 @@ struct strangederivedbuilder { auto cascade = c.cascade_as(); index = cascade.cascDataId(); } - traToCascRefs(index); + products.traToCascRefs(index); } } @@ -690,7 +955,7 @@ struct strangederivedbuilder { auto cascade = c.cascade_as(); indexKF = cascade.kfCascDataId(); } - cascToKFRefs(indexKF); + products.cascToKFRefs(indexKF); } // KF to standard for (auto const& c : KFCascades) { @@ -699,7 +964,7 @@ struct strangederivedbuilder { auto cascade = c.cascade_as(); index = cascade.cascDataId(); } - kfToCascRefs(index); + products.kfToCascRefs(index); } } @@ -710,7 +975,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()); } }); } @@ -740,7 +1005,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()); } }); } @@ -763,7 +1028,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) { @@ -788,111 +1053,109 @@ struct strangederivedbuilder { } // at end of data frame // -> pack information from this DF into a generated histogram, once / DF - geK0Short(genK0Short); - geLambda(genLambda); - geAntiLambda(genAntiLambda); - geXiMinus(genXiMinus); - geXiPlus(genXiPlus); - geOmegaMinus(genOmegaMinus); - geOmegaPlus(genOmegaPlus); + products.geK0Short(genK0Short); + products.geLambda(genLambda); + products.geAntiLambda(genAntiLambda); + products.geXiMinus(genXiMinus); + products.geXiPlus(genXiPlus); + products.geOmegaMinus(genOmegaMinus); + products.geOmegaPlus(genOmegaPlus); } void processFT0AQVectors(soa::Join::iterator const& collision) { - StraFT0AQVs(collision.qvecFT0ARe(), collision.qvecFT0AIm(), collision.sumAmplFT0A()); + products.StraFT0AQVs(collision.qvecFT0ARe(), collision.qvecFT0AIm(), collision.sumAmplFT0A()); } void processFT0CQVectors(soa::Join::iterator const& collision) { - StraFT0CQVs(collision.qvecFT0CRe(), collision.qvecFT0CIm(), collision.sumAmplFT0C()); + products.StraFT0CQVs(collision.qvecFT0CRe(), collision.qvecFT0CIm(), collision.sumAmplFT0C()); } void processFT0CQVectorsLF(soa::Join::iterator const& collision) { - StraFT0CQVs(collision.qFT0C() * std::cos(2 * collision.psiFT0C()), collision.qFT0C() * std::sin(2 * collision.psiFT0C()), collision.qFT0C()); - StraFT0CQVsEv(collision.triggereventep()); + products.StraFT0CQVs(collision.qFT0C() * std::cos(2 * collision.psiFT0C()), collision.qFT0C() * std::sin(2 * collision.psiFT0C()), collision.qFT0C()); + products.StraFT0CQVsEv(collision.triggereventep()); + } + void processZDCSP(soa::Join::iterator const& collision) + { + products.StraZDCSP(collision.triggereventsp(), + collision.psiZDCA(), collision.psiZDCC(), collision.qxZDCA(), collision.qxZDCC(), collision.qyZDCA(), collision.qyZDCC()); } void processFT0MQVectors(soa::Join::iterator const& collision) { - StraFT0MQVs(collision.qvecFT0MRe(), collision.qvecFT0MIm(), collision.sumAmplFT0M()); + products.StraFT0MQVs(collision.qvecFT0MRe(), collision.qvecFT0MIm(), collision.sumAmplFT0M()); } void processFV0AQVectors(soa::Join::iterator const& collision) { - StraFV0AQVs(collision.qvecFV0ARe(), collision.qvecFV0AIm(), collision.sumAmplFV0A()); + products.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()); + products.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()); + products.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()); } - uint64_t combineProngIndices(uint32_t low, uint32_t high) - { - return (((uint64_t)high) << 32) | ((uint64_t)low); - } - - void processV0FoundTags(aod::V0s const& foundV0s, aod::V0Datas const& findableV0s, aod::FindableV0s const& /* added to avoid troubles */) + using uint128_t = __uint128_t; + uint128_t combineProngIndices128(uint32_t pos, uint32_t neg, uint32_t bach) { - histos.fill(HIST("hFoundTagsCounters"), 0.0f, foundV0s.size()); - histos.fill(HIST("hFoundTagsCounters"), 1.0f, findableV0s.size()); - - for (auto const& findableV0 : findableV0s) { - bool hasBeenFound = false; - for (auto const& foundV0 : foundV0s) { - if (foundV0.posTrackId() == findableV0.posTrackId() && foundV0.negTrackId() == findableV0.negTrackId()) { - hasBeenFound = true; - } - } - v0FoundTags(hasBeenFound); - } + return ((static_cast(pos)) << 64) | ((static_cast(neg)) << 32) | (static_cast(bach)); } - using uint128_t = __uint128_t; - uint128_t combineProngIndices128(uint32_t pos, uint32_t neg, uint32_t bach) + void processDataframeIDs(aod::Origins const& origins) { - return (((uint128_t)pos) << 64) | (((uint128_t)neg) << 32) | ((uint128_t)bach); + auto origin = origins.begin(); + products.straOrigin(origin.dataframeID()); } - void processCascFoundTags(aod::Cascades const& foundCascades, aod::CascDatas const& findableCascades, aod::V0s const&, aod::FindableCascades const& /* added to avoid troubles */) + void processSimulatedZDCNeutrons(soa::Join const& mcCollisions, aod::McParticles const& mcParticlesEntireTable) { - histos.fill(HIST("hFoundTagsCounters"), 3.0f, foundCascades.size()); - histos.fill(HIST("hFoundTagsCounters"), 4.0f, findableCascades.size()); + for (const auto& mccollision : mcCollisions) { + const uint64_t mcCollIndex = mccollision.globalIndex(); + auto mcParticles = mcParticlesEntireTable.sliceBy(mcParticlePerMcCollision, mcCollIndex); - // pack the found V0s in a long long - std::vector foundCascadesPacked; - foundCascadesPacked.reserve(foundCascades.size()); - for (auto const& foundCascade : foundCascades) { - auto v0 = foundCascade.v0(); - foundCascadesPacked[foundCascade.globalIndex()] = combineProngIndices128(v0.posTrackId(), v0.negTrackId(), foundCascade.bachelorId()); - } + 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 + products.zdcNeutrons(mcPart.pdgCode(), mcPart.statusCode(), mcPart.flags(), + mcPart.vx(), mcPart.vy(), mcPart.vz(), mcPart.vt(), + mcPart.px(), mcPart.py(), mcPart.pz(), mcPart.e()); - bool hasBeenFound = false; - for (auto const& findableCascade : findableCascades) { - uint128_t indexPack = combineProngIndices128(findableCascade.posTrackId(), findableCascade.negTrackId(), findableCascade.bachelorId()); - for (uint32_t ic = 0; ic < foundCascades.size(); ic++) { - if (indexPack == foundCascadesPacked[ic]) { - hasBeenFound = true; - histos.fill(HIST("hFoundTagsCounters"), 5.0f); - break; + products.zdcNeutronsMCCollRefs(mcPart.mcCollisionId()); + } } } - cascFoundTags(hasBeenFound); } } - 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); + // 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); + // Event times + PROCESS_SWITCH(strangederivedbuilder, processPopulateEventTimes, "Populate event times", true); + + // 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, processTrackExtrasMCNoPID, "Produce track extra information (V0s + casc), no PID", 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); @@ -902,10 +1165,7 @@ struct strangederivedbuilder { 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); - - // dedicated findable functionality - PROCESS_SWITCH(strangederivedbuilder, processV0FoundTags, "Produce FoundV0Tags for findable exercise", false); - PROCESS_SWITCH(strangederivedbuilder, processCascFoundTags, "Produce FoundCascTags for findable exercise", 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..a4e3522104c --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx @@ -0,0 +1,2959 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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, deduplication, etc) +// -- cascadebuilderopts .: cascade-specific building options (topological, etc) + +#include "TableHelper.h" + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/strangenessBuilderHelper.h" + +#include "Common/Core/TPCVDriftManager.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::ml; + +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 FullTracksExtWithPID = soa::Join; +using FullTracksExtIUWithPID = soa::Join; +using FullTracksExtLabeled = soa::Join; +using FullTracksExtLabeledIU = soa::Join; +using FullTracksExtLabeledWithPID = soa::Join; +using FullTracksExtLabeledIUWithPID = soa::Join; +using TracksWithExtra = soa::Join; + +// For dE/dx association in pre-selection +using TracksExtraWithPID = soa::Join; + +// simple checkers, but ensure 8 bit integers +#define BITSET(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) + +struct StrangenessBuilder { + // helper object + o2::pwglf::strangenessBuilderHelper straHelper; + + // ML model + o2::ml::OnnxModel deduplication_bdt; + + // 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 }; + + enum V0PreSelection : uint8_t { selGamma = 0, + selK0Short, + selLambda, + selAntiLambda }; + + enum CascPreSelection : uint8_t { selXiMinus = 0, + selXiPlus, + selOmegaMinus, + selOmegaPlus }; + + 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; + + // ML options + std::map metadata; + + struct : ConfigurableGroup { + std::string prefix = "DeduplicationOpts"; + + Configurable deduplicationAlgorithm{"deduplicationAlgorithm", 1, + "0: disabled;" + "1: best pointing angle wins;" + "2: best DCA daughters wins;" + "3: best pointing and best DCA wins;" + "4: best BDT score wins;" + "5: selects on PA (not a winner takes it all approach!);" + "6: selects on BDT score (not a winner takes it all approach!)"}; + + // BDT settings + Configurable BDTLocalPath{"BDTLocalPath", "Deduplication_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; + Configurable BDTPathCCDB{"BDTPathCCDB", "Users/g/gsetouel/MLModels2", "Path on 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 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)"}; + + // Selection based duplicates removal + Configurable PAthreshold{"PAthreshold", 0.02, "PA cut to remove duplicates."}; + Configurable BDTthreshold{"BDTthreshold", 0.7, "BDT score cut to remove duplicates."}; + + } DeduplicationOpts; + + // 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"}; + + // Autoconfigure process functions + Configurable autoConfigureProcess{"autoConfigureProcess", false, "if true, will configure process function switches based on metadata"}; + + // 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_keepOnlyPhysicalPrimary{"mc_keepOnlyPhysicalPrimary", false, "Keep only physical primary generated V0s if not recoed"}; + 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_keepOnlyPhysicalPrimary{"mc_keepOnlyPhysicalPrimary", false, "Keep only physical primary generated cascades if not recoed"}; + Configurable mc_findableDetachedCascade{"mc_findableDetachedCascade", false, "if true, generate findable cascades that have collisionId -1. Caution advised."}; + } cascadeBuilderOpts; + + static constexpr float defaultK0MassWindowParameters[1][4] = {{2.81882e-03, 1.14057e-03, 1.72138e-03, 5.00262e-01}}; + static constexpr float defaultLambdaWindowParameters[1][4] = {{1.17518e-03, 1.24099e-04, 5.47937e-03, 3.08009e-01}}; + static constexpr float defaultXiMassWindowParameters[1][4] = {{1.43210e-03, 2.03561e-04, 2.43187e-03, 7.99668e-01}}; + static constexpr float defaultOmMassWindowParameters[1][4] = {{1.43210e-03, 2.03561e-04, 2.43187e-03, 7.99668e-01}}; + + static constexpr float defaultLifetimeCuts[1][4] = {{20, 60, 40, 20}}; + + // preselection options + struct : ConfigurableGroup { + std::string prefix = "preSelectOpts"; + Configurable preselectOnlyDesiredV0s{"preselectOnlyDesiredV0s", false, "preselect only V0s with compatible TPC PID and mass info"}; + Configurable preselectOnlyDesiredCascades{"preselectOnlyDesiredCascades", false, "preselect only Cascades with compatible TPC PID and mass info"}; + + // lifetime preselection options + // apply lifetime cuts to V0 and cascade candidates + // unit of measurement: centimeters + // lifetime of K0Short ~2.6844 cm, no feeddown and plenty to cut + // lifetime of Lambda ~7.9 cm but keep in mind feeddown from cascades + // lifetime of Xi ~4.91 cm + // lifetime of Omega ~2.461 cm + Configurable> lifetimeCut{"lifetimeCut", {defaultLifetimeCuts[0], 4, {"lifetimeCutK0S", "lifetimeCutLambda", "lifetimeCutXi", "lifetimeCutOmega"}}, "Lifetime cut for V0s and cascades (cm)"}; + + // mass preselection options + Configurable massCutPhoton{"massCutPhoton", 0.3, "Photon max mass"}; + 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> massCutXi{"massCutXi", {defaultXiMassWindowParameters[0], 4, {"constant", "linear", "expoConstant", "expoRelax"}}, "mass parameters for Xi"}; + Configurable> massCutOm{"massCutOm", {defaultOmMassWindowParameters[0], 4, {"constant", "linear", "expoConstant", "expoRelax"}}, "mass parameters for Omega"}; + Configurable massWindownumberOfSigmas{"massWindownumberOfSigmas", 20, "number of sigmas around mass peaks to keep"}; + Configurable massWindowSafetyMargin{"massWindowSafetyMargin", 0.001, "Extra mass window safety margin (in GeV/c2)"}; + + // TPC PID preselection options + Configurable maxTPCpidNsigma{"maxTPCpidNsigma", 5.0, "Maximum TPC PID N sigma (in abs value)"}; + } preSelectOpts; + + float getMassSigmaK0Short(float pt) + { + return preSelectOpts.massCutK0->get("constant") + pt * preSelectOpts.massCutK0->get("linear") + preSelectOpts.massCutK0->get("expoConstant") * TMath::Exp(-pt / preSelectOpts.massCutK0->get("expoRelax")); + } + float getMassSigmaLambda(float pt) + { + return preSelectOpts.massCutLambda->get("constant") + pt * preSelectOpts.massCutLambda->get("linear") + preSelectOpts.massCutLambda->get("expoConstant") * TMath::Exp(-pt / preSelectOpts.massCutLambda->get("expoRelax")); + } + float getMassSigmaXi(float pt) + { + return preSelectOpts.massCutXi->get("constant") + pt * preSelectOpts.massCutXi->get("linear") + preSelectOpts.massCutXi->get("expoConstant") * TMath::Exp(-pt / preSelectOpts.massCutXi->get("expoRelax")); + } + float getMassSigmaOmega(float pt) + { + return preSelectOpts.massCutOm->get("constant") + pt * preSelectOpts.massCutOm->get("linear") + preSelectOpts.massCutOm->get("expoConstant") * TMath::Exp(-pt / preSelectOpts.massCutOm->get("expoRelax")); + } + + 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; + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // Helper structure to save v0 duplicates auxiliary info + struct V0DuplicateExtra { + bool isBestPA; + bool isBestDCADau; + bool isBestMLScore; + bool isBuildOk; + float PA; + float V0DCAToPVz; + float V0zVtx; + float MLScore; + }; + + 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 (preSelectOpts.preselectOnlyDesiredV0s.value == true) { + auto hPreselectionV0s = histos.add("hPreselectionV0s", "hPreselectionV0s", kTH1D, {{16, -0.5f, 15.5f}}); + hPreselectionV0s->GetXaxis()->SetBinLabel(1, "Not preselected"); + hPreselectionV0s->GetXaxis()->SetBinLabel(2, "#gamma"); + hPreselectionV0s->GetXaxis()->SetBinLabel(3, "K^{0}_{S}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(4, "#gamma, K^{0}_{S}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(5, "#Lambda"); + hPreselectionV0s->GetXaxis()->SetBinLabel(6, "#gamma, #Lambda"); + hPreselectionV0s->GetXaxis()->SetBinLabel(7, "K^{0}_{S}, #Lambda"); + hPreselectionV0s->GetXaxis()->SetBinLabel(8, "#gamma, K^{0}_{S}, #Lambda"); + hPreselectionV0s->GetXaxis()->SetBinLabel(9, "#bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(10, "#gamma, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(11, "K^{0}_{S}, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(12, "#gamma, K^{0}_{S}, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(13, "#Lambda, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(14, "#gamma, #Lambda, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(15, "K^{0}_{S}, #Lambda, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(16, "#gamma, K^{0}_{S}, #Lambda, #bar{#Lambda}"); + } + + if (preSelectOpts.preselectOnlyDesiredCascades.value == true) { + auto hPreselectionCascades = histos.add("hPreselectionCascades", "hPreselectionCascades", kTH1D, {{16, -0.5f, 15.5f}}); + hPreselectionCascades->GetXaxis()->SetBinLabel(1, "Not preselected"); + hPreselectionCascades->GetXaxis()->SetBinLabel(2, "#Xi^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(3, "#Xi^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(4, "#Xi^{-}, #Xi^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(5, "#Omega^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(6, "#Xi^{-}, #Omega^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(7, "#Xi^{+}, #Omega^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(8, "#Xi^{-}, #Xi^{+}, #Omega^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(9, "#Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(10, "#Xi^{-}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(11, "#Xi^{+}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(12, "#Xi^{-}, #Xi^{+}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(13, "#Omega^{-}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(14, "#Xi^{-}, #Omega^{-}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(15, "#Xi^{+}, #Omega^{-}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(16, "#Xi^{-}, #Xi^{+}, #Omega^{-}, #Omega^{+}"); + } + + 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"); + } + + if (DeduplicationOpts.deduplicationAlgorithm.value > 0) { + histos.add("DeduplicationQA/hMLScore", "hMLScore", kTH1F, {{200, 0.0f, 1.0f}}); + histos.add("DeduplicationQA/hPA", "hPA", kTH1F, {{200, 0.0f, 0.4f}}); + histos.add("DeduplicationQA/hBestPA", "hBestPA", kTH1F, {{200, 0.0f, 0.4f}}); + histos.add("DeduplicationQA/hBestDCADau", "hBestDCADau", kTH1F, {{200, -10.0f, 10.0f}}); + histos.add("DeduplicationQA/hBestMLScore", "hBestMLScore", kTH1F, {{200, 0.0f, 1.0f}}); + histos.add("DeduplicationQA/hPAOfBestMLScore", "hPAOfBestMLScore", kTH1F, {{200, 0.0f, 0.4f}}); + } + + auto hPrimaryV0s = histos.add("hPrimaryV0s", "hPrimaryV0s", kTH1D, {{2, -0.5f, 1.5f}}); + hPrimaryV0s->GetXaxis()->SetBinLabel(1, "All V0s"); + hPrimaryV0s->GetXaxis()->SetBinLabel(2, "Primary V0s"); + + mRunNumber = 0; + + mEnabledTables.resize(nTables, 0); + + LOGF(info, "Configuring tables to generate"); + auto& workflows = context.services().get(); + + TString listOfRequestors[nTables]; + 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; + listOfRequestors[i] = "manual enabling"; + } + 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 (DataSpecUtils::partialMatch(input.matcher, o2::header::DataOrigin("AOD"))) { + auto&& [origin, description, version] = DataSpecUtils::asConcreteDataMatcher(input.matcher); + std::string tableNameWithVersion = tableNames[i]; + if (version > 0) { + tableNameWithVersion += Form("_%03d", version); + } + if (input.matcher.binding == tableNameWithVersion) { + LOGF(info, "Device %s has subscribed to %s (version %i)", device.name, tableNames[i], version); + listOfRequestors[i].Append(Form("%s ", device.name.c_str())); + 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, requested by %s", tableNames[i], listOfRequestors[i].Data()); + 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; + + // Loading BDT model + if (DeduplicationOpts.deduplicationAlgorithm.value == 4 || DeduplicationOpts.deduplicationAlgorithm.value == 6) { + if (DeduplicationOpts.loadModelsFromCCDB) { + + // Retrieve the model from CCDB + ccdbApi.init(ccdbConfigurations.ccdburl); + + /// Fetching model for specific timestamp + LOG(info) << "Fetching model for timestamp: " << DeduplicationOpts.timestampCCDB.value; + + bool retrieveSuccess = ccdbApi.retrieveBlob(DeduplicationOpts.BDTPathCCDB.value, ".", metadata, DeduplicationOpts.timestampCCDB.value, false, DeduplicationOpts.BDTLocalPath.value); + if (retrieveSuccess) { + deduplication_bdt.initModel(DeduplicationOpts.BDTLocalPath.value, DeduplicationOpts.enableOptimizations.value); + } else { + LOG(fatal) << "Error encountered while fetching/loading the Gamma model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; + } + } else { + deduplication_bdt.initModel(DeduplicationOpts.BDTLocalPath.value, DeduplicationOpts.enableOptimizations.value); + } + } + } + + // 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; + } + + // Simple function to rank vectors based on values + std::vector rankSort(const std::vector& v_temp, bool descending = false) + { + std::vector> v_sort(v_temp.size()); + + // Pair each value with its original index + for (size_t i = 0U; i < v_temp.size(); ++i) { + v_sort[i] = std::make_pair(v_temp[i], i); + } + + // Sort by value - ascending: lowest gets rank 1, descending: highest gets rank 1 + + if (descending) { + std::sort(v_sort.begin(), v_sort.end(), [](const auto& a, const auto& b) { + return a.first > b.first; + }); + } else { + std::sort(v_sort.begin(), v_sort.end(), [](const auto& a, const auto& b) { + return a.first < b.first; + }); + } + + std::pair rank_tracker = std::make_pair(std::numeric_limits::quiet_NaN(), 0); + std::vector result(v_temp.size()); + + for (size_t i = 0U; i < v_sort.size(); ++i) { + // Only update rank if value is different from previous + if (v_sort[i].first != rank_tracker.first) { + rank_tracker = std::make_pair(v_sort[i].first, i + 1); // +1 for 1-based rank + } + result[v_sort[i].second] = rank_tracker.second; // assign rank to original index + } + + return result; + } + + //_______________________________________________________________________ + // Process duplicated photons + template + std::vector processDuplicates(TCollisions const& collisions, TTracks const& tracks, std::vector V0Grouped, size_t iV0) + { + auto pTrack = tracks.rawIteratorAt(V0Grouped[iV0].posTrackId); + auto nTrack = tracks.rawIteratorAt(V0Grouped[iV0].negTrackId); + + bool isPosTPCOnly = (pTrack.hasTPC() && !pTrack.hasITS() && !pTrack.hasTRD() && !pTrack.hasTOF()); + bool isNegTPCOnly = (nTrack.hasTPC() && !nTrack.hasITS() && !nTrack.hasTRD() && !nTrack.hasTOF()); + + // don't try to de-duplicate if no track is TPC only + if (!isPosTPCOnly && !isNegTPCOnly) { + return {}; + } + + // 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; + + float bestMLScore = -1; // a nonsense ML score + size_t bestMLScoreIndex = -1; + + // Defining context variables + int NDuplicates = 0; + float AvgPA = 0.0f; + + // Containers for ranking + std::vector paVec(V0Grouped[iV0].collisionIds.size(), 999.f); + std::vector v0zVec(V0Grouped[iV0].collisionIds.size(), 999.f); + + // Auxiliary vector to store V0 duplicate info + std::vector V0DuplicateExtras; + + // Loop over duplicates + for (size_t ic = 0; ic < V0Grouped[iV0].collisionIds.size(); ic++) { + + // Helper structure to save duplicates info - initializing with dummy values + V0DuplicateExtra v0DuplicateInfo; + v0DuplicateInfo.isBestPA = false; + v0DuplicateInfo.isBestDCADau = false; + v0DuplicateInfo.isBestMLScore = false; + v0DuplicateInfo.isBuildOk = false; + v0DuplicateInfo.PA = 10; + v0DuplicateInfo.V0DCAToPVz = 999.f; + v0DuplicateInfo.V0zVtx = 999.f; + v0DuplicateInfo.MLScore = -1; + + // We include V0DuplicateExtra info in the vector at this point to avoid indexing issues later + V0DuplicateExtras.push_back(v0DuplicateInfo); + + // get track parametrizations, collisions + auto posTrackPar = getTrackParCov(pTrack); + auto negTrackPar = getTrackParCov(nTrack); + auto const& collision = collisions.rawIteratorAt(V0Grouped[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)) { + continue; + } + } + 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)) { + continue; + } + } + } // 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(V0Grouped[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; + } + + // Calculating features for ML Analysis + if (DeduplicationOpts.deduplicationAlgorithm.value == 4 || DeduplicationOpts.deduplicationAlgorithm.value == 6) { + AvgPA += straHelper.v0.pointingAngle; + paVec[ic] = straHelper.v0.pointingAngle; + v0zVec[ic] = std::abs(straHelper.v0.position[2]); + NDuplicates++; + } + + // Updating values in the struct + V0DuplicateExtras[ic].isBuildOk = true; + V0DuplicateExtras[ic].PA = straHelper.v0.pointingAngle; + V0DuplicateExtras[ic].V0DCAToPVz = std::abs(straHelper.v0.v0DCAToPVz); + V0DuplicateExtras[ic].V0zVtx = std::abs(straHelper.v0.position[2]); + } // end build V0 + } // end candidate loop + + // Additional loop to perform ML Analysis if requested + if (DeduplicationOpts.deduplicationAlgorithm.value == 4 || DeduplicationOpts.deduplicationAlgorithm.value == 6) { + + // Preparing features + if (NDuplicates > 0) + AvgPA /= NDuplicates; + + // Get vector of ranks + std::vector paRanks = rankSort(paVec, false); + std::vector v0zRanks = rankSort(v0zVec, false); + + // Fill the ML score for all candidates + for (size_t ic = 0; ic < V0Grouped[iV0].collisionIds.size(); ic++) { + + // Skip if v0 was not built + if (!V0DuplicateExtras[ic].isBuildOk) + continue; + + // Input vector for BDT + std::vector inputFeatures{V0DuplicateExtras[ic].V0DCAToPVz, // 1. V0DCAToPVz + V0DuplicateExtras[ic].PA, // 2. Pointing Angle + V0DuplicateExtras[ic].V0zVtx, // 3. V0 Vtx z-position + static_cast(paRanks[ic]), // 4. Pointing Angle Rank + static_cast(NDuplicates), // 5. N. of Duplicates + AvgPA, // 6. Avg Pointing Angle + static_cast(v0zRanks[ic])}; // 7. V0 Vtx z Rank + + float* BDTProbability = deduplication_bdt.evalModel(inputFeatures); + + if (BDTProbability[1] > bestMLScore) { + bestMLScore = BDTProbability[1]; + bestMLScoreIndex = ic; + } + + // QA histo + histos.fill(HIST("DeduplicationQA/hMLScore"), BDTProbability[1]); + histos.fill(HIST("DeduplicationQA/hPA"), V0DuplicateExtras[ic].PA); + + // Updating BDT score info in the struct + V0DuplicateExtras[ic].MLScore = BDTProbability[1]; + } + } + + histos.fill(HIST("DeduplicationQA/hBestPA"), bestPointingAngle); + histos.fill(HIST("DeduplicationQA/hBestDCADau"), bestDCADaughters); + histos.fill(HIST("DeduplicationQA/hBestMLScore"), bestMLScore); + + // Final step: Defining the winners: + if (bestPointingAngleIndex != static_cast(-1)) + V0DuplicateExtras[bestPointingAngleIndex].isBestPA = true; + if (bestDCADaughtersIndex != static_cast(-1)) + V0DuplicateExtras[bestDCADaughtersIndex].isBestDCADau = true; + if (bestMLScoreIndex != static_cast(-1)) { + V0DuplicateExtras[bestMLScoreIndex].isBestMLScore = true; + histos.fill(HIST("DeduplicationQA/hPAOfBestMLScore"), V0DuplicateExtras[bestMLScoreIndex].PA); + } + + // return vector with duplicates info + return V0DuplicateExtras; + } + + 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 (DeduplicationOpts.deduplicationAlgorithm.value > 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++) { + + // skip single copy V0s + if (v0tableGrouped[iV0].collisionIds.size() == 1) { + continue; + } + + // process duplicates + std::vector deduplicationOutput = processDuplicates(collisions, tracks, v0tableGrouped, iV0); + + // skip if empty + if (deduplicationOutput.empty()) { + continue; + } + + // 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 (DeduplicationOpts.deduplicationAlgorithm.value == 1 && deduplicationOutput[ic].isBestPA) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + // algorithm 2: best DCA between daughters + if (DeduplicationOpts.deduplicationAlgorithm.value == 2 && deduplicationOutput[ic].isBestDCADau) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + // algorithm 3: best PA AND DCA between daughters + if (DeduplicationOpts.deduplicationAlgorithm.value == 3 && deduplicationOutput[ic].isBestDCADau && deduplicationOutput[ic].isBestPA) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + // algorithm 4: best ML Score + if (DeduplicationOpts.deduplicationAlgorithm.value == 4 && deduplicationOutput[ic].isBestMLScore) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + // Selection-based duplicate removal + if (DeduplicationOpts.deduplicationAlgorithm.value == 5 && deduplicationOutput[ic].PA <= DeduplicationOpts.PAthreshold) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + if (DeduplicationOpts.deduplicationAlgorithm.value == 6 && deduplicationOutput[ic].MLScore >= DeduplicationOpts.BDTthreshold) { + 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(); + 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 (useV0BufferForCascades.value == false) { + return; // don't attempt to mark needlessly + } + if (mEnabledTables[kStoredCascCores]) { + for (const auto& cascade : cascadeList) { + if (cascade.v0Id < 0) + continue; + 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)) { + products.v0dataLink(-1, -1); + continue; + } + } + + 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)) { + products.v0dataLink(-1, -1); + continue; + } + } + } + + if (!straHelper.buildV0Candidate(v0.collisionId, pvX, pvY, pvZ, posTrack, negTrack, posTrackPar, negTrackPar, v0.isCollinearV0, mEnabledTables[kV0Covs], v0BuilderOpts.generatePhotonCandidates)) { + products.v0dataLink(-1, -1); + continue; + } + if constexpr (requires { posTrack.tpcNSigmaEl(); }) { + if (preSelectOpts.preselectOnlyDesiredV0s) { + float lPt = RecoDecay::sqrtSumOfSquares( + straHelper.v0.positiveMomentum[0] + straHelper.v0.negativeMomentum[0], + straHelper.v0.positiveMomentum[1] + straHelper.v0.negativeMomentum[1]); + + float lPtot = RecoDecay::sqrtSumOfSquares( + straHelper.v0.positiveMomentum[0] + straHelper.v0.negativeMomentum[0], + straHelper.v0.positiveMomentum[1] + straHelper.v0.negativeMomentum[1], + straHelper.v0.positiveMomentum[2] + straHelper.v0.negativeMomentum[2]); + + float lLengthTraveled = RecoDecay::sqrtSumOfSquares( + straHelper.v0.position[0] - pvX, + straHelper.v0.position[1] - pvY, + straHelper.v0.position[2] - pvZ); + + uint8_t maskV0Preselection = 0; + + if ( // photon PID, mass, lifetime selection + std::abs(posTrack.tpcNSigmaEl()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaEl()) < preSelectOpts.maxTPCpidNsigma && + std::abs(straHelper.v0.massGamma) < preSelectOpts.massCutPhoton) { + BITSET(maskV0Preselection, selGamma); + } + + if ( // K0Short PID, mass, lifetime selection + std::abs(posTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassKaonNeutral * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutK0S") && + std::abs(straHelper.v0.massK0Short - o2::constants::physics::MassKaonNeutral) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaK0Short(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskV0Preselection, selK0Short); + } + + if ( // Lambda PID, mass, lifetime selection + std::abs(posTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + std::abs(straHelper.v0.massLambda - o2::constants::physics::MassLambda) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaLambda(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskV0Preselection, selLambda); + } + + if ( // antiLambda PID, mass, lifetime selection + std::abs(posTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + std::abs(straHelper.v0.massAntiLambda - o2::constants::physics::MassLambda) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaLambda(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskV0Preselection, selAntiLambda); + } + + histos.fill(HIST("hPreselectionV0s"), maskV0Preselection); + + if (maskV0Preselection == 0) { + 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); + histos.fill(HIST("hPrimaryV0s"), 0); + if (thisInfo.isPhysicalPrimary) + histos.fill(HIST("hPrimaryV0s"), 1); + } + 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 + } else { + products.v0dataLink(-1, -1); + } + } + + // 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_keepOnlyPhysicalPrimary && !mcParticle.isPhysicalPrimary()) + continue; // skip secondary MC V0s + + 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); + histos.fill(HIST("hPrimaryV0s"), 0); + if (info.isPhysicalPrimary) + histos.fill(HIST("hPrimaryV0s"), 1); + } + 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 (cascade.v0Id < 0 || 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++; + + if constexpr (requires { posTrack.tpcNSigmaEl(); }) { + if (preSelectOpts.preselectOnlyDesiredCascades) { + float lPt = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.bachelorMomentum[0] + straHelper.cascade.positiveMomentum[0] + straHelper.cascade.negativeMomentum[0], + straHelper.cascade.bachelorMomentum[1] + straHelper.cascade.positiveMomentum[1] + straHelper.cascade.negativeMomentum[1]); + + float lPtot = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.bachelorMomentum[0] + straHelper.cascade.positiveMomentum[0] + straHelper.cascade.negativeMomentum[0], + straHelper.cascade.bachelorMomentum[1] + straHelper.cascade.positiveMomentum[1] + straHelper.cascade.negativeMomentum[1], + straHelper.cascade.bachelorMomentum[2] + straHelper.cascade.positiveMomentum[2] + straHelper.cascade.negativeMomentum[2]); + + float lV0Ptot = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.positiveMomentum[0] + straHelper.cascade.negativeMomentum[0], + straHelper.cascade.positiveMomentum[1] + straHelper.cascade.negativeMomentum[1], + straHelper.cascade.positiveMomentum[2] + straHelper.cascade.negativeMomentum[2]); + + float lLengthTraveled = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.cascadePosition[0] - pvX, + straHelper.cascade.cascadePosition[1] - pvY, + straHelper.cascade.cascadePosition[2] - pvZ); + + float lV0LengthTraveled = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.v0Position[0] - straHelper.cascade.cascadePosition[0], + straHelper.cascade.v0Position[1] - straHelper.cascade.cascadePosition[1], + straHelper.cascade.v0Position[2] - straHelper.cascade.cascadePosition[2]); + + uint8_t maskCascadePreselection = 0; + + if ( // XiMinus PID and mass selection + straHelper.cascade.charge < 0 && + std::abs(posTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(bachTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lV0LengthTraveled / (lV0Ptot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + o2::constants::physics::MassXiMinus * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutXi") && + std::abs(straHelper.cascade.massXi - o2::constants::physics::MassXiMinus) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaXi(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskCascadePreselection, selXiMinus); + } + + if ( // XiPlus PID and mass selection + straHelper.cascade.charge > 0 && + std::abs(posTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(bachTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lV0LengthTraveled / (lV0Ptot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + o2::constants::physics::MassXiMinus * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutXi") && + std::abs(straHelper.cascade.massXi - o2::constants::physics::MassXiMinus) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaXi(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskCascadePreselection, selXiPlus); + } + + if ( // OmegaMinus PID and mass selection + straHelper.cascade.charge < 0 && + std::abs(posTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(bachTrack.tpcNSigmaKa()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lV0LengthTraveled / (lV0Ptot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + o2::constants::physics::MassOmegaMinus * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutOmega") && + std::abs(straHelper.cascade.massOmega - o2::constants::physics::MassOmegaMinus) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaOmega(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskCascadePreselection, selOmegaMinus); + } + + if ( // OmegaPlus PID and mass selection + straHelper.cascade.charge > 0 && + std::abs(posTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(bachTrack.tpcNSigmaKa()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lV0LengthTraveled / (lV0Ptot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + o2::constants::physics::MassOmegaMinus * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutOmega") && + std::abs(straHelper.cascade.massOmega - o2::constants::physics::MassOmegaMinus) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaOmega(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskCascadePreselection, selOmegaPlus); + } + + histos.fill(HIST("hPreselectionCascades"), maskCascadePreselection); + + if (maskCascadePreselection == 0) { + products.cascdataLink(-1); + interlinks.cascadeToCascCores.push_back(-1); + continue; + } + } + } + + // 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_keepOnlyPhysicalPrimary && !mcParticle.isPhysicalPrimary()) + continue; // skip secondary MC cascades + + 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); + std::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); + } + + void processRealDataWithPID(soa::Join const& collisions, aod::V0s const& v0s, aod::Cascades const& cascades, aod::TrackedCascades const& trackedCascades, FullTracksExtIUWithPID const& tracks, aod::BCsWithTimestamps const& bcs) + { + dataProcess(collisions, static_cast(nullptr), v0s, cascades, trackedCascades, tracks, bcs, static_cast(nullptr)); + } + + void processRealDataRun2WithPID(soa::Join const& collisions, aod::V0s const& v0s, aod::Cascades const& cascades, FullTracksExtWithPID const& tracks, aod::BCsWithTimestamps const& bcs) + { + dataProcess(collisions, static_cast(nullptr), v0s, cascades, static_cast(nullptr), tracks, bcs, static_cast(nullptr)); + } + + void processMonteCarloWithPID(soa::Join const& collisions, aod::McCollisions const& mccollisions, aod::V0s const& v0s, aod::Cascades const& cascades, aod::TrackedCascades const& trackedCascades, FullTracksExtLabeledIUWithPID const& tracks, aod::BCsWithTimestamps const& bcs, aod::McParticles const& mcParticles) + { + dataProcess(collisions, mccollisions, v0s, cascades, trackedCascades, tracks, bcs, mcParticles); + } + + void processMonteCarloRun2WithPID(soa::Join const& collisions, aod::McCollisions const& mccollisions, aod::V0s const& v0s, aod::Cascades const& cascades, FullTracksExtLabeledWithPID 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); + PROCESS_SWITCH(StrangenessBuilder, processRealDataWithPID, "process real data", false); + PROCESS_SWITCH(StrangenessBuilder, processRealDataRun2WithPID, "process real data (Run 2)", false); + PROCESS_SWITCH(StrangenessBuilder, processMonteCarloWithPID, "process monte carlo", false); + PROCESS_SWITCH(StrangenessBuilder, processMonteCarloRun2WithPID, "process monte carlo (Run 2)", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + auto strangenessBuilderTask = adaptAnalysisTask(cfgc); + bool isRun3 = true, hasRunInfo = false; + bool isMC = false, hasDataTypeInfo = false; + if (cfgc.options().hasOption("aod-metadata-Run") == true) { + hasRunInfo = true; + if (cfgc.options().get("aod-metadata-Run") == "2") { + isRun3 = false; + } + } + if (cfgc.options().hasOption("aod-metadata-DataType") == true) { + hasDataTypeInfo = true; + if (cfgc.options().get("aod-metadata-DataType") == "MC") { + isMC = true; + } + } + + int idxSwitches[8]; // 8 switches (real / real r2 / MC / MC r2 + PID) + bool autoConfigureProcessConfig = true; + bool withPID = false; + + for (size_t ipar = 0; ipar < strangenessBuilderTask.options.size(); ipar++) { + auto option = strangenessBuilderTask.options[ipar]; + if (option.name == "processRealData") { + idxSwitches[0] = ipar; + } + if (option.name == "processRealDataRun2") { + idxSwitches[1] = ipar; + } + if (option.name == "processMonteCarlo") { + idxSwitches[2] = ipar; + } + if (option.name == "processMonteCarloRun2") { + idxSwitches[3] = ipar; + } + if (option.name == "processRealDataWithPID") { + idxSwitches[4] = ipar; + } + if (option.name == "processRealDataRun2WithPID") { + idxSwitches[5] = ipar; + } + if (option.name == "processMonteCarloWithPID") { + idxSwitches[6] = ipar; + } + if (option.name == "processMonteCarloRun2WithPID") { + idxSwitches[7] = ipar; + } + if (option.name == "autoConfigureProcess") { + autoConfigureProcessConfig = option.defaultValue.get(); // check if autoconfig requested + } + // use withPID in case preselection is requested + if (option.name == "preSelectOpts.preselectOnlyDesiredV0s" || option.name == "preSelectOpts.preselectOnlyDesiredCascades") { + withPID = withPID || option.defaultValue.get(); + } + } + if ((!hasRunInfo || !hasDataTypeInfo) && autoConfigureProcessConfig) { + throw std::runtime_error("Autoconfigure requested but no metadata information found! Please check if --aod-file was used in the last workflow added in the execution and if the AO2D in question has metadata saved in it."); + } + + // positions of switches are known. Next: flip if asked for + if (autoConfigureProcessConfig) { + int relevantProcess = static_cast(!isRun3) + 2 * static_cast(isMC) + 4 * static_cast(withPID); + LOGF(info, "Automatic configuration of process switches requested! Autodetected settings: isRun3? %i, isMC? %i, withPID? %i (switch #%i)", hasRunInfo, hasDataTypeInfo, isRun3, isMC, withPID, relevantProcess); + for (size_t idx = 0; idx < 8; idx++) { + auto option = strangenessBuilderTask.options[idxSwitches[idx]]; + option.defaultValue = false; // switch all off + } + strangenessBuilderTask.options[idxSwitches[relevantProcess]].defaultValue = true; + } + + return WorkflowSpec{ + strangenessBuilderTask}; +} diff --git a/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx b/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx new file mode 100644 index 00000000000..7689468d6bc --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx @@ -0,0 +1,1813 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 TOF PID +// *+-+*+-+*+-+*+-+*+-+*+-+* +// +/// \author Nicolò Jacazio +/// \author David Dobrigkeit Chinellato +/// \since 11/05/2023 +/// \brief Table producer for V0 daughter PID info +// +// This task produces daughter PID information for strange daughters +// taking into account the (candidate-by-candidate) time spent as a heavier +// (strange, weakly-decaying) particle. This task is meant to be a test, as +// it hasn't been fully tested yet! Use at your own peril for now :-) + +#include "TableHelper.h" + +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +// For original data loops +using V0OriginalDatas = soa::Join; +using CascOriginalDatas = soa::Join; +using TracksWithAllExtras = soa::Join; + +// For derived data analysis +using dauTracks = soa::Join; +using V0DerivedDatas = soa::Join; +using V0DerivedDatasMC = soa::Join; +using CascDerivedDatas = soa::Join; +using CascDerivedDatasMC = soa::Join; + +struct strangenesstofpid { + // TOF pid for strangeness (recalculated with topology) + Produces v0tofpid; // table with Nsigmas + Produces v0tofbeta; // table with betas + Produces v0tofdebugs; // table with extra debug information + Produces v0tofnsigmas; // table with nsigmas + Produces casctofpids; // cascades: table with base info + Produces casctofnsigmas; // cascades: table with Nsigmas + + Service ccdb; + + // mean vertex position to be used if no collision associated + o2::dataformats::MeanVertexObject* mVtx = nullptr; + + // LUT for Propagator + TrackLTIntegral + o2::base::MatLayerCylSet* lut = nullptr; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // master switches + Configurable calculationMethod{"calculationMethod", 0, "algorithm for TOF calculation. 0: fast analytical withouot eloss, 1: O2 Propagator + trackLTIntegral (slow), 2: both methods and do comparison studies (slow)"}; + Configurable calculateV0s{"calculateV0s", -1, "calculate V0-related TOF PID (0: no, 1: yes, -1: auto)"}; + Configurable calculateCascades{"calculateCascades", -1, "calculate cascade-related TOF PID (0: no, 1: yes, -1: auto)"}; + Configurable reassociateTracks{"reassociateTracks", true, "if true, reassociate tracks to the collision the V0 or cascade belongs to. Relevant especially at high IR"}; + Configurable doBCshift{"doBCshift", true, "if true, perform time shift for collisions in different BCs when reassigning"}; + Configurable rejectUndefinedTof{"rejectUndefinedTof", true, "if true, reject tracks with TOF signal 0.000f for safety"}; + + // auxiliary / debug tables as desired + Configurable calculateV0TOFPIDs{"calculateV0TOFPIDs", -1, "calculate V0TOFPIDs table (0: no, 1: yes, -1: auto)"}; + Configurable calculateV0TOFBetas{"calculateV0TOFBetas", -1, "calculate V0TOFBetas table (0: no, 1: yes, -1: auto)"}; + Configurable calculateV0TOFDebugs{"calculateV0TOFDebugs", -1, "calculate V0TOFDebugs table (0: no, 1: yes, -1: auto)"}; + Configurable calculateCascTOFPIDs{"calculateCascTOFPIDs", -1, "calculate CascTOFPIDs table (0: no, 1: yes, -1: auto)"}; + + // Operation and minimisation criteria + struct : ConfigurableGroup { + Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; + Configurable tofPosition{"tofPosition", 377.934f, "TOF effective (inscribed) radius"}; + } propagationConfiguration; + + Configurable doQA{"doQA", false, "create QA histos"}; + Configurable doNSigmas{"doNSigmas", true, "calculate TOF N-sigma"}; + Configurable doQANSigma{"doQANSigma", false, "create QA of Nsigma histos"}; + + // configurables related to V0s + struct : ConfigurableGroup { + std::string prefix = "v0Calibration"; + Configurable qaDCADau{"qaDCADau", 0.5, "DCA daughters (cm) for QA plots"}; + Configurable qaCosPA{"qaCosPA", 0.999, "CosPA for QA plots"}; + Configurable qaMassWindow{"qaMassWindow", 0.005, "Mass window around expected (in GeV/c2) for QA plots"}; + Configurable qaTPCNSigma{"qaTPCNSigma", 5, "TPC N-sigma to apply for qa plots"}; + } v0Group; + + // configurables related to V0s + struct : ConfigurableGroup { + std::string prefix = "cascadeCalibration"; + Configurable qaV0DCADau{"qaV0DCADau", 0.5, "DCA daughters (cm) for QA plots"}; + Configurable qaCascDCADau{"qaCascDCADau", 0.5, "DCA daughters (cm) for QA plots"}; + Configurable qaV0CosPA{"qaV0CosPA", 0.995, "CosPA for QA plots"}; + Configurable qaCascCosPA{"qaCascCosPA", 0.995, "CosPA for QA plots"}; + Configurable qaMassWindow{"qaMassWindow", 0.005, "Mass window around expected (in GeV/c2) for QA plots"}; + Configurable qaTPCNSigma{"qaTPCNSigma", 5, "TPC N-sigma to apply for qa plots"}; + } cascadeGroup; + + // 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 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"}; + } ccdbConfigurations; + + // manual + Configurable useCustomRunNumber{"useCustomRunNumber", false, "Use custom timestamp"}; + Configurable manualRunNumber{"manualRunNumber", 544122, "manual run number if no collisions saved"}; + + struct : ConfigurableGroup { + ConfigurableAxis axisPosition{"axisPosition", {400, -400.f, +400.f}, "position (cm)"}; + ConfigurableAxis axisEta{"axisEta", {20, -1.0f, +1.0f}, "#eta"}; + ConfigurableAxis axisDeltaTime{"axisDeltaTime", {2000, -1000.0f, +1000.0f}, "delta-time (ps)"}; + ConfigurableAxis axisDeltaTimeVsPrimaryCalculation{"axisDeltaTimeVsPrimaryCalculation", {500, -500.0f, +500.0f}, "delta-time (ps)"}; + ConfigurableAxis axisTime{"axisTime", {400, 10000.0f, +50000.0f}, "T (ps)"}; + ConfigurableAxis axisNSigma{"axisNSigma", {200, -10.0f, +10.0f}, "N(#sigma)"}; + ConfigurableAxis axisRatioMethods{"axisRatioMethods", {400, 0.9f, 1.9f}, "T_{method 1}/T_{method 0}"}; + ConfigurableAxis axisSnp{"axisSnp", {220, -1.1f, 1.1f}, "snp"}; + + // master p axis + ConfigurableAxis axisP{"axisP", {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)"}; + + // for zooming in at low values only (e-loss studies and effective correction) + ConfigurableAxis axisSmallP{"axisSmallP", {250, 0.0f, 2.5f}, "p_{T} (GeV/c)"}; + + // for BC shift QA plots + // binning to actually match BC shifts but show in picoseconds + const double bcShiftValuePS = o2::constants::lhc::LHCBunchSpacingNS * 1000.0f; + ConfigurableAxis axisBCshift{"axisBCshift", {130, -120.5f * bcShiftValuePS, 9.5f * bcShiftValuePS}, "time shift (ps)"}; + + // very broad time axis + ConfigurableAxis axisTimeLong{"axisTimeLong", {3000, -1500000.0f, 1500000.0f}, "time (ps)"}; + } axes; // aggregate axes fo simplicity of navigation in HY + + // for n-sigma calibration + bool nSigmaCalibLoaded; + TList* nSigmaCalibObjects = nullptr; + TH1 *hMeanPosLaPi = nullptr, *hSigmaPosLaPi = nullptr; + TH1 *hMeanPosLaPr = nullptr, *hSigmaPosLaPr = nullptr; + TH1 *hMeanNegLaPi = nullptr, *hSigmaNegLaPi = nullptr; + TH1 *hMeanNegLaPr = nullptr, *hSigmaNegLaPr = nullptr; + TH1 *hMeanPosK0Pi = nullptr, *hSigmaPosK0Pi = nullptr; + TH1 *hMeanNegK0Pi = nullptr, *hSigmaNegK0Pi = nullptr; + TH1 *hMeanPosXiPi = nullptr, *hSigmaPosXiPi = nullptr; + TH1 *hMeanPosXiPr = nullptr, *hSigmaPosXiPr = nullptr; + TH1 *hMeanNegXiPi = nullptr, *hSigmaNegXiPi = nullptr; + TH1 *hMeanNegXiPr = nullptr, *hSigmaNegXiPr = nullptr; + TH1 *hMeanBachXiPi = nullptr, *hSigmaBachXiPi = nullptr; + TH1 *hMeanPosOmPi = nullptr, *hSigmaPosOmPi = nullptr; + TH1 *hMeanPosOmPr = nullptr, *hSigmaPosOmPr = nullptr; + TH1 *hMeanNegOmPi = nullptr, *hSigmaNegOmPi = nullptr; + TH1 *hMeanNegOmPr = nullptr, *hSigmaNegOmPr = nullptr; + TH1 *hMeanBachOmKa = nullptr, *hSigmaBachOmKa = nullptr; + + int mRunNumber; + float d_bz; + float maxSnp; // max sine phi for propagation + float maxStep; // max step size (cm) for propagation + + // enum to keep track of the TOF-related properties for V0s + enum tofEnum { kLength = 0, + kHasTOF, + kNEnums }; + + // bookkeep propagation failures and successes + enum typesOfPropagation { kPropagPosV0 = 0, + kPropagNegV0, + kPropagPosCasc, + kPropagNegCasc, + kPropagBachCasc, + kPropagTypes }; + + /// function to calculate track length of this track up to a certain segment of a detector + /// to be used internally in another function that calculates length until it finds the proper one + /// warning: this could be optimised further for speed + /// \param track the input track + /// \param x1 x of the first point of the detector segment + /// \param y1 y of the first point of the detector segment + /// \param x2 x of the first point of the detector segment + /// \param y2 y of the first point of the detector segment + /// \param magneticField the magnetic field to use when propagating + float trackLengthToSegment(o2::track::TrackPar track, float x1, float y1, float x2, float y2, float magneticField) + { + // don't make use of the track parametrization + float length = -104; + + // causality protection + std::array mom; + track.getPxPyPzGlo(mom); + // get start point + std::array startPoint; + track.getXYZGlo(startPoint); + + // better replaced with scalar momentum check later + // if (((x1 + x2) * mom[0] + (y1 + y2) * mom[1]) < 0.0f) + // return -101; + + // get circle X, Y please + o2::math_utils::CircleXYf_t trcCircle; + float sna, csa; + track.getCircleParams(magneticField, trcCircle, sna, csa); + + // Calculate necessary inner product + float segmentModulus = std::hypot(x2 - x1, y2 - y1); + float alongSegment = ((trcCircle.xC - x1) * (x2 - x1) + (trcCircle.yC - y1) * (y2 - y1)) / segmentModulus; + + // find point of closest approach between segment and circle center + float pcaX = (x2 - x1) * alongSegment / segmentModulus + x1; + float pcaY = (y2 - y1) * alongSegment / segmentModulus + y1; + + float centerDistToPC = std::hypot(pcaX - trcCircle.xC, pcaY - trcCircle.yC); + + // distance pca-to-intercept in multiples of segment modulus (for convenience) + if (centerDistToPC > trcCircle.rC) + return -103; + + float pcaToIntercept = TMath::Sqrt(TMath::Abs(trcCircle.rC * trcCircle.rC - centerDistToPC * centerDistToPC)); + + float interceptX1 = pcaX + (x2 - x1) / segmentModulus * pcaToIntercept; + float interceptY1 = pcaY + (y2 - y1) / segmentModulus * pcaToIntercept; + float interceptX2 = pcaX - (x2 - x1) / segmentModulus * pcaToIntercept; + float interceptY2 = pcaY - (y2 - y1) / segmentModulus * pcaToIntercept; + + float scalarCheck1 = ((x2 - x1) * (interceptX1 - x1) + (y2 - y1) * (interceptY1 - y1)) / segmentModulus; + float scalarCheck2 = ((x2 - x1) * (interceptX2 - x1) + (y2 - y1) * (interceptY2 - y1)) / segmentModulus; + + float cosAngle1 = -1000, sinAngle1 = -1000, modulus1 = -1000; + float cosAngle2 = -1000, sinAngle2 = -1000, modulus2 = -1000; + float length1 = -1000, length2 = -1000; + + modulus1 = std::hypot(interceptX1 - trcCircle.xC, interceptY1 - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); + cosAngle1 = (interceptX1 - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (interceptY1 - trcCircle.yC) * (startPoint[1] - trcCircle.yC); + sinAngle1 = (interceptX1 - trcCircle.xC) * (startPoint[1] - trcCircle.yC) - (interceptY1 - trcCircle.yC) * (startPoint[0] - trcCircle.xC); + cosAngle1 /= modulus1; + sinAngle1 /= modulus1; + length1 = trcCircle.rC * TMath::ACos(cosAngle1); + length1 *= sqrt(1.0f + track.getTgl() * track.getTgl()); + + modulus2 = std::hypot(interceptX2 - trcCircle.xC, interceptY2 - trcCircle.yC) * std::hypot(startPoint[0] - trcCircle.xC, startPoint[1] - trcCircle.yC); + cosAngle2 = (interceptX2 - trcCircle.xC) * (startPoint[0] - trcCircle.xC) + (interceptY2 - trcCircle.yC) * (startPoint[1] - trcCircle.yC); + sinAngle2 = (interceptX2 - trcCircle.xC) * (startPoint[1] - trcCircle.yC) - (interceptY2 - trcCircle.yC) * (startPoint[0] - trcCircle.xC); + cosAngle2 /= modulus2; + sinAngle2 /= modulus2; + length2 = trcCircle.rC * TMath::ACos(cosAngle2); + length2 *= sqrt(1.0f + track.getTgl() * track.getTgl()); + + // rotate transverse momentum vector such that it is at intercepts + float angle1 = TMath::ACos(cosAngle1); + if (sinAngle1 < 0) + angle1 *= -1.0f; + float px1 = +TMath::Cos(angle1) * mom[0] + TMath::Sin(angle1) * mom[1]; + float py1 = -TMath::Sin(angle1) * mom[0] + TMath::Cos(angle1) * mom[1]; + + float angle2 = TMath::ACos(cosAngle2); + if (sinAngle2 < 0) + angle2 *= -1.0f; + float px2 = +TMath::Cos(angle2) * mom[0] + TMath::Sin(angle2) * mom[1]; + float py2 = -TMath::Sin(angle2) * mom[0] + TMath::Cos(angle2) * mom[1]; + + float midSegX = 0.5f * (x2 + x1); + float midSegY = 0.5f * (y2 + y1); + + float scalarMomentumCheck1 = px1 * midSegX + py1 * midSegY; + float scalarMomentumCheck2 = px2 * midSegX + py2 * midSegY; + + if (scalarCheck1 > 0.0f && scalarCheck1 < segmentModulus && scalarMomentumCheck1 > 0.0f) { + length = length1; + // X = interceptX1; Y = interceptY1; + } + if (scalarCheck2 > 0.0f && scalarCheck2 < segmentModulus && scalarMomentumCheck2 > 0.0f) { + length = length2; + // X = interceptX2; Y = interceptY2; + } + return length; + } + + /// function to calculate track length of this track up to a certain segmented detector + /// \param track the input track + /// \param magneticField the magnetic field to use when propagating + float findInterceptLength(o2::track::TrackPar track, float magneticField) + { + float length = 1e+6; + for (int iSeg = 0; iSeg < 18; iSeg++) { + // Detector segmentation loop + float segmentAngle = 20.0f / 180.0f * TMath::Pi(); + float theta = static_cast(iSeg) * 20.0f / 180.0f * TMath::Pi(); + float halfWidth = propagationConfiguration.tofPosition * TMath::Tan(0.5f * segmentAngle); + float x1 = TMath::Cos(theta) * (-halfWidth) + TMath::Sin(theta) * propagationConfiguration.tofPosition; + float y1 = -TMath::Sin(theta) * (-halfWidth) + TMath::Cos(theta) * propagationConfiguration.tofPosition; + float x2 = TMath::Cos(theta) * (+halfWidth) + TMath::Sin(theta) * propagationConfiguration.tofPosition; + float y2 = -TMath::Sin(theta) * (+halfWidth) + TMath::Cos(theta) * propagationConfiguration.tofPosition; + float thisLength = trackLengthToSegment(track, x1, y1, x2, y2, magneticField); + if (thisLength < length && thisLength > 0) { + length = thisLength; + } + } + if (length > 1e+5) + length = -100; // force negative to avoid misunderstandings + return length; + } + + void init(InitContext& initContext) + { + if (calculateV0s.value < 0) { + // check if TOF information is required, enable if so + calculateV0s.value = isTableRequiredInWorkflow(initContext, "V0TOFNSigmas"); + if (calculateV0s.value > 0) { + LOGF(info, "Strangeness TOF PID: V0 calculations enabled automatically"); + } + } + if (calculateCascades.value < 0) { + // check if TOF information is required, enable if so + calculateCascades.value = isTableRequiredInWorkflow(initContext, "CascTOFNSigmas"); + if (calculateCascades.value > 0) { + LOGF(info, "Strangeness TOF PID: Cascade calculations enabled automatically"); + } + } + if (calculateV0TOFPIDs.value < 0) { + // check if TOF information is required, enable if so + calculateV0TOFPIDs.value = isTableRequiredInWorkflow(initContext, "V0TOFPIDs"); + if (calculateV0TOFPIDs.value > 0) { + LOGF(info, "Strangeness TOF PID: V0TOFPIDs calculations enabled automatically"); + } + } + if (calculateV0TOFBetas.value < 0) { + // check if TOF information is required, enable if so + calculateV0TOFBetas.value = isTableRequiredInWorkflow(initContext, "V0TOFBetas"); + if (calculateV0TOFBetas.value > 0) { + LOGF(info, "Strangeness TOF PID: V0TOFBetas calculations enabled automatically"); + } + } + if (calculateV0TOFDebugs.value < 0) { + // check if TOF information is required, enable if so + calculateV0TOFDebugs.value = isTableRequiredInWorkflow(initContext, "V0TOFDebugs"); + if (calculateV0TOFDebugs.value > 0) { + LOGF(info, "Strangeness TOF PID: V0TOFDebugs calculations enabled automatically"); + } + } + if (calculateCascTOFPIDs.value < 0) { + // check if TOF information is required, enable if so + calculateCascTOFPIDs.value = isTableRequiredInWorkflow(initContext, "CascTOFPIDs"); + if (calculateCascTOFPIDs.value > 0) { + LOGF(info, "Strangeness TOF PID: CascTOFPIDs calculations enabled automatically"); + } + } + + nSigmaCalibLoaded = false; + nSigmaCalibObjects = nullptr; + + // for n-sigma calibration + hMeanPosLaPi = nullptr; + hSigmaPosLaPi = nullptr; + hMeanPosLaPr = nullptr; + hSigmaPosLaPr = nullptr; + hMeanNegLaPi = nullptr; + hSigmaNegLaPi = nullptr; + hMeanNegLaPr = nullptr; + hSigmaNegLaPr = nullptr; + hMeanPosK0Pi = nullptr; + hSigmaNegK0Pi = nullptr; + hMeanNegK0Pi = nullptr; + hSigmaNegK0Pi = nullptr; + + mRunNumber = 0; + d_bz = 0; + maxSnp = 0.85f; // could be changed later + maxStep = 2.00f; // could be changed later + + ccdb->setURL(ccdbConfigurations.ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // per event + histos.add("hCandidateCounter", "hCandidateCounter", kTH1F, {{500, -0.5f, 499.5f}}); + + histos.add("hV0PositiveBCShift", "hV0PositiveBCShift", kTH1F, {axes.axisBCshift}); + histos.add("hV0NegativeBCShift", "hV0NegativeBCShift", kTH1F, {axes.axisBCshift}); + histos.add("hCascadePositiveBCShift", "hCascadePositiveBCShift", kTH1F, {axes.axisBCshift}); + histos.add("hCascadeNegativeBCShift", "hCascadeNegativeBCShift", kTH1F, {axes.axisBCshift}); + histos.add("hCascadeBachelorBCShift", "hCascadeBachelorBCShift", kTH1F, {axes.axisBCshift}); + + histos.add("hTOFSignalPositive", "hTOFSignalPositive", kTH1F, {axes.axisTimeLong}); + histos.add("hTOFSignalNegative", "hTOFSignalNegative", kTH1F, {axes.axisTimeLong}); + + histos.add("h2dTOFSignalPositive", "h2dTOFSignalPositive", kTH2F, {axes.axisTimeLong, axes.axisBCshift}); + histos.add("h2dTOFSignalNegative", "h2dTOFSignalNegative", kTH2F, {axes.axisTimeLong, axes.axisBCshift}); + + histos.add("h2dTOFSignalCascadePositive", "h2dTOFSignalCascadePositive", kTH2F, {axes.axisTimeLong, axes.axisBCshift}); + histos.add("h2dTOFSignalCascadeNegative", "h2dTOFSignalCascadeNegative", kTH2F, {axes.axisTimeLong, axes.axisBCshift}); + histos.add("h2dTOFSignalCascadeBachelor", "h2dTOFSignalCascadeBachelor", kTH2F, {axes.axisTimeLong, axes.axisBCshift}); + + histos.add("hCollisionTimes", "hCollisionTimes", kTH1F, {{2000, -1000.0f, 1000.0f}}); + + // measured vs expected total time QA + if (doQA) { + // if in mode 1, bookkeep the failures of propagation + if (calculationMethod.value == 1) { + histos.add("hPropagationBookkeeping", "hPropagationBookkeeping", kTProfile, {{5, -0.5f, 4.5f}}); + } + + // standard deltaTime values + if (calculateV0s.value > 0) { + histos.add("h2dDeltaTimePositiveLambdaPi", "h2dDeltaTimePositiveLambdaPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dDeltaTimeNegativeLambdaPi", "h2dDeltaTimeNegativeLambdaPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dDeltaTimePositiveLambdaPr", "h2dDeltaTimePositiveLambdaPr", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dDeltaTimeNegativeLambdaPr", "h2dDeltaTimeNegativeLambdaPr", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dDeltaTimePositiveK0ShortPi", "h2dDeltaTimePositiveK0ShortPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dDeltaTimeNegativeK0ShortPi", "h2dDeltaTimeNegativeK0ShortPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + + // delta time with respect to primary-like calculation + histos.add("h2dDiffFromPrimCalcPositiveLambdaPi", "h2dDiffFromPrimCalcPositiveLambdaPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dDiffFromPrimCalcNegativeLambdaPi", "h2dDiffFromPrimCalcNegativeLambdaPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dDiffFromPrimCalcPositiveLambdaPr", "h2dDiffFromPrimCalcPositiveLambdaPr", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dDiffFromPrimCalcNegativeLambdaPr", "h2dDiffFromPrimCalcNegativeLambdaPr", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dDiffFromPrimCalcPositiveK0ShortPi", "h2dDiffFromPrimCalcPositiveK0ShortPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dDiffFromPrimCalcNegativeK0ShortPi", "h2dDiffFromPrimCalcNegativeK0ShortPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + + // QA collision reassociation fraction (from track -> V0/cascade coll index) + histos.add("h2dCorrectAssocPositiveLambdaPi", "h2dCorrectAssocPositiveLambdaPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dCorrectAssocNegativeLambdaPi", "h2dCorrectAssocNegativeLambdaPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dCorrectAssocPositiveLambdaPr", "h2dCorrectAssocPositiveLambdaPr", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dCorrectAssocNegativeLambdaPr", "h2dCorrectAssocNegativeLambdaPr", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dCorrectAssocPositiveK0ShortPi", "h2dCorrectAssocPositiveK0ShortPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dCorrectAssocNegativeK0ShortPi", "h2dCorrectAssocNegativeK0ShortPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + } + + if (calculateCascades.value > 0) { + histos.add("h2dposDeltaTimeAsXiPi", "h2dposDeltaTimeAsXiPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dposDeltaTimeAsXiPr", "h2dposDeltaTimeAsXiPr", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dnegDeltaTimeAsXiPi", "h2dnegDeltaTimeAsXiPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dnegDeltaTimeAsXiPr", "h2dnegDeltaTimeAsXiPr", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dbachDeltaTimeAsXiPi", "h2dbachDeltaTimeAsXiPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + + histos.add("h2dposDeltaTimeAsOmPi", "h2dposDeltaTimeAsOmPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dposDeltaTimeAsOmPr", "h2dposDeltaTimeAsOmPr", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dnegDeltaTimeAsOmPi", "h2dnegDeltaTimeAsOmPi", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dnegDeltaTimeAsOmPr", "h2dnegDeltaTimeAsOmPr", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + histos.add("h2dbachDeltaTimeAsOmKa", "h2dbachDeltaTimeAsOmKa", {HistType::kTH3F, {axes.axisP, axes.axisEta, axes.axisDeltaTime}}); + + // delta time with respect to primary-like calculation + histos.add("h2dposDiffFromPrimCalcAsXiPi", "h2dposDiffFromPrimCalcAsXiPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dposDiffFromPrimCalcAsXiPr", "h2dposDiffFromPrimCalcAsXiPr", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dnegDiffFromPrimCalcAsXiPi", "h2dnegDiffFromPrimCalcAsXiPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dnegDiffFromPrimCalcAsXiPr", "h2dnegDiffFromPrimCalcAsXiPr", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dbachDiffFromPrimCalcAsXiPi", "h2dbachDiffFromPrimCalcAsXiPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + + histos.add("h2dposDiffFromPrimCalcAsOmPi", "h2dposDiffFromPrimCalcAsOmPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dposDiffFromPrimCalcAsOmPr", "h2dposDiffFromPrimCalcAsOmPr", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dnegDiffFromPrimCalcAsOmPi", "h2dnegDiffFromPrimCalcAsOmPi", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dnegDiffFromPrimCalcAsOmPr", "h2dnegDiffFromPrimCalcAsOmPr", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + histos.add("h2dbachDiffFromPrimCalcAsOmKa", "h2dbachDiffFromPrimCalcAsOmKa", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTimeVsPrimaryCalculation}}); + + // QA collision reassociation fraction (from track -> V0/cascade coll index) + histos.add("h2dposCorrectAssocAsXiPi", "h2dposCorrectAssocAsXiPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dposCorrectAssocAsXiPr", "h2dposCorrectAssocAsXiPr", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dnegCorrectAssocAsXiPi", "h2dnegCorrectAssocAsXiPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dnegCorrectAssocAsXiPr", "h2dnegCorrectAssocAsXiPr", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dbachCorrectAssocAsXiPi", "h2dbachCorrectAssocAsXiPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + + histos.add("h2dposCorrectAssocAsOmPi", "h2dposCorrectAssocAsOmPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dposCorrectAssocAsOmPr", "h2dposCorrectAssocAsOmPr", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dnegCorrectAssocAsOmPi", "h2dnegCorrectAssocAsOmPi", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dnegCorrectAssocAsOmPr", "h2dnegCorrectAssocAsOmPr", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + histos.add("h2dbachCorrectAssocAsOmKa", "h2dbachCorrectAssocAsOmKa", {HistType::kTH2F, {axes.axisP, {2, -0.5f, 1.5f}}}); + } + + histos.add("h2dPositiveTOFProperties", "h2dPositiveTOFProperties", {HistType::kTH2F, {axes.axisP, {4, -0.5, 3.5f}}}); + histos.add("h2dNegativeTOFProperties", "h2dNegativeTOFProperties", {HistType::kTH2F, {axes.axisP, {4, -0.5, 3.5f}}}); + + if (doQANSigma) { + if (calculateV0s.value > 0) { + histos.add("h2dNSigmaPositiveLambdaPi", "h2dNSigmaPositiveLambdaPi", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaNegativeLambdaPi", "h2dNSigmaNegativeLambdaPi", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaPositiveLambdaPr", "h2dNSigmaPositiveLambdaPr", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaNegativeLambdaPr", "h2dNSigmaNegativeLambdaPr", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaPositiveK0ShortPi", "h2dNSigmaPositiveK0ShortPi", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaNegativeK0ShortPi", "h2dNSigmaNegativeK0ShortPi", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + } + + if (calculateCascades.value > 0) { + histos.add("h2dNSigmaXiLaPi", "h2dNSigmaXiLaPi", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaXiLaPr", "h2dNSigmaXiLaPr", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaXiPi", "h2dNSigmaXiPi", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaOmLaPi", "h2dNSigmaOmLaPi", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaOmLaPr", "h2dNSigmaOmLaPr", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + histos.add("h2dNSigmaOmKa", "h2dNSigmaOmKa", {HistType::kTH2F, {axes.axisP, axes.axisNSigma}}); + } + } + + // delta lambda decay time + histos.add("h2dLambdaDeltaDecayTime", "h2dLambdaDeltaDecayTime", {HistType::kTH2F, {axes.axisP, axes.axisDeltaTime}}); + } + } + + void initCCDB(int runNumber) + { + if (mRunNumber == runNumber) { + return; + } + + // In case override, don't proceed, please - no CCDB access required + if (propagationConfiguration.d_bz_input > -990) { + d_bz = propagationConfiguration.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); + mVtx = ccdb->getForRun(ccdbConfigurations.mVtxPath, runNumber); + mRunNumber = runNumber; + return; + } + + o2::parameters::GRPObject* grpo = ccdb->getForRun(ccdbConfigurations.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 run " << runNumber << " with magnetic field of " << d_bz << " kZG"; + } else { + grpmag = ccdb->getForRun(ccdbConfigurations.grpmagPath, runNumber); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField and " << ccdbConfigurations.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); + mVtx = ccdb->getForRun(ccdbConfigurations.mVtxPath, runNumber); + LOG(info) << "Retrieved GRP for run " << runNumber << " with magnetic field of " << d_bz << " kZG"; + } + + // if TOF Nsigma desired + if (doNSigmas) { + nSigmaCalibObjects = ccdb->getForRun(ccdbConfigurations.nSigmaPath, runNumber); + if (nSigmaCalibObjects) { + LOGF(info, "loaded TList with this many objects: %i", nSigmaCalibObjects->GetEntries()); + nSigmaCalibLoaded = true; // made it thus far, mark loaded + + if (calculateV0s.value) { + hMeanPosLaPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosLaPi")); + hMeanPosLaPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosLaPr")); + hMeanNegLaPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegLaPi")); + hMeanNegLaPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegLaPr")); + hMeanPosK0Pi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosK0Pi")); + hMeanNegK0Pi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegK0Pi")); + + hSigmaPosLaPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosLaPi")); + hSigmaPosLaPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosLaPr")); + hSigmaNegLaPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegLaPi")); + hSigmaNegLaPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegLaPr")); + hSigmaPosK0Pi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosK0Pi")); + hSigmaNegK0Pi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegK0Pi")); + + if (!hMeanPosLaPi) + LOG(info) << "Problems finding mean histogram hMeanPosLaPi!"; + if (!hMeanPosLaPr) + LOG(info) << "Problems finding mean histogram hMeanPosLaPr!"; + if (!hMeanNegLaPi) + LOG(info) << "Problems finding mean histogram hMeanNegLaPi!"; + if (!hMeanNegLaPr) + LOG(info) << "Problems finding mean histogram hMeanNegLaPr!"; + if (!hMeanPosK0Pi) + LOG(info) << "Problems finding mean histogram hMeanPosK0Pi!"; + if (!hMeanNegK0Pi) + LOG(info) << "Problems finding mean histogram hMeanNegK0Pi!"; + if (!hSigmaPosK0Pi || !hSigmaNegK0Pi || !hSigmaPosLaPi || !hSigmaPosLaPr || !hSigmaNegLaPi || !hSigmaNegLaPr) { + LOG(info) << "Problems finding sigma histograms!"; + } + } + + if (calculateCascades.value) { + hMeanPosXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosXiPi")); + hMeanPosXiPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosXiPr")); + hMeanNegXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegXiPi")); + hMeanNegXiPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegXiPr")); + hMeanBachXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanBachXiPi")); + hMeanPosOmPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosOmPi")); + hMeanPosOmPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanPosOmPr")); + hMeanNegOmPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegOmPi")); + hMeanNegOmPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanNegOmPr")); + hMeanBachOmKa = reinterpret_cast(nSigmaCalibObjects->FindObject("hMeanBachOmKa")); + + hSigmaPosXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosXiPi")); + hSigmaPosXiPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosXiPr")); + hSigmaNegXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegXiPi")); + hSigmaNegXiPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegXiPr")); + hSigmaBachXiPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaBachXiPi")); + hSigmaPosOmPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosOmPi")); + hSigmaPosOmPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaPosOmPr")); + hSigmaNegOmPi = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegOmPi")); + hSigmaNegOmPr = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaNegOmPr")); + hSigmaBachOmKa = reinterpret_cast(nSigmaCalibObjects->FindObject("hSigmaBachOmKa")); + + if (!hMeanPosXiPi || !hMeanPosXiPr || !hMeanNegXiPi || !hMeanNegXiPr || !hMeanBachXiPi) + LOG(info) << "Problems finding xi mean histograms!"; + if (!hMeanPosOmPi || !hMeanPosOmPr || !hMeanNegOmPi || !hMeanNegOmPr || !hMeanBachOmKa) + LOG(info) << "Problems finding omega sigma histograms!"; + if (!hSigmaPosXiPi || !hSigmaPosXiPr || !hSigmaNegXiPi || !hSigmaNegXiPr || !hSigmaBachXiPi) + LOG(info) << "Problems finding xi sigma histograms!"; + if (!hSigmaPosOmPi || !hSigmaPosOmPr || !hSigmaNegOmPi || !hSigmaNegOmPr || !hSigmaBachOmKa) + LOG(info) << "Problems finding omega sigma histograms!"; + } + } + } + + // if (calculationMethod.value > 0 && !lut) { + // // setMatLUT only after magfield has been initalized + // // (setMatLUT has implicit and problematic init field call if not) + // LOG(info) << "Loading full (all-radius) material look-up table for run number: " << runNumber; + // lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForRun(ccdbConfigurations.lutPath, runNumber)); + // o2::base::Propagator::Instance()->setMatLUT(lut); + // o2::base::Propagator::Instance()->setTGeoFallBackAllowed(false); + // LOG(info) << "Material look-up table loaded!"; + // } + mRunNumber = runNumber; + } + + float velocity(float lMomentum, float lMass) + { + // Momentum p and mass m -> returns speed in centimeters per picosecond + // Useful for TOF calculations + float lA = (lMomentum / lMass) * (lMomentum / lMass); + return 0.0299792458 * TMath::Sqrt(lA / (1 + lA)); + } + + // structs to hold information + struct v0TofInfo { // holds processed information regarding TOF for V0s + float timeK0Short = o2::aod::v0data::kNoTOFValue; + float timeLambda = o2::aod::v0data::kNoTOFValue; + float timePositivePr = o2::aod::v0data::kNoTOFValue; + float timePositivePi = o2::aod::v0data::kNoTOFValue; + float timeNegativePr = o2::aod::v0data::kNoTOFValue; + float timeNegativePi = o2::aod::v0data::kNoTOFValue; + + float timeAsPrimaryPositivePr = o2::aod::v0data::kNoTOFValue; + float timeAsPrimaryPositivePi = o2::aod::v0data::kNoTOFValue; + float timeAsPrimaryNegativePr = o2::aod::v0data::kNoTOFValue; + float timeAsPrimaryNegativePi = o2::aod::v0data::kNoTOFValue; + + float deltaTimePositiveLambdaPi = o2::aod::v0data::kNoTOFValue; + float deltaTimeNegativeLambdaPi = o2::aod::v0data::kNoTOFValue; + float deltaTimePositiveLambdaPr = o2::aod::v0data::kNoTOFValue; + float deltaTimeNegativeLambdaPr = o2::aod::v0data::kNoTOFValue; + float deltaTimePositiveK0ShortPi = o2::aod::v0data::kNoTOFValue; + float deltaTimeNegativeK0ShortPi = o2::aod::v0data::kNoTOFValue; + + float nSigmaPositiveLambdaPi = o2::aod::v0data::kNoTOFValue; + float nSigmaPositiveLambdaPr = o2::aod::v0data::kNoTOFValue; + float nSigmaNegativeLambdaPi = o2::aod::v0data::kNoTOFValue; + float nSigmaNegativeLambdaPr = o2::aod::v0data::kNoTOFValue; + float nSigmaPositiveK0ShortPi = o2::aod::v0data::kNoTOFValue; + float nSigmaNegativeK0ShortPi = o2::aod::v0data::kNoTOFValue; + + // extra auxiliary variables + float deltaDecayTimeLambda = o2::aod::v0data::kNoTOFValue; + float deltaDecayTimeAntiLambda = o2::aod::v0data::kNoTOFValue; + float deltaDecayTimeK0Short = o2::aod::v0data::kNoTOFValue; + + float betaLambda = o2::aod::v0data::kNoTOFValue; + float betaAntiLambda = o2::aod::v0data::kNoTOFValue; + float betaK0Short = o2::aod::v0data::kNoTOFValue; + }; + + // structs to hold information + struct cascTofInfo { // holds processed information regarding TOF for Cascades + float posFlightPi = o2::aod::cascdata::kNoTOFValue; + float posFlightPr = o2::aod::cascdata::kNoTOFValue; + float negFlightPi = o2::aod::cascdata::kNoTOFValue; + float negFlightPr = o2::aod::cascdata::kNoTOFValue; + float bachFlightPi = o2::aod::cascdata::kNoTOFValue; + float bachFlightKa = o2::aod::cascdata::kNoTOFValue; + + float posFlightAsPrimaryPi = o2::aod::cascdata::kNoTOFValue; + float posFlightAsPrimaryPr = o2::aod::cascdata::kNoTOFValue; + float negFlightAsPrimaryPi = o2::aod::cascdata::kNoTOFValue; + float negFlightAsPrimaryPr = o2::aod::cascdata::kNoTOFValue; + float bachFlightAsPrimaryPi = o2::aod::cascdata::kNoTOFValue; + float bachFlightAsPrimaryKa = o2::aod::cascdata::kNoTOFValue; + + float posDeltaTimeAsXiPi = o2::aod::cascdata::kNoTOFValue, posDeltaTimeAsXiPr = o2::aod::cascdata::kNoTOFValue; + float negDeltaTimeAsXiPi = o2::aod::cascdata::kNoTOFValue, negDeltaTimeAsXiPr = o2::aod::cascdata::kNoTOFValue; + float bachDeltaTimeAsXiPi = o2::aod::cascdata::kNoTOFValue; + float posDeltaTimeAsOmPi = o2::aod::cascdata::kNoTOFValue, posDeltaTimeAsOmPr = o2::aod::cascdata::kNoTOFValue; + float negDeltaTimeAsOmPi = o2::aod::cascdata::kNoTOFValue, negDeltaTimeAsOmPr = o2::aod::cascdata::kNoTOFValue; + float bachDeltaTimeAsOmKa = o2::aod::cascdata::kNoTOFValue; + + float nSigmaXiLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmKa = o2::aod::cascdata::kNoTOFValue; + }; + + struct trackTofInfo { // holds input track info + bool hasITS = false; + bool hasTPC = false; + bool hasTOF = false; + int collisionId = -1; + float tofExpMom = 0.0f; + float tofSignal = 0.0f; + float tofEvTime = 0.0f; + float length = 0.0f; + + // save TPC PID here for completeness too + float tpcNSigmaPi = 0.0f; + float tpcNSigmaKa = 0.0f; + float tpcNSigmaPr = 0.0f; + }; + + // templatized process function for symmetric operation in derived and original AO2D + /// \param collisions the collisions table (needed for de-referencing V0 and progns) + /// \param v0 the V0 being processed + /// \param pTof the TOF information for the positive track + /// \param nTof the TOF information for the negative track + template + v0TofInfo calculateTofInfoV0(TCollisions const& collisions, int const& collisionId, TV0 const& v0, TTOFInfo const& pTof, TTOFInfo const& nTof) + { + v0TofInfo v0tof; // return this struct + auto collision = collisions.rawIteratorAt(collisionId); + + //_____________________________________________________________________________________________ + // daughter tracks: initialize from V0 position and momenta + o2::track::TrackPar posTrack = o2::track::TrackPar({v0.x(), v0.y(), v0.z()}, {v0.pxpos(), v0.pypos(), v0.pzpos()}, +1, false); + o2::track::TrackPar negTrack = o2::track::TrackPar({v0.x(), v0.y(), v0.z()}, {v0.pxneg(), v0.pyneg(), v0.pzneg()}, -1, false); + + //_____________________________________________________________________________________________ + // time of V0 segment + float lengthV0 = std::hypot(v0.x() - collision.posX(), v0.y() - collision.posY(), v0.z() - collision.posZ()); + float velocityK0Short = velocity(v0.p(), o2::constants::physics::MassKaonNeutral); + float velocityLambda = velocity(v0.p(), o2::constants::physics::MassLambda); + v0tof.timeK0Short = lengthV0 / velocityK0Short; // in picoseconds + v0tof.timeLambda = lengthV0 / velocityLambda; // in picoseconds + + //_____________________________________________________________________________________________ + // define simple checks + bool passesQAcuts = (v0.v0cosPA() > v0Group.qaCosPA && v0.dcaV0daughters() < v0Group.qaDCADau); + bool lambdaCandidate = std::abs(v0.mLambda() - o2::constants::physics::MassLambda) < v0Group.qaMassWindow && + std::abs(pTof.tpcNSigmaPr) < v0Group.qaTPCNSigma && + std::abs(nTof.tpcNSigmaPi) < v0Group.qaTPCNSigma; + bool antiLambdaCandidate = std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda) < v0Group.qaMassWindow && + std::abs(pTof.tpcNSigmaPi) < v0Group.qaTPCNSigma && + std::abs(nTof.tpcNSigmaPr) < v0Group.qaTPCNSigma; + bool k0ShortCandidate = std::abs(v0.mK0Short() - o2::constants::physics::MassKaonNeutral) < v0Group.qaMassWindow && + std::abs(pTof.tpcNSigmaPi) < v0Group.qaTPCNSigma && + std::abs(nTof.tpcNSigmaPi) < v0Group.qaTPCNSigma; + + bool pValidTOF = rejectUndefinedTof.value ? static_cast(std::fabs(pTof.tofSignal) > o2::aod::v0data::kEpsilon) : true; + bool nValidTOF = rejectUndefinedTof.value ? static_cast(std::fabs(nTof.tofSignal) > o2::aod::v0data::kEpsilon) : true; + + //_____________________________________________________________________________________________ + // Actual calculation + float velocityPositivePr, velocityPositivePi, lengthPositive; + velocityPositivePr = velocityPositivePi = lengthPositive = o2::aod::v0data::kNoTOFValue; + + if (pTof.hasTOF && pTof.tofEvTime > -1e+5 && pValidTOF) { + // method 0: legacy standalone without use of primary particle TOF + if (calculationMethod.value == 0) { + velocityPositivePr = velocity(posTrack.getP(), o2::constants::physics::MassProton); + velocityPositivePi = velocity(posTrack.getP(), o2::constants::physics::MassPionCharged); + lengthPositive = findInterceptLength(posTrack, d_bz); + v0tof.timePositivePr = lengthPositive / velocityPositivePr; + v0tof.timePositivePi = lengthPositive / velocityPositivePi; + } + // method 1: correct primary particle TOF information + // length -> revise by removing travel length to primary vertex + // expected momentum -> kept as is for now, could correct at second stage + // use main method from TOF to calculate expected time + if (calculationMethod.value == 1) { + if (pTof.collisionId >= 0) { + auto trackCollision = collisions.rawIteratorAt(pTof.collisionId); + const o2::math_utils::Point3D trackVertex{trackCollision.posX(), trackCollision.posY(), trackCollision.posZ()}; + o2::track::TrackLTIntegral ltIntegral; + bool successPropag = o2::base::Propagator::Instance()->propagateToDCA(trackVertex, posTrack, d_bz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrNONE, nullptr, <Integral); + if (doQA) { + histos.fill(HIST("hPropagationBookkeeping"), kPropagPosV0, static_cast(successPropag)); + } + if (successPropag) { + lengthPositive = pTof.length - ltIntegral.getL(); + v0tof.timePositivePr = o2::framework::pid::tof::MassToExpTime(pTof.tofExpMom, lengthPositive, o2::constants::physics::MassProton * o2::constants::physics::MassProton); + v0tof.timePositivePi = o2::framework::pid::tof::MassToExpTime(pTof.tofExpMom, lengthPositive, o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + + // as primary + v0tof.timeAsPrimaryPositivePr = o2::framework::pid::tof::MassToExpTime(pTof.tofExpMom, pTof.length, o2::constants::physics::MassProton * o2::constants::physics::MassProton); + v0tof.timeAsPrimaryPositivePi = o2::framework::pid::tof::MassToExpTime(pTof.tofExpMom, pTof.length, o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + } + } + } + if (lengthPositive > 0.0f) { + v0tof.deltaTimePositiveLambdaPr = (pTof.tofSignal - pTof.tofEvTime) - (v0tof.timeLambda + v0tof.timePositivePr); + v0tof.deltaTimePositiveLambdaPi = (pTof.tofSignal - pTof.tofEvTime) - (v0tof.timeLambda + v0tof.timePositivePi); + v0tof.deltaTimePositiveK0ShortPi = (pTof.tofSignal - pTof.tofEvTime) - (v0tof.timeK0Short + v0tof.timePositivePi); + + // de facto nsigma + if (nSigmaCalibLoaded) { + v0tof.nSigmaPositiveLambdaPi = (v0tof.deltaTimePositiveLambdaPi - hMeanPosLaPi->Interpolate(v0.p())) / hSigmaPosLaPi->Interpolate(v0.p()); + v0tof.nSigmaPositiveLambdaPr = (v0tof.deltaTimePositiveLambdaPr - hMeanPosLaPr->Interpolate(v0.p())) / hSigmaPosLaPr->Interpolate(v0.p()); + v0tof.nSigmaPositiveK0ShortPi = (v0tof.deltaTimePositiveK0ShortPi - hMeanPosK0Pi->Interpolate(v0.p())) / hSigmaPosK0Pi->Interpolate(v0.p()); + } + + // do QA histograms (calibration / QC) + if (doQA) { + if (passesQAcuts) { + if (lambdaCandidate) { + histos.fill(HIST("h2dDeltaTimePositiveLambdaPr"), v0.p(), v0.eta(), v0tof.deltaTimePositiveLambdaPr); + histos.fill(HIST("h2dCorrectAssocPositiveLambdaPr"), v0.p(), static_cast(collisionId == pTof.collisionId)); + histos.fill(HIST("h2dDiffFromPrimCalcPositiveLambdaPr"), v0.p(), (pTof.tofSignal - pTof.tofEvTime) - v0tof.timeAsPrimaryPositivePr); + if (doQANSigma && std::fabs(v0tof.nSigmaPositiveLambdaPr - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaPositiveLambdaPr"), v0.pt(), v0tof.nSigmaPositiveLambdaPr); + } + } + if (antiLambdaCandidate) { + histos.fill(HIST("h2dDeltaTimePositiveLambdaPi"), v0.p(), v0.eta(), v0tof.deltaTimePositiveLambdaPi); + histos.fill(HIST("h2dCorrectAssocPositiveLambdaPi"), v0.p(), static_cast(collisionId == pTof.collisionId)); + histos.fill(HIST("h2dDiffFromPrimCalcPositiveLambdaPi"), v0.p(), (pTof.tofSignal - pTof.tofEvTime) - v0tof.timeAsPrimaryPositivePi); + if (doQANSigma && std::fabs(v0tof.nSigmaPositiveLambdaPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaPositiveLambdaPi"), v0.pt(), v0tof.nSigmaPositiveLambdaPi); + } + } + if (k0ShortCandidate) { + histos.fill(HIST("h2dDeltaTimePositiveK0ShortPi"), v0.p(), v0.eta(), v0tof.deltaTimePositiveK0ShortPi); + histos.fill(HIST("h2dCorrectAssocPositiveK0ShortPi"), v0.p(), static_cast(collisionId == pTof.collisionId)); + histos.fill(HIST("h2dDiffFromPrimCalcPositiveK0ShortPi"), v0.p(), (pTof.tofSignal - pTof.tofEvTime) - v0tof.timeAsPrimaryPositivePi); + if (doQANSigma && std::fabs(v0tof.nSigmaPositiveK0ShortPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaPositiveK0ShortPi"), v0.pt(), v0tof.nSigmaPositiveK0ShortPi); + } + } + } + } + } + } + float velocityNegativePr, velocityNegativePi, lengthNegative; + velocityNegativePr = velocityNegativePi = lengthNegative = o2::aod::v0data::kNoTOFValue; + if (nTof.hasTOF && nTof.tofEvTime > -1e+5 && nValidTOF) { + // method 0: legacy standalone without use of primary particle TOF + if (calculationMethod.value == 0) { + velocityNegativePr = velocity(negTrack.getP(), o2::constants::physics::MassProton); + velocityNegativePi = velocity(negTrack.getP(), o2::constants::physics::MassPionCharged); + lengthNegative = findInterceptLength(negTrack, d_bz); + v0tof.timeNegativePr = lengthNegative / velocityNegativePr; + v0tof.timeNegativePi = lengthNegative / velocityNegativePi; + } + // method 1: correct primary particle TOF information + // length -> revise by removing travel length to primary vertex + // expected momentum -> kept as is for now, could correct at second stage + // use main method from TOF to calculate expected time + if (calculationMethod.value == 1) { + if (nTof.collisionId >= 0) { + auto trackCollision = collisions.rawIteratorAt(nTof.collisionId); + const o2::math_utils::Point3D trackVertex{trackCollision.posX(), trackCollision.posY(), trackCollision.posZ()}; + o2::track::TrackLTIntegral ltIntegral; + bool successPropag = o2::base::Propagator::Instance()->propagateToDCA(trackVertex, negTrack, d_bz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrNONE, nullptr, <Integral); + if (doQA) { + histos.fill(HIST("hPropagationBookkeeping"), kPropagNegV0, static_cast(successPropag)); + } + if (successPropag) { + lengthNegative = nTof.length - ltIntegral.getL(); + v0tof.timeNegativePr = o2::framework::pid::tof::MassToExpTime(nTof.tofExpMom, lengthNegative, o2::constants::physics::MassProton * o2::constants::physics::MassProton); + v0tof.timeNegativePi = o2::framework::pid::tof::MassToExpTime(nTof.tofExpMom, lengthNegative, o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + + // as primary + v0tof.timeAsPrimaryNegativePr = o2::framework::pid::tof::MassToExpTime(nTof.tofExpMom, nTof.length, o2::constants::physics::MassProton * o2::constants::physics::MassProton); + v0tof.timeAsPrimaryNegativePi = o2::framework::pid::tof::MassToExpTime(nTof.tofExpMom, nTof.length, o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + } + } + } + if (lengthNegative > 0.0f) { + v0tof.deltaTimeNegativeLambdaPr = (nTof.tofSignal - nTof.tofEvTime) - (v0tof.timeLambda + v0tof.timeNegativePr); + v0tof.deltaTimeNegativeLambdaPi = (nTof.tofSignal - nTof.tofEvTime) - (v0tof.timeLambda + v0tof.timeNegativePi); + v0tof.deltaTimeNegativeK0ShortPi = (nTof.tofSignal - nTof.tofEvTime) - (v0tof.timeK0Short + v0tof.timeNegativePi); + + // de facto nsigma + if (nSigmaCalibLoaded) { + v0tof.nSigmaNegativeLambdaPi = (v0tof.deltaTimeNegativeLambdaPi - hMeanNegLaPi->Interpolate(v0.p())) / hSigmaNegLaPi->Interpolate(v0.p()); + v0tof.nSigmaNegativeLambdaPr = (v0tof.deltaTimeNegativeLambdaPr - hMeanNegLaPr->Interpolate(v0.p())) / hSigmaNegLaPr->Interpolate(v0.p()); + v0tof.nSigmaNegativeK0ShortPi = (v0tof.deltaTimeNegativeK0ShortPi - hMeanNegK0Pi->Interpolate(v0.p())) / hSigmaNegK0Pi->Interpolate(v0.p()); + } + + // do QA histograms (calibration / QC) + if (doQA) { + if (passesQAcuts) { + if (lambdaCandidate) { + histos.fill(HIST("h2dDeltaTimeNegativeLambdaPi"), v0.p(), v0.eta(), v0tof.deltaTimeNegativeLambdaPi); + histos.fill(HIST("h2dCorrectAssocNegativeLambdaPi"), v0.p(), static_cast(collisionId == nTof.collisionId)); + histos.fill(HIST("h2dDiffFromPrimCalcNegativeLambdaPi"), v0.p(), (nTof.tofSignal - nTof.tofEvTime) - v0tof.timeAsPrimaryNegativePi); + if (doQANSigma && std::fabs(v0tof.nSigmaNegativeLambdaPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaNegativeLambdaPi"), v0.pt(), v0tof.nSigmaNegativeLambdaPi); + } + } + if (antiLambdaCandidate) { + histos.fill(HIST("h2dDeltaTimeNegativeLambdaPr"), v0.p(), v0.eta(), v0tof.deltaTimeNegativeLambdaPr); + histos.fill(HIST("h2dCorrectAssocNegativeLambdaPr"), v0.p(), static_cast(collisionId == nTof.collisionId)); + histos.fill(HIST("h2dDiffFromPrimCalcNegativeLambdaPr"), v0.p(), (nTof.tofSignal - nTof.tofEvTime) - v0tof.timeAsPrimaryNegativePr); + if (doQANSigma && std::fabs(v0tof.nSigmaNegativeLambdaPr - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaNegativeLambdaPr"), v0.pt(), v0tof.nSigmaNegativeLambdaPr); + } + } + if (k0ShortCandidate) { + histos.fill(HIST("h2dDeltaTimeNegativeK0ShortPi"), v0.p(), v0.eta(), v0tof.deltaTimeNegativeK0ShortPi); + histos.fill(HIST("h2dCorrectAssocNegativeK0ShortPi"), v0.p(), static_cast(collisionId == nTof.collisionId)); + histos.fill(HIST("h2dDiffFromPrimCalcNegativeK0ShortPi"), v0.p(), (nTof.tofSignal - nTof.tofEvTime) - v0tof.timeAsPrimaryNegativePi); + if (doQANSigma && std::fabs(v0tof.nSigmaNegativeK0ShortPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaNegativeK0ShortPi"), v0.pt(), v0tof.nSigmaNegativeK0ShortPi); + } + } + } + } + } + + // temporarily commented out + // bool compatibleK0Short = true; + // int incompatibilityReason = 0; + // if (std::abs(v0tof.nSigmaPositiveK0ShortPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon && std::abs(v0tof.nSigmaPositiveK0ShortPi) > 4) { + // compatibleK0Short = false; // reject only if info present and incompatible + // incompatibilityReason += 1; + // } + // if (std::abs(v0tof.nSigmaNegativeK0ShortPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon && std::abs(v0tof.nSigmaNegativeK0ShortPi) > 4) { + // compatibleK0Short = false; // reject only if info present and incompatible + // incompatibilityReason += 2; + // } + + // if(!compatibleK0Short && passesQAcuts && k0ShortCandidate){ + // histos.fill(HIST("hIncompatibilityReason"), incompatibilityReason); + // // LOGF(info, "Incompatible K0, sigmas = (%.2f %.2f), lengths = (%.2f %.2f) tofSignals = (%.2f %.2f) evtimes = (%.2f %.2f)", v0tof.nSigmaPositiveK0ShortPi, v0tof.nSigmaNegativeK0ShortPi, lengthPositive, lengthNegative, pTof.tofSignal, nTof.tofSignal, pTof.tofEvTime, nTof.tofEvTime); + // } + + // calculation of delta-decay-time (no reliance on event time) + if (nTof.hasTOF && pTof.hasTOF > 0) { // does not depend on event time + v0tof.deltaDecayTimeLambda = (pTof.tofSignal - v0tof.timePositivePr) - (nTof.tofSignal - v0tof.timeNegativePi); + v0tof.deltaDecayTimeAntiLambda = (pTof.tofSignal - v0tof.timePositivePi) - (nTof.tofSignal - v0tof.timeNegativePr); + v0tof.deltaDecayTimeK0Short = (pTof.tofSignal - v0tof.timePositivePi) - (nTof.tofSignal - v0tof.timeNegativePi); + + float evTimeMean = 0.5f * (pTof.tofEvTime + nTof.tofEvTime); + float decayTimeLambda = 0.5f * ((pTof.tofSignal - v0tof.timePositivePr) + (nTof.tofSignal - v0tof.timeNegativePi)) - evTimeMean; + float decayTimeAntiLambda = 0.5f * ((pTof.tofSignal - v0tof.timePositivePi) + (nTof.tofSignal - v0tof.timeNegativePr)) - evTimeMean; + float decayTimeK0Short = 0.5f * ((pTof.tofSignal - v0tof.timePositivePi) + (nTof.tofSignal - v0tof.timeNegativePi)) - evTimeMean; + + constexpr float lightSpeed = 0.0299792458; // in cm/ps + v0tof.betaLambda = (lengthV0 / decayTimeLambda) / lightSpeed; + v0tof.betaAntiLambda = (lengthV0 / decayTimeAntiLambda) / lightSpeed; + v0tof.betaK0Short = (lengthV0 / decayTimeK0Short) / lightSpeed; + } + } + + return v0tof; + } // end calculation altogether + + template + cascTofInfo calculateTofInfoCascade(TCollisions const& collisions, int const& collisionId, TCascade const& cascade, TTOFInfo const& pTof, TTOFInfo const& nTof, TTOFInfo const& bTof) + { + cascTofInfo casctof; // return this struct + auto collision = collisions.rawIteratorAt(collisionId); + + //_____________________________________________________________________________________________ + // daughter tracks: initialize from V0 position and momenta + o2::track::TrackPar posTrack = o2::track::TrackPar({cascade.xlambda(), cascade.ylambda(), cascade.zlambda()}, {cascade.pxpos(), cascade.pypos(), cascade.pzpos()}, +1, false); + o2::track::TrackPar negTrack = o2::track::TrackPar({cascade.xlambda(), cascade.ylambda(), cascade.zlambda()}, {cascade.pxneg(), cascade.pyneg(), cascade.pzneg()}, -1, false); + o2::track::TrackPar bachTrack = o2::track::TrackPar({cascade.x(), cascade.y(), cascade.z()}, {cascade.pxbach(), cascade.pybach(), cascade.pzbach()}, cascade.sign(), false); + o2::track::TrackPar cascTrack = o2::track::TrackPar({cascade.x(), cascade.y(), cascade.z()}, {cascade.px(), cascade.py(), cascade.pz()}, cascade.sign(), false); + + //_____________________________________________________________________________________________ + // time of V0 segment + float velocityXi = velocity(cascTrack.getP(), o2::constants::physics::MassXiMinus); + float velocityOm = velocity(cascTrack.getP(), o2::constants::physics::MassOmegaMinus); + float velocityLa = velocity(std::hypot(cascade.pxlambda(), cascade.pylambda(), cascade.pzlambda()), o2::constants::physics::MassLambda); + float lengthV0 = std::hypot(cascade.xlambda() - cascade.x(), cascade.ylambda() - cascade.y(), cascade.zlambda() - cascade.z()); + float lengthCascade = o2::aod::cascdata::kNoTOFValue; + + // cascade length (N.B. could be simpler via trackLTIntegral, kept with legacy calculation) + const o2::math_utils::Point3D collVtx{collision.posX(), collision.posY(), collision.posZ()}; + bool successPropag = o2::base::Propagator::Instance()->propagateToDCA(collVtx, cascTrack, d_bz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrNONE); + float d = -1.0f; + float linearToPV = std::hypot(cascade.x() - collision.posX(), cascade.y() - collision.posY(), cascade.z() - collision.posZ()); + if (successPropag) { + std::array cascCloseToPVPosition; + cascTrack.getXYZGlo(cascCloseToPVPosition); + o2::math_utils::CircleXYf_t trcCircleCascade; + float sna, csa; + cascTrack.getCircleParams(d_bz, trcCircleCascade, sna, csa); + + // calculate 2D distance between two points + d = std::hypot(cascade.x() - cascCloseToPVPosition[0], cascade.y() - cascCloseToPVPosition[1]); + // d3d = std::hypot(cascade.x() - cascCloseToPVPosition[0], cascade.y() - cascCloseToPVPosition[1], cascade.z() - cascCloseToPVPosition[2]); // cross-check variable + float sinThetaOverTwo = d / (2.0f * trcCircleCascade.rC); + lengthCascade = 2.0f * trcCircleCascade.rC * TMath::ASin(sinThetaOverTwo); + lengthCascade *= sqrt(1.0f + cascTrack.getTgl() * cascTrack.getTgl()); + } + + if (!successPropag) { + lengthCascade = linearToPV; // if propagation failed, use linear estimate (optional: actually do not define?) + } + + // flight times of decaying particles + float lambdaFlight = lengthV0 / velocityLa; + float xiFlight = lengthCascade / velocityXi; + float omFlight = lengthCascade / velocityOm; + + //_____________________________________________________________________________________________ + // define simple checks + bool passesQAcuts = (cascade.dcaV0daughters() < cascadeGroup.qaV0DCADau && cascade.dcacascdaughters() < cascadeGroup.qaCascDCADau && cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) > cascadeGroup.qaV0CosPA && cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ()) > cascadeGroup.qaCascCosPA); + bool xiMinusCandidate = cascade.sign() < 0 && + std::abs(cascade.mXi() - o2::constants::physics::MassXiMinus) < cascadeGroup.qaMassWindow && + std::abs(pTof.tpcNSigmaPr) < cascadeGroup.qaTPCNSigma && + std::abs(nTof.tpcNSigmaPi) < cascadeGroup.qaTPCNSigma && + std::abs(bTof.tpcNSigmaPi) < cascadeGroup.qaTPCNSigma; + bool xiPlusCandidate = cascade.sign() > 0 && + std::abs(cascade.mXi() - o2::constants::physics::MassXiMinus) < cascadeGroup.qaMassWindow && + std::abs(pTof.tpcNSigmaPi) < cascadeGroup.qaTPCNSigma && + std::abs(nTof.tpcNSigmaPr) < cascadeGroup.qaTPCNSigma && + std::abs(bTof.tpcNSigmaPi) < cascadeGroup.qaTPCNSigma; + bool omegaMinusCandidate = cascade.sign() < 0 && + std::abs(cascade.mOmega() - o2::constants::physics::MassOmegaMinus) < cascadeGroup.qaMassWindow && + std::abs(pTof.tpcNSigmaPr) < cascadeGroup.qaTPCNSigma && + std::abs(nTof.tpcNSigmaPi) < cascadeGroup.qaTPCNSigma && + std::abs(bTof.tpcNSigmaKa) < cascadeGroup.qaTPCNSigma; + bool omegaPlusCandidate = cascade.sign() > 0 && + std::abs(cascade.mOmega() - o2::constants::physics::MassOmegaMinus) < cascadeGroup.qaMassWindow && + std::abs(pTof.tpcNSigmaPi) < cascadeGroup.qaTPCNSigma && + std::abs(nTof.tpcNSigmaPr) < cascadeGroup.qaTPCNSigma && + std::abs(bTof.tpcNSigmaKa) < cascadeGroup.qaTPCNSigma; + + bool pValidTOF = rejectUndefinedTof.value ? static_cast(std::fabs(pTof.tofSignal) > o2::aod::v0data::kEpsilon) : true; + bool nValidTOF = rejectUndefinedTof.value ? static_cast(std::fabs(nTof.tofSignal) > o2::aod::v0data::kEpsilon) : true; + bool bValidTOF = rejectUndefinedTof.value ? static_cast(std::fabs(bTof.tofSignal) > o2::aod::v0data::kEpsilon) : true; + + //_____________________________________________________________________________________________ + // Actual calculation + if (pTof.hasTOF && pTof.tofEvTime > -1e+5 && pValidTOF) { + float velocityPositivePr, velocityPositivePi, lengthPositive; + velocityPositivePr = velocityPositivePi = lengthPositive = o2::aod::v0data::kNoTOFValue; + if (calculationMethod.value == 0) { + velocityPositivePr = velocity(posTrack.getP(), o2::constants::physics::MassProton); + velocityPositivePi = velocity(posTrack.getP(), o2::constants::physics::MassPionCharged); + lengthPositive = findInterceptLength(posTrack, d_bz); + casctof.posFlightPr = lengthPositive / velocityPositivePr; + casctof.posFlightPi = lengthPositive / velocityPositivePi; + } + // method 1: correct primary particle TOF information + // length -> revise by removing travel length to primary vertex + // expected momentum -> kept as is for now, could correct at second stage + // use main method from TOF to calculate expected time + if (calculationMethod.value == 1) { + if (pTof.collisionId >= 0) { + auto trackCollision = collisions.rawIteratorAt(pTof.collisionId); + const o2::math_utils::Point3D trackVertex{trackCollision.posX(), trackCollision.posY(), trackCollision.posZ()}; + o2::track::TrackLTIntegral ltIntegral; + bool successPropag = o2::base::Propagator::Instance()->propagateToDCA(trackVertex, posTrack, d_bz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrNONE, nullptr, <Integral); + if (doQA) { + histos.fill(HIST("hPropagationBookkeeping"), kPropagPosCasc, static_cast(successPropag)); + } + if (successPropag) { + lengthPositive = pTof.length - ltIntegral.getL(); + casctof.posFlightPr = o2::framework::pid::tof::MassToExpTime(pTof.tofExpMom, pTof.length - ltIntegral.getL(), o2::constants::physics::MassProton * o2::constants::physics::MassProton); + casctof.posFlightPi = o2::framework::pid::tof::MassToExpTime(pTof.tofExpMom, pTof.length - ltIntegral.getL(), o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + + // as primary + casctof.posFlightAsPrimaryPr = o2::framework::pid::tof::MassToExpTime(pTof.tofExpMom, pTof.length, o2::constants::physics::MassProton * o2::constants::physics::MassProton); + casctof.posFlightAsPrimaryPi = o2::framework::pid::tof::MassToExpTime(pTof.tofExpMom, pTof.length, o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + } + } + } + if (lengthPositive > 0.0f) { + casctof.posDeltaTimeAsXiPi = (pTof.tofSignal - pTof.tofEvTime) - (xiFlight + lambdaFlight + casctof.posFlightPi); + casctof.posDeltaTimeAsXiPr = (pTof.tofSignal - pTof.tofEvTime) - (xiFlight + lambdaFlight + casctof.posFlightPr); + casctof.posDeltaTimeAsOmPi = (pTof.tofSignal - pTof.tofEvTime) - (omFlight + lambdaFlight + casctof.posFlightPi); + casctof.posDeltaTimeAsOmPr = (pTof.tofSignal - pTof.tofEvTime) - (omFlight + lambdaFlight + casctof.posFlightPr); + + // de facto nsigma + if (nSigmaCalibLoaded) { + if (cascade.sign() < 0) { + casctof.nSigmaXiLaPr = (casctof.posDeltaTimeAsXiPr - hMeanPosXiPr->Interpolate(cascade.p())) / hSigmaPosXiPr->Interpolate(cascade.p()); + casctof.nSigmaOmLaPr = (casctof.posDeltaTimeAsOmPr - hMeanPosOmPr->Interpolate(cascade.p())) / hSigmaPosOmPr->Interpolate(cascade.p()); + } else { + casctof.nSigmaXiLaPi = (casctof.posDeltaTimeAsXiPi - hMeanPosXiPi->Interpolate(cascade.p())) / hSigmaPosXiPi->Interpolate(cascade.p()); + casctof.nSigmaOmLaPi = (casctof.posDeltaTimeAsOmPi - hMeanPosOmPi->Interpolate(cascade.p())) / hSigmaPosOmPi->Interpolate(cascade.p()); + } + } + + // do QA histograms (calibration / QC) + if (doQA) { + if (passesQAcuts) { + if (xiMinusCandidate) { + histos.fill(HIST("h2dposDeltaTimeAsXiPr"), cascade.p(), cascade.eta(), casctof.posDeltaTimeAsXiPr); + histos.fill(HIST("h2dposCorrectAssocAsXiPr"), cascade.p(), static_cast(collisionId == pTof.collisionId)); + histos.fill(HIST("h2dposDiffFromPrimCalcAsXiPr"), cascade.p(), (pTof.tofSignal - pTof.tofEvTime) - casctof.posFlightAsPrimaryPr); + if (doQANSigma && std::fabs(casctof.nSigmaXiLaPr - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaXiLaPr"), cascade.pt(), casctof.nSigmaXiLaPr); + } + } + if (xiPlusCandidate) { + histos.fill(HIST("h2dposDeltaTimeAsXiPi"), cascade.p(), cascade.eta(), casctof.posDeltaTimeAsXiPi); + histos.fill(HIST("h2dposCorrectAssocAsXiPi"), cascade.p(), static_cast(collisionId == pTof.collisionId)); + histos.fill(HIST("h2dposDiffFromPrimCalcAsXiPi"), cascade.p(), (pTof.tofSignal - pTof.tofEvTime) - casctof.posFlightAsPrimaryPi); + if (doQANSigma && std::fabs(casctof.nSigmaXiLaPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaXiLaPi"), cascade.pt(), casctof.nSigmaXiLaPi); + } + } + if (omegaMinusCandidate) { + histos.fill(HIST("h2dposDeltaTimeAsOmPr"), cascade.p(), cascade.eta(), casctof.posDeltaTimeAsOmPr); + histos.fill(HIST("h2dposCorrectAssocAsOmPr"), cascade.p(), static_cast(collisionId == pTof.collisionId)); + histos.fill(HIST("h2dposDiffFromPrimCalcAsOmPr"), cascade.p(), (pTof.tofSignal - pTof.tofEvTime) - casctof.posFlightAsPrimaryPr); + if (doQANSigma && std::fabs(casctof.nSigmaOmLaPr - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaOmLaPr"), cascade.pt(), casctof.nSigmaOmLaPr); + } + } + if (omegaPlusCandidate) { + histos.fill(HIST("h2dposDeltaTimeAsOmPi"), cascade.p(), cascade.eta(), casctof.posDeltaTimeAsOmPi); + histos.fill(HIST("h2dposCorrectAssocAsOmPi"), cascade.p(), static_cast(collisionId == pTof.collisionId)); + histos.fill(HIST("h2dposDiffFromPrimCalcAsOmPi"), cascade.p(), (pTof.tofSignal - pTof.tofEvTime) - casctof.posFlightAsPrimaryPi); + if (doQANSigma && std::fabs(casctof.nSigmaOmLaPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaOmLaPi"), cascade.pt(), casctof.nSigmaOmLaPi); + } + } + } + } + } + } // end positive + + if (nTof.hasTOF && nTof.tofEvTime > -1e+5 && nValidTOF) { + float velocityNegativePr, velocityNegativePi, lengthNegative; + velocityNegativePr = velocityNegativePi = lengthNegative = o2::aod::v0data::kNoTOFValue; + // method 0: legacy standalone without use of primary particle TOF + if (calculationMethod.value == 0) { + velocityNegativePr = velocity(negTrack.getP(), o2::constants::physics::MassProton); + velocityNegativePi = velocity(negTrack.getP(), o2::constants::physics::MassPionCharged); + lengthNegative = findInterceptLength(negTrack, d_bz); + casctof.negFlightPr = lengthNegative / velocityNegativePr; + casctof.negFlightPi = lengthNegative / velocityNegativePi; + } + // method 1: correct primary particle TOF information + // length -> revise by removing travel length to primary vertex + // expected momentum -> kept as is for now, could correct at second stage + // use main method from TOF to calculate expected time + if (calculationMethod.value == 1) { + if (nTof.collisionId >= 0) { + auto trackCollision = collisions.rawIteratorAt(nTof.collisionId); + const o2::math_utils::Point3D trackVertex{trackCollision.posX(), trackCollision.posY(), trackCollision.posZ()}; + o2::track::TrackLTIntegral ltIntegral; + bool successPropag = o2::base::Propagator::Instance()->propagateToDCA(trackVertex, negTrack, d_bz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrNONE, nullptr, <Integral); + if (doQA) { + histos.fill(HIST("hPropagationBookkeeping"), kPropagNegCasc, static_cast(successPropag)); + } + if (successPropag) { + lengthNegative = nTof.length - ltIntegral.getL(); + casctof.negFlightPr = o2::framework::pid::tof::MassToExpTime(nTof.tofExpMom, nTof.length - ltIntegral.getL(), o2::constants::physics::MassProton * o2::constants::physics::MassProton); + casctof.negFlightPi = o2::framework::pid::tof::MassToExpTime(nTof.tofExpMom, nTof.length - ltIntegral.getL(), o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + + // as primary + casctof.negFlightAsPrimaryPr = o2::framework::pid::tof::MassToExpTime(nTof.tofExpMom, nTof.length, o2::constants::physics::MassProton * o2::constants::physics::MassProton); + casctof.negFlightAsPrimaryPi = o2::framework::pid::tof::MassToExpTime(nTof.tofExpMom, nTof.length, o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + } + } + } + if (lengthNegative > 0.0f) { + casctof.negDeltaTimeAsXiPi = (nTof.tofSignal - nTof.tofEvTime) - (xiFlight + lambdaFlight + casctof.negFlightPi); + casctof.negDeltaTimeAsXiPr = (nTof.tofSignal - nTof.tofEvTime) - (xiFlight + lambdaFlight + casctof.negFlightPr); + casctof.negDeltaTimeAsOmPi = (nTof.tofSignal - nTof.tofEvTime) - (omFlight + lambdaFlight + casctof.negFlightPi); + casctof.negDeltaTimeAsOmPr = (nTof.tofSignal - nTof.tofEvTime) - (omFlight + lambdaFlight + casctof.negFlightPr); + + // de facto nsigma + if (nSigmaCalibLoaded) { + if (cascade.sign() < 0) { + casctof.nSigmaXiLaPi = (casctof.negDeltaTimeAsXiPi - hMeanNegXiPi->Interpolate(cascade.p())) / hSigmaNegXiPi->Interpolate(cascade.p()); + casctof.nSigmaOmLaPi = (casctof.negDeltaTimeAsOmPi - hMeanNegOmPi->Interpolate(cascade.p())) / hSigmaNegOmPi->Interpolate(cascade.p()); + } else { + casctof.nSigmaXiLaPr = (casctof.negDeltaTimeAsXiPr - hMeanNegXiPr->Interpolate(cascade.p())) / hSigmaNegXiPr->Interpolate(cascade.p()); + casctof.nSigmaOmLaPr = (casctof.negDeltaTimeAsOmPr - hMeanNegOmPr->Interpolate(cascade.p())) / hSigmaNegOmPr->Interpolate(cascade.p()); + } + } + + // do QA histograms (calibration / QC) + if (doQA) { + if (passesQAcuts) { + if (xiMinusCandidate) { + histos.fill(HIST("h2dnegDeltaTimeAsXiPi"), cascade.p(), cascade.eta(), casctof.negDeltaTimeAsXiPi); + histos.fill(HIST("h2dnegCorrectAssocAsXiPi"), cascade.p(), static_cast(collisionId == nTof.collisionId)); + histos.fill(HIST("h2dnegDiffFromPrimCalcAsXiPi"), cascade.p(), (nTof.tofSignal - nTof.tofEvTime) - casctof.negFlightAsPrimaryPi); + if (doQANSigma && std::fabs(casctof.nSigmaXiLaPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaXiLaPi"), cascade.pt(), casctof.nSigmaXiLaPi); + } + } + if (xiPlusCandidate) { + histos.fill(HIST("h2dnegDeltaTimeAsXiPr"), cascade.p(), cascade.eta(), casctof.negDeltaTimeAsXiPr); + histos.fill(HIST("h2dnegCorrectAssocAsXiPr"), cascade.p(), static_cast(collisionId == nTof.collisionId)); + histos.fill(HIST("h2dnegDiffFromPrimCalcAsXiPr"), cascade.p(), (nTof.tofSignal - nTof.tofEvTime) - casctof.negFlightAsPrimaryPr); + if (doQANSigma && std::fabs(casctof.nSigmaXiLaPr - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaXiLaPr"), cascade.pt(), casctof.nSigmaXiLaPr); + } + } + if (omegaMinusCandidate) { + histos.fill(HIST("h2dnegDeltaTimeAsOmPi"), cascade.p(), cascade.eta(), casctof.negDeltaTimeAsOmPi); + histos.fill(HIST("h2dnegCorrectAssocAsOmPi"), cascade.p(), static_cast(collisionId == nTof.collisionId)); + histos.fill(HIST("h2dnegDiffFromPrimCalcAsOmPi"), cascade.p(), (nTof.tofSignal - nTof.tofEvTime) - casctof.negFlightAsPrimaryPi); + if (doQANSigma && std::fabs(casctof.nSigmaOmLaPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaOmLaPi"), cascade.pt(), casctof.nSigmaOmLaPi); + } + } + if (omegaPlusCandidate) { + histos.fill(HIST("h2dnegDeltaTimeAsOmPr"), cascade.p(), cascade.eta(), casctof.negDeltaTimeAsOmPr); + histos.fill(HIST("h2dnegCorrectAssocAsOmPr"), cascade.p(), static_cast(collisionId == nTof.collisionId)); + histos.fill(HIST("h2dnegDiffFromPrimCalcAsOmPr"), cascade.p(), (nTof.tofSignal - nTof.tofEvTime) - casctof.negFlightAsPrimaryPr); + if (doQANSigma && std::fabs(casctof.nSigmaOmLaPr - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaOmLaPr"), cascade.pt(), casctof.nSigmaOmLaPr); + } + } + } + } + } + } // end negative + + if (bTof.hasTOF && bTof.tofEvTime > -1e+5 && bValidTOF) { + float velocityBachelorKa, velocityBachelorPi, lengthBachelor; + velocityBachelorKa = velocityBachelorPi = lengthBachelor = o2::aod::v0data::kNoTOFValue; + // method 0: legacy standalone without use of primary particle TOF + if (calculationMethod.value == 0) { + velocityBachelorPi = velocity(bachTrack.getP(), o2::constants::physics::MassPionCharged); + velocityBachelorKa = velocity(bachTrack.getP(), o2::constants::physics::MassKaonCharged); + lengthBachelor = findInterceptLength(bachTrack, d_bz); + casctof.bachFlightPi = lengthBachelor / velocityBachelorPi; + casctof.bachFlightKa = lengthBachelor / velocityBachelorKa; + } + // method 1: correct primary particle TOF information + // length -> revise by removing travel length to primary vertex + // expected momentum -> kept as is for now, could correct at second stage + // use main method from TOF to calculate expected time + if (calculationMethod.value == 1) { + if (bTof.collisionId >= 0) { + auto trackCollision = collisions.rawIteratorAt(bTof.collisionId); + const o2::math_utils::Point3D trackVertex{trackCollision.posX(), trackCollision.posY(), trackCollision.posZ()}; + o2::track::TrackLTIntegral ltIntegral; + bool successPropag = o2::base::Propagator::Instance()->propagateToDCA(trackVertex, bachTrack, d_bz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrNONE, nullptr, <Integral); + if (doQA) { + histos.fill(HIST("hPropagationBookkeeping"), kPropagBachCasc, static_cast(successPropag)); + } + if (successPropag) { + lengthBachelor = bTof.length - ltIntegral.getL(); + casctof.bachFlightPi = o2::framework::pid::tof::MassToExpTime(bTof.tofExpMom, bTof.length - ltIntegral.getL(), o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + casctof.bachFlightKa = o2::framework::pid::tof::MassToExpTime(bTof.tofExpMom, bTof.length - ltIntegral.getL(), o2::constants::physics::MassKaonCharged * o2::constants::physics::MassKaonCharged); + + // as primary + casctof.bachFlightAsPrimaryPi = o2::framework::pid::tof::MassToExpTime(bTof.tofExpMom, bTof.length, o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged); + casctof.bachFlightAsPrimaryKa = o2::framework::pid::tof::MassToExpTime(bTof.tofExpMom, bTof.length, o2::constants::physics::MassKaonCharged * o2::constants::physics::MassKaonCharged); + } + } + } + if (lengthBachelor > 0.0f) { + casctof.bachDeltaTimeAsXiPi = (bTof.tofSignal - bTof.tofEvTime) - (xiFlight + casctof.bachFlightPi); + casctof.bachDeltaTimeAsOmKa = (bTof.tofSignal - bTof.tofEvTime) - (omFlight + casctof.bachFlightKa); + + // de facto nsigma + if (nSigmaCalibLoaded) { + if (cascade.sign() < 0) { + casctof.nSigmaXiPi = (casctof.bachDeltaTimeAsXiPi - hMeanBachXiPi->Interpolate(cascade.p())) / hSigmaBachXiPi->Interpolate(cascade.p()); + casctof.nSigmaOmKa = (casctof.bachDeltaTimeAsOmKa - hMeanBachOmKa->Interpolate(cascade.p())) / hSigmaBachOmKa->Interpolate(cascade.p()); + } else { + casctof.nSigmaXiPi = (casctof.bachDeltaTimeAsXiPi - hMeanBachXiPi->Interpolate(cascade.p())) / hSigmaBachXiPi->Interpolate(cascade.p()); + casctof.nSigmaOmKa = (casctof.bachDeltaTimeAsOmKa - hMeanBachOmKa->Interpolate(cascade.p())) / hSigmaBachOmKa->Interpolate(cascade.p()); + } + } + + // do QA histograms (calibration / QC) + if (doQA) { + if (passesQAcuts) { + if (xiMinusCandidate) { + histos.fill(HIST("h2dbachDeltaTimeAsXiPi"), cascade.p(), cascade.eta(), casctof.bachDeltaTimeAsXiPi); + histos.fill(HIST("h2dbachCorrectAssocAsXiPi"), cascade.p(), static_cast(collisionId == bTof.collisionId)); + histos.fill(HIST("h2dbachDiffFromPrimCalcAsXiPi"), cascade.p(), (bTof.tofSignal - bTof.tofEvTime) - casctof.bachFlightAsPrimaryPi); + if (doQANSigma && std::fabs(casctof.nSigmaXiPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaXiPi"), cascade.pt(), casctof.nSigmaXiPi); + } + } + if (xiPlusCandidate) { + histos.fill(HIST("h2dbachDeltaTimeAsXiPi"), cascade.p(), cascade.eta(), casctof.bachDeltaTimeAsXiPi); + histos.fill(HIST("h2dbachCorrectAssocAsXiPi"), cascade.p(), static_cast(collisionId == bTof.collisionId)); + histos.fill(HIST("h2dbachDiffFromPrimCalcAsXiPi"), cascade.p(), (bTof.tofSignal - bTof.tofEvTime) - casctof.bachFlightAsPrimaryPi); + if (doQANSigma && std::fabs(casctof.nSigmaXiPi - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaXiPi"), cascade.pt(), casctof.nSigmaXiPi); + } + } + if (omegaMinusCandidate) { + histos.fill(HIST("h2dbachDeltaTimeAsOmKa"), cascade.p(), cascade.eta(), casctof.bachDeltaTimeAsOmKa); + histos.fill(HIST("h2dbachCorrectAssocAsOmKa"), cascade.p(), static_cast(collisionId == bTof.collisionId)); + histos.fill(HIST("h2dbachDiffFromPrimCalcAsOmKa"), cascade.p(), (bTof.tofSignal - bTof.tofEvTime) - casctof.bachFlightAsPrimaryKa); + if (doQANSigma && std::fabs(casctof.nSigmaOmKa - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaOmKa"), cascade.pt(), casctof.nSigmaOmKa); + } + } + if (omegaPlusCandidate) { + histos.fill(HIST("h2dbachDeltaTimeAsOmKa"), cascade.p(), cascade.eta(), casctof.bachDeltaTimeAsOmKa); + histos.fill(HIST("h2dbachCorrectAssocAsOmKa"), cascade.p(), static_cast(collisionId == bTof.collisionId)); + histos.fill(HIST("h2dbachDiffFromPrimCalcAsOmKa"), cascade.p(), (bTof.tofSignal - bTof.tofEvTime) - casctof.bachFlightAsPrimaryKa); + if (doQANSigma && std::fabs(casctof.nSigmaOmKa - o2::aod::v0data::kNoTOFValue) > o2::aod::v0data::kEpsilon) { + histos.fill(HIST("h2dNSigmaOmKa"), cascade.pt(), casctof.nSigmaOmKa); + } + } + } + } + } + } // end bachelor + + // don't forget to give feedback + return casctof; + } + + void processStandardData(aod::BCs const& bcs, aod::Collisions const& collisions, V0OriginalDatas const& V0s, CascOriginalDatas const& cascades, TracksWithAllExtras const& tracks, aod::BCsWithTimestamps const& /*bcs*/) + { + // 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()); + } + + //________________________________________________________________________ + // estimate event times (only necessary for original data) + std::vector collisionEventTime(collisions.size(), 0.0); + std::vector collisionNtracks(collisions.size(), 0); + for (const auto& track : tracks) { + if (track.hasTOF() && track.has_collision()) { + collisionEventTime[track.collisionId()] += track.tofEvTime(); + collisionNtracks[track.collisionId()]++; + } + } + for (const auto& collision : collisions) { + if (collisionNtracks[collision.globalIndex()] > 0) { + collisionEventTime[collision.globalIndex()] /= static_cast(collisionNtracks[collision.globalIndex()]); + } else { + collisionEventTime[collision.globalIndex()] = -1e+6; // undefined + } + histos.fill(HIST("hCollisionTimes"), collisionEventTime[collision.globalIndex()]); + } + + if (calculateV0s.value) { + for (const auto& V0 : V0s) { + trackTofInfo pTof, nTof; // information storage + + auto pTra = V0.posTrack_as(); + auto nTra = V0.negTrack_as(); + double deltaTimePos = 0.0f; + double deltaTimeNeg = 0.0f; + + auto collisionV0 = collisions.rawIteratorAt(V0.collisionId()); + auto bcV0 = bcs.rawIteratorAt(collisionV0.bcId()); + + if (pTra.collisionId() >= 0) { + auto collisionPos = collisions.rawIteratorAt(pTra.collisionId()); + auto bcPos = bcs.rawIteratorAt(collisionPos.bcId()); + const int64_t deltaBcPos = bcPos.globalBC() - bcV0.globalBC(); + deltaTimePos = o2::constants::lhc::LHCBunchSpacingNS * deltaBcPos * 1000.0f; + histos.fill(HIST("hV0PositiveBCShift"), deltaTimePos); + } + + if (nTra.collisionId() >= 0) { + auto collisionNeg = collisions.rawIteratorAt(nTra.collisionId()); + auto bcNeg = bcs.rawIteratorAt(collisionNeg.bcId()); + const int64_t deltaBcNeg = bcNeg.globalBC() - bcV0.globalBC(); + deltaTimeNeg = o2::constants::lhc::LHCBunchSpacingNS * deltaBcNeg * 1000.0f; + histos.fill(HIST("hV0NegativeBCShift"), deltaTimeNeg); + } + + pTof.collisionId = pTra.collisionId(); + pTof.hasITS = pTra.hasITS(); + pTof.hasTPC = pTra.hasTPC(); + pTof.hasTOF = pTra.hasTOF(); + pTof.tofExpMom = pTra.tofExpMom(); + pTof.tofEvTime = reassociateTracks ? collisionEventTime[V0.collisionId()] : pTra.tofEvTime(); + pTof.tofSignal = pTra.tofSignal() + (doBCshift ? deltaTimePos : 0.0f); + pTof.length = pTra.length(); + pTof.tpcNSigmaPi = pTra.tpcNSigmaPi(); + pTof.tpcNSigmaPr = pTra.tpcNSigmaPr(); + + nTof.collisionId = nTra.collisionId(); + nTof.hasITS = nTra.hasITS(); + nTof.hasTPC = nTra.hasTPC(); + nTof.hasTOF = nTra.hasTOF(); + nTof.tofExpMom = nTra.tofExpMom(); + nTof.tofEvTime = reassociateTracks ? collisionEventTime[V0.collisionId()] : nTra.tofEvTime(); + nTof.tofSignal = nTra.tofSignal() + (doBCshift ? deltaTimeNeg : 0.0f); + nTof.length = nTra.length(); + nTof.tpcNSigmaPi = nTra.tpcNSigmaPi(); + nTof.tpcNSigmaPr = nTra.tpcNSigmaPr(); + + if (pTof.hasTOF) { + histos.fill(HIST("hTOFSignalPositive"), pTof.tofSignal); + histos.fill(HIST("h2dTOFSignalPositive"), pTof.tofSignal, deltaTimePos); + } + + if (nTof.hasTOF) { + histos.fill(HIST("hTOFSignalNegative"), nTof.tofSignal); + histos.fill(HIST("h2dTOFSignalNegative"), nTof.tofSignal, deltaTimeNeg); + } + + v0TofInfo v0tof = calculateTofInfoV0(collisions, V0.collisionId(), V0, pTof, nTof); + + if (doNSigmas) { + v0tofnsigmas( + v0tof.nSigmaPositiveLambdaPr, v0tof.nSigmaNegativeLambdaPi, + v0tof.nSigmaNegativeLambdaPr, v0tof.nSigmaPositiveLambdaPi, + v0tof.nSigmaPositiveK0ShortPi, v0tof.nSigmaNegativeK0ShortPi); + } + if (calculateV0TOFPIDs.value) { + v0tofpid(v0tof.deltaTimePositiveLambdaPi, v0tof.deltaTimePositiveLambdaPr, + v0tof.deltaTimeNegativeLambdaPi, v0tof.deltaTimeNegativeLambdaPr, + v0tof.deltaTimePositiveK0ShortPi, v0tof.deltaTimeNegativeK0ShortPi, + v0tof.deltaDecayTimeLambda, v0tof.deltaDecayTimeAntiLambda, v0tof.deltaDecayTimeK0Short); + } + if (calculateV0TOFBetas.value) { + v0tofbeta(v0tof.betaLambda, v0tof.betaAntiLambda, v0tof.betaK0Short); + } + if (calculateV0TOFDebugs.value) { + v0tofdebugs(v0tof.timeLambda, v0tof.timeK0Short, + v0tof.timePositivePr, v0tof.timePositivePi, + v0tof.timeNegativePr, v0tof.timeNegativePi); + } + } + } + + if (calculateCascades.value) { + for (const auto& cascade : cascades) { + trackTofInfo pTof, nTof, bTof; // information storage + + auto pTra = cascade.posTrack_as(); + auto nTra = cascade.negTrack_as(); + auto bTra = cascade.bachelor_as(); + + double deltaTimePos = 0.0f; + double deltaTimeNeg = 0.0f; + double deltaTimeBach = 0.0f; + + auto collisionCascade = collisions.rawIteratorAt(cascade.collisionId()); + auto bcV0 = bcs.rawIteratorAt(collisionCascade.bcId()); + + if (pTra.collisionId() >= 0) { + auto collisionPos = collisions.rawIteratorAt(pTra.collisionId()); + auto bcPos = bcs.rawIteratorAt(collisionPos.bcId()); + const int64_t deltaBcPos = bcPos.globalBC() - bcV0.globalBC(); + deltaTimePos = o2::constants::lhc::LHCBunchSpacingNS * deltaBcPos * 1000.0f; + histos.fill(HIST("hCascadePositiveBCShift"), deltaTimePos); + } + + if (nTra.collisionId() >= 0) { + auto collisionNeg = collisions.rawIteratorAt(nTra.collisionId()); + auto bcNeg = bcs.rawIteratorAt(collisionNeg.bcId()); + const int64_t deltaBcNeg = bcNeg.globalBC() - bcV0.globalBC(); + deltaTimeNeg = o2::constants::lhc::LHCBunchSpacingNS * deltaBcNeg * 1000.0f; + histos.fill(HIST("hCascadeNegativeBCShift"), deltaTimeNeg); + } + + if (bTra.collisionId() >= 0) { + auto collisionBach = collisions.rawIteratorAt(bTra.collisionId()); + auto bcBach = bcs.rawIteratorAt(collisionBach.bcId()); + const int64_t deltaBcBach = bcBach.globalBC() - bcV0.globalBC(); + deltaTimeBach = o2::constants::lhc::LHCBunchSpacingNS * deltaBcBach * 1000.0f; + histos.fill(HIST("hCascadeBachelorBCShift"), deltaTimeBach); + } + + pTof.collisionId = pTra.collisionId(); + pTof.hasITS = pTra.hasITS(); + pTof.hasTPC = pTra.hasTPC(); + pTof.hasTOF = pTra.hasTOF(); + pTof.tofExpMom = pTra.tofExpMom(); + pTof.tofEvTime = reassociateTracks ? collisionEventTime[cascade.collisionId()] : pTra.tofEvTime(); + pTof.tofSignal = pTra.tofSignal() + (doBCshift ? deltaTimePos : 0.0f); + pTof.length = pTra.length(); + pTof.tpcNSigmaPi = pTra.tpcNSigmaPi(); + pTof.tpcNSigmaPr = pTra.tpcNSigmaPr(); + + nTof.collisionId = nTra.collisionId(); + nTof.hasITS = nTra.hasITS(); + nTof.hasTPC = nTra.hasTPC(); + nTof.hasTOF = nTra.hasTOF(); + nTof.tofExpMom = nTra.tofExpMom(); + nTof.tofEvTime = reassociateTracks ? collisionEventTime[cascade.collisionId()] : nTra.tofEvTime(); + nTof.tofSignal = nTra.tofSignal() + (doBCshift ? deltaTimeNeg : 0.0f); + nTof.length = nTra.length(); + nTof.tpcNSigmaPi = nTra.tpcNSigmaPi(); + nTof.tpcNSigmaPr = nTra.tpcNSigmaPr(); + + bTof.collisionId = bTra.collisionId(); + bTof.hasITS = bTra.hasITS(); + bTof.hasTPC = bTra.hasTPC(); + bTof.hasTOF = bTra.hasTOF(); + bTof.tofExpMom = bTra.tofExpMom(); + bTof.tofEvTime = reassociateTracks ? collisionEventTime[cascade.collisionId()] : bTra.tofEvTime(); + bTof.tofSignal = bTra.tofSignal() + (doBCshift ? deltaTimeBach : 0.0f); + bTof.length = bTra.length(); + bTof.tpcNSigmaPi = bTra.tpcNSigmaPi(); + bTof.tpcNSigmaKa = bTra.tpcNSigmaKa(); + + if (pTof.hasTOF) { + histos.fill(HIST("h2dTOFSignalCascadePositive"), pTof.tofSignal, deltaTimePos); + } + if (nTof.hasTOF) { + histos.fill(HIST("h2dTOFSignalCascadeNegative"), nTof.tofSignal, deltaTimeNeg); + } + if (bTof.hasTOF) { + histos.fill(HIST("h2dTOFSignalCascadeBachelor"), bTof.tofSignal, deltaTimeBach); + } + + cascTofInfo casctof = calculateTofInfoCascade(collisions, cascade.collisionId(), cascade, pTof, nTof, bTof); + + if (doNSigmas) { + casctofnsigmas( + casctof.nSigmaXiLaPi, casctof.nSigmaXiLaPr, casctof.nSigmaXiPi, + casctof.nSigmaOmLaPi, casctof.nSigmaOmLaPr, casctof.nSigmaOmKa); + } + if (calculateCascTOFPIDs.value) { + casctofpids( + casctof.posDeltaTimeAsXiPi, casctof.posDeltaTimeAsXiPr, + casctof.negDeltaTimeAsXiPi, casctof.negDeltaTimeAsXiPr, casctof.bachDeltaTimeAsXiPi, + casctof.posDeltaTimeAsOmPi, casctof.posDeltaTimeAsOmPr, + casctof.negDeltaTimeAsOmPi, casctof.negDeltaTimeAsOmPr, casctof.bachDeltaTimeAsOmKa); + } + } + } + } + + void processDerivedData(soa::Join const& collisions, V0DerivedDatas const& V0s, CascDerivedDatas const& cascades, dauTracks const& dauTrackTable, aod::DauTrackTOFPIDs const& dauTrackTOFPIDs) + { + bool isNewTOFFormat = true; // can only happen for new format + + for (const auto& collision : collisions) { + histos.fill(HIST("hCollisionTimes"), collision.eventTime()); + } + + // auto-determine if using old format + if (dauTrackTOFPIDs.size() != 0) { + auto firstTOFPID = dauTrackTOFPIDs.rawIteratorAt(0); + isNewTOFFormat = firstTOFPID.straCollisionId() < 0 ? false : true; + } + + if (!isNewTOFFormat && calculationMethod.value > 0) { + LOGF(fatal, "Using the old derived data format with the new calculation method is not viable due to lack of needed info! Crashing."); + } + + // 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()); + } + + // hold indices + std::vector tofIndices(dauTrackTable.size(), -1); + + if (isNewTOFFormat) { + // re-index + for (const auto& dauTrackTOFPID : dauTrackTOFPIDs) { + tofIndices[dauTrackTOFPID.dauTrackExtraId()] = dauTrackTOFPID.globalIndex(); + } + } else { + // they are actually joinable + std::iota(tofIndices.begin(), tofIndices.end(), 0); + } + + if (calculateV0s.value) { + for (const auto& V0 : V0s) { + trackTofInfo pTof, nTof; // information storage + + auto collision = collisions.rawIteratorAt(V0.straCollisionId()); + auto pTra = V0.posTrackExtra_as(); + auto nTra = V0.negTrackExtra_as(); + + double deltaTimeBcPos = 1e+6; + double deltaTimeBcNeg = 1e+6; + + pTof.hasITS = pTra.hasITS(); + pTof.hasTPC = pTra.hasTPC(); + pTof.hasTOF = pTra.hasTOF(); + pTof.tpcNSigmaPi = pTra.tpcNSigmaPi(); + pTof.tpcNSigmaPr = pTra.tpcNSigmaPr(); + if (tofIndices[V0.posTrackExtraId()] >= 0 && collision.eventTime() > -1e+5) { + auto pTofExt = dauTrackTOFPIDs.rawIteratorAt(tofIndices[V0.posTrackExtraId()]); + + if (pTofExt.straCollisionId() >= 0) { + // extract BC for BC time shift + auto collisionTrack = collisions.rawIteratorAt(pTofExt.straCollisionId()); + const int64_t deltaBc = collisionTrack.globalBC() - collision.globalBC(); + const double deltaTimeBc = o2::constants::lhc::LHCBunchSpacingNS * deltaBc * 1000.0f; + histos.fill(HIST("hV0PositiveBCShift"), deltaTimeBc); + deltaTimeBcPos = deltaTimeBc; + + // assign variables + pTof.collisionId = pTofExt.straCollisionId(); + pTof.tofExpMom = pTofExt.tofExpMom(); + pTof.tofEvTime = reassociateTracks.value ? collision.eventTime() : pTofExt.tofEvTime(); + pTof.tofSignal = pTofExt.tofSignal() + (doBCshift.value ? deltaTimeBc : 0.0f); + pTof.length = pTofExt.length(); + } + } + + nTof.hasITS = nTra.hasITS(); + nTof.hasTPC = nTra.hasTPC(); + nTof.hasTOF = nTra.hasTOF(); + nTof.tpcNSigmaPi = nTra.tpcNSigmaPi(); + nTof.tpcNSigmaPr = nTra.tpcNSigmaPr(); + if (tofIndices[V0.negTrackExtraId()] >= 0 && collision.eventTime() > -1e+5) { + auto nTofExt = dauTrackTOFPIDs.rawIteratorAt(tofIndices[V0.negTrackExtraId()]); + + if (nTofExt.straCollisionId() >= 0) { + // extract BC for BC time shift + auto collisionTrack = collisions.rawIteratorAt(nTofExt.straCollisionId()); + const int64_t deltaBc = collisionTrack.globalBC() - collision.globalBC(); + const double deltaTimeBc = o2::constants::lhc::LHCBunchSpacingNS * deltaBc * 1000.0f; + histos.fill(HIST("hV0NegativeBCShift"), deltaTimeBc); + deltaTimeBcNeg = deltaTimeBc; + + // assign variables + nTof.collisionId = nTofExt.straCollisionId(); + nTof.tofExpMom = nTofExt.tofExpMom(); + nTof.tofEvTime = reassociateTracks.value ? collision.eventTime() : nTofExt.tofEvTime(); + nTof.tofSignal = nTofExt.tofSignal() + (doBCshift.value ? deltaTimeBc : 0.0f); + nTof.length = nTofExt.length(); + } + } + if (pTof.hasTOF) { + histos.fill(HIST("hTOFSignalPositive"), pTof.tofSignal); + histos.fill(HIST("h2dTOFSignalPositive"), pTof.tofSignal, deltaTimeBcPos); + } + + if (nTof.hasTOF) { + histos.fill(HIST("hTOFSignalNegative"), nTof.tofSignal); + histos.fill(HIST("h2dTOFSignalNegative"), nTof.tofSignal, deltaTimeBcNeg); + } + + v0TofInfo v0tof = calculateTofInfoV0(collisions, V0.straCollisionId(), V0, pTof, nTof); + + if (doNSigmas) { + v0tofnsigmas( + v0tof.nSigmaPositiveLambdaPr, v0tof.nSigmaNegativeLambdaPi, + v0tof.nSigmaNegativeLambdaPr, v0tof.nSigmaPositiveLambdaPi, + v0tof.nSigmaPositiveK0ShortPi, v0tof.nSigmaNegativeK0ShortPi); + } + if (calculateV0TOFPIDs.value) { + v0tofpid(v0tof.deltaTimePositiveLambdaPi, v0tof.deltaTimePositiveLambdaPr, + v0tof.deltaTimeNegativeLambdaPi, v0tof.deltaTimeNegativeLambdaPr, + v0tof.deltaTimePositiveK0ShortPi, v0tof.deltaTimeNegativeK0ShortPi, + v0tof.deltaDecayTimeLambda, v0tof.deltaDecayTimeAntiLambda, v0tof.deltaDecayTimeK0Short); + } + if (calculateV0TOFBetas.value) { + v0tofbeta(v0tof.betaLambda, v0tof.betaAntiLambda, v0tof.betaK0Short); + } + if (calculateV0TOFDebugs.value) { + v0tofdebugs(v0tof.timeLambda, v0tof.timeK0Short, + v0tof.timePositivePr, v0tof.timePositivePi, + v0tof.timeNegativePr, v0tof.timeNegativePi); + } + } + } + + if (calculateCascades.value) { + for (const auto& cascade : cascades) { + trackTofInfo pTof, nTof, bTof; // information storage + + auto collision = collisions.rawIteratorAt(cascade.straCollisionId()); + auto pTra = cascade.posTrackExtra_as(); + auto nTra = cascade.negTrackExtra_as(); + auto bTra = cascade.bachTrackExtra_as(); + + pTof.hasITS = pTra.hasITS(); + pTof.hasTPC = pTra.hasTPC(); + pTof.hasTOF = pTra.hasTOF(); + pTof.tpcNSigmaPi = pTra.tpcNSigmaPi(); + pTof.tpcNSigmaPr = pTra.tpcNSigmaPr(); + if (tofIndices[cascade.posTrackExtraId()] >= 0 && collision.eventTime() > -1e+5) { + auto pTofExt = dauTrackTOFPIDs.rawIteratorAt(tofIndices[cascade.posTrackExtraId()]); + + if (pTofExt.straCollisionId() >= 0) { + // extract BC for BC time shift + auto collisionTrack = collisions.rawIteratorAt(pTofExt.straCollisionId()); + const int64_t deltaBc = collisionTrack.globalBC() - collision.globalBC(); + const double deltaTimeBc = o2::constants::lhc::LHCBunchSpacingNS * deltaBc * 1000.0f; + histos.fill(HIST("hCascadePositiveBCShift"), deltaTimeBc); + histos.fill(HIST("h2dTOFSignalCascadePositive"), pTof.tofSignal, deltaTimeBc); + + pTof.collisionId = pTofExt.straCollisionId(); + pTof.tofExpMom = pTofExt.tofExpMom(); + pTof.tofEvTime = reassociateTracks.value ? collision.eventTime() : pTofExt.tofEvTime(); + pTof.tofSignal = pTofExt.tofSignal() + (doBCshift.value ? deltaTimeBc : 0.0f); + pTof.length = pTofExt.length(); + } + } + + nTof.hasITS = nTra.hasITS(); + nTof.hasTPC = nTra.hasTPC(); + nTof.hasTOF = nTra.hasTOF(); + nTof.tpcNSigmaPi = nTra.tpcNSigmaPi(); + nTof.tpcNSigmaPr = nTra.tpcNSigmaPr(); + if (tofIndices[cascade.negTrackExtraId()] >= 0 && collision.eventTime() > -1e+5) { + auto nTofExt = dauTrackTOFPIDs.rawIteratorAt(tofIndices[cascade.negTrackExtraId()]); + + if (nTofExt.straCollisionId() >= 0) { + // extract BC for BC time shift + auto collisionTrack = collisions.rawIteratorAt(nTofExt.straCollisionId()); + const int64_t deltaBc = collisionTrack.globalBC() - collision.globalBC(); + const double deltaTimeBc = o2::constants::lhc::LHCBunchSpacingNS * deltaBc * 1000.0f; + histos.fill(HIST("hCascadeNegativeBCShift"), deltaTimeBc); + histos.fill(HIST("h2dTOFSignalCascadeNegative"), nTof.tofSignal, deltaTimeBc); + + nTof.collisionId = nTofExt.straCollisionId(); + nTof.tofExpMom = nTofExt.tofExpMom(); + nTof.tofEvTime = reassociateTracks.value ? collision.eventTime() : nTofExt.tofEvTime(); + nTof.tofSignal = nTofExt.tofSignal() + (doBCshift.value ? deltaTimeBc : 0.0f); + nTof.length = nTofExt.length(); + } + } + + bTof.hasITS = bTra.hasITS(); + bTof.hasTPC = bTra.hasTPC(); + bTof.hasTOF = bTra.hasTOF(); + bTof.tpcNSigmaPi = bTra.tpcNSigmaPi(); + bTof.tpcNSigmaKa = bTra.tpcNSigmaKa(); + if (tofIndices[cascade.bachTrackExtraId()] >= 0 && collision.eventTime() > -1e+5) { + auto bTofExt = dauTrackTOFPIDs.rawIteratorAt(tofIndices[cascade.bachTrackExtraId()]); + + if (bTofExt.straCollisionId() >= 0) { + // extract BC for BC time shift + auto collisionTrack = collisions.rawIteratorAt(bTofExt.straCollisionId()); + const int64_t deltaBc = collisionTrack.globalBC() - collision.globalBC(); + const double deltaTimeBc = o2::constants::lhc::LHCBunchSpacingNS * deltaBc * 1000.0f; + histos.fill(HIST("hCascadeBachelorBCShift"), deltaTimeBc); + histos.fill(HIST("h2dTOFSignalCascadeBachelor"), bTof.tofSignal, deltaTimeBc); + + bTof.collisionId = bTofExt.straCollisionId(); + bTof.tofExpMom = bTofExt.tofExpMom(); + bTof.tofEvTime = reassociateTracks.value ? collision.eventTime() : bTofExt.tofEvTime(); + bTof.tofSignal = bTofExt.tofSignal() + (doBCshift.value ? deltaTimeBc : 0.0f); + bTof.length = bTofExt.length(); + } + } + + cascTofInfo casctof = calculateTofInfoCascade(collisions, cascade.straCollisionId(), cascade, pTof, nTof, bTof); + + if (doNSigmas) { + casctofnsigmas( + casctof.nSigmaXiLaPi, casctof.nSigmaXiLaPr, casctof.nSigmaXiPi, + casctof.nSigmaOmLaPi, casctof.nSigmaOmLaPr, casctof.nSigmaOmKa); + } + if (calculateCascTOFPIDs.value) { + casctofpids( + casctof.posDeltaTimeAsXiPi, casctof.posDeltaTimeAsXiPr, + casctof.negDeltaTimeAsXiPi, casctof.negDeltaTimeAsXiPr, casctof.bachDeltaTimeAsXiPi, + casctof.posDeltaTimeAsOmPi, casctof.posDeltaTimeAsOmPr, + casctof.negDeltaTimeAsOmPi, casctof.negDeltaTimeAsOmPr, casctof.bachDeltaTimeAsOmKa); + } + } + } + } + + PROCESS_SWITCH(strangenesstofpid, processStandardData, "Process standard data", false); + PROCESS_SWITCH(strangenesstofpid, processDerivedData, "Process derived data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/v0qaanalysis.cxx b/PWGLF/TableProducer/Strangeness/v0qaanalysis.cxx index 875d0f1c671..03b3f0ac7b3 100644 --- a/PWGLF/TableProducer/Strangeness/v0qaanalysis.cxx +++ b/PWGLF/TableProducer/Strangeness/v0qaanalysis.cxx @@ -13,18 +13,25 @@ /// /// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/v0qaanalysis.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "PWGLF/DataModel/mcCentrality.h" -#include "PWGLF/Utils/inelGt.h" + +#include +#include using namespace o2; using namespace o2::framework; @@ -40,7 +47,7 @@ void customize(std::vector& workflowOptions) using DauTracks = soa::Join; using DauTracksMC = soa::Join; -using V0Collisions = soa::Join; +using V0Collisions = soa::Join; struct LfV0qaanalysis { @@ -66,7 +73,7 @@ struct LfV0qaanalysis { } LOG(info) << "Number of process functions enabled: " << nProc; - registry.add("hNEvents", "hNEvents", {HistType::kTH1I, {{10, 0.f, 10.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, "TVX"); @@ -74,11 +81,11 @@ struct LfV0qaanalysis { 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(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("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}}}); @@ -86,14 +93,14 @@ struct LfV0qaanalysis { 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::kTH1I, {{4, 0.f, 4.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.add("hNEventsMCGenReco", "hNEventsMCGenReco", {HistType::kTH1I, {{2, 0.f, 2.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::kTH1I, {{4, 0.f, 4.f}}}); + 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"); @@ -107,6 +114,8 @@ struct LfV0qaanalysis { 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}}}); @@ -119,6 +128,8 @@ struct LfV0qaanalysis { 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}}}); @@ -134,13 +145,16 @@ struct LfV0qaanalysis { // Event selection criteria Configurable cutzvertex{"cutzvertex", 15.0f, "Accepted z-vertex range (cm)"}; + 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 isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", 0, "isGoodZvtxFT0vsPV"}; + 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"}; @@ -163,7 +177,7 @@ struct LfV0qaanalysis { return false; } registry.fill(HIST("hNEvents"), 2.5); - if (TMath::Abs(collision.posZ()) > cutzvertex) { + if (std::abs(collision.posZ()) > cutzvertex) { return false; } registry.fill(HIST("hNEvents"), 3.5); @@ -171,7 +185,7 @@ struct LfV0qaanalysis { return false; } registry.fill(HIST("hNEvents"), 4.5); - if (!isMC && isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + if (isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return false; } registry.fill(HIST("hNEvents"), 5.5); @@ -179,7 +193,7 @@ struct LfV0qaanalysis { return false; } registry.fill(HIST("hNEvents"), 6.5); - if (isGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + if (isNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; } registry.fill(HIST("hNEvents"), 7.5); @@ -201,25 +215,21 @@ struct LfV0qaanalysis { } 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; @@ -228,27 +238,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()); } } } @@ -294,7 +317,15 @@ struct LfV0qaanalysis { } auto v0mcparticle = v0.mcParticle(); - if (abs(v0mcparticle.y()) > 0.5f) { + if (std::abs(v0mcparticle.y()) > 0.5f) { + continue; + } + + if (v0.v0Type() != v0TypeSelection) { + continue; + } + + if (NotITSAfterburner && (v0.negTrack_as().isITSAfterburner() || v0.posTrack_as().isITSAfterburner())) { continue; } @@ -321,46 +352,70 @@ struct LfV0qaanalysis { } 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 // && ) { // 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, - mcCollision.centFT0M(), 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()); } } @@ -372,7 +427,7 @@ struct LfV0qaanalysis { continue; } - if (abs(mcParticle.y()) > 0.5f) { + if (std::abs(mcParticle.y()) > 0.5f) { continue; } @@ -409,7 +464,7 @@ struct LfV0qaanalysis { registry.fill(HIST("hNEventsMCGen"), 0.5); - if (TMath::Abs(mcCollision.posZ()) > cutzvertex) { + if (std::abs(mcCollision.posZ()) > MCcutzvertex) { return; } registry.fill(HIST("hNEventsMCGen"), 1.5); @@ -432,7 +487,7 @@ struct LfV0qaanalysis { if (!mcParticle.isPhysicalPrimary()) { continue; } - if (abs(mcParticle.y()) > 0.5f) { + if (std::abs(mcParticle.y()) > 0.5f) { continue; } @@ -491,7 +546,7 @@ struct LfV0qaanalysis { continue; } - if (abs(mcParticle.y()) > 0.5f) { + if (std::abs(mcParticle.y()) > 0.5f) { continue; } @@ -543,7 +598,7 @@ struct LfV0qaanalysis { continue; } - if (abs(mcParticle.y()) > 0.5f) { + if (std::abs(mcParticle.y()) > 0.5f) { continue; } @@ -565,6 +620,18 @@ struct LfV0qaanalysis { 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", false); diff --git a/PWGLF/TableProducer/Strangeness/v0selector.cxx b/PWGLF/TableProducer/Strangeness/v0selector.cxx new file mode 100644 index 00000000000..1d5d392b358 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/v0selector.cxx @@ -0,0 +1,306 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 selectK0S{"selectK0S", true, "Check V0s for K0S cuts"}; + Configurable selectLambda{"selectLambda", true, "Check V0s for Lambda cuts"}; + Configurable selectAntiLambda{"selectAntiLambda", true, "Check V0s for AntiLambda cuts"}; + + 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", false, "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; + if (selectK0S) + flag += K0SCuts(collision, v0) * aod::v0flags::FK0S; + if (selectLambda) + flag += LambdaCuts(collision, v0) * aod::v0flags::FLAMBDA; + if (selectAntiLambda) + flag += AntiLambdaCuts(collision, v0) * aod::v0flags::FANTILAMBDA; + + if (flag == 0) + flag += aod::v0flags::FREJECTED; + else if (randomSelection) + 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..50a0d2dfa52 --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/CMakeLists.txt @@ -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. + +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) + +o2physics_add_dpl_workflow(flattenicty-pikp + SOURCES flattenictyPikp.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(study-pnch + SOURCES studyPnch.cxx + PUBLIC_LINK_LIBRARIES 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..93b8625ba65 --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/dndeta-mft-pp.cxx @@ -0,0 +1,1223 @@ +// Copyright 2020-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 dndeta-mft.cxx +// \author Sarah Herrmann +// +// \brief This code loops over MFT tracks and collisions and fills histograms +// useful to compute dNdeta + +#include "PWGMM/Mult/DataModel/bestCollisionTable.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 "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 "MathUtils/Utils.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +#include "TFile.h" + +#include +#include +#include +#include +#include +#include +#include + +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, o2::constants::math::TwoPI, "Rad", "phi axis"}; +// AxisSpec EtaAxis = {18, -4.6, -1.}; +AxisSpec DCAxyAxis = {5000, -1, 500}; +AxisSpec DCAzAxis = {5000, -251, 250}; +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"}; + Configurable disableITSROFCut{"disableITSROFCut", false, "Disable ITS ROF cut for event selection"}; + ConfigurableAxis multBinning{"multBinning", {701, -0.5, 700.5}, ""}; + ConfigurableAxis EtaAxis = {"etaBinning", {36, -4.6, -1.}, ""}; + + Configurable useZDiffCut{"useZDiffCut", true, "use Z difference cut"}; + Configurable maxZDiff{ + "maxZDiff", 1.0f, + "max allowed Z difference for reconstructed collisions (cm)"}; + + Configurable usePhiCut{"usePhiCut", true, "use azimuthal angle cut"}; + Configurable useDCAxyCut{"useDCAxyCut", false, "use DCAxy cut"}; + Configurable useDCAzCut{"useDCAzCut", false, "use DCAz cut"}; + + Configurable cfgPhiCut{"cfgPhiCut", 0.1f, + "Cut on azimuthal angle of MFT tracks"}; + Configurable cfgPhiCut1{"cfgPhiCut1", 0.0f, + "low Cut on azimuthal angle of MFT tracks"}; + Configurable cfgPhiCut2{"cfgPhiCut2", 6.3f, + "high 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"}; + Configurable cfgChi2NDFMax{"cfgChi2NDFMax", 2000.0f, "Max allowed chi2/NDF for MFT tracks"}; + Configurable maxDCAxy{"maxDCAxy", 2.0f, "Cut on dcaXY"}; + Configurable maxDCAz{"maxDCAz", 2.0f, "Cut on dcaZ"}; + + 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 + // Purity-related histograms + {"Purity/SelectedAfterDCAxy/All", + ";bin;counts", + {HistType::kTH1F, {{1, 0.5, 1.5}}}}, + {"Purity/SelectedAfterDCAxy/AllEta", + ";#eta;counts", + {HistType::kTH1F, {EtaAxis}}}, + {"Purity/Gen/PrimaryEta", + ";#eta;primaries", + {HistType::kTH1F, {EtaAxis}}}, + {"Purity/Gen/All", + ";bin;counts", + {HistType::kTH1F, {{1, 0.5, 1.5}}}}, + {"Purity/Gen/AllEta", + ";#eta;counts", + {HistType::kTH1F, {EtaAxis}}}}}; + + void init(InitContext&) + { + if (static_cast(doprocessMult) + + static_cast(doprocessMultReassoc) + + static_cast(doprocessMultReassoc3d) + + static_cast(doprocessCountingCentrality) > + 1) { + LOGP(fatal, + "Exactly one process function between processMult, " + "processMultReassoc, processMultReassoc3d 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, "Vz"); + x->SetBinLabel(3, "Vz+ITSRof"); + x->SetBinLabel(4, "Vz+Selected"); + x->SetBinLabel(5, "Sel8+Vz+INEL>0"); + x->SetBinLabel(6, "Sel INEL,INEL_fwd>0"); + x->SetBinLabel(7, "Rejected"); + x->SetBinLabel(8, "Good BCs"); + x->SetBinLabel(9, "BCs with collisions"); + x->SetBinLabel(10, "BCs with pile-up/splitting"); + 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/2Danalysis/EventsNtrkZvtx_all", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"Tracks/2Danalysis/EventsNtrkZvtx_sel8", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"Tracks/2Danalysis/EventsNtrkZvtx_sel8_inelgt0", + "; N_{trk}; #it{z}_{vtx} (cm); events", + {HistType::kTH2F, {MultAxis, ZAxis}}}); + registry.add({"Tracks/2Danalysis/EventsNtrkZvtx_sel8_inelfwdgt0", + "; 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 || doprocessMultReassoc3d) { + 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/Chi2NDF", + " ; #chi^{2}/ndf", + {HistType::kTH1F, {{5000, 0.0, 5000.0}}}}); + 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/amb/DCAxy_amb", " ; DCA_{xy} (cm) ambiguous", + // {HistType::kTH1F,{{100000, 0.5, 100000.0}}}}); // + {HistType::kTH1F, {DCAxyAxis}}}); // + + 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/nonamb/DCAxy_nonamb", " ; DCA_{xy}(cm) non-ambiguous", + // {HistType::kTH1F,{{100000, 0.5, 100000.0}}}}); // + {HistType::kTH1F, {{DCAxyAxis}}}}); // + + 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/2Danalysis/EtaZvtx", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + registry.add({"Tracks/2Danalysis/EtaZvtx_sel8", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + registry.add({"Tracks/2Danalysis/EtaZvtx_sel8_inelgt0", + "; #eta; #it{z}_{vtx} (cm); tracks", + {HistType::kTH2F, {EtaAxis, ZAxis}}}); // + registry.add({"Tracks/2Danalysis/EtaZvtx_sel8_inelfwdgt0", + "; #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({"Tracks/Control/woOrp/DCAxy_woOrp", " ; DCA_{xy}(cm) w/o orphan", + // {HistType::kTH1F,{{100000, 0.5, 100000.0}}}}); // + {HistType::kTH1F, {{DCAxyAxis}}}}); // + + if (doprocessMultReassoc3d) { + // DCAz histograms analogous to DCAxy, only for 3D reassociation + registry.add({"Tracks/Control/DCAZ", + " ; DCA_{Z} (cm)", + {HistType::kTH1F, {DCAzAxis}}}); + registry.add({"Tracks/Control/amb/DCAz_amb", + " ; DCA_{z} (cm) ambiguous", + {HistType::kTH1F, {DCAzAxis}}}); + registry.add({"Tracks/Control/nonamb/DCAz_nonamb", + " ; DCA_{z}(cm) non-ambiguous", + {HistType::kTH1F, {DCAzAxis}}}); + registry.add({"Tracks/Control/woOrp/DCAz_woOrp", + " ; DCA_{z}(cm) w/o orphan", + {HistType::kTH1F, {DCAzAxis}}}); + } + + 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 (const auto& bc : bcs) { + if (!useEvSel || + (useEvSel && ((bc.selection_bit(aod::evsel::kIsBBT0A) && + bc.selection_bit(aod::evsel::kIsBBT0C)) != 0))) { + registry.fill(HIST("EventSelection"), 8); // added 5->12 + cols.clear(); + for (const 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"), 9); // added 6->13 + if (cols.size() > 1) { + registry.fill(HIST("EventSelection"), 10); // 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 (const auto& track : tracks) { + + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + + if (usePhiCut) { + if ((phi < cfgPhiCut) || + ((phi > o2::constants::math::PI - cfgPhiCut) && (phi < o2::constants::math::PI + cfgPhiCut)) || + (phi > o2::constants::math::TwoPI - cfgPhiCut) || + ((phi > ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::PI) - cfgPhiCut) && + (phi < ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::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); + // Common implementation for both BestCollisionsFwd and BestCollisionsFwd3d + template + void processMultReassocCommon(CollwEv::iterator const& collision, + o2::aod::MFTTracks const&, + RetracksT const& retracks, + FiCentralTracks const& midtracks, aod::Tracks const&) + { + registry.fill(HIST("EventSelection"), 1.); + auto perCollisionSample = sampleCentral->sliceByCached( + o2::aod::track::collisionId, collision.globalIndex(), cache); + auto Ntrk = perCollisionSample.size(); + auto z = collision.posZ(); + registry.fill(HIST("EventsNtrkZvtx"), Ntrk, z); + if ((z >= cfgVzCut1) && (z <= cfgVzCut2)) { + registry.fill(HIST("Tracks/2Danalysis/EventsNtrkZvtx_all"), Ntrk, z); + registry.fill(HIST("EventSelection"), 2.); + for (const auto& retrack : retracks) { + auto track = retrack.mfttrack(); + float ndf = std::max(2.0f * track.nClusters() - 5.0f, 1.0f); + float chi2ndf = track.chi2() / ndf; + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + if (usePhiCut) { + if ((phi <= 0.02) || ((phi >= 3.10) && (phi <= 3.23)) || (phi >= 6.21)) + continue; + } + float dcaxy_cut = retrack.bestDCAXY(); + if (useDCAxyCut) { + if (dcaxy_cut > maxDCAxy) + continue; + } + if constexpr (std::is_same_v>) { + float dcaz_cut = retrack.bestDCAZ(); + if (useDCAzCut) { + if (dcaz_cut > maxDCAz) + continue; + } + } + if ((cfgnEta1 < track.eta()) && (track.eta() < cfgnEta2) && track.nClusters() >= cfgnCluster && retrack.ambDegree() > 0 && chi2ndf < cfgChi2NDFMax && (phi > cfgPhiCut1 && phi < cfgPhiCut2)) { + registry.fill(HIST("Tracks/2Danalysis/EtaZvtx"), track.eta(), z); + } + } + if (!disableITSROFCut && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + registry.fill(HIST("EventSelection"), 3.); + if (!useEvSel || (useEvSel && collision.selection_bit(aod::evsel::kIsTriggerTVX) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoSameBunchPileup))) { + registry.fill(HIST("EventSelection"), 4.); + registry.fill(HIST("Tracks/2Danalysis/EventsNtrkZvtx_sel8"), Ntrk, z); + std::unordered_set uniqueEvents; + std::unordered_set uniqueEventsAmb; + std::unordered_set uniqueCollisions; + std::unordered_set uniqueCollisionsAmb; + std::unordered_set eventsInelMFT; + std::unordered_set eventsInel; + if (midtracks.size() > 0) { + registry.fill(HIST("EventSelection"), 5.); + registry.fill(HIST("EventsNtrkZvtx_gt0"), Ntrk, z); + registry.fill(HIST("Tracks/2Danalysis/EventsNtrkZvtx_sel8_inelgt0"), 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; + for (const auto& retrack : retracks) { + auto track = retrack.mfttrack(); + float ndf = std::max(2.0f * track.nClusters() - 5.0f, 1.0f); + float chi2ndf = track.chi2() / ndf; + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + if (usePhiCut) { + if ((phi <= 0.02) || ((phi >= 3.10) && (phi <= 3.23)) || (phi >= 6.21)) + continue; + } + float dcaxy_cut = retrack.bestDCAXY(); + if (useDCAxyCut) { + if (dcaxy_cut > maxDCAxy) + continue; + } + if constexpr (std::is_same_v>) { + float dcaz_cut = retrack.bestDCAZ(); + if (useDCAzCut) { + if (dcaz_cut > maxDCAz) + continue; + } + } + if ((cfgnEta1 < track.eta()) && (track.eta() < cfgnEta2) && track.nClusters() >= cfgnCluster && retrack.ambDegree() > 0 && chi2ndf < cfgChi2NDFMax && (phi > cfgPhiCut1 && phi < cfgPhiCut2)) { + registry.fill(HIST("Tracks/Control/Chi2NDF"), chi2ndf); + registry.fill(HIST("Tracks/2Danalysis/EtaZvtx_sel8"), track.eta(), z); + if (midtracks.size() > 0 && retrack.ambDegree() > 0) { + registry.fill(HIST("Tracks/2Danalysis/EtaZvtx_sel8_inelgt0"), track.eta(), z); + } + } + } + if (retracks.size() > 0) { + registry.fill(HIST("EventSelection"), 6.); + if (midtracks.size() > 0) { + registry.fill(HIST("Tracks/2Danalysis/EventsNtrkZvtx_sel8_inelfwdgt0"), Ntrk, z); + } + for (const auto& retrack : retracks) { + auto track = retrack.mfttrack(); + float ndf = std::max(2.0f * track.nClusters() - 5.0f, 1.0f); + float chi2ndf = track.chi2() / ndf; + float phi = track.phi(); + float dcaxy_cut = retrack.bestDCAXY(); + o2::math_utils::bringTo02Pi(phi); + // Declare dcaz_cut only if needed below. + if ((cfgnEta1 < track.eta()) && (track.eta() < cfgnEta2) && track.nClusters() >= cfgnCluster && chi2ndf < cfgChi2NDFMax && (phi > cfgPhiCut1 && phi < cfgPhiCut2)) { + if (usePhiCut) { + if ((phi <= 0.02) || ((phi >= 3.10) && (phi <= 3.23)) || (phi >= 6.21)) + continue; + } + if (useDCAxyCut) { + if (dcaxy_cut > maxDCAxy) + continue; + } + if constexpr (std::is_same_v>) { + float dcaz_cut = retrack.bestDCAZ(); + if (useDCAzCut) { + if (dcaz_cut > maxDCAz) + continue; + } + } + // Purity denominator: all tracks that pass the DCA selection and other quality cuts + registry.fill(HIST("Purity/SelectedAfterDCAxy/All"), 1.); + registry.fill(HIST("Purity/SelectedAfterDCAxy/AllEta"), track.eta()); + registry.fill(HIST("TracksEtaZvtx"), track.eta(), z); + if (midtracks.size() > 0 && retrack.ambDegree() > 0) { + registry.fill(HIST("Tracks/EtaZvtx_gt0"), track.eta(), z); + registry.fill(HIST("Tracks/2Danalysis/EtaZvtx_sel8_inelfwdgt0"), 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.template collision_as().posZ(), z); + + registry.fill(HIST("Tracks/Control/DeltaZ"), + track.template 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.template 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()); + if constexpr (std::is_same_v>) { + registry.fill(HIST("Tracks/Control/DCAZ"), retrack.bestDCAZ()); + } + 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.template collision_as().posZ(), z); + registry.fill(HIST("Tracks/Control/amb/DCAxy_amb"), retrack.bestDCAXY()); + if constexpr (std::is_same_v>) { + registry.fill(HIST("Tracks/Control/amb/DCAz_amb"), retrack.bestDCAZ()); + } + 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.template collision_as().posZ(), z); + registry.fill(HIST("Tracks/Control/nonamb/DCAxy_nonamb"), retrack.bestDCAXY()); + if constexpr (std::is_same_v>) { + registry.fill(HIST("Tracks/Control/nonamb/DCAz_nonamb"), retrack.bestDCAZ()); + } + 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.template collision_as().posZ(), z); + registry.fill(HIST("Tracks/Control/TrackCount"), 9); // without orphan + registry.fill(HIST("Tracks/Control/woOrp/DCAxy_woOrp"), retrack.bestDCAXY()); + if constexpr (std::is_same_v>) { + registry.fill(HIST("Tracks/Control/woOrp/DCAz_woOrp"), retrack.bestDCAZ()); + } + } + } + } + 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"), 7); + } + } + + void processMultReassoc(CollwEv::iterator const& collision, + o2::aod::MFTTracks const& mft, + soa::SmallGroups const& retracks, + FiCentralTracks const& midtracks, aod::Tracks const& trk) + { + processMultReassocCommon(collision, mft, retracks, midtracks, trk); + } + + void processMultReassoc3d(CollwEv::iterator const& collision, + o2::aod::MFTTracks const& mft, + soa::SmallGroups const& retracks, + FiCentralTracks const& midtracks, aod::Tracks const& trk) + { + processMultReassocCommon(collision, mft, retracks, midtracks, trk); + } + PROCESS_SWITCH(PseudorapidityDensityMFT, processMultReassoc, + "Process reco or data info", false); + + PROCESS_SWITCH(PseudorapidityDensityMFT, processMultReassoc3d, + "Process reco or data info (3d)", 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 (const auto& track : tracks) { + + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + + if (usePhiCut) { + if ((phi < cfgPhiCut) || + ((phi > o2::constants::math::PI - cfgPhiCut) && (phi < o2::constants::math::PI + cfgPhiCut)) || + (phi > o2::constants::math::TwoPI - cfgPhiCut) || + ((phi > ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::PI) - cfgPhiCut) && + (phi < ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::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 (const 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 (const auto& particle : perCollisionMCSample) { + 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 (const auto& collision : collisions) { + registry.fill(HIST("EventEfficiency"), 3.); + if (!disableITSROFCut && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + if (!useEvSel || (useEvSel && collision.selection_bit(aod::evsel::kIsTriggerTVX) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder) && collision.selection_bit(aod::evsel::kNoSameBunchPileup))) { + 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 (const 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; + } + float phi = particle.phi(); + o2::math_utils::bringTo02Pi(phi); + if (usePhiCut) { + if ((phi <= 0.02) || ((phi >= 3.10) && (phi <= 3.23)) || (phi >= 6.21)) + continue; + } + if (cfgnEta1 < particle.eta() && particle.eta() < cfgnEta2 && (phi > cfgPhiCut1 && phi < cfgPhiCut2)) { + // Purity numerator reference at generator level: physical primaries in the same eta window + if (particle.isPhysicalPrimary()) { + registry.fill(HIST("Purity/Gen/PrimaryEta"), particle.eta()); + // Truth-side total counters for primaries in acceptance (for purity calculations) + registry.fill(HIST("Purity/Gen/All"), 1.); + registry.fill(HIST("Purity/Gen/AllEta"), particle.eta()); + } + 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 (const 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 (const 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 (const 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 (const 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/flattenictyPikp.cxx b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx new file mode 100644 index 00000000000..d5bec464235 --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx @@ -0,0 +1,2404 @@ +// 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 flattenictyPikp.cxx +/// \author Gyula Bencedi, gyula.bencedi@cern.ch +/// \brief Task to produce pion, kaon, proton high-pT +/// distributions as a function of charged-particle flattenicity +/// \since 26 June 2025 + +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/MathConstants.h" +#include "DataFormatsFIT/Triggers.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include +#include + +#include "TEfficiency.h" +#include "THashList.h" +#include "TPDGCode.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::string; +using namespace o2; +using namespace o2::framework; +using namespace o2::constants::math; + +auto static constexpr CminCharge = 3.f; +static constexpr float Cnull = 0.0f; +static constexpr float Cone = 1.0f; + +// FV0 specific constants +static constexpr int CmaxRingsFV0 = 5; +static constexpr int CnCellsFV0 = 48; +static constexpr int CinnerFV0 = 32; +static constexpr float Cfv0IndexPhi[5] = {0., 8., 16., 24., 32.}; +static constexpr float CmaxEtaFV0 = 5.1; +static constexpr float CminEtaFV0 = 2.2; +static constexpr float CdEtaFV0 = (CmaxEtaFV0 - CminEtaFV0) / CmaxRingsFV0; +// PID names +static constexpr int CprocessIdWeak = 4; +static constexpr int Ncharges = 2; +static constexpr o2::track::PID::ID Npart = 5; +static constexpr o2::track::PID::ID NpartChrg = Npart * Ncharges; +static constexpr int PDGs[] = {11, 13, 211, 321, 2212}; +static constexpr int PidSgn[NpartChrg] = {11, 13, 211, 321, 2212, -11, -13, -211, -321, -2212}; +static constexpr const char* Pid[Npart] = {"el", "mu", "pi", "ka", "pr"}; +static constexpr const char* PidChrg[NpartChrg] = {"e^{-}", "#mu^{-}", "#pi^{+}", "K^{+}", "p", "e^{+}", "#mu^{+}", "#pi^{-}", "K^{-}", "#bar{p}"}; +static constexpr std::string_view Cspecies[NpartChrg] = {"Elminus", "Muplus", "PiPlus", "KaPlus", "Pr", "ElPlus", "MuMinus", "PiMinus", "KaMinus", "PrBar"}; +static constexpr std::string_view CspeciesAll[Npart] = {"El", "Mu", "Pi", "Ka", "Pr"}; +// histogram naming +static constexpr std::string_view Ccharge[] = {"all/", "pos/", "neg/"}; +static constexpr std::string_view Cprefix = "Tracks/"; +static constexpr std::string_view CprefixCleanTof = "Tracks/CleanTof/"; +static constexpr std::string_view CprefixCleanV0 = "Tracks/CleanV0/"; +static constexpr std::string_view Cstatus[] = {"preSel/", "postSel/"}; +static constexpr std::string_view CstatCalib[] = {"preCalib/", "postCalib/"}; +static constexpr std::string_view CpTgenPrimSgn = "/hPtGenPrimSgn"; +static constexpr std::string_view CpTgenPrimSgnF = "Tracks/{}/hPtGenPrimSgn"; +static constexpr std::string_view CpTgenPrimSgnINEL = "/hPtGenPrimSgnINEL"; +static constexpr std::string_view CpTgenPrimSgnINELF = "Tracks/{}/hPtGenPrimSgnINEL"; +static constexpr std::string_view CpTrecCollPrimSgn = "/hPtRecCollPrimSgn"; +static constexpr std::string_view CpTrecCollPrimSgnF = "Tracks/{}/hPtRecCollPrimSgn"; +static constexpr std::string_view CpTrecCollPrimSgnINEL = "/hPtRecCollPrimSgnINEL"; +static constexpr std::string_view CpTrecCollPrimSgnINELF = "Tracks/{}/hPtRecCollPrimSgnINEL"; +static constexpr std::string_view CpTGenRecCollPrimSgn = "/hPtGenRecCollPrimSgn"; +static constexpr std::string_view CpTGenRecCollPrimSgnF = "Tracks/{}/hPtGenRecCollPrimSgn"; +static constexpr std::string_view CpTGenRecCollPrimSgnINEL = "/hPtGenRecCollPrimSgnINEL"; +static constexpr std::string_view CpTGenRecCollPrimSgnINELF = "Tracks/{}/hPtGenRecCollPrimSgnINEL"; +static constexpr std::string_view CpTmcClosurePrim = "/hPtMCclosurePrim"; +static constexpr std::string_view CpTmcClosurePrimF = "Tracks/{}/hPtMCclosurePrim"; + +enum V0sSel { + kNaN = -1, + kGa = 0, + kKz = 1, + kLam = 2, + kaLam = 3 +}; + +enum FillType { + kBefore, + kAfter +}; + +enum ChargeType { + kAll, + kPos, + kNeg +}; + +enum TrkSel { + trkSelAll, + trkSelEta, + trkSelPt, + trkSelDCA, + trkNRowsTPC, + trkSelNClsFound, + trkSelNClsPID, + trkSelTPCBndr, + nTrkSel +}; + +enum V0Sel { + v0SelAll, + v0SelEta, + v0SelDaughters, + v0SelTPCnClsFound, + v0SelTPCnClsPID, + v0SelRejectV0sAtTPCSector, + v0SelRejectSameSign, + v0SelDCAv0daughter, + v0SelCosPA, + v0SelV0radius, + v0SelDCAposToPV, + nV0Sel +}; + +enum EvtSel { + evtSelAll, + evtSelSel8, + evtSelNoITSROFrameBorder, + evtSelkNoTimeFrameBorder, + evtSelkNoSameBunchPileup, + evtSelkIsGoodZvtxFT0vsPV, + evtSelkIsVertexITSTPC, + evtSelkIsVertexTOFmatched, + evtSelVtxZ, + evtSelINELgt0, + nEvtSel +}; + +struct MultE { + static constexpr int CnoMult = 0; + static constexpr int CmultFT0M = 1; + static constexpr int CmultTPC = 2; +}; + +std::array rhoLatticeFV0{0}; +std::array fv0AmplitudeWoCalib{0}; + +std::array, NpartChrg> hPtEffRecPrim{}; +std::array, NpartChrg> hPtEffRecWeak{}; +std::array, NpartChrg> hPtEffRecMat{}; +std::array, NpartChrg> hPtEffRec{}; +std::array, NpartChrg> hPtEffGen{}; +std::array, NpartChrg> hPtGenRecEvt{}; +std::array, NpartChrg> hPtGenPrimRecEvt{}; +std::array, NpartChrg> hPtEffGenPrim{}; +std::array, NpartChrg> hPtEffGenWeak{}; +std::array, NpartChrg> hPtEffGenMat{}; +std::array, NpartChrg> hPtVsDCAxyPrim{}; +std::array, NpartChrg> hPtVsDCAxyWeak{}; +std::array, NpartChrg> hPtVsDCAxyMat{}; +std::array, NpartChrg> hDCAxyBadCollPrim{}; +std::array, NpartChrg> hDCAxyBadCollWeak{}; +std::array, NpartChrg> hDCAxyBadCollMat{}; +std::array, NpartChrg> hPtNsigmaTPC{}; +std::array, NpartChrg> hThPtNsigmaTPC{}; +std::array, NpartChrg> hPtNsigmaTOF{}; +std::array, NpartChrg> hPtNsigmaTPCTOF{}; + +struct FlattenictyPikp { + + HistogramRegistry flatchrg{"flatchrg", {}, OutputObjHandlingPolicy::AnalysisObject, true, false}; + OutputObj listEfficiency{"Efficiency"}; + Service pdg; + + std::vector fv0AmplCorr{}; + TProfile2D* zVtxMap = nullptr; + float magField; + int runNumber{-1}; + o2::parameters::GRPMagField* grpmag = nullptr; + + Configurable multEst{"multEst", 1, "0: without multiplicity; 1: MultFT0M; 2: MultTPC"}; + Configurable applyCalibGain{"applyCalibGain", false, "equalize detector amplitudes"}; + Configurable applyCalibVtx{"applyCalibVtx", false, "equalize Amp vs vtx"}; + Configurable applyCalibDeDx{"applyCalibDeDx", false, "calibration of dedx signal"}; + Configurable applyCalibDeDxFromCCDB{"applyCalibDeDxFromCCDB", false, "use CCDB-based calibration of dedx signal"}; + Configurable cfgFillTrackQaHist{"cfgFillTrackQaHist", false, "fill track QA histograms"}; + Configurable cfgFilldEdxCalibHist{"cfgFilldEdxCalibHist", false, "fill dEdx calibration histograms"}; + Configurable cfgFilldEdxQaHist{"cfgFilldEdxQaHist", false, "fill dEdx QA histograms"}; + Configurable cfgFillNsigmaQAHist{"cfgFillNsigmaQAHist", false, "fill nsigma QA histograms"}; + Configurable cfgFillV0Hist{"cfgFillV0Hist", false, "fill V0 histograms"}; + Configurable cfgFillChrgType{"cfgFillChrgType", false, "fill histograms per charge types"}; + Configurable cfgFillChrgTypeV0s{"cfgFillChrgTypeV0s", false, "fill V0s histograms per charge types"}; + Configurable> paramsFuncMIPpos{"paramsFuncMIPpos", std::vector{-1.f}, "parameters of pol2"}; + Configurable> paramsFuncMIPneg{"paramsFuncMIPneg", std::vector{-1.f}, "parameters of pol2"}; + Configurable> paramsFuncMIPall{"paramsFuncMIPall", std::vector{-1.f}, "parameters of pol2"}; + Configurable> paramsFuncPlateaUpos{"paramsFuncPlateaUpos", std::vector{-1.f}, "parameters of pol2"}; + Configurable> paramsFuncPlateaUneg{"paramsFuncPlateaUneg", std::vector{-1.f}, "parameters of pol2"}; + Configurable> paramsFuncPlateaUall{"paramsFuncPlateaUall", std::vector{-1.f}, "parameters of pol2"}; + Configurable cfgGainEqCcdbPath{"cfgGainEqCcdbPath", "Users/g/gbencedi/flattenicity/GainEq", "CCDB path for gain equalization constants"}; + Configurable cfgVtxEqCcdbPath{"cfgVtxEqCcdbPath", "Users/g/gbencedi/flattenicity/ZvtxEq", "CCDB path for z-vertex equalization constants"}; + Configurable cfgDeDxCalibCcdbPath{"cfgDeDxCalibCcdbPath", "Users/g/gbencedi/flattenicity/dEdxCalib", "CCDB path for dEdx calibration"}; + Configurable cfgUseCcdbForRun{"cfgUseCcdbForRun", true, "Get ccdb object based on run number instead of timestamp"}; + Configurable cfgStoreThnSparse{"cfgStoreThnSparse", false, "Store histograms as THnSparse"}; + + struct : ConfigurableGroup { + Configurable cfgCustomTVX{"cfgCustomTVX", false, "Ask for custom TVX instead of sel8"}; + Configurable cfgRemoveNoTimeFrameBorder{"cfgRemoveNoTimeFrameBorder", true, "Bunch crossing is far from Time Frame borders"}; + Configurable cfgRemoveITSROFrameBorder{"cfgRemoveITSROFrameBorder", true, "Bunch crossing is far from ITS RO Frame border"}; + Configurable cfgCutVtxZ{"cfgCutVtxZ", 10.0f, "Accepted z-vertex range"}; + Configurable cfgINELCut{"cfgINELCut", true, "INEL event selection"}; + Configurable cfgRemoveNoSameBunchPileup{"cfgRemoveNoSameBunchPileup", false, "Reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable cfgRequireIsGoodZvtxFT0vsPV{"cfgRequireIsGoodZvtxFT0vsPV", false, "Small difference between z-vertex from PV and from FT0"}; + Configurable cfgRequireIsVertexITSTPC{"cfgRequireIsVertexITSTPC", false, "At least one ITS-TPC track (reject vertices built from ITS-only tracks)"}; + Configurable cfgRequirekIsVertexTOFmatched{"cfgRequirekIsVertexTOFmatched", false, "Require kIsVertexTOFmatched: at least one of vertex contributors is matched to TOF"}; + } evtSelOpt; + + struct : ConfigurableGroup { + Configurable useFlatData{"useFlatData", true, "use flattenicity from rec collisions"}; + } flatSelOpt; + + struct : ConfigurableGroup { + ConfigurableAxis axisPt{"axisPt", {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}, "pT binning"}; + ConfigurableAxis axisPtV0s{"axisPtV0s", {VARIABLE_WIDTH, 0, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.2, 1.4, 1.6, 1.8, 2, 2.5, 3.0, 3.5, 4, 5, 7, 9, 12, 15, 20}, "pT V0s binning"}; + ConfigurableAxis axisFlatPerc{"axisFlatPerc", {102, -0.01, 1.01}, "Flattenicity percentiles binning"}; + ConfigurableAxis axisMultPerc{"axisMultPerc", {20, 0, 100}, "Multiplicity percentiles binning"}; + ConfigurableAxis axisVertexZ{"axisVertexZ", {80, -20., 20.}, "Vertex z binning"}; + ConfigurableAxis axisMult{"axisMult", {301, -0.5, 300.5}, "Multiplicity binning"}; + ConfigurableAxis axisDCAxy{"axisDCAxy", {200, -5, 5}, "DCAxy binning"}; + ConfigurableAxis axisDCAz{"axisDCAz", {200, -5, 5}, "DCAz binning"}; + ConfigurableAxis axisPhi = {"axisPhi", {60, 0, constants::math::TwoPI}, "#varphi binning"}; + ConfigurableAxis axisPhiMod = {"axisPhiMod", {100, 0, constants::math::PI / 9}, "fmod(#varphi,#pi/9)"}; + ConfigurableAxis axisEta = {"axisEta", {50, -1.0, 1.0}, "#eta binning"}; + ConfigurableAxis axisRapidity = {"axisRapidity", {50, -1.0, 1.0}, "#it{y} binning"}; + ConfigurableAxis axisDedx{"axisDedx", {100, 0, 100}, "dE/dx binning"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {200, -10, 10}, "nsigmaTPC binning"}; + ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {200, -10, 10}, "nsigmaTOF binning"}; + ConfigurableAxis axisAmplFV0{"axisAmplFV0", {4096, 0, 4096}, "FV0 amplitude (ADC) binning"}; + ConfigurableAxis axisAmplFV0Sum{"axisAmplFV0Sum", {4096, 0, 4096 * 49}, "FV0 amplitude sum (ADC) binning"}; + ConfigurableAxis axisChannelFV0{"axisChannelFV0", {49, 0., 49.}, "FV0 channel ID binning"}; + } binOpt; + + struct : ConfigurableGroup { + Configurable cfgTrkEtaMax{"cfgTrkEtaMax", 0.8f, "Eta range for tracks"}; + Configurable cfgRapMax{"cfgRapMax", 0.5f, "Maximum range of rapidity for tracks"}; + Configurable cfgTrkPtMin{"cfgTrkPtMin", 0.15f, "Minimum pT of tracks"}; + Configurable cfgNclTPCMin{"cfgNclTPCMin", 80.0f, "Minimum of number of TPC found clusters"}; + Configurable cfgApplyNclPID{"cfgApplyNclPID", true, "Apply cut on TPC PID clusters"}; + Configurable cfgNclPidTPCMin{"cfgNclPidTPCMin", 130.0f, "Minimum of number of TPC PID clusters"}; + Configurable cfgPhiCutPtMin{"cfgPhiCutPtMin", 2.0f, "Minimum pT for phi cut"}; + Configurable cfgTOFBetaPion{"cfgTOFBetaPion", 1.0f, "Minimum beta for TOF pions"}; + Configurable cfgTofBetaPiMax{"cfgTofBetaPiMax", 5E-5, "Maximum beta for TOF pion selection"}; + Configurable cfgRejectTrkAtTPCSector{"cfgRejectTrkAtTPCSector", true, "Reject tracks close to the TPC sector boundaries"}; + Configurable cfgGeoTrkCutMin{"cfgGeoTrkCutMin", "0.06/x+pi/18.0-0.06", "ROOT TF1 formula for minimum phi cut in TPC"}; + Configurable cfgGeoTrkCutMax{"cfgGeoTrkCutMax", "0.1/x+pi/18.0+0.06", "ROOT TF1 formula for maximum phi cut in TPC"}; + Configurable cfgMomMIPMax{"cfgMomMIPMax", 0.6f, "Maximum momentum of MIP pions"}; + Configurable cfgMomMIPMin{"cfgMomMIPMin", 0.4f, "Minimum momentum of MIP pions"}; + Configurable cfgDeDxMIPMax{"cfgDeDxMIPMax", 60.0f, "Maximum range of MIP dedx"}; + Configurable cfgDeDxMIPMin{"cfgDeDxMIPMin", 40.0f, "Maximum range of MIP dedx"}; + Configurable cfgNsigmaMax{"cfgNsigmaMax", 100.0f, "Maximum range of nsgima for tracks"}; + Configurable cfgMomSelPiTOF{"cfgMomSelPiTOF", 0.4f, "Minimum momentum cut for TOF pions"}; + Configurable cfgNsigSelKaTOF{"cfgNsigSelKaTOF", 3.0f, "Nsigma cut for TOF kaons"}; + Configurable cfgBetaPlateuMax{"cfgBetaPlateuMax", 0.1f, "Beta max for Plateau electrons"}; + } trkSelOpt; + + struct : ConfigurableGroup { + // common selection + Configurable cfgV0TypeSel{"cfgV0TypeSel", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + Configurable cfgV0Ymax{"cfgV0Ymax", 0.5f, "Maximum rapidity of V0s"}; + Configurable cfgRejectV0sAtTPCSector{"cfgRejectV0sAtTPCSector", true, "Reject V0s close to the TPC sector boundaries"}; + Configurable cfgNsigmaElTPC{"cfgNsigmaElTPC", 5.0, "max nsigma of TPC for electorn"}; + Configurable cfgNsigmaPiTPC{"cfgNsigmaPiTPC", 5.0, "max nsigma of TPC for pion"}; + Configurable cfgNsigmaPrTPC{"cfgNsigmaPrTPC", 5.0, "max nsigma of TPC for proton"}; + Configurable cfgNsigmaElTOF{"cfgNsigmaElTOF", 3.0, "max nsigma of TOF for electorn"}; + Configurable cfgNsigmaPiTOF{"cfgNsigmaPiTOF", 3.0, "max nsigma of TOF for pion"}; + Configurable cfgNsigmaPrTOF{"cfgNsigmaPrTOF", 3.0, "max nsigma of TOF for proton"}; + ConfigurableAxis axisArmPodAlpha{"axisArmPodAlpha", {200, -1.0, 1.0}, "Armenteros-Podolanski alpha"}; + ConfigurableAxis axisArmPodqT{"axisArmPodqT", {600, 0.0f, 0.3f}, "Armenteros-Podolanski qT"}; + // standad parameters for V0 selection + Configurable cfgV0etamax{"cfgV0etamax", 0.8f, "max eta of V0s"}; + Configurable cfgTPCnClsmin{"cfgTPCnClsmin", 80.0f, "Minimum of number of TPC found clusters"}; + Configurable cfgApplyV0sNclPID{"cfgApplyV0sNclPID", true, "Apply cut on TPC PID clusters"}; + Configurable cfgTPCnClsPidmin{"cfgTPCnClsPidmin", 130.0f, "Minimum of number of TPC PID clusters"}; + Configurable cfgDCAv0daughter{"cfgDCAv0daughter", 1.0, "max DCA of V0 daughter tracks (cm)"}; + Configurable cfgv0cospa{"cfgv0cospa", 0.995, "min V0 CosPA"}; + Configurable cfgDCAposToPV{"cfgDCAposToPV", 0.05f, "min DCA Pos To PV (cm)"}; + Configurable cfgDCAnegToPV{"cfgDCAnegToPV", 0.05f, "min DCA Neg To PV (cm)"}; + Configurable cfgv0Rmin{"cfgv0Rmin", 1.2, "min V0 radius (cm)"}; + Configurable cfgv0Rmax{"cfgv0Rmax", 1E5, "max V0 radius (cm)"}; + // parameters for selection KOs + Configurable cfgcTauK0s{"cfgcTauK0s", 20, "v0ctau for K0s"}; + Configurable cfgCosPAK0s{"cfgCosPAK0s", 0.995, "V0 CosPA for K0s"}; + Configurable cfgV0radiusK0s{"cfgV0radiusK0s", 0.5, "v0radius for K0s"}; + Configurable cfgdmassK{"cfgdmassK", 0.005, "Competing Mass Rejection cut for K0s"}; + Configurable cfgArmPodK0s{"cfgArmPodK0s", 5.0f, "pT * (cut) > |alpha|, Armenteros-Podolanski cut for K0s"}; + ConfigurableAxis axisK0sMass{"axisK0sMass", {200, 0.4f, 0.6f}, "K0Short mass binning"}; + // parameters for selection Lambda / antiLambda + Configurable cfgcTauLambda{"cfgcTauLambda", 30, "v0ctau for Lambda"}; + Configurable cfgCosPALambda{"cfgCosPALambda", 0.995, "V0 CosPA for Lambda"}; + Configurable cfgV0radiusLambda{"cfgV0radiusLambda", 0.5, "v0radius for Lambda"}; + Configurable cfgdmassL{"cfgdmassL", 0.01f, "Competing Mass Rejection cut for Lambda"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, "Lambda mass binning"}; + // parameters for selection Gamma + Configurable cfgdmassG{"cfgdmassG", 0.1f, "max mass for Gammas"}; + Configurable cfgArmPodGammasalpha{"cfgArmPodGammasalpha", 0.45f, "Armenteros-Podolanski alpha cut for Gammas"}; + Configurable cfgArmPodGammasqT{"cfgArmPodGammasqT", 0.01f, "Armenteros-Podolanski qT cut for Gammas"}; + ConfigurableAxis axisGammaMass{"axisGammaMass", {200, 0.0f, 0.5f}, "Gamma mass binning"}; + Configurable cfgdEdxPlateauSel{"cfgdEdxPlateauSel", 5, "dEdx selection sensitivity for electrons"}; + } v0SelOpt; + + Service ccdb; + struct : ConfigurableGroup { + Configurable cfgMagField{"cfgMagField", 99999, "Configurable magnetic field;default CCDB will be queried"}; + 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"}; + } ccdbConf; + + struct DeDxCalib { + TList* lCalibObjects = nullptr; + TH1F* hMIPcalibPos = nullptr; + TH1F* hMIPcalibNeg = nullptr; + TH1F* hMIPcalibAll = nullptr; + TH1F* hPlateauCalibPos = nullptr; + TH1F* hPlateauCalibNeg = nullptr; + TH1F* hPlateauCalibAll = nullptr; + bool lCalibLoaded = false; + } dedxcalib; + + TrackSelection selTrkGlobal; + Configurable isCustomTracks{"isCustomTracks", true, "Use custom track cuts"}; + Configurable requirePt{"requirePt", 0.15f, "Set minimum pT of tracks"}; + Configurable requireEta{"requireEta", 0.8f, "Set eta range of tracks"}; + Configurable setITSreq{"setITSreq", 2, "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 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 minITSnClusters{"minITSnClusters", 5, "minimum number of found ITS clusters"}; + Configurable maxDcaXYFactor{"maxDcaXYFactor", 1.f, "Multiplicative factor on the maximum value of the DCA xy"}; + Configurable maxDcaZ{"maxDcaZ", 2.f, "Additional cut on the maximum value of the DCA z"}; + Configurable minTPCNClsFound{"minTPCNClsFound", 70.0f, "Additional cut on the minimum value of the number of found clusters in the TPC"}; + + TrackSelection selTrkV0sDaughters; + TrackSelection selV0sDaugthers() + { + TrackSelection selTracks; + selTracks.SetEtaRange(-0.8f, 0.8f); + selTracks.SetMinNCrossedRowsTPC(minNCrossedRowsTPC.value); + selTracks.SetMaxChi2PerClusterTPC(maxChi2PerClusterTPC.value); + selTracks.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC.value); + return selTracks; + } + + TF1* fPhiCutLow = nullptr; + TF1* fPhiCutHigh = nullptr; + + std::vector> fDeDxVsEta; + std::vector> vecParamsMIP; + std::vector> fEDeDxVsEta; + std::vector> vecParamsPLA; + + void init(InitContext&) + { + auto vecParamsMIPpos = (std::vector)paramsFuncMIPpos; + auto vecParamsMIPneg = (std::vector)paramsFuncMIPneg; + auto vecParamsMIPall = (std::vector)paramsFuncMIPall; + auto vecParamsPLApos = (std::vector)paramsFuncPlateaUpos; + auto vecParamsPLAneg = (std::vector)paramsFuncPlateaUneg; + auto vecParamsPLAall = (std::vector)paramsFuncPlateaUall; + + auto addVec = [&](std::vector>& targetVec, const std::string& name, bool isMIP) { + if (isMIP) { + targetVec.emplace_back(vecParamsMIPpos); + targetVec.emplace_back(vecParamsMIPneg); + targetVec.emplace_back(vecParamsMIPall); + if (!vecParamsMIP.size()) { + LOG(info) << "size of " << name << "is zero."; + } + } else { + targetVec.emplace_back(vecParamsPLApos); + targetVec.emplace_back(vecParamsPLAneg); + targetVec.emplace_back(vecParamsPLAall); + if (!vecParamsPLA.size()) { + LOG(info) << "size of " << name << "is zero."; + } + } + }; + addVec(vecParamsMIP, "vecParamsMIP", true); + std::transform(std::begin(vecParamsMIP), std::end(vecParamsMIP), std::back_inserter(fDeDxVsEta), [&](auto const& params) { + return setFuncPars(params); + }); + addVec(vecParamsPLA, "vecParamsPLA", false); + std::transform(std::begin(vecParamsPLA), std::end(vecParamsPLA), std::back_inserter(fEDeDxVsEta), [&](auto const& params) { + return setFuncPars(params); + }); + + ccdb->setURL(ccdbConf.ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + ccdb->setFatalWhenNull(false); + + selTrkV0sDaughters = selV0sDaugthers(); + + if (isCustomTracks.value) { + selTrkGlobal = getGlobalTrackSelectionRun3ITSMatch(setITSreq.value); + selTrkGlobal.SetPtRange(requirePt.value, 1e10f); + selTrkGlobal.SetEtaRange(-requireEta.value, requireEta.value); + selTrkGlobal.SetRequireITSRefit(requireITS.value); + selTrkGlobal.SetRequireTPCRefit(requireTPC.value); + selTrkGlobal.SetRequireGoldenChi2(requireGoldenChi2.value); + selTrkGlobal.SetMaxChi2PerClusterTPC(maxChi2PerClusterTPC.value); + selTrkGlobal.SetMaxChi2PerClusterITS(maxChi2PerClusterITS.value); + selTrkGlobal.SetMinNClustersITS(minITSnClusters.value); + selTrkGlobal.SetMinNCrossedRowsTPC(minNCrossedRowsTPC.value); + selTrkGlobal.SetMinNClustersTPC(minTPCNClsFound.value); + selTrkGlobal.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC.value); + // // selTrkGlobal.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / pow(pt, 1.1f); }); + selTrkGlobal.SetMaxDcaXYPtDep([](float /*pt*/) { return 10000.f; }); + selTrkGlobal.SetMaxDcaZ(maxDcaZ.value); + selTrkGlobal.print(); + } + + const AxisSpec chargeAxis{2, -2.f, 2.f, "Charge"}; + const AxisSpec dEdxAxis{binOpt.axisDedx, "TPC dEdx (a.u.)"}; + const AxisSpec vtxzAxis{binOpt.axisVertexZ, "Z_{vtx} (cm)"}; + const AxisSpec flatAxis{binOpt.axisFlatPerc, "Flat FV0"}; + const AxisSpec etaAxis{binOpt.axisEta, "#eta"}; + const AxisSpec rapidityAxis{binOpt.axisRapidity, "#it{y}"}; + const AxisSpec phiAxis{binOpt.axisPhi, "#varphi"}; + const AxisSpec phiAxisMod{binOpt.axisPhiMod, "fmod(#varphi,#pi/9)"}; + const AxisSpec pAxis{binOpt.axisPt, "#it{p} (GeV/#it{c})"}; + const AxisSpec ptAxis{binOpt.axisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ptAxisV0s{binOpt.axisPtV0s, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec dcaXYAxis{binOpt.axisDCAxy, "DCA_{xy} (cm)"}; + const AxisSpec dcaZAxis{binOpt.axisDCAz, "DCA_{z} (cm)"}; + const AxisSpec shCluserAxis{200, 0, 1, "Fraction of shared TPC clusters"}; + const AxisSpec clTpcAxis{160, 0, 160, "Number of clusters in TPC"}; + const AxisSpec nSigmaTPCAxis{binOpt.axisNsigmaTPC, "n#sigma_{TPC}"}; + const AxisSpec nSigmaTOFAxis{binOpt.axisNsigmaTOF, "n#sigma_{TOF}"}; + const AxisSpec amplitudeFV0{binOpt.axisAmplFV0, "FV0 amplitude (ADC)"}; + const AxisSpec amplitudeFV0Sum{binOpt.axisAmplFV0Sum, "FV0 amplitude sm (ADC)"}; + const AxisSpec channelFV0Axis{binOpt.axisChannelFV0, "FV0 channel ID"}; + + AxisSpec multAxis{binOpt.axisMultPerc, "multiplicity estimator"}; + + switch (multEst) { + case MultE::CnoMult: + break; + case MultE::CmultFT0M: + multAxis.name = "multFT0M"; + break; + case MultE::CmultTPC: + multAxis.name = "multTPC"; + break; + default: + LOG(fatal) << "No valid option for mult estimator " << multEst; + } + + // Event counter + flatchrg.add("Events/hEvtSel", "Number of events; Cut; #Events Passed Cut", {kTH1F, {{nEvtSel + 1, 0, nEvtSel + 1}}}); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelAll + 1, "Events read"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelSel8 + 1, "Evt. sel8"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelNoITSROFrameBorder + 1, "NoITSROFrameBorder"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelkNoTimeFrameBorder + 1, "NoTimeFrameBorder"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelkNoSameBunchPileup + 1, "NoSameBunchPileup"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelkIsGoodZvtxFT0vsPV + 1, "IsGoodZvtxFT0vsPV"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelkIsVertexITSTPC + 1, "IsVertexITSTPC"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelkIsVertexTOFmatched + 1, "IsVertexTOFmatched"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelVtxZ + 1, "Vtx-z pos"); + flatchrg.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelINELgt0 + 1, "INEL>0"); + // Track counter + flatchrg.add("Tracks/hTrkSel", "Number of tracks; Cut; #Tracks Passed Cut", {kTH1F, {{nTrkSel + 1, 0, nTrkSel + 1}}}); + flatchrg.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelAll + 1, "All"); + flatchrg.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelEta + 1, "Eta"); + flatchrg.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPt + 1, "Pt"); + flatchrg.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelDCA + 1, "DCA"); + flatchrg.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkNRowsTPC + 1, "trkNRowsTPC"); + flatchrg.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsFound + 1, "NClsTPCFound"); + flatchrg.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsPID + 1, "NClsTPCPid"); + flatchrg.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelTPCBndr + 1, "TPC Boundary"); + // V0 counter + flatchrg.add("Tracks/V0qa/hV0Sel", "Number of V0s; Cut; #Tracks Passed Cut", {kTH1F, {{nV0Sel + 1, 0, nV0Sel + 1}}}); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelAll + 1, "All"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelEta + 1, "Eta"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDaughters + 1, "V0 daughters' sel."); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelTPCnClsFound + 1, "TPC nCls found"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelTPCnClsPID + 1, "TPC nCls PID"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelRejectV0sAtTPCSector + 1, "Reject V0s at TPC sector"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelRejectSameSign + 1, "Reject same sign"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDCAv0daughter + 1, "DCA v0 daughter"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelCosPA + 1, "Cos PA"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelV0radius + 1, "V0 radius"); + flatchrg.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDCAposToPV + 1, "DCA pos to PV"); + + if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector) { + fPhiCutLow = new TF1("fPhiCutLow", trkSelOpt.cfgGeoTrkCutMin.value.c_str(), 0, 100); + fPhiCutHigh = new TF1("fPhiCutHigh", trkSelOpt.cfgGeoTrkCutMax.value.c_str(), 0, 100); + } + + if (doprocessFlat) { + flatchrg.add("Events/hVtxZ", "Measured vertex z position", kTH1F, {vtxzAxis}); + flatchrg.add("Events/hFlatVsMultEst", "hFlatVsMultEst", kTH2F, {flatAxis, multAxis}); + flatchrg.add("Tracks/postSel/hPVsPtEta", "; #it{p} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c}); #eta;", {kTH3F, {pAxis, ptAxis, etaAxis}}); + if (cfgFillTrackQaHist || cfgFilldEdxQaHist || cfgFillNsigmaQAHist) { + if (cfgFillTrackQaHist) { + flatchrg.add("Tracks/postSel/hPtPhi", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9)", {kTH2F, {ptAxis, phiAxisMod}}); + flatchrg.add("Tracks/postSel/hPtVsWOcutDCA", "hPtVsWOcutDCA", kTH2F, {ptAxis, dcaXYAxis}); + flatchrg.add("Tracks/postSel/hPt", "", kTH1F, {ptAxis}); + flatchrg.add("Tracks/postSel/hPhi", "", kTH1F, {phiAxis}); + flatchrg.add("Tracks/postSel/hEta", "", kTH1F, {etaAxis}); + flatchrg.add("Tracks/postSel/hDCAXYvsPt", "", kTH2F, {ptAxis, dcaXYAxis}); + flatchrg.add("Tracks/postSel/hDCAZvsPt", "", kTH2F, {ptAxis, dcaZAxis}); + // tpc + if (cfgStoreThnSparse) { + flatchrg.add("Tracks/postSel/hPtPhiNclTPC", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{cluster}", {kTHnSparseF, {ptAxis, phiAxisMod, clTpcAxis}}); + flatchrg.add("Tracks/postSel/hPtPhiNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{PID cluster}", {kTHnSparseF, {ptAxis, phiAxisMod, clTpcAxis}}); + } else { + flatchrg.add("Tracks/postSel/hPtPhiNclTPC", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{cluster}", {kTH3F, {ptAxis, phiAxisMod, clTpcAxis}}); + flatchrg.add("Tracks/postSel/hPtPhiNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{PID cluster}", {kTH3F, {ptAxis, phiAxisMod, clTpcAxis}}); + } + flatchrg.add("Tracks/postSel/hPtNclTPC", "; #it{p}_{T} (GeV/#it{c}); N_{cluster}", {kTH2F, {ptAxis, clTpcAxis}}); + flatchrg.add("Tracks/postSel/pPtNclTPC", "; #it{p}_{T} (GeV/#it{c}); N_{cluster}", {kTProfile, {ptAxis}}); + flatchrg.add("Tracks/postSel/hPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTH2F, {ptAxis, clTpcAxis}}); + flatchrg.add("Tracks/postSel/pPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTProfile, {ptAxis}}); + flatchrg.add("Tracks/postSel/hShTpcClvsPt", "", {kTH2F, {ptAxis, shCluserAxis}}); + flatchrg.add("Tracks/postSel/hNclTPCFoundvsPt", "", {kTH2F, {ptAxis, clTpcAxis}}); + flatchrg.add("Tracks/postSel/hNClTPCPidvsPt", "", {kTH2F, {ptAxis, clTpcAxis}}); + flatchrg.add("Tracks/postSel/hTPCCluster", "N_{cluster}", kTH1F, {clTpcAxis}); + flatchrg.add("Tracks/postSel/hTPCnClsShared", " ; # shared TPC clusters TPC", kTH1F, {{165, -0.5, 164.5}}); + flatchrg.add("Tracks/postSel/hTPCcrossedRows", " ; # crossed TPC rows", kTH1F, {{165, -0.5, 164.5}}); + flatchrg.add("Tracks/postSel/hTPCcrossedRowsOverFindableCls", " ; crossed rows / findable TPC clusters", kTH1F, {{60, 0.7, 1.3}}); + // its + flatchrg.add("Tracks/postSel/hITSnCls", " ; # ITS clusters", kTH1F, {{8, -0.5, 7.5}}); + flatchrg.add("Tracks/postSel/hChi2ITSTrkSegment", "chi2ITS", kTH1F, {{100, -0.5, 99.5}}); + // tof + flatchrg.add("Tracks/postSel/hTOFPvsBeta", "Beta from TOF; #it{p} (GeV/#it{c}); #beta", {kTH2F, {pAxis, {120, 0.0, 1.2}}}); + if (cfgStoreThnSparse) { + flatchrg.add("Tracks/postSel/hTOFpi", "Primary Pions from TOF; #eta; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, pAxis, dEdxAxis}}); + } else { + flatchrg.add("Tracks/postSel/hTOFpi", "Primary Pions from TOF; #eta; #it{p} (GeV/#it{c}); dEdx", {kTH3F, {etaAxis, pAxis, dEdxAxis}}); + } + } + if (cfgFilldEdxQaHist) { + if (cfgStoreThnSparse) { + flatchrg.add("Tracks/postCalib/all/hMIP", "; mult; flat; #eta; #LT dE/dx #GT_{MIP, primary tracks};", {kTHnSparseF, {multAxis, flatAxis, etaAxis, dEdxAxis}}); + flatchrg.add("Tracks/postCalib/all/hPlateau", "; mult; flat; #eta; #LT dE/dx #GT_{Plateau, primary tracks};", {kTHnSparseF, {multAxis, flatAxis, etaAxis, dEdxAxis}}); + } else { + flatchrg.add("Tracks/postCalib/all/hMIP", "; #eta; #LT dE/dx #GT_{MIP, primary tracks};", {kTH2F, {etaAxis, dEdxAxis}}); + flatchrg.add("Tracks/postCalib/all/hPlateau", "; #eta; #LT dE/dx #GT_{Plateau, primary tracks};", {kTH2F, {etaAxis, dEdxAxis}}); + } + flatchrg.add("Tracks/postCalib/all/hMIPVsPhi", "; #varphi; #LT dE/dx #GT_{MIP, primary tracks};", {kTH2F, {phiAxis, dEdxAxis}}); + flatchrg.add("Tracks/postCalib/all/pMIPVsPhi", "; #varphi; #LT dE/dx #GT_{MIP, primary tracks};", {kTProfile, {phiAxis}}); + flatchrg.add("Tracks/postCalib/all/hMIPVsPhiVsEta", "; #varphi; #LT dE/dx #GT_{MIP, primary tracks}; #eta;", {kTH3F, {phiAxis, dEdxAxis, etaAxis}}); + flatchrg.add("Tracks/postCalib/all/hPlateauVsPhi", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks};", {kTH2F, {phiAxis, dEdxAxis}}); + flatchrg.add("Tracks/postCalib/all/pPlateauVsPhi", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks};", {kTProfile, {phiAxis}}); + flatchrg.add("Tracks/postCalib/all/hPlateauVsPhiVsEta", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks}; #eta;", {kTH3F, {phiAxis, dEdxAxis, etaAxis}}); + flatchrg.addClone("Tracks/postCalib/all/", "Tracks/preCalib/all/"); + if (cfgFillChrgType) { + flatchrg.addClone("Tracks/postCalib/all/", "Tracks/postCalib/pos/"); + flatchrg.addClone("Tracks/postCalib/all/", "Tracks/postCalib/neg/"); + flatchrg.addClone("Tracks/preCalib/all/", "Tracks/preCalib/pos/"); + flatchrg.addClone("Tracks/preCalib/all/", "Tracks/preCalib/neg/"); + } + } + if (cfgFillNsigmaQAHist) { + for (int i = 0; i < NpartChrg; i++) { + const std::string strID = Form("/%s/%s", (i < Npart) ? "pos" : "neg", Pid[i % Npart]); + if (cfgStoreThnSparse) { + hThPtNsigmaTPC[i] = flatchrg.add("Tracks/hThPtNsigmaTPC" + strID, " ; p_{T} (GeV/c)", kTHnSparseF, {ptAxis, nSigmaTPCAxis, multAxis, flatAxis}); + } else { + hPtNsigmaTPC[i] = flatchrg.add("Tracks/hPtNsigmaTPC" + strID, " ; p_{T} (GeV/c)", kTH2F, {ptAxis, nSigmaTPCAxis}); + } + hPtNsigmaTOF[i] = flatchrg.add("Tracks/hPtNsigmaTOF" + strID, " ; p_{T} (GeV/c)", kTH2F, {ptAxis, nSigmaTOFAxis}); + hPtNsigmaTPCTOF[i] = flatchrg.add("Tracks/hPtNsigmaTPCTOF" + strID, PidChrg[i], kTH2F, {nSigmaTPCAxis, nSigmaTOFAxis}); + } + } + } + flatchrg.addClone("Tracks/postSel/", "Tracks/preSel/"); + // FV0 QA + flatchrg.add("FV0/hFV0AmplWCalib", "", {kTH2F, {channelFV0Axis, amplitudeFV0}}); + flatchrg.add("FV0/hFV0AmplvsVtxzWoCalib", "", {kTH2F, {vtxzAxis, amplitudeFV0Sum}}); + flatchrg.add("FV0/hFV0AmplvsVtxzCalib", "", {kTH2F, {vtxzAxis, amplitudeFV0Sum}}); + flatchrg.add("FV0/hFV0amp", "", {kTH2F, {channelFV0Axis, amplitudeFV0}}); + flatchrg.add("FV0/pFV0amp", "", kTProfile, {channelFV0Axis}); + flatchrg.add("FV0/hFV0ampCorr", "", {kTH2F, {channelFV0Axis, amplitudeFV0}}); + // V0's QA + flatchrg.add("Tracks/V0qa/hV0Pt", "pT", kTH1F, {ptAxisV0s}); + flatchrg.add("Tracks/V0qa/hEtaVsRapK0s", ";#eta;#it{y};", kTH2F, {etaAxis, rapidityAxis}); + flatchrg.add("Tracks/V0qa/hEtaVsRapLam", ";#eta;#it{y};", kTH2F, {etaAxis, rapidityAxis}); + flatchrg.add("Tracks/V0qa/hEtaVsRapALam", ";#eta;#it{y};", kTH2F, {etaAxis, rapidityAxis}); + flatchrg.add("Tracks/V0qa/hEtaVsRapGamma", ";#eta;#it{y};", kTH2F, {etaAxis, rapidityAxis}); + flatchrg.add("Tracks/V0qa/hV0ArmPod", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); + flatchrg.add("Tracks/V0qa/hArmPodK0s", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); + flatchrg.add("Tracks/V0qa/hArmPodLam", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); + flatchrg.add("Tracks/V0qa/hArmPodALam", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); + flatchrg.add("Tracks/V0qa/hArmPodGamma", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); + flatchrg.add("Tracks/V0qa/hMassK0sVsPt", ";;Inv. Mass (GeV/#it{c}^{2});", kTH2F, {ptAxisV0s, v0SelOpt.axisK0sMass}); + flatchrg.add("Tracks/V0qa/hMassLamVsPt", ";;Inv. Mass (GeV/#it{c}^{2});", kTH2F, {ptAxisV0s, v0SelOpt.axisLambdaMass}); + flatchrg.add("Tracks/V0qa/hMassALamVsPt", ";;Inv. Mass (GeV/#it{c}^{2});", kTH2F, {ptAxisV0s, v0SelOpt.axisLambdaMass}); + flatchrg.add("Tracks/V0qa/hMassGammaVsPt", ";;Inv. Mass (GeV/#it{c}^{2});", kTH2F, {ptAxisV0s, v0SelOpt.axisGammaMass}); + flatchrg.add("Tracks/V0qa/hNsigmaPiFromK0s", ";#it{n#sigma};;", kTH2F, {ptAxisV0s, nSigmaTPCAxis}); + flatchrg.add("Tracks/V0qa/hNsigmaPiFromLam", ";#it{n#sigma};;", kTH2F, {ptAxisV0s, nSigmaTPCAxis}); + flatchrg.add("Tracks/V0qa/hNsigmaPrFromLam", ";#it{n#sigma};;", kTH2F, {ptAxisV0s, nSigmaTPCAxis}); + flatchrg.add("Tracks/V0qa/hNsigmaPiFromALam", ";#it{n#sigma};;", kTH2F, {ptAxisV0s, nSigmaTPCAxis}); + flatchrg.add("Tracks/V0qa/hNsigmaPrFromALam", ";#it{n#sigma};;", kTH2F, {ptAxisV0s, nSigmaTPCAxis}); + flatchrg.add("Tracks/V0qa/hNsigmaElFromGamma", ";#it{n#sigma};;", kTH2F, {ptAxisV0s, nSigmaTPCAxis}); + + // dEdx PID + flatchrg.add({"Tracks/all/hdEdx", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); + // Clean samples + if (cfgFillV0Hist) { + if (cfgStoreThnSparse) { + flatchrg.add({"Tracks/CleanTof/all/hPiTof", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); + flatchrg.add({"Tracks/CleanV0/pos/hEV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); + flatchrg.add({"Tracks/CleanV0/pos/hPiV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); + flatchrg.add({"Tracks/CleanV0/pos/hPV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); + } else { + flatchrg.add({"Tracks/CleanTof/all/hPiTof", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTH3F, {etaAxis, pAxis, dEdxAxis}}}); + flatchrg.add({"Tracks/CleanV0/pos/hEV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTH3F, {etaAxis, pAxis, dEdxAxis}}}); + flatchrg.add({"Tracks/CleanV0/pos/hPiV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTH3F, {etaAxis, pAxis, dEdxAxis}}}); + flatchrg.add({"Tracks/CleanV0/pos/hPV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTH3F, {etaAxis, pAxis, dEdxAxis}}}); + } + flatchrg.add("Tracks/CleanTof/all/hBetaVsP", ";Momentum (GeV/#it{c}); #beta", kTH2F, {{{ptAxisV0s}, {120, 0., 1.2}}}); + flatchrg.add("Tracks/CleanTof/all/hTofExpPi", ";Momentum (GeV/#it{c});#it{t}^{#pi}_{Exp}/#it{t}_{TOF}", kTH2F, {{{ptAxisV0s}, {100, 0.2, 1.2}}}); + flatchrg.addClone("Tracks/CleanV0/pos/", "Tracks/CleanV0/neg/"); + if (cfgFillChrgType) { + flatchrg.addClone("Tracks/CleanTof/all/", "Tracks/CleanTof/pos/"); + flatchrg.addClone("Tracks/CleanTof/all/", "Tracks/CleanTof/neg/"); + } + } + if (cfgFillChrgType) { + flatchrg.addClone("Tracks/all/", "Tracks/pos/"); + flatchrg.addClone("Tracks/all/", "Tracks/neg/"); + } + } + + if (doprocessMC) { + auto h = flatchrg.add("hEvtGenRec", "Generated and Reconstructed MC Collisions", kTH1F, {{3, 0.5, 3.5}}); + h->GetXaxis()->SetBinLabel(1, "Gen coll"); + h->GetXaxis()->SetBinLabel(2, "Rec coll"); + h->GetXaxis()->SetBinLabel(3, "INEL>0"); + + flatchrg.add("hEvtMcGenColls", "Number of events; Cut; #Events Passed Cut", {kTH1F, {{5, 0.5, 5.5}}}); + flatchrg.get(HIST("hEvtMcGenColls"))->GetXaxis()->SetBinLabel(1, "Gen. coll"); + flatchrg.get(HIST("hEvtMcGenColls"))->GetXaxis()->SetBinLabel(2, "At least 1 reco"); + flatchrg.get(HIST("hEvtMcGenColls"))->GetXaxis()->SetBinLabel(3, "Reco. coll."); + flatchrg.get(HIST("hEvtMcGenColls"))->GetXaxis()->SetBinLabel(4, "Reco. good coll."); + + flatchrg.add("Events/hVtxZRec", "MC Rec vertex z position", kTH1F, {vtxzAxis}); + flatchrg.add("Events/hVtxZGen", "Generated vertex z position", kTH1F, {vtxzAxis}); + + for (int i = 0; i < NpartChrg; i++) { + const std::string strID = Form("/%s/%s", (i < Npart) ? "pos" : "neg", Pid[i % Npart]); + hPtGenRecEvt[i] = flatchrg.add("Tracks/hPtGenRecEvt" + strID, " ; p_{T} (GeV/c)", kTH1F, {ptAxis}); + hPtGenPrimRecEvt[i] = flatchrg.add("Tracks/hPtGenPrimRecEvt" + strID, " ; p_{T} (GeV/c)", kTH1F, {ptAxis}); + hPtEffGenPrim[i] = flatchrg.add("Tracks/hPtEffGenPrim" + strID, " ; p_{T} (GeV/c)", kTH3F, {multAxis, flatAxis, ptAxis}); + hPtEffGenWeak[i] = flatchrg.add("Tracks/hPtEffGenWeak" + strID, " ; p_{T} (GeV/c)", kTH3F, {multAxis, flatAxis, ptAxis}); + hPtEffGenMat[i] = flatchrg.add("Tracks/hPtEffGenMat" + strID, " ; p_{T} (GeV/c)", kTH3F, {multAxis, flatAxis, ptAxis}); + hPtEffRecPrim[i] = flatchrg.add("Tracks/hPtEffRecPrim" + strID, " ; p_{T} (GeV/c)", kTH3F, {multAxis, flatAxis, ptAxis}); + hPtEffRecWeak[i] = flatchrg.add("Tracks/hPtEffRecWeak" + strID, " ; p_{T} (GeV/c)", kTH3F, {multAxis, flatAxis, ptAxis}); + hPtEffRecMat[i] = flatchrg.add("Tracks/hPtEffRecMat" + strID, " ; p_{T} (GeV/c)", kTH3F, {multAxis, flatAxis, ptAxis}); + hDCAxyBadCollPrim[i] = flatchrg.add("Tracks/hDCAxyBadCollPrim" + strID, " ; p_{T} (GeV/c)", kTH2F, {ptAxis, dcaXYAxis}); + hDCAxyBadCollWeak[i] = flatchrg.add("Tracks/hDCAxyBadCollWeak" + strID, " ; p_{T} (GeV/c)", kTH2F, {ptAxis, dcaXYAxis}); + hDCAxyBadCollMat[i] = flatchrg.add("Tracks/hDCAxyBadCollMat" + strID, " ; p_{T} (GeV/c)", kTH2F, {ptAxis, dcaXYAxis}); + hPtVsDCAxyPrim[i] = flatchrg.add("Tracks/hPtVsDCAxyPrim" + strID, " ; p_{T} (GeV/c)", kTH2F, {ptAxis, dcaXYAxis}); + hPtVsDCAxyWeak[i] = flatchrg.add("Tracks/hPtVsDCAxyWeak" + strID, " ; p_{T} (GeV/c)", kTH2F, {ptAxis, dcaXYAxis}); + hPtVsDCAxyMat[i] = flatchrg.add("Tracks/hPtVsDCAxyMat" + strID, " ; p_{T} (GeV/c)", kTH2F, {ptAxis, dcaXYAxis}); + } + + flatchrg.add({"hPtOut", " ; p_{T} (GeV/c)", {kTH1F, {ptAxis}}}); + flatchrg.add({"hPtOutPrim", " ; p_{T} (GeV/c)", {kTH1F, {ptAxis}}}); + flatchrg.add({"hPtOutNoEtaCut", " ; p_{T} (GeV/c)", {kTH1F, {ptAxis}}}); + flatchrg.add({"PtOutFakes", " ; p_{T} (GeV/c)", {kTH1F, {ptAxis}}}); + flatchrg.add("hPtVsDCAxyPrimAll", "hPtVsDCAxyPrimAll", kTH2F, {ptAxis, dcaXYAxis}); + flatchrg.add("hPtVsDCAxyWeakAll", "hPtVsDCAxyWeakAll", kTH2F, {ptAxis, dcaXYAxis}); + flatchrg.add("hPtVsDCAxyMatAll", "hPtVsDCAxyMatAll", kTH2F, {ptAxis, dcaXYAxis}); + flatchrg.add("hPtVsDCAxyAll", "hPtVsDCAxyAll", kTH2F, {ptAxis, dcaXYAxis}); + flatchrg.add({"ResponseGen", " ; N_{part}; F_{FV0};", {kTHnSparseF, {multAxis, flatAxis}}}); + flatchrg.add("h1flatencityFV0MCGen", "", kTH1F, {{102, -0.01, 1.01, "1-flatencityFV0"}}); + + // Hash list for efficiency + listEfficiency.setObject(new THashList); + static_for<0, 1>([&](auto pidSgn) { + bookMcHist(); + bookMcHist(); + bookMcHist(); + initEfficiency(); + initEfficiency(); + initEfficiency(); + }); + } + + if (doprocessMCclosure) { + for (int i = 0; i < Npart; i++) { + flatchrg.add({fmt::format(CpTmcClosurePrimF.data(), CspeciesAll[i]).c_str(), " ; p_{T} (GeV/c)", {kTH3F, {multAxis, flatAxis, ptAxis}}}); + } + } + + if (doprocessSgnLoss) { + flatchrg.add("hFlatMCGenRecColl", "hFlatMCGenRecColl", {kTH1F, {flatAxis}}); + flatchrg.add("hFlatMCGen", "hFlatMCGen", {kTH1F, {flatAxis}}); + // Event counter + flatchrg.add("hEvtMcGen", "hEvtMcGen", {kTH1F, {{4, 0.f, 4.f}}}); + flatchrg.get(HIST("hEvtMcGen"))->GetXaxis()->SetBinLabel(1, "all"); + flatchrg.get(HIST("hEvtMcGen"))->GetXaxis()->SetBinLabel(2, "z-vtx"); + flatchrg.get(HIST("hEvtMcGen"))->GetXaxis()->SetBinLabel(3, "INELgt0"); + flatchrg.add("hEvtMCRec", "hEvtMCRec", {kTH1F, {{4, 0.f, 4.f}}}); + flatchrg.get(HIST("hEvtMCRec"))->GetXaxis()->SetBinLabel(1, "all"); + flatchrg.get(HIST("hEvtMCRec"))->GetXaxis()->SetBinLabel(2, "evt sel"); + flatchrg.get(HIST("hEvtMCRec"))->GetXaxis()->SetBinLabel(3, "INELgt0"); + flatchrg.add("hEvtMcGenRecColl", "hEvtMcGenRecColl", {kTH1F, {{2, 0.f, 2.f}}}); + flatchrg.get(HIST("hEvtMcGenRecColl"))->GetXaxis()->SetBinLabel(1, "INEL"); + flatchrg.get(HIST("hEvtMcGenRecColl"))->GetXaxis()->SetBinLabel(2, "INELgt0"); + + flatchrg.add("hFlatGenINELgt0", "hFlatGenINELgt0", {kTH1F, {flatAxis}}); + + for (int i = 0; i < NpartChrg; ++i) { + flatchrg.add({fmt::format(CpTgenPrimSgnF.data(), Cspecies[i]).c_str(), " ; p_{T} (GeV/c)", {kTH3F, {multAxis, flatAxis, ptAxis}}}); + flatchrg.add({fmt::format(CpTgenPrimSgnINELF.data(), Cspecies[i]).c_str(), " ; p_{T} (GeV/c)", {kTH3F, {multAxis, flatAxis, ptAxis}}}); + flatchrg.add({fmt::format(CpTrecCollPrimSgnF.data(), Cspecies[i]).c_str(), " ; p_{T} (GeV/c)", {kTH3F, {multAxis, flatAxis, ptAxis}}}); + flatchrg.add({fmt::format(CpTrecCollPrimSgnINELF.data(), Cspecies[i]).c_str(), " ; p_{T} (GeV/c)", {kTH3F, {multAxis, flatAxis, ptAxis}}}); + flatchrg.add({fmt::format(CpTGenRecCollPrimSgnF.data(), Cspecies[i]).c_str(), " ; p_{T} (GeV/c)", {kTH3F, {multAxis, flatAxis, ptAxis}}}); + flatchrg.add({fmt::format(CpTGenRecCollPrimSgnINELF.data(), Cspecies[i]).c_str(), " ; p_{T} (GeV/c)", {kTH3F, {multAxis, flatAxis, ptAxis}}}); + } + } + + LOG(info) << "Size of the histograms:"; + flatchrg.print(); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + fv0AmplCorr.clear(); + fv0AmplCorr = {}; + std::string fullPathCalibGain; + std::string fullPathCalibVtx; + std::string fullPathCalibDeDxMip; + std::string fullPathCalibDeDxPlateau; + auto timestamp = bc.timestamp(); + auto runnumber = bc.runNumber(); + + if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector) { + grpmag = ccdb->getForRun(ccdbConf.grpmagPath, runnumber); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConf.grpmagPath << " of object GRPMagField and " << ccdbConf.grpPath << " of object GRPObject for run " << runnumber; + } + magField = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for run " << runnumber << " with magnetic field of " << magField << " kZG"; + } + if (applyCalibGain) { + fullPathCalibGain = cfgGainEqCcdbPath; + fullPathCalibGain += "/FV0"; + const auto* objfv0Gain = getForTsOrRun>(fullPathCalibGain, timestamp, runnumber); + if (!objfv0Gain) { + for (auto i{0u}; i < CnCellsFV0; i++) { + fv0AmplCorr.push_back(1.); + LOGF(warning, "Setting FV0 calibration object values to 1"); + } + } else { + fv0AmplCorr = *(objfv0Gain); + } + } + if (applyCalibVtx) { + fullPathCalibVtx = cfgVtxEqCcdbPath; + fullPathCalibVtx += "/FV0"; + zVtxMap = getForTsOrRun(fullPathCalibVtx, timestamp, runnumber); + } + + if (applyCalibDeDxFromCCDB) { + fullPathCalibDeDxMip = cfgDeDxCalibCcdbPath; + fullPathCalibDeDxMip += "/MIP"; + fullPathCalibDeDxPlateau = cfgDeDxCalibCcdbPath; + fullPathCalibDeDxPlateau += "/Plateau"; + if (!fullPathCalibDeDxMip.empty()) { + dedxcalib.lCalibObjects = getForTsOrRun(fullPathCalibDeDxMip, timestamp, runnumber); + if (dedxcalib.lCalibObjects) { + LOG(info) << "CCDB objects loaded successfully"; + dedxcalib.hMIPcalibPos = static_cast(dedxcalib.lCalibObjects->FindObject("hMIPcalibPos")); + dedxcalib.hMIPcalibNeg = static_cast(dedxcalib.lCalibObjects->FindObject("hMIPcalibNeg")); + dedxcalib.hMIPcalibAll = static_cast(dedxcalib.lCalibObjects->FindObject("hMIPcalibAll")); + dedxcalib.lCalibLoaded = true; + if (!dedxcalib.hMIPcalibPos || !dedxcalib.hMIPcalibNeg || !dedxcalib.hMIPcalibAll) { + LOGF(error, "Problem loading CCDB objects! Please check"); + dedxcalib.lCalibLoaded = false; + } + } else { + LOGF(fatal, "Could not load hMIPcalib from %s", fullPathCalibDeDxMip.c_str()); + dedxcalib.lCalibLoaded = false; + } + } + if (!fullPathCalibDeDxPlateau.empty()) { + dedxcalib.lCalibObjects = getForTsOrRun(fullPathCalibDeDxPlateau, timestamp, runnumber); + if (dedxcalib.lCalibObjects) { + LOG(info) << "CCDB objects loaded successfully"; + dedxcalib.hPlateauCalibPos = static_cast(dedxcalib.lCalibObjects->FindObject("hPlateauCalibPos")); + dedxcalib.hPlateauCalibNeg = static_cast(dedxcalib.lCalibObjects->FindObject("hPlateauCalibNeg")); + dedxcalib.hPlateauCalibAll = static_cast(dedxcalib.lCalibObjects->FindObject("hPlateauCalibAll")); + dedxcalib.lCalibLoaded = true; + if (!dedxcalib.hPlateauCalibPos || !dedxcalib.hPlateauCalibNeg || !dedxcalib.hPlateauCalibAll) { + LOGF(error, "Problem loading CCDB objects! Please check"); + dedxcalib.lCalibLoaded = false; + } + } else { + LOGF(fatal, "Could not load hPlateauCalib from %s", fullPathCalibDeDxPlateau.c_str()); + } + } + } + } + + using MyCollisions = soa::Join; + using Colls = soa::Join; + using CollsGen = soa::Join; + using MCColls = soa::Join; + using CollsGenSgn = soa::SmallGroups>; + using MyPIDTracks = soa::Join; + using MyLabeledTracks = soa::Join; + using MyFiltLabeledTracks = soa::Filtered; + using MyLabeledPIDTracks = soa::Join; + + template + std::unique_ptr setFuncPars(T const& vecPars) + { + std::unique_ptr fCalibFunc(new TF1("fCalibFunc", "pol2", -1., 1.)); + if (vecPars.size() >= 1) { + for (typename T::size_type i = 0; i < vecPars.size(); i++) { + fCalibFunc->SetParameter(i, vecPars[i]); + } + } + return fCalibFunc; + } + + template + bool isPID(const P& mcParticle) + { + static_assert(pidSgn == Cnull || pidSgn == 1); + static_assert(id > Cnull || id < Npart); + constexpr int Cidx = id + pidSgn * Npart; + return mcParticle.pdgCode() == PidSgn[Cidx]; + } + + template + bool selTPCtrack(T const& track) + { + return (track.hasTPC() && + track.passedTPCCrossedRowsOverNCls() && + track.passedTPCChi2NDF() && + track.passedTPCNCls() && + track.passedTPCCrossedRows() && + track.passedTPCRefit()); + } + + template + bool selTOFPi(T const& track) + { + if (track.hasTOF() && track.goodTOFMatch()) { + const float tTOF = track.tofSignal(); + const float trkLength = track.length(); + const float tExpPiTOF = track.tofExpSignalPi(tTOF); + if (track.p() >= trkSelOpt.cfgMomSelPiTOF && trkLength > Cnull && tTOF > Cnull) { + flatchrg.fill(HIST(CprefixCleanTof) + HIST(Ccharge[chrg]) + HIST("hTofExpPi"), track.p(), tExpPiTOF / tTOF); + if (std::abs((tExpPiTOF / tTOF) - Cone) < trkSelOpt.cfgTofBetaPiMax) { + flatchrg.fill(HIST(CprefixCleanTof) + HIST(Ccharge[chrg]) + HIST("hBetaVsP"), track.p(), track.beta()); + // if (std::abs(track.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC && std::abs(track.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + return true; + // } + } + } + } + return false; + } + + template + void fillNsigma(T const& tracks, C const& collision) + { + const float mult = getMult(collision); + const float flat = fillFlat(collision); + for (const auto& track : tracks) { + checkNsigma(track, mult, flat); + } + } + + template + void filldEdx(T const& tracks, V const& v0s, C const& collision, aod::BCsWithTimestamps const& /*bcs*/) + { + if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector || applyCalibGain || applyCalibVtx) { + auto bc = collision.template bc_as(); + int currentRun = bc.runNumber(); + if (runNumber != currentRun) { + initCCDB(bc); + runNumber = currentRun; + } + } + + const float mult = getMult(collision); + const float flat = fillFlat(collision); + flatchrg.fill(HIST("Events/hFlatVsMultEst"), flat, mult); + + for (const auto& track : tracks) { + float dEdx = track.tpcSignal(); + if (cfgFillTrackQaHist) { + fillTrackQA(track); + } + if (!isGoodTrack(track, magField)) { + continue; + } + if (cfgFillTrackQaHist) { + fillTrackQA(track); + } + if (cfgFilldEdxCalibHist && cfgFilldEdxQaHist) { + if (cfgFillChrgType) { + if (track.sign() * track.tpcInnerParam() > Cnull) { + filldEdxQA(track, collision, dEdx); + } else { + filldEdxQA(track, collision, dEdx); + } + } else { + filldEdxQA(track, collision, dEdx); + } + } + if (applyCalibDeDx) { + if (cfgFillChrgType) { + if (track.sign() * track.tpcInnerParam() > Cnull) { + if (applyCalibDeDxFromCCDB) { + dEdx *= (50.0 / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(track.eta()))); + } else { + dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + } + if (cfgFilldEdxQaHist) { + filldEdxQA(track, collision, dEdx); + } + } else { + if (applyCalibDeDxFromCCDB) { + dEdx *= (50.0 / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(track.eta()))); + } else { + dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + } + if (cfgFilldEdxQaHist) { + filldEdxQA(track, collision, dEdx); + } + } + } else { + if (applyCalibDeDxFromCCDB) { + dEdx *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(track.eta()))); + } else { + dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + } + if (cfgFilldEdxQaHist) { + filldEdxQA(track, collision, dEdx); + } + } + } + + // PID TPC dEdx + if (cfgFillChrgType) { + if (track.sign() * track.tpcInnerParam() > Cnull) { + flatchrg.fill(HIST(Cprefix) + HIST(Ccharge[kPos]) + HIST("hdEdx"), track.eta(), mult, flat, track.tpcInnerParam(), dEdx); + } else { + flatchrg.fill(HIST(Cprefix) + HIST(Ccharge[kNeg]) + HIST("hdEdx"), track.eta(), mult, flat, track.tpcInnerParam(), dEdx); + } + } else { + flatchrg.fill(HIST(Cprefix) + HIST(Ccharge[kAll]) + HIST("hdEdx"), track.eta(), mult, flat, track.tpcInnerParam(), dEdx); + } + + // TOF pions + if (cfgFillV0Hist) { + if (selTOFPi(track)) { + if (cfgFillChrgType) { + if (track.sign() * track.tpcInnerParam() > Cnull) { + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kPos]) + HIST("hPiTof"), track.eta(), mult, flat, track.tpcInnerParam(), dEdx); + } else { + flatchrg.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kPos]) + HIST("hPiTof"), track.eta(), track.tpcInnerParam(), dEdx); + } + } else { + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kNeg]) + HIST("hPiTof"), track.eta(), mult, flat, track.tpcInnerParam(), dEdx); + } else { + flatchrg.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kNeg]) + HIST("hPiTof"), track.eta(), track.tpcInnerParam(), dEdx); + } + } + } else { + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kAll]) + HIST("hPiTof"), track.eta(), mult, flat, track.tpcInnerParam(), dEdx); + } else { + flatchrg.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kAll]) + HIST("hPiTof"), track.eta(), track.tpcInnerParam(), dEdx); + } + } + } + } + } + + // V0s + if (cfgFillV0Hist) { + for (const auto& v0 : v0s) { + if (v0.v0Type() != v0SelOpt.cfgV0TypeSel && v0SelOpt.cfgV0TypeSel > -1) { + continue; + } + if (!isGoodV0Track(v0, tracks, magField)) { + continue; + } + + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + float dEdxPos = posTrack.tpcSignal(); + float dEdxNeg = negTrack.tpcSignal(); + + if (applyCalibDeDx) { + if (cfgFillChrgTypeV0s) { + if (applyCalibDeDxFromCCDB) { + dEdxPos *= (50.0 / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(posTrack.eta()))); + dEdxNeg *= (50.0 / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(negTrack.eta()))); + } else { + dEdxPos *= (50.0 / getCalibration(fDeDxVsEta, posTrack)); + dEdxNeg *= (50.0 / getCalibration(fDeDxVsEta, negTrack)); + } + } else { + if (applyCalibDeDxFromCCDB) { + dEdxPos *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(posTrack.eta()))); + dEdxNeg *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(negTrack.eta()))); + } else { + dEdxPos *= (50.0 / getCalibration(fDeDxVsEta, posTrack)); + dEdxNeg *= (50.0 / getCalibration(fDeDxVsEta, negTrack)); + } + } + } + + if (selectTypeV0s(collision, v0, posTrack, negTrack) == kGa) { // Gamma selection + if (applyCalibDeDx) { + if (cfgFillChrgTypeV0s) { + if (applyCalibDeDxFromCCDB) { + const float dEdxPosGa = dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(posTrack.eta())); + const float dEdxNegGa = dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(negTrack.eta())); + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + continue; + } + } else { + const float dEdxPosGa = getCalibration(fEDeDxVsEta, posTrack); + const float dEdxNegGa = getCalibration(fEDeDxVsEta, negTrack); + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + continue; + } + } + } else { + if (applyCalibDeDxFromCCDB) { + const float dEdxPosGa = dedxcalib.hPlateauCalibAll->GetBinContent(dedxcalib.hPlateauCalibAll->FindBin(posTrack.eta())); + const float dEdxNegGa = dedxcalib.hPlateauCalibAll->GetBinContent(dedxcalib.hPlateauCalibAll->FindBin(negTrack.eta())); + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + continue; + } + } else { + const float dEdxPosGa = getCalibration(fEDeDxVsEta, posTrack); + const float dEdxNegGa = getCalibration(fEDeDxVsEta, negTrack); + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + continue; + } + } + } + } + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hEV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.tpcInnerParam(), dEdxPos); + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hEV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.tpcInnerParam(), dEdxNeg); + } else { + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hEV0"), posTrack.eta(), posTrack.sign() * posTrack.tpcInnerParam(), dEdxPos); + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hEV0"), negTrack.eta(), negTrack.sign() * negTrack.tpcInnerParam(), dEdxNeg); + } + } + if (selectTypeV0s(collision, v0, posTrack, negTrack) == kKz) { // K0S -> pi + pi + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.tpcInnerParam(), dEdxPos); + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.tpcInnerParam(), dEdxNeg); + } else { + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), posTrack.sign() * posTrack.tpcInnerParam(), dEdxPos); + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), negTrack.sign() * negTrack.tpcInnerParam(), dEdxNeg); + } + } + if (selectTypeV0s(collision, v0, posTrack, negTrack) == kLam) { // L -> p + pi- + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.tpcInnerParam(), dEdxPos); + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.tpcInnerParam(), dEdxNeg); + } else { + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPV0"), posTrack.eta(), posTrack.sign() * posTrack.tpcInnerParam(), dEdxPos); + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), negTrack.sign() * negTrack.tpcInnerParam(), dEdxNeg); + } + } + if (selectTypeV0s(collision, v0, posTrack, negTrack) == kaLam) { // L -> p + pi- + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.tpcInnerParam(), dEdxPos); + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.tpcInnerParam(), dEdxNeg); + } else { + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPV0"), posTrack.eta(), posTrack.sign() * posTrack.tpcInnerParam(), dEdxPos); + flatchrg.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), negTrack.sign() * negTrack.tpcInnerParam(), dEdxNeg); + } + } + } + } + } + + template + float getCalibration(std::vector> const& fCalib, V const& track) + { + float valCalib = -1.; + if constexpr (isChrg) { + if (track.sign() * track.tpcInnerParam() > Cnull) { + valCalib = fCalib.at(0)->Eval(track.eta()); + } else { + valCalib = fCalib.at(1)->Eval(track.eta()); + } + } else { + valCalib = fCalib.at(2)->Eval(track.eta()); + } + return valCalib; + } + + bool isChrgParticle(int code) + { + auto p = pdg->GetParticle(code); + auto charge = 0.; + if (p != nullptr) { + charge = p->Charge(); + } + return std::abs(charge) >= CminCharge; + } + + template + bool phiCut(T const& track, float mag, TF1* fphiCutLow, TF1* fphiCutHigh) + { + if (track.pt() < trkSelOpt.cfgPhiCutPtMin) + return true; + // cut to remove tracks at TPC boundaries + double phimodn = track.phi(); + if (mag < Cnull) // for negative polarity field + phimodn = o2::constants::math::TwoPI - phimodn; + if (track.sign() < Cnull) // for negative charge + phimodn = o2::constants::math::TwoPI - phimodn; + if (phimodn < Cnull) + LOGF(warning, "phi < Cnull: %g", phimodn); + + phimodn += o2::constants::math::PI / 18.0f; // to center gap in the middle + phimodn = std::fmod(phimodn, o2::constants::math::PI / 9.0f); + + if (cfgFillTrackQaHist) { + flatchrg.fill(HIST("Tracks/preSel/hPtPhi"), track.pt(), phimodn); + if (track.hasTPC() && track.hasITS()) { + if (cfgStoreThnSparse) { + flatchrg.fill(HIST("Tracks/preSel/hPtPhiNclTPC"), track.pt(), phimodn, track.tpcNClsFound()); + flatchrg.fill(HIST("Tracks/preSel/hPtPhiNclPIDTPC"), track.pt(), phimodn, track.tpcNClsPID()); + } else { + flatchrg.fill(HIST("Tracks/preSel/hPtPhiNclTPC"), track.pt(), phimodn, track.tpcNClsFound()); + flatchrg.fill(HIST("Tracks/preSel/hPtPhiNclPIDTPC"), track.pt(), phimodn, track.tpcNClsPID()); + flatchrg.fill(HIST("Tracks/preSel/hPtNclTPC"), track.pt(), track.tpcNClsFound()); + flatchrg.fill(HIST("Tracks/preSel/pPtNclTPC"), track.pt(), track.tpcNClsFound()); + flatchrg.fill(HIST("Tracks/preSel/hPtNclPIDTPC"), track.pt(), track.tpcNClsPID()); + flatchrg.fill(HIST("Tracks/preSel/pPtNclPIDTPC"), track.pt(), track.tpcNClsPID()); + } + } + } + if (phimodn < fphiCutHigh->Eval(track.pt()) && phimodn > fphiCutLow->Eval(track.pt())) { + return false; + } + if (cfgFillTrackQaHist) { + flatchrg.fill(HIST("Tracks/postSel/hPtPhi"), track.pt(), phimodn); + if (track.hasTPC() && track.hasITS()) { + if (cfgStoreThnSparse) { + flatchrg.fill(HIST("Tracks/postSel/hPtPhiNclTPC"), track.pt(), phimodn, track.tpcNClsFound()); + flatchrg.fill(HIST("Tracks/postSel/hPtPhiNclPIDTPC"), track.pt(), phimodn, track.tpcNClsPID()); + } else { + flatchrg.fill(HIST("Tracks/postSel/hPtPhiNclTPC"), track.pt(), phimodn, track.tpcNClsFound()); + flatchrg.fill(HIST("Tracks/postSel/hPtPhiNclPIDTPC"), track.pt(), phimodn, track.tpcNClsPID()); + flatchrg.fill(HIST("Tracks/postSel/hPtNclTPC"), track.pt(), track.tpcNClsFound()); + flatchrg.fill(HIST("Tracks/postSel/pPtNclTPC"), track.pt(), track.tpcNClsFound()); + flatchrg.fill(HIST("Tracks/postSel/hPtNclPIDTPC"), track.pt(), track.tpcNClsPID()); + flatchrg.fill(HIST("Tracks/postSel/pPtNclPIDTPC"), track.pt(), track.tpcNClsPID()); + } + } + } + return true; + } + + template + bool isGoodTrack(T const& track, int const magfield) + { + flatchrg.fill(HIST("Tracks/hTrkSel"), trkSelAll); + if (std::abs(track.eta()) > trkSelOpt.cfgTrkEtaMax) { + return false; + } + flatchrg.fill(HIST("Tracks/hTrkSel"), trkSelEta); + if (track.pt() < trkSelOpt.cfgTrkPtMin) { + return false; + } + flatchrg.fill(HIST("Tracks/hTrkSel"), trkSelPt); + if (!isDCAxyCut(track)) { + return false; + } + flatchrg.fill(HIST("Tracks/hTrkSel"), trkSelDCA); + if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) { + return false; + } + flatchrg.fill(HIST("Tracks/hTrkSel"), trkNRowsTPC); + if (track.tpcNClsFound() < trkSelOpt.cfgNclTPCMin) { + return false; + } + flatchrg.fill(HIST("Tracks/hTrkSel"), trkSelNClsFound); + + if (trkSelOpt.cfgApplyNclPID && track.tpcNClsPID() < trkSelOpt.cfgNclPidTPCMin) { + return false; + } + flatchrg.fill(HIST("Tracks/hTrkSel"), trkSelNClsPID); + if (trkSelOpt.cfgRejectTrkAtTPCSector && !phiCut(track, magfield, fPhiCutLow, fPhiCutHigh)) { + return false; + } + flatchrg.fill(HIST("Tracks/hTrkSel"), trkSelTPCBndr); + return true; + } + + template + int selectTypeV0s(C const& collision, T1 const& v0, T2 const& postrk, T2 const& negtrk) + { + // Gamma selection + const float yGamma = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma); + if (v0.mGamma() < v0SelOpt.cfgdmassG) { // inv mass cut + if (std::abs(yGamma) < v0SelOpt.cfgV0Ymax) { // rapidity cut + if (std::abs(v0.alpha()) < v0SelOpt.cfgArmPodGammasalpha && v0.qtarm() < v0SelOpt.cfgArmPodGammasqT) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaEl()) < v0SelOpt.cfgNsigmaElTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaEl()) < v0SelOpt.cfgNsigmaElTOF) { + return kGa; + } + } + if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaEl()) < v0SelOpt.cfgNsigmaElTPC) { + if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaEl()) < v0SelOpt.cfgNsigmaElTOF) { + return kGa; + } + } + flatchrg.fill(HIST("Tracks/V0qa/hEtaVsRapGamma"), negtrk.eta(), yGamma); + flatchrg.fill(HIST("Tracks/V0qa/hEtaVsRapGamma"), postrk.eta(), yGamma); + flatchrg.fill(HIST("Tracks/V0qa/hArmPodGamma"), v0.alpha(), v0.qtarm()); + flatchrg.fill(HIST("Tracks/V0qa/hMassGammaVsPt"), v0.pt(), v0.mGamma()); + flatchrg.fill(HIST("Tracks/V0qa/hNsigmaElFromGamma"), postrk.pt(), postrk.tpcNSigmaEl()); + flatchrg.fill(HIST("Tracks/V0qa/hNsigmaElFromGamma"), negtrk.pt(), negtrk.tpcNSigmaEl()); + } + } + } + // K0S selection, K0S -> pi + pi + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0SelOpt.cfgdmassK) { // inv mass cut + if (std::abs(v0.yK0Short()) < v0SelOpt.cfgV0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0SelOpt.cfgcTauK0s) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cfgCosPAK0s && v0.v0radius() >= v0SelOpt.cfgV0radiusK0s && v0.qtarm() * v0SelOpt.cfgArmPodK0s > std::abs(v0.alpha())) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + return kKz; + } + } + if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { + if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + return kKz; + } + } + flatchrg.fill(HIST("Tracks/V0qa/hEtaVsRapK0s"), negtrk.eta(), v0.yK0Short()); + flatchrg.fill(HIST("Tracks/V0qa/hEtaVsRapK0s"), postrk.eta(), v0.yK0Short()); + flatchrg.fill(HIST("Tracks/V0qa/hArmPodK0s"), v0.alpha(), v0.qtarm()); + flatchrg.fill(HIST("Tracks/V0qa/hMassK0sVsPt"), v0.pt(), v0.mK0Short()); + flatchrg.fill(HIST("Tracks/V0qa/hNsigmaPiFromK0s"), postrk.pt(), postrk.tpcNSigmaPi()); + flatchrg.fill(HIST("Tracks/V0qa/hNsigmaPiFromK0s"), negtrk.pt(), negtrk.tpcNSigmaPi()); + } + } + } + } + // Lambda selection, L -> p + pi- + if (std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.cfgdmassL) { // inv mass cut + if (std::abs(v0.yLambda()) < v0SelOpt.cfgV0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cfgcTauLambda) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cfgCosPALambda && v0.v0radius() >= v0SelOpt.cfgV0radiusLambda) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPr()) < v0SelOpt.cfgNsigmaPrTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPr()) < v0SelOpt.cfgNsigmaPrTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + return kLam; + } + } + flatchrg.fill(HIST("Tracks/V0qa/hEtaVsRapLam"), negtrk.eta(), v0.yLambda()); + flatchrg.fill(HIST("Tracks/V0qa/hEtaVsRapLam"), postrk.eta(), v0.yLambda()); + flatchrg.fill(HIST("Tracks/V0qa/hArmPodLam"), v0.alpha(), v0.qtarm()); + flatchrg.fill(HIST("Tracks/V0qa/hMassLamVsPt"), v0.pt(), v0.mLambda()); + flatchrg.fill(HIST("Tracks/V0qa/hNsigmaPrFromLam"), postrk.pt(), postrk.tpcNSigmaPr()); + flatchrg.fill(HIST("Tracks/V0qa/hNsigmaPiFromLam"), negtrk.pt(), negtrk.tpcNSigmaPi()); + } + } + } + } + // antiLambda -> pbar + pi+ + if (std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.cfgdmassL) { // inv mass cut + if (std::abs(v0.yLambda()) < v0SelOpt.cfgV0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cfgcTauLambda) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cfgCosPALambda && v0.v0radius() >= v0SelOpt.cfgV0radiusLambda) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPr()) < v0SelOpt.cfgNsigmaPrTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPr()) < v0SelOpt.cfgNsigmaPrTOF) { + return kaLam; + } + } + flatchrg.fill(HIST("Tracks/V0qa/hEtaVsRapALam"), negtrk.eta(), v0.yLambda()); + flatchrg.fill(HIST("Tracks/V0qa/hEtaVsRapALam"), postrk.eta(), v0.yLambda()); + flatchrg.fill(HIST("Tracks/V0qa/hArmPodALam"), v0.alpha(), v0.qtarm()); + flatchrg.fill(HIST("Tracks/V0qa/hMassALamVsPt"), v0.pt(), v0.mLambda()); + flatchrg.fill(HIST("Tracks/V0qa/hNsigmaPiFromALam"), postrk.pt(), postrk.tpcNSigmaPi()); + flatchrg.fill(HIST("Tracks/V0qa/hNsigmaPrFromALam"), negtrk.pt(), negtrk.tpcNSigmaPr()); + } + } + } + } + return kNaN; + } + + template + bool isGoodV0Track(T1 const& v0, T2 const& /*track*/, int const magfield) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelAll); + if (std::abs(posTrack.eta()) > v0SelOpt.cfgV0etamax || std::abs(negTrack.eta()) > v0SelOpt.cfgV0etamax) { + return false; + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelEta); + if (!(selTrkV0sDaughters.IsSelected(posTrack) && selTrkV0sDaughters.IsSelected(negTrack))) { + return false; + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDaughters); + if (posTrack.tpcNClsFound() < v0SelOpt.cfgTPCnClsmin || negTrack.tpcNClsFound() < v0SelOpt.cfgTPCnClsmin) { + return false; + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelTPCnClsFound); + + if (v0SelOpt.cfgApplyV0sNclPID) { + if (posTrack.tpcNClsPID() < v0SelOpt.cfgTPCnClsPidmin || negTrack.tpcNClsPID() < v0SelOpt.cfgTPCnClsPidmin) { + return false; + } + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelTPCnClsPID); + if (v0SelOpt.cfgRejectV0sAtTPCSector) { + if (!(phiCut(posTrack, magfield, fPhiCutLow, fPhiCutHigh) && phiCut(negTrack, magfield, fPhiCutLow, fPhiCutHigh))) { + return false; + } + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelRejectV0sAtTPCSector); + if (posTrack.sign() * negTrack.sign() > Cnull) { // reject same sign pair + return false; + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelRejectSameSign); + if (v0.dcaV0daughters() > v0SelOpt.cfgDCAv0daughter) { + return false; + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDCAv0daughter); + if (v0.v0cosPA() < v0SelOpt.cfgv0cospa) { + return false; + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelCosPA); + if (v0.v0radius() < v0SelOpt.cfgv0Rmin || v0.v0radius() > v0SelOpt.cfgv0Rmax) { + return false; + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelV0radius); + if (std::abs(v0.dcapostopv()) < v0SelOpt.cfgDCAposToPV || std::abs(v0.dcanegtopv()) < v0SelOpt.cfgDCAnegToPV) { + return false; + } + flatchrg.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDCAposToPV); + if constexpr (fillHist) { + flatchrg.fill(HIST("Tracks/V0qa/hV0Pt"), v0.pt()); + flatchrg.fill(HIST("Tracks/V0qa/hV0ArmPod"), v0.alpha(), v0.qtarm()); + } + return true; + } + + template + void checkNsigma(const T& track, const float mult, const float flat) + { + if (std::abs(track.rapidity(o2::track::PID::getMass(pid))) > trkSelOpt.cfgRapMax) { + return; + } + + float valTPCnsigma = -999, valTOFnsigma = -999; + switch (pid) { + case o2::track::PID::Pion: + valTPCnsigma = track.tpcNSigmaPi(); + valTOFnsigma = track.tofNSigmaPi(); + break; + case o2::track::PID::Kaon: + valTPCnsigma = track.tpcNSigmaKa(); + valTOFnsigma = track.tofNSigmaKa(); + break; + case o2::track::PID::Proton: + valTPCnsigma = track.tpcNSigmaPr(); + valTOFnsigma = track.tofNSigmaPr(); + break; + case o2::track::PID::Electron: + valTPCnsigma = track.tpcNSigmaEl(); + valTOFnsigma = track.tofNSigmaEl(); + break; + case o2::track::PID::Muon: + valTPCnsigma = track.tpcNSigmaMu(); + valTOFnsigma = track.tofNSigmaMu(); + break; + default: + valTPCnsigma = -999, valTOFnsigma = -999; + break; + } + + if (track.sign() > Cnull) { + if (cfgStoreThnSparse) { + hThPtNsigmaTPC[pid]->Fill(track.pt(), valTPCnsigma, mult, flat); + } else { + hPtNsigmaTPC[pid]->Fill(track.pt(), valTPCnsigma); + } + } else { + if (cfgStoreThnSparse) { + hThPtNsigmaTPC[pid + Npart]->Fill(track.pt(), valTPCnsigma, mult, flat); + } else { + hPtNsigmaTPC[pid + Npart]->Fill(track.pt(), valTPCnsigma); + } + } + if (!track.hasTOF()) { + return; + } + if (track.sign() > Cnull) { + hPtNsigmaTOF[pid]->Fill(track.pt(), valTOFnsigma); + hPtNsigmaTPCTOF[pid]->Fill(valTPCnsigma, valTOFnsigma); + } else { + hPtNsigmaTOF[pid + Npart]->Fill(track.pt(), valTOFnsigma); + hPtNsigmaTPCTOF[pid + Npart]->Fill(valTPCnsigma, valTOFnsigma); + } + } + + template + inline void fillTrackQA(T const& track) + { + if constexpr (fillHist) { + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPt"), track.pt()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPhi"), track.phi()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hEta"), track.eta()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hDCAXYvsPt"), track.pt(), track.dcaXY()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hDCAZvsPt"), track.pt(), track.dcaZ()); + + if (track.hasTPC() && track.hasITS()) { + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTPCCluster"), track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hShTpcClvsPt"), track.pt(), track.tpcFractionSharedCls()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hNclTPCFoundvsPt"), track.pt(), track.tpcNClsFound()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hNClTPCPidvsPt"), track.pt(), track.tpcNClsPID()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTPCnClsShared"), track.tpcNClsShared()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTPCcrossedRows"), track.tpcNClsCrossedRows()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hChi2ITSTrkSegment"), track.itsChi2NCl()); + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hITSnCls"), track.itsNCls()); + } + + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTOFPvsBeta"), track.tpcInnerParam(), track.beta()); + if (track.beta() > trkSelOpt.cfgTOFBetaPion && track.beta() < trkSelOpt.cfgTOFBetaPion + 0.05) { // TOF pions + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTOFpi"), track.eta(), track.tpcInnerParam(), track.tpcSignal()); + } + + if (std::abs(track.eta()) < trkSelOpt.cfgTrkEtaMax) { + if (isDCAxyWoCut(track)) { + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtVsWOcutDCA"), track.pt(), track.dcaXY()); + } + } + } + flatchrg.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPVsPtEta"), track.tpcInnerParam(), track.pt(), track.eta()); + } + + template + inline void filldEdxQA(T const& track, C const& collision, const float dEdx) + { + const float mult = getMult(collision); + const float flat = fillFlat(collision); + if constexpr (fillHist) { + if (track.tpcInnerParam() >= trkSelOpt.cfgMomMIPMin && track.tpcInnerParam() <= trkSelOpt.cfgMomMIPMax) { + if (dEdx > trkSelOpt.cfgDeDxMIPMin && dEdx < trkSelOpt.cfgDeDxMIPMax) { // MIP pions + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIP"), mult, flat, track.eta(), dEdx); + } else { + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIP"), track.eta(), dEdx); + } + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIPVsPhi"), track.phi(), dEdx); + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIPVsPhiVsEta"), track.phi(), dEdx, track.eta()); + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("pMIPVsPhi"), track.phi(), dEdx); + } + if (dEdx > trkSelOpt.cfgDeDxMIPMax + 10. && dEdx < trkSelOpt.cfgDeDxMIPMax + 30.) { // Plateau electrons + if (std::abs(track.beta() - 1) < trkSelOpt.cfgBetaPlateuMax) { + if (cfgStoreThnSparse) { + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hPlateau"), mult, flat, track.eta(), dEdx); + } else { + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hPlateau"), track.eta(), dEdx); + } + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hPlateauVsPhi"), track.phi(), dEdx); + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hPlateauVsPhiVsEta"), track.phi(), dEdx, track.eta()); + flatchrg.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("pPlateauVsPhi"), track.phi(), dEdx); + } + } + } + } + } + + template + bool isGoodEvent(C const& collision) + { + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelAll); + } + if (evtSelOpt.cfgCustomTVX) { + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + } else { + if (!collision.sel8()) { + return false; + } + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelSel8); + } + if (evtSelOpt.cfgRemoveITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelNoITSROFrameBorder); + } + if (evtSelOpt.cfgRemoveNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelkNoTimeFrameBorder); + } + if (evtSelOpt.cfgRemoveNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelkNoSameBunchPileup); + } + if (evtSelOpt.cfgRequireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelkIsGoodZvtxFT0vsPV); + } + if (evtSelOpt.cfgRequireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + return false; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelkIsVertexITSTPC); + } + if (evtSelOpt.cfgRequirekIsVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelkIsVertexTOFmatched); + } + if (std::abs(collision.posZ()) > evtSelOpt.cfgCutVtxZ) { + return false; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelVtxZ); + flatchrg.fill(HIST("Events/hVtxZ"), collision.posZ()); + } + if (evtSelOpt.cfgINELCut && !collision.isInelGt0()) { + return false; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("Events/hEvtSel"), evtSelINELgt0); + } + return true; + } + + int getFV0IndexPhi(int i_ch) + { + int iRing = -1; + + if (i_ch >= Cfv0IndexPhi[0] && i_ch < Cfv0IndexPhi[1]) { + if (i_ch < Cfv0IndexPhi[0] + 4) { + iRing = i_ch; + } else { + if (i_ch == Cfv0IndexPhi[1] - 1) { + iRing = i_ch - 3; // 4; + } else if (i_ch == Cfv0IndexPhi[1] - 2) { + iRing = i_ch - 1; // 5; + } else if (i_ch == Cfv0IndexPhi[1] - 3) { + iRing = i_ch + 1; // 6; + } else if (i_ch == Cfv0IndexPhi[1] - 4) { + iRing = i_ch + 3; // 7; + } + } + } else if (i_ch >= Cfv0IndexPhi[1] && i_ch < Cfv0IndexPhi[2]) { + if (i_ch < Cfv0IndexPhi[2] - 4) { + iRing = i_ch; + } else { + if (i_ch == Cfv0IndexPhi[2] - 1) { + iRing = i_ch - 3; // 12; + } else if (i_ch == Cfv0IndexPhi[2] - 2) { + iRing = i_ch - 1; // 13; + } else if (i_ch == Cfv0IndexPhi[2] - 3) { + iRing = i_ch + 1; // 14; + } else if (i_ch == Cfv0IndexPhi[2] - 4) { + iRing = i_ch + 3; // 15; + } + } + } else if (i_ch >= Cfv0IndexPhi[2] && i_ch < Cfv0IndexPhi[3]) { + if (i_ch < Cfv0IndexPhi[3] - 4) { + iRing = i_ch; + } else { + if (i_ch == Cfv0IndexPhi[3] - 1) { + iRing = i_ch - 3; // 20; + } else if (i_ch == Cfv0IndexPhi[3] - 2) { + iRing = i_ch - 1; // 21; + } else if (i_ch == Cfv0IndexPhi[3] - 3) { + iRing = i_ch + 1; // 22; + } else if (i_ch == Cfv0IndexPhi[3] - 4) { + iRing = i_ch + 3; // 23; + } + } + } else if (i_ch >= Cfv0IndexPhi[3] && i_ch < Cfv0IndexPhi[4]) { + if (i_ch < Cfv0IndexPhi[3] + 4) { + iRing = i_ch; + } else { + if (i_ch == Cfv0IndexPhi[4] - 5) { + iRing = i_ch - 3; // 28; + } else if (i_ch == Cfv0IndexPhi[4] - 6) { + iRing = i_ch - 1; // 29; + } else if (i_ch == Cfv0IndexPhi[4] - 7) { + iRing = i_ch + 1; // 30; + } else if (i_ch == Cfv0IndexPhi[4] - 8) { + iRing = i_ch + 3; // 31; + } + } + } else if (i_ch == Cfv0IndexPhi[4]) { + iRing = Cfv0IndexPhi[4]; + } else if (i_ch == Cfv0IndexPhi[4] + 8) { + iRing = i_ch - 7; // 33; + } else if (i_ch == Cfv0IndexPhi[4] + 1) { + iRing = i_ch + 1; // 34; + } else if (i_ch == Cfv0IndexPhi[4] + 9) { + iRing = i_ch - 6; // 35; + } else if (i_ch == Cfv0IndexPhi[4] + 2) { + iRing = i_ch + 2; // 36; + } else if (i_ch == Cfv0IndexPhi[4] + 10) { + iRing = i_ch - 5; // 37; + } else if (i_ch == Cfv0IndexPhi[4] + 3) { + iRing = i_ch + 3; // 38; + } else if (i_ch == Cfv0IndexPhi[4] + 11) { + iRing = i_ch - 4; // 39; + } else if (i_ch == Cfv0IndexPhi[4] + 15) { + iRing = i_ch - 7; // 40; + } else if (i_ch == Cfv0IndexPhi[4] + 7) { + iRing = i_ch + 2; // 41; + } else if (i_ch == Cfv0IndexPhi[4] + 14) { + iRing = i_ch - 4; // 42; + } else if (i_ch == Cfv0IndexPhi[4] + 6) { + iRing = i_ch + 5; // 43; + } else if (i_ch == Cfv0IndexPhi[4] + 13) { + iRing = i_ch - 1; // 44; + } else if (i_ch == Cfv0IndexPhi[4] + 5) { + iRing = i_ch + 8; // 45; + } else if (i_ch == Cfv0IndexPhi[4] + 12) { + iRing = i_ch + 2; // 46; + } else if (i_ch == Cfv0IndexPhi[4] + 4) { + iRing = i_ch + 11; // 47; + } + return iRing; + } + + template + float getMult(C const& collision) + { + float val = -999.0; + switch (multEst) { + case MultE::CnoMult: + return val; + break; + case MultE::CmultFT0M: + return collision.centFT0M(); + break; + case MultE::CmultTPC: + if constexpr (!isMC) { + return collision.multTPC(); + } else { + LOG(fatal) << "No valid multiplicity estimator: " << multEst; + return val; + } + break; + default: + return collision.centFT0M(); + break; + } + } + + float getMultMC(MCColls::iterator const& collision) + { + return getMult(collision); + } + + template + float calcFlatenicity(std::array const& signals) + { + static_assert(S != 0); + + int entries = signals.size(); + float flat{-1}; + float mRho{0}; + for (int iCell = 0; iCell < entries; ++iCell) { + if (signals[iCell] > Cnull) { + mRho += 1.0 * signals[iCell]; + } + } + // average activity per cell + mRho /= (1.0 * entries); + if (mRho <= 0) { + return -1; + } + // get sigma + float sRhoTmp{0}; + float sRho{0}; + for (int iCell = 0; iCell < entries; ++iCell) { + if (signals[iCell] > Cnull) { + sRhoTmp += std::pow(1.0 * signals[iCell] - mRho, 2); + } + } + sRhoTmp /= (1.0 * entries * entries); + sRho = std::sqrt(sRhoTmp); + if (mRho > Cnull) { + flat = sRho / mRho; + } else { + flat = -1; + } + return flat; + } + + template + float fillFlat(C const& collision) + { + rhoLatticeFV0.fill(0); + fv0AmplitudeWoCalib.fill(0); + if (collision.has_foundFV0()) { + auto fv0 = collision.foundFV0(); + std::bitset<8> fV0Triggers = fv0.triggerMask(); + bool isOkFV0OrA = fV0Triggers[o2::fit::Triggers::bitA]; + if (isOkFV0OrA) { + for (std::size_t ich = 0; ich < fv0.channel().size(); ich++) { + float amplCh = fv0.amplitude()[ich]; + int chv0 = fv0.channel()[ich]; + int chv0phi = getFV0IndexPhi(chv0); + if constexpr (fillHist) { + flatchrg.fill(HIST("FV0/hFV0amp"), chv0, amplCh); + flatchrg.fill(HIST("FV0/pFV0amp"), chv0, amplCh); + if (applyCalibGain) { + flatchrg.fill(HIST("FV0/hFV0ampCorr"), chv0, amplCh / fv0AmplCorr[chv0]); + } + } + if (amplCh > Cnull) { + if (applyCalibGain) { // equalize gain channel-by-channel + amplCh /= fv0AmplCorr[chv0]; + } + if (chv0phi > Cnull) { + fv0AmplitudeWoCalib[chv0phi] = amplCh; + if constexpr (fillHist) { + flatchrg.fill(HIST("FV0/hFV0AmplWCalib"), ich, fv0AmplitudeWoCalib[ich]); + } + if (chv0 < CinnerFV0) { + rhoLatticeFV0[chv0phi] += amplCh; + } else { // two channels per bin + rhoLatticeFV0[chv0phi] += amplCh / 2.; + } + if constexpr (fillHist) { + flatchrg.fill(HIST("FV0/hFV0AmplvsVtxzWoCalib"), collision.posZ(), rhoLatticeFV0[chv0phi]); + } + if (applyCalibVtx) { + rhoLatticeFV0[chv0phi] *= zVtxMap->GetBinContent(zVtxMap->GetXaxis()->FindBin(chv0phi), zVtxMap->GetYaxis()->FindBin(collision.posZ())); + if constexpr (fillHist) { + flatchrg.fill(HIST("FV0/hFV0AmplvsVtxzCalib"), collision.posZ(), rhoLatticeFV0[chv0phi]); + } + } + } + } + } + float flattenicityFV0 = calcFlatenicity(rhoLatticeFV0); + return 1. - flattenicityFV0; + } else { + return 9999; + } + } else { + return 9999; + } + } + + template + bool isDCAxyCut(T const& track) const + { + if (isCustomTracks.value) { + for (int i = 0; i < static_cast(TrackSelection::TrackCuts::kNCuts); i++) { + if (i == static_cast(TrackSelection::TrackCuts::kDCAxy)) { + continue; + } + if (!selTrkGlobal.IsSelected(track, static_cast(i))) { + return false; + } + } + return (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / std::pow(track.pt(), 1.1f)))); + } + return track.isGlobalTrack(); + } + + template + bool isDCAxyWoCut(T const& track) const + { + if (isCustomTracks.value) { + for (int i = 0; i < static_cast(TrackSelection::TrackCuts::kNCuts); i++) { + if (i == static_cast(TrackSelection::TrackCuts::kDCAxy)) { + continue; + } + if (i == static_cast(TrackSelection::TrackCuts::kDCAz)) { + continue; + } + if (!selTrkGlobal.IsSelected(track, static_cast(i))) { + return false; + } + } + return true; + } + return track.isGlobalTrackWoDCA(); + } + + Preslice perCol = aod::track::collisionId; + Preslice perColV0s = aod::v0::collisionId; + + template + void processData(C const& collisions, + MyPIDTracks const& tracks, + aod::V0Datas const& v0s, + aod::BCsWithTimestamps const& bcs) + { + for (const auto& collision : collisions) { + if (!isGoodEvent(collision)) { + continue; + } + auto tracksPerCollision = tracks.sliceBy(perCol, collision.globalIndex()); + auto v0sPerCollision = v0s.sliceBy(perColV0s, collision.globalIndex()); + v0sPerCollision.bindExternalIndices(&tracks); + filldEdx(tracksPerCollision, v0sPerCollision, collision, bcs); + if (cfgFillNsigmaQAHist) { + fillNsigma(tracksPerCollision, collision); + fillNsigma(tracksPerCollision, collision); + fillNsigma(tracksPerCollision, collision); + } + } + } + + void processFlat( + Colls const& collisions, + MyPIDTracks const& tracks, + aod::V0Datas const& v0s, + aod::BCsWithTimestamps const& bcs, + aod::FT0s const&, aod::FV0As const&) + { + processData(collisions, tracks, v0s, bcs); + } + PROCESS_SWITCH(FlattenictyPikp, processFlat, "process Flat data inclusive", true); + + template + float fillFlatMC(McPart const& mcparts) + { + int nFV0sectors = 0; + float minPhi = 0; + float maxPhi = 0; + float dPhi = 0; + + double etaMinFV0bins[CmaxRingsFV0] = {0.0}; + double etaMaxFV0bins[CmaxRingsFV0] = {0.0}; + for (int i = 0; i < CmaxRingsFV0; ++i) { + etaMaxFV0bins[i] = CmaxEtaFV0 - i * CdEtaFV0; + if (i < CmaxRingsFV0 - 1) { + etaMinFV0bins[i] = CmaxEtaFV0 - (i + 1) * CdEtaFV0; + } else { + etaMinFV0bins[i] = CminEtaFV0; + } + } + + rhoLatticeFV0.fill(0); + std::vector vNch; + float nCharged{0}; + for (const auto& mcPart : mcparts) { + if (!isChrgParticle(mcPart.pdgCode())) { + continue; + } + auto etaMc = mcPart.eta(); + auto phiMc = mcPart.phi(); + + int isegment = 0; + for (int ieta = 0; ieta < CmaxRingsFV0; ieta++) { + + nFV0sectors = CnCellsFV0 / 6.; + if (ieta == CmaxRingsFV0 - 1) { + nFV0sectors = CnCellsFV0 / 3.; + } + + for (int iphi = 0; iphi < nFV0sectors; iphi++) { + + minPhi = iphi * TwoPI / nFV0sectors; + maxPhi = (iphi + 1) * TwoPI / nFV0sectors; + dPhi = std::abs(maxPhi - minPhi); + + if (etaMc >= etaMinFV0bins[ieta] && etaMc < etaMaxFV0bins[ieta] && phiMc >= minPhi && phiMc < maxPhi) { + rhoLatticeFV0[isegment] += 1. / std::abs(CdEtaFV0 * dPhi); + } + isegment++; + } + } + nCharged++; + } + + vNch.push_back(nCharged); + auto flatFV0 = calcFlatenicity(rhoLatticeFV0); + + if constexpr (fillHist) { + flatchrg.fill(HIST("ResponseGen"), vNch[0], 1. - flatFV0); + flatchrg.fill(HIST("h1flatencityFV0MCGen"), 1. - flatFV0); + } + vNch.clear(); + return 1. - flatFV0; + } + + template + void bookMcHist() + { + AxisSpec ptAxis{binOpt.axisPt, "#it{p}_{T} (GeV/#it{c})"}; + constexpr int ChistIdx = id + pidSgn * Npart; + auto idx = static_cast(id); + const std::string strID = Form("/%s/%s", (pidSgn == Cnull && id < Npart) ? "pos" : "neg", Pid[idx]); + hPtEffRec[ChistIdx] = flatchrg.add("Tracks/hPtEffRec" + strID, " ; p_{T} (GeV/c)", kTH1F, {ptAxis}); + hPtEffGen[ChistIdx] = flatchrg.add("Tracks/hPtEffGen" + strID, " ; p_{T} (GeV/c)", kTH1F, {ptAxis}); + } + + template + void initEfficiency() + { + static_assert(pidSgn == Cnull || pidSgn == 1); + static_assert(id > Cnull || id < Npart); + constexpr int Cidx = id + pidSgn * Npart; + const TString partName = PidChrg[Cidx]; + THashList* lhash = new THashList(); + lhash->SetName(partName); + listEfficiency->Add(lhash); + + auto bookEff = [&](const TString eName, auto h) { + const TAxis* axis = h->GetXaxis(); + TString eTitle = h->GetTitle(); + eTitle.ReplaceAll("Numerator", "").Strip(TString::kBoth); + eTitle = Form("%s;%s;Efficiency", eTitle.Data(), axis->GetTitle()); + lhash->Add(new TEfficiency(eName, eTitle, axis->GetNbins(), axis->GetXbins()->GetArray())); + }; + + const int idx = id + pidSgn * Npart; + bookEff("hEffvsPt", hPtEffRec[idx]); + } + + template + void fillEfficiency() + { + static_assert(pidSgn == Cnull || pidSgn == 1); + constexpr int ChistIdx = id + pidSgn * Npart; + const char* partName = PidChrg[ChistIdx]; + THashList* lhash = static_cast(listEfficiency->FindObject(partName)); + if (!lhash) { + LOG(warning) << "No efficiency object found for particle " << partName; + return; + } + + auto fillEff = [&](const TString eName, auto num, auto den) { + TEfficiency* eff = static_cast(lhash->FindObject(eName)); + if (!eff) { + LOG(warning) << "Cannot find TEfficiency " << eName; + return; + } + eff->SetTotalHistogram(*den, "f"); + eff->SetPassedHistogram(*num, "f"); + }; + fillEff("hEffvsPt", hPtEffRec[ChistIdx], hPtEffGen[ChistIdx]); + } + + template + void fillMCRecTrack(MyLabeledPIDTracks::iterator const& track, const float mult, const float flat) + { + static_assert(pidSgn == Cnull || pidSgn == 1); + constexpr int ChistIdx = id + pidSgn * Npart; + const aod::McParticles::iterator& mcParticle = track.mcParticle(); + const CollsGen::iterator& collision = track.collision_as(); + + if (!isPID(mcParticle)) { + return; + } + flatchrg.fill(HIST("hPtOutNoEtaCut"), track.pt()); + if (std::abs(track.eta()) > trkSelOpt.cfgTrkEtaMax) { + return; + } + if (std::abs(mcParticle.y()) > trkSelOpt.cfgRapMax) { + return; + } + + if ((collision.has_mcCollision() && (mcParticle.mcCollisionId() != collision.mcCollisionId())) || !collision.has_mcCollision()) { + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == CprocessIdWeak) { + hDCAxyBadCollWeak[ChistIdx]->Fill(track.pt(), track.dcaXY()); + } else { + hDCAxyBadCollMat[ChistIdx]->Fill(track.pt(), track.dcaXY()); + } + } else { + hDCAxyBadCollPrim[ChistIdx]->Fill(track.pt(), track.dcaXY()); + } + } + + if (!isDCAxyCut(track)) { + return; + } + flatchrg.fill(HIST("hPtVsDCAxyAll"), track.pt(), track.dcaXY()); + + if (selTPCtrack(track)) { + hPtEffRec[ChistIdx]->Fill(mcParticle.pt()); + } + + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == CprocessIdWeak) { + hPtEffRecWeak[ChistIdx]->Fill(mult, flat, track.pt()); + hPtVsDCAxyWeak[ChistIdx]->Fill(track.pt(), track.dcaXY()); + flatchrg.fill(HIST("hPtVsDCAxyWeakAll"), track.pt(), track.dcaXY()); + } else { + hPtEffRecMat[ChistIdx]->Fill(mult, flat, track.pt()); + hPtVsDCAxyMat[ChistIdx]->Fill(track.pt(), track.dcaXY()); + flatchrg.fill(HIST("hPtVsDCAxyMatAll"), track.pt(), track.dcaXY()); + } + } else { + hPtEffRecPrim[ChistIdx]->Fill(mult, flat, track.pt()); + hPtVsDCAxyPrim[ChistIdx]->Fill(track.pt(), track.dcaXY()); + flatchrg.fill(HIST("hPtVsDCAxyPrimAll"), track.pt(), track.dcaXY()); + } + } + + template + void fillMCGen(aod::McParticles::iterator const& mcParticle, const float mult, const float flat) + { + static_assert(pidSgn == Cnull || pidSgn == 1); + constexpr int ChistIdx = id + pidSgn * Npart; + + if (!isPID(mcParticle)) { + return; + } + + if constexpr (recoEvt) { + hPtGenRecEvt[ChistIdx]->Fill(mcParticle.pt()); + if (mcParticle.isPhysicalPrimary()) { + hPtGenPrimRecEvt[ChistIdx]->Fill(mcParticle.pt()); + } + return; + } + + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == CprocessIdWeak) { + hPtEffGenWeak[ChistIdx]->Fill(mult, flat, mcParticle.pt()); + } else { + hPtEffGenMat[ChistIdx]->Fill(mult, flat, mcParticle.pt()); + } + } else { + hPtEffGenPrim[ChistIdx]->Fill(mult, flat, mcParticle.pt()); + hPtEffGen[ChistIdx]->Fill(mcParticle.pt()); + } + } + + void processSgnLoss(MCColls::iterator const& mcCollision, + CollsGenSgn const& collisions, + aod::FV0As const& /*fv0s*/, + aod::McParticles const& particles) + { + float flat; + float mult; + if (flatSelOpt.useFlatData) { + float flatRec = 999.0; + float multRec = 999.0; + for (const auto& collision : collisions) { + multRec = getMult(collision); + flatRec = fillFlat(collision); + } + flat = flatRec; + mult = multRec; + flatchrg.fill(HIST("hFlatMCGenRecColl"), flatRec); + } else { + float flatGen = fillFlatMC(particles); + flat = flatGen; + flatchrg.fill(HIST("hFlatMCGen"), flatGen); + float multGen = getMultMC(mcCollision); + mult = multGen; + } + + // Evt loss den + flatchrg.fill(HIST("hEvtMcGen"), 0.5); + if (std::abs(mcCollision.posZ()) > evtSelOpt.cfgCutVtxZ) { + return; + } + flatchrg.fill(HIST("hEvtMcGen"), 1.5); + + bool isINELgt0mc = false; + if (pwglf::isINELgtNmc(particles, 0, pdg)) { + isINELgt0mc = true; + flatchrg.fill(HIST("hEvtMcGen"), 2.5); + flatchrg.fill(HIST("hFlatGenINELgt0"), flat); + } + + // Sgn loss den + for (const auto& particle : particles) { + if (!particle.isPhysicalPrimary()) { + continue; + } + if (std::abs(particle.y()) > trkSelOpt.cfgRapMax) { + continue; + } + static_for<0, 5>([&](auto i) { + constexpr int Cidx = i.value; + if (particle.pdgCode() == PidSgn[Cidx]) { + flatchrg.fill(HIST(Cprefix) + HIST(Cspecies[Cidx]) + HIST(CpTgenPrimSgn), mult, flat, particle.pt()); + if (isINELgt0mc) { + flatchrg.fill(HIST(Cprefix) + HIST(Cspecies[Cidx]) + HIST(CpTgenPrimSgnINEL), mult, flat, particle.pt()); + } + } + }); + } + + int nRecCollINEL = 0; + int nRecCollINELgt0 = 0; + for (const auto& collision : collisions) { + // Evt split num + flatchrg.fill(HIST("hEvtMCRec"), 0.5); + if (!isGoodEvent(collision)) { + continue; + } + flatchrg.fill(HIST("hEvtMCRec"), 1.5); + + nRecCollINEL++; + + if (collision.isInelGt0() && isINELgt0mc) { + flatchrg.fill(HIST("hEvtMCRec"), 2.5); + nRecCollINELgt0++; + } + // Sgn split num + for (const auto& particle : particles) { + if (!particle.isPhysicalPrimary()) { + continue; + } + if (std::abs(particle.y()) > trkSelOpt.cfgRapMax) { + continue; + } + static_for<0, 5>([&](auto i) { + constexpr int Cidx = i.value; + if (particle.pdgCode() == PidSgn[Cidx]) { + flatchrg.fill(HIST(Cprefix) + HIST(Cspecies[Cidx]) + HIST(CpTrecCollPrimSgn), mult, flat, particle.pt()); + if (nRecCollINELgt0) { + flatchrg.fill(HIST(Cprefix) + HIST(Cspecies[Cidx]) + HIST(CpTrecCollPrimSgnINEL), mult, flat, particle.pt()); + } + } + }); + } + } + + if (nRecCollINEL < 1) { + return; + } + // Evt loss num + flatchrg.fill(HIST("hEvtMcGenRecColl"), 0.5); + if (nRecCollINELgt0 > Cnull) { + flatchrg.fill(HIST("hEvtMcGenRecColl"), 1.5); + } + + // Sgn loss num + for (const auto& particle : particles) { + if (!particle.isPhysicalPrimary()) { + continue; + } + if (std::abs(particle.y()) > trkSelOpt.cfgRapMax) { + continue; + } + static_for<0, 5>([&](auto i) { + constexpr int Cidx = i.value; + if (particle.pdgCode() == PidSgn[Cidx]) { + flatchrg.fill(HIST(Cprefix) + HIST(Cspecies[Cidx]) + HIST(CpTGenRecCollPrimSgn), mult, flat, particle.pt()); + if (nRecCollINELgt0) { + flatchrg.fill(HIST(Cprefix) + HIST(Cspecies[Cidx]) + HIST(CpTGenRecCollPrimSgnINEL), mult, flat, particle.pt()); + } + } + }); + } + } + PROCESS_SWITCH(FlattenictyPikp, processSgnLoss, "process to calcuate signal/event lossses", 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; + + void processMCclosure(Colls::iterator const& collision, + MyPIDTracks const& tracks, + MyLabeledTracks const& mcTrackLabels, + aod::McParticles const& particles, + // Particles const& particles, + aod::FV0As const& /*fv0s*/, + aod::BCsWithTimestamps const& /*bcs*/) + { + const float multRec = getMult(collision); + const float flatRec = fillFlat(collision); + for (const auto& track : tracks) { + if (!track.has_collision()) { + continue; + } + const auto& coll = track.collision_as(); + if (trkSelOpt.cfgRejectTrkAtTPCSector) { + auto bc = coll.template bc_as(); + int currentRun = bc.runNumber(); + if (runNumber != currentRun) { + initCCDB(bc); + runNumber = currentRun; + } + } + if (!isGoodEvent(coll)) { + continue; + } + if (!isGoodTrack(track, magField)) { + continue; + } + if (!isDCAxyCut(track)) { + continue; + } + const auto& mcLabel = mcTrackLabels.iteratorAt(track.globalIndex()); + const auto& mcParticle = particles.iteratorAt(mcLabel.mcParticleId()); + + static_for<0, 4>([&](auto i) { + constexpr int Cidx = i.value; + if ((std::abs(o2::aod::pidutils::tpcNSigma(track)) < trkSelOpt.cfgNsigmaMax) && std::abs(track.rapidity(o2::track::PID::getMass(Cidx))) <= trkSelOpt.cfgRapMax) { + if (std::fabs(mcParticle.pdgCode()) == PDGs[Cidx]) { + flatchrg.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTmcClosurePrim), multRec, flatRec, track.pt()); + } + } + }); + } + } + PROCESS_SWITCH(FlattenictyPikp, processMCclosure, "process MC closure test", false); + + Preslice perCollTrk = aod::track::collisionId; + PresliceUnsorted perCollMcLabel = aod::mccollisionlabel::mcCollisionId; + Preslice perCollMcPart = aod::mcparticle::mcCollisionId; + + void processMC(MCColls const& mcCollisions, + CollsGen const& collisions, + MyLabeledPIDTracks const& tracks, + aod::McParticles const& mcparticles) + { + flatchrg.fill(HIST("hEvtGenRec"), 1.f, mcCollisions.size()); + flatchrg.fill(HIST("hEvtGenRec"), 2.f, collisions.size()); + + for (const auto& mcCollision : mcCollisions) { + if (mcCollision.isInelGt0()) { + flatchrg.fill(HIST("hEvtGenRec"), 3.f); + } + flatchrg.fill(HIST("hEvtMcGenColls"), 1); + const auto groupedColls = collisions.sliceBy(perCollMcLabel, mcCollision.globalIndex()); + const auto groupedParts = mcparticles.sliceBy(perCollMcPart, mcCollision.globalIndex()); + const float flatMC = fillFlatMC(groupedParts); + const float multMC = getMultMC(mcCollision); + if (groupedColls.size() < 1) { // if MC events have no rec collisions + continue; + } + flatchrg.fill(HIST("hEvtMcGenColls"), 2); + for (const auto& collision : groupedColls) { + flatchrg.fill(HIST("hEvtMcGenColls"), 3); + if (!isGoodEvent(collision)) { + continue; + } + flatchrg.fill(HIST("hEvtMcGenColls"), 4); + const auto groupedTrks = tracks.sliceBy(perCollTrk, collision.globalIndex()); + for (const auto& track : groupedTrks) { + if (!isDCAxyWoCut(track)) { + continue; + } + if (!track.has_mcParticle()) { + flatchrg.fill(HIST("PtOutFakes"), track.pt()); + continue; + } + const auto& mcParticle = track.mcParticle(); + if (std::abs(mcParticle.y()) > trkSelOpt.cfgRapMax) { + continue; + } + if (!track.has_collision()) { + continue; + } + static_for<0, 1>([&](auto pidSgn) { + fillMCRecTrack(track, multMC, flatMC); + fillMCRecTrack(track, multMC, flatMC); + fillMCRecTrack(track, multMC, flatMC); + }); + } + + if (std::abs(mcCollision.posZ()) > evtSelOpt.cfgCutVtxZ) { + continue; + } + + flatchrg.fill(HIST("Events/hVtxZRec"), collision.posZ()); + flatchrg.fill(HIST("Events/hVtxZGen"), mcCollision.posZ()); + + if (evtSelOpt.cfgINELCut.value) { + if (!o2::pwglf::isINELgt0mc(groupedParts, pdg)) { + continue; + } + } + + for (const auto& particle : groupedParts) { + if (std::abs(particle.y()) > trkSelOpt.cfgRapMax) { + continue; + } + static_for<0, 1>([&](auto pidSgn) { + fillMCGen(particle, multMC, flatMC); + fillMCGen(particle, multMC, flatMC); + fillMCGen(particle, multMC, flatMC); + }); + } + } // reco collisions + + if (evtSelOpt.cfgINELCut.value) { + if (!o2::pwglf::isINELgt0mc(groupedParts, pdg)) { + continue; + } + } + + for (const auto& mcParticle : groupedParts) { + if (std::abs(mcParticle.y()) > trkSelOpt.cfgRapMax) { + continue; + } + static_for<0, 1>([&](auto pidSgn) { + fillMCGen(mcParticle, multMC, flatMC); + fillMCGen(mcParticle, multMC, flatMC); + fillMCGen(mcParticle, multMC, flatMC); + }); + } + + static_for<0, 1>([&](auto pidSgn) { + fillEfficiency(); + fillEfficiency(); + fillEfficiency(); + }); + + } // gen collisions + } + PROCESS_SWITCH(FlattenictyPikp, processMC, "process MC", false); + + template + ObjType* getForTsOrRun(std::string const& fullPath, int64_t timestamp, int runNumber) + { + if (cfgUseCcdbForRun) { + return ccdb->getForRun(fullPath, runNumber); + } else { + return ccdb->getForTimeStamp(fullPath, timestamp); + } + } +}; + +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..9a496f78016 --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx @@ -0,0 +1,1103 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" + +#include "Common/CCDB/EventSelectionParams.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/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.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 + +#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; + +using CollisionDataTable = soa::Join; +using ColDataTablepp = soa::Join; +using TrackDataTable = soa::Join; +using FilTrackDataTable = soa::Filtered; +using CollisionMCTrueTable = aod::McCollisions; +using TrackMCTrueTable = aod::McParticles; +using CollisionMCRecTable = soa::SmallGroups>; +using ColMCRecTablepp = 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 +}; + +enum { + kGenTrkTypebegin = 0, + kGenAll = 1, + kGenPion, + kGenKaon, + kGenProton, + kGenOther, + kGenTrkTypeend +}; + +enum { + kRecTrkTypebegin = 0, + kRecoAll = 1, + kRecoPion, + kRecoKaon, + kRecoProton, + kRecoOther, + kRecoSecondary, + kRecoWeakDecay, + kRecoFake, + kRecoBkg, + kRecTrkTypeend +}; + +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 axisGenTrkType = {kGenTrkTypeend - 1, +kGenTrkTypebegin + 0.5, +kGenTrkTypeend - 0.5, "", "GenTrackTypeAxis"}; +AxisSpec axisRecTrkType = {kRecTrkTypeend - 1, +kRecTrkTypebegin + 0.5, +kRecTrkTypeend - 0.5, "", "RecTrackTypeAxis"}; +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"}; +AxisSpec axisDeltaEta{50, -1.0, +1.0, "#Delta(#eta)"}; +auto static constexpr KminCharge = 3.f; +auto static constexpr KminPtCut = 0.1f; +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}, ""}; + ConfigurableAxis centBinGen{"centBinGen", {VARIABLE_WIDTH, 0, 500, 1000, 2000, 5000, 10000}, ""}; + 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 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 isApplyCentFV0A{"isApplyCentFV0A", false, "Centrality based on FV0A"}; + Configurable isApplyCentFT0CVariant1{"isApplyCentFT0CVariant1", false, "Centrality based on FT0C variant1"}; + Configurable isApplyCentFT0CVariant2{"isApplyCentFT0CVariant2", false, "Centrality based on FT0C variant2 (Run2 like truncation)"}; + 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"}; + Configurable isApplySplitRecCol{"isApplySplitRecCol", false, "Split MC reco collisions"}; + Configurable isApplyInelgt0{"isApplyInelgt0", false, "Enable INEL > 0 condition"}; + + 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"}; + AxisSpec axisCentBinGen = {centBinGen, "GenCentrality", "CentGenAxis"}; + AxisSpec impactParAxis = {binsImpactPar, "Impact Parameter"}; + + 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, "ApplyExtraCorrCut"); + x->SetBinLabel(6, "ApplyNoCollInTimeRangeStandard"); + x->SetBinLabel(7, "ApplyNoCollInRofStandard"); + x->SetBinLabel(8, "ApplyNoHighMultCollInPrevRof"); + x->SetBinLabel(9, "INEL > 0"); + + 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("Centrality_vs_FT0C", "Centrality_vs_FT0C", kTH2F, {centAxis, 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("Centrality_vs_FV0A", "Centrality_vs_FV0A", kTH2F, {centAxis, axisFv0aMult}, true); + histos.add("CentFT0Ccentrality_vs_GlobalMult", "CentFT0Ccentrality_vs_GlobalMult", kTH2F, {centAxis, axisMult}, 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); + } + + if (doprocessGen) { + histos.add("MultBarrelEta10_vs_FT0A", "MultBarrelEta10_vs_FT0A", kTH2F, {axisMult, axisFt0aMult}, true); + histos.add("MultBarrelEta10_vs_FT0C", "MultBarrelEta10_vs_FT0C", kTH2F, {axisMult, axisFt0cMult}, true); + histos.add("MultBarrelEta10", "MultBarrelEta10", kTH1F, {axisMult}, true); + histos.add("MultFT0A", "MultFT0A", kTH1F, {axisFt0aMult}, true); + histos.add("MultFT0C", "MultFT0C", kTH1F, {axisFt0cMult}, true); + histos.add("dndeta10_vs_FT0C", "dndeta10_vs_FT0C", kTH2F, {axisEta, axisCentBinGen}, true); + histos.add("dndeta10_vs_FT0A", "dndeta10_vs_FT0A", kTH2F, {axisEta, axisCentBinGen}, true); + histos.add("mult10_vs_FT0C", "mult10_vs_FT0C", kTH2F, {axisMult, axisCentBinGen}, true); + histos.add("mult10_vs_FT0A", "mult10_vs_FT0A", kTH2F, {axisMult, axisCentBinGen}, true); + } + + if (doprocessEvtLossSigLossMC) { + histos.add("MCEventHist", "MCEventHist", kTH1F, {axisEvent}, false); + auto hstat = histos.get(HIST("MCEventHist")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All MC events"); + x->SetBinLabel(2, "MC events with reco event after event selection"); + x->SetBinLabel(3, "MC events with no reco events"); + histos.add("hImpactParameterGenwithNoreco", "Impact parameter of generated MC events, with no recoevent", kTH1F, {impactParAxis}); + histos.add("hImpactParameterGen", "Impact parameter of generated MC events", kTH1F, {impactParAxis}); + histos.add("hImpactParameterRec", "Impact parameter of selected MC events", kTH1F, {impactParAxis}); + histos.add("hImpactParvsCentrRec", "Impact parameter of selected MC events vs centrality", kTH2F, {axisCent, impactParAxis}); + histos.add("hgendndetaBeforeEvtSel", "Eta of all generated particles", kTH1F, {axisEta}); + histos.add("hgendndetaAfterEvtSel", "Eta of generated particles after EvtSel", kTH1F, {axisEta}); + histos.add("hgendndetaVscentBeforeEvtSel", "hgendndetaBeforeEvtSel vs centrality", kTH2F, {axisEta, impactParAxis}); + histos.add("hgendndetaVscentAfterEvtSel", "hgendndetaAfterEvtSel vs centrality", kTH2F, {axisEta, impactParAxis}); + } + + if (doprocessMCeff) { + histos.add("hGenMCvertexZ", "hGenMCvertexZ", kTH1D, {axisVtxZ}, false); + histos.add("hGenMCvtxzcent", "hGenMCvtxzcent", kTH3D, {axisVtxZ, centAxis, axisOccupancy}, false); + histos.add("hGenMCAssoRecvertexZ", "hGenMCAssoRecvertexZ", kTH1D, {axisVtxZ}, false); + histos.add("hGenMCAssoRecvtxzcent", "hGenMCAssoRecvtxzcent", kTH3D, {axisVtxZ, centAxis, axisOccupancy}, false); + histos.add("hGenMCdndeta", "hGenMCdndeta", kTHnSparseD, {axisVtxZ, centAxis, axisOccupancy, axisEta, axisPhi}, false); + histos.add("hGenMCAssoRecdndeta", "hGenMCAssoRecdndeta", kTHnSparseD, {axisVtxZ, centAxis, axisOccupancy, axisEta, axisPhi, axisGenTrkType, axisGenPtVary}, false); + + histos.add("hRecMCvertexZ", "hRecMCvertexZ", kTH1D, {axisVtxZ}, false); + histos.add("hRecMCvtxzcent", "hRecMCvtxzcent", kTH3D, {axisVtxZ, centAxis, axisOccupancy}, false); + histos.add("hRecMCcentrality", "hRecMCcentrality", kTH1D, {axisCent}, false); + histos.add("hRecMCphivseta", "hRecMCphivseta", kTH2D, {axisPhi2, axisEta}, false); + histos.add("hRecMCdndeta", "hRecMCdndeta", kTHnSparseD, {axisVtxZ, centAxis, axisOccupancy, axisEta, axisPhi, axisRecTrkType}, false); + histos.add("etaResolution", "etaResolution", kTH2D, {axisEta, axisDeltaEta}); + } + } + + 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 (isApplyExtraCorrCut && col.multNTracksPV() > npvTracksCut && col.multFT0C() < (10 * col.multNTracksPV() - ft0cCut)) { + return false; + } + histos.fill(HIST("EventHist"), 5); + + if (isApplyNoCollInTimeRangeStandard && !col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 6); + + if (isApplyNoCollInRofStandard && !col.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 7); + + if (isApplyNoHighMultCollInPrevRof && !col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + histos.fill(HIST("EventHist"), 8); + + if (isApplyInelgt0 && !col.isInelGt0()) { + return false; + } + histos.fill(HIST("EventHist"), 9); + return true; + } + + template + float selColCent(CheckColCent const& col) + { + auto cent = -1; + if (isApplyCentFT0C) { + cent = col.centFT0C(); + } + if (isApplyCentFV0A) { + cent = col.centFV0A(); + } + if (isApplyCentFT0CVariant1) { + cent = col.centFT0CVariant1(); + } + if (isApplyCentFT0CVariant2) { + cent = col.centFT0CVariant2(); + } + 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); + } + } + } + + 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("Centrality_vs_FT0C"), cols.centFT0C(), cols.multFT0C()); + histos.fill(HIST("NPVtracks_vs_FT0C"), cols.multNTracksPV(), cols.multFT0C()); + histos.fill(HIST("GlobalMult_vs_FV0A"), nchTracks, cols.multFV0A()); + histos.fill(HIST("Centrality_vs_FV0A"), cols.centFV0A(), cols.multFV0A()); + histos.fill(HIST("CentFT0Ccentrality_vs_GlobalMult"), cols.centFT0C(), nchTracks); + histos.fill(HIST("NPVtracks_vs_GlobalMult"), cols.multNTracksPV(), nchTracks); + } + + void processMonteCarlo(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + + if (isApplySplitRecCol && (RecCols.size() == 0 || RecCols.size() > 1)) { + return; + } + + 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 + } + + 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); + } + } + } + } + + 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); + } + } + } + + 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()); + } + } + + void processppData(ColDataTablepp::iterator const& cols, FilTrackDataTable const& tracks) + { + if (!isEventSelected(cols)) { + return; + } + + histos.fill(HIST("VtxZHist"), cols.posZ()); + histos.fill(HIST("MultPercentileHist"), cols.centFT0M()); + histos.fill(HIST("hdatazvtxmultpp"), cols.posZ(), cols.centFT0M()); + + for (const auto& track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + histos.fill(HIST("PhiVsEtaHistpp"), track.phi(), track.eta()); + histos.fill(HIST("hdatadndetapp"), cols.posZ(), cols.centFT0M(), track.eta(), track.phi(), kGlobalplusITS); + if (track.hasTPC()) { + histos.fill(HIST("hdatadndetapp"), cols.posZ(), cols.centFT0M(), track.eta(), track.phi(), kGlobalonly); + } else { + histos.fill(HIST("hdatadndetapp"), cols.posZ(), cols.centFT0M(), track.eta(), track.phi(), kITSonly); + } + } // track loop + } + + void processppMonteCarlo(CollisionMCTrueTable::iterator const&, ColMCRecTablepp const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + if (isApplySplitRecCol && (RecCols.size() == 0 || RecCols.size() > 1)) { + return; + } + + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + std::vector mclabels; + + histos.fill(HIST("VtxZHist"), RecCol.posZ()); + histos.fill(HIST("MultPercentileMCRecHist"), RecCol.centFT0M()); + histos.fill(HIST("hmczvtxmultpp"), RecCol.posZ(), RecCol.centFT0M()); + + for (const auto& Rectrack : recTracksPart) { + if (!isTrackSelected(Rectrack)) { + continue; + } + histos.fill(HIST("MCrecPhiVsEtaHistpp"), Rectrack.phi(), Rectrack.eta()); + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), RecCol.centFT0M(), Rectrack.eta(), Rectrack.phi(), static_cast(kSpAll), kGlobalplusITS); + if (Rectrack.hasTPC()) { + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), RecCol.centFT0M(), Rectrack.eta(), Rectrack.phi(), static_cast(kSpAll), kGlobalonly); + } else { + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), RecCol.centFT0M(), 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(), RecCol.centFT0M(), Rectrack.eta(), Rectrack.phi(), static_cast(pid), kGlobalplusITS); + } else { + histos.fill(HIST("hmcrecdndetapp"), RecCol.posZ(), RecCol.centFT0M(), Rectrack.eta(), Rectrack.phi(), static_cast(kBkg), kGlobalplusITS); + } + } // track (mcrec) loop + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), RecCol.centFT0M(), particle.eta(), particle.phi(), static_cast(kSpAll), kNoGenpTVar); + if (particle.pt() < KminPtCut) { + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), RecCol.centFT0M(), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup, -10.0 * particle.pt() + 2); + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), RecCol.centFT0M(), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTdown, 5.0 * particle.pt() + 0.5); + } else { + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), RecCol.centFT0M(), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup); + histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), RecCol.centFT0M(), 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(), RecCol.centFT0M(), particle.eta(), particle.phi(), static_cast(pid), kNoGenpTVar); + } // track (mcgen) loop + } // collision loop + } + + void processGen(aod::McCollisions::iterator const&, aod::McParticles const& GenParticles) + { + + int multFT0A = 0; + int multFT0C = 0; + int multBarrelEta10 = 0; + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + if (std::abs(particle.eta()) < 1.0) { + multBarrelEta10++; + } + if (-3.3 < particle.eta() && particle.eta() < -2.1) { + multFT0C++; + } + if (3.5 < particle.eta() && particle.eta() < 4.9) { + multFT0A++; + } + } + + histos.fill(HIST("MultBarrelEta10_vs_FT0A"), multBarrelEta10, multFT0A); + histos.fill(HIST("MultBarrelEta10_vs_FT0C"), multBarrelEta10, multFT0C); + histos.fill(HIST("MultBarrelEta10"), multBarrelEta10); + histos.fill(HIST("MultFT0A"), multFT0A); + histos.fill(HIST("MultFT0C"), multFT0C); + histos.fill(HIST("mult10_vs_FT0A"), multBarrelEta10, multFT0A); + histos.fill(HIST("mult10_vs_FT0C"), multBarrelEta10, multFT0C); + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("dndeta10_vs_FT0A"), particle.eta(), multFT0A); + histos.fill(HIST("dndeta10_vs_FT0C"), particle.eta(), multFT0C); + } + } + + void processEvtLossSigLossMC(soa::Join::iterator const& mcCollision, CollisionMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles) + { + if (isApplyInelgt0 && !mcCollision.isInelGt0()) { + return; + } + if (std::abs(mcCollision.posZ()) >= vtxRange) { + return; + } + // All generated events + histos.fill(HIST("MCEventHist"), 1); + histos.fill(HIST("hImpactParameterGen"), mcCollision.impactParameter()); + + if (RecCols.size() == 0) { + histos.fill(HIST("MCEventHist"), 3); + histos.fill(HIST("hImpactParameterGenwithNoreco"), mcCollision.impactParameter()); + } + + bool atLeastOne = false; + auto centrality = -999.; + auto numcontributors = -999; + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (std::abs(RecCol.posZ()) >= vtxRange) { + continue; + } + if (RecCol.numContrib() <= numcontributors) { + continue; + } else { + numcontributors = RecCol.numContrib(); + } + centrality = selColCent(RecCol); + atLeastOne = true; + } + + // Generated events with at least one reconstructed collision (event loss estimation) + if (atLeastOne) { + histos.fill(HIST("MCEventHist"), 2); + histos.fill(HIST("hImpactParameterRec"), mcCollision.impactParameter()); + histos.fill(HIST("hImpactParvsCentrRec"), centrality, mcCollision.impactParameter()); + } + + for (const auto& particle : GenParticles) { + + if (!isGenTrackSelected(particle)) { + continue; + } + + // All generated particles + histos.fill(HIST("hgendndetaBeforeEvtSel"), particle.eta()); + histos.fill(HIST("hgendndetaVscentBeforeEvtSel"), particle.eta(), mcCollision.impactParameter()); + + if (atLeastOne) { + // All generated particles with at least one reconstructed collision (signal loss estimation) + histos.fill(HIST("hgendndetaAfterEvtSel"), particle.eta()); + histos.fill(HIST("hgendndetaVscentAfterEvtSel"), particle.eta(), mcCollision.impactParameter()); + } + } + } + + void processMCeff(soa::Join::iterator const& mcCollision, CollisionMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + auto gencent = -999; + auto genoccu = -999; + bool atLeastOne = false; + + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (RecCol.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + atLeastOne = true; + gencent = selColCent(RecCol); + genoccu = selColOccu(RecCol); + } + + histos.fill(HIST("hGenMCvertexZ"), mcCollision.posZ()); + histos.fill(HIST("hGenMCvtxzcent"), mcCollision.posZ(), gencent, genoccu); + + if (atLeastOne) { + histos.fill(HIST("hGenMCAssoRecvertexZ"), mcCollision.posZ()); + histos.fill(HIST("hGenMCAssoRecvtxzcent"), mcCollision.posZ(), gencent, genoccu); + } + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hGenMCdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi()); + if (atLeastOne) { + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kNoGenpTVar); + if (particle.pt() < KminPtCut) { + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kGenpTup, -10.0 * particle.pt() + 2); + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kGenpTdown, 5.0 * particle.pt() + 0.5); + } else { + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kGenpTup); + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kGenpTdown); + } + int pid = 0; + switch (std::abs(particle.pdgCode())) { + case PDG_t::kPiPlus: + pid = kGenPion; + break; + case PDG_t::kKPlus: + pid = kGenKaon; + break; + case PDG_t::kProton: + pid = kGenProton; + break; + default: + pid = kGenOther; + break; + } + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(pid), kNoGenpTVar); + } // Associated with reco col + } // track (mcgen) loop + + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (RecCol.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + histos.fill(HIST("hRecMCvertexZ"), RecCol.posZ()); + histos.fill(HIST("hRecMCcentrality"), selColCent(RecCol)); + histos.fill(HIST("hRecMCvtxzcent"), 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("hRecMCphivseta"), Rectrack.phi(), Rectrack.eta()); + histos.fill(HIST("hRecMCdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kRecoAll)); + if (Rectrack.has_mcParticle()) { + int pid = 0; + auto mcpart = Rectrack.mcParticle(); + histos.fill(HIST("etaResolution"), Rectrack.eta(), Rectrack.eta() - mcpart.eta()); + if (mcpart.isPhysicalPrimary()) { + switch (std::abs(mcpart.pdgCode())) { + case PDG_t::kPiPlus: + pid = kRecoPion; + break; + case PDG_t::kKPlus: + pid = kRecoKaon; + break; + case PDG_t::kProton: + pid = kRecoProton; + break; + default: + pid = kRecoOther; + break; + } + } else { + pid = kRecoSecondary; + } + 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 = kRecoWeakDecay; + } + } + if (find(mclabels.begin(), mclabels.end(), Rectrack.mcParticleId()) != mclabels.end()) { + pid = kRecoFake; + } + mclabels.push_back(Rectrack.mcParticleId()); + histos.fill(HIST("hRecMCdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), mcpart.eta(), mcpart.phi(), static_cast(pid)); + } else { + histos.fill(HIST("hRecMCdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kRecoBkg)); + } + } // track (mcrec) loop + } // collision loop + } + + PROCESS_SWITCH(HeavyionMultiplicity, processData, "process data CentFT0C", false); + PROCESS_SWITCH(HeavyionMultiplicity, processCorrelation, "do correlation study in data", false); + PROCESS_SWITCH(HeavyionMultiplicity, processMonteCarlo, "process MC CentFT0C", false); + PROCESS_SWITCH(HeavyionMultiplicity, processMCpTefficiency, "process MC pTefficiency", false); + PROCESS_SWITCH(HeavyionMultiplicity, processMCcheckFakeTracks, "Check Fake tracks", false); + PROCESS_SWITCH(HeavyionMultiplicity, processStrangeYield, "Strange particle yield", false); + PROCESS_SWITCH(HeavyionMultiplicity, processppData, "process pp data", false); + PROCESS_SWITCH(HeavyionMultiplicity, processppMonteCarlo, "process pp MC", false); + PROCESS_SWITCH(HeavyionMultiplicity, processGen, "process pure MC gen", false); + PROCESS_SWITCH(HeavyionMultiplicity, processEvtLossSigLossMC, "process Signal Loss, Event Loss", false); + PROCESS_SWITCH(HeavyionMultiplicity, processMCeff, "process extra efficiency function", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/GlobalEventProperties/studyPnch.cxx b/PWGLF/Tasks/GlobalEventProperties/studyPnch.cxx new file mode 100644 index 00000000000..0392059fa1e --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/studyPnch.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 studyPnch.cxx +/// +/// \brief task for analysis of charged-particle multiplicity distributions +/// \author Abhi Modak (abhi.modak@cern.ch) +/// \since September 10, 2025 + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" + +#include "Common/CCDB/EventSelectionParams.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/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.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 + +#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; + +using ColDataTable = soa::Join; +using TrackDataTable = soa::Join; +using FilTrackDataTable = soa::Filtered; +using ColMCTrueTable = aod::McCollisions; +using TrackMCTrueTable = aod::McParticles; +using ColMCRecTable = soa::SmallGroups>; +using TrackMCRecTable = soa::Join; +using FilTrackMCRecTable = soa::Filtered; + +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{629, 0, o2::constants::math::TwoPI, "#phi"}; +auto static constexpr kMinCharge = 3.f; + +struct StudyPnch { + + 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 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.}, ""}; + + Configurable isApplyTFcut{"isApplyTFcut", true, "Enable TimeFrameBorder cut"}; + Configurable isApplyITSROcut{"isApplyITSROcut", true, "Enable ITS ReadOutFrameBorder cut"}; + Configurable isApplySameBunchPileup{"isApplySameBunchPileup", true, "Enable SameBunchPileup cut"}; + Configurable isApplyInelgt0{"isApplyInelgt0", false, "Enable INEL > 0 condition"}; + Configurable isApplyExtraPhiCut{"isApplyExtraPhiCut", false, "Enable extra phi cut"}; + + 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 axisPt = {ptHistBin, "pT", "pTAxis"}; + + 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, "kIsTriggerTVX"); + x->SetBinLabel(3, "kNoTimeFrameBorder"); + x->SetBinLabel(4, "kNoITSROFrameBorder"); + x->SetBinLabel(5, "kNoSameBunchPileup"); // reject collisions in case of pileup with another collision in the same foundBC + x->SetBinLabel(6, "INEL > 0"); + x->SetBinLabel(7, "|vz| < 10"); + + if (doprocessData || doprocessCorrelation || doprocessMonteCarlo) { + histos.add("PhiVsEtaHist", "PhiVsEtaHist", kTH2F, {axisPhi, axisEta}, false); + } + if (doprocessData) { + histos.add("hMultiplicityData", "hMultiplicityData", kTH1F, {axisMult}, true); + } + 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("GlobalMult_vs_FV0A", "GlobalMult_vs_FV0A", kTH2F, {axisMult, axisFv0aMult}, true); + histos.add("NPVtracks_vs_FT0C", "NPVtracks_vs_FT0C", kTH2F, {axisPV, axisFt0cMult}, true); + histos.add("NPVtracks_vs_GlobalMult", "NPVtracks_vs_GlobalMult", kTH2F, {axisPV, axisMult}, true); + } + if (doprocessMonteCarlo) { + histos.add("hMultiplicityMCrec", "hMultiplicityMCrec", kTH1F, {axisMult}, true); + histos.add("hMultiplicityMCgen", "hMultiplicityMCgen", kTH1F, {axisMult}, true); + histos.add("hResponseMatrix", "hResponseMatrix", kTH2F, {axisMult, axisMult}, true); + } + if (doprocessEvtLossSigLossMC) { + histos.add("MCEventHist", "MCEventHist", kTH1F, {axisEvent}, false); + auto hstat = histos.get(HIST("MCEventHist")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All MC events"); + x->SetBinLabel(2, "MC events with atleast one reco event"); + histos.add("hMultiplicityMCgenAll", "hMultiplicityMCgenAll", kTH1F, {axisMult}, true); + histos.add("hMultiplicityMCgenSel", "hMultiplicityMCgenSel", kTH1F, {axisMult}, true); + } + } + + template + bool isEventSelected(CheckCol const& col) + { + histos.fill(HIST("EventHist"), 1); + if (!col.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + histos.fill(HIST("EventHist"), 2); + if (isApplyTFcut && !col.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + histos.fill(HIST("EventHist"), 3); + if (isApplyITSROcut && !col.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + histos.fill(HIST("EventHist"), 4); + if (isApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("EventHist"), 5); + if (isApplyInelgt0 && !col.isInelGt0()) { + return false; + } + histos.fill(HIST("EventHist"), 6); + if (std::abs(col.posZ()) >= vtxRange) { + return false; + } + histos.fill(HIST("EventHist"), 7); + histos.fill(HIST("VtxZHist"), col.posZ()); + return true; + } + + 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; + } + + template + int countNTracks(countTrk const& tracks) + { + auto nTrk = 0; + for (const auto& track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta()); + nTrk++; + } + return nTrk; + } + + template + int countGenTracks(countTrk const& tracks) + { + auto nTrk = 0; + for (const auto& track : tracks) { + if (!isGenTrackSelected(track)) { + continue; + } + histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta()); + nTrk++; + } + return nTrk; + } + + 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 = ifnode(dcaZ.node() > 0.f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly), + ncheckbit(aod::track::trackCutFlag, TrackSelectionDca)); + + void processData(ColDataTable::iterator const& cols, FilTrackDataTable const& tracks) + { + if (!isEventSelected(cols)) { + return; + } + auto mult = countNTracks(tracks); + histos.fill(HIST("hMultiplicityData"), mult); + } + + void processCorrelation(ColDataTable::iterator const& cols, FilTrackDataTable const& tracks) + { + if (!isEventSelected(cols)) { + return; + } + auto mult = countNTracks(tracks); + histos.fill(HIST("GlobalMult_vs_FT0A"), mult, cols.multFT0A()); + histos.fill(HIST("GlobalMult_vs_FT0C"), mult, cols.multFT0C()); + histos.fill(HIST("GlobalMult_vs_FV0A"), mult, cols.multFV0A()); + histos.fill(HIST("NPVtracks_vs_FT0C"), cols.multNTracksPV(), cols.multFT0C()); + histos.fill(HIST("NPVtracks_vs_GlobalMult"), cols.multNTracksPV(), mult); + } + + void processMonteCarlo(ColMCTrueTable::iterator const&, ColMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + auto multrec = countNTracks(recTracksPart); + histos.fill(HIST("hMultiplicityMCrec"), multrec); + auto multgen = countGenTracks(GenParticles); + histos.fill(HIST("hMultiplicityMCgen"), multgen); + histos.fill(HIST("hResponseMatrix"), multrec, multgen); + } + } + + void processEvtLossSigLossMC(soa::Join::iterator const& mcCollision, ColMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles) + { + if (isApplyInelgt0 && !mcCollision.isInelGt0()) { + return; + } + if (std::abs(mcCollision.posZ()) >= vtxRange) { + return; + } + // All generated events + histos.fill(HIST("MCEventHist"), 1); + auto multAll = countGenTracks(GenParticles); + histos.fill(HIST("hMultiplicityMCgenAll"), multAll); + + bool atLeastOne = false; + auto numcontributors = -999; + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (RecCol.numContrib() <= numcontributors) { + continue; + } else { + numcontributors = RecCol.numContrib(); + } + atLeastOne = true; + } + + if (atLeastOne) { + histos.fill(HIST("MCEventHist"), 2); + auto multSel = countGenTracks(GenParticles); + histos.fill(HIST("hMultiplicityMCgenSel"), multSel); + } + } + + PROCESS_SWITCH(StudyPnch, processData, "process data CentFT0C", false); + PROCESS_SWITCH(StudyPnch, processCorrelation, "do correlation study in data", false); + PROCESS_SWITCH(StudyPnch, processMonteCarlo, "process MC CentFT0C", false); + PROCESS_SWITCH(StudyPnch, processEvtLossSigLossMC, "process Signal Loss, Event Loss", 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..078d8aff97a --- /dev/null +++ b/PWGLF/Tasks/GlobalEventProperties/uccZdc.cxx @@ -0,0 +1,1842 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "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 + +#include "TPDGCode.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + +static constexpr int kSizeBootStrapEnsemble{8}; + +std::array, kSizeBootStrapEnsemble> hPoisson{}; +std::array, kSizeBootStrapEnsemble> hNchVsT0M{}; +std::array, kSizeBootStrapEnsemble> hNchVsV0A{}; +std::array, kSizeBootStrapEnsemble> hNchVsZN{}; + +std::array, kSizeBootStrapEnsemble> pNchVsOneParCorrVsZN{}; +std::array, kSizeBootStrapEnsemble> pNchVsTwoParCorrVsZN{}; +std::array, kSizeBootStrapEnsemble> pNchVsThreeParCorrVsZN{}; + +std::array, kSizeBootStrapEnsemble> pNchVsOneParCorrVsT0M{}; +std::array, kSizeBootStrapEnsemble> pNchVsTwoParCorrVsT0M{}; +std::array, kSizeBootStrapEnsemble> pNchVsThreeParCorrVsT0M{}; + +std::array, kSizeBootStrapEnsemble> pNchVsOneParCorrVsV0A{}; +std::array, kSizeBootStrapEnsemble> pNchVsTwoParCorrVsV0A{}; +std::array, kSizeBootStrapEnsemble> pNchVsThreeParCorrVsV0A{}; + +std::array, kSizeBootStrapEnsemble> pOneParCorrVsNch{}; +std::array, kSizeBootStrapEnsemble> pTwoParCorrVsNch{}; +std::array, kSizeBootStrapEnsemble> pThreeParCorrVsNch{}; + +std::array, kSizeBootStrapEnsemble> hPoissonMC{}; +std::array, kSizeBootStrapEnsemble> hNchGen{}; +std::array, kSizeBootStrapEnsemble> hNch{}; + +std::array, kSizeBootStrapEnsemble> pOneParCorrVsNchGen{}; +std::array, kSizeBootStrapEnsemble> pTwoParCorrVsNchGen{}; +std::array, kSizeBootStrapEnsemble> pThreeParCorrVsNchGen{}; + +struct UccZdc { + + static constexpr float kCollEnergy{2.68}; + static constexpr float kZero{0.}; + static constexpr float kOne{1.}; + static constexpr float kMinCharge{3.f}; + + // Configurables Event Selection + Configurable isNoCollInTimeRangeStrict{"isNoCollInTimeRangeStrict", true, "use isNoCollInTimeRangeStrict?"}; + Configurable isNoCollInTimeRangeStandard{"isNoCollInTimeRangeStandard", false, "use isNoCollInTimeRangeStandard?"}; + Configurable isNoCollInRofStrict{"isNoCollInRofStrict", true, "use isNoCollInRofStrict?"}; + Configurable isNoCollInRofStandard{"isNoCollInRofStandard", false, "use isNoCollInRofStandard?"}; + Configurable isNoHighMultCollInPrevRof{"isNoHighMultCollInPrevRof", true, "use isNoHighMultCollInPrevRof?"}; + Configurable isNoCollInTimeRangeNarrow{"isNoCollInTimeRangeNarrow", false, "use isNoCollInTimeRangeNarrow?"}; + Configurable isOccupancyCut{"isOccupancyCut", true, "Occupancy cut?"}; + Configurable isApplyFT0CbasedOccupancy{"isApplyFT0CbasedOccupancy", false, "T0C Occu cut"}; + Configurable isTDCcut{"isTDCcut", false, "Use TDC cut"}; + Configurable useMidRapNchSel{"useMidRapNchSel", true, "Use mid-rapidit Nch selection"}; + Configurable applyEff{"applyEff", true, "Apply track-by-track efficiency correction"}; + Configurable applyFD{"applyFD", false, "Apply track-by-track feed down correction"}; + Configurable correctNch{"correctNch", true, "Correct also Nch"}; + Configurable skipRecoColGTOne{"skipRecoColGTOne", true, "Remove collisions if reconstructed more than once"}; + Configurable detector4Calibration{"detector4Calibration", "T0M", "Detector for nSigma-Nch rejection"}; + Configurable detectorZDC{"detectorZDC", "ZN", "Detector for Cent. Selec. based on spectator neutrons"}; + + // 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 nSigmaNchCut{"nSigmaNchCut", 1., "nSigma Nch selection"}; + 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 minNchSel{"minNchSel", 5., "min Nch Selection"}; + Configurable evtFracMCcl{"evtFracMCcl", 0.5, "fraction of events for MC closure"}; + + // Track-kinematics selection + Configurable minPt{"minPt", 0.1, "minimum pt of the tracks"}; + Configurable maxPt{"maxPt", 3., "maximum pt of the tracks"}; + Configurable maxPtSpectra{"maxPtSpectra", 50., "maximum pt of the tracks"}; + Configurable minEta{"minEta", -0.8, "minimum eta"}; + Configurable maxEta{"maxEta", +0.8, "maximum eta"}; + + // Configurables, binning + Configurable minNch{"minNch", 0, "Min Nch (|eta|<0.8)"}; + Configurable minZN{"minZN", -0.5, "Min ZN signal"}; + Configurable minTdc{"minTdc", -15.0, "minimum TDC"}; + Configurable arbScale{"arbScale", 100.0, "Scale factor for forward multiplicity"}; + + Configurable maxNch{"maxNch", 3000, "Max Nch (|eta|<0.8)"}; + Configurable maxITSTrack{"maxITSTrack", 6000., "Min ITS tracks"}; + Configurable maxAmpV0A{"maxAmpV0A", 2000, "Max FV0 amp"}; + Configurable maxAmpFT0{"maxAmpFT0", 2500, "Max FT0 amp"}; + Configurable maxAmpFT0A{"maxAmpFT0A", 200, "Max FT0 amp"}; + Configurable maxAmpFT0C{"maxAmpFT0C", 60, "Max FT0 amp"}; + Configurable maxZN{"maxZN", 150, "Max ZN signal"}; + Configurable maxZP{"maxZP", 60, "Max ZP signal"}; + Configurable maxZEM{"maxZEM", 2200, "Max ZEM signal"}; + Configurable maxTdc{"maxTdc", 15.0, "maximum TDC"}; + + Configurable nBinsNch{"nBinsNch", 2501, "N bins Nch (|eta|<0.8)"}; + Configurable nBinsITSTrack{"nBinsITSTrack", 2000, "N bins ITS tracks"}; + Configurable nBinsAmpV0A{"nBinsAmpV0A", 100, "N bins V0A amp"}; + Configurable nBinsAmpFT0{"nBinsAmpFT0", 100, "N bins FT0 amp"}; + Configurable nBinsAmpFT0A{"nBinsAmpFT0A", 100, "N bins FT0A amp"}; + Configurable nBinsAmpFT0C{"nBinsAmpFT0C", 100, "N bins FT0C amp"}; + Configurable nBinsZN{"nBinsZN", 400, "N bins ZN"}; + Configurable nBinsZP{"nBinsZP", 160, "N bins ZP"}; + Configurable nBinsTDC{"nBinsTDC", 150, "nbinsTDC"}; + + 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"}; + + // CCDB paths + Configurable paTHEff{"paTHEff", "Users/o/omvazque/MCcorrection/perTimeStamp/TrackingEff", "base path to the ccdb object"}; + Configurable paTHFD{"paTHFD", "Users/o/omvazque/MCcorrection/perTimeStamp/FeedDown", "base path to the ccdb object"}; + Configurable paTHmeanNch{"paTHmeanNch", "Users/o/omvazque/FitMeanNch_9May2025", "base path to the ccdb object"}; + Configurable paTHsigmaNch{"paTHsigmaNch", "Users/o/omvazque/FitSigmaNch_9May2025", "base path to the ccdb object"}; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + + enum EvCutLabel { + All = 1, + SelEigth, + NoSameBunchPileup, + IsGoodZvtxFT0vsPV, + NoCollInTimeRangeStrict, + NoCollInTimeRangeStandard, + NoCollInRofStrict, + NoCollInRofStandard, + NoHighMultCollInPrevRof, + NoCollInTimeRangeNarrow, + OccuCut, + Centrality, + VtxZ, + Zdc, + TZero, + Tdc, + Zem + }; + + Filter trackFilter = ((aod::track::eta > minEta) && (aod::track::eta < maxEta)); + + // Apply Filters + using TheFilteredTracks = soa::Filtered; + using TheFilteredSimTracks = soa::Filtered; + + // Histograms: Data + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + Service ccdb; + + struct Config { + TH2F* hEfficiency = nullptr; + TH2F* hFeedDown = nullptr; + bool correctionsLoaded = false; + } cfg; + + struct NchConfig { + TH1F* hMeanNch = nullptr; + TH1F* hSigmaNch = nullptr; + bool calibrationsLoaded = false; + } cfgNch; + + int currentRunNumber; + + void init(InitContext const&) + { + currentRunNumber = -1; + const char* tiT0A{"T0A (#times 1/100, 3.5 < #eta < 4.9)"}; + const char* tiT0C{"T0C (#times 1/100, -3.3 < #eta < -2.1)"}; + const char* tiT0M{"T0A+T0C (#times 1/100, -3.3 < #eta < -2.1 and 3.5 < #eta < 4.9)"}; + const char* tiNch{"#it{N}_{ch} (|#eta| < 0.8)"}; + const char* tiNPV{"#it{N}_{PV} (|#eta|<1)"}; + const char* tiV0A{"V0A (#times 1/100, 2.2 < #eta < 5)"}; + const char* tiZNs{"ZNA + ZNC"}; + const char* tiZPs{"ZPA + ZPC"}; + const char* tiPt{"#it{p}_{T} (GeV/#it{c})"}; + const char* tiOneParCorr{"#LT[#it{p}_{T}^{(1)}]#GT (GeV/#it{c})"}; + const char* tiTwoParCorr{"Two-Particle #it{p}_{T} correlation"}; + const char* tiThreeParCorr{"Three-Particle #it{p}_{T} correlation"}; + + // 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{40, -1., +1., "#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("NchUncorrected", Form(";%s;Entries;", tiNch), kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("hEventCounter", ";;Events", kTH1F, {axisEvent}); + registry.add("ExcludedEvtVsFT0M", Form(";%s;Entries;", tiT0M), kTH1F, {{nBinsAmpFT0, 0., maxAmpFT0}}); + registry.add("ExcludedEvtVsFV0A", Form(";%s;Entries;", tiT0M), kTH1F, {{nBinsAmpV0A, 0., maxAmpV0A}}); + registry.add("ExcludedEvtVsNch", Form(";%s;Entries;", tiNch), kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("ExcludedEvtVsNPV", Form(";%s;Entries;", tiNPV), kTH1F, {{nBinsITSTrack, 0, maxITSTrack}}); + registry.add("Nch", Form(";%s;Entries;", tiNch), kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsOneParCorr", Form(";%s;%s;", tiNch, tiOneParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsTwoParCorr", Form(";%s;#LT[#it{p}_{T}^{(2)}]#GT;", tiNch), kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchVsThreeParCorr", Form(";%s;#LT[#it{p}_{T}^{(3)}]#GT;", tiNch), kTProfile, {{nBinsNch, minNch, maxNch}}); + + 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?"); + + if (doprocessZdcCollAss) { + registry.add("NchVsT0M", Form(";%s;%s;", tiNch, tiT0M), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsAmpFT0, 0., maxAmpFT0}}}); + registry.add("NchVsV0A", Form(";%s;%s;", tiNch, tiV0A), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsAmpV0A, 0., maxAmpV0A}}}); + registry.add("NchVsZN", Form(";%s;%s;", tiNch, tiZNs), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + registry.add("NchVsZP", Form(";%s;%s;", tiNch, tiZPs), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZP, minZN, maxZP}}}); + registry.add("NchVsZNVsPt", Form(";%s;%s;%s", tiNch, tiZNs, tiPt), kTH3F, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}, {axisPt}}}); + + registry.add("NchVsOneParCorrVsZN", Form(";%s;%s;%s", tiNch, tiZNs, tiOneParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + registry.add("NchVsTwoParCorrVsZN", Form(";%s;%s;%s", tiNch, tiZNs, tiTwoParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + registry.add("NchVsThreeParCorrVsZN", Form(";%s;%s;%s", tiNch, tiZNs, tiThreeParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + + registry.add("NchVsOneParCorrVsT0M", Form(";%s;%s;%s", tiNch, tiT0M, tiOneParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpFT0, 0., maxAmpFT0}}}); + registry.add("NchVsTwoParCorrVsT0M", Form(";%s;%s;%s", tiNch, tiT0M, tiTwoParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpFT0, 0., maxAmpFT0}}}); + registry.add("NchVsThreeParCorrVsT0M", Form(";%s;%s;%s", tiNch, tiT0M, tiThreeParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpFT0, 0., maxAmpFT0}}}); + + registry.add("NchVsOneParCorrVsV0A", Form(";%s;%s;%s", tiNch, tiV0A, tiOneParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpV0A, 0., maxAmpV0A}}}); + registry.add("NchVsTwoParCorrVsV0A", Form(";%s;%s;%s", tiNch, tiV0A, tiTwoParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpV0A, 0., maxAmpV0A}}}); + registry.add("NchVsThreeParCorrVsV0A", Form(";%s;%s;%s", tiNch, tiV0A, tiThreeParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpV0A, 0., maxAmpV0A}}}); + + for (int i = 0; i < kSizeBootStrapEnsemble; i++) { + hNchVsZN[i] = registry.add(Form("NchVsZN_Rep%d", i), Form(";%s;%s", tiNch, tiZNs), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + hNchVsV0A[i] = registry.add(Form("NchVsV0A_Rep%d", i), Form(";%s;%s", tiNch, tiV0A), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsAmpV0A, 0., maxAmpV0A}}}); + hNchVsT0M[i] = registry.add(Form("NchVsT0M_Rep%d", i), Form(";%s;%s", tiNch, tiT0M), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsAmpFT0, 0., maxAmpFT0}}}); + hPoisson[i] = registry.add(Form("Poisson_Rep%d", i), ";#it{k};Entries", kTH1F, {{11, -0.5, 10.5}}); + + pNchVsOneParCorrVsZN[i] = registry.add(Form("NchVsOneParCorrVsZN_Rep%d", i), Form(";%s;%s;%s", tiNch, tiZNs, tiOneParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + pNchVsTwoParCorrVsZN[i] = registry.add(Form("NchVsTwoParCorrVsZN_Rep%d", i), Form(";%s;%s;%s", tiNch, tiZNs, tiTwoParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + pNchVsThreeParCorrVsZN[i] = registry.add(Form("NchVsThreeParCorrVsZN_Rep%d", i), Form(";%s;%s;%s", tiNch, tiZNs, tiThreeParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + + pNchVsOneParCorrVsT0M[i] = registry.add(Form("NchVsOneParCorrVsT0M_Rep%d", i), Form(";%s;%s;%s", tiNch, tiT0M, tiOneParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpFT0, 0., maxAmpFT0}}}); + pNchVsTwoParCorrVsT0M[i] = registry.add(Form("NchVsTwoParCorrVsT0M_Rep%d", i), Form(";%s;%s;%s", tiNch, tiT0M, tiTwoParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpFT0, 0., maxAmpFT0}}}); + pNchVsThreeParCorrVsT0M[i] = registry.add(Form("NchVsThreeParCorrVsT0M_Rep%d", i), Form(";%s;%s;%s", tiNch, tiT0M, tiThreeParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpFT0, 0., maxAmpFT0}}}); + + pNchVsOneParCorrVsV0A[i] = registry.add(Form("NchVsOneParCorrVsV0A_Rep%d", i), Form(";%s;%s;%s", tiNch, tiV0A, tiOneParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpV0A, 0., maxAmpV0A}}}); + pNchVsTwoParCorrVsV0A[i] = registry.add(Form("NchVsTwoParCorrVsV0A_Rep%d", i), Form(";%s;%s;%s", tiNch, tiV0A, tiTwoParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpV0A, 0., maxAmpV0A}}}); + pNchVsThreeParCorrVsV0A[i] = registry.add(Form("NchVsThreeParCorrVsV0A_Rep%d", i), Form(";%s;%s;%s", tiNch, tiV0A, tiThreeParCorr), kTProfile2D, {{{nBinsNch, minNch, maxNch}, {nBinsAmpV0A, 0., maxAmpV0A}}}); + } + } + + if (doprocessMCclosure) { + registry.add("zPos", ";;Entries;", kTH1F, {axisZpos}); + registry.add("T0Ccent", ";;Entries", kTH1F, {axisCent}); + registry.add("EtaVsPhi", ";#eta;#varphi", kTH2F, {{{axisEta}, {100, -0.1 * PI, +2.1 * PI}}}); + registry.add("ZposVsEta", "", kTProfile, {axisZpos}); + registry.add("sigma1Pt", ";;#sigma(p_{T})/p_{T};", kTProfile, {axisPt}); + registry.add("dcaXYvspT", ";DCA_{xy} (cm);;", kTH2F, {{{50, -1., 1.}, {axisPt}}}); + registry.add("RandomNumber", "", kTH1F, {{50, 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"); + // MC closure + registry.add("NchGen", Form("MC Closure;%s;Entries", tiNch), kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("NchvsOneParCorrGen", Form("MC Closure;%s;%s", tiNch, tiOneParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchvsTwoParCorrGen", Form("MC Closure;%s;%s", tiNch, tiTwoParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + registry.add("NchvsThreeParCorrGen", Form("MC Closure;%s;%s", tiNch, tiThreeParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + // Corrections + registry.add("zPosMC", "Filled at MC closure + Corrections;;Entries;", kTH1F, {axisZpos}); + registry.add("hEventCounterMC", "Event counter", kTH1F, {axisEvent}); + registry.add("nRecColvsCent", "", kTH2F, {{6, -0.5, 5.5}, {{axisCent}}}); + registry.add("Pt_all_ch", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("Pt_ch", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("Pt_pi", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("Pt_ka", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("Pt_pr", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("Pt_sigpos", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("Pt_signeg", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("Pt_re", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("PtMC_ch", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("PtMC_pi", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("PtMC_ka", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("PtMC_pr", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("PtMC_sigpos", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("PtMC_signeg", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("PtMC_re", Form("Corrections;%s;%s", tiNch, tiPt), kTH2F, {{nBinsNch, minNch, maxNch}, {axisPt}}); + registry.add("McNchVsFT0M", Form("Corrections;%s;%s", tiT0M, tiNch), kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsNch, minNch, maxNch}}}); + + auto hECMC = registry.get(HIST("hEventCounterMC")); + auto* x = hECMC->GetXaxis(); + x->SetBinLabel(1, "All"); + x->SetBinLabel(13, "VtxZ cut"); + + for (int i = 0; i < kSizeBootStrapEnsemble; i++) { + + hPoissonMC[i] = registry.add(Form("PoissonMC_Rep%d", i), ";#it{k};Entries", kTH1F, {{11, -0.5, 10.5}}); + hNchGen[i] = registry.add(Form("NchGen_Rep%d", i), Form(";%s;Entries", tiNch), kTH1F, {{nBinsNch, minNch, maxNch}}); + pOneParCorrVsNchGen[i] = registry.add(Form("OneParCorrVsNchGen_Rep%d", i), Form(";%s;%s;", tiNch, tiOneParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + pTwoParCorrVsNchGen[i] = registry.add(Form("TwoParCorrVsNchGen_Rep%d", i), Form(";%s;%s;", tiNch, tiTwoParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + pThreeParCorrVsNchGen[i] = registry.add(Form("ThreeParCorrVsNchGen_Rep%d", i), Form(";%s;%s;", tiNch, tiThreeParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + + hNch[i] = registry.add(Form("Nch_Rep%d", i), Form(";%s;Entries", tiNch), kTH1F, {{nBinsNch, minNch, maxNch}}); + hPoisson[i] = registry.add(Form("Poisson_Rep%d", i), ";#it{k};Entries", kTH1F, {{11, -0.5, 10.5}}); + + pOneParCorrVsNch[i] = registry.add(Form("OneParCorrVsNch_Rep%d", i), Form(";%s;%s;", tiNch, tiOneParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + pTwoParCorrVsNch[i] = registry.add(Form("TwoParCorrVsNch_Rep%d", i), Form(";%s;%s;", tiNch, tiTwoParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + pThreeParCorrVsNch[i] = registry.add(Form("ThreeParCorrVsNch_Rep%d", i), Form(";%s;%s;", tiNch, tiTwoParCorr), kTProfile, {{nBinsNch, minNch, maxNch}}); + } + } + if (doprocessQA) { + registry.add("zPos", ";;Entries;", kTH1F, {axisZpos}); + registry.add("T0Ccent", ";;Entries", kTH1F, {axisCent}); + registry.add("EtaVsPhi", ";#eta;#varphi", kTH2F, {{{axisEta}, {100, -0.1 * PI, +2.1 * PI}}}); + registry.add("ZposVsEta", "", kTProfile, {axisZpos}); + registry.add("sigma1Pt", ";;#sigma(p_{T})/p_{T};", kTProfile, {axisPt}); + registry.add("dcaXYvspT", ";DCA_{xy} (cm);;", kTH2F, {{{50, -1., 1.}, {axisPt}}}); + registry.add("Debunch", ";t_{ZDC}-t_{ZDA};t_{ZDC}+t_{ZDA}", kTH2F, {{{nBinsTDC, minTdc, maxTdc}, {nBinsTDC, minTdc, maxTdc}}}); + registry.add("NchVsFT0M", Form(";%s;%s;", tiT0M, tiNch), kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsNch, minNch, maxNch}}}); + registry.add("NchVsFT0A", Form(";%s;%s;", tiT0A, tiNch), kTH2F, {{{nBinsAmpFT0A, 0., maxAmpFT0A}, {nBinsNch, minNch, maxNch}}}); + registry.add("NchVsFT0C", Form(";%s;%s;", tiT0C, tiNch), kTH2F, {{{nBinsAmpFT0C, 0., maxAmpFT0C}, {nBinsNch, minNch, maxNch}}}); + registry.add("NchVsFV0A", Form(";%s;%s;", tiV0A, tiNch), kTH2F, {{{nBinsAmpV0A, 0., maxAmpV0A}, {nBinsNch, minNch, maxNch}}}); + registry.add("NchVsNPV", ";#it{N}_{PV} (|#eta|<1);ITS+TPC tracks (|#eta|<0.8);", kTH2F, {{{nBinsITSTrack, 0, maxITSTrack}, {nBinsNch, minNch, maxNch}}}); + registry.add("NchVsITStracks", ";ITS trks (|#eta|<0.8);TITS+TPC tracks (|#eta|<0.8);", kTH2F, {{{nBinsITSTrack, 0, maxITSTrack}, {nBinsNch, minNch, maxNch}}}); + registry.add("ZNVsFT0A", Form(";%s;%s;", tiT0A, tiZNs), kTH2F, {{{nBinsAmpFT0A, 0., maxAmpFT0A}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNVsFT0C", Form(";%s;%s;", tiT0C, tiZNs), kTH2F, {{{nBinsAmpFT0C, 0., maxAmpFT0C}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNVsFT0M", Form(";%s;%s;", tiT0M, tiZNs), kTH2F, {{{nBinsAmpFT0, 0., maxAmpFT0}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNAamp", ";ZNA;Entries;", kTH1F, {{nBinsZN, minZN, maxZN}}); + registry.add("ZPAamp", ";ZPA;Entries;", kTH1F, {{nBinsZP, minZN, maxZP}}); + registry.add("ZNCamp", ";ZNC;Entries;", kTH1F, {{nBinsZN, minZN, maxZN}}); + registry.add("ZPCamp", ";ZPC;Entries;", kTH1F, {{nBinsZP, minZN, maxZP}}); + registry.add("ZNAVsZNC", ";ZNC;ZNA", kTH2F, {{{nBinsZN, minZN, maxZN}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZPAVsZPC", ";ZPC;ZPA;", kTH2F, {{{nBinsZP, minZN, maxZP}, {nBinsZP, minZN, maxZP}}}); + registry.add("ZNAVsZPA", ";ZPA;ZNA;", kTH2F, {{{nBinsZP, minZN, maxZP}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNCVsZPC", ";ZPC;ZNC;", kTH2F, {{{nBinsZP, minZN, maxZP}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNVsZEM", ";ZEM;ZNA+ZNC;", kTH2F, {{{nBinsZN, minZN, maxZEM}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNCVsNch", Form(";%s;ZNC;", tiNch), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNAVsNch", Form(";%s;ZNA;", tiNch), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNVsNch", Form(";%s;%s;", tiNch, tiZNs), kTH2F, {{{nBinsNch, minNch, maxNch}, {nBinsZN, minZN, maxZN}}}); + registry.add("ZNDifVsNch", Form(";%s;ZNA-ZNC;", tiNch), kTH2F, {{{nBinsNch, minNch, maxNch}, {100, -50., 50.}}}); + } + + LOG(info) << "\tccdbNoLaterThan=" << ccdbNoLaterThan.value; + LOG(info) << "\tapplyEff=" << applyEff.value; + LOG(info) << "\tapplyFD=" << applyFD.value; + LOG(info) << "\tcorrectNch=" << correctNch.value; + LOG(info) << "\tpaTHEff=" << paTHEff.value; + LOG(info) << "\tpaTHFD=" << paTHFD.value; + LOG(info) << "\tdetectorZDC=" << detectorZDC.value; + LOG(info) << "\tuseMidRapNchSel=" << useMidRapNchSel.value; + LOG(info) << "\tdetector4Calibration=" << detector4Calibration.value; + LOG(info) << "\tnSigmaNchCut=" << nSigmaNchCut.value; + LOG(info) << "\tpaTHmeanNch=" << paTHmeanNch.value; + LOG(info) << "\tpaTHsigmaNch=" << paTHsigmaNch.value; + LOG(info) << "\tminPt=" << minPt.value; + LOG(info) << "\tmaxPt=" << maxPt.value; + LOG(info) << "\tmaxPtSpectra=" << maxPtSpectra.value; + LOG(info) << "\tcurrentRunNumber= " << currentRunNumber; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + } + + 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(); + + double aT0A{0.}; + double aT0C{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); + + double aV0A{0.}; + if (foundBC.has_fv0a()) { + for (const auto& amplitude : foundBC.fv0a().amplitude()) { + aV0A += amplitude; + } + } + + const double nPV{collision.multNTracksPVeta1() / 1.}; + const double normT0M{(aT0A + aT0C) / arbScale}; + const double normV0A{aV0A / arbScale}; + const double normT0A{aT0A / arbScale}; + const double normT0C{aT0C / arbScale}; + float znA{zdc.amplitudeZNA()}; + float znC{zdc.amplitudeZNC()}; + float zpA{zdc.amplitudeZPA()}; + float zpC{zdc.amplitudeZPC()}; + float aZEM1{zdc.amplitudeZEM1()}; + float aZEM2{zdc.amplitudeZEM2()}; + 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}; + znA /= kCollEnergy; + znC /= kCollEnergy; + zpA /= kCollEnergy; + zpC /= kCollEnergy; + 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); + } + + int itsTracks = 0, glbTracks = 0; + for (const auto& track : tracks) { + if (track.hasITS() && ((track.eta() > minEta) && (track.eta() < maxEta))) { + itsTracks++; + } + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + glbTracks++; + } + + bool skipEvent{false}; + if (useMidRapNchSel) { + + const int nextRunNumber{foundBC.runNumber()}; + if (currentRunNumber != nextRunNumber) { + loadNchCalibrations(foundBC.timestamp()); + currentRunNumber = nextRunNumber; + LOG(info) << "\tcurrentRunNumber= " << currentRunNumber << " timeStamp = " << foundBC.timestamp(); + } + + if (!(cfgNch.hMeanNch && cfgNch.hSigmaNch)) + return; + + TString s1 = TString(detector4Calibration.value); + double xEval{1.}; + if (s1 == "T0M") { + xEval = normT0M; + } + if (s1 == "V0A") { + xEval = normV0A; + } + if (s1 == "NPV") { + xEval = nPV; + } + + const int bin4Calibration{cfgNch.hMeanNch->FindBin(xEval)}; + const double meanNch{cfgNch.hMeanNch->GetBinContent(bin4Calibration)}; + const double sigmaNch{cfgNch.hSigmaNch->GetBinContent(bin4Calibration)}; + const double nSigmaSelection{nSigmaNchCut * sigmaNch}; + const double diffMeanNch{meanNch - glbTracks}; + + if (std::abs(diffMeanNch) > nSigmaSelection) { + registry.fill(HIST("ExcludedEvtVsFT0M"), normT0M); + registry.fill(HIST("ExcludedEvtVsFV0A"), normV0A); + registry.fill(HIST("ExcludedEvtVsNch"), glbTracks); + registry.fill(HIST("ExcludedEvtVsNPV"), nPV); + skipEvent = true; + } + } + + if (useMidRapNchSel && skipEvent) { + return; + } + + double sumpt{0.}; + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + 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()); + sumpt += track.pt(); + } + + registry.fill(HIST("zPos"), collision.posZ()); + registry.fill(HIST("T0Ccent"), collision.centFT0C()); + registry.fill(HIST("Debunch"), tZDCdif, tZDCsum); + registry.fill(HIST("NchVsFV0A"), normV0A, glbTracks); + registry.fill(HIST("NchVsFT0A"), normT0A, glbTracks); + registry.fill(HIST("NchVsFT0C"), normT0C, glbTracks); + registry.fill(HIST("NchVsFT0M"), normT0M, glbTracks); + registry.fill(HIST("NchUncorrected"), glbTracks); + registry.fill(HIST("Nch"), glbTracks); + registry.fill(HIST("NchVsNPV"), collision.multNTracksPVeta1(), glbTracks); + registry.fill(HIST("NchVsITStracks"), itsTracks, glbTracks); + if (glbTracks >= minNchSel) + registry.fill(HIST("NchVsOneParCorr"), glbTracks, sumpt / glbTracks); + + // ZEM cut + if (sumZEMs > zemCut) { + registry.fill(HIST("hEventCounter"), EvCutLabel::Zem); + registry.fill(HIST("ZNAamp"), znA); + registry.fill(HIST("ZNCamp"), znC); + registry.fill(HIST("ZPAamp"), zpA); + registry.fill(HIST("ZPCamp"), zpC); + 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("ZNVsFT0A"), normT0A, sumZNs); + registry.fill(HIST("ZNVsFT0C"), normT0C, sumZNs); + registry.fill(HIST("ZNVsFT0M"), normT0M, sumZNs); + 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(); + // LOGF(info, "Getting object %s for run number %i from timestamp=%llu", paTH.value.data(), foundBC.runNumber(), foundBC.timestamp()); + + // has ZDC? + if (!foundBC.has_zdc()) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Zdc); + + double aT0A{0.}; + double aT0C{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); + + double aV0A{0.}; + if (foundBC.has_fv0a()) { + for (const auto& amplitude : foundBC.fv0a().amplitude()) { + aV0A += amplitude; + } + } + + const double nPV{collision.multNTracksPVeta1() / 1.}; + const double normT0M{(aT0A + aT0C) / arbScale}; + const double normV0A{aV0A / arbScale}; + float znA{foundBC.zdc().amplitudeZNA()}; + float znC{foundBC.zdc().amplitudeZNC()}; + float zpA{foundBC.zdc().amplitudeZPA()}; + float zpC{foundBC.zdc().amplitudeZPC()}; + 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 /= kCollEnergy; + znC /= kCollEnergy; + zpA /= kCollEnergy; + zpC /= kCollEnergy; + double sumZNs{-999.}; + const double sumZPs{zpA + zpC}; + const double sumZEMs{aZEM1 + aZEM2}; + + TString sZDC = TString(detectorZDC.value); + if (sZDC == "ZNA") { + sumZNs = znA; + } else if (sZDC == "ZNC") { + sumZNs = znC; + } else { + sumZNs = (znA + znC); + } + + // TDC cut + if (isTDCcut) { + if (std::sqrt(std::pow(tZDCdif, 2.) + std::pow(tZDCsum, 2.)) > tdcCut) { + return; + } + registry.fill(HIST("hEventCounter"), EvCutLabel::Tdc); + } + + // Nch-based selection + double glbTracks{0.0}; + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + glbTracks += 1.0; + } + + bool skipEvent{false}; + if (useMidRapNchSel) { + + const int nextRunNumber{foundBC.runNumber()}; + if (currentRunNumber != nextRunNumber) { + loadNchCalibrations(foundBC.timestamp()); + currentRunNumber = nextRunNumber; + LOG(info) << "\tcurrentRunNumber= " << currentRunNumber << " timeStamp = " << foundBC.timestamp(); + } + + if (!(cfgNch.hMeanNch && cfgNch.hSigmaNch)) + return; + + TString s1 = TString(detector4Calibration.value); + double xEval{1.}; + if (s1 == "T0M") { + xEval = normT0M; + } + if (s1 == "V0A") { + xEval = normV0A; + } + if (s1 == "NPV") { + xEval = nPV; + } + + const int bin4Calibration{cfgNch.hMeanNch->FindBin(xEval)}; + const double meanNch{cfgNch.hMeanNch->GetBinContent(bin4Calibration)}; + const double sigmaNch{cfgNch.hSigmaNch->GetBinContent(bin4Calibration)}; + const double nSigmaSelection{nSigmaNchCut * sigmaNch}; + const double diffMeanNch{meanNch - glbTracks}; + + if (std::abs(diffMeanNch) > nSigmaSelection) { + registry.fill(HIST("ExcludedEvtVsFT0M"), normT0M); + registry.fill(HIST("ExcludedEvtVsFV0A"), normV0A); + registry.fill(HIST("ExcludedEvtVsNch"), glbTracks); + registry.fill(HIST("ExcludedEvtVsNPV"), nPV); + skipEvent = true; + } + } + + // Skip event based on number of Nch sigmas + if (useMidRapNchSel && skipEvent) { + return; + } + + // Reject low-multiplcicity events + if (glbTracks < minNchSel) { + return; + } + + double nchMult{glbTracks}; + std::vector pTs; + std::vector vecFD; + std::vector vecEff; + + // apply corrections + if (applyEff || applyFD) { + nchMult = 0.; + loadCorrections(foundBC.timestamp()); + if (!(cfg.hEfficiency && cfg.hFeedDown)) + return; + + const int foundNchBin{cfg.hEfficiency->GetXaxis()->FindBin(glbTracks)}; + + // Calculates the Corrected Nch + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + + const float pt{track.pt()}; + const int foundPtBin{cfg.hEfficiency->GetYaxis()->FindBin(pt)}; + const double effValue{cfg.hEfficiency->GetBinContent(foundNchBin, foundPtBin)}; + double fdValue{1.}; + + if (applyFD) + fdValue = cfg.hFeedDown->GetBinContent(foundNchBin, foundPtBin); + + if ((effValue > 0.) && (fdValue > 0.)) { + nchMult += (std::pow(effValue, -1.) * fdValue); + } + } + + if (applyEff && !correctNch) { + nchMult = glbTracks; + } + + // Reject low-multiplcicity events + if (nchMult < minNchSel) { + return; + } + + // Fill vectors for [pT] measurement + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + + const float pt{track.pt()}; + const int foundPtBin{cfg.hEfficiency->GetYaxis()->FindBin(pt)}; + const double effValue{cfg.hEfficiency->GetBinContent(foundNchBin, foundPtBin)}; + double fdValue{1.}; + + if (applyFD) + fdValue = cfg.hFeedDown->GetBinContent(foundNchBin, foundPtBin); + + if ((effValue > 0.) && (fdValue > 0.)) { + pTs.emplace_back(pt); + vecEff.emplace_back(effValue); + vecFD.emplace_back(fdValue); + // To calculate event-averaged + registry.fill(HIST("NchVsZNVsPt"), nchMult, sumZNs, pt * (fdValue / effValue)); + } + } + } else { + // Fill vectors for [pT] measurement + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + + pTs.emplace_back(track.pt()); + vecEff.emplace_back(1.); + vecFD.emplace_back(1.); + // To calculate event-averaged + registry.fill(HIST("NchVsZNVsPt"), nchMult, sumZNs, track.pt()); + } + } + + double p1, p2, p3, p4, w1, w2, w3, w4; + p1 = p2 = p3 = p4 = w1 = w2 = w3 = w4 = 0.0; + getPTpowers(pTs, vecEff, vecFD, p1, w1, p2, w2, p3, w3, p4, w4); + + // EbE one-particle pT correlation + const double oneParCorr{p1 / w1}; + + // EbE two-particle pT correlation + const double denTwoParCorr{std::pow(w1, 2.) - w2}; + const double numTwoParCorr{std::pow(p1, 2.) - p2}; + const double twoParCorr{numTwoParCorr / denTwoParCorr}; + + // EbE three-particle pT correlation + 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 threeParCorr{numThreeParCorr / denThreeParCorr}; + + // One-dimensional distributions + registry.fill(HIST("Nch"), nchMult); + registry.fill(HIST("NchUncorrected"), glbTracks); + registry.fill(HIST("NchVsV0A"), nchMult, normV0A); + registry.fill(HIST("NchVsT0M"), nchMult, normT0M); + + registry.fill(HIST("NchVsOneParCorr"), nchMult, oneParCorr); + registry.fill(HIST("NchVsTwoParCorr"), nchMult, twoParCorr); + registry.fill(HIST("NchVsThreeParCorr"), nchMult, threeParCorr); + + registry.fill(HIST("NchVsOneParCorrVsT0M"), nchMult, normT0M, oneParCorr); + registry.fill(HIST("NchVsTwoParCorrVsT0M"), nchMult, normT0M, twoParCorr); + registry.fill(HIST("NchVsThreeParCorrVsT0M"), nchMult, normT0M, threeParCorr); + + registry.fill(HIST("NchVsOneParCorrVsV0A"), nchMult, normV0A, oneParCorr); + registry.fill(HIST("NchVsTwoParCorrVsV0A"), nchMult, normV0A, twoParCorr); + registry.fill(HIST("NchVsThreeParCorrVsV0A"), nchMult, normV0A, threeParCorr); + + if (sumZEMs > zemCut) { + registry.fill(HIST("hEventCounter"), EvCutLabel::Zem); + registry.fill(HIST("NchVsZN"), nchMult, sumZNs); + registry.fill(HIST("NchVsZP"), nchMult, sumZPs); + registry.fill(HIST("NchVsOneParCorrVsZN"), nchMult, sumZNs, oneParCorr); + registry.fill(HIST("NchVsTwoParCorrVsZN"), nchMult, sumZNs, twoParCorr); + registry.fill(HIST("NchVsThreeParCorrVsZN"), nchMult, sumZNs, threeParCorr); + } + + const uint64_t timeStamp{foundBC.timestamp()}; + eventSampling(tracks, normV0A, normT0M, sumZNs, sumZEMs, timeStamp); + } + PROCESS_SWITCH(UccZdc, processZdcCollAss, "Process ZDC W/Coll Ass.", true); + + Preslice perCollision = aod::track::collisionId; + Service pdg; + void processMCclosure(aod::McCollisions::iterator const& mccollision, soa::SmallGroups const& collisions, o2::aod::BCsRun3 const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, aod::McParticles const& mcParticles, TheFilteredSimTracks const& simTracks) + { + for (const auto& collision : collisions) { + // Event selection + if (!isEventSelected(collision)) { + continue; + } + // MC collision? + if (!collision.has_mcCollision()) { + continue; + } + + registry.fill(HIST("hEventCounterMC"), EvCutLabel::All); + // Vtx_z selection MC + if (std::fabs(mccollision.posZ()) > posZcut) { + continue; + } + + const auto& foundBC = collision.foundBC_as(); + + uint64_t timeStamp{foundBC.timestamp()}; + TRandom3 rndGen(timeStamp); + const double rndNum{rndGen.Uniform(0.0, 1.0)}; + registry.fill(HIST("RandomNumber"), rndNum); + + double aT0A = 0., aT0C = 0.; + if (foundBC.has_ft0()) { + for (const auto& amplitude : foundBC.ft0().amplitudeA()) { + aT0A += amplitude; + } + for (const auto& amplitude : foundBC.ft0().amplitudeC()) { + aT0C += amplitude; + } + } else { + continue; + } + + const double normT0M{(aT0A + aT0C) / arbScale}; + double nchRaw{0.}; + double nchMult{0.}; + double nchMC{0.}; + + registry.fill(HIST("zPos"), collision.posZ()); + registry.fill(HIST("zPosMC"), mccollision.posZ()); + registry.fill(HIST("hEventCounterMC"), EvCutLabel::VtxZ); + + if (skipRecoColGTOne && (collisions.size() > kOne)) { + continue; + } + + 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())}; + + // Half of the statistics for MC closure + if (rndNum >= kZero && rndNum < evtFracMCcl) { + + registry.fill(HIST("EvtsDivided"), 0); + + // Run-by-run efficiency + loadCorrections(foundBC.timestamp()); + if (!(cfg.hEfficiency && cfg.hFeedDown)) { + continue; + } + + std::vector pTs; + std::vector vecFD; + std::vector vecEff; + + // Calculates the event's Nch to evaluate the efficiency + for (const auto& track : groupedTracks) { + // Track Selection + if (track.eta() < minEta || track.eta() > maxEta) { + continue; + } + if (track.pt() < minPt || track.pt() > maxPt) { + continue; + } + if (!track.isGlobalTrack()) { + continue; + } + nchRaw++; + } + + // Reject event if nchRaw less than a lower cutoff + if (nchRaw < minNchSel) { + continue; + } + + const int foundNchBin{cfg.hEfficiency->GetXaxis()->FindBin(nchRaw)}; + + // Calculates the event weight, W_k + for (const auto& track : groupedTracks) { + // Track Selection + if (track.eta() < minEta || track.eta() > maxEta) { + continue; + } + if (track.pt() < minPt || track.pt() > maxPtSpectra) { + continue; + } + if (!track.isGlobalTrack()) { + continue; + } + if (!track.has_mcParticle()) { + continue; + } + const auto& particle{track.mcParticle()}; + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) { + continue; + } + + const double pt{static_cast(track.pt())}; + const int foundPtBin{cfg.hEfficiency->GetYaxis()->FindBin(pt)}; + const double effValue{cfg.hEfficiency->GetBinContent(foundNchBin, foundPtBin)}; + double fdValue{1.}; + + if (applyFD) + fdValue = cfg.hFeedDown->GetBinContent(foundNchBin, foundPtBin); + if ((effValue > 0.) && (fdValue > 0.)) { + pTs.emplace_back(pt); + vecEff.emplace_back(effValue); + vecFD.emplace_back(fdValue); + nchMult += (std::pow(effValue, -1.0) * fdValue); + } + } + + double p1, p2, p3, p4, w1, w2, w3, w4; + p1 = p2 = p3 = p4 = w1 = w2 = w3 = w4 = 0.0; + getPTpowers(pTs, vecEff, vecFD, 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 oneParCorr{p1 / w1}; + const double twoParCorr{numTwoParCorr / denTwoParCorr}; + const double threeParCorr{numThreeParCorr / denThreeParCorr}; + + registry.fill(HIST("Nch"), nchMult); + registry.fill(HIST("NchUncorrected"), nchRaw); + registry.fill(HIST("NchVsOneParCorr"), nchMult, oneParCorr); + registry.fill(HIST("NchVsTwoParCorr"), nchMult, twoParCorr); + registry.fill(HIST("NchVsThreeParCorr"), nchMult, threeParCorr); + + //--------------------------- Generated MC --------------------------- + std::vector pTsMC; + std::vector vecFullEff; + std::vector vecFDEqualOne; + + // calculates the true Nch + for (const auto& particle : mcParticles) { + if (particle.eta() < minEta || particle.eta() > maxEta) { + continue; + } + if (particle.pt() < minPt || particle.pt() > maxPt) { + continue; + } + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) { + continue; + } + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + nchMC++; + } + + if (nchMC < minNchSel) { + continue; + } + + // 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() > maxPtSpectra) { + continue; + } + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) { + continue; + } + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + + const float pt{particle.pt()}; + pTsMC.emplace_back(pt); + vecFullEff.emplace_back(1.); + vecFDEqualOne.emplace_back(1.); + } + + double p1MC, p2MC, p3MC, p4MC, w1MC, w2MC, w3MC, w4MC; + p1MC = p2MC = p3MC = p4MC = w1MC = w2MC = w3MC = w4MC = 0.0; + getPTpowers(pTsMC, vecFullEff, vecFDEqualOne, 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 oneParCorrMC{p1MC / w1MC}; + const double twoParCorrMC{numTwoParCorrMC / denTwoParCorrMC}; + const double threeParCorrMC{numThreeParCorrMC / denThreeParCorrMC}; + + registry.fill(HIST("NchGen"), nchMC); + registry.fill(HIST("NchvsOneParCorrGen"), nchMC, oneParCorrMC); + registry.fill(HIST("NchvsTwoParCorrGen"), nchMC, twoParCorrMC); + registry.fill(HIST("NchvsThreeParCorrGen"), nchMC, threeParCorrMC); + + //------------------ Poisson sampling + eventSamplingMC(mcParticles, timeStamp); + eventSamplingMCRec(groupedTracks, timeStamp); + } else { // Correction with the remaining half of the sample + registry.fill(HIST("EvtsDivided"), 1); + //----- MC reconstructed -----// + for (const auto& track : groupedTracks) { + // Track Selection + if (track.eta() < minEta || track.eta() > maxEta) { + continue; + } + if (track.pt() < minPt || track.pt() > maxPt) { + continue; + } + if (!track.isGlobalTrack()) { + continue; + } + nchRaw++; + } + + for (const auto& track : groupedTracks) { + // Track Selection + if (track.eta() < minEta || track.eta() > maxEta) { + continue; + } + if (track.pt() < minPt || track.pt() > maxPtSpectra) { + continue; + } + if (!track.isGlobalTrack()) { + continue; + } + // Has MC particle? + if (!track.has_mcParticle()) { + continue; + } + // Get the MC particle + const auto& particle{track.mcParticle()}; + auto charge{0.}; + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) { + continue; + } + + // All charged particles + registry.fill(HIST("Pt_all_ch"), nchRaw, track.pt()); + registry.fill(HIST("ZposVsEta"), collision.posZ(), track.eta()); + registry.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); + registry.fill(HIST("dcaXYvspT"), track.dcaXY(), track.pt()); + + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + + registry.fill(HIST("Pt_ch"), nchRaw, track.pt()); + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("Pt_pi"), nchRaw, track.pt()); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("Pt_ka"), nchRaw, track.pt()); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("Pt_pr"), nchRaw, track.pt()); + } else if (particle.pdgCode() == PDG_t::kSigmaPlus || particle.pdgCode() == PDG_t::kSigmaBarMinus) { + registry.fill(HIST("Pt_sigpos"), nchRaw, track.pt()); + } else if (particle.pdgCode() == PDG_t::kSigmaMinus || particle.pdgCode() == PDG_t::kSigmaBarPlus) { + registry.fill(HIST("Pt_signeg"), nchRaw, track.pt()); + } else { + registry.fill(HIST("Pt_re"), nchRaw, track.pt()); + } + } + + // Generated MC + for (const auto& particle : mcParticles) { + if (particle.eta() < minEta || particle.eta() > maxEta) { + continue; + } + if (particle.pt() < minPt || particle.pt() > maxPtSpectra) { + continue; + } + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) { + continue; + } + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + + registry.fill(HIST("PtMC_ch"), nchRaw, particle.pt()); + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { // pion + registry.fill(HIST("PtMC_pi"), nchRaw, particle.pt()); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { // kaon + registry.fill(HIST("PtMC_ka"), nchRaw, particle.pt()); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { // proton + registry.fill(HIST("PtMC_pr"), nchRaw, particle.pt()); + } else if (particle.pdgCode() == PDG_t::kSigmaPlus || particle.pdgCode() == PDG_t::kSigmaBarMinus) { // positive sigma + registry.fill(HIST("PtMC_sigpos"), nchRaw, particle.pt()); + } else if (particle.pdgCode() == PDG_t::kSigmaMinus || particle.pdgCode() == PDG_t::kSigmaBarPlus) { // negative sigma + registry.fill(HIST("PtMC_signeg"), nchRaw, particle.pt()); + } else { // rest + registry.fill(HIST("PtMC_re"), nchRaw, particle.pt()); + } + } + } // Half of statistics for corrections + registry.fill(HIST("McNchVsFT0M"), normT0M, nchRaw); + } // Collisions + } + PROCESS_SWITCH(UccZdc, processMCclosure, "Process MC closure", false); + + template + void getPTpowers(const T& pTs, const T& vecEff, const T& vecFD, 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 double pTi{pTs.at(i)}; + const double eFFi{vecEff.at(i)}; + const double fDi{vecFD.at(i)}; + const double wEighti{std::pow(eFFi, -1.) * fDi}; + 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.); + } + } + + template + void eventSamplingMC(const T& mcParticles, const V& timeStamp) + { + TRandom3 rndGen(timeStamp); + std::vector vPoisson; + for (int replica = 0; replica < kSizeBootStrapEnsemble; ++replica) + vPoisson.emplace_back(rndGen.Poisson(1.)); + + for (int replica = 0; replica < kSizeBootStrapEnsemble; ++replica) { + + hPoissonMC[replica]->Fill(vPoisson.at(replica)); + + for (uint64_t evtRep = 0; evtRep < vPoisson.at(replica); ++evtRep) { + + double nchMult{0.}; + std::vector pTs; + std::vector vecFD; + std::vector vecEff; + + // Calculates the true Nch + for (const auto& particle : mcParticles) { + if (particle.eta() < minEta || particle.eta() > maxEta) { + continue; + } + if (particle.pt() < minPt || particle.pt() > maxPt) { + continue; + } + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) { + continue; + } + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + nchMult++; + } + + if (nchMult < minNchSel) { + continue; + } + + // 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() > maxPtSpectra) { + continue; + } + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) { + continue; + } + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + + const float pt{particle.pt()}; + pTs.emplace_back(pt); + vecEff.emplace_back(1.); + vecFD.emplace_back(1.); + } + + double p1, p2, p3, p4, w1, w2, w3, w4; + p1 = p2 = p3 = p4 = w1 = w2 = w3 = w4 = 0.0; + getPTpowers(pTs, vecEff, vecFD, p1, w1, p2, w2, p3, w3, p4, w4); + + // EbE one-particle pT correlation + const double oneParCorr{p1 / w1}; + + // EbE two-particle pT correlation + const double denTwoParCorr{std::pow(w1, 2.) - w2}; + const double numTwoParCorr{std::pow(p1, 2.) - p2}; + const double twoParCorr{numTwoParCorr / denTwoParCorr}; + + // EbE three-particle pT correlation + 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 threeParCorr{numThreeParCorr / denThreeParCorr}; + + hNchGen[replica]->Fill(nchMult); + pOneParCorrVsNchGen[replica]->Fill(nchMult, oneParCorr); + pTwoParCorrVsNchGen[replica]->Fill(nchMult, twoParCorr); + pThreeParCorrVsNchGen[replica]->Fill(nchMult, threeParCorr); + } // event per replica + } // replica's loop + } + + template + void eventSamplingMCRec(const T& tracks, const V& timeStamp) + { + TRandom3 rndGen(timeStamp); + std::vector vPoisson; + for (int replica = 0; replica < kSizeBootStrapEnsemble; ++replica) + vPoisson.emplace_back(rndGen.Poisson(1.)); + + for (int replica = 0; replica < kSizeBootStrapEnsemble; ++replica) { + + hPoisson[replica]->Fill(vPoisson.at(replica)); + + for (uint64_t evtRep = 0; evtRep < vPoisson.at(replica); ++evtRep) { + + double nchMult{0.}; + int glbTracks{0}; + std::vector pTs; + std::vector vecFD; + std::vector vecEff; + + // Calculates the uncorrected Nch + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + glbTracks++; + } + + if (glbTracks < minNchSel) { + continue; + } + + // Calculates the Nch multiplicity if corrections are loaded + if (cfg.correctionsLoaded) { + const int foundNchBin{cfg.hEfficiency->GetXaxis()->FindBin(glbTracks)}; + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + + const float pt{track.pt()}; + double fdValue{1.}; + const int foundPtBin{cfg.hEfficiency->GetYaxis()->FindBin(pt)}; + const double effValue{cfg.hEfficiency->GetBinContent(foundNchBin, foundPtBin)}; + + if (applyFD) + fdValue = cfg.hFeedDown->GetBinContent(foundNchBin, foundPtBin); + if ((effValue > 0.) && (fdValue > 0.)) { + nchMult += (std::pow(effValue, -1.) * fdValue); + } + } + } + + if (!applyEff) + nchMult = static_cast(glbTracks); + if (applyEff && !correctNch) + nchMult = static_cast(glbTracks); + + // Fill vectors for [pT] measurement + if (cfg.correctionsLoaded) { + const int foundNchBin{cfg.hEfficiency->GetXaxis()->FindBin(glbTracks)}; + // Fill vectors for [pT] measurement + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + + const float pt{track.pt()}; + double fdValue{1.}; + const int foundPtBin{cfg.hEfficiency->GetYaxis()->FindBin(pt)}; + const double effValue{cfg.hEfficiency->GetBinContent(foundNchBin, foundPtBin)}; + + if (applyFD) + fdValue = cfg.hFeedDown->GetBinContent(foundNchBin, foundPtBin); + + if ((effValue > 0.) && (fdValue > 0.)) { + pTs.emplace_back(pt); + vecEff.emplace_back(effValue); + vecFD.emplace_back(fdValue); + } + } + } else { + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + + pTs.emplace_back(track.pt()); + vecEff.emplace_back(1.); + vecFD.emplace_back(1.); + } + } + + double p1, p2, p3, p4, w1, w2, w3, w4; + p1 = p2 = p3 = p4 = w1 = w2 = w3 = w4 = 0.0; + getPTpowers(pTs, vecEff, vecFD, p1, w1, p2, w2, p3, w3, p4, w4); + + // EbE one-particle pT correlation + const double oneParCorr{p1 / w1}; + + // EbE two-particle pT correlation + const double denTwoParCorr{std::pow(w1, 2.) - w2}; + const double numTwoParCorr{std::pow(p1, 2.) - p2}; + const double twoParCorr{numTwoParCorr / denTwoParCorr}; + + // EbE three-particle pT correlation + 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 threeParCorr{numThreeParCorr / denThreeParCorr}; + + hNch[replica]->Fill(nchMult); + pOneParCorrVsNch[replica]->Fill(nchMult, oneParCorr); + pTwoParCorrVsNch[replica]->Fill(nchMult, twoParCorr); + pThreeParCorrVsNch[replica]->Fill(nchMult, threeParCorr); + } // event per replica + } // replica's loop + } + + template + void eventSampling(const T& tracks, const U& normV0A, const U& normT0M, const U& sumZNs, const U& sumZEMs, const V& timeStamp) + { + TRandom3 rndGen(timeStamp); + std::vector vPoisson; + for (int replica = 0; replica < kSizeBootStrapEnsemble; ++replica) + vPoisson.emplace_back(rndGen.Poisson(1.)); + + for (int replica = 0; replica < kSizeBootStrapEnsemble; ++replica) { + + hPoisson[replica]->Fill(vPoisson.at(replica)); + + for (uint64_t evtRep = 0; evtRep < vPoisson.at(replica); ++evtRep) { + + double nchMult{0.}; + int glbTracks{0}; + std::vector pTs; + std::vector vecFD; + std::vector vecEff; + + // Calculates the uncorrected Nch multiplicity + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + glbTracks++; + } + + if (glbTracks < minNchSel) { + continue; + } + + // Calculates the Nch multiplicity if corrections are loaded + if (cfg.correctionsLoaded) { + const int foundNchBin{cfg.hEfficiency->GetXaxis()->FindBin(glbTracks)}; + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPt)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + + float pt{track.pt()}; + double fdValue{1.}; + int foundPtBin{cfg.hEfficiency->GetYaxis()->FindBin(pt)}; + double effValue{cfg.hEfficiency->GetBinContent(foundNchBin, foundPtBin)}; + + if (applyFD) + fdValue = cfg.hFeedDown->GetBinContent(foundNchBin, foundPtBin); + if ((effValue > 0.) && (fdValue > 0.)) { + nchMult += (std::pow(effValue, -1.) * fdValue); + } + } + } + + if (!applyEff) + nchMult = static_cast(glbTracks); + if (applyEff && !correctNch) + nchMult = static_cast(glbTracks); + + // Fill vectors for [pT] measurement + if (cfg.correctionsLoaded) { + const int foundNchBin{cfg.hEfficiency->GetXaxis()->FindBin(glbTracks)}; + // Fill vectors for [pT] measurement + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + if ((track.eta() < minEta) || (track.eta() > maxEta)) { + continue; + } + + float pt{track.pt()}; + double fdValue{1.}; + int foundPtBin{cfg.hEfficiency->GetYaxis()->FindBin(pt)}; + double effValue{cfg.hEfficiency->GetBinContent(foundNchBin, foundPtBin)}; + + if (applyFD) + fdValue = cfg.hFeedDown->GetBinContent(foundNchBin, foundPtBin); + + if ((effValue > 0.) && (fdValue > 0.)) { + pTs.emplace_back(pt); + vecEff.emplace_back(effValue); + vecFD.emplace_back(fdValue); + } + } + } else { + for (const auto& track : tracks) { + // Track Selection + if (!track.isGlobalTrack()) { + continue; + } + if ((track.pt() < minPt) || (track.pt() > maxPtSpectra)) { + continue; + } + + pTs.emplace_back(track.pt()); + vecEff.emplace_back(1.); + vecFD.emplace_back(1.); + } + } + + double p1, p2, p3, p4, w1, w2, w3, w4; + p1 = p2 = p3 = p4 = w1 = w2 = w3 = w4 = 0.0; + getPTpowers(pTs, vecEff, vecFD, p1, w1, p2, w2, p3, w3, p4, w4); + + // EbE one-particle pT correlation + const double oneParCorr{p1 / w1}; + + // EbE two-particle pT correlation + const double denTwoParCorr{std::pow(w1, 2.) - w2}; + const double numTwoParCorr{std::pow(p1, 2.) - p2}; + const double twoParCorr{numTwoParCorr / denTwoParCorr}; + + // EbE three-particle pT correlation + 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 threeParCorr{numThreeParCorr / denThreeParCorr}; + + hNchVsV0A[replica]->Fill(nchMult, normV0A); + hNchVsT0M[replica]->Fill(nchMult, normT0M); + + pNchVsOneParCorrVsT0M[replica]->Fill(nchMult, normT0M, oneParCorr); + pNchVsTwoParCorrVsT0M[replica]->Fill(nchMult, normT0M, twoParCorr); + pNchVsThreeParCorrVsT0M[replica]->Fill(nchMult, normT0M, threeParCorr); + + pNchVsOneParCorrVsV0A[replica]->Fill(nchMult, normV0A, oneParCorr); + pNchVsTwoParCorrVsV0A[replica]->Fill(nchMult, normV0A, twoParCorr); + pNchVsThreeParCorrVsV0A[replica]->Fill(nchMult, normV0A, threeParCorr); + + if (sumZEMs > zemCut) { + hNchVsZN[replica]->Fill(nchMult, sumZNs); + pNchVsOneParCorrVsZN[replica]->Fill(nchMult, sumZNs, oneParCorr); + pNchVsTwoParCorrVsZN[replica]->Fill(nchMult, sumZNs, twoParCorr); + pNchVsThreeParCorrVsZN[replica]->Fill(nchMult, sumZNs, threeParCorr); + } + } // event per replica + } // replica's loop + } + + void loadCorrections(uint64_t timeStamp) + { + if (paTHEff.value.empty() == false) { + cfg.hEfficiency = ccdb->getForTimeStamp(paTHEff, timeStamp); + if (cfg.hEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram from %s", paTHEff.value.c_str()); + } + } + + if (paTHFD.value.empty() == false) { + cfg.hFeedDown = ccdb->getForTimeStamp(paTHFD, timeStamp); + if (cfg.hFeedDown == nullptr) { + LOGF(fatal, "Could not load feed down histogram from %s", paTHFD.value.c_str()); + } + } + cfg.correctionsLoaded = true; + } + + void loadNchCalibrations(uint64_t timeStamp) + { + if (paTHmeanNch.value.empty() == false) { + cfgNch.hMeanNch = ccdb->getForTimeStamp(paTHmeanNch, timeStamp); + if (cfgNch.hMeanNch == nullptr) { + LOGF(fatal, "Could not load hMeanNch histogram from %s", paTHmeanNch.value.c_str()); + } + } + + if (paTHsigmaNch.value.empty() == false) { + cfgNch.hSigmaNch = ccdb->getForTimeStamp(paTHsigmaNch, timeStamp); + if (cfgNch.hSigmaNch == nullptr) { + LOGF(fatal, "Could not load hSigmaNch histogram from %s", paTHsigmaNch.value.c_str()); + } + } + cfgNch.calibrationsLoaded = true; + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/AngularCorrelationsInJets.cxx b/PWGLF/Tasks/Nuspex/AngularCorrelationsInJets.cxx deleted file mode 100644 index ad3db4a7091..00000000000 --- a/PWGLF/Tasks/Nuspex/AngularCorrelationsInJets.cxx +++ /dev/null @@ -1,769 +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: Lars Jörgensen - -#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 "PWGLF/DataModel/LFParticleIdentification.h" -#include "fastjet/PseudoJet.hh" -#include "fastjet/AreaDefinition.hh" -#include "fastjet/ClusterSequenceArea.hh" -#include "fastjet/GhostedAreaSpec.hh" -#include "fastjet/Selector.hh" -#include "fastjet/tools/Subtractor.hh" -#include "fastjet/tools/JetMedianBackgroundEstimator.hh" -#include "TVector2.h" -// #include "PWGJE/Core/JetFinder.h" -// #include "PWGJE/Core/JetFindingUtilities.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct AngularCorrelationsInJets { - // Preliminary Cuts - Configurable fMinNCrossedRowsTPC{"minNCrossedRowsTPC", 70, "min number of crossed rows TPC"}; - Configurable fMinReqClusterITS{"minReqClusterITS", 2, "min number of clusters required in ITS"}; - Configurable fMinReqClusterTPC{"minReqClusterTPC", 70, "min number of clusters required in TPC"}; - Configurable fMinRatioCrossedRowsTPC{"minRatioCrossedRowsTPC", 0.7f, "min ratio of crossed rows over findable clusters TPC"}; - Configurable fMaxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"}; - Configurable fMaxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; - Configurable fMaxDCAxy{"maxDCA_xy", 0.5f, "max DCA to vertex xy"}; - Configurable fMaxDCAz{"maxDCA_z", 2.4f, "max DCA to vertex z"}; - Configurable fMaxEta{"maxEta", 0.8, "max pseudorapidity"}; // consider jet cone? - - // Jet Cuts - Configurable fJetR{"jetR", 0.4, "jet resolution parameter"}; - Configurable fMinJetPt{"minJetPt", 10.0, "minimum total pT to accept jet"}; - Configurable fMinJetParticlePt{"minJetParticlePt", 0.0, "minimum pT to accept jet particle"}; - Configurable fMinLeadingPt{"minLeadingPt", 5.0, "minimum pT for leading track"}; - - // Proton Cuts - Configurable fProtonDCAxy{"protonDCAxy", 0.5, "[proton] DCAxy cut"}; - Configurable fProtonDCAz{"protonDCAz", 1.0, "[proton] DCAz cut"}; - Configurable fProtonTPCTOFpT{"protonTPCTOFswitchpT", 0.7, "[proton] pT for switch in TPC/TOF nsigma"}; - Configurable fProtonTPCnsigLow{"protonTPCnsigmapTLow", 5.0, "[proton] max TPC nsigma with low pT"}; - Configurable fProtonTPCnsigHigh{"protonTPCnsigmapTHigh", 4.0, "[proton] max TPC nsigma with high pT"}; - Configurable fProtonTOFnsigLow{"protonTOFnsigmapTLow", 10.0, "[proton] max TOF nsigma with low pT"}; - Configurable fProtonTOFnsigHigh{"protonTOFnsigmapTHigh", 10.0, "[proton] max TOF nsigma with high pT"}; - - // Antiproton Cuts - Configurable fAntiprotonDCAxy{"antiprotonDCAxy", 0.5, "[antiproton] DCAxy cut"}; - Configurable fAntiprotonDCAz{"antiprotonDCAz", 1.0, "[antiproton] DCAz cut"}; - Configurable fAntiprotonTPCTOFpT{"antiprotonTPCTOFswitchpT", 0.7, "[antiproton] pT for switch in TPC/TOF nsigma"}; - Configurable fAntiprotonTPCnsigLow{"antiprotonTPCnsigmapTLow", 5.0, "[antiproton] max TPC nsigma with low pT"}; - Configurable fAntiprotonTPCnsigHigh{"antiprotonTPCnsigmapTHigh", 4.0, "[antiproton] max TPC nsigma with high pT"}; - Configurable fAntiprotonTOFnsigLow{"antiprotonTOFnsigmapTLow", 10.0, "[antiproton] max TOF nsigma with low pT"}; - Configurable fAntiprotonTOFnsigHigh{"antiprotonTOFnsigmapTHigh", 10.0, "[antiproton] max TOF nsigma with high pT"}; - - // Deuteron Cuts - Configurable fDeuteronDCAxy{"deuteronDCAxy", 0.5, "[deuteron] DCAxy cut"}; - Configurable fDeuteronDCAz{"deuteronDCAz", 1.0, "[deuteron] DCAz cut"}; - Configurable fDeuteronTPCTOFpT{"deuteronTPCTOFswitchpT", 0.7, "[deuteron] pT for switch in TPC/TOF nsigma"}; - Configurable fDeuteronTPCnsigLow{"deuteronTPCnsigmapTLow", 5.0, "[deuteron] max TPC nsigma with low pT"}; - Configurable fDeuteronTPCnsigHigh{"deuteronTPCnsigmapTHigh", 4.0, "[deuteron] max TPC nsigma with high pT"}; - Configurable fDeuteronTOFnsigLow{"deuteronTOFnsigmapTLow", 10.0, "[deuteron] max TOF nsigma with low pT"}; - Configurable fDeuteronTOFnsigHigh{"deuteronTOFnsigmapTHigh", 10.0, "[deuteron] max TOF nsigma with high pT"}; - - // Antideuteron Cuts - Configurable fAntideuteronDCAxy{"antideuteronDCAxy", 0.5, "[antideuteron] DCAxy cut"}; - Configurable fAntideuteronDCAz{"antideuteronDCAz", 1.0, "[antideuteron] DCAz cut"}; - Configurable fAntideuteronTPCTOFpT{"antideuteronTPCTOFswitchpT", 0.7, "[antideuteron] pT for switch in TPC/TOF nsigma"}; - Configurable fAntideuteronTPCnsigLow{"antideuteronTPCnsigmapTLow", 5.0, "[antideuteron] max TPC nsigma with low pT"}; - Configurable fAntideuteronTPCnsigHigh{"antideuteronTPCnsigmapTHigh", 4.0, "[antideuteron] max TPC nsigma with high pT"}; - Configurable fAntideuteronTOFnsigLow{"antideuteronTOFnsigmapTLow", 10.0, "[antideuteron] max TOF nsigma with low pT"}; - Configurable fAntideuteronTOFnsigHigh{"antideuteronTOFnsigmapTHigh", 10.0, "[antideuteron] max TOF nsigma with high pT"}; - - Configurable fTrackBufferSize{"trackBufferSize", 2000, "Number of mixed-event tracks being stored"}; - - Service ccdb; - int mRunNumber; - - using FullTracksRun2 = soa::Join; - using FullTracksRun3 = soa::Join; - using BCsWithRun2Info = soa::Join; - - Filter prelimTrackCuts = (aod::track::itsChi2NCl < fMaxChi2ITS && - aod::track::tpcChi2NCl < fMaxChi2TPC && - nabs(aod::track::dcaXY) < fMaxDCAxy && - nabs(aod::track::dcaZ) < fMaxDCAz && - nabs(aod::track::eta) < fMaxEta); - - Preslice perCollisionFullTracksRun2 = o2::aod::track::collisionId; - Preslice perCollisionFullTracksRun3 = o2::aod::track::collisionId; - - AxisSpec ptAxis = {1000, 0, 100, "#it{p}_{T} [GeV/#it{c}]"}; - AxisSpec particleTypeAxis = {4, 1, 5, "[p, ap, d, ad]"}; - AxisSpec nsigmapTAxis = {1000, -50, 50, "#it{p}_{T} [GeV/#it{c}]"}; - AxisSpec nsigmaAxis = {1000, -5, 5, "n#sigma"}; - AxisSpec dcazAxis = {200, -3, 3, "DCA_{z} [cm]"}; - AxisSpec dcaxyAxis = {200, -2, 2, "DCA_{xy} [cm]"}; - AxisSpec angDistPhiAxis = {1000, -2, 5, "#Delta#varphi"}; - AxisSpec angDistEtaAxis = {1000, -2, 2, "#Delta#eta"}; - - HistogramRegistry registryData{"dataOutput", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - HistogramRegistry registryQA{"dataQA", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - - 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("hNumberOfEvents", "Number of events", HistType::kTH1I, {{1, 0, 1}}); - registryData.add("hNumberOfJets", "Total number of jets", HistType::kTH1I, {{1, 0, 1}}); - registryData.add("hEventProtocol", "Event protocol", HistType::kTH1I, {{20, 0, 20}}); - registryData.add("hTrackProtocol", "Track protocol", HistType::kTH1I, {{20, 0, 20}}); - registryData.add("hNumPartInJet", "Number of particles in a jet", HistType::kTH1I, {{200, 0, 200}}); - - // (Pseudo)Rapidity - registryData.add("hJetRapidity", "Jet rapidity;#it{y}", HistType::kTH1F, {{200, -1, 1}}); - - // pT - registryData.add("hPtJetParticle", "p_{T} of particles in jets", HistType::kTH1D, {ptAxis}); - registryData.add("hPtSubtractedJet", "Subtracted jet p_{T}", HistType::kTH1D, {ptAxis}); - registryData.add("hPtJetProtonDeuteron", "p_{T} of (anti)p, (anti)d", HistType::kTH2D, {particleTypeAxis, ptAxis}); - registryData.add("hPtTotalJet", "p_{T} of entire jet;#it{p}_{T} [GeV/#it{c}]", HistType::kTH1F, {{2000, 0, 500}}); - registryData.add("hPtDiff", "pT difference PseudoJet/original track;#it{p}_{T} [GeV/#it{c}]", HistType::kTH1D, {{100, -5, 5}}); - - // nSigma - registryData.add("hTPCsignal", "TPC signal", HistType::kTH2F, {{1000, 0, 100, "#it{p} [GeV/#it{c}]"}, {5000, 0, 5000, "d#it{E}/d#it{X} (a.u.)"}}); - registryData.add("hTOFsignal", "TOF signal", HistType::kTH2F, {{1000, 0, 100, "#it{p} [GeV/#it{c}]"}, {550, 0, 1.1, "#beta (TOF)"}}); - registryData.add("hTPCnsigmaProton", "TPC n#sigma for (anti)proton", HistType::kTH2F, {nsigmapTAxis, nsigmaAxis}); - registryData.add("hTOFnsigmaProton", "TOF n#sigma for (anti)proton", HistType::kTH2F, {nsigmapTAxis, nsigmaAxis}); - registryData.add("hTPCnsigmaDeuteron", "TPC n#sigma for (anti)deuteron", HistType::kTH2F, {nsigmapTAxis, nsigmaAxis}); - registryData.add("hTOFnsigmaDeuteron", "TOF n#sigma for (anti)deuteron", HistType::kTH2F, {nsigmapTAxis, nsigmaAxis}); - - // DCA - registryData.add("hDCAxyFullJet", "DCA_{xy} of full jet", HistType::kTH2F, {ptAxis, dcaxyAxis}); - registryData.add("hDCAzFullJet", "DCA_{z} of full jet", HistType::kTH2F, {ptAxis, dcazAxis}); - registryData.add("hDCAzJetProton", "DCA_{z} of protons after TPC cut", HistType::kTH2F, {ptAxis, dcazAxis}); - registryData.add("hDCAzJetAntiproton", "DCA_{z} of antiprotons after TPC cut", HistType::kTH2F, {ptAxis, dcazAxis}); - registryData.add("hDCAzJetDeuteron", "DCA_{z} of deuterons after TPC cut", HistType::kTH2F, {ptAxis, dcazAxis}); - registryData.add("hDCAzJetAntideuteron", "DCA_{z} of antideuterons after TPC cut", HistType::kTH2F, {ptAxis, dcazAxis}); - - // Angular Distributions - registryData.add("hDeltaPhiSE", "#Delta#varphi of (anti)p, (anti)d in single event", HistType::kTH2D, {particleTypeAxis, angDistPhiAxis}); - registryData.add("hDeltaPhiME", "#Delta#varphi of (anti)p, (anti)d in mixed events", HistType::kTH2D, {particleTypeAxis, angDistPhiAxis}); - registryData.add("hDeltaPhiEtaSE", "#Delta#varphi vs #Delta#eta of (anti)p, (anti)d in single event", HistType::kTH3D, {particleTypeAxis, angDistPhiAxis, angDistEtaAxis}); - registryData.add("hDeltaPhiEtaME", "#Delta#varphi vs #Delta#eta of (anti)p, (anti)d in mixed events", HistType::kTH3D, {particleTypeAxis, angDistPhiAxis, angDistEtaAxis}); - - registryData.add("hJetConeRadius", "Jet Radius;#it{R}", HistType::kTH1F, {{100, 0, 1}}); - - // QA - registryQA.add("hTOFmass", "TOF mass", HistType::kTH2F, {ptAxis, {1000, 0, 5, "#it{m} [GeV/#it{c}^{2}]"}}); - registryQA.add("hPtFullEvent", "p_{T} after basic cuts", HistType::kTH1F, {ptAxis}); - registryQA.add("hEtaFullEvent", "Particle pseudorapidity;#eta", HistType::kTH1F, {{200, -1, 1}}); - registryQA.get(HIST("hTOFmass"))->Sumw2(); - registryQA.add("hCrossedRowsTPC", "Crossed rows TPC", HistType::kTH2I, {ptAxis, {135, 65, 200}}); - registryQA.add("hClusterITS", "ITS clusters", HistType::kTH2I, {ptAxis, {10, 0, 10}}); - registryQA.add("hClusterTPC", "TPC clusters", HistType::kTH2I, {ptAxis, {135, 65, 200}}); - registryQA.add("hRatioCrossedRowsTPC", "Ratio crossed rows/findable TPC", HistType::kTH2F, {ptAxis, {100, 0.5, 1.5}}); - registryQA.add("hChi2ITS", "ITS #chi^{2}", HistType::kTH2F, {ptAxis, {400, 0, 40}}); - registryQA.add("hChi2TPC", "TPC #chi^{2}", HistType::kTH2F, {ptAxis, {50, 0, 5}}); - registryQA.add("hDCAxyFullEvent", "DCA_{xy} of full event", HistType::kTH2F, {ptAxis, dcaxyAxis}); - registryQA.add("hDCAzFullEvent", "DCA_{z} of full event", HistType::kTH2F, {ptAxis, dcazAxis}); - } - - std::vector fTrackBufferProtonRun2; - std::vector fTrackBufferAntiprotonRun2; - std::vector fTrackBufferDeuteronRun2; - std::vector fTrackBufferAntideuteronRun2; - std::vector fTrackBufferProtonRun3; - std::vector fTrackBufferAntiprotonRun3; - std::vector fTrackBufferDeuteronRun3; - std::vector fTrackBufferAntideuteronRun3; - // TODO: check if FullTracksRun2 works for Run3 too or add Run3 track buffers - - template - void initCCDB(Bc const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - mRunNumber = bc.runNumber(); - } - - template - bool selectTrack(T const& track) - { - if (track.tpcNClsCrossedRows() < fMinRatioCrossedRowsTPC * track.tpcNClsFindable() || - track.tpcNClsCrossedRows() < fMinNCrossedRowsTPC || - track.tpcNClsFound() < fMinReqClusterTPC || - track.itsNCls() < fMinReqClusterITS) { - return false; - } - if (doprocessRun2) { - if (!(track.trackType() & o2::aod::track::Run2Track) //|| - //!(track.flags() & o2::aod::track::TPCrefit) || - //!(track.flags() & o2::aod::track::ITSrefit) - ) { - return false; - } - } - return true; - } - - std::vector findJets(std::vector jetInput) - { - std::vector jets; - std::vector constituents; - jets.clear(); - constituents.clear(); - fastjet::PseudoJet hardestJet(0., 0., 0., 0.); - fastjet::PseudoJet subtractedJet(0., 0., 0., 0.); - - double ghost_maxrap = 1.0; - double ghost_area = 0.005; - int ghost_repeat = 1; - fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, fJetR); - fastjet::JetDefinition jetDefBkg(fastjet::kt_algorithm, 0.5); - fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(ghost_maxrap, ghost_repeat, ghost_area)); - fastjet::AreaDefinition areaDefBkg(fastjet::active_area_explicit_ghosts, fastjet::GhostedAreaSpec(ghost_maxrap)); - fastjet::ClusterSequenceArea clusterSeq(jetInput, jetDef, areaDef); - jets = sorted_by_pt(clusterSeq.inclusive_jets()); - if (jets.size() == 0) - return constituents; - - registryData.fill(HIST("hEventProtocol"), 3); - - hardestJet = jets[0]; - - if (hardestJet.pt() < fMinJetPt) - return constituents; - registryData.fill(HIST("hEventProtocol"), 4); - if (hardestJet.constituents().size() < 2) - return constituents; - registryData.fill(HIST("hEventProtocol"), 5); - registryData.fill(HIST("hNumberOfJets"), 0); - registryData.fill(HIST("hPtTotalJet"), hardestJet.pt()); - registryData.fill(HIST("hJetRapidity"), hardestJet.rap()); - registryData.fill(HIST("hNumPartInJet"), hardestJet.constituents().size()); - - for (const auto& constituent : hardestJet.constituents()) { - registryData.fill(HIST("hPtJetParticle"), constituent.pt()); - double DeltaPhi = TVector2::Phi_0_2pi(constituent.phi() - hardestJet.phi()); - double DeltaEta = constituent.eta() - hardestJet.eta(); - double Delta = TMath::Sqrt(DeltaPhi * DeltaPhi + DeltaEta * DeltaEta); - registryData.fill(HIST("hJetConeRadius"), Delta); - } - - fastjet::Selector selector = fastjet::SelectorAbsEtaMax(1.0) * (!fastjet::SelectorNHardest(2)); // TODO: fix subtraction - fastjet::JetMedianBackgroundEstimator bkgEst(selector, jetDefBkg, areaDefBkg); - fastjet::Subtractor subtractor(&bkgEst); - subtractor.set_use_rho_m(true); - bkgEst.set_particles(jetInput); - - subtractedJet = subtractor(hardestJet); - if (subtractedJet.has_constituents()) { - for (const auto& subConstituent : subtractedJet.constituents()) { - registryData.fill(HIST("hPtSubtractedJet"), subConstituent.pt()); - } - } - return hardestJet.constituents(); - } - - template - bool isProton(const T& track) - { - bool isProton = false; - if (track.sign() < 0) - return isProton; - - // TPC - if (track.pt() < fProtonTPCTOFpT && TMath::Abs(track.tpcNSigmaPr()) < fProtonTPCnsigLow) - isProton = true; - if (track.pt() > fProtonTPCTOFpT && TMath::Abs(track.tpcNSigmaPr()) < fProtonTPCnsigHigh) - isProton = true; - - registryData.fill(HIST("hDCAzJetProton"), track.pt() * track.sign(), track.dcaZ()); - - if (TMath::Abs(track.dcaXY()) > fProtonDCAxy) - return false; - if (TMath::Abs(track.dcaZ()) > fProtonDCAz) - return false; - - // TOF - if (track.pt() < fProtonTPCTOFpT && TMath::Abs(track.tofNSigmaPr()) < fProtonTOFnsigLow) - isProton = true; - if (track.pt() > fProtonTPCTOFpT && TMath::Abs(track.tofNSigmaPr()) < fProtonTOFnsigHigh) - isProton = true; - - return isProton; - } - - template - bool isAntiproton(const T& track) - { - bool isAntiproton = false; - if (track.sign() < 0) - return isAntiproton; - - // TPC - if (track.pt() < fAntiprotonTPCTOFpT && TMath::Abs(track.tpcNSigmaPr()) < fAntiprotonTPCnsigLow) - isAntiproton = true; - if (track.pt() > fAntiprotonTPCTOFpT && TMath::Abs(track.tpcNSigmaPr()) < fAntiprotonTPCnsigHigh) - isAntiproton = true; - - registryData.fill(HIST("hDCAzJetAntiproton"), track.pt() * track.sign(), track.dcaZ()); - - if (TMath::Abs(track.dcaXY()) > fAntiprotonDCAxy) - return false; - if (TMath::Abs(track.dcaZ()) > fAntiprotonDCAz) - return false; - - // TOF - if (track.pt() < fAntiprotonTPCTOFpT && TMath::Abs(track.tofNSigmaPr()) < fAntiprotonTOFnsigLow) - isAntiproton = true; - if (track.pt() > fAntiprotonTPCTOFpT && TMath::Abs(track.tofNSigmaPr()) < fAntiprotonTOFnsigHigh) - isAntiproton = true; - - return isAntiproton; - } - - template - bool isDeuteron(const T& track) - { - bool isDeuteron = false; - if (track.sign() < 0) - return isDeuteron; - - // TPC - if (track.pt() < fDeuteronTPCTOFpT && TMath::Abs(track.tpcNSigmaDe()) < fDeuteronTPCnsigLow) - isDeuteron = true; - if (track.pt() > fDeuteronTPCTOFpT && TMath::Abs(track.tpcNSigmaDe()) < fDeuteronTPCnsigHigh) - isDeuteron = true; - - registryData.fill(HIST("hDCAzJetDeuteron"), track.pt() * track.sign(), track.dcaZ()); - - if (TMath::Abs(track.dcaXY()) > fDeuteronDCAxy) - return false; - if (TMath::Abs(track.dcaZ()) > fDeuteronDCAz) - return false; - - // TOF - if (track.pt() < fDeuteronTPCTOFpT && TMath::Abs(track.tofNSigmaDe()) < fDeuteronTOFnsigLow) - isDeuteron = true; - if (track.pt() > fDeuteronTPCTOFpT && TMath::Abs(track.tofNSigmaDe()) < fDeuteronTOFnsigHigh) - isDeuteron = true; - - return isDeuteron; - } - - template - bool isAntideuteron(const T& track) - { - bool isAntideuteron = false; - if (track.sign() < 0) - return isAntideuteron; - - // TPC - if (track.pt() < fAntideuteronTPCTOFpT && TMath::Abs(track.tpcNSigmaDe()) < fAntideuteronTPCnsigLow) - isAntideuteron = true; - if (track.pt() > fAntideuteronTPCTOFpT && TMath::Abs(track.tpcNSigmaDe()) < fAntideuteronTPCnsigHigh) - isAntideuteron = true; - - registryData.fill(HIST("hDCAzJetAntideuteron"), track.pt() * track.sign(), track.dcaZ()); - - if (TMath::Abs(track.dcaXY()) > fAntideuteronDCAxy) - return false; - if (TMath::Abs(track.dcaZ()) > fAntideuteronDCAz) - return false; - - // TOF - if (track.pt() < fAntideuteronTPCTOFpT && TMath::Abs(track.tofNSigmaDe()) < fAntideuteronTOFnsigLow) - isAntideuteron = true; - if (track.pt() > fAntideuteronTPCTOFpT && TMath::Abs(track.tofNSigmaDe()) < fAntideuteronTOFnsigHigh) - isAntideuteron = true; - - return isAntideuteron; - } - - void setTrackBuffer(const auto& tempBuffer, auto& buffer) - { - for (const auto& track : tempBuffer) { - if (static_cast(buffer.size()) == fTrackBufferSize) { - buffer.insert(buffer.begin(), track); - buffer.resize(fTrackBufferSize); - } else if (static_cast(buffer.size()) < fTrackBufferSize) { - buffer.emplace_back(track); - } - } - } - - void fillMixedEventDeltas(const auto& track, const auto& buffer, int particleType) - { - if (buffer.size() == 0) - return; - for (int i = 0; i < static_cast(buffer.size()); i++) { - if (std::isnan(buffer.at(i).phi())) - continue; - if (buffer.at(i).phi() > 2 * TMath::Pi() || buffer.at(i).phi() < -2 * TMath::Pi()) { - registryData.fill(HIST("hTrackProtocol"), 13); - continue; - } - - double DeltaPhi = TVector2::Phi_0_2pi(track.phi() - buffer.at(i).phi()); - if (DeltaPhi > (1.5 * TMath::Pi())) { - DeltaPhi = DeltaPhi - 2 * TMath::Pi(); - } - double DeltaEta = TMath::Abs(track.eta() - buffer.at(i).eta()); - registryData.fill(HIST("hDeltaPhiME"), particleType, DeltaPhi); - registryData.fill(HIST("hDeltaPhiEtaME"), particleType, DeltaPhi, DeltaEta); - } - } - - void doCorrelations(const auto& particleVector, const auto& buffer, auto& tempBuffer, int particleType) - { - for (int i = 0; i < static_cast(particleVector.size()); i++) { // maybe simply introduce phi cut? - if (particleVector.at(i).phi() > 2 * TMath::Pi() || particleVector.at(i).phi() < -2 * TMath::Pi()) { - registryData.fill(HIST("hTrackProtocol"), 11); - 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 (particleVector.at(j).phi() > 2 * TMath::Pi() || particleVector.at(j).phi() < -2 * TMath::Pi()) { - registryData.fill(HIST("hTrackProtocol"), 12); - continue; - } - - double DeltaPhi = TVector2::Phi_0_2pi(particleVector.at(i).phi() - particleVector.at(j).phi()); - double DeltaEta = TMath::Abs(particleVector.at(i).eta() - particleVector[j].eta()); - if (DeltaPhi > (1.5 * TMath::Pi())) { - DeltaPhi = DeltaPhi - 2 * TMath::Pi(); - } - registryData.fill(HIST("hDeltaPhiSE"), 1, DeltaPhi); - registryData.fill(HIST("hDeltaPhiEtaSE"), 1, DeltaPhi, DeltaEta); - } - fillMixedEventDeltas(particleVector.at(i), buffer, particleType); - tempBuffer.emplace_back(particleVector.at(i)); - } - } - - template - void fillHistogramsRun2(T const& collision, U const& allTracks) - { - std::vector fTempBufferProton; - std::vector fTempBufferAntiproton; - std::vector fTempBufferDeuteron; - std::vector fTempBufferAntideuteron; - fTempBufferProton.clear(); - fTempBufferAntiproton.clear(); - fTempBufferDeuteron.clear(); - fTempBufferAntideuteron.clear(); - std::vector jetInput; - std::map particles; - jetInput.clear(); - particles.clear(); - int index = 0; - - auto tracks = allTracks.sliceBy(perCollisionFullTracksRun2, collision.globalIndex()); - - for (const auto& track : tracks) { - if (!selectTrack(track)) - continue; - - double mass; - if (track.hasTOF()) { - mass = track.mass(); // check reliability, maybe use only pion mass - registryQA.fill(HIST("hTOFmass"), track.pt(), track.mass()); - registryData.fill(HIST("hTrackProtocol"), 4); - } else { - mass = 0.139; // pion mass as default, ~80% are pions - registryData.fill(HIST("hTrackProtocol"), 5); - } - - // double ratioCrossedRowsTPC = track.tpcNClsCrossedRows()/track.tpcNClsFindable(); - registryQA.fill(HIST("hPtFullEvent"), track.pt()); - registryQA.fill(HIST("hEtaFullEvent"), track.eta()); - registryQA.fill(HIST("hCrossedRowsTPC"), track.pt(), track.tpcNClsCrossedRows()); - registryQA.fill(HIST("hClusterITS"), track.pt(), track.itsNCls()); - registryQA.fill(HIST("hClusterTPC"), track.pt(), track.tpcNClsFound()); - // registryQA.fill(HIST("hRatioCrossedRowsTPC"), track.pt(), ratioCrossedRowsTPC); - registryQA.fill(HIST("hChi2ITS"), track.pt(), track.itsChi2NCl()); - registryQA.fill(HIST("hChi2TPC"), track.pt(), track.tpcChi2NCl()); - registryQA.fill(HIST("hDCAxyFullEvent"), track.pt(), track.dcaXY()); - registryQA.fill(HIST("hDCAzFullEvent"), track.pt(), track.dcaZ()); - fastjet::PseudoJet inputPseudoJet(track.px(), track.py(), track.pz(), track.energy(mass)); - inputPseudoJet.set_user_index(index); - particles[index] = track; - jetInput.emplace_back(inputPseudoJet); - - index++; - } // for (const auto& track : tracks) - - if (jetInput.size() < 2) - return; - registryData.fill(HIST("hEventProtocol"), 2); - - std::vector constituents = findJets(jetInput); - if (constituents.empty()) - return; - - std::vector jetProtons; // replace with IDs? - std::vector jetAntiprotons; - std::vector jetDeuterons; - std::vector jetAntideuterons; - - for (int i = 0; i < static_cast(constituents.size()); i++) { - registryData.fill(HIST("hTrackProtocol"), 10); - fastjet::PseudoJet pseudoParticle = constituents.at(i); - int id = pseudoParticle.user_index(); - const auto& jetParticle = particles[id]; - - registryData.fill(HIST("hDCAxyFullJet"), jetParticle.pt() * jetParticle.sign(), jetParticle.dcaXY()); - registryData.fill(HIST("hDCAzFullJet"), jetParticle.pt() * jetParticle.sign(), jetParticle.dcaZ()); - registryData.fill(HIST("hTPCsignal"), jetParticle.pt() * jetParticle.sign(), jetParticle.tpcSignal()); - if (jetParticle.hasTOF()) - registryData.fill(HIST("hTOFsignal"), jetParticle.pt() * jetParticle.sign(), jetParticle.beta()); - - double ptDiff = pseudoParticle.pt() - jetParticle.pt(); - registryData.fill(HIST("hPtDiff"), ptDiff); - int particleType = 0; - - if (jetParticle.pt() < fMinJetParticlePt) - continue; - if (isProton(jetParticle) || isAntiproton(jetParticle)) { // collect (anti)protons in jet - registryData.fill(HIST("hTPCnsigmaProton"), jetParticle.pt() * jetParticle.sign(), jetParticle.tpcNSigmaPr()); - if (jetParticle.hasTOF()) - registryData.fill(HIST("hTOFnsigmaProton"), jetParticle.pt() * jetParticle.sign(), jetParticle.tofNSigmaPr()); - if (isProton(jetParticle)) { - particleType = 1; - registryData.fill(HIST("hTrackProtocol"), 6); // # protons - jetProtons.emplace_back(jetParticle); - } else { - particleType = 2; - registryData.fill(HIST("hTrackProtocol"), 7); // # antiprotons - jetAntiprotons.emplace_back(jetParticle); - } - } else if (isDeuteron(jetParticle) || isAntideuteron(jetParticle)) { // collect (anti)deuterons in jet - registryData.fill(HIST("hTPCnsigmaDeuteron"), jetParticle.pt() * jetParticle.sign(), jetParticle.tpcNSigmaDe()); - if (jetParticle.hasTOF()) - registryData.fill(HIST("hTOFnsigmaDeuteron"), jetParticle.pt() * jetParticle.sign(), jetParticle.tofNSigmaDe()); - if (isDeuteron(jetParticle)) { - particleType = 3; - registryData.fill(HIST("hTrackProtocol"), 8); // # deuterons - jetDeuterons.emplace_back(jetParticle); - } else { - particleType = 4; - registryData.fill(HIST("hTrackProtocol"), 9); // # antideuterons - jetAntideuterons.emplace_back(jetParticle); - } - } - registryData.fill(HIST("hPtJetProtonDeuteron"), particleType, jetParticle.pt()); - } // for (int i=0; i(constituents.size()); i++) - - if ((jetProtons.size() < 2) && (jetAntiprotons.size() < 2) && (jetDeuterons.size() < 2) && (jetAntideuterons.size() < 2)) - return; - registryData.fill(HIST("hEventProtocol"), 6); - - if (jetProtons.size() > 1) { - doCorrelations(jetProtons, fTrackBufferProtonRun2, fTempBufferProton, 1); - setTrackBuffer(fTempBufferProton, fTrackBufferProtonRun2); - } - if (jetAntiprotons.size() > 1) { - doCorrelations(jetAntiprotons, fTrackBufferAntiprotonRun2, fTempBufferAntiproton, 2); - setTrackBuffer(fTempBufferAntiproton, fTrackBufferAntiprotonRun2); - } - if (jetDeuterons.size() > 1) { - doCorrelations(jetDeuterons, fTrackBufferDeuteronRun2, fTempBufferDeuteron, 3); - setTrackBuffer(fTempBufferDeuteron, fTrackBufferDeuteronRun2); - } - if (jetAntideuterons.size() > 1) { - doCorrelations(jetAntideuterons, fTrackBufferAntideuteronRun2, fTempBufferAntideuteron, 4); - setTrackBuffer(fTempBufferAntideuteron, fTrackBufferAntideuteronRun2); - } - } - - template - void fillHistogramsRun3(T const& collision, U const& allTracks) - { - std::vector fTempBufferProton; - std::vector fTempBufferAntiproton; - std::vector fTempBufferDeuteron; - std::vector fTempBufferAntideuteron; - fTempBufferProton.clear(); - fTempBufferAntiproton.clear(); - fTempBufferDeuteron.clear(); - fTempBufferAntideuteron.clear(); - std::vector jetInput; - std::map particles; - jetInput.clear(); - particles.clear(); - int index = 0; - - auto tracks = allTracks.sliceBy(perCollisionFullTracksRun2, collision.globalIndex()); - - for (const auto& track : tracks) { - if (!selectTrack(track)) - continue; - - double mass; - if (track.hasTOF()) { - mass = track.mass(); // check reliability, maybe use only pion mass - registryQA.fill(HIST("hTOFmass"), track.pt(), track.mass()); - registryData.fill(HIST("hTrackProtocol"), 4); - } else { - mass = 0.139; // pion mass as default, ~80% are pions - registryData.fill(HIST("hTrackProtocol"), 5); - } - - // double ratioCrossedRowsTPC = track.tpcNClsCrossedRows()/track.tpcNClsFindable(); - registryQA.fill(HIST("hPtFullEvent"), track.pt()); - registryQA.fill(HIST("hEtaFullEvent"), track.eta()); - registryQA.fill(HIST("hCrossedRowsTPC"), track.pt(), track.tpcNClsCrossedRows()); - registryQA.fill(HIST("hClusterITS"), track.pt(), track.itsNCls()); - registryQA.fill(HIST("hClusterTPC"), track.pt(), track.tpcNClsFound()); - // registryQA.fill(HIST("hRatioCrossedRowsTPC"), track.pt(), ratioCrossedRowsTPC); - registryQA.fill(HIST("hChi2ITS"), track.pt(), track.itsChi2NCl()); - registryQA.fill(HIST("hChi2TPC"), track.pt(), track.tpcChi2NCl()); - registryQA.fill(HIST("hDCAxyFullEvent"), track.pt(), track.dcaXY()); - registryQA.fill(HIST("hDCAzFullEvent"), track.pt(), track.dcaZ()); - fastjet::PseudoJet inputPseudoJet(track.px(), track.py(), track.pz(), track.energy(mass)); - inputPseudoJet.set_user_index(index); - particles[index] = track; - jetInput.emplace_back(inputPseudoJet); - - index++; - } // for (const auto& track : tracks) - - if (jetInput.size() < 2) - return; - registryData.fill(HIST("hEventProtocol"), 2); - - std::vector constituents = findJets(jetInput); - if (constituents.empty()) - return; - - std::vector jetProtons; // replace with IDs? - std::vector jetAntiprotons; - std::vector jetDeuterons; - std::vector jetAntideuterons; - - for (int i = 0; i < static_cast(constituents.size()); i++) { - registryData.fill(HIST("hTrackProtocol"), 10); - fastjet::PseudoJet pseudoParticle = constituents.at(i); - int id = pseudoParticle.user_index(); - const auto& jetParticle = particles[id]; - - registryData.fill(HIST("hDCAxyFullJet"), jetParticle.pt() * jetParticle.sign(), jetParticle.dcaXY()); - registryData.fill(HIST("hDCAzFullJet"), jetParticle.pt() * jetParticle.sign(), jetParticle.dcaZ()); - registryData.fill(HIST("hTPCsignal"), jetParticle.pt() * jetParticle.sign(), jetParticle.tpcSignal()); - if (jetParticle.hasTOF()) - registryData.fill(HIST("hTOFsignal"), jetParticle.pt() * jetParticle.sign(), jetParticle.beta()); - - double ptDiff = pseudoParticle.pt() - jetParticle.pt(); - registryData.fill(HIST("hPtDiff"), ptDiff); - int particleType = 0; - - if (jetParticle.pt() < fMinJetParticlePt) - continue; - if (isProton(jetParticle) || isAntiproton(jetParticle)) { // collect (anti)protons in jet - registryData.fill(HIST("hTPCnsigmaProton"), jetParticle.pt() * jetParticle.sign(), jetParticle.tpcNSigmaPr()); - if (jetParticle.hasTOF()) - registryData.fill(HIST("hTOFnsigmaProton"), jetParticle.pt() * jetParticle.sign(), jetParticle.tofNSigmaPr()); - if (isProton(jetParticle)) { - particleType = 1; - registryData.fill(HIST("hTrackProtocol"), 6); // # protons - jetProtons.emplace_back(jetParticle); - } else { - particleType = 2; - registryData.fill(HIST("hTrackProtocol"), 7); // # antiprotons - jetAntiprotons.emplace_back(jetParticle); - } - } else if (isDeuteron(jetParticle) || isAntideuteron(jetParticle)) { // collect (anti)deuterons in jet - registryData.fill(HIST("hTPCnsigmaDeuteron"), jetParticle.pt() * jetParticle.sign(), jetParticle.tpcNSigmaDe()); - if (jetParticle.hasTOF()) - registryData.fill(HIST("hTOFnsigmaDeuteron"), jetParticle.pt() * jetParticle.sign(), jetParticle.tofNSigmaDe()); - if (isDeuteron(jetParticle)) { - particleType = 3; - registryData.fill(HIST("hTrackProtocol"), 8); // # deuterons - jetDeuterons.emplace_back(jetParticle); - } else { - particleType = 4; - registryData.fill(HIST("hTrackProtocol"), 9); // # antideuterons - jetAntideuterons.emplace_back(jetParticle); - } - } - registryData.fill(HIST("hPtJetProtonDeuteron"), particleType, jetParticle.pt()); - } // for (int i=0; i(constituents.size()); i++) - - if ((jetProtons.size() < 2) && (jetAntiprotons.size() < 2) && (jetDeuterons.size() < 2) && (jetAntideuterons.size() < 2)) - return; - registryData.fill(HIST("hEventProtocol"), 6); - - if (jetProtons.size() > 1) { - doCorrelations(jetProtons, fTrackBufferProtonRun3, fTempBufferProton, 1); - setTrackBuffer(fTempBufferProton, fTrackBufferProtonRun3); - } - if (jetAntiprotons.size() > 1) { - doCorrelations(jetAntiprotons, fTrackBufferAntiprotonRun3, fTempBufferAntiproton, 2); - setTrackBuffer(fTempBufferAntiproton, fTrackBufferAntiprotonRun3); - } - if (jetDeuterons.size() > 1) { - doCorrelations(jetDeuterons, fTrackBufferDeuteronRun3, fTempBufferDeuteron, 3); - setTrackBuffer(fTempBufferDeuteron, fTrackBufferDeuteronRun3); - } - if (jetAntideuterons.size() > 1) { - doCorrelations(jetAntideuterons, fTrackBufferAntideuteronRun3, fTempBufferAntideuteron, 4); - setTrackBuffer(fTempBufferAntideuteron, fTrackBufferAntideuteronRun3); - } - } - - 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("hEventProtocol"), 0); - registryData.fill(HIST("hNumberOfEvents"), 0); - if (!collision.alias_bit(kINT7)) - continue; - registryData.fill(HIST("hEventProtocol"), 1); - - fillHistogramsRun2(collision, tracks); - } - } - PROCESS_SWITCH(AngularCorrelationsInJets, processRun2, "process Run 2 data", true); - - void processRun3(aod::Collision const& collision, soa::Filtered const& tracks) - { - fillHistogramsRun3(collision, tracks); - } - PROCESS_SWITCH(AngularCorrelationsInJets, processRun3, "process Run 3 data", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/Tasks/Nuspex/AntiNucleiTask.cxx b/PWGLF/Tasks/Nuspex/AntiNucleiTask.cxx new file mode 100644 index 00000000000..a8b7dfe45c7 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/AntiNucleiTask.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 AntiNucleiTask.cxx +/// \brief A task to analyse Anti-nuclei +/// \author Arkaprabha Saha + +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" + +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using CollisionWithEvSel = soa::Join; +using TotalTracks = soa::Join; + +namespace +{ +static const std::vector particleName{"d"}; +static const double kBetheBlochDefault[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 float maxEtaCut = 0.8f; +static const int minTpcCrossedRowsCut = 70; +static const float maxVertexZCut = 10.f; +} // namespace + +struct AntiNucleiTask { + // Histogram registry: for holding histograms + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Configurable track cuts + Configurable trackNclusTPCcut{"trackNclusTPCcut", 70.0f, "min number of TPC clusters"}; + Configurable trackNclusITScut{"trackNclusITScut", 4.0f, "min number of ITS clusters"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; + Configurable minChi2TPC{"minChi2TPC", 0.0f, "min chi2 per cluster TPC"}; + Configurable chi2ITS{"chi2ITS", 36.0f, "max chi2 per cluster ITS"}; + Configurable trackDCAz{"trackDCAz", 0.1f, "maxDCAz"}; + Configurable trackDCAxy{"trackDCAxy", 0.1f, "maxDCAxy"}; + Configurable tpcNSigmaCut{"tpcNSigmaCut", 3.0f, "tpcNSigmaCut"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {kBetheBlochDefault, 1, 6, particleName, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for deuteron"}; + + void init(InitContext const&) + { // Defining the Histogram Axes + ConfigurableAxis etaAxis{"etaAxis", {16, -0.8, +0.8}, "#eta"}; + ConfigurableAxis phiAxis{"phiAxis", {70, 0.f, 7.f}, "#phi"}; + ConfigurableAxis zVtxAxis{"zVtxAxis", {100, -20.f, 20.f}, "Primary Vertex z (cm)"}; + ConfigurableAxis nSigmaAxis{"nSigmaAxis", {50, -5.f, 5.f}, "N_{#sigma}"}; + ConfigurableAxis ptAxis{"ptAxis", {200, -10.0f, 10.0f}, "p_{T} (GeV/c)"}; + ConfigurableAxis centAxis{"centAxis", {100, 0, 100.0f}, "Centrality"}; + ConfigurableAxis momAxis{"momAxis", {5.e2, 0.f, 5.f}, "momentum axis binning"}; + ConfigurableAxis tpcAxis{"tpcAxis", {4.e2, 0.f, 4.e3f}, "tpc signal axis binning"}; + + // Creating histograms + histos.add("RawzVtx", "RawzVtx", kTH1F, {{zVtxAxis, "Primary Vertex z (cm)"}}); + histos.add("zVtx", "zVtx", kTH1F, {{zVtxAxis, "Primary Vertex z (cm)"}}); + histos.add("RawEta", "RawEta", kTH1F, {{etaAxis, "#eta"}}); + histos.add("Eta", "Eta", kTH1F, {{etaAxis, "#eta"}}); + histos.add("RawPhi", "RawPhi", kTH1F, {{phiAxis, "#phi (rad)"}}); + histos.add("Phi", "Phi", kTH1F, {{phiAxis, "#phi (rad)"}}); + histos.add("RawPt", "RawPt", kTH1F, {{ptAxis, "#it{p}_{T} (GeV/#it{c})"}}); + histos.add("Pt", "Pt", kTH1F, {{ptAxis, "#it{p}_{T} (GeV/#it{c})"}}); + histos.add("TpcSignal", "TpcSignal", kTH2F, {{momAxis, "#it{p}_{TPC} (GeV/#it{c})"}, {tpcAxis, "d#it{E}/d#it{x}_{TPC}"}}); + histos.add("RawtpcNSigma", "RawtpcNSigma", kTH3F, {{centAxis, "Centrality"}, {ptAxis, "#it{p}_{T} (GeV/#it{c})"}, {nSigmaAxis, "N_{#sigma}"}}); + histos.add("tpcNSigma", "tpcNSigma", kTH3F, {{centAxis, "Centrality"}, {ptAxis, "#it{p}_{T} (GeV/#it{c})"}, {nSigmaAxis, "N_{#sigma}"}}); + histos.add("RawtofNSigma", "RawtofNSigma", kTH3F, {{centAxis, "Centrality"}, {ptAxis, "#it{p}_{T} (GeV/#it{c})"}, {nSigmaAxis, "N_{#sigma}"}}); + histos.add("tofNSigma", "tofNSigma", kTH3F, {{centAxis, "Centrality"}, {ptAxis, "#it{p}_{T} (GeV/#it{c})"}, {nSigmaAxis, "N_{#sigma}"}}); + } + + // Function to apply track cuts + template + bool isGoodTrack(const T& track) + { + if (track.eta() > maxEtaCut) + return false; + if (track.tpcNClsFound() < trackNclusTPCcut) + return false; + if (track.tpcNClsCrossedRows() < minTpcCrossedRowsCut) + return false; + if (track.itsNCls() < trackNclusITScut) + return false; + if (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (track.tpcChi2NCl() < minChi2TPC) + return false; + if (track.itsChi2NCl() > chi2ITS) + return false; + if (std::abs(track.dcaXY()) > trackDCAxy) + return false; + if (std::abs(track.dcaZ()) > trackDCAz) + return false; + + return true; + } + + // The process function + void process(CollisionWithEvSel::iterator const& collision, TotalTracks const& tracks) + { + // Event Selection + if (std::abs(collision.posZ()) > maxVertexZCut) { + return; + } + + // Filling the z-vertex histogram before the event selection cuts. + histos.fill(HIST("RawzVtx"), collision.posZ()); + + // Applying the built-in O2 event selection (sel8). + if (!collision.sel8()) { + return; + } + + // Filling the z-vertex histogram after the event selection cuts. + histos.fill(HIST("zVtx"), collision.posZ()); + + // Track Selection + for (const auto& track : tracks) { + + double expBethe{tpc::BetheBlochAleph(static_cast(track.tpcInnerParam()), cfgBetheBlochParams->get("p0"), cfgBetheBlochParams->get("p1"), cfgBetheBlochParams->get("p2"), cfgBetheBlochParams->get("p3"), cfgBetheBlochParams->get("p4"))}; + double expSigma{expBethe * cfgBetheBlochParams->get("resolution")}; + float tpcNSigma = static_cast((track.tpcSignal() - expBethe) / expSigma); + + float pt = track.sign() > 0 ? 2 * track.pt() : -2 * track.pt(); + // Filling histograms with track data before applying any cuts. + histos.fill(HIST("RawEta"), track.eta()); + histos.fill(HIST("RawPhi"), track.phi()); + histos.fill(HIST("RawPt"), pt); + histos.fill(HIST("RawtpcNSigma"), collision.centFT0C(), pt, tpcNSigma); + histos.fill(HIST("RawtofNSigma"), collision.centFT0C(), pt, track.tofNSigmaDe()); + + // If the track is good, fill the "after cuts" histograms. + if (isGoodTrack(track)) { + histos.fill(HIST("Eta"), track.eta()); + histos.fill(HIST("Phi"), track.phi()); + histos.fill(HIST("Pt"), pt); + histos.fill(HIST("tpcNSigma"), collision.centFT0C(), pt, tpcNSigma); + histos.fill(HIST("TpcSignal"), track.tpcInnerParam(), track.tpcSignal()); + + if (std::abs(tpcNSigma) < tpcNSigmaCut) { + histos.fill(HIST("tofNSigma"), collision.centFT0C(), pt, track.tofNSigmaDe()); + } + } + } + } + + PROCESS_SWITCH(AntiNucleiTask, process, "process", 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 b5a5a2c3ee4..873bbb3dfc9 100644 --- a/PWGLF/Tasks/Nuspex/AntimatterAbsorptionHMPID.cxx +++ b/PWGLF/Tasks/Nuspex/AntimatterAbsorptionHMPID.cxx @@ -12,33 +12,35 @@ /// \author Alberto Caliva (alberto.caliva@cern.ch) /// \since June 27, 2023 -#include -#include -#include -#include +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/Propagator.h" #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" #include "Framework/HistogramRegistry.h" #include "Framework/RunningWorkflowInfo.h" -#include "Framework/DataTypes.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/PID/PIDTOF.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/TrackParametrization.h" +#include "Framework/runDataProcessing.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" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/TrackParametrization.h" + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Nuspex/CMakeLists.txt b/PWGLF/Tasks/Nuspex/CMakeLists.txt index a69ac7d6743..20c32bc73de 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 @@ -24,21 +24,6 @@ o2physics_add_dpl_workflow(nuclei-hist PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(hypertriton3bodyanalysis - SOURCES hypertriton3bodyanalysis.cxx - PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore - 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 - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(helium-flow SOURCES helium_flow.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -54,11 +39,6 @@ o2physics_add_dpl_workflow(hyhefour-analysis PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(antid-lambda-ebye - SOURCES antidLambdaEbye.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(mc-spectra-efficiency SOURCES mcspectraefficiency.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -89,13 +69,23 @@ 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 COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(spectra-charged - SOURCES spectraCharged.cxx +o2physics_add_dpl_workflow(charged-particles + SOURCES chargedParticles.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pcc-qa + SOURCES pccQa.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -134,9 +124,55 @@ o2physics_add_dpl_workflow(nuclei-ebye PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(anti-nuclei-hist + SOURCES AntiNucleiTask.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(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 FastJet::FastJet FastJet::Contrib + SOURCES angularCorrelationsInJets.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib COMPONENT_NAME Analysis) -endif() \ No newline at end of file + +o2physics_add_dpl_workflow(antinuclei-in-jets + SOURCES antinucleiInJets.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(kink-pika + SOURCES spectraKinkPiKa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(he3-lambda-derived-analysis + SOURCES he3LambdaDerivedAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(dedx-pid-analysis + SOURCES dedxPidAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pikp-raa-analysis + SOURCES piKpRAA.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(chargedparticle-raa + SOURCES chargedparticleRaa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +endif() diff --git a/PWGLF/Tasks/Nuspex/LFNucleiBATask.cxx b/PWGLF/Tasks/Nuspex/LFNucleiBATask.cxx index d1f0f3f3977..09ddf7d765a 100644 --- a/PWGLF/Tasks/Nuspex/LFNucleiBATask.cxx +++ b/PWGLF/Tasks/Nuspex/LFNucleiBATask.cxx @@ -16,35 +16,64 @@ /// /// \author Giovanni Malfattore and Rutuparna Rath /// + #include "PWGLF/DataModel/LFNucleiTables.h" -#include -#include -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/HistogramRegistry.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/trackUtilities.h" -#include "Common/CCDB/EventSelectionParams.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include "TMCProcess.h" +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; struct LFNucleiBATask { + Service ccdb; + Service pdgDB; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // Efficiency configurator + std::unordered_set effEvtSet; + bool effEvtSetReady = false; + Configurable enableEffEvtSet{"enableEffEvtSet", true, "If true, MCGen uses the event-set built by MCReco; if false, MCGen runs stand-alone."}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry spectraGen{"spectraGen", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - HistogramRegistry debugHistos{"debugHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry evtimeHistos{"evtimeHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry debugHistos{"debugHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + HistogramRegistry evtimeHistos{"evtimeHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + HistogramRegistry evLossHistos{"evLossHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + HistogramRegistry histoGen{"histoGen", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; // Enable particle for analysis Configurable enablePr{"enablePr", true, "Flag to enable proton analysis."}; @@ -53,40 +82,53 @@ struct LFNucleiBATask { Configurable enableHe{"enableHe", true, "Flag to enable helium-3 analysis."}; Configurable enableAl{"enableAl", true, "Flag to enable alpha analysis."}; - Configurable enableTrackingEff{"enableTrackingEff", 0, "Flag to enable tracking efficiency hitos."}; + Configurable enableTrackingEff{"enableTrackingEff", 0, "Flag to enable tracking efficiency histos."}; + 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 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 useTVXtrigger{"useTVXtrigger", 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"}; - Configurable cfgHighMultCut{"cfgHighMultCut", 100.0f, "Accepted multiplicity percentage higher limit"}; + Configurable cfgMultCutLow{"cfgMultCutLow", 0.0f, "Accepted multiplicity percentage lower limit"}; + Configurable cfgMultCutHigh{"cfgMultCutHigh", 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"}; + Configurable cfgVzCutLow{"cfgVzCutLow", -10.0f, "Accepted z-vertex lower limit"}; + Configurable cfgVzCutHigh{"cfgVzCutHigh", 10.0f, "Accepted z-vertex upper 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 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)"}; + Configurable cfgMomentumCut{"cfgMomentumCut", 0.3f, "Value of the p selection for spectra (default 0.3)"}; + Configurable cfgEtaCut{"cfgEtaCut", 0.8f, "Value of the eta selection for spectra (default 0.8)"}; + Configurable cfgRapidityCutLow{"cfgRapidityCutLow", -1.0f, "Value of the low rapidity selection for spectra (default -1.0)"}; + Configurable cfgRapidityCutHigh{"cfgRapidityCutHigh", 1.0f, "Value of the high rapidity selection for spectra (default 1.0)"}; } kinemOptions; Configurable isPVContributorCut{"isPVContributorCut", false, "Flag to enable isPVContributor cut."}; + Configurable initITSPID{"initITSPID", false, "Flag to init the ITS PID response"}; struct : ConfigurableGroup { Configurable nsigmaTPCPr{"nsigmaTPCPr", 3.f, "Value of the Nsigma TPC cut for protons"}; @@ -96,8 +138,16 @@ struct LFNucleiBATask { Configurable nsigmaTPCAl{"nsigmaTPCAl", 3.f, "Value of the Nsigma TPC cut for alpha"}; } nsigmaTPCvar; + struct : ConfigurableGroup { + Configurable useITSDeCut{"useITSDeCut", false, "Select Deuteron if compatible with deuteron hypothesis (via SigmaITS)"}; + Configurable useITSHeCut{"useITSHeCut", false, "Select Helium if compatible with helium hypothesis (via SigmaITS)"}; + Configurable nsigmaITSDe{"nsigmaITSDe", -1.f, "Value of the Nsigma ITS cut for deuteron ( > nSigmaITSHe)"}; + 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)"}; + Configurable cfgBetaCut{"cfgBetaCut", 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"}; @@ -108,22 +158,27 @@ struct LFNucleiBATask { 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"}; + Configurable enableCustomDCACut{"enableCustomDCACut", 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)"}; + Configurable cfgCustomDCA{"cfgCustomDCA", 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 'enableCustomDCACut' to be enabled."}; + Configurable cfgCustomDCAxy{"cfgCustomDCAxy", 0.05f, "Value of the DCAxy selection for spectra (default 0.05 cm)"}; + Configurable cfgCustomDCAz{"cfgCustomDCAz", 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])."}; @@ -133,22 +188,26 @@ struct LFNucleiBATask { 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"}; + Configurable enablePIDplot{"enablePIDplot", false, "Flag to enable PID histograms for debug"}; + Configurable enableEffPlots{"enableEffPlots", false, "Flag to enable histograms for efficiency debug."}; + Configurable enableNoTOFPlots{"enableNoTOFPlots", false, "Flag to enable histograms for TOF debug."}; + } outFlagOptions; - Configurable enablePIDplot{"enablePIDplot", false, "Flag to enable PID histograms for debug"}; Configurable enableDebug{"enableDebug", false, "Flag to enable histograms for debug"}; - Configurable enablePtSpectra{"enablePtSpectra", false, "Flag to enable histograms for efficiency debug."}; Configurable usenITSLayer{"usenITSLayer", false, "Flag to enable ITS layer hit"}; Configurable useHasTRDConfig{"useHasTRDConfig", 0, "No selections on TRD (0); With TRD (1); Without TRD (2)"}; Configurable massTOFConfig{"massTOFConfig", 0, "Estimate massTOF using beta with (0) TPC momentum (1) TOF expected momentum (2) p momentum."}; Configurable helium3Pt{"helium3Pt", 0, "Select use default pT (0) or use instead 2*pT (1) for helium-3"}; - Configurable DeuteronPt{"DeuteronPt", 0, "Select (0) to apply deuteron pT shift or (1) to use default pT."}; - Configurable antiDeuteronPt{"antiDeuteronPt", 0, "Select (0) to apply antideuteron pT shift or (1) to use default pT."}; + Configurable unableDPtShift{"unableDPtShift", 0, "Select (0) to apply deuteron pT shift or (1) to use default pT."}; + Configurable unableAntiDPtShift{"unableAntiDPtShift", 0, "Select (0) to apply antideuteron pT shift or (1) to use default pT."}; // Additional function used for pT-shift calibration TF1* fShiftPtHe = 0; @@ -156,36 +215,107 @@ struct LFNucleiBATask { TF1* fShiftAntiD = 0; TF1* fShiftD = 0; - 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 enablePtShiftAntiD{"enablePtShiftAntiD", true, "Flag to enable Pt shift (for antiDeuteron only)"}; Configurable> parShiftPtD{"parShiftPtD", {-0.0955412, 0.798164, -0.536111, 0.0887876, -1.11022e-13}, "Parameters for Pt shift (if enabled)."}; + Configurable> parShiftPtAntiD{"parShiftPtAntiD", {-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 enablePtShiftHe{"enablePtShiftHe", 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> parShiftPtAntiHe{"parShiftPtAntiHe", {0.0f, 0.1f, 0.1f, 0.1f, 0.1f}, "Parameters for anti-helium3-Pt shift (if enabled)."}; Configurable enableCentrality{"enableCentrality", true, "Flag to enable centrality 3D histos)"}; + // ITS to TPC - Fake hit loop + static constexpr int kFakeLoop = 10; // Fixed O2Linter error + // TPC low/high momentum range + static constexpr float kCfgTpcClasses[] = {0.5f, 0.1f}; + static constexpr float kCfgKaonCut = 5.f; + // PDG codes and masses used in this analysis - static constexpr int PDGPion = 211; - static constexpr int PDGKaon = 321; - static constexpr int PDGProton = 2212; - static constexpr int PDGDeuteron = 1000010020; - 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; - - void init(o2::framework::InitContext&) + static constexpr int PDGPion = PDG_t::kPiPlus; + static constexpr int PDGKaon = PDG_t::kKPlus; + static constexpr int PDGProton = PDG_t::kProton; + static constexpr int PDGDeuteron = o2::constants::physics::Pdg::kDeuteron; + static constexpr int PDGTriton = o2::constants::physics::Pdg::kTriton; + static constexpr int PDGHelium = o2::constants::physics::Pdg::kHelium3; + static constexpr int PDGAlpha = o2::constants::physics::Pdg::kAlpha; + static constexpr int PDGHyperTriton = o2::constants::physics::Pdg::kHyperTriton; + static constexpr float MassProtonVal = o2::constants::physics::MassProton; + static constexpr float MassDeuteronVal = o2::constants::physics::MassDeuteron; + static constexpr float MassTritonVal = o2::constants::physics::MassTriton; + static constexpr float MassHeliumVal = o2::constants::physics::MassHelium3; + static constexpr float MassAlphaVal = o2::constants::physics::MassAlpha; + + // PDG of Mothers + static constexpr int kPdgMotherList[] = { + PDG_t::kPiPlus, + PDG_t::kKPlus, + PDG_t::kK0Short, + PDG_t::kNeutron, + PDG_t::kProton, + PDG_t::kLambda0, + o2::constants::physics::Pdg::kDeuteron, + o2::constants::physics::Pdg::kHelium3, + o2::constants::physics::Pdg::kTriton, + o2::constants::physics::Pdg::kHyperTriton, + o2::constants::physics::Pdg::kAlpha}; + + static constexpr int kNumMotherList = sizeof(kPdgMotherList) / sizeof(kPdgMotherList[0]); + + static constexpr const char* kMotherNames[kNumMotherList] = { + "#pi^{+}", + "K^{+}", + "K^{0}_{S}", + "n", + "p", + "#Lambda", + "d", + "He3", + "t", + "^{3}_{#Lambda}H", + "He4"}; + + static constexpr int kMaxNumMom = 2; // X: 0..4, overflow=5 + + 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& context) { + if (initITSPID) { + o2::aod::ITSResponse::setParameters(context); + } + if (skimmingOptions.applySkimming) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + effEvtSet.clear(); + effEvtSetReady = false; + 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"}; @@ -195,34 +325,142 @@ 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, {{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 (doprocessEvSgLossMC) { + evLossHistos.add("evLoss/hEvent", "Event loss histograms; ; counts", HistType::kTH1F, {{4, 0., 4.}}); + 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, "MC Sel8 (TVX + NoTFB) (reco.)"); + evLossHistos.get(HIST("evLoss/hEvent"))->GetXaxis()->SetBinLabel(4, "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/hDeuteronTriggeredMCSel8", "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/hAntiDeuteronTriggeredMCSel8", "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.}}); + + evLossHistos.add("evLoss/pt/hHeliumTriggeredTVX", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hHeliumTriggeredSel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hHeliumTriggeredMCSel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hHeliumGen", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hAntiHeliumTriggeredTVX", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hAntiHeliumTriggeredSel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hAntiHeliumTriggeredMCSel8", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + evLossHistos.add("evLoss/pt/hAntiHeliumGen", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{100, 0., 5.}}); + } + if (doprocessMCRecoLfPidEv) { + 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/prim/pT_nocut_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_TVXtrigger_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_TFrameBorder_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_ITSROFBorder_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_sel8_He", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_MCsel8_He", "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/prim/pT_nocut_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_TVXtrigger_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_TFrameBorder_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_ITSROFBorder_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_sel8_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + spectraGen.add("LfEv/helium/prim/pT_MCsel8_antiHe", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{ptHeAxis}}); + } + + if (doprocessMCGenLosses) { + histoGen.add("events/hMCGen", "hMCGen", {HistType::kTH1D, {{3, 0.f, 3.f}}}); + histoGen.get(HIST("events/hMCGen"))->GetXaxis()->SetBinLabel(1, "All"); + histoGen.get(HIST("events/hMCGen"))->GetXaxis()->SetBinLabel(2, "Vtz"); + histoGen.get(HIST("events/hMCGen"))->GetXaxis()->SetBinLabel(3, "INELgt0"); + + histoGen.add("events/hMCGenReco", "hMCGenReco", {HistType::kTH1D, {{2, 0.f, 2.f}}}); + histoGen.get(HIST("events/hMCGenReco"))->GetXaxis()->SetBinLabel(1, "INEL"); + histoGen.get(HIST("events/hMCGenReco"))->GetXaxis()->SetBinLabel(2, "INELgt0"); + + histoGen.add("events/hMCReco", "hMCReco", {HistType::kTH1D, {{3, 0.f, 3.f}}}); + histoGen.get(HIST("events/hMCReco"))->GetXaxis()->SetBinLabel(1, "All"); + histoGen.get(HIST("events/hMCReco"))->GetXaxis()->SetBinLabel(2, "Ev sel passed"); + histoGen.get(HIST("events/hMCReco"))->GetXaxis()->SetBinLabel(3, "INELgt0"); + + histoGen.add("helium/MCGen/h2HeliumYvsPt", "#it{y} vs #it{p}_{T} (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); + histoGen.add("helium/MCGen/h2antiHeliumYvsPt", "#it{y} vs #it{p}_{T} (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); + + histoGen.add("helium/MCGen/ptGen_INEL_Prim_He", "generated particles", HistType::kTH1F, {ptHeAxis}); + histoGen.add("helium/MCGen/ptGen_INEL_Prim_antiHe", "generated particles", HistType::kTH1F, {ptHeAxis}); + + histoGen.add("helium/MCGen/ptGen_INELgt0_Prim_He", "generated particles", HistType::kTH1F, {ptHeAxis}); + histoGen.add("helium/MCGen/ptGen_INELgt0_Prim_antiHe", "generated particles", HistType::kTH1F, {ptHeAxis}); + + histoGen.add("helium/MCGenReco/h2HeliumYvsPt", "#it{y} vs #it{p}_{T} (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); + histoGen.add("helium/MCGenReco/h2antiHeliumYvsPt", "#it{y} vs #it{p}_{T} (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); + + histoGen.add("helium/MCGenReco/ptGen_INEL_Prim_He", "generated particles", HistType::kTH1F, {ptHeAxis}); + histoGen.add("helium/MCGenReco/ptGen_INEL_Prim_antiHe", "generated particles", HistType::kTH1F, {ptHeAxis}); + + histoGen.add("helium/MCGenReco/ptGen_INELgt0_Prim_He", "generated particles", HistType::kTH1F, {ptHeAxis}); + histoGen.add("helium/MCGenReco/ptGen_INELgt0_Prim_antiHe", "generated particles", HistType::kTH1F, {ptHeAxis}); + + histoGen.add("helium/MCReco/ptGen_INEL_Prim_He", "generated particles", HistType::kTH1F, {ptHeAxis}); + histoGen.add("helium/MCReco/ptGen_INEL_Prim_antiHe", "generated particles", HistType::kTH1F, {ptHeAxis}); + + histoGen.add("helium/MCReco/ptGen_INELgt0_Prim_He", "generated particles", HistType::kTH1F, {ptHeAxis}); + histoGen.add("helium/MCReco/ptGen_INELgt0_Prim_antiHe", "generated particles", HistType::kTH1F, {ptHeAxis}); + + if (enableCentrality) { + histoGen.add("events/hMCGenVsMult", "hMCGenVsMult", HistType::kTH2D, {{3, 0.f, 3.f}, {binsPercentile}}); + histoGen.get(HIST("events/hMCGenVsMult"))->GetXaxis()->SetBinLabel(1, "All"); + histoGen.get(HIST("events/hMCGenVsMult"))->GetXaxis()->SetBinLabel(2, "Vtz"); + histoGen.get(HIST("events/hMCGenVsMult"))->GetXaxis()->SetBinLabel(3, "INELgt0"); + + histoGen.add("events/hMCGenRecoVsMult", "hMCGenRecoVsMult", HistType::kTH2D, {{2, 0.f, 2.f}, {binsPercentile}}); + histoGen.get(HIST("events/hMCGenRecoVsMult"))->GetXaxis()->SetBinLabel(1, "INEL"); + histoGen.get(HIST("events/hMCGenRecoVsMult"))->GetXaxis()->SetBinLabel(2, "INELgt0"); + + histoGen.add("helium/MCGen/ptGenVsMult_INEL_Prim_He", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCGen/ptGenVsMult_INEL_Prim_antiHe", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCGen/ptGenVsMult_INELgt0_Prim_He", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCGen/ptGenVsMult_INELgt0_Prim_antiHe", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + + histoGen.add("helium/MCGenReco/ptGenVsMult_INEL_Prim_He", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCGenReco/ptGenVsMult_INEL_Prim_antiHe", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCGenReco/ptGenVsMult_INELgt0_Prim_He", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCGenReco/ptGenVsMult_INELgt0_Prim_antiHe", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + + histoGen.add("helium/MCReco/ptGenVsMult_INEL_Prim_He", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCReco/ptGenVsMult_INEL_Prim_antiHe", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCReco/ptGenVsMult_INELgt0_Prim_He", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histoGen.add("helium/MCReco/ptGenVsMult_INELgt0_Prim_antiHe", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + } + } if (enableDebug) { debugHistos.add("qa/h1VtxZ_nocut", "V_{z};V_{z} (in cm); counts", HistType::kTH1F, {{1500, -15, 15}}); @@ -238,28 +476,63 @@ struct LFNucleiBATask { } } - 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("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.}}); - - 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}}); - histos.add("qa/h1rTPC", "ratio of ncr over findable in TPC; rTPC; counts", HistType::kTH1F, {{200, 0.9, 1.8}}); - histos.add("qa/h1TPCnfound", "ratio of found cluster in TPC; TPCnfound; counts", HistType::kTH1F, {{150, 60, 170}}); - histos.add("qa/h1chi2ITS", "#chi^{2}_{ITS}/n_{ITS}; #chi^{2}_{ITS}/n_{ITS};counts", HistType::kTH1F, {{51, -0.5, 50.5}}); - 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("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"); + + if (enableCentrality) { + histos.add("event/eventSelection", "eventSelection", HistType::kTH2D, {{8, -0.5, 7.5}, {binsPercentile, "Centrality FT0M"}}); + auto h2d = histos.get(HIST("event/eventSelection")); + if (skimmingOptions.applySkimming) + h2d->GetXaxis()->SetBinLabel(1, "Skimmed events"); + else + h2d->GetXaxis()->SetBinLabel(1, "Total"); + + h2d->GetXaxis()->SetBinLabel(2, "TVX trigger cut"); + h2d->GetXaxis()->SetBinLabel(3, "TF border cut"); + h2d->GetXaxis()->SetBinLabel(4, "ITS ROF cut"); + h2d->GetXaxis()->SetBinLabel(5, "TVX + TF + ITS ROF"); + h2d->GetXaxis()->SetBinLabel(6, "Sel8 cut"); + h2d->GetXaxis()->SetBinLabel(7, "Z-vert Cut"); + h2d->GetXaxis()->SetBinLabel(8, "Multiplicity cut"); + } else { + histos.add("event/eventSelection", "eventSelection", HistType::kTH1D, {{8, -0.5, 7.5}}); + auto h1d = histos.get(HIST("event/eventSelection")); + if (skimmingOptions.applySkimming) + h1d->GetXaxis()->SetBinLabel(1, "Skimmed events"); + else + h1d->GetXaxis()->SetBinLabel(1, "Total"); + + h1d->GetXaxis()->SetBinLabel(2, "TVX trigger cut"); + h1d->GetXaxis()->SetBinLabel(3, "TF border cut"); + h1d->GetXaxis()->SetBinLabel(4, "ITS ROF cut"); + h1d->GetXaxis()->SetBinLabel(5, "TVX + TF + ITS ROF"); + h1d->GetXaxis()->SetBinLabel(6, "Sel8 cut"); + h1d->GetXaxis()->SetBinLabel(7, "Z-vert Cut"); + h1d->GetXaxis()->SetBinLabel(8, "Multiplicity cut"); + } + + if (enableCentrality) + histos.add("event/h1VtxZ", "V_{z};V_{z} (in cm); counts", HistType::kTH2F, {{1500, -15, 15}, {binsPercentile, "Centrality FT0M"}}); + else + histos.add("event/h1VtxZ", "V_{z};V_{z} (in cm); counts", HistType::kTH1F, {{1500, -15, 15}}); + + if (outFlagOptions.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.}}); + } + + if (enableDebug) { + 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}}); + histos.add("qa/h1rTPC", "ratio of ncr over findable in TPC; rTPC; counts", HistType::kTH1F, {{200, 0.9, 1.8}}); + histos.add("qa/h1TPCnfound", "ratio of found cluster in TPC; TPCnfound; counts", HistType::kTH1F, {{150, 60, 170}}); + histos.add("qa/h1chi2ITS", "#chi^{2}_{ITS}/n_{ITS}; #chi^{2}_{ITS}/n_{ITS};counts", HistType::kTH1F, {{51, -0.5, 50.5}}); + histos.add("qa/h1chi2TPC", "#chi^{2}_{TPC}/n_{TPC}; #chi^{2}_{TPC}/n_{TPC}; counts", HistType::kTH1F, {{11, -0.5, 10.5}}); + } + + if (outFlagOptions.enableEffPlots) { 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}}); @@ -309,23 +582,19 @@ 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) { + if (outFlagOptions.enableEffPlots) { if (enableDebug) { debugHistos.add("tracks/eff/hPtP", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); debugHistos.add("tracks/eff/hPtantiP", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); - 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 (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.}}); - debugHistos.add("tracks/eff/hPtantiPTOFrebinned", "Track #it{p}_{T}; #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{50, 0., 5.}}); } } @@ -334,10 +603,6 @@ struct LFNucleiBATask { histos.add("tracks/eff/proton/hPtantiPr", "Track #it{p}_{T} (#bar{p}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); histos.add("tracks/eff/proton/hPtPrTOF", "Track #it{p}_{T} (p); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); histos.add("tracks/eff/proton/hPtantiPrTOF", "Track #it{p}_{T} (#bar{p}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); - histos.add("tracks/eff/proton/hPtPrrebinned", "Track #it{p}_{T} (p); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{50, 0., 5.}}); - histos.add("tracks/eff/proton/hPtantiPrrebinned", "Track #it{p}_{T} (#bar{p}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{50, 0., 5.}}); - histos.add("tracks/eff/proton/hPtPrTOFrebinned", "Track #it{p}_{T} (p); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{50, 0., 5.}}); - histos.add("tracks/eff/proton/hPtantiPrTOFrebinned", "Track #it{p}_{T} (#bar{p}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{50, 0., 5.}}); } if (enableDe) { histos.add("tracks/eff/deuteron/hPtDe", "Track #it{p}_{T} (d); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); @@ -362,23 +627,18 @@ struct LFNucleiBATask { // DCAxy,z 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/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}}); @@ -389,31 +649,34 @@ 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 (outFlagOptions.enableNoTOFPlots) { + 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/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/h3DCAvsPtHelium", "", HistType::kTHnSparseD, {dcaxyAxis, dcazAxis, ptZHeAxis}); + histos.add("tracks/helium/dca/before/h3DCAvsPtantiHelium", "", HistType::kTHnSparseD, {dcaxyAxis, dcazAxis, ptZHeAxis}); + 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.enableNoTOFPlots) { + 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}}); @@ -425,8 +688,6 @@ struct LFNucleiBATask { } } 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}}); @@ -461,6 +722,8 @@ struct LFNucleiBATask { 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/h3DCAvsPtHelium", "", HistType::kTHnSparseD, {dcaxyAxis, dcazAxis, ptZHeAxis}); + histos.add("tracks/helium/dca/after/h3DCAvsPtantiHelium", "", HistType::kTHnSparseD, {dcaxyAxis, dcazAxis, ptZHeAxis}); 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}}); @@ -506,20 +769,13 @@ struct LFNucleiBATask { histos.add("tracks/triton/h1antiTritonSpectra", "#it{p}_{T} (#bar{t})", HistType::kTH1F, {ptAxis}); } if (enableHe) { - histos.add("tracks/helium/h1HeliumSpectra", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1antiHeliumSpectra", "#it{p}_{T}/z (#bar{He})", HistType::kTH1F, {ptZHeAxis}); - - histos.add("tracks/helium/h2HeliumYvsPt", "#it{y} vs #it{p}_{T}/z (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptZHeAxis}}); histos.add("tracks/helium/h2HeliumYvsPt_Z2", "#it{y} vs #it{p}_{T} (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); - histos.add("tracks/helium/h2HeliumEtavsPt", "#it{#eta} vs #it{p}_{T}/z (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptZHeAxis}}); histos.add("tracks/helium/h2HeliumEtavsPt_Z2", "#it{#eta} vs #it{p}_{T} (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); histos.add("tracks/helium/h1HeliumSpectra_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); histos.add("tracks/helium/h1antiHeliumSpectra_Z2", "#it{p}_{T} (#bar{He})", HistType::kTH1F, {ptHeAxis}); - histos.add("tracks/helium/h2antiHeliumYvsPt", "#it{y} vs #it{p}_{T}/z (#bar{He})", HistType::kTH2F, {{96, -1.2, 1.2}, {ptZHeAxis}}); histos.add("tracks/helium/h2antiHeliumYvsPt_Z2", "#it{y} vs #it{p}_{T} (#bar{He})", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); - histos.add("tracks/helium/h2antiHeliumEtavsPt", "#it{#eta} vs #it{p}_{T}/z (#bar{He})", HistType::kTH2F, {{96, -1.2, 1.2}, {ptZHeAxis}}); histos.add("tracks/helium/h2antiHeliumEtavsPt_Z2", "#it{#eta} vs #it{p}_{T} (#bar{He})", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); } if (enableAl) { @@ -527,6 +783,13 @@ struct LFNucleiBATask { histos.add("tracks/alpha/h1antiAlphaSpectra", "#it{p}_{T} (#bar{#alpha})", HistType::kTH1F, {ptAxis}); } if (doprocessMCReco || doprocessMCRecoLfPid || doprocessMCRecoFiltered || doprocessMCRecoFilteredLight) { + + histos.add("tracks/hItsDeHeChecker", "d and {}^{3}He counters", HistType::kTH1F, {{4, -0.5, 3.5}}); + histos.get(HIST("tracks/hItsDeHeChecker"))->GetXaxis()->SetBinLabel(1, "totDe"); + histos.get(HIST("tracks/hItsDeHeChecker"))->GetXaxis()->SetBinLabel(2, "totHe"); + histos.get(HIST("tracks/hItsDeHeChecker"))->GetXaxis()->SetBinLabel(3, "keptDe"); + histos.get(HIST("tracks/hItsDeHeChecker"))->GetXaxis()->SetBinLabel(4, "keptHe"); + // inclusive production if (enableTrackingEff) { debugHistos.add("tracks/trackingEff/h1_its", "#it{p}_{T} (p)", HistType::kTH1F, {ptAxis}); @@ -719,23 +982,18 @@ struct LFNucleiBATask { histos.add("tracks/triton/h1antiTritonSpectraTrueTransport", "#it{p}_{T} (#bar{t})", HistType::kTH1F, {ptAxis}); } if (enableHe) { - histos.add("tracks/helium/h1HeliumSpectraTrue", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1HeliumSpectraTrueWPID", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1HeliumSpectraTruePrim", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1HeliumSpectraTrueSec", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1HeliumSpectraTrueTransport", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1HeliumSpectraTrue_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); histos.add("tracks/helium/h1HeliumSpectraTrueWPID_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); histos.add("tracks/helium/h1HeliumSpectraTruePrim_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); histos.add("tracks/helium/h1HeliumSpectraTrueSec_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); histos.add("tracks/helium/h1HeliumSpectraTrueTransport_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); - histos.add("tracks/helium/h1antiHeliumSpectraTrue", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1antiHeliumSpectraTrueWPID", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1antiHeliumSpectraTruePrim", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1antiHeliumSpectraTrueSec", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); - histos.add("tracks/helium/h1antiHeliumSpectraTrueTransport", "#it{p}_{T}/z (He)", HistType::kTH1F, {ptZHeAxis}); + if (enableCentrality) { + histos.add("tracks/helium/h2HeliumSpectraTrueVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histos.add("tracks/helium/h2HeliumSpectraTrueWPIDVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histos.add("tracks/helium/h2HeliumSpectraTruePrimVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histos.add("tracks/helium/h2HeliumSpectraTrueSecVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + } histos.add("tracks/helium/h1antiHeliumSpectraTrue_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); histos.add("tracks/helium/h1antiHeliumSpectraTrueWPID_Z2", "#it{p}_{T} (He)", HistType::kTH1F, {ptHeAxis}); @@ -743,16 +1001,27 @@ 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 (enableCentrality) { + histos.add("tracks/helium/h2antiHeliumSpectraTrueVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histos.add("tracks/helium/h2antiHeliumSpectraTrueWPIDVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histos.add("tracks/helium/h2antiHeliumSpectraTruePrimVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histos.add("tracks/helium/h2antiHeliumSpectraTrueSecVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + } + 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 (enableCentrality) { + histos.add("tracks/helium/TOF/h2HeliumSpectraTruePrimVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + histos.add("tracks/helium/TOF/h2antiHeliumSpectraTruePrimVsMult_Z2", "#it{p}_{T} (He)", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); + } } - 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 (outFlagOptions.enableEffPlots) { + histos.add("tracks/eff/helium/hPtHeTrue_Z2", "Track #it{p}_{T} (He); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); + histos.add("tracks/eff/helium/hPtantiHeTrue_Z2", "Track #it{p}_{T} (#bar{He}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); 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.}}); + histos.add("tracks/eff/helium/hPtHeTOFTrue_Z2", "Track #it{p}_{T} (He); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); + histos.add("tracks/eff/helium/hPtantiHeTOFTrue_Z2", "Track #it{p}_{T} (#bar{He}); #it{p}_{T} (GeV/#it{c}); counts", HistType::kTH1F, {{400, 0., 8.}}); } } } @@ -774,38 +1043,55 @@ struct LFNucleiBATask { 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/hDCAxyVsPtProtonTrueTransport", "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/hNumMothers", "N mothers per particle; N mothers;counts", HistType::kTH1I, {{7, 1.0, 8.0}}); + histos.add("tracks/proton/dca/before/hMomTrueMaterial", "MC mothers;mother index;mother type; mother #it{p}_{T}", HistType::kTH3F, {{2, -2.0, 2.0}, {kNumMotherList + 2, -1.5, static_cast(kNumMotherList) + 0.5}, {150, 0.0, 15.0}}); + + std::shared_ptr hTempPr = histos.get(HIST("tracks/proton/dca/before/hMomTrueMaterial")); + TH3* hPdgPr = hTempPr.get(); + + TAxis* axPdgPr = hPdgPr->GetXaxis(); + axPdgPr->SetBinLabel(1, "antiparticles"); + axPdgPr->SetBinLabel(2, "particles"); + + TAxis* ayPdgPr = hPdgPr->GetYaxis(); + ayPdgPr->SetBinLabel(1, "undef."); + ayPdgPr->SetBinLabel(2, "other"); + for (int i = 0; i < kNumMotherList; i++) { + ayPdgPr->SetBinLabel(i + 3, kMotherNames[i]); + } 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/hDCAxyVsPtantiProtonTrueTransport", "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}}); 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/hDCAxyVsPtProtonTrueTransport", "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/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/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/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/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/hDCAzVsPtProtonTrueTransport", "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/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/hDCAzVsPtantiProtonTrueTransport", "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}}); } } @@ -829,111 +1115,96 @@ struct LFNucleiBATask { 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/hDCAxyVsPtDeuteronTrueTransport", "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/hDCAxyVsPtantiDeuteronTrue", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + histos.add("tracks/deuteron/dca/before/hNumMothers", "N mothers per particle; N mothers;counts", HistType::kTH1I, {{7, 1.0, 8.0}}); + histos.add("tracks/deuteron/dca/before/hMomTrueMaterial", "MC mothers;mother index;mother type; mother #it{p}_{T}", HistType::kTH3F, {{2, -2.0, 2.0}, {kNumMotherList + 2, -1.5, static_cast(kNumMotherList) + 0.5}, {150, 0.0, 15.0}}); - 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/hDCAxyVsPtantiDeuteronTrueTransport", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + std::shared_ptr hTempDe = histos.get(HIST("tracks/deuteron/dca/before/hMomTrueMaterial")); + TH3* hPdgDe = hTempDe.get(); - // Fake & wrong histos - histos.add("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrue", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); + TAxis* axPdgDe = hPdgDe->GetXaxis(); + axPdgDe->SetBinLabel(1, "antiparticles"); + axPdgDe->SetBinLabel(2, "particles"); - 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}}); + TAxis* ayPdgDe = hPdgDe->GetYaxis(); + ayPdgDe->SetBinLabel(1, "undef."); + ayPdgDe->SetBinLabel(2, "other"); + for (int i = 0; i < kNumMotherList; i++) { + ayPdgDe->SetBinLabel(i + 3, kMotherNames[i]); + } - 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/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}}); + 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/wrong/hDCAxyVsPtDeuteronTrue", "DCAxy vs Pt (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/wrong/hDCAxyVsPtDeuteronTruePrim", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/hDCAxyVsPtDeuteronTrueSec", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/hDCAxyVsPtDeuteronTrueTransport", "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/hDCAxyVsPtDeuteronTrueMaterial", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/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/hDCAxyVsPtantiDeuteronTrue", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/hDCAxyVsPtantiDeuteronTruePrim", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/hDCAxyVsPtantiDeuteronTrueSec", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/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/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/hDCAxyVsPtantiDeuteronTrueMaterial", "DCAxy vs Pt (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/hDCAxyVsPtDeuteronTrueTransport", "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/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/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/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/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/hDCAzVsPtDeuteronTrueTransport", "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/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/hDCAzVsPtantiDeuteronTrueTransport", "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/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/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/fake/TOF/hDCAzVsPtantiDeuteronTrue", "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/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}}); + 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/hDCAxyVsPtDeuteronTrueMaterial", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/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/hDCAxyVsPtantiDeuteronTrue", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/TOF/hDCAxyVsPtDeuteronTruePrim", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/TOF/hDCAxyVsPtDeuteronTrueSec", "DCAxy vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/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/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/hDCAxyVsPtantiDeuteronTrueMaterial", "DCAxy vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptAxis}, {dcaxyAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/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/hDCAzVsPtDeuteronTrue", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/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/wrong/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/wrong/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/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/wrong/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/hDCAzVsPtantiDeuteronTrue", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/TOF/hDCAzVsPtDeuteronTruePrim", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/TOF/hDCAzVsPtDeuteronTrueSec", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/TOF/hDCAzVsPtDeuteronTrueTransport", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - - // histos.add("tracks/deuteron/dca/before/wrong/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/wrong/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/wrong/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/wrong/TOF/hDCAzVsPtantiDeuteronTrueTransport", "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}}); + } } } @@ -959,38 +1230,41 @@ struct LFNucleiBATask { 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/hDCAxyVsPtTritonTrueTransport", "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/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/hDCAxyVsPtantiTritonTrueMaterial", "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/hDCAxyVsPtTritonTrueTransport", "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/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/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/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/hDCAzVsPtTritonTrue", "DCAz vs Pt (t); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); + // Unused histograms + // 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/hDCAzVsPtTritonTrueTransport", "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/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/hDCAzVsPtantiTritonTrueTransport", "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}}); } } @@ -1007,31 +1281,32 @@ struct LFNucleiBATask { 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}}); + // Unused histograms + // 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/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/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/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/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/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/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}}); - } + // 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) { @@ -1041,148 +1316,174 @@ struct LFNucleiBATask { 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/hDCAxyVsPtHeliumTrueTransport", "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/hNumMothers", "N mothers per particle; N mothers;counts", HistType::kTH1I, {{7, 1.0, 8.0}}); + histos.add("tracks/helium/dca/before/hMomTrueMaterial", "MC mothers;mother index;mother type; mother #it{p}_{T}", HistType::kTH3F, {{2, -2.0, 2.0}, {kNumMotherList + 2, -1.5, static_cast(kNumMotherList) + 0.5}, {150, 0.0, 15.0}}); + + // Fix for getting TH3 pointer + std::shared_ptr hTempHe = histos.get(HIST("tracks/helium/dca/before/hMomTrueMaterial")); + TH3* hPdgHe = hTempHe.get(); + + TAxis* axPdgHe = hPdgHe->GetXaxis(); + axPdgHe->SetBinLabel(1, "antiparticles"); + axPdgHe->SetBinLabel(2, "particles"); + + TAxis* ayPdgHe = hPdgHe->GetYaxis(); + ayPdgHe->SetBinLabel(1, "undef."); + ayPdgHe->SetBinLabel(2, "other"); + for (int i = 0; i < kNumMotherList; i++) { + ayPdgHe->SetBinLabel(i + 3, kMotherNames[i]); + } 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/hDCAxyVsPtantiHeliumTrueTransport", "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/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/hDCAzVsPtHeliumTrueTransport", "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/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/hDCAzVsPtantiHeliumTrueTransport", "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}}); 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/hDCAxyVsPtHeliumTrueTransport", "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/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, {{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/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/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/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, {{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/hDCAzVsPtHeliumTrueTransport", "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/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, {{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/hDCAzVsPtantiHeliumTrueTransport", "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}}); } // Fake & wrong histos - histos.add("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + 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/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/hDCAxyVsPtHeliumTrueMaterial", "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/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/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/hDCAxyVsPtantiHeliumTrueMaterial", "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/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/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/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}}); + 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}}); + } - histos.add("tracks/helium/dca/before/wrong/hDCAxyVsPtHeliumTrue", "DCAxy vs Pt (He); #it{p}_{T} (GeV/#it{c}); DCAxy (cm)", HistType::kTH2F, {{ptZHeAxis}, {dcaxyAxis}}); + 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/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/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/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/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/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/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/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/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}}); + 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) { - 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}}); + 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/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/hDCAxyVsPtHeliumTrueMaterial", "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/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/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/hDCAxyVsPtantiHeliumTrueMaterial", "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/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/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/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}}); + 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}}); + } - 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}}); + 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/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/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/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/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/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/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/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/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/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/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/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/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/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}}); + 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}}); + } } } @@ -1244,13 +1545,13 @@ struct LFNucleiBATask { 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/hDCAxyVsPtAlphaTrueTransport", "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/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/hDCAxyVsPtantiAlphaTrueTransport", "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}}); } if (outFlagOptions.makeDCAAfterCutPlots) { @@ -1258,12 +1559,14 @@ struct LFNucleiBATask { 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}}); } } @@ -1274,13 +1577,13 @@ struct LFNucleiBATask { 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/hDCAzVsPtProtonTrueTransport", "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/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/hDCAzVsPtantiProtonTrueTransport", "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}}); } 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}}); @@ -1302,37 +1605,27 @@ struct LFNucleiBATask { 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/hDCAzVsPtDeuteronTrueTransport", "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/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/hDCAzVsPtantiDeuteronTrueTransport", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - - 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/hDCAzVsPtantiDeuteronTrueMaterial", "DCAz vs Pt (#bar{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}}); + 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/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}}); + 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/wrong/hDCAzVsPtDeuteronTrue", "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/wrong/hDCAzVsPtDeuteronTruePrim", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/hDCAzVsPtDeuteronTrueSec", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/hDCAzVsPtDeuteronTrueTransport", "DCAz vs Pt (d); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - - // histos.add("tracks/deuteron/dca/before/wrong/hDCAzVsPtantiDeuteronTrue", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - - // histos.add("tracks/deuteron/dca/before/wrong/hDCAzVsPtantiDeuteronTruePrim", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/hDCAzVsPtantiDeuteronTrueSec", "DCAz vs Pt (#bar{d}); #it{p}_{T} (GeV/#it{c}); DCAz (cm)", HistType::kTH2F, {{ptAxis}, {dcazAxis}}); - // histos.add("tracks/deuteron/dca/before/wrong/hDCAzVsPtantiDeuteronTrueTransport", "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 (outFlagOptions.makeDCAAfterCutPlots) { @@ -1357,13 +1650,13 @@ struct LFNucleiBATask { 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/hDCAzVsPtTritonTrueTransport", "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/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/hDCAzVsPtantiTritonTrueTransport", "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}}); } if (outFlagOptions.makeDCAAfterCutPlots) { @@ -1387,13 +1680,13 @@ struct LFNucleiBATask { 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/hDCAzVsPtAlphaTrueTransport", "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/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/hDCAzVsPtantiAlphaTrueTransport", "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}}); } if (outFlagOptions.makeDCAAfterCutPlots) { @@ -1413,35 +1706,47 @@ 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, {{400, -8.f, 8.f}, {dedxAxis}}); + if (nsigmaITSvar.showAverageClusterSize && outFlagOptions.enablePIDplot) { + histos.add("tracks/avgClusterSizePerCoslInvVsITSlayers", "", HistType::kTH3F, {{pZAxis}, {avClsEffAxis}, {8, -0.5, 7.5}}); + 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, {{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) { + if (outFlagOptions.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, {{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}}); + 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, {{200, 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, {{200, 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, {{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}}); + 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, {{200, 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, {{200, 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, {{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}}); + 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, {{200, 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, {{200, 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, {{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}}); + 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, {{200, 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, {{200, 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, {{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}}); + 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, {{200, 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, {{200, 0.f, 8.f}, {dedxAxis}}); } } - if (outFlagOptions.doTOFplots) { + 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 && outFlagOptions.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) @@ -1466,36 +1771,52 @@ 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) { + histos.add("tracks/deuteron/h2DeuteronVspNSigmaITSDe", "NSigmaITS(d) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(d)", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + histos.add("tracks/deuteron/h2antiDeuteronVspNSigmaITSDe", "NSigmaITS(#bar{d}) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(#bar{d})", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + histos.add("tracks/deuteron/h2DeuteronVspNSigmaITSDe_wTPCpid", "NSigmaITS(d) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(d)", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + histos.add("tracks/deuteron/h2antiDeuteronVspNSigmaITSDe_wTPCpid", "NSigmaITS(#bar{d}) vs p/z; #it{p}/z (GeV/#it{c}); NSigmaITS(#bar{d})", HistType::kTH2F, {{pZAxis}, {sigmaITSAxis}}); + 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/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/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}}); + + if (enableCentrality) { + histos.add("tracks/helium/h3HeliumVspTNSigmaTPCVsMult", "NSigmaTPC(He) vs pT; #it{p}_{T} (GeV/#it{c}) vs mult; NSigmaTPC", HistType::kTH3F, {{ptZHeAxis}, {sigmaTPCAxis}, {binsPercentile}}); + histos.add("tracks/helium/h3antiHeliumVspTNSigmaTPCVsMult", "NSigmaTPC(#bar{He}) vs pT; #it{p}_{T} (GeV/#it{c}) vs mult; NSigmaTPC", HistType::kTH3F, {{ptZHeAxis}, {sigmaTPCAxis}, {binsPercentile}}); + } + + 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 @@ -1541,23 +1862,24 @@ struct LFNucleiBATask { // NSigmaTOF histograms 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}}); + 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}}); + 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, {{180, 0.4, 4.}, {250, 0., 5.}}); + if (outFlagOptions.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, {{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.}}); @@ -1621,6 +1943,10 @@ struct LFNucleiBATask { } } if (enableHe) { + if (enableCentrality) { + histos.add("tracks/helium/h3TOFmass2HeliumVsPtVsMult", "#Delta M^{2} (He) vs #it{p}_{T}/z; #Delta M^{2} (He); #it{p}_{T}/z (GeV/#it{c})", HistType::kTH3F, {{massHeAxis}, {ptZHeAxis}, {binsPercentile}}); + histos.add("tracks/helium/h3TOFmass2antiHeliumVsPtVsMult", "#Delta M^{2} (#bar{He}) vs #it{p}_{T}/z; #Delta M^{2} (#bar{He}); #it{p}_{T}/z (GeV/#it{c})", HistType::kTH3F, {{massHeAxis}, {ptZHeAxis}, {binsPercentile}}); + } histos.add("tracks/helium/h2TOFmass2antiHeliumVsPt", "#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", "#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}}); @@ -1631,7 +1957,7 @@ struct LFNucleiBATask { } } // 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}}); @@ -1674,24 +2000,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 @@ -1761,46 +2087,46 @@ 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 (outFlagOptions.enableExpSignalTOF) { @@ -1828,14 +2154,17 @@ 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 - spectraGen.add("histGenVetxZ", "PosZ generated events", HistType::kTH1F, {{1500, -15.f, 15.f, "Vertex Z (cm)"}}); + if (enableCentrality) + spectraGen.add("histGenVetxZ", "PosZ generated events", HistType::kTH2F, {{1500, -15.f, 15.f, "Vertex Z (cm)"}, {binsPercentile, "Centrality FT0M"}}); + else + spectraGen.add("histGenVetxZ", "PosZ generated events", HistType::kTH1F, {{1500, -15.f, 15.f, "Vertex Z (cm)"}}); spectraGen.add("helium/histPtGenHe", "PtGenHe", HistType::kTH1F, {{800, 0.f, 8.f}}); spectraGen.add("helium/histPtRecHe", "PtRecHe", HistType::kTH1F, {{800, 0.f, 8.f}}); @@ -1927,11 +2256,15 @@ struct LFNucleiBATask { if (enableHe) { spectraGen.add("helium/histGenPtHe", "generated particles", HistType::kTH1F, {ptHeAxis}); spectraGen.add("helium/histGenPtHePrim", "generated particles", HistType::kTH1F, {ptHeAxis}); + if (enableCentrality) + spectraGen.add("helium/histGenPtHePrimVsMult", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); spectraGen.add("helium/histGenPtHeSec", "generated particles", HistType::kTH1F, {ptHeAxis}); spectraGen.add("helium/histSecTransportPtHe", "generated particles", HistType::kTH1F, {ptHeAxis}); spectraGen.add("helium/histGenPtantiHe", "generated particles", HistType::kTH1F, {ptHeAxis}); spectraGen.add("helium/histGenPtantiHePrim", "generated particles", HistType::kTH1F, {ptHeAxis}); + if (enableCentrality) + spectraGen.add("helium/histGenPtantiHePrimVsMult", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); spectraGen.add("helium/histGenPtantiHeSec", "generated particles", HistType::kTH1F, {ptHeAxis}); spectraGen.add("helium/histSecTransportPtantiHe", "generated particles", HistType::kTH1F, {ptHeAxis}); } @@ -1948,24 +2281,46 @@ struct LFNucleiBATask { } LOG(info) << "Histograms of LFNucleiBATask:"; histos.print(); + if (doprocessMCGen) + spectraGen.print(); } template void fillHistograms(const CollisionType& event, const TracksType& tracks, - const ParticleType& /*particles*/) + const ParticleType& particles, + float centFT0M) { + 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 (enableCentrality) + histos.fill(HIST("event/eventSelection"), 0, centFT0M); + else + histos.fill(HIST("event/eventSelection"), 0); if (enableDebug) debugHistos.fill(HIST("qa/h1VtxZ_nocut"), event.posZ()); if constexpr (!IsFilteredData) { if (!event.selection_bit(aod::evsel::kIsTriggerTVX)) { - if (evselOptions.TVXtrigger) + if (evselOptions.useTVXtrigger) return; } else { - histos.fill(HIST("event/eventSelection"), 1); + if (enableCentrality) + histos.fill(HIST("event/eventSelection"), 1, centFT0M); + else + histos.fill(HIST("event/eventSelection"), 1); if (enableDebug) debugHistos.fill(HIST("qa/h1VtxZ_TVXtrigger"), event.posZ()); } @@ -1974,7 +2329,10 @@ struct LFNucleiBATask { if (evselOptions.removeTFBorder) return; } else { - histos.fill(HIST("event/eventSelection"), 2); + if (enableCentrality) + histos.fill(HIST("event/eventSelection"), 2, centFT0M); + else + histos.fill(HIST("event/eventSelection"), 2); if (enableDebug) debugHistos.fill(HIST("qa/h1VtxZ_TFrameBorder"), event.posZ()); } @@ -1983,7 +2341,10 @@ struct LFNucleiBATask { if (evselOptions.removeITSROFBorder) return; } else { - histos.fill(HIST("event/eventSelection"), 3); + if (enableCentrality) + histos.fill(HIST("event/eventSelection"), 3, centFT0M); + else + histos.fill(HIST("event/eventSelection"), 3); if (enableDebug) debugHistos.fill(HIST("qa/h1VtxZ_ITSROFBorder"), event.posZ()); } @@ -1991,93 +2352,138 @@ struct LFNucleiBATask { 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 (enableCentrality) + histos.fill(HIST("event/eventSelection"), 4, centFT0M); + else + histos.fill(HIST("event/eventSelection"), 4); } if (evselOptions.useSel8 && !event.sel8()) return; - histos.fill(HIST("event/eventSelection"), 5); + if (enableCentrality) + histos.fill(HIST("event/eventSelection"), 5, centFT0M); + else + histos.fill(HIST("event/eventSelection"), 5); if (enableDebug) debugHistos.fill(HIST("qa/h1VtxZ_sel8"), event.posZ()); - if (enableCentrality) { - if (event.centFT0M() < cfgLowMultCut || event.centFT0M() > cfgHighMultCut) { - return; - } - if (enableDebug) - debugHistos.fill(HIST("event/h1VtxZ_Centrality"), event.posZ()); - } - - if (event.posZ() < cfgLowCutVertex || event.posZ() > cfgHighCutVertex) + if (event.posZ() < cfgVzCutLow || event.posZ() > cfgVzCutHigh) return; - histos.fill(HIST("event/eventSelection"), 6); + if (enableCentrality) + histos.fill(HIST("event/eventSelection"), 6, centFT0M); + else + histos.fill(HIST("event/eventSelection"), 6); } else { - if (event.posZ() < cfgLowCutVertex || event.posZ() > cfgHighCutVertex) + if (event.posZ() < cfgVzCutLow || event.posZ() > cfgVzCutHigh) return; if (evselOptions.removeTFBorder && !event.selection_bit(aod::evsel::kNoTimeFrameBorder)) return; } + if (centFT0M <= cfgMultCutLow || centFT0M > cfgMultCutHigh) { + return; + } + if (enableCentrality) + histos.fill(HIST("event/eventSelection"), 7, centFT0M); + else + histos.fill(HIST("event/eventSelection"), 7); + + if (enableCentrality && enableDebug) { + debugHistos.fill(HIST("event/h1VtxZ_Centrality"), event.posZ()); + } 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 isTritonTPCpid = 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()); + if (enableCentrality) + histos.fill(HIST("event/h1VtxZ"), event.posZ(), centFT0M); + else + histos.fill(HIST("event/h1VtxZ"), event.posZ()); if (enableDebug && enableCentrality) - debugHistos.fill(HIST("event/hFT0M"), event.centFT0M()); + debugHistos.fill(HIST("event/hFT0M"), centFT0M); if constexpr (IsFilteredData) { if (enableCentrality) 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 const& 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 constexpr (!IsFilteredData) { + if (nsigmaITSvar.showAverageClusterSize && outFlagOptions.enablePIDplot) + histos.fill(HIST("tracks/avgClusterSizePerCoslInvVsITSlayers"), track.p(), averageClusterSizePerCoslInv(track), track.itsNCls()); + } + + if (track.itsNCls() < trkqcOptions.cfgCutITSClusters || + track.tpcNClsCrossedRows() < trkqcOptions.cfgCutTPCXRows || + track.tpcNClsFound() < trkqcOptions.cfgCutTPCClusters || + track.tpcCrossedRowsOverFindableCls() < trkqcOptions.cfgCutTPCCROFnd) { continue; - if (track.tpcNClsCrossedRows() < cfgCutTPCXRows) + } + + auto tpcChi2NclRange = (std::vector)trkqcOptions.tpcChi2NclCuts; + if ((track.tpcChi2NCl() < tpcChi2NclRange[0]) || (track.tpcChi2NCl() > tpcChi2NclRange[1])) continue; - if (track.tpcNClsFound() < cfgCutTPCClusters) + auto itsChi2NclRange = (std::vector)trkqcOptions.itsChi2NclCuts; + if ((track.itsChi2NCl() < itsChi2NclRange[0]) || (track.itsChi2NCl() > itsChi2NclRange[1])) + continue; + + // p & eta cut + if (std::abs(track.tpcInnerParam()) < kinemOptions.cfgMomentumCut || + std::abs(track.eta()) > kinemOptions.cfgEtaCut) continue; + if (outFlagOptions.enablePIDplot) { + histos.fill(HIST("tracks/h1pT"), track.pt()); + histos.fill(HIST("tracks/h1p"), track.p()); + } + isTritonTPCpid = std::abs(track.tpcNSigmaTr()) < nsigmaTPCvar.nsigmaTPCTr; float shiftPtPos = 0.f; float shiftPtNeg = 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; - fShiftPtHe->SetParameters(par[0], par[1], par[2], par[3], par[4]); + if (enablePtShiftHe && !fShiftPtHe) { + fShiftPtHe = new TF1("fShiftPtHe", "[0] * exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); + auto parHe = (std::vector)parShiftPtHe; // NOLINT + fShiftPtHe->SetParameters(parHe[0], parHe[1], parHe[2], parHe[3], parHe[4]); } - if (enablePtShift && !fShiftPtantiHe) { - fShiftPtantiHe = new TF1("fShiftPtantiHe", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); - auto par = (std::vector)parShiftPtantiHe; - fShiftPtantiHe->SetParameters(par[0], par[1], par[2], par[3], par[4]); + if (enablePtShiftHe && !fShiftPtantiHe) { + fShiftPtantiHe = new TF1("fShiftPtantiHe", "[0] * exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); + auto parAntiHe = (std::vector)parShiftPtAntiHe; // NOLINT + fShiftPtantiHe->SetParameters(parAntiHe[0], parAntiHe[1], parAntiHe[2], parAntiHe[3], parAntiHe[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; - fShiftAntiD->SetParameters(par[0], par[1], par[2], par[3], par[4]); + fShiftAntiD = new TF1("fShiftAntiD", "[0] * exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); + auto parAntiD = (std::vector)parShiftPtAntiD; // NOLINT + fShiftAntiD->SetParameters(parAntiD[0], parAntiD[1], parAntiD[2], parAntiD[3], parAntiD[4]); } - switch (antiDeuteronPt) { + switch (unableAntiDPtShift) { case 0: if (enablePtShiftAntiD && fShiftAntiD) { auto shiftAntiD = fShiftAntiD->Eval(track.pt()); @@ -2090,12 +2496,12 @@ struct LFNucleiBATask { } if (enablePtShiftD && !fShiftD) { - fShiftD = new TF1("fShiftD", "[0] * TMath::Exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); - auto par = (std::vector)parShiftPtD; - fShiftD->SetParameters(par[0], par[1], par[2], par[3], par[4]); + fShiftD = new TF1("fShiftD", "[0] * exp([1] + [2] * x) + [3] + [4] * x", 0.f, 8.f); + auto parD = (std::vector)parShiftPtD; // NOLINT + fShiftD->SetParameters(parD[0], parD[1], parD[2], parD[3], parD[4]); } - switch (DeuteronPt) { + switch (unableDPtShift) { case 0: if (enablePtShiftD && fShiftD) { auto shiftD = fShiftD->Eval(track.pt()); @@ -2110,12 +2516,12 @@ struct LFNucleiBATask { switch (helium3Pt) { case 0: hePt = track.pt(); - if (enablePtShift && fShiftPtHe) { + if (enablePtShiftHe && fShiftPtHe) { shiftPtPos = fShiftPtHe->Eval(2 * track.pt()); hePt = track.pt() - shiftPtPos / 2.f; } antihePt = track.pt(); - if (enablePtShift && fShiftPtantiHe) { + if (enablePtShiftHe && fShiftPtantiHe) { shiftPtNeg = fShiftPtantiHe->Eval(2 * track.pt()); antihePt = track.pt() - shiftPtNeg / 2.f; } @@ -2126,166 +2532,176 @@ struct LFNucleiBATask { break; } + float nITSDe = 99.f; + float nITSHe = 99.f; + + if (!IsFilteredData) { + nITSDe = track.itsNSigmaDe(); + nITSHe = track.itsNSigmaHe(); + } heP = track.p(); antiheP = track.p(); heTPCmomentum = track.tpcInnerParam(); antiheTPCmomentum = track.tpcInnerParam(); - auto parDCAxy = (std::vector)parDCAxycuts; - auto parDCAz = (std::vector)parDCAzcuts; - - bool passDCAxyCut = kFALSE; - bool passDCAzCut = kFALSE; - bool passDCAxyCutDe = kFALSE; - bool passDCAzCutDe = kFALSE; - bool passDCAxyCutAntiDe = kFALSE; - bool passDCAzCutAntiDe = kFALSE; - bool passDCAxyCutHe = kFALSE; - bool passDCAzCutHe = kFALSE; - bool passDCAxyCutAntiHe = kFALSE; - bool passDCAzCutAntiHe = kFALSE; - - bool isDeuteron = kFALSE; - bool isHelium = kFALSE; - bool isDe = kFALSE; - bool isAntiDe = kFALSE; - bool isHe = kFALSE; - bool isAntiHe = kFALSE; - - bool isDeWoDCAxy = kFALSE; - bool isAntiDeWoDCAxy = kFALSE; - bool isHeWoDCAxy = kFALSE; - bool isAntiHeWoDCAxy = kFALSE; - - bool isDeWoDCAz = kFALSE; - bool isAntiDeWoDCAz = kFALSE; - bool isHeWoDCAz = kFALSE; - bool isAntiHeWoDCAz = kFALSE; - - bool isDeWoDCAxyWTPCpid = kFALSE; - bool isAntiDeWoDCAxyWTPCpid = kFALSE; - bool isHeWoDCAxyWTPCpid = kFALSE; - bool isAntiHeWoDCAxyWTPCpid = kFALSE; - - bool isDeWoDCAzWTPCpid = kFALSE; - bool isAntiDeWoDCAzWTPCpid = kFALSE; - bool isHeWoDCAzWTPCpid = kFALSE; - bool isAntiHeWoDCAzWTPCpid = kFALSE; - - bool isDeWoTPCpid = kFALSE; - bool isAntiDeWoTPCpid = kFALSE; - bool isHeWoTPCpid = kFALSE; - bool isAntiHeWoTPCpid = kFALSE; - - bool isDeWTPCpid = kFALSE; - bool isAntiDeWTPCpid = kFALSE; - bool isHeWTPCpid = kFALSE; - bool isAntiHeWTPCpid = kFALSE; - - bool passDCAxyzCut = kFALSE; - - switch (dcaConfOptions.DCACustomConfig) { + // auto parDCAxy = (std::vector)parDCAxycuts; + // auto parDCAz = (std::vector)parDCAzcuts; + const auto& parDCAxy = parDCAxycuts.value; + const auto& parDCAz = parDCAzcuts.value; + + 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; + + const float dcaXY2 = track.dcaXY() * track.dcaXY(); + const float dcaZ2 = track.dcaZ() * track.dcaZ(); + + switch (dcaConfOptions.cfgCustomDCA) { 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); + passDCAxyCut = passDCAxyCutDe = passDCAxyCutAntiDe = passDCAxyCutHe = passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= dcaConfOptions.cfgCustomDCAxy); + passDCAzCut = passDCAzCutDe = passDCAzCutAntiDe = passDCAzCutHe = passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= dcaConfOptions.cfgCustomDCAz); break; case 1: - passDCAxyCut = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(track.pt(), parDCAxy[2]))); - passDCAzCut = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(track.pt(), parDCAz[2]))); - - passDCAxyCutDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(DPt, parDCAxy[2]))); - passDCAzCutDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(DPt, parDCAz[2]))); - passDCAxyCutAntiDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(antiDPt, parDCAxy[2]))); - passDCAzCutAntiDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(antiDPt, parDCAz[2]))); - - passDCAxyCutHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(hePt, parDCAxy[2]))); - passDCAzCutHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(hePt, parDCAz[2]))); - passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(antihePt, parDCAxy[2]))); - passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(antihePt, parDCAz[2]))); + 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] / TMath::Power(track.pt(), parDCAxy[2]))); - passDCAzCut = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); - - passDCAxyCutDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(DPt, parDCAxy[2]))); - passDCAzCutDe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); - passDCAxyCutAntiDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(antiDPt, parDCAxy[2]))); - passDCAzCutAntiDe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); - - passDCAxyCutHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(hePt, parDCAxy[2]))); - passDCAzCutHe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); - passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(antihePt, parDCAxy[2]))); - passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= dcaConfOptions.DCAzCustomCut); + passDCAxyCutDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(DPt, parDCAxy[2]))); + passDCAxyCutAntiDe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antiDPt, parDCAxy[2]))); + + passDCAxyCutHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(hePt, parDCAxy[2]))); + passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antihePt, parDCAxy[2]))); + + passDCAxyCut = (std::abs(track.dcaXY()) <= parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(track.pt(), parDCAxy[2]))); + passDCAzCut = passDCAzCutDe = passDCAzCutAntiDe = passDCAzCutHe = passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= dcaConfOptions.cfgCustomDCAz); break; case 3: - passDCAxyCut = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); - passDCAzCut = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(track.pt(), parDCAz[2]))); - - passDCAxyCutDe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); - passDCAzCutDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(DPt, parDCAz[2]))); - passDCAxyCutAntiDe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); - passDCAzCutAntiDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(antiDPt, parDCAz[2]))); - - passDCAxyCutHe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); - passDCAzCutHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(hePt, parDCAz[2]))); - passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= dcaConfOptions.DCAxyCustomCut); - passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(antihePt, parDCAz[2]))); + passDCAxyCut = passDCAxyCutDe = passDCAxyCutAntiDe = passDCAxyCutHe = passDCAxyCutAntiHe = (std::abs(track.dcaXY()) <= dcaConfOptions.cfgCustomDCAxy); + passDCAzCut = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(track.pt(), parDCAz[2]))); + + passDCAzCutDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(DPt, parDCAz[2]))); + passDCAzCutAntiDe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antiDPt, parDCAz[2]))); + + passDCAzCutHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(hePt, parDCAz[2]))); + passDCAzCutAntiHe = (std::abs(track.dcaZ()) <= parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antihePt, parDCAz[2]))); break; case 4: - passDCAxyCut = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - passDCAzCut = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - - passDCAxyCutDe = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - passDCAzCutDe = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - passDCAxyCutAntiDe = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - passDCAzCutAntiDe = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - - passDCAxyCutHe = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - passDCAzCutHe = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - passDCAxyCutAntiHe = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; - passDCAzCutAntiHe = TMath::Power(track.dcaXY(), 2) / TMath::Power(dcaConfOptions.DCAxyCustomCut, 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(dcaConfOptions.DCAzCustomCut, 2) <= 1; + passDCAxyCut = passDCAzCut = passDCAxyCutDe = passDCAzCutDe = passDCAxyCutAntiDe = passDCAzCutAntiDe = passDCAxyCutHe = passDCAzCutHe = passDCAxyCutAntiHe = passDCAzCutAntiHe = dcaXY2 / std::pow(dcaConfOptions.cfgCustomDCAxy, 2) + dcaZ2 / std::pow(dcaConfOptions.cfgCustomDCAz, 2) <= 1; break; case 5: - passDCAxyCut = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(track.pt(), parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(track.pt(), parDCAz[2])), 2) <= 1; - passDCAzCut = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(track.pt(), parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(track.pt(), parDCAz[2])), 2) <= 1; - - passDCAxyCutDe = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(DPt, parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(DPt, parDCAz[2])), 2) <= 1; - passDCAzCutDe = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(DPt, parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(DPt, parDCAz[2])), 2) <= 1; - passDCAxyCutAntiDe = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(antiDPt, parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(antiDPt, parDCAz[2])), 2) <= 1; - passDCAzCutAntiDe = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(antiDPt, parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(antiDPt, parDCAz[2])), 2) <= 1; - - passDCAxyCutHe = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(hePt, parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(hePt, parDCAz[2])), 2) <= 1; - passDCAzCutHe = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(hePt, parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(hePt, parDCAz[2])), 2) <= 1; - passDCAxyCutAntiHe = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(antihePt, parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(antihePt, parDCAz[2])), 2) <= 1; - passDCAzCutAntiHe = TMath::Power(track.dcaXY(), 2) / TMath::Power(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / TMath::Power(antihePt, parDCAxy[2])), 2) + TMath::Power(track.dcaZ(), 2) / TMath::Power(parDCAz[3] * (parDCAz[0] + parDCAz[1] / TMath::Power(antihePt, parDCAz[2])), 2) <= 1; + passDCAxyCut = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(track.pt(), parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(track.pt(), parDCAz[2])), 2) <= 1; + passDCAzCut = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(track.pt(), parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(track.pt(), parDCAz[2])), 2) <= 1; + + passDCAxyCutDe = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(DPt, parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(DPt, parDCAz[2])), 2) <= 1; + passDCAzCutDe = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(DPt, parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(DPt, parDCAz[2])), 2) <= 1; + passDCAxyCutAntiDe = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antiDPt, parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antiDPt, parDCAz[2])), 2) <= 1; + passDCAzCutAntiDe = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antiDPt, parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antiDPt, parDCAz[2])), 2) <= 1; + + passDCAxyCutHe = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(hePt, parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(hePt, parDCAz[2])), 2) <= 1; + passDCAzCutHe = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(hePt, parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(hePt, parDCAz[2])), 2) <= 1; + passDCAxyCutAntiHe = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antihePt, parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antihePt, parDCAz[2])), 2) <= 1; + passDCAzCutAntiHe = dcaXY2 / std::pow(parDCAxy[3] * (parDCAxy[0] + parDCAxy[1] / std::pow(antihePt, parDCAxy[2])), 2) + dcaZ2 / std::pow(parDCAz[3] * (parDCAz[0] + parDCAz[1] / std::pow(antihePt, parDCAz[2])), 2) <= 1; break; } - // p cut - if (TMath::Abs(track.tpcInnerParam()) < kinemOptions.pCut) - continue; - // 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; + auto rapCheck = [&](float m2z) { + const float rap = track.rapidity(m2z); + return (rap > kinemOptions.cfgRapidityCutLow) && (rap < kinemOptions.cfgRapidityCutHigh); + }; + + prRapCut = rapCheck(MassProtonVal); + deRapCut = rapCheck(MassDeuteronVal); + trRapCut = rapCheck(MassTritonVal); + heRapCut = rapCheck(MassHeliumVal / 2.0); + alRapCut = rapCheck(MassAlphaVal / 2.0); isDeuteron = enableDe && deRapCut; isHelium = enableHe && heRapCut; isDe = isDeuteron && track.sign() > 0; isAntiDe = isDeuteron && track.sign() < 0; + + if constexpr (IsMC && !IsFilteredData) { + int pdgCheck = track.mcParticle().pdgCode(); + if (std::abs(pdgCheck) == PDGDeuteron) + histos.fill(HIST("tracks/hItsDeHeChecker"), 0); + if (std::abs(pdgCheck) == PDGHelium) + histos.fill(HIST("tracks/hItsDeHeChecker"), 1); + } + + // nSigmaITSHe cut + if (nsigmaITSvar.useITSDeCut && (nITSDe <= nsigmaITSvar.nsigmaITSDe)) { + continue; + } + + if (nsigmaITSvar.useITSHeCut && (nITSHe <= nsigmaITSvar.nsigmaITSHe)) { + continue; + } + + if constexpr (IsMC && !IsFilteredData) { + int pdgCheck = track.mcParticle().pdgCode(); + if (std::abs(pdgCheck) == PDGDeuteron) + histos.fill(HIST("tracks/hItsDeHeChecker"), 2); + if (std::abs(pdgCheck) == PDGHelium) + histos.fill(HIST("tracks/hItsDeHeChecker"), 3); + } + isHe = isHelium && track.sign() > 0; isAntiHe = isHelium && track.sign() < 0; @@ -2327,66 +2743,58 @@ struct LFNucleiBATask { 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); + histos.fill(HIST("tracks/helium/dca/before/h3DCAvsPtHelium"), 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 (isAntiHe && std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { - histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsDCAzVsPtantiHelium"), track.dcaXY(), track.dcaZ(), antihePt); + histos.fill(HIST("tracks/helium/dca/before/h3DCAvsPtantiHelium"), 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 (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 (enablePr && prRapCut && (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 (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()); - } + if (enableTr && trRapCut && 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()); } } - 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 (enableAl && alRapCut && (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 (isDeWoDCAzWTPCpid) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAzVsPtDeuteron"), DPt, track.dcaZ()); - if (!track.hasTOF()) + if (!track.hasTOF() && (outFlagOptions.enableNoTOFPlots)) 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()) + if (!track.hasTOF() && (outFlagOptions.enableNoTOFPlots)) 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()) + if (!track.hasTOF() && (outFlagOptions.enableNoTOFPlots)) 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()); @@ -2395,7 +2803,7 @@ struct LFNucleiBATask { if (isAntiHeWoDCAzWTPCpid) { histos.fill(HIST("tracks/helium/dca/before/hDCAzVsPtantiHelium"), antihePt, track.dcaZ()); - if (!track.hasTOF()) + if (!track.hasTOF() && (outFlagOptions.enableNoTOFPlots)) 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()); @@ -2413,7 +2821,7 @@ struct LFNucleiBATask { if constexpr (IsFilteredData) { isPhysPrim = track.isPhysicalPrimary(); isProdByGen = track.producedByGenerator(); - isWeakDecay = track.getProcess() == 4; + isWeakDecay = (track.getProcess() == TMCProcess::kPDecay); pdgCode = track.pdgCode(); } else { if (!track.has_mcParticle()) { @@ -2421,7 +2829,7 @@ struct LFNucleiBATask { } isPhysPrim = track.mcParticle().isPhysicalPrimary(); isProdByGen = track.mcParticle().producedByGenerator(); - isWeakDecay = track.mcParticle().getProcess() == 4; + isWeakDecay = (track.mcParticle().getProcess() == TMCProcess::kPDecay); pdgCode = track.mcParticle().pdgCode(); } @@ -2440,14 +2848,16 @@ struct LFNucleiBATask { } } 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()); } } } @@ -2466,14 +2876,16 @@ struct LFNucleiBATask { } } 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()); } } } @@ -2492,14 +2904,16 @@ struct LFNucleiBATask { } } 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()); } } } @@ -2518,14 +2932,16 @@ struct LFNucleiBATask { } } 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()); } } } @@ -2538,9 +2954,10 @@ struct LFNucleiBATask { 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()); } } } @@ -2552,9 +2969,10 @@ struct LFNucleiBATask { 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()); } } } @@ -2572,21 +2990,23 @@ struct LFNucleiBATask { } } 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) { + 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()); @@ -2626,21 +3046,23 @@ struct LFNucleiBATask { } } 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) { + 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()); @@ -2666,7 +3088,6 @@ struct LFNucleiBATask { } } } - break; case PDGAlpha: if (enableAl && alRapCut && passDCAxyCut) { @@ -2675,9 +3096,10 @@ struct LFNucleiBATask { 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()); } } } @@ -2689,9 +3111,10 @@ struct LFNucleiBATask { 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()); } } } @@ -2704,7 +3127,7 @@ struct LFNucleiBATask { // break; default: - if (isDeWoDCAzWTPCpid) { + 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()); @@ -2727,7 +3150,7 @@ struct LFNucleiBATask { } } } - } else if (isAntiDeWoDCAzWTPCpid) { + } 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()); @@ -2759,7 +3182,7 @@ struct LFNucleiBATask { // break; default: - if (isHeWoDCAzWTPCpid) { + 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()); @@ -2783,7 +3206,7 @@ struct LFNucleiBATask { } } } - if (isAntiHeWoDCAzWTPCpid) { + 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()); @@ -2810,11 +3233,12 @@ struct LFNucleiBATask { break; } } + } else { + (void)particles; } // 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) { @@ -2848,29 +3272,29 @@ struct LFNucleiBATask { } if (isDeWoDCAxyWTPCpid) { - if (usenITSLayer && !itsClusterMap.test(nITSLayer)) + if (usenITSLayer && !itsClusterMap.test(trkqcOptions.nITSLayer)) continue; if (enableCentrality) - histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronVsMult"), DPt, track.dcaXY(), event.centFT0M()); + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronVsMult"), DPt, track.dcaXY(), centFT0M); else histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteron"), DPt, track.dcaXY()); - if (!track.hasTOF()) + if (!track.hasTOF() && (outFlagOptions.enableNoTOFPlots)) histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronNoTOF"), DPt, track.dcaXY()); } if (isAntiDeWoDCAxyWTPCpid) { - if (usenITSLayer && !itsClusterMap.test(nITSLayer)) + if (usenITSLayer && !itsClusterMap.test(trkqcOptions.nITSLayer)) continue; if (enableCentrality) - histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronVsMult"), antiDPt, track.dcaXY(), event.centFT0M()); + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronVsMult"), antiDPt, track.dcaXY(), centFT0M); else histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteron"), antiDPt, track.dcaXY()); - if (!track.hasTOF()) + if (!track.hasTOF() && (outFlagOptions.enableNoTOFPlots)) 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()) + if (!track.hasTOF() && (outFlagOptions.enableNoTOFPlots)) 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()); @@ -2878,7 +3302,7 @@ struct LFNucleiBATask { } if (isAntiHeWoDCAxyWTPCpid) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHelium"), antihePt, track.dcaXY()); - if (!track.hasTOF()) + if (!track.hasTOF() && (outFlagOptions.enableNoTOFPlots)) 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()); @@ -2887,6 +3311,7 @@ struct LFNucleiBATask { } if constexpr (IsMC) { + // auto const& mcParticles = particles; bool isPhysPrim = false; bool isProdByGen = false; bool isWeakDecay = false; @@ -2894,14 +3319,24 @@ struct LFNucleiBATask { // PID int pdgCode = 0; + int pdgMom = 0; // gen Pt float genPt = 0; + float ptMom = 0; + // Mothers variables + [[maybe_unused]] int firstMotherId = -1; + [[maybe_unused]] int firstMotherPdg = -1; + [[maybe_unused]] float firstMotherPt = -1.f; + [[maybe_unused]] int pdgMomList[kMaxNumMom]; + [[maybe_unused]] float ptMomList[kMaxNumMom]; + [[maybe_unused]] int nSaved = 0; + if constexpr (IsFilteredData) { isPhysPrim = track.isPhysicalPrimary(); isProdByGen = track.producedByGenerator(); - isWeakDecay = track.getProcess() == 4; + isWeakDecay = (track.getProcess() == TMCProcess::kPDecay); pdgCode = track.pdgCode(); - genPt = TMath::Sqrt(TMath::Power(track.px(), 2) + TMath::Power(track.py(), 2)); + genPt = std::sqrt(track.px() * track.px() + track.py() * track.py()); } else { if (!track.has_mcParticle()) { @@ -2909,11 +3344,41 @@ struct LFNucleiBATask { } isPhysPrim = track.mcParticle().isPhysicalPrimary(); isProdByGen = track.mcParticle().producedByGenerator(); - isWeakDecay = track.mcParticle().getProcess() == 4; + isWeakDecay = (track.mcParticle().getProcess() == TMCProcess::kPDecay); pdgCode = track.mcParticle().pdgCode(); - genPt = track.mcParticle().pt(); - for (int i = 0; i < 10; i++) { // From ITS to TPC + // Access to MC particles mother + o2::aod::McParticles::iterator mc = particles.iteratorAt(track.mcParticleId()); + gsl::span motherIds = mc.mothersIds(); + const int nMothers = static_cast(motherIds.size()); + firstMotherId = -1; + firstMotherPdg = -1; + firstMotherPt = -1.f; + nSaved = 0; + + for (int iMom = 0; iMom < nMothers; iMom++) { + int motherId = motherIds[iMom]; + if (motherId < 0 || motherId >= particles.size()) { + continue; // added check on mother + } + o2::aod::McParticles::iterator mother = particles.iteratorAt(motherId); + pdgMom = mother.pdgCode(); + ptMom = mother.pt(); + + if (iMom == 0) { + firstMotherId = motherId; + firstMotherPdg = pdgMom; + firstMotherPt = ptMom; + } + if (nSaved < kMaxNumMom) { + pdgMomList[nSaved] = pdgMom; + ptMomList[nSaved] = ptMom; + nSaved++; + } + } + + genPt = track.mcParticle().pt(); + for (int i = 0; i < kFakeLoop; i++) { // From ITS to TPC if (track.mcMask() & 1 << i) { hasFakeHit = true; break; @@ -2937,14 +3402,37 @@ struct LFNucleiBATask { } } 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 constexpr (!IsFilteredData) { + histos.fill(HIST("tracks/proton/dca/before/hNumMothers"), nSaved); + if (nSaved > 0) { + for (int iMom = 0; iMom < nSaved; iMom++) { + int pdgMom = pdgMomList[iMom]; + float pdgSign = (pdgMom > 0) ? 1.0 : -1.0; + float ptMom = ptMomList[iMom]; + int motherSpeciesBin = -1; + if (pdgMom != -1) { + motherSpeciesBin = 0; + for (int j = 0; j < kNumMotherList; j++) { + if (std::abs(kPdgMotherList[j]) == std::abs(pdgMom)) { + motherSpeciesBin = j + 1; + break; + } + } + } + histos.fill(HIST("tracks/proton/dca/before/hMomTrueMaterial"), pdgSign, motherSpeciesBin, ptMom); + } + } + } } 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()); } } } @@ -2963,14 +3451,16 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen) { - histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrueTransport"), track.pt(), track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/proton/dca/before/hDCAxyVsPtantiProtonTrueSec"), track.pt(), track.dcaXY()); + } 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()); } } } @@ -3009,16 +3499,37 @@ struct LFNucleiBATask { } if (!isPhysPrim && !isProdByGen) { if (outFlagOptions.makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueTransport"), DPt, track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueSec"), DPt, track.dcaXY()); } else { - // LOG(info) << " PID: "<< pdgCode << " Prod. by Gen: "<< isProdByGen << " Process: " << track.mcParticle().getProcess() << " HasMothers: " << track.mcParticle().has_mothers() << " and MomIs: "<< mother.pdgCode(); + histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtDeuteronTrueMaterial"), DPt, track.dcaXY()); + if constexpr (!IsFilteredData) { + histos.fill(HIST("tracks/deuteron/dca/before/hNumMothers"), nSaved); + if (nSaved > 0) { + for (int iMom = 0; iMom < nSaved; iMom++) { + int pdgMom = pdgMomList[iMom]; + float pdgSign = (pdgMom > 0) ? 1.0 : -1.0; + float ptMom = ptMomList[iMom]; + int motherSpeciesBin = -1; + if (pdgMom != -1) { + motherSpeciesBin = 0; + for (int j = 0; j < kNumMotherList; j++) { + if (std::abs(kPdgMotherList[j]) == std::abs(pdgMom)) { + motherSpeciesBin = j + 1; + break; + } + } + } + histos.fill(HIST("tracks/deuteron/dca/before/hMomTrueMaterial"), pdgSign, motherSpeciesBin, ptMom); + } + } + } } 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()); } } } @@ -3058,14 +3569,16 @@ struct LFNucleiBATask { } if (!isPhysPrim && !isProdByGen) { if (outFlagOptions.makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrueTransport"), antiDPt, track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/deuteron/dca/before/hDCAxyVsPtantiDeuteronTrueSec"), antiDPt, track.dcaXY()); + } 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()); } } } @@ -3085,15 +3598,16 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen) { - histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtTritonTrueTransport"), track.pt(), track.dcaXY()); - 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()); 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()); + } } } } @@ -3115,15 +3629,16 @@ struct LFNucleiBATask { // } if (!isPhysPrim && !isProdByGen) { - histos.fill(HIST("tracks/triton/dca/before/hDCAxyVsPtantiTritonTrueTransport"), track.pt(), track.dcaXY()); - 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()); 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()); + } } } } @@ -3156,21 +3671,44 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen && outFlagOptions.makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); + } else { + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtHeliumTrueMaterial"), hePt, track.dcaXY()); + if (!IsFilteredData) { + histos.fill(HIST("tracks/helium/dca/before/hNumMothers"), nSaved); + if (nSaved > 0) { + for (int iMom = 0; iMom < nSaved; iMom++) { + int pdgMom = pdgMomList[iMom]; + float pdgSign = (pdgMom > 0) ? 1.0 : -1.0; + float ptMom = ptMomList[iMom]; + int motherSpeciesBin = -1; + if (pdgMom != -1) { + motherSpeciesBin = 0; + for (int j = 0; j < kNumMotherList; j++) { + if (std::abs(kPdgMotherList[j]) == std::abs(pdgMom)) { + motherSpeciesBin = j + 1; + break; + } + } + } + histos.fill(HIST("tracks/helium/dca/before/hMomTrueMaterial"), pdgSign, motherSpeciesBin, ptMom); + } + } + } } if (track.hasTOF() && outFlagOptions.doTOFplots) { - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueTransport"), hePt, track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtHeliumTrueSec"), hePt, track.dcaXY()); + } 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) { + 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()); @@ -3225,22 +3763,23 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen && outFlagOptions.makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); + } else { + histos.fill(HIST("tracks/helium/dca/before/hDCAxyVsPtantiHeliumTrueMaterial"), antihePt, track.dcaXY()); } - if (track.hasTOF() && outFlagOptions.doTOFplots) { - histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueTransport"), antihePt, track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/helium/dca/before/TOF/hDCAxyVsPtantiHeliumTrueSec"), antihePt, track.dcaXY()); + } 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) { + 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()); @@ -3274,9 +3813,10 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTruePrim"), track.pt(), track.dcaXY()); } if (!isPhysPrim && !isProdByGen) { - histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueTransport"), track.pt(), track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueSec"), track.pt(), track.dcaXY()); + } else { + histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtAlphaTrueMaterial"), track.pt(), track.dcaXY()); } } } @@ -3288,9 +3828,10 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTruePrim"), track.pt(), track.dcaXY()); } if (!isPhysPrim && !isProdByGen) { - histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueTransport"), track.pt(), track.dcaXY()); if (isWeakDecay) { histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueSec"), track.pt(), track.dcaXY()); + } else { + histos.fill(HIST("tracks/alpha/dca/before/hDCAxyVsPtantiAlphaTrueMaterial"), track.pt(), track.dcaXY()); } } } @@ -3303,7 +3844,7 @@ struct LFNucleiBATask { // break; default: - if (isDeWoDCAxyWTPCpid) { + if (isDeWoDCAxyWTPCpid && outFlagOptions.makeFakeTracksPlots) { if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrue"), DPt, track.dcaXY()); if (track.hasTOF() && outFlagOptions.doTOFplots) { @@ -3320,19 +3861,22 @@ struct LFNucleiBATask { } if (!isPhysPrim && !isProdByGen) { if (outFlagOptions.makeDCABeforeCutPlots) { - histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtDeuteronTrueTransport"), DPt, track.dcaXY()); - if (isWeakDecay) + 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) { + if (isAntiDeWoDCAxyWTPCpid && outFlagOptions.makeFakeTracksPlots) { if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/deuteron/dca/before/fake/hDCAxyVsPtantiDeuteronTrue"), antiDPt, track.dcaXY()); if (track.hasTOF() && outFlagOptions.doTOFplots) { @@ -3349,14 +3893,16 @@ struct LFNucleiBATask { } 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()); } } } @@ -3370,7 +3916,7 @@ struct LFNucleiBATask { // break; default: - if (isHeWoDCAxyWTPCpid) { + if (isHeWoDCAxyWTPCpid && outFlagOptions.makeFakeTracksPlots) { if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); if (track.hasTOF() && outFlagOptions.doTOFplots) { @@ -3383,20 +3929,22 @@ struct LFNucleiBATask { } } 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) { + if (isAntiHeWoDCAxyWTPCpid && outFlagOptions.makeFakeTracksPlots) { if (outFlagOptions.makeDCABeforeCutPlots) { histos.fill(HIST("tracks/helium/dca/before/fake/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); if (track.hasTOF() && outFlagOptions.doTOFplots) { @@ -3409,14 +3957,16 @@ struct LFNucleiBATask { } } 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()); } } } @@ -3424,16 +3974,20 @@ struct LFNucleiBATask { } break; } + } else { + (void)particles; } // DCA Cut if constexpr (!IsFilteredData) { - if (!enableDCACustomCut) { - if (!track.isGlobalTrack()) - continue; - } else { - if (!track.isGlobalTrackWoDCA()) - continue; + if (filterOptions.enableIsGlobalTrack) { + if (!enableCustomDCACut) { + if (!track.isGlobalTrack()) + continue; + } else { + if (!track.isGlobalTrackWoDCA()) + continue; + } } } @@ -3442,15 +3996,16 @@ struct LFNucleiBATask { } if (outFlagOptions.makeDCAAfterCutPlots) { - if (isHeWTPCpid) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsDCAzVsPtHelium"), track.dcaXY(), track.dcaZ(), hePt); + histos.fill(HIST("tracks/helium/dca/after/h3DCAvsPtHelium"), 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 (isAntiHeWTPCpid) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsDCAzVsPtantiHelium"), track.dcaXY(), track.dcaZ(), antihePt); + histos.fill(HIST("tracks/helium/dca/after/h3DCAvsPtantiHelium"), track.dcaXY(), track.dcaZ(), antihePt); if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/dca/after/TOF/hDCAxyVsDCAzVsPtantiHelium"), track.dcaXY(), track.dcaZ(), antihePt); } @@ -3462,48 +4017,42 @@ struct LFNucleiBATask { 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()); - } + if (enablePr && prRapCut && (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()); } } - 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 (enableTr && trRapCut && 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 && (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 (isDeWTPCpid) { - if (usenITSLayer && !itsClusterMap.test(nITSLayer)) + 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(nITSLayer)) + 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()); @@ -3527,17 +4076,14 @@ struct LFNucleiBATask { } if (passDCAxyzCut) { - // 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 (track.tpcInnerParam() < 0.5f) { + if (track.tpcInnerParam() < kCfgTpcClasses[0]) { debugHistos.fill(HIST("debug/qa/h1TPCncrLowPPos"), track.tpcNClsCrossedRows()); } - if ((track.tpcInnerParam() >= 0.5f) && (track.tpcInnerParam() < 1.f)) { + if ((track.tpcInnerParam() >= kCfgTpcClasses[0]) && (track.tpcInnerParam() < kCfgTpcClasses[1])) { debugHistos.fill(HIST("debug/qa/h1TPCncrMidPPos"), track.tpcNClsCrossedRows()); } - if (track.tpcInnerParam() >= 1.f) { + if (track.tpcInnerParam() >= kCfgTpcClasses[1]) { 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()); - if (track.tpcInnerParam() < 0.5f) { + if (track.tpcInnerParam() < kCfgTpcClasses[0]) { debugHistos.fill(HIST("debug/qa/h1TPCncrLowPNeg"), track.tpcNClsCrossedRows()); } - if ((track.tpcInnerParam() >= 0.5f) && (track.tpcInnerParam() < 1.f)) { + if ((track.tpcInnerParam() >= kCfgTpcClasses[0]) && (track.tpcInnerParam() < kCfgTpcClasses[1])) { debugHistos.fill(HIST("debug/qa/h1TPCncrMidPNeg"), track.tpcNClsCrossedRows()); } - if (track.tpcInnerParam() >= 1.f) { + if (track.tpcInnerParam() >= kCfgTpcClasses[1]) { debugHistos.fill(HIST("debug/qa/h1TPCncrHighPNeg"), track.tpcNClsCrossedRows()); } } @@ -3578,15 +4125,23 @@ struct LFNucleiBATask { debugHistos.fill(HIST("debug/tracks/kaon/h2KaonVspTNSigmaTPC"), track.pt(), track.tpcNSigmaKa()); } - if (enablePtSpectra) + if (outFlagOptions.enableEffPlots) histos.fill(HIST("tracks/eff/h2pVsTPCmomentum"), track.tpcInnerParam(), track.p()); - if (enableFiltering) { - if (track.tpcNSigmaKa() < 5) + if (filterOptions.enableFiltering) { + if (track.tpcNSigmaKa() < kCfgKaonCut) continue; } - histos.fill(HIST("tracks/h2TPCsignVsTPCmomentum"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); + if (outFlagOptions.enablePIDplot) + histos.fill(HIST("tracks/h2TPCsignVsTPCmomentum"), track.tpcInnerParam() / (1.f * track.sign()), track.tpcSignal()); + + if constexpr (!IsFilteredData) { + if (nsigmaITSvar.showAverageClusterSize && outFlagOptions.enablePIDplot) { + histos.fill(HIST("tracks/averageClusterSize"), track.p(), averageClusterSizeTrk(track)); + histos.fill(HIST("tracks/averageClusterSizePerCoslInv"), track.p(), averageClusterSizePerCoslInv(track)); + } + } if (track.sign() > 0) { if (enablePr && prRapCut) { @@ -3671,7 +4226,7 @@ struct LFNucleiBATask { histos.fill(HIST("tracks/proton/h2ProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); } - if (enableEvTimeSplitting && track.hasTOF()) { + if (filterOptions.enableEvTimeSplitting && track.hasTOF()) { if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { if (enablePr) evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); @@ -3687,7 +4242,7 @@ struct LFNucleiBATask { 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(), DPt); - if (enableDebug && (track.beta() > betaCut)) { + if (enableDebug && (track.beta() > cfgBetaCut)) { if (enablePr) debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); if (enableDe) @@ -3703,7 +4258,6 @@ struct LFNucleiBATask { debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); } } - } else if (track.isEvTimeT0AC()) { if (enablePr) evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); @@ -3719,7 +4273,7 @@ struct LFNucleiBATask { 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 (enableDebug && (track.beta() > cfgBetaCut)) { if (enablePr) debugHistos.fill(HIST("debug/evtime/ft0/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); if (enableDe) @@ -3735,7 +4289,6 @@ struct LFNucleiBATask { debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); } } - } else if (track.isEvTimeTOF()) { if (enablePr) evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); @@ -3751,7 +4304,7 @@ struct LFNucleiBATask { 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)) { + if (enableDebug && (track.beta() > cfgBetaCut)) { if (enablePr) debugHistos.fill(HIST("debug/evtime/tof/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); if (enableDe) @@ -3769,7 +4322,6 @@ struct LFNucleiBATask { debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2DeuteronTOFExpSignalDiffVsPt_BetaCut"), DPt, track.tofExpSignalDiffDe()); } } - } else { if (enablePr) evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2ProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); @@ -3785,7 +4337,7 @@ struct LFNucleiBATask { 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)) { + if (enableDebug && (track.beta() > cfgBetaCut)) { if (enablePr) debugHistos.fill(HIST("debug/evtime/fill/proton/h2ProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); if (enableDe) @@ -3825,7 +4377,7 @@ struct LFNucleiBATask { if (outFlagOptions.enableExpSignalTOF) histos.fill(HIST("tracks/proton/h2antiProtonTOFExpSignalDiffVsPt"), track.pt(), track.tofExpSignalDiffPr()); } - if (enableEvTimeSplitting && track.hasTOF()) { + if (filterOptions.enableEvTimeSplitting && track.hasTOF()) { if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { if (enablePr) evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); @@ -3841,7 +4393,7 @@ struct LFNucleiBATask { 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 (enableDebug && (track.beta() > cfgBetaCut)) { if (enablePr) debugHistos.fill(HIST("debug/evtime/ft0tof/proton/h2antiProtonVspTNSigmaTPC_BetaCut"), track.pt(), track.tpcNSigmaPr()); if (enableDe) @@ -3858,7 +4410,6 @@ struct LFNucleiBATask { debugHistos.fill(HIST("debug/evtime/ft0tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); } } - } else if (track.isEvTimeT0AC()) { if (enablePr) evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); @@ -3887,7 +4438,6 @@ struct LFNucleiBATask { debugHistos.fill(HIST("debug/evtime/ft0/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); } } - } else if (track.isEvTimeTOF()) { if (enablePr) evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); @@ -3917,7 +4467,6 @@ struct LFNucleiBATask { debugHistos.fill(HIST("debug/evtime/tof/deuteron/h2antiDeuteronTOFExpSignalDiffVsPt_BetaCut"), antiDPt, track.tofExpSignalDiffDe()); } } - } else { if (enablePr) evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2antiProtonVspTNSigmaTOF"), track.pt(), track.tofNSigmaPr()); @@ -3957,10 +4506,12 @@ struct LFNucleiBATask { if (outFlagOptions.enableExpSignalTPC) histos.fill(HIST("tracks/deuteron/h2DeuteronTPCExpSignalDiffVsPt"), DPt, track.tpcExpSignalDiffDe()); + histos.fill(HIST("tracks/deuteron/h2DeuteronVspNSigmaITSDe"), track.p(), nITSDe); + switch (useHasTRDConfig) { case 0: if (enableCentrality) - histos.fill(HIST("tracks/deuteron/h3DeuteronVspTNSigmaTPCVsMult"), DPt, track.tpcNSigmaDe(), event.centFT0M()); + histos.fill(HIST("tracks/deuteron/h3DeuteronVspTNSigmaTPCVsMult"), DPt, track.tpcNSigmaDe(), centFT0M); else histos.fill(HIST("tracks/deuteron/h2DeuteronVspTNSigmaTPC"), DPt, track.tpcNSigmaDe()); break; @@ -3980,10 +4531,12 @@ struct LFNucleiBATask { if (outFlagOptions.enableExpSignalTPC) histos.fill(HIST("tracks/deuteron/h2antiDeuteronTPCExpSignalDiffVsPt"), antiDPt, track.tpcExpSignalDiffDe()); + histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspNSigmaITSDe"), track.p(), nITSDe); + switch (useHasTRDConfig) { case 0: if (enableCentrality) - histos.fill(HIST("tracks/deuteron/h3antiDeuteronVspTNSigmaTPCVsMult"), antiDPt, track.tpcNSigmaDe(), event.centFT0M()); + histos.fill(HIST("tracks/deuteron/h3antiDeuteronVspTNSigmaTPCVsMult"), antiDPt, track.tpcNSigmaDe(), centFT0M); else histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspTNSigmaTPC"), antiDPt, track.tpcNSigmaDe()); break; @@ -4003,12 +4556,32 @@ struct LFNucleiBATask { if (isHeWoTPCpid) { if (outFlagOptions.enableExpSignalTPC) histos.fill(HIST("tracks/helium/h2HeliumTPCExpSignalDiffVsPt"), hePt, track.tpcExpSignalDiffHe()); + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSHe"), track.p(), nITSHe); histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaTPC"), hePt, track.tpcNSigmaHe()); + if (enableCentrality) + histos.fill(HIST("tracks/helium/h3HeliumVspTNSigmaTPCVsMult"), hePt, track.tpcNSigmaHe(), centFT0M); } if (isAntiHeWoTPCpid) { if (outFlagOptions.enableExpSignalTPC) histos.fill(HIST("tracks/helium/h2antiHeliumTPCExpSignalDiffVsPt"), antihePt, track.tpcExpSignalDiffHe()); + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSHe"), track.p(), nITSHe); histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaTPC"), antihePt, track.tpcNSigmaHe()); + if (enableCentrality) + histos.fill(HIST("tracks/helium/h3antiHeliumVspTNSigmaTPCVsMult"), antihePt, track.tpcNSigmaHe(), centFT0M); + } + if (isHeWTPCpid) { + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSHe_wTPCpid"), track.p(), nITSHe); + } + if (isAntiHeWTPCpid) { + 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)); + } + } } // TOF @@ -4069,41 +4642,36 @@ struct LFNucleiBATask { if (passDCAxyzCut) { // PID - if (enablePtSpectra && enableDebug) { - if (track.sign() > 0) { + if (outFlagOptions.enableEffPlots && enableDebug) { + if (track.sign() > 0) debugHistos.fill(HIST("tracks/eff/hPtP"), track.pt()); - debugHistos.fill(HIST("tracks/eff/hPtPrebinned"), track.pt()); - } else { + else debugHistos.fill(HIST("tracks/eff/hPtantiP"), track.pt()); - debugHistos.fill(HIST("tracks/eff/hPtantiPrebinned"), track.pt()); - } } if (enablePr) { if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr && prRapCut) { if (track.sign() > 0) { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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()); - if (enablePIDplot) + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/proton/h2TPCsignVsTPCmomentumProton"), track.tpcInnerParam(), track.tpcSignal()); } else { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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) + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/proton/h2TPCsignVsTPCmomentumantiProton"), track.tpcInnerParam(), track.tpcSignal()); } } @@ -4111,20 +4679,20 @@ struct LFNucleiBATask { if (enableTr) { if ((isTritonTPCpid) && trRapCut) { if (track.sign() > 0) { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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) + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/triton/h2TPCsignVsTPCmomentumTriton"), track.tpcInnerParam(), track.tpcSignal()); } else { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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) + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/triton/h2TPCsignVsTPCmomentumantiTriton"), track.tpcInnerParam(), track.tpcSignal()); } } @@ -4133,59 +4701,58 @@ struct LFNucleiBATask { if ((std::abs(track.tpcNSigmaAl()) < nsigmaTPCvar.nsigmaTPCAl) && alRapCut) { if (track.sign() > 0) { histos.fill(HIST("tracks/alpha/h1AlphaSpectra"), track.pt()); - if (enablePIDplot) + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/alpha/h2TPCsignVsTPCmomentumAlpha"), track.tpcInnerParam(), track.tpcSignal()); } else { histos.fill(HIST("tracks/alpha/h1antiAlphaSpectra"), track.pt()); - if (enablePIDplot) + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/alpha/h2TPCsignVsTPCmomentumantiAlpha"), track.tpcInnerParam(), track.tpcSignal()); } } } if (outFlagOptions.doTOFplots && track.hasTOF()) { - if (enablePtSpectra && enableDebug) { - if (track.sign() > 0) { + if (outFlagOptions.enableEffPlots && enableDebug) { + if (track.sign() > 0) debugHistos.fill(HIST("tracks/eff/hPtPTOF"), track.pt()); - debugHistos.fill(HIST("tracks/eff/hPtPTOFrebinned"), track.pt()); - } else { + else debugHistos.fill(HIST("tracks/eff/hPtantiPTOF"), track.pt()); - debugHistos.fill(HIST("tracks/eff/hPtantiPTOFrebinned"), track.pt()); - } } - if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut) && outFlagOptions.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 (outFlagOptions.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) + if (outFlagOptions.enableEffPlots) histos.fill(HIST("tracks/eff/h2TPCmomentumVsTOFExpMomentum"), track.tofExpMom(), track.tpcInnerParam()); if (enablePr && prRapCut) { if (std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr && track.sign() > 0) { histos.fill(HIST("tracks/proton/h2ProtonTOFbetaVsP"), track.p(), track.beta()); - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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()) < nsigmaTPCvar.nsigmaTPCPr && track.sign() < 0) { histos.fill(HIST("tracks/proton/h2antiProtonTOFbetaVsP"), track.p(), track.beta()); - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { histos.fill(HIST("tracks/eff/proton/h2pVsTOFExpMomentumantiPr"), track.tofExpMom(), track.p()); histos.fill(HIST("tracks/eff/proton/h2TPCmomentumVsTOFExpMomentumantiPr"), track.tofExpMom(), track.tpcInnerParam()); } @@ -4194,20 +4761,20 @@ struct LFNucleiBATask { if (enableTr && trRapCut) { if (isTritonTPCpid && track.sign() > 0) { histos.fill(HIST("tracks/triton/h2TritonTOFbetaVsP"), track.p(), track.beta()); - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { histos.fill(HIST("tracks/eff/triton/h2pVsTOFExpMomentumTr"), track.tofExpMom(), track.p()); histos.fill(HIST("tracks/eff/triton/h2TPCmomentumVsTOFExpMomentumTr"), track.tofExpMom(), track.tpcInnerParam()); } } if (isTritonTPCpid && track.sign() < 0) { histos.fill(HIST("tracks/triton/h2antiTritonTOFbetaVsP"), track.p(), track.beta()); - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { histos.fill(HIST("tracks/eff/triton/h2pVsTOFExpMomentumantiTr"), track.tofExpMom(), track.p()); histos.fill(HIST("tracks/eff/triton/h2TPCmomentumVsTOFExpMomentumantiTr"), track.tofExpMom(), track.tpcInnerParam()); } } } - 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()); @@ -4226,65 +4793,65 @@ struct LFNucleiBATask { } if (isDeWTPCpid) { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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/h2DeuteronEtavsPt"), track.eta(), DPt); + histos.fill(HIST("tracks/deuteron/h2DeuteronVspNSigmaITSDe_wTPCpid"), track.p(), nITSDe); + + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/deuteron/h2TPCsignVsTPCmomentumDeuteron"), track.tpcInnerParam(), track.tpcSignal()); } if (isAntiDeWTPCpid) { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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/h2antiDeuteronEtavsPt"), track.eta(), antiDPt); + histos.fill(HIST("tracks/deuteron/h2antiDeuteronVspNSigmaITSDe_wTPCpid"), track.p(), nITSDe); + + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/deuteron/h2TPCsignVsTPCmomentumantiDeuteron"), track.tpcInnerParam(), track.tpcSignal()); } if (isHeWTPCpid) { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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) + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/helium/h2TPCsignVsTPCmomentumHelium"), heTPCmomentum, track.tpcSignal()); } if (isAntiHeWTPCpid) { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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) + if (outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/helium/h2TPCsignVsTPCmomentumantiHelium"), antiheTPCmomentum, track.tpcSignal()); } if (outFlagOptions.doTOFplots && track.hasTOF()) { if (isDeWTPCpid) { histos.fill(HIST("tracks/deuteron/h2DeuteronTOFbetaVsP"), track.p(), track.beta()); - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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) { + if (outFlagOptions.enableEffPlots) { histos.fill(HIST("tracks/eff/deuteron/h2pVsTOFExpMomentumantiDe"), track.tofExpMom(), track.p()); histos.fill(HIST("tracks/eff/deuteron/h2TPCmomentumVsTOFExpMomentumantiDe"), track.tofExpMom(), track.tpcInnerParam()); } @@ -4292,7 +4859,7 @@ struct LFNucleiBATask { if (isHeWTPCpid) { histos.fill(HIST("tracks/helium/h2HeliumTOFbetaVsP"), heP, track.beta()); - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { histos.fill(HIST("tracks/eff/helium/h2pVsTOFExpMomentumHe"), track.tofExpMom(), heP); histos.fill(HIST("tracks/eff/helium/h2TPCmomentumVsTOFExpMomentumHe"), track.tofExpMom(), heTPCmomentum); } @@ -4300,31 +4867,31 @@ struct LFNucleiBATask { if (isAntiHeWTPCpid) { histos.fill(HIST("tracks/helium/h2antiHeliumTOFbetaVsP"), antiheP, track.beta()); - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) { 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 / TMath::Sqrt(1.f - (track.beta() * track.beta())); + gamma = 1.f / std::sqrt(1.f - (track.beta() * track.beta())); 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); + 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() * TMath::Sqrt(1.f / (track.beta() * track.beta()) - 1.f); + massTOF = track.tofExpMom() * std::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); + 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) + if (passDCAxyzCut && outFlagOptions.doTOFplots && outFlagOptions.enablePIDplot) histos.fill(HIST("tracks/h2TPCsignVsBetaGamma"), (track.beta() * gamma) / (1.f * track.sign()), track.tpcSignal()); } else { massTOF = -99.f; @@ -4333,8 +4900,9 @@ struct LFNucleiBATask { } if (passDCAxyzCut) { - histos.fill(HIST("tracks/h2TOFmassVsPt"), massTOF, track.pt()); - if (enableEvTimeSplitting) { + if (outFlagOptions.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()) { @@ -4349,157 +4917,156 @@ struct LFNucleiBATask { if (enablePr) { if ((std::abs(track.tpcNSigmaPr()) < nsigmaTPCvar.nsigmaTPCPr) && prRapCut) { if (track.sign() > 0) { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) 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 (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut)) { 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 (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 { - if (enablePtSpectra) { + if (outFlagOptions.enableEffPlots) histos.fill(HIST("tracks/eff/proton/hPtantiPrTOF"), track.pt()); - 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 (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut)) { 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 (outFlagOptions.enableExpSignalTOF) histos.fill(HIST("tracks/proton/h2antiProtonTOFExpSignalDiffVsPtCut"), track.pt(), track.tofExpSignalDiffPr()); - if (enableEvTimeSplitting) { + if (filterOptions.enableEvTimeSplitting) { if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + evtimeHistos.fill(HIST("tracks/evtime/ft0tof/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else if (track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + evtimeHistos.fill(HIST("tracks/evtime/ft0/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else if (track.isEvTimeTOF()) { - evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + evtimeHistos.fill(HIST("tracks/evtime/tof/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } else { - evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - fMassProton * fMassProton, track.pt()); + evtimeHistos.fill(HIST("tracks/evtime/fill/proton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProtonVal * MassProtonVal, track.pt()); } } } } } - if (enableTr) { - 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 (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()); - } - } 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 (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()); - } + if (enableTr && isTritonTPCpid && trRapCut) { + const float m2diff = massTOF * massTOF - MassTritonVal * MassTritonVal; + if (track.sign() > 0) { + if (outFlagOptions.enableEffPlots) + histos.fill(HIST("tracks/eff/triton/hPtTrTOF"), track.pt()); + histos.fill(HIST("tracks/triton/h2TOFmassTritonVsPt"), massTOF, track.pt()); + histos.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt"), m2diff, track.pt()); + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut)) { + histos.fill(HIST("tracks/triton/h2TOFmassTritonVsPt_BetaCut"), massTOF, track.pt()); + histos.fill(HIST("tracks/triton/h2TOFmass2TritonVsPt_BetaCut"), m2diff, track.pt()); + } + } else { + if (outFlagOptions.enableEffPlots) + histos.fill(HIST("tracks/eff/triton/hPtantiTrTOF"), track.pt()); + histos.fill(HIST("tracks/triton/h2TOFmassantiTritonVsPt"), massTOF, track.pt()); + histos.fill(HIST("tracks/triton/h2TOFmass2antiTritonVsPt"), m2diff, track.pt()); + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut)) { + histos.fill(HIST("tracks/triton/h2TOFmassantiTritonVsPt_BetaCut"), massTOF, track.pt()); + histos.fill(HIST("tracks/triton/h2TOFmass2antiTritonVsPt_BetaCut"), m2diff, track.pt()); } } } } if (isDeWTPCpid) { - if (enablePtSpectra) + if (outFlagOptions.enableEffPlots) 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()); + histos.fill(HIST("tracks/deuteron/h3TOFmass2DeuteronVsPtVsMult"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt, centFT0M); else - histos.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); - if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut)) { histos.fill(HIST("tracks/deuteron/h2TOFmassDeuteronVsPt_BetaCut"), massTOF, DPt); - histos.fill(HIST("tracks/deuteron/h2TOFmass2DeuteronVsPt_BetaCut"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, 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 (enableEvTimeSplitting) { + if (filterOptions.enableEvTimeSplitting) { if (track.isEvTimeTOF() && track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0tof/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); + 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 - fMassDeuteron * fMassDeuteron, DPt); + 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 - fMassDeuteron * fMassDeuteron, DPt); + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); } else { - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, DPt); + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, DPt); } } } if (isAntiDeWTPCpid) { - if (enablePtSpectra) + if (outFlagOptions.enableEffPlots) 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()); + histos.fill(HIST("tracks/deuteron/h3TOFmass2antiDeuteronVsPtVsMult"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt, centFT0M); else - histos.fill(HIST("tracks/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); - if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + histos.fill(HIST("tracks/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut)) { histos.fill(HIST("tracks/deuteron/h2TOFmassantiDeuteronVsPt_BetaCut"), massTOF, antiDPt); - histos.fill(HIST("tracks/deuteron/h2TOFmass2antiDeuteronVsPt_BetaCut"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, 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 (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/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); } else if (track.isEvTimeT0AC()) { - evtimeHistos.fill(HIST("tracks/evtime/ft0/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); + 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 - fMassDeuteron * fMassDeuteron, antiDPt); + evtimeHistos.fill(HIST("tracks/evtime/tof/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); } else { - evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - fMassDeuteron * fMassDeuteron, antiDPt); + evtimeHistos.fill(HIST("tracks/evtime/fill/deuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteronVal * MassDeuteronVal, antiDPt); } } } if (isHeWTPCpid) { - if (enablePtSpectra) + if (outFlagOptions.enableEffPlots) 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 - fMassHelium, hePt); - histos.fill(HIST("tracks/helium/h2TOFmass2HeliumVsPt"), 2.f * massTOFhe * 2.f * massTOFhe - fMassHelium * fMassHelium, hePt); - if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + 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 (enableCentrality) + histos.fill(HIST("tracks/helium/h3TOFmass2HeliumVsPtVsMult"), 2.f * massTOFantihe * 2.f * massTOFantihe - MassHeliumVal * MassHeliumVal, hePt, centFT0M); + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut)) { 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); + 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) + if (outFlagOptions.enableEffPlots) 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 - fMassHelium, antihePt); - histos.fill(HIST("tracks/helium/h2TOFmass2antiHeliumVsPt"), 2.f * massTOFantihe * 2.f * massTOFantihe - fMassHelium * fMassHelium, antihePt); - if (outFlagOptions.enableBetaCut && (track.beta() > betaCut)) { + 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 (enableCentrality) + histos.fill(HIST("tracks/helium/h3TOFmass2antiHeliumVsPtVsMult"), 2.f * massTOFantihe * 2.f * massTOFantihe - MassHeliumVal * MassHeliumVal, antihePt, centFT0M); + if (outFlagOptions.enableBetaCut && (track.beta() > cfgBetaCut)) { 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); + 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()); @@ -4507,6 +5074,7 @@ struct LFNucleiBATask { } if constexpr (IsMC) { + // auto const& mcParticles = particles; bool isPhysPrim = false; bool isProdByGen = false; bool isWeakDecay = false; @@ -4520,7 +5088,7 @@ struct LFNucleiBATask { if constexpr (IsFilteredData) { isPhysPrim = track.isPhysicalPrimary(); isProdByGen = track.producedByGenerator(); - isWeakDecay = track.getProcess() == 4; + isWeakDecay = (track.getProcess() == TMCProcess::kPDecay); pdgCode = track.pdgCode(); isItsPassed = track.itsPassed(); isTpcPassed = track.tpcPassed(); @@ -4532,7 +5100,7 @@ struct LFNucleiBATask { } isPhysPrim = track.mcParticle().isPhysicalPrimary(); isProdByGen = track.mcParticle().producedByGenerator(); - isWeakDecay = track.mcParticle().getProcess() == 4; + isWeakDecay = (track.mcParticle().getProcess() == TMCProcess::kPDecay); pdgCode = track.mcParticle().pdgCode(); isItsPassed = track.passedITSNCls() && track.passedITSChi2NDF() && @@ -4546,7 +5114,7 @@ struct LFNucleiBATask { track.passedTPCRefit() && track.hasTPC(); - for (int i = 0; i < 10; i++) { // From ITS to TPC + for (int i = 0; i < kFakeLoop; i++) { // From ITS to TPC if (track.mcMask() & 1 << i) { hasFakeHit = true; break; @@ -5224,8 +5792,9 @@ struct LFNucleiBATask { break; case PDGHelium: if (isHelium && passDCAzCutHe && passDCAxyCutHe) { - histos.fill(HIST("tracks/helium/h1HeliumSpectraTrue"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTrue_Z2"), 2 * hePt); + if (enableCentrality) + histos.fill(HIST("tracks/helium/h2HeliumSpectraTrueVsMult_Z2"), 2 * hePt, centFT0M); if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtHeliumTrue"), hePt, track.dcaXY()); @@ -5237,22 +5806,26 @@ struct LFNucleiBATask { } } 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 (enableCentrality) + histos.fill(HIST("tracks/helium/h2HeliumSpectraTrueWPIDVsMult_Z2"), 2 * hePt, centFT0M); + if (outFlagOptions.enableEffPlots) { + histos.fill(HIST("tracks/eff/helium/hPtHeTrue_Z2"), 2 * hePt); if (track.hasTOF() && outFlagOptions.doTOFplots) { - histos.fill(HIST("tracks/eff/helium/hPtHeTOFTrue"), 2 * hePt); + histos.fill(HIST("tracks/eff/helium/hPtHeTOFTrue_Z2"), 2 * hePt); } } } if (isPhysPrim) { - histos.fill(HIST("tracks/helium/h1HeliumSpectraTruePrim"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTruePrim_Z2"), 2 * hePt); + if (enableCentrality) + histos.fill(HIST("tracks/helium/h2HeliumSpectraTruePrimVsMult_Z2"), 2 * hePt, centFT0M); if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/TOF/h1HeliumSpectraTruePrim_Z2"), 2 * hePt); + if (enableCentrality) + histos.fill(HIST("tracks/helium/TOF/h2HeliumSpectraTruePrimVsMult_Z2"), 2 * hePt, centFT0M); } } @@ -5267,9 +5840,7 @@ struct LFNucleiBATask { } if (!isPhysPrim && !isProdByGen) { - histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueTransport"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueTransport_Z2"), 2 * hePt); - 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()); @@ -5279,9 +5850,9 @@ struct LFNucleiBATask { } } if (isWeakDecay) { - histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueSec"), hePt); histos.fill(HIST("tracks/helium/h1HeliumSpectraTrueSec_Z2"), 2 * hePt); - + if (enableCentrality) + histos.fill(HIST("tracks/helium/h2HeliumSpectraTrueSecVsMult_Z2"), 2 * hePt, centFT0M); 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()); @@ -5296,8 +5867,9 @@ struct LFNucleiBATask { break; case -PDGHelium: if (isHelium && passDCAzCutAntiHe && passDCAxyCutAntiHe) { - histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrue"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrue_Z2"), 2 * antihePt); + if (enableCentrality) + histos.fill(HIST("tracks/helium/h2antiHeliumSpectraTrueVsMult_Z2"), 2 * antihePt, centFT0M); if (outFlagOptions.makeDCAAfterCutPlots) { histos.fill(HIST("tracks/helium/dca/after/hDCAxyVsPtantiHeliumTrue"), antihePt, track.dcaXY()); @@ -5308,22 +5880,26 @@ struct LFNucleiBATask { } } 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 (enableCentrality) + histos.fill(HIST("tracks/helium/h2antiHeliumSpectraTrueWPIDVsMult_Z2"), 2 * antihePt, centFT0M); + if (outFlagOptions.enableEffPlots) { + histos.fill(HIST("tracks/eff/helium/hPtantiHeTrue_Z2"), 2 * antihePt); if (track.hasTOF() && outFlagOptions.doTOFplots) { - histos.fill(HIST("tracks/eff/helium/hPtantiHeTOFTrue"), 2 * antihePt); + histos.fill(HIST("tracks/eff/helium/hPtantiHeTOFTrue_Z2"), 2 * antihePt); } } } if (isPhysPrim) { - histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTruePrim"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTruePrim_Z2"), 2 * antihePt); + if (enableCentrality) + histos.fill(HIST("tracks/helium/h2antiHeliumSpectraTruePrimVsMult_Z2"), 2 * antihePt, centFT0M); if (std::abs(track.tpcNSigmaHe()) < nsigmaTPCvar.nsigmaTPCHe) { if (track.hasTOF() && outFlagOptions.doTOFplots) { histos.fill(HIST("tracks/helium/TOF/h1antiHeliumSpectraTruePrim_Z2"), 2 * antihePt); + if (enableCentrality) + histos.fill(HIST("tracks/helium/TOF/h2antiHeliumSpectraTruePrimVsMult_Z2"), 2 * antihePt, centFT0M); } } @@ -5337,9 +5913,7 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen) { - histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueTransport"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueTransport_Z2"), 2 * antihePt); - 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()); @@ -5350,9 +5924,9 @@ struct LFNucleiBATask { } if (isWeakDecay) { - histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueSec"), antihePt); histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTrueSec_Z2"), 2 * antihePt); - + if (enableCentrality) + histos.fill(HIST("tracks/helium/h2antiHeliumSpectraTrueSecVsMult_Z2"), 2 * antihePt, centFT0M); 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()); @@ -5429,6 +6003,8 @@ struct LFNucleiBATask { default: break; } + } else { + (void)particles; } } } @@ -5436,7 +6012,7 @@ struct LFNucleiBATask { using EventCandidates = soa::Join; using EventCandidatesMC = soa::Join; - using TrackCandidates0 = soa::Join(event, tracks, true /*dummy*/); + fillHistograms(event, tracks, true /*dummy*/, event.centFT0M()); } 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*/); + fillHistograms(event, tracks, true /*dummy*/, event.centFT0M()); } 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*/); + fillHistograms(event, tracks, true /*dummy*/, event.centFT0M()); } 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*/); + fillHistograms(event, tracks, true /*dummy*/, event.centFT0M()); } PROCESS_SWITCH(LFNucleiBATask, processDataLight, "process data on the derived trees", false); @@ -5502,26 +6082,91 @@ struct LFNucleiBATask { // MC Reco // ///////////// + Preslice perMCCol = aod::mcparticle::mcCollisionId; + SliceCache cache; + // Process function that runs on the original AO2D (for the MC) void processMCReco(EventCandidatesMC::iterator const& event, + soa::Join const& mcCollisions, soa::Join const& tracks, - aod::McParticles const& mcParticles) + aod::McParticles const& mcParticles, + o2::aod::BCsWithTimestamps const&) { - fillHistograms(event, tracks, mcParticles); + bool doRecoSep = true; + + const bool hasTVX = event.selection_bit(aod::evsel::kIsTriggerTVX); + const bool hasNoTFB = event.selection_bit(aod::evsel::kNoTimeFrameBorder); + const bool hasNoItsRofFB = event.selection_bit(aod::evsel::kNoITSROFrameBorder); + + if (evselOptions.useSel8) { + doRecoSep = (hasTVX && hasNoTFB); + } else { + if (evselOptions.useTVXtrigger && !hasTVX) + doRecoSep = false; + if (evselOptions.removeTFBorder && !hasNoTFB) + doRecoSep = false; + if (evselOptions.removeITSROFBorder && !hasNoItsRofFB) + doRecoSep = false; + } + + float mcCentFT0M = -1.f; + + if (doRecoSep && event.has_mcCollision()) { + const int mcIdx = event.mcCollisionId(); + if (mcIdx >= 0) { + effEvtSet.insert(mcIdx); + effEvtSetReady = true; + + auto mcColIter = mcCollisions.iteratorAt(mcIdx); + mcCentFT0M = mcColIter.centFT0M(); + } + } + + fillHistograms(event, tracks, mcParticles, mcCentFT0M); } // 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(EventCandidatesMC::iterator const& event, + soa::Join const& mcCollisions, soa::Join const& tracks, - aod::McParticles const& mcParticles) + aod::McParticles const& mcParticles, + o2::aod::BCsWithTimestamps const&) { - fillHistograms(event, tracks, mcParticles); + bool doRecoSep = true; + + const bool hasTVX = event.selection_bit(aod::evsel::kIsTriggerTVX); + const bool hasNoTFB = event.selection_bit(aod::evsel::kNoTimeFrameBorder); + const bool hasNoItsRofFB = event.selection_bit(aod::evsel::kNoITSROFrameBorder); + + if (evselOptions.useSel8) { + doRecoSep = (hasTVX && hasNoTFB); + } else { + if (evselOptions.useTVXtrigger && !hasTVX) + doRecoSep = false; + if (evselOptions.removeTFBorder && !hasNoTFB) + doRecoSep = false; + if (evselOptions.removeITSROFBorder && !hasNoItsRofFB) + doRecoSep = false; + } + + float mcCentFT0M = -1.f; + + if (doRecoSep && event.has_mcCollision()) { + const int mcIdx = event.mcCollisionId(); + if (mcIdx >= 0) { + effEvtSet.insert(mcIdx); + effEvtSetReady = true; + + auto mcColIter = mcCollisions.iteratorAt(mcIdx); + mcCentFT0M = mcColIter.centFT0M(); + } + } + + fillHistograms(event, tracks, mcParticles, mcCentFT0M); } // CLOSING PROCESS MC RECO PROCESS_SWITCH(LFNucleiBATask, processMCRecoLfPid, "process mc reco with LfPid", false); - Preslice perMCCol = aod::mcparticle::mcCollisionId; - SliceCache cache; // Process function that runs on the original AO2D (for the MC) with the LfPIDcalibration void processMCRecoLfPidEv(EventCandidatesMC const& collisions, soa::Join const&, @@ -5529,122 +6174,125 @@ struct LFNucleiBATask { aod::McCollisions const&) { for (const auto& collision : collisions) { - if (!collision.has_mcCollision()) { + if (!collision.has_mcCollision()) continue; - } + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, collision.mcCollision().globalIndex(), cache); + const bool hasTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); + const bool hasNoTFB = collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + const bool hasNoItsRofFB = collision.selection_bit(aod::evsel::kNoITSROFrameBorder); + const bool hasSel8 = collision.sel8(); + for (const auto& mcParticle : particlesInCollision) { - if (mcParticle.y() > kinemOptions.yHighCut || mcParticle.y() < kinemOptions.yLowCut) { + const float rapidity = mcParticle.y(); + if (rapidity > kinemOptions.cfgRapidityCutHigh || rapidity < kinemOptions.cfgRapidityCutLow) continue; + + const int pdg = mcParticle.pdgCode(); + const float pt = mcParticle.pt(); + bool isPhysPrim = mcParticle.isPhysicalPrimary(); + + // No cut + spectraGen.fill(HIST("LfEv/pT_nocut"), pt); + if (pdg == PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_nocut_He"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_nocut_He"), pt); } - spectraGen.fill(HIST("LfEv/pT_nocut"), mcParticle.pt()); - if (mcParticle.pdgCode() == PDGHelium) { - spectraGen.fill(HIST("LfEv/helium/pT_nocut_He"), mcParticle.pt()); - } - if (mcParticle.pdgCode() == -PDGHelium) { - spectraGen.fill(HIST("LfEv/helium/pT_nocut_antiHe"), mcParticle.pt()); + if (pdg == -PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_nocut_antiHe"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_nocut_antiHe"), pt); } - } - 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()); + // Trigger TVX + if (hasTVX) { + spectraGen.fill(HIST("LfEv/pT_TVXtrigger"), pt); + if (pdg == PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_TVXtrigger_He"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_TVXtrigger_He"), pt); } - if (mcParticle.pdgCode() == -PDGHelium) { - spectraGen.fill(HIST("LfEv/helium/pT_TVXtrigger_antiHe"), mcParticle.pt()); + if (pdg == -PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_TVXtrigger_antiHe"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_TVXtrigger_antiHe"), pt); } } - } - 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()); + // No Time Frame Border + if (hasNoTFB) { + spectraGen.fill(HIST("LfEv/pT_TFrameBorder"), pt); + if (pdg == PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_TFrameBorder_He"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_TFrameBorder_He"), pt); } - if (mcParticle.pdgCode() == -PDGHelium) { - spectraGen.fill(HIST("LfEv/helium/pT_TFrameBorder_antiHe"), mcParticle.pt()); + if (pdg == -PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_TFrameBorder_antiHe"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_TFrameBorder_antiHe"), pt); } } - } - 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()); + // No ITS ROF Frame Border + if (hasNoItsRofFB) { + spectraGen.fill(HIST("LfEv/pT_ITSROFBorder"), pt); + if (pdg == PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_ITSROFBorder_He"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_ITSROFBorder_He"), pt); } - if (mcParticle.pdgCode() == -PDGHelium) { - spectraGen.fill(HIST("LfEv/helium/pT_ITSROFBorder_antiHe"), mcParticle.pt()); + if (pdg == -PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_ITSROFBorder_antiHe"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_ITSROFBorder_antiHe"), pt); } } - } - 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()); + // Sel8 MC + if (hasTVX && hasNoTFB) { + spectraGen.fill(HIST("LfEv/pT_MCsel8"), pt); + if (pdg == PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_He"), pt); if (isPhysPrim) - spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_HePrim"), mcParticle.pt()); + spectraGen.fill(HIST("LfEv/helium/prim/pT_MCsel8_He"), pt); } - if (mcParticle.pdgCode() == -PDGHelium) { - spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_antiHe"), mcParticle.pt()); + if (pdg == -PDGHelium) { + spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_antiHe"), pt); if (isPhysPrim) - spectraGen.fill(HIST("LfEv/helium/pT_MCsel8_antiHePrim"), mcParticle.pt()); + spectraGen.fill(HIST("LfEv/helium/prim/pT_MCsel8_antiHe"), 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()); - } - if (mcParticle.pdgCode() == -PDGHelium) { - spectraGen.fill(HIST("LfEv/helium/pT_sel8_antiHe"), mcParticle.pt()); - } + // Sel8 tag + if (hasSel8) { + spectraGen.fill(HIST("LfEv/pT_sel8"), pt); + if (pdg == PDGHelium) + spectraGen.fill(HIST("LfEv/helium/pT_sel8_He"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_sel8_He"), pt); + if (pdg == -PDGHelium) + spectraGen.fill(HIST("LfEv/helium/pT_sel8_antiHe"), pt); + if (isPhysPrim) + spectraGen.fill(HIST("LfEv/helium/prim/pT_sel8_antiHe"), pt); } } } } - // CLOSING PROCESS MC RECO PROCESS_SWITCH(LFNucleiBATask, processMCRecoLfPidEv, "process mc reco with LfPid w/ Event", false); // 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*/); + fillHistograms(event, tracks, true /*dummy*/, event.centFT0M()); } // 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*/); + fillHistograms(event, tracks, true /*dummy*/, event.centFT0M()); } // CLOSING PROCESS MC RECO ON FILTERED DATA PROCESS_SWITCH(LFNucleiBATask, processMCRecoFilteredLight, "process mc reco on the derived trees", false); @@ -5653,175 +6301,199 @@ struct LFNucleiBATask { //////////// // LOOP OVER GENERATED MC PARTICLES - void processMCGen(aod::McCollision const& mcCollision, - aod::McParticles& mcParticles) + void processMCGen(soa::Join::iterator const& mcCollision, + aod::McParticles const& mcParticles) { - spectraGen.fill(HIST("histGenVetxZ"), mcCollision.posZ()); - for (auto& mcParticleGen : mcParticles) { - if (mcParticleGen.y() > kinemOptions.yHighCut || mcParticleGen.y() < kinemOptions.yLowCut) { + // Only events that are reconstructed + const int mcIdx = mcCollision.globalIndex(); + if (enableEffEvtSet) { + if (!effEvtSetReady) + return; + if (!effEvtSet.count(mcIdx)) + return; + } + + if (mcCollision.centFT0M() < cfgMultCutLow || mcCollision.centFT0M() > cfgMultCutHigh) + return; + + if (enableCentrality) + spectraGen.fill(HIST("histGenVetxZ"), mcCollision.posZ(), mcCollision.centFT0M()); + else + spectraGen.fill(HIST("histGenVetxZ"), mcCollision.posZ()); + + // const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcIdx, cache); + // const auto particlesInCollision = mcParticles.sliceBy(perMCCol, mcIdx); + + for (const auto& mcParticleGen : mcParticles) { + if (mcParticleGen.mcCollisionId() != mcIdx) continue; - } + if (mcParticleGen.y() > kinemOptions.cfgRapidityCutHigh || mcParticleGen.y() < kinemOptions.cfgRapidityCutLow) + continue; + + const int pdgCode = mcParticleGen.pdgCode(); + const float ptMC = mcParticleGen.pt(); bool isPhysPrim = mcParticleGen.isPhysicalPrimary(); bool isProdByGen = mcParticleGen.producedByGenerator(); - bool isWeakDecay = mcParticleGen.getProcess() == 4; + bool isWeakDecay = (mcParticleGen.getProcess() == TMCProcess::kPDecay); - if (mcParticleGen.pdgCode() == PDGPion) { - spectraGen.fill(HIST("pion/histGenPtPion"), mcParticleGen.pt()); + if (pdgCode == PDGPion) { + spectraGen.fill(HIST("pion/histGenPtPion"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("pion/histGenPtPionPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("pion/histGenPtPionPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("pion/histSecTransportPtPion"), mcParticleGen.pt()); + spectraGen.fill(HIST("pion/histSecTransportPtPion"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("pion/histGenPtPionSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("pion/histGenPtPionSec"), ptMC); } } } - if (mcParticleGen.pdgCode() == -PDGPion) { - spectraGen.fill(HIST("pion/histGenPtantiPion"), mcParticleGen.pt()); + if (pdgCode == -PDGPion) { + spectraGen.fill(HIST("pion/histGenPtantiPion"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("pion/histGenPtantiPionPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("pion/histGenPtantiPionPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("pion/histSecTransportPtantiPion"), mcParticleGen.pt()); + spectraGen.fill(HIST("pion/histSecTransportPtantiPion"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("pion/histGenPtantiPionSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("pion/histGenPtantiPionSec"), ptMC); } } } - if (mcParticleGen.pdgCode() == PDGKaon) { - spectraGen.fill(HIST("kaon/histGenPtKaon"), mcParticleGen.pt()); + if (pdgCode == PDGKaon) { + spectraGen.fill(HIST("kaon/histGenPtKaon"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("kaon/histGenPtKaonPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("kaon/histGenPtKaonPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("kaon/histSecTransportPtKaon"), mcParticleGen.pt()); + spectraGen.fill(HIST("kaon/histSecTransportPtKaon"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("kaon/histGenPtKaonSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("kaon/histGenPtKaonSec"), ptMC); } } } - if (mcParticleGen.pdgCode() == -PDGKaon) { - spectraGen.fill(HIST("kaon/histGenPtantiKaon"), mcParticleGen.pt()); + if (pdgCode == -PDGKaon) { + spectraGen.fill(HIST("kaon/histGenPtantiKaon"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("kaon/histGenPtantiKaonPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("kaon/histGenPtantiKaonPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("kaon/histSecTransportPtantiKaon"), mcParticleGen.pt()); + spectraGen.fill(HIST("kaon/histSecTransportPtantiKaon"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("kaon/histGenPtantiKaonSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("kaon/histGenPtantiKaonSec"), ptMC); } } } if (enablePr) { - if (mcParticleGen.pdgCode() == PDGProton) { - spectraGen.fill(HIST("proton/histGenPtProton"), mcParticleGen.pt()); + if (pdgCode == PDGProton) { + spectraGen.fill(HIST("proton/histGenPtProton"), ptMC); if (isPhysPrim) { - spectraGen.fill(HIST("proton/histGenPtProtonPrim"), mcParticleGen.pt()); - spectraGen.fill(HIST("proton/histGenPtProtonPrim_Y"), mcParticleGen.y(), mcParticleGen.pt()); + spectraGen.fill(HIST("proton/histGenPtProtonPrim"), ptMC); + spectraGen.fill(HIST("proton/histGenPtProtonPrim_Y"), mcParticleGen.y(), ptMC); } if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("proton/histSecTransportPtProton"), mcParticleGen.pt()); + spectraGen.fill(HIST("proton/histSecTransportPtProton"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("proton/histGenPtProtonSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("proton/histGenPtProtonSec"), ptMC); } } } - if (mcParticleGen.pdgCode() == -PDGProton) { - spectraGen.fill(HIST("proton/histGenPtantiProton"), mcParticleGen.pt()); + if (pdgCode == -PDGProton) { + spectraGen.fill(HIST("proton/histGenPtantiProton"), ptMC); if (isPhysPrim) { - spectraGen.fill(HIST("proton/histGenPtantiProtonPrim"), mcParticleGen.pt()); - spectraGen.fill(HIST("proton/histGenPtantiProtonPrim_Y"), mcParticleGen.y(), mcParticleGen.pt()); + spectraGen.fill(HIST("proton/histGenPtantiProtonPrim"), ptMC); + spectraGen.fill(HIST("proton/histGenPtantiProtonPrim_Y"), mcParticleGen.y(), ptMC); } if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("proton/histSecTransportPtantiProton"), mcParticleGen.pt()); + spectraGen.fill(HIST("proton/histSecTransportPtantiProton"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("proton/histGenPtantiProtonSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("proton/histGenPtantiProtonSec"), ptMC); } } } } if (enableDe) { - if (mcParticleGen.pdgCode() == PDGDeuteron) { - spectraGen.fill(HIST("deuteron/histGenPtD"), mcParticleGen.pt()); + if (pdgCode == PDGDeuteron) { + spectraGen.fill(HIST("deuteron/histGenPtD"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("deuteron/histGenPtDPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("deuteron/histGenPtDPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("deuteron/histSecTransportPtD"), mcParticleGen.pt()); + spectraGen.fill(HIST("deuteron/histSecTransportPtD"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("deuteron/histGenPtDSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("deuteron/histGenPtDSec"), ptMC); } } } - if (mcParticleGen.pdgCode() == -PDGDeuteron) { - spectraGen.fill(HIST("deuteron/histGenPtantiD"), mcParticleGen.pt()); + if (pdgCode == -PDGDeuteron) { + spectraGen.fill(HIST("deuteron/histGenPtantiD"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("deuteron/histGenPtantiDPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("deuteron/histGenPtantiDPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("deuteron/histSecTransportPtantiD"), mcParticleGen.pt()); + spectraGen.fill(HIST("deuteron/histSecTransportPtantiD"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("deuteron/histGenPtantiDSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("deuteron/histGenPtantiDSec"), ptMC); } } } } if (enableTr) { - if (mcParticleGen.pdgCode() == PDGTriton) { - spectraGen.fill(HIST("triton/histGenPtT"), mcParticleGen.pt()); + if (pdgCode == PDGTriton) { + spectraGen.fill(HIST("triton/histGenPtT"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("triton/histGenPtTPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("triton/histGenPtTPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("triton/histSecTransportPtT"), mcParticleGen.pt()); + spectraGen.fill(HIST("triton/histSecTransportPtT"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("triton/histGenPtTSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("triton/histGenPtTSec"), ptMC); } } } - if (mcParticleGen.pdgCode() == -PDGTriton) { - spectraGen.fill(HIST("triton/histGenPtantiT"), mcParticleGen.pt()); + if (pdgCode == -PDGTriton) { + spectraGen.fill(HIST("triton/histGenPtantiT"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("triton/histGenPtantiTPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("triton/histGenPtantiTPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("triton/histSecTransportPtantiT"), mcParticleGen.pt()); + spectraGen.fill(HIST("triton/histSecTransportPtantiT"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("triton/histGenPtantiTSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("triton/histGenPtantiTSec"), ptMC); } } } } if (enableHe) { - if (mcParticleGen.pdgCode() == PDGHelium) { - spectraGen.fill(HIST("helium/histGenPtHe"), mcParticleGen.pt()); + if (pdgCode == PDGHelium) { + spectraGen.fill(HIST("helium/histGenPtHe"), ptMC); if (isPhysPrim) { - // LOG(info) << "I AM POSITIVE HELIUM and PRIMARY, get process output is: " << mcParticleGen.getProcess(); - spectraGen.fill(HIST("helium/histGenPtHePrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("helium/histGenPtHePrim"), ptMC); + if (enableCentrality) + spectraGen.fill(HIST("helium/histGenPtHePrimVsMult"), ptMC, mcCollision.centFT0M()); } if (!isPhysPrim && isProdByGen) { { @@ -5829,18 +6501,18 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("helium/histSecTransportPtHe"), mcParticleGen.pt()); - // LOG(info) << "I AM POSITIVE HELIUM and SECONDARY, get process output is: " << mcParticleGen.getProcess(); + spectraGen.fill(HIST("helium/histSecTransportPtHe"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("helium/histGenPtHeSec"), mcParticleGen.pt()); - // LOG(info) << "I AM POSITIVE HELIUM and SECONDARY FROM MATERIAL, get process output is: " << mcParticleGen.getProcess(); + spectraGen.fill(HIST("helium/histGenPtHeSec"), ptMC); } } } - if (mcParticleGen.pdgCode() == -PDGHelium) { - spectraGen.fill(HIST("helium/histGenPtantiHe"), mcParticleGen.pt()); + if (pdgCode == -PDGHelium) { + spectraGen.fill(HIST("helium/histGenPtantiHe"), ptMC); if (isPhysPrim) { - spectraGen.fill(HIST("helium/histGenPtantiHePrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("helium/histGenPtantiHePrim"), ptMC); + if (enableCentrality) + spectraGen.fill(HIST("helium/histGenPtantiHePrimVsMult"), ptMC, mcCollision.centFT0M()); } if (!isPhysPrim && isProdByGen) { { @@ -5848,39 +6520,39 @@ struct LFNucleiBATask { } } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("helium/histSecTransportPtantiHe"), mcParticleGen.pt()); + spectraGen.fill(HIST("helium/histSecTransportPtantiHe"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("helium/histGenPtantiHeSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("helium/histGenPtantiHeSec"), ptMC); } } } } if (enableAl) { - if (mcParticleGen.pdgCode() == PDGAlpha) { - spectraGen.fill(HIST("alpha/histGenPtAl"), mcParticleGen.pt()); + if (pdgCode == PDGAlpha) { + spectraGen.fill(HIST("alpha/histGenPtAl"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("alpha/histGenPtAlPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("alpha/histGenPtAlPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("alpha/histSecTransportPtAl"), mcParticleGen.pt()); + spectraGen.fill(HIST("alpha/histSecTransportPtAl"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("alpha/histGenPtAlSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("alpha/histGenPtAlSec"), ptMC); } } } - if (mcParticleGen.pdgCode() == -PDGAlpha) { - spectraGen.fill(HIST("alpha/histGenPtantiAl"), mcParticleGen.pt()); + if (pdgCode == -PDGAlpha) { + spectraGen.fill(HIST("alpha/histGenPtantiAl"), ptMC); if (isPhysPrim) - spectraGen.fill(HIST("alpha/histGenPtantiAlPrim"), mcParticleGen.pt()); + spectraGen.fill(HIST("alpha/histGenPtantiAlPrim"), ptMC); if (!isPhysPrim && isProdByGen) { // } if (!isPhysPrim && !isProdByGen) { - spectraGen.fill(HIST("alpha/histSecTransportPtantiAl"), mcParticleGen.pt()); + spectraGen.fill(HIST("alpha/histSecTransportPtantiAl"), ptMC); if (isWeakDecay) { - spectraGen.fill(HIST("alpha/histGenPtantiAlSec"), mcParticleGen.pt()); + spectraGen.fill(HIST("alpha/histGenPtantiAlSec"), ptMC); } } } @@ -5888,6 +6560,268 @@ struct LFNucleiBATask { } } // Close processMCGen PROCESS_SWITCH(LFNucleiBATask, processMCGen, "process MC Generated", true); + + void processEvSgLossMC(soa::Join::iterator const& mcCollision, + aod::McParticles const& mcParticles, + const soa::SmallGroups& recoColls) + { + if (std::abs(mcCollision.posZ()) < cfgVzCutHigh) + evLossHistos.fill(HIST("evLoss/hEvent"), 0.5); + + bool isSel8Event = false; + bool isTvxEvent = false; + bool isNoTFBEvent = false; + bool isMCSel8Event = false; + + // Check if there is an event reconstructed for a generated event + for (const auto& recoColl : recoColls) { + if (std::abs(recoColl.posZ()) > cfgVzCutHigh) + continue; + if (recoColl.selection_bit(o2::aod::evsel::kIsTriggerTVX)) + isTvxEvent = true; + if (recoColl.sel8()) + isSel8Event = true; + if (recoColl.selection_bit(aod::evsel::kNoTimeFrameBorder)) + isNoTFBEvent = true; + if (isTvxEvent && isSel8Event && isNoTFBEvent) + break; // Optimize loop + } + + if (isTvxEvent && isNoTFBEvent) + isMCSel8Event = true; + + if (isTvxEvent) + evLossHistos.fill(HIST("evLoss/hEvent"), 1.5); + if (isSel8Event) + evLossHistos.fill(HIST("evLoss/hEvent"), 2.5); + if (isMCSel8Event) + evLossHistos.fill(HIST("evLoss/hEvent"), 3.5); + + // Loop over all the Generated level particles + for (const auto& mcPart : mcParticles) { + if (!mcPart.isPhysicalPrimary()) + continue; + if (std::abs(mcPart.y()) >= kCfgTpcClasses[0]) + continue; + + const float pt = mcPart.pt(); + const int pdg = mcPart.pdgCode(); + + if (pdg == PDGDeuteron) { + evLossHistos.fill(HIST("evLoss/pt/hDeuteronGen"), pt); + if (isTvxEvent) + evLossHistos.fill(HIST("evLoss/pt/hDeuteronTriggeredTVX"), pt); + if (isSel8Event) + evLossHistos.fill(HIST("evLoss/pt/hDeuteronTriggeredSel8"), pt); + if (isMCSel8Event) + evLossHistos.fill(HIST("evLoss/pt/hDeuteronTriggeredMCSel8"), pt); + } + if (pdg == -PDGDeuteron) { + evLossHistos.fill(HIST("evLoss/pt/hAntiDeuteronGen"), pt); + if (isTvxEvent) + evLossHistos.fill(HIST("evLoss/pt/hAntiDeuteronTriggeredTVX"), pt); + if (isSel8Event) + evLossHistos.fill(HIST("evLoss/pt/hAntiDeuteronTriggeredSel8"), pt); + if (isMCSel8Event) + evLossHistos.fill(HIST("evLoss/pt/hAntiDeuteronTriggeredMCSel8"), pt); + } + if (pdg == PDGHelium) { + evLossHistos.fill(HIST("evLoss/pt/hHeliumGen"), pt); + if (isTvxEvent) + evLossHistos.fill(HIST("evLoss/pt/hHeliumTriggeredTVX"), pt); + if (isSel8Event) + evLossHistos.fill(HIST("evLoss/pt/hHeliumTriggeredSel8"), pt); + if (isMCSel8Event) + evLossHistos.fill(HIST("evLoss/pt/hHeliumTriggeredMCSel8"), pt); + } + if (pdg == -PDGHelium) { + evLossHistos.fill(HIST("evLoss/pt/hAntiHeliumGen"), pt); + if (isTvxEvent) + evLossHistos.fill(HIST("evLoss/pt/hAntiHeliumTriggeredTVX"), pt); + if (isSel8Event) + evLossHistos.fill(HIST("evLoss/pt/hAntiHeliumTriggeredSel8"), pt); + if (isMCSel8Event) + evLossHistos.fill(HIST("evLoss/pt/hAntiHeliumTriggeredMCSel8"), pt); + } + } + } + PROCESS_SWITCH(LFNucleiBATask, processEvSgLossMC, "process MC SignLoss", false); + + // void processMCGen(soa::Join::iterator const& mcCollision, + // aod::McParticles const& mcParticles) + + // EVENT LOSS, SIGNAL LOSS and EFFICIENCY CHECKER process function + void processMCGenLosses( + soa::Join::iterator const& mcCollision, + const soa::SmallGroups>& collisions, + aod::McParticles const& mcParticles) + { + bool isINELgt0true = pwglf::isINELgtNmc(mcParticles, 0, pdgDB); + + // EVENT LOSS DENOMINATOR + // No cuts + histoGen.fill(HIST("events/hMCGen"), 0.5); + if (enableCentrality) + histoGen.fill(HIST("events/hMCGenVsMult"), 0.5, mcCollision.centFT0M()); + + // Vtz cut + if (mcCollision.posZ() < cfgVzCutLow || mcCollision.posZ() > cfgVzCutHigh) + return; + histoGen.fill(HIST("events/hMCGen"), 1.5); + if (enableCentrality) + histoGen.fill(HIST("events/hMCGenVsMult"), 1.5, mcCollision.centFT0M()); + + // INEL > 0 + if (isINELgt0true) { + histoGen.fill(HIST("events/hMCGen"), 2.5); + if (enableCentrality) + histoGen.fill(HIST("events/hMCGenVsMult"), 2.5, mcCollision.centFT0M()); + } + + // SIGNAL LOSS DENOMINATOR + for (const auto& mcParticle : mcParticles) { + if (mcParticle.y() > kinemOptions.cfgRapidityCutHigh || mcParticle.y() < kinemOptions.cfgRapidityCutLow) + continue; + + int pdg = mcParticle.pdgCode(); + float pt = mcParticle.pt(); + bool isPhysPrim = mcParticle.isPhysicalPrimary(); + + if (enableHe && isPhysPrim && (std::abs(pdg) == PDGHelium)) { + if (pdg > 0) { + histoGen.fill(HIST("helium/MCGen/h2HeliumYvsPt"), mcParticle.y(), pt); + histoGen.fill(HIST("helium/MCGen/ptGen_INEL_Prim_He"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCGen/ptGenVsMult_INEL_Prim_He"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("helium/MCGen/h2antiHeliumYvsPt"), mcParticle.y(), pt); + histoGen.fill(HIST("helium/MCGen/ptGen_INEL_Prim_antiHe"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCGen/ptGenVsMult_INEL_Prim_antiHe"), pt, mcCollision.centFT0M()); + } + if (isINELgt0true) { + if (pdg > 0) { + histoGen.fill(HIST("helium/MCGen/ptGen_INELgt0_Prim_He"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCGen/ptGenVsMult_INELgt0_Prim_He"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("helium/MCGen/ptGen_INELgt0_Prim_antiHe"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCGen/ptGenVsMult_INELgt0_Prim_antiHe"), pt, mcCollision.centFT0M()); + } + } + } + } + + int recoIdxINEL = 0; + int recoIdxINELgt0 = 0; + // for (const auto& collision : collisions) { + for (const auto& collision : collisions) { + bool hasTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); + bool hasNoTFB = collision.selection_bit(aod::evsel::kNoTimeFrameBorder); + bool hasNoItsRofFB = collision.selection_bit(aod::evsel::kNoITSROFrameBorder); + + // Check event selection + histoGen.fill(HIST("events/hMCReco"), 0.5); + if (evselOptions.useTVXtrigger && !hasTVX) + continue; + if (evselOptions.removeTFBorder && !hasNoTFB) + continue; + if (evselOptions.removeITSROFBorder && !hasNoItsRofFB) + continue; + histoGen.fill(HIST("events/hMCReco"), 1.5); + + recoIdxINEL++; + + if (collision.isInelGt0() && isINELgt0true) { + histoGen.fill(HIST("events/hMCReco"), 2.5); + recoIdxINELgt0++; + } + + for (const auto& mcParticle : mcParticles) { + if (mcParticle.y() > kinemOptions.cfgRapidityCutHigh || mcParticle.y() < kinemOptions.cfgRapidityCutLow) + continue; + + int pdg = mcParticle.pdgCode(); + float pt = mcParticle.pt(); + bool isPhysPrim = mcParticle.isPhysicalPrimary(); + + if (enableHe && isPhysPrim && (std::abs(pdg) == PDGHelium)) { + if (pdg > 0) { + histoGen.fill(HIST("helium/MCReco/ptGen_INEL_Prim_He"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCReco/ptGenVsMult_INEL_Prim_He"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("helium/MCReco/ptGen_INEL_Prim_antiHe"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCReco/ptGenVsMult_INEL_Prim_antiHe"), pt, mcCollision.centFT0M()); + } + if (recoIdxINELgt0 > 0) { + if (pdg > 0) { + histoGen.fill(HIST("helium/MCReco/ptGen_INELgt0_Prim_He"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCReco/ptGenVsMult_INELgt0_Prim_He"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("helium/MCReco/ptGen_INELgt0_Prim_antiHe"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCReco/ptGenVsMult_INELgt0_Prim_antiHe"), pt, mcCollision.centFT0M()); + } + } + } + } + } + + if (recoIdxINEL < 1) { + return; + } + + // EVENT LOSS NUMERATOR + histoGen.fill(HIST("events/hMCGenReco"), 0.5); + if (enableCentrality) + histoGen.fill(HIST("events/hMCGenRecoVsMult"), 0.5, mcCollision.centFT0M()); + + if (recoIdxINELgt0 > 0) { + histoGen.fill(HIST("events/hMCGenReco"), 1.5); + if (enableCentrality) + histoGen.fill(HIST("events/hMCGenRecoVsMult"), 1.5, mcCollision.centFT0M()); + } + + // SIGNAL LOSS NUMERATOR + for (const auto& mcParticle : mcParticles) { + if (mcParticle.y() > kinemOptions.cfgRapidityCutHigh || mcParticle.y() < kinemOptions.cfgRapidityCutLow) + continue; + + int pdg = mcParticle.pdgCode(); + float pt = mcParticle.pt(); + bool isPhysPrim = mcParticle.isPhysicalPrimary(); + + if (enableHe && isPhysPrim && (std::abs(pdg) == PDGHelium)) { + if (pdg > 0) { + histoGen.fill(HIST("helium/MCGenReco/h2HeliumYvsPt"), mcParticle.y(), pt); + histoGen.fill(HIST("helium/MCGenReco/ptGen_INEL_Prim_He"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCGenReco/ptGenVsMult_INEL_Prim_He"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("helium/MCGenReco/h2antiHeliumYvsPt"), mcParticle.y(), pt); + histoGen.fill(HIST("helium/MCGenReco/ptGen_INEL_Prim_antiHe"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCGenReco/ptGenVsMult_INEL_Prim_antiHe"), pt, mcCollision.centFT0M()); + } + if (recoIdxINELgt0 > 0) { + if (pdg > 0) { + histoGen.fill(HIST("helium/MCGenReco/ptGen_INELgt0_Prim_He"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCGenReco/ptGenVsMult_INELgt0_Prim_He"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("helium/MCGenReco/ptGen_INELgt0_Prim_antiHe"), pt); + if (enableCentrality) + histoGen.fill(HIST("helium/MCGenReco/ptGenVsMult_INELgt0_Prim_antiHe"), pt, mcCollision.centFT0M()); + } + } + } + } + } + PROCESS_SWITCH(LFNucleiBATask, processMCGenLosses, "process MCGen losses", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Nuspex/NucleiEfficiencyTask.cxx b/PWGLF/Tasks/Nuspex/NucleiEfficiencyTask.cxx index cf29855fc2f..62e8a385e42 100644 --- a/PWGLF/Tasks/Nuspex/NucleiEfficiencyTask.cxx +++ b/PWGLF/Tasks/Nuspex/NucleiEfficiencyTask.cxx @@ -12,68 +12,87 @@ // Authors: Rafael Manhart, // Date: 06.05.2024 -#include -#include -#include -#include +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/DataModel/spectraTOF.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "ReconstructionDataFormats/Track.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + #include "TPDGCode.h" +#include +#include +#include +#include + +#include +#include +#include using namespace o2; +using namespace o2::track; using namespace o2::framework; using namespace o2::framework::expressions; struct NucleiEfficiencyTask { - HistogramRegistry MC_truth_reg{"MC_particles_gen", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MC_truth_reg_cent{"MC_particles_gen_cent", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry MC_gen_reg{"MC_particles_gen", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry MC_recon_reg{"MC_particles_reco", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MC_recon_reg_cent{"MC_particles_reco_cent", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - OutputObj histPDG_mctruth{TH1F("PDG_gen", "PDG;PDG code", 20, 0.0, 20.0)}; - OutputObj histPDG{TH1F("PDG_reco", "PDG;PDG code", 20, 0.0, 20.0)}; + 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 centBinning = {0., 10., 20., 30., 40., 50., 60., 70., 80., 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 pAxis = {ptBinning, "#it{p} (GeV/#it{c})"}; - AxisSpec centralityAxis = {100, 0.0, 100.0, "VT0C (%)"}; - AxisSpec centralityAxis_extended = {105, 0.0, 105.0, "VT0C (%)"}; + AxisSpec centralityAxis = {100, 0.0, 105.0, "VT0C (%)"}; AxisSpec etaAxis = {etaBinning, "#eta"}; - AxisSpec centAxis = {centBinning, "Centrality (%)"}; - AxisSpec ImPaAxis = {centBinning, "Impact parameter"}; + AxisSpec ImPaAxis = {100, 0.0, 105.0, "Impact parameter"}; AxisSpec PDGBINNING = {PDGBinning, "PDG code"}; - // Generated - MC_truth_reg.add("histGenVtxMC", "MC generated vertex z position", HistType::kTH1F, {{400, -40., +40., "z position (cm)"}}); - MC_truth_reg.add("histCentrality", "Impact parameter", HistType::kTH1F, {centralityAxis_extended}); - MC_truth_reg.add("hist_gen_p", "generated p distribution", HistType::kTH2F, {pAxis, PDGBINNING}); - MC_truth_reg.add("hist_gen_pT", "generated p_{T} distribution", HistType::kTH2F, {ptAxis, PDGBINNING}); - 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("histRapid", "#gamma", HistType::kTH2F, {{1000, -5.0, 5.0}, PDGBINNING}); - // Centrality - MC_truth_reg_cent.add("hist_gen_p_cent", "generated p distribution vs impact param", HistType::kTH3F, {pAxis, PDGBINNING, ImPaAxis}); - MC_truth_reg_cent.add("hist_gen_pT_cent", "generated p_{T} distribution vs impact param", HistType::kTH3F, {ptAxis, PDGBINNING, ImPaAxis}); - - // Reconstructed + // *********************** 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_extended}); + 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}); @@ -82,334 +101,474 @@ struct NucleiEfficiencyTask { 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}); - // Centrality - MC_recon_reg_cent.add("hist_rec_ITS_vs_p_cent", "ITS reconstructed p distribution vs centrality", HistType::kTH3F, {pAxis, PDGBINNING, centAxis}); - MC_recon_reg_cent.add("hist_rec_ITS_TPC_vs_p_cent", "ITS_TPC reconstructed p distribution vs centrality", HistType::kTH3F, {pAxis, PDGBINNING, centAxis}); - MC_recon_reg_cent.add("hist_rec_ITS_TPC_TOF_vs_p_cent", "ITS_TPC_TOF reconstructed p distribution vs centrality", HistType::kTH3F, {pAxis, PDGBINNING, centAxis}); - MC_recon_reg_cent.add("hist_rec_ITS_vs_pT_cent", "ITS reconstructed p_{T} distribution vs centrality", HistType::kTH3F, {ptAxis, PDGBINNING, centAxis}); - MC_recon_reg_cent.add("hist_rec_ITS_TPC_vs_pT_cent", "ITS_TPC reconstructed p_{T} distribution vs centrality", HistType::kTH3F, {ptAxis, PDGBINNING, centAxis}); - MC_recon_reg_cent.add("hist_rec_ITS_TPC_TOF_vs_pT_cent", "ITS_TPC_TOF reconstructed p_{T} distribution vs centrality", HistType::kTH3F, {ptAxis, PDGBINNING, centAxis}); } + // ************************ Configurables *********************** Configurable event_selection_MC_sel8{"event_selection_MC_sel8", true, "Enable sel8 event selection in MC processing"}; - Configurable calc_cent{"calc_cent", false, "Enable centrality processing"}; - Configurable y_cut_MC_gen{"y_cut_MC_gen", true, "Enable rapidity cut for generated MC"}; - 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 yMin_gen{"yMin_gen", -0.5, "Maximum rapidity (generated)"}; - Configurable yMax_gen{"yMax_gen", 0.5, "Minimum rapidity (generated)"}; + 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.9f, "Eta range for tracks"}; - Configurable yMin_reco{"yMin_reco", -0.5, "Maximum rapidity (reconstructed)"}; - Configurable yMax_reco{"yMax_reco", 0.5, "Minimum rapidity (reconstructed)"}; - Configurable pmin_reco{"pmin_reco", 0.1f, "min p (reconstructed)"}; - Configurable pmax_reco{"pmax_reco", 1e+10f, "max p (reconstructed)"}; - Configurable pTmin_reco{"pTmin_reco", 0.1f, "min pT (reconstructed)"}; - Configurable pTmax_reco{"pTmax_reco", 1e+10f, "max pT (reconstructed)"}; + 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", 1.5f, "max ratio of crossed rows over findable clusters TPC"}; - 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 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"}; - template - void process_MC_gen(const McCollisionType& mcCollision, const McParticlesType& mcParticles) - { - MC_truth_reg.fill(HIST("histGenVtxMC"), mcCollision.posZ()); - MC_truth_reg.fill(HIST("histCentrality"), mcCollision.impactParameter()); + 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"}; - for (const auto& MCparticle : mcParticles) { - if (!MCparticle.isPhysicalPrimary()) - continue; - if ((MCparticle.y() > yMax_gen || MCparticle.y() < yMin_gen) && y_cut_MC_gen) - continue; - if ((TMath::Abs(MCparticle.eta()) > cfgCutEta) && eta_cut_MC_gen) - continue; + 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"}; - int pdgbin = 0; - switch (MCparticle.pdgCode()) { - case +211: - histPDG_mctruth->AddBinContent(1); - pdgbin = 0; - break; - case -211: - histPDG_mctruth->AddBinContent(2); - pdgbin = 1; - break; - case +321: - histPDG_mctruth->AddBinContent(3); - pdgbin = 2; - break; - case -321: - histPDG_mctruth->AddBinContent(4); - pdgbin = 3; - break; - case +2212: - histPDG_mctruth->AddBinContent(5); - pdgbin = 4; - break; - case -2212: - histPDG_mctruth->AddBinContent(6); - pdgbin = 5; - break; - case +1000010020: - histPDG_mctruth->AddBinContent(7); - pdgbin = 6; - break; - case -1000010020: - histPDG_mctruth->AddBinContent(8); - pdgbin = 7; - break; - case +1000010030: - histPDG_mctruth->AddBinContent(9); - pdgbin = 8; - break; - case -1000010030: - histPDG_mctruth->AddBinContent(10); - pdgbin = 9; - break; - case +1000020030: - histPDG_mctruth->AddBinContent(11); - pdgbin = 10; - break; - case -1000020030: - histPDG_mctruth->AddBinContent(12); - pdgbin = 11; - break; - case +1000020040: - histPDG_mctruth->AddBinContent(13); - pdgbin = 12; - break; - case -1000020040: - histPDG_mctruth->AddBinContent(14); - pdgbin = 13; - break; - default: - continue; - } + //*********************************************************************************** - MC_truth_reg.fill(HIST("histPhi"), MCparticle.phi(), pdgbin); - MC_truth_reg.fill(HIST("histEta"), MCparticle.eta(), pdgbin); - MC_truth_reg.fill(HIST("histRapid"), MCparticle.y(), pdgbin); - MC_truth_reg.fill(HIST("hist_gen_p"), MCparticle.p(), pdgbin); - MC_truth_reg.fill(HIST("hist_gen_pT"), MCparticle.pt(), pdgbin); + 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; + } - if (calc_cent) { - MC_truth_reg_cent.fill(HIST("hist_gen_p_cent"), MCparticle.p(), pdgbin, mcCollision.impactParameter()); - MC_truth_reg_cent.fill(HIST("hist_gen_pT_cent"), MCparticle.pt(), pdgbin, mcCollision.impactParameter()); - } - } + //*********************************************************************************** + + 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 process_MC_reco(const CollisionType& collision, const TracksType& tracks, const mcParticlesType& /*mcParticles*/) + template + bool isCollisionSelected(const CollType& collision) { if (event_selection_MC_sel8 && !collision.sel8()) - return; - MC_recon_reg.fill(HIST("histRecVtxMC"), collision.posZ()); - MC_recon_reg.fill(HIST("histCentrality"), collision.centFT0C()); + 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; + } - for (auto& track : tracks) { - const auto particle = track.mcParticle(); - if (!particle.isPhysicalPrimary()) - continue; + //*********************************************************************************** - int pdgbin = 0; - switch (particle.pdgCode()) { - case +211: - histPDG->AddBinContent(1); - pdgbin = 0; - break; - case -211: - histPDG->AddBinContent(2); - pdgbin = 1; - break; - case +321: - histPDG->AddBinContent(3); - pdgbin = 2; - break; - case -321: - histPDG->AddBinContent(4); - pdgbin = 3; - break; - case +2212: - histPDG->AddBinContent(5); - pdgbin = 4; - break; - case -2212: - histPDG->AddBinContent(6); - pdgbin = 5; - break; - case +1000010020: - histPDG->AddBinContent(7); - pdgbin = 6; - break; - case -1000010020: - histPDG->AddBinContent(8); - pdgbin = 7; - break; - case +1000010030: - histPDG->AddBinContent(9); - pdgbin = 8; - break; - case -1000010030: - histPDG->AddBinContent(10); - pdgbin = 9; - break; - case +1000020030: - histPDG->AddBinContent(11); - pdgbin = 10; - break; - case -1000020030: - histPDG->AddBinContent(12); - pdgbin = 11; - break; - case +1000020040: - histPDG->AddBinContent(13); - pdgbin = 12; - break; - case -1000020040: - histPDG->AddBinContent(14); - pdgbin = 13; - break; - default: - continue; - } + 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; + } - TLorentzVector lorentzVector_pion{}; - TLorentzVector lorentzVector_kaon{}; - 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_kaon.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); - 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_reco || lorentzVector_pion.Rapidity() > yMax_reco || - lorentzVector_kaon.Rapidity() < yMin_reco || lorentzVector_kaon.Rapidity() > yMax_reco || - lorentzVector_proton.Rapidity() < yMin_reco || lorentzVector_proton.Rapidity() > yMax_reco || - lorentzVector_deuteron.Rapidity() < yMin_reco || lorentzVector_deuteron.Rapidity() > yMax_reco || - lorentzVector_triton.Rapidity() < yMin_reco || lorentzVector_triton.Rapidity() > yMax_reco || - lorentzVector_He3.Rapidity() < yMin_reco || lorentzVector_He3.Rapidity() > yMax_reco || - lorentzVector_He4.Rapidity() < yMin_reco || lorentzVector_He4.Rapidity() > yMax_reco) - continue; + //*********************************************************************************** + 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) { - float TPCnumberClsFound = track.tpcNClsFound(); - float TPC_nCls_Crossed_Rows = track.tpcNClsCrossedRows(); - float RatioCrossedRowsOverFindableTPC = track.tpcCrossedRowsOverFindableCls(); - float Chi2perClusterTPC = track.tpcChi2NCl(); - float Chi2perClusterITS = track.itsChi2NCl(); + const auto groupedCollisions = collisions.sliceBy(collPerCollMc, mcCollision.globalIndex()); + const auto groupedMcParticles = mcParticles.sliceBy(perCollisionMc, mcCollision.globalIndex()); - 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 (groupedCollisions.size() < 1) continue; + float centrality = -1.; - if (use_pT_cut) { - if (track.pt() < pTmin_reco || track.pt() > pTmax_reco) + /// loop over reconstructed collisions + for (const auto& collision : groupedCollisions) { + if (!isCollisionSelected(collision)) continue; - } else { - if (track.p() < pmin_reco || track.p() > pmax_reco) + + centrality = collision.centFT0C(); + if (centrality < minCentrality || centrality > maxCentrality) continue; - } - 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); - } + 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; } - } - } 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); + + 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); + } + } } - } - } - } - if (calc_cent) { - if ((particle.pdgCode() == 1000020030) || (particle.pdgCode() == -1000020030) || (particle.pdgCode() == 1000020040) || (particle.pdgCode() == -1000020040)) { - if (track.hasITS()) { - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_vs_p_cent"), track.p() * 2, pdgbin, collision.centFT0C()); - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_vs_pT_cent"), track.pt() * 2, pdgbin, collision.centFT0C()); - if (track.hasTPC()) { - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_TPC_vs_p_cent"), track.p() * 2, pdgbin, collision.centFT0C()); - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_TPC_vs_pT_cent"), track.pt() * 2, pdgbin, collision.centFT0C()); - if (track.hasTOF()) { - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_TPC_TOF_vs_p_cent"), track.p() * 2, pdgbin, collision.centFT0C()); - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_TPC_TOF_vs_pT_cent"), track.pt() * 2, pdgbin, collision.centFT0C()); + } 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 { - if (track.hasITS()) { - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_vs_p_cent"), track.p(), pdgbin, collision.centFT0C()); - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_vs_pT_cent"), track.pt(), pdgbin, collision.centFT0C()); - if (track.hasTPC()) { - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_TPC_vs_p_cent"), track.p(), pdgbin, collision.centFT0C()); - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_TPC_vs_pT_cent"), track.pt(), pdgbin, collision.centFT0C()); - if (track.hasTOF()) { - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_TPC_TOF_vs_p_cent"), track.p(), pdgbin, collision.centFT0C()); - MC_recon_reg_cent.fill(HIST("hist_rec_ITS_TPC_TOF_vs_pT_cent"), track.pt(), pdgbin, collision.centFT0C()); - } - } + // 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; + } + } - void processMCgen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) - { - process_MC_gen(mcCollision, mcParticles); - } - PROCESS_SWITCH(NucleiEfficiencyTask, processMCgen, "process generated MC", true); + // Loop on particles to fill the denominator + for (const auto& mcParticle : groupedMcParticles) { + if (!isInAcceptance(mcParticle)) + continue; - Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVertex); - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta && requireGlobalTrackWoDCAInFilter()); + 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; + } - void processMCreco(soa::Join::iterator const& collision, - soa::Filtered> const& tracks, - aod::McParticles const& mcParticles) - { - process_MC_reco(collision, tracks, mcParticles); + 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, processMCreco, "process reconstructed MC", false); + PROCESS_SWITCH(NucleiEfficiencyTask, processMC, "process generated MC", true); }; -//**************************************************************************************************** +//*********************************************************************************** WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx b/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx index 8d55234b567..6fa6d572605 100644 --- a/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx +++ b/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx @@ -12,32 +12,48 @@ // Authors: Rafael Manhart, // Date: 30.11.2022 -#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 "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/DataModel/spectraTOF.h" +#include "PWGLF/Utils/inelGt.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" #include "TPDGCode.h" +#include +#include +#include +#include + +#include +#include +#include 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,32 +70,71 @@ 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_recon_reg{"MC_particles_reco", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - OutputObj histPDG{TH1F("PDG", "PDG;PDG code", 20, 0.0, 20.0)}; + 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 pAxis = {ptBinning, "#it{p} (GeV/#it{c})"}; - AxisSpec pAxis_reduced = {ptBinning_short, "#it{p} (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 centralityAxis = {100, 0.0, 105.0, "VT0C (%)"}; AxisSpec etaAxis = {etaBinning, "#eta"}; AxisSpec PDGBINNING = {PDGBinning, "PDG code"}; @@ -87,40 +142,33 @@ struct NucleiHistTask { // 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("histTpcSignalData_pT", "Specific energy loss", HistType::kTH2F, {{600, -6., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - spectra_reg.add("histTofSignalData_pT", "TOF signal", HistType::kTH2F, {{600, -6., 6., "#it{p}_{T} (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 P", HistType::kTH2F, {pAxis, {400, 0.0, 10.0, "m^2"}}); - spectra_reg.add("histTOFm2_pT", "TOF m^2 vs Pt", HistType::kTH2F, {ptAxis, {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("histTpcSignalData_pT", "Specific energy loss (#pi^{+})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - pion_reg.add("histTofSignalData_pT", "TOF signal (#pi^{+})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (#pi^{+})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - pion_reg.add("histTofNsigmaData_pT", "n-sigma TOF (#pi^{+})", HistType::kTH2F, {ptAxis, {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"}}); @@ -134,19 +182,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("histTpcSignalData_pT", "Specific energy loss (#pi^{-})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - apion_reg.add("histTofSignalData_pT", "TOF signal (#pi^{-})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (#pi^{-})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - apion_reg.add("histTofNsigmaData_pT", "n-sigma TOF (#pi^{-})", HistType::kTH2F, {ptAxis, {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"}}); @@ -160,19 +204,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("histTpcSignalData_pT", "Specific energy loss (p)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - proton_reg.add("histTofSignalData_pT", "TOF signal (p)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (p)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - proton_reg.add("histTofNsigmaData_pT", "n-sigma TOF (p)", HistType::kTH2F, {ptAxis, {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"}}); @@ -186,19 +226,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("histTpcSignalData_pT", "Specific energy loss (#bar{p})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - aproton_reg.add("histTofSignalData_pT", "TOF signal (#bar{p})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (#bar{p})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{p}}"}}); - aproton_reg.add("histTofNsigmaData_pT", "n-sigma TOF (#bar{p})", HistType::kTH2F, {ptAxis, {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"}}); @@ -212,19 +248,15 @@ 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("histTpcSignalData_pT", "Specific energy loss (d)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - deuteron_reg.add("histTofSignalData_pT", "TOF signal (d)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (d)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - deuteron_reg.add("histTofNsigmaData_pT", "n-sigma TOF (d)", HistType::kTH2F, {ptAxis, {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"}}); @@ -238,19 +270,15 @@ struct NucleiHistTask { 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("histTpcSignalData_pT", "Specific energy loss (#bar{d})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - adeuteron_reg.add("histTofSignalData_pT", "TOF signal (#bar{d})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (#bar{d})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{d}}"}}); - adeuteron_reg.add("histTofNsigmaData_pT", "n-sigma TOF (#bar{d})", HistType::kTH2F, {ptAxis, {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"}}); @@ -264,19 +292,15 @@ struct NucleiHistTask { 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("histTpcSignalData_pT", "Specific energy loss (t)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - triton_reg.add("histTofSignalData_pT", "TOF signal (t)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (t)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - triton_reg.add("histTofNsigmaData_pT", "n-sigma TOF (t)", HistType::kTH2F, {ptAxis, {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"}}); @@ -290,19 +314,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("histTpcSignalData_pT", "Specific energy loss (#bar{t})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - atriton_reg.add("histTofSignalData_pT", "TOF signal (#bar{t})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (#bar{t})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#bar{t}}"}}); - atriton_reg.add("histTofNsigmaData_pT", "n-sigma TOF (#bar{t})", HistType::kTH2F, {ptAxis, {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"}}); @@ -316,19 +336,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("histTpcSignalData_pT", "Specific energy loss (^{3}He)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - Helium3_reg.add("histTofSignalData_pT", "TOF signal (^{3}He)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (^{3}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); - Helium3_reg.add("histTofNsigmaData_pT", "n-sigma TOF (^{3}He)", HistType::kTH2F, {ptAxis, {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"}}); @@ -342,19 +358,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("histTpcSignalData_pT", "Specific energy loss (^{3}#bar{He})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - aHelium3_reg.add("histTofSignalData_pT", "TOF signal (^{3}#bar{He})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); - aHelium3_reg.add("histTofNsigmaData_pT", "n-sigma TOF (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {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"}}); @@ -368,19 +380,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("histTpcSignalData_pT", "Specific energy loss (^{4}He)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - Helium4_reg.add("histTofSignalData_pT", "TOF signal (^{4}He)", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (^{4}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); - Helium4_reg.add("histTofNsigmaData_pT", "n-sigma TOF (^{4}He)", HistType::kTH2F, {ptAxis, {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"}}); @@ -394,19 +402,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("histTpcSignalData_pT", "Specific energy loss (^{4}#bar{He})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}}); - aHelium4_reg.add("histTofSignalData_pT", "TOF signal (^{4}#bar{He})", HistType::kTH2F, {{600, 0., 6., "#it{p}_{T} (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("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("histTOFm2_pT", "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, {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("histTpcNsigmaData_pT", "n-sigma TPC (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{antiHe-4}"}}); - aHelium4_reg.add("histTofNsigmaData_pT", "n-sigma TOF (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {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"}}); @@ -421,21 +425,24 @@ struct NucleiHistTask { // +++++++++++++++++++++ MC ++++++++++++++++++++++++++ + // 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("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("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("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_pT", "Specific energy loss", HistType::kTH3F, {{600, -6., 6., "#it{p}_{T} (GeV/#it{c})"}, {5000, 0, 5000, "d#it{E} / d#it{X} (a. u.)"}, PDGBINNING}); - MC_recon_reg.add("histTofSignalData_pT", "TOF signal", HistType::kTH3F, {{600, -6., 6., "#it{p}_{T} (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, {pAxis, {400, 0.0, 10.0, "m^2"}, PDGBINNING}); - MC_recon_reg.add("histTOFm2_pT", "TOF m^2 vs Pt", HistType::kTH3F, {ptAxis, {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}); @@ -467,95 +474,127 @@ struct NucleiHistTask { 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_recon_reg.add("histTpcNsigmaDataPi_pT", "TPC nSigma (#pi^{+})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - MC_recon_reg.add("histTpcNsigmaDataaPi_pT", "TPC nSigma (#pi^{-})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - MC_recon_reg.add("histTpcNsigmaDataPr_pT", "TPC nSigma (p)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - MC_recon_reg.add("histTpcNsigmaDataaPr_pT", "TPC nSigma (#bar{p})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - MC_recon_reg.add("histTpcNsigmaDataDe_pT", "TPC nSigma (d)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - MC_recon_reg.add("histTpcNsigmaDataaDe_pT", "TPC nSigma (#bar{d})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - MC_recon_reg.add("histTpcNsigmaDataTr_pT", "TPC nSigma (t)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - MC_recon_reg.add("histTpcNsigmaDataaTr_pT", "TPC nSigma (#bar{t})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - MC_recon_reg.add("histTpcNsigmaDataHe_pT", "TPC nSigma (^{3}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{He-3}"}}); - MC_recon_reg.add("histTpcNsigmaDataaHe_pT", "TPC nSigma (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{He-3}"}}); - MC_recon_reg.add("histTpcNsigmaDataAl_pT", "TPC nSigma (^{4}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{He-4}"}}); - MC_recon_reg.add("histTpcNsigmaDataaAl_pT", "TPC nSigma (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{He-4}"}}); - MC_recon_reg.add("histTofNsigmaDataPi_pT", "TOF nSigma (#pi^{+})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - MC_recon_reg.add("histTofNsigmaDataaPi_pT", "TOF nSigma (#pi^{-})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{#pi^{+}}"}}); - MC_recon_reg.add("histTofNsigmaDataPr_pT", "TOF nSigma (p)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - MC_recon_reg.add("histTofNsigmaDataaPr_pT", "TOF nSigma (#bar{p})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{p}"}}); - MC_recon_reg.add("histTofNsigmaDataDe_pT", "TOF nSigma (d)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - MC_recon_reg.add("histTofNsigmaDataaDe_pT", "TOF nSigma (#bar{d})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{d}"}}); - MC_recon_reg.add("histTofNsigmaDataTr_pT", "TOF nSigma (t)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - MC_recon_reg.add("histTofNsigmaDataaTr_pT", "TOF nSigma (#bar{t})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{t}"}}); - MC_recon_reg.add("histTofNsigmaDataHe_pT", "TOF nSigma (^{3}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); - MC_recon_reg.add("histTofNsigmaDataaHe_pT", "TOF nSigma (^{3}#bar{He})", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{3}He}"}}); - MC_recon_reg.add("histTofNsigmaDataAl_pT", "TOF nSigma (^{4}He)", HistType::kTH2F, {ptAxis, {160, -20., +20., "n#sigma_{^{4}He}"}}); - MC_recon_reg.add("histTofNsigmaDataaAl_pT", "TOF nSigma (^{4}#bar{He})", HistType::kTH2F, {ptAxis, {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.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"}; - Configurable maxCentrality{"maxCentrality", 90.0, "max Centrality used"}; + Configurable maxCentrality{"maxCentrality", 80.0, "max Centrality used"}; Configurable enable_Centrality_cut_global{"enable_Centrality_cut_global", true, "use Centrality cut"}; // Replacement for globalTrack 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 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 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", -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"}; - - template - void fillHistograms(const CollisionType& event, const TracksType& tracks) + 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; + } - 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; + //*********************************************************************************** + template + void fillHistograms_spectra(const CollisionType& event, const TracksType& tracks) + { 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) { + for (auto track : tracks) { // start loop over all tracks + 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()); @@ -565,127 +604,221 @@ struct NucleiHistTask { spectra_reg.fill(HIST("histDcaVsPtData_antiparticle"), track.pt(), track.dcaXY()); spectra_reg.fill(HIST("histDcaZVsPtData_antiparticle"), track.pt(), track.dcaZ()); } - - 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; - - float nSigmaPion = track.tpcNSigmaPi(); - float nSigmaProton = track.tpcNSigmaPr(); - float nSigmaDeut = track.tpcNSigmaDe(); - float nSigmaTriton = track.tpcNSigmaTr(); - float nSigmaHe3 = track.tpcNSigmaHe(); - float nSigmaHe4 = track.tpcNSigmaAl(); - 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 || 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.pt() < pTmin || track.pt() > pTmax) + 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) + continue; + histTrackcuts_data_spectra->AddBinContent(3); + if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC) + continue; + 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.p() * track.sign(), track.tpcSignal()); - spectra_reg.fill(HIST("histTpcSignalData_pT"), track.pt() * track.sign(), track.tpcSignal()); + spectra_reg.fill(HIST("histTpcSignalData"), track.pt() * track.sign(), track.tpcSignal()); + 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.p(), nSigmaPion); - proton_reg.fill(HIST("histTpcNsigmaData"), track.p(), nSigmaProton); - deuteron_reg.fill(HIST("histTpcNsigmaData"), track.p(), nSigmaDeut); - triton_reg.fill(HIST("histTpcNsigmaData"), track.p(), nSigmaTriton); - Helium3_reg.fill(HIST("histTpcNsigmaData"), track.p() * 2.0, nSigmaHe3); - Helium4_reg.fill(HIST("histTpcNsigmaData"), track.p() * 2.0, nSigmaHe4); - pion_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt(), nSigmaPion); - proton_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt(), nSigmaProton); - deuteron_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt(), nSigmaDeut); - triton_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt(), nSigmaTriton); - Helium3_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt() * 2.0, nSigmaHe3); - Helium4_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt() * 2.0, nSigmaHe4); + //*********************************************************************************** - 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())); - spectra_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2); - spectra_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - } + template + void fillHistograms_particle(const CollisionType& event, const TracksType& tracks, const int Partilce_type) + { + + if (!isEventSelected(event)) + return; + + 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.p(), nSigmaPion); - aproton_reg.fill(HIST("histTpcNsigmaData"), track.p(), nSigmaProton); - adeuteron_reg.fill(HIST("histTpcNsigmaData"), track.p(), nSigmaDeut); - atriton_reg.fill(HIST("histTpcNsigmaData"), track.p(), nSigmaTriton); - aHelium3_reg.fill(HIST("histTpcNsigmaData"), track.p() * 2.0, nSigmaHe3); - aHelium4_reg.fill(HIST("histTpcNsigmaData"), track.p() * 2.0, nSigmaHe4); - apion_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt(), nSigmaPion); - aproton_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt(), nSigmaProton); - adeuteron_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt(), nSigmaDeut); - atriton_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt(), nSigmaTriton); - aHelium3_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt() * 2.0, nSigmaHe3); - aHelium4_reg.fill(HIST("histTpcNsigmaData_pT"), track.pt() * 2.0, nSigmaHe4); + if (enable_pT_shift_tpc_nSigma) { + float nSigma_shift = Particle_Tpc_nSigma_shift->Eval(momentum); + TPCnSigma_particle -= nSigma_shift; + } - 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())); - spectra_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2); - spectra_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); + histTrackcuts_data_particle->AddBinContent(1); + if (event_selection_sel8 && !event.sel8()) + continue; + histTrackcuts_data_particle->AddBinContent(2); + + 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; + + 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()); } } - //************** Pion ******************* + bool insideDCAxy = (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(momentum, 1.1f)))); + + if (!(insideDCAxy) || TMath::Abs(track.dcaZ()) > maxDCA_Z) + continue; + histTrackcuts_data_particle->AddBinContent(13); + + //******* Fill particle histograms *********** + if (track.sign() > 0) { + particle_reg.fill(HIST("histTpcNsigmaData"), momentum, TPCnSigma_particle); + } + + if (track.sign() < 0) { + aparticle_reg.fill(HIST("histTpcNsigmaData"), momentum, TPCnSigma_particle); + } - if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh) { + if (TPCnSigma_particle > nsigmacutLow && TPCnSigma_particle < nsigmacutHigh) { if (track.sign() > 0) { - keepEvent_pi = kTRUE; - pion_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - pion_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - pion_reg.fill(HIST("histTpcSignalData"), track.p(), track.tpcSignal()); - pion_reg.fill(HIST("histTpcSignalData_pT"), 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()); + 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)) { @@ -701,26 +834,21 @@ struct NucleiHistTask { } Float_t TOFmass2 = ((track.mass()) * (track.mass())); Float_t beta = track.beta(); - pion_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2); - pion_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - pion_reg.fill(HIST("histTofSignalData"), track.p(), beta); - pion_reg.fill(HIST("histTofSignalData_pT"), track.pt(), beta); - pion_reg.fill(HIST("histTofNsigmaData"), track.p(), track.tofNSigmaPi()); - pion_reg.fill(HIST("histTofNsigmaData_pT"), 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 (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.p(), track.tpcSignal()); - apion_reg.fill(HIST("histTpcSignalData_pT"), 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)) { @@ -736,14 +864,148 @@ struct NucleiHistTask { } Float_t TOFmass2 = ((track.mass()) * (track.mass())); Float_t beta = track.beta(); - apion_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2); - apion_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - apion_reg.fill(HIST("histTofSignalData"), track.p(), beta); - apion_reg.fill(HIST("histTofSignalData_pT"), track.pt(), beta); - apion_reg.fill(HIST("histTofNsigmaData"), track.p(), track.tofNSigmaPi()); - apion_reg.fill(HIST("histTofNsigmaData_pT"), 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); } } + } + } + } + + //*********************************************************************************** + + template + void fillHistograms_particle_cent(const CollisionType& event, const TracksType& tracks, const int Partilce_type) + { + if (!isEventSelected(event)) + return; + + 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]); + } + + if (event_selection_sel8 && event.sel8()) + spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); + if (!event_selection_sel8) + spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); + + for (auto track : tracks) { + if ((event_selection_sel8 && !event.sel8()) || (enable_Centrality_cut_global && (event.centFT0C() < minCentrality) && (event.centFT0C() > maxCentrality))) + continue; + + 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 (enable_pT_shift_tpc_nSigma) { + float nSigma_shift = Particle_Tpc_nSigma_shift->Eval(momentum); + TPCnSigma_particle -= nSigma_shift; + } + + spectra_reg.fill(HIST("histEtaWithOverFlow"), track.eta()); + spectra_reg.fill(HIST("histEta_cent"), event.centFT0C(), track.eta()); + + if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { + spectra_reg.fill(HIST("histEta"), track.eta()); + } + + 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; + + bool insideDCAxy = (std::abs(track.dcaXY()) <= (maxDcaXYFactor.value * (0.0105f + 0.0350f / pow(momentum, 1.1f)))); + + 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.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.hasTOF()) { if (track.hasTRD() && (lastRequiredTrdCluster > 0)) { @@ -757,83 +1019,19 @@ struct NucleiHistTask { if (lastLayer < lastRequiredTrdCluster) continue; } - spectra_reg.fill(HIST("histTofSignalData"), track.p() * track.sign(), track.beta()); - spectra_reg.fill(HIST("histTofSignalData_pT"), track.pt() * track.sign(), track.beta()); - } - } - - //************** Proton ******************* + particle_reg.fill(HIST("histTofNsigmaData_cent"), momentum, TOFnSigma_particle, event.centFT0C()); + particle_reg.fill(HIST("histTofm2_cent"), momentum, track.mass() * track.mass(), event.centFT0C()); - if (nSigmaProton > nsigmacutLow && nSigmaProton < nsigmacutHigh) { - - 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.p(), track.tpcSignal()); - proton_reg.fill(HIST("histTpcSignalData_pT"), 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()); - - 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(); - proton_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2); - proton_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - proton_reg.fill(HIST("histTofSignalData"), track.p(), beta); - proton_reg.fill(HIST("histTofSignalData_pT"), track.pt(), beta); - proton_reg.fill(HIST("histTofNsigmaData"), track.p(), track.tofNSigmaPr()); - proton_reg.fill(HIST("histTofNsigmaData_pT"), 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) { - keepEvent_antip = kTRUE; - aproton_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - aproton_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - aproton_reg.fill(HIST("histTpcSignalData"), track.p(), track.tpcSignal()); - aproton_reg.fill(HIST("histTpcSignalData_pT"), 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 (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(); - aproton_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2); - aproton_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - aproton_reg.fill(HIST("histTofSignalData"), track.p(), beta); - aproton_reg.fill(HIST("histTofSignalData_pT"), track.pt(), beta); - aproton_reg.fill(HIST("histTofNsigmaData"), track.p(), track.tofNSigmaPr()); - aproton_reg.fill(HIST("histTofNsigmaData_pT"), track.pt(), track.tofNSigmaPr()); - } + } + 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()) { @@ -848,571 +1046,19 @@ struct NucleiHistTask { if (lastLayer < lastRequiredTrdCluster) continue; } - spectra_reg.fill(HIST("histTofSignalData"), track.p() * track.sign(), track.beta()); - spectra_reg.fill(HIST("histTofSignalData_pT"), track.pt() * track.sign(), track.beta()); - } - } - - //************** Deuteron ******************* - - if (nSigmaDeut > nsigmacutLow && nSigmaDeut < nsigmacutHigh) { - - if (track.sign() > 0) { - keepEvent_d = kTRUE; - deuteron_reg.fill(HIST("histDcaVsPtData"), track.pt(), track.dcaXY()); - deuteron_reg.fill(HIST("histDcaZVsPtData"), track.pt(), track.dcaZ()); - deuteron_reg.fill(HIST("histTpcSignalData"), track.p(), track.tpcSignal()); - deuteron_reg.fill(HIST("histTpcSignalData_pT"), 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()); - - 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(); - deuteron_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2); - deuteron_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - deuteron_reg.fill(HIST("histTofSignalData"), track.p(), beta); - deuteron_reg.fill(HIST("histTofSignalData_pT"), track.pt(), beta); - deuteron_reg.fill(HIST("histTofNsigmaData"), track.p(), track.tofNSigmaDe()); - deuteron_reg.fill(HIST("histTofNsigmaData_pT"), track.pt(), track.tofNSigmaDe()); - } - } - - 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.p(), track.tpcSignal()); - adeuteron_reg.fill(HIST("histTpcSignalData_pT"), 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.p(), TOFmass2); - adeuteron_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - adeuteron_reg.fill(HIST("histTofSignalData"), track.p(), beta); - adeuteron_reg.fill(HIST("histTofSignalData_pT"), track.pt(), beta); - adeuteron_reg.fill(HIST("histTofNsigmaData"), track.p(), track.tofNSigmaDe()); - adeuteron_reg.fill(HIST("histTofNsigmaData_pT"), 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.p() * track.sign(), track.beta()); - spectra_reg.fill(HIST("histTofSignalData_pT"), track.pt() * track.sign(), track.beta()); - } - } - - //************** Triton ******************* - - if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh) { - - 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.p(), track.tpcSignal()); - triton_reg.fill(HIST("histTpcSignalData_pT"), 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.p(), TOFmass2); - triton_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - triton_reg.fill(HIST("histTofSignalData"), track.p(), beta); - triton_reg.fill(HIST("histTofSignalData_pT"), track.pt(), beta); - triton_reg.fill(HIST("histTofNsigmaData"), track.p(), track.tofNSigmaTr()); - triton_reg.fill(HIST("histTofNsigmaData_pT"), track.pt(), track.tofNSigmaTr()); - } - } - - 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.p(), track.tpcSignal()); - atriton_reg.fill(HIST("histTpcSignalData_pT"), 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()) { - 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(); - atriton_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2); - atriton_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2); - atriton_reg.fill(HIST("histTofSignalData"), track.p(), beta); - atriton_reg.fill(HIST("histTofSignalData_pT"), track.pt(), beta); - atriton_reg.fill(HIST("histTofNsigmaData"), track.p(), track.tofNSigmaTr()); - atriton_reg.fill(HIST("histTofNsigmaData_pT"), track.pt(), track.tofNSigmaTr()); - } - } - - 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.p() * track.sign(), track.beta()); - spectra_reg.fill(HIST("histTofSignalData_pT"), track.pt() * track.sign(), track.beta()); - } - } - - //************** Helium-3 ******************* - - if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh) { - - 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.p() * 2.0, track.tpcSignal()); - Helium3_reg.fill(HIST("histTpcSignalData_pT"), 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.p() * 2.0, TOFmass2); - Helium3_reg.fill(HIST("histTOFm2_pT"), track.pt() * 2.0, TOFmass2); - Helium3_reg.fill(HIST("histTofSignalData"), track.p() * 2.0, beta); - Helium3_reg.fill(HIST("histTofSignalData_pT"), track.pt() * 2.0, beta); - Helium3_reg.fill(HIST("histTofNsigmaData"), track.p() * 2.0, track.tofNSigmaHe()); - Helium3_reg.fill(HIST("histTofNsigmaData_pT"), track.pt() * 2.0, track.tofNSigmaHe()); - } - } - - 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.p() * 2.0, track.tpcSignal()); - aHelium3_reg.fill(HIST("histTpcSignalData_pT"), 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.p() * 2.0, TOFmass2); - aHelium3_reg.fill(HIST("histTOFm2_pT"), track.pt() * 2.0, TOFmass2); - aHelium3_reg.fill(HIST("histTofSignalData"), track.p() * 2.0, beta); - aHelium3_reg.fill(HIST("histTofSignalData_pT"), track.pt() * 2.0, beta); - aHelium3_reg.fill(HIST("histTofNsigmaData"), track.p() * 2.0, track.tofNSigmaHe()); - aHelium3_reg.fill(HIST("histTofNsigmaData_pT"), 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.p() * 2.0 * track.sign(), track.beta()); - spectra_reg.fill(HIST("histTofSignalData_pT"), track.pt() * 2.0 * track.sign(), track.beta()); - } - } - - //************** Helium-4 ******************* - - if (nSigmaHe4 > nsigmacutLow && nSigmaHe4 < nsigmacutHigh) { - - 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.p() * 2.0, track.tpcSignal()); - Helium4_reg.fill(HIST("histTpcSignalData_pT"), 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.p() * 2.0, TOFmass2); - Helium4_reg.fill(HIST("histTOFm2_pT"), track.pt() * 2.0, TOFmass2); - Helium4_reg.fill(HIST("histTofSignalData"), track.p() * 2.0, beta); - Helium4_reg.fill(HIST("histTofSignalData_pT"), track.pt() * 2.0, beta); - Helium4_reg.fill(HIST("histTofNsigmaData"), track.p() * 2.0, track.tofNSigmaAl()); - Helium4_reg.fill(HIST("histTofNsigmaData_pT"), track.pt() * 2.0, track.tofNSigmaAl()); - } - } - - 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.p() * 2.0, track.tpcSignal()); - aHelium4_reg.fill(HIST("histTpcSignalData_pT"), 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.p() * 2.0, TOFmass2); - aHelium4_reg.fill(HIST("histTOFm2_pT"), track.pt() * 2.0, TOFmass2); - aHelium4_reg.fill(HIST("histTofSignalData"), track.p() * 2.0, beta); - aHelium4_reg.fill(HIST("histTofSignalData_pT"), track.pt() * 2.0, beta); - aHelium4_reg.fill(HIST("histTofNsigmaData"), track.p() * 2.0, track.tofNSigmaAl()); - aHelium4_reg.fill(HIST("histTofNsigmaData_pT"), 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.p() * 2.0 * track.sign(), track.beta()); - spectra_reg.fill(HIST("histTofSignalData_pT"), track.pt() * 2.0 * track.sign(), track.beta()); - } - } - } - - 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); - } - - //**************************************************************************************************** - - template - void fillCentHistorgrams(const CollisionType& event, const TracksType& tracks) - { - - if (event_selection_sel8 && event.sel8()) - spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); - if (!event_selection_sel8) - spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); - - for (auto track : tracks) { - - if ((event_selection_sel8 && !event.sel8()) || (enable_Centrality_cut_global && (event.centFT0C() < minCentrality) && (event.centFT0C() > maxCentrality))) - continue; - - spectra_reg.fill(HIST("histEtaWithOverFlow"), track.eta()); - spectra_reg.fill(HIST("histEta_cent"), event.centFT0C(), track.eta()); - - if ((event.centFT0C() > minCentrality) && (event.centFT0C() < maxCentrality)) { - spectra_reg.fill(HIST("histEta"), track.eta()); - } - - 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; - - 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; - - 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()); + aparticle_reg.fill(HIST("histTofNsigmaData_cent"), momentum, TOFnSigma_particle, event.centFT0C()); + aparticle_reg.fill(HIST("histTofm2_cent"), momentum, 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()); + aparticle_reg.fill(HIST("histTofm2_eta"), momentum, track.mass() * track.mass(), track.eta()); + aparticle_reg.fill(HIST("histTofNsigmaData_eta"), momentum, TOFnSigma_particle, track.eta()); } } } } } - //**************************************************************************************************** + //*********************************************************************************** Filter collisionFilter = (nabs(aod::collision::posZ) < cfgCutVertex); Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta && requireGlobalTrackWoDCAInFilter()); @@ -1425,118 +1071,271 @@ struct NucleiHistTask { void processData(EventCandidates::iterator const& event, TrackCandidates const& tracks) { - fillHistograms(event, 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); void processDataCent(EventCandidatesCent::iterator const& event, TrackCandidates const& tracks) { - fillHistograms(event, tracks); - fillCentHistorgrams(event, 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); - void processMC(soa::Join::iterator const& collisions, soa::Filtered> const& tracks, - aod::McParticles& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + //********************** MC **************************************** + + 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()); + + for (const auto& mcParticleGen : mcParticles) { + if (require_PhysicalPrimary_MC_gen && !mcParticleGen.isPhysicalPrimary()) + continue; + int pdgCode = mcParticleGen.pdgCode(); + + if (mcParticleGen.y() > yMax || mcParticleGen.y() < yMin) + continue; + if (mcParticleGen.eta() > cfgCutEta || mcParticleGen.eta() < -cfgCutEta) + continue; + + 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; + } + 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); + } + } + } + PROCESS_SWITCH(NucleiHistTask, processMCgen, "process generated MC", false); + + void processMCreco(soa::Join::iterator const& collisions, soa::Filtered> const& tracks, + aod::McParticles& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) { 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 (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) { + histTrackcuts_MC->AddBinContent(1); const auto particle = track.mcParticle(); - if (!particle.isPhysicalPrimary()) - continue; int pdgbin = 0; + TLorentzVector lorentzVector_particle_MC{}; switch (particle.pdgCode()) { case +211: - histPDG->AddBinContent(1); pdgbin = 0; + histPDG_reco->AddBinContent(1); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); break; case -211: - histPDG->AddBinContent(2); pdgbin = 1; + histPDG_reco->AddBinContent(2); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); break; case +321: - histPDG->AddBinContent(3); pdgbin = 2; + histPDG_reco->AddBinContent(3); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); break; case -321: - histPDG->AddBinContent(4); pdgbin = 3; + histPDG_reco->AddBinContent(4); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); break; case +2212: - histPDG->AddBinContent(5); pdgbin = 4; + histPDG_reco->AddBinContent(5); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); break; case -2212: - histPDG->AddBinContent(6); pdgbin = 5; + histPDG_reco->AddBinContent(6); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); break; case +1000010020: - histPDG->AddBinContent(7); pdgbin = 6; + histPDG_reco->AddBinContent(7); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); break; case -1000010020: - histPDG->AddBinContent(8); pdgbin = 7; + histPDG_reco->AddBinContent(8); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); break; case +1000010030: - histPDG->AddBinContent(9); pdgbin = 8; + histPDG_reco->AddBinContent(9); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); break; case -1000010030: - histPDG->AddBinContent(10); pdgbin = 9; + histPDG_reco->AddBinContent(10); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); break; case +1000020030: - histPDG->AddBinContent(11); pdgbin = 10; + histPDG_reco->AddBinContent(11); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); break; case -1000020030: - histPDG->AddBinContent(12); pdgbin = 11; + histPDG_reco->AddBinContent(12); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassHelium3); break; case +1000020040: - histPDG->AddBinContent(13); pdgbin = 12; + histPDG_reco->AddBinContent(13); + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt() * 2.0, track.eta(), track.phi(), constants::physics::MassAlpha); break; case -1000020040: - histPDG->AddBinContent(14); 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; } - TLorentzVector lorentzVector_pion{}; - TLorentzVector lorentzVector_kaon{}; - 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_kaon.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); - 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_kaon.Rapidity() < yMin || lorentzVector_kaon.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) + if (require_PhysicalPrimary_MC_reco && !particle.isPhysicalPrimary()) + continue; + histTrackcuts_MC->AddBinContent(2); + + if (lorentzVector_particle_MC.Rapidity() < yMin || lorentzVector_particle_MC.Rapidity() > yMax) continue; + histTrackcuts_MC->AddBinContent(3); MC_recon_reg.fill(HIST("histEta"), track.eta(), pdgbin); @@ -1544,8 +1343,7 @@ struct NucleiHistTask { 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.p() * 2.0 * track.sign(), track.tpcSignal(), pdgbin); - MC_recon_reg.fill(HIST("histTpcSignalData_pT"), track.pt() * 2.0 * track.sign(), track.tpcSignal(), 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); @@ -1557,8 +1355,7 @@ struct NucleiHistTask { 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.p() * track.sign(), track.tpcSignal(), pdgbin); - MC_recon_reg.fill(HIST("histTpcSignalData_pT"), track.pt() * track.sign(), track.tpcSignal(), 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); @@ -1574,8 +1371,38 @@ struct NucleiHistTask { 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) + 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) + continue; + histTrackcuts_MC->AddBinContent(4); + if (TPCnumberClsFound < minTPCnClsFound || TPC_nCls_Crossed_Rows < minNCrossedRowsTPC) + continue; + histTrackcuts_MC->AddBinContent(5); + if (RatioCrossedRowsOverFindableTPC < minRatioCrossedRowsTPC || RatioCrossedRowsOverFindableTPC > maxRatioCrossedRowsTPC) + continue; + 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(); @@ -1584,91 +1411,225 @@ 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.p(), nSigmaPion); - MC_recon_reg.fill(HIST("histTpcNsigmaDataPr"), track.p(), nSigmaProton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataDe"), track.p(), nSigmaDeuteron); - MC_recon_reg.fill(HIST("histTpcNsigmaDataTr"), track.p(), nSigmaTriton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataHe"), track.p() * 2.0, nSigmaHe3); - MC_recon_reg.fill(HIST("histTpcNsigmaDataAl"), track.p() * 2.0, nSigmaHe4); - MC_recon_reg.fill(HIST("histTpcNsigmaDataPi_pT"), track.pt(), nSigmaPion); - MC_recon_reg.fill(HIST("histTpcNsigmaDataPr_pT"), track.pt(), nSigmaProton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataDe_pT"), track.pt(), nSigmaDeuteron); - MC_recon_reg.fill(HIST("histTpcNsigmaDataTr_pT"), track.pt(), nSigmaTriton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataHe_pT"), track.pt() * 2.0, nSigmaHe3); - MC_recon_reg.fill(HIST("histTpcNsigmaDataAl_pT"), track.pt() * 2.0, nSigmaHe4); + 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() * 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.p(), nSigmaPion); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaPr"), track.p(), nSigmaProton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaDe"), track.p(), nSigmaDeuteron); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaTr"), track.p(), nSigmaTriton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaHe"), track.p() * 2.0, nSigmaHe3); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaAl"), track.p() * 2.0, nSigmaHe4); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaPi_pT"), track.pt(), nSigmaPion); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaPr_pT"), track.pt(), nSigmaProton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaDe_pT"), track.pt(), nSigmaDeuteron); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaTr_pT"), track.pt(), nSigmaTriton); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaHe_pT"), track.pt() * 2.0, nSigmaHe3); - MC_recon_reg.fill(HIST("histTpcNsigmaDataaAl_pT"), track.pt() * 2.0, nSigmaHe4); + 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() * 2.0, nSigmaHe3); + MC_recon_reg.fill(HIST("histTpcNsigmaDataaAl"), track.pt() * 2.0, nSigmaHe4); } if (track.hasTOF()) { Float_t TOFmass2 = ((track.mass()) * (track.mass())); - MC_recon_reg.fill(HIST("histTOFm2"), track.p(), TOFmass2, pdgbin); - MC_recon_reg.fill(HIST("histTOFm2_pT"), track.pt(), TOFmass2, pdgbin); - MC_recon_reg.fill(HIST("histTofSignalData"), track.p() * track.sign(), track.beta(), pdgbin); - MC_recon_reg.fill(HIST("histTofSignalData_pT"), track.pt() * track.sign(), track.beta(), pdgbin); + 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()); if (track.sign() > 0) { if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataPi"), track.p(), track.tofNSigmaPi()); - MC_recon_reg.fill(HIST("histTofNsigmaDataPi_pT"), track.pt(), track.tofNSigmaPi()); + MC_recon_reg.fill(HIST("histTofNsigmaDataPi"), track.pt(), track.tofNSigmaPi()); if (nSigmaProton > nsigmacutLow && nSigmaProton < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataPr"), track.p(), track.tofNSigmaPr()); - MC_recon_reg.fill(HIST("histTofNsigmaDataPr_pT"), track.pt(), track.tofNSigmaPr()); + MC_recon_reg.fill(HIST("histTofNsigmaDataPr"), track.pt(), track.tofNSigmaPr()); if (nSigmaDeuteron > nsigmacutLow && nSigmaDeuteron < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataDe"), track.p(), track.tofNSigmaDe()); - MC_recon_reg.fill(HIST("histTofNsigmaDataDe_pT"), track.pt(), track.tofNSigmaDe()); + MC_recon_reg.fill(HIST("histTofNsigmaDataDe"), track.pt(), track.tofNSigmaDe()); if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataTr"), track.p(), track.tofNSigmaTr()); - MC_recon_reg.fill(HIST("histTofNsigmaDataTr_pT"), track.pt(), track.tofNSigmaTr()); + MC_recon_reg.fill(HIST("histTofNsigmaDataTr"), track.pt(), track.tofNSigmaTr()); if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataHe"), track.p() * 2.0, track.tofNSigmaHe()); - MC_recon_reg.fill(HIST("histTofNsigmaDataHe_pT"), track.pt() * 2.0, 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.p() * 2.0, track.tofNSigmaAl()); - MC_recon_reg.fill(HIST("histTofNsigmaDataAl_pT"), track.pt() * 2.0, track.tofNSigmaAl()); + MC_recon_reg.fill(HIST("histTofNsigmaDataAl"), track.pt() * 2.0, track.tofNSigmaAl()); } if (track.sign() < 0) { if (nSigmaPion > nsigmacutLow && nSigmaPion < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataaPi"), track.p(), track.tofNSigmaPi()); - MC_recon_reg.fill(HIST("histTofNsigmaDataaPi_pT"), track.pt(), track.tofNSigmaPi()); + MC_recon_reg.fill(HIST("histTofNsigmaDataaPi"), track.pt(), track.tofNSigmaPi()); if (nSigmaProton > nsigmacutLow && nSigmaProton < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataaPr"), track.p(), track.tofNSigmaPr()); - MC_recon_reg.fill(HIST("histTofNsigmaDataaPr_pT"), track.pt(), track.tofNSigmaPr()); + MC_recon_reg.fill(HIST("histTofNsigmaDataaPr"), track.pt(), track.tofNSigmaPr()); if (nSigmaDeuteron > nsigmacutLow && nSigmaDeuteron < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataaDe"), track.p(), track.tofNSigmaDe()); - MC_recon_reg.fill(HIST("histTofNsigmaDataaDe_pT"), track.pt(), track.tofNSigmaDe()); + MC_recon_reg.fill(HIST("histTofNsigmaDataaDe"), track.pt(), track.tofNSigmaDe()); if (nSigmaTriton > nsigmacutLow && nSigmaTriton < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataaTr"), track.p(), track.tofNSigmaTr()); - MC_recon_reg.fill(HIST("histTofNsigmaDataaTr_pT"), track.pt(), track.tofNSigmaTr()); + MC_recon_reg.fill(HIST("histTofNsigmaDataaTr"), track.pt(), track.tofNSigmaTr()); if (nSigmaHe3 > nsigmacutLow && nSigmaHe3 < nsigmacutHigh) - MC_recon_reg.fill(HIST("histTofNsigmaDataaHe"), track.p() * 2.0, track.tofNSigmaHe()); - MC_recon_reg.fill(HIST("histTofNsigmaDataaHe_pT"), track.pt() * 2.0, 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.p() * 2.0, track.tofNSigmaAl()); - MC_recon_reg.fill(HIST("histTofNsigmaDataaAl_pT"), track.pt() * 2.0, track.tofNSigmaAl()); + MC_recon_reg.fill(HIST("histTofNsigmaDataaAl"), track.pt() * 2.0, track.tofNSigmaAl()); + } + } + } + } + PROCESS_SWITCH(NucleiHistTask, processMCreco, "process reconstructed MC", false); + + 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(); + + 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) + 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_DCA.fill(HIST("histEta"), track.eta(), pdgbin); + + 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); + } + } 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, processMC, "process MC", false); + PROCESS_SWITCH(NucleiHistTask, processMCdca, "process MC DCA", false); }; -//**************************************************************************************************** +//*********************************************************************************** WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Nuspex/QAHistTask.cxx b/PWGLF/Tasks/Nuspex/QAHistTask.cxx index 40318c18ca9..02a88f8f210 100644 --- a/PWGLF/Tasks/Nuspex/QAHistTask.cxx +++ b/PWGLF/Tasks/Nuspex/QAHistTask.cxx @@ -12,28 +12,30 @@ // Authors: Rafael Manhart, // Date: 05.10.2023 -#include -#include -#include -#include - -#include "ReconstructionDataFormats/Track.h" - -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + #include "TPDGCode.h" #include -#include "Framework/runDataProcessing.h" +#include +#include +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -44,33 +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 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{TH1D("PDG", "PDG;PDG code", 20, 0.0, 20.0)}; + 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.}; @@ -129,60 +131,60 @@ 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 ++++++++++++++++++++++++++ @@ -223,13 +225,13 @@ struct QAHistTask { } // 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"}; @@ -266,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()) { @@ -279,28 +306,63 @@ struct QAHistTask { QA_reg.fill(HIST("histRecVtxZData"), event.posZ()); } - for (auto track : 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; @@ -315,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; @@ -335,44 +396,28 @@ struct QAHistTask { continue; } - 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()); @@ -395,37 +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()); } - 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()) { @@ -444,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()) { @@ -489,8 +534,8 @@ 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()); } } } @@ -511,6 +556,9 @@ struct QAHistTask { QA_reg.fill(HIST("histCentrality"), event.centFT0C()); } + if (!isEventSelected(event)) + return; + for (auto track : tracks) { if (event_selection_sel8 && !event.sel8()) { @@ -530,33 +578,61 @@ 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*/) { 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(); @@ -582,66 +658,83 @@ struct QAHistTask { } } - int pdgbin = 0; + int pdgbin = -10; + TLorentzVector lorentzVector_particle_MC{}; switch (particle.pdgCode()) { case +211: - histPDG->AddBinContent(1); + histPDG_reco->AddBinContent(1); pdgbin = 0; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); break; case -211: - histPDG->AddBinContent(2); + histPDG_reco->AddBinContent(2); pdgbin = 1; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassPiPlus); break; case +321: - histPDG->AddBinContent(3); + histPDG_reco->AddBinContent(3); pdgbin = 2; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); break; case -321: - histPDG->AddBinContent(4); + histPDG_reco->AddBinContent(4); pdgbin = 3; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassKPlus); break; case +2212: - histPDG->AddBinContent(5); + histPDG_reco->AddBinContent(5); pdgbin = 4; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); break; case -2212: - histPDG->AddBinContent(6); + histPDG_reco->AddBinContent(6); pdgbin = 5; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassProton); break; case +1000010020: - histPDG->AddBinContent(7); + histPDG_reco->AddBinContent(7); pdgbin = 6; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); break; case -1000010020: - histPDG->AddBinContent(8); + histPDG_reco->AddBinContent(8); pdgbin = 7; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassDeuteron); break; case +1000010030: - histPDG->AddBinContent(9); + histPDG_reco->AddBinContent(9); pdgbin = 8; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); break; case -1000010030: - histPDG->AddBinContent(10); + histPDG_reco->AddBinContent(10); pdgbin = 9; + lorentzVector_particle_MC.SetPtEtaPhiM(track.pt(), track.eta(), track.phi(), constants::physics::MassTriton); break; case +1000020030: - histPDG->AddBinContent(11); + 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->AddBinContent(12); + 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->AddBinContent(13); + 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->AddBinContent(14); + 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); @@ -697,7 +790,7 @@ struct QAHistTask { } } } - PROCESS_SWITCH(QAHistTask, processMC, "process MC", false); + PROCESS_SWITCH(QAHistTask, processMCreco, "process MC", false); }; //**************************************************************************************************** diff --git a/PWGLF/Tasks/Nuspex/QCspectraTPC.cxx b/PWGLF/Tasks/Nuspex/QCspectraTPC.cxx index 079b0d44a31..bce49483b33 100644 --- a/PWGLF/Tasks/Nuspex/QCspectraTPC.cxx +++ b/PWGLF/Tasks/Nuspex/QCspectraTPC.cxx @@ -9,22 +9,25 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "Framework/AnalysisTask.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" + #include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "Framework/StaticFor.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/McCollisionExtra.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" #include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + #include "TPDGCode.h" using namespace o2; @@ -496,7 +499,7 @@ struct QCspectraTPC { histos.fill(HIST("MC/pr/neg/prm/pt/numtof"), track.pt(), multiplicity, track.dcaXY()); } } - } // primaries + } // primaries if (!mcParticle.isPhysicalPrimary()) { // secondaries loop start if (mcParticle.pdgCode() == 211) { if (std::abs(mcParticle.y()) > cfgCutY) { diff --git a/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx b/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx new file mode 100644 index 00000000000..30d9b2125d2 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx @@ -0,0 +1,1561 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetUtilities.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "TPDGCode.h" +#include "TVector3.h" + +#include "fastjet/AreaDefinition.hh" +#include "fastjet/ClusterSequenceArea.hh" +#include "fastjet/GhostedAreaSpec.hh" +#include "fastjet/PseudoJet.hh" + +#include +#include +#include +#include +#include +#include + +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 doUECorrelations{"doUECorrelations", false, "measure correlations for p-p, pbar-pbar in cone perp. to jet"}; + Configurable measureKaons{"measureKaons", false, "measure correlations for K-K"}; + Configurable useBkgEstimateForUE{"useBkgEstimateForUE", false, "use bkg density for anti-kt-style clustering in UE"}; + Configurable rejectEvents{"rejectEvents", false, "reject some events"}; + Configurable rejectionPercentage{"rejectionPercentage", 3, "percentage of events to reject"}; + + // 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"}; + + 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 && // some of the track cuts already as filter + 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; // struct for axis specs because at one point there were too many variables for the compiler + + 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; // this block is a remnant from the run2 code adapted here + 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("numberRejectedEvents", "Number of events rejected", HistType::kTH1I, {{2, 0, 2, "counter"}}); + 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 (doUECorrelations) { + registryData.add("deltaPhiSEProtonUE", "#Delta#varphi of UE protons in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEProtonUE", "#Delta#varphi of UE protons in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEProtonUE", "#Delta#varphi vs #Delta#eta of UE protons in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEProtonUE", "#Delta#varphi vs #Delta#eta of UE protons in mixed events", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiSEAntiprotonUE", "#Delta#varphi of UE antiprotons in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEAntiprotonUE", "#Delta#varphi of UE antiprotons in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEAntiprotonUE", "#Delta#varphi vs #Delta#eta of UE antiprotons in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEAntiprotonUE", "#Delta#varphi vs #Delta#eta of UE antiprotons in mixed events", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiSEPionUE", "#Delta#varphi of UE pions in same event", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiMEPionUE", "#Delta#varphi of UE pions in mixed events", HistType::kTH1D, {axisSpecs.angDistPhiAxis}); + registryData.add("deltaPhiEtaSEPionUE", "#Delta#varphi vs #Delta#eta of UE pions in same event", HistType::kTH2D, {axisSpecs.angDistPhiAxis, axisSpecs.angDistEtaAxis}); + registryData.add("deltaPhiEtaMEPionUE", "#Delta#varphi vs #Delta#eta of UE pions 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})"}}); + + registryQC.add("whichUECone", "whichUECone", HistType::kTH1D, {{2, 0, 2, "UE cone"}}); + } + } + + // create track buffers outside processes so the tracks can be stored independently of events for mixed-event distributions + std::vector> fBufferProton; + std::vector> fBufferAntiproton; + std::vector> fBufferPiPlus; + std::vector> fBufferPiMinus; + std::vector> fBufferJet; + std::vector> fBufferFull; + std::vector> fBufferProtonsUE; + std::vector> fBufferAntiprotonsUE; + std::vector> fBufferPiPlusUE; + std::vector> fBufferPiMinusUE; + + template + void initCCDB(Bc const& bc) // remnant from run2 code + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + } + + 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 + } + + 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; + } + + // reject any track that has TPC nsigma < 3 for more than 1 species to avoid ambiguity (not really suitable for the low statistics in jets, thus optional) + template + bool singleSpeciesTPCNSigma(T const& track) + { + 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; + + // set max nsigma depending on pt range + double maxTPCnsigma = protonTPCnsigma; + double maxTOFnsigma = protonTOFnsigma; + if (pt > midPt) { + maxTPCnsigma = protonTPCnsigma - 1; + maxTOFnsigma = protonTOFnsigma - 1; + } + if (pt > highPt) { + maxTPCnsigma = protonTPCnsigma - 2; + maxTOFnsigma = protonTOFnsigma - 2; + } + + // only TPC below 0.7 GeV + 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(); + } + + // require TOF as well above 0.7 GeV + if (pt > protonTPCTOFpT && ((std::abs(tofNSigma) > maxTOFnsigma) || std::abs(track.tpcNSigmaPr()) > maxTPCnsigma)) + return false; + + if (useRejectionCut && !singleSpeciesTPCNSigma(track)) // useRejectionCut false by default + 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; + + // set max nsigma depending on pt range + double maxTPCnsigma = antiprotonTPCnsigma; + double maxTOFnsigma = antiprotonTOFnsigma; + if (pt > midPt) { + maxTPCnsigma = antiprotonTPCnsigma - 1; + maxTOFnsigma = antiprotonTOFnsigma - 1; + } + if (pt > highPt) { + maxTPCnsigma = antiprotonTPCnsigma - 2; + maxTOFnsigma = antiprotonTOFnsigma - 2; + } + + // only TPC below 0.7 GeV + 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(); + } + + // require TOF as well above 0.7 GeV + 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) + { + // looser cuts because it's pions and also because the results aren't used in ToMCCA + // 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) + { + // looser cuts because this was just for the particle-jet pt correlations + // 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) { // loop over angles we collected during same-event correlations + if (static_cast(buffer.size()) == trackBufferSize) { + buffer.insert(buffer.begin(), pair); // insert angles at the beginning + buffer.resize(trackBufferSize); // trim at the end, down to buffer size + } else if (static_cast(buffer.size()) < trackBufferSize) { // buffer not full yet + 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; + } + + // deltaPhi = (difference track 1 to jet axis 1) - (difference track 2 to jet axis 2) + // overlay jet axes from different events to pretend tracks are from same jet + 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; + case 5: + registryData.fill(HIST("deltaPhiMEProtonUE"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEProtonUE"), deltaPhi, deltaEta); + break; + case 6: + registryData.fill(HIST("deltaPhiMEAntiprotonUE"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEAntiprotonUE"), deltaPhi, deltaEta); + break; + case 7: + registryData.fill(HIST("deltaPhiMEPionUE"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaMEPionUE"), 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++) { // loop over SE tracks + if (std::isnan(particleVector.at(i).phi())) + continue; + double phiToAxis = RecoDecay::constrainAngle(particleVector.at(i).phi() - jetAxis.Phi(), 0); // for use in ME function + 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++) { // loop over remaining SE tracks + 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); // dPhi in [-pi/2, 3pi/2] + 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; + case 5: + registryData.fill(HIST("deltaPhiSEProtonUE"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEProtonUE"), deltaPhi, deltaEta); + break; + case 6: + registryData.fill(HIST("deltaPhiSEAntiprotonUE"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEAntiprotonUE"), deltaPhi, deltaEta); + break; + case 7: + registryData.fill(HIST("deltaPhiSEPionUE"), deltaPhi); + registryData.fill(HIST("deltaPhiEtaSEPionUE"), deltaPhi, deltaEta); + break; + } + } // for (int j = i + 1; j < static_cast(particleVector.size()); j++) + fillMixedEventDeltas(particleVector.at(i), buffer, particleType, jetAxis); // do ME distribution of current track vs all tracks in buffer + tempBuffer.emplace_back(std::make_pair(phiToAxis, etaToAxis)); // use pair to maintain phi-eta correlation + } // for (int i = 0; i < static_cast(particleVector.size()); i++) + } + + void doCorrelationsAnti(const auto& particleVector, const auto& particleVectorAnti, const auto& bufferAnti, auto& tempBuffer, const TVector3 jetAxis) // correlations between proton/antiproton - same story as doCorrelations but different track vectors are correlated + { + 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)); + } + } + + 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 without bkg + return jetCounter; + if ((std::fabs(jet.eta()) + jetR) > (maxEta - deltaEtaEdge)) // keep jet away from acceptance edge + 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()); // create jet axis + + if (outputQC) { // for comparison with antinucleiInJets + registryQC.fill(HIST("jetBkgDeltaPt"), jetBkgDeltaPt); + registryQC.fill(HIST("jetPtVsNumPart"), jet.pt(), jet.constituents().size()); + + double maxRadius = 0; // get max distance of a jet track to jet axis + 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 = RecoDecay::constrainAngle(particleDir.Phi() - pJet.Phi(), -constants::math::PI); + double deltaRJet = std::abs(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUE1 = particleDir.Eta() - ueAxis1.Eta(); + double deltaPhiUE1 = RecoDecay::constrainAngle(particleDir.Phi() - ueAxis1.Phi(), -constants::math::PI); + double deltaRUE1 = std::abs(deltaEtaUE1 * deltaEtaUE1 + deltaPhiUE1 * deltaPhiUE1); + double deltaEtaUE2 = particleDir.Eta() - ueAxis2.Eta(); + double deltaPhiUE2 = RecoDecay::constrainAngle(particleDir.Phi() - ueAxis2.Phi(), -constants::math::PI); + double deltaRUE2 = std::abs(deltaEtaUE2 * deltaEtaUE2 + deltaPhiUE2 * deltaPhiUE2); + double failedPhi = -999; + if (deltaRJet < jetR) { + if (deltaPhiJet != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiJet"), deltaEtaJet, deltaPhiJet); + nchJetPlusUE++; + ptJetPlusUE = ptJetPlusUE + track.pt(); + } + if (deltaRUE1 < jetR) { + if (deltaPhiUE1 != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiUE"), deltaEtaUE1, deltaPhiUE1); + nchUE++; + ptUE = ptUE + track.pt(); + } + if (deltaRUE2 < jetR) { + 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 + registryData.fill(HIST("trackProtocol"), 2); + int id = pseudoParticle.user_index(); + const auto& jetParticle = particles.at(id); // get track for corresponding PseudoJet index + 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(); // track recovery from PseudoJet index working properly if this is close to 0 + registryQC.fill(HIST("ptDiff"), ptDiff); + } + + // gather proton/antiproton/pion/kaon in respective vectors + 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) { // correlation of all jet particles + 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); // don't worry about dividing result by 2, the factor will drop out in correlation function + } + int minNumPartForCorrelations = 2; + // need at least 2 tracks in any one list + 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; + std::vector protonsUE; + std::vector antiprotonsUE; + std::vector piPlusUE; + std::vector piMinusUE; + jetProtons.clear(); + jetAntiprotons.clear(); + jetPiPlus.clear(); + jetPiMinus.clear(); + jetAll.clear(); + protonsUE.clear(); + antiprotonsUE.clear(); + piPlusUE.clear(); + piMinusUE.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; // index attached to input PseudoJets + int jetCounter = 0; // how many actual jets in the event + + 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] = jetutilities::estimateRhoPerpCone(jetInput, jets[0], jetR); + + for (const auto& jet : jets) { + // this is where the magic happens + 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 and UE, use hardest jet as orientation + doCorrelations(particlesForCF, fBufferFull, fTempBufferFull, -1, hardestJetAxis); + setTrackBuffer(fTempBufferFull, fBufferFull); + + if (!doUECorrelations) + return; + + // UE correlations + TVector3 ueAxis1(0.0, 0.0, 0.0); + TVector3 ueAxis2(0.0, 0.0, 0.0); + getPerpendicularAxis(hardestJetAxis, ueAxis1, +1.0); + getPerpendicularAxis(hardestJetAxis, ueAxis2, -1.0); + + // untested so far, and the method may need to be rethought, this is the best I could think of + // useBkgEstimateForUE == true tries to somewhat imitate a seeded anti-kt algorithm centred around the perp cone axis + // useBkgEstimateForUE == false simply collects all tracks geometrically, with a hard cut at R + for (const auto& track : tracks) { // try for first cone + double uePt = rhoPerp * constants::math::PI * jetR * jetR; // pt = rho_bkg * area + double trackPt = track.pt(); + if (isProton(track)) { + double geometricDelta = (std::pow(track.phi() - ueAxis1.Phi(), 2) + std::pow(track.eta() - ueAxis1.Eta(), 2)) / (jetR * jetR); + double dij = useBkgEstimateForUE ? std::min(1 / (trackPt * trackPt), 1 / (uePt * uePt)) * geometricDelta : geometricDelta; + double diB = useBkgEstimateForUE ? 1 / (uePt * uePt) : 1; + if (dij < diB) { + protonsUE.emplace_back(track); + if (outputQC) + registryQC.fill(HIST("whichUECone"), 1); // see if track ends up in cone 1 or 2 + } + } else if (isAntiproton(track)) { + double geometricDelta = (std::pow(track.phi() - ueAxis1.Phi(), 2) + std::pow(track.eta() - ueAxis1.Eta(), 2)) / (jetR * jetR); + double dij = useBkgEstimateForUE ? std::min(1 / (trackPt * trackPt), 1 / (uePt * uePt)) * geometricDelta : geometricDelta; + double diB = useBkgEstimateForUE ? 1 / (uePt * uePt) : 1; + if (dij < diB) { + antiprotonsUE.emplace_back(track); + if (outputQC) + registryQC.fill(HIST("whichUECone"), 1); + } + } else if (isPion(track)) { + double geometricDelta = (std::pow(track.phi() - ueAxis1.Phi(), 2) + std::pow(track.eta() - ueAxis1.Eta(), 2)) / (jetR * jetR); + double dij = useBkgEstimateForUE ? std::min(1 / (trackPt * trackPt), 1 / (uePt * uePt)) * geometricDelta : geometricDelta; + double diB = useBkgEstimateForUE ? 1 / (uePt * uePt) : 1; + if (dij < diB) { + track.sign() > 0 ? piPlusUE.emplace_back(track) : piMinusUE.emplace_back(track); + if (outputQC) + registryQC.fill(HIST("whichUECone"), 1); + } + } + } // for (const auto& track : tracks) + + std::vector> fTempBufferProtonUE; + std::vector> fTempBufferAntiprotonUE; + std::vector> fTempBufferPiPlusUE; + std::vector> fTempBufferPiMinusUE; + + doCorrelations(protonsUE, fBufferProtonsUE, fTempBufferProtonUE, 5, ueAxis1); + setTrackBuffer(fTempBufferProtonUE, fBufferProtonsUE); + + doCorrelations(antiprotonsUE, fBufferAntiprotonsUE, fTempBufferAntiprotonUE, 6, ueAxis1); + setTrackBuffer(fTempBufferProtonUE, fBufferAntiprotonsUE); + + doCorrelations(piPlusUE, fBufferPiPlusUE, fTempBufferPiPlusUE, 7, ueAxis1); + setTrackBuffer(fTempBufferProtonUE, fBufferPiPlusUE); + + doCorrelations(piMinusUE, fBufferPiMinusUE, fTempBufferPiMinusUE, 7, ueAxis1); + setTrackBuffer(fTempBufferProtonUE, fBufferPiMinusUE); + + fTempBufferProtonUE.clear(); + fTempBufferAntiprotonUE.clear(); + fTempBufferPiPlusUE.clear(); + fTempBufferPiMinusUE.clear(); + fBufferProtonsUE.clear(); + fBufferAntiprotonsUE.clear(); + fBufferPiPlusUE.clear(); + fBufferPiMinusUE.clear(); + + for (const auto& track : tracks) { // try for second cone + double uePt = rhoPerp * constants::math::PI * jetR * jetR; // pt = rho_bkg * area + double trackPt = track.pt(); + if (isProton(track)) { + double geometricDelta = (std::pow(track.phi() - ueAxis2.Phi(), 2) + std::pow(track.eta() - ueAxis2.Eta(), 2)) / (jetR * jetR); + double dij = useBkgEstimateForUE ? std::min(1 / (trackPt * trackPt), 1 / (uePt * uePt)) * geometricDelta : geometricDelta; + double diB = useBkgEstimateForUE ? 1 / (uePt * uePt) : 1; + if (dij < diB) { + protonsUE.emplace_back(track); + if (outputQC) + registryQC.fill(HIST("whichUECone"), 2); // see if track ends up in cone 1 or 2 + } + } else if (isAntiproton(track)) { + double geometricDelta = (std::pow(track.phi() - ueAxis2.Phi(), 2) + std::pow(track.eta() - ueAxis2.Eta(), 2)) / (jetR * jetR); + double dij = useBkgEstimateForUE ? std::min(1 / (trackPt * trackPt), 1 / (uePt * uePt)) * geometricDelta : geometricDelta; + double diB = useBkgEstimateForUE ? 1 / (uePt * uePt) : 1; + if (dij < diB) { + antiprotonsUE.emplace_back(track); + if (outputQC) + registryQC.fill(HIST("whichUECone"), 2); + } + } else if (isPion(track)) { + double geometricDelta = (std::pow(track.phi() - ueAxis2.Phi(), 2) + std::pow(track.eta() - ueAxis2.Eta(), 2)) / (jetR * jetR); + double dij = useBkgEstimateForUE ? std::min(1 / (trackPt * trackPt), 1 / (uePt * uePt)) * geometricDelta : geometricDelta; + double diB = useBkgEstimateForUE ? 1 / (uePt * uePt) : 1; + if (dij < diB) { + track.sign() > 0 ? piPlusUE.emplace_back(track) : piMinusUE.emplace_back(track); + if (outputQC) + registryQC.fill(HIST("whichUECone"), 2); + } + } + } // for (const auto& track : tracks) + + doCorrelations(protonsUE, fBufferProtonsUE, fTempBufferProtonUE, 5, ueAxis2); + setTrackBuffer(fTempBufferProtonUE, fBufferProtonsUE); + + doCorrelations(antiprotonsUE, fBufferAntiprotonsUE, fTempBufferAntiprotonUE, 6, ueAxis2); + setTrackBuffer(fTempBufferProtonUE, fBufferAntiprotonsUE); + + doCorrelations(piPlusUE, fBufferPiPlusUE, fTempBufferPiPlusUE, 7, ueAxis2); + setTrackBuffer(fTempBufferProtonUE, fBufferPiPlusUE); + + doCorrelations(piMinusUE, fBufferPiMinusUE, fTempBufferPiMinusUE, 7, ueAxis2); + setTrackBuffer(fTempBufferProtonUE, fBufferPiMinusUE); + } + + // this may need to be reworked, it hasn't really been tested yet + // so far it does almost the same as fillHistograms without correlations but including MCgen tracks + 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] = jetutilities::estimateRhoPerpCone(jetInput, jets[0], jetR); + + 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 = RecoDecay::constrainAngle(particleDir.Phi() - pJet.Phi(), -constants::math::PI); + double deltaRJet = std::abs(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUE1 = particleDir.Eta() - ueAxis1.Eta(); + double deltaPhiUE1 = RecoDecay::constrainAngle(particleDir.Phi() - ueAxis1.Phi(), -constants::math::PI); + double deltaRUE1 = std::abs(deltaEtaUE1 * deltaEtaUE1 + deltaPhiUE1 * deltaPhiUE1); + double deltaEtaUE2 = particleDir.Eta() - ueAxis2.Eta(); + double deltaPhiUE2 = RecoDecay::constrainAngle(particleDir.Phi() - ueAxis2.Phi(), -constants::math::PI); + double deltaRUE2 = std::abs(deltaEtaUE2 * deltaEtaUE2 + deltaPhiUE2 * deltaPhiUE2); + + double failedPhi = -999; + if (deltaRJet < jetR) { + if (deltaPhiJet != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiJet"), deltaEtaJet, deltaPhiJet); + nchJetPlusUE++; + } + if (deltaRUE1 < jetR) { + if (deltaPhiUE1 != failedPhi) + registryQC.fill(HIST("deltaEtadeltaPhiUE"), deltaEtaUE1, deltaPhiUE1); + nchUE++; + } + if (deltaRUE2 < jetR) { + 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) { + if (rejectEvents) { + // event counter: before event rejection + registryData.fill(HIST("numberRejectedEvents"), 0); + + if (shouldRejectEvent()) + continue; + + // event counter: after event rejection + registryData.fill(HIST("numberRejectedEvents"), 1); + } + 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) { + if (rejectEvents) { + // event counter: before event rejection + registryData.fill(HIST("numberRejectedEvents"), 0); + + if (shouldRejectEvent()) + continue; + + // event counter: after event rejection + registryData.fill(HIST("numberRejectedEvents"), 1); + } + 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) { + if (rejectEvents) { + // event counter: before event rejection + registryData.fill(HIST("numberRejectedEvents"), 0); + + if (shouldRejectEvent()) + continue; + + // event counter: after event rejection + registryData.fill(HIST("numberRejectedEvents"), 1); + } + 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) { + if (rejectEvents) { + // event counter: before event rejection + registryData.fill(HIST("numberRejectedEvents"), 0); + + if (shouldRejectEvent()) + continue; + + // event counter: after event rejection + registryData.fill(HIST("numberRejectedEvents"), 1); + } + 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 deleted file mode 100644 index f31fff08713..00000000000 --- a/PWGLF/Tasks/Nuspex/antidLambdaEbye.cxx +++ /dev/null @@ -1,1241 +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 "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 "Common/Core/PID/TPCPIDResponse.h" -#include "Common/DataModel/PIDResponse.h" -#include "DCAFitter/DCAFitterN.h" - -#include "TDatabasePDG.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -using TracksFull = soa::Join; -using TracksFullIU = soa::Join; -using BCsWithRun2Info = soa::Join; - -namespace -{ -constexpr int kNpart = 2; -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 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 particleNamesBB{"p", "d"}; -std::array, kNpart> tempTracks; -std::shared_ptr tempAntiLambda; -std::shared_ptr tempLambda; -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::array, kNpart> recTracks; -std::array, kNpart> recAntiTracks; -std::array, kNpart> genTracks; -std::array, kNpart> genAntiTracks; -std::array, kNpart> tpcNsigma; -std::array, kNpart> tpcNsigmaGlo; -std::array, kNpart> tofMass; -std::array, kNpart> tofSignal; -std::array, kNpart> tofSignal_glo; -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; - float eta; - float mass; - float cpa; - float dcav0daugh; - float dcav0pv; - int64_t globalIndexPos = -999; - int64_t globalIndexNeg = -999; -}; - -struct CandidateTrack { - float pt; - float eta; - int64_t globalIndex = -999; -}; - -struct antidLambdaEbye { - std::mt19937 gen32; - std::vector candidateV0s; - std::array, 2> candidateTracks; - Service ccdb; - o2::vertexing::DCAFitterN<2> fitter; - - int nSubsamples; - int mRunNumber; - float d_bz; - // o2::base::MatLayerCylSet* lut = nullptr; - - 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 multAxis{"multAxis", {100, 0, 10000}, "Binning for the multiplicity axis"}; - ConfigurableAxis multFt0Axis{"multFt0Axis", {100, 0, 100000}, "Binning for the ft0 multiplicity axis"}; - 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"}; - - 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; - std::array ptMax; - std::array nSigmaTpcCutLow; - std::array nSigmaTpcCutUp; - std::array nSigmaTofCut; - std::array tpcInnerParamMax; - std::array tofMassMax; - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry tempHistos{"tempHistos", {}, OutputObjHandlingPolicy::TransientObject}; - - Preslice perCollisionTracksFull = o2::aod::track::collisionId; - Preslice perCollisionTracksFullIU = o2::aod::track::collisionId; - Preslice perCollisionV0 = o2::aod::v0::collisionId; - Preslice perCollisionMcParts = o2::aod::mcparticle::mcCollisionId; - - template - bool selectV0Daughter(T const& track) - { - if (std::abs(track.eta()) > config.etaMaxV0dau) { - return false; - } - if (track.itsNCls() < config.v0trackNclusItsCut || - track.tpcNClsFound() < config.v0trackNclusTpcCut || - track.tpcNClsCrossedRows() < config.v0trackNclusTpcCut || - track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || - track.tpcNClsShared() > config.v0trackNsharedClusTpc) { - return false; - } - if (doprocessRun2 || doprocessMcRun2) { - if (!(track.trackType() & o2::aod::track::Run2Track) || - !(track.flags() & o2::aod::track::TPCrefit)) { - return false; - } - if (config.v0requireITSrefit && !(track.flags() & o2::aod::track::ITSrefit)) { - return false; - } - } - return true; - } - - template - bool selectTrack(T const& track) - { - if (std::abs(track.eta()) > config.etaMax) { - return false; - } - if (!(track.itsClusterMap() & 0x01) && !(track.itsClusterMap() & 0x02)) { - return false; - } - 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.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(); - } - - 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); - } - } - } - } - - 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); - } 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(); - 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(1); - fitter.setMaxChi2(1e9); - fitter.setUseAbsDCA(true); - 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()); - 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}); - 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}); - 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}); - - // event QA - 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) { - histos.add("QA/V0MvsCL0", ";Centrality CL0 (%);Centrality V0M (%)", HistType::kTH2F, {centAxis, centAxis}); - histos.add("QA/trackletsVsV0M", ";Centrality CL0 (%);Centrality V0M (%)", HistType::kTH2F, {centAxis, multAxis}); - } - - // 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}); - histos.add("QA/nClsTPC", ";tpcCls;Entries", HistType::kTH1F, {tpcClsAxis}); - histos.add("QA/nCrossedRowsTPC", ";nCrossedRowsTPC;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}); - histos.add("QA/nCrossedRowsTPCBeforeCut", ";nCrossedRowsTPC;Entries", HistType::kTH1F, {tpcClsAxis}); - - // 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, {momAxisFine, tpcAxis}); - histos.add("QA/tpcSignal_glo", ";#it{p}_{glo} (GeV/#it{c});d#it{E}/d#it{x}_{TPC} (a.u.);", HistType::kTH2F, {momAxisFine, tpcAxis}); - - tpcNsigma[0] = histos.add("QA/tpcNsigma_p", ";#it{p}_{TPC} (GeV/#it{c});n#sigma_{TPC} (a.u.)", HistType::kTH2F, {momAxis, tpcNsigmaAxis}); - 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}); - tofSignal[0] = histos.add("QA/tofSignal_p", ";#it{p}_{TPC} (GeV/#it{c});#beta_{TOF}", HistType::kTH2F, {momAxisFine, tofAxis}); - tofSignal_glo[0] = histos.add("QA/tofSignal_glo_p", ";#it{p}_{T} (GeV/#it{c});#beta_{TOF}", HistType::kTH2F, {momAxisFine, tofAxis}); - - tpcNsigma[1] = histos.add("QA/tpcNsigma_d", ";#it{p}_{TPC} (GeV/#it{c});n#sigma_{TPC} (a.u.)", HistType::kTH2F, {momAxis, tpcNsigmaAxis}); - 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}); - tofSignal[1] = histos.add("QA/tofSignal_d", ";#it{p}_{TPC} (GeV/#it{c});#beta_{TOF}", HistType::kTH2F, {momAxisFine, tofAxis}); - tofSignal_glo[1] = histos.add("QA/tofSignal_glo_d", ";#it{p}_{T} (GeV/#it{c});#beta_{TOF}", HistType::kTH2F, {momAxisFine, tofAxis}); - - // mc histograms - if (doprocessMcRun3 || doprocessMcRun2) { - 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{config.antipPtMin, config.antidPtMin}; - ptMax = std::array{config.antipPtMax, config.antidPtMax}; - ptTof = std::array{config.antipPtTof, config.antidPtTof}; - - 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 - int fillRecoEvent(C const& collision, T const& tracksAll, aod::V0s const& V0s, float const& centrality) - { - auto tracks = (doprocessRun3 || doprocessMcRun3) ? tracksAll.sliceBy(perCollisionTracksFullIU, collision.globalIndex()) : tracksAll.sliceBy(perCollisionTracksFull, collision.globalIndex()); - 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); - - 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; - } - - if (track.sign() > 0.) { - 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(); - histos.fill(HIST("QA/dcaPvBefore"), trackPt, dca); - if (dca > config.trackDcaCut) { - continue; - } - histos.fill(HIST("QA/dcaPv"), trackPt, dca); - - histos.fill(HIST("QA/nClsTPC"), track.tpcNClsFound()); - histos.fill(HIST("QA/nCrossedRowsTPC"), track.tpcNClsCrossedRows()); - histos.fill(HIST("QA/tpcSignal"), track.tpcInnerParam(), track.tpcSignal()); - histos.fill(HIST("QA/tpcSignal_glo"), track.p(), 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 < config.antidItsClsSizeCut && trackPt < config.antidPtItsClsSizeCut) { - continue; - } - } - - 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}; - 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]) < config.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; - } - - tpcNsigma[iP]->Fill(track.tpcInnerParam(), nSigmaTPC); - if (trackPt > ptTof[iP] && hasTof) { - tofSignal_glo[iP]->Fill(track.p(), beta); - tofSignal[iP]->Fill(track.tpcInnerParam(), beta); - } - - // 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])) { - tempTracks[iP]->Fill(std::abs(trackEta), trackPt); - CandidateTrack candTrack; - candTrack.pt = trackPt; - candTrack.eta = trackEta; - candTrack.globalIndex = track.globalIndex(); - candidateTracks[iP].push_back(candTrack); - } - } - } - histos.fill(HIST("QA/nTrklCorrelation"), nTracklets[0], nTracklets[1]); - - 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 || doprocessMcRun2) { - 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 < config.lambdaPtMin || ptV0 > config.lambdaPtMax) { - continue; - } - - auto etaV0 = etaFromMom(momPos, momNeg); - if (std::abs(etaV0) > config.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), 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) < config.vetoMassK0Short) { - continue; - } - - float dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); - histos.fill(HIST("QA/dcaV0daughBeforeCut"), dcaV0dau); - if (dcaV0dau > config.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]); - histos.fill(HIST("QA/radiusBeforeCut"), radiusV0); - 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 < 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 < 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 < config.v0setting_dcadaughtopv && std::abs(dcaInfo[0]) < config.v0setting_dcadaughtopv) { - continue; - } - - 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) > config.lambdaMassCut) { - continue; - } - histos.fill(HIST("QA/cosPa"), cosPA); - histos.fill(HIST("QA/radius"), radiusV0); - 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(posTrack.globalIndex()); - trkId.emplace_back(negTrack.globalIndex()); - - 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); - } - - // 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()) && config.fillOnlySignal) { - 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 ((doprocessMcRun3 || doprocessMcRun2) && config.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, aod::V0s const& V0s, float const& centrality, aod::McParticles const&, aod::McTrackLabels const& mcLabels) - { - 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 (config.fillOnlySignal) { - tempTracks[0]->Reset(); - tempTracks[1]->Reset(); - tempLambda->Reset(); - tempAntiLambda->Reset(); - } - - for (int iP{0}; iP < kNpart; ++iP) { - for (auto& candidateTrack : candidateTracks[iP]) { - auto mcLab = mcLabels.rawIteratorAt(candidateTrack.globalIndex); - if (mcLab.has_mcParticle()) { - auto mcTrack = mcLab.template mcParticle_as(); - if (std::abs(mcTrack.pdgCode()) != partPdg[iP]) - continue; - if (((mcTrack.flags() & 0x8) && doprocessMcRun2) || (mcTrack.flags() & 0x2) || (mcTrack.flags() & 0x1)) - continue; - if (!mcTrack.isPhysicalPrimary()) - 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 (config.fillOnlySignal) - tempTracks[iP]->Fill(std::abs(candidateTrack.eta), candidateTrack.pt); - } - } - } - } - for (auto& candidateV0 : candidateV0s) { - 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) { - 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 (config.fillOnlySignal) - tempLambda->Fill(std::abs(candidateV0.eta), candidateV0.pt); - } else { - histos.fill(HIST("recAntiL"), centrality, candidateV0.pt, std::abs(candidateV0.eta)); - if (config.fillOnlySignal) - tempAntiLambda->Fill(std::abs(candidateV0.eta), candidateV0.pt); - } - } - } - } - } - } - - if (config.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()); - } - } - - void fillMcGen(aod::McParticles const& mcParticles, aod::McTrackLabels const& /*mcLab*/, std::vector> const& goodCollisions) - { - for (uint64_t iC{0}; iC < goodCollisions.size(); ++iC) { - if (goodCollisions[iC].first == false) { - continue; - } - - tempTracks[0]->Reset(); - tempTracks[1]->Reset(); - tempLambda->Reset(); - tempAntiLambda->Reset(); - - auto centrality = goodCollisions[iC].second; - auto rnd = static_cast(gen32()) / static_cast(gen32.max()); - auto subsample = static_cast(rnd * nSubsamples); - auto mcParticles_thisCollision = mcParticles.sliceBy(perCollisionMcParts, iC); - for (auto& mcPart : mcParticles_thisCollision) { - auto genEta = mcPart.eta(); - if (std::abs(genEta) > config.etaMax) { - continue; - } - if (((mcPart.flags() & 0x8) && doprocessMcRun2) || (mcPart.flags() & 0x2) || (mcPart.flags() & 0x1)) - 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()); - - 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); - } - } 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() && !mcPart.has_mothers()) - continue; - auto genPt = std::hypot(mcPart.px(), mcPart.py()); - 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 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()) > config.zVtxMax) - continue; - - if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) - continue; - - if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - continue; - - if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) - continue; - - if (!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); - } - } - PROCESS_SWITCH(antidLambdaEbye, processRun3, "process (Run 3)", false); - - void processRun2(soa::Join const& collisions, TracksFull const& tracks, aod::V0s const& V0s, BCsWithRun2Info const&) - { - for (const auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - - if (std::abs(collision.posZ()) > config.zVtxMax) - continue; - - if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) - continue; - - if (config.kUseTPCPileUpCut && !(bc.eventCuts() & BIT(aod::Run2EventCuts::kTPCPileUp))) - continue; - - auto centrality = collision.centRun2V0M(); - if (!(collision.sel7() && collision.alias_bit(kINT7)) && (!config.kINT7Intervals || (config.kINT7Intervals && ((centrality >= 10 && centrality < 30) || centrality > 50)))) - continue; - - auto centralityCl0 = collision.centRun2CL0(); - 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); - if (centrality < center - deltaEstimatorNsigma[0] * sigma || centrality > 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, centrality); - - histos.fill(HIST("QA/V0MvsCL0"), centralityCl0, centrality); - histos.fill(HIST("QA/trackletsVsV0M"), centrality, multTracklets); - } - } - PROCESS_SWITCH(antidLambdaEbye, processRun2, "process (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&) - { - std::vector> goodCollisions(mcCollisions.size(), std::make_pair(false, -999.)); - for (auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - - if (!collision.sel8()) - continue; - - if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) - continue; - - if (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - continue; - - if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) - continue; - - if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) - continue; - - if (std::abs(collision.posZ()) > config.zVtxMax) - continue; - - auto centrality = collision.centFT0C(); - goodCollisions[collision.mcCollisionId()].first = true; - goodCollisions[collision.mcCollisionId()].second = centrality; - - 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); - if (candidateV0s.size() == 1 && candidateV0s[0].pt < -998.f && candidateV0s[0].eta < -998.f && candidateV0s[0].globalIndexPos == -999 && candidateV0s[0].globalIndexPos == -999) { - goodCollisions[collision.mcCollisionId()].first = false; - } - } - - fillMcGen(mcParticles, mcLab, goodCollisions); - } - PROCESS_SWITCH(antidLambdaEbye, processMcRun3, "process MC (Run 3)", false); - - void processMcRun2(soa::Join const& collisions, aod::McCollisions const& mcCollisions, TracksFull const& tracks, aod::V0s const& V0s, aod::McParticles const& mcParticles, aod::McTrackLabels const& mcLab, BCsWithRun2Info const&) - { - std::vector> goodCollisions(mcCollisions.size(), std::make_pair(false, -999.)); - for (auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - - if (std::abs(collision.posZ()) > config.zVtxMax) - continue; - - if (!(bc.eventCuts() & BIT(aod::Run2EventCuts::kAliEventCutsAccepted))) - continue; - - auto centrality = collision.centRun2V0M(); - goodCollisions[collision.mcCollisionId()].first = true; - goodCollisions[collision.mcCollisionId()].second = centrality; - - 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); - if (candidateV0s.size() == 1 && candidateV0s[0].pt < -998.f && candidateV0s[0].eta < -998.f && candidateV0s[0].globalIndexPos == -999 && candidateV0s[0].globalIndexPos == -999) { - goodCollisions[collision.mcCollisionId()].first = false; - } - } - - fillMcGen(mcParticles, mcLab, goodCollisions); - } - PROCESS_SWITCH(antidLambdaEbye, processMcRun2, "process MC (Run 2)", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx b/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx new file mode 100644 index 00000000000..0fe4432d80f --- /dev/null +++ b/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx @@ -0,0 +1,3065 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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), Francesca Casillo (francesca.casillo@cern.ch) +/// \since February 13, 2025 + +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include "TGrid.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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; + +// Define convenient aliases for commonly used table joins +using SelectedCollisions = soa::Join; +using RecCollisionsMc = soa::Join; +using GenCollisionsMc = aod::McCollisions; +using AntiNucleiTracks = soa::Join; +using AntiNucleiTracksMc = soa::Join; + +struct AntinucleiInJets { + + // Histogram registries for data, MC, quality control, multiplicity and correlations + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMult{"registryMult", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryCorr{"registryCorr", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Random generator for subsample assignment + TRandom3 mRand; + + // Event selection criteria + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "Reject events near the ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "Reject events near the TF border"}; + Configurable requireVtxITSTPC{"requireVtxITSTPC", true, "Require at least one ITS-TPC matched track"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "Reject events with same-bunch pileup collisions"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "Require consistent FT0 vs PV z-vertex"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "Require at least one vertex track matched to TOF"}; + + // Skimmed data flag and list of active triggers for processing + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + Configurable triggerList{"triggerList", "fHe", "Trigger list"}; + + // Jet selection and event filtering parameters + Configurable minJetPt{"minJetPt", 10.0, "Minimum pt of the jet after bkg subtraction"}; + Configurable ptLeadingMin{"ptLeadingMin", 5.0, "pt Leading Min"}; + Configurable rJet{"rJet", 0.3, "Jet resolution parameter R"}; + Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; + Configurable applyAreaCut{"applyAreaCut", true, "apply area cut"}; + Configurable maxNormalizedJetArea{"maxNormalizedJetArea", 1.0, "area cut"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "eta gap from the edge"}; + Configurable nSyst{"nSyst", 50, "number of systematic variations"}; + + // Track quality, kinematic, and PID selection parameters + Configurable requirePvContributor{"requirePvContributor", false, "require that the track is a PV contributor"}; + Configurable applyItsPid{"applyItsPid", false, "apply ITS PID"}; + Configurable minItsNclusters{"minItsNclusters", 5, "minimum number of ITS clusters"}; + Configurable minTpcNcrossedRows{"minTpcNcrossedRows", 100, "minimum number of TPC crossed pad rows"}; + Configurable minChiSquareTpc{"minChiSquareTpc", 0.0, "minimum TPC chi^2/Ncls"}; + 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", -3.0, "nSigmaITS min"}; + Configurable nSigmaItsMax{"nSigmaItsMax", +3.0, "nSigmaITS max"}; + Configurable setMCDefaultItsParams{"setMCDefaultItsParams", true, "set MC default parameters"}; + Configurable cfgCompensatePIDinTracking{"cfgCompensatePIDinTracking", false, "If true, divide tpcInnerParam by the electric charge"}; + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {0.6539, 1.591, 0.8225, 2.363, 0.09}, "TPC Bethe-Bloch parameterisation for He3"}; + + // Configuration parameters for CCDB access and reweighting input files + Configurable applyReweighting{"applyReweighting", true, "enable reweighting for efficiency"}; + Configurable urlToCcdb{"urlToCcdb", "http://alice-ccdb.cern.ch", "url of the personal ccdb"}; + Configurable pathToFile{"pathToFile", "Users/a/alcaliva/reweightingHistogramsAntipInJet", "path to file"}; + Configurable weightsProton{"weightsProton", "", "weightsProton"}; + Configurable weightsLambda{"weightsLambda", "", "weightsLambda"}; + Configurable weightsSigma{"weightsSigma", "", "weightsSigma"}; + Configurable weightsXi{"weightsXi", "", "weightsXi"}; + Configurable weightsOmega{"weightsOmega", "", "weightsOmega"}; + Configurable weightsJet{"weightsJet", "", "weightsJet"}; + Configurable weightsUe{"weightsUe", "", "weightsUe"}; + + // Number of events + Configurable shrinkInterval{"shrinkInterval", 1000, "variable that controls how often shrinking happens"}; + + // Reweighting histograms + TH1F* primaryAntiprotons; + TH1F* primaryAntiLambda; + TH1F* primaryAntiSigma; + TH1F* primaryAntiXi; + TH1F* primaryAntiOmega; + TH1F* antiprotonsInsideJets; + TH1F* antiprotonsPerpCone; + + // CCDB manager service for accessing condition data + Service ccdb; + + // Direct interface to the CCDB API for manual data access + o2::ccdb::CcdbApi ccdbApi; + + // Instantiate the main Zorro processing object and define an output to store summary information + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // Utility object for jet background subtraction methods + JetBkgSubUtils backgroundSub; + + // Initialize ITS PID Response object + o2::aod::ITSResponse itsResponse; + + // Initialize CCDB access and histogram registry for Zorro processing + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + zorro.populateHistRegistry(registryData, bc.runNumber()); + } + } + + void init(InitContext const&) + { + // Set summary object if processing skimmed data + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + // Set default MC parametrization for ITS response + if (setMCDefaultItsParams) { + itsResponse.setMCDefaultParameters(); + } + + // Initialize random seed using high-resolution clock to ensure unique sequences across parallel Grid jobs + auto time_seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + mRand.SetSeed(time_seed); + + // Load reweighting histograms from CCDB if antinuclei efficiency processing is enabled + if (doprocessAntinucleiEfficiency || doprocessJetsMCgen || doprocessJetsMCrec) { + 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); + getReweightingHistograms(ccdb, TString(pathToFile), TString(weightsProton), TString(weightsLambda), TString(weightsSigma), TString(weightsXi), TString(weightsOmega), TString(weightsJet), TString(weightsUe)); + } + + // Binning + double min = 0.0; + double max = 6.0; + int nbins = 120; + + // Quality control histograms for jet/UE topology and multiplicity + 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("jetPtDifference", "jetPtDifference", HistType::kTH1F, {{200, -1, 1, "#Deltap_{T}^{jet}"}}); + registryQC.add("ptDistributionJetCone", "ptDistributionJetCone", HistType::kTH1F, {{2000, 0, 200, "#it{p}_{T} (GeV/#it{c})"}}); + registryQC.add("ptDistributionJet", "ptDistributionJet", HistType::kTH1F, {{2000, 0, 200, "#it{p}_{T} (GeV/#it{c})"}}); + } + + // Multiplicity histograms: check charged-particle multiplicity in events with selected jets (Run 3) or ptTrigger > threshold (Run 2-like) + if (doprocessMultEvents) { + registryMult.add("multiplicityEvtsPtLeading", "multiplicityEvtsPtLeading", HistType::kTH1F, {{1000, 0, 1000, "#it{N}_{ch}"}}); + registryMult.add("multiplicityEvtsWithJet", "multiplicityEvtsWithJet", HistType::kTH1F, {{1000, 0, 1000, "#it{N}_{ch}"}}); + } + + // Histograms for real data + if (doprocessData) { + + // Event counters + registryData.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{20, 0, 20, "counter"}}); + + // Configuration + registryData.add("settingData", "settingData", HistType::kTH2F, {{100, 0.0, 50.0, "min #it{p}^{jet}_{T} (GeV/#it{c})"}, {20, 0.0, 1.0, "#it{R}_{jet}"}}); + + // Jet effective area over piR^2 + registryData.add("jetEffectiveAreaOverPiR2", "jet effective area / piR^2", HistType::kTH1F, {{2000, 0, 2, "Area/#piR^{2}"}}); + + // angle between track and jet axis + registryData.add("theta_track_jet", "theta_track_jet", HistType::kTH2F, {{100, 0, 100, "#it{p}^{jet}_{T} (GeV/#it{c})"}, {400, 0, 20.0, "#theta_{track-jet} (deg)"}}); + + // 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, -1.0, 1.0, "DCA_{xy} (cm)"}}); + registryData.add("antiproton_dca_ue", "antiproton_dca_ue", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {200, -1.0, 1.0, "DCA_{xy} (cm)"}}); + + // Antideuterons + registryData.add("antideuteron_jet_tpc", "antideuteron_jet_tpc", HistType::kTH2F, {{nbins, 2 * min, 2 * max, "#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, 2 * min, 2 * max, "#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, 2 * min, 2 * max, "#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, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + + // Deuterons + registryData.add("deuteron_jet_tpc", "deuteron_jet_tpc", HistType::kTH2F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("deuteron_jet_tof", "deuteron_jet_tof", HistType::kTH2F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("deuteron_ue_tpc", "deuteron_ue_tpc", HistType::kTH2F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("deuteron_ue_tof", "deuteron_ue_tof", HistType::kTH2F, {{nbins, 2 * min, 2 * max, "#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, 3 * min, 3 * max, "#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, 3 * min, 3 * max, "#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, 3 * min, 3 * max, "#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, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + + // nsigmaITS for antiproton candidates + registryData.add("antiproton_nsigma_its_data", "antiproton_nsigma_its_data", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{ITS}"}}); + + // custom nsigma for He3 - needed for 24 pp data + registryData.add("tpcsignal_data", "Specific energy loss", HistType::kTH2F, {{600, -6., 6., "#it{p} (GeV/#it{c})"}, {1400, 0, 1400, "d#it{E} / d#it{X} (a. u.)"}}); + registryData.add("antihelium3_jet_tpc_custom", "antihelium3_jet_tpc_custom", HistType::kTH2F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC} custom"}}); + registryData.add("antihelium3_ue_tpc_custom", "antihelium3_ue_tpc_custom", HistType::kTH2F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC} custom"}}); + } + + // Generated antiproton spectra in jets and UE from MC truth + if (doprocessJetsMCgen) { + + // Event counter + registryMC.add("genEvents", "number of generated events in mc", HistType::kTH1F, {{10, 0, 10, "counter"}}); + registryMC.add("genJets", "number of generated jets", HistType::kTH1F, {{10, 0, 10, "counter"}}); + + // Size of particle array + registryMC.add("sizeParticleArray", "number of particles", HistType::kTH1F, {{1000, 0, 1000, "#it{N}_{part}"}}); + + // Generated spectra of antiprotons + registryMC.add("antiproton_gen_jet", "antiproton_gen_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_gen_ue", "antiproton_gen_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_gen_full", "antiproton_gen_full", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Normalization histogram + registryMC.add("antiproton_deltay_deltaphi_jet", "antiproton_deltay_deltaphi_jet", HistType::kTH2F, {{2000, -1.0, 1.0, "#Delta#it{y}"}, {2000, 0.0, 2.0, "#Delta#phi"}}); + registryMC.add("antiproton_deltay_deltaphi_ue", "antiproton_deltay_deltaphi_ue", HistType::kTH2F, {{2000, -1.0, 1.0, "#Delta#it{y}"}, {2000, 0.0, 2.0, "#Delta#phi"}}); + + // 2d kinematic distributions (eta,pt) in jets and UE + registryMC.add("antiproton_eta_pt_jet", "antiproton_eta_pt_jet", HistType::kTH2F, {{500, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); + registryMC.add("antiproton_eta_pt_ue", "antiproton_eta_pt_ue", HistType::kTH2F, {{500, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); + } + + // Reconstructed antiproton spectra in jets and UE (MC-matched) with TPC/TOF PID + if (doprocessJetsMCrec) { + + // Event counter + registryMC.add("recEvents", "number of reconstructed events in mc", HistType::kTH1F, {{20, 0, 20, "counter"}}); + registryMC.add("recJets", "number of reconstructed jets", HistType::kTH1F, {{10, 0, 10, "counter"}}); + + // Configuration + registryMC.add("settingMC", "settingMC", HistType::kTH2F, {{100, 0.0, 50.0, "min #it{p}^{jet}_{T} (GeV/#it{c})"}, {20, 0.0, 1.0, "#it{R}_{jet}"}}); + + // Reconstructed spectra of antiprotons + registryMC.add("antiproton_rec_tpc_jet", "antiproton_rec_tpc_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tof_jet", "antiproton_rec_tof_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tpc_ue", "antiproton_rec_tpc_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tof_ue", "antiproton_rec_tof_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tpc_full", "antiproton_rec_tpc_full", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tof_full", "antiproton_rec_tof_full", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Fraction of primary antiprotons + registryMC.add("antiproton_prim_jet", "antiproton_prim_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_incl_jet", "antiproton_incl_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_prim_ue", "antiproton_prim_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_incl_ue", "antiproton_incl_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + + // DCA templates + registryMC.add("antiproton_prim_dca_jet", "antiproton_prim_dca_jet", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); + registryMC.add("antiproton_prim_dca_ue", "antiproton_prim_dca_ue", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); + registryMC.add("antiproton_all_dca_jet", "antiproton_all_dca_jet", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); + registryMC.add("antiproton_all_dca_ue", "antiproton_all_dca_ue", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); + + // nsigmaTOF for antiprotons + registryMC.add("antiproton_nsigma_tof_jet_mc", "antiproton_nsigma_tof_jet_mc", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + } + + // Efficiency of antinuclei + if (doprocessAntinucleiEfficiency) { + + // Event counter MC + registryMC.add("number_of_events_mc_nuclei_efficiency", "number of events in mc", HistType::kTH1F, {{20, 0, 20, "counter"}}); + + // Generated spectra of (anti)protons + registryMC.add("antip_gen_jet", "antip_gen_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_gen_ue", "antip_gen_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Generated spectra of (anti)deuterons + registryMC.add("deuteron_gen_jet", "deuteron_gen_jet", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("deuteron_gen_ue", "deuteron_gen_ue", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_gen_jet", "antideuteron_gen_jet", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_gen_ue", "antideuteron_gen_ue", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Generated spectra of (anti)helium3 + registryMC.add("helium3_gen_jet", "helium3_gen_jet", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("helium3_gen_ue", "helium3_gen_ue", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antihelium3_gen_jet", "antihelium3_gen_jet", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antihelium3_gen_ue", "antihelium3_gen_ue", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Reconstructed spectra of antiprotons + registryMC.add("antip_rec_tpc_jet", "antip_rec_tpc_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_rec_tof_jet", "antip_rec_tof_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_rec_tpc_ue", "antip_rec_tpc_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_rec_tof_ue", "antip_rec_tof_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Reconstructed spectra of (anti)deuterons + registryMC.add("deuteron_rec_tpc_jet", "deuteron_rec_tpc_jet", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("deuteron_rec_tof_jet", "deuteron_rec_tof_jet", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("deuteron_rec_tpc_ue", "deuteron_rec_tpc_ue", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("deuteron_rec_tof_ue", "deuteron_rec_tof_ue", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_rec_tpc_jet", "antideuteron_rec_tpc_jet", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_rec_tof_jet", "antideuteron_rec_tof_jet", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_rec_tpc_ue", "antideuteron_rec_tpc_ue", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_rec_tof_ue", "antideuteron_rec_tof_ue", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Reconstructed spectra of (anti)helium3 + registryMC.add("helium3_rec_tpc_jet", "helium3_rec_tpc_jet", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("helium3_rec_tpc_ue", "helium3_rec_tpc_ue", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antihelium3_rec_tpc_jet", "antihelium3_rec_tpc_jet", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antihelium3_rec_tpc_ue", "antihelium3_rec_tpc_ue", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Generated spectra needed for reweighting + registryMC.add("protonBar", "protonBar", HistType::kTH1F, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("lambdaBar", "lambdaBar", HistType::kTH1F, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("xiBar", "xiBar", HistType::kTH1F, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("omegaBar", "omegaBar", HistType::kTH1F, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("sigmaBar", "sigmaBar", HistType::kTH1F, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}}); + + // nsigmaITS for antiproton candidates + registryMC.add("antiproton_nsigma_its_mc", "antiproton_nsigma_its_mc", HistType::kTH2F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{ITS}"}}); + + // Systematics on the fraction of primary antiprotons + registryMC.add("antip_prim_pythia", "antip_prim_pythia", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_prim_std", "antip_prim_std", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_prim_up", "antip_prim_up", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_prim_low", "antip_prim_low", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + + registryMC.add("antip_sec_pythia", "antip_sec_pythia", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_sec_std", "antip_sec_std", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_sec_up", "antip_sec_up", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antip_sec_low", "antip_sec_low", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + } + + // Systematic uncertainties (Data) + if (doprocessSystData) { + registryData.add("number_of_events_data_syst", "event counter", HistType::kTH1F, {{20, 0, 20, "counter"}}); + + registryData.add("antiproton_tpc_syst", "antiproton_tpc_syst", HistType::kTH3F, {{50, 0, 50, "systematic uncertainty"}, {nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antiproton_tof_syst", "antiproton_tof_syst", HistType::kTH3F, {{50, 0, 50, "systematic uncertainty"}, {nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antideuteron_tpc_syst", "antideuteron_tpc_syst", HistType::kTH3F, {{50, 0, 50, "systematic uncertainty"}, {nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antideuteron_tof_syst", "antideuteron_tof_syst", HistType::kTH3F, {{50, 0, 50, "systematic uncertainty"}, {nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antihelium3_tpc_syst", "antihelium3_tpc_syst", HistType::kTH3F, {{50, 0, 50, "systematic uncertainty"}, {nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); + } + + // Systematic uncertainties (MC) + if (doprocessSystEff) { + + // Histograms for generated antiparticles + registryMC.add("antiproton_gen_syst", "antiproton_gen_syst", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_gen_syst", "antideuteron_gen_syst", HistType::kTH1F, {{nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antihelium3_gen_syst", "antihelium3_gen_syst", HistType::kTH1F, {{nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Histograms for reconstructed antiparticles + registryMC.add("antiproton_rec_tpc_syst", "antiproton_rec_tpc_syst", HistType::kTH2F, {{50, 0, 50, "systematic uncertainty"}, {nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_rec_tof_syst", "antiproton_rec_tof_syst", HistType::kTH2F, {{50, 0, 50, "systematic uncertainty"}, {nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_rec_tpc_syst", "antideuteron_rec_tpc_syst", HistType::kTH2F, {{50, 0, 50, "systematic uncertainty"}, {nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_rec_tof_syst", "antideuteron_rec_tof_syst", HistType::kTH2F, {{50, 0, 50, "systematic uncertainty"}, {nbins, 2 * min, 2 * max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antihelium3_rec_tpc_syst", "antihelium3_rec_tpc_syst", HistType::kTH2F, {{50, 0, 50, "systematic uncertainty"}, {nbins, 3 * min, 3 * max, "#it{p}_{T} (GeV/#it{c})"}}); + + // Histograms for primary antiprotons + registryMC.add("antiproton_incl_syst", "antiproton_incl_syst", HistType::kTH2F, {{50, 0, 50, "systematic uncertainty"}, {nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antiproton_prim_syst", "antiproton_prim_syst", HistType::kTH2F, {{50, 0, 50, "systematic uncertainty"}, {nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + } + + // Correlation analysis + if (doprocessCorr) { + + // Axes definitions for multidimensional histogram binning + const AxisSpec multiplicityAxis{100, 0.0, 100.0, "multiplicity percentile"}; + const AxisSpec ptPerNucleonAxis{5, 0.4, 0.9, "{p}_{T}/A (GeV/#it{c})"}; + const AxisSpec nAntideuteronsAxis{10, 0.0, 10.0, "N_{#bar{d}}"}; + const AxisSpec nAntiprotonsAxis{10, 0.0, 10.0, "N_{#bar{p}}"}; + const AxisSpec nBarD2Axis{100, 0.0, 100.0, "N_{#bar{d}}^{i} #times N_{#bar{d}}^{j}"}; + const AxisSpec nBarP2Axis{100, 0.0, 100.0, "N_{#bar{p}}^{i} #times N_{#bar{p}}^{j}"}; + const AxisSpec nBarDnBarPAxis{100, 0.0, 100.0, "N_{#bar{d}}^{i} #times N_{#bar{p}}^{j}"}; + const AxisSpec subsampleAxis{20, 0, 20, "Subsample Index"}; + + // Event counter + registryCorr.add("eventCounter", "number of events", HistType::kTH1F, {{20, 0, 20, "counter"}}); + registryCorr.add("eventCounter_centrality_fullEvent", "Number of events per centrality (Full Event)", HistType::kTH2F, {multiplicityAxis, subsampleAxis}); + // registryCorr.add("eventCounter_centrality_jet", "Number of events per centrality (Jet)", HistType::kTH1F, {multiplicityAxis}); + // registryCorr.add("eventCounter_centrality_ue", "Number of events per centrality (Underlying Event)", HistType::kTH1F, {multiplicityAxis}); + + // Correlation histograms: antiproton vs. antideuteron number vs. event multiplicity + // registryCorr.add("rho_jet", "rho_jet", HistType::kTH3F, {nAntideuteronsAxis, nAntiprotonsAxis, multiplicityAxis}); + // registryCorr.add("rho_ue", "rho_ue", HistType::kTH3F, {nAntideuteronsAxis, nAntiprotonsAxis, multiplicityAxis}); + registryCorr.add("rho_fullEvent", "rho_fullEvent", HistType::kTHnSparseD, {nAntideuteronsAxis, nAntiprotonsAxis, multiplicityAxis, subsampleAxis}); + + // Correlation histograms: net antiproton vs. net antideuteron numbers + // registryCorr.add("rho_netP_netD_jet", "rho_netP_netD_jet", HistType::kTH2F, {nAntideuteronsAxis, nAntiprotonsAxis}); + // registryCorr.add("rho_netP_netD_ue", "rho_netP_netD_ue", HistType::kTH2F, {nAntideuteronsAxis, nAntiprotonsAxis}); + registryCorr.add("rho_netP_netD_fullEvent", "rho_netP_netD_fullEvent", HistType::kTH3F, {nAntideuteronsAxis, nAntiprotonsAxis, subsampleAxis}); + + // Efficiency histograms jet + // registryCorr.add("q1d_jet", "q1d_jet", HistType::kTH3F, {nAntideuteronsAxis, ptPerNucleonAxis, multiplicityAxis}); + // registryCorr.add("q1p_jet", "q1p_jet", HistType::kTH3F, {nAntiprotonsAxis, ptPerNucleonAxis, multiplicityAxis}); + // registryCorr.add("q1d_square_jet", "q1d_square_jet", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarD2Axis, multiplicityAxis}); + // registryCorr.add("q1p_square_jet", "q1p_square_jet", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarP2Axis, multiplicityAxis}); + // registryCorr.add("q1d_q1p_jet", "q1d_q1p_jet", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarDnBarPAxis, multiplicityAxis}); + + // Efficiency histograms UE + // registryCorr.add("q1d_ue", "q1d_ue", HistType::kTH3F, {nAntideuteronsAxis, ptPerNucleonAxis, multiplicityAxis}); + // registryCorr.add("q1p_ue", "q1p_ue", HistType::kTH3F, {nAntiprotonsAxis, ptPerNucleonAxis, multiplicityAxis}); + // registryCorr.add("q1d_square_ue", "q1d_square_ue", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarD2Axis, multiplicityAxis}); + // registryCorr.add("q1p_square_ue", "q1p_square_ue", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarP2Axis, multiplicityAxis}); + // registryCorr.add("q1d_q1p_ue", "q1d_q1p_ue", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarDnBarPAxis, multiplicityAxis}); + + // Efficiency histograms full event + registryCorr.add("q1d_fullEvent", "q1d_fullEvent", HistType::kTHnSparseD, {nAntideuteronsAxis, ptPerNucleonAxis, multiplicityAxis, subsampleAxis}); + registryCorr.add("q1p_fullEvent", "q1p_fullEvent", HistType::kTHnSparseD, {nAntiprotonsAxis, ptPerNucleonAxis, multiplicityAxis, subsampleAxis}); + registryCorr.add("q1d_square_fullEvent", "q1d_square_fullEvent", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarD2Axis, multiplicityAxis, subsampleAxis}); + registryCorr.add("q1p_square_fullEvent", "q1p_square_fullEvent", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarP2Axis, multiplicityAxis, subsampleAxis}); + registryCorr.add("q1d_q1p_fullEvent", "q1d_q1p_fullEvent", HistType::kTHnSparseD, {ptPerNucleonAxis, ptPerNucleonAxis, nBarDnBarPAxis, multiplicityAxis, subsampleAxis}); + } + } + + void getReweightingHistograms(o2::framework::Service const& ccdbObj, TString filepath, TString antip, TString antilambda, TString antisigma, TString antixi, TString antiomega, TString jet, TString ue) + { + TList* list = ccdbObj->get(filepath.Data()); + if (!list) { + LOGP(error, "Could not retrieve the list from CCDB"); + return; + } + + // Get reweighting histograms for primary fraction + primaryAntiprotons = static_cast(list->FindObject(antip)); + primaryAntiLambda = static_cast(list->FindObject(antilambda)); + primaryAntiSigma = static_cast(list->FindObject(antisigma)); + primaryAntiXi = static_cast(list->FindObject(antixi)); + primaryAntiOmega = static_cast(list->FindObject(antiomega)); + + if (!primaryAntiprotons || !primaryAntiSigma || !primaryAntiLambda || !primaryAntiXi || !primaryAntiOmega) { + LOGP(error, "Missing one or more reweighting histograms for primary fraction in CCDB list"); + } + + // Get reweighting histograms for efficiency + antiprotonsInsideJets = static_cast(list->FindObject(jet)); + antiprotonsPerpCone = static_cast(list->FindObject(ue)); + if (!antiprotonsInsideJets || !antiprotonsPerpCone) { + LOGP(error, "Missing one or more reweighting histograms for efficiency in CCDB list"); + } + + LOGP(info, "Successfully loaded reweighting histograms from CCDB path"); + } + + // Get first ancestor + aod::McParticle getFirstAncestor(aod::McParticle const& particle, aod::McParticles const& mcParticles) + { + auto current = particle; + + // If already physical primary, return it + if (current.isPhysicalPrimary()) + return current; + + while (current.has_mothers()) { + auto motherId = current.mothersIds()[0]; + + // Stop if motherId is invalid + if (motherId < 0 || motherId >= mcParticles.size()) { + break; + } + + // Move up the chain + current = mcParticles.iteratorAt(motherId); + + if (current.isPhysicalPrimary()) + break; + } + + return current; + } + + // Check if particle is a physical primary or a decay product of a heavy-flavor hadron + bool isPhysicalPrimaryOrFromHF(aod::McParticle const& particle, aod::McParticles const& mcParticles) + { + // Keep only pi, K, p, e, mu + int pdg = std::abs(particle.pdgCode()); + if (!(pdg == PDG_t::kPiPlus || pdg == PDG_t::kKPlus || pdg == PDG_t::kProton || pdg == PDG_t::kElectron || pdg == PDG_t::kMuonMinus)) + return false; + + // Constants for identifying heavy-flavor (charm and bottom) content from PDG codes + static constexpr int kCharmQuark = 4; + static constexpr int kBottomQuark = 5; + static constexpr int hundreds = 100; + static constexpr int thousands = 1000; + + // Check if particle is from heavy-flavor decay + bool fromHF = false; + if (particle.has_mothers()) { + auto mother = mcParticles.iteratorAt(particle.mothersIds()[0]); + int motherPdg = std::abs(mother.pdgCode()); + fromHF = (motherPdg / hundreds == kCharmQuark || motherPdg / hundreds == kBottomQuark || motherPdg / thousands == kCharmQuark || motherPdg / thousands == kBottomQuark); + } + + // Select only physical primary particles or from heavy-flavor + return (particle.isPhysicalPrimary() || fromHF); + } + + /* + // Compute two unit vectors perpendicular to p + 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); + } + */ + + // Compute two transverse directions orthogonal to vector p + void getPerpendicularDirections(const TVector3& p, TVector3& u1, TVector3& u2) + { + // Get momentum components + double px = p.X(); + double py = p.Y(); + double pz = p.Z(); + + // Precompute squared terms + double px2 = px * px; + double py2 = py * py; + double pz2 = pz * pz; + double pz4 = pz2 * pz2; + + // Case 1: vector along z-axis -> undefined perpendiculars + if (px == 0 && py == 0) { + u1.SetXYZ(0, 0, 0); + u2.SetXYZ(0, 0, 0); + return; + } + + // Case 2: px = 0 -> avoid division by zero + if (px == 0 && py != 0) { + double ux = std::sqrt(py2 - pz4 / py2); + double uy = -pz2 / py; + u1.SetXYZ(ux, uy, pz); + u2.SetXYZ(-ux, uy, pz); + return; + } + + // Case 3: py = 0 -> avoid division by zero + if (py == 0 && px != 0) { + double ux = -pz2 / px; + double uy = std::sqrt(px2 - pz4 / px2); + u1.SetXYZ(ux, uy, pz); + u2.SetXYZ(ux, -uy, pz); + return; + } + + // General case: solve quadratic for perpendicular vectors + 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; + + // Invalid or degenerate solutions + if (delta < 0 || a == 0) { + u1.SetXYZ(0, 0, 0); + u2.SetXYZ(0, 0, 0); + return; + } + + // Solution 1 + double u1x = (-b + std::sqrt(delta)) / (2.0 * a); + double u1y = (-pz2 - px * u1x) / py; + u1.SetXYZ(u1x, u1y, pz); + + // Solution 2 + double u2x = (-b - std::sqrt(delta)) / (2.0 * a); + double u2y = (-pz2 - px * u2x) / py; + u2.SetXYZ(u2x, u2y, pz); + } + + // Compute delta phi + 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; + } + + // Find bin + int findBin(const std::vector& edges, double value) + { + auto it = std::upper_bound(edges.begin(), edges.end(), value); + int index = static_cast(it - edges.begin()) - 1; + if (index < 0 || index >= static_cast(edges.size()) - 1) { + return -1; // value is out of bounds + } + return index; + } + + // 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) + { + static constexpr int MinTpcCr = 70; + static constexpr double MaxChi2Tpc = 4.0; + static constexpr double MaxChi2Its = 36.0; + static constexpr double MinPtTrack = 0.1; + static constexpr double DcaxyMaxTrackPar0 = 0.0105; + static constexpr double DcaxyMaxTrackPar1 = 0.035; + static constexpr double DcaxyMaxTrackPar2 = 1.1; + static constexpr 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 (track.tpcChi2NCl() > MaxChi2Tpc) + return false; + if (track.itsChi2NCl() > MaxChi2Its) + return false; + if (std::fabs(track.eta()) > maxEta) + 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 for antinuclei + template + bool passedTrackSelection(const AntinucleusTrack& track) + { + if (requirePvContributor && !(track.isPVContributor())) + return false; + if (!track.hasITS()) + return false; + if ((!hasITSHit(track, 1)) && (!hasITSHit(track, 2)) && (!hasITSHit(track, 3))) + return false; + if (track.itsNCls() < minItsNclusters) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minTpcNcrossedRows) + return false; + if (track.tpcChi2NCl() < minChiSquareTpc) + 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; + } + + // Single-track selection for antinuclei candidates with systematic variations + template + bool passedTrackSelectionSyst(const AntinucleusTrack& track, int isyst) + { + // Define cut settings + static std::vector minItsNclustersSyst = { + 3, 7, 6, 6, 6, 4, 5, 6, 7, 4, + 4, 3, 6, 3, 7, 5, 4, 6, 5, 7, + 6, 5, 3, 5, 4, 3, 6, 6, 4, 7, + 3, 4, 3, 5, 7, 6, 6, 4, 3, 5, + 4, 7, 3, 6, 4, 5, 6, 3, 7, 5}; + + static std::vector minTpcNcrossedRowsSyst = { + 90, 108, 112, 119, 92, 111, 98, 105, 86, 117, + 118, 101, 87, 116, 82, 109, 80, 115, 89, 97, + 107, 120, 104, 94, 100, 93, 103, 84, 102, 85, + 108, 96, 113, 117, 91, 88, 99, 110, 106, 83, + 118, 95, 112, 114, 109, 89, 116, 92, 98, 120}; + + static std::vector maxChiSquareTpcSyst = { + 4.28, 4.81, 4.43, 4.02, 3.38, 3.58, 3.11, 4.17, 3.51, 4.53, + 4.90, 3.07, 3.20, 4.86, 4.62, 3.91, 3.98, 4.38, 3.66, 3.84, + 3.03, 3.14, 4.96, 4.07, 4.75, 4.32, 3.31, 3.78, 4.11, 3.23, + 3.87, 3.70, 4.99, 4.48, 4.69, 4.25, 3.93, 3.45, 4.58, 3.35, + 3.18, 3.60, 4.21, 3.75, 4.64, 4.35, 3.26, 3.42, 4.15, 3.09}; + + static std::vector maxChiSquareItsSyst = { + 42.84, 48.66, 39.27, 34.09, 43.73, 36.98, 30.23, 49.11, 37.67, 35.10, + 44.55, 46.79, 38.92, 40.66, 47.14, 33.46, 30.88, 41.32, 45.90, 39.68, + 31.42, 32.71, 43.17, 36.04, 49.80, 33.95, 31.89, 38.37, 48.08, 35.87, + 47.61, 44.02, 32.15, 46.21, 34.75, 40.17, 37.14, 30.55, 45.42, 42.30, + 41.79, 33.21, 39.12, 47.98, 36.52, 31.58, 49.44, 38.02, 35.56, 43.49}; + + // Track Selection + if (requirePvContributor && !(track.isPVContributor())) + return false; + if (!track.hasITS()) + return false; + if (track.itsNCls() < minItsNclustersSyst[isyst]) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minTpcNcrossedRowsSyst[isyst]) + return false; + if (track.tpcChi2NCl() > maxChiSquareTpcSyst[isyst]) + return false; + if (track.itsChi2NCl() > maxChiSquareItsSyst[isyst]) + return false; + if (track.eta() < minEta || track.eta() > maxEta) + return false; + if (track.pt() < minPt) + return false; + + return true; + } + + // Selection of high-purity antiproton sample + template + bool isHighPurityAntiproton(const AntiprotonTrack& track) + { + // variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double pt = track.pt(); + static constexpr double PtThreshold = 0.5; + static constexpr 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; + } + + // Selection of (anti)protons + template + bool isProton(const ProtonTrack& track) + { + // Constants + static constexpr double kPtThreshold = 0.6; + static constexpr double kNsigmaMax = 3.0; + + // PID variables and transverse momentum of the track + const double nsigmaTPC = track.tpcNSigmaPr(); + const double nsigmaTOF = track.tofNSigmaPr(); + const double pt = track.pt(); + + // Apply TPC PID cut + if (std::abs(nsigmaTPC) > kNsigmaMax) + return false; + + // Low-pt: TPC PID is sufficient + if (pt < kPtThreshold) + return true; + + // High-pt: require valid TOF match and pass TOF PID + return (track.hasTOF() && std::abs(nsigmaTOF) < kNsigmaMax); + } + + // Selection of (anti)deuterons + template + bool isDeuteron(const DeuteronTrack& track) + { + // Constants + static constexpr double kPtThreshold = 1.0; + static constexpr double kNsigmaMax = 3.0; + + // PID variables and transverse momentum of the track + const double nsigmaTPC = track.tpcNSigmaDe(); + const double nsigmaTOF = track.tofNSigmaDe(); + const double pt = track.pt(); + + // Apply TPC PID cut + if (std::abs(nsigmaTPC) > kNsigmaMax) + return false; + + // Low-pt: TPC PID is sufficient + if (pt < kPtThreshold) + return true; + + // High-pt: require valid TOF match and pass TOF PID + return (track.hasTOF() && std::abs(nsigmaTOF) < kNsigmaMax); + } + + // Process Data + void processData(SelectedCollisions::iterator const& collision, AntiNucleiTracks const& tracks, aod::BCsWithTimestamps const&) + { + // Event counter: before event selection + registryData.fill(HIST("number_of_events_data"), 0.5); + registryData.fill(HIST("settingData"), minJetPt.value, rJet.value); + + // Retrieve the bunch crossing information with timestamps from the collision + auto bc = collision.template bc_as(); + initCCDB(bc); + + // If skimmed processing is enabled, apply Zorro trigger selection + if (cfgSkimmedProcessing && !zorro.isSelected(collision.template bc_as().globalBC())) { + return; + } + registryData.fill(HIST("number_of_events_data"), 1.5); + + // Apply standard event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // Event counter: after event selection + registryData.fill(HIST("number_of_events_data"), 2.5); + + // Reject events near the ITS Read-Out Frame border + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + return; + registryData.fill(HIST("number_of_events_data"), 3.5); + + // Reject events at the Time Frame border + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + return; + registryData.fill(HIST("number_of_events_data"), 4.5); + + // Require at least one ITS-TPC matched track + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return; + registryData.fill(HIST("number_of_events_data"), 5.5); + + // Reject events with same-bunch pileup + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + registryData.fill(HIST("number_of_events_data"), 6.5); + + // Require consistent FT0 vs PV z-vertex + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + registryData.fill(HIST("number_of_events_data"), 7.5); + + // Require TOF match for at least one vertex track + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + return; + registryData.fill(HIST("number_of_events_data"), 8.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); + + // Fill TPC signal vs p*sign for PID calibration + bool heliumPID = track.pidForTracking() == o2::track::PID::Helium3; + float correctedTpcInnerParam = (heliumPID && cfgCompensatePIDinTracking) ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); + registryData.fill(HIST("tpcsignal_data"), correctedTpcInnerParam * track.sign(), track.tpcSignal()); + } + + // Reject empty events + if (fjParticles.empty()) + return; + registryData.fill(HIST("number_of_events_data"), 9.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] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // 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 (jetMinusBkg.pt() < minJetPt) + continue; + + // Apply area cut if required + double normalizedJetArea = jet.area() / (PI * rJet * rJet); + if (applyAreaCut && normalizedJetArea > maxNormalizedJetArea) + continue; + isAtLeastOneJetSelected = true; + + // Perpendicular cones + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Fill histogram with jet effective area / piR^2 + registryData.fill(HIST("jetEffectiveAreaOverPiR2"), jet.area() / (PI * rJet * rJet)); + + // Get jet constituents + std::vector jetConstituents = jet.constituents(); + + // 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; + + // Define 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); + } + + // Apply DCA selections + if (std::fabs(dcaxy) > maxDcaxy || std::fabs(dcaz) > maxDcaz) + continue; + + // Fill angular distribution of tracks wrt jet axis + TVector3 trackDirection(track.px(), track.py(), track.pz()); + double thetaTrackJet = (180.0 / PI) * jetAxis.Angle(trackDirection); + registryData.fill(HIST("theta_track_jet"), jet.pt(), thetaTrackJet); + + // Particle identification using the ITS cluster size + bool passedItsPidProt(true), passedItsPidDeut(true), passedItsPidHel(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITSdeut = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITShel3 = static_cast(itsResponse.nSigmaITS(track)); + + // Fill nsigmaITS for antiproton candidates + if (isHighPurityAntiproton(track)) { + registryData.fill(HIST("antiproton_nsigma_its_data"), pt, nSigmaITSprot); + } + + if (applyItsPid && pt < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMin || nSigmaITSprot > nSigmaItsMax)) { + passedItsPidProt = false; + } + if (applyItsPid && pt < ptMaxItsPidDeut && (nSigmaITSdeut < nSigmaItsMin || nSigmaITSdeut > nSigmaItsMax)) { + passedItsPidDeut = false; + } + if (applyItsPid && (2.0 * pt) < ptMaxItsPidHel && (nSigmaITShel3 < nSigmaItsMin || nSigmaITShel3 > nSigmaItsMax)) { + passedItsPidHel = false; + } + + // Fill histograms for 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); + // custom nsigma He3 based on bethe bloch fit of TPC signal + double tpcSignal = track.tpcSignal(); + double expectedSignalHe3 = tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() * 2. / o2::constants::physics::MassHelium3), cfgBetheBlochParams.value[0], cfgBetheBlochParams.value[1], cfgBetheBlochParams.value[2], cfgBetheBlochParams.value[3], cfgBetheBlochParams.value[4]); + double sigmaHe3 = expectedSignalHe3 * cfgBetheBlochParams.value[4]; + double nSigmaTPCHe3Custom = (tpcSignal - expectedSignalHe3) / sigmaHe3; + registryData.fill(HIST("antihelium3_jet_tpc_custom"), 2.0 * pt, nSigmaTPCHe3Custom); + } + } + + // Fill histograms for matter + if (track.sign() > 0) { + if (passedItsPidDeut) { + registryData.fill(HIST("deuteron_jet_tpc"), pt, nsigmaTPCDe); + if (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); + } + } + } + + // Loop over tracks in the underlying event + for (auto const& track : tracks) { + + // Get corresponding track and apply track selection criteria + if (!passedTrackSelection(track)) + continue; + + // Calculate the angular distance between the track and underlying event axes in eta-phi space + 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); + + // Determine the maximum allowed distance from UE axes for particle selection + double maxConeRadius = coneRadius; + if (applyAreaCut) { + maxConeRadius = std::sqrt(maxNormalizedJetArea) * rJet; + } + + // Reject tracks that lie outside the maxConeRadius from both UE axes + if (deltaRUe1 > maxConeRadius && deltaRUe2 > maxConeRadius) + continue; + + // Define 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); + } + + // Apply DCA selections + if (std::fabs(dcaxy) > maxDcaxy || std::fabs(dcaz) > maxDcaz) + continue; + + // Particle identification using the ITS cluster size + bool passedItsPidProt(true), passedItsPidDeut(true), passedItsPidHel(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITSdeut = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITShel3 = static_cast(itsResponse.nSigmaITS(track)); + + if (applyItsPid && pt < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMin || nSigmaITSprot > nSigmaItsMax)) { + passedItsPidProt = false; + } + if (applyItsPid && pt < ptMaxItsPidDeut && (nSigmaITSdeut < nSigmaItsMin || nSigmaITSdeut > nSigmaItsMax)) { + passedItsPidDeut = false; + } + if (applyItsPid && (2.0 * pt) < ptMaxItsPidHel && (nSigmaITShel3 < nSigmaItsMin || nSigmaITShel3 > nSigmaItsMax)) { + passedItsPidHel = false; + } + + // Fill histograms for 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); + // custom nsigma He3 based on bethe bloch fit of TPC signal + double tpcSignal = track.tpcSignal(); + double expectedSignalHe3 = tpc::BetheBlochAleph(static_cast(track.tpcInnerParam() * 2. / o2::constants::physics::MassHelium3), cfgBetheBlochParams.value[0], cfgBetheBlochParams.value[1], cfgBetheBlochParams.value[2], cfgBetheBlochParams.value[3], cfgBetheBlochParams.value[4]); + double sigmaHe3 = expectedSignalHe3 * cfgBetheBlochParams.value[4]; + double nSigmaTPCHe3Custom = (tpcSignal - expectedSignalHe3) / sigmaHe3; + registryData.fill(HIST("antihelium3_ue_tpc_custom"), 2.0 * pt, nSigmaTPCHe3Custom); + } + } + + // Fill histograms for matter + if (track.sign() > 0) { + if (passedItsPidDeut) { + registryData.fill(HIST("deuteron_ue_tpc"), pt, nsigmaTPCDe); + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc && track.hasTOF()) + registryData.fill(HIST("deuteron_ue_tof"), pt, nsigmaTOFDe); + } + if (passedItsPidHel) { + registryData.fill(HIST("helium3_ue_tpc"), 2.0 * pt, nsigmaTPCHe); + } + } + } + } + // Event counter: events with at least one jet selected + if (isAtLeastOneJetSelected) { + registryData.fill(HIST("number_of_events_data"), 10.5); + } + } + PROCESS_SWITCH(AntinucleiInJets, processData, "Process Data", true); + + // Charged-particle multiplicity in events with selected jets (Run 3) or ptTrigger > threshold (Run 2-like) + void processMultEvents(SelectedCollisions::iterator const& collision, AntiNucleiTracks const& tracks) + { + // Apply event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + return; + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + return; + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return; + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + return; + + // Initialize variable to store the maximum pt in the event + double ptMax(0.0); + + // Loop over reconstructed tracks + int id(-1); + std::vector fjParticles; + for (auto const& track : tracks) { + id++; + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + if (track.pt() > ptMax) { + ptMax = track.pt(); + } + + // 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.empty()) { + return; + } + + // Fill charged-particle multiplicity for events with leading track having pt>threshold + if (ptMax > ptLeadingMin) { + registryMult.fill(HIST("multiplicityEvtsPtLeading"), fjParticles.size()); + } + + // 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] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // 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 (jetMinusBkg.pt() < minJetPt) + continue; + + // Apply area cut if required + double normalizedJetArea = jet.area() / (PI * rJet * rJet); + if (applyAreaCut && normalizedJetArea > maxNormalizedJetArea) + continue; + isAtLeastOneJetSelected = true; + } + + // Fill histogram of charged-particle multiplicity for events containing at least one selected jet + if (isAtLeastOneJetSelected) { + registryMult.fill(HIST("multiplicityEvtsWithJet"), fjParticles.size()); + } + } + PROCESS_SWITCH(AntinucleiInJets, processMultEvents, "Process Mult Events", false); + + // Process QC + void processQC(SelectedCollisions::iterator const& collision, AntiNucleiTracks const& tracks) + { + // Apply event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + return; + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + return; + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return; + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + 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.empty()) + 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)); + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // 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); + registryQC.fill(HIST("ptDistributionJetCone"), ptJetBeforeSub); + registryQC.fill(HIST("ptDistributionJet"), ptJetAfterSub); + + if (jetMinusBkg.pt() < 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), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + 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); + + // Define preslices to group MC tracks and MC particles by their associated MC collision + Preslice mcTracksPerMcCollision = o2::aod::track::collisionId; + Preslice mcParticlesPerMcCollision = o2::aod::mcparticle::mcCollisionId; + + // Antinuclei reconstruction efficiency + void processAntinucleiEfficiency(GenCollisionsMc const& genCollisions, RecCollisionsMc const& recCollisions, AntiNucleiTracksMc const& mcTracks, aod::McParticles const& mcParticles) + { + // Loop over generated collisions + for (const auto& collision : genCollisions) { + + // Apply event selection: require vertex position to be within the allowed z range + if (std::fabs(collision.posZ()) > zVtx) + continue; + + // Get particles in this MC collision + const auto mcParticlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, collision.globalIndex()); + + // Loop over all generated Monte Carlo particles for the selected event + for (const auto& particle : mcParticlesThisMcColl) { + + // Select primary particles + if (!particle.isPhysicalPrimary()) + continue; + + // Select particles within the specified pseudorapidity interval + if (particle.eta() < minEta || particle.eta() > maxEta) + continue; + + // Process different particle species based on PDG code + switch (particle.pdgCode()) { + case PDG_t::kProtonBar: + registryMC.fill(HIST("antip_gen_jet"), particle.pt()); + registryMC.fill(HIST("antip_gen_ue"), particle.pt()); + registryMC.fill(HIST("protonBar"), particle.pt()); + break; + case o2::constants::physics::Pdg::kDeuteron: + registryMC.fill(HIST("deuteron_gen_jet"), particle.pt()); + registryMC.fill(HIST("deuteron_gen_ue"), particle.pt()); + break; + case -o2::constants::physics::Pdg::kDeuteron: + registryMC.fill(HIST("antideuteron_gen_jet"), particle.pt()); + registryMC.fill(HIST("antideuteron_gen_ue"), particle.pt()); + break; + case o2::constants::physics::Pdg::kHelium3: + registryMC.fill(HIST("helium3_gen_jet"), particle.pt()); + registryMC.fill(HIST("helium3_gen_ue"), particle.pt()); + break; + case -o2::constants::physics::Pdg::kHelium3: + registryMC.fill(HIST("antihelium3_gen_jet"), particle.pt()); + registryMC.fill(HIST("antihelium3_gen_ue"), particle.pt()); + break; + // Histograms for re-weighting + case PDG_t::kLambda0Bar: + registryMC.fill(HIST("lambdaBar"), particle.pt()); + break; + case PDG_t::kXiPlusBar: + registryMC.fill(HIST("xiBar"), particle.pt()); + break; + case PDG_t::kOmegaPlusBar: + registryMC.fill(HIST("omegaBar"), particle.pt()); + break; + case PDG_t::kSigmaBarMinus: + registryMC.fill(HIST("sigmaBar"), particle.pt()); + break; + } + } + } + + // Loop over all reconstructed collisions + for (const auto& collision : recCollisions) { + + // Count all generated events before applying any event selection criteria + registryMC.fill(HIST("number_of_events_mc_nuclei_efficiency"), 0.5); + + // Apply event selection: require sel8 and vertex position within the allowed z range + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + continue; + + // Count events that pass the selection criteria + registryMC.fill(HIST("number_of_events_mc_nuclei_efficiency"), 1.5); + + // Reject events near the ITS Read-Out Frame border + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + continue; + registryMC.fill(HIST("number_of_events_mc_nuclei_efficiency"), 2.5); + + // Reject events at the Time Frame border + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + continue; + registryMC.fill(HIST("number_of_events_mc_nuclei_efficiency"), 3.5); + + // Require at least one ITS-TPC matched track + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + continue; + registryMC.fill(HIST("number_of_events_mc_nuclei_efficiency"), 4.5); + + // Reject events with same-bunch pileup + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + continue; + registryMC.fill(HIST("number_of_events_mc_nuclei_efficiency"), 5.5); + + // Require consistent FT0 vs PV z-vertex + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + registryMC.fill(HIST("number_of_events_mc_nuclei_efficiency"), 6.5); + + // Require TOF match for at least one vertex track + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + continue; + registryMC.fill(HIST("number_of_events_mc_nuclei_efficiency"), 7.5); + + // Get tracks in this MC collision + const auto mcTracksThisMcColl = mcTracks.sliceBy(mcTracksPerMcCollision, collision.globalIndex()); + + // Loop over all reconstructed MC tracks + for (auto const& track : mcTracksThisMcColl) { + + // Apply standard track selection criteria + if (!passedTrackSelection(track)) + continue; + + // Cut on transverse and longitudinal distance of closest approach + if (std::fabs(track.dcaXY()) > maxDcaxy || std::fabs(track.dcaZ()) > maxDcaz) + continue; + + // Skip tracks that are not associated with a true MC particle + if (!track.has_mcParticle()) + continue; + const auto particle = track.mcParticle(); + + // **************************************************************************************************************** + + // Systematic uncertainty on primary fraction + if (track.sign() < 0 && particle.pdgCode() == PDG_t::kProtonBar) { + + // Primary antiprotons + if (particle.isPhysicalPrimary()) { + + // Initialize weights + double wPrimStd(1.0), wPrimUp(1.0), wPrimLow(1.0); + + // Weight assignment + if (particle.pt() < primaryAntiprotons->GetXaxis()->GetXmax()) { + int ipt = primaryAntiprotons->FindBin(particle.pt()); + wPrimStd = primaryAntiprotons->GetBinContent(ipt); + wPrimUp = wPrimStd + primaryAntiprotons->GetBinError(ipt); + wPrimLow = wPrimStd - primaryAntiprotons->GetBinError(ipt); + } + + // Fill histograms + registryMC.fill(HIST("antip_prim_pythia"), track.pt()); + registryMC.fill(HIST("antip_prim_std"), track.pt(), wPrimStd); + registryMC.fill(HIST("antip_prim_up"), track.pt(), wPrimUp); + registryMC.fill(HIST("antip_prim_low"), track.pt(), wPrimLow); + } + + // Secondary antiprotons from material + if (!particle.isPhysicalPrimary() && !particle.has_mothers()) { + + // Fill histograms + registryMC.fill(HIST("antip_sec_pythia"), track.pt()); + registryMC.fill(HIST("antip_sec_std"), track.pt()); + registryMC.fill(HIST("antip_sec_up"), track.pt()); + registryMC.fill(HIST("antip_sec_low"), track.pt()); + } + + // Secondary antiprotons from weak decays + if (!particle.isPhysicalPrimary() && particle.has_mothers()) { + + // Get first ancestor + auto ancestor = getFirstAncestor(particle, mcParticles); + double wSecStd(1.0), wSecUp(1.0), wSecLow(1.0); + + // Antiprotons from antiSigma + if (ancestor.pdgCode() == PDG_t::kSigmaBarMinus && ancestor.pt() < primaryAntiSigma->GetXaxis()->GetXmax()) { + int ipt = primaryAntiSigma->FindBin(ancestor.pt()); + wSecStd = primaryAntiSigma->GetBinContent(ipt); + wSecUp = wSecStd + primaryAntiSigma->GetBinError(ipt); + wSecLow = wSecStd - primaryAntiSigma->GetBinError(ipt); + } + + // Antiprotons from antiLambda0 + if (ancestor.pdgCode() == PDG_t::kLambda0Bar && ancestor.pt() < primaryAntiLambda->GetXaxis()->GetXmax()) { + int ipt = primaryAntiLambda->FindBin(ancestor.pt()); + wSecStd = primaryAntiLambda->GetBinContent(ipt); + wSecUp = wSecStd + primaryAntiLambda->GetBinError(ipt); + wSecLow = wSecStd - primaryAntiLambda->GetBinError(ipt); + } + + // Antiprotons from antiXi + if (ancestor.pdgCode() == PDG_t::kXiPlusBar && ancestor.pt() < primaryAntiXi->GetXaxis()->GetXmax()) { + int ipt = primaryAntiXi->FindBin(ancestor.pt()); + wSecStd = primaryAntiXi->GetBinContent(ipt); + wSecUp = wSecStd + primaryAntiXi->GetBinError(ipt); + wSecLow = wSecStd - primaryAntiXi->GetBinError(ipt); + } + + // Antiprotons from antiXi0 + if (ancestor.pdgCode() == -o2::constants::physics::Pdg::kXi0 && ancestor.pt() < primaryAntiXi->GetXaxis()->GetXmax()) { + int ipt = primaryAntiXi->FindBin(ancestor.pt()); + wSecStd = primaryAntiXi->GetBinContent(ipt); + wSecUp = wSecStd + primaryAntiXi->GetBinError(ipt); + wSecLow = wSecStd - primaryAntiXi->GetBinError(ipt); + } + + // Antiprotons from antiOmega + if (ancestor.pdgCode() == PDG_t::kOmegaPlusBar && ancestor.pt() < primaryAntiOmega->GetXaxis()->GetXmax()) { + int ipt = primaryAntiOmega->FindBin(ancestor.pt()); + wSecStd = primaryAntiOmega->GetBinContent(ipt); + wSecUp = wSecStd + primaryAntiOmega->GetBinError(ipt); + wSecLow = wSecStd - primaryAntiOmega->GetBinError(ipt); + } + + // Fill histograms + registryMC.fill(HIST("antip_sec_pythia"), track.pt()); + registryMC.fill(HIST("antip_sec_std"), track.pt(), wSecStd); + registryMC.fill(HIST("antip_sec_up"), track.pt(), wSecUp); + registryMC.fill(HIST("antip_sec_low"), track.pt(), wSecLow); + } + } + + // **************************************************************************************************************** + + // Select only physical primary particles + if (!particle.isPhysicalPrimary()) + continue; + + // Retrieve PID responses from TPC and TOF detectors for proton, deuteron, helium-3 + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double nsigmaTPCDe = track.tpcNSigmaDe(); + double nsigmaTOFDe = track.tofNSigmaDe(); + double nsigmaTPCHe = track.tpcNSigmaHe(); + double pt = track.pt(); + + // particle identification using the ITS cluster size + bool passedItsPidProt(true), passedItsPidDeut(true), passedItsPidHel(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITSdeut = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITShel3 = static_cast(itsResponse.nSigmaITS(track)); + + if (applyItsPid && pt < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMin || nSigmaITSprot > nSigmaItsMax)) { + passedItsPidProt = false; + } + if (applyItsPid && pt < ptMaxItsPidDeut && (nSigmaITSdeut < nSigmaItsMin || nSigmaITSdeut > nSigmaItsMax)) { + passedItsPidDeut = false; + } + if (applyItsPid && (2.0 * pt) < ptMaxItsPidHel && (nSigmaITShel3 < nSigmaItsMin || nSigmaITShel3 > nSigmaItsMax)) { + passedItsPidHel = false; + } + + // Fill nsigmaITS for antiproton candidates + if (track.sign() < 0 && particle.pdgCode() == PDG_t::kProtonBar && isHighPurityAntiproton(track)) { + registryMC.fill(HIST("antiproton_nsigma_its_mc"), pt, nSigmaITSprot); + } + + // Fill histograms of antiprotons + if (track.sign() < 0 && particle.pdgCode() == PDG_t::kProtonBar && passedItsPidProt) { + if (nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { + registryMC.fill(HIST("antip_rec_tpc_jet"), track.pt()); + registryMC.fill(HIST("antip_rec_tpc_ue"), track.pt()); + + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) { + registryMC.fill(HIST("antip_rec_tof_jet"), track.pt()); + registryMC.fill(HIST("antip_rec_tof_ue"), track.pt()); + } + } + } + + // Fill histograms of antideuterons + if (track.sign() < 0 && particle.pdgCode() == -o2::constants::physics::Pdg::kDeuteron && passedItsPidDeut) { + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc) { + registryMC.fill(HIST("antideuteron_rec_tpc_jet"), track.pt()); + registryMC.fill(HIST("antideuteron_rec_tpc_ue"), track.pt()); + + if (track.hasTOF() && nsigmaTOFDe > minNsigmaTof && nsigmaTOFDe < maxNsigmaTof) { + registryMC.fill(HIST("antideuteron_rec_tof_jet"), track.pt()); + registryMC.fill(HIST("antideuteron_rec_tof_ue"), track.pt()); + } + } + } + + // Fill histograms of deuterons + if (track.sign() > 0 && particle.pdgCode() == o2::constants::physics::Pdg::kDeuteron && passedItsPidDeut) { + if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc) { + registryMC.fill(HIST("deuteron_rec_tpc_jet"), track.pt()); + registryMC.fill(HIST("deuteron_rec_tpc_ue"), track.pt()); + if (track.hasTOF() && nsigmaTOFDe > minNsigmaTof && nsigmaTOFDe < maxNsigmaTof) { + registryMC.fill(HIST("deuteron_rec_tof_jet"), track.pt()); + registryMC.fill(HIST("deuteron_rec_tof_ue"), track.pt()); + } + } + } + + // Fill histograms of antihelium3 + if (track.sign() < 0 && particle.pdgCode() == -o2::constants::physics::Pdg::kHelium3 && passedItsPidHel) { + if (nsigmaTPCHe > minNsigmaTpc && nsigmaTPCHe < maxNsigmaTpc) { + registryMC.fill(HIST("antihelium3_rec_tpc_jet"), 2.0 * track.pt()); + registryMC.fill(HIST("antihelium3_rec_tpc_ue"), 2.0 * track.pt()); + } + } + + // Fill histograms of helium3 + if (track.sign() > 0 && particle.pdgCode() == o2::constants::physics::Pdg::kHelium3 && passedItsPidHel) { + if (nsigmaTPCHe > minNsigmaTpc && nsigmaTPCHe < maxNsigmaTpc) { + registryMC.fill(HIST("helium3_rec_tpc_jet"), 2.0 * track.pt()); + registryMC.fill(HIST("helium3_rec_tpc_ue"), 2.0 * track.pt()); + } + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processAntinucleiEfficiency, "process antinuclei efficiency", false); + + // Generated events + void processJetsMCgen(GenCollisionsMc const& collisions, aod::McParticles const& mcParticles) + { + // Define per-event particle containers + std::vector fjParticles; + std::vector protonMomentum; + + // Event counter + int eventCounter = 0; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Loop over all simulated collisions + for (const auto& collision : collisions) { + + // Increment event counter + eventCounter++; + + // Clear containers at the start of the event loop + fjParticles.clear(); + protonMomentum.clear(); + + // Event counter: before event selection + registryMC.fill(HIST("genEvents"), 0.5); + + // Apply event selection: require vertex position to be within the allowed z range + if (std::fabs(collision.posZ()) > zVtx) + continue; + + // Event counter: after event selection + registryMC.fill(HIST("genEvents"), 1.5); + + // Get particles in this MC collision + const auto mcParticlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, collision.globalIndex()); + + // Loop over MC particles + for (const auto& particle : mcParticlesThisMcColl) { + + // Select physical primary particles or HF decay products + if (!isPhysicalPrimaryOrFromHF(particle, mcParticles)) + continue; + + // Select particles within acceptance + static constexpr double MinPtParticle = 0.1; + if (particle.eta() < minEta || particle.eta() > maxEta || particle.pt() < MinPtParticle) + continue; + + // Store 3-momentum vectors of antiprotons for further analysis + if (particle.pdgCode() == PDG_t::kProtonBar) { + TVector3 pVec(particle.px(), particle.py(), particle.pz()); + protonMomentum.emplace_back(pVec); + registryMC.fill(HIST("antiproton_gen_full"), particle.pt()); + } + + // 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); + fourMomentum.set_user_index(particle.pdgCode()); + fjParticles.emplace_back(fourMomentum); + } + + // Reject empty events + if (fjParticles.empty()) + continue; + registryMC.fill(HIST("genEvents"), 2.5); + + // Size of particle array + registryMC.fill(HIST("sizeParticleArray"), fjParticles.size()); + + // Cluster MC particles into jets using anti-kt algorithm + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Loop over clustered 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 (jetMinusBkg.pt() < minJetPt) + continue; + + // Apply area cut if required + double normalizedJetArea = jet.area() / (PI * rJet * rJet); + if (applyAreaCut && normalizedJetArea > maxNormalizedJetArea) + continue; + isAtLeastOneJetSelected = true; + + // Generated jets + registryMC.fill(HIST("genJets"), 0.5); + + // Analyze jet constituents + std::vector jetConstituents = jet.constituents(); + for (const auto& particle : jetConstituents) { + if (particle.user_index() != PDG_t::kProtonBar) + continue; + + if (particle.eta() < minEta || particle.eta() > maxEta) + continue; + + // Fill normalization histogram + registryMC.fill(HIST("antiproton_deltay_deltaphi_jet"), particle.eta() - jet.eta(), getDeltaPhi(particle.phi(), jet.phi())); + + // Calculate weight + double weightJet(1.0); + if (applyReweighting && particle.pt() < antiprotonsInsideJets->GetXaxis()->GetXmax()) { + int ipt = antiprotonsInsideJets->FindBin(particle.pt()); + weightJet = antiprotonsInsideJets->GetBinContent(ipt); + } + + // Fill histogram for generated antiprotons + registryMC.fill(HIST("antiproton_gen_jet"), particle.pt(), weightJet); + + // Fill 2d (pt,eta) distribution of antiprotons + registryMC.fill(HIST("antiproton_eta_pt_jet"), particle.pt(), particle.eta(), weightJet); + } + + // Set up two perpendicular cone axes for underlying event estimation + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Loop over MC particles to analyze underlying event region + for (const auto& protonVec : protonMomentum) { + + // Compute distance of particle from both perpendicular cone axes + double deltaEtaUe1 = protonVec.Eta() - ueAxis1.Eta(); + double deltaPhiUe1 = getDeltaPhi(protonVec.Phi(), ueAxis1.Phi()); + double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = protonVec.Eta() - ueAxis2.Eta(); + double deltaPhiUe2 = getDeltaPhi(protonVec.Phi(), ueAxis2.Phi()); + double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Determine the maximum allowed distance from UE axes for particle selection + double maxConeRadius = coneRadius; + if (applyAreaCut) { + maxConeRadius = std::sqrt(maxNormalizedJetArea) * rJet; + } + + // Reject tracks that lie outside the maxConeRadius from both UE axes + if (deltaRUe1 > maxConeRadius && deltaRUe2 > maxConeRadius) + continue; + + // Fill normalization histogram + registryMC.fill(HIST("antiproton_deltay_deltaphi_ue"), protonVec.Eta() - ueAxis1.Eta(), getDeltaPhi(protonVec.Phi(), ueAxis1.Phi())); + registryMC.fill(HIST("antiproton_deltay_deltaphi_ue"), protonVec.Eta() - ueAxis2.Eta(), getDeltaPhi(protonVec.Phi(), ueAxis2.Phi())); + + // Calculate weight + double weightUe(1.0); + if (applyReweighting && protonVec.Pt() < antiprotonsPerpCone->GetXaxis()->GetXmax()) { + int ipt = antiprotonsPerpCone->FindBin(protonVec.Pt()); + weightUe = antiprotonsPerpCone->GetBinContent(ipt); + } + + // Fill histogram for antiprotons in the UE + registryMC.fill(HIST("antiproton_gen_ue"), protonVec.Pt(), weightUe); + + // Fill 2d (pt,eta) distribution of antiprotons + registryMC.fill(HIST("antiproton_eta_pt_ue"), protonVec.Pt(), protonVec.Eta(), weightUe); + } + } + if (isAtLeastOneJetSelected) { + registryMC.fill(HIST("genEvents"), 3.5); + } + + // Shrink large vectors + if (eventCounter % shrinkInterval == 0) { + std::vector().swap(fjParticles); + std::vector().swap(protonMomentum); + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processJetsMCgen, "process jets mc gen", false); + + // Reconstructed events + void processJetsMCrec(RecCollisionsMc const& collisions, AntiNucleiTracksMc const& mcTracks, McParticles const&) + { + // Define per-event containers + std::vector fjParticles; + std::vector antiprotonTrackIndex; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Event counter + int eventCounter = 0; + + // Loop over all reconstructed collisions + for (const auto& collision : collisions) { + + // Configuration + registryMC.fill(HIST("settingMC"), minJetPt.value, rJet.value); + + // Increment event counter + eventCounter++; + + // Clear containers at the start of the event loop + fjParticles.clear(); + antiprotonTrackIndex.clear(); + + // Event counter: before event selection + registryMC.fill(HIST("recEvents"), 0.5); + + // Apply event selection: require sel8 and vertex position to be within the allowed z range + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + continue; + + // Event counter: after event selection + registryMC.fill(HIST("recEvents"), 1.5); + + // Reject events near the ITS Read-Out Frame border + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + continue; + registryMC.fill(HIST("recEvents"), 2.5); + + // Reject events at the Time Frame border + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + continue; + registryMC.fill(HIST("recEvents"), 3.5); + + // Require at least one ITS-TPC matched track + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + continue; + registryMC.fill(HIST("recEvents"), 4.5); + + // Reject events with same-bunch pileup + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + continue; + registryMC.fill(HIST("recEvents"), 5.5); + + // Require consistent FT0 vs PV z-vertex + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + registryMC.fill(HIST("recEvents"), 6.5); + + // Require TOF match for at least one vertex track + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + continue; + registryMC.fill(HIST("recEvents"), 7.5); + + // Get tracks in this MC collision + const auto mcTracksThisMcColl = mcTracks.sliceBy(mcTracksPerMcCollision, collision.globalIndex()); + + // Loop over reconstructed tracks + int id(-1); + for (auto const& track : mcTracksThisMcColl) { + id++; + + // Get corresponding MC particle + if (!track.has_mcParticle()) + continue; + const auto mcparticle = track.mcParticle(); + + // Store track index for antiproton tracks + if (passedTrackSelection(track) && track.sign() < 0 && mcparticle.pdgCode() == PDG_t::kProtonBar) { + antiprotonTrackIndex.emplace_back(id); + + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double pt = track.pt(); + double dcaxy = track.dcaXY(); + double dcaz = track.dcaZ(); + + if (mcparticle.isPhysicalPrimary() && std::fabs(dcaxy) < maxDcaxy && std::fabs(dcaz) < maxDcaz && nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { + registryMC.fill(HIST("antiproton_rec_tpc_full"), pt); + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) { + registryMC.fill(HIST("antiproton_rec_tof_full"), pt); + } + } + } + + // Apply track selection for jet reconstruction + 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.empty()) + continue; + registryMC.fill(HIST("recEvents"), 8.5); + + // Cluster particles using the anti-kt algorithm + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // 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 (jetMinusBkg.pt() < minJetPt) + continue; + + // Apply area cut if required + double normalizedJetArea = jet.area() / (PI * rJet * rJet); + if (applyAreaCut && normalizedJetArea > maxNormalizedJetArea) + continue; + isAtLeastOneJetSelected = true; + + // Reconstructed jets + registryMC.fill(HIST("recJets"), 0.5); + + // Set up two perpendicular cone axes for underlying event estimation + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Get jet constituents + std::vector jetConstituents = jet.constituents(); + + // Loop over jet constituents + for (const auto& particle : jetConstituents) { + + // Get corresponding track and apply track selection criteria + auto const& track = mcTracksThisMcColl.iteratorAt(particle.user_index()); + if (!passedTrackSelection(track)) + continue; + + // Antimatter selection + if (track.sign() > 0) + continue; + + // Get corresponding MC particle + if (!track.has_mcParticle()) + continue; + const auto mcparticle = track.mcParticle(); + + // Define variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double pt = track.pt(); + double dcaxy = track.dcaXY(); + double dcaz = track.dcaZ(); + + // Fill nsigmaTOF template + if (track.hasTOF() && std::fabs(dcaxy) < maxDcaxy && std::fabs(dcaz) < maxDcaz && mcparticle.isPhysicalPrimary() && nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc && mcparticle.pdgCode() != PDG_t::kProtonBar) { + registryMC.fill(HIST("antiproton_nsigma_tof_jet_mc"), pt, nsigmaTOFPr); + } + + // Antiproton selection based on the PDG + if (mcparticle.pdgCode() != PDG_t::kProtonBar) + continue; + + // Fill DCA templates + if (std::fabs(dcaz) < maxDcaz) { + if (mcparticle.isPhysicalPrimary()) { + registryMC.fill(HIST("antiproton_prim_dca_jet"), pt, dcaxy); + } else { + registryMC.fill(HIST("antiproton_all_dca_jet"), pt, dcaxy); + } + } + + // Apply DCA selections + if (std::fabs(dcaxy) > maxDcaxy || std::fabs(dcaz) > maxDcaz) + continue; + + // nsigmaITS for antiprotons + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + + // Particle identification using the ITS cluster size + bool passedItsPidProt(true); + if (applyItsPid && pt < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMin || nSigmaITSprot > nSigmaItsMax)) { + passedItsPidProt = false; + } + + // Fill inclusive antiproton spectrum + registryMC.fill(HIST("antiproton_incl_jet"), pt); + + // Select physical primary antiprotons + if (!mcparticle.isPhysicalPrimary()) + continue; + + // Fill antiproton spectrum for physical primaries + registryMC.fill(HIST("antiproton_prim_jet"), pt); + + // Calculate weight + double weightJet(1.0); + if (applyReweighting && mcparticle.pt() < antiprotonsInsideJets->GetXaxis()->GetXmax()) { + int ipt = antiprotonsInsideJets->FindBin(mcparticle.pt()); + weightJet = antiprotonsInsideJets->GetBinContent(ipt); + } + + // Fill histograms (TPC and TOF) only for selected candidates + if (passedItsPidProt && nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { + registryMC.fill(HIST("antiproton_rec_tpc_jet"), pt, weightJet); + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) { + registryMC.fill(HIST("antiproton_rec_tof_jet"), pt, weightJet); + } + } + } + + // Loop over tracks in the underlying event + for (auto const& index : antiprotonTrackIndex) { + + // retrieve track associated to index + auto const& track = mcTracksThisMcColl.iteratorAt(index); + + // Get corresponding MC particle + if (!track.has_mcParticle()) + continue; + const auto mcparticle = track.mcParticle(); + + // Define variables + double nsigmaTPCPr = track.tpcNSigmaPr(); + double nsigmaTOFPr = track.tofNSigmaPr(); + double pt = track.pt(); + double dcaxy = track.dcaXY(); + double dcaz = track.dcaZ(); + + // Fill DCA templates + if (std::fabs(dcaz) < maxDcaz) { + if (mcparticle.isPhysicalPrimary()) { + registryMC.fill(HIST("antiproton_prim_dca_ue"), pt, dcaxy); + } else { + registryMC.fill(HIST("antiproton_all_dca_ue"), pt, dcaxy); + } + } + + // Apply DCA selection + if (std::fabs(dcaxy) > maxDcaxy || std::fabs(dcaz) > maxDcaz) + continue; + + // Calculate the angular distance between the track and underlying event axes in eta-phi space + 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); + + // Determine the maximum allowed distance from UE axes for particle selection + double maxConeRadius = coneRadius; + if (applyAreaCut) { + maxConeRadius = std::sqrt(maxNormalizedJetArea) * rJet; + } + + // Reject tracks that lie outside the maxConeRadius from both UE axes + if (deltaRUe1 > maxConeRadius && deltaRUe2 > maxConeRadius) + continue; + + // Particle identification using the ITS cluster size + bool passedItsPidProt(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + if (applyItsPid && pt < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMin || nSigmaITSprot > nSigmaItsMax)) { + passedItsPidProt = false; + } + + // Fill inclusive antiproton spectrum + registryMC.fill(HIST("antiproton_incl_ue"), pt); + + // Select physical primary antiprotons + if (!mcparticle.isPhysicalPrimary()) + continue; + + // Fill antiproton spectrum for physical primaries + registryMC.fill(HIST("antiproton_prim_ue"), pt); + + // Calculate weight + double weightUe(1.0); + if (applyReweighting && mcparticle.pt() < antiprotonsPerpCone->GetXaxis()->GetXmax()) { + int ipt = antiprotonsPerpCone->FindBin(mcparticle.pt()); + weightUe = antiprotonsPerpCone->GetBinContent(ipt); + } + + // Fill histograms (TPC and TOF) only for selected candidates + if (passedItsPidProt && nsigmaTPCPr > minNsigmaTpc && nsigmaTPCPr < maxNsigmaTpc) { + registryMC.fill(HIST("antiproton_rec_tpc_ue"), pt, weightUe); + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTof && nsigmaTOFPr < maxNsigmaTof) { + registryMC.fill(HIST("antiproton_rec_tof_ue"), pt, weightUe); + } + } + } + } + if (isAtLeastOneJetSelected) { + registryMC.fill(HIST("recEvents"), 9.5); + } + + // Shrink large vectors + if (eventCounter % shrinkInterval == 0) { + std::vector().swap(fjParticles); + std::vector().swap(antiprotonTrackIndex); + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processJetsMCrec, "process jets MC rec", false); + + // Process real data with systematic variations of analysis parameters + void processSystData(SelectedCollisions::iterator const& collision, AntiNucleiTracks const& tracks) + { + // Event counter: before event selection + registryData.fill(HIST("number_of_events_data_syst"), 0.5); + + // Apply standard event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // Event counter: after event selection + registryData.fill(HIST("number_of_events_data_syst"), 1.5); + + // Reject events near the ITS Read-Out Frame border + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + return; + registryData.fill(HIST("number_of_events_data_syst"), 2.5); + + // Reject events at the Time Frame border + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + return; + registryData.fill(HIST("number_of_events_data_syst"), 3.5); + + // Require at least one ITS-TPC matched track + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return; + registryData.fill(HIST("number_of_events_data_syst"), 4.5); + + // Reject events with same-bunch pileup + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + registryData.fill(HIST("number_of_events_data_syst"), 5.5); + + // Require consistent FT0 vs PV z-vertex + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + registryData.fill(HIST("number_of_events_data_syst"), 6.5); + + // Require TOF match for at least one vertex track + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + return; + registryData.fill(HIST("number_of_events_data_syst"), 7.5); + + // Cut settings + static std::vector maxDcaxySyst = { + 0.071, 0.060, 0.066, 0.031, 0.052, 0.078, 0.045, 0.064, 0.036, 0.074, + 0.079, 0.043, 0.067, 0.059, 0.032, 0.070, 0.048, 0.077, 0.062, 0.034, + 0.057, 0.055, 0.073, 0.038, 0.050, 0.075, 0.041, 0.061, 0.033, 0.069, + 0.035, 0.044, 0.076, 0.049, 0.037, 0.054, 0.072, 0.046, 0.058, 0.040, + 0.068, 0.042, 0.056, 0.039, 0.047, 0.065, 0.051, 0.053, 0.063, 0.030}; + + static std::vector maxDcazSyst = { + 0.064, 0.047, 0.032, 0.076, 0.039, 0.058, 0.043, 0.069, 0.050, 0.035, + 0.074, 0.061, 0.045, 0.033, 0.068, 0.055, 0.037, 0.071, 0.042, 0.053, + 0.077, 0.038, 0.065, 0.049, 0.036, 0.059, 0.044, 0.067, 0.041, 0.034, + 0.073, 0.052, 0.040, 0.063, 0.046, 0.031, 0.070, 0.054, 0.037, 0.062, + 0.048, 0.035, 0.075, 0.051, 0.039, 0.066, 0.043, 0.060, 0.032, 0.056}; + + static std::vector nSigmaItsMinSyst = { + -2.9, -2.8, -3.0, -3.4, -2.7, -3.3, -3.0, -3.1, -3.4, -3.1, + -3.0, -2.8, -3.2, -2.6, -2.7, -3.4, -2.9, -3.0, -3.0, -2.7, + -2.9, -3.3, -3.0, -3.1, -3.2, -3.0, -2.9, -2.7, -3.3, -3.0, + -2.8, -3.3, -2.7, -3.3, -2.8, -3.4, -2.8, -3.4, -2.9, -3.1, + -3.2, -2.6, -3.1, -2.9, -3.1, -2.8, -2.9, -3.3, -3.0, -2.8}; + + static std::vector nSigmaItsMaxSyst = { + 2.9, 2.8, 3.0, 3.4, 2.7, 3.3, 3.0, 3.1, 3.4, 3.1, + 3.0, 2.8, 3.2, 2.6, 2.7, 3.4, 2.9, 3.0, 3.0, 2.7, + 2.9, 3.3, 3.0, 3.1, 3.2, 3.0, 2.9, 2.7, 3.3, 3.0, + 2.8, 3.3, 2.7, 3.3, 2.8, 3.4, 2.8, 3.4, 2.9, 3.1, + 3.2, 2.6, 3.1, 2.9, 3.1, 2.8, 2.9, 3.3, 3.0, 2.8}; + + static std::vector minNsigmaTpcSyst = { + -3.2, -2.9, -3.1, -2.9, -3.5, -2.6, -3.3, -3.0, -3.5, -2.7, + -3.0, -2.6, -3.3, -3.4, -2.8, -3.1, -2.6, -3.2, -3.1, -2.8, + -3.4, -2.7, -3.4, -2.9, -3.0, -2.5, -3.3, -2.8, -3.1, -2.7, + -3.4, -2.8, -3.3, -2.6, -3.1, -2.5, -3.4, -3.0, -3.2, -2.6, + -3.4, -2.8, -3.1, -2.6, -3.3, -2.7, -3.2, -2.7, -3.4, -2.9}; + + static std::vector maxNsigmaTpcSyst = { + 3.2, 2.9, 3.1, 2.9, 3.5, 2.6, 3.3, 3.0, 3.5, 2.7, + 3.0, 2.6, 3.3, 3.4, 2.8, 3.1, 2.6, 3.2, 3.1, 2.8, + 3.4, 2.7, 3.4, 2.9, 3.0, 2.5, 3.3, 2.8, 3.1, 2.7, + 3.4, 2.8, 3.3, 2.6, 3.1, 2.5, 3.4, 3.0, 3.2, 2.6, + 3.4, 2.8, 3.1, 2.6, 3.3, 2.7, 3.2, 2.7, 3.4, 2.9}; + + // Loop over reconstructed tracks + for (auto const& track : tracks) { + + // Select only antimatter + if (track.sign() > 0) + continue; + + // Loop over different cut settings + for (int isyst = 0; isyst < nSyst; isyst++) { + + // Apply track selection + if (!passedTrackSelectionSyst(track, isyst)) + continue; + + // Define 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(); + + // Apply DCA selections + if (std::fabs(dcaxy) > maxDcaxySyst[isyst] || std::fabs(dcaz) > maxDcazSyst[isyst]) + continue; + + // Particle identification using the ITS cluster size (vary also PID ITS) + bool passedItsPidProt(true), passedItsPidDeut(true), passedItsPidHel(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITSdeut = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITShel3 = static_cast(itsResponse.nSigmaITS(track)); + + if (applyItsPid && pt < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMinSyst[isyst] || nSigmaITSprot > nSigmaItsMaxSyst[isyst])) { + passedItsPidProt = false; + } + if (applyItsPid && pt < ptMaxItsPidDeut && (nSigmaITSdeut < nSigmaItsMinSyst[isyst] || nSigmaITSdeut > nSigmaItsMaxSyst[isyst])) { + passedItsPidDeut = false; + } + if (applyItsPid && (2.0 * pt) < ptMaxItsPidHel && (nSigmaITShel3 < nSigmaItsMinSyst[isyst] || nSigmaITShel3 > nSigmaItsMaxSyst[isyst])) { + passedItsPidHel = false; + } + + // Fill histograms + if (passedItsPidProt) { + registryData.fill(HIST("antiproton_tpc_syst"), isyst, pt, nsigmaTPCPr); + if (nsigmaTPCPr > minNsigmaTpcSyst[isyst] && nsigmaTPCPr < maxNsigmaTpcSyst[isyst] && track.hasTOF()) + registryData.fill(HIST("antiproton_tof_syst"), isyst, pt, nsigmaTOFPr); + } + if (passedItsPidDeut) { + registryData.fill(HIST("antideuteron_tpc_syst"), isyst, pt, nsigmaTPCDe); + if (nsigmaTPCDe > minNsigmaTpcSyst[isyst] && nsigmaTPCDe < maxNsigmaTpcSyst[isyst] && track.hasTOF()) + registryData.fill(HIST("antideuteron_tof_syst"), isyst, pt, nsigmaTOFDe); + } + if (passedItsPidHel) { + registryData.fill(HIST("antihelium3_tpc_syst"), isyst, 2.0 * pt, nsigmaTPCHe); + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processSystData, "Process syst data", false); + + // Process MC with systematic variations of analysis parameters + void processSystEff(GenCollisionsMc const& genCollisions, RecCollisionsMc const& recCollisions, AntiNucleiTracksMc const& mcTracks, aod::McParticles const& mcParticles) + { + // Cut settings + static std::vector maxDcaxySyst = { + 0.071, 0.060, 0.066, 0.031, 0.052, 0.078, 0.045, 0.064, 0.036, 0.074, + 0.079, 0.043, 0.067, 0.059, 0.032, 0.070, 0.048, 0.077, 0.062, 0.034, + 0.057, 0.055, 0.073, 0.038, 0.050, 0.075, 0.041, 0.061, 0.033, 0.069, + 0.035, 0.044, 0.076, 0.049, 0.037, 0.054, 0.072, 0.046, 0.058, 0.040, + 0.068, 0.042, 0.056, 0.039, 0.047, 0.065, 0.051, 0.053, 0.063, 0.030}; + + static std::vector maxDcazSyst = { + 0.064, 0.047, 0.032, 0.076, 0.039, 0.058, 0.043, 0.069, 0.050, 0.035, + 0.074, 0.061, 0.045, 0.033, 0.068, 0.055, 0.037, 0.071, 0.042, 0.053, + 0.077, 0.038, 0.065, 0.049, 0.036, 0.059, 0.044, 0.067, 0.041, 0.034, + 0.073, 0.052, 0.040, 0.063, 0.046, 0.031, 0.070, 0.054, 0.037, 0.062, + 0.048, 0.035, 0.075, 0.051, 0.039, 0.066, 0.043, 0.060, 0.032, 0.056}; + + static std::vector nSigmaItsMinSyst = { + -2.9, -2.8, -3.0, -3.4, -2.7, -3.3, -3.0, -3.1, -3.4, -3.1, + -3.0, -2.8, -3.2, -2.6, -2.7, -3.4, -2.9, -3.0, -3.0, -2.7, + -2.9, -3.3, -3.0, -3.1, -3.2, -3.0, -2.9, -2.7, -3.3, -3.0, + -2.8, -3.3, -2.7, -3.3, -2.8, -3.4, -2.8, -3.4, -2.9, -3.1, + -3.2, -2.6, -3.1, -2.9, -3.1, -2.8, -2.9, -3.3, -3.0, -2.8}; + + static std::vector nSigmaItsMaxSyst = { + 2.9, 2.8, 3.0, 3.4, 2.7, 3.3, 3.0, 3.1, 3.4, 3.1, + 3.0, 2.8, 3.2, 2.6, 2.7, 3.4, 2.9, 3.0, 3.0, 2.7, + 2.9, 3.3, 3.0, 3.1, 3.2, 3.0, 2.9, 2.7, 3.3, 3.0, + 2.8, 3.3, 2.7, 3.3, 2.8, 3.4, 2.8, 3.4, 2.9, 3.1, + 3.2, 2.6, 3.1, 2.9, 3.1, 2.8, 2.9, 3.3, 3.0, 2.8}; + + static std::vector minNsigmaTpcSyst = { + -3.2, -2.9, -3.1, -2.9, -3.5, -2.6, -3.3, -3.0, -3.5, -2.7, + -3.0, -2.6, -3.3, -3.4, -2.8, -3.1, -2.6, -3.2, -3.1, -2.8, + -3.4, -2.7, -3.4, -2.9, -3.0, -2.5, -3.3, -2.8, -3.1, -2.7, + -3.4, -2.8, -3.3, -2.6, -3.1, -2.5, -3.4, -3.0, -3.2, -2.6, + -3.4, -2.8, -3.1, -2.6, -3.3, -2.7, -3.2, -2.7, -3.4, -2.9}; + + static std::vector maxNsigmaTpcSyst = { + 3.2, 2.9, 3.1, 2.9, 3.5, 2.6, 3.3, 3.0, 3.5, 2.7, + 3.0, 2.6, 3.3, 3.4, 2.8, 3.1, 2.6, 3.2, 3.1, 2.8, + 3.4, 2.7, 3.4, 2.9, 3.0, 2.5, 3.3, 2.8, 3.1, 2.7, + 3.4, 2.8, 3.3, 2.6, 3.1, 2.5, 3.4, 3.0, 3.2, 2.6, + 3.4, 2.8, 3.1, 2.6, 3.3, 2.7, 3.2, 2.7, 3.4, 2.9}; + + static std::vector minNsigmaTofSyst = { + -3.2, -2.9, -3.1, -2.9, -3.5, -2.6, -3.3, -3.0, -3.5, -2.7, + -3.0, -2.6, -3.3, -3.4, -2.8, -3.1, -2.6, -3.2, -3.1, -2.8, + -3.4, -2.7, -3.4, -2.9, -3.0, -2.5, -3.3, -2.8, -3.1, -2.7, + -3.4, -2.8, -3.3, -2.6, -3.1, -2.5, -3.4, -3.0, -3.2, -2.6, + -3.4, -2.8, -3.1, -2.6, -3.3, -2.7, -3.2, -2.7, -3.4, -2.9}; + + static std::vector maxNsigmaTofSyst = { + 3.9, 3.6, 3.8, 3.2, 3.2, 3.5, 3.1, 3.8, 3.5, 3.4, + 3.9, 3.8, 3.7, 3.0, 3.6, 3.1, 3.7, 3.4, 4.0, 3.0, + 3.7, 3.3, 3.9, 3.1, 3.3, 3.5, 3.6, 3.2, 3.5, 3.3, + 3.9, 3.0, 3.4, 3.2, 3.1, 3.9, 3.6, 3.1, 3.2, 4.0, + 3.1, 3.7, 3.6, 3.1, 3.3, 3.5, 3.3, 3.4, 3.1, 3.8}; + + // Loop over generated collisions + for (const auto& collision : genCollisions) { + + // Apply event selection: require vertex position to be within the allowed z range + if (std::fabs(collision.posZ()) > zVtx) + continue; + + // Get particles in this MC collision + const auto mcParticlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, collision.globalIndex()); + + // Loop over all generated Monte Carlo particles for the selected event + for (const auto& particle : mcParticlesThisMcColl) { + + // Select primary particles + if (!particle.isPhysicalPrimary()) + continue; + + // Select particles within the specified pseudorapidity interval + if (particle.eta() < minEta || particle.eta() > maxEta) + continue; + + // Process different particle species based on PDG code + switch (particle.pdgCode()) { + case PDG_t::kProtonBar: + registryMC.fill(HIST("antiproton_gen_syst"), particle.pt()); + break; + case -o2::constants::physics::Pdg::kDeuteron: + registryMC.fill(HIST("antideuteron_gen_syst"), particle.pt()); + break; + case -o2::constants::physics::Pdg::kHelium3: + registryMC.fill(HIST("antihelium3_gen_syst"), particle.pt()); + break; + } + } + } + + // Loop over reconstructed collisions + for (const auto& collision : recCollisions) { + + // Apply standard event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + continue; + + // Reject events near the ITS Read-Out Frame border + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + continue; + + // Reject events at the Time Frame border + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + continue; + + // Require at least one ITS-TPC matched track + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + continue; + + // Reject events with same-bunch pileup + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + continue; + + // Require consistent FT0 vs PV z-vertex + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + + // Require TOF match for at least one vertex track + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + continue; + + // Get tracks in this MC collision + const auto mcTracksThisMcColl = mcTracks.sliceBy(mcTracksPerMcCollision, collision.globalIndex()); + + // Loop over reconstructed tracks + for (auto const& track : mcTracksThisMcColl) { + + // Select only antimatter + if (track.sign() > 0) + continue; + + // Get corresponding MC particle + if (!track.has_mcParticle()) + continue; + const auto mcparticle = track.mcParticle(); + + // Loop over different cut settings + for (int isyst = 0; isyst < nSyst; isyst++) { + + // Apply track selection + if (!passedTrackSelectionSyst(track, isyst)) + continue; + + // Define 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(); + + // Apply DCA selections + if (std::fabs(dcaxy) > maxDcaxySyst[isyst] || std::fabs(dcaz) > maxDcazSyst[isyst]) + continue; + + // Fill inclusive antiproton spectrum + registryMC.fill(HIST("antiproton_incl_syst"), isyst, pt); + + // Select physical primary antiprotons + if (!mcparticle.isPhysicalPrimary()) + continue; + + // Fill antiproton spectrum for physical primaries + registryMC.fill(HIST("antiproton_prim_syst"), isyst, pt); + + // Particle identification using the ITS cluster size (vary also PID ITS) + bool passedItsPidProt(true), passedItsPidDeut(true), passedItsPidHel(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITSdeut = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITShel3 = static_cast(itsResponse.nSigmaITS(track)); + + if (applyItsPid && pt < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMinSyst[isyst] || nSigmaITSprot > nSigmaItsMaxSyst[isyst])) { + passedItsPidProt = false; + } + if (applyItsPid && pt < ptMaxItsPidDeut && (nSigmaITSdeut < nSigmaItsMinSyst[isyst] || nSigmaITSdeut > nSigmaItsMaxSyst[isyst])) { + passedItsPidDeut = false; + } + if (applyItsPid && (2.0 * pt) < ptMaxItsPidHel && (nSigmaITShel3 < nSigmaItsMinSyst[isyst] || nSigmaITShel3 > nSigmaItsMaxSyst[isyst])) { + passedItsPidHel = false; + } + + // Fill histograms for antiprotons + if (passedItsPidProt && mcparticle.pdgCode() == PDG_t::kProtonBar && nsigmaTPCPr > minNsigmaTpcSyst[isyst] && nsigmaTPCPr < maxNsigmaTpcSyst[isyst]) { + registryMC.fill(HIST("antiproton_rec_tpc_syst"), isyst, pt); + if (track.hasTOF() && nsigmaTOFPr > minNsigmaTofSyst[isyst] && nsigmaTOFPr < maxNsigmaTofSyst[isyst]) + registryMC.fill(HIST("antiproton_rec_tof_syst"), isyst, pt); + } + // Fill histograms for antideuterons + if (passedItsPidDeut && mcparticle.pdgCode() == -o2::constants::physics::Pdg::kDeuteron && nsigmaTPCDe > minNsigmaTpcSyst[isyst] && nsigmaTPCDe < maxNsigmaTpcSyst[isyst]) { + registryMC.fill(HIST("antideuteron_rec_tpc_syst"), isyst, pt); + if (track.hasTOF() && nsigmaTOFDe > minNsigmaTofSyst[isyst] && nsigmaTOFDe < maxNsigmaTofSyst[isyst]) + registryMC.fill(HIST("antideuteron_rec_tof_syst"), isyst, pt); + } + // Fill histograms for antihelium3 + if (passedItsPidHel && mcparticle.pdgCode() == -o2::constants::physics::Pdg::kHelium3 && nsigmaTPCHe > minNsigmaTpcSyst[isyst] && nsigmaTPCHe < maxNsigmaTpcSyst[isyst]) { + registryMC.fill(HIST("antihelium3_rec_tpc_syst"), isyst, 2.0 * pt); + } + } + } + } + } + PROCESS_SWITCH(AntinucleiInJets, processSystEff, "process syst mc", false); + + // Process correlation + void processCorr(SelectedCollisions::iterator const& collision, AntiNucleiTracks const& tracks) + { + // Event counter: before event selection + registryCorr.fill(HIST("eventCounter"), 0.5); + + // Apply standard event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // Event counter: after event selection + registryCorr.fill(HIST("eventCounter"), 1.5); + + // Reject events near the ITS Read-Out Frame border + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) + return; + registryCorr.fill(HIST("eventCounter"), 2.5); + + // Reject events at the Time Frame border + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) + return; + registryCorr.fill(HIST("eventCounter"), 3.5); + + // Require at least one ITS-TPC matched track + if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) + return; + registryCorr.fill(HIST("eventCounter"), 4.5); + + // Reject events with same-bunch pileup + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + registryCorr.fill(HIST("eventCounter"), 5.5); + + // Require consistent FT0 vs PV z-vertex + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + registryCorr.fill(HIST("eventCounter"), 6.5); + + // Require TOF match for at least one vertex track + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) + return; + registryCorr.fill(HIST("eventCounter"), 7.5); + + // Assign event to a random subsample (0-19) + double sampleId = mRand.Integer(20) + 0.5; + + // Multiplicity percentile + const float multiplicity = collision.centFT0M(); + + // Fill event counter vs centrality (full Event region) + registryCorr.fill(HIST("eventCounter_centrality_fullEvent"), multiplicity, sampleId); + + // pt/A bins + std::vector ptOverAbins = {0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; + const int nBins = ptOverAbins.size() - 1; + + // Particle counters + std::vector nAntiprotonFullEvent(nBins, 0); + std::vector nAntideuteronFullEvent(nBins, 0); + int nTotProtonFullEvent(0); + int nTotDeuteronFullEvent(0); + int nTotAntiprotonFullEvent(0); + int nTotAntideuteronFullEvent(0); + + // Loop over reconstructed tracks + for (auto const& track : tracks) { + + // Apply track selection + if (!passedTrackSelection(track)) + continue; + + // Apply DCA selections + if (std::fabs(track.dcaXY()) > maxDcaxy || std::fabs(track.dcaZ()) > maxDcaz) + continue; + + // Particle identification using the ITS cluster size + bool passedItsPidProt(true), passedItsPidDeut(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITSdeut = static_cast(itsResponse.nSigmaITS(track)); + + if (applyItsPid && track.pt() < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMin || nSigmaITSprot > nSigmaItsMax)) { + passedItsPidProt = false; + } + if (applyItsPid && track.pt() < ptMaxItsPidDeut && (nSigmaITSdeut < nSigmaItsMin || nSigmaITSdeut > nSigmaItsMax)) { + passedItsPidDeut = false; + } + + // Kinematic range selection + if (isProton(track) && passedItsPidProt) { + if (track.pt() < ptOverAbins[0] || track.pt() >= ptOverAbins[nBins]) { + continue; + } + } else if (isDeuteron(track) && passedItsPidDeut) { + double ptPerNucleon = 0.5 * track.pt(); + if (ptPerNucleon < ptOverAbins[0] || ptPerNucleon >= ptOverAbins[nBins]) { + continue; + } + } else { + continue; + } + + // (Anti)protons + if (isProton(track) && passedItsPidProt) { + if (track.sign() > 0) { + nTotProtonFullEvent++; + } else if (track.sign() < 0) { + nTotAntiprotonFullEvent++; + int ibin = findBin(ptOverAbins, track.pt()); + nAntiprotonFullEvent[ibin]++; + } + } + + // (Anti)deuterons + if (isDeuteron(track) && passedItsPidDeut) { + const double ptPerNucleon = 0.5 * track.pt(); + + if (track.sign() > 0) { + nTotDeuteronFullEvent++; + } else if (track.sign() < 0) { + nTotAntideuteronFullEvent++; + int ibin = findBin(ptOverAbins, ptPerNucleon); + nAntideuteronFullEvent[ibin]++; + } + } + } + + // Fill correlation histograms + int netProtonFullEvent = nTotProtonFullEvent - nTotAntiprotonFullEvent; + int netDeuteronFullEvent = nTotDeuteronFullEvent - nTotAntideuteronFullEvent; + + registryCorr.fill(HIST("rho_fullEvent"), nTotAntideuteronFullEvent, nTotAntiprotonFullEvent, multiplicity, sampleId); + registryCorr.fill(HIST("rho_netP_netD_fullEvent"), netDeuteronFullEvent, netProtonFullEvent, sampleId); + + // Fill efficiency histograms + for (int i = 0; i < nBins; i++) { + double ptAcenteri = 0.5 * (ptOverAbins[i] + ptOverAbins[i + 1]); + + registryCorr.fill(HIST("q1d_fullEvent"), nAntideuteronFullEvent[i], ptAcenteri, multiplicity, sampleId); + registryCorr.fill(HIST("q1p_fullEvent"), nAntiprotonFullEvent[i], ptAcenteri, multiplicity, sampleId); + for (int j = 0; j < nBins; j++) { + double ptAcenterj = 0.5 * (ptOverAbins[j] + ptOverAbins[j + 1]); + registryCorr.fill(HIST("q1d_square_fullEvent"), ptAcenteri, ptAcenterj, (nAntideuteronFullEvent[i] * nAntideuteronFullEvent[j]), multiplicity, sampleId); + registryCorr.fill(HIST("q1p_square_fullEvent"), ptAcenteri, ptAcenterj, (nAntiprotonFullEvent[i] * nAntiprotonFullEvent[j]), multiplicity, sampleId); + registryCorr.fill(HIST("q1d_q1p_fullEvent"), ptAcenteri, ptAcenterj, (nAntideuteronFullEvent[i] * nAntiprotonFullEvent[j]), multiplicity, sampleId); + } + } + + /* + // Loop over reconstructed tracks (refactoring: this part can be incorporated above) + 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.empty()) + return; + registryCorr.fill(HIST("eventCounter"), 8.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] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // 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 (jetMinusBkg.pt() < minJetPt) + continue; + + // Apply area cut if required + double normalizedJetArea = jet.area() / (PI * rJet * rJet); + if (applyAreaCut && normalizedJetArea > maxNormalizedJetArea) + continue; + isAtLeastOneJetSelected = true; + + // Perpendicular cones + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Get jet constituents + std::vector jetConstituents = jet.constituents(); + + // Particle counters + std::vector nAntiprotonJet(nBins, 0); + std::vector nAntideuteronJet(nBins, 0); + int nTotProtonJet(0); + int nTotDeuteronJet(0); + int nTotAntiprotonJet(0); + int nTotAntideuteronJet(0); + + // 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; + + // Apply DCA selections + if (std::fabs(track.dcaXY()) > maxDcaxy || std::fabs(track.dcaZ()) > maxDcaz) + continue; + + // Particle identification using the ITS cluster size + bool passedItsPidProt(true), passedItsPidDeut(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITSdeut = static_cast(itsResponse.nSigmaITS(track)); + + if (applyItsPid && track.pt() < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMin || nSigmaITSprot > nSigmaItsMax)) { + passedItsPidProt = false; + } + if (applyItsPid && track.pt() < ptMaxItsPidDeut && (nSigmaITSdeut < nSigmaItsMin || nSigmaITSdeut > nSigmaItsMax)) { + passedItsPidDeut = false; + } + + // Kinematic range selection + if (isProton(track) && passedItsPidProt) { + if (track.pt() < ptOverAbins[0] || track.pt() >= ptOverAbins[nBins]) { + continue; + } + } else if (isDeuteron(track) && passedItsPidDeut) { + double ptPerNucleon = 0.5 * track.pt(); + if (ptPerNucleon < ptOverAbins[0] || ptPerNucleon >= ptOverAbins[nBins]) { + continue; + } + } else { + continue; + } + + // (Anti)protons + if (isProton(track) && passedItsPidProt) { + if (track.sign() > 0) { + nTotProtonJet++; + } else if (track.sign() < 0) { + nTotAntiprotonJet++; + int ibin = findBin(ptOverAbins, track.pt()); + nAntiprotonJet[ibin]++; + } + } + + // (Anti)deuterons + if (isDeuteron(track) && passedItsPidDeut) { + const double ptPerNucleon = 0.5 * track.pt(); + + if (track.sign() > 0) { + nTotDeuteronJet++; + } else if (track.sign() < 0) { + nTotAntideuteronJet++; + int ibin = findBin(ptOverAbins, ptPerNucleon); + nAntideuteronJet[ibin]++; + } + } + } // end of loop over constituents + + // Fill correlation histograms + int netProtonJet = nTotProtonJet - nTotAntiprotonJet; + int netDeuteronJet = nTotDeuteronJet - nTotAntideuteronJet; + registryCorr.fill(HIST("rho_jet"), nTotAntideuteronJet, nTotAntiprotonJet, multiplicity); + registryCorr.fill(HIST("rho_netP_netD_jet"), netDeuteronJet, netProtonJet); + + // Fill efficiency histograms + for (int i = 0; i < nBins; i++) { + double ptAcenteri = 0.5 * (ptOverAbins[i] + ptOverAbins[i + 1]); + + registryCorr.fill(HIST("q1d_jet"), nAntideuteronJet[i], ptAcenteri, multiplicity); + registryCorr.fill(HIST("q1p_jet"), nAntiprotonJet[i], ptAcenteri, multiplicity); + for (int j = 0; j < nBins; j++) { + double ptAcenterj = 0.5 * (ptOverAbins[j] + ptOverAbins[j + 1]); + registryCorr.fill(HIST("q1d_square_jet"), ptAcenteri, ptAcenterj, nAntideuteronJet[i] * nAntideuteronJet[j], multiplicity); + registryCorr.fill(HIST("q1p_square_jet"), ptAcenteri, ptAcenterj, nAntiprotonJet[i] * nAntiprotonJet[j], multiplicity); + registryCorr.fill(HIST("q1d_q1p_jet"), ptAcenteri, ptAcenterj, nAntideuteronJet[i] * nAntiprotonJet[j], multiplicity); + } + } + + // Particle counters + std::vector nAntiprotonUE(nBins, 0); + std::vector nAntideuteronUE(nBins, 0); + int nTotProtonUE(0); + int nTotDeuteronUE(0); + int nTotAntiprotonUE(0); + int nTotAntideuteronUE(0); + + // Loop over tracks in the underlying event + for (auto const& track : tracks) { + + // Get corresponding track and apply track selection criteria + if (!passedTrackSelection(track)) + continue; + + // Apply DCA selections + if (std::fabs(track.dcaXY()) > maxDcaxy || std::fabs(track.dcaZ()) > maxDcaz) + continue; + + // Calculate the angular distance between the track and underlying event axes in eta-phi space + 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); + + // Determine the maximum allowed distance from UE axes for particle selection + double maxConeRadius = coneRadius; + if (applyAreaCut) { + maxConeRadius = std::sqrt(maxNormalizedJetArea) * rJet; + } + + // Reject tracks that lie outside the maxConeRadius from both UE axes + if (deltaRUe1 > maxConeRadius && deltaRUe2 > maxConeRadius) + continue; + + // Particle identification using the ITS cluster size + bool passedItsPidProt(true), passedItsPidDeut(true); + double nSigmaITSprot = static_cast(itsResponse.nSigmaITS(track)); + double nSigmaITSdeut = static_cast(itsResponse.nSigmaITS(track)); + + if (applyItsPid && track.pt() < ptMaxItsPidProt && (nSigmaITSprot < nSigmaItsMin || nSigmaITSprot > nSigmaItsMax)) { + passedItsPidProt = false; + } + if (applyItsPid && track.pt() < ptMaxItsPidDeut && (nSigmaITSdeut < nSigmaItsMin || nSigmaITSdeut > nSigmaItsMax)) { + passedItsPidDeut = false; + } + + // Kinematic range selection + if (isProton(track) && passedItsPidProt) { + if (track.pt() < ptOverAbins[0] || track.pt() >= ptOverAbins[nBins]) { + continue; + } + } else if (isDeuteron(track) && passedItsPidDeut) { + double ptPerNucleon = 0.5 * track.pt(); + if (ptPerNucleon < ptOverAbins[0] || ptPerNucleon >= ptOverAbins[nBins]) { + continue; + } + } else { + continue; + } + + // (Anti)protons + if (isProton(track) && passedItsPidProt) { + if (track.sign() > 0) { + nTotProtonUE++; + } else if (track.sign() < 0) { + nTotAntiprotonUE++; + int ibin = findBin(ptOverAbins, track.pt()); + nAntiprotonUE[ibin]++; + } + } + + // (Anti)deuterons + if (isDeuteron(track) && passedItsPidDeut) { + const double ptPerNucleon = 0.5 * track.pt(); + + if (track.sign() > 0) { + nTotDeuteronUE++; + } else if (track.sign() < 0) { + nTotAntideuteronUE++; + int ibin = findBin(ptOverAbins, ptPerNucleon); + nAntideuteronUE[ibin]++; + } + } + } + + // Fill correlation histograms + int netProtonUE = nTotProtonUE - nTotAntiprotonUE; + int netDeuteronUE = nTotDeuteronUE - nTotAntideuteronUE; + registryCorr.fill(HIST("rho_ue"), nTotAntideuteronUE, nTotAntiprotonUE, multiplicity); + registryCorr.fill(HIST("rho_netP_netD_ue"), netDeuteronUE, netProtonUE); + + // Fill efficiency histograms + for (int i = 0; i < nBins; i++) { + double ptAcenteri = 0.5 * (ptOverAbins[i] + ptOverAbins[i + 1]); + + registryCorr.fill(HIST("q1d_ue"), nAntideuteronUE[i], ptAcenteri, multiplicity); + registryCorr.fill(HIST("q1p_ue"), nAntiprotonUE[i], ptAcenteri, multiplicity); + for (int j = 0; j < nBins; j++) { + double ptAcenterj = 0.5 * (ptOverAbins[j] + ptOverAbins[j + 1]); + registryCorr.fill(HIST("q1d_square_ue"), ptAcenteri, ptAcenterj, nAntideuteronUE[i] * nAntideuteronUE[j], multiplicity); + registryCorr.fill(HIST("q1p_square_ue"), ptAcenteri, ptAcenterj, nAntiprotonUE[i] * nAntiprotonUE[j], multiplicity); + registryCorr.fill(HIST("q1d_q1p_ue"), ptAcenteri, ptAcenterj, nAntideuteronUE[i] * nAntiprotonUE[j], multiplicity); + } + } + // Fill event counter vs centrality (ue region) + registryCorr.fill(HIST("eventCounter_centrality_ue"), multiplicity); + } + // Event counter: events with at least one jet selected + if (isAtLeastOneJetSelected) { + registryCorr.fill(HIST("eventCounter"), 9.5); + registryCorr.fill(HIST("eventCounter_centrality_jet"), multiplicity); + } + */ + } + PROCESS_SWITCH(AntinucleiInJets, processCorr, "Process Correlation analysis", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/spectraCharged.cxx b/PWGLF/Tasks/Nuspex/chargedParticles.cxx similarity index 59% rename from PWGLF/Tasks/Nuspex/spectraCharged.cxx rename to PWGLF/Tasks/Nuspex/chargedParticles.cxx index 94e3b30dc4a..9da546afd57 100644 --- a/PWGLF/Tasks/Nuspex/spectraCharged.cxx +++ b/PWGLF/Tasks/Nuspex/chargedParticles.cxx @@ -9,52 +9,99 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// task for charged particle pt spectra vs multiplicity analysis with 2d unfolding for run3+ -// mimics https://github.com/alisw/AliPhysics/blob/master/PWGLF/SPECTRA/ChargedHadrons/MultDepSpec/AliMultDepSpecAnalysisTask.cxx - -#include "Framework/HistogramRegistry.h" -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/O2DatabasePDGPlugin.h" -#include "Common/DataModel/EventSelection.h" +/// \file chargedParticles.cxx +/// \brief Task for analysis of charged particle pt spectra vs multiplicity with 2d unfolding. +/// \author Mario Krüger + +#include "PWGLF/DataModel/particleCompositionCorrectionTable.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "TDatabasePDG.h" + +#include +#include +#include +#include +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; +using aod::track::TrackSelectionFlags; //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- // Task declaration //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- -struct chargedSpectra { +struct ChargedParticles { + std::random_device rnd; + std::mt19937 gen{rnd()}; + std::uniform_real_distribution dist{0.f, 1.f}; + uint32_t getNRepetitons(float scalingFactor) + { + uint32_t nRepetitions = static_cast(scalingFactor); + float rest = scalingFactor - nRepetitions; + if (rest) { + nRepetitions += (dist(gen) <= rest) ? 1u : 0u; + // LOGP(info, "scalingFactor: {} -> {}", scalingFactor, nRepetitions); + } + return nRepetitions; + }; HistogramRegistry histos; Service pdg; - // task settings that can be steered via hyperloop Configurable isRun3{"isRun3", true, "is Run3 dataset"}; Configurable maxMultMeas{"maxMultMeas", 100, "max measured multiplicity"}; Configurable maxMultTrue{"maxMultTrue", 100, "max true multiplicity"}; Configurable etaCut{"etaCut", 0.8f, "eta cut"}; Configurable ptMinCut{"ptMinCut", 0.15f, "pt min cut"}; Configurable ptMaxCut{"ptMaxCut", 10.f, "pt max cut"}; - Configurable normINELGT0{"normINELGT0", false, "normalize INEL>0 according to MC"}; + enum : uint32_t { + kSystNominal = 100, + kSystDownChi2PerClusterITS, + kSystUpChi2PerClusterITS, + kSystDownChi2PerClusterTPC, + kSystUpChi2PerClusterTPC, + kSystDownTPCCrossedRowsOverNCls, + kSystUpTPCCrossedRowsOverNCls, + kSystDownDCAxy = 111, + kSystUpDCAxy, + kSystDownDCAz, + kSystUpDCAz, + kSystITSHits, // only relevant for converted data + kSystDownTPCCrossedRows, + kSystUpTPCCrossedRows, + kSystDownPCC = 120, + kSystUpPCC + }; + Configurable systMode{"systMode", kSystNominal, "variation for systematic uncertainties"}; + uint16_t trackSelMask{TrackSelectionFlags::kGlobalTrackWoPtEta}; // track selection bitmask (without cut that is being varied) + uint16_t cutVarFlag{0}; + TrackSelection trackSel; + TrackSelection::TrackCuts trackSelFlag; + // helper struct to store transient properties - struct varContainer { + struct VarContainer { uint32_t multMeas{0u}; uint32_t multTrue{0u}; bool isAcceptedEvent{false}; bool isAcceptedEventMC{false}; bool isINELGT0EventMC{false}; bool isChargedPrimary{false}; + uint32_t nRepetitions{1u}; }; - varContainer vars; + VarContainer vars; + static constexpr float kMaxVtxZ = 10.f; void init(InitContext const&); @@ -64,49 +111,35 @@ struct chargedSpectra { template bool initTrack(const T& track); - template + template void initEvent(const C& collision, const T& tracks); template void initEventMC(const C& collision, const P& particles); - template - void processMeas(const C& collision, const T& tracks); + template + void processMeas(const T& tracks); - template - void processTrue(const C& collision, const P& particles); + template + void processTrue(const P& particles); using CollisionTableData = soa::Join; - using TrackTableData = soa::Join; + using TrackTableData = soa::Join; void processData(CollisionTableData::iterator const& collision, TrackTableData const& tracks); - PROCESS_SWITCH(chargedSpectra, processData, "process data", false); + PROCESS_SWITCH(ChargedParticles, processData, "process data", false); using CollisionTableMCTrue = aod::McCollisions; using CollisionTableMC = soa::SmallGroups>; - using TrackTableMC = soa::Join; - using ParticleTableMC = aod::McParticles; + using TrackTableMC = soa::Join; + using ParticleTableMC = soa::Join; Preslice perCollision = aod::track::collisionId; - void processMC(CollisionTableMCTrue::iterator const& mcCollision, CollisionTableMC const& collisions, TrackTableMC const& tracks, ParticleTableMC const& particles); - PROCESS_SWITCH(chargedSpectra, processMC, "process mc", true); - - // TODO: - Milestone - express most of the selections on events and tracks in a declarative way to improve performance - /* - add - Filter xy; - soa::Filtered

- - For the collision and track tables (data and MC): - - collision z pos < 10cm - - trigger condition + event selection - - track selection + is in kine range - - For the MC tables we need to keep everything that EITHER fulfils the conditions in data OR in MC to get correct efficiencies and contamination! - */ + void processMC(CollisionTableMCTrue::iterator const& mcCollision, TrackTableMC const& tracks, CollisionTableMC const& collisions, ParticleTableMC const& particles); + PROCESS_SWITCH(ChargedParticles, processMC, "process mc", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } //-------------------------------------------------------------------------------------------------- @@ -120,7 +153,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) * Initialise the task and add histograms. */ //************************************************************************************************** -void chargedSpectra::init(InitContext const&) +void ChargedParticles::init(InitContext const&) { std::vector ptBinEdges = {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, @@ -162,6 +195,62 @@ void chargedSpectra::init(InitContext const&) histos.add("multPtSpec_trk_meas_evtcont", "", kTH2D, {multMeasAxis, ptMeasAxis}); // tracks from events that are measured, but do not belong to the desired class of events histos.add("multPtSpec_trk_inter", "", kTH2D, {multTrueAxis, ptMeasAxis}); } + + trackSel = getGlobalTrackSelection(); + if (systMode == kSystDownChi2PerClusterITS) { + trackSel.SetMaxChi2PerClusterITS(25.); + cutVarFlag = TrackSelectionFlags::kITSChi2NDF; + trackSelFlag = TrackSelection::TrackCuts::kITSChi2NDF; + } else if (systMode == kSystUpChi2PerClusterITS) { + trackSel.SetMaxChi2PerClusterITS(49.); + cutVarFlag = TrackSelectionFlags::kITSChi2NDF; + trackSelFlag = TrackSelection::TrackCuts::kITSChi2NDF; + } else if (systMode == kSystDownChi2PerClusterTPC) { + trackSel.SetMaxChi2PerClusterTPC(3.0); + cutVarFlag = TrackSelectionFlags::kTPCChi2NDF; + trackSelFlag = TrackSelection::TrackCuts::kTPCChi2NDF; + } else if (systMode == kSystUpChi2PerClusterTPC) { + trackSel.SetMaxChi2PerClusterTPC(5.0); + cutVarFlag = TrackSelectionFlags::kTPCChi2NDF; + trackSelFlag = TrackSelection::TrackCuts::kTPCChi2NDF; + } else if (systMode == kSystDownTPCCrossedRowsOverNCls) { + trackSel.SetMinNCrossedRowsOverFindableClustersTPC(0.7); + cutVarFlag = TrackSelectionFlags::kTPCCrossedRowsOverNCls; + trackSelFlag = TrackSelection::TrackCuts::kTPCCrossedRowsOverNCls; + } else if (systMode == kSystUpTPCCrossedRowsOverNCls) { + trackSel.SetMinNCrossedRowsOverFindableClustersTPC(0.9); + cutVarFlag = TrackSelectionFlags::kTPCCrossedRowsOverNCls; + trackSelFlag = TrackSelection::TrackCuts::kTPCCrossedRowsOverNCls; + } else if (systMode == kSystDownDCAxy) { + trackSel.SetMaxDcaXYPtDep([](float pt) { return 4. / 7. * (0.0105f + 0.0350f / std::pow(pt, 1.1f)); }); + cutVarFlag = TrackSelectionFlags::kDCAxy; + trackSelFlag = TrackSelection::TrackCuts::kDCAxy; + } else if (systMode == kSystUpDCAxy) { + trackSel.SetMaxDcaXYPtDep([](float pt) { return 10. / 7. * (0.0105f + 0.0350f / std::pow(pt, 1.1f)); }); + cutVarFlag = TrackSelectionFlags::kDCAxy; + trackSelFlag = TrackSelection::TrackCuts::kDCAxy; + } else if (systMode == kSystDownDCAz) { + trackSel.SetMaxDcaZ(1.0); + cutVarFlag = TrackSelectionFlags::kDCAz; + trackSelFlag = TrackSelection::TrackCuts::kDCAz; + } else if (systMode == kSystUpDCAz) { + trackSel.SetMaxDcaZ(5.0); + cutVarFlag = TrackSelectionFlags::kDCAz; + trackSelFlag = TrackSelection::TrackCuts::kDCAz; + } else if (systMode == kSystITSHits) { + trackSel.ResetITSRequirements(); + cutVarFlag = TrackSelectionFlags::kITSHits; + trackSelFlag = TrackSelection::TrackCuts::kITSHits; + } else if (systMode == kSystDownTPCCrossedRows) { + trackSel.SetMinNCrossedRowsTPC(60); + cutVarFlag = TrackSelectionFlags::kTPCCrossedRows; + trackSelFlag = TrackSelection::TrackCuts::kTPCCrossedRows; + } else if (systMode == kSystUpTPCCrossedRows) { + trackSel.SetMinNCrossedRowsTPC(80); + cutVarFlag = TrackSelectionFlags::kTPCCrossedRows; + trackSelFlag = TrackSelection::TrackCuts::kTPCCrossedRows; + } + trackSelMask &= (~cutVarFlag); } //************************************************************************************************** @@ -169,10 +258,10 @@ void chargedSpectra::init(InitContext const&) * Entrypoint to processes data. */ //************************************************************************************************** -void chargedSpectra::processData(CollisionTableData::iterator const& collision, TrackTableData const& tracks) +void ChargedParticles::processData(CollisionTableData::iterator const& collision, TrackTableData const& tracks) { - initEvent(collision, tracks); - processMeas(collision, tracks); + initEvent(collision, tracks); + processMeas(tracks); } //************************************************************************************************** @@ -180,7 +269,7 @@ void chargedSpectra::processData(CollisionTableData::iterator const& collision, * Entrypoint to processes mc. */ //************************************************************************************************** -void chargedSpectra::processMC(CollisionTableMCTrue::iterator const& mcCollision, CollisionTableMC const& collisions, TrackTableMC const& tracks, ParticleTableMC const& particles) +void ChargedParticles::processMC(CollisionTableMCTrue::iterator const& mcCollision, TrackTableMC const& tracks, CollisionTableMC const& collisions, ParticleTableMC const& particles) { histos.fill(HIST("collision_ambiguity"), collisions.size()); @@ -198,14 +287,14 @@ void chargedSpectra::processMC(CollisionTableMCTrue::iterator const& mcCollision if (collisions.size() == 0) { vars.isAcceptedEvent = false; } else { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { auto curTracks = tracks.sliceBy(perCollision, collision.globalIndex()); - initEvent(collision, curTracks); - processMeas(collision, curTracks); + initEvent(collision, curTracks); + processMeas(curTracks); break; // for now look only at first collision... } } - processTrue(mcCollision, particles); + processTrue(particles); } //************************************************************************************************** @@ -214,7 +303,7 @@ void chargedSpectra::processMC(CollisionTableMCTrue::iterator const& mcCollision */ //************************************************************************************************** template -bool chargedSpectra::initParticle(const P& particle) +bool ChargedParticles::initParticle(const P& particle) { vars.isChargedPrimary = false; auto pdgParticle = pdg->GetParticle(particle.pdgCode()); @@ -232,6 +321,15 @@ bool chargedSpectra::initParticle(const P& particle) if (particle.pt() <= ptMinCut || particle.pt() >= ptMaxCut) { return false; } + + float pccWeight = particle.pccWeight(); + if (systMode == kSystDownPCC) { + pccWeight = particle.pccWeightSysDown(); + } else if (systMode == kSystUpPCC) { + pccWeight = particle.pccWeightSysUp(); + } + vars.nRepetitions = getNRepetitons(pccWeight); + // FIXME: in case of nRepetitions = 0 INELGT0 can be wrong return true; } @@ -241,7 +339,7 @@ bool chargedSpectra::initParticle(const P& particle) */ //************************************************************************************************** template -bool chargedSpectra::initTrack(const T& track) +bool ChargedParticles::initTrack(const T& track) { if (std::abs(track.eta()) >= etaCut) { return false; @@ -249,7 +347,11 @@ bool chargedSpectra::initTrack(const T& track) if (track.pt() <= ptMinCut || track.pt() >= ptMaxCut) { return false; } - if (!track.isGlobalTrackWoPtEta()) { + if (!TrackSelectionFlags::checkFlag(track.trackCutFlag(), trackSelMask)) { + return false; + } + // for systematic variation of standard selections, check if the varied cut is passed + if (cutVarFlag && !trackSel.IsSelected(track, trackSelFlag)) { return false; } return true; @@ -260,20 +362,43 @@ bool chargedSpectra::initTrack(const T& track) * Check if event is good. */ //************************************************************************************************** -template -void chargedSpectra::initEvent(const C& collision, const T& tracks) +template +void ChargedParticles::initEvent(const C& collision, const T& tracks) { vars.multMeas = 0; - for (auto& track : tracks) { + for (const auto& track : tracks) { if (initTrack(track)) { - ++vars.multMeas; + if constexpr (IS_MC) { + if (!track.has_mcParticle()) { + continue; + } + const auto& particle = track.template mcParticle_as(); + if (!initParticle(particle)) { + continue; + } + vars.multMeas += vars.nRepetitions; + } else { + ++vars.multMeas; + } } } vars.isAcceptedEvent = false; - if (std::abs(collision.posZ()) < 10.f) { - if (isRun3 ? collision.sel8() : collision.sel7()) { - if ((isRun3 || doprocessMC) ? true : collision.alias_bit(kINT7)) { + if (std::abs(collision.posZ()) < kMaxVtxZ) { + if (isRun3) { + if (collision.sel8() && + collision.selection_bit(aod::evsel::kNoSameBunchPileup) && + collision.selection_bit(aod::evsel::kIsVertexITSTPC) && + collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + // !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched) && + // collision.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) && + // collision.selection_bit(aod::evsel::kNoCollInRofStandard) && + // collision.selection_bit(aod::evsel::kIsVertexTOFmatched) + { + vars.isAcceptedEvent = true; + } + } else { + if (collision.sel7() && ((doprocessMC) ? true : collision.alias_bit(kINT7))) { vars.isAcceptedEvent = true; } } @@ -286,18 +411,18 @@ void chargedSpectra::initEvent(const C& collision, const T& tracks) */ //************************************************************************************************** template -void chargedSpectra::initEventMC(const C& collision, const P& particles) +void ChargedParticles::initEventMC(const C& collision, const P& particles) { vars.isINELGT0EventMC = false; // will be set to true in case a charged particle within eta +-1 is found vars.multTrue = 0; - for (auto& particle : particles) { + for (const auto& particle : particles) { if (!initParticle(particle) || !vars.isChargedPrimary) { continue; } - ++vars.multTrue; + vars.multTrue += vars.nRepetitions; } bool isGoodEventClass = (normINELGT0) ? vars.isINELGT0EventMC : (vars.multTrue > 0); - vars.isAcceptedEventMC = isGoodEventClass && (std::abs(collision.posZ()) < 10.f); + vars.isAcceptedEventMC = isGoodEventClass && (std::abs(collision.posZ()) < kMaxVtxZ); } //************************************************************************************************** @@ -305,8 +430,8 @@ void chargedSpectra::initEventMC(const C& collision, const P& particles) * Function to processes MC truth info. Assumes initEvent and initEventMC have been called previously. */ //************************************************************************************************** -template -void chargedSpectra::processTrue(const C& /*collision*/, const P& particles) +template +void ChargedParticles::processTrue(const P& particles) { if (!vars.isAcceptedEventMC) { return; @@ -314,11 +439,13 @@ void chargedSpectra::processTrue(const C& /*collision*/, const P& particles) histos.fill(HIST("multDist_evt_gen"), vars.multTrue); - for (auto& particle : particles) { + for (const auto& particle : particles) { if (initParticle(particle) && vars.isChargedPrimary) { - histos.fill(HIST("multPtSpec_prim_gen"), vars.multTrue, particle.pt()); - if (!vars.isAcceptedEvent) { - histos.fill(HIST("multPtSpec_prim_gen_evtloss"), vars.multTrue, particle.pt()); + for (auto i = 0u; i < vars.nRepetitions; ++i) { + histos.fill(HIST("multPtSpec_prim_gen"), vars.multTrue, particle.pt()); + if (!vars.isAcceptedEvent) { + histos.fill(HIST("multPtSpec_prim_gen_evtloss"), vars.multTrue, particle.pt()); + } } } } @@ -329,8 +456,8 @@ void chargedSpectra::processTrue(const C& /*collision*/, const P& particles) * Function to process reconstructed data and MC. Assumes initEvent (and initEventMC in case of MC) have been called previously. */ //************************************************************************************************** -template -void chargedSpectra::processMeas(const C& /*collision*/, const T& tracks) +template +void ChargedParticles::processMeas(const T& tracks) { if (!vars.isAcceptedEvent) { return; @@ -345,8 +472,7 @@ void chargedSpectra::processMeas(const C& /*collision*/, const T& tracks) } std::vector foundParticles; - for (auto& track : tracks) { - + for (const auto& track : tracks) { if (!initTrack(track)) { continue; } @@ -368,7 +494,7 @@ void chargedSpectra::processMeas(const C& /*collision*/, const T& tracks) foundParticles.push_back(track.mcParticleId()); - const auto& particle = track.template mcParticle_as(); + const auto& particle = track.template mcParticle_as(); if (!vars.isAcceptedEventMC) { histos.fill(HIST("multPtSpec_trk_meas_evtcont"), vars.multMeas, track.pt()); @@ -377,20 +503,22 @@ void chargedSpectra::processMeas(const C& /*collision*/, const T& tracks) histos.fill(HIST("multPtSpec_trk_inter"), vars.multTrue, track.pt()); if (initParticle(particle)) { - if (!vars.isChargedPrimary) { - histos.fill(HIST("multPtSpec_trk_sec_meas"), vars.multMeas, track.pt()); - } else { - histos.fill(HIST("multCorrel_prim"), vars.multMeas, vars.multTrue); - histos.fill(HIST("ptCorrel_prim"), track.pt(), particle.pt()); - histos.fill(HIST("multPtSpec_prim_meas"), vars.multTrue, particle.pt()); - histos.fill(HIST("multPtSpec_trk_prim_meas"), vars.multMeas, track.pt()); + for (auto i = 0u; i < vars.nRepetitions; ++i) { + if (!vars.isChargedPrimary) { + histos.fill(HIST("multPtSpec_trk_sec_meas"), vars.multMeas, track.pt()); + } else { + histos.fill(HIST("multCorrel_prim"), vars.multMeas, vars.multTrue); + histos.fill(HIST("ptCorrel_prim"), track.pt(), particle.pt()); + histos.fill(HIST("multPtSpec_prim_meas"), vars.multTrue, particle.pt()); + histos.fill(HIST("multPtSpec_trk_prim_meas"), vars.multMeas, track.pt()); + } } } } } - std::unordered_set uniqueIndices(foundParticles.begin(), foundParticles.end()); - for (auto mcParticleID : uniqueIndices) { + std::unordered_set uniqueIndices(foundParticles.begin(), foundParticles.end()); + for (const auto& mcParticleID : uniqueIndices) { histos.fill(HIST("track_ambiguity"), std::count(foundParticles.begin(), foundParticles.end(), mcParticleID)); } } diff --git a/PWGLF/Tasks/Nuspex/chargedparticleRaa.cxx b/PWGLF/Tasks/Nuspex/chargedparticleRaa.cxx new file mode 100644 index 00000000000..20b8c919bcb --- /dev/null +++ b/PWGLF/Tasks/Nuspex/chargedparticleRaa.cxx @@ -0,0 +1,484 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file chargedparticleRaa.cxx +/// +/// \brief task for analysis of charged-particle RAA at midrapidity in light-ion collisions +/// \author Abhi Modak (abhi.modak@cern.ch) +/// \since October 01, 2025 + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" + +#include "Common/CCDB/EventSelectionParams.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/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.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 + +#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; + +using ColDataTablePbPb = soa::Join; +using ColDataTablepp = soa::Join; +using ColMCRecTablePbPb = soa::SmallGroups>; +using ColMCRecTablepp = soa::SmallGroups>; +using ColMCTrueTable = aod::McCollisions; +using TrackDataTable = soa::Join; +using FilTrackDataTable = soa::Filtered; +using TrackMCRecTable = soa::Join; +using FilTrackMCRecTable = soa::Filtered; +using TrackMCTrueTable = aod::McParticles; + +enum { + kTrackTypebegin = 0, + kGlobalplusITS = 1, + kGlobalonly, + kITSonly, + kTrackTypeend +}; + +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{15, 0.5, 15.5, "#Event", "EventAxis"}; +AxisSpec axisVtxZ{40, -20, 20, "Vertex Z", "VzAxis"}; +AxisSpec axisEta{40, -2, 2, "#eta", "EtaAxis"}; +AxisSpec axisPhi{629, 0, o2::constants::math::TwoPI, "#phi"}; +AxisSpec axisCent{100, 0, 100, "#Cent"}; +AxisSpec axisTrackType = {kTrackTypeend - 1, +kTrackTypebegin + 0.5, +kTrackTypeend - 0.5, "", "TrackTypeAxis"}; +auto static constexpr kMinCharge = 3.f; + +struct ChargedparticleRaa { + + 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 occuRange{"occuRange", 500.0f, "Occupancy range to consider"}; + Configurable dcaZ{"dcaZ", 0.2f, "Custom DCA Z cut (ignored if negative)"}; + Configurable cfgPtCutMin{"cfgPtCutMin", 0.15f, "minimum accepted track pT"}; + 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 ptHistBin{"ptHistBin", {200, 0., 20.}, ""}; + ConfigurableAxis centralityBinning{"centralityBinning", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, ""}; + 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 isApplySameBunchPileup{"isApplySameBunchPileup", false, "Enable SameBunchPileup cut"}; + Configurable isApplyGoodZvtxFT0vsPV{"isApplyGoodZvtxFT0vsPV", false, "Enable GoodZvtxFT0vsPV cut"}; + Configurable isApplyExtraPhiCut{"isApplyExtraPhiCut", false, "Enable extra phi 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 isApplyInelgt0{"isApplyInelgt0", false, "Enable INEL > 0 condition"}; + Configurable isApplyOccuCut{"isApplyOccuCut", false, "Enable occupancy selection"}; + + void init(InitContext const&) + { + AxisSpec centAxis = {centralityBinning, "Centrality", "CentralityAxis"}; + AxisSpec axisPt = {ptHistBin, "pT", "pTAxis"}; + AxisSpec impactParAxis = {binsImpactPar, "Impact Parameter"}; + + histos.add("EventHist", "EventHist", kTH1D, {axisEvent}, false); + histos.add("VtxZHist", "VtxZHist", kTH1D, {axisVtxZ}, false); + histos.add("CentPercentileHist", "CentPercentileHist", kTH1D, {axisCent}, false); + histos.add("CentPercentileMCRecHist", "CentPercentileMCRecHist", kTH1D, {axisCent}, false); + histos.add("PhiVsEtaHistNoCut", "PhiVsEtaHistNoCut", kTH2D, {axisPhi, axisEta}, false); + histos.add("PhiVsEtaHistWithCut", "PhiVsEtaHistWithCut", kTH2D, {axisPhi, axisEta}, false); + + if (doprocessDataPbPb) { + histos.add("hdatazvtxcent", "hdatazvtxcent", kTH2D, {axisVtxZ, centAxis}, false); + histos.add("hdatahistPbPb", "hdatahistPbPb", kTHnSparseD, {axisVtxZ, centAxis, axisPt, axisTrackType}, false); + } + + if (doprocessDatapp) { + histos.add("hdatahistpp", "hdatahistpp", kTHnSparseD, {axisVtxZ, axisPt, axisTrackType}, false); + } + + if (doprocessMCPbPb) { + histos.add("hmczvtxcent", "hmczvtxcent", kTH2D, {axisVtxZ, centAxis}, false); + histos.add("hmcrechistPbPb", "hmcrechistPbPb", kTHnSparseD, {axisVtxZ, centAxis, axisPt, axisTrackType}, false); + histos.add("hmcgenhistPbPb", "hmcgenhistPbPb", kTHnSparseD, {axisVtxZ, centAxis, axisPt}, false); + } + + if (doprocessMCpp) { + histos.add("hmcrechistpp", "hmcrechistpp", kTHnSparseD, {axisVtxZ, axisPt, axisTrackType}, false); + histos.add("hmcgenhistpp", "hmcgenhistpp", kTHnSparseD, {axisVtxZ, axisPt}, false); + } + + if (doprocessEvtLossSigLossMCpp || doprocessEvtLossSigLossMCPbPb) { + histos.add("MCEventHist", "MCEventHist", kTH1F, {axisEvent}, false); + auto hstat = histos.get(HIST("MCEventHist")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "All MC events"); + x->SetBinLabel(2, "MC events with atleast one reco event"); + histos.add("hgenptBeforeEvtSel", "hgenptBeforeEvtSel", kTH1F, {axisPt}, false); + histos.add("hgenptAfterEvtSel", "hgenptAfterEvtSel", kTH1F, {axisPt}, false); + histos.add("hgenptBeforeEvtSelPbPb", "hgenptBeforeEvtSelPbPb", kTH2F, {axisPt, impactParAxis}, false); + histos.add("hgenptAfterEvtSelPbPb", "hgenptAfterEvtSelPbPb", kTH2F, {axisPt, impactParAxis}, false); + histos.add("hImpactParameterGen", "Impact parameter of generated MC events", kTH1F, {impactParAxis}); + histos.add("hImpactParameterRec", "Impact parameter of selected MC events", kTH1F, {impactParAxis}); + histos.add("hImpactParvsCentrRec", "Impact parameter of selected MC events vs centrality", kTH2F, {axisCent, impactParAxis}); + } + + 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, "ApplyNoCollInTimeRangeStandard"); + x->SetBinLabel(6, "ApplyNoCollInRofStandard"); + x->SetBinLabel(7, "ApplyNoHighMultCollInPrevRof"); + x->SetBinLabel(8, "INEL > 0"); + x->SetBinLabel(9, "|vz|<10"); + x->SetBinLabel(10, "Occupancy<500"); + } + + 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 (isApplyNoCollInTimeRangeStandard && !col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 5); + + if (isApplyNoCollInRofStandard && !col.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + histos.fill(HIST("EventHist"), 6); + + if (isApplyNoHighMultCollInPrevRof && !col.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + histos.fill(HIST("EventHist"), 7); + + if (isApplyInelgt0 && !col.isInelGt0()) { + return false; + } + histos.fill(HIST("EventHist"), 8); + + if (std::abs(col.posZ()) >= vtxRange) { + return false; + } + histos.fill(HIST("EventHist"), 9); + + auto occu = isApplyFT0CbasedOccupancy ? col.ft0cOccupancyInTimeRange() : col.trackOccupancyInTimeRange(); + if (isApplyOccuCut && occu > occuRange) { + return false; + } + histos.fill(HIST("EventHist"), 10); + return true; + } + + template + bool isTrackSelected(CheckTrack const& track) + { + if (std::abs(track.eta()) >= etaRange) { + return false; + } + histos.fill(HIST("PhiVsEtaHistNoCut"), track.phi(), track.eta()); + if (isApplyExtraPhiCut && ((track.phi() > extraphicut1 && track.phi() < extraphicut2) || track.phi() <= extraphicut3 || track.phi() >= extraphicut4)) { + return false; + } + histos.fill(HIST("PhiVsEtaHistWithCut"), track.phi(), track.eta()); + 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; + } + + 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 = ifnode(dcaZ.node() > 0.f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly), + ncheckbit(aod::track::trackCutFlag, TrackSelectionDca)); + Filter fTracksPt = aod::track::pt > cfgPtCutMin; + + void processDataPbPb(ColDataTablePbPb::iterator const& cols, FilTrackDataTable const& tracks) + { + if (!isEventSelected(cols)) { + return; + } + histos.fill(HIST("VtxZHist"), cols.posZ()); + histos.fill(HIST("CentPercentileHist"), cols.centFT0C()); + histos.fill(HIST("hdatazvtxcent"), cols.posZ(), cols.centFT0C()); + + for (const auto& track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + histos.fill(HIST("hdatahistPbPb"), cols.posZ(), cols.centFT0C(), track.pt(), kGlobalplusITS); + if (track.hasTPC()) { + histos.fill(HIST("hdatahistPbPb"), cols.posZ(), cols.centFT0C(), track.pt(), kGlobalonly); + } else { + histos.fill(HIST("hdatahistPbPb"), cols.posZ(), cols.centFT0C(), track.pt(), kITSonly); + } + } + } + + void processDatapp(ColDataTablepp::iterator const& cols, FilTrackDataTable const& tracks) + { + if (!isEventSelected(cols)) { + return; + } + histos.fill(HIST("VtxZHist"), cols.posZ()); + + for (const auto& track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + histos.fill(HIST("hdatahistpp"), cols.posZ(), track.pt(), kGlobalplusITS); + if (track.hasTPC()) { + histos.fill(HIST("hdatahistpp"), cols.posZ(), track.pt(), kGlobalonly); + } else { + histos.fill(HIST("hdatahistpp"), cols.posZ(), track.pt(), kITSonly); + } + } + } + + void processMCPbPb(ColMCTrueTable::iterator const&, ColMCRecTablePbPb 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"), RecCol.centFT0C()); + histos.fill(HIST("hmczvtxcent"), RecCol.posZ(), RecCol.centFT0C()); + + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + for (const auto& Rectrack : recTracksPart) { + if (!isTrackSelected(Rectrack)) { + continue; + } + histos.fill(HIST("hmcrechistPbPb"), RecCol.posZ(), RecCol.centFT0C(), Rectrack.pt(), kGlobalplusITS); + if (Rectrack.hasTPC()) { + histos.fill(HIST("hmcrechistPbPb"), RecCol.posZ(), RecCol.centFT0C(), Rectrack.pt(), kGlobalonly); + } else { + histos.fill(HIST("hmcrechistPbPb"), RecCol.posZ(), RecCol.centFT0C(), Rectrack.pt(), kITSonly); + } + } // track (mcrec) loop + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgenhistPbPb"), RecCol.posZ(), RecCol.centFT0C(), particle.pt()); + } // track (mcgen) loop + } // collision loop + } + + void processMCpp(ColMCTrueTable::iterator const&, ColMCRecTablepp const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + histos.fill(HIST("VtxZHist"), RecCol.posZ()); + + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + for (const auto& Rectrack : recTracksPart) { + if (!isTrackSelected(Rectrack)) { + continue; + } + histos.fill(HIST("hmcrechistpp"), RecCol.posZ(), Rectrack.pt(), kGlobalplusITS); + if (Rectrack.hasTPC()) { + histos.fill(HIST("hmcrechistpp"), RecCol.posZ(), Rectrack.pt(), kGlobalonly); + } else { + histos.fill(HIST("hmcrechistpp"), RecCol.posZ(), Rectrack.pt(), kITSonly); + } + } // track (mcrec) loop + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hmcgenhistpp"), RecCol.posZ(), particle.pt()); + } // track (mcgen) loop + } // collision loop + } + + void processEvtLossSigLossMCpp(soa::Join::iterator const& mcCollision, ColMCRecTablepp const& RecCols, TrackMCTrueTable const& GenParticles) + { + if (isApplyInelgt0 && !mcCollision.isInelGt0()) { + return; + } + if (std::abs(mcCollision.posZ()) >= vtxRange) { + return; + } + // All generated events + histos.fill(HIST("MCEventHist"), 1); + + bool atLeastOne = false; + auto numcontributors = -999; + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (RecCol.numContrib() <= numcontributors) { + continue; + } else { + numcontributors = RecCol.numContrib(); + } + atLeastOne = true; + } + if (atLeastOne) { + histos.fill(HIST("MCEventHist"), 2); + } + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + // All generated particles + histos.fill(HIST("hgenptBeforeEvtSel"), particle.pt()); + if (atLeastOne) { + // All generated particles with at least one reconstructed collision (signal loss estimation) + histos.fill(HIST("hgenptAfterEvtSel"), particle.pt()); + } + } + } + + void processEvtLossSigLossMCPbPb(soa::Join::iterator const& mcCollision, ColMCRecTablePbPb const& RecCols, TrackMCTrueTable const& GenParticles) + { + if (isApplyInelgt0 && !mcCollision.isInelGt0()) { + return; + } + if (std::abs(mcCollision.posZ()) >= vtxRange) { + return; + } + // All generated events + histos.fill(HIST("MCEventHist"), 1); + histos.fill(HIST("hImpactParameterGen"), mcCollision.impactParameter()); + + bool atLeastOne = false; + auto centrality = -999.; + auto numcontributors = -999; + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (RecCol.numContrib() <= numcontributors) { + continue; + } else { + numcontributors = RecCol.numContrib(); + } + centrality = RecCol.centFT0C(); + atLeastOne = true; + } + if (atLeastOne) { + histos.fill(HIST("MCEventHist"), 2); + histos.fill(HIST("hImpactParameterRec"), mcCollision.impactParameter()); + histos.fill(HIST("hImpactParvsCentrRec"), centrality, mcCollision.impactParameter()); + } + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + // All generated particles + histos.fill(HIST("hgenptBeforeEvtSelPbPb"), particle.pt(), mcCollision.impactParameter()); + if (atLeastOne) { + // All generated particles with at least one reconstructed collision (signal loss estimation) + histos.fill(HIST("hgenptAfterEvtSelPbPb"), particle.pt(), mcCollision.impactParameter()); + } + } + } + + PROCESS_SWITCH(ChargedparticleRaa, processDataPbPb, "process data heavy-ion", false); + PROCESS_SWITCH(ChargedparticleRaa, processDatapp, "process data pp", false); + PROCESS_SWITCH(ChargedparticleRaa, processMCPbPb, "process MC heavy-ion", false); + PROCESS_SWITCH(ChargedparticleRaa, processMCpp, "process MC pp", false); + PROCESS_SWITCH(ChargedparticleRaa, processEvtLossSigLossMCpp, "process Signal Loss, Event Loss", false); + PROCESS_SWITCH(ChargedparticleRaa, processEvtLossSigLossMCPbPb, "process Signal Loss, Event Loss", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx b/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx new file mode 100644 index 00000000000..441056dc30e --- /dev/null +++ b/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx @@ -0,0 +1,1532 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 dedxPidAnalysis.cxx +/// \brief Analysis to do PID + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "TF1.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +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, aod::pidTPCPi, aod::pidTPCPr, aod::pidTPCEl>; + +using SelectedCollisions = soa::Join; +using BCsRun3 = soa::Join; + +static constexpr int kNCentHists{10}; +std::array, kNCentHists> hDedxVsMomentumVsCentPos{}; +std::array, kNCentHists> hDedxVsMomentumVsCentNeg{}; + +struct DedxPidAnalysis { + + // dE/dx for all charged particles + HistogramRegistry registryDeDx{ + "registryDeDx", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + // Constant values + static constexpr int kEtaIntervals = 8; + static constexpr int kParticlesType = 4; + static constexpr int kCentralityClasses = 10; + float tpcCut = 0.6; + float pionMin = 0.35; + float pionMax = 0.45; + float elTofCut = 0.1; + float pionTofCut = 1.0; + float pTcut = 2.0; + + bool fillHist = false; + + enum V0SelectionMode { + V0TPC = 1, + V0TOF = 2, + V0TPCTOF = 3 + + }; + + enum MomentumMode { + TpcInnerParam = 1, + TotalMomentum = 2 + }; + + // Event cut labels + enum EvCutLabel { + AllEv = 1, + SelEigth, + ZVtxCut, + NoSameBunchPileup, + GoodZvtxFT0vsPV + + }; + + // Track primary label + enum TrkPriCutLabel { + AllPri = 1, + SelectionPrim, + PhiVarCutPri, + NClTPCFoundCutPri, + NClTPCPIDCutPri + }; + + // Track secondary lebel + enum TrkSecCutLabel { + AllSec = 1, + V0Type, + V0CosPA, + V0DecayRadius, + V0Daughters, + TPCRefit, + PhiVarCutSec, + NClTPCFoundCutSec, + NClTPCPIDCutSec, + AllK0s, + V0RapidityK0s, + V0ProperLifetimeK0s, + MassCutK0s, + AllLambda, + V0RapidityLambda, + V0ProperLifetimeLambda, + MassCutLambda, + AllAntiLambda, + V0RapidityAntiLambda, + V0ProperLifetimeAntiLambda, + MassCutAntiLambda, + AllGamma, + V0RapidityGamma, + MassCutGamma + }; + // Configurable Parameters + // Tracks cuts + Configurable minTPCnClsFound{"minTPCnClsFound", 70.0f, + "min number of found TPC clusters"}; + Configurable minTPCnClsPID{"minTPCnClsPID", 70.0f, + "min number of PID 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 maxZDistanceToIP{"maxZDistanceToIP", 10.0f, + "max z distance to IP"}; + 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", 0.1f, "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 v0rapidityCut{"v0rapidityCut", 0.5f, "V0 rapidity cut"}; + Configurable v0ProperLifetimeCutK0s{"v0ProperLifetimeCutK0s", 20.f, "V0 proper lifetime cut for K0s"}; + Configurable v0ProperLifetimeCutLambda{"v0ProperLifetimeCutLambda", 30.f, "V0 proper lifetime cut for Lambda"}; + Configurable nsigmaTOFmax{"nsigmaTOFmax", 3.0f, "Maximum nsigma TOF"}; + Configurable invMassCutK0s{"invMassCutK0s", 0.2f, "invariant Mass Cut for K0s"}; + Configurable invMassCutLambda{"invMassCutLambda", 0.1f, "invariant Mass Cut for Lambda"}; + Configurable invMassCutGamma{"invMassCutGamma", 0.1f, "invariant Mass Cut for Gamma"}; + Configurable calibrationMode{"calibrationMode", false, "calibration mode"}; + Configurable phiVarCut{"phiVarCut", true, "phi var cut"}; + Configurable nClTPCFoundCut{"nClTPCFoundCut", false, "number of found clusters in TPC cut"}; + Configurable nClTPCPIDCut{"nClTPCPIDCut", true, "number of PID clusters in TPC cut"}; + Configurable v0SelectionMode{"v0SelectionMode", 3, "V0 Selection base on TPC: 1, TOF:2 ,Both:3"}; + Configurable momentumMode{"momentumMode", 1, "1: TPC inner param, 2: Total momentum p"}; + Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + Configurable lowParam1{"lowParam1", 0.119297, "First parameter for low phi cut"}; + Configurable lowParam2{"lowParam2", 0.000379693, "Second parameter for low phi cut"}; + Configurable highParam1{"highParam1", 0.16685, "First parameter for high phi cut"}; + Configurable highParam2{"highParam2", 0.00981942, "Second parameter for high phi cut"}; + // Histograms names + static constexpr std::string_view kDedxvsMomentumPos[kParticlesType] = {"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[kParticlesType] = {"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 std::string_view kDedxvsMomentumvsCentPos[kCentralityClasses] = {"dEdx_vs_Momentum_Cent0_1_Pos", "dEdx_vs_Momentum_Cent1_5_Pos", "dEdx_vs_Momentum_Cent5_10_Pos", "dEdx_vs_Momentum_Cent10_15_Pos", "dEdx_vs_Momentum_Cent15_20_Pos", "dEdx_vs_Momentum_Cent20_30_Pos", "dEdx_vs_Momentum_Cent30_40_Pos", "dEdx_vs_Momentum_Cent40_50_Pos", "dEdx_vs_Momentum_Cent50_70_Pos", "dEdx_vs_Momentum_Cent70_100_Pos"}; + static constexpr std::string_view kDedxvsMomentumvsCentNeg[kCentralityClasses] = {"dEdx_vs_Momentum_Cent0_1_Neg", "dEdx_vs_Momentum_Cent1_5_Neg", "dEdx_vs_Momentum_Cent5_10_Neg", "dEdx_vs_Momentum_Cent10_15_Neg", "dEdx_vs_Momentum_Cent15_20_Neg", "dEdx_vs_Momentum_Cent20_30_Neg", "dEdx_vs_Momentum_Cent30_40_Neg", "dEdx_vs_Momentum_Cent40_50_Neg", "dEdx_vs_Momentum_Cent50_70_Neg", "dEdx_vs_Momentum_Cent70_100_Neg"}; + // Ncl TPC + static constexpr std::string_view kNclTPCDedxMomentumNegBefore[kEtaIntervals] = {"Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_1_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_2_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_3_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_4_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_5_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_6_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_7_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_8_Before"}; + static constexpr std::string_view kNclTPCDedxMomentumPosBefore[kEtaIntervals] = {"Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_1_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_2_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_3_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_4_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_5_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_6_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_7_Before", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_8_Before"}; + static constexpr std::string_view kNclTPCDedxMomentumNegAfter[kEtaIntervals] = {"Ncl_TFoundPC_vs_dEdx_vs_Momentum_Neg_1_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_2_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_3_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_4_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_5_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_6_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_7_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Neg_8_After"}; + static constexpr std::string_view kNclTPCDedxMomentumPosAfter[kEtaIntervals] = {"Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_1_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_2_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_3_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_4_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_5_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_6_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_7_After", "Ncl_FoundTPC_vs_dEdx_vs_Momentum_Pos_8_After"}; + // Ncl PID TPC + static constexpr std::string_view kNclPIDTPCDedxMomentumNegBefore[kEtaIntervals] = {"Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_1_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_2_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_3_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_4_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_5_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_6_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_7_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_8_Before"}; + static constexpr std::string_view kNclPIDTPCDedxMomentumPosBefore[kEtaIntervals] = {"Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_1_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_2_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_3_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_4_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_5_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_6_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_7_Before", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_8_Before"}; + static constexpr std::string_view kNclPIDTPCDedxMomentumNegAfter[kEtaIntervals] = {"Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_1_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_2_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_3_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_4_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_5_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_6_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_7_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Neg_8_After"}; + static constexpr std::string_view kNclPIDTPCDedxMomentumPosAfter[kEtaIntervals] = {"Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_1_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_2_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_3_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_4_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_5_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_6_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_7_After", "Ncl_PIDTPC_vs_dEdx_vs_Momentum_Pos_8_After"}; + static constexpr double EtaCut[kEtaIntervals + 1] = {-0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8}; + static constexpr double CentClasses[kCentralityClasses + 1] = {0.0, 0.1, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 70.0, 100.0}; + 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}, ""}; + + // phi cut fits + TF1* fphiCutHigh = nullptr; + TF1* fphiCutLow = nullptr; + Service ccdb; + + 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, 2}); + selectedTracks.SetMaxChi2PerClusterITS(maxChi2ITS); + selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / std::pow(pt, 1.1f); }); + selectedTracks.SetMaxDcaZ(maxDCAz); + selectedTracks.SetRequireGoldenChi2(true); + + return selectedTracks; + } + + TrackSelection mySelectionPrim; + + void init(InitContext const&) + { + if (v0SelectionMode == V0TPC) { + LOGF(info, "V0 seleccion using TPC only"); + } else if (v0SelectionMode == V0TOF) { + LOGF(info, "V0 seleccion using TOF only"); + } else if (v0SelectionMode == V0TPCTOF) { + LOGF(info, "V0 seleccion using TOF + TPC"); + } + if (calibrationMode) { + LOGF(info, "Calibration mode activated"); + } else { + LOGF(info, "Running data applying calibration values"); + } + + if (phiVarCut) { + LOGF(info, "Applying phi prime cut"); + } else { + LOGF(info, "Phi prime cut disabled"); + } + + if (nClTPCFoundCut) { + LOGF(info, "Applying TPC found clusters cut"); + } else { + LOGF(info, "TPC found clusters cut disabled"); + } + + if (nClTPCPIDCut) { + LOGF(info, "Applying TPC clusters for PID cut"); + } else { + LOGF(info, "TPC clusters for PID cut disabled"); + } + if (momentumMode == TpcInnerParam) { + LOGF(info, "Using TPC inner parameter for momentum calculation"); + } else { + LOGF(info, "Using total momentum (p) for calculation"); + } + LOGF(info, "Centrality clases between %.1f - %.1f", CentClasses[0], CentClasses[10]); + + AxisSpec dedxAxis{100, 0.0, 100.0, "dE/dx (a. u.)"}; + AxisSpec ptAxis = {binP, "pT (GeV/c)"}; + AxisSpec etaAxis{8, -0.8, 0.8, "#eta"}; + AxisSpec pAxis = {binP, "#it{p}/Z (GeV/c)"}; + AxisSpec pAxisTrack = {binP, "#it{p} (GeV/c)"}; + fphiCutLow = new TF1("StandardPhiCutLow", + Form("%f/x/x+pi/18.0-%f", lowParam1.value, lowParam2.value), + 0, 50); + fphiCutHigh = new TF1("StandardPhiCutHigh", + Form("%f/x+pi/18.0+%f", highParam1.value, highParam2.value), + 0, 50); + LOGF(info, "=== Phi Cut Parameters ==="); + LOGF(info, "Low cut: %.6f/x² + pi/18 - %.6f", lowParam1.value, lowParam2.value); + LOGF(info, "High cut: %.6f/x + pi/18 + %.6f", highParam1.value, highParam2.value); + + 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}}); + + // pt vs p + registryDeDx.add( + "heta_vs_pt_vs_p_all_Neg", "eta_vs_pT_vs_p", HistType::kTH3F, + {{etaAxis}, {ptAxis}, {pAxisTrack}}); + registryDeDx.add( + "heta_vs_pt_vs_p_all_Pos", "eta_vs_pT_vs_p", HistType::kTH3F, + {{etaAxis}, {ptAxis}, {pAxisTrack}}); + + // De/Dx for ch and v0 particles + for (int i = 0; i < kParticlesType; ++i) { + registryDeDx.add(kDedxvsMomentumPos[i].data(), "dE/dx", HistType::kTH3F, + {{pAxisTrack}, {dedxAxis}, {etaAxis}}); + registryDeDx.add(kDedxvsMomentumNeg[i].data(), "dE/dx", HistType::kTH3F, + {{pAxisTrack}, {dedxAxis}, {etaAxis}}); + } + + for (int i = 0; i < kCentralityClasses; ++i) { + hDedxVsMomentumVsCentPos[i] = registryDeDx.add(kDedxvsMomentumvsCentPos[i].data(), "dE/dx", HistType::kTH3F, {{pAxisTrack}, {dedxAxis}, {etaAxis}}); + hDedxVsMomentumVsCentNeg[i] = registryDeDx.add(kDedxvsMomentumvsCentNeg[i].data(), "dE/dx", HistType::kTH3F, {{pAxisTrack}, {dedxAxis}, {etaAxis}}); + } + } + + registryDeDx.add( + "hdEdx_vs_phi", "dE/dx", HistType::kTH2F, + {{100, 0.0, 6.4, "#phi"}, {dedxAxis}}); + // phi cut + if (phiVarCut) { + // pt for found + registryDeDx.add( + "hpt_vs_phi_NclFound_TPC_After", "phi cut vs pt", HistType::kTH3F, + {{ptAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl, found}"}}); + + registryDeDx.add( + "hpt_vs_phi_NclFound_TPC_Before", "phi cut vs pt", HistType::kTH3F, + {{ptAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl, found}"}}); + // p + registryDeDx.add( + "hp_vs_phi_NclFound_TPC_After", "phi cut vs p", HistType::kTH3F, + {{pAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl, found}"}}); + + registryDeDx.add( + "hp_vs_phi_NclFound_TPC_Before", "phi cut vs p", HistType::kTH3F, + {{pAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl, found}"}}); + + // pt for PID + registryDeDx.add( + "hpt_vs_phi_NclPID_TPC_After", "phi cut vs pt", HistType::kTH3F, + {{ptAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hpt_vs_phi_NclPID_TPC_Before", "phi cut vs pt", HistType::kTH3F, + {{ptAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl, PID}"}}); + // p + registryDeDx.add( + "hp_vs_phi_NclPID_TPC_After", "phi cut vs p", HistType::kTH3F, + {{pAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_phi_NclPID_TPC_Before", "phi cut vs p", HistType::kTH3F, + {{pAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl, PID}"}}); + } + // Ncl vs de/dx TPC + if (nClTPCFoundCut) { + for (int i = 0; i < kEtaIntervals; ++i) { + registryDeDx.add(kNclTPCDedxMomentumPosBefore[i].data(), "Ncl found TPC vs dE/dx vs Momentum Positive before", HistType::kTH3F, + {{100, 0, 160, "N_{cl, found}^{TPC}"}, {dedxAxis}, {pAxis}}); + registryDeDx.add(kNclTPCDedxMomentumNegBefore[i].data(), "Ncl found TPC vs dE/dx vs Momentum Negative before", HistType::kTH3F, + {{100, 0, 160, "N_{cl, found}^{TPC}"}, {dedxAxis}, {pAxis}}); + + registryDeDx.add(kNclTPCDedxMomentumPosAfter[i].data(), "Ncl found TPC vs dE/dx vs Momentum Positive after", HistType::kTH3F, + {{100, 0, 160, "N_{cl, found}^{TPC}"}, {dedxAxis}, {pAxis}}); + registryDeDx.add(kNclTPCDedxMomentumNegAfter[i].data(), "Ncl found TPC vs dE/dx vs Momentum Negative after", HistType::kTH3F, + {{100, 0, 160, "N_{cl, found}^{TPC}"}, {dedxAxis}, {pAxis}}); + } + } + + // Ncl vs de/dx ITS + if (nClTPCPIDCut) { + for (int i = 0; i < kEtaIntervals; ++i) { + registryDeDx.add(kNclPIDTPCDedxMomentumPosBefore[i].data(), "Ncl PID TPC vs dE/dx vs Momentum Positive before", HistType::kTH3F, + {{100, 0, 160, "N_{cl, PID}^{TPC}"}, {dedxAxis}, {pAxis}}); + registryDeDx.add(kNclPIDTPCDedxMomentumNegBefore[i].data(), "Ncl PID TPC vs dE/dx vs Momentum Negative before", HistType::kTH3F, + {{100, 0, 160, "N_{cl, PID}^{TPC}"}, {dedxAxis}, {pAxis}}); + + registryDeDx.add(kNclPIDTPCDedxMomentumPosAfter[i].data(), "Ncl PID TPC vs dE/dx vs Momentum Positive after", HistType::kTH3F, + {{100, 0, 160, "N_{cl, PID}^{TPC}"}, {dedxAxis}, {pAxis}}); + registryDeDx.add(kNclPIDTPCDedxMomentumNegAfter[i].data(), "Ncl PID TPC vs dE/dx vs Momentum Negative after", HistType::kTH3F, + {{100, 0, 160, "N_{cl, PID}^{TPC}"}, {dedxAxis}, {pAxis}}); + } + } + // eta + registryDeDx.add( + "heta_vs_NclFound_TPC_Before_Primary", "eta and N_{cl}", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, found}"}}); + + registryDeDx.add( + "heta_vs_NclFound_TPC_After_Primary", "eta and N_{cl} ", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, found}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_Before_Primary", "eta and N_{cl, PID}", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_After_Primary", "eta and N_{cl, PID} ", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + // momentum for primaries + registryDeDx.add( + "hp_vs_NclPID_TPC_Before_Primary", "p and N_{cl, PID}", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_NclPID_TPC_After_Primary", "p and N_{cl, PID} ", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + // eta for secondaries + registryDeDx.add( + "heta_vs_NclPID_TPC_Before_PionsK0s", "eta and N_{cl, PID}", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_After_PionsK0s", "eta and N_{cl, PID} ", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_Before_PionsLambda", "eta and N_{cl, PID}", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_After_PionsLambda", "eta and N_{cl, PID} ", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_Before_ProtonsLambda", "eta and N_{cl, PID}", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_After_ProtonsLambda", "eta and N_{cl, PID} ", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_Before_ElectronsGamma", "eta and N_{cl, PID}", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "heta_vs_NclPID_TPC_After_ElectronsGamma", "eta and N_{cl, PID} ", HistType::kTH2F, + {{100, -0.8, 0.8, "#eta"}, {100, 0, 160, "N_{cl, PID}"}}); + + // momentum for secondaries + registryDeDx.add( + "hp_vs_NclPID_TPC_Before_PionsK0s", "p and N_{cl, PID}", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_NclPID_TPC_After_PionsK0s", "p and N_{cl, PID} ", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_NclPID_TPC_Before_PionsLambda", "p and N_{cl, PID}", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_NclPID_TPC_After_PionsLambda", "p and N_{cl, PID} ", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_NclPID_TPC_Before_ProtonsLambda", "p and N_{cl, PID}", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_NclPID_TPC_After_ProtonsLambda", "p and N_{cl, PID} ", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_NclPID_TPC_Before_ElectronsGamma", "p and N_{cl, PID}", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + registryDeDx.add( + "hp_vs_NclPID_TPC_After_ElectronsGamma", "p and N_{cl, PID} ", HistType::kTH2F, + {{pAxisTrack}, {100, 0, 160, "N_{cl, PID}"}}); + + // beta plot + 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)"}}); + + // Event Counter + registryDeDx.add("evsel", "events selected", HistType::kTH1F, {{5, 0.5, 5.5, ""}}); + auto hstat = registryDeDx.get(HIST("evsel")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(AllEv, "AllEv"); + x->SetBinLabel(SelEigth, "SelEigth"); + x->SetBinLabel(ZVtxCut, "ZVtxCut"); + x->SetBinLabel(NoSameBunchPileup, "NoSameBunchPileup"); + x->SetBinLabel(GoodZvtxFT0vsPV, "GoodZvtxFT0vsPV"); + + // Track Counter + registryDeDx.add("trackselAll", "track selected all particles", HistType::kTH1F, {{5, 0.5, 6.5, ""}}); + auto htrackAll = registryDeDx.get(HIST("trackselAll")); + auto* xAll = htrackAll->GetXaxis(); + xAll->SetBinLabel(AllPri, "AllPri"); + xAll->SetBinLabel(SelectionPrim, "SelectionPrim"); + xAll->SetBinLabel(PhiVarCutPri, "PhiVarCutPri"); + xAll->SetBinLabel(NClTPCFoundCutPri, "NClTPCFoundCutPri"); + xAll->SetBinLabel(NClTPCPIDCutPri, "NClTPCPIDCutPri"); + + registryDeDx.add("trackselSec", "track selected sec particles", HistType::kTH1F, {{24, 0.5, 24.5, ""}}); + auto htrackSec = registryDeDx.get(HIST("trackselSec")); + auto* xSec = htrackSec->GetXaxis(); + xSec->SetBinLabel(AllSec, "AllSec"); + xSec->SetBinLabel(V0Type, "V0Type"); + xSec->SetBinLabel(V0CosPA, "V0CosPA"); + xSec->SetBinLabel(V0DecayRadius, "V0DecayRadius"); + xSec->SetBinLabel(V0Daughters, "V0Daughters"); + xSec->SetBinLabel(TPCRefit, "TPCRefit"); + xSec->SetBinLabel(PhiVarCutSec, "PhiVarCutSec"); + xSec->SetBinLabel(NClTPCFoundCutSec, "NClTPCFoundCutSec"); + xSec->SetBinLabel(NClTPCPIDCutSec, "NClTPCPIDCutSec"); + xSec->SetBinLabel(AllK0s, "AllK0s"); + xSec->SetBinLabel(V0RapidityK0s, "V0RapidityK0s"); + xSec->SetBinLabel(V0ProperLifetimeK0s, "V0ProperLifetimeK0s"); + xSec->SetBinLabel(MassCutK0s, "MassCutK0s"); + xSec->SetBinLabel(AllLambda, "AllLambda"); + xSec->SetBinLabel(V0RapidityLambda, "V0RapidityLambda"); + xSec->SetBinLabel(V0ProperLifetimeLambda, "V0ProperLifetimeLambda"); + xSec->SetBinLabel(MassCutLambda, "MassCutLambda"); + xSec->SetBinLabel(AllAntiLambda, "AllAntiLambda"); + xSec->SetBinLabel(V0RapidityAntiLambda, "V0RapidityAntiLambda"); + xSec->SetBinLabel(V0ProperLifetimeAntiLambda, "V0ProperLifetimeAntiLambda"); + xSec->SetBinLabel(MassCutAntiLambda, "MassCutAntiLambda"); + xSec->SetBinLabel(AllGamma, "AllGamma"); + xSec->SetBinLabel(V0RapidityGamma, "V0RapidityGamma"); + xSec->SetBinLabel(MassCutGamma, "MassCutGamma"); + + mySelectionPrim = myTrackSelection(); + } + + // Single-Track Selection + template + bool passedSingleTrackSelection(const T1& track, const C& /*collision*/) + { + // Single-Track Selections + 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; + } + + // Momentum + template + float getMomentum(const T1& track) + { + return (momentumMode == TpcInnerParam) ? track.tpcInnerParam() : track.p(); + }; + + // General V0 Selections + template + bool passedV0Selection(const T1& v0, const C& /*collision*/) + { + if (v0.v0cosPA() < v0cospaMin) + return false; + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0CosPA); + + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0DecayRadius); + + if (v0.dcaV0daughters() > dcaV0DaughtersMax) + return false; + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0Daughters); + + 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; + double sigmap = 0.0; + double sigman = 0.0; + + if (v0SelectionMode == V0TPC) { + sigmap = ptrack.tpcNSigmaPi(); + sigman = ntrack.tpcNSigmaPi(); + } else if (v0SelectionMode == V0TOF) { + sigmap = ptrack.tofNSigmaPi(); + sigman = ntrack.tofNSigmaPi(); + } else if (v0SelectionMode == V0TPCTOF) { + sigmap = std::hypot(ptrack.tpcNSigmaPi(), ptrack.tofNSigmaPi()); + sigman = std::hypot(ntrack.tpcNSigmaPi(), ntrack.tofNSigmaPi()); + } + + if (ptrack.tpcInnerParam() > tpcCut) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(sigmap) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > tpcCut) { + if (!ntrack.hasTOF()) + return false; + if (std::abs(sigman) > nsigmaTOFmax) + return false; + } + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllK0s); + + if (std::abs(v0.yK0Short()) > v0rapidityCut) + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityK0s); + + float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + + if (properLifetime > v0ProperLifetimeCutK0s) + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeK0s); + + if (std::abs(v0.mK0Short() - MassK0Short) > invMassCutK0s) + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::MassCutK0s); + + 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; + + double sigmap = 0.0; + double sigman = 0.0; + + if (v0SelectionMode == V0TPC) { + sigmap = ptrack.tpcNSigmaPr(); + sigman = ntrack.tpcNSigmaPi(); + } else if (v0SelectionMode == V0TOF) { + sigmap = ptrack.tofNSigmaPr(); + sigman = ntrack.tofNSigmaPi(); + } else if (v0SelectionMode == V0TPCTOF) { + sigmap = std::hypot(ptrack.tpcNSigmaPr(), ptrack.tofNSigmaPr()); + sigman = std::hypot(ntrack.tpcNSigmaPi(), ntrack.tofNSigmaPi()); + } + + if (ptrack.tpcInnerParam() > tpcCut) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(sigmap) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > tpcCut) { + if (!ntrack.hasTOF()) + return false; + if (std::abs(sigman) > nsigmaTOFmax) + return false; + } + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllLambda); + + if (std::abs(v0.yLambda()) > v0rapidityCut) + return false; + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityLambda); + + float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda; + + if (properLifetime > v0ProperLifetimeCutLambda) + return false; + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeLambda); + + if (std::abs(v0.mLambda() - MassLambda) > invMassCutLambda) { + return false; + } + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::MassCutLambda); + + 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; + double sigmap = 0.0; + double sigman = 0.0; + + if (v0SelectionMode == V0TPC) { + sigmap = ptrack.tpcNSigmaPi(); + sigman = ntrack.tpcNSigmaPr(); + } else if (v0SelectionMode == V0TOF) { + sigmap = ptrack.tofNSigmaPi(); + sigman = ntrack.tofNSigmaPr(); + } else if (v0SelectionMode == V0TPCTOF) { + sigmap = std::hypot(ptrack.tpcNSigmaPi(), ptrack.tofNSigmaPi()); + sigman = std::hypot(ntrack.tpcNSigmaPr(), ntrack.tofNSigmaPr()); + } + if (ptrack.tpcInnerParam() > tpcCut) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(sigmap) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > tpcCut) { + if (!ntrack.hasTOF()) + return false; + if (std::abs(sigman) > nsigmaTOFmax) + return false; + } + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllAntiLambda); + + if (std::abs(v0.yLambda()) > v0rapidityCut) + return false; + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityAntiLambda); + + float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda; + + if (properLifetime > v0ProperLifetimeCutLambda) + return false; + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeAntiLambda); + + if (std::abs(v0.mAntiLambda() - MassLambda) > invMassCutLambda) + return false; + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::MassCutAntiLambda); + + 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; + + double sigmap = 0.0; + double sigman = 0.0; + + if (v0SelectionMode == V0TPC) { + sigmap = ptrack.tpcNSigmaEl(); + sigman = ntrack.tpcNSigmaEl(); + } else if (v0SelectionMode == V0TOF) { + sigmap = ptrack.tofNSigmaEl(); + sigman = ntrack.tofNSigmaEl(); + } else if (v0SelectionMode == V0TPCTOF) { + sigmap = std::hypot(ptrack.tpcNSigmaEl(), ptrack.tofNSigmaEl()); + sigman = std::hypot(ntrack.tpcNSigmaEl(), ntrack.tofNSigmaEl()); + } + + if (ptrack.tpcInnerParam() > tpcCut) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(sigmap) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > tpcCut) { + if (!ntrack.hasTOF()) + return false; + if (std::abs(sigman) > nsigmaTOFmax) + return false; + } + const float gammaMass = 2 * MassElectron; // GeV/c^2 + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllGamma); + + const float yGamma = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, MassGamma); + + if (std::abs(yGamma) > v0rapidityCut) + return false; + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityGamma); + + if (std::abs(v0.mGamma() - gammaMass) > invMassCutGamma) + return false; + + if (fillHist) + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::MassCutGamma); + + return true; + } + // Magnetic field + int getMagneticField(uint64_t timestamp) + { + 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(); + } + // Phi cut + template + bool passedPhiCutPri(const T& trk, float magField, const TF1& fphiCutLow, const TF1& fphiCutHigh) + { + float p = trk.p(); + float pt = trk.pt(); + float phi = trk.phi(); + int charge = trk.sign(); + auto nTPCCl = trk.tpcNClsFound(); + auto nTPCPIDCl = trk.tpcNClsPID(); + + if (pt < pTcut) + return true; + + if (magField < 0) // for negatve polarity field + phi = o2::constants::math::TwoPI - phi; + if (charge < 0) // for negatve charge + phi = o2::constants::math::TwoPI - phi; + + // to center gap in the middle + phi += o2::constants::math::PI / 18.0f; + phi = std::fmod(phi, o2::constants::math::PI / 9.0f); + + registryDeDx.fill(HIST("hpt_vs_phi_NclFound_TPC_Before"), pt, phi, nTPCCl); + registryDeDx.fill(HIST("hp_vs_phi_NclFound_TPC_Before"), p, phi, nTPCCl); + registryDeDx.fill(HIST("hpt_vs_phi_NclPID_TPC_Before"), pt, phi, nTPCPIDCl); + registryDeDx.fill(HIST("hp_vs_phi_NclPID_TPC_Before"), p, phi, nTPCPIDCl); + + // cut phi + if (phi < fphiCutHigh.Eval(pt) && phi > fphiCutLow.Eval(pt)) + return false; // reject track + + registryDeDx.fill(HIST("hpt_vs_phi_NclFound_TPC_After"), pt, phi, nTPCCl); + registryDeDx.fill(HIST("hp_vs_phi_NclFound_TPC_After"), p, phi, nTPCCl); + registryDeDx.fill(HIST("hpt_vs_phi_NclPID_TPC_After"), pt, phi, nTPCPIDCl); + registryDeDx.fill(HIST("hp_vs_phi_NclPID_TPC_After"), p, phi, nTPCPIDCl); + + return true; + } + + // NclCutTPC + template + bool passedNClTPCFoundCutPri(const T& trk) + { + float eta = trk.eta(); + float sigP = trk.sign() * getMomentum(trk); + auto nTPCCl = trk.tpcNClsFound(); + + if (eta >= EtaCut[0] && eta < EtaCut[1]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[0]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[0]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[1] && eta < EtaCut[2]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[1]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[1]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[2] && eta < EtaCut[3]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[2]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[2]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[3] && eta < EtaCut[4]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[3]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[3]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[4] && eta < EtaCut[5]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[4]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[4]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[5] && eta < EtaCut[6]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[5]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[5]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[6] && eta < EtaCut[7]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[6]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[6]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[7] && eta < EtaCut[8]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[7]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[7]), nTPCCl, trk.tpcSignal(), sigP); + } + } + + if (nTPCCl < minTPCnClsFound) + return false; + + if (eta >= EtaCut[0] && eta < EtaCut[1]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[0]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[0]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[1] && eta < EtaCut[2]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[1]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[1]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[2] && eta < EtaCut[3]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[2]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[2]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[3] && eta < EtaCut[4]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[3]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[3]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[4] && eta < EtaCut[5]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[4]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[4]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[5] && eta < EtaCut[6]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[5]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[5]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[6] && eta < EtaCut[7]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[6]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[6]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[7] && eta < EtaCut[8]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[7]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[7]), nTPCCl, trk.tpcSignal(), sigP); + } + } + + return true; + } + + // NclPIDCutTPC + template + bool passedNClTPCPIDCutPri(const T& trk) + { + float eta = trk.eta(); + float sigP = trk.sign() * getMomentum(trk); + auto nTPCCl = trk.tpcNClsPID(); + + if (eta >= EtaCut[0] && eta < EtaCut[1]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegBefore[0]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosBefore[0]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[1] && eta < EtaCut[2]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegBefore[1]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosBefore[1]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[2] && eta < EtaCut[3]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegBefore[2]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosBefore[2]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[3] && eta < EtaCut[4]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegBefore[3]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosBefore[3]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[4] && eta < EtaCut[5]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegBefore[4]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosBefore[4]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[5] && eta < EtaCut[6]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegBefore[5]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosBefore[5]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[6] && eta < EtaCut[7]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegBefore[6]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosBefore[6]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[7] && eta < EtaCut[8]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegBefore[7]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosBefore[7]), nTPCCl, trk.tpcSignal(), sigP); + } + } + + if (nTPCCl < minTPCnClsPID) + return false; + + if (eta >= EtaCut[0] && eta < EtaCut[1]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegAfter[0]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosAfter[0]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[1] && eta < EtaCut[2]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegAfter[1]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosAfter[1]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[2] && eta < EtaCut[3]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegAfter[2]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosAfter[2]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[3] && eta < EtaCut[4]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegAfter[3]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosAfter[3]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[4] && eta < EtaCut[5]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegAfter[4]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosAfter[4]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[5] && eta < EtaCut[6]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegAfter[5]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosAfter[5]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[6] && eta < EtaCut[7]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegAfter[6]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosAfter[6]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta >= EtaCut[7] && eta < EtaCut[8]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumNegAfter[7]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclPIDTPCDedxMomentumPosAfter[7]), nTPCCl, trk.tpcSignal(), sigP); + } + } + + return true; + } + + // Phi cut Secondaries + template + bool passedPhiCutSecondaries(const T& trk, float magField, const TF1& fphiCutLow, const TF1& fphiCutHigh) + { + float pt = trk.pt(); + float phi = trk.phi(); + int charge = trk.sign(); + + if (pt < pTcut) + return true; + + if (magField < 0) // for negatve polarity field + phi = o2::constants::math::TwoPI - phi; + if (charge < 0) // for negatve charge + phi = o2::constants::math::TwoPI - phi; + + // to center gap in the middle + phi += o2::constants::math::PI / 18.0f; + phi = std::fmod(phi, o2::constants::math::PI / 9.0f); + + // cut phi + if (phi < fphiCutHigh.Eval(pt) && phi > fphiCutLow.Eval(pt)) + return false; // reject track + + return true; + } + + // NclCutTPC + template + bool passedNClTPCFoundCutSecondaries(const T& trk) + { + auto nTPCCl = trk.tpcNClsFound(); + + if (nTPCCl < minTPCnClsFound) + return false; + + return true; + } + + // NclCutPIDTPC secondary + template + bool passedNClTPCPIDCutSecondaries(const T& trk) + { + auto nTPCCl = trk.tpcNClsPID(); + + if (nTPCCl < minTPCnClsPID) + return false; + + return true; + } + + // Process Data + void process(SelectedCollisions::iterator const& collision, BCsRun3 const& /**/, + aod::V0Datas const& fullV0s, PIDTracks const& tracks) + { + registryDeDx.fill(HIST("evsel"), EvCutLabel::AllEv); + // Event Selection + if (!collision.sel8()) + return; + + registryDeDx.fill(HIST("evsel"), EvCutLabel::SelEigth); + + if (std::abs(collision.posZ()) > maxZDistanceToIP) + return; + + registryDeDx.fill(HIST("evsel"), EvCutLabel::ZVtxCut); + + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + + registryDeDx.fill(HIST("evsel"), EvCutLabel::NoSameBunchPileup); + + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + + registryDeDx.fill(HIST("evsel"), EvCutLabel::GoodZvtxFT0vsPV); + + // Event Counter + registryDeDx.fill(HIST("histRecVtxZData"), collision.posZ()); + + // For magnetic field + const auto& foundBC = collision.foundBC_as(); + const uint64_t timeStamp{foundBC.timestamp()}; + const int magField{getMagneticField(timeStamp)}; + + float centrality = collision.centFT0C(); + if (centrality < CentClasses[0] || centrality > CentClasses[10]) + return; + + for (const auto& trk : tracks) { + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::AllPri); + // track Selection + if (!mySelectionPrim.IsSelected(trk)) + continue; + + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::SelectionPrim); + + // phi and Ncl cut + if (phiVarCut) { + if (!passedPhiCutPri(trk, magField, *fphiCutLow, *fphiCutHigh)) + continue; + } + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::PhiVarCutPri); + + // NCl cut TPC + registryDeDx.fill(HIST("heta_vs_NclFound_TPC_Before_Primary"), trk.eta(), trk.tpcNClsFound()); + if (nClTPCFoundCut) { + if (!passedNClTPCFoundCutPri(trk)) + continue; + } + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::NClTPCFoundCutPri); + registryDeDx.fill(HIST("heta_vs_NclFound_TPC_After_Primary"), trk.eta(), trk.tpcNClsFound()); + + // NCl cut PID TPC + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_Primary"), trk.eta(), trk.tpcNClsPID()); + if (nClTPCPIDCut) { + if (!passedNClTPCPIDCutPri(trk)) + continue; + } + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::NClTPCPIDCutPri); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_Primary"), trk.eta(), trk.tpcNClsPID()); + + float signedP = trk.sign() * getMomentum(trk); + + // MIP calibration for pions + if (getMomentum(trk) >= pionMin && getMomentum(trk) <= pionMax) { + 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 < kEtaIntervals; ++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) < elTofCut) { // 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 < kEtaIntervals; ++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() > pionTofCut && trk.beta() < pionTofCut + 0.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 < kEtaIntervals; ++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) { + int centIndex = -1; + for (int j = 0; j < kCentralityClasses; ++j) { + if (centrality >= CentClasses[j] && centrality < CentClasses[j + 1]) { + centIndex = j; + break; + } + } + if (centIndex == -1) + continue; + + for (int i = 0; i < kEtaIntervals; ++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()); + registryDeDx.fill(HIST("heta_vs_pt_vs_p_all_Pos"), trk.eta(), trk.pt(), trk.p()); + hDedxVsMomentumVsCentPos[centIndex]->Fill(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()); + registryDeDx.fill(HIST("heta_vs_pt_vs_p_all_Neg"), trk.eta(), trk.pt(), trk.p()); + hDedxVsMomentumVsCentNeg[centIndex]->Fill(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 + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllSec); + + // Select V0 type + if (v0.v0Type() != v0TypeSelection) + continue; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0Type); + + if (!passedV0Selection(v0, collision)) { + 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; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::TPCRefit); + // phi and Ncl cut + if (phiVarCut) { + if (!passedPhiCutSecondaries(posTrack, magField, *fphiCutLow, *fphiCutHigh)) + continue; + + if (!passedPhiCutSecondaries(negTrack, magField, *fphiCutLow, *fphiCutHigh)) + continue; + } + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel ::PhiVarCutSec); + + fillHist = false; + // K0s Selection + if (passedK0Selection(v0, negTrack, posTrack, collision)) { + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_PionsK0s"), posTrack.eta(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_PionsK0s"), negTrack.eta(), negTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_Before_PionsK0s"), posTrack.p(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_Before_PionsK0s"), negTrack.p(), negTrack.tpcNClsPID()); + } + // Lambda Selection + if (passedLambdaSelection(v0, negTrack, posTrack, collision)) { + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_ProtonsLambda"), posTrack.eta(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_PionsLambda"), negTrack.eta(), negTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_Before_ProtonsLambda"), posTrack.p(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_Before_PionsLambda"), negTrack.p(), negTrack.tpcNClsPID()); + } + // AntiLambda Selection + if (passedAntiLambdaSelection(v0, negTrack, posTrack, collision)) { + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_PionsLambda"), posTrack.eta(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_ProtonsLambda"), negTrack.eta(), negTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_Before_PionsLambda"), posTrack.p(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_Before_ProtonsLambda"), negTrack.p(), negTrack.tpcNClsPID()); + } + // Gamma Selection + if (passedGammaSelection(v0, negTrack, posTrack, collision)) { + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_ElectronsGamma"), posTrack.eta(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_Before_ElectronsGamma"), negTrack.eta(), negTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_Before_ElectronsGamma"), posTrack.p(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_Before_ElectronsGamma"), negTrack.p(), negTrack.tpcNClsPID()); + } + + if (nClTPCFoundCut) { + if (!passedNClTPCFoundCutSecondaries(posTrack)) + continue; + + if (!passedNClTPCFoundCutSecondaries(negTrack)) + continue; + } + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel ::NClTPCFoundCutSec); + + if (nClTPCPIDCut) { + if (!passedNClTPCPIDCutSecondaries(posTrack)) + continue; + + if (!passedNClTPCPIDCutSecondaries(negTrack)) + continue; + } + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel ::NClTPCPIDCutSec); + + float signedPpos = posTrack.sign() * getMomentum(posTrack); + float signedPneg = negTrack.sign() * getMomentum(negTrack); + + fillHist = true; + + // K0s Selection + if (passedK0Selection(v0, negTrack, posTrack, collision)) { + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_PionsK0s"), posTrack.eta(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_PionsK0s"), negTrack.eta(), negTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_After_PionsK0s"), posTrack.p(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_After_PionsK0s"), negTrack.p(), negTrack.tpcNClsPID()); + for (int i = 0; i < kEtaIntervals; ++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)) { + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_ProtonsLambda"), posTrack.eta(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_PionsLambda"), negTrack.eta(), negTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_After_ProtonsLambda"), posTrack.p(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_After_PionsLambda"), negTrack.p(), negTrack.tpcNClsPID()); + for (int i = 0; i < kEtaIntervals; ++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)) { + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_PionsLambda"), posTrack.eta(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_ProtonsLambda"), negTrack.eta(), negTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_After_PionsLambda"), posTrack.p(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_After_ProtonsLambda"), negTrack.p(), negTrack.tpcNClsPID()); + for (int i = 0; i < kEtaIntervals; ++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)) { + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_ElectronsGamma"), posTrack.eta(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("heta_vs_NclPID_TPC_After_ElectronsGamma"), negTrack.eta(), negTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_After_ElectronsGamma"), posTrack.p(), posTrack.tpcNClsPID()); + registryDeDx.fill(HIST("hp_vs_NclPID_TPC_After_ElectronsGamma"), negTrack.p(), negTrack.tpcNClsPID()); + for (int i = 0; i < kEtaIntervals; ++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/PWGLF/Tasks/Nuspex/deutRtTask.cxx b/PWGLF/Tasks/Nuspex/deutRtTask.cxx index f0092793232..98abc19c5ee 100644 --- a/PWGLF/Tasks/Nuspex/deutRtTask.cxx +++ b/PWGLF/Tasks/Nuspex/deutRtTask.cxx @@ -9,21 +9,24 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "TVector2.h" -#include "Framework/AnalysisTask.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" + #include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/Core/TrackSelection.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "TVector2.h" using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx b/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx index f9890fbe17d..1f6c7f3707c 100644 --- a/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx +++ b/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx @@ -13,32 +13,39 @@ /// \author Francesca Ercolessi /// \since 21 April 2024 -#include -#include -#include -#include -#include -#include -#include -#include -#include "TGrid.h" +#include "PWGCF/Femto3D/Core/femto3dPairTask.h" +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Multiplicity.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" -#include "Framework/DataTypes.h" -#include "Common/DataModel/Multiplicity.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" #include "Framework/Expressions.h" - +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/StaticFor.h" -#include "PWGCF/Femto3D/DataModel/singletrackselector.h" -#include "PWGCF/Femto3D/Core/femto3dPairTask.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" + +#include "TGrid.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::soa; @@ -52,10 +59,13 @@ struct hadronnucleicorrelation { static constexpr int pdgProton = 2212; static constexpr int pdgDeuteron = 1000010020; + Configurable mode{"mode", 0, "0: antid-antip, 1: d-p, 2: antid-p, 3: d-antip, 4: antip-p, 5: antip-antip, 6: p-p"}; + Configurable doQA{"doQA", true, "save QA histograms"}; + Configurable doMCQA{"doMCQA", false, "save MC QA histograms"}; Configurable isMC{"isMC", false, "is MC"}; - Configurable mcCorrelation{"mcCorrelation", false, "true: build the correlation function only for SE"}; - Configurable disable_pantip{"disable_pantip", false, "disable_pantip"}; + Configurable isMCGen{"isMCGen", false, "is isMCGen"}; + Configurable isPrim{"isPrim", true, "is isPrim"}; Configurable docorrection{"docorrection", false, "do efficiency correction"}; Configurable fCorrectionPath{"fCorrectionPath", "", "Correction path to file"}; @@ -66,6 +76,8 @@ struct hadronnucleicorrelation { 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"}; @@ -74,84 +86,96 @@ 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 debug_ptthrp{"debug_ptthrp", 2.0f, "threshold pT proton for phi/eta debug"}; - Configurable debug_ptthrd{"debug_ptthrd", 2.0f, "threshold pT deuteron for phi/eta debug"}; + 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 threta{"threta", 0.1, "threshold for debug DeltaEta"}; - Configurable thrphi{"thrphi", 0.5, "threshold for debug DeltaPhi"}; + Configurable maxmixcollsGen{"maxmixcollsGen", 100, "maxmixcollsGen"}; + Configurable radiusTPC{"radiusTPC", 1.2, "TPC radius to calculate phi_star for"}; + 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"}; // 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"}; + Configurable maxmultmix{"maxmultmix", 20, "maximum multiplicity to mix"}; // pT/A bins - Configurable> pTBins{"pTBins", {0.4f, 0.6f, 0.8f}, "p_{T} bins"}; - Configurable> etaBins{"etaBins", {-0.8f, 0.f, 0.8f}, "#eta bins"}; - Configurable> phiBins{"phiBins", {0.f, TMath::Pi(), 2 * TMath::Pi()}, "#phi bins"}; + Configurable> pTBins{"pTBins", {0.6f, 1.0f, 1.2f, 2.f}, "p_{T} bins"}; - ConfigurableAxis AxisNSigma{"AxisNSigma", {50, -10.f, 10.f}, "n#sigma"}; + ConfigurableAxis AxisNSigma{"AxisNSigma", {35, -7.f, 7.f}, "n#sigma"}; + ConfigurableAxis DeltaPhiAxis = {"DeltaPhiAxis", {46, -1 * o2::constants::math::PIHalf, 3 * o2::constants::math::PIHalf}, "#Delta#phi (rad)"}; using FilteredCollisions = soa::Filtered; - using FilteredTracks = soa::Filtered; - using FilteredTracksMC = 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 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> selectedtracksMC_p; - std::map> selectedtracksMC_antid; - std::map> selectedtracksMC_antip; - std::map> selectedtracksPIDMC_p; - std::map> selectedtracksPIDMC_antid; - std::map> selectedtracksPIDMC_antip; + std::map> selectedparticlesMC_d; + std::map> selectedparticlesMC_p; + std::map> selectedparticlesMC_antid; + std::map> selectedparticlesMC_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, std::vector> mixbinsPID_pantip; - - std::vector> hEtaPhi_PrAntiPr_SE; - std::vector> hEtaPhi_PrAntiPr_ME; - std::vector> hEtaPhi_AntiDeAntiPr_SE; - std::vector> hEtaPhi_AntiDeAntiPr_ME; - std::vector> hCorrEtaPhi_PrAntiPr_SE; - std::vector> hCorrEtaPhi_PrAntiPr_ME; - std::vector> hCorrEtaPhi_AntiDeAntiPr_SE; - std::vector> hCorrEtaPhi_AntiDeAntiPr_ME; - - std::vector> hEtaPhiRec_AntiDeAntiPr_SE; + std::map, std::vector> mixbins_antid; + std::map, std::vector> mixbins_d; + std::map, std::vector> mixbins_antip; + std::map, std::vector> mixbins_p; + std::map, std::vector> mixbinsMC_antid; + std::map, std::vector> mixbinsMC_d; + std::map, std::vector> mixbinsMC_antip; + std::map, std::vector> mixbinsMC_p; + + std::unique_ptr> Pair = std::make_unique>(); + std::unique_ptr> PairMC = std::make_unique>(); + + // Data histograms + std::vector> hEtaPhi_SE; + std::vector> hEtaPhi_ME; + std::vector> hCorrEtaPhi_SE; + std::vector> hCorrEtaPhi_ME; + + // MC histograms std::vector> hEtaPhiGen_AntiDeAntiPr_SE; - std::vector> hEtaPhiRec_AntiDeAntiPr_ME; std::vector> hEtaPhiGen_AntiDeAntiPr_ME; - std::vector> hEtaPhiRec_PrAntiPr_SE; - std::vector> hEtaPhiGen_PrAntiPr_SE; - std::vector> hEtaPhiRec_PrAntiPr_ME; - std::vector> hEtaPhiGen_PrAntiPr_ME; - std::vector> hPIDEtaPhiRec_AntiDeAntiPr_SE; - std::vector> hPIDEtaPhiGen_AntiDeAntiPr_SE; - std::vector> hPIDEtaPhiRec_AntiDeAntiPr_ME; - std::vector> hPIDEtaPhiGen_AntiDeAntiPr_ME; - std::vector> hPIDEtaPhiRec_PrAntiPr_SE; - std::vector> hPIDEtaPhiGen_PrAntiPr_SE; - std::vector> hPIDEtaPhiRec_PrAntiPr_ME; - std::vector> hPIDEtaPhiGen_PrAntiPr_ME; - - int nBinspT, nBinseta, nBinsphi; + std::vector> hEtaPhiGen_AntiPrAntiPr_SE; + std::vector> hEtaPhiGen_AntiPrAntiPr_ME; + std::vector> hEtaPhiGen_PrPr_SE; + std::vector> hEtaPhiGen_PrPr_ME; + std::vector> hEtaPhiGen_AntiPrPr_SE; + std::vector> hEtaPhiGen_AntiPrPr_ME; + std::vector> hEtaPhiGen_AntiDePr_SE; + std::vector> hEtaPhiGen_AntiDePr_ME; + std::vector> hEtaPhiGen_DeAntiPr_SE; + std::vector> hEtaPhiGen_DeAntiPr_ME; + std::vector> hEtaPhiGen_DePr_SE; + std::vector> hEtaPhiGen_DePr_ME; + + int nBinspT; TH2F* hEffpTEta_proton; TH2F* hEffpTEta_antiproton; TH2F* hEffpTEta_deuteron; @@ -160,6 +184,8 @@ struct hadronnucleicorrelation { Service ccdb; o2::ccdb::CcdbApi ccdbApi; + Service pdgDB; + void init(o2::framework::InitContext&) { ccdb->setURL(url.value); @@ -178,185 +204,187 @@ struct hadronnucleicorrelation { } AxisSpec ptBinnedAxis = {pTBins, "#it{p}_{T} of #bar{p} (GeV/c)"}; - AxisSpec etaBinnedAxis = {etaBins, "#eta"}; - AxisSpec phiBinnedAxis = {phiBins, "#phi"}; - AxisSpec etaAxis = {100, -1.5, 1.5, "#Delta#eta"}; - AxisSpec phiAxis = {60, -TMath::Pi() / 2, 1.5 * TMath::Pi(), "#Delta#phi"}; + AxisSpec etaAxis = {100, -1., 1., "#eta"}; + AxisSpec phiAxis = {157, 0., o2::constants::math::TwoPI, "#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 = {300, -1.5, 1.5, "#Delta#eta"}; - registry.add("hNEvents", "hNEvents", {HistType::kTH1I, {{3, 0.f, 3.f}}}); + registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{7, 0.f, 7.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.get(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"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(6, "events with #bar{p}"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(7, "events with p"); nBinspT = pTBins.value.size() - 1; - nBinseta = etaBins.value.size() - 1; - nBinsphi = phiBins.value.size() - 1; - if (mcCorrelation) { + if (isMCGen) { 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("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("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("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("hEtaPhiRec_PrAntiPr_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("hEtaPhiGen_PrAntiPr_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("hEtaPhiRec_PrAntiPr_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("hEtaPhiGen_PrAntiPr_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("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("hPIDEtaPhiRec_PrAntiPr_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_PrAntiPr_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_PrAntiPr_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_PrAntiPr_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("hEtaPhiGen_PrPr_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_PrPr_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_AntiPrPr_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_AntiPrPr_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_DePr_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_DePr_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_AntiDePr_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_AntiDePr_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_DeAntiPr_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_DeAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), + Form("Gen #Delta#eta#Delta#phi (%.1f(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"); + TString name = "AntiDeAntiPr"; + switch (mode) { + case 1: + name = "DePr"; + break; + case 2: + name = "AntiDePr"; + break; + case 3: + name = "DeAntiPr"; + break; + case 4: + name = "AntiPrPr"; + break; + case 5: + name = "AntiPrAntiPr"; + break; + case 6: + name = "PrPr"; + break; + } + if (!isMC) { for (int i = 0; i < nBinspT; i++) { - if (!disable_pantip) { - auto htempSE_PrAntiPr = registry.add(Form("hEtaPhi_PrAntiPr_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_PrAntiPr_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("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_PrAntiPr_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_PrAntiPr_ME_pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(Form("hEtaPhi_%s_SE_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("Raw #Delta#eta#Delta#phi (%.1f(Form("hEtaPhi_%s_ME_pt%02.0f%02.0f", name.Data(), 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(Form("hCorrEtaPhi_%s_SE_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(Form("hCorrEtaPhi_%s_ME_pt%02.0f%02.0f", name.Data(), 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("hGen_EtaPhiPt_Proton", "Gen (anti)protons in gen collisions", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); + registry.add("hGen_EtaPhiPt_Deuteron", "Gen (anti)deuteron in gen collisions", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); + + 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}}}); } } @@ -384,147 +476,278 @@ struct hadronnucleicorrelation { o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcChi2NCl) <= max_chi2_TPC && 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_v1)) <= max_dcaxy && // For now no filtering on the DCAxy or DCAz (casting not supported) - // nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaXY_v1)) <= max_dcaz && // For now no filtering on the DCAxy or DCAz (casting not supported) + nabs(o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedDcaXY)) <= max_dcaxy && + 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, bool isMCPID) - { // last value: 0 -- SE; 1 -- ME - for (auto it1 : tracks1) { - for (auto it2 : tracks2) { + template + bool IsProton(Type const& track, int sign) + { + bool isProton = false; - // Variables - float deltaEta = it2->eta() - it1->eta(); - float deltaPhi = it2->phi() - it1->phi(); - deltaPhi = getDeltaPhi(deltaPhi); + 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; - 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); + 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; + } - float pcorr = 1, antipcorr = 1, antidcorr = 1; + 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; + } - for (int k = 0; k < nBinspT; k++) { + template + void mixTracks(Type const& tracks1, Type const& tracks2, bool isIdentical) + { // last value: 0 -- SE; 1 -- ME + for (auto const& it1 : tracks1) { + for (auto const& it2 : tracks2) { - if (!isDe && !disable_pantip) { - if (it1->pt() > pTBins.value.at(k) && it1->pt() <= pTBins.value.at(k + 1)) { + Pair->SetPair(it1, it2); + Pair->SetIdentical(isIdentical); - if (doQA) { - QA.fill(HIST("QA/Pt_Pr"), it1->pt()); - QA.fill(HIST("QA/Pt_AntiPr"), it2->pt()); - } + // if Identical (pp and antip-antip) + if (isIdentical && Pair->IsClosePair(deta, dphi, radiusTPC)) { + QA.fill(HIST("QA/hdetadphistar"), Pair->GetPhiStarDiff(radiusTPC), Pair->GetEtaDiff()); + continue; + } - if (docorrection) { - pcorr = hEffpTEta_proton->Interpolate(it1->pt(), it1->eta()); - antipcorr = hEffpTEta_antiproton->Interpolate(it2->pt(), it2->eta()); - } + // Calculate Delta-eta Delta-phi (reco) + float deltaEta = it2->eta() - it1->eta(); + float deltaPhi = it2->phi() - it1->phi(); + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -1 * o2::constants::math::PIHalf); + + for (int k = 0; k < nBinspT; k++) { - if (ME) { - if constexpr (!doMC) { - hEtaPhi_PrAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); - hCorrEtaPhi_PrAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt(), 1. / (pcorr * antipcorr)); - } - if constexpr (doMC) { - if (isMCPID) { - hPIDEtaPhiRec_PrAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); - hPIDEtaPhiGen_PrAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); - } else { - hEtaPhiRec_PrAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); - hEtaPhiGen_PrAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); - } - } - } else { - if constexpr (!doMC) { - hEtaPhi_PrAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); - hCorrEtaPhi_PrAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt(), 1. / (pcorr * antipcorr)); - - if (doQA && abs(deltaEta) < threta && abs(deltaPhi) < thrphi) { - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr_Debug"), it1->pt(), it1->tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr_Debug"), -1.f * it2->pt(), it2->tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr_Debug"), it1->pt(), it1->tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr_Debug"), -1.f * it2->pt(), it2->tofNSigmaPr()); - } - } - if constexpr (doMC) { - if (isMCPID) { - hPIDEtaPhiRec_PrAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); - hPIDEtaPhiGen_PrAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); - } else { - hEtaPhiRec_PrAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); - hEtaPhiGen_PrAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); - } - } + if (it1->pt() >= pTBins.value.at(k) && it1->pt() < pTBins.value.at(k + 1)) { + + float corr1 = 1, corr2 = 1; + + if (docorrection) { // Apply corrections + switch (mode) { + case 0: + corr1 = hEffpTEta_antideuteron->Interpolate(it1->pt(), it1->eta()); + corr2 = hEffpTEta_antiproton->Interpolate(it2->pt(), it2->eta()); + break; + case 1: + corr1 = hEffpTEta_deuteron->Interpolate(it1->pt(), it1->eta()); + corr2 = hEffpTEta_proton->Interpolate(it2->pt(), it2->eta()); + break; + case 2: + corr1 = hEffpTEta_antideuteron->Interpolate(it1->pt(), it1->eta()); + corr2 = hEffpTEta_proton->Interpolate(it2->pt(), it2->eta()); + break; + case 3: + corr1 = hEffpTEta_deuteron->Interpolate(it1->pt(), it1->eta()); + corr2 = hEffpTEta_antiproton->Interpolate(it2->pt(), it2->eta()); + break; + case 4: + corr1 = hEffpTEta_antiproton->Interpolate(it1->pt(), it1->eta()); + corr2 = hEffpTEta_proton->Interpolate(it2->pt(), it2->eta()); + break; + case 5: + corr1 = hEffpTEta_antiproton->Interpolate(it1->pt(), it1->eta()); + corr2 = hEffpTEta_antiproton->Interpolate(it2->pt(), it2->eta()); + break; + case 6: + corr1 = hEffpTEta_proton->Interpolate(it1->pt(), it1->eta()); + corr2 = hEffpTEta_proton->Interpolate(it2->pt(), it2->eta()); + break; } } - } else { - if (it1->pt() > pTBins.value.at(k) && it1->pt() <= pTBins.value.at(k + 1)) { - if (doQA) { - QA.fill(HIST("QA/Pt_AntiDe"), it1->pt()); - QA.fill(HIST("QA/Pt_AntiPr"), it2->pt()); - } + if (ME) { + hEtaPhi_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); + hCorrEtaPhi_ME[k]->Fill(deltaEta, deltaPhi, it2->pt(), 1. / (corr1 * corr2)); + } else { + hEtaPhi_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); + hCorrEtaPhi_SE[k]->Fill(deltaEta, deltaPhi, it2->pt(), 1. / (corr1 * corr2)); + } // SE + } // pT condition + } // nBinspT loop - if (docorrection) { - antipcorr = hEffpTEta_antiproton->Interpolate(it2->pt(), it2->eta()); - antidcorr = hEffpTEta_antideuteron->Interpolate(it1->pt(), it1->eta()); - } + Pair->ResetPair(); + + } // tracks 2 + } // tracks 1 + } - if (ME) { - if constexpr (!doMC) { - hEtaPhi_AntiDeAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt()); - hCorrEtaPhi_AntiDeAntiPr_ME[k]->Fill(deltaEta, deltaPhi, it2->pt(), 1. / (antipcorr * antidcorr)); - } - if constexpr (doMC) { - 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) { - hEtaPhi_AntiDeAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt()); - hCorrEtaPhi_AntiDeAntiPr_SE[k]->Fill(deltaEta, deltaPhi, it2->pt(), 1. / (antipcorr * antidcorr)); - - if (doQA && abs(deltaEta) < threta && abs(deltaPhi) < thrphi) { - QA.fill(HIST("QA/hnSigmaTPCVsPt_De_Debug"), -1.f * it1->pt(), it1->tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_APrDe_Debug"), -1.f * it2->pt(), it2->tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_De_Debug"), -1.f * it1->pt(), it1->tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_APrDe_Debug"), -1.f * it2->pt(), it2->tofNSigmaPr()); - } - } - if constexpr (doMC) { - 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 + template + void mixMCParticles(Type const& particles1, Type const& particles2, int mode) + { + for (auto const& it1 : particles1) { + for (auto const& it2 : particles2) { + // Calculate Delta-eta Delta-phi (gen) + float deltaEtaGen = it2->eta() - it1->eta(); + float deltaPhiGen = RecoDecay::constrainAngle(it2->phi() - it1->phi(), -1 * o2::constants::math::PIHalf); + + // 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) { + if (mode == 0) + hEtaPhiGen_AntiPrPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else if (mode == 1) + hEtaPhiGen_AntiDeAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else if (mode == 2) + hEtaPhiGen_AntiDePr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else if (mode == 3) + hEtaPhiGen_DeAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else if (mode == 4) + hEtaPhiGen_DePr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } else { + if (mode == 0) + hEtaPhiGen_AntiPrPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else if (mode == 1) + hEtaPhiGen_AntiDeAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else if (mode == 2) + hEtaPhiGen_AntiDePr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else if (mode == 3) + hEtaPhiGen_DeAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else if (mode == 4) + hEtaPhiGen_DePr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); } } - } // nBinspT loop + } } } } - float getDeltaPhi(float deltaPhi) + template + void mixMCParticlesIdentical(Type const& particles1, Type const& particles2, bool ismatter) { - if (deltaPhi < -TMath::Pi() / 2) { - return deltaPhi += 2 * TMath::Pi(); - } else if (deltaPhi >= 3 * TMath::Pi() / 2) { - return deltaPhi -= 2 * TMath::Pi(); + for (auto const& it1 : particles1) { + for (auto const& it2 : particles2) { + // Calculate Delta-eta Delta-phi (gen) + float deltaEtaGen = it2->eta() - it1->eta(); + float deltaPhiGen = RecoDecay::constrainAngle(it2->phi() - it1->phi(), -1 * o2::constants::math::PIHalf); + + if (!ME && std::abs(deltaPhiGen) < 0.0001 && std::abs(deltaEtaGen) < 0.0001) { + 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) { + if (ismatter) + hEtaPhiGen_PrPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else + hEtaPhiGen_AntiPrAntiPr_ME[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } else { + if (ismatter) + hEtaPhiGen_PrPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + else + hEtaPhiGen_AntiPrAntiPr_SE[k]->Fill(deltaEtaGen, deltaPhiGen, it2->pt()); + } + } + } + } } - return deltaPhi; } void GetCorrection(o2::framework::Service const& ccdbObj, TString filepath, TString histname) @@ -563,110 +786,91 @@ struct hadronnucleicorrelation { 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 (abs(track.dcaXY()) > max_dcaxy || abs(track.dcaZ()) > max_dcaz) { // For now no filtering on the DCAxy or DCAz (casting not supported) + if (track.itsNCls() < min_itsNCls) continue; - } + + if (IsProton(track, +1)) + registry.fill(HIST("hPrDCAxy"), track.dcaXY(), track.pt()); + if (IsProton(track, -1)) + registry.fill(HIST("hAntiPrDCAxy"), track.dcaXY(), track.pt()); + if (IsDeuteron(track, +1)) + registry.fill(HIST("hDeDCAxy"), track.dcaXY(), track.pt()); + if (IsDeuteron(track, -1)) + registry.fill(HIST("hAntiDeDCAxy"), track.dcaXY(), track.pt()); + + if (!applyDCAcut(track)) + continue; + if (doQA) { QA.fill(HIST("QA/hTPCnClusters"), track.tpcNClsFound()); + QA.fill(HIST("QA/hTPCSharedClusters"), track.tpcFractionSharedCls()); 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/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()); } + // Discard candidates outside pT of interest if (track.pt() > pTBins.value.at(nBinspT) || track.pt() < pTBins.value.at(0)) continue; - // Additional track cuts - if (track.tpcFractionSharedCls() > max_tpcSharedCls || track.itsNCls() < min_itsNCls) - continue; - - bool isPr = false; - bool isAntiPr = false; - bool isDeTPCTOF = false; - bool isAntiDeTPCTOF = false; - - if (TMath::Abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() > 0) { - if (track.pt() < pTthrpr_TOF) { - isPr = true; - } else if (TMath::Abs(track.tofNSigmaPr()) < nsigmaTOF) { - isPr = true; - } - } - if (TMath::Abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() < 0) { - if (track.pt() < pTthrpr_TOF) { - isAntiPr = true; - } else if (TMath::Abs(track.tofNSigmaPr()) < nsigmaTOF) { - isAntiPr = true; - } - } - if (TMath::Abs(track.tpcNSigmaDe()) < nsigmaTPC && TMath::Abs(track.tpcNSigmaPr()) >= nsigmaTPC) { - if (TMath::Abs(track.tofNSigmaDe()) < nsigmaTOF && TMath::Abs(track.tofNSigmaPr()) >= nsigmaTOF) { - if (track.sign() > 0) { - isDeTPCTOF = true; - } else if (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); - if (!isPr && !isAntiPr && !isDeTPCTOF && !isAntiDeTPCTOF) + if (!isPr && !isAntiPr && !isDe && !isAntiDe) continue; - if (isPr && isDeTPCTOF) { - isDeTPCTOF = 0; + if (isPr && isDe) { + isDe = 0; } - if (isAntiPr && isAntiDeTPCTOF) { - isAntiDeTPCTOF = 0; + if (isAntiPr && isAntiDe) { + isAntiDe = 0; } - // Deuterons - if (isAntiDeTPCTOF) { + // 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/hnSigmaTOFVsPhi_Pr"), track.phi(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTOFVsEta_Pr"), track.eta(), track.tofNSigmaPr()); 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()); } @@ -676,10 +880,6 @@ 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/hnSigmaTOFVsPhi_AntiPr"), track.phi(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTOFVsEta_AntiPr"), track.eta(), track.tofNSigmaPr()); 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()); } @@ -688,97 +888,214 @@ struct hadronnucleicorrelation { 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); - } + registry.fill(HIST("hMult"), collision.mult()); if (selectedtracks_antid.find(collision.globalIndex()) != selectedtracks_antid.end() && selectedtracks_antip.find(collision.globalIndex()) != selectedtracks_antip.end()) { registry.fill(HIST("hNEvents"), 1.5); } + if (selectedtracks_d.find(collision.globalIndex()) != selectedtracks_d.end() && + selectedtracks_p.find(collision.globalIndex()) != selectedtracks_p.end()) { + registry.fill(HIST("hNEvents"), 2.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_antid.find(collision.globalIndex()) != selectedtracks_antid.end()) { + registry.fill(HIST("hNEvents"), 3.5); + mixbins_antid[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + } + if (selectedtracks_d.find(collision.globalIndex()) != selectedtracks_d.end()) { + registry.fill(HIST("hNEvents"), 4.5); + mixbins_d[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); } - if (selectedtracks_antip.find(collision.globalIndex()) != selectedtracks_antip.end()) { - registry.fill(HIST("hDebug"), 2.5); + registry.fill(HIST("hNEvents"), 5.5); + mixbins_antip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + } + if (selectedtracks_p.find(collision.globalIndex()) != selectedtracks_p.end()) { + registry.fill(HIST("hNEvents"), 6.5); + mixbins_p[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); } - 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 - mixbins_antidantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + Pair->SetMagField1(collision.magField()); + Pair->SetMagField2(collision.magField()); + } + + if (mode == 0 && !mixbins_antid.empty()) { + + for (auto i = mixbins_antid.begin(); i != mixbins_antid.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 (selectedtracks_antip.find(col1->index()) != selectedtracks_antip.end()) { + mixTracks<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 (col1 == col2) { + continue; + } + + if (selectedtracks_antip.find(col2->index()) != selectedtracks_antip.end()) { + mixTracks<1>(selectedtracks_antid[col1->index()], selectedtracks_antip[col2->index()], 0); // mixing ME + } + } + } } } - registry.get(HIST("hDebugdp"))->SetBinContent(6, mixbins_antidantip.size()); + if (mode == 1 && !mixbins_d.empty()) { + + for (auto i = mixbins_d.begin(); i != mixbins_d.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 - if (!disable_pantip) { - if (!mixbins_pantip.empty()) { - for (auto i = mixbins_pantip.begin(); i != mixbins_pantip.end(); i++) { // iterating over all vertex&mult bins + auto col1 = value[indx1]; - int EvPerBin = (i->second).size(); // number of collisions in each vertex&mult bin + if (selectedtracks_p.find(col1->index()) != selectedtracks_p.end()) { + mixTracks<0>(selectedtracks_d[col1->index()], selectedtracks_p[col1->index()], 0); // mixing SE + } - for (int indx1 = 0; indx1 < EvPerBin; indx1++) { // loop over all the events in each vertex&mult bin + for (int indx2 = 0; indx2 < EvPerBin; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin - auto col1 = (i->second)[indx1]; + auto col2 = value[indx2]; - if (selectedtracks_antip.find(col1->index()) != selectedtracks_antip.end()) { - mixTracks<0, 0>(selectedtracks_p[col1->index()], selectedtracks_antip[col1->index()], 0, 0); // mixing SE + if (col1 == col2) { + continue; } - int indx3 = EvPerBin; - if (indx1 < (EvPerBin - 11)) { - indx3 = indx1 + 11; + if (selectedtracks_p.find(col2->index()) != selectedtracks_p.end()) { + mixTracks<1>(selectedtracks_d[col1->index()], selectedtracks_p[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 + if (mode == 2 && !mixbins_antid.empty()) { - auto col2 = (i->second)[indx2]; + for (auto i = mixbins_antid.begin(); i != mixbins_antid.end(); i++) { // iterating over all vertex&mult bins - if (col1 == col2) { - continue; - } + std::vector value = i->second; + int EvPerBin = value.size(); // number of collisions in each vertex&mult bin - if (selectedtracks_antip.find(col2->index()) != selectedtracks_antip.end()) { - mixTracks<1, 0>(selectedtracks_p[col1->index()], selectedtracks_antip[col2->index()], 0, 0); // mixing ME - } + for (int indx1 = 0; indx1 < EvPerBin; indx1++) { // loop over all the events in each vertex&mult bin + + auto col1 = value[indx1]; + + if (selectedtracks_p.find(col1->index()) != selectedtracks_p.end()) { + mixTracks<0>(selectedtracks_antid[col1->index()], selectedtracks_p[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 (col1 == col2) { + continue; + } + + if (selectedtracks_p.find(col2->index()) != selectedtracks_p.end()) { + mixTracks<1>(selectedtracks_antid[col1->index()], selectedtracks_p[col2->index()], 0); // mixing ME } } } } } - if (!mixbins_antidantip.empty()) { + if (mode == 3 && !mixbins_d.empty()) { + + for (auto i = mixbins_d.begin(); i != mixbins_d.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 (selectedtracks_antip.find(col1->index()) != selectedtracks_antip.end()) { + mixTracks<0>(selectedtracks_d[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 (col1 == col2) { + continue; + } + + if (selectedtracks_antip.find(col2->index()) != selectedtracks_antip.end()) { + mixTracks<1>(selectedtracks_d[col1->index()], selectedtracks_antip[col2->index()], 0); // mixing ME + } + } + } + } + } - for (auto i = mixbins_antidantip.begin(); i != mixbins_antidantip.end(); i++) { // iterating over all vertex&mult bins + if (mode == 4 && !mixbins_antip.empty()) { - registry.fill(HIST("hDebugdp"), 1.5); // numero di keys (vertex&mult bins) nella mappa mixbins_antidantip + for (auto i = mixbins_antip.begin(); i != mixbins_antip.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 - registry.fill(HIST("hDebugdp"), 2.5); + auto col1 = value[indx1]; + + if (selectedtracks_p.find(col1->index()) != selectedtracks_p.end()) { + mixTracks<0>(selectedtracks_antip[col1->index()], selectedtracks_p[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 (col1 == col2) { + continue; + } + + if (selectedtracks_p.find(col2->index()) != selectedtracks_p.end()) { + mixTracks<1>(selectedtracks_antip[col1->index()], selectedtracks_p[col2->index()], 0); // mixing ME + } + } + } + } + } + + if (mode == 5 && !mixbins_antip.empty()) { + + for (auto i = mixbins_antip.begin(); i != mixbins_antip.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 (selectedtracks_antip.find(col1->index()) != selectedtracks_antip.end()) { - registry.fill(HIST("hDebugdp"), 3.5); - mixTracks<0, 0>(selectedtracks_antid[col1->index()], selectedtracks_antip[col1->index()], 1, 0); // mixing SE + mixTracks<0>(selectedtracks_antip[col1->index()], selectedtracks_antip[col1->index()], 1); // mixing SE } for (int indx2 = 0; indx2 < EvPerBin; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin @@ -790,8 +1107,38 @@ struct hadronnucleicorrelation { } if (selectedtracks_antip.find(col2->index()) != selectedtracks_antip.end()) { - registry.fill(HIST("hDebugdp"), 4.5); - mixTracks<1, 0>(selectedtracks_antid[col1->index()], selectedtracks_antip[col2->index()], 1, 0); // mixing ME + mixTracks<1>(selectedtracks_antip[col1->index()], selectedtracks_antip[col2->index()], 1); // mixing ME + } + } + } + } + } + + if (mode == 6 && !mixbins_p.empty()) { + + for (auto i = mixbins_p.begin(); i != mixbins_p.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 (selectedtracks_p.find(col1->index()) != selectedtracks_p.end()) { + mixTracks<0>(selectedtracks_p[col1->index()], selectedtracks_p[col1->index()], 1); // 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 (col1 == col2) { + continue; + } + + if (selectedtracks_p.find(col2->index()) != selectedtracks_p.end()) { + mixTracks<1>(selectedtracks_p[col1->index()], selectedtracks_p[col2->index()], 1); // mixing ME } } } @@ -811,72 +1158,134 @@ struct hadronnucleicorrelation { (i->second).clear(); selectedtracks_p.clear(); - for (auto& pair : mixbins_antidantip) { + for (auto i = selectedtracks_d.begin(); i != selectedtracks_d.end(); i++) + (i->second).clear(); + selectedtracks_d.clear(); + + for (auto& pair : mixbins_antid) { + pair.second.clear(); // Clear the vector associated with the key + } + mixbins_antid.clear(); // Then clear the map itself + + for (auto& pair : mixbins_d) { pair.second.clear(); // Clear the vector associated with the key } - mixbins_antidantip.clear(); // Then clear the map itself + mixbins_d.clear(); // Then clear the map itself - for (auto& pair : mixbins_antidantip) { + for (auto& pair : mixbins_antip) { pair.second.clear(); // Clear the vector associated with the key } - mixbins_antidantip.clear(); // Then clear the map itself + mixbins_antip.clear(); // Then clear the map itself - for (auto& pair : mixbins_pantip) { + for (auto& pair : mixbins_p) { pair.second.clear(); // Clear the vector associated with the key } - mixbins_pantip.clear(); // Then clear the map itself + mixbins_p.clear(); // Then clear the map itself } PROCESS_SWITCH(hadronnucleicorrelation, processData, "processData", true); - void processMC(FilteredCollisions const& collisions, FilteredTracksMC const& tracks) + void processMC(FilteredCollisions const&, FilteredTracksMC 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 (abs(track.dcaXY()) > max_dcaxy || abs(track.dcaZ()) > max_dcaz) { // For now no filtering on the DCAxy or DCAz (casting not supported) + if (track.tpcFractionSharedCls() > max_tpcSharedCls) + continue; + if (track.itsNCls() < min_itsNCls) continue; + + if (IsProton(track, +1) && track.pdgCode() == pdgProton) { + registry.fill(HIST("hPrDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 0) + registry.fill(HIST("hPrimPrDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 1) + registry.fill(HIST("hSecWeakPrDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 2) + registry.fill(HIST("hSecMatPrDCAxy"), track.dcaXY(), track.pt()); + } + if (IsProton(track, -1) && track.pdgCode() == -pdgProton) { + registry.fill(HIST("hAntiPrDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 0) + registry.fill(HIST("hPrimAntiPrDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 1) + registry.fill(HIST("hSecWeakAntiPrDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 2) + registry.fill(HIST("hSecMatAntiPrDCAxy"), track.dcaXY(), track.pt()); } + if (IsDeuteron(track, +1) && track.pdgCode() == pdgDeuteron) { + registry.fill(HIST("hDeDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 0) + registry.fill(HIST("hPrimDeDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 1) + registry.fill(HIST("hSecWeakDeDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 2) + registry.fill(HIST("hSecMatDeDCAxy"), track.dcaXY(), track.pt()); + } + if (IsDeuteron(track, -1) && track.pdgCode() == -pdgDeuteron) { + registry.fill(HIST("hAntiDeDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 0) + registry.fill(HIST("hPrimAntiDeDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 1) + registry.fill(HIST("hSecWeakAntiDeDCAxy"), track.dcaXY(), track.pt()); + if (track.origin() == 2) + registry.fill(HIST("hSecMatAntiDeDCAxy"), track.dcaXY(), track.pt()); + } + + 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/hTPCSharedClusters"), track.tpcFractionSharedCls()); 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/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()); } - if (track.origin() != 0) - continue; + 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 (abs(track.pdgCode()) != pdgProton && abs(track.pdgCode()) != pdgDeuteron) - continue; + if (isPr) { + registry.fill(HIST("hPrimSec_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * +1); + if (track.origin() == 1 || track.origin() == 2) { // 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 || track.origin() == 2) { + registry.fill(HIST("hSec_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * -1); + } + } - bool isPr = false; - bool isAntiPr = false; - bool isAntiDeTPCTOF = false; + 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()); - 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 (TMath::Abs(track.tpcNSigmaPr()) < nsigmaTPC) { - if (track.pt() < pTthrpr_TOF) { - isPr = true; - registry.fill(HIST("hReco_PID_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt()); - } else if (TMath::Abs(track.tofNSigmaPr()) < nsigmaTOF) { - isPr = true; - registry.fill(HIST("hReco_PID_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt()); - } + 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()); @@ -885,17 +1294,12 @@ struct hadronnucleicorrelation { 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()); - 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 (TMath::Abs(track.tpcNSigmaPr()) < nsigmaTPC) { - if (track.pt() < pTthrpr_TOF) { - isAntiPr = true; - registry.fill(HIST("hReco_PID_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * -1); - } else if (TMath::Abs(track.tofNSigmaPr()) < nsigmaTOF) { - isAntiPr = true; - registry.fill(HIST("hReco_PID_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * -1); - } + 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()); @@ -904,13 +1308,12 @@ struct hadronnucleicorrelation { 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()); - 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 (TMath::Abs(track.tpcNSigmaDe()) < nsigmaTPC && TMath::Abs(track.tpcNSigmaPr()) >= nsigmaTPC) { - if (TMath::Abs(track.tofNSigmaDe()) < nsigmaTOF && TMath::Abs(track.tofNSigmaPr()) >= nsigmaTOF) { - registry.fill(HIST("hReco_PID_EtaPhiPt_Deuteron"), track.eta(), track.phi(), track.pt()); - } + 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()); @@ -919,85 +1322,365 @@ struct hadronnucleicorrelation { 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()); - 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 (TMath::Abs(track.tpcNSigmaDe()) < nsigmaTPC && TMath::Abs(track.tpcNSigmaPr()) >= nsigmaTPC) { - if (TMath::Abs(track.tofNSigmaDe()) < nsigmaTOF && TMath::Abs(track.tofNSigmaPr()) >= nsigmaTOF) { - isAntiDeTPCTOF = true; - registry.fill(HIST("hReco_PID_EtaPhiPt_Deuteron"), track.eta(), track.phi(), track.pt() * -1); - } + 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()); } - if (!mcCorrelation) { + // 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); + } + } // track + } + PROCESS_SWITCH(hadronnucleicorrelation, processMC, "processMC", false); + + Preslice perMCCol = aod::mcparticle::mcCollisionId; + + void processGen(SimCollisions const& mcCollisions, + SimParticles const& mcParticles) + { + for (auto particle : mcParticles) { + + if (std::abs(particle.template mcCollision_as().posZ()) > cutzvertex) continue; + + if (particle.pdgCode() == pdgProton) { + registry.fill(HIST("Generated/hQAProtons"), 0.5); + } + if (particle.pdgCode() == pdgDeuteron) { + registry.fill(HIST("Generated/hQADeuterons"), 0.5); } - if (isAntiDeTPCTOF) { - selectedtracksPIDMC_antid[track.singleCollSelId()].push_back(std::make_shared(track)); + if (isPrim && !particle.isPhysicalPrimary()) { + continue; } - if (track.pdgCode() == -pdgDeuteron) { - selectedtracksMC_antid[track.singleCollSelId()].push_back(std::make_shared(track)); + if (particle.pdgCode() == pdgProton) { + registry.fill(HIST("Generated/hQAProtons"), 1.5); } - if (isPr) { - selectedtracksPIDMC_p[track.singleCollSelId()].push_back(std::make_shared(track)); + if (particle.pdgCode() == pdgDeuteron) { + registry.fill(HIST("Generated/hQADeuterons"), 1.5); } - if (track.pdgCode() == pdgProton) { - selectedtracksMC_p[track.singleCollSelId()].push_back(std::make_shared(track)); + + if (particle.pdgCode() == pdgDeuteron && std::abs(particle.y()) < 0.5) { + registry.fill(HIST("Generated/hDeuteronsVsPt"), particle.pt()); } - if (isAntiPr) { - selectedtracksPIDMC_antip[track.singleCollSelId()].push_back(std::make_shared(track)); + if (particle.pdgCode() == -pdgDeuteron && std::abs(particle.y()) < 0.5) { + registry.fill(HIST("Generated/hAntiDeuteronsVsPt"), particle.pt()); } - if (track.pdgCode() == -pdgProton) { - selectedtracksMC_antip[track.singleCollSelId()].push_back(std::make_shared(track)); + + 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); } - } // track - if (!mcCorrelation) { - return; + if (particle.pdgCode() == pdgDeuteron) { + registry.fill(HIST("hGen_EtaPhiPt_Deuteron"), particle.eta(), particle.phi(), particle.pt()); + selectedparticlesMC_d[particle.mcCollisionId()].push_back(std::make_shared(particle)); + } + if (particle.pdgCode() == -pdgDeuteron) { + registry.fill(HIST("hGen_EtaPhiPt_Deuteron"), particle.eta(), particle.phi(), -1. * particle.pt()); + selectedparticlesMC_antid[particle.mcCollisionId()].push_back(std::make_shared(particle)); + } + if (particle.pdgCode() == pdgProton) { + registry.fill(HIST("hGen_EtaPhiPt_Proton"), particle.eta(), particle.phi(), particle.pt()); + selectedparticlesMC_p[particle.mcCollisionId()].push_back(std::make_shared(particle)); + } + if (particle.pdgCode() == -pdgProton) { + registry.fill(HIST("hGen_EtaPhiPt_Proton"), particle.eta(), particle.phi(), -1. * particle.pt()); + selectedparticlesMC_antip[particle.mcCollisionId()].push_back(std::make_shared(particle)); + } } - for (auto collision : collisions) { - if (TMath::Abs(collision.posZ()) > cutzvertex) + for (auto collision1 : mcCollisions) { // loop on collisions + + registry.fill(HIST("Generated/hNEventsMC"), 0.5); + + if (std::abs(collision1.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)); + const auto particlesInCollision = mcParticles.sliceBy(perMCCol, collision1.globalIndex()); - if (selectedtracksMC_p.find(collision.globalIndex()) != selectedtracksMC_p.end()) { - mixbins_pantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + float Ncharged = 0.; + for (auto& mcParticle : particlesInCollision) { + + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + if (std::abs(mcParticle.eta()) > 0.5f) { + continue; + } + + TParticlePDG* p = pdgDB->GetParticle(mcParticle.pdgCode()); + if (std::abs(p->Charge()) > 1E-3) { + Ncharged++; + } + } + + registry.fill(HIST("hMult"), Ncharged); + + int vertexBinToMix = std::floor((collision1.posZ() + cutzvertex) / (2 * cutzvertex / _vertexNbinsToMix)); + int centBinToMix = std::floor(Ncharged / (maxmultmix / _multNsubBins)); + + if (Ncharged > maxmultmix) + centBinToMix = _multNsubBins - 1; // to avoid overflow in centrality bin + if (centBinToMix < 0) + centBinToMix = 0; // to avoid underflow in centrality bin + + if (selectedparticlesMC_antid.find(collision1.globalIndex()) != selectedparticlesMC_antid.end()) { + mixbinsMC_antid[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision1)); } - if (selectedtracksMC_antid.find(collision.globalIndex()) != selectedtracksMC_antid.end()) { - mixbins_antidantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + if (selectedparticlesMC_d.find(collision1.globalIndex()) != selectedparticlesMC_d.end()) { + mixbinsMC_d[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision1)); } - if (selectedtracksPIDMC_p.find(collision.globalIndex()) != selectedtracksPIDMC_p.end()) { - mixbinsPID_pantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + if (selectedparticlesMC_antip.find(collision1.globalIndex()) != selectedparticlesMC_antip.end()) { + mixbinsMC_antip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision1)); } - if (selectedtracksPIDMC_antid.find(collision.globalIndex()) != selectedtracksPIDMC_antid.end()) { - mixbinsPID_antidantip[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision)); + if (selectedparticlesMC_p.find(collision1.globalIndex()) != selectedparticlesMC_p.end()) { + mixbinsMC_p[std::pair{vertexBinToMix, centBinToMix}].push_back(std::make_shared(collision1)); } + } // coll - if (!mixbins_pantip.empty()) { + if (!mixbinsMC_antip.empty()) { - for (auto i = mixbins_pantip.begin(); i != mixbins_pantip.end(); i++) { // iterating over all vertex&mult bins + // antip-antip + for (auto i = mixbinsMC_antip.begin(); i != mixbinsMC_antip.end(); i++) { // iterating over all vertex&mult bins - std::vector value = i->second; + 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 (selectedtracksMC_antip.find(col1->index()) != selectedtracksMC_antip.end()) { - mixTracks<0, 1 /*MC qa*/>(selectedtracksMC_p[col1->index()], selectedtracksMC_antip[col1->index()], 0, 0); // mixing SE + if (selectedparticlesMC_antip.find(col1->index()) != selectedparticlesMC_antip.end()) { + mixMCParticlesIdentical<0>(selectedparticlesMC_antip[col1->index()], selectedparticlesMC_antip[col1->index()], 0); // mixing SE } for (int indx2 = indx1 + 1; indx2 < EvPerBin; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin @@ -1008,27 +1691,58 @@ struct hadronnucleicorrelation { continue; } - if (selectedtracksMC_antip.find(col2->index()) != selectedtracksMC_antip.end()) { - mixTracks<1, 1>(selectedtracksMC_p[col1->index()], selectedtracksMC_antip[col2->index()], 0, 0); // mixing ME + if (selectedparticlesMC_antip.find(col2->index()) != selectedparticlesMC_antip.end()) { + mixMCParticlesIdentical<1>(selectedparticlesMC_antip[col1->index()], selectedparticlesMC_antip[col2->index()], 0); // mixing SE } } - } // event + } } - } - if (!mixbinsPID_pantip.empty()) { + // antip-p + for (auto i = mixbinsMC_antip.begin(); i != mixbinsMC_antip.end(); i++) { // iterating over all vertex&mult bins - for (auto i = mixbinsPID_pantip.begin(); i != mixbinsPID_pantip.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 - std::vector value = i->second; + for (int indx1 = 0; indx1 < EvPerBin; indx1++) { // loop over all the events in each vertex&mult bin + + auto col1 = value[indx1]; + + if (selectedparticlesMC_antip.find(col1->index()) != selectedparticlesMC_antip.end()) { + mixMCParticles<0>(selectedparticlesMC_antip[col1->index()], selectedparticlesMC_p[col1->index()], 0); // 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 (selectedparticlesMC_antip.find(col2->index()) != selectedparticlesMC_antip.end()) { + mixMCParticles<1>(selectedparticlesMC_antip[col1->index()], selectedparticlesMC_p[col2->index()], 0); // mixing SE + } + } + } + } + + } // mixbinsMC_antip + + if (!mixbinsMC_p.empty()) { + + // p-p + for (auto i = mixbinsMC_p.begin(); i != mixbinsMC_p.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 /*MC qa*/>(selectedtracksPIDMC_p[col1->index()], selectedtracksPIDMC_antip[col1->index()], 0, 1); // mixing SE + if (selectedparticlesMC_p.find(col1->index()) != selectedparticlesMC_p.end()) { + mixMCParticlesIdentical<0>(selectedparticlesMC_p[col1->index()], selectedparticlesMC_p[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 @@ -1039,27 +1753,28 @@ struct hadronnucleicorrelation { continue; } - if (selectedtracksPIDMC_antip.find(col2->index()) != selectedtracksPIDMC_antip.end()) { - mixTracks<1, 1>(selectedtracksPIDMC_p[col1->index()], selectedtracksPIDMC_antip[col2->index()], 0, 1); // mixing ME + if (selectedparticlesMC_p.find(col2->index()) != selectedparticlesMC_p.end()) { + mixMCParticlesIdentical<1>(selectedparticlesMC_p[col1->index()], selectedparticlesMC_p[col2->index()], 1); // mixing SE } } } } - } + } // mixbinsMC_p - if (!mixbins_antidantip.empty()) { + if (!mixbinsMC_antid.empty()) { - for (auto i = mixbins_antidantip.begin(); i != mixbins_antidantip.end(); i++) { // iterating over all vertex&mult bins + // antid-antip + for (auto i = mixbinsMC_antid.begin(); i != mixbinsMC_antid.end(); i++) { // iterating over all vertex&mult bins - std::vector value = i->second; + 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 (selectedtracksMC_antip.find(col1->index()) != selectedtracksMC_antip.end()) { - mixTracks<0, 1 /*MC qa*/>(selectedtracksMC_antid[col1->index()], selectedtracksMC_antip[col1->index()], 1, 0); // mixing SE + if (selectedparticlesMC_antid.find(col1->index()) != selectedparticlesMC_antid.end()) { + mixMCParticles<0>(selectedparticlesMC_antid[col1->index()], selectedparticlesMC_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 @@ -1070,27 +1785,58 @@ struct hadronnucleicorrelation { continue; } - if (selectedtracksMC_antip.find(col2->index()) != selectedtracksMC_antip.end()) { - mixTracks<1, 1>(selectedtracksMC_antid[col1->index()], selectedtracksMC_antip[col2->index()], 1, 0); // mixing ME + if (selectedparticlesMC_antid.find(col2->index()) != selectedparticlesMC_antid.end()) { + mixMCParticles<1>(selectedparticlesMC_antid[col1->index()], selectedparticlesMC_antip[col2->index()], 1); // mixing SE } } } } - } - if (!mixbinsPID_antidantip.empty()) { + // antid-p + for (auto i = mixbinsMC_antid.begin(); i != mixbinsMC_antid.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 (auto i = mixbinsPID_antidantip.begin(); i != mixbinsPID_antidantip.end(); i++) { // iterating over all vertex&mult bins + for (int indx1 = 0; indx1 < EvPerBin; indx1++) { // loop over all the events in each vertex&mult bin - std::vector value = i->second; + auto col1 = value[indx1]; + + if (selectedparticlesMC_antid.find(col1->index()) != selectedparticlesMC_antid.end()) { + mixMCParticles<0>(selectedparticlesMC_antid[col1->index()], selectedparticlesMC_p[col1->index()], 2); // 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 (selectedparticlesMC_antid.find(col2->index()) != selectedparticlesMC_antid.end()) { + mixMCParticles<1>(selectedparticlesMC_antid[col1->index()], selectedparticlesMC_p[col2->index()], 2); // mixing SE + } + } + } + } + + } // mixbinsMC_antid + + if (!mixbinsMC_d.empty()) { + + // d-antip + for (auto i = mixbinsMC_d.begin(); i != mixbinsMC_d.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 /*MC qa*/>(selectedtracksPIDMC_antid[col1->index()], selectedtracksPIDMC_antip[col1->index()], 1, 1); // mixing SE + if (selectedparticlesMC_d.find(col1->index()) != selectedparticlesMC_d.end()) { + mixMCParticles<0>(selectedparticlesMC_d[col1->index()], selectedparticlesMC_antip[col1->index()], 3); // mixing SE } for (int indx2 = indx1 + 1; indx2 < EvPerBin; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin @@ -1101,60 +1847,81 @@ struct hadronnucleicorrelation { continue; } - if (selectedtracksPIDMC_antip.find(col2->index()) != selectedtracksPIDMC_antip.end()) { - mixTracks<1, 1>(selectedtracksPIDMC_antid[col1->index()], selectedtracksPIDMC_antip[col2->index()], 1, 1); // mixing ME + if (selectedparticlesMC_d.find(col2->index()) != selectedparticlesMC_d.end()) { + mixMCParticles<1>(selectedparticlesMC_d[col1->index()], selectedparticlesMC_antip[col2->index()], 3); // mixing SE } } } } - } - // clearing up - for (auto i = selectedtracksMC_antid.begin(); i != selectedtracksMC_antid.end(); i++) - (i->second).clear(); - selectedtracksMC_antid.clear(); + // d-p + for (auto i = mixbinsMC_d.begin(); i != mixbinsMC_d.end(); i++) { // iterating over all vertex&mult bins - for (auto i = selectedtracksMC_antip.begin(); i != selectedtracksMC_antip.end(); i++) - (i->second).clear(); - selectedtracksMC_antip.clear(); + 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 (selectedparticlesMC_d.find(col1->index()) != selectedparticlesMC_d.end()) { + mixMCParticles<0>(selectedparticlesMC_d[col1->index()], selectedparticlesMC_p[col1->index()], 4); // mixing SE + } + + for (int indx2 = indx1 + 1; indx2 < EvPerBin; indx2++) { // nested loop for all the combinations of collisions in a chosen mult/vertex bin - for (auto i = selectedtracksMC_p.begin(); i != selectedtracksMC_p.end(); i++) + auto col2 = (i->second)[indx2]; + + if (col1 == col2) { + continue; + } + + if (selectedparticlesMC_d.find(col2->index()) != selectedparticlesMC_d.end()) { + mixMCParticles<1>(selectedparticlesMC_d[col1->index()], selectedparticlesMC_p[col2->index()], 4); // mixing SE + } + } + } + } + + } // mixbinsMC_d + + // clearing up + for (auto i = selectedparticlesMC_antid.begin(); i != selectedparticlesMC_antid.end(); i++) (i->second).clear(); - selectedtracksMC_p.clear(); + selectedparticlesMC_antid.clear(); - for (auto i = selectedtracksPIDMC_antid.begin(); i != selectedtracksPIDMC_antid.end(); i++) + for (auto i = selectedparticlesMC_d.begin(); i != selectedparticlesMC_d.end(); i++) (i->second).clear(); - selectedtracksPIDMC_antid.clear(); + selectedparticlesMC_d.clear(); - for (auto i = selectedtracksPIDMC_antip.begin(); i != selectedtracksPIDMC_antip.end(); i++) + for (auto i = selectedparticlesMC_antip.begin(); i != selectedparticlesMC_antip.end(); i++) (i->second).clear(); - selectedtracksPIDMC_antip.clear(); + selectedparticlesMC_antip.clear(); - for (auto i = selectedtracksPIDMC_p.begin(); i != selectedtracksPIDMC_p.end(); i++) + for (auto i = selectedparticlesMC_p.begin(); i != selectedparticlesMC_p.end(); i++) (i->second).clear(); - selectedtracksPIDMC_p.clear(); + selectedparticlesMC_p.clear(); - for (auto& pair : mixbinsPID_antidantip) { + for (auto& pair : mixbinsMC_antip) { pair.second.clear(); // clear the vector associated with the key } - mixbinsPID_antidantip.clear(); // clear the map + mixbinsMC_antip.clear(); // clear the map - for (auto& pair : mixbins_antidantip) { + for (auto& pair : mixbinsMC_p) { pair.second.clear(); // clear the vector associated with the key } - mixbins_antidantip.clear(); // clear the map - - for (auto& pair : mixbinsPID_pantip) { + mixbinsMC_p.clear(); // clear the map + for (auto& pair : mixbinsMC_antid) { pair.second.clear(); // clear the vector associated with the key } - mixbinsPID_pantip.clear(); // clear the map + mixbinsMC_antid.clear(); // clear the map - for (auto& pair : mixbins_pantip) { + for (auto& pair : mixbinsMC_d) { pair.second.clear(); // clear the vector associated with the key } - mixbins_pantip.clear(); // clear the map + mixbinsMC_d.clear(); // clear the map } - PROCESS_SWITCH(hadronnucleicorrelation, processMC, "processMC", false); + PROCESS_SWITCH(hadronnucleicorrelation, processGen, "processGen", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Nuspex/he3LambdaDerivedAnalysis.cxx b/PWGLF/Tasks/Nuspex/he3LambdaDerivedAnalysis.cxx new file mode 100644 index 00000000000..7929f4eaa9c --- /dev/null +++ b/PWGLF/Tasks/Nuspex/he3LambdaDerivedAnalysis.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. + +#include "PWGLF/DataModel/LFSlimHeLambda.h" + +#include +#include +#include +#include + +#include + +#include + +namespace +{ +std::shared_ptr hInvariantMassUS[2]; +std::shared_ptr hInvariantMassLS[2]; +std::shared_ptr hRotationInvariantMassUS[2]; +std::shared_ptr hRotationInvariantMassLS[2]; +std::shared_ptr hRotationInvariantMassAntiLSeta[2]; +std::shared_ptr hInvariantMassLambda[2]; +std::shared_ptr hCosPALambda; +std::shared_ptr hNsigmaHe3; +std::shared_ptr hNsigmaProton; +}; // namespace + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct he3LambdaDerivedAnalysis { + HistogramRegistry mRegistry{"He3LambdaDerivedAnalysis"}; + + Configurable cfgNrotations{"cfgNrotations", 7, "Number of rotations for He3 candidates"}; + Configurable cfgMirrorEta{"cfgMirrorEta", true, "Mirror eta for He3 candidates"}; + Configurable cfgMinCosPA{"cfgMinCosPA", 0.99, "Minimum cosPA for Lambda candidates"}; + Configurable cfgMaxNSigmaTPCHe3{"cfgMaxNSigmaTPCHe3", 2.0, "Maximum nSigmaTPC for He3 candidates"}; + Configurable cfgMinLambdaPt{"cfgMinLambdaPt", 0.4, "Minimum pT for Lambda candidates"}; + Configurable cfgMaxLambdaDeltaM{"cfgMaxLambdaDeltaM", 10.0e-3, "Maximum deltaM for Lambda candidates"}; + + void init(InitContext const&) + { + constexpr double ConstituentsMass = o2::constants::physics::MassProton + o2::constants::physics::MassNeutron * 2 + o2::constants::physics::MassSigmaPlus; + for (int i = 0; i < 2; ++i) { + hInvariantMassUS[i] = mRegistry.add(Form("hInvariantMassUS%i", i), "Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); + hInvariantMassLS[i] = mRegistry.add(Form("hInvariantMassLS%i", i), "Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); + hRotationInvariantMassUS[i] = mRegistry.add(Form("hRotationInvariantMassUS%i", i), "Rotation Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); + hRotationInvariantMassLS[i] = mRegistry.add(Form("hRotationInvariantMassLS%i", i), "Rotation Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); + hInvariantMassLambda[i] = mRegistry.add(Form("hInvariantMassLambda%i", i), "Invariant Mass Lambda", {HistType::kTH2D, {{50, 0., 10.}, {30, o2::constants::physics::MassLambda0 - 0.015, o2::constants::physics::MassLambda0 + 0.015}}}); + hRotationInvariantMassAntiLSeta[i] = mRegistry.add(Form("hRotationInvariantMassAntiLSeta%i", i), "Rotation Invariant Mass Anti-Lambda", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); + } + hCosPALambda = mRegistry.add("hCosPALambda", "Cosine of Pointing Angle for Lambda", {HistType::kTH2D, {{50, 0., 10.}, {500, 0.9, 1.}}}); + hNsigmaHe3 = mRegistry.add("hNsigmaHe3", "nSigma TPC for He3", {HistType::kTH2D, {{100, -10., 10.}, {200, -5, 5.}}}); + hNsigmaProton = mRegistry.add("hNsigmaProton", "nSigma TPC for Proton", {HistType::kTH2D, {{100, -10., 10.}, {200, -5, 5.}}}); + } + + void processSameEvent(o2::aod::LFEvents::iterator const& collision, o2::aod::LFHe3_000 const& he3s, o2::aod::LFLambda_000 const& lambdas) + { + std::vector he3Candidates; + he3Candidates.reserve(he3s.size()); + std::vector lambdaCandidates; + lambdaCandidates.reserve(lambdas.size()); + for (const auto& he3 : he3s) { + if (he3.lfEventId() != collision.globalIndex()) { + std::cout << "He3 candidate does not match event index, skipping." << std::endl; + return; + } + he3Candidate candidate; + candidate.momentum = ROOT::Math::LorentzVector>(he3.pt(), he3.eta(), he3.phi(), o2::constants::physics::MassHelium3); + candidate.nSigmaTPC = he3.nSigmaTPC(); + candidate.dcaXY = he3.dcaXY(); + candidate.dcaZ = he3.dcaZ(); + candidate.tpcNClsFound = he3.tpcNCls(); + candidate.itsNCls = he3.itsClusterSizes(); + candidate.itsClusterSizes = he3.itsClusterSizes(); + candidate.sign = he3.sign(); + hNsigmaHe3->Fill(he3.pt() * he3.sign(), he3.nSigmaTPC()); + if (std::abs(he3.nSigmaTPC()) > cfgMaxNSigmaTPCHe3) { + continue; // Skip candidates with nSigmaTPC outside range + } + he3Candidates.push_back(candidate); + } + for (const auto& lambda : lambdas) { + if (lambda.lfEventId() != collision.globalIndex()) { + std::cout << "Lambda candidate does not match event index, skipping." << std::endl; + return; + } + lambdaCandidate candidate; + candidate.momentum.SetCoordinates(lambda.pt(), lambda.eta(), lambda.phi(), o2::constants::physics::MassLambda0); + candidate.mass = lambda.mass(); + candidate.cosPA = lambda.cosPA(); + candidate.dcaV0Daughters = lambda.dcaDaughters(); + hCosPALambda->Fill(lambda.pt(), candidate.cosPA); + // hNsigmaProton->Fill(lambda.pt() * lambda.sign(), lambda.protonNSigmaTPC()); + hInvariantMassLambda[0]->Fill(lambda.pt(), lambda.mass()); + if (candidate.cosPA < cfgMinCosPA || lambda.pt() < cfgMinLambdaPt || + std::abs(lambda.mass() - o2::constants::physics::MassLambda0) > cfgMaxLambdaDeltaM) { + continue; // Skip candidates with low cosPA + } + hInvariantMassLambda[1]->Fill(lambda.pt(), lambda.mass()); + lambdaCandidates.push_back(candidate); + } + + for (const auto& he3 : he3Candidates) { + for (const auto& lambda : lambdaCandidates) { + auto pairMomentum = lambda.momentum + he3.momentum; // Calculate invariant mass + (he3.sign * lambda.sign > 0 ? hInvariantMassLS : hInvariantMassUS)[he3.sign > 0]->Fill(pairMomentum.Pt(), pairMomentum.M()); + } + for (int iEta{0}; iEta <= cfgMirrorEta; ++iEta) { + for (int iR{0}; iR <= cfgNrotations; ++iR) { + auto he3Momentum = ROOT::Math::LorentzVector>(he3.momentum.Pt(), (1. - iEta * 2.) * he3.momentum.Eta(), he3.momentum.Phi() + TMath::Pi() * (0.75 + 0.5 * iR / cfgNrotations), he3.momentum.M()); + for (const auto& lambda : lambdaCandidates) { + auto pairMomentum = lambda.momentum + he3Momentum; // Calculate invariant mass + (he3.sign * lambda.sign > 0 ? hRotationInvariantMassLS : hRotationInvariantMassUS)[he3.sign > 0]->Fill(pairMomentum.Pt(), pairMomentum.M()); + if (he3.sign < 0 && lambda.sign < 0) { + hRotationInvariantMassAntiLSeta[iEta]->Fill(pairMomentum.Pt(), pairMomentum.M()); + } + } + } + } + } + } + PROCESS_SWITCH(he3LambdaDerivedAnalysis, processSameEvent, "Process same event", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/helium_flow.cxx b/PWGLF/Tasks/Nuspex/helium_flow.cxx index cc791f7fb2f..10b5bffef1e 100644 --- a/PWGLF/Tasks/Nuspex/helium_flow.cxx +++ b/PWGLF/Tasks/Nuspex/helium_flow.cxx @@ -12,30 +12,34 @@ /// \author Alberto Caliva (alberto.caliva@cern.ch) /// \since November 27, 2023 -#include -#include -#include -#include -#include -#include -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" #include "Framework/HistogramRegistry.h" #include "Framework/RunningWorkflowInfo.h" -#include "Framework/DataTypes.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/PID.h" +#include "Framework/runDataProcessing.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 "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +#include using namespace std; using namespace o2; 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/hypertriton3bodyanalysis.cxx b/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx deleted file mode 100644 index 4e0b781d897..00000000000 --- a/PWGLF/Tasks/Nuspex/hypertriton3bodyanalysis.cxx +++ /dev/null @@ -1,732 +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. -// -// 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 -// - -#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/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; - -struct hypertriton3bodyQa { - // Basic checks - HistogramRegistry registry{ - "registry", - { - {"hVtxRadius", "hVtxRadius", {HistType::kTH1F, {{1000, 0.0f, 100.0f, "cm"}}}}, - {"hVtxCosPA", "hVtxCosPA", {HistType::kTH1F, {{1000, 0.9f, 1.0f}}}}, - {"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, {{300, 0, 300, "TPC cluster"}}}}, - {"hPionTPCNcls", "hPionTPCNcls", {HistType::kTH1F, {{300, 0, 300, "TPC cluster"}}}}, - {"hDeuteronTPCNcls", "hDeuteronTPCNcls", {HistType::kTH1F, {{300, 0, 300, "TPC cluster"}}}}, - {"hDCAVtxDau", "hDCAVtxDau", {HistType::kTH1F, {{1000, 0.0f, 10.0f, "cm^{2}"}}}}, - {"hVtxPt", "hVtxPt", {HistType::kTH1F, {{200, 0.0f, 10.0f, "p_{T}"}}}}, - {"hTOFPIDDeuteron", "hTOFPIDDeuteron", {HistType::kTH1F, {{2000, -100.0f, 100.0f}}}}, - {"hDeuTOFNsigma", "Deuteron TOF Nsigma distribution", {HistType::kTH2F, {{1200, -6, 6, "#it{p} (GeV/#it{c})"}, {2000, -100, 100, "TOF n#sigma"}}}}, - {"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}}); - } - void process(aod::Collision const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const& /*tracks*/) - { - for (auto& vtx : vtx3bodydatas) { - auto track0 = vtx.track0_as(); - auto track1 = vtx.track1_as(); - auto track2 = vtx.track2_as(); - - registry.fill(HIST("hVtxRadius"), vtx.vtxradius()); - registry.fill(HIST("hVtxCosPA"), vtx.vtxcosPA(collision.posX(), collision.posY(), collision.posZ())); - registry.fill(HIST("hDCAVtxDau"), vtx.dcaVtxdaughters()); - registry.fill(HIST("hVtxPt"), vtx.pt()); - registry.fill(HIST("hMassHypertriton"), vtx.mHypertriton()); - registry.fill(HIST("hMassAntiHypertriton"), vtx.mAntiHypertriton()); - registry.fill(HIST("hTOFPIDDeuteron"), vtx.tofNSigmaBachDe()); - registry.fill(HIST("hDeuTOFNsigma"), track2.tpcInnerParam() * track2.sign(), vtx.tofNSigmaBachDe()); - if (std::abs(track2.tpcNSigmaDe()) < 5) { - 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("hDCAProtonToPV"), vtx.dcatrack0topv()); - registry.fill(HIST("hDCAPionToPV"), vtx.dcatrack1topv()); - registry.fill(HIST("hProtonTPCNcls"), track0.tpcNClsCrossedRows()); - registry.fill(HIST("hPionTPCNcls"), track1.tpcNClsCrossedRows()); - } else { - registry.fill(HIST("hPtPionPlus"), track0.pt()); - registry.fill(HIST("hPtAntiProton"), track1.pt()); - registry.fill(HIST("hPtAntiDeuteron"), track2.pt()); - 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("hDCADeuteronToPV"), vtx.dcatrack2topv()); - registry.fill(HIST("hDeuteronTPCNcls"), track2.tpcNClsCrossedRows()); - } - } -}; - -struct hypertriton3bodyAnalysis { - - // 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 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 mcsigma{"mcsigma", 0.0015, "sigma of mc invariant mass fit"}; // obtained from MC - - HistogramRegistry registry{ - "registry", - { - {"hEventCounter", "hEventCounter", {HistType::kTH1F, {{4, 0.0f, 4.0f}}}}, - {"hCandidatesCounter", "hCandidatesCounter", {HistType::kTH1F, {{12, 0.0f, 12.0f}}}}, - {"hMassHypertriton", "hMassHypertriton", {HistType::kTH1F, {{80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hMassAntiHypertriton", "hMassAntiHypertriton", {HistType::kTH1F, {{80, 2.96f, 3.04f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hMassHypertritonTotal", "hMassHypertritonTotal", {HistType::kTH1F, {{300, 2.9f, 3.2f, "Inv. Mass (GeV/c^{2})"}}}}, - {"hPtProton", "hPtProton", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"hPtPionMinus", "hPtPionMinus", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"hPtDeuteron", "hPtDeuteron", {HistType::kTH1F, {{200, 0.0f, 10.0f, "#it{p}_{T} (GeV/c)"}}}}, - {"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)"}}}}, - {"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, {{120, -6.0f, 6.0f}}}}, - {"hTPCPIDPion", "hTPCPIDPion", {HistType::kTH1F, {{120, -6.0f, 6.0f}}}}, - {"hTPCPIDDeuteron", "hTPCPIDDeuteron", {HistType::kTH1F, {{120, -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"}}}}, - {"hProtonTPCVsPt", "hProtonTPCVsPt", {HistType::kTH2F, {{50, 0.0f, 5.0f, "#it{p}_{T} (GeV/c)"}, {120, -6.0f, 6.0f, "TPC n#sigma"}}}}, - {"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"}}}}, - - {"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"}}}}, - {"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}}}}, - }, - }; - - //------------------------------------------------------------------ - // Fill stats histograms - enum vtxstep { kCandAll = 0, - kCandCosPA, - kCandDauEta, - kCandRapidity, - kCandct, - kCandDcaDau, - kCandTOFPID, - kCandTPCPID, - kCandTPCNcls, - kCandDauPt, - kCandDcaToPV, - kCandInvMass, - kNCandSteps }; - - struct { - std::array candstats; - std::array truecandstats; - } statisticsRegistry; - - void resetHistos() - { - for (Int_t ii = 0; ii < kNCandSteps; ii++) { - statisticsRegistry.candstats[ii] = 0; - statisticsRegistry.truecandstats[ii] = 0; - } - } - void FillCandCounter(int kn, bool istrue = false) - { - statisticsRegistry.candstats[kn]++; - if (istrue) { - statisticsRegistry.truecandstats[kn]++; - } - } - void fillHistos() - { - for (Int_t ii = 0; ii < kNCandSteps; ii++) { - registry.fill(HIST("hCandidatesCounter"), ii, statisticsRegistry.candstats[ii]); - 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}, ""}; - - 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"}; - 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("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) - { - - 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; - } - 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(), candData.tofNSigmaBachDe()); - if (isTrueCand) { - registry.fill(HIST("hDeuteronTOFVsPBeforeTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - } - if ((candData.tofNSigmaBachDe() < TofPidNsigmaMin || candData.tofNSigmaBachDe() > TofPidNsigmaMax) && trackDeuteron.p() > minDeuteronPUseTOF) { - return; - } - FillCandCounter(kCandTOFPID, isTrueCand); - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCut"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - if (isTrueCand) { - registry.fill(HIST("hDeuteronTOFVsPAtferTOFCutSig"), trackDeuteron.sign() * trackDeuteron.p(), candData.tofNSigmaBachDe()); - } - - if (TMath::Abs(trackProton.tpcNSigmaPr()) > TpcPidNsigmaCut || TMath::Abs(trackPion.tpcNSigmaPi()) > TpcPidNsigmaCut || TMath::Abs(trackDeuteron.tpcNSigmaDe()) > TpcPidNsigmaCut) { - return; - } - FillCandCounter(kCandTPCPID, isTrueCand); - - if (trackProton.tpcNClsFound() < mintpcNClsproton || trackPion.tpcNClsFound() < mintpcNClspion || trackDeuteron.tpcNClsFound() < mintpcNClsdeuteron) { - return; - } - FillCandCounter(kCandTPCNcls, isTrueCand); - - if (trackProton.pt() < minProtonPt || trackProton.pt() > maxProtonPt || trackPion.pt() < minPionPt || trackPion.pt() > maxPionPt || trackDeuteron.pt() < minDeuteronPt || trackDeuteron.pt() > maxDeuteronPt) { - return; - } - FillCandCounter(kCandDauPt, isTrueCand); - - double dcapion = (track2.sign() > 0) ? candData.dcatrack1topv() : candData.dcatrack0topv(); - if (TMath::Abs(dcapion) < dcapiontopv) { - return; - } - FillCandCounter(kCandDcaToPV, isTrueCand); - - // 3sigma region for Dalitz plot - double lowersignallimit = o2::constants::physics::MassHyperTriton - 3 * mcsigma; - double uppersignallimit = o2::constants::physics::MassHyperTriton + 3 * mcsigma; - - // Hypertriton - if ((track2.sign() > 0 && candData.mHypertriton() > h3LMassLowerlimit && candData.mHypertriton() < h3LMassUpperlimit)) { - if_hasvtx = true; - 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()); - 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, lPt, candData.mHypertriton()); - } - } else if ((track2.sign() < 0 && 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("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, lPt, candData.mHypertriton()); - } - } else { - return; - } - 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.tpcNClsCrossedRows()); - registry.fill(HIST("hPionTPCNcls"), trackPion.tpcNClsCrossedRows()); - registry.fill(HIST("hDeuteronTPCNcls"), trackDeuteron.tpcNClsCrossedRows()); - 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"), candData.tofNSigmaBachDe()); - } - - //------------------------------------------------------------------ - // 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) { - 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) - haveProton = true; - if (mcparticleDaughter.pdgCode() == -2212) - haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == 211) - havePionPlus = true; - if (mcparticleDaughter.pdgCode() == -211) - havePionMinus = true; - if (mcparticleDaughter.pdgCode() == 1000010020) { - 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) { - 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) { - 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) { - registry.fill(HIST("hGeneratedHypertritonCounter"), 1.5); - registry.fill(HIST("hPtGeneratedAntiHypertriton"), mcparticle.pt()); - registry.fill(HIST("hctGeneratedAntiHypertriton"), MClifetime); - registry.fill(HIST("hEtaGeneratedAntiHypertriton"), mcparticle.eta()); - registry.fill(HIST("hRapidityGeneratedAntiHypertriton"), mcparticle.y()); - } - } - } - - //------------------------------------------------------------------ - // process real data analysis - void processData(soa::Join::iterator const& collision, aod::Vtx3BodyDatas const& vtx3bodydatas, FullTracksExtIU const& /*tracks*/) - { - 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); - - bool if_hasvtx = false; - - for (auto& vtx : vtx3bodydatas) { - CandidateAnalysis(collision, vtx, if_hasvtx); - } - - if (if_hasvtx) - registry.fill(HIST("hEventCounter"), 3.5); - fillHistos(); - resetHistos(); - } - PROCESS_SWITCH(hypertriton3bodyAnalysis, processData, "Real data analysis", true); - - //------------------------------------------------------------------ - // process mc analysis - void processMC(soa::Join const& collisions, aod::Vtx3BodyDatas const& vtx3bodydatas, aod::McParticles const& particlesMC, MCLabeledTracksIU const& /*tracks*/) - { - GetGeneratedH3LInfo(particlesMC); - - for (const auto& collision : collisions) { - registry.fill(HIST("hEventCounter"), 0.5); - if (event_sel8_selection && !collision.sel8()) { - continue; - } - registry.fill(HIST("hEventCounter"), 1.5); - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm - return; - } - registry.fill(HIST("hEventCounter"), 2.5); - - bool if_hasvtx = false; - auto vtxsthiscol = vtx3bodydatas.sliceBy(perCollisionVtx3BodyDatas, collision.globalIndex()); - - for (auto& vtx : vtxsthiscol) { - // int lLabel = -1; - int lPDG = -1; - float lPt = -1; - double MClifetime = -1; - bool isTrueCand = false; - auto track0 = vtx.track0_as(); - auto track1 = vtx.track1_as(); - auto track2 = vtx.track2_as(); - if (track0.has_mcParticle() && track1.has_mcParticle() && track2.has_mcParticle()) { - auto lMCTrack0 = track0.mcParticle_as(); - 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()) { - 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)) { - isTrueCand = true; - MClifetime = RecoDecay::sqrtSumOfSquares(lMCTrack2.vx() - lMother2.vx(), lMCTrack2.vy() - lMother2.vy(), lMCTrack2.vz() - lMother2.vz()) * o2::constants::physics::MassHyperTriton / lMother2.p(); - } - } - } - } - } - } - } - - CandidateAnalysis(collision, vtx, if_hasvtx, isTrueCand, MClifetime, lPt); - } - - if (if_hasvtx) - registry.fill(HIST("hEventCounter"), 3.5); - fillHistos(); - resetHistos(); - } - } - PROCESS_SWITCH(hypertriton3bodyAnalysis, processMC, "MC analysis", false); -}; - -// 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}}}}, - }, - }; - - 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"); - } - - 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; - 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&) - { - // dummy function - } - PROCESS_SWITCH(hypertriton3bodyLabelCheck, process, "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) { - registry.fill(HIST("hDecay3BodyCounter"), 0.5); - auto lTrack0 = d3body.track0_as(); - auto lTrack1 = d3body.track1_as(); - auto lTrack2 = d3body.track2_as(); - if (!lTrack0.has_mcParticle() || !lTrack1.has_mcParticle() || !lTrack2.has_mcParticle()) { - continue; - } - auto lMCTrack0 = lTrack0.mcParticle_as(); - auto lMCTrack1 = lTrack1.mcParticle_as(); - auto lMCTrack2 = lTrack2.mcParticle_as(); - if (!lMCTrack0.has_mothers() || !lMCTrack1.has_mothers() || !lMCTrack2.has_mothers()) { - continue; - } - - for (auto& lMother0 : lMCTrack0.mothers_as()) { - for (auto& lMother1 : lMCTrack1.mothers_as()) { - for (auto& lMother2 : lMCTrack2.mothers_as()) { - if (lMother0.globalIndex() == lMother1.globalIndex() && lMother0.globalIndex() == lMother2.globalIndex()) { - registry.fill(HIST("hDecay3BodyCounter"), 1.5); - // duplicated daughters check - Indexdaughters temp = {lMCTrack0.globalIndex(), lMCTrack1.globalIndex(), lMCTrack2.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("hDecay3BodyCounter"), 2.5); - if (lMother0.mcCollisionId() == collision.mcCollisionId()) { - registry.fill(HIST("hDecay3BodyCounter"), 3.5); - if (lTrack0.collisionId() == lTrack1.collisionId() && lTrack0.collisionId() == lTrack2.collisionId()) { - registry.fill(HIST("hDecay3BodyCounter"), 4.5); - } - } - } - } - } - } - } - } - - if (event_sel8_selection && !collision.sel8()) { - return; - } - - if (event_posZ_selection && abs(collision.posZ()) > 10.f) { // 10cm - return; - } - - std::vector set_mothertrack; - for (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); - registry.fill(HIST("hHypertritonCounter"), 0.5); - registry.fill(HIST("hMassTrueH3L"), vtx.mHypertriton()); - registry.fill(HIST("hMassTrueH3LMatter"), vtx.mHypertriton()); - 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) { - registry.fill(HIST("hPIDCounter"), 0.5); - } - if (TMath::Abs(lTrack1.tpcNSigmaPi()) > TpcPidNsigmaCut) { - registry.fill(HIST("hPIDCounter"), 1.5); - } - if (TMath::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) { - registry.fill(HIST("hHypertritonCounter"), 1.5); - } - } else if (mcparticle.pdgCode() == -1010010030) { - registry.fill(HIST("hLabeledVtxCounter"), 1.5); - registry.fill(HIST("hHypertritonCounter"), 2.5); - registry.fill(HIST("hMassTrueH3L"), vtx.mAntiHypertriton()); - registry.fill(HIST("hMassTrueH3LAntiMatter"), vtx.mAntiHypertriton()); - 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) { - registry.fill(HIST("hPIDCounter"), 4.5); - } - if (TMath::Abs(lTrack1.tpcNSigmaPr()) > TpcPidNsigmaCut) { - registry.fill(HIST("hPIDCounter"), 3.5); - } - if (TMath::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) { - registry.fill(HIST("hHypertritonCounter"), 3.5); - } - } - } - } - } - PROCESS_SWITCH(hypertriton3bodyLabelCheck, processCheckLabel, "Check MC label tables", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; -} diff --git a/PWGLF/Tasks/Nuspex/hypertritonAnalysis.cxx b/PWGLF/Tasks/Nuspex/hypertritonAnalysis.cxx index 8a296edc5b5..b8fb61d6391 100644 --- a/PWGLF/Tasks/Nuspex/hypertritonAnalysis.cxx +++ b/PWGLF/Tasks/Nuspex/hypertritonAnalysis.cxx @@ -18,37 +18,39 @@ // Please write to: // david.dobrigkeit.chinellato@cern.ch // -#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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.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 "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include #include #include -#include #include -#include #include -#include -#include +#include + #include +#include #include -#include "Framework/ASoAHelpers.h" using namespace o2; using namespace o2::framework; @@ -218,7 +220,7 @@ struct hypertritonAnalysis { auto bc = collision.bc_as(); initCCDB(bc); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; evselstats[kEvSelAll]++; if (event_sel8_selection && !collision.sel8()) { @@ -324,7 +326,7 @@ struct hypertritonAnalysis { auto bc = collision.bc_as(); initCCDB(bc); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; evselstats[kEvSelAll]++; if (event_sel8_selection && !collision.sel8()) { diff --git a/PWGLF/Tasks/Nuspex/identifiedraa.cxx b/PWGLF/Tasks/Nuspex/identifiedraa.cxx index 3086152d226..ad3ae5537e0 100644 --- a/PWGLF/Tasks/Nuspex/identifiedraa.cxx +++ b/PWGLF/Tasks/Nuspex/identifiedraa.cxx @@ -28,8 +28,10 @@ #include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/AnalysisTask.h" using namespace o2; diff --git a/PWGLF/Tasks/Nuspex/nucleiEbye.cxx b/PWGLF/Tasks/Nuspex/nucleiEbye.cxx index 0915320f529..681d8b2892e 100644 --- a/PWGLF/Tasks/Nuspex/nucleiEbye.cxx +++ b/PWGLF/Tasks/Nuspex/nucleiEbye.cxx @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -357,6 +359,8 @@ struct nucleiEbye { 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; } @@ -673,6 +677,8 @@ struct nucleiEbye { 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()); } @@ -681,6 +687,8 @@ struct nucleiEbye { 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()); diff --git a/PWGLF/Tasks/Nuspex/nucleiFromHypertritonMap.cxx b/PWGLF/Tasks/Nuspex/nucleiFromHypertritonMap.cxx new file mode 100644 index 00000000000..9ef20c7a58a --- /dev/null +++ b/PWGLF/Tasks/Nuspex/nucleiFromHypertritonMap.cxx @@ -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. +/// +/// \author Roberta Ferioli (roberta.ferioli@cern.ch) +/// \since November, 2024 + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +#include + +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_ITS_InnerBarrel_nClusters{"min_ITS_InnerBarrel_nClusters", 1, "minimum number of found ITS Inner Barrel clusters"}; + Configurable max_ITS_InnerBarrel_nClusters{"max_ITS_InnerBarrel_nClusters", 3, "maximum number of found ITS Inner Barrel 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("he3SecPtGen_from_hypertriton", "he3SecPtGen_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("he3SecPtGen_from_hyperHe4", "he3SecPtGen_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("deutSecPtGen_from_hypertriton", "deutSecPtGen_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 (saveHelium) { + registryMC.fill(HIST("he3SecPtGen_from_hypertriton"), daughter.pt()); + } else { + registryMC.fill(HIST("deutSecPtGen_from_hypertriton"), daughter.pt()); + } + } + } + } + if (mcparticle.pdgCode() == AntiHyperHelium4PDG) { + for (auto& daughter : mcparticle.daughters_as()) { + if (daughter.pdgCode() == selectedPDG) { + registryMC.fill(HIST("hyperHe4PtGen"), mcparticle.pt()); + if (saveHelium) { + registryMC.fill(HIST("he3SecPtGen_from_hyperHe4"), daughter.pt()); + } + } + } + } + if (mcparticle.pdgCode() == AntihePDG && mcparticle.isPhysicalPrimary()) { + registryMC.fill(HIST("he3PtGen"), mcparticle.pt()); + } + if (mcparticle.pdgCode() == AntideuteronPDG && mcparticle.isPhysicalPrimary()) { + 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.itsNClsInnerBarrel() < min_ITS_InnerBarrel_nClusters || + track.itsNClsInnerBarrel() > max_ITS_InnerBarrel_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 && mcparticle.isPhysicalPrimary()) { + registryMC.fill(HIST("deutPtRec"), track.pt()); + } + if (mcparticle.pdgCode() == AntihePDG && mcparticle.isPhysicalPrimary()) { + 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 3c7ad7c0fa2..00000000000 --- a/PWGLF/Tasks/Nuspex/nuclei_in_jets.cxx +++ /dev/null @@ -1,1053 +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.0, "Minimum pt of leading particle"}; - Configurable min_jet_pt{"min_jet_pt", 10.0, "Minimum pt of the jet"}; - Configurable Rjet{"Rjet", 0.3, "Jet resolution parameter R"}; - Configurable Rmax{"Rmax", 0.3, "Maximum radius for jet and UE regions"}; - Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; - Configurable min_nPartInJet{"min_nPartInJet", 2, "Minimum number of particles inside jet"}; - - // 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&) - { - // QC Histograms - 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("ptLeading", "ptLeading", HistType::kTH1F, {{500, 0, 50, "#it{p}_{T} (GeV/#it{c})"}}); - registryQC.add("etaLeading", "etaLeading", HistType::kTH1F, {{100, -0.8, 0.8, "#eta"}}); - registryQC.add("phiLeading", "phiLeading", HistType::kTH1F, {{100, 0, TMath::TwoPi(), "#phi"}}); - registryQC.add("rJet", "rJet", HistType::kTH1F, {{100, 0.0, 0.5, "#it{R}"}}); - registryQC.add("rUE", "rUE", HistType::kTH1F, {{100, 0.0, 0.5, "#it{R}"}}); - registryQC.add("angle_jet_leading_track", "angle_jet_leading_track", HistType::kTH1F, {{200, 0.0, 50.0, "#theta"}}); - 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, 0.5 * TMath::Pi(), "#Delta#phi"}}); - registryQC.add("deltaEtadeltaPhiUE", "deltaEtadeltaPhiUE", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, 0.5 * TMath::Pi(), "#Delta#phi"}}); - registryQC.add("deltaEtadeltaPhi_leading_jet", "deltaEtadeltaPhi_leading_jet", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, 0.5 * TMath::Pi(), "#Delta#phi"}}); - - // QC Histograms for ptJet < pt_leading - 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})"}}); - registryQC.add("dEtadPhi_jetaxis", "dEtadPhi_jetaxis", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, 0.5 * TMath::Pi(), "#Delta#phi"}}); - registryQC.add("dEtadPhi_jetaxis_leadTrk", "dEtadPhi_jetaxis_leadTrk", HistType::kTH2F, {{200, -0.5, 0.5, "#Delta#eta"}, {200, 0, 0.5 * TMath::Pi(), "#Delta#phi"}}); - - // 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"}}); - - // Antiprotons - registryData.add("antiproton_jet_tpc", "antiproton_jet_tpc", HistType::kTH2F, {{20, 0.0, 1.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, {{90, 0.5, 5.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, {{20, 0.0, 1.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, {{90, 0.5, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); - registryData.add("antiproton_dca_jet", "antiproton_dca_jet", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -0.5, 0.5, "DCA_{xy} (cm)"}}); - registryData.add("antiproton_dca_ue", "antiproton_dca_ue", HistType::kTH2F, {{100, 0.0, 5.0, "#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, {{10, 0.0, 1.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("antideuteron_jet_tof", "antideuteron_jet_tof", HistType::kTH2F, {{45, 0.5, 5.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); - registryData.add("antideuteron_ue_tpc", "antideuteron_ue_tpc", HistType::kTH2F, {{10, 0.0, 1.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("antideuteron_ue_tof", "antideuteron_ue_tof", HistType::kTH2F, {{45, 0.5, 5.0, "#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, {{40, 1.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("antihelium3_ue_tpc", "antihelium3_ue_tpc", HistType::kTH2F, {{40, 1.0, 7.0, "#it{p}_{T} (GeV/#it{c})"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - - // 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})"}}); - registryMC.add("antiproton_prim_jet", "antiproton_prim_jet", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_all_jet", "antiproton_all_jet", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_prim_ue", "antiproton_prim_ue", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_all_ue", "antiproton_all_ue", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // Antiproton Reweighting - registryMC.add("antiproton_incl", "antiproton_incl", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_jet", "antiproton_jet", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("antiproton_ue", "antiproton_ue", HistType::kTH1F, {{100, 0.0, 5.0, "#it{p}_{T} (GeV/#it{c})"}}); - } - - // Single-Track Selection for Particles inside Jets - template - bool passedTrackSelectionForJetReconstruction(const T1& 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.0105 * 0.035 / TMath::Power(track.pt(), 1.1))) - return false; - if (TMath::Abs(track.dcaZ()) > 2.0) - return false; - - return true; - } - - // Single-Track Selection - template - bool passedTrackSelection(const T2& 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; - } - - template - bool isHighPurityAntiproton(const T3& track) - { - // Variables - double nsigmaTPCPr = track.tpcNSigmaPr(); - double nsigmaTOFPr = track.tofNSigmaPr(); - double 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 - double Minimum(double x1, double x2) - { - double 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; - } - - // 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; - } - - void get_perpendicular_axis(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 * 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 - 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 * 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 - 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); - - // Indices of Reduced Event - std::vector particle_ID; - - // 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(); - } - particle_ID.push_back(i); - } - - // 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_jet(leading_track.px(), leading_track.py(), leading_track.pz()); - - // QC: pt, eta, and phi Distributions of Leading Track - registryQC.fill(HIST("ptLeading"), p_leading.Pt()); - registryQC.fill(HIST("etaLeading"), p_leading.Eta()); - registryQC.fill(HIST("phiLeading"), p_leading.Phi()); - - // Event Counter: Skip Events with pt(particle_ID.size()); - std::vector jet_particle_ID; - jet_particle_ID.push_back(leading_ID); - - // Jet Finder - do { - // Initialization - double distance_jet_min(1e+08); - double 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 - double one_over_pt2_part = 1.0 / (p_particle.Pt() * p_particle.Pt()); - double one_over_pt2_lead = 1.0 / (p_jet.Pt() * p_jet.Pt()); - double deltaEta = p_particle.Eta() - p_jet.Eta(); - double deltaPhi = GetDeltaPhi(p_particle.Phi(), p_jet.Phi()); - double min = Minimum(one_over_pt2_part, one_over_pt2_lead); - double Delta2 = deltaEta * deltaEta + deltaPhi * deltaPhi; - - // Distances - double distance_jet = min * Delta2 / (Rjet * Rjet); - double 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_jet = p_jet + 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); - - // Event Counter: Skip Events with jet not fully inside acceptance - if ((TMath::Abs(p_jet.Eta()) + Rmax) > max_eta) - return; - registryData.fill(HIST("number_of_events_data"), 4.5); - - // Perpendicular Cones for the UE Estimate - TVector3 ue_axis1(0.0, 0.0, 0.0); - TVector3 ue_axis2(0.0, 0.0, 0.0); - get_perpendicular_axis(p_jet, ue_axis1, +1.0); - get_perpendicular_axis(p_jet, ue_axis2, -1.0); - - // Protection against delta<0 - if (ue_axis1.Mag() == 0 || ue_axis2.Mag() == 0) - return; - registryData.fill(HIST("number_of_events_data"), 5.5); - - // QA Plots - double deltaEta = p_leading.Eta() - p_jet.Eta(); - double deltaPhi = GetDeltaPhi(p_leading.Phi(), p_jet.Phi()); - registryQC.fill(HIST("angle_jet_leading_track"), (180.0 / TMath::Pi()) * p_leading.Angle(p_jet)); - registryQC.fill(HIST("deltaEtadeltaPhi_leading_jet"), deltaEta, deltaPhi); - - double NchJetPlusUE(0); - double NchJet(0); - double NchUE(0); - double ptJetPlusUE(0); - double ptJet(0); - double ptUE(0); - - for (int i = 0; i < nParticles; i++) { - - auto track = tracks.iteratorAt(particle_ID[i]); - - TVector3 particle_dir(track.px(), track.py(), track.pz()); - double deltaEta_jet = particle_dir.Eta() - p_jet.Eta(); - double deltaPhi_jet = GetDeltaPhi(particle_dir.Phi(), p_jet.Phi()); - double deltaR_jet = sqrt(deltaEta_jet * deltaEta_jet + deltaPhi_jet * deltaPhi_jet); - double deltaEta_ue1 = particle_dir.Eta() - ue_axis1.Eta(); - double deltaPhi_ue1 = GetDeltaPhi(particle_dir.Phi(), ue_axis1.Phi()); - double deltaR_ue1 = sqrt(deltaEta_ue1 * deltaEta_ue1 + deltaPhi_ue1 * deltaPhi_ue1); - double deltaEta_ue2 = particle_dir.Eta() - ue_axis2.Eta(); - double deltaPhi_ue2 = GetDeltaPhi(particle_dir.Phi(), ue_axis2.Phi()); - double deltaR_ue2 = sqrt(deltaEta_ue2 * deltaEta_ue2 + deltaPhi_ue2 * deltaPhi_ue2); - - if (deltaR_jet < Rmax) { - registryQC.fill(HIST("deltaEtadeltaPhiJet"), deltaEta_jet, deltaPhi_jet); - registryQC.fill(HIST("rJet"), deltaR_jet); - NchJetPlusUE++; - ptJetPlusUE = ptJetPlusUE + track.pt(); - } - if (deltaR_ue1 < Rmax) { - registryQC.fill(HIST("deltaEtadeltaPhiUE"), deltaEta_ue1, deltaPhi_ue1); - registryQC.fill(HIST("rUE"), deltaR_ue1); - NchUE++; - ptUE = ptUE + track.pt(); - } - if (deltaR_ue2 < Rmax) { - registryQC.fill(HIST("deltaEtadeltaPhiUE"), deltaEta_ue2, deltaPhi_ue2); - registryQC.fill(HIST("rUE"), deltaR_ue2); - NchUE++; - ptUE = ptUE + track.pt(); - } - } - - 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); - - // Fill QA Histograms - if (ptJetPlusUE < min_pt_leading) { - - int nPartClustered_Jet = static_cast(jet_particle_ID.size()); - registryQC.fill(HIST("nParticlesClusteredInJet"), nPartClustered_Jet); - - double dEta = p_leading.Eta() - p_jet.Eta(); - double dPhi = GetDeltaPhi(p_leading.Phi(), p_jet.Phi()); - registryQC.fill(HIST("dEtadPhi_jetaxis_leadTrk"), dEta, dPhi); - - for (int i = 0; i < nPartClustered_Jet; i++) { - - auto track = tracks.iteratorAt(jet_particle_ID[i]); - TVector3 particle_dir(track.px(), track.py(), track.pz()); - double dEta = particle_dir.Eta() - p_jet.Eta(); - double dPhi = GetDeltaPhi(particle_dir.Phi(), p_jet.Phi()); - registryQC.fill(HIST("ptParticlesClusteredInJet"), track.pt()); - registryQC.fill(HIST("dEtadPhi_jetaxis"), dEta, dPhi); - } - } - - // Event Counter: Skip Events with n. particles in jet less than given value - if (NchJetPlusUE < min_nPartInJet) - return; - registryData.fill(HIST("number_of_events_data"), 6.5); - - // Event Counter: Skip Events with Jet Pt lower than threshold - if (ptJet < min_jet_pt) - return; - registryData.fill(HIST("number_of_events_data"), 7.5); - - // Loop over Reconstructed Tracks - for (auto track : tracks) { - - if (!passedTrackSelection(track)) - continue; - if (require_PV_contributor && !(track.isPVContributor())) - continue; - if (track.sign() > 0) - 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(); - double y_proton = get_rapidity(track.px(), track.py(), track.pz(), 0.93827208816); - double y_deuteron = get_rapidity(track.px(), track.py(), track.pz(), 1.87561294257); - double y_helium3 = get_rapidity(2.0 * track.px(), 2.0 * track.py(), 2.0 * track.pz(), 2.80839160743); - - TVector3 particle_dir(track.px(), track.py(), track.pz()); - double deltaEta_jet = particle_dir.Eta() - p_jet.Eta(); - double deltaPhi_jet = GetDeltaPhi(particle_dir.Phi(), p_jet.Phi()); - double deltaR_jet = sqrt(deltaEta_jet * deltaEta_jet + deltaPhi_jet * deltaPhi_jet); - double deltaEta_ue1 = particle_dir.Eta() - ue_axis1.Eta(); - double deltaPhi_ue1 = GetDeltaPhi(particle_dir.Phi(), ue_axis1.Phi()); - double deltaR_ue1 = sqrt(deltaEta_ue1 * deltaEta_ue1 + deltaPhi_ue1 * deltaPhi_ue1); - double deltaEta_ue2 = particle_dir.Eta() - ue_axis2.Eta(); - double deltaPhi_ue2 = GetDeltaPhi(particle_dir.Phi(), ue_axis2.Phi()); - double deltaR_ue2 = sqrt(deltaEta_ue2 * deltaEta_ue2 + deltaPhi_ue2 * deltaPhi_ue2); - - // DCAxy Distributions of Antiprotons - if (isHighPurityAntiproton(track) && TMath::Abs(dcaz) < max_dcaz) { - if (deltaR_jet < Rmax) { - registryData.fill(HIST("antiproton_dca_jet"), pt, dcaxy); - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryData.fill(HIST("antiproton_dca_ue"), pt, dcaxy); - } - } - - // DCA Cuts - if (TMath::Abs(dcaxy) > max_dcaxy) - continue; - if (TMath::Abs(dcaz) > max_dcaz) - continue; - - // Jet - if (deltaR_jet < Rmax) { - - // Antiproton - if (y_proton > min_y && y_proton < max_y) { - if (pt < 1.0) - registryData.fill(HIST("antiproton_jet_tpc"), pt, nsigmaTPCPr); - if (pt >= 0.5 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC && track.hasTOF()) - registryData.fill(HIST("antiproton_jet_tof"), pt, nsigmaTOFPr); - } - - // Antideuteron - if (y_deuteron > min_y && y_deuteron < max_y) { - if (pt < 1.0) - registryData.fill(HIST("antideuteron_jet_tpc"), pt, nsigmaTPCDe); - if (pt >= 0.5 && nsigmaTPCDe > min_nsigmaTPC && nsigmaTPCDe < max_nsigmaTPC && track.hasTOF()) - registryData.fill(HIST("antideuteron_jet_tof"), pt, nsigmaTOFDe); - } - - // Antihelium3 - if (y_helium3 > min_y && y_helium3 < max_y) { - registryData.fill(HIST("antihelium3_jet_tpc"), 2.0 * pt, nsigmaTPCHe); - } - } - - // UE - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - - // Antiproton - if (y_proton > min_y && y_proton < max_y) { - if (pt < 1.0) - registryData.fill(HIST("antiproton_ue_tpc"), pt, nsigmaTPCPr); - if (pt >= 0.5 && nsigmaTPCPr > min_nsigmaTPC && nsigmaTPCPr < max_nsigmaTPC && track.hasTOF()) - registryData.fill(HIST("antiproton_ue_tof"), pt, nsigmaTOFPr); - } - - // Antideuteron - if (y_deuteron > min_y && y_deuteron < max_y) { - if (pt < 1.0) - registryData.fill(HIST("antideuteron_ue_tpc"), pt, nsigmaTPCDe); - if (pt >= 0.5 && nsigmaTPCDe > min_nsigmaTPC && nsigmaTPCDe < max_nsigmaTPC && track.hasTOF()) - registryData.fill(HIST("antideuteron_ue_tof"), pt, nsigmaTOFDe); - } - - // Antihelium3 - if (y_helium3 > min_y && y_helium3 < max_y) { - registryData.fill(HIST("antihelium3_ue_tpc"), 2.0 * pt, nsigmaTPCHe); - } - } - } - } - - Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; - Preslice perCollision = o2::aod::track::collisionId; - - void processMC(o2::aod::McCollisions const& mcCollisions, SimCollisions const& collisions, MCTracks const& mcTracks, aod::McParticles const& mcParticles) - { - // Generated Events - for (const auto& mccollision : mcCollisions) { - - registryMC.fill(HIST("number_of_events_mc"), 0.5); - auto mcParticles_per_coll = mcParticles.sliceBy(perMCCollision, mccollision.globalIndex()); - - 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; - - if (particle.pdgCode() == -2212) { - registryMC.fill(HIST("antiproton_jet_gen"), particle.pt()); - registryMC.fill(HIST("antiproton_ue_gen"), particle.pt()); - } - if (particle.pdgCode() == -1000010020) { - registryMC.fill(HIST("antideuteron_jet_gen"), particle.pt()); - registryMC.fill(HIST("antideuteron_ue_gen"), particle.pt()); - } - if (particle.pdgCode() == -1000020030) { - registryMC.fill(HIST("antihelium3_jet_gen"), particle.pt()); - registryMC.fill(HIST("antihelium3_ue_gen"), particle.pt()); - } - } - } - - // Reconstructed Events - for (const auto& collision : collisions) { - - registryMC.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) - registryMC.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; - - // Track Selection - if (!passedTrackSelection(track)) - continue; - if (require_PV_contributor && !(track.isPVContributor())) - continue; - - // 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); - registryMC.fill(HIST("antiproton_ue_rec_tpc"), pt); - } - 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); - registryMC.fill(HIST("antiproton_ue_rec_tof"), pt); - } - } - - // Antideuteron - if (particle.pdgCode() == -1000010020) { - if (pt < 1.0 && nsigmaTPCDe > min_nsigmaTPC && nsigmaTPCDe < max_nsigmaTPC) { - registryMC.fill(HIST("antideuteron_jet_rec_tpc"), pt); - registryMC.fill(HIST("antideuteron_ue_rec_tpc"), pt); - } - 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); - registryMC.fill(HIST("antideuteron_ue_rec_tof"), pt); - } - } - - // Antihelium-3 - if (particle.pdgCode() == -1000020030) { - if (nsigmaTPCHe > min_nsigmaTPC && nsigmaTPCHe < max_nsigmaTPC) { - registryMC.fill(HIST("antihelium3_jet_rec_tpc"), 2.0 * pt); - registryMC.fill(HIST("antihelium3_ue_rec_tpc"), 2.0 * pt); - } - } - } - } - } - - void processSecAntiprotons(SimCollisions const& collisions, MCTracks const& mcTracks, aod::McCollisions const&, const aod::McParticles&) - { - for (const auto& collision : collisions) { - - // Event Selection - if (!collision.sel8()) - continue; - - if (abs(collision.posZ()) > zVtx) - continue; - - auto tracks_per_coll = mcTracks.sliceBy(perCollision, collision.globalIndex()); - - // Reduced Event - std::vector particle_ID; - 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(); - } - particle_ID.push_back(i); - } - if (pt_max < min_pt_leading) - continue; - - // Momentum of the Leading Particle - auto const& leading_track = tracks_per_coll.iteratorAt(leading_ID); - TVector3 p_jet(leading_track.px(), leading_track.py(), leading_track.pz()); - - // Labels - int exit(0); - int nPartAssociated(0); - int nParticles = static_cast(particle_ID.size()); - std::vector jet_particle_ID; - jet_particle_ID.push_back(leading_ID); - - // Jet Finder - do { - // Initialization - double distance_jet_min(1e+08); - double 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_per_coll.iteratorAt(particle_ID[i]); - TVector3 p_particle(stored_track.px(), stored_track.py(), stored_track.pz()); - - // Variables - double one_over_pt2_part = 1.0 / (p_particle.Pt() * p_particle.Pt()); - double one_over_pt2_lead = 1.0 / (p_jet.Pt() * p_jet.Pt()); - double deltaEta = p_particle.Eta() - p_jet.Eta(); - double deltaPhi = GetDeltaPhi(p_particle.Phi(), p_jet.Phi()); - double min = Minimum(one_over_pt2_part, one_over_pt2_lead); - double Delta2 = deltaEta * deltaEta + deltaPhi * deltaPhi; - - // Distances - double distance_jet = min * Delta2 / (Rjet * Rjet); - double 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_per_coll.iteratorAt(label_jet_particle); - TVector3 p_i(jet_track.px(), jet_track.py(), jet_track.pz()); - p_jet = p_jet + 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); - - // Event Counter: Skip Events with jet not fully inside acceptance - if ((TMath::Abs(p_jet.Eta()) + Rmax) > max_eta) - continue; - - // 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_axis(p_jet, ue_axis1, +1.0); - get_perpendicular_axis(p_jet, ue_axis2, -1.0); - - // Protection against delta<0 - if (ue_axis1.Mag() == 0 || ue_axis2.Mag() == 0) - continue; - - double NchJetPlusUE(0); - // double NchJet(0); - // double NchUE(0); - double ptJetPlusUE(0); - double ptJet(0); - double ptUE(0); - - for (int i = 0; i < nParticles; i++) { - - auto track = tracks_per_coll.iteratorAt(particle_ID[i]); - - TVector3 particle_dir(track.px(), track.py(), track.pz()); - double deltaEta_jet = particle_dir.Eta() - p_jet.Eta(); - double deltaPhi_jet = GetDeltaPhi(particle_dir.Phi(), p_jet.Phi()); - double deltaR_jet = sqrt(deltaEta_jet * deltaEta_jet + deltaPhi_jet * deltaPhi_jet); - double deltaEta_ue1 = particle_dir.Eta() - ue_axis1.Eta(); - double deltaPhi_ue1 = GetDeltaPhi(particle_dir.Phi(), ue_axis1.Phi()); - double deltaR_ue1 = sqrt(deltaEta_ue1 * deltaEta_ue1 + deltaPhi_ue1 * deltaPhi_ue1); - double deltaEta_ue2 = particle_dir.Eta() - ue_axis2.Eta(); - double deltaPhi_ue2 = GetDeltaPhi(particle_dir.Phi(), ue_axis2.Phi()); - double deltaR_ue2 = sqrt(deltaEta_ue2 * deltaEta_ue2 + deltaPhi_ue2 * deltaPhi_ue2); - - if (deltaR_jet < Rmax) { - NchJetPlusUE++; - ptJetPlusUE = ptJetPlusUE + track.pt(); - } - if (deltaR_ue1 < Rmax) { - // NchUE++; - ptUE = ptUE + track.pt(); - } - if (deltaR_ue2 < Rmax) { - // NchUE++; - ptUE = ptUE + track.pt(); - } - } - - // NchJet = NchJetPlusUE - 0.5 * NchUE; - ptJet = ptJetPlusUE - 0.5 * ptUE; - - // Skip Events with n. particles in jet less than given value - if (NchJetPlusUE < min_nPartInJet) - continue; - - // Skip Events with Jet Pt lower than threshold - if (ptJet < min_jet_pt) - continue; - - for (auto track : tracks_per_coll) { - - if (!passedTrackSelection(track)) - continue; - if (require_PV_contributor && !(track.isPVContributor())) - continue; - if (TMath::Abs(track.dcaXY()) > max_dcaxy) - continue; - if (TMath::Abs(track.dcaZ()) > max_dcaz) - continue; - - // Get MC Particle - if (!track.has_mcParticle()) - continue; - const auto particle = track.mcParticle(); - if (particle.pdgCode() != -2212) - continue; - - TVector3 particle_dir(track.px(), track.py(), track.pz()); - float deltaEta_jet = particle_dir.Eta() - p_jet.Eta(); - float deltaPhi_jet = GetDeltaPhi(particle_dir.Phi(), p_jet.Phi()); - float deltaR_jet = sqrt(deltaEta_jet * deltaEta_jet + deltaPhi_jet * deltaPhi_jet); - float deltaEta_ue1 = particle_dir.Eta() - ue_axis1.Eta(); - float deltaPhi_ue1 = GetDeltaPhi(particle_dir.Phi(), ue_axis1.Phi()); - float deltaR_ue1 = sqrt(deltaEta_ue1 * deltaEta_ue1 + deltaPhi_ue1 * deltaPhi_ue1); - float deltaEta_ue2 = particle_dir.Eta() - ue_axis2.Eta(); - float deltaPhi_ue2 = GetDeltaPhi(particle_dir.Phi(), ue_axis2.Phi()); - float deltaR_ue2 = sqrt(deltaEta_ue2 * deltaEta_ue2 + deltaPhi_ue2 * deltaPhi_ue2); - - // Inclusive antiprotons - registryMC.fill(HIST("antiproton_incl"), track.pt()); - - if (deltaR_jet < Rmax) { - registryMC.fill(HIST("antiproton_all_jet"), track.pt()); - if (particle.isPhysicalPrimary()) { - registryMC.fill(HIST("antiproton_prim_jet"), track.pt()); - registryMC.fill(HIST("antiproton_jet"), track.pt()); - } - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryMC.fill(HIST("antiproton_all_ue"), track.pt()); - if (particle.isPhysicalPrimary()) { - registryMC.fill(HIST("antiproton_prim_ue"), track.pt()); - registryMC.fill(HIST("antiproton_ue"), track.pt()); - } - } - } - } - } - PROCESS_SWITCH(nuclei_in_jets, processData, "Process Data", true); - PROCESS_SWITCH(nuclei_in_jets, processMC, "process MC", false); - PROCESS_SWITCH(nuclei_in_jets, processSecAntiprotons, "Process sec antip", 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..71eece23cd8 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/nuclei_in_toward_transv_regions.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. +/// +/// \author Alberto Caliva (alberto.caliva@cern.ch) +/// \since August 22, 2024 + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/PID.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +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/nucleitpcpbpb.cxx b/PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx new file mode 100644 index 00000000000..e2a68cf189e --- /dev/null +++ b/PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx @@ -0,0 +1,1328 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file nucleitpcpbpb.cxx +/// \brief nuclei analysis +/// \note under work +/// +/// \author Jaideep Tanwar , Panjab University + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/TPCPIDResponse.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include + +#include +#include +#include +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using CollisionsFull = soa::Join; +using TracksFull = soa::Join; +using CollisionsFullMC = soa::Join; +//--------------------------------------------------------------------------------------------------------------------------------- +namespace +{ +static const int nParticles = 6; +static const std::vector particleNames{"pion", "proton", "deuteron", "triton", "helion", "alpha"}; +static const std::vector correctedparticleNames{"helion", "antihelion", "alpha", "antialpha"}; +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; +std::vector hfMothCodes = {511, 521, 531, 541, 5122}; // b-mesons + Lambda_b +static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +constexpr double kBetheBlochDefault[nParticles][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 = 13; +static const std::vector trackPIDsettingsNames{"useBBparams", "minITSnCls", "minITSnClscos", "minTPCnCls", "maxTPCchi2", "minTPCchi2", "maxITSchi2", "maxTPCnSigma", "maxDcaXY", "maxDcaZ", "minITSclsSize", "minTPCnClsCrossedRows", "minReqClusterITSib"}; +constexpr double kTrackPIDSettings[nParticles][nTrkSettings]{ + {0, 0, 4, 60, 4.0, 0.5, 100, 2.5, 2., 2., 0., 70, 1}, + {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, + {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, + {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, + {1, 0, 4, 75, 4.0, 0.5, 100, 5.0, 2., 2., 0., 70, 1}, + {1, 0, 4, 70, 4.0, 0.5, 100, 5.0, 2., 2., 0., 70, 1}}; + +const int nTrkSettings2 = 6; +static const std::vector trackPIDsettingsNames2{"useITSnsigma", "minITSnsigma", "maxITSnsigma", "fillsparsh", "useTPCnsigmaTOF", "maxTPCnsigmaTOF"}; +constexpr double kTrackPIDSettings2[nParticles][nTrkSettings2]{ + {1, -5, 4, 0, 1, 2}, + {1, -5, 4, 0, 1, 2}, + {1, -5, 4, 0, 1, 2}, + {1, -5, 4, 1, 1, 2}, + {1, -5, 4, 1, 1, 2}, + {1, -5, 4, 1, 1, 2}}; + +static const int nfittingparticle = 4; +const int nfittingparameters = 4; +static const std::vector trackcorrectionNames{"correctionneed", "a", "b", "c"}; +constexpr double ktrackcorrection[nfittingparticle][nfittingparameters]{ + {1, 0.464215, 0.195771, 0.0183111}, // He3 + {1, 0.464215, 0.195771, 0.0183111}, // anti-He3 + {1, 0.00765, 0.503791, -1.10517}, // He4 + {1, 0.00765, 0.503791, -1.10517}}; // anti-He4 + +struct PrimParticles { + TString name; + int pdgCode, charge; + double mass, resolution; + std::vector betheParams; + bool active; + PrimParticles(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(); + constexpr unsigned int kNSpecies = 5; + for (unsigned int i = 0; i < kNSpecies; i++) + betheParams.push_back(bethe.get(name, i)); + } +}; // struct PrimParticles +//---------------------------------------------------------------------------------------------------------------- +std::vector> hmass; +std::vector> hmassnsigma; +} // namespace +//---------------------------------------------------------------------------------------------------------------- +struct NucleitpcPbPb { + + Preslice tracksPerCollision = aod::track::collisionId; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histomc{"histomc", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + Configurable cfgDebug{"cfgDebug", 1, "debug level"}; + // event Selections cuts + 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 cfgRigidityCorrection{"cfgRigidityCorrection", false, "apply rigidity correction"}; + // Track Selection Cuts + Configurable cfgetaRequire{"cfgetaRequire", true, "eta cut require"}; + Configurable cfgetaRequireMC{"cfgetaRequireMC", true, "eta cut require for generated particles"}; + Configurable cfgRapidityRequireMC{"cfgRapidityRequireMC", true, "rapidity cut require for generated particles"}; + Configurable cfgUsePVcontributors{"cfgUsePVcontributors", true, "use tracks that are PV contibutors"}; + Configurable cfgITSrequire{"cfgITSrequire", true, "Additional cut on ITS require"}; + Configurable cfgTPCrequire{"cfgTPCrequire", true, "Additional cut on TPC require"}; + Configurable cfgPassedITSRefit{"cfgPassedITSRefit", true, "Require ITS refit"}; + Configurable cfgPassedTPCRefit{"cfgPassedTPCRefit", true, "Require TPC refit"}; + Configurable cfgRapidityRequire{"cfgRapidityRequire", true, "Require Rapidity cut"}; + Configurable cfgTPCNClsfoundRequire{"cfgTPCNClsfoundRequire", true, "Require TPCNClsfound Cut"}; + Configurable cfgTPCNClsCrossedRowsRequire{"cfgTPCNClsCrossedRowsRequire", true, "Require TPCNClsCrossedRows Cut"}; + Configurable cfgmaxTPCchi2Require{"cfgmaxTPCchi2Require", true, "Require maxTPCchi2 Cut"}; + Configurable cfgminTPCchi2Require{"cfgminTPCchi2Require", true, "Require minTPCchi2 Cut"}; + Configurable cfgminITSnClsRequire{"cfgminITSnClsRequire", false, "Require minITSnCls Cut"}; + Configurable cfgmccorrectionhe4Require{"cfgmccorrectionhe4Require", true, "MC correction for pp he4 particle"}; + Configurable cfgminITSnClscosRequire{"cfgminITSnClscosRequire", true, "Require minITSnCls / cosh(eta) Cut"}; + Configurable cfgminReqClusterITSibRequire{"cfgminReqClusterITSibRequire", true, " Require min number of clusters required in ITS inner barrel"}; + Configurable cfgmaxITSchi2Require{"cfgmaxITSchi2Require", true, "Require maxITSchi2 Cut"}; + Configurable cfgmaxTPCnSigmaRequire{"cfgmaxTPCnSigmaRequire", true, "Require maxTPCnSigma Cut"}; + Configurable cfgminGetMeanItsClsSizeRequire{"cfgminGetMeanItsClsSizeRequire", true, "Require minGetMeanItsClsSize Cut"}; + Configurable cfgmaxGetMeanItsClsSizeRequire{"cfgmaxGetMeanItsClsSizeRequire", true, "Require maxGetMeanItsClsSize Cut"}; + Configurable cfgRequirebetaplot{"cfgRequirebetaplot", true, "Require beta plot"}; + Configurable cfgdcaxynopt{"cfgdcaxynopt", true, "DCA xy cut without pT dependent"}; + Configurable cfgdcaznopt{"cfgdcaznopt", false, "DCA xy cut without pT dependent"}; + Configurable cfgmass2{"cfgmass2", true, "Fill mass square difference"}; + + Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {kBetheBlochDefault[0], nParticles, nBetheParams, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; + Configurable> cfgTrackPIDsettings{"cfgTrackPIDsettings", {kTrackPIDSettings[0], nParticles, nTrkSettings, particleNames, trackPIDsettingsNames}, "track selection and PID criteria"}; + Configurable> cfgTrackPIDsettings2{"cfgTrackPIDsettings2", {kTrackPIDSettings2[0], nParticles, nTrkSettings2, particleNames, trackPIDsettingsNames2}, "track selection and PID criteria"}; + Configurable> cfgktrackcorrection{"cfgktrackcorrection", {ktrackcorrection[0], nfittingparticle, nfittingparameters, correctedparticleNames, trackcorrectionNames}, "fitting paramters"}; + Configurable cfgFillhspectra{"cfgFillhspectra", true, "fill data sparsh"}; + Configurable cfgFillmass{"cfgFillmass", false, "Fill mass histograms"}; + Configurable cfgFillmassnsigma{"cfgFillmassnsigma", true, "Fill mass vs nsigma histograms"}; + Configurable centcut{"centcut", 80.0f, "centrality cut"}; + Configurable cfgCutEta{"cfgCutEta", 0.9f, "Eta range for tracks"}; + Configurable cfgCutRapidity{"cfgCutRapidity", 0.5f, "Rapidity range"}; + Configurable cfgtpcNClsFindable{"cfgtpcNClsFindable", 0.8f, "tpcNClsFindable over crossedRows"}; + Configurable cfgZvertex{"cfgZvertex", 10, "Min Z Vertex"}; + Configurable cfgZvertexRequireMC{"cfgZvertexRequireMC", true, "Pos Z cut in MC"}; + Configurable cfgsel8Require{"cfgsel8Require", true, "sel8 cut require"}; + Configurable cfgminmassrejection{"cfgminmassrejection", 6.5, "Min side of He3 particle rejection"}; + Configurable cfgmaxmassrejection{"cfgmaxmassrejection", 9.138, "Max side of He3 particle rejection"}; + Configurable correctionsigma{"correctionsigma", 2, "Max sigma value outside which correction is require"}; + Configurable cfghe3massrejreq{"cfghe3massrejreq", true, "Require mass cut on He4 particles"}; + + o2::track::TrackParametrizationWithError mTrackParCov; + // Binning configuration + ConfigurableAxis axisMagField{"axisMagField", {10, -10., 10.}, "magnetic field"}; + ConfigurableAxis axisNev{"axisNev", {10, 0., 10.}, "Number of events"}; + ConfigurableAxis axisRigidity{"axisRigidity", {4000, -10., 10.}, "#it{p}^{TPC}/#it{z}"}; + ConfigurableAxis axisdEdx{"axisdEdx", {4000, 0, 4000}, "d#it{E}/d#it{x}"}; + ConfigurableAxis axisCent{"axisCent", {100, 0, 100}, "centrality"}; + ConfigurableAxis axisVtxZ{"axisVtxZ", {120, -20, 20}, "z"}; + + ConfigurableAxis ptAxis{"ptAxis", {200, 0, 10}, "#it{p}_{T} (GeV/#it{c})"}; + + ConfigurableAxis ptAxisa{"ptAxisa", {20, 0, 10}, "#it{p}_{T} (GeV/#it{c})"}; // just check + + ConfigurableAxis axiseta{"axiseta", {100, -1, 1}, "eta"}; + ConfigurableAxis axisrapidity{"axisrapidity", {100, -2, 2}, "rapidity"}; + ConfigurableAxis axismass{"axismass", {100, -10, 10}, "mass"}; + ConfigurableAxis axismassnsigma{"axismassnsigma", {100, 0, 20}, "nsigma mass"}; + ConfigurableAxis nsigmaAxis{"nsigmaAxis", {160, -10, 10}, "n#sigma_{#pi^{+}}"}; + ConfigurableAxis speciesBitAxis{"speciesBitAxis", {8, -0.5, 7.5}, "particle type 0: pion, 1: proton, 2: deuteron, 3: triton, 4:He3, 5:He4"}; + ConfigurableAxis speciesTrackingAxis{"speciesTrackingAxis", {11, -0.5, 10.5}, "particle type 0: pion, 1: proton, 2: deuteron, 3: triton, 4:He3, 5:He4"}; + ConfigurableAxis axisDCA{"axisDCA", {400, -10., 10.}, "DCA axis"}; + ConfigurableAxis particleAntiAxis{"particleAntiAxis", {2, -0.5, 1.5}, "Particle/Anti-particle"}; // 0 = particle, 1 = anti-particle + ConfigurableAxis decayTypeAxis{"decayTypeAxis", {3, -0.5, 2.5}, "Decay type"}; // 0 = primary, 1 = from decay, 2 = material + + // 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; + float he3 = 4; + float he4 = 5; + //---------------------------------------------------------------------------------------------------------------- + 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 < nParticles; i++) { // create primaryParticles + primaryParticles.push_back(PrimParticles(particleNames.at(i), particlePdgCodes.at(i), particleMasses.at(i), particleCharge.at(i), cfgBetheBlochParams)); + } + // create histograms + if (doprocessData) { + histos.add("histMagField", "histMagField", kTH1F, {axisMagField}); + histos.add("histNev", "histNev", kTH1F, {axisNev}); + histos.add("histVtxZ", "histVtxZ", kTH1F, {axisVtxZ}); + histos.add("histCentFT0C", "histCentFT0C", kTH1F, {axisCent}); + histos.add("histCentFT0M", "histCentFT0M", kTH1F, {axisCent}); + histos.add("histCentFTOC_cut", "histCentFTOC_cut", kTH1F, {axisCent}); + histos.add("hSpectra", " ", HistType::kTHnSparseF, {speciesBitAxis, ptAxis, nsigmaAxis, {5, -2.5, 2.5}, axisCent, axisDCA, axisDCA}); + } + histos.add("histeta", "histeta", kTH1F, {axiseta}); + histos.add("dcaZ", "dcaZ", kTH2F, {ptAxis, axisDCA}); + histos.add("dcaXY", "dcaXY", kTH2F, {ptAxis, axisDCA}); + histos.add("Tofsignal", "Tofsignal", kTH2F, {axisRigidity, {4000, 0.2, 1.2, "#beta"}}); + histos.add("Tpcsignal", "Tpcsignal", kTH2F, {axisRigidity, axisdEdx}); + + hmass.resize(2 * nParticles + 2); + hmassnsigma.resize(2 * nParticles + 2); + + for (int i = 0; i < nParticles; i++) { + TString histName = primaryParticles[i].name; + if (cfgFillmass) { + hmass[2 * i] = histos.add(Form("histmass_pt/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismass, axisCent}); + hmass[2 * i + 1] = histos.add(Form("histmass_ptanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismass, axisCent}); + } + } + for (int i = 0; i < nParticles; i++) { + TString histName = primaryParticles[i].name; + if (cfgFillmassnsigma) { + hmassnsigma[2 * i] = histos.add(Form("histmass_nsigma/histmass_%s", histName.Data()), ";nsigma; mass^{2}", HistType::kTH2F, {nsigmaAxis, axismassnsigma}); + hmassnsigma[2 * i + 1] = histos.add(Form("histmass_nsigmaanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}", HistType::kTH2F, {nsigmaAxis, axismassnsigma}); + } + } + + if (doprocessMC) { + histomc.add("hSpectramc", " ", HistType::kTHnSparseF, {speciesBitAxis, {5, -2.5, 2.5}, axisCent, ptAxis, ptAxis}); + + // Efficiency x Acceptance + histomc.add("hDenomEffAcc", "Denominator for Efficiency x Acceptance", + {HistType::kTHnSparseF, {speciesBitAxis, ptAxis, axisrapidity, axisCent, particleAntiAxis, decayTypeAxis}}); + histomc.add("hNumerEffAcc", "Numerator for Efficiency x Acceptance", + {HistType::kTHnSparseF, {speciesBitAxis, ptAxis, axisrapidity, axisCent, particleAntiAxis, decayTypeAxis}}); + + // The Signal loss correction + histomc.add("hHe3SignalLossDenom", "He3 Signal Loss Denominator", kTH1F, {axisCent}); + histomc.add("hHe3SignalLossNumer", "He3 Signal Loss Numerator", kTH1F, {axisCent}); + histomc.add("hHe4SignalLossDenom", "He4 Signal Loss Denominator", kTH1F, {axisCent}); + histomc.add("hHe4SignalLossNumer", "He4 Signal Loss Numerator", kTH1F, {axisCent}); + + histomc.add("haHe3SignalLossDenom", "He3 Signal Loss Denominator", kTH1F, {axisCent}); + histomc.add("haHe3SignalLossNumer", "He3 Signal Loss Numerator", kTH1F, {axisCent}); + histomc.add("haHe4SignalLossDenom", "He4 Signal Loss Denominator", kTH1F, {axisCent}); + histomc.add("haHe4SignalLossNumer", "He4 Signal Loss Numerator", kTH1F, {axisCent}); + + // The event loss correction + histomc.add("hEventLossDenom", "Event loss denominator", kTH1F, {axisCent}); + histomc.add("hEventLossNumer", "Event loss numerator", kTH1F, {axisCent}); + + histomc.add("histVtxZgen", "histVtxZgen", kTH1F, {axisVtxZ}); + histomc.add("histNevReco", "histNevReco", kTH1F, {axisNev}); + histomc.add("histVtxZReco", "histVtxZReco", kTH1F, {axisVtxZ}); + histomc.add("histCentFT0CReco", "histCentFT0CReco", kTH1F, {axisCent}); + histomc.add("histCentFT0MReco", "histCentFT0MReco", kTH1F, {axisCent}); + + histomc.add("histdetapttriton", " delta pt vs pt rec for trition detected", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); + histomc.add("histdetapttritonanti", " delta pt vs pt rec for trition detected", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); + + histomc.add("histDeltaPtVsPtGen", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); + histomc.add("histDeltaPtVsPtGenanti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); + histomc.add("histDeltaPtVsPtGenHe4", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); + histomc.add("histDeltaPtVsPtGenHe4anti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); + histomc.add("histPIDtrack", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); + histomc.add("histPIDtrackanti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); + histomc.add("histPIDtrackhe4", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); + histomc.add("histPIDtrackantihe4", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); + } + + if (doprocessDCA) { + + histomc.add("hSpectraDCA", " ", HistType::kTHnSparseF, {speciesBitAxis, {5, -2.5, 2.5}, axisCent, ptAxis, ptAxis, decayTypeAxis, axisDCA}); + } + } + //---------------------------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------------------------- + void processData(CollisionsFull const& collisions, + TracksFull const& tracks, + aod::BCsWithTimestamps const&) + { + for (const auto& collision : collisions) { + auto bc = collision.bc_as(); + initCCDB(bc); + initCollision(collision); + + if (!collPassedEvSel) + continue; + if (collision.centFT0C() > centcut) + continue; + if (removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + continue; + histos.fill(HIST("histNev"), 2.5); + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + continue; + histos.fill(HIST("histNev"), 3.5); + + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + histos.fill(HIST("histNev"), 4.5); + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + continue; + + histos.fill(HIST("histNev"), 5.5); + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + continue; + histos.fill(HIST("histNev"), 6.5); + histos.fill(HIST("histCentFTOC_cut"), collision.centFT0C()); + + // new slicing + auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + + // loop over sliced tracks + for (const auto& track : tracksInColl) { + if (!track.isPVContributor() && cfgUsePVcontributors) + continue; + if (!track.hasITS() && cfgITSrequire) + continue; + if (!track.hasTPC() && cfgTPCrequire) + continue; + if (!track.passedITSRefit() && cfgPassedITSRefit) + continue; + if (!track.passedTPCRefit() && cfgPassedTPCRefit) + continue; + if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) + continue; + + for (size_t i = 0; i < primaryParticles.size(); i++) { + float ptMomn; + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + ptMomn = (i == he3 || i == he4) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); + + float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); + if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) + continue; + if (std::abs(tpcNsigma) > correctionsigma) { + double a = 0, b = 0, c = 0; + + int param = -1; + if (i == he3) { + param = (track.sign() > 0) ? 0 : 1; + } else if (i == he4) { + param = (track.sign() > 0) ? 2 : 3; + } + + if (param >= 0) { + a = cfgktrackcorrection->get(param, "a"); + b = cfgktrackcorrection->get(param, "b"); + c = cfgktrackcorrection->get(param, "c"); + } + + if (i == he4 && cfgmccorrectionhe4Require) { + ptMomn = ptMomn + a + b * std::exp(c * ptMomn); + } + + if (i == he3 && cfgmccorrectionhe4Require) { + int pidGuess = track.pidForTracking(); + int antitriton = 6; + if (pidGuess == antitriton) { + ptMomn = ptMomn - a + b * ptMomn - c * ptMomn * ptMomn; + } + } + } + int sign = (track.sign() > 0) ? 1 : ((track.sign() < 0) ? -1 : 0); + + if (std::abs(getRapidity(track, i)) > cfgCutRapidity && cfgRapidityRequire) + continue; + if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls") && cfgTPCNClsfoundRequire) + continue; + if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || + track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && + cfgTPCNClsCrossedRowsRequire) + continue; + if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) + continue; + if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) + continue; + if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) + continue; + + double cosheta = std::cosh(track.eta()); + if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) + continue; + if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) + continue; + if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) + continue; + if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) + continue; + + // DCA XY cut + bool insideDCAxy = cfgdcaxynopt ? (std::abs(track.dcaXY()) <= cfgTrackPIDsettings->get(i, "maxDcaXY")) : (std::abs(track.dcaXY()) <= (cfgTrackPIDsettings->get(i, "maxDcaXY") * (0.0105f + 0.0350f / std::pow(ptMomn, 1.1f)))); + + // DCA Z cut + bool insideDCAz = cfgdcaznopt ? (std::abs(track.dcaZ()) <= cfgTrackPIDsettings->get(i, "maxDcaZ")) : (std::abs(track.dcaZ()) <= dcazSigma(ptMomn, cfgTrackPIDsettings->get(i, "maxDcaZ"))); + + if ((!insideDCAxy || !insideDCAz)) { + continue; + } + + float itsSigma = getITSnSigma(track, primaryParticles.at(i)); + if (itsSigma < cfgTrackPIDsettings2->get(i, "minITSnsigma") && cfgTrackPIDsettings2->get(i, "useITSnsigma") < 1) + continue; + if (itsSigma > cfgTrackPIDsettings2->get(i, "maxITSnsigma") && cfgTrackPIDsettings2->get(i, "useITSnsigma") < 1) + continue; + + histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); + + histos.fill(HIST("dcaXY"), ptMomn, track.dcaXY()); + histos.fill(HIST("dcaZ"), ptMomn, track.dcaZ()); + + if (cfgFillhspectra && cfgTrackPIDsettings2->get(i, "fillsparsh") == 1) { + + if (i != he4) { + histos.fill(HIST("hSpectra"), i, ptMomn, tpcNsigma, sign, collision.centFT0C(), track.dcaZ(), track.dcaXY()); + } else { + if (!track.hasTOF()) { + // Fill without TOF + histos.fill(HIST("hSpectra"), i, ptMomn, tpcNsigma, sign, collision.centFT0C(), track.dcaZ(), track.dcaXY()); + } else { + // Has TOF - apply mass cut + float beta = o2::pid::tof::Beta::GetBeta(track); + const float eps = 1e-6f; + if (beta < eps || beta > 1.0f - eps) + continue; + + float charge = 2.f; // he4 has charge 2 + float p = getRigidity(track); + float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); + + // Apply mass cut for he4 (mass^2 around 3.73^2 = 13.9) + if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) { + continue; // Skip if mass cut fails + } + + histos.fill(HIST("hSpectra"), i, ptMomn, tpcNsigma, sign, collision.centFT0C(), track.dcaZ(), track.dcaXY()); + } + } + } + fillhmassnsigma(track, i, tpcNsigma); + + if ((std::abs(tpcNsigma) > cfgTrackPIDsettings2->get(i, "maxTPCnsigmaTOF")) && cfgTrackPIDsettings2->get(i, "useTPCnsigmaTOF") < 1) + continue; + fillhmass(track, i, collision.centFT0C()); + + if (cfgRequirebetaplot) { + histos.fill(HIST("Tofsignal"), getRigidity(track) * track.sign(), o2::pid::tof::Beta::GetBeta(track)); + } + } // loop primaryParticles + + histos.fill(HIST("histeta"), track.eta()); + } // loop sliced tracks + } // collision loop + } + PROCESS_SWITCH(NucleitpcPbPb, processData, "data analysis", false); + + //---------------------------------------------------------------------------------------------------------------- + // MC particles - Efficiency x Acceptance and Signal Loss calculations + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + struct McCollInfo { + bool passedEvSel = false; + float centrality = -1.0f; + bool passedEvSelVtZ = false; + }; + std::vector mcCollInfos; + + void processMC(CollisionsFullMC const& collisions, + aod::McCollisions const& mcCollisions, + soa::Join const& tracks, + aod::McParticles const& particlesMC, + aod::BCsWithTimestamps const&) + + { + + mcCollInfos.clear(); + mcCollInfos.resize(mcCollisions.size()); + + // First pass: Store centrality and apply event selection + for (auto const& collision : collisions) { + int mcCollIdx = collision.mcCollisionId(); + if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { + continue; + } + + // STORE CENTRALITY WITHOUt CUTS + mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); + + if (!collision.sel8() && cfgsel8Require) + continue; + if (collision.centFT0C() > centcut) + continue; + + // Additional cuts + if (removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + continue; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + continue; + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + continue; + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + continue; + + // Mark this MC collision as passing event selection + mcCollInfos[mcCollIdx].passedEvSel = true; + + // Apply event selection cuts + if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) + continue; + + mcCollInfos[mcCollIdx].passedEvSelVtZ = true; + } + + // FILL EVENT LOSS AND SIGNAL LOSS: Combined loop per MC collision + for (size_t i = 0; i < mcCollInfos.size(); i++) { + if (mcCollInfos[i].centrality >= 0) { // Only if we found a matching collision + // Event loss denominator + histomc.fill(HIST("hEventLossDenom"), mcCollInfos[i].centrality); + + // Event loss numerator (if passed selection) + if (mcCollInfos[i].passedEvSel) { + histomc.fill(HIST("hEventLossNumer"), mcCollInfos[i].centrality); + } + + // Fill signal loss for all primary particles in this MC collision + for (auto const& mcParticle : particlesMC) { + if (mcParticle.mcCollisionId() != static_cast(i)) { + continue; + } + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + // Signal loss denominator + if (mcParticle.pdgCode() == particlePdgCodes.at(4)) { // He3 + histomc.fill(HIST("hHe3SignalLossDenom"), mcCollInfos[i].centrality); + + } else if (mcParticle.pdgCode() == particlePdgCodes.at(5)) { // He4 + histomc.fill(HIST("hHe4SignalLossDenom"), mcCollInfos[i].centrality); + } else if (mcParticle.pdgCode() == -particlePdgCodes.at(4)) { // anti-He3 + histomc.fill(HIST("haHe3SignalLossDenom"), mcCollInfos[i].centrality); + + } else if (mcParticle.pdgCode() == -particlePdgCodes.at(5)) { // He4 + histomc.fill(HIST("haHe4SignalLossDenom"), mcCollInfos[i].centrality); + } + + // Signal loss numerator (if event passed selection) + if (mcCollInfos[i].passedEvSel) { + if (mcParticle.pdgCode() == particlePdgCodes.at(4)) { // He3 + histomc.fill(HIST("hHe3SignalLossNumer"), mcCollInfos[i].centrality); + } else if (mcParticle.pdgCode() == particlePdgCodes.at(5)) { // He4 + histomc.fill(HIST("hHe4SignalLossNumer"), mcCollInfos[i].centrality); + } else if (mcParticle.pdgCode() == -particlePdgCodes.at(4)) { // anti-He3 + histomc.fill(HIST("haHe3SignalLossNumer"), mcCollInfos[i].centrality); + } else if (mcParticle.pdgCode() == -particlePdgCodes.at(5)) { // anti-He4 + histomc.fill(HIST("haHe4SignalLossNumer"), mcCollInfos[i].centrality); + } + } + } + } + } + + // Process MC collisions for efficiency and reconstructed collisions + for (auto const& mcCollision : mcCollisions) { + size_t idx = mcCollision.globalIndex(); + if (idx >= mcCollInfos.size()) + continue; + + float centrality = mcCollInfos[idx].centrality; + // bool passedEvSel = mcCollInfos[idx].passedEvSel; + bool passedEvSelVtZ = mcCollInfos[idx].passedEvSelVtZ; + + // Process generated particles for efficiency denominators + histomc.fill(HIST("histVtxZgen"), mcCollision.posZ()); + + for (auto const& mcParticle : particlesMC) { + if (mcParticle.mcCollisionId() != mcCollision.globalIndex()) + continue; + + int pdgCode = mcParticle.pdgCode(); + bool isHe3 = (std::abs(pdgCode) == particlePdgCodes.at(4)); + bool isHe4 = (std::abs(pdgCode) == particlePdgCodes.at(5)); + + if (!isHe3 && !isHe4) + continue; + + if (std::abs(mcParticle.eta()) > cfgCutEta && cfgetaRequireMC) + continue; + if (std::abs(mcParticle.y()) > cfgCutRapidity && cfgRapidityRequireMC) + continue; + + int decayType = 0; + int particleAnti = (pdgCode > 0) ? 0 : 1; + + if (mcParticle.isPhysicalPrimary()) { + decayType = 0; + if (mcParticle.has_mothers()) { + for (const auto& motherparticle : mcParticle.mothers_as()) { + if (std::find(hfMothCodes.begin(), hfMothCodes.end(), + std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { + decayType = 1; + break; + } + } + } + } else if (mcParticle.has_mothers()) { + decayType = 1; + } else { + decayType = 2; + continue; + } + bool isFromWeakDecay = (decayType == 1); + + if (!mcParticle.isPhysicalPrimary() && !isFromWeakDecay) + // if (!mcParticle.isPhysicalPrimary()) + continue; + + int particleType = -1; + if (std::abs(pdgCode) == particlePdgCodes.at(4)) + particleType = he3; + else if (std::abs(pdgCode) == particlePdgCodes.at(5)) + particleType = he4; + + if (particleType >= 0) { + + // Efficiency x Acceptance histograms + if (passedEvSelVtZ) { + histomc.fill(HIST("hDenomEffAcc"), particleType, mcParticle.pt(), mcParticle.y(), centrality, particleAnti, decayType); + } + } + } + + // Process reconstructed collisions for this MC collision + if (passedEvSelVtZ) { + // Find the corresponding reconstructed collision + for (auto const& collision : collisions) { + if (collision.mcCollisionId() != static_cast(idx)) + continue; + + auto bc = collision.bc_as(); + initCCDB(bc); + + histomc.fill(HIST("histNevReco"), 0.5); + histomc.fill(HIST("histVtxZReco"), collision.posZ()); + histomc.fill(HIST("histCentFT0CReco"), collision.centFT0C()); + histomc.fill(HIST("histCentFT0MReco"), collision.centFT0M()); + + auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + + for (auto const& track : tracksInColl) { + if (!track.has_mcParticle()) + continue; // skip un-matched reco tracks + + auto const& matchedMCParticle = track.mcParticle_as(); + + // Only process particles from this MC collision + if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) + continue; + + int pdg = matchedMCParticle.pdgCode(); + bool isHe3 = (std::abs(pdg) == particlePdgCodes.at(4)); + bool isHe4 = (std::abs(pdg) == particlePdgCodes.at(5)); + + if (!isHe3 && !isHe4) + continue; + + int decayType = 0; + bool isFromWeakDecay = false; + + if (matchedMCParticle.isPhysicalPrimary()) { + decayType = 0; + if (matchedMCParticle.has_mothers()) { + for (const auto& motherparticle : matchedMCParticle.mothers_as()) { + if (std::find(hfMothCodes.begin(), hfMothCodes.end(), + std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { + isFromWeakDecay = true; + decayType = 1; + break; + } + } + } + } else if (matchedMCParticle.has_mothers()) { + isFromWeakDecay = true; + decayType = 1; + } else { + decayType = 2; + } + + if (!track.isPVContributor() && cfgUsePVcontributors) + continue; + if (!track.hasITS() && cfgITSrequire) + continue; + if (!track.hasTPC() && cfgTPCrequire) + continue; + if (!track.passedITSRefit() && cfgPassedITSRefit) + continue; + if (!track.passedTPCRefit() && cfgPassedTPCRefit) + continue; + if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) + continue; + if (!matchedMCParticle.isPhysicalPrimary() && isFromWeakDecay) + continue; + + for (size_t i = 0; i < primaryParticles.size(); i++) { + if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) + continue; + + float ptReco; + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + + ptReco = (std::abs(pdg) == particlePdgCodes.at(4) || std::abs(pdg) == particlePdgCodes.at(5)) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); + + int particleAnti = (pdg > 0) ? 0 : 1; + + double a = 0, b = 0, c = 0; + + int param = -1; + if (i == he3) { + param = (-particlePdgCodes.at(4) > 0) ? 0 : 1; + } else if (i == he4) { + param = (-particlePdgCodes.at(4) > 0) ? 2 : 3; + } + + if (param >= 0) { + a = cfgktrackcorrection->get(param, "a"); + b = cfgktrackcorrection->get(param, "b"); + c = cfgktrackcorrection->get(param, "c"); + } + + if (std::abs(pdg) == particlePdgCodes.at(5) && cfgmccorrectionhe4Require) { + ptReco = ptReco + a + b * std::exp(c * ptReco); + } + + if (std::abs(pdg) == particlePdgCodes.at(4) && cfgmccorrectionhe4Require) { + int pidGuess = track.pidForTracking(); + int antitriton = 6; + if (pidGuess == antitriton) { + ptReco = ptReco - a + b * ptReco - c * ptReco * ptReco; + } + } + + if (std::abs(getRapidity(track, i)) > cfgCutRapidity && cfgRapidityRequire) + continue; + + if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls") && cfgTPCNClsfoundRequire) + continue; + if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && cfgTPCNClsCrossedRowsRequire) + continue; + if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) + continue; + if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) + continue; + if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) + continue; + double cosheta = std::cosh(track.eta()); + if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) + continue; + if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) + continue; + if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) + continue; + if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) + continue; + + // DCA XY cut + bool insideDCAxy = cfgdcaxynopt ? (std::abs(track.dcaXY()) <= cfgTrackPIDsettings->get(i, "maxDcaXY")) : (std::abs(track.dcaXY()) <= (cfgTrackPIDsettings->get(i, "maxDcaXY") * (0.0105f + 0.0350f / std::pow(ptReco, 1.1f)))); + + // DCA Z cut + bool insideDCAz = cfgdcaznopt ? (std::abs(track.dcaZ()) <= cfgTrackPIDsettings->get(i, "maxDcaZ")) : (std::abs(track.dcaZ()) <= dcazSigma(ptReco, cfgTrackPIDsettings->get(i, "maxDcaZ"))); + + if ((!insideDCAxy || !insideDCAz)) { + continue; + } + + float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); + if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) + continue; + + if (i == he3 || i == he4) { + histomc.fill(HIST("hNumerEffAcc"), i, ptReco, getRapidity(track, i), collision.centFT0C(), particleAnti, decayType); + } + + float ptTOF = -1.0; // Default: no TOF + if (track.hasTOF()) { + ptTOF = ptReco; + } + + if (cfgTrackPIDsettings2->get(i, "fillsparsh") == 1) { + histomc.fill(HIST("hSpectramc"), i, particleAnti, collision.centFT0C(), + ptReco, ptTOF); + } + + fillhmassnsigma(track, i, tpcNsigma); + histos.fill(HIST("dcaXY"), ptReco, track.dcaXY()); + histos.fill(HIST("dcaZ"), ptReco, track.dcaZ()); + + histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); + + // Fill the requested histograms + float ptGen = matchedMCParticle.pt(); + float deltaPt = ptReco - ptGen; + + if (pdg == -particlePdgCodes.at(4)) { + histomc.fill(HIST("histDeltaPtVsPtGenanti"), ptReco, deltaPt); + histomc.fill(HIST("histPIDtrackanti"), ptReco, track.pidForTracking()); + + int pidGuess = track.pidForTracking(); + int antitriton = 6; + if (pidGuess == antitriton) { + histomc.fill(HIST("histdetapttritonanti"), ptReco, deltaPt); + } + } + if (pdg == particlePdgCodes.at(4)) { + histomc.fill(HIST("histDeltaPtVsPtGen"), ptReco, deltaPt); + histomc.fill(HIST("histPIDtrack"), ptReco, track.pidForTracking()); + + int pidGuess = track.pidForTracking(); + int antitriton = 6; + if (pidGuess == antitriton) { + histomc.fill(HIST("histdetapttriton"), ptReco, deltaPt); + } + } + if (pdg == -particlePdgCodes.at(5)) { + histomc.fill(HIST("histDeltaPtVsPtGenHe4anti"), ptReco, deltaPt); + histomc.fill(HIST("histPIDtrackantihe4"), ptReco, track.pidForTracking()); + } + if (pdg == particlePdgCodes.at(5)) { + histomc.fill(HIST("histDeltaPtVsPtGenHe4"), ptReco, deltaPt); + histomc.fill(HIST("histPIDtrackhe4"), ptReco, track.pidForTracking()); + } + } + } + break; // Found the matching collision, break out of collision loop + } + } + } + } + PROCESS_SWITCH(NucleitpcPbPb, processMC, "MC reco+gen analysis with efficiency corrections", false); + //=-=-=-==-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + //---------------------------------------------------------------------------------------------------------------- + // MC particles - DCA secondary fraction + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + void processDCA(CollisionsFullMC const& collisions, + aod::McCollisions const& mcCollisions, + aod::McParticles const& particlesMC, + soa::Join const& tracks, + aod::BCsWithTimestamps const&) + + { + (void)particlesMC; + mcCollInfos.clear(); + mcCollInfos.resize(mcCollisions.size()); + + // First pass: Store centrality and apply event selection + for (auto const& collision : collisions) { + int mcCollIdx = collision.mcCollisionId(); + if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { + continue; + } + + // STORE CENTRALITY WITHOUt CUTS + mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); + + if (!collision.sel8() && cfgsel8Require) + continue; + if (collision.centFT0C() > centcut) + continue; + + // Additional cuts + if (removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + continue; + if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + continue; + if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) + continue; + if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + continue; + + // Mark this MC collision as passing event selection + mcCollInfos[mcCollIdx].passedEvSel = true; + + // Apply event selection cuts + if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) + continue; + + mcCollInfos[mcCollIdx].passedEvSelVtZ = true; + } + + // Process MC collisions for efficiency and reconstructed collisions + for (auto const& mcCollision : mcCollisions) { + size_t idx = mcCollision.globalIndex(); + if (idx >= mcCollInfos.size()) + continue; + + // bool passedEvSel = mcCollInfos[idx].passedEvSel; + bool passedEvSelVtZ = mcCollInfos[idx].passedEvSelVtZ; + + // Process reconstructed collisions for this MC collision + if (passedEvSelVtZ) { + // Find the corresponding reconstructed collision + for (auto const& collision : collisions) { + if (collision.mcCollisionId() != static_cast(idx)) + continue; + + auto bc = collision.bc_as(); + initCCDB(bc); + auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + + for (auto const& track : tracksInColl) { + if (!track.has_mcParticle()) + continue; // skip un-matched reco tracks + + auto const& matchedMCParticle = track.mcParticle_as(); + + // Only process particles from this MC collision + if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) + continue; + + int pdg = matchedMCParticle.pdgCode(); + bool isHe3 = (std::abs(pdg) == particlePdgCodes.at(4)); + bool isHe4 = (std::abs(pdg) == particlePdgCodes.at(5)); + + if (!isHe3 && !isHe4) + continue; + + if (!track.isPVContributor() && cfgUsePVcontributors) + continue; + if (!track.hasITS() && cfgITSrequire) + continue; + if (!track.hasTPC() && cfgTPCrequire) + continue; + if (!track.passedITSRefit() && cfgPassedITSRefit) + continue; + if (!track.passedTPCRefit() && cfgPassedTPCRefit) + continue; + if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) + continue; + + for (size_t i = 0; i < primaryParticles.size(); i++) { + if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) + continue; + + float ptReco; + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + + ptReco = (std::abs(pdg) == particlePdgCodes.at(4) || std::abs(pdg) == particlePdgCodes.at(5)) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); + + int particleAnti = (pdg > 0) ? 0 : 1; + + double a = 0, b = 0, c = 0; + + int param = -1; + if (i == he3) { + param = (-particlePdgCodes.at(4) > 0) ? 0 : 1; + } else if (i == he4) { + param = (-particlePdgCodes.at(4) > 0) ? 2 : 3; + } + + if (param >= 0) { + a = cfgktrackcorrection->get(param, "a"); + b = cfgktrackcorrection->get(param, "b"); + c = cfgktrackcorrection->get(param, "c"); + } + + if (std::abs(pdg) == particlePdgCodes.at(5) && cfgmccorrectionhe4Require) { + ptReco = ptReco + a + b * std::exp(c * ptReco); + } + + if (std::abs(pdg) == particlePdgCodes.at(4) && cfgmccorrectionhe4Require) { + int pidGuess = track.pidForTracking(); + int antitriton = 6; + if (pidGuess == antitriton) { + ptReco = ptReco - a + b * ptReco - c * ptReco * ptReco; + } + } + + if (std::abs(getRapidity(track, i)) > cfgCutRapidity && cfgRapidityRequire) + continue; + + if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls") && cfgTPCNClsfoundRequire) + continue; + if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && cfgTPCNClsCrossedRowsRequire) + continue; + if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) + continue; + if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) + continue; + if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) + continue; + double cosheta = std::cosh(track.eta()); + if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) + continue; + if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) + continue; + if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) + continue; + if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) + continue; + + // DCA XY cut + bool insideDCAxy = cfgdcaxynopt ? (std::abs(track.dcaXY()) <= cfgTrackPIDsettings->get(i, "maxDcaXY")) : (std::abs(track.dcaXY()) <= (cfgTrackPIDsettings->get(i, "maxDcaXY") * (0.0105f + 0.0350f / std::pow(ptReco, 1.1f)))); + + // DCA Z cut + bool insideDCAz = cfgdcaznopt ? (std::abs(track.dcaZ()) <= cfgTrackPIDsettings->get(i, "maxDcaZ")) : (std::abs(track.dcaZ()) <= dcazSigma(ptReco, cfgTrackPIDsettings->get(i, "maxDcaZ"))); + + if ((!insideDCAxy || !insideDCAz)) { + continue; + } + + float ptTOF = -1.0; // Default: no TOF + if (track.hasTOF()) { + ptTOF = ptReco; + } + + int decayType = 0; // 0 = primary, 1 = weak decay, 2 = material + + bool isProdByGen = false; + isProdByGen = track.mcParticle().producedByGenerator(); + + if (matchedMCParticle.isPhysicalPrimary()) { + // ---- Primary particles ---- + decayType = 0; + + } else if (matchedMCParticle.getProcess() == TMCProcess::kPDecay && !isProdByGen) { + // ---- Secondary from weak decay ---- + decayType = 1; + + } else if (matchedMCParticle.getProcess() == 23) { + // ---- Secondary from material interaction ---- + decayType = 2; + } + + if (cfgTrackPIDsettings2->get(i, "fillsparsh") == 1) { + histomc.fill(HIST("hSpectraDCA"), i, particleAnti, collision.centFT0C(), + ptReco, ptTOF, decayType, track.dcaXY()); + } + + // + } + } + break; // Found the matching collision, break out of collision loop + } + } + } + } + PROCESS_SWITCH(NucleitpcPbPb, processDCA, "MC DCA analysis For secondary correction", false); + //=-=-=-==-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + constexpr float kInvalidBField = -990.f; + 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 < kInvalidBField) { + // 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 < kInvalidBField) { + // 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()) < cfgZvertex; + occupancy = collision.trackOccupancyInTimeRange(); + if (collPassedEvSel) { + histos.fill(HIST("histNev"), 1.5); + histos.fill(HIST("histVtxZ"), collision.posZ()); + histos.fill(HIST("histCentFT0C"), collision.centFT0C()); + histos.fill(HIST("histCentFT0M"), collision.centFT0M()); + } + primVtx.assign({collision.posX(), collision.posY(), collision.posZ()}); + cents.assign({collision.centFT0A(), collision.centFT0C(), collision.centFT0M()}); + } + //---------------------------------------------------------------------------------------------------------------- + template + void fillhmass(T const& track, int species, float cent) + { + if (!track.hasTOF() || !cfgFillmass) + return; + + float beta{o2::pid::tof::Beta::GetBeta(track)}; + const float eps = 1e-6f; + if (beta < eps || beta > 1.0f - eps) + return; + float charge = (species == he3 || species == he4) ? 2.f : 1.f; + float p = getRigidity(track); // assuming this is the momentum from inner TPC + float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); + // get PDG mass + float pdgMass = particleMasses[species]; + float massDiff = 0.0; + if (species != he4) { + if (cfgmass2) { + // Compare squared masses + massDiff = massTOF * massTOF - pdgMass * pdgMass; + } else { + // Compare linear masses + massDiff = massTOF - pdgMass; + } + } + if (species == he4) { + if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) + return; + if (cfgmass2) { + // Compare squared masses + massDiff = massTOF * massTOF - pdgMass * pdgMass; + } else { + // Compare linear masses + massDiff = massTOF - pdgMass; + } + } + + float ptMomn; + setTrackParCov(track, mTrackParCov); + mTrackParCov.setPID(track.pidForTracking()); + ptMomn = (species == he3 || species == he4) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); + if (track.sign() > 0) { + hmass[2 * species]->Fill(ptMomn, massDiff, cent); + } else if (track.sign() < 0) { + hmass[2 * species + 1]->Fill(ptMomn, massDiff, cent); + } + } + //---------------------------------------------------------------------------------------------------------------- + template + void fillhmassnsigma(T const& track, int species, float sigma) + { + if (!track.hasTOF() || !cfgFillmassnsigma) + return; + float beta{o2::pid::tof::Beta::GetBeta(track)}; + const float eps = 1e-6f; + if (beta < eps || beta > 1.0f - eps) + return; + float charge = (species == he3 || species == he4) ? 2.f : 1.f; + float p = getRigidity(track); + float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); + + // get PDG mass + float masssquare = massTOF * massTOF; + + if (species != he4) { + masssquare = massTOF * massTOF; + } + if (species == he4) { + if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) + return; + masssquare = massTOF * massTOF; + } + + if (track.sign() > 0) { + hmassnsigma[2 * species]->Fill(sigma, masssquare); + } else if (track.sign() < 0) { + hmassnsigma[2 * species + 1]->Fill(sigma, masssquare); + } + } + //---------------------------------------------------------------------------------------------------------------- + template + float getTPCnSigma(T const& track, PrimParticles& 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 getITSnSigma(T const& track, PrimParticles& particle) + { + if (!track.hasITS()) + return -999; + o2::aod::ITSResponse itsResponse; + if (particle.name == "pion") + return itsResponse.nSigmaITS(track); + if (particle.name == "proton") + return itsResponse.nSigmaITS(track); + if (particle.name == "deuteron") + return itsResponse.nSigmaITS(track); + if (particle.name == "triton") + return itsResponse.nSigmaITS(track); + if (particle.name == "helion") + return itsResponse.nSigmaITS(track); + if (particle.name == "alpha") + return itsResponse.nSigmaITS(track); + return -999; // fallback if no match + } + //---------------------------------------------------------------------------------------------------------------- + template + float getMeanItsClsSize(T const& track) + { + int sum = 0, n = 0; + constexpr int kNITSLayers = 8; + for (int i = 0; i < kNITSLayers; 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(); + } + //---------------------------------------------------------------------------------------------------------------- + float dcazSigma(double pt, float dcasigma) + { + float invPt = 1.f / pt; + return (5.00000e-04 + 8.73690e-03 * invPt + 9.62329e-04 * invPt * invPt) * dcasigma; // o2-linter: disable=magic-number (To be checked) + } + //---------------------------------------------------------------------------------------------------------------- + template + float getRapidity(T const& track, int species) + { + using PtEtaPhiMVector = ROOT::Math::LorentzVector>; + double momn; + int speciesHe3 = 4; + int speciesHe4 = 5; + if (species == speciesHe3 || species == speciesHe4) { + momn = 2 * track.pt(); + } else { + momn = track.pt(); + } + PtEtaPhiMVector lorentzVectorParticle(momn, track.eta(), track.phi(), particleMasses[species]); + return lorentzVectorParticle.Rapidity(); + } +}; // end of the task here +//---------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------- +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/pccQa.cxx b/PWGLF/Tasks/Nuspex/pccQa.cxx new file mode 100644 index 00000000000..fbef346fa64 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/pccQa.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 pccQa.cxx +/// \brief Task producing DCA distributions with and without particle-composition correction. +/// \author Mario Krüger + +#include "PWGLF/DataModel/particleCompositionCorrectionTable.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include + +#include + +#include + +using namespace o2; +using namespace o2::framework; +using aod::track::TrackSelectionFlags; + +struct PccQa { + HistogramRegistry histos; + Service pdg; + + static constexpr float MaxVtxZ = 10.f; + + void init(InitContext const&); + + template + void processMeas(const C& collision, const T& tracks); + + using CollisionTableData = soa::Join; + using TrackTableData = soa::Join; + void processData(CollisionTableData::iterator const& collision, TrackTableData const& tracks); + PROCESS_SWITCH(PccQa, processData, "process data", false); + + using CollisionTableMCTrue = aod::McCollisions; + using CollisionTableMC = soa::SmallGroups>; + using TrackTableMC = soa::Join; + using ParticleTableMC = soa::Join; + Preslice perCollision = aod::track::collisionId; + void processMC(CollisionTableMCTrue::iterator const& mcCollision, TrackTableMC const& tracks, CollisionTableMC const& collisions, ParticleTableMC const&); + PROCESS_SWITCH(PccQa, processMC, "process mc", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} + +void PccQa::init(InitContext const&) +{ + histos.add("eventCounter", "", kTH1D, {{1, 0.5, 1.5}}); + const AxisSpec dcaAxis = {1000, -1., 1., "#it{DCA}_{xy}", "dca"}; + std::vector ptBinEdges = {0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0}; + const AxisSpec ptAxis{ptBinEdges, "#it{p}_{T} (GeV/#it{c})", "pt"}; + + histos.add("DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + + if (doprocessMC) { + histos.add("DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("prim/DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("prim/DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/dec/DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/dec/DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/mat/DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/mat/DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + } +} + +void PccQa::processData(CollisionTableData::iterator const& collision, TrackTableData const& tracks) +{ + processMeas(collision, tracks); +} +void PccQa::processMC(CollisionTableMCTrue::iterator const&, TrackTableMC const& tracks, CollisionTableMC const& collisions, ParticleTableMC const&) +{ + for (const auto& collision : collisions) { + auto curTracks = tracks.sliceBy(perCollision, collision.globalIndex()); + processMeas(collision, curTracks); + break; + } +} + +template +void PccQa::processMeas(const C& collision, const T& tracks) +{ + if ((std::abs(collision.posZ()) > MaxVtxZ) || !collision.sel8()) { + return; + } + histos.fill(HIST("eventCounter"), 1); + + for (const auto& track : tracks) { + if (!TrackSelectionFlags::checkFlag(track.trackCutFlag(), TrackSelectionFlags::kGlobalTrackWoDCA)) { + continue; + } + histos.fill(HIST("DCAxyVsPt"), track.pt(), track.dcaXY()); + + if constexpr (IS_MC) { + if (!track.has_mcParticle()) { + continue; + } + const auto& particle = track.template mcParticle_as(); + + histos.fill(HIST("DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + + if (particle.isPhysicalPrimary()) { + histos.fill(HIST("prim/DCAxyVsPt"), track.pt(), track.dcaXY()); + histos.fill(HIST("prim/DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + } else { + histos.fill(HIST("sec/DCAxyVsPt"), track.pt(), track.dcaXY()); + histos.fill(HIST("sec/DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + if (particle.getProcess() == TMCProcess::kPDecay) { + histos.fill(HIST("sec/dec/DCAxyVsPt"), track.pt(), track.dcaXY()); + histos.fill(HIST("sec/dec/DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + } else if (particle.getProcess() == TMCProcess::kPHInhelastic || particle.getProcess() == TMCProcess::kPHadronic || particle.getProcess() == TMCProcess::kPHElastic) { + histos.fill(HIST("sec/mat/DCAxyVsPt"), track.pt(), track.dcaXY()); + histos.fill(HIST("sec/mat/DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + } + } + } + } +} diff --git a/PWGLF/Tasks/Nuspex/piKpRAA.cxx b/PWGLF/Tasks/Nuspex/piKpRAA.cxx new file mode 100644 index 00000000000..0e412acf028 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/piKpRAA.cxx @@ -0,0 +1,2284 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file piKpRAA.cxx +/// +/// \brief task for analysis of piKp RAA +/// \author Omar Vazquez (omar.vazquez.rueda@cern.ch) +/// \since August 10, 2025 + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.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 "CommonConstants/MathConstants.h" +#include "CommonConstants/ZDCConstants.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.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 + +#include "TMCProcess.h" +#include "TPDGCode.h" +#include "TVector3.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::evsel; +using namespace o2::constants::math; +using namespace o2::framework::expressions; + +using ColEvSels = soa::Join; +using BCsRun3 = soa::Join; + +using ColEvSelsMC = soa::Join; + +using TracksFull = soa::Join; + +using TracksMC = soa::Join; +// using SimTracks = soa::Join; + +static constexpr int kNEtaHists{8}; + +std::array, kNEtaHists> dEdxPiV0{}; +std::array, kNEtaHists> dEdxPrV0{}; +std::array, kNEtaHists> dEdxElV0{}; +std::array, kNEtaHists> dEdxPiTOF{}; +std::array, kNEtaHists> dEdx{}; +std::array, kNEtaHists> nClVsdEdxPiV0{}; +std::array, kNEtaHists> nClVsdEdxElV0{}; +std::array, kNEtaHists> nClVsdEdxPrV0{}; +std::array, kNEtaHists> pTVsP{}; +std::array, kNEtaHists> nClVsP{}; +std::array, kNEtaHists> nClVsPElV0{}; +std::array, kNEtaHists> nClVsPPiV0{}; +std::array, kNEtaHists> nClVsPPrV0{}; +std::array, kNEtaHists> nClVsPp{}; +std::array, kNEtaHists> nClVsPpElV0{}; +std::array, kNEtaHists> nClVsPpPiV0{}; +std::array, kNEtaHists> nClVsPpPrV0{}; +std::array, kNEtaHists> nClVsdEdxpPiV0{}; +std::array, kNEtaHists> nClVsdEdxpElV0{}; +std::array, kNEtaHists> nClVsdEdxpPrV0{}; + +struct PiKpRAA { + + static constexpr int kZeroInt{0}; + static constexpr int kSevenInt{7}; + + static constexpr float kZero{0.0f}; + static constexpr float kOne{1.0f}; + static constexpr float kTwoPtGeVSel{2.0f}; + static constexpr float kThree{3.0f}; + static constexpr float kTenToMinusNine{1e-9}; + static constexpr float kMinPtNchSel{0.1f}; + static constexpr float kMaxPtNchSel{3.0f}; + static constexpr float kMinCharge{3.f}; + static constexpr float kMinPElMIP{0.3f}; + static constexpr float kMaxPElMIP{0.45f}; + static constexpr float kMinPMIP{0.4f}; + static constexpr float kMaxPMIP{0.6f}; + static constexpr float kMindEdxMIP{40.0f}; + static constexpr float kMaxdEdxMIP{60.0f}; + static constexpr float kMindEdxMIPPlateau{70.0f}; + static constexpr float kMaxdEdxMIPPlateau{90.0f}; + + static constexpr float kLowEta[kNEtaHists] = {-0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6}; + static constexpr float kHighEta[kNEtaHists] = {-0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8}; + // static constexpr float kLowEta[kNEtaHists] = {0.0, 0.2, 0.4, 0.6}; + // static constexpr float kHighEta[kNEtaHists] = {0.2, 0.4, 0.6, 0.8}; + + static constexpr float DefaultLifetimeCuts[1][2] = {{30., 20.}}; + Configurable> lifetimecut{"lifetimecut", {DefaultLifetimeCuts[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecut"}; + + 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 minEtaDaughter{"minEtaDaughter", -0.8, "Daughter minimum-eta selection"}; + Configurable maxEtaDaughter{"maxEtaDaughter", +0.8, "Daughter maximum-eta selection"}; + Configurable minPt{"minPt", 0.15, "minimum pt of the tracks"}; + Configurable maxPt{"maxPt", 20.0, "maximum pt of the tracks"}; + Configurable minPtDaughter{"minPtDaughter", 0.15, "minimum pt of the tracks"}; + Configurable maxPtDaughter{"maxPtDaughter", 20.0, "maximum pt of the tracks"}; + Configurable useNclsPID{"useNclsPID", true, "Use Ncl for PID?"}; + Configurable minNcl{"minNcl", 135, "minimum found Ncl in TPC"}; + Configurable minNCrossedRows{"minNCrossedRows", 70, "minimum number of crossed rows"}; + Configurable minNCrossedRowsOverFindableCls{"minNCrossedRowsOverFindableCls", 0.8, "min N crossed rows over findable Cls"}; + Configurable maxChi2ClsTPC{"maxChi2ClsTPC", 4.0, "Max chi2 per Cls TPC"}; + Configurable maxChi2ClsITS{"maxChi2ClsITS", 36.0, "chi2 per Cls ITS"}; + Configurable maxDCAZ{"maxDCAZ", 2.0, "Max DCA Z"}; + Configurable itsRefit{"itsRefit", true, "Require ITS refit"}; + Configurable tpcRefit{"tpcRefit", true, "Require TPC refit"}; + Configurable chi2Golden{"chi2Golden", true, "Require Chi2 golde selection"}; + Configurable its1HitIB{"its1HitIB", true, "Require one hit in the ITS IB"}; + Configurable requireITShit{"requireITShit", true, "Apply requirement of one hit in the ITS IB?"}; + + // Standard 5 topological criteria + Configurable v0cospa{"v0cospa", 0.995, "min V0 CosPA"}; + Configurable dcav0dau{"dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; + Configurable dcanegtopv{"dcanegtopv", .1, "min DCA Neg To PV (cm)"}; + Configurable dcapostopv{"dcapostopv", .1, "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"}; + Configurable armAlphaSel{"armAlphaSel", 0.45f, "Armenteros alpha selection (Gammas)"}; + Configurable qTSel{"qTSel", 0.01f, "Armenteros qT select (Gammas)"}; + + // Selection + Configurable selElecFromGammas{"selElecFromGammas", true, "track selection for electrons"}; + Configurable applyInvMassSel{"applyInvMassSel", false, "Select V0s close to the Inv. mass value"}; + Configurable dMassSel{"dMassSel", 0.01f, "Invariant mass selection"}; + Configurable dMassSelG{"dMassSelG", 0.1f, "Inv mass selection gammas"}; + + // PID (TPC/TOF) + Configurable dEdxPlateauSel{"dEdxPlateauSel", 50, "dEdx selection for electrons"}; + Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + Configurable maxExpTOFPi{"maxExpTOFPi", 0.00005, "Maximum beta TOF selection"}; + Configurable applyTPCTOFCombinedCut{"applyTPCTOFCombinedCut", false, " Apply geometrical cut ? "}; + + // Phi cut + Configurable applyPhiCut{"applyPhiCut", false, "Apply geometrical cut?"}; + Configurable applyEtaCal{"applyEtaCal", false, "Apply eta calibration?"}; + Configurable applyPlateauSel{"applyPlateauSel", false, "Apply eta calibration?"}; + Configurable usePinPhiSelection{"usePinPhiSelection", true, "Uses Phi selection as a function of P or Pt?"}; + Configurable applyNclSel{"applyNclSel", false, "Apply Min. found Ncl in TPC?"}; + } v0Selections; + + // Configurables Event Selection + Configurable isNoCollInTimeRangeStrict{"isNoCollInTimeRangeStrict", true, "use isNoCollInTimeRangeStrict?"}; + Configurable isNoCollInTimeRangeStandard{"isNoCollInTimeRangeStandard", false, "use isNoCollInTimeRangeStandard?"}; + Configurable isNoCollInRofStrict{"isNoCollInRofStrict", true, "use isNoCollInRofStrict?"}; + Configurable isNoCollInRofStandard{"isNoCollInRofStandard", false, "use isNoCollInRofStandard?"}; + Configurable isNoHighMultCollInPrevRof{"isNoHighMultCollInPrevRof", true, "use isNoHighMultCollInPrevRof?"}; + Configurable isNoCollInTimeRangeNarrow{"isNoCollInTimeRangeNarrow", false, "use isNoCollInTimeRangeNarrow?"}; + Configurable isOccupancyCut{"isOccupancyCut", true, "Occupancy cut?"}; + Configurable isCentSel{"isCentSel", true, "Centrality selection?"}; + Configurable isT0Ccent{"isT0Ccent", true, "Use T0C-based centrality?"}; + Configurable isZvtxPosSel{"isZvtxPosSel", true, "Zvtx position selection?"}; + Configurable isINELgt0{"isINELgt0", true, "Apply INEL > 0?"}; + Configurable isApplyFT0CbasedOccupancy{"isApplyFT0CbasedOccupancy", false, "T0C Occu cut"}; + Configurable applyNchSel{"applyNchSel", false, "Use mid-rapidity-based Nch selection"}; + Configurable skipRecoColGTOne{"skipRecoColGTOne", true, "Remove collisions if reconstructed more than once"}; + Configurable detector4Calibration{"detector4Calibration", "T0M", "Detector for nSigma-Nch rejection"}; + + // Event selection + Configurable posZcut{"posZcut", +10.0, "z-vertex position cut"}; + Configurable minT0CcentCut{"minT0CcentCut", 0.0, "Min T0C Cent. cut"}; + Configurable maxT0CcentCut{"maxT0CcentCut", 100.0, "Max T0C Cent. cut"}; + Configurable minOccCut{"minOccCut", 0., "min Occu cut"}; + Configurable maxOccCut{"maxOccCut", 500., "max Occu cut"}; + Configurable nSigmaNchCut{"nSigmaNchCut", 3., "nSigma Nch selection"}; + + ConfigurableAxis binsPtPhiCut{"binsPtPhiCut", {VARIABLE_WIDTH, 0.0, 0.6, 0.8, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0, 3.5, 4.0, 5.0, 7.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0, 45.0, 50.0}, "pT"}; + ConfigurableAxis binsPtV0s{"binsPtV0s", {VARIABLE_WIDTH, 0, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.2, 1.4, 1.6, 1.8, 2, 2.5, 3.0, 3.5, 4, 5, 7, 9, 12, 15, 20}, "pT"}; + ConfigurableAxis binsPtNcl{"binsPtNcl", {VARIABLE_WIDTH, 0.0, 0.15, 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, 3.5, 4.0, 5.0, 7.0, 9.0, 12.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0}, "pT"}; + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.12}, "pT binning"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100.}, "T0C binning"}; + ConfigurableAxis binsZpos{"binsZpos", {60, -30.0, 30.0}, "Z pos axis"}; + ConfigurableAxis axisEta{"axisEta", {50, -1.0, 1.0}, "Eta axis"}; + ConfigurableAxis axisY{"axisY", {50, -1.0, 1.0}, "rapidity axis"}; + ConfigurableAxis axisArmAlpha{"axisArmAlpha", {200, -1.0, 1.0}, "Armenteros alpha"}; + ConfigurableAxis axisArmqT{"axisArmqT", {600, 0.0f, 0.3f}, "Armenteros qT"}; + ConfigurableAxis axisK0Mass{"axisK0Mass", {200, 0.4f, 0.6f}, "Mass K0Short"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, "Mass Lambda"}; + ConfigurableAxis axisGammaMass{"axisGammaMass", {150, 0.0f, 0.15f}, "Mass Gamma"}; + ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {200, -10.0f, 10.0f}, "N sigma TPC"}; + ConfigurableAxis axisdEdx{"axisdEdx", {140, 20.0, 160.0}, "dEdx binning"}; + ConfigurableAxis axisDCAxy{"axisDCAxy", {105, -1.05f, 1.05f}, "DCAxy axis"}; + Configurable nBinsNch{"nBinsNch", 400, "N bins Nch (|eta|<0.8)"}; + Configurable nBinsNPV{"nBinsNPV", 600, "N bins ITS tracks"}; + Configurable minNch{"minNch", 0, "Min Nch (|eta|<0.8)"}; + Configurable maxNch{"maxNch", 400, "Max Nch (|eta|<0.8)"}; + Configurable minNpv{"minNpv", 0, "Min NPV"}; + Configurable maxNpv{"maxNpv", 600, "Max NPV"}; + + // CCDB paths + Configurable pathMeanNch{"pathMeanNch", "Users/o/omvazque/MeanNch/OO/Pass2/PerTimeStamp/Aug20", "base path to the ccdb object"}; + Configurable pathSigmaNch{"pathSigmaNch", "Users/o/omvazque/SigmaNch/OO/Pass2/PerTimeStamp/Aug20", "base path to the ccdb object"}; + Configurable pathEtaCal{"pathEtaCal", "Users/o/omvazque/EtaCal/OO/Global", "base path to the ccdb object"}; + Configurable pathEtaCalPlateau{"pathEtaCalPlateau", "Users/o/omvazque/EtaCal/OO/Global", "base path to the ccdb object"}; + Configurable pathPhiCutHigh{"pathPhiCutHigh", "Users/o/omvazque/PhiCut/OO/Global/High", "base path to the ccdb object"}; + Configurable pathPhiCutLow{"pathPhiCutLow", "Users/o/omvazque/PhiCut/OO/Global/Low", "base path to the ccdb object"}; + Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + + enum EvCutLabel { + All = 1, + SelEigth, + NoSameBunchPileup, + IsGoodZvtxFT0vsPV, + NoCollInTimeRangeStrict, + NoCollInTimeRangeStandard, + NoCollInRofStrict, + NoCollInRofStandard, + NoHighMultCollInPrevRof, + NoCollInTimeRangeNarrow, + OccuCut, + Centrality, + VtxZ, + NchSel, + INELgt0 + }; + + enum TrkSelLabel { + AllTrks = 1, + Eta, + Pt, + XRows, + XRowsOverFindableCls, + Chi2TPC, + Chi2ITS, + Itsrefit, + Tpcrefit, + Golden, + Itshit, + PassedAll + }; + + enum V0sCounter { + K0s = 1, + Lambda, + AntiLambda, + Gamma + }; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + Service ccdb; + + struct ConfigNch { + TH1F* hMeanNch = nullptr; + TH1F* hSigmaNch = nullptr; + bool calibrationsLoaded = false; + } cfgNch; + + struct ConfigPhiCut { + TH1F* hPhiCutHigh = nullptr; + TH1F* hPhiCutLow = nullptr; + bool isPhiCutLoaded = false; + } phiCut; + + struct ConfigEtaCalib { + TProfile* pEtaCal = nullptr; + TProfile* pEtaCalPlateau = nullptr; + bool isMIPCalLoaded = false; + bool isCalPlateauLoaded = false; + } etaCal; + + TrackSelection trkSelGlobalOpenDCAxy; + // TrackSelection trkSelDaugthers; + TrackSelection trkSelGlobal; + // TrackSelection trkSelDaugthersV0s() { + // TrackSelection selectedTracks; + // selectedTracks.SetEtaRange(-0.8f, 0.8f); + // selectedTracks.SetMinNCrossedRowsTPC(70); + // return selectedTracks; + // } + + TrackSelection trkSelOpenDCAxy() + { + TrackSelection selectedTracks; + selectedTracks.SetTrackType(o2::aod::track::TrackTypeEnum::Track); // Run 2 track asked by default + 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; + } + + int currentRunNumberNchSel; + int currentRunNumberPhiSel; + void init(InitContext const&) + { + currentRunNumberNchSel = -1; + currentRunNumberPhiSel = -1; + trkSelGlobalOpenDCAxy = trkSelOpenDCAxy(); + // trkSelDaugthers = trkSelDaugthersV0s(); + trkSelGlobal = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + + // define axes you want to use + const std::string titlePorPt{v0Selections.usePinPhiSelection ? "#it{p} (GeV/#it{c})" : "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisZpos{binsZpos, "Vtx_{z} (cm)"}; + const AxisSpec axisEvent{17, 0.5, 17.5, ""}; + const AxisSpec axisNcl{161, -0.5, 160.5, "#it{N}_{cl} TPC"}; + const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisPtV0s{binsPtV0s, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisPtNcl{binsPtNcl, Form("%s", titlePorPt.data())}; + const AxisSpec axisXPhiCut{binsPtPhiCut, Form("%s", titlePorPt.data())}; + const AxisSpec axisCent{binsCent, "Centrality Perc."}; + const char* endingEta[kNEtaHists] = {"86", "64", "42", "20", "02", "24", "46", "68"}; + const char* latexEta[kNEtaHists] = {"-0.8<#eta<-0.6", "-0.6<#eta<-0.4", "-0.4<#eta<-0.2", "-0.2<#eta<0", "0<#eta<0.2", "0.2<#eta<0.4", "0.4<#eta<0.6", "0.6<#eta<0.8"}; + + registry.add("EventCounter", ";;Events", kTH1F, {axisEvent}); + registry.add("zPos", "With Event Selection;;Entries;", kTH1F, {axisZpos}); + registry.add("T0Ccent", ";;Entries", kTH1F, {axisCent}); + registry.add("NclVsEtaPID", ";#eta;Ncl used for PID", kTH2F, {{{axisEta}, {161, -0.5, 160.5}}}); + registry.add("NclVsEtaPIDp", ";#eta;#LTNcl#GT used for PID", kTProfile, {axisEta}); + registry.add("dcaVsPtPi", "Primary pions;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("dcaVsPtPr", "Primary protons;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + + auto hstat = registry.get(HIST("EventCounter")); + 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 Sel."); + x->SetBinLabel(14, "Nch Sel."); + x->SetBinLabel(15, "INEL > 0"); + + if (doprocessCalibrationAndV0s) { + registry.add("NchVsNPV", ";Nch; NPV;", kTH2F, {{{nBinsNPV, minNpv, maxNpv}, {nBinsNch, minNch, maxNch}}}); + registry.add("ExcludedEvtVsNch", ";Nch;Entries;", kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("ExcludedEvtVsNPV", ";NPV;Entries;", kTH1F, {{nBinsNPV, minNpv, maxNpv}}); + registry.add("TrackDaughterCounter", "itsrefit, and itshit NOT appplied for electrons sel.;Trk Sel.; Entries;", kTH1F, {{14, 0.5, 14.5}}); + registry.add("V0sCounter", ";V0 type; Entries;", kTH1F, {{4, 0.5, 4.5}}); + registry.add("dcaDauVsPt", ";V0 #it{p}_{T} (GeV/#it{c});DCA_{xy} (cm) daughters;", kTH2F, {axisPt, axisDCAxy}); + registry.add("nSigPiFromK0s", ";#it{n#sigma};;", kTH2F, {axisPtV0s, axisNsigmaTPC}); + registry.add("nSigPiFromL", ";#it{n#sigma};;", kTH2F, {axisPtV0s, axisNsigmaTPC}); + registry.add("nSigPrFromL", ";#it{n#sigma};;", kTH2F, {axisPtV0s, axisNsigmaTPC}); + registry.add("nSigPiFromAL", ";#it{n#sigma};;", kTH2F, {axisPtV0s, axisNsigmaTPC}); + registry.add("nSigPrFromAL", ";#it{n#sigma};;", kTH2F, {axisPtV0s, axisNsigmaTPC}); + registry.add("nSigElFromG", ";#it{n#sigma};;", kTH2F, {axisPtV0s, axisNsigmaTPC}); + registry.add("ArmAll", "Armenteros-Podolanski;#alpha;q_{T} (GeV/c)", kTH2F, {axisArmAlpha, axisArmqT}); + registry.add("ArmAfterTopoSel", "Armenteros-Podolanski anfter topological selection;#alpha;q_{T} (GeV/c)", kTH2F, {axisArmAlpha, axisArmqT}); + registry.add("ArmK0NOSel", "Armenteros-Podolanski WITH OUT 5 #times q_{T} > #alpha selection;#alpha;q_{T} (GeV/c)", kTH2F, {axisArmAlpha, axisArmqT}); + registry.add("ArmK0", "Armenteros-Podolanski WITH 5 #times q_{T} > #alpha selection;#alpha;q_{T} (GeV/c)", kTH2F, {axisArmAlpha, axisArmqT}); + registry.add("ArmL", "Armenteros-Podolanski;#alpha;q_{T} (GeV/c)", kTH2F, {axisArmAlpha, axisArmqT}); + registry.add("ArmAL", "Armenteros-Podolanski;#alpha;q_{T} (GeV/c)", kTH2F, {axisArmAlpha, axisArmqT}); + registry.add("ArmG", "Armenteros-Podolanski;#alpha;q_{T} (GeV/c)", kTH2F, {axisArmAlpha, axisArmqT}); + registry.add("MassK0sVsPt", ";;Inv. Mass (GeV/#it{c}^{2});", kTH2F, {axisPtV0s, axisK0Mass}); + registry.add("MassLVsPt", ";;Inv. Mass (GeV/#it{c}^{2});", kTH2F, {axisPtV0s, axisLambdaMass}); + registry.add("MassALVsPt", ";;Inv. Mass (GeV/#it{c}^{2});", kTH2F, {axisPtV0s, axisLambdaMass}); + registry.add("MassGVsPt", ";;Inv. Mass (GeV/#it{c}^{2});", kTH2F, {axisPtV0s, axisGammaMass}); + + // registry.add("NclFindable", ";;Findable Ncl TPC", kTH2F, {axisPtNcl, axisNcl}); + // registry.add("NclFindablep", ";;Findable #LTNcl#GT TPC", kTProfile, {axisPtNcl}); + registry.add("NclVsPhipBeforeCut", Form("Found #LTNcl#GT TPC;%s (GeV/#it{c});#varphi", titlePorPt.data()), kTProfile2D, {{{axisXPhiCut}, {350, 0.0, 0.35}}}); + registry.add("NclVsPhipBeforeCutPID", Form("#LTNcl#GT used for PID;%s (GeV/#it{c});#varphi", titlePorPt.data()), kTProfile2D, {{{axisXPhiCut}, {350, 0.0, 0.35}}}); + registry.add("NclVsPhipAfterCut", Form("Found #LTNcl#GT TPC;%s (GeV/#it{c});#varphi", titlePorPt.data()), kTProfile2D, {{{axisXPhiCut}, {350, 0.0, 0.35}}}); + registry.add("NclVsPhipAfterCutPID", Form("#LTNcl#GT used for PID;%s (GeV/#it{c});#varphi", titlePorPt.data()), kTProfile2D, {{{axisXPhiCut}, {350, 0.0, 0.35}}}); + registry.add("NclVsEta", ";#eta;Found Ncl TPC", kTH2F, {{{axisEta}, {161, -0.5, 160.5}}}); + registry.add("NclVsEtap", ";#eta;Found #LTNcl#GT TPC", kTProfile, {axisEta}); + + registry.add("NclVsEtaPiMIP", "MIP #pi^{+} + #pi^{-} (0.4 < #it{p} < 0.6 GeV/#it{c}, 40 < dE/dx < 60);#eta;Ncl TPC", kTH2F, {{{axisEta}, {161, -0.5, 160.5}}}); + registry.add("NclVsEtaPiMIPp", "MIP #pi^{+} + #pi^{-} (0.4 < #it{p} < 0.6 GeV/#it{c}, 40 < dE/dx < 60);#eta;#LTNcl#GT TPC", kTProfile, {axisEta}); + registry.add("NclVsEtaPiV0", ";#eta;Ncl TPC", kTH2F, {axisEta, axisNcl}); + registry.add("NclVsEtaPiV0p", ";#eta;#LTNcl#GT TPC", kTProfile, {axisEta}); + registry.add("NclVsEtaPrV0", ";#eta;Ncl TPC", kTH2F, {axisEta, axisNcl}); + registry.add("NclVsEtaPrV0p", ";#eta;#LTNcl#GT TPC", kTProfile, {axisEta}); + registry.add("NclVsEtaElV0", ";#eta;Ncl TPC", kTH2F, {axisEta, axisNcl}); + registry.add("NclVsEtaElV0p", ";#eta;#LTNcl#GT TPC", kTProfile, {axisEta}); + + registry.add("EtaVsPhi", ";#eta;#varphi;", kTH2F, {{axisEta}, {100, 0, o2::constants::math::TwoPI}}); + registry.add("EtaVsYK0s", ";#eta;#it{y};", kTH2F, {axisEta, axisY}); + registry.add("EtaVsYPiL", ";#eta;#it{y};", kTH2F, {axisEta, axisY}); + registry.add("EtaVsYPrL", ";#eta;#it{y};", kTH2F, {axisEta, axisY}); + registry.add("EtaVsYPiAL", ";#eta;#it{y};", kTH2F, {axisEta, axisY}); + registry.add("EtaVsYPrAL", ";#eta;#it{y};", kTH2F, {axisEta, axisY}); + registry.add("EtaVsYG", ";#eta;#it{y};", kTH2F, {axisEta, axisY}); + + // registry.add("TOFExpPi2TOF", ";Momentum (GeV/#it{c});t^{#pi}_{Exp}/t_{TOF}", kTH2F, {{{axisPtV0s}, {100, 0.2, 1.2}}}); + registry.add("DCAxyDCAzPiK0s", ";DCA_{xy} (cm); DCA_{z} (cm)", kTH2F, {axisDCAxy, axisDCAxy}); + registry.add("DCAxyDCAzPrL", ";DCA_{xy} (cm); DCA_{z} (cm)", kTH2F, {axisDCAxy, axisDCAxy}); + registry.add("DCAxyDCAzPrAL", ";DCA_{xy} (cm); DCA_{z} (cm)", kTH2F, {axisDCAxy, axisDCAxy}); + + // registry.add("betaVsMomentum", ";Momentum (GeV/#it{c}); #beta", kTH2F, {{{axisPtV0s}, {500, 0, 1.2}}}); + registry.add("dEdxVsEtaPiMIP", "MIP #pi^{+} + #pi^{-} (0.4 < #it{p} < 0.6 GeV/#it{c});#eta; dE/dx;", kTH2F, {{{axisEta}, {100, 0, 100}}}); + registry.add("dEdxVsEtaPiMIPp", "MIP #pi^{+} + #pi^{-} (0.4 < #it{p} < 0.6 GeV/#it{c});#eta; #LTdE/dx#GT", kTProfile, {axisEta}); + registry.add("dEdxVsEtaElMIP", "MIP e^{+} + e^{-} (0.3 < #it{p} < 0.45 GeV/#it{c});#eta; dE/dx;", kTH2F, {{{axisEta}, {100, 0, 100}}}); + registry.add("dEdxVsEtaElMIPp", "MIP e^{+} + e^{-} (0.3 < #it{p} < 0.45 GeV/#it{c});#eta; #LTdE/dx#GT", kTProfile, {axisEta}); + registry.add("dEdxVsEtaPiMIPV0", "MIP #pi^{+} + #pi^{-} (0.4 < #it{p} < 0.6 GeV/#it{c});#eta; dE/dx", kTH2F, {{{axisEta}, {100, 0, 100}}}); + registry.add("dEdxVsEtaPiMIPV0p", "MIP #pi^{+} + #pi^{-} (0.4 < #it{p} < 0.6 GeV/#it{c});#eta; #LTdE/dx#GT", kTProfile, {axisEta}); + registry.add("dEdxVsEtaElMIPV0", "e^{+} + e^{-} (0.15 <#it{p}_{T} < 50 GeV/#it{c});#eta; dE/dx", kTH2F, {{{axisEta}, {100, 0, 100}}}); + registry.add("dEdxVsEtaElMIPV0p", "e^{+} + e^{-} (0.15 <#it{p}_{T} < 50 GeV/#it{c});#eta; #LTdE/dx#GT", kTProfile, {axisEta}); + + registry.add("pTVsCent", "", kTH2F, {axisPt, axisCent}); + + for (int i = 0; i < kNEtaHists; ++i) { + dEdx[i] = registry.add(Form("dEdx_%s", endingEta[i]), Form("%s;Momentum (GeV/#it{c});dE/dx;", latexEta[i]), kTH3F, {axisPt, axisdEdx, axisCent}); + pTVsP[i] = registry.add(Form("pTVsP_%s", endingEta[i]), Form("%s;Momentum (GeV/#it{c});#it{p}_{T} (GeV/#it{c});", latexEta[i]), kTH2F, {axisPt, axisPt}); + dEdxPiV0[i] = registry.add(Form("dEdxPiV0_%s", endingEta[i]), Form("#pi^{+} + #pi^{-}, %s;Momentum (GeV/#it{c});dE/dx;", latexEta[i]), kTH3F, {axisPtV0s, axisdEdx, axisCent}); + dEdxPrV0[i] = registry.add(Form("dEdxPrV0_%s", endingEta[i]), Form("p + #bar{p}, %s;Momentum (GeV/#it{c});dE/dx;", latexEta[i]), kTH3F, {axisPtV0s, axisdEdx, axisCent}); + dEdxElV0[i] = registry.add(Form("dEdxElV0_%s", endingEta[i]), Form("e^{+} + e^{-}, %s;Momentum (GeV/#it{c});dE/dx;", latexEta[i]), kTH3F, {axisPtV0s, axisdEdx, axisCent}); + dEdxPiTOF[i] = registry.add(Form("dEdxPiTOF_%s", endingEta[i]), Form("#pi^{+} + #pi^{-}, %s;Momentum (GeV/#it{c});dE/dx;", latexEta[i]), kTH3F, {axisPtV0s, axisdEdx, axisCent}); + nClVsdEdxPiV0[i] = registry.add(Form("NclVsdEdxPiV0_%s", endingEta[i]), Form("%s;#it{N}_{cl} used for PID;dE/dx;", latexEta[i]), kTH2F, {axisNcl, axisdEdx}); + nClVsdEdxElV0[i] = registry.add(Form("NclVsdEdxElV0_%s", endingEta[i]), Form("%s;#it{N}_{cl} used for PID;dE/dx;", latexEta[i]), kTH2F, {axisNcl, axisdEdx}); + nClVsdEdxPrV0[i] = registry.add(Form("NclVsdEdxPrV0_%s", endingEta[i]), Form("%s;#it{N}_{cl} used for PID;dE/dx;", latexEta[i]), kTH2F, {axisNcl, axisdEdx}); + nClVsP[i] = registry.add(Form("NclVsPPrimaries_%s", endingEta[i]), Form("%s;;Ncl TPC", latexEta[i]), kTH2F, {axisPtNcl, axisNcl}); + nClVsPElV0[i] = registry.add(Form("NclVsPElV0_%s", endingEta[i]), Form("%s;;Ncl TPC", latexEta[i]), kTH2F, {axisPtNcl, axisNcl}); + nClVsPPiV0[i] = registry.add(Form("NclVsPPiV0_%s", endingEta[i]), Form("%s;;Ncl TPC", latexEta[i]), kTH2F, {axisPtNcl, axisNcl}); + nClVsPPrV0[i] = registry.add(Form("NclVsPPrV0_%s", endingEta[i]), Form("%s;;Ncl TPC", latexEta[i]), kTH2F, {axisPtNcl, axisNcl}); + nClVsPp[i] = registry.add(Form("NclVsPrimariesp_%s", endingEta[i]), Form("%s;;#LT#it{N}_{cl}#GT TPC", latexEta[i]), kTProfile, {axisPtNcl}); + nClVsPpElV0[i] = registry.add(Form("NclVsPElV0p_%s", endingEta[i]), Form("%s;;#LT#it{N}_{cl}#GT TPC", latexEta[i]), kTProfile, {axisPtNcl}); + nClVsPpPiV0[i] = registry.add(Form("NclVsPPiV0p_%s", endingEta[i]), Form("%s;;#LT#it{N}_{cl}#GT TPC", latexEta[i]), kTProfile, {axisPtNcl}); + nClVsPpPrV0[i] = registry.add(Form("NclVsPPrV0p_%s", endingEta[i]), Form("%s;;#LT#it{N}_{cl}#GT TPC", latexEta[i]), kTProfile, {axisPtNcl}); + nClVsdEdxpElV0[i] = registry.add(Form("NclVsdEdxElV0p_%s", endingEta[i]), Form("%s;;#LTd#it{E}/d#it{x}#GT", latexEta[i]), kTProfile, {axisNcl}); + nClVsdEdxpPiV0[i] = registry.add(Form("NclVsdEdxPiV0p_%s", endingEta[i]), Form("%s;;#LTd#it{E}/d#it{x}#GT", latexEta[i]), kTProfile, {axisNcl}); + nClVsdEdxpPrV0[i] = registry.add(Form("NclVsdEdxPrV0p_%s", endingEta[i]), Form("%s;;#LTd#it{E}/d#it{x}#GT", latexEta[i]), kTProfile, {axisNcl}); + } + + auto htrkSel = registry.get(HIST("TrackDaughterCounter")); + auto* xtrkSel = htrkSel->GetXaxis(); + xtrkSel->SetBinLabel(1, "All"); + xtrkSel->SetBinLabel(2, "Eta"); + xtrkSel->SetBinLabel(3, "Pt"); + xtrkSel->SetBinLabel(4, "XRows"); + xtrkSel->SetBinLabel(5, "XRowsOverFindableCls"); + xtrkSel->SetBinLabel(6, "Chi2TPC"); + xtrkSel->SetBinLabel(7, "Chi2ITS"); + xtrkSel->SetBinLabel(8, "Itsrefit"); + xtrkSel->SetBinLabel(9, "Tpcrefit"); + xtrkSel->SetBinLabel(10, "Golden"); + xtrkSel->SetBinLabel(11, "Itshit"); + xtrkSel->SetBinLabel(12, "Passed all"); + } + + if (doprocessMC || doprocessSim) { + registry.add("zPosMC", "Generated Events With at least One Rec. Collision + Sel. criteria;;Entries;", kTH1F, {axisZpos}); + registry.add("dcaVsPtPiDec", "Secondary pions from decays;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("dcaVsPtPrDec", "Secondary protons from decays;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("dcaVsPtPiMat", "Secondary pions from material interactions;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("dcaVsPtPrMat", "Secondary protons from material interactions;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("NclVsPhip", Form("#LTNcl#GT used for PID;%s (GeV/#it{c});#varphi", titlePorPt.data()), kTProfile2D, {{{axisXPhiCut}, {350, 0.0, 0.35}}}); + } + + if (doprocessMC) { + + registry.add("EventCounterMC", "Event counter", kTH1F, {axisEvent}); + + registry.add("PtPiVsCent", "", kTH2F, {axisPt, axisCent}); + registry.add("PtKaVsCent", "", kTH2F, {axisPt, axisCent}); + registry.add("PtPrVsCent", "", kTH2F, {axisPt, axisCent}); + + registry.add("PtPiVsCentMC", "", kTH2F, {axisPt, axisCent}); + registry.add("PtKaVsCentMC", "", kTH2F, {axisPt, axisCent}); + registry.add("PtPrVsCentMC", "", kTH2F, {axisPt, axisCent}); + } + + if (doprocessSim) { + + registry.add("NumberOfRecoCollisions", "Number of times Gen. Coll.are reconstructed;N;Entries", kTH1F, {{10, -0.5, 9.5}}); + + // Pt resolution + registry.add("PtResolution", "p_{T} resolution;;(pt_{rec} - pt_{gen})/pt_{gen};", kTH2F, {axisPt, {100, -1.0, 1.0}}); + + // Needed to calculate the numerator of the Acceptance X Efficiency + registry.add("PtPiVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtKaVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtPrVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + + // Needed to calculate the denominator of the Acceptance X Efficiency + registry.add("PtPiVsCentMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtKaVsCentMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtPrVsCentMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;;", kTH2F, {axisPt, axisCent}); + + // Needed for the Gen. Nch to Centrality conversion + registry.add("NchMCVsCent", "Generated Nch v.s. Centrality (At least Once Rec. Coll. + Sel. criteria);;Gen. Nch", kTH2F, {{axisCent, {nBinsNch, minNch, maxNch}}}); + + // Needed to measure Event Loss + registry.add("NchMC_WithRecoEvt", "Generated Nch of Evts With at least one Rec. Coll. + Sel. criteria;Gen. Nch MC;Entries", kTH1F, {{nBinsNch, minNch, maxNch}}); + registry.add("NchMC_AllGen", "Generated Nch of All Gen. Evts.;Gen. Nch;Entries", kTH1F, {{nBinsNch, minNch, maxNch}}); + + // Needed to measure Event Splitting + registry.add("Centrality_WRecoEvt", "Generated Events With at least One Rec. Collision And NO Sel. criteria;;Entries", kTH1F, {axisCent}); + registry.add("Centrality_WRecoEvtWSelCri", "Generated Events With at least One Rec. Collision + Sel. criteria;;Entries", kTH1F, {axisCent}); + registry.add("Centrality_AllRecoEvt", "Generated Events Irrespective of the number of times it was reconstructed + Evt. Selections;;Entries", kTH1F, {axisCent}); + + // Needed to calculate the numerator of the Signal Loss correction + registry.add("PtPiVsNchMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;Gen. Nch;", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + registry.add("PtKaVsNchMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;Gen. Nch;", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + registry.add("PtPrVsNchMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;Gen. Nch;", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + + // Needed to calculate the denominator of the Signal Loss correction + registry.add("PtPiVsNchMC_AllGen", "All Generated Events;;Gen. Nch;", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + registry.add("PtKaVsNchMC_AllGen", "All Generated Events;;Gen. Nch;", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + registry.add("PtPrVsNchMC_AllGen", "All Generated Events;;Gen. Nch;", kTH2F, {{axisPt, {nBinsNch, minNch, maxNch}}}); + } + + LOG(info) << "\tccdbNoLaterThan=" << ccdbNoLaterThan.value; + LOG(info) << "\tapplyNchSel=" << applyNchSel.value; + LOG(info) << "\tisINELgt0=" << isINELgt0.value; + LOG(info) << "\tdetector4Calibration=" << detector4Calibration.value; + LOG(info) << "\tv0TypeSelection=" << static_cast(v0Selections.v0TypeSelection); + LOG(info) << "\tselElecFromGammas=" << v0Selections.selElecFromGammas; + LOG(info) << "\trequireITShit=" << v0Selections.requireITShit; + LOG(info) << "\tminPt=" << v0Selections.minPt; + LOG(info) << "\tmaxPt=" << v0Selections.maxPt; + LOG(info) << "\tminPtDaughter=" << v0Selections.minPtDaughter; + LOG(info) << "\tmaxPtDaughter=" << v0Selections.maxPtDaughter; + LOG(info) << "\tuseNclsPID=" << v0Selections.useNclsPID; + LOG(info) << "\tqTSel=" << v0Selections.qTSel; + LOG(info) << "\tarmAlphaSel=" << v0Selections.armAlphaSel; + LOG(info) << "\tapplyTPCTOFCombinedCut=" << v0Selections.applyTPCTOFCombinedCut; + LOG(info) << "\tapplyInvMassSel=" << v0Selections.applyInvMassSel; + LOG(info) << "\tapplyNclSel=" << v0Selections.applyNclSel; + LOG(info) << "\tapplyPhiCut=" << v0Selections.applyPhiCut; + LOG(info) << "\tusePinPhiSelection=" << v0Selections.usePinPhiSelection; + LOG(info) << "\ttitlePorPt=" << titlePorPt; + LOG(info) << "\tcurrentRunNumberNchSel=" << currentRunNumberNchSel; + LOG(info) << "\tcurrentRunNumberPhiSel=" << currentRunNumberPhiSel; + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + + if (applyNchSel.value) { + LOG(info) << "\tLoading Nch-based selections!"; + LOG(info) << "\tpathMeanNch=" << pathMeanNch.value; + LOG(info) << "\tpathSigmaNch=" << pathSigmaNch.value; + } + + if (v0Selections.applyPhiCut) { + LOG(info) << "\tLoading Phi cut!"; + LOG(info) << "\tpathPhiCutLow=" << pathPhiCutLow.value; + LOG(info) << "\tpathPhiCutHigh=" << pathPhiCutHigh.value; + } + + if (v0Selections.applyEtaCal) { + LOG(info) << "\tLoading Eta Cal!"; + LOG(info) << "\tpathEtaCal=" << pathEtaCal.value; + loadEtaCalibration(); + LOG(info) << "\tisMIPCalLoaded=" << etaCal.isMIPCalLoaded; + } + + if (v0Selections.applyPlateauSel) { + LOG(info) << "\tLoading Eta Plateau Cal!"; + LOG(info) << "\tpathEtaCalPlateau=" << pathEtaCalPlateau.value; + loadEtaPlateauCalibration(); + LOG(info) << "\tisCalPlateauLoaded=" << etaCal.isCalPlateauLoaded; + } + + if (v0Selections.applyNclSel) + LOG(info) << "\t minNcl=" << v0Selections.minNcl; + } + + void processCalibrationAndV0s(ColEvSels::iterator const& collision, BCsRun3 const& /**/, aod::V0Datas const& v0s, aod::FV0As const& /**/, aod::FT0s const& /**/, TracksFull const& tracks) + { + // LOG(info) << " Collisions size: " << collisions.size() << " + // Table's size: " << collisions.tableSize() << "\n"; + // LOG(info) << "Run number: " << foundBC.runNumber() << "\n"; + if (!isEventSelected(collision)) { + return; + } + + const auto& foundBC = collision.foundBC_as(); + const uint64_t timeStamp{foundBC.timestamp()}; + const int magField{getMagneticField(timeStamp)}; + const double nPV{collision.multNTracksPVeta1() / 1.}; + + if (applyNchSel) { + const int nextRunNumber{foundBC.runNumber()}; + if (currentRunNumberNchSel != nextRunNumber) { + loadNchCalibrations(timeStamp); + currentRunNumberNchSel = nextRunNumber; + LOG(info) << "\tcurrentRunNumberNchSel= " << currentRunNumberNchSel << " timeStamp = " << timeStamp; + } + + // return if Nch selection objects are nullptr + if (!(cfgNch.hMeanNch && cfgNch.hSigmaNch)) + return; + } + + int nch{0}; + for (const auto& track : tracks) { + // Track Selection + if (!trkSelGlobal.IsSelected(track)) { + continue; + } + if (track.pt() < kMinPtNchSel || track.pt() > kMaxPtNchSel) { + continue; + } + nch++; + } + + bool skipEvent{false}; + if (applyNchSel) { + if (!cfgNch.calibrationsLoaded) + return; + + const double xEval{nPV}; + const int bin4Calibration{cfgNch.hMeanNch->FindBin(xEval)}; + const double meanNch{cfgNch.hMeanNch->GetBinContent(bin4Calibration)}; + const double sigmaNch{cfgNch.hSigmaNch->GetBinContent(bin4Calibration)}; + const double nSigmaSelection{nSigmaNchCut * sigmaNch}; + const double diffMeanNch{meanNch - nch}; + + if (std::abs(diffMeanNch) > nSigmaSelection) { + registry.fill(HIST("ExcludedEvtVsNch"), nch); + registry.fill(HIST("ExcludedEvtVsNPV"), nPV); + skipEvent = true; + } + } + + if (applyNchSel && skipEvent) { + return; + } + + if (applyNchSel) + registry.fill(HIST("EventCounter"), EvCutLabel::NchSel); + + registry.fill(HIST("NchVsNPV"), nPV, nch); + registry.fill(HIST("zPos"), collision.posZ()); + const float centrality{isT0Ccent ? collision.centFT0C() : collision.centFT0M()}; + + if (v0Selections.applyPhiCut) { + const int nextRunNumber{foundBC.runNumber()}; + if (currentRunNumberPhiSel != nextRunNumber) { + loadPhiCutSelections(timeStamp); + currentRunNumberPhiSel = nextRunNumber; + LOG(info) << "\tcurrentRunNumberPhiSel= " << currentRunNumberPhiSel << " timeStamp = " << timeStamp; + } + + // return if phi cut objects are nullptr + if (!(phiCut.hPhiCutHigh && phiCut.hPhiCutLow)) + return; + } + + registry.fill(HIST("T0Ccent"), centrality); + // Fill DCAxy vs pT for secondary-particle contamination correction + for (const auto& track : tracks) { + // Track Selection + if (!trkSelGlobalOpenDCAxy.IsSelected(track)) + continue; + + if (track.pt() < v0Selections.minPt || track.pt() > v0Selections.maxPt) + continue; + + if (track.eta() < v0Selections.minEtaDaughter || track.eta() > v0Selections.maxEtaDaughter) + continue; + + const float momentum{track.p()}; + const float pt{track.pt()}; + const float phi{track.phi()}; + const float pOrPt{v0Selections.usePinPhiSelection ? momentum : pt}; + const int16_t nclFound{track.tpcNClsFound()}; + const int16_t nclPID{track.tpcNClsPID()}; + const int16_t ncl{v0Selections.useNclsPID ? nclPID : nclFound}; + + if (v0Selections.applyNclSel && ncl < v0Selections.minNcl) + continue; + + float phiPrime{phi}; + const int charge{track.sign()}; + phiPrimeFunc(phiPrime, magField, charge); + + if (v0Selections.applyPhiCut) { + if (!passesPhiSelection(pOrPt, phiPrime)) + continue; + } + + const float piTPCNsigma{std::fabs(track.tpcNSigmaPi())}; + const float prTPCNsigma{std::fabs(track.tpcNSigmaPr())}; + const float piTOFNsigma{std::fabs(track.tofNSigmaPi())}; + const float prTOFNsigma{std::fabs(track.tofNSigmaPr())}; + const double piRadiusNsigma{std::sqrt(std::pow(piTPCNsigma, 2.) + std::pow(piTOFNsigma, 2.))}; + const double prRadiusNsigma{std::sqrt(std::pow(prTPCNsigma, 2.) + std::pow(prTOFNsigma, 2.))}; + + if (piRadiusNsigma < kThree) + registry.fill(HIST("dcaVsPtPi"), track.pt(), track.dcaXY(), centrality); + if (prRadiusNsigma < kThree) + registry.fill(HIST("dcaVsPtPr"), track.pt(), track.dcaXY(), centrality); + } + + for (const auto& track : tracks) { + + if (!trkSelGlobal.IsSelected(track)) + continue; + + if (track.pt() < v0Selections.minPt || track.pt() > v0Selections.maxPt) + continue; + + if (track.eta() < v0Selections.minEtaDaughter || track.eta() > v0Selections.maxEtaDaughter) + continue; + + const float momentum{track.p()}; + const float pt{track.pt()}; + const float phi{track.phi()}; + const float eta{track.eta()}; + float dedx{track.tpcSignal()}; + const int charge{track.sign()}; + const float pOrPt{v0Selections.usePinPhiSelection ? momentum : pt}; + const int16_t nclFound{track.tpcNClsFound()}; + const int16_t nclPID{track.tpcNClsPID()}; + const int16_t ncl{v0Selections.useNclsPID ? nclPID : nclFound}; + + if (v0Selections.applyNclSel && ncl < v0Selections.minNcl) + continue; + + float phiPrime{phi}; + phiPrimeFunc(phiPrime, magField, charge); + registry.fill(HIST("NclVsPhipBeforeCut"), pOrPt, phiPrime, nclFound); + registry.fill(HIST("NclVsPhipBeforeCutPID"), pOrPt, phiPrime, nclPID); + + if (v0Selections.applyPhiCut) { + if (!passesPhiSelection(pOrPt, phiPrime)) + continue; + } + + if (v0Selections.applyEtaCal && etaCal.isMIPCalLoaded) { + const double dedxCal{etaCal.pEtaCal->GetBinContent(etaCal.pEtaCal->FindBin(eta))}; + if (dedxCal > kMindEdxMIP && dedxCal < kMaxdEdxMIP) + dedx *= (50.0 / dedxCal); + else + continue; + } + + int indexEta{-999}; + for (int i = 0; i < kNEtaHists; ++i) { + if (eta >= kLowEta[i] && eta < kHighEta[i]) { + indexEta = i; + break; + } + } + + if (indexEta < kZeroInt || indexEta > kSevenInt) + continue; + + if (momentum > kMinPMIP && momentum < kMaxPMIP && dedx > kMindEdxMIP && dedx < kMaxdEdxMIP) { + registry.fill(HIST("dEdxVsEtaPiMIP"), eta, dedx); + registry.fill(HIST("dEdxVsEtaPiMIPp"), eta, dedx); + registry.fill(HIST("NclVsEtaPiMIP"), eta, ncl); + registry.fill(HIST("NclVsEtaPiMIPp"), eta, ncl); + } + + if (momentum > kMinPElMIP && momentum < kMaxPElMIP && dedx > kMindEdxMIPPlateau && dedx < kMaxdEdxMIPPlateau) { + registry.fill(HIST("dEdxVsEtaElMIP"), eta, dedx); + registry.fill(HIST("dEdxVsEtaElMIPp"), eta, dedx); + } + + dEdx[indexEta]->Fill(momentum, dedx, centrality); + pTVsP[indexEta]->Fill(momentum, pt); + nClVsP[indexEta]->Fill(pOrPt, ncl); + nClVsPp[indexEta]->Fill(pOrPt, ncl); + registry.fill(HIST("pTVsCent"), pt, centrality); + registry.fill(HIST("EtaVsPhi"), eta, track.phi()); + registry.fill(HIST("NclVsEta"), eta, nclFound); + registry.fill(HIST("NclVsEtap"), eta, nclFound); + registry.fill(HIST("NclVsEtaPID"), eta, nclPID); + registry.fill(HIST("NclVsEtaPIDp"), eta, nclPID); + // registry.fill(HIST("NclFindable"), pOrPt, track.tpcNClsFindable()); + // registry.fill(HIST("NclFindablep"), pOrPt, track.tpcNClsFindable()); + registry.fill(HIST("NclVsPhipAfterCut"), pOrPt, phiPrime, nclFound); + registry.fill(HIST("NclVsPhipAfterCutPID"), pOrPt, phiPrime, nclPID); + + if (track.hasTOF() && track.goodTOFMatch()) { + const float tTOF{track.tofSignal()}; + const float trkLength{track.length()}; + const float tExpPiTOF{track.tofExpSignalPi(tTOF)}; + // const float tExpElTOF{track.tofExpSignalEl(tTOF)}; + + if (trkLength > kZero && tTOF > kZero) { + // registry.fill(HIST("betaVsMomentum"), momentum, track.beta()); + // registry.fill(HIST("TOFExpPi2TOF"), momentum, tExpPiTOF / tTOF); + // registry.fill(HIST("TOFExpEl2TOF"), momentum, tExpElTOF / tTOF); + + if (std::abs((tExpPiTOF / tTOF) - kOne) < v0Selections.maxExpTOFPi) { + dEdxPiTOF[indexEta]->Fill(momentum, dedx, centrality); + } + } + } + } + + for (const auto& v0 : v0s) { + + // Select V0 type + if (v0.v0Type() != v0Selections.v0TypeSelection) + continue; + + // Positive-(negative-)charged tracks (daughters) + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + const int posTrackCharge{posTrack.sign()}; + const int negTrackCharge{negTrack.sign()}; + const float posTrkP{posTrack.p()}; + const float negTrkP{negTrack.p()}; + const float posTrkPt{posTrack.pt()}; + const float negTrkPt{negTrack.pt()}; + const float posTrkEta{posTrack.eta()}; + const float negTrkEta{negTrack.eta()}; + float posTrkdEdx{posTrack.tpcSignal()}; + float negTrkdEdx{negTrack.tpcSignal()}; + float posTrackPhiPrime{posTrack.phi()}; + float negTrackPhiPrime{negTrack.phi()}; + const int16_t posNclFound{posTrack.tpcNClsFound()}; + const int16_t negNclFound{negTrack.tpcNClsFound()}; + const int16_t posNclPID{posTrack.tpcNClsPID()}; + const int16_t negNclPID{negTrack.tpcNClsPID()}; + const int16_t posNcl = v0Selections.useNclsPID ? posNclPID : posNclFound; + const int16_t negNcl = v0Selections.useNclsPID ? negNclPID : negNclFound; + + phiPrimeFunc(posTrackPhiPrime, magField, posTrackCharge); + phiPrimeFunc(negTrackPhiPrime, magField, negTrackCharge); + const float posPorPt{v0Selections.usePinPhiSelection ? posTrkP : posTrkPt}; + const float negPorPt{v0Selections.usePinPhiSelection ? negTrkP : negTrkPt}; + + // Skip v0s with like-sig daughters + if (posTrack.sign() == negTrack.sign()) + continue; + + // Passes Geometrical (Phi) cut? + if (v0Selections.applyPhiCut) { + if (!(passesPhiSelection(posPorPt, posTrackPhiPrime) && passesPhiSelection(negPorPt, negTrackPhiPrime))) + continue; + } + + // Passes daughters track-selection? + if (!(passesTrackSelectionDaughters(posTrack) && passesTrackSelectionDaughters(negTrack))) + continue; + + if (v0Selections.applyNclSel && !(posNcl >= v0Selections.minNcl && negNcl >= v0Selections.minNcl)) + continue; + + if (v0Selections.applyEtaCal && etaCal.isMIPCalLoaded) { + const double dedxCal{etaCal.pEtaCal->GetBinContent(etaCal.pEtaCal->FindBin(posTrkEta))}; + if (dedxCal > kMindEdxMIP && dedxCal < kMaxdEdxMIP) + posTrkdEdx *= (50.0 / dedxCal); + else + continue; + } + + if (v0Selections.applyEtaCal && etaCal.isMIPCalLoaded) { + const double dedxCal{etaCal.pEtaCal->GetBinContent(etaCal.pEtaCal->FindBin(negTrkEta))}; + if (dedxCal > kMindEdxMIP && dedxCal < kMaxdEdxMIP) + negTrkdEdx *= (50.0 / dedxCal); + else + continue; + } + + const TVector3 ppos(posTrack.px(), posTrack.py(), posTrack.pz()); + const TVector3 pneg(negTrack.px(), negTrack.py(), negTrack.pz()); + double alpha, qT; + + getArmeterosVariables(ppos, pneg, alpha, qT); + registry.fill(HIST("ArmAll"), alpha, qT); + + bool passesTopoSel{false}; + // Passes V0 topological cuts? + if (passesV0TopologicalSelection(v0)) + passesTopoSel = true; + + if (!passesTopoSel) + continue; + + const double dMassK0s{std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short)}; + const double dMassL{std::abs(v0.mLambda() - o2::constants::physics::MassLambda0)}; + const double dMassAL{std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0)}; + const double dMassG{std::abs(v0.mGamma() - o2::constants::physics::MassGamma)}; + + int posIndexEta{-999}; + int negIndexEta{-999}; + for (int i = 0; i < kNEtaHists; ++i) { + if (posTrkEta >= kLowEta[i] && posTrkEta < kHighEta[i]) { + posIndexEta = i; + break; + } + } + + for (int i = 0; i < kNEtaHists; ++i) { + if (negTrkEta >= kLowEta[i] && negTrkEta < kHighEta[i]) { + negIndexEta = i; + break; + } + } + + if (posIndexEta < kZeroInt || posIndexEta > kSevenInt) + continue; + + if (negIndexEta < kZeroInt || negIndexEta > kSevenInt) + continue; + + registry.fill(HIST("ArmAfterTopoSel"), alpha, qT); + registry.fill(HIST("dcaDauVsPt"), v0.pt(), v0.dcapostopv()); + registry.fill(HIST("dcaDauVsPt"), v0.pt(), v0.dcanegtopv()); + + bool isMassK0s{true}; + bool isMassL{true}; + bool isMassAL{true}; + bool isMassG{true}; + if (v0Selections.applyInvMassSel) { // apply Inv. Mass selection? + if (!(dMassK0s < v0Selections.dMassSel && dMassL > v0Selections.dMassSel && dMassAL > v0Selections.dMassSel && dMassG > v0Selections.dMassSelG)) + isMassK0s = false; + + if (!(dMassL < v0Selections.dMassSel && dMassK0s > v0Selections.dMassSel && dMassG > v0Selections.dMassSelG)) + isMassL = false; + + if (!(dMassAL < v0Selections.dMassSel && dMassK0s > v0Selections.dMassSel && dMassG > v0Selections.dMassSelG)) + isMassAL = false; + + if (!(dMassK0s > v0Selections.dMassSel && dMassL > v0Selections.dMassSel && dMassAL > v0Selections.dMassSel && dMassG < v0Selections.dMassSel)) + isMassG = false; + } + + if (passesK0Selection(collision, v0)) { // nSigma TPC and y cuts + if (isMassK0s) { // apply Inv. Mass selection? + registry.fill(HIST("ArmK0NOSel"), alpha, qT); + if (v0Selections.armPodCut * qT > std::abs(alpha)) { // Armenters selection + registry.fill(HIST("V0sCounter"), V0sCounter::K0s); + registry.fill(HIST("ArmK0"), alpha, qT); + registry.fill(HIST("MassK0sVsPt"), v0.pt(), v0.mK0Short()); + registry.fill(HIST("nSigPiFromK0s"), posTrkPt, posTrack.tpcNSigmaPi()); + registry.fill(HIST("nSigPiFromK0s"), negTrkPt, negTrack.tpcNSigmaPi()); + registry.fill(HIST("NclVsEtaPiV0"), posTrkEta, posNcl); + registry.fill(HIST("NclVsEtaPiV0p"), posTrkEta, posNcl); + registry.fill(HIST("NclVsEtaPiV0"), negTrkEta, negNcl); + registry.fill(HIST("NclVsEtaPiV0p"), negTrkEta, negNcl); + nClVsPPiV0[posIndexEta]->Fill(posPorPt, posNcl); + nClVsPpPiV0[posIndexEta]->Fill(posPorPt, posNcl); + nClVsPPiV0[negIndexEta]->Fill(negPorPt, negNcl); + nClVsdEdxPiV0[negIndexEta]->Fill(negNcl, negTrkdEdx); + nClVsdEdxpPiV0[negIndexEta]->Fill(negNcl, negTrkdEdx); + nClVsdEdxPiV0[posIndexEta]->Fill(posNcl, posTrkdEdx); + nClVsdEdxpPiV0[posIndexEta]->Fill(posNcl, posTrkdEdx); + nClVsPpPiV0[negIndexEta]->Fill(negPorPt, negNcl); + dEdxPiV0[posIndexEta]->Fill(posTrkP, posTrkdEdx, centrality); + dEdxPiV0[negIndexEta]->Fill(negTrkP, negTrkdEdx, centrality); + registry.fill(HIST("DCAxyDCAzPiK0s"), posTrack.dcaXY(), posTrack.dcaZ()); + + if (posTrkP > kMinPMIP && posTrkP < kMaxPMIP && posTrkdEdx > kMindEdxMIP && posTrkdEdx < kMaxdEdxMIP) { + registry.fill(HIST("dEdxVsEtaPiMIPV0"), posTrkEta, posTrkdEdx); + registry.fill(HIST("dEdxVsEtaPiMIPV0p"), posTrkEta, posTrkdEdx); + } + if (negTrkP > kMinPMIP && negTrkP < kMaxPMIP && negTrkdEdx > kMindEdxMIP && negTrkdEdx < kMaxdEdxMIP) { + registry.fill(HIST("dEdxVsEtaPiMIPV0"), negTrkEta, negTrkdEdx); + registry.fill(HIST("dEdxVsEtaPiMIPV0p"), negTrkEta, negTrkdEdx); + } + } + } + } + + if (passesLambdaSelection(collision, v0)) { + if (isMassL) { + registry.fill(HIST("V0sCounter"), V0sCounter::Lambda); + registry.fill(HIST("ArmL"), alpha, qT); + registry.fill(HIST("MassLVsPt"), v0.pt(), v0.mLambda()); + if (posTrackCharge > kZero) { + registry.fill(HIST("nSigPrFromL"), posTrkPt, posTrack.tpcNSigmaPr()); + registry.fill(HIST("NclVsEtaPrV0"), posTrkEta, posNcl); + registry.fill(HIST("NclVsEtaPrV0p"), posTrkEta, posNcl); + nClVsPPrV0[posIndexEta]->Fill(posPorPt, posNcl); + nClVsPpPrV0[posIndexEta]->Fill(posPorPt, posNcl); + nClVsdEdxPrV0[posIndexEta]->Fill(posNcl, posTrkdEdx); + nClVsdEdxpPrV0[posIndexEta]->Fill(posNcl, posTrkdEdx); + dEdxPrV0[posIndexEta]->Fill(posTrkP, posTrkdEdx, centrality); + registry.fill(HIST("DCAxyDCAzPrL"), posTrack.dcaXY(), posTrack.dcaZ()); + } + if (negTrackCharge < kZero) { + registry.fill(HIST("nSigPiFromL"), negTrkPt, negTrack.tpcNSigmaPi()); + registry.fill(HIST("NclVsEtaPiV0"), negTrkEta, negNcl); + registry.fill(HIST("NclVsEtaPiV0p"), negTrkEta, negNcl); + nClVsPPiV0[negIndexEta]->Fill(negPorPt, negNcl); + nClVsPpPiV0[negIndexEta]->Fill(negPorPt, negNcl); + nClVsdEdxPiV0[negIndexEta]->Fill(negNcl, negTrkdEdx); + nClVsdEdxpPiV0[negIndexEta]->Fill(negNcl, negTrkdEdx); + dEdxPiV0[negIndexEta]->Fill(negTrkP, negTrkdEdx, centrality); + } + } + } + + if (passesAntiLambdaSelection(collision, v0)) { + if (isMassAL) { + registry.fill(HIST("V0sCounter"), V0sCounter::AntiLambda); + registry.fill(HIST("ArmAL"), alpha, qT); + registry.fill(HIST("MassALVsPt"), v0.pt(), v0.mAntiLambda()); + if (posTrackCharge > kZero) { + registry.fill(HIST("nSigPiFromAL"), posTrkPt, posTrack.tpcNSigmaPi()); + registry.fill(HIST("NclVsEtaPiV0"), posTrkEta, posNcl); + registry.fill(HIST("NclVsEtaPiV0p"), posTrkEta, posNcl); + nClVsPPiV0[posIndexEta]->Fill(posPorPt, posNcl); + nClVsPpPiV0[posIndexEta]->Fill(posPorPt, posNcl); + nClVsdEdxPiV0[posIndexEta]->Fill(posNcl, posTrkdEdx); + nClVsdEdxpPiV0[posIndexEta]->Fill(posNcl, posTrkdEdx); + dEdxPiV0[posIndexEta]->Fill(posTrkP, posTrkdEdx, centrality); + } + if (negTrackCharge < kZero) { + registry.fill(HIST("nSigPrFromAL"), negTrkPt, negTrack.tpcNSigmaPr()); + registry.fill(HIST("NclVsEtaPrV0"), negTrkEta, negNcl); + registry.fill(HIST("NclVsEtaPrV0p"), negTrkEta, negNcl); + nClVsPPrV0[negIndexEta]->Fill(negPorPt, negNcl); + nClVsPpPrV0[negIndexEta]->Fill(negPorPt, negNcl); + nClVsdEdxPrV0[negIndexEta]->Fill(negNcl, negTrkdEdx); + nClVsdEdxpPrV0[negIndexEta]->Fill(negNcl, negTrkdEdx); + registry.fill(HIST("DCAxyDCAzPrAL"), negTrack.dcaXY(), negTrack.dcaZ()); + dEdxPrV0[negIndexEta]->Fill(negTrkP, negTrkdEdx, centrality); + } + } + } + + if (passesGammaSelection(collision, v0)) { + if (isMassG) { + if (std::abs(alpha) < v0Selections.armAlphaSel && qT < v0Selections.qTSel) { + + if (v0Selections.applyPlateauSel && etaCal.isCalPlateauLoaded) { + const double posDedxCal{etaCal.pEtaCalPlateau->GetBinContent(etaCal.pEtaCalPlateau->FindBin(posTrkEta))}; + const double negDedxCal{etaCal.pEtaCalPlateau->GetBinContent(etaCal.pEtaCalPlateau->FindBin(negTrkEta))}; + if (!(std::abs(posTrkdEdx - posDedxCal) < v0Selections.dEdxPlateauSel && std::abs(negTrkdEdx - negDedxCal) < v0Selections.dEdxPlateauSel)) + continue; + } + + registry.fill(HIST("V0sCounter"), V0sCounter::Gamma); + registry.fill(HIST("ArmG"), alpha, qT); + registry.fill(HIST("MassGVsPt"), v0.pt(), v0.mGamma()); + registry.fill(HIST("nSigElFromG"), negTrkPt, negTrack.tpcNSigmaEl()); + registry.fill(HIST("nSigElFromG"), posTrkPt, posTrack.tpcNSigmaEl()); + registry.fill(HIST("NclVsEtaElV0"), posTrkEta, posNcl); + registry.fill(HIST("NclVsEtaElV0p"), posTrkEta, posNcl); + registry.fill(HIST("NclVsEtaElV0"), negTrkEta, negNcl); + registry.fill(HIST("NclVsEtaElV0p"), negTrkEta, negNcl); + nClVsPElV0[negIndexEta]->Fill(negPorPt, negNcl); + nClVsPpElV0[negIndexEta]->Fill(negPorPt, negNcl); + nClVsPElV0[posIndexEta]->Fill(posPorPt, posNcl); + nClVsPpElV0[posIndexEta]->Fill(posPorPt, posNcl); + nClVsdEdxElV0[negIndexEta]->Fill(negNcl, negTrkdEdx); + nClVsdEdxpElV0[negIndexEta]->Fill(negNcl, negTrkdEdx); + nClVsdEdxElV0[posIndexEta]->Fill(posNcl, posTrkdEdx); + nClVsdEdxpElV0[posIndexEta]->Fill(posNcl, posTrkdEdx); + registry.fill(HIST("dEdxVsEtaElMIPV0"), posTrkEta, posTrkdEdx); + registry.fill(HIST("dEdxVsEtaElMIPV0p"), posTrkEta, posTrkdEdx); + registry.fill(HIST("dEdxVsEtaElMIPV0"), negTrkEta, negTrkdEdx); + registry.fill(HIST("dEdxVsEtaElMIPV0p"), negTrkEta, negTrkdEdx); + dEdxElV0[posIndexEta]->Fill(posTrkP, posTrkdEdx, centrality); + dEdxElV0[negIndexEta]->Fill(negTrkP, negTrkdEdx, centrality); + } + } + } + } // v0s + } + PROCESS_SWITCH(PiKpRAA, processCalibrationAndV0s, "Process QA", true); + + Preslice perCollision = aod::track::collisionId; + Service pdg; + void processMC(aod::McCollisions::iterator const& mccollision, soa::SmallGroups const& collisions, BCsRun3 const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::McParticles const& mcParticles, TracksMC const& tracksMC) + { + for (const auto& collision : collisions) { + // Event selection + if (!isEventSelected(collision)) { + continue; + } + // MC collision? + if (!collision.has_mcCollision()) { + continue; + } + + registry.fill(HIST("EventCounterMC"), EvCutLabel::All); + + if (std::fabs(mccollision.posZ()) > posZcut) + continue; + + registry.fill(HIST("zPos"), collision.posZ()); + registry.fill(HIST("zPosMC"), mccollision.posZ()); + registry.fill(HIST("EventCounterMC"), EvCutLabel::VtxZ); + + const auto& foundBC = collision.foundBC_as(); + uint64_t timeStamp{foundBC.timestamp()}; + const int magField{getMagneticField(timeStamp)}; + + if (v0Selections.applyPhiCut) { + const int nextRunNumber{foundBC.runNumber()}; + if (currentRunNumberPhiSel != nextRunNumber) { + loadPhiCutSelections(timeStamp); + currentRunNumberPhiSel = nextRunNumber; + LOG(info) << "\tcurrentRunNumberPhiSel= " << currentRunNumberPhiSel << " timeStamp = " << timeStamp; + } + + // return if phi cut objects are nullptr + if (!(phiCut.hPhiCutHigh && phiCut.hPhiCutLow)) + return; + } + + // Remove collisions if reconstructed more than once + if (skipRecoColGTOne && (collisions.size() > kOne)) + continue; + + const float centrality{isT0Ccent ? collision.centFT0C() : collision.centFT0M()}; + registry.fill(HIST("T0Ccent"), centrality); + + const auto& groupedTracks{tracksMC.sliceBy(perCollision, collision.globalIndex())}; + + // Track selection with Open DCAxy + for (const auto& track : groupedTracks) { + // Track Selection + if (track.eta() < v0Selections.minEtaDaughter || track.eta() > v0Selections.maxEtaDaughter) + continue; + + if (track.pt() < v0Selections.minPt || track.pt() > v0Selections.maxPt) + continue; + + if (!trkSelGlobalOpenDCAxy.IsSelected(track)) + continue; + + if (!track.has_mcParticle()) + continue; + + // Get the MC particle + const auto& particle{track.mcParticle()}; + auto charge{0.}; + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) + charge = pdgParticle->Charge(); + else + continue; + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + float phiPrime{track.phi()}; + phiPrimeFunc(phiPrime, magField, charge); + + const float pOrPt{v0Selections.usePinPhiSelection ? track.p() : track.pt()}; + if (v0Selections.applyPhiCut) { + if (!passesPhiSelection(pOrPt, phiPrime)) + continue; + } + + const int16_t nclFound{track.tpcNClsFound()}; + const int16_t nclPID{track.tpcNClsPID()}; + const int16_t ncl = v0Selections.useNclsPID ? nclPID : nclFound; + if (v0Selections.applyNclSel && ncl < v0Selections.minNcl) + continue; + + bool isPrimary{false}; + bool isDecay{false}; + bool isMaterial{false}; + if (particle.isPhysicalPrimary()) + isPrimary = true; + else if (particle.getProcess() == TMCProcess::kPDecay) + isDecay = true; + else + isMaterial = true; + + bool isPi{false}; + bool isPr{false}; + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) + isPi = true; + else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) + isPr = true; + else + continue; + + if (isPrimary && !isDecay && !isMaterial) { + if (isPi && !isPr) + registry.fill(HIST("dcaVsPtPi"), track.pt(), track.dcaXY(), centrality); + if (isPr && !isPi) + registry.fill(HIST("dcaVsPtPr"), track.pt(), track.dcaXY(), centrality); + } + + if (isDecay && !isPrimary && !isMaterial) { + if (isPi && !isPr) + registry.fill(HIST("dcaVsPtPiDec"), track.pt(), track.dcaXY(), centrality); + if (isPr && !isPi) + registry.fill(HIST("dcaVsPtPrDec"), track.pt(), track.dcaXY(), centrality); + } + + if (isMaterial && !isPrimary && !isDecay) { + if (isPi && !isPr) + registry.fill(HIST("dcaVsPtPiMat"), track.pt(), track.dcaXY(), centrality); + if (isPr && !isPi) + registry.fill(HIST("dcaVsPtPrMat"), track.pt(), track.dcaXY(), centrality); + } + } + + // Global track + DCAxy selections + for (const auto& track : groupedTracks) { + // Track Selection + if (track.eta() < v0Selections.minEtaDaughter || track.eta() > v0Selections.maxEtaDaughter) + continue; + + if (track.pt() < v0Selections.minPt || track.pt() > v0Selections.maxPt) + continue; + + if (!trkSelGlobal.IsSelected(track)) + continue; + + // Has MC particle? + if (!track.has_mcParticle()) + continue; + + // Get the MC particle + const auto& particle{track.mcParticle()}; + auto charge{0.}; + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) + charge = pdgParticle->Charge(); + else + continue; + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + float phiPrime{track.phi()}; + phiPrimeFunc(phiPrime, magField, charge); + + const float pOrPt{v0Selections.usePinPhiSelection ? track.p() : track.pt()}; + if (v0Selections.applyPhiCut) { + if (!passesPhiSelection(pOrPt, phiPrime)) + continue; + } + + const int16_t nclFound{track.tpcNClsFound()}; + const int16_t nclPID{track.tpcNClsPID()}; + const int16_t ncl = v0Selections.useNclsPID ? nclPID : nclFound; + if (v0Selections.applyNclSel && ncl < v0Selections.minNcl) + continue; + + int indexEta{-999}; + const float eta{track.eta()}; + for (int i = 0; i < kNEtaHists; ++i) { + if (eta >= kLowEta[i] && eta < kHighEta[i]) { + indexEta = i; + break; + } + } + + if (indexEta < kZeroInt || indexEta > kSevenInt) + continue; + + registry.fill(HIST("NclVsPhip"), pOrPt, phiPrime, ncl); + registry.fill(HIST("NclVsEtaPID"), eta, ncl); + registry.fill(HIST("NclVsEtaPIDp"), eta, ncl); + + bool isPrimary{false}; + if (particle.isPhysicalPrimary()) + isPrimary = true; + + if (!isPrimary) + continue; + + bool isPi{false}; + bool isKa{false}; + bool isPr{false}; + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) + isPi = true; + else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) + isKa = true; + else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) + isPr = true; + else + continue; + + if (isPi && !isKa && !isPr) + registry.fill(HIST("PtPiVsCent"), track.pt(), centrality); + if (isKa && !isPi && !isPr) + registry.fill(HIST("PtKaVsCent"), track.pt(), centrality); + if (isPr && !isPi && !isKa) + registry.fill(HIST("PtPrVsCent"), track.pt(), centrality); + } + + // Generated MC + for (const auto& particle : mcParticles) { + if (particle.eta() < v0Selections.minEtaDaughter || particle.eta() > v0Selections.maxEtaDaughter) + continue; + + if (particle.pt() < v0Selections.minPt || particle.pt() > v0Selections.maxPt) + continue; + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) + charge = pdgParticle->Charge(); + else + continue; + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + // Is it a primary particle? + bool isPrimary{true}; + if (!particle.isPhysicalPrimary()) + isPrimary = false; + + if (isPrimary) { + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) // pion + registry.fill(HIST("PtPiVsCentMC"), particle.pt(), centrality); + else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) // kaon + registry.fill(HIST("PtKaVsCentMC"), particle.pt(), centrality); + else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) // proton + registry.fill(HIST("PtPrVsCentMC"), particle.pt(), centrality); + else + continue; + } + } + } // Collisions + } + PROCESS_SWITCH(PiKpRAA, processMC, "Process MC closure", false); + + void processSim(aod::McCollisions::iterator const& mccollision, soa::SmallGroups const& collisions, BCsRun3 const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::McParticles const& mcParticles, TracksMC const& tracksMC) + { + + // Only INEL > 0 generated collisions + // By counting number of primary charged particles in |eta| < 1 + if (isINELgt0) { + int nChMC{0}; + for (const auto& particle : mcParticles) { + + if (std::abs(particle.eta()) > kOne) + continue; + + auto charge{0.}; + // Get the MC particle + const auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) + continue; + + nChMC++; + } + + // Only INEL > 0 generated events + if (!(nChMC > kZeroInt)) { + return; + } + } + + const auto& nRecColls{collisions.size()}; + + registry.fill(HIST("NumberOfRecoCollisions"), nRecColls); + + if (nRecColls > kZeroInt) { + + // Finds the collisions with the largest number of contributors + // in case nRecColls is larger than One + int biggestNContribs{-1}; + int bestCollisionIndex{-1}; + for (const auto& collision : collisions) { + if (biggestNContribs < collision.numContrib()) { + biggestNContribs = collision.numContrib(); + bestCollisionIndex = collision.globalIndex(); + } + + // Needed to calculate denominator of the Event Splitting correction + if (isEventSelected(collision)) { + const float centrality{isT0Ccent ? collision.centFT0C() : collision.centFT0M()}; + registry.fill(HIST("Centrality_AllRecoEvt"), centrality); + } + } + + for (const auto& collision : collisions) { + + // Choose the collisions with the largest number of contributors + if (bestCollisionIndex != collision.globalIndex()) { + continue; + } + + // Needed to load the Phi selection from the CCDB + const auto& foundBC = collision.foundBC_as(); + uint64_t timeStamp{foundBC.timestamp()}; + const int magField{getMagneticField(timeStamp)}; + + if (v0Selections.applyPhiCut) { + const int nextRunNumber{foundBC.runNumber()}; + if (currentRunNumberPhiSel != nextRunNumber) { + loadPhiCutSelections(timeStamp); + currentRunNumberPhiSel = nextRunNumber; + LOG(info) << "\tcurrentRunNumberPhiSel= " << currentRunNumberPhiSel << " timeStamp = " << timeStamp; + } + + // return if phi cut objects are nullptr + if (!(phiCut.hPhiCutHigh && phiCut.hPhiCutLow)) + return; + } + + // Needed to construct the correlation between MC Nch v.s. centrality + int nChMC{0}; + for (const auto& particle : mcParticles) { + if (particle.eta() < v0Selections.minEtaDaughter || particle.eta() > v0Selections.maxEtaDaughter) + continue; + + if (particle.pt() < v0Selections.minPt || particle.pt() > v0Selections.maxPt) + continue; + + auto charge{0.}; + // Get the MC particle + const auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) + continue; + + nChMC++; + } + + const float centrality{isT0Ccent ? collision.centFT0C() : collision.centFT0M()}; + registry.fill(HIST("Centrality_WRecoEvt"), centrality); + registry.fill(HIST("zPosMC"), mccollision.posZ()); + + //--------------------------- + // All Generated events with at least one associated reconstructed collision + // The Generated events are not subjected to any selection criteria + //--------------------------- + for (const auto& particle : mcParticles) { + if (particle.eta() < v0Selections.minEtaDaughter || particle.eta() > v0Selections.maxEtaDaughter) + continue; + + if (particle.pt() < v0Selections.minPt || particle.pt() > v0Selections.maxPt) + continue; + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + // Is it a primary particle? + bool isPrimary{true}; + if (!particle.isPhysicalPrimary()) + isPrimary = false; + + if (isPrimary) { + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtPiVsNchMC_WithRecoEvt"), particle.pt(), nChMC); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtKaVsNchMC_WithRecoEvt"), particle.pt(), nChMC); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtPrVsNchMC_WithRecoEvt"), particle.pt(), nChMC); + } else { + continue; + } + } + } // Loop over generated particles per generated collision + + //--------------------------- + // Reconstructed collisions subjected to selection criteria + //--------------------------- + + // Event selection + if (!isEventSelected(collision)) { + continue; + } + + registry.fill(HIST("Centrality_WRecoEvtWSelCri"), centrality); + registry.fill(HIST("NchMCVsCent"), centrality, nChMC); + registry.fill(HIST("NchMC_WithRecoEvt"), nChMC); + registry.fill(HIST("T0Ccent"), centrality); + registry.fill(HIST("zPos"), collision.posZ()); + + const auto& groupedTracks{tracksMC.sliceBy(perCollision, collision.globalIndex())}; + + // Track selection with Open DCAxy + for (const auto& track : groupedTracks) { + // Track Selection + if (track.eta() < v0Selections.minEtaDaughter || track.eta() > v0Selections.maxEtaDaughter) + continue; + + if (track.pt() < v0Selections.minPt || track.pt() > v0Selections.maxPt) + continue; + + if (!trkSelGlobalOpenDCAxy.IsSelected(track)) + continue; + + if (!track.has_mcParticle()) + continue; + + // Get the MC particle + const auto& particle{track.mcParticle()}; + auto charge{0.}; + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + float phiPrime{track.phi()}; + phiPrimeFunc(phiPrime, magField, charge); + + const float pOrPt{v0Selections.usePinPhiSelection ? track.p() : track.pt()}; + if (v0Selections.applyPhiCut) { + if (!passesPhiSelection(pOrPt, phiPrime)) + continue; + } + + const int16_t nclFound{track.tpcNClsFound()}; + const int16_t nclPID{track.tpcNClsPID()}; + const int16_t ncl = v0Selections.useNclsPID ? nclPID : nclFound; + if (v0Selections.applyNclSel && ncl < v0Selections.minNcl) + continue; + + bool isPrimary{false}; + bool isDecay{false}; + bool isMaterial{false}; + if (particle.isPhysicalPrimary()) { + isPrimary = true; + } else if (particle.getProcess() == TMCProcess::kPDecay) { + isDecay = true; + } else { + isMaterial = true; + } + + bool isPi{false}; + bool isPr{false}; + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + isPi = true; + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + isPr = true; + } else { + continue; + } + + if (isPrimary && !isDecay && !isMaterial) { + if (isPi && !isPr) + registry.fill(HIST("dcaVsPtPi"), track.pt(), track.dcaXY(), centrality); + if (isPr && !isPi) + registry.fill(HIST("dcaVsPtPr"), track.pt(), track.dcaXY(), centrality); + } + + if (isDecay && !isPrimary && !isMaterial) { + if (isPi && !isPr) + registry.fill(HIST("dcaVsPtPiDec"), track.pt(), track.dcaXY(), centrality); + if (isPr && !isPi) + registry.fill(HIST("dcaVsPtPrDec"), track.pt(), track.dcaXY(), centrality); + } + + if (isMaterial && !isPrimary && !isDecay) { + if (isPi && !isPr) + registry.fill(HIST("dcaVsPtPiMat"), track.pt(), track.dcaXY(), centrality); + if (isPr && !isPi) + registry.fill(HIST("dcaVsPtPrMat"), track.pt(), track.dcaXY(), centrality); + } + } + + // Global track + DCAxy selections + for (const auto& track : groupedTracks) { + // Track Selection + if (track.eta() < v0Selections.minEtaDaughter || track.eta() > v0Selections.maxEtaDaughter) + continue; + + if (track.pt() < v0Selections.minPt || track.pt() > v0Selections.maxPt) + continue; + + if (!trkSelGlobal.IsSelected(track)) + continue; + + // Has MC particle? + if (!track.has_mcParticle()) + continue; + + // Get the MC particle + const auto& particle{track.mcParticle()}; + auto charge{0.}; + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + float phiPrime{track.phi()}; + phiPrimeFunc(phiPrime, magField, charge); + + const float pOrPt{v0Selections.usePinPhiSelection ? track.p() : track.pt()}; + if (v0Selections.applyPhiCut) { + if (!passesPhiSelection(pOrPt, phiPrime)) + continue; + } + + const int16_t nclFound{track.tpcNClsFound()}; + const int16_t nclPID{track.tpcNClsPID()}; + const int16_t ncl = v0Selections.useNclsPID ? nclPID : nclFound; + if (v0Selections.applyNclSel && ncl < v0Selections.minNcl) + continue; + + int indexEta{-999}; + const float eta{track.eta()}; + for (int i = 0; i < kNEtaHists; ++i) { + if (eta >= kLowEta[i] && eta < kHighEta[i]) { + indexEta = i; + break; + } + } + + if (indexEta < kZeroInt || indexEta > kSevenInt) + continue; + + registry.fill(HIST("NclVsPhip"), pOrPt, phiPrime, ncl); + registry.fill(HIST("NclVsEtaPID"), eta, ncl); + registry.fill(HIST("NclVsEtaPIDp"), eta, ncl); + + bool isPrimary{false}; + if (particle.isPhysicalPrimary()) + isPrimary = true; + + if (!isPrimary) + continue; + + bool isPi{false}; + bool isKa{false}; + bool isPr{false}; + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + isPi = true; + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + isKa = true; + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + isPr = true; + } else { + continue; + } + + if (isPi && !isKa && !isPr) + registry.fill(HIST("PtPiVsCent_WithRecoEvt"), track.pt(), centrality); + if (isKa && !isPi && !isPr) + registry.fill(HIST("PtKaVsCent_WithRecoEvt"), track.pt(), centrality); + if (isPr && !isPi && !isKa) + registry.fill(HIST("PtPrVsCent_WithRecoEvt"), track.pt(), centrality); + + registry.fill(HIST("PtResolution"), particle.pt(), (track.pt() - particle.pt()) / particle.pt()); + } // Loop over reconstructed tracks + } // Loop over Reco. Collisions: These collisions are not required to pass the event selection + } // If condition: Only simulated evets with at least one reconstrued collision + + //--------------------------- + // All Generated events irrespective of whether there is an associated reconstructed collision + // Consequently, the centrality being a reconstructed quantity, might not always be available + // Therefore it is expressed as a function of the generated pT and the generated Nch in ∣eta∣ < 0.5 + //--------------------------- + + int nChMC{0}; + for (const auto& particle : mcParticles) { + if (particle.eta() < v0Selections.minEtaDaughter || particle.eta() > v0Selections.maxEtaDaughter) + continue; + + if (particle.pt() < v0Selections.minPt || particle.pt() > v0Selections.maxPt) + continue; + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) + continue; + + nChMC++; + } + + for (const auto& particle : mcParticles) { + if (particle.eta() < v0Selections.minEtaDaughter || particle.eta() > v0Selections.maxEtaDaughter) + continue; + + if (particle.pt() < v0Selections.minPt || particle.pt() > v0Selections.maxPt) + continue; + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < kMinCharge) + continue; + + // Is it a primary particle? + bool isPrimary{true}; + if (!particle.isPhysicalPrimary()) + isPrimary = false; + + if (isPrimary) { + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsNchMC_AllGen"), particle.pt(), nChMC); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsNchMC_AllGen"), particle.pt(), nChMC); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsNchMC_AllGen"), particle.pt(), nChMC); + } else { + continue; + } + } + } // Loop over Generated Particles + registry.fill(HIST("NchMC_AllGen"), nChMC); + } + PROCESS_SWITCH(PiKpRAA, processSim, "Process Sim", false); + + template + void getArmeterosVariables(const T& ppos, const T& pneg, U& alpha, U& qT) + { + + alpha = 0., qT = 0.; + TVector3 pV0 = ppos + pneg; + double pV0mag = pV0.Mag(); + if (pV0mag < kTenToMinusNine) + return; // protect against zero momentum + + const TVector3 u = pV0 * (1.0 / pV0mag); + + double pLpos = ppos.Dot(u); + double pLneg = pneg.Dot(u); + + // qT: transverse momentum of the + track w.r.t. V0 direction + TVector3 pTpos = ppos - pLpos * u; + qT = pTpos.Mag(); + + // α: longitudinal asymmetry (uses + and − labels by charge) + double denom = pLpos + pLneg; + if (std::abs(denom) < kTenToMinusNine) + return; // avoid 0 division (unphysical for V0s) + + alpha = (pLpos - pLneg) / denom; // equivalently / pV0mag + } + + // Daughters DCA selection + template + bool passesDCASelectionDaughters(const T& v0) + { + + bool isSelected{false}; + const double dcaPos{std::fabs(v0.dcapostopv())}; + const double dcaNeg{std::fabs(v0.dcanegtopv())}; + + isSelected = dcaPos > v0Selections.dcapostopv && dcaNeg > v0Selections.dcanegtopv ? true : false; + return isSelected; + } + + template + bool passesTrackSelectionDaughters(const T& track) + { + + // Secondary particle selection are basically Global tracks excluding the DCAxy selection + // This approach was used in the Run 2 analyses + // https://github.com/AliceO2Group/O2Physics/blob/b178c96d03ede873ee769ef8a4d7c1e21bf78332/Common/Core/TrackSelectionDefaults.cxx + const float pt{track.pt()}; + const float eta{track.eta()}; + const int16_t nCrossedRows{track.tpcNClsCrossedRows()}; + const float nCrossedRowsOverFindableCls{track.tpcCrossedRowsOverFindableCls()}; + const float chi2PerClsTPC{track.tpcChi2NCl()}; + const float chi2PerClsITS{track.itsChi2NCl()}; + const bool refitITS{track.passedITSRefit()}; + const bool refitTPC{track.passedTPCRefit()}; + const bool goldeChi2{track.passedGoldenChi2()}; + const bool oneHitITSib{track.passedITSHitsFB1()}; + + bool etaSel{false}; + bool ptSel{false}; + bool xRows{false}; + bool xRowsToFindCls{false}; + bool chi2TPC{false}; + bool chi2ITS{false}; + bool itsrefit{false}; + bool tpcrefit{false}; + bool golden{false}; + bool itshit{false}; + + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::AllTrks); + if (eta > v0Selections.minEtaDaughter && eta < v0Selections.maxEtaDaughter) { + etaSel = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::Eta); + } + if (pt > v0Selections.minPtDaughter && pt < v0Selections.maxPtDaughter) { + ptSel = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::Pt); + } + if (nCrossedRows >= v0Selections.minNCrossedRows) { + xRows = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::XRows); + } + if (nCrossedRowsOverFindableCls >= v0Selections.minNCrossedRowsOverFindableCls) { + xRowsToFindCls = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::XRowsOverFindableCls); + } + if (chi2PerClsTPC < v0Selections.maxChi2ClsTPC) { + chi2TPC = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::Chi2TPC); + } + if (chi2PerClsITS < v0Selections.maxChi2ClsITS) { + chi2ITS = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::Chi2ITS); + } + if (refitITS == v0Selections.itsRefit) { + itsrefit = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::Itsrefit); + } + if (refitTPC == v0Selections.tpcRefit) { + tpcrefit = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::Tpcrefit); + } + if (goldeChi2 == v0Selections.chi2Golden) { + golden = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::Golden); + } + if (oneHitITSib == v0Selections.its1HitIB) { + itshit = true; + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::Itshit); + } + + bool isSelected{false}; + if (!v0Selections.selElecFromGammas && v0Selections.requireITShit) + isSelected = etaSel && ptSel && xRows && xRowsToFindCls && chi2TPC && chi2ITS && itsrefit && tpcrefit && golden && itshit ? true : false; + if (!v0Selections.selElecFromGammas && !v0Selections.requireITShit) + isSelected = etaSel && ptSel && xRows && xRowsToFindCls && chi2TPC && chi2ITS && itsrefit && tpcrefit && golden ? true : false; + if (v0Selections.selElecFromGammas) { + isSelected = etaSel && ptSel && xRows && xRowsToFindCls && chi2TPC && chi2ITS && tpcrefit && golden ? true : false; + } + + if (isSelected == true) + registry.fill(HIST("TrackDaughterCounter"), TrkSelLabel::PassedAll); + + return isSelected; + } + + // V0 topological selection + template + bool passesV0TopologicalSelection(const T& v0) + { + + bool isSelected = v0.v0radius() > v0Selections.v0radius && v0.v0radius() < v0Selections.v0radiusMax && passesDCASelectionDaughters(v0) && v0.v0cosPA() > v0Selections.v0cospa && v0.dcaV0daughters() < v0Selections.dcav0dau ? true : false; + + return isSelected; + } + + template + bool passesK0Selection(const C& collision, const T& v0) + { + // Selection on rapiditty, proper lifetime, and Nsigma Pion + + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + const float posTPCNsigma{std::fabs(posTrack.tpcNSigmaPi())}; + const float negTPCNsigma{std::fabs(negTrack.tpcNSigmaPi())}; + const float posTOFNsigma{std::fabs(posTrack.tofNSigmaPi())}; + const float negTOFNsigma{std::fabs(negTrack.tofNSigmaPi())}; + const double posRadiusNsigma{std::sqrt(std::pow(posTPCNsigma, 2.) + std::pow(posTOFNsigma, 2.))}; + const double negRadiusNsigma{std::sqrt(std::pow(negTPCNsigma, 2.) + std::pow(negTOFNsigma, 2.))}; + + registry.fill(HIST("EtaVsYK0s"), negTrack.eta(), v0.yK0Short()); + registry.fill(HIST("EtaVsYK0s"), posTrack.eta(), v0.yK0Short()); + + bool isSelected{false}; + if (v0Selections.applyTPCTOFCombinedCut) + isSelected = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < lifetimecut->get("lifetimecutK0S") && std::abs(v0.yK0Short()) < v0Selections.rapidityCut && posTrack.hasTOF() && negTrack.hasTOF() && posRadiusNsigma < v0Selections.tpcPidNsigmaCut && negRadiusNsigma < v0Selections.tpcPidNsigmaCut ? true : false; + else + isSelected = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < lifetimecut->get("lifetimecutK0S") && std::abs(v0.yK0Short()) < v0Selections.rapidityCut && posTPCNsigma < v0Selections.tpcPidNsigmaCut && negTPCNsigma < v0Selections.tpcPidNsigmaCut ? true : false; + + return isSelected; + } + + template + bool passesLambdaSelection(const C& collision, const T& v0) + { + // Selection on rapiditty, proper lifetime, and Nsigma Pion + + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + const float posTPCNsigma{std::fabs(posTrack.tpcNSigmaPr())}; + const float negTPCNsigma{std::fabs(negTrack.tpcNSigmaPi())}; + const float posTOFNsigma{std::fabs(posTrack.tofNSigmaPr())}; + const float negTOFNsigma{std::fabs(negTrack.tofNSigmaPi())}; + const double posRadiusNsigma{std::sqrt(std::pow(posTPCNsigma, 2.) + std::pow(posTOFNsigma, 2.))}; + const double negRadiusNsigma{std::sqrt(std::pow(negTPCNsigma, 2.) + std::pow(negTOFNsigma, 2.))}; + + registry.fill(HIST("EtaVsYPiL"), negTrack.eta(), v0.yLambda()); + registry.fill(HIST("EtaVsYPrL"), posTrack.eta(), v0.yLambda()); + + bool isSelected{false}; + if (v0Selections.applyTPCTOFCombinedCut) + isSelected = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < lifetimecut->get("lifetimecutLambda") && std::abs(v0.yLambda()) < v0Selections.rapidityCut && posTrack.hasTOF() && negTrack.hasTOF() && posRadiusNsigma < v0Selections.tpcPidNsigmaCut && negRadiusNsigma < v0Selections.tpcPidNsigmaCut ? true : false; + else + isSelected = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < lifetimecut->get("lifetimecutLambda") && std::abs(v0.yLambda()) < v0Selections.rapidityCut && posTPCNsigma < v0Selections.tpcPidNsigmaCut && negTPCNsigma < v0Selections.tpcPidNsigmaCut ? true : false; + + return isSelected; + } + + template + bool passesAntiLambdaSelection(const C& collision, const T& v0) + { + // Selection on rapiditty, proper lifetime, and Nsigma Pion + + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + const float posTPCNsigma{std::fabs(posTrack.tpcNSigmaPi())}; + const float negTPCNsigma{std::fabs(negTrack.tpcNSigmaPr())}; + const float posTOFNsigma{std::fabs(posTrack.tofNSigmaPi())}; + const float negTOFNsigma{std::fabs(negTrack.tofNSigmaPr())}; + const double posRadiusNsigma{std::sqrt(std::pow(posTPCNsigma, 2.) + std::pow(posTOFNsigma, 2.))}; + const double negRadiusNsigma{std::sqrt(std::pow(negTPCNsigma, 2.) + std::pow(negTOFNsigma, 2.))}; + + registry.fill(HIST("EtaVsYPiAL"), posTrack.eta(), v0.yLambda()); + registry.fill(HIST("EtaVsYPrAL"), negTrack.eta(), v0.yLambda()); + + bool isSelected{false}; + if (v0Selections.applyTPCTOFCombinedCut) + isSelected = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < lifetimecut->get("lifetimecutLambda") && std::abs(v0.yLambda()) < v0Selections.rapidityCut && posTrack.hasTOF() && negTrack.hasTOF() && posRadiusNsigma < v0Selections.tpcPidNsigmaCut && negRadiusNsigma < v0Selections.tpcPidNsigmaCut ? true : false; + else + isSelected = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < lifetimecut->get("lifetimecutLambda") && std::abs(v0.yLambda()) < v0Selections.rapidityCut && posTPCNsigma < v0Selections.tpcPidNsigmaCut && negTPCNsigma < v0Selections.tpcPidNsigmaCut ? true : false; + + return isSelected; + } + + template + bool passesGammaSelection(const C& /*collision*/, const T& v0) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + const float posTPCNsigma{std::fabs(posTrack.tpcNSigmaEl())}; + const float negTPCNsigma{std::fabs(negTrack.tpcNSigmaEl())}; + const float posTOFNsigma{std::fabs(posTrack.tofNSigmaEl())}; + const float negTOFNsigma{std::fabs(negTrack.tofNSigmaEl())}; + const double posRadiusNsigma{std::sqrt(std::pow(posTPCNsigma, 2.) + std::pow(posTOFNsigma, 2.))}; + const double negRadiusNsigma{std::sqrt(std::pow(negTPCNsigma, 2.) + std::pow(negTOFNsigma, 2.))}; + const float yGamma = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma); + + registry.fill(HIST("EtaVsYG"), negTrack.eta(), yGamma); + registry.fill(HIST("EtaVsYG"), posTrack.eta(), yGamma); + + if (!(std::abs(yGamma) < v0Selections.rapidityCut)) + return false; + + bool isSelected{false}; + if (v0Selections.applyTPCTOFCombinedCut) + isSelected = posTrack.hasTOF() && negTrack.hasTOF() && posRadiusNsigma < v0Selections.tpcPidNsigmaCut && negRadiusNsigma < v0Selections.tpcPidNsigmaCut ? true : false; + else + isSelected = posTPCNsigma < v0Selections.tpcPidNsigmaCut && negTPCNsigma < v0Selections.tpcPidNsigmaCut ? true : false; + + return isSelected; + } + + int getMagneticField(uint64_t timestamp) + { + // TODO done only once (and not per run). Will be replaced by CCDBConfigurable + 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 phiPrimeFunc(float& phi, const int& magField, const int& charge) + { + + if (magField < 0) + phi = o2::constants::math::TwoPI - phi; + if (charge < 0) + phi = o2::constants::math::TwoPI - phi; + + phi += o2::constants::math::PI / 18.0f; + phi = std::fmod(phi, o2::constants::math::PI / 9.0f); + } + + bool passesPhiSelection(const float& pt, const float& phi) + { + + // Do not apply Phi Sel if pt < 2 GeV/c + if (pt < kTwoPtGeVSel) + return true; + + bool isSelected{true}; + if (phiCut.isPhiCutLoaded) { + const int binLow{phiCut.hPhiCutLow->FindBin(pt)}; + const int binHigh{phiCut.hPhiCutHigh->FindBin(pt)}; + const double phiCutLow{phiCut.hPhiCutLow->GetBinContent(binLow)}; + const double phiCutHigh{phiCut.hPhiCutHigh->GetBinContent(binHigh)}; + if (phi >= phiCutLow && phi <= phiCutHigh) + isSelected = false; + } + return isSelected; + } + + template + bool isEventSelected(CheckCol const& col) + { + registry.fill(HIST("EventCounter"), EvCutLabel::All); + if (!col.sel8()) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::SelEigth); + + if (!col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::NoSameBunchPileup); + + if (!col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::IsGoodZvtxFT0vsPV); + + if (isNoCollInTimeRangeStrict) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::NoCollInTimeRangeStrict); + } + + if (isNoCollInTimeRangeStandard) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::NoCollInTimeRangeStandard); + } + + if (isNoCollInRofStrict) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::NoCollInRofStrict); + } + + if (isNoCollInRofStandard) { + if (!col.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::NoCollInRofStandard); + } + + if (isNoHighMultCollInPrevRof) { + if (!col.selection_bit( + o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + registry.fill(HIST("EventCounter"), 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("EventCounter"), EvCutLabel::NoCollInTimeRangeNarrow); + } + + if (isOccupancyCut) { + auto occuValue{isApplyFT0CbasedOccupancy ? col.ft0cOccupancyInTimeRange() : col.trackOccupancyInTimeRange()}; + if (occuValue < minOccCut || occuValue > maxOccCut) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::OccuCut); + } + + if (isCentSel) { + if (col.centFT0C() < minT0CcentCut || col.centFT0C() > maxT0CcentCut) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::Centrality); + } + + if (isZvtxPosSel) { + if (std::fabs(col.posZ()) > posZcut) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::VtxZ); + } + + if (isINELgt0) { + if (!col.isInelGt0()) { + return false; + } + registry.fill(HIST("EventCounter"), EvCutLabel::INELgt0); + } + + return true; + } + + template + void getPTpowers(const T& pTs, const T& vecEff, const T& vecFD, 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 double pTi{pTs.at(i)}; + const double eFFi{vecEff.at(i)}; + const double fDi{vecFD.at(i)}; + const double wEighti{std::pow(eFFi, -1.) * fDi}; + 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.); + } + } + + void loadNchCalibrations(uint64_t timeStamp) + { + if (pathMeanNch.value.empty() == false) { + cfgNch.hMeanNch = ccdb->getForTimeStamp(pathMeanNch, timeStamp); + if (cfgNch.hMeanNch == nullptr) { + LOGF(fatal, "Could not load hMeanNch histogram from %s", pathMeanNch.value.c_str()); + } + } + + if (pathSigmaNch.value.empty() == false) { + cfgNch.hSigmaNch = ccdb->getForTimeStamp(pathSigmaNch, timeStamp); + if (cfgNch.hSigmaNch == nullptr) { + LOGF(fatal, "Could not load hSigmaNch histogram from %s", pathSigmaNch.value.c_str()); + } + } + if (cfgNch.hMeanNch && cfgNch.hSigmaNch) + cfgNch.calibrationsLoaded = true; + } + + void loadPhiCutSelections(const uint64_t& timeStamp) + { + + if (pathPhiCutHigh.value.empty() == false) { + phiCut.hPhiCutHigh = ccdb->getForTimeStamp(pathPhiCutHigh, timeStamp); + if (phiCut.hPhiCutHigh == nullptr) { + LOGF(fatal, "Could not load efficiency histogram from %s", pathPhiCutHigh.value.c_str()); + } + } + + if (pathPhiCutLow.value.empty() == false) { + phiCut.hPhiCutLow = ccdb->getForTimeStamp(pathPhiCutLow, timeStamp); + if (phiCut.hPhiCutLow == nullptr) { + LOGF(fatal, "Could not load efficiency histogram from %s", pathPhiCutLow.value.c_str()); + } + } + + if (phiCut.hPhiCutHigh && phiCut.hPhiCutLow) + phiCut.isPhiCutLoaded = true; + } + + void loadEtaCalibration() + { + if (pathEtaCal.value.empty() == false) { + etaCal.pEtaCal = ccdb->getForTimeStamp(pathEtaCal, ccdbNoLaterThan.value); + if (etaCal.pEtaCal == nullptr) + LOGF(fatal, "Could not load pEtaCal from %s", pathEtaCal.value.c_str()); + } + + if (etaCal.pEtaCal) + etaCal.isMIPCalLoaded = true; + } + + void loadEtaPlateauCalibration() + { + if (pathEtaCalPlateau.value.empty() == false) { + etaCal.pEtaCalPlateau = ccdb->getForTimeStamp(pathEtaCalPlateau, ccdbNoLaterThan.value); + + if (etaCal.pEtaCalPlateau == nullptr) + LOGF(fatal, "Could not load pEtaCalPlateau from %s", pathEtaCalPlateau.value.c_str()); + } + + if (etaCal.pEtaCalPlateau) + etaCal.isCalPlateauLoaded = true; + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/spectraKinkPiKa.cxx b/PWGLF/Tasks/Nuspex/spectraKinkPiKa.cxx new file mode 100644 index 00000000000..aa96ef670d4 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/spectraKinkPiKa.cxx @@ -0,0 +1,1002 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file spectraKinkPiKa.cxx +/// \brief Example of a simple task for the analysis of the muon from Kaon pion using kink topology +/// \author sandeep dudi sandeep.dudi@cern.ch + +#include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/Utils/svPoolCreator.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +////////////// +#include "Common/DataModel/PIDResponseTPC.h" + +#include "Framework/O2DatabasePDGPlugin.h" +#include "ReconstructionDataFormats/PID.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TPDGCode.h" +#include "TVector3.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using VBracket = o2::math_utils::Bracket; + +using TracksFull = soa::Join; +using CollisionsFull = soa::Join; +using CollisionsFullMC = 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"}; + +} // namespace + +struct KinkCandidate { + 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 dcaXYdaug = -999; + float dcaXYmoth = -999; + float kinkAngle = -999; +}; +struct KinkBuilder { + // kink analysis + Produces outputDataTable; + Service ccdb; + // Selection criteria + Configurable maxDCAMothToPV{"maxDCAMothToPV", 0.2, "Max DCA of the mother to the PV"}; + Configurable minDCADaugToPV{"minDCADaugToPV", 0.1, "Min DCA of the daughter to the PV"}; + Configurable minPtMoth{"minPtMoth", 0.15, "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 etaMaxDaug{"etaMaxDaug", 1., "eta max daughter"}; + Configurable etaMaxMoth{"etaMaxMoth", 1., "eta max Mother"}; + Configurable nTPCClusMinDaug{"nTPCClusMinDaug", 30, "mother NTPC clusters cut"}; + Configurable itsChi2cut{"itsChi2cut", 36, "mother itsChi2 cut"}; + Configurable askTOFforDaug{"askTOFforDaug", false, "If true, ask for TOF signal"}; + Configurable kaontopologhy{"kaontopologhy", true, "If true, selected mother have both ITS+TPC "}; + Configurable vertexfinding{"vertexfinding", false, "If true, find the vextex in TPC and applied cut of z and phi"}; + Configurable rMin{"rMin", 120., "min radius for kink vertex"}; + Configurable rMax{"rMax", 200., "max radius for kink vertex"}; + Configurable rStep{"rStep", 2., "step size for scan radius in tpc"}; + + o2::vertexing::DCAFitterN<2> fitter; + o2::base::MatLayerCylSet* lut = nullptr; + + // constants + float radToDeg = o2::constants::math::Rad2Deg; + 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 ccdbPath{"ccdbPath", "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"}; + + // std vector of candidates + std::vector kinkCandidates; + int mRunNumber; + float mBz; + std::array mBBparamsDaug; + + // mother and daughter tracks' properties (absolute charge and mass) + int charge = 1; + 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(); + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMinParamChange(1e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setMaxDZIni(1e9); + fitter.setMaxChi2(1e9); + fitter.setUseAbsDCA(true); + + svCreator.setTimeMargin(customVertexerTimeMargin); + if (skipAmbiTracks) { + svCreator.setSkipAmbiTracks(); + } + const int blpar = 5; + for (int i = 0; i < blpar; i++) { + mBBparamsDaug[i] = cfgBetheBlochParams->get("Daughter", Form("p%i", i)); + } + mBBparamsDaug[5] = cfgBetheBlochParams->get("Daughter", "resolution"); + } + + template + bool selectMothTrack(const T& candidate) + { + const int itscls = 6; + const int itsclsinb = 3; + // ITS-standalone (no TPC, no TOF) + if (!kaontopologhy) { + if (candidate.has_collision() && candidate.hasITS() && !candidate.hasTPC() && !candidate.hasTOF() && + candidate.itsNCls() < itscls && + candidate.itsNClsInnerBarrel() == itsclsinb && + candidate.itsChi2NCl() < itsChi2cut && + candidate.pt() > minPtMoth) { + return true; + } + return false; + } + // Kaon topology: ITS+TPC, no TOF + if (kaontopologhy) { + if (candidate.has_collision() && candidate.hasITS() && candidate.hasTPC() && !candidate.hasTOF() && + candidate.pt() > minPtMoth && + candidate.tpcNClsCrossedRows() >= nTPCClusMinDaug && + candidate.itsChi2NCl() <= itsChi2cut) { + return true; + } + return false; + } + return false; // fallback + } + + template + bool selectDaugTrack(const T& candidate) + { + if (!kaontopologhy && (!candidate.hasTPC() || !candidate.hasITS())) { + return false; + } + if (kaontopologhy && (!candidate.hasTPC() || candidate.hasITS())) { + return false; + } + if (askTOFforDaug && !candidate.hasTOF()) { + return false; + } + return true; + } + + template + void fillCandidateData(const Tcolls& collisions, const Ttracks& tracks, aod::AmbiguousTracks const& ambiguousTracks, aod::BCs const& bcs) + { + svCreator.clearPools(); + svCreator.fillBC2Coll(collisions, bcs); + for (const auto& track : tracks) { + bool isDaug = selectDaugTrack(track); + + bool isMoth = selectMothTrack(track); + + if (!isDaug && !isMoth) + continue; + if (isDaug && track.isPVContributor()) + continue; + if (isMoth && !track.isPVContributor()) + continue; + if (isDaug && std::abs(track.eta()) > etaMaxDaug) + continue; + if (isMoth && std::abs(track.eta()) > etaMaxMoth) + continue; + + int pdgHypo = isMoth ? 1 : 0; + svCreator.appendTrackCand(track, collisions, pdgHypo, ambiguousTracks, bcs); + } + auto& kinkPool = svCreator.getSVCandPool(collisions, !unlikeSignBkg); + + for (const 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::track::TrackParCov trackParCovMothPV{trackParCovMoth}; + std::array dcaInfoMoth; + o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, trackParCovMothPV, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoMoth); + o2::track::TrackParCov trackParCovDaug = getTrackParCov(trackDaug); + // propagate to PV + std::array dcaInfoDaug; + o2::base::Propagator::Instance()->propagateToDCABxByBz({primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ()}, trackParCovDaug, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfoDaug); + + if (std::abs(dcaInfoMoth[1]) > maxDCAMothToPV) { + continue; + } + if (std::abs(dcaInfoDaug[1]) < minDCADaugToPV) { + continue; + } + + if (vertexfinding) { + float bestR = -1; + float bestDeltaPhi = 999; + float bestDeltaZ = 999; + float bestCost = 1e12; + // make local copies (don’t modify originals) + auto mothTmp0 = trackParCovMoth; + auto daugTmp0 = trackParCovDaug; + const float minr = rMin; + const float maxr = rMax; + const float rs = rStep; + for (float R = minr; R <= maxr; R += rs) { + auto mothTmp = mothTmp0; + auto daugTmp = daugTmp0; + if (!o2::base::Propagator::Instance()->PropagateToXBxByBz(mothTmp, R)) + continue; + if (!o2::base::Propagator::Instance()->PropagateToXBxByBz(daugTmp, R)) + continue; + float dphi = std::abs(mothTmp.getPhi() - daugTmp.getPhi()); + if (dphi > M_PI) + dphi = 2 * M_PI - dphi; // wrap φ + float dz = std::abs(mothTmp.getZ() - daugTmp.getZ()); + float cost = dphi * dphi + dz * dz; // <-- correct metric + if (cost < bestCost) { + bestCost = cost; + bestDeltaPhi = dphi; + bestDeltaZ = dz; + bestR = R; + } + } + if (bestR < 0) + continue; + if (bestDeltaZ > maxZDiff) + continue; + if (bestDeltaPhi * radToDeg > maxPhiDiff) + continue; + } + /* // 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; + } + */ + 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(); + const int vtxp = 3; + for (int i = 0; i < vtxp; i++) { + kinkCand.decVtx[i] -= kinkCand.primVtx[i]; + } + propMothTrack.getPxPyPzGlo(kinkCand.momMoth); + propDaugTrack.getPxPyPzGlo(kinkCand.momDaug); + for (int i = 0; i < vtxp; i++) { + kinkCand.momMoth[i] *= charge; + kinkCand.momDaug[i] *= charge; + } + float pMoth = propMothTrack.getP() * charge; + float pDaug = propDaugTrack.getP() * charge; + 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)); + + 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::BCs::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + LOG(info) << "Initializing CCDB for run " << mRunNumber; + o2::parameters::GRPMagField* grpmag = ccdb->getForRun(grpmagPath, mRunNumber); + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = grpmag->getNominalL3Field(); + fitter.setBz(mBz); + + if (!lut) { + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + int mat{static_cast(cfgMaterialCorrection)}; + fitter.setMatCorrType(static_cast(mat)); + } + 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::BCs 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 (const 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); + } + } + PROCESS_SWITCH(KinkBuilder, process, "Produce kink tables", false); +}; + +struct SpectraKinkPiKa { + Service pdg; + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rpiKkink{"rpiKkink", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cutNsigmaKa{"cutNsigmaKa", 4, "NSigmaTPCKaon"}; + Configurable cutNsigmaMu{"cutNsigmaMu", 4, "cutNSigmaMu"}; + Configurable etaCut{"etaCut", 0.8, "etaCut"}; + Configurable rapCut{"rapCut", 0.8, "rapCut"}; + Configurable kinkanglecut{"kinkanglecut", 2.0, "kinkanglecut"}; + Configurable minradius{"minradius", 130.0, "minradiuscut"}; + Configurable maxradius{"maxradius", 200.0, "maxradiuscut"}; + Configurable dcaXYcut{"dcaXYcut", 0.2, "dcaXYcut"}; + Configurable dcaXYcutkink{"dcaXYcutkink", 0.2, "dcaXYcutkink"}; + Configurable dcaZcut{"dcaZcut", 0.2, "dcaZcut"}; + Configurable tpcChi2Cut{"tpcChi2Cut", 4.0, "tpcChi2Cut"}; + Configurable minqt{"minqt", 0.12, "min qt for kaon"}; + Configurable maxqt{"maxqt", 0.3, "max qt for kaon"}; + Configurable minPtMothmc{"minPtMothmc", 0.15, "Minimum pT of the mother"}; + Configurable centestimator{"centestimator", 0, "Select multiplicity estimator: 0 - FT0C, 1 - FT0A, 2 - FT0M, 3 - FV0A, 4 - PVTracks"}; + Configurable pid{"pid", 321, ""}; + Configurable dpid{"dpid", 13, ""}; + Configurable dpidCut{"dpidCut", 0, ""}; + Configurable dptCut{"dptCut", 0, ""}; + Configurable qa{"qa", 0, ""}; + Configurable maxtpcncle{"maxtpcncle", 0, "max tpc find ncle"}; + Configurable mintpcncle{"mintpcncle", 0, "min tpc find ncle"}; + Configurable onlykaon{"onlykaon", 0, "kaon"}; + Configurable additionalhist{"additionalhist", 1, "additional histogram"}; + Configurable pvtrack{"pvtrack", 1, "pvtrack"}; + Configurable cfgUseItsRefit{"cfgUseItsRefit", 1, "ITS refit"}; + Configurable cfgUseTpcRefit{"cfgUseTpcRefit", 1, "TPC refit"}; + + ConfigurableAxis ptAxis{"ptAxis", {150, 0, 15}, ""}; + ConfigurableAxis qtAxis{"qtAxis", {2000, 0.0, 2.0}, ""}; + ConfigurableAxis kinkAxis{"kinkAxis", {300, 0.0, 300.0}, ""}; + ConfigurableAxis etaAxis{"etaAxis", {200, -5.0, 5.0}, ""}; + ConfigurableAxis vertexAxis{"vertexAxis", {1200, -300.0, 300.0}, ""}; + ConfigurableAxis radiusAxis{"radiusAxis", {600, 0.0, 300.0}, ""}; + ConfigurableAxis massAxis{"massAxis", {600, 0.1, 0.7}, ""}; + ConfigurableAxis multAxis{"multAxis", {120, 0.0, 120.0}, ""}; + + Preslice mPerCol = aod::track::collisionId; + Preslice mtPerCol = aod::track::collisionId; + + void init(InitContext const&) + { + + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {{200, -20.0, 20.0}}}); + rEventSelection.add("hMultiplicity", "hMultiplicity", {HistType::kTH1F, {multAxis}}); + if (additionalhist) { + rpiKkink.add("h2_dau_pt_vs_eta_rec", "pt_vs_eta_dau", {HistType::kTH3F, {ptAxis, etaAxis, multAxis}}); + rpiKkink.add("h2_moth_pt_vs_eta_rec", "pt_vs_eta_moth", {HistType::kTH3F, {ptAxis, etaAxis, multAxis}}); + rpiKkink.add("h2_pt_moth_vs_dau_rec", "pt_moth_vs_dau", {HistType::kTH2F, {ptAxis, ptAxis}}); + rpiKkink.add("h2_qt_vs_pt", "qt_pt", {HistType::kTH2F, {qtAxis, ptAxis}}); + } + rpiKkink.add("h2_kink_angle", "kink angle", {HistType::kTH2F, {ptAxis, kinkAxis}}); + // inv mass + rpiKkink.add("h2_kaon_data", "h2_kaon_data", HistType::kTHnSparseF, {massAxis, ptAxis, qtAxis, multAxis}, true); + rpiKkink.add("h1_tracks_data", "track_cut_data", {HistType::kTH1F, {{17, 0.5, 17.5}}}); + + // track qa + if (qa) { + rpiKkink.add("h2_kinkradius_vs_pt", "kink radius_vs pt", {HistType::kTH2F, {radiusAxis, ptAxis}}); + rpiKkink.add("h2_kinkradius_vs_ncl", "kink radius_vs ncl", {HistType::kTH2F, {radiusAxis, {300, 0.0, 300.0}}}); + + rpiKkink.add("h2_kinkradius_vs_vz", "kink radius_vz", {HistType::kTH2F, {vertexAxis, radiusAxis}}); + rpiKkink.add("h2_kink_vx_vs_vy", "kink vx vs vz ", {HistType::kTH2F, {vertexAxis, vertexAxis}}); + + rpiKkink.add("tpc_dedx", "p vs dE/dx", {HistType::kTH2F, {{500, 0.0, 10.0}, {5000, 0.0, 5000.0}}}); + rpiKkink.add("tpc_nsigma_kaon", "p#k n#sigma", {HistType::kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}}); + + rpiKkink.add("tr_dcaxyM", "dcaxym", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + rpiKkink.add("tr_dcaxyD", "dcaxyd", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + rpiKkink.add("tr_dcaxykink_topo", "tr_dcaxykink_topo", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + + rpiKkink.add("tr_chi2nclM", "chi2nclm", {HistType::kTH1F, {{100, 0.0, 100.0}}}); + rpiKkink.add("tr_chi2nclD", "chi2ncld", {HistType::kTH1F, {{100, 0.0, 100.0}}}); + rpiKkink.add("tr_tpcnclfindM", "tpcnclfindm", {HistType::kTH1F, {{300, 0.0, 300.0}}}); + rpiKkink.add("tr_tpcnclfindD", "tpcnclfindd", {HistType::kTH1F, {{300, 0.0, 300.0}}}); + rpiKkink.add("tr_itsChi2NClM", "itsChi2NClm", {HistType::kTH1F, {{200, 0.0, 200.0}}}); + + rpiKkink.add("h2_kinkradius_vs_vz_m", "kink radius_vz", {HistType::kTH2F, {vertexAxis, radiusAxis}}); + rpiKkink.add("h2_kink_vx_vs_vy_m", "kink vx vs vz ", {HistType::kTH2F, {vertexAxis, vertexAxis}}); + + rpiKkink.add("tpc_dedx_m", "p vs dE/dx", {HistType::kTH2F, {{500, 0.0, 10.0}, {5000, 0.0, 5000.0}}}); + rpiKkink.add("tpc_nsigma_kaon_m", "p#k n#sigma", {HistType::kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}}); + + rpiKkink.add("tr_dcaxyM_m", "dcaxym", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + rpiKkink.add("tr_dcaxyD_m", "dcaxyd", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + rpiKkink.add("tr_dcaxykink_topo_m", "tr_dcaxykink_topo", {HistType::kTH1F, {{1000, -5.0, 5.0}}}); + + rpiKkink.add("tr_chi2nclM_m", "chi2nclm", {HistType::kTH1F, {{100, 0.0, 100.0}}}); + rpiKkink.add("tr_chi2nclD_m", "chi2ncld", {HistType::kTH1F, {{100, 0.0, 100.0}}}); + rpiKkink.add("tr_tpcnclfindM_m", "tpcnclfindm", {HistType::kTH1F, {{300, 0.0, 300.0}}}); + rpiKkink.add("tr_tpcnclfindD_m", "tpcnclfindd", {HistType::kTH1F, {{300, 0.0, 300.0}}}); + rpiKkink.add("tr_itsChi2NClM_m", "itsChi2NClm", {HistType::kTH1F, {{200, 0.0, 200.0}}}); + + rpiKkink.add("h2_kinkradius_vs_pt_m", "kinkradius_vs_pt", {HistType::kTH2F, {{250, 0.0, 250.0}, ptAxis}}); + rpiKkink.add("h2_kinkradius_vs_ncl_m", "kinkradius_vs_ncl", {HistType::kTH2F, {{250, 0.0, 250.0}, {300, 0.0, 300.0}}}); + } + if (doprocessMC) { + + rpiKkink.add("h2_kaon_pt_vs_rap_rec_full", "pt_vs_rap_kaon", {HistType::kTH2F, {ptAxis, etaAxis}}); + // rpiKkink.add("h2_kaon_pt_vs_qt_rec_full1", "pt_vs_qt_kaon1", {HistType::kTH2F, {ptAxis, qtAxis}}); + rpiKkink.add("h2_kaon_pt_vs_qt_rec_full1", "pt_vs_qt_kaon1", {HistType::kTH1F, {qtAxis}}); + + rpiKkink.add("h2_moth_ptrapqt_egen", "pt_vs_rap_qt_egen", {HistType::kTH2F, {ptAxis, qtAxis}}); + rpiKkink.add("h2_moth_ptrapqt_mugen", "pt_vs_rap_qt_mugen", {HistType::kTH2F, {ptAxis, qtAxis}}); + rpiKkink.add("h2_moth_ptrapqt_pigen", "pt_vs_rap_qt_pigen", {HistType::kTH2F, {ptAxis, qtAxis}}); + + rpiKkink.add("h2_dau_pt_vs_eta_gen", "pt_vs_eta_dau", {HistType::kTH2F, {ptAxis, etaAxis}}); + rpiKkink.add("h2_moth_pt_vs_eta_gen", "pt_vs_eta_moth", {HistType::kTH2F, {ptAxis, etaAxis}}); + rpiKkink.add("h2_moth_pt_vs_rap_genall", "pt_vs_rap_moth", {HistType::kTH2F, {ptAxis, etaAxis}}); + rpiKkink.add("h2_pt_moth_vs_dau_gen", "pt_moth_vs_dau", {HistType::kTH2F, {ptAxis, ptAxis}}); + rpiKkink.add("h1_tracks", "track_cut", {HistType::kTH1F, {{18, 0.5, 18.5}}}); + rpiKkink.add("h1_tracks_gen", "track_cut_gen", {HistType::kTH1F, {{15, 0.5, 15.5}}}); + rpiKkink.add("h2_qt_gen", "qt", {HistType::kTH1F, {qtAxis}}); + rpiKkink.add("h2_qt_rec", "qt", {HistType::kTH1F, {qtAxis}}); + rpiKkink.add("h2_kink_angle_gen", "kink angle", {HistType::kTH2F, {ptAxis, kinkAxis}}); + + rpiKkink.add("h2_kaon_mc_gen", "h2_kaon_mc_gen", HistType::kTHnSparseF, {massAxis, ptAxis, qtAxis}, true); + rpiKkink.add("h2_kaon_mc_gen1", "h2_kaon_mc_gen1", HistType::kTHnSparseF, {massAxis, ptAxis, qtAxis}, true); + rpiKkink.add("h2_kaon_mc_rec", "h2_kaon_mc_rec", HistType::kTHnSparseF, {massAxis, ptAxis, qtAxis, multAxis}, true); + + rpiKkink.add("h2_dau_pt_vs_eta_rec_m", "pt_vs_eta_dau", {HistType::kTH3F, {ptAxis, etaAxis, multAxis}}); + rpiKkink.add("h2_moth_pt_vs_eta_rec_m", "pt_vs_eta_moth", {HistType::kTH3F, {ptAxis, etaAxis, multAxis}}); + rpiKkink.add("h2_pt_moth_vs_dau_rec_m", "pt_moth_vs_dau", {HistType::kTH2F, {ptAxis, ptAxis}}); + rpiKkink.add("h2_kink_angle_m", "kink angle", {HistType::kTH2F, {ptAxis, kinkAxis}}); + rpiKkink.add("h2_kaon_mc_rec_m", "h2_kaon_mc_rec_m", HistType::kTHnSparseF, {massAxis, ptAxis, qtAxis, multAxis}, true); + } + } + + double computeMotherMass(ROOT::Math::PxPyPzMVector pmoth, ROOT::Math::PxPyPzMVector pdaug) + { + // Infer neutrino momentum from conservation + ROOT::Math::XYZVector pnuvec = pmoth.Vect() - pdaug.Vect(); + // Neutrino energy (massless): E_nu = |p_nu| + double enu = pnuvec.R(); + // Total energy of the system + double etotal = pdaug.E() + enu; + // Total momentum = p_nu + p_daug + ROOT::Math::XYZVector ptotalvec = pnuvec + pdaug.Vect(); + double ptotalsq = ptotalvec.Mag2(); + // Invariant mass from E² - |p|² + double m2 = etotal * etotal - ptotalsq; + return (m2 > 0) ? std::sqrt(m2) : -1.0; + } + double computeQt(ROOT::Math::PxPyPzMVector pmoth, ROOT::Math::PxPyPzMVector pdaug) + { + TVector3 pdlab(pdaug.Px(), pdaug.Py(), pdaug.Pz()); + // Compute transverse component + TVector3 motherDir(pmoth.Px(), pmoth.Py(), pmoth.Pz()); + double ptd = pdlab.Perp(motherDir); // or p_d_lab.Mag() * sin(theta) + return ptd; + } + + void processData(CollisionsFull::iterator const& collision, aod::KinkCands const& KinkCands, TracksFull const&) + { + ROOT::Math::PxPyPzMVector v0; + ROOT::Math::PxPyPzMVector v1; + + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8() || !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return; + } + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return; + } + + float multiplicity{-1}; + const int kCentFT0C = 0; + const int kCentFT0A = 1; + const int kCentFT0M = 2; + const int kCentFV0A = 3; + + if (centestimator == kCentFT0C) { + multiplicity = collision.centFT0C(); + } else if (centestimator == kCentFT0A) { + multiplicity = collision.centFT0A(); + } else if (centestimator == kCentFT0M) { + multiplicity = collision.centFT0M(); + } else if (centestimator == kCentFV0A) { + multiplicity = collision.centFV0A(); + } + + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + rEventSelection.fill(HIST("hMultiplicity"), multiplicity); + for (const auto& kinkCand : KinkCands) { + auto dauTrack = kinkCand.trackDaug_as(); + auto mothTrack = kinkCand.trackMoth_as(); + + rpiKkink.fill(HIST("h1_tracks_data"), 1.0); + if (mothTrack.collisionId() != collision.globalIndex()) { + continue; // not from this event + } + if (!mothTrack.has_collision() || !dauTrack.has_collision()) { + continue; + } + if (mothTrack.collisionId() != dauTrack.collisionId()) { + continue; // skip mismatched collision tracks + } + rpiKkink.fill(HIST("h1_tracks_data"), 2.0); + if (dauTrack.sign() != mothTrack.sign()) { + LOG(info) << "Skipping kink candidate with opposite sign daughter and mother: " << kinkCand.globalIndex(); + continue; // Skip if the daughter has the opposite sign as the mother + } + rpiKkink.fill(HIST("h1_tracks_data"), 3.0); + if (pvtrack && !mothTrack.isPVContributor()) + continue; + + rpiKkink.fill(HIST("h1_tracks_data"), 4.0); + if (cfgUseItsRefit && !(o2::aod::track::ITSrefit)) + continue; + if (cfgUseTpcRefit && !(o2::aod::track::TPCrefit)) + continue; + rpiKkink.fill(HIST("h1_tracks_data"), 5.0); + bool kaon = false; + + v0.SetCoordinates(mothTrack.px(), mothTrack.py(), mothTrack.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(dauTrack.px(), dauTrack.py(), dauTrack.pz(), o2::constants::physics::MassMuon); + + if (dptCut && v1.Pt() > v0.Pt()) + continue; + rpiKkink.fill(HIST("h1_tracks_data"), 6.0); + if (qa) { + rpiKkink.fill(HIST("tpc_dedx"), v0.P(), mothTrack.tpcSignal()); + rpiKkink.fill(HIST("tpc_nsigma_kaon"), v0.Pt(), mothTrack.tpcNSigmaKa()); + rpiKkink.fill(HIST("tr_chi2nclM"), mothTrack.tpcChi2NCl()); + rpiKkink.fill(HIST("tr_chi2nclD"), dauTrack.tpcChi2NCl()); + rpiKkink.fill(HIST("tr_tpcnclfindM"), mothTrack.tpcNClsFound()); + rpiKkink.fill(HIST("tr_tpcnclfindD"), dauTrack.tpcNClsFound()); + rpiKkink.fill(HIST("tr_itsChi2NClM"), mothTrack.itsChi2NCl()); + } + if (mothTrack.tpcChi2NCl() > tpcChi2Cut) + continue; + rpiKkink.fill(HIST("h1_tracks_data"), 7.0); + if (mothTrack.tpcNClsFound() > maxtpcncle || mothTrack.tpcNClsFound() < mintpcncle) + continue; + rpiKkink.fill(HIST("h1_tracks_data"), 8.0); + if (std::abs(mothTrack.tpcNSigmaKa()) < cutNsigmaKa) { + kaon = true; + } + if (!kaon) { + continue; + } + rpiKkink.fill(HIST("h1_tracks_data"), 9.0); + if (cutNsigmaMu != -1 && std::abs(dauTrack.tpcNSigmaMu()) > cutNsigmaMu) { + continue; + } + double radiusxy = std::sqrt(kinkCand.xDecVtx() * kinkCand.xDecVtx() + kinkCand.yDecVtx() * kinkCand.yDecVtx()); + if (radiusxy < minradius || radiusxy > maxradius) + continue; + rpiKkink.fill(HIST("h1_tracks_data"), 10.0); + // dcaXYmoth kinkCand.decVtx[0], kinkCand.decVtx[1], kinkCand.decVtx[2], + if (qa) { + rpiKkink.fill(HIST("tr_dcaxyM"), kinkCand.dcaMothPv()); + rpiKkink.fill(HIST("tr_dcaxyD"), kinkCand.dcaDaugPv()); + rpiKkink.fill(HIST("tr_dcaxykink_topo"), kinkCand.dcaKinkTopo()); + + rpiKkink.fill(HIST("h2_kinkradius_vs_vz"), kinkCand.zDecVtx(), radiusxy); + rpiKkink.fill(HIST("h2_kink_vx_vs_vy"), kinkCand.xDecVtx(), kinkCand.yDecVtx()); + rpiKkink.fill(HIST("h2_kinkradius_vs_pt"), radiusxy, v0.Pt()); + rpiKkink.fill(HIST("h2_kinkradius_vs_ncl"), radiusxy, mothTrack.tpcNClsFound()); + } + if (std::abs(kinkCand.dcaMothPv()) > dcaXYcut) + continue; + rpiKkink.fill(HIST("h1_tracks_data"), 11.0); + if (kinkCand.dcaKinkTopo() > dcaXYcutkink) + continue; + rpiKkink.fill(HIST("h1_tracks_data"), 12.0); + float pMoth = v0.P(); + float pDaug = v1.P(); + float spKink = mothTrack.px() * dauTrack.px() + mothTrack.py() * dauTrack.py() + mothTrack.pz() * dauTrack.pz(); + float angle = std::acos(spKink / (pMoth * pDaug)); + float radToDeg = o2::constants::math::Rad2Deg; + float kinkangle = angle * radToDeg; + if (kinkangle < kinkanglecut) + continue; + rpiKkink.fill(HIST("h1_tracks_data"), 13.0); + TVector3 pdlab(v1.Px(), v1.Py(), v1.Pz()); + // Compute transverse component + TVector3 motherDir(v0.Px(), v0.Py(), v0.Pz()); + double ptd = pdlab.Perp(motherDir); // or p_d_lab.Mag() * sin(theta) + + if (kaon && onlykaon && std::abs(v0.Rapidity()) < rapCut) { + rpiKkink.fill(HIST("h1_tracks_data"), 14.0); + v0.SetCoordinates(mothTrack.px(), mothTrack.py(), mothTrack.pz(), o2::constants::physics::MassKaonCharged); + if (additionalhist) { + rpiKkink.fill(HIST("h2_moth_pt_vs_eta_rec"), v0.Pt(), v0.Eta(), multiplicity); + rpiKkink.fill(HIST("h2_dau_pt_vs_eta_rec"), v1.Pt(), v1.Eta(), multiplicity); + rpiKkink.fill(HIST("h2_pt_moth_vs_dau_rec"), v0.Pt(), v1.Pt()); + rpiKkink.fill(HIST("h2_qt_vs_pt"), ptd, v1.Pt()); + } + double mass = computeMotherMass(v0, v1); + rpiKkink.fill(HIST("h2_kaon_data"), mass, v0.Pt(), ptd, multiplicity); + rpiKkink.fill(HIST("h2_kink_angle"), v0.Pt(), kinkangle); + if (qa && ptd > minqt && ptd < maxqt) { + rpiKkink.fill(HIST("h2_kinkradius_vs_vz_m"), kinkCand.zDecVtx(), radiusxy); + rpiKkink.fill(HIST("h2_kink_vx_vs_vy_m"), kinkCand.xDecVtx(), kinkCand.yDecVtx()); + + rpiKkink.fill(HIST("tpc_dedx_m"), v0.P(), mothTrack.tpcSignal()); + rpiKkink.fill(HIST("tpc_nsigma_kaon_m"), v0.Pt(), mothTrack.tpcNSigmaKa()); + + rpiKkink.fill(HIST("tr_chi2nclM_m"), mothTrack.tpcChi2NCl()); + rpiKkink.fill(HIST("tr_chi2nclD_m"), dauTrack.tpcChi2NCl()); + rpiKkink.fill(HIST("tr_tpcnclfindM_m"), mothTrack.tpcNClsFound()); + rpiKkink.fill(HIST("tr_tpcnclfindD_m"), dauTrack.tpcNClsFound()); + rpiKkink.fill(HIST("tr_itsChi2NClM_m"), mothTrack.itsChi2NCl()); + + rpiKkink.fill(HIST("tr_dcaxyM_m"), kinkCand.dcaMothPv()); + rpiKkink.fill(HIST("tr_dcaxyD_m"), kinkCand.dcaDaugPv()); + rpiKkink.fill(HIST("tr_dcaxykink_topo_m"), kinkCand.dcaKinkTopo()); + + rpiKkink.fill(HIST("h2_kinkradius_vs_pt_m"), radiusxy, v0.Pt()); + rpiKkink.fill(HIST("h2_kinkradius_vs_ncl_m"), radiusxy, mothTrack.tpcNClsFound()); + } + } + } + } + PROCESS_SWITCH(SpectraKinkPiKa, processData, "Data processing", true); + + void processMC(CollisionsFullMC const& collisions, aod::KinkCands const& KinkCands, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC, TracksFull const&) + { + for (const auto& collision : collisions) { + ROOT::Math::PxPyPzMVector v0; + ROOT::Math::PxPyPzMVector v1; + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8() || !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + float multiplicity{-1}; + const int kCentFT0C = 0; + const int kCentFT0A = 1; + const int kCentFT0M = 2; + const int kCentFV0A = 3; + + if (centestimator == kCentFT0C) { + multiplicity = collision.centFT0C(); + } else if (centestimator == kCentFT0A) { + multiplicity = collision.centFT0A(); + } else if (centestimator == kCentFT0M) { + multiplicity = collision.centFT0M(); + } else if (centestimator == kCentFV0A) { + multiplicity = collision.centFV0A(); + } + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + rEventSelection.fill(HIST("hMultiplicity"), multiplicity); + + auto kinkCandPerColl = KinkCands.sliceBy(mPerCol, collision.globalIndex()); + for (const auto& kinkCand : kinkCandPerColl) { + auto dauTrack = kinkCand.trackDaug_as(); + auto mothTrack = kinkCand.trackMoth_as(); + if (dauTrack.sign() != mothTrack.sign()) { + LOG(info) << "Skipping kink candidate with opposite sign daughter and mother: " << kinkCand.globalIndex(); + continue; // Skip if the daughter has the opposite sign as the mother + } + rpiKkink.fill(HIST("h1_tracks"), 1.0); + if (pvtrack && !mothTrack.isPVContributor()) + continue; + rpiKkink.fill(HIST("h1_tracks"), 2.0); + v0.SetCoordinates(mothTrack.px(), mothTrack.py(), mothTrack.pz(), o2::constants::physics::MassKaonCharged); + + double radiusxy = std::sqrt(kinkCand.xDecVtx() * kinkCand.xDecVtx() + kinkCand.yDecVtx() * kinkCand.yDecVtx()); + if (radiusxy < minradius || radiusxy > maxradius) + continue; + rpiKkink.fill(HIST("h1_tracks"), 3.0); + // do MC association + auto mcLabMoth1 = trackLabelsMC.rawIteratorAt(mothTrack.globalIndex()); + if (mcLabMoth1.has_mcParticle()) { + auto mcTrackMoth1 = mcLabMoth1.mcParticle_as(); + if (!mcTrackMoth1.isPhysicalPrimary()) + continue; + if (std::abs(mcTrackMoth1.pdgCode()) == pid) { + rpiKkink.fill(HIST("h2_kaon_pt_vs_rap_rec_full"), v0.Pt(), v0.Rapidity()); + } + } + if (cfgUseItsRefit && !(o2::aod::track::ITSrefit)) + continue; + rpiKkink.fill(HIST("h1_tracks"), 4.0); + if (cfgUseTpcRefit && !(o2::aod::track::TPCrefit)) + continue; + rpiKkink.fill(HIST("h1_tracks"), 5.0); + + v1.SetCoordinates(dauTrack.px(), dauTrack.py(), dauTrack.pz(), o2::constants::physics::MassMuon); + if (qa) { + rpiKkink.fill(HIST("tpc_dedx"), v0.P(), mothTrack.tpcSignal()); + rpiKkink.fill(HIST("tpc_nsigma_kaon"), v0.Pt(), mothTrack.tpcNSigmaKa()); + rpiKkink.fill(HIST("tr_chi2nclM"), mothTrack.tpcChi2NCl()); + rpiKkink.fill(HIST("tr_chi2nclD"), dauTrack.tpcChi2NCl()); + rpiKkink.fill(HIST("tr_tpcnclfindM"), mothTrack.tpcNClsFound()); + rpiKkink.fill(HIST("tr_tpcnclfindD"), dauTrack.tpcNClsFound()); + rpiKkink.fill(HIST("tr_itsChi2NClM"), mothTrack.itsChi2NCl()); + } + if (mothTrack.tpcChi2NCl() > tpcChi2Cut) + continue; + rpiKkink.fill(HIST("h1_tracks"), 6.0); + if (mothTrack.tpcNClsFound() > maxtpcncle || mothTrack.tpcNClsFound() < mintpcncle) + continue; + rpiKkink.fill(HIST("h1_tracks"), 7.0); + bool kaon = false; + if (std::abs(mothTrack.tpcNSigmaKa()) < cutNsigmaKa) { + kaon = true; + } + if (dptCut && v1.Pt() > v0.Pt()) + continue; + rpiKkink.fill(HIST("h1_tracks"), 8.0); + if (!kaon) + continue; + rpiKkink.fill(HIST("h1_tracks"), 9.0); + if (qa) { + rpiKkink.fill(HIST("tr_dcaxyM"), kinkCand.dcaMothPv()); + rpiKkink.fill(HIST("tr_dcaxyD"), kinkCand.dcaDaugPv()); + rpiKkink.fill(HIST("tr_dcaxykink_topo"), kinkCand.dcaKinkTopo()); + + rpiKkink.fill(HIST("h2_kinkradius_vs_vz"), kinkCand.zDecVtx(), radiusxy); + rpiKkink.fill(HIST("h2_kink_vx_vs_vy"), kinkCand.xDecVtx(), kinkCand.yDecVtx()); + + rpiKkink.fill(HIST("h2_kinkradius_vs_pt"), radiusxy, v0.Pt()); + rpiKkink.fill(HIST("h2_kinkradius_vs_ncl"), radiusxy, mothTrack.tpcNClsFound()); + } + if (std::abs(kinkCand.dcaMothPv()) > dcaXYcut) + continue; + rpiKkink.fill(HIST("h1_tracks"), 10.0); + if (kinkCand.dcaKinkTopo() > dcaXYcutkink) + continue; + rpiKkink.fill(HIST("h1_tracks"), 11.0); + float pMoth = v0.P(); + float pDaug = v1.P(); + float spKink = mothTrack.px() * dauTrack.px() + mothTrack.py() * dauTrack.py() + mothTrack.pz() * dauTrack.pz(); + float angle = std::acos(spKink / (pMoth * pDaug)); + float radToDeg = o2::constants::math::Rad2Deg; + float kinkangle = angle * radToDeg; + if (kinkangle < kinkanglecut) + continue; + + rpiKkink.fill(HIST("h1_tracks"), 12.0); + if (additionalhist) { + rpiKkink.fill(HIST("h2_moth_pt_vs_eta_rec"), v0.Pt(), v0.Eta(), multiplicity); + rpiKkink.fill(HIST("h2_dau_pt_vs_eta_rec"), v1.Pt(), v1.Eta(), multiplicity); + rpiKkink.fill(HIST("h2_pt_moth_vs_dau_rec"), v0.Pt(), v1.Pt()); + } + rpiKkink.fill(HIST("h2_kink_angle"), v0.Pt(), kinkangle); + TVector3 pdlab(v1.Px(), v1.Py(), v1.Pz()); + // Compute transverse component + TVector3 motherDir(v0.Px(), v0.Py(), v0.Pz()); + double ptd = pdlab.Perp(motherDir); // or p_d_lab.Mag() * sin(theta) + double mass = computeMotherMass(v0, v1); + + rpiKkink.fill(HIST("h2_kaon_mc_rec"), mass, v0.Pt(), ptd, multiplicity); + // do MC association + auto mcLabMoth = trackLabelsMC.rawIteratorAt(mothTrack.globalIndex()); + auto mcLabDau = trackLabelsMC.rawIteratorAt(dauTrack.globalIndex()); + + if (mcLabMoth.has_mcParticle()) { + auto mcTrackMoth = mcLabMoth.mcParticle_as(); + if (!mcTrackMoth.isPhysicalPrimary()) + continue; + rpiKkink.fill(HIST("h1_tracks"), 13.0); + if (std::abs(mcTrackMoth.pdgCode()) != pid) + continue; + rpiKkink.fill(HIST("h1_tracks"), 14.0); + // rpiKkink.fill(HIST("h2_kaon_pt_vs_qt_rec_full1"), v0.Pt(), ptd); + rpiKkink.fill(HIST("h2_kaon_pt_vs_qt_rec_full1"), ptd); + + if (mcLabDau.has_mcParticle()) { + auto mcTrackDau = mcLabDau.mcParticle_as(); + if (!mcTrackDau.has_mothers()) + continue; + rpiKkink.fill(HIST("h1_tracks"), 15.0); + const int process = 4; + if (mcTrackDau.getProcess() != process) + continue; + rpiKkink.fill(HIST("h1_tracks"), 16.0); + for (const auto& piMother : mcTrackDau.mothers_as()) { + if (piMother.globalIndex() != mcTrackMoth.globalIndex()) { + continue; + } + rpiKkink.fill(HIST("h1_tracks"), 17.0); + if (dpidCut && std::abs(mcTrackDau.pdgCode()) != dpid) { + continue; + } + rpiKkink.fill(HIST("h1_tracks"), 18.0); + if (additionalhist) { + rpiKkink.fill(HIST("h2_moth_pt_vs_eta_rec_m"), v0.Pt(), v0.Eta(), multiplicity); + rpiKkink.fill(HIST("h2_dau_pt_vs_eta_rec_m"), v1.Pt(), v1.Eta(), multiplicity); + rpiKkink.fill(HIST("h2_pt_moth_vs_dau_rec_m"), v0.Pt(), v1.Pt()); + } + rpiKkink.fill(HIST("h2_kink_angle_m"), v0.Pt(), kinkangle); + rpiKkink.fill(HIST("h2_kaon_mc_rec_m"), mass, v0.Pt(), ptd, multiplicity); + + if (qa && ptd > minqt && ptd < maxqt) { + rpiKkink.fill(HIST("h2_kinkradius_vs_vz_m"), kinkCand.zDecVtx(), radiusxy); + rpiKkink.fill(HIST("h2_kink_vx_vs_vy_m"), kinkCand.xDecVtx(), kinkCand.yDecVtx()); + + rpiKkink.fill(HIST("tpc_dedx_m"), v0.P(), mothTrack.tpcSignal()); + rpiKkink.fill(HIST("tpc_nsigma_kaon_m"), v0.Pt(), mothTrack.tpcNSigmaKa()); + + rpiKkink.fill(HIST("tr_chi2nclM_m"), mothTrack.tpcChi2NCl()); + rpiKkink.fill(HIST("tr_chi2nclD_m"), dauTrack.tpcChi2NCl()); + rpiKkink.fill(HIST("tr_tpcnclfindM_m"), mothTrack.tpcNClsFound()); + rpiKkink.fill(HIST("tr_tpcnclfindD_m"), dauTrack.tpcNClsFound()); + rpiKkink.fill(HIST("tr_itsChi2NClM_m"), mothTrack.itsChi2NCl()); + + rpiKkink.fill(HIST("tr_dcaxyM_m"), kinkCand.dcaMothPv()); + rpiKkink.fill(HIST("tr_dcaxyD_m"), kinkCand.dcaDaugPv()); + rpiKkink.fill(HIST("tr_dcaxykink_topo_m"), kinkCand.dcaKinkTopo()); + + rpiKkink.fill(HIST("h2_kinkradius_vs_pt_m"), radiusxy, v0.Pt()); + rpiKkink.fill(HIST("h2_kinkradius_vs_ncl_m"), radiusxy, mothTrack.tpcNClsFound()); + } + } + } + } + } + } + + for (const auto& mcPart : particlesMC) { + ROOT::Math::PxPyPzMVector v0; + ROOT::Math::PxPyPzMVector v1; + if (std::abs(mcPart.pdgCode()) != pid) { + continue; + } + rpiKkink.fill(HIST("h1_tracks_gen"), 1.0); + if (!mcPart.isPhysicalPrimary()) { + continue; + } + rpiKkink.fill(HIST("h1_tracks_gen"), 2.0); + v0.SetCoordinates(mcPart.px(), mcPart.py(), mcPart.pz(), o2::constants::physics::MassKaonCharged); + if (std::abs(v0.Rapidity()) > rapCut) { + continue; + } + if (std::abs(v0.Pt()) < minPtMothmc) { + continue; + } + rpiKkink.fill(HIST("h2_moth_pt_vs_rap_genall"), v0.Pt(), v0.Rapidity()); + rpiKkink.fill(HIST("h1_tracks_gen"), 3.0); + if (!mcPart.has_daughters()) { + continue; // Skip if no daughters + } + rpiKkink.fill(HIST("h1_tracks_gen"), 4.0); + int muond = 0; + int piond = 0; + int eld = 0; + double ptd = 0; + const int process = 4; + for (const auto& daughter : mcPart.daughters_as()) { + v1.SetCoordinates(daughter.px(), daughter.py(), daughter.pz(), o2::constants::physics::MassMuon); + if (daughter.getProcess() != process) + continue; + ptd = computeQt(v0, v1); + if (std::abs(daughter.pdgCode()) == kElectron) { + eld++; + } else if (std::abs(daughter.pdgCode()) == dpid) { + muond++; + } else if (std::abs(daughter.pdgCode()) == kPiPlus) { + piond++; + } + } + if (additionalhist) { + if (eld >= 1) + rpiKkink.fill(HIST("h2_moth_ptrapqt_egen"), v0.Pt(), ptd); + if (muond >= 1) + rpiKkink.fill(HIST("h2_moth_ptrapqt_mugen"), v0.Pt(), ptd); + if (piond >= 1) + rpiKkink.fill(HIST("h2_moth_ptrapqt_pigen"), v0.Pt(), ptd); + } + rpiKkink.fill(HIST("h1_tracks_gen"), 5.0); + float pMoth = v0.P(); + float pDaug = v1.P(); + float spKink = v0.Px() * v1.Px() + v0.Py() * v1.Py() + v0.Pz() * v1.Pz(); + float angle = std::acos(spKink / (pMoth * pDaug)); + float radToDeg = o2::constants::math::Rad2Deg; + float kinkangle = angle * radToDeg; + // if (kinkangle * radToDeg < kinkanglecut) + // continue; + if (additionalhist) { + rpiKkink.fill(HIST("h2_moth_pt_vs_eta_gen"), v0.Pt(), v0.Eta()); + rpiKkink.fill(HIST("h2_dau_pt_vs_eta_gen"), v1.Pt(), v1.Eta()); + rpiKkink.fill(HIST("h2_pt_moth_vs_dau_gen"), v0.Pt(), v1.Pt()); + } + rpiKkink.fill(HIST("h2_kink_angle_gen"), v0.Pt(), kinkangle); + rpiKkink.fill(HIST("h2_qt_gen"), ptd); + double mass = computeMotherMass(v0, v1); + if (eld >= 1 || muond >= 1 || piond >= 1) { + rpiKkink.fill(HIST("h2_kaon_mc_gen"), mass, v0.Pt(), ptd); + } else { + rpiKkink.fill(HIST("h2_kaon_mc_gen1"), mass, v0.Pt(), ptd); + } + } + } + PROCESS_SWITCH(SpectraKinkPiKa, processMC, "MC processing", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + auto builderTask = adaptAnalysisTask(cfgc); + auto spectraTask = adaptAnalysisTask(cfgc); + return {builderTask, spectraTask}; // Just return both tasks +} diff --git a/PWGLF/Tasks/Nuspex/spectraTOF.cxx b/PWGLF/Tasks/Nuspex/spectraTOF.cxx index e30d511ee88..978542c2c69 100644 --- a/PWGLF/Tasks/Nuspex/spectraTOF.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTOF.cxx @@ -18,27 +18,35 @@ /// // O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/McCollisionExtra.h" + +#include "PWGLF/DataModel/spectraTOF.h" + +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Framework/StaticFor.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "PWGLF/DataModel/spectraTOF.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "PWGLF/Utils/inelGt.h" -#include "PWGLF/DataModel/mcCentrality.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" #include "TPDGCode.h" +#include +#include using namespace o2; using namespace o2::track; using namespace o2::framework; @@ -52,6 +60,23 @@ 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 { @@ -69,6 +94,7 @@ struct tofSpectra { 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"}; @@ -78,11 +104,13 @@ struct tofSpectra { } trkselOptions; Configurable enableDcaGoodEvents{"enableDcaGoodEvents", true, "Enables the MC plots with the correct match between data and MC"}; + Configurable enablePureDCAHistogram{"enablePureDCAHistogram", false, "Enables the pure DCA histograms"}; 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 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"}; @@ -111,14 +139,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 enableTPCTOFvsEtaHistograms{"enableTPCTOFvsEtaHistograms", false, "choose if produce TPC tof vs Eta"}; - Configurable includeCentralityMC{"includeCentralityMC", true, "choose if include Centrality to MC"}; + 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}; @@ -192,7 +225,9 @@ 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; @@ -202,6 +237,7 @@ struct tofSpectra { 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); @@ -258,6 +294,7 @@ struct tofSpectra { } 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)"); @@ -316,11 +353,14 @@ struct tofSpectra { 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{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"}; @@ -400,8 +440,34 @@ struct tofSpectra { histos.add("Data/neg/pt/its", "neg ITS", kTH1D, {ptAxis}); 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) { - const AxisSpec nsigmaTPCAxisOccupancy{binsOptions.binsnsigmaTPC, "nsigmaTPC"}; 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}); @@ -423,6 +489,69 @@ struct tofSpectra { 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}); @@ -431,12 +560,18 @@ struct tofSpectra { 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/den", "generated MC #pi^{+} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); - histos.add("MC/test/RecoEvs/pi/neg/prm/pt/den", "generated MC #pi^{-} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); - histos.add("MC/test/RecoEvs/ka/pos/prm/pt/den", "generated MC K^{+} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); - histos.add("MC/test/RecoEvs/ka/neg/prm/pt/den", "generated MC K^{-} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); - histos.add("MC/test/RecoEvs/pr/pos/prm/pt/den", "generated MC p from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); - histos.add("MC/test/RecoEvs/pr/neg/prm/pt/den", "generated MC #bar{p} from recons. events", kTHnSparseD, {ptAxis, impParamAxis}); + 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}}); @@ -568,16 +703,27 @@ struct tofSpectra { } 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], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); - 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}); + 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, multAxis, dcaXyAxis}); - 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], 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_numtofgoodmatch_prm[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); @@ -599,6 +745,7 @@ struct tofSpectra { histos.add(hpt_numtof_mat[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); 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], kTH2D, {ptAxis, multAxis}); histos.add(hpt_den_str[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); @@ -610,28 +757,45 @@ struct tofSpectra { } 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) { - hDcaXYZPrm[i] = histos.add(Form("dcaprm/%s/%s", (i < Np) ? "pos" : "neg", pN[i % Np]), pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); - hDcaXYZStr[i] = histos.add(Form("dcastr/%s/%s", (i < Np) ? "pos" : "neg", pN[i % Np]), pTCharge[i], kTH3D, {ptAxis, dcaXyAxis, dcaZAxis}); - hDcaXYZMat[i] = histos.add(Form("dcamat/%s/%s", (i < Np) ? "pos" : "neg", pN[i % Np]), 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(Form("dcaxywrongcollprm/%s/%s", (i < Np) ? "pos" : "neg", pN[i % Np]), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); - hDcaXYWrongCollisionStr[i] = histos.add(Form("dcaxywrongcollstr/%s/%s", (i < Np) ? "pos" : "neg", pN[i % Np]), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); - hDcaXYWrongCollisionMat[i] = histos.add(Form("dcaxywrongcollmat/%s/%s", (i < Np) ? "pos" : "neg", pN[i % Np]), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); + 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 @@ -675,7 +839,7 @@ struct tofSpectra { template void fillParticleHistos(const T& track, const C& collision) { - if (abs(track.rapidity(PID::getMass(id))) > trkselOptions.cfgCutY) { + if (std::abs(track.rapidity(PID::getMass(id))) > trkselOptions.cfgCutY) { return; } if constexpr (id == PID::Kaon) { @@ -685,9 +849,9 @@ struct tofSpectra { } 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); @@ -861,7 +1025,6 @@ struct tofSpectra { } } } - if constexpr (fillFullInfo) { if (enableDeltaHistograms) { const auto& deltaTOF = o2::aod::pidutils::tofExpSignalDiff(track); @@ -880,7 +1043,6 @@ struct tofSpectra { } } } - // Filling DCA info with the TPC+TOF PID bool isDCAPureSample = (std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.f); if (track.pt() <= 0.4) { @@ -1000,7 +1162,7 @@ struct tofSpectra { histos.fill(HIST("evsel"), 12.f); } } - if (abs(collision.posZ()) > evselOptions.cfgCutVertex) { + if (std::abs(collision.posZ()) > evselOptions.cfgCutVertex) { return false; } if constexpr (fillHistograms) { @@ -1050,7 +1212,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 / std::pow(track.pt(), 1.1f)))); } return track.isGlobalTrack(); } @@ -1075,8 +1237,8 @@ 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); @@ -1128,6 +1290,10 @@ struct tofSpectra { } } + if (track.tpcChi2NCl() < minChi2PerClusterTPC || track.tpcChi2NCl() > maxChi2PerClusterTPC) { + return false; + } + if (!passesCutWoDCA(track)) { return false; } @@ -1277,45 +1443,239 @@ struct tofSpectra { aod::CentFV0As, aod::CentFT0Ms, aod::CentFT0As, aod::CentFT0Cs>; 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 = collision.centFT0C(); + 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) { - if (!isTrackSelected(track)) { + // 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); - histos.fill(HIST("nsigmatpc/test_occupancy/pos/pi"), track.pt(), nsigmaTPCPi, multiplicity, occupancy); - histos.fill(HIST("nsigmatpc/test_occupancy/neg/pi"), track.pt(), nsigmaTPCPi, multiplicity, occupancy); - histos.fill(HIST("nsigmatpc/test_occupancy/pos/ka"), track.pt(), nsigmaTPCKa, multiplicity, occupancy); - histos.fill(HIST("nsigmatpc/test_occupancy/neg/ka"), track.pt(), nsigmaTPCKa, multiplicity, occupancy); - histos.fill(HIST("nsigmatpc/test_occupancy/pos/pr"), track.pt(), nsigmaTPCPr, multiplicity, occupancy); - histos.fill(HIST("nsigmatpc/test_occupancy/neg/pr"), track.pt(), nsigmaTPCPr, multiplicity, occupancy); - - histos.fill(HIST("nsigmatof/test_occupancy/pos/pi"), track.pt(), nsigmaTOFPi, multiplicity, occupancy); - histos.fill(HIST("nsigmatof/test_occupancy/neg/pi"), track.pt(), nsigmaTOFPi, multiplicity, occupancy); - histos.fill(HIST("nsigmatof/test_occupancy/pos/ka"), track.pt(), nsigmaTOFKa, multiplicity, occupancy); - histos.fill(HIST("nsigmatof/test_occupancy/neg/ka"), track.pt(), nsigmaTOFKa, multiplicity, occupancy); - histos.fill(HIST("nsigmatof/test_occupancy/pos/pr"), track.pt(), nsigmaTOFPr, multiplicity, occupancy); - histos.fill(HIST("nsigmatof/test_occupancy/neg/pr"), track.pt(), nsigmaTOFPr, multiplicity, occupancy); - - } // track - } // process function - PROCESS_SWITCH(tofSpectra, processOccupancy, "check for occupancy plots", false); + + 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(CollisionCandidates::iterator const& collision, TrackCandidates const& tracks) @@ -1325,7 +1685,7 @@ struct tofSpectra { } hMultiplicityvsPercentile->Fill(getMultiplicity(collision), collision.multNTracksPV()); for (const auto& track : tracks) { - if (!isTrackSelected(track)) { + if (!isTrackSelected(track, collision)) { continue; } } @@ -1343,7 +1703,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); @@ -1364,7 +1724,7 @@ struct tofSpectra { return; \ } \ for (const auto& track : tracks) { \ - if (!isTrackSelected(track)) { \ + if (!isTrackSelected(track, collision)) { \ continue; \ } \ fillParticleHistos(track, collision); \ @@ -1525,23 +1885,28 @@ struct tofSpectra { using RecoMCCollisions = soa::Join; // RD template - void fillTrackHistograms_MC(TrackType const& track, ParticleType const& mcParticle, RecoMCCollisions::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; } - + if (!collision.has_mcCollision()) { + return; // Skips processing if no corresponding MC collision is found (rare case!) + } const auto& mcCollision = collision.mcCollision_as(); - float multiplicity = getMultiplicityMC(mcCollision); + const float multiplicity = getMultiplicity(collision); + const int occupancy = collision.trackOccupancyInTimeRange(); //************************************RD************************************************** - if (includeCentralityMC) { - multiplicity = mcCollision.impactParameter(); - } + const float impParam = mcCollision.impactParameter(); //************************************RD************************************************** if (mcParticle.pdgCode() != PDGs[i]) { return; } + if (track.eta() < trkselOptions.cfgCutEtaMin || track.eta() > trkselOptions.cfgCutEtaMax) { return; } @@ -1549,35 +1914,137 @@ struct tofSpectra { if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { return; } - if (!mcParticle.isPhysicalPrimary()) { - if (mcParticle.getProcess() == 4) { - 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 (enablePureDCAHistogram) { + const auto& nsigmaTPCKa = o2::aod::pidutils::tpcNSigma<3>(track); + const auto& nsigmaTOFKa = o2::aod::pidutils::tofNSigma<3>(track); + + // 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()); } - } else { - 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()); + + 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 { // Primaries + if (enableDCAxyzHistograms) { + 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 { + // DCAxy for all primaries + 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); + } + } + } + } } } } else { - if (enableDCAxyzHistograms) { - 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()); + if (!mcParticle.isPhysicalPrimary()) { + if (mcParticle.getProcess() == 4) { + histos.fill(HIST(hdcaxystr[i]), track.pt(), track.dcaXY()); + } else { + histos.fill(HIST(hdcaxymat[i]), track.pt(), track.dcaXY()); } } 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()); - } } } @@ -1596,11 +2063,29 @@ struct tofSpectra { 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& nsigmaTPCKa = o2::aod::pidutils::tpcNSigma<3>(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 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 = std::abs(nsigmaTOFPi) < trkselOptions.cfgCutNsigma; + const bool isKaonTOF = std::abs(nsigmaTOFKa) < 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.dcaXY()); + if (includeCentralityMC) { + histos.fill(HIST(hpt_num_str[i]), track.pt(), multiplicity, track.dcaXY()); + } } else { histos.fill(HIST(hpt_num_str[i]), track.pt(), multiplicity); } @@ -1624,12 +2109,139 @@ struct tofSpectra { } } } - } else { + } else { // Is physical primary if (includeCentralityMC) { - histos.fill(HIST(hpt_num_prm[i]), track.pt(), multiplicity, track.dcaXY()); + 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(), 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() && trkselOptions.lastRequiredTrdCluster > 0) { int lastLayer = 0; for (int l = 7; l >= 0; l--) { @@ -1643,8 +2255,99 @@ struct tofSpectra { } } 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.dcaXY()); + 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(), multiplicity); } @@ -1655,6 +2358,28 @@ struct tofSpectra { 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); + } } // Filling mismatched info for primary tracks @@ -1691,7 +2416,11 @@ struct tofSpectra { histos.fill(HIST(hpt_den_mat[i]), mcParticle.pt(), multiplicity); } } else { - histos.fill(HIST(hpt_den_prm[i]), mcParticle.pt(), multiplicity); + if (includeCentralityMC) { + histos.fill(HIST(hpt_den_prm[i]), mcParticle.pt(), multiplicity); + } else { + histos.fill(HIST(hpt_den_prm[i]), mcParticle.pt(), multiplicity); + } } } @@ -1767,7 +2496,7 @@ struct tofSpectra { const float multiplicity = getMultiplicityMC(mcCollision); if (mcParticle.isPhysicalPrimary()) { - if (abs(mcCollision.posZ()) < evselOptions.cfgCutVertex) { + 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(), multiplicity); @@ -1781,6 +2510,7 @@ struct tofSpectra { SliceCache cache; void processMC(soa::Join const& tracks, aod::McParticles const& mcParticles, @@ -1817,7 +2547,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) { @@ -1828,7 +2558,6 @@ struct tofSpectra { 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()) > trkselOptions.cfgCutY) { @@ -1886,7 +2615,7 @@ struct tofSpectra { // Loop on generated collisions for (const auto& mcCollision : mcCollisions) { - if (abs(mcCollision.posZ()) > evselOptions.cfgCutVertex) { + if (std::abs(mcCollision.posZ()) > evselOptions.cfgCutVertex) { continue; } histos.fill(HIST("MC/Multiplicity"), getMultiplicityMC(mcCollision)); @@ -1913,12 +2642,12 @@ struct tofSpectra { fillParticleHistograms_MCGenEvs(mcParticle, mcCollision); }); } - // if (mcCollision.isInelGt0()) { - // histos.fill(HIST("MC/GenRecoCollisions"), 3.f); - // } - // if (mcCollision.isInelGt1()) { - // histos.fill(HIST("MC/GenRecoCollisions"), 4.f); - // } + if (mcCollision.isInelGt0()) { + histos.fill(HIST("MC/GenRecoCollisions"), 3.f); + } + if (mcCollision.isInelGt1()) { + histos.fill(HIST("MC/GenRecoCollisions"), 4.f); + } if (hasParticleInFT0C && hasParticleInFT0A) { histos.fill(HIST("MC/GenRecoCollisions"), 5.f); } @@ -1937,81 +2666,120 @@ struct tofSpectra { int pdgCode = mcParticleGen.pdgCode(); float pt = mcParticleGen.pt(); float absY = std::abs(mcParticleGen.y()); - // Apply rapidity cut if (absY > trkselOptions.cfgCutY) { continue; } - // Fill histograms based on particle type - switch (pdgCode) { - case 2212: - histos.fill(HIST("MC/test/pr/pos/prm/pt/den"), pt, multiplicity); - break; - case -2212: - histos.fill(HIST("MC/test/pr/neg/prm/pt/den"), pt, multiplicity); - break; - case 211: - histos.fill(HIST("MC/test/pi/pos/prm/pt/den"), pt, multiplicity); - break; - case -211: - histos.fill(HIST("MC/test/pi/neg/prm/pt/den"), pt, multiplicity); - break; - case 321: - histos.fill(HIST("MC/test/ka/pos/prm/pt/den"), pt, multiplicity); - break; - case -321: - histos.fill(HIST("MC/test/ka/neg/prm/pt/den"), pt, multiplicity); - break; - default: - break; + 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(GenMCCollisions const&, RecoMCCollisions const& collisions, aod::McParticles const& mcParticles) + 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(); - const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); histos.fill(HIST("Vertex/RecoEvs/histGenVtxMC"), mcCollision.posZ()); histos.fill(HIST("Centrality/RecoEvs/ImpParm"), mcCollision.impactParameter()); const float multiplicity = mcCollision.impactParameter(); - for (const auto& mcParticleGen : particlesInCollision) { - if (!mcParticleGen.isPhysicalPrimary()) + + 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; - int pdgCode = mcParticleGen.pdgCode(); - float pt = mcParticleGen.pt(); - float absY = std::abs(mcParticleGen.y()); - // Apply rapidity cut + } + 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; } - // Fill histograms based on particle type - switch (pdgCode) { - case 2212: - histos.fill(HIST("MC/test/RecoEvs/pr/pos/prm/pt/den"), pt, multiplicity); - break; - case -2212: - histos.fill(HIST("MC/test/RecoEvs/pr/neg/prm/pt/den"), pt, multiplicity); - break; - case 211: - histos.fill(HIST("MC/test/RecoEvs/pi/pos/prm/pt/den"), pt, multiplicity); - break; - case -211: - histos.fill(HIST("MC/test/RecoEvs/pi/neg/prm/pt/den"), pt, multiplicity); - break; - case 321: - histos.fill(HIST("MC/test/RecoEvs/ka/pos/prm/pt/den"), pt, multiplicity); - break; - case -321: - histos.fill(HIST("MC/test/RecoEvs/ka/neg/prm/pt/den"), pt, multiplicity); - break; - default: - break; + 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); + } } } } diff --git a/PWGLF/Tasks/Nuspex/spectraTOFRun2.cxx b/PWGLF/Tasks/Nuspex/spectraTOFRun2.cxx index efcc58dd55d..e485f56bba4 100644 --- a/PWGLF/Tasks/Nuspex/spectraTOFRun2.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTOFRun2.cxx @@ -18,20 +18,22 @@ /// // O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/spectraTOF.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" #include "Framework/StaticFor.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "PWGLF/DataModel/spectraTOF.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" #include "TPDGCode.h" @@ -348,7 +350,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 +470,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 +498,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..d3f49748bc7 100644 --- a/PWGLF/Tasks/Nuspex/spectraTPC.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTPC.cxx @@ -18,14 +18,16 @@ /// // O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::track; @@ -117,7 +119,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 +133,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 +157,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 +165,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); @@ -186,7 +188,7 @@ struct tpcSpectra { fillParticleHistos(track); } } // end of the process function -}; // end of spectra task +}; // end of spectra task struct tpcPidQaSignalwTof { static constexpr int Np = 9; @@ -279,7 +281,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 +289,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/spectraTPCPiKaPr.cxx b/PWGLF/Tasks/Nuspex/spectraTPCPiKaPr.cxx index 0b856a92e6b..75595bf89ef 100644 --- a/PWGLF/Tasks/Nuspex/spectraTPCPiKaPr.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTPCPiKaPr.cxx @@ -17,12 +17,13 @@ /// // O2 includes -#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Nuspex/spectraTPCtiny.cxx b/PWGLF/Tasks/Nuspex/spectraTPCtiny.cxx index 12fc53f6bfc..c75db4dfd3a 100644 --- a/PWGLF/Tasks/Nuspex/spectraTPCtiny.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTPCtiny.cxx @@ -17,12 +17,13 @@ /// // O2 includes -#include "ReconstructionDataFormats/Track.h" -#include "Framework/runDataProcessing.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::framework; @@ -58,7 +59,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 +79,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 +87,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..a2df451d147 100644 --- a/PWGLF/Tasks/Nuspex/spectraTPCtinyPiKaPr.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTPCtinyPiKaPr.cxx @@ -17,12 +17,13 @@ /// // O2 includes -#include "ReconstructionDataFormats/Track.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" #include "Framework/HistogramRegistry.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::framework; @@ -49,7 +50,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 index c640ee82586..319d21d9d96 100644 --- a/PWGLF/Tasks/QC/CMakeLists.txt +++ b/PWGLF/Tasks/QC/CMakeLists.txt @@ -44,6 +44,12 @@ 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 @@ -66,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 @@ -105,11 +111,41 @@ o2physics_add_dpl_workflow(mcinelgt0 COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(tracked-cascade-properties - SOURCES tracked_cascade_properties.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + SOURCES trackedCascadeProperties.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils 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) + +o2physics_add_dpl_workflow(systematics-mapping + SOURCES systematicsMapping.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(hypertriton3body-qa + SOURCES hypertriton3bodyQa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::TOFBase + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/QC/efficiencyQA.cxx b/PWGLF/Tasks/QC/efficiencyQA.cxx index 62bfc4e1622..83ef2f05a65 100644 --- a/PWGLF/Tasks/QC/efficiencyQA.cxx +++ b/PWGLF/Tasks/QC/efficiencyQA.cxx @@ -9,27 +9,27 @@ // 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/Core/PID/TPCPIDResponse.h" #include "Common/Core/RecoDecay.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 "Common/DataModel/PIDResponseTPC.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "Common/DataModel/PIDResponse.h" +#include "CCDB/BasicCCDBManager.h" #include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -449,7 +449,7 @@ struct efficiencyQA { histos.fill(HIST("tagCuts"), 5., tagTrack.sign() * tagTrack.pt()); // if survived all selections, propagate decay daughters to PV - gpu::gpustd::array dcaInfo; + std::array dcaInfo; o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, tagTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); float tagDcaXYZ = dcaInfo[0]; @@ -534,7 +534,7 @@ struct efficiencyQA { continue; } - gpu::gpustd::array dcaInfo; + std::array dcaInfo; auto tpcTrackCov = getTrackParCov(tpcTrack); if (propToTPCinnerWall) { o2::base::Propagator::Instance()->PropagateToXBxByBz(probeTrackCov, 70.f, 1.f, 2.f, fitter.getMatCorrType()); @@ -660,7 +660,7 @@ struct efficiencyQA { if (hasITS && !hasTPC) { auto tagTrack = tracks.rawIteratorAt(probeTrack.globalIndexTag); auto tagTrackCov = getTrackParCov(tagTrack); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; o2::base::Propagator::Instance()->propagateToDCABxByBz({probeTrack.vtx0, probeTrack.vtx1, probeTrack.vtx2}, tagTrackCov, 2.f, fitter.getMatCorrType(), &dcaInfo); std::array momTag; tagTrackCov.getPxPyPzGlo(momTag); @@ -697,7 +697,7 @@ struct efficiencyQA { histos.fill(HIST("timeTpcItsNoNorm"), tdiff); auto trackCov = getTrackParCov(tpcTrack); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; if (propToTPCinnerWall) { o2::base::Propagator::Instance()->PropagateToXBxByBz(trackCov, 70.f, 1.f, 2.f, fitter.getMatCorrType()); } else { @@ -848,7 +848,7 @@ struct efficiencyQA { const o2::math_utils::Point3D collVtx{collision.posX(), collision.posY(), collision.posZ()}; auto trackParCov = getTrackParCov(track); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParCov, d_bz, 2.f, static_cast(cfgMaterialCorrection.value), &dcaInfo); auto trackPt = track.sign() * trackParCov.getPt(); diff --git a/PWGLF/Tasks/QC/findableStudy.cxx b/PWGLF/Tasks/QC/findableStudy.cxx index d8ca8cc8c80..512f5dd6b4d 100644 --- a/PWGLF/Tasks/QC/findableStudy.cxx +++ b/PWGLF/Tasks/QC/findableStudy.cxx @@ -19,42 +19,43 @@ // david.dobrigkeit.chinellato@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/v0SelectionBits.h" +#include "PWGLF/Utils/v0SelectionGroup.h" +#include "PWGLF/Utils/v0SelectionTools.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/LFStrangenessPIDTables.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" #include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.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 "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include #include #include -#include #include #include -#include +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/QC/hypertriton3bodyQa.cxx b/PWGLF/Tasks/QC/hypertriton3bodyQa.cxx new file mode 100644 index 00000000000..c0b2c1dfd55 --- /dev/null +++ b/PWGLF/Tasks/QC/hypertriton3bodyQa.cxx @@ -0,0 +1,843 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file hypertriton3bodyQa.cxx +/// \brief QA for MC productions which contain hypertriton 3body decay process, including special checks for TOF PID +/// \author Yuanzhe Wang + +#include "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/pidTOFGeneric.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/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "CommonDataFormat/IRFrame.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +o2::common::core::MetadataHelper metadataInfo; + +using std::array; +using ColwithEvTimes = o2::soa::Join; +using FullTracksExtIU = soa::Join; +using MCLabeledTracksIU = soa::Join; + +namespace +{ +constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f; // c in cm/ps +} // namespace + +template +bool is3bodyDecayedH3L(TMCParticle const& particle) +{ + if (std::abs(particle.pdgCode()) != o2::constants::physics::Pdg::kHyperTriton) { + 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() == PDG_t::kProton) + haveProton = true; + if (mcDaughter.pdgCode() == -PDG_t::kProton) + haveAntiProton = true; + if (mcDaughter.pdgCode() == PDG_t::kPiPlus) + havePion = true; + if (mcDaughter.pdgCode() == PDG_t::kPiMinus) + haveAntiPion = true; + if (mcDaughter.pdgCode() == o2::constants::physics::Pdg::kDeuteron) + haveDeuteron = true; + if (mcDaughter.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) + 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() == o2::constants::physics::Pdg::kHyperTriton && mctrack0.pdgCode() == PDG_t::kProton && mctrack1.pdgCode() == PDG_t::kPiMinus && mctrack2.pdgCode() == o2::constants::physics::Pdg::kDeuteron) && + !(particleMother.pdgCode() == -o2::constants::physics::Pdg::kHyperTriton && mctrack0.pdgCode() == -PDG_t::kProton && mctrack1.pdgCode() == PDG_t::kPiPlus && mctrack2.pdgCode() == -o2::constants::physics::Pdg::kDeuteron)) { + 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 Hypertriton3bodyQa { + + Service ccdb; + Preslice perCollisionTracks = aod::track::collisionId; + + 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 doSel8selection{"doSel8selection", true, "flag for sel8 event selection"}; + Configurable doPosZselection{"doPosZselection", true, "flag for posZ event selection"}; + + Configurable maxZVertex{"maxZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable nTPCClusMinDaug{"nTPCClusMinDaug", 70, "daug NTPC clusters cut"}; + Configurable cutTOFNSigmaDeuteron{"cutTOFNSigmaDeuteron", 5, "TOF NSigma cut for good performance"}; + + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + + // 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}}}}, + + {"hDetectedHypertritonEta", "hDetectedHypertritonEta", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hDetectedHypertritonMcRapidity", "hDetectedHypertritonMcRapidity", {HistType::kTH1F, {{200, -10.0f, 10.0f}}}}, + {"hDetectedHypertritonMcPt", "hDetectedHypertritonMcPt", {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}}}}, + {"hDauDeuteronNsigmaDeuteron", "hDauDeuteronNsigmaDeuteron", {HistType::kTH1F, {{120, -6.0f, 6.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, {{2, 0.0f, 2.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"}}}}, + {"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}}}}, + }, + }; + + int mRunNumber = 0; + + o2::aod::pidtofgeneric::TofPidNewCollision bachelorTOFPID; + o2::pid::tof::TOFResoParamsV3 mRespParamsV3; + o2::aod::pidtofgeneric::TOFCalibConfig mTOFCalibConfig; // TOF Calib configuration + + void init(InitContext& initContext) + { + // Initialization of ccdb and TOF PID + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + mTOFCalibConfig.metadataInfo = metadataInfo; + mTOFCalibConfig.inheritFromBaseTask(initContext); + mTOFCalibConfig.initSetup(mRespParamsV3, ccdb); + bachelorTOFPID.SetPidType(o2::track::PID::Deuteron); + + // Initialization of histograms + 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"); + + std::vector trackCounterbinLabel = {"hasMom", "FromHypertriton"}; + for (size_t i = 0; i < trackCounterbinLabel.size(); 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"); + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + + mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bc); + } + + 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 (doSel8selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + continue; + } + registry.fill(HIST("hEventCounter"), 1.5); + if (doPosZselection && std::abs(collision.posZ()) > maxZVertex) { // 10cm + continue; + } + registry.fill(HIST("hEventCounter"), 2.5); + + std::vector indicesProton, indicesPion, indicesDeuteron; // indices for daughter tracks + std::unordered_set globalIDProton, globalIDPion, globalIDDeuteron; // 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 (std::abs(mcparticle.pdgCode()) == o2::constants::physics::Pdg::kHyperTriton) { + registry.fill(HIST("hParticleCounter"), 3.5); + registry.fill(HIST("hDetectedHypertritonMcPt"), mcparticle.pt()); + registry.fill(HIST("hDetectedHypertritonEta"), track.eta()); + registry.fill(HIST("hDetectedHypertritonMcRapidity"), mcparticle.y()); + } + + // Proton + if (std::abs(mcparticle.pdgCode()) == PDG_t::kProton) { + registry.fill(HIST("hParticleCounter"), 4.5); + if (track.tpcNClsFound() > nTPCClusMinDaug) { + 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 is3bodyH3L = is3bodyDecayedH3L(particleMother); + if (!is3bodyH3L) { + continue; + } + indicesProton.push_back(itrack); + auto p = globalIDProton.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 (std::abs(mcparticle.pdgCode()) == PDG_t::kPiPlus) { + registry.fill(HIST("hParticleCounter"), 5.5); + if (track.tpcNClsFound() > nTPCClusMinDaug) { + 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 is3bodyH3L = is3bodyDecayedH3L(particleMother); + if (!is3bodyH3L) { + continue; + } + indicesPion.push_back(itrack); + auto p = globalIDPion.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("hDauPionNsigmaPion"), track.tpcNSigmaPi()); + 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; + + 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(mRespParamsV3, track, tofsignal, track.tofEvTimeErr()); + // tofNsigmaDe = (track.tofSignal() - track.tofEvTime() - responseDe.GetCorrectedExpectedSignal(mRespParamsV2, track)) / expSigma; + tofNsigmaDe = (tofsignal - track.tofEvTime() - responseDe.GetCorrectedExpectedSignal(mRespParamsV3, 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 deuteron 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(mRespParamsV3, track, collision, collision)); + // registry.fill(HIST("hDiffTrackTOFNSigmaDe"), track.tofExpSigmaDe() - bachelorTOFPID.GetTOFNSigma(mRespParamsV3, track, collision, collision)); + } + + // Deuteron + if (std::abs(mcparticle.pdgCode()) == o2::constants::physics::Pdg::kDeuteron) { + registry.fill(HIST("hParticleCounter"), 6.5); + if (track.tpcNClsFound() > nTPCClusMinDaug) { + 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 is3bodyH3L = is3bodyDecayedH3L(particleMother); + if (!is3bodyH3L) { + continue; + } + indicesDeuteron.push_back(itrack); + auto p = globalIDDeuteron.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("hDauDeuteronNsigmaDeuteron"), track.tpcNSigmaDe()); + 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()); + } + } + + // Check how many daughters are assigned to the same collision + std::vector pairsInSameCol; + for (size_t iproton = 0; iproton < indicesProton.size(); iproton++) { + auto track0 = tracks.iteratorAt(indicesProton[iproton]); + auto mctrack0 = track0.mcParticle_as(); + for (size_t ipion = 0; ipion < indicesPion.size(); ipion++) { + auto track1 = tracks.iteratorAt(indicesPion[ipion]); + auto mctrack1 = track1.mcParticle_as(); + for (size_t ideuteron = 0; ideuteron < indicesDeuteron.size(); ideuteron++) { + auto track2 = tracks.iteratorAt(indicesDeuteron[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); + // duplicated daughters check + Indexdaughters temp = {mctrack0.globalIndex(), mctrack1.globalIndex(), mctrack2.globalIndex()}; + auto p = std::find(pairsInSameCol.begin(), pairsInSameCol.end(), temp); + if (p == pairsInSameCol.end()) { + pairsInSameCol.push_back(temp); + registry.fill(HIST("hPairedH3LDaughers"), 1); + } + } + } + } + } + } + + // Check for recalculated TOF PID for secondary deuteron + + 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() == o2::constants::physics::Pdg::kDeuteron || mcparticle.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) { + 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 is3bodyH3L = is3bodyDecayedH3L(particleMother); + if (!is3bodyH3L) { + 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(mRespParamsV3, track, originalcollision, collision); + tofNsigmaDeEvSel = bachelorTOFPID.GetTOFNSigma(mRespParamsV3, 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()) >= cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 0.5); + if (std::abs(tofNsigmaDeAO2D) < cutTOFNSigmaDeuteron && std::abs(tofNsigmaDeEvSel) < cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 1.5); + } else if (std::abs(tofNsigmaDeAO2D) < cutTOFNSigmaDeuteron && std::abs(tofNsigmaDeEvSel) >= cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 2.5); + } else if (std::abs(tofNsigmaDeAO2D) >= cutTOFNSigmaDeuteron && std::abs(tofNsigmaDeEvSel) < cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 3.5); + } else if (std::abs(tofNsigmaDeAO2D) >= cutTOFNSigmaDeuteron && std::abs(tofNsigmaDeEvSel) >= cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter"), 4.5); + } + } else if (std::abs(track.tofNSigmaDe()) < cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 0.5); + if (std::abs(tofNsigmaDeAO2D) < cutTOFNSigmaDeuteron && std::abs(tofNsigmaDeEvSel) < cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 1.5); + } else if (std::abs(tofNsigmaDeAO2D) < cutTOFNSigmaDeuteron && std::abs(tofNsigmaDeEvSel) >= cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 2.5); + } else if (std::abs(tofNsigmaDeAO2D) >= cutTOFNSigmaDeuteron && std::abs(tofNsigmaDeEvSel) < cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 3.5); + } else if (std::abs(tofNsigmaDeAO2D) >= cutTOFNSigmaDeuteron && std::abs(tofNsigmaDeEvSel) >= cutTOFNSigmaDeuteron) { + registry.fill(HIST("hDauDeuteronTOFPIDCounter_CloseBC"), 4.5); + } + } + } + } + } + } + } +}; + +// check the performance of mcparticle +struct Hypertriton3bodyMcParticleCheck { + + Configurable maxZVertex{"maxZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + + // 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, {{6, 0.0f, 6.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"); + } + + Configurable doSel8selection{"doSel8selection", true, "flag for sel8 event selection"}; + Configurable doPosZselection{"doPosZselection", true, "flag for posZ event selection"}; + + 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 (doSel8selection && (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + continue; + } + if (doPosZselection && std::abs(collision.posZ()) > maxZVertex) { // 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 (std::abs(mcparticle.pdgCode()) == PDG_t::kProton) { + registry.fill(HIST("hMcProtonPt"), mcparticle.pt()); + } + if (std::abs(mcparticle.pdgCode()) == PDG_t::kPiPlus) { + registry.fill(HIST("hMcPionPt"), mcparticle.pt()); + } + if (std::abs(mcparticle.pdgCode()) == o2::constants::physics::Pdg::kDeuteron) { + registry.fill(HIST("hMcDeuteronPt"), mcparticle.pt()); + } + + if (std::abs(mcparticle.pdgCode()) == o2::constants::physics::Pdg::kHyperTriton) { + registry.fill(HIST("hMcHypertritonCounter"), 0.5); + registry.fill(HIST("hMcHypertritonPt"), mcparticle.pt()); + bool isMatter = mcparticle.pdgCode() > 0 ? true : false; + if (isMatter) { + registry.fill(HIST("hMcHypertritonCounter"), 1.5); + } else { + registry.fill(HIST("hMcHypertritonCounter"), 2.5); + } + + 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 is3bodyH3L = is3bodyDecayedH3L(mcparticle); + if (!is3bodyH3L) { + continue; + } + for (const auto& mcparticleDaughter : mcparticle.daughters_as()) { + if (std::abs(mcparticleDaughter.pdgCode()) == PDG_t::kProton) { + 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()) == PDG_t::kPiPlus) { + 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()) == o2::constants::physics::Pdg::kDeuteron) { + 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 (isMatter) { + registry.fill(HIST("hMcHypertritonCounter"), 3.5); + registry.fill(HIST("hMcHypertritonCounter"), 4.5); + } else { + 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); + + 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); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/Tasks/QC/kfPerformanceStudy.cxx b/PWGLF/Tasks/QC/kfPerformanceStudy.cxx index 5a9f49ecabf..2fb758041e6 100644 --- a/PWGLF/Tasks/QC/kfPerformanceStudy.cxx +++ b/PWGLF/Tasks/QC/kfPerformanceStudy.cxx @@ -13,22 +13,23 @@ // cascades computed with standard DCAFitter methods and the KFparticle // package. It is meant for the purposes of larger-scale QA of KF reco. -#include +#include "PWGLF/DataModel/LFStrangenessTables.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 "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include using namespace o2; using namespace o2::framework; @@ -151,8 +152,8 @@ struct kfPerformanceStudy { } histos.fill(HIST("hPtCorrelation"), pt, ptKF); - histos.fill(HIST("h3dMassLambda"), pt, massLambda, massLambdaKF); // <- implicit pT choice, beware - histos.fill(HIST("h3dDCAxy"), pt, dcaXY, dcaXYKF); // <- implicit pT choice, beware + histos.fill(HIST("h3dMassLambda"), pt, massLambda, massLambdaKF); // <- implicit pT choice, beware + histos.fill(HIST("h3dDCAxy"), pt, dcaXY, dcaXYKF); // <- implicit pT choice, beware histos.fill(HIST("h3dPointingAngle"), pt, pointingAngle, pointingAngleKF); // <- implicit pT choice, beware histos.fill(HIST("hPointingAngle"), pointingAngle); diff --git a/PWGLF/Tasks/QC/lfITSTPCMatchingQA.cxx b/PWGLF/Tasks/QC/lfITSTPCMatchingQA.cxx index c31258d51ae..a4813422730 100644 --- a/PWGLF/Tasks/QC/lfITSTPCMatchingQA.cxx +++ b/PWGLF/Tasks/QC/lfITSTPCMatchingQA.cxx @@ -9,26 +9,27 @@ // 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 "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/TPCPIDResponse.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "DataFormatsTPC/BetheBlochAleph.h" -#include "Common/Core/PID/PIDTOF.h" #include "Common/TableProducer/PID/pidTOFBase.h" + +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Common/Core/PID/TPCPIDResponse.h" -#include "Common/DataModel/PIDResponse.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" #include "TDatabasePDG.h" +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/PWGLF/Tasks/QC/lfITSTPCMatchingSecondaryTracksQA.cxx b/PWGLF/Tasks/QC/lfITSTPCMatchingSecondaryTracksQA.cxx new file mode 100644 index 00000000000..9cdf87e0593 --- /dev/null +++ b/PWGLF/Tasks/QC/lfITSTPCMatchingSecondaryTracksQA.cxx @@ -0,0 +1,348 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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/lfpidqa.cxx b/PWGLF/Tasks/QC/lfpidqa.cxx index 746473fd0a7..64882d204e6 100644 --- a/PWGLF/Tasks/QC/lfpidqa.cxx +++ b/PWGLF/Tasks/QC/lfpidqa.cxx @@ -17,21 +17,23 @@ /// \brief Task to produce the PID QA information for the TPC for the purpose of the Light flavor PWG /// -#include +#include "PWGLF/DataModel/LFParticleIdentification.h" -#include "Framework/runDataProcessing.h" -#include "Framework/StaticFor.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/HistogramRegistry.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/TrackSelection.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/EventSelection.h" -#include "Common/Core/TrackSelection.h" -#include "PWGLF/DataModel/LFParticleIdentification.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" + +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/QC/lfpropStudy.cxx b/PWGLF/Tasks/QC/lfpropStudy.cxx index ab3c88ebbb3..45f05aeb700 100644 --- a/PWGLF/Tasks/QC/lfpropStudy.cxx +++ b/PWGLF/Tasks/QC/lfpropStudy.cxx @@ -14,20 +14,21 @@ /// \author Carolina Reetz /// \brief QA task to study properties of propagated tracks -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/DCA.h" #include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.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/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" + #include "TPDGCode.h" using namespace o2; diff --git a/PWGLF/Tasks/QC/mcParticlePrediction.cxx b/PWGLF/Tasks/QC/mcParticlePrediction.cxx index 6d769fecae5..821d98de975 100644 --- a/PWGLF/Tasks/QC/mcParticlePrediction.cxx +++ b/PWGLF/Tasks/QC/mcParticlePrediction.cxx @@ -43,21 +43,28 @@ bool enabledParticlesArray[PIDExtended::NIDsTot]; // Estimators struct Estimators { - static const int FT0A = 0; - static const int FT0C = 1; - static const int FT0AC = 2; - static const int FV0A = 3; - static const int FDDA = 4; - static const int FDDC = 5; - static const int FDDAC = 6; - static const int ZNA = 7; - static const int ZNC = 8; - static const int ZEM1 = 9; - static const int ZEM2 = 10; - static const int ZPA = 11; - static const int ZPC = 12; - static const int ITS = 13; - static const int nEstimators = 14; + 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 ImpactParameter = 19; // (Run2 V0M) + static constexpr estID nEstimators = 20; static constexpr const char* estimatorNames[nEstimators] = {"FT0A", "FT0C", @@ -72,10 +79,19 @@ struct Estimators { "ZEM2", "ZPA", "ZPC", - "ITS"}; + "ITSIB", + "ETA05", + "ETA08", + "V0A", + "V0C", + "V0AC", + "ImpactParameter"}; static std::vector arrayNames() { - std::vector names; + static std::vector names; + if (!names.empty()) { + return names; + } for (int i = 0; i < nEstimators; i++) { names.push_back(estimatorNames[i]); } @@ -96,11 +112,20 @@ static const int defaultEstimators[Estimators::nEstimators][nParameters]{{0}, / {0}, // ZEM2 {0}, // ZPA {0}, // ZPC - {0}}; // ITS + {0}, // ITSIB + {0}, // ETA05 + {0}, // ETA08 + {0}, // V0A (Run2) + {0}, // V0C (Run2) + {0}, // V0AC (Run2 V0M) + {0}}; // ImpactParamter // 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> hestimatorsVsImpactParameter; std::array, Estimators::nEstimators> hestimatorsRecoEvGenVsReco; std::array, Estimators::nEstimators> hestimatorsRecoEvGenVsReco_BCMC; std::array, Estimators::nEstimators> hestimatorsRecoEvGenVsRecoITS; @@ -125,6 +150,7 @@ struct mcParticlePrediction { 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 binsImpactParameter{"binsImpactParameter", {400, 0.0, 20.0}, "Binning of the impact parameter 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", @@ -135,7 +161,7 @@ struct mcParticlePrediction { "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"}; @@ -145,6 +171,10 @@ struct mcParticlePrediction { 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"}; + Configurable enableVsImpactParameterHistograms{"enableVsImpactParameterHistograms", true, "Enables the correlation between impact parameter and other estimators"}; Service pdgDB; o2::pwglf::ParticleCounter mCounter; @@ -158,9 +188,10 @@ struct mcParticlePrediction { const AxisSpec axisVy{binsVxy, "Vy"}; const AxisSpec axisVz{binsVz, "Vz"}; const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisImpactParameter{binsImpactParameter, "Impact parameter (fm)"}; const AxisSpec axisMultiplicity{binsMultiplicity, "Multiplicity (undefined)"}; const AxisSpec axisMultiplicityReco{binsMultiplicityReco, "Multiplicity Reco. (undefined)"}; - const AxisSpec axisMultiplicityRecoITS{100, 0, 100, "Multiplicity Reco. ITS"}; + const AxisSpec axisMultiplicityRecoITS{binsMultiplicityReco, "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"}; @@ -234,18 +265,44 @@ struct mcParticlePrediction { if (!enabledEstimatorsArray[i]) { continue; } + AxisSpec axisThisEstimator = axisMultiplicity; + if (i == Estimators::ImpactParameter) { + axisThisEstimator = axisImpactParameter; + } const char* name = Estimators::estimatorNames[i]; - hestimators[i] = histos.add(Form("multiplicity/%s", name), name, kTH1D, {axisMultiplicity}); + hestimators[i] = histos.add(Form("multiplicity/%s", name), name, kTH1D, {axisThisEstimator}); hestimators[i]->GetXaxis()->SetTitle(Form("Multiplicity %s", name)); - hestimatorsVsITS[i] = histos.add(Form("multiplicity/vsITS/%s", name), name, kTH2D, {axisMultiplicity, axisMultiplicity}); - hestimatorsVsITS[i]->GetXaxis()->SetTitle(Form("Multiplicity %s", name)); - hestimatorsVsITS[i]->GetYaxis()->SetTitle(Form("Multiplicity %s", Estimators::estimatorNames[Estimators::ITS])); + auto make2DH = [&](const std::string& h, const char* ytitle, bool isImpactParameterX = false, bool isImpactParameterY = false) { + auto hist = histos.add(Form("%s%s", h.c_str(), name), + name, + kTH2D, + {isImpactParameterX ? axisImpactParameter : axisMultiplicity, + isImpactParameterY ? axisImpactParameter : axisMultiplicity}); + hist->GetXaxis()->SetTitle(Form("Multiplicity %s", name)); + hist->GetYaxis()->SetTitle(Form("Multiplicity %s", ytitle)); + return hist; + }; + if (enableVsITSHistograms) { + hestimatorsVsITS[i] = make2DH("multiplicity/vsITS/", Estimators::estimatorNames[Estimators::ITSIB], (i == Estimators::ImpactParameter)); + } + if (enableVsEta05Histograms) { + hestimatorsVsETA05[i] = make2DH("multiplicity/vsETA05/", Estimators::estimatorNames[Estimators::ETA05], (i == Estimators::ImpactParameter)); + } + if (enableVsEta08Histograms) { + hestimatorsVsETA08[i] = make2DH("multiplicity/vsETA08/", Estimators::estimatorNames[Estimators::ETA08], (i == Estimators::ImpactParameter)); + } + if (enableVsImpactParameterHistograms) { + hestimatorsVsImpactParameter[i] = make2DH("multiplicity/vsImpactParameter/", Estimators::estimatorNames[Estimators::ImpactParameter], (i == Estimators::ImpactParameter), true); + } - hvertexPosZ[i] = histos.add(Form("multiplicity/posZ/%s", name), name, kTH2D, {{200, -20, 20, "pos Z"}, axisMultiplicity}); + hvertexPosZ[i] = histos.add(Form("multiplicity/posZ/%s", name), name, kTH2D, {{200, -20, 20, "pos Z"}, axisThisEstimator}); hvertexPosZ[i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); - // Reco events + 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)); @@ -259,7 +316,7 @@ struct mcParticlePrediction { 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::ITS])); + 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)); @@ -274,8 +331,7 @@ struct mcParticlePrediction { 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] = histosRecoEvs.add(Form("multiplicity/Reco/VsBCId/%s", name), name, kTH2D, {axisBCID, axisMultiplicity}); hestimatorsRecoEvVsBCId[i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); } @@ -290,11 +346,15 @@ struct mcParticlePrediction { if (!enabledEstimatorsArray[j]) { continue; } + AxisSpec axisThisEstimator = axisMultiplicity; + if (j == Estimators::ImpactParameter) { + axisThisEstimator = axisImpactParameter; + } 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] = histosPt.add(Form("prediction/pt/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH2D, {axisPt, axisThisEstimator}); 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] = histosYield.add(Form("prediction/yield/%s/%s", name, PIDExtended::getName(i)), PIDExtended::getName(i), kTH1D, {axisThisEstimator}); hyield[j][i]->GetYaxis()->SetTitle(Form("Multiplicity %s", name)); } } @@ -304,6 +364,69 @@ struct mcParticlePrediction { histosYield.print(); } + std::array genMult(const auto& mcCollision, 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; + } + } + if (enabledEstimatorsArray[Estimators::ImpactParameter]) { + nMult[Estimators::ImpactParameter] = mcCollision.impactParameter(); + } + return nMult; + } + void process(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { @@ -313,21 +436,12 @@ struct mcParticlePrediction { } histos.fill(HIST("collisions/generated"), 1); - if (abs(mcCollision.posZ()) > 10.f) { + if (std::abs(mcCollision.posZ()) > 10.f) { return; } histos.fill(HIST("collisions/generated"), 2); - float nMult[Estimators::nEstimators]; - nMult[Estimators::FT0A] = mCounter.countFT0A(mcParticles); - nMult[Estimators::FT0C] = mCounter.countFT0C(mcParticles); - nMult[Estimators::FT0AC] = nMult[Estimators::FT0A] + nMult[Estimators::FT0C]; - nMult[Estimators::FV0A] = mCounter.countFV0A(mcParticles); - nMult[Estimators::FDDA] = mCounter.countFDDA(mcParticles); - nMult[Estimators::FDDC] = mCounter.countFDDC(mcParticles); - nMult[Estimators::FDDAC] = nMult[Estimators::FDDA] + nMult[Estimators::FDDC]; - nMult[Estimators::ZNA] = mCounter.countZNA(mcParticles); - nMult[Estimators::ZNC] = mCounter.countZNC(mcParticles); - nMult[Estimators::ITS] = mCounter.countITSIB(mcParticles); + + const std::array& nMult = genMult(mcCollision, mcParticles); for (int i = 0; i < Estimators::nEstimators; i++) { if (!enabledEstimatorsArray[i]) { @@ -335,7 +449,18 @@ struct mcParticlePrediction { } hestimators[i]->Fill(nMult[i]); - hestimatorsVsITS[i]->Fill(nMult[i], nMult[Estimators::ITS]); + 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]); + } + if (enableVsImpactParameterHistograms) { + hestimatorsVsImpactParameter[i]->Fill(nMult[i], nMult[Estimators::ImpactParameter]); + } hvertexPosZ[i]->Fill(mcCollision.posZ(), nMult[i]); } @@ -355,14 +480,14 @@ struct mcParticlePrediction { TParticlePDG* p = pdgDB->GetParticle(particle.pdgCode()); if (p) { - if (abs(p->Charge()) > 1e-3) { + 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 (abs(particle.y()) > 0.5) { + if (std::abs(particle.y()) > 0.5) { continue; } @@ -436,7 +561,7 @@ struct mcParticlePrediction { } histos.fill(HIST("collisions/reconstructed"), 8); - if (abs(collision.posZ()) > posZCut.value) { + if (std::abs(collision.posZ()) > posZCut.value) { return; } histos.fill(HIST("collisions/reconstructed"), 9); @@ -511,17 +636,7 @@ struct mcParticlePrediction { histos.fill(HIST("particles/FromCollVsFromCollBad"), particlesFromColl, particlesFromCollWrongBC); histos.fill(HIST("particles/FromCollBadOverFromCollVsVsFromMCColl"), 1.f * particlesFromCollWrongBC / particlesFromColl, particlesInCollision.size()); - float nMult[Estimators::nEstimators]; - nMult[Estimators::FT0A] = mCounter.countFT0A(particlesInCollision); - nMult[Estimators::FT0C] = mCounter.countFT0C(particlesInCollision); - nMult[Estimators::FT0AC] = nMult[Estimators::FT0A] + nMult[Estimators::FT0C]; - nMult[Estimators::FV0A] = mCounter.countFV0A(particlesInCollision); - nMult[Estimators::FDDA] = mCounter.countFDDA(particlesInCollision); - nMult[Estimators::FDDC] = mCounter.countFDDC(particlesInCollision); - nMult[Estimators::FDDAC] = nMult[Estimators::FDDA] + nMult[Estimators::FDDC]; - nMult[Estimators::ZNA] = mCounter.countZNA(particlesInCollision); - nMult[Estimators::ZNC] = mCounter.countZNC(particlesInCollision); - nMult[Estimators::ITS] = mCounter.countITSIB(particlesInCollision); + const std::array& nMult = genMult(mcCollision, particlesInCollision); float nMultReco[Estimators::nEstimators]; nMultReco[Estimators::FT0A] = collision.multFT0A(); @@ -533,7 +648,7 @@ struct mcParticlePrediction { nMultReco[Estimators::FDDAC] = collision.multFDDM(); nMultReco[Estimators::ZNA] = collision.multZNA(); nMultReco[Estimators::ZNC] = collision.multZNC(); - nMultReco[Estimators::ITS] = collision.multNTracksPV(); + nMultReco[Estimators::ITSIB] = collision.multNTracksPV(); float nMultRecoMCBC[Estimators::nEstimators] = {0}; if (mcBC.has_ft0()) { @@ -556,10 +671,10 @@ struct mcParticlePrediction { } hestimatorsRecoEvGenVsReco[i]->Fill(nMult[i], nMultReco[i]); hestimatorsRecoEvGenVsReco_BCMC[i]->Fill(nMult[i], nMultRecoMCBC[i]); - hestimatorsRecoEvGenVsRecoITS[i]->Fill(nMult[i], nMultReco[Estimators::ITS]); - hestimatorsRecoEvRecoVsITS[i]->Fill(nMultReco[i], nMult[Estimators::ITS]); - hestimatorsRecoEvRecoVsRecoITS[i]->Fill(nMultReco[i], nMultReco[Estimators::ITS]); - hestimatorsRecoEvRecoVsRecoITS_BCMC[i]->Fill(nMultRecoMCBC[i], nMultReco[Estimators::ITS]); + 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]); diff --git a/PWGLF/Tasks/QC/mcSignalLoss.cxx b/PWGLF/Tasks/QC/mcSignalLoss.cxx index aefb6c98c1b..b88ba77ef15 100644 --- a/PWGLF/Tasks/QC/mcSignalLoss.cxx +++ b/PWGLF/Tasks/QC/mcSignalLoss.cxx @@ -24,25 +24,26 @@ // // Build hypertriton candidates from V0s and tracks -#include +#include "PWGLF/Utils/inelGt.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/PID/PIDTOF.h" +#include "Common/Core/PID/TPCPIDResponse.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 "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.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" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/QC/mcinelgt0.cxx b/PWGLF/Tasks/QC/mcinelgt0.cxx index cac4eff5bf7..40acd66a67f 100644 --- a/PWGLF/Tasks/QC/mcinelgt0.cxx +++ b/PWGLF/Tasks/QC/mcinelgt0.cxx @@ -48,7 +48,7 @@ struct mcInelGt0 { if (!track.isPVContributor()) { continue; } - if (abs(track.eta()) > 1) { + if (std::abs(track.eta()) > 1) { LOG(info) << "Track with eta > 1: " << track.eta() << (track.hasTPC() ? "hasTPC" diff --git a/PWGLF/Tasks/QC/resonanceqa.cxx b/PWGLF/Tasks/QC/resonanceqa.cxx index 21c17a6e31b..271e38305df 100644 --- a/PWGLF/Tasks/QC/resonanceqa.cxx +++ b/PWGLF/Tasks/QC/resonanceqa.cxx @@ -16,38 +16,39 @@ // (5) particle = 2 --> lambdastar // (6) 4 process function (a) Data same event (b) Data mixed event (c) MC generated (d) MC reconstructed -#include +#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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#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 "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" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/PWGLF/Tasks/QC/straRecoStudy.cxx b/PWGLF/Tasks/QC/straRecoStudy.cxx index 1f7851cdbef..290fd2ecebd 100644 --- a/PWGLF/Tasks/QC/straRecoStudy.cxx +++ b/PWGLF/Tasks/QC/straRecoStudy.cxx @@ -20,38 +20,40 @@ // Please write to: // david.dobrigkeit.chinellato@cern.ch // -#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 "PWGLF/DataModel/LFStrangenessTables.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/McCollisionExtra.h" +#include "Common/DataModel/PIDResponseTPC.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 "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include #include #include -#include #include -#include #include -#include -#include +#include + #include +#include #include -#include "Framework/ASoAHelpers.h" using namespace o2; using namespace o2::framework; 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/strangenessQCPP.cxx b/PWGLF/Tasks/QC/strangenessQCPP.cxx index 6dab146b363..c16bd0c1823 100644 --- a/PWGLF/Tasks/QC/strangenessQCPP.cxx +++ b/PWGLF/Tasks/QC/strangenessQCPP.cxx @@ -14,13 +14,14 @@ /// In case of questions please write to: /// \author Roman Nepeivoda (roman.nepeivoda@cern.ch) -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" +#include "PWGLF/DataModel/QC/strangenessTablesQC.h" + #include "Common/DataModel/EventSelection.h" -#include "Framework/O2DatabasePDGPlugin.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGLF/DataModel/QC/strangenessTablesQC.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; @@ -454,4 +455,4 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc, TaskName{"lf-strangenessqcpp"})}; -} \ No newline at end of file +} diff --git a/PWGLF/Tasks/QC/strangenessTrackingQC.cxx b/PWGLF/Tasks/QC/strangenessTrackingQC.cxx new file mode 100644 index 00000000000..7e133e50805 --- /dev/null +++ b/PWGLF/Tasks/QC/strangenessTrackingQC.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 "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +// #include "PWGHF/Core/PDG.h" +#include "PWGLF/DataModel/LFNonPromptCascadeTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.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/strangepidqa.cxx b/PWGLF/Tasks/QC/strangepidqa.cxx index c2bd9d89774..5b66a4972bf 100644 --- a/PWGLF/Tasks/QC/strangepidqa.cxx +++ b/PWGLF/Tasks/QC/strangepidqa.cxx @@ -12,32 +12,35 @@ // This task is designed to do QA to the TOF PID applied to strangeness // in the regular framework -#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/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include #include #include -#include #include -#include #include -#include -#include +#include + #include +#include #include -#include "Framework/ASoAHelpers.h" using namespace o2; using namespace o2::framework; @@ -51,20 +54,16 @@ struct strangepidqa { ConfigurableAxis vertexZ{"vertexZ", {30, -15.0f, 15.0f}, ""}; // base properties - 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 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}, "p_{T} (GeV/c)"}; ConfigurableAxis axisRadius{"axisRadius", {200, 0.0f, 100.0f}, "V0 radius (cm)"}; - AxisSpec centAxis = {100, 0.0f, 100.0f, "mult percentile"}; - AxisSpec massAxisXi = {200, 1.222f, 1.422f, "Inv. Mass (GeV/c^{2})"}; - AxisSpec massAxisOmega = {200, 1.572f, 1.772f, "Inv. Mass (GeV/c^{2})"}; + ConfigurableAxis centAxis{"centAxis", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 50.0f, 70.0f, 100.0f}, "FT0C centrality"}; // Invariant Mass + ConfigurableAxis axisK0ShortMass{"axisK0ShortMass", {200, 0.497f - 0.050f, 0.497f + 0.050f}, "M_{K0s} (GeV/c^{2})"}; ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.08f, 1.16f}, "M_{#Lambda} (GeV/c^{2})"}; - - // time axes - ConfigurableAxis axisDeltaTime{"axisDeltaTime", {200, -1000.0f, +1000.0f}, "#Delta time (ps)"}; - ConfigurableAxis axisTime{"axisTime", {200, 0.0f, +20000.0f}, "T (ps)"}; - ConfigurableAxis axisBeta{"axisBeta", {1200, 0.0f, +1.2f}, "#Beta"}; + AxisSpec massAxisXi = {200, 1.222f, 1.422f, "Inv. Mass (GeV/c^{2})"}; + AxisSpec massAxisOmega = {200, 1.572f, 1.772f, "Inv. Mass (GeV/c^{2})"}; // Length axis ConfigurableAxis axisLength{"axisLength", {600, 0.0f, +600.0f}, "track Length (cm)"}; @@ -72,24 +71,8 @@ struct strangepidqa { // TOF cut axis ConfigurableAxis axisTOFCut{"axisTOFCut", {100, 0.0f, +10000.0f}, "TOF compat. cut (ps)"}; - // TOF selection matters - Configurable requireTOFsignalPion{"requireTOFsignalPion", true, "require that pion prongs have TOF"}; - Configurable requireTOFsignalProton{"requireTOFsignalProton", true, "require that proton prongs have TOF"}; - Configurable requireTOFEventTimePion{"requireTOFEventTimePion", true, "require that pion prongs have TOF event time"}; - Configurable requireTOFEventTimeProton{"requireTOFEventTimeProton", true, "require that proton prongs have TOF event time"}; - - Configurable maxDeltaTimeProton{"maxDeltaTimeProton", 1e+9, "check maximum allowed time"}; - Configurable maxDeltaTimePion{"maxDeltaTimePion", 1e+9, "check maximum allowed time"}; - Configurable maxDeltaTimeDecay{"maxDeltaTimeDecay", 1e+9, "check maximum allowed delta-time-decay"}; - - Configurable minCentrality{"minCentrality", 60, "max value of centrality allowed"}; - Configurable maxCentrality{"maxCentrality", 100, "max value of centrality allowed"}; - - Configurable minV0Radius{"minV0Radius", 1.5, "min radius"}; - Configurable minCosPA{"minCosPA", .98, "min cosPA"}; - - Configurable minPtV0{"minPtV0", 1.0, "min pT for integrated mass histograms"}; - Configurable maxPtV0{"maxPtV0", 3.0, "max pT for integrated mass histograms"}; + // nsigma axis + ConfigurableAxis axisNSigma{"axisNSigma", {60, -3.0f, +3.0f}, "NSigma"}; //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* // Selection criteria for cascade analysis @@ -110,13 +93,11 @@ struct strangepidqa { Configurable tpcNsigmaBachelor{"tpcNsigmaBachelor", 4, "TPC NSigma bachelor (>10 is no cut)"}; Configurable tpcNsigmaProton{"tpcNsigmaProton", 4, "TPC NSigma proton <- lambda (>10 is no cut)"}; Configurable tpcNsigmaPion{"tpcNsigmaPion", 4, "TPC NSigma pion <- lambda (>10 is no cut)"}; - - Configurable tofNsigmaXiLaPr{"tpcNsigmaXiLaPr", 1e+5, "TOF NSigma proton <- lambda <- Xi (>10 is no cut)"}; - Configurable tofNsigmaXiLaPi{"tpcNsigmaXiLaPi", 1e+5, "TOF NSigma pion <- lambda <- Xi (>10 is no cut)"}; - Configurable tofNsigmaXiPi{"tpcNsigmaXiPi", 1e+5, "TOF NSigma pion <- Xi (>10 is no cut)"}; - Configurable tofNsigmaOmLaPr{"tpcNsigmaOmLaPr", 1e+5, "TOF NSigma proton <- lambda <- Omega (>10 is no cut)"}; - Configurable tofNsigmaOmLaPi{"tpcNsigmaOmLaPi", 1e+5, "TOF NSigma pion <- lambda <- Omega (>10 is no cut)"}; - Configurable tofNsigmaOmKa{"tpcNsigmaOmKa", 1e+5, "TOF NSigma Kaon <- Omega (>10 is no cut)"}; + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + // Direct test configurables + Configurable massWindowForNSigmaPlots{"massWindowForNSigmaPlots", 0.005f, "mass window for Nsigma comparison plots"}; + Configurable tofNsigmaCompatibility{"tofNsigmaCompatibility", 4, "compatibility check for V0s"}; + Configurable tofNsigmaCompatibilityCascades{"tofNsigmaCompatibilityCascades", 4, "compatibility check for cascades"}; //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* void init(InitContext const&) @@ -124,262 +105,256 @@ struct strangepidqa { // Event counter histos.add("hEventCentrality", "hEventCentrality", kTH1F, {{100, 0.0f, 100.0f}}); - // Presence of negative and positive signals and event time - auto hPositiveStatus = histos.add("hPositiveStatus", "hPositiveStatus", kTH1F, {{4, -0.5f, 3.5f}}); - auto hNegativeStatus = histos.add("hNegativeStatus", "hNegativeStatus", kTH1F, {{4, -0.5f, 3.5f}}); - auto hPositiveStatusReachedTOF = histos.add("hPositiveStatusReachedTOF", "hPositiveStatusReachedTOF", kTH1F, {{4, -0.5f, 3.5f}}); - auto hNegativeStatusReachedTOF = histos.add("hNegativeStatusReachedTOF", "hNegativeStatusReachedTOF", kTH1F, {{4, -0.5f, 3.5f}}); - hPositiveStatus->GetXaxis()->SetBinLabel(1, "All positive"); - hPositiveStatus->GetXaxis()->SetBinLabel(2, "Has only TOF sig"); - hPositiveStatus->GetXaxis()->SetBinLabel(3, "Has only TOF ev time"); - hPositiveStatus->GetXaxis()->SetBinLabel(4, "Has full time info"); - hNegativeStatus->GetXaxis()->SetBinLabel(1, "All negative"); - hNegativeStatus->GetXaxis()->SetBinLabel(2, "Has only TOF sig"); - hNegativeStatus->GetXaxis()->SetBinLabel(3, "Has only TOF ev time"); - hNegativeStatus->GetXaxis()->SetBinLabel(4, "Has full time info"); - - hPositiveStatusReachedTOF->GetXaxis()->SetBinLabel(1, "All positive"); - hPositiveStatusReachedTOF->GetXaxis()->SetBinLabel(2, "Has only TOF sig"); - hPositiveStatusReachedTOF->GetXaxis()->SetBinLabel(3, "Has only TOF ev time"); - hPositiveStatusReachedTOF->GetXaxis()->SetBinLabel(4, "Has full time info"); - hNegativeStatusReachedTOF->GetXaxis()->SetBinLabel(1, "All negative"); - hNegativeStatusReachedTOF->GetXaxis()->SetBinLabel(2, "Has only TOF sig"); - hNegativeStatusReachedTOF->GetXaxis()->SetBinLabel(3, "Has only TOF ev time"); - hNegativeStatusReachedTOF->GetXaxis()->SetBinLabel(4, "Has full time info"); - - // V0 Radius - histos.add("hLambdaMass", "hLambdaMass", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("hAssocLambdaMass", "hAssocLambdaMass", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("hAssocLambdaMassGoodTime", "hAssocLambdaMassGoodTime", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("hAssocLambdaMassBadTime", "hAssocLambdaMassBadTime", {HistType::kTH1F, {axisLambdaMass}}); - - // V0 Radius - histos.add("h2dLambdaRadiusVsPt", "hLambdaRadiusVsPt", {HistType::kTH2F, {axisPt, axisRadius}}); - - // Invariant Mass - histos.add("h2dLambdaMassVsPt", "hLambdaMassVsPt", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - - // Invariant Mass - histos.add("h2dLambdaMassVsTOFCut", "h2dLambdaMassVsTOFCut", {HistType::kTH2F, {axisLambdaMass, axisTOFCut}}); - histos.add("h2dLambdaMassVsTOFCutWithSignals", "h2dLambdaMassVsTOFCutWithSignals", {HistType::kTH2F, {axisLambdaMass, axisTOFCut}}); - histos.add("h2dLambdaMassVsTOFCutMeson", "h2dLambdaMassVsTOFCutMeson", {HistType::kTH2F, {axisLambdaMass, axisTOFCut}}); - histos.add("h2dLambdaMassVsTOFCutMesonWithSignals", "h2dLambdaMassVsTOFCutMesonWithSignals", {HistType::kTH2F, {axisLambdaMass, axisTOFCut}}); - - // Invariant Mass with TOF selections - histos.add("hLambdaMass_ProtonTOF", "hLambdaMass_ProtonTOF", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("hLambdaMass_PionTOF", "hLambdaMass_PionTOF", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("hLambdaMass_AllTOF", "hLambdaMass_AllTOF", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("hLambdaMass_DeltaDecayTime", "hLambdaMass_DeltaDecayTime", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("h2dLambdaMassVsPt_ProtonTOF", "hLambdaMassVsPtProtonTOF", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - histos.add("h2dLambdaMassVsPt_PionTOF", "hLambdaMassVsPtPionTOF", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - histos.add("h2dLambdaMassVsPt_AllTOF", "hLambdaMassVsPtAllTOF", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - histos.add("h2dLambdaMassVsPt_DeltaDecayTime", "hLambdaMassVsPtDeltaDecayTime", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - - // Invariant Mass with TOF selections - histos.add("hLambdaMass_InvertProtonTOF", "hLambdaMass_InvertProtonTOF", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("hLambdaMass_InvertPionTOF", "hLambdaMass_InvertPionTOF", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("hLambdaMass_InvertAllTOF", "hLambdaMass_InvertAllTOF", {HistType::kTH1F, {axisLambdaMass}}); - histos.add("h2dLambdaMassVsPt_InvertProtonTOF", "hLambdaMassVsPtInvertProtonTOF", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - histos.add("h2dLambdaMassVsPt_InvertPionTOF", "hLambdaMassVsPtInvertPionTOF", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - histos.add("h2dLambdaMassVsPt_InvertAllTOF", "hLambdaMassVsPtInvertAllTOF", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - - // radius vs prong length - histos.add("h2dProtonLengthVsRadius", "h2dProtonLengthVsRadius", {HistType::kTH2F, {axisRadius, axisLength}}); - histos.add("h2dPionLengthVsRadius", "h2dPionLengthVsRadius", {HistType::kTH2F, {axisRadius, axisLength}}); - - // recalculated vs topv lengths - histos.add("h2dProtonLengthVsLengthToPV", "h2dProtonLengthVsRadiusToPV", {HistType::kTH2F, {axisRadius, axisRadius}}); - histos.add("h2dPionLengthVsLengthToPV", "h2dPionLengthVsLengthToPV", {HistType::kTH2F, {axisRadius, axisRadius}}); - - // TOF PID testing for prongs - histos.add("h2dProtonDeltaTimeVsPt", "h2dProtonDeltaTimeVsPt", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - histos.add("h2dProtonDeltaTimeVsRadius", "h2dProtonDeltaTimeVsRadius", {HistType::kTH2F, {axisRadius, axisDeltaTime}}); - histos.add("h2dPionDeltaTimeVsPt", "h2dPionDeltaTimeVsPt", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - histos.add("h2dPionDeltaTimeVsRadius", "h2dPionDeltaTimeVsRadius", {HistType::kTH2F, {axisRadius, axisDeltaTime}}); - - // TOF PID testing for prongs - histos.add("h2dProtonDeltaTimeVsPt_MassSelected", "h2dProtonDeltaTimeVsPt_MassSelected", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - histos.add("h2dProtonDeltaTimeVsRadius_MassSelected", "h2dProtonDeltaTimeVsRadius_MassSelected", {HistType::kTH2F, {axisRadius, axisDeltaTime}}); - histos.add("h2dPionDeltaTimeVsPt_MassSelected", "h2dPionDeltaTimeVsPt_MassSelected", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - histos.add("h2dPionDeltaTimeVsRadius_MassSelected", "h2dPionDeltaTimeVsRadius_MassSelected", {HistType::kTH2F, {axisRadius, axisDeltaTime}}); - - // delta lambda decay time - histos.add("h2dLambdaDeltaDecayTime", "h2dLambdaDeltaDecayTime", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - histos.add("h2dLambdaDeltaDecayTime_MassSelected", "h2dLambdaDeltaDecayTime_MassSelected", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - - // beta plots - histos.add("h2dLambdaBeta", "h2dLambdaBeta", {HistType::kTH2F, {axisPt, axisBeta}}); - histos.add("h2dLambdaBeta_MassSelected", "h2dLambdaBeta_MassSelected", {HistType::kTH2F, {axisPt, axisBeta}}); - - // length vs time for prongs / debug - histos.add("h2dTimeVsLengthProtonProng", "h2dTimeVsLengthProtonProng", {HistType::kTH2F, {axisLength, axisTime}}); - histos.add("h2dTimeVsLengthPionProng", "h2dTimeVsLengthPionProng", {HistType::kTH2F, {axisLength, axisTime}}); - - // --- ASSOCIATED --- - // V0 Radius - if (doprocessSim) { - histos.add("h2dAssocLambdaRadiusVsPt", "hLambdaRadiusVsPt", {HistType::kTH2F, {axisPt, axisRadius}}); - - // Invariant Mass - histos.add("h2dAssocLambdaMassVsPt", "hLambdaMassVsPt", {HistType::kTH2F, {axisPt, axisLambdaMass}}); - - // radius vs prong length - histos.add("h2dAssocProtonLengthVsRadius", "h2dAssocProtonLengthVsRadius", {HistType::kTH2F, {axisRadius, axisLength}}); - histos.add("h2dAssocPionLengthVsRadius", "h2dAssocPionLengthVsRadius", {HistType::kTH2F, {axisRadius, axisLength}}); - - // recalculated vs topv lengths - histos.add("h2dAssocProtonLengthVsLengthToPV", "h2dAssocProtonLengthVsRadiusToPV", {HistType::kTH2F, {axisRadius, axisRadius}}); - histos.add("h2dAssocPionLengthVsLengthToPV", "h2dAssocPionLengthVsLengthToPV", {HistType::kTH2F, {axisRadius, axisRadius}}); - - // TOF PID testing for prongs - histos.add("h2dAssocProtonDeltaTimeVsPt", "h2dAssocProtonDeltaTimeVsPt", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - histos.add("h2dAssocProtonDeltaTimeVsRadius", "h2dAssocProtonDeltaTimeVsRadius", {HistType::kTH2F, {axisRadius, axisDeltaTime}}); - histos.add("h2dAssocPionDeltaTimeVsPt", "h2dAssocPionDeltaTimeVsPt", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - histos.add("h2dAssocPionDeltaTimeVsRadius", "h2dAssocPionDeltaTimeVsRadius", {HistType::kTH2F, {axisRadius, axisDeltaTime}}); - - // delta lambda decay time - histos.add("h2dAssocLambdaDeltaDecayTime", "h2dAssocLambdaDeltaDecayTime", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - histos.add("h2dAssocLambdaDeltaDecayTime_MassSelected", "h2dAssocLambdaDeltaDecayTime_MassSelected", {HistType::kTH2F, {axisPt, axisDeltaTime}}); - } + histos.add("h1dMassK0Short", "h1dMassK0Short", {HistType::kTH1F, {axisK0ShortMass}}); + histos.add("h1dMassLambda", "h1dMassLambda", {HistType::kTH1F, {axisLambdaMass}}); + histos.add("h1dMassAntiLambda", "h1dMassAntiLambda", {HistType::kTH1F, {axisLambdaMass}}); + histos.add("h1dMassCompatibleK0Short", "h1dMassCompatibleK0Short", {HistType::kTH1F, {axisK0ShortMass}}); + histos.add("h1dMassCompatibleLambda", "h1dMassCompatibleLambda", {HistType::kTH1F, {axisLambdaMass}}); + histos.add("h1dMassCompatibleAntiLambda", "h1dMassCompatibleAntiLambda", {HistType::kTH1F, {axisLambdaMass}}); + + histos.add("h3dMassK0Short", "h3dMassK0Short", {HistType::kTH3F, {centAxis, axisPt, axisK0ShortMass}}); + histos.add("h3dMassLambda", "h3dMassLambda", {HistType::kTH3F, {centAxis, axisPt, axisLambdaMass}}); + histos.add("h3dMassAntiLambda", "h3dMassAntiLambda", {HistType::kTH3F, {centAxis, axisPt, axisLambdaMass}}); + histos.add("h3dMassCompatibleK0Short", "h3dMassCompatibleK0Short", {HistType::kTH3F, {centAxis, axisPt, axisK0ShortMass}}); + histos.add("h3dMassCompatibleLambda", "h3dMassCompatibleLambda", {HistType::kTH3F, {centAxis, axisPt, axisLambdaMass}}); + histos.add("h3dMassCompatibleAntiLambda", "h3dMassCompatibleAntiLambda", {HistType::kTH3F, {centAxis, axisPt, axisLambdaMass}}); + + // cross-check if compatibility requested with primary TOF instead (requires non-derived) + histos.add("h3dPrimaryTOFMassCompatibleK0Short", "h3dPrimaryTOFMassCompatibleK0Short", {HistType::kTH3F, {centAxis, axisPt, axisK0ShortMass}}); + histos.add("h3dPrimaryTOFMassCompatibleLambda", "h3dPrimaryTOFMassCompatibleLambda", {HistType::kTH3F, {centAxis, axisPt, axisLambdaMass}}); + histos.add("h3dPrimaryTOFMassCompatibleAntiLambda", "h3dPrimaryTOFMassCompatibleAntiLambda", {HistType::kTH3F, {centAxis, axisPt, axisLambdaMass}}); + + // plot Nsigma: primary vs secondary TOF vs pT (use narrow window around mass) + histos.add("h3dNSigmasLaPr", "h3dNSigmasLaPr", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); + histos.add("h3dNSigmasLaPi", "h3dNSigmasLaPi", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); + histos.add("h3dNSigmasK0Pi", "h3dNSigmasK0Pi", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); + + if (doprocessCascades || doprocessCascadesNonDerived) { + histos.add("h1dMassXiMinus", "h1dMassXiMinus", {HistType::kTH1F, {massAxisXi}}); + histos.add("h1dMassXiPlus", "h1dMassXiPlus", {HistType::kTH1F, {massAxisXi}}); + histos.add("h1dMassOmegaMinus", "h1dMassOmegaMinus", {HistType::kTH1F, {massAxisOmega}}); + histos.add("h1dMassOmegaPlus", "h1dMassOmegaPlus", {HistType::kTH1F, {massAxisOmega}}); + histos.add("h1dMassCompatibleXiMinus", "h1dMassCompatibleXiMinus", {HistType::kTH1F, {massAxisXi}}); + histos.add("h1dMassCompatibleXiPlus", "h1dMassCompatibleXiPlus", {HistType::kTH1F, {massAxisXi}}); + histos.add("h1dMassCompatibleOmegaMinus", "h1dMassCompatibleOmegaMinus", {HistType::kTH1F, {massAxisOmega}}); + histos.add("h1dMassCompatibleOmegaPlus", "h1dMassCompatibleOmegaPlus", {HistType::kTH1F, {massAxisOmega}}); - if (doprocessCascades) { histos.add("h3dMassXiMinus", "h3dMassXiMinus", {HistType::kTH3F, {centAxis, axisPt, massAxisXi}}); histos.add("h3dMassXiPlus", "h3dMassXiPlus", {HistType::kTH3F, {centAxis, axisPt, massAxisXi}}); histos.add("h3dMassOmegaMinus", "h3dMassOmegaMinus", {HistType::kTH3F, {centAxis, axisPt, massAxisOmega}}); histos.add("h3dMassOmegaPlus", "h3dMassOmegaPlus", {HistType::kTH3F, {centAxis, axisPt, massAxisOmega}}); + histos.add("h3dMassCompatibleXiMinus", "h3dMassCompatibleXiMinus", {HistType::kTH3F, {centAxis, axisPt, massAxisXi}}); + histos.add("h3dMassCompatibleXiPlus", "h3dMassCompatibleXiPlus", {HistType::kTH3F, {centAxis, axisPt, massAxisXi}}); + histos.add("h3dMassCompatibleOmegaMinus", "h3dMassCompatibleOmegaMinus", {HistType::kTH3F, {centAxis, axisPt, massAxisOmega}}); + histos.add("h3dMassCompatibleOmegaPlus", "h3dMassCompatibleOmegaPlus", {HistType::kTH3F, {centAxis, axisPt, massAxisOmega}}); + + // cross-check if compatibility requested with primary TOF instead (requires non-derived) + histos.add("h3dPrimaryTOFMassCompatibleXiMinus", "h3dPrimaryTOFMassCompatibleXiMinus", {HistType::kTH3F, {centAxis, axisPt, massAxisXi}}); + histos.add("h3dPrimaryTOFMassCompatibleXiPlus", "h3dPrimaryTOFMassCompatibleXiPlus", {HistType::kTH3F, {centAxis, axisPt, massAxisXi}}); + histos.add("h3dPrimaryTOFMassCompatibleOmegaMinus", "h3dPrimaryTOFMassCompatibleOmegaMinus", {HistType::kTH3F, {centAxis, axisPt, massAxisOmega}}); + histos.add("h3dPrimaryTOFMassCompatibleOmegaPlus", "h3dPrimaryTOFMassCompatibleOmegaPlus", {HistType::kTH3F, {centAxis, axisPt, massAxisOmega}}); + + // plot Nsigma: primary vs secondary TOF vs pT (use narrow window around mass) + histos.add("h3dNSigmasXiLaPr", "h3dNSigmasXiLaPr", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); + histos.add("h3dNSigmasXiLaPi", "h3dNSigmasXiLaPi", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); + histos.add("h3dNSigmasXiPi", "h3dNSigmasXiPi", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); + + histos.add("h3dNSigmasOmLaPr", "h3dNSigmasOmLaPr", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); + histos.add("h3dNSigmasOmLaPi", "h3dNSigmasOmLaPi", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); + histos.add("h3dNSigmasOmKa", "h3dNSigmasOmKa", {HistType::kTH3F, {axisNSigma, axisNSigma, axisPt}}); } } - void processReal(soa::Join::iterator const& coll, soa::Join const& v0s) + void processReal(soa::Join::iterator const& coll, soa::Join const& v0s, soa::Join const&) { - histos.fill(HIST("hEventVertexZ"), coll.posZ()); - - if (coll.centFT0C() > maxCentrality || coll.centFT0C() < minCentrality) - return; - - for (auto& lambda : v0s) { // selecting photons from Sigma0 + for (auto& lambda : v0s) { if (TMath::Abs(lambda.eta()) > 0.5) continue; - histos.fill(HIST("h2dLambdaMassVsTOFCut"), lambda.mLambda(), TMath::Abs(lambda.posTOFDeltaTLaPr())); - histos.fill(HIST("h2dLambdaMassVsTOFCutMeson"), lambda.mLambda(), TMath::Abs(lambda.negTOFDeltaTLaPi())); + auto negExtra = lambda.negTrackExtra_as>(); + auto posExtra = lambda.posTrackExtra_as>(); - if (lambda.v0radius() < minV0Radius) - continue; + if (TMath::Abs(posExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(negExtra.tpcNSigmaPi()) < tpcNsigmaPion) { + // lambda case + histos.fill(HIST("h3dMassLambda"), coll.centFT0C(), lambda.pt(), lambda.mLambda()); + histos.fill(HIST("h1dMassLambda"), lambda.mLambda()); + if (lambda.tofLambdaCompatibility(tofNsigmaCompatibility.value)) { + histos.fill(HIST("h3dMassCompatibleLambda"), coll.centFT0C(), lambda.pt(), lambda.mLambda()); + histos.fill(HIST("h1dMassCompatibleLambda"), lambda.mLambda()); + } + } - histos.fill(HIST("h2dLambdaDeltaDecayTime"), lambda.pt(), lambda.deltaDecayTimeLambda()); - if (TMath::Abs(lambda.mLambda() - 1.115683) < 0.01 && lambda.v0cosPA() > minCosPA) { - histos.fill(HIST("h2dLambdaDeltaDecayTime_MassSelected"), lambda.pt(), lambda.deltaDecayTimeLambda()); + if (TMath::Abs(posExtra.tpcNSigmaPi()) < tpcNsigmaProton && TMath::Abs(negExtra.tpcNSigmaPr()) < tpcNsigmaPion) { + // lambda case + histos.fill(HIST("h3dMassAntiLambda"), coll.centFT0C(), lambda.pt(), lambda.mAntiLambda()); + histos.fill(HIST("h1dMassAntiLambda"), lambda.mAntiLambda()); + if (lambda.tofAntiLambdaCompatibility(tofNsigmaCompatibility.value)) { + histos.fill(HIST("h3dMassCompatibleAntiLambda"), coll.centFT0C(), lambda.pt(), lambda.mAntiLambda()); + histos.fill(HIST("h1dMassCompatibleAntiLambda"), lambda.mAntiLambda()); + } } - if (lambda.pt() > minPtV0 && lambda.pt() < maxPtV0) - histos.fill(HIST("hLambdaMass"), lambda.mLambda()); + if (TMath::Abs(posExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(negExtra.tpcNSigmaPr()) < tpcNsigmaPion) { + // lambda case + histos.fill(HIST("h3dMassK0Short"), coll.centFT0C(), lambda.pt(), lambda.mK0Short()); + histos.fill(HIST("h1dMassK0Short"), lambda.mK0Short()); + if (lambda.tofK0ShortCompatibility(tofNsigmaCompatibility.value)) { + histos.fill(HIST("h3dMassCompatibleK0Short"), coll.centFT0C(), lambda.pt(), lambda.mK0Short()); + histos.fill(HIST("h1dMassCompatibleK0Short"), lambda.mK0Short()); + } + } + } + } - histos.fill(HIST("h2dLambdaRadiusVsPt"), lambda.pt(), lambda.v0radius()); - histos.fill(HIST("h2dLambdaMassVsPt"), lambda.pt(), lambda.mLambda()); + // ____________________________________________________________________________ + // QA TOF NSigma quantities + Filter preFilter = + nabs(aod::cascdata::dcapostopv) > v0setting_dcapostopv&& nabs(aod::cascdata::dcanegtopv) > v0setting_dcanegtopv&& nabs(aod::cascdata::dcabachtopv) > cascadesetting_dcabachtopv&& aod::cascdata::dcaV0daughters < v0setting_dcav0dau&& aod::cascdata::dcacascdaughters < cascadesetting_dcacascdau; - histos.fill(HIST("h2dProtonDeltaTimeVsPt"), lambda.pt(), lambda.posTOFDeltaTLaPr()); - histos.fill(HIST("h2dProtonDeltaTimeVsRadius"), lambda.v0radius(), lambda.posTOFDeltaTLaPr()); - histos.fill(HIST("h2dPionDeltaTimeVsPt"), lambda.pt(), lambda.negTOFDeltaTLaPi()); - histos.fill(HIST("h2dPionDeltaTimeVsRadius"), lambda.v0radius(), lambda.negTOFDeltaTLaPi()); - histos.fill(HIST("h2dLambdaBeta"), lambda.p(), lambda.tofBetaLambda()); + void processCascades(soa::Join const& collisions, soa::Filtered> const& Cascades, soa::Join const&) + { + for (auto& casc : Cascades) { + auto col = collisions.rawIteratorAt(casc.straCollisionId()); - if (TMath::Abs(lambda.mLambda() - 1.115683) < 0.01 && lambda.v0cosPA() > minCosPA) { - histos.fill(HIST("h2dProtonDeltaTimeVsPt_MassSelected"), lambda.pt(), lambda.posTOFDeltaTLaPr()); - histos.fill(HIST("h2dProtonDeltaTimeVsRadius_MassSelected"), lambda.v0radius(), lambda.posTOFDeltaTLaPr()); - histos.fill(HIST("h2dPionDeltaTimeVsPt_MassSelected"), lambda.pt(), lambda.negTOFDeltaTLaPi()); - histos.fill(HIST("h2dPionDeltaTimeVsRadius_MassSelected"), lambda.v0radius(), lambda.negTOFDeltaTLaPi()); - histos.fill(HIST("h2dLambdaBeta_MassSelected"), lambda.p(), lambda.tofBetaLambda()); - } + // major selections here + if (casc.v0radius() > v0setting_radius && + casc.cascradius() > cascadesetting_cascradius && + casc.v0cosPA(col.posX(), col.posY(), col.posZ()) > v0setting_cospa && + casc.casccosPA(col.posX(), col.posY(), col.posZ()) > cascadesetting_cospa && + casc.dcav0topv(col.posX(), col.posY(), col.posZ()) > cascadesetting_mindcav0topv && + TMath::Abs(casc.mLambda() - 1.115683) < cascadesetting_v0masswindow) { - // Standard selection of time - if (TMath::Abs(lambda.deltaDecayTimeLambda()) < maxDeltaTimeDecay) { - histos.fill(HIST("h2dLambdaMassVsPt_DeltaDecayTime"), lambda.pt(), lambda.mLambda()); - if (lambda.pt() > minPtV0 && lambda.pt() < maxPtV0) - histos.fill(HIST("hLambdaMass_DeltaDecayTime"), lambda.mLambda()); - } + auto negExtra = casc.negTrackExtra_as>(); + auto posExtra = casc.posTrackExtra_as>(); + auto bachExtra = casc.bachTrackExtra_as>(); - if (TMath::Abs(lambda.posTOFDeltaTLaPr()) < maxDeltaTimeProton) { - histos.fill(HIST("h2dLambdaMassVsPt_ProtonTOF"), lambda.pt(), lambda.mLambda()); - if (lambda.pt() > minPtV0 && lambda.pt() < maxPtV0) - histos.fill(HIST("hLambdaMass_ProtonTOF"), lambda.mLambda()); - } - if (TMath::Abs(lambda.negTOFDeltaTLaPi()) < maxDeltaTimeProton) { - histos.fill(HIST("h2dLambdaMassVsPt_PionTOF"), lambda.pt(), lambda.mLambda()); - if (lambda.pt() > minPtV0 && lambda.pt() < maxPtV0) - histos.fill(HIST("hLambdaMass_PionTOF"), lambda.mLambda()); - if (TMath::Abs(lambda.posTOFDeltaTLaPr()) < maxDeltaTimeProton) { - histos.fill(HIST("h2dLambdaMassVsPt_AllTOF"), lambda.pt(), lambda.mLambda()); - if (lambda.pt() > minPtV0 && lambda.pt() < maxPtV0) - histos.fill(HIST("hLambdaMass_AllTOF"), lambda.mLambda()); - } - } - // Inversion of time selection for debug - // if(TMath::Abs(lambda.deltaDecayTimeLambda())>maxDeltaTimeDecay && TMath::Abs(lambda.deltaDecayTimeLambda()) < 5e+4){ - // histos.fill(HIST("h2dLambdaMassVsPt_DeltaDecayTime"), lambda.pt(), lambda.mLambda()); - // if(lambda.pt()>minPtV0 && lambda.pt() < maxPtV0) histos.fill(HIST("hLambdaMass_DeltaDecayTime"), lambda.mLambda()); - // } - - if (TMath::Abs(lambda.posTOFDeltaTLaPr()) > maxDeltaTimeProton && TMath::Abs(lambda.posTOFDeltaTLaPr()) < 5e+4) { - histos.fill(HIST("h2dLambdaMassVsPt_InvertProtonTOF"), lambda.pt(), lambda.mLambda()); - if (lambda.pt() > minPtV0 && lambda.pt() < maxPtV0) - histos.fill(HIST("hLambdaMass_InvertProtonTOF"), lambda.mLambda()); - } - if (TMath::Abs(lambda.negTOFDeltaTLaPi()) > maxDeltaTimeProton && TMath::Abs(lambda.negTOFDeltaTLaPi()) < 5e+4) { - histos.fill(HIST("h2dLambdaMassVsPt_InvertPionTOF"), lambda.pt(), lambda.mLambda()); - if (lambda.pt() > minPtV0 && lambda.pt() < maxPtV0) - histos.fill(HIST("hLambdaMass_InvertPionTOF"), lambda.mLambda()); - if (TMath::Abs(lambda.posTOFDeltaTLaPr()) > maxDeltaTimeProton && TMath::Abs(lambda.posTOFDeltaTLaPr()) < 5e+4) { - histos.fill(HIST("h2dLambdaMassVsPt_InvertAllTOF"), lambda.pt(), lambda.mLambda()); - if (lambda.pt() > minPtV0 && lambda.pt() < maxPtV0) - histos.fill(HIST("hLambdaMass_InvertAllTOF"), lambda.mLambda()); + if (negExtra.tpcCrossedRows() < tpcCrossedRows || posExtra.tpcCrossedRows() < tpcCrossedRows || bachExtra.tpcCrossedRows() < tpcCrossedRows) + continue; + + if (casc.sign() < 0) { + if (TMath::Abs(posExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(negExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(bachExtra.tpcNSigmaPi()) < tpcNsigmaBachelor) { + histos.fill(HIST("h3dMassXiMinus"), col.centFT0C(), casc.pt(), casc.mXi()); + histos.fill(HIST("h1dMassXiMinus"), casc.mXi()); + if (casc.tofXiCompatibility(tofNsigmaCompatibilityCascades.value)) { + histos.fill(HIST("h3dMassCompatibleXiMinus"), col.centFT0C(), casc.pt(), casc.mXi()); + histos.fill(HIST("h1dMassCompatibleXiMinus"), casc.mXi()); + } + } + if (TMath::Abs(posExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(negExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(bachExtra.tpcNSigmaKa()) < tpcNsigmaBachelor) { + histos.fill(HIST("h3dMassOmegaMinus"), col.centFT0C(), casc.pt(), casc.mOmega()); + histos.fill(HIST("h1dMassOmegaMinus"), casc.mOmega()); + if (casc.tofOmegaCompatibility(tofNsigmaCompatibilityCascades.value)) { + histos.fill(HIST("h3dMassCompatibleOmegaMinus"), col.centFT0C(), casc.pt(), casc.mOmega()); + histos.fill(HIST("h1dMassCompatibleOmegaMinus"), casc.mOmega()); + } + } + } else { + if (TMath::Abs(posExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(negExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(bachExtra.tpcNSigmaPi()) < tpcNsigmaBachelor) { + histos.fill(HIST("h3dMassXiPlus"), col.centFT0C(), casc.pt(), casc.mXi()); + histos.fill(HIST("h1dMassXiPlus"), casc.mXi()); + if (casc.tofXiCompatibility(tofNsigmaCompatibilityCascades.value)) { + histos.fill(HIST("h3dMassCompatibleXiPlus"), col.centFT0C(), casc.pt(), casc.mXi()); + histos.fill(HIST("h1dMassCompatibleXiPlus"), casc.mXi()); + } + } + + if (TMath::Abs(posExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(negExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(bachExtra.tpcNSigmaKa()) < tpcNsigmaBachelor) { + histos.fill(HIST("h3dMassOmegaPlus"), col.centFT0C(), casc.pt(), casc.mOmega()); + histos.fill(HIST("h1dMassOmegaPlus"), casc.mOmega()); + if (casc.tofOmegaCompatibility(tofNsigmaCompatibilityCascades.value)) { + histos.fill(HIST("h3dMassCompatibleOmegaPlus"), col.centFT0C(), casc.pt(), casc.mOmega()); + histos.fill(HIST("h1dMassCompatibleOmegaPlus"), casc.mOmega()); + } + } } } } } - void processSim(aod::StraCollision const&, soa::Join const& v0s) + void processRealNonDerived(soa::Join const& collisions, soa::Join const& v0s, soa::Join const&) { - for (auto& lambda : v0s) { // selecting photons from Sigma0 - if (lambda.pdgCode() != 3122) - continue; - if (!lambda.isPhysicalPrimary()) - continue; - if (lambda.pdgCodePositive() != 2212) - continue; - if (lambda.pdgCodeNegative() != -211) + for (auto const& col : collisions) { + histos.fill(HIST("hEventCentrality"), col.centFT0C()); + } + + for (auto& lambda : v0s) { + auto coll = collisions.rawIteratorAt(lambda.collisionId()); + + if (TMath::Abs(lambda.eta()) > 0.5) continue; - histos.fill(HIST("hAssocLambdaMass"), lambda.mLambda()); + auto negExtra = lambda.negTrack_as>(); + auto posExtra = lambda.posTrack_as>(); - histos.fill(HIST("h2dAssocLambdaRadiusVsPt"), lambda.pt(), lambda.v0radius()); - histos.fill(HIST("h2dAssocLambdaMassVsPt"), lambda.pt(), lambda.mLambda()); + bool primaryTOFcompatible_Lambda = + (!posExtra.hasTOF() || (std::fabs(posExtra.tofNSigmaPr()) < tofNsigmaCompatibilityCascades.value)) && + (!negExtra.hasTOF() || (std::fabs(negExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)); - histos.fill(HIST("h2dAssocProtonDeltaTimeVsPt"), lambda.pt(), lambda.posTOFDeltaTLaPr()); - histos.fill(HIST("h2dAssocProtonDeltaTimeVsRadius"), lambda.v0radius(), lambda.posTOFDeltaTLaPr()); - histos.fill(HIST("h2dAssocPionDeltaTimeVsPt"), lambda.pt(), lambda.negTOFDeltaTLaPi()); - histos.fill(HIST("h2dAssocPionDeltaTimeVsRadius"), lambda.v0radius(), lambda.negTOFDeltaTLaPi()); + bool primaryTOFcompatible_AntiLambda = + (!posExtra.hasTOF() || (std::fabs(posExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)) && + (!negExtra.hasTOF() || (std::fabs(negExtra.tofNSigmaPr()) < tofNsigmaCompatibilityCascades.value)); - // delta lambda decay time - histos.fill(HIST("h2dAssocLambdaDeltaDecayTime"), lambda.pt(), lambda.deltaDecayTimeLambda()); - } - } + bool primaryTOFcompatible_K0Short = + (!posExtra.hasTOF() || (std::fabs(posExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)) && + (!negExtra.hasTOF() || (std::fabs(negExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)); - // ____________________________________________________________________________ - // QA TOF NSigma quantities + if (TMath::Abs(posExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(negExtra.tpcNSigmaPi()) < tpcNsigmaPion) { + // lambda case + histos.fill(HIST("h3dMassLambda"), coll.centFT0C(), lambda.pt(), lambda.mLambda()); + histos.fill(HIST("h1dMassLambda"), lambda.mLambda()); + if (lambda.tofLambdaCompatibility(tofNsigmaCompatibility.value)) { + histos.fill(HIST("h3dMassCompatibleLambda"), coll.centFT0C(), lambda.pt(), lambda.mLambda()); + histos.fill(HIST("h1dMassCompatibleLambda"), lambda.mLambda()); + } + if (primaryTOFcompatible_Lambda) { + histos.fill(HIST("h3dPrimaryTOFMassCompatibleLambda"), coll.centFT0C(), lambda.pt(), lambda.mLambda()); + } + if (std::abs(lambda.mLambda() - o2::constants::physics::MassLambda) < massWindowForNSigmaPlots.value) { + histos.fill(HIST("h3dNSigmasLaPr"), lambda.tofNSigmaLaPr(), posExtra.tofNSigmaPr(), lambda.pt()); + histos.fill(HIST("h3dNSigmasLaPi"), lambda.tofNSigmaLaPi(), negExtra.tofNSigmaPi(), lambda.pt()); + } + } - Partition> negCasc = aod::cascdata::sign < 0; - Partition> posCasc = aod::cascdata::sign > 0; + if (TMath::Abs(posExtra.tpcNSigmaPi()) < tpcNsigmaProton && TMath::Abs(negExtra.tpcNSigmaPr()) < tpcNsigmaPion) { + // lambda case + histos.fill(HIST("h3dMassAntiLambda"), coll.centFT0C(), lambda.pt(), lambda.mAntiLambda()); + histos.fill(HIST("h1dMassAntiLambda"), lambda.mAntiLambda()); + if (lambda.tofAntiLambdaCompatibility(tofNsigmaCompatibility.value)) { + histos.fill(HIST("h3dMassCompatibleAntiLambda"), coll.centFT0C(), lambda.pt(), lambda.mAntiLambda()); + histos.fill(HIST("h1dMassCompatibleAntiLambda"), lambda.mAntiLambda()); + } + if (primaryTOFcompatible_AntiLambda) { + histos.fill(HIST("h3dPrimaryTOFMassCompatibleAntiLambda"), coll.centFT0C(), lambda.pt(), lambda.mAntiLambda()); + } + } - Filter preFilter = - nabs(aod::cascdata::dcapostopv) > v0setting_dcapostopv&& nabs(aod::cascdata::dcanegtopv) > v0setting_dcanegtopv&& nabs(aod::cascdata::dcabachtopv) > cascadesetting_dcabachtopv&& aod::cascdata::dcaV0daughters < v0setting_dcav0dau&& aod::cascdata::dcacascdaughters < cascadesetting_dcacascdau; + if (TMath::Abs(posExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(negExtra.tpcNSigmaPr()) < tpcNsigmaPion) { + // lambda case + histos.fill(HIST("h3dMassK0Short"), coll.centFT0C(), lambda.pt(), lambda.mK0Short()); + histos.fill(HIST("h1dMassK0Short"), lambda.mK0Short()); + if (lambda.tofK0ShortCompatibility(tofNsigmaCompatibility.value)) { + histos.fill(HIST("h3dMassCompatibleK0Short"), coll.centFT0C(), lambda.pt(), lambda.mK0Short()); + histos.fill(HIST("h1dMassCompatibleK0Short"), lambda.mK0Short()); + } + if (primaryTOFcompatible_K0Short) { + histos.fill(HIST("h3dPrimaryTOFMassCompatibleK0Short"), coll.centFT0C(), lambda.pt(), lambda.mK0Short()); + } + if (std::abs(lambda.mK0Short() - o2::constants::physics::MassK0Short) < massWindowForNSigmaPlots.value) { + histos.fill(HIST("h3dNSigmasK0Pi"), lambda.tofNSigmaLaPi(), posExtra.tofNSigmaPi(), lambda.pt()); + histos.fill(HIST("h3dNSigmasK0Pi"), lambda.tofNSigmaLaPi(), negExtra.tofNSigmaPi(), lambda.pt()); + } + } + } + } - void processCascades(soa::Join::iterator const& col, soa::Filtered> const& Cascades, soa::Join const&) + // to test original data (not derived) as well, compare with primary TOF Nsigmas + // don't do grouping, faster to simply stream through + void processCascadesNonDerived(soa::Join const& collisions, soa::Filtered> const& Cascades, soa::Join const&) { - histos.fill(HIST("hEventCentrality"), col.centFT0C()); - for (auto& casc : Cascades) { + auto col = collisions.rawIteratorAt(casc.collisionId()); + // major selections here if (casc.v0radius() > v0setting_radius && casc.cascradius() > cascadesetting_cascradius && @@ -388,51 +363,90 @@ struct strangepidqa { casc.dcav0topv(col.posX(), col.posY(), col.posZ()) > cascadesetting_mindcav0topv && TMath::Abs(casc.mLambda() - 1.115683) < cascadesetting_v0masswindow) { - auto negExtra = casc.negTrackExtra_as>(); - auto posExtra = casc.posTrackExtra_as>(); - auto bachExtra = casc.bachTrackExtra_as>(); + auto negExtra = casc.negTrack_as>(); + auto posExtra = casc.posTrack_as>(); + auto bachExtra = casc.bachelor_as>(); - if (negExtra.tpcCrossedRows() < tpcCrossedRows || posExtra.tpcCrossedRows() < tpcCrossedRows || bachExtra.tpcCrossedRows() < tpcCrossedRows) + if (negExtra.tpcNClsCrossedRows() < tpcCrossedRows || posExtra.tpcNClsCrossedRows() < tpcCrossedRows || bachExtra.tpcNClsCrossedRows() < tpcCrossedRows) { continue; + } + + bool primaryTOFcompatible_XiMinus = + (!posExtra.hasTOF() || (std::fabs(posExtra.tofNSigmaPr()) < tofNsigmaCompatibilityCascades.value)) && + (!negExtra.hasTOF() || (std::fabs(negExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)) && + (!bachExtra.hasTOF() || (std::fabs(bachExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)); + + bool primaryTOFcompatible_XiPlus = + (!posExtra.hasTOF() || (std::fabs(posExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)) && + (!negExtra.hasTOF() || (std::fabs(negExtra.tofNSigmaPr()) < tofNsigmaCompatibilityCascades.value)) && + (!bachExtra.hasTOF() || (std::fabs(bachExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)); + + bool primaryTOFcompatible_OmegaMinus = + (!posExtra.hasTOF() || (std::fabs(posExtra.tofNSigmaPr()) < tofNsigmaCompatibilityCascades.value)) && + (!negExtra.hasTOF() || (std::fabs(negExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)) && + (!bachExtra.hasTOF() || (std::fabs(bachExtra.tofNSigmaKa()) < tofNsigmaCompatibilityCascades.value)); + + bool primaryTOFcompatible_OmegaPlus = + (!posExtra.hasTOF() || (std::fabs(posExtra.tofNSigmaPi()) < tofNsigmaCompatibilityCascades.value)) && + (!negExtra.hasTOF() || (std::fabs(negExtra.tofNSigmaPr()) < tofNsigmaCompatibilityCascades.value)) && + (!bachExtra.hasTOF() || (std::fabs(bachExtra.tofNSigmaKa()) < tofNsigmaCompatibilityCascades.value)); if (casc.sign() < 0) { if (TMath::Abs(posExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(negExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(bachExtra.tpcNSigmaPi()) < tpcNsigmaBachelor) { - if (tofNsigmaXiLaPr < 100 && fabs(casc.tofNSigmaXiLaPr()) > tofNsigmaXiLaPr) - continue; - if (tofNsigmaXiLaPi < 100 && fabs(casc.tofNSigmaXiLaPi()) > tofNsigmaXiLaPi) - continue; - if (tofNsigmaXiPi < 100 && fabs(casc.tofNSigmaXiPi()) > tofNsigmaXiPi) - continue; histos.fill(HIST("h3dMassXiMinus"), col.centFT0C(), casc.pt(), casc.mXi()); + histos.fill(HIST("h1dMassXiMinus"), casc.mXi()); + if (casc.tofXiCompatibility(tofNsigmaCompatibilityCascades.value)) { + histos.fill(HIST("h3dMassCompatibleXiMinus"), col.centFT0C(), casc.pt(), casc.mXi()); + histos.fill(HIST("h1dMassCompatibleXiMinus"), casc.mXi()); + } + if (primaryTOFcompatible_XiMinus) { + histos.fill(HIST("h3dPrimaryTOFMassCompatibleXiMinus"), col.centFT0C(), casc.pt(), casc.mXi()); + } + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) < massWindowForNSigmaPlots.value) { + histos.fill(HIST("h3dNSigmasXiLaPr"), casc.tofNSigmaXiLaPr(), posExtra.tofNSigmaPr(), casc.pt()); + histos.fill(HIST("h3dNSigmasXiLaPi"), casc.tofNSigmaXiLaPi(), negExtra.tofNSigmaPi(), casc.pt()); + histos.fill(HIST("h3dNSigmasXiPi"), casc.tofNSigmaXiPi(), bachExtra.tofNSigmaPi(), casc.pt()); + } } if (TMath::Abs(posExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(negExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(bachExtra.tpcNSigmaKa()) < tpcNsigmaBachelor) { - if (tofNsigmaOmLaPr < 100 && fabs(casc.tofNSigmaOmLaPr()) > tofNsigmaOmLaPr) - continue; - if (tofNsigmaOmLaPi < 100 && fabs(casc.tofNSigmaOmLaPi()) > tofNsigmaOmLaPi) - continue; - if (tofNsigmaOmKa < 100 && fabs(casc.tofNSigmaOmKa()) > tofNsigmaOmKa) - continue; histos.fill(HIST("h3dMassOmegaMinus"), col.centFT0C(), casc.pt(), casc.mOmega()); + histos.fill(HIST("h1dMassOmegaMinus"), casc.mOmega()); + if (casc.tofOmegaCompatibility(tofNsigmaCompatibilityCascades.value)) { + histos.fill(HIST("h3dMassCompatibleOmegaMinus"), col.centFT0C(), casc.pt(), casc.mOmega()); + histos.fill(HIST("h1dMassCompatibleOmegaMinus"), casc.mOmega()); + } + if (primaryTOFcompatible_OmegaMinus) { + histos.fill(HIST("h3dPrimaryTOFMassCompatibleOmegaMinus"), col.centFT0C(), casc.pt(), casc.mOmega()); + } + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < massWindowForNSigmaPlots.value) { + histos.fill(HIST("h3dNSigmasOmLaPr"), casc.tofNSigmaOmLaPr(), posExtra.tofNSigmaPr(), casc.pt()); + histos.fill(HIST("h3dNSigmasOmLaPi"), casc.tofNSigmaOmLaPi(), negExtra.tofNSigmaPi(), casc.pt()); + histos.fill(HIST("h3dNSigmasOmKa"), casc.tofNSigmaOmKa(), bachExtra.tofNSigmaKa(), casc.pt()); + } } } else { if (TMath::Abs(posExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(negExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(bachExtra.tpcNSigmaPi()) < tpcNsigmaBachelor) { - if (tofNsigmaXiLaPr < 100 && fabs(casc.tofNSigmaXiLaPr()) > tofNsigmaXiLaPr) - continue; - if (tofNsigmaXiLaPi < 100 && fabs(casc.tofNSigmaXiLaPi()) > tofNsigmaXiLaPi) - continue; - if (tofNsigmaXiPi < 100 && fabs(casc.tofNSigmaXiPi()) > tofNsigmaXiPi) - continue; histos.fill(HIST("h3dMassXiPlus"), col.centFT0C(), casc.pt(), casc.mXi()); + histos.fill(HIST("h1dMassXiPlus"), casc.mXi()); + if (casc.tofXiCompatibility(tofNsigmaCompatibilityCascades.value)) { + histos.fill(HIST("h3dMassCompatibleXiPlus"), col.centFT0C(), casc.pt(), casc.mXi()); + histos.fill(HIST("h1dMassCompatibleXiPlus"), casc.mXi()); + } + if (primaryTOFcompatible_XiPlus) { + histos.fill(HIST("h3dPrimaryTOFMassCompatibleXiPlus"), col.centFT0C(), casc.pt(), casc.mXi()); + } } if (TMath::Abs(posExtra.tpcNSigmaPi()) < tpcNsigmaPion && TMath::Abs(negExtra.tpcNSigmaPr()) < tpcNsigmaProton && TMath::Abs(bachExtra.tpcNSigmaKa()) < tpcNsigmaBachelor) { - if (tofNsigmaOmLaPr < 100 && fabs(casc.tofNSigmaOmLaPr()) > tofNsigmaOmLaPr) - continue; - if (tofNsigmaOmLaPi < 100 && fabs(casc.tofNSigmaOmLaPi()) > tofNsigmaOmLaPi) - continue; - if (tofNsigmaOmKa < 100 && fabs(casc.tofNSigmaOmKa()) > tofNsigmaOmKa) - continue; histos.fill(HIST("h3dMassOmegaPlus"), col.centFT0C(), casc.pt(), casc.mOmega()); + histos.fill(HIST("h1dMassOmegaPlus"), casc.mOmega()); + if (casc.tofOmegaCompatibility(tofNsigmaCompatibilityCascades.value)) { + histos.fill(HIST("h3dMassCompatibleOmegaPlus"), col.centFT0C(), casc.pt(), casc.mOmega()); + histos.fill(HIST("h1dMassCompatibleOmegaPlus"), casc.mOmega()); + } + if (primaryTOFcompatible_OmegaPlus) { + histos.fill(HIST("h3dPrimaryTOFMassCompatibleOmegaPlus"), col.centFT0C(), casc.pt(), casc.mOmega()); + } } } } @@ -440,8 +454,11 @@ struct strangepidqa { } PROCESS_SWITCH(strangepidqa, processReal, "Produce real information", true); - PROCESS_SWITCH(strangepidqa, processSim, "Produce simulated information", true); PROCESS_SWITCH(strangepidqa, processCascades, "Process real cascades", true); + + // non-derived options + PROCESS_SWITCH(strangepidqa, processRealNonDerived, "Process real cascades from non-derived data", true); + PROCESS_SWITCH(strangepidqa, processCascadesNonDerived, "Process real cascades from non-derived data", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/QC/strderivedGenQA.cxx b/PWGLF/Tasks/QC/strderivedGenQA.cxx new file mode 100644 index 00000000000..bd52292894e --- /dev/null +++ b/PWGLF/Tasks/QC/strderivedGenQA.cxx @@ -0,0 +1,1241 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.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/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 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 v0radiusMin{"v0radiusMin", 1.2, "minimum V0 radius (cm)"}; + Configurable v0radiusMax{"v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + + // Track quality + Configurable minTPCrows{"minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minITSclusters{"minITSclusters", -1, "minimum ITS clusters"}; + + } v0Selections; + + // Axis declarations + struct : ConfigurableGroup { + 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 axisPA{"axisPA", {200, 0.0f, 0.4f}, "PA"}; + 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"}; + } AxisConfig; + + PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; + + void init(InitContext const&) + { + // Histogram declarations (can be improved!) + histos.add("Event/hPosZ", "hPosZ", kTH1F, {AxisConfig.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, {AxisConfig.axisFt0cOccupancyInTimeRange}); + histos.add("Event/htrackOccupancyInTimeRange", "htrackOccupancyInTimeRange", kTH1F, {AxisConfig.axisTrackOccupancyInTimeRange}); + histos.add("Event/h2dMultFT0C", "h2dMultFT0C", kTH2F, {AxisConfig.axisCentrality, AxisConfig.axisMultFT0C}); + histos.add("Event/h2dMultNTracksPVeta1", "h2dMultNTracksPVeta1", kTH2F, {AxisConfig.axisCentrality, AxisConfig.axisMultNTracksPVeta1}); + histos.add("Event/h2dMultPVTotalContributors", "h2dMultPVTotalContributors", kTH2F, {AxisConfig.axisCentrality, AxisConfig.axisMultPVTotalContributors}); + histos.add("Event/h2dMultAllTracksTPCOnly", "h2dMultAllTracksTPCOnly", kTH2F, {AxisConfig.axisCentrality, AxisConfig.axisMultAllTracksTPCOnly}); + histos.add("Event/h2dMultAllTracksITSTPC", "h2dMultAllTracksITSTPC", kTH2F, {AxisConfig.axisCentrality, AxisConfig.axisMultAllTracksITSTPC}); + histos.add("Event/h2dNumV0sPerColl", "h2dNumV0sPerColl", kTH2F, {AxisConfig.axisCentrality, AxisConfig.axisNumV0sPerColl}); + + if (doprocessDerivedV0s) { + histos.add("V0/hpT", "hpT", kTH1F, {AxisConfig.axisPt}); + histos.add("V0/h2dArmenterosP", "h2dArmenterosP", kTH2F, {AxisConfig.axisAlpha, AxisConfig.axisQtarm}); + histos.add("V0/hRadius", "hRadius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("V0/hZ", "hZ", kTH1F, {AxisConfig.axisPosZ}); + histos.add("V0/hCosPA", "hCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("V0/hdcaDau", "hdcaDau", kTH1F, {AxisConfig.axisDCAdau}); + histos.add("V0/hdcaNegtopv", "hdcaNegtopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("V0/hdcaPostopv", "hdcaPostopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("V0/h2dEtaPhi", "h2dEtaPhi", kTH2F, {AxisConfig.axisEta, AxisConfig.axisPhi}); + histos.add("V0/hYGamma", "hYGamma", kTH1F, {AxisConfig.axisEta}); + histos.add("V0/hYLambda", "hYLambda", kTH1F, {AxisConfig.axisEta}); + histos.add("V0/hYK0Short", "hYK0Short", kTH1F, {AxisConfig.axisEta}); + histos.add("V0/hMassGamma", "hMassGamma", kTH1F, {AxisConfig.axisMassGamma}); + histos.add("V0/hMassLambda", "hMassLambda", kTH1F, {AxisConfig.axisMassLambda}); + histos.add("V0/hMassALambda", "hMassALambda", kTH1F, {AxisConfig.axisMassLambda}); + histos.add("V0/hMassK0Short", "hMassK0Short", kTH1F, {AxisConfig.axisMassK0Short}); + + histos.add("V0/h3dPAVsPtVsGammaMass", "h3dPAVsPtVsGammaMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisMassGamma}); + histos.add("V0/h3dPAVsPtVsLambdaMass", "h3dPAVsPtVsLambdaMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisMassLambda}); + histos.add("V0/h3dPAVsPtVsALambdaMass", "h3dPAVsPtVsALambdaMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisMassLambda}); + histos.add("V0/h3dPAVsPtVsK0SMassMass", "h3dPAVsPtVsK0SMassMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisMassK0Short}); + + histos.add("V0/hV0Type", "hV0Type", kTH1F, {AxisConfig.axisV0Type}); + histos.add("V0/h2dV0Indices", "h2dV0Indices", kTH2F, {AxisConfig.axisStraCollisionId, AxisConfig.axisGlobalIndex}); + + histos.add("V0/Track/h2dITSNCls", "h2dITSNCls", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisNCls}); + histos.add("V0/Track/h2dITSChi2PerNcl", "h2dITSChi2PerNcl", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisChi2PerNcl}); + histos.add("V0/Track/h2dTPCCrossedRows", "h2dTPCCrossedRows", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCrows}); + + histos.add("V0/Track/h2dPosTrackProperties", "h2dPosTrackProperties", kTH2F, {AxisConfig.axisTrackProperties, AxisConfig.axisPt}); + histos.add("V0/Track/h3dTrackPropertiesVspT", "h3dTrackPropertiesVspT", kTH3F, {AxisConfig.axisTrackProperties, AxisConfig.axisTrackProperties, AxisConfig.axisPt}); + histos.add("V0/Track/h2dNegTrackProperties", "h2dNegTrackProperties", kTH2F, {AxisConfig.axisTrackProperties, AxisConfig.axisPt}); + + // Add histogram to the list + histos.add("V0/Track/hTrackCode", "hTrackCode", kTH1F, {AxisConfig.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, {AxisConfig.axisPt2, AxisConfig.axisTPCNSigma}); + histos.add("V0/PID/h2dTPCNSigmaPr", "h2dTPCNSigmaPr", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCNSigma}); + histos.add("V0/PID/h2dTPCNSigmaPi", "h2dTPCNSigmaPi", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCNSigma}); + histos.add("V0/PID/h2dTPCSignal", "h2dTPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + + histos.add("V0/PID/h2dTOFNSigmaLaPr", "h2dTOFNSigmaLaPr", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("V0/PID/h2dTOFNSigmaLaPi", "h2dTOFNSigmaLaPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("V0/PID/h2dposTOFDeltaTLaPr", "h2dposTOFDeltaTLaPr", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFDeltaT}); + histos.add("V0/PID/h2dnegTOFDeltaTLaPi", "h2dnegTOFDeltaTLaPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFDeltaT}); + histos.add("V0/PID/h2dnegTOFDeltaTLaPr", "h2dnegTOFDeltaTLaPr", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFDeltaT}); + histos.add("V0/PID/h2dposTOFDeltaTLaPi", "h2dposTOFDeltaTLaPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFDeltaT}); + histos.add("V0/PID/h2dTOFNSigmaALaPr", "h2dTOFNSigmaALaPr", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("V0/PID/h2dTOFNSigmaALaPi", "h2dTOFNSigmaALaPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("V0/PID/h2dTOFNSigmaK0PiPlus", "h2dTOFNSigmaK0PiPlus", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("V0/PID/h2dTOFNSigmaK0PiMinus", "h2dTOFNSigmaK0PiMinus", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("V0/PID/h3dTPCVsTOFNSigmaLaPr", "h3dTPCVsTOFNSigmaLaPr", kTH3F, {AxisConfig.axisTPCNSigma, AxisConfig.axisTOFNSigma, AxisConfig.axisPt}); + histos.add("V0/PID/h3dTPCVsTOFNSigmaLaPi", "h3dTPCVsTOFNSigmaLaPi", kTH3F, {AxisConfig.axisTPCNSigma, AxisConfig.axisTOFNSigma, AxisConfig.axisPt}); + } + if (doprocessMCDerivedV0s) { + histos.add("MCV0/hv0MCCore", "hv0MCCore", kTH1F, {AxisConfig.axisBool}); + histos.add("MCV0/h2dPDGV0VsMother", "h2dPDGV0VsMother", kTHnSparseD, {AxisConfig.axisPDGCode, AxisConfig.axisPDGCode}); + histos.add("MCV0/h2dPDGV0VsPositive", "h2dPDGV0VsPositive", kTHnSparseD, {AxisConfig.axisPDGCode, AxisConfig.axisPDGCode}); + histos.add("MCV0/h2dPDGV0VsNegative", "h2dPDGV0VsNegative", kTHnSparseD, {AxisConfig.axisPDGCode, AxisConfig.axisPDGCode}); + histos.add("MCV0/h2dPDGV0VsIsPhysicalPrimary", "h2dPDGV0VsIsPhysicalPrimary", kTH2F, {AxisConfig.axisPDGCode, AxisConfig.axisBool}); + histos.add("MCV0/h2dArmenterosP", "h2dArmenterosP", kTH2F, {AxisConfig.axisAlpha, AxisConfig.axisQtarm}); + + histos.add("MCV0/Gamma/h2dpTResolution", "h2dpTResolution", kTH2F, {AxisConfig.axisPt, AxisConfig.axisPtResolution}); + histos.add("MCV0/Gamma/h2dMass", "h2dMass", kTH2F, {AxisConfig.axisPt, AxisConfig.axisMassGamma}); + histos.add("MCV0/Gamma/h2dTPCNSigmaEl", "h2dTPCNSigmaEl", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCNSigma}); + histos.add("MCV0/Gamma/h2dTPCSignal", "h2dTPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("MCV0/Gamma/hRadius", "hRadius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("MCV0/Gamma/hCosPA", "hCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCV0/Gamma/hdcaDau", "hdcaDau", kTH1F, {AxisConfig.axisDCAdau}); + histos.add("MCV0/Gamma/hdcaNegtopv", "hdcaNegtopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCV0/Gamma/hdcaPostopv", "hdcaPostopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCV0/Gamma/hZ", "hZ", kTH1F, {{240, -120.0f, 120.0f}}); + histos.add("MCV0/Gamma/h3dPAVsPtVsMass", "h3dPAVsPtVsMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisMassGamma}); + + histos.add("MCV0/Lambda/h2dpTResolution", "h2dpTResolution", kTH2F, {AxisConfig.axisPt, AxisConfig.axisPtResolution}); + histos.add("MCV0/Lambda/h2dMass", "h2dMass", kTH2F, {AxisConfig.axisPt, AxisConfig.axisMassLambda}); + histos.add("MCV0/Lambda/h2dTPCNSigmaPr", "h2dTPCNSigmaPr", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTPCNSigma}); + histos.add("MCV0/Lambda/h2dTPCNSigmaPi", "h2dTPCNSigmaPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTPCNSigma}); + histos.add("MCV0/Lambda/h2dTPCSignal", "h2dTPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("MCV0/Lambda/hRadius", "hRadius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("MCV0/Lambda/hCosPA", "hCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCV0/Lambda/hdcaDau", "hdcaDau", kTH1F, {AxisConfig.axisDCAdau}); + histos.add("MCV0/Lambda/hdcaNegtopv", "hdcaNegtopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCV0/Lambda/hdcaPostopv", "hdcaPostopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCV0/Lambda/h3dPAVsPtVsMass", "h3dPAVsPtVsMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisMassLambda}); + + histos.add("MCV0/AntiLambda/h2dpTResolution", "h2dpTResolution", kTH2F, {AxisConfig.axisPt, AxisConfig.axisPtResolution}); + histos.add("MCV0/AntiLambda/h2dMass", "h2dMass", kTH2F, {AxisConfig.axisPt, AxisConfig.axisMassLambda}); + histos.add("MCV0/AntiLambda/h2dTPCNSigmaPr", "h2dTPCNSigmaPr", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTPCNSigma}); + histos.add("MCV0/AntiLambda/h2dTPCNSigmaPi", "h2dTPCNSigmaPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTPCNSigma}); + histos.add("MCV0/AntiLambda/h2dTPCSignal", "h2dTPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("MCV0/AntiLambda/hRadius", "hRadius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("MCV0/AntiLambda/hCosPA", "hCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCV0/AntiLambda/hdcaDau", "hdcaDau", kTH1F, {AxisConfig.axisDCAdau}); + histos.add("MCV0/AntiLambda/hdcaNegtopv", "hdcaNegtopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCV0/AntiLambda/hdcaPostopv", "hdcaPostopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCV0/AntiLambda/h3dPAVsPtVsMass", "h3dPAVsPtVsMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisMassLambda}); + + histos.add("MCV0/K0Short/h2dpTResolution", "h2dpTResolution", kTH2F, {AxisConfig.axisPt, AxisConfig.axisPtResolution}); + histos.add("MCV0/K0Short/h2dMass", "h2dMass", kTH2F, {AxisConfig.axisPt, AxisConfig.axisMassK0Short}); + histos.add("MCV0/K0Short/h2dTPCNSigmaPi", "h2dTPCNSigmaPi", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCNSigma}); + histos.add("MCV0/K0Short/h2dTPCSignal", "h2dTPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("MCV0/K0Short/hRadius", "hRadius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("MCV0/K0Short/hCosPA", "hCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCV0/K0Short/hdcaDau", "hdcaDau", kTH1F, {AxisConfig.axisDCAdau}); + histos.add("MCV0/K0Short/hdcaNegtopv", "hdcaNegtopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCV0/K0Short/hdcaPostopv", "hdcaPostopv", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCV0/K0Short/h3dPAVsPtVsMass", "h3dPAVsPtVsMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisMassK0Short}); + } + if (doprocessDerivedCascades) { + histos.add("Casc/Sign", "Sign", kTH1F, {{3, -1.5f, 1.5f}}); + histos.add("Casc/hpT", "hpT", kTH1F, {AxisConfig.axisPt}); + histos.add("Casc/hV0Radius", "hV0Radius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("Casc/hCascRadius", "hCascRadius", kTH1F, {AxisConfig.axisCascRadius}); + histos.add("Casc/hV0CosPA", "hV0CosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("Casc/hCascCosPA", "hCascCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("Casc/hDCAPosToPV", "hDCAPosToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("Casc/hDCANegToPV", "hDCANegToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("Casc/hDCABachToPV", "hDCABachToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("Casc/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {AxisConfig.axisDCAXYCascToPV}); + histos.add("Casc/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {AxisConfig.axisDCAZCascToPV}); + histos.add("Casc/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {AxisConfig.axisDCAV0ToPV}); + histos.add("Casc/hDCAV0Dau", "hDCAV0Dau", kTH1F, {AxisConfig.axisDCAV0Dau}); + histos.add("Casc/hDCACascDau", "hDCACascDau", kTH1F, {AxisConfig.axisDCACascDau}); + histos.add("Casc/hLambdaMass", "hLambdaMass", kTH1F, {AxisConfig.axisMassLambda}); + + histos.add("Casc/Track/h3dTrackProperties", "h3dTrackProperties", kTH3F, {AxisConfig.axisTrackProperties, AxisConfig.axisTrackProperties, AxisConfig.axisTrackProperties}); + histos.add("Casc/Track/h2dPosTrackProperties", "h2dPosTrackProperties", kTH2F, {AxisConfig.axisTrackProperties, AxisConfig.axisPt}); + histos.add("Casc/Track/h2dNegTrackProperties", "h2dNegTrackProperties", kTH2F, {AxisConfig.axisTrackProperties, AxisConfig.axisPt}); + histos.add("Casc/Track/h2dBachTrackProperties", "h2dBachTrackProperties", kTH2F, {AxisConfig.axisTrackProperties, AxisConfig.axisPt}); + histos.add("Casc/Track/h2dV0ITSChi2PerNcl", "h2dV0ITSChi2PerNcl", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisChi2PerNcl}); + histos.add("Casc/Track/h2dV0TPCCrossedRows", "h2dV0TPCCrossedRows", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCrows}); + histos.add("Casc/Track/h2dV0ITSNCls", "h2dV0ITSNCls", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisNCls}); + + histos.add("Casc/PID/h2dV0TPCNSigmaPr", "h2dV0TPCNSigmaPr", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCNSigma}); + histos.add("Casc/PID/h2dV0TPCNSigmaPi", "h2dV0TPCNSigmaPi", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCNSigma}); + histos.add("Casc/PID/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("Casc/PID/h2dTOFNSigmaXiLaPi", "h2dTOFNSigmaXiLaPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaXiLaPr", "h2dTOFNSigmaXiLaPr", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaXiPi", "h2dTOFNSigmaXiPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaOmLaPi", "h2dTOFNSigmaOmLaPi", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaOmLaPr", "h2dTOFNSigmaOmLaPr", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + histos.add("Casc/PID/h2dTOFNSigmaOmKa", "h2dTOFNSigmaOmKa", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTOFNSigma}); + + histos.add("Casc/hMassXiMinus", "hMassXiMinus", kTH1F, {AxisConfig.axisXiMass}); + histos.add("Casc/hMassOmegaMinus", "hMassOmegaMinus", kTH1F, {AxisConfig.axisOmegaMass}); + histos.add("Casc/hMassXiPlus", "hMassXiPlus", kTH1F, {AxisConfig.axisXiMass}); + histos.add("Casc/hMassOmegaPlus", "hMassOmegaPlus", kTH1F, {AxisConfig.axisOmegaMass}); + + histos.add("Casc/h3dPAVsPtVsMassXiMinus", "h3dPAVsPtVsMassXiMinus", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisXiMass}); + histos.add("Casc/h3dPAVsPtVsMassOmegaMinus", "h3dPAVsPtVsMassOmegaMinus", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisOmegaMass}); + histos.add("Casc/h3dPAVsPtVsMassXiPlus", "h3dPAVsPtVsMassXiPlus", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisXiMass}); + histos.add("Casc/h3dPAVsPtVsMassOmegaPlus", "h3dPAVsPtVsMassOmegaPlus", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisOmegaMass}); + + histos.add("Casc/Track/h2dBachITSNCls", "h2dBachITSNCls", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisNCls}); + histos.add("Casc/Track/h2dBachITSChi2PerNcl", "h2dBachITSChi2PerNcl", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisChi2PerNcl}); + histos.add("Casc/Track/h2dBachTPCCrossedRows", "h2dBachTPCCrossedRows", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCrows}); + histos.add("Casc/PID/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + } + + if (doprocessMCDerivedCascades) { + histos.add("MCCasc/hcascMCCore", "hcascMCCore", kTH1F, {AxisConfig.axisBool}); + histos.add("MCCasc/h2dPDGV0VsMother", "h2dPDGV0VsMother", kTHnSparseD, {AxisConfig.axisPDGCode, AxisConfig.axisPDGCode}); + histos.add("MCCasc/h2dPDGV0VsPositive", "h2dPDGV0VsPositive", kTHnSparseD, {AxisConfig.axisPDGCode, AxisConfig.axisPDGCode}); + histos.add("MCCasc/h2dPDGV0VsNegative", "h2dPDGV0VsNegative", kTHnSparseD, {AxisConfig.axisPDGCode, AxisConfig.axisPDGCode}); + histos.add("MCCasc/h2dPDGV0VsBach", "h2dPDGV0VsBach", kTHnSparseD, {AxisConfig.axisPDGCode, AxisConfig.axisPDGCode}); + histos.add("MCCasc/h2dPDGV0VsIsPhysicalPrimary", "h2dPDGV0VsIsPhysicalPrimary", kTH2F, {AxisConfig.axisPDGCode, AxisConfig.axisBool}); + + histos.add("MCCasc/XiMinus/h2dpTResolution", "h2dpTResolution", kTH2F, {AxisConfig.axisPt, AxisConfig.axisPtResolution}); + histos.add("MCCasc/XiMinus/h3dPAVsPtVsMass", "h3dPAVsPtVsMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisXiMass}); + histos.add("MCCasc/XiMinus/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("MCCasc/XiMinus/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTPCSignal}); + histos.add("MCCasc/XiMinus/hV0Radius", "hV0Radius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("MCCasc/XiMinus/hCascRadius", "hCascRadius", kTH1F, {AxisConfig.axisCascRadius}); + histos.add("MCCasc/XiMinus/hV0CosPA", "hV0CosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCCasc/XiMinus/hCascCosPA", "hCascCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCCasc/XiMinus/hDCAPosToPV", "hDCAPosToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/XiMinus/hDCANegToPV", "hDCANegToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/XiMinus/hDCABachToPV", "hDCABachToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/XiMinus/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {AxisConfig.axisDCAXYCascToPV}); + histos.add("MCCasc/XiMinus/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {AxisConfig.axisDCAZCascToPV}); + histos.add("MCCasc/XiMinus/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {AxisConfig.axisDCAV0ToPV}); + histos.add("MCCasc/XiMinus/hDCAV0Dau", "hDCAV0Dau", kTH1F, {AxisConfig.axisDCAV0Dau}); + histos.add("MCCasc/XiMinus/hDCACascDau", "hDCACascDau", kTH1F, {AxisConfig.axisDCACascDau}); + histos.add("MCCasc/XiMinus/hLambdaMass", "hLambdaMass", kTH1F, {AxisConfig.axisMassLambda}); + + histos.add("MCCasc/XiPlus/h2dpTResolution", "h2dpTResolution", kTH2F, {AxisConfig.axisPt, AxisConfig.axisPtResolution}); + histos.add("MCCasc/XiPlus/h3dPAVsPtVsMass", "h3dPAVsPtVsMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisXiMass}); + histos.add("MCCasc/XiPlus/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("MCCasc/XiPlus/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTPCSignal}); + histos.add("MCCasc/XiPlus/hV0Radius", "hV0Radius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("MCCasc/XiPlus/hCascRadius", "hCascRadius", kTH1F, {AxisConfig.axisCascRadius}); + histos.add("MCCasc/XiPlus/hV0CosPA", "hV0CosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCCasc/XiPlus/hCascCosPA", "hCascCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCCasc/XiPlus/hDCAPosToPV", "hDCAPosToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/XiPlus/hDCANegToPV", "hDCANegToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/XiPlus/hDCABachToPV", "hDCABachToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/XiPlus/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {AxisConfig.axisDCAXYCascToPV}); + histos.add("MCCasc/XiPlus/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {AxisConfig.axisDCAZCascToPV}); + histos.add("MCCasc/XiPlus/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {AxisConfig.axisDCAV0ToPV}); + histos.add("MCCasc/XiPlus/hDCAV0Dau", "hDCAV0Dau", kTH1F, {AxisConfig.axisDCAV0Dau}); + histos.add("MCCasc/XiPlus/hDCACascDau", "hDCACascDau", kTH1F, {AxisConfig.axisDCACascDau}); + histos.add("MCCasc/XiPlus/hLambdaMass", "hLambdaMass", kTH1F, {AxisConfig.axisMassLambda}); + + histos.add("MCCasc/OmegaMinus/h2dpTResolution", "h2dpTResolution", kTH2F, {AxisConfig.axisPt, AxisConfig.axisPtResolution}); + histos.add("MCCasc/OmegaMinus/h3dPAVsPtVsMass", "h3dPAVsPtVsMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisXiMass}); + histos.add("MCCasc/OmegaMinus/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("MCCasc/OmegaMinus/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTPCSignal}); + histos.add("MCCasc/OmegaMinus/hV0Radius", "hV0Radius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("MCCasc/OmegaMinus/hCascRadius", "hCascRadius", kTH1F, {AxisConfig.axisCascRadius}); + histos.add("MCCasc/OmegaMinus/hV0CosPA", "hV0CosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCCasc/OmegaMinus/hCascCosPA", "hCascCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCCasc/OmegaMinus/hDCAPosToPV", "hDCAPosToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/OmegaMinus/hDCANegToPV", "hDCANegToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/OmegaMinus/hDCABachToPV", "hDCABachToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/OmegaMinus/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {AxisConfig.axisDCAXYCascToPV}); + histos.add("MCCasc/OmegaMinus/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {AxisConfig.axisDCAZCascToPV}); + histos.add("MCCasc/OmegaMinus/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {AxisConfig.axisDCAV0ToPV}); + histos.add("MCCasc/OmegaMinus/hDCAV0Dau", "hDCAV0Dau", kTH1F, {AxisConfig.axisDCAV0Dau}); + histos.add("MCCasc/OmegaMinus/hDCACascDau", "hDCACascDau", kTH1F, {AxisConfig.axisDCACascDau}); + histos.add("MCCasc/OmegaMinus/hLambdaMass", "hLambdaMass", kTH1F, {AxisConfig.axisMassLambda}); + + histos.add("MCCasc/OmegaPlus/h2dpTResolution", "h2dpTResolution", kTH2F, {AxisConfig.axisPt, AxisConfig.axisPtResolution}); + histos.add("MCCasc/OmegaPlus/h3dPAVsPtVsMass", "h3dPAVsPtVsMass", kTH3D, {AxisConfig.axisPA, AxisConfig.axisPt, AxisConfig.axisXiMass}); + histos.add("MCCasc/OmegaPlus/h2dV0TPCSignal", "h2dV0TPCSignal", kTH2F, {AxisConfig.axisPt2, AxisConfig.axisTPCSignal}); + histos.add("MCCasc/OmegaPlus/h2dBachTPCSignal", "h2dBachTPCSignal", kTH2F, {AxisConfig.axisPt, AxisConfig.axisTPCSignal}); + histos.add("MCCasc/OmegaPlus/hV0Radius", "hV0Radius", kTH1F, {AxisConfig.axisV0Radius}); + histos.add("MCCasc/OmegaPlus/hCascRadius", "hCascRadius", kTH1F, {AxisConfig.axisCascRadius}); + histos.add("MCCasc/OmegaPlus/hV0CosPA", "hV0CosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCCasc/OmegaPlus/hCascCosPA", "hCascCosPA", kTH1F, {AxisConfig.axisCosPA}); + histos.add("MCCasc/OmegaPlus/hDCAPosToPV", "hDCAPosToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/OmegaPlus/hDCANegToPV", "hDCANegToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/OmegaPlus/hDCABachToPV", "hDCABachToPV", kTH1F, {AxisConfig.axisDCAToPV}); + histos.add("MCCasc/OmegaPlus/hDCAXYCascToPV", "hDCAXYCascToPV", kTH1F, {AxisConfig.axisDCAXYCascToPV}); + histos.add("MCCasc/OmegaPlus/hDCAZCascToPV", "hDCAZCascToPV", kTH1F, {AxisConfig.axisDCAZCascToPV}); + histos.add("MCCasc/OmegaPlus/hDCAV0ToPV", "hDCAV0ToPV", kTH1F, {AxisConfig.axisDCAV0ToPV}); + histos.add("MCCasc/OmegaPlus/hDCAV0Dau", "hDCAV0Dau", kTH1F, {AxisConfig.axisDCAV0Dau}); + histos.add("MCCasc/OmegaPlus/hDCACascDau", "hDCACascDau", kTH1F, {AxisConfig.axisDCACascDau}); + histos.add("MCCasc/OmegaPlus/hLambdaMass", "hLambdaMass", kTH1F, {AxisConfig.axisMassLambda}); + } + + // MC Generated level + if (doprocessGenerated) { + histos.add("GenMC/hGenEvents", "hGenEvents", kTH2F, {{AxisConfig.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, {AxisConfig.axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("GenMC/hCentralityVsNcoll_afterEvSel", "hCentralityVsNcoll_afterEvSel", kTH2F, {AxisConfig.axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("GenMC/hCentralityVsMultMC", "hCentralityVsMultMC", kTH2F, {{101, 0.0f, 101.0f}, AxisConfig.axisNch}); + histos.add("GenMC/h2dGenGamma", "h2dGenGamma", kTH2D, {AxisConfig.axisCentrality, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenK0Short", "h2dGenK0Short", kTH2D, {AxisConfig.axisCentrality, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenLambda", "h2dGenLambda", kTH2D, {AxisConfig.axisCentrality, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenAntiLambda", "h2dGenAntiLambda", kTH2D, {AxisConfig.axisCentrality, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenXiMinus", "h2dGenXiMinus", kTH2D, {AxisConfig.axisCentrality, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenXiPlus", "h2dGenXiPlus", kTH2D, {AxisConfig.axisCentrality, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenOmegaMinus", "h2dGenOmegaMinus", kTH2D, {AxisConfig.axisCentrality, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenOmegaPlus", "h2dGenOmegaPlus", kTH2D, {AxisConfig.axisCentrality, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenK0ShortVsMultMC_RecoedEvt", "h2dGenK0ShortVsMultMC_RecoedEvt", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenLambdaVsMultMC_RecoedEvt", "h2dGenLambdaVsMultMC_RecoedEvt", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenAntiLambdaVsMultMC_RecoedEvt", "h2dGenAntiLambdaVsMultMC_RecoedEvt", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenXiMinusVsMultMC_RecoedEvt", "h2dGenXiMinusVsMultMC_RecoedEvt", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenXiPlusVsMultMC_RecoedEvt", "h2dGenXiPlusVsMultMC_RecoedEvt", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenOmegaMinusVsMultMC_RecoedEvt", "h2dGenOmegaMinusVsMultMC_RecoedEvt", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenOmegaPlusVsMultMC_RecoedEvt", "h2dGenOmegaPlusVsMultMC_RecoedEvt", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenGammaVsMultMC", "h2dGenGammaVsMultMC", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenK0ShortVsMultMC", "h2dGenK0ShortVsMultMC", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenLambdaVsMultMC", "h2dGenLambdaVsMultMC", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenAntiLambdaVsMultMC", "h2dGenAntiLambdaVsMultMC", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenXiMinusVsMultMC", "h2dGenXiMinusVsMultMC", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenXiPlusVsMultMC", "h2dGenXiPlusVsMultMC", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenOmegaMinusVsMultMC", "h2dGenOmegaMinusVsMultMC", kTH2D, {AxisConfig.axisNch, AxisConfig.axisPt}); + histos.add("GenMC/h2dGenOmegaPlusVsMultMC", "h2dGenOmegaPlusVsMultMC", kTH2D, {AxisConfig.axisNch, AxisConfig.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/hMassALambda"), v0.mAntiLambda()); + histos.fill(HIST("V0/hMassK0Short"), v0.mK0Short()); + + histos.fill(HIST("V0/h3dPAVsPtVsGammaMass"), TMath::ACos(v0.v0cosPA()), pT, v0.mGamma()); + histos.fill(HIST("V0/h3dPAVsPtVsLambdaMass"), TMath::ACos(v0.v0cosPA()), pT, v0.mLambda()); + histos.fill(HIST("V0/h3dPAVsPtVsALambdaMass"), TMath::ACos(v0.v0cosPA()), pT, v0.mAntiLambda()); + histos.fill(HIST("V0/h3dPAVsPtVsK0SMassMass"), TMath::ACos(v0.v0cosPA()), pT, 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/h3dPAVsPtVsMass"), TMath::ACos(v0.v0cosPA()), 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()); + histos.fill(HIST("MCV0/Gamma/hZ"), v0.z()); + } + 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/h3dPAVsPtVsMass"), TMath::ACos(v0.v0cosPA()), 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/h3dPAVsPtVsMass"), TMath::ACos(v0.v0cosPA()), 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/h3dPAVsPtVsMass"), TMath::ACos(v0.v0cosPA()), 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/h3dPAVsPtVsMassXiMinus"), TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z())), pT, casc.mXi()); + histos.fill(HIST("Casc/h3dPAVsPtVsMassOmegaMinus"), TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z())), pT, 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/h3dPAVsPtVsMassXiPlus"), TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z())), pT, casc.mXi()); + histos.fill(HIST("Casc/h3dPAVsPtVsMassOmegaPlus"), TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z())), pT, 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/h3dPAVsPtVsMass"), TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z())), 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/h3dPAVsPtVsMass"), TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z())), 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/h3dPAVsPtVsMass"), TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z())), 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/h3dPAVsPtVsMass"), TMath::ACos(casc.v0cosPA(casc.x(), casc.y(), casc.z())), 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/systematicsMapping.cxx b/PWGLF/Tasks/QC/systematicsMapping.cxx new file mode 100644 index 00000000000..1b26b3b525a --- /dev/null +++ b/PWGLF/Tasks/QC/systematicsMapping.cxx @@ -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. + +/// \file systematicsMapping.cxx +/// \brief Task to perform a systematics study for K0s and charged Kaons +/// \author Nicolò Jacazio, Universita del Piemonte Orientale (IT) +/// \since September 22, 2025 + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; + +struct SystematicsMapping { + // Returns a unique index for the combination of cuts + ConfigurableAxis ptBins{"ptBins", {100, 0.f, 10.f}, "Binning for pT (GeV/c)"}; + ConfigurableAxis etaBins{"etaBins", {40, -1.0f, 1.0f}, "Binning for #eta"}; + ConfigurableAxis phiBins{"phiBins", {36, 0.f, o2::constants::math::TwoPI}, "Binning for #phi (rad)"}; + // Define the Signal axis + ConfigurableAxis invariantMassBins{"invariantMassBins", {100, -0.1f, 0.1f}, "Binning for the invariant mass (GeV/c^2)"}; + ConfigurableAxis nsigmaBins{"nsigmaBins", {100, -10.f, 10.f}, "Binning for nSigma"}; + // Selection bins + ConfigurableAxis tpcCrossedRowsBins{"tpcCrossedRowsBins", {5, 70, 100, 120, 135, 150}, "Min TPC clusters for tracks"}; + ConfigurableAxis itsClustersBins{"itsClustersBins", {5, 0, 6}, "Min ITS clusters for tracks"}; + ConfigurableAxis dcaBins{"dcaBins", {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 for DCA (cm)"}; + ConfigurableAxis chi2Bins{"chi2Bins", {100, 0.f, 100.f}, "Binning for chi2"}; + // Selection configurables + Configurable selectionPosZ{"selectionPosZ", 10.f, "Max |z| of the primary vertex"}; + // V0 selection criteria + Configurable v0cospa{"v0cospa", 0.97, "V0 CosPA"}; + Configurable dcav0dau{"dcav0dau", 10, "DCA V0 Daughters"}; + Configurable dcanegtopv{"dcanegtopv", 0.0, "DCA Neg To PV"}; + Configurable dcapostopv{"dcapostopv", 0.0, "DCA Pos To PV"}; + Configurable v0radius{"v0radius", 0.0, "Radius"}; + Configurable etadau{"etadau", 0.8, "Eta Daughters"}; + + HistogramRegistry registry{"registry"}; + + template + bool isCollisionSelected(T const& collision) + { + return collision.sel8() && std::abs(collision.posZ()) <= selectionPosZ; + } + + void init(InitContext const&) + { + const AxisSpec ptAxis{ptBins, "#it{p}_{T} (GeV/c)"}; + const AxisSpec etaAxis{etaBins, "#eta"}; + const AxisSpec phiAxis{phiBins, "#phi (rad)"}; + const AxisSpec invariantMassAxis{invariantMassBins, "Invariant Mass (GeV/c^{2})"}; + const AxisSpec nsigmaAxisTPC{nsigmaBins, "nSigma TPC"}; + const AxisSpec nsigmaAxisTOF{nsigmaBins, "nSigma TOF"}; + const AxisSpec tpcCrossedRowsAxis{tpcCrossedRowsBins, "TPC crossed rows"}; + const AxisSpec itsClustersAxis{itsClustersBins, "ITS clusters"}; + const AxisSpec dcaXYAxis{dcaBins, "DCAxy (cm)"}; + const AxisSpec dcaZAxis{dcaBins, "DCAz (cm)"}; + const AxisSpec chi2TPCAxis{chi2Bins, "TPC Chi2"}; + const AxisSpec chi2ITSAxis{chi2Bins, "ITS Chi2"}; + + if (doprocessData) { + + // First we define the histograms on which we are cutting (tpc clusters, its clusters, ..) + registry.add("K/hTPCCrossedRows", "", HistType::kTH1F, {{100, 0, 200}}); + registry.add("K/hITSClusters", "", HistType::kTH1F, {{10, 0, 10}}); + registry.add("K/hDCAxy", "", HistType::kTH1F, {dcaBins}); + registry.add("K/hDCAz", "", HistType::kTH1F, {dcaBins}); + registry.add("K/hChi2OverNCLsTPC", "", HistType::kTH1F, {chi2Bins}); + registry.add("K/hChi2OverNCLsITS", "", HistType::kTH1F, {chi2Bins}); + registry.addClone("K/", "K0s/"); + + // Add the signal histograms + registry.add("K/SignalPositive", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis, nsigmaAxisTPC, nsigmaAxisTOF, tpcCrossedRowsAxis, itsClustersAxis, dcaXYAxis, dcaZAxis, chi2TPCAxis, chi2ITSAxis}); + registry.add("K/SignalNegative", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis, nsigmaAxisTPC, nsigmaAxisTOF, tpcCrossedRowsAxis, itsClustersAxis, dcaXYAxis, dcaZAxis, chi2TPCAxis, chi2ITSAxis}); + registry.add("K0s/Signal", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis, invariantMassBins, nsigmaAxisTPC, nsigmaAxisTOF, tpcCrossedRowsAxis, itsClustersAxis, dcaXYAxis, dcaZAxis, chi2TPCAxis, chi2ITSAxis}); + } + + if (doprocessMc) { + registry.add("K/GeneratedPositive", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis}); + registry.add("K/GeneratedNegative", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis}); + registry.add("K0s/Generated", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis}); + registry.add("K/ReconstructedPositive", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis, nsigmaAxisTPC, nsigmaAxisTOF, tpcCrossedRowsAxis, itsClustersAxis, dcaXYAxis, dcaZAxis, chi2TPCAxis, chi2ITSAxis}); + registry.add("K/ReconstructedNegative", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis, nsigmaAxisTPC, nsigmaAxisTOF, tpcCrossedRowsAxis, itsClustersAxis, dcaXYAxis, dcaZAxis, chi2TPCAxis, chi2ITSAxis}); + registry.add("K0s/Reconstructed", "", HistType::kTHnSparseF, {ptAxis, etaAxis, phiAxis, invariantMassBins, nsigmaAxisTPC, nsigmaAxisTOF, tpcCrossedRowsAxis, itsClustersAxis, dcaXYAxis, dcaZAxis, chi2TPCAxis, chi2ITSAxis}); + } + } + + using TrackType = soa::Join; + using CollisionType = soa::Join; + + void processData(CollisionType const& collisions, + TrackType const& tracks, + aod::V0Datas const& v0s) + { + for (const auto& collision : collisions) { + if (isCollisionSelected(collision)) + continue; // MB selection + + // Kaon loop + for (const auto& track : tracks) { + if (track.collisionId() != collision.globalIndex()) + continue; + registry.fill(HIST("K/hTPCCrossedRows"), track.tpcNClsCrossedRows()); + registry.fill(HIST("K/hITSClusters"), track.itsNCls()); + registry.fill(HIST("K/hDCAxy"), track.dcaXY()); + registry.fill(HIST("K/hDCAz"), track.dcaZ()); + registry.fill(HIST("K/hChi2OverNCLsTPC"), track.tpcChi2NCl()); + registry.fill(HIST("K/hChi2OverNCLsITS"), track.itsChi2NCl()); + if (track.sign() > 0) + registry.fill(HIST("K/SignalPositive"), track.pt(), track.eta(), track.phi(), track.tpcNSigmaKa(), track.tofNSigmaKa(), track.tpcNClsCrossedRows(), track.itsNCls(), track.dcaXY(), track.dcaZ(), track.tpcChi2NCl(), track.itsChi2NCl()); + else + registry.fill(HIST("K/SignalNegative"), track.pt(), track.eta(), track.phi(), track.tpcNSigmaKa(), track.tofNSigmaKa(), track.tpcNClsCrossedRows(), track.itsNCls(), track.dcaXY(), track.dcaZ(), track.tpcChi2NCl(), track.itsChi2NCl()); + } + + // K0s loop + for (const auto& v0 : v0s) { + if (v0.collisionId() != collision.globalIndex()) + continue; + + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + if (v0.v0radius() < v0radius || + v0.v0cosPA() < v0cospa || + std::abs(posTrack.eta()) > etadau || + std::abs(negTrack.eta()) > etadau) + continue; + registry.fill(HIST("K0s/hTPCCrossedRows"), std::min(posTrack.tpcNClsCrossedRows(), negTrack.tpcNClsCrossedRows())); + registry.fill(HIST("K0s/hITSClusters"), std::min(posTrack.itsNCls(), negTrack.itsNCls())); + registry.fill(HIST("K0s/hDCAxy"), std::min(posTrack.dcaXY(), negTrack.dcaXY())); + registry.fill(HIST("K0s/hDCAz"), std::min(posTrack.dcaZ(), negTrack.dcaZ())); + registry.fill(HIST("K0s/hChi2OverNCLsTPC"), std::min(posTrack.tpcChi2NCl(), negTrack.tpcChi2NCl())); + registry.fill(HIST("K0s/hChi2OverNCLsITS"), std::min(posTrack.itsChi2NCl(), negTrack.itsChi2NCl())); + registry.fill(HIST("K0s/Signal"), v0.pt(), v0.eta(), v0.phi(), v0.mK0Short() - constants::physics::MassK0Short, + std::max(posTrack.tpcNSigmaPi(), negTrack.tpcNSigmaPi()), + std::max(posTrack.tofNSigmaPi(), negTrack.tofNSigmaPi()), + std::min(posTrack.tpcNClsCrossedRows(), negTrack.tpcNClsCrossedRows()), + std::min(posTrack.itsNCls(), negTrack.itsNCls()), + std::min(posTrack.dcaXY(), negTrack.dcaXY()), + std::min(posTrack.dcaZ(), negTrack.dcaZ()), + std::min(posTrack.tpcChi2NCl(), negTrack.tpcChi2NCl()), + std::min(posTrack.itsChi2NCl(), negTrack.itsChi2NCl())); + } + } + } + PROCESS_SWITCH(SystematicsMapping, processData, "Systematics study for K0s and charged Kaons", true); + + void processMc(soa::Join const& collisions, + soa::Join const& tracks, + soa::Join const& v0s, + aod::McParticles const& particles, + aod::McCollisions const&) + { + for (const auto& collision : collisions) { + if (!isCollisionSelected(collision)) + continue; // MB selection + if (!collision.has_mcCollision()) + continue; + const auto& mcCollision = collision.mcCollision(); + + for (const auto& track : tracks) { + if (track.collisionId() != collision.globalIndex()) + continue; + if (!track.has_mcParticle()) + continue; + const auto& mcParticle = track.mcParticle(); + if (mcParticle.mcCollisionId() != mcCollision.globalIndex()) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + switch (mcParticle.pdgCode()) { + case 321: // K+ + registry.fill(HIST("K/ReconstructedPositive"), track.pt(), track.eta(), track.phi(), track.tpcNSigmaKa(), track.tofNSigmaKa(), track.tpcNClsCrossedRows(), track.itsNCls(), track.dcaXY(), track.dcaZ(), track.tpcChi2NCl(), track.itsChi2NCl()); + break; + case -321: // K- + registry.fill(HIST("K/ReconstructedNegative"), track.pt(), track.eta(), track.phi(), track.tpcNSigmaKa(), track.tofNSigmaKa(), track.tpcNClsCrossedRows(), track.itsNCls(), track.dcaXY(), track.dcaZ(), track.tpcChi2NCl(), track.itsChi2NCl()); + break; + default: + break; + } + } + + for (const auto& v0 : v0s) { + if (v0.collisionId() != collision.globalIndex()) + continue; + if (!v0.has_mcParticle()) + continue; + const auto& mcParticle = v0.mcParticle(); + if (mcParticle.mcCollisionId() != mcCollision.globalIndex()) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + if (std::abs(mcParticle.pdgCode()) != 310) + continue; + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); + if (v0.v0radius() < v0radius || + v0.v0cosPA() < v0cospa || + std::abs(posTrack.eta()) > etadau || + std::abs(negTrack.eta()) > etadau) + continue; + + registry.fill(HIST("K0s/Reconstructed"), v0.pt(), v0.eta(), v0.phi(), v0.mK0Short() - constants::physics::MassK0Short, + std::max(posTrack.tpcNSigmaPi(), negTrack.tpcNSigmaPi()), + std::max(posTrack.tofNSigmaPi(), negTrack.tofNSigmaPi()), + std::min(posTrack.tpcNClsCrossedRows(), negTrack.tpcNClsCrossedRows()), + std::min(posTrack.itsNCls(), negTrack.itsNCls()), + std::min(posTrack.dcaXY(), negTrack.dcaXY()), + std::min(posTrack.dcaZ(), negTrack.dcaZ()), + std::min(posTrack.tpcChi2NCl(), negTrack.tpcChi2NCl()), + std::min(posTrack.itsChi2NCl(), negTrack.itsChi2NCl())); + } + + for (const auto& particle : particles) { + if (particle.mcCollisionId() != mcCollision.globalIndex()) + continue; + if (!particle.isPhysicalPrimary()) + continue; + switch (particle.pdgCode()) { + case 321: // K+ + registry.fill(HIST("K/GeneratedPositive"), particle.pt(), particle.eta(), particle.phi()); + break; + case -321: // K- + registry.fill(HIST("K/GeneratedNegative"), particle.pt(), particle.eta(), particle.phi()); + break; + case 310: // K0s + registry.fill(HIST("K0s/Generated"), particle.pt(), particle.eta(), particle.phi()); + break; + default: + break; + } + } + } + } + PROCESS_SWITCH(SystematicsMapping, processMc, "Systematics study for K0s and charged Kaons on MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/QC/tpc_dEdx_postcalibration.cxx b/PWGLF/Tasks/QC/tpc_dEdx_postcalibration.cxx index 1e9fbd43851..aaf874e6da3 100644 --- a/PWGLF/Tasks/QC/tpc_dEdx_postcalibration.cxx +++ b/PWGLF/Tasks/QC/tpc_dEdx_postcalibration.cxx @@ -12,17 +12,20 @@ /// \author Alberto Caliva (alberto.caliva@cern.ch) /// \since June 27, 2023 +#include "PWGLF/DataModel/LFStrangenessTables.h" + #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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.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 o2; diff --git a/PWGLF/Tasks/QC/tpc_dedx_qa.cxx b/PWGLF/Tasks/QC/tpc_dedx_qa.cxx index 38f73b8edcb..2e4d63de9cb 100644 --- a/PWGLF/Tasks/QC/tpc_dedx_qa.cxx +++ b/PWGLF/Tasks/QC/tpc_dedx_qa.cxx @@ -12,19 +12,22 @@ /// \author Alberto Caliva (alberto.caliva@cern.ch) /// \since September 19, 2023 +#include "PWGLF/DataModel/LFStrangenessTables.h" + #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/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.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 o2; diff --git a/PWGLF/Tasks/QC/trackchecks.cxx b/PWGLF/Tasks/QC/trackchecks.cxx index 70eaa28dd3b..1b974f824b1 100644 --- a/PWGLF/Tasks/QC/trackchecks.cxx +++ b/PWGLF/Tasks/QC/trackchecks.cxx @@ -8,21 +8,23 @@ // In applying this license CERN does 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/TrackSelection.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" +#include "Framework/runDataProcessing.h" #include +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/PWGLF/Tasks/QC/trackedCascadeProperties.cxx b/PWGLF/Tasks/QC/trackedCascadeProperties.cxx new file mode 100644 index 00000000000..e18abfd6e3c --- /dev/null +++ b/PWGLF/Tasks/QC/trackedCascadeProperties.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 trackedCascadeProperties.cxx +/// +/// \brief task to study the average cluster size of tracked cascades +/// +/// \author Alberto Caliva (alberto.caliva@cern.ch), Francesca Ercolessi (francesca.ercolessi@cern.ch) +/// \since May 31, 2024 + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; +using namespace o2::constants::math; +using std::array; + +// Define type aliases for joined tables +using SelectedCollisions = soa::Join; +using FullTracks = soa::Join; + +struct TrackedCascadeProperties { + + // Instantiate the CCDB manager service and API interface + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + // Instantiate the main Zorro processing object and define an output to store summary information + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // Histogram registry for quality control + HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Histogram registry for data + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Global Parameters + Configurable zVtx{"zVtx", 10.0f, "z vertex cut"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + Configurable triggerList{"triggerList", "fTrackedOmega, fTrackedXi, fOmegaLargeRadius, fDoubleOmega, fOmegaHighMult, fSingleXiYN, fQuadrupleXi, fDoubleXi, fhadronOmega, fOmegaXi, fTripleXi, fOmega", "Trigger list"}; + + // Analysis Selections + Configurable minItsClustersCasc{"minItsClustersCasc", 4, "min ITS Clusters"}; + Configurable massMinXi{"massMinXi", 1.315f, "mMin Xi"}; + Configurable massMaxXi{"massMaxXi", 1.328f, "mMax Xi"}; + Configurable massMinOmega{"massMinOmega", 1.665f, "mMin Omega"}; + Configurable massMaxOmega{"massMaxOmega", 1.680f, "mMax Omega"}; + + // Initialize CCDB access and histogram registry for Zorro processing + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + zorro.populateHistRegistry(registryData, bc.runNumber()); + } + } + + void init(InitContext const&) + { + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + // Quality Control Histograms + 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"}}); + + // Event Counter + registryData.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{5, 0, 5, "Event Cuts"}}); + + // Average cluster size vs momentum + registryData.add("xi_pos_avgclustersize_cosL_vs_p", "xi_pos_avgclustersize_cosL_vs_p", 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_vs_p", "xi_neg_avgclustersize_cosL_vs_p", 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_vs_p", "omega_pos_avgclustersize_cosL_vs_p", 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_vs_p", "omega_neg_avgclustersize_cosL_vs_p", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + + // Average cluster size vs betagamma + 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)"}}); + + // Cluster size using truncated mean vs momentum + registryData.add("xi_pos_avgclustersize_trunc_cosL_vs_p", "xi_pos_avgclustersize_trunc_cosL_vs_p", 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_trunc_cosL_vs_p", "xi_neg_avgclustersize_trunc_cosL_vs_p", 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_trunc_cosL_vs_p", "omega_pos_avgclustersize_trunc_cosL_vs_p", 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_trunc_cosL_vs_p", "omega_neg_avgclustersize_trunc_cosL_vs_p", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p} (GeV/#it{c})"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + + // Cluster size using truncated mean vs betagamma + registryData.add("xi_pos_avgclustersize_trunc_cosL_vs_betagamma", "xi_pos_avgclustersize_trunc_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_trunc_cosL_vs_betagamma", "xi_neg_avgclustersize_trunc_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_trunc_cosL_vs_betagamma", "omega_pos_avgclustersize_trunc_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_trunc_cosL_vs_betagamma", "omega_neg_avgclustersize_trunc_cosL_vs_betagamma", HistType::kTH2F, {{200, 0.0, 10.0, "#beta#gamma"}, {100, 0.0, 20.0, "#LT ITS cluster size #GT cos(#lambda)"}}); + + // mass histograms + 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 trackInclination(double eta) + { + double lambda(0); + double theta = 2.0 * std::atan(std::exp(-eta)); + if (theta <= PIHalf) + lambda = PIHalf - theta; + if (theta > PIHalf) + lambda = theta - PIHalf; + return lambda; + } + + int findBin(const std::vector& edges, double value) + { + auto it = std::upper_bound(edges.begin(), edges.end(), value); + int index = static_cast(it - edges.begin()) - 1; + if (index < 0 || index >= static_cast(edges.size()) - 1) { + return -1; // value is out of bounds + } + return index; + } + + void processData(SelectedCollisions::iterator const& collision, aod::AssignedTrackedCascades const& trackedCascades, + aod::Cascades const&, FullTracks const&, aod::BCsWithTimestamps const&) + { + // Number of events before any selection + registryData.fill(HIST("number_of_events_data"), 0.5); + + // Retrieve the bunch crossing information with timestamps from the collision + auto bc = collision.template bc_as(); + initCCDB(bc); + + // If skimmed processing is enabled, apply Zorro trigger selection + if (cfgSkimmedProcessing && !zorro.isSelected(collision.template bc_as().globalBC())) { + return; + } + + // Number of events after skimming selection + registryData.fill(HIST("number_of_events_data"), 1.5); + if (!collision.sel8()) + return; + + // Number of events after sel8 + registryData.fill(HIST("number_of_events_data"), 2.5); + if (std::abs(collision.posZ()) > zVtx) + return; + + // Number of events after zVtx cut + registryData.fill(HIST("number_of_events_data"), 3.5); + + // radii of ITS layers + std::vector edgesItsLayers = {0.0, 2.2, 2.8, 3.6, 20.0, 22.0, 37.0, 39.0, 100.0}; + + // Loop over tracked cascades + for (const auto& trackedCascade : trackedCascades) { + + // Get tracked cascade + const auto track = trackedCascade.track_as(); + const auto trackITS = trackedCascade.itsTrack_as(); + const auto& casc = trackedCascade.cascade(); + const auto& btrack = casc.bachelor_as(); + double dx = trackedCascade.decayX(); + double dy = trackedCascade.decayY(); + double r = std::sqrt(dx * dx + dy * dy); + int nItsLayersCrossed = findBin(edgesItsLayers, r); + + // Fill QC histograms + registryQC.fill(HIST("matchingChi2"), trackedCascade.matchingChi2()); + registryQC.fill(HIST("topologyChi2"), trackedCascade.topologyChi2()); + registryQC.fill(HIST("decayXY"), dx, dy); + + // Compute average cluster size and truncated mean + double sumClusterSize = 0.0; + double sumClusterSizeTrunc = 0.0; + double maxClusterSize = 0.0; + double averageClusterSize = 0.0; + double averageClusterSizeTrunc = 0.0; + int nCls = 0; + + for (int i = 0; i < nItsLayersCrossed; i++) { + double clusterSize = static_cast(trackITS.itsClsSizeInLayer(i)); + if (clusterSize > 0) { + sumClusterSize += clusterSize; + sumClusterSizeTrunc += clusterSize; + nCls++; + if (clusterSize > maxClusterSize) { + maxClusterSize = clusterSize; + } + } + } + if (nCls > 0) { + averageClusterSize = sumClusterSize / static_cast(nCls); + } + if (nCls > 1) { + averageClusterSizeTrunc = (sumClusterSizeTrunc - maxClusterSize) / static_cast(nCls - 1); + } + + // Apply selection on number of ITS clusters + if (nCls < minItsClustersCasc) + continue; + + // 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()); + } + + // Variables + double lambda = trackInclination(track.eta()); + double clsSizeCosL = averageClusterSize * std::cos(lambda); + double clsSizeCosLtrunc = averageClusterSizeTrunc * std::cos(lambda); + double bgXi = track.p() / MassXiPlusBar; + double bgOmega = track.p() / MassOmegaPlusBar; + + // Xi + if (trackedCascade.xiMass() > massMinXi && trackedCascade.xiMass() < massMaxXi) { + registryQC.fill(HIST("nITScls_vs_p_xi"), track.p(), trackITS.itsNCls()); + if (btrack.sign() > 0) { + registryData.fill(HIST("xi_pos_avgclustersize_cosL_vs_p"), track.p(), clsSizeCosL); + registryData.fill(HIST("xi_pos_avgclustersize_cosL_vs_betagamma"), bgXi, clsSizeCosL); + registryData.fill(HIST("xi_pos_avgclustersize_trunc_cosL_vs_p"), track.p(), clsSizeCosLtrunc); + registryData.fill(HIST("xi_pos_avgclustersize_trunc_cosL_vs_betagamma"), bgXi, clsSizeCosLtrunc); + } + if (btrack.sign() < 0) { + registryData.fill(HIST("xi_neg_avgclustersize_cosL_vs_p"), track.p(), clsSizeCosL); + registryData.fill(HIST("xi_neg_avgclustersize_cosL_vs_betagamma"), bgXi, clsSizeCosL); + registryData.fill(HIST("xi_neg_avgclustersize_trunc_cosL_vs_p"), track.p(), clsSizeCosLtrunc); + registryData.fill(HIST("xi_neg_avgclustersize_trunc_cosL_vs_betagamma"), bgXi, clsSizeCosLtrunc); + } + 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() > massMinOmega && trackedCascade.omegaMass() < massMaxOmega) { + registryQC.fill(HIST("nITScls_vs_p_omega"), track.p(), trackITS.itsNCls()); + if (btrack.sign() > 0) { + registryData.fill(HIST("omega_pos_avgclustersize_cosL_vs_p"), track.p(), clsSizeCosL); + registryData.fill(HIST("omega_pos_avgclustersize_cosL_vs_betagamma"), bgOmega, clsSizeCosL); + registryData.fill(HIST("omega_pos_avgclustersize_trunc_cosL_vs_p"), track.p(), clsSizeCosLtrunc); + registryData.fill(HIST("omega_pos_avgclustersize_trunc_cosL_vs_betagamma"), bgOmega, clsSizeCosLtrunc); + } + if (btrack.sign() < 0) { + registryData.fill(HIST("omega_neg_avgclustersize_cosL_vs_p"), track.p(), clsSizeCosL); + registryData.fill(HIST("omega_neg_avgclustersize_cosL_vs_betagamma"), bgOmega, clsSizeCosL); + registryData.fill(HIST("omega_neg_avgclustersize_trunc_cosL_vs_p"), track.p(), clsSizeCosLtrunc); + registryData.fill(HIST("omega_neg_avgclustersize_trunc_cosL_vs_betagamma"), bgOmega, clsSizeCosLtrunc); + } + } + } + } + PROCESS_SWITCH(TrackedCascadeProperties, processData, "Process data", true); +}; + +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 deleted file mode 100644 index bf070e8aec8..00000000000 --- a/PWGLF/Tasks/QC/tracked_cascade_properties.cxx +++ /dev/null @@ -1,218 +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), 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" - -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.31f, "mMin Xi"}; - Configurable mMax_xi{"mMax_xi", 1.33f, "mMax Xi"}; - Configurable mMin_omega{"mMin_omega", 1.66f, "mMin Omega"}; - Configurable mMax_omega{"mMax_omega", 1.68f, "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_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()); - - // 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(), track.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_mass_pos"), track.p(), trackedCascade.xiMass()); - } - 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_mass_neg"), track.p(), trackedCascade.xiMass()); - } - continue; - } - - // Omega - if (trackedCascade.omegaMass() > mMin_omega && trackedCascade.omegaMass() < mMax_omega) { - registryQC.fill(HIST("nITScls_vs_p_omega"), track.p(), track.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_mass_pos"), track.p(), trackedCascade.omegaMass()); - } - 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_mass_neg"), track.p(), trackedCascade.omegaMass()); - } - } - } - } - 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..9effceb40e5 --- /dev/null +++ b/PWGLF/Tasks/QC/v0assoqa.cxx @@ -0,0 +1,483 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFParticleIdentification.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/strangenessBuilderHelper.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TPCVDriftManager.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/McCollisionExtra.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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/v0cascadesqa.cxx b/PWGLF/Tasks/QC/v0cascadesqa.cxx index 5be2b6d4ba5..c22ac235cfd 100644 --- a/PWGLF/Tasks/QC/v0cascadesqa.cxx +++ b/PWGLF/Tasks/QC/v0cascadesqa.cxx @@ -18,20 +18,23 @@ #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" + #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" using namespace o2; using namespace o2::framework; 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 5a30b91e5de..660eb015a1e 100644 --- a/PWGLF/Tasks/Resonances/CMakeLists.txt +++ b/PWGLF/Tasks/Resonances/CMakeLists.txt @@ -19,11 +19,21 @@ o2physics_add_dpl_workflow(phianalysis PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(cksspinalignder + SOURCES cksspinalignder.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(k892analysis SOURCES k892analysis.cxx 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 @@ -34,16 +44,36 @@ o2physics_add_dpl_workflow(k892pmanalysis PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(lambda1405analysis + SOURCES lambda1405analysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(lambda1520analysis SOURCES lambda1520analysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(lambda1520analysisinpp + SOURCES lambda1520analysisinpp.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambda1520analysisinoo + SOURCES lambda1520analysisinOO.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(k1analysis SOURCES k1analysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(k1analysismicro + SOURCES k1AnalysisMicro.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phianalysisrun3 SOURCES phianalysisrun3.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -54,6 +84,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 @@ -90,7 +125,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) @@ -124,11 +159,36 @@ 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(omega2012analysis + SOURCES omega2012Analysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(xi1820analysis + SOURCES xi1820Analysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(initializereventqa + SOURCES initializereventqa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(kaonkaonanalysis SOURCES kaonkaonanalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -136,7 +196,7 @@ o2physics_add_dpl_workflow(kaonkaonanalysis o2physics_add_dpl_workflow(highmasslambda SOURCES highmasslambda.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(lambdav2 @@ -148,3 +208,87 @@ 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) + +o2physics_add_dpl_workflow(kstarinoo + SOURCES kstarInOO.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(phioo + SOURCES phiOO.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(kstar892-light-ion + SOURCES kstar892LightIon.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(phispectrapbpbqa + SOURCES phispectrapbpbqa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phi-1020-spherocity-analysis + SOURCES phi1020SpherocityAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phitutorial + SOURCES phitutorial.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(phitutorial-step0 + SOURCES phitutorial_step0.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phitutorial-step1 + SOURCES phitutorial_step1.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phitutorial-step2 + SOURCES phitutorial_step2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(phitutorial-step3 + SOURCES phitutorial_step3.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 895f61dc3a3..00000000000 --- a/PWGLF/Tasks/Resonances/KshortKshort.cxx +++ /dev/null @@ -1,875 +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 -#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 "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 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 QAevents{"QAevents", false, "QA of events"}; - 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"}; - - // 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 c_nof_rotations{"c_nof_rotations", 3, "Number of random rotations in the rotational background"}; - - // 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", 50.0f, "Maximum pT"}; - Configurable cPtBins{"cPtBins", 500, "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"}; - 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)"}; - - // 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 = {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"}; - - // 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, {{2000, 0, 20000}}); - rEventSelection.add("multdist_FT0A", "FT0A Multiplicity distribution", kTH1F, {{2000, 0, 20000}}); - rEventSelection.add("multdist_FT0C", "FT0C Multiplicity distribution", kTH1F, {{2000, 0, 20000}}); - rEventSelection.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 10000.0f}}); - } - - if (inv_mass1D) { - hglue.add("h1glueInvMassDS", "h1glueInvMassDS", kTH1F, {glueballMassAxis}); - hglue.add("h1glueInvMassME", "h1glueInvMassME", kTH1F, {glueballMassAxis}); - hglue.add("h1glueInvMassRot", "h1glueInvMassRot", kTH1F, {glueballMassAxis}); - } - - 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 (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, {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_lambda_kshort", "mass under lambda hypotheses and Kshort mass", kTH2F, {{100, 0.2, 0.8}, {100, 0.9, 1.5}}); - // 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("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}}); - - // // 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}}}); - rKzeroShort.add("dE_by_dx_TPC", "dE/dx signal in the TPC as a function of pT", kTH2F, {axisPtfordEbydx, axisdEdx}); - } - 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) - { - hglue.fill(HIST("heventscheck"), 1.5); - - if (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 (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return false; - } - hglue.fill(HIST("heventscheck"), 4.5); - if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return false; - } - hglue.fill(HIST("heventscheck"), 5.5); - if (itstpctracks && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return false; - } - hglue.fill(HIST("heventscheck"), 6.5); - // if (collision.alias_bit(kTVXinTRD)) { - // // TRD triggered - // // return 0; - // } - auto multNTracksPV = collision.multNTracksPV(); - if (additionalEvsel && multNTracksPV < fMultPVCutLow->Eval(multiplicity)) { - return false; - } - hglue.fill(HIST("heventscheck"), 7.5); - if (additionalEvsel && multNTracksPV > fMultPVCutHigh->Eval(multiplicity)) { - return false; - } - hglue.fill(HIST("heventscheck"), 8.5); - // 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("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("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("hqtarmbyalpha"), arm); - rKzeroShort.fill(HIST("hpsipair"), candidate.psipair()); - rKzeroShort.fill(HIST("mass_lambda_kshort"), candidate.mK0Short(), candidate.mLambda()); - } - - hglue.fill(HIST("htrackscheck_v0"), 0.5); - - if (!DCAv0topv && fabs(candidate.dcav0topv()) > cMaxV0DCA) { - return false; - } - - hglue.fill(HIST("htrackscheck_v0"), 1.5); - - if (rapidityks && TMath::Abs(candidate.yK0Short()) >= ConfKsrapidity) { - return false; - } - - hglue.fill(HIST("htrackscheck_v0"), 2.5); - - if (masslambda && TMath::Abs(candidate.mLambda() - candidate.mK0Short()) >= competingcascrejlambda && TMath::Abs(candidate.mAntiLambda() - candidate.mK0Short()) >= competingcascrejlambdaanti) { - return false; - } - - hglue.fill(HIST("htrackscheck_v0"), 3.5); - - // if (isStandarv0 && candidate.isStandardV0 == 0) { - // return false; - // } - - if (pT < ConfV0PtMin) { - return false; - } - hglue.fill(HIST("htrackscheck_v0"), 4.5); - - if (dcaDaughv0 > ConfV0DCADaughMax) { - return false; - } - hglue.fill(HIST("htrackscheck_v0"), 5.5); - - if (cpav0 < ConfV0CPAMin) { - return false; - } - hglue.fill(HIST("htrackscheck_v0"), 6.5); - - if (tranRad < ConfV0TranRadV0Min) { - return false; - } - hglue.fill(HIST("htrackscheck_v0"), 7.5); - - if (tranRad > ConfV0TranRadV0Max) { - return false; - } - hglue.fill(HIST("htrackscheck_v0"), 8.5); - - if (fabs(CtauK0s) > cMaxV0LifeTime || candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { - return false; - } - hglue.fill(HIST("htrackscheck_v0"), 9.5); - - if (!armcut && arm < Confarmcut) { - return false; - } - hglue.fill(HIST("htrackscheck_v0"), 10.5); - - 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()); - rKzeroShort.fill(HIST("dE_by_dx_TPC"), track.pt(), track.tpcSignal()); - } - 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(); - hglue.fill(HIST("htrackscheck_v0_daughters"), 0.5); - if (!track.hasTPC()) - return false; - hglue.fill(HIST("htrackscheck_v0_daughters"), 1.5); - if (track.tpcNClsCrossedRows() < tpcCrossedrows) - return false; - hglue.fill(HIST("htrackscheck_v0_daughters"), 2.5); - if (track.tpcCrossedRowsOverFindableCls() < tpcCrossedrowsOverfcls) - return false; - hglue.fill(HIST("htrackscheck_v0_daughters"), 3.5); - - if (charge < 0 && sign > 0) { - 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 (std::abs(eta) > ConfDaughEta) { - return false; - } - hglue.fill(HIST("htrackscheck_v0_daughters"), 6.5); - if (tpcNClsF < ConfDaughTPCnclsMin) { - return false; - } - hglue.fill(HIST("htrackscheck_v0_daughters"), 7.5); - // if (std::abs(dcaXY) < ConfDaughDCAMin) { - // return false; - // } - // v0 PID selection - if (std::abs(nsigmaV0Daughter) > ConfDaughPIDCuts) { - return false; - } - hglue.fill(HIST("htrackscheck_v0_daughters"), 8.5); - - // 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&) - - ROOT::Math::PxPyPzMVector daughter1, daughter2; - ROOT::Math::PxPyPzMVector lv3; - 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; - } - - if (QAevents) { - rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - rEventSelection.fill(HIST("hmultiplicity"), multiplicity); - rEventSelection.fill(HIST("multdist_FT0M"), collision.centFT0M()); - rEventSelection.fill(HIST("multdist_FT0A"), collision.centFT0A()); - rEventSelection.fill(HIST("multdist_FT0C"), collision.centFT0C()); - rEventSelection.fill(HIST("hNcontributor"), collision.numContrib()); - } - - std::vector v0indexes; - - for (auto& [v1, v2] : combinations(CombinationsStrictlyUpperIndexPolicy(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(); - - 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, v1)) { - continue; - } - if (!isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2, v2)) { - continue; - } - if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1, v1)) { - continue; - } - if (!isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2, v2)) { - continue; - } - - if (!(std::find(v0indexes.begin(), v0indexes.end(), v1.globalIndex()) != v0indexes.end())) { - v0indexes.push_back(v1.globalIndex()); - } - // std::cout << "global index of v1: " << v1.globalIndex() << " global index of v2: " << v2.globalIndex() << std::endl; - if (!(std::find(v0indexes.begin(), v0indexes.end(), v2.globalIndex()) != v0indexes.end())) { - v0indexes.push_back(v2.globalIndex()); - } - - TLorentzVector lv1, lv2, lv3, lv4, lv5; - - lv1.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi(), massK0s); - - lv2.SetPtEtaPhiM(v2.pt(), v2.eta(), v2.phi(), massK0s); - - lv3 = lv1 + lv2; - - daughter1 = ROOT::Math::PxPyPzMVector(v1.px(), v1.py(), v1.pz(), massK0s); // Kplus - daughter2 = ROOT::Math::PxPyPzMVector(v2.px(), v2.py(), v2.pz(), massK0s); // Kminus - - // 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(), massK0s); // Kshort - - ROOT::Math::PxPyPzMVector 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 - 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 - - TRandom* rn = new TRandom(); - - if (TMath::Abs(lv3.Rapidity() < 0.5)) { - - if (inv_mass1D) { - hglue.fill(HIST("h1glueInvMassRot"), lv3.M()); - } - - 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())); - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - lv4.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi() + theta2, massK0s); // for rotated background - lv5 = lv2 + lv4; - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarHelicity); - } - - } 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())); - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - lv4.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi() + theta2, massK0s); // for rotated background - lv5 = lv2 + lv4; - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarProduction); - } - } 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()); - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - lv4.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi() + theta2, massK0s); // for rotated background - lv5 = lv2 + lv4; - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarBeam); - } - } else if (activateTHnSparseCosThStarRandom) { - 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()); - hglue.fill(HIST("h3glueInvMassDS"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - lv4.SetPtEtaPhiM(v1.pt(), v1.eta(), v1.phi() + theta2, massK0s); // for rotated background - lv5 = lv2 + lv4; - hglue.fill(HIST("h3glueInvMassRot"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarRandom); - } - } - } - } - if (QAv0) { - int sizeofv0indexes = v0indexes.size(); - rKzeroShort.fill(HIST("NksProduced"), sizeofv0indexes); - // std::cout << "Size of v0indexes: " << sizeofv0indexes << std::endl; - } - } - - 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) - { - - 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 - { - - float multiplicity = 0.0f; - - multiplicity = c1.centFT0M(); - - 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{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; - } - - 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; - - 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(), massK0s); // Kshort - - ROOT::Math::PxPyPzMVector 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 - 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 (TMath::Abs(lv3.Rapidity() < 0.5)) { - - 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())); - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); - } 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())); - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); - } 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()); - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); - } else if (activateTHnSparseCosThStarRandom) { - 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()); - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); - } - } - - // 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{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; - } - - 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; - - 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(), massK0s); // Kshort - - ROOT::Math::PxPyPzMVector 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 - 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 (TMath::Abs(lv3.Rapidity() < 0.5)) { - - 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())); - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); - } 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())); - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); - } 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()); - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); - } else if (activateTHnSparseCosThStarRandom) { - 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()); - hglue.fill(HIST("h3glueInvMassME"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); - } - } - - // 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 c3d0437fe54..f600962f8c9 100644 --- a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx +++ b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx @@ -8,1047 +8,955 @@ // In applying this license CERN does 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 CKS resonance -/// \author prottay das -/// \since 13/01/2024 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "TF1.h" +/// \file chargedkstaranalysis.cxx +/// \brief Reconstruction of track-track decay resonance candidates +/// +/// +/// \author Protay +/// \author Navneet -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" #include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" #include "Framework/StepTHn.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include "TVector2.h" +// #include // FIXME +#include +#include +#include +#include +#include +#include +#include +#include +#include // FIXME + +#include +#include +#include +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using std::array; +using namespace o2::soa; +using namespace o2::constants::physics; 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; + using EventCandidates = soa::Join; + // using EventCandidates = soa::Join; + // using TrackCandidates = soa::Join; + // using TrackCandidates = 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}; + + 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"}; + + 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"}; + + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 2.0, "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"}; + + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + + Configurable trackSelection{"trackSelection", 0, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQ ualityTracks, 5 -> kInAcceptanceTracks"}; + // + // 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 + // + // 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"}; + + 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 - // Histograms are defined with HistogramRegistry - HistogramRegistry rEventSelection{"eventSelection", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - HistogramRegistry histos{ - "histos", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - HistogramRegistry rGenParticles{"genParticles", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rRecParticles{"recParticles", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - - // 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 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"}; - 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"}; - Configurable cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; - Configurable isMC{"isMC", true, "Run MC"}; - Configurable avoidsplitrackMC{"avoidsplitrackMC", false, "avoid split track in MC"}; - Configurable isNoTOF{"isNoTOF", false, "isNoTOF"}; - Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; - Configurable TVXEvsel{"TVXEvsel", false, "Triggger selection"}; - 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; - - 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}}); - } - - 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}}}); - } - - // histos.add("counter", "counter", {HistType::kTH1F, {{10, 0.0f, 10.0f}}}); - - // 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}}); - rGenParticles.add("hCentGen", "Gen MC Event centrality", kTH1F, {{100, 0.0f, 100.0f}}); - rRecParticles.add("hCentRec", "Rec MC Event centrality", kTH1F, {{100, 0.0f, 100.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}}}); - - rGenParticles.add("hCKSGen", - "Invariant mass of CKS meson Gen", kTHnSparseF, - {{200, 0.0, 20.0}, {100, 0.0f, 100.0f}}, true); - rRecParticles.add("hCKSRec", - "Invariant mass of CKS meson Rec", kTHnSparseF, - {{200, 0.0, 20.0}, {100, 0.0f, 100.0f}}, true); - } - - // 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); - } - } - - double massPi = TDatabasePDG::Instance() - ->GetParticle(kPiPlus) - ->Mass(); - double massK0s = TDatabasePDG::Instance() - ->GetParticle(kK0Short) - ->Mass(); - double massKa = o2::constants::physics::MassKPlus; - ROOT::Math::PtEtaPhiMVector CKSVector; - - template - bool eventSelected(TCollision collision, const float& centrality) + 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{"cfgReturnFlag", false, "Return Flag for debugging"}; + Configurable cSecondaryRequire{"cSecondaryRequire", true, "Secondary cuts on/off"}; + + 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 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"}; + + // 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"}; + + float centrality; + + // PDG code + int kPDGK0s = 310; + int kKstarPlus = static_cast(o2::constants::physics::Pdg::kKPlusStar892); + int kPiPlus = 211; + int kPDGK0 = 311; + + void init(o2::framework::InitContext&) { - 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; + 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 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 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/CentDist1", "Centrality distribution", o2::framework::kTH1F, {{110, 0, 110}}); + 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}}); + + histos.add("QA/trkbpionTPCPIDME", "TPC PID of bachelor pion candidates", HistType::kTH2D, {ptAxisQA, pidQAAxis}); + + // 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, {centAxis, ptAxis, invMassAxisReso}); + histos.add("hInvmass_KstarME", "Invariant mass of unlike-sign chK(892)ME", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisReso}); + histos.add("hInvmass_KstarRotated", "Invariant mass of unlike-sign chK(892)Rota", HistType::kTHnSparseD, {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}); + + if (fillRotation) { + histos.add("hRotation", "hRotation", kTH1F, {{360, 0.0, o2::constants::math::TwoPI}}); + } + // 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/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, {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 - bool selectionTrack(const T& candidate) + // Track selection + template + bool trackCut(TrackType const& track) { - if (iscustomDCAcut && - (!candidate.isGlobalTrack() || !candidate.isPVContributor() || - candidate.itsNCls() < cfgITScluster)) { + // basic track cuts + if (std::abs(track.pt()) < cMinPtcut) return false; - } - /* - if (ismanualDCAcut && - (!candidate.isGlobalTrackWoDCA() || !candidate.isPVContributor() || - std::abs(candidate.dcaXY()) > cfgCutDCAxy || - std::abs(candidate.dcaZ()) > cfgCutDCAz || - candidate.itsNCls() < cfgITScluster || candidate.tpcNClsFound() < 70)) { - return false; - } - */ - if (ismanualDCAcut && !(candidate.isGlobalTrackWoDCA() && candidate.isPVContributor() && std::abs(candidate.dcaXY()) < cfgCutDCAxy && std::abs(candidate.dcaZ()) < cfgCutDCAz && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { + if (std::abs(track.eta()) > cMaxEtacut) return false; - } - - return true; - } - - template - bool selectionPID(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; - } - - /* - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { - return true; - } - else if (candidate.hasTOF() && - std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOF) { - return true; - } - */ - - /* - if (candidate.hasTOF() && - (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + - candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < - (nsigmaCutCombined * nsigmaCutCombined)) { - return true; - } - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { - return true; - } - */ - - /* - 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 SelectionV0(Collision const& collision, V0 const& candidate, - float multiplicity) - { - if (fabs(candidate.dcav0topv()) > cMaxV0DCA) { + if (track.itsNCls() < cfgITScluster) return false; - } - - if (TMath::Abs(candidate.yK0Short()) > 0.5) { + if (track.tpcNClsFound() < cfgTPCcluster) 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) { + if (track.tpcCrossedRowsOverFindableCls() < cfgRatioTPCRowsOverFindableCls) return false; - } - if (dcaDaughv0 > ConfV0DCADaughMax) { + if (track.itsChi2NCl() >= cfgITSChi2NCl) return false; - } - if (cpav0 < ConfV0CPAMin) { + if (track.tpcChi2NCl() >= cfgTPCChi2NCl) return false; - } - if (tranRad < ConfV0TranRadV0Min) { + if (cfgHasITS && !track.hasITS()) return false; - } - if (tranRad > ConfV0TranRadV0Max) { + if (cfgHasTPC && !track.hasTPC()) return false; - } - if (fabs(CtauK0s) > cMaxV0LifeTime || - candidate.mK0Short() < lowmasscutks0 || - candidate.mK0Short() > highmasscutks0) { + if (cfgHasTOF && !track.hasTOF()) return false; - } - if (arm < 0.2) { + if (cfgUseITSRefit && !track.passedITSRefit()) 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) - { - const auto eta = track.eta(); - const auto tpcNClsF = track.tpcNClsFound(); - const auto dcaXY = track.dcaXY(); - const auto sign = track.sign(); - - if (!track.hasTPC()) + if (cfgUseTPCRefit && !track.passedTPCRefit()) return false; - if (track.tpcNClsCrossedRows() < 70) + if (cfgPVContributor && !track.isPVContributor()) return false; - if (track.tpcCrossedRowsOverFindableCls() < 0.8) + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) return false; - - if (charge < 0 && sign > 0) { + if (cfgGlobalTrack && !track.isGlobalTrack()) return false; - } - if (charge > 0 && sign < 0) { + if (cfgPrimaryTrack && !track.isPrimaryTrack()) return false; - } - if (std::abs(eta) > ConfDaughEta) { + if (std::abs(track.dcaXY()) > cMaxbDCArToPVcut) return false; - } - if (tpcNClsF < ConfDaughTPCnclsMin) { + if (std::abs(track.dcaZ()) > cMaxbDCAzToPVcut) return false; - } - if (std::abs(dcaXY) < ConfDaughDCAMin) { + return true; + } + + template + bool isTrackSelected(TrackType const& track) + { + // Track selection + // These are the track selection for the resotracks this cut is to compare the no. of tracks after reso-initializer + // MC case can be handled here + // DCAxy cut + if (std::fabs(track.dcaXY()) > cMaxDCArToPVcut) return false; - } - if (std::abs(nsigmaV0Daughter) > ConfDaughPIDCuts) { + // DCAz cut + if (std::fabs(track.dcaZ()) > cMaxDCAzToPVcut || std::fabs(track.dcaZ()) < cMinDCAzToPVcut) 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>; - 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", - {2, 0, 100}, - "multiplicity percentile for bin"}; - ConfigurableAxis axisMultiplicity{ - "axisMultiplicity", - {2000, 0, 10000}, - "TPC multiplicity for bin"}; - - using BinningTypeTPCMultiplicity = - ColumnBinningPolicy; - // using BinningTypeVertexContributor = - // ColumnBinningPolicy; - using BinningTypeCentralityM = - ColumnBinningPolicy; - using BinningTypeVertexContributor = - ColumnBinningPolicy; - - BinningTypeVertexContributor binningOnPositions{ - {axisVertex, axisMultiplicityClass}, - 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 processSE(EventCandidates::iterator const& collision, - TrackCandidates const& tracks, aod::BCs const&) - */ + // PID selection tools + template + bool selectionPIDPion(TrackType const& candidate) { + bool tpcPIDPassed{false}, tofPIDPassed{false}; - if (!collision.sel8()) { - return; - } - - std::vector pions, kaons, kshorts; - std::vector pions2, kaons2; - std::vector PionIndex = {}; - std::vector PionSign = {}; - std::vector PioncollIndex = {}; - std::vector PionIndex2 = {}; - std::vector PionSign2 = {}; - std::vector PioncollIndex2 = {}; - - std::vector KaonIndex = {}; - std::vector KaonSign = {}; - std::vector KaoncollIndex = {}; - std::vector KaonIndex2 = {}; - std::vector KaonSign2 = {}; - std::vector KaoncollIndex2 = {}; - - 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 (TVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { - return; - } - - if (additionalEvsel && !eventSelected(collision, centrality)) { - return; - } + if (cTPConly) { - // 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 (std::abs(candidate.tpcNSigmaPi()) < cMaxTPCnSigmaPion) { + tpcPIDPassed = true; + } else { + return false; } - */ - if (!selectionPID(track1)) - continue; // for primary particle PID + tofPIDPassed = true; - if (!selectionTrack(track1)) { - continue; - } + } else { - 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()); + 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; } - - ROOT::Math::PtEtaPhiMVector temp1(track1.pt(), track1.eta(), track1.phi(), - massPi); - pions.push_back(temp1); - PionIndex.push_back(track1.globalIndex()); - // PionIndex.push_back(track1.index()); - PioncollIndex.push_back(track1.collisionId()); - PionSign.push_back(track1.sign()); } - /* - for (auto track2 : tracks) { - if (!selectionPID(track2)) - continue; // for primary particle PID - - if (!selectionTrack(track2)) { - continue; - } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } - ROOT::Math::PtEtaPhiMVector temp2(track2.pt(), track2.eta(), track2.phi(), - massKa); - kaons.push_back(temp2); - //PionIndex.push_back(track1.globalIndex()); - KaonIndex.push_back(track2.index()); - KaoncollIndex.push_back(track2.collisionId()); - KaonSign.push_back(track2.sign()); - } // track loop ends - */ + 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 v0Radius = candidate.v0radius(); + auto DCAtoPV = candidate.dcav0topv(); + auto cosPA = candidate.v0cosPA(); + auto PropTauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massK0s; + 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 (v0Radius < cSecondaryRadiusMin) { + histos.fill(HIST("QA/K0sCutCheck"), 6); + returnFlag = false; + } + if (DCAtoPV > cSecondaryDCAtoPVMax) { + histos.fill(HIST("QA/K0sCutCheck"), 7); + returnFlag = false; + } + if (cosPA < cSecondaryCosPAMin) { + histos.fill(HIST("QA/K0sCutCheck"), 8); + returnFlag = false; + } + if (PropTauK0s > cSecondaryProperLifetimeMax) { + histos.fill(HIST("QA/K0sCutCheck"), 9); + returnFlag = false; + } + if (std::fabs(mK0s - massK0s) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + returnFlag = false; + } - for (auto& v0 : V0s) { + return returnFlag; - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - double nTPCSigmaPos[1]{postrack.tpcNSigmaPi()}; - double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; + } else { + if (std::fabs(mK0s - massK0s) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + returnFlag = false; + } - if (!isSelectedV0Daughter(postrack, 1, nTPCSigmaPos[0])) { - continue; - } - if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { - continue; + return returnFlag; } - if (!SelectionV0(collision, v0, centrality)) { - continue; - } + } else { + if (cSecondaryRequire) { - ROOT::Math::PtEtaPhiMVector temp2(v0.pt(), v0.eta(), v0.phi(), massK0s); - kshorts.push_back(temp2); - V0collIndex.push_back(v0.collisionId()); - // KshortPosDaughIndex.push_back(postrack.index()); - // KshortNegDaughIndex.push_back(negtrack.index()); - KshortPosDaughIndex.push_back(postrack.globalIndex()); - KshortNegDaughIndex.push_back(negtrack.globalIndex()); - } + 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 (v0Radius < cSecondaryRadiusMin) { + histos.fill(HIST("QA/K0sCutCheck"), 6); + return false; + } + if (DCAtoPV > cSecondaryDCAtoPVMax) { + histos.fill(HIST("QA/K0sCutCheck"), 7); + return false; + } + if (cosPA < cSecondaryCosPAMin) { + histos.fill(HIST("QA/K0sCutCheck"), 8); + return false; + } + if (PropTauK0s > cSecondaryProperLifetimeMax) { + histos.fill(HIST("QA/K0sCutCheck"), 9); + return false; + } + if (std::fabs(mK0s - massK0s) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + return false; + } + return true; - if (pions.size() != 0 && kshorts.size() != 0) { - // if (pions.size() != 0 && kaons.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 ikaon = kaons.begin(); ikaon != kaons.end(); - // ++ikaon) { - // for (auto ikshort = pions2.begin(); ikshort != pions2.end(); - // ++ikshort) { - auto i3 = std::distance(kshorts.begin(), ikshort); - // auto i3 = std::distance(kaons.begin(), ikaon); - if (PionIndex.at(i1) == KshortPosDaughIndex.at(i3)) - continue; - if (PionIndex.at(i1) == KshortNegDaughIndex.at(i3)) - continue; - // if (KaonIndex.at(i3) <= PionIndex.at(i1)) - // continue; - if (PioncollIndex.at(i1) != V0collIndex.at(i3)) - continue; - - // if (PionSign.at(i1) * KaonSign.at(i3) >= 0) - // continue; - - CKSVector = pions.at(i1) + kshorts.at(i3); - // CKSVector = pions.at(i1) + kaons.at(i3); - if (TMath::Abs(CKSVector.Rapidity()) < 0.5) { - histos.fill(HIST("h3CKSInvMassUnlikeSign"), centrality, - CKSVector.Pt(), CKSVector.M()); - } + } else { + if (std::fabs(mK0s - massK0s) > cSecondaryMassWindow) { + histos.fill(HIST("QA/K0sCutCheck"), 10); + return false; } + return true; } } - } + } // selectionK0s - PROCESS_SWITCH(chargedkstaranalysis, processSE, "Process Same event", true); + 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; - void processME(EventCandidates const& /*collisions*/, - TrackCandidates const& /*tracks*/, V0TrackCandidate const& /*V0s*/) + auto motherbTrack = bTrack.template mothers_as(); + auto motherkV0 = K0scand.template mothers_as(); - /* - void processME(EventCandidates const& collisions, - TrackCandidates const& tracks)*/ - { + // Check bTrack first + if (std::abs(motherbTrack.pdgCode()) != kKstarPlus) // Are you charged Kstar's daughter? + return false; // Apply first since it's more restrictive - // histos.fill(HIST("counter"), 1.5); - /* - 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, t - racksTuple, &cache}; - */ + if (std::abs(motherkV0.pdgCode()) != kPDGK0) // Is it K0s? + return false; + // Check if K0s's mother is K0 (311) + auto motherK0 = motherkV0.template mothers_as(); + if (std::abs(motherK0.pdgCode()) != kPDGK0) + return false; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + // Check if K0's mother is Kstar (323) + auto motherKstar = motherK0.template mothers_as(); + if (std::abs(motherKstar.pdgCode()) != kKstarPlus) + return false; - if (!c1.sel8()) { - continue; - } - if (!c2.sel8()) { - continue; - } + // Check if bTrack and K0 have the same mother (global index) + if (motherbTrack.globalIndex() != motherK0.globalIndex()) + return false; - // histos.fill(HIST("counter"), 2.5); + return true; + } - auto centrality = c1.centFT0C(); - auto centrality2 = c2.centFT0C(); + int count = 0; + double massPi = o2::constants::physics::MassPionCharged; + double massK0s = o2::constants::physics::MassK0Short; - 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))) { + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksTypeK0s& dTracks2) + { + histos.fill(HIST("QA/before/CentDist"), collision.centFT0M()); + histos.fill(HIST("QA/before/CentDist1"), collision.centFT0M()); + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResoSecondary, lDecayDaughter_bach, lResoKstar, chargekstarrot; + 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 (!isTrackSelected(bTrack)) continue; - } + 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()); + } else { - if (TVXEvsel && (!c1.selection_bit(aod::evsel::kIsTriggerTVX) || !c2.selection_bit(aod::evsel::kIsTriggerTVX))) { - continue; + histos.fill(HIST("QA/trkbpionTPCPIDME"), trkbpt, trkbNSigmaPiTPC); } - if (additionalEvsel && !eventSelected(c1, centrality)) { + if (!trackCut(bTrack)) continue; - } - if (additionalEvsel && !eventSelected(c2, centrality2)) { + if (!selectionPIDPion(bTrack)) continue; - } - - for (auto& [t1, t2] : o2::soa::combinations( - o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - - // histos.fill(HIST("counter"), 3.5); - if (!selectionTrack(t1)) - continue; - // histos.fill(HIST("counter"), 4.5); - if (!selectionPID(t1)) - continue; - // histos.fill(HIST("counter"), 5.5); - if (t1.sign() == 0) - continue; - // histos.fill(HIST("counter"), 6.5); - - /*if (!selectionTrack(t2)) - continue; - if (!selectionPID(t2)) - continue; - */ - - if (!SelectionV0(c2, t2, centrality2)) - continue; - - // histos.fill(HIST("counter"), 7.5); - 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 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("counter"), 8.5); - if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { - continue; + 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 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 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("counter"), 9.5); - - // if (t1.sign() * t2.sign() >= 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()); + 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/hInvmassSecondary"), trkkMass); } - } - } - PROCESS_SWITCH(chargedkstaranalysis, processME, "Process Mixed event", true); - - void processGenMC(aod::McCollision const& mcCollision, aod::McParticles& mcParticles, const soa::SmallGroups& collisions) - { - - if (std::abs(mcCollision.posZ()) < cutzvertex) - rGenParticles.fill(HIST("hMC"), 0.5); - std::vector SelectedEvents(collisions.size()); - int nevts = 0; - auto cent = 0; - for (const auto& collision : collisions) { - // if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cutzvertex) { - if (std::abs(collision.mcCollision().posZ()) > cutzvertex) { - continue; - } - rGenParticles.fill(HIST("hMC"), 1.5); - /*if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + // 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 (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + if (!cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) continue; - } - if (TVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { + if (!selectionK0s(collision, K0scand)) continue; - } - rGenParticles.fill(HIST("hMC"), 2.5); - - cent = collision.centFT0C(); - rGenParticles.fill(HIST("hCentGen"), cent); - SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); - } - 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 - return; - } - rGenParticles.fill(HIST("hMC"), 3.5); - for (auto& mcParticle : mcParticles) { - if (std::abs(mcParticle.y()) >= 0.5) { - continue; - } - rGenParticles.fill(HIST("hMC"), 4.5); - if (std::abs(mcParticle.pdgCode()) != 323) { - continue; - } - rGenParticles.fill(HIST("hMC"), 5.5); - auto kDaughters = mcParticle.daughters_as(); - if (kDaughters.size() != 2) { - continue; - } + if constexpr (!IsMix) { + // Seconddary QA plots after applying cuts - 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; + 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); } - // count += 1; - } - rGenParticles.fill(HIST("hMC"), 7.5); - if (daughtp && daughts) { - rGenParticles.fill(HIST("hCKSGen"), mcParticle.pt(), cent); + 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/hInvmassSecondary"), trkkMass); } + k0sIndicies.push_back(K0scand.index()); } - } - void processRecMC(EventCandidatesMC::iterator const& collision, - TrackCandidatesMC const& tracks, V0TrackCandidatesMC const& V0s, - aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + for (const auto& trackIndex : trackIndicies) { + for (const auto& k0sIndex : k0sIndicies) { + auto bTrack = dTracks1.rawIteratorAt(trackIndex); + auto K0scand = dTracks2.rawIteratorAt(k0sIndex); - { + lDecayDaughter_bach = ROOT::Math::PxPyPzMVector(bTrack.px(), bTrack.py(), bTrack.pz(), massPi); + lResoSecondary = ROOT::Math::PxPyPzMVector(K0scand.px(), K0scand.py(), K0scand.pz(), massK0s); + lResoKstar = lResoSecondary + lDecayDaughter_bach; - if (!collision.has_mcCollision()) { - return; - } - // if (std::abs(collision.mcCollision().posZ()) > cutzvertex || !collision.sel8()) { - if (std::abs(collision.mcCollision().posZ()) > cutzvertex) { - return; - } + // QA plots + if constexpr (!IsMix) { + histos.fill(HIST("QA/before/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/before/kstarinvmass"), lResoKstar.M()); + } - rRecParticles.fill(HIST("hMCRec"), 0.5); + if (lResoKstar.Rapidity() > cKstarMaxRap || lResoKstar.Rapidity() < cKstarMinRap) + continue; - // if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { - return; - } - if (TVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { - return; - } + if constexpr (!IsMix) { - auto cent = 0; - cent = collision.centFT0C(); + histos.fill(HIST("QA/after/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/after/kstarinvmass"), lResoKstar.M()); + histos.fill(HIST("hInvmass_Kstar"), collision.centFT0M(), lResoKstar.Pt(), lResoKstar.M()); - rRecParticles.fill(HIST("hMCRec"), 1.5); - rRecParticles.fill(HIST("hCentRec"), cent); + } else { + + histos.fill(HIST("hInvmass_KstarME"), collision.centFT0M(), lResoKstar.Pt(), lResoKstar.M()); + } + if constexpr (!IsMix) { + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { + auto rotangle = o2::constants::math::PI; // If there is only one rotation then it should be pi ): + if (nBkgRotations > 1) { + auto anglestart = confMinRot; + auto angleend = confMaxRot; + auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); + rotangle = anglestart + nrotbkg * anglestep; + } + histos.fill(HIST("hRotation"), rotangle); + auto rotpionPx = lDecayDaughter_bach.Px() * std::cos(rotangle) - lDecayDaughter_bach.Py() * std::sin(rotangle); + auto rotpionPy = lDecayDaughter_bach.Px() * std::sin(rotangle) + lDecayDaughter_bach.Py() * std::cos(rotangle); + ROOT::Math::PtEtaPhiMVector pionrot; + pionrot = ROOT::Math::PxPyPzMVector(rotpionPx, rotpionPy, lDecayDaughter_bach.Pz(), massPi); + chargekstarrot = pionrot + lResoSecondary; + if (chargekstarrot.Rapidity() > cKstarMaxRap || chargekstarrot.Rapidity() < cKstarMinRap) + continue; + histos.fill(HIST("hInvmass_KstarRotated"), collision.centFT0M(), chargekstarrot.Pt(), chargekstarrot.M()); + } + } + } + } // K0scand + } // bTrack - float centrality = 0.0f; - auto oldindex = -999; + count++; - for (auto track1 : tracks) { + } // fillHistograms - if (!selectionPID(track1)) - continue; // for primary particle PID + // process data + void processDataSE(EventCandidates::iterator const& collision, + TrackCandidates const& tracks, + V0Candidates const& v0s, + aod::BCsWithTimestamps const&) + { + if (!colCuts.isSelected(collision)) // Default event selection + return; + colCuts.fillQA(collision); + fillHistograms(collision, tracks, v0s); + } + PROCESS_SWITCH(chargedkstaranalysis, processDataSE, "Process Event for data without Partitioning", true); - if (!track1.has_mcParticle()) { - continue; - } + SliceCache cache; + using BinningTypeVertexContributor = ColumnBinningPolicy; + BinningTypeVertexContributor binningOnPositions{{cfgvtxbins, cfgmultbins}, true}; + Pair pair{binningOnPositions, nEvtMixing, -1, &cache}; + void processDataME(EventCandidates const& /*collisions*/, TrackCandidates const& /*tracks*/, V0Candidates const& /*V0s*/) + { + for (auto& [c1, tracks1, c2, tracks2] : pair) { - if (!selectionTrack(track1)) { + if (!colCuts.isSelected(c1)) { continue; } - - auto mctrack1 = track1.mcParticle(); - - if (!mctrack1.isPhysicalPrimary()) { + if (!colCuts.isSelected(c2)) { 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 + for (auto& [t1, t2] : o2::soa::combinations( + o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + // Here t1 corressponds to bachelor track and t2 corressponds to v0s. + if (!isTrackSelected(t1)) 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])) { + if (!trackCut(t1)) continue; - } - - if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0])) { + if (!selectionPIDPion(t1)) continue; - } - if (!SelectionV0(collision, v0, centrality)) { + auto posDauTrack = t2.template posTrack_as(); + auto negDauTrack = t2.template negTrack_as(); + if (!cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) // Perhaps it's already applied in trackCut (need to check QA plots) continue; - } - - auto mctrackv0 = v0.mcParticle(); - - int track1PDG = std::abs(mctrack1.pdgCode()); - // int track2PDG = std::abs(mctrack2.pdgCode()); - int trackv0PDG = std::abs(mctrackv0.pdgCode()); - - if (postrack.globalIndex() == track1.globalIndex()) + if (!cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) continue; - if (negtrack.globalIndex() == track1.globalIndex()) + if (!selectionK0s(c2, t2)) continue; - rRecParticles.fill(HIST("hMCRec"), 2.5); + ROOT::Math::PxPyPzMVector lResoSecondary, lDecayDaughter_bach, lResoKstar; + lDecayDaughter_bach = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massPi); + lResoSecondary = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massK0s); + lResoKstar = lResoSecondary + lDecayDaughter_bach; - if (track1PDG != 211) { + if (lResoKstar.Rapidity() > cKstarMaxRap || lResoKstar.Rapidity() < cKstarMinRap) 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; - } + // process MC reconstructed level + void processMC(MCEventCandidates::iterator const& collision, + MCTrackCandidates const& tracks, + MCV0Candidates const& v0s) + { - rRecParticles.fill(HIST("hMCRec"), 7.5); + // histos.fill(HIST("QAMC/hEvent"), 1.0); - rRecParticles.fill(HIST("hCKSRec"), mothertrack1.pt(), cent); - } - } - } - } - } // track loop ends + fillHistograms(collision, tracks, v0s); } - - PROCESS_SWITCH(chargedkstaranalysis, processGenMC, "Process Gen event", true); - PROCESS_SWITCH(chargedkstaranalysis, processRecMC, "Process Rec event", true); + PROCESS_SWITCH(chargedkstaranalysis, processMC, "Process Event for MC", false); }; - WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; diff --git a/PWGLF/Tasks/Resonances/chk892Flow.cxx b/PWGLF/Tasks/Resonances/chk892Flow.cxx new file mode 100644 index 00000000000..55d2979d103 --- /dev/null +++ b/PWGLF/Tasks/Resonances/chk892Flow.cxx @@ -0,0 +1,1058 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/EndOfStreamContext.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/RotationZ.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include "TVector2.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; +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 + }; + + enum class K0sCut { + DauDCA, // lDauDCA <= cfgSecondaryDauDCAMax + PosDCAtoPVMin, // lDauPosDCAtoPV >= min + NegDCAtoPVMin, // lDauNegDCAtoPV >= min + RadiusWindow, // cfgSecondaryRadiusMin <= lRadius <= cfgSecondaryRadiusMax + DCAtoPVMax, // lDCAtoPV <= max + CPAMin, // lCPA >= min + ProperTauMax, // lPropTauK0s <= max + Armenteros, // qtarm >= param * |alpha| + MassWindow, // |mK0s - m0| <= window + LambdaMassHypo // NOT(lambda-window) + }; + + std::array, 10> hN1NoCut{}; + std::array, 10> hN1Pass{}; + + static constexpr const char* cutTag[] = { + "DauDCA", "PosDCA", "NegDCA", "Radius", "DCAtoPV", "CPA", "Tau", "Arm", "Mass", "LambdaHypo"}; + static constexpr K0sCut kCutsToTest[] = { + K0sCut::DauDCA, K0sCut::PosDCAtoPVMin, K0sCut::NegDCAtoPVMin, + K0sCut::RadiusWindow, K0sCut::DCAtoPVMax, K0sCut::CPAMin, + K0sCut::ProperTauMax, K0sCut::Armenteros, K0sCut::MassWindow, K0sCut::LambdaMassHypo}; + + static constexpr size_t NCuts = sizeof(kCutsToTest) / sizeof(kCutsToTest[0]); + + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + + using EventCandidates = soa::Join; + // using TrackCandidates = soa::Join; + using TrackCandidates = soa::Join; + using V0Candidates = aod::V0Datas; + + // for MC reco + using MCEventCandidates = soa::Join; + using MCTrackCandidates = soa::Join; //, aod::McParticles>; + using MCV0Candidates = soa::Join; + + // for MC truth + using MCTrueEventCandidates = aod::McCollisions; + using MCTrueTrackCandidates = aod::McParticles; + + using LorentzVectorSetXYZM = ROOT::Math::LorentzVector>; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + Service pdg; + + 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"}; + 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"}; + ConfigurableAxis cfgBinsOccu{"cfgBinsOccu", {VARIABLE_WIDTH, 0, 500, 1000, 2500, 9999}, "Binning of the occupancy 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 cfgEvtZvtxMC{"cfgEvtZvtxMC", 10.f, "MC Evt sel: Max z-vertex (cm)"}; + Configurable cfgIsPhysicalPrimaryMC{"cfgIsPhysicalPrimaryMC", true, "Physical primary selection for MC parents"}; + // 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", true, "Apply cut based on the lambda mass hypothesis"}; + + Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", true, "Bypass Daughters PID selection"}; + Configurable cfgByPassDauRapiditySelection{"cfgByPassDauRapiditySelection", false, "Bypass Daughters Rapidity 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 cfgSecondaryDauRapidityMax{"cfgSecondaryDauRapidityMax", 0.3, "Maximum rapidity of Secondary daughters"}; + 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*/ false, /*EventCuts.cfgEvtOccupancyInTimeRangeMin*/ false); + 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 occuAxis = {AxisConfig.cfgBinsOccu, "Occupancy"}; + 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 = {800 / AxisConfig.cNbinsDiv, 0.46, 0.54, "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", "z-vertex distribution", {HistType::kTH1D, {vtxzAxis}}); + histos.add("QA/before/Occupancy", "Occupancy distribution", {HistType::kTH1D, {occuAxis}}); + + // 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}); + + LOG(info) << "Size of the histograms in spectraTOF"; + histos.print(); + } + + // 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, occuAxis}); + histos.add("hInvmass_K0s", "Invariant mass of unlike-sign K0s", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisK0s, v2Axis, phiAxis, occuAxis}); + if (doprocessMC) { + histos.add("hInvmass_Kstar_MC", "Invariant mass of unlike chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis, phiAxis, occuAxis}); + histos.add("hInvmass_K0s_MC", "Invariant mass of unlike K0s", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisReso, v2Axis, phiAxis, occuAxis}); + } + } else { + histos.add("hInvmass_Kstar", "Invariant mass of unlike-sign chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis, occuAxis}); + histos.add("hInvmass_K0s", "Invariant mass of unlike-sign K0s", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisK0s, v2Axis, occuAxis}); + if (doprocessMC) { + histos.add("hInvmass_Kstar_MC", "Invariant mass of unlike chK(892)", HistType::kTHnSparseD, {axisType, centAxis, ptAxis, invMassAxisReso, v2Axis, occuAxis}); + histos.add("hInvmass_K0s_MC", "Invariant mass of unlike K0s", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisK0s, v2Axis, occuAxis}); + } + } + + 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 < EventPlaneConfig.cfgnMods) { + LOG(fatal) << "nMode must be larger than 1, current input (cfgNQvec): " << EventPlaneConfig.cfgNQvec; + } + LOGF(info, "lDetId: %d, lRefAId: %d, lRefBId: %d", lDetId, lRefAId, lRefBId); + + 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(); + } // init + + const int kCentFT0C = 1; + const int kCentFT0M = 2; + const float kInvalidCentrality = -999.f; + + template + float getCentrality(CollisionType const& collision) + { + if (AnalysisConfig.cfgCentEst == kCentFT0C) { + return collision.centFT0C(); + } else if (AnalysisConfig.cfgCentEst == kCentFT0M) { + return collision.centFT0M(); + } else { + return kInvalidCentrality; + } + } + + template + int getlDetId(DetNameType const& 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 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::fabs(candidate.dcapostopv()); + auto lDauNegDCAtoPV = std::fabs(candidate.dcanegtopv()); + auto lPt = candidate.pt(); + auto lRapidity = candidate.yK0Short(); + auto lRadius = candidate.v0radius(); + auto lDCAtoPV = std::fabs(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::fabs(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()) != kPDGK0s) // Is it K0s? + return false; + // Check if K0s's mother is K0 (311) + auto motherK0 = motherkV0.template mothers_as(); + if (std::abs(motherK0.pdgCode()) != kPDGK0) + return false; + + // Check if K0's mother is Kstar (323) + auto motherKstar = motherK0.template mothers_as(); + if (std::abs(motherKstar.pdgCode()) != kKstarPlus) + 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); + } + + LorentzVectorSetXYZM 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 trkpy = posDauTrack.y(); + auto istrkphasTOF = posDauTrack.hasTOF(); + auto trkpNSigmaPiTPC = posDauTrack.tpcNSigmaPi(); + auto trkpNSigmaPiTOF = (istrkphasTOF) ? posDauTrack.tofNSigmaPi() : -999.; + // Negative pion + auto trknpt = negDauTrack.pt(); + auto trkny = negDauTrack.y(); + 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 = LorentzVectorSetXYZM(k0sCand.px(), k0sCand.py(), k0sCand.pz(), trkkMass); + auto lPhiMinusPsiK0s = RecoDecay::constrainAngle(lResoSecondary.Phi() - lEPDet, 0.0, 2); // constrain angle to range 0, Pi + // auto v2K0s = std::cos(static_cast(nmode) * lPhiMinusPsiK0s); + + float cosNPhiK0s = std::cos(static_cast(nmode) * lResoSecondary.Phi()); + float sinNPhiK0s = std::sin(static_cast(nmode) * lResoSecondary.Phi()); + + auto v2K0s = cosNPhiK0s * collision.qvecRe()[lQvecDetInd] + sinNPhiK0s * collision.qvecIm()[lQvecDetInd]; + 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 (!SecondaryCuts.cfgByPassDauRapiditySelection && std::fabs(trkpy) > SecondaryCuts.cfgSecondaryDauRapidityMax) + continue; + if (!SecondaryCuts.cfgByPassDauRapiditySelection && std::fabs(trkny) > SecondaryCuts.cfgSecondaryDauRapidityMax) + 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, collision.trackOccupancyInTimeRange()); + } else { + histos.fill(HIST("hInvmass_K0s"), lCentrality, lResoSecondary.Pt(), lResoSecondary.M(), v2K0s, collision.trackOccupancyInTimeRange()); + } + } + 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); + auto trkkMass = k0sCand.mK0Short(); + + lDecayDaughter_bach = LorentzVectorSetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), MassPionCharged); + lResoSecondary = LorentzVectorSetXYZM(k0sCand.px(), k0sCand.py(), k0sCand.pz(), trkkMass); + 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, collision.trackOccupancyInTimeRange()); + } else { + histos.fill(HIST("hInvmass_Kstar"), typeKstar, lCentrality, lResoKstar.Pt(), lResoKstar.M(), resoFlowValue, collision.trackOccupancyInTimeRange()); + } + + 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; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lDaughterRot + lResoSecondary; + } else { + lDaughterRot = lResoSecondary; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + 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, collision.trackOccupancyInTimeRange()); + } else { + histos.fill(HIST("hInvmass_Kstar"), typeKstar, lCentrality, lResonanceRot.Pt(), lResonanceRot.M(), resoFlowValue, collision.trackOccupancyInTimeRange()); + } + } + } + } // IsMix + + } // k0sCand + } // bTrack + + count++; + + } // fillHistograms + + // process dummy + void processDummy(aod::Collisions const&) + { + } + PROCESS_SWITCH(Chk892Flow, processDummy, "process Dummy", false); + + // 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; + } + float qAmpThr = 1e-4f; + if (AnalysisConfig.cfgQvecSel && (collision.qvecAmp()[lDetId] < qAmpThr || collision.qvecAmp()[lRefAId] < qAmpThr || collision.qvecAmp()[lRefBId] < qAmpThr)) + return; // If we don't have a Q-vector + lCentrality = getCentrality(collision); + // lCentrality = collision.centFT0C(); + 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", true); + + void processMC(aod::McCollisions const&) + { + } + PROCESS_SWITCH(Chk892Flow, processMC, "Process MC for efficiency correction", 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..088d532680d --- /dev/null +++ b/PWGLF/Tasks/Resonances/chk892flow_pp.cxx @@ -0,0 +1,924 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/collisionCuts.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include "TVector2.h" +#include // FIXME +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // FIXME + +#include +#include +#include +#include +#include +#include + +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..fd4e7d8d75d --- /dev/null +++ b/PWGLF/Tasks/Resonances/chk892pp.cxx @@ -0,0 +1,1397 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 , Bong-Hwi Lim + +#include +#include +#include +#include +#include +#include +#include +#include +// #include // FIXME +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/collisionCuts.h" +#include "PWGLF/Utils/inelGt.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/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/RotationZ.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TParticlePDG.h" +#include "TRandom3.h" +#include "TVector2.h" +#include +#include // FIXME + +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +namespace +{ +template +inline bool getTruthK0sAndGenKinematics(V0T const& v0, double& ptgen, double& ygen) +{ + if (!v0.has_mcParticle()) + return false; + auto mcPart = v0.template mcParticle_as(); + if (mcPart.pdgCode() != kK0Short) + return false; + ptgen = mcPart.pt(); + ygen = mcPart.y(); + return true; +} +} // namespace + +struct Chk892pp { + enum BinType : unsigned int { + kKstarP = 0, + kKstarN, + kKstarP_Mix, + kKstarN_Mix, + kKstarP_Rot, + kKstarN_Rot, + kTYEnd + }; + + enum EvtStep { + kAll = 0, + kZvtx, + kINELgt0, + kAssocReco, + kNSteps + }; + + const int nSteps = static_cast(EvtStep::kNSteps); + + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + Preslice perCollisionV0 = aod::v0data::collisionId; + Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; + + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + using V0Candidates = aod::V0Datas; + + // for MC reco + using MCEventCandidates = soa::Join; + using MCTrackCandidates = soa::Join; //, aod::McParticles>; + using MCV0Candidates = soa::Join; + + // for MC truth + using MCTrueEventCandidates = aod::McCollisions; + using MCTrueTrackCandidates = aod::McParticles; + + using LorentzVectorSetXYZM = ROOT::Math::LorentzVector>; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service ccdb; + Service pdg; + 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.8, 1.3, 1.8, 2.3, 2.8, 3.4, 4.0, 5.0, 6.0, 7.0, 8.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"}; + } AxisConfig; + + /// 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", false, "Evt sel: check for offline selection"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", true, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", true, "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", true, "Evt sel: apply NoITSRO border cut"}; + Configurable cfgincludeCentralityMC{"cfgincludeCentralityMC", false, "Include centrality in MC"}; + Configurable cfgEvtCollInTimeRangeStandard{"cfgEvtCollInTimeRangeStandard", false, "Evt sel: apply NoCollInTimeRangeStandard"}; + Configurable cfgEventCentralityMin{"cfgEventCentralityMin", 0.0f, "Event sel: minimum centrality"}; + Configurable cfgEventCentralityMax{"cfgEventCentralityMax", 100.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; + + Configurable cfgFillQAPlots{"cfgFillQAPlots", false, "Fill QA plots"}; + Configurable cfgCentEst{"cfgCentEst", 2, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + /// 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", false, "TOF Veto, if false, TOF is nessessary for PID selection"}; // TOF Veto + Configurable cfgTOFMinPt{"cfgTOFMinPt", 0.6, "Minimum TOF pT cut for Pion"}; // TOF pT cut + } PIDCuts; + + // Track selections + struct : ConfigurableGroup { + Configurable cfgMinPtcut{"cfgMinPtcut", 0.15, "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", true, "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"}; + // DCAr to PV + Configurable cfgMaxbDCArToPVcut{"cfgMaxbDCArToPVcut", 0.1, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + 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", 1., "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, "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 selciton 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; + + // 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", 4, "Number of rotated copies (background) per each original candidate"}; + } BkgEstimationConfig; + + Configurable cfgTruthUseInelGt0{"cfgTruthUseInelGt0", true, "Truth denominator: require INEL>0"}; + Configurable cfgTruthIncludeZvtx{"cfgTruthIncludeZvtx", true, "Truth denominator: also require |vtxz|(HIST("QA/K0sCutFlow")); + hcut->GetXaxis()->SetBinLabel(1, "TOTAL"); + hcut->GetXaxis()->SetBinLabel(2, "PASS"); + hcut->GetXaxis()->SetBinLabel(3, "DauDCA>max"); + hcut->GetXaxis()->SetBinLabel(4, "PosDCAtoPVGetXaxis()->SetBinLabel(5, "NegDCAtoPVGetXaxis()->SetBinLabel(6, "pTGetXaxis()->SetBinLabel(7, "|y|>max"); + hcut->GetXaxis()->SetBinLabel(8, "Rmax"); + hcut->GetXaxis()->SetBinLabel(9, "DCAtoPV>max"); + hcut->GetXaxis()->SetBinLabel(10, "cosPAGetXaxis()->SetBinLabel(11, "ctau>max"); + hcut->GetXaxis()->SetBinLabel(12, "qtarmGetXaxis()->SetBinLabel(13, "|M(K0s)-m0|>win"); + hcut->GetXaxis()->SetBinLabel(14, "cross-mass veto"); + + 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}}); + + 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/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}); + histos.add("hInvmass_K0s", "Invariant mass of unlike-sign K0s", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisK0s}); + + // 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("QACent_woCut", "Centrality without cut", HistType::kTH1F, {centAxis}); + histos.add("QACent_woCentCut", "Centrality without cent cut", HistType::kTH1F, {centAxis}); + histos.add("QACent_wCentCut", "Centrality with cent cut", HistType::kTH1F, {centAxis}); + histos.add("QAvtxz_woCut", "z-vertex without cut", HistType::kTH1F, {vtxzAxis}); + histos.add("QAvtxz_wVtxzCut", "z-vertex with vtxz cut", HistType::kTH1F, {vtxzAxis}); + + histos.add("EffK0s/genK0s", "Gen K0s (|y<0.8|)", HistType::kTH2F, {ptAxisQA, centAxis}); + histos.add("EffK0s/recoK0s", "Reco K0s (|y<0.8|)", HistType::kTH2F, {ptAxisQA, centAxis}); + + histos.add("EffKstar/genKstar", "Gen Kstar (|y|<0.5)", HistType::kTH2F, {ptAxisQA, centAxis}); + histos.add("EffKstar/recoKstar", "Kstar Reco matched (final all)", HistType::kTH2F, {ptAxisQA, centAxis}); + + histos.add("Correction/sigLoss_den", "Gen Kstar (|y|<0.5) in truth class", HistType::kTH2F, {ptAxisQA, centAxis}); + histos.add("Correction/sigLoss_num", "Gen Kstar (|y|<0.5, selected events) in reco class", HistType::kTH2F, {ptAxisQA, centAxis}); + histos.add("Correction/EF_den", "Gen events (truth class)", HistType::kTH1F, {centAxis}); + histos.add("Correction/EF_num", "Reco events (selected events)", HistType::kTH1F, {centAxis}); + histos.add("Correction/MCTruthCent_all", "MC truth FT0M centrality (all mcCollisions)", HistType::kTH1F, {centAxis}); + histos.add("Correction/MCTruthCent_cut", "MC truth FT0M centrality (truth selection applied)", HistType::kTH1F, {centAxis}); + + histos.add("Correction/setSizes", "Sizes of sets", HistType::kTH1F, {{4, -0.5, 3.5}}); + auto hset = histos.get(HIST("Correction/setSizes")); + hset->GetXaxis()->SetBinLabel(1, "refClassIds"); + hset->GetXaxis()->SetBinLabel(2, "allowedMcIds"); + hset->GetXaxis()->SetBinLabel(3, "intersection"); + hset->GetXaxis()->SetBinLabel(4, "allowed-only"); + + histos.add("Correction/hNEventsMCTruth", "hNEventsMCTruth", HistType::kTH1F, {AxisSpec{nSteps, 0.5, nSteps + 0.5, ""}}); + auto hstep = histos.get(HIST("Correction/hNEventsMCTruth")); + hstep->GetXaxis()->SetBinLabel(1, "All"); + hstep->GetXaxis()->SetBinLabel(2, "zvtx"); + hstep->GetXaxis()->SetBinLabel(3, "INEL>0"); + hstep->GetXaxis()->SetBinLabel(4, "Assoc with reco coll"); + + histos.add("MCReco/hInvmass_Kstar_true", "MC-reco truth-tagged chK(892)", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisReso}); + histos.add("MCReco/hInvmass_Kstar_bkg", "MC-reco residual background chK(892)", HistType::kTHnSparseD, {centAxis, ptAxis, invMassAxisReso}); + } + + 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(); + } + + const int kCentFT0C = 1; + const int kCentFT0M = 2; + const float kInvalidCentrality = -999.f; + + template + float getCentrality(CollisionType const& collision) + { + if (cfgCentEst == kCentFT0C) { + return collision.centFT0C(); + } else if (cfgCentEst == kCentFT0M) { + return collision.centFT0M(); + } else { + return kInvalidCentrality; + } + } + + // 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) + { + if (std::abs(candidate.tpcNSigmaPi()) >= PIDCuts.cfgMaxTPCnSigmaPion) + return false; + if (PIDCuts.cfgTPConly) + return true; + if (candidate.pt() <= PIDCuts.cfgTOFMinPt) + return true; + + if (candidate.hasTOF()) { + const bool tofPIDPassed = std::abs(candidate.tofNSigmaPi()) < PIDCuts.cfgMaxTOFnSigmaPion; + const bool combo = (PIDCuts.cfgNsigmaCutCombinedPion > 0) && + (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + + candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < + PIDCuts.cfgNsigmaCutCombinedPion * PIDCuts.cfgNsigmaCutCombinedPion); + return tofPIDPassed || combo; + } else { + return PIDCuts.cfgTOFVeto; + } + } + + template + bool selectionK0s(CollisionType const& collision, K0sType const& candidate) + { + auto lDauDCA = std::fabs(candidate.dcaV0daughters()); + auto lDauPosDCAtoPV = std::fabs(candidate.dcapostopv()); + auto lDauNegDCAtoPV = std::fabs(candidate.dcanegtopv()); + auto lPt = candidate.pt(); + auto lRapidity = candidate.yK0Short(); + auto lRadius = candidate.v0radius(); + auto lDCAtoPV = std::fabs(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 (std::fabs(lDauDCA) > SecondaryCuts.cfgSecondaryDauDCAMax) + return false; + if (std::fabs(lDauPosDCAtoPV) < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin) + return false; + if (std::fabs(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 (std::fabs(lDCAtoPV) > SecondaryCuts.cfgSecondaryDCAtoPVMax) + return false; + if (lCPA < SecondaryCuts.cfgSecondaryCosPAMin) + return false; + if (lPropTauK0s > SecondaryCuts.cfgSecondaryProperLifetimeMax) + return false; + if (candidate.qtarm() < SecondaryCuts.cfgSecondaryparamArmenterosCut * std::fabs(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::fabs(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()) != kPDGK0s) // Is it K0s? + return false; + // Check if K0s's mother is K0 (311) + auto motherK0 = motherkV0.template mothers_as(); + if (std::abs(motherK0.pdgCode()) != kPDGK0) + return false; + + // Check if K0's mother is Kstar (323) + auto motherKstar = motherK0.template mothers_as(); + if (std::abs(motherKstar.pdgCode()) != kKstarPlus) + return false; + + // Check if bTrack and K0 have the same mother (global index) + if (motherbTrack.globalIndex() != motherK0.globalIndex()) + return false; + + return true; + } + + std::unordered_set allowedMcIds; + std::unordered_map centTruthByAllowed; + std::unordered_set refClassIds; + std::unordered_map refCentByMcId; + + template + void buildAllowedMcIds(RecoEventsT const& events) + { + allowedMcIds.clear(); + centTruthByAllowed.clear(); + + for (const auto& coll : events) { + // lCentrality = getCentrality(coll); + + if (!coll.has_mcCollision()) + continue; + + const auto mcid = coll.mcCollisionId(); + const auto mccoll = coll.template mcCollision_as>(); + + const float lCentrality = mccoll.centFT0M(); + + if (doprocessMC) { + histos.fill(HIST("QACent_woCut"), lCentrality); + histos.fill(HIST("QAvtxz_woCut"), coll.posZ()); + } + + if (!colCuts.isSelected(coll)) + continue; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(coll)) + continue; + if (!coll.isInelGt0()) + continue; + + if (doprocessMC) { + histos.fill(HIST("QACent_woCentCut"), lCentrality); + histos.fill(HIST("QAvtxz_wVtxzCut"), coll.posZ()); + } + + if (lCentrality < EventCuts.cfgEventCentralityMin || lCentrality > EventCuts.cfgEventCentralityMax) + continue; + + if (doprocessMC) { + histos.fill(HIST("QACent_wCentCut"), lCentrality); + } + allowedMcIds.insert(mcid); + centTruthByAllowed.emplace(mcid, lCentrality); + } + } + + template + void buildReferenceMcIds(McCollsT const& mccolls, McPartsT const& mcparts) + { + refClassIds.clear(); + refCentByMcId.clear(); + + for (const auto& coll : mccolls) { + bool pass = true; + + if (cfgTruthIncludeZvtx && std::abs(coll.posZ()) >= EventCuts.cfgEvtZvtx) + pass = false; + + if (pass && cfgTruthUseInelGt0) { + auto partsThisMc = mcparts.sliceBy(perMCCollision, coll.globalIndex()); + if (!pwglf::isINELgtNmc(partsThisMc, 0, pdg)) + pass = false; + } + + if (!pass) + continue; + + const auto mcid = coll.globalIndex(); + refClassIds.insert(mcid); + const float lCentrality = coll.centFT0M(); + refCentByMcId.emplace(mcid, lCentrality); + } + } + + void effK0sProcessGen(MCTrueTrackCandidates const& mcparts) + { + for (const auto& part : mcparts) { + if (!part.has_mcCollision()) + continue; + if (part.pdgCode() != kPDGK0s) + continue; + if (!part.isPhysicalPrimary()) + continue; + if (std::abs(part.y()) > SecondaryCuts.cfgSecondaryRapidityMax) + continue; + + const auto mcid = part.mcCollisionId(); + if (allowedMcIds.count(mcid) == 0) + continue; + + auto iter = centTruthByAllowed.find(mcid); + if (iter == centTruthByAllowed.end()) + continue; + + const float lCentrality = iter->second; + + histos.fill(HIST("EffK0s/genK0s"), part.pt(), lCentrality); + } + } + + void effK0sProcessReco(MCV0Candidates const& v0s) + { + for (const auto& v0 : v0s) { + auto coll = v0.template collision_as(); + + if (!coll.has_mcCollision()) + continue; + + const auto mcid = coll.mcCollisionId(); + + if (allowedMcIds.count(mcid) == 0) + continue; + + const auto mccoll = coll.template mcCollision_as>(); + const float lCentrality = mccoll.centFT0M(); + + const double ptreco = v0.pt(); + const double yreco = v0.yK0Short(); + + double ptgen = -1, ygen = 0; + if (!getTruthK0sAndGenKinematics(v0, ptgen, ygen)) + continue; + if (std::abs(yreco) > SecondaryCuts.cfgSecondaryRapidityMax) + continue; + + if (!SecondaryCuts.cfgByPassDauPIDSelection) { + auto posDauTrack = v0.template posTrack_as(); + auto negDauTrack = v0.template negTrack_as(); + if (!selectionPIDPion(posDauTrack)) + continue; + if (!selectionPIDPion(negDauTrack)) + continue; + } + if (!selectionK0s(coll, v0)) + continue; + + histos.fill(HIST("EffK0s/recoK0s"), ptreco, lCentrality); + } + } // effK0sProcessReco + + template + bool matchRecoToTruthKstar(V0T const& v0, TrkT const& trk, double& ptgen, double& ygen) + { + if (!v0.has_mcParticle() || !trk.has_mcParticle()) + return false; + + auto mcK0s = v0.template mcParticle_as(); + auto mcPi = trk.template mcParticle_as(); + + if (std::abs(mcK0s.pdgCode()) != kPDGK0s) + return false; + if (std::abs(mcPi.pdgCode()) != kPiPlus) + return false; + + MCTrueTrackCandidates::iterator kstarFromPi; + bool havePiKstar = false; + for (const auto& m1 : mcPi.template mothers_as()) { + if (std::abs(m1.pdgCode()) == kKstarPlus) { + kstarFromPi = m1; + havePiKstar = true; + break; + } + } + if (!havePiKstar) { + return false; + } + + bool shareSameKstar = false; + for (const auto& m1 : mcK0s.template mothers_as()) { + if (std::abs(m1.pdgCode()) == kPDGK0) { + for (const auto& m2 : m1.template mothers_as()) { + if (m2.globalIndex() == kstarFromPi.globalIndex()) { + shareSameKstar = true; + break; + } + } + if (shareSameKstar) + break; + } + } + if (!shareSameKstar) { + return false; + } + + ptgen = kstarFromPi.pt(); + ygen = kstarFromPi.y(); + + return true; + } // matchRecoToTruthKstar + + void effKstarProcessGen(MCTrueTrackCandidates const& mcparts) + { + for (const auto& part : mcparts) { + if (!part.has_mcCollision()) + continue; + if (std::abs(part.pdgCode()) != kKstarPlus) + continue; + if (std::abs(part.y()) > KstarCuts.cfgKstarMaxRap) + continue; + + const auto mcid = part.mcCollisionId(); + if (allowedMcIds.count(mcid) == 0) + continue; + + auto iter = centTruthByAllowed.find(mcid); + if (iter == centTruthByAllowed.end()) + continue; + + const float lCentrality = iter->second; + + histos.fill(HIST("EffKstar/genKstar"), part.pt(), lCentrality); + } + } // effKstarProcessGen + + template + void effKstarProcessReco(V0RangeT const& v0s, TrkRangeT const& tracks) + { + for (const auto& v0 : v0s) { + auto coll = v0.template collision_as(); + + if (!coll.has_mcCollision()) + continue; + + const auto mcid = coll.mcCollisionId(); + + if (allowedMcIds.count(mcid) == 0) + continue; + + const auto mccoll = coll.template mcCollision_as>(); + const float lCentrality = mccoll.centFT0M(); + + if (!SecondaryCuts.cfgByPassDauPIDSelection) { + auto posDauTrack = v0.template posTrack_as(); + auto negDauTrack = v0.template negTrack_as(); + if (!selectionPIDPion(posDauTrack)) + continue; + if (!selectionPIDPion(negDauTrack)) + continue; + } + if (!selectionK0s(coll, v0)) + continue; + + auto trks = tracks.sliceBy(perCollision, v0.collisionId()); + for (const auto& bTrack : trks) { + if (bTrack.collisionId() != v0.collisionId()) + continue; + if (!trackCut(bTrack)) + continue; + if (!selectionPIDPion(bTrack)) + continue; + + LorentzVectorSetXYZM lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot, lResonanceRot; + + lResoSecondary = LorentzVectorSetXYZM(v0.px(), v0.py(), v0.pz(), v0.mK0Short()); + lDecayDaughter_bach = LorentzVectorSetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), MassPionCharged); + lResoKstar = lResoSecondary + lDecayDaughter_bach; + + const double ptreco = lResoKstar.Pt(); + const double yreco = lResoKstar.Rapidity(); + + if (std::abs(yreco) > KstarCuts.cfgKstarMaxRap) + continue; + + double ptgen = 0, ygen = 0; + const bool isTrue = matchRecoToTruthKstar(v0, bTrack, ptgen, ygen); + + if (isTrue) { + + histos.fill(HIST("EffKstar/recoKstar"), ptreco, lCentrality); + histos.fill(HIST("MCReco/hInvmass_Kstar_true"), lCentrality, ptreco, lResoKstar.M()); + + } else { + histos.fill(HIST("MCReco/hInvmass_Kstar_bkg"), lCentrality, ptreco, lResoKstar.M()); + } + } + } + } // effKstarProcessReco + + void fillSigLossNum(MCTrueTrackCandidates const& mcparts) + { + for (auto const& part : mcparts) { + if (!part.has_mcCollision()) + continue; + if (std::abs(part.pdgCode()) != kKstarPlus) + continue; + if (std::abs(part.y()) > KstarCuts.cfgKstarMaxRap) + continue; + + const auto mcid = part.mcCollisionId(); + if (allowedMcIds.count(mcid) == 0) + continue; + + auto iter = centTruthByAllowed.find(mcid); + if (iter == centTruthByAllowed.end()) + continue; + + const float lCentrality = iter->second; + + histos.fill(HIST("Correction/sigLoss_num"), part.pt(), lCentrality); + } + } // fillSigLossNum + + void fillSigLossDen(MCTrueTrackCandidates const& mcparts) + { + for (auto const& part : mcparts) { + if (!part.has_mcCollision()) + continue; + if (std::abs(part.pdgCode()) != kKstarPlus) + continue; + if (std::abs(part.y()) > KstarCuts.cfgKstarMaxRap) + continue; + + const auto mcid = part.mcCollisionId(); + if (refClassIds.count(mcid) == 0) + continue; + + auto iter = refCentByMcId.find(mcid); + if (iter == refCentByMcId.end()) + continue; + + const float lCentrality = iter->second; + + histos.fill(HIST("Correction/sigLoss_den"), part.pt(), lCentrality); + } + } // fillSigLossDen + + int count = 0; + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksTypeK0s& dTracks2) + { + using TrackTarget = std::decay_t; + + histos.fill(HIST("QA/before/CentDist"), lCentrality); + + LorentzVectorSetXYZM 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 (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 (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(); + auto trkkDauDCAPostoPV = k0sCand.dcapostopv(); + auto trkkDauDCANegtoPV = k0sCand.dcanegtopv(); + auto trkkpt = k0sCand.pt(); + auto trkkRadius = k0sCand.v0radius(); + + lResoSecondary = LorentzVectorSetXYZM(k0sCand.px(), k0sCand.py(), k0sCand.pz(), trkkMass); + + if constexpr (!IsMix) { + if (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/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 (!SecondaryCuts.cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) + continue; + if (!SecondaryCuts.cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) + continue; + if (!selectionK0s(collision, k0sCand)) + continue; + + if constexpr (!IsMix) { + if (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/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); + } + histos.fill(HIST("hInvmass_K0s"), lCentrality, lResoSecondary.Pt(), lResoSecondary.M()); + } + k0sIndicies.push_back(k0sCand.index()); + } + + for (const auto& trackIndex : trackIndicies) { + auto bTrack = dTracks1.rawIteratorAt(trackIndex); + for (const auto& k0sIndex : k0sIndicies) { + auto k0sCand = dTracks2.rawIteratorAt(k0sIndex); + + auto trkkMass = k0sCand.mK0Short(); + + lDecayDaughter_bach = LorentzVectorSetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), MassPionCharged); + lResoSecondary = LorentzVectorSetXYZM(k0sCand.px(), k0sCand.py(), k0sCand.pz(), trkkMass); + lResoKstar = lResoSecondary + lDecayDaughter_bach; + + // QA plots + if constexpr (!IsMix) { + if (cfgFillQAPlots) { + histos.fill(HIST("QA/before/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/before/kstarinvmass"), lResoKstar.M()); + } + } + + if (lResoKstar.Rapidity() > KstarCuts.cfgKstarMaxRap || lResoKstar.Rapidity() < KstarCuts.cfgKstarMinRap) + continue; + + if constexpr (!IsMix) { + unsigned int typeKstar = bTrack.sign() > 0 ? BinType::kKstarP : BinType::kKstarN; + if (cfgFillQAPlots) { + + histos.fill(HIST("QA/after/KstarRapidity"), lResoKstar.Rapidity()); + histos.fill(HIST("QA/after/kstarinvmass"), lResoKstar.M()); + } + histos.fill(HIST("hInvmass_Kstar"), typeKstar, lCentrality, lResoKstar.Pt(), lResoKstar.M()); + + if (BkgEstimationConfig.cfgFillRotBkg) { + for (int i = 0; i < BkgEstimationConfig.cfgNrotBkg; i++) { + auto lRotAngle = BkgEstimationConfig.cfgMinRot + i * ((BkgEstimationConfig.cfgMaxRot - BkgEstimationConfig.cfgMinRot) / (BkgEstimationConfig.cfgNrotBkg - 1)); + if (cfgFillQAPlots) { + histos.fill(HIST("QA/RotBkg/hRotBkg"), lRotAngle); + } + if (BkgEstimationConfig.cfgRotPion) { + lDaughterRot = lDecayDaughter_bach; + // lDaughterRot.RotateZ(lRotAngle); + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lDaughterRot + lResoSecondary; + } else { + lDaughterRot = lResoSecondary; + // lDaughterRot.RotateZ(lRotAngle); + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lDecayDaughter_bach + lDaughterRot; + } + typeKstar = bTrack.sign() > 0 ? BinType::kKstarP_Rot : BinType::kKstarN_Rot; + histos.fill(HIST("hInvmass_Kstar"), typeKstar, lCentrality, lResonanceRot.Pt(), lResonanceRot.M()); + } + } + } // IsMix + } // K0scand + } // bTrack + + count++; + + } // fillHistograms + + 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; + } + lCentrality = getCentrality(collision); + if (lCentrality < EventCuts.cfgEventCentralityMin || lCentrality > EventCuts.cfgEventCentralityMax) + return; + if (!collision.isInelGt0()) + return; + colCuts.fillQA(collision); + + fillHistograms(collision, tracks, v0s); + } + PROCESS_SWITCH(Chk892pp, processData, "Process Event for data without Partitioning", false); + + void processMC(MCTrueTrackCandidates const& mcpart, + MCTrackCandidates const& tracks, + MCV0Candidates const& v0s, + MCEventCandidates const& events, + soa::Join const& mccolls) + { + buildAllowedMcIds(events); + buildReferenceMcIds(mccolls, mcpart); + effK0sProcessGen(mcpart); + effK0sProcessReco(v0s); + effKstarProcessGen(mcpart); + effKstarProcessReco(v0s, tracks); + fillSigLossNum(mcpart); + fillSigLossDen(mcpart); + + for (const auto& mcid : refClassIds) { + histos.fill(HIST("Correction/EF_den"), refCentByMcId[mcid]); + } + for (const auto& mcid : allowedMcIds) { + auto iter = centTruthByAllowed.find(mcid); + if (iter == centTruthByAllowed.end()) + continue; + + const float lCentrality = iter->second; + histos.fill(HIST("Correction/EF_num"), lCentrality); + } + + size_t nIntersect = 0; + for (const auto& mcid : allowedMcIds) + if (refClassIds.count(mcid)) + nIntersect++; + histos.fill(HIST("Correction/setSizes"), 0.0, refClassIds.size()); + histos.fill(HIST("Correction/setSizes"), 1.0, allowedMcIds.size()); + histos.fill(HIST("Correction/setSizes"), 2.0, nIntersect); + histos.fill(HIST("Correction/setSizes"), 3.0, allowedMcIds.size() - nIntersect); + + for (const auto& mcc : mccolls) { + histos.fill(HIST("Correction/MCTruthCent_all"), mcc.centFT0M()); + } + + for (const auto& mcid : refClassIds) { + auto iter = refCentByMcId.find(mcid); + if (iter == refCentByMcId.end()) + continue; + lCentrality = iter->second; + histos.fill(HIST("Correction/MCTruthCent_cut"), lCentrality); + } + + for (auto const& mcc : mccolls) { + const auto mcid = mcc.globalIndex(); + + histos.fill(HIST("Correction/hNEventsMCTruth"), 1.0); + + bool passZvtx = true; + if (cfgTruthIncludeZvtx && std::abs(mcc.posZ()) > EventCuts.cfgEvtZvtx) { + passZvtx = false; + } + if (passZvtx) { + histos.fill(HIST("Correction/hNEventsMCTruth"), 2.0); + + auto partsThisMc = mcpart.sliceBy(perMCCollision, mcid); + if (pwglf::isINELgtNmc(partsThisMc, 0, pdg)) { + histos.fill(HIST("Correction/hNEventsMCTruth"), 3.0); + } + } + if (allowedMcIds.count(mcid)) { + histos.fill(HIST("Correction/hNEventsMCTruth"), 4.0); + } + } + } + PROCESS_SWITCH(Chk892pp, processMC, "Process Event for MC", true); + + void processMCQA(MCEventCandidates::iterator const& collision, + MCTrackCandidates const& tracks, + MCV0Candidates const& v0s, + soa::Join const& mccolls, + aod::BCsWithTimestamps const&) + { + if (!colCuts.isSelected(collision)) + return; + if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) + return; + if (!collision.isInelGt0()) + return; + + if (!collision.has_mcCollision()) + return; + + auto id = collision.mcCollisionId(); + + auto mccoll = mccolls.iteratorAt(id); + const float lCentrality = mccoll.centFT0M(); + + if (lCentrality < EventCuts.cfgEventCentralityMin || lCentrality > EventCuts.cfgEventCentralityMax) + return; + colCuts.fillQA(collision); + + fillHistograms(collision, tracks, v0s); + } + PROCESS_SWITCH(Chk892pp, processMCQA, "Process Event for MC and fill QA plots", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/cksspinalignder.cxx b/PWGLF/Tasks/Resonances/cksspinalignder.cxx new file mode 100644 index 00000000000..ae29ab6a6fc --- /dev/null +++ b/PWGLF/Tasks/Resonances/cksspinalignder.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 cksspinalignder.cxx +/// \brief Analysis task for ChargedKStar spin alignment +/// +/// \author prottay.das@cern.ch + +#include "PWGLF/DataModel/LFCKSSpinalignmentTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include + +#include +#include +#include +#include + +#include + +#include // for std::fabs +#include +// #include +#include +#include // <<< CHANGED: for dedup sets +#include +#include +#include +#include // <<< CHANGED: for seenMap +#include +#include + +// o2 includes. +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct cksspinalignder { + + struct : ConfigurableGroup { + 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"}; + } cfgCcdbParam; + + // event sel///////// + Configurable centMin{"centMin", 0, "Minimum Centrality"}; + Configurable centMax{"centMax", 80, "Maximum Centrality"}; + // V0 selection //////////// + Configurable cosPA{"cosPA", 0.995, "Cosine Pointing Angle"}; + Configurable radiusMin{"radiusMin", 1.2, "Minimum V0 radius"}; + Configurable radiusMax{"radiusMax", 100, "Maximum V0 radius"}; + Configurable dcaPion{"dcaPion", 0.1, "DCA Pion"}; + Configurable dcaDaughters{"dcaDaughters", 1.0, "DCA between daughters"}; + Configurable lifetimeMax{"lifetimeMax", 20, "Maximum V0 lifetime"}; + Configurable ptMin{"ptMin", 0.5, "V0 Pt minimum"}; + Configurable ptMax{"ptMax", 10.0, "V0 Pt maximum"}; + Configurable v0eta{"v0eta", 0.8, "Eta cut on lambda"}; + // pion sel///////// + Configurable nsigmaCutTPC{"nsigmaCutTPC", 3.0, "N sigma TPC cut for bachelor pions"}; + Configurable nsigmaCutTOF{"nsigmaCutTOF", 3.0, "N sigma TOF cut for bachelor pions"}; + Configurable usePID{"usePID", false, "Flag for using PID selection"}; + + // Event Mixing + Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgMultBins{"cfgMultBins", {8, 0.0, 80}, "Mixing bins - centrality"}; + + // THnsparse bining + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {50, 1.09, 1.14}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.0, 10.0}, "#it{p}_{T}"}; + ConfigurableAxis configThnAxisSA{"configThnAxisSA", {20, -1.0, 1.0}, "cos#it{#theta *}"}; + ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {8, 0.0, 80.0}, "Centrality"}; + + // 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}; + + void init(o2::framework::InitContext&) + { + + histos.add("hCentrality", "Centrality distribution", kTH1F, {{80, 0, 80}}); + histos.add("hKShortMass", "hKShortMass", kTH1F, {{100, 0.45, 0.55}}); + + histos.add("hSparsesame", "hSparsesame", kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisSA, configThnAxisCentrality}); + histos.add("hSparsemix", "hSparsemix", kTHnSparseF, {configThnAxisInvMass, configThnAxisPt, configThnAxisSA, configThnAxisCentrality}); + + 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()); + } + + template + bool selectionV0(T const& candidate) + { + auto kshortPt = std::sqrt(candidate.kShortPx() * candidate.kShortPx() + candidate.kShortPy() * candidate.kShortPy()); + auto px = candidate.kShortPx(); + auto py = candidate.kShortPy(); + auto pz = candidate.kShortPz(); + auto p = std::sqrt(px * px + py * py + pz * pz); + auto kshortEta = 0.5 * std::log((p + pz) / (p - pz)); + + if (std::abs(kshortEta) > v0eta) { + return false; + } + if (candidate.v0Cospa() < cosPA) { + return false; + } + if (candidate.v0Radius() > radiusMax) { + return false; + } + if (candidate.v0Radius() < radiusMin) { + return false; + } + if (candidate.dcaBetweenDaughter() > dcaDaughters) { + return false; + } + if (std::abs(candidate.dcaPositive()) < dcaPion && std::abs(candidate.dcaNegative()) < dcaPion) { + return false; + } + if (candidate.v0Lifetime() > lifetimeMax) { + return false; + } + if (kshortPt < ptMin) { + return false; + } + if (kshortPt > ptMax) { + return false; + } + return true; + } + + template + bool selectionPID(const T& candidate) + { + auto px = candidate.pionBachPx(); + auto py = candidate.pionBachPy(); + auto pz = candidate.pionBachPz(); + auto p = std::sqrt(px * px + py * py + pz * pz); + float lowmom = 0.5; + if (p < lowmom) { + if (!candidate.pionBachTOFHit() && std::abs(candidate.pionBachTPC()) < nsigmaCutTPC) { + return true; + } else if (candidate.pionBachTOFHit() && std::sqrt(candidate.pionBachTPC() * candidate.pionBachTPC() + candidate.pionBachTOF() * candidate.pionBachTOF()) < nsigmaCutTOF) { + return true; + } + } else if (candidate.pionBachTOFHit() && std::sqrt(candidate.pionBachTPC() * candidate.pionBachTPC() + candidate.pionBachTOF() * candidate.pionBachTOF()) < nsigmaCutTOF) { + return true; + } + return false; + } + + std::tuple computePtEtaPhi(float px, float py, float pz) + { + float pt = std::sqrt(px * px + py * py); + float p = std::sqrt(px * px + py * py + pz * pz); + float eta = (p != std::abs(pz)) ? 0.5 * std::log((p + pz) / (p - pz)) : 0.0f; // avoid division by zero + float phi = RecoDecay::constrainAngle(std::atan2(py, px)); + return {pt, eta, phi}; + } + + ROOT::Math::PtEtaPhiMVector kshort, pion, chkstar; + ROOT::Math::PtEtaPhiMVector kshortmix, pionmix, chkstarmix; + ROOT::Math::PxPyPzMVector fourVecDauCM, fourVecDauCMmix; + ROOT::Math::XYZVector threeVecDauCM, eventplaneVecNorm, threeVecDauCMmix, eventplaneVecNormmix; + + Filter centralityFilter = (nabs(aod::kshortpionevent::cent) < centMax && nabs(aod::kshortpionevent::cent) > centMin); + + using EventCandidates = soa::Filtered; + + void processSameData(EventCandidates::iterator const& collision, aod::KShortTracks const& V0s, aod::PionTracks const& piontracks) + { + auto centrality = collision.cent(); + histos.fill(HIST("hCentrality"), centrality); + + auto psiFT0C = collision.psiFT0C(); + + for (const auto& v0 : V0s) { + if (!selectionV0(v0)) { + continue; + } + auto [kshortPt, kshortEta, kshortPhi] = computePtEtaPhi(v0.kShortPx(), v0.kShortPy(), v0.kShortPz()); + kshort = ROOT::Math::PtEtaPhiMVector(kshortPt, kshortEta, kshortPhi, v0.kShortMass()); + histos.fill(HIST("hKShortMass"), kshort.M()); + + for (const auto& piontrack : piontracks) { + auto [pionPt, pionEta, pionPhi] = computePtEtaPhi(piontrack.pionBachPx(), piontrack.pionBachPy(), piontrack.pionBachPz()); + pion = ROOT::Math::PtEtaPhiMVector(pionPt, pionEta, pionPhi, o2::constants::physics::MassPionCharged); + + if (piontrack.pionBachIndex() == v0.pionIndex1() || piontrack.pionBachIndex() == v0.pionIndex2()) + continue; // checking if bachelor pion is khort daughter or not -> skip further processing if such is the case + + if (usePID && !selectionPID(piontrack)) + continue; // checking PID + + chkstar = kshort + pion; + + ROOT::Math::Boost boost{chkstar.BoostToCM()}; + fourVecDauCM = boost(kshort); + threeVecDauCM = fourVecDauCM.Vect(); + eventplaneVecNorm = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0C), -std::cos(2.0 * psiFT0C), 0); + auto cosThetaStar = eventplaneVecNorm.Dot(threeVecDauCM) / std::sqrt(threeVecDauCM.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); + + histos.fill(HIST("hSparsesame"), chkstar.M(), chkstar.Pt(), cosThetaStar, centrality); + } + } + } + PROCESS_SWITCH(cksspinalignder, processSameData, "Process same data", true); + + // Processing Event Mixing + SliceCache cache; + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{cfgVtxBins, cfgMultBins}, true}; + Preslice tracksPerCollisionV0 = aod::kshortpionpair::kshortpioneventId; + Preslice tracksPerCollisionBach = aod::kshortpionpair::kshortpioneventId; + + void processMixedData(EventCandidates const& collisions, aod::KShortTracks const& V0s, aod::PionTracks const& piontracks) + { + for (const auto& [collision1, collision2] : selfCombinations(colBinning, nEvtMixing, -1, collisions, collisions)) { + if (collision1.index() == collision2.index()) { + continue; + } + auto centrality = collision1.cent(); + auto psiFT0Cmix = collision1.psiFT0C(); + + auto groupV0 = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + auto groupPion = piontracks.sliceBy(tracksPerCollisionBach, collision2.index()); + for (const auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV0, groupPion))) { + if (!selectionV0(t1)) + continue; + auto [kshortPtmix, kshortEtamix, kshortPhimix] = computePtEtaPhi(t1.kShortPx(), t1.kShortPy(), t1.kShortPz()); + kshortmix = ROOT::Math::PtEtaPhiMVector(kshortPtmix, kshortEtamix, kshortPhimix, t1.kShortMass()); + + auto [pionPtmix, pionEtamix, pionPhimix] = computePtEtaPhi(t2.pionBachPx(), t2.pionBachPy(), t2.pionBachPz()); + if (usePID && !selectionPID(t2)) + continue; // checking PID + pionmix = ROOT::Math::PtEtaPhiMVector(pionPtmix, pionEtamix, pionPhimix, o2::constants::physics::MassPionCharged); + + chkstarmix = kshortmix + pionmix; + + ROOT::Math::Boost boost{chkstarmix.BoostToCM()}; + fourVecDauCMmix = boost(kshortmix); + threeVecDauCMmix = fourVecDauCMmix.Vect(); + eventplaneVecNormmix = ROOT::Math::XYZVector(std::sin(2.0 * psiFT0Cmix), -std::cos(2.0 * psiFT0Cmix), 0); + auto cosThetaStarmix = eventplaneVecNormmix.Dot(threeVecDauCMmix) / std::sqrt(threeVecDauCMmix.Mag2()) / std::sqrt(eventplaneVecNormmix.Mag2()); + + histos.fill(HIST("hSparsemix"), chkstarmix.M(), chkstarmix.Pt(), cosThetaStarmix, centrality); + } + } + } + PROCESS_SWITCH(cksspinalignder, processMixedData, "Process mixed data", true); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/deltaanalysis.cxx b/PWGLF/Tasks/Resonances/deltaanalysis.cxx index 10c0d3071d2..f0a4a6ea48b 100644 --- a/PWGLF/Tasks/Resonances/deltaanalysis.cxx +++ b/PWGLF/Tasks/Resonances/deltaanalysis.cxx @@ -10,44 +10,44 @@ // or submit itself to any jurisdiction. // Analysis task for delta analysis -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include "PWGLF/DataModel/LFLithium4Tables.h" #include "Common/Core/PID/PIDTOF.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Common/TableProducer/PID/pidTOFBase.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx b/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx new file mode 100644 index 00000000000..4b67171c448 --- /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::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > -Epsilon) + return false; + } else { + if (o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > cMaxDCArToPVcut - Epsilon) + return false; + } + if (o2::aod::resomicrodaughter::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::resomicrodaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPiFlag()); + case 1: // kaon + return o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaKaFlag()); + case 2: // proton + return o2::aod::resomicrodaughter::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::resomicrodaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaPiFlag()) : -999; + case 1: // kaon + return candidate.hasTOF() ? o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaKaFlag()) : -999; + case 2: // proton + return candidate.hasTOF() ? o2::aod::resomicrodaughter::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::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()); + dcaZ = o2::aod::resomicrodaughter::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..38a7f31ed21 --- /dev/null +++ b/PWGLF/Tasks/Resonances/doublephimeson.cxx @@ -0,0 +1,1114 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/ReducedDoublePhiTables.h" + +#include "Common/Core/trackUtilities.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +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 daughterDeltaR{"daughterDeltaR", 0.0, "delta R of daughter"}; + Configurable minPhiMass1{"minPhiMass1", 1.01, "Minimum phi mass1"}; + Configurable maxPhiMass1{"maxPhiMass1", 1.03, "Maximum phi mass1"}; + Configurable minPhiPt{"minPhiPt", 0, "Minimum phi Pt"}; + Configurable maxPhiPt{"maxPhiPt", 100, "Maximum phi Pt"}; + Configurable minPhiMass2{"minPhiMass2", 1.01, "Minimum phi mass2"}; + Configurable maxPhiMass2{"maxPhiMass2", 1.03, "Maximum phi mass2"}; + Configurable minExoticMass{"minExoticMass", 2.0, "Minimum Exotic mass"}; + Configurable maxExoticMass{"maxExoticMass", 3.6, "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", 100.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 configThnAxisPtCorr{"configThnAxisPtCorr", {1000, 0.0, 100}, "#it{M} (GeV/#it{c}^{2})"}; + 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{*}"}; + ConfigurableAxis configThnAxisDeltaPt{"configThnAxisDeltaPt", {100, 0.0, 1.0}, "delta pt"}; + Configurable maxDeltaMPhi{"maxDeltaMPhi", 0.01f, "Delta-m cut on the two phi masses: sqrt((m1-mPDG)^2 + (m2-mPDG)^2) < maxDeltaMPhi (GeV/c^2)"}; + + // Initialize the ananlysis task + void init(o2::framework::InitContext&) + { + // register histograms + histos.add("hnsigmaTPCKaonPlusBefore", "hnsigmaTPCKaonPlusBefore", kTH2F, {{1000, -3.0, 3.0f}, {100, 0.0f, 10.0f}}); + histos.add("hnsigmaTPCKaonMinusBefore", "hnsigmaTPCKaonMinusBefore", kTH2F, {{1000, -3.0, 3.0f}, {100, 0.0f, 10.0f}}); + histos.add("hnsigmaTPCTOFKaonBefore", "hnsigmaTPCTOFKaonBefore", kTH3F, {{500, -3.0, 3.0f}, {500, -3.0, 3.0f}, {100, 0.0f, 10.0f}}); + 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", kTH3F, {{40, 1.0, 1.04f}, {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}}); + histos.add("hkPlusDeltaetaDeltaPhi", "hkPlusDeltaetaDeltaPhi", kTH2F, {{400, -2.0, 2.0}, {640, -2.0 * TMath::Pi(), 2.0 * TMath::Pi()}}); + histos.add("hkMinusDeltaetaDeltaPhi", "hkMinusDeltaetaDeltaPhi", kTH2F, {{400, -2.0, 2.0}, {640, -2.0 * TMath::Pi(), 2.0 * TMath::Pi()}}); + histos.add("hDeltaRkaonplus", "hDeltaRkaonplus", kTH1F, {{800, 0.0, 8.0}}); + histos.add("hDeltaRkaonminus", "hDeltaRkaonminus", kTH1F, {{800, 0.0, 8.0}}); + histos.add("hPtCorrelation", "hPtCorrelation", kTH2F, {{400, 0.0, 40.0}, {5000, 0.0, 100.0}}); + const AxisSpec thnAxisdeltapt{configThnAxisDeltaPt, "Delta pt"}; + const AxisSpec thnAxisInvMass{configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{configThnAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisInvMassPhi{configThnAxisInvMassPhi, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisInvMassDeltaPhi{configThnAxisInvMassDeltaPhi, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisDeltaR{configThnAxisDeltaR, "#Delta R)"}; + const AxisSpec thnAxisCosTheta{configThnAxisCosTheta, "cos #theta"}; + const AxisSpec thnAxisNumPhi{configThnAxisNumPhi, "Number of phi meson"}; + const AxisSpec thnAxisPtCorr{configThnAxisPtCorr, "Pt Corr var"}; + + histos.add("SEMassUnlike", "SEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisDeltaR, thnAxisPt, thnAxisDeltaR, thnAxisInvMassDeltaPhi, thnAxisPtCorr}); + // histos.add("SEMassLike", "SEMassLike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisDeltaR, thnAxisInvMassPhi, thnAxisInvMassPhi, thnAxisNumPhi}); + histos.add("MEMassUnlike", "MEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisDeltaR, thnAxisPt, thnAxisDeltaR, thnAxisInvMassDeltaPhi, thnAxisPtCorr}); + } + + // 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 deepangle2(const ROOT::Math::PtEtaPhiMVector candidate1, + const ROOT::Math::PtEtaPhiMVector 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; + } + + 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 == 100) { + if (ptcand < 1.2) { + if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { + return true; + } else if (TOFHit != 1) { + if (ptcand < 0.5 && nsigmaTPC > -2.0 && nsigmaTPC < 2.5) { + return true; + } + if (ptcand >= 0.5 && ptcand < 0.6 && nsigmaTPC > -1.5 && nsigmaTPC < 2.5) { + return true; + } + if (ptcand >= 0.6 && ptcand < 0.7 && nsigmaTPC > -1.0 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 0.7 && ptcand < 0.8 && nsigmaTPC > -0.4 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 0.8 && ptcand < 1.0 && nsigmaTPC > 0.0 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 1.0 && ptcand < 1.2 && nsigmaTPC > -2.5 && nsigmaTPC < 0.5) { + return true; + } + } + } else { + if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { + return true; + } else if (TOFHit != 1 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0) { + return true; + } + } + } + + if (PIDStrategy == 101) { + if (ptcand < 1.0) { + if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { + return true; + } else if (TOFHit != 1) { + if (ptcand < 0.5 && nsigmaTPC > -2.0 && nsigmaTPC < 2.5) { + return true; + } + if (ptcand >= 0.5 && ptcand < 0.6 && nsigmaTPC > -1.5 && nsigmaTPC < 2.5) { + return true; + } + if (ptcand >= 0.6 && ptcand < 0.7 && nsigmaTPC > -1.0 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 0.7 && ptcand < 0.8 && nsigmaTPC > -0.4 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 0.8 && ptcand < 1.0 && nsigmaTPC > 0.0 && nsigmaTPC < 2.0) { + return true; + } + } + } else if (ptcand >= 1.0 && ptcand < 2.0 && TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { + return true; + } else if (ptcand > 2.0) { + if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { + return true; + } else if (TOFHit != 1 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0) { + return true; + } + } + } + + if (PIDStrategy == 102) { + if (TOFHit != 1) { + if (ptcand < 0.5 && nsigmaTPC > -2.0 && nsigmaTPC < 2.5) { + return true; + } + if (ptcand >= 0.5 && ptcand < 0.6 && nsigmaTPC > -1.5 && nsigmaTPC < 2.5) { + return true; + } + if (ptcand >= 0.6 && ptcand < 0.7 && nsigmaTPC > -1.0 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 2.2 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0) { + return true; + } + } + if (TOFHit == 1 && ptcand > 0.4 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { + return true; + } + } + + // optimized TPC TOF + if (PIDStrategy == 0) { + if (ptcand < 0.4) { + if (nsigmaTPC > -3.0 && nsigmaTPC < 3.0) { + return true; + } + } else if (ptcand >= 0.4 && ptcand < 0.5) { + if (nsigmaTPC > -2.0 && nsigmaTPC < 3.0) { + return true; + } + } else if (ptcand >= 0.5 && ptcand < 5.0 && TOFHit == 1) { + if (ptcand < 2.0 && TMath::Sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { + return true; + } + if (ptcand >= 2.0 && TMath::Sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { + return true; + } + } else if (ptcand >= 0.5 && ptcand < 5.0 && TOFHit != 1) { + if (ptcand >= 0.5 && ptcand < 0.6 && nsigmaTPC > -1.5 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 0.6 && ptcand < 0.7 && nsigmaTPC > -1.0 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 0.7 && ptcand < 0.8 && nsigmaTPC > -0.4 && nsigmaTPC < 2.0) { + return true; + } + if (ptcand >= 0.8 && ptcand < 1.0 && nsigmaTPC > -0.0 && nsigmaTPC < 2.0) { + 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; + } + } else if (ptcand >= 5.0 && nsigmaTPC > -2.0 && nsigmaTPC < 2.0) { + return true; + } + } + // optimized TPC TOF combined + if (PIDStrategy == 1) { + if (ptcand < 0.4) { + if (nsigmaTPC > cutMinNsigmaTPC && nsigmaTPC < cutNsigmaTPC) { + return true; + } + } else if (ptcand >= 0.4 && ptcand < 0.5) { + if (nsigmaTPC > -2.0 && nsigmaTPC < cutNsigmaTPC) { + return true; + } + } else if (ptcand >= 0.5 && ptcand < 5.0 && TOFHit == 1) { + if (ptcand < 2.0 && TMath::Sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { + return true; + } + if (ptcand >= 2.0 && TMath::Sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { + return true; + } + } else if (ptcand >= 5.0 && nsigmaTPC > -2.0 && nsigmaTPC < 2.0) { + 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 Phi1kaonplus, Phi1kaonminus, Phi2kaonplus, Phi2kaonminus; + // TLorentzVector exoticRot, Phid1Rot; + + void processSE(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() < minPhiMass1 || phitrackd1.phiMass() > maxPhiMass1) { + 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(), strategyPID2, kaonminusd1pt)) { + continue; + } + phimult = phimult + 1; + } + for (auto phitrackd1 : phitracks) { + 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; + } + histos.fill(HIST("hnsigmaTPCTOFKaon"), phitrackd1.phid1TPC(), phitrackd1.phid1TOF(), kaonplusd1pt); + histos.fill(HIST("hnsigmaTPCKaonPlus"), phitrackd1.phid1TPC(), kaonplusd1pt); + histos.fill(HIST("hnsigmaTPCKaonMinus"), phitrackd1.phid2TPC(), kaonminusd1pt); + histos.fill(HIST("hPhiMass2"), Phid1.M(), Phid1.Pt()); + auto phid1id = phitrackd1.index(); + Phid1.SetXYZM(phitrackd1.phiPx(), phitrackd1.phiPy(), phitrackd1.phiPz(), phitrackd1.phiMass()); + Phi1kaonplus.SetXYZM(phitrackd1.phid1Px(), phitrackd1.phid1Py(), phitrackd1.phid1Pz(), 0.493); + Phi1kaonminus.SetXYZM(phitrackd1.phid2Px(), phitrackd1.phid2Py(), phitrackd1.phid2Pz(), 0.493); + for (auto phitrackd2 : phitracks) { + auto phid2id = phitrackd2.index(); + if (phid2id <= phid1id) { + 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; + } + Phid2.SetXYZM(phitrackd2.phiPx(), phitrackd2.phiPy(), phitrackd2.phiPz(), phitrackd2.phiMass()); + Phi2kaonplus.SetXYZM(phitrackd2.phid1Px(), phitrackd2.phid1Py(), phitrackd2.phid1Pz(), 0.493); + Phi2kaonminus.SetXYZM(phitrackd2.phid2Px(), phitrackd2.phid2Py(), phitrackd2.phid2Pz(), 0.493); + + /* + // Like + Phid1like = Phi1kaonplus + Phi2kaonplus; + Phid2like = Phi1kaonminus + Phi2kaonminus; + exoticlike = Phid1like + Phid2like; + auto deltaRlike = TMath::Sqrt(TMath::Power(Phid1like.Phi() - Phid2like.Phi(), 2.0) + TMath::Power(Phid1like.Eta() - Phid2like.Eta(), 2.0)); + auto costhetalike = (Phid1like.Px() * Phid2like.Px() + Phid1like.Py() * Phid2like.Py() + Phid1like.Pz() * Phid2like.Pz()) / (Phid1like.P() * Phid2like.P()); + auto deltamlike = TMath::Sqrt(TMath::Power(Phid1like.M() - 1.0192, 2.0) + TMath::Power(Phid2like.M() - 1.0192, 2.0)); + if (!isDeep) { + histos.fill(HIST("SEMassLike"), exoticlike.M(), exoticlike.Pt(), deltaRlike, costhetalike, deltamlike, phimult); + } + if (isDeep) { + histos.fill(HIST("SEMassLike"), exoticlike.M(), exoticlike.Pt(), deltaRlike, deepangle(Phid1like, Phid2like), deltamlike, phimult); + } + */ + + // Unlike + // histos.fill(HIST("hPhiMass2"), Phid1.M(), Phid2.M()); + if (phitrackd2.phiMass() < minPhiMass2 || phitrackd2.phiMass() > maxPhiMass2) { + continue; + } + if (phitrackd1.phiMass() < minPhiMass1 || phitrackd1.phiMass() > maxPhiMass1) { + continue; + } + exotic = Phid1 + Phid2; + if (exotic.M() < minExoticMass || exotic.M() > maxExoticMass) { + continue; + } + histos.fill(HIST("hkPlusDeltaetaDeltaPhi"), Phi1kaonplus.Eta() - Phi2kaonplus.Eta(), Phi1kaonplus.Phi() - Phi2kaonplus.Phi()); + histos.fill(HIST("hkMinusDeltaetaDeltaPhi"), Phi1kaonminus.Eta() - Phi2kaonminus.Eta(), Phi1kaonminus.Phi() - Phi2kaonminus.Phi()); + // 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 deltaRd1 = TMath::Sqrt(TMath::Power(Phi1kaonplus.Phi() - Phi2kaonplus.Phi(), 2.0) + TMath::Power(Phi1kaonplus.Eta() - Phi2kaonplus.Eta(), 2.0)); + auto deltaRd2 = TMath::Sqrt(TMath::Power(Phi1kaonminus.Phi() - Phi2kaonminus.Phi(), 2.0) + TMath::Power(Phi1kaonminus.Eta() - Phi2kaonminus.Eta(), 2.0)); + auto deltam = TMath::Sqrt(TMath::Power(Phid1.M() - 1.0192, 2.0) + TMath::Power(Phid2.M() - 1.0192, 2.0)); + if (deltaRd1 < daughterDeltaR) { + continue; + } + if (deltaRd2 < daughterDeltaR) { + continue; + } + if (!isDeep) { + histos.fill(HIST("SEMassUnlike"), exotic.M(), std::abs(Phid1.Pt() - Phid2.Pt()) / exotic.Pt(), exotic.Pt(), deltaR, deltam, phimult); + } + if (isDeep) { + histos.fill(HIST("SEMassUnlike"), exotic.M(), std::abs(Phid1.Pt() - Phid2.Pt()) / exotic.Pt(), exotic.Pt(), deltaR, deltam, phimult); + } + } + } + } + PROCESS_SWITCH(doublephimeson, processSE, "Process Same Event", false); + void processopti(aod::RedPhiEvents::iterator const& collision, aod::PhiTracks const& phitracks) + { + std::vector exoticresonance, phiresonanced1, phiresonanced2, kaonplus1, kaonplus2, kaonminus1, kaonminus2; + std::vector d1trackid = {}; + std::vector d2trackid = {}; + std::vector d3trackid = {}; + std::vector d4trackid = {}; + if (additionalEvsel && (collision.numPos() < 2 || collision.numNeg() < 2)) { + return; + } + int phimult = 0; + + for (auto phitrackd1 : phitracks) { + if (phitrackd1.phiMass() < minPhiMass1 || phitrackd1.phiMass() > maxPhiMass1) { + 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) { + auto kaonplusd1pt = TMath::Sqrt(phitrackd1.phid1Px() * phitrackd1.phid1Px() + phitrackd1.phid1Py() * phitrackd1.phid1Py()); + auto kaonminusd1pt = TMath::Sqrt(phitrackd1.phid2Px() * phitrackd1.phid2Px() + phitrackd1.phid2Py() * phitrackd1.phid2Py()); + + histos.fill(HIST("hnsigmaTPCTOFKaonBefore"), phitrackd1.phid1TPC(), phitrackd1.phid1TOF(), kaonplusd1pt); + histos.fill(HIST("hnsigmaTPCKaonPlusBefore"), phitrackd1.phid1TPC(), kaonplusd1pt); + histos.fill(HIST("hnsigmaTPCKaonMinusBefore"), phitrackd1.phid2TPC(), kaonminusd1pt); + + 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; + } + histos.fill(HIST("hnsigmaTPCTOFKaon"), phitrackd1.phid1TPC(), phitrackd1.phid1TOF(), kaonplusd1pt); + histos.fill(HIST("hnsigmaTPCKaonPlus"), phitrackd1.phid1TPC(), kaonplusd1pt); + histos.fill(HIST("hnsigmaTPCKaonMinus"), phitrackd1.phid2TPC(), kaonminusd1pt); + histos.fill(HIST("hPhiMass2"), Phid1.M(), Phid1.Pt()); + auto phid1id = phitrackd1.index(); + Phid1.SetXYZM(phitrackd1.phiPx(), phitrackd1.phiPy(), phitrackd1.phiPz(), phitrackd1.phiMass()); + Phi1kaonplus.SetXYZM(phitrackd1.phid1Px(), phitrackd1.phid1Py(), phitrackd1.phid1Pz(), 0.493); + Phi1kaonminus.SetXYZM(phitrackd1.phid2Px(), phitrackd1.phid2Py(), phitrackd1.phid2Pz(), 0.493); + for (auto phitrackd2 : phitracks) { + auto phid2id = phitrackd2.index(); + if (phid2id <= phid1id) { + 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()) || (phitrackd1.phid2Index() == phitrackd2.phid2Index())) { + continue; + } + Phid2.SetXYZM(phitrackd2.phiPx(), phitrackd2.phiPy(), phitrackd2.phiPz(), phitrackd2.phiMass()); + Phi2kaonplus.SetXYZM(phitrackd2.phid1Px(), phitrackd2.phid1Py(), phitrackd2.phid1Pz(), 0.493); + Phi2kaonminus.SetXYZM(phitrackd2.phid2Px(), phitrackd2.phid2Py(), phitrackd2.phid2Pz(), 0.493); + + // unlike + if (phitrackd1.phiMass() < minPhiMass1 || phitrackd1.phiMass() > maxPhiMass1) { + continue; + } + if (phitrackd2.phiMass() < minPhiMass2 || phitrackd2.phiMass() > maxPhiMass2) { + continue; + } + exotic = Phid1 + Phid2; + if (exotic.M() < minExoticMass || exotic.M() > maxExoticMass) { + continue; + } + + ROOT::Math::PtEtaPhiMVector temp1(exotic.Pt(), exotic.Eta(), exotic.Phi(), exotic.M()); + ROOT::Math::PtEtaPhiMVector temp2(Phid1.Pt(), Phid1.Eta(), Phid1.Phi(), Phid1.M()); + ROOT::Math::PtEtaPhiMVector temp3(Phid2.Pt(), Phid2.Eta(), Phid2.Phi(), Phid2.M()); + exoticresonance.push_back(temp1); + phiresonanced1.push_back(temp2); + phiresonanced2.push_back(temp3); + d1trackid.push_back(phitrackd1.phid1Index()); + d2trackid.push_back(phitrackd2.phid1Index()); + d3trackid.push_back(phitrackd1.phid2Index()); + d4trackid.push_back(phitrackd2.phid2Index()); + + ROOT::Math::PtEtaPhiMVector temp4(Phi1kaonplus.Pt(), Phi1kaonplus.Eta(), Phi1kaonplus.Phi(), 0.493); + ROOT::Math::PtEtaPhiMVector temp5(Phi1kaonminus.Pt(), Phi1kaonminus.Eta(), Phi1kaonminus.Phi(), 0.493); + ROOT::Math::PtEtaPhiMVector temp6(Phi2kaonplus.Pt(), Phi2kaonplus.Eta(), Phi2kaonplus.Phi(), 0.493); + ROOT::Math::PtEtaPhiMVector temp7(Phi2kaonminus.Pt(), Phi2kaonminus.Eta(), Phi2kaonminus.Phi(), 0.493); + kaonplus1.push_back(temp4); + kaonplus2.push_back(temp6); + kaonminus1.push_back(temp5); + kaonminus2.push_back(temp7); + } + } + if (exoticresonance.size() == 0) { + return; + } + // LOGF(info, "Total number of exotic: %d", exoticresonance.size()); + if (exoticresonance.size() == 2) { + for (auto if1 = exoticresonance.begin(); if1 != exoticresonance.end(); ++if1) { + auto i5 = std::distance(exoticresonance.begin(), if1); + + auto exotic1phi1 = phiresonanced1.at(i5); + auto exotic1phi2 = phiresonanced2.at(i5); + auto exotic1 = exoticresonance.at(i5); + + auto exotic1kaonplus1 = kaonplus1.at(i5); + auto exotic1kaonminus1 = kaonminus1.at(i5); + auto exotic1kaonplus2 = kaonplus2.at(i5); + auto exotic1kaonminus2 = kaonminus2.at(i5); + auto deltaRkaonplus1 = TMath::Sqrt(TMath::Power(exotic1kaonplus1.Phi() - exotic1kaonplus2.Phi(), 2.0) + TMath::Power(exotic1kaonplus1.Eta() - exotic1kaonplus2.Eta(), 2.0)); + auto deltaRkaonminus1 = TMath::Sqrt(TMath::Power(exotic1kaonminus1.Phi() - exotic1kaonminus2.Phi(), 2.0) + TMath::Power(exotic1kaonminus1.Eta() - exotic1kaonminus2.Eta(), 2.0)); + histos.fill(HIST("hDeltaRkaonplus"), deltaRkaonplus1); + histos.fill(HIST("hDeltaRkaonminus"), deltaRkaonminus1); + + auto deltam1 = TMath::Sqrt(TMath::Power(exotic1phi1.M() - 1.0192, 2.0) + TMath::Power(exotic1phi2.M() - 1.0192, 2.0)); + auto deltaR1 = TMath::Sqrt(TMath::Power(exotic1phi1.Phi() - exotic1phi2.Phi(), 2.0) + TMath::Power(exotic1phi1.Eta() - exotic1phi2.Eta(), 2.0)); + + if (deltaRkaonplus1 < daughterDeltaR) { + continue; + } + if (deltaRkaonminus1 < daughterDeltaR) { + continue; + } + + for (auto if2 = if1 + 1; if2 != exoticresonance.end(); ++if2) { + auto i6 = std::distance(exoticresonance.begin(), if2); + auto exotic2phi1 = phiresonanced1.at(i6); + auto exotic2phi2 = phiresonanced2.at(i6); + auto exotic2 = exoticresonance.at(i6); + + auto exotic2kaonplus1 = kaonplus1.at(i6); + auto exotic2kaonminus1 = kaonminus1.at(i6); + auto exotic2kaonplus2 = kaonplus2.at(i6); + auto exotic2kaonminus2 = kaonminus2.at(i6); + auto deltaRkaonplus2 = TMath::Sqrt(TMath::Power(exotic2kaonplus1.Phi() - exotic2kaonplus2.Phi(), 2.0) + TMath::Power(exotic2kaonplus1.Eta() - exotic2kaonplus2.Eta(), 2.0)); + auto deltaRkaonminus2 = TMath::Sqrt(TMath::Power(exotic2kaonminus1.Phi() - exotic2kaonminus2.Phi(), 2.0) + TMath::Power(exotic2kaonminus1.Eta() - exotic2kaonminus2.Eta(), 2.0)); + + auto deltam2 = TMath::Sqrt(TMath::Power(exotic2phi1.M() - 1.0192, 2.0) + TMath::Power(exotic2phi2.M() - 1.0192, 2.0)); + auto deltaR2 = TMath::Sqrt(TMath::Power(exotic2phi1.Phi() - exotic2phi2.Phi(), 2.0) + TMath::Power(exotic2phi1.Eta() - exotic2phi2.Eta(), 2.0)); + + if ((d1trackid.at(i5) == d1trackid.at(i6) || d1trackid.at(i5) == d2trackid.at(i6)) && + (d2trackid.at(i5) == d1trackid.at(i6) || d2trackid.at(i5) == d2trackid.at(i6)) && + (d3trackid.at(i5) == d3trackid.at(i6) || d3trackid.at(i5) == d4trackid.at(i6)) && + (d4trackid.at(i5) == d3trackid.at(i6) || d4trackid.at(i5) == d4trackid.at(i6))) { + + if (deltam2 < deltam1 && deltaRkaonplus2 > daughterDeltaR && deltaRkaonminus2 > daughterDeltaR) { + histos.fill(HIST("SEMassUnlike"), exotic2.M(), std::abs(exotic2phi1.Pt() - exotic2phi2.Pt()) / exotic2.Pt(), exotic2.Pt(), deltaR2, deltam2, phimult); + // LOGF(info, "Fill exotic Id %d which is pair of Id %d", i6, i5); + } else { + histos.fill(HIST("SEMassUnlike"), exotic1.M(), std::abs(exotic2phi1.Pt() - exotic2phi2.Pt()) / exotic1.Pt(), exotic1.Pt(), deltaR1, deltam1, phimult); + } + } else { + histos.fill(HIST("SEMassUnlike"), exotic1.M(), std::abs(exotic2phi1.Pt() - exotic2phi2.Pt()) / exotic1.Pt(), exotic1.Pt(), deltaR1, deltam1, phimult); + } + } + } + } else { + for (auto if1 = exoticresonance.begin(); if1 != exoticresonance.end(); ++if1) { + auto i5 = std::distance(exoticresonance.begin(), if1); + auto exotic1phi1 = phiresonanced1.at(i5); + auto exotic1phi2 = phiresonanced2.at(i5); + auto exotic1 = exoticresonance.at(i5); + + auto exotic1kaonplus1 = kaonplus1.at(i5); + auto exotic1kaonminus1 = kaonminus1.at(i5); + auto exotic1kaonplus2 = kaonplus2.at(i5); + auto exotic1kaonminus2 = kaonminus2.at(i5); + auto deltaRkaonplus1 = TMath::Sqrt(TMath::Power(exotic1kaonplus1.Phi() - exotic1kaonplus2.Phi(), 2.0) + TMath::Power(exotic1kaonplus1.Eta() - exotic1kaonplus2.Eta(), 2.0)); + auto deltaRkaonminus1 = TMath::Sqrt(TMath::Power(exotic1kaonminus1.Phi() - exotic1kaonminus2.Phi(), 2.0) + TMath::Power(exotic1kaonminus1.Eta() - exotic1kaonminus2.Eta(), 2.0)); + auto deltam1 = TMath::Sqrt(TMath::Power(exotic1phi1.M() - 1.0192, 2.0) + TMath::Power(exotic1phi2.M() - 1.0192, 2.0)); + auto deltaR1 = TMath::Sqrt(TMath::Power(exotic1phi1.Phi() - exotic1phi2.Phi(), 2.0) + TMath::Power(exotic1phi1.Eta() - exotic1phi2.Eta(), 2.0)); + + histos.fill(HIST("hDeltaRkaonplus"), deltaRkaonplus1); + histos.fill(HIST("hDeltaRkaonminus"), deltaRkaonminus1); + + if (deltaRkaonplus1 < daughterDeltaR) { + continue; + } + if (deltaRkaonminus1 < daughterDeltaR) { + continue; + } + + histos.fill(HIST("SEMassUnlike"), exotic1.M(), std::abs(exotic1phi1.Pt() - exotic1phi2.Pt()) / exotic1.Pt(), exotic1.Pt(), deltaR1, deltam1, phimult); + } + } + } + PROCESS_SWITCH(doublephimeson, processopti, "Process Optimized same event", false); + + void processopti3(aod::RedPhiEvents::iterator const& collision, aod::PhiTracks const& phitracks) + { + if (additionalEvsel && (collision.numPos() < 2 || collision.numNeg() < 2)) + return; + + // --- φ multiplicity with PID --- + int phimult = 0; + for (auto const& t : phitracks) { + const double kpluspt = std::hypot(t.phid1Px(), t.phid1Py()); + const double kminuspt = std::hypot(t.phid2Px(), t.phid2Py()); + // PID QA before + histos.fill(HIST("hnsigmaTPCTOFKaonBefore"), t.phid1TPC(), t.phid1TOF(), kpluspt); + histos.fill(HIST("hnsigmaTPCKaonPlusBefore"), t.phid1TPC(), kpluspt); + histos.fill(HIST("hnsigmaTPCKaonMinusBefore"), t.phid2TPC(), kminuspt); + if (t.phiMass() < minPhiMass1 || t.phiMass() > maxPhiMass1) + continue; + if (kpluspt > maxKaonPt || kminuspt > maxKaonPt) + continue; + if (!selectionPID(t.phid1TPC(), t.phid1TOF(), t.phid1TOFHit(), strategyPID1, kpluspt)) + continue; + if (!selectionPID(t.phid2TPC(), t.phid2TOF(), t.phid2TOFHit(), strategyPID2, kminuspt)) + continue; + // PID QA after + histos.fill(HIST("hnsigmaTPCTOFKaon"), t.phid1TPC(), t.phid1TOF(), kpluspt); + histos.fill(HIST("hnsigmaTPCKaonPlus"), t.phid1TPC(), kpluspt); + histos.fill(HIST("hnsigmaTPCKaonMinus"), t.phid2TPC(), kminuspt); + + ++phimult; + } + if (phimult < 2) + return; + + // --- helpers --- + constexpr double mPhiPDG = 1.019461; // GeV/c^2 + + const auto deltaMPhi = [=](double m1, double m2) { + const double d1 = m1 - mPhiPDG, d2 = m2 - mPhiPDG; + return std::sqrt(d1 * d1 + d2 * d2); + }; + + const auto deltaR = [](double phi1, double eta1, double phi2, double eta2) { + const double dphi = TVector2::Phi_mpi_pi(phi1 - phi2); + const double deta = eta1 - eta2; + return std::sqrt(dphi * dphi + deta * deta); + }; + + // minimum ΔR among all kaons in the candidate (4 kaons → 6 combinations) + const auto minKaonDeltaR = [&](const ROOT::Math::PtEtaPhiMVector& kplusA, + const ROOT::Math::PtEtaPhiMVector& kplusB, + const ROOT::Math::PtEtaPhiMVector& kminusA, + const ROOT::Math::PtEtaPhiMVector& kminusB) { + // same-sign first (keep your QA histos) + const double dRkplus = deltaR(kplusA.Phi(), kplusA.Eta(), kplusB.Phi(), kplusB.Eta()); + const double dRkminus = deltaR(kminusA.Phi(), kminusA.Eta(), kminusB.Phi(), kminusB.Eta()); + histos.fill(HIST("hDeltaRkaonplus"), dRkplus); + histos.fill(HIST("hDeltaRkaonminus"), dRkminus); + + // all other combinations + const double dR_k1p_k1m = deltaR(kplusA.Phi(), kplusA.Eta(), kminusA.Phi(), kminusA.Eta()); + const double dR_k1p_k2m = deltaR(kplusA.Phi(), kplusA.Eta(), kminusB.Phi(), kminusB.Eta()); + const double dR_k2p_k1m = deltaR(kplusB.Phi(), kplusB.Eta(), kminusA.Phi(), kminusA.Eta()); + const double dR_k2p_k2m = deltaR(kplusB.Phi(), kplusB.Eta(), kminusB.Phi(), kminusB.Eta()); + + double minDR = dRkplus; + minDR = std::min(minDR, dRkminus); + minDR = std::min(minDR, dR_k1p_k1m); + minDR = std::min(minDR, dR_k1p_k2m); + minDR = std::min(minDR, dR_k2p_k1m); + minDR = std::min(minDR, dR_k2p_k2m); + return minDR; + }; + + // --- collect candidates once --- + std::vector pairV, phi1V, phi2V, kplus1V, kplus2V, kminus1V, kminus2V; + std::vector minDRV; // store minimum ΔR for each pair + + for (auto const& t1 : phitracks) { + const double kplus1pt = std::hypot(t1.phid1Px(), t1.phid1Py()); + const double kminus1pt = std::hypot(t1.phid2Px(), t1.phid2Py()); + + if (kplus1pt > maxKaonPt || kminus1pt > maxKaonPt) + continue; + if (!selectionPID(t1.phid1TPC(), t1.phid1TOF(), t1.phid1TOFHit(), strategyPID1, kplus1pt)) + continue; + if (!selectionPID(t1.phid2TPC(), t1.phid2TOF(), t1.phid2TOFHit(), strategyPID2, kminus1pt)) + continue; + + TLorentzVector phi1, k1p, k1m; + phi1.SetXYZM(t1.phiPx(), t1.phiPy(), t1.phiPz(), t1.phiMass()); + k1p.SetXYZM(t1.phid1Px(), t1.phid1Py(), t1.phid1Pz(), 0.493); + k1m.SetXYZM(t1.phid2Px(), t1.phid2Py(), t1.phid2Pz(), 0.493); + + // φ mass windows + if (t1.phiMass() < minPhiMass1 || t1.phiMass() > maxPhiMass1) + continue; + if (phi1.Pt() < minPhiPt || phi1.Pt() > maxPhiPt) + continue; + + const auto id1 = t1.index(); + + for (auto const& t2 : phitracks) { + const auto id2 = t2.index(); + if (id2 <= id1) + continue; + + const double kplus2pt = std::hypot(t2.phid1Px(), t2.phid1Py()); + const double kminus2pt = std::hypot(t2.phid2Px(), t2.phid2Py()); + if (kplus2pt > maxKaonPt || kminus2pt > maxKaonPt) + continue; + if (!selectionPID(t2.phid1TPC(), t2.phid1TOF(), t2.phid1TOFHit(), strategyPID1, kplus2pt)) + continue; + if (!selectionPID(t2.phid2TPC(), t2.phid2TOF(), t2.phid2TOFHit(), strategyPID2, kminus2pt)) + continue; + + // block shared same-sign daughters + if ((t1.phid1Index() == t2.phid1Index()) || (t1.phid2Index() == t2.phid2Index())) + continue; + + TLorentzVector phi2, k2p, k2m; + phi2.SetXYZM(t2.phiPx(), t2.phiPy(), t2.phiPz(), t2.phiMass()); + k2p.SetXYZM(t2.phid1Px(), t2.phid1Py(), t2.phid1Pz(), 0.493); + k2m.SetXYZM(t2.phid2Px(), t2.phid2Py(), t2.phid2Pz(), 0.493); + if (t2.phiMass() < minPhiMass2 || t2.phiMass() > maxPhiMass2) + continue; + if (phi1.Pt() < minPhiPt || phi1.Pt() > maxPhiPt) + continue; + // Δm cut (configurable) + const double dM = deltaMPhi(phi1.M(), phi2.M()); + if (dM > maxDeltaMPhi) + continue; + + TLorentzVector pair = phi1 + phi2; + if (pair.M() < minExoticMass || pair.M() > maxExoticMass) + continue; + histos.fill(HIST("hPhiMass"), phi1.M(), phi2.M(), pair.Pt()); + // daughter ΔR QA and minΔR (NO CUT anymore) + ROOT::Math::PtEtaPhiMVector k1pV(k1p.Pt(), k1p.Eta(), k1p.Phi(), 0.493); + ROOT::Math::PtEtaPhiMVector k1mV(k1m.Pt(), k1m.Eta(), k1m.Phi(), 0.493); + ROOT::Math::PtEtaPhiMVector k2pV(k2p.Pt(), k2p.Eta(), k2p.Phi(), 0.493); + ROOT::Math::PtEtaPhiMVector k2mV(k2m.Pt(), k2m.Eta(), k2m.Phi(), 0.493); + const double minDR = minKaonDeltaR(k1pV, k2pV, k1mV, k2mV); + + // store for one-pass fill + pairV.emplace_back(pair.Pt(), pair.Eta(), pair.Phi(), pair.M()); + phi1V.emplace_back(phi1.Pt(), phi1.Eta(), phi1.Phi(), phi1.M()); + phi2V.emplace_back(phi2.Pt(), phi2.Eta(), phi2.Phi(), phi2.M()); + kplus1V.emplace_back(k1p.Pt(), k1p.Eta(), k1p.Phi(), 0.493); + kminus1V.emplace_back(k1m.Pt(), k1m.Eta(), k1m.Phi(), 0.493); + kplus2V.emplace_back(k2p.Pt(), k2p.Eta(), k2p.Phi(), 0.493); + kminus2V.emplace_back(k2m.Pt(), k2m.Eta(), k2m.Phi(), 0.493); + minDRV.emplace_back(minDR); // per-candidate minimum ΔR of kaons + } + } + + if (pairV.empty()) + return; + + // --- fill the single THnSparse --- + for (size_t i = 0; i < pairV.size(); ++i) { + TLorentzVector p1, p2, pair; + p1.SetPtEtaPhiM(phi1V[i].Pt(), phi1V[i].Eta(), phi1V[i].Phi(), phi1V[i].M()); + p2.SetPtEtaPhiM(phi2V[i].Pt(), phi2V[i].Eta(), phi2V[i].Phi(), phi2V[i].M()); + pair.SetPtEtaPhiM(pairV[i].Pt(), pairV[i].Eta(), pairV[i].Phi(), pairV[i].M()); + + const double dM = deltaMPhi(p1.M(), p2.M()); + const double M = pair.M(); + const double dR = deltaR(p1.Phi(), p1.Eta(), p2.Phi(), p2.Eta()); + const double minDR = minDRV[i]; + double ptcorr = p1.Pt() / (pair.Pt() - p1.Pt()); + histos.fill(HIST("hPtCorrelation"), pair.Pt(), ptcorr); + // NOTE: second axis is now minΔR(all kaons), ΔpT/pT has been removed + histos.fill(HIST("SEMassUnlike"), + M, + minDR, + pair.Pt(), + dR, + dM, + ptcorr); + } + } + PROCESS_SWITCH(doublephimeson, processopti3, "Process Optimized same event", false); + + 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}; + + // --- helpers (same as in processopti3) --- + constexpr double mPhiPDG = 1.019461; // GeV/c^2 + + const auto deltaMPhi = [=](double m1, double m2) { + const double d1 = m1 - mPhiPDG; + const double d2 = m2 - mPhiPDG; + return std::sqrt(d1 * d1 + d2 * d2); + }; + + const auto deltaR = [](double phi1, double eta1, double phi2, double eta2) { + const double dphi = TVector2::Phi_mpi_pi(phi1 - phi2); + const double deta = eta1 - eta2; + return std::sqrt(dphi * dphi + deta * deta); + }; + + const auto minKaonDeltaR = + [&](const ROOT::Math::PtEtaPhiMVector& kplusA, + const ROOT::Math::PtEtaPhiMVector& kplusB, + const ROOT::Math::PtEtaPhiMVector& kminusA, + const ROOT::Math::PtEtaPhiMVector& kminusB) { + // same-sign first (keep QA as in SE) + const double dRkplus = + deltaR(kplusA.Phi(), kplusA.Eta(), kplusB.Phi(), kplusB.Eta()); + const double dRkminus = + deltaR(kminusA.Phi(), kminusA.Eta(), kminusB.Phi(), kminusB.Eta()); + histos.fill(HIST("hDeltaRkaonplus"), dRkplus); + histos.fill(HIST("hDeltaRkaonminus"), dRkminus); + + // all other combinations + const double dR_k1p_k1m = + deltaR(kplusA.Phi(), kplusA.Eta(), kminusA.Phi(), kminusA.Eta()); + const double dR_k1p_k2m = + deltaR(kplusA.Phi(), kplusA.Eta(), kminusB.Phi(), kminusB.Eta()); + const double dR_k2p_k1m = + deltaR(kplusB.Phi(), kplusB.Eta(), kminusA.Phi(), kminusA.Eta()); + const double dR_k2p_k2m = + deltaR(kplusB.Phi(), kplusB.Eta(), kminusB.Phi(), kminusB.Eta()); + + double minDR = dRkplus; + minDR = std::min(minDR, dRkminus); + minDR = std::min(minDR, dR_k1p_k1m); + minDR = std::min(minDR, dR_k1p_k2m); + minDR = std::min(minDR, dR_k2p_k1m); + minDR = std::min(minDR, dR_k2p_k2m); + return minDR; + }; + + struct PhiCand { + ROOT::Math::PtEtaPhiMVector phi; + ROOT::Math::PtEtaPhiMVector kplus; + ROOT::Math::PtEtaPhiMVector kminus; + }; + + for (auto& [collision1, tracks1, collision2, tracks2] : pair) { + // safety: should never happen but keep it + if (collision1.index() == collision2.index()) { + continue; + } + + // optional event-level selection (same idea as in SE) + if (additionalEvsel) { + if (collision1.numPos() < 2 || collision1.numNeg() < 2) { + continue; + } + if (collision2.numPos() < 2 || collision2.numNeg() < 2) { + continue; + } + } + + std::vector cands1, cands2; + + // --- build φ candidates for event 1 (φ1) --- + for (auto const& t1 : tracks1) { + const double kplus1pt = std::hypot(t1.phid1Px(), t1.phid1Py()); + const double kminus1pt = std::hypot(t1.phid2Px(), t1.phid2Py()); + + if (kplus1pt > maxKaonPt || kminus1pt > maxKaonPt) + continue; + if (!selectionPID(t1.phid1TPC(), t1.phid1TOF(), t1.phid1TOFHit(), strategyPID1, kplus1pt)) + continue; + if (!selectionPID(t1.phid2TPC(), t1.phid2TOF(), t1.phid2TOFHit(), strategyPID2, kminus1pt)) + continue; + + TLorentzVector phi1, k1p, k1m; + phi1.SetXYZM(t1.phiPx(), t1.phiPy(), t1.phiPz(), t1.phiMass()); + k1p.SetXYZM(t1.phid1Px(), t1.phid1Py(), t1.phid1Pz(), 0.493); + k1m.SetXYZM(t1.phid2Px(), t1.phid2Py(), t1.phid2Pz(), 0.493); + + if (t1.phiMass() < minPhiMass1 || t1.phiMass() > maxPhiMass1) + continue; + if (phi1.Pt() < minPhiPt || phi1.Pt() > maxPhiPt) + continue; + + PhiCand cand; + cand.phi = ROOT::Math::PtEtaPhiMVector(phi1.Pt(), phi1.Eta(), phi1.Phi(), phi1.M()); + cand.kplus = ROOT::Math::PtEtaPhiMVector(k1p.Pt(), k1p.Eta(), k1p.Phi(), 0.493); + cand.kminus = ROOT::Math::PtEtaPhiMVector(k1m.Pt(), k1m.Eta(), k1m.Phi(), 0.493); + + cands1.emplace_back(std::move(cand)); + } + + // --- build φ candidates for event 2 (φ2) --- + for (auto const& t2 : tracks2) { + const double kplus2pt = std::hypot(t2.phid1Px(), t2.phid1Py()); + const double kminus2pt = std::hypot(t2.phid2Px(), t2.phid2Py()); + + if (kplus2pt > maxKaonPt || kminus2pt > maxKaonPt) + continue; + if (!selectionPID(t2.phid1TPC(), t2.phid1TOF(), t2.phid1TOFHit(), strategyPID1, kplus2pt)) + continue; + if (!selectionPID(t2.phid2TPC(), t2.phid2TOF(), t2.phid2TOFHit(), strategyPID2, kminus2pt)) + continue; + + TLorentzVector phi2, k2p, k2m; + phi2.SetXYZM(t2.phiPx(), t2.phiPy(), t2.phiPz(), t2.phiMass()); + k2p.SetXYZM(t2.phid1Px(), t2.phid1Py(), t2.phid1Pz(), 0.493); + k2m.SetXYZM(t2.phid2Px(), t2.phid2Py(), t2.phid2Pz(), 0.493); + + if (t2.phiMass() < minPhiMass2 || t2.phiMass() > maxPhiMass2) + continue; + if (phi2.Pt() < minPhiPt || phi2.Pt() > maxPhiPt) + continue; + + PhiCand cand; + cand.phi = ROOT::Math::PtEtaPhiMVector(phi2.Pt(), phi2.Eta(), phi2.Phi(), phi2.M()); + cand.kplus = ROOT::Math::PtEtaPhiMVector(k2p.Pt(), k2p.Eta(), k2p.Phi(), 0.493); + cand.kminus = ROOT::Math::PtEtaPhiMVector(k2m.Pt(), k2m.Eta(), k2m.Phi(), 0.493); + + cands2.emplace_back(std::move(cand)); + } + + if (cands1.empty() || cands2.empty()) { + continue; + } + + // --- build mixed-event pairs and fill MEMassUnlike --- + for (auto const& c1 : cands1) { + TLorentzVector phi1; + phi1.SetPtEtaPhiM(c1.phi.Pt(), c1.phi.Eta(), c1.phi.Phi(), c1.phi.M()); + + for (auto const& c2 : cands2) { + TLorentzVector phi2; + phi2.SetPtEtaPhiM(c2.phi.Pt(), c2.phi.Eta(), c2.phi.Phi(), c2.phi.M()); + + const double dM = deltaMPhi(phi1.M(), phi2.M()); + if (dM > maxDeltaMPhi) + continue; + + TLorentzVector pair = phi1 + phi2; + if (pair.M() < minExoticMass || pair.M() > maxExoticMass) + continue; + + const double minDR = minKaonDeltaR(c1.kplus, c2.kplus, c1.kminus, c2.kminus); + const double dR = deltaR(phi1.Phi(), phi1.Eta(), phi2.Phi(), phi2.Eta()); + + // same definition as SE + const double ptcorr = (pair.Pt() - phi1.Pt() != 0.) + ? phi1.Pt() / (pair.Pt() - phi1.Pt()) + : 0.; + + histos.fill(HIST("MEMassUnlike"), + pair.M(), // M(phi-phi) + minDR, // min ΔR among all kaon pairs + pair.Pt(), // pT(phi-phi) + dR, // ΔR(phi1, phi2) + dM, // Δm(phi) + ptcorr); // pT correlation + } + } + } + } + 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 05b55183842..6ae7b3534a0 100644 --- a/PWGLF/Tasks/Resonances/f0980analysis.cxx +++ b/PWGLF/Tasks/Resonances/f0980analysis.cxx @@ -8,138 +8,121 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// +/// \file f0980analysis.cxx +/// \brief f0(980) analysis in pp 13.6 TeV +/// \author Yunseul Bae (ybae@cern.ch), Junlee Kim (jikim1290@gmail.com) +/// \since 01/07/2024 -/// \author Junlee Kim (jikim1290@gmail.com) - -#include -#include -#include "TVector2.h" +#include "PWGLF/DataModel/LFResonanceTables.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" #include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisHelpers.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "CommonConstants/PhysicsConstants.h" +#include + +#include "Math/LorentzVector.h" +#include "Math/Vector4D.h" +#include "TVector2.h" +#include + +#include using namespace o2; +using namespace o2::constants::physics; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::aod; using namespace o2::soa; -using namespace o2::constants::physics; struct f0980analysis { SliceCache cache; - Preslice perRCol = aod::resodaughter::resoCollisionId; - Preslice perCollision = aod::track::collisionId; - HistogramRegistry histos{ - "histos", - {}, - OutputObjHandlingPolicy::AnalysisObject}; - - 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 cfgMaxTPC{"cfgMaxTPC", 5.0, "Maximum TPC PID with TOF"}; - Configurable cfgMaxTOF{"cfgMaxTOF", 3.0, "Maximum TOF PID with TPC"}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Event selections + 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 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 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 cfgFindRT{"cfgFindRT", false, "boolean for RT analysis"}; + + // Track selections + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgGlobalTrack{"cfgGlobalTrack", false, "Global 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"}; 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"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 0, "Number of TPC cluster"}; - // PID - Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF - Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 3.0, "TPC nSigma cut for Pion"}; // TPC + // PID + Configurable cMaxTOFnSigmaPion{"cMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; + Configurable cMaxTPCnSigmaPion{"cMaxTPCnSigmaPion", 5.0, "TPC nSigma cut for Pion"}; + Configurable cMaxTPCnSigmaPionWoTOF{"cMaxTPCnSigmaPionWoTOF", 2.0, "TPC nSigma cut without TOF for Pion"}; Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -999, "Combined nSigma cut for Pion"}; - Configurable SelectType{"SelectType", 0, "PID selection type"}; + Configurable selectType{"SelectType", 0, "PID selection type"}; - // Axis + // 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"}; + 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 lptBinning = {0, 5.0, 13.0, 20.0, 50.0, 1000.0}; - AxisSpec RTAxis = {3, 0, 3}; - AxisSpec LptAxis = {lptBinning}; // Minimum leading hadron pT selection + AxisSpec rtAxis = {3, 0, 3}; + AxisSpec lptAxis = {lptBinning}; // Minimum leading hadron pT selection - AxisSpec PIDqaAxis = {120, -6, 6}; + AxisSpec pidqaAxis = {60, -6, 6}; AxisSpec pTqaAxis = {200, 0, 20}; - AxisSpec phiqaAxis = {72, 0., 2.0 * constants::math::PI}; - AxisSpec EPAxis = {10, 0, constants::math::PI}; - 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}}); - - 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("QA/hEPResAB", "", {HistType::kTH2F, {centAxis, EPresAxis}}); - histos.add("QA/hEPResAC", "", {HistType::kTH2F, {centAxis, EPresAxis}}); - histos.add("QA/hEPResBC", "", {HistType::kTH2F, {centAxis, EPresAxis}}); - - 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}}); + AxisSpec phiqaAxis = {72, 0, o2::constants::math::TwoPI}; // Azimuthal angle axis + + AxisSpec epAxis = {10, 0, o2::constants::math::PI}; // Event Plane + AxisSpec epqaAxis = {200, -o2::constants::math::PI, o2::constants::math::PI}; + AxisSpec epResAxis = {200, -2, 2}; + + 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}}); + } else { + 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("QA/EPhist", "", {HistType::kTH2F, {centAxis, epqaAxis}}); + histos.add("QA/hEPResAB", "", {HistType::kTH2F, {centAxis, epResAxis}}); + histos.add("QA/hEPResBC", "", {HistType::kTH2F, {centAxis, epResAxis}}); + histos.add("QA/hEPResAC", "", {HistType::kTH2F, {centAxis, epResAxis}}); histos.add("QA/LTpt", "", {HistType::kTH3F, {pTqaAxis, centAxis, phiqaAxis}}); - histos.add("QA/EPhist", "", {HistType::kTH2F, {centAxis, EPqaAxis}}); + + histos.add("QA/Nsigma_TPC", "", {HistType::kTH2F, {pTqaAxis, pidqaAxis}}); + histos.add("QA/Nsigma_TOF", "", {HistType::kTH2F, {pTqaAxis, pidqaAxis}}); + histos.add("QA/Nsigma_TPC_TOF", "", {HistType::kTH2F, {pidqaAxis, pidqaAxis}}); if (doprocessMCLight) { - histos.add("MCL/hpT_f0980_GEN", "generated f0 signals", HistType::kTH1F, - {pTqaAxis}); - histos.add("MCL/hpT_f0980_REC", "reconstructed f0 signals", - HistType::kTH3F, {massAxis, pTqaAxis, centAxis}); + histos.add("MCL/hpT_f0980_GEN", "generated f0 signals", HistType::kTH1F, {pTqaAxis}); + histos.add("MCL/hpT_f0980_REC", "reconstructed f0 signals", HistType::kTH3F, {massAxis, pTqaAxis, centAxis}); } histos.print(); @@ -147,23 +130,28 @@ struct f0980analysis { double massPi = MassPionCharged; - int RTIndex(double pairphi, double lhphi) + static constexpr float OneThird = 1.0f / 3.0f; + static constexpr float PIthird = o2::constants::math::PI * OneThird; + static constexpr float TWOPIthird = o2::constants::math::TwoPI * OneThird; + + int rtIndex(double pairphi, double lhphi) { double dphi = std::fabs(TVector2::Phi_mpi_pi(lhphi - pairphi)); - if (dphi < constants::math::PI / 3.0) + + if (dphi < PIthird) return 0; - if (dphi < 2.0 * constants::math::PI / 3.0 && dphi > constants::math::PI / 3.0) + if (dphi < TWOPIthird && dphi > PIthird) return 1; - if (dphi > 2.0 * constants::math::PI / 3.0) + if (dphi > TWOPIthird) return 2; return -1; } template - bool SelTrack(const TrackType track) + bool selTrack(const TrackType track) { - if (std::abs(track.pt()) < cfgMinPt) + if (std::abs(track.pt()) < cfgMinpT) return false; if (std::fabs(track.eta()) > cfgMaxEta) return false; @@ -171,153 +159,145 @@ struct f0980analysis { return false; if (std::abs(track.dcaZ()) > cfgMaxDCAzToPVcut) 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 (cfgPrimaryTrack && !track.isPrimaryTrack()) return false; - if (cfgHasITS && !track.hasITS()) + if (cfgGlobalTrack && !track.isGlobalTrack()) return false; - if (cfgHasTPC && !track.hasTPC()) + if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) return false; - if (cfgHasTOF && !track.hasTOF()) + if (cfgPVContributor && !track.isPVContributor()) 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()) + if (cfgHasTOF && !track.hasTOF()) return false; return true; } template - bool SelPion(const TrackType track) + 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; + switch (selectType) { + case 0: + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaPi()) >= cMaxTOFnSigmaPion) + return false; + break; + case 1: + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion) + return false; + break; + case 2: + if (track.tpcNSigmaPi() * track.tpcNSigmaPi() + track.tofNSigmaPi() * track.tofNSigmaPi() >= nsigmaCutCombinedPion * nsigmaCutCombinedPion) + return false; + break; + case 3: + if (track.hasTOF()) { + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPion || std::fabs(track.tofNSigmaPi()) >= cMaxTOFnSigmaPion) + return false; + } else { + if (std::fabs(track.tpcNSigmaPi()) >= cMaxTPCnSigmaPionWoTOF) + return false; + } + break; } return true; } template - void fillHistograms(const CollisionType& collision, - const TracksType& dTracks) + void fillHistograms(const CollisionType& collision, const TracksType& dTracks) { - double LHpt = 0.; - double LHphi = 0.; - double relPhi = 0.; - for (auto& trk : dTracks) { - if (trk.pt() > LHpt) { - LHpt = trk.pt(); - LHphi = trk.phi(); + double lhpT = 0.; + double lhphi = 0.; + double relphi = 0.; + if (cfgFindRT) { + for (const 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()); - histos.fill(HIST("QA/hEPResBC"), collision.cent(), collision.evtPlResAC()); - histos.fill(HIST("QA/LTpt"), LHpt, collision.cent(), LHphi); - - TLorentzVector Pion1, Pion2, Reco; - for (auto& [trk1, trk2] : - combinations(CombinationsUpperIndexPolicy(dTracks, dTracks))) { - if (trk1.index() == trk2.index()) { - 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; - } + histos.fill(HIST("QA/hEPResBC"), collision.cent(), collision.evtPlResBC()); + histos.fill(HIST("QA/hEPResAC"), collision.cent(), collision.evtPlResAC()); + histos.fill(HIST("QA/LTpt"), lhpT, collision.cent(), lhphi); - if (!SelTrack(trk1) || !SelTrack(trk2)) - continue; - if (!SelPion(trk1) || !SelPion(trk2)) + ROOT::Math::LorentzVector> pion1, pion2, reco; + for (const auto& [trk1, trk2] : combinations(CombinationsStrictlyUpperIndexPolicy(dTracks, dTracks))) { + + if (!selTrack(trk1) || !selTrack(trk2)) 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/Nsigma_TPC_TOF"), trk1.tpcNSigmaPi(), trk1.tofNSigmaPi()); - Pion1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); - Pion2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massPi); - Reco = Pion1 + Pion2; + if (!selPion(trk1) || !selPion(trk2)) + continue; - if (Reco.Rapidity() > cfgMaxRap || Reco.Rapidity() < cfgMinRap) + pion1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massPi); + pion2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massPi); + reco = pion1 + pion2; + if (reco.Rapidity() > cfgMaxRap || reco.Rapidity() < cfgMinRap) continue; - relPhi = TVector2::Phi_0_2pi(Reco.Phi() - collision.evtPl()); - if (relPhi > constants::math::PI) { - relPhi -= constants::math::PI; + relphi = TVector2::Phi_0_2pi(reco.Phi() - collision.evtPl()); + if (relphi > o2::constants::math::PI) { + relphi -= o2::constants::math::PI; } if (trk1.sign() * trk2.sign() < 0) { - 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 (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) { - if (abs(trk1.pdgCode()) != 211 || abs(trk2.pdgCode()) != 211) + if (std::abs(trk1.pdgCode()) != kPiPlus || std::abs(trk2.pdgCode()) != kPiPlus) continue; if (trk1.motherId() != trk2.motherId()) continue; - if (abs(trk1.motherPDG()) != 9010221) + if (std::abs(trk1.motherPDG()) != 9010221) continue; - histos.fill(HIST("MCL/hpT_f0980_REC"), Reco.M(), Reco.Pt(), - collision.cent()); + histos.fill(HIST("MCL/hpT_f0980_REC"), reco.M(), reco.Pt(), 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); - histos.fill(HIST("hInvMass_f0980_LSpp_EPA"), Reco.M(), Reco.Pt(), - collision.cent(), relPhi); + 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); - histos.fill(HIST("hInvMass_f0980_LSmm_EPA"), Reco.M(), Reco.Pt(), - collision.cent(), relPhi); + 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, - aod::ResoTracks const& resotracks) + void processData(o2::soa::Join::iterator const& collision, + o2::aod::ResoTracks const& resotracks) { fillHistograms(collision, resotracks); } PROCESS_SWITCH(f0980analysis, processData, "Process Event for data", true); void processMCLight( - aod::ResoCollision& collision, - soa::Join const& resotracks) + o2::soa::Join::iterator const& collision, + o2::soa::Join const& resotracks) { fillHistograms(collision, resotracks); } PROCESS_SWITCH(f0980analysis, processMCLight, "Process Event for MC", false); - void processMCTrue(aod::ResoMCParents& resoParents) + void processMCTrue(const o2::aod::ResoMCParents& resoParents) { - - for (auto& part : resoParents) { // loop over all pre-filtered MC particles - if (abs(part.pdgCode()) != 9010221) + for (const auto& part : resoParents) { // loop over all pre-filtered MC particles + if (std::abs(part.pdgCode()) != 9010221) continue; if (!part.producedByGenerator()) continue; @@ -325,8 +305,8 @@ struct f0980analysis { continue; } bool pass = false; - if ((abs(part.daughterPDG1()) == 211 && - abs(part.daughterPDG2()) == 211)) { + if ((std::abs(part.daughterPDG1()) == kPiPlus && + std::abs(part.daughterPDG2()) == kPiPlus)) { pass = true; } if (!pass) // If we have both decay products diff --git a/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx b/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx new file mode 100644 index 00000000000..6cf4b2b176c --- /dev/null +++ b/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx @@ -0,0 +1,855 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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), Sangwoo Park (sangwoo.park@cern.ch) + +#include +#include + +#include +#include +#include +#include +// #include +#include +#include +#include + +// #include "TLorentzVector.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include "TVector2.h" +#include + +// from phi +#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"}; + + // Evnet Selection Configurables + Configurable cfgEventCutVertex{"cfgEventCutVertex", 10.0, "PV selection"}; + Configurable cfgEventQvecSel{"cfgEventQvecSel", true, "Reject events when no QVector"}; + Configurable cfgEventOccupancySel{"cfgEventOccupancySel", false, "Occupancy selection"}; + Configurable cfgEventOccupancyMax{"cfgEventOccupancyMax", 999999, "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgEventOccupancyMin{"cfgEventOccupancyMin", -100, "minimum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgEventGoodZvtxSel{"cfgEventGoodZvtxSel", true, "kIsGoodZvtxFT0vsPV selection"}; + Configurable cfgEventNSamePileupSel{"cfgEventNSamePileupSel", true, "kNoSameBunchPileup selection"}; + Configurable cfgEventNCollinTRSel{"cfgEventNCollinTRSel", true, "kNoCollInTimeRangeStandard selection"}; + Configurable cfgEventPVSel{"cfgEventPVSel", false, "Additional PV selection flag for syst"}; + Configurable cfgEventPV{"cfgEventPV", 8.0, "Additional PV selection range for syst"}; + + Configurable cfgEventCentMax{"cfgEventCentMax", 80., "CentralityMax cut"}; + Configurable cfgEventCentEst{"cfgEventCentEst", 1, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + // Track Selection Configurables + Configurable cfgTrackPtMin{"cfgTrackPtMin", 0.15, "Minimum transverse momentum for charged track"}; + Configurable cfgTrackEtaMax{"cfgTrackEtaMax", 0.8, "Maximum pseudorapidiy for charged track"}; + Configurable cfgTrackDCArToPVcutMax{"cfgTrackDCArToPVcutMax", 0.5, "Maximum transverse DCA"}; + Configurable cfgTrackDCAzToPVcutMax{"cfgTrackDCAzToPVcutMax", 2.0, "Maximum longitudinal DCA"}; + Configurable cfgTrackRapMin{"cfgTrackRapMin", -0.5, "Minimum rapidity for pair"}; + Configurable cfgTrackRapMax{"cfgTrackRapMax", 0.5, "Maximum rapidity for pair"}; + + Configurable cfgTrackIsPrimaryTrack{"cfgTrackIsPrimaryTrack", true, "Primary track selection"}; + Configurable cfgTrackIsGlobalWoDCATrack{"cfgTrackIsGlobalWoDCATrack", true, "Global track selection without DCA"}; + Configurable cfgTrackIsPVContributor{"cfgTrackIsPVContributor", true, "PV contributor track selection"}; + + Configurable cfgTrackNTPCCrossedRows{"cfgTrackNTPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable cfgTrackNFindableTPCClusters{"cfgTrackNFindableTPCClusters", 50, "nFindable TPC Clusters"}; + Configurable cfgTrackNRowsOverFindable{"cfgTrackNRowsOverFindable", 1.2, "nRowsOverFindable TPC CLusters"}; + Configurable cfgTrackNTPCChi2{"cfgTrackNTPCChi2", 4.0, "nTPC Chi2 per Cluster"}; + + Configurable cfgTrackNITSChi2{"cfgTrackNITSChi2", 36.0, "nITS Chi2 per Cluster"}; + + // PID Configurables + Configurable cfgPIDUSETOF{"cfgPIDUSETOF", true, "TOF usage"}; + + Configurable cfgPIDMaxTOFnSigmaPion{"cfgPIDMaxTOFnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; // TOF + Configurable cfgPIDMaxTPCnSigmaPion{"cfgPIDMaxTPCnSigmaPion", 5.0, "TPC nSigma cut for Pion"}; // TPC + Configurable cfgPIDMaxTPCnSigmaPionS{"cfgPIDMaxTPCnSigmaPionS", 3.0, "TPC nSigma cut for Pion as a standalone"}; + Configurable cfgPIDMaxTiednSigmaPion{"cfgPIDMaxTiednSigmaPion", 3.0, "Combined nSigma cut for Pion"}; + + // Flow Configurables + Configurable cfgQvecNMods{"cfgQvecNMods", 1, "The number of modulations of interest starting from 2"}; + Configurable cfgQvecNum{"cfgQvecNum", 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"}; + + // Rotational Background Configurables + Configurable cfgBkgRotSel{"cfgBkgRotSel", false, "flag to construct rotational backgrounds"}; + Configurable cfgBkgRotNum{"cfgBkgRotNum", 5, "the number of rotational backgrounds"}; + + // Mixed Event Background Configurables + SliceCache cache; + Configurable cfgBkgMixedNum{"cfgBkgMixedNum", 5, "Number of mixed events per event"}; + ConfigurableAxis mixAxisVertex{"mixAxisVertex", {10, -10, 10}, "Vertex axis for mixing bin"}; + ConfigurableAxis mixAxisCent{"mixAxisCent", {VARIABLE_WIDTH, 0, 10, 20, 50, 100}, "multiplicity percentile for mixing bin"}; + // ConfigurableAxis mixingAxisMultiplicity{"mixingAxisMultiplicity", {2000, 0, 10000}, "TPC multiplicity for bin"}; + + // List Configurables + Configurable cfgListPID{"cfgListPID", 0, "PID selection type"}; + Configurable cfgListPtl{"cfgListPtl", 0, "Particle selection type"}; + + // Histogram QA Configurables + Configurable cfgQAEventCut{"cfgQAEventCut", true, "Enable Event QA Hists"}; + Configurable cfgQATrackCut{"cfgQATrackCut", true, "Enable Track QA Hists"}; + Configurable cfgQAPIDCut{"cfgQAPIDCut", true, "Enable PID QA Hists"}; + Configurable cfgQAEPCut{"cfgQAEPCut", true, "Enable Event Plane QA Hists"}; + Configurable cfgQAEventFlowCut{"cfgQAEventFlowCut", true, "Enable Event Flow QA Hists"}; + + ConfigurableAxis histAxisDCAz{"histAxisDCAz", {40, -0.2, 0.2}, "DCAz axis"}; + ConfigurableAxis histAxisDCAr{"histAxisDCAr", {40, -0.2, 0.2}, "DCAxy axis"}; + ConfigurableAxis histAxisOccupancy{"histAxisOccupancy", {100, 0.0, 20000}, "Occupancy axis"}; + + Configurable cfgAnalysisMethod{"cfgAnalysisMethod", true, "true: Two for-loop, false: Combination"}; + + // Configurable for axis + ConfigurableAxis axisMass{"axisMass", {400, 0.2, 2.2}, "Invariant mass axis"}; + ConfigurableAxis axisPT{"axisPT", {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 axisCent{"axisCent", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 100}, "Centrality interval"}; + ConfigurableAxis axisEp{"axisEp", {6, 0.0, o2::constants::math::TwoPI}, "EP axis"}; + + // for phi test + Configurable cfgPhiITSClsSel{"cfgPhiITSClsSel", false, "ITS cluster selection flag"}; + Configurable cfgPhiITScluster{"cfgPhiITScluster", 0, "Number of ITS cluster"}; + Configurable cfgPhiTOFBetaSel{"cfgPhiTOFBetaSel", false, "TOF beta cut selection flag"}; + Configurable cfgPhiTOFBetaCut{"cfgPhiTOFBetaCut", 0.0, "cut TOF beta"}; + Configurable cfgPhiDeepAngleSel{"cfgPhiDeepAngleSel", false, "Deep Angle cut"}; + Configurable cfgPhiDeepAngle{"cfgPhiDeepAngle", 0.04, "Deep Angle cut value"}; + + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + + int nmode = 2; + static constexpr double QvecAmpMin = 1e-4; + + int detId; + int refAId; + int refBId; + + int qVecDetInd; + int qVecRefAInd; + int qVecRefBInd; + + double eventPlaneDet; + double eventPlaneRefA; + double eventPlaneRefB; + + float centrality; + + double angle; + double relPhi; + double relPhiRot; + double relPhiMix; + + // double massPi = o2::constants::physics::MassPionCharged; + double massPtl; + + int nTotalEvents = 0; + + enum CentEstList { + FT0C = 0, + FT0M = 1, + }; + + enum PIDList { + PIDRun3 = 0, + PIDRun2 = 1, + PIDTest = 2, + }; + + enum PtlList { + PtlPion = 0, + PtlKaon = 1, + }; + + enum QAList { + QAEvent = 1, + QAEP = 2, + QATrack = 3, + QAPID = 4, + }; + + TRandom* rn = new TRandom(); + + using EventCandidatesOrigin = soa::Join; + using TrackCandidatesOrigin = soa::Join; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgEventCutVertex; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfgTrackEtaMax && nabs(aod::track::pt) > cfgTrackPtMin); + Filter cutDCAFilter = (nabs(aod::track::dcaXY) < cfgTrackDCArToPVcutMax) && (nabs(aod::track::dcaZ) < cfgTrackDCAzToPVcutMax); + + using EventCandidates = soa::Filtered; + using TrackCandidates = soa::Filtered; + + using BinningTypeVertexContributor = ColumnBinningPolicy; + + 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 + void fillQA(const bool pass, const objType& obj, const int objecttype = 0) + { + if constexpr (requires { obj.posZ(); }) { + if (objecttype == QAEvent) { + if (!pass) { + histos.fill(HIST("EventQA/Vz_BC"), obj.posZ(), 1.0); + histos.fill(HIST("EventQA/CentDist_BC"), centrality, 1.0); + histos.fill(HIST("EventQA/Occupancy_BC"), obj.trackOccupancyInTimeRange(), 1.0); + } else { + histos.fill(HIST("EventQA/Vz_AC"), obj.posZ(), 1.0); + histos.fill(HIST("EventQA/CentDist_AC"), centrality, 1.0); + histos.fill(HIST("EventQA/Occupancy_AC"), obj.trackOccupancyInTimeRange(), 1.0); + } + } + if (objecttype == QAEP) { + if (!pass) { + histos.fill(HIST("EventQA/EPhist_BC"), centrality, eventPlaneDet); + histos.fill(HIST("EventQA/EPhistAB_BC"), centrality, std::cos(static_cast(nmode) * (eventPlaneDet - eventPlaneRefA))); + histos.fill(HIST("EventQA/EPhistAC_BC"), centrality, std::cos(static_cast(nmode) * (eventPlaneDet - eventPlaneRefB))); + histos.fill(HIST("EventQA/EPhistBC_BC"), centrality, std::cos(static_cast(nmode) * (eventPlaneRefA - eventPlaneRefB))); + } else { + histos.fill(HIST("EventQA/EPhist_AC"), centrality, eventPlaneDet); + histos.fill(HIST("EventQA/EPhistAB_AC"), centrality, std::cos(static_cast(nmode) * (eventPlaneDet - eventPlaneRefA))); + histos.fill(HIST("EventQA/EPhistAC_AC"), centrality, std::cos(static_cast(nmode) * (eventPlaneDet - eventPlaneRefB))); + histos.fill(HIST("EventQA/EPhistBC_AC"), centrality, std::cos(static_cast(nmode) * (eventPlaneRefA - eventPlaneRefB))); + } + } + } + if constexpr (requires { obj.tpcCrossedRowsOverFindableCls(); }) { + if (objecttype == QATrack) { + if (!pass) { + histos.fill(HIST("TrackQA/DCArToPv_BC"), obj.dcaXY()); + histos.fill(HIST("TrackQA/DCAzToPv_BC"), obj.dcaZ()); + histos.fill(HIST("TrackQA/IsPrim_BC"), obj.isPrimaryTrack()); + histos.fill(HIST("TrackQA/IsGood_BC"), obj.isGlobalTrackWoDCA()); + histos.fill(HIST("TrackQA/IsPrimCont_BC"), obj.isPVContributor()); + histos.fill(HIST("TrackQA/FindableTPCClusters_BC"), obj.tpcNClsFindable()); + histos.fill(HIST("TrackQA/FindableTPCRows_BC"), obj.tpcNClsCrossedRows()); + histos.fill(HIST("TrackQA/ClustersVsRows_BC"), obj.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("TrackQA/TPCChi2_BC"), obj.tpcChi2NCl()); + } else { + histos.fill(HIST("TrackQA/DCArToPv_AC"), obj.dcaXY()); + histos.fill(HIST("TrackQA/DCAzToPv_AC"), obj.dcaZ()); + histos.fill(HIST("TrackQA/IsPrim_AC"), obj.isPrimaryTrack()); + histos.fill(HIST("TrackQA/IsGood_AC"), obj.isGlobalTrackWoDCA()); + histos.fill(HIST("TrackQA/IsPrimCont_AC"), obj.isPVContributor()); + histos.fill(HIST("TrackQA/FindableTPCClusters_AC"), obj.tpcNClsFindable()); + histos.fill(HIST("TrackQA/FindableTPCRows_AC"), obj.tpcNClsCrossedRows()); + histos.fill(HIST("TrackQA/ClustersVsRows_AC"), obj.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("TrackQA/TPCChi2_AC"), obj.tpcChi2NCl()); + } + } + if (objecttype == QAPID) { + if (!pass) { + histos.fill(HIST("PIDQA/Nsigma_TPC_BC"), obj.pt(), getTpcNSigma(obj)); + histos.fill(HIST("PIDQA/Nsigma_TOF_BC"), obj.pt(), getTofNSigma(obj)); + histos.fill(HIST("PIDQA/TPC_TOF_BC"), getTpcNSigma(obj), getTofNSigma(obj)); + } else { + histos.fill(HIST("PIDQA/Nsigma_TPC_AC"), obj.pt(), getTpcNSigma(obj)); + histos.fill(HIST("PIDQA/Nsigma_TOF_AC"), obj.pt(), getTofNSigma(obj)); + histos.fill(HIST("PIDQA/TPC_TOF_AC"), getTpcNSigma(obj), getTofNSigma(obj)); + } + } + } + } + + template + bool eventSelected(TCollision collision, const bool QA) + { + if (cfgQAEventCut && QA) + fillQA(false, collision, 1); + if (cfgQAEPCut && QA) + fillQA(false, collision, 2); + // if (cfgQAEventFlowCut) histos.fill(HIST("EventQA/hnEvents"), 0); + // + if (std::abs(collision.posZ()) > cfgEventCutVertex) { + return 0; + } + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 1); + + if (!collision.sel8()) { + return 0; + } + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 2); + + if (cfgEventGoodZvtxSel && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return 0; + } + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 3); + + if (cfgEventNSamePileupSel && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return 0; + } + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 4); + + if (cfgEventNCollinTRSel && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return 0; + } + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 5); + + if (cfgEventQvecSel && (collision.qvecAmp()[detId] < QvecAmpMin || collision.qvecAmp()[refAId] < QvecAmpMin || collision.qvecAmp()[refBId] < QvecAmpMin)) { + return 0; + } + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 6); + + if (cfgEventOccupancySel && (collision.trackOccupancyInTimeRange() > cfgEventOccupancyMax || collision.trackOccupancyInTimeRange() < cfgEventOccupancyMin)) { + return 0; + } + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 7); + + if (cfgEventCentMax < centrality) { + return 0; + } + /* + auto multNTracksPV = collision.multNTracksPV(); + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) { + return 0; + } + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) { + return 0; + } + */ + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 8); + + if (cfgEventPVSel && std::abs(collision.posZ()) > cfgEventPV) { + return 0; + } + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 9); + + // All passed + if (cfgQAEventFlowCut && QA) + histos.fill(HIST("EventQA/hnEvents"), 10); + return 1; + } // event selection + + template + bool trackSelected(const TrackType track, const bool QA) + { + if (cfgQATrackCut && QA) + fillQA(false, track, 3); + // + if (std::abs(track.pt()) < cfgTrackPtMin) { + return 0; + } + if (std::abs(track.eta()) > cfgTrackEtaMax) { + return 0; + } + if (std::abs(track.dcaXY()) > cfgTrackDCArToPVcutMax) { + return 0; + } + if (std::abs(track.dcaZ()) > cfgTrackDCAzToPVcutMax) { + return 0; + } + if (cfgTrackIsPVContributor && !track.isPVContributor()) { + return 0; + } + if (cfgTrackIsPrimaryTrack && !track.isPrimaryTrack()) { + return 0; + } + if (cfgTrackIsGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) { + return 0; + } + if (cfgTrackNTPCCrossedRows > 0 && track.tpcNClsCrossedRows() < cfgTrackNTPCCrossedRows) { + return 0; + } + if (cfgTrackNFindableTPCClusters > 0 && track.tpcNClsFindable() < cfgTrackNFindableTPCClusters) { + return 0; + } + if (cfgTrackNRowsOverFindable > 0 && track.tpcCrossedRowsOverFindableCls() > cfgTrackNRowsOverFindable) { + return 0; + } + if (cfgTrackNTPCChi2 > 0 && track.tpcChi2NCl() > cfgTrackNTPCChi2) { + return 0; + } + if (cfgTrackNITSChi2 > 0 && track.itsChi2NCl() > cfgTrackNITSChi2) { + return 0; + } + return 1; + } + + template + bool selectionPID(const TrackType track, const bool QA) + { + if (QA) + fillQA(false, track, 4); + // + if (cfgListPID == PIDList::PIDRun3) { + if (cfgPIDUSETOF) { + if (std::abs(track.tofNSigmaPi()) > cfgPIDMaxTOFnSigmaPion) { + return 0; + } + if (std::abs(track.tpcNSigmaPi()) > cfgPIDMaxTPCnSigmaPion) { + return 0; + } + } + if (std::abs(track.tpcNSigmaPi()) > cfgPIDMaxTPCnSigmaPionS) { + return 0; + } + } else if (cfgListPID == PIDList::PIDRun2) { + if (cfgPIDUSETOF) { + if (track.hasTOF()) { + if (std::abs(track.tofNSigmaPi()) > cfgPIDMaxTOFnSigmaPion) { + return 0; + } + if (std::abs(track.tpcNSigmaPi()) > cfgPIDMaxTPCnSigmaPion) { + return 0; + } + } else { + if (std::abs(track.tpcNSigmaPi()) > cfgPIDMaxTPCnSigmaPionS) { + return 0; + } + } + } else { + if (std::abs(track.tpcNSigmaPi()) > cfgPIDMaxTPCnSigmaPionS) { + return 0; + } + } + } else if (cfgListPID == PIDList::PIDTest) { + if (cfgPIDUSETOF) { + if (track.hasTOF()) { + if ((getTpcNSigma(track) * getTpcNSigma(track) + getTofNSigma(track) * getTofNSigma(track)) > (cfgPIDMaxTiednSigmaPion * cfgPIDMaxTiednSigmaPion)) { + return 0; + } + } else { + if (std::abs(getTpcNSigma(track)) > cfgPIDMaxTPCnSigmaPionS) { + return 0; + } + } + } else { + if (std::abs(getTpcNSigma(track)) > cfgPIDMaxTPCnSigmaPionS) { + return 0; + } + } + } + return 1; + } + + template + bool pairAngleSelection(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 (cfgPhiDeepAngleSel && angle < cfgPhiDeepAngle) { + return 0; + } + return 1; + } + + template + float getTpcNSigma(const TrackType track) + { + if (cfgListPtl == PtlList::PtlPion) { + return track.tpcNSigmaPi(); + } else { + return track.tpcNSigmaKa(); + } + } + + template + float getTofNSigma(const TrackType track) + { + if (cfgListPtl == PtlList::PtlPion) { + return track.tofNSigmaPi(); + } else { + return track.tofNSigmaKa(); + } + } + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks) + { + qVecDetInd = detId * 4 + 3 + (nmode - 2) * cfgQvecNum * 4; + qVecRefAInd = refAId * 4 + 3 + (nmode - 2) * cfgQvecNum * 4; + qVecRefBInd = refBId * 4 + 3 + (nmode - 2) * cfgQvecNum * 4; + + eventPlaneDet = std::atan2(collision.qvecIm()[qVecDetInd], collision.qvecRe()[qVecDetInd]) / static_cast(nmode); + eventPlaneRefA = std::atan2(collision.qvecIm()[qVecRefAInd], collision.qvecRe()[qVecRefAInd]) / static_cast(nmode); + eventPlaneRefB = std::atan2(collision.qvecIm()[qVecRefBInd], collision.qvecRe()[qVecRefBInd]) / static_cast(nmode); + + fillQA(true, collision, 2); // EP QA + + ROOT::Math::PxPyPzMVector pion1, pion2, pion2Rot, reco, recoRot; + for (const auto& trk1 : dTracks) { + if (!trackSelected(trk1, true)) { + continue; + } + if (cfgQATrackCut) + fillQA(true, trk1, 3); + + if (!selectionPID(trk1, true)) { + continue; + } + fillQA(true, trk1, 4); + + for (const auto& trk2 : dTracks) { + if (trk1.globalIndex() >= trk2.globalIndex()) { + continue; + } + + if (!trackSelected(trk2, false)) { + continue; + } + + // PID + if (!selectionPID(trk2, false)) { + continue; + } + + if (cfgPhiDeepAngleSel && !pairAngleSelection(trk1, trk2)) { + continue; + } + + pion1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massPtl); + pion2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massPtl); + reco = pion1 + pion2; + + if (reco.Rapidity() > cfgTrackRapMax || reco.Rapidity() < cfgTrackRapMin) { + 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 (cfgBkgRotSel && trk1.sign() * trk2.sign() < 0) { + for (int nr = 0; nr < cfgBkgRotNum; 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 = ROOT::Math::PxPyPzMVector(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 processEventMixing(EventCandidates const& collisions, TrackCandidates const& tracks) + { + // nmode = 2; // second order + qVecDetInd = detId * 4 + 3 + (nmode - 2) * cfgQvecNum * 4; + + auto trackTuple = std::make_tuple(tracks); + BinningTypeVertexContributor binningOnPositions{{mixAxisVertex, mixAxisCent}, true}; + SameKindPair pair{binningOnPositions, cfgBkgMixedNum, -1, collisions, trackTuple, &cache}; + ROOT::Math::PxPyPzMVector ptl1, ptl2, recoPtl; + for (const auto& [c1, t1, c2, t2] : pair) { + if (cfgEventCentEst == CentEstList::FT0C) { + centrality = c1.centFT0C(); + } else if (cfgEventCentEst == CentEstList::FT0M) { + centrality = c1.centFT0M(); + } + if (!eventSelected(c1, false) || !eventSelected(c2, false)) { + continue; + } + if (c1.bcId() == c2.bcId()) { + continue; + } + double eventPlaneDet = std::atan2(c1.qvecIm()[qVecDetInd], c1.qvecRe()[qVecDetInd]) / static_cast(nmode); + + for (const auto& trk1 : t1) { + if (!trackSelected(trk1, false)) { + continue; + } + if (!selectionPID(trk1, false)) { + continue; + } + + for (const auto& trk2 : t2) { + if (!trackSelected(trk2, false)) { + continue; + } + if (!selectionPID(trk2, false)) { + continue; + } + // if (!pairIndexSelection(trk1, trk2)) { + // continue; + // } + if (cfgPhiDeepAngleSel && !pairAngleSelection(trk1, trk2)) { + continue; + } + ptl1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massPtl); + ptl2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massPtl); + recoPtl = ptl1 + ptl2; + if (recoPtl.Rapidity() > cfgTrackRapMax || recoPtl.Rapidity() < cfgTrackRapMin) { + continue; + } + + relPhiMix = TVector2::Phi_0_2pi((recoPtl.Phi() - eventPlaneDet) * static_cast(nmode)); + + if (trk1.sign() * trk2.sign() < 0) { + histos.fill(HIST("hInvMass_f0980_MixedUS_EPA"), recoPtl.M(), recoPtl.Pt(), centrality, relPhiMix); + } + } + } + } + } + PROCESS_SWITCH(F0980pbpbanalysis, processEventMixing, "Process Event mixing", false); + + void processTotalEvent(EventCandidatesOrigin const& events) + { + if (cfgQAEventFlowCut) { + nTotalEvents += events.size(); + auto hTotalEvents = histos.get(HIST("EventQA/hnEvents")); + if (hTotalEvents) { + hTotalEvents->SetBinContent(1, static_cast(nTotalEvents)); + } + } + } + PROCESS_SWITCH(F0980pbpbanalysis, processTotalEvent, "fill Total nEvents once", false); + + void init(o2::framework::InitContext&) + { + 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}; + + // Event QA + if (cfgQAEventCut) { + histos.add("EventQA/CentDist_BC", "", {HistType::kTH1F, {qaCentAxis}}); + histos.add("EventQA/Vz_BC", "", {HistType::kTH1F, {qaVzAxis}}); + histos.add("EventQA/Occupancy_BC", "", kTH1F, {{histAxisOccupancy}}); + } + histos.add("EventQA/CentDist_AC", "", {HistType::kTH1F, {qaCentAxis}}); + histos.add("EventQA/Vz_AC", "", {HistType::kTH1F, {qaVzAxis}}); + histos.add("EventQA/Occupancy_AC", "", kTH1F, {{histAxisOccupancy}}); + + // Track QA + if (cfgQATrackCut) { + histos.add("TrackQA/DCArToPv_BC", "", {HistType::kTH1F, {histAxisDCAz}}); + histos.add("TrackQA/DCAzToPv_BC", "", {HistType::kTH1F, {histAxisDCAz}}); + histos.add("TrackQA/IsPrim_BC", "", kTH1F, {{2, -0.5, 1.5}}); + histos.add("TrackQA/IsGood_BC", "", kTH1F, {{2, -0.5, 1.5}}); + histos.add("TrackQA/IsPrimCont_BC", "", kTH1F, {{2, -0.5, 1.5}}); + histos.add("TrackQA/FindableTPCClusters_BC", "", kTH1F, {{200, 0, 200}}); + histos.add("TrackQA/FindableTPCRows_BC", "", kTH1F, {{200, 0, 200}}); + histos.add("TrackQA/ClustersVsRows_BC", "", kTH1F, {{200, 0, 2}}); + histos.add("TrackQA/TPCChi2_BC", "", kTH1F, {{200, 0, 100}}); + histos.add("TrackQA/ITSChi2_BC", "", kTH1F, {{200, 0, 100}}); + // + histos.add("TrackQA/DCArToPv_AC", "", {HistType::kTH1F, {histAxisDCAz}}); + histos.add("TrackQA/DCAzToPv_AC", "", {HistType::kTH1F, {histAxisDCAz}}); + histos.add("TrackQA/IsPrim_AC", "", kTH1F, {{2, -0.5, 1.5}}); + histos.add("TrackQA/IsGood_AC", "", kTH1F, {{2, -0.5, 1.5}}); + histos.add("TrackQA/IsPrimCont_AC", "", kTH1F, {{2, -0.5, 1.5}}); + histos.add("TrackQA/FindableTPCClusters_AC", "", kTH1F, {{200, 0, 200}}); + histos.add("TrackQA/FindableTPCRows_AC", "", kTH1F, {{200, 0, 200}}); + histos.add("TrackQA/ClustersVsRows_AC", "", kTH1F, {{200, 0, 2}}); + histos.add("TrackQA/TPCChi2_AC", "", kTH1F, {{200, 0, 100}}); + histos.add("TrackQA/ITSChi2_AC", "", kTH1F, {{200, 0, 100}}); + } + + // PID QA + histos.add("PIDQA/Nsigma_TPC_BC", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + histos.add("PIDQA/Nsigma_TOF_BC", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + histos.add("PIDQA/TPC_TOF_BC", "", {HistType::kTH2F, {qaPIDAxis, qaPIDAxis}}); + // + histos.add("PIDQA/Nsigma_TPC_AC", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + histos.add("PIDQA/Nsigma_TOF_AC", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + histos.add("PIDQA/TPC_TOF_AC", "", {HistType::kTH2F, {qaPIDAxis, qaPIDAxis}}); + // + // histos.add("PIDQA/Nsigma_TPC_selected", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + // histos.add("PIDQA/Nsigma_TOF_selected", "", {HistType::kTH2F, {qaPtAxis, qaPIDAxis}}); + // histos.add("PIDQA/TPC_TOF_selected", "", {HistType::kTH2F, {qaPIDAxis, qaPIDAxis}}); + + // Event Plane QA + if (cfgQAEPCut) { + histos.add("EventQA/EPhist_BC", "", {HistType::kTH2F, {qaCentAxis, qaEpAxis}}); + histos.add("EventQA/EPhistAB_BC", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + histos.add("EventQA/EPhistAC_BC", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + histos.add("EventQA/EPhistBC_BC", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + } + // + histos.add("EventQA/EPhist_AC", "", {HistType::kTH2F, {qaCentAxis, qaEpAxis}}); + histos.add("EventQA/EPhistAB_AC", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + histos.add("EventQA/EPhistAC_AC", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + histos.add("EventQA/EPhistBC_AC", "", {HistType::kTH2F, {qaCentAxis, epresAxis}}); + + // Invariant Mass Histograms + histos.add("hInvMass_f0980_US_EPA", "unlike invariant mass", + {HistType::kTHnSparseF, {axisMass, axisPT, axisCent, axisEp}}); + histos.add("hInvMass_f0980_LSpp_EPA", "++ invariant mass", + {HistType::kTHnSparseF, {axisMass, axisPT, axisCent, axisEp}}); + histos.add("hInvMass_f0980_LSmm_EPA", "-- invariant mass", + {HistType::kTHnSparseF, {axisMass, axisPT, axisCent, axisEp}}); + histos.add("hInvMass_f0980_USRot_EPA", "unlike invariant mass Rotation", + {HistType::kTHnSparseF, {axisMass, axisPT, axisCent, axisEp}}); + histos.add("hInvMass_f0980_MixedUS_EPA", "unlike invariant mass EventMixing", + {HistType::kTHnSparseF, {axisMass, axisPT, axisCent, axisEp}}); + // 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, {axisMass, qaPtAxis, axisCent}); + // } + + // Event Histograms + if (cfgQAEventFlowCut) { + histos.add("EventQA/hnEvents", "Event selection steps", {HistType::kTH1F, {{11, -0.5, 10.5}}}); + std::shared_ptr hEventsCutFlow = histos.get(HIST("EventQA/hnEvents")); + std::vector eventCutLabels = { + "All Events", + "Zvtx", + "sel8", + "GoodZvtxFT0vsPV", + "NoSameBunchPileup", + "NoCollInTimeRangeStandard", + "Qvec Amplitude", + "Occupancy", + "Centrality", + "Additional PV cut", + "Passed Events"}; + for (size_t i = 0; i < eventCutLabels.size(); ++i) { + hEventsCutFlow->GetXaxis()->SetBinLabel(i + 1, eventCutLabels[i].c_str()); + } + } + + 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 (cfgListPtl == PtlList::PtlPion) { + massPtl = o2::constants::physics::MassPionCharged; + } else if (cfgListPtl == 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 (cfgEventCentEst == CentEstList::FT0C) { + centrality = collision.centFT0C(); + } else if (cfgEventCentEst == CentEstList::FT0M) { + centrality = collision.centFT0M(); + } + if (!eventSelected(collision, true)) { + return; + } + fillQA(true, collision, 1); // Event QA + + fillHistograms(collision, tracks); + }; + PROCESS_SWITCH(F0980pbpbanalysis, processData, "Process Event for data", false); +}; + +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..5424379d0b7 100644 --- a/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx +++ b/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx @@ -13,69 +13,188 @@ /// \author sourav kundu /// \since 02/11/2023 +#include "PWGLF/DataModel/ReducedF1ProtonTables.h" + +#include "Common/Core/trackUtilities.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" #include -#include + #include #include +#include #include + #include + #include #include #include -#include "Framework/AnalysisTask.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/ReducedF1ProtonTables.h" -#include "CommonConstants/PhysicsConstants.h" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; struct f1protoncorrelation { + + double bz = 0.; + double bz2 = 0.; + + // Enable access to the CCDB for the offset and correction constants and save them in dedicated variables. + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + 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; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // 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 momentumProtonMin{"momentumProtonMin", 0.1, "Minimum proton momentum"}; Configurable lowPtF1{"lowPtF1", 1.0, "PT cut F1"}; + Configurable nRot{"nRot", 4, "Number of rotational bkg"}; // Event Mixing - Configurable nEvtMixing{"nEvtMixing", 1, "Number of events to mix"}; + Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; + Configurable nEvtMixingBkg{"nEvtMixingBkg", 5, "Number of events to mix for background reconstruction"}; 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"}; + ConfigurableAxis configThnAxisCharge{"configThnAxisCharge", {5, -2.5, 2.5}, "Charge"}; + + // 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"}; + const AxisSpec thnAxisCharge{configThnAxisCharge, "Charge"}; + const AxisSpec thnAxisMultiplicity{CfgMultBins, "Multiplicity"}; + // 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("hPhaseSpaceProtonKaonSame", "hPhaseSpaceProtonKaonSame", kTH3F, {{40, -2.0f, 2.0f}, {180, -2.0 * TMath::Pi(), 2.0 * TMath::Pi()}, {100, 0.0, 1.0}}); + histos.add("hPhaseSpaceProtonPionSame", "hPhaseSpaceProtonPionSame", kTH3F, {{40, -2.0f, 2.0f}, {180, -2.0 * TMath::Pi(), 2.0 * TMath::Pi()}, {100, 0.0, 1.0}}); + histos.add("hPhaseSpaceProtonKaonMix", "hPhaseSpaceProtonKaonMix", kTH3F, {{40, -2.0f, 2.0f}, {180, -2.0 * TMath::Pi(), 2.0 * TMath::Pi()}, {100, 0.0, 1.0}}); + histos.add("hPhaseSpaceProtonPionMix", "hPhaseSpaceProtonPionMix", kTH3F, {{40, -2.0f, 2.0f}, {180, -2.0 * TMath::Pi(), 2.0 * TMath::Pi()}, {100, 0.0, 1.0}}); + + 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", kTHnSparseF, {thnAxisKstar, thnAxisPt, thnAxisInvMass, thnAxisCharge, thnAxisMultiplicity}); + histos.add("h2SameEventInvariantMassLike_mass", "Like Sign Invariant mass of f1 same event", kTHnSparseF, {thnAxisKstar, thnAxisPt, thnAxisInvMass, thnAxisCharge, thnAxisMultiplicity}); + histos.add("h2SameEventInvariantMassRot_mass", "Rotational Invariant mass of f1 same event", kTHnSparseF, {thnAxisKstar, thnAxisPt, thnAxisInvMass, thnAxisCharge}); + + histos.add("h2MixEventInvariantMassUnlike_mass", "Unlike Sign Invariant mass of f1 mix event", kTHnSparseF, {thnAxisKstar, thnAxisPt, thnAxisInvMass, thnAxisCharge, thnAxisMultiplicity}); + histos.add("h2MixEventInvariantMassLike_mass", "Like Sign Invariant mass of f1 mix event", kTHnSparseF, {thnAxisKstar, thnAxisPt, thnAxisInvMass, thnAxisCharge, thnAxisMultiplicity}); + histos.add("h2MixEventInvariantMassRot_mass", "Rotational Sign Invariant mass of f1 mix event", kTHnSparseF, {thnAxisKstar, thnAxisPt, thnAxisInvMass, thnAxisCharge}); + + histos.add("h2MixEventInvariantMassUnlike_mass_SEFP", "Unlike-sign invariant mass of f1 mix event (SE-F1P: π mixed, p same event)", kTHnSparseF, {thnAxisKstar, thnAxisPt, thnAxisInvMass, thnAxisCharge}); + histos.add("h2MixEventInvariantMassUnlike_mass_DEFP", "Unlike-sign invariant mass of f1 mix event (DE-F1P: π + p mixed)", kTHnSparseF, {thnAxisKstar, thnAxisPt, thnAxisInvMass, thnAxisCharge}); + + if (fillSparse) { + histos.add("SEMassUnlike", "SEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma, thnAxisCharge}); + histos.add("SEMassLike", "SEMassLike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma, thnAxisCharge}); + histos.add("SEMassRot", "SEMassRot", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma, thnAxisCharge}); + + histos.add("MEMassUnlike", "MEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma, thnAxisCharge}); + histos.add("MEMassLike", "MEMassLike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma, thnAxisCharge}); + histos.add("MEMassRot", "MEMassRot", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisPtProton, thnAxisKstar, thnAxisNsigma, thnAxisCharge}); + } + + 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 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 %2.2f kG", timestamp, 0.1 * grpo->getNominalL3Field()); + } + return 0.1 * grpo->getNominalL3Field(); + } + + /// Magnetic field to be provided in Tesla + static constexpr float tmpRadiiTPC[9] = {85., 105., 125., 145., 165., 185., 205., 225., 245.}; + float PhiAtSpecificRadiiTPC(const TLorentzVector part1, const TLorentzVector part2, float charge1 = 0, int charge2 = 0, float magfield1 = 0.0, float magfield2 = 0.0) + { + float pt1 = part1.Pt(); + float phi1 = part1.Phi(); + float value1 = 0.0; + float count1 = 0.0; + for (size_t i = 0; i < 9; i++) { + auto arg1 = 0.3 * charge1 * magfield1 * tmpRadiiTPC[i] * 0.01 / (2. * pt1); + if (std::fabs(arg1) < 1) { + value1 = value1 + (phi1 - std::asin(arg1)); + count1 = count1 + 1.0; + } + } + value1 = value1 / count1; + + float pt2 = part2.Pt(); + float phi2 = part2.Phi(); + float value2 = 0.0; + float count2 = 0.0; + for (size_t i = 0; i < 9; i++) { + auto arg2 = 0.3 * charge2 * magfield2 * tmpRadiiTPC[i] * 0.01 / (2. * pt2); + if (std::fabs(arg2) < 1) { + value2 = value2 + (phi2 - std::asin(arg2)); + count2 = count2 + 1.0; + } + } + value2 = value2 / count2; + return value1 - value2; } // get kstar @@ -100,71 +219,136 @@ 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; // Process the data in same event - void process(aod::RedF1PEvents::iterator const& /*collision*/, aod::F1Tracks const& f1tracks, aod::ProtonTracks const& protontracks) + + int currentRunNumber = -999; + int lastRunNumber = -999; + + void process(aod::RedF1PEvents::iterator const& collision, aod::F1Tracks const& f1tracks, aod::ProtonTracks const& protontracks) { + + // auto bc = collision.template bc_as(); + // currentRunNumber = collision.bc_as().runNumber(); + currentRunNumber = collision.runNumber(); + if (currentRunNumber != lastRunNumber) { + bz = getMagneticField(collision.timestamp()); + } + lastRunNumber = currentRunNumber; + 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 || Proton.Pt() < momentumProtonMin) { + 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() > 0) { + // check charge + float pairCharge = f1track.f1SignalStat() * protontrack.protonCharge(); + int f1Charge = f1track.f1SignalStat(); + int pionCharge = -1; + int kaonCharge = 1; + if (f1Charge == 2) { + pionCharge = 1; + kaonCharge = -1; } - } - 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 + histos.fill(HIST("hPhaseSpaceProtonKaonSame"), Proton.Eta() - Kaon.Eta(), PhiAtSpecificRadiiTPC(Proton, Kaon, protontrack.protonCharge(), kaonCharge, bz, bz), relative_momentum); // Phase Space Proton kaon + histos.fill(HIST("hPhaseSpaceProtonPionSame"), Proton.Eta() - Kaon.Eta(), PhiAtSpecificRadiiTPC(Proton, Pion, protontrack.protonCharge(), pionCharge, bz, bz), relative_momentum); // Phase Space Proton Pion + histos.fill(HIST("h2SameEventInvariantMassUnlike_mass"), relative_momentum, F1.Pt(), F1.M(), pairCharge, collision.numContrib()); // F1 sign = 1 unlike, F1 sign = -1 like + if (fillSparse) { + histos.fill(HIST("SEMassUnlike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC, pairCharge); } - if (f1track.f1SignalStat() == -1) { - histos.fill(HIST("h2SameEventInvariantMassLike_mass102"), relative_momentum, F1.Pt(), F1.M()); + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nRot; 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 rotPionPx = Pion.Px() * std::cos(rotangle) - Pion.Py() * std::sin(rotangle); + auto rotPionPy = Pion.Px() * std::sin(rotangle) + Pion.Py() * std::cos(rotangle); + PionRot.SetXYZM(rotPionPx, rotPionPy, Pion.Pz(), Pion.M()); + F1Rot = PionRot + KaonKshortPair; + if (F1Rot.Pt() < 1.0) { + continue; + } + auto relative_momentum_rot = getkstar(F1Rot, Proton); + histos.fill(HIST("h2SameEventInvariantMassRot_mass"), relative_momentum_rot, F1Rot.Pt(), F1Rot.M(), pairCharge); + if (fillSparse) { + histos.fill(HIST("SEMassRot"), F1Rot.M(), F1Rot.Pt(), Proton.Pt(), relative_momentum_rot, combinedTPC, pairCharge); + } + } } } - 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 (f1track.f1SignalStat() == -1) { + histos.fill(HIST("h2SameEventInvariantMassLike_mass"), relative_momentum, F1.Pt(), F1.M(), protontrack.protonCharge(), collision.numContrib()); + if (fillSparse) { + histos.fill(HIST("SEMassLike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC, protontrack.protonCharge()); } } } @@ -172,94 +356,290 @@ 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}; Preslice tracksPerCollisionPresliceF1 = aod::f1protondaughter::redF1PEventId; Preslice tracksPerCollisionPresliceP = aod::f1protondaughter::redF1PEventId; - void processME(aod::RedF1PEvents& collisions, aod::F1Tracks& f1tracks, aod::ProtonTracks& protontracks) + void processME(aod::RedF1PEvents& collisions, + aod::F1Tracks& f1tracks, + aod::ProtonTracks& protontracks) + { + for (auto const& [collision1, collision2] : + selfCombinations(colBinning, nEvtMixingBkg, -1, collisions, collisions)) { + if (collision1.index() == collision2.index()) + continue; + + // Preslices + auto f1_c1 = f1tracks.sliceBy(tracksPerCollisionPresliceF1, collision1.globalIndex()); + auto f1_c2 = f1tracks.sliceBy(tracksPerCollisionPresliceF1, collision2.globalIndex()); + auto p_c1 = protontracks.sliceBy(tracksPerCollisionPresliceP, collision1.globalIndex()); + auto p_c2 = protontracks.sliceBy(tracksPerCollisionPresliceP, collision2.globalIndex()); + + // ------------------------------- + // CASE 1: SE-F1P (π mixed from c2, K+K0s from c1, proton from c1) + // ------------------------------- + for (auto const& t1 : f1_c1) { + if (t1.f1MassKaonKshort() > maxKKS0Mass) + continue; + + Kaon.SetXYZM(t1.f1d2Px(), t1.f1d2Py(), t1.f1d2Pz(), 0.493); + Kshort.SetXYZM(t1.f1d3Px(), t1.f1d3Py(), t1.f1d3Pz(), 0.497); + KaonKshortPair = Kaon + Kshort; + + if (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 (Kaon.Pt() > 1.0 && (t1.f1d2TPC() < -2.5 || t1.f1d2TPC() > 2.5)) + continue; + } + if (strategyPIDKaon == 1 && + Kaon.Pt() > momentumTOFKaonMin && Kaon.Pt() <= momentumTOFKaonMax && + t1.f1d2TOFHit() != 1) + continue; + + for (auto const& t2 : p_c1) { // proton from c1 + Proton.SetXYZM(t2.protonPx(), t2.protonPy(), t2.protonPz(), 0.938); + if (Proton.Pt() > momentumProtonMax || Proton.Pt() < momentumProtonMin) + 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; + + for (auto const& t3 : f1_c2) { // pion source from c2 + Pion.SetXYZM(t3.f1d1Px(), t3.f1d1Py(), t3.f1d1Pz(), 0.139); + if (Pion.Pt() > maxMomentumPion) + continue; + if (pdepPID) { + if (Pion.Pt() < 2.0 && (t3.f1d1TPC() < -2.5 || t3.f1d1TPC() > 2.5)) + continue; + if (Pion.Pt() >= 2.0 && (t3.f1d1TPC() < -2.5 || t3.f1d1TPC() > 2.5)) + continue; + } + if (strategyPIDPion == 1 && + Pion.Pt() > momentumTOFPionMin && Pion.Pt() <= momentumTOFPionMax && + t3.f1d1TOFHit() != 1) + continue; + + // Fake f1: π(mixed) + (K+K0s from c1) + F1 = Pion + KaonKshortPair; + + // keep only unlike-sign branch + if (t1.f1SignalStat() <= 0) + continue; + + int f1Charge = t1.f1SignalStat(); + float pairQ = f1Charge * t2.protonCharge(); + + auto kstar = getkstar(F1, Proton); + + histos.fill(HIST("h2MixEventInvariantMassUnlike_mass_SEFP"), + kstar, F1.Pt(), F1.M(), pairQ); + } + } + } + + // ------------------------------- + // CASE 2: DE-F1P (π mixed from c2, K+K0s from c1, proton from c2) + // ------------------------------- + for (auto const& t1 : f1_c1) { + if (t1.f1MassKaonKshort() > maxKKS0Mass) + continue; + + Kaon.SetXYZM(t1.f1d2Px(), t1.f1d2Py(), t1.f1d2Pz(), 0.493); + Kshort.SetXYZM(t1.f1d3Px(), t1.f1d3Py(), t1.f1d3Pz(), 0.497); + KaonKshortPair = Kaon + Kshort; + + if (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 (Kaon.Pt() > 1.0 && (t1.f1d2TPC() < -2.5 || t1.f1d2TPC() > 2.5)) + continue; + } + if (strategyPIDKaon == 1 && + Kaon.Pt() > momentumTOFKaonMin && Kaon.Pt() <= momentumTOFKaonMax && + t1.f1d2TOFHit() != 1) + continue; + + for (auto const& t2 : p_c2) { // proton from c2 + Proton.SetXYZM(t2.protonPx(), t2.protonPy(), t2.protonPz(), 0.938); + if (Proton.Pt() > momentumProtonMax || Proton.Pt() < momentumProtonMin) + 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; + + for (auto const& t3 : f1_c2) { // pion from c2 + Pion.SetXYZM(t3.f1d1Px(), t3.f1d1Py(), t3.f1d1Pz(), 0.139); + if (Pion.Pt() > maxMomentumPion) + continue; + if (pdepPID) { + if (Pion.Pt() < 2.0 && (t3.f1d1TPC() < -2.5 || t3.f1d1TPC() > 2.5)) + continue; + if (Pion.Pt() >= 2.0 && (t3.f1d1TPC() < -2.5 || t3.f1d1TPC() > 2.5)) + continue; + } + if (strategyPIDPion == 1 && + Pion.Pt() > momentumTOFPionMin && Pion.Pt() <= momentumTOFPionMax && + t3.f1d1TOFHit() != 1) + continue; + + F1 = Pion + KaonKshortPair; + + if (t1.f1SignalStat() <= 0) + continue; + + int f1Charge = t1.f1SignalStat(); + float pairQ = f1Charge * t2.protonCharge(); + + auto kstar = getkstar(F1, Proton); + + histos.fill(HIST("h2MixEventInvariantMassUnlike_mass_DEFP"), + kstar, F1.Pt(), F1.M(), pairQ); + } + } + } + } + } + + PROCESS_SWITCH(f1protoncorrelation, processME, "Process EventMixing for combinatorial background (SE-F1P & DE-F1P, minimal)", false); + + void processMEOpti(aod::RedF1PEvents& collisions, aod::F1Tracks& f1tracks, aod::ProtonTracks& protontracks) { - for (auto& [collision1, collision2] : selfCombinations(colBinning, nEvtMixing, -1, collisions, collisions)) { + // 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; } - if (f1tracks.size() == 0 || protontracks.size() == 0) { - continue; + currentRunNumber = collision1.runNumber(); + if (currentRunNumber != lastRunNumber) { + bz = getMagneticField(collision1.timestamp()); + bz2 = getMagneticField(collision2.timestamp()); } + lastRunNumber = currentRunNumber; 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(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 || Proton.Pt() < momentumProtonMin) { continue; } - if (Proton.P() >= momentumTOFProton && t2.protonTOFHit() != 1 && TMath::Abs(t2.protonNsigmaTOF()) > 3) { + if (Proton.P() < momentumTOFProton && TMath::Abs(t2.protonNsigmaTPC()) > 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 (Proton.P() >= momentumTOFProton && (t2.protonTOFHit() != 1 || TMath::Abs(t2.protonNsigmaTOF()) > 2.5)) { + continue; } - 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_mass103"), relative_momentum, F1.Pt(), F1.M()); + auto relative_momentum = getkstar(F1, Proton); + if (t1.f1SignalStat() > 0) { + float pairCharge = t1.f1SignalStat() * t2.protonCharge(); + int f1Charge = t1.f1SignalStat(); + int pionCharge = -1; + int kaonCharge = 1; + if (f1Charge == 2) { + pionCharge = 1; + kaonCharge = -1; } - } - 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 + histos.fill(HIST("h2MixEventInvariantMassUnlike_mass"), relative_momentum, F1.Pt(), F1.M(), pairCharge, collision1.numContrib()); // F1 sign = 1 unlike, F1 sign = -1 like + histos.fill(HIST("hPhaseSpaceProtonKaonMix"), Proton.Eta() - Kaon.Eta(), PhiAtSpecificRadiiTPC(Proton, Kaon, t2.protonCharge(), kaonCharge, bz, bz2), relative_momentum); // Phase Space Proton kaon + histos.fill(HIST("hPhaseSpaceProtonPionMix"), Proton.Eta() - Kaon.Eta(), PhiAtSpecificRadiiTPC(Proton, Pion, t2.protonCharge(), pionCharge, bz, bz2), relative_momentum); // Phase Space Proton Pion + if (fillSparse) { + histos.fill(HIST("MEMassUnlike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC, pairCharge); } - if (t1.f1SignalStat() == -1) { - histos.fill(HIST("h2MixEventInvariantMassLike_mass102"), relative_momentum, F1.Pt(), F1.M()); + + if (fillRotation) { + for (int nrotbkg = 0; nrotbkg < nRot; 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 rotPionPx = Pion.Px() * std::cos(rotangle) - Pion.Py() * std::sin(rotangle); + auto rotPionPy = Pion.Px() * std::sin(rotangle) + Pion.Py() * std::cos(rotangle); + PionRot.SetXYZM(rotPionPx, rotPionPy, Pion.Pz(), Pion.M()); + F1Rot = PionRot + KaonKshortPair; + if (F1Rot.Pt() < 1.0) { + continue; + } + auto relative_momentum_rot = getkstar(F1Rot, Proton); + if (t1.f1SignalStat() > 0) { + histos.fill(HIST("h2MixEventInvariantMassRot_mass"), relative_momentum_rot, F1Rot.Pt(), F1Rot.M(), pairCharge); + if (fillSparse) { + histos.fill(HIST("MEMassRot"), F1Rot.M(), F1Rot.Pt(), Proton.Pt(), relative_momentum_rot, combinedTPC, pairCharge); + } + } + } } } - 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 (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(), t2.protonCharge(), collision1.numContrib()); + if (fillSparse) { + histos.fill(HIST("MEMassLike"), F1.M(), F1.Pt(), Proton.Pt(), relative_momentum, combinedTPC, t2.protonCharge()); } } } } } - 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..71b5f251f08 --- /dev/null +++ b/PWGLF/Tasks/Resonances/higherMassResonances.cxx @@ -0,0 +1,1540 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.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/PIDResponseTOF.h" // +#include "Common/DataModel/PIDResponseTPC.h" // +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" // +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" // +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#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; +using namespace o2::soa; +using namespace o2::aod::rctsel; +// 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 { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + RCTFlagsChecker rctChecker; + + enum MultEstimator { + kFT0M, + kFT0A, + kFT0C, + kFV0A, + kFV0C, + kFV0M, + kNEstimators + }; + + struct : ConfigurableGroup { + // PID and QA + Configurable qAv0{"qAv0", false, "qAv0"}; + Configurable qAPID{"qAPID", true, "qAPID"}; + Configurable qAevents{"qAevents", false, "QA of events"}; + Configurable correlation2Dhist{"correlation2Dhist", true, "Lamda K0 mass correlation"}; + Configurable isApplyDCAv0topv{"isApplyDCAv0topv", false, "DCA V0 to PV"}; + Configurable hasTPC{"hasTPC", false, "TPC"}; + Configurable isselectTWOKsOnly{"isselectTWOKsOnly", true, "Select only events with two K0s"}; + Configurable isapplyPairRapidityRec{"isapplyPairRapidityRec", false, "Apply pair rapidity cut on reconstructed mother (after already applying rapidity cut on generated mother)"}; + Configurable isapplyPairRapidityGen{"isapplyPairRapidityGen", false, "Apply pair rapidity cut on generated mother (before applying rapidity cut on reconstructed mother)"}; + Configurable cSelectMultEstimator{"cSelectMultEstimator", 0, "Select multiplicity estimator: 0 - FT0M, 1 - FT0A, 2 - FT0C"}; + Configurable configOccCut{"configOccCut", 1000, "Occupancy cut"}; + Configurable isVertexTOFMatched{"isVertexTOFMatched", false, "Vertex TOF Matched"}; + Configurable isNoCollInTimeRangeStandard{"isNoCollInTimeRangeStandard", false, "No collision in time range standard"}; + Configurable isSel8{"isSel8", false, "Event Selection 8"}; + + // Configurables for event selection + // Configurable isINELgt0{"isINELgt0", true, "INEL>0 selection"}; + Configurable isTriggerTVX{"isTriggerTVX", false, "TriggerTVX"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", false, "IsGoodZvtxFT0vsPV"}; + Configurable isApplyOccCut{"isApplyOccCut", true, "Apply occupancy cut"}; + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable timFrameEvsel{"timFrameEvsel", true, "TPC Time frame boundary cut"}; + Configurable isNoSameBunchPileup{"isNoSameBunchPileup", true, "kNoSameBunchPileup"}; + Configurable isAllLayersGoodITS{"isAllLayersGoodITS", true, "Require all ITS layers to be good"}; + Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", true, "kNoTimeFrameBorder"}; + Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", true, "kNoITSROFrameBorder"}; + + // 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", 0.5, "DCA V0 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 confDaughPIDCutTPC{"confDaughPIDCutTPC", 5, "PID selections for KS0 daughters"}; + Configurable confDaughPIDCutTOF{"confDaughPIDCutTOF", 5, "PID selections for KS0 daughters in TOF"}; + Configurable confKsrapidity{"confKsrapidity", 0.5f, "Rapidity cut on K0s"}; + Configurable angSepCut{"angSepCut", 0.01f, "Angular separation cut"}; + Configurable isapplyAngSepCut{"isapplyAngSepCut", false, "Apply angular separation cut"}; + Configurable isStandardV0{"isStandardV0", false, "Standard V0 selection"}; + Configurable isApplyEtaCutK0s{"isApplyEtaCutK0s", false, "Apply eta cut on K0s daughters"}; + Configurable cfgETAcut{"cfgETAcut", 0.8f, "Track ETA cut"}; + + // Configurable for track selection and multiplicity + Configurable cfgPTcut{"cfgPTcut", 0.2f, "Track PT cut"}; + Configurable cfgNmixedEvents{"cfgNmixedEvents", 5, "Number of mixed events"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 5., 10., 30., 50., 70., 100., 110., 150.}, "Binning of the centrality axis"}; + + // Configurable for MC + Configurable isMC{"isMC", false, "Is MC"}; + Configurable isallGenCollisions{"isallGenCollisions", true, "To fill all generated collisions for the signal loss calculations"}; + Configurable iscTVXEvsel{"iscTVXEvsel", true, "Triggger selection"}; + Configurable isavoidsplitrackMC{"isavoidsplitrackMC", false, "avoid split track in MC"}; + Configurable isapplyRapidityMC{"isapplyRapidityMC", true, "Apply rapidity cut on generated and reconstructed particles"}; + Configurable selectMCparticles{"selectMCparticles", 1, "0: f0(1710), 1: f2(1525), 2: a2(1320), 3: f0(1370), 4: f0(1500), 5: f2(1270)"}; + std::vector pdgCodes = {10331, 335, 115, 10221, 9030221, 225}; + + // output THnSparses + Configurable activateHelicityFrame{"activateHelicityFrame", false, "Activate the THnSparse with cosThStar w.r.t. helicity axis"}; + Configurable activateCollinsSoperFrame{"activateCollinsSoperFrame", false, "Activate the THnSparse with cosThStar w.r.t. Collins soper axis"}; + Configurable activateProductionFrame{"activateProductionFrame", false, "Activate the THnSparse with cosThStar w.r.t. production axis"}; + Configurable activateBeamAxisFrame{"activateBeamAxisFrame", true, "Activate the THnSparse with cosThStar w.r.t. beam axis (Gottified jackson frame)"}; + Configurable activateRandomFrame{"activateRandomFrame", 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 isapplyCompetingcut{"isapplyCompetingcut", false, "Competing cascade rejection cut"}; + Configurable competingcascrejlambda{"competingcascrejlambda", 0.005, "rejecting competing cascade 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 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 configThnAxisPhi{"configThnAxisPhi", {70, 0.0f, 7.0f}, "Phi axis"}; // 0 to 2pi + ConfigurableAxis ksMassBins{"ksMassBins", {200, 0.45f, 0.55f}, "K0s invariant mass axis"}; + ConfigurableAxis cGlueMassBins{"cGlueMassBins", {200, 0.9f, 3.0f}, "Glueball invariant mass axis"}; + ConfigurableAxis cPtBins{"cPtBins", {200, 0.0f, 20.0f}, "Glueball pT axis"}; + + // fixed variables + float rapidityMotherData = 0.5; + float beamEnergy = 13600.0; + double beamMomentum = std::sqrt(beamEnergy * beamEnergy / 4 - o2::constants::physics::MassProton * o2::constants::physics::MassProton); // GeV + int noOfDaughters = 2; + } config; + + // Service PDGdatabase; + TRandom* rn = new TRandom(); + + // variables declaration + float multiplicity = 0.0f; + float theta2; + ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterRot, daughterRotCM, mother, motherRot, fourVecDauCM, fourVecDauCM1; + ROOT::Math::PxPyPzEVector mother1; + ROOT::Math::XYZVector randomVec, beamVec, normalVec; + ROOT::Math::XYZVectorF v1CM, zaxisHE, yaxisHE, xaxisHE; + // ROOT::Math::XYZVector threeVecDauCM, helicityVec, randomVec, beamVec, normalVec; + ROOT::Math::XYZVector zBeam; // ẑ: beam direction in lab frame + ROOT::Math::PxPyPzEVector beam1{0., 0., -config.beamMomentum, 13600. / 2.}; + ROOT::Math::PxPyPzEVector beam2{0., 0., config.beamMomentum, 13600. / 2.}; + ROOT::Math::XYZVectorF beam1CM, beam2CM, zAxisCS, yAxisCS, xAxisCS; + + // const double massK0s = o2::constants::physics::MassK0Short; + bool isMix = false; + + void init(InitContext const&) + { + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + // Axes + AxisSpec k0ShortMassAxis = {config.ksMassBins, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec glueballMassAxis = {config.cGlueMassBins, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {60, -15.f, 15.f, "vrtx_{Z} [cm]"}; // for histogram + AxisSpec ptAxis = {config.cPtBins, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec multiplicityAxis = {config.binsCent, "Multiplicity Axis"}; + AxisSpec thnAxisPOL{config.configThnAxisPOL, "Configurabel theta axis"}; + AxisSpec thnAxisPhi = {config.configThnAxisPhi, "Configurabel phi axis"}; // 0 to 2pi + + // THnSparses + std::array sparses = {config.activateHelicityFrame, config.activateCollinsSoperFrame, config.activateProductionFrame, config.activateBeamAxisFrame, config.activateRandomFrame}; + + if (std::accumulate(sparses.begin(), sparses.end(), 0) == 0) { + LOGP(fatal, "No output THnSparses enabled"); + } else { + if (config.activateHelicityFrame) { + LOGP(info, "THnSparse with cosThStar w.r.t. helicity axis active."); + } + if (config.activateCollinsSoperFrame) { + LOGP(info, "THnSparse with cosThStar w.r.t. Collins Soper axis active."); + } + if (config.activateProductionFrame) { + LOGP(info, "THnSparse with cosThStar w.r.t. production axis active."); + } + if (config.activateBeamAxisFrame) { + LOGP(info, "THnSparse with cosThStar w.r.t. beam axis active. (Gottified jackson frame)"); + } + if (config.activateRandomFrame) { + 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("htrackscheck_v0", "htrackscheck_v0", kTH1I, {{15, 0, 15}}); + rEventSelection.add("htrackscheck_v0_daughters", "htrackscheck_v0_daughters", kTH1I, {{15, 0, 15}}); + 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}}); + + rEventSelection.add("hEventCut", "No. of event after cuts", kTH1I, {{20, 0, 20}}); + std::shared_ptr hCutFlow = rEventSelection.get(HIST("hEventCut")); + hCutFlow->GetXaxis()->SetBinLabel(1, "All Events"); + hCutFlow->GetXaxis()->SetBinLabel(2, "|Vz| < cut"); + hCutFlow->GetXaxis()->SetBinLabel(3, "sel8"); + hCutFlow->GetXaxis()->SetBinLabel(4, "kNoTimeFrameBorder"); + hCutFlow->GetXaxis()->SetBinLabel(5, "kNoITSROFrameBorder"); + hCutFlow->GetXaxis()->SetBinLabel(6, "kNoSameBunchPileup"); + hCutFlow->GetXaxis()->SetBinLabel(7, "kIsGoodITSLayersAll"); + hCutFlow->GetXaxis()->SetBinLabel(8, "Occupancy Cut"); + hCutFlow->GetXaxis()->SetBinLabel(9, "rctChecker"); + hCutFlow->GetXaxis()->SetBinLabel(10, "kIsTriggerTVX"); + hCutFlow->GetXaxis()->SetBinLabel(11, "kIsGoodZvtxFT0vsPV"); + hCutFlow->GetXaxis()->SetBinLabel(12, "IsINELgt0"); + hCutFlow->GetXaxis()->SetBinLabel(13, "isVertexITSTPC"); + hCutFlow->GetXaxis()->SetBinLabel(14, "isVertexTOFMatched"); + + std::shared_ptr hv0label = rEventSelection.get(HIST("htrackscheck_v0")); + hv0label->GetXaxis()->SetBinLabel(1, "All Tracks"); + hv0label->GetXaxis()->SetBinLabel(2, "DCA V0 to PV"); + hv0label->GetXaxis()->SetBinLabel(3, "y K0s"); + hv0label->GetXaxis()->SetBinLabel(4, "Min V0 pT"); + hv0label->GetXaxis()->SetBinLabel(5, "Daughter DCA"); + hv0label->GetXaxis()->SetBinLabel(6, "CosPA"); + hv0label->GetXaxis()->SetBinLabel(7, "Decay Radius"); + hv0label->GetXaxis()->SetBinLabel(8, "Lifetime"); + hv0label->GetXaxis()->SetBinLabel(9, "CompetingCascade"); + hv0label->GetXaxis()->SetBinLabel(10, "Standard V0"); + hv0label->GetXaxis()->SetBinLabel(11, "Mass Tolerance"); + + std::shared_ptr hv0DauLabel = rEventSelection.get(HIST("htrackscheck_v0_daughters")); + hv0DauLabel->GetXaxis()->SetBinLabel(1, "AllDau Tracks"); + hv0DauLabel->GetXaxis()->SetBinLabel(2, "has TPC"); + hv0DauLabel->GetXaxis()->SetBinLabel(3, "TPC CrossedRows"); + hv0DauLabel->GetXaxis()->SetBinLabel(4, "TPC CRFC"); + hv0DauLabel->GetXaxis()->SetBinLabel(5, "TPC Chi2NCL"); + hv0DauLabel->GetXaxis()->SetBinLabel(6, "Charge"); + hv0DauLabel->GetXaxis()->SetBinLabel(7, "Eta"); + hv0DauLabel->GetXaxis()->SetBinLabel(8, "PID TPC"); + + std::shared_ptr hv0labelmcrec = hMChists.get(HIST("events_checkrec")); + hv0labelmcrec->GetXaxis()->SetBinLabel(1, "All Tracks"); + hv0labelmcrec->GetXaxis()->SetBinLabel(2, "V0Daughter Sel."); + hv0labelmcrec->GetXaxis()->SetBinLabel(3, "V0 Sel."); + hv0labelmcrec->GetXaxis()->SetBinLabel(4, "V0 PDG"); + hv0labelmcrec->GetXaxis()->SetBinLabel(5, "All Mothers"); + hv0labelmcrec->GetXaxis()->SetBinLabel(6, "Mother PDG"); + hv0labelmcrec->GetXaxis()->SetBinLabel(7, "Same Mother"); + hv0labelmcrec->GetXaxis()->SetBinLabel(8, "Split Track"); + hv0labelmcrec->GetXaxis()->SetBinLabel(9, "Global Index"); + hv0labelmcrec->GetXaxis()->SetBinLabel(10, "Generator"); + hv0labelmcrec->GetXaxis()->SetBinLabel(11, "Rapidity"); + + std::shared_ptr hv0labelmcgen = hMChists.get(HIST("events_check")); + hv0labelmcgen->GetXaxis()->SetBinLabel(1, "All Events"); + hv0labelmcgen->GetXaxis()->SetBinLabel(2, "Event Sel."); + hv0labelmcgen->GetXaxis()->SetBinLabel(3, "Event reconstructed"); + hv0labelmcgen->GetXaxis()->SetBinLabel(4, "PDG check"); + hv0labelmcgen->GetXaxis()->SetBinLabel(5, "Rapidity"); + hv0labelmcgen->GetXaxis()->SetBinLabel(6, "Daughters2"); + hv0labelmcgen->GetXaxis()->SetBinLabel(7, "PhysicalPrimary"); + hv0labelmcgen->GetXaxis()->SetBinLabel(8, "Daughters K0s"); + } + + hglue.add("h3glueInvMassDS", "h3glueInvMassDS", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL, thnAxisPhi}, true); + hglue.add("h3glueInvMassME", "h3glueInvMassME", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL, thnAxisPhi}, true); + hglue.add("h3glueInvMassRot", "h3glueInvMassRot", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL, thnAxisPhi}, true); + + // 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_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("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}); + } + + // For MC + if (config.isMC) { + hMChists.add("Genf1710", "Gen f_{0}(1710)", kTHnSparseF, {multiplicityAxis, ptAxis, thnAxisPOL}); + hMChists.add("Genf17102", "Gen f_{0}(1710)", kTHnSparseF, {multiplicityAxis, ptAxis, thnAxisPOL}); + hMChists.add("Recf1710_pt1", "Rec f_{0}(1710) p_{T}", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}); + hMChists.add("Recf1710_pt2", "Rec f_{0}(1710) p_{T}", kTHnSparseF, {multiplicityAxis, ptAxis, glueballMassAxis, thnAxisPOL}); + hMChists.add("h1Recsplit", "Rec p_{T}2", kTH1F, {ptAxis}); + hMChists.add("Genf1710_mass", "Gen f_{0}(1710) mass", kTH1F, {glueballMassAxis}); + hMChists.add("Genf1710_mass2", "Gen f_{0}(1710) mass", kTH1F, {glueballMassAxis}); + hMChists.add("GenPhi", "Gen Phi", kTH1F, {{70, 0.0, 7.0f}}); + hMChists.add("GenPhi2", "Gen Phi", kTH1F, {{70, 0.0, 7.0f}}); + hMChists.add("GenEta", "Gen Eta", kTHnSparseF, {{150, -1.5f, 1.5f}}); + hMChists.add("GenEta2", "Gen Eta", kTHnSparseF, {{150, -1.5f, 1.5f}}); + hMChists.add("GenRapidity", "Gen Rapidity", kTHnSparseF, {{100, -1.0f, 1.0f}}); + hMChists.add("GenRapidity2", "Gen Rapidity", kTHnSparseF, {{100, -1.0f, 1.0f}}); + hMChists.add("RecEta", "Rec Eta", kTH1F, {{150, -1.5f, 1.5f}}); + hMChists.add("RecEta2", "Rec Eta", kTH1F, {{150, -1.5f, 1.5f}}); + hMChists.add("RecPhi", "Rec Phi", kTH1F, {{70, 0.0f, 7.0f}}); + hMChists.add("RecPhi2", "Rec Phi", kTH1F, {{70, 0.0f, 7.0f}}); + hMChists.add("RecRapidity", "Rec Rapidity", kTH1F, {{100, -1.0f, 1.0f}}); + hMChists.add("RecRapidity2", "Rec Rapidity", kTH1F, {{100, -1.0f, 1.0f}}); + hMChists.add("Rec_Multiplicity", "Multiplicity in MC", kTH1F, {multiplicityAxis}); + hMChists.add("MC_mult_after_event_sel", "Multiplicity in MC", kTH1F, {multiplicityAxis}); + } + } + + template + bool selectionEvent(const Coll& collision, bool fillHist = true) + { + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 0); + + if (std::abs(collision.posZ()) > config.cutzvertex) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 1); + + if (config.isSel8 && !collision.sel8()) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 2); + + if (config.isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 3); + + if (config.isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 4); + + if (config.isNoSameBunchPileup && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup))) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 5); + + if (config.isAllLayersGoodITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 6); + + // if (config.isNoCollInTimeRangeStandard && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) + // return false; + + if (config.isApplyOccCut && (std::abs(collision.trackOccupancyInTimeRange()) > config.configOccCut)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 7); + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 8); + + if (config.isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 9); + + if (config.isGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 10); + + // if (config.isINELgt0 && !collision.isInelGt0()) { + // return false; + // } + // if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 11); + + // if (config.isVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + // return false; + // } + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 12); + + if (config.isVertexTOFMatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 13); + + 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 = o2::constants::physics::MassKPlus - config.cWidthKs0 * config.cSigmaMassKs0; + float highmasscutks0 = o2::constants::physics::MassKPlus + config.cWidthKs0 * config.cSigmaMassKs0; + + 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()); + } + if (config.correlation2Dhist) + rKzeroShort.fill(HIST("mass_lambda_kshort_before"), candidate.mK0Short(), candidate.mLambda()); + + rEventSelection.fill(HIST("htrackscheck_v0"), 0.5); + + if (config.isApplyDCAv0topv && std::fabs(candidate.dcav0topv()) > config.cMaxV0DCA) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 1.5); + + if (std::abs(candidate.rapidity(0)) >= config.confKsrapidity) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 2.5); + + if (pT < config.confV0PtMin) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 3.5); + + if (dcaDaughv0 > config.confV0DCADaughMax) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 4.5); + + if (cpav0 < config.confV0CPAMin) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 5.5); + + if (tranRad < config.confV0TranRadV0Min) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 6.5); + + if (tranRad > config.confV0TranRadV0Max) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 7.5); + + if (std::fabs(ctauK0s) > config.cMaxV0LifeTime) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 8.5); + + if (config.isapplyCompetingcut && (std::abs(candidate.mLambda() - o2::constants::physics::MassLambda0) <= config.competingcascrejlambda || std::abs(candidate.mAntiLambda() - o2::constants::physics::MassLambda0) <= config.competingcascrejlambda)) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 9.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()); + } + + if (config.isStandardV0 && candidate.v0Type() != 1) { + return false; // Only standard V0s are selected + } + rEventSelection.fill(HIST("htrackscheck_v0"), 10.5); + + if (candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0"), 11.5); + + return true; + } + + template + bool isSelectedV0Daughter(T const& track, float charge, double nsigmaV0DaughterTPC, V0s const& v0candidate) + { + 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()); + } + const auto eta = track.eta(); + const auto tpcNClsF = track.tpcNClsFound(); + const auto sign = track.sign(); + + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 0.5); + + if (config.hasTPC && !track.hasTPC()) + return false; + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 1.5); + + if (track.tpcNClsCrossedRows() < config.tpcCrossedrows) + return false; + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 2.5); + + if (track.tpcCrossedRowsOverFindableCls() < config.tpcCrossedrowsOverfcls) + return false; + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 3.5); + + if (tpcNClsF < config.confDaughTPCnclsMin) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 4.5); + + if (charge < 0 && sign > 0) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 5.5); + + if (charge > 0 && sign < 0) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 6.5); + + if (std::abs(eta) > config.confDaughEta) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 7.5); + + if (std::abs(nsigmaV0DaughterTPC) > config.confDaughPIDCutTPC) { + return false; + } + rEventSelection.fill(HIST("htrackscheck_v0_daughters"), 8.5); + + if (std::abs(v0candidate.tofNSigmaK0PiPlus()) > config.confDaughPIDCutTOF && v0candidate.positiveHasTOF()) { + return false; + } + + if (std::abs(v0candidate.tofNSigmaK0PiMinus()) > config.confDaughPIDCutTOF && v0candidate.negativeHasTOF()) { + return false; + } + + 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; + } + + using EventCandidatesDerivedData = soa::Join; + using V0CandidatesDerivedData = soa::Join; + // using DauTracks = soa::Join; + using DauTracks = soa::Join; + + template + bool isSelectedK0sDaughtersDerived(TV0 const& v0) + { + // Fpr derived dataset + + // de-ref track extras + auto posTrackExtra = v0.template posTrackExtra_as(); + auto negTrackExtra = v0.template negTrackExtra_as(); + + if (std::abs(v0.positiveeta()) > config.confDaughEta || std::abs(v0.negativeeta()) > config.confDaughEta) { + return false; + } + + if (posTrackExtra.tpcNClsCrossedRows() < config.tpcCrossedrows || negTrackExtra.tpcNClsCrossedRows() < config.tpcCrossedrows) { + return false; + } + + if (posTrackExtra.tpcNClsFound() < config.confDaughTPCnclsMin || negTrackExtra.tpcNClsFound() < config.confDaughTPCnclsMin) { + return false; + } + if (posTrackExtra.tpcCrossedRowsOverFindableCls() < config.tpcCrossedrowsOverfcls || negTrackExtra.tpcCrossedRowsOverFindableCls() < config.tpcCrossedrowsOverfcls) { + return false; + } + + // check TPC PID + if (((std::abs(posTrackExtra.tpcNSigmaPi()) > config.confDaughPIDCutTPC) || (std::abs(negTrackExtra.tpcNSigmaPi()) > config.confDaughPIDCutTPC))) { + return false; + } + + // // check TOF PID if TOF exists + + if (config.isApplyDCAv0topv && (std::abs(v0.dcapostopv()) < config.cMaxV0DCA || std::abs(v0.dcanegtopv()) < config.cMaxV0DCA)) { + return false; + } + + if (std::abs(v0.tofNSigmaK0PiPlus()) > config.confDaughPIDCutTOF && v0.positiveHasTOF()) { + return false; + } + + if (std::abs(v0.tofNSigmaK0PiMinus()) > config.confDaughPIDCutTOF && v0.negativeHasTOF()) { + return false; + } + + // rKzeroShort.fill(HIST("negative_pt"), negTrackExtra.pt()); + // rKzeroShort.fill(HIST("positive_pt"), posTrackExtra.pt()); + // rKzeroShort.fill(HIST("negative_eta"), negTrackExtra.eta()); + // rKzeroShort.fill(HIST("positive_eta"), posTrackExtra.eta()); + // rKzeroShort.fill(HIST("negative_phi"), negTrackExtra.phi()); + // rKzeroShort.fill(HIST("positive_phi"), posTrackExtra.phi()); + 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)); + if (config.qAv0) { + rKzeroShort.fill(HIST("angularSeparation"), angle); + } + if (config.isapplyAngSepCut && 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 = soa::Join; + // For Monte Carlo + using EventCandidatesMC = soa::Join; + using TrackCandidatesMC = soa::Filtered>; + using V0TrackCandidatesMC = soa::Filtered>; + // zBeam direction in lab frame + + template + void fillInvMass(const T& mother, float multiplicity, const T& daughter1, const T& daughter2, bool isMix) + { + + // //polarization calculations + // zBeam = ROOT::Math::XYZVector(0.f, 0.f, 1.f); // ẑ: beam direction in lab frame + + ROOT::Math::Boost boost{mother.BoostToCM()}; // define the boost to the center of mass frame + fourVecDauCM = boost(daughter1); // boost the frame of daughter to the center of mass frame + // threeVecDauCM = fourVecDauCM.Vect(); // get the 3 vector of daughter in the frame of mother + + beam1CM = ROOT::Math::XYZVectorF((boost(beam1).Vect()).Unit()); + beam2CM = ROOT::Math::XYZVectorF((boost(beam2).Vect()).Unit()); + + //========================Helicity and Production frame calculation========================== + // define y = zBeam x z: Normal to the production plane + // ẑ: mother direction in lab, boosted into mother's rest frame + + // auto motherLabDirection = ROOT::Math::XYZVector(0, 0, mother.Vect().Z()); // ẑ axis in lab frame + + // // ŷ = zBeam × ẑ + // auto y_axis = zBeam.Cross(motherLabDirection).Unit(); + + // // x̂ = ŷ × ẑ + // auto x_axis = y_axis.Cross(motherLabDirection).Unit(); + + // // Project daughter momentum onto x–y plane + // auto p_proj_x = threeVecDauCM.Dot(x_axis); + // auto p_proj_y = threeVecDauCM.Dot(y_axis); + + // // Calculate φ in [-π, π] + // auto anglePhi = std::atan2(p_proj_y, p_proj_x); // φ in radians + //============================================================================================= + + v1CM = ROOT::Math::XYZVectorF(boost(daughter1).Vect()).Unit(); + // ROOT::Math::XYZVectorF v2_CM{(boost(daughter1).Vect()).Unit()}; + // using positive sign convention for the first track + // ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1CM : v2_CM); // here selected decay daughter momentum is intested. here you can choose one decay daughter no need to check both case as it is neutral particle for our case + // Helicity Frame + zaxisHE = ROOT::Math::XYZVectorF(mother.Vect()).Unit(); + yaxisHE = ROOT::Math::XYZVectorF(beam1CM.Cross(beam2CM)).Unit(); + xaxisHE = ROOT::Math::XYZVectorF(yaxisHE.Cross(zaxisHE)).Unit(); + + // CosThetaHE = zaxisHE.Dot(v_CM); + + auto anglePhi = std::atan2(yaxisHE.Dot(v1CM), xaxisHE.Dot(v1CM)); + anglePhi = RecoDecay::constrainAngle(anglePhi, 0.0); + // if (anglePhi < 0) { + // anglePhi += o2::constants::math::TwoPI; // ensure phi is in [0, 2pi] + // } + + // CS Frame + zAxisCS = ROOT::Math::XYZVectorF((beam1CM.Unit() - beam2CM.Unit())).Unit(); + yAxisCS = ROOT::Math::XYZVectorF(beam1CM.Cross(beam2CM)).Unit(); + xAxisCS = ROOT::Math::XYZVectorF(yAxisCS.Cross(zAxisCS)).Unit(); + double cosThetaStarCS = zAxisCS.Dot(v1CM); + auto phiCS = std::atan2(yAxisCS.Dot(v1CM), xAxisCS.Dot(v1CM)); + phiCS = RecoDecay::constrainAngle(phiCS, 0.0); + + // if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + if (config.activateHelicityFrame) { + // helicityVec = mother.Vect(); // 3 vector of mother in COM frame + // auto cosThetaStarHelicity = helicityVec.Dot(threeVecDauCM) / (std::sqrt(threeVecDauCM.Mag2()) * std::sqrt(helicityVec.Mag2())); + auto cosThetaStarHelicity = mother.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(mother.Vect().Mag2())); + if (!isMix) { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity, anglePhi); + } + + 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); + + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + + motherRot = daughterRot + daughter2; + + ROOT::Math::Boost boost2{motherRot.BoostToCM()}; + daughterRotCM = boost2(daughterRot); + + auto cosThetaStarHelicityRot = motherRot.Vect().Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(motherRot.Vect().Mag2())); + auto phiHelicityRot = std::atan2(yaxisHE.Dot(daughterRotCM.Vect().Unit()), xaxisHE.Dot(daughterRotCM.Vect().Unit())); + phiHelicityRot = RecoDecay::constrainAngle(phiHelicityRot, 0.0); + if (motherRot.Rapidity() < config.rapidityMotherData) + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarHelicityRot, phiHelicityRot); + } + } else { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity, anglePhi); + } + } + } else if (config.activateCollinsSoperFrame) { + if (!isMix) { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaStarCS, phiCS); + } + + 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); + + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + + motherRot = daughterRot + daughter2; + + ROOT::Math::Boost boost2{motherRot.BoostToCM()}; + daughterRotCM = boost2(daughterRot); + + auto cosThetaStarCSrot = zAxisCS.Dot(daughterRotCM.Vect()) / std::sqrt(daughterRotCM.Vect().Mag2()); + auto phiCSrot = std::atan2(yAxisCS.Dot(daughterRotCM.Vect().Unit()), xAxisCS.Dot(daughterRotCM.Vect().Unit())); + phiCSrot = RecoDecay::constrainAngle(phiCSrot, 0.0); + + if (motherRot.Rapidity() < config.rapidityMotherData) + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarCSrot, phiCSrot); + } + } else { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaStarCS, phiCS); + } + } + } else if (config.activateProductionFrame) { + normalVec = ROOT::Math::XYZVector(mother.Py(), -mother.Px(), 0.f); + auto cosThetaProduction = normalVec.Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(normalVec.Mag2())); + if (!isMix) { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaProduction, anglePhi); + } + 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); + motherRot = ROOT::Math::PxPyPzMVector(mother.Px() * std::cos(theta2) - mother.Py() * std::sin(theta2), mother.Px() * std::sin(theta2) + mother.Py() * std::cos(theta2), mother.Pz(), mother.M()); + if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaProduction, anglePhi); + } + } + } else { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaProduction, anglePhi); + } + } + } else if (config.activateBeamAxisFrame) { + beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(fourVecDauCM.Vect()) / std::sqrt(fourVecDauCM.Vect().Mag2()); + if (!isMix) { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam, anglePhi); + } + 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); + motherRot = ROOT::Math::PxPyPzMVector(mother.Px() * std::cos(theta2) - mother.Py() * std::sin(theta2), mother.Px() * std::sin(theta2) + mother.Py() * std::cos(theta2), mother.Pz(), mother.M()); + if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarBeam, anglePhi); + } + } + } else { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam, anglePhi); + } + } + } else if (config.activateRandomFrame) { + 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(fourVecDauCM.Vect()) / std::sqrt(fourVecDauCM.Vect().Mag2()); + if (!isMix) { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom, phiRandom); + } + 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); + motherRot = ROOT::Math::PxPyPzMVector(mother.Px() * std::cos(theta2) - mother.Py() * std::sin(theta2), mother.Px() * std::sin(theta2) + mother.Py() * std::cos(theta2), mother.Pz(), mother.M()); + if (std::abs(motherRot.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassRot"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarRandom, phiRandom); + } + } + } else { + if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { + hglue.fill(HIST("h3glueInvMassME"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom, phiRandom); + } + } + } + // } + } + + void processSE(EventCandidates::iterator const& collision, TrackCandidates const& /*tracks*/, V0TrackCandidate const& V0s) + { + multiplicity = 0.0; + + if (config.cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (config.cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (config.cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (config.cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + + if (!selectionEvent(collision, true)) { + return; + } + // if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(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 (postrack1.hasTOF()) { + // double nTOFSigmaPos1{postrack1.tofNSigmaPi()}; + // if ((std::abs(nTOFSigmaPos1) > config.confDaughPIDCutTOF)) { + // continue; + // } + // } + + // if (negtrack1.hasTOF()) { + // double nTOFSigmaNeg1{negtrack1.tofNSigmaPi()}; + // if (std::abs(nTOFSigmaNeg1) > config.confDaughPIDCutTOF) { + // continue; + // } + // } + + // if (postrack2.hasTOF()) { + // double nTOFSigmaPos2{postrack2.tofNSigmaPi()}; + // if ((std::abs(nTOFSigmaPos2) > config.confDaughPIDCutTOF)) { + // continue; + // } + // } + + // if (negtrack2.hasTOF()) { + // double nTOFSigmaNeg2{negtrack2.tofNSigmaPi()}; + // if (std::abs(nTOFSigmaNeg2) > config.confDaughPIDCutTOF) { + // continue; + // } + // } + + if (std::find(v0indexes.begin(), v0indexes.end(), v1.globalIndex()) == v0indexes.end()) { + v0indexes.push_back(v1.globalIndex()); + } + + if (v2.globalIndex() <= v1.globalIndex()) { + continue; + } + + if (postrack1.globalIndex() == postrack2.globalIndex()) { + continue; + } + if (negtrack1.globalIndex() == negtrack2.globalIndex()) { + continue; + } + + if (!applyAngSep(v1, v2)) { + continue; + } + + if (config.isApplyEtaCutK0s && (v1.eta() < config.confDaughEta || v2.eta() < config.confDaughEta)) { + 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 + daughter2 = ROOT::Math::PxPyPzMVector(v2.px(), v2.py(), v2.pz(), o2::constants::physics::MassK0Short); // Kshort + + mother = daughter1 + daughter2; // invariant mass of Kshort pair + isMix = false; + + if (!config.isselectTWOKsOnly) + fillInvMass(mother, multiplicity, daughter1, daughter2, isMix); + } + int sizeofv0indexes = v0indexes.size(); + rKzeroShort.fill(HIST("NksProduced"), sizeofv0indexes); + if (config.isselectTWOKsOnly && sizeofv0indexes == config.noOfDaughters && allConditionsMet) { + fillInvMass(mother, multiplicity, daughter1, daughter2, false); + } + v0indexes.clear(); + } + PROCESS_SWITCH(HigherMassResonances, processSE, "same event process", true); + + 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"}; + + // using BinningTypeTPCMultiplicity = ColumnBinningPolicy; + using BinningTypeFT0M = ColumnBinningPolicy; + using BinningTypeFT0A = ColumnBinningPolicy; + using BinningTypeFT0C = ColumnBinningPolicy; + using BinningTypeFV0A = ColumnBinningPolicy; + + BinningTypeFT0M binningOnFT0M{{axisVertex, axisMultiplicity}, true}; + BinningTypeFT0A binningOnFT0A{{axisVertex, axisMultiplicity}, true}; + BinningTypeFT0C binningOnFT0C{{axisVertex, axisMultiplicity}, true}; + BinningTypeFV0A binningOnFV0A{{axisVertex, axisMultiplicity}, true}; + + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{axisVertex, axisMultiplicity}, true}; // for derived data only + Preslice tracksPerCollisionV0Mixed = o2::aod::v0data::straCollisionId; // for derived data only + + void processME(EventCandidates const& collisions, TrackCandidates const& /*tracks*/, V0TrackCandidate const& v0s) + { + auto tracksTuple = std::make_tuple(v0s); + SameKindPair pair1{binningOnFT0M, config.cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; + SameKindPair pair2{binningOnFT0A, config.cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; + SameKindPair pair3{binningOnFT0C, config.cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; + SameKindPair pair4{binningOnFV0A, config.cfgNmixedEvents, -1, collisions, tracksTuple, &cache}; + + auto runMixing = [&](auto& pair, auto multiplicityGetter) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + multiplicity = multiplicityGetter(c1); + + if (!selectionEvent(c1, false) || !selectionEvent(c2, false)) { + 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(); + 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 + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), o2::constants::physics::MassK0Short); // Kshort + + mother = daughter1 + daughter2; // invariant mass of Kshort pair + isMix = true; + fillInvMass(mother, multiplicity, daughter1, daughter2, isMix); + } + } + }; + // Call mixing based on selected estimator + if (config.cSelectMultEstimator == kFT0M) { + runMixing(pair1, [](const auto& c) { return c.centFT0M(); }); + } else if (config.cSelectMultEstimator == kFT0A) { + runMixing(pair2, [](const auto& c) { return c.centFT0A(); }); + } else if (config.cSelectMultEstimator == kFT0C) { + runMixing(pair3, [](const auto& c) { return c.centFT0C(); }); + } else if (config.cSelectMultEstimator == kFV0A) { + runMixing(pair4, [](const auto& c) { return c.centFV0A(); }); + } + } + PROCESS_SWITCH(HigherMassResonances, processME, "mixed event process", true); + + int counter = 0; + float multiplicityGen = 0.0; + std::vector passKs; + ROOT::Math::PxPyPzMVector lResonanceGen1; + ROOT::Math::PxPyPzEVector lResonanceGen; + + void processGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + { + if (config.isMC == false) { + return; + } + hMChists.fill(HIST("events_check"), 0.5); + + std::vector selectedEvents(collisions.size()); + int nevts = 0; + multiplicityGen = -999.0; + for (const auto& collision : collisions) { + + // multiplicityGen = collision.centFT0M(); + if (config.cSelectMultEstimator == kFT0M) { + multiplicityGen = collision.centFT0M(); + } else if (config.cSelectMultEstimator == kFT0A) { + multiplicityGen = collision.centFT0A(); + } else if (config.cSelectMultEstimator == kFT0C) { + multiplicityGen = collision.centFT0C(); + } else if (config.cSelectMultEstimator == kFV0A) { + multiplicityGen = collision.centFV0A(); + } else { + multiplicityGen = collision.centFT0M(); // default + } + + if (!selectionEvent(collision, true)) { + continue; + } + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + hMChists.fill(HIST("events_check"), 1.5); + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + + if (!config.isallGenCollisions && !evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + hMChists.fill(HIST("events_check"), 2.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"), 3.5); + + if (config.isapplyRapidityMC && std::abs(mcParticle.y()) >= config.rapidityMotherData) { + continue; + } + hMChists.fill(HIST("events_check"), 4.5); + + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != config.noOfDaughters) { + continue; + } + hMChists.fill(HIST("events_check"), 5.5); + + for (const auto& kCurrentDaughter : kDaughters) { + // int daupdg = std::abs(kCurrentDaughter.pdgCode()); + + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + hMChists.fill(HIST("events_check"), 6.5); + if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kK0Short) { + passKs.push_back(true); + hMChists.fill(HIST("events_check"), 7.5); + if (passKs.size() == 1) { + daughter1 = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassK0Short); + } else if (static_cast(passKs.size()) == config.noOfDaughters) { + daughter2 = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassK0Short); + } + } + } + if (static_cast(passKs.size()) == config.noOfDaughters) { + lResonanceGen = ROOT::Math::PxPyPzEVector(mcParticle.pt(), mcParticle.eta(), mcParticle.phi(), mcParticle.e()); + lResonanceGen1 = daughter1 + daughter2; + + ROOT::Math::Boost boost{lResonanceGen.BoostToCM()}; + ROOT::Math::Boost boost1{lResonanceGen1.BoostToCM()}; + + fourVecDauCM = boost(daughter1); + fourVecDauCM1 = boost1(daughter1); + + auto helicityGen = lResonanceGen.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(lResonanceGen.Vect().Mag2())); + auto helicityGen1 = lResonanceGen1.Vect().Dot(fourVecDauCM1.Vect()) / (std::sqrt(fourVecDauCM1.Vect().Mag2()) * std::sqrt(lResonanceGen1.Vect().Mag2())); + + hMChists.fill(HIST("Genf1710"), multiplicityGen, lResonanceGen.pt(), helicityGen); + hMChists.fill(HIST("Genf1710_mass"), lResonanceGen.M()); + hMChists.fill(HIST("GenRapidity"), mcParticle.y()); + hMChists.fill(HIST("GenEta"), mcParticle.eta()); + hMChists.fill(HIST("GenPhi"), mcParticle.phi()); + + if (config.isapplyPairRapidityGen && std::abs(lResonanceGen1.Rapidity()) >= config.rapidityMotherData) { + continue; + } + + hMChists.fill(HIST("Genf17102"), multiplicityGen, lResonanceGen1.pt(), helicityGen1); + hMChists.fill(HIST("Genf1710_mass2"), lResonanceGen1.M()); + hMChists.fill(HIST("GenRapidity2"), lResonanceGen1.Rapidity()); + hMChists.fill(HIST("GenEta2"), lResonanceGen1.Eta()); + hMChists.fill(HIST("GenPhi2"), lResonanceGen1.Phi()); + } + passKs.clear(); // clear the vector for the next iteration + } + } + PROCESS_SWITCH(HigherMassResonances, processGen, "Process Generated", false); + + 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*/) + { + if (config.isMC == false) { + return; + } + + auto multiplicity = -999.0; + if (config.cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (config.cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (config.cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (config.cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + + if (!selectionEvent(collision, false)) { + return; + } + hMChists.fill(HIST("Rec_Multiplicity"), multiplicity); + + if (!collision.has_mcCollision()) { + return; + } + + hMChists.fill(HIST("MC_mult_after_event_sel"), multiplicity); + eventCounter++; + + for (const auto& v01 : V0s) { + + for (const auto& v02 : V0s) { + + if (v02.index() <= v01.index()) { + continue; + } + + if (!v01.has_mcParticle() || !v02.has_mcParticle()) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 0.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 + + if (!negtrack1.has_mcParticle() || !negtrack2.has_mcParticle()) + 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], v01) || !isSelectedV0Daughter(postrack2, 1, nTPCSigmaPos2[0], v02)) { + continue; + } + + if (!isSelectedV0Daughter(negtrack1, -1, nTPCSigmaNeg1[0], v01) || !isSelectedV0Daughter(negtrack2, -1, nTPCSigmaNeg2[0], v02)) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 1.5); + + if (!selectionV0(collision, v01, multiplicity) || !selectionV0(collision, v02, multiplicity)) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 2.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) != PDG_t::kK0Short || std::abs(trackv0PDG2) != PDG_t::kK0Short) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 3.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; + } + } + + for (const auto& mothertrack2 : mctrackv02.mothers_as()) { + hMChists.fill(HIST("events_checkrec"), 4.5); + + if (mothertrack1.pdgCode() != config.pdgCodes[config.selectMCparticles]) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 5.5); + + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 6.5); + + gindex2.push_back(mothertrack2.globalIndex()); + if (gindex2.size() > 1) { + if (std::find(gindex2.begin(), gindex2.end(), mothertrack2.globalIndex()) != gindex2.end()) { + continue; + } + } + hMChists.fill(HIST("events_checkrec"), 7.5); + + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 8.5); + + if (!mothertrack1.producedByGenerator()) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 9.5); + + if (config.isapplyRapidityMC && std::abs(mothertrack1.y()) >= config.rapidityMotherData) { + continue; + } + hMChists.fill(HIST("events_checkrec"), 10.5); + + // if (config.isavoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + // hMChists.fill(HIST("h1Recsplit"), mothertrack1.pt()); + // continue; + // } + // hMChists.fill(HIST("events_checkrec"), 11.5); + // oldindex = mothertrack1.globalIndex(); // split tracks is already handled using gindex1 and gindex2 + + daughter1 = ROOT::Math::PxPyPzMVector(v01.px(), v01.py(), v01.pz(), o2::constants::physics::MassK0Short); + daughter2 = ROOT::Math::PxPyPzMVector(v02.px(), v02.py(), v02.pz(), o2::constants::physics::MassK0Short); + mother = daughter1 + daughter2; + mother1 = ROOT::Math::PxPyPzEVector(mothertrack1.px(), mothertrack1.py(), mothertrack1.pz(), mothertrack1.e()); + + ROOT::Math::Boost boost{mother.BoostToCM()}; + ROOT::Math::Boost boost1{mother1.BoostToCM()}; + + fourVecDauCM = boost(daughter1); + fourVecDauCM1 = boost1(daughter1); + + auto helicityRec = mother.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(mother.Vect().Mag2())); + + auto helicityRec2 = mother1.Vect().Dot(fourVecDauCM1.Vect()) / (std::sqrt(fourVecDauCM1.Vect().Mag2()) * std::sqrt(mother1.Vect().Mag2())); + + hMChists.fill(HIST("Recf1710_pt1"), multiplicity, mothertrack1.pt(), mother1.M(), helicityRec2); + hMChists.fill(HIST("RecRapidity"), mothertrack1.y()); + hMChists.fill(HIST("RecPhi"), mothertrack1.phi()); + hMChists.fill(HIST("RecEta"), mothertrack1.eta()); + + if (config.isapplyPairRapidityRec && std::abs(mother.Rapidity()) >= config.rapidityMotherData) { + continue; + } + + hMChists.fill(HIST("Recf1710_pt2"), multiplicity, mother.Pt(), mother.M(), helicityRec); + hMChists.fill(HIST("RecRapidity2"), mother.Rapidity()); + hMChists.fill(HIST("RecPhi2"), mother.Phi()); + hMChists.fill(HIST("RecEta2"), mother.Eta()); + } + gindex2.clear(); + } + gindex1.clear(); + } + } + } + PROCESS_SWITCH(HigherMassResonances, processRec, "Process Reconstructed", false); + + void processSEderived(EventCandidatesDerivedData::iterator const& collision, V0CandidatesDerivedData const& V0s, DauTracks const&) + { + multiplicity = 0.0; + if (config.cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (config.cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (config.cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (config.cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + + if (!selectionEvent(collision, true)) { + return; + } + + if (config.qAevents) { + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + rEventSelection.fill(HIST("hmultiplicity"), multiplicity); + } + + 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; + } + + if (!isSelectedK0sDaughtersDerived(v1) || !isSelectedK0sDaughtersDerived(v2)) { + continue; + } + + if (std::find(v0indexes.begin(), v0indexes.end(), v1.globalIndex()) == v0indexes.end()) { + v0indexes.push_back(v1.globalIndex()); + } + + if (v2.globalIndex() <= v1.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 + daughter2 = ROOT::Math::PxPyPzMVector(v2.px(), v2.py(), v2.pz(), o2::constants::physics::MassK0Short); // Kshort + + mother = daughter1 + daughter2; // invariant mass of Kshort pair + isMix = false; + + if (!config.isselectTWOKsOnly) + fillInvMass(mother, multiplicity, daughter1, daughter2, isMix); + } + int sizeofv0indexes = v0indexes.size(); + rKzeroShort.fill(HIST("NksProduced"), sizeofv0indexes); + if (config.isselectTWOKsOnly && sizeofv0indexes == config.noOfDaughters && allConditionsMet) { + fillInvMass(mother, multiplicity, daughter1, daughter2, false); + } + v0indexes.clear(); + } + PROCESS_SWITCH(HigherMassResonances, processSEderived, "same event process in strangeness derived data", false); + + void processMEderived(EventCandidatesDerivedData const& collisions, V0CandidatesDerivedData const& v0s, DauTracks const&) + { + + for (const auto& [c1, c2] : selfCombinations(colBinning, config.cfgNmixedEvents, -1, collisions, collisions)) // two different centrality c1 and c2 and tracks corresponding to them + { + + multiplicity = 0.0; + multiplicity = c1.centFT0M(); + + if (!selectionEvent(c1, false) || !selectionEvent(c2, false)) { + continue; + } + + auto groupV01 = v0s.sliceBy(tracksPerCollisionV0Mixed, c1.index()); + auto groupV02 = v0s.sliceBy(tracksPerCollisionV0Mixed, c2.index()); + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV01, groupV02))) { + + if (t1.size() == 0 || t2.size() == 0) { + continue; + } + + if (!selectionV0(c1, t1, multiplicity)) + continue; + if (!selectionV0(c2, t2, multiplicity)) + continue; + + if (!isSelectedK0sDaughtersDerived(t1) || !isSelectedK0sDaughtersDerived(t2)) { + continue; + } + + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassK0Short); // Kshort + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), o2::constants::physics::MassK0Short); // Kshort + + mother = daughter1 + daughter2; // invariant mass of Kshort pair + isMix = true; + fillInvMass(mother, multiplicity, daughter1, daughter2, isMix); + } + } + } + PROCESS_SWITCH(HigherMassResonances, processMEderived, "mixed event process in derived data", 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 8b3a0bc6ade..fb3d0de5926 100644 --- a/PWGLF/Tasks/Resonances/highmasslambda.cxx +++ b/PWGLF/Tasks/Resonances/highmasslambda.cxx @@ -11,107 +11,111 @@ // Phi meson spin alignment task // sourav.kundu@cern.ch -#include +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include #include +#include +#include +#include #include #include #include #include -#include -#include -#include #include -#include -#include + #include +#include #include +#include +#include +// #include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" -#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 "CCDB/BasicCCDBManager.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "DCAFitter/DCAFitterN.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 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 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 cnfabsdca{"cnfabsdca", false, "Use Abs DCA for secondary vertex fitting"}; // fill output - Configurable useSP{"useSP", false, "useSP"}; - Configurable useSignDCAV0{"useSignDCAV0", true, "useSignDCAV0"}; - Configurable additionalEvSel{"additionalEvSel", true, "additionalEvSel"}; - Configurable additionalEvSel2{"additionalEvSel2", false, "additionalEvSel2"}; - Configurable fillDefault{"fillDefault", false, "fill Occupancy"}; - Configurable fillOccupancy{"fillOccupancy", true, "fill Occupancy"}; - Configurable fillDecayLength{"fillDecayLength", true, "fill decay length"}; - 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", 50.0f, "Accepted maximum Centrality"}; Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 30.0f, "Accepted minimum Centrality"}; + Configurable additionalEvSel{"additionalEvSel", true, "additionalEvSel"}; // proton track cut - Configurable ispTdifferentialDCA{"ispTdifferentialDCA", true, "is pT differential DCA"}; - Configurable isPVContributor{"isPVContributor", true, "is PV contributor"}; - Configurable rejectPID{"rejectPID", true, "Reject PID"}; 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 cfgCutPT{"cfgCutPT", 0.4, "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 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", 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.2f, "Maximum DCA between the V0 daughters"}; @@ -121,138 +125,125 @@ struct highmasslambda { 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", 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"}; + // 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", {24, 1.0, 25.}, "#it{p}_{T} (GeV/#it{c})"}; - ConfigurableAxis configThnAxisCosThetaStar{"configThnAxisCosThetaStar", {10, -1.0, 1.}, "cos(#vartheta)"}; - ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {1, 30., 50}, "Centrality"}; - ConfigurableAxis configThnAxisPhiminusPsi{"configThnAxisPhiminusPsi", {6, 0.0, TMath::Pi()}, "#phi - #psi"}; + ConfigurableAxis configThnAxisPt{"configThnAxisPt", {5, 1.0, 6.}, "#it{p}_{T} (GeV/#it{c})"}; ConfigurableAxis configThnAxisV2{"configThnAxisV2", {80, -1, 1}, "V2"}; - ConfigurableAxis configThnAxisSA{"configThnAxisSA", {100, -1, 1}, "SA"}; - ConfigurableAxis cnfigThnAxisDecayLength{"cnfigThnAxisDecayLength", {150, 0.0, 0.3}, "SA"}; - ConfigurableAxis cnfigThnAxisDCASum{"cnfigThnAxisDCASum", {150, -0.3, 0.3}, "SA"}; + 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 configThnAxisSP{"configThnAxisSP", {400, -12, 12}, "SP"}; + 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 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.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.002, 0.003, 0.004, 0.006, 0.008, 0.01, 0.015, 0.02, 0.04, 0.08, 0.1, 0.3, 1.0}; - std::vector ptProtonBinning = {0.2, 0.3, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 100.0}; - std::vector ptLambdaBinning = {2.0, 3.0, 4.0, 5.0, 8.0, 16.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 thnAxisDCASum{cnfigThnAxisDCASum, "DCA Sum"}; const AxisSpec thnAxisPtProton{cnfigThnAxisPtProton, "Proton Pt"}; - const AxisSpec thnAxisSP{configThnAxisSP, "SP"}; - - AxisSpec phiAxis = {500, -6.28, 6.28, "phi"}; - AxisSpec resAxis = {1000, -10, 10, "Res"}; - AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; - // AxisSpec ptProtonAxis = {16, 0.0, 8, "V0M (%)"}; - AxisSpec dcaAxis = {dcaBinning, "DCAxy"}; - AxisSpec dcatoPVAxis = {50, 0.0, 0.4, "V0M (%)"}; + const AxisSpec thnAxisCPA{cnfigThnAxisCPA, "CPA"}; AxisSpec occupancyAxis = {occupancyBinning, "occupancy"}; - AxisSpec ptProtonAxis = {ptProtonBinning, "pT proton"}; - histos.add("hRejectPID", "hRejectPID", kTH1F, {{2, 0.0f, 2.0f}}); - histos.add("hMomCorr", "hMomCorr", kTH3F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}, {8, 0.0f, 80.0f}}); + // 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.0, 50000.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("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("hMassvsDecaySum", "hMassvsDecaySum", kTH2F, {thnAxisInvMass, thnAxisDCASum}); + 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}); - histos.add("hPsiTPCR", "PsiTPCR", kTH3F, {centAxis, phiAxis, occupancyAxis}); - histos.add("hPsiTPCL", "PsiTPCL", kTH3F, {centAxis, phiAxis, occupancyAxis}); - if (fillDefault) { - if (fillDecayLength) { - histos.add("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, thnAxisDCASum}); - histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, thnAxisDCASum}); - histos.add("hSparseV2SASameEventRotational_V2", "hSparseV2SASameEventRotational_V2", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, thnAxisDCASum}); - } - histos.add("hSparseV2SASameEvent_V2_new", "hSparseV2SASameEvent_V2_new", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, dcaAxis, ptProtonAxis}); - histos.add("hSparseV2SAMixedEvent_V2_new", "hSparseV2SAMixedEvent_V2_new", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, dcaAxis, ptProtonAxis}); - histos.add("hSparseV2SASameEventRotational_V2_new", "hSparseV2SASameEventRotational_V2_new", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, dcaAxis, ptProtonAxis}); - } - if (fillOccupancy) { - if (fillDecayLength) { - histos.add("hSparseV2SASameEvent_V2_occupancy", "hSparseV2SASameEvent_V2_occupancy", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, thnAxisDCASum, dcaAxis, occupancyAxis}); - histos.add("hSparseV2SASameEventRotational_V2_occupancy", "hSparseV2SASameEventRotational_V2_occupancy", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, thnAxisDCASum, dcaAxis, occupancyAxis}); - histos.add("hSparseV2SAMixedEvent_V2_occupancy", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, thnAxisDCASum, dcaAxis, occupancyAxis}); - } - histos.add("hSparseV2SASameEvent_V2_new_occupancy", "hSparseV2SASameEvent_V2_new_occupancy", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, dcaAxis, ptProtonAxis, occupancyAxis}); - histos.add("hSparseV2SASameEventRotational_V2_new_occupancy", "hSparseV2SASameEventRotational_V2_new_occupancy", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, dcaAxis, ptProtonAxis, occupancyAxis}); - histos.add("hSparseV2SAMixedEvent_V2_new_occupancy", "hSparseV2SAMixedEvent_V2_new", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSP, dcaAxis, ptProtonAxis, occupancyAxis}); - } - if (fillPolarization) { - histos.add("hSparseV2SASameEventplus_SA", "hSparseV2SASameEventplus_SA", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEventplus_SA_A0", "hSparseV2SASameEventplus_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEventplus_SA_azimuth", "hSparseV2SASameEventplus_SA_azimuth", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisCentrality}); - histos.add("hSparseV2SASameEventminus_SA", "hSparseV2SASameEventminus_SA", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEventminus_SA_A0", "hSparseV2SASameEventminus_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SASameEventminus_SA_azimuth", "hSparseV2SASameEventminus_SA_azimuth", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisCentrality}); - - histos.add("hSparseV2SAMixedEventplus_SA", "hSparseV2SAMixedEventplus_SA", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventplus_SA_A0", "hSparseV2SAMixedEventplus_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventplus_SA_azimuth", "hSparseV2SAMixedEventplus_SA_azimuth", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventminus_SA", "hSparseV2SAMixedEventminus_SA", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventminus_SA_A0", "hSparseV2SAMixedEventminus_SA_A0", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisPhiminusPsi, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEventminus_SA_azimuth", "hSparseV2SAMixedEventminus_SA_azimuth", HistType::kTHnSparseF, {thnAxisInvMass, ptLambdaBinning, thnAxisSA, thnAxisCentrality}); - } + // 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}); @@ -260,165 +251,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 (isPVContributor && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { + if (!(candidate.isGlobalTrackWoDCA() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsCrossedRows() > cfgTPCcluster)) { return false; } - if (!isPVContributor && !(candidate.isGlobalTrackWoDCA() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { + if (std::abs(candidate.dcaXY()) > (0.0105 + (0.035 / TMath::Power(candidate.pt(), 1.1)))) { return false; } - - if (ispTdifferentialDCA) { - 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() < 2.5 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin5) { - return false; - } - if (candidate.pt() >= 2.5 && candidate.pt() < 3.0 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin6) { - return false; - } - if (candidate.pt() >= 3.0 && candidate.pt() < 4.0 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin7) { - return false; - } - if (candidate.pt() >= 4.0 && candidate.pt() < 10.0 && TMath::Abs(candidate.dcaXY()) < cfgCutDCAxymin8) { - return false; - } + if (candidate.pt() > 0.0 && candidate.pt() < 0.5 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin1) { + return false; } - - if (!ispTdifferentialDCA) { - if (candidate.pt() > 0.0 && candidate.pt() < 0.5 && TMath::Abs(candidate.dcaXY()) < 0.004) { - return false; - } - if (candidate.pt() >= 0.5 && candidate.pt() < 1.0 && TMath::Abs(candidate.dcaXY()) < 0.003) { - return false; - } - if (candidate.pt() >= 1.0 && candidate.pt() < 2.0 && TMath::Abs(candidate.dcaXY()) < 0.002) { - return false; - } + if (candidate.pt() >= 0.5 && candidate.pt() < 1.0 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin2) { + return false; } - return true; - } - - template - bool selectionPIDpTdependent(const T& candidate) - { - if (candidate.p() <= 0.5 && TMath::Abs(candidate.tpcNSigmaPr()) < 5.0) { - return true; + if (candidate.pt() >= 1.0 && candidate.pt() < 1.5 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin3) { + return false; } - if (candidate.p() > 0.5 && candidate.p() <= 0.8 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { - return true; + if (candidate.pt() >= 1.5 && candidate.pt() < 2.0 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin4) { + return false; } - if (candidate.p() > 0.8 && candidate.hasTOF() && TMath::Sqrt(candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < nsigmaCutTOF) { - return true; + if (candidate.pt() >= 2.0 && candidate.pt() < 10000000.0 && std::abs(candidate.dcaXY()) < cfgCutDCAxymin5) { + return false; } - return false; + return true; } + // TOF Veto template - bool selectionPID(const T& candidate) + bool selectionPID1(const T& candidate) { if (candidate.hasTOF()) { - if (candidate.pt() < 0.8 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && TMath::Abs(candidate.tofNSigmaPr()) < 10.0) { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } - if (candidate.pt() >= 0.8 && candidate.pt() < 3.0 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && TMath::Abs(candidate.tofNSigmaPr()) < 3.0) { - return true; - } - if (candidate.pt() >= 3.0 && candidate.pt() < 4.0 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < 3.0) { - return true; - } - if (candidate.pt() >= 4.0 && candidate.pt() < 5.0 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -1.5 && candidate.tofNSigmaPr() < 3.0) { - return true; - } - if (candidate.pt() >= 5.0 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -1.5 && candidate.tofNSigmaPr() < 3.0) { + if (candidate.p() >= 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOF) { return true; } } if (!candidate.hasTOF()) { - if (candidate.pt() < 0.7 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { - return true; - } - if (candidate.pt() >= 0.7 && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -2.0 && candidate.tpcNSigmaPr() < 3.0) { - return true; - } - if (candidate.pt() >= 0.8 && candidate.tpcNSigmaPr() > -1.5 && candidate.tpcNSigmaPr() < 3.0) { + if (std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } } return false; } - + // TPC TOF template - bool selectionPIDNew(const T& candidate) + bool selectionPID7(const T& candidate) { - if (candidate.pt() < 0.7 && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { - return true; - } - if (candidate.pt() >= 0.7 && !candidate.hasTOF() && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -2.0 && candidate.tpcNSigmaPr() < 3.0) { - return true; - } - if (candidate.pt() < 0.8 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && TMath::Abs(candidate.tofNSigmaPr()) < 10.0) { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } - if (candidate.pt() >= 0.8 && candidate.pt() < 1.0 && !candidate.hasTOF() && candidate.tpcNSigmaPr() > -1.5 && candidate.tpcNSigmaPr() < 3.0) { - 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; + } + } } - if (candidate.pt() >= 0.8 && candidate.pt() < 3.0 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && TMath::Abs(candidate.tofNSigmaPr()) < 3.0) { + return false; + } + + // TPC TOF + template + bool selectionPID8(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } - if (candidate.pt() >= 3.0 && candidate.pt() < 4.0 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < 4.0) { - 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.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; + } + } } - if (candidate.pt() >= 4.0 && candidate.pt() < 5.0 && candidate.hasTOF() && candidate.tofNSigmaPr() > -2.0) { + return false; + } + + // TPC TOF + template + bool selectionPID9(const T& candidate) + { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { return true; } - if (candidate.pt() >= 5.0 && candidate.hasTOF() && candidate.tofNSigmaPr() > -1.5) { - 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.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 RejectPion(const T& candidate) + bool selectionPID10(const T& candidate) { - if (candidate.p() > 1.0 && candidate.p() < 2.0 && !candidate.hasTOF() && candidate.tpcNSigmaPi() < 2) { - return false; + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + return true; } - return true; + 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 - bool RejectKaon(const T& candidate) + double combinekaon(const T& candidate) { - if (candidate.p() > 1.0 && candidate.p() < 2.0 && !candidate.hasTOF() && candidate.tpcNSigmaKa() < 2) { - return false; + 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 true; + 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 @@ -440,7 +500,7 @@ 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; @@ -450,7 +510,7 @@ struct highmasslambda { { 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) { @@ -459,13 +519,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) { @@ -494,30 +554,26 @@ 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()) { - return; - } - auto centrality = collision.centFT0C(); - auto multTPC = collision.multNTracksPV(); - histos.fill(HIST("hFTOCvsTPCNoCut"), centrality, multTPC); - if (!collision.triggereventep()) { + if (!collision.sel8() || !collision.triggereventep() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return; } - if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + 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; } - if (additionalEvSel2 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + o2::aod::ITSResponse itsResponse; + auto centrality = collision.centFT0C(); + // auto multTPC = collision.multNTracksPV(); + int occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy > cfgOccupancyCut) { return; } - int occupancy = collision.trackOccupancyInTimeRange(); auto psiFT0C = collision.psiFT0C(); auto psiFT0A = collision.psiFT0A(); auto psiTPC = collision.psiTPC(); @@ -529,14 +585,9 @@ struct highmasslambda { 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, 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))); @@ -551,37 +602,50 @@ struct highmasslambda { if (!selectionTrack(track1)) { continue; } - // PID check - if (ispTdepPID && !selectionPIDNew(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 (!ispTdepPID && rejectPID && !RejectPion(track1)) { - histos.fill(HIST("hRejectPID"), 0.5); + if (PIDstrategy == 3 && !selectionPID10(track1)) { continue; } - if (!ispTdepPID && rejectPID && !RejectKaon(track1)) { - histos.fill(HIST("hRejectPID"), 1.5); + if (PIDstrategy == 4 && !selectionPID1(track1)) { continue; } - histos.fill(HIST("hMomCorr"), 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("hNsigmaProtonTPCDiff"), track1.tpcNSigmaPr(), track1.tpcNSigmaKa(), track1.pt()); + histos.fill(HIST("hDcaxy"), track1.dcaXY(), track1.pt()); + histos.fill(HIST("hDcaz"), track1.dcaZ(), track1.pt()); histos.fill(HIST("hNsigmaProtonTPC"), track1.tpcNSigmaPr(), track1.pt()); - histos.fill(HIST("hNsigmaProtonTOF"), track1.tofNSigmaPr(), 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("hInvMassKs0before"), v0.mK0Short()); + } if (!SelectionV0(collision, v0)) { continue; } - auto anglesign = (v0.x() - collision.posX()) * v0.px() + (v0.y() - collision.posY()) * v0.py() + (v0.z() - collision.posZ()) * v0.pz(); - anglesign = anglesign / TMath::Abs(anglesign); if (firstprimarytrack == 0) { - histos.fill(HIST("hV0Dca"), anglesign * v0.dcav0topv()); + 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(); @@ -591,6 +655,10 @@ struct highmasslambda { if (!isSelectedV0Daughter(negtrack, -1)) { continue; } + if (firstprimarytrack == 0) { + histos.fill(HIST("hInvMassKs0before3"), v0.mK0Short()); + } + if (track1ID == postrack.globalIndex()) { continue; } @@ -602,96 +670,50 @@ 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); - + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; if (useSP) { - v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; - } - if (!useSP) { v2 = TMath::Cos(2.0 * phiminuspsi); } - 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 = std::abs((track1.dcaXY() / TMath::Sin(diffangle)) / (Lambdac.P() / 2.286)); - // auto dcasum = TMath::Sqrt(track1.dcaXY() * track1.dcaXY() + v0.dcav0topv() * v0.dcav0topv()); - histos.fill(HIST("hMassvsDecaySum"), Lambdac.M(), dcasum); - if (fillDefault && Lambdac.M() > 2.18 && Lambdac.M() <= 2.42) { - if (fillDecayLength) { - histos.fill(HIST("hSparseV2SASameEvent_V2"), Lambdac.M(), Lambdac.Pt(), v2, dcasum); + 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()); } - histos.fill(HIST("hSparseV2SASameEvent_V2_new"), Lambdac.M(), Lambdac.Pt(), v2, std::abs(track1.dcaXY()), Proton.Pt()); - } - if (fillOccupancy && Lambdac.M() > 2.18 && Lambdac.M() <= 2.42) { - if (fillDecayLength) { - histos.fill(HIST("hSparseV2SASameEvent_V2_occupancy"), Lambdac.M(), Lambdac.Pt(), v2, dcasum, std::abs(track1.dcaXY()), occupancy); + if (useKshortOpti == 1) { + histos.fill(HIST("hSparseV2SASameEvent_V2"), Lambdac.M(), Lambdac.Pt(), dcaV0toPV, cpaV0, ptV0, dcaV0Daughters, dcaProtonV0); + } + if (useKshortOpti == 2) { + histos.fill(HIST("hSparseV2SASameEvent_V2"), Lambdac.M(), Lambdac.Pt(), v2, std::abs(track1.dcaXY()), combinekaon(track1)); } - histos.fill(HIST("hSparseV2SASameEvent_V2_new_occupancy"), Lambdac.M(), Lambdac.Pt(), v2, std::abs(track1.dcaXY()), Proton.Pt(), occupancy); } if (fillRotation) { for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { auto anglestart = confMinRot; auto angleend = confMaxRot; - // auto anglestep = nrotbkg * (TMath::Pi() / nBkgRotations); auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); auto rotangle = anglestart + nrotbkg * anglestep; histos.fill(HIST("hRotation"), rotangle); - auto rotProtonPx = track1.px() * std::cos(rotangle) - track1.py() * std::sin(rotangle); - auto rotProtonPy = track1.px() * std::sin(rotangle) + track1.py() * std::cos(rotangle); - ProtonRot = ROOT::Math::PxPyPzMVector(rotProtonPx, rotProtonPy, track1.pz(), massPr); - LambdacRot = ProtonRot + Kshort; + 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) * QFT0C; - } - if (!useSP) { v2Rot = TMath::Cos(2.0 * phiminuspsiRot); } - // auto diffangleRot = ProtonRot.Phi() - LambdacRot.Phi(); - // auto decaylengthRot = std::abs((track1.dcaXY() / TMath::Sin(diffangleRot)) / (Lambdac.P() / 2.286)); - if (fillDefault && LambdacRot.M() > 2.18 && LambdacRot.M() <= 2.42) { - if (fillDecayLength) { - histos.fill(HIST("hSparseV2SASameEventRotational_V2"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, dcasum); - } - histos.fill(HIST("hSparseV2SASameEventRotational_V2_new"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, std::abs(track1.dcaXY()), Proton.Pt()); - } - if (fillOccupancy && LambdacRot.M() > 2.18 && LambdacRot.M() <= 2.42) { - if (fillDecayLength) { - histos.fill(HIST("hSparseV2SASameEventRotational_V2_occupancy"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, dcasum, std::abs(track1.dcaXY()), occupancy); - } - histos.fill(HIST("hSparseV2SASameEventRotational_V2_new_occupancy"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, std::abs(track1.dcaXY()), Proton.Pt(), occupancy); + 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); } } } - 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); - } - } } } } @@ -702,37 +724,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()) { - continue; + if (!collision1.sel8() || !collision1.triggereventep() || !collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; } - if (!collision1.triggereventep() || !collision2.triggereventep()) { - continue; + 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 (additionalEvSel && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { - continue; + 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 (additionalEvSel && (!collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + if (collision1.bcId() == collision2.bcId()) { continue; } - if (additionalEvSel2 && (!collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { - return; + if (additionalEvSel && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; } - if (additionalEvSel2 && (!collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { - return; + if (additionalEvSel && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; } - auto centrality = collision1.centFT0C(); + o2::aod::ITSResponse itsResponse; + auto psiFT0C = collision1.psiFT0C(); auto QFT0C = collision1.qFT0C(); - int occupancy = collision1.trackOccupancyInTimeRange(); + 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 && !selectionPIDNew(track1)) { + if (PIDstrategy == 0 && !selectionPID7(track1)) { continue; } - if (!ispTdepPID && !selectionPID(track1)) { + if (PIDstrategy == 1 && !selectionPID8(track1)) { + continue; + } + if (PIDstrategy == 2 && !selectionPID9(track1)) { + continue; + } + if (PIDstrategy == 3 && !selectionPID10(track1)) { + continue; + } + if (PIDstrategy == 4 && !selectionPID1(track1)) { continue; } if (!SelectionV0(collision2, v0)) { @@ -746,67 +795,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); + v2 = TMath::Cos(2.0 * phiminuspsi) * QFT0C; 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 = std::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); + 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()); } - histos.fill(HIST("hSparseV2SAMixedEvent_V2_new"), Lambdac.M(), Lambdac.Pt(), v2, std::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, std::abs(track1.dcaXY()), occupancy); + if (useKshortOpti == 1) { + histos.fill(HIST("hSparseV2SAMixedEvent_V2"), Lambdac.M(), Lambdac.Pt(), dcaV0toPV, cpaV0, ptV0, dcaV0Daughters, dcaProtonV0); } - histos.fill(HIST("hSparseV2SAMixedEvent_V2_new_occupancy"), Lambdac.M(), Lambdac.Pt(), v2, std::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 (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 index 9daa9da7a8c..4280e2b6b01 100644 --- a/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx +++ b/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx @@ -11,55 +11,57 @@ // 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 "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsTrkCandHf.h" +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/Core/TrackSelection.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 "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" -#include "Common/Core/TrackSelection.h" -#include "Framework/ASoAHelpers.h" -#include "ReconstructionDataFormats/Track.h" -#include "DataFormatsParameters/GRPObject.h" +#include "DCAFitter/DCAFitterN.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 "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" #include "ReconstructionDataFormats/V0.h" +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -107,29 +109,32 @@ struct highmasslambdasvx { 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.004f, "Minimum DCAxy range for tracks pt 0 to 0.5"}; + 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.0025f, "Minimum DCAxy range for tracks pt 1.0 to 1.5"}; + 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.0015f, "Minimum DCAxy range for tracks pt 2.0 to 3.0"}; - Configurable cfgCutDCAxymin6{"cfgCutDCAxymin6", 0.001f, "Minimum DCAxy range for tracks GT pt 3.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 ispTdepPID{"ispTdepPID", true, "pT dependent PID"}; + 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", 2.0, "Combined nsigma cut"}; - Configurable nsigmaCutCombinedKaon{"nsigmaCutCombinedKaon", 1.5, "Combined nsigma cut Kaon"}; - Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", 2.0, "Combined nsigma cut Pion"}; - Configurable nsigmaCutTPCPre{"nsigmacutTPCPre", 5.0, "Value of the TPC Nsigma cut Pre filter"}; + 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"}; @@ -160,7 +165,7 @@ struct highmasslambdasvx { // using TrackCandidates = soa::Filtered>; // using AllTrackCandidates = soa::Join; - using TrackCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; using AllTrackCandidates = soa::Join; using ResoV0s = soa::Join; @@ -172,10 +177,11 @@ struct highmasslambdasvx { void init(o2::framework::InitContext&) { - std::vector occupancyBinning = {0.0, 500.0, 1500.0, 50000.0}; - std::vector dcaBinning = {0.0, 0.0005, 0.001, 0.002, 0.003, 0.004, 0.006, 0.008, 0.01, 0.015, 0.02, 0.04, 0.08, 0.1, 0.3, 1.0}; - std::vector ptprotonBinning = {0.0, 0.5, 1.0, 1.5, 2.0, 10.0}; + 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"}; @@ -187,16 +193,9 @@ struct highmasslambdasvx { 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, occupancyAxis}); - histos.add("hSparseV2SASameEventRotational_V2_EP", "hSparseV2SASameEventRotational_V2_EP", HistType::kTHnSparseF, {thnAxisInvMass, ptAxis, thnAxisV2, ptProtonAxis, decaylengthAxis, occupancyAxis}); - histos.add("hSparseV2SAMixedEvent_V2_EP", "hSparseV2SAMixedEvent_V2_EP", HistType::kTHnSparseF, {thnAxisInvMass, ptAxis, thnAxisV2, ptProtonAxis, decaylengthAxis, occupancyAxis}); - - histos.add("hSparseV2SASameEvent_V2_IOP", "hSparseV2SASameEvent_V2_IOP", HistType::kTHnSparseF, {thnAxisInvMass, ptAxis, thnAxisPhiminusPsi, ptProtonAxis, decaylengthAxis, occupancyAxis}); - histos.add("hSparseV2SASameEventRotational_V2_IOP", "hSparseV2SASameEventRotational_V2_IOP", HistType::kTHnSparseF, {thnAxisInvMass, ptAxis, thnAxisPhiminusPsi, ptProtonAxis, decaylengthAxis, occupancyAxis}); - histos.add("hSparseV2SAMixedEvent_V2_IOP", "hSparseV2SAMixedEvent_V2_IOP", HistType::kTHnSparseF, {thnAxisInvMass, ptAxis, thnAxisPhiminusPsi, ptProtonAxis, decaylengthAxis, occupancyAxis}); - + 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}}); @@ -275,42 +274,165 @@ struct highmasslambdasvx { } template - bool selectionPID(const T& candidate) + bool rejectPi(const T& candidate) { - if (candidate.pt() < 0.7 && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { - return true; + if (candidate.tpcInnerParam() > 0.9 && candidate.tpcInnerParam() < 1.0 && candidate.tpcNSigmaPi() < 6.0) { + return false; } - if (candidate.pt() >= 0.7 && !candidate.hasTOF() && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -2.0 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { - return true; + if (candidate.tpcInnerParam() > 1.0 && candidate.tpcInnerParam() < 1.1 && candidate.tpcNSigmaPi() < 4.0) { + return false; } - if (candidate.pt() < 0.8 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaPr()) < 10.0) { - return true; + if (candidate.tpcInnerParam() > 1.1 && candidate.tpcInnerParam() < 1.2 && candidate.tpcNSigmaPi() < 3.0) { + return false; } - if (candidate.pt() >= 0.8 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr() + candidate.tofNSigmaPr() * candidate.tofNSigmaPr()) < 2.0 * nsigmaCutCombined * nsigmaCutCombined && TMath::Abs(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) > 2.0 * nsigmaCutCombinedKaon * nsigmaCutCombinedKaon && TMath::Abs(candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) > 2.0 * nsigmaCutCombinedPion * nsigmaCutCombinedPion) { - return true; + if (candidate.tpcInnerParam() > 1.2 && candidate.tpcInnerParam() < 1.4 && candidate.tpcNSigmaPi() < 1.0) { + return false; } - if (candidate.pt() >= 0.8 && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutCombined && TMath::Abs(candidate.tpcNSigmaKa()) > nsigmaCutCombinedKaon && TMath::Abs(candidate.tpcNSigmaPi()) > nsigmaCutCombinedPion) { - return true; + if (candidate.tpcInnerParam() > 1.4 && candidate.tpcInnerParam() < 1.5 && candidate.tpcNSigmaPi() < 0.5) { + return false; } + return true; + } - return false; + 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 selectionPIDNew(const T& candidate) + bool selectionPID1(const T& candidate) { - if (candidate.pt() < 0.7 && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC) { + if (candidate.tpcInnerParam() < 0.7 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { return true; } - if (candidate.pt() >= 0.7 && !candidate.hasTOF() && candidate.pt() < 0.8 && candidate.tpcNSigmaPr() > -2.0 && candidate.tpcNSigmaPr() < nsigmaCutTPC) { + 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.pt() < 0.8 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaPr()) < 10.0) { + 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.pt() >= 0.8 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr() + candidate.tofNSigmaPr() * candidate.tofNSigmaPr()) < 2.0 * nsigmaCutCombined * nsigmaCutCombined && TMath::Abs(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) > 2.0 * nsigmaCutCombinedKaon * nsigmaCutCombinedKaon && TMath::Abs(candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi() + candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) > 2.0 * nsigmaCutCombinedPion * nsigmaCutCombinedPion) { + 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; } @@ -327,13 +449,13 @@ struct highmasslambdasvx { float lowmasscutks0 = 0.497 - 2.0 * cSigmaMassKs0; float highmasscutks0 = 0.497 + 2.0 * cSigmaMassKs0; - if (fabs(CtauK0s) < 2.0 || fabs(CtauK0s) > cMaxV0LifeTime || candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { + if (TMath::Abs(CtauK0s) < 2.0 || TMath::Abs(CtauK0s) > cMaxV0LifeTime || candidate.mK0Short() < lowmasscutks0 || candidate.mK0Short() > highmasscutks0) { return false; } if (dcaDaughv0 > ConfV0DCADaughMax) { return false; } - if (fabs(candidate.dcav0topv()) > cMaxV0DCA) { + if (TMath::Abs(candidate.dcav0topv()) > cMaxV0DCA) { return false; } if (cpav0 < ConfV0CPAMin) { @@ -361,19 +483,19 @@ struct highmasslambdasvx { if (charge > 0 && sign < 0) { return false; } - if (std::abs(eta) > 0.8) { + if (TMath::Abs(eta) > 0.8) { return false; } - if (std::abs(pt) < ConfDaughPt) { + if (TMath::Abs(pt) < ConfDaughPt) { return false; } if (tpcNClsF < ConfDaughTPCnclsMin) { return false; } - if (std::abs(dcaXY) < ConfDaughDCAMin) { + if (TMath::Abs(dcaXY) < ConfDaughDCAMin) { return false; } - if (std::abs(track.tpcNSigmaPi()) > ConfDaughPIDCuts) { + if (TMath::Abs(track.tpcNSigmaPi()) > ConfDaughPIDCuts) { return false; } return true; @@ -396,7 +518,7 @@ struct highmasslambdasvx { ConfigurableAxis axisEPAngle{"axisEPAngle", {1, -TMath::Pi() / 2, TMath::Pi() / 2}, "event plane angle"}; using BinningTypeVertexContributor = ColumnBinningPolicy; - ROOT::Math::PxPyPzMVector Lambdac, Proton, Kshort, LambdacRot, ProtonRot; + 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 @@ -460,14 +582,32 @@ struct highmasslambdasvx { if (!selectionTrack(track1)) { continue; } + + if (!track1.hasTOF()) { + if (!rejectPi(track1)) { + continue; + } + if (!rejectEl(track1)) { + continue; + } + if (!rejectKa(track1)) { + continue; + } + } + // PID check - if (ispTdepPID && !selectionPIDNew(track1)) { + if (PIDstrategy == 0 && !selectionPID1(track1)) { continue; } - if (!ispTdepPID && !selectionPID(track1)) { + 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()); @@ -588,9 +728,7 @@ struct highmasslambdasvx { 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; - if (TMath::Abs(Lambdac.Rapidity()) > confRapidity) { - continue; - } + double protonimpactparameter = impactParameter1.getY(); // double kshortimpactparameter=impactParameter0.getY(); @@ -617,14 +755,12 @@ struct highmasslambdasvx { 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) { + 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, occupancy); - histos.fill(HIST("hSparseV2SASameEvent_V2_IOP"), Lambdac.M(), Lambdac.Pt(), phiminuspsi, Proton.Pt(), decaylength, occupancy); + 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, occupancy); - histos.fill(HIST("hSparseV2SASameEvent_V2_IOP"), Lambdac.M(), Lambdac.Pt(), phiminuspsi, Proton.Pt(), decaylengthxy, occupancy); + 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++) { @@ -633,22 +769,20 @@ struct highmasslambdasvx { auto anglestep = (angleend - anglestart) / (1.0 * (nBkgRotations - 1)); auto rotangle = anglestart + nrotbkg * anglestep; histos.fill(HIST("hRotation"), rotangle); - auto rotProtonPx = Proton.Px() * std::cos(rotangle) - Proton.Py() * std::sin(rotangle); - auto rotProtonPy = Proton.Px() * std::sin(rotangle) + Proton.Py() * std::cos(rotangle); - ProtonRot = ROOT::Math::PxPyPzMVector(rotProtonPx, rotProtonPy, Proton.pz(), massPr); - LambdacRot = ProtonRot + Kshort; + 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) { + 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, occupancy); - histos.fill(HIST("hSparseV2SASameEventRotational_V2_IOP"), LambdacRot.M(), LambdacRot.Pt(), phiminuspsiRot, Proton.Pt(), decaylength, occupancy); + 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, occupancy); - histos.fill(HIST("hSparseV2SASameEventRotational_V2_IOP"), LambdacRot.M(), LambdacRot.Pt(), phiminuspsiRot, Proton.Pt(), decaylengthxy, occupancy); + histos.fill(HIST("hSparseV2SASameEventRotational_V2_EP"), LambdacRot.M(), LambdacRot.Pt(), v2Rot, Proton.Pt(), decaylengthxy, TMath::Abs(track1.dcaXY())); } } } @@ -750,19 +884,19 @@ struct highmasslambdasvx { dcasum = TMath::Sqrt((track1.dcaXY() + (v0.dcav0topv())) * (track1.dcaXY() + (v0.dcav0topv()))); } // auto diffangle = Proton.Phi() - Lambdac.Phi(); - // auto decaylength = std::abs((track1.dcaXY() / TMath::Sin(diffangle)) / (Lambdac.P() / 2.286)); + // 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, std::abs(track1.dcaXY()), Proton.Pt()); + 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, std::abs(track1.dcaXY()), occupancy); + 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, std::abs(track1.dcaXY()), Proton.Pt(), 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); diff --git a/PWGLF/Tasks/Resonances/initializereventqa.cxx b/PWGLF/Tasks/Resonances/initializereventqa.cxx new file mode 100644 index 00000000000..a000b00f13b --- /dev/null +++ b/PWGLF/Tasks/Resonances/initializereventqa.cxx @@ -0,0 +1,474 @@ +// 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 initializereventqa.cxx +/// \brief QA for the event-loss and signal-loss correction at the generator level for the ResonanceInitializer in pp collisions (referred to TableProducer/Strangeness/cascqaanalysis.cxx) +/// +/// Following the discussions at the two PAG meetings (https://indico.cern.ch/event/1518979, https://indico.cern.ch/event/1575984) +/// we have introduced an auxiliary task that, when the resonanceInitializer.cxx is used, +/// computes the event-loss and signal-loss correction factors at the generator level. +/// With minor configuration tuning for a truth-tagging, +/// we expect it to be applicable to most analyses that rely on the initializer. +/// +/// \author Minjae Kim (minjae.kim@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/cascqaanalysis.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "TRandom2.h" +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using TrkPidInfo = soa::Join; +using DauTracks = soa::Join; + +struct Initializereventqa { + + // Templates used, new hedder wil be added + Produces mycascades; + Produces myMCcascades; + + HistogramRegistry registry{"registry"}; + + // Axes + ConfigurableAxis ptAxis{"ptAxis", {400, 0.0f, 20.0f}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis rapidityAxis{"rapidityAxis", {200, -2.0f, 2.0f}, "y"}; + ConfigurableAxis centFT0MAxis{"centFT0MAxis", + {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 70.0, 100.0, 110.0}, + "FT0M (%)"}; + ConfigurableAxis eventTypeAxis{"eventTypeAxis", {2, -0.5f, 1.5f}, "Event Type"}; + + ConfigurableAxis nAssocCollAxis{"nAssocCollAxis", {5, -0.5f, 4.5f}, "N_{assoc.}"}; + ConfigurableAxis nChargedFT0MGenAxis{"nChargedFT0MGenAxis", {300, 0, 300}, "N_{FT0M, gen.}"}; + ConfigurableAxis multNTracksAxis{"multNTracksAxis", {500, 0, 500}, "N_{tracks}"}; + ConfigurableAxis signalFT0MAxis{"signalFT0MAxis", {4000, 0, 40000}, "FT0M amplitude"}; + ConfigurableAxis signalFV0AAxis{"signalFV0AAxis", {4000, 0, 40000}, "FV0A amplitude"}; + ConfigurableAxis nCandidates{"nCandidates", {30, -0.5, 29.5}, "N_{cand.}"}; + + // Event selection criteria + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable isZvtxcut{"isZvtxcut", 1, "Select collisions with Accepted z-vertex"}; + 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", 0, "No collisions in +-2us window"}; + + // QA histograms for the multiplicity estimation + Configurable multQA{"multQA", 1, "0 - not to do QA, 1 - do the QA"}; + + // Selection for signal-loss corrections + Configurable isDaughterCheck{"isDaughterCheck", 1, "Check if the candidate has the correct daughters when it is considered"}; + + Configurable cfgRapidityCut{"cfgRapidityCut", 0.5, "Rapidity cut for the truth particle"}; + + Configurable pdgTruthMother{"pdgTruthMother", 3324, "pdgcode for the truth mother particle, e.g. Xi(1530) (3324)"}; + Configurable pdgTruthDaughter1{"pdgTruthDaughter1", 3312, "pdgcode for the first daughter particle, e.g. Xi-3312"}; + Configurable pdgTruthDaughter2{"pdgTruthDaughter2", 211, "pdgcode for the second daughter particle, e.g. Xi-3312"}; + + // Necessary for particle charges + Service pdgDB; + + SliceCache cache; + + // Struct to select on event type + typedef struct CollisionIndexAndType { + int64_t index; + uint8_t typeFlag; + } CollisionIndexAndType; + + void init(InitContext const&) + { + TString hNEventsMCLabels[5] = {"All", "z vrtx", "INEL", "INEL>0", "Associated with rec. collision"}; + TString hNEventsLabels[12] = {"All", "kIsTriggerTVX", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kIsVertexITSTPC", "kNoSameBunchPileup", "kIsGoodZvtxFT0vsPV", "isVertexTOFmatched", "kNoCollInTimeRangeNarrow", "z vrtx", "INEL", "INEL>0"}; + + registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{12, 0.f, 12.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::kTH1D, {{200, -20.f, 20.f}}}); + + registry.add("fakeEvents", "fakeEvents", {HistType::kTH1F, {{1, -0.5f, 0.5f}}}); + + registry.add("hNEventsMC", "hNEventsMC", {HistType::kTH1D, {{5, 0.0f, 5.0f}}}); + 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::kTH1D, {{200, -20.f, 20.f}}}); + registry.add("hCentFT0MNAssocMCCollisions", "hCentFT0MNAssocMCCollisions", {HistType::kTH3D, {centFT0MAxis, nAssocCollAxis, eventTypeAxis}}); + registry.add("hCentFT0MNAssocMCCollisionsSameType", "hCentFT0MNAssocMCCollisionsSameType", {HistType::kTH3D, {centFT0MAxis, nAssocCollAxis, eventTypeAxis}}); + registry.add("hNchFT0MNAssocMCCollisions", "hNchFT0MNAssocMCCollisions", {HistType::kTH3D, {nChargedFT0MGenAxis, nAssocCollAxis, eventTypeAxis}}); + registry.add("hNchFT0MNAssocMCCollisionsSameType", "hNchFT0MNAssocMCCollisionsSameType", {HistType::kTH3D, {nChargedFT0MGenAxis, nAssocCollAxis, eventTypeAxis}}); + 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::kTH2D, {nChargedFT0MGenAxis, eventTypeAxis}}); + registry.add("hCentFT0M_genMC", "hCentFT0M_genMC", {HistType::kTH2D, {centFT0MAxis, eventTypeAxis}}); + + registry.add("hCentFT0M_rec", "hCentFT0M_rec", {HistType::kTH2D, {centFT0MAxis, eventTypeAxis}}); + registry.add("hCentFT0M_corr", "hCentFT0M_Corr", {HistType::kTH2D, {centFT0MAxis, centFT0MAxis}}); + + if (multQA) { + registry.add("hNchFT0Mglobal", "hNchFT0Mglobal", {HistType::kTH3D, {nChargedFT0MGenAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hNchFT0MPVContr", "hNchFT0MPVContr", {HistType::kTH3D, {nChargedFT0MGenAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFT0MpvContr", "hFT0MpvContr", {HistType::kTH3D, {centFT0MAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFT0Mglobal", "hFT0Mglobal", {HistType::kTH3D, {centFT0MAxis, multNTracksAxis, eventTypeAxis}}); + registry.add("hFT0MsignalPVContr", "hFT0MsignalPVContr", {HistType::kTH3D, {signalFT0MAxis, multNTracksAxis, eventTypeAxis}}); + } + + registry.add("h3ResonanceTruth", "pT distribution of True Resonance", kTHnSparseF, {eventTypeAxis, ptAxis, centFT0MAxis}); + registry.add("h3ResonanceTruthAnti", "pT distribution of True Resonance Anti", kTHnSparseF, {eventTypeAxis, ptAxis, centFT0MAxis}); + } + float pvEta1 = 1.0f; + float globalEta05 = 0.5f; + + Partition pvContribTracksIUEta1 = (nabs(aod::track::eta) < pvEta1) && ((aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor)); + Partition globalTracksIUEta05 = (nabs(aod::track::eta) < globalEta05) && (requireGlobalTrackInFilter()); + + template + uint16_t getGenNchInFT0Mregion(TMcParticles particles) + { + float region1FT0 = -3.3f; + float region2FT0 = -2.1f; + float region3FT0 = 3.5f; + float region4FT0 = 4.9f; + // Particle counting in FITFT0: -3.3<η<-2.1; 3.5<η<4.9 + uint16_t nchFT0 = 0; + for (const auto& mcParticle : particles) { + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + const auto& pdgInfo = pdgDB->GetParticle(mcParticle.pdgCode()); + if (!pdgInfo) { + continue; + } + if (pdgInfo->Charge() == 0) { + continue; + } + if (mcParticle.eta() < region1FT0 || mcParticle.eta() > region4FT0 || (mcParticle.eta() > region2FT0 && mcParticle.eta() < region3FT0)) { + continue; // select on T0M Nch region + } + nchFT0++; // increment + } + return nchFT0; + } + + template + bool acceptEvent(TCollision const& collision, bool isFillEventSelectionQA) + { + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 0.5); + } + + // kIsTriggerTVX selection + if (isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 1.5); + } + + // kNoTimeFrameBorder selection + if (isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 2.5); + } + + // kNoITSROFrameBorder selection + if (isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 3.5); + } + + // kIsVertexITSTPC selection + if (isVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 4.5); + } + // kNoSameBunchPileup selection + if (isNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 5.5); + } + // 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); + } + + // Z vertex selection + if (isZvtxcut && std::fabs(collision.posZ()) > cutzvertex) { + return false; + } + if (isFillEventSelectionQA) { + registry.fill(HIST("hNEvents"), 9.5); + registry.fill(HIST("hZCollision"), collision.posZ()); + } + + return true; + } + + template + void fillMCParticles(TotalMCParts const& mcParticles, MultMCGen const& multiplicity, evtType const& eventType) + { + for (auto const& mcPart : mcParticles) { + + if (std::abs(mcPart.pdgCode()) != pdgTruthMother || std::abs(mcPart.y()) >= cfgRapidityCut) + continue; + 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}; + } + + if (isDaughterCheck) { + bool pass1 = std::abs(daughterPDGs[0]) == pdgTruthDaughter1 || std::abs(daughterPDGs[1]) == pdgTruthDaughter1; + bool pass2 = std::abs(daughterPDGs[0]) == pdgTruthDaughter2 || std::abs(daughterPDGs[1]) == pdgTruthDaughter2; + if (!pass1 || !pass2) + continue; + } + if (mcPart.pdgCode() > 0) // Consider INELt0 or INEL + registry.fill(HIST("h3ResonanceTruth"), eventType, mcPart.pt(), multiplicity); + else + registry.fill(HIST("h3ResonanceTruthAnti"), eventType, mcPart.pt(), multiplicity); + + daughterPDGs.clear(); + } + } + void processData(soa::Join::iterator const& collision, + DauTracks const&) + { + if (!acceptEvent(collision, 1)) { + return; + } + + int evType = 0; + registry.fill(HIST("hNEvents"), 10.5); // INEL + if (collision.isInelGt0()) { + evType += 1; + registry.fill(HIST("hNEvents"), 11.5); // INEL>0 + } + + auto tracksGroupedPVcontr = pvContribTracksIUEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + int nTracksPVcontr = tracksGroupedPVcontr.size(); + + auto tracksGroupedGlobal = globalTracksIUEta05->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + int nTracksGlobal = tracksGroupedGlobal.size(); + + registry.fill(HIST("hCentFT0M_rec"), collision.centFT0M(), evType); + + if (multQA) { + registry.fill(HIST("hFT0MpvContr"), collision.centFT0M(), nTracksPVcontr, evType); + registry.fill(HIST("hFT0Mglobal"), collision.centFT0M(), nTracksGlobal, evType); + registry.fill(HIST("hFT0MsignalPVContr"), collision.multFT0A() + collision.multFT0C(), nTracksPVcontr, evType); + } + } + + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + void processMCrec(soa::Join::iterator const& collision, + soa::Join const&, + DauTracks const&, + aod::McParticles const& mcParticles) + { + if (!acceptEvent(collision, 1)) { + return; + } + + if (!collision.has_mcCollision()) { + registry.fill(HIST("fakeEvents"), 0); // no assoc. MC collisions + return; + } + + const auto& mcCollision = collision.mcCollision_as>(); + + auto tracksGroupedPVcontr = pvContribTracksIUEta1->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + int nTracksPVcontr = tracksGroupedPVcontr.size(); + + auto tracksGroupedGlobal = globalTracksIUEta05->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + 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); + + int evType = 0; + registry.fill(HIST("hNEvents"), 10.5); // reco INEL + if (collision.isInelGt0()) { + evType += 1; + registry.fill(HIST("hNEvents"), 11.5); // reco INEL>0 + } + + registry.fill(HIST("hCentFT0M_rec"), mcCollision.centFT0M(), evType); // correction only reco level in this stage + registry.fill(HIST("hCentFT0M_corr"), mcCollision.centFT0M(), mcCollision.centFT0M(), evType); + + if (multQA) { + registry.fill(HIST("hNchFT0MPVContr"), nchFT0, nTracksPVcontr, evType); + registry.fill(HIST("hFT0MpvContr"), mcCollision.centFT0M(), nTracksPVcontr, evType); + registry.fill(HIST("hFT0Mglobal"), mcCollision.centFT0M(), nTracksGlobal, evType); + registry.fill(HIST("hNchFT0Mglobal"), nchFT0, nTracksGlobal, evType); + registry.fill(HIST("hFT0MsignalPVContr"), collision.multFT0A() + collision.multFT0C(), nTracksPVcontr, evType); + } + } + + void processMCgen(soa::Join::iterator const& mcCollision, + aod::McParticles const& mcParticles, + const soa::SmallGroups>& collisions) + { + auto cent = mcCollision.centFT0M(); + + registry.fill(HIST("hNEventsMC"), 0.5); + + if (isZvtxcut && std::fabs(mcCollision.posZ()) > cutzvertex) { + return; + } + registry.fill(HIST("hZCollisionGen"), mcCollision.posZ()); + registry.fill(HIST("hNEventsMC"), 1.5); + + int evType = 0; + registry.fill(HIST("hNEventsMC"), 2.5); + if (pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { // Truth INEL>0 + evType++; + registry.fill(HIST("hNEventsMC"), 3.5); + } + + fillMCParticles(mcParticles, cent, evType); + + registry.fill(HIST("hCentFT0M_genMC"), cent, evType); + + uint16_t nchFT0 = getGenNchInFT0Mregion(mcParticles); + registry.fill(HIST("hNchFT0MGenEvType"), nchFT0, evType); + + std::vector selectedEvents(collisions.size()); + std::vector numberOfContributors; + int nevts = 0; + int nAssocColl = 0; + const int nContSize = 2; + for (const auto& collision : collisions) { + CollisionIndexAndType collWithType = {0, 0x0}; + if (!acceptEvent(collision, 0)) { + continue; + } + collWithType.index = collision.mcCollision_as>().globalIndex(); + collWithType.typeFlag |= o2::aod::myMCcascades::EvFlags::EvINEL; + + if (collision.isInelGt0()) { // reco INEL>0 + collWithType.typeFlag |= o2::aod::myMCcascades::EvFlags::EvINELgt0; + } + selectedEvents[nevts++] = collWithType; + if (collision.mcCollision_as>().globalIndex() == mcCollision.globalIndex()) { + nAssocColl++; + numberOfContributors.push_back(collision.numContrib()); + } + } + selectedEvents.resize(nevts); + + registry.fill(HIST("hCentFT0MNAssocMCCollisions"), cent, nAssocColl, evType); + registry.fill(HIST("hNchFT0MNAssocMCCollisions"), nchFT0, nAssocColl, evType); + + if (numberOfContributors.size() == nContSize) { + 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); }; + // number of reconstructed INEL events that have the same global index as mcCollision + 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); + switch (evType) { + case 0: { + registry.fill(HIST("hCentFT0MNAssocMCCollisionsSameType"), cent, evtReconstructedAndINEL, evType); + registry.fill(HIST("hNchFT0MNAssocMCCollisionsSameType"), nchFT0, evtReconstructedAndINEL, evType); + break; + } + case 1: { + registry.fill(HIST("hCentFT0MNAssocMCCollisionsSameType"), cent, evtReconstructedAndINELgt0, evType); + registry.fill(HIST("hNchFT0MNAssocMCCollisionsSameType"), nchFT0, evtReconstructedAndINELgt0, evType); + break; + } + default: + LOGF(fatal, "incorrect evType in event task"); + break; + } + + if (evtReconstructedAndINELgt0) { // N INEL>0 reconstructed events associated with the MC collision + registry.fill(HIST("hNEventsMC"), 4.5); + } + } + PROCESS_SWITCH(Initializereventqa, processData, "Process Run 3 data", false); + PROCESS_SWITCH(Initializereventqa, processMCrec, "Process Run 3 mc, Reconstructed", true); + PROCESS_SWITCH(Initializereventqa, processMCgen, "Process Run 3 mc, genereated", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} diff --git a/PWGLF/Tasks/Resonances/k1AnalysisMicro.cxx b/PWGLF/Tasks/Resonances/k1AnalysisMicro.cxx new file mode 100644 index 00000000000..0c6b147d13e --- /dev/null +++ b/PWGLF/Tasks/Resonances/k1AnalysisMicro.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. +/// +/// \file k1AnalysisMicro.cxx +/// \brief Reconstruction of track-track decay resonance candidates +/// \author Su-Jeong Ji , Bong-Hwi Lim +/// + +#include "PWGLF/DataModel/LFResonanceTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include // FIXME +#include +#include // FIXME + +#include + +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; +; + +struct K1AnalysisMicro { + 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 + // 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 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 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 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 cMinSecondaryPtCut{"cMinSecondaryPtCut", 0.5, "Min pT cut for secondary selection"}; + /* + Configurable cfgModeK892orRho{"cfgModeK892orRho", false, "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"}; + Configurable cMaxPairAsym{"cMaxPairAsym", 1, "Maximum pair asymmetry"}; +*/ + + // K1 selection + Configurable cK1MaxRap{"cK1MaxRap", 0.5, "K1 maximum rapidity"}; + Configurable cK1MinRap{"cK1MinRap", -0.5, "K1 minimum rapidity"}; + + void init(o2::framework::InitContext&) + { + std::vector centBinning = {0., 1., 5., 10., 15., 20., 25., 30., 35., 40., 45., 50., 55., 60., 65., 70., 80., 90., 100., 200.}; + AxisSpec centAxis = {centBinning, "T0M (%)"}; + 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{z}} (cm)"}; + 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"}; + + // 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 + // Primary pion + histos.add("QA/trkppionDCAxy", "DCAxy disstribution of primary pion candidates", HistType::kTH1F, {dcaxyAxis}); + histos.add("QA/trkppionDCAz", "DCAz disstribution of primary pion candidates", HistType::kTH1F, {dcazAxis}); + 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, {dcazAxis}); + 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, {dcazAxis}); + 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, {dcazAxis}); + 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, {dcazAxis}); + 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, {dcazAxis}); + 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/K1PairAsym", "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, {invMassAxisRho, 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/K1PairAsym", "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, {invMassAxisRho, 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) (US)", HistType::kTHnSparseD, {axisAnti, axisType, centAxis, ptAxis, invMassAxisReso}); + histos.add("hInvmass_K1_LS", "Invariant mass of K1(1270) (LS)", HistType::kTHnSparseD, {axisAnti, axisType, centAxis, ptAxis, invMassAxisReso}); + histos.add("hInvmass_K1_Mix", "Invariant mass of K1(1270) (ME)", HistType::kTHnSparseD, {axisAnti, axisType, centAxis, ptAxis, invMassAxisReso}); + // Mass QA (quick check) + histos.add("k1invmass", "Invariant mass of K1(1270) (US)", HistType::kTH1F, {invMassAxisReso}); + histos.add("k1invmass_LS", "Invariant mass of K1(1270) (LS)", HistType::kTH1F, {invMassAxisReso}); + histos.add("k1invmass_Mix", "Invariant mass of K1(1270) (ME)", HistType::kTH1F, {invMassAxisReso}); + + // MC + if (doprocessMC) { + 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, {dcazAxis}); + 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, {dcazAxis}); + 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, {dcazAxis}); + 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/K1PairAsym", "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, {invMassAxisRho, 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}); + } // doprocessMC + // Print output histograms statistics + LOG(info) << "Size of the histograms in K1 Analysis Task"; + histos.print(); + } // init + + // PDG code + int kPDGRho770 = 113; + int kK1Plus = 10323; + + template + bool trackCut(const TrackType track) + { + if constexpr (!IsResoMicrotrack) { + // 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 (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; + } else { + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > cMaxDCArToPVcut - Epsilon) + return false; + if (o2::aod::resomicrodaughter::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; + } + + // Pion PID selection tools + template + bool selectionPIDpion(const T& candidate) + { + if constexpr (!IsResoMicrotrack) { + 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) { + 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; + } + } else { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + tpcPIDPassed = std::abs(o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPiFlag())) < cMaxTPCnSigmaPion + Epsilon; + tofPIDPassed = candidate.hasTOF() ? std::abs(o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaPiFlag())) < cMaxTOFnSigmaPion + Epsilon : true; + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + } + return false; + } + + // Kaon PID selection tools + template + bool selectionPIDkaon(const T& candidate) + { + if constexpr (!IsResoMicrotrack) { + 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) { + tofPIDPassed = true; + } + if ((nsigmaCutCombinedKaon > 0) && (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa() < nsigmaCutCombinedKaon * nsigmaCutCombinedKaon)) { + tofPIDPassed = true; + } + } else { + if (!cTOFVeto) { + return false; + } + tofPIDPassed = true; + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + } else { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + tpcPIDPassed = std::abs(o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaKaFlag())) < cMaxTPCnSigmaKaon + Epsilon; + tofPIDPassed = candidate.hasTOF() ? std::abs(o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaKaFlag())) < cMaxTOFnSigmaKaon + Epsilon : true; + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + } + return false; + } + + template + bool isTrueK1(const T& trk1, const T& trk2, const T2& bTrack) + { + if (std::abs(trk1.pdgCode()) != kPiPlus || std::abs(trk2.pdgCode()) != kPiPlus) + return false; + if (std::abs(bTrack.pdgCode()) != kKPlus) + return false; + auto mother1 = trk1.motherId(); + auto mother2 = trk2.motherId(); + if (mother1 != mother2) + return false; + if (((std::abs(trk1.motherPDG()) && std::abs(trk2.motherPDG()) != kPDGRho770) && (std::abs(bTrack.motherPDG()) != kK1Plus)) || (std::abs(trk1.motherPDG()) && std::abs(bTrack.motherPDG()) != kK0Star892 && (std::abs(trk2.motherPDG()) != kK1Plus)) || (std::abs(trk2.motherPDG()) && std::abs(bTrack.motherPDG()) != kK0Star892 && (std::abs(trk1.motherPDG()) != kK1Plus))) + return false; + auto siblings = bTrack.siblingIds(); + if (siblings[0] != mother1 && siblings[1] != mother2) + return false; + return true; + } // isTrueK1 + + template + bool isTrueK892(const T& trk1, const T& trk2) + { + if (std::abs(trk1.pdgCode()) != kPiPlus || std::abs(trk2.pdgCode()) != kKPlus) + return false; + auto mother1 = trk1.motherId(); + auto mother2 = trk2.motherId(); + if (mother1 != mother2) + return false; + if (std::abs(trk1.motherPDG()) != kK0Star892) + return false; + return true; + } + + template + bool isTrueRho(const T& trk1, const T& trk2) + { + if (std::abs(trk1.pdgCode()) != kPiPlus || std::abs(trk2.pdgCode()) != kPiPlus) + return false; + auto mother1 = trk1.motherId(); + auto mother2 = trk2.motherId(); + if (mother1 != mother2) + return false; + if (std::abs(trk1.motherPDG()) != kPDGRho770) + return false; + return true; + } + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + { + auto multiplicity = collision.cent(); + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonanceSecondary, lDecayDaughter_bach, lResonanceK1; + for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks2, 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 too. But the same id pairs are not needed. + // trk1: pion, trk2: pion, bTrack: kaon + if (!trackCut(trk1) || !trackCut(trk2)) + continue; + + auto trk1pt = trk1.pt(); + auto trk2pt = trk2.pt(); + auto isTrk1hasTOF = trk1.hasTOF(); + auto isTrk2hasTOF = trk2.hasTOF(); + + if constexpr (!IsResoMicrotrack) { + auto trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); + auto trk1NSigmaPiTOF = (isTrk1hasTOF) ? trk1.tofNSigmaPi() : -999.; + auto trk2NSigmaPiTPC = trk2.tpcNSigmaPi(); + auto trk2NSigmaPiTOF = (isTrk2hasTOF) ? trk2.tofNSigmaPi() : -999.; + + if (cUseOnlyTOFTrackPi && !isTrk1hasTOF) + continue; + if (!selectionPIDpion(trk1) || !selectionPIDpion(trk2)) + continue; + + if constexpr (!IsMix) { + + histos.fill(HIST("QA/trkppionTPCPID"), trk1pt, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/trkppionTOFPID"), trk1pt, trk1NSigmaPiTOF); + histos.fill(HIST("QA/trkppionTPCTOFPID"), trk1NSigmaPiTPC, trk1NSigmaPiTOF); + } + histos.fill(HIST("QA/trkppionpT"), trk1pt); + histos.fill(HIST("QA/trkppionDCAxy"), trk1.dcaXY()); + histos.fill(HIST("QA/trkppionDCAz"), trk1.dcaZ()); + + histos.fill(HIST("QA/trkspionTPCPID"), trk2pt, trk2NSigmaPiTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/trkspionTOFPID"), trk2pt, trk2NSigmaPiTOF); + histos.fill(HIST("QA/trkspionTPCTOFPID"), trk2NSigmaPiTPC, trk2NSigmaPiTOF); + } + histos.fill(HIST("QA/trkspionpT"), trk2pt); + histos.fill(HIST("QA/trkspionDCAxy"), trk2.dcaXY()); + histos.fill(HIST("QA/trkspionDCAz"), trk2.dcaZ()); + } + } else { + histos.fill(HIST("QA/trkppionTPCPID"), trk1pt, o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk1.pidNSigmaPiFlag())); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/trkppionTOFPID"), trk1pt, o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk1.pidNSigmaPiFlag())); + histos.fill(HIST("QA/trkppionTPCTOFPID"), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk1.pidNSigmaPiFlag()), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk1.pidNSigmaPiFlag())); + } + histos.fill(HIST("QA/trkppionpT"), trk1pt); + histos.fill(HIST("QA/trkppionDCAxy"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(trk1.trackSelectionFlags())); + histos.fill(HIST("QA/trkppionDCAz"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(trk1.trackSelectionFlags())); + + histos.fill(HIST("QA/trkspionTPCPID"), trk2pt, o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk2.pidNSigmaPiFlag())); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/trkspionTOFPID"), trk2pt, o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk2.pidNSigmaPiFlag())); + histos.fill(HIST("QA/trkspionTPCTOFPID"), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk2.pidNSigmaPiFlag()), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk2.pidNSigmaPiFlag())); + } + histos.fill(HIST("QA/trkspionpT"), trk2pt); + histos.fill(HIST("QA/trkspionDCAxy"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(trk2.trackSelectionFlags())); + histos.fill(HIST("QA/trkspionDCAz"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(trk2.trackSelectionFlags())); + } + + // Resonance reconstruction + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), MassPionCharged); + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), MassPionCharged); + lResonanceSecondary = lDecayDaughter1 + lDecayDaughter2; + + if (lResonanceSecondary.Pt() < cMinSecondaryPtCut) + continue; + + if constexpr (!IsMix) { + histos.fill(HIST("QA/hInvmassSecon"), lResonanceSecondary.M()); + } + if constexpr (IsMC) { + /* + 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()); + } + */ + histos.fill(HIST("QAMC/hpT_Secondary"), lResonanceSecondary.Pt()); + } + // Mass Window cut is removed + + for (const auto& bTrack : dTracks1) { + if (bTrack.index() == trk1.index() || bTrack.index() == trk2.index()) + continue; + if (!trackCut(bTrack)) + continue; + if (!selectionPIDkaon(bTrack)) + continue; + + // K1 reconstruction + lDecayDaughter_bach.SetXYZM(bTrack.px(), bTrack.py(), bTrack.pz(), MassKaonCharged); + lResonanceK1 = lResonanceSecondary + lDecayDaughter_bach; + + // Cuts + if (lResonanceK1.Rapidity() > cK1MaxRap || lResonanceK1.Rapidity() < cK1MinRap) + continue; + + 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 histogram + if constexpr (!IsMix) { + histos.fill(HIST("QA/K1OA"), lK1Angle); + histos.fill(HIST("QA/K1PairAsym"), lPairAsym); + 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()); + } + // Selection cuts are removed + // QA histograms after the cuts are removed as no cuts are applied + + if constexpr (!IsMix) { + unsigned int typeK1 = bTrack.sign() > 0 ? BinType::kK1P : BinType::kK1N; + unsigned int typeNormal = BinAnti::kNormal; + if (trk1.sign() * trk2.sign() < 0) { + histos.fill(HIST("k1invmass"), lResonanceK1.M()); + histos.fill(HIST("hInvmass_K1"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); + } else { + histos.fill(HIST("k1invmass_LS"), lResonanceK1.M()); + histos.fill(HIST("hInvmass_K1_LS"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); + } + + if constexpr (IsMC) { + if (isTrueK1(trk1, trk2, bTrack)) { + 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/K1PairAsym"), lPairAsym); + histos.fill(HIST("QAMC/hInvmassK892_Rho"), temp13.M(), lResonanceSecondary.M()); + histos.fill(HIST("QAMC/hInvmassSecon_PiKa"), lResonanceSecondary.M(), temp23.M()); + histos.fill(HIST("QAMC/hInvmassSecon"), lResonanceSecondary.M()); + histos.fill(HIST("QAMC/hpT_Seocondary"), lResonanceSecondary.Pt()); + + if constexpr (!IsResoMicrotrack) { + + auto trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); + auto trk1NSigmaPiTOF = (isTrk1hasTOF) ? trk1.tofNSigmaPi() : -999.; + auto trk2NSigmaPiTPC = trk2.tpcNSigmaPi(); + auto trk2NSigmaPiTOF = (isTrk2hasTOF) ? trk2.tofNSigmaPi() : -999.; + + // PID QA primary pion + histos.fill(HIST("QAMC/trkppionTPCPID"), trk1pt, trk1NSigmaPiTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QAMC/trkppionTOFPID"), trk1pt, trk1NSigmaPiTOF); + histos.fill(HIST("QAMC/trkppionTPCTOFPID"), trk1NSigmaPiTPC, trk1NSigmaPiTOF); + } + histos.fill(HIST("QAMC/trkppionpT"), trk1pt); + histos.fill(HIST("QAMC/trkppionDCAxy"), trk1.dcaXY()); + histos.fill(HIST("QAMC/trkppionDCAz"), trk1.dcaZ()); + + // PID QA secondary pion + histos.fill(HIST("QAMC/trkspionTPCPID"), trk2pt, trk2NSigmaPiTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QAMC/trkspionTOFPID"), trk2pt, trk2NSigmaPiTOF); + histos.fill(HIST("QAMC/trkspionTPCTOFPID"), trk2NSigmaPiTPC, trk2NSigmaPiTOF); + } + histos.fill(HIST("QAMC/trkspionpT"), trk2pt); + histos.fill(HIST("QAMC/trkspionDCAxy"), trk2.dcaXY()); + histos.fill(HIST("QAMC/trkspionDCAz"), trk2.dcaZ()); + + } else { + + histos.fill(HIST("QAMC/trkppionTPCPID"), trk1pt, o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk1.pidNSigmaSelectionFlags())); + if (isTrk1hasTOF) { + histos.fill(HIST("QAMC/trkppionTOFPID"), trk1pt, o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk1.pidNSigmaSelectionFlags())); + histos.fill(HIST("QAMC/trkppionTPCTOFPID"), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk1.pidNSigmaSelectionFlags()), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk1.pidNSigmaSelectionFlags())); + } + histos.fill(HIST("QAMC/trkppionpT"), trk1pt); + histos.fill(HIST("QAMC/trkppionDCAxy"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(trk1.trackSelectionFlags())); + histos.fill(HIST("QAMC/trkppionDCAz"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(trk1.trackSelectionFlags())); + + // PID QA secondary pion + histos.fill(HIST("QAMC/trkspionTPCPID"), trk2pt, o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk2.pidNSigmaSelectionFlags())); + if (isTrk2hasTOF) { + histos.fill(HIST("QAMC/trkspionTOFPID"), trk2pt, o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk2.pidNSigmaSelectionFlags())); + histos.fill(HIST("QAMC/trkspionTPCTOFPID"), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk2.pidNSigmaSelectionFlags()), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk2.pidNSigmaSelectionFlags())); + } + histos.fill(HIST("QAMC/trkspionpT"), trk2pt); + histos.fill(HIST("QAMC/trkspionDCAxy"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(trk2.trackSelectionFlags())); + histos.fill(HIST("QAMC/trkspionDCAz"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(trk2.trackSelectionFlags())); + } + } else { + histos.fill(HIST("k1invmass_MC_noK1"), lResonanceK1.M()); + } + } // IsMC + } else { + unsigned int typeK1 = bTrack.sign() > 0 ? BinType::kK1P_Mix : BinType::kK1N_Mix; + unsigned int typeNormal = BinAnti::kNormal; + histos.fill(HIST("hInvmass_K1_Mix"), typeNormal, typeK1, multiplicity, lResonanceK1.Pt(), lResonanceK1.M()); + histos.fill(HIST("k1invmass_Mix"), lResonanceK1.M()); + } + } // bTrack + } + } // fillHistograms + + void processResoTracks(aod::ResoCollision const& collision, + aod::ResoTracks const& resotracks) + { + fillHistograms(collision, resotracks, resotracks); + } + PROCESS_SWITCH(K1AnalysisMicro, processResoTracks, "Process ResoTracks", false); + + void processResoMicroTracks(aod::ResoCollision const& collision, + aod::ResoMicroTracks const& resomicrotracks) + { + fillHistograms(collision, resomicrotracks, resomicrotracks); + } + PROCESS_SWITCH(K1AnalysisMicro, processResoMicroTracks, "Process ResoMicroTracks", true); + + void processMC(aod::ResoCollision const& collision, + soa::Join const& resotracks) + { + fillHistograms(collision, resotracks, resotracks); + } + PROCESS_SWITCH(K1AnalysisMicro, processMC, "Process Event for MC", false); + + void processMCTrue(ResoMCCols::iterator const& collision, aod::ResoMCParents const& resoParents) + { + auto multiplicity = collision.cent(); + for (const auto& part : resoParents) { + if (std::abs(part.pdgCode()) != kK1Plus) + continue; + if (std::abs(part.y()) > 0.5) { + continue; + } + bool pass1 = false; + bool pass2 = false; + bool pass3 = false; + bool pass4 = false; + if (std::abs(part.daughterPDG1()) == 313 || std::abs(part.daughterPDG2()) == 313) { // At least one decay into K892 + pass2 = true; + } + if (std::abs(part.daughterPDG1()) == kPiPlus || std::abs(part.daughterPDG2()) == kPiPlus) { // At lest one decay into pion + pass1 = true; + } + if (std::abs(part.daughterPDG1()) == kPDGRho770 || std::abs(part.daughterPDG2()) == kPDGRho770) { + pass4 = true; + } + if (std::abs(part.daughterPDG1()) == kKPlus || std::abs(part.daughterPDG2()) == kKPlus) { + pass3 = true; + } + if (!pass1 || !pass2 || !pass3 || !pass4) // If we have both decay products + continue; + auto typeNormal = part.pdgCode() > 0 ? BinAnti::kNormal : BinAnti::kAnti; + if (collision.isVtxIn10()) // INEL>10 + { + 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); + } + } + } + PROCESS_SWITCH(K1AnalysisMicro, processMCTrue, "Process Event for MC", false); + + // Processing Event Mixing + using BinningTypeVtxZT0M = ColumnBinningPolicy; + void processME(o2::aod::ResoCollisions const& collisions, aod::ResoTracks const& resotracks) + { + auto tracksTuple = std::make_tuple(resotracks); + BinningTypeVtxZT0M colBinning{{cfgVtxBins, cfgMultBins}, true}; + SameKindPair pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + fillHistograms(collision1, tracks1, tracks2); + } + }; + PROCESS_SWITCH(K1AnalysisMicro, processME, "Process EventMixing light without partition", false); + + // Processing Event Mixing -- Micro + // using BinningTypeVtxZT0M = ColumnBinningPolicy; + void processMEMicro(o2::aod::ResoCollisions const& collisions, aod::ResoMicroTracks const& resomicrotracks) + { + auto tracksTuple = std::make_tuple(resomicrotracks); + BinningTypeVtxZT0M colBinning{{cfgVtxBins, cfgMultBins}, true}; + SameKindPair pairs{colBinning, nEvtMixing, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + fillHistograms(collision1, tracks1, tracks2); + } + }; + PROCESS_SWITCH(K1AnalysisMicro, processMEMicro, "Process EventMixing light without partition", true); +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/k1analysis.cxx b/PWGLF/Tasks/Resonances/k1analysis.cxx index e3599531046..a743c349c51 100644 --- a/PWGLF/Tasks/Resonances/k1analysis.cxx +++ b/PWGLF/Tasks/Resonances/k1analysis.cxx @@ -15,67 +15,105 @@ /// /// \author Bong-Hwi Lim -#include -#include // FIXME -#include // FIXME +#include "PWGLF/DataModel/LFResonanceTables.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisTask.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "DataFormatsParameters/GRPObject.h" + +#include // FIXME +#include +#include // FIXME + +#include 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 +130,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 (track.dcaXY() > cMaxDCArToPVcut) + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) return false; - if (track.dcaZ() < cMinDCAzToPVcut || track.dcaZ() > cMaxDCAzToPVcut) + 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 (cfgPVContributor && !track.isPVContributor()) + if (cfgGlobalTrack && !track.isGlobalTrack()) return false; + return true; } @@ -204,6 +296,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 +307,9 @@ struct k1analysis { tofPIDPassed = true; } } else { + if (!cTOFVeto) { + return false; + } tofPIDPassed = true; } if (tpcPIDPassed && tofPIDPassed) { @@ -226,6 +323,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 +334,9 @@ struct k1analysis { tofPIDPassed = true; } } else { + if (!cTOFVeto) { + return false; + } tofPIDPassed = true; } if (tpcPIDPassed && tofPIDPassed) { @@ -245,6 +347,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 +390,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 +413,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 +425,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 +653,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..18bc381a6f6 100644 --- a/PWGLF/Tasks/Resonances/k892SpherocityAnalysis.cxx +++ b/PWGLF/Tasks/Resonances/k892SpherocityAnalysis.cxx @@ -13,17 +13,18 @@ /// \brief Invariant Mass Reconstruction of K*(892) Resonance /// \author Sayan Dhani -#include -#include +#include "PWGLF/DataModel/LFResonanceTables.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisTask.h" + +#include "CommonConstants/PhysicsConstants.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "CommonConstants/PhysicsConstants.h" + +#include +#include using namespace o2; using namespace o2::framework; @@ -437,7 +438,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 14e5f4e496e..e18af86a5fa 100644 --- a/PWGLF/Tasks/Resonances/k892analysis.cxx +++ b/PWGLF/Tasks/Resonances/k892analysis.cxx @@ -8,25 +8,29 @@ // In applying this license CERN does not 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 /// /// /// \author Bong-Hwi Lim , Sawan Sawan -#include -#include "TF1.h" +#include "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisTask.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "DataFormatsParameters/GRPObject.h" -#include "CommonConstants/PhysicsConstants.h" + +#include "TF1.h" +#include "TRandom3.h" +#include using namespace o2; using namespace o2::framework; @@ -34,7 +38,7 @@ 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; @@ -47,6 +51,7 @@ struct k892analysis { 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"}; @@ -54,10 +59,19 @@ 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 cisInelGt0{"cisInelGt0", true, "check if INEL>0"}; + Configurable cMCCent{"cMCCent", true, "Using calibrated MC centrality (for FT0M)"}; + + // 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"}; @@ -87,18 +101,18 @@ struct k892analysis { 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 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 cfgHasITS{"cfgHasITS", false, "Require ITS"}; - Configurable cfgHasTPC{"cfgHasTPC", false, "Require TPC"}; 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"}; @@ -117,6 +131,7 @@ struct k892analysis { 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&) { @@ -128,6 +143,7 @@ struct k892analysis { 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 @@ -149,11 +165,15 @@ struct k892analysis { } // 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}); @@ -194,19 +214,21 @@ 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::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}}); + 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) { @@ -231,11 +253,18 @@ struct k892analysis { } // 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}); @@ -248,14 +277,16 @@ 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::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", 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}); + 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}); @@ -312,20 +343,8 @@ 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) - return false; - if (cfgHasITS && !track.hasITS()) - return false; - if (cfgHasTPC && !track.hasTPC()) - return false; if (cfgHasTOF && !track.hasTOF()) return false; if (cfgUseITSRefit && !track.passedITSRefit()) @@ -347,7 +366,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; } @@ -381,7 +400,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; } @@ -413,14 +432,18 @@ struct k892analysis { return false; } - template - void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2, const Multdatamc& multiplicity) { // auto multNTracksPV = collision.multNTracksPV(); - auto multiplicity = collision.cent(); + // 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 @@ -446,8 +469,8 @@ 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()) @@ -476,23 +499,25 @@ struct k892analysis { auto trk2NSigmaKaTPC = trk2.tpcNSigmaKa(); auto trk2NSigmaKaTOF = (isTrk2hasTOF) ? trk2.tofNSigmaKa() : -999.; - auto deltaEta = TMath::Abs(trk1.eta() - trk2.eta()); - auto deltaPhi = TMath::Abs(trk1.phi() - trk2.phi()); - deltaPhi = (deltaPhi > TMath::Pi()) ? (2 * TMath::Pi() - deltaPhi) : deltaPhi; + 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"), 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); + 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); @@ -528,16 +553,18 @@ struct k892analysis { if constexpr (!IsMix) { //// QA plots after the selection // --- PID QA Pion - 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); + 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); @@ -558,11 +585,11 @@ struct k892analysis { } //// 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 @@ -590,22 +617,41 @@ struct k892analysis { //// 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) { - histos.fill(HIST("k892invmassME_DS"), lResonance.M()); + if (invmass1D) + 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()); + if (invmass1D) + histos.fill(HIST("k892invmassME_DSAnti"), lResonance.M()); histos.fill(HIST("h3k892invmassME_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); } } @@ -613,11 +659,11 @@ struct k892analysis { // 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. @@ -625,13 +671,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"), 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); + 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 @@ -648,10 +696,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()); } } @@ -659,59 +709,136 @@ struct k892analysis { } } - void processDataLight(aod::ResoCollision& collision, - aod::ResoTracks const& resotracks) + void processDataLight(aod::ResoCollision const& resocollisions, aod::ResoCollisionColls const& collisionIndex, soa::Join const& collisions, aod::ResoTracks const& resotracks) { // LOG(info) << "new collision, zvtx: " << collision.posZ(); + if (cisInelGt0) { + auto linkRow = collisionIndex.iteratorAt(resocollisions.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisions.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + } if (additionalQAeventPlots) histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); - fillHistograms(collision, resotracks, resotracks); + auto multiplicity = resocollisions.cent(); + fillHistograms(resocollisions, resotracks, resotracks, multiplicity); } - PROCESS_SWITCH(k892analysis, processDataLight, "Process Event for data", false); + PROCESS_SWITCH(K892analysis, processDataLight, "Process Event for data", false); - void processMCLight(ResoMCCols::iterator const& collision, - soa::Join const& resotracks) + void processMCLight(ResoMCCols::iterator const& resoCollision, + aod::ResoCollisionColls const& collisionIndex, + soa::Join const& collisionsMC, + soa::Join const& resoTracks, + soa::Join const&) { - if (!collision.isInAfterAllCuts() || (abs(collision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + float multiplicity; + if (cMCCent && cisInelGt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + + auto mcColl = coll.mcCollision_as>(); + multiplicity = mcColl.centFT0M(); + } else if (!cMCCent && cisInelGt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + + multiplicity = resoCollision.cent(); + } else if (cMCCent && !cisInelGt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + auto mcColl = coll.mcCollision_as>(); + multiplicity = mcColl.centFT0M(); + } else { + multiplicity = resoCollision.cent(); + } + if (!resoCollision.isInAfterAllCuts() || (std::abs(resoCollision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut return; - fillHistograms(collision, resotracks, resotracks); + fillHistograms(resoCollision, resoTracks, resoTracks, multiplicity); } - PROCESS_SWITCH(k892analysis, processMCLight, "Process Event for MC (Reconstructed)", false); + PROCESS_SWITCH(K892analysis, processMCLight, "Process Event for MC (Reconstructed)", false); - void processMCTrue(ResoMCCols::iterator const& collision, aod::ResoMCParents& resoParents) + void processMCTrue(ResoMCCols::iterator const& resoCollision, aod::ResoCollisionColls const& collisionIndex, aod::ResoMCParents const& resoParents, aod::ResoCollisionCandidatesMC const& collisionsMC, soa::Join const&) { - auto multiplicity = collision.cent(); - for (auto& part : resoParents) { // loop over all pre-filtered MC particles - if (abs(part.pdgCode()) != 313 || abs(part.y()) >= 0.5) + float multiplicity; + if (cMCCent && cisInelGt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + + auto mcColl = coll.mcCollision_as>(); + multiplicity = mcColl.centFT0M(); + } else if (!cMCCent && cisInelGt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + + multiplicity = resoCollision.cent(); + } else if (cMCCent && !cisInelGt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + auto mcColl = coll.mcCollision_as>(); + multiplicity = mcColl.centFT0M(); + } else { + multiplicity = resoCollision.cent(); + } + 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; - bool pass1 = abs(part.daughterPDG1()) == 211 || abs(part.daughterPDG2()) == 211; - bool pass2 = abs(part.daughterPDG1()) == 321 || abs(part.daughterPDG2()) == 321; + 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 (resoCollision.isVtxIn10()) // INEL10 { if (part.pdgCode() > 0) histos.fill(HIST("k892Gen"), 0, part.pt(), multiplicity); else histos.fill(HIST("k892GenAnti"), 0, part.pt(), multiplicity); } - if (collision.isVtxIn10() && collision.isInSel8()) // INEL>10, vtx10 + if (resoCollision.isVtxIn10() && resoCollision.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 (collision.isVtxIn10() && collision.isTriggerTVX()) // vtx10, TriggerTVX + if (resoCollision.isVtxIn10() && resoCollision.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 (resoCollision.isInAfterAllCuts()) // after all event selection { if (part.pdgCode() > 0) histos.fill(HIST("k892Gen"), 3, part.pt(), multiplicity); @@ -720,26 +847,27 @@ struct k892analysis { } } } - 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) { + auto multiplicity = collision1.cent(); if (additionalQAeventPlots) histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); - fillHistograms(collision1, tracks1, tracks2); + fillHistograms(collision1, tracks1, tracks2, multiplicity); } }; - 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..f0d2db3a2f7 --- /dev/null +++ b/PWGLF/Tasks/Resonances/k892analysispbpb.cxx @@ -0,0 +1,1256 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#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; +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); + + Preslice trackPerCollision = aod::track::collisionId; + + 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&, 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.sliceBy(trackPerCollision, RecCollision.globalIndex()); + + // + 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.sliceBy(trackPerCollision, RecCollision.globalIndex()); + + // + 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 0f161bfc694..275d8d07fd0 100644 --- a/PWGLF/Tasks/Resonances/k892pmanalysis.cxx +++ b/PWGLF/Tasks/Resonances/k892pmanalysis.cxx @@ -15,17 +15,18 @@ /// /// \author Bong-Hwi Lim , Alessandro Sturniolo -#include +#include "PWGLF/DataModel/LFResonanceTables.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisTask.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "DataFormatsParameters/GRPObject.h" -#include "CommonConstants/PhysicsConstants.h" + +#include using namespace o2; using namespace o2::framework; @@ -352,9 +353,9 @@ struct k892pmanalysis { } // apply the competing V0 rejection cut (excluding Lambda0 candidates, massLambdaPDG = 1115.683 MeV/c2) - if (abs(v0.mLambda() - massLambda0) < cV0MassWindow) + if (std::abs(v0.mLambda() - massLambda0) < cV0MassWindow) continue; - if (abs(v0.mAntiLambda() - massAntiLambda0) < cV0MassWindow) + if (std::abs(v0.mAntiLambda() - massAntiLambda0) < cV0MassWindow) continue; if (!IsMix && !IsV0QAFilled) { @@ -382,7 +383,7 @@ struct k892pmanalysis { } // Checking whether the mid-rapidity condition is met - if (abs(lResonance.Rapidity()) > 0.5) { + if (std::abs(lResonance.Rapidity()) > 0.5) { continue; } @@ -401,7 +402,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; @@ -443,18 +444,18 @@ 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) + for (auto& part : resoParents) { // loop over all pre-filtered MC particles + 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(); }*/ @@ -466,11 +467,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 b78d774d8b2..9a6d95406b0 100644 --- a/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx +++ b/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx @@ -12,75 +12,87 @@ // (1) For Run3 // (2) Event and track selection need to be optimized // (3) particle = 0 --> phi -// (4) particle = 1 --> kstar +// (4) particle = 1 --> Phi // (5) particle = 2 --> lambdastar // (6) 4 process function (a) Data same event (b) Data mixed event (c) MC generated (d) MC reconstructed /// \brief kaon kaon analysis for higher mass resonances (code taken from phianalysisrun3) /// \author Sawan (sawan.sawan@cern.ch) -#include +#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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include #include +#include +#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 "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 +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; +using namespace o2::aod::rctsel; + struct kaonkaonAnalysisRun3 { + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + RCTFlagsChecker rctChecker; + SliceCache cache; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry hInvMass{"hInvMass", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // For histograms + Configurable calcLikeSign{"calcLikeSign", true, "Calculate Like Sign"}; + Configurable calcRotational{"calcRotational", false, "Calculate Rotational"}; // events Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; - 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 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 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; - TF1* fMultPVCutHigh = nullptr; - TF1* fMultCutLow = nullptr; - TF1* fMultCutHigh = nullptr; - TF1* fMultMultPVCut = nullptr; - // track + Configurable rotationalCut{"rotationalCut", 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"}; @@ -92,23 +104,16 @@ struct kaonkaonAnalysisRun3 { Configurable iscustomDCAcut{"iscustomDCAcut", false, "iscustomDCAcut"}; Configurable isNoTOF{"isNoTOF", false, "isNoTOF"}; Configurable ismanualDCAcut{"ismanualDCAcut", true, "ismanualDCAcut"}; - Configurable isITSOnlycut{"isITSOnlycut", true, "isITSOnlycut"}; + Configurable isITSOnlycut{"isITSOnlycut", false, "isITSOnlycut"}; Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; 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.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)"}; + + Configurable cRotations{"cRotations", 3, "Number of random rotations in the rotational background"}; + 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"}; // different frames Configurable activateTHnSparseCosThStarHelicity{"activateTHnSparseCosThStarHelicity", true, "Activate the THnSparse with cosThStar w.r.t. helicity axis"}; @@ -116,16 +121,21 @@ struct kaonkaonAnalysisRun3 { 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"}; + ConfigurableAxis invMassKKAxis{"invMassKKAxis", {200, 1.0f, 3.0f}, "KK pair invariant mass axis"}; + ConfigurableAxis ptAxisKK{"ptAxisKK", {200, 0.0f, 20.0f}, "KK pair pT axis"}; + ConfigurableAxis multAxis{"multAxis", {110, 0.0f, 110.0f}, "THnSparse multiplicity 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, "Multiplicity"}; - AxisSpec axisPt{cpTbins, cpTlow, cpThigh, "pT (GeV/c)"}; - AxisSpec axisMass{cMassbins, cMasslow, cMasshigh, "Invariant mass (GeV/c^2)"}; + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + AxisSpec axisMult{multAxis, "Multiplicity"}; + AxisSpec axisPt{ptAxisKK, "pT (GeV/c)"}; + AxisSpec axisMass{invMassKKAxis, "Invariant mass (GeV/c^2)"}; const AxisSpec thnAxisPOL{configThnAxisPOL, "Frame axis"}; // THnSparses @@ -154,20 +164,24 @@ struct kaonkaonAnalysisRun3 { 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, {{2000, 0, 20000}}); - histos.add("multdist_FT0A", "FT0A Multiplicity distribution", kTH1F, {{2000, 0, 20000}}); - histos.add("multdist_FT0C", "FT0C Multiplicity distribution", kTH1F, {{2000, 0, 20000}}); + 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}); } - 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}}); 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}}); @@ -179,49 +193,32 @@ struct kaonkaonAnalysisRun3 { 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}}); - histos.add("dE_by_dx_TPC", "dE/dx signal in the TPC as a function of pT", kTH2F, {axisPtfordEbydx, axisdEdx}); } 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); + hInvMass.add("h3PhiInvMassUnlikeSign", "KK Unlike Sign", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); + hInvMass.add("h3PhiInvMassLikeSignPP", "KK Like Sign +", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); + hInvMass.add("h3PhiInvMassLikeSignMM", "KK Like Sign -", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); + hInvMass.add("h3PhiInvMassMixed", "KK Mixed", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); + hInvMass.add("h3PhiInvMassRotated", "KK Rotation", kTHnSparseF, {axisMult, axisPt, axisMass, thnAxisPOL}, true); } else if (isMC) { + hInvMass.add("h1PhiGen", "Phi meson Gen", kTH1F, {axisMult, axisPt}); + hInvMass.add("h3PhiRec", "Phi meson Rec", kTHnSparseF, {axisMult, axisPt, axisMass}); histos.add("hMC", "MC Event statistics", kTH1F, {{6, 0.0f, 6.0f}}); - histos.add("h1PhiGen", "Phi meson Gen", kTH1F, {axisPt}); histos.add("h1PhiRecsplit", "Phi meson Rec split", kTH1F, {axisPt}); - histos.add("h3PhiRec", "Phi meson Rec", kTHnSparseF, {axisPt, axisPt, {200, -0.1, 0.1}}, true); - } - 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); + histos.add("Recmutiplicity", "Reconstructed multiplicity distribution", kTH1F, {axisMult}); + histos.add("Genmutiplicity", "Generated multiplicity distribution", kTH1F, {axisMult}); } } double massKa = o2::constants::physics::MassKPlus; - double rapidity; - double genMass, recMass, resolution; - double mass{0.}; - double massrotation1{0.}; - double massrotation2{0.}; - double pT{0.}; - array pvec0; - array pvec1; - array pvec1rotation; - array pvec2rotation; - ROOT::Math::PxPyPzMVector daughter1, daughter2; + double rapidity{0.0}, mass{0.}, massrotation1{0.}, massrotation2{0.}, pT{0.}; + float theta2; + ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterRot, mother, motherRot, daughterSelected, fourVecDauCM, daughterRotCM; + ROOT::Math::XYZVector randomVec, beamVec, normalVec; + bool isMix = false; template - bool eventselection(Collision const& collision, const float& multiplicity) + bool eventselection(Collision const& collision) { if (!collision.sel8()) { return false; @@ -229,32 +226,15 @@ struct kaonkaonAnalysisRun3 { 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; + // 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; // } - 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; } @@ -303,72 +283,141 @@ struct kaonkaonAnalysisRun3 { } return true; } - 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) + + template + void fillInvMass(const T1& daughter1, const T1& daughter2, const T1& mother, float multiplicity, bool isMix, const T2& track1, const T2& track2) { - TRandom* rn = new TRandom(); - int track1Sign = candidate1.sign(); - int track2Sign = candidate2.sign(); - 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(); + ROOT::Math::Boost boost{mother.BoostToCM()}; + fourVecDauCM = boost(daughter1); - 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()); - histos.fill(HIST("dE_by_dx_TPC"), candidate1.pt(), candidate1.tpcSignal()); - histos.fill(HIST("dE_by_dx_TPC"), candidate2.pt(), candidate2.tpcSignal()); - } + if (std::abs(mother.Rapidity()) < 0.5) { + if (activateTHnSparseCosThStarHelicity) { + auto cosThetaStarHelicity = mother.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(mother.Vect().Mag2())); - // 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 (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, vec3.Pt(), vec3.M(), framecalculation); - } - if (mix) { - histos.fill(HIST("h3PhiInvMassMixed"), multiplicity, vec3.Pt(), vec3.M(), framecalculation); - } + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + hInvMass.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.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); + + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + + motherRot = daughterRot + daughter2; + + ROOT::Math::Boost boost2{motherRot.BoostToCM()}; + daughterRotCM = boost2(daughterRot); - if (rotation) { - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - 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); + auto cosThetaStarHelicityRot = motherRot.Vect().Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(motherRot.Vect().Mag2())); + + if (calcRotational) + hInvMass.fill(HIST("h3PhiInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarHelicityRot); + } + } else { + hInvMass.fill(HIST("h3PhiInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + } + } else { + if (!isMix) { + if (calcLikeSign) { + if (track1.sign() * track2.sign() > 0) { + hInvMass.fill(HIST("h3PhiInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + } else { + hInvMass.fill(HIST("h3PhiInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + } + } + } + } + + } else if (activateTHnSparseCosThStarProduction) { + normalVec = ROOT::Math::XYZVector(mother.Py(), -mother.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(normalVec.Mag2())); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + hInvMass.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.M(), cosThetaStarProduction); + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + + motherRot = daughterRot + daughter2; + if (calcRotational) + hInvMass.fill(HIST("h3PhiInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarProduction); + } + } else { + hInvMass.fill(HIST("h3PhiInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarProduction); + } + } else { + if (!isMix) { + if (calcLikeSign) { + if (track1.sign() * track2.sign() > 0) { + hInvMass.fill(HIST("h3PhiInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarProduction); + } else { + hInvMass.fill(HIST("h3PhiInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.M(), cosThetaStarProduction); + } + } + } + } + } else if (activateTHnSparseCosThStarBeam) { + beamVec = ROOT::Math::XYZVector(0.f, 0.f, 1.f); + auto cosThetaStarBeam = beamVec.Dot(fourVecDauCM.Vect()) / std::sqrt(fourVecDauCM.Vect().Mag2()); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + hInvMass.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam); + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + + motherRot = daughterRot + daughter2; + if (calcRotational) + hInvMass.fill(HIST("h3PhiInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarBeam); + } + } else { + hInvMass.fill(HIST("h3PhiInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam); + } + } else { + if (calcLikeSign) { + if (track1.sign() * track2.sign() > 0) { + hInvMass.fill(HIST("h3PhiInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam); + } else { + hInvMass.fill(HIST("h3PhiInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.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(fourVecDauCM.Vect()) / std::sqrt(fourVecDauCM.Vect().Mag2()); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + hInvMass.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom); + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + + motherRot = daughterRot + daughter2; + if (calcRotational) + hInvMass.fill(HIST("h3PhiInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarRandom); + } + } else { + hInvMass.fill(HIST("h3PhiInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom); + } + } else { + if (!isMix) { + if (calcLikeSign) { + if (track1.sign() * track2.sign() > 0) { + hInvMass.fill(HIST("h3PhiInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom); + } else { + hInvMass.fill(HIST("h3PhiInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom); + } + } + } } } } - if (std::abs(rapidity) < 0.5 && track1Sign * track2Sign > 0 && likesign) { - if (track1Sign > 0 && track2Sign > 0) { - histos.fill(HIST("h3PhiInvMassLikeSignPP"), multiplicity, vec3.Pt(), vec3.M(), framecalculation); - } else { - histos.fill(HIST("h3PhiInvMassLikeSignMM"), multiplicity, vec3.Pt(), vec3.M(), framecalculation); - } - } - // } } Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; @@ -379,12 +428,15 @@ struct kaonkaonAnalysisRun3 { using TrackCandidates = soa::Filtered>; // using EventCandidatesMC = soa::Join; - using EventCandidatesMC = soa::Join; + using EventCandidatesMC = soa::Join; using TrackCandidatesMC = soa::Filtered>; void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) { - if (!eventselection(collision, collision.centFT0M())) { + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + return; + } + if (!eventselection(collision)) { return; } float multiplicity; @@ -404,12 +456,14 @@ struct kaonkaonAnalysisRun3 { 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_before"), track1.pt(), track1.tpcNSigmaKa()); - histos.fill(HIST("hNsigmaKaonTOF_before"), track1.pt(), track1.tofNSigmaKa()); - histos.fill(HIST("hNsigmaKaonTOF_TPC_before"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + 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)) { @@ -423,74 +477,16 @@ struct kaonkaonAnalysisRun3 { 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 - - 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(), 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 (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) { - 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 (!selectionPID(track1)) // Track 1 is checked with Kaon + continue; + if (!selectionPID(track2)) // Track 2 is checked with Pion + continue; - // 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()); - // } + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + mother = daughter1 + daughter2; // Kstar meson + isMix = false; + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, track1, track2); } } } @@ -506,204 +502,53 @@ struct kaonkaonAnalysisRun3 { { auto tracksTuple = std::make_tuple(tracks); //////// currently mixing the event with similar TPC multiplicity //////// - BinningTypeVertexContributor1 binningOnPositions1{{axisVertex, axisMultiplicity}, true}; - BinningTypeVertexContributor2 binningOnPositions2{{axisVertex, axisMultiplicity}, true}; + BinningTypeVertexContributor1 binningOnPositions1{{axisVertex, axisMultiplicity}, true}; // for pp + BinningTypeVertexContributor2 binningOnPositions2{{axisVertex, axisMultiplicity}, true}; // for PbPb 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 (!eventselection(c2, multiplicity)) { - continue; - } + for (auto& [c1, tracks1, c2, tracks2] : pair1) { + float multiplicity = c1.centFT0M(); - 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 - - 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(), 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 (rctCut.requireRCTFlagChecker && !rctChecker(c1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctChecker(c2)) { + continue; + } - 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) { - 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 (!eventselection(c1)) { + continue; + } + if (!eventselection(c2)) { + continue; + } - 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); - } - } + for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - // 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); - // } + if (!selectionTrack(t1)) { + continue; } - } - } else { - for (auto& [c1, tracks1, c2, tracks2] : pair2) { - float multiplicity = c1.centFT0C(); - - if (!eventselection(c1, multiplicity)) { + if (!selectionTrack(t2)) { continue; } - if (!eventselection(c2, multiplicity)) { + if (!selectionPair(t1, t2)) { continue; } - 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 - - 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(), 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 (!selectionPID(t1)) + continue; + if (!selectionPID(t2)) + continue; - 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()); + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massKa); + mother = daughter1 + daughter2; // Kstar meson - 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) { - 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()); + isMix = true; - 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); - // } + if (std::abs(mother.Rapidity()) < 0.5) { + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, t1, t2); } } } @@ -716,6 +561,7 @@ struct kaonkaonAnalysisRun3 { if (std::abs(mcCollision.posZ()) < cfgCutVertex) { histos.fill(HIST("hMC"), 1.5); } + auto multiplicity = -1; int Nchinel = 0; for (auto& mcParticle : mcParticles) { auto pdgcode = std::abs(mcParticle.pdgCode()); @@ -734,6 +580,7 @@ struct kaonkaonAnalysisRun3 { continue; } SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + multiplicity = collision.centFT0M(); } SelectedEvents.resize(nevts); const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); @@ -741,6 +588,7 @@ struct kaonkaonAnalysisRun3 { if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection return; } + histos.fill(HIST("Genmutiplicity"), multiplicity); histos.fill(HIST("hMC"), 4.5); for (auto& mcParticle : mcParticles) { if (std::abs(mcParticle.y()) > 0.5) { @@ -766,7 +614,7 @@ struct kaonkaonAnalysisRun3 { } } if (daughtp && daughtm) { - histos.fill(HIST("h1PhiGen"), mcParticle.pt()); + hInvMass.fill(HIST("h1PhiGen"), multiplicity, mcParticle.pt()); } } } @@ -780,6 +628,8 @@ struct kaonkaonAnalysisRun3 { if (std::abs(collision.mcCollision().posZ()) > cfgCutVertex || !collision.sel8()) { return; } + auto multiplicity = collision.centFT0M(); + histos.fill(HIST("Recmutiplicity"), multiplicity); histos.fill(HIST("hMC"), 5.5); auto oldindex = -999; for (auto track1 : tracks) { @@ -837,23 +687,27 @@ struct kaonkaonAnalysisRun3 { if (std::abs(mothertrack1.pdgCode()) != 333) { continue; } - if (!isITSOnlycut && !(selectionPID(track1) && selectionPID(track2))) { + if (!(selectionPID(track1))) { + continue; + } + if (!(selectionPID(track2))) { 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}; - auto motherP = mothertrack1.p(); - auto motherE = mothertrack1.e(); - genMass = std::sqrt(motherE * motherE - motherP * motherP); - recMass = RecoDecay::m(arrMomrec, array{massKa, massKa}); - auto recpt = TMath::Sqrt((track1.px() + track2.px()) * (track1.px() + track2.px()) + (track1.py() + track2.py()) * (track1.py() + track2.py())); - histos.fill(HIST("h3PhiRec"), mothertrack1.pt(), recpt, recMass - genMass); + + if (track1.sign() * track2.sign() < 0) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } + mother = daughter1 + daughter2; + + if (TMath::Abs(mother.Rapidity()) >= 0.5) { + continue; + } + hInvMass.fill(HIST("h3PhiRec"), multiplicity, mother.Pt(), mother.M()); } } } diff --git a/PWGLF/Tasks/Resonances/kshortlambda.cxx b/PWGLF/Tasks/Resonances/kshortlambda.cxx new file mode 100644 index 00000000000..39e682098ba --- /dev/null +++ b/PWGLF/Tasks/Resonances/kshortlambda.cxx @@ -0,0 +1,946 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessTables.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/PIDResponseTOF.h" // +#include "Common/DataModel/PIDResponseTPC.h" // +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" // +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" // +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +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/kstar892LightIon.cxx b/PWGLF/Tasks/Resonances/kstar892LightIon.cxx new file mode 100644 index 00000000000..958697541a3 --- /dev/null +++ b/PWGLF/Tasks/Resonances/kstar892LightIon.cxx @@ -0,0 +1,1475 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file kstar892LightIon.cxx +/// \brief Code for K*0(892) resonance without resonance initializer in Light Ion collisions +/// \author Subhadeep Mandal +/// \since 22/11/2025 + +#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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TRandom3.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using std::array; +using namespace o2::aod::rctsel; + +struct Kstar892LightIon { + SliceCache cache; + + // Histograms are defined with HistogramRegistry + HistogramRegistry hEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hInvMass{"InvMass", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hMC{"MC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hPID{"PID", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry hOthers{"Others", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", false, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + RCTFlagsChecker rctChecker; + + struct : ConfigurableGroup { + // Configurables for event selections + Configurable cfgVrtxZCut{"cfgVrtxZCut", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable isTriggerTVX{"isTriggerTVX", true, "TriggerTVX"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", true, "IsGoodZvtxFT0vsPV"}; + Configurable isApplyOccCut{"isApplyOccCut", false, "Apply occupancy cut"}; + Configurable cfgOccCut{"cfgOccCut", 1000., "Occupancy cut"}; + Configurable isNoSameBunchPileup{"isNoSameBunchPileup", true, "kNoSameBunchPileup"}; + Configurable isGoodITSLayersAll{"isGoodITSLayersAll", false, "Require all ITS layers to be good"}; + Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", true, "kNoTimeFrameBorder"}; + Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", true, "kNoITSROFrameBorder"}; + Configurable isApplyDeepAngle{"isApplyDeepAngle", false, "Deep Angle cut"}; + Configurable isNoCollInTimeRangeStandard{"isNoCollInTimeRangeStandard", false, "No collision in time range standard"}; + Configurable isVertexITSTPC{"isVertexITSTPC", false, "Vertex ITS TPC"}; + Configurable isVertexTOFMatched{"isVertexTOFMatched", false, "Vertex TOF Matched"}; + + // Configurables for track selections + Configurable isPVContributor{"isPVContributor", true, "PV contributor track selection"}; // PV Contriuibutor + Configurable isPrimaryTrack{"isPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable isGlobalTracks{"isGlobalTracks", true, "isGlobalTracks"}; + + Configurable cfgCutPT{"cfgCutPT", 0.1f, "PT cut on daughter track"}; + Configurable cfgCutEtaMax{"cfgCutEtaMax", 0.8f, "Eta cut on daughter track"}; + Configurable cfgCutDCAxyMax{"cfgCutDCAxyMax", 0.1f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 0.1f, "DCAz range for tracks"}; + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 15, "Number of mixed events per event"}; + 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 cfgTPCChi2NClMax{"cfgTPCChi2NClMax", 4.0, "TPC Chi2/NCl"}; + Configurable cfgTPCChi2NClMin{"cfgTPCChi2NClMin", 0.0, "TPC Chi2/NCl"}; + Configurable isUseITSTPCRefit{"isUseITSTPCRefit", false, "Require ITS Refit"}; + Configurable isApplyPtDepDCAxyCut{"isApplyPtDepDCAxyCut", false, "Apply pT dependent DCAxy cut"}; + Configurable isGoldenChi2{"isGoldenChi2", false, "Apply golden chi2 cut"}; + Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; + // Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", false, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfgBetaCutTOF{"cfgBetaCutTOF", 0.0, "cut TOF beta"}; + + Configurable isAvoidsplitrackMC{"isAvoidsplitrackMC", true, "avoid split track in MC"}; + + // cuts on mother + // Configurable isApplyCutsOnMother{"isApplyCutsOnMother", false, "Enable additional cuts on Kstar mother"}; + // Configurable cMaxPtMotherCut{"cMaxPtMotherCut", 15.0, "Maximum pt of mother cut"}; + // Configurable cMaxMinvMotherCut{"cMaxMinvMotherCut", 1.5, "Maximum mass of mother cut"}; + Configurable motherRapidityCut{"motherRapidityCut", 0.5, "Maximum rapidity of mother"}; + // PID selections + + Configurable onlyTOF{"onlyTOF", false, "only TOF tracks"}; + Configurable onlyTOFHIT{"onlyTOFHIT", false, "accept only TOF hit tracks at high pt"}; + Configurable onlyTPC{"onlyTPC", false, "only TPC tracks"}; + Configurable isApplypTdepPID{"isApplypTdepPID", false, "Apply pT dependent PID"}; + + 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 nsigmaCutCombinedKa{"nsigmaCutCombinedKa", 3.0, "Combined Nsigma cut for kaon"}; + Configurable nsigmaCutCombinedPi{"nsigmaCutCombinedPi", 3.0, "Combined Nsigma cut for pion"}; + + // Fixed variables + float lowPtCutPID = 0.5; + } selectionConfig; + + Configurable calcLikeSign{"calcLikeSign", true, "Calculate Like Sign"}; + Configurable calcRotational{"calcRotational", true, "Calculate Rotational"}; + Configurable cRotations{"cRotations", 3, "Number of random rotations in the rotational background"}; + Configurable rotationalCut{"rotationalCut", 10, "Cut value (Rotation angle pi - pi/cut and pi + pi/cut)"}; + + // Confugrable for QA histograms + Configurable cQAplots{"cQAplots", true, "cQAplots"}; + Configurable cQAevents{"cQAevents", true, "centrality dist, DCAxy, DCAz"}; + + Configurable selectCentEstimator{"selectCentEstimator", 0, "Select centrality estimator: 0 - FT0M, 1 - FT0A, 2 - FT0C, 3 - FV0A"}; + + // Configurable for histograms + ConfigurableAxis binsCentPlot{"binsCentPlot", {110, 0.0, 110}, "Centrality axis"}; + ConfigurableAxis axisdEdx{"axisdEdx", {1, 0.0f, 200.0f}, "dE/dx (a.u.)"}; + ConfigurableAxis axisPtfordEbydx{"axisPtfordEbydx", {1, 0, 20}, "pT (GeV/c)"}; + ConfigurableAxis invMassKstarAxis{"invMassKstarAxis", {300, 0.7f, 1.3f}, "Kstar invariant mass axis"}; + ConfigurableAxis ptAxisKstar{"ptAxisKstar", {200, 0.0f, 20.0f}, "Kstar pT axis"}; + ConfigurableAxis binsImpactPar{"binsImpactPar", {100, 0, 25}, "Binning of the impact parameter axis"}; + ConfigurableAxis axisNch{"axisNch", {100, 0.0f, 100.0f}, "Number of charged particles in |y| < 0.5"}; + + Configurable indexCheck{"indexCheck", true, "Check if track2id < track1id matters"}; // check and remove + + enum MultEstimator { + kFT0M, + kFT0A, + kFT0C, + kFV0A, + kFV0C, + kFV0M, + kNEstimators // useful if you want to iterate or size things + }; + + enum PIDParticle { + kPion, + kKaon, + kProton + }; + + int noOfDaughters = 2; + + TRandom* rn = new TRandom(); + + void init(InitContext const&) + { + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + // Axes + AxisSpec vertexZAxis = {60, -15., 15., "V_{Z} (cm) for plots"}; + AxisSpec ptAxis = {ptAxisKstar, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec invmassAxis = {invMassKstarAxis, "Invariant mass (GeV/#it{c}^{2})"}; + AxisSpec centralityAxis = {binsCentPlot, "Centrality Axis"}; + AxisSpec impactParAxis = {binsImpactPar, "Impact Parameter (cm)"}; + + // Histograms + // Event selection + hEventSelection.add("hVertexZ", "hVertexZ", kTH1F, {vertexZAxis}); + hEventSelection.add("hCentrality", "Centrality percentile", kTH1F, {{110, 0, 110}}); + hEventSelection.add("hOccupancy", "Occupancy distribution", kTH1F, {{1000, 0, 15000}}); + + hEventSelection.add("hEventCut", "No. of event after cuts", kTH1D, {{20, 0, 20}}); + std::shared_ptr hCutFlow = hEventSelection.get(HIST("hEventCut")); + + auto check = [](bool enabled) { return enabled ? "" : " #otimes"; }; // check if a cut is enabled and put #otimes beside that label if not enabled + + std::vector eveCutLabels = { + "All Events", + Form("|Vz| < %.1f", selectionConfig.cfgVrtxZCut.value), + "sel8", + std::string("kNoTimeFrameBorder") + check(selectionConfig.isNoTimeFrameBorder.value), + std::string("kNoITSROFrameBorder") + check(selectionConfig.isNoITSROFrameBorder.value), + std::string("kNoSameBunchPileup") + check(selectionConfig.isNoSameBunchPileup.value), + std::string("kIsGoodITSLayersAll") + check(selectionConfig.isGoodITSLayersAll.value), + std::string("kNoCollInTimeRangeStandard") + check(selectionConfig.isNoCollInTimeRangeStandard.value), + Form("Occupancy < %.0f%s", selectionConfig.cfgOccCut.value, check(selectionConfig.isApplyOccCut.value)), + std::string("rctChecker") + check(rctCut.requireRCTFlagChecker.value), + std::string("kIsTriggerTVX") + check(selectionConfig.isTriggerTVX.value), + std::string("kIsGoodZvtxFT0vsPV") + check(selectionConfig.isGoodZvtxFT0vsPV.value), + std::string("isVertexITSTPC") + check(selectionConfig.isVertexITSTPC.value), + std::string("isVertexTOFMatched") + check(selectionConfig.isVertexTOFMatched.value)}; + // assign labels + for (size_t i = 0; i < eveCutLabels.size(); ++i) { + hCutFlow->GetXaxis()->SetBinLabel(i + 1, eveCutLabels[i].c_str()); + } + + // for primary tracksbinsCentPlot + if (cQAplots) { + hOthers.add("dE_by_dx_TPC", "dE/dx signal in the TPC as a function of pT", kTH2F, {axisPtfordEbydx, axisdEdx}); + 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}}); + + hOthers.add("hKstar_rap_pt", "Pair rapidity distribution; y; p_{T}; Counts", kTH2F, {{400, -2.0f, 2.0f}, ptAxis}); + hOthers.add("hKstar_eta_pt", "Pair eta distribution; #eta; p_{T}; Counts", kTH2F, {{400, -2.0f, 2.0f}, ptAxis}); + + hOthers.add("hDcaxyPi", "Dcaxy distribution of selected Pions", kTH1F, {{200, -1.0f, 1.0f}}); + hOthers.add("hDcaxyKa", "Dcaxy distribution of selected Kaons", kTH1F, {{200, -1.0f, 1.0f}}); + hOthers.add("hDcazPi", "Dcaz distribution of selected Pions", kTH1F, {{200, -1.0f, 1.0f}}); + hOthers.add("hDcazKa", "Dcaz distribution of selected Kaons", kTH1F, {{200, -1.0f, 1.0f}}); + + hOthers.add("hDcaxy_cent_pt", "Dcaxy distribution before PID", kTH3F, {{200, -1.0f, 1.0f}, centralityAxis, ptAxis}); + hOthers.add("hDcaz_cent_pt", "Dcaz distribution before PID", kTH3F, {{200, -1.0f, 1.0f}, centralityAxis, ptAxis}); + + hPID.add("Before/hNsigma_TPC_TOF_Ka_pt", "N #sigma Kaon TPC TOF before", kTH3F, {{50, -5.0f, 5.0f}, {50, -5.0f, 5.0f}, ptAxis}); + hPID.add("Before/hNsigma_TPC_TOF_Pi_pt", "N #sigma Pion TPC TOF before", kTH3F, {{50, -5.0f, 5.0f}, {50, -5.0f, 5.0f}, ptAxis}); + + hPID.add("Before/hTPCnsigKa_Neg_mult_pt", "TPC nsigma of K^{-} before PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("Before/hTPCnsigPi_Neg_mult_pt", "TPC nsigma of #pi^{-} before PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("Before/hTOFnsigKa_Neg_mult_pt", "TOF nsigma of K^{-} before PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("Before/hTOFnsigPi_Neg_mult_pt", "TOF nsigma of #pi^{-} before PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + + hPID.add("Before/hTPCnsigKa_Pos_mult_pt", "TPC nsigma of K^{+} before PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("Before/hTPCnsigPi_Pos_mult_pt", "TPC nsigma of #pi^{+} before PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("Before/hTOFnsigKa_Pos_mult_pt", "TOF nsigma of K^{+} before PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("Before/hTOFnsigPi_Pos_mult_pt", "TOF nsigma of #pi^{+} before PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + + hPID.add("After/hNsigma_TPC_TOF_Ka_pt", "N #sigma Kaon TPC TOF after", kTH3F, {{50, -5.0f, 5.0f}, {50, -5.0f, 5.0f}, ptAxis}); + hPID.add("After/hNsigma_TPC_TOF_Pi_pt", "N #sigma Pion TPC TOF after", kTH3F, {{50, -5.0f, 5.0f}, {50, -5.0f, 5.0f}, ptAxis}); + + hPID.add("After/hTPCnsigKa_Neg_mult_pt", "TPC nsigma of K^{-} after PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("After/hTPCnsigPi_Neg_mult_pt", "TPC nsigma of #pi^{-} after PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("After/hTOFnsigKa_Neg_mult_pt", "TOF nsigma of K^{-} after PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("After/hTOFnsigPi_Neg_mult_pt", "TOF nsigma of #pi^{-} after PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + + hPID.add("After/hTPCnsigKa_Pos_mult_pt", "TPC nsigma of K^{+} after PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("After/hTPCnsigPi_Pos_mult_pt", "TPC nsigma of #pi^{+} after PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("After/hTOFnsigKa_Pos_mult_pt", "TOF nsigma of K^{+} after PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + hPID.add("After/hTOFnsigPi_Pos_mult_pt", "TOF nsigma of #pi^{+} after PID with pt and centrality", kTH3F, {{100, -10.0f, 10.0f}, centralityAxis, ptAxis}); + } + + // KStar histograms + hInvMass.add("h3KstarInvMassUnlikeSign", "kstar Unlike Sign", kTH3F, {centralityAxis, ptAxis, invmassAxis}); + hInvMass.add("h3KstarInvMassMixed", "kstar Mixed", kTH3F, {centralityAxis, ptAxis, invmassAxis}); + if (calcLikeSign) { + hInvMass.add("h3KstarInvMasslikeSignPP", "kstar like Sign", kTH3F, {centralityAxis, ptAxis, invmassAxis}); + hInvMass.add("h3KstarInvMasslikeSignMM", "kstar like Sign", kTH3F, {centralityAxis, ptAxis, invmassAxis}); + } + if (calcRotational) + hInvMass.add("h3KstarInvMassRotated", "kstar rotated", kTH3F, {centralityAxis, ptAxis, invmassAxis}); + + // MC histograms + if (doprocessGen) { + hMC.add("Gen/hk892GenpT", "pT distribution of True MC K(892)0", kTH2F, {ptAxis, centralityAxis}); + hMC.add("Gen/hk892GenpT2", "pT distribution of True MC K(892)0", kTH2F, {ptAxis, centralityAxis}); + hMC.add("Gen/h1genmass", "Invariant mass of generated kstar meson", kTH1F, {invmassAxis}); + hMC.add("Gen/h1GenCent", "centrality generated", kTH1F, {centralityAxis}); + hMC.add("Gen/hAllGenCollisions", "All generated events", kTH1F, {centralityAxis}); + hMC.add("Gen/hAllGenCollisions1Rec", "All gen events with at least one rec event", kTH1F, {centralityAxis}); + hMC.add("Gen/hAllKstarGenCollisisons", "All generated Kstar in events with rapidity in 0.5", kTH2F, {ptAxis, centralityAxis}); + hMC.add("Gen/hAllKstarGenCollisisons1Rec", "All generated Kstar in events with at least one rec event in rapidity in 0.5", kTH2F, {ptAxis, centralityAxis}); + } + + if (doprocessRec) { + hMC.add("Rec/hAllRecCollisions", "All reconstructed events", kTH1F, {centralityAxis}); + hMC.add("Rec/h1KstarRecMass", "Invariant mass of kstar meson", kTH1F, {invmassAxis}); + hMC.add("Rec/h2KstarRecpt1", "pT of kstar meson", kTH3F, {ptAxis, centralityAxis, invmassAxis}); + hMC.add("Rec/h2KstarRecpt2", "pT of kstar meson", kTH3F, {ptAxis, centralityAxis, invmassAxis}); + hMC.add("Rec/h1RecCent", "centrality reconstructed", kTH1F, {centralityAxis}); + hMC.add("Rec/h1KSRecsplit", "KS meson Rec split", kTH1F, {{100, 0.0f, 10.0f}}); + } + + // Signal Loss & Event Loss + if (doprocessEvtLossSigLossMC) { + hMC.add("ImpactCorr/hImpactParameterGen", "Impact parameter of generated MC events", kTH1F, {impactParAxis}); + hMC.add("ImpactCorr/hImpactParameterRec", "Impact parameter of selected MC events", kTH1F, {impactParAxis}); + hMC.add("ImpactCorr/hImpactParvsCentrRec", "Impact parameter of selected MC events vs centrality", kTH2F, {{centralityAxis}, impactParAxis}); + hMC.add("ImpactCorr/hKstarGenBeforeEvtSel", "K*0 before event selections", kTH2F, {ptAxis, impactParAxis}); + hMC.add("ImpactCorr/hKstarGenAfterEvtSel", "K*0 after event selections", kTH2F, {ptAxis, impactParAxis}); + } + + if (doprocessCorrFactors) { + hMC.add("CorrFactors/hCentralityVsMultMC", "Event centrality vs MC centrality", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); + hMC.add("CorrFactors/hEventCentrality", "Event centrality", kTH1F, {{101, 0, 101}}); + hMC.add("CorrFactors/hNrecInGen", "Number of collisions in MC", kTH1F, {{4, -0.5, 3.5}}); + hMC.add("CorrFactors/hGenEvents", "Generated events", kTH2F, {{axisNch}, {4, 0, 4}}); + auto hGenEvents = hMC.get(HIST("CorrFactors/hGenEvents")); + hGenEvents->GetYaxis()->SetBinLabel(1, "All generated events"); + hGenEvents->GetYaxis()->SetBinLabel(2, "Generated events with Mc collision V_{z} cut"); + hGenEvents->GetYaxis()->SetBinLabel(3, "Generated events with at least one reconstructed event"); + hMC.add("CorrFactors/h2dGenKstar", "Centrality vs p_{T}", kTH2D, {{101, 0.0f, 101.0f}, ptAxis}); + hMC.add("CorrFactors/h3dGenKstarVsMultMCVsCentrality", "MC centrality vs centrality vs p_{T}", kTH3D, {axisNch, {101, 0.0f, 101.0f}, ptAxis}); + } + } + + double massPi = o2::constants::physics::MassPiPlus; + double massKa = o2::constants::physics::MassKPlus; + + template + bool selectionEvent(const Coll& collision, bool fillHist = false) // default to false + { + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 0); + + if (std::abs(collision.posZ()) > selectionConfig.cfgVrtxZCut) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 1); + + if (!collision.sel8()) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 2); + + if (selectionConfig.isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 3); + + if (selectionConfig.isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 4); + + if (selectionConfig.isNoSameBunchPileup && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup))) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 5); + + if (selectionConfig.isGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 6); + + if (selectionConfig.isNoCollInTimeRangeStandard && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 7); + + if (selectionConfig.isApplyOccCut && (std::abs(collision.trackOccupancyInTimeRange()) > selectionConfig.cfgOccCut)) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 8); + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 9); + + if (selectionConfig.isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 10); + + if (selectionConfig.isGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 11); + + if (selectionConfig.isVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 12); + + if (selectionConfig.isVertexTOFMatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHist) + hEventSelection.fill(HIST("hEventCut"), 13); + + return true; + } + + template + bool selectionTrack(const T& candidate) + { + if (selectionConfig.isGlobalTracks) { + if (!candidate.isGlobalTrackWoDCA()) + return false; + if (std::abs(candidate.pt()) < selectionConfig.cfgCutPT) + return false; + + if (std::abs(candidate.eta()) > selectionConfig.cfgCutEtaMax) + return false; + if (!selectionConfig.isApplyPtDepDCAxyCut) { + if (std::abs(candidate.dcaXY()) > selectionConfig.cfgCutDCAxyMax) + return false; + } else { + if (std::abs(candidate.dcaXY()) > (0.0105 + 0.035 / std::pow(candidate.pt(), 1.1))) + return false; + } + if (selectionConfig.isGoldenChi2 && !candidate.passedGoldenChi2()) + return false; + if (std::abs(candidate.dcaZ()) > selectionConfig.cfgCutDCAz) + return false; + if (candidate.tpcCrossedRowsOverFindableCls() < selectionConfig.cfgRCRFC) + return false; + if (candidate.itsNCls() < selectionConfig.cfgITScluster) + return false; + if (candidate.tpcNClsFound() < selectionConfig.cfgTPCcluster) + return false; + if (candidate.itsChi2NCl() >= selectionConfig.cfgITSChi2NCl) + return false; + if (candidate.tpcChi2NCl() >= selectionConfig.cfgTPCChi2NClMax || candidate.tpcChi2NCl() < selectionConfig.cfgTPCChi2NClMin) + return false; + if (selectionConfig.isPVContributor && !candidate.isPVContributor()) + return false; + if (selectionConfig.isUseITSTPCRefit && (!(o2::aod::track::ITSrefit) || !(o2::aod::track::TPCrefit))) + return false; + } else if (!selectionConfig.isGlobalTracks) { + if (std::abs(candidate.pt()) < selectionConfig.cfgCutPT) + return false; + // if (std::abs(candidate.eta()) > selectionConfig.cfgCutEtaMax || std::abs(candidate.eta()) < selectionConfig.cfgCutEtaMin) + if (std::abs(candidate.eta()) > selectionConfig.cfgCutEtaMax) + return false; + // if (std::abs(candidate.dcaXY()) > selectionConfig.cfgCutDCAxyMax || std::abs(candidate.dcaXY()) < selectionConfig.cfgCutDCAxyMin) + if (std::abs(candidate.dcaXY()) > selectionConfig.cfgCutDCAxyMax) + return false; + if (std::abs(candidate.dcaZ()) > selectionConfig.cfgCutDCAz) + return false; + if (candidate.tpcCrossedRowsOverFindableCls() < selectionConfig.cfgRCRFC) + return false; + if (candidate.itsNCls() < selectionConfig.cfgITScluster) + return false; + if (candidate.tpcNClsFound() < selectionConfig.cfgTPCcluster) + return false; + if (candidate.itsChi2NCl() >= selectionConfig.cfgITSChi2NCl) + return false; + if (candidate.tpcChi2NCl() >= selectionConfig.cfgTPCChi2NClMax || candidate.tpcChi2NCl() < selectionConfig.cfgTPCChi2NClMin) + return false; + if (selectionConfig.isPVContributor && !candidate.isPVContributor()) + return false; + if (selectionConfig.isPrimaryTrack && !candidate.isPrimaryTrack()) + return false; + } + + return true; + } + + // 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 = std::acos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + if (selectionConfig.isApplyDeepAngle && angle < selectionConfig.cfgDeepAngle) { + return false; + } + return true; + } + + template + bool selectionPID(const T& candidate, int PID) + { + if (PID == PIDParticle::kPion) { + if (selectionConfig.onlyTOF) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < selectionConfig.nsigmaCutTOFPi && candidate.beta() > selectionConfig.cfgBetaCutTOF) { + return true; + } + } else if (selectionConfig.onlyTOFHIT) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < selectionConfig.nsigmaCutTOFPi && candidate.beta() > selectionConfig.cfgBetaCutTOF) { + return true; + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi) { + return true; + } + } else if (selectionConfig.onlyTPC) { + if (std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi) { + return true; + } + } else { + if (candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < (selectionConfig.nsigmaCutCombinedPi * selectionConfig.nsigmaCutCombinedPi) && candidate.beta() > selectionConfig.cfgBetaCutTOF) { + return true; + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi) { + return true; + } + } + } else if (PID == PIDParticle::kKaon) { + if (selectionConfig.onlyTOF) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < selectionConfig.nsigmaCutTOFKa && candidate.beta() > selectionConfig.cfgBetaCutTOF) { + return true; + } + } else if (selectionConfig.onlyTOFHIT) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < selectionConfig.nsigmaCutTOFKa && candidate.beta() > selectionConfig.cfgBetaCutTOF) { + return true; + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa) { + return true; + } + } else if (selectionConfig.onlyTPC) { + if (std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa) { + return true; + } + } else { + if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (selectionConfig.nsigmaCutCombinedKa * selectionConfig.nsigmaCutCombinedKa) && candidate.beta() > selectionConfig.cfgBetaCutTOF) { + return true; + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa) { + return true; + } + } + } + return false; + } + + template + bool selectionPIDNew(const T& candidate, int PID) + { + if (PID == PIDParticle::kPion) { + if (candidate.pt() < selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi && candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < selectionConfig.nsigmaCutTOFPi) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi && !candidate.hasTOF()) { + return true; + } + } else if (PID == PIDParticle::kKaon) { + if (candidate.pt() < selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa && candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < selectionConfig.nsigmaCutTOFKa) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa && !candidate.hasTOF()) { + return true; + } + } + return false; + } + + //*********Varibles declaration*************** + float centrality{-1.0}, theta2; + ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterRot, mother, motherRot; + bool isMix = false; + + template + void fillInvMass(const T1& daughter1, const T1& daughter2, const T1& mother, float centrality, bool isMix, const T2& track1, const T2& track2) + { + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + if (std::abs(mother.Rapidity()) < selectionConfig.motherRapidityCut) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), centrality, mother.Pt(), mother.M()); + } + 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); + + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + motherRot = daughterRot + daughter2; + + if (calcRotational && std::abs(motherRot.Rapidity()) < selectionConfig.motherRapidityCut) + hInvMass.fill(HIST("h3KstarInvMassRotated"), centrality, motherRot.Pt(), motherRot.M()); + } + } else if (isMix && std::abs(mother.Rapidity()) < selectionConfig.motherRapidityCut) { + hInvMass.fill(HIST("h3KstarInvMassMixed"), centrality, mother.Pt(), mother.M()); + } + } else { + if (!isMix) { + if (calcLikeSign && std::abs(mother.Rapidity()) < selectionConfig.motherRapidityCut) { + if (track1.sign() > 0 && track2.sign() > 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignPP"), centrality, mother.Pt(), mother.M()); + } else if (track1.sign() < 0 && track2.sign() < 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignMM"), centrality, mother.Pt(), mother.M()); + } + } + } + } + } + + // 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) < selectionConfig.cfgVrtxZCut); + Filter acceptanceFilter = (nabs(aod::track::eta) < selectionConfig.cfgCutEtaMax && nabs(aod::track::pt) > selectionConfig.cfgCutPT); + Filter fDCAcutFilter = (nabs(aod::track::dcaXY) < selectionConfig.cfgCutDCAxyMax) && (nabs(aod::track::dcaZ) < selectionConfig.cfgCutDCAz); + + // using EventCandidates = soa::Filtered>; // aod::CentNGlobals, aod::CentNTPVs, aod::CentMFTs + // using EventCandidatesMC = soa::Filtered>; + // using TrackCandidates = soa::Filtered>; + // using TrackCandidatesMC = soa::Filtered>; + using EventCandidatesMix = soa::Filtered>; // aod::CentNGlobals, aod::CentNTPVs, aod::CentMFTs + + using EventCandidates = soa::Join; // aod::CentNGlobals, aod::CentNTPVs, aod::CentMFTs + using TrackCandidates = soa::Join; + + using EventMCGenerated = soa::Join; // aod::CentNGlobals, aod::CentNTPVs, aod::CentMFTs + using EventCandidatesMC = soa::Join; + using TrackCandidatesMC = soa::Join; + + void processSE(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + { + int occupancy = collision.trackOccupancyInTimeRange(); + hEventSelection.fill(HIST("hOccupancy"), occupancy); + + if (!selectionEvent(collision, true)) { // fill data event cut histogram + return; + } + + centrality = -1; + + if (selectCentEstimator == kFT0M) { + centrality = collision.centFT0M(); + } else if (selectCentEstimator == kFT0A) { + centrality = collision.centFT0A(); + } else if (selectCentEstimator == kFT0C) { + centrality = collision.centFT0C(); + } else if (selectCentEstimator == kFV0A) { + centrality = collision.centFV0A(); + } else { + centrality = collision.centFT0M(); // default + } + + /* else if (selectCentEstimator == 4) { + centrality = collision.centMFT(); + } */ + /* else if (selectCentEstimator == 5) { + centrality = collision.centNGlobal(); + } */ + /* else if (selectCentEstimator == 6) { + centrality = collision.centNTPV(); + } */ + + // Fill the event counter + if (cQAevents) { + hEventSelection.fill(HIST("hVertexZ"), collision.posZ()); + hEventSelection.fill(HIST("hCentrality"), centrality); + } + + for (const auto& [track1, track2] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { + if (!selectionTrack(track1) || !selectionTrack(track2)) { + continue; + } + + if (track1.globalIndex() == track2.globalIndex()) + continue; + + if (!selectionPair(track1, track2)) { + continue; + } + + if (cQAplots) { + hOthers.fill(HIST("hCRFC_before"), track1.tpcCrossedRowsOverFindableCls()); + hOthers.fill(HIST("dE_by_dx_TPC"), track1.p(), track1.tpcSignal()); + + if (track1.sign() < 0) { + hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + } else if (track1.sign() > 0) { + hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + } + + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track1.tpcNSigmaPi(), track1.tofNSigmaPi(), track1.pt()); + } + + if (cQAevents) { + hOthers.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), centrality, track1.pt()); + hOthers.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), centrality, track1.pt()); + } + + // 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 (!selectionConfig.isApplypTdepPID && !selectionPID(track1, 1)) // Track 1 is checked with Kaon + continue; + if (!selectionConfig.isApplypTdepPID && !selectionPID(track2, 0)) // Track 2 is checked with Pion + continue; + + if (selectionConfig.isApplypTdepPID && !selectionPIDNew(track1, 1)) // Track 1 is checked with Kaon + continue; + if (selectionConfig.isApplypTdepPID && !selectionPIDNew(track2, 0)) // Track 2 is checked with Pion + continue; + + if (cQAplots) { + hOthers.fill(HIST("hEta_after"), track1.eta()); + hOthers.fill(HIST("hCRFC_after"), track1.tpcCrossedRowsOverFindableCls()); + hOthers.fill(HIST("hDcaxyPi"), track2.dcaXY()); + hOthers.fill(HIST("hDcaxyKa"), track1.dcaXY()); + hOthers.fill(HIST("hDcazPi"), track2.dcaZ()); + hOthers.fill(HIST("hDcazKa"), track1.dcaZ()); + + if (track1.sign() < 0) { + hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + } else if (track1.sign() > 0) { + hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + } + + if (track2.sign() < 0) { + hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + } else if (track2.sign() > 0) { + hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + } + + hPID.fill(HIST("After/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); + hPID.fill(HIST("After/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), track2.tofNSigmaPi(), track2.pt()); + } + + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + mother = daughter1 + daughter2; // Kstar meson + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mother.Pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (mother.M() >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + hOthers.fill(HIST("hKstar_rap_pt"), mother.Rapidity(), mother.Pt()); + hOthers.fill(HIST("hKstar_eta_pt"), mother.Eta(), mother.Pt()); + + isMix = false; + fillInvMass(daughter1, daughter2, mother, centrality, isMix, track1, track2); + } + } + PROCESS_SWITCH(Kstar892LightIon, processSE, "Process Same event", true); + + void processSEMC(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, aod::McCollisions const& /*mcCollisions*/) + { + // auto oldindex = -999; + if (!collision.has_mcCollision()) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + hEventSelection.fill(HIST("hOccupancy"), occupancy); + + if (!selectionEvent(collision, false)) { // don't fill event cut histogram + return; + } + + centrality = -1; + + if (selectCentEstimator == kFT0M) { + centrality = collision.centFT0M(); + } else if (selectCentEstimator == kFT0A) { + centrality = collision.centFT0A(); + } else if (selectCentEstimator == kFT0C) { + centrality = collision.centFT0C(); + } else if (selectCentEstimator == kFV0A) { + centrality = collision.centFV0A(); + } else { + centrality = collision.centFT0M(); // default + } + + // Fill the event counter + if (cQAevents) { + hEventSelection.fill(HIST("hVertexZ"), collision.posZ()); + hEventSelection.fill(HIST("hCentrality"), centrality); + } + + for (const auto& [track1, track2] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { + if (!selectionTrack(track1) || !selectionTrack(track2)) + continue; + + const auto mctrack1 = track1.mcParticle(); + const auto mctrack2 = track2.mcParticle(); + + if (!track1.has_mcParticle() || !track2.has_mcParticle()) + continue; // skip if no MC particle associated + + if (!mctrack1.isPhysicalPrimary() || !mctrack2.isPhysicalPrimary()) + continue; + + if (track1.globalIndex() == track2.globalIndex()) + continue; + + if (cQAplots) { + hOthers.fill(HIST("hCRFC_before"), track1.tpcCrossedRowsOverFindableCls()); + hOthers.fill(HIST("dE_by_dx_TPC"), track1.p(), track1.tpcSignal()); + + if (track1.sign() < 0) { + hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + } else { + hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + } + + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track1.tpcNSigmaPi(), track1.tofNSigmaPi(), track1.pt()); + } + + if (cQAevents) { + hOthers.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), centrality, track1.pt()); + hOthers.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), centrality, track1.pt()); + } + + // 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 (!selectionConfig.isApplypTdepPID && (!selectionPID(track1, 1) || !selectionPID(track2, 0))) // Track 1 is checked with Kaon, track 2 is checked with Pion + continue; + + if (selectionConfig.isApplypTdepPID && (!selectionPIDNew(track1, 1) || !selectionPIDNew(track2, 0))) // Track 1 is checked with Kaon, track 2 is checked with Pion + continue; + + if (cQAplots) { + hOthers.fill(HIST("hEta_after"), track1.eta()); + hOthers.fill(HIST("hCRFC_after"), track1.tpcCrossedRowsOverFindableCls()); + hOthers.fill(HIST("hDcaxyPi"), track2.dcaXY()); + hOthers.fill(HIST("hDcaxyKa"), track1.dcaXY()); + hOthers.fill(HIST("hDcazPi"), track2.dcaZ()); + hOthers.fill(HIST("hDcazKa"), track1.dcaZ()); + + if (track1.sign() < 0) { + hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + } else if (track1.sign() > 0) { + hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + } + + if (track2.sign() < 0) { + hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + } else if (track2.sign() > 0) { + hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + } + + hPID.fill(HIST("After/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); + hPID.fill(HIST("After/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), track2.tofNSigmaPi(), track2.pt()); + } + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + mother = daughter1 + daughter2; // Kstar meson + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mother.Pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (mother.M() >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + hOthers.fill(HIST("hKstar_rap_pt"), mother.Rapidity(), mother.Pt()); + hOthers.fill(HIST("hKstar_eta_pt"), mother.Eta(), mother.Pt()); + + isMix = false; + fillInvMass(daughter1, daughter2, mother, centrality, isMix, track1, track2); + } + } + PROCESS_SWITCH(Kstar892LightIon, processSEMC, "Process same event in MC", false); + + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for ME mixing"}; + // ConfigurableAxis axisCentralityClass{"axisCentralityClass", {10, 0, 100}, "centrality percentile for ME mixing"}; + ConfigurableAxis axisCentrality{"axisCentrality", {2000, 0, 10000}, "TPC centrality axis for ME mixing"}; + + // using BinningTypeTPCcentrality = ColumnBinningPolicy; + using BinningTypeFT0M = ColumnBinningPolicy; + using BinningTypeFT0A = ColumnBinningPolicy; + using BinningTypeFT0C = ColumnBinningPolicy; + using BinningTypeFV0A = ColumnBinningPolicy; + + BinningTypeFT0M binningOnFT0M{{axisVertex, axisCentrality}, true}; + BinningTypeFT0A binningOnFT0A{{axisVertex, axisCentrality}, true}; + BinningTypeFT0C binningOnFT0C{{axisVertex, axisCentrality}, true}; + BinningTypeFV0A binningOnFV0A{{axisVertex, axisCentrality}, true}; + + SameKindPair pair1{binningOnFT0M, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pair2{binningOnFT0A, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pair3{binningOnFT0C, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pair4{binningOnFV0A, selectionConfig.cfgNoMixedEvents, -1, &cache}; + + void processME(EventCandidatesMix const&, TrackCandidates const&) + { + // Map estimator to pair and centrality accessor + auto runMixing = [&](auto& pair, auto centralityGetter) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + if (!selectionEvent(c1, false) || !selectionEvent(c2, false)) { // don't fill event cut histogram + continue; + } + + centrality = centralityGetter(c1); + + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!selectionTrack(t1) || !selectionTrack(t2)) + continue; + + if (!selectionPair(t1, t2)) { + continue; + } + + if (!selectionConfig.isApplypTdepPID && (!selectionPID(t1, 1) || !selectionPID(t2, 0))) // Track 1 is checked with Kaon, track 2 is checked with Pion + continue; + + if (selectionConfig.isApplypTdepPID && (!selectionPIDNew(t1, 1) || !selectionPIDNew(t2, 0))) // Track 1 is checked with Kaon, track 2 is checked with Pion + continue; + + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massPi); + mother = daughter1 + daughter2; + + isMix = true; + + if (std::abs(mother.Rapidity()) < selectionConfig.motherRapidityCut) { + fillInvMass(daughter1, daughter2, mother, centrality, isMix, t1, t2); + } + } + } + }; + + // Call mixing based on selected estimator + if (selectCentEstimator == kFT0M) { + runMixing(pair1, [](const auto& c) { return c.centFT0M(); }); + } else if (selectCentEstimator == kFT0A) { + runMixing(pair2, [](const auto& c) { return c.centFT0A(); }); + } else if (selectCentEstimator == kFT0C) { + runMixing(pair3, [](const auto& c) { return c.centFT0C(); }); + } else if (selectCentEstimator == kFV0A) { + runMixing(pair4, [](const auto& c) { return c.centFV0A(); }); + } + } + PROCESS_SWITCH(Kstar892LightIon, processME, "Process Mixed event", true); + + using BinningTypeMCFT0M = ColumnBinningPolicy; + using BinningTypeMCFT0A = ColumnBinningPolicy; + using BinningTypeMCFT0C = ColumnBinningPolicy; + using BinningTypeMCFV0A = ColumnBinningPolicy; + + BinningTypeMCFT0M binningOnMCFT0M{{axisVertex, axisCentrality}, true}; + BinningTypeMCFT0A binningOnMCFT0A{{axisVertex, axisCentrality}, true}; + BinningTypeMCFT0C binningOnMCFT0C{{axisVertex, axisCentrality}, true}; + BinningTypeMCFV0A binningOnMCFV0A{{axisVertex, axisCentrality}, true}; + + SameKindPair pairmc1{binningOnMCFT0M, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairmc2{binningOnMCFT0A, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairmc3{binningOnMCFT0C, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairmc4{binningOnMCFV0A, selectionConfig.cfgNoMixedEvents, -1, &cache}; + + void processMEMC(EventCandidatesMC const&, TrackCandidatesMC const&, aod::McParticles const&, aod::McCollisions const&) + { + auto runMixing = [&](auto& pair, auto centralityGetter) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + if (!selectionEvent(c1, false) || !selectionEvent(c2, false)) { // don't fill event cut histogram + continue; + } + + if (!c1.has_mcCollision() || !c2.has_mcCollision()) { + continue; // skip if no MC collision associated + } + + centrality = centralityGetter(c1); + + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!selectionTrack(t1) || !selectionTrack(t2)) + continue; + + if (!selectionPair(t1, t2)) { + continue; + } + + if (!selectionConfig.isApplypTdepPID && (!selectionPID(t1, 1) || !selectionPID(t2, 0))) // Track 1 is checked with Kaon, track 2 is checked with Pion + continue; + + if (selectionConfig.isApplypTdepPID && (!selectionPIDNew(t1, 1) || !selectionPIDNew(t2, 0))) // Track 1 is checked with Kaon, track 2 is checked with Pion + continue; + + if (!t1.has_mcParticle() || !t2.has_mcParticle()) { + continue; // skip if no MC particle associated + } + + const auto mctrack1 = t1.mcParticle(); + const auto mctrack2 = t2.mcParticle(); + + if (!mctrack1.isPhysicalPrimary() || !mctrack2.isPhysicalPrimary()) { + continue; + } + + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massPi); + mother = daughter1 + daughter2; + + isMix = true; + + if (std::abs(mother.Rapidity()) < selectionConfig.motherRapidityCut) { + fillInvMass(daughter1, daughter2, mother, centrality, isMix, t1, t2); + } + } + } + }; + // Call mixing based on selected estimator + if (selectCentEstimator == kFT0M) { + runMixing(pairmc1, [](const auto& c) { return c.centFT0M(); }); + } else if (selectCentEstimator == kFT0A) { + runMixing(pairmc2, [](const auto& c) { return c.centFT0A(); }); + } else if (selectCentEstimator == kFT0C) { + runMixing(pairmc3, [](const auto& c) { return c.centFT0C(); }); + } else if (selectCentEstimator == kFV0A) { + runMixing(pairmc4, [](const auto& c) { return c.centFV0A(); }); + } + } + PROCESS_SWITCH(Kstar892LightIon, processMEMC, "Process mixed-event in MC", false); + + void processGen(EventMCGenerated::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + { + std::vector selectedEvents(collisions.size()); + int nevts = 0; + centrality = -1.0; + + for (const auto& collision : collisions) { + if (!selectionEvent(collision, false)) { // don't fill event cut histogram + continue; + } + centrality = collision.centFT0M(); + + if (selectCentEstimator == kFT0M) { + centrality = collision.centFT0M(); + } else if (selectCentEstimator == kFT0A) { + centrality = collision.centFT0A(); + } else if (selectCentEstimator == kFT0C) { + centrality = collision.centFT0C(); + } else if (selectCentEstimator == kFV0A) { + centrality = collision.centFV0A(); + } else { + centrality = collision.centFT0M(); // default + } + hMC.fill(HIST("Gen/h1GenCent"), centrality); + + int occupancy = collision.trackOccupancyInTimeRange(); + hEventSelection.fill(HIST("hOccupancy"), occupancy); + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.y()) < selectionConfig.motherRapidityCut && std::abs(mcParticle.pdgCode()) == o2::constants::physics::kK0Star892) { + hMC.fill(HIST("Gen/hAllKstarGenCollisisons"), mcParticle.pt(), centrality); + } + } + + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + hMC.fill(HIST("Gen/hAllGenCollisions"), centrality); + if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + + hMC.fill(HIST("Gen/hAllGenCollisions1Rec"), centrality); + + for (const auto& mcParticle : mcParticles) { + + if (std::abs(mcParticle.y()) >= selectionConfig.motherRapidityCut) { + continue; + } + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mcParticle.pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if ((std::sqrt(mcParticle.e() * mcParticle.e() - mcParticle.p() * mcParticle.p())) >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + if (std::abs(mcParticle.pdgCode()) != o2::constants::physics::kK0Star892) { + continue; + } + hMC.fill(HIST("Gen/hAllKstarGenCollisisons1Rec"), mcParticle.pt(), centrality); + + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != noOfDaughters) { + continue; + } + + bool hasPos = false; + bool hasNeg = false; + + auto passkaon = false; + auto passpion = false; + + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + + int pdgDau = kCurrentDaughter.pdgCode(); + int charge = (pdgDau > 0) - (pdgDau < 0); + + if (charge > 0) + hasPos = true; + if (charge < 0) + hasNeg = true; + + if (std::abs(pdgDau) == PDG_t::kKPlus) { + passkaon = true; + } else if (std::abs(pdgDau) == PDG_t::kPiPlus) { + passpion = true; + } + } + + if ((passkaon && passpion) && (hasPos && hasNeg)) { + hMC.fill(HIST("Gen/hk892GenpT"), mcParticle.pt(), centrality); + } + } + } + PROCESS_SWITCH(Kstar892LightIon, processGen, "Process Generated", false); + + void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, EventMCGenerated const&) + { + if (!collision.has_mcCollision()) { + return; + } + + centrality = collision.centFT0M(); + + if (selectCentEstimator == kFT0M) { + centrality = collision.centFT0M(); + } else if (selectCentEstimator == kFT0A) { + centrality = collision.centFT0A(); + } else if (selectCentEstimator == kFT0C) { + centrality = collision.centFT0C(); + } else if (selectCentEstimator == kFV0A) { + centrality = collision.centFV0A(); + } else { + centrality = collision.centFT0M(); // default + } + + hMC.fill(HIST("Rec/hAllRecCollisions"), centrality); + + if (!selectionEvent(collision, true)) { // fill MC event cut histogram + return; + } + + hMC.fill(HIST("Rec/h1RecCent"), centrality); + + if (cQAevents) { + hEventSelection.fill(HIST("hVertexZ"), collision.posZ()); + } + + auto oldindex = -999; + + for (const auto& [track1, track2] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { + if (!selectionTrack(track1) || !selectionTrack(track2)) { + continue; + } + + if (!track1.has_mcParticle() || !track2.has_mcParticle()) { + continue; + } + + if (track1.index() == track2.index()) + continue; + + if (indexCheck && (track2.index() < track1.index())) + continue; + + if (!selectionPair(track1, track2)) { + continue; + } + + if (cQAevents) { + hOthers.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), centrality, track1.pt()); + hOthers.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), centrality, track1.pt()); + } + + if (track1.sign() * track2.sign() >= 0) { + continue; + } + + const auto mctrack1 = track1.mcParticle(); + const auto mctrack2 = track2.mcParticle(); + if (!mctrack1.isPhysicalPrimary() || !mctrack2.isPhysicalPrimary()) { + continue; + } + + int track1PDG = std::abs(mctrack1.pdgCode()); + int track2PDG = std::abs(mctrack2.pdgCode()); + + if (cQAplots) { + if (mctrack2.pdgCode() == PDG_t::kPiPlus) { // pion + hPID.fill(HIST("Before/hTPCnsigPi_Pos_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Pos_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + } + if (mctrack2.pdgCode() == PDG_t::kKPlus) { // kaon + hPID.fill(HIST("Before/hTPCnsigKa_Pos_mult_pt"), track2.tpcNSigmaKa(), centrality, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Pos_mult_pt"), track2.tofNSigmaKa(), centrality, track2.pt()); + } + if (mctrack2.pdgCode() == PDG_t::kPiMinus) { // negative track pion + hPID.fill(HIST("Before/hTPCnsigPi_Neg_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_Neg_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + } + if (mctrack2.pdgCode() == PDG_t::kKMinus) { // negative track kaon + hPID.fill(HIST("Before/hTPCnsigKa_Neg_mult_pt"), track2.tpcNSigmaKa(), centrality, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_Neg_mult_pt"), track2.tofNSigmaKa(), centrality, track2.pt()); + } + if (std::abs(mctrack1.pdgCode()) == PDG_t::kKPlus && std::abs(mctrack2.pdgCode()) == PDG_t::kPiPlus) { + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Ka_pt"), track1.tpcNSigmaKa(), track1.tofNSigmaKa(), track1.pt()); + hPID.fill(HIST("Before/hNsigma_TPC_TOF_Pi_pt"), track2.tpcNSigmaPi(), track2.tofNSigmaPi(), track2.pt()); + } + } + + if (!(track1PDG == PDG_t::kPiPlus && track2PDG == PDG_t::kKPlus) && !(track1PDG == PDG_t::kKPlus && track2PDG == PDG_t::kPiPlus)) { + continue; + } + + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { + continue; + } + + if (!mothertrack1.producedByGenerator()) { + continue; + } + + if (std::abs(mothertrack1.y()) >= selectionConfig.motherRapidityCut) { + continue; + } + + if (std::abs(mothertrack1.pdgCode()) != o2::constants::physics::kK0Star892) { + continue; + } + + if (track1PDG == PDG_t::kPiPlus) { + if (!selectionConfig.isApplypTdepPID && !(selectionPID(track1, 0) && selectionPID(track2, 1))) { // pion and kaon + continue; + } else if (selectionConfig.isApplypTdepPID && !(selectionPIDNew(track1, 0) && selectionPIDNew(track2, 1))) { // pion and kaon + continue; + } + + if (cQAplots) { + if (track1.sign() < 0 && track2.sign() > 0) { + hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_pt"), track2.tpcNSigmaKa(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), track2.tofNSigmaKa(), centrality, track2.pt()); + } else { + hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_pt"), track1.tpcNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), track1.tofNSigmaPi(), centrality, track1.pt()); + hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_pt"), track2.tpcNSigmaKa(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), track2.tofNSigmaKa(), centrality, track2.pt()); + } + } + + } else if (track1PDG == PDG_t::kKPlus) { + if (!selectionConfig.isApplypTdepPID && !(selectionPID(track1, 1) && selectionPID(track2, 0))) { // kaon and pion + continue; + } else if (selectionConfig.isApplypTdepPID && !(selectionPIDNew(track1, 1) && selectionPIDNew(track2, 0))) { // kaon and pion + continue; + } + + if (cQAplots) { + if (track1.sign() < 0 && track2.sign() > 0) { + hPID.fill(HIST("After/hTPCnsigKa_Neg_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Neg_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTPCnsigPi_Pos_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Pos_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + } else { + hPID.fill(HIST("After/hTPCnsigKa_Pos_mult_pt"), track1.tpcNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_Pos_mult_pt"), track1.tofNSigmaKa(), centrality, track1.pt()); + hPID.fill(HIST("After/hTPCnsigPi_Neg_mult_pt"), track2.tpcNSigmaPi(), centrality, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_Neg_mult_pt"), track2.tofNSigmaPi(), centrality, track2.pt()); + } + } + } + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mothertrack1.pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if ((std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())) >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + if (selectionConfig.isAvoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + hMC.fill(HIST("Rec/h1KSRecsplit"), mothertrack1.pt()); + continue; + } + + oldindex = mothertrack1.globalIndex(); + + if (track1PDG == PDG_t::kPiPlus) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPi); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } else if (track1PDG == PDG_t::kKPlus) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + } + + mother = daughter1 + daughter2; // Kstar meson + + hMC.fill(HIST("Rec/h2KstarRecpt2"), mothertrack1.pt(), centrality, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); + + if (mother.Rapidity() >= selectionConfig.motherRapidityCut) { + continue; + } + + hMC.fill(HIST("Rec/h1KstarRecMass"), mother.M()); + hMC.fill(HIST("Rec/h2KstarRecpt1"), mother.Pt(), centrality, mother.M()); + } + } + } + } + PROCESS_SWITCH(Kstar892LightIon, processRec, "Process Reconstructed", false); + + void processEvtLossSigLossMC(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions) + { + auto impactPar = mcCollision.impactParameter(); + hMC.fill(HIST("ImpactCorr/hImpactParameterGen"), impactPar); + + bool isSelectedEvent = false; + auto centrality = -999.; + for (const auto& RecCollision : recCollisions) { + if (!RecCollision.has_mcCollision()) + continue; + if (!selectionEvent(RecCollision, false)) // don't fill event cut histogram + continue; + + if (selectCentEstimator == kFT0M) { + centrality = RecCollision.centFT0M(); + } else if (selectCentEstimator == kFT0A) { + centrality = RecCollision.centFT0A(); + } else if (selectCentEstimator == kFT0C) { + centrality = RecCollision.centFT0C(); + } else if (selectCentEstimator == kFV0A) { + centrality = RecCollision.centFV0A(); + } else { + centrality = RecCollision.centFT0M(); // default + } + + isSelectedEvent = true; + } + + if (isSelectedEvent) { + hMC.fill(HIST("ImpactCorr/hImpactParameterRec"), impactPar); + hMC.fill(HIST("ImpactCorr/hImpactParvsCentrRec"), centrality, impactPar); + } + + // Generated MC + for (const auto& mcPart : mcParticles) { + + if (std::abs(mcPart.y()) >= selectionConfig.motherRapidityCut || std::abs(mcPart.pdgCode()) != o2::constants::physics::kK0Star892) + continue; + + // signal loss estimation + hMC.fill(HIST("ImpactCorr/hKstarGenBeforeEvtSel"), mcPart.pt(), impactPar); + if (isSelectedEvent) { + // signal loss estimation + hMC.fill(HIST("ImpactCorr/hKstarGenAfterEvtSel"), mcPart.pt(), impactPar); + } + } // end loop on gen particles + } + PROCESS_SWITCH(Kstar892LightIon, processEvtLossSigLossMC, "Process Signal Loss, Event Loss using impact parameter", false); + + using McCollisionMults = soa::Join; + using LabeledTracks = soa::Join; + + void processCorrFactors(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) + { + hMC.fill(HIST("CorrFactors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 0.5); + + if (std::abs(mcCollision.posZ()) > selectionConfig.cfgVrtxZCut) + return; + + hMC.fill(HIST("CorrFactors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 1.5); + + float centrality = 100.5f; + for (auto const& collision : collisions) { + centrality = collision.centFT0M(); + } + + hMC.fill(HIST("CorrFactors/hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta08()); + hMC.fill(HIST("CorrFactors/hNrecInGen"), collisions.size()); + + for (const auto& mcParticle : mcParticles) { + + if (std::abs(mcParticle.y()) >= selectionConfig.motherRapidityCut) + continue; + + if (std::abs(mcParticle.pdgCode()) == o2::constants::physics::kK0Star892) { + + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != noOfDaughters) { + continue; + } + + bool hasPos = false; + bool hasNeg = false; + + auto passkaon = false; + auto passpion = false; + for (const auto& kCurrentDaughter : kDaughters) { + // if (!kCurrentDaughter.isPhysicalPrimary()) + // continue; + + int pdgDau = kCurrentDaughter.pdgCode(); + int sign = (pdgDau > 0) - (pdgDau < 0); + + if (sign > 0) + hasPos = true; + if (sign < 0) + hasNeg = true; + + if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kKPlus) { + passkaon = true; + daughter1 = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + + } else if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kPiPlus) { + passpion = true; + daughter2 = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massPi); + } + } + + if ((passkaon && passpion) && (hasPos && hasNeg)) { + mother = daughter1 + daughter2; // Kstar meson + + hMC.fill(HIST("CorrFactors/h2dGenKstar"), centrality, mother.Pt()); + hMC.fill(HIST("CorrFactors/h3dGenKstarVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta08(), centrality, mother.Pt()); + } + } + } + + if (collisions.size() == 0) + return; + + hMC.fill(HIST("CorrFactors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 2.5); + } + PROCESS_SWITCH(Kstar892LightIon, processCorrFactors, "Process Signal Loss, Event Loss using chaged particle multiplicity", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/kstar892analysis.cxx b/PWGLF/Tasks/Resonances/kstar892analysis.cxx index ba456d46532..a4fae009388 100644 --- a/PWGLF/Tasks/Resonances/kstar892analysis.cxx +++ b/PWGLF/Tasks/Resonances/kstar892analysis.cxx @@ -16,25 +16,29 @@ /// adaped from k892analysis.cxx by Bong-Hwi Lim , Sawan Sawan /// \author Marta Urioni -#include -#include "TF1.h" +#include "PWGLF/DataModel/LFResonanceTables.h" #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 "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "DataFormatsParameters/GRPObject.h" -#include "CommonConstants/PhysicsConstants.h" + +#include "TF1.h" +#include + +#include 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}; @@ -87,11 +91,7 @@ struct kstar892analysis { Configurable additionalMEPlots{"additionalMEPlots", false, "Additional Mixed event plots"}; Configurable tof_at_high_pt{"tof_at_high_pt", false, "Use TOF at high pT"}; - 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"}; @@ -110,7 +110,6 @@ struct kstar892analysis { void init(o2::framework::InitContext&) { - // LOG(info) << "\n cfgITScluster ============>"<< static_cast(cfgITScluster); // LOG(info)<< "\n cfgTPCcluster ============>"<< static_cast(cfgTPCcluster); AxisSpec centAxis = {binsCent, "V0M (%)"}; @@ -247,30 +246,71 @@ struct kstar892analysis { // Filters Filter acceptanceFilter = nabs(aod::resodaughter::pt) >= cMinPtcut; - Filter qualityFilter = (aod::track::itsChi2NCl <= cfgITSChi2NCl) && (aod::track::tpcChi2NCl <= cfgTPCChi2NCl) && (aod::resodaughter::tpcCrossedRowsOverFindableCls >= cfgRatioTPCRowsOverFindableCls); Filter DCAcutFilter = (nabs(aod::track::dcaXY) <= cMaxDCArToPVcut) && (nabs(aod::track::dcaZ) <= cMaxDCAzToPVcut); - Filter hasTPCfilter = aod::resodaughter::hasTPC == true; - Filter primarytrackFilter = aod::resodaughter::isPVContributor && aod::resodaughter::isPrimaryTrack && aod::resodaughter::isGlobalTrackWoDCA; + // Filter primarytrackFilter = aod::resodaughter::isPVContributor && aod::resodaughter::isPrimaryTrack && aod::resodaughter::isGlobalTrackWoDCA; + Filter primarytrackFilter = requirePVContributor() && requirePrimaryTrack() && requireGlobalTrackWoDCA(); // partitions for data - Partition> resoKaWithTof = (nabs(aod::pidtof::tofNSigmaKa) <= cMaxTOFnSigmaKaon) && (aod::resodaughter::hasTOF == true); - Partition> resoPiWithTof = (nabs(aod::pidtof::tofNSigmaPi) <= cMaxTOFnSigmaPion) && (aod::resodaughter::hasTOF == true); - Partition> resoKa = (nabs(aod::pidtpc::tpcNSigmaKa) <= cMaxTPCnSigmaKaon); - Partition> resoPi = (nabs(aod::pidtpc::tpcNSigmaPi) <= cMaxTPCnSigmaPion); - Partition> resoKaTPClowPt = (nabs(aod::pidtpc::tpcNSigmaKa) <= cMaxTPCnSigmaKaon) && (nabs(aod::resodaughter::pt) < cMaxPtTPC); - Partition> resoPiTPClowPt = (nabs(aod::pidtpc::tpcNSigmaPi) <= cMaxTPCnSigmaPion) && (nabs(aod::resodaughter::pt) < cMaxPtTPC); - Partition> resoKaTOFhighPt = (nabs(aod::pidtof::tofNSigmaKa) <= cMaxTOFnSigmaKaon) && (aod::resodaughter::hasTOF == true) && (nabs(aod::resodaughter::pt) >= cMinPtTOF); - Partition> resoPiTOFhighPt = (nabs(aod::pidtof::tofNSigmaPi) <= cMaxTOFnSigmaPion) && (aod::resodaughter::hasTOF == true) && (nabs(aod::resodaughter::pt) >= cMinPtTOF); + 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::pidtof::tofNSigmaKa) <= cMaxTOFnSigmaKaon) && (aod::resodaughter::hasTOF == true); - Partition>> resoMCrecPiWithTof = (nabs(aod::pidtof::tofNSigmaPi) <= cMaxTOFnSigmaPion) && (aod::resodaughter::hasTOF == true); - Partition>> resoMCrecKa = (nabs(aod::pidtpc::tpcNSigmaKa) <= cMaxTPCnSigmaKaon); - Partition>> resoMCrecPi = (nabs(aod::pidtpc::tpcNSigmaPi) <= cMaxTPCnSigmaPion); - Partition>> resoMCrecKaTPClowPt = (nabs(aod::pidtpc::tpcNSigmaKa) <= cMaxTPCnSigmaKaon) && (nabs(aod::resodaughter::pt) < cMaxPtTPC); - Partition>> resoMCrecPiTPClowPt = (nabs(aod::pidtpc::tpcNSigmaPi) <= cMaxTPCnSigmaPion) && (nabs(aod::resodaughter::pt) < cMaxPtTPC); - Partition>> resoMCrecKaTOFhighPt = (nabs(aod::pidtof::tofNSigmaKa) <= cMaxTOFnSigmaKaon) && (aod::resodaughter::hasTOF == true) && (nabs(aod::resodaughter::pt) >= cMinPtTOF); - Partition>> resoMCrecPiTOFhighPt = (nabs(aod::pidtof::tofNSigmaPi) <= cMaxTOFnSigmaPion) && (aod::resodaughter::hasTOF == true) && (nabs(aod::resodaughter::pt) >= cMinPtTOF); + 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; @@ -282,11 +322,10 @@ struct kstar892analysis { template bool trackCut(const TrackType track) { - if (track.itsNCls() < cfgITScluster) - return false; + // TPC if (track.tpcNClsFound() < cfgTPCcluster) return false; - + // ITS if (cfgUseITSRefit && !track.passedITSRefit()) return false; if (cfgUseTPCRefit && !track.passedTPCRefit()) @@ -602,7 +641,7 @@ struct kstar892analysis { } // MC histograms - if (trk1.motherPDG() < 0) { + 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()); diff --git a/PWGLF/Tasks/Resonances/kstarFlowv1.cxx b/PWGLF/Tasks/Resonances/kstarFlowv1.cxx new file mode 100644 index 00000000000..871b763efb2 --- /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 "PWGLF/DataModel/SPCalibrationTables.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" + +#include +#include +#include + +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/kstarInOO.cxx b/PWGLF/Tasks/Resonances/kstarInOO.cxx new file mode 100644 index 00000000000..628e2a6fddb --- /dev/null +++ b/PWGLF/Tasks/Resonances/kstarInOO.cxx @@ -0,0 +1,876 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// \file kstarInOO.cxx +/// \brief the pT spectra of k*0(892) resonance analysis in OO collisions +/// \author Jimun Lee + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include +#include +#include +#include +#include + +#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 kstarInOO { + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + //================================== + //|| + //|| Selection + //|| + //================================== + + // Event Selection + Configurable cfgEventVtxCut{"cfgEventVtxCut", 10.0, "V_z cut selection"}; + ConfigurableAxis cfgCentAxis{"cfgCentAxis", {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}, "Binning of the centrality axis"}; + Configurable cfgOccupancySel{"cfgOccupancySel", false, "Occupancy selection"}; + Configurable cfgOccupancyMax{"cfgOccupancyMax", 999999., "maximum occupancy of tracks in neighbouring collisions in a given time range"}; + Configurable cfgOccupancyMin{"cfgOccupancyMin", -100., "minimum occupancy of tracks in neighbouring collisions in a given time range"}; + + // Track Selection + // General + Configurable cfgTrackMinPt{"cfgTrackMinPt", 0.15, "set track min pT"}; + Configurable cfgTrackMaxEta{"cfgTrackMaxEta", 0.8, "set track max Eta"}; + Configurable cfgTrackMaxDCArToPVcut{"cfgTrackMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + Configurable cfgTrackMaxDCAzToPVcut{"cfgTrackMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cfgTrackGlobalSel{"cfgTrackGlobalSel", true, "Global track selection"}; + Configurable cfgTrackPrimaryTrack{"cfgTrackPrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfgTrackConnectedToPV{"cfgTrackConnectedToPV", true, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgTrackGlobalWoDCATrack{"cfgTrackGlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + // TPC + Configurable cfgTracknFindableTPCClusters{"cfgTrackFindableTPCClusters", 50, "nFindable TPC Clusters"}; + Configurable cfgTracknTPCCrossedRows{"cfgTrackTPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable cfgTracknRowsOverFindable{"cfgTrackRowsOverFindable", 1.2, "nRowsOverFindable TPC CLusters"}; + Configurable cfgTracknTPCChi2{"cfgTrackTPCChi2", 4.0, "nTPC Chi2 per Cluster"}; + + // ITS + Configurable cfgTracknITSChi2{"cfgTrackITSChi2", 36.0, "nITS Chi2 per Cluster"}; + + // PID + Configurable cfgTrackTPCPID{"cfgTrackTPCPID", true, "Enables TPC PID"}; + Configurable cfgTrackTOFPID{"cfgTrackTOFPID", true, "Enables TOF PID"}; + Configurable cfgTrackSquarePIDCut{"cfgTrackSqurePIDCut", true, "Enables PID cut shape square switch"}; + Configurable cfgTrackCirclePIDCut{"cfgTrackCirclePIDCut", true, "Enables PID cut shape circle switch"}; + Configurable cfgTrackCircleValue{"cfgTrackCircleValue", 2, "Enables TOF TPC PID circle cut value"}; + Configurable cfgTrackTOFHard{"cfgTrackTOFHard", false, "Enables TOF Hard"}; + + Configurable cfgTrackTPCPIDnSig{"cfgTrackTPCPIDnSig", 4.0, "nTPC PID sigma"}; + Configurable cfgTrackTOFPIDnSig{"cfgTrackTOFPIDnSig", 4.0, "nTOF PID sigma"}; + Configurable cDebugLevel{"cDebugLevel", 0, "Resolution of Debug"}; + + // Mixing + ConfigurableAxis cfgBinsMixMult{"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 cfgBinsMixVtx{"cfgBinsMixVtx", {VARIABLE_WIDTH, -10.0f, -5.f, 0.f, 5.f, 10.f}, "Mixing bins - z-vertex"}; + Configurable cfgMixNMixedEvents{"cfgMixNMixedEvents", 10, "Number of mixed events per event"}; + Configurable cfgVtxMixCut{"cfgVtxMixCut", 10, "Vertex Mix Cut"}; + + // MCGen + Configurable cfgForceGenReco{"cfgForceGenReco", false, "Only consider events which are reconstructed (neglect event-loss)"}; + + // Pair + Configurable cfgMinvNBins{"cfgMinvNBins", 300, "Number of bins for Minv axis"}; + Configurable cfgMinvMin{"cfgMinvMin", 0.60, "Minimum Minv value"}; + Configurable cfgMinvMax{"cfgMinvMax", 1.20, "Maximum Minv value"}; + + // Histogram + ConfigurableAxis binsDCAz{"binsDCAz", {40, -0.2, 0.2}, ""}; + ConfigurableAxis binsDCAxy{"binsDCAxy", {40, -0.2, 0.2}, ""}; + Configurable cfgEventCutQA{"cfgEventCutsQA", false, "Enable Event QA Hists"}; + Configurable cfgTrackCutQA{"cfgTrackCutQA", false, "Enable Track QA Hists"}; + Configurable cfgDataHistos{"cfgDataHistos", false, "Enable Data Hists"}; + Configurable cfgMcHistos{"cfgMcHistos", false, "Enable MC Hists"}; + + // Main + void init(o2::framework::InitContext&) + { + // HISTOGRAMS + const AxisSpec axisEta{30, -1.5, +1.5, "#eta"}; + const AxisSpec axisPhi{200, -1, +7, "#phi"}; + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec pidAxis = {120, -6, 6}; + const AxisSpec minvAxis = {cfgMinvNBins, cfgMinvMin, cfgMinvMax}; + const AxisSpec axisDCAz{binsDCAz, "DCA_{z}"}; + const AxisSpec axisDCAxy{binsDCAxy, "DCA_{XY}"}; + + if (cfgEventCutQA) { + histos.add("hEvent_Cut", "Number of event after cuts", kTH1D, {{12, 0, 12}}); + histos.add("hPosZ_BC", "hPosZ_Bc", kTH1F, {{300, -15.0, 15.0}}); + histos.add("hPosZ_AC", "hPosZ_AC", kTH1F, {{300, -15.0, 15.0}}); + histos.add("hcentFT0C_BC", "centFT0C_BC", kTH1F, {{110, 0.0, 110.0}}); + histos.add("hcentFT0C_AC", "centFT0C_AC", kTH1F, {{110, 0.0, 110.0}}); + } + + if (cfgTrackCutQA) { + histos.add("hDCArToPv_BC", "DCArToPv_BC", kTH1F, {axisDCAxy}); + histos.add("hDCAzToPv_BC", "DCAzToPv_BC", kTH1F, {axisDCAz}); + histos.add("hIsPrim_BC", "hIsPrim_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsGood_BC", "hIsGood_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsPrimCont_BC", "hIsPrimCont_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hFindableTPCClusters_BC", "hFindableTPCClusters_BC", kTH1F, {{200, 0, 200}}); + histos.add("hFindableTPCRows_BC", "hFindableTPCRows_BC", kTH1F, {{200, 0, 200}}); + histos.add("hClustersVsRows_BC", "hClustersVsRows_BC", kTH1F, {{200, 0, 2}}); + histos.add("hTPCChi2_BC", "hTPCChi2_BC", kTH1F, {{200, 0, 100}}); + histos.add("QA_nSigma_pion_TPC_BC", "QA_nSigma_pion_TPC_BC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_nSigma_pion_TOF_BC", "QA_nSigma_pion_TOF_BC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_pion_TPC_TOF_BC", "QA_pion_TPC_TOF_BC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("QA_nSigma_kaon_TPC_BC", "QA_nSigma_kaon_TPC_BC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_nSigma_kaon_TOF_BC", "QA_nSigma_kaon_TOF_BC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_kaon_TPC_TOF_BC", "QA_kaon_TPC_TOF_BC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("QA_track_pT_BC", "QA_track_pT_BC", kTH1F, {{13, 0.0, 13.0}}); + + histos.add("hDCArToPv_AC", "DCArToPv_AC", kTH1F, {axisDCAxy}); + histos.add("hDCAzToPv_AC", "DCAzToPv_AC", kTH1F, {axisDCAz}); + histos.add("hIsPrim_AC", "hIsPrim_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsGood_AC", "hIsGood_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsPrimCont_AC", "hIsPrimCont_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hFindableTPCClusters_AC", "hFindableTPCClusters_AC", kTH1F, {{200, 0, 200}}); + histos.add("hFindableTPCRows_AC", "hFindableTPCRows_AC", kTH1F, {{200, 0, 200}}); + histos.add("hClustersVsRows_AC", "hClustersVsRows_AC", kTH1F, {{200, 0, 2}}); + histos.add("hTPCChi2_AC", "hTPCChi2_AC", kTH1F, {{200, 0, 100}}); + histos.add("QA_nSigma_pion_TPC_AC", "QA_nSigma_pion_TPC_AC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_nSigma_pion_TOF_AC", "QA_nSigma_pion_TOF_AC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_pion_TPC_TOF_AC", "QA_pion_TPC_TOF_AC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("QA_nSigma_kaon_TPC_AC", "QA_nSigma_kaon_TPC_AC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_nSigma_kaon_TOF_AC", "QA_nSigma_kaon_TOF_AC", {HistType::kTH2F, {ptAxis, pidAxis}}); + histos.add("QA_kaon_TPC_TOF_AC", "QA_kaon_TPC_TOF_AC", {HistType::kTH2F, {pidAxis, pidAxis}}); + histos.add("QA_track_pT_AC", "QA_track_pT_AC", kTH1F, {{13, 0.0, 13.0}}); + } + + if (cfgDataHistos) { + histos.add("nEvents", "nEvents", kTH1F, {{4, 0.0, 4.0}}); + histos.add("hUSS_KPi", "hUSS_KPi", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hUSS_PiK", "hUSS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hLSS_KPi", "hLSS_KPi", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hLSS_PiK", "hLSS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hUSS_KPi_Mix", "hUSS_KPi_Mix", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hUSS_PiK_Mix", "hUSS_PiK_Mix", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + } + + if (cfgMcHistos) { + histos.add("nEvents_MC", "nEvents_MC", kTH1F, {{4, 0.0, 4.0}}); + histos.add("nEvents_MC_True", "nEvents_MC_True", kTH1F, {{4, 0.0, 4.0}}); + histos.add("hMC_kstar_True", "hMC_kstar_True", kTHnSparseF, {cfgCentAxis, ptAxis}); + + histos.add("hMC_USS_True", "hMC_USS_True", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hMC_USS_KPi", "hMC_USS_KPi", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hMC_USS_PiK", "hMC_USS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hMC_LSS_KPi", "hMC_LSS_KPi", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hMC_LSS_PiK", "hMC_LSS_PiK", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + + histos.add("hMC_USS_KPi_Mix", "hMC_USS_KPi_Mix", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hMC_USS_PiK_Mix", "hMC_USS_PiK_Mix", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + + histos.add("hMC_USS_KPi_True", "hMC_USS_KPi_True", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + histos.add("hMC_USS_PiK_True", "hMC_USS_PiK_True", kTHnSparseF, {cfgCentAxis, ptAxis, minvAxis}); + } + + std::shared_ptr hCutFlow = histos.get(HIST("hEvent_Cut")); + std::vector eventCutLabels = { + "All Events", + "sel8", + Form("|Vz| < %.1f", cfgEventVtxCut.value), + "kIsGoodZvtxFT0vsPV", + "kNoSameBunchPileup", + "kNoTimeFrameBorder", + "kNoITSROFrameBorder", + "kNoCollInTimeRangeStandard", + "kIsGoodITSLayersAll", + Form("Occupancy < %.0f", cfgOccupancyMax.value), + "All passed events"}; + for (size_t i = 0; i < eventCutLabels.size(); ++i) { + hCutFlow->GetXaxis()->SetBinLabel(i + 1, eventCutLabels[i].c_str()); + } + + } // end of init + + using EventCandidates = soa::Join; //, aod::CentFT0Ms, aod::CentFT0As + using EventCandidatesTrue = aod::McCollisions; + using TrackCandidates = soa::Join; + using TrackCandidatesMC = soa::Join; + // For Mixed Event + using BinningType = ColumnBinningPolicy; + + Partition kaon = !cfgTrackTPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfgTrackTPCPIDnSig); + Partition pion = !cfgTrackTPCPID || (nabs(aod::pidtpc::tpcNSigmaPi) <= cfgTrackTPCPIDnSig); + Partition kaonMC = !cfgTrackTPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfgTrackTPCPIDnSig); + Partition pionMC = !cfgTrackTPCPID || (nabs(aod::pidtpc::tpcNSigmaPi) <= cfgTrackTPCPIDnSig); + + double massKa = o2::constants::physics::MassKPlus; + double massPi = o2::constants::physics::MassPiMinus; + + //================================== + //|| + //|| Helper Templates + //|| + //================================== + template + bool eventSelection(const EventType event) + { + if (cfgEventCutQA) { + histos.fill(HIST("hEvent_Cut"), 0); + histos.fill(HIST("hPosZ_BC"), event.posZ()); + histos.fill(HIST("hcentFT0C_BC"), event.centFT0C()); + } + if (!event.sel8()) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 1); + + if (std::abs(event.posZ()) > cfgEventVtxCut) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 2); + + if (!event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 3); + + if (!event.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 4); + + if (!event.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 5); + + if (!event.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 6); + + if (!event.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 7); + + if (!event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 8); + + if (cfgOccupancySel && (event.trackOccupancyInTimeRange() > cfgOccupancyMax || event.trackOccupancyInTimeRange() < cfgOccupancyMin)) + return false; + if (cfgEventCutQA) + histos.fill(HIST("hEvent_Cut"), 9); + + if (cfgEventCutQA) { + histos.fill(HIST("hEvent_Cut"), 10); + histos.fill(HIST("hPosZ_AC"), event.posZ()); + histos.fill(HIST("hcentFT0C_AC"), event.centFT0C()); + } + return true; + }; + + template + bool trackSelection(const TracksType track, const bool QA) + { + if (cfgTrackCutQA && QA) { + histos.fill(HIST("hDCArToPv_BC"), track.dcaXY()); + histos.fill(HIST("hDCAzToPv_BC"), track.dcaZ()); + histos.fill(HIST("hIsPrim_BC"), track.isPrimaryTrack()); + histos.fill(HIST("hIsGood_BC"), track.isGlobalTrackWoDCA()); + histos.fill(HIST("hIsPrimCont_BC"), track.isPVContributor()); + histos.fill(HIST("hFindableTPCClusters_BC"), track.tpcNClsFindable()); + histos.fill(HIST("hFindableTPCRows_BC"), track.tpcNClsCrossedRows()); + histos.fill(HIST("hClustersVsRows_BC"), track.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("hTPCChi2_BC"), track.tpcChi2NCl()); + histos.fill(HIST("QA_track_pT_BC"), track.pt()); + } + if (cfgTrackGlobalSel && !track.isGlobalTrack()) + return false; + if (track.pt() < cfgTrackMinPt) + return false; + if (std::abs(track.eta()) > cfgTrackMaxEta) + return false; + if (std::abs(track.dcaXY()) > cfgTrackMaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cfgTrackMaxDCAzToPVcut) + return false; + if (cfgTrackPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (cfgTrackGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (cfgTracknFindableTPCClusters > 0 && track.tpcNClsFindable() < cfgTracknFindableTPCClusters) + return false; + if (track.tpcNClsCrossedRows() < cfgTracknTPCCrossedRows) + return false; + if (cfgTracknRowsOverFindable > 0 && track.tpcCrossedRowsOverFindableCls() > cfgTracknRowsOverFindable) + return false; + if (track.tpcChi2NCl() > cfgTracknTPCChi2) + return false; + if (track.itsChi2NCl() > cfgTracknITSChi2) + return false; + if (cfgTrackConnectedToPV && !track.isPVContributor()) + return false; + + if (cfgTrackCutQA && QA) { + histos.fill(HIST("hDCArToPv_AC"), track.dcaXY()); + histos.fill(HIST("hDCAzToPv_AC"), track.dcaZ()); + histos.fill(HIST("hIsPrim_AC"), track.isPrimaryTrack()); + histos.fill(HIST("hIsGood_AC"), track.isGlobalTrackWoDCA()); + histos.fill(HIST("hIsPrimCont_AC"), track.isPVContributor()); + histos.fill(HIST("hFindableTPCClusters_AC"), track.tpcNClsFindable()); + histos.fill(HIST("hFindableTPCRows_AC"), track.tpcNClsCrossedRows()); + histos.fill(HIST("hClustersVsRows_AC"), track.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("hTPCChi2_AC"), track.tpcChi2NCl()); + histos.fill(HIST("QA_track_pT_AC"), track.pt()); + } + return true; + }; + + template + bool trackPIDKaon(const TrackPID& candidate, const bool QA) + { + if (cfgTrackCutQA && QA) { + histos.fill(HIST("QA_nSigma_kaon_TPC_BC"), candidate.pt(), candidate.tpcNSigmaKa()); + histos.fill(HIST("QA_nSigma_kaon_TOF_BC"), candidate.pt(), candidate.tofNSigmaKa()); + histos.fill(HIST("QA_kaon_TPC_TOF_BC"), candidate.tpcNSigmaKa(), candidate.tofNSigmaKa()); + } + double tpcpid = 0; + double tofpid = 0; + bool tpcPIDPassed{false}, tofPIDPassed{false}; + // TPC + if (cfgTrackSquarePIDCut) { + if (std::abs(candidate.tpcNSigmaKa()) < cfgTrackTPCPIDnSig) + tpcPIDPassed = true; + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < cfgTrackTOFPIDnSig) { + tofPIDPassed = true; + } + } else { + if (!cfgTrackTOFHard) { + tofPIDPassed = true; + } else { + tofPIDPassed = false; + } + } + } // end of square cut + if (cfgTrackCirclePIDCut) { + if (std::abs(candidate.tpcNSigmaKa()) < cfgTrackTPCPIDnSig) + tpcpid = std::abs(candidate.tpcNSigmaKa()); + tofpid = 0; + + if (candidate.hasTOF()) { + tofpid = std::abs(candidate.tofNSigmaKa()); + } else { + if (cfgTrackTOFHard) { + tofpid = 999; + } + } + if (tpcpid * tpcpid + tofpid * tofpid < cfgTrackCircleValue) { + tpcPIDPassed = true; + tofPIDPassed = true; + } + } // circular cut + // TPC & TOF + if (tpcPIDPassed && tofPIDPassed) { + if (cfgTrackCutQA && QA) { + histos.fill(HIST("QA_nSigma_kaon_TPC_AC"), candidate.pt(), candidate.tpcNSigmaKa()); + histos.fill(HIST("QA_nSigma_kaon_TOF_AC"), candidate.pt(), candidate.tofNSigmaKa()); + histos.fill(HIST("QA_kaon_TPC_TOF_AC"), candidate.tpcNSigmaKa(), candidate.tofNSigmaKa()); + } + return true; + } + return false; + } + + template + bool trackPIDPion(const TrackPID& candidate, const bool QA) + { + if (cfgTrackCutQA && QA) { + histos.fill(HIST("QA_nSigma_pion_TPC_BC"), candidate.pt(), candidate.tpcNSigmaPi()); + histos.fill(HIST("QA_nSigma_pion_TOF_BC"), candidate.pt(), candidate.tofNSigmaPi()); + histos.fill(HIST("QA_pion_TPC_TOF_BC"), candidate.tpcNSigmaPi(), candidate.tofNSigmaPi()); + } + double tpcpid = 0; + double tofpid = 0; + bool tpcPIDPassed{false}, tofPIDPassed{false}; + // TPC + if (cfgTrackSquarePIDCut) { + if (std::abs(candidate.tpcNSigmaPi()) < cfgTrackTPCPIDnSig) + tpcPIDPassed = true; + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaPi()) < cfgTrackTOFPIDnSig) { + tofPIDPassed = true; + } + } else { + if (!cfgTrackTOFHard) { + tofPIDPassed = true; + } else { + tofPIDPassed = false; + } + } + } // end of square cut + if (cfgTrackCirclePIDCut) { + if (std::abs(candidate.tpcNSigmaPi()) < cfgTrackTPCPIDnSig) + tpcpid = std::abs(candidate.tpcNSigmaPi()); + tofpid = 0; + + if (candidate.hasTOF()) { + tofpid = std::abs(candidate.tofNSigmaPi()); + } else { + if (cfgTrackTOFHard) { + tofpid = 999; + } + } + if (tpcpid * tpcpid + tofpid * tofpid < cfgTrackCircleValue) { + tpcPIDPassed = true; + tofPIDPassed = true; + } + } // circular cut + + // TPC & TOF + if (tpcPIDPassed && tofPIDPassed) { + if (cfgTrackCutQA && QA) { + histos.fill(HIST("QA_nSigma_pion_TPC_AC"), candidate.pt(), candidate.tpcNSigmaPi()); + histos.fill(HIST("QA_nSigma_pion_TOF_AC"), candidate.pt(), candidate.tofNSigmaPi()); + histos.fill(HIST("QA_pion_TPC_TOF_AC"), candidate.tpcNSigmaPi(), candidate.tofNSigmaPi()); + } + return true; + } + return false; + } + + template + void TrackSlicing(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool IsMix, const bool QA) + { + auto tracks1 = kaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto tracks2 = pion->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + auto centrality = collision1.centFT0C(); + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + auto [KstarPt_Kpi, Minv_Kpi] = minvReconstruction(trk1, trk2, QA, false); + auto [KstarPt_piK, Minv_piK] = minvReconstruction(trk1, trk2, QA, true); + + if (Minv_Kpi < 0) + continue; + + double conjugate = trk1.sign() * trk2.sign(); + if (cfgDataHistos) { + if (!IsMix) { + if (conjugate < 0) { + histos.fill(HIST("hUSS_KPi"), centrality, KstarPt_Kpi, Minv_Kpi); + histos.fill(HIST("hUSS_PiK"), centrality, KstarPt_piK, Minv_piK); + } else if (conjugate > 0) { + histos.fill(HIST("hLSS_KPi"), centrality, KstarPt_Kpi, Minv_Kpi); + histos.fill(HIST("hLSS_PiK"), centrality, KstarPt_piK, Minv_piK); + } + } else { + if (conjugate < 0) { + histos.fill(HIST("hUSS_KPi_Mix"), centrality, KstarPt_Kpi, Minv_Kpi); + histos.fill(HIST("hUSS_PiK_Mix"), centrality, KstarPt_piK, Minv_piK); + } + } + } + } // for + } // TrackSlicing + + template + void TrackSlicingMC(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool IsMix, const bool QA) + { + auto tracks1 = kaonMC->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto tracks2 = pionMC->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + auto centrality = collision1.centFT0C(); + + std::vector mcMemory; + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!trk1.has_mcParticle() || !trk2.has_mcParticle()) + continue; + + auto [KstarPt_Kpi, Minv_Kpi] = minvReconstruction(trk1, trk2, QA, false); + auto [KstarPt_piK, Minv_piK] = minvReconstruction(trk1, trk2, QA, true); + + if (Minv_Kpi < 0) + continue; + + double conjugate = trk1.sign() * trk2.sign(); + if (cfgMcHistos) { + if (!IsMix) { + if (conjugate < 0) { + histos.fill(HIST("hMC_USS_KPi"), centrality, KstarPt_Kpi, Minv_Kpi); + histos.fill(HIST("hMC_USS_PiK"), centrality, KstarPt_piK, Minv_piK); + } else if (conjugate > 0) { + histos.fill(HIST("hMC_LSS_KPi"), centrality, KstarPt_Kpi, Minv_Kpi); + histos.fill(HIST("hMC_LSS_PiK"), centrality, KstarPt_piK, Minv_piK); + } + } else { + if (conjugate < 0) { + histos.fill(HIST("hMC_USS_KPi_Mix"), centrality, KstarPt_Kpi, Minv_Kpi); + histos.fill(HIST("hMC_USS_PiK_Mix"), centrality, KstarPt_piK, Minv_piK); + } + } + } + //====================== + // Gen MC + auto particle1 = trk1.mcParticle(); + auto particle2 = trk2.mcParticle(); + + if (!particle1.has_mothers() || !particle2.has_mothers()) { + continue; + } + int mcindex1 = trk1.globalIndex(); + int mcindex2 = trk2.globalIndex(); + + std::vector mothers1{}; + std::vector mothers1PDG{}; + for (auto& particle1_mom : particle1.template mothers_as()) { + mothers1.push_back(particle1_mom.globalIndex()); + mothers1PDG.push_back(particle1_mom.pdgCode()); + } + + std::vector mothers2{}; + std::vector mothers2PDG{}; + for (auto& particle2_mom : particle2.template mothers_as()) { + mothers2.push_back(particle2_mom.globalIndex()); + mothers2PDG.push_back(particle2_mom.pdgCode()); + } + + if (mothers1PDG[0] != 313) + continue; // mother not K*0 + if (mothers2PDG[0] != 313) + continue; // mothers not K*0 + + if (mothers1[0] != mothers2[0]) + continue; // Kaon and pion not from the same K*0 + + if (std::fabs(particle1.pdgCode()) != 211 && std::fabs(particle1.pdgCode()) != 321) + continue; + if (std::fabs(particle2.pdgCode()) != 211 && std::fabs(particle2.pdgCode()) != 321) + continue; + + double track1_mass, track2_mass; + bool track1f{false}; // true means pion + + if (std::fabs(particle1.pdgCode()) == 211) { + track1f = true; + track1_mass = massPi; + } else { + track1_mass = massKa; + } + + if (std::fabs(particle2.pdgCode()) == 211) { + track2_mass = massPi; + } else { + track2_mass = massKa; + } + + if (track1_mass == track2_mass) { + return; + } + + bool exists1 = std::find(mcMemory.begin(), mcMemory.end(), mcindex1) != mcMemory.end(); + bool exists2 = std::find(mcMemory.begin(), mcMemory.end(), mcindex2) != mcMemory.end(); + if (exists1 || exists2) { + continue; + } else { + mcMemory.push_back(trk1.globalIndex()); + mcMemory.push_back(trk2.globalIndex()); + } + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), track1_mass); + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), track2_mass); + lResonance = lDecayDaughter1 + lDecayDaughter2; + + if (cfgMcHistos) { + histos.fill(HIST("hMC_USS_True"), centrality, lResonance.Pt(), lResonance.M()); + if (track1f) { + histos.fill(HIST("hMC_USS_PiK_True"), centrality, lResonance.Pt(), lResonance.M()); + } else { + histos.fill(HIST("hMC_USS_KPi_True"), centrality, lResonance.Pt(), lResonance.M()); + } + } + //====================== + } // for + } // TrackSlicingMC + + template + std::pair minvReconstruction(const TracksType& trk1, const TracksType& trk2, const bool QA, const bool flip) + { + if (!trackSelection(trk1, false) || !trackSelection(trk2, false)) + return {-1.0, -1.0}; + + if (!trackPIDKaon(trk1, QA) || !trackPIDPion(trk2, QA)) + return {-1.0, -1.0}; + + if (trk1.globalIndex() >= trk2.globalIndex()) + return {-1.0, -1.0}; + + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + if (!flip) { + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massPi); + } else { + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massPi); + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + } + lResonance = lDecayDaughter1 + lDecayDaughter2; + + if (std::abs(lResonance.Eta()) > cfgTrackMaxEta) + return {-1.0, -1.0}; + return {lResonance.Pt(), lResonance.M()}; + } + + //======================================================= + //| + //| DATA STUFF (SE) + //| + //======================================================= + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + if (cDebugLevel > 0) { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + } + + auto goodEv = eventSelection(collision); + if (cfgDataHistos) { + histos.fill(HIST("nEvents"), 0.5); + } + if (!goodEv) + return; + + bool INELgt0 = false; + for (const auto& track : tracks) { + if (!trackSelection(track, true)) + continue; + if (std::fabs(track.eta()) < cfgTrackMaxEta) { + INELgt0 = true; + } + } + if (!INELgt0) + return; + + if (cfgDataHistos) { + histos.fill(HIST("nEvents"), 1.5); + } + TrackSlicing(collision, tracks, collision, tracks, false, true); + + } // processSameEvents + PROCESS_SWITCH(kstarInOO, processDataSameEvent, "process Data Same Event", false); + + //======================================================= + //| + //| DATA STUFF (ME) + //| + //======================================================= + int nEventsMix = 0; + void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningType colBinning{{cfgBinsMixVtx, cfgBinsMixMult}, true}; // true is for 'ignore overflows' (true by default) + SameKindPair pairs{colBinning, cfgMixNMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (cDebugLevel > 0) { + nEventsMix++; + if ((nEventsMix + 1) % 10000 == 0) { + std::cout << "Processed DATA Mixed Events : " << nEventsMix << std::endl; + } + } + auto goodEv1 = eventSelection(collision1); + auto goodEv2 = eventSelection(collision2); + bool VtxMixFlag = false; + bool CentMixFlag = false; + // bool OccupanacyMixFlag = false; + if (std::fabs(collision1.posZ() - collision2.posZ()) <= cfgVtxMixCut) // set default to maybe 10 + VtxMixFlag = true; + if (std::fabs(collision1.centFT0C() - collision2.centFT0C()) <= cfgVtxMixCut) // set default to maybe 10 + CentMixFlag = true; + + if (!goodEv1 || !goodEv2) + continue; + if (!CentMixFlag) + continue; + if (!VtxMixFlag) + continue; + + TrackSlicing(collision1, tracks1, collision2, tracks2, true, false); + } + } + PROCESS_SWITCH(kstarInOO, processDataMixedEvent, "process DATA Mixed Event", false); + + //======================================================= + //| + //| MC STUFF (SE) + //| + //========================================================= + int nEventsMC = 0; + void processSameEventMC(EventCandidates::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&) + { + if (cDebugLevel > 0) { + nEventsMC++; + if ((nEventsMC + 1) % 10000 == 0) { + double histmem = histos.getSize(); + std::cout << histmem << std::endl; + std::cout << "process_SameEvent_MC: " << nEventsMC << std::endl; + } + } + auto goodEv = eventSelection(collision); + if (cfgMcHistos) { + histos.fill(HIST("nEvents_MC"), 0.5); + } + if (!goodEv) + return; + + bool INELgt0 = false; + for (const auto& track : tracks) { + if (!trackSelection(track, true)) + continue; + if (std::fabs(track.eta()) < cfgTrackMaxEta) { + INELgt0 = true; + } + } + if (!INELgt0) + return; + + if (cfgMcHistos) { + histos.fill(HIST("nEvents_MC"), 1.5); + } + TrackSlicingMC(collision, tracks, collision, tracks, false, true); + } // processSameEvents_MC + PROCESS_SWITCH(kstarInOO, processSameEventMC, "process Same Event MC", false); + + //======================================================= + //| + //| MC STUFF (ME) + //| + //======================================================= + int nEventsMCMix = 0; + void processMixedEventMC(EventCandidates const& collisions, TrackCandidatesMC const& tracks, aod::McParticles const&) + { + auto tracksTuple = std::make_tuple(tracks); + BinningType colBinning{{cfgBinsMixVtx, cfgBinsMixMult}, true}; // true is for 'ignore overflows' (true by default) + SameKindPair pairs{colBinning, cfgMixNMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (cDebugLevel > 0) { + nEventsMCMix++; + if ((nEventsMCMix + 1) % 10000 == 0) { + std::cout << "Processed Mixed Events: " << nEventsMCMix << std::endl; + } + } + auto goodEv1 = eventSelection(collision1); + auto goodEv2 = eventSelection(collision2); + if (!goodEv1 || !goodEv2) { + continue; + } + + TrackSlicingMC(collision1, tracks1, collision2, tracks2, true, false); + } // mixing + } // processMixedEvent_MC + PROCESS_SWITCH(kstarInOO, processMixedEventMC, "process Mixed Event MC", false); + + //======================================================= + //| + //| GENERATED MC STUFF (TRUE) + //| + //======================================================= + int nEventsTrue = 0; + void processMCTrue(EventCandidatesTrue::iterator const& collision, soa::SmallGroups> const& recocolls, aod::McParticles const& particles) + { + if (cDebugLevel > 0) { + ++nEventsTrue; + } + + if (fabs(collision.posZ()) > cfgEventVtxCut) + return; + if (recocolls.size() <= 0) { // not reconstructed + if (cfgForceGenReco) { + return; + } + } + + double centrality = -1; + for (auto& recocoll : recocolls) { + centrality = recocoll.centFT0C(); + auto goodEv = eventSelection(recocoll); + + if (cfgMcHistos) { + histos.fill(HIST("nEvents_MC_True"), 0.5); + } + if (!goodEv) + continue; + } // for + + for (auto& particle : particles) { + if (particle.pdgCode() != 313) + continue; // Not K*0 + if (std::fabs(particle.eta()) > cfgTrackMaxEta) + continue; + + if (cfgMcHistos) { + histos.fill(HIST("hMC_kstar_True"), centrality, particle.pt()); + } + if (cfgMcHistos) { + histos.fill(HIST("nEvents_MC_True"), 1.5); + } + + } // loop over particles + } // processMCTrue + PROCESS_SWITCH(kstarInOO, processMCTrue, "process MC True", false); + + void processEventsDummy(EventCandidates::iterator const&, TrackCandidates const&) + { + return; + } + PROCESS_SWITCH(kstarInOO, processEventsDummy, "dummy", false); +}; // kstarInOO +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/kstarpbpb.cxx b/PWGLF/Tasks/Resonances/kstarpbpb.cxx index 4894d8149d4..322e1cbaf4d 100644 --- a/PWGLF/Tasks/Resonances/kstarpbpb.cxx +++ b/PWGLF/Tasks/Resonances/kstarpbpb.cxx @@ -8,79 +8,105 @@ // In applying this license CERN does 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 "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" #include +#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 "CCDB/BasicCCDBManager.h" +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; +using namespace o2::aod::rctsel; 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; + struct RCTCut : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + + RCTFlagsChecker rctChecker; + }; + + RCTCut rctCut; // 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 usepolar{"usepolar", true, "flag to fill type of SA"}; + 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"}; @@ -89,30 +115,55 @@ struct kstarpbpb { 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 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; + + Preslice perCollision = aod::track::collisionId; SliceCache cache; - Partition posTracks = aod::track::signed1Pt > cfgCutCharge; - Partition negTracks = aod::track::signed1Pt < cfgCutCharge; + // Partition posTracks = aod::track::signed1Pt > cfgCutCharge; + // Partition negTracks = aod::track::signed1Pt < cfgCutCharge; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -125,66 +176,109 @@ 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"}; + rctCut.rctChecker.init( + rctCut.cfgEvtRCTFlagCheckerLabel, + rctCut.cfgEvtRCTFlagCheckerZDCCheck, + rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + 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 = {1500, 0, 1500, "Occupancy"}; - - 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("hOccupancy", "Occupancy distribution", kTH1F, {occupancyAxis}); - histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); - 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("hSparseV2SASameEvent_V2", "hSparseV2SASameEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - histos.add("hSparseV2SAMixedEvent_V2", "hSparseV2SAMixedEvent_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - histos.add("hSparseV2SASameEventRotational_V2", "hSparseV2SASameEventRotational_V2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisV2, thnAxisCentrality}); - histos.add("hMC", "MC Event statistics", kTH1F, {{6, 0.0f, 6.0f}}); - - // histogram for resolution - histos.add("ResFT0CTPC", "ResFT0CTPC", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0CFT0A", "ResFT0CFT0A", kTH2F, {centAxis, resAxis}); - histos.add("ResFT0ATPC", "ResFT0ATPC", kTH2F, {centAxis, resAxis}); + AxisSpec occupancyAxis = {occupancyBinning, "Occupancy"}; + histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{10, 0, 10.0}}); + 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}); + } + } + + 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}}); - histos.add("QAbefore/trkDCAzka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); - histos.add("QAafter/trkDCAxyka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); - histos.add("QAafter/trkDCAzka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); + histos.add("QAbefore/trkDCAxyka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAbefore/trkDCAzka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAafter/trkDCAxyka", "DCAxy distribution of kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAafter/trkDCAzka", "DCAz distribution of kaon track candidates", HistType::kTH1F, {{150, -1.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}}); - histos.add("QAbefore/trkDCAzpi", "DCAz distribution of pion track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); - histos.add("QAafter/trkDCAxypi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); - histos.add("QAafter/trkDCAzpi", "DCAz distribution of pion track candidates", HistType::kTH1F, {{150, 0.0f, 1.0f}}); + histos.add("QAbefore/trkDCAxypi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAbefore/trkDCAzpi", "DCAz distribution of pion track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAafter/trkDCAxypi", "DCAxy distribution of pion track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAafter/trkDCAzpi", "DCAz distribution of pion track candidates", HistType::kTH1F, {{150, -1.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}}}); - } - if (fillRotation) { - histos.add("hRotation", "hRotation", kTH1F, {{360, 0.0, 2.0 * TMath::Pi()}}); + 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); @@ -198,13 +292,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 @@ -224,7 +323,6 @@ struct kstarpbpb { return 1; } - template bool selectionTrack(const T& candidate) { @@ -238,62 +336,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.pt() >= 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && candidate.hasTOF() && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { 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()) { 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.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() && 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; } - template - bool selectionPID(const T& candidate, int PID) + bool selectionPID2(const T& candidate, int PID) { if (PID == 0) { - if (candidate.hasTOF() && ((candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) + (candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa())) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { return true; } - } else if (PID == 1) { - if (candidate.hasTOF() && ((candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) + (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi())) < (nsigmaCutCombined * nsigmaCutCombined)) { + } + if (PID == 1) { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tofNSigmaPi()) < nsigmaCutTOF) { return true; } } return false; } - template - bool selectionPIDNew(const T& candidate, int PID) + bool selectionPID(const T& candidate, int PID) { if (PID == 0) { - if (candidate.p() < 0.6 && TMath::Abs(candidate.tpcNSigmaKa()) < 2.0) { + 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.p() >= 0.6 && candidate.p() < 3.0 && candidate.hasTOF() && candidate.tpcNSigmaKa() > -2.0 && candidate.tpcNSigmaKa() < 3.0 && TMath::Abs(candidate.tofNSigmaKa()) < 2.0) { + if (isNoTOF && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { return true; } } else if (PID == 1) { - if (candidate.p() < 1.0 && TMath::Abs(candidate.tpcNSigmaPi()) < 2.0) { + if (!isNoTOF && !candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { + return true; + } + if (!isNoTOF && candidate.hasTOF() && ((candidate.tofNSigmaPi() * candidate.tofNSigmaPi()) + (candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi())) < (nsigmaCutCombined * nsigmaCutCombined)) { return true; } - if (candidate.p() >= 1.0 && candidate.p() < 3.0 && candidate.hasTOF() && candidate.tpcNSigmaPi() > -2.0 && candidate.tpcNSigmaPi() < 3.0 && TMath::Abs(candidate.tofNSigmaPi()) < 2.0) { + 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; @@ -305,63 +486,310 @@ 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, kaonrot, kstarrot; + 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; + + int currentRunNumber = -999; + int lastRunNumber = -999; + TH2D* hweight; + void processSE(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCsWithTimestamps const&) + { + histos.fill(HIST("hEvtSelInfo"), 0.5); + if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(collision)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 1.5); + 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; + } + histos.fill(HIST("hEvtSelInfo"), 2.5); + 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; + } + histos.fill(HIST("hEvtSelInfo"), 3.5); + if (additionalEvsel && !eventSelected(collision, centrality)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 4.5); + if (additionalEvselITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 5.5); + 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); + 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 (track1Sign * track2Sign < 0) { + if (usepolar) { + histos.fill(HIST("hSparseSAvsrapsameunlike"), KstarMother.M(), KstarMother.Pt(), cosThetaStar, KstarMother.Rapidity(), centrality); + } else { + histos.fill(HIST("hSparseSAvsrapsameunlike"), KstarMother.M(), KstarMother.Pt(), SA, KstarMother.Rapidity(), centrality); + } + } else if (track1Sign * track2Sign > 0) { + if (usepolar) { + histos.fill(HIST("hSparseSAvsrapsamelike"), KstarMother.M(), KstarMother.Pt(), cosThetaStar, KstarMother.Rapidity(), centrality); + } else { + 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; + if (!fillSA) { + 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); - void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) + 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); + auto cosThetaStarrot = eventplaneVecNorm.Dot(threeVecDauCMrot) / std::sqrt(threeVecDauCMrot.Mag2()) / std::sqrt(eventplaneVecNorm.Mag2()); + if (usepolar) { + histos.fill(HIST("hSparseSAvsraprot"), kstarrot.M(), kstarrot.Pt(), cosThetaStarrot, kstarrot.Rapidity(), centrality); + } else { + 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&) { - histos.fill(HIST("hMC"), 0.5); if (!collision.sel8()) { return; } - histos.fill(HIST("hMC"), 1.5); + auto centrality = collision.centFT0C(); + auto multTPC = collision.multNTracksPV(); + auto QFT0C = collision.qFT0C(); if (!collision.triggereventep()) { return; } - histos.fill(HIST("hMC"), 2.5); if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { return; } - histos.fill(HIST("hMC"), 3.5); + 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(); - int occupancy = collision.trackOccupancyInTimeRange(); - if (occupancy >= 1500) // occupancy info is available for this collision (*) + if (fillOccupancy && occupancy >= cfgOccupancyCut) // occupancy info is available for this collision (*) { return; } - histos.fill(HIST("hFTOCvsTPC"), centrality, multTPC); - if (additionalEvsel && !eventSelected(collision, tracks.size(), centrality)) { + if (additionalEvsel && !eventSelected(collision, centrality)) { return; } - histos.fill(HIST("hFTOCvsTPCSelected"), centrality, multTPC); - histos.fill(HIST("hPsiFT0C"), centrality, occupancy, psiFT0C); - histos.fill(HIST("hPsiFT0A"), centrality, occupancy, psiFT0A); - histos.fill(HIST("hPsiTPC"), centrality, occupancy, 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()); - + 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()); @@ -369,12 +797,16 @@ struct kstarpbpb { bool track1pion = false; bool track1kaon = false; - if (ispTdepPID && !(selectionPIDNew(track1, 0) || selectionPIDNew(track1, 1))) { + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track1, 0) || selectionPIDNew(track1, 1))) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track1, 0) || selectionPID(track1, 1))) { continue; } - if (!ispTdepPID && !(selectionPID(track1, 0) || selectionPID(track1, 1))) { + if (isTOFOnly && !(selectionPID2(track1, 0) || selectionPID2(track1, 1))) { continue; } + auto track1ID = track1.globalIndex(); for (auto track2 : negThisColl) { bool track2pion = false; bool track2kaon = false; @@ -383,73 +815,114 @@ 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 && !(selectionPIDNew(track2, 0) || selectionPIDNew(track2, 1))) { + 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 (!ispTdepPID && !(selectionPID(track2, 0) || selectionPID(track2, 1))) { + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) { continue; } if (track1.sign() * track2.sign() > 0) { continue; } - if (ispTdepPID) { + if (ispTdepPID && !isTOFOnly) { if (selectionPIDNew(track1, 1) && selectionPIDNew(track2, 0)) { track1pion = true; 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) { + 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; track1kaon = true; + if (removefaketrak && isFakeKaon(track1, 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()); - } - 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) { - 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; - histos.fill(HIST("hpTvsRapidity"), KstarMother.Pt(), KstarMother.Rapidity()); - if (TMath::Abs(KstarMother.Rapidity()) > confRapidity) { - 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; + } + } } - auto phiminuspsi = GetPhiInRange(KstarMother.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - histos.fill(HIST("hSparseV2SASameEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + if (same) { + if (track1kaon && track2pion) { + 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()); + } + 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) { + 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("hSparseV2SASameEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + } if (fillRotation) { for (int nrotbkg = 0; nrotbkg < nBkgRotations; nrotbkg++) { auto anglestart = confMinRot; @@ -471,109 +944,657 @@ struct kstarpbpb { continue; } kstarrot = kaonrot + daughter2; + if (TMath::Abs(kstarrot.Rapidity()) > confRapidity) { + continue; + } auto phiminuspsiRot = GetPhiInRange(kstarrot.Phi() - psiFT0C); - auto v2Rot = TMath::Cos(2.0 * phiminuspsiRot); + + 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", true); - void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + PROCESS_SWITCH(kstarpbpb, processSameEvent, "Process Same event", false); + + void processlikeEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) { - auto tracksTuple = std::make_tuple(tracks); - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisEPAngle}, true}; - SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; - for (auto& [collision1, tracks1, collision2, tracks2] : pair) { - if (!collision1.sel8() || !collision2.sel8()) { - continue; - } - if (!collision1.triggereventep() || !collision2.triggereventep()) { - 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 (!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; } - int occupancy = collision1.trackOccupancyInTimeRange(); - if (occupancy >= 1500) { - return; - } - 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)) { + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track1, 0) || selectionPIDNew(track1, 1))) { continue; } - if (additionalEvsel && !eventSelected(collision2, tracks.size(), centrality2)) { + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track1, 0) || selectionPID(track1, 1))) { continue; } - - for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (track1.sign() * track2.sign() > 0) { - continue; - } - if (!selectionTrack(track1) || !selectionTrack(track2)) { + 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 && !(selectionPIDNew(track1, 0) || selectionPIDNew(track1, 1))) { + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track2, 0) || selectionPIDNew(track2, 1))) { continue; } - if (ispTdepPID && !(selectionPIDNew(track2, 1) || selectionPIDNew(track2, 0))) { + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track2, 0) || selectionPID(track2, 1))) { continue; } - if (!ispTdepPID && !(selectionPID(track1, 0) || selectionPID(track1, 1))) { + if (isTOFOnly && !(selectionPID2(track2, 0) || selectionPID2(track2, 1))) { continue; } - if (!ispTdepPID && !(selectionPID(track2, 1) || selectionPID(track2, 0))) { + if (track1.sign() * track2.sign() < 0) { continue; } - if (ispTdepPID) { + if (ispTdepPID && !isTOFOnly) { if (selectionPIDNew(track1, 1) && selectionPIDNew(track2, 0)) { track1pion = true; 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) { + 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; 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 (track1kaon && track2pion) { - daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); - daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + 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); + + 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) { - daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPi); - daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); - } else { + 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); + 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); + } + } + } + } + } + + 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, axisOccup}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (auto& [collision1, tracks1, collision2, tracks2] : pair) { + if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(collision1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(collision2)) { + continue; + } + 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.bcId() == collision2.bcId()) { + continue; + } + 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(); + 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 (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 (!selectionTrack(track1) || !selectionTrack(track2)) { + + continue; + } + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track1, 0))) { + continue; + } + if (ispTdepPID && !isTOFOnly && !(selectionPIDNew(track2, 1))) { continue; } + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track1, 0))) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !(selectionPID(track2, 1))) { + continue; + } + 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); - auto v2 = TMath::Cos(2.0 * phiminuspsi); - histos.fill(HIST("hSparseV2SAMixedEvent_V2"), KstarMother.M(), KstarMother.Pt(), v2, centrality); + + 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); + 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 (usepolar) { + histos.fill(HIST("hSparseSAvsrapmix"), KstarMother.M(), KstarMother.Pt(), cosThetaStar, KstarMother.Rapidity(), centrality); + } else { + 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 (!selectionTrack(track2)) { + continue; + } + 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()); + } + } + } + } + // 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 (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 (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 + + } // 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; + } + + 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()); + } + } + } + } + // 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 84037f2dcad..b539b4c1d9e 100644 --- a/PWGLF/Tasks/Resonances/kstarqa.cxx +++ b/PWGLF/Tasks/Resonances/kstarqa.cxx @@ -8,34 +8,28 @@ // In applying this license CERN does 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 "TRandom3.h" -#include "Math/Vector3D.h" -#include "Math/Vector4D.h" -#include "Math/GenVector/Boost.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" +// #include +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" #include "CommonConstants/PhysicsConstants.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" @@ -43,839 +37,2968 @@ #include "Framework/HistogramRegistry.h" #include "Framework/StepTHn.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TRandom3.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; using std::array; +using namespace o2::aod::rctsel; -struct kstarqa { +struct Kstarqa { SliceCache cache; + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + RCTFlagsChecker rctChecker; + + struct : ConfigurableGroup { + // Configurables for event selections + Configurable isINELgt0{"isINELgt0", true, "INEL>0 selection"}; + Configurable isTriggerTVX{"isTriggerTVX", false, "TriggerTVX"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", false, "IsGoodZvtxFT0vsPV"}; + Configurable isApplyOccCut{"isApplyOccCut", true, "Apply occupancy cut"}; + Configurable isNoSameBunchPileup{"isNoSameBunchPileup", true, "kNoSameBunchPileup"}; + Configurable isGoodITSLayersAll{"isGoodITSLayersAll", true, "Require all ITS layers to be good"}; + Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", true, "kNoTimeFrameBorder"}; + Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", true, "kNoITSROFrameBorder"}; + // Configurable isApplyParticleMID{"isApplyParticleMID", true, "Apply particle misidentification"}; + Configurable checkVzEvSigLoss{"checkVzEvSigLoss", false, "Check Vz event signal loss"}; + Configurable isApplyDeepAngle{"isApplyDeepAngle", false, "Deep Angle cut"}; + Configurable isApplyMCchecksClosure{"isApplyMCchecksClosure", true, "Apply MC checks for closure test"}; + + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable configOccCut{"configOccCut", 1000., "Occupancy cut"}; + + // Configurables for track selections + Configurable cfgPVContributor{"cfgPVContributor", false, "PV contributor track selection"}; // PV Contriuibutor + Configurable cfgPrimaryTrack{"cfgPrimaryTrack", false, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable isGlobalTracks{"isGlobalTracks", true, "isGlobalTracks"}; + + 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 cfgCutEtaMax{"cfgCutEtaMax", 0.8f, "Eta cut on daughter track"}; + // Configurable cfgCutEtaMin{"cfgCutEtaMin", 0.0f, "Eta cut on daughter track"}; + Configurable cfgCutDCAxyMax{"cfgCutDCAxyMax", 2.0f, "DCAxy range for tracks"}; + // Configurable cfgCutDCAxyMin{"cfgCutDCAxyMin", 0.0f, "DCAxy range for tracks"}; + Configurable cfgCutDCAz{"cfgCutDCAz", 2.0f, "DCAz range for tracks"}; + Configurable ctrackRapidity{"ctrackRapidity", 0.3f, "Cut on track rapidity"}; + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; + 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 cfgTPCChi2NClMax{"cfgTPCChi2NClMax", 4.0, "TPC Chi2/NCl"}; + Configurable cfgTPCChi2NClMin{"cfgTPCChi2NClMin", 0.0, "TPC Chi2/NCl"}; + Configurable cfgUseITSTPCRefit{"cfgUseITSTPCRefit", false, "Require ITS Refit"}; + Configurable isVertexITSTPC{"isVertexITSTPC", false, "Vertex ITS TPC"}; + Configurable isVertexTOFMatched{"isVertexTOFMatched", false, "Vertex TOF Matched"}; + Configurable isNoCollInTimeRangeStandard{"isNoCollInTimeRangeStandard", false, "No collision in time range standard"}; + Configurable isApplyPtDepDCAxyCut{"isApplyPtDepDCAxyCut", false, "Apply pT dependent DCAxy cut"}; + Configurable isGoldenChi2{"isGoldenChi2", false, "Apply golden chi2 cut"}; + Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; + + // cuts on mother + // Configurable isApplyCutsOnMother{"isApplyCutsOnMother", false, "Enable additional cuts on Kstar mother"}; + // Configurable cMaxPtMotherCut{"cMaxPtMotherCut", 15.0, "Maximum pt of mother cut"}; + // Configurable cMaxMinvMotherCut{"cMaxMinvMotherCut", 1.5, "Maximum mass of mother cut"}; + Configurable rapidityMotherData{"rapidityMotherData", 0.5, "Maximum rapidity of mother"}; + Configurable isPDGCheckMC{"isPDGCheckMC", true, "Check PDG code in MC (false for MC closure test)"}; + + // 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 nsigmaCutCombinedKa{"nsigmaCutCombinedKa", 3.0, "Combined Nsigma cut for kaon"}; + Configurable nsigmaCutCombinedPi{"nsigmaCutCombinedPi", 3.0, "Combined Nsigma cut for pion"}; + /* Configurable nsigmaCutCombinedMIDKa{"nsigmaCutCombinedMIDKa", 3.0, "Combined Nsigma cut for kaon in MID"}; + Configurable nsigmaCutCombinedMIDPi{"nsigmaCutCombinedMIDPi", 3.0, "Combined Nsigma cut for pion in MID"}; + Configurable nsigmaCutTPCMIDPi{"nsigmaCutTPCMIDPi", 1.0, "MID Nsigma cut for pion in TPC"}; + Configurable nsigmaCutTPCMIDKa{"nsigmaCutTPCMIDKa", 1.0, "MID Nsigma cut for kaon in TPC"}; + Configurable nsigmaCutTOFMIDPi{"nsigmaCutTOFMIDPi", 1.0, "MID Nsigma cut for pion in TOF"}; + Configurable nsigmaCutTOFMIDKa{"nsigmaCutTOFMIDKa", 1.0, "MID Nsigma cut for kaon in TOF"}; + Configurable nsigmaCutTPCMIDPr{"nsigmaCutTPCMIDPr", 3.0, "TPC Nsigma cut for protons (for MID)"}; + Configurable nsigmaCutTOFMIDPr{"nsigmaCutTOFMIDPr", 3.0, "TOF Nsigma cut for protons (for MID)"}; */ + + // Other fixed variables + float lowPtCutPID = 0.5; + int noOfDaughters = 2; + // float rapidityMotherData = 0.5; + + } selectionConfig; + + enum MultEstimator { + kFT0M, + kFT0A, + kFT0C, + kFV0A, + kFV0C, + kFV0M, + kNEstimators // useful if you want to iterate or size things + }; + + enum PIDParticle { + kPion, + kKaon, + kProton + }; + // 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 QAevents{"QAevents", true, "Multiplicity dist, DCAxy, DCAz"}; + Configurable calcLikeSign{"calcLikeSign", true, "Calculate Like Sign"}; + Configurable calcRotational{"calcRotational", false, "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"}; + Configurable cRotations{"cRotations", 3, "Number of random rotations in the rotational background"}; + Configurable cSelectMultEstimator{"cSelectMultEstimator", 0, "Select multiplicity estimator: 0 - FT0M, 1 - FT0A, 2 - FT0C, 3 - FV0A"}; + Configurable applyRecMotherRapidity{"applyRecMotherRapidity", true, "Apply rapidity cut on reconstructed mother track"}; + Configurable applypTdepPID{"applypTdepPID", false, "Apply pT dependent PID"}; - // 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 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 ismanualDCAcut{"ismanualDCAcut", true, "ismanualDCAcut"}; - Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; - Configurable cfgTPCcluster{"cfgTPCcluster", 120, "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 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 - - // Event selection configurables - Configurable timFrameEvsel{"timFrameEvsel", false, "TPC Time frame boundary cut"}; - Configurable TVXEvsel{"TVXEvsel", false, "Triggger selection"}; - Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; - Configurable MID{"MID", false, "Misidentification of tracks"}; + // Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", false, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cBetaCutTOF{"cBetaCutTOF", 0.0, "cut TOF beta"}; + Configurable cFakeTrack{"cFakeTrack", true, "Fake track selection"}; + 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 for histograms - Configurable nBins{"nBins", 100, "N bins in all histos"}; - Configurable nBinsinvMass{"nBinsinvMass", 180, "N bins in invMass histos"}; - 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 pTbinlow{"pTbinlow", 0.0, "pT bin low"}; - Configurable pTbinhigh{"pTbinhigh", 20.0, "pT bin high"}; - ConfigurableAxis binsMultPlot{"binsCent", {201, -0.5f, 200.5f}, "Binning of the centrality axis for plots"}; Configurable avoidsplitrackMC{"avoidsplitrackMC", true, "avoid split track in MC"}; - Configurable AllGenCollisions{"AllGenCollisions", true, "To fill all generated collisions for the signal loss calculations"}; - ConfigurableAxis axisdEdx{"axisdEdx", {20000, 0.0f, 200.0f}, "dE/dx (a.u.)"}; - ConfigurableAxis axisPtfordEbydx{"axisPtfordEbydx", {2000, 0, 20}, "pT (GeV/c)"}; + Configurable cAllGenCollisions{"cAllGenCollisions", false, "To fill all generated collisions for the signal loss calculations"}; + ConfigurableAxis binsMultPlot{"binsMultPlot", {110, 0.0, 110}, "THnSpare multiplicity axis"}; + 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"}; + ConfigurableAxis configThnAxisPOL{"configThnAxisPOL", {20, -1.0, 1.0}, "Costheta axis"}; + ConfigurableAxis invMassKstarAxis{"invMassKstarAxis", {300, 0.7f, 1.3f}, "Kstar invariant mass axis"}; + ConfigurableAxis ptAxisKstar{"ptAxisKstar", {200, 0.0f, 20.0f}, "Kstar pT axis"}; + ConfigurableAxis binsImpactPar{"binsImpactPar", {100, 0, 25}, "Binning of the impact parameter axis"}; // Event plane configurables - Configurable boost_daugter1{"boost_daugter1", false, "Boost daughter Kaon in the COM frame"}; - Configurable boost_daugter2{"boost_daugter2", true, "Boost daughter Pion in the COM frame"}; + 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 c_nof_rotations{"c_nof_rotations", 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&) { + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); // Axes - 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 vertexZAxis = {60, -15., 15., "vrtx_{Z} [cm] for plots"}; + AxisSpec ptAxis = {ptAxisKstar, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec invmassAxis = {invMassKstarAxis, "Invariant mass (GeV/#it{c}^{2})"}; AxisSpec thnAxisPOL{configThnAxisPOL, "cos(#theta)"}; + AxisSpec multiplicityAxis = {binsMultPlot, "Multiplicity Axis"}; + AxisSpec impactParAxis = {binsImpactPar, "Impact Parameter (cm)"}; // Histograms // Event selection rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); - rEventSelection.add("hmult", "Multiplicity percentile", kTH1F, {{binsMultPlot}}); - - // for primary tracks - if (QAbefore && QAafter) { - histos.add("hNsigmaTPC_before", "NsigmaKaon TPC distribution before", kTH2F, {{100, 0.0f, 10.0f}, {200, -10.0f, 10.0f}}); - histos.add("hNsigmaTOF_before", "NsigmaKaon TOF distribution before", kTH2F, {{100, 0.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}); - histos.add("hphi", "Phi distribution", kTH1F, {{65, 0, 6.5}}); + rEventSelection.add("hMultiplicity", "Multiplicity percentile", kTH1F, {{110, 0, 110}}); + + rEventSelection.add("hEventCut", "No. of event after cuts", kTH1D, {{20, 0, 20}}); + std::shared_ptr hCutFlow = rEventSelection.get(HIST("hEventCut")); + + auto check = [](bool enabled) { return enabled ? "" : " #otimes"; }; // check if a cut is enabled and put #otimes beside that label if not enabled + + std::vector eveCutLabels = { + "All Events", + Form("|Vz| < %.1f", selectionConfig.cutzvertex.value), + "sel8", + std::string("kNoTimeFrameBorder") + check(selectionConfig.isNoTimeFrameBorder.value), + std::string("kNoITSROFrameBorder") + check(selectionConfig.isNoITSROFrameBorder.value), + std::string("kNoSameBunchPileup") + check(selectionConfig.isNoSameBunchPileup.value), + std::string("kIsGoodITSLayersAll") + check(selectionConfig.isGoodITSLayersAll.value), + std::string("kNoCollInTimeRangeStandard") + check(selectionConfig.isNoCollInTimeRangeStandard.value), + Form("Occupancy < %.0f%s", selectionConfig.configOccCut.value, check(selectionConfig.isApplyOccCut.value)), + std::string("rctChecker") + check(rctCut.requireRCTFlagChecker.value), + std::string("kIsTriggerTVX") + check(selectionConfig.isTriggerTVX.value), + std::string("kIsGoodZvtxFT0vsPV") + check(selectionConfig.isGoodZvtxFT0vsPV.value), + std::string("IsINELgt0") + check(selectionConfig.isINELgt0.value), + std::string("isVertexITSTPC") + check(selectionConfig.isVertexITSTPC.value), + std::string("isVertexTOFMatched") + check(selectionConfig.isVertexTOFMatched.value)}; + // assign labels + for (size_t i = 0; i < eveCutLabels.size(); ++i) { + hCutFlow->GetXaxis()->SetBinLabel(i + 1, eveCutLabels[i].c_str()); + } - 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}}); + // for primary tracksbinsMultPlot + 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}}); + + hOthers.add("hKstar_rap_pt", "Pair rapidity distribution; y; p_{T}; Counts", kTH2F, {{400, -2.0f, 2.0f}, ptAxis}); + hOthers.add("hKstar_eta_pt", "Pair eta distribution; #eta; p_{T}; Counts", kTH2F, {{400, -2.0f, 2.0f}, ptAxis}); + + hPID.add("Before/hNsigmaTPC_Ka_before", "N #sigma Kaon TPC before", kTH2F, {{50, 0.0f, 10.0f}, {100, -10.0f, 10.0f}}); + hPID.add("Before/hNsigmaTOF_Ka_before", "N #sigma Kaon TOF before", kTH2F, {{50, 0.0f, 10.0f}, {100, -10.0f, 10.0f}}); + hPID.add("Before/hNsigmaTPC_Pi_before", "N #sigma Pion TPC before", kTH2F, {{50, 0.0f, 10.0f}, {100, -10.0f, 10.0f}}); + hPID.add("Before/hNsigmaTOF_Pi_before", "N #sigma Pion TOF before", kTH2F, {{50, 0.0f, 10.0f}, {100, -10.0f, 10.0f}}); + hPID.add("Before/hNsigma_TPC_TOF_Ka_before", "N #sigma Kaon TOF before", kTH2F, {{50, -5.0f, 5.0f}, {50, -5.0f, 5.0f}}); + hPID.add("Before/hNsigma_TPC_TOF_Pi_before", "N #sigma Pion TOF before", kTH2F, {{50, -5.0f, 5.0f}, {50, -5.0f, 5.0f}}); + + hPID.add("Before/h1PID_TPC_pos_kaon", "Kaon PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("Before/h1PID_TPC_pos_pion", "Pion PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("Before/h1PID_TOF_pos_kaon", "Kaon PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("Before/h1PID_TOF_pos_pion", "Pion PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("Before/h1PID_TPC_neg_kaon", "Kaon PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("Before/h1PID_TPC_neg_pion", "Pion PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("Before/h1PID_TOF_neg_kaon", "Kaon PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + hPID.add("Before/h1PID_TOF_neg_pion", "Pion PID distribution in data", kTH1F, {{100, -10.0f, 10.0f}}); + + hPID.add("Before/hTPCnsigKa_mult_pt", "TPC nsigma of Kaon brfore PID with pt and multiplicity", kTH3F, {{100, -10.0f, 10.0f}, multiplicityAxis, ptAxis}); + hPID.add("Before/hTPCnsigPi_mult_pt", "TPC nsigma of Pion brfore PID with pt and multiplicity", kTH3F, {{100, -10.0f, 10.0f}, multiplicityAxis, ptAxis}); + hPID.add("Before/hTOFnsigKa_mult_pt", "TOF nsigma of Kaon brfore PID with pt and multiplicity", kTH3F, {{100, -10.0f, 10.0f}, multiplicityAxis, ptAxis}); + hPID.add("Before/hTOFnsigPi_mult_pt", "TOF nsigma of Pion brfore PID with pt and multiplicity", kTH3F, {{100, -10.0f, 10.0f}, multiplicityAxis, ptAxis}); + + hPID.add("After/hNsigmaPionTPC_after", "N #Pi TPC after", kTH2F, {{50, 0.0f, 10.0f}, {100, -10.0f, 10.0f}}); + hPID.add("After/hNsigmaPionTOF_after", "N #Pi TOF after", kTH2F, {{50, 0.0f, 10.0f}, {100, -10.0f, 10.0f}}); + hPID.add("After/hNsigmaKaonTPC_after", "N #sigma Kaon TPC after", kTH2F, {{50, 0.0f, 10.0f}, {100, -10.0f, 10.0f}}); + hPID.add("After/hNsigmaKaonTOF_after", "N #sigma Kaon TOF after", kTH2F, {{50, 0.0f, 10.0f}, {100, -10.0f, 10.0f}}); + hPID.add("After/hNsigma_TPC_TOF_Ka_after", "N #sigma Kaon TOF after", kTH2F, {{50, -5.0f, 5.0f}, {50, -5.0f, 5.0f}}); + hPID.add("After/hNsigma_TPC_TOF_Pi_after", "N #sigma Pion TOF after", kTH2F, {{50, -5.0f, 5.0f}, {50, -5.0f, 5.0f}}); + + hPID.add("After/hDcaxyPi", "Dcaxy distribution of selected Pions", kTH1F, {{200, -1.0f, 1.0f}}); + hPID.add("After/hDcaxyKa", "Dcaxy distribution of selected Kaons", kTH1F, {{200, -1.0f, 1.0f}}); + hPID.add("After/hDcazPi", "Dcaz distribution of selected Pions", kTH1F, {{200, -1.0f, 1.0f}}); + hPID.add("After/hDcazKa", "Dcaz distribution of selected Kaons", kTH1F, {{200, -1.0f, 1.0f}}); + + hPID.add("After/hTPCnsigKa_mult_pt", "TPC nsigma of Kaon after PID with pt and multiplicity", kTH3F, {{100, -10.0f, 10.0f}, multiplicityAxis, ptAxis}); + hPID.add("After/hTPCnsigPi_mult_pt", "TPC nsigma of Pion after PID with pt and multiplicity", kTH3F, {{100, -10.0f, 10.0f}, multiplicityAxis, ptAxis}); + hPID.add("After/hTOFnsigKa_mult_pt", "TOF nsigma of Kaon after PID with pt and multiplicity", kTH3F, {{100, -10.0f, 10.0f}, multiplicityAxis, ptAxis}); + hPID.add("After/hTOFnsigPi_mult_pt", "TOF nsigma of Pion after PID with pt and multiplicity", kTH3F, {{100, -10.0f, 10.0f}, multiplicityAxis, ptAxis}); } // KStar histograms - histos.add("h3KstarInvMassUnlikeSign", "kstar Unlike Sign", kTHnSparseF, {binsMultPlot, ptAxis, invmassAxis, thnAxisPOL}, true); - histos.add("h3KstarInvMasslikeSign", "kstar like Sign", kTHnSparseF, {binsMultPlot, ptAxis, invmassAxis, thnAxisPOL}, true); - histos.add("h3KstarInvMassRotated", "kstar rotated", kTHnSparseF, {binsMultPlot, ptAxis, invmassAxis, thnAxisPOL}, true); - histos.add("h3KstarInvMassMixed", "kstar Mixed", kTHnSparseF, {binsMultPlot, ptAxis, invmassAxis, thnAxisPOL}, true); - - // 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}); - // Reconstructed MC histogram - histos.add("h3KstarRec", "pT of reconstructed kstar", kTH1F, {ptAxis}); - histos.add("h1KstarRecMass", "Invariant mass of kstar meson", kTH1D, {invmassAxis}); - histos.add("h1KstarRecpt", "pT of kstar meson", kTH1F, {ptAxis}); - histos.add("h1genmass", "Invariant mass of generated kstar meson", kTH1D, {invmassAxis}); - histos.add("h1recpt", "pT of generated kstar meson", kTH1F, {ptAxis}); - histos.add("events_check_data", "No. of events in the data", kTH1I, {{20, 0, 20}}); - histos.add("events_check", "No. of events in the generated MC", kTH1I, {{20, 0, 20}}); - histos.add("events_checkrec", "No. of events in the reconstructed MC", kTH1I, {{20, 0, 20}}); - histos.add("h1KSRecsplit", "KS meson Rec split", kTH1F, {{100, 0.0f, 10.0f}}); + hInvMass.add("h3KstarInvMassUnlikeSign", "kstar Unlike Sign", kTHnSparseF, {multiplicityAxis, ptAxis, invmassAxis, thnAxisPOL}); + hInvMass.add("h3KstarInvMassMixed", "kstar Mixed", kTHnSparseF, {multiplicityAxis, ptAxis, invmassAxis, thnAxisPOL}); + if (calcLikeSign) { + hInvMass.add("h3KstarInvMasslikeSignPP", "kstar like Sign", kTHnSparseF, {multiplicityAxis, ptAxis, invmassAxis, thnAxisPOL}); + hInvMass.add("h3KstarInvMasslikeSignMM", "kstar like Sign", kTHnSparseF, {multiplicityAxis, ptAxis, invmassAxis, thnAxisPOL}); + } + if (calcRotational) + hInvMass.add("h3KstarInvMassRotated", "kstar rotated", kTHnSparseF, {multiplicityAxis, ptAxis, invmassAxis, thnAxisPOL}); + + // MC histograms + hInvMass.add("hk892GenpT", "pT distribution of True MC K(892)0", kTHnSparseF, {ptAxis, multiplicityAxis}); + hInvMass.add("hk892GenpT2", "pT distribution of True MC K(892)0", kTHnSparseF, {ptAxis, multiplicityAxis}); + hInvMass.add("hk892GenpTCalib1", "pT distribution of True MC K(892)0", kTHnSparseF, {ptAxis, multiplicityAxis}); + hInvMass.add("hk892GenpTCalib2", "pT distribution of True MC K(892)0", kTHnSparseF, {ptAxis, multiplicityAxis}); + hInvMass.add("h1KstarRecMass", "Invariant mass of kstar meson", kTH1F, {invmassAxis}); + hInvMass.add("h2KstarRecpt1", "pT of kstar meson", kTHnSparseF, {ptAxis, multiplicityAxis, invmassAxis}); + hInvMass.add("h2KstarRecpt2", "pT of kstar meson", kTHnSparseF, {ptAxis, multiplicityAxis, invmassAxis}); + hInvMass.add("h2KstarRecptCalib1", "pT of kstar meson", kTHnSparseF, {ptAxis, multiplicityAxis, invmassAxis}); + hInvMass.add("h2KstarRecptCalib2", "pT of kstar meson", kTHnSparseF, {ptAxis, multiplicityAxis, invmassAxis}); + hInvMass.add("h1genmass", "Invariant mass of generated kstar meson", kTH1F, {invmassAxis}); + hInvMass.add("h1GenMult", "Multiplicity generated", kTH1F, {multiplicityAxis}); + hInvMass.add("h1GenMult2", "Multiplicity generated (direct)", kTH1F, {multiplicityAxis}); + hInvMass.add("h1RecMult", "Multiplicity reconstructed", kTH1F, {multiplicityAxis}); + hInvMass.add("h1RecMult2", "Multiplicity reconstructed", kTH1F, {multiplicityAxis}); + hInvMass.add("h1KSRecsplit", "KS meson Rec split", kTH1F, {{100, 0.0f, 10.0f}}); + // hInvMass.add("hAllGenCollisionsImpact", "All generated collisions vs impact parameter", kTH1F, {multiplicityAxis}); + hInvMass.add("hAllGenCollisions", "All generated events", kTH1F, {multiplicityAxis}); + hInvMass.add("hAllGenCollisions1Rec", "All gen events with at least one rec event", kTH1F, {multiplicityAxis}); + hInvMass.add("hAllKstarGenCollisisons", "All generated Kstar in events with rapidity in 0.5", kTH2F, {{multiplicityAxis}, {ptAxis}}); + hInvMass.add("hAllKstarGenCollisisons1Rec", "All generated Kstar in events with at least one rec event in rapidity in 0.5", kTH2F, {{multiplicityAxis}, {ptAxis}}); + hInvMass.add("hAllRecCollisions", "All reconstructed events", kTH1F, {multiplicityAxis}); + hInvMass.add("hAllRecCollisionsCalib", "All reconstructed events", kTH1F, {multiplicityAxis}); + + if (doprocessEvtLossSigLossMC || doprocessEvtLossSigLossMCPhi) { + hInvMass.add("MCcorrections/hSignalLossDenominator", "Kstar generated before event selection", kTH2F, {{ptAxis}, {multiplicityAxis}}); + hInvMass.add("MCcorrections/hSignalLossNumerator", "Kstar generated after event selection", kTH2F, {{ptAxis}, {multiplicityAxis}}); + hInvMass.add("MCcorrections/hImpactParameterRec", "Impact parameter in reconstructed MC", kTH1F, {impactParAxis}); + hInvMass.add("MCcorrections/MultiplicityRec", "Multiplicity in generated MC with at least 1 reconstruction", kTH1F, {multiplicityAxis}); + hInvMass.add("MCcorrections/MultiplicityRec2", "Multiplicity in reconstructed MC", kTH1F, {multiplicityAxis}); + hInvMass.add("MCcorrections/hImpactParameterGen", "Impact parameter in generated MC", kTH1F, {impactParAxis}); + hInvMass.add("MCcorrections/MultiplicityGen", "Multiplicity in generated MC", kTH1F, {multiplicityAxis}); + hInvMass.add("MCcorrections/hImpactParametervsMultiplicity", "Impact parameter vs multiplicity in reconstructed MC", kTH2F, {{impactParAxis}, {multiplicityAxis}}); + } + + // Signal Loss & Event Loss in Light Ion Collisions + if (doprocessEvtLossSigLossLightIonMC) { + hInvMass.add("MCcorrections/hImpactParameterGen", "Impact parameter of generated MC events", kTH1F, {impactParAxis}); + hInvMass.add("MCcorrections/hImpactParameterRec", "Impact parameter of selected MC events", kTH1F, {impactParAxis}); + hInvMass.add("MCcorrections/hImpactParvsCentrRec", "Impact parameter of selected MC events vs centrality", kTH2F, {{multiplicityAxis}, impactParAxis}); + hInvMass.add("MCcorrections/hKstarGenBeforeEvtSel", "K*0 before event selections", kTH2F, {ptAxis, impactParAxis}); + hInvMass.add("MCcorrections/hKstarGenAfterEvtSel", "K*0 after event selections", kTH2F, {ptAxis, impactParAxis}); + } + + rEventSelection.add("tracksCheckData", "No. of events in the data", kTH1I, {{10, 0, 10}}); + rEventSelection.add("eventsCheckGen", "No. of events in the generated MC", kTH1I, {{10, 0, 10}}); + rEventSelection.add("recMCparticles", "No. of events in the reconstructed MC", kTH1I, {{20, 0, 20}}); + rEventSelection.add("hOccupancy", "Occupancy distribution", kTH1F, {{1000, 0, 15000}}); + + std::shared_ptr hrecLabel = rEventSelection.get(HIST("recMCparticles")); + hrecLabel->GetXaxis()->SetBinLabel(1, "All tracks"); + hrecLabel->GetXaxis()->SetBinLabel(2, "has_MC"); + hrecLabel->GetXaxis()->SetBinLabel(3, "Track selection"); + hrecLabel->GetXaxis()->SetBinLabel(4, "StrictlyUpperIndex"); + hrecLabel->GetXaxis()->SetBinLabel(5, "Unlike Sign"); + hrecLabel->GetXaxis()->SetBinLabel(6, "Physical Primary"); + hrecLabel->GetXaxis()->SetBinLabel(7, "TrackPDG Check1"); + hrecLabel->GetXaxis()->SetBinLabel(8, "TrackPDG Check2"); + hrecLabel->GetXaxis()->SetBinLabel(9, "Global Index"); + hrecLabel->GetXaxis()->SetBinLabel(10, "Generator"); + hrecLabel->GetXaxis()->SetBinLabel(11, "Mother y"); + hrecLabel->GetXaxis()->SetBinLabel(12, "Mother PDG"); + hrecLabel->GetXaxis()->SetBinLabel(13, "Track PID"); + hrecLabel->GetXaxis()->SetBinLabel(14, "Track MID"); + hrecLabel->GetXaxis()->SetBinLabel(15, "Track y"); + hrecLabel->GetXaxis()->SetBinLabel(16, "Split tracks"); + hrecLabel->GetXaxis()->SetBinLabel(17, "DeepAngle Cut"); + + std::shared_ptr hDataTracks = rEventSelection.get(HIST("tracksCheckData")); + hDataTracks->GetXaxis()->SetBinLabel(1, "All tracks"); + hDataTracks->GetXaxis()->SetBinLabel(2, "Track selection"); + hDataTracks->GetXaxis()->SetBinLabel(3, "PID Cut"); + hDataTracks->GetXaxis()->SetBinLabel(4, "Remove Fake Tracks"); + hDataTracks->GetXaxis()->SetBinLabel(5, "Rapidity Cut"); + hDataTracks->GetXaxis()->SetBinLabel(6, "MID"); + hDataTracks->GetXaxis()->SetBinLabel(7, "DeepAngle Cut"); + + std::shared_ptr hGenTracks = rEventSelection.get(HIST("eventsCheckGen")); + hGenTracks->GetXaxis()->SetBinLabel(1, "All events"); + hGenTracks->GetXaxis()->SetBinLabel(2, "INELgt0+vtz"); + hGenTracks->GetXaxis()->SetBinLabel(3, "INELgt0"); + hGenTracks->GetXaxis()->SetBinLabel(4, "Event Reconstructed"); // Multplicity distribution - if (QAevents) { - histos.add("multdist_FT0M", "FT0M Multiplicity distribution", kTH1F, {{2000, 0, 20000}}); - histos.add("multdist_FT0A", "FT0A Multiplicity distribution", kTH1F, {{2000, 0, 20000}}); - histos.add("multdist_FT0C", "FT0C Multiplicity distribution", kTH1F, {{2000, 0, 20000}}); - histos.add("hNcontributor", "Number of primary vertex contributor", kTH1F, {{2000, 0.0f, 10000.0f}}); - histos.add("hDcaxy", "Dcaxy distribution", kTH1F, {{200, -1.0f, 1.0f}}); - histos.add("hDcaz", "Dcaz distribution", kTH1F, {{200, -1.0f, 1.0f}}); + 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_cent_pt", "Dcaxy distribution", kTH3F, {{200, -1.0f, 1.0f}, multiplicityAxis, ptAxis}); + rEventSelection.add("hDcaz_cent_pt", "Dcaz distribution", kTH3F, {{200, -1.0f, 1.0f}, multiplicityAxis, ptAxis}); } } - 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; - ROOT::Math::PtEtaPhiMVector CKSVectorRot1; - ROOT::Math::PtEtaPhiMVector CKSVectorRot2; + + template + bool selectionEvent(const Coll& collision, bool fillHist = false) // default to false + { + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 0); + + if (std::abs(collision.posZ()) > selectionConfig.cutzvertex) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 1); + + if (!collision.sel8()) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 2); + + if (selectionConfig.isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 3); + + if (selectionConfig.isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 4); + + if (selectionConfig.isNoSameBunchPileup && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup))) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 5); + + if (selectionConfig.isGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 6); + + if (selectionConfig.isNoCollInTimeRangeStandard && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 7); + + if (selectionConfig.isApplyOccCut && (std::abs(collision.trackOccupancyInTimeRange()) > selectionConfig.configOccCut)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 8); + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 9); + + if (selectionConfig.isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 10); + + if (selectionConfig.isGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 11); + + if (selectionConfig.isINELgt0 && !collision.isInelGt0()) { + return false; + } + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 12); + + if (selectionConfig.isVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 13); + + if (selectionConfig.isVertexTOFMatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHist) + rEventSelection.fill(HIST("hEventCut"), 14); + + return true; + } template bool selectionTrack(const T& candidate) { - if (ismanualDCAcut && !(candidate.isGlobalTrackWoDCA() && candidate.isPVContributor() && std::abs(candidate.dcaXY()) < cfgCutDCAxy && std::abs(candidate.dcaZ()) < cfgCutDCAz && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster)) { - return false; - } else if (!ismanualDCAcut) { - if (std::abs(candidate.pt()) < cfgCutPT) + if (selectionConfig.isGlobalTracks) { + if (!candidate.isGlobalTrackWoDCA()) + return false; + if (std::abs(candidate.pt()) < selectionConfig.cfgCutPT) + return false; + // if (std::abs(candidate.eta()) > selectionConfig.cfgCutEtaMax || std::abs(candidate.eta()) < selectionConfig.cfgCutEtaMin) + if (std::abs(candidate.eta()) > selectionConfig.cfgCutEtaMax) + return false; + if (!selectionConfig.isApplyPtDepDCAxyCut) { + // if (std::abs(candidate.dcaXY()) > selectionConfig.cfgCutDCAxyMax || std::abs(candidate.dcaXY()) < selectionConfig.cfgCutDCAxyMin) + if (std::abs(candidate.dcaXY()) > selectionConfig.cfgCutDCAxyMax) + return false; + } else { + if (std::abs(candidate.dcaXY()) > (0.0105 + 0.035 / std::pow(candidate.pt(), 1.1))) + return false; + } + if (selectionConfig.isGoldenChi2 && !candidate.passedGoldenChi2()) + return false; + if (std::abs(candidate.dcaZ()) > selectionConfig.cfgCutDCAz) + return false; + if (candidate.tpcCrossedRowsOverFindableCls() < selectionConfig.cfgRCRFC) + return false; + if (candidate.itsNCls() < selectionConfig.cfgITScluster) + return false; + if (candidate.tpcNClsFound() < selectionConfig.cfgTPCcluster) + return false; + if (candidate.itsChi2NCl() >= selectionConfig.cfgITSChi2NCl) + return false; + if (candidate.tpcChi2NCl() >= selectionConfig.cfgTPCChi2NClMax || candidate.tpcChi2NCl() < selectionConfig.cfgTPCChi2NClMin) + return false; + if (selectionConfig.cfgPVContributor && !candidate.isPVContributor()) + return false; + if (selectionConfig.cfgUseITSTPCRefit && (!(o2::aod::track::ITSrefit) || !(o2::aod::track::TPCrefit))) return false; - if (std::abs(candidate.dcaXY()) > cfgCutDCAxy) + } else if (!selectionConfig.isGlobalTracks) { + if (std::abs(candidate.pt()) < selectionConfig.cfgCutPT) return false; - if (std::abs(candidate.dcaZ()) > cfgCutDCAz) + // if (std::abs(candidate.eta()) > selectionConfig.cfgCutEtaMax || std::abs(candidate.eta()) < selectionConfig.cfgCutEtaMin) + if (std::abs(candidate.eta()) > selectionConfig.cfgCutEtaMax) return false; - if (candidate.tpcCrossedRowsOverFindableCls() < cfgRCRFC) + // if (std::abs(candidate.dcaXY()) > selectionConfig.cfgCutDCAxyMax || std::abs(candidate.dcaXY()) < selectionConfig.cfgCutDCAxyMin) + if (std::abs(candidate.dcaXY()) > selectionConfig.cfgCutDCAxyMax) return false; - if (candidate.itsNCls() < cfgITScluster) + if (std::abs(candidate.dcaZ()) > selectionConfig.cfgCutDCAz) return false; - if (candidate.tpcNClsFound() < cfgTPCcluster) + if (candidate.tpcCrossedRowsOverFindableCls() < selectionConfig.cfgRCRFC) return false; - if (candidate.itsChi2NCl() >= cfgITSChi2NCl) + if (candidate.itsNCls() < selectionConfig.cfgITScluster) return false; - if (candidate.tpcChi2NCl() >= cfgTPCChi2NCl) + if (candidate.tpcNClsFound() < selectionConfig.cfgTPCcluster) return false; - if (cfgPVContributor && !candidate.isPVContributor()) + if (candidate.itsChi2NCl() >= selectionConfig.cfgITSChi2NCl) return false; - // if (cfgPrimaryTrack && !candidate.isPrimaryTrack()) - // return false; - if (cfgGlobalWoDCATrack && !candidate.isGlobalTrackWoDCA()) + if (candidate.tpcChi2NCl() >= selectionConfig.cfgTPCChi2NClMax || candidate.tpcChi2NCl() < selectionConfig.cfgTPCChi2NClMin) return false; - if (cfgGlobalTrack && !candidate.isGlobalTrack()) + if (selectionConfig.cfgPVContributor && !candidate.isPVContributor()) return false; + if (selectionConfig.cfgPrimaryTrack && !candidate.isPrimaryTrack()) + return false; + } + + return true; + } + + template + bool isFakeTrack(const T& track, int PID) + { + 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; + } + // 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 = std::acos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + if (selectionConfig.isApplyDeepAngle && angle < selectionConfig.cfgDeepAngle) { + return false; + } return true; } template bool selectionPID(const T& candidate, int PID) { - if (PID == 0) { + if (PID == PIDParticle::kPion) { if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOFPi) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < selectionConfig.nsigmaCutTOFPi && candidate.beta() > cBetaCutTOF) { return true; } } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOFPi) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < selectionConfig.nsigmaCutTOFPi && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi) { return true; } } else if (onlyTPC) { - if (std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { + if (std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi) { return true; } } else { - if (candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < (selectionConfig.nsigmaCutCombinedPi * selectionConfig.nsigmaCutCombinedPi) && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPCPi) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi) { return true; } } - } else if (PID == 1) { + } else if (PID == PIDParticle::kKaon) { if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < nsigmaCutTOFKa) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < selectionConfig.nsigmaCutTOFKa && candidate.beta() > cBetaCutTOF) { return true; } } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < nsigmaCutTOFKa) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < selectionConfig.nsigmaCutTOFKa && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa) { return true; } } else if (onlyTPC) { - if (std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { + if (std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa) { return true; } } else { - if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (nsigmaCutCombined * nsigmaCutCombined)) { + if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (selectionConfig.nsigmaCutCombinedKa * selectionConfig.nsigmaCutCombinedKa) && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa) { return true; } } } + /* else if (PID == PIDParticle::kProton) { // for proton + if (onlyTOF) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < selectionConfig.nsigmaCutTOFPr && candidate.beta() > cBetaCutTOF) { + return true; + } + } else if (onlyTOFHIT) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < selectionConfig.nsigmaCutTOFPr && candidate.beta() > cBetaCutTOF) { + return true; + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr) { + return true; + } + } else if (onlyTPC) { + if (std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr) { + return true; + } + } else { + if (candidate.hasTOF() && (candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < (selectionConfig.nsigmaCutTOFPr * selectionConfig.nsigmaCutTOFPr) && candidate.beta() > cBetaCutTOF) { + return true; + } + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr) { + return true; + } + } + } */ return false; } - template - bool MIDselectionPID(const T& candidate, int PID) + /* template + bool selectionMID(const T& candidate, int PID) { - if (PID == 0) { + if (PID == PIDParticle::kPion) { if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < selectionConfig.nsigmaCutTOFMIDPi && candidate.beta() > cBetaCutTOF) { return true; } } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < selectionConfig.nsigmaCutTOFMIDPi && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaPi()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCMIDPi) { return true; } } else if (onlyTPC) { - if (std::abs(candidate.tpcNSigmaPi()) < 3.0) { + if (std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCMIDPi) { return true; } } else { - 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()) < (selectionConfig.nsigmaCutCombinedMIDPi * selectionConfig.nsigmaCutCombinedMIDPi) && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCMIDPi) { return true; } } - } else if (PID == 1) { + } else if (PID == PIDParticle::kKaon) { if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < selectionConfig.nsigmaCutTOFMIDKa && candidate.beta() > cBetaCutTOF) { return true; } } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < selectionConfig.nsigmaCutTOFMIDKa && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCMIDKa) { return true; } } else if (onlyTPC) { - if (std::abs(candidate.tpcNSigmaKa()) < 3.0) { + if (std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCMIDKa) { return true; } } else { - if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (3.0 * 3.0)) { + if (candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (selectionConfig.nsigmaCutCombinedMIDKa * selectionConfig.nsigmaCutCombinedMIDKa) && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCMIDKa) { return true; } } - } else if (PID == 2) { + } else if (PID == PIDParticle::kProton) { // for proton if (onlyTOF) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < selectionConfig.nsigmaCutTOFPr && candidate.beta() > cBetaCutTOF) { return true; } } else if (onlyTOFHIT) { - if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < 3.0) { + if (candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < selectionConfig.nsigmaCutTOFPr && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr) { return true; } } else if (onlyTPC) { - if (std::abs(candidate.tpcNSigmaPr()) < 3.0) { + if (std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr) { return true; } } else { - if (candidate.hasTOF() && (candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < (3.0 * 3.0)) { + if (candidate.hasTOF() && (candidate.tofNSigmaPr() * candidate.tofNSigmaPr() + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr()) < (selectionConfig.nsigmaCutTOFPr * selectionConfig.nsigmaCutTOFPr) && candidate.beta() > cBetaCutTOF) { return true; } - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < 3.0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr) { return true; } } } + return false; + } */ + + template + bool selectionPIDNew(const T& candidate, int PID) + { + if (PID == PIDParticle::kPion) { + if (candidate.pt() < selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi && candidate.hasTOF() && std::abs(candidate.tofNSigmaPi()) < selectionConfig.nsigmaCutTOFPi) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPi()) < selectionConfig.nsigmaCutTPCPi && !candidate.hasTOF()) { + return true; + } + } else if (PID == PIDParticle::kKaon) { + if (candidate.pt() < selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa && candidate.hasTOF() && std::abs(candidate.tofNSigmaKa()) < selectionConfig.nsigmaCutTOFKa) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaKa()) < selectionConfig.nsigmaCutTPCKa && !candidate.hasTOF()) { + return true; + } + } + /* else if (PID == PIDParticle::kProton) { // for proton + if (candidate.pt() < selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr && candidate.hasTOF() && std::abs(candidate.tofNSigmaPr()) < selectionConfig.nsigmaCutTOFPr) { + return true; + } + if (candidate.pt() >= selectionConfig.lowPtCutPID && std::abs(candidate.tpcNSigmaPr()) < selectionConfig.nsigmaCutTPCPr && !candidate.hasTOF()) { + return true; + } + } */ + return false; } - array pvec0; - array pvec1; + std::array pvec0; + std::array pvec1; // 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 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 V0TrackCandidate = aod::V0Datas; - using EventCandidatesMC = soa::Join; - // using TrackCandidatesMC = soa::Filtered>; - using TrackCandidatesMC = soa::Filtered>; - - 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 BinningTypeTPCMultiplicity = ColumnBinningPolicy; - // using BinningTypeVertexContributor = - // ColumnBinningPolicy; - using BinningTypeCentralityM = ColumnBinningPolicy; - using BinningTypeVertexContributor = ColumnBinningPolicy; - - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicity}, true}; - - SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, &cache}; - - template - void fillInvMass(const T1& track1, const T2& track2, const T3& lv2, const T4& lv3, float multiplicity, bool isMix) + Filter posZFilter = (nabs(o2::aod::collision::posZ) < selectionConfig.cutzvertex); + + // Filter acceptanceFilter = (nabs(aod::track::eta) < selectionConfig.cfgCutEtaMax && nabs(aod::track::pt) > selectionConfig.cfgCutPT) && (nabs(aod::track::eta) > selectionConfig.cfgCutEtaMin); + Filter acceptanceFilter = (nabs(aod::track::eta) < selectionConfig.cfgCutEtaMax && nabs(aod::track::pt) > selectionConfig.cfgCutPT); + // Filter fDCAcutFilter = (nabs(aod::track::dcaXY) < selectionConfig.cfgCutDCAxyMax) && (nabs(aod::track::dcaZ) < selectionConfig.cfgCutDCAz) && (nabs(aod::track::dcaXY) > selectionConfig.cfgCutDCAxyMin); + Filter fDCAcutFilter = (nabs(aod::track::dcaXY) < selectionConfig.cfgCutDCAxyMax) && (nabs(aod::track::dcaZ) < selectionConfig.cfgCutDCAz); + + using EventCandidates = soa::Filtered>; // aod::CentNGlobals, aod::CentNTPVs, aod::CentMFTs + using EventCandidatesMix = soa::Filtered>; // aod::CentNGlobals, aod::CentNTPVs, aod::CentMFTs + using TrackCandidates = soa::Filtered>; + using EventCandidatesMC = soa::Join; + // using EventCandidatesMC = soa::Filtered>; + + using TrackCandidatesMC = soa::Filtered>; + // using EventMCGenerated = soa::Join; // aod::CentNGlobals, aod::CentNTPVs, aod::CentMFTs + using EventMCGenerated = soa::Join; + + //*********Varibles declaration*************** + float multiplicity{-1.0}, theta2; + ROOT::Math::PxPyPzMVector daughter1, daughter2, daughterRot, mother, motherRot, daughterSelected, fourVecDauCM, daughterRotCM; + ROOT::Math::XYZVector randomVec, beamVec, normalVec; + bool isMix = false; + + template + void fillInvMass(const T1& daughter1, const T1& daughter2, const T1& mother, float multiplicity, bool isMix, const T2& track1, const T2& track2) { - ROOT::Math::PxPyPzMVector daughter1, daughter2, daughter_selected; - daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); // Kaon - daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); // Pion - daughter_selected = (boost_daugter1) ? daughter1 : daughter2; - auto selected_dau_mass = (boost_daugter1) ? massKa : massPi; - - TLorentzVector lv4, lv5; - // polarization calculations - - auto phiRandom = gRandom->Uniform(0.f, constants::math::TwoPI); - auto thetaRandom = gRandom->Uniform(0.f, constants::math::PI); - ROOT::Math::PxPyPzMVector fourVecDau1 = ROOT::Math::PxPyPzMVector(daughter_selected.Px(), daughter_selected.Py(), daughter_selected.Pz(), selected_dau_mass); // Kaon or Pion + daughterSelected = (boostDaugter1) ? daughter1 : daughter2; // polarization calculations + ROOT::Math::Boost boost{mother.BoostToCM()}; // boost mother to center of mass frame + fourVecDauCM = boost(daughterSelected); // boost the frame of daughter same as mother + + // if (std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + if (activateTHnSparseCosThStarHelicity) { + auto cosThetaStarHelicity = mother.Vect().Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(mother.Vect().Mag2())); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + if (std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + } - ROOT::Math::PxPyPzMVector 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 - ROOT::Math::PxPyPzMVector fourVecDauCM = boost(fourVecDau1); // 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 + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / selectionConfig.rotationalCut, o2::constants::math::PI + o2::constants::math::PI / selectionConfig.rotationalCut); - TRandom* rn = new TRandom(); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); - if (TMath::Abs(lv3.Rapidity() < 0.5)) { + motherRot = daughterRot + daughter2; - 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())); + ROOT::Math::Boost boost2{motherRot.BoostToCM()}; + daughterRotCM = boost2(daughterRot); - if (track1.sign() * track2.sign() < 0) { - if (!isMix) { - histos.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); + auto cosThetaStarHelicityRot = motherRot.Vect().Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(motherRot.Vect().Mag2())); - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - lv4.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi() + theta2, massKa); // for rotated background - lv5 = lv2 + lv4; - histos.fill(HIST("h3KstarInvMassRotated"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarHelicity); - } - } else { - histos.fill(HIST("h3KstarInvMassMixed"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); + if (calcRotational && std::abs(motherRot.Rapidity()) < selectionConfig.rapidityMotherData) + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarHelicityRot); } - } else { - if (!isMix) { - histos.fill(HIST("h3KstarInvMasslikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarHelicity); + } else if (isMix && std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + } + } else { + if (!isMix) { + if (calcLikeSign && std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + if (track1.sign() > 0 && track2.sign() > 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + } else if (track1.sign() < 0 && track2.sign() < 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.M(), cosThetaStarHelicity); + } } } + } + + } else if (activateTHnSparseCosThStarProduction) { + normalVec = ROOT::Math::XYZVector(mother.Py(), -mother.Px(), 0.f); + auto cosThetaStarProduction = normalVec.Dot(fourVecDauCM.Vect()) / (std::sqrt(fourVecDauCM.Vect().Mag2()) * std::sqrt(normalVec.Mag2())); - } 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 (track1.sign() * track2.sign() < 0) { + if (!isMix) { + if (std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.M(), cosThetaStarProduction); + } + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); - if (track1.sign() * track2.sign() < 0) { - if (!isMix) { - histos.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - lv4.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi() + theta2, massKa); // for rotated background - lv5 = lv2 + lv4; - histos.fill(HIST("h3KstarInvMassRotated"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarProduction); + motherRot = daughterRot + daughter2; + if (calcRotational && std::abs(motherRot.Rapidity()) < selectionConfig.rapidityMotherData) + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarProduction); + } + } else if (isMix && std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarProduction); + } + } else { + if (!isMix) { + if (calcLikeSign && std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + if (track1.sign() > 0 && track2.sign() > 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarProduction); + } else if (track1.sign() < 0 && track2.sign() < 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.M(), cosThetaStarProduction); } - } else { - histos.fill(HIST("h3KstarInvMassMixed"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarProduction); } - } else { - if (!isMix) { - histos.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(fourVecDauCM.Vect()) / std::sqrt(fourVecDauCM.Vect().Mag2()); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + if (std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam); + } + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + + motherRot = daughterRot + daughter2; + if (calcRotational && std::abs(motherRot.Rapidity()) < selectionConfig.rapidityMotherData) + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarBeam); } + } else if (isMix && std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam); } - } 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 (track1.sign() * track2.sign() < 0) { - if (!isMix) { - histos.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - lv4.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi() + theta2, massKa); // for rotated background - lv5 = lv2 + lv4; - histos.fill(HIST("h3KstarInvMassRotated"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarBeam); - } - } else { - histos.fill(HIST("h3KstarInvMassMixed"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); + } else { + if (calcLikeSign && std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + if (track1.sign() > 0 && track2.sign() > 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam); + } else if (track1.sign() < 0 && track2.sign() < 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.M(), cosThetaStarBeam); } - } else { - histos.fill(HIST("h3KstarInvMasslikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarBeam); - } - } else if (activateTHnSparseCosThStarRandom) { - 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 (track1.sign() * track2.sign() < 0) { - if (!isMix) { - histos.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); - for (int i = 0; i < c_nof_rotations; i++) { - float theta2 = rn->Uniform(0, TMath::Pi()); - lv4.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi() + theta2, massKa); // for rotated background - lv5 = lv2 + lv4; - histos.fill(HIST("h3KstarInvMassRotated"), multiplicity, lv5.Pt(), lv5.M(), cosThetaStarRandom); - } - } else { - histos.fill(HIST("h3KstarInvMassMixed"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); + } + } + } 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(fourVecDauCM.Vect()) / std::sqrt(fourVecDauCM.Vect().Mag2()); + + if (track1.sign() * track2.sign() < 0) { + if (!isMix) { + if (std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassUnlikeSign"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom); } - } else { - if (!isMix) { - histos.fill(HIST("h3KstarInvMasslikeSign"), multiplicity, lv3.Pt(), lv3.M(), cosThetaStarRandom); + for (int i = 0; i < cRotations; i++) { + theta2 = rn->Uniform(0, o2::constants::math::PI); + daughterRot = ROOT::Math::PxPyPzMVector(daughter1.Px() * std::cos(theta2) - daughter1.Py() * std::sin(theta2), daughter1.Px() * std::sin(theta2) + daughter1.Py() * std::cos(theta2), daughter1.Pz(), daughter1.M()); + + motherRot = daughterRot + daughter2; + if (calcRotational && std::abs(motherRot.Rapidity()) < selectionConfig.rapidityMotherData) + hInvMass.fill(HIST("h3KstarInvMassRotated"), multiplicity, motherRot.Pt(), motherRot.M(), cosThetaStarRandom); + } + } else if (isMix && std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + hInvMass.fill(HIST("h3KstarInvMassMixed"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom); + } + } else { + if (!isMix) { + if (calcLikeSign && std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + if (track1.sign() > 0 && track2.sign() > 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignPP"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom); + } else if (track1.sign() < 0 && track2.sign() < 0) { + hInvMass.fill(HIST("h3KstarInvMasslikeSignMM"), multiplicity, mother.Pt(), mother.M(), cosThetaStarRandom); + } } } } } + // } } + // int counter = 0; void processSE(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) { - histos.fill(HIST("events_check_data"), 0.5); - if (TVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { - return; - } - histos.fill(HIST("events_check_data"), 1.5); + // if (cTVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { + // return; + // } + + // if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + // return; + // } - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + // if (!collision.sel8()) { + // return; + // } + int occupancy = collision.trackOccupancyInTimeRange(); + rEventSelection.fill(HIST("hOccupancy"), occupancy); + + if (!selectionEvent(collision, true)) { // fill data event cut histogram return; } - histos.fill(HIST("events_check_data"), 2.5); - if (!collision.sel8()) { - return; + multiplicity = -1; + + if (cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default } - histos.fill(HIST("events_check_data"), 3.5); - float multiplicity = 0.0f; - multiplicity = collision.centFT0M(); + /* else if (cSelectMultEstimator == 4) { + multiplicity = collision.centMFT(); + } */ + /* else if (cSelectMultEstimator == 5) { + multiplicity = collision.centNGlobal(); + } */ + /* else if (cSelectMultEstimator == 6) { + multiplicity = collision.centNTPV(); + } */ // Fill the event counter - if (QAevents) { + if (cQAevents) { rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - rEventSelection.fill(HIST("hmult"), multiplicity); - histos.fill(HIST("multdist_FT0M"), collision.multFT0M()); - histos.fill(HIST("multdist_FT0A"), collision.multFT0A()); - histos.fill(HIST("multdist_FT0C"), collision.multFT0C()); - histos.fill(HIST("hNcontributor"), collision.numContrib()); + 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()); } - for (auto& [track1, track2] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { - if (QAbefore) { - histos.fill(HIST("hNsigmaTPC_before"), track1.pt(), track1.tpcNSigmaKa()); - histos.fill(HIST("hNsigmaTOF_before"), track1.pt(), track1.tofNSigmaKa()); - histos.fill(HIST("hCRFC_before"), track1.tpcCrossedRowsOverFindableCls()); - histos.fill(HIST("dE_by_dx_TPC"), track1.pt(), track1.tpcSignal()); - histos.fill(HIST("hphi"), track1.phi()); - } - histos.fill(HIST("events_check_data"), 4.5); - + for (const auto& [track1, track2] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { + rEventSelection.fill(HIST("tracksCheckData"), 0.5); if (!selectionTrack(track1)) { continue; } if (!selectionTrack(track2)) { continue; } - histos.fill(HIST("events_check_data"), 5.5); - if (QAevents) { - histos.fill(HIST("hDcaxy"), track1.dcaXY()); - histos.fill(HIST("hDcaz"), track1.dcaZ()); + rEventSelection.fill(HIST("tracksCheckData"), 1.5); + + if (track1.globalIndex() == track2.globalIndex()) + continue; + + 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("Before/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("Before/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + + hOthers.fill(HIST("hCRFC_before"), track1.tpcCrossedRowsOverFindableCls()); + hOthers.fill(HIST("dE_by_dx_TPC"), track1.p(), track1.tpcSignal()); + hOthers.fill(HIST("hphi"), track1.phi()); + + if (track1.sign() < 0) { + hPID.fill(HIST("Before/h1PID_TPC_neg_kaon"), track1.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TPC_neg_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_neg_kaon"), track1.tofNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_neg_pion"), track2.tofNSigmaPi()); + } else { + hPID.fill(HIST("Before/h1PID_TPC_pos_kaon"), track1.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TPC_pos_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_pos_kaon"), track1.tofNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_pos_pion"), track2.tofNSigmaPi()); + } + } + + if (cQAevents) { + rEventSelection.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), multiplicity, track1.pt()); + rEventSelection.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), multiplicity, track1.pt()); } // 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 + if (!applypTdepPID && !selectionPID(track1, 1)) // Track 1 is checked with Kaon + continue; + if (!applypTdepPID && !selectionPID(track2, 0)) // Track 2 is checked with Pion + continue; + + if (applypTdepPID && !selectionPIDNew(track1, 1)) // Track 1 is checked with Kaon + continue; + if (applypTdepPID && !selectionPIDNew(track2, 0)) // Track 2 is checked with Pion + continue; + + rEventSelection.fill(HIST("tracksCheckData"), 2.5); + + if (cFakeTrack && isFakeTrack(track1, 1)) // Kaon + continue; + if (cFakeTrack && isFakeTrack(track2, 0)) // Pion continue; - if (!selectionPID(track2, 0)) // Track 2 is checked with Pion + rEventSelection.fill(HIST("tracksCheckData"), 3.5); + + if (std::abs(track1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) continue; - histos.fill(HIST("events_check_data"), 6.5); + if (std::abs(track2.rapidity(o2::track::PID::getMass(o2::track::PID::Pion))) > selectionConfig.ctrackRapidity) + continue; + rEventSelection.fill(HIST("tracksCheckData"), 4.5); - if (MID) { - if (MIDselectionPID(track1, 0)) // Kaon misidentified as pion + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(track1, 0)) // Kaon misidentified as pion continue; - if (MIDselectionPID(track1, 2)) // Kaon misidentified as proton + if (selectionMID(track1, 2)) // Kaon misidentified as proton continue; - if (MIDselectionPID(track2, 1)) // Pion misidentified as kaon + if (selectionMID(track2, 1)) // Pion misidentified as kaon continue; + if (selectionMID(track2, 2)) // Pion misidentified as proton + continue; + } */ + + rEventSelection.fill(HIST("tracksCheckData"), 5.5); + + if (cQAplots) { + hPID.fill(HIST("After/hDcaxyPi"), track2.dcaXY()); + hPID.fill(HIST("After/hDcaxyKa"), track1.dcaXY()); + hPID.fill(HIST("After/hDcazPi"), track2.dcaZ()); + hPID.fill(HIST("After/hDcazKa"), track1.dcaZ()); + + hPID.fill(HIST("After/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + 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()); } - histos.fill(HIST("events_check_data"), 7.5); - - 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()); - // histos.fill(HIST("hNsigmaPionTPC_after"), track2.pt(), track2.tpcNSigmaPi()); - // histos.fill(HIST("hNsigmaPionTOF_after"), track2.pt(), track2.tofNSigmaPi()); + if (!selectionPair(track1, track2)) { + continue; } + rEventSelection.fill(HIST("tracksCheckData"), 6.5); - if (track1.globalIndex() == track2.globalIndex()) - continue; + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + mother = daughter1 + daughter2; // Kstar meson + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mother.Pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (mother.M() >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ - histos.fill(HIST("events_check_data"), 8.5); + hOthers.fill(HIST("hKstar_rap_pt"), mother.Rapidity(), mother.Pt()); + hOthers.fill(HIST("hKstar_eta_pt"), mother.Eta(), mother.Pt()); - TLorentzVector lv1, lv2, lv3; - lv1.SetPtEtaPhiM(track1.pt(), track1.eta(), track1.phi(), massKa); - lv2.SetPtEtaPhiM(track2.pt(), track2.eta(), track2.phi(), massPi); - lv3 = lv1 + lv2; - bool isMix = false; - fillInvMass(track1, track2, lv2, lv3, multiplicity, isMix); + isMix = false; + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, track1, track2); } } - PROCESS_SWITCH(kstarqa, processSE, "Process Same event", true); + PROCESS_SWITCH(Kstarqa, processSE, "Process Same event", true); + + void processSEPhi(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) - void processME(EventCandidates const&, TrackCandidates const&) { - for (auto& [c1, tracks1, c2, tracks2] : pair) { - if (!c1.sel8()) { + int occupancy = collision.trackOccupancyInTimeRange(); + rEventSelection.fill(HIST("hOccupancy"), occupancy); + + if (!selectionEvent(collision, true)) { // fill data event cut histogram + return; + } + + multiplicity = -1; + + if (cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + + // Fill the event counter + if (cQAevents) { + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + rEventSelection.fill(HIST("hMultiplicity"), multiplicity); + rEventSelection.fill(HIST("multdist_FT0M"), collision.multFT0M()); + } + + for (const auto& [track1, track2] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + rEventSelection.fill(HIST("tracksCheckData"), 0.5); + if (!selectionTrack(track1)) { continue; } - if (!c2.sel8()) { + if (!selectionTrack(track2)) { continue; } + rEventSelection.fill(HIST("tracksCheckData"), 1.5); - 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))) { + if (track1.globalIndex() == track2.globalIndex()) continue; + + 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("Before/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + // hPID.fill(HIST("Before/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + + hOthers.fill(HIST("hCRFC_before"), track1.tpcCrossedRowsOverFindableCls()); + hOthers.fill(HIST("dE_by_dx_TPC"), track1.p(), track1.tpcSignal()); + hOthers.fill(HIST("hphi"), track1.phi()); + + if (track1.sign() < 0) { + hPID.fill(HIST("Before/h1PID_TPC_neg_kaon"), track1.tpcNSigmaKa()); + // hPID.fill(HIST("Before/h1PID_TPC_neg_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_neg_kaon"), track1.tofNSigmaKa()); + // hPID.fill(HIST("Before/h1PID_TOF_neg_pion"), track2.tofNSigmaPi()); + } else { + hPID.fill(HIST("Before/h1PID_TPC_pos_kaon"), track1.tpcNSigmaKa()); + // hPID.fill(HIST("Before/h1PID_TPC_pos_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_pos_kaon"), track1.tofNSigmaKa()); + // hPID.fill(HIST("Before/h1PID_TOF_pos_pion"), track2.tofNSigmaPi()); + } } - if (TVXEvsel && (!c1.selection_bit(aod::evsel::kIsTriggerTVX) || !c2.selection_bit(aod::evsel::kIsTriggerTVX))) { - return; + if (cQAevents) { + rEventSelection.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), multiplicity, track1.pt()); + rEventSelection.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), multiplicity, track1.pt()); } - auto multiplicity = c1.centFT0M(); + // since we are using combinations full index policy, so repeated pairs are allowed, so we can check one with Kaon and other with kaon + if (!applypTdepPID && !selectionPID(track1, 1)) // Track 1 is checked with Kaon + continue; + if (!applypTdepPID && !selectionPID(track2, 1)) // Track 2 is checked with kaon + continue; + + if (applypTdepPID && !selectionPIDNew(track1, 1)) // Track 1 is checked with Kaon + continue; + if (applypTdepPID && !selectionPIDNew(track2, 1)) // Track 2 is checked with kaon + continue; + + rEventSelection.fill(HIST("tracksCheckData"), 2.5); + + if (cFakeTrack && isFakeTrack(track1, 1)) // Kaon + continue; + if (cFakeTrack && isFakeTrack(track2, 1)) // Pion + continue; + rEventSelection.fill(HIST("tracksCheckData"), 3.5); + + if (std::abs(track1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; - for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (std::abs(track2.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + rEventSelection.fill(HIST("tracksCheckData"), 4.5); - if (!selectionTrack(t1)) // Kaon + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(track1, 0)) // Kaon misidentified as pion continue; - if (!selectionTrack(t2)) // Pion + if (selectionMID(track1, 2)) // Kaon misidentified as proton continue; - if (!selectionPID(t1, 1)) // Kaon + if (selectionMID(track2, 0)) // Pion misidentified as pion continue; - if (!selectionPID(t2, 0)) // Pion + if (selectionMID(track2, 2)) // Pion misidentified as proton 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; - } + } */ + + rEventSelection.fill(HIST("tracksCheckData"), 5.5); + + if (cQAplots) { + // hPID.fill(HIST("After/hDcaxyPi"), track2.dcaXY()); + hPID.fill(HIST("After/hDcaxyKa"), track1.dcaXY()); + // hPID.fill(HIST("After/hDcazPi"), track2.dcaZ()); + hPID.fill(HIST("After/hDcazKa"), track1.dcaZ()); + + hPID.fill(HIST("After/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + // hPID.fill(HIST("After/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + 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()); + } - TLorentzVector KAON; - KAON.SetPtEtaPhiM(t1.pt(), t1.eta(), t1.phi(), massKa); - TLorentzVector PION; - PION.SetPtEtaPhiM(t2.pt(), t2.eta(), t2.phi(), massPi); + if (!selectionPair(track1, track2)) { + continue; + } + rEventSelection.fill(HIST("tracksCheckData"), 6.5); - TLorentzVector Kstar = KAON + PION; - bool isMix = true; + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + mother = daughter1 + daughter2; // Phi meson - if (!QA) { - if (TMath::Abs(Kstar.Rapidity()) < 0.5) { - fillInvMass(t1, t2, PION, Kstar, multiplicity, isMix); - } - } - } - } + /* if (selectionConfig.isApplyCutsOnMother) { + if (mother.Pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (mother.M() >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + hOthers.fill(HIST("hKstar_rap_pt"), mother.Rapidity(), mother.Pt()); + hOthers.fill(HIST("hKstar_eta_pt"), mother.Eta(), mother.Pt()); + + isMix = false; + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, track1, track2); + } + } + + PROCESS_SWITCH(Kstarqa, processSEPhi, "Process Same event for Phi", false); + + 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"}; + + // using BinningTypeTPCMultiplicity = ColumnBinningPolicy; + using BinningTypeFT0M = ColumnBinningPolicy; + using BinningTypeFT0A = ColumnBinningPolicy; + using BinningTypeFT0C = ColumnBinningPolicy; + using BinningTypeFV0A = ColumnBinningPolicy; + + using BinningTypeMCFT0M = ColumnBinningPolicy; + using BinningTypeMCFT0A = ColumnBinningPolicy; + using BinningTypeMCFT0C = ColumnBinningPolicy; + using BinningTypeMCFV0A = ColumnBinningPolicy; + + BinningTypeFT0M binningOnFT0M{{axisVertex, axisMultiplicity}, true}; + BinningTypeFT0A binningOnFT0A{{axisVertex, axisMultiplicity}, true}; + BinningTypeFT0C binningOnFT0C{{axisVertex, axisMultiplicity}, true}; + BinningTypeFV0A binningOnFV0A{{axisVertex, axisMultiplicity}, true}; + + BinningTypeMCFT0M binningOnMCFT0M{{axisVertex, axisMultiplicity}, true}; + BinningTypeMCFT0A binningOnMCFT0A{{axisVertex, axisMultiplicity}, true}; + BinningTypeMCFT0C binningOnMCFT0C{{axisVertex, axisMultiplicity}, true}; + BinningTypeMCFV0A binningOnMCFV0A{{axisVertex, axisMultiplicity}, true}; + + SameKindPair pair1{binningOnFT0M, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pair2{binningOnFT0A, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pair3{binningOnFT0C, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pair4{binningOnFV0A, selectionConfig.cfgNoMixedEvents, -1, &cache}; + + SameKindPair pairmc1{binningOnMCFT0M, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairmc2{binningOnMCFT0A, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairmc3{binningOnMCFT0C, selectionConfig.cfgNoMixedEvents, -1, &cache}; + SameKindPair pairmc4{binningOnMCFV0A, selectionConfig.cfgNoMixedEvents, -1, &cache}; + + void processME(EventCandidatesMix const&, TrackCandidates const&) + { + // Map estimator to pair and multiplicity accessor + auto runMixing = [&](auto& pair, auto multiplicityGetter) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + // if (!c1.sel8() || !c2.sel8()) + // continue; + + if (!selectionEvent(c1, false) || !selectionEvent(c2, false)) { // don't fill event cut histogram + continue; + } + + multiplicity = multiplicityGetter(c1); + + for (const auto& [t1, t2] : o2::soa::combinations( + o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!selectionTrack(t1) || !selectionTrack(t2)) + continue; + if (!selectionPID(t1, 1) || !selectionPID(t2, 0)) + continue; + + if (std::abs(t1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + + if (std::abs(t2.rapidity(o2::track::PID::getMass(o2::track::PID::Pion))) > selectionConfig.ctrackRapidity) + continue; + + if (cFakeTrack && isFakeTrack(t1, 1)) // Kaon + continue; + if (cFakeTrack && isFakeTrack(t2, 0)) // Pion + continue; + + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(t1, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(t1, 2)) // Kaon misidentified as proton + continue; + if (selectionMID(t2, 1)) // Pion misidentified as kaon + continue; + if (selectionMID(t2, 2)) // Pion misidentified as proton + continue; + } */ + + if (!selectionPair(t1, t2)) { + continue; + } + + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massPi); + mother = daughter1 + daughter2; + + isMix = true; + + if (std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, t1, t2); + } + } + } + }; + + // Call mixing based on selected estimator + if (cSelectMultEstimator == kFT0M) { + runMixing(pair1, [](const auto& c) { return c.centFT0M(); }); + } else if (cSelectMultEstimator == kFT0A) { + runMixing(pair2, [](const auto& c) { return c.centFT0A(); }); + } else if (cSelectMultEstimator == kFT0C) { + runMixing(pair3, [](const auto& c) { return c.centFT0C(); }); + } else if (cSelectMultEstimator == kFV0A) { + runMixing(pair4, [](const auto& c) { return c.centFV0A(); }); + } + } + PROCESS_SWITCH(Kstarqa, processME, "Process Mixed event", true); + + void processMEPhi(EventCandidatesMix const&, TrackCandidates const&) + { + // Map estimator to pair and multiplicity accessor + auto runMixing = [&](auto& pair, auto multiplicityGetter) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + // if (!c1.sel8() || !c2.sel8()) + // continue; + + if (!selectionEvent(c1, false) || !selectionEvent(c2, false)) { // don't fill event cut histogram + continue; + } + + multiplicity = multiplicityGetter(c1); + + for (const auto& [t1, t2] : o2::soa::combinations( + o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!selectionTrack(t1) || !selectionTrack(t2)) + continue; + if (!selectionPID(t1, 1) || !selectionPID(t2, 1)) + continue; + + if (std::abs(t1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + + if (std::abs(t2.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + + if (cFakeTrack && isFakeTrack(t1, 1)) // Kaon + continue; + if (cFakeTrack && isFakeTrack(t2, 1)) // Kaon + continue; + + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(t1, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(t1, 2)) // Kaon misidentified as proton + continue; + if (selectionMID(t2, 0)) // Pion misidentified as pion + continue; + if (selectionMID(t2, 2)) // Pion misidentified as proton + continue; + } */ + + if (!selectionPair(t1, t2)) { + continue; + } + + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massKa); + mother = daughter1 + daughter2; + + isMix = true; + + if (std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, t1, t2); + } + } + } + }; + + // Call mixing based on selected estimator + if (cSelectMultEstimator == kFT0M) { + runMixing(pair1, [](const auto& c) { return c.centFT0M(); }); + } else if (cSelectMultEstimator == kFT0A) { + runMixing(pair2, [](const auto& c) { return c.centFT0A(); }); + } else if (cSelectMultEstimator == kFT0C) { + runMixing(pair3, [](const auto& c) { return c.centFT0C(); }); + } else if (cSelectMultEstimator == kFV0A) { + runMixing(pair4, [](const auto& c) { return c.centFV0A(); }); + } + } + PROCESS_SWITCH(Kstarqa, processMEPhi, "Process Mixed event for Phi", false); + + void processMEMC(EventCandidatesMC const&, TrackCandidatesMC const&, aod::McParticles const&, aod::McCollisions const&) + { + auto runMixing = [&](auto& pair, auto multiplicityGetter) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + if (!selectionEvent(c1, false) || !selectionEvent(c2, false)) { // don't fill event cut histogram + continue; + } + + if (selectionConfig.isApplyMCchecksClosure && (!c1.has_mcCollision() || !c2.has_mcCollision())) { + continue; // skip if no MC collision associated + } + + multiplicity = multiplicityGetter(c1); + // multiplicity = c1.centFT0M(); // default, can be changed later + + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!selectionTrack(t1) || !selectionTrack(t2)) + continue; + if (!selectionPID(t1, 1) || !selectionPID(t2, 0)) + continue; + + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(t1, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(t1, 2)) // Kaon misidentified as proton + continue; + if (selectionMID(t2, 1)) // Pion misidentified as kaon + continue; + if (selectionMID(t2, 2)) // Pion misidentified as proton + continue; + } */ + + if (selectionConfig.isApplyMCchecksClosure && (!t1.has_mcParticle() || !t2.has_mcParticle())) { + continue; // skip if no MC particle associated + } + + if (std::abs(t1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + + if (std::abs(t2.rapidity(o2::track::PID::getMass(o2::track::PID::Pion))) > selectionConfig.ctrackRapidity) + continue; + + const auto mctrack1 = t1.mcParticle(); + const auto mctrack2 = t2.mcParticle(); + + if (selectionConfig.isApplyMCchecksClosure && !mctrack1.isPhysicalPrimary()) { + continue; + } + + if (selectionConfig.isApplyMCchecksClosure && !mctrack2.isPhysicalPrimary()) { + continue; + } + + daughter1 = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), massPi); + mother = daughter1 + daughter2; + + isMix = true; + + if (std::abs(mother.Rapidity()) < selectionConfig.rapidityMotherData) { + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, t1, t2); + } + } + } + }; + // Call mixing based on selected estimator + if (cSelectMultEstimator == kFT0M) { + runMixing(pairmc1, [](const auto& c) { return c.centFT0M(); }); + } else if (cSelectMultEstimator == kFT0A) { + runMixing(pairmc2, [](const auto& c) { return c.centFT0A(); }); + } else if (cSelectMultEstimator == kFT0C) { + runMixing(pairmc3, [](const auto& c) { return c.centFT0C(); }); + } else if (cSelectMultEstimator == kFV0A) { + runMixing(pairmc4, [](const auto& c) { return c.centFV0A(); }); + } } + PROCESS_SWITCH(Kstarqa, processMEMC, "Process mixed-event in MC", false); + + void processSEMC(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, aod::McCollisions const& /*mcCollisions*/) + { + auto oldindex = -999; + if (!collision.has_mcCollision()) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + rEventSelection.fill(HIST("hOccupancy"), occupancy); + + if (!selectionEvent(collision, false)) { // don't fill event cut histogram + return; + } + + multiplicity = -1; + + if (cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + + // Fill the event counter + if (cQAevents) { + 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()); + } + + for (const auto& [track1, track2] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { + rEventSelection.fill(HIST("tracksCheckData"), 0.5); + if (!selectionTrack(track1)) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + + const auto mctrack1 = track1.mcParticle(); + const auto mctrack2 = track2.mcParticle(); + + if (selectionConfig.isApplyMCchecksClosure && (!track1.has_mcParticle() || !track2.has_mcParticle())) { + continue; // skip if no MC particle associated + } + + if (selectionConfig.isApplyMCchecksClosure && !mctrack1.isPhysicalPrimary()) { + continue; + } + + if (selectionConfig.isApplyMCchecksClosure && !mctrack2.isPhysicalPrimary()) { + continue; + } + rEventSelection.fill(HIST("tracksCheckData"), 1.5); + + 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("Before/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("Before/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + + hOthers.fill(HIST("hCRFC_before"), track1.tpcCrossedRowsOverFindableCls()); + hOthers.fill(HIST("dE_by_dx_TPC"), track1.p(), track1.tpcSignal()); + hOthers.fill(HIST("hphi"), track1.phi()); + + if (track1.sign() < 0) { + hPID.fill(HIST("Before/h1PID_TPC_neg_kaon"), track1.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TPC_neg_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_neg_kaon"), track1.tofNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_neg_pion"), track2.tofNSigmaPi()); + } else { + hPID.fill(HIST("Before/h1PID_TPC_pos_kaon"), track1.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TPC_pos_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_pos_kaon"), track1.tofNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_pos_pion"), track2.tofNSigmaPi()); + } + } + + if (cQAevents) { + rEventSelection.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), multiplicity, track1.pt()); + rEventSelection.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), multiplicity, track1.pt()); + } + + // 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 (!applypTdepPID && !selectionPID(track1, 1)) // Track 1 is checked with Kaon + continue; + if (!applypTdepPID && !selectionPID(track2, 0)) // Track 2 is checked with Pion + continue; + rEventSelection.fill(HIST("tracksCheckData"), 2.5); + + if (applypTdepPID && !selectionPIDNew(track1, 1)) // Track 1 is checked with Kaon + continue; + if (applypTdepPID && !selectionPIDNew(track2, 0)) // Track 2 is checked with Pion + continue; + rEventSelection.fill(HIST("tracksCheckData"), 3.5); + + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(track1, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(track1, 2)) // Kaon misidentified as proton + continue; + if (selectionMID(track2, 1)) // Pion misidentified as kaon + continue; + if (selectionMID(track2, 2)) // Pion misidentified as proton + continue; + } */ + + rEventSelection.fill(HIST("tracksCheckData"), 4.5); + if (std::abs(track1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + + if (std::abs(track2.rapidity(o2::track::PID::getMass(o2::track::PID::Pion))) > selectionConfig.ctrackRapidity) + continue; + + // if (cFakeTrack && isFakeTrack(track1, 1)) // Kaon + // continue; + // if (cFakeTrack && isFakeTrack(track2, 0)) // Pion + // continue; + rEventSelection.fill(HIST("tracksCheckData"), 5.5); + + if (track1.globalIndex() == track2.globalIndex()) + continue; + + rEventSelection.fill(HIST("tracksCheckData"), 6.5); + + if (cQAplots) { + hPID.fill(HIST("After/hDcaxyPi"), track2.dcaXY()); + hPID.fill(HIST("After/hDcaxyKa"), track1.dcaXY()); + hPID.fill(HIST("After/hDcazPi"), track2.dcaZ()); + hPID.fill(HIST("After/hDcazKa"), track1.dcaZ()); + + hPID.fill(HIST("After/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + 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 (selectionConfig.isApplyMCchecksClosure) { + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { + continue; + } + + if (selectionConfig.isApplyMCchecksClosure && !mothertrack1.producedByGenerator()) { + continue; + } + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mothertrack1.pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if ((std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())) >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + if (selectionConfig.isApplyMCchecksClosure && avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 11.5); + + oldindex = mothertrack1.globalIndex(); + + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + mother = daughter1 + daughter2; // Kstar meson + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mother.Pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (mother.M() >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + hOthers.fill(HIST("hKstar_rap_pt"), mother.Rapidity(), mother.Pt()); + hOthers.fill(HIST("hKstar_eta_pt"), mother.Eta(), mother.Pt()); + + isMix = false; + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, track1, track2); + } + } + } else { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + mother = daughter1 + daughter2; // Kstar meson + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mother.Pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (mother.M() >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + hOthers.fill(HIST("hKstar_rap_pt"), mother.Rapidity(), mother.Pt()); + hOthers.fill(HIST("hKstar_eta_pt"), mother.Eta(), mother.Pt()); + + isMix = false; + fillInvMass(daughter1, daughter2, mother, multiplicity, isMix, track1, track2); + } + } + } + PROCESS_SWITCH(Kstarqa, processSEMC, "Process same event in MC", false); + + Service pdgDB; + + void processGen(EventMCGenerated::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + // void processGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + { + rEventSelection.fill(HIST("eventsCheckGen"), 0.5); + + 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 == std::abs(PDG_t::kElectron) || pdgcode == std::abs(PDG_t::kMuonMinus))) { + if (std::abs(mcParticle.eta()) < 1.0) { + nChInel = nChInel + 1; + } + } + } + if (nChInel > 0 && std::abs(mcCollision.posZ()) < selectionConfig.cutzvertex) + rEventSelection.fill(HIST("eventsCheckGen"), 1.5); + + std::vector selectedEvents(collisions.size()); + int nevts = 0; + multiplicity = -1.0; + // float impactParameter = mcCollision.impactParameter(); + + bool isINELgt0true = false; + + if (pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { + isINELgt0true = true; + } + if (selectionConfig.isINELgt0 && !isINELgt0true) { + return; + } + + // if (selectionConfig.isINELgt0 && !mcCollision.isInelGt0()) { + // return; + // } + rEventSelection.fill(HIST("eventsCheckGen"), 2.5); + + for (const auto& collision : collisions) { + if (!selectionEvent(collision, false)) { // don't fill event cut histogram + continue; + } + multiplicity = collision.centFT0M(); + + if (cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + hInvMass.fill(HIST("h1GenMult"), multiplicity); + + int occupancy = collision.trackOccupancyInTimeRange(); + rEventSelection.fill(HIST("hOccupancy"), occupancy); + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.y()) < selectionConfig.rapidityMotherData && std::abs(mcParticle.pdgCode()) == o2::constants::physics::kK0Star892) { + hInvMass.fill(HIST("hAllKstarGenCollisisons"), multiplicity, mcParticle.pt()); + } + } + + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + hInvMass.fill(HIST("hAllGenCollisions"), multiplicity); + if (!cAllGenCollisions && !evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + double genMultiplicity = mcCollision.centFT0M(); + hInvMass.fill(HIST("h1GenMult2"), genMultiplicity); + hInvMass.fill(HIST("hAllGenCollisions1Rec"), multiplicity); + rEventSelection.fill(HIST("eventsCheckGen"), 3.5); + + for (const auto& mcParticle : mcParticles) { + + if (std::abs(mcParticle.y()) >= selectionConfig.rapidityMotherData) { + continue; + } + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mcParticle.pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if ((std::sqrt(mcParticle.e() * mcParticle.e() - mcParticle.p() * mcParticle.p())) >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + if (std::abs(mcParticle.pdgCode()) != o2::constants::physics::kK0Star892) { + continue; + } + hInvMass.fill(HIST("hAllKstarGenCollisisons1Rec"), multiplicity, mcParticle.pt()); + + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != selectionConfig.noOfDaughters) { + continue; + } + + auto passkaon = false; + auto passpion = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + + if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kKPlus) { + passkaon = true; + daughter1 = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + + } else if (std::abs(kCurrentDaughter.pdgCode()) == PDG_t::kPiPlus) { + passpion = true; + daughter2 = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massPi); + } + } + if (passkaon && passpion) { + mother = daughter1 + daughter2; // Kstar meson + hInvMass.fill(HIST("hk892GenpT"), mcParticle.pt(), multiplicity); + hInvMass.fill(HIST("hk892GenpT2"), mother.Pt(), multiplicity); + hInvMass.fill(HIST("hk892GenpTCalib1"), mcParticle.pt(), genMultiplicity); + hInvMass.fill(HIST("hk892GenpTCalib2"), mother.Pt(), genMultiplicity); + hInvMass.fill(HIST("h1genmass"), mother.M()); + } + } + } + PROCESS_SWITCH(Kstarqa, processGen, "Process Generated", false); + + void processGenPhi(EventMCGenerated::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + // void processGenPhi(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions) + { + rEventSelection.fill(HIST("eventsCheckGen"), 0.5); + + 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 == std::abs(PDG_t::kElectron) || pdgcode == std::abs(PDG_t::kMuonMinus))) { + if (std::abs(mcParticle.eta()) < 1.0) { + nChInel = nChInel + 1; + } + } + } + if (nChInel > 0 && std::abs(mcCollision.posZ()) < selectionConfig.cutzvertex) + rEventSelection.fill(HIST("eventsCheckGen"), 1.5); + + std::vector selectedEvents(collisions.size()); + int nevts = 0; + multiplicity = -1.0; + // float impactParameter = mcCollision.impactParameter(); + + bool isINELgt0true = false; + + if (pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { + isINELgt0true = true; + } + if (selectionConfig.isINELgt0 && !isINELgt0true) { + return; + } + + // if (selectionConfig.isINELgt0 && !mcCollision.isInelGt0()) { + // return; + // } + rEventSelection.fill(HIST("eventsCheckGen"), 2.5); + + for (const auto& collision : collisions) { + if (!selectionEvent(collision, false)) { // don't fill event cut histogram + continue; + } + multiplicity = collision.centFT0M(); + + if (cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + hInvMass.fill(HIST("h1GenMult"), multiplicity); + + int occupancy = collision.trackOccupancyInTimeRange(); + rEventSelection.fill(HIST("hOccupancy"), occupancy); + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.y()) < selectionConfig.rapidityMotherData && std::abs(mcParticle.pdgCode()) == o2::constants::physics::kPhi) { + hInvMass.fill(HIST("hAllKstarGenCollisisons"), multiplicity, mcParticle.pt()); + } + } + + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + hInvMass.fill(HIST("hAllGenCollisions"), multiplicity); + if (!cAllGenCollisions && !evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + double genMultiplicity = mcCollision.centFT0M(); + hInvMass.fill(HIST("h1GenMult2"), genMultiplicity); + hInvMass.fill(HIST("hAllGenCollisions1Rec"), multiplicity); + rEventSelection.fill(HIST("eventsCheckGen"), 3.5); + + for (const auto& mcParticle : mcParticles) { + + if (std::abs(mcParticle.y()) >= selectionConfig.rapidityMotherData) { + continue; + } + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mcParticle.pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if ((std::sqrt(mcParticle.e() * mcParticle.e() - mcParticle.p() * mcParticle.p())) >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + if (std::abs(mcParticle.pdgCode()) != o2::constants::physics::kPhi) { + continue; + } + hInvMass.fill(HIST("hAllKstarGenCollisisons1Rec"), multiplicity, mcParticle.pt()); + + auto kDaughters = mcParticle.daughters_as(); + if (kDaughters.size() != selectionConfig.noOfDaughters) { + continue; + } + + auto passPosKaon = false; + auto passNegKaon = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + + if (kCurrentDaughter.pdgCode() == PDG_t::kKPlus) { + passPosKaon = true; + daughter1 = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + + } else if (kCurrentDaughter.pdgCode() == PDG_t::kKMinus) { + passNegKaon = true; + daughter2 = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } + } + if (passPosKaon && passNegKaon) { + mother = daughter1 + daughter2; // Phi meson + hInvMass.fill(HIST("hk892GenpT"), mcParticle.pt(), multiplicity); + hInvMass.fill(HIST("hk892GenpT2"), mother.Pt(), multiplicity); + hInvMass.fill(HIST("hk892GenpTCalib1"), mcParticle.pt(), genMultiplicity); + hInvMass.fill(HIST("hk892GenpTCalib2"), mother.Pt(), genMultiplicity); + hInvMass.fill(HIST("h1genmass"), mother.M()); + } + } + } + PROCESS_SWITCH(Kstarqa, processGenPhi, "Process Generated for Phi meson", false); + + void processEvtLossSigLossMC(EventMCGenerated::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions) + // void processEvtLossSigLossMC(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions) + { + auto multiplicityRec = -1; + bool isSelectedEvent = false; + auto multiplicity1 = -999.; + for (const auto& RecCollision : recCollisions) { + if (!RecCollision.has_mcCollision()) + continue; + if (!selectionEvent(RecCollision, false)) // don't fill event cut histogram + continue; + // multiplicity1 = RecCollision.centFT0M(); + const auto& mcCollisionRec = RecCollision.mcCollision_as(); + multiplicityRec = mcCollisionRec.centFT0M(); + + if (cSelectMultEstimator == kFT0M) { + multiplicity1 = RecCollision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity1 = RecCollision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity1 = RecCollision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity1 = RecCollision.centFV0A(); + } else { + multiplicity1 = RecCollision.centFT0M(); // default + } + + isSelectedEvent = true; + } + + bool isINELgt0true = false; + + if (pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { + isINELgt0true = true; + } + if (selectionConfig.isINELgt0 && !isINELgt0true) { + return; + } + + if (selectionConfig.checkVzEvSigLoss && (std::abs(mcCollision.posZ()) >= selectionConfig.cutzvertex)) { + return; + } + + auto impactPar = mcCollision.impactParameter(); + auto multiplicityGen = -1; + multiplicityGen = mcCollision.centFT0M(); + hInvMass.fill(HIST("MCcorrections/hImpactParameterGen"), impactPar); + hInvMass.fill(HIST("MCcorrections/MultiplicityGen"), multiplicityGen); + + // Event loss + if (isSelectedEvent) { + hInvMass.fill(HIST("MCcorrections/hImpactParameterRec"), impactPar); + hInvMass.fill(HIST("MCcorrections/MultiplicityRec"), multiplicityGen); + hInvMass.fill(HIST("MCcorrections/MultiplicityRec2"), multiplicityRec); + hInvMass.fill(HIST("MCcorrections/hImpactParametervsMultiplicity"), impactPar, multiplicity1); + } + + // Generated MC + for (const auto& mcPart : mcParticles) { + if (std::abs(mcPart.y()) >= selectionConfig.rapidityMotherData || std::abs(mcPart.pdgCode()) != o2::constants::physics::kK0Star892) + continue; + + hInvMass.fill(HIST("MCcorrections/hSignalLossDenominator"), mcPart.pt(), multiplicityGen); + if (isSelectedEvent) { + hInvMass.fill(HIST("MCcorrections/hSignalLossNumerator"), mcPart.pt(), multiplicityGen); + } + } // end loop on gen particles + } + PROCESS_SWITCH(Kstarqa, processEvtLossSigLossMC, "Process Signal Loss, Event Loss", false); + + void processEvtLossSigLossLightIonMC(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions) + { + + // Event loss estimation + auto impactPar = mcCollision.impactParameter(); + hInvMass.fill(HIST("MCcorrections/hImpactParameterGen"), impactPar); + + bool isSelectedEvent = false; + auto centrality = -999.; + for (const auto& RecCollision : recCollisions) { + if (!RecCollision.has_mcCollision()) + continue; + if (!selectionEvent(RecCollision, false)) // don't fill event cut histogram + continue; + + if (cSelectMultEstimator == kFT0M) { + centrality = RecCollision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + centrality = RecCollision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + centrality = RecCollision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + centrality = RecCollision.centFV0A(); + } else { + centrality = RecCollision.centFT0M(); // default + } + + isSelectedEvent = true; + } + + if (isSelectedEvent) { + hInvMass.fill(HIST("MCcorrections/hImpactParameterRec"), impactPar); + hInvMass.fill(HIST("MCcorrections/hImpactParvsCentrRec"), centrality, impactPar); + } + + // Generated MC + for (const auto& mcPart : mcParticles) { + + if (std::abs(mcPart.y()) >= selectionConfig.rapidityMotherData || std::abs(mcPart.pdgCode()) != o2::constants::physics::kK0Star892) + continue; + + // signal loss estimation + hInvMass.fill(HIST("MCcorrections/hKstarGenBeforeEvtSel"), mcPart.pt(), impactPar); + if (isSelectedEvent) { + // signal loss estimation + hInvMass.fill(HIST("MCcorrections/hKstarGenAfterEvtSel"), mcPart.pt(), impactPar); + } + } // end loop on gen particles + } + PROCESS_SWITCH(Kstarqa, processEvtLossSigLossLightIonMC, "Process Signal Loss, Event Loss for Kstar in Light Ion", false); + + void processEvtLossSigLossMCPhi(EventMCGenerated::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions) + // void processEvtLossSigLossMCPhi(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& recCollisions) + { + // if (selectionConfig.isINELgt0 && !mcCollision.isInelGt0()) { + // return; + // } + + bool isINELgt0true = false; + + if (pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { + isINELgt0true = true; + } + if (selectionConfig.isINELgt0 && !isINELgt0true) { + return; + } + + if (selectionConfig.checkVzEvSigLoss && (std::abs(mcCollision.posZ()) >= selectionConfig.cutzvertex)) { + return; + } + + auto impactPar = mcCollision.impactParameter(); + auto multiplicityRec = -1; + auto multiplicityGen = -1; + multiplicityGen = mcCollision.centFT0M(); + hInvMass.fill(HIST("MCcorrections/hImpactParameterGen"), impactPar); + hInvMass.fill(HIST("MCcorrections/MultiplicityGen"), multiplicityGen); + + bool isSelectedEvent = false; + auto multiplicity1 = -999.; + for (const auto& RecCollision : recCollisions) { + if (!RecCollision.has_mcCollision()) + continue; + if (!selectionEvent(RecCollision, false)) // don't fill event cut histogram + continue; + // multiplicity1 = RecCollision.centFT0M(); + const auto& mcCollisionRec = RecCollision.mcCollision_as(); + multiplicityRec = mcCollisionRec.centFT0M(); + + if (cSelectMultEstimator == kFT0M) { + multiplicity1 = RecCollision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity1 = RecCollision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity1 = RecCollision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity1 = RecCollision.centFV0A(); + } else { + multiplicity1 = RecCollision.centFT0M(); // default + } + + isSelectedEvent = true; + } + + // Event loss + if (isSelectedEvent) { + hInvMass.fill(HIST("MCcorrections/hImpactParameterRec"), impactPar); + hInvMass.fill(HIST("MCcorrections/MultiplicityRec"), multiplicityGen); + hInvMass.fill(HIST("MCcorrections/MultiplicityRec2"), multiplicityRec); + hInvMass.fill(HIST("MCcorrections/hImpactParametervsMultiplicity"), impactPar, multiplicity1); + } + + // Generated MC + for (const auto& mcPart : mcParticles) { + if (std::abs(mcPart.y()) >= selectionConfig.rapidityMotherData || std::abs(mcPart.pdgCode()) != o2::constants::physics::kPhi) + continue; + + // signal loss estimation + hInvMass.fill(HIST("MCcorrections/hSignalLossDenominator"), mcPart.pt(), multiplicityGen); + if (isSelectedEvent) { + hInvMass.fill(HIST("MCcorrections/hSignalLossNumerator"), mcPart.pt(), multiplicityGen); + } + } // end loop on gen particles + } + PROCESS_SWITCH(Kstarqa, processEvtLossSigLossMCPhi, "Process Signal Loss, Event Loss for Phi", false); + + void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, EventMCGenerated const&) + { + + if (!collision.has_mcCollision()) { + return; + } + + double multiplicityRec = -1.0; + // multiplicityRec = collision.mcCollision_as().centFT0M(); + const auto& mcCollisionRec = collision.mcCollision_as(); + multiplicityRec = mcCollisionRec.centFT0M(); + + if (selectionConfig.isINELgt0 && !collision.isInelGt0()) { + return; + } + // multiplicity = collision.centFT0M(); + + if (cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } - PROCESS_SWITCH(kstarqa, processME, "Process Mixed event", true); + hInvMass.fill(HIST("hAllRecCollisions"), multiplicity); + hInvMass.fill(HIST("hAllRecCollisionsCalib"), multiplicityRec); - void processGen(aod::McCollision const& mcCollision, aod::McParticles& mcParticles, const soa::SmallGroups& collisions) - { - histos.fill(HIST("events_check"), 0.5); - if (std::abs(mcCollision.posZ()) < cutzvertex) { - histos.fill(HIST("events_check"), 1.5); + if (!selectionEvent(collision, true)) { // fill MC event cut histogram + return; } - 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; - } - } + + hInvMass.fill(HIST("h1RecMult"), multiplicity); + hInvMass.fill(HIST("h1RecMult2"), multiplicityRec); + + if (cQAevents) { + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); } - if (Nchinel > 0 && std::abs(mcCollision.posZ()) < cutzvertex) - histos.fill(HIST("events_check"), 2.5); - std::vector SelectedEvents(collisions.size()); - int nevts = 0; - for (const auto& collision : collisions) { - // if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cutzvertex) { - if (std::abs(collision.mcCollision().posZ()) > cutzvertex) { + + auto oldindex = -999; + for (const auto& track1 : tracks) { + if (!selectionTrack(track1)) { continue; } - if (timFrameEvsel && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (!track1.has_mcParticle()) { continue; } - if (TVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { - continue; + + if (cQAevents) { + rEventSelection.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), multiplicity, track1.pt()); + rEventSelection.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), multiplicity, track1.pt()); + } + + auto track1ID = track1.index(); + for (const auto& track2 : tracks) { + rEventSelection.fill(HIST("recMCparticles"), 0.5); + if (!track2.has_mcParticle()) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 1.5); + + if (!selectionTrack(track2)) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 2.5); + + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 3.5); + + if (track1.sign() * track2.sign() >= 0) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 4.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 && (mctrack2.pdgCode() == PDG_t::kPiPlus)) { // pion + hPID.fill(HIST("Before/h1PID_TPC_pos_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_pos_pion"), track2.tofNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTPC_Pi_before"), track2.pt(), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTOF_Pi_before"), track2.pt(), track2.tofNSigmaPi()); + } + if (cQAplots && (mctrack2.pdgCode() == PDG_t::kKPlus)) { // kaon + hPID.fill(HIST("Before/h1PID_TPC_pos_kaon"), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_pos_kaon"), track2.tofNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTPC_Ka_before"), track2.pt(), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTOF_Ka_before"), track2.pt(), track2.tofNSigmaKa()); + } + if (cQAplots && (mctrack2.pdgCode() == PDG_t::kPiMinus)) { // negative track pion + hPID.fill(HIST("Before/h1PID_TPC_neg_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_neg_pion"), track2.tofNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTPC_Pi_before"), track2.pt(), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTOF_Pi_before"), track2.pt(), track2.tofNSigmaPi()); + } + if (cQAplots && (mctrack2.pdgCode() == PDG_t::kKMinus)) { // negative track kaon + hPID.fill(HIST("Before/h1PID_TPC_neg_kaon"), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_neg_kaon"), track2.tofNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTPC_Ka_before"), track2.pt(), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTOF_Ka_before"), track2.pt(), track2.tofNSigmaKa()); + } + if (cQAplots && (std::abs(mctrack1.pdgCode()) == PDG_t::kKPlus && std::abs(mctrack2.pdgCode()) == PDG_t::kPiPlus)) { + 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("Before/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("Before/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + } + + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + + if (!mctrack2.isPhysicalPrimary()) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 5.5); + rEventSelection.fill(HIST("recMCparticles"), 6.5); + + if (selectionConfig.isPDGCheckMC && !(track1PDG == PDG_t::kPiPlus && track2PDG == PDG_t::kKPlus) && !(track1PDG == PDG_t::kKPlus && track2PDG == PDG_t::kPiPlus)) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 7.5); + + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + if (selectionConfig.isPDGCheckMC && (mothertrack1.pdgCode() != mothertrack2.pdgCode())) { + continue; + } + + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 8.5); + + if (!mothertrack1.producedByGenerator()) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 9.5); + + if (std::abs(mothertrack1.y()) >= selectionConfig.rapidityMotherData) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 10.5); + + if (selectionConfig.isPDGCheckMC && (std::abs(mothertrack1.pdgCode()) != o2::constants::physics::kK0Star892)) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 11.5); + + if (selectionConfig.isPDGCheckMC && (track1PDG == PDG_t::kPiPlus)) { + if (!applypTdepPID && !(selectionPID(track1, 0) && selectionPID(track2, 1))) { // pion and kaon + continue; + } else if (applypTdepPID && !(selectionPIDNew(track1, 0) && selectionPIDNew(track2, 1))) { // pion and kaon + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 12.5); + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(track2, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(track2, 2)) // Kaon misidentified as proton + continue; + if (selectionMID(track1, 1)) // Pion misidentified as kaon + continue; + if (selectionMID(track1, 2)) // Pion misidentified as proton + continue; + } */ + rEventSelection.fill(HIST("recMCparticles"), 13.5); + + if (std::abs(track1.rapidity(o2::track::PID::getMass(o2::track::PID::Pion))) > selectionConfig.ctrackRapidity) + continue; + + if (std::abs(track2.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + rEventSelection.fill(HIST("recMCparticles"), 14.5); + + if (cQAplots) { + hPID.fill(HIST("After/hTPCnsigPi_mult_pt"), track1.tpcNSigmaPi(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTPCnsigKa_mult_pt"), track2.tpcNSigmaKa(), multiplicity, track2.pt()); + hPID.fill(HIST("After/hTOFnsigPi_mult_pt"), track1.tofNSigmaPi(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTOFnsigKa_mult_pt"), track2.tofNSigmaKa(), multiplicity, track2.pt()); + } + + } else if (selectionConfig.isPDGCheckMC && (track1PDG == PDG_t::kKPlus)) { + if (!applypTdepPID && !(selectionPID(track1, 1) && selectionPID(track2, 0))) { // kaon and pion + continue; + } else if (applypTdepPID && !(selectionPIDNew(track1, 1) && selectionPIDNew(track2, 0))) { // kaon and pion + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 12.5); + + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(track1, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(track1, 2)) // Kaon misidentified as proton + continue; + if (selectionMID(track2, 1)) // Pion misidentified as kaon + continue; + if (selectionMID(track2, 2)) // Pion misidentified as proton + continue; + } */ + rEventSelection.fill(HIST("recMCparticles"), 13.5); + + if (std::abs(track1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + + if (std::abs(track2.rapidity(o2::track::PID::getMass(o2::track::PID::Pion))) > selectionConfig.ctrackRapidity) + continue; + rEventSelection.fill(HIST("recMCparticles"), 14.5); + + if (cQAplots) { + hPID.fill(HIST("After/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("After/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + } + } + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mothertrack1.pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if ((std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())) >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + hInvMass.fill(HIST("h1KSRecsplit"), mothertrack1.pt()); + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 15.5); + + if (!selectionPair(track1, track2)) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 16.5); + + oldindex = mothertrack1.globalIndex(); + if (track1PDG == PDG_t::kPiPlus) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPi); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + } else if (track1PDG == PDG_t::kKPlus) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massPi); + } + mother = daughter1 + daughter2; // Kstar meson + + hInvMass.fill(HIST("h2KstarRecpt2"), mothertrack1.pt(), multiplicity, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); + hInvMass.fill(HIST("h2KstarRecptCalib2"), mothertrack1.pt(), multiplicityRec, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); + + if (applyRecMotherRapidity && mother.Rapidity() >= selectionConfig.rapidityMotherData) { + continue; + } + + hInvMass.fill(HIST("h1KstarRecMass"), mother.M()); + hInvMass.fill(HIST("h2KstarRecpt1"), mother.Pt(), multiplicity, mother.M()); + hInvMass.fill(HIST("h2KstarRecptCalib1"), mother.Pt(), multiplicityRec, mother.M()); + } + } } + } + } + PROCESS_SWITCH(Kstarqa, processRec, "Process Reconstructed", false); + + void processRecPhi(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, EventMCGenerated const&) + { + + if (!collision.has_mcCollision()) { + return; + } - SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + double multiplicityRec = -1.0; + // multiplicityRec = collision.mcCollision_as().centFT0M(); + const auto& mcCollisionRec = collision.mcCollision_as(); + multiplicityRec = mcCollisionRec.centFT0M(); + + if (selectionConfig.isINELgt0 && !collision.isInelGt0()) { + return; } - SelectedEvents.resize(nevts); - histos.fill(HIST("events_check"), 3.5); - const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); + // multiplicity = collision.centFT0M(); + + if (cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + + hInvMass.fill(HIST("hAllRecCollisions"), multiplicity); + hInvMass.fill(HIST("hAllRecCollisionsCalib"), multiplicityRec); - if (!AllGenCollisions && !evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + if (!selectionEvent(collision, true)) { // fill MC event cut histogram return; } - histos.fill(HIST("events_check"), 4.5); - for (auto& mcParticle : mcParticles) { - if (std::abs(mcParticle.y()) >= 0.5) { + + hInvMass.fill(HIST("h1RecMult"), multiplicity); + hInvMass.fill(HIST("h1RecMult2"), multiplicityRec); + + if (cQAevents) { + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + } + + auto oldindex = -999; + for (const auto& track1 : tracks) { + if (!selectionTrack(track1)) { continue; } - histos.fill(HIST("events_check"), 5.5); - if (abs(mcParticle.pdgCode()) != 313) { + + if (!track1.has_mcParticle()) { continue; } - histos.fill(HIST("events_check"), 6.5); - auto kDaughters = mcParticle.daughters_as(); - if (kDaughters.size() != 2) { - continue; + + if (cQAevents) { + rEventSelection.fill(HIST("hDcaxy_cent_pt"), track1.dcaXY(), multiplicity, track1.pt()); + rEventSelection.fill(HIST("hDcaz_cent_pt"), track1.dcaZ(), multiplicity, track1.pt()); } - histos.fill(HIST("events_check"), 7.5); - auto passkaon = false; - auto passpion = false; - for (auto kCurrentDaughter : kDaughters) { - if (!kCurrentDaughter.isPhysicalPrimary()) { + + auto track1ID = track1.index(); + for (const auto& track2 : tracks) { + rEventSelection.fill(HIST("recMCparticles"), 0.5); + if (!track2.has_mcParticle()) { continue; } - histos.fill(HIST("events_check"), 8.5); - if (abs(kCurrentDaughter.pdgCode()) == 321) { - // if (kCurrentDaughter.pdgCode() == +321) { - passkaon = true; - histos.fill(HIST("events_check"), 9.5); - } else if (abs(kCurrentDaughter.pdgCode()) == 211) { - //} else if (kCurrentDaughter.pdgCode() == -321) { - passpion = true; - // histos.fill(HIST("events_check"), 10.5); + rEventSelection.fill(HIST("recMCparticles"), 1.5); + + if (!selectionTrack(track2)) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 2.5); + + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 3.5); + + if (track1.sign() * track2.sign() >= 0) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 4.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) { + hPID.fill(HIST("Before/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + // hPID.fill(HIST("Before/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("Before/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + hPID.fill(HIST("Before/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + } + // if (cQAplots && (mctrack2.pdgCode() == PDG_t::kPiPlus)) { // pion + // hPID.fill(HIST("Before/h1PID_TPC_pos_pion"), track2.tpcNSigmaPi()); + // hPID.fill(HIST("Before/h1PID_TOF_pos_pion"), track2.tofNSigmaPi()); + // hPID.fill(HIST("Before/hNsigmaTPC_Pi_before"), track2.pt(), track2.tpcNSigmaPi()); + // hPID.fill(HIST("Before/hNsigmaTOF_Pi_before"), track2.pt(), track2.tofNSigmaPi()); + // } + if (cQAplots && (mctrack2.pdgCode() == PDG_t::kKPlus)) { // kaon + hPID.fill(HIST("Before/h1PID_TPC_pos_kaon"), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_pos_kaon"), track2.tofNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTPC_Ka_before"), track2.pt(), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTOF_Ka_before"), track2.pt(), track2.tofNSigmaKa()); + } + // if (cQAplots && (mctrack2.pdgCode() == -PDG_t::kPiMinus)) { // negative track pion + // hPID.fill(HIST("Before/h1PID_TPC_neg_pion"), track2.tpcNSigmaPi()); + // hPID.fill(HIST("Before/h1PID_TOF_neg_pion"), track2.tofNSigmaPi()); + // hPID.fill(HIST("Before/hNsigmaTPC_Pi_before"), track2.pt(), track2.tpcNSigmaPi()); + // hPID.fill(HIST("Before/hNsigmaTOF_Pi_before"), track2.pt(), track2.tofNSigmaPi()); + // } + if (cQAplots && (mctrack2.pdgCode() == -PDG_t::kKMinus)) { // negative track kaon + hPID.fill(HIST("Before/h1PID_TPC_neg_kaon"), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_neg_kaon"), track2.tofNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTPC_Ka_before"), track2.pt(), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTOF_Ka_before"), track2.pt(), track2.tofNSigmaKa()); + } + if (cQAplots && (std::abs(mctrack1.pdgCode()) == PDG_t::kKPlus && std::abs(mctrack2.pdgCode()) == PDG_t::kKMinus)) { + 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()); + } + + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + + if (!mctrack2.isPhysicalPrimary()) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 5.5); + + if (selectionConfig.isPDGCheckMC && ((track1PDG != PDG_t::kKPlus) || (track2PDG != PDG_t::kKPlus))) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 6.5); + rEventSelection.fill(HIST("recMCparticles"), 7.5); + + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + if (selectionConfig.isPDGCheckMC && (mothertrack1.pdgCode() != mothertrack2.pdgCode())) { + continue; + } + + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 8.5); + + if (!mothertrack1.producedByGenerator()) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 9.5); + + if (std::abs(mothertrack1.y()) >= selectionConfig.rapidityMotherData) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 10.5); + + if (selectionConfig.isPDGCheckMC && (std::abs(mothertrack1.pdgCode()) != o2::constants::physics::kPhi)) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 11.5); + + if (!applypTdepPID && !(selectionPID(track1, 1) && selectionPID(track2, 1))) { // kaon and kaon + continue; + } else if (applypTdepPID && !(selectionPIDNew(track1, 1) && selectionPIDNew(track2, 1))) { // kaon and kaon + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 12.5); + + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(track1, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(track1, 2)) // Kaon misidentified as proton + continue; + if (selectionMID(track2, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(track2, 2)) // Kaon misidentified as proton + continue; + } */ + rEventSelection.fill(HIST("recMCparticles"), 13.5); + + if (std::abs(track1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + + if (std::abs(track2.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + rEventSelection.fill(HIST("recMCparticles"), 14.5); + if (cQAplots) { + hPID.fill(HIST("After/hTPCnsigKa_mult_pt"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + // hPID.fill(HIST("After/hTPCnsigPi_mult_pt"), track2.tpcNSigmaPi(), multiplicity, track2.pt()); + hPID.fill(HIST("After/hTOFnsigKa_mult_pt"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + // hPID.fill(HIST("After/hTOFnsigPi_mult_pt"), track2.tofNSigmaPi(), multiplicity, track2.pt()); + } + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mothertrack1.pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if ((std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())) >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ + + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + hInvMass.fill(HIST("h1KSRecsplit"), mothertrack1.pt()); + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 15.5); + + if (!selectionPair(track1, track2)) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 16.5); + + oldindex = mothertrack1.globalIndex(); + if (track1.sign() * track2.sign() < 0) { + daughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + daughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + mother = daughter1 + daughter2; // Phi meson + + hInvMass.fill(HIST("h2KstarRecpt2"), mothertrack1.pt(), multiplicity, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); + hInvMass.fill(HIST("h2KstarRecptCalib2"), mothertrack1.pt(), multiplicityRec, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); + + if (applyRecMotherRapidity && mother.Rapidity() >= selectionConfig.rapidityMotherData) { + continue; + } + + hInvMass.fill(HIST("h1KstarRecMass"), mother.M()); + hInvMass.fill(HIST("h2KstarRecpt1"), mother.Pt(), multiplicity, mother.M()); + hInvMass.fill(HIST("h2KstarRecptCalib1"), mother.Pt(), multiplicityRec, mother.M()); + } + } } - } - if (passkaon && passpion) { - // if (mcParticle.pdgCode() > 0) - histos.fill(HIST("k892Gen"), mcParticle.pt()); - // else - // histos.fill(HIST("k892GenAnti"), mcParticle.pt()); } } } - PROCESS_SWITCH(kstarqa, processGen, "Process Generated", false); + PROCESS_SWITCH(Kstarqa, processRecPhi, "Process Reconstructed", false); - void processRec(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, aod::McCollisions const& /*mcCollisions*/) + void processRec2(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const&, EventMCGenerated const&) { - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; - - histos.fill(HIST("events_checkrec"), 0.5); if (!collision.has_mcCollision()) { return; } - histos.fill(HIST("events_checkrec"), 1.5); - // if (std::abs(collision.mcCollision().posZ()) > cutzvertex || !collision.sel8()) { - if (std::abs(collision.mcCollision().posZ()) > cutzvertex) { - return; - } - histos.fill(HIST("events_checkrec"), 2.5); - if (timFrameEvsel && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + double multiplicityRec = -1.0; + const auto& mcCollisionRec = collision.mcCollision_as(); + multiplicityRec = mcCollisionRec.centFT0M(); + + if (selectionConfig.isINELgt0 && !collision.isInelGt0()) { return; } - histos.fill(HIST("events_checkrec"), 3.5); - if (TVXEvsel && (!collision.selection_bit(aod::evsel::kIsTriggerTVX))) { + // multiplicity = collision.centFT0M(); + + if (cSelectMultEstimator == kFT0M) { + multiplicity = collision.centFT0M(); + } else if (cSelectMultEstimator == kFT0A) { + multiplicity = collision.centFT0A(); + } else if (cSelectMultEstimator == kFT0C) { + multiplicity = collision.centFT0C(); + } else if (cSelectMultEstimator == kFV0A) { + multiplicity = collision.centFV0A(); + } else { + multiplicity = collision.centFT0M(); // default + } + + hInvMass.fill(HIST("hAllRecCollisions"), multiplicity); + hInvMass.fill(HIST("hAllRecCollisionsCalib"), multiplicityRec); + + if (!selectionEvent(collision, false)) { // don't fill event cut histogram return; } - histos.fill(HIST("events_checkrec"), 4.5); + + hInvMass.fill(HIST("h1RecMult"), multiplicity); + hInvMass.fill(HIST("h1RecMult2"), multiplicityRec); + + hInvMass.fill(HIST("h1RecMult"), multiplicity); auto oldindex = -999; - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } - histos.fill(HIST("events_checkrec"), 5.5); + if (!track1.has_mcParticle()) { continue; } - histos.fill(HIST("events_checkrec"), 6.5); + auto track1ID = track1.index(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { + rEventSelection.fill(HIST("recMCparticles"), 0.5); if (!track2.has_mcParticle()) { continue; } - histos.fill(HIST("events_checkrec"), 7.5); + rEventSelection.fill(HIST("recMCparticles"), 1.5); + if (!selectionTrack(track2)) { continue; } - histos.fill(HIST("events_checkrec"), 8.5); + rEventSelection.fill(HIST("recMCparticles"), 2.5); + auto track2ID = track2.index(); - if (track2ID <= track1ID) { + if (track2ID == track1ID) { continue; } - // if (!selectionPair(track1, track2)) { - // continue; - // } - histos.fill(HIST("events_checkrec"), 9.5); + rEventSelection.fill(HIST("recMCparticles"), 3.5); + if (track1.sign() * track2.sign() >= 0) { continue; } - histos.fill(HIST("events_checkrec"), 10.5); + rEventSelection.fill(HIST("recMCparticles"), 4.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 && (mctrack2.pdgCode() == PDG_t::kPiPlus)) { // pion + hPID.fill(HIST("Before/h1PID_TPC_pos_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_pos_pion"), track2.tofNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTPC_Pi_before"), track2.pt(), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTOF_Pi_before"), track2.pt(), track2.tofNSigmaPi()); + } + if (cQAplots && (mctrack2.pdgCode() == PDG_t::kKPlus)) { // kaon + hPID.fill(HIST("Before/h1PID_TPC_pos_kaon"), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_pos_kaon"), track2.tofNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTPC_Ka_before"), track2.pt(), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTOF_Ka_before"), track2.pt(), track2.tofNSigmaKa()); + } + if (cQAplots && (mctrack2.pdgCode() == -PDG_t::kPiMinus)) { // negative track pion + hPID.fill(HIST("Before/h1PID_TPC_neg_pion"), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/h1PID_TOF_neg_pion"), track2.tofNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTPC_Pi_before"), track2.pt(), track2.tpcNSigmaPi()); + hPID.fill(HIST("Before/hNsigmaTOF_Pi_before"), track2.pt(), track2.tofNSigmaPi()); + } + if (cQAplots && (mctrack2.pdgCode() == -PDG_t::kKMinus)) { // negative track kaon + hPID.fill(HIST("Before/h1PID_TPC_neg_kaon"), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/h1PID_TOF_neg_kaon"), track2.tofNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTPC_Ka_before"), track2.pt(), track2.tpcNSigmaKa()); + hPID.fill(HIST("Before/hNsigmaTOF_Ka_before"), track2.pt(), track2.tofNSigmaKa()); + } + if (cQAplots && (std::abs(mctrack1.pdgCode()) == PDG_t::kKPlus && std::abs(mctrack2.pdgCode()) == PDG_t::kPiPlus)) { + 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()); + } + if (!mctrack1.isPhysicalPrimary()) { continue; } - histos.fill(HIST("events_checkrec"), 11.5); + if (!mctrack2.isPhysicalPrimary()) { continue; } - histos.fill(HIST("events_checkrec"), 12.5); - if (!(selectionPID(track1, 1) && selectionPID(track2, 0))) { // pion and kaon + rEventSelection.fill(HIST("recMCparticles"), 5.5); + + // if (!(track1PDG == PDG_t::kKPlus && track2PDG == PDG_t::kPiPlus)) { + // continue; + // } + if (selectionConfig.isPDGCheckMC && (track1PDG != PDG_t::kKPlus)) { continue; } - histos.fill(HIST("events_checkrec"), 13.5); - if (!(track1PDG == 321 && track2PDG == 211)) { + if (selectionConfig.isPDGCheckMC && (track2PDG != PDG_t::kPiPlus)) { continue; } - // LOG(info) << "trackpdgs are:"<()) { - for (auto& mothertrack2 : mctrack2.mothers_as()) { - if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + rEventSelection.fill(HIST("recMCparticles"), 6.5); + + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + if (selectionConfig.isPDGCheckMC && (mothertrack1.pdgCode() != mothertrack2.pdgCode())) { continue; } - histos.fill(HIST("events_checkrec"), 15.5); + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { continue; } - histos.fill(HIST("events_checkrec"), 16.5); + rEventSelection.fill(HIST("recMCparticles"), 7.5); + if (!mothertrack1.producedByGenerator()) { continue; } - histos.fill(HIST("events_checkrec"), 17.5); - if (std::abs(mothertrack1.y()) >= 0.5) { + rEventSelection.fill(HIST("recMCparticles"), 8.5); + + if (std::abs(mothertrack1.y()) >= selectionConfig.rapidityMotherData) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 9.5); + + if (selectionConfig.isPDGCheckMC && (std::abs(mothertrack1.pdgCode()) != o2::constants::physics::kK0Star892)) { continue; } - histos.fill(HIST("events_checkrec"), 18.5); - if (std::abs(mothertrack1.pdgCode()) != 313) { + rEventSelection.fill(HIST("recMCparticles"), 10.5); + + if (!applypTdepPID && !(selectionPID(track1, 1) && selectionPID(track2, 0))) { + continue; + } else if (applypTdepPID && !(selectionPIDNew(track1, 1) && selectionPIDNew(track2, 0))) { continue; } + rEventSelection.fill(HIST("recMCparticles"), 11.5); + + /* if (selectionConfig.isApplyParticleMID) { + if (selectionMID(track1, 0)) // Kaon misidentified as pion + continue; + if (selectionMID(track1, 2)) // Kaon misidentified as proton + continue; + if (selectionMID(track2, 1)) // Pion misidentified as kaon + continue; + if (selectionMID(track2, 2)) // Pion misidentified as proton + continue; + } */ + rEventSelection.fill(HIST("recMCparticles"), 12.5); + + if (std::abs(track1.rapidity(o2::track::PID::getMass(o2::track::PID::Kaon))) > selectionConfig.ctrackRapidity) + continue; + + if (std::abs(track2.rapidity(o2::track::PID::getMass(o2::track::PID::Pion))) > selectionConfig.ctrackRapidity) + continue; + + rEventSelection.fill(HIST("recMCparticles"), 13.5); + + /* if (selectionConfig.isApplyCutsOnMother) { + if (mothertrack1.pt() >= selectionConfig.cMaxPtMotherCut) // excluding candidates in overflow + continue; + if ((std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())) >= selectionConfig.cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } */ if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { - histos.fill(HIST("h1KSRecsplit"), mothertrack1.pt()); + hInvMass.fill(HIST("h1KSRecsplit"), mothertrack1.pt()); continue; } + rEventSelection.fill(HIST("recMCparticles"), 14.5); + + if (!selectionPair(track1, track2)) { + continue; + } + rEventSelection.fill(HIST("recMCparticles"), 15.5); + oldindex = mothertrack1.globalIndex(); - 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(); - 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())); - //// Resonance reconstruction - lDecayDaughter1.SetXYZM(track1.px(), track1.py(), track1.pz(), massKa); - lDecayDaughter2.SetXYZM(track2.px(), track2.py(), track2.pz(), massPi); - lResonance = lDecayDaughter1 + lDecayDaughter2; - histos.fill(HIST("h3KstarRec"), motherP); - histos.fill(HIST("h1KstarRecMass"), recMass); - histos.fill(HIST("h1KstarRecpt"), mothertrack1.pt()); - histos.fill(HIST("h1genmass"), genMass); - histos.fill(HIST("h1recpt"), lResonance.Pt()); + if (track1.sign() * 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); + mother = daughter1 + daughter2; // Kstar meson + + hInvMass.fill(HIST("h2KstarRecpt2"), mothertrack1.pt(), multiplicity, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); + hInvMass.fill(HIST("h2KstarRecptCalib2"), mothertrack1.pt(), multiplicityRec, std::sqrt(mothertrack1.e() * mothertrack1.e() - mothertrack1.p() * mothertrack1.p())); + + if (applyRecMotherRapidity && mother.Rapidity() >= selectionConfig.rapidityMotherData) { + continue; + } + + hInvMass.fill(HIST("h1KstarRecMass"), mother.M()); + hInvMass.fill(HIST("h2KstarRecpt1"), mother.Pt(), multiplicity, mother.M()); + hInvMass.fill(HIST("h2KstarRecptCalib1"), mother.Pt(), multiplicityRec, mother.M()); + } } } } } } - PROCESS_SWITCH(kstarqa, processRec, "Process Reconstructed", false); + PROCESS_SWITCH(Kstarqa, processRec2, "Process Reconstructed 2", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx new file mode 100644 index 00000000000..72fb94255d1 --- /dev/null +++ b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx @@ -0,0 +1,466 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file lambda1405analysis.cxx +/// \brief Analysis task for lambda1405 via sigma kink decay +/// \author Francesco Mazzaschi + +#include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFLambda1405Table.h" + +#include "Common/Core/PID/PIDTOF.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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; +using CollisionsFullMC = soa::Join; + +struct lambda1405candidate { + // Columns for Lambda(1405) candidate + float mass = -1; // Invariant mass of the Lambda(1405) candidate + float massXi1530 = -1; // Invariant mass of the Xi(1530) candidate + float px = -1; // Px of the Lambda(1405) candidate + float py = -1; // Py of the Lambda(1405) candidate + float pz = -1; // Pz of the Lambda(1405) candidate + float pt() const { return std::sqrt(px * px + py * py); } // pT of the Lambda(1405 candidate + + bool isSigmaPlus = false; // True if compatible with Sigma+ + bool isSigmaMinus = false; // True if compatible with Sigma- + float sigmaMinusMass = -1; // Invariant mass of the Sigma- candidate + float sigmaPlusMass = -1; // Invariant mass of the Sigma+ candidate + float xiMinusMass = -1; // Invariant mass of the Xi- candidate + int sigmaSign = 0; // Sign of the Sigma candidate: 1 for matter, -1 for antimatter + float sigmaPt = -1; // pT of the Sigma daughter + float sigmaAlphaAP = -1; // Alpha of the Sigma + float sigmaQtAP = -1; // qT of the Sigma + float kinkPt = -1; // pT of the kink daughter + float kinkTPCNSigmaPi = -1; // Number of sigmas for the pion candidate from Sigma kink in TPC + float kinkTOFNSigmaPi = -1; // Number of sigmas for the pion candidate from Sigma kink in TOF + float kinkTPCNSigmaPr = -1; // Number of sigmas for the proton candidate from Sigma kink in TPC + float kinkTOFNSigmaPr = -1; // Number of sigmas for the proton candidate from Sigma kink in TOF + float dcaKinkDauToPV = -1; // DCA of the kink daughter to the primary vertex + float sigmaRadius = -1; // Radius of the Sigma decay vertex + + float piPt = -1; // pT of the pion daughter + float nSigmaTPCPi = -1; // Number of sigmas for the pion candidate + float nSigmaTOFPi = -1; // Number of sigmas for the pion candidate using TOF + int kinkDauID = 0; // ID of the pion from Sigma decay in MC + int sigmaID = 0; // ID of the Sigma candidate in MC + int piID = 0; // ID of the pion candidate in MC +}; + +struct lambda1405analysis { + int lambda1405PdgCode = 102132; // PDG code for Lambda(1405) + lambda1405candidate lambda1405Cand; // Lambda(1405) candidate structure + Produces outputDataTable; // Output table for Lambda(1405) candidates + Produces outputDataTableMC; // Output table for Lambda(1405) candidates in MC + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambda1405{"lambda1405", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // Configurable for event selection + Configurable cutzvertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cutEtaDaught{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; + Configurable cutDCAtoPVSigma{"cutDCAtoPVSigma", 0.1f, "Max DCA to primary vertex for Sigma candidates (cm)"}; + Configurable cutDCAtoPVPiFromSigma{"cutDCAtoPVPiFromSigma", 2., "Min DCA to primary vertex for pion from Sigma candidates (cm)"}; + + Configurable cutUpperMass{"cutUpperMass", 1.6f, "Upper mass cut for Lambda(1405) candidates (GeV/c^2)"}; + Configurable cutSigmaRadius{"cutSigmaRadius", 20.f, "Minimum radius for Sigma candidates (cm)"}; + Configurable cutSigmaMass{"cutSigmaMass", 0.1, "Sigma mass window (MeV/c^2)"}; + Configurable cutNITSClusPi{"cutNITSClusPi", 5, "Minimum number of ITS clusters for pion candidate"}; + Configurable cutNTPCClusPi{"cutNTPCClusPi", 90, "Minimum number of TPC clusters for pion candidate"}; + Configurable cutNSigmaTPC{"cutNSigmaTPC", 3, "NSigmaTPCPion"}; + Configurable cutNSigmaTOF{"cutNSigmaTOF", 3, "NSigmaTOFPion"}; + + Configurable fillOutputTree{"fillOutputTree", true, "If true, fill the output tree with Lambda(1405) candidates"}; + Configurable doLSBkg{"doLikeSignBkg", false, "Use like-sign background"}; + Configurable useTOF{"useTOF", false, "Use TOF for PID for pion candidates"}; + + Preslice mKinkPerCol = aod::track::collisionId; + Preslice mPerColTracks = aod::track::collisionId; + + void init(InitContext const&) + { + // Axes + const AxisSpec ptAxis{100, -10, 10, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ptPiAxis{100, -5, 5, "#it{p}_{T}^{#pi} (GeV/#it{c})"}; + const AxisSpec ptResolutionAxis{100, -0.5, 0.5, "#it{p}_{T}^{rec} - #it{p}_{T}^{gen} (GeV/#it{c})"}; + const AxisSpec massAxis{100, 1.3, 1.6, "m (GeV/#it{c}^{2})"}; + const AxisSpec massResolutionAxis{100, -0.1, 0.1, "m_{rec} - m_{gen} (GeV/#it{c}^{2})"}; + 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]"}; + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // lambda1405 to sigmaminus + rLambda1405.add("h2PtMass_0", "h2PtMass_0", {HistType::kTH2F, {ptAxis, massAxis}}); + rLambda1405.add("h2PtMassSigmaBeforeCuts_0", "h2PtMassSigmaBeforeCuts_0", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); + rLambda1405.add("h2PtMassSigma_0", "h2PtMassSigma_0", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); + rLambda1405.add("h2SigmaMassVsMass_0", "h2SigmaMassVsMass_0", {HistType::kTH2F, {massAxis, sigmaMassAxis}}); + rLambda1405.add("h2PtPiNSigma_0", "h2PtPiNSigma_0", {HistType::kTH2F, {ptPiAxis, nSigmaPiAxis}}); + rLambda1405.add("h2PtPiNSigmaTOF_0", "h2PtPiNSigmaTOF_0", {HistType::kTH2F, {ptPiAxis, nSigmaPiAxis}}); + // lambda1405 to sigmaplus + rLambda1405.add("h2PtMass_1", "h2PtMass_1", {HistType::kTH2F, {ptAxis, massAxis}}); + rLambda1405.add("h2PtMassSigmaBeforeCuts_1", "h2PtMassSigmaBeforeCuts_1", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); + rLambda1405.add("h2PtMassSigma_1", "h2PtMassSigma_1", {HistType::kTH2F, {ptAxis, sigmaMassAxis}}); + rLambda1405.add("h2SigmaMassVsMass_1", "h2SigmaMassVsMass_1", {HistType::kTH2F, {massAxis, sigmaMassAxis}}); + rLambda1405.add("h2PtPiNSigma_1", "h2PtPiNSigma_1", {HistType::kTH2F, {ptPiAxis, nSigmaPiAxis}}); + rLambda1405.add("h2PtPiNSigmaTOF_1", "h2PtPiNSigmaTOF_1", {HistType::kTH2F, {ptPiAxis, nSigmaPiAxis}}); + + if (doprocessMC) { + // Add MC histograms if needed, to sigmaminus + rLambda1405.add("h2MassResolution_0", "h2MassResolution_0", {HistType::kTH2F, {massAxis, massResolutionAxis}}); + rLambda1405.add("h2PtResolution_0", "h2PtResolution_0", {HistType::kTH2F, {ptAxis, ptResolutionAxis}}); + rLambda1405.add("h2PtMassMC_0", "h2PtMassMC_0", {HistType::kTH2F, {ptAxis, massAxis}}); + // Add MC histograms if needed, to sigmaplus + rLambda1405.add("h2MassResolution_1", "h2MassResolution_1", {HistType::kTH2F, {massAxis, massResolutionAxis}}); + rLambda1405.add("h2PtResolution_1", "h2PtResolution_1", {HistType::kTH2F, {ptAxis, ptResolutionAxis}}); + rLambda1405.add("h2PtMassMC_1", "h2PtMassMC_1", {HistType::kTH2F, {ptAxis, massAxis}}); + } + } + + float alphaAP(const std::array& momMother, const std::array& momKink) + { + std::array momMissing = {momMother[0] - momKink[0], momMother[1] - momKink[1], momMother[2] - momKink[2]}; + float lQlP = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); + float lQlN = std::inner_product(momMother.begin(), momMother.end(), momMissing.begin(), 0.f); + return (lQlP - lQlN) / (lQlP + lQlN); + } + + float qtAP(const std::array& momMother, const std::array& momKink) + { + float dp = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); + float p2V0 = std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f); + float p2A = std::inner_product(momKink.begin(), momKink.end(), momKink.begin(), 0.f); + return std::sqrt(p2A - dp * dp / p2V0); + } + + template + bool selectPiTrack(const Ttrack& candidate, bool piFromSigma) + { + if (std::abs(candidate.tpcNSigmaPi()) > cutNSigmaTPC || candidate.tpcNClsFound() < cutNTPCClusPi || std::abs(candidate.eta()) > cutEtaDaught) { + return false; + } + if (piFromSigma) { + return true; + } + + if (candidate.itsNCls() < cutNITSClusPi) { + return false; + } + + if (useTOF && !candidate.hasTOF()) { + return false; + } + + if (useTOF && std::abs(candidate.tofNSigmaPi()) > cutNSigmaTOF) { + return false; + } + + return true; // Track is selected + } + + template + bool selectProTrack(const Ttrack& candidate, bool prFromSigma) + { + if (std::abs(candidate.tpcNSigmaPr()) > cutNSigmaTPC || candidate.tpcNClsFound() < cutNTPCClusPi || std::abs(candidate.eta()) > cutEtaDaught) { + return false; + } + if (prFromSigma) { + return true; + } + if (candidate.itsNCls() < cutNITSClusPi) { + return false; + } + if (useTOF && !candidate.hasTOF()) { + return false; + } + if (useTOF && std::abs(candidate.tofNSigmaPr()) > cutNSigmaTOF) { + return false; + } + return true; // Track is selected + } + + bool selectCandidate(aod::KinkCands::iterator const& sigmaCand, TracksFull const& tracks) + { + auto kinkDauTrack = sigmaCand.trackDaug_as(); + bool isPiKink = selectPiTrack(kinkDauTrack, true); + bool isProKink = selectProTrack(kinkDauTrack, true); + if (!isPiKink && !isProKink) { + return false; + } + + if (isPiKink) { + rLambda1405.fill(HIST("h2PtMassSigmaBeforeCuts_0"), sigmaCand.mothSign() * sigmaCand.ptMoth(), sigmaCand.mSigmaMinus()); + rLambda1405.fill(HIST("h2PtPiNSigma_0"), sigmaCand.mothSign() * kinkDauTrack.pt(), kinkDauTrack.tpcNSigmaPi()); + } + if (isProKink) { + rLambda1405.fill(HIST("h2PtMassSigmaBeforeCuts_1"), sigmaCand.mothSign() * sigmaCand.ptMoth(), sigmaCand.mSigmaPlus()); + rLambda1405.fill(HIST("h2PtPiNSigma_1"), sigmaCand.mothSign() * kinkDauTrack.pt(), kinkDauTrack.tpcNSigmaPr()); + } + + lambda1405Cand.isSigmaPlus = isProKink && (sigmaCand.mSigmaPlus() > o2::constants::physics::MassSigmaPlus - cutSigmaMass && sigmaCand.mSigmaPlus() < o2::constants::physics::MassSigmaPlus + cutSigmaMass); + lambda1405Cand.isSigmaMinus = isPiKink && (sigmaCand.mSigmaMinus() > o2::constants::physics::MassSigmaMinus - cutSigmaMass && sigmaCand.mSigmaMinus() < o2::constants::physics::MassSigmaMinus + cutSigmaMass); + if (!lambda1405Cand.isSigmaPlus && !lambda1405Cand.isSigmaMinus) { + return false; + } + float sigmaRad = std::hypot(sigmaCand.xDecVtx(), sigmaCand.yDecVtx()); + if (std::abs(sigmaCand.dcaMothPv()) > cutDCAtoPVSigma || std::abs(sigmaCand.dcaDaugPv()) < cutDCAtoPVPiFromSigma || sigmaRad < cutSigmaRadius) { + return false; + } + + for (const auto& piTrack : tracks) { + if (!doLSBkg) { + if (piTrack.sign() == sigmaCand.mothSign()) { + continue; + } + } else { + if (piTrack.sign() != sigmaCand.mothSign()) { + continue; + } + } + + if (!selectPiTrack(piTrack, false)) { + continue; + } + + auto kinkDauMom = std::array{sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; + auto sigmaMom = std::array{sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; + auto piMom = std::array{piTrack.px(), piTrack.py(), piTrack.pz()}; + float invMass = RecoDecay::m(std::array{sigmaMom, piMom}, std::array{o2::constants::physics::MassSigmaMinus, o2::constants::physics::MassPiPlus}); + float invMassXiPi = RecoDecay::m(std::array{sigmaMom, kinkDauMom}, std::array{o2::constants::physics::MassXiMinus, o2::constants::physics::MassPiPlus}); + if (invMass > cutUpperMass) { + continue; + } + + lambda1405Cand.kinkDauID = kinkDauTrack.globalIndex(); + lambda1405Cand.sigmaID = sigmaCand.globalIndex(); + lambda1405Cand.piID = piTrack.globalIndex(); + + lambda1405Cand.px = sigmaMom[0] + piMom[0]; + lambda1405Cand.py = sigmaMom[1] + piMom[1]; + lambda1405Cand.pz = sigmaMom[2] + piMom[2]; + lambda1405Cand.mass = invMass; + lambda1405Cand.massXi1530 = invMassXiPi; + + lambda1405Cand.sigmaMinusMass = sigmaCand.mSigmaMinus(); + lambda1405Cand.sigmaPlusMass = sigmaCand.mSigmaPlus(); + lambda1405Cand.xiMinusMass = sigmaCand.mXiMinus(); + lambda1405Cand.sigmaSign = sigmaCand.mothSign(); + lambda1405Cand.sigmaAlphaAP = alphaAP(sigmaMom, kinkDauMom); + lambda1405Cand.sigmaQtAP = qtAP(sigmaMom, kinkDauMom); + lambda1405Cand.sigmaPt = sigmaCand.ptMoth(); + lambda1405Cand.sigmaRadius = sigmaRad; + lambda1405Cand.kinkPt = kinkDauTrack.pt(); + lambda1405Cand.kinkTPCNSigmaPi = kinkDauTrack.tpcNSigmaPi(); + lambda1405Cand.kinkTOFNSigmaPi = kinkDauTrack.tofNSigmaPi(); + lambda1405Cand.kinkTPCNSigmaPr = kinkDauTrack.tpcNSigmaPr(); + lambda1405Cand.kinkTOFNSigmaPr = kinkDauTrack.tofNSigmaPr(); + lambda1405Cand.dcaKinkDauToPV = sigmaCand.dcaDaugPv(); + + lambda1405Cand.piPt = piTrack.pt(); + lambda1405Cand.nSigmaTPCPi = piTrack.tpcNSigmaPi(); + if (useTOF) { + lambda1405Cand.nSigmaTOFPi = piTrack.tofNSigmaPi(); + } else { + lambda1405Cand.nSigmaTOFPi = -999; // Not used if TOF is not enabled + } + return true; // Candidate is selected + } + return false; // No valid pion track found + } + + template + bool checkSigmaKinkMC(const mcTrack& mcTrackSigma, const mcTrack& mcTrackKinkDau, float sigmaAbsPDG, float kinkAbsPDG, aod::McParticles const&) + { + if (std::abs(mcTrackSigma.pdgCode()) != sigmaAbsPDG || std::abs(mcTrackKinkDau.pdgCode()) != kinkAbsPDG) { + return false; // Not a valid Sigma kink decay + } + if (!mcTrackKinkDau.has_mothers()) { + return false; // No mothers found + } + // Check if the kink comes from the Sigma + bool isKinkFromSigma = false; + for (const auto& mcMother : mcTrackKinkDau.template mothers_as()) { + if (mcMother.globalIndex() == mcTrackSigma.globalIndex()) { + isKinkFromSigma = true; + break; + } + } + return isKinkFromSigma; // Return true if the kink comes from the Sigma + } + + void processData(CollisionsFull::iterator const& collision, aod::KinkCands const& kinkCands, TracksFull const& tracks) + { + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { + return; + } + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + for (const auto& sigmaCand : kinkCands) { + if (selectCandidate(sigmaCand, tracks)) { + if (lambda1405Cand.isSigmaMinus) { + rLambda1405.fill(HIST("h2PtMass_0"), lambda1405Cand.sigmaSign * lambda1405Cand.pt(), lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtMassSigma_0"), lambda1405Cand.sigmaSign * lambda1405Cand.sigmaPt, lambda1405Cand.sigmaMinusMass); + rLambda1405.fill(HIST("h2SigmaMassVsMass_0"), lambda1405Cand.mass, lambda1405Cand.sigmaMinusMass); + rLambda1405.fill(HIST("h2PtPiNSigmaTOF_0"), lambda1405Cand.sigmaSign * lambda1405Cand.piPt, lambda1405Cand.nSigmaTOFPi); + } + if (lambda1405Cand.isSigmaPlus) { + rLambda1405.fill(HIST("h2PtMass_1"), lambda1405Cand.sigmaSign * lambda1405Cand.pt(), lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtMassSigma_1"), lambda1405Cand.sigmaSign * lambda1405Cand.sigmaPt, lambda1405Cand.sigmaPlusMass); + rLambda1405.fill(HIST("h2SigmaMassVsMass_1"), lambda1405Cand.mass, lambda1405Cand.sigmaPlusMass); + rLambda1405.fill(HIST("h2PtPiNSigmaTOF_1"), lambda1405Cand.sigmaSign * lambda1405Cand.piPt, lambda1405Cand.nSigmaTOFPi); + } + if (fillOutputTree) { + outputDataTable(lambda1405Cand.px, lambda1405Cand.py, lambda1405Cand.pz, + lambda1405Cand.mass, lambda1405Cand.massXi1530, + lambda1405Cand.sigmaMinusMass, lambda1405Cand.sigmaPlusMass, lambda1405Cand.xiMinusMass, + lambda1405Cand.sigmaPt, lambda1405Cand.sigmaAlphaAP, lambda1405Cand.sigmaQtAP, lambda1405Cand.sigmaRadius, + lambda1405Cand.kinkPt, + lambda1405Cand.kinkTPCNSigmaPi, lambda1405Cand.kinkTOFNSigmaPi, + lambda1405Cand.kinkTPCNSigmaPr, lambda1405Cand.kinkTOFNSigmaPr, + lambda1405Cand.dcaKinkDauToPV, + lambda1405Cand.nSigmaTPCPi, lambda1405Cand.nSigmaTOFPi); + } + } + } + } + PROCESS_SWITCH(lambda1405analysis, processData, "Data processing", true); + + void processMC(CollisionsFullMC const& collisions, aod::KinkCands const& kinkCands, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC, TracksFull const& tracks) + { + for (const auto& collision : collisions) { + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { + continue; + } + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + auto sigmaCandsPerCol = kinkCands.sliceBy(mKinkPerCol, collision.globalIndex()); + auto tracksPerCol = tracks.sliceBy(mPerColTracks, collision.globalIndex()); + for (const auto& sigmaCand : sigmaCandsPerCol) { + if (selectCandidate(sigmaCand, tracksPerCol)) { + // Do MC association + auto mcLabPiKink = trackLabelsMC.rawIteratorAt(lambda1405Cand.kinkDauID); + auto mcLabSigma = trackLabelsMC.rawIteratorAt(lambda1405Cand.sigmaID); + auto mcLabPi = trackLabelsMC.rawIteratorAt(lambda1405Cand.piID); + if (!mcLabSigma.has_mcParticle() || mcLabPiKink.has_mcParticle() || mcLabPi.has_mcParticle()) { + continue; // Skip if no valid MC association + } + auto mcTrackKink = mcLabPiKink.mcParticle_as(); + auto mcTrackSigma = mcLabSigma.mcParticle_as(); + auto mcTrackPi = mcLabPi.mcParticle_as(); + + bool isSigmaMinusKink = checkSigmaKinkMC(mcTrackSigma, mcTrackKink, 3122, 211, particlesMC); + bool isSigmaPlusToPiKink = checkSigmaKinkMC(mcTrackSigma, mcTrackKink, 3222, 211, particlesMC); + bool isSigmaPlusToPrKink = checkSigmaKinkMC(mcTrackSigma, mcTrackKink, 3222, 2212, particlesMC); + + if (!isSigmaMinusKink && !isSigmaPlusToPiKink && !isSigmaPlusToPrKink) { + continue; // Skip if not a valid Sigma kink decay + } + + if (std::abs(mcTrackPi.pdgCode()) != 211) { + continue; // Skip if not a valid pion candidate + } + + if (!mcTrackSigma.has_mothers() || !mcTrackPi.has_mothers()) { + continue; // Skip if no mothers found + } + + // check that labpi and labsigma have the same mother (a lambda1405 candidate) + int lambda1405Id = -1; + for (const auto& piMother : mcTrackPi.mothers_as()) { + for (const auto& sigmaMother : mcTrackSigma.mothers_as()) { + if (piMother.globalIndex() == sigmaMother.globalIndex() && std::abs(piMother.pdgCode()) == lambda1405PdgCode) { + lambda1405Id = piMother.globalIndex(); + break; // Found the mother, exit loop + } + } + } + if (lambda1405Id == -1) { + continue; // Skip if the Sigma and pion do not share the same lambda1405 candidate + } + auto lambda1405Mother = particlesMC.rawIteratorAt(lambda1405Id); + float lambda1405Mass = std::sqrt(lambda1405Mother.e() * lambda1405Mother.e() - lambda1405Mother.p() * lambda1405Mother.p()); + if (lambda1405Cand.isSigmaMinus) { + rLambda1405.fill(HIST("h2PtMass_0"), lambda1405Cand.sigmaSign * lambda1405Cand.pt(), lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtMassSigma_0"), lambda1405Cand.sigmaSign * lambda1405Cand.sigmaPt, lambda1405Cand.sigmaMinusMass); + rLambda1405.fill(HIST("h2SigmaMassVsMass_0"), lambda1405Cand.mass, lambda1405Cand.sigmaMinusMass); + rLambda1405.fill(HIST("h2PtPiNSigma_0"), lambda1405Cand.piPt, lambda1405Cand.nSigmaTPCPi); + rLambda1405.fill(HIST("h2MassResolution_0"), lambda1405Mass, lambda1405Mass - lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtResolution_0"), lambda1405Cand.pt(), lambda1405Cand.pt() - lambda1405Mother.pt()); + } + if (lambda1405Cand.isSigmaPlus) { + rLambda1405.fill(HIST("h2PtMass_1"), lambda1405Cand.sigmaSign * lambda1405Cand.pt(), lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtMassSigma_1"), lambda1405Cand.sigmaSign * lambda1405Cand.sigmaPt, lambda1405Cand.sigmaPlusMass); + rLambda1405.fill(HIST("h2SigmaMassVsMass_1"), lambda1405Cand.mass, lambda1405Cand.sigmaPlusMass); + rLambda1405.fill(HIST("h2PtPiNSigma_1"), lambda1405Cand.piPt, lambda1405Cand.nSigmaTPCPi); + rLambda1405.fill(HIST("h2MassResolution_1"), lambda1405Mass, lambda1405Mass - lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtResolution_1"), lambda1405Cand.pt(), lambda1405Cand.pt() - lambda1405Mother.pt()); + } + + if (fillOutputTree) { + outputDataTableMC(lambda1405Cand.px, lambda1405Cand.py, lambda1405Cand.pz, + lambda1405Cand.mass, lambda1405Cand.massXi1530, + lambda1405Cand.sigmaMinusMass, lambda1405Cand.sigmaPlusMass, lambda1405Cand.xiMinusMass, + lambda1405Cand.sigmaPt, lambda1405Cand.sigmaAlphaAP, lambda1405Cand.sigmaQtAP, lambda1405Cand.sigmaRadius, + lambda1405Cand.kinkPt, + lambda1405Cand.kinkTPCNSigmaPi, lambda1405Cand.kinkTOFNSigmaPi, + lambda1405Cand.kinkTPCNSigmaPr, lambda1405Cand.kinkTOFNSigmaPr, + lambda1405Cand.dcaKinkDauToPV, + lambda1405Cand.nSigmaTPCPi, lambda1405Cand.nSigmaTOFPi, + lambda1405Mother.pt(), lambda1405Mass, mcTrackSigma.pdgCode(), mcTrackKink.pdgCode()); + } + } + } + } + + // Loop over generated particles to fill MC histograms + for (const auto& mcPart : particlesMC) { + if (std::abs(mcPart.pdgCode()) != lambda1405PdgCode) { + continue; // Only consider Lambda(1405) candidates + } + + if (!mcPart.has_daughters()) { + continue; // Skip if no daughters + } + + // Check if the Lambda(1405) has a Sigma daughter + bool hasSigmaDaughter = false; + int dauPdgCode = 0; + for (const auto& daughter : mcPart.daughters_as()) { + if (std::abs(daughter.pdgCode()) == 3122 || std::abs(daughter.pdgCode()) == 3222) { // Sigma PDG code + hasSigmaDaughter = true; + dauPdgCode = daughter.pdgCode(); + break; // Found a Sigma daughter, exit loop + } + } + if (!hasSigmaDaughter) { + continue; // Skip if no Sigma daughter found + } + + float mcMass = std::sqrt(mcPart.e() * mcPart.e() - mcPart.p() * mcPart.p()); + dauPdgCode ? rLambda1405.fill(HIST("h2PtMassMC_0"), mcPart.pt(), mcMass) : rLambda1405.fill(HIST("h2PtMassMC_1"), mcPart.pt(), mcMass); + } + } + PROCESS_SWITCH(lambda1405analysis, processMC, "MC processing", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx b/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx index d7303f3e5fd..3062ceb1ffb 100644 --- a/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx @@ -13,18 +13,21 @@ /// \brief Invariant Mass Reconstruction of Lambda(1520) Resonance /// \author Yash Patley -#include -#include +#include "PWGLF/DataModel/LFResonanceTables.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisTask.h" + +#include "CommonConstants/PhysicsConstants.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Common/Core/RecoDecay.h" + +#include +#include + +#include using namespace o2; using namespace o2::framework; @@ -515,7 +518,7 @@ struct lambdaAnalysis { } } - 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/lambda1520_PbPb.cxx b/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx index 63f1c7d58d5..16c44ab832b 100644 --- a/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520_PbPb.cxx @@ -13,24 +13,26 @@ /// /// Invariant Mass Reconstruction of Lambda(1520) Resonance. /// /// \author Yash Patley -/// \author Nasir Mehdi Malik +/// \author Nasir Mehdi Malik +#include "PWGLF/DataModel/LFResonanceTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" #include #include #include #include + #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/LFResonanceTables.h" -#include "PWGLF/DataModel/LFResonanceTablesMergeDF.h" -#include "CommonConstants/PhysicsConstants.h" +#include using namespace o2; using namespace o2::framework; @@ -42,6 +44,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"}; @@ -69,10 +73,8 @@ struct lambdaAnalysis_pb { 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 cRejNsigmaTpcEl{"cRejNsigmaTpcEl", 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 cRejNsigmakTpcEl{"cRejNsigmakTpcEl", 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"}; @@ -104,7 +106,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}; @@ -124,8 +126,9 @@ struct lambdaAnalysis_pb { 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(%)", kTH3F, {axisCent, axisVz, axisEP}); } @@ -138,49 +141,45 @@ 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/hd_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}); histos.add("QAafter/Proton/h2d_pr_nsigma_tpc_pt", " Protons", kTH2F, {axisPt_pid, axisTPCNsigma}); histos.add("QAafter/Proton/h2d_Prpi_nsigma_tpc_p", " Protons pion", kTH2F, {axisPt_pid, axisTPCNsigma}); histos.add("QAafter/Proton/h2d_Prka_nsigma_tpc_p", " Protons kaon", kTH2F, {axisPt_pid, axisTPCNsigma}); - histos.add("QAafter/Proton/h2d_Prel_nsigma_tpc_p", " Protons electron", kTH2F, {axisPt_pid, axisTPCNsigma}); histos.add("QAafter/Proton/h2d_pr_nsigma_tpc_p", " Protons", kTH2F, {axisP_pid, axisTPCNsigma}); histos.add("QAafter/Proton/h2d_pr_nsigma_tof_pt", " Protons", kTH2F, {axisPt_pid, axisTOFNsigma}); histos.add("QAafter/Proton/h2d_pr_nsigma_tof_p", " Protons", kTH2F, {axisP_pid, axisTOFNsigma}); 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_Prel_nsigma_tof_p", " Protons electron", 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/hd_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}); histos.add("QAafter/Kaon/h2d_Kapi_nsigma_tpc_p", " Kaons pion", kTH2F, {axisPt_pid, axisTPCNsigma}); histos.add("QAafter/Kaon/h2d_Kapr_nsigma_tpc_p", " Kaons proton", kTH2F, {axisP_pid, axisTPCNsigma}); - histos.add("QAafter/Kaon/h2d_Kael_nsigma_tpc_p", " Kaons electron", kTH2F, {axisP_pid, axisTPCNsigma}); histos.add("QAafter/Kaon/h2d_ka_nsigma_tpc_pt", " Kaons", kTH2F, {axisPt_pid, axisTPCNsigma}); histos.add("QAafter/Kaon/h2d_ka_nsigma_tpc_p", " Kaons", kTH2F, {axisP_pid, axisTPCNsigma}); histos.add("QAafter/Kaon/h2d_ka_nsigma_tof_pt", " Kaons", kTH2F, {axisPt_pid, axisTOFNsigma}); histos.add("QAafter/Kaon/h2d_ka_nsigma_tof_p", " Kaons", kTH2F, {axisP_pid, axisTOFNsigma}); histos.add("QAafter/Kaon/h2d_Kapi_nsigma_tof_p", " Kaons pion", kTH2F, {axisP_pid, axisTOFNsigma}); histos.add("QAafter/Kaon/h2d_Kapr_nsigma_tof_p", " Kaons proton", kTH2F, {axisP_pid, axisTOFNsigma}); - histos.add("QAafter/Kaon/h2d_Kael_nsigma_tof_p", " Kaons electron", 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}); // 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) { @@ -239,16 +238,13 @@ struct lambdaAnalysis_pb { float tpcNsigmaPi = std::abs(candidate.tpcNSigmaPi()); float tpcNsigmaKa = std::abs(candidate.tpcNSigmaKa()); float tpcNsigmaPr = std::abs(candidate.tpcNSigmaPr()); - float tpcNsigmaEl = std::abs(candidate.tpcNSigmaEl()); float tofNsigmaPi = std::abs(candidate.tofNSigmaPi()); float tofNsigmaKa = std::abs(candidate.tofNSigmaKa()); float tofNsigmaPr = std::abs(candidate.tofNSigmaPr()); - float tofNsigmaEl = std::abs(candidate.tofNSigmaEl()); float tpcTofNsigmaPi = tpcNsigmaPi * tpcNsigmaPi + tofNsigmaPi * tofNsigmaPi; float tpcTofNsigmaKa = tpcNsigmaKa * tpcNsigmaKa + tofNsigmaKa * tofNsigmaKa; float tpcTofNsigmaPr = tpcNsigmaPr * tpcNsigmaPr + tofNsigmaPr * tofNsigmaPr; - float tpcTofNsigmaEl = tpcNsigmaEl * tpcNsigmaEl + tofNsigmaEl * tofNsigmaEl; float combinedCut = nsigmaCutCombinedProton * nsigmaCutCombinedProton; float combinedRejCut = cRejNsigmaTof * cRejNsigmaTpc; @@ -258,17 +254,17 @@ struct lambdaAnalysis_pb { 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 && tofNsigmaEl > cRejNsigmaTof)) + if (p >= tofPIDp[i] && p < tofPIDp[i + 1] && (tofNsigmaPr < tofPIDcut[i] && tofNsigmaPi > cRejNsigmaTof && tofNsigmaKa > cRejNsigmaTof)) tofPIDPassed = true; } if (candidate.tpcNSigmaPr() < minnsigmatpctofPr) return false; - if (tpcNsigmaPr < cMaxTPCnSigmaProton && tpcNsigmaPi > cRejNsigmaTpcVeto && tpcNsigmaKa > cRejNsigmaTpcVeto && tpcNsigmaEl > cRejNsigmaTpcVeto) + if (tpcNsigmaPr < cMaxTPCnSigmaProton && tpcNsigmaPi > cRejNsigmaTpcVeto && tpcNsigmaKa > cRejNsigmaTpcVeto) tpcPIDPassed = true; } // circular cut - if ((nsigmaCutCombinedProton > 0) && p >= cPMin && (tpcTofNsigmaPr < combinedCut && tpcTofNsigmaPi > combinedRejCut && tpcTofNsigmaKa > combinedRejCut && tpcTofNsigmaEl > combinedRejCut)) { + if ((nsigmaCutCombinedProton > 0) && p >= cPMin && (tpcTofNsigmaPr < combinedCut && tpcTofNsigmaPi > combinedRejCut && tpcTofNsigmaKa > combinedRejCut)) { tofPIDPassed = true; tpcPIDPassed = true; } @@ -283,7 +279,7 @@ struct lambdaAnalysis_pb { 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 > cRejNsigmaTpcPi && tpcNsigmaKa > cRejNsigmaTpcKa && tpcNsigmaEl > cRejNsigmaTpcEl)) { + if (p >= tpcPIDp[i] && p < tpcPIDp[i + 1] && (tpcNsigmaPr < tpcPIDcut[i] && tpcNsigmaPi > cRejNsigmaTpcPi && tpcNsigmaKa > cRejNsigmaTpcKa)) { tpcPIDPassed = true; } } @@ -307,16 +303,13 @@ struct lambdaAnalysis_pb { float tpcNsigmaPi = std::abs(candidate.tpcNSigmaPi()); float tpcNsigmaKa = std::abs(candidate.tpcNSigmaKa()); float tpcNsigmaPr = std::abs(candidate.tpcNSigmaPr()); - float tpcNsigmaEl = std::abs(candidate.tpcNSigmaEl()); float tofNsigmaPi = std::abs(candidate.tofNSigmaPi()); float tofNsigmaKa = std::abs(candidate.tofNSigmaKa()); float tofNsigmaPr = std::abs(candidate.tofNSigmaPr()); - float tofNsigmaEl = std::abs(candidate.tofNSigmaEl()); float tpcTofNsigmaPi = tpcNsigmaPi * tpcNsigmaPi + tofNsigmaPi * tofNsigmaPi; float tpcTofNsigmaKa = tpcNsigmaKa * tpcNsigmaKa + tofNsigmaKa * tofNsigmaKa; float tpcTofNsigmaPr = tpcNsigmaPr * tpcNsigmaPr + tofNsigmaPr * tofNsigmaPr; - float tpcTofNsigmaEl = tpcNsigmaEl * tpcNsigmaEl + tofNsigmaEl * tofNsigmaEl; float combinedCut = nsigmaCutCombinedKaon * nsigmaCutCombinedKaon; float combinedRejCut = cRejNsigmaTpc * cRejNsigmaTof; @@ -326,17 +319,17 @@ struct lambdaAnalysis_pb { 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 && tofNsigmaEl > cRejNsigmaTof)) + if (p >= tofPIDp[i] && p < tofPIDp[i + 1] && (tofNsigmaKa < tofPIDcut[i] && tofNsigmaPi > cRejNsigmaTof && tofNsigmaPr > cRejNsigmaTof)) tofPIDPassed = true; } if (candidate.tpcNSigmaKa() < minnsigmatpctofKa) return false; - if (tpcNsigmaKa < cMaxTPCnSigmaKaon && tpcNsigmaPi > cRejNsigmaTpcVeto && tpcNsigmaPr > cRejNsigmaTpcVeto && tpcNsigmaEl > cRejNsigmaTpcVeto) + if (tpcNsigmaKa < cMaxTPCnSigmaKaon && tpcNsigmaPi > cRejNsigmaTpcVeto && tpcNsigmaPr > cRejNsigmaTpcVeto) tpcPIDPassed = true; } // circular - if ((nsigmaCutCombinedKaon > 0) && p >= cPMin && (tpcTofNsigmaKa < combinedCut && tpcTofNsigmaPi > combinedRejCut && tpcTofNsigmaPr > combinedRejCut && tpcTofNsigmaEl > combinedRejCut)) { + if ((nsigmaCutCombinedKaon > 0) && p >= cPMin && (tpcTofNsigmaKa < combinedCut && tpcTofNsigmaPi > combinedRejCut && tpcTofNsigmaPr > combinedRejCut)) { tofPIDPassed = true; tpcPIDPassed = true; } @@ -352,7 +345,7 @@ struct lambdaAnalysis_pb { 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 > cRejNsigmakTpcPi && tpcNsigmaPr > cRejNsigmakTpcPr && tpcNsigmaEl > cRejNsigmakTpcEl)) { + if (p >= tpcPIDp[i] && p < tpcPIDp[i + 1] && (tpcNsigmaKa < tpcPIDcut[i] && tpcNsigmaPi > cRejNsigmakTpcPi && tpcNsigmaPr > cRejNsigmakTpcPr)) { tpcPIDPassed = true; } } @@ -364,7 +357,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; @@ -396,7 +389,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); @@ -427,13 +419,12 @@ struct lambdaAnalysis_pb { auto _tpcnsigmaPr = trkPr.tpcNSigmaPr(); // Proton - histos.fill(HIST("QAafter/Proton/hd_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()); histos.fill(HIST("QAafter/Proton/h2d_Prpi_nsigma_tpc_p"), p_ptot, trkPr.tpcNSigmaPi()); histos.fill(HIST("QAafter/Proton/h2d_Prka_nsigma_tpc_p"), p_ptot, trkPr.tpcNSigmaKa()); - histos.fill(HIST("QAafter/Proton/h2d_Prel_nsigma_tpc_p"), p_ptot, trkPr.tpcNSigmaEl()); histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tpc_p"), p_ptot, _tpcnsigmaPr); histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tpc_pt"), _ptPr, _tpcnsigmaPr); if (!cUseTpcOnly && trkPr.hasTOF()) { @@ -442,20 +433,18 @@ struct lambdaAnalysis_pb { histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tof_pt"), _ptPr, _tofnsigmaPr); histos.fill(HIST("QAafter/Proton/h2d_Prpi_nsigma_tof_p"), p_ptot, trkPr.tofNSigmaPi()); histos.fill(HIST("QAafter/Proton/h2d_Prka_nsigma_tof_p"), p_ptot, trkPr.tofNSigmaKa()); - histos.fill(HIST("QAafter/Proton/h2d_Prel_nsigma_tof_p"), p_ptot, trkPr.tofNSigmaEl()); histos.fill(HIST("QAafter/Proton/h2d_pr_nsigma_tof_vs_tpc"), _tpcnsigmaPr, _tofnsigmaPr); } auto _ptKa = trkKa.pt(); auto _tpcnsigmaKa = trkKa.tpcNSigmaKa(); // Kaon - histos.fill(HIST("QAafter/Kaon/hd_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()); histos.fill(HIST("QAafter/Kaon/h2d_Kapi_nsigma_tpc_p"), k_ptot, trkKa.tpcNSigmaPi()); histos.fill(HIST("QAafter/Kaon/h2d_Kapr_nsigma_tpc_p"), k_ptot, trkKa.tpcNSigmaPr()); - histos.fill(HIST("QAafter/Kaon/h2d_Kael_nsigma_tpc_p"), k_ptot, trkKa.tpcNSigmaEl()); histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tpc_p"), k_ptot, _tpcnsigmaKa); histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tpc_pt"), _ptKa, _tpcnsigmaKa); if (!cUseTpcOnly && trkKa.hasTOF()) { @@ -464,7 +453,6 @@ struct lambdaAnalysis_pb { histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tof_pt"), _ptKa, _tofnsigmaKa); histos.fill(HIST("QAafter/Kaon/h2d_Kapi_nsigma_tof_p"), k_ptot, trkKa.tofNSigmaPi()); histos.fill(HIST("QAafter/Kaon/h2d_Kapr_nsigma_tof_p"), k_ptot, trkKa.tofNSigmaPr()); - histos.fill(HIST("QAafter/Kaon/h2d_Kael_nsigma_tof_p"), k_ptot, trkKa.tofNSigmaEl()); histos.fill(HIST("QAafter/Kaon/h2d_ka_nsigma_tof_vs_tpc"), _tpcnsigmaKa, _tofnsigmaKa); } } @@ -495,22 +483,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); } } } @@ -518,14 +506,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); } } @@ -551,14 +539,14 @@ 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()); } @@ -569,7 +557,7 @@ struct lambdaAnalysis_pb { { auto mult = collision.cent(); - histos.fill(HIST("Event/h1d_ft0_mult_percentile"), mult); + histos.fill(HIST("Event/h1d_ft0_mult_percentile"), mult, 100); fillDataHistos(tracks, tracks, mult); // get MC pT-spectra @@ -597,7 +585,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 @@ -616,7 +603,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 @@ -637,7 +627,6 @@ 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(), c1.evtPl()); fillDataHistos(t1, t2, c1.cent()); @@ -646,7 +635,7 @@ struct lambdaAnalysis_pb { 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; @@ -656,15 +645,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) @@ -676,28 +668,29 @@ 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(), c1.evtPl()); - fillDataHistos(t1, t2, c1.cent()); + 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(), c1.evtPl()); fillDataHistos(t1, t2, c1.cent()); diff --git a/PWGLF/Tasks/Resonances/lambda1520analysis.cxx b/PWGLF/Tasks/Resonances/lambda1520analysis.cxx index 5884c7b067a..3e6749d451d 100644 --- a/PWGLF/Tasks/Resonances/lambda1520analysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520analysis.cxx @@ -15,6 +15,7 @@ #include "TLorentzVector.h" #include "TF1.h" +#include "TRandom3.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "PWGLF/DataModel/LFResonanceTables.h" @@ -25,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; @@ -39,24 +40,18 @@ struct lambda1520analysis { // switches Configurable cEtaAssym{"cEtaAssym", false, "Turn on/off EtaAssym calculation"}; Configurable isFilladditionalQA{"isFilladditionalQA", false, "Turn on/off additional QA plots"}; - Configurable cAddlTrackcut{"cAddlTrackcut", false, "Switch to turn on/off Additional track cut"}; 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 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 additionalEvsel{"additionalEvsel", true, "Additional event selcection"}; 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 cfgRatioTPCRowsOverFindableCls{"cfgRatioTPCRowsOverFindableCls", 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 cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; Configurable cMinTPCncr{"cMinTPCncr", 70, "Minimum number of TPC X rows"}; // DCA Selections @@ -70,23 +65,26 @@ struct lambda1520analysis { 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 cfgHasITS{"cfgHasITS", false, "Require ITS"}; - Configurable cfgHasTPC{"cfgHasTPC", false, "Require TPC"}; 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 tof_at_high_pt{"tof_at_high_pt", false, "Use TOF at high pT"}; - Configurable cByPassTOF{"cByPassTOF", false, "By pass TOF PID selection"}; // By pass TOF PID selection + 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 @@ -98,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 @@ -111,8 +111,8 @@ struct lambda1520analysis { /// 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, 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"}; + 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"}; @@ -121,24 +121,33 @@ struct lambda1520analysis { 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"}; - // Event selection cuts - (Temporary, need to fix!) - TF1* fMultPVCutLow = nullptr; - TF1* fMultPVCutHigh = nullptr; - TF1* fMultCutLow = nullptr; - TF1* fMultCutHigh = nullptr; - TF1* fMultMultPVCut = nullptr; + // 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&) { @@ -153,6 +162,7 @@ struct lambda1520analysis { 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 @@ -198,16 +208,10 @@ struct lambda1520analysis { 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_before", "Centrality vs Global-Tracks", kTH2F, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}}); - histos.add("MultCalib/centgloka_before", "Centrality vs Global-Tracks", kTH2F, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}}); - histos.add("MultCalib/GloPVpr_before", "Global tracks vs PV tracks", kTH2F, {{500, 0, 5000, "Global tracks"}, {500, 0, 5000, "PV tracks"}}); - histos.add("MultCalib/GloPVka_before", "Global tracks vs PV tracks", kTH2F, {{500, 0, 5000, "Global tracks"}, {500, 0, 5000, "PV tracks"}}); - - // Multiplicity correlation calibrations - histos.add("MultCalib/centglopr_after", "Centrality vs Global-Tracks", kTH2F, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}}); - histos.add("MultCalib/centgloka_after", "Centrality vs Global-Tracks", kTH2F, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}}); - histos.add("MultCalib/GloPVpr_after", "Global tracks vs PV tracks", kTH2F, {{500, 0, 5000, "Global tracks"}, {500, 0, 5000, "PV tracks"}}); - histos.add("MultCalib/GloPVka_after", "Global tracks vs PV tracks", kTH2F, {{500, 0, 5000, "Global tracks"}, {500, 0, 5000, "PV tracks"}}); + 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 @@ -236,26 +240,49 @@ struct lambda1520analysis { 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 - 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 + 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 (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::kTH3F, {axisMult, axisPt, axisMassLambda1520}); - histos.add("Result/Data/h3antilambda1520invmass", "Invariant mass of #Lambda(1520) K^{#mp}p^{#pm}", 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 + 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) { - 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}); + 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::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", kTH3F, {axisMult, axisPt, axisMassLambda1520}); - histos.add("Result/Data/h3lambda1520invmassME_DSAnti", "Invariant mass of #Lambda(1520) mixed event DSAnti", kTH3F, {axisMult, axisPt, 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}); } } @@ -265,16 +292,16 @@ struct lambda1520analysis { 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}); + 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}); } } //} @@ -284,10 +311,10 @@ struct lambda1520analysis { 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}}); @@ -295,51 +322,19 @@ struct lambda1520analysis { 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/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}); + 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}); + } } - 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); - } // Print output histograms statistics LOG(info) << "Size of the histograms in spectraTOF"; histos.print(); } - 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; - } - double massKa = MassKaonCharged; double massPr = MassProton; @@ -358,22 +353,10 @@ 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() < cfgRatioTPCRowsOverFindableCls) - return false; - if (track.itsChi2NCl() > cMaxChi2ITScut) - return false; - if (track.tpcChi2NCl() > cMaxChi2TPCcut) - return false; - if (track.itsNCls() < cfgITScluster) - 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()) @@ -382,11 +365,11 @@ struct lambda1520analysis { return false; if (cfgGlobalTrack && !track.isGlobalTrack()) return false; - if (cfgHasITS && !track.hasITS()) + if (cfgUseITSRefit && !track.passedITSRefit()) return false; - if (cfgHasTPC && !track.hasTPC()) + if (cfgUseTPCRefit && !track.passedTPCRefit()) return false; - if (cfgHasTOF && !track.hasTOF()) + if (track.tpcNClsCrossedRows() < cMinTPCncr) return false; return true; @@ -396,7 +379,7 @@ struct lambda1520analysis { template bool selectionnewPIDProton(const T& candidate) { - if (tof_at_high_pt) { + if (tofAtHighPt) { if (candidate.hasTOF() && (std::abs(candidate.tofNSigmaPr()) < cMaxTOFnSigmaProton)) { return true; } @@ -448,7 +431,7 @@ struct lambda1520analysis { template bool selectionnewPIDKaon(const T& candidate) { - if (tof_at_high_pt) { + if (tofAtHighPt) { if (candidate.hasTOF() && (std::abs(candidate.tofNSigmaKa()) < cMaxTOFnSigmaKaon)) { return true; } @@ -505,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; + } } } } @@ -551,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; + } } } } @@ -595,27 +616,27 @@ struct lambda1520analysis { bool selectionPIDProtonFixed(const T& candidate) { if (candidate.hasTOF()) { - if (candidate.pt() < 1.5 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && TMath::Abs(candidate.tofNSigmaPr()) < 4.0) { + 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() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -3.0 && candidate.tofNSigmaPr() < 4.0) { + 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() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -2.0 && candidate.tofNSigmaPr() < 4.0) { + 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() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -1.5 && candidate.tofNSigmaPr() < 3.0) { + 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() && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0 && candidate.tofNSigmaPr() > -1.0 && candidate.tofNSigmaPr() < 2.0) { + 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 && TMath::Abs(candidate.tpcNSigmaPr()) < 4.0) { + if (candidate.pt() < 0.4 && std::abs(candidate.tpcNSigmaPr()) < 4.0) { return true; } - if (candidate.pt() >= 0.4 && candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaPr()) < 3.0) { + 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) { @@ -635,24 +656,24 @@ struct lambda1520analysis { bool selectionPIDKaonFixed(const T& candidate) { if (candidate.hasTOF()) { - if (candidate.pt() < 0.8 && candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < 3.0 && TMath::Abs(candidate.tofNSigmaKa()) < 4.0) { + 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() && TMath::Abs(candidate.tpcNSigmaKa()) < 3.0 && candidate.tofNSigmaKa() > -3.0 && candidate.tofNSigmaKa() < 4.0) { + 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() && TMath::Abs(candidate.tpcNSigmaKa()) < 3.0 && candidate.tofNSigmaKa() > -2.0 && candidate.tofNSigmaKa() < 3.0) { + 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() && TMath::Abs(candidate.tpcNSigmaKa()) < 3.0 && candidate.tofNSigmaKa() > -1.5 && candidate.tofNSigmaKa() < 2.5) { + 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() && TMath::Abs(candidate.tpcNSigmaKa()) < 3.0 && candidate.tofNSigmaKa() > -1.0 && candidate.tofNSigmaKa() < 2.0) { + 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 && TMath::Abs(candidate.tpcNSigmaKa()) < 3.0) { + 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) { @@ -666,7 +687,7 @@ struct lambda1520analysis { } template - bool RejectPion(const T& candidate) + bool rejectPion(const T& candidate) { if (candidate.pt() > 1.0 && candidate.pt() < 2.0 && !candidate.hasTOF() && candidate.tpcNSigmaPi() < 2) { return false; @@ -679,25 +700,20 @@ struct lambda1520analysis { { auto multiplicity = collision.cent(); - // Multiplicity correlation calibration plots - if (isFilladditionalQA) { - if constexpr (IsData) { - histos.fill(HIST("MultCalib/centglopr_before"), multiplicity, dTracks1.size()); - histos.fill(HIST("MultCalib/centgloka_before"), multiplicity, dTracks2.size()); - histos.fill(HIST("MultCalib/GloPVpr_before"), dTracks1.size(), collision.multNTracksPV()); - histos.fill(HIST("MultCalib/GloPVka_before"), dTracks2.size(), collision.multNTracksPV()); - } - } + // LOG(info) << "Before pass, Collision index:" << collision.index() << "multiplicity: " << collision.cent() << std::endl; - if (additionalEvsel && !eventSelected(collision, multiplicity)) { - return; - } + // auto occupancyNo = collision.trackOccupancyInTimeRange(); + // if (applyOccupancyCut && occupancyNo < occupancyCut) { + // return; + // } + + // Multiplicity correlation calibration plots if (isFilladditionalQA) { if constexpr (IsData) { - histos.fill(HIST("MultCalib/centglopr_after"), multiplicity, dTracks1.size()); - histos.fill(HIST("MultCalib/centgloka_after"), multiplicity, dTracks2.size()); - histos.fill(HIST("MultCalib/GloPVpr_after"), dTracks1.size(), collision.multNTracksPV()); - histos.fill(HIST("MultCalib/GloPVka_after"), dTracks2.size(), collision.multNTracksPV()); + 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()); } } @@ -714,10 +730,10 @@ struct lambda1520analysis { 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; - TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; - - 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. @@ -746,6 +762,10 @@ 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 (IsData) { @@ -771,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 @@ -778,15 +802,15 @@ struct lambda1520analysis { continue; if (cUseOnlyTOFTrackKa && !isTrk2hasTOF) continue; - if (cRejectPion && RejectPion(trk2)) + if (crejectPion && rejectPion(trk2)) continue; if (cOldPIDcut) { if (!selectionoldPIDProton(trk1) || !selectionoldPIDKaon(trk2)) continue; - } else if (!cOldPIDcut && !FixedPIDcut) { + } else if (!cOldPIDcut && !fixedPIDcut) { if (!selectionnewPIDProton(trk1) || !selectionnewPIDKaon(trk2)) continue; - } else if (FixedPIDcut) { + } else if (fixedPIDcut) { if (!selectionPIDProtonFixed(trk1) || !selectionPIDKaonFixed(trk2)) continue; } @@ -823,7 +847,10 @@ 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()); @@ -843,11 +870,11 @@ 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) { @@ -857,14 +884,43 @@ struct lambda1520analysis { 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 (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) { - histos.fill(HIST("Result/Data/lambda1520invmass"), lResonance.M()); + if (invmass1D) { + histos.fill(HIST("Result/Data/lambda1520invmass"), lResonance.M()); + } histos.fill(HIST("Result/Data/h3lambda1520invmass"), multiplicity, lResonance.Pt(), lResonance.M()); - } else { - histos.fill(HIST("Result/Data/antilambda1520invmass"), 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 @@ -875,7 +931,9 @@ struct lambda1520analysis { histos.fill(HIST("Result/Data/h3lambda1520invmassUnlikeSignCside"), multiplicity, lResonance.Pt(), lResonance.M()); } } else if (IsMix) { - histos.fill(HIST("Result/Data/lambda1520invmassME"), lResonance.M()); + 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()); @@ -899,18 +957,18 @@ 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()) != 102134) + 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) { @@ -923,12 +981,16 @@ struct lambda1520analysis { // MC histograms if (trk1.motherPDG() > 0) { - histos.fill(HIST("Result/MC/lambda1520Reco"), lResonance.Pt(), multiplicity); - histos.fill(HIST("Result/MC/hlambda1520Recoinvmass"), 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(), multiplicity); - histos.fill(HIST("Result/MC/hantilambda1520Recoinvmass"), 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()); } } @@ -943,10 +1005,14 @@ struct lambda1520analysis { } // Like sign pair ++ if (trk1.sign() > 0) { - histos.fill(HIST("Result/Data/lambda1520invmassLSPP"), 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()); + if (invmass1D) { + histos.fill(HIST("Result/Data/lambda1520invmassLSMM"), lResonance.M()); + } histos.fill(HIST("Result/Data/h3lambda1520invmassLSMM"), multiplicity, lResonance.Pt(), lResonance.M()); } } @@ -954,43 +1020,39 @@ struct lambda1520analysis { } } - void processData(aod::ResoCollision& collision, + void processData(aod::ResoCollision const& collision, aod::ResoTracks const& 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(ResoMCCols::iterator const& collision, soa::Join const& resotracks) { - if (!collision.isInAfterAllCuts() || (abs(collision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + 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(ResoMCCols::iterator const& collision, 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()) != 102134) // 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; + if (collision.isVtxIn10()) // INEL10 { if (part.pdgCode() > 0) @@ -1021,26 +1083,26 @@ struct lambda1520analysis { } } } - 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) { + 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/lambda1520analysisinOO.cxx b/PWGLF/Tasks/Resonances/lambda1520analysisinOO.cxx new file mode 100644 index 00000000000..f5dfe0eb59a --- /dev/null +++ b/PWGLF/Tasks/Resonances/lambda1520analysisinOO.cxx @@ -0,0 +1,1182 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file lstaranalysis.cxx +/// \brief This standalone task reconstructs track-track decay of lambda(1520) resonance candidate +/// \author Hirak Kumar Koley + +// 1. Own header (doesn't exist) + +// 2. C system headers (none) + +// 3. C++ system headers +#include + +// 4. Other includes: O2 framework, ROOT, etc. +#include "PWGLF/Utils/collisionCuts.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TPDGCode.h" +#include "TRandom.h" +#include "TVector3.h" + +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 LorentzVectorPtEtaPhiMass = ROOT::Math::PtEtaPhiMVector; + +enum { + kINEL = 1, + kINEL10, + kINELg0, + kINELg010, + kTrig, + kTrig10, + kTrigINELg0, + kTrigINELg010, + kSel8, + kSel810, + kSel8INELg0, + kSel8INELg010, + kAllCuts, + kAllCuts10, + kAllCutsINELg0, + kAllCutsINELg010, +}; + +struct Lstaranalysis { + // Define slice per Resocollision + SliceCache cache; + Preslice perCollision = o2::aod::track::collisionId; + Preslice perMcCollision = o2::aod::mcparticle::mcCollisionId; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service pdg; + + /// Event cuts + o2::analysis::CollisonCuts colCuts; + + 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 cfgEventCentralityMin{"cfgEventCentralityMin", 0.0f, "Event sel: minimum centrality"}; + Configurable cfgEventCentralityMax{"cfgEventCentralityMax", 100.0f, "Event sel: maximum centrality"}; + + // Configurables + // Pre-selection Track cuts + Configurable trackSelection{"trackSelection", 0, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable cMinPtcut{"cMinPtcut", 0.15f, "Minimal pT for tracks"}; + Configurable cMinTPCNClsFound{"cMinTPCNClsFound", 120, "minimum TPCNClsFound value for good track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + Configurable cfgMinCrossedRows{"cfgMinCrossedRows", 70, "min crossed rows for good track"}; + + // DCA Selections + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.1f, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + 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"}; + Configurable cTPCNClsFound{"cTPCNClsFound", false, "Switch to turn on/off TPCNClsFound cut"}; + Configurable cDCAr7SigCut{"cDCAr7SigCut", false, "Track DCAr 7 Sigma cut to PV Maximum"}; + + /// PID Selections + Configurable cByPassTOF{"cByPassTOF", false, "By pass TOF PID selection"}; // By pass TOF PID selection + Configurable cPIDcutType{"cPIDcutType", 2, "cPIDcutType = 1 for square cut, 2 for circular cut"}; // By pass TOF PID selection + + // Kaon + Configurable> kaonTPCPIDpTintv{"kaonTPCPIDpTintv", {0.5}, "pT intervals for Kaon TPC PID cuts"}; + Configurable> kaonTPCPIDcuts{"kaonTPCPIDcuts", {2}, "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> kaonTPCTOFCombinedpTintv{"kaonTPCTOFCombinedpTintv", {999.}, "pT intervals for Kaon TPC-TOF PID cuts"}; + Configurable> kaonTPCTOFCombinedPIDcuts{"kaonTPCTOFCombinedPIDcuts", {2}, "nSigma list for Kaon TPC-TOF PID cuts"}; + + // Proton + Configurable> protonTPCPIDpTintv{"protonTPCPIDpTintv", {0.9}, "pT intervals for Kaon TPC PID cuts"}; + Configurable> protonTPCPIDcuts{"protonTPCPIDcuts", {2}, "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> protonTPCTOFCombinedpTintv{"protonTPCTOFCombinedpTintv", {999.}, "pT intervals for Proton TPC-TOF PID cuts"}; + Configurable> protonTPCTOFCombinedPIDcuts{"protonTPCTOFCombinedPIDcuts", {2}, "nSigma list for Proton TPC-TOF PID cuts"}; + + // Additional purity check + Configurable crejectPion{"crejectPion", false, "Switch to turn on/off pion contamination"}; + Configurable cApplyOpeningAngle{"cApplyOpeningAngle", false, "Kinematic Cuts for p-K pair opening angle"}; + Configurable cMinOpeningAngle{"cMinOpeningAngle", 1.4, "Maximum deltaEta between daughters"}; + Configurable cMaxOpeningAngle{"cMaxOpeningAngle", 2.4, "Maximum deltaPhi between daughters"}; + + /// 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, 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"}; + + // 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 selection cut + Configurable cZvertCutMC{"cZvertCutMC", 10.0, "MC Z-vertex cut"}; + Configurable cEtacutMC{"cEtacutMC", 0.5, "MC eta cut"}; + Configurable cUseRapcutMC{"cUseRapcutMC", true, "MC eta cut"}; + Configurable cUseEtacutMC{"cUseEtacutMC", true, "MC eta cut"}; + + // cuts on mother + Configurable cfgCutsOnMother{"cfgCutsOnMother", false, "Enable 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 cMaxDeltaEtaCut{"cMaxDeltaEtaCut", 0.7, "Maximum deltaEta between daughters"}; + Configurable cMaxDeltaPhiCut{"cMaxDeltaPhiCut", 1.5, "Maximum deltaPhi between daughters"}; + + // switches + Configurable cFillMultQA{"cFillMultQA", false, "Turn on/off additional QA plots"}; + Configurable cFilladditionalQAeventPlots{"cFilladditionalQAeventPlots", false, "Additional QA event plots"}; + Configurable cFilladditionalMEPlots{"cFilladditionalMEPlots", false, "Additional Mixed event plots"}; + Configurable cFilldeltaEtaPhiPlots{"cFilldeltaEtaPhiPlots", false, "Enamble additional cuts on daughters"}; + Configurable cFillinvmass1DPlots{"cFillinvmass1DPlots", false, "Invariant mass 1D"}; + Configurable multEstimator{"multEstimator", 0, "Select multiplicity estimator: 0 - FT0M, 1 - FT0A, 2 - FT0C"}; + + Configurable cfgCentEst{"cfgCentEst", 2, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + TRandom* rn = new TRandom(); + + // 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 == 0) || + ((trackSelection == 1) && requireGlobalTrackInFilter()) || + ((trackSelection == 2) && requireGlobalTrackWoPtEtaInFilter()) || + ((trackSelection == 3) && requireGlobalTrackWoDCAInFilter()) || + ((trackSelection == 4) && requireQualityTracksInFilter()) || + ((trackSelection == 5) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); */ + Filter trackEtaFilter = nabs(aod::track::eta) < cfgCutEta; // Eta cut + + using EventCandidates = soa::Join; + using TrackCandidates = soa::Filtered>; + + using MCEventCandidates = soa::Join; + using MCTrackCandidates = soa::Filtered>; + + /// Figures + 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 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, 10.2, 10.4, 10.6, 10.8, 11, 11.2, 11.4, 11.6, 11.8, 12, 12.2, 12.4, 12.6, 12.8, 13, 13.2, 13.4, 13.6, 13.8, 14, 14.2, 14.4, 14.6, 14.8, 15, 15.2, 15.4, 15.6, 15.8, 16, 16.2, 16.4, 16.6, 16.8, 17, 17.2, 17.4, 17.6, 17.8, 18, 18.2, 18.4, 18.6, 18.8, 19, 19.2, 19.4, 19.6, 19.8, 20}, "Binning of the pT axis"}; + ConfigurableAxis binsEta{"binsEta", {150, -1.5, 1.5}, ""}; + ConfigurableAxis binsMass{"binsMass", {70, 1.3, 2.0}, "Invariant Mass (GeV/#it{c}^2)"}; + ConfigurableAxis binsMult{"binsMult", {105, 0.0, 105.0}, "mult_{FT0M}"}; + 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 binsEtaPhi{"binsEtaPhi", {350, -3.5, 3.5}, ""}; + + float centrality; + + void init(framework::InitContext&) + { + centrality = -999; + + colCuts.setCuts(cfgEvtZvtx, cfgEvtTriggerCheck, cfgEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, cfgEvtOccupancyInTimeRangeMax, cfgEvtOccupancyInTimeRangeMin); + + colCuts.init(&histos); + colCuts.setTriggerTVX(cfgEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(cfgEvtTFBorderCut); + colCuts.setApplyITSTPCvertex(cfgEvtUseITSTPCvertex); + colCuts.setApplyZvertexTimedifference(cfgEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(cfgEvtPileupRejection); + colCuts.setApplyNoITSROBorderCut(cfgEvtNoITSROBorderCut); + colCuts.setApplyCollInTimeRangeStandard(cfgEvtCollInTimeRangeStandard); + colCuts.printCuts(); + + // axes + AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPtQA{binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisEta{binsEta, "#eta"}; + AxisSpec axisRap{binsEta, "#it{y}"}; + AxisSpec axisMassLambda1520{binsMass, "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec axisMult{binsMult, "mult_{V0M}"}; + AxisSpec axisDCAz{binsDCAz, "DCA_{z}"}; + AxisSpec axisDCAxy{binsDCAxy, "DCA_{XY}"}; + AxisSpec axisTPCXrow{binsTPCXrows, "#Xrows_{TPC}"}; + AxisSpec axisPIDQA{binsnSigma, "#sigma"}; + AxisSpec axisTPCSignal{binsnTPCSignal, ""}; + AxisSpec axisMClabel{6, -1.5, 5.5, "MC Label"}; + AxisSpec axisEtaPhi{binsEtaPhi, ""}; + AxisSpec axisPhi{350, 0, 7, "#Phi"}; + AxisSpec axisMultMix{cfgMultBins, "Multiplicity"}; + AxisSpec axisVtxMix{cfgVtxBins, "Vertex Z (cm)"}; + AxisSpec idxMCAxis = {26, -0.5, 25.5, "Index"}; + + if (cFilladditionalQAeventPlots) { + // event histograms + if (doprocessData) { + histos.add("TestME/hPairsCounterSameE", "tot n pairs sameE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + 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("TestME/hCollisionIndexSameE", "coll index sameE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hnTrksSameE", "n tracks per event SameE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + } + // Test on Mixed event + if (doprocessME) { + + // Histograms for Mixed Event Pool characteristics + histos.add("QAevent/hMixPool_VtxZ", "Mixed Event Pool: Vertex Z;Vtx Z (cm);Counts", HistType::kTH1F, {axisVtxMix}); + histos.add("QAevent/hMixPool_Multiplicity", "Mixed Event Pool: Multiplicity;Multiplicity;Counts", HistType::kTH1F, {axisMultMix}); + histos.add("QAevent/hMixPool_VtxZ_vs_Multiplicity", "Mixed Event Pool: Vertex Z vs Multiplicity;Counts", HistType::kTH2F, {axisVtxMix, axisMultMix}); + + histos.add("TestME/hPairsCounterMixedE", "tot n pairs mixedE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + 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}}); + histos.add("TestME/hCollisionIndexMixedE", "coll index mixedE", HistType::kTH1F, {{500, 0.0f, 500.0f}}); + histos.add("TestME/hnTrksMixedE", "n tracks per event MixedE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + } + } + + 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, {axisPIDQA, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TPConly_Nsigma_ka", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Kaon}};", {HistType::kTH2F, {axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;{#sigma_{TOF}^{Proton}};{#sigma_{TPC}^{Proton}}", {HistType::kTH2F, {axisPIDQA, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TPConly_Nsigma_pr", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Proton}};", {HistType::kTH2F, {axisPt, axisPIDQA}}); + 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 (cFillMultQA) { + // Multiplicity correlation calibrations + histos.add("MultCalib/centGloPVpr", "Centrality vs Global-Tracks", kTHnSparseF, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}, {500, 0, 5000, "PV tracks"}}); + histos.add("MultCalib/centGloPVka", "Centrality vs Global-Tracks", kTHnSparseF, {{110, 0, 110, "Centrality"}, {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::kTH2F, {axisPIDQA, axisPIDQA}}); + histos.add("QA/QAafter/Kaon/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAafter/Kaon/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + 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, axisPIDQA}}); + 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} (GeV/#it{c});TPC Signal (A.U.)", {HistType::kTH2F, {axisPt, axisTPCSignal}}); + histos.add("QA/QAafter/Kaon/TPCnclusterPhika", "TPC ncluster vs phi", kTHnSparseF, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + + // --- 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, {axisPIDQA, axisPIDQA}}); + histos.add("QA/QAafter/Proton/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAafter/Proton/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + 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, axisPIDQA}}); + 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} (GeV/#it{c});TPC Signal (A.U.)", {HistType::kTH2F, {axisPt, axisTPCSignal}}); + histos.add("QA/QAafter/Proton/TPCnclusterPhipr", "TPC ncluster vs phi", kTHnSparseF, {{160, 0, 160, "TPC nCluster"}, {63, 0, 6.28, "#phi"}}); + + // Mass QA 1D for quick check + if (cFillinvmass1DPlots) { + 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 (cFilldeltaEtaPhiPlots) { + histos.add("QAbefore/deltaEta", "deltaEta of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + histos.add("QAbefore/deltaPhi", "deltaPhi of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + + histos.add("QAafter/deltaEta", "deltaEta of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + histos.add("QAafter/deltaPhi", "deltaPhi of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + + histos.add("QAafter/deltaEtaafter", "deltaEta of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + histos.add("QAafter/deltaPhiafter", "deltaPhi of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + histos.add("QAafter/EtaPrafter", "Eta of proton candidates", HistType::kTH1F, {axisEta}); + histos.add("QAafter/PhiPrafter", "Phi of proton candidates", HistType::kTH1F, {axisPhi}); + histos.add("QAafter/EtaKaafter", "Eta of kaon candidates", HistType::kTH1F, {axisEta}); + histos.add("QAafter/PhiKaafter", "Phi of kaon candidates", HistType::kTH1F, {axisPhi}); + } + + 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 (cFillinvmass1DPlots) { + 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::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + + if (cFilladditionalMEPlots) { + 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}); + } + } + + // MC QA + histos.add("Event/hMCEventIndices", "hMCEventIndices", kTH2D, {axisMult, idxMCAxis}); + if (doprocessMCTrue) { + histos.add("QA/MC/h2GenEtaPt_beforeanycut", " #eta-#it{p}_{T} distribution of Generated #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPtQA}); + histos.add("QA/MC/h2GenPhiRapidity_beforeanycut", " #phi-y distribution of Generated #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); + histos.add("QA/MC/h2GenEtaPt_afterEtaRapCut", " #eta-#it{p}_{T} distribution of Generated #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPtQA}); + histos.add("QA/MC/h2GenPhiRapidity_afterEtaRapCut", " #phi-y distribution of Generated #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); + histos.add("QA/MC/h2GenEtaPt_afterRapcut", " #phi-#it{p}_{T} distribution of Generated #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPtQA}); + histos.add("QA/MC/h2GenPhiRapidity_afterRapcut", " #phi-y distribution of Generated #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); + + histos.add("Result/MC/Genlambda1520pt", "pT distribution of True MC #Lambda(1520)0", kTHnSparseF, {axisMClabel, axisPt, axisMult}); + histos.add("Result/MC/Genantilambda1520pt", "pT distribution of True MC Anti-#Lambda(1520)0", kTHnSparseF, {axisMClabel, axisPt, axisMult}); + } + if (doprocessMC) { + histos.add("QA/MC/h2RecoEtaPt_after", " #eta-#it{p}_{T} distribution of Reconstructed #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPt}); + histos.add("QA/MC/h2RecoPhiRapidity_after", " #phi-y distribution of Reconstructed #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); + + histos.add("QA/MC/trkDCAxy_pr", "DCAxy distribution of proton track candidates", HistType::kTHnSparseF, {axisPt, axisDCAxy}); + histos.add("QA/MC/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTHnSparseF, {axisPt, axisDCAxy}); + histos.add("QA/MC/trkDCAz_pr", "DCAz distribution of proton track candidates", HistType::kTHnSparseF, {axisPt, axisDCAz}); + histos.add("QA/MC/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTHnSparseF, {axisPt, axisDCAz}); + histos.add("QA/MC/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/MC/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/MC/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/MC/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + + histos.add("Result/MC/h3lambda1520Recoinvmass", "Invariant mass of Reconstructed MC #Lambda(1520)0", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/MC/h3antilambda1520Recoinvmass", "Invariant mass of Reconstructed MC Anti-#Lambda(1520)0", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + } + + // Print output histograms statistics + LOG(info) << "Size of the histograms in LstarAnalysis:"; + histos.print(); + } + + float massKa = MassKaonCharged; + float massPr = MassProton; + + int kLambda1520PDG = static_cast(102134); // PDG code for Lambda(1520) + + template + float getCentrality(CollisionType const& collision) + { + if (cfgCentEst == static_cast(1)) { + return collision.multFT0C(); + } else if (cfgCentEst == static_cast(2)) { + return collision.multFT0M(); + } else { + return -999; + } + } + + // Centralicity estimator selection + template + float centEst(ResoColl ResoEvents) + { + float returnValue = -999.0; + switch (multEstimator) { + case 0: + returnValue = ResoEvents.centFT0M(); + break; + case 1: + returnValue = ResoEvents.centFT0A(); + break; + case 2: + returnValue = ResoEvents.centFT0C(); + break; + default: + returnValue = ResoEvents.centFT0M(); + break; + } + return returnValue; + } + + // 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; + } + + template + bool trackCut(const TrackType track) + { + // basic track cuts + if (std::abs(track.pt()) < cMinPtcut) + return false; + if (cDCAr7SigCut) { + if (std::abs(track.dcaXY()) > (0.004f + 0.0130f / (track.pt()))) // 7 - Sigma cut + return false; + } else { + if (std::abs(track.dcaXY()) > cMaxDCArToPVcut) + return false; + } + if (std::abs(track.dcaZ()) > cMaxDCAzToPVcut) + return false; + if (cTPCNClsFound && (track.tpcNClsFound() < cMinTPCNClsFound)) + return false; + if (track.tpcNClsCrossedRows() < cfgMinCrossedRows) + 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; + + return true; + } + + // LOGF(info, "AFTER: pt: %f, hasTOF: %d, TPCSigma: %f, TOFSigma: %f, boolTPC: %d, boolTOF: %d, bool: %d", pt, candidate.hasTOF(), + // candidate.tpcNSigmaPr(), candidate.tofNSigmaPr(), tpcPIDPassed, tofPIDPassed, tpcPIDPassed || tofPIDPassed); + + template + bool pTdependentPIDProton(const T& candidate) + { + auto vProtonTPCPIDpTintv = static_cast>(protonTPCPIDpTintv); + 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); + + float pt = candidate.pt(); + float ptSwitchToTOF = vProtonTPCPIDpTintv.back(); + + bool tpcPIDPassed = false; + + // TPC PID (interval check) + for (size_t i = 0; i < vProtonTPCPIDpTintv.size() - 1; ++i) { + if (pt > vProtonTPCPIDpTintv[i] && pt < vProtonTPCPIDpTintv[i + 1]) { + if (std::abs(candidate.tpcNSigmaPr()) < vProtonTPCPIDcuts[i]) + tpcPIDPassed = true; + } + } + + // TOF bypass option (for QA or MC) + if (cByPassTOF) { + return std::abs(candidate.tpcNSigmaPr()) < vProtonTPCPIDcuts.back(); + } + + // Case 1: No TOF and pt ≤ threshold → accept only via TPC PID + if (!candidate.hasTOF() && pt <= ptSwitchToTOF) { + return tpcPIDPassed; + } + + // Case 2: No TOF but pt > threshold → reject + if (!candidate.hasTOF() && pt > ptSwitchToTOF) { + return false; + } + + // Case 3: Has TOF → use TPC + TOF (square or circular) + if (candidate.hasTOF()) { + if (cPIDcutType == 1) { + // Rectangular cut + for (size_t i = 0; i < vProtonTOFPIDpTintv.size(); ++i) { + if (pt < vProtonTOFPIDpTintv[i]) { + if (std::abs(candidate.tofNSigmaPr()) < vProtonTOFPIDcuts[i] && + std::abs(candidate.tpcNSigmaPr()) < vProtonTPCPIDcuts.back()) + return true; + } + } + } else if (cPIDcutType == 2) { + // Circular cut + for (size_t i = 0; i < vProtonTPCTOFCombinedpTintv.size(); ++i) { + if (pt < vProtonTPCTOFCombinedpTintv[i]) { + float combinedSigma2 = + candidate.tpcNSigmaPr() * candidate.tpcNSigmaPr() + + candidate.tofNSigmaPr() * candidate.tofNSigmaPr(); + if (combinedSigma2 < vProtonTPCTOFCombinedPIDcuts[i] * vProtonTPCTOFCombinedPIDcuts[i]) + return true; + } + } + } + } + + return false; + } + + template + bool pTdependentPIDKaon(const T& candidate) + { + auto vKaonTPCPIDpTintv = static_cast>(kaonTPCPIDpTintv); + 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); + + float pt = candidate.pt(); + float ptSwitchToTOF = vKaonTPCPIDpTintv.back(); + + bool tpcPIDPassed = false; + + // TPC PID interval-based check + for (size_t i = 0; i < vKaonTPCPIDpTintv.size() - 1; ++i) { + if (pt > vKaonTPCPIDpTintv[i] && pt < vKaonTPCPIDpTintv[i + 1]) { + if (std::abs(candidate.tpcNSigmaKa()) < vKaonTPCPIDcuts[i]) { + tpcPIDPassed = true; + break; + } + } + } + + // TOF bypass option + if (cByPassTOF) { + return std::abs(candidate.tpcNSigmaKa()) < vKaonTPCPIDcuts.back(); + } + + // Case 1: No TOF and pt ≤ ptSwitch → use TPC-only + if (!candidate.hasTOF() && pt <= ptSwitchToTOF) { + return tpcPIDPassed; + } + + // Case 2: No TOF but pt > ptSwitch → reject + if (!candidate.hasTOF() && pt > ptSwitchToTOF) { + return false; + } + + // Case 3: TOF is available → apply TPC+TOF PID logic + if (candidate.hasTOF()) { + if (cPIDcutType == 1) { + // Rectangular cut + for (size_t i = 0; i < vKaonTOFPIDpTintv.size(); ++i) { + if (pt < vKaonTOFPIDpTintv[i]) { + if (std::abs(candidate.tofNSigmaKa()) < vKaonTOFPIDcuts[i] && + std::abs(candidate.tpcNSigmaKa()) < vKaonTPCPIDcuts.back()) { + return true; + } + } + } + } else if (cPIDcutType == 2) { + // Circular cut + for (size_t i = 0; i < vKaonTPCTOFCombinedpTintv.size(); ++i) { + if (pt < vKaonTPCTOFCombinedpTintv[i]) { + float combinedSigma2 = candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + + candidate.tofNSigmaKa() * candidate.tofNSigmaKa(); + if (combinedSigma2 < vKaonTPCTOFCombinedPIDcuts[i] * vKaonTPCTOFCombinedPIDcuts[i]) { + return true; + } + } + } + } + } + + return false; + } + + template + bool rejectPion(const T& candidate) + { + if (candidate.pt() > static_cast(1.0) && candidate.pt() < static_cast(2.0) && !candidate.hasTOF() && candidate.tpcNSigmaPi() < static_cast(2)) { + return false; + } + return true; + } + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + { + auto multiplicity = collision.centFT0M(); + + // Multiplicity correlation calibration plots + if (cFillMultQA) { + if constexpr (IsData) { + histos.fill(HIST("MultCalib/centGloPVpr"), multiplicity, dTracks1.size(), collision.multNTracksPV()); + histos.fill(HIST("MultCalib/centGloPVka"), multiplicity, dTracks2.size(), collision.multNTracksPV()); + } + } + + if (cFilladditionalQAeventPlots) { + 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.centFT0M() << endl; + + LorentzVectorPtEtaPhiMass 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 (cFilladditionalQAeventPlots) { + 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; + + //// Initialize variables + // Trk1: Proton, Trk2: Kaon + auto isTrk1hasTOF = trk1.hasTOF(); + auto isTrk2hasTOF = trk2.hasTOF(); + + auto trk1ptPr = trk1.pt(); + auto trk1NSigmaPrTPC = trk1.tpcNSigmaPr(); + auto trk1NSigmaPrTOF = (isTrk1hasTOF) ? trk1.tofNSigmaPr() : -999.; + auto trk2ptKa = trk2.pt(); + 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; + + //// QA plots before the selection + // --- Track QA all + 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"), multiplicity, trk1ptPr, trk1NSigmaPrTOF); + histos.fill(HIST("QA/QAbefore/Track/TOF_TPC_Map_pr_all"), trk1NSigmaPrTOF, trk1NSigmaPrTPC); + } + if (!isTrk1hasTOF) { + histos.fill(HIST("QA/QAbefore/Track/TPConly_Nsigma_pr"), trk1ptPr, trk1NSigmaPrTPC); + } + 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"), multiplicity, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QA/QAbefore/Track/TOF_TPC_Map_ka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } + if (!isTrk2hasTOF) { + histos.fill(HIST("QA/QAbefore/Track/TPConly_Nsigma_ka"), trk2ptKa, trk2NSigmaKaTPC); + } + + histos.fill(HIST("QA/QAbefore/Track/dcaZ"), trk1ptPr, trk1.dcaZ()); + histos.fill(HIST("QA/QAbefore/Track/dcaXY"), trk1ptPr, trk1.dcaXY()); + 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 (cFilldeltaEtaPhiPlots) { + histos.fill(HIST("QAbefore/deltaEta"), deltaEta); + histos.fill(HIST("QAbefore/deltaPhi"), deltaPhi); + } + } + + //// Apply the pid selection + if (crejectPion && rejectPion(trk2)) + continue; + + if (!pTdependentPIDProton(trk1) || !pTdependentPIDKaon(trk2)) + continue; + + //// QA plots after the selection + 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"), trk1.tpcInnerParam(), trk1.tpcSignal()); + if (isTrk1hasTOF) { + 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) { + histos.fill(HIST("QA/QAafter/Proton/TPC_Nsigma_pr_TPConly"), trk1ptPr, trk1NSigmaPrTPC); + } + histos.fill(HIST("QA/QAafter/Proton/dcaZ"), trk1ptPr, trk1.dcaZ()); + histos.fill(HIST("QA/QAafter/Proton/dcaXY"), trk1ptPr, trk1.dcaXY()); + histos.fill(HIST("QA/QAafter/Proton/TPC_CR"), trk1ptPr, trk1.tpcNClsCrossedRows()); + histos.fill(HIST("QA/QAafter/Proton/pT"), trk1ptPr); + histos.fill(HIST("QA/QAafter/Proton/eta"), trk1.eta()); + histos.fill(HIST("QA/QAafter/Proton/TPCnclusterPhipr"), trk1.tpcNClsFound(), trk1.phi()); + + // --- PID QA Kaon + histos.fill(HIST("QA/QAafter/Kaon/TPC_Nsigma_ka_all"), multiplicity, trk2ptKa, trk2NSigmaKaTPC); + histos.fill(HIST("QA/QAafter/Kaon/TPC_Signal_ka_all"), trk2.tpcInnerParam(), trk2.tpcSignal()); + if (isTrk2hasTOF) { + 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) { + histos.fill(HIST("QA/QAafter/Kaon/TPC_Nsigma_ka_TPConly"), trk2ptKa, trk2NSigmaKaTPC); + } + histos.fill(HIST("QA/QAafter/Kaon/dcaZ"), trk2ptKa, trk2.dcaZ()); + histos.fill(HIST("QA/QAafter/Kaon/dcaXY"), trk2ptKa, trk2.dcaXY()); + 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()); + histos.fill(HIST("QA/QAafter/Kaon/TPCnclusterPhika"), trk2.tpcNClsFound(), trk2.phi()); + + if (cFilldeltaEtaPhiPlots) { + histos.fill(HIST("QAafter/deltaEta"), deltaEta); + histos.fill(HIST("QAafter/deltaPhi"), deltaPhi); + } + } + + // Apply kinematic opening angle cut + if (cApplyOpeningAngle) { + TVector3 v1(trk1.px(), trk1.py(), trk1.pz()); + TVector3 v2(trk2.px(), trk2.py(), trk2.pz()); + float alpha = v1.Angle(v2); + if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) + continue; + } + + //// Resonance reconstruction + lDecayDaughter1 = LorentzVectorPtEtaPhiMass(trk1.pt(), trk1.eta(), trk1.phi(), massPr); + lDecayDaughter2 = LorentzVectorPtEtaPhiMass(trk2.pt(), trk2.eta(), trk2.phi(), massKa); + lResonance = lDecayDaughter1 + lDecayDaughter2; + + if constexpr (IsData || IsMix) { + // Rapidity cut + if (std::abs(lResonance.Rapidity()) > static_cast(0.5)) + continue; + } + + if (cfgCutsOnMother) { + if (lResonance.Pt() >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (lResonance.M() >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + + if (cFilldeltaEtaPhiPlots) { + 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 (IsData) { + 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 = LorentzVectorPtEtaPhiMass(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 (cFillinvmass1DPlots) { + 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 (cFillinvmass1DPlots) { + histos.fill(HIST("Result/Data/antilambda1520invmass"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3antilambda1520invmass"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } else if (IsMix) { + if (cFillinvmass1DPlots) { + histos.fill(HIST("Result/Data/lambda1520invmassME"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassME"), multiplicity, lResonance.Pt(), lResonance.M()); + if (cFilladditionalMEPlots) { + if (trk1.sign() < 0) { + histos.fill(HIST("Result/Data/h3lambda1520invmassME_DS"), multiplicity, lResonance.Pt(), lResonance.M()); + } else if (trk1.sign() > 0) { + histos.fill(HIST("Result/Data/h3lambda1520invmassME_DSAnti"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } + } + + // MC + if constexpr (IsMC) { + + // ------ 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; + }; + // ------ + std::vector motherstrk1 = {-1, -1}; + std::vector mothersPDGtrk1 = {-1, -1}; + + std::vector motherstrk2 = {-1, -1}; + std::vector mothersPDGtrk2 = {-1, -1}; + + // + // Get the MC particle + const auto& mctrk1 = trk1.mcParticle(); + if (mctrk1.has_mothers()) { + motherstrk1 = getMothersIndeces(mctrk1); + mothersPDGtrk1 = getMothersPDGCodes(mctrk1); + } + while (motherstrk1.size() > 2) { + motherstrk1.pop_back(); + mothersPDGtrk1.pop_back(); + } + + const auto& mctrk2 = trk2.mcParticle(); + if (mctrk2.has_mothers()) { + motherstrk2 = getMothersIndeces(mctrk2); + mothersPDGtrk2 = getMothersPDGCodes(mctrk2); + } + while (motherstrk2.size() > 2) { + motherstrk2.pop_back(); + mothersPDGtrk2.pop_back(); + } + + if (std::abs(mctrk1.pdgCode()) != 2212 || std::abs(mctrk2.pdgCode()) != 321) + continue; + + if (motherstrk1[0] != motherstrk2[0]) // Same mother + continue; + + if (std::abs(mothersPDGtrk1[0]) != 102134) + continue; + + // LOGF(info, "mother trk1 id: %d, mother trk1: %d, trk1 id: %d, trk1 pdgcode: %d, mother trk2 id: %d, mother trk2: %d, trk2 id: %d, trk2 pdgcode: %d", motherstrk1[0], mothersPDGtrk1[0], trk1.globalIndex(), mctrk1.pdgCode(), motherstrk2[0], mothersPDGtrk2[0], trk2.globalIndex(), mctrk2.pdgCode()); + + if (cUseEtacutMC && std::abs(lResonance.Eta()) > cEtacutMC) // eta cut + continue; + + if (cUseRapcutMC && std::abs(lResonance.Rapidity()) > static_cast(0.5)) // rapidity cut + continue; + + histos.fill(HIST("QA/MC/h2RecoEtaPt_after"), lResonance.Eta(), lResonance.Pt()); + histos.fill(HIST("QA/MC/h2RecoPhiRapidity_after"), lResonance.Phi(), lResonance.Rapidity()); + + // Track selection check. + 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 (mothersPDGtrk1[0] > 0) { + histos.fill(HIST("Result/MC/h3lambda1520Recoinvmass"), multiplicity, lResonance.Pt(), lResonance.M()); + } else { + histos.fill(HIST("Result/MC/h3antilambda1520Recoinvmass"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } + } else { + if constexpr (IsData) { + // Like sign pair ++ + if (trk1.sign() > 0) { + if (cFillinvmass1DPlots) { + histos.fill(HIST("Result/Data/lambda1520invmassLSPP"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassLSPP"), multiplicity, lResonance.Pt(), lResonance.M()); + } else { // Like sign pair -- + if (cFillinvmass1DPlots) { + histos.fill(HIST("Result/Data/lambda1520invmassLSMM"), lResonance.M()); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassLSMM"), multiplicity, lResonance.Pt(), lResonance.M()); + } + } + } + } + } + + void processData(EventCandidates::iterator const& collision, + TrackCandidates const& tracks) + { + if (!colCuts.isSelected(collision)) // Default event selection + return; + + colCuts.fillQA(collision); + + if (cFilladditionalQAeventPlots) + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + fillHistograms(collision, tracks, tracks); + } + PROCESS_SWITCH(Lstaranalysis, processData, "Process Event for data without partition", false); + + void processMC(MCEventCandidates::iterator const& collision, + aod::McCollisions const&, + MCTrackCandidates const& tracks, aod::McParticles const&) + { + colCuts.fillQA(collision); + + if (std::abs(collision.posZ()) > cZvertCutMC) // Z-vertex cut + return; + + fillHistograms(collision, tracks, tracks); + } + PROCESS_SWITCH(Lstaranalysis, processMC, "Process Event for MC Light without partition", false); + + Partition selectedMCParticles = (nabs(aod::mcparticle::pdgCode) == 102134); // Lambda(1520) + + void processMCTrue(MCEventCandidates::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) + { + bool isInAfterAllCuts = colCuts.isSelected(collision); + bool inVtx10 = (std::abs(collision.mcCollision().posZ()) > 10.) ? false : true; + bool isTriggerTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); + bool isSel8 = collision.sel8(); + bool isTrueINELgt0 = isTrueINEL0(collision, mcParticles); + centrality = centEst(collision); + + auto multiplicity = collision.centFT0M(); + + auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + + // Not related to the real collisions + for (const auto& part : mcParts) { // loop over all MC particles + + if (std::abs(part.pdgCode()) != kLambda1520PDG) // Lambda1520(0) + continue; + + std::vector daughterPDGs; + if (part.has_daughters()) { + auto daughter01 = mcParticles.rawIteratorAt(part.daughtersIds()[0] - mcParticles.offset()); + auto daughter02 = mcParticles.rawIteratorAt(part.daughtersIds()[1] - mcParticles.offset()); + daughterPDGs = {daughter01.pdgCode(), daughter02.pdgCode()}; + } else { + daughterPDGs = {-1, -1}; + } + + bool pass1 = std::abs(daughterPDGs[0]) == kKPlus || std::abs(daughterPDGs[1]) == kKPlus; // At least one decay to Kaon + bool pass2 = std::abs(daughterPDGs[0]) == kProton || std::abs(daughterPDGs[1]) == kProton; // At least one decay to Proton + + // Checking if we have both decay products + if (!pass1 || !pass2) + continue; + + // LOGF(info, "Part PDG: %d", part.pdgCode(), "DAU_ID1: %d", pass1, "DAU_ID2: %d", pass2); + + histos.fill(HIST("QA/MC/h2GenEtaPt_beforeanycut"), part.eta(), part.pt()); + histos.fill(HIST("QA/MC/h2GenPhiRapidity_beforeanycut"), part.phi(), part.y()); + + if (cUseRapcutMC && std::abs(part.y()) > static_cast(0.5)) // rapidity cut + continue; + + histos.fill(HIST("QA/MC/h2GenEtaPt_afterRapcut"), part.eta(), part.pt()); + histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterRapcut"), part.phi(), part.y()); + + if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) // eta cut + continue; + + histos.fill(HIST("QA/MC/h2GenEtaPt_afterEtaRapCut"), part.eta(), part.pt()); + histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterEtaRapCut"), part.phi(), part.y()); + + // without any event selection + 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 (inVtx10) // INEL10 + { + 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 (inVtx10 && isSel8) // INEL>10, vtx10 + { + 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 (inVtx10 && isTriggerTVX) // vtx10, TriggerTVX + { + 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); + } + if (isInAfterAllCuts) // after all event selection + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 4, part.pt(), multiplicity); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 4, part.pt(), multiplicity); + } + } + + // QA for Trigger efficiency + histos.fill(HIST("Event/hMCEventIndices"), centrality, kINEL); + if (inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kINEL10); + if (isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kINELg0); + if (inVtx10 && isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kINELg010); + + // TVX MB trigger + if (isTriggerTVX) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kTrig); + if (isTriggerTVX && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kTrig10); + if (isTriggerTVX && isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kTrigINELg0); + if (isTriggerTVX && isTrueINELgt0 && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kTrigINELg010); + + // Sel8 event selection + if (isSel8) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kSel8); + if (isSel8 && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kSel810); + if (isSel8 && isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kSel8INELg0); + if (isSel8 && isTrueINELgt0 && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kSel8INELg010); + + // CollisionCuts selection + if (isInAfterAllCuts) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kAllCuts); + if (isInAfterAllCuts && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kAllCuts10); + if (isInAfterAllCuts && isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kAllCutsINELg0); + if (isInAfterAllCuts && isTrueINELgt0 && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, kAllCutsINELg010); + } + PROCESS_SWITCH(Lstaranalysis, processMCTrue, "Process Event for MC only", false); + + // Processing Event Mixing + using BinningTypeVtxZT0M = ColumnBinningPolicy; + BinningTypeVtxZT0M colBinning{{cfgVtxBins, cfgMultBins}, true}; + + void processME(EventCandidates const& collision, + TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + SameKindPair pairs{colBinning, nEvtMixing, -1, collision, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.globalIndex(), collision2.globalIndex()); + + // for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + // LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d)", t1.index(), t2.index(), collision1.index(), collision2.index()); + // } + + if (cFilladditionalQAeventPlots) { + // Fill histograms for the characteristics of the *mixed* events (collision1 and collision2) + // This will show the distribution of events that are actually being mixed. + histos.fill(HIST("QAevent/hMixPool_VtxZ"), collision1.posZ()); + histos.fill(HIST("QAevent/hMixPool_Multiplicity"), collision1.centFT0M()); // Assuming getCentrality() gives multiplicity + histos.fill(HIST("QAevent/hMixPool_VtxZ_vs_Multiplicity"), collision1.posZ(), collision1.centFT0M()); + + // You might also want to fill for collision2 if you want to see both partners' distributions + // histos.fill(HIST("QAevent/hMixPool_VtxZ"), collision2.posZ()); + // histos.fill(HIST("QAevent/hMixPool_Multiplicity"), collision2.getCentrality()); + // histos.fill(HIST("QAevent/hMixPool_VtxZ_vs_Multiplicity"), collision2.posZ(), collision2.getCentrality()); + + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.f); + } + fillHistograms(collision1, tracks1, tracks2); + } + } + PROCESS_SWITCH(Lstaranalysis, processME, "Process EventMixing light without partition", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx b/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx new file mode 100644 index 00000000000..3d3aac5b773 --- /dev/null +++ b/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx @@ -0,0 +1,1244 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file lambda1520analysisinpp.cxx +/// \brief This standalone task reconstructs track-track decay of lambda(1520) resonance candidate +/// \author Hirak Kumar Koley + +#include "PWGLF/Utils/collisionCuts.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TPDGCode.h" +#include "TRandom.h" + +#include +#include + +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 LorentzVectorPtEtaPhiMass = ROOT::Math::PtEtaPhiMVector; + +enum { + Inel = 1, + Inel10, + Inelg0, + Inelg010, + Trig, + Trig10, + TrigINELg0, + TrigINELg010, + Sel8, + Sel810, + Sel8INELg0, + Sel8INELg010, + AllCuts, + AllCuts10, + AllCutsINELg0, + AllCutsINELg010, +}; + +enum TrackSelectionType { + AllTracks = 0, + GlobalTracks, + GlobalTracksWoPtEta, + GlobalTracksWoDCA, + QualityTracks, + InAcceptanceTracks, +}; + +enum PIDCutType { + SquareType = 1, + CircularType, +}; + +struct Lambda1520analysisinpp { + // Define slice per Resocollision + SliceCache cache; + Preslice perCollision = o2::aod::track::collisionId; + Preslice perMcCollision = o2::aod::mcparticle::mcCollisionId; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service pdg; + + /// Event cuts + o2::analysis::CollisonCuts colCuts; + + struct : ConfigurableGroup { + Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.0f, "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"}; + } configEvents; + + struct : ConfigurableGroup { + // Pre-selection Track cuts + Configurable trackSelection{"trackSelection", 0, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable cMinPtcut{"cMinPtcut", 0.15f, "Minimal pT for tracks"}; + Configurable cMinTPCNClsFound{"cMinTPCNClsFound", 120, "minimum TPCNClsFound value for good track"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + Configurable cfgCutRapidity{"cfgCutRapidity", 0.5f, "rapidity range for particles"}; + Configurable cfgMinCrossedRows{"cfgMinCrossedRows", 70, "min crossed rows for good track"}; + + // DCA Selections + // DCAr to PV + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.1f, "Track DCAr cut to PV Maximum"}; + // DCAz to PV + 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"}; + Configurable cTPCNClsFound{"cTPCNClsFound", false, "Switch to turn on/off TPCNClsFound cut"}; + Configurable cDCAr7SigCut{"cDCAr7SigCut", false, "Track DCAr 7 Sigma cut to PV Maximum"}; + } configTracks; + + struct : ConfigurableGroup { + /// PID Selections + Configurable pidnSigmaPreSelectionCut{"pidnSigmaPreSelectionCut", 4.0f, "pidnSigma Cut for pre-selection of tracks"}; + Configurable cByPassTOF{"cByPassTOF", false, "By pass TOF PID selection"}; // By pass TOF PID selection + Configurable cPIDcutType{"cPIDcutType", 2, "cPIDcutType = 1 for square cut, 2 for circular cut"}; // By pass TOF PID selection + + // Kaon + Configurable> kaonTPCPIDpTintv{"kaonTPCPIDpTintv", {0.5f}, "pT intervals for Kaon TPC PID cuts"}; + Configurable> kaonTPCPIDcuts{"kaonTPCPIDcuts", {2}, "nSigma list for Kaon TPC PID cuts"}; + Configurable> kaonTOFPIDpTintv{"kaonTOFPIDpTintv", {999.0f}, "pT intervals for Kaon TOF PID cuts"}; + Configurable> kaonTOFPIDcuts{"kaonTOFPIDcuts", {2}, "nSigma list for Kaon TOF PID cuts"}; + Configurable> kaonTPCTOFCombinedpTintv{"kaonTPCTOFCombinedpTintv", {999.0f}, "pT intervals for Kaon TPC-TOF PID cuts"}; + Configurable> kaonTPCTOFCombinedPIDcuts{"kaonTPCTOFCombinedPIDcuts", {2}, "nSigma list for Kaon TPC-TOF PID cuts"}; + + // Proton + Configurable> protonTPCPIDpTintv{"protonTPCPIDpTintv", {0.9f}, "pT intervals for Kaon TPC PID cuts"}; + Configurable> protonTPCPIDcuts{"protonTPCPIDcuts", {2}, "nSigma list for Kaon TPC PID cuts"}; + Configurable> protonTOFPIDpTintv{"protonTOFPIDpTintv", {999.0f}, "pT intervals for Kaon TOF PID cuts"}; + Configurable> protonTOFPIDcuts{"protonTOFPIDcuts", {2}, "nSigma list for Kaon TOF PID cuts"}; + Configurable> protonTPCTOFCombinedpTintv{"protonTPCTOFCombinedpTintv", {999.0f}, "pT intervals for Proton TPC-TOF PID cuts"}; + Configurable> protonTPCTOFCombinedPIDcuts{"protonTPCTOFCombinedPIDcuts", {2}, "nSigma list for Proton TPC-TOF PID cuts"}; + } configPID; + + struct : ConfigurableGroup { + /// Event Mixing + Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f, 10.0f}, "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"}; + + // 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"}; + Configurable cfgRotPr{"cfgRotPr", true, "rotate Proton"}; + } configBkg; + + // Additional purity check + Configurable crejectPion{"crejectPion", false, "Switch to turn on/off pion contamination"}; + Configurable cUseOpeningAngleCut{"cUseOpeningAngleCut", false, "Kinematic Cuts for p-K pair opening angle"}; + Configurable cMinOpeningAngle{"cMinOpeningAngle", 1.4f, "Minimum opening angle between daughters"}; + Configurable cMaxOpeningAngle{"cMaxOpeningAngle", 2.4f, "Maximum opening angle between daughters"}; + Configurable cfgUseDeltaEtaPhiCuts{"cfgUseDeltaEtaPhiCuts", false, "Switch to turn on/off delta eta and delta phi cuts"}; + Configurable cfgUseDaughterEtaCutMC{"cfgUseDaughterEtaCutMC", false, "Switch to turn on/off eta cuts for daughters in MC"}; + + // MC selection cut + Configurable cZvertCutMC{"cZvertCutMC", 10.0f, "MC Z-vertex cut"}; + Configurable cEtacutMC{"cEtacutMC", 0.5f, "MC eta cut"}; + Configurable cUseRapcutMC{"cUseRapcutMC", true, "MC eta cut"}; + Configurable cUseEtacutMC{"cUseEtacutMC", true, "MC eta cut"}; + + // cuts on mother + Configurable cfgUseCutsOnMother{"cfgUseCutsOnMother", false, "Enable additional cuts on mother"}; + Configurable cMaxPtMotherCut{"cMaxPtMotherCut", 10.0f, "Maximum pt of mother cut"}; + Configurable cMaxMinvMotherCut{"cMaxMinvMotherCut", 3.0f, "Maximum Minv of mother cut"}; + Configurable cMaxDeltaEtaCut{"cMaxDeltaEtaCut", 0.7f, "Maximum deltaEta between daughters"}; + Configurable cMaxDeltaPhiCut{"cMaxDeltaPhiCut", 1.5f, "Maximum deltaPhi between daughters"}; + + // switches + Configurable cFillMultQA{"cFillMultQA", false, "Turn on/off additional QA plots"}; + Configurable cFillTrackQA{"cFillTrackQA", false, "Turn on/off additional QA plots"}; + Configurable cFilladditionalQAeventPlots{"cFilladditionalQAeventPlots", false, "Additional QA event plots"}; + Configurable cFilladditionalMEPlots{"cFilladditionalMEPlots", false, "Additional Mixed event plots"}; + Configurable cFilldeltaEtaPhiPlots{"cFilldeltaEtaPhiPlots", false, "Enable additional cuts on daughters"}; + Configurable cFill1DQAs{"cFill1DQAs", false, "Invariant mass 1D"}; + Configurable centEstimator{"centEstimator", 0, "Select centrality estimator: 0 - FT0M, 1 - FT0A, 2 - FT0C"}; + + TRandom* rn = new TRandom(); + + // Pre-filters for efficient process + Filter zVtxFilter = (nabs(o2::aod::collision::posZ) <= configEvents.cfgEvtZvtx); + Filter collisionFilterMC = nabs(aod::mccollision::posZ) <= configEvents.cfgEvtZvtx; + // Filter centralityFilter = nabs(aod::cent::centFT0C) <= cfg_Event_CentralityMax; + // Filter triggerFilter = (o2::aod::evsel::sel8 == true); + + Filter acceptanceFilter = (nabs(aod::track::eta) < configTracks.cfgCutEta && nabs(aod::track::pt) > configTracks.cMinPtcut) && + (nabs(aod::track::dcaXY) < configTracks.cMaxDCArToPVcut) && (nabs(aod::track::dcaZ) < configTracks.cMaxDCAzToPVcut); + + // Filter tofPIDFilter = aod::track::tofExpMom < 0.0f || ((aod::track::tofExpMom > 0.0f) && ( (nabs(aod::pidtof::tofNSigmaPi) < configPID.pidnSigmaPreSelectionCut) || (nabs(aod::pidtof::tofNSigmaKa) < configPID.pidnSigmaPreSelectionCut) || (nabs(aod::pidtof::tofNSigmaPr) < configPID.pidnSigmaPreSelectionCut))); // TOF + // Filter tpcPIDFilter = nabs(aod::pidtpc::tpcNSigmaPi) < configPID.pidnSigmaPreSelectionCut || nabs(aod::pidtpc::tpcNSigmaKa) < configPID.pidnSigmaPreSelectionCut || nabs(aod::pidtpc::tpcNSigmaPr) < configPID.pidnSigmaPreSelectionCut; // TPC + /* Filter trackFilter = (configTracks.trackSelection == AllTracks) || + ((configTracks.trackSelection == GlobalTracks) && requireGlobalTrackInFilter()) || + ((configTracks.trackSelection == GlobalTracksWoPtEta) && requireGlobalTrackWoPtEtaInFilter()) || + ((configTracks.trackSelection == GlobalTracksWoDCA) && requireGlobalTrackWoDCAInFilter()) || + ((configTracks.trackSelection == QualityTracks) && requireQualityTracksInFilter()) || + ((configTracks.trackSelection == InAcceptanceTracks) && requireTrackCutInFilter(TrackSelectionFlags::kInAcceptanceTracks)); + */ + // Filter primarytrackFilter = requirePVContributor() && requirePrimaryTrack() && requireGlobalTrackWoDCA(); + + using EventCandidates = soa::Join; + using TrackCandidates = soa::Filtered>; + using MCEventCandidates = soa::Join; + using MCTrackCandidates = soa::Filtered>; + + /// Figures + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.12f, 0.14f, 0.16f, 0.18f, 0.2f, 0.25f, 0.3f, 0.35f, 0.4f, 0.45f, 0.5f, 0.55f, 0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 0.95f, 1.0f, 1.1f, 1.2f, 1.25f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.75f, 1.8f, 1.9f, 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 3.0f, 3.1f, 3.2f, 3.3f, 3.4f, 3.6f, 3.7f, 3.8f, 3.9f, 4.0f, 4.1f, 4.2f, 4.5f, 4.6f, 4.8f, 4.9f, 5.0f, 5.5f, 5.6f, 6.0f, 6.4f, 6.5f, 7.0f, 7.2f, 8.0f, 9.0f, 9.5f, 9.6f, 10.0f, 11.0f, 11.5f, 12.0f, 13.0f, 14.0f, 14.4f, 15.0f, 16.0f, 18.0f, 19.2f, 20.0f}, "Binning of the pT axis"}; + ConfigurableAxis binsPtQA{"binsPtQA", {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.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.2f, 4.4f, 4.6f, 4.8f, 5.0f, 5.2f, 5.4f, 5.6f, 5.8f, 6.0f, 6.2f, 6.4f, 6.6f, 6.8f, 7.0f, 7.2f, 7.4f, 7.6f, 7.8f, 8.0f, 8.2f, 8.4f, 8.6f, 8.8f, 9.0f, 9.2f, 9.4f, 9.6f, 9.8f, 10.0f, 10.2f, 10.4f, 10.6f, 10.8f, 11.0f, 11.2f, 11.4f, 11.6f, 11.8f, 12.0f, 12.2f, 12.4f, 12.6f, 12.8f, 13.0f, 13.2f, 13.4f, 13.6f, 13.8f, 14.0f, 14.2f, 14.4f, 14.6f, 14.8f, 15.0f, 15.2f, 15.4f, 15.6f, 15.8f, 16.0f, 16.2f, 16.4f, 16.6f, 16.8f, 17.0f, 17.2f, 17.4f, 17.6f, 17.8f, 18.0f, 18.2f, 18.4f, 18.6f, 18.8f, 19.0f, 19.2f, 19.4f, 19.6f, 19.8f, 20.0f}, "Binning of the pT axis"}; + ConfigurableAxis binsEta{"binsEta", {150, -1.5f, 1.5f}, ""}; + ConfigurableAxis binsMass{"binsMass", {70, 1.3f, 2.0f}, "Invariant Mass (GeV/#it{c}^2)"}; + ConfigurableAxis binsMult{"binsMult", {105, 0.0f, 105.0f}, "mult_{FT0M}"}; + ConfigurableAxis binsDCAz{"binsDCAz", {40, -0.2f, 0.2f}, ""}; + ConfigurableAxis binsDCAxy{"binsDCAxy", {40, -0.2f, 0.2f}, ""}; + ConfigurableAxis binsTPCXrows{"binsTPCXrows", {100, 60, 160}, ""}; + ConfigurableAxis binsnSigma{"binsnSigma", {130, -6.5f, 6.5f}, ""}; + ConfigurableAxis binsnTPCSignal{"binsnTPCSignal", {1000, 0, 1000}, ""}; + ConfigurableAxis binsEtaPhi{"binsEtaPhi", {350, -3.5f, 3.5f}, ""}; + + void init(framework::InitContext&) + { + colCuts.setCuts(configEvents.cfgEvtZvtx, configEvents.cfgEvtTriggerCheck, configEvents.cfgEvtOfflineCheck, /*checkRun3*/ true, /*triggerTVXsel*/ false, configEvents.cfgEvtOccupancyInTimeRangeMax, configEvents.cfgEvtOccupancyInTimeRangeMin); + + colCuts.init(&histos); + colCuts.setTriggerTVX(configEvents.cfgEvtTriggerTVXSel); + colCuts.setApplyTFBorderCut(configEvents.cfgEvtTFBorderCut); + colCuts.setApplyITSTPCvertex(configEvents.cfgEvtUseITSTPCvertex); + colCuts.setApplyZvertexTimedifference(configEvents.cfgEvtZvertexTimedifference); + colCuts.setApplyPileupRejection(configEvents.cfgEvtPileupRejection); + colCuts.setApplyNoITSROBorderCut(configEvents.cfgEvtNoITSROBorderCut); + colCuts.setApplyCollInTimeRangeStandard(configEvents.cfgEvtCollInTimeRangeStandard); + colCuts.printCuts(); + + // axes + AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisPtQA{binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec axisEta{binsEta, "#eta"}; + AxisSpec axisRap{binsEta, "#it{y}"}; + AxisSpec axisMassLambda1520{binsMass, "Invariant Mass (GeV/#it{c}^2)"}; + AxisSpec axisMult{binsMult, "mult_{V0M}"}; + AxisSpec axisDCAz{binsDCAz, "DCA_{z}"}; + AxisSpec axisDCAxy{binsDCAxy, "DCA_{XY}"}; + AxisSpec axisTPCXrow{binsTPCXrows, "#Xrows_{TPC}"}; + AxisSpec axisPIDQA{binsnSigma, "#sigma"}; + AxisSpec axisTPCSignal{binsnTPCSignal, ""}; + AxisSpec axisMClabel{6, -1.5f, 5.5f, "MC Label"}; + AxisSpec axisEtaPhi{binsEtaPhi, ""}; + AxisSpec axisPhi{350, 0, 7, "#Phi"}; + AxisSpec axisMultMix{configBkg.cfgMultBins, "Multiplicity"}; + AxisSpec axisVtxMix{configBkg.cfgVtxBins, "Vertex Z (cm)"}; + AxisSpec idxMCAxis = {26, -0.5f, 25.5f, "Index"}; + + if (cFilladditionalQAeventPlots) { + // event histograms + if (doprocessData) { + histos.add("QAevent/hPairsCounterSameE", "total valid no. of pairs sameE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + histos.add("QAevent/hnTrksSameE", "n tracks per event SameE", HistType::kTH1F, {{1000, 0.0, 1000.0}}); + } + // Test on Mixed event + if (doprocessME) { + + // Histograms for Mixed Event Pool characteristics + histos.add("QAevent/hMixPool_VtxZ", "Mixed Event Pool: Vertex Z;Vtx Z (cm);Counts", HistType::kTH1F, {axisVtxMix}); + histos.add("QAevent/hMixPool_Multiplicity", "Mixed Event Pool: Multiplicity;Multiplicity;Counts", HistType::kTH1F, {axisMultMix}); + histos.add("QAevent/hMixPool_VtxZ_vs_Multiplicity", "Mixed Event Pool: Vertex Z vs Multiplicity;Counts", HistType::kTH2F, {axisVtxMix, axisMultMix}); + + histos.add("QAevent/hPairsCounterMixedE", "total valid no. of pairs mixedE", HistType::kTH1F, {{1, 0.5f, 1.5f}}); + histos.add("QAevent/hVertexZMixedE", "Collision Vertex Z position", HistType::kTH1F, {{100, -15.0f, 15.0f}}); + histos.add("QAevent/hMultiplicityPercentMixedE", "Multiplicity percentile of collision", HistType::kTH1F, {{120, 0.0f, 120.0f}}); + histos.add("QAevent/hnTrksMixedE", "n tracks per event MixedE", HistType::kTH1F, {{1000, 0.0f, 1000.0f}}); + } + } + + if (doprocessData) { + // Track QA before cuts + // --- Track + if (cFillTrackQA) { + histos.add("QA/QAbefore/Track/TOF_TPC_Map_ka_all", "TOF + TPC Combined PID for Kaon;{#sigma_{TOF}^{Kaon}};{#sigma_{TPC}^{Kaon}}", {HistType::kTH2F, {axisPIDQA, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TPConly_Nsigma_ka", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Kaon}};", {HistType::kTH2F, {axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TOF_TPC_Map_pr_all", "TOF + TPC Combined PID for Proton;{#sigma_{TOF}^{Proton}};{#sigma_{TPC}^{Proton}}", {HistType::kTH2F, {axisPIDQA, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAbefore/Track/TPConly_Nsigma_pr", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Proton}};", {HistType::kTH2F, {axisPt, axisPIDQA}}); + 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 (cFillMultQA) { + // Multiplicity correlation calibrations + histos.add("MultCalib/centGloPVpr", "Centrality vs Global-Tracks", kTHnSparseF, {{110, 0, 110, "Centrality"}, {500, 0, 5000, "Global Tracks"}, {500, 0, 5000, "PV tracks"}}); + histos.add("MultCalib/centGloPVka", "Centrality vs Global-Tracks", kTHnSparseF, {{110, 0, 110, "Centrality"}, {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::kTH2F, {axisPIDQA, axisPIDQA}}); + histos.add("QA/QAafter/Kaon/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAafter/Kaon/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + 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, axisPIDQA}}); + 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} (GeV/#it{c});TPC Signal (A.U.)", {HistType::kTH2F, {axisPt, axisTPCSignal}}); + histos.add("QA/QAafter/Kaon/TPCnclusterPhika", "TPC ncluster vs phi", kTHnSparseF, {{160, 0, 160, "TPC nCluster"}, {63, 0.0f, 6.28f, "#phi"}}); + + // --- 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, {axisPIDQA, axisPIDQA}}); + histos.add("QA/QAafter/Proton/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/QAafter/Proton/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + 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, axisPIDQA}}); + 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} (GeV/#it{c});TPC Signal (A.U.)", {HistType::kTH2F, {axisPt, axisTPCSignal}}); + histos.add("QA/QAafter/Proton/TPCnclusterPhipr", "TPC ncluster vs phi", kTHnSparseF, {{160, 0, 160, "TPC nCluster"}, {63, 0.0f, 6.28f, "#phi"}}); + + // Mass QA 1D for quick check + if (cFill1DQAs) { + 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 (cFilldeltaEtaPhiPlots) { + histos.add("QAbefore/deltaEta", "deltaEta of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + histos.add("QAbefore/deltaPhi", "deltaPhi of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + + histos.add("QAafter/deltaEta", "deltaEta of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + histos.add("QAafter/deltaPhi", "deltaPhi of kaon and proton candidates", HistType::kTH1F, {axisEtaPhi}); + + histos.add("QAafter/PhiPrafter", "Phi of proton candidates", HistType::kTH1F, {axisPhi}); + histos.add("QAafter/PhiKaafter", "Phi of kaon candidates", HistType::kTH1F, {axisPhi}); + } + + // 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 (doprocessRotational) { + if (cFill1DQAs) { + histos.add("Result/Data/lambda1520InvMassRotation", "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/antilambda1520InvMassRotation", "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 + } + histos.add("Result/Data/h3lambda1520InvMassRotation", "Invariant mass of #Lambda(1520) rotation", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3antilambda1520InvMassRotation", "Invariant mass of #Lambda(1520) rotation", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + } + // Mixed event histograms + if (doprocessME) { + if (cFill1DQAs) { + histos.add("Result/Data/lambda1520invmassME_UnlikeSign", "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/antilambda1520invmassME_UnlikeSign", "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_UnlikeSign", "Invariant mass of #Lambda(1520) mixed event K^{#pm}p^{#mp}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/Data/h3antilambda1520invmassME_UnlikeSign", "Invariant mass of #Lambda(1520) mixed event K^{#pm}p^{#mp}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + + if (cFilladditionalMEPlots) { + if (cFill1DQAs) { + histos.add("Result/Data/lambda1520invmassME_LSPP", "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/lambda1520invmassME_LSMM", "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 + } + histos.add("Result/Data/h3lambda1520invmassME_LSPP", "Invariant mass of #Lambda(1520) mixed event Like Sign Method K^{#plus}p^{#plus}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); // K+ + Pr + histos.add("Result/Data/h3lambda1520invmassME_LSMM", "Invariant mass of #Lambda(1520) mixed event Like Sign Method K^{#minus}p^{#minus}", HistType::kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); // K- + anti-Pr + } + } + + // MC QA + histos.add("Event/hMCEventIndices", "hMCEventIndices", kTH2D, {axisMult, idxMCAxis}); + if (doprocessMCTrue) { + histos.add("QA/MC/h2GenEtaPt_beforeanycut", " #eta-#it{p}_{T} distribution of Generated #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPtQA}); + histos.add("QA/MC/h2GenPhiRapidity_beforeanycut", " #phi-y distribution of Generated #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); + histos.add("QA/MC/h2GenEtaPt_afterEtaRapCut", " #eta-#it{p}_{T} distribution of Generated #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPtQA}); + histos.add("QA/MC/h2GenPhiRapidity_afterEtaRapCut", " #phi-y distribution of Generated #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); + histos.add("QA/MC/h2GenEtaPt_afterRapcut", " #phi-#it{p}_{T} distribution of Generated #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPtQA}); + histos.add("QA/MC/h2GenPhiRapidity_afterRapcut", " #phi-y distribution of Generated #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); + + histos.add("Result/MC/Genlambda1520pt", "pT distribution of True MC #Lambda(1520)0", kTH3F, {axisMClabel, axisPt, axisMult}); + histos.add("Result/MC/Genantilambda1520pt", "pT distribution of True MC Anti-#Lambda(1520)0", kTH3F, {axisMClabel, axisPt, axisMult}); + } + if (doprocessMC) { + histos.add("QA/MC/h2RecoEtaPt_after", " #eta-#it{p}_{T} distribution of Reconstructed #Lambda(1520); #eta; #it{p}_{T}; Counts;", HistType::kTHnSparseF, {axisEta, axisPt}); + histos.add("QA/MC/h2RecoPhiRapidity_after", " #phi-y distribution of Reconstructed #Lambda(1520); #phi; y; Counts;", HistType::kTHnSparseF, {axisPhi, axisRap}); + + histos.add("QA/MC/trkDCAxy_pr", "DCAxy distribution of proton track candidates", HistType::kTHnSparseF, {axisPt, axisDCAxy}); + histos.add("QA/MC/trkDCAxy_ka", "DCAxy distribution of kaon track candidates", HistType::kTHnSparseF, {axisPt, axisDCAxy}); + histos.add("QA/MC/trkDCAz_pr", "DCAz distribution of proton track candidates", HistType::kTHnSparseF, {axisPt, axisDCAz}); + histos.add("QA/MC/trkDCAz_ka", "DCAz distribution of kaon track candidates", HistType::kTHnSparseF, {axisPt, axisDCAz}); + histos.add("QA/MC/TOF_Nsigma_pr_all", "TOF NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/MC/TPC_Nsigma_pr_all", "TPC NSigma for Proton;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Proton}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/MC/TOF_Nsigma_ka_all", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TOF}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + histos.add("QA/MC/TPC_Nsigma_ka_all", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});{#sigma_{TPC}^{Kaon}};", {HistType::kTHnSparseF, {axisMult, axisPt, axisPIDQA}}); + + histos.add("Result/MC/h3lambda1520Recoinvmass", "Invariant mass of Reconstructed MC #Lambda(1520)0", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + histos.add("Result/MC/h3antilambda1520Recoinvmass", "Invariant mass of Reconstructed MC Anti-#Lambda(1520)0", kTHnSparseF, {axisMult, axisPt, axisMassLambda1520}); + } + + // Print output histograms statistics + LOG(info) << "Size of the histograms in Lambda1520analysisinpp:"; + histos.print(); + } + + float massKa = MassKaonCharged; + float massPr = MassProton; + + // Centralicity estimator selection + template + float centEst(Coll collisions) + { + float returnValue = -999.0f; + switch (centEstimator) { + case 0: + returnValue = collisions.centFT0M(); + break; + case 1: + returnValue = collisions.centFT0A(); + break; + case 2: + returnValue = collisions.centFT0C(); + break; + default: + returnValue = collisions.centFT0M(); + break; + } + return returnValue; + } + + auto static constexpr TripleCharge = 3.0f; + + // 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()) >= TripleCharge) { // check if the particle is charged + if (std::abs(mcparticle.eta()) < 1.0f) + return true; + } + } + } + return false; + } + + template + bool trackCut(const TrackType track) + { + // basic track cuts + if (configTracks.cDCAr7SigCut && std::abs(track.dcaXY()) > (0.004f + 0.013f / (track.pt()))) // 7 - Sigma cut + return false; + if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) + return false; + if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) + return false; + if (configTracks.cfgHasTOF && !track.hasTOF()) + return false; + if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) + return false; + if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (configTracks.cfgPVContributor && !track.isPVContributor()) + return false; + if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) + return false; + + return true; + } + + // LOGF(info, "AFTER: pt: %f, hasTOF: %d, TPCSigma: %f, TOFSigma: %f, boolTPC: %d, boolTOF: %d, bool: %d", pt, candidate.hasTOF(), + // candidate.tpcNSigmaPr(), candidate.tofNSigmaPr(), tpcPIDPassed, tofPIDPassed, tpcPIDPassed || tofPIDPassed); + + template + bool ptDependentPidProton(const T& candidate) + { + auto vProtonTPCPIDpTintv = configPID.protonTPCPIDpTintv.value; + vProtonTPCPIDpTintv.insert(vProtonTPCPIDpTintv.begin(), configTracks.cMinPtcut); + auto vProtonTPCPIDcuts = configPID.protonTPCPIDcuts.value; + auto vProtonTOFPIDpTintv = configPID.protonTOFPIDpTintv.value; + auto vProtonTPCTOFCombinedpTintv = configPID.protonTPCTOFCombinedpTintv.value; + auto vProtonTPCTOFCombinedPIDcuts = configPID.protonTPCTOFCombinedPIDcuts.value; + auto vProtonTOFPIDcuts = configPID.protonTOFPIDcuts.value; + + float pt = candidate.pt(); + float ptSwitchToTOF = vProtonTPCPIDpTintv.back(); + float tpcNsigmaPr = candidate.tpcNSigmaPr(); + float tofNsigmaPr = candidate.tofNSigmaPr(); + + bool tpcPIDPassed = false; + + // TPC PID (interval check) + for (size_t i = 0; i < vProtonTPCPIDpTintv.size() - 1; ++i) { + if (pt > vProtonTPCPIDpTintv[i] && pt < vProtonTPCPIDpTintv[i + 1]) { + if (std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts[i]) + tpcPIDPassed = true; + } + } + + // TOF bypass option (for QA or MC) + if (configPID.cByPassTOF) { + return std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back(); + } + + // Case 1: No TOF and pt ≤ threshold → accept only via TPC PID + if (!candidate.hasTOF() && pt <= ptSwitchToTOF) { + return tpcPIDPassed; + } + + // Case 2: No TOF but pt > threshold → reject + if (!candidate.hasTOF() && pt > ptSwitchToTOF) { + return false; + } + + // Case 3: Has TOF → use TPC + TOF (square or circular) + if (candidate.hasTOF()) { + if (configPID.cPIDcutType == SquareType) { + // Rectangular cut + for (size_t i = 0; i < vProtonTOFPIDpTintv.size(); ++i) { + if (pt < vProtonTOFPIDpTintv[i]) { + if (std::abs(tofNsigmaPr) < vProtonTOFPIDcuts[i] && + std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back()) + return true; + } + } + } else if (configPID.cPIDcutType == CircularType) { + // Circular cut + for (size_t i = 0; i < vProtonTPCTOFCombinedpTintv.size(); ++i) { + if (pt < vProtonTPCTOFCombinedpTintv[i]) { + float combinedSigma2 = + tpcNsigmaPr * tpcNsigmaPr + + tofNsigmaPr * tofNsigmaPr; + if (combinedSigma2 < vProtonTPCTOFCombinedPIDcuts[i] * vProtonTPCTOFCombinedPIDcuts[i]) + return true; + } + } + } + } + + return false; + } + + template + bool ptDependentPidKaon(const T& candidate) + { + auto vKaonTPCPIDpTintv = configPID.kaonTPCPIDpTintv.value; + vKaonTPCPIDpTintv.insert(vKaonTPCPIDpTintv.begin(), configTracks.cMinPtcut); + auto vKaonTPCPIDcuts = configPID.kaonTPCPIDcuts.value; + auto vKaonTOFPIDpTintv = configPID.kaonTOFPIDpTintv.value; + auto vKaonTPCTOFCombinedpTintv = configPID.kaonTPCTOFCombinedpTintv.value; + auto vKaonTPCTOFCombinedPIDcuts = configPID.kaonTPCTOFCombinedPIDcuts.value; + auto vKaonTOFPIDcuts = configPID.kaonTOFPIDcuts.value; + + float pt = candidate.pt(); + float ptSwitchToTOF = vKaonTPCPIDpTintv.back(); + float tpcNsigmaKa = candidate.tpcNSigmaKa(); + float tofNsigmaKa = candidate.tofNSigmaKa(); + + bool tpcPIDPassed = false; + + // TPC PID interval-based check + for (size_t i = 0; i < vKaonTPCPIDpTintv.size() - 1; ++i) { + if (pt > vKaonTPCPIDpTintv[i] && pt < vKaonTPCPIDpTintv[i + 1]) { + if (std::abs(tpcNsigmaKa) < vKaonTPCPIDcuts[i]) { + tpcPIDPassed = true; + break; + } + } + } + + // TOF bypass option + if (configPID.cByPassTOF) { + return std::abs(tpcNsigmaKa) < vKaonTPCPIDcuts.back(); + } + + // Case 1: No TOF and pt ≤ ptSwitch → use TPC-only + if (!candidate.hasTOF() && pt <= ptSwitchToTOF) { + return tpcPIDPassed; + } + + // Case 2: No TOF but pt > ptSwitch → reject + if (!candidate.hasTOF() && pt > ptSwitchToTOF) { + return false; + } + + // Case 3: TOF is available → apply TPC+TOF PID logic + if (candidate.hasTOF()) { + if (configPID.cPIDcutType == SquareType) { + // Rectangular cut + for (size_t i = 0; i < vKaonTOFPIDpTintv.size(); ++i) { + if (pt < vKaonTOFPIDpTintv[i]) { + if (std::abs(tofNsigmaKa) < vKaonTOFPIDcuts[i] && + std::abs(tpcNsigmaKa) < vKaonTPCPIDcuts.back()) { + return true; + } + } + } + } else if (configPID.cPIDcutType == CircularType) { + // Circular cut + for (size_t i = 0; i < vKaonTPCTOFCombinedpTintv.size(); ++i) { + if (pt < vKaonTPCTOFCombinedpTintv[i]) { + float combinedSigma2 = tpcNsigmaKa * tpcNsigmaKa + + tofNsigmaKa * tofNsigmaKa; + if (combinedSigma2 < vKaonTPCTOFCombinedPIDcuts[i] * vKaonTPCTOFCombinedPIDcuts[i]) { + return true; + } + } + } + } + } + + return false; + } + + auto static constexpr MinPtforPionRejection = 1.0f; + auto static constexpr MaxPtforPionRejection = 2.0f; + auto static constexpr MaxnSigmaforPionRejection = 2.0f; + + template + bool rejectPion(const T& candidate) + { + if (candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection) { + return false; + } + return true; + } + + auto static constexpr MaxNoLambda1520Daughters = 2; + + template + void fillHistograms(const CollisionType& collision, const TracksType& dTracks1, const TracksType& dTracks2) + { + auto centrality = centEst(collision); + + // Multiplicity correlation calibration plots + if (cFillMultQA) { + if constexpr (IsData) { + histos.fill(HIST("MultCalib/centGloPVpr"), centrality, dTracks1.size(), collision.multNTracksPV()); + histos.fill(HIST("MultCalib/centGloPVka"), centrality, dTracks2.size(), collision.multNTracksPV()); + } + } + + if (cFilladditionalQAeventPlots) { + if constexpr (IsData) { + histos.fill(HIST("QAevent/hnTrksSameE"), dTracks1.size()); + } else if constexpr (IsMix) { + histos.fill(HIST("QAevent/hVertexZMixedE"), collision.posZ()); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), centrality); + histos.fill(HIST("QAevent/hnTrksMixedE"), dTracks1.size()); + } + } + // LOG(info) << "After pass, Collision index:" << collision.index() << "multiplicity: " << collision.centFT0M() << endl; + + LorentzVectorPtEtaPhiMass 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. + + // apply the track cut + if (!trackCut(trk1) || !trackCut(trk2)) + continue; + + //// Initialize variables + // Trk1: Proton + auto isTrk1hasTOF = trk1.hasTOF(); + auto trk1ptPr = trk1.pt(); + auto trk1etaPr = trk1.eta(); + auto trk1phiPr = trk1.phi(); + auto trk1NSigmaPrTPC = trk1.tpcNSigmaPr(); + auto trk1NSigmaPrTOF = (isTrk1hasTOF) ? trk1.tofNSigmaPr() : -999.0f; + + // Trk2: Kaon + auto isTrk2hasTOF = trk2.hasTOF(); + auto trk2ptKa = trk2.pt(); + auto trk2etaKa = trk2.eta(); + auto trk2phiKa = trk2.phi(); + auto trk2NSigmaKaTPC = trk2.tpcNSigmaKa(); + auto trk2NSigmaKaTOF = (isTrk2hasTOF) ? trk2.tofNSigmaKa() : -999.0f; + + auto deltaEta = 0.0f; + auto deltaPhi = 0.0f; + + if (cfgUseDeltaEtaPhiCuts) { + deltaEta = std::abs(trk1etaPr - trk2etaKa); + deltaPhi = std::abs(trk1phiPr - trk2phiKa); + deltaPhi = (deltaPhi > o2::constants::math::PI) ? (o2::constants::math::TwoPI - deltaPhi) : deltaPhi; + if (deltaEta >= cMaxDeltaEtaCut) + continue; + if (deltaPhi >= cMaxDeltaPhiCut) + continue; + } + + //// QA plots before the selection + // --- Track QA all + if constexpr (IsData) { + if (cFillTrackQA) { + histos.fill(HIST("QA/QAbefore/Track/TPC_Nsigma_pr_all"), centrality, trk1ptPr, trk1NSigmaPrTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/QAbefore/Track/TOF_Nsigma_pr_all"), centrality, trk1ptPr, trk1NSigmaPrTOF); + histos.fill(HIST("QA/QAbefore/Track/TOF_TPC_Map_pr_all"), trk1NSigmaPrTOF, trk1NSigmaPrTPC); + } + if (!isTrk1hasTOF) { + histos.fill(HIST("QA/QAbefore/Track/TPConly_Nsigma_pr"), trk1ptPr, trk1NSigmaPrTPC); + } + histos.fill(HIST("QA/QAbefore/Track/TPC_Nsigma_ka_all"), centrality, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/QAbefore/Track/TOF_Nsigma_ka_all"), centrality, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QA/QAbefore/Track/TOF_TPC_Map_ka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } + if (!isTrk2hasTOF) { + histos.fill(HIST("QA/QAbefore/Track/TPConly_Nsigma_ka"), trk2ptKa, trk2NSigmaKaTPC); + } + + histos.fill(HIST("QA/QAbefore/Track/dcaZ"), trk1ptPr, trk1.dcaZ()); + histos.fill(HIST("QA/QAbefore/Track/dcaXY"), trk1ptPr, trk1.dcaXY()); + 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"), trk1etaPr); + } + if (cFilldeltaEtaPhiPlots) { + histos.fill(HIST("QAbefore/deltaEta"), deltaEta); + histos.fill(HIST("QAbefore/deltaPhi"), deltaPhi); + } + } + + //// Apply the pid selection + if (crejectPion && rejectPion(trk2)) // to remove pion contamination from the kaon track + continue; + + if (!ptDependentPidProton(trk1) || !ptDependentPidKaon(trk2)) + continue; + + //// QA plots after the selection + if constexpr (IsData) { // --- PID QA Proton + histos.fill(HIST("QA/QAafter/Proton/TPC_Nsigma_pr_all"), centrality, trk1ptPr, trk1NSigmaPrTPC); + histos.fill(HIST("QA/QAafter/Proton/TPC_Signal_pr_all"), trk1.tpcInnerParam(), trk1.tpcSignal()); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/QAafter/Proton/TOF_Nsigma_pr_all"), centrality, trk1ptPr, trk1NSigmaPrTOF); + histos.fill(HIST("QA/QAafter/Proton/TOF_TPC_Map_pr_all"), trk1NSigmaPrTOF, trk1NSigmaPrTPC); + } + if (!isTrk1hasTOF) { + histos.fill(HIST("QA/QAafter/Proton/TPC_Nsigma_pr_TPConly"), trk1ptPr, trk1NSigmaPrTPC); + } + histos.fill(HIST("QA/QAafter/Proton/dcaZ"), trk1ptPr, trk1.dcaZ()); + histos.fill(HIST("QA/QAafter/Proton/dcaXY"), trk1ptPr, trk1.dcaXY()); + histos.fill(HIST("QA/QAafter/Proton/TPC_CR"), trk1ptPr, trk1.tpcNClsCrossedRows()); + histos.fill(HIST("QA/QAafter/Proton/pT"), trk1ptPr); + histos.fill(HIST("QA/QAafter/Proton/eta"), trk1etaPr); + histos.fill(HIST("QA/QAafter/Proton/TPCnclusterPhipr"), trk1.tpcNClsFound(), trk1phiPr); + + // --- PID QA Kaon + histos.fill(HIST("QA/QAafter/Kaon/TPC_Nsigma_ka_all"), centrality, trk2ptKa, trk2NSigmaKaTPC); + histos.fill(HIST("QA/QAafter/Kaon/TPC_Signal_ka_all"), trk2.tpcInnerParam(), trk2.tpcSignal()); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/QAafter/Kaon/TOF_Nsigma_ka_all"), centrality, trk2ptKa, trk2NSigmaKaTOF); + histos.fill(HIST("QA/QAafter/Kaon/TOF_TPC_Map_ka_all"), trk2NSigmaKaTOF, trk2NSigmaKaTPC); + } + if (!isTrk2hasTOF) { + histos.fill(HIST("QA/QAafter/Kaon/TPC_Nsigma_ka_TPConly"), trk2ptKa, trk2NSigmaKaTPC); + } + histos.fill(HIST("QA/QAafter/Kaon/dcaZ"), trk2ptKa, trk2.dcaZ()); + histos.fill(HIST("QA/QAafter/Kaon/dcaXY"), trk2ptKa, trk2.dcaXY()); + 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"), trk2etaKa); + histos.fill(HIST("QA/QAafter/Kaon/TPCnclusterPhika"), trk2.tpcNClsFound(), trk2phiKa); + + if (cFilldeltaEtaPhiPlots) { + histos.fill(HIST("QAafter/PhiPrafter"), trk1phiPr); + histos.fill(HIST("QAafter/PhiKaafter"), trk2phiKa); + histos.fill(HIST("QAafter/deltaEta"), deltaEta); + histos.fill(HIST("QAafter/deltaPhi"), deltaPhi); + } + } + + //// Resonance reconstruction + lDecayDaughter1 = LorentzVectorPtEtaPhiMass(trk1ptPr, trk1etaPr, trk1phiPr, massPr); + lDecayDaughter2 = LorentzVectorPtEtaPhiMass(trk2ptKa, trk2etaKa, trk2phiKa, massKa); + + // Apply kinematic opening angle cut + if (cUseOpeningAngleCut) { + auto v1 = lDecayDaughter1.Vect(); + auto v2 = lDecayDaughter2.Vect(); + float alpha = std::acos(v1.Dot(v2) / (v1.R() * v2.R())); + if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) + continue; + } + + lResonance = lDecayDaughter1 + lDecayDaughter2; + + auto resonanceMass = lResonance.M(); + auto resonancePt = lResonance.Pt(); + auto resonanceRapidity = lResonance.Rapidity(); + + if constexpr (IsData || IsMix) { + // Rapidity cut + if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) + continue; + } + + if (cfgUseCutsOnMother) { + if (resonancePt >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (resonanceMass >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + + if (cFilladditionalQAeventPlots) { + if constexpr (IsData) { + histos.fill(HIST("QAevent/hPairsCounterSameE"), 1.0f); + } else if (IsMix) { + histos.fill(HIST("QAevent/hPairsCounterMixedE"), 1.0f); + } + } + + //// Un-like sign pair only + if (trk1.sign() * trk2.sign() < 0) { + if constexpr (IsRot) { + for (int i = 0; i < configBkg.cNofRotations; i++) { + float theta = rn->Uniform(o2::constants::math::PI - o2::constants::math::PI / configBkg.rotationalcut, o2::constants::math::PI + o2::constants::math::PI / configBkg.rotationalcut); + if (configBkg.cfgRotPr) { + ldaughterRot = LorentzVectorPtEtaPhiMass(trk1ptPr, trk1etaPr, trk1phiPr + theta, massPr); + lResonanceRot = ldaughterRot + lDecayDaughter2; + } else { + ldaughterRot = LorentzVectorPtEtaPhiMass(trk2ptKa, trk2etaKa, trk2phiKa + theta, massKa); + lResonanceRot = lDecayDaughter1 + ldaughterRot; + } + auto resonanceRotMass = lResonanceRot.M(); + auto resonanceRotPt = lResonanceRot.Pt(); + + // Rapidity cut + if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) + continue; + + if (cfgUseCutsOnMother) { + if (resonanceRotPt >= cMaxPtMotherCut) // excluding candidates in overflow + continue; + if (resonanceRotMass >= cMaxMinvMotherCut) // excluding candidates in overflow + continue; + } + if (trk1.sign() < 0) { + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/lambda1520InvMassRotation"), resonanceRotMass); + } + histos.fill(HIST("Result/Data/h3lambda1520InvMassRotation"), centrality, resonanceRotPt, resonanceRotMass); + } else if (trk1.sign() > 0) { + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/antilambda1520InvMassRotation"), resonanceRotMass); + } + histos.fill(HIST("Result/Data/h3antilambda1520InvMassRotation"), centrality, resonanceRotPt, resonanceRotMass); + } + } + } + if constexpr (IsData) { + if (trk1.sign() < 0) { + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/lambda1520invmass"), resonanceMass); + } + histos.fill(HIST("Result/Data/h3lambda1520invmass"), centrality, resonancePt, resonanceMass); + } else if (trk1.sign() > 0) { + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/antilambda1520invmass"), resonanceMass); + } + histos.fill(HIST("Result/Data/h3antilambda1520invmass"), centrality, resonancePt, resonanceMass); + } + } else if (IsMix) { + if (trk1.sign() < 0) { + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/lambda1520invmassME_UnlikeSign"), resonanceMass); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassME_UnlikeSign"), centrality, resonancePt, resonanceMass); + } else if (trk1.sign() > 0) { + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/antilambda1520invmassME_UnlikeSign"), resonanceMass); + } + histos.fill(HIST("Result/Data/h3antilambda1520invmassME_UnlikeSign"), centrality, resonancePt, resonanceMass); + } + } + + // MC + if constexpr (IsMC) { + // now we do mc true + // ------ 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; + }; + // ------ + std::vector motherstrk1 = {-1, -1}; + std::vector mothersPDGtrk1 = {-1, -1}; + + std::vector motherstrk2 = {-1, -1}; + std::vector mothersPDGtrk2 = {-1, -1}; + + // + // Get the MC particle + const auto& mctrk1 = trk1.mcParticle(); + if (mctrk1.has_mothers()) { + motherstrk1 = getMothersIndeces(mctrk1); + mothersPDGtrk1 = getMothersPDGCodes(mctrk1); + } + while (motherstrk1.size() > MaxNoLambda1520Daughters) { + motherstrk1.pop_back(); + mothersPDGtrk1.pop_back(); + } + + const auto& mctrk2 = trk2.mcParticle(); + if (mctrk2.has_mothers()) { + motherstrk2 = getMothersIndeces(mctrk2); + mothersPDGtrk2 = getMothersPDGCodes(mctrk2); + } + while (motherstrk2.size() > MaxNoLambda1520Daughters) { + motherstrk2.pop_back(); + mothersPDGtrk2.pop_back(); + } + + if (std::abs(mctrk1.pdgCode()) != kProton || std::abs(mctrk2.pdgCode()) != kKPlus) + continue; + + if (motherstrk1[0] != motherstrk2[0]) // Same mother + continue; + + if (std::abs(mothersPDGtrk1[0]) != Pdg::kLambda1520_Py) + continue; + + // LOGF(info, "mother trk1 id: %d, mother trk1: %d, trk1 id: %d, trk1 pdgcode: %d, mother trk2 id: %d, mother trk2: %d, trk2 id: %d, trk2 pdgcode: %d", motherstrk1[0], mothersPDGtrk1[0], trk1.globalIndex(), mctrk1.pdgCode(), motherstrk2[0], mothersPDGtrk2[0], trk2.globalIndex(), mctrk2.pdgCode()); + + if (cUseEtacutMC && std::abs(lResonance.Eta()) > cEtacutMC) // eta cut + continue; + + if (cUseRapcutMC && std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) // rapidity cut + continue; + + histos.fill(HIST("QA/MC/h2RecoEtaPt_after"), lResonance.Eta(), resonancePt); + histos.fill(HIST("QA/MC/h2RecoPhiRapidity_after"), lResonance.Phi(), resonanceRapidity); + + // Track selection check. + 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"), centrality, trk1ptPr, trk1NSigmaPrTPC); + if (isTrk1hasTOF) { + histos.fill(HIST("QA/MC/TOF_Nsigma_pr_all"), centrality, trk1ptPr, trk1NSigmaPrTOF); + } + histos.fill(HIST("QA/MC/TPC_Nsigma_ka_all"), centrality, trk2ptKa, trk2NSigmaKaTPC); + if (isTrk2hasTOF) { + histos.fill(HIST("QA/MC/TOF_Nsigma_ka_all"), centrality, trk2ptKa, trk2NSigmaKaTOF); + } + + // MC histograms + if (mothersPDGtrk1[0] > 0) { + histos.fill(HIST("Result/MC/h3lambda1520Recoinvmass"), centrality, resonancePt, resonanceMass); + } else { + histos.fill(HIST("Result/MC/h3antilambda1520Recoinvmass"), centrality, resonancePt, resonanceMass); + } + } + } else { + if constexpr (IsData) { + // Like sign pair ++ + if (trk1.sign() > 0) { + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/lambda1520invmassLSPP"), resonanceMass); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassLSPP"), centrality, resonancePt, resonanceMass); + } else { // Like sign pair -- + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/lambda1520invmassLSMM"), resonanceMass); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassLSMM"), centrality, resonancePt, resonanceMass); + } + } else if (IsMix) { + if (cFilladditionalMEPlots) { + // Like sign pair ++ + if (trk1.sign() > 0) { + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/lambda1520invmassME_LSPP"), resonanceMass); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassME_LSPP"), centrality, resonancePt, resonanceMass); + } else { // Like sign pair -- + if (cFill1DQAs) { + histos.fill(HIST("Result/Data/lambda1520invmassME_LSMM"), resonanceMass); + } + histos.fill(HIST("Result/Data/h3lambda1520invmassME_LSMM"), centrality, resonancePt, resonanceMass); + } + } + } + } + } + } + + void processData(EventCandidates::iterator const& collision, + TrackCandidates const& tracks) + { + if (!colCuts.isSelected(collision)) // Default event selection + return; + + colCuts.fillQA(collision); + + fillHistograms(collision, tracks, tracks); + } + PROCESS_SWITCH(Lambda1520analysisinpp, processData, "Process Event for data without partition", false); + + void processRotational(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + if (!colCuts.isSelected(collision, false)) // Default event selection + return; + + fillHistograms(collision, tracks, tracks); + } + PROCESS_SWITCH(Lambda1520analysisinpp, processRotational, "Process Rotational Background", false); + + void processMC(MCEventCandidates::iterator const& collision, + aod::McCollisions const&, + MCTrackCandidates const& tracks, aod::McParticles const&) + { + colCuts.fillQA(collision); + + if (std::abs(collision.posZ()) > cZvertCutMC) // Z-vertex cut + return; + + fillHistograms(collision, tracks, tracks); + } + PROCESS_SWITCH(Lambda1520analysisinpp, processMC, "Process Event for MC Light without partition", false); + + Partition selectedMCParticles = (nabs(aod::mcparticle::pdgCode) == static_cast(Pdg::kLambda1520_Py)); // Lambda(1520) + + void processMCTrue(MCEventCandidates::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) + { + bool isInAfterAllCuts = colCuts.isSelected(collision); + bool inVtx10 = (std::abs(collision.mcCollision().posZ()) > configEvents.cfgEvtZvtx) ? false : true; + bool isTriggerTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); + bool isSel8 = collision.sel8(); + bool isTrueINELgt0 = isTrueINEL0(collision, mcParticles); + auto centrality = centEst(collision); + + auto mcParts = selectedMCParticles->sliceBy(perMcCollision, collision.mcCollision().globalIndex()); + + // Not related to the real collisions + for (const auto& part : mcParts) { // loop over all MC particles + + std::vector daughterPDGs; + if (part.has_daughters()) { + auto daughter01 = mcParticles.rawIteratorAt(part.daughtersIds()[0] - mcParticles.offset()); + auto daughter02 = mcParticles.rawIteratorAt(part.daughtersIds()[1] - mcParticles.offset()); + daughterPDGs = {daughter01.pdgCode(), daughter02.pdgCode()}; + } else { + daughterPDGs = {-1, -1}; + } + + bool pass1 = std::abs(daughterPDGs[0]) == kKPlus || std::abs(daughterPDGs[1]) == kKPlus; // At least one decay to Kaon + bool pass2 = std::abs(daughterPDGs[0]) == kProton || std::abs(daughterPDGs[1]) == kProton; // At least one decay to Proton + + // Checking if we have both decay products + if (!pass1 || !pass2) + continue; + + // LOGF(info, "Part PDG: %d", part.pdgCode(), "DAU_ID1: %d", pass1, "DAU_ID2: %d", pass2); + + histos.fill(HIST("QA/MC/h2GenEtaPt_beforeanycut"), part.eta(), part.pt()); + histos.fill(HIST("QA/MC/h2GenPhiRapidity_beforeanycut"), part.phi(), part.y()); + + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) // rapidity cut + continue; + + if (cfgUseDaughterEtaCutMC) { + for (auto const& daughters : part.daughters_as()) { + if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) + continue; // eta cut for daughters + } // loop over daughters + } + + histos.fill(HIST("QA/MC/h2GenEtaPt_afterRapcut"), part.eta(), part.pt()); + histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterRapcut"), part.phi(), part.y()); + + if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) // eta cut + continue; + + histos.fill(HIST("QA/MC/h2GenEtaPt_afterEtaRapCut"), part.eta(), part.pt()); + histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterEtaRapCut"), part.phi(), part.y()); + + // without any event selection + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 0, part.pt(), centrality); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 0, part.pt(), centrality); + + if (inVtx10) // INEL10 + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 1, part.pt(), centrality); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 1, part.pt(), centrality); + } + if (inVtx10 && isSel8) // INEL>10, vtx10 + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 2, part.pt(), centrality); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 2, part.pt(), centrality); + } + if (inVtx10 && isTriggerTVX) // vtx10, TriggerTVX + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 3, part.pt(), centrality); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 3, part.pt(), centrality); + } + if (isInAfterAllCuts) // after all event selection + { + if (part.pdgCode() > 0) + histos.fill(HIST("Result/MC/Genlambda1520pt"), 4, part.pt(), centrality); + else + histos.fill(HIST("Result/MC/Genantilambda1520pt"), 4, part.pt(), centrality); + } + } + + // QA for Trigger efficiency + histos.fill(HIST("Event/hMCEventIndices"), centrality, Inel); + if (inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Inel10); + if (isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Inelg0); + if (inVtx10 && isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Inelg010); + + // TVX MB trigger + if (isTriggerTVX) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Trig); + if (isTriggerTVX && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Trig10); + if (isTriggerTVX && isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, TrigINELg0); + if (isTriggerTVX && isTrueINELgt0 && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, TrigINELg010); + + // Sel8 event selection + if (isSel8) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Sel8); + if (isSel8 && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Sel810); + if (isSel8 && isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Sel8INELg0); + if (isSel8 && isTrueINELgt0 && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, Sel8INELg010); + + // CollisionCuts selection + if (isInAfterAllCuts) + histos.fill(HIST("Event/hMCEventIndices"), centrality, AllCuts); + if (isInAfterAllCuts && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, AllCuts10); + if (isInAfterAllCuts && isTrueINELgt0) + histos.fill(HIST("Event/hMCEventIndices"), centrality, AllCutsINELg0); + if (isInAfterAllCuts && isTrueINELgt0 && inVtx10) + histos.fill(HIST("Event/hMCEventIndices"), centrality, AllCutsINELg010); + } + PROCESS_SWITCH(Lambda1520analysisinpp, processMCTrue, "Process Event for MC only", false); + + // Processing Event Mixing + using BinningTypeVtxZT0M = ColumnBinningPolicy; + + void processME(EventCandidates const& collision, + TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + + BinningTypeVtxZT0M colBinning{{configBkg.cfgVtxBins, configBkg.cfgMultBins}, true}; + SameKindPair pairs{colBinning, configBkg.nEvtMixing, -1, collision, tracksTuple, &cache}; // -1 is the number of the bin to skip + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.globalIndex(), collision2.globalIndex()); + + // for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + // LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d)", t1.index(), t2.index(), collision1.index(), collision2.index()); + // } + + if (cFilladditionalQAeventPlots) { + // Fill histograms for the characteristics of the *mixed* events (collision1 and collision2) + // This will show the distribution of events that are actually being mixed. + if (cFill1DQAs) { + histos.fill(HIST("QAevent/hMixPool_VtxZ"), collision1.posZ()); + histos.fill(HIST("QAevent/hMixPool_Multiplicity"), collision1.centFT0M()); + } + histos.fill(HIST("QAevent/hMixPool_VtxZ_vs_Multiplicity"), collision1.posZ(), collision1.centFT0M()); + + // You might also want to fill for collision2 if you want to see both partners' distributions + // histos.fill(HIST("QAevent/hMixPool_VtxZ"), collision2.posZ()); + // histos.fill(HIST("QAevent/hMixPool_Multiplicity"), collision2.centFT0M()); + // histos.fill(HIST("QAevent/hMixPool_VtxZ_vs_Multiplicity"), collision2.posZ(), collision2.centFT0M()); + } + fillHistograms(collision1, tracks1, tracks2); + } + } + PROCESS_SWITCH(Lambda1520analysisinpp, processME, "Process EventMixing light without partition", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/lambdav2.cxx b/PWGLF/Tasks/Resonances/lambdav2.cxx index 4fbb16beddc..9b50cc5a490 100644 --- a/PWGLF/Tasks/Resonances/lambdav2.cxx +++ b/PWGLF/Tasks/Resonances/lambdav2.cxx @@ -8,11 +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 this is a code for flow of lambda baryons for exotic pheno -/// \author prottay das -/// \since 25/04/2024 +// Particle flow task +// prottay.das@cern.ch +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" #include #include #include @@ -23,33 +26,38 @@ #include #include #include -#include "TF1.h" #include #include #include -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" +// #include "Common/DataModel/Qvectors.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/SPCalibrationTables.h" + #include "Common/Core/TrackSelection.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/StepTHn.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" -#include "PWGLF/DataModel/EPCalibrationTables.h" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -57,302 +65,148 @@ using std::array; struct lambdav2 { - // 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", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - // Configurable for histograms - Configurable nBins{"nBins", 100, "N bins in all histos"}; - // Confugrable for QA histograms - Configurable QA{"QA", true, "QA"}; - 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", 4, - "Maximum V0 life time"}; - Configurable cMaxV0DCA{"cMaxV0DCA", 0.3, "DCA V0 to PV"}; - Configurable cSigmaMassLambda{"cSigmaMassLambda", 4, - "n Sigma cut on Lambda mass"}; - Configurable cWidthLambda{"cWidthLambda", 0.005, "Width of Lambda"}; - 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 nsigmaCutTOF{"nsigmacutTOF", 3.0, - "Value of the TOF Nsigma cut"}; - Configurable nsigmaCutCombined{"nsigmaCutCombined", 3.0, - "Value of the Combined Nsigma cut"}; - Configurable iscustomDCAcut{"iscustomDCAcut", false, "iscustomDCAcut"}; - Configurable ismanualDCAcut{"ismanualDCAcut", true, "ismanualDCAcut"}; - Configurable cfgITScluster{"cfgITScluster", 0, "Number of ITS cluster"}; + 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 isNoTOF{"isNoTOF", false, "isNoTOF"}; - 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; - - void init(InitContext const&) - { - // Axes - AxisSpec vertexZAxis = {nBins, -10., 10., "vrtx_{Z} [cm]"}; - AxisSpec ptAxis = {200, 0.0f, 20.0f, "#it{p}_{T} (GeV/#it{c})"}; - - // Event selection - rEventSelection.add("hVertexZRec", "hVertexZRec", - {HistType::kTH1F, {vertexZAxis}}); - rEventSelection.add("hmult", "Centrality distribution", kTH1F, - {{100, 0.0f, 100.0f}}); - - // from sourav da - AxisSpec phiAxis = {500, -6.28, 6.28, "phi"}; - AxisSpec resAxis = {400, -2, 2, "Res"}; - AxisSpec centAxis = {100, 0, 100, "V0M (%)"}; - - if (QA) { - histos.add("hFTOCvsTPCNoCut", "Mult correlation FT0C vs. TPC without any cut", 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("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}); - // 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}); - } - - if (QAv0) { - // Lambda topological 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}}}); - } + 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"}; - // CKStar histograms - histos.add("hLamInvMass", - "Invariant mass of Lambda baryon", kTHnSparseF, - {{100, 0.0, 100.0}, {200, 0.0f, 20.0f}, {200, 1.0, 1.2}, {100, -1, 1}}, true); - - // 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); - } - } - - double massLambda = TDatabasePDG::Instance() - ->GetParticle(kLambda0) - ->Mass(); // FIXME: Get from the common header + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - template - bool eventSelected(TCollision collision, const float& centrality) + void init(o2::framework::InitContext&) { - 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; + 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 (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 && candidate.tpcNClsFound() > cfgTPCcluster)) { - return false; - } - - return true; - } - - template - bool selectionPID(const T& candidate) - { - - if (!candidate.hasTOF() && - std::abs(candidate.tpcNSigmaPi()) < nsigmaCutTPC) { - return true; - } else if (candidate.hasTOF() && - std::abs(candidate.tofNSigmaPi()) < nsigmaCutTOF) { - return true; - } - - return false; - } - - template - bool SelectionV0(Collision const& collision, V0 const& candidate, - float /*multiplicity*/) - { - if (fabs(candidate.dcav0topv()) > cMaxV0DCA) { - return false; - } - - 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(kLambda0) - ->Mass(); // FIXME: Get from the common header - // float lowmasscutks0 = 0.497 - cWidthKs0 * cSigmaMassKs0; - // float highmasscutks0 = 0.497 + cWidthKs0 * cSigmaMassKs0; - float lowmasscutlambda = 1.0; - float highmasscutlambda = 1.2; - // float decayLength = candidate.distovertotmom(collision.posX(), - // collision.posY(), collision.posZ()) * - // RecoDecay::sqrtSumOfSquares(candidate.px(), candidate.py(), - // candidate.pz()); - - 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.mLambda() < lowmasscutlambda || - candidate.mLambda() > highmasscutlambda) { - return false; - } - if (QAv0) { - histos.fill(HIST("hLT"), CtauK0s); - histos.fill(HIST("hDCAV0Daughters"), candidate.dcaV0daughters()); - histos.fill(HIST("hV0CosPA"), candidate.v0cosPA()); - } - return true; - } - - template - bool isSelectedV0Daughter(T const& track, float charge, - double nsigmaV0Daughter) - { - const auto eta = track.eta(); - const auto tpcNClsF = track.tpcNClsFound(); - const auto dcaXY = track.dcaXY(); - const auto sign = track.sign(); - - if (!track.hasTPC()) - return false; - if (track.tpcNClsCrossedRows() < 70) - return false; - if (track.tpcCrossedRowsOverFindableCls() < 0.8) - 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; - } - if (std::abs(nsigmaV0Daughter) > ConfDaughPIDCuts) { - return false; + 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; } @@ -360,119 +214,183 @@ struct lambdav2 { { double result = phi; while (result < 0) { - result = result + 2. * TMath::Pi() / 2; + result = result + 2. * TMath::Pi(); } - while (result > 2. * TMath::Pi() / 2) { - result = result - 2. * TMath::Pi() / 2; + while (result > 2. * TMath::Pi()) { + result = result - 2. * TMath::Pi(); } return result; } - // 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 acceptanceFilter = - (nabs(aod::track::eta) < cfgCutEta && nabs(aod::track::pt) > cfgCutPT); - - using EventCandidates = soa::Filtered>; - - using TrackCandidates = soa::Filtered>; - using V0TrackCandidate = aod::V0Datas; - - ROOT::Math::PxPyPzMVector Lambda; - - void processSE(EventCandidates::iterator const& collision, - TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s, - aod::BCs const&) + 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; } - - float centrality = 0.0f; - centrality = collision.centFT0C(); - auto multTPC = collision.multNTracksPV(); - - if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + auto centrality = collision.centFT0C(); + // histos.fill(HIST("hCentrality0"), centrality); + if (!collision.triggereventsp()) { return; } + // histos.fill(HIST("hCentrality1"), centrality); - if (additionalEvsel && !eventSelected(collision, centrality)) { + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { return; } - - if (QA) { - histos.fill(HIST("hFTOCvsTPCNoCut"), centrality, multTPC); - } - if (!collision.triggereventep()) { + // histos.fill(HIST("hCentrality2"), centrality); + // if (additionalEvSel2 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + if (additionalEvSel2 && (collision.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < cfgMinOccupancy)) { return; } - auto psiFT0C = collision.psiFT0C(); - auto psiFT0A = collision.psiFT0A(); - auto psiTPC = collision.psiTPC(); - auto psiTPCR = collision.psiTPCR(); - auto psiTPCL = collision.psiTPCL(); - if (QA) { - 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("hCentrality3"), centrality); + if (additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; } - // Fill the event counter - rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - rEventSelection.fill(HIST("hmult"), centrality); + 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; + } - for (auto& v0 : V0s) { + bool ispion = 0; + bool iskaon = 0; + bool isproton = 0; - auto postrack = v0.template posTrack_as(); - auto negtrack = v0.template negTrack_as(); - double nTPCSigmaPos[1]{postrack.tpcNSigmaPr()}; - double nTPCSigmaNeg[1]{negtrack.tpcNSigmaPi()}; - double nTPCSigmaPos2[1]{postrack.tpcNSigmaPi()}; - double nTPCSigmaNeg2[1]{negtrack.tpcNSigmaPr()}; + if (SelectionPID(track, 0)) + ispion = 1; + if (SelectionPID(track, 1)) + iskaon = 1; + if (SelectionPID(track, 2)) + isproton = 1; - if (!isSelectedV0Daughter(postrack, 1, nTPCSigmaPos[0]) && !isSelectedV0Daughter(postrack, 1, nTPCSigmaPos2[0])) { + if (ispion && iskaon) continue; - } - if (!isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg[0]) && !isSelectedV0Daughter(negtrack, -1, nTPCSigmaNeg2[0])) { + if (ispion && isproton) continue; - } - - if (!SelectionV0(collision, v0, centrality)) { + if (iskaon && isproton) continue; - } - - Lambda = ROOT::Math::PxPyPzMVector(v0.px(), v0.py(), v0.pz(), massLambda); - auto phiminuspsi = GetPhiInRange(Lambda.Phi() - psiFT0C); - auto v2 = TMath::Cos(2.0 * phiminuspsi); + float sign = track.sign(); + if (sign == 0.0) // removing neutral particles + continue; - if (TMath::Abs(Lambda.Rapidity()) < 0.5) { - histos.fill(HIST("hLamInvMass"), centrality, - Lambda.Pt(), v0.mLambda(), v2); + 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, processSE, "Process Same event", true); + PROCESS_SWITCH(lambdav2, processData, "Process data", true); }; - WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(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..f2dc7072ef0 --- /dev/null +++ b/PWGLF/Tasks/Resonances/lstarpbpbv2.cxx @@ -0,0 +1,532 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/EPCalibrationTables.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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#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; +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/omega2012Analysis.cxx b/PWGLF/Tasks/Resonances/omega2012Analysis.cxx new file mode 100644 index 00000000000..850eb0f1f71 --- /dev/null +++ b/PWGLF/Tasks/Resonances/omega2012Analysis.cxx @@ -0,0 +1,962 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file omega2012Analysis.cxx +/// \brief Invariant Mass Reconstruction of Omega(2012) Resonance +/// \author Bong-Hwi Lim + +#include "PWGLF/DataModel/LFResonanceTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct Omega2012Analysis { + // Constants + static constexpr float kSmallNumber = 1e-10f; // Small number to avoid division by zero + static constexpr float kMaxDCAV0ToPV = 1.0f; // Maximum DCA of V0 to PV + static constexpr int kNumExpectedDaughters = 2; // Expected number of daughters for 2-body decay + static constexpr int kPlaceholderPdgCode = 9999999; // o2-linter: disable=pdg/explicit-code (placeholder for generator-specific Omega(2012) PDG code) + SliceCache cache; + Preslice perResoCollisionCasc = aod::resodaughter::resoCollisionId; + Preslice perResoCollisionV0 = aod::resodaughter::resoCollisionId; + Preslice perResoCollisionTrack = aod::resodaughter::resoCollisionId; + Preslice perResoCollisionMicroTrack = aod::resodaughter::resoCollisionId; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Axes + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 10.0}, "pT"}; + ConfigurableAxis binsPtQA{"binsPtQA", {VARIABLE_WIDTH, 0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0}, "pT (QA)"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Centrality"}; + + // Invariant mass range for Omega(2012) → Xi + K0s + Configurable cInvMassStart{"cInvMassStart", 1.6, "Invariant mass start (GeV/c^2)"}; + Configurable cInvMassEnd{"cInvMassEnd", 2.2, "Invariant mass end (GeV/c^2)"}; + Configurable cInvMassBins{"cInvMassBins", 600, "Invariant mass bins"}; + + // Basic pre-selections (mirroring refs) + Configurable cMinPtcut{"cMinPtcut", 0.15, "Minimum pT for candidates"}; + Configurable cMaxEtaCut{"cMaxEtaCut", 0.8, "Maximum |eta|"}; + // V0 selections (K0s) from k892pmanalysis + Configurable cV0MinCosPA{"cV0MinCosPA", 0.97, "V0 minimum pointing angle cosine"}; + Configurable cV0MaxDaughDCA{"cV0MaxDaughDCA", 1.0, "V0 daughter DCA Maximum"}; + Configurable cV0MassWindow{"cV0MassWindow", 0.0043, "Mass window for competing Lambda0 rejection"}; + Configurable cMaxV0Etacut{"cMaxV0Etacut", 0.8, "V0 maximum eta cut"}; + + // Xi (cascade) selections from xi1530Analysisqa.cxx + Configurable cDCAxyToPVByPtCascP0{"cDCAxyToPVByPtCascP0", 999., "Cascade DCAxy p0"}; + Configurable cDCAxyToPVByPtCascExp{"cDCAxyToPVByPtCascExp", 1., "Cascade DCAxy exp"}; + Configurable cDCAxyToPVAsPtForCasc{"cDCAxyToPVAsPtForCasc", true, "Use pt-dep DCAxy cut (casc)"}; + + Configurable cDCAzToPVAsPtForCasc{"cDCAzToPVAsPtForCasc", true, "Use pt-dep DCAz cut (casc)"}; + + // V0 topology inside cascade (Λ) + Configurable cDCALambdaDaugtherscut{"cDCALambdaDaugtherscut", 0.7, "Λ daughters DCA cut"}; + Configurable cDCALambdaToPVcut{"cDCALambdaToPVcut", 0.02, "Λ DCA to PV min"}; + Configurable cDCAPionToPVcut{"cDCAPionToPVcut", 0.06, "π DCA to PV min"}; + Configurable cDCAProtonToPVcut{"cDCAProtonToPVcut", 0.07, "p DCA to PV min"}; + Configurable cV0CosPACutPtDepP0{"cV0CosPACutPtDepP0", 0.25, "V0 CosPA p0"}; + Configurable cV0CosPACutPtDepP1{"cV0CosPACutPtDepP1", 0.022, "V0 CosPA p1"}; + Configurable cMaxV0radiuscut{"cMaxV0radiuscut", 200., "V0 radius max"}; + Configurable cMinV0radiuscut{"cMinV0radiuscut", 2.5, "V0 radius min"}; + Configurable cMasswindowV0cut{"cMasswindowV0cut", 0.005, "Λ mass window for cascade V0"}; + + // Cascade topology + Configurable cDCABachlorToPVcut{"cDCABachlorToPVcut", 0.06, "Bachelor DCA to PV min"}; + Configurable cDCAXiDaugthersCutPtRangeLower{"cDCAXiDaugthersCutPtRangeLower", 1., "Xi pt low boundary"}; + Configurable cDCAXiDaugthersCutPtRangeUpper{"cDCAXiDaugthersCutPtRangeUpper", 4., "Xi pt high boundary"}; + Configurable cDCAXiDaugthersCutPtDepLower{"cDCAXiDaugthersCutPtDepLower", 0.8, "Xi daugh DCA (pt cDCAXiDaugthersCutPtDepMiddle{"cDCAXiDaugthersCutPtDepMiddle", 0.5, "Xi daugh DCA (low<=pt cDCAXiDaugthersCutPtDepUpper{"cDCAXiDaugthersCutPtDepUpper", 0.2, "Xi daugh DCA (pt>=high)"}; + Configurable cCosPACascCutPtDepP0{"cCosPACascCutPtDepP0", 0.2, "Cascade CosPA p0"}; + Configurable cCosPACascCutPtDepP1{"cCosPACascCutPtDepP1", 0.022, "Cascade CosPA p1"}; + Configurable cMaxCascradiuscut{"cMaxCascradiuscut", 200., "Cascade radius max"}; + Configurable cMinCascradiuscut{"cMinCascradiuscut", 1.1, "Cascade radius min"}; + Configurable cMasswindowCasccut{"cMasswindowCasccut", 0.008, "Xi mass window"}; + Configurable cMassXiminus{"cMassXiminus", 1.32171, "Xi mass (GeV/c^2)"}; // PDG + + // 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 - centrality"}; + + // Enhanced K0s selections + Configurable cK0sProperLifetimeMax{"cK0sProperLifetimeMax", 20.0, "K0s proper lifetime max (cm/c)"}; + Configurable cK0sArmenterosQtMin{"cK0sArmenterosQtMin", 0.0, "K0s Armenteros qt min"}; + Configurable cK0sArmenterosAlphaMax{"cK0sArmenterosAlphaMax", 0.8, "K0s Armenteros alpha max"}; + Configurable cK0sDauPosDCAtoPVMin{"cK0sDauPosDCAtoPVMin", 0.1, "K0s positive daughter DCA to PV min"}; + Configurable cK0sDauNegDCAtoPVMin{"cK0sDauNegDCAtoPVMin", 0.1, "K0s negative daughter DCA to PV min"}; + Configurable cK0sRadiusMin{"cK0sRadiusMin", 0.5, "K0s decay radius min"}; + Configurable cK0sRadiusMax{"cK0sRadiusMax", 100.0, "K0s decay radius max"}; + Configurable cK0sCrossMassRejection{"cK0sCrossMassRejection", true, "Enable Lambda mass rejection for K0s"}; + + // Pion track selections for 3-body decay + Configurable cPionPtMin{"cPionPtMin", 0.15, "Minimum pion pT"}; + Configurable cPionEtaMax{"cPionEtaMax", 0.8, "Maximum pion |eta|"}; + Configurable cPionDCAxyMax{"cPionDCAxyMax", 0.1, "Maximum pion DCAxy to PV"}; + Configurable cPionDCAzMax{"cPionDCAzMax", 0.2, "Maximum pion DCAz to PV"}; + Configurable cPionTPCNClusMin{"cPionTPCNClusMin", 70, "Minimum TPC clusters for pion"}; + + // Pion PID selections + Configurable cPionTPCNSigmaMax{"cPionTPCNSigmaMax", 3.0, "Maximum TPC NSigma for pion"}; + Configurable cPionTOFNSigmaMax{"cPionTOFNSigmaMax", 3.0, "Maximum TOF NSigma for pion"}; + Configurable cPionUsePtDepPID{"cPionUsePtDepPID", false, "Use pT-dependent PID cuts for pion"}; + Configurable> cPionPIDPtBins{"cPionPIDPtBins", {0.0f, 0.5f, 0.8f, 2.0f, 999.0f}, "pT bin edges for pion PID cuts"}; + Configurable> cPionTPCNSigmaCuts{"cPionTPCNSigmaCuts", {3.0f, 3.0f, 2.0f, 2.0f}, "TPC NSigma cuts per pT bin (pion)"}; + Configurable> cPionTOFNSigmaCuts{"cPionTOFNSigmaCuts", {3.0f, 3.0f, 3.0f, 3.0f}, "TOF NSigma cuts per pT bin (pion)"}; + Configurable> cPionTOFRequired{"cPionTOFRequired", {0, 0, 1, 1}, "Require TOF per pT bin (pion)"}; + + // Xi1530 mass window cut + Configurable cXi1530Mass{"cXi1530Mass", 1.53, "Xi(1530) mass (GeV/c^2)"}; + Configurable cXi1530MassWindow{"cXi1530MassWindow", 0.01, "Xi(1530) mass window (GeV/c^2)"}; + + // PDG masses + double massK0 = MassK0Short; + + using BinningTypeVertexContributor = ColumnBinningPolicy; + BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; + + void init(InitContext&) + { + AxisSpec centAxis = {binsCent, "V0M (%)"}; + 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 xiMassAxis = {400, 1.25, 1.65, "#Xi mass (GeV/#it{c}^{2})"}; + AxisSpec k0sMassAxis = {100, 0.4, 0.6, "K^{0}_{S} mass (GeV/#it{c}^{2})"}; + AxisSpec dcaAxis = {200, 0., 2.0, "DCA (cm)"}; + AxisSpec dcaxyAxis = {200, -1.0, 1.0, "DCA_{xy} (cm)"}; + AxisSpec dcazAxis = {200, -2.0, 2.0, "DCA_{z} (cm)"}; + AxisSpec cosPAAxis = {1000, 0.95, 1.0, "cos(PA)"}; + AxisSpec radiusAxis = {200, 0, 200, "Radius (cm)"}; + AxisSpec lifetimeAxis = {200, 0, 50, "Proper lifetime (cm/c)"}; + AxisSpec armQtAxis = {100, 0, 0.3, "q_{T} (GeV/c)"}; + AxisSpec armAlphaAxis = {100, -1.0, 1.0, "#alpha"}; + + // Event QA histograms + histos.add("Event/posZ", "Event vertex Z position", kTH1F, {{200, -20., 20., "V_{z} (cm)"}}); + histos.add("Event/centrality", "Event centrality distribution", kTH1F, {centAxis}); + histos.add("Event/posZvsCent", "Vertex Z vs Centrality", kTH2F, {{200, -20., 20., "V_{z} (cm)"}, centAxis}); + histos.add("Event/nCascades", "Number of cascades per event", kTH1F, {{100, 0., 100., "N_{cascades}"}}); + histos.add("Event/nV0s", "Number of V0s per event", kTH1F, {{200, 0., 200., "N_{V0s}"}}); + histos.add("Event/nCascadesAfterCuts", "Number of cascades per event after cuts", kTH1F, {{50, 0., 50., "N_{cascades}"}}); + histos.add("Event/nV0sAfterCuts", "Number of V0s per event after cuts", kTH1F, {{100, 0., 100., "N_{V0s}"}}); + + // Xi QA histograms + histos.add("QAbefore/xiMass", "Xi mass before cuts", kTH1F, {xiMassAxis}); + histos.add("QAbefore/xiPt", "Xi pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/xiEta", "Xi eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/xiDCAxy", "Xi DCAxy before cuts", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAbefore/xiDCAz", "Xi DCAz before cuts", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAbefore/xiV0CosPA", "Xi V0 CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAbefore/xiCascCosPA", "Xi Cascade CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAbefore/xiV0Radius", "Xi V0 radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAbefore/xiCascRadius", "Xi Cascade radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAbefore/xiV0DauDCA", "Xi V0 daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/xiCascDauDCA", "Xi Cascade daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + + histos.add("QAafter/xiMass", "Xi mass after cuts", kTH1F, {xiMassAxis}); + histos.add("QAafter/xiPt", "Xi pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/xiEta", "Xi eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/xiDCAxy", "Xi DCAxy after cuts", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAafter/xiDCAz", "Xi DCAz after cuts", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAafter/xiV0CosPA", "Xi V0 CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAafter/xiCascCosPA", "Xi Cascade CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAafter/xiV0Radius", "Xi V0 radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAafter/xiCascRadius", "Xi Cascade radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAafter/xiV0DauDCA", "Xi V0 daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/xiCascDauDCA", "Xi Cascade daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + + // K0s QA histograms + histos.add("QAbefore/k0sMassPt", "K0s mass vs pT before cuts", kTH2F, {ptAxisQA, k0sMassAxis}); + histos.add("QAbefore/k0sPt", "K0s pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/k0sEta", "K0s eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/k0sCosPA", "K0s CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAbefore/k0sRadius", "K0s radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAbefore/k0sDauDCA", "K0s daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/k0sDCAtoPV", "K0s DCA to PV before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/k0sProperLifetime", "K0s proper lifetime before cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + histos.add("QAbefore/k0sArmenteros", "K0s Armenteros plot before cuts", kTH2F, {armAlphaAxis, armQtAxis}); + histos.add("QAbefore/k0sDauPosDCA", "K0s positive daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/k0sDauNegDCA", "K0s negative daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + + histos.add("QAafter/k0sMassPt", "K0s mass vs pT after cuts", kTH2F, {ptAxisQA, k0sMassAxis}); + histos.add("QAafter/k0sPt", "K0s pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/k0sEta", "K0s eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/k0sCosPA", "K0s CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAafter/k0sRadius", "K0s radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAafter/k0sDauDCA", "K0s daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/k0sDCAtoPV", "K0s DCA to PV after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/k0sProperLifetime", "K0s proper lifetime after cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + histos.add("QAafter/k0sArmenteros", "K0s Armenteros plot after cuts", kTH2F, {armAlphaAxis, armQtAxis}); + histos.add("QAafter/k0sDauPosDCA", "K0s positive daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/k0sDauNegDCA", "K0s negative daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + + // Resonance (2-body decay: Xi + K0s) + histos.add("omega2012/invmass", "Invariant mass of Omega(2012) → Xi + K0s", kTH1F, {invMassAxis}); + histos.add("omega2012/invmass_Mix", "Mixed event Invariant mass of Omega(2012) → Xi + K0s", kTH1F, {invMassAxis}); + histos.add("omega2012/massPtCent", "Omega(2012) mass vs pT vs cent", kTH3F, {invMassAxis, ptAxis, centAxis}); + histos.add("omega2012/massPtCent_Mix", "Mixed event Omega(2012) mass vs pT vs cent", kTH3F, {invMassAxis, ptAxis, centAxis}); + + // 3-body decay: Xi + pi + K0s + histos.add("omega2012_3body/invmass", "Invariant mass of Omega(2012) → Xi + #pi + K^{0}_{S}", kTH1F, {invMassAxis}); + histos.add("omega2012_3body/massPtCent", "Omega(2012) 3-body mass vs pT vs cent", kTH3F, {invMassAxis, ptAxis, centAxis}); + + // Pion QA histograms for 3-body + AxisSpec nsigmaAxis = {100, -5.0, 5.0, "N#sigma"}; + histos.add("QAbefore/pionPt", "Pion pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/pionEta", "Pion eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/pionDCAxy", "Pion DCAxy before cuts", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAbefore/pionDCAz", "Pion DCAz before cuts", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAbefore/pionTPCNcls", "Pion TPC clusters before cuts", kTH1F, {{160, 0, 160, "N_{TPC clusters}"}}); + histos.add("QAbefore/pionTPCNSigma", "Pion TPC NSigma before cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("QAbefore/pionTOFNSigma", "Pion TOF NSigma before cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + + histos.add("QAafter/pionPt", "Pion pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/pionEta", "Pion eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/pionDCAxy", "Pion DCAxy after cuts", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAafter/pionDCAz", "Pion DCAz after cuts", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAafter/pionTPCNcls", "Pion TPC clusters after cuts", kTH1F, {{160, 0, 160, "N_{TPC clusters}"}}); + histos.add("QAafter/pionTPCNSigma", "Pion TPC NSigma after cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("QAafter/pionTOFNSigma", "Pion TOF NSigma after cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + + // MC truth histograms + AxisSpec etaAxis = {100, -2.0, 2.0, "#eta"}; + AxisSpec rapidityAxis = {100, -2.0, 2.0, "y"}; + + histos.add("MC/hMCGenOmega2012Pt", "MC Generated Omega(2012) pT", kTH1F, {ptAxis}); + histos.add("MC/hMCGenOmega2012PtEta", "MC Generated Omega(2012) pT vs eta", kTH2F, {ptAxis, etaAxis}); + histos.add("MC/hMCGenOmega2012Y", "MC Generated Omega(2012) rapidity", kTH1F, {rapidityAxis}); + histos.add("MC/hMCRecOmega2012Pt", "MC Reconstructed Omega(2012) pT", kTH1F, {ptAxis}); + histos.add("MC/hMCRecOmega2012PtEta", "MC Reconstructed Omega(2012) pT vs eta", kTH2F, {ptAxis, etaAxis}); + + // MC truth invariant mass (from MC particles) + histos.add("MC/hMCTruthInvMassXiK0s", "MC Truth Inv Mass Xi + K^{0}_{S}", kTH1F, {invMassAxis}); + histos.add("MC/hMCTruthMassPtXiK0s", "MC Truth Mass vs pT Xi + K^{0}_{S}", kTH2F, {invMassAxis, ptAxis}); + + // MC reconstruction efficiency + histos.add("MC/hMCRecXiPt", "MC Reconstructed Xi pT", kTH1F, {ptAxis}); + histos.add("MC/hMCRecK0sPt", "MC Reconstructed K0s pT", kTH1F, {ptAxis}); + histos.add("MC/hMCTrueXiPt", "MC True Xi pT", kTH1F, {ptAxis}); + histos.add("MC/hMCTrueK0sPt", "MC True K0s pT", kTH1F, {ptAxis}); + } + + // Enhanced V0 selection (K0s) with detailed criteria + template + bool v0CutEnhanced(const CollisionType& collision, const V0Type& v0) + { + // Basic kinematic cuts + if (std::abs(v0.eta()) > cMaxV0Etacut) + return false; + if (v0.pt() < cMinPtcut) + return false; + + // Topological cuts + if (v0.v0CosPA() < cV0MinCosPA) + return false; + if (v0.daughDCA() > cV0MaxDaughDCA) + return false; + + // Enhanced selections from chk892Flow + // Daughter DCA to PV cuts + if (std::abs(v0.dcapostopv()) < cK0sDauPosDCAtoPVMin) + return false; + if (std::abs(v0.dcanegtopv()) < cK0sDauNegDCAtoPVMin) + return false; + + // Radius cuts - use transRadius instead of v0radius + auto radius = v0.transRadius(); + if (radius < cK0sRadiusMin || radius > cK0sRadiusMax) + return false; + + // DCA to PV + if (std::abs(v0.dcav0topv()) > kMaxDCAV0ToPV) + return false; // max DCA to PV + + // Proper lifetime cut - calculate manually + float dx = v0.decayVtxX() - collision.posX(); + float dy = v0.decayVtxY() - collision.posY(); + float dz = v0.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); + auto properLifetime = (l / (p + kSmallNumber)) * MassK0Short; + if (properLifetime > cK0sProperLifetimeMax) + return false; + + // Armenteros cut - skip for now as we don't have daughter momentum info in ResoV0s table + // If needed, this would require accessing daughter tracks separately or using alternative cuts + + // Mass window + if (std::abs(v0.mK0Short() - MassK0Short) > cV0MassWindow) + return false; + + // Competing V0 rejection: remove (Anti)Λ + if (cK0sCrossMassRejection) { + if (std::abs(v0.mLambda() - MassLambda) < cV0MassWindow) + return false; + if (std::abs(v0.mAntiLambda() - MassLambda) < cV0MassWindow) + return false; + } + + return true; + } + + // Original V0 selection for backward compatibility + template + bool v0Cut(const V0Type& v0) + { + if (std::abs(v0.eta()) > cMaxV0Etacut) + return false; + if (v0.v0CosPA() < cV0MinCosPA) + return false; + if (v0.daughDCA() > cV0MaxDaughDCA) + return false; + // Competing V0 rejection: remove (Anti)Λ + if (std::abs(v0.mLambda() - MassLambda) < cV0MassWindow) + return false; + if (std::abs(v0.mAntiLambda() - MassLambda) < cV0MassWindow) + return false; + return true; + } + + // Helper function to find pT bin index + int getPtBinIndex(float pt) + { + auto ptBins = static_cast>(cPionPIDPtBins); + for (size_t i = 0; i < ptBins.size() - 1; i++) { + if (pt >= ptBins[i] && pt < ptBins[i + 1]) { + return i; + } + } + return -1; + } + + // Pion PID selection + template + bool pionPidCut(const TrackType& track) + { + float pt = track.pt(); + + if constexpr (IsResoMicrotrack) { + // For ResoMicroTracks - decode PID from flags + float tpcNSigma = o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(track.pidNSigmaPiFlag()); + float tofNSigma = track.hasTOF() ? o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(track.pidNSigmaPiFlag()) : 999.f; + + if (cPionUsePtDepPID) { + int ptBin = getPtBinIndex(pt); + if (ptBin < 0) + return false; + + auto tpcCuts = static_cast>(cPionTPCNSigmaCuts); + auto tofCuts = static_cast>(cPionTOFNSigmaCuts); + auto tofRequired = static_cast>(cPionTOFRequired); + + if (ptBin >= static_cast(tpcCuts.size()) || + ptBin >= static_cast(tofCuts.size()) || + ptBin >= static_cast(tofRequired.size())) { + return false; + } + + if (std::abs(tpcNSigma) >= tpcCuts[ptBin]) + return false; + + if (tofRequired[ptBin] != 0) { + if (!track.hasTOF()) + return false; + if (std::abs(tofNSigma) >= tofCuts[ptBin]) + return false; + } else { + if (track.hasTOF() && std::abs(tofNSigma) >= tofCuts[ptBin]) + return false; + } + + return true; + } else { + bool tpcPass = std::abs(tpcNSigma) < cPionTPCNSigmaMax; + bool tofPass = track.hasTOF() ? std::abs(tofNSigma) < cPionTOFNSigmaMax : true; + return tpcPass && tofPass; + } + } else { + // For ResoTracks - direct access + float tpcNSigma = track.tpcNSigmaPi(); + float tofNSigma = track.hasTOF() ? track.tofNSigmaPi() : 999.f; + + if (cPionUsePtDepPID) { + int ptBin = getPtBinIndex(pt); + if (ptBin < 0) + return false; + + auto tpcCuts = static_cast>(cPionTPCNSigmaCuts); + auto tofCuts = static_cast>(cPionTOFNSigmaCuts); + auto tofRequired = static_cast>(cPionTOFRequired); + + if (ptBin >= static_cast(tpcCuts.size()) || + ptBin >= static_cast(tofCuts.size()) || + ptBin >= static_cast(tofRequired.size())) { + return false; + } + + if (std::abs(tpcNSigma) >= tpcCuts[ptBin]) + return false; + + if (tofRequired[ptBin] != 0) { + if (!track.hasTOF()) + return false; + if (std::abs(tofNSigma) >= tofCuts[ptBin]) + return false; + } else { + if (track.hasTOF() && std::abs(tofNSigma) >= tofCuts[ptBin]) + return false; + } + + return true; + } else { + bool tpcPass = std::abs(tpcNSigma) < cPionTPCNSigmaMax; + bool tofPass = track.hasTOF() ? std::abs(tofNSigma) < cPionTOFNSigmaMax : true; + return tpcPass && tofPass; + } + } + } + + // Pion track selection (for both ResoTracks and ResoMicroTracks) + template + bool pionCut(const TrackType& track) + { + // Basic kinematic cuts + if (track.pt() < cPionPtMin) + return false; + if (std::abs(track.eta()) > cPionEtaMax) + return false; + + // DCA cuts - different access for ResoMicroTracks + if constexpr (IsResoMicrotrack) { + if (o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > cPionDCAxyMax) + return false; + if (o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags()) > cPionDCAzMax) + return false; + } else { + if (std::abs(track.dcaXY()) > cPionDCAxyMax) + return false; + if (std::abs(track.dcaZ()) > cPionDCAzMax) + return false; + } + + // Track quality cuts - only for ResoTracks + if constexpr (!IsResoMicrotrack) { + if constexpr (requires { track.tpcNClsFound(); }) { + if (track.tpcNClsFound() < cPionTPCNClusMin) + return false; + } + } + + // PID selection + if (!pionPidCut(track)) + return false; + + return true; + } + + // Xi1530 mass window cut + template + bool xi1530MassCut(const XiType& xi, const PionType& pion) + { + // Calculate Xi + pion invariant mass + ROOT::Math::PxPyPzEVector pXi, pPion, pXi1530; + pXi = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(xi.pt(), xi.eta(), xi.phi(), xi.mXi())); + pPion = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(pion.pt(), pion.eta(), pion.phi(), MassPionCharged)); + pXi1530 = pXi + pPion; + + // Check if mass is within Xi(1530) window + float massDiff = std::abs(pXi1530.M() - cXi1530Mass); + return massDiff < cXi1530MassWindow; + } + + // Primary-level cascade kinematics + template + bool cascprimaryTrackCut(const CascT& c) + { + if (std::abs(c.eta()) > cMaxEtaCut) + return false; + if (std::abs(c.pt()) < cMinPtcut) + return false; + if (cDCAxyToPVAsPtForCasc) { + if (std::abs(c.dcaXYCascToPV()) > (cDCAxyToPVByPtCascP0 + cDCAxyToPVByPtCascExp * c.pt())) + return false; + } + if (cDCAzToPVAsPtForCasc) { + if (std::abs(c.dcaZCascToPV()) > (cDCAxyToPVByPtCascP0 + cDCAxyToPVByPtCascExp * std::pow(c.pt(), -1.1f))) + return false; + } + return true; + } + + // Cascade topological selections adapted from xi1530Analysisqa + template + bool casctopCut(const CascT& c) + { + // V0 (Λ) topology inside cascade + if (std::abs(c.daughDCA()) > cDCALambdaDaugtherscut) + return false; + if (std::abs(c.dcav0topv()) < cDCALambdaToPVcut) + return false; + + if (c.sign() < 0) { // Xi- + if (std::abs(c.dcanegtopv()) < cDCAPionToPVcut) + return false; + if (std::abs(c.dcapostopv()) < cDCAProtonToPVcut) + return false; + } else { // Anti-Xi + if (std::abs(c.dcanegtopv()) < cDCAProtonToPVcut) + return false; + if (std::abs(c.dcapostopv()) < cDCAPionToPVcut) + return false; + } + + if (c.v0CosPA() < std::cos(cV0CosPACutPtDepP0 - cV0CosPACutPtDepP1 * c.pt())) + return false; + if (c.transRadius() > cMaxV0radiuscut || c.transRadius() < cMinV0radiuscut) + return false; + if (std::abs(c.mLambda() - MassLambda) > cMasswindowV0cut) + return false; + + // Cascade-level topology + if (std::abs(c.dcabachtopv()) < cDCABachlorToPVcut) + return false; + + if (c.pt() < cDCAXiDaugthersCutPtRangeLower) { + if (c.cascDaughDCA() > cDCAXiDaugthersCutPtDepLower) + return false; + } else if (c.pt() < cDCAXiDaugthersCutPtRangeUpper) { + if (c.cascDaughDCA() > cDCAXiDaugthersCutPtDepMiddle) + return false; + } else { + if (c.cascDaughDCA() > cDCAXiDaugthersCutPtDepUpper) + return false; + } + + if (c.cascCosPA() < std::cos(cCosPACascCutPtDepP0 - cCosPACascCutPtDepP1 * c.pt())) + return false; + if (c.cascTransRadius() > cMaxCascradiuscut || c.cascTransRadius() < cMinCascradiuscut) + return false; + if (std::abs(c.mXi() - cMassXiminus) > cMasswindowCasccut) + return false; + + return true; + } + + template + void fill(const CollisionT& collision, const CascadesT& cascades, const V0sT& v0s) + { + auto cent = collision.cent(); + + // Fill event QA histograms (only for same-event) + if constexpr (!IsMix) { + histos.fill(HIST("Event/posZ"), collision.posZ()); + histos.fill(HIST("Event/centrality"), cent); + histos.fill(HIST("Event/posZvsCent"), collision.posZ(), cent); + histos.fill(HIST("Event/nCascades"), cascades.size()); + histos.fill(HIST("Event/nV0s"), v0s.size()); + } + + // Count candidates after cuts + int nCascAfterCuts = 0; + int nV0sAfterCuts = 0; + + for (const auto& xi : cascades) { + // QA before Xi cuts - detailed histograms + histos.fill(HIST("QAbefore/xiMass"), xi.mXi()); + histos.fill(HIST("QAbefore/xiPt"), xi.pt()); + histos.fill(HIST("QAbefore/xiEta"), xi.eta()); + histos.fill(HIST("QAbefore/xiDCAxy"), xi.pt(), xi.dcaXYCascToPV()); + histos.fill(HIST("QAbefore/xiDCAz"), xi.pt(), xi.dcaZCascToPV()); + histos.fill(HIST("QAbefore/xiV0CosPA"), xi.pt(), xi.v0CosPA()); + histos.fill(HIST("QAbefore/xiCascCosPA"), xi.pt(), xi.cascCosPA()); + histos.fill(HIST("QAbefore/xiV0Radius"), xi.pt(), xi.transRadius()); + histos.fill(HIST("QAbefore/xiCascRadius"), xi.pt(), xi.cascTransRadius()); + histos.fill(HIST("QAbefore/xiV0DauDCA"), xi.pt(), xi.daughDCA()); + histos.fill(HIST("QAbefore/xiCascDauDCA"), xi.pt(), xi.cascDaughDCA()); + + if (!cascprimaryTrackCut(xi)) + continue; + if (!casctopCut(xi)) + continue; + + // Count cascades passing cuts + if constexpr (!IsMix) { + nCascAfterCuts++; + } + + // QA after Xi cuts - detailed histograms + histos.fill(HIST("QAafter/xiMass"), xi.mXi()); + histos.fill(HIST("QAafter/xiPt"), xi.pt()); + histos.fill(HIST("QAafter/xiEta"), xi.eta()); + histos.fill(HIST("QAafter/xiDCAxy"), xi.pt(), xi.dcaXYCascToPV()); + histos.fill(HIST("QAafter/xiDCAz"), xi.pt(), xi.dcaZCascToPV()); + histos.fill(HIST("QAafter/xiV0CosPA"), xi.pt(), xi.v0CosPA()); + histos.fill(HIST("QAafter/xiCascCosPA"), xi.pt(), xi.cascCosPA()); + histos.fill(HIST("QAafter/xiV0Radius"), xi.pt(), xi.transRadius()); + histos.fill(HIST("QAafter/xiCascRadius"), xi.pt(), xi.cascTransRadius()); + histos.fill(HIST("QAafter/xiV0DauDCA"), xi.pt(), xi.daughDCA()); + histos.fill(HIST("QAafter/xiCascDauDCA"), xi.pt(), xi.cascDaughDCA()); + + // Build Xi + K0s + for (const auto& v0 : v0s) { + // QA before K0s selection - detailed histograms + histos.fill(HIST("QAbefore/k0sMassPt"), v0.pt(), v0.mK0Short()); + histos.fill(HIST("QAbefore/k0sPt"), v0.pt()); + histos.fill(HIST("QAbefore/k0sEta"), v0.eta()); + histos.fill(HIST("QAbefore/k0sCosPA"), v0.pt(), v0.v0CosPA()); + histos.fill(HIST("QAbefore/k0sRadius"), v0.pt(), v0.transRadius()); + histos.fill(HIST("QAbefore/k0sDauDCA"), v0.pt(), v0.daughDCA()); + histos.fill(HIST("QAbefore/k0sDCAtoPV"), v0.pt(), std::abs(v0.dcav0topv())); + // Calculate proper lifetime manually + float dx = v0.decayVtxX() - collision.posX(); + float dy = v0.decayVtxY() - collision.posY(); + float dz = v0.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); + auto properLifetime = (l / (p + 1e-10)) * MassK0Short; + histos.fill(HIST("QAbefore/k0sProperLifetime"), v0.pt(), properLifetime); + // Skip Armenteros plot for now - requires daughter momentum info + // histos.fill(HIST("QAbefore/k0sArmenteros"), alpha, qt); + histos.fill(HIST("QAbefore/k0sDauPosDCA"), v0.pt(), std::abs(v0.dcapostopv())); + histos.fill(HIST("QAbefore/k0sDauNegDCA"), v0.pt(), std::abs(v0.dcanegtopv())); + + if (!v0CutEnhanced(collision, v0)) + continue; + + // Count V0s passing cuts + if constexpr (!IsMix) { + nV0sAfterCuts++; + } + + // QA after K0s selection - detailed histograms + histos.fill(HIST("QAafter/k0sMassPt"), v0.pt(), v0.mK0Short()); + histos.fill(HIST("QAafter/k0sPt"), v0.pt()); + histos.fill(HIST("QAafter/k0sEta"), v0.eta()); + histos.fill(HIST("QAafter/k0sCosPA"), v0.pt(), v0.v0CosPA()); + histos.fill(HIST("QAafter/k0sRadius"), v0.pt(), v0.transRadius()); + histos.fill(HIST("QAafter/k0sDauDCA"), v0.pt(), v0.daughDCA()); + histos.fill(HIST("QAafter/k0sDCAtoPV"), v0.pt(), std::abs(v0.dcav0topv())); + histos.fill(HIST("QAafter/k0sProperLifetime"), v0.pt(), properLifetime); + // Skip Armenteros plot for now - requires daughter momentum info + // histos.fill(HIST("QAafter/k0sArmenteros"), alpha, qt); + histos.fill(HIST("QAafter/k0sDauPosDCA"), v0.pt(), std::abs(v0.dcapostopv())); + histos.fill(HIST("QAafter/k0sDauNegDCA"), v0.pt(), std::abs(v0.dcanegtopv())); + + // 4-vectors + ROOT::Math::PxPyPzEVector pXi, pK0s, pRes; + pXi = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(xi.pt(), xi.eta(), xi.phi(), xi.mXi())); + pK0s = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), massK0)); + pRes = pXi + pK0s; + + if constexpr (!IsMix) { + histos.fill(HIST("omega2012/invmass"), pRes.M()); + histos.fill(HIST("omega2012/massPtCent"), pRes.M(), pRes.Pt(), cent); + } else { + histos.fill(HIST("omega2012/invmass_Mix"), pRes.M()); + histos.fill(HIST("omega2012/massPtCent_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + } + + // Fill event QA for after-cuts counters (only for same-event) + if constexpr (!IsMix) { + histos.fill(HIST("Event/nCascadesAfterCuts"), nCascAfterCuts); + histos.fill(HIST("Event/nV0sAfterCuts"), nV0sAfterCuts); + } + } + + void processDummy(aod::ResoCollision const& /*collision*/) + { + // Dummy function to satisfy the compiler + } + PROCESS_SWITCH(Omega2012Analysis, processDummy, "Process Dummy", true); + + void processData(const aod::ResoCollision& collision, + aod::ResoCascades const& resocasc, + aod::ResoV0s const& resov0s) + { + fill(collision, resocasc, resov0s); + } + PROCESS_SWITCH(Omega2012Analysis, processData, "Process Event for data", false); + + void processMixedEvent(const aod::ResoCollisions& collisions, + aod::ResoCascades const& resocasc, + aod::ResoV0s const& resov0s) + { + + auto cascV0sTuple = std::make_tuple(resocasc, resov0s); + Pair pairs{colBinning, nEvtMixing, -1, collisions, cascV0sTuple, &cache}; + + for (auto& [collision1, casc1, collision2, v0s2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured binding cannot be const in this context) + auto cent = collision1.cent(); + + for (const auto& xi : casc1) { + if (!cascprimaryTrackCut(xi)) + continue; + if (!casctopCut(xi)) + continue; + + for (const auto& v0 : v0s2) { + if (!v0CutEnhanced(collision2, v0)) + continue; + + // 4-vectors for mixed event + ROOT::Math::PxPyPzEVector pXi, pK0s, pRes; + pXi = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(xi.pt(), xi.eta(), xi.phi(), xi.mXi())); + pK0s = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), massK0)); + pRes = pXi + pK0s; + + histos.fill(HIST("omega2012/invmass_Mix"), pRes.M()); + histos.fill(HIST("omega2012/massPtCent_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + } + } + PROCESS_SWITCH(Omega2012Analysis, processMixedEvent, "Process Mixed Event", false); + + // MC processes - placeholder for future implementation + void processMC(const aod::ResoCollision& /*collision*/, + aod::ResoCascades const& /*resocasc*/, + aod::ResoV0s const& /*resov0s*/, + aod::McParticles const& /*mcParticles*/) + { + // TODO: Implement MC truth matching for Xi + K0s + // - Match reconstructed Xi to MC Xi + // - Match reconstructed K0s to MC K0s + // - Fill MC truth histograms + // - Fill reconstruction efficiency histograms + // - Check if the Xi and K0s come from same Omega(2012) mother + } + PROCESS_SWITCH(Omega2012Analysis, processMC, "Process MC with truth matching (placeholder)", false); + + void processMCGenerated(aod::McParticles const& mcParticles) + { + // Process MC generated particles (no reconstruction requirement) + // Omega(2012) PDG code: Need to check - likely custom or using generator-specific codes + // This resonance decays to Xi + K0s + + for (const auto& mcParticle : mcParticles) { + // Look for Omega(2012) - PDG code may vary by generator + int pdg = mcParticle.pdgCode(); + + // TODO: Determine correct PDG code for Omega(2012) + // Placeholder check - update with correct PDG code + if (std::abs(pdg) != kPlaceholderPdgCode) // o2-linter: disable=pdg/explicit-code (placeholder for generator-specific PDG code) + continue; + + // Fill generated level histograms + auto pt = mcParticle.pt(); + auto eta = mcParticle.eta(); + auto y = mcParticle.y(); + + histos.fill(HIST("MC/hMCGenOmega2012Pt"), pt); + histos.fill(HIST("MC/hMCGenOmega2012PtEta"), pt, eta); + histos.fill(HIST("MC/hMCGenOmega2012Y"), y); + + // Get daughters + auto daughters = mcParticle.daughters_as(); + if (daughters.size() != kNumExpectedDaughters) + continue; + + int daughter1PDG = 0, daughter2PDG = 0; + ROOT::Math::PxPyPzEVector p1, p2, pMother; + + int iDaughter = 0; + for (const auto& daughter : daughters) { + if (iDaughter == 0) { + daughter1PDG = daughter.pdgCode(); + p1 = ROOT::Math::PxPyPzEVector(daughter.px(), daughter.py(), daughter.pz(), daughter.e()); + } else { + daughter2PDG = daughter.pdgCode(); + p2 = ROOT::Math::PxPyPzEVector(daughter.px(), daughter.py(), daughter.pz(), daughter.e()); + } + iDaughter++; + } + + pMother = p1 + p2; + + // Check decay channels + auto motherPt = pMother.Pt(); + auto motherM = pMother.M(); + + // Xi- + K0s or Xi+ + K0s + if ((std::abs(daughter1PDG) == kXiMinus && daughter2PDG == kK0Short) || + (std::abs(daughter2PDG) == kXiMinus && daughter1PDG == kK0Short)) { + histos.fill(HIST("MC/hMCTruthInvMassXiK0s"), motherM); + histos.fill(HIST("MC/hMCTruthMassPtXiK0s"), motherM, motherPt); + } + } + } + PROCESS_SWITCH(Omega2012Analysis, processMCGenerated, "Process MC generated particles (placeholder)", false); + + // Fill function for 3-body decay analysis + template + void fillThreeBody(const CollisionT& collision, const CascadesT& cascades, const V0sT& v0s, const TracksT& tracks) + { + auto cent = collision.cent(); + + // Collect track IDs used in xi and v0 construction to exclude them from pion selection + std::set usedTrackIds; + + // Collect track IDs from xi cascades + for (const auto& xi : cascades) { + if (!cascprimaryTrackCut(xi)) + continue; + if (!casctopCut(xi)) + continue; + + // Add xi daughter track IDs from cascadeIndices array (ordered: positive, negative, bachelor) + auto cascIndices = xi.cascadeIndices(); + usedTrackIds.insert(cascIndices[0]); // positive track + usedTrackIds.insert(cascIndices[1]); // negative track + usedTrackIds.insert(cascIndices[2]); // bachelor track + } + + // Collect track IDs from v0s + for (const auto& v0 : v0s) { + if (!v0CutEnhanced(collision, v0)) + continue; + + // Add v0 daughter track IDs from indices array + auto v0Indices = v0.indices(); + usedTrackIds.insert(v0Indices[0]); // positive track + usedTrackIds.insert(v0Indices[1]); // negative track + } + + // First loop: xi + pion to check xi1530 mass window + for (const auto& xi : cascades) { + if (!cascprimaryTrackCut(xi)) + continue; + if (!casctopCut(xi)) + continue; + + for (const auto& pion : tracks) { + // Skip pion tracks that are already used in xi construction + if (usedTrackIds.find(pion.globalIndex()) != usedTrackIds.end()) { + continue; + } + + // Pion QA before cuts + histos.fill(HIST("QAbefore/pionPt"), pion.pt()); + histos.fill(HIST("QAbefore/pionEta"), pion.eta()); + + if constexpr (IsResoMicrotrack) { + histos.fill(HIST("QAbefore/pionDCAxy"), pion.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(pion.trackSelectionFlags())); + histos.fill(HIST("QAbefore/pionDCAz"), pion.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(pion.trackSelectionFlags())); + histos.fill(HIST("QAbefore/pionTPCNSigma"), pion.pt(), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(pion.pidNSigmaPiFlag())); + if (pion.hasTOF()) { + histos.fill(HIST("QAbefore/pionTOFNSigma"), pion.pt(), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(pion.pidNSigmaPiFlag())); + } + } else { + histos.fill(HIST("QAbefore/pionDCAxy"), pion.pt(), pion.dcaXY()); + histos.fill(HIST("QAbefore/pionDCAz"), pion.pt(), pion.dcaZ()); + histos.fill(HIST("QAbefore/pionTPCNSigma"), pion.pt(), pion.tpcNSigmaPi()); + if (pion.hasTOF()) { + histos.fill(HIST("QAbefore/pionTOFNSigma"), pion.pt(), pion.tofNSigmaPi()); + } + if constexpr (requires { pion.tpcNClsFound(); }) { + histos.fill(HIST("QAbefore/pionTPCNcls"), pion.tpcNClsFound()); + } + } + + if (!pionCut(pion)) + continue; + + // Pion QA after cuts + histos.fill(HIST("QAafter/pionPt"), pion.pt()); + histos.fill(HIST("QAafter/pionEta"), pion.eta()); + + if constexpr (IsResoMicrotrack) { + histos.fill(HIST("QAafter/pionDCAxy"), pion.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(pion.trackSelectionFlags())); + histos.fill(HIST("QAafter/pionDCAz"), pion.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(pion.trackSelectionFlags())); + histos.fill(HIST("QAafter/pionTPCNSigma"), pion.pt(), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(pion.pidNSigmaPiFlag())); + if (pion.hasTOF()) { + histos.fill(HIST("QAafter/pionTOFNSigma"), pion.pt(), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(pion.pidNSigmaPiFlag())); + } + } else { + histos.fill(HIST("QAafter/pionDCAxy"), pion.pt(), pion.dcaXY()); + histos.fill(HIST("QAafter/pionDCAz"), pion.pt(), pion.dcaZ()); + histos.fill(HIST("QAafter/pionTPCNSigma"), pion.pt(), pion.tpcNSigmaPi()); + if (pion.hasTOF()) { + histos.fill(HIST("QAafter/pionTOFNSigma"), pion.pt(), pion.tofNSigmaPi()); + } + if constexpr (requires { pion.tpcNClsFound(); }) { + histos.fill(HIST("QAafter/pionTPCNcls"), pion.tpcNClsFound()); + } + } + + // Check xi1530 mass window cut + if (!xi1530MassCut(xi, pion)) + continue; + + // Second loop: v0 for the selected xi-pion pair + for (const auto& v0 : v0s) { + if (!v0CutEnhanced(collision, v0)) + continue; + + // 4-vectors for 3-body decay: Xi + K0s + pion + ROOT::Math::PxPyPzEVector pXi, pK0s, pPion, pRes; + pXi = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(xi.pt(), xi.eta(), xi.phi(), xi.mXi())); + pK0s = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), massK0)); + pPion = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(pion.pt(), pion.eta(), pion.phi(), MassPionCharged)); + + pRes = pXi + pK0s + pPion; + + histos.fill(HIST("omega2012_3body/invmass"), pRes.M()); + histos.fill(HIST("omega2012_3body/massPtCent"), pRes.M(), pRes.Pt(), cent); + } + } + } + } + + // 3-body decay analysis: Xi + pi + K0s with ResoTracks + void processThreeBodyWithTracks(const aod::ResoCollision& collision, + aod::ResoCascades const& resocasc, + aod::ResoV0s const& resov0s, + aod::ResoTracks const& resotracks) + { + fillThreeBody(collision, resocasc, resov0s, resotracks); + } + PROCESS_SWITCH(Omega2012Analysis, processThreeBodyWithTracks, "Process 3-body decay with ResoTracks", false); + + // 3-body decay analysis: Xi + pi + K0s with ResoMicroTracks + void processThreeBodyWithMicroTracks(const aod::ResoCollision& collision, + aod::ResoCascades const& resocasc, + aod::ResoV0s const& resov0s, + aod::ResoMicroTracks const& resomicrotracks) + { + fillThreeBody(collision, resocasc, resov0s, resomicrotracks); + } + PROCESS_SWITCH(Omega2012Analysis, processThreeBodyWithMicroTracks, "Process 3-body decay with ResoMicroTracks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/phi1020SpherocityAnalysis.cxx b/PWGLF/Tasks/Resonances/phi1020SpherocityAnalysis.cxx new file mode 100644 index 00000000000..30964bfd762 --- /dev/null +++ b/PWGLF/Tasks/Resonances/phi1020SpherocityAnalysis.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. + +/// \file phi1020SpherocityAnalysis.cxx +/// \brief Invariant Mass Reconstruction of phi(1020) Resonance in K+K- channel and Spherocity dependence study in pp collision at 13.6 TeV. +/// \author Swadhin Behera , Balaram Singh + +#include "PWGLF/DataModel/LFResonanceTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct Phi1020SpherocityAnalysis { + + // Named constants to avoid magic numbers + static constexpr float kRapidityCut = 0.5F; + static constexpr float kRotateMin = 0.01F; + static constexpr float kRotateMax = 0.1F; + static constexpr float kMaxMcPosZ = 10.0F; + + SliceCache cache; + Preslice perRCol = aod::resodaughter::resoCollisionId; + Preslice perCollision = aod::track::collisionId; + + // Configurables. + Configurable nBinsPt{"nBinsPt", 200, "N bins in pT histogram"}; + Configurable nBinsInvM{"nBinsInvM", 200, "N bins in InvMass histogram"}; + Configurable nBinsSp{"nBinsSp", 120, "N bins in spherocity histogram"}; + Configurable doRotate{"doRotate", true, "rotated inv mass spectra"}; + + // Tracks + Configurable ptMin{"ptMin", 0.15, "Minimum Track pT"}; + Configurable etaCut{"etaCut", 0.8, "Pseudorapidity cut"}; + Configurable dcazMin{"dcazMin", 1., "Minimum DCAz"}; + Configurable dcaxyMin{"dcaxyMin", 0.1, "Minimum DCAxy"}; + Configurable primaryTrack{"primaryTrack", true, "Primary track selection"}; + Configurable globalWoDCATrack{"globalWoDCATrack", true, "Global track selection without DCA"}; + Configurable pvContributor{"pvContributor", true, "PV contributor track selection"}; + + // PID Selections (Kaons) + Configurable useOnlyTOFTrackK{"useOnlyTOFTrackK", false, "Use only TOF track for PID selection (Kaon)"}; + Configurable useTpcOnly{"useTpcOnly", false, "Use TPC Only selection"}; + Configurable rejNsigma{"rejNsigma", 1.0, "Reject tracks to improve purity of PID"}; + Configurable maxTPCnSigmaKaon{"maxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; + Configurable maxTOFnSigmaKaon{"maxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; + Configurable nsigmaCutCombinedKaon{"nsigmaCutCombinedKaon", 3.0, "Combined nSigma cut for Kaon"}; + Configurable> kaonTPCPIDp{"kaonTPCPIDp", {0.0, 0.25, 0.5, 1.0}, "pT dependent TPC cuts kaons"}; + Configurable> kaonTPCPIDcut{"kaonTPCPIDcut", {6., 3.5, 2.5}, "TPC nsigma cuts kaons"}; + + // Event Mixing. + Configurable mixSph{"mixSph", true, "Include Sph Bins to be mixed"}; + Configurable numMixEv{"numMixEv", 20, "Number of Events to be mixed"}; + ConfigurableAxis mixVtxBins{"mixVtxBins", {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 mixMultBins{"mixMultBins", {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 mixSphBins{"mixSphBins", {VARIABLE_WIDTH, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f}, "Mixing bins - spherocity"}; + + // Histogram Registry. + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + const AxisSpec axisSp(nBinsSp, 0., 1., "S_{0}"); + const AxisSpec axisCent(105, 0, 105, "FT0M (%)"); + const AxisSpec axisPpid(400, 0., 4., "p (GeV/c)"); + const AxisSpec axisPtPid(400, 0., 4., "p_{T} (GeV/c)"); + const AxisSpec axisPt(nBinsPt, 0., 10., "p_{T} (GeV/c)"); + const AxisSpec axisEta(40, -1, 1, "#eta"); + const AxisSpec axisDCAz(500, -0.5, 0.5, {"DCA_{z} (cm)"}); + const AxisSpec axisDCAxy(240, -0.12, 0.12, {"DCA_{xy} (cm)"}); + const AxisSpec axisTPCNCls(200, 0, 200, {"TPCNCls"}); + const AxisSpec axisTPCNsigma(120, -6, 6, {"n#sigma^{TPC}"}); + const AxisSpec axisTOFNsigma(120, -6, 6, {"n#sigma^{TOF}"}); + const AxisSpec axisdEdx(380, 10, 200, {"#frac{dE}{dx}"}); + const AxisSpec axisInvM(nBinsInvM, 0.98, 1.06, {"M_{inv} (GeV/#it{c}^{2})"}); + + // Event + histos.add("Event/h1d_ft0m_mult_percentile", "FT0M (%)", kTH1F, {axisCent}); + histos.add("Event/h1d_spherocity", "Event Spherocity", kTH1F, {axisSp}); + histos.add("Event/h2d_sph_vs_multpercentile", "Spherocity vs FT0M(%)", kTH2F, {axisCent, axisSp}); + + // QA Before + histos.add("QAbefore/Kaon/h2d_ka_nsigma_tpc_p", "n#sigma^{TPC} Kaons", kTH2F, {axisPpid, axisTPCNsigma}); + histos.add("QAbefore/Kaon/h2d_ka_nsigma_tof_p", "n#sigma^{TOF} Kaons", kTH2F, {axisPpid, axisTOFNsigma}); + 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/Kaon/h1d_ka_pt", "p_{T}-spectra Kaons", kTH1F, {axisPt}); + histos.add("QAafter/Kaon/h2d_ka_dca_z", "dca_{z} Kaons", kTH2F, {axisPtPid, axisDCAz}); + histos.add("QAafter/Kaon/h2d_ka_dca_xy", "dca_{xy} Kaons", kTH2F, {axisPtPid, axisDCAxy}); + histos.add("QAafter/Kaon/h2d_ka_dEdx_p", "TPC Signal Kaon", kTH2F, {axisPpid, axisdEdx}); + histos.add("QAafter/Kaon/h2d_ka_nsigma_tpc_pt", " Kaons", kTH2F, {axisPtPid, axisTPCNsigma}); + histos.add("QAafter/Kaon/h2d_ka_nsigma_tpc_p", " Kaons", kTH2F, {axisPpid, axisTPCNsigma}); + histos.add("QAafter/Kaon/h2d_ka_nsigma_tof_pt", " Kaons", kTH2F, {axisPtPid, axisTOFNsigma}); + histos.add("QAafter/Kaon/h2d_ka_nsigma_tof_p", " Kaons", kTH2F, {axisPpid, axisTOFNsigma}); + histos.add("QAafter/Kaon/h2d_ka_nsigma_tof_vs_tpc", "n#sigma(TOF) vs n#sigma(TPC) Kaons", kTH2F, {axisTPCNsigma, axisTOFNsigma}); + + // Analysis - phi(1020) -> K+ K- + histos.add("Analysis/h1d_phi_invm_US", "phi(1020) M_{inv} unlike-sign", kTH1D, {axisInvM}); + histos.add("Analysis/h1d_phi_invm_PP", "Like Signs M_{inv} K^{+}K^{+}", kTH1D, {axisInvM}); + histos.add("Analysis/h1d_phi_invm_MM", "Like Signs M_{inv} K^{-}K^{-}", kTH1D, {axisInvM}); + histos.add("Analysis/h1d_phi_invm_rot", "Rotated Spectra", kTH1D, {axisInvM}); + histos.add("Analysis/h1d_phi_invm_US_mix", "Mixed Events M_{inv}", kTH1D, {axisInvM}); + histos.add("Analysis/h1d_phi_invm_LS_mix", "Mixed Events M_{inv}", kTH1D, {axisInvM}); + histos.add("Analysis/h4d_phi_invm_US", "THn #phi(1020)", kTHnSparseD, {axisInvM, axisPt, axisSp, axisCent}); + histos.add("Analysis/h4d_phi_invm_PP", "THn Like Signs K^{+}K^{+}", kTHnSparseD, {axisInvM, axisPt, axisSp, axisCent}); + histos.add("Analysis/h4d_phi_invm_MM", "THn Like Signs K^{-}K^{-}", kTHnSparseD, {axisInvM, axisPt, axisSp, axisCent}); + histos.add("Analysis/h4d_phi_invm_rot", "THn Rotated", kTHnSparseD, {axisInvM, axisPt, axisSp, axisCent}); + histos.add("Analysis/h4d_phi_invm_US_mix", "THn Mixed Events", kTHnSparseD, {axisInvM, axisPt, axisSp, axisCent}); + histos.add("Analysis/h4d_phi_invm_LS_mix", "THn Mixed Events", kTHnSparseD, {axisInvM, axisPt, axisSp, axisCent}); + + // MC + if (doprocessMC) { + histos.add("Event/h1d_rec_sph", "Reconstructed S_{0}", kTH1F, {axisSp}); + histos.add("Analysis/h1d_gen_phi", "Generated phi(1020) p_{T}", kTH1D, {axisPt}); + histos.add("Analysis/h1d_rec_phi", "Reconstructed phi(1020) p_{T}", kTH1D, {axisPt}); + histos.add("Analysis/h1d_rec_invm_phi", "Recostructed phi(1020)", kTH1D, {axisInvM}); + // MC truth histograms for daughters + histos.add("MCTruth/h1d_gen_posZ", "Generated PosZ", kTH1F, {{240, -12., 12.}}); + histos.add("MCTruth/h1d_ch_gen_phi", "Generated #phi distribution", kTH1F, {{128, -0.05, 6.35}}); + histos.add("MCTruth/h1d_ka_gen_eta", "Generated #eta Kaons", kTH1F, {{40, -1, 1}}); + histos.add("QAChecks/h1d_ka_gen_pt", "Generated p_{T}-spectra Kaons", kTH1F, {{400, 0., 4.}}); + } + } + + template + bool selTracks(T const& track) + { + if (track.pt() < ptMin) + return false; + if (std::abs(track.eta()) > etaCut) + return false; + if (std::abs(track.dcaZ()) > dcazMin) + return false; + if (std::abs(track.dcaXY()) > dcaxyMin) + return false; + if (primaryTrack && !track.isPrimaryTrack()) + return false; + if (globalWoDCATrack && !track.isGlobalTrackWoDCA()) + return false; + if (pvContributor && !track.isPVContributor()) + return false; + return true; + } + + // PID selection tools (Kaon focused) + template + bool selectionPIDKaon(const T& candidate, float p) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + auto tpcPIDp = static_cast>(kaonTPCPIDp); + auto tpcPIDcut = static_cast>(kaonTPCPIDcut); + int nitr = static_cast(tpcPIDp.size()); + + 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 = nsigmaCutCombinedKaon * nsigmaCutCombinedKaon; + float combinedRejCut = rejNsigma * rejNsigma; + + if (!useTpcOnly && candidate.hasTOF()) { + if (tofNsigmaKa < maxTOFnSigmaKaon && tofNsigmaPi > rejNsigma && tofNsigmaPr > rejNsigma) { + tofPIDPassed = true; + } + // square cut + if ((nsigmaCutCombinedKaon < 0) && (tpcNsigmaKa < maxTPCnSigmaKaon)) { + tpcPIDPassed = true; + } + // circular + if ((nsigmaCutCombinedKaon > 0) && (tpcTofNsigmaKa < combinedCut && tpcTofNsigmaPi > combinedRejCut && tpcTofNsigmaPr > combinedRejCut)) { + tofPIDPassed = true; + tpcPIDPassed = true; + } + } else { + tofPIDPassed = true; + if (useTpcOnly) { + if (tpcNsigmaKa < maxTPCnSigmaKaon && tpcNsigmaPi > rejNsigma && tpcNsigmaPr > rejNsigma) { + tpcPIDPassed = true; + } + } else { + for (int i = 0; i < nitr - 1; ++i) { + if (p >= tpcPIDp[i] && p < tpcPIDp[i + 1] && (tpcNsigmaKa < tpcPIDcut[i] && tpcNsigmaPi > rejNsigma && tpcNsigmaPr > rejNsigma)) { + tpcPIDPassed = true; + } + } + } + } + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + template + void fillQAHistos(T const& track) + { + // get total momentum + float p = RecoDecay::p(track.px(), track.py(), track.pz()); + + // fill before QA + 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()); + } + + // fill after QA if it passes PID + if (selectionPIDKaon(track, p)) { + histos.fill(HIST("QAafter/Kaon/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 (track.hasTOF() && !useTpcOnly) { + 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 fillInvMassHistos(trackType const& trk1, trackType const& trk2, float const& sph, float const& mult) + { + // use std random for rotation + static thread_local std::mt19937 rng{std::random_device{}()}; + std::uniform_real_distribution distRotate(kRotateMin, kRotateMax); + float k1Ptot = 0., k2Ptot = 0.; + + for (auto const& pair : soa::combinations(soa::CombinationsFullIndexPolicy(trk1, trk2))) { + auto const& trkK1 = std::get<0>(pair); + auto const& trkK2 = std::get<1>(pair); + // Do not analyse same index tracks. + if (trkK1.index() == trkK2.index()) + continue; + + // pT, DCA, Global Tracks and PVcontrib selection. + if (!selTracks(trkK1) || !selTracks(trkK2)) + continue; + + k1Ptot = RecoDecay::p(trkK1.px(), trkK1.py(), trkK1.pz()); + k2Ptot = RecoDecay::p(trkK2.px(), trkK2.py(), trkK2.pz()); + + // Apply PID Selection + if (useOnlyTOFTrackK && !trkK1.hasTOF()) + continue; + if (useOnlyTOFTrackK && !trkK2.hasTOF()) + continue; + if (!selectionPIDKaon(trkK1, k1Ptot) || !selectionPIDKaon(trkK2, k2Ptot)) + continue; + + // Invariant mass reconstruction using RecoDecay utilities. + std::array mom1{trkK1.px(), trkK1.py(), trkK1.pz()}; + std::array mom2{trkK2.px(), trkK2.py(), trkK2.pz()}; + auto momTot = RecoDecay::pVec(mom1, mom2); + double mass = RecoDecay::m(std::array{mom1, mom2}, std::array{MassKaonCharged, MassKaonCharged}); + double rap = RecoDecay::y(momTot, mass); + double ptTot = RecoDecay::pt(momTot); + + // rapidity cut + if (std::abs(rap) > kRapidityCut) + continue; + + // Fill Invariant Mass Histograms. + if constexpr (!mix && !mc) { + if (trkK1.sign() * trkK2.sign() < 0) { + histos.fill(HIST("Analysis/h1d_phi_invm_US"), mass); + histos.fill(HIST("Analysis/h4d_phi_invm_US"), mass, ptTot, sph, mult); + if (doRotate) { + float theta = distRotate(rng); + // rotate first daughter's transverse momentum + float px1 = mom1[0]; + float py1 = mom1[1]; + float px1r = px1 * std::cos(theta) - py1 * std::sin(theta); + float py1r = px1 * std::sin(theta) + py1 * std::cos(theta); + std::array mom1r{px1r, py1r, mom1[2]}; + auto momTotR = RecoDecay::pVec(mom1r, mom2); + double massR = RecoDecay::m(std::array{mom1r, mom2}, std::array{MassKaonCharged, MassKaonCharged}); + double rapR = RecoDecay::y(momTotR, massR); + double ptR = RecoDecay::pt(momTotR); + if (std::abs(rapR) < kRapidityCut) { + histos.fill(HIST("Analysis/h1d_phi_invm_rot"), massR); + histos.fill(HIST("Analysis/h4d_phi_invm_rot"), massR, ptR, sph, mult); + } + } + } else { + if (trkK1.sign() == 1) { + histos.fill(HIST("Analysis/h1d_phi_invm_PP"), mass); + histos.fill(HIST("Analysis/h4d_phi_invm_PP"), mass, ptTot, sph, mult); + } else { + histos.fill(HIST("Analysis/h1d_phi_invm_MM"), mass); + histos.fill(HIST("Analysis/h4d_phi_invm_MM"), mass, ptTot, sph, mult); + } + } + } + + if constexpr (mix) { + if (trkK1.sign() * trkK2.sign() < 0) { + histos.fill(HIST("Analysis/h1d_phi_invm_US_mix"), mass); + histos.fill(HIST("Analysis/h4d_phi_invm_US_mix"), mass, ptTot, sph, mult); + } else { + histos.fill(HIST("Analysis/h1d_phi_invm_LS_mix"), mass); + histos.fill(HIST("Analysis/h4d_phi_invm_LS_mix"), mass, ptTot, sph, mult); + } + } + + if constexpr (mc) { + if (std::abs(trkK1.pdgCode()) != static_cast(PDG_t::kKPlus) || std::abs(trkK2.pdgCode()) != static_cast(PDG_t::kKPlus)) + continue; + + if (trkK1.motherId() != trkK2.motherId()) + continue; + + if (std::abs(trkK1.motherPDG()) != static_cast(Pdg::kPhi)) // phi pdg + continue; + + // MC histograms + histos.fill(HIST("Analysis/h1d_rec_phi"), ptTot); + histos.fill(HIST("Analysis/h1d_rec_invm_phi"), mass); + } + } + } + + using ResoCols = soa::Join; + using ResoTracks = aod::ResoTracks; + + void processData(ResoCols::iterator const& collision, ResoTracks const& tracks) + { + histos.fill(HIST("Event/h1d_ft0m_mult_percentile"), collision.cent()); + histos.fill(HIST("Event/h1d_spherocity"), collision.spherocity()); + histos.fill(HIST("Event/h2d_sph_vs_multpercentile"), collision.cent(), collision.spherocity()); + + // QA per track + for (auto const& track : tracks) { + if (!selTracks(track)) + continue; + fillQAHistos(track); + } + + // get invariant mass histograms + fillInvMassHistos(tracks, tracks, collision.spherocity(), collision.cent()); + } + + PROCESS_SWITCH(Phi1020SpherocityAnalysis, processData, "Process for Same Event Data", true); + + void processMC(ResoCols::iterator const& collision, + soa::Join const& tracks) + { + histos.fill(HIST("Event/h1d_rec_sph"), collision.spherocity()); + + // get MC reco pT-spectra and QA + for (auto const& track : tracks) { + if (!selTracks(track)) + continue; + fillQAHistos(track); + } + + // get invariant mass histograms + fillInvMassHistos(tracks, tracks, collision.spherocity(), collision.cent()); + } + PROCESS_SWITCH(Phi1020SpherocityAnalysis, processMC, "Process Event for MC", false); + + void processMCTrue(aod::ResoMCParents const& resoParents) + { + for (auto const& part : resoParents) { + if (std::abs(part.pdgCode()) != static_cast(Pdg::kPhi)) // phi pdg + continue; + if (std::abs(part.y()) > kRapidityCut) + continue; + + bool passKa1 = false; + bool passKa2 = false; + if (std::abs(part.daughterPDG1()) == static_cast(PDG_t::kKPlus) || std::abs(part.daughterPDG2()) == static_cast(PDG_t::kKPlus)) + passKa1 = true; + if (std::abs(part.daughterPDG1()) == static_cast(PDG_t::kKPlus) || std::abs(part.daughterPDG2()) == static_cast(PDG_t::kKPlus)) + passKa2 = true; + + if (!passKa1 || !passKa2) + continue; + + histos.fill(HIST("Analysis/h1d_gen_phi"), part.pt()); + } + } + PROCESS_SWITCH(Phi1020SpherocityAnalysis, processMCTrue, "Process Event for MC", false); + + void processMCTrueDaughters(aod::McCollisions::iterator const& McCollision, aod::McParticles const& McParts) + { + // IP range selection + if (std::abs(McCollision.posZ()) > kMaxMcPosZ) + return; + + histos.fill(HIST("MCTruth/h1d_gen_posZ"), McCollision.posZ()); + + for (auto const& part : McParts) { + // kinematic acceptance of particles + if (part.pt() < ptMin || std::abs(part.eta()) > etaCut || !part.isPhysicalPrimary()) + continue; + + histos.fill(HIST("MCTruth/h1d_ch_gen_phi"), part.phi()); + + if (std::abs(part.pdgCode()) == static_cast(PDG_t::kKPlus)) { + histos.fill(HIST("MCTruth/h1d_ka_gen_eta"), part.eta()); + histos.fill(HIST("QAChecks/h1d_ka_gen_pt"), part.pt()); + } + } + } + PROCESS_SWITCH(Phi1020SpherocityAnalysis, processMCTrueDaughters, "Process Event for MC truth of kaons", false); + + // Processing Event Mixing + using BinningType1 = ColumnBinningPolicy; + using BinningType2 = ColumnBinningPolicy; + void processMix(ResoCols const& collisions, ResoTracks const& tracks) + { + LOGF(debug, "Event Mixing Started"); + BinningType1 binningPositions1{{mixVtxBins, mixMultBins, mixSphBins}, true}; + BinningType2 binningPositions2{{mixVtxBins, mixMultBins}, true}; + auto tracksTuple = std::make_tuple(tracks); + if (mixSph) { + SameKindPair pairs{binningPositions1, numMixEv, -1, collisions, tracksTuple, &cache}; + for (auto const& item : pairs) { + auto const& c1 = std::get<0>(item); + auto const& t1 = std::get<1>(item); + auto const& t2 = std::get<3>(item); + fillInvMassHistos(t1, t2, c1.spherocity(), c1.cent()); + } + } else { + SameKindPair pairs{binningPositions2, numMixEv, -1, collisions, tracksTuple, &cache}; + for (auto const& item : pairs) { + auto const& c1 = std::get<0>(item); + auto const& t1 = std::get<1>(item); + auto const& t2 = std::get<3>(item); + fillInvMassHistos(t1, t2, c1.spherocity(), c1.cent()); + } + } + } + PROCESS_SWITCH(Phi1020SpherocityAnalysis, processMix, "Process for Mixed Events", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/phiOO.cxx b/PWGLF/Tasks/Resonances/phiOO.cxx new file mode 100644 index 00000000000..9c7e6005264 --- /dev/null +++ b/PWGLF/Tasks/Resonances/phiOO.cxx @@ -0,0 +1,675 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file phiInJets.cxx +/// \brief Reconstruction of Phi yield through track-track Minv correlations for resonance OO analysis +/// +/// +/// \author Adrian Fereydon Nassirpour +#include +#include +#include +#include +#include + +#include "TRandom.h" +#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 phiOO { + + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Event configurables + Configurable cfg_Event_Sel{"cfg_Event_Sel", "sel8", "choose event selection"}; + Configurable cfg_Event_VtxCut{"cfg_Event_VtxCut", 10.0, "V_z cut selection"}; + Configurable cfg_Event_Timeframe{"cfg_Event_Timeframe", true, "Timeframe border cut"}; + Configurable cfg_Event_Timerange{"cfg_Event_Timerange", true, "Timerange border cut"}; + Configurable cfg_Event_Centrality{"cfg_Event_Centrality", true, "Centrality cut"}; + Configurable cfg_Event_CentralityMax{"cfg_Event_CentralityMax", 100, "CentralityMax cut"}; + Configurable cfg_Event_Pileup{"cfg_Event_Pileup", true, "Pileup border cut"}; + Configurable cfg_Event_OccupancyCut{"cfg_Event_OccupancyCut", true, "Occupancy border cut"}; + Configurable cfg_Event_MaxOccupancy{"cfg_Event_MaxOccupancy", 1, "Max TPC Occupancy"}; + + // Track configurables + Configurable cfg_Track_Sel{"cfg_Track_Sel", "globalTracks", "set track selections"}; + Configurable cfg_Track_MinPt{"cfg_Track_MinPt", 0.15, "set track min pT"}; + Configurable cfg_Track_MaxEta{"cfg_Track_MaxEta", 0.9, "set track max Eta"}; + Configurable cfg_Track_MaxDCArToPVcut{"cfg_Track_MaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + Configurable cfg_Track_MaxDCAzToPVcut{"cfg_Track_MaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cfg_Track_PrimaryTrack{"cfg_Track_PrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfg_Track_ConnectedToPV{"cfg_Track_ConnectedToPV", true, "PV contributor track selection"}; // PV Contributor + Configurable cfg_Track_GlobalWoDCATrack{"cfg_Track_GlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfg_Track_nFindableTPCClusters{"cfg_Track_FindableTPCClusters", 50, "nFindable TPC Clusters"}; + Configurable cfg_Track_nTPCCrossedRows{"cfg_Track_TPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable cfg_Track_nRowsOverFindable{"cfg_Track_RowsOverFindable", 1.2, "nRowsOverFindable TPC CLusters"}; + Configurable cfg_Track_nTPCChi2{"cfg_Track_TPCChi2", 4.0, "nTPC Chi2 per Cluster"}; + Configurable cfg_Track_nITSChi2{"cfg_Track_ITSChi2", 36.0, "nITS Chi2 per Cluster"}; + Configurable cfg_Track_TPCPID{"cfg_Track_TPCPID", true, "Enables TPC PID"}; + Configurable cfg_Track_TOFPID{"cfg_Track_TOFPID", true, "Enables TOF PID"}; + Configurable cfg_Track_Hard_TOFPID{"cfg_Track_Hard_TOFPID", true, "Enables STRICT TOF Reqruirement"}; + Configurable cfg_Track_TPCPID_nSig{"cfg_Track_TPCPID_nSig", 4, "nTPC PID sigma"}; + Configurable cfg_Track_TOFPID_nSig{"cfg_Track_TOFPID_nSig", 4, "nTOF PID sigma"}; + Configurable cfg_Track_Explicit_PID{"cfg_Track_Explicit_PID", true, "Enables explicit pid cehck"}; + Configurable cDebugLevel{"cDebugLevel", 0, "Resolution of Debug"}; + + // Pair configurables + Configurable cfg_Pair_MinvBins{"cfg_Pair_MinvBins", 300, "Number of bins for Minv axis"}; + Configurable cfg_Pair_MinvMin{"cfg_Pair_MinvMin", 0.90, "Minimum Minv value"}; + Configurable cfg_Pair_MinvMax{"cfg_Pair_MinvMax", 1.50, "Maximum Minv value"}; + + Configurable cfg_Mix_NMixedEvents{"cfg_Mix_NMixedEvents", 5, "Number of mixed events per event"}; + + // MCGen configurables + Configurable cfg_Force_GenReco{"cfg_Force_GenReco", false, "Only consider events which are reconstructed (neglect event-loss)"}; + Configurable cfg_Force_BR{"cfg_Force_BR", false, "Only consider phi->K+K-"}; + Configurable cfg_Force_Kaon_Acceptence{"cfg_Force_Kaon_Acceptence", false, "Only consider phi's whose daughters decay inside acceptence (no signal loss)"}; + + // Histogram Configurables + Configurable cfg_Event_CutQA{"cfg_Event_CutsQA", true, "Enables Track QA plots"}; + Configurable cfg_Track_CutQA{"cfg_Track_CutsQA", true, "Enables Track QA plots"}; + + // Configurables for axis + ConfigurableAxis binsDCAz{"binsDCAz", {40, -0.2, 0.2}, ""}; + ConfigurableAxis binsDCAxy{"binsDCAxy", {40, -0.2, 0.2}, ""}; + ConfigurableAxis cfg_bins_Cent{"cfg_bins_Cent", {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 cfg_bins_MixVtx{"cfg_bins_MixVtx", {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 cfg_bins_MixMult{"cfg_bins_MixMult", {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"}; + + void init(o2::framework::InitContext&) + { + const AxisSpec MinvAxis = {cfg_Pair_MinvBins, cfg_Pair_MinvMin, cfg_Pair_MinvMax}; + const AxisSpec PtAxis = {200, 0, 20.0}; + const AxisSpec MultAxis = {100, 0, 100}; + const AxisSpec dRAxis = {100, 0, 100}; + const AxisSpec pidAxis = {100, -5, 5}; + const AxisSpec axisDCAz{binsDCAz, "DCA_{z}"}; + const AxisSpec axisDCAxy{binsDCAxy, "DCA_{XY}"}; + + // Event QA + if (cfg_Event_CutQA) { + histos.add("hPosZ_BC", "PosZ_BC", kTH1F, {{240, -12.0, 12.0}}); + histos.add("hcentFT0C_BC", "centFT0C_BC", kTH1F, {{110, 0.0, 110.0}}); + histos.add("hOccupancy_BC", "Occupancy_BC", kTH1F, {{100, 0.0, 20000}}); + // + histos.add("hcentFT0C_AC", "centFT0C_AC", kTH1F, {{110, 0.0, 110.0}}); + histos.add("hPosZ_AC", "PosZ_AC", kTH1F, {{240, -12.0, 12.0}}); + histos.add("hOccupancy_AC", "Occupancy_AC", kTH1F, {{100, 0.0, 20000}}); + } + // Track QA + if (cfg_Track_CutQA) { + histos.add("hDCArToPv_BC", "DCArToPv_BC", kTH1F, {axisDCAxy}); + histos.add("hDCAzToPv_BC", "DCAzToPv_BC", kTH1F, {axisDCAz}); + histos.add("hIsPrim_BC", "hIsPrim_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsGood_BC", "hIsGood_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsPrimCont_BC", "hIsPrimCont_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hFindableTPCClusters_BC", "hFindableTPCClusters_BC", kTH1F, {{200, 0, 200}}); + histos.add("hFindableTPCRows_BC", "hFindableTPCRows_BC", kTH1F, {{200, 0, 200}}); + histos.add("hClustersVsRows_BC", "hClustersVsRows_BC", kTH1F, {{200, 0, 2}}); + histos.add("hTPCChi2_BC", "hTPCChi2_BC", kTH1F, {{200, 0, 100}}); + histos.add("hITSChi2_BC", "hITSChi2_BC", kTH1F, {{200, 0, 100}}); + histos.add("hTPC_nSigma_BC", "hTPC_nSigma_BC", kTH1F, {pidAxis}); + histos.add("hTOF_nSigma_BC", "hTOF_nSigma_BC", kTH1F, {pidAxis}); + histos.add("hTPC_nSigma_v_pt_BC", "hTPC_nSigma_v_pt_BC", HistType::kTHnSparseD, {pidAxis, PtAxis}); + histos.add("hTOF_nSigma_v_pt_BC", "hTOF_nSigma_v_pt_BC", HistType::kTHnSparseD, {pidAxis, PtAxis}); + // + histos.add("hDCArToPv_AC", "DCArToPv_AC", kTH1F, {axisDCAxy}); + histos.add("hDCAzToPv_AC", "DCAzToPv_AC", kTH1F, {axisDCAz}); + histos.add("hIsPrim_AC", "hIsPrim_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsGood_AC", "hIsGood_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsPrimCont_AC", "hIsPrimCont_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hFindableTPCClusters_AC", "hFindableTPCClusters_AC", kTH1F, {{200, 0, 200}}); + histos.add("hFindableTPCRows_AC", "hFindableTPCRows_AC", kTH1F, {{200, 0, 200}}); + histos.add("hClustersVsRows_AC", "hClustersVsRows_AC", kTH1F, {{200, 0, 2}}); + histos.add("hTPCChi2_AC", "hTPCChi2_AC", kTH1F, {{200, 0, 100}}); + histos.add("hITSChi2_AC", "hITSChi2_AC", kTH1F, {{200, 0, 100}}); + histos.add("hTPC_nSigma_AC", "hTPC_nSigma_AC", kTH1F, {pidAxis}); + histos.add("hTOF_nSigma_AC", "hTOF_nSigma_AC", kTH1F, {pidAxis}); + histos.add("hTPC_nSigma_v_pt_AC", "hTPC_nSigma_v_pt_AC", HistType::kTHnSparseD, {pidAxis, PtAxis}); + histos.add("hTOF_nSigma_v_pt_AC", "hTOF_nSigma_v_pt_AC", HistType::kTHnSparseD, {pidAxis, PtAxis}); + } + // Data histos + histos.add("hUSS", "hUSS", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hLSS", "hLSS", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hUSS_Mix", "hUSS_Mix", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hLSS_Mix", "hLSS_Mix", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + + // MC histos + histos.add("hMC_USS", "hMC_USS", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_LSS", "hMC_LSS", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_USS_Mix", "hMC_USS_Mix", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_LSS_Mix", "hMC_LSS_Mix", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_USS_True", "hMC_USS_True", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_Phi_True", "hMC_Phi_True", HistType::kTHnSparseD, {cfg_bins_Cent, PtAxis}); + + // Event Histograms + histos.add("hnEvents", "Event selection decision", kTH1I, {{10, -0.5, 9.5}}); + histos.add("hnEvents_MC", "Event selection decision", kTH1I, {{10, -0.5, 9.5}}); + histos.add("hnEvents_MC_True", "Event selection decision", kTH1I, {{10, -0.5, 9.5}}); + + } // end of init + + Filter collisionFilter = nabs(aod::collision::posZ) <= cfg_Event_VtxCut; + Filter collisionFilter_MC = nabs(aod::mccollision::posZ) <= cfg_Event_VtxCut; + Filter centralityFilter = nabs(aod::cent::centFT0C) <= cfg_Event_CentralityMax; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfg_Track_MaxEta && nabs(aod::track::pt) >= cfg_Track_MinPt); + using EventCandidates = soa::Filtered>; + using EventCandidates_True = soa::Filtered; + + using TrackCandidates = soa::Filtered>; + using TrackCandidates_MC = soa::Filtered>; + + using BinningTypeVtxCent = ColumnBinningPolicy; + + Partition PosKaon_MC = + (aod::track::signed1Pt > static_cast(0)) && + (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); + Partition NegKaon_MC = + (aod::track::signed1Pt < static_cast(0)) && + (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); + Partition PosKaon = + (aod::track::signed1Pt > static_cast(0)) && + (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); + Partition NegKaon = + (aod::track::signed1Pt < static_cast(0)) && + (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); + + double massKa = o2::constants::physics::MassKPlus; + //***********************************// + // First, we declare some helper functions + template + void fillQA(const bool pass, const objType& obj, const int objecttype = 0) + { + + if (objecttype == 1) { + if constexpr (requires { obj.posZ(); }) { + if (!pass) { + histos.fill(HIST("hPosZ_BC"), obj.posZ()); + histos.fill(HIST("hcentFT0C_BC"), obj.centFT0C()); + } else { + histos.fill(HIST("hPosZ_AC"), obj.posZ()); + histos.fill(HIST("hcentFT0C_AC"), obj.centFT0C()); + } + } + } + if constexpr (requires { obj.tpcCrossedRowsOverFindableCls(); }) { + if (objecttype == 2) { + if (!pass) { + histos.fill(HIST("hDCArToPv_BC"), obj.dcaXY()); + histos.fill(HIST("hDCAzToPv_BC"), obj.dcaZ()); + histos.fill(HIST("hIsPrim_BC"), obj.isPrimaryTrack()); + histos.fill(HIST("hIsGood_BC"), obj.isGlobalTrackWoDCA()); + histos.fill(HIST("hIsPrimCont_BC"), obj.isPVContributor()); + histos.fill(HIST("hFindableTPCClusters_BC"), obj.tpcNClsFindable()); + histos.fill(HIST("hFindableTPCRows_BC"), obj.tpcNClsCrossedRows()); + histos.fill(HIST("hClustersVsRows_BC"), obj.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("hTPCChi2_BC"), obj.tpcChi2NCl()); + } else { + histos.fill(HIST("hDCArToPv_AC"), obj.dcaXY()); + histos.fill(HIST("hDCAzToPv_AC"), obj.dcaZ()); + histos.fill(HIST("hIsPrim_AC"), obj.isPrimaryTrack()); + histos.fill(HIST("hIsGood_AC"), obj.isGlobalTrackWoDCA()); + histos.fill(HIST("hIsPrimCont_AC"), obj.isPVContributor()); + histos.fill(HIST("hFindableTPCClusters_AC"), obj.tpcNClsFindable()); + histos.fill(HIST("hFindableTPCRows_AC"), obj.tpcNClsCrossedRows()); + histos.fill(HIST("hClustersVsRows_AC"), obj.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("hTPCChi2_AC"), obj.tpcChi2NCl()); + } + } + if (objecttype == 3) { + if (!pass) { + histos.fill(HIST("hTPC_nSigma_BC"), obj.tpcNSigmaKa()); + histos.fill(HIST("hTOF_nSigma_BC"), obj.tofNSigmaKa()); + histos.fill(HIST("hTPC_nSigma_v_pt_BC"), obj.tpcNSigmaKa(), obj.pt()); + histos.fill(HIST("hTOF_nSigma_v_pt_BC"), obj.tofNSigmaKa(), obj.pt()); + } else { + histos.fill(HIST("hTPC_nSigma_AC"), obj.tpcNSigmaKa()); + histos.fill(HIST("hTOF_nSigma_AC"), obj.tofNSigmaKa()); + histos.fill(HIST("hTPC_nSigma_v_pt_AC"), obj.tpcNSigmaKa(), obj.pt()); + histos.fill(HIST("hTOF_nSigma_v_pt_AC"), obj.tofNSigmaKa(), obj.pt()); + } + } + } + }; + //***********************************// + + // evsel + template + std::pair eventSelection(const EventType event, const bool QA) + { + + if (cfg_Track_CutQA && QA) + fillQA(false, event, 1); + + if (!event.sel8()) + return {false, 1}; + if (std::abs(event.posZ()) > cfg_Event_VtxCut) + return {false, 2}; + if (cfg_Event_Timeframe && (!event.selection_bit(aod::evsel::kNoTimeFrameBorder) || !event.selection_bit(aod::evsel::kNoITSROFrameBorder))) + return {false, 3}; + if (cfg_Event_Timerange && (!event.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) + return {false, 4}; + if (cfg_Event_Pileup && (!event.selection_bit(aod::evsel::kNoSameBunchPileup) || !event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) + return {false, 5}; + if (cfg_Event_Centrality && (event.centFT0C() > cfg_Event_CentralityMax)) + return {false, 6}; + if (cfg_Event_OccupancyCut && (event.trackOccupancyInTimeRange() > cfg_Event_MaxOccupancy)) + return {false, 7}; + + if (cfg_Track_CutQA && QA) + fillQA(true, event, 1); + + return {true, 8}; + }; + + // tracksel + template + bool trackSelection(const TrackType track, const bool QA) + { + if (cfg_Track_CutQA && QA) + fillQA(false, track, 2); + + // basic track cuts + if (track.pt() < cfg_Track_MinPt) + return false; + if (std::abs(track.eta()) > cfg_Track_MaxEta) + return false; + if (std::abs(track.dcaXY()) > cfg_Track_MaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cfg_Track_MaxDCAzToPVcut) + return false; + if (cfg_Track_PrimaryTrack && !track.isPrimaryTrack()) + return false; + if (track.tpcNClsFindable() < cfg_Track_nFindableTPCClusters) + return false; + if (track.tpcNClsCrossedRows() < cfg_Track_nTPCCrossedRows) + return false; + if (track.tpcCrossedRowsOverFindableCls() > cfg_Track_nRowsOverFindable) + return false; + if (track.tpcChi2NCl() > cfg_Track_nTPCChi2) + return false; + if (track.itsChi2NCl() > cfg_Track_nITSChi2) + return false; + if (cfg_Track_ConnectedToPV && !track.isPVContributor()) + return false; + + if (cfg_Track_CutQA && QA) + fillQA(true, track, 2); + return true; + }; + + // trackpid + + template + bool trackPIDKaon(const TrackPID& candidate, const bool QA) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + + if (cfg_Track_CutQA && QA) + fillQA(false, candidate, 3); + + if (!cfg_Track_TPCPID) { + tpcPIDPassed = true; + } else { + if (std::abs(candidate.tpcNSigmaKa()) < cfg_Track_TPCPID_nSig) + tpcPIDPassed = true; + } + + if (!cfg_Track_TOFPID) { + tofPIDPassed = true; + } else { + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < cfg_Track_TOFPID_nSig) { + tofPIDPassed = true; + } + } else if (!cfg_Track_Hard_TOFPID) { + tofPIDPassed = true; + } + if (!candidate.hasTOF()) { + std::cout << candidate.tofNSigmaKa() << std::endl; + } + } + if (tpcPIDPassed && tofPIDPassed) { + if (cfg_Track_CutQA && QA) { + fillQA(true, candidate, 3); + } + return true; + } + return false; + } + + template + void TrackSlicing(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool QA, const bool IsMix) + { + auto slicedtracks1 = PosKaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto slicedtracks2 = NegKaon->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + auto centrality = collision1.centFT0C(); + for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(slicedtracks1, slicedtracks2))) { + auto [Minv, PhiPt] = minvReconstruction(track1, track2, QA); + if (Minv < 0) + continue; + double conjugate = track1.sign() * track2.sign(); + if (!IsMix) { + if (conjugate < 0) { + histos.fill(HIST("hUSS"), centrality, Minv, PhiPt); + } else if (conjugate > 0) { + histos.fill(HIST("hLSS"), centrality, Minv, PhiPt); + } + } else { + if (conjugate < 0) { + histos.fill(HIST("hUSS_Mix"), centrality, Minv, PhiPt); + } else if (conjugate > 0) { + histos.fill(HIST("hLSS_Mix"), centrality, Minv, PhiPt); + } + } + } + } // TrackSlicing + + template + void TrackSlicing_MC(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool QA, const bool IsMix) + { + auto slicedtracks1 = PosKaon_MC->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto slicedtracks2 = NegKaon_MC->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + auto centrality = collision1.centFT0C(); + for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(slicedtracks1, slicedtracks2))) { + auto [Minv, PhiPt] = minvReconstruction(track1, track2, QA); + if (Minv < 0) + continue; + double conjugate = track1.sign() * track2.sign(); + if (!IsMix) { + if (conjugate < 0) { + histos.fill(HIST("hMC_USS"), centrality, Minv, PhiPt); + } else if (conjugate > 0) { + histos.fill(HIST("hMC_LSS"), centrality, Minv, PhiPt); + } + } else { + if (conjugate < 0) { + histos.fill(HIST("hMC_USS_Mix"), centrality, Minv, PhiPt); + } else if (conjugate > 0) { + histos.fill(HIST("hMC_LSS_Mix"), centrality, Minv, PhiPt); + } + } + // now we do mc true + if (!track1.has_mcParticle() || !track2.has_mcParticle()) + continue; + auto part1 = track1.mcParticle(); + auto part2 = track2.mcParticle(); + if (std::fabs(part1.pdgCode()) != 321) + continue; // Not Kaon + if (std::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.template 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.template mothers_as()) { + mothers2.push_back(part2_mom.globalIndex()); + mothers2PDG.push_back(part2_mom.pdgCode()); + } + + 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 + + histos.fill(HIST("hMC_USS_True"), centrality, Minv, PhiPt); + } + } // TrackSlicing + + // Invariant mass + template + std::pair minvReconstruction(const TracksType& trk1, const TracksType& trk2, const bool QA) + { + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + //==================================================== + + if (!trackSelection(trk1, QA) || !trackSelection(trk2, false)) + return {-1.0, -1.0}; + + if (cfg_Track_Explicit_PID) { + if (!trackPIDKaon(trk1, QA) || !trackPIDKaon(trk2, false)) + return {-1.0, -1.0}; + } + + if (trk1.globalIndex() >= trk2.globalIndex()) + return {-1.0, -1.0}; + + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + lResonance = lDecayDaughter1 + lDecayDaughter2; + + return {lResonance.M(), lResonance.Pt()}; + } // MinvReconstruction + + //***************// + // DATA + //***************// + + int nEvents = 0; + void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + if (cDebugLevel > 0) { + ++nEvents; + if (nEvents % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + } + + auto [goodEv, code] = eventSelection(collision, true); + histos.fill(HIST("hnEvents"), code); + if (!goodEv) + return; + TrackSlicing(collision, tracks, collision, tracks, true, false); + + } // end of process + + PROCESS_SWITCH(phiOO, processSameEvent, "Process Same events", true); + + //***************// + // DATA (MIX) + //***************// + + int nEvents_Mix = 0; + void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVtxCent colBinning{{cfg_bins_MixVtx, cfg_bins_MixMult}, true}; + SameKindPair pairs{colBinning, cfg_Mix_NMixedEvents, -1, collisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (cDebugLevel > 0) { + ++nEvents_Mix; + if (nEvents_Mix % 10000 == 0) { + std::cout << "Processed Mixed Events: " << nEvents_Mix << std::endl; + } + } + auto [goodEv1, code1] = eventSelection(collision1, false); + auto [goodEv2, code2] = eventSelection(collision2, false); + if (!goodEv1 || !goodEv2) + continue; + TrackSlicing(collision1, tracks1, collision2, tracks2, false, true); + } // mixing + } // end of process + PROCESS_SWITCH(phiOO, processMixedEvent, "Process Mixed events", false); + + //***************// + // RECONSTRUCTED MC + //***************// + + int nEvents_MC = 0; + void processSameEvent_MC(EventCandidates::iterator const& collision, TrackCandidates_MC const& tracks, aod::McParticles const&) + { + if (cDebugLevel > 0) { + ++nEvents_MC; + if (nEvents_MC % 10000 == 0) { + std::cout << "Processed MC (REC) Events: " << nEvents_MC << std::endl; + } + } + + auto [goodEv, code] = eventSelection(collision, true); + histos.fill(HIST("hnEvents_MC"), code); + if (!goodEv) + return; + TrackSlicing_MC(collision, tracks, collision, tracks, true, false); + + } // end of process + PROCESS_SWITCH(phiOO, processSameEvent_MC, "Process Same events (MC)", true); + + //***************// + // RECONSTRUCTED MC (MIX) + //***************// + + int nEvents_MC_Mix = 0; + void processMixedEvent_MC(EventCandidates const& collisions, TrackCandidates_MC const& tracks, aod::McParticles const&) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVtxCent colBinning{{cfg_bins_MixVtx, cfg_bins_MixMult}, true}; + SameKindPair pairs{colBinning, cfg_Mix_NMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (cDebugLevel > 0) { + ++nEvents_MC_Mix; + if (nEvents_MC_Mix % 10000 == 0) { + std::cout << "Processed Mixed Events: " << nEvents_MC_Mix << std::endl; + } + } + auto [goodEv1, code1] = eventSelection(collision1, false); + auto [goodEv2, code2] = eventSelection(collision2, false); + if (!goodEv1 || !goodEv2) + continue; + TrackSlicing_MC(collision1, tracks1, collision2, tracks2, false, true); + } // mixing + } // end of process + PROCESS_SWITCH(phiOO, processMixedEvent_MC, "Process Mixed events (MC)", false); + + //***************// + // GENERATED MC + //***************// + + int nEvents_True = 0; + void processParticles(EventCandidates_True::iterator const& collision, soa::SmallGroups> const& recocolls, aod::McParticles const& particles) + { + if (cDebugLevel > 0) { + ++nEvents_True; + if (nEvents_True % 10000 == 0) { + std::cout << "Processed MC (GEN) Events: " << nEvents_True << std::endl; + } + } + + if (fabs(collision.posZ()) > cfg_Event_VtxCut) + return; + + if (recocolls.size() <= 0) { // not reconstructed + if (cfg_Force_GenReco) { + return; + } + } + + double centrality = -1; + for (auto& recocoll : recocolls) { // poorly reconstructed + centrality = recocoll.centFT0C(); + auto [goodEv, code] = eventSelection(recocoll, false); + histos.fill(HIST("hnEvents_MC_True"), code); + if (!goodEv) + return; + } + + for (auto& particle : particles) { + if (particle.pdgCode() != 333) + continue; + if (std::fabs(particle.eta()) > cfg_Track_MaxEta) + continue; + + if (cfg_Force_BR) { + bool baddecay = false; + for (auto& phidaughter : particle.daughters_as()) { + if (std::fabs(phidaughter.pdgCode()) != 321) { + baddecay = true; + break; + } + if (cfg_Force_Kaon_Acceptence) { + if (std::fabs(phidaughter.eta()) > cfg_Track_MaxEta) { + baddecay = true; + break; + } + } + } // loop over daughters + + if (baddecay) + continue; + } // enforce BR restriction + + histos.fill(HIST("hMC_Phi_True"), centrality, particle.pt()); + } // loop over particles + + } // end of process + PROCESS_SWITCH(phiOO, processParticles, "Process Particles", false); + +}; // end of main struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phianalysis.cxx b/PWGLF/Tasks/Resonances/phianalysis.cxx index 57d4d24fad6..bd2c838b469 100644 --- a/PWGLF/Tasks/Resonances/phianalysis.cxx +++ b/PWGLF/Tasks/Resonances/phianalysis.cxx @@ -15,17 +15,18 @@ /// /// \author Bong-Hwi Lim -#include +#include "PWGLF/DataModel/LFResonanceTables.h" -#include "Common/DataModel/PIDResponse.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisTask.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFResonanceTables.h" -#include "DataFormatsParameters/GRPObject.h" -#include "CommonConstants/PhysicsConstants.h" + +#include using namespace o2; using namespace o2::framework; @@ -66,8 +67,6 @@ struct phianalysis { 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"}; - /// ITS nCluster cut - Configurable cMinITSNcls{"cMinITSNcls", 0, "Minimum ITS nCluster"}; // Kaon Configurable cMaxTPCnSigmaKaon{"cMaxTPCnSigmaKaon", 3.0, "TPC nSigma cut for Kaon"}; // TPC Configurable cMaxTOFnSigmaKaon{"cMaxTOFnSigmaKaon", 3.0, "TOF nSigma cut for Kaon"}; // TOF @@ -142,8 +141,6 @@ struct phianalysis { return false; if (track.tpcNClsFound() < cMinTPCNclsFound) return false; - if (track.itsNCls() < cMinITSNcls) - return false; if (cfgPrimaryTrack && !track.isPrimaryTrack()) return false; if (cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) diff --git a/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx b/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx index 24f86f940e4..49a754b6a4b 100644 --- a/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx +++ b/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx @@ -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. // @@ -9,92 +9,109 @@ // 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 "PWGLF/Utils/rsnOutput.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/PID.h" -#include "PWGLF/Utils/rsnOutput.h" -#include "TDatabasePDG.h" + +#include + +#include +#include 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 produceStats{"produceStats", false, "Produce statistics 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."}; + Configurable produceRotational{"produceRotational", false, "Produce Rotational histograms."}; } 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."}; - } 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 daughterPos{"daughterPos", 3, "Particle type of the positive dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; + Configurable daughterNeg{"daughterNeg", 3, "Particle type of the negative dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; + Configurable motherPDG{"motherPDG", 333, "PDG code of mother particle."}; + Configurable daughterPosPDG{"daughterPosPDG", 321, "PDG code of positive dauther particle."}; + Configurable daughterNegPDG{"daughterNegPDG", 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 etatrack{"eta-track-cut", 0.8, "Eta cut for track."}; - Configurable etapair{"eta-pair-cut", 0.8, "Eta cut for pair."}; - 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 tpcNClsFound{"tpc-ncl-found-cut", 70, "Cut: Minimal value of found TPC clasters"}; + 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 tpcPidOnly{"tpcPidOnly", false, "Use TPC only for PID."}; + Configurable combinedNSigma{"combinedNSigma", 3.0f, "Combined NSigma cut for combined TPC and TOF NSigma cut."}; + Configurable ptTOFThreshold{"ptTOFThreshold", 0.5f, "Threshold for applying TOF."}; + Configurable rapidity{"rapidity", 0.5f, "Rapidity cut (maximum)."}; + Configurable etatrack{"etatrack", 0.8f, "Eta cut for track."}; + 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 globalTrack{"globalTrack", false, "Use global track selection."}; + Configurable inelGrater0{"inelGrater0", true, "Select events with INEL>0."}; + Configurable tpcNClsFound{"tpcNClsFound", 70, "Cut: Minimal value of found TPC clasters"}; } cut; - Configurable> sparseAxes{"sparse-axes", std::vector{o2::analysis::rsn::PairAxis::names}, "Axes."}; - Configurable> sysAxes{"systematics-axes", std::vector{o2::analysis::rsn::SystematicsAxis::names}, "Axes."}; + struct : ConfigurableGroup { + 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> 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 centralityaxis{"centrality-axis", {20, 0., 100.}, "Centrality axis binning."}; - ConfigurableAxis etaaxis{"eta-axis", {16., -1.0 * static_cast(cut.etatrack), static_cast(cut.etatrack)}, "Pseudorapidity 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.rapidity), static_cast(cut.rapidity)}, "Rapidity axis binning."}; + ConfigurableAxis nsigmaaxisPos{"nsigmaaxisPos", {1, -static_cast(cut.tpcnSigmaPos), static_cast(cut.tpcnSigmaPos)}, "NSigma of positive particle axis binning in THnSparse."}; + ConfigurableAxis nsigmaaxisNeg{"nsigmaaxisNeg", {1, -static_cast(cut.tpcnSigmaNeg), 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", {5, -10, 10}, "Z vertex axis for bin"}; - ConfigurableAxis axisMultiplicityMixing{"multiplicity-axis-mixing", {5, 0, 5000}, "TPC multiplicity for bin"}; + 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"}; + + // rotational + Configurable numberofRotations{"numberofRotations", 1, "Number of rotations for rotational background estimation."}; - // defined in DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h - float massPos = o2::track::PID::getMass(dautherPos); - float massNeg = o2::track::PID::getMass(dautherNeg); + // Normalization factors + ConfigurableAxis axisNch{"axisNch", {100, 0.0f, +100.0f}, "Number of charged particles in |y| < 0.5"}; // Axes specifications - 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 posZaxis = {400, -20., 20., "V_{z} (cm)"}; + AxisSpec dcaXYaxis = {800, -2.0, 2.0, "DCA_{xy} (cm)"}; + AxisSpec dcaZaxis = {800, -2.0, 2.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; @@ -102,37 +119,52 @@ struct phianalysisTHnSparse { Service pdg; int n = 0; + float massPos = o2::track::PID::getMass(3); + float massNeg = o2::track::PID::getMass(3); double* pointPair = nullptr; double* pointSys = nullptr; - TLorentzVector d1, d2, mother; - bool QA = false; - float etapair = 0.8; - float tpcnSigmaPos = 3.0f; - float tpcnSigmaNeg = 3.0f; + ROOT::Math::PxPyPzMVector d1, d2, mother; + bool produceTrue, produceLikesign, produceQA, produceStats, produceRotational, dataQA, MCTruthQA, globalTrack, inelGrater0, tpcPidOnly = false; + float tpcnSigmaPos = 100.0f; + float tpcnSigmaNeg = 100.0f; + float combinedNSigma = 100.0f; + float ptTOFThreshold = 0.5f; int tpcNClsFound = 70; + int dauSize = 2; - Filter triggerFilter = (o2::aod::evsel::sel8 == true); - Filter vtxFilter = (nabs(o2::aod::collision::posZ) < static_cast(cut.vZ)); + rsn::MixingType mixingType = rsn::MixingType::none; - Filter ptFilter = nabs(aod::track::pt) > static_cast(cut.pt); - 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)); + float vzCut = 10.0f; + Filter triggerFilter = (o2::aod::evsel::sel8 == true); + Filter vtxFilter = (nabs(o2::aod::collision::posZ) < vzCut); - using EventCandidates = soa::Filtered>; + using EventCandidates = soa::Filtered>; using EventCandidate = EventCandidates::iterator; - using TrackCandidates = soa::Filtered>; + using TrackCandidates = soa::Join; + + using EventCandidatesMC = soa::Filtered>; + using TrackCandidatesMC = soa::Join; - using EventCandidatesMC = soa::Filtered>; - using TrackCandidatesMC = soa::Filtered>; + using EventCandidatesMCGen = soa::Join; + using McCollisionMults = 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 positive = (aod::track::signed1Pt > 0.0f); + Partition negative = (aod::track::signed1Pt < 0.0f); - 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))); + Partition positiveMC = (aod::track::signed1Pt > 0.0f); + Partition negativeMC = (aod::track::signed1Pt < 0.0f); void init(o2::framework::InitContext&) { + // defined in DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h + massPos = o2::track::PID::getMass(static_cast(daughterPos)); + massNeg = o2::track::PID::getMass(static_cast(daughterNeg)); + LOGF(info, "Initializing particle masses: "); + LOGF(info, " Positive: %d, mass: %f", static_cast(daughterPos), massPos); + LOGF(info, " Negative: %d, mass: %f", static_cast(daughterNeg), massNeg); + // Sparse axes AxisSpec invAxis = {invaxis, "Inv. mass (GeV/c^{2})", "im"}; AxisSpec ptAxis = {ptaxis, "p_{T} (GeV/c)", "pt"}; @@ -148,95 +180,321 @@ struct phianalysisTHnSparse { AxisSpec vzmAxis = {vzaxis, "V_{z} (cm)", "vzm"}; // Systematics axes - std::vector tpcNClsFound_bins = {65., 66., 67., 68., 69., 70., 71., 72., 73.}; - AxisSpec tpcNClsFoundAxis = {tpcNClsFound_bins, "TPC NCl", "ncl"}; + 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, ceAxis, nsAxisPos, nsAxisNeg, etaAxis, yAxis, vzAxis, mumAxis, cemAxis, vzmAxis}; - std::vector allAxes_sys = {tpcNClsFoundAxis}; - - QA = static_cast(produce.QA); - etapair = static_cast(cut.etapair); + std::vector allAxesSys = {tpcNClsFoundAxis}; + + produceQA = static_cast(produce.produceQA); + produceStats = static_cast(produce.produceStats); + produceTrue = static_cast(produce.produceTrue); + produceLikesign = static_cast(produce.produceLikesign); + mixingType = rsn::mixingTypeName(static_cast(produce.eventMixing)); + produceRotational = static_cast(produce.produceRotational); tpcnSigmaPos = static_cast(cut.tpcnSigmaPos); tpcnSigmaNeg = static_cast(cut.tpcnSigmaNeg); tpcNClsFound = static_cast(cut.tpcNClsFound); + globalTrack = static_cast(cut.globalTrack); + inelGrater0 = static_cast(cut.inelGrater0); + combinedNSigma = static_cast(cut.combinedNSigma); + tpcPidOnly = static_cast(cut.tpcPidOnly); + ptTOFThreshold = static_cast(cut.ptTOFThreshold); pointPair = new double[static_cast(o2::analysis::rsn::PairAxisType::unknown)]; pointSys = new double[static_cast(o2::analysis::rsn::SystematicsAxisType::unknown)]; rsnOutput = new o2::analysis::rsn::OutputSparse(); - rsnOutput->init(sparseAxes, allAxes, sysAxes, allAxes_sys, static_cast(produce.True), static_cast(produce.eventMixing), static_cast(produce.Likesign), ®istry); + rsnOutput->init(sparseAxes, allAxes, sysAxes, allAxesSys, produceTrue, mixingType, produceLikesign, produceRotational, ®istry); + + // Print summary of configuration + LOGF(info, "=== PhianalysisTHnSparse configuration summary ==="); + LOGF(info, "produceQA: %s", produceQA ? "true" : "false"); + LOGF(info, "produceStats: %s", produceStats ? "true" : "false"); + LOGF(info, "produceTrue: %s", static_cast(produce.produceTrue) ? "true" : "false"); + LOGF(info, "produceLikesign: %s", static_cast(produce.produceLikesign) ? "true" : "false"); + LOGF(info, "eventMixing: %s", static_cast(produce.eventMixing).c_str()); + LOGF(info, "daughterPos: %d (PDG: %d)", static_cast(daughterPos), static_cast(daughterPosPDG)); + LOGF(info, "daughterNeg: %d (PDG: %d)", static_cast(daughterNeg), static_cast(daughterNegPDG)); + LOGF(info, "motherPDG: %d", static_cast(motherPDG)); + LOGF(info, "tpcnSigmaPos: %.2f", tpcnSigmaPos); + LOGF(info, "tpcnSigmaNeg: %.2f", tpcnSigmaNeg); + LOGF(info, "tpcPidOnly: %s", tpcPidOnly ? "true" : "false"); + LOGF(info, "combinedNSigma: %.2f", combinedNSigma); + LOGF(info, "ptTOFThreshold: %.2f", ptTOFThreshold); + LOGF(info, "rapidity: %.2f", static_cast(cut.rapidity)); + LOGF(info, "etatrack: %.2f", static_cast(cut.etatrack)); + LOGF(info, "pt (min): %.2f", static_cast(cut.pt)); + LOGF(info, "dcaXY: %.2f", static_cast(cut.dcaXY)); + LOGF(info, "dcaZ: %.2f", static_cast(cut.dcaZ)); + LOGF(info, "globalTrack: %s", globalTrack ? "true" : "false"); + LOGF(info, "inelGrater0: %s", inelGrater0 ? "true" : "false"); + LOGF(info, "tpcNClsFound: %d", tpcNClsFound); + LOGF(info, "mixingType: %d", static_cast(mixingType)); + LOGF(info, "numberofMixedEvents: %d", static_cast(numberofMixedEvents)); + LOGF(info, "numberofRotations: %d", static_cast(numberofRotations)); + LOGF(info, "sparseAxes: "); + for (const auto& axis : static_cast>(sparseAxes)) { + LOGF(info, " %s", axis.c_str()); + } + LOGF(info, "sysAxes: "); + for (const auto& axis : static_cast>(sysAxes)) { + LOGF(info, " %s", axis.c_str()); + } + LOGF(info, "==============================================="); - if (QA) { + if (produceQA) { // Event QA - registry.add("QAEvent/hVtxZ", "", kTH1F, {posZaxis}); - registry.add("QAEvent/hCent", "", kTH1F, {{20, 0., 100.}}); - registry.add("QAEvent/hMult", "", kTH1F, {{50, 0., 10000.}}); - registry.add("QAEvent/s4Size", "", kTHnSparseF, {{30, 0., 30.}, {30, 0., 30.}, muAxis, vzAxis}); - registry.add("QAEvent/s2Mult_Vz", "", kTHnSparseF, {axisMultiplicityMixing, axisVertexMixing}); - // 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("QATrack/unlikepm/beforeSelection/hTrack1tpcNClsFound", "", kTH1F, {{110, 50., 160.}}); - - 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/afterSelection/hTrack1tpcNClsFound", "", kTH1F, {{110, 50., 160.}}); - - registry.add("QATrack/unlikepm/TPCPID/h2TracknSigma", "", kTH2F, {{120, -6, 6}, {120, -6, 6}}); - - registry.add("QAMC/hInvMassTrueFalse", "", kTH1F, {invAxis}); + registry.add("QAEvent/hSelection", "Event selection statistics", kTH1D, {{4, 0.0f, 4.0f}}); + auto hEvent = registry.get(HIST("QAEvent/hSelection")); + hEvent->GetXaxis()->SetBinLabel(1, "Full event statistics"); + hEvent->GetXaxis()->SetBinLabel(2, "Events with at least one primary vertex"); + hEvent->GetXaxis()->SetBinLabel(3, "Events with at least one #phi candidate"); + hEvent->GetXaxis()->SetBinLabel(4, "Number of #phi candidates"); + hEvent->SetMinimum(0.1); + + registry.add("QAEvent/hVtxZ", "Vertex position along the z-axis", kTH1F, {posZaxis}); + registry.add("QAEvent/hCent", "Distribution of multiplicity percentile", kTH1F, {{101, 0., 101.}}); + registry.add("QAEvent/hMult", "Multiplicity (amplitude of non-zero channels in the FV0A + FV0C) ", kTH1F, {{300, 0., 30000.}}); + // Track QA + registry.add("QATrack/hSelection", "Tracks statistics", kTH1D, {{9, 0.0f, 9.0f}}); + auto hTrack = registry.get(HIST("QATrack/hSelection")); + hTrack->GetXaxis()->SetBinLabel(1, "all tracks"); + hTrack->GetXaxis()->SetBinLabel(2, "passed pT cut"); + hTrack->GetXaxis()->SetBinLabel(3, "passed eta cut"); + hTrack->GetXaxis()->SetBinLabel(4, "passed DCA cut"); + hTrack->GetXaxis()->SetBinLabel(5, "passed PID cut"); + hTrack->GetXaxis()->SetBinLabel(6, "passed tpcNClsFound cut"); + hTrack->GetXaxis()->SetBinLabel(7, "passed isPrimaryTrack cut"); + hTrack->GetXaxis()->SetBinLabel(8, "passed isPVContributor cut"); + hTrack->GetXaxis()->SetBinLabel(9, "passed all cuts"); + hTrack->SetMinimum(0.1); + + registry.add("QATrack/hRapidity", "Rapidity distribution of K^{+} and K^{-}", kTH1F, {{200, -1, 1}}); + registry.add("QATrack/hEta", "Pseudorapidity distribution of K^{+} and K^{-}", kTH1F, {{200, -1, 1}}); + registry.add("QATrack/hTPCNClsFound", "Distribution of TPC NClsFound of K^{+} and K^{-}", kTH1F, {tpcNClsFoundQAaxis}); + registry.add("QATrack/hDCAxy", "Distribution of DCA_{xy} of K^{+} and K^{-}", kTH1F, {dcaXYaxis}); + registry.add("QATrack/hDCAz", "Distribution of DCA_{z} of K^{+} and K^{-}", kTH1F, {dcaZaxis}); + registry.add("QATrack/hPt", "Distribution of p_{T} of K^{+} and K^{-}", kTH1F, {ptaxis}); + + // General Phi distributions + registry.add("QAPhi/hRapidity", "Rapidity distribution of #phi candidates", kTH1F, {rapidityaxis}); + registry.add("QAPhi/hEta", "Pseudorapidity distribution of #phi candidates", kTH1F, {etaaxis}); + + registry.add("QAPhi/hdPhi", "Azimuthal distribution of #phi candidates", kTH1F, {{100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); + auto hdPhi = registry.get(HIST("QAPhi/hdPhi")); + hdPhi->GetXaxis()->SetTitle("#phi (rad)"); + + registry.add("QAPhi/h2dPhiPt", "Azimuthal distribution of #Delta#phi candidates vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); + auto h2dPhiPt = registry.get(HIST("QAPhi/h2dPhiPt")); + h2dPhiPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + h2dPhiPt->GetYaxis()->SetTitle("#Delta#phi (rad)"); + + registry.add("QAPhi/hTheta", "Polar distribution of #phi candidates", kTH1F, {{100, 0.0f, o2::constants::math::PI}}); + auto hTheta = registry.get(HIST("QAPhi/hTheta")); + hTheta->GetXaxis()->SetTitle("#theta (rad)"); + + registry.add("QAPhi/h2dThetaPt", "Polar distribution of #phi candidates vs p_{T}", kTH2F, {{12, 0, 12}, {100, -o2::constants::math::PI, o2::constants::math::PI}}); + auto h2dThetaPt = registry.get(HIST("QAPhi/h2dThetaPt")); + h2dThetaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + h2dThetaPt->GetYaxis()->SetTitle("#theta (rad)"); + + // TPC PID + registry.add("QATrack/hTPCnSigma", "Distribution of TPC nSigma of K^{+} and K^{-}", kTH1F, {{200, -10, 10}}); + + registry.add("QATrack/h2TPCnSigma", "", kTH2F, {{200, -10, 10}, {200, -10, 10}}); + auto h2TPCnSigma = registry.get(HIST("QATrack/h2TPCnSigma")); + h2TPCnSigma->GetXaxis()->SetTitle("n#sigma_{TPC} K^{+}"); + h2TPCnSigma->GetYaxis()->SetTitle("n#sigma_{TPC} K^{-}"); + + registry.add("QATrack/h2TPCnSigmaPt", "", kTH2F, {ptaxis, {200, -10, 10}}); + auto h2TPCnSigmaPt = registry.get(HIST("QATrack/h2TPCnSigmaPt")); + h2TPCnSigmaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + h2TPCnSigmaPt->GetYaxis()->SetTitle("n#sigma_{TPC} K^{#pm}"); + + // TOF PID + registry.add("QATrack/hTOFnSigma", "Distribution of TOF nSigma of K^{+} and K^{-}", kTH1F, {{200, -10, 10}}); + + registry.add("QATrack/h2TOFnSigma", "", kTH2F, {{200, -10, 10}, {200, -10, 10}}); + auto h2TOFnSigma = registry.get(HIST("QATrack/h2TOFnSigma")); + h2TOFnSigma->GetXaxis()->SetTitle("n#sigma_{TOF} K^{+}"); + h2TOFnSigma->GetYaxis()->SetTitle("n#sigma_{TOF} K^{-}"); + + registry.add("QATrack/h2TOFnSigmaPt", "", kTH2F, {ptaxis, {200, -10, 10}}); + auto h2TOFnSigmaPt = registry.get(HIST("QATrack/h2TOFnSigmaPt")); + h2TOFnSigmaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + h2TOFnSigmaPt->GetYaxis()->SetTitle("n#sigma_{TOF} K^{#pm}"); + + // 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/hInvMassTrueFalse", "", kTH1F, {invAxis}); // not written events in True distribution due to repetition of mothers?? + } // Mixing QA - registry.add("QAMixing/s4Mult_Vz", "", kTHnSparseF, {axisMultiplicityMixing, axisMultiplicityMixing, axisVertexMixing, axisVertexMixing}); - registry.add("QAMixing/s2Mult_Vz", "", kTHnSparseF, {axisMultiplicityMixing, axisVertexMixing}); - } + if (mixingType != rsn::MixingType::none) { + registry.add("QAMixing/hSelection", "Event mixing selection statistics", kTH1D, {{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/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); + if (produceRotational) { + registry.add("QARotational/hSelection", "Rotational background selection statistics", kTH1D, {{1, 0.0f, 1.0f}}); + auto hRB = registry.get(HIST("QARotational/hSelection")); + hRB->GetXaxis()->SetBinLabel(1, "Full rotational background statistics"); + hRB->SetMinimum(0.1); + + // General rotational distributions + registry.add("QARotational/hRapidity", "Rapidity distribution of #phi candidates from rotational background", kTH1F, {rapidityaxis}); + registry.add("QARotational/hEta", "Pseudorapidity distribution of #phi candidates from rotational background", kTH1F, {etaaxis}); + + // Angular distributions for rotational background + registry.add("QARotational/hdPhi", "Rotational background #Delta#phi distribution", kTH1F, {{100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); + auto hRPhi = registry.get(HIST("QARotational/hdPhi")); + hRPhi->GetXaxis()->SetTitle("#Delta#phi"); + hRPhi->GetYaxis()->SetTitle("Counts"); + + registry.add("QARotational/h2dPhiPt", "Rotational background #Delta#phi vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); + auto hR2dPhiPt = registry.get(HIST("QARotational/h2dPhiPt")); + hR2dPhiPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + hR2dPhiPt->GetYaxis()->SetTitle("#Delta#phi"); + + registry.add("QARotational/hTheta", "Rotational background #Delta#theta distribution", kTH1F, {{100, 0.0f, o2::constants::math::PI}}); + auto hRdTheta = registry.get(HIST("QARotational/hTheta")); + hRdTheta->GetXaxis()->SetTitle("#Delta#theta"); + hRdTheta->GetYaxis()->SetTitle("Counts"); + + registry.add("QARotational/h2dThetaPt", "Rotational background #Delta#theta vs p_{T}", kTH2F, {{12, 0, 12}, {100, -o2::constants::math::PI, o2::constants::math::PI}}); + auto hR2dThetaPt = registry.get(HIST("QARotational/h2dThetaPt")); + hR2dThetaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); + hR2dThetaPt->GetYaxis()->SetTitle("#Delta#theta"); + } + } + // Event/Signal loss histograms + registry.add("Factors/hCentralityVsMultMC", "Event centrality vs MC multiplicity", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); + registry.add("Factors/hEventCentrality", "Event centrality", kTH1F, {{101, 0, 101}}); + registry.add("Factors/hNrecInGen", "Number of collisions in MC", kTH1F, {{4, -0.5, 3.5}}); + registry.add("Factors/hGenEvents", "Generated events", HistType::kTH2F, {{axisNch}, {4, 0, 4}}); + auto hGenEvents = registry.get(HIST("Factors/hGenEvents")); + hGenEvents->GetYaxis()->SetBinLabel(1, "All generated events"); + hGenEvents->GetYaxis()->SetBinLabel(2, "Generated events with Mc collision V_{z} cut"); + hGenEvents->GetYaxis()->SetBinLabel(3, "Generated events with Mc collision V_{z} cut and INEL>0"); + hGenEvents->GetYaxis()->SetBinLabel(4, "Generated events with at least one reconstructed event"); + registry.add("Factors/h2dGenPhi", "Centrality vs p_{T}", kTH2D, {{101, 0.0f, 101.0f}, ptaxis}); + registry.add("Factors/h3dGenPhiVsMultMCVsCentrality", "MC multiplicity vs centrality vs p_{T}", kTH3D, {axisNch, {101, 0.0f, 101.0f}, ptaxis}); } template - bool selectedTrack(const T& track) + bool selectedTrack(const T& track, bool isPositive) { - if (track.tpcNClsFound() < tpcNClsFound) + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 0.5); // all tracks + + // Apply pT cut + if (track.pt() < static_cast(cut.pt)) + return false; + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 1.5); + + // Apply eta cut + if (std::abs(track.eta()) >= static_cast(cut.etatrack)) + return false; + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 2.5); + + // Apply DCA cuts + if (std::abs(track.dcaXY()) >= static_cast(cut.dcaXY) || + std::abs(track.dcaZ()) >= static_cast(cut.dcaZ)) return false; - if (!track.isPrimaryTrack()) + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 3.5); + + // PID selection: TPC-only for pt < threshold value, TPC+TOF for pt >= threshold value and have TOF, else TPC-only + float nSigmaCut = isPositive ? tpcnSigmaPos : tpcnSigmaNeg; + if (track.pt() < ptTOFThreshold || !track.hasTOF() || tpcPidOnly) { + if (std::abs(track.tpcNSigmaKa()) >= nSigmaCut) + return false; + } else { + if (std::sqrt(track.tpcNSigmaKa() * track.tpcNSigmaKa() + track.tofNSigmaKa() * track.tofNSigmaKa()) >= combinedNSigma) + return false; + } + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 4.5); + + // Apply tpcNClsFound cut + if (track.tpcNClsFound() < tpcNClsFound) return false; + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 5.5); + + if (globalTrack) { + // Apply Global track cuts + if (!track.isGlobalTrack()) + return false; + } else { + // Apply Primary track cuts + if (!track.isPrimaryTrack()) + return false; + } + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 6.5); + + // Apply PV Contributor cuts if (!track.isPVContributor()) return false; + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 7.5); + + if (produceQA && dataQA) + registry.fill(HIST("QATrack/hSelection"), 8.5); + return true; } - template - bool selectedPair(TLorentzVector& mother, const T& track1, const T& track2) + bool selectedPair(ROOT::Math::PxPyPzMVector& mother, const T& track1, const T& track2) { - d1.SetXYZM(track1.px(), track1.py(), track1.pz(), massPos); - d2.SetXYZM(track2.px(), track2.py(), track2.pz(), massNeg); + d1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massPos); + d2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massNeg); mother = d1 + d2; - if (std::abs(mother.Eta()) > etapair) + if (std::abs(mother.Rapidity()) > static_cast(cut.rapidity)) return false; + return true; } - template - float GetMultiplicity(const T& collision) + float getMultiplicity(const T& collision) { - float multiplicity = collision.multFT0C() + collision.multFT0A(); + float multiplicity = collision.multFT0M(); return multiplicity; } template - float GetCentrality(const T& collision) + float getCentrality(const T& collision) { float centrality = collision.centFT0M(); return centrality; } - - 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) + 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) { pointPair[static_cast(o2::analysis::rsn::PairAxisType::im)] = im; pointPair[static_cast(o2::analysis::rsn::PairAxisType::pt)] = pt; @@ -256,60 +514,91 @@ struct phianalysisTHnSparse { 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); + auto posDaughters = positive->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negDaughters = negative->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + n = 0; - if (QA) { - registry.fill(HIST("QAEvent/s4Size"), posDauthers.size(), negDauthers.size(), GetMultiplicity(collision), collision.posZ()); - registry.fill(HIST("QAEvent/s2Mult_Vz"), GetMultiplicity(collision), collision.posZ()); - } + if (produceQA) + registry.fill(HIST("QAEvent/hSelection"), 0.5); + + if (inelGrater0 && !collision.isInelGt0()) + return; - 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(), GetMultiplicity(collision)); + registry.fill(HIST("Factors/hEventCentrality"), collision.centFT0M()); - if (QA) { + if (produceQA) { + registry.fill(HIST("QAEvent/hSelection"), 1.5); registry.fill(HIST("QAEvent/hVtxZ"), collision.posZ()); - registry.fill(HIST("QAEvent/hMult"), GetMultiplicity(collision)); - registry.fill(HIST("QAEvent/hCent"), GetCentrality(collision)); + registry.fill(HIST("QAEvent/hMult"), getMultiplicity(collision)); + registry.fill(HIST("QAEvent/hCent"), getCentrality(collision)); + if (produceStats) { + dataQA = true; + for (const auto& track : posDaughters) { + selectedTrack(track, true); + } + for (const auto& track : negDaughters) { + selectedTrack(track, false); + } + dataQA = false; + } } - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthers, negDauthers))) { - if (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/unlikepm/beforeSelection/hTrack1tpcNClsFound"), track1.tpcNClsFound()); - } + 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(), posDaughters.size(), negDaughters.size(), collision.posZ()); - if (!selectedTrack(track1)) - continue; + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughters, negDaughters))) { - if (!selectedTrack(track2)) + if (!selectedTrack(track1, true)) // track1 is positive + continue; + if (!selectedTrack(track2, false)) // track2 is negative continue; - - if (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()); - registry.fill(HIST("QATrack/unlikepm/afterSelection/hTrack1tpcNClsFound"), track1.tpcNClsFound()); - } if (!selectedPair(mother, track1, track2)) continue; - if (QA) { - registry.fill(HIST("QATrack/unlikepm/TPCPID/h2TracknSigma"), track1.tpcNSigmaKa(), track2.tpcNSigmaKa()); + if (produceQA) { + registry.fill(HIST("QATrack/h2TPCnSigma"), track1.tpcNSigmaKa(), track2.tpcNSigmaKa()); + registry.fill(HIST("QATrack/h2TPCnSigmaPt"), track1.pt(), track1.tpcNSigmaKa()); + registry.fill(HIST("QATrack/h2TPCnSigmaPt"), track2.pt(), track2.tpcNSigmaKa()); + + registry.fill(HIST("QATrack/h2TOFnSigma"), track1.tofNSigmaKa(), track2.tofNSigmaKa()); + registry.fill(HIST("QATrack/h2TOFnSigmaPt"), track1.pt(), track1.tofNSigmaKa()); + registry.fill(HIST("QATrack/h2TOFnSigmaPt"), track2.pt(), track2.tofNSigmaKa()); + + registry.fill(HIST("QATrack/hTPCnSigma"), track1.tpcNSigmaKa()); + registry.fill(HIST("QATrack/hTPCnSigma"), track2.tpcNSigmaKa()); + if (track1.hasTOF()) + registry.fill(HIST("QATrack/hTOFnSigma"), track1.tofNSigmaKa()); + if (track2.hasTOF()) + registry.fill(HIST("QATrack/hTOFnSigma"), track2.tofNSigmaKa()); + + registry.fill(HIST("QATrack/hEta"), track1.eta()); + registry.fill(HIST("QATrack/hEta"), track2.eta()); + registry.fill(HIST("QATrack/hPt"), track1.pt()); + registry.fill(HIST("QATrack/hPt"), track2.pt()); + registry.fill(HIST("QATrack/hDCAxy"), track1.dcaXY()); + registry.fill(HIST("QATrack/hDCAxy"), track2.dcaXY()); + registry.fill(HIST("QATrack/hDCAz"), track1.dcaZ()); + registry.fill(HIST("QATrack/hDCAz"), track2.dcaZ()); + registry.fill(HIST("QATrack/hTPCNClsFound"), track1.tpcNClsFound()); + registry.fill(HIST("QATrack/hTPCNClsFound"), track2.tpcNClsFound()); + registry.fill(HIST("QATrack/hRapidity"), track1.rapidity(massPos)); + registry.fill(HIST("QATrack/hRapidity"), track2.rapidity(massNeg)); + + registry.fill(HIST("QAPhi/hRapidity"), mother.Rapidity()); + registry.fill(HIST("QAPhi/hEta"), mother.Eta()); + registry.fill(HIST("QAPhi/hdPhi"), track1.phi() - track2.phi()); + registry.fill(HIST("QAPhi/h2dPhiPt"), mother.Pt(), track1.phi() - track2.phi()); + registry.fill(HIST("QAPhi/hTheta"), mother.Theta()); + registry.fill(HIST("QAPhi/h2dThetaPt"), mother.Pt(), d1.Theta() - d2.Theta()); } - pointPair = FillPointPair(mother.Mag(), + pointPair = fillPointPair(mother.M(), mother.Pt(), - GetMultiplicity(collision), - GetCentrality(collision), - (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), - (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + getMultiplicity(collision), + getCentrality(collision), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), mother.Eta(), mother.Rapidity(), collision.posZ(), @@ -317,28 +606,71 @@ struct phianalysisTHnSparse { 0, 0); rsnOutput->fillUnlikepm(pointPair); + + if (produceQA) { + registry.fill(HIST("QAEvent/hSelection"), 3.5); + if (n == 0) + registry.fill(HIST("QAEvent/hSelection"), 2.5); + } + n = n + 1; + + if (produceRotational) { + for (int i = 1; i <= static_cast(numberofRotations); i++) { + // compute rotation angle in radians using o2::constants::math::PI + float angleDeg = i * (360.0f / (static_cast(numberofRotations) + 1)); + float angleRad = angleDeg * (o2::constants::math::PI / 180.0f); + float px2new = track2.px() * std::cos(angleRad) - track2.py() * std::sin(angleRad); + float py2new = track2.px() * std::sin(angleRad) + track2.py() * std::cos(angleRad); + d2 = ROOT::Math::PxPyPzMVector(px2new, py2new, track2.pz(), massNeg); + mother = d1 + d2; + + if (produceQA) { + registry.fill(HIST("QARotational/hSelection"), 0.5); + registry.fill(HIST("QARotational/hRapidity"), mother.Rapidity()); + registry.fill(HIST("QARotational/hEta"), mother.Eta()); + registry.fill(HIST("QARotational/hdPhi"), track1.phi() - track2.phi()); + registry.fill(HIST("QARotational/h2dPhiPt"), mother.Pt(), track1.phi() - track2.phi()); + registry.fill(HIST("QARotational/hTheta"), mother.Theta()); + registry.fill(HIST("QARotational/h2dThetaPt"), mother.Pt(), d1.Theta() - d2.Theta()); + } + pointPair = fillPointPair(mother.M(), + mother.Pt(), + getMultiplicity(collision), + getCentrality(collision), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + collision.posZ(), + 0, + 0, + 0); + + rsnOutput->fillRotationpm(pointPair); + } + } } - if (static_cast(produce.Likesign)) { + if (produceLikesign) { - for (auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(posDauthers, posDauthers))) { - if (!selectedTrack(track1)) + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(posDaughters, posDaughters))) { + if (!selectedTrack(track1, true)) // both positive continue; - if (!selectedTrack(track2)) + if (!selectedTrack(track2, true)) // both positive continue; if (!selectedPair(mother, track1, track2)) continue; if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "Like-sign positive: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.Mag()); + LOGF(info, "Like-sign positive: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.M()); - pointPair = FillPointPair(mother.Mag(), + pointPair = fillPointPair(mother.M(), mother.Pt(), - GetMultiplicity(collision), - GetCentrality(collision), - (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), - (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + getMultiplicity(collision), + getCentrality(collision), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), mother.Eta(), mother.Rapidity(), collision.posZ(), @@ -349,24 +681,24 @@ struct phianalysisTHnSparse { rsnOutput->fillLikepp(pointPair); } - for (auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(negDauthers, negDauthers))) { - if (!selectedTrack(track1)) + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(negDaughters, negDaughters))) { + if (!selectedTrack(track1, false)) // both negative continue; - if (!selectedTrack(track2)) + if (!selectedTrack(track2, false)) // both negative continue; if (!selectedPair(mother, track1, track2)) continue; if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "Like-sign negative: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.Mag()); + LOGF(info, "Like-sign negative: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.M()); - pointPair = FillPointPair(mother.Mag(), + pointPair = fillPointPair(mother.M(), mother.Pt(), - GetMultiplicity(collision), - GetCentrality(collision), - (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), - (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + getMultiplicity(collision), + getCentrality(collision), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), mother.Eta(), mother.Rapidity(), collision.posZ(), @@ -378,40 +710,46 @@ struct phianalysisTHnSparse { } } } - 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; - auto posDauthersMC = positiveMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto negDauthersMC = negativeMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + registry.fill(HIST("QAMC/Truth/hMCEvent"), 0.5); + + auto posDaughtersMC = positiveMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negDaughtersMC = negativeMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); if (!collision.has_mcCollision()) { - LOGF(warning, "No MC collision for this collision, skip..."); + if (static_cast(verbose.verboselevel) > 0) + LOGF(warning, "No MC collision for this collision, skip..."); return; } - - if (std::abs(collision.posZ()) > static_cast(cut.vZ)) + auto mcCollision = collision.mcCollision(); + if (std::abs(mcCollision.posZ()) > vzCut) + return; + if (inelGrater0 && !collision.isInelGt0()) return; - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersMC, negDauthersMC))) { + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersMC, negDaughtersMC))) { if (!track1.has_mcParticle()) { - LOGF(warning, "No MC particle for track, skip..."); + if (static_cast(verbose.verboselevel) > 0) + LOGF(warning, "No MC particle for track, skip..."); continue; } if (!track2.has_mcParticle()) { - LOGF(warning, "No MC particle for track, skip..."); + if (static_cast(verbose.verboselevel) > 0) + LOGF(warning, "No MC particle for track, skip..."); continue; } - if (!selectedTrack(track1)) + if (!selectedTrack(track1, true)) // track1 is positive continue; - - if (!selectedTrack(track2)) + if (!selectedTrack(track2, false)) // track2 is negative continue; const auto mctrack1 = track1.mcParticle(); @@ -419,12 +757,12 @@ struct phianalysisTHnSparse { int track1PDG = std::abs(mctrack1.pdgCode()); int track2PDG = std::abs(mctrack2.pdgCode()); - if (!(track1PDG == dautherPosPDG && track2PDG == dautherNegPDG)) { + if (!(track1PDG == daughterPosPDG && track2PDG == daughterNegPDG)) { continue; } n = 0; - for (auto& mothertrack1 : mctrack1.mothers_as()) { - for (auto& mothertrack2 : mctrack2.mothers_as()) { + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) continue; @@ -432,10 +770,7 @@ struct phianalysisTHnSparse { if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) continue; - if (std::abs(mothertrack1.y()) > static_cast(cut.y)) - continue; - - if (std::abs(mothertrack2.y()) > static_cast(cut.y)) + if (std::abs(mothertrack1.y()) > static_cast(cut.rapidity)) continue; if (std::abs(mothertrack1.pdgCode()) != motherPDG) @@ -450,17 +785,17 @@ struct phianalysisTHnSparse { continue; if (n > 0) { - if (QA) - registry.fill(HIST("QAMC/hInvMassTrueFalse"), mother.Mag()); + if (produceQA) + registry.fill(HIST("QAMC/Truth/hInvMassTrueFalse"), mother.M()); continue; } - pointPair = FillPointPair(mother.Mag(), + pointPair = fillPointPair(mother.M(), mother.Pt(), - GetMultiplicity(collision), - GetCentrality(collision), - (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), - (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + getMultiplicity(collision), + getCentrality(collision), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), mother.Eta(), mother.Rapidity(), collision.posZ(), @@ -474,226 +809,291 @@ struct phianalysisTHnSparse { } } } + 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(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) { + if (std::abs(mcCollision.posZ()) > vzCut) + return; - if (!static_cast(produce.True)) + if (inelGrater0 && !mcCollision.isInelGt0()) return; - if (std::abs(mcCollision.posZ()) > static_cast(cut.vZ)) + if (collisions.size() == 0) return; - int nuberofPhi = 0; + for (const auto& collision : collisions) { + auto centralityGen = getCentrality(collision); + auto multiplicityGen = getMultiplicity(collision); - for (auto& particle : mcParticles) { - if (std::abs(particle.y()) > static_cast(cut.y)) - continue; + for (const auto& particle : mcParticles) { - if (particle.pdgCode() == motherPDG) { - auto daughters = particle.daughters_as(); - if (daughters.size() != 2) + if (std::abs(particle.y()) > static_cast(cut.rapidity)) continue; - auto daup = false; - auto daun = false; + if (particle.pdgCode() == motherPDG) { - for (auto& dau : daughters) { - if (!dau.isPhysicalPrimary()) + auto daughters = particle.daughters_as(); + if (daughters.size() != dauSize) 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); + auto daup = false; + auto daun = false; + + for (const auto& dau : daughters) { + if (dau.pdgCode() == daughterPosPDG) { + daup = true; + d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -daughterNegPDG) { + daun = true; + d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); + } } - } - if (!daup && !daun) - continue; - - 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); + if (!daup || !daun) + continue; - rsnOutput->fillUnlikegen(pointPair); + mother = d1 + d2; - nuberofPhi++; - numberofEntries++; + pointPair = fillPointPair(mother.M(), + mother.Pt(), + multiplicityGen, + centralityGen, + 0, + 0, + mother.Eta(), + mother.Rapidity(), + mcCollision.posZ(), + 0, + 0, + 0); - 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()); + rsnOutput->fillUnlikegen(pointPair); + } } } } - - PROCESS_SWITCH(phianalysisTHnSparse, processGen, "Process generated.", false); - - int id; + PROCESS_SWITCH(PhianalysisTHnSparse, processGen, "Process MC Generated.", false); void processMixed(EventCandidates const& collisions, TrackCandidates const& tracks) { - if (!static_cast(produce.eventMixing)) + if (mixingType == rsn::MixingType::none) return; - BinningType binning{{axisVertexMixing, axisMultiplicityMixing}, true}; + auto tracksTuple = std::make_tuple(tracks); - SameKindPair pair{binning, numberofMixedEvents, -1, collisions, tracksTuple, &cache}; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + BinningTypeVzCe binningVzCe{{axisVertexMixing, axisCentralityMixing}, true}; + SameKindPair pairVzCe{binningVzCe, static_cast(numberofMixedEvents), -1, collisions, tracksTuple, &cache}; - if (!c1.sel8()) { - continue; - } - if (!c2.sel8()) { - continue; - } - if (QA) { - if (!(id == c1.globalIndex())) { - registry.fill(HIST("QAMixing/s2Mult_Vz"), GetMultiplicity(c1), c1.posZ()); - id = c1.globalIndex(); + BinningTypeVzMu binningVzMu{{axisVertexMixing, axisMultiplicityMixing}, true}; + SameKindPair pairVzMu{binningVzMu, static_cast(numberofMixedEvents), -1, collisions, tracksTuple, &cache}; + + if (mixingType == rsn::MixingType::ce) { + for (const auto& [c1, tracks1, c2, tracks2] : pairVzCe) { + if (produceQA) + registry.fill(HIST("QAMixing/hSelection"), 0.5); + + auto posDaughtersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); + auto posDaughtersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); + auto negDaughtersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); + auto negDaughtersc2 = 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()); } - } - 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); + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc1, negDaughtersc2))) { - if (QA) - registry.fill(HIST("QAMixing/s4Mult_Vz"), GetMultiplicity(c1), GetMultiplicity(c2), c1.posZ(), c2.posZ()); + if (!selectedTrack(track1, true)) // track1 is positive + continue; + if (!selectedTrack(track2, false)) // track2 is negative + continue; - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc1, negDauthersc2))) { + if (!selectedPair(mother, track1, track2)) + continue; - if (!selectedTrack(track1)) + pointPair = fillPointPair(mother.M(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); - continue; - if (!selectedTrack(track2)) - continue; + rsnOutput->fillMixingpm(pointPair); + } - if (!selectedPair(mother, track1, track2)) - continue; + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc2, negDaughtersc1))) { - 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()); + if (!selectedTrack(track1, true)) // track1 is positive + continue; + if (!selectedTrack(track2, false)) // track2 is negative + continue; - rsnOutput->fillMixingpm(pointPair); - } + if (!selectedPair(mother, track1, track2)) + continue; - if (static_cast(produce.Likesign)) { + pointPair = fillPointPair(mother.M(), + mother.Pt(), + getMultiplicity(c1), + getCentrality(c1), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), + mother.Eta(), + mother.Rapidity(), + c1.posZ(), + getMultiplicity(c2), + getCentrality(c2), + c2.posZ()); - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc1, posDauthersc2))) { + 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 posDaughtersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); + auto posDaughtersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); + auto negDaughtersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); + auto negDaughtersc2 = 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()); + } - if (!selectedTrack(track1)) + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc1, negDaughtersc2))) { + if (!selectedTrack(track1, true)) // track1 is positive continue; - if (!selectedTrack(track2)) + + if (!selectedTrack(track2, false)) // track2 is negative continue; if (!selectedPair(mother, track1, track2)) continue; - pointPair = FillPointPair(mother.Mag(), + pointPair = fillPointPair(mother.M(), mother.Pt(), - GetMultiplicity(c1), - GetCentrality(c1), - (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), - (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + getMultiplicity(c1), + getCentrality(c1), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), mother.Eta(), mother.Rapidity(), c1.posZ(), - GetMultiplicity(c2), - GetCentrality(c2), + getMultiplicity(c2), + getCentrality(c2), c2.posZ()); - rsnOutput->fillMixingpp(pointPair); + rsnOutput->fillMixingpm(pointPair); } - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(negDauthersc1, negDauthersc2))) { + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc2, negDaughtersc1))) { - if (!selectedTrack(track1)) + if (!selectedTrack(track1, true)) continue; - if (!selectedTrack(track2)) + if (!selectedTrack(track2, false)) continue; if (!selectedPair(mother, track1, track2)) continue; - pointPair = FillPointPair(mother.Mag(), + + pointPair = fillPointPair(mother.M(), mother.Pt(), - GetMultiplicity(c1), - GetCentrality(c1), - (tpcnSigmaPos > 0) ? std::abs(track1.tpcNSigmaKa()) : track1.tpcNSigmaKa(), - (tpcnSigmaNeg > 0) ? std::abs(track2.tpcNSigmaKa()) : track2.tpcNSigmaKa(), + getMultiplicity(c1), + getCentrality(c1), + track1.tpcNSigmaKa(), + track2.tpcNSigmaKa(), mother.Eta(), mother.Rapidity(), c1.posZ(), - GetMultiplicity(c2), - GetCentrality(c2), + getMultiplicity(c2), + getCentrality(c2), c2.posZ()); - rsnOutput->fillMixingmm(pointPair); + rsnOutput->fillMixingmp(pointPair); } } + } + } + PROCESS_SWITCH(PhianalysisTHnSparse, processMixed, "Process Mixing Event.", false); - for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDauthersc2, negDauthersc1))) { + void processFactors(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) + { + registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 0.5); - if (!selectedTrack(track1)) + if (std::abs(mcCollision.posZ()) > vzCut) + return; - continue; - if (!selectedTrack(track2)) + registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 1.5); + + if (inelGrater0 && !mcCollision.isInelGt0()) + return; + + registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 2.5); + + float centrality = 100.5f; + for (auto const& collision : collisions) { + centrality = collision.centFT0M(); + } + + registry.fill(HIST("Factors/hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta08()); + registry.fill(HIST("Factors/hNrecInGen"), collisions.size()); + + for (const auto& particle : mcParticles) { + + if (std::abs(particle.y()) > static_cast(cut.rapidity)) + continue; + + if (particle.pdgCode() == motherPDG) { + + auto daughters = particle.daughters_as(); + if (daughters.size() != dauSize) continue; - if (!selectedPair(mother, track1, track2)) + auto daup = false; + auto daun = false; + + for (const auto& dau : daughters) { + if (dau.pdgCode() == daughterPosPDG) { + daup = true; + d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -daughterNegPDG) { + daun = true; + d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); + } + } + if (!daup || !daun) 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()); + mother = d1 + d2; - rsnOutput->fillMixingmp(pointPair); + registry.fill(HIST("Factors/h2dGenPhi"), centrality, mother.Pt()); + registry.fill(HIST("Factors/h3dGenPhiVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta08(), centrality, mother.Pt()); } } + + if (collisions.size() == 0) + return; + + registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 3.5); } - PROCESS_SWITCH(phianalysisTHnSparse, processMixed, "Process Mixing Event.", true); + PROCESS_SWITCH(PhianalysisTHnSparse, processFactors, "Process to obtain normalization factors from MC.", false); }; - WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Tasks/Resonances/phianalysisrun3.cxx b/PWGLF/Tasks/Resonances/phianalysisrun3.cxx index a865482393a..74d82612efc 100644 --- a/PWGLF/Tasks/Resonances/phianalysisrun3.cxx +++ b/PWGLF/Tasks/Resonances/phianalysisrun3.cxx @@ -16,38 +16,40 @@ // (5) particle = 2 --> lambdastar // (6) 4 process function (a) Data same event (b) Data mixed event (c) MC generated (d) MC reconstructed -#include +#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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#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 "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" - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -56,6 +58,7 @@ struct phianalysisrun3 { SliceCache cache; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // events + Configurable applyEvsel{"applyEvsel", false, "applyEvsel"}; Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; // track Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; @@ -252,7 +255,7 @@ struct phianalysisrun3 { void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) { - if (!collision.sel8()) { + if (applyEvsel && !collision.sel8()) { return; } if (timFrameEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { @@ -309,10 +312,10 @@ struct phianalysisrun3 { BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicity}, true}; SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; for (auto& [c1, tracks1, c2, tracks2] : pair) { - if (!c1.sel8()) { + if (applyEvsel && !c1.sel8()) { continue; } - if (!c2.sel8()) { + if (applyEvsel && !c2.sel8()) { continue; } 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))) { diff --git a/PWGLF/Tasks/Resonances/phianalysisrun3_PbPb.cxx b/PWGLF/Tasks/Resonances/phianalysisrun3_PbPb.cxx index 9de16794c14..647d14ea519 100644 --- a/PWGLF/Tasks/Resonances/phianalysisrun3_PbPb.cxx +++ b/PWGLF/Tasks/Resonances/phianalysisrun3_PbPb.cxx @@ -8,53 +8,71 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// Preliminary QA analysis task for resonances -// (1) For Run3 -// (2) Event and track selection need to be optimized -// (3) particle = 0 --> phi -// (4) particle = 1 --> kstar -// (5) particle = 2 --> lambdastar -// (6) 4 process function (a) Data same event (b) Data mixed event (c) MC generated (d) MC reconstructed +/// \file phianalysisrun3_PbPb.cxx +/// \brief Code for phi resonance without resonance initializer +/// \author Sarjeeta Gami -#include +#include "PWGLF/DataModel/EPCalibrationTables.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/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#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 "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 +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; +using namespace o2::aod::rctsel; + struct phianalysisrun3_PbPb { - SliceCache cache; + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + RCTFlagsChecker rctChecker; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registry{"registry"}; // events Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; // track @@ -62,65 +80,196 @@ 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.0f, "Value of the TPC Nsigma cut"}; + Configurable nsigmacutTOF{"nsigmacutTOF", 2.0f, "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 tof{"TOF", true, "TOF"}; - Configurable tpc{"TPC", false, "TPC"}; - Configurable combined{"combined", true, "combined"}; - Configurable isEtaAssym{"isEtaAssym", false, "isEtaAssym"}; + Configurable fillOccupancy{"fillOccupancy", true, "fill Occupancy"}; + Configurable isNoTOF{"isNoTOF", false, "isNoTOF"}; + Configurable pid{"pid", 0, "pid"}; + Configurable additionalEvSel1{"additionalEvSel1", true, "Additional evsel1"}; + Configurable additionalEvSel2{"additionalEvSel2", true, "Additional evsel2"}; + Configurable additionalEvSel3{"additionalEvSel3", true, "Additional evsel3"}; + Configurable additionalEvSel4{"additionalEvSel4", true, "Additional evsel4"}; + Configurable additionalEvSel5{"additionalEvSel5", true, "Additional evsel5"}; + Configurable additionalEvSel6{"additionalEvSel6", true, "Additional evsel6"}; Configurable cfgMultFT0{"cfgMultFT0", true, "cfgMultFT0"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.0, "cut TOF beta"}; + Configurable useGlobalTrack{"useGlobalTrack", false, "use Global track"}; 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 rapiditycut1{"rapiditycut1", -0.5f, "Rapidity cut lower"}; + Configurable rapiditycut2{"rapiditycut2", 0.5f, "Rapidity cut upper"}; + 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 cfgTPCcluster{"cfgTPCcluster", 70, "Number of TPC cluster"}; + Configurable cfgTPCSharedcluster{"cfgTPCSharedcluster", 0.4, "Maximum Number of TPC shared cluster"}; + Configurable confMinRot{"confMinRot", 5.0f * 3.14159265f / 6.0f, "Minimum of rotation"}; + Configurable confMaxRot{"confMaxRot", 7.0f * 3.14159265f / 6.0f, "Maximum of rotation"}; + Configurable pdgcheck{"pdgcheck", true, "pdgcheck"}; + Configurable reco{"reco", true, "reco"}; + Configurable cfgDoSel8{"cfgDoSel8", true, "Apply sel8 selection"}; + ConfigurableAxis ptAxisphi{"ptAxisphi", {200, 0.0f, 20.0f}, "phi pT axis"}; + ConfigurableAxis centAxisphi{"centAxisphi", {200, 0.0, 200.0}, "phi centrality axis"}; + ConfigurableAxis massAxisphi{"massAxisphi", {200, 0.9, 1.1}, "phi mass axis"}; + ConfigurableAxis axisNch{"axisNch", {100, 0.0f, 100.0f}, "Number of charged particles in |y| < 0.5"}; + 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 cfgMinOccupancy{"cfgMinOccupancy", 0, "Minimum occupancy cut"}; + Configurable cfgMaxOccupancy{"cfgMaxOccupancy", 3000, "Maximum occupancy cut"}; + Configurable centestimator{"centestimator", 0, "Select multiplicity estimator: 0 - FT0C, 1 - FT0A, 2 - FT0M, 3 - FV0A, 4 - PVTracks"}; + + 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&) { - 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("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}}); + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + AxisSpec impactParAxis = {binsImpactPar, "Impact Parameter"}; + AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec centAxis = {binsCent, "V0M (%)"}; 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("hCentrality", "Centrality distribution", kTH1F, {centAxisphi}); + histos.add("hVtxZ", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); + histos.add("hOccupancy", "Occupancy distribution", kTH1F, {{500, 0, 50000}}); + histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{10, 0, 10.0}}); + histos.add("h3PhiInvMassUnlikeSign", "Invariant mass of Phi meson Unlike Sign", kTH3F, {centAxisphi, ptAxisphi, massAxisphi}); + histos.add("h3PhiInvMassMixed", "Invariant mass of Phi meson Mixed", kTH3F, {centAxisphi, ptAxisphi, massAxisphi}); + histos.add("h3PhiInvMassRot", "Invariant mass of Phi meson Rotation", kTH3F, {centAxisphi, ptAxisphi, massAxisphi}); + histos.add("h3PhiInvMassSame", "Invariant mass of Phi meson same", kTH3F, {centAxisphi, ptAxisphi, massAxisphi}); + histos.add("h2PhiRapidity", "phi meson Rapidity", kTH2F, {ptAxisphi, {200, -4, 4}}); + histos.add("hEta", "eta of kaon track candidates", HistType::kTH2F, {{200, -1.0f, 1.0f}, ptAxisphi}); + histos.add("hPhi", "phi of kaon track candidates", HistType::kTH2F, {{65, 0, 6.5}, ptAxisphi}); + + // DCA QA + // DCA histograms: separate for positive and negative kaons, range [-1.0, 1.0] + histos.add("QAbefore/trkDCAxy_pos", "DCAxy distribution of positive kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAbefore/trkDCAxy_neg", "DCAxy distribution of negative kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAbefore/trkDCAz_pos", "DCAz distribution of positive kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAbefore/trkDCAz_neg", "DCAz distribution of negative kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + + histos.add("QAbefore/trkDCAxypt_pos", "DCAxy distribution of positive kaon track candidates", HistType::kTH2F, {{150, -1.0f, 1.0f}, ptAxisphi}); + histos.add("QAbefore/trkDCAxypt_neg", "DCAxy distribution of negative kaon track candidates", HistType::kTH2F, {{150, -1.0f, 1.0f}, ptAxisphi}); + histos.add("QAbefore/trkDCAzpt_pos", "DCAz distribution of positive kaon track candidates", HistType::kTH2F, {{150, -1.0f, 1.0f}, ptAxisphi}); + histos.add("QAbefore/trkDCAzpt_neg", "DCAz distribution of negative kaon track candidates", HistType::kTH2F, {{150, -1.0f, 1.0f}, ptAxisphi}); + + histos.add("QAafter/trkDCAxy_pos", "DCAxy distribution of positive kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAafter/trkDCAxy_neg", "DCAxy distribution of negative kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAafter/trkDCAz_pos", "DCAz distribution of positive kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + histos.add("QAafter/trkDCAz_neg", "DCAz distribution of negative kaon track candidates", HistType::kTH1F, {{150, -1.0f, 1.0f}}); + + histos.add("QAafter/trkDCAxypt_pos", "DCAxy distribution of positive kaon track candidates", HistType::kTH2F, {{150, -1.0f, 1.0f}, ptAxisphi}); + histos.add("QAafter/trkDCAxypt_neg", "DCAxy distribution of negative kaon track candidates", HistType::kTH2F, {{150, -1.0f, 1.0f}, ptAxisphi}); + histos.add("QAafter/trkDCAzpt_pos", "DCAz distribution of positive kaon track candidates", HistType::kTH2F, {{150, -1.0f, 1.0f}, ptAxisphi}); + histos.add("QAafter/trkDCAzpt_neg", "DCAz distribution of negative kaon track candidates", HistType::kTH2F, {{150, -1.0f, 1.0f}, ptAxisphi}); + // PID QA before cuts + histos.add("QAbefore/TOF_TPC_Mapka_all_pos", "TOF + TPC Combined PID for positive Kaon;#sigma_{TOF}^{K^{+}};#sigma_{TPC}^{K^{+}}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); + histos.add("QAbefore/TOF_TPC_Mapka_all_neg", "TOF + TPC Combined PID for negative Kaon;#sigma_{TOF}^{K^{-}};#sigma_{TPC}^{K^{-}}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); + + histos.add("QAbefore/TOF_Nsigma_all_pos", "TOF NSigma for positive Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{K^{+}}", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + histos.add("QAbefore/TOF_Nsigma_all_neg", "TOF NSigma for negative Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{K^{-}}", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + + histos.add("QAbefore/TPC_Nsigma_all_pos", "TPC NSigma for positive Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{K^{+}}", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + histos.add("QAbefore/TPC_Nsigma_all_neg", "TPC NSigma for negative Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{K^{-}}", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + + // PID QA after cuts + histos.add("QAafter/TOF_TPC_Mapka_all_pos", "TOF + TPC Combined PID for positive Kaon;#sigma_{TOF}^{K^{+}};#sigma_{TPC}^{K^{+}}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); + histos.add("QAafter/TOF_TPC_Mapka_all_neg", "TOF + TPC Combined PID for negative Kaon;#sigma_{TOF}^{K^{-}};#sigma_{TPC}^{K^{-}}", {HistType::kTH2D, {{100, -6, 6}, {100, -6, 6}}}); + + histos.add("QAafter/TOF_Nsigma_all_pos", "TOF NSigma for positive Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{K^{+}}", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + histos.add("QAafter/TOF_Nsigma_all_neg", "TOF NSigma for negative Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{K^{-}}", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + + histos.add("QAafter/TPC_Nsigma_all_pos", "TPC NSigma for positive Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{K^{+}}", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + histos.add("QAafter/TPC_Nsigma_all_neg", "TPC NSigma for negative Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{K^{-}}", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); } else if (isMC) { - histos.add("hMC", "MC Event statistics", kTH1F, {{6, 0.0f, 6.0f}}); - histos.add("h1PhiGen", "Phi meson Gen", 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("h2PhiGen2", "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("h1Phimassgen", "Phi meson gen", kTH1F, {{200, 0.9, 1.1}}); - histos.add("h1Phimassrec", "Phi meson Rec", kTH1F, {{200, 0.9, 1.1}}); - histos.add("h1Phipt", "Phi meson Rec", kTH1F, {{200, 0.0f, 20.0f}}); + histos.add("hMC", "MC Event statistics", kTH1F, {{15, 0.0f, 15.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, {ptAxisphi}); + histos.add("h1PhiGen1", "Phi meson Gen", kTH1F, {ptAxisphi}); + histos.add("h1PhiRecsplit", "Phi meson Rec split", kTH1F, {ptAxisphi}); + histos.add("Centrec", "MC Centrality", kTH1F, {centAxisphi}); + histos.add("Centgen", "MC Centrality", kTH1F, {centAxisphi}); + histos.add("hVtxZgen", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); + histos.add("hVtxZrec", "Vertex distribution in Z;Z (cm)", kTH1F, {{400, -20.0, 20.0}}); + histos.add("h2PhiRec2", "Phi meson Rec", kTH2F, {ptAxisphi, centAxisphi}); + histos.add("h3PhiRec3", "Phi meson Rec", kTH3F, {ptAxisphi, centAxisphi, massAxisphi}); + histos.add("h3Phi1Rec3", "Phi meson Rec", kTH3F, {ptAxisphi, centAxisphi, massAxisphi}); + histos.add("h3PhiGen3", "Phi meson Gen", kTH3F, {ptAxisphi, centAxisphi, massAxisphi}); + histos.add("h3PhiInvMassMixedMC", "Invariant mass of Phi meson Mixed", kTH3F, {centAxisphi, ptAxisphi, massAxisphi}); + histos.add("h3PhiInvMassSameMC", "Invariant mass of Phi meson same", kTH3F, {centAxisphi, ptAxisphi, massAxisphi}); + histos.add("h3PhiInvMassSameMC1", "Invariant mass of Phi meson same", kTH3F, {centAxisphi, ptAxisphi, massAxisphi}); + histos.add("h3PhiInvMassRotMC", "Invariant mass of Phi meson Rotation", kTH3F, {centAxisphi, ptAxisphi, massAxisphi}); + histos.add("h2PhiGen2", "Phi meson gen", kTH2F, {ptAxisphi, centAxisphi}); + histos.add("h2PhiGen1", "Phi meson gen", kTH2F, {ptAxis, impactParAxis}); + histos.add("h1PhiRec1", "Phi meson Rec", kTH1F, {ptAxisphi}); + histos.add("h1Phimassgen", "Phi meson gen", kTH1F, {massAxisphi}); + histos.add("h1Phimassrec", "Phi meson Rec", kTH1F, {massAxisphi}); + histos.add("h1Phimasssame", "Phi meson Rec", kTH1F, {massAxisphi}); + histos.add("h1Phimassmix", "Phi meson Rec", kTH1F, {massAxisphi}); + histos.add("h1Phimassrot", "Phi meson Rec", kTH1F, {massAxisphi}); + histos.add("h1Phi1massrec", "Phi meson Rec", kTH1F, {massAxisphi}); + histos.add("h1Phipt", "Phi meson Rec", kTH1F, {ptAxisphi}); + histos.add("hOccupancy1", "Occupancy distribution", kTH1F, {{500, 0, 50000}}); + histos.add("h1PhifinalRec", "Phi meson Rec", kTH1F, {ptAxisphi}); + histos.add("h1Phifinalgenmass", "Phi meson gen mass", kTH1F, {massAxisphi}); + histos.add("h3PhifinalRec", "Phi meson Rec", kTH3F, {ptAxisphi, centAxisphi, massAxisphi}); + histos.add("h1PhifinalGen", "Phi meson Gen", kTH1F, {ptAxisphi}); + histos.add("h2PhifinalGen", "Phi meson Gen", kTH2F, {ptAxisphi, centAxisphi}); + histos.add("hMC1", "MC Event statistics", kTH1F, {{15, 0.0f, 15.0f}}); + histos.add("Centrec1", "MC Centrality", kTH1F, {centAxisphi}); + histos.add("Centsame", "MC Centrality", kTH1F, {centAxisphi}); + histos.add("Centmc", "MC Centrality", kTH1F, {centAxisphi}); + histos.add("Centmix", "MC Centrality", kTH1F, {centAxisphi}); + histos.add("Centgen1", "MC Centrality", kTH1F, {centAxisphi}); + histos.add("h1PhiRecsplit1", "Phi meson Rec split", kTH1F, {ptAxisphi}); + 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}, centAxisphi, ptAxisphi}}); + histos.add("TPC_Nsigma_MC", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + histos.add("TOF_Nsigma1_MC", "TOF NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TOF}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + histos.add("TPC_Nsigma1_MC", "TPC NSigma for Kaon;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Kaon};", {HistType::kTH3D, {{200, -12, 12}, centAxisphi, ptAxisphi}}); + histos.add("trkDCAxy", "DCAxy distribution of positive kaon track candidates", HistType::kTH3F, {{150, -1.0f, 1.0f}, centAxisphi, ptAxisphi}); + histos.add("trkDCAz", "DCAxy distribution of negative kaon track candidates", HistType::kTH3F, {{150, -1.0f, 1.0f}, centAxisphi, ptAxisphi}); + registry.add("Factors/hCentralityVsMultMC", "Event centrality vs MC multiplicity", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); + registry.add("Factors/hEventCentrality", "Event centrality", kTH1F, {{101, 0, 101}}); + registry.add("Factors/hNrecInGen", "Number of collisions in MC", kTH1F, {{4, -0.5, 3.5}}); + registry.add("Factors/hGenEvents", "Generated events", HistType::kTH2F, {{axisNch}, {4, 0, 4}}); + auto hGenEvents = registry.get(HIST("Factors/hGenEvents")); + hGenEvents->GetYaxis()->SetBinLabel(1, "All generated events"); + hGenEvents->GetYaxis()->SetBinLabel(2, "Generated events with Mc collision V_{z} cut"); + hGenEvents->GetYaxis()->SetBinLabel(3, "Generated events with at least one reconstructed event"); + registry.add("Factors/h2dGenPhi", "Centrality vs p_{T}", kTH2D, {{101, 0.0f, 101.0f}, ptAxisphi}); + registry.add("Factors/h3dGenPhiVsMultMCVsCentrality", "MC multiplicity vs centrality vs p_{T}", kTH3D, {axisNch, {101, 0.0f, 101.0f}, ptAxisphi}); + 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}); + } } } double massKa = o2::constants::physics::MassKPlus; double rapidity; double genMass, recMass, resolution; + ROOT::Math::PxPyPzMVector phiMother, daughter1, daughter2; + ROOT::Math::PxPyPzMVector d1, d2, mother; double mass{0.}; double massrotation{0.}; double pT{0.}; @@ -136,7 +285,7 @@ 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)) { + if (useGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsCrossedRows() > cfgTPCcluster && candidate.tpcFractionSharedCls() < cfgTPCSharedcluster)) { return false; } return true; @@ -145,14 +294,78 @@ struct phianalysisrun3_PbPb { template bool selectionPID(const T& candidate) { - if (tof && combined && (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 (tpc && combined && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + 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, int pid) + { + if (pid == 0) { + if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmacutTPC) { + return true; + } + if (candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmacutTPC && + std::abs(candidate.tofNSigmaKa()) < nsigmacutTOF) { + return true; + } + return false; + + } else if (pid == 1) { + constexpr double kPtThresholdForTOF = 0.5; + if (candidate.pt() < kPtThresholdForTOF && std::abs(candidate.tpcNSigmaKa()) < nsigmacutTPC) { + return true; + } + if (candidate.pt() >= kPtThresholdForTOF && candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && + std::abs(candidate.tpcNSigmaKa()) < nsigmacutTPC && std::abs(candidate.tofNSigmaKa()) < nsigmacutTOF) { + return true; + } + if (!useGlobalTrack && !candidate.hasTPC()) { + return true; + } + return false; + } return false; } + + template + bool myEventSelections(const CollType& collision) + { + if (std::abs(collision.posZ()) > cfgCutVertex) + return false; + + if (!collision.sel8()) + return false; + + if (additionalEvSel1 && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) + return false; + + if (additionalEvSel2 && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) + return false; + + if (additionalEvSel3 && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return false; + if (additionalEvSel5 && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) + return false; + if (additionalEvSel6 && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) + return false; + + return true; + } + // deep angle cut on pair to remove photon conversion template bool selectionPair(const T1& candidate1, const T2& candidate2) @@ -164,121 +377,165 @@ struct phianalysisrun3_PbPb { pz2 = candidate2.pz(); p1 = candidate1.p(); p2 = candidate2.p(); - angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + angle = std::acos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); if (isDeepAngle && angle < cfgDeepAngle) { return false; } 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}; + pvec0 = std::array{candidate1.px(), candidate1.py(), candidate1.pz()}; + pvec1 = std::array{candidate2.px(), candidate2.py(), candidate2.pz()}; + auto arrMom = std::array, 2>{pvec0, pvec1}; + 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); - } - } + mass = RecoDecay::m(arrMom, std::array{massd1, massd2}); + + pT = RecoDecay::pt(std::array{ + candidate1.px() + candidate2.px(), + candidate1.py() + candidate2.py()}); + + rapidity = RecoDecay::y(std::array{ + candidate1.px() + candidate2.px(), + candidate1.py() + candidate2.py(), + candidate1.pz() + candidate2.pz()}, + mass); + + constexpr int kOppositeCharge = 0; // default filling - if (std::abs(rapidity) < 0.5 && !isEtaAssym && track1Sign * track2Sign < 0) { + if (rapidity > rapiditycut1 && rapidity < rapiditycut2 && track1Sign * track2Sign < kOppositeCharge) { if (unlike) { histos.fill(HIST("h3PhiInvMassUnlikeSign"), multiplicity, pT, mass); + histos.fill(HIST("h2PhiRapidity"), pT, rapidity); } 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); + Filter dcacutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); - using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; + using EventCandidates = soa::Filtered>; + using TrackCandidates = soa::Filtered>; // using EventCandidatesMC = soa::Join; - using EventCandidatesMC = soa::Join; + using EventCandidatesMC = soa::Join; using TrackCandidatesMC = soa::Filtered>; + aod::McTrackLabels, aod::pidTOFbeta>>; + using CollisionMCTrueTable = aod::McCollisions; + using TrackMCTrueTable = aod::McParticles; + using CollisionMCRecTableCentFT0C = soa::SmallGroups>; + using TrackMCRecTable = soa::Join; + using FilTrackMCRecTable = soa::Filtered; + using McCollisionMults = soa::Join; + using LabeledTracks = soa::Join; 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}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {2000, 0, 10000}, "multiplicity for bin"}; - // 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 BinningTypeVertexContributor1 = ColumnBinningPolicy; + using BinningTypeVertexContributor2 = ColumnBinningPolicy; + using BinningTypeVertexContributor3 = ColumnBinningPolicy; + using BinningTypeVertexContributor4 = ColumnBinningPolicy; + ROOT::Math::PxPyPzMVector phiMesonMother, kaonPlus, kaonMinus; void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks, aod::BCs const&) { + histos.fill(HIST("hEvtSelInfo"), 0.5); + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 1.5); if (!collision.sel8()) { return; } - float multiplicity; - if (cfgMultFT0) + histos.fill(HIST("hEvtSelInfo"), 2.5); + if (additionalEvSel1 && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 3.5); + if (additionalEvSel2 && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 4.5); + if (additionalEvSel3 && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 5.5); + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 6.5); + if (additionalEvSel5 && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 7.5); + if (additionalEvSel6 && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 8.5); + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 9.5); + float multiplicity{-1}; + const int kCentFT0C = 0; + const int kCentFT0A = 1; + const int kCentFT0M = 2; + const int kCentFV0A = 3; + + if (centestimator == kCentFT0C) { multiplicity = collision.centFT0C(); - if (!cfgMultFT0) - multiplicity = collision.numContrib(); + } else if (centestimator == kCentFT0A) { + multiplicity = collision.centFT0A(); + } else if (centestimator == kCentFT0M) { + multiplicity = collision.centFT0M(); + } else if (centestimator == kCentFV0A) { + multiplicity = collision.centFV0A(); + } + histos.fill(HIST("hCentrality"), multiplicity); - histos.fill(HIST("hNcontributor"), collision.numContrib()); histos.fill(HIST("hVtxZ"), collision.posZ()); - for (auto track1 : tracks) { + histos.fill(HIST("hOccupancy"), occupancy); + for (const 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()); + int track1Sign = track1.sign(); // or track1.charge(), assuming it returns ±1 + + histos.fill(HIST("hEta"), track1.eta(), track1.pt()); + histos.fill(HIST("hPhi"), track1.phi(), track1.pt()); + if (track1Sign > 0) { // Positive kaon + histos.fill(HIST("QAbefore/TPC_Nsigma_all_pos"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAbefore/TOF_Nsigma_all_pos"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAbefore/trkDCAxy_pos"), track1.dcaXY()); + histos.fill(HIST("QAbefore/trkDCAz_pos"), track1.dcaZ()); + histos.fill(HIST("QAbefore/trkDCAxypt_pos"), track1.dcaXY(), track1.pt()); + histos.fill(HIST("QAbefore/trkDCAzpt_pos"), track1.dcaZ(), track1.pt()); + histos.fill(HIST("QAbefore/TOF_TPC_Mapka_all_pos"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + } else if (track1Sign < 0) { // Negative kaon + histos.fill(HIST("QAbefore/TPC_Nsigma_all_neg"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAbefore/TOF_Nsigma_all_neg"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAbefore/trkDCAxy_neg"), track1.dcaXY()); + histos.fill(HIST("QAbefore/trkDCAz_neg"), track1.dcaZ()); + histos.fill(HIST("QAbefore/trkDCAxypt_neg"), track1.dcaXY(), track1.pt()); + histos.fill(HIST("QAbefore/trkDCAzpt_neg"), track1.dcaZ(), track1.pt()); + histos.fill(HIST("QAbefore/TOF_TPC_Mapka_all_neg"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + } + auto track1ID = track1.globalIndex(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!selectionTrack(track2)) { continue; } @@ -291,44 +548,110 @@ 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)) { + int track1Sign = track1.sign(); // Assuming `charge()` gives +1 or -1 + + if (track1Sign > 0) { // Positive kaon + histos.fill(HIST("QAafter/TPC_Nsigma_all_pos"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/TOF_Nsigma_all_pos"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/trkDCAxy_pos"), track1.dcaXY()); + histos.fill(HIST("QAafter/trkDCAz_pos"), track1.dcaZ()); + histos.fill(HIST("QAafter/trkDCAxypt_pos"), track1.dcaXY(), track1.pt()); + histos.fill(HIST("QAafter/trkDCAzpt_pos"), track1.dcaZ(), track1.pt()); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_all_pos"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + } else if (track1Sign < 0) { // Negative kaon + histos.fill(HIST("QAafter/TPC_Nsigma_all_neg"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/TOF_Nsigma_all_neg"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/trkDCAxy_neg"), track1.dcaXY()); + histos.fill(HIST("QAafter/trkDCAz_neg"), track1.dcaZ()); + histos.fill(HIST("QAafter/trkDCAxypt_neg"), track1.dcaXY(), track1.pt()); + histos.fill(HIST("QAafter/trkDCAzpt_neg"), track1.dcaZ(), track1.pt()); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_all_neg"), 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, 0) || selectionPIDpTdependent(track1, 1)) && + (selectionPIDpTdependent(track2, 0) || selectionPIDpTdependent(track2, 1))) { + int track1Sign = track1.sign(); // Same assumption as above + + if (track1Sign > 0) { // Positive kaon + histos.fill(HIST("QAafter/TPC_Nsigma_all_pos"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/TOF_Nsigma_all_pos"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/trkDCAxy_pos"), track1.dcaXY()); + histos.fill(HIST("QAafter/trkDCAz_pos"), track1.dcaZ()); + histos.fill(HIST("QAafter/trkDCAxypt_pos"), track1.dcaXY(), track1.pt()); + histos.fill(HIST("QAafter/trkDCAzpt_pos"), track1.dcaZ(), track1.pt()); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_all_pos"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + } else if (track1Sign < 0) { // Negative kaon + histos.fill(HIST("QAafter/TPC_Nsigma_all_neg"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/TOF_Nsigma_all_neg"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("QAafter/trkDCAxy_neg"), track1.dcaXY()); + histos.fill(HIST("QAafter/trkDCAz_neg"), track1.dcaZ()); + histos.fill(HIST("QAafter/trkDCAxypt_neg"), track1.dcaXY(), track1.pt()); + histos.fill(HIST("QAafter/trkDCAzpt_neg"), track1.dcaZ(), track1.pt()); + histos.fill(HIST("QAafter/TOF_TPC_Mapka_all_neg"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); + } + + fillinvMass(track1, track2, multiplicity, unlike, mix, massKa, massKa); } } } } PROCESS_SWITCH(phianalysisrun3_PbPb, processSameEvent, "Process Same event", false); - void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + void processMixedEvent1(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) { + BinningTypeVertexContributor1 binningOnPositions{{axisVertex, axisMultiplicity}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + if (rctCut.requireRCTFlagChecker && !rctChecker(c1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctChecker(c2)) { + continue; + } if (!c1.sel8()) { continue; } if (!c2.sel8()) { continue; } + if (additionalEvSel1 && (!c1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c2.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + continue; + } + if (additionalEvSel2 && (!c1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !c2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (additionalEvSel3 && (!c1.selection_bit(aod::evsel::kNoSameBunchPileup) || !c2.selection_bit(aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (additionalEvSel4 && (!c1.selection_bit(aod::evsel::kIsGoodITSLayersAll) || !c2.selection_bit(aod::evsel::kIsGoodITSLayersAll))) { + continue; + } + if (additionalEvSel5 && (!c1.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) || !c2.selection_bit(aod::evsel::kNoCollInTimeRangeStandard))) { + continue; + } + if (additionalEvSel6 && (!c1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !c2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + int occupancy1 = c1.trackOccupancyInTimeRange(); + int occupancy2 = c2.trackOccupancyInTimeRange(); + if (fillOccupancy && + ((occupancy1 < cfgMinOccupancy || occupancy1 > cfgMaxOccupancy) || + (occupancy2 < cfgMinOccupancy || occupancy2 > cfgMaxOccupancy))) { + continue; + } float multiplicity; - if (cfgMultFT0) - multiplicity = c1.centFT0C(); - if (!cfgMultFT0) - multiplicity = c1.numContrib(); - - for (auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + multiplicity = c1.centFT0C(); + for (const 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; } @@ -338,178 +661,1294 @@ 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, 0) || selectionPIDpTdependent(t1, 1)) && + (selectionPIDpTdependent(t2, 0) || selectionPIDpTdependent(t2, 1))) { + fillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); } } } } - - PROCESS_SWITCH(phianalysisrun3_PbPb, processMixedEvent, "Process Mixed event", false); - void processGen(aod::McCollision const& mcCollision, aod::McParticles& mcParticles, const soa::SmallGroups& collisions) + PROCESS_SWITCH(phianalysisrun3_PbPb, processMixedEvent1, "Process Mixed event", false); + void processMixedEvent2(EventCandidates const& collisions, TrackCandidates const& tracks) { - 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; - } + auto tracksTuple = std::make_tuple(tracks); + //////// currently mixing the event with similar TPC multiplicity //////// + BinningTypeVertexContributor2 binningOnPositions{{axisVertex, axisMultiplicity}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + if (rctCut.requireRCTFlagChecker && !rctChecker(c1)) { + continue; } - } - if (Nchinel > 0 && std::abs(mcCollision.posZ()) < cfgCutVertex) - histos.fill(HIST("hMC"), 2.5); - std::vector SelectedEvents(collisions.size()); - int nevts = 0; - auto multiplicity = 0; - for (const auto& collision : collisions) { - if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { + if (rctCut.requireRCTFlagChecker && !rctChecker(c2)) { continue; } - multiplicity = collision.centFT0C(); - histos.fill(HIST("Centgen"), multiplicity); - 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); - for (auto& mcParticle : mcParticles) { - if (std::abs(mcParticle.y()) >= 0.5) { + if (!c1.sel8()) { continue; } - if (mcParticle.pdgCode() != 333) { + if (!c2.sel8()) { continue; } - auto kDaughters = mcParticle.daughters_as(); - if (kDaughters.size() != 2) { + if (additionalEvSel1 && (!c1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c2.selection_bit(aod::evsel::kNoTimeFrameBorder))) { continue; } - auto daughtp = false; - auto daughtm = false; - for (auto kCurrentDaughter : kDaughters) { - if (!kCurrentDaughter.isPhysicalPrimary()) { - continue; - } - if (kCurrentDaughter.pdgCode() == +321) { - daughtp = true; - } else if (kCurrentDaughter.pdgCode() == -321) { - daughtm = true; - } + if (additionalEvSel2 && (!c1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !c2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; } - if (daughtp && daughtm) { - histos.fill(HIST("h1PhiGen"), mcParticle.pt()); - histos.fill(HIST("h2PhiGen2"), mcParticle.pt(), multiplicity); + if (additionalEvSel3 && (!c1.selection_bit(aod::evsel::kNoSameBunchPileup) || !c2.selection_bit(aod::evsel::kNoSameBunchPileup))) { + continue; } - } - } - - PROCESS_SWITCH(phianalysisrun3_PbPb, 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()) { - return; - } - if (std::abs(collision.mcCollision().posZ()) > cfgCutVertex || !collision.sel8()) { - return; - } - auto multiplicity = collision.centFT0C(); - histos.fill(HIST("Centrec"), multiplicity); - histos.fill(HIST("hMC"), 5.5); - auto oldindex = -999; - for (auto track1 : tracks) { - if (!selectionTrack(track1)) { + if (additionalEvSel4 && (!c1.selection_bit(aod::evsel::kIsGoodITSLayersAll) || !c2.selection_bit(aod::evsel::kIsGoodITSLayersAll))) { continue; } - if (!track1.has_mcParticle()) { + if (additionalEvSel5 && (!c1.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) || !c2.selection_bit(aod::evsel::kNoCollInTimeRangeStandard))) { continue; } - auto track1ID = track1.index(); - for (auto track2 : tracks) { - if (!track2.has_mcParticle()) { - continue; - } - if (!selectionTrack(track2)) { - continue; - } - auto track2ID = track2.index(); - if (track2ID <= track1ID) { - continue; - } - if (!selectionPair(track1, track2)) { + if (additionalEvSel6 && (!c1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !c2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + int occupancy1 = c1.trackOccupancyInTimeRange(); + int occupancy2 = c2.trackOccupancyInTimeRange(); + + if (fillOccupancy && + ((occupancy1 < cfgMinOccupancy || occupancy1 > cfgMaxOccupancy) || + (occupancy2 < cfgMinOccupancy || occupancy2 > cfgMaxOccupancy))) { + continue; + } + float multiplicity; + multiplicity = c1.centFT0A(); + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + bool unlike = false; + bool mix = true; + if (!selectionTrack(t1)) { continue; } - if (track1.sign() * track2.sign() > 0) { + if (!selectionTrack(t2)) { continue; } - const auto mctrack1 = track1.mcParticle(); - const auto mctrack2 = track2.mcParticle(); - int track1PDG = std::abs(mctrack1.pdgCode()); - int track2PDG = std::abs(mctrack2.pdgCode()); - if (!mctrack1.isPhysicalPrimary()) { + if (!selectionPair(t1, t2)) { continue; } - if (!mctrack2.isPhysicalPrimary()) { - continue; + if (!ispTdepPID && selectionPID(t1) && selectionPID(t2)) { + fillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); } - if (!(track1PDG == 321 && track2PDG == 321)) { - continue; + if (ispTdepPID && + (selectionPIDpTdependent(t1, 0) || selectionPIDpTdependent(t1, 1)) && + (selectionPIDpTdependent(t2, 0) || selectionPIDpTdependent(t2, 1))) { + fillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); } - for (auto& mothertrack1 : mctrack1.mothers_as()) { - for (auto& mothertrack2 : mctrack2.mothers_as()) { - if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { - continue; - } - if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { - continue; - } - if (!mothertrack1.producedByGenerator()) { - continue; - } - if (std::abs(mothertrack1.y()) >= 0.5) { - continue; - } - if (std::abs(mothertrack1.pdgCode()) != 333) { - continue; - } - if (!isITSOnlycut && !(selectionPID(track1) && selectionPID(track2))) { + } + } + } + + PROCESS_SWITCH(phianalysisrun3_PbPb, processMixedEvent2, "Process Mixed event", false); + void processMixedEvent3(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + //////// currently mixing the event with similar TPC multiplicity //////// + BinningTypeVertexContributor3 binningOnPositions{{axisVertex, axisMultiplicity}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + if (rctCut.requireRCTFlagChecker && !rctChecker(c1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctChecker(c2)) { + continue; + } + if (!c1.sel8()) { + continue; + } + if (!c2.sel8()) { + continue; + } + if (additionalEvSel1 && (!c1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c2.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + continue; + } + if (additionalEvSel2 && (!c1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !c2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (additionalEvSel3 && (!c1.selection_bit(aod::evsel::kNoSameBunchPileup) || !c2.selection_bit(aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (additionalEvSel4 && (!c1.selection_bit(aod::evsel::kIsGoodITSLayersAll) || !c2.selection_bit(aod::evsel::kIsGoodITSLayersAll))) { + continue; + } + if (additionalEvSel5 && (!c1.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) || !c2.selection_bit(aod::evsel::kNoCollInTimeRangeStandard))) { + continue; + } + if (additionalEvSel6 && (!c1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !c2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + int occupancy1 = c1.trackOccupancyInTimeRange(); + int occupancy2 = c2.trackOccupancyInTimeRange(); + + if (fillOccupancy && + ((occupancy1 < cfgMinOccupancy || occupancy1 > cfgMaxOccupancy) || + (occupancy2 < cfgMinOccupancy || occupancy2 > cfgMaxOccupancy))) { + continue; + } + float multiplicity; + multiplicity = c1.centFT0M(); + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + bool unlike = false; + bool mix = true; + if (!selectionTrack(t1)) { + continue; + } + if (!selectionTrack(t2)) { + continue; + } + if (!selectionPair(t1, t2)) { + continue; + } + if (!ispTdepPID && selectionPID(t1) && selectionPID(t2)) { + fillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); + } + if (ispTdepPID && + (selectionPIDpTdependent(t1, 0) || selectionPIDpTdependent(t1, 1)) && + (selectionPIDpTdependent(t2, 0) || selectionPIDpTdependent(t2, 1))) { + fillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); + } + } + } + } + + PROCESS_SWITCH(phianalysisrun3_PbPb, processMixedEvent3, "Process Mixed event", false); + void processMixedEvent4(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + //////// currently mixing the event with similar TPC multiplicity //////// + BinningTypeVertexContributor4 binningOnPositions{{axisVertex, axisMultiplicity}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + if (rctCut.requireRCTFlagChecker && !rctChecker(c1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctChecker(c2)) { + continue; + } + if (!c1.sel8()) { + continue; + } + if (!c2.sel8()) { + continue; + } + if (additionalEvSel1 && (!c1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c2.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + continue; + } + if (additionalEvSel2 && (!c1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !c2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (additionalEvSel3 && (!c1.selection_bit(aod::evsel::kNoSameBunchPileup) || !c2.selection_bit(aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (additionalEvSel4 && (!c1.selection_bit(aod::evsel::kIsGoodITSLayersAll) || !c2.selection_bit(aod::evsel::kIsGoodITSLayersAll))) { + continue; + } + if (additionalEvSel5 && (!c1.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) || !c2.selection_bit(aod::evsel::kNoCollInTimeRangeStandard))) { + continue; + } + if (additionalEvSel6 && (!c1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !c2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + int occupancy1 = c1.trackOccupancyInTimeRange(); + int occupancy2 = c2.trackOccupancyInTimeRange(); + + if (fillOccupancy && + ((occupancy1 < cfgMinOccupancy || occupancy1 > cfgMaxOccupancy) || + (occupancy2 < cfgMinOccupancy || occupancy2 > cfgMaxOccupancy))) { + continue; + } + float multiplicity; + multiplicity = c1.centFV0A(); + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + bool unlike = false; + bool mix = true; + if (!selectionTrack(t1)) { + continue; + } + if (!selectionTrack(t2)) { + continue; + } + if (!selectionPair(t1, t2)) { + continue; + } + if (!ispTdepPID && selectionPID(t1) && selectionPID(t2)) { + fillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); + } + if (ispTdepPID && + (selectionPIDpTdependent(t1, 0) || selectionPIDpTdependent(t1, 1)) && + (selectionPIDpTdependent(t2, 0) || selectionPIDpTdependent(t2, 1))) { + fillinvMass(t1, t2, multiplicity, unlike, mix, massKa, massKa); + } + } + } + } + + PROCESS_SWITCH(phianalysisrun3_PbPb, processMixedEvent4, "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 < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) { + 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 (const 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 (const 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, 0) || selectionPIDpTdependent(track1, 1)) && + (selectionPIDpTdependent(track2, 0) || selectionPIDpTdependent(track2, 1))) { + 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 (std::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 (std::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 (const auto& RecCollision : RecCollisions) { + histos.fill(HIST("hMC"), 3); + if (cfgDoSel8 && !RecCollision.sel8()) { + continue; + } + if (std::abs(RecCollision.posZ()) > cfgCutVertex) { + continue; + } + + histos.fill(HIST("hMC"), 4); + if (additionalEvSel1 && !RecCollision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + continue; + } + histos.fill(HIST("hMC"), 5); + if (additionalEvSel2 && !RecCollision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + continue; + } + histos.fill(HIST("hMC"), 6); + if (additionalEvSel3 && !RecCollision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + histos.fill(HIST("hMC"), 7); + if (additionalEvSel4 && !RecCollision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + histos.fill(HIST("hMC"), 8); + if (additionalEvSel5 && !RecCollision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + histos.fill(HIST("hMC"), 9); + if (additionalEvSel6 && !RecCollision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + continue; + } + histos.fill(HIST("hMC"), 10); + int occupancy = RecCollision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) { + continue; + } + histos.fill(HIST("hMC"), 11); + const int kCentFT0C = 0; + const int kCentFT0A = 1; + const int kCentFT0M = 2; + const int kCentFV0A = 3; + auto centrality = -1.0; + if (centestimator == kCentFT0C) { + centrality = RecCollision.centFT0C(); + } else if (centestimator == kCentFT0A) { + centrality = RecCollision.centFT0A(); + } else if (centestimator == kCentFT0M) { + centrality = RecCollision.centFT0M(); + } else if (centestimator == kCentFV0A) { + centrality = RecCollision.centFV0A(); + } + histos.fill(HIST("Centmc"), centrality); + auto oldindex = -999; + auto rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + // loop over reconstructed particle + for (const auto& track1 : rectrackspart) { + if (!selectionTrack(track1)) { + continue; + } + if (!ispTdepPID && !selectionPID(track1)) { + continue; + } + if (ispTdepPID && !(selectionPIDpTdependent(track1, 0) || selectionPIDpTdependent(track1, 1))) { + + continue; + } + if (!track1.has_mcParticle()) { + continue; + } + auto track1ID = track1.index(); + for (const auto& track2 : rectrackspart) { + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + if (!ispTdepPID && !selectionPID(track2)) { + continue; + } + if (ispTdepPID && !(selectionPIDpTdependent(track2, 0) || selectionPIDpTdependent(track2, 1))) { + + 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(); + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + if (!mctrack2.isPhysicalPrimary()) { + 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 (std::abs(phiMesonMother.Rapidity()) > confRapidity) { + continue; + } + histos.fill(HIST("h3PhiInvMassSameMC1"), centrality, phiMesonMother.pt(), phiMesonMother.M()); + int track1PDG = std::abs(mctrack1.pdgCode()); + int track2PDG = std::abs(mctrack2.pdgCode()); + if (!(track1PDG == PDG_t::kKPlus && track2PDG == PDG_t::kKPlus)) { + continue; + } + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + if (mothertrack1 != mothertrack2) { + continue; + } + if (pdgcheck && std::abs(mothertrack1.pdgCode()) != o2::constants::physics::kPhi) { + continue; + } + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + histos.fill(HIST("h1PhiRecsplit"), mothertrack1.pt()); + continue; + } + oldindex = mothertrack1.globalIndex(); + 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 (std::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); + histos.fill(HIST("hVtxZrec"), RecCollision.posZ()); + } + } + } + } + // loop over generated particle + for (const auto& mcParticle : GenParticles) { + if (std::abs(mcParticle.y()) > confRapidity) { + continue; + } + if (pdgcheck && mcParticle.pdgCode() != o2::constants::physics::kPhi) { + continue; + } + auto kDaughters = mcParticle.daughters_as(); + const size_t kExpectedDaughterCount = 2; + + if (kDaughters.size() != kExpectedDaughterCount) { + + continue; + } + auto daughtp = false; + auto daughtm = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + if (kCurrentDaughter.pdgCode() == PDG_t::kKPlus) { + if (genacceptancecut && kCurrentDaughter.pt() > cfgCutPT && std::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() == PDG_t::kKMinus) { + if (genacceptancecut && kCurrentDaughter.pt() > cfgCutPT && std::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); + } + float imp = mcCollision.impactParameter(); + histos.fill(HIST("hImpactParameterGen"), imp); + std::vector selectedEvents(collisions.size()); + int nevts = 0; + auto multiplicity = 0; + for (const auto& collision : collisions) { + if (cfgDoSel8 && !collision.sel8()) { + continue; + } + if (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 < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) { + continue; + } + histos.fill(HIST("hOccupancy1"), occupancy); + multiplicity = collision.centFT0C(); + histos.fill(HIST("Centgen"), multiplicity); + histos.fill(HIST("hVtxZgen"), collision.mcCollision().posZ()); + 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(); + 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("ES1"), imp); + histos.fill(HIST("ES2"), multiplicity); + for (const auto& mcParticle : mcParticles) { + const double kMaxAcceptedRapidity = 0.5; + + if (std::abs(mcParticle.y()) >= kMaxAcceptedRapidity) { + + continue; + } + if (pdgcheck && mcParticle.pdgCode() != o2::constants::physics::kPhi) { + continue; + } + auto kDaughters = mcParticle.daughters_as(); + const size_t kExpectedNumberOfDaughters = 2; + + if (kDaughters.size() != kExpectedNumberOfDaughters) { + + continue; + } + auto daughtp = false; + auto daughtm = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + if (kCurrentDaughter.pdgCode() == PDG_t::kKPlus) { + daughtp = true; + kaonPlus = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), massKa); + } else if (kCurrentDaughter.pdgCode() == PDG_t::kKMinus) { + 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(), 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& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + { + if (!collision.has_mcCollision()) { + return; + } + if (cfgDoSel8 && !collision.sel8()) { + return; + } + if (std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { + return; + } + + if (additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) { + return; + } + auto multiplicity = collision.centFT0C(); + histos.fill(HIST("Centrec"), multiplicity); + histos.fill(HIST("hVtxZrec"), collision.posZ()); + 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 (const auto& track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + if (!track1.has_mcParticle()) { + continue; + } + auto track1ID = track1.index(); + for (const auto& track2 : tracks) { + if (!track2.has_mcParticle()) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + 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 = std::abs(mctrack1.pdgCode()); + int track2PDG = std::abs(mctrack2.pdgCode()); + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + if (!mctrack2.isPhysicalPrimary()) { + continue; + } + if (!(track1PDG == PDG_t::kKPlus && track2PDG == PDG_t::kKPlus)) { + 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 (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { + continue; + } + if (!mothertrack1.producedByGenerator()) { + continue; + } + const double kMaxRapidityCut = 0.5; + + if (std::abs(mothertrack1.y()) >= kMaxRapidityCut) { + continue; + } + + if (pdgcheck && std::abs(mothertrack1.pdgCode()) != o2::constants::physics::kPhi) { + continue; + } + if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + continue; + } + if (ispTdepPID && + (selectionPIDpTdependent(track1, 0) || selectionPIDpTdependent(track1, 1)) && + (selectionPIDpTdependent(track2, 0) || selectionPIDpTdependent(track2, 1))) { + + continue; + } + + 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; + + if (std::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()); + } + } + } + } + } + + 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 (additionalEvSel1 && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return; + } + if (additionalEvSel2 && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + if (additionalEvSel3 && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return; + } + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + if (additionalEvSel5 && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + if (additionalEvSel6 && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) { + return; + } + float multiplicity{-1}; + multiplicity = collision.centFT0C(); + histos.fill(HIST("Centsame"), multiplicity); + for (const auto& track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + if (!ispTdepPID && !selectionPID(track1)) { + continue; + } + if (ispTdepPID && !(selectionPIDpTdependent(track1, 0) || selectionPIDpTdependent(track1, 1))) { + + continue; + } + if (!track1.has_mcParticle()) { + continue; + } + auto track1ID = track1.index(); + for (const auto& track2 : tracks) { + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + if (!ispTdepPID && !selectionPID(track2)) { + continue; + } + if (ispTdepPID && !(selectionPIDpTdependent(track2, 0) || selectionPIDpTdependent(track2, 1))) { + + 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(); + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + if (!mctrack2.isPhysicalPrimary()) { + 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 (std::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 (std::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); + BinningTypeVertexContributor1 binningOnPositions{{axisVertex, axisMultiplicity}, true}; + SameKindPair pairs{binningOnPositions, cfgNoMixedEvents, -1, recCollisions, tracksTuple, &cache}; + + for (const auto& [c1, tracks1, c2, tracks2] : pairs) { + if (!c1.sel8()) { + continue; + } + if (!c2.sel8()) { + continue; + } + if (additionalEvSel1 && (!c1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !c2.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + continue; + } + if (additionalEvSel2 && (!c1.selection_bit(aod::evsel::kNoITSROFrameBorder) || !c2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (additionalEvSel3 && (!c1.selection_bit(aod::evsel::kNoSameBunchPileup) || !c2.selection_bit(aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (additionalEvSel4 && (!c1.selection_bit(aod::evsel::kIsGoodITSLayersAll) || !c2.selection_bit(aod::evsel::kIsGoodITSLayersAll))) { + continue; + } + if (additionalEvSel5 && (!c1.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) || !c2.selection_bit(aod::evsel::kNoCollInTimeRangeStandard))) { + continue; + } + if (additionalEvSel6 && (!c1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !c2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + int occupancy1 = c1.trackOccupancyInTimeRange(); + int occupancy2 = c2.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy1 < cfgMinOccupancy || occupancy1 > cfgMaxOccupancy)) { + continue; + } + if (fillOccupancy && (occupancy2 < cfgMinOccupancy || occupancy2 > cfgMaxOccupancy)) { + continue; + } + + auto multiplicity = c1.centFT0C(); + histos.fill(HIST("Centmix"), multiplicity); + for (const auto& [t1, t2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (!selectionTrack(t1)) { + continue; + } + if (!selectionTrack(t2)) { + continue; + } + if (!selectionPair(t1, t2)) { + continue; + } + if (!ispTdepPID && (!selectionPID(t1) || !selectionPID(t2))) { + continue; + } + if (ispTdepPID && + (selectionPIDpTdependent(t1, 0) || selectionPIDpTdependent(t1, 1)) && + (selectionPIDpTdependent(t2, 0) || selectionPIDpTdependent(t2, 1))) { + + continue; + } + if (!t1.has_mcParticle() || !t2.has_mcParticle()) { + continue; + } + const auto mctrack1 = t1.mcParticle(); + const auto mctrack2 = t2.mcParticle(); + + if (!mctrack1.isPhysicalPrimary() || !mctrack2.isPhysicalPrimary()) { + 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 (std::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 processGen1(aod::McCollision const& mcCollision, aod::McParticles& mcParticles, const soa::SmallGroups& collisions) + { + histos.fill(HIST("hMC1"), 0.5); + if (std::abs(mcCollision.posZ()) < cfgCutVertex) { + histos.fill(HIST("hMC1"), 1.5); + } + std::vector selectedEvents(collisions.size()); + int nevts = 0; + auto multiplicity = -1.0; + for (const auto& collision : collisions) { + histos.fill(HIST("hMC1"), 2.5); + if (cfgDoSel8 && !collision.sel8()) { + continue; + } + if (std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { + continue; + } + + histos.fill(HIST("hMC1"), 3.5); + if (additionalEvSel1 && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + continue; + } + histos.fill(HIST("hMC1"), 4.5); + if (additionalEvSel2 && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + continue; + } + histos.fill(HIST("hMC1"), 5.5); + if (additionalEvSel3 && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + histos.fill(HIST("hMC1"), 6.5); + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + histos.fill(HIST("hMC1"), 7.5); + if (additionalEvSel5 && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + histos.fill(HIST("hMC1"), 8.5); + if (additionalEvSel6 && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + continue; + } + histos.fill(HIST("hMC1"), 9.5); + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) { + continue; + } + histos.fill(HIST("hMC1"), 10.5); + const int kCentFT0C = 0; + const int kCentFT0A = 1; + const int kCentFT0M = 2; + const int kCentFV0A = 3; + + if (centestimator == kCentFT0C) { + multiplicity = collision.centFT0C(); + } else if (centestimator == kCentFT0A) { + multiplicity = collision.centFT0A(); + } else if (centestimator == kCentFT0M) { + multiplicity = collision.centFT0M(); + } else if (centestimator == kCentFV0A) { + multiplicity = collision.centFV0A(); + } + histos.fill(HIST("Centgen1"), multiplicity); + 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("hMC1"), 11.5); + if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection + return; + } + histos.fill(HIST("hMC1"), 12.5); + for (const auto& mcParticle : mcParticles) { + + if (mcParticle.y() < rapiditycut1 || mcParticle.y() > rapiditycut2) { + continue; + } + + if (mcParticle.pdgCode() != o2::constants::physics::kPhi) { + continue; + } + auto kDaughters = mcParticle.daughters_as(); + const size_t kExpectedNumberOfDaughters = 2; + + if (kDaughters.size() != kExpectedNumberOfDaughters) { + + continue; + } + auto daughtp = false; + auto daughtm = false; + for (const auto& kCurrentDaughter : kDaughters) { + if (!kCurrentDaughter.isPhysicalPrimary()) { + continue; + } + if (kCurrentDaughter.pdgCode() == PDG_t::kKPlus) { + daughtp = true; + } else if (kCurrentDaughter.pdgCode() == PDG_t::kKMinus) { + daughtm = true; + } + } + if (daughtp && daughtm) { + histos.fill(HIST("h1PhifinalGen"), mcParticle.pt()); + histos.fill(HIST("h2PhifinalGen"), mcParticle.pt(), multiplicity); + } + } + } + + PROCESS_SWITCH(phianalysisrun3_PbPb, processGen1, "Process Generated", false); + void processRec1(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + { + if (!collision.has_mcCollision()) { + return; + } + if (cfgDoSel8 && !collision.sel8()) { + return; + } + if (std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { + return; + } + if (additionalEvSel1 && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return; + } + + if (additionalEvSel2 && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return; + } + + if (additionalEvSel3 && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return; + } + + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + if (additionalEvSel5 && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + if (additionalEvSel6 && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + int occupancy = collision.trackOccupancyInTimeRange(); + if (fillOccupancy && (occupancy < cfgMinOccupancy || occupancy > cfgMaxOccupancy)) { + return; + } + const int kCentFT0C = 0; + const int kCentFT0A = 1; + const int kCentFT0M = 2; + const int kCentFV0A = 3; + auto multiplicity = -1.0; + if (centestimator == kCentFT0C) { + multiplicity = collision.centFT0C(); + } else if (centestimator == kCentFT0A) { + multiplicity = collision.centFT0A(); + } else if (centestimator == kCentFT0M) { + multiplicity = collision.centFT0M(); + } else if (centestimator == kCentFV0A) { + multiplicity = collision.centFV0A(); + } + histos.fill(HIST("Centrec1"), multiplicity); + histos.fill(HIST("hMC1"), 13.5); + auto oldindex = -999; + for (const auto& track1 : tracks) { + if (!selectionTrack(track1)) { + continue; + } + if (!track1.has_mcParticle()) { + continue; + } + auto track1ID = track1.index(); + for (const auto& track2 : tracks) { + if (!track2.has_mcParticle()) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + 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 = std::abs(mctrack1.pdgCode()); + int track2PDG = std::abs(mctrack2.pdgCode()); + if (!mctrack1.isPhysicalPrimary()) { + continue; + } + if (!mctrack2.isPhysicalPrimary()) { + continue; + } + if (!(track1PDG == PDG_t::kKPlus && track2PDG == PDG_t::kKPlus)) { + continue; + } + for (const auto& mothertrack1 : mctrack1.mothers_as()) { + for (const auto& mothertrack2 : mctrack2.mothers_as()) { + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { + continue; + } + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { + continue; + } + if (!mothertrack1.producedByGenerator()) { + continue; + } + if (mothertrack1.y() < rapiditycut1 || mothertrack1.y() > rapiditycut2) { + continue; + } + if (std::abs(mothertrack1.pdgCode()) != o2::constants::physics::kPhi) { continue; } + if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + continue; + } + if (ispTdepPID && + (selectionPIDpTdependent(track1, 0) || selectionPIDpTdependent(track1, 1)) && + (selectionPIDpTdependent(track2, 0) || selectionPIDpTdependent(track2, 1))) { + + continue; + } + histos.fill(HIST("TPC_Nsigma1_MC"), track1.tpcNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("TOF_Nsigma1_MC"), track1.tofNSigmaKa(), multiplicity, track1.pt()); + histos.fill(HIST("trkDCAxy"), track1.dcaXY(), multiplicity, track1.pt()); + histos.fill(HIST("trkDCAz"), track1.dcaZ(), multiplicity, track1.pt()); if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { - histos.fill(HIST("h1PhiRecsplit"), mothertrack1.pt()); + histos.fill(HIST("h1PhiRecsplit1"), 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}; + std::array pvec0 = {track1.px(), track1.py(), track1.pz()}; + std::array pvec1 = {track2.px(), track2.py(), track2.pz()}; + std::array, 2> arrMomrec = {pvec0, pvec1}; + auto motherP = mothertrack1.p(); auto motherE = mothertrack1.e(); genMass = std::sqrt(motherE * motherE - motherP * motherP); - recMass = RecoDecay::m(arrMomrec, array{massKa, massKa}); - auto recpt = TMath::Sqrt((track1.px() + track2.px()) * (track1.px() + track2.px()) + (track1.py() + track2.py()) * (track1.py() + track2.py())); - histos.fill(HIST("h1PhiRec1"), mothertrack1.pt()); - histos.fill(HIST("h2PhiRec2"), mothertrack1.pt(), multiplicity); - histos.fill(HIST("h1Phimassgen"), genMass); - histos.fill(HIST("h1Phimassrec"), recMass); - histos.fill(HIST("h1Phipt"), recpt); + recMass = RecoDecay::m(arrMomrec, std::array{massKa, massKa}); + + histos.fill(HIST("h1PhifinalRec"), mothertrack1.pt()); + histos.fill(HIST("h3PhifinalRec"), mothertrack1.pt(), multiplicity, recMass); + histos.fill(HIST("h1Phifinalgenmass"), genMass); } } } } } - PROCESS_SWITCH(phianalysisrun3_PbPb, processRec, "Process Reconstructed", false); + PROCESS_SWITCH(phianalysisrun3_PbPb, processRec1, "Process Reconstructed", 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.; + 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) { + const double kMaxRapidity = 0.5; + + if (std::abs(mcPart.y()) >= kMaxRapidity || std::abs(mcPart.pdgCode()) != o2::constants::physics::kPhi) + + 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); + void processFactors(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) + { + registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 0.5); + + if (std::abs(mcCollision.posZ()) > cfgCutVertex) + return; + + registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 1.5); + + float centrality = 100.5f; + for (auto const& collision : collisions) { + centrality = collision.centFT0M(); + } + + registry.fill(HIST("Factors/hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta08()); + registry.fill(HIST("Factors/hNrecInGen"), collisions.size()); + + for (const auto& particle : mcParticles) { + + if (std::abs(particle.y()) > 0.5) + continue; + + if (particle.pdgCode() == 333) { + int dauSize = 2; + auto daughters = particle.daughters_as(); + if (daughters.size() != dauSize) + continue; + + auto daup = false; + auto daun = false; + + for (const auto& dau : daughters) { + if (dau.pdgCode() == 321) { + daup = true; + d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massKa); + } else if (dau.pdgCode() == -321) { + daun = true; + d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massKa); + } + } + if (!daup || !daun) + continue; + + mother = d1 + d2; + + registry.fill(HIST("Factors/h2dGenPhi"), centrality, mother.Pt()); + registry.fill(HIST("Factors/h3dGenPhiVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta08(), centrality, mother.Pt()); + } + } + + if (collisions.size() == 0) + return; + + registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 2.5); + } + PROCESS_SWITCH(phianalysisrun3_PbPb, processFactors, "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 5ba8198e1da..2468059b1de 100644 --- a/PWGLF/Tasks/Resonances/phipbpb.cxx +++ b/PWGLF/Tasks/Resonances/phipbpb.cxx @@ -11,47 +11,56 @@ // Phi meson spin alignment task // sourav.kundu@cern.ch -#include +#include "PWGLF/DataModel/EPCalibrationTables.h" +#include "PWGLF/DataModel/SPCalibrationTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#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/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include #include +#include +#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 "CCDB/BasicCCDBManager.h" +#include +#include using namespace o2; using namespace o2::framework; @@ -62,57 +71,81 @@ 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 additionalEvSel2{"additionalEvSel2", true, "Additional evsel2"}; - Configurable additionalEvSel3{"additionalEvSel3", false, "Additional evsel3"}; + Configurable cqvas{"cqvas", false, "change q vectors after shift correction"}; + Configurable fillv1{"fillv1", false, "flag to fill v1 histograms"}; + Configurable fillLOCC{"fillLOCC", false, "flag to fill LOCC histograms"}; + 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 fillRapidity{"fillRapidity", false, "fill rapidity bin"}; 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})"}; - ConfigurableAxis configThnAxisPt{"configThnAxisPt", {100, 0.0, 10.}, "#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", {200, -1, 1}, "V2"}; - ConfigurableAxis configThnAxisSP{"configThnAxisSP", {400, -4, 4}, "SP"}; - 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"}; + struct : ConfigurableGroup { + 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})"}; + 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, -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"}; + } cnfgaxis; + 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"}; + 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"}; + 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); @@ -120,14 +153,15 @@ struct phipbpb { Filter PIDcutFilter = nabs(aod::pidtpc::tpcNSigmaKa) < nsigmaCutTPC; using EventCandidates = soa::Filtered>; - using TrackCandidates = soa::Filtered>; + using EventCandidatesv1 = 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; @@ -146,123 +180,188 @@ 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.0, 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 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"}; + std::vector occupancyBinning = {-0.5, 500.0, 1000.0, 1500.0, 2000.0, 3000.0, 4000.0, 5000.0, 50000.0}; + const AxisSpec thnAxisInvMass{cnfgaxis.configThnAxisInvMass, "#it{M} (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{cnfgaxis.configThnAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisCosThetaStar{cnfgaxis.configThnAxisCosThetaStar, "cos(#vartheta_{OP})"}; + const AxisSpec thnAxisCentrality{cnfgaxis.configThnAxisCentrality, "Centrality (%)"}; + const AxisSpec thnAxisV2{cnfgaxis.configThnAxisV2, "V2"}; + const AxisSpec thnAxisRapidity{cnfgaxis.configThnAxisRapidity, "Rapidity"}; + const AxisSpec thnAxisSA{cnfgaxis.configThnAxisSA, "SA"}; + 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 = {2000, -10, 10, "Res"}; + AxisSpec resAxis = {6000, -30, 30, "Res"}; + AxisSpec resAxisSquare = {800, -1, 1, "Res"}; AxisSpec centAxis = {8, 0, 80, "V0M (%)"}; AxisSpec occupancyAxis = {occupancyBinning, "Occupancy"}; + AxisSpec spAxis = {spNbins, lbinsp, hbinsp, "Sp"}; + + if (fillv1) { + histos.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + histos.add("hpQytQypvscent", "hpQytQypvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + histos.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + histos.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + + histos.add("hpQxpvscent", "hpQxpvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + histos.add("hpQxtvscent", "hpQxtvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + histos.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + histos.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {cnfgaxis.configThnAxisCentrality, spAxis}, true); + + histos.add("hpoddvscentpteta", "hpoddvscentpteta", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxyQxypvscentpteta", "hpuxyQxypvscentpteta", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxyQxytvscentpteta", "hpuxyQxytvscentpteta", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxvscentpteta", "hpuxvscentpteta", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuyvscentpteta", "hpuyvscentpteta", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpoddvscentptetamixacc", "hpoddvscentptetamixacc", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxyQxypvscentptetamixacc", "hpuxyQxypvscentptetamixacc", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxyQxytvscentptetamixacc", "hpuxyQxytvscentptetamixacc", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxvscentptetamixacc", "hpuxvscentptetamixacc", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuyvscentptetamixacc", "hpuyvscentptetamixacc", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpoddvscentptetamixopti", "hpoddvscentptetamixopti", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxyQxypvscentptetamixopti", "hpuxyQxypvscentptetamixopti", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxyQxytvscentptetamixopti", "hpuxyQxytvscentptetamixopti", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuxvscentptetamixopti", "hpuxvscentptetamixopti", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + histos.add("hpuyvscentptetamixopti", "hpuyvscentptetamixopti", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisCentrality, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisRapidity, spAxis}, true); + } - 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}}); - 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("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}}); - 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}); - 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, occupancyAxis}); - histos.add("hSparseV2SAMixedEvent_SP", "hSparseV2SAMixedEvent_SP", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisSP, thnAxisCentrality, occupancyAxis}); - } - 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}); - } - // histogram for resolution - 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("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}); - - // 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}); + + if (!fillv1) { + + histos.add("hKaonpIsotropic", "hKaonpIsotropic", HistType::kTHnSparseD, {{8, 0.0, 80.0}, {100, 0.0, 10.0}, {8, -0.8, 0.8}, {36, 0.0, TMath::Pi()}}); + histos.add("hKaonpData", "hKaonpData", HistType::kTHnSparseD, {{8, 0.0, 80.0}, {100, 0.0, 10.0}, {8, -0.8, 0.8}, {36, 0.0, TMath::Pi()}}); + histos.add("hKaonmIsotropic", "hKaonmIsotropic", HistType::kTHnSparseD, {{8, 0.0, 80.0}, {100, 0.0, 10.0}, {8, -0.8, 0.8}, {36, 0.0, TMath::Pi()}}); + histos.add("hKaonmData", "hKaonmData", HistType::kTHnSparseD, {{8, 0.0, 80.0}, {100, 0.0, 10.0}, {8, -0.8, 0.8}, {36, 0.0, TMath::Pi()}}); + + 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}}); + histos.add("hFTOCvsTPCSelected", "Mult correlation FT0C vs. TPC after selection", kTH2F, {{80, 0.0f, 80.0f}, {100, -0.5f, 5999.5f}}); + 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", 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("hSparseV2MixEPAngleCosDeltaPhi", "hSparseV2MixEPAngleCosDeltaPhi", 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", 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}}); + + 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 @@ -278,6 +377,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; @@ -307,10 +412,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; @@ -321,7 +429,7 @@ struct phipbpb { if (candidate.pt() < 0.5 && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { return true; } - if (candidate.pt() >= 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()) { @@ -332,13 +440,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; @@ -389,41 +503,56 @@ struct phipbpb { { const auto pglobal = track.p(); const auto ptpc = track.tpcInnerParam(); - if (std::abs(pglobal - ptpc) > ConfFakeKaonCut) { + if (TMath::Abs(pglobal - ptpc) > ConfFakeKaonCut) { return true; } return false; } + void fillHisoWithTGenPS(const ROOT::Math::PxPyPzMVector& Pphi_lab, double psi2, double ptMin, double etaMax, double centrality) + { + TLorentzVector parent; + double masses[2] = {0.493, 0.493}; + parent.SetPxPyPzE(Pphi_lab.Px(), Pphi_lab.Py(), Pphi_lab.Pz(), Pphi_lab.E()); + TGenPhaseSpace gen; + gen.SetDecay(parent, 2, masses); + gen.Generate(); + + TLorentzVector* K1 = gen.GetDecay(0); + TLorentzVector* K2 = gen.GetDecay(1); + + if (K1->Pt() > ptMin && std::abs(K1->Eta()) < etaMax) + histos.fill(HIST("hKaonpIsotropic"), centrality, K1->Pt(), K1->Eta(), GetPhiInRange(K1->Phi() - psi2)); + if (K2->Pt() > ptMin && std::abs(K2->Eta()) < etaMax) + histos.fill(HIST("hKaonmIsotropic"), centrality, K2->Pt(), K2->Eta(), GetPhiInRange(K2->Phi() - psi2)); + } + 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.0, 40000.0}, "occupancy axis"}; + ConfigurableAxis axisSPAngle{"axisSPAngle", {6, -TMath::Pi(), TMath::Pi()}, "spectator plane angle"}; + ConfigurableAxis axisOccup{"axisOccup", {20, -0.5, 40000.0}, "occupancy axis"}; - using BinningTypeVertexContributor = ColumnBinningPolicy; + // using BinningTypeVertexContributor = ColumnBinningPolicy; + using BinningTypeVertexContributor = ColumnBinningPolicy; + using BinningTypeVertexContributorv1 = 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; - } - 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; - } auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto psiFT0C = collision.psiFT0C(); @@ -437,8 +566,15 @@ struct phipbpb { 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); @@ -455,6 +591,20 @@ struct phipbpb { 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))); @@ -462,19 +612,43 @@ struct phipbpb { 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); @@ -483,17 +657,33 @@ struct phipbpb { 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 && !isTOFOnly && !selectionPID(track2)) { continue; } - if (!ispTdepPID && !selectionPID(track2)) { + if (isTOFOnly && !selectionPID2(track2)) { continue; } auto track2ID = track2.globalIndex(); @@ -512,107 +702,203 @@ struct phipbpb { if (removefaketrak && isFakeKaon(track2)) { continue; } + if (useGlobalTrack && track2.p() < 1.0 && !(itsResponse.nSigmaITS(track2) > -2.5 && itsResponse.nSigmaITS(track2) < 2.5)) { + 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; - 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, occupancy); + 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("hKaonpData"), centrality, KaonPlus.Pt(), KaonPlus.Eta(), GetPhiInRange(KaonPlus.Phi() - psiFT0C)); + histos.fill(HIST("hKaonmData"), centrality, KaonMinus.Pt(), KaonMinus.Eta(), GetPhiInRange(KaonMinus.Phi() - psiFT0C)); + fillHisoWithTGenPS(PhiMesonMother, psiFT0C, cfgCutPT, cfgCutEta, 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 (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 (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, processSameEvent, "Process Same event", true); - void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& /*tracks*/) + + void processSameEventv1(EventCandidatesv1::iterator const& collision, TrackCandidates const& /*tracks, aod::BCs const&*/, aod::BCsWithTimestamps const&) { - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisOccup}, 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); + if (!collision.sel8() || !collision.triggereventsp() || !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return; + } + auto centrality = collision.centFT0C(); + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + int occupancy = collision.trackOccupancyInTimeRange(); + o2::aod::ITSResponse itsResponse; + if (occupancy > cfgCutOccupancy) { + return; + } + if (additionalEvsel && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + if (additionalEvselITS && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hVtxZ"), collision.posZ()); + + 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 QxtQxp = modqxZDCA * modqxZDCC; + auto QytQyp = modqyZDCA * modqyZDCC; + auto Qxytp = QxtQxp + QytQyp; + auto QxpQyt = modqxZDCA * modqyZDCC; + auto QxtQyp = modqxZDCC * modqyZDCA; + + if (fillv1) { + 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); + } + + int Npostrack = 0; + for (auto track1 : posThisColl) { + // track selection + if (!selectionTrack(track1)) { continue; } - if (additionalEvSel2 && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + // PID check + if (ispTdepPID && !isTOFOnly && !selectionPIDpTdependent(track1)) { continue; } - if (additionalEvSel2 && (!collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + if (!ispTdepPID && !isTOFOnly && !selectionPID(track1)) { continue; } - int occupancy = collision1.trackOccupancyInTimeRange(); - 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); + if (isTOFOnly && !selectionPID2(track1)) { continue; } - if (additionalEvsel && !eventSelected(collision2, centrality2)) { - // printf("Mix = %d\n", 5); + if (useGlobalTrack && track1.p() < 1.0 && !(itsResponse.nSigmaITS(track1) > -2.5 && itsResponse.nSigmaITS(track1) < 2.5)) { continue; } - for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posThisColl, negThisColl))) { + auto track1ID = track1.globalIndex(); + for (auto track2 : negThisColl) { // track selection - if (!selectionTrack(track1) || !selectionTrack(track2)) { - // printf("Mix = %d\n", 6); + if (!selectionTrack(track2)) { continue; } // PID check - if (ispTdepPID && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { - // printf("Mix = %d\n", 7); + if (ispTdepPID && !isTOFOnly && !selectionPIDpTdependent(track2)) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !selectionPID(track2)) { + continue; + } + if (isTOFOnly && !selectionPID2(track2)) { continue; } - if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) { continue; } if (!selectionPair(track1, track2)) { - // printf("Mix = %d\n", 8); continue; } if (removefaketrak && isFakeKaon(track1)) { @@ -621,162 +907,529 @@ struct phipbpb { if (removefaketrak && isFakeKaon(track2)) { continue; } + if (useGlobalTrack && track2.p() < 1.0 && !(itsResponse.nSigmaITS(track2) > -2.5 && itsResponse.nSigmaITS(track2) < 2.5)) { + 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 (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, occupancy); - } - 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); + + if (fillv1) { + auto ux = TMath::Cos(GetPhiInRange(PhiMesonMother.Phi())); + auto uy = TMath::Sin(GetPhiInRange(PhiMesonMother.Phi())); + auto uxQxp = ux * modqxZDCA; + auto uyQyp = uy * modqyZDCA; // correlations of particle and ZDC q vectors + auto uxyQxyp = uxQxp + uyQyp; + auto uxQxt = ux * modqxZDCC; + auto uyQyt = uy * modqyZDCC; + auto uxyQxyt = uxQxt + uyQyt; + auto oddv1 = ux * (modqxZDCA - modqxZDCC) + uy * (modqyZDCA - modqyZDCC); + + histos.fill(HIST("hpoddvscentpteta"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), oddv1); + if (fillLOCC) { + histos.fill(HIST("hpuxyQxypvscentpteta"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uxyQxyp); + histos.fill(HIST("hpuxyQxytvscentpteta"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uxyQxyt); + histos.fill(HIST("hpuxvscentpteta"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), ux); + histos.fill(HIST("hpuyvscentpteta"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uy); + } } } + Npostrack = Npostrack + 1; } } - PROCESS_SWITCH(phipbpb, processMixedEvent, "Process Mixed event", true); - void processMixedEventOpti(EventCandidates const& collisions, TrackCandidates const& tracks) + PROCESS_SWITCH(phipbpb, processSameEventv1, "Process Same event for v1", false); + + BinningTypeVertexContributor binningOnEPAngle{{axisVertex, axisMultiplicityClass, axisEPAngle}, true}; + BinningTypeVertexContributorv1 binningOnSPAngle{{axisVertex, axisMultiplicityClass, axisSPAngle}, true}; + Preslice tracksPerCollision = aod::track::collisionId; + void processMEAcc(EventCandidates const& collisions, TrackCandidates const& tracks) { - auto tracksTuple = std::make_tuple(tracks); - 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()) { + for (auto& [collision1, collision2] : selfCombinations(binningOnEPAngle, cfgNoMixedEvents, -1, collisions, collisions)) { + + if (!collision1.sel8() || !collision1.triggereventep() || !collision1.selection_bit(aod::evsel::kNoSameBunchPileup)) { continue; } - if (!collision1.triggereventep() || !collision2.triggereventep()) { + if (!collision2.sel8() || !collision2.triggereventep() || !collision2.selection_bit(aod::evsel::kNoSameBunchPileup)) { 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 (occupancy1 > cfgCutOccupancy) { continue; } - if (additionalEvSel2 && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { - return; - } - if (additionalEvSel3 && (!collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { - return; + if (occupancy2 > cfgCutOccupancy) { + continue; } - if (additionalEvSel2 && (!collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { - return; + if (additionalEvsel && !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; } - if (additionalEvSel3 && (!collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { - return; + if (additionalEvsel && !collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; } - int occupancy = collision1.trackOccupancyInTimeRange(); - auto centrality = collision1.centFT0C(); - auto centrality2 = collision2.centFT0C(); - auto psiFT0C = collision1.psiFT0C(); - auto QFT0C = collision1.qFT0C(); - if (additionalEvsel && !eventSelected(collision1, centrality)) { + if (additionalEvselITS && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { continue; } - if (additionalEvsel && !eventSelected(collision2, centrality2)) { + if (additionalEvselITS && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { continue; } + auto centrality = collision1.centFT0C(); + auto psiFT0C = collision1.psiFT0C(); + auto QFT0C = collision1.qFT0C(); - for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { - if (track1.sign() * track2.sign() > 0) { + o2::aod::ITSResponse itsResponse; + auto grouptrack1 = tracks.sliceBy(tracksPerCollision, collision2.globalIndex()); + auto grouptrack2 = tracks.sliceBy(tracksPerCollision, collision2.globalIndex()); + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(grouptrack1, grouptrack2))) { + if (t2.index() <= t1.index()) { continue; } - if (!selectionTrack(track1) || !selectionTrack(track2)) { + if (t1.sign() * t2.sign() > 0) { continue; } - // PID check - if (ispTdepPID && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + if (!selectionTrack(t1)) { continue; } - if (!ispTdepPID && (!selectionPID(track1) || !selectionPID(track2))) { + if (ispTdepPID && !isTOFOnly && !selectionPIDpTdependent(t1)) { continue; } - if (!selectionPair(track1, track2)) { + if (!ispTdepPID && !isTOFOnly && !selectionPID(t1)) { continue; } - if (removefaketrak && isFakeKaon(track1)) { + if (isTOFOnly && !selectionPID2(t1)) { continue; } - if (removefaketrak && isFakeKaon(track2)) { + if (useGlobalTrack && t1.p() < 1.0 && !(itsResponse.nSigmaITS(t1) > -2.5 && itsResponse.nSigmaITS(t1) < 2.5)) { 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); - } else if (track1.sign() < 0 && track2.sign() > 0) { - 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 (!selectionTrack(t2)) { + continue; + } + if (ispTdepPID && !isTOFOnly && !selectionPIDpTdependent(t2)) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !selectionPID(t2)) { + continue; + } + if (isTOFOnly && !selectionPID2(t2)) { + continue; + } + if (useGlobalTrack && t2.p() < 1.0 && !(itsResponse.nSigmaITS(t2) > -2.5 && itsResponse.nSigmaITS(t2) < 2.5)) { + continue; + } + + if (!selectionPair(t1, t2)) { + continue; + } + if (removefaketrak && isFakeKaon(t1)) { + continue; + } + if (removefaketrak && isFakeKaon(t2)) { + continue; + } + + 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; + auto phiminuspsi = GetPhiInRange(PhiMesonMother.Phi() - psiFT0C); + auto v2 = TMath::Cos(2.0 * phiminuspsi); 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()); + + if (useSP) { + histos.fill(HIST("hSparseV2MixEPAngleCosDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2 * QFT0C, centrality); + } else { + histos.fill(HIST("hSparseV2MixEPAngleCosDeltaPhi"), PhiMesonMother.M(), PhiMesonMother.Pt(), v2, centrality); + } + } + } + } + PROCESS_SWITCH(phipbpb, processMEAcc, "Process ME Acceptance", true); + + void processMEAccv1(EventCandidatesv1 const& collisions, TrackCandidates const& tracks) + { + for (auto& [collision1, collision2] : selfCombinations(binningOnSPAngle, cfgNoMixedEvents, -1, collisions, collisions)) { + + if (!collision1.sel8() || !collision1.triggereventsp() || !collision1.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + if (!collision2.sel8() || !collision2.triggereventsp() || !collision2.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + int occupancy1 = collision1.trackOccupancyInTimeRange(); + int occupancy2 = collision2.trackOccupancyInTimeRange(); + if (occupancy1 > cfgCutOccupancy) { + continue; + } + if (occupancy2 > cfgCutOccupancy) { + continue; + } + if (additionalEvsel && !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + 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; + } + auto centrality = collision1.centFT0C(); + + auto qxZDCA = collision1.qxZDCA(); + auto qxZDCC = collision1.qxZDCC(); + auto qyZDCA = collision1.qyZDCA(); + auto qyZDCC = collision1.qyZDCC(); + auto psiZDCC = collision1.psiZDCC(); + auto psiZDCA = collision1.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; + } + + o2::aod::ITSResponse itsResponse; + auto grouptrack1 = tracks.sliceBy(tracksPerCollision, collision1.globalIndex()); + auto grouptrack2 = tracks.sliceBy(tracksPerCollision, collision2.globalIndex()); + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(grouptrack1, grouptrack2))) { + if (t2.index() <= t1.index()) { + continue; + } + if (t1.sign() * t2.sign() > 0) { + continue; + } + if (!selectionTrack(t1)) { + continue; + } + if (ispTdepPID && !isTOFOnly && !selectionPIDpTdependent(t1)) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !selectionPID(t1)) { + continue; + } + if (isTOFOnly && !selectionPID2(t1)) { + continue; + } + if (useGlobalTrack && t1.p() < 1.0 && !(itsResponse.nSigmaITS(t1) > -2.5 && itsResponse.nSigmaITS(t1) < 2.5)) { + continue; + } + + if (!selectionTrack(t2)) { + continue; + } + if (ispTdepPID && !isTOFOnly && !selectionPIDpTdependent(t2)) { + continue; + } + if (!ispTdepPID && !isTOFOnly && !selectionPID(t2)) { + continue; + } + if (isTOFOnly && !selectionPID2(t2)) { + continue; + } + if (useGlobalTrack && t2.p() < 1.0 && !(itsResponse.nSigmaITS(t2) > -2.5 && itsResponse.nSigmaITS(t2) < 2.5)) { + continue; + } + + if (!selectionPair(t1, t2)) { + continue; + } + if (removefaketrak && isFakeKaon(t1)) { + continue; + } + if (removefaketrak && isFakeKaon(t2)) { + continue; + } + + 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 (fillv1) { + auto ux = TMath::Cos(GetPhiInRange(PhiMesonMother.Phi())); + auto uy = TMath::Sin(GetPhiInRange(PhiMesonMother.Phi())); + auto uxQxp = ux * modqxZDCA; + auto uyQyp = uy * modqyZDCA; // correlations of particle and ZDC q vectors + auto uxyQxyp = uxQxp + uyQyp; + auto uxQxt = ux * modqxZDCC; + auto uyQyt = uy * modqyZDCC; + auto uxyQxyt = uxQxt + uyQyt; + auto oddv1 = ux * (modqxZDCA - modqxZDCC) + uy * (modqyZDCA - modqyZDCC); + + histos.fill(HIST("hpoddvscentptetamixacc"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), oddv1); + if (fillLOCC) { + histos.fill(HIST("hpuxyQxypvscentptetamixacc"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uxyQxyp); + histos.fill(HIST("hpuxyQxytvscentptetamixacc"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uxyQxyt); + histos.fill(HIST("hpuxvscentptetamixacc"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), ux); + histos.fill(HIST("hpuyvscentptetamixacc"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uy); + } + } + } + } + } + PROCESS_SWITCH(phipbpb, processMEAccv1, "Process ME Acceptance v1", false); + + void processMixedEventOpti(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicityClass, axisEPAngle}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (auto& [collision1, tracks1, collision2, tracks2] : pair) { + // 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; + // } + o2::aod::ITSResponse itsResponse; + int occupancy1 = collision1.trackOccupancyInTimeRange(); + int occupancy2 = collision2.trackOccupancyInTimeRange(); + if (occupancy1 > cfgCutOccupancy) { + continue; + } + if (occupancy2 > cfgCutOccupancy) { + continue; + } + auto centrality = collision1.centFT0C(); + // auto centrality2 = collision2.centFT0C(); + auto psiFT0C = collision1.psiFT0C(); + auto QFT0C = collision1.qFT0C(); + if (additionalEvsel && !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + 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 && !isTOFOnly && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + continue; + } + 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); + } else if (track1.sign() < 0 && track2.sign() > 0) { + 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; 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, occupancy); + 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 (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); + 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); } } } } PROCESS_SWITCH(phipbpb, processMixedEventOpti, "Process Mixed event new", true); + + void processMixedEventOptiv1(EventCandidatesv1 const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVertexContributorv1 binningOnPositions{{axisVertex, axisMultiplicityClass, axisSPAngle}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (auto& [collision1, tracks1, collision2, tracks2] : pair) { + if (!collision1.sel8() || !collision1.triggereventsp() || !collision1.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + if (!collision2.sel8() || !collision2.triggereventsp() || !collision2.selection_bit(aod::evsel::kNoSameBunchPileup)) { + continue; + } + o2::aod::ITSResponse itsResponse; + int occupancy1 = collision1.trackOccupancyInTimeRange(); + int occupancy2 = collision2.trackOccupancyInTimeRange(); + if (occupancy1 > cfgCutOccupancy) { + continue; + } + if (occupancy2 > cfgCutOccupancy) { + continue; + } + auto centrality = collision1.centFT0C(); + + if (additionalEvsel && !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + 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; + } + + auto qxZDCA = collision1.qxZDCA(); + auto qxZDCC = collision1.qxZDCC(); + auto qyZDCA = collision1.qyZDCA(); + auto qyZDCC = collision1.qyZDCC(); + auto psiZDCC = collision1.psiZDCC(); + auto psiZDCA = collision1.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; + } + + 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 && !isTOFOnly && (!selectionPIDpTdependent(track1) || !selectionPIDpTdependent(track2))) { + continue; + } + 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); + } else if (track1.sign() < 0 && track2.sign() > 0) { + 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 (fillv1) { + auto ux = TMath::Cos(GetPhiInRange(PhiMesonMother.Phi())); + auto uy = TMath::Sin(GetPhiInRange(PhiMesonMother.Phi())); + auto uxQxp = ux * modqxZDCA; + auto uyQyp = uy * modqyZDCA; // correlations of particle and ZDC q vectors + auto uxyQxyp = uxQxp + uyQyp; + auto uxQxt = ux * modqxZDCC; + auto uyQyt = uy * modqyZDCC; + auto uxyQxyt = uxQxt + uyQyt; + auto oddv1 = ux * (modqxZDCA - modqxZDCC) + uy * (modqyZDCA - modqyZDCC); + + histos.fill(HIST("hpoddvscentptetamixopti"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), oddv1); + if (fillLOCC) { + histos.fill(HIST("hpuxyQxypvscentptetamixopti"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uxyQxyp); + histos.fill(HIST("hpuxyQxytvscentptetamixopti"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uxyQxyt); + histos.fill(HIST("hpuxvscentptetamixopti"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), ux); + histos.fill(HIST("hpuyvscentptetamixopti"), PhiMesonMother.M(), centrality, PhiMesonMother.Pt(), PhiMesonMother.Rapidity(), uy); + } + } + } + } + } + PROCESS_SWITCH(phipbpb, processMixedEventOptiv1, "Process Mixed event new v1", false); + void processMC(CollisionMCTrueTable::iterator const& /*TrueCollision*/, CollisionMCRecTableCentFT0C const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) { histos.fill(HIST("hMC"), 0); @@ -795,11 +1448,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; } @@ -848,8 +1502,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; } @@ -867,10 +1521,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)) { @@ -890,10 +1544,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(); @@ -903,39 +1553,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) { @@ -980,36 +1607,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); - } - 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); - } + 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 (!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, processMCPhiWeight, "Process MC Phi Weight", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { diff --git a/PWGLF/Tasks/Resonances/phispectrapbpbqa.cxx b/PWGLF/Tasks/Resonances/phispectrapbpbqa.cxx new file mode 100644 index 00000000000..a7db74aa5eb --- /dev/null +++ b/PWGLF/Tasks/Resonances/phispectrapbpbqa.cxx @@ -0,0 +1,829 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/V0.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#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; +using std::array; +using namespace o2::aod::rctsel; +struct phispectrapbpbqa { + double bz = 0.; + + // 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; + 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; + + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + + TH3D* hTPCCallib; + TH3D* hTOFCallib; + + Configurable ConfPathTPC{"ConfPathTPC", "Users/s/skundu/My/Object/PIDcallib/TPC", "Weight path TPC"}; + Configurable ConfPathTOF{"ConfPathTOF", "Users/s/skundu/My/Object/PIDcallib/TOF", "Weight path TOF"}; + + // events + Configurable applyStrictEvSel{"applyStrictEvSel", true, "Apply strict event selection"}; + Configurable applyMCsel8{"applyMCsel8", false, "Apply sel8 in MC"}; + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 10, "Number of event mixing"}; + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for bin"}; + // ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {8, 0, 80}, "multiplicity percentile for bin"}; + + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentrality{"cfgCutCentrality", 80.0f, "Accepted maximum Centrality"}; + + // track + Configurable cfgCutPT{"cfgCutPT", 0.2, "PT cut on daughter track"}; + Configurable cfgCutCharge{"cfgCutCharge", 0.0, "cut on Charge"}; + Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut on daughter track"}; + + Configurable cfgITScluster{"cfgITScluster", 4, "Number of ITS cluster"}; + Configurable cfgTPCcluster{"cfgTPCcluster", 80, "Number of TPC cluster"}; + Configurable cfgTPCPIDcluster{"cfgTPCPIDcluster", 80, "Number of TPC PID cluster"}; + Configurable cfgTPCcrossedRows{"cfgTPCcrossedRows", 90, "Number of TPC crossed Rows"}; + + Configurable cfgUpdatePID{"cfgUpdatePID", false, "Update PID callibration"}; + Configurable applyPID{"applyPID", true, "Apply PID"}; + Configurable applyPIDCluster{"applyPIDCluster", true, "Apply PID cluster"}; + Configurable isDeepAngle{"isDeepAngle", false, "Deep Angle cut"}; + Configurable cfgDeepAngle{"cfgDeepAngle", 0.04, "Deep Angle cut value"}; + Configurable timeFrameMC{"timeFrameMC", false, "time frame cut in MC"}; + Configurable readOutFrameMC{"readOutFrameMC", true, "ITS read out frame cut in MC"}; + Configurable ispTdepPID{"ispTdepPID", false, "pT dependent PID"}; + Configurable cfgCutTOFBeta{"cfgCutTOFBeta", 0.5, "cut TOF beta"}; + Configurable nsigmaCutTPC{"nsigmacutTPC", 2.0, "Value of the TPC Nsigma cut"}; + Configurable applyTOF{"applyTOF", true, "Apply TOF"}; + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, -1.0, 200.0, 500.0, 1000.0, 2000.0f, 4000.0, 10000.0f, 100000.0f}, "occupancy axis"}; + struct : ConfigurableGroup { + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {90, 0.98, 1.07}, "#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 configThnAxisSector{"configThnAxisSector", {2, 0.0, 2.0}, "TPC sector"}; + + } cnfgaxis; + Configurable isMC{"isMC", false, "use MC"}; + Configurable avoidsplitrackMC{"avoidsplitrackMC", false, "avoid split track in MC"}; + + 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 PIDcutFilter = nabs(aod::pidtpc::tpcNSigmaKa) < nsigmaCutTPC; + // Filter DCAcutFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz); + + using EventCandidates = 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; + Preslice perCollision = aod::track::collisionId; + + SliceCache cache; + Partition posTracks = aod::track::signed1Pt > cfgCutCharge; + Partition negTracks = aod::track::signed1Pt < cfgCutCharge; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + RCTFlagsChecker rctChecker; + // Event selection cuts - Alex + // TF1* fMultPVCutLow = nullptr; + + void init(o2::framework::InitContext&) + { + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + histos.add("hphiSE", "hphiSE", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisCentrality, axisOccupancy, cnfgaxis.configThnAxisSector}, true); + histos.add("hphiME", "hphiME", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisCentrality, axisOccupancy, cnfgaxis.configThnAxisSector}, true); + histos.add("hphiGen", "hphiGen", HistType::kTHnSparseF, {cnfgaxis.configThnAxisInvMass, cnfgaxis.configThnAxisPt, cnfgaxis.configThnAxisCentrality, axisOccupancy}, true); + + histos.add("hNsigmaTPC", "NsigmaKaon TPC", HistType::kTHnSparseF, {{200, -10.0f, 10.0f}, {100, 0.0, 10.0}, axisOccupancy, cnfgaxis.configThnAxisCentrality}); + histos.add("hNsigmaTOF", "NsigmaKaon TOF", HistType::kTHnSparseF, {{200, -10.0f, 10.0f}, {100, 0.0, 10.0}, axisOccupancy, cnfgaxis.configThnAxisCentrality}); + + histos.add("hPhiMommentum", "hPhiMommentum", kTH3F, {{36, 0, 6.283}, {200, -10.0, 10.0}, axisOccupancy}); + + histos.add("hNsigmaTPCBeforeCut", "NsigmaKaon TPC Before Cut", kTH3F, {{200, -10.0f, 10.0f}, {100, 0.0, 10.0}, axisOccupancy}); + histos.add("hNsigmaTOFBeforeCut", "NsigmaKaon TOF Before Cut", kTH3F, {{200, -10.0f, 10.0f}, {100, 0.0, 10.0}, axisOccupancy}); + histos.add("hNsigmaTPCAfterCut", "NsigmaKaon TPC After Cut", kTH3F, {{200, -10.0f, 10.0f}, {100, 0.0, 10.0}, axisOccupancy}); + histos.add("hNsigmaTOFAfterCut", "NsigmaKaon TOF After Cut", kTH3F, {{200, -10.0f, 10.0f}, {100, 0.0, 10.0}, axisOccupancy}); + + histos.add("hNsigmaKaonTOFTPC", "NsigmaKaon TOFTPC distribution", kTH3F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}, {100, 0.0, 10.0}}); + + histos.add("hdcaxy", "DCA xy dist.", kTH2F, {{1000, -1.0f, 1.0f}, {200, -10.0, 10.0}}); + histos.add("hdcaz", "DCA z dist.", kTH2F, {{1000, -1.0f, 1.0f}, {200, -10.0, 10.0}}); + + histos.add("hCentrality", "hCentrality", kTH1F, {{8, 0.0f, 80.0f}}); + histos.add("hVtxZ", "hVtxZ", kTH1F, {{8, 0.0f, 80.0f}}); + histos.add("hOccupancy", "hOccupancy", kTH2F, {axisOccupancy, cnfgaxis.configThnAxisCentrality}); + histos.add("hMC", "hMC", kTH1F, {{20, 0.0f, 20.0f}}); + histos.add("h1PhiRecsplit", "h1PhiRecsplit", kTH1F, {{100, 0.0f, 10.0f}}); + histos.add("hData", "hData", kTH1F, {{20, 0.0f, 20.0f}}); + 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()); + if (cfgUpdatePID) { + hTPCCallib = ccdb->getForTimeStamp(ConfPathTPC.value, cfgCcdbParam.nolaterthan.value); + hTOFCallib = ccdb->getForTimeStamp(ConfPathTOF.value, cfgCcdbParam.nolaterthan.value); + } + } + + double massKa = o2::constants::physics::MassKPlus; + + 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(); + } + + template + bool selectionTrack(const T& candidate) + { + if (!(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTPCcluster && candidate.tpcNClsCrossedRows() > cfgTPCcrossedRows)) { + return false; + } + if (applyPIDCluster && candidate.tpcNClsPID() < cfgTPCPIDcluster) { + return false; + } + return true; + } + + template + bool selectionPIDpTdependent(const T& candidate, double nsigmaTPC, double nsigmaTOF) + { + if (candidate.p() < 0.7 && TMath::Abs(nsigmaTPC) < nsigmaCutTPC) { + return true; + } + if (candidate.p() > 0.7 && candidate.hasTOF() && TMath::Abs(nsigmaTPC) < nsigmaCutTPC) { + if (candidate.p() > 0.7 && candidate.p() < 1.6 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -5.0 && nsigmaTOF < 10.0) { + return true; + } + if (candidate.p() >= 1.6 && candidate.p() < 2.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 10.0) { + return true; + } + if (candidate.p() >= 2.0 && candidate.p() < 2.5 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 6.0) { + return true; + } + if (candidate.p() >= 2.5 && candidate.p() < 4.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -2.5 && nsigmaTOF < 4.0) { + return true; + } + if (candidate.p() >= 4.0 && candidate.p() < 5.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -4.0 && nsigmaTOF < 3.0) { + return true; + } + if (candidate.p() >= 5.0 && candidate.p() < 6.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -4.0 && nsigmaTOF < 2.5) { + return true; + } + if (candidate.p() >= 6.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 3.0) { + return true; + } + } + return false; + } + + template + bool selectionPID(const T& candidate, double nsigmaTPC, double nsigmaTOF) + { + if (applyTOF) { + if (!candidate.hasTOF() && TMath::Abs(nsigmaTPC) < nsigmaCutTPC) { + return true; + } + if (candidate.p() > 0.5 && candidate.hasTOF() && TMath::Abs(nsigmaTPC) < nsigmaCutTPC) { + if (candidate.p() > 0.5 && candidate.p() < 1.6 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -5.0 && nsigmaTOF < 10.0) { + return true; + } + if (candidate.p() >= 1.6 && candidate.p() < 2.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 10.0) { + return true; + } + if (candidate.p() >= 2.0 && candidate.p() < 2.5 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 6.0) { + return true; + } + if (candidate.p() >= 2.5 && candidate.p() < 4.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -2.5 && nsigmaTOF < 4.0) { + return true; + } + if (candidate.p() >= 4.0 && candidate.p() < 5.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -4.0 && nsigmaTOF < 3.0) { + return true; + } + if (candidate.p() >= 5.0 && candidate.p() < 6.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -4.0 && nsigmaTOF < 2.5) { + return true; + } + if (candidate.p() >= 6.0 && candidate.beta() > cfgCutTOFBeta && nsigmaTOF > -3.0 && nsigmaTOF < 3.0) { + return true; + } + } + } else if (TMath::Abs(nsigmaTPC) < nsigmaCutTPC) { + 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; + } + + // Keep a track only if its azimuth is NOT inside the periodic boundary window. + // phi : track azimuth (radians) at your chosen reference radius (e.g. Rout ~ 247 cm) + // badHalfWidth : half-width of the bad strip near each boundary (rad). Your example: 0.15 + // nSectors : 18 for ALICE TPC + bool keepTrackNoTPCBoundary(float phi, + float badWidth = 0.15f, + int nSectors = 18) + { + constexpr float TwoPi = 6.283185307179586f; + float ph = std::fmod(phi, TwoPi); + if (ph < 0.f) + ph += TwoPi; // wrap phi into [0, 2π) + + const float secW = TwoPi / static_cast(nSectors); // ≈ 0.349 rad + + float rel = std::fmod(ph, secW); // position inside sector [0, secW) + + return rel > badWidth; // keep if NOT inside boundary strip [0, badWidth] + } + + using BinningTypeVertexContributor = ColumnBinningPolicy; + ROOT::Math::PxPyPzMVector PhiMesonMother, KaonPlus, KaonMinus, fourVecDauCM; + int currentRunNumber = -999; + int lastRunNumber = -999; + void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const&, aod::BCsWithTimestamps const&) + { + histos.fill(HIST("hData"), 1); + 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; + } + histos.fill(HIST("hData"), 2); + if (rctCut.requireRCTFlagChecker) { + if (!rctChecker(collision)) { + return; + } + } + histos.fill(HIST("hData"), 3); + if (applyStrictEvSel && (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) || !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow))) { + return; + } + histos.fill(HIST("hData"), 4); + auto centrality = collision.centFT0C(); + int occupancy = collision.trackOccupancyInTimeRange(); + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hVtxZ"), collision.posZ()); + + /*auto bc = collision.template bc_as(); + currentRunNumber = collision.bc_as().runNumber(); + if (currentRunNumber != lastRunNumber) { + bz = getMagneticField(bc.timestamp()); + } + lastRunNumber = currentRunNumber; + */ + + auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + int Npostrack = 0; + histos.fill(HIST("hOccupancy"), occupancy, centrality); + for (auto track1 : posThisColl) { + if (!selectionTrack(track1)) { + continue; + } + histos.fill(HIST("hdcaxy"), track1.dcaXY(), track1.p() / track1.sign()); + histos.fill(HIST("hdcaz"), track1.dcaZ(), track1.p() / track1.sign()); + double nSigmaTPC = track1.tpcNSigmaKa(); + double nSigmaTOF = track1.tofNSigmaKa(); + if (!track1.hasTOF()) { + nSigmaTOF = -9999.99; + } + + if (cfgUpdatePID) { + // update PID + nSigmaTPC = (nSigmaTPC - hTPCCallib->GetBinContent(hTPCCallib->FindBin(track1.p(), centrality, occupancy))) / hTPCCallib->GetBinError(hTPCCallib->FindBin(track1.p(), centrality, occupancy)); + if (track1.hasTOF()) { + nSigmaTOF = (nSigmaTOF - hTOFCallib->GetBinContent(hTOFCallib->FindBin(track1.p(), centrality, occupancy))) / hTOFCallib->GetBinError(hTOFCallib->FindBin(track1.p(), centrality, occupancy)); + } + } + if (track1.p() < 0.6) { + histos.fill(HIST("hNsigmaTPC"), nSigmaTPC, track1.p(), occupancy, centrality); + } else if (track1.p() > 0.6 && track1.hasTOF() && std::abs(nSigmaTOF) < 2.5) { + histos.fill(HIST("hNsigmaTPC"), nSigmaTPC, track1.p(), occupancy, centrality); + } + if (track1.hasTOF()) { + histos.fill(HIST("hNsigmaTOF"), nSigmaTOF, track1.p(), occupancy, centrality); + } + histos.fill(HIST("hNsigmaTPCBeforeCut"), nSigmaTPC, track1.p(), occupancy); + histos.fill(HIST("hNsigmaTOFBeforeCut"), nSigmaTOF, track1.p(), occupancy); + if (applyPID) { + if (ispTdepPID && !selectionPIDpTdependent(track1, nSigmaTPC, nSigmaTOF)) { + continue; + } + if (!ispTdepPID && !selectionPID(track1, nSigmaTPC, nSigmaTOF)) { + continue; + } + } + histos.fill(HIST("hNsigmaTPCAfterCut"), nSigmaTPC, track1.p(), occupancy); + histos.fill(HIST("hNsigmaTOFAfterCut"), nSigmaTOF, track1.p(), occupancy); + if (track1.hasTOF()) { + histos.fill(HIST("hNsigmaKaonTOFTPC"), nSigmaTOF, nSigmaTPC, track1.p()); + } + Npostrack = Npostrack + 1; + + // 1) φ at a chosen radius (e.g., outer pad rows ~247 cm) + histos.fill(HIST("hPhiMommentum"), track1.phi(), track1.p(), occupancy); + + for (auto track2 : negThisColl) { + if (track1.sign() * track2.sign() > 0.0) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + if (Npostrack == 1) { + histos.fill(HIST("hdcaxy"), track2.dcaXY(), track2.p() / track2.sign()); + histos.fill(HIST("hdcaz"), track2.dcaZ(), track2.p() / track2.sign()); + } + double nSigmaTPC2 = track2.tpcNSigmaKa(); + double nSigmaTOF2 = track2.tofNSigmaKa(); + if (!track2.hasTOF()) { + nSigmaTOF2 = -9999.9; + } + if (cfgUpdatePID) { + // update PID + nSigmaTPC2 = (nSigmaTPC2 - hTPCCallib->GetBinContent(hTPCCallib->FindBin(track2.p(), centrality, occupancy))) / hTPCCallib->GetBinError(hTPCCallib->FindBin(track2.p(), centrality, occupancy)); + if (track2.hasTOF()) { + nSigmaTOF2 = (nSigmaTOF2 - hTOFCallib->GetBinContent(hTOFCallib->FindBin(track2.p(), centrality, occupancy))) / hTOFCallib->GetBinError(hTOFCallib->FindBin(track2.p(), centrality, occupancy)); + } + } + if (Npostrack == 1) { + if (track2.p() < 0.6) { + histos.fill(HIST("hNsigmaTPC"), nSigmaTPC2, track2.p(), occupancy, centrality); + } else if (track2.p() > 0.6 && track2.hasTOF() && std::abs(nSigmaTOF2) < 2.5) { + histos.fill(HIST("hNsigmaTPC"), nSigmaTPC2, track2.p(), occupancy, centrality); + } + if (track2.hasTOF()) { + histos.fill(HIST("hNsigmaTOF"), nSigmaTOF2, track2.p(), occupancy, centrality); + } + histos.fill(HIST("hNsigmaTPCBeforeCut"), nSigmaTPC2, track2.p(), occupancy); + histos.fill(HIST("hNsigmaTOFBeforeCut"), nSigmaTOF2, track2.p(), occupancy); + } + if (applyPID) { + if (ispTdepPID && !selectionPIDpTdependent(track2, nSigmaTPC2, nSigmaTOF2)) { + continue; + } + if (!ispTdepPID && !selectionPID(track2, nSigmaTPC2, nSigmaTOF2)) { + continue; + } + } + if (Npostrack == 1) { + histos.fill(HIST("hNsigmaTPCAfterCut"), nSigmaTPC2, track2.p(), occupancy); + histos.fill(HIST("hNsigmaTOFAfterCut"), nSigmaTOF2, track2.p(), occupancy); + if (track2.hasTOF()) { + histos.fill(HIST("hNsigmaKaonTOFTPC"), nSigmaTOF2, nSigmaTPC2, track2.p()); + } + } + if (Npostrack == 1) { + histos.fill(HIST("hPhiMommentum"), track2.phi(), track2.p(), occupancy); + } + auto track1ID = track1.globalIndex(); + auto track2ID = track2.globalIndex(); + if (track2ID == track1ID) { + continue; + } + if (!selectionPair(track1, track2)) { + continue; + } + bool crossed1 = keepTrackNoTPCBoundary(track1.phi(), 0.15, 18); + bool crossed2 = keepTrackNoTPCBoundary(track2.phi(), 0.15, 18); + float passsector = -999.0; + if (crossed1 && crossed2) { + passsector = 1.5; + } else { + passsector = 0.5; + } + + 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()) < 0.5) { + histos.fill(HIST("hphiSE"), PhiMesonMother.M(), PhiMesonMother.Pt(), centrality, occupancy, passsector); + } + } + } + } + PROCESS_SWITCH(phispectrapbpbqa, processSameEvent, "Process Same event", true); + + void processMixedEventOpti(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVertexContributor binningOnPositions{{axisVertex, cnfgaxis.configThnAxisCentrality, axisOccupancy}, true}; + SameKindPair pair{binningOnPositions, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + for (auto& [collision1, tracks1, collision2, tracks2] : pair) { + if (!collision1.sel8() || !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.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 (rctCut.requireRCTFlagChecker) { + if (!rctChecker(collision1) || !rctChecker(collision2)) { + continue; + } + } + if (applyStrictEvSel && (!collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) || !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow))) { + return; + } + if (applyStrictEvSel && (!collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) || !collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow))) { + return; + } + int occupancy = collision1.trackOccupancyInTimeRange(); + auto centrality = collision1.centFT0C(); + for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + if (track1.sign() * track2.sign() > 0) { + continue; + } + if (!selectionTrack(track1)) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + // PID track 1 + double nSigmaTPC = track1.tpcNSigmaKa(); + double nSigmaTOF = track1.tofNSigmaKa(); + if (!track1.hasTOF()) { + nSigmaTOF = -9999.99; + } + if (cfgUpdatePID) { + nSigmaTPC = (nSigmaTPC - hTPCCallib->GetBinContent(hTPCCallib->FindBin(track1.p(), centrality, occupancy))) / hTPCCallib->GetBinError(hTPCCallib->FindBin(track1.p(), centrality, occupancy)); + if (track1.hasTOF()) { + nSigmaTOF = (nSigmaTOF - hTOFCallib->GetBinContent(hTOFCallib->FindBin(track1.p(), centrality, occupancy))) / hTOFCallib->GetBinError(hTOFCallib->FindBin(track1.p(), centrality, occupancy)); + } + } + // PID track 2 + double nSigmaTPC2 = track2.tpcNSigmaKa(); + double nSigmaTOF2 = track2.tofNSigmaKa(); + if (!track2.hasTOF()) { + nSigmaTOF2 = -9999.99; + } + if (cfgUpdatePID) { + nSigmaTPC2 = (nSigmaTPC2 - hTPCCallib->GetBinContent(hTPCCallib->FindBin(track2.p(), centrality, occupancy))) / hTPCCallib->GetBinError(hTPCCallib->FindBin(track2.p(), centrality, occupancy)); + if (track2.hasTOF()) { + nSigmaTOF2 = (nSigmaTOF2 - hTOFCallib->GetBinContent(hTOFCallib->FindBin(track2.p(), centrality, occupancy))) / hTOFCallib->GetBinError(hTOFCallib->FindBin(track2.p(), centrality, occupancy)); + } + } + if (applyPID) { + if (ispTdepPID && !selectionPIDpTdependent(track1, nSigmaTPC, nSigmaTOF)) { + continue; + } + if (!ispTdepPID && !selectionPID(track1, nSigmaTPC, nSigmaTOF)) { + continue; + } + + if (ispTdepPID && !selectionPIDpTdependent(track2, nSigmaTPC2, nSigmaTOF2)) { + continue; + } + if (!ispTdepPID && !selectionPID(track2, nSigmaTPC2, nSigmaTOF2)) { + continue; + } + } + if (!selectionPair(track1, track2)) { + continue; + } + bool crossed1 = keepTrackNoTPCBoundary(track1.phi(), 0.15, 18); + bool crossed2 = keepTrackNoTPCBoundary(track2.phi(), 0.15, 18); + float passsector = -999.0; + if (crossed1 && crossed2) { + passsector = 1.5; + } else { + passsector = 0.5; + } + 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()) < 0.5) { + histos.fill(HIST("hphiME"), PhiMesonMother.M(), PhiMesonMother.Pt(), centrality, occupancy, passsector); + } + } + } + } + PROCESS_SWITCH(phispectrapbpbqa, processMixedEventOpti, "Process Mixed event new", true); + + void processMC(CollisionMCTrueTable::iterator const&, 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) { + if (applyMCsel8 && !RecCollision.sel8()) { + histos.fill(HIST("hMC"), 3); + continue; + } + if (!applyMCsel8 && !RecCollision.selection_bit(aod::evsel::kIsTriggerTVX)) { + histos.fill(HIST("hMC"), 3); + continue; + } + if (!RecCollision.selection_bit(aod::evsel::kNoSameBunchPileup) || !RecCollision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !RecCollision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + histos.fill(HIST("hMC"), 4); + continue; + } + if (TMath::Abs(RecCollision.posZ()) > cfgCutVertex) { + histos.fill(HIST("hMC"), 6); + continue; + } + + if (timeFrameMC && !RecCollision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + histos.fill(HIST("hMC"), 7); + continue; + } + if (readOutFrameMC && !RecCollision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + histos.fill(HIST("hMC"), 8); + continue; + } + histos.fill(HIST("hMC"), 9); + if (rctCut.requireRCTFlagChecker) { + if (!rctChecker(RecCollision)) { + continue; + } + } + histos.fill(HIST("hMC"), 10); + if (applyStrictEvSel && (!RecCollision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) || !RecCollision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow))) { + return; + } + histos.fill(HIST("hMC"), 11); + auto centrality = RecCollision.centFT0C(); + int occupancy = RecCollision.trackOccupancyInTimeRange(); + histos.fill(HIST("hOccupancy"), occupancy, centrality); + + auto oldindex = -999; + auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); + // loop over reconstructed particle + int ntrack1 = 0; + for (auto track1 : Rectrackspart) { + if (!selectionTrack(track1)) { + continue; + } + if (!track1.has_mcParticle()) { + continue; + } + auto track1ID = track1.index(); + // PID track 1 + double nSigmaTPC = track1.tpcNSigmaKa(); + double nSigmaTOF = track1.tofNSigmaKa(); + if (!track1.hasTOF()) { + nSigmaTOF = -9999.99; + } + if (cfgUpdatePID) { + nSigmaTPC = (nSigmaTPC - hTPCCallib->GetBinContent(hTPCCallib->FindBin(track1.p(), centrality, occupancy))) / hTPCCallib->GetBinError(hTPCCallib->FindBin(track1.p(), centrality, occupancy)); + if (track1.hasTOF()) { + nSigmaTOF = (nSigmaTOF - hTOFCallib->GetBinContent(hTOFCallib->FindBin(track1.p(), centrality, occupancy))) / hTOFCallib->GetBinError(hTOFCallib->FindBin(track1.p(), centrality, occupancy)); + } + } + histos.fill(HIST("hNsigmaTPCBeforeCut"), nSigmaTPC, track1.p(), occupancy); + histos.fill(HIST("hNsigmaTOFBeforeCut"), nSigmaTOF, track1.p(), occupancy); + + if (applyPID) { + if (ispTdepPID && !selectionPIDpTdependent(track1, nSigmaTPC, nSigmaTOF)) { + continue; + } + if (!ispTdepPID && !selectionPID(track1, nSigmaTPC, nSigmaTOF)) { + continue; + } + histos.fill(HIST("hNsigmaTPCAfterCut"), nSigmaTPC, track1.p(), occupancy); + histos.fill(HIST("hNsigmaTOFAfterCut"), nSigmaTOF, track1.p(), occupancy); + } + ntrack1 = ntrack1 + 1; + for (auto track2 : Rectrackspart) { + auto track2ID = track2.index(); + if (track2ID <= track1ID) { + continue; + } + if (!selectionTrack(track2)) { + continue; + } + if (!track2.has_mcParticle()) { + continue; + } + if (!selectionPair(track1, track2)) { + continue; + } + if (track1.sign() * track2.sign() > 0) { + continue; + } + + // PID track 2 + double nSigmaTPC2 = track2.tpcNSigmaKa(); + double nSigmaTOF2 = track2.tofNSigmaKa(); + if (!track2.hasTOF()) { + nSigmaTOF2 = -9999.99; + } + if (cfgUpdatePID) { + nSigmaTPC2 = (nSigmaTPC2 - hTPCCallib->GetBinContent(hTPCCallib->FindBin(track2.p(), centrality, occupancy))) / hTPCCallib->GetBinError(hTPCCallib->FindBin(track2.p(), centrality, occupancy)); + if (track2.hasTOF()) { + nSigmaTOF2 = (nSigmaTOF2 - hTOFCallib->GetBinContent(hTOFCallib->FindBin(track2.p(), centrality, occupancy))) / hTOFCallib->GetBinError(hTOFCallib->FindBin(track2.p(), centrality, occupancy)); + } + } + if (ntrack1 == 1) { + histos.fill(HIST("hNsigmaTPCBeforeCut"), nSigmaTPC2, track2.p(), occupancy); + histos.fill(HIST("hNsigmaTOFBeforeCut"), nSigmaTOF2, track2.p(), occupancy); + } + if (applyPID) { + if (ispTdepPID && !selectionPIDpTdependent(track2, nSigmaTPC2, nSigmaTOF2)) { + continue; + } + if (!ispTdepPID && !selectionPID(track2, nSigmaTPC2, nSigmaTOF2)) { + continue; + } + } + if (ntrack1 == 1) { + histos.fill(HIST("hNsigmaTPCAfterCut"), nSigmaTPC2, track2.p(), occupancy); + histos.fill(HIST("hNsigmaTOFAfterCut"), nSigmaTOF2, track2.p(), occupancy); + } + + 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.pdgCode()) != 333) { + continue; + } + if (avoidsplitrackMC && oldindex == mothertrack1.globalIndex()) { + histos.fill(HIST("h1PhiRecsplit"), mothertrack1.pt()); + continue; + } + oldindex = mothertrack1.globalIndex(); + bool crossed1 = keepTrackNoTPCBoundary(track1.phi(), 0.15, 18); + bool crossed2 = keepTrackNoTPCBoundary(track2.phi(), 0.15, 18); + float passsector = -999.0; + if (crossed1 && crossed2) { + passsector = 1.5; + } else { + passsector = 0.5; + } + 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()) < 0.5) { + histos.fill(HIST("hphiSE"), PhiMesonMother.M(), PhiMesonMother.Pt(), centrality, occupancy, passsector); + } + } + } + } + } + // loop over generated particle + for (auto& mcParticle : GenParticles) { + if (TMath::Abs(mcParticle.y()) > 0.5) { + 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) { + PhiMesonMother = KaonPlus + KaonMinus; + if (TMath::Abs(PhiMesonMother.Rapidity()) < 0.5) { + histos.fill(HIST("hphiGen"), PhiMesonMother.M(), PhiMesonMother.Pt(), centrality, occupancy); + } + } + } + } // rec collision loop + + } // process MC + PROCESS_SWITCH(phispectrapbpbqa, processMC, "Process MC", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"phispectrapbpbqa"})}; +} diff --git a/PWGLF/Tasks/Resonances/phitutorial.cxx b/PWGLF/Tasks/Resonances/phitutorial.cxx new file mode 100644 index 00000000000..5e93f7c39bc --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial.cxx @@ -0,0 +1,227 @@ +// 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 phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#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/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); + histos.add("Nch_LSS_Minv", "Nch_LSS_Minv", kTH1F, {MinvAxis}); + + histos.add("Nch_ME_Minv", "Nch_ME_Minv", kTH1F, {MinvAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) + return false; + if (std::abs(event.posZ()) > 10) + return false; + if (!event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + if (!event.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + if (!event.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) + return false; + + return true; + }; + //********************************************// + template + bool trackSelection(const TracksType track) + { + if (!track.isGlobalTrack()) + return false; + if (track.pt() < 0.15) + return false; + if (std::abs(track.eta()) > 1.0) + return false; + + return true; + }; + //********************************************// + template + bool trackPIDKaon(const TrackPID& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + // TPC + if (std::abs(candidate.tpcNSigmaKa()) < 3) + tpcPIDPassed = true; + // TOF + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < 3) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + // TPC & TOF + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + for (const auto& track : tracks) { + histos.fill(HIST("Nch_pT"), track.pt()); + } + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + if (!trackSelection(trk1) || !trackSelection(trk2)) { + continue; + } + if (!trackPIDKaon(trk1) || !trackPIDKaon(trk2)) { + continue; + } + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate < 0) { + histos.fill(HIST("Nch_USS_Minv"), lResonance.M()); + } else { + histos.fill(HIST("Nch_LSS_Minv"), lResonance.M()); + } + } // Invariant mass combinations + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial, processDataSameEvent, "process Data Same Event", false); + + //**************************************************************************************************************************// + + // MIXED EVENT + + //*********************************************************// + // DEFINITION OF SLICE CACHE, BINNING AND MIXING STRUCTURE + //*********************************************************// + Preslice perCollision = aod::track::collisionId; + std::vector zBins{10, -10, 10}; + std::vector multBins{VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}; + using BinningType = ColumnBinningPolicy; + BinningType binning{{zBins, multBins}, true}; + SameKindPair pair{binning, 5, -1, &cache}; + + void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + { + LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); + + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + if (!eventSelection(c1) || !eventSelection(c2)) + continue; + + for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + if (track1.sign() * track2.sign() > 0) + continue; + + if (!trackSelection(track1) || !trackSelection(track2)) { + continue; + } + if (!trackPIDKaon(track1) || !trackPIDKaon(track2)) { + continue; + } + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, mother; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKa); + + mother = lDecayDaughter1 + lDecayDaughter2; + + histos.fill(HIST("Nch_ME_Minv"), mother.M()); + } + } + } // processMixedEvent + PROCESS_SWITCH(phitutorial, processDataMixedEvent, "process Data Mixed Event", false); +}; + +//***************************************// +// TASK COMPLETE! +//**************************************// + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step0.cxx b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx new file mode 100644 index 00000000000..16394389c91 --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx @@ -0,0 +1,134 @@ +// 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 phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#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/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial_step0 { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) // This is required to extract good events + return false; + + return true; + }; + //********************************************// + // Space for more helper functions! + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + // Now, time to start coding the task! + // Keep in mind that: + // M_inv = sqrt( (E1+E2)^2 - |P1 + P2|^2 ) + // Where you use the energies and momenta of the individual Kaons. + + // You should fill: histos.fill(HIST("Minv"), M_inv), calculated as above. + + // Usefull tips: + // E = sqrt(p^2 + m^2). The Kaon mass is found above in the constant massKa + // pz = pT*sinh(eta) + // track.pt() + // track.eta(); + // std::sinh(x) + + // For more concise techinques, check out: + // ROOT::Math::PxPyPzMVector //Check google + // combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy.... //check ALICE O2 documentation + + for (const auto& track : tracks) { + histos.fill(HIST("Nch_pT"), track.pt()); + //.. + //.. + //.. + } + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial_step0, processDataSameEvent, "process Data Same Event", false); + + //***************************************// + // TASK COMPLETE! + //**************************************// +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step1.cxx b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx new file mode 100644 index 00000000000..32b1760b809 --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx @@ -0,0 +1,140 @@ +// 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 phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#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/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial_step1 { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) // This is required to extract good events + return false; + + return true; + }; + //********************************************// + // Space for more helper functions! + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + // Now, we want to add some kind of filter for our tracks! + // Tracks we want to accept: + // track.isGlobalTrack() <.... this menas that it is a good track + // track.pt() >0.15 <.... we want to remove really low momentum tracks + // -0.8 0.15f; + // then you have to modify the subscription + // soa::Filtered const& tracks + + for (const auto& track : tracks) { + histos.fill(HIST("Nch_pT"), track.pt()); + } + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate < 0) { + histos.fill(HIST("Nch_USS_Minv"), lResonance.M()); + } + } // Invariant mass combinations + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial_step1, processDataSameEvent, "process Data Same Event", false); + + //***************************************// + // TASK COMPLETE! + //**************************************// +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step2.cxx b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx new file mode 100644 index 00000000000..0a97f6d1afe --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx @@ -0,0 +1,161 @@ +// 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 phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#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/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial_step2 { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) // This is required to extract good events + return false; + + return true; + }; + //********************************************// + template + bool trackSelection(const TracksType track) + { + if (!track.isGlobalTrack()) + return false; + if (track.pt() < 0.15) + return false; + if (std::abs(track.eta()) > 1.0) + return false; + + return true; + }; + // Space for more helper functions! + //********************************************// + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + // Now, we want to add some PID to ensure that we are with a higher likelhood pairing Kaons. + // Three ways to do this: + // 1.) Directly cut on the tracks in the looping functions (not recommended) + + // 2.) Create a helper function above similar to trackSelection + + // 3.) Partition your tracks with a preselection by adding this outside of your process function: + // Partition kaon (nabs(aod::pidtpc::tpcNSigmaKa) <= X); // X is a cfg value or a hardcoded integer. + // Then inside the function: auto tracks1 = kaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); Do the same for tracks2. + + // Getters for PID: + // tracks.tpcNSigmaKa() + // tracks.tofNSigmaKa() + // Good starting value for the selected nsigma value is "3". + // You might not want to have a STRICT TOF cut, a lot of tracks with good TPC PID does not have TOF information. You can make a conditional cut on TOF by only implementing the TOF cut if track.hasTOF() returns TRUE. + + for (const auto& track : tracks) { + if (!trackSelection(track)) { + continue; + } + histos.fill(HIST("Nch_pT"), track.pt()); + } + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + if (!trackSelection(trk1) || !trackSelection(trk2)) { + continue; + } + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate < 0) { + histos.fill(HIST("Nch_USS_Minv"), lResonance.M()); + } + } // Invariant mass combinations + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial_step2, processDataSameEvent, "process Data Same Event", false); + + //***************************************// + // TASK COMPLETE! + //**************************************// +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx new file mode 100644 index 00000000000..1ccf59aa9c2 --- /dev/null +++ b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx @@ -0,0 +1,211 @@ +// 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 phitutorial.cxx +/// \brief Phi meson analysis tutorial +/// \author Adrian Fereydon Nassirpour + +// IMPORTANT INCLUDES +#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/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include + +// ROOT Includes (optional) +#include + +// C++ includes +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// MAIN STRUCT +struct phitutorial_step3 { + + //*************************************// + // SLICECACHE AND REGISTRY DEFS + //*************************************// + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + //*************************************// + // INIT FUNCTION AND HISTOGRAM BOOKING + //*************************************// + void init(o2::framework::InitContext&) + { + const AxisSpec ptAxis = {200, 0, 20.0}; + const AxisSpec MinvAxis = {200, 0.85, 1.25}; + + histos.add("Nch_pT", "Nch_pT", kTH1F, {ptAxis}); + histos.add("Nch_USS_Minv", "Nch_USS_Minv", kTH1F, {MinvAxis}); + + histos.add("Nch_LSS_Minv", "Nch_LSS_Minv", kTH1F, {MinvAxis}); + + histos.add("Nch_ME_Minv", "Nch_ME_Minv", kTH1F, {MinvAxis}); + + }; // end of init + + //*************************************// + // TIME TO BUILD TRACK AND EVENT CANDIDATES + //*************************************// + using EventCandidates = soa::Join; + using TrackCandidates = soa::Join; + double massKa = o2::constants::physics::MassKPlus; + + //***************************************// + // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS + //**************************************// + template + bool eventSelection(const EventType event) + { + if (!event.sel8()) // This is required to extract good events + return false; + + return true; + }; + //********************************************// + template + bool trackSelection(const TracksType track) + { + if (!track.isGlobalTrack()) + return false; + if (track.pt() < 0.15) + return false; + if (std::abs(track.eta()) > 1.0) + return false; + + return true; + }; + + //********************************************// + + template + bool trackPIDKaon(const TrackPID& candidate) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + // TPC + if (std::abs(candidate.tpcNSigmaKa()) < 3) + tpcPIDPassed = true; + // TOF + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < 3) { + tofPIDPassed = true; + } + } else { + tofPIDPassed = true; + } + // TPC & TOF + if (tpcPIDPassed && tofPIDPassed) { + return true; + } + return false; + } + + //********************************************// + // HELPER FCNS COMPLETE, NOW WE DO PROCESS FCNS + //********************************************// + + // SAME EVENT + int nEvents = 0; + void processDataSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + nEvents++; + if ((nEvents + 1) % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + + if (!eventSelection(collision)) + return; + + // Last step, we want to remove the cominbatorial background to get a clean peak. We want to fill our new two booked historams, Nch_LSS_Minv and Nch_ME_Minv + + // LSS is easy, you simply need to fill the histogram if the conjugate argument below is NOT true. + // For event mixing, we have to now copy our logic into a new process function below, and iterate over track pairs between different events! + + for (const auto& track : tracks) { + if (!trackSelection(track)) { + continue; + } + histos.fill(HIST("Nch_pT"), track.pt()); + } + + for (const auto& [trk1, trk2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { + if (!trackSelection(trk1) || !trackSelection(trk2)) { + continue; + } + if (!trackPIDKaon(trk1) || !trackPIDKaon(trk2)) { + continue; + } + + ROOT::Math::PxPyPzMVector lDecayDaughter1, lDecayDaughter2, lResonance; + lDecayDaughter1 = ROOT::Math::PxPyPzMVector(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2 = ROOT::Math::PxPyPzMVector(trk2.px(), trk2.py(), trk2.pz(), massKa); + + lResonance = lDecayDaughter1 + lDecayDaughter2; + double conjugate = trk1.sign() * trk2.sign(); + if (conjugate < 0) { + histos.fill(HIST("Nch_USS_Minv"), lResonance.M()); + } + } // Invariant mass combinations + + } // proccessSameEvent + PROCESS_SWITCH(phitutorial_step3, processDataSameEvent, "process Data Same Event", false); + + //**************************************************************************************************************************// + + // MIXED EVENT + + //*********************************************************// + // DEFINITION OF SLICE CACHE, BINNING AND MIXING STRUCTURE + //*********************************************************// + Preslice perCollision = aod::track::collisionId; + // We ensure here that we mix events that have relatively similar characteristics. + std::vector zBins{10, -10, 10}; + std::vector multBins{VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}; + using BinningType = ColumnBinningPolicy; + BinningType binning{{zBins, multBins}, true}; + SameKindPair pair{binning, 5, -1, &cache}; + + void processDataMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) // notice the collisions subscrition, it is not an iterator here! + { + LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); + + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + + if (!eventSelection(c1) || !eventSelection(c2)) + continue; + // Fill your event mixing logic here. + //.. + //.. + //.. + } // pairs + } // processMixedEvent + PROCESS_SWITCH(phitutorial_step3, processDataMixedEvent, "process Data Mixed Event", false); + + //***************************************// + // TASK COMPLETE! + //**************************************// +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +}; diff --git a/PWGLF/Tasks/Resonances/rho770analysis.cxx b/PWGLF/Tasks/Resonances/rho770analysis.cxx new file mode 100644 index 00000000000..48ba715031d --- /dev/null +++ b/PWGLF/Tasks/Resonances/rho770analysis.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. +/// +/// \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 "PWGLF/DataModel/LFResonanceTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include + +#include "TVector2.h" +#include + +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/rhoanalysis.cxx b/PWGLF/Tasks/Resonances/rhoanalysis.cxx index ab1112f4995..f4f6edf4a2b 100644 --- a/PWGLF/Tasks/Resonances/rhoanalysis.cxx +++ b/PWGLF/Tasks/Resonances/rhoanalysis.cxx @@ -15,23 +15,26 @@ /// /// \author Nasir Mehdi Malik -#include +#include "RecoDecay.h" -#include +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/RecoDecay.h" +#include "Framework/DataProcessorSpec.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "RecoDecay.h" +#include "Framework/runDataProcessing.h" + +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Resonances/rsnanalysis.cxx b/PWGLF/Tasks/Resonances/rsnanalysis.cxx index 7a672fe59a8..f147a0453fc 100644 --- a/PWGLF/Tasks/Resonances/rsnanalysis.cxx +++ b/PWGLF/Tasks/Resonances/rsnanalysis.cxx @@ -15,11 +15,14 @@ // O2 includes #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" -#include "Framework/ASoAHelpers.h" + #include "TLorentzVector.h" using namespace std; diff --git a/PWGLF/Tasks/Resonances/sigma.cxx b/PWGLF/Tasks/Resonances/sigma.cxx index 9bcad07c143..1f63688627a 100644 --- a/PWGLF/Tasks/Resonances/sigma.cxx +++ b/PWGLF/Tasks/Resonances/sigma.cxx @@ -11,30 +11,19 @@ /// /// \brief sigma resonance /// \author sarjeeta gami (sarjeeta.gami@cern.ch) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" #include "CommonConstants/PhysicsConstants.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" @@ -42,9 +31,23 @@ #include "Framework/HistogramRegistry.h" #include "Framework/StepTHn.h" #include "Framework/runDataProcessing.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "ReconstructionDataFormats/Track.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/PWGLF/Tasks/Resonances/xi1530Analysis.cxx b/PWGLF/Tasks/Resonances/xi1530Analysis.cxx index be3c24b8ffb..beab4136e78 100644 --- a/PWGLF/Tasks/Resonances/xi1530Analysis.cxx +++ b/PWGLF/Tasks/Resonances/xi1530Analysis.cxx @@ -13,19 +13,22 @@ /// \brief Invariant Mass Reconstruction of Xi(1530) Resonance /// \author Yash Patley -#include -#include +#include "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Framework/AnalysisTask.h" + +#include "CommonConstants/PhysicsConstants.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.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 +#include + +#include using namespace o2; using namespace o2::framework; @@ -342,7 +345,7 @@ struct cascadeXiAnalysis { for (auto const& casc : cascTracks) { 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_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()); @@ -350,7 +353,7 @@ struct cascadeXiAnalysis { 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()); + histos.fill(HIST("QA_Casc_Xi/h1d_dca_casc_dau"), casc.cascDaughDCA()); } fillDataHisto(cascTracks, resoTracks, resoCollision.cent()); diff --git a/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx b/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx new file mode 100644 index 00000000000..aa98e9fc9b7 --- /dev/null +++ b/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx @@ -0,0 +1,1296 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFResonanceTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; +using LorentzVectorPtEtaPhiMass = ROOT::Math::PtEtaPhiMVector; +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; + Preslice perResoCollision = + aod::resodaughter::resoCollisionId; + Preslice perResoCollisionCasc = + aod::resodaughter::resoCollisionId; + 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, 15.0, 20.0, 30.0, 40.0, 50.0, 70.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"}; + + // 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", 80, "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"}; //refit is included in global track selection + // 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"}; + + Configurable cMinTOFpt{"cMinTOFpt", 0.5, "Maximum TOF pt cut"}; + + // 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"}; + + //*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*// + + // 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 studyStableXi{"studyStableXi", false, "Study stable Xi"}; + + Configurable cMCCent{"cMCCent", true, "Using calibrated MC centrality (for FT0M)"}; + Configurable cRecoINELgt0{"cRecoINELgt0", true, "check if INEL>0 for reco events"}; + 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"}; + + { + // 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, {centAxis}); + + 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, {centAxis}); + } + + 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 (doprocessMEDF || doprocessMEMicro) { + 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}); + } + + // 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 (doprocessMEDF || doprocessMEMicro) { + 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::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags())) > (cDCAxytoPVByPtPiFirstP0 + cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.1))) + return false; + if (cDCAzToPVAsPt) { + if (std::abs(o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags())) > (cDCAxytoPVByPtPiFirstP0 + cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.1))) + return false; + } else { + if (std::abs(o2::aod::resomicrodaughter::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) + { + 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 // + + // 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, float trackPt) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + + if (tofAtHighPt && trackPt > cMinTOFpt) { + 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; + } 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) + { + + float tpcNsigmaPionFirst, tofNsigmaPionFirst; + float trackPt = candidate.pt(); + + if constexpr (IsResoMicrotrack) { + tpcNsigmaPionFirst = o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPiFlag()); + tofNsigmaPionFirst = o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaPiFlag()); + } else { + tpcNsigmaPionFirst = candidate.tpcNSigmaPi(); + tofNsigmaPionFirst = candidate.tofNSigmaPi(); + } + + PidSelectionParam pionFirstParams = {cMaxtpcnSigmaPionFirst, cMaxtofnSigmaPionFirst, cByPassTOFPionFirst, nsigmaCutCombinedPionFirst}; + + return pidSelector(tpcNsigmaPionFirst, tofNsigmaPionFirst, pionFirstParams, tofAtHighPt, trackPt); + } + + template + bool selectionPIDCascades(const TCascade& candidate) + { + bool lConsistentWithXi{false}, lConsistentWithLambda{false}, lConsistentWithPion{false}, lConsistentWithProton{false}; + + float tpcNsigmaBachelor, tofNsigmaBachelor; + float tpcNsigmaPion, tofNsigmaPion; + float tpcNsigmaProton, tofNsigmaProton; + float trackPt = candidate.pt(); + + 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, trackPt); + lConsistentWithPion = pidSelector(tpcNsigmaPion, tofNsigmaPion, pionParams, tofAtHighPt, trackPt); + lConsistentWithProton = pidSelector(tpcNsigmaProton, tofNsigmaProton, protonParams, tofAtHighPt, trackPt); + + lConsistentWithLambda = lConsistentWithProton && lConsistentWithPion; + + return lConsistentWithXi && lConsistentWithLambda; + } + + template + void fillHistograms(const CollisionType& collision, const CenMult& multiplicity, const TracksType& dTracks1, const TracksTypeCasc& dTracks2) // Order: ResoColl, ResoTrack, ResoCascTrack + { + // auto multiplicity = collision.cent(); + + { + 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()); + } + } + + LorentzVectorPtEtaPhiMass lDecayDaughter1, lDecayDaughter2, lResonance; // It will be replaced to use RecoDecay (In fixing...) + + for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { + + { + 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::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(trk1.trackSelectionFlags()); + trk1DCAZ = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(trk1.trackSelectionFlags()); + trk1NSigmaPiTPC = o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk1.pidNSigmaPiFlag()); + trk1NSigmaPiTOF = o2::aod::resomicrodaughter::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 // + // --- 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); + } + + 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; + + 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 = LorentzVectorPtEtaPhiMass(trk1ptPi, trk1.eta(), trk1.phi(), massPi); + lDecayDaughter2 = LorentzVectorPtEtaPhiMass(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::ResoCollisionColls const& collisionIndex, + soa::Join const& collisions, + aod::ResoTracks const& resoTracks, + aod::ResoCascades const& cascTracks) + { + if (cRecoINELgt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisions.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + } + + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + auto multiplicity = resoCollision.cent(); + fillHistograms(resoCollision, multiplicity, resoTracks, cascTracks); + } + + // Reconstructed level MC for the track + void processMC(ResoMCCols::iterator const& resoCollision, + aod::ResoCollisionColls const& collisionIndex, + soa::Join const& collisionsMC, + soa::Join const& cascTracks, + soa::Join const& resoTracks, + soa::Join const&) + { + float multiplicity; + if (cMCCent && cRecoINELgt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + + auto mcColl = coll.mcCollision_as>(); + multiplicity = mcColl.centFT0M(); + } else if (!cMCCent && cRecoINELgt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + + multiplicity = resoCollision.cent(); + } else if (cMCCent && !cRecoINELgt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + auto mcColl = coll.mcCollision_as>(); + multiplicity = mcColl.centFT0M(); + } else { + multiplicity = resoCollision.cent(); + } + + if (!resoCollision.isInAfterAllCuts() || (std::abs(resoCollision.posZ()) > cZvertCutMC)) // MC event selection, all cuts missing vtx cut + return; + + fillHistograms(resoCollision, multiplicity, resoTracks, cascTracks); + } + + // Truth level MC for the track with reco event + void processMCTrue(ResoMCCols::iterator const& resoCollision, + aod::ResoCollisionColls const& collisionIndex, + aod::ResoMCParents const& resoParents, + aod::ResoCollisionCandidatesMC const& collisionsMC, + soa::Join const&) + { + float multiplicity; + if (cMCCent && cRecoINELgt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + + auto mcColl = coll.mcCollision_as>(); + multiplicity = mcColl.centFT0M(); + } else if (!cMCCent && cRecoINELgt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + + multiplicity = resoCollision.cent(); + } else if (cMCCent && !cRecoINELgt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisionsMC.iteratorAt(collId); // Take original collision matched with resoCollision + + auto mcColl = coll.mcCollision_as>(); + multiplicity = mcColl.centFT0M(); + } else { + 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 (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::ResoCollisionColls const& collisionIndex, + soa::Join const& collisions, + aod::ResoMicroTracks const& resomicrotracks, + aod::ResoCascades const& cascTracks) + { + if (cRecoINELgt0) { + auto linkRow = collisionIndex.iteratorAt(resoCollision.globalIndex()); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisions.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + return; + } + + histos.fill(HIST("QAevent/hEvtCounterSameE"), 1.0); + auto multiplicity = resoCollision.cent(); + fillHistograms(resoCollision, multiplicity, resomicrotracks, cascTracks); + } + + using BinningTypeVtxZT0M = ColumnBinningPolicy; + Preslice perRColdf = aod::resodaughter::resoCollisionDFId; + Preslice perRColdfCasc = aod::resodaughter::resoCollisionDFId; + + void processMEDF(aod::ResoCollisionDFs const& resoCollisions, aod::ResoTrackDFs const& resotracks, aod::ResoCascadeDFs const& cascTracks) + { + + auto tracksTuple = std::make_tuple(resotracks, cascTracks); + + BinningTypeVtxZT0M colBinning{{cfgVtxBins, cfgMultBins}, true}; + Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + auto multiplicity = collision1.cent(); + fillHistograms(collision1, multiplicity, tracks1, tracks2); + } + } + void processDataDF(aod::ResoCollisionDF const& resoCollision, aod::ResoTrackDFs const& resotracks, aod::ResoCascadeDFs const& cascTracks) + { + auto multiplicity = resoCollision.cent(); + fillHistograms(resoCollision, multiplicity, resotracks, cascTracks); + } + + void processMEMicro(aod::ResoCollisions const& resoCollisions, + aod::ResoCollisionColls const& collisionIndex, + soa::Join const& collisions, + 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 (cRecoINELgt0) { + const auto rcIdx = collision1.globalIndex(); + auto linkRow = collisionIndex.iteratorAt(rcIdx); + auto collId = linkRow.collisionId(); // Take original collision global index matched with resoCollision + + auto coll = collisions.iteratorAt(collId); // Take original collision matched with resoCollision + + if (!coll.isInelGt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + continue; + } + histos.fill(HIST("QAevent/hEvtCounterMixedE"), 1.0); + auto multiplicity = collision1.cent(); + fillHistograms(collision1, multiplicity, 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)", false); + PROCESS_SWITCH(Xi1530Analysisqa, processMEMicro, "Process EventMixing (MicroTrack) ", false); + PROCESS_SWITCH(Xi1530Analysisqa, processMEDF, "Process EventMixing (DF) ", true); + PROCESS_SWITCH(Xi1530Analysisqa, processDataDF, "Process Event for Data (DF) ", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/xi1820Analysis.cxx b/PWGLF/Tasks/Resonances/xi1820Analysis.cxx new file mode 100644 index 00000000000..997c68a5015 --- /dev/null +++ b/PWGLF/Tasks/Resonances/xi1820Analysis.cxx @@ -0,0 +1,1109 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file xi1820Analysis.cxx +/// \brief Invariant Mass Reconstruction of Xi(1820) Resonance +/// \author Bong-Hwi Lim + +#include "PWGLF/DataModel/LFResonanceTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct Xi1820Analysis { + SliceCache cache; + Preslice perResoCollisionV0 = aod::resodaughter::resoCollisionId; + Preslice perResoCollisionTrack = aod::resodaughter::resoCollisionId; + Preslice perResoCollisionMicroTrack = aod::resodaughter::resoCollisionId; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Constants + static constexpr float kSmallMomentumDenominator = 1e-10f; // Small value to avoid division by zero + static constexpr float kMaxDcaToPv = 1.0f; // Maximum DCA to primary vertex + static constexpr int kPdgXi1820 = 123314; // o2-linter: disable=pdg/explicit-code (Xi(1820) PDG code not available in PDG_t or o2::constants::physics::Pdg) + static constexpr int kExpectedDaughters = 2; // Expected number of daughters for two-body decay + + // Axes + ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 10.0}, "pT"}; + ConfigurableAxis binsPtQA{"binsPtQA", {VARIABLE_WIDTH, 0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0}, "pT (QA)"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Centrality"}; + + // Invariant mass range for Xi(1820) → Λ + K + Configurable cInvMassStart{"cInvMassStart", 1.6, "Invariant mass start (GeV/c^2)"}; + Configurable cInvMassEnd{"cInvMassEnd", 2.2, "Invariant mass end (GeV/c^2)"}; + Configurable cInvMassBins{"cInvMassBins", 600, "Invariant mass bins"}; + + // Basic pre-selections + Configurable cMinPtcut{"cMinPtcut", 0.15, "Minimum pT for candidates"}; + Configurable cMaxEtaCut{"cMaxEtaCut", 0.8, "Maximum |eta|"}; + + // Kaon track selections + Configurable cKaonPtMin{"cKaonPtMin", 0.15, "Minimum kaon pT"}; + Configurable cKaonEtaMax{"cKaonEtaMax", 0.8, "Maximum kaon |eta|"}; + Configurable cKaonDCAxyMax{"cKaonDCAxyMax", 0.1, "Maximum kaon DCAxy to PV"}; + Configurable cKaonDCAzMax{"cKaonDCAzMax", 0.2, "Maximum kaon DCAz to PV"}; + Configurable cKaonTPCRefit{"cKaonTPCRefit", true, "Require TPC refit for kaon"}; + Configurable cKaonITSRefit{"cKaonITSRefit", true, "Require ITS refit for kaon"}; + Configurable cKaonTPCNClusMin{"cKaonTPCNClusMin", 70, "Minimum TPC clusters for kaon"}; + Configurable cKaonITSNClusMin{"cKaonITSNClusMin", 2, "Minimum ITS clusters for kaon"}; + + // Kaon PID selections + Configurable cKaonTPCNSigmaMax{"cKaonTPCNSigmaMax", 3.0, "Maximum TPC NSigma for kaon (if not using pT-dependent)"}; + Configurable cKaonTOFNSigmaMax{"cKaonTOFNSigmaMax", 3.0, "Maximum TOF NSigma for kaon (if not using pT-dependent)"}; + Configurable cKaonUsePtDepPID{"cKaonUsePtDepPID", false, "Use pT-dependent PID cuts"}; + Configurable> cKaonPIDPtBins{"cKaonPIDPtBins", {0.0f, 0.5f, 0.8f, 2.0f, 999.0f}, "pT bin edges for PID cuts (N+1 values for N bins)"}; + Configurable> cKaonTPCNSigmaCuts{"cKaonTPCNSigmaCuts", {3.0f, 3.0f, 2.0f, 2.0f}, "TPC NSigma cuts per pT bin (N values)"}; + Configurable> cKaonTOFNSigmaCuts{"cKaonTOFNSigmaCuts", {3.0f, 3.0f, 3.0f, 3.0f}, "TOF NSigma cuts per pT bin (N values)"}; + Configurable> cKaonTOFRequired{"cKaonTOFRequired", {0, 0, 1, 1}, "Require TOF per pT bin (N values, 0=false, 1=true)"}; + + // V0 (Lambda) selections + Configurable cV0MinCosPA{"cV0MinCosPA", 0.995, "V0 minimum pointing angle cosine"}; + Configurable cV0MaxDaughDCA{"cV0MaxDaughDCA", 1.0, "V0 daughter DCA Maximum"}; + Configurable cV0MassWindow{"cV0MassWindow", 0.005, "Mass window for Lambda selection"}; + Configurable cMaxV0Etacut{"cMaxV0Etacut", 0.8, "V0 maximum eta cut"}; + Configurable cV0RadiusMin{"cV0RadiusMin", 0.5, "V0 decay radius min"}; + Configurable cV0RadiusMax{"cV0RadiusMax", 200.0, "V0 decay radius max"}; + Configurable cV0DauPosDCAtoPVMin{"cV0DauPosDCAtoPVMin", 0.05, "V0 positive daughter DCA to PV min"}; + Configurable cV0DauNegDCAtoPVMin{"cV0DauNegDCAtoPVMin", 0.05, "V0 negative daughter DCA to PV min"}; + Configurable cV0ProperLifetimeMax{"cV0ProperLifetimeMax", 30.0, "Lambda proper lifetime max (cm/c)"}; + + // K0s selections + Configurable cK0sMinCosPA{"cK0sMinCosPA", 0.97, "K0s minimum pointing angle cosine"}; + Configurable cK0sMaxDaughDCA{"cK0sMaxDaughDCA", 1.0, "K0s daughter DCA Maximum"}; + Configurable cK0sMassWindow{"cK0sMassWindow", 0.0043, "Mass window for K0s selection"}; + Configurable cK0sProperLifetimeMax{"cK0sProperLifetimeMax", 20.0, "K0s proper lifetime max (cm/c)"}; + Configurable cK0sArmenterosQtMin{"cK0sArmenterosQtMin", 0.0, "K0s Armenteros qt min"}; + Configurable cK0sArmenterosAlphaMax{"cK0sArmenterosAlphaMax", 0.8, "K0s Armenteros alpha max"}; + Configurable cK0sDauPosDCAtoPVMin{"cK0sDauPosDCAtoPVMin", 0.1, "K0s positive daughter DCA to PV min"}; + Configurable cK0sDauNegDCAtoPVMin{"cK0sDauNegDCAtoPVMin", 0.1, "K0s negative daughter DCA to PV min"}; + Configurable cK0sRadiusMin{"cK0sRadiusMin", 0.5, "K0s decay radius min"}; + Configurable cK0sRadiusMax{"cK0sRadiusMax", 100.0, "K0s decay radius max"}; + Configurable cK0sCrossMassRejection{"cK0sCrossMassRejection", true, "Enable Lambda mass rejection for K0s"}; + + // 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 - centrality"}; + + // Track type selection + Configurable cUseMicroTracks{"cUseMicroTracks", false, "Use ResoMicroTracks instead of ResoTracks"}; + + using BinningTypeVertexContributor = ColumnBinningPolicy; + BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; + + void init(InitContext&) + { + AxisSpec centAxis = {binsCent, "V0M (%)"}; + 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 lambdaMassAxis = {200, 1.08, 1.16, "#Lambda mass (GeV/#it{c}^{2})"}; + AxisSpec dcaAxis = {200, 0., 2.0, "DCA (cm)"}; + AxisSpec dcaxyAxis = {200, -1.0, 1.0, "DCA_{xy} (cm)"}; + AxisSpec dcazAxis = {200, -2.0, 2.0, "DCA_{z} (cm)"}; + AxisSpec cosPAAxis = {1000, 0.95, 1.0, "cos(PA)"}; + AxisSpec radiusAxis = {200, 0, 200, "Radius (cm)"}; + AxisSpec lifetimeAxis = {200, 0, 50, "Proper lifetime (cm/c)"}; + AxisSpec nsigmaAxis = {100, -5.0, 5.0, "N#sigma"}; + + // Event QA histograms + histos.add("Event/posZ", "Event vertex Z position", kTH1F, {{200, -20., 20., "V_{z} (cm)"}}); + histos.add("Event/centrality", "Event centrality distribution", kTH1F, {centAxis}); + histos.add("Event/posZvsCent", "Vertex Z vs Centrality", kTH2F, {{200, -20., 20., "V_{z} (cm)"}, centAxis}); + histos.add("Event/nV0s", "Number of V0s per event", kTH1F, {{200, 0., 200., "N_{V0s}"}}); + histos.add("Event/nKaons", "Number of kaons per event", kTH1F, {{200, 0., 200., "N_{kaons}"}}); + histos.add("Event/nV0sAfterCuts", "Number of V0s per event after cuts", kTH1F, {{100, 0., 100., "N_{V0s}"}}); + histos.add("Event/nKaonsAfterCuts", "Number of kaons per event after cuts", kTH1F, {{100, 0., 100., "N_{kaons}"}}); + + // Lambda QA histograms + histos.add("QAbefore/lambdaMass", "Lambda mass before cuts", kTH1F, {lambdaMassAxis}); + histos.add("QAbefore/lambdaPt", "Lambda pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/lambdaEta", "Lambda eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/lambdaCosPA", "Lambda CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAbefore/lambdaRadius", "Lambda radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAbefore/lambdaDauDCA", "Lambda daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/lambdaProperLifetime", "Lambda proper lifetime before cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + histos.add("QAbefore/lambdaDauPosDCA", "Lambda positive daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/lambdaDauNegDCA", "Lambda negative daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + + histos.add("QAafter/lambdaMass", "Lambda mass after cuts", kTH1F, {lambdaMassAxis}); + histos.add("QAafter/lambdaPt", "Lambda pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/lambdaEta", "Lambda eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/lambdaCosPA", "Lambda CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAafter/lambdaRadius", "Lambda radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAafter/lambdaDauDCA", "Lambda daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/lambdaProperLifetime", "Lambda proper lifetime after cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + histos.add("QAafter/lambdaDauPosDCA", "Lambda positive daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/lambdaDauNegDCA", "Lambda negative daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + + // Kaon QA histograms + histos.add("QAbefore/kaonPt", "Kaon pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/kaonEta", "Kaon eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/kaonDCAxy", "Kaon DCAxy before cuts", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAbefore/kaonDCAz", "Kaon DCAz before cuts", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAbefore/kaonTPCNcls", "Kaon TPC clusters before cuts", kTH1F, {{160, 0, 160, "N_{TPC clusters}"}}); + histos.add("QAbefore/kaonITSNcls", "Kaon ITS clusters before cuts", kTH1F, {{10, 0, 10, "N_{ITS clusters}"}}); + histos.add("QAbefore/kaonTPCNSigma", "Kaon TPC NSigma before cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("QAbefore/kaonTOFNSigma", "Kaon TOF NSigma before cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + + histos.add("QAafter/kaonPt", "Kaon pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/kaonEta", "Kaon eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/kaonDCAxy", "Kaon DCAxy after cuts", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAafter/kaonDCAz", "Kaon DCAz after cuts", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAafter/kaonTPCNcls", "Kaon TPC clusters after cuts", kTH1F, {{160, 0, 160, "N_{TPC clusters}"}}); + histos.add("QAafter/kaonITSNcls", "Kaon ITS clusters after cuts", kTH1F, {{10, 0, 10, "N_{ITS clusters}"}}); + histos.add("QAafter/kaonTPCNSigma", "Kaon TPC NSigma after cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("QAafter/kaonTOFNSigma", "Kaon TOF NSigma after cuts", kTH2F, {ptAxisQA, nsigmaAxis}); + + // Resonance histograms - 4 combinations + // K+ Lambda + histos.add("xi1820/kplus_lambda/hInvMassKplusLambda", "Invariant mass of Xi(1820) → K^{+} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/kplus_lambda/hInvMassKplusLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{+} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/kplus_lambda/hMassPtCentKplusLambda", "Xi(1820) mass vs pT vs cent (K^{+}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{+}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); + + // K+ Anti-Lambda + histos.add("xi1820/kplus_antilambda/hInvMassKplusAntiLambda", "Invariant mass of Xi(1820) → K^{+} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{+} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda", "Xi(1820) mass vs pT vs cent (K^{+}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{+}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); + + // K- Lambda + histos.add("xi1820/kminus_lambda/hInvMassKminusLambda", "Invariant mass of Xi(1820) → K^{-} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/kminus_lambda/hInvMassKminusLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{-} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/kminus_lambda/hMassPtCentKminusLambda", "Xi(1820) mass vs pT vs cent (K^{-}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{-}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); + + // K- Anti-Lambda + histos.add("xi1820/kminus_antilambda/hInvMassKminusAntiLambda", "Invariant mass of Xi(1820) → K^{-} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{-} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda", "Xi(1820) mass vs pT vs cent (K^{-}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{-}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); + + // K0s + Lambda + histos.add("xi1820/k0s_lambda/hInvMassK0sLambda", "Invariant mass of Xi(1820) → K^{0}_{S} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/k0s_lambda/hInvMassK0sLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{0}_{S} + #Lambda", kTH1F, {invMassAxis}); + histos.add("xi1820/k0s_lambda/hMassPtCentK0sLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/k0s_lambda/hMassPtCentK0sLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{0}_{S}#Lambda)", kTH3F, {invMassAxis, ptAxis, centAxis}); + + // K0s + Anti-Lambda + histos.add("xi1820/k0s_antilambda/hInvMassK0sAntiLambda", "Invariant mass of Xi(1820) → K^{0}_{S} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/k0s_antilambda/hInvMassK0sAntiLambda_Mix", "Mixed event Invariant mass of Xi(1820) → K^{0}_{S} + #bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); + histos.add("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda})", kTH3F, {invMassAxis, ptAxis, centAxis}); + + // MC truth histograms + AxisSpec etaAxis = {100, -2.0, 2.0, "#eta"}; + AxisSpec rapidityAxis = {100, -2.0, 2.0, "y"}; + + histos.add("MC/hMCGenXi1820Pt", "MC Generated Xi(1820) pT", kTH1F, {ptAxis}); + histos.add("MC/hMCGenXi1820PtEta", "MC Generated Xi(1820) pT vs eta", kTH2F, {ptAxis, etaAxis}); + histos.add("MC/hMCGenXi1820Y", "MC Generated Xi(1820) rapidity", kTH1F, {rapidityAxis}); + histos.add("MC/hMCRecXi1820Pt", "MC Reconstructed Xi(1820) pT", kTH1F, {ptAxis}); + histos.add("MC/hMCRecXi1820PtEta", "MC Reconstructed Xi(1820) pT vs eta", kTH2F, {ptAxis, etaAxis}); + + // MC truth invariant mass (from MC particles) + histos.add("MC/hMCTruthInvMassKplusLambda", "MC Truth Inv Mass K^{+}#Lambda", kTH1F, {invMassAxis}); + histos.add("MC/hMCTruthInvMassKminusAntiLambda", "MC Truth Inv Mass K^{-}#bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("MC/hMCTruthInvMassK0sLambda", "MC Truth Inv Mass K^{0}_{S}#Lambda", kTH1F, {invMassAxis}); + histos.add("MC/hMCTruthInvMassK0sAntiLambda", "MC Truth Inv Mass K^{0}_{S}#bar{#Lambda}", kTH1F, {invMassAxis}); + + // MC truth invariant mass vs pT (2D) + histos.add("MC/hMCTruthMassPtKplusLambda", "MC Truth Mass vs pT K^{+}#Lambda", kTH2F, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtKminusAntiLambda", "MC Truth Mass vs pT K^{-}#bar{#Lambda}", kTH2F, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtK0sLambda", "MC Truth Mass vs pT K^{0}_{S}#Lambda", kTH2F, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtK0sAntiLambda", "MC Truth Mass vs pT K^{0}_{S}#bar{#Lambda}", kTH2F, {invMassAxis, ptAxis}); + + // K0s QA histograms + histos.add("QAbefore/k0sMass", "K0s mass before cuts", kTH1F, {{100, 0.4, 0.6, "K^{0}_{S} mass (GeV/#it{c}^{2})"}}); + histos.add("QAbefore/k0sPt", "K0s pT before cuts", kTH1F, {ptAxisQA}); + histos.add("QAbefore/k0sEta", "K0s eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAbefore/k0sCosPA", "K0s CosPA before cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAbefore/k0sRadius", "K0s radius before cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAbefore/k0sDauDCA", "K0s daughter DCA before cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAbefore/k0sProperLifetime", "K0s proper lifetime before cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + + histos.add("QAafter/k0sMass", "K0s mass after cuts", kTH1F, {{100, 0.4, 0.6, "K^{0}_{S} mass (GeV/#it{c}^{2})"}}); + histos.add("QAafter/k0sPt", "K0s pT after cuts", kTH1F, {ptAxisQA}); + histos.add("QAafter/k0sEta", "K0s eta after cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); + histos.add("QAafter/k0sCosPA", "K0s CosPA after cuts", kTH2F, {ptAxisQA, cosPAAxis}); + histos.add("QAafter/k0sRadius", "K0s radius after cuts", kTH2F, {ptAxisQA, radiusAxis}); + histos.add("QAafter/k0sDauDCA", "K0s daughter DCA after cuts", kTH2F, {ptAxisQA, dcaAxis}); + histos.add("QAafter/k0sProperLifetime", "K0s proper lifetime after cuts", kTH2F, {ptAxisQA, lifetimeAxis}); + } + + // Lambda/Anti-Lambda selection + template + bool v0Cut(const CollisionType& collision, const V0Type& v0, bool isLambda) + { + // Basic kinematic cuts + if (std::abs(v0.eta()) > cMaxV0Etacut) + return false; + if (v0.pt() < cMinPtcut) + return false; + + // Topological cuts + if (v0.v0CosPA() < cV0MinCosPA) + return false; + if (v0.daughDCA() > cV0MaxDaughDCA) + return false; + + // Daughter DCA to PV cuts + if (std::abs(v0.dcapostopv()) < cV0DauPosDCAtoPVMin) + return false; + if (std::abs(v0.dcanegtopv()) < cV0DauNegDCAtoPVMin) + return false; + + // Radius cuts + auto radius = v0.transRadius(); + if (radius < cV0RadiusMin || radius > cV0RadiusMax) + return false; + + // Proper lifetime cut + float dx = v0.decayVtxX() - collision.posX(); + float dy = v0.decayVtxY() - collision.posY(); + float dz = v0.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); + auto properLifetime = (l / (p + kSmallMomentumDenominator)) * MassLambda; + if (properLifetime > cV0ProperLifetimeMax) + return false; + + // Mass window + if (isLambda) { + if (std::abs(v0.mLambda() - MassLambda) > cV0MassWindow) + return false; + } else { + if (std::abs(v0.mAntiLambda() - MassLambda) > cV0MassWindow) + return false; + } + + return true; + } + + // K0s selection + template + bool k0sCut(const CollisionType& collision, const V0Type& v0) + { + // Basic kinematic cuts + if (std::abs(v0.eta()) > cMaxV0Etacut) + return false; + if (v0.pt() < cMinPtcut) + return false; + + // Topological cuts + if (v0.v0CosPA() < cK0sMinCosPA) + return false; + if (v0.daughDCA() > cK0sMaxDaughDCA) + return false; + + // Daughter DCA to PV cuts + if (std::abs(v0.dcapostopv()) < cK0sDauPosDCAtoPVMin) + return false; + if (std::abs(v0.dcanegtopv()) < cK0sDauNegDCAtoPVMin) + return false; + + // Radius cuts + auto radius = v0.transRadius(); + if (radius < cK0sRadiusMin || radius > cK0sRadiusMax) + return false; + + // DCA to PV + if (std::abs(v0.dcav0topv()) > kMaxDcaToPv) + return false; + + // Proper lifetime cut + float dx = v0.decayVtxX() - collision.posX(); + float dy = v0.decayVtxY() - collision.posY(); + float dz = v0.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); + auto properLifetime = (l / (p + kSmallMomentumDenominator)) * MassK0Short; + if (properLifetime > cK0sProperLifetimeMax) + return false; + + // Mass window + if (std::abs(v0.mK0Short() - MassK0Short) > cK0sMassWindow) + return false; + + // Competing V0 rejection: remove (Anti)Λ + if (cK0sCrossMassRejection) { + if (std::abs(v0.mLambda() - MassLambda) < cK0sMassWindow) + return false; + if (std::abs(v0.mAntiLambda() - MassLambda) < cK0sMassWindow) + return false; + } + + return true; + } + + // Helper function to find pT bin index + int getPtBinIndex(float pt) + { + auto ptBins = static_cast>(cKaonPIDPtBins); + for (size_t i = 0; i < ptBins.size() - 1; i++) { + if (pt >= ptBins[i] && pt < ptBins[i + 1]) { + return i; + } + } + return -1; // should not happen if bins are properly configured + } + + // Kaon PID selection + template + bool kaonPidCut(const TrackType& track) + { + float pt = track.pt(); + + if constexpr (IsResoMicrotrack) { + // For ResoMicroTracks - decode PID from flags + float tpcNSigma = o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(track.pidNSigmaKaFlag()); + float tofNSigma = track.hasTOF() ? o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(track.pidNSigmaKaFlag()) : 999.f; + + if (cKaonUsePtDepPID) { + // pT-dependent PID with binning + int ptBin = getPtBinIndex(pt); + if (ptBin < 0) + return false; // safety check + + auto tpcCuts = static_cast>(cKaonTPCNSigmaCuts); + auto tofCuts = static_cast>(cKaonTOFNSigmaCuts); + auto tofRequired = static_cast>(cKaonTOFRequired); + + // Check array sizes + if (ptBin >= static_cast(tpcCuts.size()) || + ptBin >= static_cast(tofCuts.size()) || + ptBin >= static_cast(tofRequired.size())) { + return false; // safety check + } + + // Apply TPC cut + if (std::abs(tpcNSigma) >= tpcCuts[ptBin]) + return false; + + // Apply TOF requirement and cut + if (tofRequired[ptBin] != 0) { + if (!track.hasTOF()) + return false; + if (std::abs(tofNSigma) >= tofCuts[ptBin]) + return false; + } else { + // TOF optional but apply cut if present + if (track.hasTOF() && std::abs(tofNSigma) >= tofCuts[ptBin]) + return false; + } + + return true; + } else { + // Standard PID + bool tpcPass = std::abs(tpcNSigma) < cKaonTPCNSigmaMax; + bool tofPass = track.hasTOF() ? std::abs(tofNSigma) < cKaonTOFNSigmaMax : true; + return tpcPass && tofPass; + } + } else { + // For ResoTracks - direct access + float tpcNSigma = track.tpcNSigmaKa(); + float tofNSigma = track.hasTOF() ? track.tofNSigmaKa() : 999.f; + + if (cKaonUsePtDepPID) { + // pT-dependent PID with binning + int ptBin = getPtBinIndex(pt); + if (ptBin < 0) + return false; // safety check + + auto tpcCuts = static_cast>(cKaonTPCNSigmaCuts); + auto tofCuts = static_cast>(cKaonTOFNSigmaCuts); + auto tofRequired = static_cast>(cKaonTOFRequired); + + // Check array sizes + if (ptBin >= static_cast(tpcCuts.size()) || + ptBin >= static_cast(tofCuts.size()) || + ptBin >= static_cast(tofRequired.size())) { + return false; // safety check + } + + // Apply TPC cut + if (std::abs(tpcNSigma) >= tpcCuts[ptBin]) + return false; + + // Apply TOF requirement and cut + if (tofRequired[ptBin] != 0) { + if (!track.hasTOF()) + return false; + if (std::abs(tofNSigma) >= tofCuts[ptBin]) + return false; + } else { + // TOF optional but apply cut if present + if (track.hasTOF() && std::abs(tofNSigma) >= tofCuts[ptBin]) + return false; + } + + return true; + } else { + // Standard PID + bool tpcPass = std::abs(tpcNSigma) < cKaonTPCNSigmaMax; + bool tofPass = track.hasTOF() ? std::abs(tofNSigma) < cKaonTOFNSigmaMax : true; + return tpcPass && tofPass; + } + } + } + + // Kaon track selection (for both ResoTracks and ResoMicroTracks) + template + bool kaonCut(const TrackType& track) + { + // Basic kinematic cuts + if (track.pt() < cKaonPtMin) + return false; + if (std::abs(track.eta()) > cKaonEtaMax) + return false; + + // DCA cuts - different access for ResoMicroTracks + if constexpr (IsResoMicrotrack) { + if (o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > cKaonDCAxyMax) + return false; + if (o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags()) > cKaonDCAzMax) + return false; + } else { + if (std::abs(track.dcaXY()) > cKaonDCAxyMax) + return false; + if (std::abs(track.dcaZ()) > cKaonDCAzMax) + return false; + } + + // Track quality cuts - check if fields are available (only for ResoTracks) + if constexpr (!IsResoMicrotrack) { + if constexpr (requires { track.tpcNClsFound(); }) { + if (track.tpcNClsFound() < cKaonTPCNClusMin) + return false; + } + if constexpr (requires { track.itsNCls(); }) { + if (track.itsNCls() < cKaonITSNClusMin) + return false; + } + } + + // PID selection + if (!kaonPidCut(track)) + return false; + + return true; + } + + template + void fill(const CollisionT& collision, const V0sT& v0s, const TracksT& tracks) + { + auto cent = collision.cent(); + + // Fill event QA histograms (only for same-event) + if constexpr (!IsMix) { + histos.fill(HIST("Event/posZ"), collision.posZ()); + histos.fill(HIST("Event/centrality"), cent); + histos.fill(HIST("Event/posZvsCent"), collision.posZ(), cent); + histos.fill(HIST("Event/nV0s"), v0s.size()); + histos.fill(HIST("Event/nKaons"), tracks.size()); + } + + // Count candidates after cuts + int nV0sAfterCuts = 0; + int nKaonsAfterCuts = 0; + + // Loop over kaon candidates + for (const auto& kaon : tracks) { + // QA before cuts + if constexpr (!IsMix) { + histos.fill(HIST("QAbefore/kaonPt"), kaon.pt()); + histos.fill(HIST("QAbefore/kaonEta"), kaon.eta()); + if constexpr (IsResoMicrotrack) { + histos.fill(HIST("QAbefore/kaonDCAxy"), kaon.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(kaon.trackSelectionFlags())); + histos.fill(HIST("QAbefore/kaonDCAz"), kaon.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(kaon.trackSelectionFlags())); + histos.fill(HIST("QAbefore/kaonTPCNSigma"), kaon.pt(), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(kaon.pidNSigmaKaFlag())); + if (kaon.hasTOF()) { + histos.fill(HIST("QAbefore/kaonTOFNSigma"), kaon.pt(), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(kaon.pidNSigmaKaFlag())); + } + } else { + histos.fill(HIST("QAbefore/kaonDCAxy"), kaon.pt(), kaon.dcaXY()); + histos.fill(HIST("QAbefore/kaonDCAz"), kaon.pt(), kaon.dcaZ()); + histos.fill(HIST("QAbefore/kaonTPCNSigma"), kaon.pt(), kaon.tpcNSigmaKa()); + if (kaon.hasTOF()) { + histos.fill(HIST("QAbefore/kaonTOFNSigma"), kaon.pt(), kaon.tofNSigmaKa()); + } + if constexpr (requires { kaon.tpcNClsFound(); }) { + histos.fill(HIST("QAbefore/kaonTPCNcls"), kaon.tpcNClsFound()); + } + if constexpr (requires { kaon.itsNCls(); }) { + histos.fill(HIST("QAbefore/kaonITSNcls"), kaon.itsNCls()); + } + } + } + + if (!kaonCut(kaon)) + continue; + + if constexpr (!IsMix) { + nKaonsAfterCuts++; + // QA after cuts + histos.fill(HIST("QAafter/kaonPt"), kaon.pt()); + histos.fill(HIST("QAafter/kaonEta"), kaon.eta()); + if constexpr (IsResoMicrotrack) { + histos.fill(HIST("QAafter/kaonDCAxy"), kaon.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(kaon.trackSelectionFlags())); + histos.fill(HIST("QAafter/kaonDCAz"), kaon.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(kaon.trackSelectionFlags())); + histos.fill(HIST("QAafter/kaonTPCNSigma"), kaon.pt(), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(kaon.pidNSigmaKaFlag())); + if (kaon.hasTOF()) { + histos.fill(HIST("QAafter/kaonTOFNSigma"), kaon.pt(), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(kaon.pidNSigmaKaFlag())); + } + } else { + histos.fill(HIST("QAafter/kaonDCAxy"), kaon.pt(), kaon.dcaXY()); + histos.fill(HIST("QAafter/kaonDCAz"), kaon.pt(), kaon.dcaZ()); + histos.fill(HIST("QAafter/kaonTPCNSigma"), kaon.pt(), kaon.tpcNSigmaKa()); + if (kaon.hasTOF()) { + histos.fill(HIST("QAafter/kaonTOFNSigma"), kaon.pt(), kaon.tofNSigmaKa()); + } + if constexpr (requires { kaon.tpcNClsFound(); }) { + histos.fill(HIST("QAafter/kaonTPCNcls"), kaon.tpcNClsFound()); + } + if constexpr (requires { kaon.itsNCls(); }) { + histos.fill(HIST("QAafter/kaonITSNcls"), kaon.itsNCls()); + } + } + } + + int kaonCharge = kaon.sign(); + + // Loop over V0 candidates + for (const auto& v0 : v0s) { + // Lambda QA before cuts + if constexpr (!IsMix) { + histos.fill(HIST("QAbefore/lambdaMass"), v0.mLambda()); + histos.fill(HIST("QAbefore/lambdaPt"), v0.pt()); + histos.fill(HIST("QAbefore/lambdaEta"), v0.eta()); + histos.fill(HIST("QAbefore/lambdaCosPA"), v0.pt(), v0.v0CosPA()); + histos.fill(HIST("QAbefore/lambdaRadius"), v0.pt(), v0.transRadius()); + histos.fill(HIST("QAbefore/lambdaDauDCA"), v0.pt(), v0.daughDCA()); + histos.fill(HIST("QAbefore/lambdaDauPosDCA"), v0.pt(), std::abs(v0.dcapostopv())); + histos.fill(HIST("QAbefore/lambdaDauNegDCA"), v0.pt(), std::abs(v0.dcanegtopv())); + + // Calculate proper lifetime manually + float dx = v0.decayVtxX() - collision.posX(); + float dy = v0.decayVtxY() - collision.posY(); + float dz = v0.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); + auto properLifetime = (l / (p + kSmallMomentumDenominator)) * MassLambda; + histos.fill(HIST("QAbefore/lambdaProperLifetime"), v0.pt(), properLifetime); + } + + // Try Lambda + bool isLambda = v0Cut(collision, v0, true); + // Try Anti-Lambda + bool isAntiLambda = v0Cut(collision, v0, false); + + if (!isLambda && !isAntiLambda) + continue; + + if constexpr (!IsMix) { + nV0sAfterCuts++; + // QA after cuts (fill for whichever passes) + if (isLambda) { + histos.fill(HIST("QAafter/lambdaMass"), v0.mLambda()); + } + if (isAntiLambda) { + histos.fill(HIST("QAafter/lambdaMass"), v0.mAntiLambda()); + } + histos.fill(HIST("QAafter/lambdaPt"), v0.pt()); + histos.fill(HIST("QAafter/lambdaEta"), v0.eta()); + histos.fill(HIST("QAafter/lambdaCosPA"), v0.pt(), v0.v0CosPA()); + histos.fill(HIST("QAafter/lambdaRadius"), v0.pt(), v0.transRadius()); + histos.fill(HIST("QAafter/lambdaDauDCA"), v0.pt(), v0.daughDCA()); + histos.fill(HIST("QAafter/lambdaDauPosDCA"), v0.pt(), std::abs(v0.dcapostopv())); + histos.fill(HIST("QAafter/lambdaDauNegDCA"), v0.pt(), std::abs(v0.dcanegtopv())); + + float dx = v0.decayVtxX() - collision.posX(); + float dy = v0.decayVtxY() - collision.posY(); + float dz = v0.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); + auto properLifetime = (l / (p + kSmallMomentumDenominator)) * MassLambda; + histos.fill(HIST("QAafter/lambdaProperLifetime"), v0.pt(), properLifetime); + } + + // Build 4 combinations + ROOT::Math::PxPyPzEVector pKaon, pLambda, pRes; + pKaon = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(kaon.pt(), kaon.eta(), kaon.phi(), MassKaonCharged)); + + // K+ Lambda + if (kaonCharge > 0 && isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); + pRes = pKaon + pLambda; + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda"), pRes.M()); + histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda"), pRes.M(), pRes.Pt(), cent); + } else { + histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + + // K+ Anti-Lambda + if (kaonCharge > 0 && isAntiLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); + pRes = pKaon + pLambda; + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda"), pRes.M()); + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda"), pRes.M(), pRes.Pt(), cent); + } else { + histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + + // K- Lambda + if (kaonCharge < 0 && isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); + pRes = pKaon + pLambda; + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda"), pRes.M()); + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda"), pRes.M(), pRes.Pt(), cent); + } else { + histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + + // K- Anti-Lambda + if (kaonCharge < 0 && isAntiLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); + pRes = pKaon + pLambda; + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda"), pRes.M()); + histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda"), pRes.M(), pRes.Pt(), cent); + } else { + histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + } + } + + // Fill event QA for after-cuts counters (only for same-event) + if constexpr (!IsMix) { + histos.fill(HIST("Event/nV0sAfterCuts"), nV0sAfterCuts); + histos.fill(HIST("Event/nKaonsAfterCuts"), nKaonsAfterCuts); + } + } + + void processDummy(const aod::ResoCollision& /*collision*/) + { + // Dummy function to satisfy the compiler + } + PROCESS_SWITCH(Xi1820Analysis, processDummy, "Process Dummy", true); + + void processDataWithTracks(const aod::ResoCollision& collision, + aod::ResoV0s const& resov0s, + aod::ResoTracks const& resotracks) + { + fill(collision, resov0s, resotracks); + } + PROCESS_SWITCH(Xi1820Analysis, processDataWithTracks, "Process Event with ResoTracks", false); + + void processDataWithMicroTracks(const aod::ResoCollision& collision, + aod::ResoV0s const& resov0s, + aod::ResoMicroTracks const& resomicrotracks) + { + fill(collision, resov0s, resomicrotracks); + } + PROCESS_SWITCH(Xi1820Analysis, processDataWithMicroTracks, "Process Event with ResoMicroTracks", false); + + void processMixedEventWithTracks(const aod::ResoCollisions& collisions, + aod::ResoV0s const& resov0s, + aod::ResoTracks const& resotracks) + { + + auto v0sTracksTuple = std::make_tuple(resov0s, resotracks); + Pair pairs{colBinning, nEvtMixing, -1, collisions, v0sTracksTuple, &cache}; + + for (auto& [collision1, v0s1, collision2, tracks2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) + auto cent = collision1.cent(); + + for (const auto& kaon : tracks2) { + if (!kaonCut(kaon)) + continue; + int kaonCharge = kaon.sign(); + + for (const auto& v0 : v0s1) { + bool isLambda = v0Cut(collision1, v0, true); + bool isAntiLambda = v0Cut(collision1, v0, false); + + if (!isLambda && !isAntiLambda) + continue; + + ROOT::Math::PxPyPzEVector pKaon, pLambda, pRes; + pKaon = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(kaon.pt(), kaon.eta(), kaon.phi(), MassKaonCharged)); + + // K+ Lambda + if (kaonCharge > 0 && isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); + pRes = pKaon + pLambda; + histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + + // K+ Anti-Lambda + if (kaonCharge > 0 && isAntiLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); + pRes = pKaon + pLambda; + histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + + // K- Lambda + if (kaonCharge < 0 && isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); + pRes = pKaon + pLambda; + histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + + // K- Anti-Lambda + if (kaonCharge < 0 && isAntiLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); + pRes = pKaon + pLambda; + histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + } + } + } + PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithTracks, "Process Mixed Event with ResoTracks", false); + + void processMixedEventWithMicroTracks(const aod::ResoCollisions& collisions, + aod::ResoV0s const& resov0s, + aod::ResoMicroTracks const& resomicrotracks) + { + + auto v0sTracksTuple = std::make_tuple(resov0s, resomicrotracks); + Pair pairs{colBinning, nEvtMixing, -1, collisions, v0sTracksTuple, &cache}; + + for (auto& [collision1, v0s1, collision2, tracks2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) + auto cent = collision1.cent(); + + for (const auto& kaon : tracks2) { + if (!kaonCut(kaon)) + continue; + int kaonCharge = kaon.sign(); + + for (const auto& v0 : v0s1) { + bool isLambda = v0Cut(collision1, v0, true); + bool isAntiLambda = v0Cut(collision1, v0, false); + + if (!isLambda && !isAntiLambda) + continue; + + ROOT::Math::PxPyPzEVector pKaon, pLambda, pRes; + pKaon = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(kaon.pt(), kaon.eta(), kaon.phi(), MassKaonCharged)); + + // K+ Lambda + if (kaonCharge > 0 && isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); + pRes = pKaon + pLambda; + histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + + // K+ Anti-Lambda + if (kaonCharge > 0 && isAntiLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); + pRes = pKaon + pLambda; + histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + + // K- Lambda + if (kaonCharge < 0 && isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); + pRes = pKaon + pLambda; + histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + + // K- Anti-Lambda + if (kaonCharge < 0 && isAntiLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); + pRes = pKaon + pLambda; + histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + } + } + } + PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithMicroTracks, "Process Mixed Event with ResoMicroTracks", false); + + // K0s + Lambda analysis + void processK0sLambda(const aod::ResoCollision& collision, + aod::ResoV0s const& resov0s) + { + auto cent = collision.cent(); + + // Fill event QA histograms + histos.fill(HIST("Event/posZ"), collision.posZ()); + histos.fill(HIST("Event/centrality"), cent); + histos.fill(HIST("Event/posZvsCent"), collision.posZ(), cent); + histos.fill(HIST("Event/nV0s"), resov0s.size()); + + // Loop over V0s for K0s + for (const auto& k0s : resov0s) { + // K0s QA before cuts + histos.fill(HIST("QAbefore/k0sMass"), k0s.mK0Short()); + histos.fill(HIST("QAbefore/k0sPt"), k0s.pt()); + histos.fill(HIST("QAbefore/k0sEta"), k0s.eta()); + histos.fill(HIST("QAbefore/k0sCosPA"), k0s.pt(), k0s.v0CosPA()); + histos.fill(HIST("QAbefore/k0sRadius"), k0s.pt(), k0s.transRadius()); + histos.fill(HIST("QAbefore/k0sDauDCA"), k0s.pt(), k0s.daughDCA()); + + float dx = k0s.decayVtxX() - collision.posX(); + float dy = k0s.decayVtxY() - collision.posY(); + float dz = k0s.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(k0s.px() * k0s.px() + k0s.py() * k0s.py() + k0s.pz() * k0s.pz()); + auto k0sProperLifetime = (l / (p + 1e-10)) * MassK0Short; + histos.fill(HIST("QAbefore/k0sProperLifetime"), k0s.pt(), k0sProperLifetime); + + if (!k0sCut(collision, k0s)) + continue; + + // K0s QA after cuts + histos.fill(HIST("QAafter/k0sMass"), k0s.mK0Short()); + histos.fill(HIST("QAafter/k0sPt"), k0s.pt()); + histos.fill(HIST("QAafter/k0sEta"), k0s.eta()); + histos.fill(HIST("QAafter/k0sCosPA"), k0s.pt(), k0s.v0CosPA()); + histos.fill(HIST("QAafter/k0sRadius"), k0s.pt(), k0s.transRadius()); + histos.fill(HIST("QAafter/k0sDauDCA"), k0s.pt(), k0s.daughDCA()); + histos.fill(HIST("QAafter/k0sProperLifetime"), k0s.pt(), k0sProperLifetime); + + // Loop over V0s for Lambda + for (const auto& lambda : resov0s) { + // Try Lambda + bool isLambda = v0Cut(collision, lambda, true); + // Try Anti-Lambda + bool isAntiLambda = v0Cut(collision, lambda, false); + + if (!isLambda && !isAntiLambda) + continue; + + // 4-vectors + ROOT::Math::PxPyPzEVector pK0s, pLambda, pRes; + pK0s = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(k0s.pt(), k0s.eta(), k0s.phi(), MassK0Short)); + + // K0s + Lambda + if (isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mLambda())); + pRes = pK0s + pLambda; + histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda"), pRes.M()); + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda"), pRes.M(), pRes.Pt(), cent); + } + + // K0s + Anti-Lambda + if (isAntiLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mAntiLambda())); + pRes = pK0s + pLambda; + histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda"), pRes.M()); + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda"), pRes.M(), pRes.Pt(), cent); + } + } + } + } + PROCESS_SWITCH(Xi1820Analysis, processK0sLambda, "Process K0s + Lambda", false); + + // K0s + Lambda mixed event analysis + void processK0sLambdaMixedEvent(const aod::ResoCollisions& collisions, + aod::ResoV0s const& resov0s) + { + + auto v0sV0sTuple = std::make_tuple(resov0s, resov0s); + Pair pairs{colBinning, nEvtMixing, -1, collisions, v0sV0sTuple, &cache}; + + for (auto& [collision1, k0s1, collision2, lambda2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) + auto cent = collision1.cent(); + + for (const auto& k0s : k0s1) { + if (!k0sCut(collision1, k0s)) + continue; + + for (const auto& lambda : lambda2) { + bool isLambda = v0Cut(collision2, lambda, true); + bool isAntiLambda = v0Cut(collision2, lambda, false); + + if (!isLambda && !isAntiLambda) + continue; + + ROOT::Math::PxPyPzEVector pK0s, pLambda, pRes; + pK0s = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(k0s.pt(), k0s.eta(), k0s.phi(), MassK0Short)); + + // K0s + Lambda + if (isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mLambda())); + pRes = pK0s + pLambda; + histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + + // K0s + Anti-Lambda + if (isAntiLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mAntiLambda())); + pRes = pK0s + pLambda; + histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda_Mix"), pRes.M()); + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } + } + } + } + } + PROCESS_SWITCH(Xi1820Analysis, processK0sLambdaMixedEvent, "Process K0s + Lambda Mixed Event", false); + + // MC processes - placeholder for future implementation + void processMCWithTracks(const aod::ResoCollision& /*collision*/, + aod::ResoV0s const& /*resov0s*/, + aod::ResoTracks const& /*resotracks*/, + aod::McParticles const& /*mcParticles*/) + { + // TODO: Implement MC truth matching for K± + Lambda + // - Match reconstructed kaons to MC kaons + // - Match reconstructed Lambdas to MC Lambdas + // - Fill MC truth histograms + // - Fill reconstruction efficiency histograms + } + PROCESS_SWITCH(Xi1820Analysis, processMCWithTracks, "Process MC with ResoTracks (placeholder)", false); + + void processMCWithMicroTracks(const aod::ResoCollision& /*collision*/, + aod::ResoV0s const& /*resov0s*/, + aod::ResoMicroTracks const& /*resomicrotracks*/, + aod::McParticles const& /*mcParticles*/) + { + // TODO: Implement MC truth matching for K± + Lambda with MicroTracks + } + PROCESS_SWITCH(Xi1820Analysis, processMCWithMicroTracks, "Process MC with ResoMicroTracks (placeholder)", false); + + void processMCK0sLambda(const aod::ResoCollision& /*collision*/, + aod::ResoV0s const& /*resov0s*/, + aod::McParticles const& /*mcParticles*/) + { + // TODO: Implement MC truth matching for K0s + Lambda + // - Match reconstructed K0s to MC K0s + // - Match reconstructed Lambdas to MC Lambdas + // - Fill MC truth histograms + // - Fill reconstruction efficiency histograms + } + PROCESS_SWITCH(Xi1820Analysis, processMCK0sLambda, "Process MC K0s + Lambda (placeholder)", false); + + void processMCGenerated(aod::McParticles const& mcParticles) + { + // Process MC generated particles (no reconstruction requirement) + // Xi(1820)0 PDG code: 123314 (neutral, decays to K+ Lambda or K0s Lambda) + // Note: PDG doesn't have separate codes for charge states in this case + + for (const auto& mcParticle : mcParticles) { + // Look for Xi(1820) - PDG code can vary, check for resonance mass ~1820 MeV + int pdg = mcParticle.pdgCode(); + + // Xi(1820)0: PDG 123314 + // Check if it's Xi(1820) or similar resonance + if (std::abs(pdg) != kPdgXi1820) + continue; + + // Fill generated level histograms + auto pt = mcParticle.pt(); + auto eta = mcParticle.eta(); + auto y = mcParticle.y(); + + histos.fill(HIST("MC/hMCGenXi1820Pt"), pt); + histos.fill(HIST("MC/hMCGenXi1820PtEta"), pt, eta); + histos.fill(HIST("MC/hMCGenXi1820Y"), y); + + // Get daughters + auto daughters = mcParticle.daughters_as(); + if (daughters.size() != kExpectedDaughters) + continue; + + int daughter1PDG = 0, daughter2PDG = 0; + ROOT::Math::PxPyPzEVector p1, p2, pMother; + + int iDaughter = 0; + for (const auto& daughter : daughters) { + if (iDaughter == 0) { + daughter1PDG = daughter.pdgCode(); + p1.SetPxPyPzE(daughter.px(), daughter.py(), daughter.pz(), daughter.e()); + } else { + daughter2PDG = daughter.pdgCode(); + p2.SetPxPyPzE(daughter.px(), daughter.py(), daughter.pz(), daughter.e()); + } + iDaughter++; + } + + pMother = p1 + p2; + + // Check decay channels + auto motherPt = pMother.Pt(); + auto motherM = pMother.M(); + + // K+ + Lambda + if ((daughter1PDG == PDG_t::kKPlus && daughter2PDG == PDG_t::kLambda0) || + (daughter1PDG == PDG_t::kLambda0 && daughter2PDG == PDG_t::kKPlus)) { + histos.fill(HIST("MC/hMCTruthInvMassKplusLambda"), motherM); + histos.fill(HIST("MC/hMCTruthMassPtKplusLambda"), motherM, motherPt); + } + + // K- + Anti-Lambda + if ((daughter1PDG == PDG_t::kKMinus && daughter2PDG == PDG_t::kLambda0Bar) || + (daughter1PDG == PDG_t::kLambda0Bar && daughter2PDG == PDG_t::kKMinus)) { + histos.fill(HIST("MC/hMCTruthInvMassKminusAntiLambda"), motherM); + histos.fill(HIST("MC/hMCTruthMassPtKminusAntiLambda"), motherM, motherPt); + } + + // K0s + Lambda + if ((daughter1PDG == PDG_t::kK0Short && daughter2PDG == PDG_t::kLambda0) || + (daughter1PDG == PDG_t::kLambda0 && daughter2PDG == PDG_t::kK0Short)) { + histos.fill(HIST("MC/hMCTruthInvMassK0sLambda"), motherM); + histos.fill(HIST("MC/hMCTruthMassPtK0sLambda"), motherM, motherPt); + } + + // K0s + Anti-Lambda + if ((daughter1PDG == PDG_t::kK0Short && daughter2PDG == PDG_t::kLambda0Bar) || + (daughter1PDG == PDG_t::kLambda0Bar && daughter2PDG == PDG_t::kK0Short)) { + histos.fill(HIST("MC/hMCTruthInvMassK0sAntiLambda"), motherM); + histos.fill(HIST("MC/hMCTruthMassPtK0sAntiLambda"), motherM, motherPt); + } + } + } + PROCESS_SWITCH(Xi1820Analysis, processMCGenerated, "Process MC generated particles", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/CMakeLists.txt b/PWGLF/Tasks/Strangeness/CMakeLists.txt index 4873d3e6b1b..333e2600d08 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 @@ -41,17 +41,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 O2::DetectorsVertexing O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(k0mixedevents @@ -59,6 +54,11 @@ o2physics_add_dpl_workflow(k0mixedevents PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(xi-lambda-corr-task + SOURCES xiLambdaCorr.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(vzero-cascade-absorption SOURCES vzero_cascade_absorption.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -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,16 +76,16 @@ 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 + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(phik0shortanalysis - SOURCES phik0sanalysis.cxx + SOURCES phik0shortanalysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -94,12 +94,94 @@ o2physics_add_dpl_workflow(lambdapolarization PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(strangeness-in-jets - SOURCES strangeness_in_jets.cxx +o2physics_add_dpl_workflow(lambdapolsp + SOURCES lambdapolsp.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdak0seff + SOURCES lambdak0seff.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) + +o2physics_add_dpl_workflow(strangeness-in-jets-ions + SOURCES strangenessInJetsIons.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sjet-tree-creator + SOURCES sjetTreeCreator.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib + COMPONENT_NAME Analysis) +endif() + o2physics_add_dpl_workflow(v0topologicalcuts SOURCES v0topologicalcuts.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore - COMPONENT_NAME Analysis) \ No newline at end of file + 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 O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdajetpolarization + SOURCES lambdaJetpolarization.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdaspincorrderived + SOURCES lambdaspincorrderived.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(strangenessderivedbinnedinfo + SOURCES strangenessderivedbinnedinfo.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambdatwopartpolarization + SOURCES lambdaTwoPartPolarization.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cascadeanalysislightions + SOURCES cascadeAnalysisLightIonsDerivedData.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(strange-casc-track + SOURCES strangeCascTrack.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Strangeness/cascadeAnalysisLightIonsDerivedData.cxx b/PWGLF/Tasks/Strangeness/cascadeAnalysisLightIonsDerivedData.cxx new file mode 100644 index 00000000000..aba22a2f900 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/cascadeAnalysisLightIonsDerivedData.cxx @@ -0,0 +1,1121 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file cascadeAnalysisLightIonsDerivedData.cxx +/// \brief analysis of cascades (Xi, antiXi, Omega, antiOmega) in light-ion collisions using derived data +/// +/// \author Sara Pucillo (sara.pucillo@cern.ch), Alberto Caliva (alberto.caliva@cern.ch) +// + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/ctpRateFetcher.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/TrackSelectionTables.h" + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::math; +using namespace o2::constants::physics; +using std::array; + +using SelCollisions = soa::Join; +using SimCollisions = soa::Join; +using CascadeCandidates = soa::Join; +using CascadeMCCandidates = soa::Join; +using DaughterTracks = soa::Join; +using CollisionMCTrueTable = soa::Join; +using CascadeMCCores = soa::Join; + +struct CascadeAnalysisLightIonsDerivedData { + + // Instantiate the CCDB service and API interface + // 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; + int mRunNumber; + + // Define histogram registries + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Global analysis parameters + Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "eta gap from the edge"}; + Configurable nBins{"nBins", 100, "N bins in all QC histos"}; + + // Event selections parameters + Configurable applySel8{"applySel8", true, "0 - no, 1 - yes"}; + Configurable applyVtxZ{"applyVtxZ", true, "0 - no, 1 - yes"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireVertexITSTPC{"requireVertexITSTPC", false, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require is good Zvtx FT0 vs PV"}; + 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"}; + + // Track analysis 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 etaMin{"etaMin", -0.8f, "eta min"}; + Configurable etaMax{"etaMax", +0.8f, "eta max"}; + Configurable rapcut{"rapcut", +0.5f, "rapidity cut"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"}; + Configurable requireITS{"requireITS", false, "require ITS hit"}; + Configurable requireTOF{"requireTOF", false, "require TOF hit"}; + + // Configurable parameters for PID selection + Configurable nsigmaTPCmin{"nsigmaTPCmin", -5.0f, "Minimum nsigma TPC"}; + Configurable nsigmaTPCmax{"nsigmaTPCmax", +5.0f, "Maximum nsigma TPC"}; + + // Configurable parameters for TOF PID selection + Configurable nsigmaTOFmin{"nsigmaTOFmin", -3.0f, "Minimum nsigma TOF"}; + Configurable nsigmaTOFmax{"nsigmaTOFmax", +3.0f, "Maximum nsigma TOF"}; + + // Topological Parameters + Configurable dcanegtoPVmin{"dcanegtoPVmin", 0.1f, "Minimum DCA Neg To PV"}; + Configurable dcapostoPVmin{"dcapostoPVmin", 0.1f, "Minimum DCA Pos To PV"}; + Configurable dcabachtopvMin{"dcabachtopvMin", 0.1f, "Minimum DCA bachelor to PV"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.7f, "Maximum DCA Daughters"}; + Configurable dcaV0topvMin{"dcaV0topvMin", 0.02f, "Minimum DCA V0 to PV"}; + Configurable dcaCascDaughtersMax{"dcaCascDaughtersMax", 0.8f, "Maximum DCA Daughters"}; + Configurable v0cospaMin{"v0cospaMin", 0.99f, "Minimum V0 CosPA"}; + Configurable casccospaMin{"casccospaMin", 0.99f, "Minimum Cascade CosPA"}; + Configurable minimumV0Radius{"minimumV0Radius", 2.5f, "Minimum V0 Radius"}; + Configurable minimumCascRadius{"minimumCascRadius", 1.1f, "Minimum Cascade Radius"}; + Configurable v0masswindow{"v0masswindow", 0.005, "v0 mass window"}; + Configurable competingmassrej{"competingmassrej", 0.008, "Competing mass rejection"}; + // Axes parameters + ConfigurableAxis centEstimatorHistBin{"centEstimatorHistBin", {101, 0.0f, 101.0f}, ""}; + ConfigurableAxis centralityBinning{"centralityBinning", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f}, ""}; + ConfigurableAxis axisNch{"axisNch", {500, 0.0f, +5000.0f}, "Number of charged particles"}; + ConfigurableAxis axisMult{"axisMult", {500, 0.0f, +100000.0f}, "Multiplicity"}; + + // Centrality estimator + Configurable centralityEstimator{"centralityEstimator", 0, "0 = FT0C, 1 = FTOM, 2 = FV0A, 3 = NGlobal"}; + + // List of estimators + enum Option { kFT0C, + kFT0M, + kFV0A, + kNGlobal }; + + // For manual sliceBy + PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; + + void init(InitContext const&) + { + // setting CCDB service + ccdb->setURL(ccdbConfigurations.ccdbUrl); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter( + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count()); + + // Axes and Binning + AxisSpec axisCentEstimator = {centEstimatorHistBin, "CentEstimator", "CentEstimatorAxis"}; + AxisSpec centAxis = {centralityBinning, "Centrality", "CentralityAxis"}; + const AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm]"}; + const AxisSpec etaAxis{18, -0.9, 0.9, "#eta"}; + const AxisSpec ptAxis{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}; + 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})"}; + const AxisSpec nsigmaTOFAxis{200, -10, 10, "n#sigma_{TOF}"}; + const AxisSpec nsigmaTPCAxis{200, -10, 10, "n#sigma_{TPC}"}; + + // Histograms for data + if (doprocessData) { + registryData.add("number_of_events_data", "number of events in data", HistType::kTH1D, {{20, -0.5f, +19.5f}}); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(1, "All collisions"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); + + registryData.add("number_of_events_data_vs_centrality", "number of events in data vs centrality", HistType::kTH2D, {{20, -0.5f, +19.5f}, {101, 0.0f, 101.0f}}); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(1, "All collisions"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetYaxis()->SetTitle("Centrality (%)"); + + // QC Histograms + registryQC.add("hVertexZdata", "hVertexZdata", HistType::kTH1D, {vertexZAxis}); + registryQC.add("hv0cosPAdata", "hv0cosPAdata", HistType::kTH1D, {{nBins, 0.95f, 1.f}}); + registryQC.add("hcasccosPAdata", "hcasccosPAdata", HistType::kTH1D, {{nBins, 0.95f, 1.f}}); + registryQC.add("hv0radiusdata", "hv0radiusdata", HistType::kTH1D, {{nBins, 0.0f, 5.0f}}); + registryQC.add("hcascradiusdata", "hcascradiusdata", HistType::kTH1D, {{nBins, 0.0f, 5.0f}}); + registryQC.add("hdcaV0daughtersdata", "hdcaV0daughtersdata", HistType::kTH1D, {{nBins, 0.0f, 1.5f}}); + registryQC.add("hdcacascdaughtersdata", "hdcacascdaughtersdata", HistType::kTH1D, {{nBins, 0.0f, 1.5f}}); + registryQC.add("hdcapostopvdata", "hdcapostopvdata", HistType::kTH1D, {{nBins, 0.0f, 2.0f}}); + registryQC.add("hdcanegtopvdata", "hdcanegtopvdata", HistType::kTH1D, {{nBins, 0.0f, 2.0f}}); + registryQC.add("hdcabachtopvdata", "hdcabachtopvdata", HistType::kTH1D, {{nBins, 0.0f, 2.0f}}); + registryQC.add("hdcav0topvdata", "hdcav0topvdata", HistType::kTH1D, {{nBins, 0.0f, 2.0f}}); + + // Multiplicity Histograms + registryData.add("hCentEstimator", "hCentEstimator", HistType::kTH1D, {{101, 0.0f, 101.0f}}); + registryData.add("hCentralityVsNch", "hCentralityVsNch", HistType::kTH2D, {{101, 0.0f, 101.0f}, axisNch}); + if (centralityEstimator == Option::kNGlobal) + registryData.add("hCentralityVsMultiplicity", "hCentralityVsMultiplicity", HistType::kTH2D, {{101, 0.0f, 101.0f}, axisNch}); + else + registryData.add("hCentralityVsMultiplicity", "hCentralityVsMultiplicity", HistType::kTH2D, {{101, 0.0f, 101.0f}, axisMult}); + + // Histograms for xi (data) + registryData.add("hMassXipos", "hMassXipos", HistType::kTH3D, {centAxis, ptAxis, invMassXiAxis}); + registryData.add("hMassXineg", "hMassXineg", HistType::kTH3D, {centAxis, ptAxis, invMassXiAxis}); + registryData.add("hMassXiposSelected", "hMassXiposSelected", HistType::kTH3D, {centAxis, ptAxis, invMassXiAxis}); + registryData.add("hMassXinegSelected", "hMassXinegSelected", HistType::kTH3D, {centAxis, ptAxis, invMassXiAxis}); + + // Histograms for omega (data) + registryData.add("hMassOmegapos", "hMassOmegapos", HistType::kTH3D, {centAxis, ptAxis, invMassOmegaAxis}); + registryData.add("hMassOmeganeg", "hMassOmeganeg", HistType::kTH3D, {centAxis, ptAxis, invMassOmegaAxis}); + registryData.add("hMassOmegaposSelected", "hMassOmegaposSelected", HistType::kTH3D, {centAxis, ptAxis, invMassOmegaAxis}); + registryData.add("hMassOmeganegSelected", "hMassOmeganegSelected", HistType::kTH3D, {centAxis, ptAxis, invMassOmegaAxis}); + } + + if (doprocessMonteCarloRec) { + // Histograms for mc reconstructed + registryMC.add("number_of_events_mc_rec", "number of events in mc_rec", HistType::kTH1D, {{20, -0.5f, +19.5f}}); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(1, "All collisions"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); + + registryMC.add("number_of_events_mc_rec_vs_centrality", "number of events in mc_rec vs centrality", HistType::kTH2D, {{20, -0.5f, +19.5f}, {101, 0.0f, 101.0f}}); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(1, "All collisions"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetYaxis()->SetTitle("Centrality (%)"); + + // QC Histograms + registryQC.add("hVertexZRec", "hVertexZRec", HistType::kTH1D, {{vertexZAxis}}); + registryQC.add("hv0cosPARec", "hv0cosPARec", HistType::kTH1D, {{nBins, 0.95f, 1.f}}); + registryQC.add("hcasccosPARec", "hcasccosPARec", HistType::kTH1D, {{nBins, 0.95f, 1.f}}); + registryQC.add("hv0radiusRec", "hv0radiusRec", HistType::kTH1D, {{nBins, 0.0f, 5.0f}}); + registryQC.add("hcascradiusRec", "hcascradiusRec", HistType::kTH1D, {{nBins, 0.0f, 5.0f}}); + registryQC.add("hdcaV0daughtersRec", "hdcaV0daughtersRec", HistType::kTH1D, {{nBins, 0.0f, 1.5f}}); + registryQC.add("hdcacascdaughtersRec", "hdcacascdaughtersRec", HistType::kTH1D, {{nBins, 0.0f, 1.5f}}); + registryQC.add("hdcapostopvRec", "hdcapostopvRec", HistType::kTH1D, {{nBins, 0.0f, 2.0f}}); + registryQC.add("hdcanegtopvRec", "hdcanegtopvRec", HistType::kTH1D, {{nBins, 0.0f, 2.0f}}); + registryQC.add("hdcabachtopvRec", "hdcabachtopvRec", HistType::kTH1D, {{nBins, 0.0f, 2.0f}}); + registryQC.add("hdcav0topvRec", "hdcav0topvRec", HistType::kTH1D, {{nBins, 0.0f, 2.0f}}); + + // Multiplicity Histograms + registryMC.add("hCentEstimator_truerec", "hCentEstimator_truerec", HistType::kTH1D, {{101, 0.0f, 101.0f}}); + registryMC.add("hCentralityVsNch_truerec", "hCentralityVsNch_truerec", HistType::kTH2D, {{101, 0.0f, 101.0f}, axisNch}); + if (centralityEstimator == Option::kNGlobal) + registryMC.add("hCentralityVsMultiplicity_truerec", "hCentralityVsMultiplicity_truerec", HistType::kTH2D, {{101, 0.0f, 101.0f}, axisNch}); + else + registryMC.add("hCentralityVsMultiplicity_truerec", "hCentralityVsMultiplicity_truerec", HistType::kTH2D, {{101, 0.0f, 101.0f}, axisMult}); + + // Histograms for xi (mc) + registryMC.add("hMassXipos_truerec", "hMassXipos_truerec", HistType::kTH3D, {centAxis, ptAxis, invMassXiAxis}); + registryMC.add("hMassXineg_truerec", "hMassXineg_truerec", HistType::kTH3D, {centAxis, ptAxis, invMassXiAxis}); + registryMC.add("hMassXiposSelected_truerec", "hMassXiposSelected_truerec", HistType::kTH3D, {centAxis, ptAxis, invMassXiAxis}); + registryMC.add("hMassXinegSelected_truerec", "hMassXinegSelected_truerec", HistType::kTH3D, {centAxis, ptAxis, invMassXiAxis}); + + // Histograms for omega (mc) + registryMC.add("hMassOmegapos_truerec", "hMassOmegapos_truerec", HistType::kTH3D, {centAxis, ptAxis, invMassOmegaAxis}); + registryMC.add("hMassOmeganeg_truerec", "hMassOmeganeg_truerec", HistType::kTH3D, {centAxis, ptAxis, invMassOmegaAxis}); + registryMC.add("hMassOmegaposSelected_truerec", "hMassOmegaposSelected_truerec", HistType::kTH3D, {centAxis, ptAxis, invMassOmegaAxis}); + registryMC.add("hMassOmeganegSelected_truerec", "hMassOmeganegSelected_truerec", HistType::kTH3D, {centAxis, ptAxis, invMassOmegaAxis}); + } + + if (doprocessMonteCarloGen) { + // Histograms for mc generated + // QC Histograms + registryQC.add("hVertexZGen", "hVertexZGen", HistType::kTH1D, {{vertexZAxis}}); + // Histograms for xi (mc) + registryMC.add("h2dGenXiMinusVsMultMC_RecoedEvt", "h2dGenXiMinusVsMultMC_RecoedEvt", HistType::kTH2D, {axisNch, ptAxis}); + registryMC.add("h2dGenXiPlusVsMultMC_RecoedEvt", "h2dGenXiPlusVsMultMC_RecoedEvt", HistType::kTH2D, {axisNch, ptAxis}); + registryMC.add("h2dGenXiMinusVsMultMC", "h2dGenXiMinusVsMultMC", HistType::kTH2D, {axisNch, ptAxis}); + registryMC.add("h2dGenXiPlusVsMultMC", "h2dGenXiPlusVsMultMC", HistType::kTH2D, {axisNch, ptAxis}); + registryMC.add("h2dGenXiMinus", "h2dGenXiMinus", HistType::kTH2D, {centAxis, ptAxis}); + registryMC.add("h2dGenXiPlus", "h2dGenXiPlus", HistType::kTH2D, {centAxis, ptAxis}); + + // Histograms for omega (mc) + registryMC.add("h2dGenOmegaMinusVsMultMC_RecoedEvt", "h2dGenOmegaMinusVsMultMC_RecoedEvt", HistType::kTH2D, {axisNch, ptAxis}); + registryMC.add("h2dGenOmegaPlusVsMultMC_RecoedEvt", "h2dGenOmegaPlusVsMultMC_RecoedEvt", HistType::kTH2D, {axisNch, ptAxis}); + registryMC.add("h2dGenOmegaMinusVsMultMC", "h2dGenOmegaMinusVsMultMC", HistType::kTH2D, {axisNch, ptAxis}); + registryMC.add("h2dGenOmegaPlusVsMultMC", "h2dGenOmegaPlusVsMultMC", HistType::kTH2D, {axisNch, ptAxis}); + registryMC.add("h2dGenOmegaMinus", "h2dGenOmegaMinus", HistType::kTH2D, {centAxis, ptAxis}); + registryMC.add("h2dGenOmegaPlus", "h2dGenOmegaPlus", HistType::kTH2D, {centAxis, ptAxis}); + + // Histograms for event loss/splitting + registryMC.add("hGenEvents", "hGenEvents", HistType::kTH2D, {{axisNch}, {2, -0.5f, +1.5f}}); + registryMC.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(1, "All gen. events"); + registryMC.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(2, "Gen. with at least 1 rec. events"); + registryMC.add("hGenEventCentrality", "hGenEventCentrality", kTH1D, {{101, 0.0f, 101.0f}}); + + registryMC.add("hCentralityVsNcoll_beforeEvSel", "hCentralityVsNcoll_beforeEvSel", HistType::kTH2D, {centAxis, {50, -0.5f, 49.5f}}); + registryMC.add("hCentralityVsNcoll_afterEvSel", "hCentralityVsNcoll_afterEvSel", HistType::kTH2D, {centAxis, {50, -0.5f, 49.5f}}); + + registryMC.add("hCentralityVsMultMC", "hCentralityVsMultMC", HistType::kTH2D, {{101, 0.0f, 101.0f}, axisNch}); + } + } + + // ______________________________________________________ + // Return slicing output + template + auto getGroupedCollisions(TCollisions const& collisions, int globalIndex) + { + return collisions.sliceBy(perMcCollision, globalIndex); + } + + template + void initCCDB(TCollision collision) + { + if (mRunNumber == collision.runNumber()) { + return; + } + + mRunNumber = collision.runNumber(); + } + + // Find ITS hit + // template + // bool hasITSHitOnLayer(const TrackIts& track, int layer) + // { + // int ibit = layer - 1; + // return (track.itsClusterMap() & (1 << ibit)); + // } + + // 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 (track.tpcChi2NCl() > maxChi2TPC) + return false; + if (requireTOF && (!track.hasTOF())) + return false; + return true; + } + + // Xi Selection + 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; + + if (std::abs(casc.yXi()) > rapcut) + return false; + + // Xi+ Selection (Xi+ -> antiL + pi+) + if (casc.sign() > 0) { + + // 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 (casc.tofNSigmaXiLaPr() < nsigmaTOFmin || + casc.tofNSigmaXiLaPr() > nsigmaTOFmax) + return false; + if (casc.tofNSigmaXiLaPi() < nsigmaTOFmin || + casc.tofNSigmaXiLaPi() > nsigmaTOFmax) + return false; + } + } + + // Xi- Selection (Xi- -> L + pi-) + if (casc.sign() < 0) { + + // 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 (casc.tofNSigmaXiLaPr() < nsigmaTOFmin || + casc.tofNSigmaXiLaPr() > nsigmaTOFmax) + return false; + if (casc.tofNSigmaXiLaPi() < nsigmaTOFmin || + casc.tofNSigmaXiLaPi() > nsigmaTOFmax) + return false; + } + } + + if (casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ()) < v0cospaMin) + return false; + if (casc.v0radius() < minimumV0Radius) + 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; + + if (casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()) < casccospaMin) + return false; + if (casc.cascradius() < minimumCascRadius) + 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; + + // V0 mass window + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > + v0masswindow) + return false; + + // reject candidates compatible with omega + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < + competingmassrej) + return false; + + // PID Selection on bachelor + if (btrack.tpcNSigmaPi() < nsigmaTPCmin || + btrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (casc.tofNSigmaXiPi() < nsigmaTOFmin || + casc.tofNSigmaXiPi() > nsigmaTOFmax) + return false; + } + return true; + } + + // Omega Selection + 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; + + if (std::abs(casc.yOmega()) > rapcut) + return false; + + // Omega+ Selection (Omega+ -> antiL + K+) + if (casc.sign() > 0) { + // 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 (casc.tofNSigmaOmLaPr() < nsigmaTOFmin || + casc.tofNSigmaOmLaPr() > nsigmaTOFmax) + return false; + if (casc.tofNSigmaOmLaPi() < nsigmaTOFmin || + casc.tofNSigmaOmLaPi() > nsigmaTOFmax) + return false; + } + } + + // Omega- Selection (Omega- -> L + K-) + if (casc.sign() < 0) { + // 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 (casc.tofNSigmaOmLaPr() < nsigmaTOFmin || + casc.tofNSigmaOmLaPr() > nsigmaTOFmax) + return false; + if (casc.tofNSigmaOmLaPi() < nsigmaTOFmin || + casc.tofNSigmaOmLaPi() > nsigmaTOFmax) + return false; + } + } + + if (casc.v0cosPA(coll.posX(), coll.posY(), coll.posZ()) < v0cospaMin) + return false; + if (casc.v0radius() < minimumV0Radius) + 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; + + if (casc.casccosPA(coll.posX(), coll.posY(), coll.posZ()) < casccospaMin) + return false; + if (casc.cascradius() < minimumCascRadius) + 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; + + // V0 mass window + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > + v0masswindow) + return false; + + // Reject candidates compatible with Xi + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) < + competingmassrej) + return false; + + // PID Selection on bachelor + if (btrack.tpcNSigmaKa() < nsigmaTPCmin || + btrack.tpcNSigmaKa() > nsigmaTPCmax) + return false; + + // PID Selections (TOF) + if (requireTOF) { + if (casc.tofNSigmaOmKa() < nsigmaTOFmin || + casc.tofNSigmaOmKa() > nsigmaTOFmax) + return false; + } + return true; + } + + // 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) + { + 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) { + // event selections + if (applySel8 && !collision.sel8()) + continue; + + if (applyVtxZ && std::fabs(collision.posZ()) > zVtx) + continue; + + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; + } + + if (requireVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + continue; + } + + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + continue; + } + + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + continue; + } + + if (requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + continue; + } + + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + continue; + } + + // 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(); + } + } + listBestCollisionIdx[mcCollision.globalIndex()] = bestCollisionIndex; + } + return listBestCollisionIdx; + } + + // 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) { + // event selections + if (applyVtxZ && std::fabs(mcCollision.posZ()) > zVtx) + continue; + + registryMC.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; + int nCollisions = 0; + float centralitydata = 100.5f; + for (auto const& collision : groupedCollisions) { + // event selections + if (applySel8 && !collision.sel8()) + continue; + + if (applyVtxZ && std::fabs(collision.posZ()) > zVtx) + continue; + + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; + } + + if (requireVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + continue; + } + + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + continue; + } + + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + continue; + } + + if (requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + continue; + } + + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + continue; + } + + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + if (centralityEstimator == Option::kFT0C) + centralitydata = collision.centFT0C(); + if (centralityEstimator == Option::kFT0M) + centralitydata = collision.centFT0M(); + if (centralityEstimator == Option::kFV0A) + centralitydata = collision.centFV0A(); + if (centralityEstimator == Option::kNGlobal) + centralitydata = collision.centNGlobal(); + } + nCollisions++; + + atLeastOne = true; + } + + registryMC.fill(HIST("hCentralityVsNcoll_beforeEvSel"), centralitydata, groupedCollisions.size()); + registryMC.fill(HIST("hCentralityVsNcoll_afterEvSel"), centralitydata, nCollisions); + registryMC.fill(HIST("hCentralityVsMultMC"), centralitydata, mcCollision.multMCNParticlesEta05()); + + registryQC.fill(HIST("hVertexZGen"), mcCollision.posZ()); + + if (atLeastOne) { + registryMC.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 1 /* at least 1 rec. event*/); + + registryMC.fill(HIST("hGenEventCentrality"), centralitydata); + } + } + return; + } + + void processData(SelCollisions::iterator const& collision, + CascadeCandidates const& fullCascades, + DaughterTracks const&) + { + // Fill event counter before event selection + registryData.fill(HIST("number_of_events_data"), 0); + + // Initialize CCDB objects using the BC info + initCCDB(collision); + + // Define the event centrality using different estimators + float centrality = -1; + float multiplicity = -1; + + if (centralityEstimator == Option::kFT0C) { + centrality = collision.centFT0C(); + multiplicity = collision.multFT0C(); + } + if (centralityEstimator == Option::kFT0M) { + centrality = collision.centFT0M(); + multiplicity = collision.multFT0C() + collision.multFT0A(); + } + if (centralityEstimator == Option::kFV0A) { + centrality = collision.centFV0A(); + multiplicity = collision.multFV0A(); + } + if (centralityEstimator == Option::kNGlobal) { + centrality = collision.centNGlobal(); + multiplicity = collision.multNTracksGlobal(); + } + + registryData.fill(HIST("number_of_events_data_vs_centrality"), 0, centrality); + + // event selections + if (applySel8 && !collision.sel8()) + return; + registryData.fill(HIST("number_of_events_data"), 1); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 1, centrality); + + if (applyVtxZ && std::fabs(collision.posZ()) > zVtx) + return; + registryData.fill(HIST("number_of_events_data"), 2); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 2, centrality); + + if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return; + } + registryData.fill(HIST("number_of_events_data"), 3 /* Not at ITS ROF border */); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 3, centrality); + + if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return; + } + registryData.fill(HIST("number_of_events_data"), 4 /* Not at TF border */); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 4, centrality); + + if (requireVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return; + } + registryData.fill(HIST("number_of_events_data"), 5 /* Contains at least one ITS-TPC track */); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 5, centrality); + + if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + registryData.fill(HIST("number_of_events_data"), 6 /* PV position consistency check */); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 6, centrality); + + if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return; + } + registryData.fill(HIST("number_of_events_data"), 7 /* PV with at least one contributor matched with TOF */); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 7, centrality); + + if (requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return; + } + registryData.fill(HIST("number_of_events_data"), 8 /* PV with at least one contributor matched with TRD */); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 8, centrality); + + if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } + registryData.fill(HIST("number_of_events_data"), 9 /* Not at same bunch pile-up */); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 9, centrality); + + // Store the Zvtx + registryQC.fill(HIST("hVertexZdata"), collision.posZ()); + + // Store the event centrality + registryData.fill(HIST("hCentEstimator"), centrality); + registryData.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + registryData.fill(HIST("hCentralityVsMultiplicity"), centrality, multiplicity); + + // Loop over cascades + for (const auto& casc : fullCascades) { + if (etaMin > casc.bacheloreta() || casc.bacheloreta() > etaMax || + etaMin > casc.negativeeta() || casc.negativeeta() > etaMax || + etaMin > casc.positiveeta() || casc.positiveeta() > etaMax) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + + // Get cascade daughters + auto bach = casc.bachTrackExtra_as(); + auto pos = casc.posTrackExtra_as(); + auto neg = casc.negTrackExtra_as(); + + // ------------------------------------- Store selctions distribution for QC + registryQC.fill(HIST("hv0cosPAdata"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registryQC.fill(HIST("hcasccosPAdata"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registryQC.fill(HIST("hv0radiusdata"), casc.v0radius()); + registryQC.fill(HIST("hcascradiusdata"), casc.cascradius()); + registryQC.fill(HIST("hdcaV0daughtersdata"), casc.dcaV0daughters()); + registryQC.fill(HIST("hdcacascdaughtersdata"), casc.dcacascdaughters()); + registryQC.fill(HIST("hdcapostopvdata"), casc.dcapostopv()); + registryQC.fill(HIST("hdcanegtopvdata"), casc.dcanegtopv()); + registryQC.fill(HIST("hdcabachtopvdata"), casc.dcabachtopv()); + registryQC.fill(HIST("hdcav0topvdata"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + + // ------------------------------------- Store selctions distribution for analysis + if (casc.sign() < 0) { + registryData.fill(HIST("hMassXineg"), centrality, casc.pt(), casc.mXi()); + registryData.fill(HIST("hMassOmeganeg"), centrality, casc.pt(), casc.mOmega()); + } + if (casc.sign() > 0) { + registryData.fill(HIST("hMassXipos"), centrality, casc.pt(), casc.mXi()); + registryData.fill(HIST("hMassOmegapos"), centrality, casc.pt(), casc.mOmega()); + } + + if (casc.sign() < 0 && passedXiSelection(casc, pos, neg, bach, collision)) { + registryData.fill(HIST("hMassXinegSelected"), centrality, casc.pt(), casc.mXi()); + } + if (casc.sign() < 0 && passedOmegaSelection(casc, pos, neg, bach, collision)) { + registryData.fill(HIST("hMassOmeganegSelected"), centrality, casc.pt(), casc.mOmega()); + } + if (casc.sign() > 0 && passedXiSelection(casc, pos, neg, bach, collision)) { + registryData.fill(HIST("hMassXiposSelected"), centrality, casc.pt(), casc.mXi()); + } + if (casc.sign() > 0 && passedOmegaSelection(casc, pos, neg, bach, collision)) { + registryData.fill(HIST("hMassOmegaposSelected"), centrality, casc.pt(), casc.mOmega()); + } + } + } + + PROCESS_SWITCH(CascadeAnalysisLightIonsDerivedData, processData, "Process data", true); + + void processMonteCarloRec(SimCollisions const& RecCols, CascadeMCCandidates const& fullCascades, DaughterTracks const&, CascadeMCCores const&) + { + for (const auto& RecCol : RecCols) { + // Fill event counter before event selection + registryMC.fill(HIST("number_of_events_mc_rec"), 0); + + // Initialize CCDB objects using the BC info + initCCDB(RecCol); + + // Define the event centrality using different estimators + float centralityMcRec = -1; + float multiplicityMcRec = -1; + + if (centralityEstimator == Option::kFT0C) { + centralityMcRec = RecCol.centFT0C(); + multiplicityMcRec = RecCol.multFT0C(); + } + if (centralityEstimator == Option::kFT0M) { + centralityMcRec = RecCol.centFT0M(); + multiplicityMcRec = RecCol.multFT0C() + RecCol.multFT0A(); + } + if (centralityEstimator == Option::kFV0A) { + centralityMcRec = RecCol.centFV0A(); + multiplicityMcRec = RecCol.multFV0A(); + } + if (centralityEstimator == Option::kNGlobal) { + centralityMcRec = RecCol.centNGlobal(); + multiplicityMcRec = RecCol.multNTracksGlobal(); + } + + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 0, centralityMcRec); + + // event selections + if (applySel8 && !RecCol.sel8()) + continue; + registryMC.fill(HIST("number_of_events_mc_rec"), 1); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 1, centralityMcRec); + + if (applyVtxZ && std::fabs(RecCol.posZ()) > zVtx) + continue; + registryMC.fill(HIST("number_of_events_mc_rec"), 2); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 2, centralityMcRec); + + if (rejectITSROFBorder && !RecCol.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + registryMC.fill(HIST("number_of_events_mc_rec"), 3 /* Not at ITS ROF border */); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 3, centralityMcRec); + + if (rejectTFBorder && !RecCol.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; + } + registryMC.fill(HIST("number_of_events_mc_rec"), 4 /* Not at TF border */); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 4, centralityMcRec); + + if (requireVertexITSTPC && !RecCol.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + continue; + } + registryMC.fill(HIST("number_of_events_mc_rec"), 5 /* Contains at least one ITS-TPC track */); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 5, centralityMcRec); + + if (requireIsGoodZvtxFT0VsPV && !RecCol.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + continue; + } + registryMC.fill(HIST("number_of_events_mc_rec"), 6 /* PV position consistency check */); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 6, centralityMcRec); + + if (requireIsVertexTOFmatched && !RecCol.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + continue; + } + registryMC.fill(HIST("number_of_events_mc_rec"), 7 /* PV with at least one contributor matched with TOF */); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 7, centralityMcRec); + + if (requireIsVertexTRDmatched && !RecCol.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + continue; + } + registryMC.fill(HIST("number_of_events_mc_rec"), 8 /* PV with at least one contributor matched with TRD */); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 8, centralityMcRec); + + if (rejectSameBunchPileup && !RecCol.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + continue; + } + registryMC.fill(HIST("number_of_events_mc_rec"), 9 /* Not at same bunch pile-up */); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 9, centralityMcRec); + + // Store the Zvtx + registryQC.fill(HIST("hVertexZRec"), RecCol.posZ()); + + // Store the event centrality + registryMC.fill(HIST("hCentEstimator_truerec"), centralityMcRec); + registryMC.fill(HIST("hCentralityVsNch_truerec"), centralityMcRec, RecCol.multNTracksPVeta1()); + registryMC.fill(HIST("hCentralityVsMultiplicity_truerec"), centralityMcRec, multiplicityMcRec); + + for (const auto& casc : fullCascades) { + if (etaMin > casc.bacheloreta() || casc.bacheloreta() > etaMax || + etaMin > casc.negativeeta() || casc.negativeeta() > etaMax || + etaMin > casc.positiveeta() || casc.positiveeta() > etaMax) + continue; // remove acceptance that's badly reproduced by MC / superfluous in future + + if (!casc.has_cascMCCore()) + continue; + + auto cascMC = casc.template cascMCCore_as(); + + auto bach = casc.bachTrackExtra_as(); + auto pos = casc.posTrackExtra_as(); + auto neg = casc.negTrackExtra_as(); + + int pdgParent = cascMC.pdgCode(); + bool isPhysPrim = cascMC.isPhysicalPrimary(); + if (pdgParent == 0) + continue; + if (!isPhysPrim) + continue; + + float ptmc = RecoDecay::sqrtSumOfSquares(cascMC.pxMC(), cascMC.pyMC()); + + // ------------------------------------- Store selctions distribution for QC + registryQC.fill(HIST("hv0cosPARec"), casc.v0cosPA(RecCol.posX(), RecCol.posY(), RecCol.posZ())); + registryQC.fill(HIST("hcasccosPARec"), casc.casccosPA(RecCol.posX(), RecCol.posY(), RecCol.posZ())); + registryQC.fill(HIST("hv0radiusRec"), casc.v0radius()); + registryQC.fill(HIST("hcascradiusRec"), casc.cascradius()); + registryQC.fill(HIST("hdcaV0daughtersRec"), casc.dcaV0daughters()); + registryQC.fill(HIST("hdcacascdaughtersRec"), casc.dcacascdaughters()); + registryQC.fill(HIST("hdcapostopvRec"), casc.dcapostopv()); + registryQC.fill(HIST("hdcanegtopvRec"), casc.dcanegtopv()); + registryQC.fill(HIST("hdcabachtopvRec"), casc.dcabachtopv()); + registryQC.fill(HIST("hdcav0topvRec"), casc.dcav0topv(RecCol.posX(), RecCol.posY(), RecCol.posZ())); + + // ------------------------------------- Store selctions distribution for analysis + if (casc.sign() < 0) { + if (pdgParent == kXiMinus) { + registryMC.fill(HIST("hMassXineg_truerec"), centralityMcRec, ptmc, casc.mXi()); + } + if (pdgParent == kOmegaMinus) { + registryMC.fill(HIST("hMassOmeganeg_truerec"), centralityMcRec, ptmc, casc.mOmega()); + } + } + + if (casc.sign() > 0) { + if (pdgParent == kXiPlusBar) { + registryMC.fill(HIST("hMassXipos_truerec"), centralityMcRec, ptmc, casc.mXi()); + } + if (pdgParent == kOmegaPlusBar) { + registryMC.fill(HIST("hMassOmegapos_truerec"), centralityMcRec, ptmc, casc.mOmega()); + } + } + + if (casc.sign() < 0 && pdgParent == kXiMinus && passedXiSelection(casc, pos, neg, bach, RecCol)) { + registryMC.fill(HIST("hMassXinegSelected_truerec"), centralityMcRec, ptmc, casc.mXi()); + } + if (casc.sign() < 0 && pdgParent == kOmegaMinus && passedOmegaSelection(casc, pos, neg, bach, RecCol)) { + registryMC.fill(HIST("hMassOmeganegSelected_truerec"), centralityMcRec, ptmc, casc.mOmega()); + } + if (casc.sign() > 0 && pdgParent == kXiPlusBar && passedXiSelection(casc, pos, neg, bach, RecCol)) { + registryMC.fill(HIST("hMassXiposSelected_truerec"), centralityMcRec, ptmc, casc.mXi()); + } + if (casc.sign() > 0 && pdgParent == kOmegaPlusBar && passedOmegaSelection(casc, pos, neg, bach, RecCol)) { + registryMC.fill(HIST("hMassOmegaposSelected_truerec"), centralityMcRec, ptmc, casc.mOmega()); + } + } // casc loop + } // rec.collision loop + } + + PROCESS_SWITCH(CascadeAnalysisLightIonsDerivedData, processMonteCarloRec, "Process MC Rec", false); + + void processMonteCarloGen(CollisionMCTrueTable const& mcCollisions, + CascadeMCCores const& CascMCCores, + SimCollisions const& RecCols) + { + // Fill generated event information (for event loss/splitting estimation) + fillGeneratedEventProperties(mcCollisions, RecCols); + std::vector listBestCollisionIdx = getListOfRecoCollIndices(mcCollisions, RecCols); + for (auto const& cascMC : CascMCCores) { + int pdgParent = cascMC.pdgCode(); + bool isPhysPrim = cascMC.isPhysicalPrimary(); + if (pdgParent == 0) + continue; + if (!isPhysPrim) + continue; + + float ptmc = RecoDecay::sqrtSumOfSquares(cascMC.pxMC(), cascMC.pyMC()); + + auto mcCollision = cascMC.template straMCCollision_as(); + + // event selections + if (applyVtxZ && std::abs(mcCollision.posZ()) > zVtx) + continue; + + // Store the Zvtx + registryQC.fill(HIST("hVertexZGen"), mcCollision.posZ()); + + float centralityMC = 100.5f; + + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = RecCols.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + if (centralityEstimator == Option::kFT0C) + centralityMC = collision.centFT0C(); + if (centralityEstimator == Option::kFT0M) + centralityMC = collision.centFT0M(); + if (centralityEstimator == Option::kFV0A) + centralityMC = collision.centFV0A(); + if (centralityEstimator == Option::kNGlobal) + centralityMC = collision.centNGlobal(); + + if (cascMC.pdgCode() == kXiMinus && std::abs(cascMC.rapidityMC(0)) < rapcut) { + registryMC.fill(HIST("h2dGenXiMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == kXiPlusBar && std::abs(cascMC.rapidityMC(0)) < rapcut) { + registryMC.fill(HIST("h2dGenXiPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == kOmegaMinus && std::abs(cascMC.rapidityMC(2)) < rapcut) { + registryMC.fill(HIST("h2dGenOmegaMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == kOmegaPlusBar && std::abs(cascMC.rapidityMC(2)) < rapcut) { + registryMC.fill(HIST("h2dGenOmegaPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + if (cascMC.pdgCode() == kXiMinus && std::abs(cascMC.rapidityMC(0)) < rapcut) { + registryMC.fill(HIST("h2dGenXiMinus"), centralityMC, ptmc); + registryMC.fill(HIST("h2dGenXiMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == kXiPlusBar && std::abs(cascMC.rapidityMC(0)) < rapcut) { + registryMC.fill(HIST("h2dGenXiPlus"), centralityMC, ptmc); + registryMC.fill(HIST("h2dGenXiPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == kOmegaMinus && std::abs(cascMC.rapidityMC(2)) < rapcut) { + registryMC.fill(HIST("h2dGenOmegaMinus"), centralityMC, ptmc); + registryMC.fill(HIST("h2dGenOmegaMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == kOmegaPlusBar && std::abs(cascMC.rapidityMC(2)) < rapcut) { + registryMC.fill(HIST("h2dGenOmegaPlus"), centralityMC, ptmc); + registryMC.fill(HIST("h2dGenOmegaPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } // cascMC loop + } + + PROCESS_SWITCH(CascadeAnalysisLightIonsDerivedData, processMonteCarloGen, "Process MC Gen", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/cascadeanalysis.cxx b/PWGLF/Tasks/Strangeness/cascadeanalysis.cxx index baf37b72717..0b14c7fa38a 100644 --- a/PWGLF/Tasks/Strangeness/cascadeanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/cascadeanalysis.cxx @@ -28,31 +28,33 @@ // david.dobrigkeit.chinellato@cern.ch // -#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/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include #include #include -#include #include -#include #include -#include -#include +#include + #include +#include #include -#include "Framework/ASoAHelpers.h" using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Strangeness/cascadeanalysisMC.cxx b/PWGLF/Tasks/Strangeness/cascadeanalysisMC.cxx index 05df2504e4e..cd01a778474 100644 --- a/PWGLF/Tasks/Strangeness/cascadeanalysisMC.cxx +++ b/PWGLF/Tasks/Strangeness/cascadeanalysisMC.cxx @@ -31,31 +31,33 @@ // david.dobrigkeit.chinellato@cern.ch // -#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/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include #include #include -#include #include -#include #include -#include -#include +#include + #include +#include #include -#include "Framework/ASoAHelpers.h" using namespace o2; using namespace o2::framework; @@ -78,16 +80,24 @@ 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"}; + Configurable requirePhysicalPrimary{"requirePhysicalPrimary", false, "require the generated cascade to be a physical primary"}; 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 +109,26 @@ 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 (requirePhysicalPrimary && !particle.isPhysicalPrimary()) + continue; + 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 +204,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 +219,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 +375,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 +392,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 { @@ -442,7 +474,7 @@ struct cascadeAnalysisMC { } PROCESS_SWITCH(cascadeAnalysisMC, processRun2VsMultiplicity, "Process Run 2 data vs multiplicity", false); - void processRun3WithPID(soa::Join::iterator const& collision, soa::Filtered const& Cascades, aod::V0sLinked const&, FullTracksExtIUWithPID const&, aod::McParticles const&) + void processRun3WithPID(soa::Join::iterator const& collision, soa::Filtered const& Cascades, FullTracksExtIUWithPID const&, aod::McParticles const&) // process function subscribing to Run 3-like analysis objects { // Run 3 event selection criteria @@ -457,7 +489,7 @@ struct cascadeAnalysisMC { } PROCESS_SWITCH(cascadeAnalysisMC, processRun3WithPID, "Process Run 3 data with PID", false); - void processRun2WithPID(soa::Join::iterator const& collision, soa::Filtered const& Cascades, aod::V0sLinked const&, FullTracksExtWithPID const&, aod::McParticles const&) + void processRun2WithPID(soa::Join::iterator const& collision, soa::Filtered const& Cascades, FullTracksExtWithPID const&, aod::McParticles const&) // process function subscribing to Run 3-like analysis objects { // Run 2 event selection criteria diff --git a/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx b/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx index 152ca106846..9dd5e7bf9d2 100644 --- a/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx +++ b/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx @@ -15,31 +15,41 @@ // Author: Rik Spijkers (rik.spijkers@cern.ch) // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/inelGt.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 "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/Zorro.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/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include #include #include -#include +#include #include #include -#include +#include + +#include +#include +#include +#include +#include +// #include using namespace o2; using namespace o2::soa; @@ -49,10 +59,12 @@ using namespace o2::framework::expressions; using std::array; // use parameters + cov mat non-propagated, aux info + (extension propagated) -using FullTracksExt = soa::Join; -using FullTracksExtIU = soa::Join; -using FullTracksExtWithPID = soa::Join; -using FullTracksExtIUWithPID = soa::Join; +using FullTracksExt = soa::Join; +using FullTracksExtIU = soa::Join; +using FullTracksExtWithPID = 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 @@ -67,16 +79,39 @@ 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; + Service pdgDB; + 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"}; + Configurable etaCascades{"etaCascades", 0.8, "min/max of eta for cascades"}; + Configurable doCompetingMassCut{"doCompetingMassCut", true, "Switch to apply a competing mass cut for the Omega's"}; + Configurable competingMassWindow{"competingMassWindow", 0.01, "Mass window for the competing mass cut"}; + + // 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"}; + Configurable tpcChi2{"tpcChi2", 4, "TPC Chi2"}; + Configurable itsChi2{"itsChi2", 36, "ITS Chi2"}; // Selection criteria - compatible with core wagon autodetect - copied from cascadeanalysis.cxx //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -94,280 +129,703 @@ 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}"}; + ConfigurableAxis radiusAxis = {"radiusAxis", {100, 0.0f, 50.0f}, "cm"}; + ConfigurableAxis cpaAxis = {"cpaAxis", {100, 0.95f, 1.0f}, "CPA"}; + ConfigurableAxis vertexAxis = {"vertexAxis", {100, -10.0f, 10.0f}, "cm"}; + ConfigurableAxis dcaAxis = {"dcaAxis", {100, 0.0f, 2.0f}, "cm"}; + ConfigurableAxis invXiMassAxis = {"invXiMassAxis", {100, 1.28f, 1.38f}, "Inv. Mass (GeV/c^{2})"}; + ConfigurableAxis invOmegaMassAxis = {"invOmegaMassAxis", {100, 1.62f, 1.72f}, "Inv. Mass (GeV/c^{2})"}; + ConfigurableAxis ptAxis = {"ptAxis", {150, 0, 15}, "#it{p}_{T}"}; + ConfigurableAxis rapidityAxis{"rapidityAxis", {100, -1.f, 1.f}, "y"}; + ConfigurableAxis invLambdaMassAxis{"invLambdaMassAxis", {100, 1.07f, 1.17f}, "Inv. Mass (GeV/c^{2})"}; + AxisSpec itsClustersAxis{8, -0.5, 7.5, "number of ITS clusters"}; + AxisSpec tpcRowsAxis{160, -0.5, 159.5, "TPC crossed rows"}; 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, {radiusAxis, invXiMassAxis, ptAxis}}}, + {"hCascRadius", "hCascRadius", {HistType::kTH3F, {radiusAxis, invXiMassAxis, ptAxis}}}, + {"hV0CosPA", "hV0CosPA", {HistType::kTH3F, {cpaAxis, invXiMassAxis, ptAxis}}}, + {"hCascCosPA", "hCascCosPA", {HistType::kTH3F, {cpaAxis, 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, {invLambdaMassAxis, 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, {tpcRowsAxis, invXiMassAxis, ptAxis}}}, + {"hTPCnCrossedRowsNeg", "hTPCnCrossedRowsNeg", {HistType::kTH3F, {tpcRowsAxis, invXiMassAxis, ptAxis}}}, + {"hTPCnCrossedRowsBach", "hTPCnCrossedRowsBach", {HistType::kTH3F, {tpcRowsAxis, invXiMassAxis, ptAxis}}}, + {"hITSnClustersPos", "hITSnClustersPos", {HistType::kTH3F, {itsClustersAxis, invXiMassAxis, ptAxis}}}, + {"hITSnClustersNeg", "hITSnClustersNeg", {HistType::kTH3F, {itsClustersAxis, invXiMassAxis, ptAxis}}}, + {"hITSnClustersBach", "hITSnClustersBach", {HistType::kTH3F, {itsClustersAxis, invXiMassAxis, ptAxis}}}, + {"hTPCChi2Pos", "hTPCChi2Pos", {HistType::kTH1F, {{100, 0, 10, "TPC Chi2 Pos"}}}}, + {"hTPCChi2Neg", "hTPCChi2Neg", {HistType::kTH1F, {{100, 0, 10, "TPC Chi2 Neg"}}}}, + {"hTPCChi2Bach", "hTPCChi2Bach", {HistType::kTH1F, {{100, 0, 10, "TPC Chi2 Bach"}}}}, + {"hITSChi2Pos", "hITSChi2Pos", {HistType::kTH1F, {{100, 0, 100, "ITS Chi2 Pos"}}}}, + {"hITSChi2Neg", "hITSChi2Neg", {HistType::kTH1F, {{100, 0, 100, "ITS Chi2 Neg"}}}}, + {"hITSChi2Bach", "hITSChi2Bach", {HistType::kTH1F, {{100, 0, 100, "ITS Chi2 Bach"}}}}, + + {"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(4, "track Chi2 OK"); + h->GetXaxis()->SetBinLabel(5, "Topo OK"); + h->GetXaxis()->SetBinLabel(6, "Track eta OK"); + h->GetXaxis()->SetBinLabel(7, "Cascade eta OK"); + h->GetXaxis()->SetBinLabel(8, "V0 PID OK"); + h->GetXaxis()->SetBinLabel(9, "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"); + + if (doprocessRecMC) { + // only create the rec matched to gen histograms if relevant + registry.add("truerec/hV0Radius", "hV0Radius", HistType::kTH1F, {radiusAxis}); + registry.add("truerec/hCascRadius", "hCascRadius", HistType::kTH1F, {radiusAxis}); + registry.add("truerec/hV0CosPA", "hV0CosPA", HistType::kTH1F, {cpaAxis}); + registry.add("truerec/hCascCosPA", "hCascCosPA", HistType::kTH1F, {cpaAxis}); + registry.add("truerec/hDCAPosToPV", "hDCAPosToPV", HistType::kTH1F, {vertexAxis}); + registry.add("truerec/hDCANegToPV", "hDCANegToPV", HistType::kTH1F, {vertexAxis}); + registry.add("truerec/hDCABachToPV", "hDCABachToPV", HistType::kTH1F, {vertexAxis}); + registry.add("truerec/hDCAV0ToPV", "hDCAV0ToPV", HistType::kTH1F, {vertexAxis}); + registry.add("truerec/hDCAV0Dau", "hDCAV0Dau", HistType::kTH1F, {dcaAxis}); + registry.add("truerec/hDCACascDau", "hDCACascDau", HistType::kTH1F, {dcaAxis}); + registry.add("truerec/hLambdaMass", "hLambdaMass", HistType::kTH1F, {invLambdaMassAxis}); + registry.add("truerec/hTPCnCrossedRowsPos", "hTPCnCrossedRowsPos", HistType::kTH1F, {tpcRowsAxis}); + registry.add("truerec/hTPCnCrossedRowsNeg", "hTPCnCrossedRowsNeg", HistType::kTH1F, {tpcRowsAxis}); + registry.add("truerec/hTPCnCrossedRowsBach", "hTPCnCrossedRowsBach", HistType::kTH1F, {tpcRowsAxis}); + registry.add("truerec/hITSnClustersPos", "hITSnClustersPos", HistType::kTH1F, {itsClustersAxis}); + registry.add("truerec/hITSnClustersNeg", "hITSnClustersNeg", HistType::kTH1F, {itsClustersAxis}); + registry.add("truerec/hITSnClustersBach", "hITSnClustersBach", HistType::kTH1F, {itsClustersAxis}); + registry.add("truerec/hTPCChi2Pos", "hTPCChi2Pos", HistType::kTH1F, {{100, 0, 10, "TPC Chi2 Pos"}}); + registry.add("truerec/hTPCChi2Neg", "hTPCChi2Neg", HistType::kTH1F, {{100, 0, 10, "TPC Chi2 Neg"}}); + registry.add("truerec/hTPCChi2Bach", "hTPCChi2Bach", HistType::kTH1F, {{100, 0, 10, "TPC Chi2 Bach"}}); + registry.add("truerec/hITSChi2Pos", "hITSChi2Pos", HistType::kTH1F, {{100, 0, 100, "ITS Chi2 Pos"}}); + registry.add("truerec/hITSChi2Neg", "hITSChi2Neg", HistType::kTH1F, {{100, 0, 100, "ITS Chi2 Neg"}}); + registry.add("truerec/hITSChi2Bach", "hITSChi2Bach", HistType::kTH1F, {{100, 0, 100, "ITS Chi2 Bach"}}); + registry.add("truerec/hXiMinus", "hXiMinus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("truerec/hXiPlus", "hXiPlus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("truerec/hOmegaMinus", "hOmegaMinus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("truerec/hOmegaPlus", "hOmegaPlus", HistType::kTH2F, {ptAxis, rapidityAxis}); + } + + if (doprocessGenMC) { + // only create the MC gen histograms if relevant + registry.add("gen/hXiMinus", "hXiMinus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("gen/hXiPlus", "hXiPlus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("gen/hOmegaMinus", "hOmegaMinus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("gen/hOmegaPlus", "hOmegaPlus", HistType::kTH2F, {ptAxis, rapidityAxis}); + + registry.add("genwithrec/hXiMinus", "hXiMinus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("genwithrec/hXiPlus", "hXiPlus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("genwithrec/hOmegaMinus", "hOmegaMinus", HistType::kTH2F, {ptAxis, rapidityAxis}); + registry.add("genwithrec/hOmegaPlus", "hOmegaPlus", HistType::kTH2F, {ptAxis, rapidityAxis}); + + registry.add("genwithrec/hNevents", "hNevents", HistType::kTH1F, {{1, 0, 1, "N generated events with reconstructed event"}}); + registry.add("gen/hNevents", "hNevents", HistType::kTH1F, {{1, 0, 1, "N generated events"}}); + } } - void process(soa::Join::iterator const& collision, aod::CascDataExt const& Cascades, FullTracksExtIUWithPID const&) + + template + bool eventSelection(TCollision const& collision, bool fillHistos) { - for (auto& casc : Cascades) { - - // these are the tracks: - auto bachTrack = casc.bachelor_as(); - auto posTrack = casc.posTrack_as(); - auto negTrack = casc.negTrack_as(); - - // topo variables before cuts: - registry.fill(HIST("hV0Radius"), casc.v0radius(), casc.mXi(), casc.pt()); - registry.fill(HIST("hCascRadius"), casc.cascradius(), casc.mXi(), casc.pt()); - registry.fill(HIST("hV0CosPA"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), casc.mXi(), casc.pt()); - registry.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), casc.mXi(), casc.pt()); - registry.fill(HIST("hDCAPosToPV"), casc.dcapostopv(), casc.mXi(), casc.pt()); - registry.fill(HIST("hDCANegToPV"), casc.dcanegtopv(), casc.mXi(), casc.pt()); - registry.fill(HIST("hDCABachToPV"), casc.dcabachtopv(), casc.mXi(), casc.pt()); - registry.fill(HIST("hDCAV0ToPV"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()), casc.mXi(), casc.pt()); - registry.fill(HIST("hDCAV0Dau"), casc.dcaV0daughters(), casc.mXi(), casc.pt()); - registry.fill(HIST("hDCACascDau"), casc.dcacascdaughters(), casc.mXi(), casc.pt()); - registry.fill(HIST("hLambdaMass"), casc.mLambda(), casc.mXi(), casc.pt()); - - registry.fill(HIST("hITSnClustersPos"), posTrack.itsNCls(), casc.mXi(), casc.pt()); - registry.fill(HIST("hITSnClustersNeg"), negTrack.itsNCls(), casc.mXi(), casc.pt()); - registry.fill(HIST("hITSnClustersBach"), bachTrack.itsNCls(), casc.mXi(), casc.pt()); - registry.fill(HIST("hTPCnCrossedRowsPos"), posTrack.tpcNClsCrossedRows(), casc.mXi(), casc.pt()); - registry.fill(HIST("hTPCnCrossedRowsNeg"), negTrack.tpcNClsCrossedRows(), casc.mXi(), casc.pt()); - 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()); - - // TPC N crossed rows - if (posTrack.tpcNClsCrossedRows() < minTPCCrossedRows || negTrack.tpcNClsCrossedRows() < minTPCCrossedRows || bachTrack.tpcNClsCrossedRows() < minTPCCrossedRows) { - cascflags(0); - continue; + if (useTrigger) { + auto bc = collision.template bc_as(); + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerList); + bool eventTrigger = zorro.isSelected(bc.globalBC()); + if (eventTrigger) { + if (fillHistos) + registry.fill(HIST("hTriggerQA"), 1); + } else { + if (fillHistos) + registry.fill(HIST("hTriggerQA"), 0); + return false; } - registry.fill(HIST("hSelectionStatus"), 1); // passes nTPC crossed rows - registry.fill(HIST("hMassXi1"), casc.mXi(), casc.pt()); + } + // fill event selection based on which selection criteria are applied and passed + if (fillHistos) + registry.fill(HIST("hEventSel"), 0); + if (doSel8 && !collision.sel8()) { + if (fillHistos) + registry.fill(HIST("hEventSel"), 1); + return false; + } else if (collision.multNTracksPVeta1() <= INEL) { + if (fillHistos) + registry.fill(HIST("hEventSel"), 2); + return false; + } else if (std::abs(collision.posZ()) > maxVertexZ) { + if (fillHistos) + registry.fill(HIST("hEventSel"), 3); + return false; + } else if (doNoSameBunchPileUp && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + if (fillHistos) + registry.fill(HIST("hEventSel"), 4); + return false; + } + // passes all selections + if (fillHistos) + registry.fill(HIST("hEventSel"), 5); + return true; + } - // ITS N clusters - 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()); - - //// TOPO CUTS //// TODO: improve! - double pvx = collision.posX(); - double pvy = collision.posY(); - double pvz = collision.posZ(); - if (casc.v0radius() < v0setting_radius || - casc.cascradius() < cascadesetting_cascradius || - casc.v0cosPA(pvx, pvy, pvz) < v0setting_cospa || - casc.casccosPA(pvx, pvy, pvz) < cascadesetting_cospa || - casc.dcav0topv(pvx, pvy, pvz) < cascadesetting_mindcav0topv || - TMath::Abs(casc.mLambda() - 1.115683) > cascadesetting_v0masswindow) { - // It failed at least one topo selection - cascflags(0); - continue; + template + void fillMatchedHistos(LabeledCascades::iterator rec, int flag, TCollision collision) + { + if (flag == 0) + return; + if (!rec.has_mcParticle()) + return; + auto gen = rec.mcParticle(); + if (!gen.isPhysicalPrimary()) + return; + int genpdg = gen.pdgCode(); + if ((flag < 3 && std::abs(genpdg) == 3312) || (flag > 1 && std::abs(genpdg) == 3334)) { + // if casc is consistent with Xi and has matched gen Xi OR cand is consistent with Omega and has matched gen omega + // have to do this in case we reco true Xi with only Omega hypothesis (or vice versa) (very unlikely) + registry.fill(HIST("truerec/hV0Radius"), rec.v0radius()); + registry.fill(HIST("truerec/hCascRadius"), rec.cascradius()); + registry.fill(HIST("truerec/hV0CosPA"), rec.v0cosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("truerec/hCascCosPA"), rec.casccosPA(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("truerec/hDCAPosToPV"), rec.dcapostopv()); + registry.fill(HIST("truerec/hDCANegToPV"), rec.dcanegtopv()); + registry.fill(HIST("truerec/hDCABachToPV"), rec.dcabachtopv()); + registry.fill(HIST("truerec/hDCAV0ToPV"), rec.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + registry.fill(HIST("truerec/hDCAV0Dau"), rec.dcaV0daughters()); + registry.fill(HIST("truerec/hDCACascDau"), rec.dcacascdaughters()); + registry.fill(HIST("truerec/hLambdaMass"), rec.mLambda()); + registry.fill(HIST("truerec/hITSnClustersPos"), rec.posTrack_as().itsNCls()); + registry.fill(HIST("truerec/hITSnClustersNeg"), rec.negTrack_as().itsNCls()); + registry.fill(HIST("truerec/hITSnClustersBach"), rec.bachelor_as().itsNCls()); + registry.fill(HIST("truerec/hTPCnCrossedRowsPos"), rec.posTrack_as().tpcNClsCrossedRows()); + registry.fill(HIST("truerec/hTPCnCrossedRowsNeg"), rec.negTrack_as().tpcNClsCrossedRows()); + registry.fill(HIST("truerec/hTPCnCrossedRowsBach"), rec.bachelor_as().tpcNClsCrossedRows()); + registry.fill(HIST("truerec/hITSChi2Pos"), rec.posTrack_as().itsChi2NCl()); + registry.fill(HIST("truerec/hITSChi2Neg"), rec.negTrack_as().itsChi2NCl()); + registry.fill(HIST("truerec/hITSChi2Bach"), rec.bachelor_as().itsChi2NCl()); + registry.fill(HIST("truerec/hTPCChi2Pos"), rec.posTrack_as().tpcChi2NCl()); + registry.fill(HIST("truerec/hTPCChi2Neg"), rec.negTrack_as().tpcChi2NCl()); + registry.fill(HIST("truerec/hTPCChi2Bach"), rec.bachelor_as().tpcChi2NCl()); + switch (genpdg) { // is matched so we can use genpdg + case 3312: + registry.fill(HIST("truerec/hXiMinus"), rec.pt(), rec.yXi()); + break; + case -3312: + registry.fill(HIST("truerec/hXiPlus"), rec.pt(), rec.yXi()); + break; + case 3334: + registry.fill(HIST("truerec/hOmegaMinus"), rec.pt(), rec.yOmega()); + break; + case -3334: + registry.fill(HIST("truerec/hOmegaPlus"), rec.pt(), rec.yOmega()); + break; } - registry.fill(HIST("hSelectionStatus"), 3); // passes topo - registry.fill(HIST("hMassXi3"), casc.mXi(), casc.pt()); + } + } - // TODO: TOF (for pT > 2 GeV per track?) + template + int processCandidate(TCascade const& casc, TCollision const& collision) + { + // these are the tracks: + auto bachTrack = casc.template bachelor_as(); + auto posTrack = casc.template posTrack_as(); + auto negTrack = casc.template negTrack_as(); - //// TPC PID //// - // Lambda check - if (casc.sign() < 0) { - // Proton check: - if (TMath::Abs(posTrack.tpcNSigmaPr()) > tpcNsigmaProton) { - cascflags(0); - continue; - } - // Pion check: - if (TMath::Abs(negTrack.tpcNSigmaPi()) > tpcNsigmaPion) { - cascflags(0); - continue; + // topo variables before cuts: + registry.fill(HIST("hV0Radius"), casc.v0radius(), casc.mXi(), casc.pt()); + registry.fill(HIST("hCascRadius"), casc.cascradius(), casc.mXi(), casc.pt()); + registry.fill(HIST("hV0CosPA"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), casc.mXi(), casc.pt()); + registry.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), casc.mXi(), casc.pt()); + registry.fill(HIST("hDCAPosToPV"), casc.dcapostopv(), casc.mXi(), casc.pt()); + registry.fill(HIST("hDCANegToPV"), casc.dcanegtopv(), casc.mXi(), casc.pt()); + registry.fill(HIST("hDCABachToPV"), casc.dcabachtopv(), casc.mXi(), casc.pt()); + registry.fill(HIST("hDCAV0ToPV"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()), casc.mXi(), casc.pt()); + registry.fill(HIST("hDCAV0Dau"), casc.dcaV0daughters(), casc.mXi(), casc.pt()); + registry.fill(HIST("hDCACascDau"), casc.dcacascdaughters(), casc.mXi(), casc.pt()); + registry.fill(HIST("hLambdaMass"), casc.mLambda(), casc.mXi(), casc.pt()); + + registry.fill(HIST("hITSnClustersPos"), posTrack.itsNCls(), casc.mXi(), casc.pt()); + registry.fill(HIST("hITSnClustersNeg"), negTrack.itsNCls(), casc.mXi(), casc.pt()); + registry.fill(HIST("hITSnClustersBach"), bachTrack.itsNCls(), casc.mXi(), casc.pt()); + registry.fill(HIST("hTPCnCrossedRowsPos"), posTrack.tpcNClsCrossedRows(), casc.mXi(), casc.pt()); + registry.fill(HIST("hTPCnCrossedRowsNeg"), negTrack.tpcNClsCrossedRows(), casc.mXi(), casc.pt()); + registry.fill(HIST("hTPCnCrossedRowsBach"), bachTrack.tpcNClsCrossedRows(), casc.mXi(), casc.pt()); + registry.fill(HIST("hITSChi2Pos"), posTrack.itsChi2NCl()); + registry.fill(HIST("hITSChi2Neg"), negTrack.itsChi2NCl()); + registry.fill(HIST("hITSChi2Bach"), bachTrack.itsChi2NCl()); + registry.fill(HIST("hTPCChi2Pos"), posTrack.tpcChi2NCl()); + registry.fill(HIST("hTPCChi2Neg"), negTrack.tpcChi2NCl()); + registry.fill(HIST("hTPCChi2Bach"), bachTrack.tpcChi2NCl()); + + registry.fill(HIST("hSelectionStatus"), 0); // all the cascade before selections + // registry.fill(HIST("hMassXi0"), casc.mXi(), casc.pt()); + + // TPC N crossed rows todo: check if minTPCCrossedRows > 50 + if (posTrack.tpcNClsCrossedRows() < minTPCCrossedRows || negTrack.tpcNClsCrossedRows() < minTPCCrossedRows || bachTrack.tpcNClsCrossedRows() < minTPCCrossedRows) + return 0; + + registry.fill(HIST("hSelectionStatus"), 1); // passes nTPC crossed rows + // registry.fill(HIST("hMassXi1"), casc.mXi(), casc.pt()); + + // ITS N clusters todo: check if minITSClusters > 0 + if (posTrack.itsNCls() < minITSClusters || negTrack.itsNCls() < minITSClusters || bachTrack.itsNCls() < minITSClusters) + return 0; + + registry.fill(HIST("hSelectionStatus"), 2); // passes nITS clusters + // registry.fill(HIST("hMassXi2"), casc.mXi(), casc.pt()); + + // Chi2 cuts + if (posTrack.itsChi2NCl() > itsChi2 || negTrack.itsChi2NCl() > itsChi2 || bachTrack.itsChi2NCl() > itsChi2) + return 0; + if (posTrack.tpcChi2NCl() > tpcChi2 || negTrack.tpcChi2NCl() > tpcChi2 || bachTrack.tpcChi2NCl() > tpcChi2) + return 0; + + registry.fill(HIST("hSelectionStatus"), 3); // passes Chi2 cuts + + //// TOPO CUTS //// TODO: improve! + double pvx = collision.posX(); + double pvy = collision.posY(); + double pvz = collision.posZ(); + if (casc.v0radius() < v0setting_radius || + casc.cascradius() < cascadesetting_cascradius || + casc.v0cosPA(pvx, pvy, pvz) < v0setting_cospa || + casc.casccosPA(pvx, pvy, pvz) < cascadesetting_cospa || + casc.dcav0topv(pvx, pvy, pvz) < cascadesetting_mindcav0topv || + std::abs(casc.mLambda() - 1.115683) > cascadesetting_v0masswindow) + return 0; // It failed at least one topo selection + + registry.fill(HIST("hSelectionStatus"), 4); // passes topo + // registry.fill(HIST("hMassXi3"), casc.mXi(), casc.pt()); + + if (std::abs(posTrack.eta()) > etaTracks || std::abs(negTrack.eta()) > etaTracks || std::abs(bachTrack.eta()) > etaTracks) + return 0; + + registry.fill(HIST("hSelectionStatus"), 5); // passes track eta + + if (std::abs(casc.eta()) > etaCascades) + return 0; + + registry.fill(HIST("hSelectionStatus"), 6); // passes candidate eta + + // TODO: TOF (for pT > 2 GeV per track?) + + //// TPC PID //// + // Lambda check + if (casc.sign() < 0) { + // Proton check: + if (std::abs(posTrack.tpcNSigmaPr()) > tpcNsigmaProton) + return 0; + // Pion check: + if (std::abs(negTrack.tpcNSigmaPi()) > tpcNsigmaPion) + return 0; + } else { + // Proton check: + if (std::abs(negTrack.tpcNSigmaPr()) > tpcNsigmaProton) + return 0; + // Pion check: + if (std::abs(posTrack.tpcNSigmaPi()) > tpcNsigmaPion) + return 0; + } + registry.fill(HIST("hSelectionStatus"), 7); // passes V0 daughters PID + // registry.fill(HIST("hMassXi4"), casc.mXi(), casc.pt()); + + // setting selection flag based on bachelor PID (and competing mass cut for omega's) + int flag = 0; + if (std::abs(bachTrack.tpcNSigmaPi()) < tpcNsigmaBachelor) + flag = 1; + if (std::abs(bachTrack.tpcNSigmaKa()) < tpcNsigmaBachelor && (!doCompetingMassCut || std::abs(pdgDB->Mass(3312) - casc.mXi()) > competingMassWindow)) + flag = 3 - flag; // 3 if only consistent with omega, 2 if consistent with both + + switch (flag) { + case 1: // only Xi + registry.fill(HIST("hSelectionStatus"), 8); // passes bach PID + 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()); } - } else { - // Proton check: - if (TMath::Abs(negTrack.tpcNSigmaPr()) > tpcNsigmaProton) { - cascflags(0); - continue; + break; + case 2: // Xi or Omega + registry.fill(HIST("hSelectionStatus"), 8); // passes bach PID + 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()); } - // Pion check: - if (TMath::Abs(posTrack.tpcNSigmaPi()) > tpcNsigmaPion) { - cascflags(0); - continue; + break; + case 3: // only Omega + registry.fill(HIST("hSelectionStatus"), 8); // 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()); } + break; + } + + return flag; + + } // processCandidate + + void processGenMC(aod::McCollision const& mcCollision, soa::SmallGroups> const& collisions, aod::McParticles const& mcParticles) + { + // evsel + if (INEL >= 0 && !pwglf::isINELgtNmc(mcParticles, INEL, pdgDB)) + return; + if (std::abs(mcCollision.posZ()) > maxVertexZ) + return; + + registry.fill(HIST("gen/hNevents"), 0); + + for (auto const& mcPart : mcParticles) { + if (!mcPart.isPhysicalPrimary()) + continue; + if (std::abs(mcPart.eta()) > etaCascades) + continue; + + switch (mcPart.pdgCode()) { + case 3312: + registry.fill(HIST("gen/hXiMinus"), mcPart.pt(), mcPart.y()); + break; + case -3312: + registry.fill(HIST("gen/hXiPlus"), mcPart.pt(), mcPart.y()); + break; + case 3334: + registry.fill(HIST("gen/hOmegaMinus"), mcPart.pt(), mcPart.y()); + break; + case -3334: + registry.fill(HIST("gen/hOmegaPlus"), mcPart.pt(), mcPart.y()); + break; } - registry.fill(HIST("hSelectionStatus"), 4); // fails at 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()); - continue; + } + + // Do the same thing, but now making sure there is at least one matched reconstructed event: + if (collisions.size() < 1) { + return; + } else { + bool evSel = false; // will be true if at least one rec. collision passes evsel + for (auto const& collision : collisions) { + // can be more than 1 rec. collisions due to event splitting + evSel = eventSelection(collision, false); + if (evSel) // exit loop if we find 1 rec. event that passes evsel + break; + } + if (evSel) { + // N gen events with a reconstructed event + registry.fill(HIST("genwithrec/hNevents"), 0); + + for (auto const& mcPart : mcParticles) { + if (!mcPart.isPhysicalPrimary()) + continue; + if (std::abs(mcPart.eta()) > etaCascades) + continue; + + switch (mcPart.pdgCode()) { + case 3312: + registry.fill(HIST("genwithrec/hXiMinus"), mcPart.pt(), mcPart.y()); + break; + case -3312: + registry.fill(HIST("genwithrec/hXiPlus"), mcPart.pt(), mcPart.y()); + break; + case 3334: + registry.fill(HIST("genwithrec/hOmegaMinus"), mcPart.pt(), mcPart.y()); + break; + case -3334: + registry.fill(HIST("genwithrec/hOmegaPlus"), mcPart.pt(), mcPart.y()); + break; + } } - cascflags(1); - registry.fill(HIST("hSelectionStatus"), 5); // passes bach PID - registry.fill(HIST("hMassXi5"), casc.mXi(), casc.pt()); + } + } + } // processGen + + // wrappers for data/MC processes on reco level + void processRecData(MyCollisions::iterator const& collision, aod::CascDataExt const& Cascades, FullTracksExtIUWithPID const&, aod::BCsWithTimestamps const&) + { + bool evSel = eventSelection(collision, true); + // do not skip the collision if event selection fails - this will lead to the cascadeFlag table having less entries than the Cascade table, and therefor not joinable. + for (auto const& casc : Cascades) { + if (!evSel) { + cascflags(0); continue; - } else if (TMath::Abs(bachTrack.tpcNSigmaKa()) < tpcNsigmaBachelor) { - cascflags(3); - registry.fill(HIST("hSelectionStatus"), 5); // passes bach PID + } + int flag = processCandidate(casc, collision); + cascflags(flag); + } + } + + void processRecMC(MyCollisions::iterator const& collision, LabeledCascades const& Cascades, FullTracksExtIUWithPID const&, aod::BCsWithTimestamps const&, aod::McParticles const&) + { + bool evSel = eventSelection(collision, true); + // do not skip the collision if event selection fails - this will lead to the cascadeFlag table having less entries than the Cascade table, and therefor not joinable. + for (auto const& casc : Cascades) { + if (!evSel) { + cascflags(0); continue; } - // if we reach here, the bachelor was neither pion nor kaon - cascflags(0); - } // cascade loop - } // process -}; // struct + int flag = processCandidate(casc, collision); + cascflags(flag); + // do mc matching here + fillMatchedHistos(casc, flag, collision); // if sign < 0 then pdg > 0 + } + } + + PROCESS_SWITCH(CascadeSelector, processRecData, "Process rec data", true); + PROCESS_SWITCH(CascadeSelector, processRecMC, "Process rec MC", false); + PROCESS_SWITCH(CascadeSelector, processGenMC, "Process gen MC", false); +}; // 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"}; + 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"}; + + ConfigurableAxis radiusAxis = {"radiusAxis", {100, 0.0f, 50.0f}, "cm"}; + ConfigurableAxis cpaAxis = {"cpaAxis", {100, 0.95f, 1.0f}, "CPA"}; + ConfigurableAxis invMassAxis = {"invMassAxis", {1000, 1.0f, 2.0f}, "Inv. Mass (GeV/c^{2})"}; + ConfigurableAxis deltaPhiAxis = {"deltaPhiAxis", {180, -PIHalf, 3 * PIHalf}, "#Delta#varphi"}; // 180 is divisible by 18 (tpc sectors) and 20 (run 2 binning) + ConfigurableAxis ptAxis = {"ptAxis", {150, 0, 15}, "#it{p}_{T}"}; + ConfigurableAxis vertexAxis = {"vertexAxis", {200, -10.0f, 10.0f}, "cm"}; + ConfigurableAxis dcaAxis = {"dcaAxis", {100, 0.0f, 2.0f}, "cm"}; + ConfigurableAxis multiplicityAxis{"multiplicityAxis", {100, 0, 100}, "Multiplicity (centFT0M?)"}; + ConfigurableAxis invLambdaMassAxis{"invLambdaMassAxis", {100, 1.07f, 1.17f}, "Inv. Mass (GeV/c^{2})"}; + AxisSpec signAxis{3, -1.5, 1.5, "sign of cascade"}; + AxisSpec deltaYAxis{40, -2.f, 2.f, "#Delta y"}; + AxisSpec rapidityAxis{100, -1.f, 1.f, "y"}; + AxisSpec selectionFlagAxis{4, -0.5f, 3.5f, "Selection flag of casc candidate"}; + AxisSpec itsClustersAxis{8, -0.5, 7.5, "number of ITS clusters"}; + AxisSpec tpcRowsAxis{160, -0.5, 159.5, "TPC crossed rows"}; + + // 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(TH1* h, double pT, double y = 0) + { + // This function returns 1 / eff + double eff = h->GetBinContent(h->FindFixBin(pT, y)); + if (eff == 0) + return 0; + else + return 1. / eff; + } - 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}"}; - 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?)"}; + bool autoCorrelation(std::array triggerTracks, std::array assocTracks) + { + // function that loops over 2 arrays of track indices, checking for common elements + for (int triggerTrack : triggerTracks) { + for (int assocTrack : assocTracks) { + if (triggerTrack == assocTrack) + return true; + } + } + return false; + } HistogramRegistry registry{ "registry", { // inv mass - {"hMassXiMinus", "hMassXiMinus", {HistType::kTH2F, {invMassAxis, ptAxis}}}, - {"hMassXiPlus", "hMassXiPlus", {HistType::kTH2F, {invMassAxis, ptAxis}}}, - {"hMassOmegaMinus", "hMassOmegaMinus", {HistType::kTH2F, {invMassAxis, ptAxis}}}, - {"hMassOmegaPlus", "hMassOmegaPlus", {HistType::kTH2F, {invMassAxis, ptAxis}}}, + {"hMassXiMinus", "hMassXiMinus", {HistType::kTH3F, {{200, 1.24, 1.44, "Inv. Mass (GeV/c^{2})"}, ptAxis, rapidityAxis}}}, + {"hMassXiPlus", "hMassXiPlus", {HistType::kTH3F, {{200, 1.24, 1.44, "Inv. Mass (GeV/c^{2})"}, ptAxis, rapidityAxis}}}, + {"hMassOmegaMinus", "hMassOmegaMinus", {HistType::kTH3F, {{200, 1.6, 1.8, "Inv. Mass (GeV/c^{2})"}, ptAxis, rapidityAxis}}}, + {"hMassOmegaPlus", "hMassOmegaPlus", {HistType::kTH3F, {{200, 1.6, 1.8, "Inv. Mass (GeV/c^{2})"}, ptAxis, rapidityAxis}}}, + // efficiency corrected inv mass + {"hMassXiEffCorrected", "hMassXiEffCorrected", {HistType::kTHnSparseF, {invMassAxis, signAxis, ptAxis, rapidityAxis, vertexAxis, multiplicityAxis}}, true}, + {"hMassOmegaEffCorrected", "hMassOmegaEffCorrected", {HistType::kTHnSparseF, {invMassAxis, signAxis, ptAxis, rapidityAxis, vertexAxis, multiplicityAxis}}, true}, - // basic selection variables - {"hV0Radius", "hV0Radius", {HistType::kTH1F, {{1000, 0.0f, 100.0f, "cm"}}}}, - {"hCascRadius", "hCascRadius", {HistType::kTH1F, {{1000, 0.0f, 100.0f, "cm"}}}}, - {"hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.95f, 1.0f}}}}, - {"hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{100, 0.95f, 1.0f}}}}, + // trigger QA + {"hTriggerQA", "hTriggerQA", {HistType::kTH1F, {{2, -0.5, 1.5, "Trigger y/n"}}}}, + + // basic selection variables (after cuts) + {"hV0Radius", "hV0Radius", {HistType::kTH1F, {radiusAxis}}}, + {"hCascRadius", "hCascRadius", {HistType::kTH1F, {radiusAxis}}}, + {"hV0CosPA", "hV0CosPA", {HistType::kTH1F, {cpaAxis}}}, + {"hCascCosPA", "hCascCosPA", {HistType::kTH1F, {cpaAxis}}}, {"hDCAPosToPV", "hDCAPosToPV", {HistType::kTH1F, {vertexAxis}}}, {"hDCANegToPV", "hDCANegToPV", {HistType::kTH1F, {vertexAxis}}}, {"hDCABachToPV", "hDCABachToPV", {HistType::kTH1F, {vertexAxis}}}, {"hDCAV0ToPV", "hDCAV0ToPV", {HistType::kTH1F, {vertexAxis}}}, - {"hDCAV0Dau", "hDCAV0Dau", {HistType::kTH1F, {{100, 0.0f, 10.0f, "cm^{2}"}}}}, - {"hDCACascDau", "hDCACascDau", {HistType::kTH1F, {{100, 0.0f, 10.0f, "cm^{2}"}}}}, - {"hLambdaMass", "hLambdaMass", {HistType::kTH1F, {{500, 1.0f, 1.5f, "Inv. Mass (GeV/c^{2})"}}}}, + {"hDCAV0Dau", "hDCAV0Dau", {HistType::kTH1F, {dcaAxis}}}, + {"hDCACascDau", "hDCACascDau", {HistType::kTH1F, {dcaAxis}}}, + {"hLambdaMass", "hLambdaMass", {HistType::kTH1F, {invLambdaMassAxis}}}, + {"hTPCnCrossedRowsPos", "hTPCnCrossedRowsPos", {HistType::kTH1F, {tpcRowsAxis}}}, + {"hTPCnCrossedRowsNeg", "hTPCnCrossedRowsNeg", {HistType::kTH1F, {tpcRowsAxis}}}, + {"hTPCnCrossedRowsBach", "hTPCnCrossedRowsBach", {HistType::kTH1F, {tpcRowsAxis}}}, + {"hITSnClustersPos", "hITSnClustersPos", {HistType::kTH1F, {itsClustersAxis}}}, + {"hITSnClustersNeg", "hITSnClustersNeg", {HistType::kTH1F, {itsClustersAxis}}}, + {"hITSnClustersBach", "hITSnClustersBach", {HistType::kTH1F, {itsClustersAxis}}}, {"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 + + {"hXiXi", "hXiXi", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, signAxis, signAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hXiOm", "hXiOm", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, signAxis, signAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"hOmOm", "hOmOm", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, signAxis, signAxis, 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/hMEXiXi", "hMEXiXi", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, signAxis, signAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEXiOm", "hMEXiOm", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, signAxis, signAxis, ptAxis, ptAxis, invMassAxis, invMassAxis, vertexAxis, multiplicityAxis}}, true}, + {"MixedEvents/hMEOmOm", "hMEOmOm", {HistType::kTHnSparseF, {deltaPhiAxis, deltaYAxis, signAxis, signAxis, 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"}}}}, + + // debug + {"MC/hPhi", "hPhi", {HistType::kTH1F, {{180, 0, TwoPI}}}}, + {"MC/hEta", "hEta", {HistType::kTH1F, {{100, -2, 2}}}}, + {"MC/hRapidity", "hRapidity", {HistType::kTH1F, {{100, -2, 2}}}}, }, }; // 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()); + registry.fill(HIST("hMassXiMinus"), casc.mXi(), casc.pt(), casc.yXi()); + weight = getEfficiency(hEffXiMin, casc.pt(), casc.yXi()); } else { - registry.fill(HIST("hMassXiPlus"), casc.mXi(), casc.pt()); + registry.fill(HIST("hMassXiPlus"), casc.mXi(), casc.pt(), casc.yXi()); + weight = getEfficiency(hEffXiPlus, casc.pt(), casc.yXi()); } + // LOGF(info, "casc pt %f, weight %f", casc.pt(), weight); + registry.fill(HIST("hMassXiEffCorrected"), casc.mXi(), casc.sign(), casc.pt(), casc.yXi(), collision.posZ(), collision.centFT0M(), 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()); + registry.fill(HIST("hMassOmegaMinus"), casc.mOmega(), casc.pt(), casc.yOmega()); + weight = getEfficiency(hEffOmegaMin, casc.pt(), casc.yOmega()); } else { - registry.fill(HIST("hMassOmegaPlus"), casc.mOmega(), casc.pt()); + registry.fill(HIST("hMassOmegaPlus"), casc.mOmega(), casc.pt(), casc.yOmega()); + weight = getEfficiency(hEffOmegaPlus, casc.pt(), casc.yOmega()); } + registry.fill(HIST("hMassOmegaEffCorrected"), casc.mOmega(), casc.sign(), casc.pt(), casc.yOmega(), collision.posZ(), collision.centFT0M(), weight); + registry.fill(HIST("hRapidityOmega"), casc.yOmega()); } registry.fill(HIST("hV0Radius"), casc.v0radius()); registry.fill(HIST("hCascRadius"), casc.cascradius()); @@ -380,6 +838,12 @@ struct cascadeCorrelations { registry.fill(HIST("hDCAV0Dau"), casc.dcaV0daughters()); registry.fill(HIST("hDCACascDau"), casc.dcacascdaughters()); registry.fill(HIST("hLambdaMass"), casc.mLambda()); + registry.fill(HIST("hITSnClustersPos"), casc.posTrack_as().itsNCls()); + registry.fill(HIST("hITSnClustersNeg"), casc.negTrack_as().itsNCls()); + registry.fill(HIST("hITSnClustersBach"), casc.bachelor_as().itsNCls()); + registry.fill(HIST("hTPCnCrossedRowsPos"), casc.posTrack_as().tpcNClsCrossedRows()); + registry.fill(HIST("hTPCnCrossedRowsNeg"), casc.negTrack_as().tpcNClsCrossedRows()); + registry.fill(HIST("hTPCnCrossedRowsBach"), casc.bachelor_as().tpcNClsCrossedRows()); registry.fill(HIST("hSelectionFlag"), casc.isSelected()); registry.fill(HIST("hPhi"), casc.phi()); @@ -396,111 +860,76 @@ struct cascadeCorrelations { auto trigger = *triggerAddress; auto assoc = *assocAddress; - // track indices for posterior checks - // retains logic of V0 index while being safe wrt data model - int posIdTrigg = trigger.posTrackId(); - int negIdTrigg = trigger.negTrackId(); - int posIdAssoc = assoc.posTrackId(); - int negIdAssoc = assoc.negTrackId(); + // autocorrelation check + std::array triggerTracks = {trigger.posTrackId(), trigger.negTrackId(), trigger.bachelorId()}; + std::array assocTracks = {assoc.posTrackId(), assoc.negTrackId(), assoc.bachelorId()}; + if (autoCorrelation(triggerTracks, assocTracks)) + continue; // 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 - - // Fill the correct histograms based on same-sign or opposite-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) { - if (trigger.sign() > 0 && trigger.bachelorId() == posIdAssoc) { - // K+ from trigger Omega is the same as proton from assoc lambda - registry.fill(HIST("hAutoCorrelationOS"), 1); - continue; - } - if (trigger.sign() < 0 && trigger.bachelorId() == negIdAssoc) { - // K- from trigger Omega is the same as antiproton from assoc antilambda - registry.fill(HIST("hAutoCorrelationOS"), -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("hAutoCorrelationOS"), 1); - continue; - } - if (assoc.sign() < 0 && assoc.bachelorId() == negIdTrigg) { - // K- from assoc Omega is the same as antiproton from trigger antilambda - registry.fill(HIST("hAutoCorrelationOS"), -1); - continue; - } - } + double weightTrigg = 1.; + double weightAssoc = 1.; - 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); - } 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("hAutoCorrelation"), 0); - continue; + if (trigger.isSelected() <= 2 && std::abs(trigger.yXi()) < maxRapidity) { // trigger Xi + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? getEfficiency(hEffXiMin, trigger.pt()) : getEfficiency(hEffXiPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && std::abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? getEfficiency(hEffXiMin, assoc.pt()) : getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("hXiXi"), dphi, trigger.yXi() - assoc.yXi(), trigger.sign(), assoc.sign(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, collision.posZ(), collision.centFT0M(), weightTrigg * weightAssoc); } - 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("hAutoCorrelation"), 1); - continue; + if (assoc.isSelected() >= 2 && std::abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? getEfficiency(hEffOmegaMin, assoc.pt()) : getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("hXiOm"), dphi, trigger.yXi() - assoc.yOmega(), trigger.sign(), assoc.sign(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, collision.posZ(), collision.centFT0M(), weightTrigg * weightAssoc); } - // 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("hAutoCorrelation"), 2); - continue; + } + if (trigger.isSelected() >= 2 && std::abs(trigger.yOmega()) < maxRapidity) { // trigger Omega + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? getEfficiency(hEffOmegaMin, trigger.pt()) : getEfficiency(hEffOmegaPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && std::abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? getEfficiency(hEffXiMin, assoc.pt()) : getEfficiency(hEffXiPlus, assoc.pt()); + // if Omega-Xi, fill the Xi-Omega histogram (flip the trigger/assoc and dphy,dy signs) + registry.fill(HIST("hXiOm"), RecoDecay::constrainAngle(assoc.phi() - trigger.phi(), -PIHalf), -(trigger.yOmega() - assoc.yXi()), assoc.sign(), trigger.sign(), assoc.pt(), trigger.pt(), invMassXiAssoc, invMassOmTrigg, collision.posZ(), collision.centFT0M(), weightTrigg * weightAssoc); } - 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("hAutoCorrelation"), 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("hAutoCorrelation"), 3); - continue; - } + if (assoc.isSelected() >= 2 && std::abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? getEfficiency(hEffOmegaMin, assoc.pt()) : getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("hOmOm"), dphi, trigger.yOmega() - assoc.yOmega(), trigger.sign(), assoc.sign(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, collision.posZ(), collision.centFT0M(), weightTrigg * weightAssoc); } + } + + // QA plots + if (trigger.sign() * assoc.sign() < 0) { + registry.fill(HIST("hDeltaPhiOS"), dphi); + } else { 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); } } // 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) + if (std::abs(col1.posZ()) > zVertexCut || std::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 +943,141 @@ 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; + } + + std::array triggerTracks = {trigger.posTrackId(), trigger.negTrackId(), trigger.bachelorId()}; + std::array assocTracks = {assoc.posTrackId(), assoc.negTrackId(), assoc.bachelorId()}; + if (autoCorrelation(triggerTracks, assocTracks)) + 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 + double weightTrigg = 1.; + double weightAssoc = 1.; + + if (trigger.isSelected() <= 2 && std::abs(trigger.yXi()) < maxRapidity) { // trigger Xi + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? getEfficiency(hEffXiMin, trigger.pt()) : getEfficiency(hEffXiPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && std::abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? getEfficiency(hEffXiMin, assoc.pt()) : getEfficiency(hEffXiPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEXiXi"), dphi, trigger.yXi() - assoc.yXi(), trigger.sign(), assoc.sign(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassXiAssoc, col1.posZ(), col1.centFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && std::abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? getEfficiency(hEffOmegaMin, assoc.pt()) : getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEXiOm"), dphi, trigger.yXi() - assoc.yOmega(), trigger.sign(), assoc.sign(), trigger.pt(), assoc.pt(), invMassXiTrigg, invMassOmAssoc, col1.posZ(), col1.centFT0M(), weightTrigg * weightAssoc); + } + } + if (trigger.isSelected() >= 2 && std::abs(trigger.yOmega()) < maxRapidity) { // trigger Omega + if (doEfficiencyCorrection) + weightTrigg = trigger.sign() < 0 ? getEfficiency(hEffOmegaMin, trigger.pt()) : getEfficiency(hEffOmegaPlus, trigger.pt()); + if (assoc.isSelected() <= 2 && std::abs(assoc.yXi()) < maxRapidity) { // assoc Xi + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? getEfficiency(hEffXiMin, assoc.pt()) : getEfficiency(hEffXiPlus, assoc.pt()); + // if Omega-Xi, fill the Xi-Omega histogram (flip the trigger/assoc and dphy,dy signs) + registry.fill(HIST("MixedEvents/hMEXiOm"), RecoDecay::constrainAngle(assoc.phi() - trigger.phi(), -PIHalf), -(trigger.yOmega() - assoc.yXi()), assoc.sign(), trigger.sign(), assoc.pt(), trigger.pt(), invMassXiAssoc, invMassOmTrigg, col1.posZ(), col1.centFT0M(), weightTrigg * weightAssoc); + } + if (assoc.isSelected() >= 2 && std::abs(assoc.yOmega()) < maxRapidity) { // assoc Omega + if (doEfficiencyCorrection) + weightAssoc = assoc.sign() < 0 ? getEfficiency(hEffOmegaMin, assoc.pt()) : getEfficiency(hEffOmegaPlus, assoc.pt()); + registry.fill(HIST("MixedEvents/hMEOmOm"), dphi, trigger.yOmega() - assoc.yOmega(), trigger.sign(), assoc.sign(), trigger.pt(), assoc.pt(), invMassOmTrigg, invMassOmAssoc, col1.posZ(), col1.centFT0M(), weightTrigg * weightAssoc); + } + } - if (trigger.sign() * assoc.sign() < 0) { // opposite-sign + // QA plots + if (trigger.sign() * assoc.sign() < 0) { 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); - } else { // same sign + } else { 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); } } // correlations - } // collisions - } // process mixed events + } // collisions + } // process mixed events + + Configurable etaGenCascades{"etaGenCascades", 0.8, "min/max of eta for generated cascades"}; + 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.centFT0M(); + vtxz = collision.posZ(); + } + } else if (collisions.size() > 1) { + registry.fill(HIST("MC/hSplitEvents"), collisions.size()); + return; + } + + // QA + for (auto& casc : genCascades) { + if (!casc.isPhysicalPrimary()) + continue; + registry.fill(HIST("MC/hPhi"), casc.phi()); + registry.fill(HIST("MC/hEta"), casc.eta()); + registry.fill(HIST("MC/hRapidity"), casc.y()); + } + + 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; + + if (!trigger.isPhysicalPrimary() || !assoc.isPhysicalPrimary()) + continue; // require the cascades to be primaries + if (std::abs(trigger.eta()) > etaGenCascades) + continue; // only apply eta cut to trigger - trigger normalization still valid without introducing 2-particle-acceptance effects + + 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..0eb75478d7d --- /dev/null +++ b/PWGLF/Tasks/Strangeness/cascpolsp.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. +// Cascade polarisation task +// prottay.das@cern.ch + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/SPCalibrationTables.h" +#include "PWGLF/DataModel/cascqaanalysis.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +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 3bbff7b117a..098251faf28 100644 --- a/PWGLF/Tasks/Strangeness/cascpostprocessing.cxx +++ b/PWGLF/Tasks/Strangeness/cascpostprocessing.cxx @@ -16,14 +16,15 @@ /// \modified by Roman Nepeivoda (roman.nepeivoda@cern.ch) /// \since June 1, 2023 -#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 "PWGLF/DataModel/cascqaanalysis.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" // constants const float ctauxiPDG = 4.91; // from PDG @@ -216,8 +217,8 @@ struct cascpostprocessing { registry.add("hPtCascPlusTrueRec", "hPtCascPlusTrueRec", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); registry.add("hPtCascMinusTrueRec", "hPtCascMinusTrueRec", {HistType::kTH3F, {ptAxis, rapidityAxis, centFT0MAxis}}); - registry.add("hCascMinusMassvsPtTrueRec", "hCascMinusMassvsPtTrueRec", {HistType::kTH2F, {ptAxis, massAxis}}); - registry.add("hCascPlusMassvsPtTrueRec", "hCascPlusMassvsPtTrueRec", {HistType::kTH2F, {ptAxis, massAxis}}); + 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) { @@ -489,7 +490,7 @@ struct cascpostprocessing { if (candidate.sign() < 0) { if (isCorrectlyRec) { registry.fill(HIST("hPtCascMinusTrueRec"), candidate.pt(), rapidity, candidate.centFT0M()); // 3rd axis is from MC calibration - registry.fill(HIST("hCascMinusMassvsPtTrueRec"), candidate.pt(), invmass); + registry.fill(HIST("hCascMinusMassvsPtTrueRec"), candidate.pt(), invmass, candidate.centFT0M()); } else { registry.fill(HIST("hCascMinusMassvsPtBG"), candidate.pt(), invmass); } @@ -500,7 +501,7 @@ struct cascpostprocessing { if (candidate.sign() > 0) { if (isCorrectlyRec) { registry.fill(HIST("hPtCascPlusTrueRec"), candidate.pt(), rapidity, candidate.centFT0M()); // 3rd axis is from MC calibration - registry.fill(HIST("hCascPlusMassvsPtTrueRec"), candidate.pt(), invmass); + registry.fill(HIST("hCascPlusMassvsPtTrueRec"), candidate.pt(), invmass, candidate.centFT0M()); } else { registry.fill(HIST("hCascPlusMassvsPtBG"), candidate.pt(), invmass); } diff --git a/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx b/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx index 012da260c95..aae3fb50f8d 100644 --- a/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/derivedcascadeanalysis.cxx @@ -9,32 +9,50 @@ // 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 "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 "MetadataHelper.h" + #include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "ReconstructionDataFormats/Track.h" #include #include -#include #include #include -#include +#include + +#include +#include // constants const float ctauxiPDG = 4.91; // from PDG @@ -45,169 +63,340 @@ 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, 50000.0f}, "occupancy axis"}; - + 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 doOccupancyCheck{"doOccupancyCheck", true, ""}; - Configurable doTimeRangeStandardCut{"doTimeRangeStandardCut", true, "It rejects a given collision if there are other events nearby in |dt|< 10 μs"}; - - Configurable centMin{"centMin", 0, "Minimal accepted centrality"}; - Configurable centMax{"centMax", 100, "Maximal accepted centrality"}; - + Configurable ispO{"ispO", 0, "Analyse p--O collisions"}; + 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 doFillNsigmaTPCHistPionBach{"doFillNsigmaTPCHistPionBach", false, ""}; - Configurable doFillNsigmaTPCHistKaonBach{"doFillNsigmaTPCHistKaonBach", false, ""}; - Configurable doFillNsigmaTPCHistProton{"doFillNsigmaTPCHistProton", false, ""}; - Configurable doFillNsigmaTPCHistV0Pion{"doFillNsigmaTPCHistV0Pion", false, ""}; 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"}; + Configurable globalTracksCorrelpar0Low{"globalTracksCorrelpar0Low", 81, "[0]*exp([1]*centrality)+[2], mean minus 3*sigma"}; + Configurable globalTracksCorrelpar1Low{"globalTracksCorrelpar1Low", -0.0431016, "[0]*exp([1]*centrality)+[2], mean minus 3*sigma"}; + Configurable globalTracksCorrelpar2Low{"globalTracksCorrelpar2Low", -6, "[0]*exp([1]*centrality)+[2], mean minus 3*sigma"}; + Configurable globalTracksCorrelpar0High{"globalTracksCorrelpar0High", 226, "[0]*exp([1]*centrality)+[2], mean minus 3*sigma"}; + Configurable globalTracksCorrelpar1High{"globalTracksCorrelpar1High", -0.0181686, "[0]*exp([1]*centrality)+[2], mean plus 3*sigma"}; + Configurable globalTracksCorrelpar2High{"globalTracksCorrelpar2High", -22, "[0]*exp([1]*centrality)+[2], mean plus 3*sigma"}; + Configurable pvContribCorrelpar0Low{"pvContribCorrelpar0Low", 152, "[0]*exp([1]*centrality)+[2], mean minus 3*sigma"}; + Configurable pvContribCorrelpar1Low{"pvContribCorrelpar1Low", -0.0431016, "[0]*exp([1]*centrality)+[2], mean minus 3*sigma"}; + Configurable pvContribCorrelpar2Low{"pvContribCorrelpar2Low", -15.3776, "[0]*exp([1]*centrality)+[2], mean minus 3*sigma"}; + Configurable pvContribCorrelpar0High{"pvContribCorrelpar0High", 384.861, "[0]*exp([1]*centrality)+[2], mean minus 3*sigma"}; + Configurable pvContribCorrelpar1High{"pvContribCorrelpar1High", -0.0181686, "[0]*exp([1]*centrality)+[2], mean plus 3*sigma"}; + Configurable pvContribCorrelpar2High{"pvContribCorrelpar2High", -39, "[0]*exp([1]*centrality)+[2], mean plus 3*sigma"}; + } 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 minRapCut{"minRapCut", -0.845, "minimal rapidity acceptance in case of p--o"}; + Configurable maxRapCut{"maxRapCut", 0.155, "maximal rapidity acceptance in case of p--o"}; + 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; - 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"}; + Service pdgDB; - 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"}; + uint16_t selectionCheckMask; + double selectionCheck; - Service pdgDB; + 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"}; - static constexpr std::string_view Index[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; - static constexpr float centralityIntervals[11] = {0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90.}; + // 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, {{13, 0, 13}}); - histos.add("hOccupancyVsCentrality", "", kTH2F, {axisOccupancy, {100, 0, 100}}); + + 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("hPseudorapPosDaughter", "", kTH1F, {{50, -1, 1}}); + histos.add("hPseudorapNegDaughter", "", kTH1F, {{50, -1, 1}}); + histos.add("hPseudorapBachelor", "", kTH1F, {{50, -1, 1}}); 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}}); - if (doFillNsigmaTPCHistProton) { + 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 (doFillNsigmaTPCHistV0Pion) { + 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 (doFillNsigmaTPCHistPionBach) { + 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 (doFillNsigmaTPCHistKaonBach) + 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 (doOccupancyCheck) { - histos.add("InvMassAfterSelCent1/hNegativeCascade", "hNegativeCascade", HistType::kTH3F, {axisPt, axisXiMass, axisOccupancy}); - histos.add("InvMassAfterSelCent1/hPositiveCascade", "hPositiveCascade", HistType::kTH3F, {axisPt, axisXiMass, axisOccupancy}); + 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 (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/"); @@ -219,516 +408,844 @@ struct derivedCascadeAnalysis { 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); - } + histos.add("hInteractionRate", "hInteractionRate", kTH1F, {axisIR}); + histos.add("hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {{101, 0.0f, 101.0f}, axisIR}); - if (doBefSelCheck) + 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 (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 (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 (eventSelectionCommonFlags.doTriggerTVXEventCut && !coll.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; } - if (isMC) { - if (!coll.selection_bit(aod::evsel::kIsTriggerTVX)) { + 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()); + } + + if (centrality > eventSelectionCommonFlags.centMax || centrality < eventSelectionCommonFlags.centMin) { return false; } - histos.fill(HIST("hEventSelection"), 1.5 /* MB trigger*/); + if (fillHists) + histos.fill(HIST("hEventSelection"), 4.5 /* collisions after centrality sel*/); - if (TMath::Abs(coll.posZ()) > zVertexCut) { + 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"), 2.5 /* collisions after sel pvz 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 (doTFeventCut && !coll.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + if (eventSelectionRun3Flags.doITSTPCvertexEventCut && !coll.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { return false; } - histos.fill(HIST("hEventSelection"), 3.5 /* Not at TF border */); - if (doITSFrameBorderCut && !coll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + if (fillHists) + histos.fill(HIST("hEventSelection"), 7.5 /* At least one ITS-TPC track in the event*/); + + if (eventSelectionRun3Flags.doVertexTOFmatch && !coll.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { return false; } - histos.fill(HIST("hEventSelection"), 4.5 /* Not at ITS ROF border */); - } else { - if (!sel) { + if (fillHists) + histos.fill(HIST("hEventSelection"), 8.5 /* At least one of vertex contributors is matched to TOF*/); + + if (eventSelectionRun3Flags.doVertexTRDmatch && !coll.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { return false; } - histos.fill(HIST("hEventSelection"), 1.5 /* collisions after sel*/); - if (TMath::Abs(coll.posZ()) > zVertexCut) { + if (fillHists) + histos.fill(HIST("hEventSelection"), 9.5 /* At least one of vertex contributors is matched to TRD*/); + + 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 */); - histos.fill(HIST("hEventSelection"), 2.5 /* collisions after sel pvz sel*/); + 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 (coll.centFT0C() > centMax || coll.centFT0C() < centMin) { + if (eventSelectionRun3Flags.doMultiplicityCorrCut) { + if (coll.multNTracksGlobal() < (eventSelectionRun3Flags.globalTracksCorrelpar0Low * std::exp(eventSelectionRun3Flags.globalTracksCorrelpar1Low * centrality) + eventSelectionRun3Flags.globalTracksCorrelpar2Low) || coll.multNTracksGlobal() > (eventSelectionRun3Flags.globalTracksCorrelpar0High * std::exp(eventSelectionRun3Flags.globalTracksCorrelpar1High * centrality) + eventSelectionRun3Flags.globalTracksCorrelpar2High)) + return false; + if (coll.multNTracksPVeta1() < (eventSelectionRun3Flags.pvContribCorrelpar0Low * std::exp(eventSelectionRun3Flags.pvContribCorrelpar1Low * centrality) + eventSelectionRun3Flags.pvContribCorrelpar2Low) || coll.multNTracksPVeta1() > (eventSelectionRun3Flags.pvContribCorrelpar0High * std::exp(eventSelectionRun3Flags.pvContribCorrelpar1High * centrality) + eventSelectionRun3Flags.pvContribCorrelpar2High)) + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 12.5 /* Remove outlyers */); + + 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 */); - histos.fill(HIST("hEventSelection"), 3.5 /* collisions after centrality sel*/); + 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 */); - if (doSameBunchPileUpEventCut && !coll.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + 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; } - histos.fill(HIST("hEventSelection"), 4.5 /* Not same Bunch pile up */); + if (fillHists) + histos.fill(HIST("hEventSelection"), 16.5 /* Above max occupancy */); - if (doGoodPVFT0EventCut && !coll.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + if (eventSelectionRun3Flags.doNoCollInRofStrictCut && !coll.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { return false; } - histos.fill(HIST("hEventSelection"), 5.5 /* No large vertexZ difference from tracks and FT0*/); + if (fillHists) + histos.fill(HIST("hEventSelection"), 17.5 /*rejects a collision if there are other events within the same ITS ROF*/); - if (doITSTPCvertexEventCut && !coll.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + if (eventSelectionRun3Flags.doNoCollInRofStandardCut && !coll.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { return false; } - histos.fill(HIST("hEventSelection"), 6.5 /* At least one ITS-TPC track in the event*/); + 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 (doVertexTOFmatch && !coll.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + if (eventSelectionRun3Flags.doITSallLayersCut && !coll.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { return false; } - histos.fill(HIST("hEventSelection"), 7.5 /* At least one of vertex contributors is matched to TOF*/); + if (fillHists) + histos.fill(HIST("hEventSelection"), 19.5 /*rejects collisions if ITS was in rebooting stage*/); - if (doVertexTRDmatch && !coll.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + occupancyFT0 = coll.ft0cOccupancyInTimeRange(); + if (eventSelectionRun3Flags.minOccupancyFT0 > -1 && occupancyFT0 < eventSelectionRun3Flags.minOccupancyFT0) { + return false; + } + if (eventSelectionRun3Flags.maxOccupancyFT0 > -1 && occupancyFT0 > eventSelectionRun3Flags.maxOccupancyFT0) { return false; } - histos.fill(HIST("hEventSelection"), 8.5 /* At least one of vertex contributors is matched to TRD*/); + 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 (doITSFrameBorderCut && !coll.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + if (centrality > eventSelectionCommonFlags.centMax || centrality < eventSelectionCommonFlags.centMin) { return false; } - histos.fill(HIST("hEventSelection"), 9.5 /* Not at ITS ROF border */); + if (fillHists) + histos.fill(HIST("hEventSelection"), 4.5 /* collisions after centrality sel*/); - if (doTFeventCut && !coll.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + if (eventSelectionRun2Flags.doSel7 && !coll.sel7()) { return false; } - histos.fill(HIST("hEventSelection"), 10.5 /* Not at TF border */); + if (fillHists) + histos.fill(HIST("hEventSelection"), 5.5 /* sel7 selection */); - if (doMultiplicityCorrCut) { - if (coll.multNTracksGlobal() < (1343.3 * TMath::Exp(-0.0443259 * coll.centFT0C()) - 50) || coll.multNTracksGlobal() > (2098.9 * TMath::Exp(-0.0332444 * coll.centFT0C()))) - return false; - if (coll.multNTracksPVeta1() < (3703 * TMath::Exp(-0.0455483 * coll.centFT0C()) - 150) || coll.multNTracksPVeta1() > (4937.33 * TMath::Exp(-0.0372668 * coll.centFT0C()) + 20)) - return false; + if (eventSelectionRun2Flags.doINT7 && !coll.alias_bit(kINT7)) { + return false; } - histos.fill(HIST("hEventSelection"), 11.5 /* Remove outlyers */); - } + 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 (doTimeRangeStandardCut && !coll.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + 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"), 12.5 /* Rejection of events too close in time */); - - int occupancy = coll.trackOccupancyInTimeRange(); - histos.fill(HIST("hOccupancyVsCentrality"), occupancy, coll.centFT0C()); - 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; + if (ispO) + cut = candidateSelectionValues.maxRapCut; 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 (ispO && (casc.yXi() < candidateSelectionValues.minRapCut || casc.yXi() > candidateSelectionValues.maxRapCut)) + return false; + else 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 (ispO && (casc.yOmega() < candidateSelectionValues.minRapCut || casc.yOmega() > candidateSelectionValues.maxRapCut)) + return false; + else 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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()) == PDG_t::kXiMinus) || (!isXi && std::abs(cascMC.pdgCode()) == PDG_t::kOmegaMinus))) + isTrueMCCascade = true; + if (isTrueMCCascade && ((isPositive && cascMC.pdgCodePositive() == PDG_t::kPiPlus && cascMC.pdgCodeNegative() == PDG_t::kProtonBar) || (isNegative && cascMC.pdgCodePositive() == PDG_t::kProton && cascMC.pdgCodeNegative() == PDG_t::kPiMinus))) + isCorrectLambdaDecay = true; + if (isTrueMCCascade && isCorrectLambdaDecay && ((isXi && std::abs(cascMC.pdgCodeBachelor()) == PDG_t::kPiPlus) || (!isXi && std::abs(cascMC.pdgCodeBachelor()) == PDG_t::kKPlus))) + 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()}); - auto fullMomentumPosDaugh = TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)); - auto fullmomentumNegDaugh = TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)); - auto fullmomentumBachelor = TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)); + 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 = etaDauCut; + 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)) + histos.fill(HIST("hPseudorapPosDaughter"), poseta); + histos.fill(HIST("hPseudorapNegDaughter"), negeta); + histos.fill(HIST("hPseudorapBachelor"), bacheta); + + if (candidateSelectionFlags.doCascadeCosPaCut) { + if (!isCosPAAccepted(casc, coll.posX(), coll.posY(), coll.posZ(), candidateSelectionFlags.doPtDepCosPaCut, true)) continue; histos.fill(HIST("hCandidate"), ++counter); } 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 { + if (qaFlags.doPtDepCutStudy) + selectionCheck = std::abs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())); ++counter; } - if (casc.sign() < 0) { - if (doFillNsigmaTPCHistProton) - histos.fill(HIST("hNsigmaProton"), posExtra.tpcNSigmaPr(), fullMomentumPosDaugh, coll.centFT0C()); - if (doFillNsigmaTPCHistV0Pion) - histos.fill(HIST("hNsigmaPionNeg"), negExtra.tpcNSigmaPi(), fullmomentumNegDaugh, coll.centFT0C()); - if (doFillNsigmaTPCHistPionBach && isXi) - histos.fill(HIST("hNsigmaPionNegBach"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, coll.centFT0C()); - if (doFillNsigmaTPCHistPionBach && !isXi) - histos.fill(HIST("hNsigmaKaon"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, coll.centFT0C()); - - } else if (casc.sign() > 0) { - if (doFillNsigmaTPCHistV0Pion) - histos.fill(HIST("hNsigmaPionPos"), posExtra.tpcNSigmaPi(), fullMomentumPosDaugh, coll.centFT0C()); - if (doFillNsigmaTPCHistProton) - histos.fill(HIST("hNsigmaProtonNeg"), negExtra.tpcNSigmaPr(), fullmomentumNegDaugh, coll.centFT0C()); - if (doFillNsigmaTPCHistPionBach && isXi) - histos.fill(HIST("hNsigmaPionPosBach"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, coll.centFT0C()); - if (doFillNsigmaTPCHistPionBach && !isXi) - histos.fill(HIST("hNsigmaKaon"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, coll.centFT0C()); - } - - if (casc.sign() < 0) { - if (doNTPCSigmaCut) { - 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 { ++counter; } - } else if (casc.sign() > 0) { - if (doNTPCSigmaCut) { - if (TMath::Abs(posExtra.tpcNSigmaPi()) > nsigmatpcPi || TMath::Abs(negExtra.tpcNSigmaPr()) > nsigmatpcPr) + } else { + if (candidateSelectionFlags.doNTPCSigmaCut) { + if (std::abs(posExtra.tpcNSigmaPi()) > candidateSelectionValues.nsigmatpcPi || std::abs(negExtra.tpcNSigmaPr()) > candidateSelectionValues.nsigmatpcPr) continue; histos.fill(HIST("hCandidate"), ++counter); } else { @@ -736,18 +1253,53 @@ struct derivedCascadeAnalysis { } } - 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 { @@ -758,490 +1310,358 @@ 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(), fullMomentumPosDaugh, coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPr()) > nsigmatofPr && fullMomentumPosDaugh > 0.6) + 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(), fullMomentumPosDaugh, 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(), fullmomentumNegDaugh, coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPr()) > nsigmatofPr && fullmomentumNegDaugh > 0.6) + 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(), fullmomentumNegDaugh, 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 (doNTPCSigmaCut) { - if (TMath::Abs(bachExtra.tpcNSigmaPi()) > nsigmatpcPi) + if (candidateSelectionFlags.doNTPCSigmaCut) { + if (std::abs(bachExtra.tpcNSigmaPi()) > candidateSelectionValues.nsigmatpcPi) continue; histos.fill(HIST("hCandidate"), ++counter); } else { ++counter; } - if (bachExtra.hasTOF() && doNTOFSigmaBachelorCut) { - histos.fill(HIST("hNsigmaTOFBachelorPion"), casc.tofNSigmaXiPi(), fullmomentumBachelor, 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 { - 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 { ++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 { + if (qaFlags.doPtDepCutStudy) + selectionCheck = ctau; ++counter; } } - if (casc.sign() < 0) { - histos.fill(HIST("InvMassAfterSel/hNegativeCascade"), casc.pt(), invmass, coll.centFT0C()); - if (doOccupancyCheck) { - static_for<0, 9>([&](auto i) { - constexpr int index = i.value; - if (coll.centFT0C() < centralityIntervals[index + 1] && coll.centFT0C() > centralityIntervals[index]) { - histos.fill(HIST("InvMassAfterSelCent") + HIST(Index[index]) + HIST("/hNegativeCascade"), casc.pt(), invmass, coll.trackOccupancyInTimeRange()); - } - }); - } - 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 (doOccupancyCheck) { - static_for<0, 9>([&](auto i) { - constexpr int index = i.value; - if (coll.centFT0C() < centralityIntervals[index + 1] && coll.centFT0C() > centralityIntervals[index]) { - histos.fill(HIST("InvMassAfterSelCent") + HIST(Index[index]) + HIST("/hPositiveCascade"), casc.pt(), invmass, coll.trackOccupancyInTimeRange()); - } - }); + 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 (!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 (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 (!doProperLifeTimeCut && doPtDepCutStudy) - histos.fill(HIST("PtDepCutStudy/hPositiveCascadeProperLifeTime"), casc.pt(), invmass, ctau); + } + + 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 (!cascMC.isPhysicalPrimary()) + continue; - auto fullMomentumPosDaugh = TMath::Sqrt(TMath::Power(casc.pxpos(), 2) + TMath::Power(casc.pypos(), 2) + TMath::Power(casc.pzpos(), 2)); - auto fullmomentumNegDaugh = TMath::Sqrt(TMath::Power(casc.pxneg(), 2) + TMath::Power(casc.pyneg(), 2) + TMath::Power(casc.pzneg(), 2)); - auto fullmomentumBachelor = TMath::Sqrt(TMath::Power(casc.pxbach(), 2) + TMath::Power(casc.pybach(), 2) + TMath::Power(casc.pzbach(), 2)); + float ptmc = RecoDecay::sqrtSumOfSquares(cascMC.pxMC(), cascMC.pyMC()); + 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 (TMath::Abs(poseta) > etaDauCut || TMath::Abs(negeta) > etaDauCut || TMath::Abs(bacheta) > etaDauCut) + if (ispO && (ymc > candidateSelectionValues.maxRapCut || ymc < candidateSelectionValues.minRapCut)) + continue; + else if (std::abs(ymc) > candidateSelectionValues.rapCut) 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; + auto mcCollision = cascMC.template straMCCollision_as>(); + if (eventSelectionCommonFlags.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelectionCommonFlags.zVertexCut) { + continue; } - if (doDCAV0ToPVCut) { - if (TMath::Abs(casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ())) < dcaV0ToPV) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else { - ++counter; + if (eventSelectionCommonFlags.doInel0MCGen && mcCollision.multMCNParticlesEta10() < 1) { + continue; } - if (casc.sign() < 0) { - if (doFillNsigmaTPCHistProton) - histos.fill(HIST("hNsigmaProton"), posExtra.tpcNSigmaPr(), fullMomentumPosDaugh, coll.centFT0C()); - if (doFillNsigmaTPCHistV0Pion) - histos.fill(HIST("hNsigmaPionNeg"), negExtra.tpcNSigmaPi(), fullmomentumNegDaugh, coll.centFT0C()); - if (doFillNsigmaTPCHistPionBach && isXi) - histos.fill(HIST("hNsigmaPionNegBach"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, coll.centFT0C()); - if (doFillNsigmaTPCHistPionBach && !isXi) - histos.fill(HIST("hNsigmaKaon"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, coll.centFT0C()); - - } else if (casc.sign() > 0) { - if (doFillNsigmaTPCHistV0Pion) - histos.fill(HIST("hNsigmaPionPos"), posExtra.tpcNSigmaPi(), fullMomentumPosDaugh, coll.centFT0C()); - if (doFillNsigmaTPCHistProton) - histos.fill(HIST("hNsigmaProtonNeg"), negExtra.tpcNSigmaPr(), fullmomentumNegDaugh, coll.centFT0C()); - if (doFillNsigmaTPCHistPionBach && isXi) - histos.fill(HIST("hNsigmaPionPosBach"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, coll.centFT0C()); - if (doFillNsigmaTPCHistPionBach && !isXi) - histos.fill(HIST("hNsigmaKaon"), bachExtra.tpcNSigmaPi(), fullmomentumBachelor, coll.centFT0C()); - } - - if (casc.sign() < 0) { - if (doNTPCSigmaCut) { - if (TMath::Abs(posExtra.tpcNSigmaPr()) > nsigmatpcPr || TMath::Abs(negExtra.tpcNSigmaPi()) > nsigmatpcPi) - continue; - histos.fill(HIST("hCandidate"), ++counter); + 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 { - ++counter; + centrality = eventSelectionRun2Flags.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); } + nChEta1 = collision.multNTracksPVeta1(); + } - } else if (casc.sign() > 0) { - if (doNTPCSigmaCut) { - if (TMath::Abs(posExtra.tpcNSigmaPi()) > nsigmatpcPi || TMath::Abs(negExtra.tpcNSigmaPr()) > nsigmatpcPr) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else { - ++counter; - } + if (cascMC.pdgCode() == PDG_t::kXiMinus && 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() == PDG_t::kXiPlusBar && 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() == PDG_t::kOmegaMinus && !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() == PDG_t::kOmegaPlusBar && !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 (posExtra.tpcCrossedRows() < mintpccrrows || negExtra.tpcCrossedRows() < mintpccrrows || bachExtra.tpcCrossedRows() < mintpccrrows) + if (eventSelectionCommonFlags.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelectionCommonFlags.zVertexCut) { 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; } + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 1.5 /* gen. events with vertex cut*/); - 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 (posExtra.hasTOF()) { - if (doNTOFSigmaProtonCut && casc.sign() < 0) { - histos.fill(HIST("hNsigmaTOFProton"), casc.tofNSigmaXiLaPr(), fullMomentumPosDaugh, coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPr()) > nsigmatofPr && fullMomentumPosDaugh > 0.6) - continue; - } - if (doNTOFSigmaV0PionCut && casc.sign() > 0) { - histos.fill(HIST("hNsigmaTOFV0Pion"), casc.tofNSigmaXiLaPi(), fullMomentumPosDaugh, coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPi()) > nsigmatofPion) - continue; - } + if (eventSelectionCommonFlags.doInel0MCGen && mcCollision.multMCNParticlesEta10() < 1) { + continue; } - - if (negExtra.hasTOF()) { - if (doNTOFSigmaProtonCut && casc.sign() > 0) { - histos.fill(HIST("hNsigmaTOFProton"), casc.tofNSigmaXiLaPr(), fullmomentumNegDaugh, coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPr()) > nsigmatofPr && fullmomentumNegDaugh > 0.6) - continue; - } - if (doNTOFSigmaV0PionCut && casc.sign() < 0) { - histos.fill(HIST("hNsigmaTOFV0Pion"), casc.tofNSigmaXiLaPi(), fullmomentumNegDaugh, coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiLaPi()) > nsigmatofPion) - 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; } - } - if (isXi) { - if (doNTPCSigmaCut) { - if (TMath::Abs(bachExtra.tpcNSigmaPi()) > nsigmatpcPi) - 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++; - if (bachExtra.hasTOF() && doNTOFSigmaBachelorCut) { - histos.fill(HIST("hNsigmaTOFBachelorPion"), casc.tofNSigmaXiPi(), fullmomentumBachelor, coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaXiPi()) > nsigmatofBachPion) - continue; - } + atLeastOne = true; + } + listBestCollisionIdx[mcCollision.globalIndex()] = bestCollisionIndex; - ctau = pdgDB->Mass(3312) * cascpos / ((cascptotmom + 1e-13) * ctauxiPDG); - if (doProperLifeTimeCut) { - if (ctau > proplifetime) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else { - ++counter; - } + histos.fill(HIST("hCentralityVsNcoll_beforeEvSel"), centrality, groupedCollisions.size() + 0.5); + histos.fill(HIST("hCentralityVsNcoll_afterEvSel"), centrality, nCollisions + 0.5); - invmass = casc.mXi(); - } else { - if (doNTPCSigmaCut) { - if (TMath::Abs(bachExtra.tpcNSigmaKa()) > nsigmatpcKa) - continue; - histos.fill(HIST("hCandidate"), ++counter); - } else { - ++counter; - } + histos.fill(HIST("hCentralityVsIRGen"), centrality, intRate); + histos.fill(HIST("hMultMCVsCentralityVsIRGen"), mcCollision.multMCNParticlesEta05(), centrality, intRate); - if (bachExtra.hasTOF() && doNTOFSigmaBachelorCut) { - histos.fill(HIST("hNsigmaTOFBachelorKaon"), casc.tofNSigmaOmKa(), fullmomentumBachelor, coll.centFT0C()); - if (TMath::Abs(casc.tofNSigmaOmKa()) > nsigmatofBachKaon) - continue; - } + histos.fill(HIST("hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("hRecMultVsMultMC"), nChEta05, mcCollision.multMCNParticlesEta05()); - 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 (doOccupancyCheck) { - static_for<0, 9>([&](auto i) { - constexpr int index = i.value; - if (coll.centFT0C() < centralityIntervals[index + 1] && coll.centFT0C() > centralityIntervals[index]) { - histos.fill(HIST("InvMassAfterSelCent") + HIST(Index[index]) + HIST("/hNegativeCascade"), casc.pt(), invmass, coll.trackOccupancyInTimeRange()); - } - }); - } - 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 (doOccupancyCheck) { - static_for<0, 9>([&](auto i) { - constexpr int index = i.value; - if (coll.centFT0C() < centralityIntervals[index + 1] && coll.centFT0C() > centralityIntervals[index]) { - histos.fill(HIST("InvMassAfterSelCent") + HIST(Index[index]) + HIST("/hPositiveCascade"), casc.pt(), invmass, coll.trackOccupancyInTimeRange()); - } - }); - } - 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("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 ac1835fa9ea..949709c68fc 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 // ================ // @@ -22,165 +28,348 @@ // david.dobrigkeit.chinellato@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/CCDB/ctpRateFetcher.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/TrackSelectionTables.h" +#include "Tools/ML/MlResponse.h" +#include "Tools/ML/model.h" + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#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" -#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 +#include +#include +#include +#include +#include +#include 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 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))) + +enum CentEstimator { + kCentFT0C = 0, + kCentFT0M, + kCentFT0CVariant1, + kCentMFT, + kCentNGlobal, + kCentFV0A +}; 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"}; - - 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 requireNoHighOccupancyAgressive{"requireNoHighOccupancyAgressive", false, "reject collisions with high occupancies according to the aggressive cuts"}; - Configurable requireNoHighOccupancyStrict{"requireNoHighOccupancyStrict", false, "reject collisions with high occupancies according to the strict cuts"}; - Configurable requireNoHighOccupancyMedium{"requireNoHighOccupancyMedium", false, "reject collisions with high occupancies according to the medium cuts"}; - Configurable requireNoHighOccupancyRelaxed{"requireNoHighOccupancyRelaxed", false, "reject collisions with high occupancies according to the relaxed cuts"}; - Configurable requireNoHighOccupancyGentle{"requireNoHighOccupancyGentle", false, "reject collisions with high occupancies according to the gentle cuts"}; - 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 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)"}; - - // 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)"}; + Configurable centralityEstimator{"centralityEstimator", kCentFT0C, "Run 3 centrality estimator (0:CentFT0C, 1:CentFT0M, 2:CentFT0CVariant1, 3:CentMFT, 4:CentNGlobal, 5:CentFV0A)"}; + + Configurable doEventQA{"doEventQA", false, "do event QA histograms"}; 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 doEtaPhiQA{"doEtaPhiQA", false, "do Eta/Phi QA histograms"}; 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"}; - // fast check on occupancy - Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; - Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; - - 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"}; - 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 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 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 axisPointingAngle{"axisPointingAngle", {20, 0.0f, 2.0f}, "pointing angle (rad)"}; - 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 axisTOFdeltaT{"axisTOFdeltaT", {200, -5000.0f, 5000.0f}, "TOF Delta T (ps)"}; - - // 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"}; - ConfigurableAxis axisITScluMap{"axisITSMap", {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"}; - - // MC coll assoc QA axis - ConfigurableAxis axisMonteCarloNch{"axisMonteCarloNch", {300, 0.0f, 3000.0f}, "N_{ch} MC"}; - - enum selection : uint64_t { selCosPA = 0, + struct : ConfigurableGroup { + std::string prefix = "eventSelections"; // JSON group name + 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; + + static constexpr float DefaultLifetimeCuts[1][2] = {{30., 20.}}; + + struct : ConfigurableGroup { + std::string prefix = "v0Selections"; // JSON group name + 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)"}; + Configurable> lifetimecut{"lifetimecut", {DefaultLifetimeCuts[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecut"}; + + // invariant mass selection + Configurable compMassRejection{"compMassRejection", -1, "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{"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"}; + Configurable rejectTPCsectorBoundary{"rejectTPCsectorBoundary", false, "reject tracks close to the TPC sector boundaries"}; + Configurable phiLowCut{"phiLowCut", "0.06/x+pi/18.0-0.06", "Low azimuth cut parametrisation"}; + Configurable phiHighCut{"phiHighCut", "0.1/x+pi/18.0+0.06", "High azimuth cut parametrisation"}; + + // 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; + + TF1* fPhiCutLow = new TF1("fPhiCutLow", v0Selections.phiLowCut.value.data(), 0, 100); + TF1* fPhiCutHigh = new TF1("fPhiCutHigh", v0Selections.phiHighCut.value.data(), 0, 100); + + 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"}; + + // manual + Configurable useCustomMagField{"useCustomMagField", false, "Use custom magnetic field value"}; + Configurable customMagField{"customMagField", 5.0f, "Manually set magnetic field"}; + } ccdbConfigurations; + + o2::ccdb::CcdbApi ccdbApi; + Service ccdb; + ctpRateFetcher rateFetcher; + int mRunNumber; + float magField; + std::map metadata; + o2::parameters::GRPMagField* grpmag = nullptr; + + // CCDB options + struct : ConfigurableGroup { + 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"}; + 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 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 axisMultFT0M{"axisMultFT0M", {500, 0.0f, +100000.0f}, "Multiplicity FT0M"}; + ConfigurableAxis axisMultFT0C{"axisMultFT0C", {500, 0.0f, +10000.0f}, "Multiplicity FT0C"}; + ConfigurableAxis axisMultFV0A{"axisMultFV0A", {500, 0.0f, +100000.0f}, "Multiplicity FV0A"}; + + 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 axisPointingAngle{"axisPointingAngle", {20, 0.0f, 2.0f}, "pointing angle (rad)"}; + 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 axisPhiMod{"axisPhiMod", {100, 0.0f, constants::math::TwoPI / 18}, "Azimuth angle wrt TPC sector (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"}; + + // 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"}; + 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"}; + + // MC coll assoc QA axis + ConfigurableAxis axisMonteCarloNch{"axisMonteCarloNch", {300, 0.0f, 3000.0f}, "N_{ch} MC"}; + } axisConfigurations; + + // 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; + + // 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, @@ -188,6 +377,8 @@ struct derivedlambdakzeroanalysis { selDCAV0Dau, selK0ShortRapidity, selLambdaRapidity, + selK0ShortMassRejection, + selLambdaMassRejection, selTPCPIDPositivePion, selTPCPIDNegativePion, selTPCPIDPositiveProton, @@ -244,421 +435,921 @@ 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 (requireNegITSonly) { - maskTrackProperties = maskTrackProperties | (uint64_t(1) << selNegItsOnly) | (uint64_t(1) << selNegGoodITSTrack); + 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 (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); + } + + if (v0Selections.compMassRejection > -1) { + BITSET(maskK0ShortSpecific, selLambdaMassRejection); + BITSET(maskLambdaSpecific, selK0ShortMassRejection); + BITSET(maskAntiLambdaSpecific, selK0ShortMassRejection); } // 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; + maskSelectionLambda = maskTopological | maskTrackProperties | maskLambdaSpecific; + maskSelectionAntiLambda = maskTopological | maskTrackProperties | maskAntiLambdaSpecific; + + 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, {{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, "posZ cut"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "kIsVertexITSTPC"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsGoodZvtxFT0vsPV"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoHighOccupancyAgressive"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoHighOccupancyStrict"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoHighOccupancyMedium"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoHighOccupancyRelaxed"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoHighOccupancyGentle"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInTimeRangeStd"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "kNoCollInTimeRangeNarrow"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "Below min occup."); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "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}); + histos.add("hEventSelection", "hEventSelection", kTH1D, {{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", kTH1D, {{101, 0.0f, 101.0f}}); + histos.add("hCentralityVsNch", "hCentralityVsNch", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisNch}); + if (doEventQA) { + if (isRun3) { + histos.add("hEventSelectionVsCentrality", "hEventSelectionVsCentrality", kTH2D, {{21, -0.5f, +20.5f}, {101, 0.0f, 101.0f}}); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + if (doPPAnalysis) { + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + } else { + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(17, "Below min occup."); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(18, "Above max occup."); + } + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(19, "Below min IR"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(20, "Above max IR"); + histos.get(HIST("hEventSelectionVsCentrality"))->GetXaxis()->SetBinLabel(21, "RCT flags"); + + histos.add("hCentralityVsNGlobal", "hCentralityVsNGlobal", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisNch}); + histos.add("hEventCentVsMultFT0M", "hEventCentVsMultFT0M", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisMultFT0M}); + histos.add("hEventCentVsMultFT0C", "hEventCentVsMultFT0C", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisMultFT0C}); + histos.add("hEventCentVsMultNGlobal", "hEventCentVsMultNGlobal", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisNch}); + histos.add("hEventCentVsMultFV0A", "hEventCentVsMultFV0A", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisMultFV0A}); + histos.add("hEventMultFT0MvsMultNGlobal", "hEventMultFT0MvsMultNGlobal", kTH2D, {axisConfigurations.axisMultFT0M, axisConfigurations.axisNch}); + histos.add("hEventMultFT0CvsMultNGlobal", "hEventMultFT0CvsMultNGlobal", kTH2D, {axisConfigurations.axisMultFT0C, axisConfigurations.axisNch}); + histos.add("hEventMultFV0AvsMultNGlobal", "hEventMultFV0AvsMultNGlobal", kTH2D, {axisConfigurations.axisMultFV0A, axisConfigurations.axisNch}); + histos.add("hEventMultPVvsMultNGlobal", "hEventMultPVvsMultNGlobal", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisNch}); + histos.add("hEventMultFT0CvsMultFV0A", "hEventMultFT0CvsMultFV0A", kTH2D, {axisConfigurations.axisMultFT0C, axisConfigurations.axisMultFV0A}); + } + } + + histos.add("hEventPVz", "hEventPVz", kTH1D, {{100, -20.0f, +20.0f}}); + histos.add("hCentralityVsPVz", "hCentralityVsPVz", kTH2D, {{101, 0.0f, 101.0f}, {100, -20.0f, +20.0f}}); + if (doprocessGeneratedRun3 || doprocessGeneratedRun2) { + histos.add("hEventPVzMC", "hEventPVzMC", kTH1D, {{100, -20.0f, +20.0f}}); + histos.add("hCentralityVsPVzMC", "hCentralityVsPVzMC", kTH2D, {{101, 0.0f, 101.0f}, {100, -20.0f, +20.0f}}); + } + + histos.add("hEventOccupancy", "hEventOccupancy", kTH1D, {axisConfigurations.axisOccupancy}); + histos.add("hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisOccupancy}); + + histos.add("hGapSide", "Gap side; Entries", kTH1D, {{5, -0.5, 4.5}}); + histos.add("hSelGapSide", "Selected gap side; Entries", kTH1D, {axisConfigurations.axisSelGap}); + histos.add("hEventCentralityVsSelGapSide", ";Centrality (%); Selected gap side", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisSelGap}); + + histos.add("hInteractionRate", "hInteractionRate", kTH1D, {axisConfigurations.axisIRBinning}); + histos.add("hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisIRBinning}); + + histos.add("hInteractionRateVsOccupancy", "hInteractionRateVsOccupancy", kTH2D, {axisConfigurations.axisIRBinning, axisConfigurations.axisOccupancy}); // for QA and test purposes - auto hRawCentrality = histos.add("hRawCentrality", "hRawCentrality", kTH1F, {axisRawCentrality}); + auto hRawCentrality = histos.add("hRawCentrality", "hRawCentrality", kTH1D, {axisConfigurations.axisRawCentrality}); for (int ii = 1; ii < 101; ii++) { float value = 100.5f - static_cast(ii); hRawCentrality->SetBinContent(ii, value); } + auto hSelectionV0s = histos.add("GeneralQA/hSelectionV0s", "hSelectionV0s", kTH1D, {{static_cast(selPhysPrimAntiLambda) + 3, -0.5f, static_cast(selPhysPrimAntiLambda) + 2.5f}}); + hSelectionV0s->GetXaxis()->SetBinLabel(1, "All"); + hSelectionV0s->GetXaxis()->SetBinLabel(selCosPA + 2, "cosPA"); + hSelectionV0s->GetXaxis()->SetBinLabel(selRadius + 2, "Radius min."); + hSelectionV0s->GetXaxis()->SetBinLabel(selRadiusMax + 2, "Radius max."); + hSelectionV0s->GetXaxis()->SetBinLabel(selDCANegToPV + 2, "DCA neg. to PV"); + hSelectionV0s->GetXaxis()->SetBinLabel(selDCAPosToPV + 2, "DCA pos. to PV"); + hSelectionV0s->GetXaxis()->SetBinLabel(selDCAV0Dau + 2, "DCA V0 dau."); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortRapidity + 2, "K^{0}_{S} rapidity"); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaRapidity + 2, "#Lambda rapidity"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortMassRejection + 2, "K^{0}_{S} mass rej."); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaMassRejection + 2, "#Lambda mass rej."); + hSelectionV0s->GetXaxis()->SetBinLabel(selTPCPIDPositivePion + 2, "TPC PID #pi^{+}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTPCPIDNegativePion + 2, "TPC PID #pi^{-}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTPCPIDPositiveProton + 2, "TPC PID p"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTPCPIDNegativeProton + 2, "TPC PID #bar{p}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFDeltaTPositiveProtonLambda + 2, "TOF #Delta t p from #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFDeltaTPositivePionLambda + 2, "TOF #Delta t #pi^{+} from #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFDeltaTPositivePionK0Short + 2, "TOF #Delta t #pi^{+} from K^{0}_{S}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFDeltaTNegativeProtonLambda + 2, "TOF #Delta t #bar{p} from #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFDeltaTNegativePionLambda + 2, "TOF #Delta t #pi^{-} from #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFDeltaTNegativePionK0Short + 2, "TOF #Delta t #pi^{-} from K^{0}_{S}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFNSigmaPositiveProtonLambda + 2, "TOF PID p from #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFNSigmaPositivePionLambda + 2, "TOF PID #pi^{+} from #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFNSigmaPositivePionK0Short + 2, "TOF PID #pi^{+} from K^{0}_{S}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFNSigmaNegativeProtonLambda + 2, "TOF PID #bar{p} from #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFNSigmaNegativePionLambda + 2, "TOF PID #pi^{-} from #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selTOFNSigmaNegativePionK0Short + 2, "TOF PID #pi^{-} from K^{0}_{S}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortCTau + 2, "K^{0}_{S} lifetime"); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaCTau + 2, "#Lambda lifetime"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortArmenteros + 2, "Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPosGoodTPCTrack + 2, "Pos. good TPC track"); + hSelectionV0s->GetXaxis()->SetBinLabel(selNegGoodTPCTrack + 2, "Neg. good TPC track"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPosGoodITSTrack + 2, "Pos. good ITS track"); + hSelectionV0s->GetXaxis()->SetBinLabel(selNegGoodITSTrack + 2, "Neg. good ITS track"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPosItsOnly + 2, "Pos. ITS-only"); + hSelectionV0s->GetXaxis()->SetBinLabel(selNegItsOnly + 2, "Neg. ITS-only"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPosNotTPCOnly + 2, "Pos. not TPC-only"); + hSelectionV0s->GetXaxis()->SetBinLabel(selNegNotTPCOnly + 2, "Neg. not TPC-only"); + hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderK0Short + 2, "True K^{0}_{S}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderLambda + 2, "True #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderAntiLambda + 2, "True #bar{#Lambda}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimK0Short + 2, "Phys. prim. K^{0}_{S}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimLambda + 2, "Phys. prim. #Lambda"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimAntiLambda + 2, "Phys. prim. #bar{#Lambda}"); + hSelectionV0s->GetXaxis()->SetBinLabel(selPhysPrimAntiLambda + 3, "Cand. selected"); + // histograms versus mass if (analyseK0Short) { - histos.add("h3dMassK0Short", "h3dMassK0Short", kTH3F, {axisCentrality, axisPt, axisK0Mass}); + histos.add("h2dNbrOfK0ShortVsCentrality", "h2dNbrOfK0ShortVsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("h3dMassK0Short", "h3dMassK0Short", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + // Non-UPC info + histos.add("h3dMassK0ShortHadronic", "h3dMassK0ShortHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + // UPC info + histos.add("h3dMassK0ShortSGA", "h3dMassK0ShortSGA", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + histos.add("h3dMassK0ShortSGC", "h3dMassK0ShortSGC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); + histos.add("h3dMassK0ShortDG", "h3dMassK0ShortDG", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisK0Mass}); if (doTPCQA) { - histos.add("K0Short/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("K0Short/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("K0Short/h3dPosTPCsignal", "h3dPosTPCsignal", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("K0Short/h3dNegTPCsignal", "h3dNegTPCsignal", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("K0Short/h3dPosNsigmaTPCvsTrackPtot", "h3dPosNsigmaTPCvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("K0Short/h3dNegNsigmaTPCvsTrackPtot", "h3dNegNsigmaTPCvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("K0Short/h3dPosTPCsignalVsTrackPtot", "h3dPosTPCsignalVsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("K0Short/h3dNegTPCsignalVsTrackPtot", "h3dNegTPCsignalVsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("K0Short/h3dPosNsigmaTPCvsTrackPt", "h3dPosNsigmaTPCvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("K0Short/h3dNegNsigmaTPCvsTrackPt", "h3dNegNsigmaTPCvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("K0Short/h3dPosTPCsignalVsTrackPt", "h3dPosTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("K0Short/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); + histos.add("K0Short/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("K0Short/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("K0Short/h3dPosTPCsignal", "h3dPosTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("K0Short/h3dNegTPCsignal", "h3dNegTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("K0Short/h3dPosNsigmaTPCvsTrackPtot", "h3dPosNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("K0Short/h3dNegNsigmaTPCvsTrackPtot", "h3dNegNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("K0Short/h3dPosTPCsignalVsTrackPtot", "h3dPosTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("K0Short/h3dNegTPCsignalVsTrackPtot", "h3dNegTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("K0Short/h3dPosNsigmaTPCvsTrackPt", "h3dPosNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("K0Short/h3dNegNsigmaTPCvsTrackPt", "h3dNegNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("K0Short/h3dPosTPCsignalVsTrackPt", "h3dPosTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("K0Short/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); } if (doTOFQA) { - histos.add("K0Short/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("K0Short/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("K0Short/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("K0Short/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("K0Short/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("K0Short/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("K0Short/h3dPosNsigmaTOF", "h3dPosNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("K0Short/h3dNegNsigmaTOF", "h3dNegNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("K0Short/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("K0Short/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("K0Short/h3dPosNsigmaTOFvsTrackPtot", "h3dPosNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("K0Short/h3dNegNsigmaTOFvsTrackPtot", "h3dNegNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("K0Short/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("K0Short/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("K0Short/h3dPosNsigmaTOFvsTrackPt", "h3dPosNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("K0Short/h3dNegNsigmaTOFvsTrackPt", "h3dNegNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("K0Short/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("K0Short/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); } if (doCollisionAssociationQA) { - histos.add("K0Short/h2dPtVsNch", "h2dPtVsNch", kTH2F, {axisMonteCarloNch, axisPt}); - histos.add("K0Short/h2dPtVsNch_BadCollAssig", "h2dPtVsNch_BadCollAssig", kTH2F, {axisMonteCarloNch, axisPt}); + histos.add("K0Short/h2dPtVsNch", "h2dPtVsNch", kTH2D, {axisConfigurations.axisMonteCarloNch, axisConfigurations.axisPt}); + histos.add("K0Short/h2dPtVsNch_BadCollAssig", "h2dPtVsNch_BadCollAssig", kTH2D, {axisConfigurations.axisMonteCarloNch, axisConfigurations.axisPt}); } if (doDetectPropQA == 1) { - histos.add("K0Short/h6dDetectPropVsCentrality", "h6dDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse}); - histos.add("K0Short/h4dPosDetectPropVsCentrality", "h4dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse}); - histos.add("K0Short/h4dNegDetectPropVsCentrality", "h4dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse}); + histos.add("K0Short/h6dDetectPropVsCentrality", "h6dDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisPtCoarse}); + histos.add("K0Short/h4dPosDetectPropVsCentrality", "h4dPosDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse}); + histos.add("K0Short/h4dNegDetectPropVsCentrality", "h4dNegDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse}); } if (doDetectPropQA == 2) { - histos.add("K0Short/h7dDetectPropVsCentrality", "h7dDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse, axisK0Mass}); - histos.add("K0Short/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisK0Mass}); - histos.add("K0Short/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisK0Mass}); + histos.add("K0Short/h7dDetectPropVsCentrality", "h7dDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass}); + histos.add("K0Short/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass}); + histos.add("K0Short/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass}); + } + if (doDetectPropQA == 3) { + histos.add("K0Short/h3dITSchi2", "h3dMaxITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("K0Short/h3dTPCchi2", "h3dMaxTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("K0Short/h3dTPCFoundOverFindable", "h3dTPCFoundOverFindable", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCfoundOverFindable}); + histos.add("K0Short/h3dTPCrowsOverFindable", "h3dTPCrowsOverFindable", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrowsOverFindable}); + histos.add("K0Short/h3dTPCsharedCls", "h3dTPCsharedCls", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsharedClusters}); + histos.add("K0Short/h3dPositiveITSchi2", "h3dPositiveITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("K0Short/h3dNegativeITSchi2", "h3dNegativeITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("K0Short/h3dPositiveTPCchi2", "h3dPositiveTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("K0Short/h3dNegativeTPCchi2", "h3dNegativeTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("K0Short/h3dPositiveITSclusters", "h3dPositiveITSclusters", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSclus}); + histos.add("K0Short/h3dNegativeITSclusters", "h3dNegativeITSclusters", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSclus}); + histos.add("K0Short/h3dPositiveTPCcrossedRows", "h3dPositiveTPCcrossedRows", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrows}); + histos.add("K0Short/h3dNegativeTPCcrossedRows", "h3dNegativeTPCcrossedRows", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrows}); + } + if (doEtaPhiQA) { + histos.add("K0Short/h5dV0PhiVsEta", "h5dV0PhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("K0Short/h5dPosPhiVsEta", "h5dPosPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("K0Short/h5dNegPhiVsEta", "h5dNegPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); } } if (analyseLambda) { - histos.add("h3dMassLambda", "h3dMassLambda", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("h2dNbrOfLambdaVsCentrality", "h2dNbrOfLambdaVsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("h3dMassLambda", "h3dMassLambda", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + // Non-UPC info + histos.add("h3dMassLambdaHadronic", "h3dMassLambdaHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + // UPC info + histos.add("h3dMassLambdaSGA", "h3dMassLambdaSGA", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("h3dMassLambdaSGC", "h3dMassLambdaSGC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("h3dMassLambdaDG", "h3dMassLambdaDG", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); if (doTPCQA) { - histos.add("Lambda/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("Lambda/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("Lambda/h3dPosTPCsignal", "h3dPosTPCsignal", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("Lambda/h3dNegTPCsignal", "h3dNegTPCsignal", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("Lambda/h3dPosNsigmaTPCvsTrackPtot", "h3dPosNsigmaTPCvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("Lambda/h3dNegNsigmaTPCvsTrackPtot", "h3dNegNsigmaTPCvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("Lambda/h3dPosTPCsignalVsTrackPtot", "h3dPosTPCsignalVsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("Lambda/h3dNegTPCsignalVsTrackPtot", "h3dNegTPCsignalVsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("Lambda/h3dPosNsigmaTPCvsTrackPt", "h3dPosNsigmaTPCvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("Lambda/h3dNegNsigmaTPCvsTrackPt", "h3dNegNsigmaTPCvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("Lambda/h3dPosTPCsignalVsTrackPt", "h3dPosTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("Lambda/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); + histos.add("Lambda/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dPosTPCsignal", "h3dPosTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dNegTPCsignal", "h3dNegTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dPosNsigmaTPCvsTrackPtot", "h3dPosNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dNegNsigmaTPCvsTrackPtot", "h3dNegNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dPosTPCsignalVsTrackPtot", "h3dPosTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dNegTPCsignalVsTrackPtot", "h3dNegTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dPosNsigmaTPCvsTrackPt", "h3dPosNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dNegNsigmaTPCvsTrackPt", "h3dNegNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("Lambda/h3dPosTPCsignalVsTrackPt", "h3dPosTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("Lambda/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); } if (doTOFQA) { - histos.add("Lambda/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("Lambda/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("Lambda/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("Lambda/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("Lambda/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("Lambda/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("Lambda/h3dPosNsigmaTOF", "h3dPosNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOF", "h3dNegNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dPosNsigmaTOFvsTrackPtot", "h3dPosNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOFvsTrackPtot", "h3dNegNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dPosNsigmaTOFvsTrackPt", "h3dPosNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dNegNsigmaTOFvsTrackPt", "h3dNegNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("Lambda/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("Lambda/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); } if (doCollisionAssociationQA) { - histos.add("Lambda/h2dPtVsNch", "h2dPtVsNch", kTH2F, {axisMonteCarloNch, axisPt}); - histos.add("Lambda/h2dPtVsNch_BadCollAssig", "h2dPtVsNch_BadCollAssig", kTH2F, {axisMonteCarloNch, axisPt}); + histos.add("Lambda/h2dPtVsNch", "h2dPtVsNch", kTH2D, {axisConfigurations.axisMonteCarloNch, axisConfigurations.axisPt}); + histos.add("Lambda/h2dPtVsNch_BadCollAssig", "h2dPtVsNch_BadCollAssig", kTH2D, {axisConfigurations.axisMonteCarloNch, axisConfigurations.axisPt}); } if (doDetectPropQA == 1) { - histos.add("Lambda/h6dDetectPropVsCentrality", "h6dDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse}); - histos.add("Lambda/h4dPosDetectPropVsCentrality", "h4dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse}); - histos.add("Lambda/h4dNegDetectPropVsCentrality", "h4dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse}); + histos.add("Lambda/h6dDetectPropVsCentrality", "h6dDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisPtCoarse}); + histos.add("Lambda/h4dPosDetectPropVsCentrality", "h4dPosDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse}); + histos.add("Lambda/h4dNegDetectPropVsCentrality", "h4dNegDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse}); } if (doDetectPropQA == 2) { - histos.add("Lambda/h7dDetectPropVsCentrality", "h7dDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse, axisLambdaMass}); - histos.add("Lambda/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisLambdaMass}); - histos.add("Lambda/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisLambdaMass}); + histos.add("Lambda/h7dDetectPropVsCentrality", "h7dDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass}); + histos.add("Lambda/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass}); + histos.add("Lambda/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass}); + } + if (doDetectPropQA == 3) { + histos.add("Lambda/h3dITSchi2", "h3dMaxITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("Lambda/h3dTPCchi2", "h3dMaxTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("Lambda/h3dTPCFoundOverFindable", "h3dTPCFoundOverFindable", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCfoundOverFindable}); + histos.add("Lambda/h3dTPCrowsOverFindable", "h3dTPCrowsOverFindable", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrowsOverFindable}); + histos.add("Lambda/h3dTPCsharedCls", "h3dTPCsharedCls", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsharedClusters}); + histos.add("Lambda/h3dPositiveITSchi2", "h3dPositiveITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("Lambda/h3dNegativeITSchi2", "h3dNegativeITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("Lambda/h3dPositiveTPCchi2", "h3dPositiveTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("Lambda/h3dNegativeTPCchi2", "h3dNegativeTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("Lambda/h3dPositiveITSclusters", "h3dPositiveITSclusters", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSclus}); + histos.add("Lambda/h3dNegativeITSclusters", "h3dNegativeITSclusters", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSclus}); + histos.add("Lambda/h3dPositiveTPCcrossedRows", "h3dPositiveTPCcrossedRows", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrows}); + histos.add("Lambda/h3dNegativeTPCcrossedRows", "h3dNegativeTPCcrossedRows", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrows}); + } + if (doEtaPhiQA) { + histos.add("Lambda/h5dV0PhiVsEta", "h5dV0PhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("Lambda/h5dPosPhiVsEta", "h5dPosPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("Lambda/h5dNegPhiVsEta", "h5dNegPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); } } if (analyseAntiLambda) { - histos.add("h3dMassAntiLambda", "h3dMassAntiLambda", kTH3F, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("h2dNbrOfAntiLambdaVsCentrality", "h2dNbrOfAntiLambdaVsCentrality", kTH2D, {axisConfigurations.axisCentrality, {10, -0.5f, 9.5f}}); + histos.add("h3dMassAntiLambda", "h3dMassAntiLambda", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + // Non-UPC info + histos.add("h3dMassAntiLambdaHadronic", "h3dMassAntiLambdaHadronic", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + // UPC info + histos.add("h3dMassAntiLambdaSGA", "h3dMassAntiLambdaSGA", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("h3dMassAntiLambdaSGC", "h3dMassAntiLambdaSGC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); + histos.add("h3dMassAntiLambdaDG", "h3dMassAntiLambdaDG", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisLambdaMass}); if (doTPCQA) { - histos.add("AntiLambda/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("AntiLambda/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("AntiLambda/h3dPosTPCsignal", "h3dPosTPCsignal", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("AntiLambda/h3dNegTPCsignal", "h3dNegTPCsignal", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("AntiLambda/h3dPosNsigmaTPCvsTrackPtot", "h3dPosNsigmaTPCvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("AntiLambda/h3dNegNsigmaTPCvsTrackPtot", "h3dNegNsigmaTPCvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("AntiLambda/h3dPosTPCsignalVsTrackPtot", "h3dPosTPCsignalVsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("AntiLambda/h3dNegTPCsignalVsTrackPtot", "h3dNegTPCsignalVsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("AntiLambda/h3dPosNsigmaTPCvsTrackPt", "h3dPosNsigmaTPCvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("AntiLambda/h3dNegNsigmaTPCvsTrackPt", "h3dNegNsigmaTPCvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisNsigmaTPC}); - histos.add("AntiLambda/h3dPosTPCsignalVsTrackPt", "h3dPosTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); - histos.add("AntiLambda/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTPCsignal}); + histos.add("AntiLambda/h3dPosNsigmaTPC", "h3dPosNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dNegNsigmaTPC", "h3dNegNsigmaTPC", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dPosTPCsignal", "h3dPosTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dNegTPCsignal", "h3dNegTPCsignal", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dPosNsigmaTPCvsTrackPtot", "h3dPosNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dNegNsigmaTPCvsTrackPtot", "h3dNegNsigmaTPCvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dPosTPCsignalVsTrackPtot", "h3dPosTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dNegTPCsignalVsTrackPtot", "h3dNegTPCsignalVsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dPosNsigmaTPCvsTrackPt", "h3dPosNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dNegNsigmaTPCvsTrackPt", "h3dNegNsigmaTPCvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTPC}); + histos.add("AntiLambda/h3dPosTPCsignalVsTrackPt", "h3dPosTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); + histos.add("AntiLambda/h3dNegTPCsignalVsTrackPt", "h3dNegTPCsignalVsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsignal}); } if (doTOFQA) { - histos.add("AntiLambda/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("AntiLambda/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("AntiLambda/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("AntiLambda/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("AntiLambda/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); - histos.add("AntiLambda/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3F, {axisCentrality, axisPtCoarse, axisTOFdeltaT}); + histos.add("AntiLambda/h3dPosNsigmaTOF", "h3dPosNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOF", "h3dNegNsigmaTOF", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dPosTOFdeltaT", "h3dPosTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dNegTOFdeltaT", "h3dNegTOFdeltaT", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dPosNsigmaTOFvsTrackPtot", "h3dPosNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOFvsTrackPtot", "h3dNegNsigmaTOFvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dPosTOFdeltaTvsTrackPtot", "h3dPosTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dNegTOFdeltaTvsTrackPtot", "h3dNegTOFdeltaTvsTrackPtot", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dPosNsigmaTOFvsTrackPt", "h3dPosNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dNegNsigmaTOFvsTrackPt", "h3dNegNsigmaTOFvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisNsigmaTOF}); + histos.add("AntiLambda/h3dPosTOFdeltaTvsTrackPt", "h3dPosTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); + histos.add("AntiLambda/h3dNegTOFdeltaTvsTrackPt", "h3dNegTOFdeltaTvsTrackPt", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTOFdeltaT}); } if (doCollisionAssociationQA) { - histos.add("AntiLambda/h2dPtVsNch", "h2dPtVsNch", kTH2F, {axisMonteCarloNch, axisPt}); - histos.add("AntiLambda/h2dPtVsNch_BadCollAssig", "h2dPtVsNch_BadCollAssig", kTH2F, {axisMonteCarloNch, axisPt}); + histos.add("AntiLambda/h2dPtVsNch", "h2dPtVsNch", kTH2D, {axisConfigurations.axisMonteCarloNch, axisConfigurations.axisPt}); + histos.add("AntiLambda/h2dPtVsNch_BadCollAssig", "h2dPtVsNch_BadCollAssig", kTH2D, {axisConfigurations.axisMonteCarloNch, axisConfigurations.axisPt}); } if (doDetectPropQA == 1) { - histos.add("AntiLambda/h6dDetectPropVsCentrality", "h6dDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse}); - histos.add("AntiLambda/h4dPosDetectPropVsCentrality", "h4dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse}); - histos.add("AntiLambda/h4dNegDetectPropVsCentrality", "h4dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse}); + histos.add("AntiLambda/h6dDetectPropVsCentrality", "h6dDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisPtCoarse}); + histos.add("AntiLambda/h4dPosDetectPropVsCentrality", "h4dPosDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse}); + histos.add("AntiLambda/h4dNegDetectPropVsCentrality", "h4dNegDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse}); } if (doDetectPropQA == 2) { - histos.add("AntiLambda/h7dDetectPropVsCentrality", "h7dDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse, axisLambdaMass}); - histos.add("AntiLambda/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisLambdaMass}); - histos.add("AntiLambda/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnF, {axisCentrality, axisDetMap, axisITScluMap, axisPtCoarse, axisLambdaMass}); + histos.add("AntiLambda/h7dDetectPropVsCentrality", "h7dDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisDetMapCoarse, axisConfigurations.axisITScluMapCoarse, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass}); + histos.add("AntiLambda/h5dPosDetectPropVsCentrality", "h5dPosDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass}); + histos.add("AntiLambda/h5dNegDetectPropVsCentrality", "h5dNegDetectPropVsCentrality", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisDetMap, axisConfigurations.axisITScluMap, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass}); + } + if (doDetectPropQA == 3) { + histos.add("AntiLambda/h3dITSchi2", "h3dMaxITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("AntiLambda/h3dTPCchi2", "h3dMaxTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("AntiLambda/h3dTPCFoundOverFindable", "h3dTPCFoundOverFindable", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCfoundOverFindable}); + histos.add("AntiLambda/h3dTPCrowsOverFindable", "h3dTPCrowsOverFindable", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrowsOverFindable}); + histos.add("AntiLambda/h3dTPCsharedCls", "h3dTPCsharedCls", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCsharedClusters}); + histos.add("AntiLambda/h3dPositiveITSchi2", "h3dPositiveITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("AntiLambda/h3dNegativeITSchi2", "h3dNegativeITSchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSchi2}); + histos.add("AntiLambda/h3dPositiveTPCchi2", "h3dPositiveTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("AntiLambda/h3dNegativeTPCchi2", "h3dNegativeTPCchi2", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCchi2}); + histos.add("AntiLambda/h3dPositiveITSclusters", "h3dPositiveITSclusters", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSclus}); + histos.add("AntiLambda/h3dNegativeITSclusters", "h3dNegativeITSclusters", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisITSclus}); + histos.add("AntiLambda/h3dPositiveTPCcrossedRows", "h3dPositiveTPCcrossedRows", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrows}); + histos.add("AntiLambda/h3dNegativeTPCcrossedRows", "h3dNegativeTPCcrossedRows", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisTPCrows}); + } + if (doEtaPhiQA) { + histos.add("AntiLambda/h5dV0PhiVsEta", "h5dV0PhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("AntiLambda/h5dPosPhiVsEta", "h5dPosPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); + histos.add("AntiLambda/h5dNegPhiVsEta", "h5dNegPhiVsEta", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPhi, axisConfigurations.axisEta}); } } - if (analyseLambda && calculateFeeddownMatrix && doprocessMonteCarlo) - histos.add("h3dLambdaFeeddown", "h3dLambdaFeeddown", kTH3F, {axisCentrality, axisPt, axisPtXi}); - if (analyseAntiLambda && calculateFeeddownMatrix && doprocessMonteCarlo) - histos.add("h3dAntiLambdaFeeddown", "h3dAntiLambdaFeeddown", kTH3F, {axisCentrality, axisPt, axisPtXi}); + if (analyseLambda && calculateFeeddownMatrix && (doprocessMonteCarloRun3 || doprocessMonteCarloRun2)) + histos.add("h3dLambdaFeeddown", "h3dLambdaFeeddown", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisPtXi}); + if (analyseAntiLambda && calculateFeeddownMatrix && (doprocessMonteCarloRun3 || doprocessMonteCarloRun2)) + histos.add("h3dAntiLambdaFeeddown", "h3dAntiLambdaFeeddown", kTH3D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt, axisConfigurations.axisPtXi}); - // demo // fast - histos.add("hMassK0Short", "hMassK0Short", kTH1F, {axisK0Mass}); + if (analyseK0Short) + histos.add("hMassK0Short", "hMassK0Short", kTH1D, {axisConfigurations.axisK0Mass}); + if (analyseLambda) + histos.add("hMassLambda", "hMassLambda", kTH1D, {axisConfigurations.axisLambdaMass}); + if (analyseAntiLambda) + histos.add("hMassAntiLambda", "hMassAntiLambda", kTH1D, {axisConfigurations.axisLambdaMass}); // QA histograms if requested if (doCompleteTopoQA) { // initialize for K0short... if (analyseK0Short) { - histos.add("K0Short/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnF, {axisCentrality, axisPtCoarse, axisK0Mass, axisDCAtoPV}); - histos.add("K0Short/h4dNegDCAToPV", "h4dNegDCAToPV", kTHnF, {axisCentrality, axisPtCoarse, axisK0Mass, axisDCAtoPV}); - 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/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass, axisConfigurations.axisDCAtoPV}); + histos.add("K0Short/h4dNegDCAToPV", "h4dNegDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass, axisConfigurations.axisDCAtoPV}); + histos.add("K0Short/h4dDCADaughters", "h4dDCADaughters", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass, axisConfigurations.axisDCAdau}); + histos.add("K0Short/h4dPointingAngle", "h4dPointingAngle", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass, axisConfigurations.axisPointingAngle}); + histos.add("K0Short/h4dV0Radius", "h4dV0Radius", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisK0Mass, axisConfigurations.axisV0Radius}); } if (analyseLambda) { - histos.add("Lambda/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisDCAtoPV}); - histos.add("Lambda/h4dNegDCAToPV", "h4dNegDCAToPV", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisDCAtoPV}); - 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/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAtoPV}); + histos.add("Lambda/h4dNegDCAToPV", "h4dNegDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAtoPV}); + histos.add("Lambda/h4dDCADaughters", "h4dDCADaughters", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAdau}); + histos.add("Lambda/h4dPointingAngle", "h4dPointingAngle", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPointingAngle}); + histos.add("Lambda/h4dV0Radius", "h4dV0Radius", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisV0Radius}); } if (analyseAntiLambda) { - histos.add("AntiLambda/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisDCAtoPV}); - histos.add("AntiLambda/h4dNegDCAToPV", "h4dNegDCAToPV", kTHnF, {axisCentrality, axisPtCoarse, axisLambdaMass, axisDCAtoPV}); - 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/h4dPosDCAToPV", "h4dPosDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAtoPV}); + histos.add("AntiLambda/h4dNegDCAToPV", "h4dNegDCAToPV", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAtoPV}); + histos.add("AntiLambda/h4dDCADaughters", "h4dDCADaughters", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisDCAdau}); + histos.add("AntiLambda/h4dPointingAngle", "h4dPointingAngle", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisPointingAngle}); + histos.add("AntiLambda/h4dV0Radius", "h4dV0Radius", kTHnD, {axisConfigurations.axisCentrality, axisConfigurations.axisPtCoarse, axisConfigurations.axisLambdaMass, axisConfigurations.axisV0Radius}); } } if (doPlainTopoQA) { // All candidates received - histos.add("hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("hDCADaughters", "hDCADaughters", kTH1F, {axisDCAdau}); - histos.add("hPointingAngle", "hPointingAngle", kTH1F, {axisPointingAngle}); - histos.add("hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); - histos.add("h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("hPosDCAToPV", "hPosDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("hNegDCAToPV", "hNegDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("hPointingAngle", "hPointingAngle", kTH1D, {axisConfigurations.axisPointingAngle}); + histos.add("hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("h2dPositivePtVsPhi", "h2dPositivePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + histos.add("h2dNegativePtVsPhi", "h2dNegativePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); if (analyseK0Short) { - histos.add("K0Short/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("K0Short/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("K0Short/hDCADaughters", "hDCADaughters", kTH1F, {axisDCAdau}); - histos.add("K0Short/hPointingAngle", "hPointingAngle", kTH1F, {axisPointingAngle}); - histos.add("K0Short/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); - histos.add("K0Short/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("K0Short/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("K0Short/hPosDCAToPV", "hPosDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("K0Short/hNegDCAToPV", "hNegDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("K0Short/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("K0Short/hPointingAngle", "hPointingAngle", kTH1D, {axisConfigurations.axisPointingAngle}); + histos.add("K0Short/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("K0Short/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("K0Short/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("K0Short/h2dPositivePtVsPhi", "h2dPositivePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + histos.add("K0Short/h2dNegativePtVsPhi", "h2dNegativePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); } if (analyseLambda) { - histos.add("Lambda/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("Lambda/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("Lambda/hDCADaughters", "hDCADaughters", kTH1F, {axisDCAdau}); - histos.add("Lambda/hPointingAngle", "hPointingAngle", kTH1F, {axisPointingAngle}); - histos.add("Lambda/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); - histos.add("Lambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("Lambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("Lambda/hPosDCAToPV", "hPosDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("Lambda/hNegDCAToPV", "hNegDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("Lambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("Lambda/hPointingAngle", "hPointingAngle", kTH1D, {axisConfigurations.axisPointingAngle}); + histos.add("Lambda/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("Lambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("Lambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("Lambda/h2dPositivePtVsPhi", "h2dPositivePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + histos.add("Lambda/h2dNegativePtVsPhi", "h2dNegativePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); } if (analyseAntiLambda) { - histos.add("AntiLambda/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("AntiLambda/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("AntiLambda/hDCADaughters", "hDCADaughters", kTH1F, {axisDCAdau}); - histos.add("AntiLambda/hPointingAngle", "hPointingAngle", kTH1F, {axisPointingAngle}); - histos.add("AntiLambda/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); - histos.add("AntiLambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("AntiLambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); + histos.add("AntiLambda/hPosDCAToPV", "hPosDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("AntiLambda/hNegDCAToPV", "hNegDCAToPV", kTH1D, {axisConfigurations.axisDCAtoPV}); + histos.add("AntiLambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); + histos.add("AntiLambda/hPointingAngle", "hPointingAngle", kTH1D, {axisConfigurations.axisPointingAngle}); + histos.add("AntiLambda/hV0Radius", "hV0Radius", kTH1D, {axisConfigurations.axisV0Radius}); + histos.add("AntiLambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("AntiLambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2D, {axisConfigurations.axisTPCrows, axisConfigurations.axisITSclus}); + histos.add("AntiLambda/h2dPositivePtVsPhi", "h2dPositivePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); + histos.add("AntiLambda/h2dNegativePtVsPhi", "h2dNegativePtVsPhi", kTH2D, {axisConfigurations.axisPtCoarse, axisConfigurations.axisPhiMod}); } } // Check if doing the right thing in AP space please - histos.add("GeneralQA/h2dArmenterosAll", "h2dArmenterosAll", kTH2F, {axisAPAlpha, axisAPQt}); - histos.add("GeneralQA/h2dArmenterosSelected", "h2dArmenterosSelected", kTH2F, {axisAPAlpha, axisAPQt}); + histos.add("GeneralQA/h2dArmenterosAll", "h2dArmenterosAll", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + histos.add("GeneralQA/h2dArmenterosSelected", "h2dArmenterosSelected", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); // Creation of histograms: MC generated + if ((doprocessGeneratedRun3 || doprocessGeneratedRun2)) { + histos.add("hGenEvents", "hGenEvents", kTH2D, {{axisConfigurations.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", kTH1D, {{101, 0.0f, 101.0f}}); + + histos.add("hCentralityVsNcoll_beforeEvSel", "hCentralityVsNcoll_beforeEvSel", kTH2D, {axisConfigurations.axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("hCentralityVsNcoll_afterEvSel", "hCentralityVsNcoll_afterEvSel", kTH2D, {axisConfigurations.axisCentrality, {50, -0.5f, 49.5f}}); + + histos.add("hCentralityVsMultMC", "hCentralityVsMultMC", kTH2D, {{101, 0.0f, 101.0f}, axisConfigurations.axisNch}); + + histos.add("h2dGenK0Short", "h2dGenK0Short", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenLambda", "h2dGenLambda", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambda", "h2dGenAntiLambda", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinus", "h2dGenXiMinus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlus", "h2dGenXiPlus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinus", "h2dGenOmegaMinus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlus", "h2dGenOmegaPlus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + + histos.add("h2dGenK0ShortVsMultMC_RecoedEvt", "h2dGenK0ShortVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenLambdaVsMultMC_RecoedEvt", "h2dGenLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambdaVsMultMC_RecoedEvt", "h2dGenAntiLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinusVsMultMC_RecoedEvt", "h2dGenXiMinusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlusVsMultMC_RecoedEvt", "h2dGenXiPlusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinusVsMultMC_RecoedEvt", "h2dGenOmegaMinusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlusVsMultMC_RecoedEvt", "h2dGenOmegaPlusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + + histos.add("h2dGenK0ShortVsMultMC", "h2dGenK0ShortVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenLambdaVsMultMC", "h2dGenLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambdaVsMultMC", "h2dGenAntiLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinusVsMultMC", "h2dGenXiMinusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlusVsMultMC", "h2dGenXiPlusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinusVsMultMC", "h2dGenOmegaMinusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlusVsMultMC", "h2dGenOmegaPlusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + } if (doprocessBinnedGenerated) { - histos.add("h2dGenK0Short", "h2dGenK0Short", kTH2D, {axisCentrality, axisPt}); - histos.add("h2dGenLambda", "h2dGenLambda", kTH2D, {axisCentrality, axisPt}); - histos.add("h2dGenAntiLambda", "h2dGenAntiLambda", kTH2D, {axisCentrality, axisPt}); - histos.add("h2dGenXiMinus", "h2dGenXiMinus", kTH2D, {axisCentrality, axisPt}); - histos.add("h2dGenXiPlus", "h2dGenXiPlus", kTH2D, {axisCentrality, axisPt}); - histos.add("h2dGenOmegaMinus", "h2dGenOmegaMinus", kTH2D, {axisCentrality, axisPt}); - histos.add("h2dGenOmegaPlus", "h2dGenOmegaPlus", kTH2D, {axisCentrality, axisPt}); + histos.add("h2dGeneratedK0Short", "h2dGeneratedK0Short", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGeneratedLambda", "h2dGeneratedLambda", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGeneratedAntiLambda", "h2dGeneratedAntiLambda", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGeneratedXiMinus", "h2dGeneratedXiMinus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGeneratedXiPlus", "h2dGeneratedXiPlus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGeneratedOmegaMinus", "h2dGeneratedOmegaMinus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGeneratedOmegaPlus", "h2dGeneratedOmegaPlus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); } // inspect histogram sizes, please histos.print(); } + // ______________________________________________________ + // Return slicing output + template + auto getCentralityRun3(TCollision const& collision) + { + if (centralityEstimator == kCentFT0C) + return collision.centFT0C(); + else if (centralityEstimator == kCentFT0M) + return collision.centFT0M(); + else if (centralityEstimator == kCentFT0CVariant1) + return collision.centFT0CVariant1(); + else if (centralityEstimator == kCentMFT) + return collision.centMFT(); + else if (centralityEstimator == kCentNGlobal) + return collision.centNGlobal(); + else if (centralityEstimator == kCentFV0A) + return collision.centFV0A(); + + return -1.f; + } + + // ______________________________________________________ + // 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); + } + // Fetching magnetic field if requested + if (v0Selections.rejectTPCsectorBoundary) { + // In case override, don't proceed, please - no CCDB access required + if (ccdbConfigurations.useCustomMagField) { + magField = ccdbConfigurations.customMagField; + } else { + grpmag = ccdb->getForRun(ccdbConfigurations.grpmagPath, mRunNumber); + if (!grpmag) { + LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConfigurations.grpmagPath << " of object GRPMagField and " << ccdbConfigurations.grpPath << " of object GRPObject for run " << mRunNumber; + } + // Fetch magnetic field from ccdb for current collision + magField = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for run " << mRunNumber << " with magnetic field of " << magField << " kZG"; + } + } + } + + double computePhiMod(double phi, int sign) + // Compute phi wrt to a TPC sector + // Calculation taken from CF: https://github.com/AliceO2Group/O2Physics/blob/376392cb87349886a300c75fa2492b50b7f46725/PWGCF/Flow/Tasks/flowAnalysisGF.cxx#L470 + { + if (magField < 0) // for negative polarity field + phi = o2::constants::math::TwoPI - phi; + if (sign < 0) // for negative charge + phi = o2::constants::math::TwoPI - phi; + if (phi < 0) + LOGF(warning, "phi < 0: %g", phi); + + phi += o2::constants::math::PI / 18.0; // to center gap in the middle + return fmod(phi, o2::constants::math::PI / 9.0); + } + + bool isTrackFarFromTPCBoundary(double trackPt, double trackPhi, int sign) + // check whether the track passes close to a TPC sector boundary + { + double phiModn = computePhiMod(trackPhi, sign); + if (phiModn > fPhiCutHigh->Eval(trackPt)) + return true; // keep track + if (phiModn < fPhiCutLow->Eval(trackPt)) + return true; // keep track + return false; // reject track + } + 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); - - auto posTrackExtra = v0.template posTrackExtra_as(); - auto negTrackExtra = v0.template negTrackExtra_as(); + if (std::abs(rapidityLambda) < v0Selections.rapidityCut) + BITSET(bitMap, selLambdaRapidity); + if (std::abs(rapidityK0Short) < v0Selections.rapidityCut) + BITSET(bitMap, selK0ShortRapidity); + + // + // 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() >= 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 + (!v0Selections.rejectTPCsectorBoundary || isTrackFarFromTPCBoundary(v0.positivept(), v0.positivephi(), 1))) // reject track far from TPC sector boundary or not + 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 + (!v0Selections.rejectTPCsectorBoundary || isTrackFarFromTPCBoundary(v0.negativept(), v0.negativephi(), -1))) // reject track far from TPC sector boundary or not + 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 (!posTrackExtra.hasTOF() || std::fabs(v0.posTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) + BITSET(bitMap, selTOFDeltaTPositiveProtonLambda); + if (!posTrackExtra.hasTOF() || std::fabs(v0.posTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTPositivePionLambda); + if (!posTrackExtra.hasTOF() || 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 (!negTrackExtra.hasTOF() || std::fabs(v0.negTOFDeltaTLaPr()) < v0Selections.maxDeltaTimeProton) + BITSET(bitMap, selTOFDeltaTNegativeProtonLambda); + if (!negTrackExtra.hasTOF() || std::fabs(v0.negTOFDeltaTLaPi()) < v0Selections.maxDeltaTimePion) + BITSET(bitMap, selTOFDeltaTNegativePionLambda); + if (!negTrackExtra.hasTOF() || 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 (!posTrackExtra.hasTOF() || std::fabs(v0.tofNSigmaLaPr()) < v0Selections.tofPidNsigmaCutLaPr) + BITSET(bitMap, selTOFNSigmaPositiveProtonLambda); + if (!posTrackExtra.hasTOF() || std::fabs(v0.tofNSigmaALaPi()) < v0Selections.tofPidNsigmaCutLaPi) + BITSET(bitMap, selTOFNSigmaPositivePionLambda); + if (!posTrackExtra.hasTOF() || 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 (!negTrackExtra.hasTOF() || std::fabs(v0.tofNSigmaALaPr()) < v0Selections.tofPidNsigmaCutLaPr) + BITSET(bitMap, selTOFNSigmaNegativeProtonLambda); + if (!negTrackExtra.hasTOF() || std::fabs(v0.tofNSigmaLaPi()) < v0Selections.tofPidNsigmaCutLaPi) + BITSET(bitMap, selTOFNSigmaNegativePionLambda); + if (!negTrackExtra.hasTOF() || 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); - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < lifetimecut->get("lifetimecutK0S")) - bitset(bitMap, selK0ShortCTau); + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0Selections.lifetimecut->get("lifetimecutLambda")) + BITSET(bitMap, selLambdaCTau); + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selections.lifetimecut->get("lifetimecutK0S")) + 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; } @@ -668,22 +1359,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() == PDG_t::kProton; + bool isPositivePion = v0.pdgCodePositive() == PDG_t::kPiPlus || (doTreatPiToMuon && v0.pdgCodePositive() == PDG_t::kMuonPlus); + bool isNegativeProton = v0.pdgCodeNegative() == PDG_t::kProtonBar; + bool isNegativePion = v0.pdgCodeNegative() == PDG_t::kPiMinus || (doTreatPiToMuon && v0.pdgCodeNegative() == PDG_t::kMuonMinus); - if (v0.pdgCode() == 310 && v0.pdgCodePositive() == 211 && v0.pdgCodeNegative() == -211) { - bitset(bitMap, selConsiderK0Short); + if (v0.pdgCode() == PDG_t::kK0Short && 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() == PDG_t::kLambda0 && 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() == PDG_t::kLambda0Bar && isPositivePion && isNegativeProton) { + BITSET(bitMap, selConsiderAntiLambda); if (v0.isPhysicalPrimary()) - bitset(bitMap, selPhysPrimAntiLambda); + BITSET(bitMap, selPhysPrimAntiLambda); } return bitMap; } @@ -799,12 +1493,110 @@ struct derivedlambdakzeroanalysis { 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; @@ -820,26 +1612,48 @@ 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()); + histos.fill(HIST("h2dPositivePtVsPhi"), v0.positivept(), computePhiMod(v0.positivephi(), 1)); + histos.fill(HIST("h2dNegativePtVsPhi"), v0.negativept(), computePhiMod(v0.negativephi(), -1)); + } + + // Fill first bin: all candidates + histos.fill(HIST("GeneralQA/hSelectionV0s"), 0); + // Loop over all bits in the enum and fill if passed + for (uint64_t i = 0; i <= selPhysPrimAntiLambda; i++) { + if (BITCHECK(selMap, i)) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), i + 1); // +1 because bin 0 = "All" + } } // __________________________________________ // main analysis - if (verifyMask(selMap, maskSelectionK0Short) && analyseK0Short) { + if (passK0ShortSelections && analyseK0Short) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), selPhysPrimAntiLambda + 2); // 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()); + histos.fill(HIST("K0Short/h2dPositivePtVsPhi"), v0.positivept(), computePhiMod(v0.positivephi(), 1)); + histos.fill(HIST("K0Short/h2dNegativePtVsPhi"), v0.negativept(), computePhiMod(v0.negativephi(), -1)); } if (doDetectPropQA == 1) { histos.fill(HIST("K0Short/h6dDetectPropVsCentrality"), centrality, posDetMap, posITSclusMap, negDetMap, negITSclusMap, pt); @@ -851,39 +1665,78 @@ 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()); } + if (doEtaPhiQA) { + histos.fill(HIST("K0Short/h5dV0PhiVsEta"), centrality, pt, v0.mK0Short(), v0.phi(), v0.eta()); + histos.fill(HIST("K0Short/h5dPosPhiVsEta"), centrality, v0.positivept(), v0.mK0Short(), v0.positivephi(), v0.positiveeta()); + histos.fill(HIST("K0Short/h5dNegPhiVsEta"), centrality, v0.negativept(), v0.mK0Short(), v0.negativephi(), v0.negativeeta()); + } + nK0Shorts++; } - if (verifyMask(selMap, maskSelectionLambda) && analyseLambda) { + if (passLambdaSelections && analyseLambda) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), selPhysPrimAntiLambda + 2); // 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()); + histos.fill(HIST("hMassLambda"), 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()); + histos.fill(HIST("Lambda/h2dPositivePtVsPhi"), v0.positivept(), computePhiMod(v0.positivephi(), 1)); + histos.fill(HIST("Lambda/h2dNegativePtVsPhi"), v0.negativept(), computePhiMod(v0.negativephi(), -1)); } if (doDetectPropQA == 1) { histos.fill(HIST("Lambda/h6dDetectPropVsCentrality"), centrality, posDetMap, posITSclusMap, negDetMap, negITSclusMap, pt); @@ -895,39 +1748,78 @@ 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()); } + if (doEtaPhiQA) { + histos.fill(HIST("Lambda/h5dV0PhiVsEta"), centrality, pt, v0.mLambda(), v0.phi(), v0.eta()); + histos.fill(HIST("Lambda/h5dPosPhiVsEta"), centrality, v0.positivept(), v0.mLambda(), v0.positivephi(), v0.positiveeta()); + histos.fill(HIST("Lambda/h5dNegPhiVsEta"), centrality, v0.negativept(), v0.mLambda(), v0.negativephi(), v0.negativeeta()); + } + nLambdas++; } - if (verifyMask(selMap, maskSelectionAntiLambda) && analyseAntiLambda) { + if (passAntiLambdaSelections && analyseAntiLambda) { + histos.fill(HIST("GeneralQA/hSelectionV0s"), selPhysPrimAntiLambda + 2); // 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()); + histos.fill(HIST("hMassAntiLambda"), 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()); + histos.fill(HIST("AntiLambda/h2dPositivePtVsPhi"), v0.positivept(), computePhiMod(v0.positivephi(), 1)); + histos.fill(HIST("AntiLambda/h2dNegativePtVsPhi"), v0.negativept(), computePhiMod(v0.negativephi(), -1)); } if (doDetectPropQA == 1) { histos.fill(HIST("AntiLambda/h6dDetectPropVsCentrality"), centrality, posDetMap, posITSclusMap, negDetMap, negITSclusMap, pt); @@ -939,28 +1831,55 @@ 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()); } + if (doEtaPhiQA) { + histos.fill(HIST("AntiLambda/h5dV0PhiVsEta"), centrality, pt, v0.mAntiLambda(), v0.phi(), v0.eta()); + histos.fill(HIST("AntiLambda/h5dPosPhiVsEta"), centrality, v0.positivept(), v0.mAntiLambda(), v0.positivephi(), v0.positiveeta()); + histos.fill(HIST("AntiLambda/h5dNegPhiVsEta"), centrality, v0.negativept(), v0.mAntiLambda(), v0.negativephi(), v0.negativeeta()); + } + nAntiLambdas++; } // __________________________________________ @@ -970,24 +1889,23 @@ 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 (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()); } @@ -995,11 +1913,11 @@ struct derivedlambdakzeroanalysis { 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()); } @@ -1039,274 +1957,662 @@ 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) // __________________________________________ if (verifyMask(selMap, secondaryMaskSelectionLambda) && analyseLambda) { - if (v0mother.pdgCode() == 3312 && v0mother.isPhysicalPrimary()) + if (v0mother.pdgCode() == PDG_t::kXiMinus && v0mother.isPhysicalPrimary()) histos.fill(HIST("h3dLambdaFeeddown"), centrality, pt, std::hypot(v0mother.px(), v0mother.py())); } if (verifyMask(selMap, secondaryMaskSelectionAntiLambda) && analyseAntiLambda) { - if (v0mother.pdgCode() == -3312 && v0mother.isPhysicalPrimary()) + if (v0mother.pdgCode() == PDG_t::kXiPlusBar && v0mother.isPhysicalPrimary()) histos.fill(HIST("h3dAntiLambdaFeeddown"), centrality, pt, std::hypot(v0mother.px(), v0mother.py())); } } - // ______________________________________________________ - // Real data processing - no MC subscription - void processRealData(soa::Join::iterator const& collision, v0Candidates const& fullV0s, dauTracks const&) + template + bool isEventAccepted(TCollision collision, bool fillHists) + // check whether the collision passes our collision selections { - histos.fill(HIST("hEventSelection"), 0. /* all collisions */); - if (!collision.sel8()) { - return; + float centrality = -1.0f; + if (fillHists) { + histos.fill(HIST("hEventSelection"), 0. /* all collisions */); + if (doEventQA) { + if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 + centrality = getCentralityRun3(collision); + } + histos.fill(HIST("hEventSelectionVsCentrality"), 0. /* all collisions */, centrality); + } } - histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); - if (std::abs(collision.posZ()) > 10.f) { - return; - } - histos.fill(HIST("hEventSelection"), 2 /* vertex-Z selected */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 1 /* sel8 collisions */, centrality); + } + } - if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - return; - } - histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */, centrality); + } + } - if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return; - } - histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 3 /* Not at ITS ROF border */, centrality); + } + } - if (requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return; - } - histos.fill(HIST("hEventSelection"), 5 /* Contains at least one ITS-TPC track */); + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + if (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 4 /* Not at TF border */, centrality); + } + } - if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return; - } - histos.fill(HIST("hEventSelection"), 6 /* PV position consistency check */); + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + if (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 5 /* vertex-Z selected */, centrality); + } + } - if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { - return; - } - histos.fill(HIST("hEventSelection"), 7 /* PV with at least one contributor matched with TOF */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 6 /* Contains at least one ITS-TPC track */, centrality); + } + } - if (requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { - return; - } - histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TRD */); + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + if (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 7 /* PV position consistency check */, centrality); + } + } - if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return; - } - histos.fill(HIST("hEventSelection"), 9 /* Not at same bunch pile-up */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 8 /* PV with at least one contributor matched with TOF */, centrality); + } + } - if (requireNoHighOccupancyAgressive && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyAgressive)) { - return; - } - histos.fill(HIST("hEventSelection"), 10 /* No occupancy according to the aggressive cuts */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 9 /* PV with at least one contributor matched with TRD */, centrality); + } + } - if (requireNoHighOccupancyStrict && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyStrict)) { - return; - } - histos.fill(HIST("hEventSelection"), 11 /* No occupancy according to the strict cuts */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 10 /* Not at same bunch pile-up */, centrality); + } + } - if (requireNoHighOccupancyMedium && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyMedium)) { - return; - } - histos.fill(HIST("hEventSelection"), 12 /* No occupancy according to the medium cuts */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 11 /* No other collision within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds*/, centrality); + } + } - if (requireNoHighOccupancyRelaxed && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyRelaxed)) { - return; - } - histos.fill(HIST("hEventSelection"), 13 /* No occupancy according to the relaxed cuts */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 12 /* No other collision within +/- 10 microseconds */, centrality); + } + } - if (requireNoHighOccupancyGentle && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyGentle)) { - return; - } - histos.fill(HIST("hEventSelection"), 14 /* No occupancy according to the gentle cuts */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 13 /* No other collision within +/- 2 microseconds */, centrality); + } + } - if (requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { - return; - } - histos.fill(HIST("hEventSelection"), 15 /* No other collision within +/- 10 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 14 /* No other collision within the same ITS ROF with mult. above a certain threshold */, centrality); + } + } - if (requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { - return; - } - histos.fill(HIST("hEventSelection"), 16 /* No other collision within +/- 4 microseconds */); + 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 15 /* No other collision within the same ITS ROF */, centrality); + } + } - if (minOccupancy > 0 && collision.trackOccupancyInTimeRange() < minOccupancy) { - return; - } - histos.fill(HIST("hEventSelection"), 17 /* Below min occupancy */); - if (maxOccupancy > 0 && collision.trackOccupancyInTimeRange() > maxOccupancy) { - return; - } - histos.fill(HIST("hEventSelection"), 18 /* Above max occupancy */); + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + if (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 16 /* INEL > 0 */, centrality); + } + } - float centrality = collision.centFT0C(); - if (qaCentrality) { - auto hRawCentrality = histos.get(HIST("hRawCentrality")); - centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); - } + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + if (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 17 /* INEL > 1 */, centrality); + } + } - histos.fill(HIST("hEventCentrality"), centrality); + } 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 16 /* Below min occupancy */, centrality); + } + } - histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 17 /* Above max occupancy */); + if (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 17 /* Above max occupancy */, centrality); + } + } + } - histos.fill(HIST("hEventOccupancy"), collision.trackOccupancyInTimeRange()); - histos.fill(HIST("hCentralityVsOccupancy"), centrality, collision.trackOccupancyInTimeRange()); + // 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 (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 18 /* Below min IR */, centrality); + } + } - // __________________________________________ - // perform main analysis - for (auto& v0 : fullV0s) { - if (std::abs(v0.negativeeta()) > daughterEtaCut || std::abs(v0.positiveeta()) > daughterEtaCut) - continue; // remove acceptance that's badly reproduced by MC / superfluous in future + if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 19 /* Above max IR */); + if (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 19 /* Above max IR */, centrality); + } + } - if (v0.v0Type() != v0TypeSelection && v0TypeSelection > -1) - continue; // skip V0s that are not standard + if (!rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(collision)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 20 /* Pass CBT condition */); + if (doEventQA) { + histos.fill(HIST("hEventSelectionVsCentrality"), 20 /* Pass CBT condition */, centrality); + } + } - // fill AP plot for all V0s - histos.fill(HIST("GeneralQA/h2dArmenterosAll"), v0.alpha(), v0.qtarm()); + } else { // we are in Run 2 + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); - uint64_t selMap = computeReconstructionBitmap(v0, collision, v0.yLambda(), v0.yK0Short(), v0.pt()); + if (eventSelections.requireSel7 && !collision.sel7()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 2 /* sel7 collisions */); - // 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); + if (eventSelections.requireINT7 && !collision.alias_bit(kINT7)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 3 /* INT7-triggered collisions */); - analyseCandidate(v0, v0.pt(), centrality, selMap); - } // end v0 loop + 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; } // ______________________________________________________ - // 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*/) + // 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; - } - histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + 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 (std::abs(collision.posZ()) > 10.f) { - return; + 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"), 2 /* vertex-Z selected */); + return listBestCollisionIdx; + } - if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - return; - } - histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + // ______________________________________________________ + // 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 = getCentralityRun3(collision); + 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())); + } - if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return; + // 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"), 4 /* Not at TF border */); - if (requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return; - } - histos.fill(HIST("hEventSelection"), 5 /* Contains at least one ITS-TPC track */); + histos.fill(HIST("hGapSide"), gapSide); + histos.fill(HIST("hSelGapSide"), selGapSide); + histos.fill(HIST("hEventCentralityVsSelGapSide"), centrality, selGapSide <= 2 ? selGapSide : -1); - if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return; - } - histos.fill(HIST("hEventSelection"), 6 /* PV position consistency check */); + histos.fill(HIST("hEventCentrality"), centrality); - if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { - return; + histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + if (doEventQA) { + if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 + histos.fill(HIST("hCentralityVsNGlobal"), centrality, collision.multNTracksGlobal()); + histos.fill(HIST("hEventCentVsMultFT0M"), collision.centFT0M(), collision.multFT0A() + collision.multFT0C()); + histos.fill(HIST("hEventCentVsMultFT0C"), collision.centFT0C(), collision.multFT0C()); + histos.fill(HIST("hEventCentVsMultNGlobal"), collision.centNGlobal(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventCentVsMultFV0A"), collision.centFV0A(), collision.multFV0A()); + histos.fill(HIST("hEventMultFT0MvsMultNGlobal"), collision.multFT0A() + collision.multFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventMultFT0CvsMultNGlobal"), collision.multFT0C(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventMultFV0AvsMultNGlobal"), collision.multFV0A(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventMultPVvsMultNGlobal"), collision.multNTracksPVeta1(), collision.multNTracksGlobal()); + histos.fill(HIST("hEventMultFT0CvsMultFV0A"), collision.multFT0C(), collision.multFV0A()); + } } - histos.fill(HIST("hEventSelection"), 7 /* PV with at least one contributor matched with TOF */); - if (requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { - return; - } - histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TRD */); + histos.fill(HIST("hCentralityVsPVz"), centrality, collision.posZ()); + histos.fill(HIST("hEventPVz"), collision.posZ()); - if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return; - } - histos.fill(HIST("hEventSelection"), 9 /* Not at same bunch pile-up */); + histos.fill(HIST("hEventOccupancy"), collisionOccupancy); + histos.fill(HIST("hCentralityVsOccupancy"), centrality, collisionOccupancy); - if (requireNoHighOccupancyAgressive && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyAgressive)) { - return; - } - histos.fill(HIST("hEventSelection"), 10 /* No occupancy according to the aggressive cuts */); + histos.fill(HIST("hInteractionRate"), interactionRate); + histos.fill(HIST("hCentralityVsInteractionRate"), centrality, interactionRate); - if (requireNoHighOccupancyStrict && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyStrict)) { - return; - } - histos.fill(HIST("hEventSelection"), 11 /* No occupancy according to the strict cuts */); + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); + return; + } - if (requireNoHighOccupancyMedium && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyMedium)) { - return; - } - histos.fill(HIST("hEventSelection"), 12 /* No occupancy according to the medium cuts */); + // ______________________________________________________ + // 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 (requireNoHighOccupancyRelaxed && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyRelaxed)) { - return; - } - histos.fill(HIST("hEventSelection"), 13 /* No occupancy according to the relaxed cuts */); + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + } - if (requireNoHighOccupancyGentle && !collision.selection_bit(o2::aod::evsel::kNoHighOccupancyGentle)) { - return; + 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 = getCentralityRun3(collision); + } + } 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"), 14 /* No occupancy according to the gentle cuts */); + return; + } - if (requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { - 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) || + v0Selections.rejectTPCsectorBoundary) { + initCCDB(collision); } - histos.fill(HIST("hEventSelection"), 15 /* No other collision within +/- 10 microseconds */); - if (requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + if (!isEventAccepted(collision, true)) { return; } - histos.fill(HIST("hEventSelection"), 16 /* No other collision within +/- 4 microseconds */); - if (minOccupancy > 0 && collision.trackOccupancyInTimeRange() < minOccupancy) { - return; + 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("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); + + // __________________________________________ + // perform main analysis + 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 + BITSET(selMap, selConsiderK0Short); + BITSET(selMap, selConsiderLambda); + BITSET(selMap, selConsiderAntiLambda); + + BITSET(selMap, selPhysPrimK0Short); + BITSET(selMap, selPhysPrimLambda); + BITSET(selMap, selPhysPrimAntiLambda); + + 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); } - histos.fill(HIST("hEventSelection"), 17 /* Below min occupancy */); - if (maxOccupancy > 0 && collision.trackOccupancyInTimeRange() > maxOccupancy) { - return; + if (analyseLambda) { + histos.fill(HIST("h2dNbrOfLambdaVsCentrality"), centrality, nLambdas); + } + if (analyseAntiLambda) { + histos.fill(HIST("h2dNbrOfAntiLambdaVsCentrality"), centrality, nAntiLambdas); } - histos.fill(HIST("hEventSelection"), 18 /* Above max occupancy */); + } - float centrality = collision.centFT0C(); - if (qaCentrality) { - auto hRawCentrality = histos.get(HIST("hRawCentrality")); - centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(collision.multFT0C())); + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + template + void analyzeRecoedV0sInMonteCarlo(TCollision const& collision, TV0s const& fullV0s) + { + // Fire up CCDB + if ((mlConfigurations.useK0ShortScores && mlConfigurations.calculateK0ShortScores) || + (mlConfigurations.useLambdaScores && mlConfigurations.calculateLambdaScores) || + (mlConfigurations.useAntiLambdaScores && mlConfigurations.calculateAntiLambdaScores) || + v0Selections.rejectTPCsectorBoundary) { + initCCDB(collision); } - histos.fill(HIST("hEventCentrality"), centrality); + if (!isEventAccepted(collision, true)) { + return; + } - histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); + 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("hEventOccupancy"), collision.trackOccupancyInTimeRange()); - histos.fill(HIST("hCentralityVsOccupancy"), centrality, collision.trackOccupancyInTimeRange()); + 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() == PDG_t::kK0Short) + 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()) == PDG_t::kLambda0) + 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) @@ -1314,25 +2620,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() == PDG_t::kK0Short) + ymc = v0MC.rapidityMC(0); + else if (std::abs(v0MC.pdgCode()) == PDG_t::kLambda0) + 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 = getCentralityRun3(collision); + } else { // no, we are in Run 2 + centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); + } + + if (v0MC.pdgCode() == PDG_t::kK0Short) { + histos.fill(HIST("h2dGenK0ShortVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == PDG_t::kLambda0) { + histos.fill(HIST("h2dGenLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == PDG_t::kLambda0Bar) { + histos.fill(HIST("h2dGenAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + if (v0MC.pdgCode() == PDG_t::kK0Short) { + histos.fill(HIST("h2dGenK0Short"), centrality, ptmc); + histos.fill(HIST("h2dGenK0ShortVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == PDG_t::kLambda0) { + histos.fill(HIST("h2dGenLambda"), centrality, ptmc); + histos.fill(HIST("h2dGenLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == PDG_t::kLambda0Bar) { + 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()) == PDG_t::kXiMinus) + ymc = cascMC.rapidityMC(0); + else if (std::abs(cascMC.pdgCode()) == PDG_t::kOmegaMinus) + 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 = getCentralityRun3(collision); + } else { // no, we are in Run 2 + centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); + } + + if (cascMC.pdgCode() == PDG_t::kXiMinus) { + histos.fill(HIST("h2dGenXiMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == PDG_t::kXiPlusBar) { + histos.fill(HIST("h2dGenXiPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == PDG_t::kOmegaMinus) { + histos.fill(HIST("h2dGenOmegaMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar) { + histos.fill(HIST("h2dGenOmegaPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + + if (cascMC.pdgCode() == PDG_t::kXiMinus) { + histos.fill(HIST("h2dGenXiMinus"), centrality, ptmc); + histos.fill(HIST("h2dGenXiMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == PDG_t::kXiPlusBar) { + histos.fill(HIST("h2dGenXiPlus"), centrality, ptmc); + histos.fill(HIST("h2dGenXiPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == PDG_t::kOmegaMinus) { + histos.fill(HIST("h2dGenOmegaMinus"), centrality, ptmc); + histos.fill(HIST("h2dGenOmegaMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar) { + 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); } // ______________________________________________________ @@ -1342,67 +2851,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..6b43f823c12 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/derivedupcanalysis.cxx @@ -0,0 +1,2355 @@ +// 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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/strangenessMasks.h" +#include "PWGUD/Core/SGSelector.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/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; + +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 NeutronsMC = soa::Join; + +using CascMCCoresFull = soa::Join; + +using StraCollisonsFull = soa::Join; +using StraCollisonFull = soa::Join::iterator; + +using StraCollisonsFullMC = soa::Join; +using StraCollisonFullMC = soa::Join::iterator; + +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 + struct : ConfigurableGroup { + 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 requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", true, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerFV0Check{"cfgEvtRCTFlagCheckerFV0Check", true, "Evt sel: RCT flag checker FV0 check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } evSels; + + RCTFlagsChecker rctChecker; + + // Custom grouping + std::vector> v0sGrouped; + std::vector> cascadesGrouped; + + 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 kNCtauCutsV0[1][2] = {{6, 6.}}; + Configurable> nCtauCutV0{"nCtauCutV0", {kNCtauCutsV0[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "nCtauCutV0"}; + + // 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 axisFT0ampl{"axisFT0ampl", {2002, -1.5f, 2000.5f}, "axisFT0ampl"}; + 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"}; + Configurable checkNeutronsInMC{"checkNeutronsInMC", true, "require no neutrons for single-gap in MC"}; + Configurable neutronEtaCut{"neutronEtaCut", 8.8, "ZN acceptance"}; + + // Occupancy cut + 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., 1., 5, 10, 20, 30, 40, 50, 60, 70, 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", {48, 0.0f, 1.2f}, "DCA (cm)"}; + ConfigurableAxis axisPointingAngle{"axisPointingAngle", {100, 0.0f, 0.5f}, "pointing angle (rad)"}; + ConfigurableAxis axisCosPA{"axisCosPA", {300, 0.97f, 1.0f}, "cosPA"}; + ConfigurableAxis axisV0Radius{"axisV0Radius", {100, 0.0f, 10.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 axisCtau{"axisCtau", {200, 0.0f, 20.0f}, "c x tau (cm)"}; + + 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/hCtau", kParticlenames[partID].data()), "hCtau", kTH2F, {axisPtCoarse, axisCtau}); + 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/hCosPA", kParticlenames[partID].data()), "hCosPA", kTH1F, {axisCosPA}); + 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}); + histos.add(Form("%s/hCtau", kParticlenames[partID].data()), "hCtau", kTH2F, {axisPtCoarse, axisCtau}); + } + } + + template + void addTPCQAHistograms(HistogramRegistry& histos) + { + const bool isCascade = (partID > 2.5) ? true : false; + histos.add(Form("%s/h3dPosNsigmaTPC", kParticlenames[partID].data()), "h3dPosNsigmaTPC", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dNegNsigmaTPC", kParticlenames[partID].data()), "h3dNegNsigmaTPC", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dPosTPCsignal", kParticlenames[partID].data()), "h3dPosTPCsignal", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dNegTPCsignal", kParticlenames[partID].data()), "h3dNegTPCsignal", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTPCsignal}); + + histos.add(Form("%s/h3dPosNsigmaTPCvsTrackPtot", kParticlenames[partID].data()), "h3dPosNsigmaTPCvsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dNegNsigmaTPCvsTrackPtot", kParticlenames[partID].data()), "h3dNegNsigmaTPCvsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + + histos.add(Form("%s/h3dPosTPCsignalVsTrackPtot", kParticlenames[partID].data()), "h3dPosTPCsignalVsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dNegTPCsignalVsTrackPtot", kParticlenames[partID].data()), "h3dNegTPCsignalVsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTPCsignal}); + + histos.add(Form("%s/h3dPosNsigmaTPCvsTrackPt", kParticlenames[partID].data()), "h3dPosNsigmaTPCvsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dNegNsigmaTPCvsTrackPt", kParticlenames[partID].data()), "h3dNegNsigmaTPCvsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + + histos.add(Form("%s/h3dPosTPCsignalVsTrackPt", kParticlenames[partID].data()), "h3dPosTPCsignalVsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dNegTPCsignalVsTrackPt", kParticlenames[partID].data()), "h3dNegTPCsignalVsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTPCsignal}); + + if (isCascade) { + histos.add(Form("%s/h3dBachTPCsignal", kParticlenames[partID].data()), "h3dBachTPCsignal", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dBachNsigmaTPC", kParticlenames[partID].data()), "h3dBachNsigmaTPC", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dBachNsigmaTPCvsTrackPtot", kParticlenames[partID].data()), "h3dBachNsigmaTPCvsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dBachTPCsignalVsTrackPtot", kParticlenames[partID].data()), "h3dBachTPCsignalVsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTPCsignal}); + histos.add(Form("%s/h3dBachNsigmaTPCvsTrackPt", kParticlenames[partID].data()), "h3dBachNsigmaTPCvsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisNsigmaTPC}); + histos.add(Form("%s/h3dBachTPCsignalVsTrackPt", kParticlenames[partID].data()), "h3dBachTPCsignalVsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, 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, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dNegTOFdeltaT", kParticlenames[partID].data()), "h3dNegTOFdeltaT", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dPosTOFdeltaTvsTrackPtot", kParticlenames[partID].data()), "h3dPosTOFdeltaTvsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dNegTOFdeltaTvsTrackPtot", kParticlenames[partID].data()), "h3dNegTOFdeltaTvsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dPosTOFdeltaTvsTrackPt", kParticlenames[partID].data()), "h3dPosTOFdeltaTvsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dNegTOFdeltaTvsTrackPt", kParticlenames[partID].data()), "h3dNegTOFdeltaTvsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTOFdeltaT}); + if (isCascade) { + histos.add(Form("%s/h3dBachTOFdeltaT", kParticlenames[partID].data()), "h3dBachTOFdeltaT", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dBachTOFdeltaTvsTrackPtot", kParticlenames[partID].data()), "h3dBachTOFdeltaTvsTrackPtot", kTH3F, {axisDetectors.axisFT0ampl, axisPtCoarse, axisTOFdeltaT}); + histos.add(Form("%s/h3dBachTOFdeltaTvsTrackPt", kParticlenames[partID].data()), "h3dBachTOFdeltaTvsTrackPt", kTH3F, {axisDetectors.axisFT0ampl, 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, {axisDetectors.axisFT0ampl, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse}); + } else { + histos.add(Form("%s/h6dDetectPropVsCentrality", kParticlenames[partID].data()), "h6dDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse}); + } + histos.add(Form("%s/h4dPosDetectPropVsCentrality", kParticlenames[partID].data()), "h4dPosDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMap, axisITScluMap, axisPtCoarse}); + histos.add(Form("%s/h4dNegDetectPropVsCentrality", kParticlenames[partID].data()), "h4dNegDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMap, axisITScluMap, axisPtCoarse}); + histos.add(Form("%s/h4dBachDetectPropVsCentrality", kParticlenames[partID].data()), "h4dBachDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMap, axisITScluMap, axisPtCoarse}); + } + if (doDetectPropQA == 2) { + if (isCascade) { + histos.add(Form("%s/h9dDetectPropVsCentrality", kParticlenames[partID].data()), "h9dDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse, axisInvMass.at(partID)}); + } else { + histos.add(Form("%s/h7dDetectPropVsCentrality", kParticlenames[partID].data()), "h7dDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMapCoarse, axisITScluMapCoarse, axisDetMapCoarse, axisITScluMapCoarse, axisPtCoarse, axisInvMass.at(partID)}); + } + histos.add(Form("%s/h5dPosDetectPropVsCentrality", kParticlenames[partID].data()), "h5dPosDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMap, axisITScluMap, axisPtCoarse, axisInvMass.at(partID)}); + histos.add(Form("%s/h5dNegDetectPropVsCentrality", kParticlenames[partID].data()), "h5dNegDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMap, axisITScluMap, axisPtCoarse, axisInvMass.at(partID)}); + histos.add(Form("%s/h5dBachDetectPropVsCentrality", kParticlenames[partID].data()), "h5dBachDetectPropVsCentrality", kTHnSparseF, {axisDetectors.axisFT0ampl, axisDetMap, axisITScluMap, axisPtCoarse, axisInvMass.at(partID)}); + } + } + + template + void addHistograms(HistogramRegistry& histos) + { + histos.add(Form("%s/h7dMass", kParticlenames[partID].data()), "h7dMass", kTHnSparseF, {axisDetectors.axisFT0ampl, 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 ft0ampl = -1.f; + if (gap == 0) { + ft0ampl = coll.totalFT0AmplitudeC(); + } else if (gap == 1) { + ft0ampl = coll.totalFT0AmplitudeA(); + } + float pT = cand.pt(); + float rapidity = 1e6; + + // c x tau + float ctau = 0; + + 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(); + ctau = cand.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * o2::constants::physics::MassK0Short; + 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(); + ctau = cand.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * o2::constants::physics::MassLambda0; + 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(); + ctau = cand.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * o2::constants::physics::MassLambda0Bar; + 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"), ft0ampl, 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("/hCosPA"), 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()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/hCtau"), pT, ctau); + } + if (doDetectPropQA == 1) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h6dDetectPropVsCentrality"), ft0ampl, posDetMap, posITSclusMap, negDetMap, negITSclusMap, pT); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h4dPosDetectPropVsCentrality"), ft0ampl, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pT); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h4dNegDetectPropVsCentrality"), ft0ampl, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pT); + } + if (doDetectPropQA == 2) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h7dPosDetectPropVsCentrality"), ft0ampl, posDetMap, posITSclusMap, negDetMap, negITSclusMap, pT, invMass); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h5dPosDetectPropVsCentrality"), ft0ampl, posTrackExtra.detectorMap(), posTrackExtra.itsClusterMap(), pT, invMass); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h5dNegDetectPropVsCentrality"), ft0ampl, negTrackExtra.detectorMap(), negTrackExtra.itsClusterMap(), pT, invMass); + } + if (PIDConfigurations.doTPCQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignal"), ft0ampl, pT, posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignal"), ft0ampl, pT, negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignalVsTrackPtot"), ft0ampl, cand.positivept() * std::cosh(cand.positiveeta()), posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignalVsTrackPtot"), ft0ampl, cand.negativept() * std::cosh(cand.negativeeta()), negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTPCsignalVsTrackPt"), ft0ampl, cand.positivept(), posTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTPCsignalVsTrackPt"), ft0ampl, cand.negativept(), negTrackExtra.tpcSignal()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPCvsTrackPt"), ft0ampl, cand.positivept(), posTrackExtra.tpcNSigmaPi()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPCvsTrackPt"), ft0ampl, cand.negativept(), negTrackExtra.tpcNSigmaPi()); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPCvsTrackPtot"), ft0ampl, cand.positivept() * std::cosh(cand.positiveeta()), tpcNsigmaPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPCvsTrackPtot"), ft0ampl, cand.negativept() * std::cosh(cand.negativeeta()), tpcNsigmaNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosNsigmaTPC"), ft0ampl, pT, tpcNsigmaPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegNsigmaTPC"), ft0ampl, pT, tpcNsigmaNeg); + } + if (PIDConfigurations.doTOFQA) { + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaTvsTrackPt"), ft0ampl, cand.positivept(), tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaTvsTrackPt"), ft0ampl, cand.negativept(), tofDeltaTNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaT"), ft0ampl, pT, tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaT"), ft0ampl, pT, tofDeltaTNeg); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dPosTOFdeltaTvsTrackPtot"), ft0ampl, cand.positivept() * std::cosh(cand.positiveeta()), tofDeltaTPos); + histos.fill(HIST(kParticlenames[partID]) + HIST("/h3dNegTOFdeltaTvsTrackPtot"), ft0ampl, cand.negativept() * std::cosh(cand.negativeeta()), tofDeltaTNeg); + } + } + + template + void fillHistogramsCasc(TCand cand, TCollision coll, const int gap) + { + float invMass = 0; + float centrality = -1.f; + if (gap == 0) { + centrality = coll.totalFT0AmplitudeC(); + } else if (gap == 1) { + centrality = coll.totalFT0AmplitudeA(); + } + 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("/hCtau"), 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."; + } + + rctChecker.init(evSels.cfgEvtRCTFlagCheckerLabel, evSels.cfgEvtRCTFlagCheckerZDCCheck, evSels.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + if (evSels.cfgEvtRCTFlagCheckerFV0Check) { + rctChecker.set(o2::aod::rctsel::kFV0Bad); + } + + // 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", kTH1D, {{17, -0.5f, 16.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, "RCTFlagsChecker"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(16, "isUPC"); + histos.get(HIST("eventQA/hEventSelection"))->GetXaxis()->SetBinLabel(17, "has UPC flag"); + + // Event QA + histos.add("eventQA/hCentralityVsFT0ampl", "hCentralityVsFT0ampl", kTH3D, {axisFT0Cqa, axisDetectors.axisFT0Aampl, axisSelGap}); + histos.add("eventQA/hCentrality", "hCentrality", kTH2D, {axisFT0Cqa, axisSelGap}); + histos.add("eventQA/hFT0ampl", "hFT0ampl", kTH2D, {axisDetectors.axisFT0Aampl, axisSelGap}); + histos.add("eventQA/hCentralityVsTracksPVeta1", "hCentralityVsTracksPVeta1", kTH3D, {axisFT0Cqa, axisNTracksPVeta1, axisSelGap}); + histos.add("eventQA/hCentralityVsTracksTotalExceptITSonly", "hCentralityVsTracksTotalExceptITSonly", kTH3D, {axisFT0Cqa, axisNTracksTotalExceptITSonly, axisSelGap}); + histos.add("eventQA/hOccupancy", "hOccupancy", kTH2D, {axisOccupancy, axisSelGap}); + histos.add("eventQA/hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH3D, {axisFT0Cqa, axisOccupancy, axisSelGap}); + histos.add("eventQA/hTracksPVeta1VsTracksGlobal", "hTracksPVeta1VsTracksGlobal", kTH3D, {axisNTracksPVeta1, axisNTracksGlobal, axisSelGap}); + histos.add("eventQA/hCentralityVsTracksGlobal", "hCentralityVsTracksGlobal", kTH3D, {axisFT0Cqa, axisNTracksGlobal, axisSelGap}); + histos.add("eventQA/hFT0amplVsTracksGlobal", "hFT0amplVsTracksGlobal", kTH3D, {axisDetectors.axisFT0Aampl, axisNTracksGlobal, axisSelGap}); + histos.add("eventQA/hRawGapSide", "Raw Gap side; Entries", kTH1D, {{6, -1.5, 4.5}}); + histos.add("eventQA/hSelGapSide", "Selected gap side (with n); Entries", kTH1D, {axisSelGap}); + histos.add("eventQA/hPosX", "Vertex position in x", kTH2D, {{100, -0.1, 0.1}, axisSelGap}); + histos.add("eventQA/hPosY", "Vertex position in y", kTH2D, {{100, -0.1, 0.1}, axisSelGap}); + histos.add("eventQA/hPosZ", "Vertex position in z", kTH2D, {{100, -20., 20.}, axisSelGap}); + histos.add("eventQA/hFT0", "hFT0", kTH3D, {axisDetectors.axisFT0Aampl, axisDetectors.axisFT0Campl, axisSelGap}); + histos.add("eventQA/hFDD", "hFDD", kTH3D, {axisDetectors.axisFDDAampl, axisDetectors.axisFDDCampl, axisSelGap}); + histos.add("eventQA/hZN", "hZN", kTH3D, {axisDetectors.axisZNAampl, axisDetectors.axisZNCampl, axisSelGap}); + + if (doprocessGenerated) { + histos.add("eventQA/mc/hEventSelectionMC", "hEventSelectionMC", kTH3D, {{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/hTracksGlobalvsMCNParticlesEta08gen", "hTracksGlobalvsMCNParticlesEta08gen", kTH2D, {axisNTracksGlobal, axisNTracksGlobal}); + histos.add("eventQA/mc/hTracksGlobalVsNcoll_beforeEvSel", "hTracksGlobalVsNcoll_beforeEvSel", kTH2D, {axisNTracksGlobal, axisNAssocColl}); + histos.add("eventQA/mc/hTracksGlobalVsNcoll_afterEvSel", "hTracksGlobalVsNcoll_afterEvSel", kTH2D, {axisNTracksGlobal, axisNAssocColl}); + histos.add("eventQA/mc/hTracksGlobalVsPVzMC", "hTracksGlobalVsPVzMC", kTH2D, {axisNTracksGlobal, {100, -20., 20.}}); + histos.add("eventQA/mc/hEventPVzMC", "hEventPVzMC", kTH1D, {{100, -20., 20.}}); + histos.add("eventQA/mc/hGenEventFT0ampl", "hGenEventFT0ampl", kTH1D, {axisDetectors.axisFT0Aampl}); + histos.add("eventQA/mc/hGenEventCentrality", "hGenEventCentrality", kTH1D, {axisFT0Cqa}); + histos.add("eventQA/mc/hGeneratorsId", "hGeneratorsId", kTH1D, {axisGeneratorIds}); + histos.add("eventQA/mc/hSelGeneratorsId", "hSelGeneratorsId", kTH1D, {axisGeneratorIds}); + } + + if (doprocessV0sMC || doprocessCascadesMC) { + // Event QA + histos.add("eventQA/mc/hFakeEvents", "hFakeEvents", {kTH1D, {{1, -0.5f, 0.5f}}}); + histos.add("eventQA/mc/hNTracksGlobalvsMCNParticlesEta08rec", "hNTracksGlobalvsMCNParticlesEta08rec", kTH2D, {axisNTracksGlobal, axisNTracksGlobal}); + histos.add("eventQA/mc/hNTracksPVeta1vsMCNParticlesEta10rec", "hNTracksPVeta1vsMCNParticlesEta10rec", kTH2D, {axisNTracksPVeta1, axisNTracksPVeta1}); + histos.add("eventQA/mc/hNTracksGlobalvstotalMultMCParticles", "hNTracksGlobalvstotalMultMCParticles", kTH2D, {axisNTracksGlobal, axisNchInvMass}); + histos.add("eventQA/mc/hNTracksPVeta1vstotalMultMCParticles", "hNTracksPVeta1vstotalMultMCParticles", kTH2D, {axisNTracksPVeta1, axisNchInvMass}); + histos.add("eventQA/hSelGapSideNoNeutrons", "Selected gap side (no n); Entries", kTH1D, {{5, -0.5, 4.5}}); + } + + if (doprocessV0sMC) { + if (analyseLambda && calculateFeeddownMatrix) + histos.add(Form("%s/h3dLambdaFeeddown", kParticlenames[1].data()), "h3dLambdaFeeddown", kTH3F, {axisNTracksGlobal, axisPt, axisPt}); + if (analyseAntiLambda && calculateFeeddownMatrix) + histos.add(Form("%s/h3dAntiLambdaFeeddown", kParticlenames[2].data()), "h3dAntiLambdaFeeddown", kTH3F, {axisNTracksGlobal, axisPt, axisPt}); + } + + if (doprocessGenerated) { + for (int partID = 0; partID <= 6; partID++) { + histos.add(Form("%s/mc/h7dGen", kParticlenames[partID].data()), "h7dGen", kTHnSparseF, {axisDetectors.axisFT0ampl, 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/hCosPA", "hCosPA", kTH1F, {axisCosPA}); + 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) + { + int selGapSide = sgSelector.trueGap(collision, upcCuts.fv0a, upcCuts.ft0a, upcCuts.ft0c, upcCuts.zdc); + return selGapSide; + } + + template + void fillHistogramsQA(TCollision const& collision, int const& gap) + { + // QA histograms + float centrality = collision.centFT0C(); + float ft0ampl = -1.f; + + if (gap == 0) { + ft0ampl = collision.totalFT0AmplitudeC(); + } else if (gap == 1) { + ft0ampl = collision.totalFT0AmplitudeA(); + } + + histos.fill(HIST("eventQA/hCentralityVsFT0ampl"), centrality, ft0ampl, gap); + histos.fill(HIST("eventQA/hCentrality"), centrality, gap); + histos.fill(HIST("eventQA/hFT0ampl"), ft0ampl, 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/hFT0amplVsTracksGlobal"), ft0ampl, 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); + + histos.fill(HIST("eventQA/hSelGapSide"), gap); + histos.fill(HIST("eventQA/hFT0"), collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), gap); + histos.fill(HIST("eventQA/hFDD"), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), gap); + + auto zna = collision.energyCommonZNA(); + auto znc = collision.energyCommonZNC(); + constexpr float inf_f = std::numeric_limits::infinity(); + + if (zna == -inf_f) + histos.fill(HIST("eventQA/hZN"), -1, znc, gap); + else if (znc == -inf_f) + histos.fill(HIST("eventQA/hZN"), zna, -1, gap); + else if (zna == -999 && znc == -999) + histos.fill(HIST("eventQA/hZN"), -2, -2, gap); + else if (zna == -999 || znc == -999) + LOG(warning) << "Only one ZDC signal is -999"; + } + + template + bool acceptEvent(TCollision const& collision, bool fillQA) + { + struct SelectionCheck { + bool selection; + bool condition; + float qaBin; + }; + + const std::array selections = {{ + {true, true, 0.0}, // All collisions + {evSels.requireIsTriggerTVX, collision.selection_bit(aod::evsel::kIsTriggerTVX), 1.0}, // Triggered by FT0M + {true, std::fabs(collision.posZ()) < maxZVtxPosition, 2.0}, // Vertex-Z selected + {evSels.rejectITSROFBorder, collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder), 3.0}, // Not at ITS ROF border + {evSels.rejectTFBorder, collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder), 4.0}, // Not at TF border + {evSels.requireIsVertexITSTPC, collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC), 5.0}, // At least one ITS-TPC track + {evSels.requireIsGoodZvtxFT0VsPV, collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV), 6.0}, // PV position consistency + {evSels.requireIsVertexTOFmatched, collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched), 7.0}, // PV with TOF match + {evSels.requireIsVertexTRDmatched, collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched), 8.0}, // PV with TRD match + {evSels.rejectSameBunchPileup, collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup), 9.0}, // No same-bunch pileup + {evSels.requireNoCollInTimeRangeStd, collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard), 10.0}, // No collision within +-10 µs + {evSels.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 + {evSels.requireRCTFlagChecker, rctChecker(collision), 14.0}, // Verify collision in RCT + }}; + + for (const auto& sel : selections) { + if (sel.selection && !sel.condition) { + return false; + } + if (fillQA && sel.selection) { + histos.fill(HIST("eventQA/hEventSelection"), sel.qaBin); + } + } + + if (evSels.studyUPConly && !collision.isUPC()) { + return false; + } else if (collision.isUPC() && fillQA) { + histos.fill(HIST("eventQA/hEventSelection"), 15.0); // is UPC compatible + } + + // Additional check for UPC collision flag + if (evSels.useUPCflag && collision.flags() < 1) { + return false; + } + if (collision.flags() >= 1 && fillQA) { + histos.fill(HIST("eventQA/hEventSelection"), 16.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); + + // c x tau + float ctauK0short = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short; + float ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + + 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 (ctauLambda < nCtauCutV0->get("lifetimecutLambda") * ctaulambdaPDG) + bitMap.set(selLambdaCTau); + if (ctauK0short < nCtauCutV0->get("lifetimecutK0S") * ctauk0shortPDG) + 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/hCosPA"), 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; + PresliceUnsorted neutronsPerMcCollision = aod::zdcneutrons::straMCCollisionId; + + std::vector getListOfRecoCollIds(StraMCCollisionsFull const& mcCollisions, + StraCollisonsFullMC const& collisions, + NeutronsMC const& neutrons) + { + std::vector listBestCollisionIds(mcCollisions.size(), -1); + + for (auto const& mcCollision : mcCollisions) { + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + continue; + } + + // Group collisions and neutrons by MC collision index + auto groupedCollisions = collisions.sliceBy(perMcCollision, mcCollision.globalIndex()); + auto groupedNeutrons = neutrons.sliceBy(neutronsPerMcCollision, 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) : -1; + if (checkNeutronsInMC) { + for (const auto& neutron : groupedNeutrons) { + if (selGapSide < -0.5) + break; + + const float eta = neutron.eta(); + switch (selGapSide) { + case 0: // SGA + if (eta > neutronEtaCut) + selGapSide = -1; + break; + case 1: // SGC + if (eta < -neutronEtaCut) + selGapSide = -1; + break; + case 2: // DG + if (eta > neutronEtaCut) + selGapSide = 1; + else if (eta < -neutronEtaCut) + selGapSide = 0; + break; + } + } + } + + if (evSels.studyUPConly && (selGapSide != static_cast(upcCuts.genGapSide))) + 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, + NeutronsMC const& neutrons) + { + for (auto const& mcCollision : mcCollisions) { + // LOGF(info, "Generator ID is %i", mcCollision.generatorsID()); + histos.fill(HIST("eventQA/mc/hGeneratorsId"), mcCollision.generatorsID()); + + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + continue; + } + + histos.fill(HIST("eventQA/mc/hSelGeneratorsId"), mcCollision.generatorsID()); + + histos.fill(HIST("eventQA/mc/hEventSelectionMC"), 0.0, mcCollision.multMCNParticlesEta08(), mcCollision.generatorsID()); + + if (std::abs(mcCollision.posZ()) > maxZVtxPosition) + continue; + + histos.fill(HIST("eventQA/mc/hEventSelectionMC"), 1.0, mcCollision.multMCNParticlesEta08(), mcCollision.generatorsID()); + + // Group collisions and neutrons by MC collision index + auto groupedCollisions = collisions.sliceBy(perMcCollision, mcCollision.globalIndex()); + auto groupedNeutrons = neutrons.sliceBy(neutronsPerMcCollision, mcCollision.globalIndex()); + + bool atLeastOne = false; + float centrality = -1.f; + float ft0ampl = -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) : -1; + if (checkNeutronsInMC) { + for (const auto& neutron : groupedNeutrons) { + if (selGapSide < -0.5) + break; + + const float eta = neutron.eta(); + switch (selGapSide) { + case 0: // SGA + if (eta > neutronEtaCut) + selGapSide = -1; + break; + case 1: // SGC + if (eta < -neutronEtaCut) + selGapSide = -1; + break; + case 2: // DG + if (eta > neutronEtaCut) + selGapSide = 1; + else if (eta < -neutronEtaCut) + selGapSide = 0; + break; + } + } + } + + if (evSels.studyUPConly && (selGapSide != static_cast(upcCuts.genGapSide))) + continue; + + ++nCollisions; + atLeastOne = true; + + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + if (static_cast(upcCuts.genGapSide) == 0) { + ft0ampl = collision.totalFT0AmplitudeC(); + centrality = collision.centFT0C(); + } else if (static_cast(upcCuts.genGapSide) == 1) { + ft0ampl = collision.totalFT0AmplitudeA(); + centrality = collision.centFT0A(); + } + 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/hTracksGlobalvsMCNParticlesEta08gen"), nTracksGlobal, mcCollision.multMCNParticlesEta08()); + 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.multMCNParticlesEta08(), mcCollision.generatorsID()); + histos.fill(HIST("eventQA/mc/hGenEventCentrality"), centrality); + histos.fill(HIST("eventQA/mc/hGenEventFT0ampl"), ft0ampl); + } + } + } + + template + void fillFeeddownMatrix(TCollision const& collision, TV0 const& v0, std::bitset const& selMap) + { + if (!v0.has_motherMCPart()) { + return; + } + + const auto v0mother = v0.template motherMCPart_as(); + if (v0mother.size() < 1) { + return; + } + + 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(kParticlenames[1]) + HIST("/h3dLambdaFeeddown"), mult, v0pt, motherPt); + } + + if (analyseAntiLambda && verifyMask(selMap, secondaryMaskSelectionAntiLambda) && + (v0mother.pdgCode() == PDG_t::kXiPlusBar) && v0mother.isPhysicalPrimary()) { + histos.fill(HIST(kParticlenames[2]) + HIST("/h3dAntiLambdaFeeddown"), mult, v0pt, motherPt); + } + } + + void processV0s(StraCollisonsFull const& collisions, V0Candidates const& fullV0s, DauTracks const&) + { + v0sGrouped.clear(); + v0sGrouped.resize(collisions.size()); + for (const auto& v0 : fullV0s) { + v0sGrouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + for (const auto& collision : collisions) { + if (!acceptEvent(collision, true)) { + continue; + } // event is accepted + + histos.fill(HIST("eventQA/hRawGapSide"), collision.gapSide()); + + int selGapSide = collision.isUPC() ? getGapSide(collision) : -1; + if (evSels.studyUPConly && (selGapSide < -0.5)) + continue; + + fillHistogramsQA(collision, selGapSide); + + std::size_t nV0sThisColl = v0sGrouped[collision.globalIndex()].size(); + + for (std::size_t i = 0; i < nV0sThisColl; i++) { + auto v0 = fullV0s.rawIteratorAt(v0sGrouped[collision.globalIndex()][i]); + 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(StraCollisonsFullMC const& collisions, + V0CandidatesMC const& fullV0s, + DauTracks const&, + aod::MotherMCParts const&, + StraMCCollisionsFull const&, + V0MCCoresFull const&, + NeutronsMC const& neutrons) + { + v0sGrouped.clear(); + v0sGrouped.resize(collisions.size()); + for (const auto& v0 : fullV0s) { + v0sGrouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + + for (const auto& collision : collisions) { + if (!collision.has_straMCCollision()) { + histos.fill(HIST("eventQA/mc/hFakeEvents"), 0); // no assoc. MC collisions + continue; + } + + const auto& mcCollision = collision.straMCCollision_as(); // take gen. collision associated to the rec. collision + + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + continue; + } + + if (!acceptEvent(collision, true)) { + continue; + } // event is accepted + + histos.fill(HIST("eventQA/hRawGapSide"), collision.gapSide()); + + int selGapSide = collision.isUPC() ? getGapSide(collision) : -1; + int selGapSideNoNeutrons = selGapSide; + + auto groupedNeutrons = neutrons.sliceBy(neutronsPerMcCollision, mcCollision.globalIndex()); + if (checkNeutronsInMC) { + for (const auto& neutron : groupedNeutrons) { + if (selGapSide < -0.5) + break; + + const float eta = neutron.eta(); + switch (selGapSide) { + case 0: // SGA + if (eta > neutronEtaCut) + selGapSide = -1; + break; + case 1: // SGC + if (eta < -neutronEtaCut) + selGapSide = -1; + break; + case 2: // DG + if (eta > neutronEtaCut) + selGapSide = 1; + else if (eta < -neutronEtaCut) + selGapSide = 0; + break; + } + } + } + + if (evSels.studyUPConly && (selGapSide < -0.5)) + continue; + + histos.fill(HIST("eventQA/hSelGapSideNoNeutrons"), selGapSideNoNeutrons); + fillHistogramsQA(collision, selGapSide); + + histos.fill(HIST("eventQA/mc/hNTracksGlobalvsMCNParticlesEta08rec"), collision.multNTracksGlobal(), mcCollision.multMCNParticlesEta08()); + 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()); + + std::size_t nV0sThisColl = v0sGrouped[collision.globalIndex()].size(); + + for (std::size_t i = 0; i < nV0sThisColl; i++) { + auto v0 = fullV0s.rawIteratorAt(v0sGrouped[collision.globalIndex()][i]); + 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(StraCollisonsFull const& collisions, + CascadeCandidates const& fullCascades, + DauTracks const&) + { + cascadesGrouped.clear(); + cascadesGrouped.resize(collisions.size()); + for (const auto& cascade : fullCascades) { + cascadesGrouped[cascade.straCollisionId()].push_back(cascade.globalIndex()); + } + + for (const auto& collision : collisions) { + if (!acceptEvent(collision, true)) { + continue; + } // event is accepted + + histos.fill(HIST("eventQA/hRawGapSide"), collision.gapSide()); + + int selGapSide = collision.isUPC() ? getGapSide(collision) : -1; + if (evSels.studyUPConly && (selGapSide < -0.5)) + continue; + + fillHistogramsQA(collision, selGapSide); + + std::size_t nCascadesThisColl = cascadesGrouped[collision.globalIndex()].size(); + + for (std::size_t i = 0; i < nCascadesThisColl; i++) { + auto casc = fullCascades.rawIteratorAt(cascadesGrouped[collision.globalIndex()][i]); + 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(StraCollisonsFullMC const& collisions, + CascadeCandidatesMC const& fullCascades, + DauTracks const&, + aod::MotherMCParts const&, + StraMCCollisionsFull const&, + CascMCCoresFull const&, + NeutronsMC const& neutrons) + { + cascadesGrouped.clear(); + cascadesGrouped.resize(collisions.size()); + for (const auto& cascade : fullCascades) { + cascadesGrouped[cascade.straCollisionId()].push_back(cascade.globalIndex()); + } + + for (const auto& collision : collisions) { + if (!collision.has_straMCCollision()) { + histos.fill(HIST("eventQA/mc/hFakeEvents"), 0); // no assoc. MC collisions + continue; + } + + const auto& mcCollision = collision.straMCCollision_as(); // take gen. collision associated to the rec. collision + + if (std::find(generatorIds->begin(), generatorIds->end(), mcCollision.generatorsID()) == generatorIds->end()) { + continue; + } + + if (!acceptEvent(collision, true)) { + continue; + } // event is accepted + + histos.fill(HIST("eventQA/hRawGapSide"), collision.gapSide()); + + int selGapSide = collision.isUPC() ? getGapSide(collision) : -1; + int selGapSideNoNeutrons = selGapSide; + + auto groupedNeutrons = neutrons.sliceBy(neutronsPerMcCollision, mcCollision.globalIndex()); + if (checkNeutronsInMC) { + for (const auto& neutron : groupedNeutrons) { + if (selGapSide < -0.5) + break; + + const float eta = neutron.eta(); + switch (selGapSide) { + case 0: // SGA + if (eta > neutronEtaCut) + selGapSide = -1; + break; + case 1: // SGC + if (eta < -neutronEtaCut) + selGapSide = -1; + break; + case 2: // DG + if (eta > neutronEtaCut) + selGapSide = 1; + else if (eta < -neutronEtaCut) + selGapSide = 0; + break; + } + } + } + + if (evSels.studyUPConly && (selGapSide < -0.5)) + continue; + + histos.fill(HIST("eventQA/hSelGapSideNoNeutrons"), selGapSideNoNeutrons); + fillHistogramsQA(collision, selGapSide); + + histos.fill(HIST("eventQA/mc/hNTracksGlobalvsMCNParticlesEta08rec"), collision.multNTracksGlobal(), mcCollision.multMCNParticlesEta08()); + 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()); + + std::size_t nCascadesThisColl = cascadesGrouped[collision.globalIndex()].size(); + + for (std::size_t i = 0; i < nCascadesThisColl; i++) { + auto casc = fullCascades.rawIteratorAt(cascadesGrouped[collision.globalIndex()][i]); + 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, + NeutronsMC const& neutrons) + { + fillGenMCHistogramsQA(mcCollisions, collisions, neutrons); + std::vector listBestCollisionIds = getListOfRecoCollIds(mcCollisions, collisions, neutrons); + // 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 ((v0MC.pdgCode() == PDG_t::kLambda0) || (v0MC.pdgCode() == PDG_t::kLambda0Bar)) + ymc = v0MC.rapidityMC(1); + if (std::abs(ymc) > rapidityCut) + continue; + + const 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; + float ft0ampl = -1.f; + int nTracksGlobal = -1; + + if (listBestCollisionIds[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIds[mcCollision.globalIndex()]); + // centrality = collision.centFT0C(); + if (static_cast(upcCuts.genGapSide) == 0) { + ft0ampl = collision.totalFT0AmplitudeC(); + } else if (static_cast(upcCuts.genGapSide) == 1) { + ft0ampl = collision.totalFT0AmplitudeA(); + } + nTracksGlobal = collision.multNTracksGlobal(); + } + + const int pdgPos = v0MC.pdgCodePositive(); + const int pdgNeg = v0MC.pdgCodeNegative(); + const int pdgV0 = v0MC.pdgCode(); + + 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); + + // Fill histograms + if ((pdgV0 == PDG_t::kK0Short) && isPositivePion && isNegativePion) { + histos.fill(HIST(kParticlenames[0]) + HIST("/mc/h7dGen"), ft0ampl, nTracksGlobal, mcCollision.multMCNParticlesEta08(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if ((pdgV0 == PDG_t::kLambda0) && isPositiveProton && isNegativePion) { + histos.fill(HIST(kParticlenames[1]) + HIST("/mc/h7dGen"), ft0ampl, nTracksGlobal, mcCollision.multMCNParticlesEta08(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if ((pdgV0 == PDG_t::kLambda0Bar) && isPositivePion && isNegativeProton) { + histos.fill(HIST(kParticlenames[2]) + HIST("/mc/h7dGen"), ft0ampl, nTracksGlobal, mcCollision.multMCNParticlesEta08(), 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 ((cascMC.pdgCode() == PDG_t::kXiMinus) || (cascMC.pdgCode() == PDG_t::kXiPlusBar)) { + ymc = cascMC.rapidityMC(0); + } else if ((cascMC.pdgCode() == PDG_t::kOmegaMinus) || (cascMC.pdgCode() == PDG_t::kOmegaPlusBar)) { + ymc = cascMC.rapidityMC(2); + } + if (std::abs(ymc) > rapidityCut) + continue; + + const auto& mcCollision = cascMC.straMCCollision_as(); // take gen. collision + if (std::abs(mcCollision.posZ()) > maxZVtxPosition) + continue; + + // float centrality = -1.f; + float ft0ampl = -1.f; + int nTracksGlobal = -1; + + if (listBestCollisionIds[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIds[mcCollision.globalIndex()]); + // centrality = collision.centFT0C(); + if (static_cast(upcCuts.genGapSide) == 0) { + ft0ampl = collision.totalFT0AmplitudeC(); + } else if (static_cast(upcCuts.genGapSide) == 1) { + ft0ampl = collision.totalFT0AmplitudeA(); + } + } + + const int pdgPos = cascMC.pdgCodePositive(); + const int pdgNeg = cascMC.pdgCodeNegative(); + const int pdgBach = cascMC.pdgCodeBachelor(); + const int pdgCasc = cascMC.pdgCode(); + + 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); + + // Fill histograms + if ((pdgCasc == PDG_t::kXiMinus) && isPositiveProton && isNegativePion && isBachelorNegativePion) { + histos.fill(HIST(kParticlenames[3]) + HIST("/mc/h7dGen"), ft0ampl, nTracksGlobal, mcCollision.multMCNParticlesEta08(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if ((pdgCasc == PDG_t::kXiPlusBar) && isNegativeProton && isPositivePion && isBachelorPositivePion) { + histos.fill(HIST(kParticlenames[4]) + HIST("/mc/h7dGen"), ft0ampl, nTracksGlobal, mcCollision.multMCNParticlesEta08(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if ((pdgCasc == PDG_t::kOmegaMinus) && isPositiveProton && isNegativePion && isBachelorNegativeKaon) { + histos.fill(HIST(kParticlenames[5]) + HIST("/mc/h7dGen"), ft0ampl, nTracksGlobal, mcCollision.multMCNParticlesEta08(), pTmc, static_cast(upcCuts.genGapSide), ymc, mcCollision.generatorsID()); + } + if ((pdgCasc == PDG_t::kOmegaPlusBar) && isNegativeProton && isPositivePion && isBachelorPositiveKaon) { + histos.fill(HIST(kParticlenames[6]) + HIST("/mc/h7dGen"), ft0ampl, nTracksGlobal, mcCollision.multMCNParticlesEta08(), 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 320dbb91316..ed61b5d07bd 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,33 +21,39 @@ /// \author David Dobrigkeit Chinellato (david.dobrigkeit.chinellato@cern.ch) /// \author Zhongbao Yin (Zhong-Bao.Yin@cern.ch) -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/LFHStrangeCorrelationTables.h" + +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/Centrality.h" #include "Framework/StaticFor.h" -#include "CCDB/BasicCCDBManager.h" +#include "Framework/runDataProcessing.h" +#include + +#include + +#include +#include 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 V0DatasWithoutTrackX = soa::Join; +using V0DatasWithoutTrackXMC = soa::Join; -struct correlateStrangeness { +struct HStrangeCorrelation { // for efficiency corrections if requested Service ccdb; @@ -54,6 +61,16 @@ struct correlateStrangeness { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // event filtering + Configurable zorroMask{"zorroMask", "", "zorro trigger class to select on (empty: none)"}; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // master analysis switches + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + Configurable doFullCorrelationStudy{"doFullCorrelationStudy", true, "if true, do full correlation study by creating all THnSparse histograms for the correlation function"}; + 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"}; @@ -65,30 +82,61 @@ struct correlateStrangeness { 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 doAssocPhysicalPrimaryInGen{"doAssocPhysicalPrimaryInGen", false, "require physical primary for associated particles in Generated Partilces"}; 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 doMixingQAandEventQA{"doMixingQAandEventQA", true, "if true, add EvnetQA and MixingQA hist to histos"}; + Configurable doITSClustersQA{"doITSClustersQA", true, "if true, add ITSCluster hist to histos"}; + Configurable doDeltaPhiStarCheck{"doDeltaPhiStarCheck", false, "if true, create and fill delta phi star histograms"}; + + 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"}; + Configurable etaSel{"etaSel", 0.8, "Selection in eta for trigger and associated particles"}; + Configurable ySel{"ySel", 0.5, "Selection in rapidity for consistency checks"}; + + // used for event selections in Pb-Pb + Configurable cfgCutOccupancyHigh{"cfgCutOccupancyHigh", 3000, "High cut on TPC occupancy"}; + Configurable cfgCutOccupancyLow{"cfgCutOccupancyLow", 0, "Low cut on TPC occupancy"}; // 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 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"}; + struct : ConfigurableGroup { + 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, 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"}; + } axesConfigurations; + + // 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)"}; + Configurable nSigmaNearXiMassCenter{"nSigmaNearXiMassCenter", 1, "for Oemga analysis only, to check if candidate mass is around Xi"}; + } 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 applyEfficiencyForTrigger{"applyEfficiencyForTrigger", false, "apply efficiency correction for the trigger particle"}; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository to use"}; + struct : ConfigurableGroup { + Configurable applyEfficiencyCorrection{"applyEfficiencyCorrection", false, "apply efficiency correction"}; + Configurable applyEfficiencyForTrigger{"applyEfficiencyForTrigger", false, "apply efficiency correction for the trigger particle"}; + Configurable applyEfficiencyPropagation{"applyEfficiencyPropagation", false, "propagate also the efficiency uncertainty"}; + Configurable applyPurityHadron{"applyPurityHadron", false, "apply the purity correction for associated hadrons"}; + Configurable applyPurityTrigger{"applyPurityTrigger", false, "apply the purity correction for trigger particle"}; + Configurable applyEffAsFunctionOfMult{"applyEffAsFunctionOfMult", false, "apply efficiency as a function of multiplicity as well"}; + } efficiencyFlags; + 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 @@ -96,39 +144,80 @@ struct correlateStrangeness { struct : ConfigurableGroup { std::string prefix = "systematics"; // --- Track quality variations (single track, both trigger and assoc daughters) - Configurable minTPCNCrossedRows{"minTPCNCrossedRows", 70, "Minimum TPC crossed rows"}; + 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"}; + // Track quality in PbPb + Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; // --- 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 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 v0RadiusMin{"v0RadiusMin", 0.5, "v0radius"}; + Configurable v0RadiusMax{"v0RadiusMax", 200, "v0radius"}; + // more V0 selections in PbPb + Configurable lifetimecutK0S{"lifetimecutK0S", 20, "lifetimecutK0S"}; + Configurable lifetimecutLambda{"lifetimecutLambda", 30, "lifetimecutLambda"}; + Configurable dcanegtopvK0S{"dcanegtopvK0S", 0.1, "DCA Neg To PV"}; + Configurable dcapostopvK0S{"dcapostopvK0S", 0.1, "DCA Pos To PV"}; + Configurable dcanegtopvLambda{"dcanegtopvLambda", 0.05, "DCA Neg To PV"}; + Configurable dcapostopvLambda{"dcapostopvLambda", 0.2, "DCA Pos To PV"}; + Configurable dcanegtopvAntiLambda{"dcanegtopvAntiLambda", 0.2, "DCA Neg To PV"}; + Configurable dcapostopvAntiLambda{"dcapostopvAntiLambda", 0.05, "DCA Pos To PV"}; + // original equation: lArmPt*2>TMath::Abs(lArmAlpha) only for K0S + Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; // cascade selections - Configurable casc_cospa{"casc_cospa", 0.95, "casc_cospa"}; - Configurable casc_dcacascdau{"casc_dcacascdau", 1.0, "casc_dcacascdau"}; - Configurable casc_dcabachtopv{"casc_dcabachtopv", 0.1, "casc_dcabachtopv"}; - Configurable casc_cascradius{"casc_cascradius", 0.5, "casc_cascradius"}; - Configurable casc_v0masswindow{"casc_v0masswindow", 0.01, "casc_v0masswindow"}; - Configurable casc_mindcav0topv{"casc_mindcav0topv", 0.01, "casc_mindcav0topv"}; + 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"}; + // more cascade selections in PbPb + Configurable bachBaryonCosPA{"bachBaryonCosPA", 0.9999, "Bachelor baryon CosPA"}; + Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; + 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.07, "DCA Bach To PV"}; + Configurable cascdcaV0dau{"cascdcaV0dau", 0.5, "DCA V0 Daughters"}; + 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 cascdcaV0ToPV{"cascdcaV0ToPV", 0.06, "DCA V0 To PV"}; + Configurable cascv0cospa{"cascv0cospa", 0.98, "V0 CosPA"}; + Configurable cascv0RadiusMin{"cascv0RadiusMin", 2.5, "v0radius"}; + Configurable proplifetime{"proplifetime", 3, "ctau/"}; + Configurable lambdaMassWin{"lambdaMassWin", 0.005, "V0 Mass window limit"}; + Configurable rejcomp{"rejcomp", 0.008, "Competing Cascade rejection"}; + Configurable rapCut{"rapCut", 0.8, "Rapidity acceptance"}; // dE/dx for associated daughters - Configurable dEdxCompatibility{"dEdxCompatibility", 1, "0: loose, 1: normal, 2: tight. Defined in hStrangeCorrelationFilter"}; + Configurable dEdxCompatibility{"dEdxCompatibility", 1, "0: loose, 1: normal, 2: tight. Defined in HStrangeCorrelationFilter"}; + + // on the fly correction instead of mixingParameter + Configurable doOnTheFlyFlattening{"doOnTheFlyFlattening", 0, "enable an on-the-fly correction instead of using mixing"}; // (N.B.: sources that can be investigated in post are not listed!) } systCuts; // objects to use for efficiency corrections TH2F* hEfficiencyTrigger; + TH3F* hEfficiencyTriggerMult; TH2F* hEfficiencyPion; TH2F* hEfficiencyK0Short; TH2F* hEfficiencyLambda; @@ -137,39 +226,73 @@ struct correlateStrangeness { TH2F* hEfficiencyXiPlus; TH2F* hEfficiencyOmegaMinus; TH2F* hEfficiencyOmegaPlus; - - using BinningType = ColumnBinningPolicy; - BinningType colBinning{{axisVtxZ, axisMult}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. + TH2F* hEfficiencyHadron; + TH3F* hEfficiencyHadronMult; + TH1F* hPurityHadron; + TH2F* hPurityHadronMult; + // objects to propagate the efficiency uncertainty + TH2F* hEfficiencyUncertaintyTrigger; + TH3F* hEfficiencyUncertaintyTriggerMult; + TH2F* hEfficiencyUncertaintyPion; + TH2F* hEfficiencyUncertaintyK0Short; + TH2F* hEfficiencyUncertaintyLambda; + TH2F* hEfficiencyUncertaintyAntiLambda; + TH2F* hEfficiencyUncertaintyXiMinus; + TH2F* hEfficiencyUncertaintyXiPlus; + TH2F* hEfficiencyUncertaintyOmegaMinus; + TH2F* hEfficiencyUncertaintyOmegaPlus; + TH2F* hEfficiencyUncertaintyHadron; + TH3F* hEfficiencyUncertaintyHadronMult; + TH1F* hPurityUncertaintyHadron; + TH2F* hPurityUncertaintyHadronMult; + + using BinningTypePP = ColumnBinningPolicy; + using BinningTypePbPb = ColumnBinningPolicy; // collision slicing for mixed events 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 particlenames[] = {"Pion", "K0Short", "Lambda", "AntiLambda", "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; + const float ctauxiPDG = 4.91; // from PDG + const float ctauomegaPDG = 2.461; // from PDG + /// 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 @@ -190,6 +313,7 @@ struct correlateStrangeness { } hEfficiencyTrigger = static_cast(listEfficiencies->FindObject("hEfficiencyTrigger")); + hEfficiencyTriggerMult = static_cast(listEfficiencies->FindObject("hEfficiencyTriggerMult")); hEfficiencyK0Short = static_cast(listEfficiencies->FindObject("hEfficiencyK0Short")); hEfficiencyLambda = static_cast(listEfficiencies->FindObject("hEfficiencyLambda")); hEfficiencyAntiLambda = static_cast(listEfficiencies->FindObject("hEfficiencyAntiLambda")); @@ -197,40 +321,332 @@ struct correlateStrangeness { hEfficiencyXiPlus = static_cast(listEfficiencies->FindObject("hEfficiencyXiPlus")); hEfficiencyOmegaMinus = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinus")); hEfficiencyOmegaPlus = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlus")); + hEfficiencyHadron = static_cast(listEfficiencies->FindObject("hEfficiencyHadron")); + hEfficiencyHadronMult = static_cast(listEfficiencies->FindObject("hEfficiencyHadronMult")); + hEfficiencyPion = static_cast(listEfficiencies->FindObject("hEfficiencyPion")); + hPurityHadron = static_cast(listEfficiencies->FindObject("hPurityHadron")); + hPurityHadronMult = static_cast(listEfficiencies->FindObject("hPurityHadronMult")); + hEfficiencyUncertaintyTrigger = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTrigger")); + hEfficiencyUncertaintyTriggerMult = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTriggerMult")); + hEfficiencyUncertaintyK0Short = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyK0Short")); + hEfficiencyUncertaintyLambda = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyLambda")); + hEfficiencyUncertaintyAntiLambda = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyAntiLambda")); + hEfficiencyUncertaintyXiMinus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiMinus")); + hEfficiencyUncertaintyXiPlus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiPlus")); + hEfficiencyUncertaintyOmegaMinus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaMinus")); + hEfficiencyUncertaintyOmegaPlus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaPlus")); + hEfficiencyUncertaintyPion = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyPion")); + hEfficiencyUncertaintyHadron = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadron")); + hEfficiencyUncertaintyHadronMult = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadronMult")); + hPurityUncertaintyHadron = static_cast(listEfficiencies->FindObject("hPurityUncertaintyHadron")); + hPurityUncertaintyHadronMult = static_cast(listEfficiencies->FindObject("hPurityUncertaintyHadronMult")); + if (efficiencyFlags.applyEfficiencyPropagation && !hEfficiencyUncertaintyTrigger) + LOG(fatal) << "Problem getting hEfficiencyUncertaintyTrigger!"; LOG(info) << "Efficiencies now loaded for " << mRunNumber; } - void fillCorrelationsV0(aod::TriggerTracks const& triggers, aod::AssocV0s const& assocs, bool mixing, float pvz, float mult) + template + uint64_t V0selectionBitmap(TV0 v0, float pvx, float pvy, float pvz) + // precalculate this information so that a check is one mask operation, not many + { + uint64_t bitMap = 0; + // proper lifetime , DCA daughter to prim.vtx + if (doCorrelationK0Short) { + // proper lifetime + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassK0Short < systCuts.lifetimecutK0S) + SETBIT(bitMap, 0); + // DCA daughter to prim.vtx and armenteros + if (std::abs(v0.dcapostopv()) > systCuts.dcapostopvK0S && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvK0S && v0.qtarm() * systCuts.armPodCut > std::abs(v0.alpha())) + SETBIT(bitMap, 3); + } + if (doCorrelationLambda) { + // proper lifetime + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < systCuts.lifetimecutLambda) + SETBIT(bitMap, 1); + // DCA daughter to prim.vtx + if (std::abs(v0.dcapostopv()) > systCuts.dcapostopvLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvLambda) + SETBIT(bitMap, 4); + } + if (doCorrelationAntiLambda) { + // proper lifetime + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < systCuts.lifetimecutLambda) + SETBIT(bitMap, 2); + // DCA daughter to prim.vtx + if (std::abs(v0.dcapostopv()) > systCuts.dcapostopvAntiLambda && std::abs(v0.dcanegtopv()) > systCuts.dcanegtopvAntiLambda) + SETBIT(bitMap, 5); + } + return bitMap; + } + + template + uint64_t CascadeselectionBitmap(TCascade casc, float pvx, float pvy, float pvz) + { + uint64_t bitMap = 0; + float cascpos = std::hypot(casc.x() - pvx, casc.y() - pvy, casc.z() - pvz); + float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); + float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxiPDG); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomegaPDG); + // TPC PID and DCA daughter to prim.vtx and comopeting casc.rej and life time + if (doCorrelationXiMinus) { + // DCA daughter to prim.vtx + if (std::abs(casc.dcabachtopv()) > systCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > systCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > systCuts.dcaMesonToPV) + SETBIT(bitMap, 0); + // comopeting casc.rej + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > systCuts.rejcomp) + SETBIT(bitMap, 4); + if (ctauXi < systCuts.proplifetime) + SETBIT(bitMap, 8); + // y cut + if (std::abs(casc.yXi()) < systCuts.rapCut) + SETBIT(bitMap, 12); + } + if (doCorrelationXiPlus) { + // DCA daughter to prim.vtx + if (std::abs(casc.dcabachtopv()) > systCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > systCuts.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > systCuts.dcaBaryonToPV) + SETBIT(bitMap, 1); + // comopeting casc.rej + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > systCuts.rejcomp) + SETBIT(bitMap, 5); + // life time + if (ctauXi < systCuts.proplifetime) + SETBIT(bitMap, 9); + // y cut + if (std::abs(casc.yXi()) > systCuts.rapCut) + SETBIT(bitMap, 13); + } + if (doCorrelationOmegaMinus) { + // DCA daughter to prim.vtx + if (std::abs(casc.dcabachtopv()) > systCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > systCuts.dcaBaryonToPV && + std::abs(casc.dcanegtopv()) > systCuts.dcaMesonToPV) + SETBIT(bitMap, 2); + // comopeting casc.rej + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > systCuts.rejcomp) + SETBIT(bitMap, 6); + // life time + if (ctauOmega < systCuts.proplifetime) + SETBIT(bitMap, 10); + // y cut + if (std::abs(casc.yOmega()) < systCuts.rapCut) + SETBIT(bitMap, 14); + } + if (doCorrelationOmegaPlus) { + // DCA daughter to prim.vtx + if (std::abs(casc.dcabachtopv()) > systCuts.dcaBachToPV && std::abs(casc.dcapostopv()) > systCuts.dcaMesonToPV && + std::abs(casc.dcanegtopv()) > systCuts.dcaBaryonToPV) + SETBIT(bitMap, 3); + // comopeting casc.rej + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > systCuts.rejcomp) + SETBIT(bitMap, 7); + // life time + if (ctauOmega < systCuts.proplifetime) + SETBIT(bitMap, 11); + // y cut + if (std::abs(casc.yOmega()) > systCuts.rapCut) + SETBIT(bitMap, 15); + } + return bitMap; + } + + 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; + } + // V0selection in PbPb + template + bool V0SelectedPbPb(TV0 v0) + { + // v0radius + if (v0.v0radius() < systCuts.v0RadiusMin) + return false; + if (v0.v0radius() > systCuts.v0RadiusMax) + return false; + // v0cosPA + if (v0.v0cosPA() < systCuts.v0cospa) + return false; + // dcaV0daughters + if (v0.dcaV0daughters() > systCuts.dcaV0dau) + return false; + return true; + } + + // cascadeselection in PbPb + template + bool CascadeSelectedPbPb(TCascade casc, float pvx, float pvy, float pvz) + { + // bachBaryonCosPA + if (casc.bachBaryonCosPA() < systCuts.bachBaryonCosPA) + return false; + // bachBaryonDCAxyToPV + if (std::abs(casc.bachBaryonDCAxyToPV()) > systCuts.bachBaryonDCAxyToPV) + return false; + // casccosPA + if (casc.casccosPA(pvx, pvy, pvz) < systCuts.cascCospa) + return false; + // dcacascdaughters + float ptDepCut = systCuts.dcaCacsDauPar0; + if (casc.pt() > 1 && casc.pt() < 4) + ptDepCut = systCuts.dcaCacsDauPar1; + else if (casc.pt() > 4) + ptDepCut = systCuts.dcaCacsDauPar2; + if (casc.dcacascdaughters() > ptDepCut) + return false; + // dcaV0daughters + if (casc.dcaV0daughters() > systCuts.dcaV0dau) + return false; + // dcav0topv + if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < systCuts.cascdcaV0ToPV) + return false; + // cascradius + if (casc.cascradius() < systCuts.cascRadius) + return false; + // v0radius + if (casc.v0radius() < systCuts.cascv0RadiusMin) + return false; + // v0cosPA + if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < systCuts.cascv0cospa) + return false; + // lambdaMassWin + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > systCuts.lambdaMassWin) + return false; + return true; + } + double calculateAverageDeltaPhiStar(double* trigg, double* assoc, double B) + { + double dPhiStar = 0; + double dPhiStarMean = 0; + + double dPhi = assoc[0] - trigg[0]; + double phaseProton = (-0.3 * B * assoc[2]) / (2 * assoc[1]); + double phaseTrack = (-0.3 * B * trigg[2]) / (2 * trigg[1]); + + for (double r = 0.8; r <= 2.5; r += 0.05) { + dPhiStar = dPhi + std::asin(phaseProton * r) - std::asin(phaseTrack * r); + dPhiStarMean += (dPhiStar / 34); + } + + return dPhiStarMean; + } + void fillTriggerHistogram(std::shared_ptr hist, double pt, double mult, float eff, float effUncert, float purity, float purityErr) + { + int binx = hist->GetXaxis()->FindBin(pt); + int biny = hist->GetYaxis()->FindBin(mult); + float previousContent = hist->GetBinContent(binx, biny); + float previousUncert = hist->GetBinError(binx, biny); + float newContent = previousContent + purity / eff; + float newUncert = std::sqrt(previousUncert * previousUncert + std::pow(purity / eff, 2) + std::pow(purityErr / eff, 2) + std::pow(effUncert, 2) / std::pow(eff, 4)); + hist->SetBinContent(binx, biny, newContent); + hist->SetBinError(binx, biny, newUncert); + } + void fillCorrelationHistogram(std::shared_ptr hist, double binFillThn[], float etaWeight, float efficiency, float totalEffUncert, float purity, float totalPurityUncert) + { + float previousContent, previousError2, currentContent, currentError2; + int bin = hist->GetBin(binFillThn); + previousContent = hist->GetBinContent(bin); + previousError2 = hist->GetBinError2(bin); + currentContent = previousContent + etaWeight * purity / (efficiency); + currentError2 = previousError2 + std::pow(etaWeight * purity / (efficiency), 2) + std::pow(etaWeight * totalPurityUncert / (efficiency), 2) + std::pow(totalEffUncert * purity * etaWeight, 2) / std::pow(efficiency, 4); + hist->SetBinContent(bin, currentContent); + hist->SetBinError2(bin, currentError2); + } + void fillCorrelationsV0(aod::TriggerTracks const& triggers, aod::AssocV0s const& assocs, bool mixing, float pvx, float pvy, float pvz, float mult, double bField) { - for (auto& triggerTrack : triggers) { + for (auto const& triggerTrack : triggers) { if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) continue; auto trigg = triggerTrack.track_as(); - - // systematic variations: track quality - if (trigg.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) - continue; - if (!trigg.hasITS() && systCuts.triggerRequireITS) - continue; - if (trigg.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) - continue; - if (!(bitcheck(trigg.itsClusterMap(), 0)) && systCuts.triggerRequireL0) - continue; - // systematic variations: trigger DCAxy - if (std::abs(trigg.dcaXY()) < systCuts.dcaXYconstant + systCuts.dcaXYpTdep * std::abs(trigg.signed1Pt())) + if (!isValidTrigger(trigg)) continue; + float efficiencyTrigg = 1.0f; + float efficiencyTriggError = 0.0f; + float purityTrigg = 1.0f; + float purityTriggErr = 0.0; + if (!mixing) { + if (efficiencyFlags.applyEfficiencyForTrigger) { + efficiencyTrigg = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); + if (efficiencyFlags.applyPurityTrigger) + purityTrigg = hPurityHadron->Interpolate(trigg.pt()); + if (efficiencyFlags.applyEfficiencyPropagation) { + efficiencyTriggError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); + if (efficiencyFlags.applyPurityTrigger) + purityTriggErr = hPurityHadron->Interpolate(trigg.pt()); + } + if (efficiencyTrigg == 0) { // check for zero efficiency, do not apply if the case + efficiencyTrigg = 1; + efficiencyTriggError = 0; + } + } + fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesV0")), trigg.pt(), mult, efficiencyTrigg, efficiencyTriggError, purityTrigg, purityTriggErr); + } - if (!mixing) - histos.fill(HIST("sameEvent/TriggerParticlesV0"), trigg.pt(), mult); - for (auto& assocCandidate : assocs) { + double triggSign = trigg.sign(); + double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + + for (auto const& assocCandidate : assocs) { auto assoc = assocCandidate.v0Core_as(); //---] syst cuts [--- - if (assoc.v0radius() < systCuts.v0RadiusMin || assoc.v0radius() > systCuts.v0RadiusMax || - assoc.dcapostopv() > systCuts.dcapostopv || assoc.dcanegtopv() < systCuts.dcanegtopv || - assoc.v0cosPA() < systCuts.v0cospa) + if ((doPPAnalysis && (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; + + if (!doPPAnalysis && !V0SelectedPbPb(assoc)) continue; + uint64_t selMap = V0selectionBitmap(assoc, pvx, pvy, pvz); + //---] removing autocorrelations [--- auto postrack = assoc.posTrack_as(); auto negtrack = assoc.negTrack_as(); @@ -245,7 +661,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(); @@ -257,79 +677,198 @@ 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; + + TH2F* hEfficiencyUncertaintyV0[3]; + hEfficiencyUncertaintyV0[0] = hEfficiencyUncertaintyK0Short; + hEfficiencyUncertaintyV0[1] = hEfficiencyUncertaintyLambda; + hEfficiencyUncertaintyV0[2] = hEfficiencyUncertaintyAntiLambda; + + float etaWeight = 1; + if (systCuts.doOnTheFlyFlattening) { + float preWeight = 1 - std::abs(deltaeta) / 1.6; + etaWeight = preWeight != 0 ? 1.0f / preWeight : 1.0f; + } + + double phiProton = postrack.phi(); // in Case of K0, both are pions, but the one in proton tagged is the positive one + double phiPion = negtrack.phi(); + double etaProton = postrack.eta(); + double etaPion = negtrack.eta(); + double ptProton = postrack.pt(); + double ptPion = negtrack.pt(); + double signProton = postrack.sign(); + if (assocCandidate.compatible(2, systCuts.dEdxCompatibility)) { + phiProton = negtrack.phi(); + etaProton = negtrack.eta(); + ptProton = negtrack.pt(); + signProton = negtrack.sign(); + } + double assocForDeltaPhiStar[] = {phiProton, ptProton, signProton}; + double assocForDeltaPhiStarPion[] = {phiPion, ptPion, -1}; + static_for<0, 2>([&](auto i) { - constexpr int index = i.value; + constexpr int Index = i.value; float efficiency = 1.0f; - if (applyEfficiencyCorrection) { - efficiency = hEfficiencyV0[index]->Interpolate(ptassoc, assoc.eta()); + float totalEffUncert = 0.0; + float efficiencyError = 0.0f; + if (efficiencyFlags.applyEfficiencyCorrection) { + efficiency = hEfficiencyV0[Index]->Interpolate(ptassoc, assoc.eta()); + if (efficiencyFlags.applyEfficiencyPropagation) + efficiencyError = hEfficiencyUncertaintyV0[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; + efficiencyError = 0; } - float weight = (applyEfficiencyCorrection || applyEfficiencyForTrigger) ? 1. / efficiency : 1.0f; - if (bitcheck(doCorrelation, index) && (!applyEfficiencyCorrection || efficiency != 0)) { - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && assocCandidate.invMassRegionCheck(index, 1)) - histos.fill(HIST("sameEvent/LeftBg/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && assocCandidate.invMassRegionCheck(index, 2)) - histos.fill(HIST("sameEvent/Signal/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && assocCandidate.invMassRegionCheck(index, 3)) - histos.fill(HIST("sameEvent/RightBg/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && assocCandidate.invMassRegionCheck(index, 1)) - histos.fill(HIST("mixedEvent/LeftBg/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && assocCandidate.invMassRegionCheck(index, 2)) - histos.fill(HIST("mixedEvent/Signal/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && assocCandidate.invMassRegionCheck(index, 3)) - histos.fill(HIST("mixedEvent/RightBg/") + HIST(v0names[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (efficiencyFlags.applyEfficiencyPropagation) { + totalEffUncert = std::sqrt(std::pow(efficiencyTrigg * efficiencyError, 2) + std::pow(efficiencyTriggError * efficiency, 2)); + } + double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + if (TESTBIT(doCorrelation, Index) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (doPPAnalysis || (TESTBIT(selMap, Index) && TESTBIT(selMap, Index + 3)))) { + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(kV0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (doDeltaPhiStarCheck) { + double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); + double deltaPhiStarPion = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStarPion, bField); + if ((Index == 0 && triggSign > 0) || (Index == 1 && triggSign > 0) || (Index == 2 && triggSign < 0)) { + histos.fill(HIST("sameEvent/LeftBg/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); + if (Index == 0) { + histos.fill(HIST("sameEvent/LeftBg/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStarPion, trigg.eta() - etaPion, -0.5); + } + } else { + histos.fill(HIST("sameEvent/LeftBg/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + if (Index == 0) { + histos.fill(HIST("sameEvent/LeftBg/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStarPion, trigg.eta() - etaPion, 0.5); + } + } + } + } + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(kV0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (std::abs(deltaphi) < 0.8 && doITSClustersQA) { + 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 && doITSClustersQA) { + 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 (doDeltaPhiStarCheck) { + double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); + double deltaPhiStarPion = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStarPion, bField); + if ((Index == 0 && triggSign > 0) || (Index == 1 && triggSign > 0) || (Index == 2 && triggSign < 0)) { + histos.fill(HIST("sameEvent/Signal/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); + if (Index == 0) { + histos.fill(HIST("sameEvent/Signal/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStarPion, trigg.eta() - etaPion, -0.5); + } + } else { + histos.fill(HIST("sameEvent/Signal/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + if (Index == 0) { + histos.fill(HIST("sameEvent/Signal/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStarPion, trigg.eta() - etaPion, 0.5); + } + } + } + } + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/RightBg/") + HIST(kV0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (doDeltaPhiStarCheck) { + double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); + double deltaPhiStarPion = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStarPion, bField); + if ((Index == 0 && triggSign > 0) || (Index == 1 && triggSign > 0) || (Index == 2 && triggSign < 0)) { + histos.fill(HIST("sameEvent/RightBg/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); + if (Index == 0) { + histos.fill(HIST("sameEvent/RightBg/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStarPion, trigg.eta() - etaPion, -0.5); + } + } else { + histos.fill(HIST("sameEvent/RightBg/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + if (Index == 0) { + histos.fill(HIST("sameEvent/RightBg/") + HIST(kV0names[Index]) + HIST("DeltaPhiStar"), deltaPhiStarPion, trigg.eta() - etaPion, 0.5); + } + } + } + } + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) + fillCorrelationHistogram(histos.get(HIST("mixedEvent/LeftBg/") + HIST(kV0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(kV0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) + fillCorrelationHistogram(histos.get(HIST("mixedEvent/RightBg/") + HIST(kV0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); } }); } } } - void fillCorrelationsCascade(aod::TriggerTracks const& triggers, aod::AssocCascades const& assocs, bool mixing, float pvx, float pvy, float pvz, float mult) + void fillCorrelationsCascade(aod::TriggerTracks const& triggers, aod::AssocCascades const& assocs, bool mixing, float pvx, float pvy, float pvz, float mult, double bField) { - for (auto& triggerTrack : triggers) { + for (auto const& triggerTrack : triggers) { if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) continue; auto trigg = triggerTrack.track_as(); - - // systematic variations: track quality - if (trigg.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) - continue; - if (!trigg.hasITS() && systCuts.triggerRequireITS) - continue; - if (trigg.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) - continue; - if (!(bitcheck(trigg.itsClusterMap(), 0)) && systCuts.triggerRequireL0) - continue; - // systematic variations: trigger DCAxy - if (std::abs(trigg.dcaXY()) < systCuts.dcaXYconstant + systCuts.dcaXYpTdep * std::abs(trigg.signed1Pt())) + if (!isValidTrigger(trigg)) continue; - if (!mixing) - histos.fill(HIST("sameEvent/TriggerParticlesCascade"), trigg.pt(), mult); - for (auto& assocCandidate : assocs) { + float efficiencyTrigg = 1.0f; + float efficiencyTriggError = 0.0f; + float purityTrigg = 1.0f; + float purityTriggErr = 0.0f; + if (!mixing) { + if (efficiencyFlags.applyEfficiencyForTrigger) { + if (efficiencyFlags.applyEffAsFunctionOfMult) { + efficiencyTrigg = hEfficiencyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); + } else { + efficiencyTrigg = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); + } + if (efficiencyFlags.applyPurityTrigger) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + purityTrigg = hPurityHadronMult->Interpolate(trigg.pt(), mult); + else + purityTrigg = hPurityHadron->Interpolate(trigg.pt()); + } + if (efficiencyFlags.applyEfficiencyPropagation) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + efficiencyTriggError = hEfficiencyUncertaintyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); + else + efficiencyTriggError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); + if (efficiencyFlags.applyPurityTrigger) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + purityTriggErr = hPurityUncertaintyHadronMult->Interpolate(trigg.pt(), mult); + else + purityTriggErr = hPurityUncertaintyHadron->Interpolate(trigg.pt()); + } + } + if (efficiencyTrigg == 0) { // check for zero efficiency, do not apply if the case + efficiencyTrigg = 1; + efficiencyTriggError = 0; + } + } + fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesCascade")), trigg.pt(), mult, efficiencyTrigg, efficiencyTriggError, purityTrigg, purityTriggErr); + } + double triggSign = trigg.sign(); + double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + + for (auto const& assocCandidate : assocs) { auto assoc = assocCandidate.cascData(); //---] syst cuts [--- - if (assoc.dcapostopv() < systCuts.dcapostopv || - assoc.dcanegtopv() < systCuts.dcanegtopv || - assoc.dcabachtopv() < systCuts.casc_dcabachtopv || - assoc.dcaV0daughters() > systCuts.dcaV0dau || - assoc.dcacascdaughters() > systCuts.casc_dcacascdau || - assoc.v0cosPA(pvx, pvy, pvz) < systCuts.v0cospa || - assoc.casccosPA(pvx, pvy, pvz) < systCuts.casc_cospa || - assoc.cascradius() < systCuts.casc_cascradius || - std::abs(assoc.dcav0topv(pvx, pvy, pvz)) < systCuts.casc_mindcav0topv || - std::abs(assoc.mLambda() - pdgDB->Mass(3122)) > systCuts.casc_v0masswindow) + if (doPPAnalysis && (std::abs(assoc.dcapostopv()) < systCuts.dcapostopv || + std::abs(assoc.dcanegtopv()) < systCuts.dcanegtopv || + std::abs(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; - + if (!doPPAnalysis && !CascadeSelectedPbPb(assoc, pvx, pvy, pvz)) + continue; + uint64_t CascselMap = CascadeselectionBitmap(assoc, pvx, pvy, pvz); //---] removing autocorrelations [--- auto postrack = assoc.posTrack_as(); auto negtrack = assoc.negTrack_as(); @@ -348,8 +887,22 @@ struct correlateStrangeness { continue; } } + double phiProton = postrack.phi(); + double etaProton = postrack.eta(); + double ptProton = postrack.pt(); + double signProton = postrack.sign(); + if (assoc.sign() > 0) { + phiProton = negtrack.phi(); + etaProton = negtrack.eta(); + ptProton = negtrack.pt(); + signProton = negtrack.sign(); + } + double assocForDeltaPhiStar[] = {phiProton, ptProton, signProton}; + //---] 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 deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); float deltaeta = trigg.eta() - assoc.eta(); float ptassoc = assoc.pt(); float pttrigger = trigg.pt(); @@ -361,82 +914,170 @@ 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; hEfficiencyCascade[1] = hEfficiencyXiPlus; hEfficiencyCascade[2] = hEfficiencyOmegaMinus; hEfficiencyCascade[3] = hEfficiencyOmegaPlus; + TH2F* hEfficiencyUncertaintyCascade[4]; + hEfficiencyUncertaintyCascade[0] = hEfficiencyUncertaintyXiMinus; + hEfficiencyUncertaintyCascade[1] = hEfficiencyUncertaintyXiPlus; + hEfficiencyUncertaintyCascade[2] = hEfficiencyUncertaintyOmegaMinus; + hEfficiencyUncertaintyCascade[3] = hEfficiencyUncertaintyOmegaPlus; + + float etaWeight = 1; + if (systCuts.doOnTheFlyFlattening) { + float preWeight = 1 - std::abs(deltaeta) / 1.6; + etaWeight = preWeight != 0 ? 1.0f / preWeight : 1.0f; + } + static_for<0, 3>([&](auto i) { - constexpr int index = i.value; + constexpr int Index = i.value; float efficiency = 1.0f; - if (applyEfficiencyCorrection) { - efficiency = hEfficiencyCascade[index]->GetBinContent(hEfficiencyCascade[index]->GetXaxis()->FindBin(ptassoc), hEfficiencyCascade[index]->GetYaxis()->FindBin(assoc.eta())); + float totalEffUncert = 0.0; + float efficiencyError = 0.0f; + if (efficiencyFlags.applyEfficiencyCorrection) { + efficiency = hEfficiencyCascade[Index]->Interpolate(ptassoc, assoc.eta()); + if (efficiencyFlags.applyEfficiencyPropagation) + efficiencyError = hEfficiencyUncertaintyCascade[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; + efficiencyError = 0; } - float weight = (applyEfficiencyCorrection || applyEfficiencyForTrigger) ? 1. / efficiency : 1.0f; - if (bitcheck(doCorrelation, index + 3) && (!applyEfficiencyCorrection || efficiency != 0)) { - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && assocCandidate.invMassRegionCheck(index, 1)) - histos.fill(HIST("sameEvent/LeftBg/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && assocCandidate.invMassRegionCheck(index, 2)) - histos.fill(HIST("sameEvent/Signal/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && assocCandidate.invMassRegionCheck(index, 3)) - histos.fill(HIST("sameEvent/RightBg/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && assocCandidate.invMassRegionCheck(index, 1)) - histos.fill(HIST("mixedEvent/LeftBg/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && assocCandidate.invMassRegionCheck(index, 2)) - histos.fill(HIST("mixedEvent/Signal/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); - if (assocCandidate.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && assocCandidate.invMassRegionCheck(index, 3)) - histos.fill(HIST("mixedEvent/RightBg/") + HIST(cascadenames[index]), deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult, weight); + if (efficiencyFlags.applyEfficiencyPropagation) { + totalEffUncert = std::sqrt(std::pow(efficiencyTrigg * efficiencyError, 2) + std::pow(efficiencyTriggError * efficiency, 2)); + } + double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + if (TESTBIT(doCorrelation, Index + 3) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (doPPAnalysis || (TESTBIT(CascselMap, Index) && TESTBIT(CascselMap, Index + 4) && TESTBIT(CascselMap, Index + 8) && TESTBIT(CascselMap, Index + 12)))) { + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(kCascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (doDeltaPhiStarCheck) { + double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); + if ((Index == 0 && triggSign > 0) || (Index == 1 && triggSign < 0) || (Index == 2 && triggSign > 0) || (Index == 3 && triggSign < 0)) + histos.fill(HIST("sameEvent/LeftBg/") + HIST(kCascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); + else + histos.fill(HIST("sameEvent/LeftBg/") + HIST(kCascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } + } + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(kCascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (doDeltaPhiStarCheck) { + double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); + if ((Index == 0 && triggSign > 0) || (Index == 1 && triggSign < 0) || (Index == 2 && triggSign > 0) || (Index == 3 && triggSign < 0)) + histos.fill(HIST("sameEvent/Signal/") + HIST(kCascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); + else + histos.fill(HIST("sameEvent/Signal/") + HIST(kCascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } + } + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/RightBg/") + HIST(kCascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (doDeltaPhiStarCheck) { + double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); + if ((Index == 0 && triggSign > 0) || (Index == 1 && triggSign < 0) || (Index == 2 && triggSign > 0) || (Index == 3 && triggSign < 0)) + histos.fill(HIST("sameEvent/RightBg/") + HIST(kCascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); + else + histos.fill(HIST("sameEvent/RightBg/") + HIST(kCascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } + } + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) + fillCorrelationHistogram(histos.get(HIST("mixedEvent/LeftBg/") + HIST(kCascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(kCascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); + if (assocCandidate.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) + fillCorrelationHistogram(histos.get(HIST("mixedEvent/RightBg/") + HIST(kCascadenames[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); } }); } } } - - 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, double bField) { - for (auto& triggerTrack : triggers) { + for (auto const& triggerTrack : triggers) { if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) continue; - auto trigg = triggerTrack.track_as(); - - // systematic variations: track quality - if (trigg.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) - continue; - if (!trigg.hasITS() && systCuts.triggerRequireITS) - continue; - if (trigg.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) - continue; - if (!(bitcheck(trigg.itsClusterMap(), 0)) && systCuts.triggerRequireL0) - continue; - // systematic variations: trigger DCAxy - if (std::abs(trigg.dcaXY()) < systCuts.dcaXYconstant + systCuts.dcaXYpTdep * std::abs(trigg.signed1Pt())) + auto trigg = triggerTrack.template track_as(); + if (!isValidTrigger(trigg)) continue; - if (!mixing) - histos.fill(HIST("sameEvent/TriggerParticlesPion"), trigg.pt(), mult); - for (auto& assocTrack : assocs) { - auto assoc = assocTrack.track_as(); + float efficiencyTrigger = 1.0f; + float efficiencyTriggerError = 0.0f; + float purityTrigger = 1.0f; + float purityTriggerError = 0.0f; + if (!mixing) { + + if (efficiencyFlags.applyEfficiencyForTrigger) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + efficiencyTrigger = hEfficiencyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); + else + efficiencyTrigger = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); + if (efficiencyFlags.applyPurityTrigger) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + purityTrigger = hPurityHadronMult->Interpolate(trigg.pt(), mult); + else + purityTrigger = hPurityHadron->Interpolate(trigg.pt()); + } + if (efficiencyFlags.applyEfficiencyPropagation) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + efficiencyTriggerError = hEfficiencyUncertaintyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); + else + efficiencyTriggerError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); + if (efficiencyFlags.applyPurityTrigger) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + purityTriggerError = hPurityUncertaintyHadronMult->Interpolate(trigg.pt(), mult); + else + purityTriggerError = hPurityUncertaintyHadron->Interpolate(trigg.pt()); + } + } + if (efficiencyTrigger == 0) { // check for zero efficiency, do not apply if the case + efficiencyTrigger = 1; + efficiencyTriggerError = 0; + } + } + if constexpr (requires { triggerTrack.extra(); }) + fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesPion")), trigg.pt(), mult, efficiencyTrigger, efficiencyTriggerError, purityTrigger, purityTriggerError); + else + fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesHadron")), trigg.pt(), mult, efficiencyTrigger, efficiencyTriggerError, purityTrigger, purityTriggerError); + } + double triggSign = trigg.sign(); + double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + 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(); + double assocSign = assoc.sign(); + double assocForDeltaPhiStar[] = {assoc.phi(), assoc.pt(), assocSign}; + + float etaWeight = 1.; + if (systCuts.doOnTheFlyFlattening) { + float preWeight = 1 - std::abs(deltaeta) / 1.6; + etaWeight = preWeight != 0 ? 1.0f / preWeight : 1.0f; + } + // skip if basic ranges not met if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) continue; @@ -444,20 +1085,85 @@ 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; + float purity = 1.0f; + float purityUncertainty = 0.0f; + float totalEffUncert = 0.0; + float efficiencyUncertainty = 0.0f; + float totalPurityUncert = 0.0; + if (efficiencyFlags.applyEfficiencyCorrection) { + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { + efficiency = hEfficiencyPion->Interpolate(ptassoc, assoc.eta()); + if (efficiencyFlags.applyEfficiencyPropagation) + efficiencyUncertainty = hEfficiencyUncertaintyPion->Interpolate(ptassoc, assoc.eta()); + } else { + if (efficiencyFlags.applyEffAsFunctionOfMult) + efficiency = hEfficiencyHadronMult->Interpolate(ptassoc, assoc.eta(), mult); + else + efficiency = hEfficiencyHadron->Interpolate(ptassoc, assoc.eta()); + if (efficiencyFlags.applyPurityHadron) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + purity = hPurityHadronMult->Interpolate(ptassoc, mult); + else + purity = hPurityHadron->Interpolate(ptassoc); + } + if (efficiencyFlags.applyEfficiencyPropagation) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + efficiencyUncertainty = hEfficiencyUncertaintyHadronMult->Interpolate(ptassoc, assoc.eta(), mult); + else + efficiencyUncertainty = hEfficiencyUncertaintyHadron->Interpolate(ptassoc, assoc.eta()); + if (efficiencyFlags.applyPurityHadron) { + if (efficiencyFlags.applyEffAsFunctionOfMult) + purityUncertainty = hPurityUncertaintyHadronMult->Interpolate(ptassoc, mult); + else + purityUncertainty = hPurityUncertaintyHadron->Interpolate(ptassoc); + } + } + } + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + efficiencyUncertainty = 0.0; + } + if (efficiencyFlags.applyEfficiencyPropagation) { + totalEffUncert = std::sqrt(std::pow(efficiencyTrigger * efficiencyUncertainty, 2) + std::pow(efficiencyTriggerError * efficiency, 2)); + totalPurityUncert = std::sqrt(std::pow(purityTrigger * purityUncertainty, 2) + std::pow(purity * purityTriggerError, 2)); + } + double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); + if (!mixing) { + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/Pion")), binFillThn, etaWeight, efficiency * efficiencyTrigger, totalEffUncert, purity * purityTrigger, totalPurityUncert); + if (triggSign == assocSign && doDeltaPhiStarCheck) { + histos.fill(HIST("sameEvent/Signal/Pion") + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - assoc.eta(), 0.5); + } else if (doDeltaPhiStarCheck) { + histos.fill(HIST("sameEvent/Signal/Pion") + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - assoc.eta(), -0.5); + } + } else { + if (triggSign == assocSign && doDeltaPhiStarCheck) { + histos.fill(HIST("sameEvent/Signal/Hadron") + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - assoc.eta(), 0.5); + } else if (doDeltaPhiStarCheck) { + histos.fill(HIST("sameEvent/Signal/Hadron") + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - assoc.eta(), -0.5); + } + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/Hadron")), binFillThn, etaWeight, efficiency * efficiencyTrigger, totalEffUncert, purity * purityTrigger, totalPurityUncert); + } + } else { + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/Pion")), binFillThn, 1, efficiency * efficiencyTrigger, totalEffUncert, purity * purityTrigger, totalPurityUncert); + } else { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/Hadron")), binFillThn, 1, efficiency * efficiencyTrigger, totalEffUncert, purity * purityTrigger, totalPurityUncert); + } + } } } } void init(InitContext const&) { + zorroSummary.setObject(zorro.getZorroSummary()); mRunNumber = 0; + mRunNumberZorro = 0; hEfficiencyPion = 0x0; hEfficiencyK0Short = 0x0; hEfficiencyLambda = 0x0; @@ -466,25 +1172,41 @@ struct correlateStrangeness { hEfficiencyXiPlus = 0x0; hEfficiencyOmegaMinus = 0x0; hEfficiencyOmegaPlus = 0x0; + hEfficiencyUncertaintyTrigger = 0x0; + hEfficiencyUncertaintyXiMinus = 0x0; + hEfficiencyUncertaintyXiPlus = 0x0; + hEfficiencyUncertaintyOmegaMinus = 0x0; + hEfficiencyUncertaintyOmegaPlus = 0x0; + hEfficiencyUncertaintyPion = 0x0; + hEfficiencyUncertaintyK0Short = 0x0; + hEfficiencyUncertaintyLambda = 0x0; + hEfficiencyUncertaintyAntiLambda = 0x0; + + hEfficiencyHadron = 0x0; + hPurityHadron = 0x0; + hPurityUncertaintyHadron = 0x0; + hEfficiencyUncertaintyHadron = 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: @@ -495,12 +1217,14 @@ struct correlateStrangeness { // --- multiplicity -> check // grab axis edge from ConfigurableAxes - const AxisSpec preAxisDeltaPhi{axisDeltaPhi, "#Delta#varphi"}; - const AxisSpec preAxisDeltaEta{axisDeltaEta, "#Delta#eta"}; - const AxisSpec preAxisPtAssoc{axisPtAssoc, "#it{p}_{T}^{assoc} (GeV/c)"}; - 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 preAxisDeltaPhi{axesConfigurations.axisDeltaPhi, "#Delta#varphi"}; + const AxisSpec preAxisDeltaEta{axesConfigurations.axisDeltaEta, "#Delta#eta"}; + const AxisSpec preAxisPtAssoc{axesConfigurations.axisPtAssoc, "#it{p}_{T}^{assoc} (GeV/c)"}; + const AxisSpec preAxisPtTrigger{axesConfigurations.axisPtTrigger, "#it{p}_{T}^{trigger} (GeV/c)"}; + const AxisSpec preAxisVtxZ{axesConfigurations.axisVtxZ, "vertex Z (cm)"}; + const AxisSpec preAxisMult{axesConfigurations.axisMult, "mult percentile"}; + const AxisSpec axisPtLambda{axesConfigurations.axisPtAssoc, "#it{p}_{T}^{#Lambda} (GeV/c)"}; + const AxisSpec axisPtCascade{axesConfigurations.axisPtAssoc, "#it{p}_{T}^{Mother} (GeV/c)"}; // store the original axes in specific TH1Cs for completeness histos.add("axes/hDeltaPhiAxis", "", kTH1C, {preAxisDeltaPhi}); @@ -635,151 +1359,169 @@ struct correlateStrangeness { const AxisSpec axisPtTriggerNDim{edgesPtTrigger, "#it{p}_{T}^{trigger} (GeV/c)"}; 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("sameEvent/Signal/K0Short", "K0Short", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (!doPPAnalysis) { + // event selections in Pb-Pb + histos.add("hEventSelection", "hEventSelection", kTH1F, {{10, 0, 10}}); + TString eventSelLabel[] = {"all", "sel8", "kIsTriggerTVX", "PV_{z}", "kIsGoodITSLayersAll", "kIsGoodZvtxFT0vsPV", "OccupCut", "kNoITSROFrameBorder", "kNoSameBunchPileup ", " kNoCollInTimeRangeStandard"}; + for (int i = 1; i <= histos.get(HIST("hEventSelection"))->GetNbinsX(); i++) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabel[i - 1]); + } } - 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("sameEvent/Signal/Lambda", "Lambda", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + // Some QA plots + if (doprocessMCGenerated) { + histos.add("hGeneratedQAPtTrigger", "hGeneratedQAPtTrigger", kTH2F, {axesConfigurations.axisPtQA, {5, -0.5f, 4.5f}}); + histos.add("hGeneratedQAPtAssociatedK0", "hGeneratedQAPtAssociatedK0", kTH2F, {axesConfigurations.axisPtQA, {5, -0.5f, 4.5f}}); } - 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("sameEvent/Signal/AntiLambda", "AntiLambda", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (doprocessClosureTest) { + histos.add("hClosureQAPtTrigger", "hClosureQAPtTrigger", kTH2F, {axesConfigurations.axisPtQA, {5, -0.5f, 4.5f}}); + histos.add("hClosureQAPtAssociatedK0", "hClosureQAPtAssociatedK0", kTH2F, {axesConfigurations.axisPtQA, {5, -0.5f, 4.5f}}); } - 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("sameEvent/Signal/XiMinus", "XiMinus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (doprocessMCGenerated || doprocessClosureTest) { + histos.add("hClosureTestEventCounter", "hClosureTestEventCounter", kTH1F, {{10, 0, 10}}); } - 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("sameEvent/Signal/XiPlus", "XiPlus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (doprocessSameEventHV0s || doprocessSameEventHCascades || doprocessSameEventHPions || doprocessSameEventHHadrons) { + histos.add("hTriggerAllSelectedEtaVsPt", "hTriggerAllSelectedEtaVsPt", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("hPositiveTriggerPrimaryEtaVsPt", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("hNegativeTriggerPrimaryEtaVsPt", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + // QA and THn Histograms + histos.add("hTriggerPtResolution", ";p_{T}^{reconstructed} (GeV/c); p_{T}^{generated} (GeV/c)", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisPtQA}); + histos.add("hTriggerPrimaryEtaVsPt", "hTriggerPrimaryEtaVsPt", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("hTrackEtaVsPtVsPhi", "hTrackEtaVsPtVsPhi", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + histos.add("hAssocTrackEtaVsPtVsPhi", "hAssocTrackEtaVsPtVsPhi", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + // histos.add("hTrackAttempt", "Attempt", kTH3F, {axisPtQA, axisEta, axisPhi}); } - 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("sameEvent/Signal/OmegaMinus", "OmegaMinus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (doprocessSameEventHPions || doprocessSameEventHHadrons || doprocessMixedEventHPions || doprocessMixedEventHHadrons) { + histos.add("hNumberOfRejectedPairsHadron", "hNumberOfRejectedPairsHadron", kTH1F, {{1, 0, 1}}); + histos.add("hNumberOfRejectedPairsPion", "hNumberOfRejectedPairsPion", kTH1F, {{1, 0, 1}}); } - 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("sameEvent/Signal/OmegaPlus", "OmegaPlus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (doprocessSameEventHV0s || doprocessMixedEventHV0s) { + histos.add("hNumberOfRejectedPairsV0", "hNumberOfRejectedPairsV0", kTH1F, {{1, 0, 1}}); } - if (bitcheck(doCorrelation, 7)) { - histos.add("sameEvent/Pion", "Pion", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (doprocessSameEventHCascades || doprocessMixedEventHCascades) { + histos.add("hNumberOfRejectedPairsCascades", "hNumberOfRejectedPairsCascades", kTH1F, {{1, 0, 1}}); } - LOGF(info, "Init THnFs done"); - if (doCorrelationK0Short || doCorrelationLambda || doCorrelationAntiLambda || doCorrelationXiMinus || doCorrelationXiPlus || doCorrelationOmegaMinus || doCorrelationOmegaPlus) { + + if (doMixingQAandEventQA) { + // mixing QA + histos.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{140, -0.5, 139.5}}); + histos.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{140, -0.5, 139.5}}); + histos.add("MixingQA/hMEpvz1", ";pvz;Entries", kTH1F, {{30, -15, 15}}); + histos.add("MixingQA/hMEpvz2", ";pvz;Entries", kTH1F, {{30, -15, 15}}); + + // Event QA + histos.add("EventQA/hMixingQA", "mixing QA", kTH1F, {{2, -0.5, 1.5}}); + histos.add("EventQA/hMult", "Multiplicity", kTH1F, {axesConfigurations.axisMult}); + histos.add("EventQA/hPvz", ";pvz;Entries", kTH1F, {{30, -15, 15}}); + histos.add("EventQA/hMultFT0vsTPC", ";centFT0M;multNTracksPVeta1", kTH2F, {{100, 0, 100}, {300, 0, 300}}); + } + + bool hStrange = false; + for (int i = 0; i < 9; i++) { + if (TESTBIT(doCorrelation, i)) { + if (doFullCorrelationStudy) + histos.add(fmt::format("sameEvent/Signal/{}", kParticlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + if (doDeltaPhiStarCheck && doFullCorrelationStudy) { + histos.add(fmt::format("sameEvent/Signal/{}DeltaPhiStar", kParticlenames[i]).c_str(), "", kTH3F, {{100, -0.3, 0.3}, {50, -0.05, 0.05}, {2, -1, 1}}); // -1 oposite charge, 1 same charge + } + if (i < 7) { + histos.add(fmt::format("h{}EtaVsPtVsPhi", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + histos.add(fmt::format("h3d{}Spectrum", kParticlenames[i]).c_str(), fmt::format("h3d{}Spectrum", kParticlenames[i]).c_str(), kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult, axesConfigurations.axisMassNSigma}); + histos.add(fmt::format("h3d{}SpectrumY", kParticlenames[i]).c_str(), fmt::format("h3d{}SpectrumY", kParticlenames[i]).c_str(), kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult, axesConfigurations.axisMassNSigma}); + hStrange = true; + histos.add(fmt::format("h{}EtaVsPtVsPhiBg", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + if (doITSClustersQA) { + histos.add(fmt::format("hITSClusters{}NegativeDaughterToward", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtAssoc, {8, -0.5, 7.5}, {20, 0, 10}}); + histos.add(fmt::format("hITSClusters{}PositiveDaughterToward", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtAssoc, {8, -0.5, 7.5}, {20, 0, 10}}); + histos.add(fmt::format("hITSClusters{}NegativeDaughterTransverse", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtAssoc, {8, -0.5, 7.5}, {20, 0, 10}}); + histos.add(fmt::format("hITSClusters{}PositiveDaughterTransverse", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtAssoc, {8, -0.5, 7.5}, {20, 0, 10}}); + } + } + } + } + if (TESTBIT(doCorrelation, 7)) { + histos.add("hPionEtaVsPtAllSelected", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("hPionEtaVsPt", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("hPositivePionEtaVsPt", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("hNegativePionEtaVsPt", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + } + if (TESTBIT(doCorrelation, 8)) { + histos.add("hAsssocTrackEtaVsPtVsPhi", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + histos.add("hAssocPrimaryEtaVsPt", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("hAssocHadronsAllSelectedEtaVsPt", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("hAssocPtResolution", ";p_{T}^{reconstructed} (GeV/c); p_{T}^{generated} (GeV/c)", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisPtQA}); + } + + if (hStrange && doFullCorrelationStudy) { 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) { + if ((doprocessMixedEventHV0s || doprocessMixedEventHCascades || doprocessMixedEventHPions || doprocessMixedEventHHadrons) && doFullCorrelationStudy) { histos.addClone("sameEvent/", "mixedEvent/"); } - - // Some QA plots - histos.add("hTrackEtaVsPtVsPhi", "hTrackEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hK0ShortEtaVsPtVsPhi", "hK0ShortEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hK0ShortEtaVsPtVsPhiBg", "hK0ShortEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hLambdaEtaVsPtVsPhi", "hLambdaEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hLambdaEtaVsPtVsPhiBg", "hLambdaEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hAntiLambdaEtaVsPtVsPhi", "hAntiLambdaEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hAntiLambdaEtaVsPtVsPhiBg", "hAntiLambdaEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hXiMinusEtaVsPtVsPhi", "hXiMinusEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hXiMinusEtaVsPtVsPhiBg", "hXiMinusEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hXiPlusEtaVsPtVsPhi", "hXiPlusEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hXiPlusEtaVsPtVsPhiBg", "hXiPlusEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hOmegaMinusEtaVsPtVsPhi", "hOmegaMinusEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hOmegaMinusEtaVsPtVsPhiBg", "hOmegaMinusEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hOmegaPlusEtaVsPtVsPhi", "hOmegaPlusEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hOmegaPlusEtaVsPtVsPhiBg", "hOmegaPlusEtaVsPtVsPhiBg", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hPionEtaVsPtVsPhi", "hPionEtaVsPtVsPhi", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("hTriggerPrimaryEtaVsPt", "hTriggerPrimaryEtaVsPt", kTH3F, {axisPtQA, axisEta, axisMult}); - histos.add("hTriggerAllSelectedEtaVsPt", "hTriggerAllSelectedEtaVsPt", kTH3F, {axisPtQA, axisEta, axisMult}); - - 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}); - - // mixing QA - histos.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{140, -0.5, 139.5}}); - histos.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{140, -0.5, 139.5}}); - histos.add("MixingQA/hMEpvz1", ";pvz;Entries", kTH1F, {{30, -15, 15}}); - histos.add("MixingQA/hMEpvz2", ";pvz;Entries", kTH1F, {{30, -15, 15}}); - - // Event QA - 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}}); + if (doprocessSameEventHHadrons && doFullCorrelationStudy) + histos.add("sameEvent/TriggerParticlesHadron", "TriggersHadron", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); + if (doprocessSameEventHV0s && doFullCorrelationStudy) + histos.add("sameEvent/TriggerParticlesV0", "TriggersV0", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); + if (doprocessSameEventHCascades && doFullCorrelationStudy) + histos.add("sameEvent/TriggerParticlesCascade", "TriggersCascade", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); + if (doprocessSameEventHPions && doFullCorrelationStudy) + histos.add("sameEvent/TriggerParticlesPion", "TriggersPion", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); // MC generated plots if (doprocessMCGenerated) { - histos.add("Generated/hTrigger", "", kTH2F, {axisPtQA, axisEta}); - 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", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("Generated/hPositiveTrigger", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add("Generated/hNegativeTrigger", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + for (int i = 0; i < 9; i++) { + histos.add(fmt::format("Generated/h{}", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + if (i == 7) { + histos.add(fmt::format("Generated/hPositive{}", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + histos.add(fmt::format("Generated/hNegative{}", kParticlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); + } + } 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, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); + histos.add(fmt::format("GeneratedWithPV/h{}_MidYVsMult_TwoPVsOrMore", kParticlenames[i]).c_str(), "", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); + } } if (doprocessClosureTest) { - histos.add("ClosureTest/sameEvent/Pion", "Pion", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMult}); - histos.add("ClosureTest/sameEvent/K0Short", "K0Short", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMult}); - histos.add("ClosureTest/sameEvent/Lambda", "Lambda", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMult}); - histos.add("ClosureTest/sameEvent/AntiLambda", "AntiLambda", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMult}); - histos.add("ClosureTest/sameEvent/XiMinus", "XiMinus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMult}); - histos.add("ClosureTest/sameEvent/XiPlus", "XiPlus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMult}); - histos.add("ClosureTest/sameEvent/OmegaMinus", "OmegaMinus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMult}); - histos.add("ClosureTest/sameEvent/OmegaPlus", "OmegaPlus", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMult}); - histos.add("ClosureTest/hTrigger", "Trigger Tracks", kTH3F, {axisPtQA, axisEta, axisMult}); - histos.add("ClosureTest/hPion", "", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("ClosureTest/hK0Short", "", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("ClosureTest/hLambda", "", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("ClosureTest/hAntiLambda", "", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("ClosureTest/hXiMinus", "", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("ClosureTest/hXiPlus", "", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("ClosureTest/hOmegaMinus", "", kTH3F, {axisPtQA, axisEta, axisPhi}); - histos.add("ClosureTest/hOmegaPlus", "", kTH3F, {axisPtQA, axisEta, axisPhi}); + for (int i = 0; i < 9; 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, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + } + histos.add("ClosureTest/hTrigger", "Trigger Tracks", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.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}); + histos.add("hLambdaFromXiMinusEtaVsPtVsPhi", "hLambdaFromXiMinusEtaVsPtVsPhi", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + histos.add("hLambdaFromXiZeroEtaVsPtVsPhi", "hLambdaFromXiZeroEtaVsPtVsPhi", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + histos.add("hAntiLambdaFromXiPlusEtaVsPtVsPhi", "hAntiLambdaFromXiPlusEtaVsPtVsPhi", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + histos.add("hAntiLambdaFromXiZeroEtaVsPtVsPhi", "hAntiLambdaFromXiZeroEtaVsPtVsPhi", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + histos.add("GeneratedWithPV/hLambdaFromXiZero", "", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta}); + histos.add("GeneratedWithPV/hLambdaFromXiMinus", "", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta}); + histos.add("GeneratedWithPV/hAntiLambdaFromXiZero", "", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta}); + histos.add("GeneratedWithPV/hAntiLambdaFromXiPlus", "", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta}); } + + // visual inspection of sizes + histos.print(); + // initialize CCDB *only* if efficiency correction requested // skip if not requested, saves a bit of time - if (applyEfficiencyCorrection) { + if (efficiencyFlags.applyEfficiencyCorrection) { ccdb->setURL(ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -787,127 +1529,391 @@ struct correlateStrangeness { } } - void processSameEventHV0s(soa::Join::iterator const& collision, - aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, - V0DatasWithoutTrackX const&, aod::V0sLinked const&, TracksComplete const&, aod::BCsWithTimestamps 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; + return false; } - if (TMath::Abs(collision.posZ()) > zVertexCut) { - return; + if (std::abs(collision.posZ()) > zVertexCut) { + return false; } if (collision.centFT0M() > axisRanges[5][1] || collision.centFT0M() < axisRanges[5][0]) { - return; + return false; } if (!collision.isInelGt0() && selectINELgtZERO) { - return; + return false; } - // ________________________________________________ - if (!doprocessSameEventHCascades) { - 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()); + if (!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) && requireAllGoodITSLayers) { + return false; } - // Do basic QA + 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 (applyEfficiencyCorrection) { - auto bc = collision.bc_as(); - initEfficiencyFromCCDB(bc); + // event selections in Pb-Pb + template + bool isCollisionSelectedPbPb(TCollision collision, bool fillHists) + { + if (fillHists) + histos.fill(HIST("hEventSelection"), 0.5 /* all collisions */); + + // Perform basic event selection + if (!collision.sel8()) { + return false; } - TH2F* hEfficiencyV0[3]; - hEfficiencyV0[0] = hEfficiencyK0Short; - hEfficiencyV0[1] = hEfficiencyLambda; - hEfficiencyV0[2] = hEfficiencyAntiLambda; + if (fillHists) + histos.fill(HIST("hEventSelection"), 1.5 /* collisions after sel8*/); - for (auto const& v0 : associatedV0s) { - auto v0Data = v0.v0Core_as(); + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 2.5 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); - //---] syst cuts [--- - if (v0Data.v0radius() < systCuts.v0RadiusMin || v0Data.v0radius() > systCuts.v0RadiusMax || - v0Data.dcapostopv() > systCuts.dcapostopv || v0Data.dcanegtopv() < systCuts.dcanegtopv || - v0Data.v0cosPA() < systCuts.v0cospa) - continue; + if (std::abs(collision.posZ()) > zVertexCut) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 3.5 /* collisions after sel pvz sel*/); - static_for<0, 2>([&](auto i) { - constexpr int index = i.value; - float efficiency = 1.0f; - if (applyEfficiencyCorrection) { - efficiency = hEfficiencyV0[index]->Interpolate(v0Data.pt(), v0Data.eta()); - } - float weight = applyEfficiencyCorrection ? 1. / efficiency : 1.0f; - if (v0.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || v0.mcTrue(index)) && (!doAssocPhysicalPrimary || v0.mcPhysicalPrimary()) && (!applyEfficiencyCorrection || efficiency != 0)) { - if (v0.invMassRegionCheck(index, 2)) - histos.fill(HIST("h") + HIST(v0names[index]) + HIST("EtaVsPtVsPhi"), v0Data.pt(), v0Data.eta(), v0Data.phi(), weight); - if (v0.invMassRegionCheck(index, 1) || v0.invMassRegionCheck(index, 3)) - histos.fill(HIST("h") + HIST(v0names[index]) + HIST("EtaVsPtVsPhiBg"), v0Data.pt(), v0Data.eta(), v0Data.phi(), weight); - if (bitcheck(doCorrelation, index)) { - 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); - } - } - } - }); + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + // cut time intervals with dead ITS staves + return false; } - if (!doprocessSameEventHCascades) { - for (auto const& triggerTrack : triggerTracks) { - auto track = triggerTrack.track_as(); + if (fillHists) + histos.fill(HIST("hEventSelection"), 4.5 /* collisions after cut time intervals with dead ITS staves*/); - // systematic variations: track quality - if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) - continue; - if (!track.hasITS() && systCuts.triggerRequireITS) - continue; - if (track.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) - continue; - if (!(bitcheck(track.itsClusterMap(), 0)) && systCuts.triggerRequireL0) - continue; - // systematic variations: trigger DCAxy - if (std::abs(track.dcaXY()) < systCuts.dcaXYconstant + systCuts.dcaXYpTdep * std::abs(track.signed1Pt())) - continue; + 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 (fillHists) + histos.fill(HIST("hEventSelection"), 5.5 /* removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference*/); + + auto occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) + return false; + if (fillHists) + histos.fill(HIST("hEventSelection"), 6.5 /* Below min occupancy and Above max occupancy*/); + + /* + if (collision.alias_bit(kTVXinTRD)) { + // TRD triggered + return false; + } + */ - histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); - 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()); - } + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + // reject collisions close to Time Frame borders + // O2-4623 + return false; } + if (fillHists) + histos.fill(HIST("hEventSelection"), 7.5 /* reject collisions close to Time Frame borders*/); - // ________________________________________________ - // Do hadron - V0 correlations - fillCorrelationsV0(triggerTracks, associatedV0s, false, collision.posZ(), collision.centFT0M()); + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + // reject events affected by the ITS ROF border + // O2-4309 + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 8.5 /* reject events affected by the ITS ROF border*/); + + 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 (fillHists) + histos.fill(HIST("hEventSelection"), 9.5 /* rejects collisions which are associated with the same "found-by-T0" bunch crossing*/); + return true; } - 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&, aod::BCsWithTimestamps const&) + 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 + } + // 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&) + { + BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. + + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(triggerPresenceMap[collision.globalIndex()], triggerBinToSelect)) { + return; + } + + auto bc = collision.bc_as(); + auto bField = getMagneticField(bc.timestamp()); + + if (efficiencyFlags.applyEfficiencyCorrection) { + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ // Perform basic event selection - if (!collision.sel8()) { + if (!isCollisionSelected(collision)) { return; } - if (TMath::Abs(collision.posZ()) > zVertexCut) { + // ________________________________________________ + if (!doprocessSameEventHCascades && !doprocessSameEventHV0s && !doprocessSameEventHPions && doMixingQAandEventQA) { + 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 + if (!doprocessSameEventHCascades && !doprocessSameEventHV0s && !doprocessSameEventHPions) { + for (auto const& triggerTrack : triggerTracks) { + auto track = triggerTrack.track_as(); + if (!isValidTrigger(track)) + continue; + float efficiency = 1.0f; + if (efficiencyFlags.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 = efficiencyFlags.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; + float purity = 1.0f; + if (efficiencyFlags.applyEfficiencyCorrection) { + efficiency = hEfficiencyHadron->Interpolate(assoc.pt(), assoc.eta()); + if (efficiencyFlags.applyPurityHadron) + purity = hPurityHadron->Interpolate(assoc.pt()); + } + if (efficiency == 0) { // check for zero efficiency, do not apply if the case + efficiency = 1; + } + float weight = efficiencyFlags.applyEfficiencyCorrection ? purity / efficiency : 1.0f; + histos.fill(HIST("hAssocHadronsAllSelectedEtaVsPt"), assoc.pt(), assoc.eta(), collision.centFT0M(), weight); + 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 + if (doFullCorrelationStudy) + fillCorrelationsHadron(triggerTracks, assocHadrons, false, collision.posZ(), collision.centFT0M(), bField); + } + + void processSameEventHV0s(soa::Join::iterator const& collision, + aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, + V0DatasWithoutTrackX const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + std::variant colBinning = + doPPAnalysis + ? std::variant{ + BinningTypePP{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}} + : std::variant{BinningTypePbPb{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}}; + + double cent = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + // ________________________________________________ + // 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 (((doPPAnalysis && !isCollisionSelected(collision))) || (!doPPAnalysis && !isCollisionSelectedPbPb(collision, true))) { return; } - if (!collision.isInelGt0() && selectINELgtZERO) { + // ________________________________________________ + if (!doprocessSameEventHCascades && doMixingQAandEventQA) { + std::visit([&](auto const& binning) { + histos.fill(HIST("MixingQA/hSECollisionBins"), binning.getBin({collision.posZ(), cent})); + }, + colBinning); + histos.fill(HIST("EventQA/hMult"), cent); + histos.fill(HIST("EventQA/hPvz"), collision.posZ()); + histos.fill(HIST("EventQA/hMultFT0vsTPC"), cent, collision.multNTracksPVeta1()); + } + // Do basic QA + auto bc = collision.bc_as(); + auto bField = getMagneticField(bc.timestamp()); + if (efficiencyFlags.applyEfficiencyCorrection) { + initEfficiencyFromCCDB(bc); + } + TH2F* hEfficiencyV0[3]; + hEfficiencyV0[0] = hEfficiencyK0Short; + hEfficiencyV0[1] = hEfficiencyLambda; + hEfficiencyV0[2] = hEfficiencyAntiLambda; + + 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 (doPPAnalysis && (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 (!doPPAnalysis && !V0SelectedPbPb(v0Data)) + continue; + uint64_t selMap = V0selectionBitmap(v0Data, collision.posX(), collision.posY(), collision.posZ()); + + static_for<0, 2>([&](auto i) { + constexpr int Index = i.value; + float efficiency = 1.0f; + if (efficiencyFlags.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 = efficiencyFlags.applyEfficiencyCorrection ? 1. / efficiency : 1.0f; + if (v0.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || v0.mcTrue(Index)) && (!doAssocPhysicalPrimary || v0.mcPhysicalPrimary()) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0)) { + if ((TESTBIT(doCorrelation, Index)) && (doPPAnalysis || (TESTBIT(selMap, Index) && TESTBIT(selMap, Index + 3)))) { + histos.fill(HIST("h3d") + HIST(kV0names[Index]) + HIST("Spectrum"), v0Data.pt(), cent, v0.invMassNSigma(Index), weight); + if (std::abs(v0Data.rapidity(Index)) < ySel) { + histos.fill(HIST("h3d") + HIST(kV0names[Index]) + HIST("SpectrumY"), v0Data.pt(), cent, 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 (!doprocessSameEventHCascades) { + for (auto const& triggerTrack : triggerTracks) { + auto track = triggerTrack.track_as(); + if (!isValidTrigger(track)) + continue; + histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), cent); + histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + continue; + histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); + histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); + } + } + + // ________________________________________________ + // Do hadron - V0 correlations + if (doFullCorrelationStudy) + fillCorrelationsV0(triggerTracks, associatedV0s, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } + + void processSameEventHCascades(soa::Join::iterator const& collision, + aod::AssocV0s const&, aod::AssocCascades const& associatedCascades, aod::TriggerTracks const& triggerTracks, + V0DatasWithoutTrackX const&, aod::CascDatas const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + std::variant colBinning = + doPPAnalysis + ? std::variant{ + BinningTypePP{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}} + : std::variant{BinningTypePbPb{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}}; + + double cent = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && !TESTBIT(triggerPresenceMap[collision.globalIndex()], triggerBinToSelect)) { + return; + } + + // ________________________________________________ + // Perform basic event selection + if (((doPPAnalysis && !isCollisionSelected(collision))) || (!doPPAnalysis && !isCollisionSelectedPbPb(collision, true))) { return; } // ________________________________________________ - 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()); + if (doMixingQAandEventQA) { + std::visit([&](auto const& binning) { + histos.fill(HIST("MixingQA/hSECollisionBins"), binning.getBin({collision.posZ(), cent})); + }, + colBinning); + histos.fill(HIST("EventQA/hMult"), cent); + histos.fill(HIST("EventQA/hPvz"), collision.posZ()); + } // Do basic QA - if (applyEfficiencyCorrection) { - auto bc = collision.bc_as(); + auto bc = collision.bc_as(); + auto bField = getMagneticField(bc.timestamp()); + if (efficiencyFlags.applyEfficiencyCorrection) { initEfficiencyFromCCDB(bc); } TH2F* hEfficiencyCascade[4]; @@ -920,84 +1926,101 @@ struct correlateStrangeness { auto cascData = casc.cascData(); //---] syst cuts [--- - if (cascData.dcapostopv() < systCuts.dcapostopv || - cascData.dcanegtopv() < systCuts.dcanegtopv || - cascData.dcabachtopv() < systCuts.casc_dcabachtopv || - cascData.dcaV0daughters() > systCuts.dcaV0dau || - cascData.dcacascdaughters() > systCuts.casc_dcacascdau || - cascData.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.v0cospa || - cascData.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < systCuts.casc_cospa || - cascData.cascradius() < systCuts.casc_cascradius || - std::abs(cascData.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < systCuts.casc_mindcav0topv || - std::abs(cascData.mLambda() - pdgDB->Mass(3122)) > systCuts.casc_v0masswindow) + if (doPPAnalysis && (std::abs(cascData.dcapostopv()) < systCuts.dcapostopv || + std::abs(cascData.dcanegtopv()) < systCuts.dcanegtopv || + std::abs(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; + if (!doPPAnalysis && !CascadeSelectedPbPb(cascData, collision.posX(), collision.posY(), collision.posZ())) + continue; + uint64_t CascselMap = CascadeselectionBitmap(cascData, collision.posX(), collision.posY(), collision.posZ()); + //---] 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; + constexpr int Index = i.value; + if ((Index == 2 || Index == 3) && casc.compatible(Index, systCuts.dEdxCompatibility) && std::abs(casc.invMassNSigma(Index - 2)) < massWindowConfigurations.nSigmaNearXiMassCenter) { + return; + } float efficiency = 1.0f; - if (applyEfficiencyCorrection) { - efficiency = hEfficiencyCascade[index]->Interpolate(cascData.pt(), cascData.eta()); - } - float weight = applyEfficiencyCorrection ? 1. / efficiency : 1.0f; - if (casc.compatible(index, systCuts.dEdxCompatibility) && (!doMCassociation || casc.mcTrue(index)) && (!doAssocPhysicalPrimary || casc.mcPhysicalPrimary()) && (!applyEfficiencyCorrection || efficiency != 0)) { - if (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); + if (efficiencyFlags.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 = efficiencyFlags.applyEfficiencyCorrection ? 1. / efficiency : 1.0f; + if (casc.compatible(Index, systCuts.dEdxCompatibility) && (!doMCassociation || casc.mcTrue(Index)) && (!doAssocPhysicalPrimary || casc.mcPhysicalPrimary()) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0)) { + if (TESTBIT(doCorrelation, Index + 3) && (doPPAnalysis || (TESTBIT(CascselMap, Index) && TESTBIT(CascselMap, Index + 4) && TESTBIT(CascselMap, Index + 8) && TESTBIT(CascselMap, Index + 12)))) { + histos.fill(HIST("h3d") + HIST(kCascadenames[Index]) + HIST("Spectrum"), cascData.pt(), cent, casc.invMassNSigma(Index), weight); + if (std::abs(cascData.rapidity(Index)) < ySel) { + histos.fill(HIST("h3d") + HIST(kCascadenames[Index]) + HIST("SpectrumY"), cascData.pt(), cent, 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(), weight); - if (casc.invMassRegionCheck(index, 1) || casc.invMassRegionCheck(index, 3)) - histos.fill(HIST("h") + HIST(cascadenames[index]) + HIST("EtaVsPtVsPhiBg"), cascData.pt(), cascData.eta(), cascData.phi(), weight); } }); } for (auto const& triggerTrack : triggerTracks) { - if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) - continue; auto track = triggerTrack.track_as(); - - // systematic variations: track quality - if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) - continue; - if (!track.hasITS() && systCuts.triggerRequireITS) - continue; - if (track.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) - continue; - if (!(bitcheck(track.itsClusterMap(), 0)) && systCuts.triggerRequireL0) + if (!isValidTrigger(track)) continue; - // systematic variations: trigger DCAxy - if (std::abs(track.dcaXY()) < systCuts.dcaXYconstant + systCuts.dcaXYpTdep * std::abs(track.signed1Pt())) + histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), cent); + histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); + if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) continue; - + histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); + if (track.sign() > 0) + histos.fill(HIST("hPositiveTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); + else + histos.fill(HIST("hNegativeTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); } // ________________________________________________ // Do hadron - cascade correlations - fillCorrelationsCascade(triggerTracks, associatedCascades, false, collision.posX(), collision.posY(), collision.posZ(), collision.centFT0M()); + if (doFullCorrelationStudy) + fillCorrelationsCascade(triggerTracks, associatedCascades, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); } void processSameEventHPions(soa::Join::iterator const& collision, - aod::AssocPions const& associatedPions, aod::TriggerTracks const& triggerTracks, + soa::Join const& associatedPions, soa::Join const& triggerTracks, TracksComplete const&, aod::BCsWithTimestamps const&) { + BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; // ________________________________________________ - // 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]) { - return; + auto bc = collision.bc_as(); + auto bField = getMagneticField(bc.timestamp()); + + if (efficiencyFlags.applyEfficiencyCorrection) { + initEfficiencyFromCCDB(bc); } - if (!collision.isInelGt0() && selectINELgtZERO) { + + // ________________________________________________ + // Perform basic event selection + if (!isCollisionSelected(collision)) { return; } // ________________________________________________ - if (!doprocessSameEventHCascades && !doprocessSameEventHV0s) { + if (!doprocessSameEventHCascades && !doprocessSameEventHV0s && doMixingQAandEventQA) { 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()); @@ -1005,58 +2028,68 @@ struct correlateStrangeness { // Do basic QA for (auto const& pion : associatedPions) { auto pionTrack = pion.track_as(); - histos.fill(HIST("hPionEtaVsPtVsPhi"), pionTrack.pt(), pionTrack.eta(), pionTrack.phi()); + if (!isValidAssocHadron(pionTrack)) + continue; + + histos.fill(HIST("hPionEtaVsPtAllSelected"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); + if (doAssocPhysicalPrimary && !pion.mcPhysicalPrimary()) + continue; + if (doMCassociation && std::abs(pion.pdgCode()) != 211) + continue; + histos.fill(HIST("hPionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); + if (pionTrack.sign() > 0) + histos.fill(HIST("hPositivePionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); + else + histos.fill(HIST("hNegativePionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); } if (!doprocessSameEventHCascades && !doprocessSameEventHV0s) { for (auto const& triggerTrack : triggerTracks) { - if (doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) - continue; auto track = triggerTrack.track_as(); - - // systematic variations: track quality - if (track.tpcNClsCrossedRows() < systCuts.minTPCNCrossedRows) - continue; - if (!track.hasITS() && systCuts.triggerRequireITS) + if (!isValidTrigger(track)) continue; - if (track.tpcNClsShared() > systCuts.triggerMaxTPCSharedClusters) - continue; - if (!(bitcheck(track.itsClusterMap(), 0)) && systCuts.triggerRequireL0) - continue; - // systematic variations: trigger DCAxy - if (std::abs(track.dcaXY()) < systCuts.dcaXYconstant + systCuts.dcaXYpTdep * std::abs(track.signed1Pt())) + 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()); + if (doFullCorrelationStudy) + fillCorrelationsHadron(triggerTracks, associatedPions, false, collision.posZ(), collision.centFT0M(), bField); } - void processMixedEventHV0s(soa::Join const& collisions, - aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, - V0DatasWithoutTrackX const&, aod::V0sLinked const&, TracksComplete const&, aod::BCsWithTimestamps 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)) { + BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { + auto bc = collision1.bc_as(); + auto bField = getMagneticField(bc.timestamp()); // ________________________________________________ - if (applyEfficiencyCorrection) { - auto bc = collision1.bc_as(); + if (efficiencyFlags.applyEfficiencyCorrection) { 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()) - continue; - if (TMath::Abs(collision1.posZ()) > zVertexCut || TMath::Abs(collision2.posZ()) > zVertexCut) + 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.isInelGt0() || !collision2.isInelGt0()) && selectINELgtZERO) - continue; - - if (!doprocessMixedEventHCascades) { + if (doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting } @@ -1067,107 +2100,212 @@ struct correlateStrangeness { // ________________________________________________ // Do slicing auto slicedTriggerTracks = triggerTracks.sliceBy(collisionSliceTracks, collision1.globalIndex()); - auto slicedAssocV0s = associatedV0s.sliceBy(collisionSliceV0s, collision2.globalIndex()); + auto slicedAssocHadrons = assocHadrons.sliceBy(collisionSliceHadrons, collision2.globalIndex()); // ________________________________________________ - // Do hadron - V0 correlations - fillCorrelationsV0(slicedTriggerTracks, slicedAssocV0s, true, collision1.posZ(), collision1.centFT0M()); + // Do hadron - hadron correlations + if (doFullCorrelationStudy) + fillCorrelationsHadron(slicedTriggerTracks, slicedAssocHadrons, true, collision1.posZ(), collision1.centFT0M(), bField); } } - void processMixedEventHCascades(soa::Join const& collisions, + + void processMixedEventHV0s(soa::Join const& collisions, + aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, + V0DatasWithoutTrackX const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + std::variant colBinning = + doPPAnalysis + ? std::variant{ + BinningTypePP{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}} + : std::variant{BinningTypePbPb{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}}; + + std::visit([&](auto const& binning) { + for (auto const& [collision1, collision2] : soa::selfCombinations(binning, mixingParameter, -1, collisions, collisions)) { + double cent1 = doPPAnalysis ? collision1.centFT0M() : collision1.centFT0C(); + double cent2 = doPPAnalysis ? collision2.centFT0M() : collision2.centFT0C(); + auto bc = collision1.template bc_as(); + auto bField = getMagneticField(bc.timestamp()); + // ________________________________________________ + if (efficiencyFlags.applyEfficiencyCorrection) { + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && (!TESTBIT(triggerPresenceMap[collision1.globalIndex()], triggerBinToSelect) || !TESTBIT(triggerPresenceMap[collision2.globalIndex()], triggerBinToSelect))) { + continue; + } + + // Perform basic event selection on both collisions + if ((doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!doPPAnalysis && (!isCollisionSelectedPbPb(collision1, true) || (!isCollisionSelectedPbPb(collision2, true))))) { + continue; + } + if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) + continue; + if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) + continue; + + if (!doprocessMixedEventHCascades && doMixingQAandEventQA) { + 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"), binning.getBin({collision1.posZ(), cent1})); + } + // ________________________________________________ + // Do slicing + auto slicedTriggerTracks = triggerTracks.sliceBy(collisionSliceTracks, collision1.globalIndex()); + auto slicedAssocV0s = associatedV0s.sliceBy(collisionSliceV0s, collision2.globalIndex()); + // ________________________________________________ + // Do hadron - V0 correlations + if (doFullCorrelationStudy) + fillCorrelationsV0(slicedTriggerTracks, slicedAssocV0s, true, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); + } + }, + colBinning); + } + + 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&, aod::BCsWithTimestamps const&) + V0DatasWithoutTrackX const&, aod::CascDatas const&, TracksComplete const&, aod::BCsWithTimestamps const&) + { + std::variant colBinning = + doPPAnalysis + ? std::variant{ + BinningTypePP{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}} + : std::variant{BinningTypePbPb{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}}; + + std::visit([&](auto const& binning) { + for (auto const& [collision1, collision2] : soa::selfCombinations(binning, mixingParameter, -1, collisions, collisions)) { + double cent1 = doPPAnalysis ? collision1.centFT0M() : collision1.centFT0C(); + double cent2 = doPPAnalysis ? collision2.centFT0M() : collision2.centFT0C(); + // ________________________________________________ + auto bc = collision1.template bc_as(); + auto bField = getMagneticField(bc.timestamp()); + if (efficiencyFlags.applyEfficiencyCorrection) { + initEfficiencyFromCCDB(bc); + } + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && (!TESTBIT(triggerPresenceMap[collision1.globalIndex()], triggerBinToSelect) || !TESTBIT(triggerPresenceMap[collision2.globalIndex()], triggerBinToSelect))) { + continue; + } + + // Perform basic event selection on both collisions + if ((doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!doPPAnalysis && (!isCollisionSelectedPbPb(collision1, true) || (!isCollisionSelectedPbPb(collision2, true))))) { + continue; + } + if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) + continue; + if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) + continue; + if (doMixingQAandEventQA) { + 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"), binning.getBin({collision1.posZ(), cent1})); + } + // ________________________________________________ + // Do slicing + auto slicedTriggerTracks = triggerTracks.sliceBy(collisionSliceTracks, collision1.globalIndex()); + auto slicedAssocCascades = associatedCascades.sliceBy(collisionSliceCascades, collision2.globalIndex()); + // ________________________________________________ + // Do hadron - cascade correlations + if (doFullCorrelationStudy) + fillCorrelationsCascade(slicedTriggerTracks, slicedAssocCascades, true, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); + } + }, + colBinning); + } + + 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)) { + BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; + for (auto const& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { + auto bc = collision1.bc_as(); + auto bField = getMagneticField(bc.timestamp()); // ________________________________________________ - if (applyEfficiencyCorrection) { - auto bc = collision1.bc_as(); + if (efficiencyFlags.applyEfficiencyCorrection) { initEfficiencyFromCCDB(bc); } - // Perform basic event selection on both collisions - if (!collision1.sel8() || !collision2.sel8()) - continue; - if (TMath::Abs(collision1.posZ()) > zVertexCut || TMath::Abs(collision2.posZ()) > zVertexCut) - 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.isInelGt0() || !collision2.isInelGt0()) && selectINELgtZERO) + // ________________________________________________ + // skip if desired trigger not found + if (triggerPresenceMap.size() > 0 && (!TESTBIT(triggerPresenceMap[collision1.globalIndex()], triggerBinToSelect) || !TESTBIT(triggerPresenceMap[collision2.globalIndex()], triggerBinToSelect))) { 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 slicedAssocCascades = associatedCascades.sliceBy(collisionSliceCascades, collision2.globalIndex()); - // ________________________________________________ - // Do hadron - cascade correlations - 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&) - { - for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, mixingParameter, -1, collisions, collisions)) { // ________________________________________________ // Perform basic event selection on both collisions - if (!collision1.sel8() || !collision2.sel8()) - continue; - if (TMath::Abs(collision1.posZ()) > zVertexCut || TMath::Abs(collision2.posZ()) > zVertexCut) + 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.isInelGt0() || !collision2.isInelGt0()) && selectINELgtZERO) - continue; - - if (collision1.globalIndex() == collision2.globalIndex()) { - histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting + if (doMixingQAandEventQA) { + 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()})); } - - 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 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()); + if (doFullCorrelationStudy) + fillCorrelationsHadron(slicedTriggerTracks, slicedAssocPions, true, collision1.posZ(), collision1.centFT0M(), bField); } } - 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) > etaSel) { 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()) == PDG_t::kPiPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kProton || std::abs(mcParticle.pdgCode()) == PDG_t::kElectron || std::abs(mcParticle.pdgCode()) == PDG_t::kMuonMinus) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hGeneratedQAPtTrigger"), gpt, 0.0f); // step 1: before all selections + } + } + + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() == PDG_t::kK0Short && doCorrelationK0Short) { + histos.fill(HIST("hGeneratedQAPtAssociatedK0"), gpt, 0.0f); // step 1: before all selections + } + } + } + + for (auto const& mcParticle : mcParticles) { + if (doAssocPhysicalPrimaryInGen && !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(), 1); + if (i == 7 && mcParticle.pdgCode() > 0) + histos.fill(HIST("Generated/hPositive") + HIST(kParticlenames[Index]), mcParticle.pt(), mcParticle.eta(), 1); + else if (i == 7 && mcParticle.pdgCode() < 0) + histos.fill(HIST("Generated/hNegative") + HIST(kParticlenames[Index]), mcParticle.pt(), mcParticle.eta(), 1); + } + } else { + if (mcParticle.pdgCode() == kPdgCodes[i]) + histos.fill(HIST("Generated/h") + HIST(kParticlenames[Index]), mcParticle.pt(), mcParticle.eta(), 1); + } + }); } if (collisions.size() < 1) return; @@ -1178,44 +2316,49 @@ struct correlateStrangeness { float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; - for (auto& collision : collisions) { + 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()]; } } if (collisions.size() > 1) { for (auto const& mcParticle : mcParticles) { - if (!mcParticle.isPhysicalPrimary()) + if (doAssocPhysicalPrimaryInGen && !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()) > ySel) + 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) @@ -1223,56 +2366,111 @@ struct correlateStrangeness { 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) > etaSel) { continue; } - Double_t geta = mcParticle.eta(); - Double_t gpt = mcParticle.pt(); - if (abs(mcParticle.pdgCode()) == 211 || abs(mcParticle.pdgCode()) == 321 || abs(mcParticle.pdgCode()) == 2212 || abs(mcParticle.pdgCode()) == 11 || abs(mcParticle.pdgCode()) == 13) - histos.fill(HIST("GeneratedWithPV/hTrigger"), gpt, geta); - if (abs(mcParticle.pdgCode()) == 211) - histos.fill(HIST("GeneratedWithPV/hPion"), gpt, geta); - if (abs(mcParticle.pdgCode()) == 310) - histos.fill(HIST("GeneratedWithPV/hK0Short"), gpt, geta); - if (mcParticle.pdgCode() == 3122) - histos.fill(HIST("GeneratedWithPV/hLambda"), gpt, geta); - if (mcParticle.pdgCode() == -3122) - histos.fill(HIST("GeneratedWithPV/hAntiLambda"), gpt, geta); - if (mcParticle.pdgCode() == 3312) - histos.fill(HIST("GeneratedWithPV/hXiMinus"), gpt, geta); - if (mcParticle.pdgCode() == -3312) - histos.fill(HIST("GeneratedWithPV/hXiPlus"), gpt, geta); - if (mcParticle.pdgCode() == 3334) - histos.fill(HIST("GeneratedWithPV/hOmegaMinus"), gpt, geta); - if (mcParticle.pdgCode() == -3334) - histos.fill(HIST("GeneratedWithPV/hOmegaPlus"), gpt, geta); - - if (abs(mcParticle.y()) < 0.5) { - if (abs(mcParticle.pdgCode()) == 211) - histos.fill(HIST("GeneratedWithPV/hPion_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); - if (abs(mcParticle.pdgCode()) == 310) - histos.fill(HIST("GeneratedWithPV/hK0Short_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3122) - histos.fill(HIST("GeneratedWithPV/hLambda_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3122) - histos.fill(HIST("GeneratedWithPV/hAntiLambda_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3312) - histos.fill(HIST("GeneratedWithPV/hXiMinus_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3312) - histos.fill(HIST("GeneratedWithPV/hXiPlus_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == 3334) - histos.fill(HIST("GeneratedWithPV/hOmegaMinus_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); - if (mcParticle.pdgCode() == -3334) - histos.fill(HIST("GeneratedWithPV/hOmegaPlus_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kProton || std::abs(mcParticle.pdgCode()) == PDG_t::kElectron || std::abs(mcParticle.pdgCode()) == PDG_t::kMuonMinus) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hGeneratedQAPtTrigger"), gpt, 1.0f); // step 2: after event selection + } + } + + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() == PDG_t::kK0Short && doCorrelationK0Short) { + histos.fill(HIST("hGeneratedQAPtAssociatedK0"), gpt, 1.0f); // step 2: before all selections + } } } + + for (auto const& mcParticle : mcParticles) { + if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { + continue; + } + double geta = mcParticle.eta(); + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kProton || std::abs(mcParticle.pdgCode()) == PDG_t::kElectron || std::abs(mcParticle.pdgCode()) == PDG_t::kMuonMinus) { + histos.fill(HIST("GeneratedWithPV/hTrigger"), gpt, geta, bestCollisionFT0Mpercentile); + if (mcParticle.pdgCode() > 0) + histos.fill(HIST("GeneratedWithPV/hPositiveTrigger"), gpt, geta, bestCollisionFT0Mpercentile); + else + histos.fill(HIST("GeneratedWithPV/hNegativeTrigger"), gpt, geta, bestCollisionFT0Mpercentile); + } + + if (mcParticle.pdgCode() == PDG_t::kLambda0 && !doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { + if (std::abs(geta) > etaSel) { + continue; + } + auto lamMothers = mcParticle.mothers_as(); + if (lamMothers.size() == 1) { + for (const auto& lamParticleMother : lamMothers) { + if (std::abs(lamParticleMother.eta()) > etaSel) { + continue; + } + if (lamParticleMother.pdgCode() == PDG_t::kXiMinus) // Xi Minus Mother Matched + { + histos.fill(HIST("GeneratedWithPV/hLambdaFromXiMinus"), gpt, geta); + } + if (lamParticleMother.pdgCode() == o2::constants::physics::Pdg::kXi0) // Xi Zero Mother Matched + { + histos.fill(HIST("GeneratedWithPV/hLambdaFromXiZero"), gpt, geta); + } + } + } + } + if (mcParticle.pdgCode() == PDG_t::kLambda0Bar && !doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { + if (std::abs(geta) > etaSel) { + continue; + } + auto lamMothers = mcParticle.mothers_as(); + if (lamMothers.size() == 1) { + for (const auto& lamParticleMother : lamMothers) { + if (std::abs(lamParticleMother.eta()) > etaSel) { + continue; + } + if (lamParticleMother.pdgCode() == PDG_t::kXiPlusBar) { + histos.fill(HIST("GeneratedWithPV/hAntiLambdaFromXiPlus"), gpt, geta); + } + if (lamParticleMother.pdgCode() == -o2::constants::physics::Pdg::kXi0) // Xi Zero Mother Matched + { + histos.fill(HIST("GeneratedWithPV/hAntiLambdaFromXiZero"), 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, bestCollisionFT0Mpercentile); + if (std::abs(mcParticle.y()) < ySel) + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]) + HIST("_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); + if (i == 7 && mcParticle.pdgCode() > 0) + histos.fill(HIST("GeneratedWithPV/hPositive") + HIST(kParticlenames[Index]), mcParticle.pt(), mcParticle.eta(), bestCollisionFT0Mpercentile); + else if (i == 7 && mcParticle.pdgCode() < 0) + histos.fill(HIST("GeneratedWithPV/hNegative") + HIST(kParticlenames[Index]), mcParticle.pt(), mcParticle.eta(), bestCollisionFT0Mpercentile); + } + + } else { + if (mcParticle.pdgCode() == kPdgCodes[i]) { + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]), gpt, geta, bestCollisionFT0Mpercentile); + if (std::abs(mcParticle.y()) < ySel) + histos.fill(HIST("GeneratedWithPV/h") + HIST(kParticlenames[Index]) + HIST("_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); + } + } + }); + } } - void processClosureTest(aod::McCollision const& collision, soa::SmallGroups> const& recCollisions, aod::McParticles const& mcParticles) + void processClosureTest(aod::McCollision const& /*mcCollision*/, soa::SmallGroups> const& recCollisions, aod::McParticles const& mcParticles) { std::vector triggerIndices; std::vector> associatedIndices; + std::vector assocHadronIndices; std::vector piIndices; std::vector k0ShortIndices; std::vector lambdaIndices; @@ -1282,80 +2480,141 @@ struct correlateStrangeness { std::vector omegaMinusIndices; std::vector omegaPlusIndices; + for (auto const& mcParticle : mcParticles) { + double geta = mcParticle.eta(); + if (std::abs(geta) > etaSel) { + continue; + } + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kProton || std::abs(mcParticle.pdgCode()) == PDG_t::kElectron || std::abs(mcParticle.pdgCode()) == PDG_t::kMuonMinus) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hClosureQAPtTrigger"), gpt, 0.0f); // step 1: no event selection whatsoever + } + } + + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() == PDG_t::kK0Short && 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; - for (auto& recCollision : recCollisions) { + 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) > 10.0f) + 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) > etaSel) { + continue; + } + double gpt = mcParticle.pt(); + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kProton || std::abs(mcParticle.pdgCode()) == PDG_t::kElectron || std::abs(mcParticle.pdgCode()) == PDG_t::kMuonMinus) { + if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("hClosureQAPtTrigger"), gpt, 1.0f); // step 2: after event selection + } + } + + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + if (mcParticle.pdgCode() == PDG_t::kK0Short && 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_t geta = mcParticle.eta(); - Double_t gpt = mcParticle.pt(); - Double_t gphi = mcParticle.phi(); - if (abs(geta) > 0.8) { + double geta = mcParticle.eta(); + double gpt = mcParticle.pt(); + double gphi = mcParticle.phi(); + if (std::abs(geta) > etaSel) { continue; } - if (abs(mcParticle.pdgCode()) == 211 || abs(mcParticle.pdgCode()) == 321 || abs(mcParticle.pdgCode()) == 2212 || abs(mcParticle.pdgCode()) == 11 || abs(mcParticle.pdgCode()) == 13) { + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kKPlus || std::abs(mcParticle.pdgCode()) == PDG_t::kProton || std::abs(mcParticle.pdgCode()) == PDG_t::kElectron || std::abs(mcParticle.pdgCode()) == PDG_t::kMuonMinus) { if (!doTriggPhysicalPrimary || mcParticle.isPhysicalPrimary()) { triggerIndices.emplace_back(iteratorNum); - histos.fill(HIST("ClosureTest/hTrigger"), gpt, geta, gphi); + histos.fill(HIST("ClosureTest/hTrigger"), gpt, geta, bestCollisionFT0Mpercentile); + } + if (doCorrelationHadron) { + if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { + assocHadronIndices.emplace_back(iteratorNum); + histos.fill(HIST("ClosureTest/hHadron"), gpt, geta, gphi); + } } } if (!doAssocPhysicalPrimary || mcParticle.isPhysicalPrimary()) { - if (abs(mcParticle.pdgCode()) == 211) { + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus && doCorrelationPion) { piIndices.emplace_back(iteratorNum); histos.fill(HIST("ClosureTest/hPion"), gpt, geta, gphi); } - if (abs(mcParticle.pdgCode()) == 310) { + if (mcParticle.pdgCode() == PDG_t::kK0Short && doCorrelationK0Short) { k0ShortIndices.emplace_back(iteratorNum); histos.fill(HIST("ClosureTest/hK0Short"), gpt, geta, gphi); } - if (mcParticle.pdgCode() == 3122) { + if (mcParticle.pdgCode() == PDG_t::kLambda0 && doCorrelationLambda) { lambdaIndices.emplace_back(iteratorNum); histos.fill(HIST("ClosureTest/hLambda"), gpt, geta, gphi); } - if (mcParticle.pdgCode() == -3122) { + if (mcParticle.pdgCode() == PDG_t::kLambda0Bar && doCorrelationAntiLambda) { antiLambdaIndices.emplace_back(iteratorNum); histos.fill(HIST("ClosureTest/hAntiLambda"), gpt, geta, gphi); } - if (mcParticle.pdgCode() == 3312) { + if (mcParticle.pdgCode() == PDG_t::kXiMinus && doCorrelationXiMinus) { xiMinusIndices.emplace_back(iteratorNum); histos.fill(HIST("ClosureTest/hXiMinus"), gpt, geta, gphi); } - if (mcParticle.pdgCode() == -3312) { + if (mcParticle.pdgCode() == PDG_t::kXiPlusBar && doCorrelationXiPlus) { xiPlusIndices.emplace_back(iteratorNum); histos.fill(HIST("ClosureTest/hXiPlus"), gpt, geta, gphi); } - if (mcParticle.pdgCode() == 3334) { + if (mcParticle.pdgCode() == PDG_t::kOmegaMinus && doCorrelationOmegaMinus) { omegaMinusIndices.emplace_back(iteratorNum); histos.fill(HIST("ClosureTest/hOmegaMinus"), gpt, geta, gphi); } - if (mcParticle.pdgCode() == -3334) { + if (mcParticle.pdgCode() == PDG_t::kOmegaPlusBar && doCorrelationOmegaPlus) { omegaPlusIndices.emplace_back(iteratorNum); histos.fill(HIST("ClosureTest/hOmegaPlus"), gpt, geta, gphi); } } } - associatedIndices.emplace_back(piIndices); + associatedIndices.emplace_back(k0ShortIndices); associatedIndices.emplace_back(lambdaIndices); associatedIndices.emplace_back(antiLambdaIndices); @@ -1363,44 +2622,143 @@ struct correlateStrangeness { associatedIndices.emplace_back(xiPlusIndices); associatedIndices.emplace_back(omegaMinusIndices); associatedIndices.emplace_back(omegaPlusIndices); + associatedIndices.emplace_back(piIndices); + associatedIndices.emplace_back(assocHadronIndices); - for (Int_t iTrigger = 0; iTrigger < triggerIndices.size(); iTrigger++) { + for (std::size_t iTrigger = 0; iTrigger < triggerIndices.size(); iTrigger++) { auto triggerParticle = mcParticles.iteratorAt(triggerIndices[iTrigger]); - // if (!mcParticle) { - // continue; - // } - Double_t getatrigger = triggerParticle.eta(); - Double_t gphitrigger = triggerParticle.phi(); - Double_t pttrigger = triggerParticle.pt(); + // check range of trigger particle + if (triggerParticle.pt() > axisRanges[3][1] || triggerParticle.pt() < axisRanges[3][0]) { + continue; + } + double getatrigger = triggerParticle.eta(); + double gphitrigger = triggerParticle.phi(); + double pttrigger = triggerParticle.pt(); auto const& mother = triggerParticle.mothers_first_as(); - Int_t globalIndex = mother.globalIndex(); - static_for<0, 7>([&](auto i) { // associated loop - constexpr int index = i.value; - for (Int_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_t getaassoc = assocParticle.eta(); - Double_t gphiassoc = assocParticle.phi(); - Double_t ptassoc = assocParticle.pt(); - histos.fill(HIST("ClosureTest/sameEvent/") + HIST(particlenames[index]), ComputeDeltaPhi(gphitrigger, gphiassoc), getatrigger - getaassoc, ptassoc, pttrigger, collision.posZ(), bestCollisionFT0Mpercentile); + auto globalIndex = mother.globalIndex(); + static_for<0, 8>([&](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); - PROCESS_SWITCH(correlateStrangeness, processClosureTest, "Process Closure Test", 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 == PDG_t::kLambda0 && !v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); + if (v0mothers.size() == 1) { + for (const auto& v0mcParticleMother : v0mothers) { + // auto& v0mcParticleMother = v0mothers.front(); + if (std::abs(v0mcParticleMother.eta()) > etaSel) { + continue; + } + if (v0mcParticleMother.pdgCode() == PDG_t::kXiMinus) // Xi Minus Mother Matched + { + histos.fill(HIST("hLambdaXiMinusFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + histos.fill(HIST("hLambdaFromXiMinusEtaVsPtVsPhi"), v0mcParticle.pt(), v0mcParticle.eta(), v0mcParticle.phi()); + } + if (v0mcParticleMother.pdgCode() == o2::constants::physics::Pdg::kXi0) // Xi Zero Mother Matched + { + histos.fill(HIST("hLambdaXiZeroFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + histos.fill(HIST("hLambdaFromXiZeroEtaVsPtVsPhi"), v0mcParticle.pt(), v0mcParticle.eta(), v0mcParticle.phi()); + } + if (v0mcParticleMother.pdgCode() == PDG_t::kOmegaMinus) // Omega Mother Matched + { + histos.fill(HIST("hLambdaOmegaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + } + } + } + } + if (mcParticlePdg == PDG_t::kLambda0Bar && !v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); + if (v0mothers.size() == 1) { + for (const auto& v0mcParticleMother : v0mothers) { + if (std::abs(v0mcParticleMother.eta()) > etaSel) { + continue; + } + if (v0mcParticleMother.pdgCode() == PDG_t::kXiPlusBar) // Xi Plus Mother Matched + { + histos.fill(HIST("hAntiLambdaXiPlusFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + histos.fill(HIST("hAntiLambdaFromXiPlusEtaVsPtVsPhi"), v0mcParticle.pt(), v0mcParticle.eta(), v0mcParticle.phi()); + } + if (v0mcParticleMother.pdgCode() == -o2::constants::physics::Pdg::kXi0) // Anti Xi Zero Mother Matched + { + histos.fill(HIST("hAntiLambdaXiZeroFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt()); + histos.fill(HIST("hAntiLambdaFromXiZeroEtaVsPtVsPhi"), v0mcParticle.pt(), v0mcParticle.eta(), v0mcParticle.phi()); + } + if (v0mcParticleMother.pdgCode() == PDG_t::kOmegaPlusBar) // 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/hyperon-reco-test.cxx b/PWGLF/Tasks/Strangeness/hyperon-reco-test.cxx index da2a9b0bd0b..3088e7d5d0b 100644 --- a/PWGLF/Tasks/Strangeness/hyperon-reco-test.cxx +++ b/PWGLF/Tasks/Strangeness/hyperon-reco-test.cxx @@ -1,4 +1,4 @@ -// Copyright 2020-2022 CERN and copyright holders of ALICE O2. +// Copyright 2020-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. // @@ -9,31 +9,31 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include -#include +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/Centrality.h" -#include "Framework/ASoAHelpers.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" - #include "TMath.h" - #include #include #include +#include +#include + using namespace std; using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx b/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx index d43be490657..f9e880937fb 100644 --- a/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx +++ b/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx @@ -9,31 +9,46 @@ // 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 -#include -#include +#include "PWGCF/Femto3D/Core/femto3dPairTask.h" +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/Propagator.h" #include "Framework/ASoA.h" -#include "Framework/DataTypes.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" #include "Framework/Expressions.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" #include "Framework/StaticFor.h" - +#include "Framework/runDataProcessing.h" #include "MathUtils/Utils.h" -#include "Common/DataModel/Multiplicity.h" -#include "PWGCF/Femto3D/DataModel/singletrackselector.h" -#include "PWGCF/Femto3D/Core/femto3dPairTask.h" +#include +#include +#include -#include "TLorentzVector.h" -#include "TDatabasePDG.h" +#include +#include +#include +#include +#include using namespace o2; using namespace o2::soa; @@ -42,9 +57,21 @@ using namespace o2::framework; using namespace o2::framework::expressions; using FilteredCollisions = soa::Filtered; -using FilteredTracks = soa::Filtered; +using FilteredTracks = soa::Filtered>; + +using RecoTracks = soa::Join; typedef std::shared_ptr trkType; +typedef std::shared_ptr trkTypeData; + typedef std::shared_ptr colType; using MyFemtoPair = o2::aod::singletrackselector::FemtoPair; @@ -55,46 +82,53 @@ class ResoPair : public MyFemtoPair ResoPair() {} ResoPair(trkType const& first, trkType const& second) : MyFemtoPair(first, second) { - SetPair(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) + 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"}; @@ -119,18 +153,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; @@ -140,18 +190,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) { @@ -170,149 +218,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", _particlePDG_1.value), kTH2F, {ptAxis, {100, -10., 10., "#eta"}}); - registry.add("p_first", Form("p_%i", _particlePDG_1.value), kTH1F, {ptAxis}); - registry.add("dcaXY_first", Form("dca_%i", _particlePDG_1.value), kTH2F, {ptAxis, dcaXyAxis}); + 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", _particlePDG_2.value), kTH1F, {ptAxis}); - registry.add("dcaXY_second", Form("dca_%i", _particlePDG_2.value), kTH2F, {ptAxis, dcaXyAxis}); + 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 LOG(debug) << "Mixing tracks of the same event"; - for (uint32_t ii = 0; ii < tracks.size(); ii++) { // nested loop for all the combinations - for (uint32_t iii = ii + 1; iii < tracks.size(); iii++) { + 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) { LOG(debug) << "Mixing tracks of two different events"; - for (auto ii : tracks1) { - for (auto iii : tracks2) { + 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(FilteredTracks const& tracks, FilteredCollisions const& collisions) + template + bool isTrackSelected(TrkType const& track) { - LOG(debug) << "Processing " << collisions.size() << " collisions and " << tracks.size() << " tracks"; + 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 collision : collisions) { + 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) { LOG(debug) << "Track index " << track.singleCollSelId(); - if (track.itsChi2NCl() > _itsChi2NCl) { - continue; - } - if (track.tpcChi2NCl() > _tpcChi2NCl) { - continue; - } - if (track.tpcCrossedRowsOverFindableCls() < _tpcCrossedRowsOverFindableCls) { + if (!isTrackSelected(track)) { continue; } - if (track.dcaXY() < _dcaXYmin || track.dcaXY() > _dcaXY) { - continue; - } - if (track.dcaZ() < _dcaZmin || track.dcaZ() > _dcaZ) { - continue; - } - registry.fill(HIST("Trks"), 1); - const float& vtxZ = track.singleCollSel_as().posZ(); - registry.fill(HIST("VTX"), vtxZ); - if (abs(vtxZ) > _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()); @@ -338,12 +580,13 @@ struct K0MixedEvents { 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 ^) + (_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()); @@ -391,7 +634,7 @@ struct K0MixedEvents { 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; } @@ -401,7 +644,7 @@ struct K0MixedEvents { 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 } } } @@ -419,7 +662,7 @@ struct K0MixedEvents { 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; } @@ -429,7 +672,7 @@ struct K0MixedEvents { 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 } } } @@ -451,9 +694,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..498dac596c4 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdaJetpolarization.cxx @@ -0,0 +1,1995 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/lambdaJetpolarization.h" + +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TProfile2D.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using std::cout; +using std::endl; +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct LfMyV0s { + + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + Configurable zVtx{"zVtx", 10.0, "Maximum zVertex"}; + Configurable rJet{"rJet", 0.4, "Jet resolution parameter R"}; + Configurable etaMin{"etaMin", -0.9f, "eta min"}; + Configurable etaMax{"etaMax", +0.9f, "eta max"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.00, "eta gap from the edge"}; + // 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 requireTOF{"requireTOF", false, "require TOF hit"}; + Configurable requireITS{"requireITS", false, "require ITS hit"}; + Configurable require_max_tpcSharedCls{"require_max_tpcSharedCls", false, "require ITS hit"}; + Configurable max_tpcSharedCls{"max_tpcSharedCls", 100, "max_tpcSharedCls"}; + Configurable max_chi2_TPC{"max_chi2_TPC", 4, "max_chi2_TPC"}; + Configurable max_chi2_ITS{"max_chi2_ITS", 36, "max_chi2_ITS"}; + + 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 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 cfgtrkMinPt{"cfgtrkMinPt", 0.10, "set track min pT"}; + + // v0 parameters + Configurable v0cospaMin{"v0cospaMin", 0.995f, "Minimum V0 CosPA"}; + Configurable v0cospainit{"v0cospainit", 0.97f, "Minimum V0 CosPA"}; + Configurable minimumV0Radius{"minimumV0Radius", 0.2f, "Minimum V0 Radius"}; + Configurable maximumV0Radius{"maximumV0Radius", 100000.0f, "Maximum V0 Radius"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 1.0f, "Maximum DCA Daughters"}; + Configurable dcanegtoPVmin{"dcanegtoPVmin", 0.1f, "Minimum DCA Neg To PV"}; + Configurable dcapostoPVmin{"dcapostoPVmin", 0.1f, "Minimum DCA Pos To PV"}; + Configurable v0radius{"v0radius", 0.0, "Radius"}; + Configurable dcav0dau{"dcav0dau", 10, "DCA V0 Daughters"}; + Configurable dcanegtopv{"dcanegtopv", 0.0, "DCA Neg To PV"}; + Configurable dcapostopv{"dcapostopv", 0.0, "DCA Pos To PV"}; + + // jet selection + Configurable cfgjetPtMin{"cfgjetPtMin", 8.0, "minimum jet pT cut"}; + Configurable ispassdTrackSelectionForJetReconstruction{"ispassdTrackSelectionForJetReconstruction", 1, "do track selection"}; + + // v0Event selection + Configurable sel8{"sel8", 1, "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 isNoSameBunchPileup{"isNoSameBunchPileup", 0, "isNoSameBunchPileup"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", 1, "isGoodZvtxFT0vsPV"}; + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable CtauLambda{"ctauLambda", 30, "C tau Lambda (cm)"}; + Configurable requirepassedSingleTrackSelection{"requirepassedSingleTrackSelection", false, "requirepassedSingleTrackSelection"}; + Configurable V0tracketaMin{"V0tracketaMin", -0.8f, "eta min track"}; + Configurable V0tracketaMax{"V0tracketaMax", +0.8f, "eta max track"}; + Configurable requireTPC{"requireTPC", true, "require TPC hit"}; + Configurable yMin{"V0yMin", -0.5f, "minimum y"}; + Configurable yMax{"V0yMax", +0.5f, "maximum y"}; + Configurable v0rejLambda{"v0rejLambda", 0.01, "V0 rej Lambda"}; + Configurable v0accLambda{"v0accLambda", 0.075, "V0 acc Lambda"}; + Configurable ifinitpasslambda{"ifinitpasslambda", 0, "ifinitpasslambda"}; + Configurable ifpasslambda{"passedLambdaSelection", 1, "passedLambdaSelection"}; + Configurable paramArmenterosCut{"paramArmenterosCut", 0.2, "parameter Armenteros Cut"}; + Configurable doArmenterosCut{"doArmenterosCut", 0, "do Armenteros Cut"}; + Configurable noSameBunchPileUp{"noSameBunchPileUp", true, "reject SameBunchPileUp"}; + Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + Configurable NotITSAfterburner{"NotITSAfterburner", 0, "NotITSAfterburner"}; + Configurable doQA{"doQA", 1, "fill QA histograms"}; + Configurable evSel{"evSel", 1, "evSel"}; + Configurable hasTOF2Leg{"hasTOF2Leg", 0, "hasTOF2Leg"}; + Configurable hasTOF1Leg{"hasTOF1Leg", 0, "hasTOF1Leg"}; + + // Jet background subtraction + JetBkgSubUtils backgroundSub; + 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, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec axisPhi{100, -TMath::Pi(), TMath::Pi(), "#Phi"}; + const AxisSpec axisTheta{100, -TMath::Pi(), TMath::Pi(), "#Theta"}; + const AxisSpec axisMass{100, 0.9, 1.0, "Mass(GeV/c^{2})"}; + const AxisSpec axisCostheta{100, -1, 1, "Cos(#theta^{*}_{p})"}; + const AxisSpec axisSinPhi{100, -1, 1, "Sin(#phi^{*}_{p})"}; + + const AxisSpec JetaxisEta{30, -1.5, +1.5, "#eta"}; + const AxisSpec JetaxisPhi{200, -1, +7, "#phi"}; + const AxisSpec JetaxisPt{200, 0, +200, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec ptAxis{100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec invMassLambdaAxis{200, 1.016, 1.216, "m_{p#pi} (GeV/#it{c}^{2})"}; + + ConfigurableAxis TProfile2DaxisPt{"#it{p}_{T} (GeV/#it{c})", {VARIABLE_WIDTH, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.2, 3.7, 4.2, 5, 6, 8, 10, 12}, "pt axis for histograms"}; + ConfigurableAxis TProfile2DaxisMass{"Mass p#pi (GeV/#it{c^{2}})", {VARIABLE_WIDTH, 1.10068, 1.10668, 1.11068, 1.11268, 1.11368, 1.11468, 1.11568, 1.11668, 1.11768, 1.11868, 1.12068, 1.12468, 1.13068}, "Mass axis for histograms"}; + + registryData.add("number_of_events_vsmultiplicity", "number of events in data vs multiplicity", HistType::kTH1D, {{101, 0, 101, "Multiplicity percentile"}}); + registryData.add("h_track_pt", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", kTH1F, {{200, 0., 200.}}); + registryData.add("h_track_eta", "track #eta;#eta_{track};entries", kTH1F, {{100, -1.f, 1.f}}); + registryData.add("h_track_phi", "track #varphi;#varphi_{track};entries", kTH1F, {{80, -1.f, 7.f}}); + registryData.add("h_track_pt_sel", "track pT;#it{p}_{T,track} (GeV/#it{c});entries", kTH1F, {{200, 0., 200.}}); + registryData.add("h_track_eta_sel", "track #eta;#eta_{track};entries", kTH1F, {{100, -1.f, 1.f}}); + registryData.add("h_track_phi_sel", "track #varphi;#varphi_{track};entries", kTH1F, {{80, -1.f, 7.f}}); + + registryData.add("FJetaHistogram", "FJetaHistogram", kTH1F, {JetaxisEta}); + registryData.add("FJphiHistogram", "FJphiHistogram", kTH1F, {JetaxisPhi}); + registryData.add("FJptHistogram", "FJptHistogram", kTH1F, {JetaxisPt}); + registryData.add("nJetsPerEvent", "nJetsPerEvent", kTH1F, {{10, 0.0, 10.0}}); + registryData.add("nJetsPerEventsel", "nJetsPerEventsel", kTH1F, {{10, 0.0, 10.0}}); + registryData.add("nV0sPerEvent", "nV0sPerEvent", kTH1F, {{10, 0.0, 10.0}}); + registryData.add("FJetaHistogramsel", "FJetaHistogramsel", kTH1F, {JetaxisEta}); + registryData.add("FJphiHistogramsel", "FJphiHistogramsel", kTH1F, {JetaxisPhi}); + registryData.add("FJptHistogramsel", "FJptHistogramsel", kTH1F, {JetaxisPt}); + + registryData.add("FLeadingJetaHistogramsel", "FLeadingJetaHistogramsel", kTH1F, {JetaxisEta}); + registryData.add("FLeadingJphiHistogramsel", "FLeadingJphiHistogramsel", kTH1F, {JetaxisPhi}); + registryData.add("FLeadingJptHistogramsel", "FLeadingJptHistogramsel", kTH1F, {JetaxisPt}); + + registryData.add("LambdaPtMass", "LambdaPtMass", HistType::kTH2F, {ptAxis, invMassLambdaAxis}); + registryData.add("AntiLambdaPtMass", "AntiLambdaPtMass", HistType::kTH2F, {ptAxis, invMassLambdaAxis}); + + registryData.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {invMassLambdaAxis}}); + registryData.add("hMassAntiLambda", "hMassAntiLambda", {HistType::kTH1F, {invMassLambdaAxis}}); + registryData.add("V0pTInLab", "V0pTInLab", kTH1F, {axisPT}); + + registryData.add("V0pxInLab", "V0pxInLab", kTH1F, {axisPx}); + registryData.add("V0pyInLab", "V0pyInLab", kTH1F, {axisPy}); + registryData.add("V0pzInLab", "V0pzInLab", kTH1F, {axisPz}); + + registryData.add("V0pxInRest_frame", "V0pxInRest_frame", kTH1F, {axisPx}); + registryData.add("V0pyInRest_frame", "V0pyInRest_frame", kTH1F, {axisPy}); + registryData.add("V0pzInRest_frame", "V0pzInRest_frame", kTH1F, {axisPz}); + + registryData.add("V0pxInJetframe", "V0pxInJetframe", kTH1F, {axisPx}); + registryData.add("V0pyInJetframe", "V0pyInJetframe", kTH1F, {axisPy}); + registryData.add("V0pzInJetframe", "V0pzInJetframe", kTH1F, {axisPz}); + + registryData.add("protonQA/V0protonpxInLab", "V0protonpxInLab", kTH1F, {axisPx}); + registryData.add("protonQA/V0protonpyInLab", "V0protonpyInLab", kTH1F, {axisPy}); + registryData.add("protonQA/V0protonpzInLab", "V0protonpzInLab", kTH1F, {axisPz}); + registryData.add("protonQA/V0protonMassInLab", "V0protonMassInLab", kTH1F, {axisMass}); + registryData.add("protonQA/V0protonphiInLab", "V0protonphiInLab", kTH1F, {axisPhi}); + registryData.add("protonQA/V0protonthetaInLab", "V0protonthetaInLab", kTH1F, {axisTheta}); + registryData.add("protonQA/V0protoncosthetaInLab", "V0protoncosthetaInLab", kTH1F, {axisCostheta}); + registryData.add("protonQA/profileprotonsinthetaInLab", "Invariant Mass vs sin(theta)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/profileprotonsinphiInLab", "Invariant Mass vs sin(phi)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/profileprotoncosSquarethetaInLab", "Invariant Mass vs cos^2(theta)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("JetQA/JetthetaInLab", "JetthetaInLab", kTH1F, {axisTheta}); + registryData.add("JetQA/JetphiInLab", "JetphiInLab", kTH1F, {axisPhi}); + registryData.add("JetQA/JetpxInLab", "JetpxInLab", kTH1F, {axisPx}); + registryData.add("JetQA/JetpyInLab", "JetpyInLab", kTH1F, {axisPy}); + registryData.add("JetQA/JetpzInLab", "JetpzInLab", kTH1F, {axisPz}); + registryData.add("JetQA/JetptInLab", "JetptInLab", kTH1F, {axisPT}); + + registryData.add("protonQA/V0protonpxInRest_frame", "V0protonpxInRest_frame", kTH1F, {axisPx}); + registryData.add("protonQA/V0protonpyInRest_frame", "V0protonpyInRest_frame", kTH1F, {axisPy}); + registryData.add("protonQA/V0protonpzInRest_frame", "V0protonpzInRest_frame", kTH1F, {axisPz}); + registryData.add("protonQA/V0protonMassInRest_frame", "V0protonMassInRest_frame", kTH1F, {axisMass}); + registryData.add("protonQA/V0protonphiInRest_frame", "V0protonphiInRest_frame", kTH1F, {axisPhi}); + registryData.add("protonQA/V0protonthetaInRest_frame", "V0protonthetaInRest_frame", kTH1F, {axisTheta}); + registryData.add("protonQA/V0protoncosthetaInV0frame", "V0protoncosthetaInV0frame", kTH1F, {axisCostheta}); + registryData.add("protonQA/profileprotonsinthetaInV0frame", "Invariant Mass vs sin(theta)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/profileprotonsinphiInV0frame", "Invariant Mass vs sin(phi)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/profileprotoncosSquarethetaInV0frame", "Invariant Mass vs cos^2(theta)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("JetQA/JetthetaInV0", "JetthetaInV0", kTH1F, {axisTheta}); + registryData.add("JetQA/JetphiInV0", "JetphiInV0", kTH1F, {axisPhi}); + registryData.add("JetQA/JetpxInV0", "JetpxInV0", kTH1F, {axisPx}); + registryData.add("JetQA/JetpyInV0", "JetpyInV0", kTH1F, {axisPy}); + registryData.add("JetQA/JetpzInV0", "JetpzInV0", kTH1F, {axisPz}); + registryData.add("JetQA/JetptInV0", "JetptInV0", kTH1F, {axisPT}); + + registryData.add("protonQA/V0protonpxInJetframe", "V0protonpxInJetframe", kTH1F, {axisPx}); + registryData.add("protonQA/V0protonpyInJetframe", "V0protonpyInJetframe", kTH1F, {axisPy}); + registryData.add("protonQA/V0protonpzInJetframe", "V0protonpzInJetframe", kTH1F, {axisPz}); + registryData.add("protonQA/V0protonphiInJetframe", "V0protonphiInJetframe", kTH1F, {axisPhi}); + registryData.add("protonQA/V0protonthetaInJetframe", "V0protonthetaInJetframe", kTH1F, {axisTheta}); + registryData.add("protonQA/V0protoncosthetaInJetframe", "V0protoncosthetaInJetframe", kTH1F, {axisCostheta}); + registryData.add("protonQA/profileprotonsinthetaInJetframe", "Invariant Mass vs sin(theta)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/profileprotonsinphiInJetframe", "Invariant Mass vs sin(phi)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/profileprotoncosSquarethetaInJetframe", "Invariant Mass vs cos^2(theta)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/V0protonMassInJetframe", "V0protonMassInJetframe", kTH1F, {axisMass}); + registryData.add("JetQA/JetthetaInJetframe", "JetthetaInJetframe", kTH1F, {axisTheta}); + registryData.add("JetQA/JetphiInJetframe", "JetphiInJetframe", kTH1F, {axisPhi}); + registryData.add("JetQA/JetpxInJetframe", "JetpxInJetframe", kTH1F, {axisPx}); + registryData.add("JetQA/JetpyInJetframe", "JetpyInJetframe", kTH1F, {axisPy}); + registryData.add("JetQA/JetpzInJetframe", "JetpzInJetframe", kTH1F, {axisPz}); + registryData.add("JetQA/JetptInJetframe", "JetptInJetframe", kTH1F, {axisPT}); + + registryData.add("protonQA/V0protonpxInJetV0frame", "V0protonpxInJetV0frame", kTH1F, {axisPx}); + registryData.add("protonQA/V0protonpyInJetV0frame", "V0protonpyInJetV0frame", kTH1F, {axisPy}); + registryData.add("protonQA/V0protonpzInJetV0frame", "V0protonpzInJetV0frame", kTH1F, {axisPz}); + registryData.add("protonQA/V0protonphiInJetV0frame", "V0protonphiInJetV0frame", kTH1F, {axisPhi}); + registryData.add("protonQA/V0protonthetaInJetV0frame", "V0protonthetaInJetV0frame", kTH1F, {axisTheta}); + registryData.add("protonQA/V0protoncosthetaInJetV0", "V0protoncosthetaInJetV0", kTH1F, {axisCostheta}); + registryData.add("protonQA/V0protonMassInJetV0frame", "V0protonMassInJetV0frame", kTH1F, {axisMass}); + registryData.add("protonQA/profileprotonsinthetaInJetV0frame", "Invariant Mass vs sin(theta)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/profileprotonsinphiInJetV0frame", "Invariant Mass vs sin(phi)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("protonQA/profileprotoncosSquarethetaInJetV0frame", "Invariant Mass vs cos^2(theta)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("JetQA/JetthetaInJetV0frame", "JetthetaInJetV0frame", kTH1F, {axisTheta}); + registryData.add("JetQA/JetphiInJetV0frame", "JetphiInJetV0frame", kTH1F, {axisPhi}); + registryData.add("JetQA/JetpxInJetV0frame", "JetpxInJetV0frame", kTH1F, {axisPx}); + registryData.add("JetQA/JetpyInJetV0frame", "JetpyInJetV0frame", kTH1F, {axisPy}); + registryData.add("JetQA/JetpzInJetV0frame", "JetpzInJetV0frame", kTH1F, {axisPz}); + registryData.add("JetQA/JetptInJetV0frame", "JetptInJetV0frame", kTH1F, {axisPT}); + + registryData.add("V0LambdapxInJetV0frame", "V0LambdapxInJetV0frame", kTH1F, {axisPx}); + registryData.add("V0LambdapyInJetV0frame", "V0LambdapyInJetV0frame", kTH1F, {axisPy}); + registryData.add("V0LambdapzInJetV0frame", "V0LambdapzInJetV0frame", kTH1F, {axisPz}); + + registryData.add("hprotonPhi", "hprotonPhi", kTH1F, {axisPhi}); + registryData.add("hantiprotonPhi", "hantiprotonPhi", kTH1F, {axisPhi}); + + registryData.add("hLambdamassandSinPhi", "hLambdamassandSinPhi", kTH2F, {{200, 0.9, 1.2}, {200, -1, 1}}); + registryData.add("profileLambda", "Invariant Mass vs sin(phi)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("hLambdaPhiandSinPhi", "hLambdaPhiandSinPhi", kTH2F, {{200, -TMath::Pi() / 2, TMath::Pi() / 2}, {200, -1, 1}}); + registryData.add("V0LambdaprotonPhi", "V0LambdaprotonPhi", {HistType::kTH1F, {{200, -TMath::Pi() / 2, TMath::Pi() / 2}}}); + + registryData.add("profileAntiLambda", "Invariant Mass vs sin(phi)", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("TProfile1DLambdasinphiInJet", "#Delta #theta vs sin(phi)", {HistType::kTProfile, {{200, 0.0, TMath::Pi()}}}); + registryData.add("hAntiLambdamassandSinPhi", "hAntiLambdaPhiandSinPhi", kTH2F, {{200, -TMath::Pi() / 2, TMath::Pi() / 2}, {200, -1, 1}}); + registryData.add("hprotonsinphiInJetV0frame", "hprotonsinphiInJetV0frame", kTH1F, {axisSinPhi}); + registryData.add("TProfile2DLambdaPtMassSinPhi", "", kTProfile2D, {TProfile2DaxisMass, TProfile2DaxisPt}); + registryData.add("TProfile2DAntiLambdaPtMassSinPhi", "", kTProfile2D, {TProfile2DaxisMass, TProfile2DaxisPt}); + registryData.add("TProfile2DLambdaPtMassSintheta", "", kTProfile2D, {TProfile2DaxisMass, TProfile2DaxisPt}); + registryData.add("TProfile2DAntiLambdaPtMassSintheta", "", kTProfile2D, {TProfile2DaxisMass, TProfile2DaxisPt}); + + registryData.add("TProfile2DLambdaPtMassCosSquareTheta", "", kTProfile2D, {TProfile2DaxisMass, TProfile2DaxisPt}); + registryData.add("TProfile2DAntiLambdaPtMassCosSquareTheta", "", kTProfile2D, {TProfile2DaxisMass, TProfile2DaxisPt}); + registryData.add("TProfile2DLambdaMassDeltaPhi", "", kTProfile2D, {{200, -TMath::Pi(), TMath::Pi(), "#Delta#varphi"}, TProfile2DaxisMass}); + registryData.add("TProfile2DLambdaMassDeltaTheta", "", kTProfile2D, {{200, 0, TMath::Pi(), "#Delta#theta"}, TProfile2DaxisMass}); + registryData.add("TProfile2DAntiLambdaMassDeltaPhi", "", kTProfile2D, {{200, -TMath::Pi(), TMath::Pi(), "#Delta#varphi"}, TProfile2DaxisMass}); + registryData.add("hprotonThetaInLab", "hprotonThetaInLab", kTH1F, {axisTheta}); + registryData.add("hprotonThetaInV0", "hprotonThetaInV0", kTH1F, {axisTheta}); + registryData.add("hprotonThetaInJetV0", "hprotonThetaInJetV0", kTH1F, {axisTheta}); + + registryData.add("LambdaQA/TH2FLambdaMassPhiInJet", "TH2FLambdaMassPhiInJet", kTH2F, {{200, -TMath::Pi(), TMath::Pi()}, {200, 0.9, 1.2}}); + + // Lab frame measures + registryData.add("LambdaQA/TH2FprotonCosThetaInLab", "TH2FprotonCosThetaInLab", kTH2F, {{200, 0.9, 1.2}, {200, -1.0, 1.0}}); + registryData.add("LambdaQA/TProfile1DprotonCosThetaInLab", "TProfile1DprotonCosThetaInLab", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("LambdaQA/TProfile1DprotonCos2ThetaInLab", "TProfile1DprotonCos2ThetaInLab", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + + // V0(Lambda) frame messages + registryData.add("LambdaQA/TH2FprotonCosThetaInV0", "TH2FprotonCosThetaInV0", kTH2F, {{200, 0.9, 1.2}, {200, -1.0, 1.0}}); + registryData.add("LambdaQA/TProfile1DprotonCosThetaInV0", "TProfile1DprotonCosThetaInV0", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("LambdaQA/TProfile1DprotonCos2ThetaInV0", "TProfile1DprotonCos2ThetaInV0", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + + // jet frame messages + registryData.add("LambdaQA/TH2FprotonCosThetaInJet", "TH2FprotonCosThetaInJet", kTH2F, {{200, 0.9, 1.2}, {200, -1.0, 1.0}}); + registryData.add("LambdaQA/TProfile1DprotonCosThetaInJet", "TProfile1DprotonCosThetaInJet", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("LambdaQA/TProfile1DprotonCos2ThetaInJet", "TProfile1DprotonCos2ThetaInJet", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + + // Jet-V0 frame messages + registryData.add("LambdaQA/TH2FprotonCosThetaInJetV0", "TH2FprotonCosThetaInJetV0", kTH2F, {{200, 0.9, 1.2}, {200, -1.0, 1.0}}); + registryData.add("LambdaQA/TProfile1DprotonCosThetaInJetV0", "TProfile1DprotonCosThetaInJetV0", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("LambdaQA/TProfile1DprotonCos2ThetaInJetV0", "TProfile1DprotonCos2ThetaInJetV0", {HistType::kTProfile, {{200, 0.9, 1.2}}}); + registryData.add("LambdaQA/TProfile2DprotonCosThetaInJetV0", "TProfile2DprotonCosThetaInJetV0", kTProfile2D, {TProfile2DaxisMass, axisPhi}); + registryData.add("LambdaQA/TProfile2DprotonCos2ThetaInJetV0", "TProfile2DprotonCos2ThetaInJetV0", kTProfile2D, {TProfile2DaxisMass, axisPhi}); + + registryData.add("hNEvents", "hNEvents", {HistType::kTH1D, {{10, 0.f, 10.f}}}); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "all"); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "sel8"); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "TVX"); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, "zvertex"); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(5, "TFBorder"); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(6, "ITSROFBorder"); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(7, "isTOFVertexMatched"); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(8, "isGoodZvtxFT0vsPV"); + registryData.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(9, "Applied selected"); + + if (doQA) { + registryData.add("QA/hv0sSelection", ";Sel", {HistType::kTH1D, {{22, 0., 22.}}}); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(1, "all"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(2, "Event selection"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(3, "Radius"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(4, "Eta Daughters"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(5, "Dau DCA to PV"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(6, "DCA Daughters"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(7, "min ITS hits"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(8, "has TOF 1 Leg"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(9, "has TOF 2 Legs"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(10, "TPC NCl"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(11, "TPC Cls Shared"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(12, "ITS Chi2"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(13, "TPC Chi2"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(14, "cosPA"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(15, "rapidity"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(16, "ctau"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(17, "v0 rej"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(18, "TPC nsigma Neg Dau"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(19, "TPC nsigma Pos Dau"); + registryData.get(HIST("QA/hv0sSelection"))->GetXaxis()->SetBinLabel(20, "Armenteros-Podolansky"); + } + } + double massPr = o2::constants::physics::MassProton; + double massLambda = o2::constants::physics::MassLambda; + double massPi = o2::constants::physics::MassPionCharged; + ROOT::Math::PxPyPzMVector ProtonVec, PionVec, LambdaVec, ProtonBoostedVec, LambdaBoostedVec; + + 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; + } + // The direction of jet is z axis, y is perpendicular to jet and lambda momentum + 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; + } + // New transformation: The direction of jet is x axis, z is perpendicular to jet and lambda momentum + TMatrixD TMatrixTranslationToJet(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_z = (JetP.Cross(V0LambdaP)); + + TVector3 x_hat = JetP.Unit(); + TVector3 z_hat = vortex_z.Unit(); + TVector3 y_hat = z_hat.Cross(x_hat); + + 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 + + // 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.9; + 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; + } + + // init Selection + template + bool passedInitLambdaSelection(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + if (v0.v0radius() < v0radius || v0.v0cosPA() < v0cospainit || + TMath::Abs(ptrack.eta()) > V0tracketaMax || + TMath::Abs(ntrack.eta()) > V0tracketaMax) { + 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; + } + + template + bool AcceptV0Lambda(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack, const TCollision& collision) + { + // Single-Track Selections + if (requirepassedSingleTrackSelection && !passedSingleTrackSelection(ptrack)) + return false; + if (requirepassedSingleTrackSelection && !passedSingleTrackSelection(ntrack)) + return false; + + int evFlag = 0; + if (collision.isInelGt0()) { + evFlag = 1; + } + + if (evSel && evFlag < 1) + return false; + + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + + if (TMath::Abs(ptrack.eta()) > V0tracketaMax || TMath::Abs(ntrack.eta()) > V0tracketaMax) { + return false; + } + + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + + if (requireITS && ptrack.itsNCls() < minITSnCls) + return false; + if (requireITS && ntrack.itsNCls() < minITSnCls) + return false; + + if (hasTOF1Leg && !ptrack.hasTOF() && !ntrack.hasTOF()) + return false; + + if (hasTOF2Leg && (!ptrack.hasTOF() || !ntrack.hasTOF())) + return false; + + if (ptrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (ntrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + + if (ptrack.tpcNClsShared() > max_tpcSharedCls) + return false; + if (ntrack.tpcNClsShared() > max_tpcSharedCls) + return false; + + if (ptrack.itsChi2NCl() > max_chi2_ITS) + return false; + if (ntrack.itsChi2NCl() > max_chi2_ITS) + return false; + + if (ptrack.tpcChi2NCl() > max_chi2_TPC) + return false; + if (ntrack.tpcChi2NCl() > max_chi2_TPC) + return false; + + if (v0.v0cosPA() < v0cospaMin) + return false; + + if (v0.yLambda() < yMin || v0.yLambda() > yMax) { + return false; + } + + float ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + if (ctauLambda >= CtauLambda) + return false; + + if (TMath::Abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0rejLambda) { + return false; + } + if (std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0accLambda) { + return false; + } + + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + + if (doArmenterosCut && v0.qtarm() > (paramArmenterosCut * std::abs(v0.alpha()))) + return false; + + return true; + } + + template + bool AcceptV0AntiLambda(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack, const TCollision& collision) + { + // Single-Track Selections + if (requirepassedSingleTrackSelection && !passedSingleTrackSelection(ptrack)) + return false; + if (requirepassedSingleTrackSelection && !passedSingleTrackSelection(ntrack)) + return false; + + int evFlag = 0; + if (collision.isInelGt0()) { + evFlag = 1; + } + + if (evSel && evFlag < 1) + return false; + + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + + if (TMath::Abs(ptrack.eta()) > V0tracketaMax || TMath::Abs(ntrack.eta()) > V0tracketaMax) { + return false; + } + + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + + if (requireITS && ptrack.itsNCls() < minITSnCls) + return false; + if (requireITS && ntrack.itsNCls() < minITSnCls) + return false; + + if (hasTOF1Leg && !ptrack.hasTOF() && !ntrack.hasTOF()) + return false; + + if (hasTOF2Leg && (!ptrack.hasTOF() || !ntrack.hasTOF())) + return false; + + if (ptrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (ntrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + + if (ptrack.tpcNClsShared() > max_tpcSharedCls) + return false; + if (ntrack.tpcNClsShared() > max_tpcSharedCls) + return false; + + if (ptrack.itsChi2NCl() > max_chi2_ITS) + return false; + if (ntrack.itsChi2NCl() > max_chi2_ITS) + return false; + + if (ptrack.tpcChi2NCl() > max_chi2_TPC) + return false; + if (ntrack.tpcChi2NCl() > max_chi2_TPC) + return false; + + if (v0.v0cosPA() < v0cospaMin) + return false; + + if (v0.yLambda() < yMin || v0.yLambda() > yMax) { + return false; + } + + float ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; + if (ctauAntiLambda >= CtauLambda) + return false; + + if (TMath::Abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0rejLambda) { + return false; + } + if (std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0accLambda) { + return false; + } + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + if (doArmenterosCut && v0.qtarm() > (paramArmenterosCut * std::abs(v0.alpha()))) + return false; + + return true; + } + + template + bool registryDataAcceptV0Lambda(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack, const TCollision& collision) + { + + int evFlag = 0; + if (collision.isInelGt0()) { + evFlag = 1; + } + + registryData.fill(HIST("QA/hv0sSelection"), 0.5); + + if (evSel && evFlag < 1) + return false; + + registryData.fill(HIST("QA/hv0sSelection"), 1.5); + + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + + registryData.fill(HIST("QA/hv0sSelection"), 2.5); + + if (TMath::Abs(ptrack.eta()) > V0tracketaMax || TMath::Abs(ntrack.eta()) > V0tracketaMax) { + return false; + } + registryData.fill(HIST("QA/hv0sSelection"), 3.5); + + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 4.5); + + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 5.5); + + if (requireITS && ptrack.itsNCls() < minITSnCls) + return false; + if (requireITS && ntrack.itsNCls() < minITSnCls) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 6.5); + + if (hasTOF1Leg && !ptrack.hasTOF() && !ntrack.hasTOF()) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 7.5); + + if (hasTOF2Leg && (!ptrack.hasTOF() || !ntrack.hasTOF())) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 8.5); + + if (ptrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (ntrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 9.5); + + if (require_max_tpcSharedCls && ptrack.tpcNClsShared() > max_tpcSharedCls) + return false; + if (require_max_tpcSharedCls && ntrack.tpcNClsShared() > max_tpcSharedCls) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 10.5); + + if (ptrack.itsChi2NCl() > max_chi2_ITS) + return false; + if (ntrack.itsChi2NCl() > max_chi2_ITS) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 11.5); + + if (ptrack.tpcChi2NCl() > max_chi2_TPC) + return false; + if (ntrack.tpcChi2NCl() > max_chi2_TPC) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 12.5); + + if (v0.v0cosPA() < v0cospaMin) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 13.5); + + if (v0.yLambda() < yMin || v0.yLambda() > yMax) { + return false; + } + registryData.fill(HIST("QA/hv0sSelection"), 14.5); + + float ctauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + if (ctauLambda >= CtauLambda) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 15.5); + + if (TMath::Abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0rejLambda) { + return false; + } + if (std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0accLambda) { + return false; + } + + registryData.fill(HIST("QA/hv0sSelection"), 16.5); + + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 17.5); + + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 18.5); + + if (doArmenterosCut && v0.qtarm() > (paramArmenterosCut * std::abs(v0.alpha()))) + return false; + registryData.fill(HIST("QA/hv0sSelection"), 19.5); + + return true; + } + + template + bool registryDataAcceptV0AntiLambda(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack, const TCollision& collision) + { + + int evFlag = 0; + if (collision.isInelGt0()) { + evFlag = 1; + } + + if (evSel && evFlag < 1) + return false; + + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + + if (TMath::Abs(ptrack.eta()) > V0tracketaMax || TMath::Abs(ntrack.eta()) > V0tracketaMax) { + return false; + } + + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + + if (requireITS && ptrack.itsNCls() < minITSnCls) + return false; + if (requireITS && ntrack.itsNCls() < minITSnCls) + return false; + + if (hasTOF1Leg && !ptrack.hasTOF() && !ntrack.hasTOF()) + return false; + + if (hasTOF2Leg && (!ptrack.hasTOF() || !ntrack.hasTOF())) + return false; + + if (ptrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (ntrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + + if (ptrack.tpcNClsShared() > max_tpcSharedCls) + return false; + if (ntrack.tpcNClsShared() > max_tpcSharedCls) + return false; + + if (ptrack.itsChi2NCl() > max_chi2_ITS) + return false; + if (ntrack.itsChi2NCl() > max_chi2_ITS) + return false; + + if (ptrack.tpcChi2NCl() > max_chi2_TPC) + return false; + if (ntrack.tpcChi2NCl() > max_chi2_TPC) + return false; + + if (v0.v0cosPA() < v0cospaMin) + return false; + + if (v0.yLambda() < yMin || v0.yLambda() > yMax) { + return false; + } + + float ctauAntiLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0Bar; + if (ctauAntiLambda >= CtauLambda) + return false; + + if (TMath::Abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0rejLambda) { + return false; + } + if (std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0accLambda) { + return false; + } + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + if (doArmenterosCut && v0.qtarm() > (paramArmenterosCut * std::abs(v0.alpha()))) + return false; + + return true; + } + + // Lambda Selections + template + bool passedLambdaSelection(const Lambda& 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.v0radius() > maximumV0Radius) + return false; + + if (TMath::Abs(ptrack.eta()) > V0tracketaMax || TMath::Abs(ntrack.eta()) > V0tracketaMax) { + return false; + } + + if (std::fabs(v0.dcapostopv()) < dcapostoPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin) + return false; + + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + + if (requireITS && ptrack.itsNCls() < minITSnCls) + return false; + if (requireITS && ntrack.itsNCls() < minITSnCls) + return false; + + if (hasTOF1Leg && !ptrack.hasTOF() && !ntrack.hasTOF()) + return false; + + if (hasTOF2Leg && (!ptrack.hasTOF() || !ntrack.hasTOF())) + return false; + + if (ptrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + if (ntrack.tpcNClsCrossedRows() < minNCrossedRowsTPC) + return false; + + if (ptrack.tpcNClsShared() > max_tpcSharedCls) + return false; + if (ntrack.tpcNClsShared() > max_tpcSharedCls) + return false; + + if (ptrack.itsChi2NCl() > max_chi2_ITS) + return false; + if (ntrack.itsChi2NCl() > max_chi2_ITS) + return false; + + if (ptrack.tpcChi2NCl() > max_chi2_TPC) + return false; + if (ntrack.tpcChi2NCl() > max_chi2_TPC) + return false; + + if (v0.v0cosPA() < v0cospaMin) + return false; + + if (v0.yLambda() < yMin || v0.yLambda() > yMax) { + 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; + } + // PID Selections (TOF) + 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) > v0accLambda) { + return false; + } + if (doArmenterosCut && v0.qtarm() > (paramArmenterosCut * std::abs(v0.alpha()))) + 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; + + // 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; + + if (TMath::Abs(ptrack.eta()) > V0tracketaMax || TMath::Abs(ntrack.eta()) > V0tracketaMax) { + return false; + } + + // PID Selections (TPC) + if (requireTPC) { + 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; + } + 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) > v0accLambda) { + return false; + } + if (doArmenterosCut && v0.qtarm() > (paramArmenterosCut * std::abs(v0.alpha()))) + 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; + } + + ///////Event selection + template + bool AcceptEvent(TCollision const& collision) + { + if (sel8 && !collision.sel8()) { + return false; + } + registryData.fill(HIST("hNEvents"), 1.5); + + if (isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + registryData.fill(HIST("hNEvents"), 2.5); + + if (iscutzvertex && TMath::Abs(collision.posZ()) > cutzvertex) { + return false; + } + registryData.fill(HIST("hNEvents"), 3.5); + + if (isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + registryData.fill(HIST("hNEvents"), 4.5); + + if (isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + registryData.fill(HIST("hNEvents"), 5.5); + if (isVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + registryData.fill(HIST("hNEvents"), 6.5); + if (isGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + registryData.fill(HIST("hNEvents"), 7.5); + + return true; + } + + template + bool AcceptEventForLongitudinalPolarization(TCollision const& collision) + { + + if (sel8 && !collision.sel8()) { + return false; + } + + if (isTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + + if (std::abs(collision.posZ()) > cutzvertex) { + return false; + } + + if (isNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + + if (isNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + + if (isVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + return false; + } + + if (isNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + + return true; + } + + using SelCollisions = soa::Join; + using SelV0Collisions = soa::Join; + using StrHadronDaughterTracks = soa::Join; + void processData(SelV0Collisions::iterator const& collision, aod::V0Datas const& fullV0s, StrHadronDaughterTracks const& tracks) + { + registryData.fill(HIST("hNEvents"), 0.5); + if (!AcceptEvent(collision)) { + return; + } + registryData.fill(HIST("hNEvents"), 8.5); + // event selection + // loop over reconstructed tracks + std::vector fjParticles; + for (auto const& track : tracks) { + registryData.fill(HIST("h_track_pt"), track.pt()); + registryData.fill(HIST("h_track_eta"), track.eta()); + registryData.fill(HIST("h_track_phi"), track.phi()); + if (ispassdTrackSelectionForJetReconstruction && !passedTrackSelectionForJetReconstruction(track)) { + continue; + } + registryData.fill(HIST("h_track_pt_sel"), track.pt()); + registryData.fill(HIST("h_track_eta_sel"), track.eta()); + registryData.fill(HIST("h_track_phi_sel"), track.phi()); + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + // reject empty events + if (fjParticles.size() < 1) + return; + // cluster particles using the anti-kt algorithm + fastjet::RecombinationScheme recombScheme = fastjet::E_scheme; + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet, recombScheme); + 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()); + + // jet selection + bool isAtLeastOneJetSelected = false; + int nJets = 0; + int nJetssel = 0; + // select most large momentum jet + float maxJetpx = 0; + float maxJetpy = 0; + float maxJetpz = 0; + float maxJeteta = 0; + float maxJetphi = 0; + float maxJetE = 0; + float maxJetpT = 0; + float maxJetPt = -999; + for (auto& jet : jets) { + nJets++; + registryData.fill(HIST("FJetaHistogram"), jet.eta()); + registryData.fill(HIST("FJphiHistogram"), jet.phi()); + registryData.fill(HIST("FJptHistogram"), jet.pt()); + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - deltaEtaEdge)) { + continue; + } + + if (jet.pt() < cfgjetPtMin) + continue; + nJetssel++; + registryData.fill(HIST("FJetaHistogramsel"), jet.eta()); + registryData.fill(HIST("FJphiHistogramsel"), jet.phi()); + registryData.fill(HIST("FJptHistogramsel"), jet.pt()); + + if (jet.pt() > maxJetPt) { + maxJetpx = jet.px(); + maxJetpy = jet.py(); + maxJetpz = jet.pz(); + maxJeteta = jet.eta(); + maxJetE = jet.E(); + maxJetphi = jet.phi(); + maxJetpT = jet.pt(); + maxJetPt = maxJetpT; + } + } + if (maxJetpT > 0) { + registryData.fill(HIST("FLeadingJetaHistogramsel"), maxJeteta); + registryData.fill(HIST("FLeadingJphiHistogramsel"), maxJetphi); + registryData.fill(HIST("FLeadingJptHistogramsel"), maxJetpT); + } + registryData.fill(HIST("nJetsPerEvent"), nJets); + registryData.fill(HIST("nJetsPerEventsel"), nJetssel); + isAtLeastOneJetSelected = true; + if (!isAtLeastOneJetSelected) { + return; + } + + // Event multiplicity + const float multiplicity = collision.centFT0M(); + registryData.fill(HIST("number_of_events_vsmultiplicity"), multiplicity); + // v0 loop + int V0Numbers = 0; + int AntiV0Numbers = 0; + 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()); + if (registryDataAcceptV0Lambda(v0, pos, neg, collision)) { + V0Numbers = V0Numbers + 1; + registryData.fill(HIST("LambdaPtMass"), v0.pt(), v0.mLambda()); + } + if (registryDataAcceptV0AntiLambda(v0, pos, neg, collision)) { + AntiV0Numbers = AntiV0Numbers + 1; + registryData.fill(HIST("AntiLambdaPtMass"), v0.pt(), v0.mAntiLambda()); + } + } + registryData.fill(HIST("nV0sPerEvent"), V0Numbers); + + // calculate lambda polarization induced by jet + + if (V0Numbers == 0 && AntiV0Numbers == 0) { + return; + } + if (maxJetpx == 0) { + return; + } + double protonsinPhiInJetV0frame = 0; + double AntiprotonsinPhiInJetV0frame = 0; + for (const auto& candidate : fullV0s) { + const auto& pos = candidate.posTrack_as(); + const auto& neg = candidate.negTrack_as(); + TVector3 v0dir(candidate.px(), candidate.py(), candidate.pz()); + + if (registryDataAcceptV0Lambda(candidate, pos, neg, collision)) { + registryData.fill(HIST("hMassLambda"), candidate.mLambda()); + registryData.fill(HIST("V0pTInLab"), candidate.pt()); + registryData.fill(HIST("V0pxInLab"), candidate.px()); + registryData.fill(HIST("V0pyInLab"), candidate.py()); + registryData.fill(HIST("V0pzInLab"), candidate.pz()); + registryData.fill(HIST("protonQA/V0protonpxInLab"), pos.px()); + registryData.fill(HIST("protonQA/V0protonpyInLab"), pos.py()); + registryData.fill(HIST("protonQA/V0protonpzInLab"), pos.pz()); + + double PLambda = sqrt(candidate.px() * candidate.px() + candidate.py() * candidate.py() + candidate.pz() * candidate.pz()); + double ELambda = sqrt(candidate.mLambda() * candidate.mLambda() + PLambda * PLambda); + double protonE = sqrt(massPr * massPr + pos.px() * pos.px() + pos.py() * pos.py() + pos.pz() * pos.pz()); + + TMatrixD pLabJet(4, 1); + pLabJet(0, 0) = maxJetE; + pLabJet(1, 0) = maxJetpx; + pLabJet(2, 0) = maxJetpy; + pLabJet(3, 0) = maxJetpz; + + TMatrixD pLabV0(4, 1); + pLabV0(0, 0) = ELambda; + pLabV0(1, 0) = candidate.px(); + pLabV0(2, 0) = candidate.py(); + pLabV0(3, 0) = candidate.pz(); + + TMatrixD V0InV0(4, 1); + V0InV0 = LorentzTransInV0frame(ELambda, candidate.px(), candidate.py(), candidate.pz()) * pLabV0; + registryData.fill(HIST("V0pxInRest_frame"), V0InV0(1, 0)); + registryData.fill(HIST("V0pyInRest_frame"), V0InV0(2, 0)); + registryData.fill(HIST("V0pzInRest_frame"), V0InV0(3, 0)); + + TMatrixD lambdaInJet(4, 1); + lambdaInJet = MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabV0; + double cosThetaLambdaInJet = lambdaInJet(3, 0) / sqrt(lambdaInJet(1, 0) * lambdaInJet(1, 0) + lambdaInJet(2, 0) * lambdaInJet(2, 0) + lambdaInJet(3, 0) * lambdaInJet(3, 0)); + double lambdasinphiInJet = lambdaInJet(2, 0) / sqrt(lambdaInJet(1, 0) * lambdaInJet(1, 0) + lambdaInJet(2, 0) * lambdaInJet(2, 0)); + registryData.fill(HIST("TProfile2DLambdaMassDeltaTheta"), TMath::ACos(cosThetaLambdaInJet), candidate.mLambda(), lambdasinphiInJet); + registryData.fill(HIST("TProfile1DLambdasinphiInJet"), TMath::ACos(cosThetaLambdaInJet), lambdasinphiInJet); + + registryData.fill(HIST("V0pxInJetframe"), lambdaInJet(1, 0)); + registryData.fill(HIST("V0pyInJetframe"), lambdaInJet(2, 0)); + registryData.fill(HIST("V0pzInJetframe"), lambdaInJet(3, 0)); + + TMatrixD lambdaInJetV0(4, 1); + lambdaInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabV0; + registryData.fill(HIST("V0LambdapxInJetV0frame"), lambdaInJetV0(1, 0)); + registryData.fill(HIST("V0LambdapyInJetV0frame"), lambdaInJetV0(2, 0)); + registryData.fill(HIST("V0LambdapzInJetV0frame"), lambdaInJetV0(3, 0)); + + TMatrixD pLabproton(4, 1); + pLabproton(0, 0) = protonE; + pLabproton(1, 0) = pos.px(); + pLabproton(2, 0) = pos.py(); + pLabproton(3, 0) = pos.pz(); + double protonsinPhiInLab = pLabproton(2, 0) / sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0)); + double protoncosthetaInLab = pLabproton(3, 0) / sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0) + pLabproton(3, 0) * pLabproton(3, 0)); + double protonPtInLab = sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0)); + double protonPInLab = sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0) + pLabproton(3, 0) * pLabproton(3, 0)); + double protonsinThetaInLab = protonPtInLab / protonPInLab; + double protonMassInLab = sqrt(pLabproton(0, 0) * pLabproton(0, 0) - pLabproton(1, 0) * pLabproton(1, 0) - pLabproton(2, 0) * pLabproton(2, 0) - pLabproton(3, 0) * pLabproton(3, 0)); + double jettheta = maxJetpz / sqrt(pLabJet(1, 0) * pLabJet(1, 0) + pLabJet(2, 0) * pLabJet(2, 0) + pLabJet(3, 0) * pLabJet(3, 0)); + double jetphi = maxJetpy / sqrt(pLabJet(1, 0) * pLabJet(1, 0) + pLabJet(2, 0) * pLabJet(2, 0)); + double jetptInLab = sqrt(pLabJet(1, 0) * pLabJet(1, 0) + pLabJet(2, 0) * pLabJet(2, 0)); + registryData.fill(HIST("JetQA/JetthetaInLab"), TMath::ASin(jettheta)); + registryData.fill(HIST("JetQA/JetphiInLab"), TMath::ASin(jetphi)); + registryData.fill(HIST("JetQA/JetpxInLab"), pLabJet(1, 0)); + registryData.fill(HIST("JetQA/JetpyInLab"), pLabJet(2, 0)); + registryData.fill(HIST("JetQA/JetpzInLab"), pLabJet(3, 0)); + registryData.fill(HIST("JetQA/JetptInLab"), jetptInLab); + + registryData.fill(HIST("protonQA/V0protonphiInLab"), TMath::ASin(protonsinPhiInLab)); + registryData.fill(HIST("protonQA/V0protonthetaInLab"), TMath::ACos(protoncosthetaInLab)); + registryData.fill(HIST("protonQA/V0protoncosthetaInLab"), protoncosthetaInLab); + registryData.fill(HIST("protonQA/profileprotonsinthetaInLab"), candidate.mLambda(), protonsinThetaInLab); + registryData.fill(HIST("protonQA/profileprotonsinphiInLab"), candidate.mLambda(), protonsinPhiInLab); + registryData.fill(HIST("protonQA/profileprotoncosSquarethetaInLab"), candidate.mLambda(), protoncosthetaInLab * protoncosthetaInLab); + registryData.fill(HIST("protonQA/V0protonMassInLab"), protonMassInLab); + + TMatrixD protonInV0(4, 1); + protonInV0 = LorentzTransInV0frame(ELambda, candidate.px(), candidate.py(), candidate.pz()) * 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)); + double protonPInV0 = sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0) + protonInV0(3, 0) * protonInV0(3, 0)); + double protonPtInV0 = sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0)); + double protonsinThetaInV0 = protonPtInV0 / protonPInV0; + + TMatrixD JetInV0(4, 1); + JetInV0 = LorentzTransInV0frame(ELambda, candidate.px(), candidate.py(), candidate.pz()) * pLabJet; + double jetthetaInV0 = JetInV0(3, 0) / sqrt(JetInV0(1, 0) * JetInV0(1, 0) + JetInV0(2, 0) * JetInV0(2, 0) + JetInV0(3, 0) * JetInV0(3, 0)); + double jetphiInV0 = JetInV0(2, 0) / sqrt(JetInV0(1, 0) * JetInV0(1, 0) + JetInV0(2, 0) * JetInV0(2, 0)); + double jetptInV0 = sqrt(JetInV0(1, 0) * JetInV0(1, 0) + JetInV0(2, 0) * JetInV0(2, 0)); + registryData.fill(HIST("JetQA/JetthetaInV0"), TMath::ASin(jetthetaInV0)); + registryData.fill(HIST("JetQA/JetphiInV0"), TMath::ASin(jetphiInV0)); + registryData.fill(HIST("JetQA/JetpxInV0"), JetInV0(1, 0)); + registryData.fill(HIST("JetQA/JetpyInV0"), JetInV0(2, 0)); + registryData.fill(HIST("JetQA/JetpzInV0"), JetInV0(3, 0)); + registryData.fill(HIST("JetQA/JetptInV0"), jetptInV0); + + registryData.fill(HIST("protonQA/V0protonMassInRest_frame"), protonMassInV0); + registryData.fill(HIST("protonQA/V0protonpxInRest_frame"), protonInV0(1, 0)); + registryData.fill(HIST("protonQA/V0protonpyInRest_frame"), protonInV0(2, 0)); + registryData.fill(HIST("protonQA/V0protonpzInRest_frame"), protonInV0(3, 0)); + double protonsinPhiInV0frame = protonInV0(2, 0) / sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0)); + double protoncosthetaInV0frame = protonInV0(3, 0) / sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0) + protonInV0(3, 0) * protonInV0(3, 0)); + registryData.fill(HIST("protonQA/V0protonphiInRest_frame"), TMath::ASin(protonsinPhiInV0frame)); + registryData.fill(HIST("protonQA/V0protonthetaInRest_frame"), TMath::ACos(protoncosthetaInV0frame)); + registryData.fill(HIST("protonQA/V0protoncosthetaInV0frame"), protoncosthetaInV0frame); + registryData.fill(HIST("protonQA/profileprotonsinthetaInV0frame"), candidate.mLambda(), protonsinThetaInV0); + registryData.fill(HIST("protonQA/profileprotonsinphiInV0frame"), candidate.mLambda(), protonsinPhiInV0frame); + registryData.fill(HIST("protonQA/profileprotoncosSquarethetaInV0frame"), candidate.mLambda(), protoncosthetaInV0frame * protoncosthetaInV0frame); + + TMatrixD protonInJet(4, 1); + protonInJet = MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabproton; + double protoncosthetaInJet = protonInJet(3, 0) / sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0) + protonInJet(3, 0) * protonInJet(3, 0)); + double protonsinPhiInJet = protonInJet(2, 0) / sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0)); + double protonPtinJet = sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0)); + double protonPinJet = sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0) + protonInJet(3, 0) * protonInJet(3, 0)); + double protonSinThetainJet = protonPtinJet / protonPinJet; + double protonMassInJetframe = sqrt(protonInJet(0, 0) * protonInJet(0, 0) - protonInJet(1, 0) * protonInJet(1, 0) - protonInJet(2, 0) * protonInJet(2, 0) - protonInJet(3, 0) * protonInJet(3, 0)); + + TMatrixD pInJet(4, 1); + pInJet = MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabJet; + double jetthetaInJet = pInJet(3, 0) / sqrt(pInJet(1, 0) * pInJet(1, 0) + pInJet(2, 0) * pInJet(2, 0) + pInJet(3, 0) * pInJet(3, 0)); + double jetphiInJet = pInJet(2, 0) / sqrt(pInJet(1, 0) * pInJet(1, 0) + pInJet(2, 0) * pInJet(2, 0)); + double jetptInJet = sqrt(pInJet(1, 0) * pInJet(1, 0) + pInJet(2, 0) * pInJet(2, 0)); + registryData.fill(HIST("JetQA/JetthetaInJetframe"), TMath::ASin(jetthetaInJet)); + registryData.fill(HIST("JetQA/JetphiInJetframe"), TMath::ASin(jetphiInJet)); + registryData.fill(HIST("JetQA/JetpxInJetframe"), pInJet(1, 0)); + registryData.fill(HIST("JetQA/JetpyInJetframe"), pInJet(2, 0)); + registryData.fill(HIST("JetQA/JetpzInJetframe"), pInJet(3, 0)); + registryData.fill(HIST("JetQA/JetptInJetframe"), jetptInJet); + + registryData.fill(HIST("protonQA/V0protonpxInJetframe"), protonInJet(1, 0)); + registryData.fill(HIST("protonQA/V0protonpyInJetframe"), protonInJet(2, 0)); + registryData.fill(HIST("protonQA/V0protonpzInJetframe"), protonInJet(3, 0)); + registryData.fill(HIST("protonQA/V0protonphiInJetframe"), TMath::ASin(protonsinPhiInJet)); + registryData.fill(HIST("protonQA/V0protonthetaInJetframe"), TMath::ACos(protoncosthetaInJet)); + registryData.fill(HIST("protonQA/V0protoncosthetaInJetframe"), protoncosthetaInJet); + registryData.fill(HIST("protonQA/profileprotonsinthetaInJetframe"), candidate.mLambda(), protonSinThetainJet); + registryData.fill(HIST("protonQA/profileprotonsinphiInJetframe"), candidate.mLambda(), protonsinPhiInJet); + registryData.fill(HIST("protonQA/profileprotoncosSquarethetaInJetframe"), candidate.mLambda(), protoncosthetaInJet * protoncosthetaInJet); + registryData.fill(HIST("protonQA/V0protonMassInJetframe"), protonMassInJetframe); + + TMatrixD protonInJetV0(4, 1); + protonInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabproton; + double protoncosthetaInJetV0 = protonInJetV0(3, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0) + protonInJetV0(3, 0) * protonInJetV0(3, 0)); + double protonsinphiInJetV0 = protonInJetV0(2, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0)); + double protonPtinJetV0 = sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0)); + double protonPinJetV0 = sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0) + protonInJetV0(3, 0) * protonInJetV0(3, 0)); + double protonSinThetainJetV0 = protonPtinJetV0 / protonPinJetV0; + double protonMassInJetV0frame = sqrt(protonInJetV0(0, 0) * protonInJetV0(0, 0) - protonInJetV0(1, 0) * protonInJetV0(1, 0) - protonInJetV0(2, 0) * protonInJetV0(2, 0) - protonInJetV0(3, 0) * protonInJetV0(3, 0)); + + TMatrixD JetInJetV0(4, 1); + JetInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabJet; + double jetthetaInJetV0 = JetInJetV0(3, 0) / sqrt(JetInJetV0(1, 0) * JetInJetV0(1, 0) + JetInJetV0(2, 0) * JetInJetV0(2, 0) + JetInJetV0(3, 0) * JetInJetV0(3, 0)); + double jetphiInJetV0 = JetInJetV0(2, 0) / sqrt(JetInJetV0(1, 0) * JetInJetV0(1, 0) + JetInJetV0(2, 0) * JetInJetV0(2, 0)); + double jetptInJetV0 = sqrt(JetInJetV0(1, 0) * JetInJetV0(1, 0) + JetInJetV0(2, 0) * JetInJetV0(2, 0)); + registryData.fill(HIST("JetQA/JetthetaInJetV0frame"), TMath::ASin(jetthetaInJetV0)); + registryData.fill(HIST("JetQA/JetphiInJetV0frame"), TMath::ASin(jetphiInJetV0)); + registryData.fill(HIST("JetQA/JetpxInJetV0frame"), JetInJetV0(1, 0)); + registryData.fill(HIST("JetQA/JetpyInJetV0frame"), JetInJetV0(2, 0)); + registryData.fill(HIST("JetQA/JetpzInJetV0frame"), JetInJetV0(3, 0)); + registryData.fill(HIST("JetQA/JetptInJetV0frame"), jetptInJetV0); + + registryData.fill(HIST("protonQA/V0protonpxInJetV0frame"), protonInJetV0(1, 0)); + registryData.fill(HIST("protonQA/V0protonpyInJetV0frame"), protonInJetV0(2, 0)); + registryData.fill(HIST("protonQA/V0protonpzInJetV0frame"), protonInJetV0(3, 0)); + registryData.fill(HIST("protonQA/V0protonphiInJetV0frame"), TMath::ASin(protonsinphiInJetV0)); + registryData.fill(HIST("protonQA/V0protonthetaInJetV0frame"), TMath::ACos(protoncosthetaInJetV0)); + registryData.fill(HIST("protonQA/V0protoncosthetaInJetV0"), protoncosthetaInJetV0); + registryData.fill(HIST("protonQA/V0protonMassInJetV0frame"), protonMassInJetV0frame); + registryData.fill(HIST("protonQA/profileprotonsinthetaInJetV0frame"), candidate.mLambda(), protonSinThetainJetV0); + registryData.fill(HIST("protonQA/profileprotonsinphiInJetV0frame"), candidate.mLambda(), protonsinphiInJetV0); + registryData.fill(HIST("protonQA/profileprotoncosSquarethetaInJetV0frame"), candidate.mLambda(), protoncosthetaInJetV0 * protoncosthetaInJetV0); + + double protonCosThetainJetV0 = protonInJetV0(3, 0) / protonPinJetV0; + + protonsinPhiInJetV0frame = protonsinPhiInJetV0frame + protonInJetV0(2, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0)); + + registryData.fill(HIST("hprotonsinphiInJetV0frame"), protonsinPhiInJetV0frame); + + registryData.fill(HIST("TProfile2DLambdaPtMassSinPhi"), candidate.mLambda(), candidate.pt(), protonInJetV0(2, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0))); + registryData.fill(HIST("TProfile2DLambdaPtMassSintheta"), candidate.mLambda(), candidate.pt(), (4.0 / TMath::Pi()) * protonSinThetainJetV0); + registryData.fill(HIST("TProfile2DLambdaPtMassCosSquareTheta"), candidate.mLambda(), candidate.pt(), 3.0 * protonCosThetainJetV0 * protonCosThetainJetV0); + registryData.fill(HIST("TProfile2DLambdaMassDeltaPhi"), TMath::ASin(protonsinPhiInJetV0frame), candidate.mLambda(), protonsinPhiInJetV0frame); + registryData.fill(HIST("hprotonPhi"), TMath::ASin(protonsinPhiInJetV0frame)); + + double protonCosThetaInLab = pLabproton(3, 0) / sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0) + pLabproton(3, 0) * pLabproton(3, 0)); // cos(theta) of lambda in lab frame + double protonCosThetaInV0frame = protonInV0(3, 0) / sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0) + protonInV0(3, 0) * protonInV0(3, 0)); // cos(theta) of lambda in V0 frame + double protonCosThetaInJetV0frame = protonCosThetainJetV0; // cos(theta) of lambda in jet V0 frame + registryData.fill(HIST("hprotonThetaInLab"), TMath::ACos(protonCosThetaInLab)); + registryData.fill(HIST("hprotonThetaInV0"), TMath::ACos(protonCosThetaInV0frame)); + registryData.fill(HIST("hprotonThetaInJetV0"), TMath::ACos(protonCosThetaInJetV0frame)); + } + if (registryDataAcceptV0AntiLambda(candidate, pos, neg, collision)) { + registryData.fill(HIST("hMassAntiLambda"), candidate.mAntiLambda()); + double PAntiLambda = sqrt(candidate.px() * candidate.px() + candidate.py() * candidate.py() + candidate.pz() * candidate.pz()); + double EAntiLambda = sqrt(candidate.mAntiLambda() * candidate.mAntiLambda() + PAntiLambda * PAntiLambda); + double AntiprotonE = sqrt(massPr * massPr + neg.px() * neg.px() + neg.py() * neg.py() + neg.pz() * neg.pz()); + TMatrixD pLabAntiV0(4, 1); + pLabAntiV0(0, 0) = EAntiLambda; + pLabAntiV0(1, 0) = candidate.px(); + pLabAntiV0(2, 0) = candidate.py(); + pLabAntiV0(3, 0) = candidate.pz(); + + TMatrixD AntilambdaInJet(4, 1); + AntilambdaInJet = MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabAntiV0; + + TMatrixD pLabAntiproton(4, 1); + pLabAntiproton(0, 0) = AntiprotonE; + pLabAntiproton(1, 0) = neg.px(); + pLabAntiproton(2, 0) = neg.py(); + pLabAntiproton(3, 0) = neg.pz(); + TMatrixD AntiprotonInJetV0(4, 1); + AntiprotonInJetV0 = LorentzTransInV0frame(EAntiLambda, AntilambdaInJet(1, 0), AntilambdaInJet(2, 0), AntilambdaInJet(3, 0)) * MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabAntiproton; + AntiprotonsinPhiInJetV0frame = AntiprotonsinPhiInJetV0frame + AntiprotonInJetV0(2, 0) / sqrt(AntiprotonInJetV0(1, 0) * AntiprotonInJetV0(1, 0) + AntiprotonInJetV0(2, 0) * AntiprotonInJetV0(2, 0)); + TMatrixD AntiprotonInV0(4, 1); + AntiprotonInV0 = LorentzTransInV0frame(EAntiLambda, candidate.px(), candidate.py(), candidate.pz()) * pLabAntiproton; + double AntiprotonPinJetV0 = sqrt(AntiprotonInJetV0(1, 0) * AntiprotonInJetV0(1, 0) + AntiprotonInJetV0(2, 0) * AntiprotonInJetV0(2, 0) + AntiprotonInJetV0(3, 0) * AntiprotonInJetV0(3, 0)); + double AntiprotonPtinJetV0 = sqrt(AntiprotonInJetV0(1, 0) * AntiprotonInJetV0(1, 0) + AntiprotonInJetV0(2, 0) * AntiprotonInJetV0(2, 0)); + double AntiprotonCosThetainJetV0 = AntiprotonInJetV0(3, 0) / AntiprotonPinJetV0; + double AntiprotonSinThetainJetV0 = AntiprotonPtinJetV0 / AntiprotonPinJetV0; + registryData.fill(HIST("TProfile2DAntiLambdaPtMassSinPhi"), candidate.mAntiLambda(), candidate.pt(), AntiprotonInJetV0(2, 0) / sqrt(AntiprotonInJetV0(1, 0) * AntiprotonInJetV0(1, 0) + AntiprotonInJetV0(2, 0) * AntiprotonInJetV0(2, 0))); + registryData.fill(HIST("TProfile2DAntiLambdaPtMassSintheta"), candidate.mAntiLambda(), candidate.pt(), (4.0 / TMath::Pi()) * AntiprotonSinThetainJetV0); + registryData.fill(HIST("TProfile2DAntiLambdaPtMassCosSquareTheta"), candidate.mAntiLambda(), candidate.pt(), 3.0 * AntiprotonCosThetainJetV0 * AntiprotonCosThetainJetV0); + registryData.fill(HIST("TProfile2DAntiLambdaMassDeltaPhi"), TMath::ASin(AntiprotonsinPhiInJetV0frame), candidate.mAntiLambda(), AntiprotonsinPhiInJetV0frame); + registryData.fill(HIST("hantiprotonPhi"), TMath::ASin(AntiprotonsinPhiInJetV0frame)); + } + } + + for (const auto& candidate : fullV0s) { + const auto& pos = candidate.posTrack_as(); + const auto& neg = candidate.negTrack_as(); + if (passedLambdaSelection(candidate, pos, neg)) { + registryData.fill(HIST("hLambdamassandSinPhi"), candidate.mLambda(), protonsinPhiInJetV0frame / V0Numbers); + registryData.fill(HIST("hLambdaPhiandSinPhi"), TMath::ASin(protonsinPhiInJetV0frame / V0Numbers), protonsinPhiInJetV0frame / V0Numbers); + registryData.fill(HIST("V0LambdaprotonPhi"), TMath::ASin(protonsinPhiInJetV0frame / V0Numbers)); + registryData.fill(HIST("profileLambda"), candidate.mLambda(), protonsinPhiInJetV0frame / V0Numbers); + } + if (passedAntiLambdaSelection(candidate, pos, neg)) { + registryData.fill(HIST("hAntiLambdamassandSinPhi"), candidate.mAntiLambda(), AntiprotonsinPhiInJetV0frame / AntiV0Numbers); + registryData.fill(HIST("profileAntiLambda"), candidate.mAntiLambda(), AntiprotonsinPhiInJetV0frame / AntiV0Numbers); + } + } + } + PROCESS_SWITCH(LfMyV0s, processData, "processData", false); + + // V0Collisions + // SelCollisions + using V0Collisions = soa::Join; + void processLongitudinalPolarization(V0Collisions::iterator const& collision, aod::V0Datas const& fullV0s, StrHadronDaughterTracks const&) + { + + if (!AcceptEventForLongitudinalPolarization(collision)) { + return; + } + + for (const auto& v0 : fullV0s) { // loop over V0s + + if (v0.v0Type() != v0TypeSelection) { + continue; + } + + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + + if (NotITSAfterburner && (v0.negTrack_as().isITSAfterburner() || v0.posTrack_as().isITSAfterburner())) { + continue; + } + + if (AcceptV0Lambda(v0, pos, neg, collision) && ifpasslambda) { + + ProtonVec = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPr); + PionVec = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPi); + LambdaVec = ProtonVec + PionVec; + LambdaVec.SetM(massLambda); + ROOT::Math::Boost boost{LambdaVec.BoostToCM()}; + ProtonBoostedVec = boost(ProtonVec); + LambdaBoostedVec = boost(LambdaVec); + } + if (AcceptV0AntiLambda(v0, pos, neg, collision) && ifpasslambda) { + + 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); + LambdaBoostedVec = boost(LambdaVec); + } + } + } + PROCESS_SWITCH(LfMyV0s, processLongitudinalPolarization, "processLongitudinalPolarization", true); + + void processLambdaJetPolarization(SelV0Collisions::iterator const& collision, aod::V0Datas const& fullV0s, StrHadronDaughterTracks const& tracks) + { + registryData.fill(HIST("hNEvents"), 0.5); + if (!AcceptEvent(collision)) { + return; + } + registryData.fill(HIST("hNEvents"), 8.5); + // event selection + // loop over reconstructed tracks + std::vector fjParticles; + for (auto const& track : tracks) { + registryData.fill(HIST("h_track_pt"), track.pt()); + registryData.fill(HIST("h_track_eta"), track.eta()); + registryData.fill(HIST("h_track_phi"), track.phi()); + if (ispassdTrackSelectionForJetReconstruction && !passedTrackSelectionForJetReconstruction(track)) { + continue; + } + registryData.fill(HIST("h_track_pt_sel"), track.pt()); + registryData.fill(HIST("h_track_eta_sel"), track.eta()); + registryData.fill(HIST("h_track_phi_sel"), track.phi()); + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + // reject empty events + if (fjParticles.size() < 1) + return; + // cluster particles using the anti-kt algorithm + fastjet::RecombinationScheme recombScheme = fastjet::E_scheme; + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet, recombScheme); + 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()); + // jet selection + bool isAtLeastOneJetSelected = false; + int nJets = 0; + int nJetssel = 0; + // select most large momentum jet + float maxJetpx = 0; + float maxJetpy = 0; + float maxJetpz = 0; + float maxJeteta = 0; + float maxJetphi = 0; + float maxJetE = 0; + float maxJetpT = 0; + float maxJetPt = -999; + for (auto& jet : jets) { + nJets++; + registryData.fill(HIST("FJetaHistogram"), jet.eta()); + registryData.fill(HIST("FJphiHistogram"), jet.phi()); + registryData.fill(HIST("FJptHistogram"), jet.pt()); + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - deltaEtaEdge)) { + continue; + } + + if (jet.pt() < cfgjetPtMin) + continue; + nJetssel++; + registryData.fill(HIST("FJetaHistogramsel"), jet.eta()); + registryData.fill(HIST("FJphiHistogramsel"), jet.phi()); + registryData.fill(HIST("FJptHistogramsel"), jet.pt()); + + if (jet.pt() > maxJetPt) { + maxJetpx = jet.px(); + maxJetpy = jet.py(); + maxJetpz = jet.pz(); + maxJeteta = jet.eta(); + maxJetE = jet.E(); + maxJetphi = jet.phi(); + maxJetpT = jet.pt(); + maxJetPt = maxJetpT; + } + } + if (maxJetpT > 0) { + registryData.fill(HIST("FLeadingJetaHistogramsel"), maxJeteta); + registryData.fill(HIST("FLeadingJphiHistogramsel"), maxJetphi); + registryData.fill(HIST("FLeadingJptHistogramsel"), maxJetpT); + } + registryData.fill(HIST("nJetsPerEvent"), nJets); + registryData.fill(HIST("nJetsPerEventsel"), nJetssel); + isAtLeastOneJetSelected = true; + if (!isAtLeastOneJetSelected) { + return; + } + + // Event multiplicity + const float multiplicity = collision.centFT0M(); + registryData.fill(HIST("number_of_events_vsmultiplicity"), multiplicity); + // v0 loop + int V0Numbers = 0; + int AntiV0Numbers = 0; + 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()); + if (registryDataAcceptV0Lambda(v0, pos, neg, collision)) { + V0Numbers = V0Numbers + 1; + registryData.fill(HIST("LambdaPtMass"), v0.pt(), v0.mLambda()); + } + if (registryDataAcceptV0AntiLambda(v0, pos, neg, collision)) { + AntiV0Numbers = AntiV0Numbers + 1; + registryData.fill(HIST("AntiLambdaPtMass"), v0.pt(), v0.mAntiLambda()); + } + } + registryData.fill(HIST("nV0sPerEvent"), V0Numbers); + + // calculate lambda polarization induced by jet + + if (V0Numbers == 0 && AntiV0Numbers == 0) { + return; + } + if (maxJetpx == 0) { + return; + } + double protonsinPhiInJetV0frame = 0; + double AntiprotonsinPhiInJetV0frame = 0; + for (const auto& candidate : fullV0s) { + const auto& pos = candidate.posTrack_as(); + const auto& neg = candidate.negTrack_as(); + TVector3 v0dir(candidate.px(), candidate.py(), candidate.pz()); + + if (registryDataAcceptV0Lambda(candidate, pos, neg, collision)) { + registryData.fill(HIST("hMassLambda"), candidate.mLambda()); + registryData.fill(HIST("V0pTInLab"), candidate.pt()); + registryData.fill(HIST("V0pxInLab"), candidate.px()); + registryData.fill(HIST("V0pyInLab"), candidate.py()); + registryData.fill(HIST("V0pzInLab"), candidate.pz()); + registryData.fill(HIST("protonQA/V0protonpxInLab"), pos.px()); + registryData.fill(HIST("protonQA/V0protonpyInLab"), pos.py()); + registryData.fill(HIST("protonQA/V0protonpzInLab"), pos.pz()); + + double PLambda = sqrt(candidate.px() * candidate.px() + candidate.py() * candidate.py() + candidate.pz() * candidate.pz()); + double ELambda = sqrt(candidate.mLambda() * candidate.mLambda() + PLambda * PLambda); + double protonE = sqrt(massPr * massPr + pos.px() * pos.px() + pos.py() * pos.py() + pos.pz() * pos.pz()); + + TMatrixD pLabJet(4, 1); + pLabJet(0, 0) = maxJetE; + pLabJet(1, 0) = maxJetpx; + pLabJet(2, 0) = maxJetpy; + pLabJet(3, 0) = maxJetpz; + + TMatrixD pLabV0(4, 1); + pLabV0(0, 0) = ELambda; + pLabV0(1, 0) = candidate.px(); + pLabV0(2, 0) = candidate.py(); + pLabV0(3, 0) = candidate.pz(); + + TMatrixD V0InV0(4, 1); + V0InV0 = LorentzTransInV0frame(ELambda, candidate.px(), candidate.py(), candidate.pz()) * pLabV0; + registryData.fill(HIST("V0pxInRest_frame"), V0InV0(1, 0)); + registryData.fill(HIST("V0pyInRest_frame"), V0InV0(2, 0)); + registryData.fill(HIST("V0pzInRest_frame"), V0InV0(3, 0)); + + TMatrixD lambdaInJet(4, 1); + lambdaInJet = TMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabV0; + + registryData.fill(HIST("LambdaQA/TH2FLambdaMassPhiInJet"), TMath::ATan2(lambdaInJet(2, 0), lambdaInJet(1, 0)), candidate.mLambda()); + + registryData.fill(HIST("V0pxInJetframe"), lambdaInJet(1, 0)); + registryData.fill(HIST("V0pyInJetframe"), lambdaInJet(2, 0)); + registryData.fill(HIST("V0pzInJetframe"), lambdaInJet(3, 0)); + + TMatrixD lambdaInJetV0(4, 1); + lambdaInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabV0; + registryData.fill(HIST("V0LambdapxInJetV0frame"), lambdaInJetV0(1, 0)); + registryData.fill(HIST("V0LambdapyInJetV0frame"), lambdaInJetV0(2, 0)); + registryData.fill(HIST("V0LambdapzInJetV0frame"), lambdaInJetV0(3, 0)); + + TMatrixD pLabproton(4, 1); + pLabproton(0, 0) = protonE; + pLabproton(1, 0) = pos.px(); + pLabproton(2, 0) = pos.py(); + pLabproton(3, 0) = pos.pz(); + double protonsinPhiInLab = pLabproton(2, 0) / sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0)); + double protoncosthetaInLab = pLabproton(3, 0) / sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0) + pLabproton(3, 0) * pLabproton(3, 0)); + double protonPtInLab = sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0)); + double protonPInLab = sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0) + pLabproton(3, 0) * pLabproton(3, 0)); + double protonsinThetaInLab = protonPtInLab / protonPInLab; + double protonMassInLab = sqrt(pLabproton(0, 0) * pLabproton(0, 0) - pLabproton(1, 0) * pLabproton(1, 0) - pLabproton(2, 0) * pLabproton(2, 0) - pLabproton(3, 0) * pLabproton(3, 0)); + double jettheta = maxJetpz / sqrt(pLabJet(1, 0) * pLabJet(1, 0) + pLabJet(2, 0) * pLabJet(2, 0) + pLabJet(3, 0) * pLabJet(3, 0)); + double jetphi = maxJetpy / sqrt(pLabJet(1, 0) * pLabJet(1, 0) + pLabJet(2, 0) * pLabJet(2, 0)); + double jetptInLab = sqrt(pLabJet(1, 0) * pLabJet(1, 0) + pLabJet(2, 0) * pLabJet(2, 0)); + registryData.fill(HIST("JetQA/JetthetaInLab"), TMath::ASin(jettheta)); + registryData.fill(HIST("JetQA/JetphiInLab"), TMath::ASin(jetphi)); + registryData.fill(HIST("JetQA/JetpxInLab"), pLabJet(1, 0)); + registryData.fill(HIST("JetQA/JetpyInLab"), pLabJet(2, 0)); + registryData.fill(HIST("JetQA/JetpzInLab"), pLabJet(3, 0)); + registryData.fill(HIST("JetQA/JetptInLab"), jetptInLab); + + registryData.fill(HIST("protonQA/V0protonphiInLab"), TMath::ASin(protonsinPhiInLab)); + registryData.fill(HIST("protonQA/V0protonthetaInLab"), TMath::ACos(protoncosthetaInLab)); + registryData.fill(HIST("protonQA/V0protoncosthetaInLab"), protoncosthetaInLab); + registryData.fill(HIST("protonQA/profileprotonsinthetaInLab"), candidate.mLambda(), protonsinThetaInLab); + registryData.fill(HIST("protonQA/profileprotonsinphiInLab"), candidate.mLambda(), protonsinPhiInLab); + registryData.fill(HIST("protonQA/profileprotoncosSquarethetaInLab"), candidate.mLambda(), protoncosthetaInLab * protoncosthetaInLab); + registryData.fill(HIST("protonQA/V0protonMassInLab"), protonMassInLab); + + TMatrixD protonInV0(4, 1); + protonInV0 = LorentzTransInV0frame(ELambda, candidate.px(), candidate.py(), candidate.pz()) * 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)); + double protonPInV0 = sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0) + protonInV0(3, 0) * protonInV0(3, 0)); + double protonPtInV0 = sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0)); + double protonsinThetaInV0 = protonPtInV0 / protonPInV0; + + TMatrixD JetInV0(4, 1); + JetInV0 = LorentzTransInV0frame(ELambda, candidate.px(), candidate.py(), candidate.pz()) * pLabJet; + double jetthetaInV0 = JetInV0(3, 0) / sqrt(JetInV0(1, 0) * JetInV0(1, 0) + JetInV0(2, 0) * JetInV0(2, 0) + JetInV0(3, 0) * JetInV0(3, 0)); + double jetphiInV0 = JetInV0(2, 0) / sqrt(JetInV0(1, 0) * JetInV0(1, 0) + JetInV0(2, 0) * JetInV0(2, 0)); + double jetptInV0 = sqrt(JetInV0(1, 0) * JetInV0(1, 0) + JetInV0(2, 0) * JetInV0(2, 0)); + registryData.fill(HIST("JetQA/JetthetaInV0"), TMath::ASin(jetthetaInV0)); + registryData.fill(HIST("JetQA/JetphiInV0"), TMath::ASin(jetphiInV0)); + registryData.fill(HIST("JetQA/JetpxInV0"), JetInV0(1, 0)); + registryData.fill(HIST("JetQA/JetpyInV0"), JetInV0(2, 0)); + registryData.fill(HIST("JetQA/JetpzInV0"), JetInV0(3, 0)); + registryData.fill(HIST("JetQA/JetptInV0"), jetptInV0); + + registryData.fill(HIST("protonQA/V0protonMassInRest_frame"), protonMassInV0); + registryData.fill(HIST("protonQA/V0protonpxInRest_frame"), protonInV0(1, 0)); + registryData.fill(HIST("protonQA/V0protonpyInRest_frame"), protonInV0(2, 0)); + registryData.fill(HIST("protonQA/V0protonpzInRest_frame"), protonInV0(3, 0)); + double protonsinPhiInV0frame = protonInV0(2, 0) / sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0)); + double protoncosthetaInV0frame = protonInV0(3, 0) / sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0) + protonInV0(3, 0) * protonInV0(3, 0)); + registryData.fill(HIST("protonQA/V0protonphiInRest_frame"), TMath::ASin(protonsinPhiInV0frame)); + registryData.fill(HIST("protonQA/V0protonthetaInRest_frame"), TMath::ACos(protoncosthetaInV0frame)); + registryData.fill(HIST("protonQA/V0protoncosthetaInV0frame"), protoncosthetaInV0frame); + registryData.fill(HIST("protonQA/profileprotonsinthetaInV0frame"), candidate.mLambda(), protonsinThetaInV0); + registryData.fill(HIST("protonQA/profileprotonsinphiInV0frame"), candidate.mLambda(), protonsinPhiInV0frame); + registryData.fill(HIST("protonQA/profileprotoncosSquarethetaInV0frame"), candidate.mLambda(), protoncosthetaInV0frame * protoncosthetaInV0frame); + + TMatrixD protonInJet(4, 1); + protonInJet = TMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabproton; + double protoncosthetaInJet = protonInJet(3, 0) / sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0) + protonInJet(3, 0) * protonInJet(3, 0)); + double protonsinPhiInJet = protonInJet(2, 0) / sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0)); + double protonPtinJet = sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0)); + double protonPinJet = sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0) + protonInJet(3, 0) * protonInJet(3, 0)); + double protonSinThetainJet = protonPtinJet / protonPinJet; + double protonMassInJetframe = sqrt(protonInJet(0, 0) * protonInJet(0, 0) - protonInJet(1, 0) * protonInJet(1, 0) - protonInJet(2, 0) * protonInJet(2, 0) - protonInJet(3, 0) * protonInJet(3, 0)); + + TMatrixD pInJet(4, 1); + pInJet = TMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabJet; + double jetthetaInJet = pInJet(3, 0) / sqrt(pInJet(1, 0) * pInJet(1, 0) + pInJet(2, 0) * pInJet(2, 0) + pInJet(3, 0) * pInJet(3, 0)); + double jetphiInJet = pInJet(2, 0) / sqrt(pInJet(1, 0) * pInJet(1, 0) + pInJet(2, 0) * pInJet(2, 0)); + double jetptInJet = sqrt(pInJet(1, 0) * pInJet(1, 0) + pInJet(2, 0) * pInJet(2, 0)); + registryData.fill(HIST("JetQA/JetthetaInJetframe"), TMath::ASin(jetthetaInJet)); + registryData.fill(HIST("JetQA/JetphiInJetframe"), TMath::ASin(jetphiInJet)); + registryData.fill(HIST("JetQA/JetpxInJetframe"), pInJet(1, 0)); + registryData.fill(HIST("JetQA/JetpyInJetframe"), pInJet(2, 0)); + registryData.fill(HIST("JetQA/JetpzInJetframe"), pInJet(3, 0)); + registryData.fill(HIST("JetQA/JetptInJetframe"), jetptInJet); + + registryData.fill(HIST("protonQA/V0protonpxInJetframe"), protonInJet(1, 0)); + registryData.fill(HIST("protonQA/V0protonpyInJetframe"), protonInJet(2, 0)); + registryData.fill(HIST("protonQA/V0protonpzInJetframe"), protonInJet(3, 0)); + registryData.fill(HIST("protonQA/V0protonphiInJetframe"), TMath::ASin(protonsinPhiInJet)); + registryData.fill(HIST("protonQA/V0protonthetaInJetframe"), TMath::ACos(protoncosthetaInJet)); + registryData.fill(HIST("protonQA/V0protoncosthetaInJetframe"), protoncosthetaInJet); + registryData.fill(HIST("protonQA/profileprotonsinthetaInJetframe"), candidate.mLambda(), protonSinThetainJet); + registryData.fill(HIST("protonQA/profileprotonsinphiInJetframe"), candidate.mLambda(), protonsinPhiInJet); + registryData.fill(HIST("protonQA/profileprotoncosSquarethetaInJetframe"), candidate.mLambda(), protoncosthetaInJet * protoncosthetaInJet); + registryData.fill(HIST("protonQA/V0protonMassInJetframe"), protonMassInJetframe); + + TMatrixD protonInJetV0(4, 1); + protonInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * TMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabproton; + double protoncosthetaInJetV0 = protonInJetV0(3, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0) + protonInJetV0(3, 0) * protonInJetV0(3, 0)); + double protonsinphiInJetV0 = protonInJetV0(2, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0)); + double protonPtinJetV0 = sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0)); + double protonPinJetV0 = sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0) + protonInJetV0(3, 0) * protonInJetV0(3, 0)); + double protonSinThetainJetV0 = protonPtinJetV0 / protonPinJetV0; + double protonMassInJetV0frame = sqrt(protonInJetV0(0, 0) * protonInJetV0(0, 0) - protonInJetV0(1, 0) * protonInJetV0(1, 0) - protonInJetV0(2, 0) * protonInJetV0(2, 0) - protonInJetV0(3, 0) * protonInJetV0(3, 0)); + + TMatrixD JetInJetV0(4, 1); + JetInJetV0 = LorentzTransInV0frame(ELambda, lambdaInJet(1, 0), lambdaInJet(2, 0), lambdaInJet(3, 0)) * TMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabJet; + double jetthetaInJetV0 = JetInJetV0(3, 0) / sqrt(JetInJetV0(1, 0) * JetInJetV0(1, 0) + JetInJetV0(2, 0) * JetInJetV0(2, 0) + JetInJetV0(3, 0) * JetInJetV0(3, 0)); + double jetphiInJetV0 = JetInJetV0(2, 0) / sqrt(JetInJetV0(1, 0) * JetInJetV0(1, 0) + JetInJetV0(2, 0) * JetInJetV0(2, 0)); + double jetptInJetV0 = sqrt(JetInJetV0(1, 0) * JetInJetV0(1, 0) + JetInJetV0(2, 0) * JetInJetV0(2, 0)); + registryData.fill(HIST("JetQA/JetthetaInJetV0frame"), TMath::ASin(jetthetaInJetV0)); + registryData.fill(HIST("JetQA/JetphiInJetV0frame"), TMath::ASin(jetphiInJetV0)); + registryData.fill(HIST("JetQA/JetpxInJetV0frame"), JetInJetV0(1, 0)); + registryData.fill(HIST("JetQA/JetpyInJetV0frame"), JetInJetV0(2, 0)); + registryData.fill(HIST("JetQA/JetpzInJetV0frame"), JetInJetV0(3, 0)); + registryData.fill(HIST("JetQA/JetptInJetV0frame"), jetptInJetV0); + + registryData.fill(HIST("protonQA/V0protonpxInJetV0frame"), protonInJetV0(1, 0)); + registryData.fill(HIST("protonQA/V0protonpyInJetV0frame"), protonInJetV0(2, 0)); + registryData.fill(HIST("protonQA/V0protonpzInJetV0frame"), protonInJetV0(3, 0)); + registryData.fill(HIST("protonQA/V0protonphiInJetV0frame"), TMath::ASin(protonsinphiInJetV0)); + registryData.fill(HIST("protonQA/V0protonthetaInJetV0frame"), TMath::ACos(protoncosthetaInJetV0)); + registryData.fill(HIST("protonQA/V0protoncosthetaInJetV0"), protoncosthetaInJetV0); + registryData.fill(HIST("protonQA/V0protonMassInJetV0frame"), protonMassInJetV0frame); + registryData.fill(HIST("protonQA/profileprotonsinthetaInJetV0frame"), candidate.mLambda(), protonSinThetainJetV0); + registryData.fill(HIST("protonQA/profileprotonsinphiInJetV0frame"), candidate.mLambda(), protonsinphiInJetV0); + registryData.fill(HIST("protonQA/profileprotoncosSquarethetaInJetV0frame"), candidate.mLambda(), protoncosthetaInJetV0 * protoncosthetaInJetV0); + + double protonCosThetainJetV0 = protonInJetV0(3, 0) / protonPinJetV0; + + protonsinPhiInJetV0frame = protonsinPhiInJetV0frame + protonInJetV0(2, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0)); + + registryData.fill(HIST("hprotonsinphiInJetV0frame"), protonsinPhiInJetV0frame); + + registryData.fill(HIST("TProfile2DLambdaPtMassSinPhi"), candidate.mLambda(), candidate.pt(), protonInJetV0(2, 0) / sqrt(protonInJetV0(1, 0) * protonInJetV0(1, 0) + protonInJetV0(2, 0) * protonInJetV0(2, 0))); + registryData.fill(HIST("TProfile2DLambdaPtMassSintheta"), candidate.mLambda(), candidate.pt(), (4.0 / TMath::Pi()) * protonSinThetainJetV0); + registryData.fill(HIST("TProfile2DLambdaPtMassCosSquareTheta"), candidate.mLambda(), candidate.pt(), 3.0 * protonCosThetainJetV0 * protonCosThetainJetV0); + registryData.fill(HIST("TProfile2DLambdaMassDeltaPhi"), TMath::ASin(protonsinPhiInJetV0frame), candidate.mLambda(), protonsinPhiInJetV0frame); + registryData.fill(HIST("hprotonPhi"), TMath::ASin(protonsinPhiInJetV0frame)); + + double protonCosThetaInLab = pLabproton(3, 0) / sqrt(pLabproton(1, 0) * pLabproton(1, 0) + pLabproton(2, 0) * pLabproton(2, 0) + pLabproton(3, 0) * pLabproton(3, 0)); // cos(theta) of lambda in lab frame + double protonCosThetaInV0frame = protonInV0(3, 0) / sqrt(protonInV0(1, 0) * protonInV0(1, 0) + protonInV0(2, 0) * protonInV0(2, 0) + protonInV0(3, 0) * protonInV0(3, 0)); // cos(theta) of lambda in V0 frame + double protonCosThetaInJetV0frame = protonCosThetainJetV0; + double protonCosThetaInJet = protonInJet(3, 0) / sqrt(protonInJet(1, 0) * protonInJet(1, 0) + protonInJet(2, 0) * protonInJet(2, 0) + protonInJet(3, 0) * protonInJet(3, 0)); // cos(theta) of lambda in Jet frame + + registryData.fill(HIST("hprotonThetaInLab"), TMath::ACos(protonCosThetaInLab)); + registryData.fill(HIST("hprotonThetaInV0"), TMath::ACos(protonCosThetaInV0frame)); + registryData.fill(HIST("hprotonThetaInJetV0"), TMath::ACos(protonCosThetaInJetV0frame)); + + registryData.fill(HIST("LambdaQA/TH2FprotonCosThetaInLab"), candidate.mLambda(), protonCosThetaInLab); + registryData.fill(HIST("LambdaQA/TProfile1DprotonCosThetaInLab"), candidate.mLambda(), protonCosThetaInLab); + registryData.fill(HIST("LambdaQA/TProfile1DprotonCos2ThetaInLab"), candidate.mLambda(), protonCosThetaInLab * protonCosThetaInLab); + + registryData.fill(HIST("LambdaQA/TH2FprotonCosThetaInV0"), candidate.mLambda(), protonCosThetaInV0frame); + registryData.fill(HIST("LambdaQA/TProfile1DprotonCosThetaInV0"), candidate.mLambda(), protonCosThetaInV0frame); + registryData.fill(HIST("LambdaQA/TProfile1DprotonCos2ThetaInV0"), candidate.mLambda(), protonCosThetaInV0frame * protonCosThetaInV0frame); + + registryData.fill(HIST("LambdaQA/TH2FprotonCosThetaInJet"), candidate.mLambda(), protonCosThetaInJet); + registryData.fill(HIST("LambdaQA/TProfile1DprotonCosThetaInJet"), candidate.mLambda(), protonCosThetaInJet); + registryData.fill(HIST("LambdaQA/TProfile1DprotonCos2ThetaInJet"), candidate.mLambda(), protonCosThetaInJet * protonCosThetaInJet); + + registryData.fill(HIST("LambdaQA/TH2FprotonCosThetaInJetV0"), candidate.mLambda(), protonCosThetaInJetV0frame); + registryData.fill(HIST("LambdaQA/TProfile1DprotonCosThetaInJetV0"), candidate.mLambda(), protonCosThetaInJetV0frame); + registryData.fill(HIST("LambdaQA/TProfile1DprotonCos2ThetaInJetV0"), candidate.mLambda(), protonCosThetaInJetV0frame * protonCosThetaInJetV0frame); + registryData.fill(HIST("LambdaQA/TProfile2DprotonCosThetaInJetV0"), candidate.mLambda(), TMath::ATan2(lambdaInJet(2, 0), lambdaInJet(1, 0)), protonCosThetaInJetV0frame); + registryData.fill(HIST("LambdaQA/TProfile2DprotonCos2ThetaInJetV0"), candidate.mLambda(), TMath::ATan2(lambdaInJet(2, 0), lambdaInJet(1, 0)), protonCosThetaInJetV0frame * protonCosThetaInJetV0frame); + } + if (registryDataAcceptV0AntiLambda(candidate, pos, neg, collision)) { + registryData.fill(HIST("hMassAntiLambda"), candidate.mAntiLambda()); + double PAntiLambda = sqrt(candidate.px() * candidate.px() + candidate.py() * candidate.py() + candidate.pz() * candidate.pz()); + double EAntiLambda = sqrt(candidate.mAntiLambda() * candidate.mAntiLambda() + PAntiLambda * PAntiLambda); + double AntiprotonE = sqrt(massPr * massPr + neg.px() * neg.px() + neg.py() * neg.py() + neg.pz() * neg.pz()); + TMatrixD pLabAntiV0(4, 1); + pLabAntiV0(0, 0) = EAntiLambda; + pLabAntiV0(1, 0) = candidate.px(); + pLabAntiV0(2, 0) = candidate.py(); + pLabAntiV0(3, 0) = candidate.pz(); + + TMatrixD AntilambdaInJet(4, 1); + AntilambdaInJet = MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabAntiV0; + + TMatrixD pLabAntiproton(4, 1); + pLabAntiproton(0, 0) = AntiprotonE; + pLabAntiproton(1, 0) = neg.px(); + pLabAntiproton(2, 0) = neg.py(); + pLabAntiproton(3, 0) = neg.pz(); + TMatrixD AntiprotonInJetV0(4, 1); + AntiprotonInJetV0 = LorentzTransInV0frame(EAntiLambda, AntilambdaInJet(1, 0), AntilambdaInJet(2, 0), AntilambdaInJet(3, 0)) * MyTMatrixTranslationToJet(maxJetpx, maxJetpy, maxJetpz, candidate.px(), candidate.py(), candidate.pz()) * pLabAntiproton; + AntiprotonsinPhiInJetV0frame = AntiprotonsinPhiInJetV0frame + AntiprotonInJetV0(2, 0) / sqrt(AntiprotonInJetV0(1, 0) * AntiprotonInJetV0(1, 0) + AntiprotonInJetV0(2, 0) * AntiprotonInJetV0(2, 0)); + TMatrixD AntiprotonInV0(4, 1); + AntiprotonInV0 = LorentzTransInV0frame(EAntiLambda, candidate.px(), candidate.py(), candidate.pz()) * pLabAntiproton; + double AntiprotonPinJetV0 = sqrt(AntiprotonInJetV0(1, 0) * AntiprotonInJetV0(1, 0) + AntiprotonInJetV0(2, 0) * AntiprotonInJetV0(2, 0) + AntiprotonInJetV0(3, 0) * AntiprotonInJetV0(3, 0)); + double AntiprotonPtinJetV0 = sqrt(AntiprotonInJetV0(1, 0) * AntiprotonInJetV0(1, 0) + AntiprotonInJetV0(2, 0) * AntiprotonInJetV0(2, 0)); + double AntiprotonCosThetainJetV0 = AntiprotonInJetV0(3, 0) / AntiprotonPinJetV0; + double AntiprotonSinThetainJetV0 = AntiprotonPtinJetV0 / AntiprotonPinJetV0; + registryData.fill(HIST("TProfile2DAntiLambdaPtMassSinPhi"), candidate.mAntiLambda(), candidate.pt(), AntiprotonInJetV0(2, 0) / sqrt(AntiprotonInJetV0(1, 0) * AntiprotonInJetV0(1, 0) + AntiprotonInJetV0(2, 0) * AntiprotonInJetV0(2, 0))); + registryData.fill(HIST("TProfile2DAntiLambdaPtMassSintheta"), candidate.mAntiLambda(), candidate.pt(), (4.0 / TMath::Pi()) * AntiprotonSinThetainJetV0); + registryData.fill(HIST("TProfile2DAntiLambdaPtMassCosSquareTheta"), candidate.mAntiLambda(), candidate.pt(), 3.0 * AntiprotonCosThetainJetV0 * AntiprotonCosThetainJetV0); + registryData.fill(HIST("TProfile2DAntiLambdaMassDeltaPhi"), TMath::ASin(AntiprotonsinPhiInJetV0frame), candidate.mAntiLambda(), AntiprotonsinPhiInJetV0frame); + registryData.fill(HIST("hantiprotonPhi"), TMath::ASin(AntiprotonsinPhiInJetV0frame)); + } + } + + for (const auto& candidate : fullV0s) { + const auto& pos = candidate.posTrack_as(); + const auto& neg = candidate.negTrack_as(); + if (passedLambdaSelection(candidate, pos, neg)) { + registryData.fill(HIST("hLambdamassandSinPhi"), candidate.mLambda(), protonsinPhiInJetV0frame / V0Numbers); + registryData.fill(HIST("hLambdaPhiandSinPhi"), TMath::ASin(protonsinPhiInJetV0frame / V0Numbers), protonsinPhiInJetV0frame / V0Numbers); + registryData.fill(HIST("V0LambdaprotonPhi"), TMath::ASin(protonsinPhiInJetV0frame / V0Numbers)); + registryData.fill(HIST("profileLambda"), candidate.mLambda(), protonsinPhiInJetV0frame / V0Numbers); + } + if (passedAntiLambdaSelection(candidate, pos, neg)) { + registryData.fill(HIST("hAntiLambdamassandSinPhi"), candidate.mAntiLambda(), AntiprotonsinPhiInJetV0frame / AntiV0Numbers); + registryData.fill(HIST("profileAntiLambda"), candidate.mAntiLambda(), AntiprotonsinPhiInJetV0frame / AntiV0Numbers); + } + } + } + PROCESS_SWITCH(LfMyV0s, processLambdaJetPolarization, "processLambdaJetPolarization", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lf-my-v0s"}), + }; +} diff --git a/PWGLF/Tasks/Strangeness/lambdaTwoPartPolarization.cxx b/PWGLF/Tasks/Strangeness/lambdaTwoPartPolarization.cxx new file mode 100644 index 00000000000..63d26a6d50c --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdaTwoPartPolarization.cxx @@ -0,0 +1,477 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.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/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TLorentzVector.h" +#include "TRandom3.h" +#include "TVector3.h" +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::constants::physics; + +struct lambdaTwoPartPolarization { + 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", 2, "Centrality estimator, 1: FT0C, 2: FT0M"}; + + Configurable cfgEvtSel{"cfgEvtSel", true, "event selection flag"}; + Configurable cfgPVSel{"cfgPVSel", true, "Additional PV selection flag for syst"}; + Configurable cfgPV{"cfgPV", 10.0, "Additional PV selection range for syst"}; + Configurable cfgAddEvtSelPileup{"cfgAddEvtSelPileup", true, "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.99, "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", 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 cfgHypMassWindow{"cfgHypMassWindow", 0.005, "single lambda mass selection"}; + + 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 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 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, 100}, "Centrality interval"}; + ConfigurableAxis RapAxis{"RapAxis", {10, -0.5, 0.5}, "Rapidity axis"}; + ConfigurableAxis detaAxis{"dyAxis", {20, -1, 1}, "relative rapidity axis"}; + ConfigurableAxis dphiAxis{"dphiAxis", {20, -constants::math::PI * 0.5, constants::math::PI * 1.5}, "relative azimuth axis"}; + + ConfigurableAxis cosSigAxis{"cosSigAxis", {110, -1.05, 1.05}, "Signal cosine axis"}; + ConfigurableAxis cosAccAxis{"cosAccAxis", {110, -7.05, 7.05}, "Accepatance cosine axis"}; + + ConfigurableAxis vertexAxis{"vertexAxis", {5, -10, 10}, "vertex axis for mixing"}; + + TF1* fMultPVCutLow = nullptr; + TF1* fMultPVCutHigh = nullptr; + + float centrality; + float dphi; + float weight; + + TProfile2D* EffMap = nullptr; + TProfile2D* AccMap = nullptr; + + void init(o2::framework::InitContext&) + { + AxisSpec centQaAxis = {100, 0.0, 100.0}; + AxisSpec PVzQaAxis = {300, -15.0, 15.0}; + AxisSpec epAxis = {6, 0.0, 2.0 * constants::math::PI}; + + AxisSpec pidAxis = {100, -10, 10}; + + AxisSpec shiftAxis = {10, 0, 10, "shift"}; + AxisSpec basisAxis = {20, 0, 20, "basis"}; + + 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}}); + } + + histos.add("Ana/Signal", "", {HistType::kTHnSparseF, {ptAxis, ptAxis, detaAxis, dphiAxis, centAxis, cosSigAxis}}); + histos.add("Ana/SignalCos2", "", {HistType::kTHnSparseF, {ptAxis, ptAxis, detaAxis, dphiAxis, centAxis, cosSigAxis}}); + histos.add("Ana/Acceptance", "", {HistType::kTHnSparseF, {ptAxis, centAxis, RapAxis, cosAccAxis}}); + + 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 ProtonVec1, PionVec1, LambdaVec1, ProtonBoostedVec1, PionBoostedVec1; + ROOT::Math::PxPyPzMVector ProtonVec2, PionVec2, LambdaVec2, ProtonBoostedVec2, PionBoostedVec2; + int V01Tag; + int V02Tag; + double costhetastar1; + double costhetastar2; + + template + bool eventSelected(TCollision collision) + { + if (!collision.sel8()) { + return 0; + } + if (cfgCentSel < 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 FillHistograms(C1 const& c1, C2 const& c2, V01 const& V01s, V02 const& V02s) + { + for (auto& v01 : V01s) { + auto postrack_v01 = v01.template posTrack_as(); + auto negtrack_v01 = v01.template negTrack_as(); + + int LambdaTag = 0; + int aLambdaTag = 0; + + if (isSelectedV0Daughter(postrack_v01, 0) && isSelectedV0Daughter(negtrack_v01, 1)) { + LambdaTag = 1; + } + if (isSelectedV0Daughter(negtrack_v01, 0) && isSelectedV0Daughter(postrack_v01, 1)) { + aLambdaTag = 1; + } + + if (LambdaTag == aLambdaTag) + continue; + + if (!SelectionV0(c1, v01, LambdaTag)) + continue; + + if (LambdaTag) { + ProtonVec1 = ROOT::Math::PxPyPzMVector(v01.pxpos(), v01.pypos(), v01.pzpos(), massPr); + PionVec1 = ROOT::Math::PxPyPzMVector(v01.pxneg(), v01.pyneg(), v01.pzneg(), massPi); + V01Tag = 0; + } + if (aLambdaTag) { + ProtonVec1 = ROOT::Math::PxPyPzMVector(v01.pxneg(), v01.pyneg(), v01.pzneg(), massPr); + PionVec1 = ROOT::Math::PxPyPzMVector(v01.pxpos(), v01.pypos(), v01.pzpos(), massPi); + V01Tag = 1; + } + LambdaVec1 = ProtonVec1 + PionVec1; + LambdaVec1.SetM(massLambda); + + ROOT::Math::Boost boost1{LambdaVec1.BoostToCM()}; + ProtonBoostedVec1 = boost1(ProtonVec1); + + costhetastar1 = ProtonBoostedVec1.Pz() / ProtonBoostedVec1.P(); + + histos.fill(HIST("Ana/Acceptance"), v01.pt(), centrality, v01.yLambda(), costhetastar1 * costhetastar1); + + 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; + + if (isSelectedV0Daughter(postrack_v02, 0) && isSelectedV0Daughter(negtrack_v02, 1)) { + LambdaTag = 1; + } + if (isSelectedV0Daughter(negtrack_v02, 0) && isSelectedV0Daughter(postrack_v02, 1)) { + aLambdaTag = 1; + } + + if (LambdaTag == aLambdaTag) + continue; + + if (!SelectionV0(c2, v02, LambdaTag)) + 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) { + ProtonVec2 = ROOT::Math::PxPyPzMVector(v02.pxpos(), v02.pypos(), v02.pzpos(), massPr); + PionVec2 = ROOT::Math::PxPyPzMVector(v02.pxneg(), v02.pyneg(), v02.pzneg(), massPi); + V02Tag = 0; + } + if (aLambdaTag) { + ProtonVec2 = ROOT::Math::PxPyPzMVector(v02.pxneg(), v02.pyneg(), v02.pzneg(), massPr); + PionVec2 = ROOT::Math::PxPyPzMVector(v02.pxpos(), v02.pypos(), v02.pzpos(), massPi); + V02Tag = 1; + } + LambdaVec2 = ProtonVec2 + PionVec2; + LambdaVec2.SetM(massLambda); + + ROOT::Math::Boost boost2{LambdaVec2.BoostToCM()}; + ProtonBoostedVec2 = boost2(ProtonVec2); + + costhetastar2 = ProtonBoostedVec2.Pz() / ProtonBoostedVec2.P(); + + weight = 1.0; + weight *= cfgEffCor ? 1.0 / EffMap->GetBinContent(EffMap->GetXaxis()->FindBin(v01.pt()), EffMap->GetYaxis()->FindBin(centrality)) : 1.; + weight *= cfgAccCor ? 1.0 / AccMap->GetBinContent(AccMap->GetXaxis()->FindBin(v01.pt()), AccMap->GetYaxis()->FindBin(v01.yLambda())) : 1.; + weight *= cfgEffCor ? 1.0 / EffMap->GetBinContent(EffMap->GetXaxis()->FindBin(v02.pt()), EffMap->GetYaxis()->FindBin(centrality)) : 1.; + weight *= cfgAccCor ? 1.0 / AccMap->GetBinContent(AccMap->GetXaxis()->FindBin(v02.pt()), AccMap->GetYaxis()->FindBin(v02.yLambda())) : 1.; + + if (V01Tag != V02Tag) { + weight *= -1.0; + } + + dphi = TVector2::Phi_0_2pi(v01.phi() - v02.phi()); + if (dphi > constants::math::PI * 1.5) { + dphi -= constants::math::PI * 2.0; + } + + histos.fill(HIST("Ana/Signal"), v01.pt(), v02.pt(), v01.yLambda() - v02.yLambda(), dphi, centrality, costhetastar1 * costhetastar2 * weight); + histos.fill(HIST("Ana/SignalCos2"), v01.pt(), v02.pt(), v01.yLambda() - v02.yLambda(), dphi, centrality, costhetastar1 * costhetastar2 * std::cos(2.0 * dphi) * weight); + } + } + } + + 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(); + } + if (!eventSelected(collision) && cfgEvtSel) { + return; + } + + histos.fill(HIST("QA/CentDist"), centrality, 1.0); + histos.fill(HIST("QA/PVzDist"), collision.posZ(), 1.0); + + auto bc = collision.bc_as(); + if (cfgEffCor) { + EffMap = ccdb->getForTimeStamp(cfgEffCorPath.value, bc.timestamp()); + } + if (cfgAccCor) { + AccMap = ccdb->getForTimeStamp(cfgAccCorPath.value, bc.timestamp()); + } + + FillHistograms(collision, collision, V0s, V0s); + } + PROCESS_SWITCH(lambdaTwoPartPolarization, processDataSame, "Process event for same data", true); + + SliceCache cache; + Preslice tracksPerCollisionV0 = aod::v0data::collisionId; + + using BinningTypeT0C = ColumnBinningPolicy; + BinningTypeT0C colBinningT0C{{vertexAxis, centAxis}, true}; + + void processDataMixedT0C(EventCandidates const& collisions, + TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) + { + for (auto& [c1, c2] : selfCombinations(colBinningT0C, cfgNoMixedEvents, -1, collisions, collisions)) { + + if (c1.index() == c2.index()) + continue; + + centrality = c1.centFT0C(); + if (cfgAccCor) { + auto bc = c1.bc_as(); + AccMap = ccdb->getForTimeStamp(cfgAccCorPath.value, bc.timestamp()); + } + if (!eventSelected(c1)) + continue; + if (!eventSelected(c2)) + continue; + + auto tracks1 = V0s.sliceBy(tracksPerCollisionV0, c1.globalIndex()); + auto tracks2 = V0s.sliceBy(tracksPerCollisionV0, c2.globalIndex()); + + FillHistograms(c1, c2, tracks1, tracks2); + } + } + PROCESS_SWITCH(lambdaTwoPartPolarization, processDataMixedT0C, "Process event for mixed data in PbPb", false); + + using BinningTypeT0M = ColumnBinningPolicy; + BinningTypeT0M colBinningT0M{{vertexAxis, centAxis}, true}; + + void processDataMixedT0M(EventCandidates const& collisions, + TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) + { + for (auto& [c1, c2] : selfCombinations(colBinningT0M, cfgNoMixedEvents, -1, collisions, collisions)) { + + if (c1.index() == c2.index()) + continue; + + centrality = c1.centFT0M(); + if (cfgAccCor) { + auto bc = c1.bc_as(); + AccMap = ccdb->getForTimeStamp(cfgAccCorPath.value, bc.timestamp()); + } + if (!eventSelected(c1)) + continue; + if (!eventSelected(c2)) + continue; + + auto tracks1 = V0s.sliceBy(tracksPerCollisionV0, c1.globalIndex()); + auto tracks2 = V0s.sliceBy(tracksPerCollisionV0, c2.globalIndex()); + + FillHistograms(c1, c2, tracks1, tracks2); + } + } + PROCESS_SWITCH(lambdaTwoPartPolarization, processDataMixedT0M, "Process event for mixed data in pp", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lf-lambdaTwoPartPolarization"})}; +} diff --git a/PWGLF/Tasks/Strangeness/lambdak0seff.cxx b/PWGLF/Tasks/Strangeness/lambdak0seff.cxx new file mode 100644 index 00000000000..2a3864f2ede --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdak0seff.cxx @@ -0,0 +1,458 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// Fast Lambda k0s eff QA task for correlation analysis +// prottay.das@cern.ch + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/SPCalibrationTables.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/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include // <<< CHANGED: for dedup sets +#include +#include +#include // <<< CHANGED: for seenMap +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; + +struct lambdak0seff { + + 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; + + int mRunNumber; + Service ccdb; + Service pdg; + o2::ccdb::CcdbApi ccdbApi; + TH1D* hwgtAL; + // fill output + struct : ConfigurableGroup { + Configurable additionalEvSel{"additionalEvSel", false, "additionalEvSel"}; + Configurable additionalEvSel2{"additionalEvSel2", false, "additionalEvSel2"}; + Configurable additionalEvSel3{"additionalEvSel3", false, "additionalEvSel3"}; + } evselGrp; + // 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"}; + // 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"}; + Configurable analyzeLambda{"analyzeLambda", true, "flag for lambda analysis"}; + Configurable analyzeK0s{"analyzeK0s", false, "flag for K0s analysis"}; + Configurable qtArmenterosMinForK0{"qtArmenterosMinForK0", 0.2, "Armenterous cut for K0s"}; + // 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 rcrfc{"rcrfc", 0.8f, "Ratio of CR to FC"}; + Configurable ConfDaughTPCnclsMin{"ConfDaughTPCnclsMin", 50.f, "V0 Daugh sel: Min. nCls TPC"}; + Configurable ConfDaughPIDCuts{"ConfDaughPIDCuts", 3, "PID selections for Lambda daughters"}; + + struct : ConfigurableGroup { + 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"}; + } binGrp; + struct : ConfigurableGroup { + ConfigurableAxis configcentAxis{"configcentAxis", {VARIABLE_WIDTH, 0.0, 10.0, 40.0, 80.0, 150, 300}, "Cent FT0C"}; + 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 configvzAxis{"configvzAxis", {VARIABLE_WIDTH, -10, -5, -0.0, 5, 10}, "Vz"}; + } axisGrp; + + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + AxisSpec thnAxisInvMass{binGrp.IMNbins, binGrp.lbinIM, binGrp.hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + + std::vector runaxes2 = {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configetaAxis, axisGrp.configvzAxis, axisGrp.configcentAxis}; + + histos.add("hCentrality", "Centrality distribution", kTH1F, {{axisGrp.configcentAxis}}); + histos.add("hSparseGenLambda", "hSparseGenLambda", HistType::kTHnSparseF, runaxes2, true); + histos.add("hSparseGenAntiLambda", "hSparseGenAntiLambda", HistType::kTHnSparseF, runaxes2, true); + histos.add("hSparseRecLambda", "hSparseRecLambda", HistType::kTHnSparseF, runaxes2, true); + histos.add("hSparseRecAntiLambda", "hSparseRecAntiLambda", HistType::kTHnSparseF, runaxes2, true); + histos.add("hSparseGenK0s", "hSparseGenK0s", HistType::kTHnSparseF, runaxes2, true); + histos.add("hSparseRecK0s", "hSparseRecK0s", HistType::kTHnSparseF, runaxes2, true); + + 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()); + LOGF(info, "Getting alignment offsets from the CCDB..."); + } + + 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 CtauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massK0s; + + 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 (analyzeLambda && TMath::Abs(CtauLambda) > cMaxV0LifeTime) { + return false; + } + if (analyzeK0s && TMath::Abs(CtauK0s) > cMaxV0LifeTime) { + return false; + } + if (analyzeLambda && TMath::Abs(candidate.yLambda()) > ConfV0Rap) { + return false; + } + if (analyzeK0s && TMath::Abs(candidate.yK0Short()) > ConfV0Rap) { + return false; + } + return true; + } + + template + bool isSelectedV0Daughter(V0 const& candidate, T const& track, int pid, int pid2) + { + const auto tpcNClsF = track.tpcNClsFound(); + if (track.tpcNClsCrossedRows() < cfgTPCcluster) { + return false; + } + + if (tpcNClsF < ConfDaughTPCnclsMin) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < rcrfc) { + return false; + } + + if (analyzeLambda && pid == 0 && TMath::Abs(track.tpcNSigmaPr()) > ConfDaughPIDCuts) { + return false; + } + if (analyzeLambda && pid == 1 && TMath::Abs(track.tpcNSigmaPi()) > ConfDaughPIDCuts) { + return false; + } + if (analyzeK0s && 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 (analyzeLambda && pid2 == 0 && (TMath::Abs(candidate.dcapostopv()) < cMinV0DCAPr || TMath::Abs(candidate.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + if (analyzeLambda && pid2 == 1 && (TMath::Abs(candidate.dcapostopv()) < cMinV0DCAPi || TMath::Abs(candidate.dcanegtopv()) < cMinV0DCAPr)) { + return false; + } + if (analyzeK0s && (TMath::Abs(candidate.dcapostopv()) < cMinV0DCAPi || TMath::Abs(candidate.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + if (analyzeK0s && (candidate.qtarm() / (std::abs(candidate.alpha()))) < 0.2) { + 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)); + } + + ROOT::Math::PxPyPzMVector Lambda, AntiLambda, Lambdadummy, AntiLambdadummy, Proton, Pion, AntiProton, AntiPion, K0sdummy, K0s; + double massLambda = o2::constants::physics::MassLambda; + double massK0s = o2::constants::physics::MassK0Short; + 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 EventCandidatesMC = soa::Filtered>; + using AllTrackCandidates = soa::Filtered>; + using ResoV0s = aod::V0Datas; + + using TrackMCTrueTable = aod::McParticles; + ROOT::Math::PxPyPzMVector lambdadummymc, antiLambdadummymc, kshortdummymc, protonmc, pionmc, antiProtonmc, antiPionmc; + + void processMC(EventCandidatesMC::iterator const& collision, AllTrackCandidates const& /*tracks*/, TrackMCTrueTable const& GenParticles, ResoV0s const& V0s) + { + if (!collision.sel8()) { + return; + } + double centrality = -999.; + centrality = collision.centFT0C(); + // centrality = collision.multiplicity(); + double vz = collision.posZ(); + + if (evselGrp.additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + if (evselGrp.additionalEvSel2 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + if (evselGrp.additionalEvSel3 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + + histos.fill(HIST("hCentrality"), centrality); + + for (const auto& v0 : V0s) { + + auto postrack = v0.template posTrack_as(); + auto negtrack = v0.template negTrack_as(); + + if (analyzeLambda && analyzeK0s) + continue; + if (!analyzeLambda && !analyzeK0s) + continue; + + int LambdaTag = 0; + int aLambdaTag = 0; + int K0sTag = 0; + + const auto signpos = postrack.sign(); + const auto signneg = negtrack.sign(); + + if (signpos < 0 || signneg > 0) { + continue; + } + if (analyzeLambda) { + if (isSelectedV0Daughter(v0, postrack, 0, 0) && isSelectedV0Daughter(v0, negtrack, 1, 0)) { + LambdaTag = 1; + } + if (isSelectedV0Daughter(v0, negtrack, 0, 1) && isSelectedV0Daughter(v0, postrack, 1, 1)) { + aLambdaTag = 1; + } + } + if (analyzeK0s) { + if (isSelectedV0Daughter(v0, postrack, 0, 0) && isSelectedV0Daughter(v0, negtrack, 1, 0)) { + K0sTag = 1; + } + } + + if (analyzeLambda && (!LambdaTag && !aLambdaTag)) + continue; + if (analyzeK0s && (!K0sTag)) + continue; + + if (!SelectionV0(collision, v0)) { + continue; + } + + if (analyzeLambda) { + 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; + } + 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; + } + + if (shouldReject(LambdaTag, aLambdaTag, Lambdadummy, AntiLambdadummy)) { + continue; + } + } + + if (analyzeK0s) { + if (K0sTag) { + Pion = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPi); + AntiPion = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPi); + K0sdummy = Pion + AntiPion; + } + } + + if (TMath::Abs(v0.eta()) > 0.8) + continue; + + if (LambdaTag) { + Lambda = Proton + AntiPion; + histos.fill(HIST("hSparseRecLambda"), v0.mLambda(), v0.pt(), v0.eta(), vz, centrality); + } + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + histos.fill(HIST("hSparseRecAntiLambda"), v0.mAntiLambda(), v0.pt(), v0.eta(), vz, centrality); + } + if (K0sTag) { + histos.fill(HIST("hSparseRecK0s"), v0.mK0Short(), v0.pt(), v0.eta(), vz, centrality); + } + } + + for (const auto& mcParticle : GenParticles) { + if (analyzeLambda && std::abs(mcParticle.pdgCode()) != PDG_t::kLambda0) { + continue; + } + if (analyzeK0s && std::abs(mcParticle.pdgCode()) != PDG_t::kK0Short) { + continue; + } + if (std::abs(mcParticle.y()) > ConfV0Rap) { + continue; + } + auto pdg1 = mcParticle.pdgCode(); + auto kDaughters = mcParticle.daughters_as(); + int daughsize = 2; + if (kDaughters.size() != daughsize) { + continue; + } + for (const auto& kCurrentDaughter : kDaughters) { + + if (std::abs(kCurrentDaughter.pdgCode()) != PDG_t::kProton && std::abs(kCurrentDaughter.pdgCode()) != PDG_t::kPiPlus) { + continue; + } + if (kCurrentDaughter.pdgCode() == PDG_t::kProton) { + protonmc = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassProton); + } + if (kCurrentDaughter.pdgCode() == PDG_t::kPiMinus) { + antiPionmc = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassPionCharged); + } + + if (kCurrentDaughter.pdgCode() == PDG_t::kProtonBar) { + antiProtonmc = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassProton); + } + if (kCurrentDaughter.pdgCode() == PDG_t::kPiPlus) { + pionmc = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassPionCharged); + } + } + if (pdg1 == PDG_t::kLambda0) { + lambdadummymc = protonmc + antiPionmc; + histos.fill(HIST("hSparseGenLambda"), lambdadummymc.M(), lambdadummymc.Pt(), lambdadummymc.Eta(), vz, centrality); + } + + if (pdg1 == PDG_t::kLambda0Bar) { + antiLambdadummymc = antiProtonmc + pionmc; + histos.fill(HIST("hSparseGenAntiLambda"), antiLambdadummymc.M(), antiLambdadummymc.Pt(), lambdadummymc.Eta(), vz, centrality); + } + if (pdg1 == PDG_t::kK0Short) { + kshortdummymc = antiPionmc + pionmc; + histos.fill(HIST("hSparseGenK0s"), kshortdummymc.M(), kshortdummymc.Pt(), kshortdummymc.Eta(), vz, centrality); + } + } + } + PROCESS_SWITCH(lambdak0seff, processMC, "Process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lambdak0seff"})}; +} diff --git a/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx b/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx new file mode 100644 index 00000000000..372c67ad9e8 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx @@ -0,0 +1,2014 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include +#include + +#include +#include + +#include +#include + +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/lambdakzeroanalysisMC.cxx b/PWGLF/Tasks/Strangeness/lambdakzeroanalysisMC.cxx index afbe1a8a061..53f80bd26ae 100644 --- a/PWGLF/Tasks/Strangeness/lambdakzeroanalysisMC.cxx +++ b/PWGLF/Tasks/Strangeness/lambdakzeroanalysisMC.cxx @@ -22,31 +22,33 @@ // aimeric.landou@cern.ch (MC adaptation) // david.dobrigkeit.chinellato@cern.ch (original lambdakzeroanalysis task) -#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" + #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include +#include #include #include -#include #include -#include #include -#include -#include +#include + #include +#include #include -#include "Framework/ASoAHelpers.h" using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Strangeness/lambdalambda.cxx b/PWGLF/Tasks/Strangeness/lambdalambda.cxx new file mode 100644 index 00000000000..2190a5d353c --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdalambda.cxx @@ -0,0 +1,591 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TLorentzVector.h" +#include "TRandom3.h" +#include "TVector3.h" +#include + +#include +#include +#include +#include +#include +#include + +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; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + 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"}; + + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Enable processing of skimmed data"}; + Configurable cfgTriggerName{"cfgTriggerName", "fLambdaLambda", "Software trigger name"}; + + 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 initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfgTriggerName.value); + zorro.populateHistRegistry(histos, bc.runNumber()); + } + } + + void init(o2::framework::InitContext&) + { + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + 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); + + auto bc = collision.bc_as(); + if (cfgSkimmedProcessing) { + initCCDB(bc); + if (!zorro.isSelected(collision.template bc_as().globalBC())) { + return; + } + } + + if (cfgEffCor) { + 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 BinningType = ColumnBinningPolicy; + BinningType colBinning{{vertexAxis, centAxis}, true}; + + Preslice tracksPerCollisionV0 = aod::v0data::collisionId; + void processDataMixed(EventCandidates const& collisions, + TrackCandidates const& /*tracks*/, aod::V0Datas const& V0s, aod::BCsWithTimestamps const&) + { + int currentRun = -1; + for (auto& [c1, c2] : selfCombinations(colBinning, cfgNoMixedEvents, -1, collisions, collisions)) { + if (c1.index() == c2.index()) + continue; + + auto bc1 = c1.bc_as(); + auto bc2 = c2.bc_as(); + + if (bc1.runNumber() != bc2.runNumber()) + continue; + + if (bc1.runNumber() != currentRun) { + if (cfgSkimmedProcessing) { + initCCDB(bc1); + if (!zorro.isSelected(bc1.globalBC()) || !zorro.isSelected(bc2.globalBC())) { + continue; + } + } + } + + centrality = c1.centFT0M(); + if (!eventSelected(c1)) + continue; + if (!eventSelected(c2)) + continue; + + auto tracks1 = V0s.sliceBy(tracksPerCollisionV0, c1.globalIndex()); + auto tracks2 = V0s.sliceBy(tracksPerCollisionV0, c2.globalIndex()); + + FillHistograms(c1, c2, tracks1, tracks2); + } + } + PROCESS_SWITCH(lambdalambda, processDataMixed, "Process Event for mixed data", false); +}; + +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 index ac133f93e83..772b5d04e7f 100644 --- a/PWGLF/Tasks/Strangeness/lambdapolarization.cxx +++ b/PWGLF/Tasks/Strangeness/lambdapolarization.cxx @@ -11,51 +11,49 @@ /// \author Junlee Kim (jikim1290@gmail.com) -#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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table -#include "Common/DataModel/PIDResponse.h" -#include "Common/DataModel/Multiplicity.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/trackUtilities.h" -#include "Common/Core/TrackSelection.h" - +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" #include "CommonConstants/PhysicsConstants.h" - -#include "ReconstructionDataFormats/Track.h" - -#include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" -#include "CCDB/CcdbApi.h" -#include "CCDB/BasicCCDBManager.h" +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TLorentzVector.h" +#include "TRandom3.h" +#include "TVector2.h" +#include -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -87,9 +85,15 @@ struct lambdapolarization { 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 cfgDCAPosToPVMin{"cfgDCAPosToPVMin", 0.05, "minimum DCA to PV for positive track"}; - Configurable cfgDCANegToPVMin{"cfgDCANegToPVMin", 0.2, "minimum DCA to PV for negative track"}; + 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"}; @@ -115,10 +119,33 @@ struct lambdapolarization { 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; @@ -133,14 +160,29 @@ struct lambdapolarization { 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) { @@ -156,6 +198,8 @@ struct lambdapolarization { return 4; } else if (name.value == "TPCneg") { return 5; + } else if (name.value == "TPCall") { + return 6; } else { return 0; } @@ -163,11 +207,8 @@ struct lambdapolarization { void init(o2::framework::InitContext&) { - AxisSpec massAxis = {100, 1.065, 1.165}; - AxisSpec ptAxis = {100, 0.0, 10.0}; - AxisSpec cosAxis = {110, -1.05, 1.05}; - AxisSpec centAxis = {8, 0.0, 80.0}; 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}; @@ -182,12 +223,100 @@ struct lambdapolarization { 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_cos_rap", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis, RapAxis}}); + histos.add(Form("psi%d/h_alambda_cos_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}}); @@ -199,6 +328,14 @@ struct lambdapolarization { 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}}); @@ -213,6 +350,16 @@ struct lambdapolarization { } } + 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}); @@ -273,22 +420,38 @@ struct lambdapolarization { 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) + bool SelectionV0(TCollision const& collision, V0 const& candidate, int LambdaTag) { if (candidate.v0radius() < cfgv0radiusMin) return false; - if (std::abs(candidate.dcapostopv()) < cfgDCAPosToPVMin) - return false; - if (std::abs(candidate.dcanegtopv()) < cfgDCANegToPVMin) - 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 (candidate.dcaV0daughters() > cfgDCAV0Dau) + if (std::abs(candidate.dcaV0daughters()) > cfgDCAV0Dau) return false; if (candidate.pt() < cfgV0PtMin) return false; @@ -376,6 +539,14 @@ struct lambdapolarization { 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]))); @@ -384,6 +555,14 @@ struct lambdapolarization { 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]))); @@ -392,6 +571,14 @@ struct lambdapolarization { 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]))); @@ -483,16 +670,16 @@ struct lambdapolarization { if (LambdaTag == aLambdaTag) continue; - if (!SelectionV0(collision, v0)) + if (!SelectionV0(collision, v0, LambdaTag)) continue; if (LambdaTag) { - ProtonVec = ROOT::Math::PxPyPzMVector(postrack.px(), postrack.py(), postrack.pz(), massPr); - PionVec = ROOT::Math::PxPyPzMVector(negtrack.px(), negtrack.py(), negtrack.pz(), massPi); + 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(negtrack.px(), negtrack.py(), negtrack.pz(), massPr); - PionVec = ROOT::Math::PxPyPzMVector(postrack.px(), postrack.py(), postrack.pz(), massPi); + 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); @@ -501,16 +688,17 @@ struct lambdapolarization { ProtonBoostedVec = boost(ProtonVec); angle = ProtonBoostedVec.Pz() / ProtonBoostedVec.P(); - relphi = TVector2::Phi_0_2pi(static_cast(nmode) * (LambdaVec.Phi() - TMath::ATan2(collision.qvecIm()[QvecDetInd], collision.qvecRe()[QvecDetInd]) / static_cast(nmode))); + 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()[3 + (nmode - 2) * 28], collision.qvecRe()[3 + (nmode - 2) * 28]) / static_cast(nmode); - auto psidefFT0A = TMath::ATan2(collision.qvecIm()[3 + 4 + (nmode - 2) * 28], collision.qvecRe()[3 + 4 + (nmode - 2) * 28]) / static_cast(nmode); - auto psidefFV0A = TMath::ATan2(collision.qvecIm()[3 + 12 + (nmode - 2) * 28], collision.qvecRe()[3 + 12 + (nmode - 2) * 28]) / static_cast(nmode); + 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)); @@ -523,41 +711,202 @@ struct lambdapolarization { 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, centrality, relphi); + 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), centrality); + 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); + histos.fill(HIST("psi2/h_lambda_cos_rap"), v0.mLambda(), v0.pt(), angle * weight, centrality, v0.yLambda()); + } + + 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, centrality, relphi); + 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), centrality); + 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); + histos.fill(HIST("psi2/h_alambda_cos_rap"), v0.mAntiLambda(), v0.pt(), angle * weight, centrality, v0.yLambda()); + } + + 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, centrality, relphi); + 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), centrality); + 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); + histos.fill(HIST("psi3/h_lambda_cos_rap"), v0.mLambda(), v0.pt(), angle * weight, centrality, v0.yLambda()); + } + + 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, centrality, relphi); - histos.fill(HIST("psi3/h_alambda_cos2"), v0.mAntiLambda(), v0.pt(), angle * angle, centrality, relphi); - histos.fill(HIST("psi3/h_alambda_cossin"), v0.mAntiLambda(), v0.pt(), angle * TMath::Sin(relphi), centrality); + 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); + histos.fill(HIST("psi3/h_alambda_cos_rap"), v0.mAntiLambda(), v0.pt(), angle * weight, centrality, v0.yLambda()); + } + + 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, centrality, relphi); + 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), centrality); + 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); + histos.fill(HIST("psi4/h_lambda_cos_rap"), v0.mLambda(), v0.pt(), angle * weight, centrality, v0.yLambda()); + } + + 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, centrality, relphi); + 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), centrality); + 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); + histos.fill(HIST("psi4/h_alambda_cos_rap"), v0.mAntiLambda(), v0.pt(), angle * weight, centrality, v0.yLambda()); + } + + 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 } @@ -576,6 +925,8 @@ struct lambdapolarization { 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(); @@ -591,6 +942,13 @@ struct lambdapolarization { 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); @@ -602,6 +960,89 @@ struct lambdapolarization { } // 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) diff --git a/PWGLF/Tasks/Strangeness/lambdapolsp.cxx b/PWGLF/Tasks/Strangeness/lambdapolsp.cxx new file mode 100644 index 00000000000..1f2ecd4b580 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdapolsp.cxx @@ -0,0 +1,2014 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/SPCalibrationTables.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/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TF1.h" +#include "TRandom3.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include // <<< CHANGED: for dedup sets +#include +#include +#include // <<< CHANGED: for seenMap +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using namespace o2::aod::rctsel; + +using dauTracks = soa::Join; +using v0Candidates = soa::Join; + +struct lambdapolsp { + + 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; + + int mRunNumber; + Service ccdb; + Service pdg; + o2::ccdb::CcdbApi ccdbApi; + TH1D* hwgtAL; + // fill output + struct : ConfigurableGroup { + Configurable additionalEvSel{"additionalEvSel", false, "additionalEvSel"}; + Configurable additionalEvSel2{"additionalEvSel2", false, "additionalEvSel2"}; + Configurable additionalEvSel3{"additionalEvSel3", false, "additionalEvSel3"}; + Configurable additionalEvSel4{"additionalEvSel4", false, "additionalEvSel4"}; + 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"}; + } evselGrp; + 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 sys{"sys", 1, "flag to select systematic source"}; + Configurable centestim{"centestim", 0, "flag to select centrality estimator"}; + Configurable dosystematic{"dosystematic", false, "flag to perform systematic study"}; + Configurable needetaaxis{"needetaaxis", false, "flag to use last axis"}; + struct : ConfigurableGroup { + Configurable doRandomPsi{"doRandomPsi", true, "randomize psi"}; + Configurable doRandomPsiAC{"doRandomPsiAC", true, "randomize psiAC"}; + Configurable doRandomPhi{"doRandomPhi", true, "randomize phi"}; + Configurable etaMix{"etaMix", 0.1, "eta difference in mixing"}; + Configurable ptMix{"ptMix", 0.1, "pt difference in mixing"}; + Configurable phiMix{"phiMix", 0.1, "phi difference in mixing"}; + Configurable useSP{"useSP", false, "use scalar product"}; + } randGrp; + // 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"}; + Configurable analyzeLambda{"analyzeLambda", true, "flag for lambda analysis"}; + Configurable analyzeK0s{"analyzeK0s", false, "flag for K0s analysis"}; + Configurable qtArmenterosMinForK0{"qtArmenterosMinForK0", 0.2, "Armenterous cut for K0s"}; + + // 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 rcrfc{"rcrfc", 0.8f, "Ratio of CR to FC"}; + 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 useyldwgt{"useyldwgt", false, "use yield weight"}; + 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 ConfWgtPathAL{"ConfWgtPathAL", "Users/p/prottay/My/Object/From379780/Fulldata/NewPbPbpass4_10082025/yieldweight2050", "Path to yield weight correction for AntiLambda"}; + + struct : ConfigurableGroup { + 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 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"}; + // 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"}; + } binGrp; + /* + 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"}; + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", true, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + struct : ConfigurableGroup { + 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"}; + } axisGrp; + struct : ConfigurableGroup { + ConfigurableAxis axisVertex{"axisVertex", {5, -10, 10}, "vertex axis for bin"}; + ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {8, 0, 80}, "multiplicity percentile for bin"}; + Configurable nMix{"nMix", 5, "number of event mixing"}; + } meGrp; + + struct : ConfigurableGroup { + ConfigurableAxis axisCosine{"axisCosine", {100, 0, 1}, "cosine axis"}; + ConfigurableAxis axisRadius{"axisRadius", {200, 0, 100}, "radius axis"}; + ConfigurableAxis axisDca{"axisDca", {100, -5, 5}, "dca axis"}; + ConfigurableAxis axisLT{"axisLT", {50, 0, 50}, "lifetime axis"}; + ConfigurableAxis axisCR{"axisCR", {40, 0, 200}, "CR axis"}; + ConfigurableAxis axisnsig{"axisnsig", {100, -10, 10}, "nsigma axis"}; + ConfigurableAxis axispt{"axispt", {100, 0, 10}, "pt axis"}; + Configurable filldist{"filldist", true, "fill topo distr"}; + Configurable lowmasscut{"lowmasscut", 1.11, "low mass cut"}; + Configurable highmasscut{"highmasscut", 1.12, "high mass cut"}; + } distGrp; + + RCTFlagsChecker rctChecker; + + SliceCache cache; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + AxisSpec thnAxisres{binGrp.resNbins, binGrp.lbinres, binGrp.hbinres, "Reso"}; + AxisSpec thnAxisInvMass{binGrp.IMNbins, binGrp.lbinIM, binGrp.hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + AxisSpec spAxis = {binGrp.spNbins, binGrp.lbinsp, binGrp.hbinsp, "Sp"}; + // AxisSpec qxZDCAxis = {binGrp.QxyNbins, binGrp.lbinQxy, binGrp.hbinQxy, "Qx"}; + // AxisSpec centAxis = {CentNbins, lbinCent, hbinCent, "V0M (%)"}; + + std::vector runaxes = {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}; + if (needetaaxis) + runaxes.insert(runaxes.end(), {axisGrp.configbinAxis}); + std::vector runaxes2 = {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configcentAxis}; + + if (checkwithpub) { + if (useprofile == 2) { + histos.add("hpuxQxpvscentpteta", "hpuxQxpvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyQypvscentpteta", "hpuyQypvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxQxtvscentpteta", "hpuxQxtvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyQytvscentpteta", "hpuyQytvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentpteta", "hpuxyQxytvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentpteta", "hpuxyQxypvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpoddv1vscentpteta", "hpoddv1vscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpevenv1vscentpteta", "hpevenv1vscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpv21", "hpv21", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpv22", "hpv22", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpv23", "hpv23", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx2Tx1Ax1Cvscentpteta", "hpx2Tx1Ax1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx2Ty1Ay1Cvscentpteta", "hpx2Ty1Ay1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy2Tx1Ay1Cvscentpteta", "hpy2Tx1Ay1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy2Ty1Ax1Cvscentpteta", "hpy2Ty1Ax1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx1Ax1Cvscentpteta", "hpx1Ax1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy1Ay1Cvscentpteta", "hpy1Ay1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx1Avscentpteta", "hpx1Avscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx1Cvscentpteta", "hpx1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy1Avscentpteta", "hpy1Avscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy1Cvscentpteta", "hpy1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + + histos.add("hpx2Tx1Avscentpteta", "hpx2Tx1Avscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx2Tx1Cvscentpteta", "hpx2Tx1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx2Ty1Avscentpteta", "hpx2Ty1Avscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx2Ty1Cvscentpteta", "hpx2Ty1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy2Tx1Avscentpteta", "hpy2Tx1Avscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy2Ty1Cvscentpteta", "hpy2Ty1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy2Ty1Avscentpteta", "hpy2Ty1Avscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy2Tx1Cvscentpteta", "hpy2Tx1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx1Ay1Cvscentpteta", "hpx1Ay1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy1Ax1Cvscentpteta", "hpy1Ax1Cvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpx2Tvscentpteta", "hpx2Tvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpy2Tvscentpteta", "hpy2Tvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + + histos.add("hpuxvscentpteta", "hpuxvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyvscentpteta", "hpuyvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + /* + histos.add("hpuxvscentptetaneg", "hpuxvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyvscentptetaneg", "hpuyvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + + histos.add("hpuxQxpvscentptetaneg", "hpuxQxpvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQypvscentptetaneg", "hpuyQypvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxQxtvscentptetaneg", "hpuxQxtvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuyQytvscentptetaneg", "hpuyQytvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentptetaneg", "hpuxyQxytvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentptetaneg", "hpuxyQxypvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpoddv1vscentptetaneg", "hpoddv1vscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetaneg", "hpevenv1vscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, configthnAxispT, configetaAxis, spAxis}, true); + */ + + histos.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQytQypvscent", "hpQytQypvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + + histos.add("hpQxpvscent", "hpQxpvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQxtvscent", "hpQxtvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + } else { + histos.add("hpuxQxpvscentpteta", "hpuxQxpvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyQypvscentpteta", "hpuyQypvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxQxtvscentpteta", "hpuxQxtvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyQytvscentpteta", "hpuyQytvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentpteta", "hpuxyQxytvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentpteta", "hpuxyQxypvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpoddv1vscentpteta", "hpoddv1vscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpevenv1vscentpteta", "hpevenv1vscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + + histos.add("hpuxvscentpteta", "hpuxvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyvscentpteta", "hpuyvscentpteta", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + /*histos.add("hpuxvscentptetaneg", "hpuxvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyvscentptetaneg", "hpuyvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + + histos.add("hpuxQxpvscentptetaneg", "hpuxQxpvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyQypvscentptetaneg", "hpuyQypvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxQxtvscentptetaneg", "hpuxQxtvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuyQytvscentptetaneg", "hpuyQytvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxyQxytvscentptetaneg", "hpuxyQxytvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpuxyQxypvscentptetaneg", "hpuxyQxypvscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpoddv1vscentptetaneg", "hpoddv1vscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true); + histos.add("hpevenv1vscentptetaneg", "hpevenv1vscentptetaneg", HistType::kTHnSparseF, {axisGrp.configcentAxis, axisGrp.configthnAxispT, axisGrp.configetaAxis, spAxis}, true);*/ + + histos.add("hpQxtQxpvscent", "hpQxtQxpvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQytQypvscent", "hpQytQypvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + + histos.add("hpQxpvscent", "hpQxpvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQxtvscent", "hpQxtvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + histos.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + } + } + + histos.add("hCentrality", "Centrality distribution", kTH1F, {{axisGrp.configcentAxis}}); + // 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, {axisGrp.configcentAxis, thnAxisres}); + // histos.add("hpResSin", "hpResSin", HistType::kTHnSparseF, {axisGrp.configcentAxis, thnAxisres}); + /*histos.add("hpCosPsiA", "hpCosPsiA", HistType::kTHnSparseF, {axisGrp.configcentAxis, thnAxisres}); + histos.add("hpCosPsiC", "hpCosPsiC", HistType::kTHnSparseF, {axisGrp.configcentAxis, thnAxisres}); + histos.add("hpSinPsiA", "hpSinPsiA", HistType::kTHnSparseF, {axisGrp.configcentAxis, thnAxisres}); + histos.add("hpSinPsiC", "hpSinPsiC", HistType::kTHnSparseF, {axisGrp.configcentAxis, thnAxisres});*/ + if (randGrp.useSP) { + histos.add("hcentQxZDCA", "hcentQxZDCA", kTH2F, {axisGrp.configcentAxis, spAxis}); + histos.add("hcentQyZDCA", "hcentQyZDCA", kTH2F, {axisGrp.configcentAxis, spAxis}); + histos.add("hcentQxZDCC", "hcentQxZDCC", kTH2F, {axisGrp.configcentAxis, spAxis}); + histos.add("hcentQyZDCC", "hcentQyZDCC", kTH2F, {axisGrp.configcentAxis, spAxis}); + } + 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("hSparseLambdaPolAwgt", "hSparseLambdaPolAwgt", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaPolCwgt", "hSparseLambdaPolCwgt", 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("hSparseAntiLambdaPolAwgt", "hSparseAntiLambdaPolAwgt", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaPolCwgt", "hSparseAntiLambdaPolCwgt", 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); + if (randGrp.useSP) { + histos.add("hSparseAntiLambda_avgux", "hSparseAntiLambda_avgux", HistType::kTHnSparseF, {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}, true); + histos.add("hSparseAntiLambda_avguy", "hSparseAntiLambda_avguy", HistType::kTHnSparseF, {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}, true); + histos.add("hSparseLambda_avgux", "hSparseLambda_avgux", HistType::kTHnSparseF, {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}, true); + histos.add("hSparseLambda_avguy", "hSparseLambda_avguy", HistType::kTHnSparseF, {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}, true); + } + } + + if (distGrp.filldist) { + histos.add("hcosinelambda", "hcosinelambda", HistType::kTH1D, {distGrp.axisCosine}, true); + histos.add("hdcabwv0daughlambda", "hdcabwv0daughlambda", HistType::kTH1D, {distGrp.axisDca}, true); + histos.add("hlifetimelambda", "hlifetimelambda", HistType::kTH1D, {distGrp.axisLT}, true); + histos.add("hradiuslambda", "hradiuslambda", HistType::kTH1D, {distGrp.axisRadius}, true); + histos.add("hdcaposlambda", "hdcaposlambda", HistType::kTH1D, {distGrp.axisDca}, true); + histos.add("hdcaneglambda", "hdcaneglambda", HistType::kTH1D, {distGrp.axisDca}, true); + histos.add("htpcCRlambda", "htpcCRlambda", HistType::kTH1D, {distGrp.axisCR}, true); + histos.add("htpcposlambda", "htpcposlambda", HistType::kTH1D, {distGrp.axisnsig}, true); + histos.add("htpcneglambda", "htpcneglambda", HistType::kTH1D, {distGrp.axisnsig}, true); + histos.add("hptposlambda", "hptposlambda", HistType::kTH1D, {distGrp.axispt}, true); + histos.add("hptneglambda", "hptneglambda", HistType::kTH1D, {distGrp.axispt}, true); + + histos.add("hcosineantilambda", "hcosineantilambda", HistType::kTH1D, {distGrp.axisCosine}, true); + histos.add("hdcabwv0daughantilambda", "hdcabwv0daughantilambda", HistType::kTH1D, {distGrp.axisDca}, true); + histos.add("hlifetimeantilambda", "hlifetimeantilambda", HistType::kTH1D, {distGrp.axisLT}, true); + histos.add("hradiusantilambda", "hradiusantilambda", HistType::kTH1D, {distGrp.axisRadius}, true); + histos.add("hdcaposantilambda", "hdcaposantilambda", HistType::kTH1D, {distGrp.axisDca}, true); + histos.add("hdcanegantilambda", "hdcanegantilambda", HistType::kTH1D, {distGrp.axisDca}, true); + histos.add("htpcCRantilambda", "htpcCRantilambda", HistType::kTH1D, {distGrp.axisCR}, true); + histos.add("htpcposantilambda", "htpcposantilambda", HistType::kTH1D, {distGrp.axisnsig}, true); + histos.add("htpcnegantilambda", "htpcnegantilambda", HistType::kTH1D, {distGrp.axisnsig}, true); + histos.add("hptposantilambda", "hptposantilambda", HistType::kTH1D, {distGrp.axispt}, true); + histos.add("hptnegantilambda", "hptnegantilambda", HistType::kTH1D, {distGrp.axispt}, true); + } + + histos.add("hSparseGenLambda", "hSparseGenLambda", HistType::kTHnSparseF, runaxes2, true); + histos.add("hSparseGenAntiLambda", "hSparseGenAntiLambda", HistType::kTHnSparseF, runaxes2, true); + histos.add("hSparseRecLambda", "hSparseRecLambda", HistType::kTHnSparseF, runaxes2, true); + histos.add("hSparseRecAntiLambda", "hSparseRecAntiLambda", HistType::kTHnSparseF, runaxes2, true); + + 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()); + LOGF(info, "Getting alignment offsets from the CCDB..."); + hwgtAL = ccdb->getForTimeStamp(ConfWgtPathAL.value, cfgCcdbParam.nolaterthan.value); + } + + 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 CtauK0s = candidate.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massK0s; + // 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 (analyzeLambda && TMath::Abs(CtauLambda) > cMaxV0LifeTime) { + return false; + } + if (analyzeK0s && TMath::Abs(CtauK0s) > cMaxV0LifeTime) { + return false; + } + if (analyzeLambda && TMath::Abs(candidate.yLambda()) > ConfV0Rap) { + return false; + } + if (analyzeK0s && TMath::Abs(candidate.yK0Short()) > ConfV0Rap) { + return false; + } + return true; + } + + template + bool isSelectedV0Daughter(V0 const& candidate, T const& track, int pid, int pid2) + { + // const auto eta = track.eta(); + // const auto pt = track.pt(); + const auto tpcNClsF = track.tpcNClsFound(); + if (track.tpcNClsCrossedRows() < cfgTPCcluster) { + return false; + } + /*if (TMath::Abs(eta) > ConfDaughEta) { + return false; + }*/ + + if (tpcNClsF < ConfDaughTPCnclsMin) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < rcrfc) { + 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 (pid2 == 0 && (TMath::Abs(candidate.dcapostopv()) < cMinV0DCAPr || TMath::Abs(candidate.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + if (pid2 == 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() < cfgTPCcluster || negTrackExtra.tpcNClsCrossedRows() < cfgTPCcluster) { + return false; + } + + if (posTrackExtra.tpcNClsFound() < ConfDaughTPCnclsMin || negTrackExtra.tpcNClsFound() < ConfDaughTPCnclsMin) { + return false; + } + if (posTrackExtra.tpcCrossedRowsOverFindableCls() < rcrfc || negTrackExtra.tpcCrossedRowsOverFindableCls() < rcrfc) { + 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; + } + + template + bool isCompatibleK0s(TV0 const& v0) + { + // 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 ((v0.positivept() < cfgDaughPrPt || v0.negativept() < cfgDaughPiPt)) { + return false; // doesn´t pass lambda pT sels + } + if (std::abs(v0.positiveeta()) > ConfDaughEta || std::abs(v0.negativeeta()) > ConfDaughEta) { + return false; + } + // check TPC tracking properties + if (posTrackExtra.tpcNClsCrossedRows() < cfgTPCcluster || negTrackExtra.tpcNClsCrossedRows() < cfgTPCcluster) { + return false; + } + + if (posTrackExtra.tpcNClsFound() < ConfDaughTPCnclsMin || negTrackExtra.tpcNClsFound() < ConfDaughTPCnclsMin) { + return false; + } + if (posTrackExtra.tpcCrossedRowsOverFindableCls() < rcrfc || negTrackExtra.tpcCrossedRowsOverFindableCls() < rcrfc) { + return false; + } + + // check TPC PID + if (((std::abs(posTrackExtra.tpcNSigmaPi()) > ConfDaughPIDCuts) || (std::abs(negTrackExtra.tpcNSigmaPi()) > ConfDaughPIDCuts))) { + return false; + } + if ((TMath::Abs(v0.dcapostopv()) < cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + if ((v0.qtarm() / (std::abs(v0.alpha()))) < qtArmenterosMinForK0) { + 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)); + } + + double modqxZDCA; + double modqyZDCA; + double modqxZDCC; + double modqyZDCC; + + 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, double wgtfactor) + { + TRandom3 randPhi(0); + + ROOT::Math::Boost boost{particle.BoostToCM()}; + auto fourVecDauCM = boost(daughter); + auto phiangle = TMath::ATan2(fourVecDauCM.Py(), fourVecDauCM.Px()); + if (randGrp.doRandomPhi) { + phiangle = randPhi.Uniform(0, 2 * TMath::Pi()); + } + + auto ux = TMath::Cos(phiangle); + auto uy = TMath::Sin(phiangle); + + 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 PolSP = uy * TMath::Cos(psiZDC) - ux * TMath::Sin(psiZDC); + auto PolSP = uy * (modqxZDCC - modqxZDCA) - ux * (modqyZDCC - modqyZDCA); + 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; + auto PolAwgt = PolA / acvalue; + auto PolCwgt = PolC / acvalue; + + if (randGrp.useSP) + Polwgt = PolSP / acvalue; + + // Fill histograms using constructed names + if (tag2) { + if (needetaaxis) { + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); + } + histos.fill(HIST("hSparseAntiLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, PolA, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, PolC, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, desbinvalue, wgtfactor); + } + histos.fill(HIST("hSparseAntiLambdaPol"), candmass, candpt, Pol, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, desbinvalue, wgtfactor); + // histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, phiphiStar, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, desbinvalue, wgtfactor); + // histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, desbinvalue, wgtfactor); + if (randGrp.useSP) { + histos.fill(HIST("hSparseAntiLambda_avgux"), candmass, candpt, ux, centrality); + histos.fill(HIST("hSparseAntiLambda_avguy"), candmass, candpt, uy, centrality); + } + } else { + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, wgtfactor); + } + histos.fill(HIST("hSparseAntiLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, wgtfactor); + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, PolA, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, PolC, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, wgtfactor); + } + histos.fill(HIST("hSparseAntiLambdaPol"), candmass, candpt, Pol, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, wgtfactor); + // histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, phiphiStar, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, wgtfactor); + // histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, wgtfactor); + } + } + if (tag1) { + if (needetaaxis) { + if (usesubdet) { + histos.fill(HIST("hSparseLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); + } + histos.fill(HIST("hSparseLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); + if (usesubdet) { + histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, PolA, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, PolC, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, desbinvalue, wgtfactor); + } + histos.fill(HIST("hSparseLambdaPol"), candmass, candpt, Pol, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, desbinvalue, wgtfactor); + // histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, phiphiStar, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, desbinvalue, wgtfactor); + // histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, desbinvalue, wgtfactor); + if (randGrp.useSP) { + histos.fill(HIST("hSparseLambda_avgux"), candmass, candpt, ux, centrality); + histos.fill(HIST("hSparseLambda_avguy"), candmass, candpt, uy, centrality); + } + } else { + if (usesubdet) { + histos.fill(HIST("hSparseLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, wgtfactor); + } + histos.fill(HIST("hSparseLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, wgtfactor); + if (usesubdet) { + histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, PolA, centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, PolC, centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, wgtfactor); + } + histos.fill(HIST("hSparseLambdaPol"), candmass, candpt, Pol, centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, wgtfactor); + histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, wgtfactor); + histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, wgtfactor); + // histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, phiphiStar, centrality, wgtfactor); + histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, wgtfactor); + // histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, wgtfactor); + } + } + } + + ROOT::Math::PxPyPzMVector Lambda, AntiLambda, Lambdadummy, AntiLambdadummy, Proton, Pion, AntiProton, AntiPion, fourVecDauCM, K0sdummy, K0s; + ROOT::Math::XYZVector threeVecDauCM, threeVecDauCMXY; + double phiangle = 0.0; + // double angleLambda=0.0; + // double angleAntiLambda=0.0; + double massLambda = o2::constants::physics::MassLambda; + double massK0s = o2::constants::physics::MassK0Short; + 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 EventCandidatesMC = 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; + } + double centrality = -999.; + if (centestim == 0) + centrality = collision.centFT0C(); + else if (centestim == 1) + centrality = collision.centFT0M(); + else if (centestim == 2) + centrality = collision.centFT0A(); + else if (centestim == 3) + centrality = collision.centFV0A(); + + // histos.fill(HIST("hCentrality0"), centrality); + if (!collision.triggereventsp()) { + return; + } + // histos.fill(HIST("hCentrality1"), centrality); + + if (evselGrp.additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + // histos.fill(HIST("hCentrality2"), centrality); + // if (evselGrp.additionalEvSel2 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + if (evselGrp.additionalEvSel2 && (collision.trackOccupancyInTimeRange() > evselGrp.cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < evselGrp.cfgMinOccupancy)) { + return; + } + // histos.fill(HIST("hCentrality3"), centrality); + if (evselGrp.additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + + if (evselGrp.additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + 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(); + + 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()); + if (randGrp.useSP) { + histos.fill(HIST("hpRes"), centrality, ((modqxZDCA * modqxZDCC) + (modqyZDCA * modqyZDCC))); + // 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, modqxZDCA); + histos.fill(HIST("hcentQyZDCA"), centrality, modqyZDCA); + histos.fill(HIST("hcentQxZDCC"), centrality, modqxZDCC); + histos.fill(HIST("hcentQyZDCC"), centrality, modqyZDCC); + } else { + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); + } + } + + ///////////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, 0) && isSelectedV0Daughter(v0, negtrack, 1, 0)) { + LambdaTag = 1; + } + if (isSelectedV0Daughter(v0, negtrack, 0, 1) && isSelectedV0Daughter(v0, postrack, 1, 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()); + } + double acvalue = 1.0; + int binxwgt; + double wgtvalue; + if (useyldwgt) { + binxwgt = hwgtAL->GetXaxis()->FindBin(v0.pt()); + wgtvalue = hwgtAL->GetBinContent(binxwgt); + } else { + wgtvalue = 1.0; + } + + 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; + if (useAccCorr) { + int binx = accprofileL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileL->GetYaxis()->FindBin(v0.pt()); + acvalue = accprofileL->GetBinContent(binx, biny); + } else { + acvalue = 1.0; + } + + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mLambda(), v0.pt(), desbinvalue, acvalue, 1.0); + } + + tagb = aLambdaTag; + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + if (useAccCorr) { + int binx = accprofileAL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileAL->GetYaxis()->FindBin(v0.pt()); + acvalue = accprofileAL->GetBinContent(binx, biny); + } else { + acvalue = 1.0; + } + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mAntiLambda(), v0.pt(), desbinvalue, acvalue, 1.0); + } + } + } else { + if (LambdaTag) { + Lambda = Proton + AntiPion; + tagb = 0; + if (useAccCorr) { + int binx = accprofileL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileL->GetYaxis()->FindBin(v0.pt()); + acvalue = accprofileL->GetBinContent(binx, biny); + } else { + acvalue = 1.0; + } + if (distGrp.filldist && aLambdaTag == 0 && Lambda.M() > distGrp.lowmasscut && Lambda.M() < distGrp.highmasscut) { + histos.fill(HIST("hcosinelambda"), v0.v0cosPA()); + histos.fill(HIST("hdcabwv0daughlambda"), v0.dcaV0daughters()); + histos.fill(HIST("hlifetimelambda"), TMath::Abs(v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda)); + histos.fill(HIST("hradiuslambda"), v0.v0radius()); + histos.fill(HIST("htpcCRlambda"), postrack.tpcNClsCrossedRows()); + histos.fill(HIST("hdcaposlambda"), v0.dcapostopv()); + histos.fill(HIST("hdcaneglambda"), v0.dcanegtopv()); + histos.fill(HIST("htpcposlambda"), postrack.tpcNSigmaPr()); + histos.fill(HIST("htpcneglambda"), negtrack.tpcNSigmaPi()); + histos.fill(HIST("hptposlambda"), Proton.Pt()); + histos.fill(HIST("hptneglambda"), AntiPion.Pt()); + } + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mLambda(), v0.pt(), v0.eta(), acvalue, 1.0); + } + + tagb = aLambdaTag; + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + if (useAccCorr) { + int binx = accprofileAL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileAL->GetYaxis()->FindBin(v0.pt()); + acvalue = accprofileAL->GetBinContent(binx, biny); + } else { + acvalue = 1.0; + } + if (distGrp.filldist && LambdaTag == 0 && AntiLambda.M() > distGrp.lowmasscut && AntiLambda.M() < distGrp.highmasscut) { + histos.fill(HIST("hcosineantilambda"), v0.v0cosPA()); + histos.fill(HIST("hdcabwv0daughantilambda"), v0.dcaV0daughters()); + histos.fill(HIST("hlifetimeantilambda"), TMath::Abs(v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * massLambda)); + histos.fill(HIST("hradiusantilambda"), v0.v0radius()); + histos.fill(HIST("htpcCRantilambda"), postrack.tpcNClsCrossedRows()); + histos.fill(HIST("hdcaposantilambda"), v0.dcapostopv()); + histos.fill(HIST("hdcanegantilambda"), v0.dcanegtopv()); + histos.fill(HIST("htpcposantilambda"), postrack.tpcNSigmaPi()); + histos.fill(HIST("htpcnegantilambda"), negtrack.tpcNSigmaPr()); + histos.fill(HIST("hptposantilambda"), Pion.Pt()); + histos.fill(HIST("hptnegantilambda"), AntiProton.Pt()); + } + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mAntiLambda(), v0.pt(), v0.eta(), acvalue, wgtvalue); + } + } + } + } + // 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&) + { + //___________________________________________________________________________________________________ + // event selection + if (!collision.sel8()) { + return; + } + double centrality = -999.; + if (centestim == 0) + centrality = collision.centFT0C(); + else if (centestim == 1) + centrality = collision.centFT0M(); + else if (centestim == 2) + centrality = collision.centFT0A(); + else if (centestim == 3) + centrality = collision.centFV0A(); + + auto runnumber = collision.runNumber(); + // auto centrality = collision.centFT0C(); + if (!collision.triggereventsp()) { // provided by StraZDCSP + return; + } + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + return; + } + + if (evselGrp.additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + // histos.fill(HIST("hCentrality2"), centrality); + // if (evselGrp.additionalEvSel2 && (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) { + if (evselGrp.additionalEvSel2 && (collision.trackOccupancyInTimeRange() > evselGrp.cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < evselGrp.cfgMinOccupancy)) { + return; + } + // histos.fill(HIST("hCentrality3"), centrality); + if (evselGrp.additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + + if (evselGrp.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()); + } + */ + auto timestamps = ccdb->getRunDuration(runnumber, true); /// fatalise if timestamps are not found + int64_t sorTimestamp = timestamps.first; // timestamp of the SOR/SOX/STF in ms + int64_t eorTimestamp = timestamps.second; // timestamp of the EOR/EOX/ETF in ms + int64_t ts = eorTimestamp / 2 + sorTimestamp / 2; // timestamp of the middle of the run + + if (useAccCorr) { + accprofileL = ccdb->getForTimeStamp(ConfAccPathL.value, ts); + accprofileAL = ccdb->getForTimeStamp(ConfAccPathAL.value, ts); + } + + //___________________________________________________________________________________________________ + // 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()); + if (randGrp.useSP) { + histos.fill(HIST("hpRes"), centrality, ((modqxZDCA * modqxZDCC) + (modqyZDCA * modqyZDCC))); + // 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, modqxZDCA); + histos.fill(HIST("hcentQyZDCA"), centrality, modqyZDCA); + histos.fill(HIST("hcentQxZDCC"), centrality, modqxZDCC); + histos.fill(HIST("hcentQyZDCC"), centrality, modqyZDCC); + } else { + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); + } + } + + //___________________________________________________________________________________________________ + // loop over V0s as necessary + for (const auto& v0 : V0s) { + + if (analyzeLambda && analyzeK0s) + continue; + if (!analyzeLambda && !analyzeK0s) + continue; + + bool LambdaTag = isCompatible(v0, 0); + bool aLambdaTag = isCompatible(v0, 1); + + bool K0sTag = isCompatibleK0s(v0); + + if (analyzeLambda && !LambdaTag && !aLambdaTag) + continue; + + if (analyzeK0s && !K0sTag) + continue; + + if (!SelectionV0(collision, v0)) { + continue; + } + if (analyzeLambda) { + 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 (analyzeK0s) { + if (K0sTag) { + Pion = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), massPi); + AntiPion = ROOT::Math::PxPyPzMVector(v0.pxneg(), v0.pyneg(), v0.pzneg(), massPi); + K0sdummy = Pion + AntiPion; + } + } + + if (TMath::Abs(v0.eta()) > 0.8) + continue; + + int taga = LambdaTag; + int tagb = aLambdaTag; + int tagc = K0sTag; + + float desbinvalue = 0.0; + + if (analyzeK0s && K0sTag) { + K0s = Pion + AntiPion; + double acvalue = 1.0; + fillHistograms(tagc, 0, K0s, Pion, psiZDCC, psiZDCA, psiZDC, centrality, v0.mK0Short(), v0.pt(), v0.eta(), acvalue, 1.0); + } + + if (analyzeLambda && 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 (analyzeLambda && 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, 1.0); + } + + tagb = aLambdaTag; + if (analyzeLambda && 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, 1.0); + } + } + } else { + + int binxwgt; + double wgtvalue; + if (useyldwgt) { + binxwgt = hwgtAL->GetXaxis()->FindBin(v0.pt()); + wgtvalue = hwgtAL->GetBinContent(binxwgt); + } else { + wgtvalue = 1.0; + } + if (analyzeLambda && LambdaTag) { + Lambda = Proton + AntiPion; + tagb = 0; + double acvalue = 1.0; + if (useAccCorr) { + int binx = accprofileL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileL->GetYaxis()->FindBin(v0.pt()); + acvalue = accprofileL->GetBinContent(binx, biny); + } else { + acvalue = 1.0; + } + // double acvalue = 1.0; + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mLambda(), v0.pt(), v0.eta(), acvalue, 1.0); + } + + tagb = aLambdaTag; + if (analyzeLambda && aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + double acvalue = 1.0; + if (useAccCorr) { + int binx = accprofileAL->GetXaxis()->FindBin(v0.eta()); + int biny = accprofileAL->GetYaxis()->FindBin(v0.pt()); + acvalue = accprofileAL->GetBinContent(binx, biny); + } else { + acvalue = 1.0; + } + // double acvalue = 1.0; + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, psiZDC, centrality, v0.mAntiLambda(), v0.pt(), v0.eta(), acvalue, wgtvalue); + } + } + } + // lastRunNumber = currentRunNumber; + } + PROCESS_SWITCH(lambdapolsp, processDerivedData, "Process derived data", false); + + using TrackMCTrueTable = aod::McParticles; + ROOT::Math::PxPyPzMVector lambdadummymc, antiLambdadummymc, protonmc, pionmc, antiProtonmc, antiPionmc; + + void processMC(EventCandidatesMC::iterator const& collision, AllTrackCandidates const& /*tracks*/, TrackMCTrueTable const& GenParticles, ResoV0s const& V0s) + { + if (!collision.sel8()) { + return; + } + double centrality = -999.; + centrality = collision.centFT0C(); + + if (evselGrp.additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + + if (evselGrp.additionalEvSel2 && (collision.trackOccupancyInTimeRange() > evselGrp.cfgMaxOccupancy || collision.trackOccupancyInTimeRange() < evselGrp.cfgMinOccupancy)) { + return; + } + + if (evselGrp.additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + if (evselGrp.additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + return; + } + + histos.fill(HIST("hCentrality"), centrality); + + 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, 0) && isSelectedV0Daughter(v0, negtrack, 1, 0)) { + LambdaTag = 1; + } + if (isSelectedV0Daughter(v0, negtrack, 0, 1) && isSelectedV0Daughter(v0, postrack, 1, 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; + } + 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; + } + + if (shouldReject(LambdaTag, aLambdaTag, Lambdadummy, AntiLambdadummy)) { + continue; + } + + if (TMath::Abs(v0.eta()) > 0.8) + continue; + + if (LambdaTag) { + Lambda = Proton + AntiPion; + histos.fill(HIST("hSparseRecLambda"), v0.mLambda(), v0.pt(), centrality); + } + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + histos.fill(HIST("hSparseRecAntiLambda"), v0.mAntiLambda(), v0.pt(), centrality); + } + } + + for (const auto& mcParticle : GenParticles) { + if (std::abs(mcParticle.pdgCode()) != PDG_t::kLambda0) { + continue; + } + if (std::abs(mcParticle.y()) > ConfV0Rap) { + continue; + } + auto pdg1 = mcParticle.pdgCode(); + auto kDaughters = mcParticle.daughters_as(); + int daughsize = 2; + if (kDaughters.size() != daughsize) { + continue; + } + for (const auto& kCurrentDaughter : kDaughters) { + + if (std::abs(kCurrentDaughter.pdgCode()) != PDG_t::kProton && std::abs(kCurrentDaughter.pdgCode()) != PDG_t::kPiPlus) { + continue; + } + if (kCurrentDaughter.pdgCode() == PDG_t::kProton) { + protonmc = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassProton); + } + if (kCurrentDaughter.pdgCode() == PDG_t::kPiMinus) { + antiPionmc = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassPionCharged); + } + + if (kCurrentDaughter.pdgCode() == PDG_t::kProtonBar) { + antiProtonmc = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassProton); + } + if (kCurrentDaughter.pdgCode() == PDG_t::kPiPlus) { + pionmc = ROOT::Math::PxPyPzMVector(kCurrentDaughter.px(), kCurrentDaughter.py(), kCurrentDaughter.pz(), o2::constants::physics::MassPionCharged); + } + } + if (pdg1 == PDG_t::kLambda0) { + lambdadummymc = protonmc + antiPionmc; + histos.fill(HIST("hSparseGenLambda"), lambdadummymc.M(), lambdadummymc.Pt(), centrality); + } + + if (pdg1 == PDG_t::kLambda0Bar) { + antiLambdadummymc = antiProtonmc + pionmc; + histos.fill(HIST("hSparseGenAntiLambda"), antiLambdadummymc.M(), antiLambdadummymc.Pt(), centrality); + } + } + } + PROCESS_SWITCH(lambdapolsp, processMC, "Process MC", false); + + // Processing Event Mixing + /* + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{meGrp.axisVertex, meGrp.axisMultiplicityClass}, true}; + Preslice tracksPerCollisionV0Mixed = o2::aod::v0data::straCollisionId; // for derived data only + + void processDerivedDataMixed(soa::Join const& collisions, v0Candidates const& V0s, dauTracks const&) + { + TRandom3 randGen(0); + + for (auto& [collision1, collision2] : selfCombinations(colBinning, meGrp.nMix, -1, collisions, collisions)) { + + if (collision1.index() == collision2.index()) { + continue; + } + + if (!collision1.sel8()) { + continue; + } + if (!collision2.sel8()) { + continue; + } + + if (!collision1.triggereventsp()) { // provided by StraZDCSP + continue; + } + if (!collision2.triggereventsp()) { // provided by StraZDCSP + continue; + } + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctChecker(collision2)) { + continue; + } + + if (evselGrp.additionalEvSel && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (evselGrp.additionalEvSel && (!collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (evselGrp.additionalEvSel2 && (collision1.trackOccupancyInTimeRange() > evselGrp.cfgMaxOccupancy || collision1.trackOccupancyInTimeRange() < evselGrp.cfgMinOccupancy)) { + continue; + } + if (evselGrp.additionalEvSel2 && (collision2.trackOccupancyInTimeRange() > evselGrp.cfgMaxOccupancy || collision2.trackOccupancyInTimeRange() < evselGrp.cfgMinOccupancy)) { + continue; + } + if (evselGrp.additionalEvSel3 && (!collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (evselGrp.additionalEvSel3 && (!collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (evselGrp.additionalEvSel4 && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + if (evselGrp.additionalEvSel4 && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + + auto centrality = collision1.centFT0C(); + auto qxZDCA = collision2.qxZDCA(); + auto qxZDCC = collision2.qxZDCC(); + auto qyZDCA = collision2.qyZDCA(); + auto qyZDCC = collision2.qyZDCC(); + auto psiZDCC = collision2.psiZDCC(); + auto psiZDCA = collision2.psiZDCA(); + double modqxZDCA; + double modqyZDCA; + double modqxZDCC; + double modqyZDCC; + + 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); + + auto psiZDC = TMath::ATan2((modqyZDCC - modqyZDCA), (modqxZDCC - modqxZDCA)); // full event plane from collision 2 + auto groupV0 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision1.index()); + + histos.fill(HIST("hCentrality"), centrality); + + if (randGrp.doRandomPsi) { + psiZDC = randGen.Uniform(0, 2 * TMath::Pi()); + } + if (randGrp.doRandomPsiAC) { + psiZDCA = randGen.Uniform(0, 2 * TMath::Pi()); + psiZDCC = randGen.Uniform(0, 2 * TMath::Pi()); + } + + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); + // histos.fill(HIST("hpResSin"), centrality, (TMath::Sin(GetPhiInRange(psiZDCA - psiZDCC)))); + + for (const auto& v0 : groupV0) { + + bool LambdaTag = isCompatible(v0, 0); + bool aLambdaTag = isCompatible(v0, 1); + if (!LambdaTag && !aLambdaTag) + continue; + if (!SelectionV0(collision1, 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; + } + 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; + } + if (shouldReject(LambdaTag, aLambdaTag, Lambdadummy, AntiLambdadummy)) { + continue; + } + if (TMath::Abs(v0.eta()) > 0.8) + continue; + int taga = LambdaTag; + int tagb = aLambdaTag; + + 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, 1.0); + } + + 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, 1.0); + } + } + } + } + PROCESS_SWITCH(lambdapolsp, processDerivedDataMixed, "Process mixed event using derived data", false); + + + void processDerivedDataMixed2(soa::Join const& collisions, v0Candidates const& V0s, dauTracks const&) + { + TRandom3 randGen(0); + + for (auto& [collision1, collision2] : selfCombinations(colBinning, meGrp.nMix, -1, collisions, collisions)) { + + if (collision1.index() == collision2.index()) { + continue; + } + + if (!collision1.sel8()) { + continue; + } + if (!collision2.sel8()) { + continue; + } + + if (!collision1.triggereventsp()) { // provided by StraZDCSP + continue; + } + if (!collision2.triggereventsp()) { // provided by StraZDCSP + continue; + } + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctChecker(collision2)) { + continue; + } + + if (evselGrp.additionalEvSel && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (evselGrp.additionalEvSel && (!collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (evselGrp.additionalEvSel2 && (collision1.trackOccupancyInTimeRange() > evselGrp.cfgMaxOccupancy || collision1.trackOccupancyInTimeRange() < evselGrp.cfgMinOccupancy)) { + continue; + } + if (evselGrp.additionalEvSel2 && (collision2.trackOccupancyInTimeRange() > evselGrp.cfgMaxOccupancy || collision2.trackOccupancyInTimeRange() < evselGrp.cfgMinOccupancy)) { + continue; + } + if (evselGrp.additionalEvSel3 && (!collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (evselGrp.additionalEvSel3 && (!collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (evselGrp.additionalEvSel4 && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + if (evselGrp.additionalEvSel4 && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + auto centrality = collision1.centFT0C(); + auto qxZDCA = collision1.qxZDCA(); + auto qxZDCC = collision1.qxZDCC(); + auto qyZDCA = collision1.qyZDCA(); + auto qyZDCC = collision1.qyZDCC(); + auto psiZDCC = collision1.psiZDCC(); + auto psiZDCA = collision1.psiZDCA(); + double modqxZDCA; + double modqyZDCA; + double modqxZDCC; + double modqyZDCC; + + 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); + + auto psiZDC = TMath::ATan2((modqyZDCC - modqyZDCA), (modqxZDCC - modqxZDCA)); // full event plane from collision 2 + + histos.fill(HIST("hCentrality"), centrality); + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); + // histos.fill(HIST("hpResSin"), centrality, (TMath::Sin(GetPhiInRange(psiZDCA - psiZDCC)))); + + // V0s from collision1 to match kinematics + auto v0sCol1 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision1.index()); + // V0s from collision2 to test + auto v0sCol2 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision2.index()); + + for (const auto& v0_2 : v0sCol2) { + + bool LambdaTag = isCompatible(v0_2, 0); + bool aLambdaTag = isCompatible(v0_2, 1); + if (!LambdaTag && !aLambdaTag) + continue; + if (!SelectionV0(collision2, v0_2)) + continue; + if (LambdaTag) { + Proton = ROOT::Math::PxPyPzMVector(v0_2.pxpos(), v0_2.pypos(), v0_2.pzpos(), massPr); + AntiPion = ROOT::Math::PxPyPzMVector(v0_2.pxneg(), v0_2.pyneg(), v0_2.pzneg(), massPi); + Lambdadummy = Proton + AntiPion; + } + if (aLambdaTag) { + AntiProton = ROOT::Math::PxPyPzMVector(v0_2.pxneg(), v0_2.pyneg(), v0_2.pzneg(), massPr); + Pion = ROOT::Math::PxPyPzMVector(v0_2.pxpos(), v0_2.pypos(), v0_2.pzpos(), massPi); + AntiLambdadummy = AntiProton + Pion; + } + if (shouldReject(LambdaTag, aLambdaTag, Lambdadummy, AntiLambdadummy)) { + continue; + } + if (TMath::Abs(v0_2.eta()) > 0.8) + continue; + + // Check if lambda kinematics from collision2 matches with collision1 + bool matched = false; + for (const auto& v0_1 : v0sCol1) { + bool LambdaTag1 = isCompatible(v0_1, 0); + bool aLambdaTag1 = isCompatible(v0_1, 1); + if (!LambdaTag1 && !aLambdaTag1) + continue; + if (!SelectionV0(collision1, v0_1)) + continue; + if (TMath::Abs(v0_1.eta()) > 0.8) + continue; + + double deta = std::abs(v0_1.eta() - v0_2.eta()); + double dpt = std::abs(v0_1.pt() - v0_2.pt()); + double dphi = RecoDecay::constrainAngle(v0_1.phi() - v0_2.phi(), 0.0); + if (deta < randGrp.etaMix && dpt < randGrp.ptMix && dphi < randGrp.phiMix && ((v0_1.eta() * v0_2.eta()) > 0.0)) { + matched = true; + break; + } + } + if (!matched) + continue; + + int taga = LambdaTag; + int tagb = aLambdaTag; + + if (LambdaTag) { + Lambda = Proton + AntiPion; + tagb = 0; + double acvalue = 1.0; + fillHistograms(taga, tagb, Lambda, Proton, psiZDCC, psiZDCA, psiZDC, centrality, v0_2.mLambda(), v0_2.pt(), v0_2.eta(), acvalue, 1.0); + } + + tagb = aLambdaTag; + if (aLambdaTag) { + AntiLambda = AntiProton + Pion; + taga = 0; + double acvalue = 1.0; + fillHistograms(taga, tagb, AntiLambda, AntiProton, psiZDCC, psiZDCA, psiZDC, centrality, v0_2.mAntiLambda(), v0_2.pt(), v0_2.eta(), acvalue, 1.0); + } + } + } + } + PROCESS_SWITCH(lambdapolsp, processDerivedDataMixed2, "Process mixed event2 using derived data", false); + */ +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"lambdapolsp"})}; +} diff --git a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx new file mode 100644 index 00000000000..9040c6bf16d --- /dev/null +++ b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx @@ -0,0 +1,1045 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 sourav.kundu@cern.ch + +#include "PWGLF/DataModel/LFSpincorrelationTables.h" + +#include "Common/Core/trackUtilities.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/BinningPolicy.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include // for std::fabs +#include +#include +#include +#include +#include +#include +#include // <<< CHANGED: for dedup sets +#include +#include +#include // <<< CHANGED: for seenMap +#include +#include + +// o2 includes. +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +struct lambdaspincorrderived { + // BinningType colBinning; + 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; + TH3D* hweight1; + TH3D* hweight2; + TH3D* hweight3; + TH3D* hweight4; + + TH3D* hweight12; + TH3D* hweight22; + TH3D* hweight32; + TH3D* hweight42; + + Configurable ConfWeightPathLL{"ConfWeightPathLL", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path"}; + Configurable ConfWeightPathALAL{"ConfWeightPathALAL", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path"}; + Configurable ConfWeightPathLAL{"ConfWeightPathLAL", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path"}; + Configurable ConfWeightPathALL{"ConfWeightPathALL", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path"}; + + Configurable ConfWeightPathLL2{"ConfWeightPathLL2", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path 2"}; + Configurable ConfWeightPathALAL2{"ConfWeightPathALAL2", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path 2"}; + Configurable ConfWeightPathLAL2{"ConfWeightPathLAL2", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path 2"}; + Configurable ConfWeightPathALL2{"ConfWeightPathALL2", "Users/s/skundu/My/Object/spincorr/cent010LL", "Weight path 2"}; + + // event sel///////// + Configurable centMin{"centMin", 0, "Minimum Centrality"}; + Configurable centMax{"centMax", 80, "Maximum Centrality"}; + Configurable rngSeed{"rngSeed", 12345, "Seed for random mixing (reproducible)"}; + std::mt19937 rng{12345}; + // Lambda selection //////////// + Configurable harmonic{"harmonic", 1, "Harmonic phi"}; + Configurable harmonicDphi{"harmonicDphi", 2, "Harmonic delta phi"}; + Configurable useweight{"useweight", 0, "Use weight"}; + Configurable usebothweight{"usebothweight", 1, "Use both weight"}; + // Configurable useNUA{"useNUA", 0, "Use NUA weight"}; + Configurable usePDGM{"usePDGM", 1, "Use PDG mass"}; + Configurable useAdditionalHisto{"useAdditionalHisto", 0, "Use additional histogram"}; + Configurable checkDoubleStatus{"checkDoubleStatus", 0, "Check Double status"}; + Configurable cosPA{"cosPA", 0.995, "Cosine Pointing Angle"}; + Configurable radiusMin{"radiusMin", 3, "Minimum V0 radius"}; + Configurable radiusMax{"radiusMax", 30, "Maximum V0 radius"}; + Configurable dcaProton{"dcaProton", 0.1, "DCA Proton"}; + Configurable dcaPion{"dcaPion", 0.2, "DCA Pion"}; + Configurable dcaDaughters{"dcaDaughters", 1.0, "DCA between daughters"}; + Configurable ptMin{"ptMin", 0.5, "V0 Pt minimum"}; + Configurable ptMax{"ptMax", 3.0, "V0 Pt maximum"}; + Configurable MassMin{"MassMin", 1.09, "V0 Mass minimum"}; + Configurable MassMax{"MassMax", 1.14, "V0 Mass maximum"}; + Configurable rapidity{"rapidity", 0.5, "Rapidity cut on lambda"}; + Configurable v0eta{"v0eta", 0.8, "Eta cut on lambda"}; + + // Event Mixing + Configurable cosDef{"cosDef", 1, "Defination of cos"}; + Configurable nEvtMixing{"nEvtMixing", 10, "Number of events to mix"}; + ConfigurableAxis CfgVtxBins{"CfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; + ConfigurableAxis CfgMultBins{"CfgMultBins", {8, 0.0, 80}, "Mixing bins - centrality"}; + Configurable etaMix{"etaMix", 0.1, "Eta cut on event mixing"}; + Configurable ptMix{"ptMix", 0.1, "Pt cut on event mixing"}; + Configurable phiMix{"phiMix", 0.1, "Phi cut on event mixing"}; + Configurable massMix{"massMix", 0.0028, "Masscut on event mixing"}; + + ConfigurableAxis ax_dphi_h{"ax_dphi_h", {72, 0.0, 2.0 * TMath::Pi()}, "Δφ_h"}; + ConfigurableAxis ax_deta{"ax_deta", {40, -1.0, 1.0}, "Δη"}; + ConfigurableAxis ax_ptpair{"ax_ptpair", {100, 0.0, 10.0}, "p_{T,pair} (GeV/c)"}; + + // THnsparse bining + ConfigurableAxis configThnAxisInvMass{"configThnAxisInvMass", {50, 1.09, 1.14}, "#it{M} (GeV/#it{c}^{2})"}; + ConfigurableAxis configThnAxisR{"configThnAxisR", {80, 0.0, 8.0}, "#it{R}"}; + ConfigurableAxis configThnAxisPol{"configThnAxisPol", {80, 0.0, 8.0}, "cos#it{#theta *}"}; + ConfigurableAxis configThnAxisCentrality{"configThnAxisCentrality", {8, 0.0, 80.0}, "Centrality"}; + ConfigurableAxis configThnAxisRapidity{"configThnAxisRapidity", {5, 0.0, 1.0}, "Rapidity"}; + ConfigurableAxis configThnAxisPairMass{"configThnAxisPairMass", {100, 2.0, 3.0}, "PairMass"}; + ConfigurableAxis configThnAxisPhi{"configThnAxisPhi", {18, 0.0, 2.0 * TMath::Pi()}, "Phi"}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + histos.add("hPtYSame", "hPtYSame", kTH2F, {{100, 0.0, 10.0}, {200, -1.0, 1.0}}); + histos.add("hPtYMix", "hPtYMix", kTH2F, {{100, 0.0, 10.0}, {200, -1.0, 1.0}}); + histos.add("hCentrality", "Centrality distribution", kTH1F, {{configThnAxisCentrality}}); + histos.add("deltaPhiSame", "deltaPhiSame", HistType::kTH1D, {{72, 0.0, 2.0 * TMath::Pi()}}, true); + histos.add("deltaPhiMix", "deltaPhiMix", HistType::kTH1D, {{72, 0.0, 2.0 * TMath::Pi()}}, true); + histos.add("ptCent", "ptCent", HistType::kTH2D, {{100, 0.0, 10.0}, {8, 0.0, 80.0}}, true); + histos.add("etaCent", "etaCent", HistType::kTH2D, {{32, -0.8, 0.8}, {8, 0.0, 80.0}}, true); + + // --- 3D SE/ME pair-space maps per category (LL, LAL, ALL, ALAL) + histos.add("SE_LL", "SE pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("SE_LAL", "SE pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("SE_ALL", "SE pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("SE_ALAL", "SE pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + + histos.add("ME_LL", "ME pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("ME_LAL", "ME pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("ME_ALL", "ME pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("ME_ALAL", "ME pairs", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + + histos.add("SE_LL2", "SE pairs 2", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("SE_LAL2", "SE pairs 2", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("SE_ALL2", "SE pairs 2", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("SE_ALAL2", "SE pairs 2", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + + histos.add("ME_LL2", "ME pairs 2", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("ME_LAL2", "ME pairs 2", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("ME_ALL2", "ME pairs 2", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + histos.add("ME_ALAL2", "ME pairs 2", HistType::kTH3D, {ax_dphi_h, ax_deta, ax_ptpair}, true); + + histos.add("hSparseLambdaLambda", "hSparseLambdaLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + histos.add("hSparseLambdaAntiLambda", "hSparseLambdaAntiLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + histos.add("hSparseAntiLambdaLambda", "hSparseAntiLambdLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + histos.add("hSparseAntiLambdaAntiLambda", "hSparseAntiLambdaAntiLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + + histos.add("hSparseLambdaLambdaMixed", "hSparseLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + histos.add("hSparseLambdaAntiLambdaMixed", "hSparseLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + histos.add("hSparseAntiLambdaLambdaMixed", "hSparseAntiLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + histos.add("hSparseAntiLambdaAntiLambdaMixed", "hSparseAntiLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + if (useAdditionalHisto) { + histos.add("hSparseRapLambdaLambda", "hSparseRapLambdaLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisRapidity}, true); + histos.add("hSparseRapLambdaAntiLambda", "hSparseRapLambdaAntiLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisRapidity}, true); + histos.add("hSparseRapAntiLambdaLambda", "hSparseRapAntiLambdLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisRapidity}, true); + histos.add("hSparseRapAntiLambdaAntiLambda", "hSparseRapAntiLambdaAntiLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisRapidity}, true); + + histos.add("hSparseRapLambdaLambdaMixed", "hSparseRapLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisRapidity}, true); + histos.add("hSparseRapLambdaAntiLambdaMixed", "hSparseRapLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisRapidity}, true); + histos.add("hSparseRapAntiLambdaLambdaMixed", "hSparseRapAntiLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisRapidity}, true); + histos.add("hSparseRapAntiLambdaAntiLambdaMixed", "hSparseRapAntiLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisRapidity}, true); + + histos.add("hSparsePhiLambdaLambda", "hSparsePhiLambdaLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, ax_dphi_h}, true); + histos.add("hSparsePhiLambdaAntiLambda", "hSparsePhiLambdaAntiLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, ax_dphi_h}, true); + histos.add("hSparsePhiAntiLambdaLambda", "hSparsePhiAntiLambdLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, ax_dphi_h}, true); + histos.add("hSparsePhiAntiLambdaAntiLambda", "hSparsePhiAntiLambdaAntiLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, ax_dphi_h}, true); + + histos.add("hSparsePhiLambdaLambdaMixed", "hSparsePhiLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, ax_dphi_h}, true); + histos.add("hSparsePhiLambdaAntiLambdaMixed", "hSparsePhiLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, ax_dphi_h}, true); + histos.add("hSparsePhiAntiLambdaLambdaMixed", "hSparsePhiAntiLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, ax_dphi_h}, true); + histos.add("hSparsePhiAntiLambdaAntiLambdaMixed", "hSparsePhiAntiLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, ax_dphi_h}, true); + + histos.add("hSparsePairMassLambdaLambda", "hSparsePairMassLambdaLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); + histos.add("hSparsePairMassLambdaAntiLambda", "hSparsePairMassLambdaAntiLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); + histos.add("hSparsePairMassAntiLambdaLambda", "hSparsePairMassAntiLambdLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); + histos.add("hSparsePairMassAntiLambdaAntiLambda", "hSparsePairMassAntiLambdaAntiLambda", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); + + histos.add("hSparsePairMassLambdaLambdaMixed", "hSparsePairMassLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); + histos.add("hSparsePairMassLambdaAntiLambdaMixed", "hSparsePairMassLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); + histos.add("hSparsePairMassAntiLambdaLambdaMixed", "hSparsePairMassAntiLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); + histos.add("hSparsePairMassAntiLambdaAntiLambdaMixed", "hSparsePairMassAntiLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisPairMass}, true); + } + rng.seed(static_cast(rngSeed.value)); + 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()); + LOGF(info, "Getting alignment offsets from the CCDB..."); + if (useweight) { + hweight1 = ccdb->getForTimeStamp(ConfWeightPathLL.value, cfgCcdbParam.nolaterthan.value); + hweight2 = ccdb->getForTimeStamp(ConfWeightPathLAL.value, cfgCcdbParam.nolaterthan.value); + hweight3 = ccdb->getForTimeStamp(ConfWeightPathALL.value, cfgCcdbParam.nolaterthan.value); + hweight4 = ccdb->getForTimeStamp(ConfWeightPathALAL.value, cfgCcdbParam.nolaterthan.value); + + hweight12 = ccdb->getForTimeStamp(ConfWeightPathLL2.value, cfgCcdbParam.nolaterthan.value); + hweight22 = ccdb->getForTimeStamp(ConfWeightPathLAL2.value, cfgCcdbParam.nolaterthan.value); + hweight32 = ccdb->getForTimeStamp(ConfWeightPathALL2.value, cfgCcdbParam.nolaterthan.value); + hweight42 = ccdb->getForTimeStamp(ConfWeightPathALAL2.value, cfgCcdbParam.nolaterthan.value); + } + } + + template + bool selectionV0(T const& candidate) + { + auto particle = ROOT::Math::PtEtaPhiMVector(candidate.lambdaPt(), candidate.lambdaEta(), candidate.lambdaPhi(), candidate.lambdaMass()); + if (std::abs(particle.Rapidity()) > rapidity || std::abs(particle.Eta()) > v0eta) { + return false; + } + if (candidate.lambdaMass() < MassMin || candidate.lambdaMass() > MassMax) { + return false; + } + if (candidate.v0Cospa() < cosPA) { + return false; + } + if (checkDoubleStatus && candidate.doubleStatus()) { + return false; + } + if (candidate.v0Radius() > radiusMax) { + return false; + } + if (candidate.v0Radius() < radiusMin) { + return false; + } + if (candidate.dcaBetweenDaughter() > dcaDaughters) { + return false; + } + if (candidate.v0Status() == 0 && (std::abs(candidate.dcaPositive()) < dcaProton || std::abs(candidate.dcaNegative()) < dcaPion)) { + return false; + } + if (candidate.v0Status() == 1 && (std::abs(candidate.dcaPositive()) < dcaPion || std::abs(candidate.dcaNegative()) < dcaProton)) { + return false; + } + if (candidate.lambdaPt() < ptMin) { + return false; + } + if (candidate.lambdaPt() > ptMax) { + return false; + } + return true; + } + + template + bool checkKinematics(T1 const& candidate1, T2 const& candidate2) + { + if (candidate1.v0Status() != candidate2.v0Status()) { + return false; + } + if (std::abs(candidate1.lambdaPt() - candidate2.lambdaPt()) > ptMix) { + return false; + } + if (std::abs(candidate1.lambdaEta() - candidate2.lambdaEta()) > etaMix) { + return false; + } + if (std::abs(RecoDecay::constrainAngle(candidate1.lambdaPhi(), 0.0F, harmonic) - RecoDecay::constrainAngle(candidate2.lambdaPhi(), 0.0F, harmonic)) > phiMix) { + return false; + } + if (std::abs(candidate1.lambdaMass() - candidate2.lambdaMass()) > massMix) { + return false; + } + return true; + } + + void fillHistograms(int tag1, int tag2, + const ROOT::Math::PtEtaPhiMVector& particle1, const ROOT::Math::PtEtaPhiMVector& particle2, + const ROOT::Math::PtEtaPhiMVector& daughpart1, const ROOT::Math::PtEtaPhiMVector& daughpart2, + int datatype, float mixpairweight) + { + + auto lambda1Mass = 0.0; + auto lambda2Mass = 0.0; + if (!usePDGM) { + lambda1Mass = particle1.M(); + lambda2Mass = particle2.M(); + } else { + lambda1Mass = o2::constants::physics::MassLambda; + lambda2Mass = o2::constants::physics::MassLambda; + } + auto particle1Dummy = ROOT::Math::PtEtaPhiMVector(particle1.Pt(), particle1.Eta(), particle1.Phi(), lambda1Mass); + auto particle2Dummy = ROOT::Math::PtEtaPhiMVector(particle2.Pt(), particle2.Eta(), particle2.Phi(), lambda2Mass); + auto pairDummy = particle1Dummy + particle2Dummy; + ROOT::Math::Boost boostPairToCM{pairDummy.BoostToCM()}; // boosting vector for pair CM + + // Step1: Boosting both Lambdas to Lambda-Lambda pair rest frame + auto lambda1CM = boostPairToCM(particle1Dummy); + auto lambda2CM = boostPairToCM(particle2Dummy); + + // 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); + + // --- STAR-style Δθ (as written: dot product of proton directions in their own Λ RFs) --- + + // Boost each proton into its parent's rest frame + ROOT::Math::Boost boostL1_LabToRF{particle1Dummy.BoostToCM()}; // Λ1 velocity in lab + ROOT::Math::Boost boostL2_LabToRF{particle2Dummy.BoostToCM()}; // Λ2 velocity in lab + + auto p1_LRF = boostL1_LabToRF(daughpart1); + auto p2_LRF = boostL2_LabToRF(daughpart2); + + // Unit 3-vectors (in different rest frames!) + TVector3 u1 = TVector3(p1_LRF.Px(), p1_LRF.Py(), p1_LRF.Pz()).Unit(); + TVector3 u2 = TVector3(p2_LRF.Px(), p2_LRF.Py(), p2_LRF.Pz()).Unit(); + + // Proton unit directions in Λ rest frames + TVector3 k1(proton1LambdaRF.Px(), proton1LambdaRF.Py(), proton1LambdaRF.Pz()); + k1 = k1.Unit(); + TVector3 k2(proton2LambdaRF.Px(), proton2LambdaRF.Py(), proton2LambdaRF.Pz()); + k2 = k2.Unit(); + + // STAR-style cosΔθ definition + double cosDeltaTheta_STAR_naive = u1.Dot(u2); + if (cosDeltaTheta_STAR_naive > 1.0) + cosDeltaTheta_STAR_naive = 111.0; + if (cosDeltaTheta_STAR_naive < -1.0) + cosDeltaTheta_STAR_naive = -111.0; + + double cosDeltaTheta_hel = k1.Dot(k2); + if (cosDeltaTheta_hel > 1.0) + cosDeltaTheta_hel = 111.0; + if (cosDeltaTheta_hel < -1.0) + cosDeltaTheta_hel = -111.0; + + auto cosThetaDiff = -999.0; + if (cosDef == 0) { + cosThetaDiff = cosDeltaTheta_STAR_naive; + } else { + cosThetaDiff = cosDeltaTheta_hel; + } + + double pt1 = particle1.Pt(); + double dphi1 = RecoDecay::constrainAngle(particle1.Phi(), 0.0F, harmonic); + double deta1 = particle1.Eta(); + + double pt2 = particle2.Pt(); + double dphi2 = RecoDecay::constrainAngle(particle2.Phi(), 0.0F, harmonic); + double deta2 = particle2.Eta(); + + double deta_pair = std::abs(deta1 - deta2); + double dphi_pair = RecoDecay::constrainAngle(particle1.Phi() - particle2.Phi(), 0.0F, harmonicDphi); + + double deltaR = TMath::Sqrt(deta_pair * deta_pair + dphi_pair * dphi_pair); + double deltaRap = std::abs(particle1.Rapidity() - particle2.Rapidity()); + + double epsWeight1 = 1.0; + double epsWeight2 = 1.0; + + if (useweight && datatype == 1) { + if (tag1 == 0 && tag2 == 0) { + epsWeight1 = hweight1->GetBinContent(hweight1->FindBin(dphi1, deta1, pt1)); + epsWeight2 = hweight12->GetBinContent(hweight12->FindBin(dphi2, deta2, pt2)); + } else if (tag1 == 0 && tag2 == 1) { + epsWeight1 = hweight2->GetBinContent(hweight2->FindBin(dphi1, deta1, pt1)); + epsWeight2 = hweight22->GetBinContent(hweight22->FindBin(dphi2, deta2, pt2)); + } else if (tag1 == 1 && tag2 == 0) { + epsWeight1 = hweight3->GetBinContent(hweight3->FindBin(dphi1, deta1, pt1)); + epsWeight2 = hweight32->GetBinContent(hweight32->FindBin(dphi2, deta2, pt2)); + } else if (tag1 == 1 && tag2 == 1) { + epsWeight1 = hweight4->GetBinContent(hweight4->FindBin(dphi1, deta1, pt1)); + epsWeight2 = hweight42->GetBinContent(hweight42->FindBin(dphi2, deta2, pt2)); + } + } + + if (datatype == 0) { + mixpairweight = 1.0; + histos.fill(HIST("hPtYSame"), particle1.Pt(), particle1.Rapidity(), mixpairweight); + if (tag1 == 0 && tag2 == 0) { + histos.fill(HIST("SE_LL"), dphi1, deta1, pt1, mixpairweight); + histos.fill(HIST("SE_LL2"), dphi2, deta2, pt2, mixpairweight); + histos.fill(HIST("hSparseLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, mixpairweight); + if (useAdditionalHisto) { + histos.fill(HIST("hSparseRapLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, mixpairweight); + histos.fill(HIST("hSparsePhiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, mixpairweight); + histos.fill(HIST("hSparsePairMassLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), mixpairweight); + } + } else if (tag1 == 0 && tag2 == 1) { + histos.fill(HIST("SE_LAL"), dphi1, deta1, pt1, mixpairweight); + histos.fill(HIST("SE_LAL2"), dphi2, deta2, pt2, mixpairweight); + histos.fill(HIST("hSparseLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, mixpairweight); + if (useAdditionalHisto) { + histos.fill(HIST("hSparseRapLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, mixpairweight); + histos.fill(HIST("hSparsePhiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, mixpairweight); + histos.fill(HIST("hSparsePairMassLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), mixpairweight); + } + } else if (tag1 == 1 && tag2 == 0) { + histos.fill(HIST("hSparseAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, mixpairweight); + histos.fill(HIST("SE_ALL"), dphi1, deta1, pt1, mixpairweight); + histos.fill(HIST("SE_ALL2"), dphi2, deta2, pt2, mixpairweight); + if (useAdditionalHisto) { + histos.fill(HIST("hSparseRapAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, mixpairweight); + histos.fill(HIST("hSparsePhiAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, mixpairweight); + histos.fill(HIST("hSparsePairMassAntiLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), mixpairweight); + } + } else if (tag1 == 1 && tag2 == 1) { + histos.fill(HIST("hSparseAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, mixpairweight); + histos.fill(HIST("SE_ALAL"), dphi1, deta1, pt1, mixpairweight); + histos.fill(HIST("SE_ALAL2"), dphi2, deta2, pt2, mixpairweight); + if (useAdditionalHisto) { + histos.fill(HIST("hSparseRapAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, mixpairweight); + histos.fill(HIST("hSparsePhiAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, mixpairweight); + histos.fill(HIST("hSparsePairMassAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), mixpairweight); + } + } + } else if (datatype == 1) { + double weight = mixpairweight; + if (useweight) { + if (usebothweight) { + weight = mixpairweight / (epsWeight1 * epsWeight2); + } else { + weight = mixpairweight / (epsWeight1); + } + } + if (weight <= 0.0) { + weight = 1.0; + } + histos.fill(HIST("hPtYMix"), particle1.Pt(), particle1.Rapidity(), weight); + if (tag1 == 0 && tag2 == 0) { + histos.fill(HIST("ME_LL"), dphi1, deta1, pt1, mixpairweight); + histos.fill(HIST("ME_LL2"), dphi2, deta2, pt2, mixpairweight); + histos.fill(HIST("hSparseLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); + if (useAdditionalHisto) { + histos.fill(HIST("hSparseRapLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); + histos.fill(HIST("hSparsePhiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); + histos.fill(HIST("hSparsePairMassLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); + } + } else if (tag1 == 0 && tag2 == 1) { + histos.fill(HIST("ME_LAL"), dphi1, deta1, pt1, mixpairweight); + histos.fill(HIST("ME_LAL2"), dphi2, deta2, pt2, mixpairweight); + histos.fill(HIST("hSparseLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); + if (useAdditionalHisto) { + histos.fill(HIST("hSparseRapLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); + histos.fill(HIST("hSparsePhiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); + histos.fill(HIST("hSparsePairMassLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); + } + } else if (tag1 == 1 && tag2 == 0) { + histos.fill(HIST("ME_ALL"), dphi1, deta1, pt1, mixpairweight); + histos.fill(HIST("ME_ALL2"), dphi2, deta2, pt2, mixpairweight); + histos.fill(HIST("hSparseAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); + if (useAdditionalHisto) { + histos.fill(HIST("hSparseRapAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); + histos.fill(HIST("hSparsePhiAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); + histos.fill(HIST("hSparsePairMassAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); + } + } else if (tag1 == 1 && tag2 == 1) { + histos.fill(HIST("ME_ALAL"), dphi1, deta1, pt1, mixpairweight); + histos.fill(HIST("ME_ALAL2"), dphi2, deta2, pt2, mixpairweight); + histos.fill(HIST("hSparseAntiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); + if (useAdditionalHisto) { + histos.fill(HIST("hSparseRapAntiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); + histos.fill(HIST("hSparsePhiAntiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, dphi_pair, weight); + histos.fill(HIST("hSparsePairMassAntiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); + } + } + } + } + + ROOT::Math::PtEtaPhiMVector lambda0, proton0; + ROOT::Math::PtEtaPhiMVector lambda, proton; + ROOT::Math::PtEtaPhiMVector lambda2, proton2; + + Filter centralityFilter = (nabs(aod::lambdaevent::cent) < centMax && nabs(aod::lambdaevent::cent) > centMin); + + using EventCandidates = soa::Filtered; + using AllTrackCandidates = aod::LambdaPairs; + + void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& V0s) + { + auto centrality = collision.cent(); + for (const auto& v0 : V0s) { + if (!selectionV0(v0)) { + continue; + } + histos.fill(HIST("ptCent"), v0.lambdaPt(), centrality); + histos.fill(HIST("etaCent"), v0.lambdaEta(), centrality); + proton = ROOT::Math::PtEtaPhiMVector(v0.protonPt(), v0.protonEta(), v0.protonPhi(), o2::constants::physics::MassProton); + lambda = ROOT::Math::PtEtaPhiMVector(v0.lambdaPt(), v0.lambdaEta(), v0.lambdaPhi(), v0.lambdaMass()); + + for (const auto& v02 : V0s) { + if (v02.index() <= v0.index()) { + continue; + } + if (!selectionV0(v02)) { + continue; + } + if (v0.protonIndex() == v02.protonIndex()) { + continue; + } + if (v0.pionIndex() == v02.pionIndex()) { + continue; + } + if (v0.protonIndex() == v02.pionIndex()) { + continue; + } + if (v0.pionIndex() == v02.protonIndex()) { + continue; + } + proton2 = ROOT::Math::PtEtaPhiMVector(v02.protonPt(), v02.protonEta(), v02.protonPhi(), o2::constants::physics::MassProton); + lambda2 = ROOT::Math::PtEtaPhiMVector(v02.lambdaPt(), v02.lambdaEta(), v02.lambdaPhi(), v02.lambdaMass()); + histos.fill(HIST("deltaPhiSame"), RecoDecay::constrainAngle(v0.lambdaPhi() - v02.lambdaPhi(), 0.0F, harmonicDphi)); + if (v0.v0Status() == 0 && v02.v0Status() == 0) { + fillHistograms(0, 0, lambda, lambda2, proton, proton2, 0, 1.0); + } + if (v0.v0Status() == 0 && v02.v0Status() == 1) { + fillHistograms(0, 1, lambda, lambda2, proton, proton2, 0, 1.0); + } + if (v0.v0Status() == 1 && v02.v0Status() == 0) { + fillHistograms(1, 0, lambda, lambda2, proton, proton2, 0, 1.0); + } + if (v0.v0Status() == 1 && v02.v0Status() == 1) { + fillHistograms(1, 1, lambda, lambda2, proton, proton2, 0, 1.0); + } + } + } + } + PROCESS_SWITCH(lambdaspincorrderived, processData, "Process data", true); + + // Processing Event Mixing + SliceCache cache; + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{CfgVtxBins, CfgMultBins}, true}; + Preslice tracksPerCollisionV0 = aod::lambdapair::lambdaeventId; + void processME(EventCandidates const& collisions, AllTrackCandidates const& V0s) + { + auto collOldIndex = -999; + std::vector t1Used; + for (auto& [collision1, collision2] : selfCombinations(colBinning, nEvtMixing, -1, collisions, collisions)) { + // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.index(), collision2.index()); + // auto centrality = collision1.cent(); + auto groupV01 = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + auto groupV02 = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + auto groupV03 = V0s.sliceBy(tracksPerCollisionV0, collision2.index()); + auto collNewIndex = collision1.index(); + // LOGF(info, "Mixed event collisions: (%d, %d)", collNewIndex, collOldIndex); + if (collOldIndex != collNewIndex) { + t1Used.resize(groupV01.size(), false); + // std::fill(t1Used.begin(), t1Used.end(), false); + // std::vector t1Used(groupV01.size(), false); // <-- reset here + collOldIndex = collNewIndex; + } + for (auto& [t1, t3] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV01, groupV03))) { + if (t1Used[t1.index()]) { + continue; + } + if (!checkKinematics(t1, t3)) { + continue; + } + if (!selectionV0(t1)) { + continue; + } + if (!selectionV0(t3)) { + continue; + } + t1Used[t1.index()] = true; + for (const auto& t2 : groupV02) { + if (t2.index() <= t1.index()) { + continue; + } + if (!selectionV0(t2)) { + continue; + } + if (t1.protonIndex() == t2.protonIndex()) { + continue; + } + if (t1.pionIndex() == t2.pionIndex()) { + continue; + } + proton = ROOT::Math::PtEtaPhiMVector(t3.protonPt(), t3.protonEta(), t3.protonPhi(), o2::constants::physics::MassProton); + lambda = ROOT::Math::PtEtaPhiMVector(t3.lambdaPt(), t3.lambdaEta(), t3.lambdaPhi(), t3.lambdaMass()); + proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); + lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); + histos.fill(HIST("deltaPhiMix"), RecoDecay::constrainAngle(t3.lambdaPhi() - t2.lambdaPhi(), 0.0F, harmonicDphi)); + if (t3.v0Status() == 0 && t2.v0Status() == 0) { + fillHistograms(0, 0, lambda, lambda2, proton, proton2, 1, 1.0); + } + if (t3.v0Status() == 0 && t2.v0Status() == 1) { + fillHistograms(0, 1, lambda, lambda2, proton, proton2, 1, 1.0); + } + if (t3.v0Status() == 1 && t2.v0Status() == 0) { + fillHistograms(1, 0, lambda, lambda2, proton, proton2, 1, 1.0); + } + if (t3.v0Status() == 1 && t2.v0Status() == 1) { + fillHistograms(1, 1, lambda, lambda2, proton, proton2, 1, 1.0); + } + } + } // replacement track pair + } // collision pair + } + PROCESS_SWITCH(lambdaspincorrderived, processME, "Process data ME", false); + + void processMEV2(EventCandidates const& collisions, AllTrackCandidates const& V0s) + { + auto nBins = colBinning.getAllBinsCount(); + std::vector>> eventPools(nBins); + + for (auto& collision1 : collisions) { + int bin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); + auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + // float centrality = collision1.cent(); + + // <<< CHANGED: map old collision index → set of (t2.idx, t3.idx) we've already filled + std::unordered_map>> seenMap; + + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + if (!selectionV0(t1) || !selectionV0(t2)) + continue; + if (t2.index() <= t1.index()) + continue; + if (t1.protonIndex() == t2.protonIndex()) + continue; + if (t1.pionIndex() == t2.pionIndex()) + continue; + + int mixes = 0; + for (auto it = eventPools[bin].rbegin(); it != eventPools[bin].rend() && mixes < nEvtMixing; ++it, ++mixes) { + int collision2idx = it->first; + AllTrackCandidates& poolB = it->second; + + int nRepl = 0; + for (auto& t3 : poolB) { + if (selectionV0(t3) && checkKinematics(t1, t3)) { + ++nRepl; + } + } + if (nRepl == 0) + continue; + float invN = 1.0f / static_cast(nRepl); + + for (auto& t3 : poolB) { + if (!(selectionV0(t3) && checkKinematics(t1, t3))) { + continue; + } + if (collision1.index() == collision2idx) { + continue; + } + + // <<< CHANGED: dedupe (t2, t3) pairs per prior collision + auto key = std::make_pair(t2.index(), t3.index()); + auto& seen = seenMap[collision2idx]; + if (!seen.insert(key).second) { + continue; + } + + // reconstruct 4-vectors + proton = ROOT::Math::PtEtaPhiMVector(t3.protonPt(), t3.protonEta(), t3.protonPhi(), o2::constants::physics::MassProton); + lambda = ROOT::Math::PtEtaPhiMVector(t3.lambdaPt(), t3.lambdaEta(), t3.lambdaPhi(), t3.lambdaMass()); + proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); + lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); + + float dPhi = std::fabs(RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic)); + histos.fill(HIST("deltaPhiMix"), dPhi, invN); + + if (t3.v0Status() == 0 && t2.v0Status() == 0) { + fillHistograms(0, 0, lambda, lambda2, proton, proton2, 1, invN); + } + if (t3.v0Status() == 0 && t2.v0Status() == 1) { + fillHistograms(0, 1, lambda, lambda2, proton, proton2, 1, invN); + } + if (t3.v0Status() == 1 && t2.v0Status() == 0) { + fillHistograms(1, 0, lambda, lambda2, proton, proton2, 1, invN); + } + if (t3.v0Status() == 1 && t2.v0Status() == 1) { + fillHistograms(1, 1, lambda, lambda2, proton, proton2, 1, invN); + } + } + } // end mixing-event loop + } // end same-event pair loop + + auto sliced = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); + if (static_cast(eventPools[bin].size()) > nEvtMixing) { + eventPools[bin].pop_front(); + } + } // end primary-event loop + } + PROCESS_SWITCH(lambdaspincorrderived, processMEV2, "Process data ME", false); + + void processMEV3(EventCandidates const& collisions, AllTrackCandidates const& V0s) + { + auto nBins = colBinning.getAllBinsCount(); + std::vector>> eventPools(nBins); + + for (auto& collision1 : collisions) { + const int bin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); + + // if pool empty, push and continue + if (eventPools[bin].empty()) { + auto sliced = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); + if ((int)eventPools[bin].size() > nEvtMixing) + eventPools[bin].pop_front(); + continue; + } + + // current event slice + auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + + // loop over SE unordered pairs (t1,t2) + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + if (!selectionV0(t1) || !selectionV0(t2)) + continue; + if (t2.index() <= t1.index()) + continue; + if (t1.protonIndex() == t2.protonIndex()) + continue; + if (t1.pionIndex() == t2.pionIndex()) + continue; + if (t1.protonIndex() == t2.pionIndex()) + continue; + if (t1.pionIndex() == t2.protonIndex()) + continue; + + // scan prior events for replacements for t1 + struct PV { + AllTrackCandidates* pool; + int nRepl; + }; + std::vector usable; + int totalRepl = 0; + + int mixes = 0; + for (auto it = eventPools[bin].rbegin(); + it != eventPools[bin].rend() && mixes < nEvtMixing; ++it, ++mixes) { + const int collision2idx = it->first; + auto& poolB = it->second; + if (collision2idx == collision1.index()) + continue; + + int nRepl = 0; + for (auto& tX : poolB) { + if (!selectionV0(tX)) + continue; + if (checkKinematics(t1, tX)) + ++nRepl; + } + if (nRepl > 0) { + usable.push_back(PV{&poolB, nRepl}); + totalRepl += nRepl; + } + } + + if (totalRepl == 0) + continue; + const float wBase = 1.0f / static_cast(totalRepl); + + // emit mixed pairs: tX replaces t1; t2 stays + for (auto& pv : usable) { + auto& poolB = *pv.pool; + for (auto& tX : poolB) { + if (!selectionV0(tX)) + continue; + if (!checkKinematics(t1, tX)) + continue; + + auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); + + const float dPhi = std::fabs(RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic)); + histos.fill(HIST("deltaPhiMix"), dPhi, wBase); + fillHistograms(tX.v0Status(), t2.v0Status(), lambda, lambda2, proton, proton2, 1, wBase); + } + } + } + // push current event into pool + auto sliced = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); + if ((int)eventPools[bin].size() > nEvtMixing) + eventPools[bin].pop_front(); + } + } + PROCESS_SWITCH(lambdaspincorrderived, processMEV3, "Process data ME (first-leg, pair-3D maps)", false); + + static constexpr int N_STATUS = 2; // v0Status ∈ {0,1} + + struct MixBinner { + // constructed from the task's configurables; φ is assumed already constrained into [0, 2π) + float ptMin, ptMax, ptStep; + float etaMin, etaMax, etaStep; + float phiMin, phiMax, phiStep; + + // Mass binning: [1.09, 1.14) with 50 bins (1e-3 GeV/c^2) + static constexpr float mMin = 1.09f; + static constexpr float mMax = 1.14f; // exclusive + static constexpr int nM_ = 1; + static constexpr float mStep = (mMax - mMin) / nM_; + + int nPt_, nEta_, nPhi_; + + MixBinner(float ptMin_, float ptMax_, float ptStep_, + float etaAbsMax, float etaStep_, + float phiStep_) + : ptMin(ptMin_), ptMax(ptMax_), ptStep(ptStep_), etaMin(-etaAbsMax), etaMax(+etaAbsMax), etaStep(etaStep_), phiMin(0.f), phiMax(static_cast(2.0 * TMath::Pi())), phiStep(phiStep_) + { + ptStep = (ptStep > 0.f ? ptStep : 0.1f); + etaStep = (etaStep > 0.f ? etaStep : 0.1f); + phiStep = (phiStep > 0.f ? phiStep : 0.1f); + + nPt_ = std::max(1, static_cast(std::floor((ptMax - ptMin) / ptStep + 0.5f))); + nEta_ = std::max(1, static_cast(std::floor((etaMax - etaMin) / etaStep + 0.5f))); + nPhi_ = std::max(1, static_cast(std::ceil((phiMax - phiMin) / phiStep))); + } + + inline int nPt() const { return nPt_; } + inline int nEta() const { return nEta_; } + inline int nPhi() const { return nPhi_; } + inline int nM() const { return nM_; } + + inline int binFromValue(float v, float vmin, float step, int nBins) const + { + if (!std::isfinite(v)) + return -1; + const float x = (v - vmin) / step; + int b = static_cast(std::floor(x + 1e-6f)); + if (b < 0) + return -1; + if (b >= nBins) + b = nBins - 1; // clamp exact-top edge + return b; + } + + inline int ptBin(float pt) const { return binFromValue(pt, ptMin, ptStep, nPt_); } + inline int etaBin(float eta) const { return binFromValue(eta, etaMin, etaStep, nEta_); } + inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } // φ already constrained upstream + inline int massBin(float m) const { return binFromValue(m, mMin, mStep, nM_); } + }; + + struct BufferCand { + int64_t collisionIdx; // from col.index() + int64_t rowIndex; // global row id in V0s + uint8_t v0Status; + uint16_t ptBin, etaBin, phiBin, mBin; + }; + + struct MatchRef { + int64_t collisionIdx; + int64_t rowIndex; + }; + + // 6D key: (colBin, status, pt, eta, phi, mass) + static inline size_t linearKey(int colBin, int statBin, + int ptBin, int etaBin, int phiBin, int mBin, + int nStatus, int nPt, int nEta, int nPhi, int nM) + { + return ((((((static_cast(colBin) * nStatus + statBin) * nPt + ptBin) * nEta + etaBin) * nPhi + phiBin) * nM + mBin)); + } + + // ===================== Main mixing (with mass-bin + random unique sampling) ===================== + void processMEV4(EventCandidates const& collisions, AllTrackCandidates const& V0s) + { + // Build binner from your existing configurables + MixBinner mb{ + ptMin.value, ptMax.value, ptMix.value, // pT range & step + v0eta.value, etaMix.value, // |eta| max & step + phiMix.value // φ step; φ range fixed to [0, 2π) + }; + + const int nCol = colBinning.getAllBinsCount(); // event-class bins (vz, centrality) + const int nStat = N_STATUS; // 2 + const int nPt = mb.nPt(); + const int nEta = mb.nEta(); + const int nPhi = mb.nPhi(); + const int nM = mb.nM(); + + const size_t nKeys = static_cast(nCol) * nStat * nPt * nEta * nPhi * nM; + std::vector> buffer(nKeys); + + // ---- PASS 1: fill 6D buffer ---- + for (auto const& col : collisions) { + const int colBin = colBinning.getBin(std::make_tuple(col.posz(), col.cent())); + auto slice = V0s.sliceBy(tracksPerCollisionV0, col.index()); + + for (auto const& t : slice) { + if (!selectionV0(t)) + continue; + + const int status = static_cast(t.v0Status()); + if (status < 0 || status >= nStat) + continue; + + // Bin kinematics (φ already constrained via your call-site) + const int ptB = mb.ptBin(t.lambdaPt()); + const int etaB = mb.etaBin(t.lambdaEta()); + const int phiB = mb.phiBin(RecoDecay::constrainAngle(t.lambdaPhi(), 0.0F, harmonic)); + const int mB = mb.massBin(t.lambdaMass()); + if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0) + continue; + + const size_t key = linearKey(colBin, status, ptB, etaB, phiB, mB, + nStat, nPt, nEta, nPhi, nM); + + buffer[key].push_back(BufferCand{ + .collisionIdx = static_cast(col.index()), + .rowIndex = static_cast(t.globalIndex()), // adapt accessor if needed + .v0Status = static_cast(status), + .ptBin = static_cast(ptB), + .etaBin = static_cast(etaB), + .phiBin = static_cast(phiB), + .mBin = static_cast(mB)}); + } + } + + // ---- PASS 2: mixing over same-event pairs ---- + for (auto const& collision1 : collisions) { + const int colBin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); + auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + + for (auto const& [t1, t2] : + soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + + if (!selectionV0(t1) || !selectionV0(t2)) + continue; + if (t2.index() <= t1.index()) + continue; + + // no shared daughters + if (t1.protonIndex() == t2.protonIndex()) + continue; + if (t1.pionIndex() == t2.pionIndex()) + continue; + if (t1.protonIndex() == t2.pionIndex()) + continue; + if (t1.pionIndex() == t2.protonIndex()) + continue; + + const int status = static_cast(t1.v0Status()); + if (status < 0 || status >= nStat) + continue; + + // Bin of t1 defines where to search (exact 6D bin) + const int ptB = mb.ptBin(t1.lambdaPt()); + const int etaB = mb.etaBin(t1.lambdaEta()); + const int phiB = mb.phiBin(RecoDecay::constrainAngle(t1.lambdaPhi(), 0.0F, harmonic)); // φ already constrained upstream + const int mB = mb.massBin(t1.lambdaMass()); + if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0) + continue; + + const size_t key = linearKey(colBin, status, ptB, etaB, phiB, mB, + nStat, nPt, nEta, nPhi, nM); + auto const& binVec = buffer[key]; + if (binVec.empty()) + continue; + + // Collect all partners from this 6D bin but different collision + std::vector matches; + matches.reserve(binVec.size()); + const int64_t curColIdx = static_cast(collision1.index()); + + for (const auto& bc : binVec) { + if (bc.collisionIdx == curColIdx) + continue; // ensure different event + matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); + } + if (matches.empty()) + continue; + + // ---------- YOUR PREFERRED RANDOM UNIQUE SAMPLING BLOCK ---------- + const int cap = nEvtMixing.value; + const int n = static_cast(matches.size()); + if (cap > 0 && cap < n) { + std::uniform_int_distribution dist(0, n - 1); + // pick cap unique indices + std::unordered_set chosen; + chosen.reserve(cap * 2); + while ((int)chosen.size() < cap) { + chosen.insert(dist(rng)); + } + std::vector subset; + subset.reserve(cap); + for (int idx : chosen) + subset.push_back(matches[idx]); + matches.swap(subset); + } else { + std::shuffle(matches.begin(), matches.end(), rng); + } + // ---------------------------------------------------------------- + + const float wBase = 1.0f / static_cast(matches.size()); + + // Emit mixed pairs: tX replaces t1; keep t2 + for (const auto& m : matches) { + auto tX = V0s.iteratorAt(m.rowIndex); // replace accessor if different + if (!selectionV0(tX)) + continue; // optional extra guard + if (!checkKinematics(t1, tX)) + continue; + + auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); + + const float dPhi = std::fabs(RecoDecay::constrainAngle(lambda.Phi() - lambda2.Phi(), 0.0F, harmonicDphi)); + histos.fill(HIST("deltaPhiMix"), dPhi, wBase); + fillHistograms(tX.v0Status(), t2.v0Status(), lambda, lambda2, proton, proton2, 1, wBase); + } + } + } + } + PROCESS_SWITCH(lambdaspincorrderived, processMEV4, "Process data ME (5d buffer)", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx index e22e76234ba..47417fa070f 100644 --- a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx +++ b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx @@ -9,42 +9,74 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "CCDB/BasicCCDBManager.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DCAFitter/DCAFitterN.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 "DetectorsVertexing/PVertexer.h" #include "Framework/ASoA.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Vertex.h" + +#include "Math/Vector4D.h" +#include "TDatabasePDG.h" +#include "TParticlePDG.h" + +#include +#include +#include +#include // #include "PWGHF/Core/PDG.h" +#include "PWGLF/DataModel/LFNonPromptCascadeTables.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 NPCascCandidate { + int runNumber; + int64_t mcParticleId; int64_t trackGlobID; int64_t trackITSID; + int64_t collisionID; float matchingChi2; + float deltaPtITS; + float deltaPt; float itsClusSize; + bool hasReassociatedCluster; + bool hasFakeReassociation; bool isGoodMatch; bool isGoodCascade; - int pdgCodePrimary; + int pdgCodeMom; + int pdgCodeITStrack; + bool isFromBeauty; + bool isFromCharm; + uint16_t pvContributors; + uint8_t cascPVContribs; + float pvTimeResolution; float pvX; float pvY; float pvZ; @@ -77,42 +109,52 @@ 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 multFV0A; + float multFT0M; + float centFT0C; + float centFV0A; + float centFT0M; + int multNTracksGlobal; + uint32_t toiMask; + bool noSameBunchPileup; }; - -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"}; @@ -124,17 +166,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 @@ -142,76 +176,72 @@ 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 CollisionsCandidatesRun3 = soa::Join; + using CollisionCandidatesRun3 = soa::Join; + using CollisionCandidatesRun3MC = soa::Join; + using CollisionsWithLabel = soa::Join; + + Preslice perCollision = aod::track::collisionId; + Preslice perCollisionMC = aod::track::collisionId; + + HistogramRegistry mRegistry; 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 cfgRedoPV{"cfgRedoPV", true, "redo PV"}; + 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; + Configurable cfgTriggersOfInterest{"cfgTriggersOfInterest", "fTrackedOmega,fOmegaHighMult,fHighFt0Mult", "Triggers of interest, comma separated for Zorro"}; + + Configurable cfgMaxMult{"cfgMaxMult", 8000.f, "Upper range of multiplicty histo"}; + Configurable cfgMaxMultFV0{"cfgMaxMultFV0", 10000.f, "Upper range of multiplicty FV0 histo"}; + Configurable cfgMinMult{"cfgMinMult", 3000.f, "Lower range of FT0M histo in zoomed histo"}; + Configurable cfgMaxCent{"cfgMaxCent", 8.0025f, "Upper range of FT0M histo"}; + + Zorro mZorro; + OutputObj mZorroSummary{"ZorroSummary"}; + SliceCache cache; + + Service mCCDB; int mRunNumber = 0; - float bz = 0.f; - - HistogramRegistry registry{ - "registry", - { - {"h_PV_x", "Primary vertex x;x (cm)", {HistType::kTH1D, {{100, -1., 1.}}}}, - {"h_PV_y", "Primary vertex y;y (cm)", {HistType::kTH1D, {{100, -1., 1.}}}}, - {"h_PV_z", "Primary vertex z;z (cm)", {HistType::kTH1D, {{100, -1., 1.}}}}, - - {"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; + std::array mProcessCounter = {0, 0}; // {Tracked, All} + std::map mToiMap; + std::unordered_map> mHistsPerRunMultVsCent; + std::unordered_map> mHistsPerRunMultVsCentZoom; + std::unordered_map> mHistsPerRunNtracktVsCent; + std::unordered_map> mHistsPerRunNtracktVsCentZoom; + + int nBinsMult = cfgMaxMult; + int nBinsMultFV0 = cfgMaxMultFV0; + int nBinsMultZoom = cfgMaxMult - cfgMinMult; + int nBinsCentZoom = (cfgMaxCent + 0.0025) / 0.005; + + AxisSpec multAxis = {nBinsMult, 0, cfgMaxMult, "Multiplicity FT0M"}; + AxisSpec multAxisFV0 = {nBinsMultFV0, 0, cfgMaxMultFV0, "Multiplicity FT0M"}; + AxisSpec centAxis = {101, -0.025, 101.025, "Centrality"}; + AxisSpec centAxisZoom = {nBinsCentZoom, -0.0025, cfgMaxCent, "Centrality"}; + AxisSpec multAxisZoom = {nBinsMultZoom, cfgMinMult, cfgMaxMult, "Multiplicity FT0M"}; + AxisSpec nTracksAxis = {100, 0., 100., "NTracksGlobal"}; + AxisSpec nTracksAxisMC = {100, 0., 100., "NTracksMC"}; void initCCDB(aod::BCsWithTimestamps::iterator const& bc) { @@ -219,475 +249,254 @@ struct NonPromptCascadeTask { 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)) { + if (o2::parameters::GRPMagField* grpmag = mCCDB->getForRun(cfgGRPmagPath, mRunNumber)) { 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; + mBz = static_cast(grpmag->getNominalL3Field()); + } + mDCAFitter.setBz(mBz); + + if (static_cast(cfgMaterialCorrection.value) == o2::base::Propagator::MatCorrType::USEMatCorrLUT) { + auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(mCCDB->getForRun("GLO/Param/MatLUT", mRunNumber)); + o2::base::Propagator::Instance()->setMatLUT(lut); } } void init(InitContext const&) { - ccdb->setURL(ccdbUrl); - ccdb->setFatalWhenNull(false); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - - if (static_cast(cfgMaterialCorrection.value) == o2::base::Propagator::MatCorrType::USEMatCorrLUT) { - auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get("GLO/Param/MatLUT")); - o2::base::Propagator::Instance(true)->setMatLUT(lut); - } + 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})"}}); + // AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + + 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}}))}; + mRegistry.add("hMultVsCent", "hMultVsCent", HistType::kTH2F, {centAxis, multAxis}); + mRegistry.add("hMultVsCentZoom", "hMultVsCentZoom", HistType::kTH2F, {centAxisZoom, multAxisZoom}); + mRegistry.add("hNTracksVsCent", "hNTracksVsCent", HistType::kTH2F, {centAxis, nTracksAxis}); + mRegistry.add("hNTracksVsCentZoom", "hNTracksVsCentZoom", HistType::kTH2F, {centAxisZoom, nTracksAxis}); + mRegistry.add("hMultFV0VshNTracks", "hMultFV0VshNTracks", HistType::kTH2F, {nTracksAxis, multAxisFV0}); + mRegistry.add("hNTracksVsCentFV0A", "hNTracksVsCentFV0A", HistType::kTH2F, {nTracksAxis, centAxis}); + mRegistry.add("hNTracksMCVsTracksReco", "hNTracksMCVsTracksReco", HistType::kTH2F, {nTracksAxisMC, nTracksAxis}); + mRegistry.add("hNTracksMCNotInReco", "hNTracksMCNotInReco", HistType::kTH1F, {nTracksAxisMC}); + 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()); + } } - template - void fillCascadeDCA(T const track, PR const& protonTrack, PI const& pionTrack, o2::dataformats::VertexBase primaryVertex, bool isOmega, motherDCA& mDCA) + template + bool recalculatePV(CollisionType const& collision, TrackType const& tracks, int idToRemove, o2::dataformats::VertexBase& primaryVertex) { - 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())); + // slice tracks by collision + o2::vertexing::PVertexer vertexer; + std::vector pvContributors = {}; + std::vector pvContributorsMask = {}; + + auto tracksInCollision = doprocessTrackedCascadesMC ? tracks.sliceBy(perCollisionMC, collision.globalIndex()) : tracks.sliceBy(perCollision, collision.globalIndex()); + // loop over tracks + for (auto const& trkInColl : tracksInCollision) { // Loop on tracks + if (trkInColl.isPVContributor()) { + pvContributors.push_back(getTrackParCov(trkInColl)); + idToRemove == trkInColl.globalIndex() ? pvContributorsMask.push_back(false) : pvContributorsMask.push_back(true); } } - mDCA.DCAxy = impactParameterTrk.getY(); - mDCA.DCAz = impactParameterTrk.getZ(); + LOG(debug) << "Tracks pushed to the vector: " << pvContributors.size(); + vertexer.init(); + bool canRefit = vertexer.prepareVertexRefit(pvContributors, primaryVertex); + if (!canRefit) { + return false; + } + // refit the vertex + auto newPV = vertexer.refitVertex(pvContributorsMask, primaryVertex); + // set the new vertex to primaryVertex + primaryVertex.setX(newPV.getX()); + primaryVertex.setY(newPV.getY()); + primaryVertex.setZ(newPV.getZ()); + primaryVertex.setCov(newPV.getCov()); + return true; } - 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 && mProcessCounter[0] != mProcessCounter[1]) { + mToiMap.clear(); + 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(), cfgTriggersOfInterest.value); + if (mZorro.getNTOIs() > 32) { + LOG(fatal) << "N TOIs:" << mZorro.getNTOIs() << " Max 32 TOIs possible."; + } + mZorro.populateHistRegistry(mRegistry, bc.runNumber()); + runNumber = bc.runNumber(); + } + bool sel = mZorro.isSelected(bc.globalBC()); /// Just let Zorro do the accounting + if (sel) { + std::vector toivect = mZorro.getTriggerOfInterestResults(); + uint32_t toiMask = 0; + for (size_t i{0}; i < toivect.size(); i++) { + toiMask += toivect[i] << i; + } + mToiMap[bc.globalBC()] = toiMask; } - 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()); } - 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()); + } + template + void fillMultHistos(CollisionType const& collisions) + { + // std::cout << "Filling mult histos" << std::endl; + for (const auto& coll : collisions) { + std::string histNameMvC = "mult/hMultVsCent_run" + std::to_string(mRunNumber); + std::string histNameMvCZ = "mult/hMultVsCentZoom_run" + std::to_string(mRunNumber); + std::string histNameTvC = "mult/hNTracksVsCent_run" + std::to_string(mRunNumber); + std::string histNameTvCZ = "mult/hNTracksVsCentZoom_run" + std::to_string(mRunNumber); + if (!mHistsPerRunMultVsCent.contains(histNameMvC)) { + mHistsPerRunMultVsCent[histNameMvC] = std::get>(mRegistry.add(histNameMvC.c_str(), histNameMvC.c_str(), HistType::kTH2F, {centAxis, multAxis})); + mHistsPerRunMultVsCentZoom[histNameMvCZ] = std::get>(mRegistry.add(histNameMvCZ.c_str(), histNameMvCZ.c_str(), HistType::kTH2F, {centAxisZoom, multAxisZoom})); + mHistsPerRunNtracktVsCent[histNameTvC] = std::get>(mRegistry.add(histNameTvC.c_str(), histNameTvC.c_str(), HistType::kTH2F, {centAxis, nTracksAxis})); + mHistsPerRunNtracktVsCentZoom[histNameTvCZ] = std::get>(mRegistry.add(histNameTvCZ.c_str(), histNameTvCZ.c_str(), HistType::kTH2F, {centAxisZoom, nTracksAxis})); } - registry.fill(HIST("h_ptrackdcavspt_Xi"), impactParameterProtontrack.getY(), protonTrack.pt()); + mHistsPerRunMultVsCent[histNameMvC]->Fill(coll.centFT0M(), coll.multFT0M()); + mHistsPerRunMultVsCentZoom[histNameMvCZ]->Fill(coll.centFT0M(), coll.multFT0M()); + mHistsPerRunNtracktVsCent[histNameTvC]->Fill(coll.centFT0M(), coll.multNTracksGlobal()); + mHistsPerRunNtracktVsCentZoom[histNameTvCZ]->Fill(coll.centFT0M(), coll.multNTracksGlobal()); + // run integrated histos + mRegistry.fill(HIST("hMultVsCent"), coll.centFT0M(), coll.multFT0M()); + mRegistry.fill(HIST("hMultVsCentZoom"), coll.centFT0M(), coll.multFT0M()); + mRegistry.fill(HIST("hNTracksVsCent"), coll.centFT0M(), (float)coll.multNTracksGlobal()); + mRegistry.fill(HIST("hNTracksVsCentZoom"), coll.centFT0M(), coll.multNTracksGlobal()); + mRegistry.fill(HIST("hMultFV0VshNTracks"), coll.multNTracksGlobal(), coll.multFV0A()); + mRegistry.fill(HIST("hNTracksVsCentFV0A"), coll.multNTracksGlobal(), coll.centFV0A()); } + }; - 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(CollisionsCandidatesRun3 const& /*collisions*/, - 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&, TrackType const& tracks, auto const& cascades, auto& candidates) { + const auto& getCascade = [](auto const& candidate) { + if constexpr (requires { candidate.cascade(); }) { + return candidate.cascade(); + } else { + return candidate; + } + }; + candidates.clear(); - std::vector mcParticleId; - for (const auto& trackedCascade : trackedCascades) { - auto collision = trackedCascade.collision_as(); + for (const auto& candidate : cascades) { - auto bc = collision.bc_as(); + auto collision = candidate.template collision_as(); + auto bc = collision.template 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& track = trackedCascade.track_as(); - const auto& ITStrack = trackedCascade.itsTrack_as(); - const auto& casc = trackedCascade.cascade(); - const auto& bachelor = casc.bachelor_as(); + auto primaryVertex = getPrimaryVertex(collision); + + 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; - } + // 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; - // PV - registry.fill(HIST("h_PV_x"), primaryVertex.getX()); - registry.fill(HIST("h_PV_y"), primaryVertex.getY()); - registry.fill(HIST("h_PV_z"), primaryVertex.getZ()); + mRegistry.fill(HIST("h_PIDcutsXi"), 0, 1.322); + mRegistry.fill(HIST("h_PIDcutsOmega"), 0, 1.675); - // Omega - masses = {o2::constants::physics::MassLambda0, o2::constants::physics::MassKPlus}; - const auto massOmega = RecoDecay::m(momenta, masses); + mRegistry.fill(HIST("h_PIDcutsXi"), 1, 1.322); + mRegistry.fill(HIST("h_PIDcutsOmega"), 1, 1.675); - // Xi - masses = {o2::constants::physics::MassLambda0, o2::constants::physics::MassPiPlus}; - const auto massXi = RecoDecay::m(momenta, masses); - - // 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); - - 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; - - bachPionNClusTPC = bachelor.tpcNClsFound(); /// by default cascade = Xi - bachPionNClusITS = bachelor.itsNCls(); /// by default cascade = Xi - - bool bachKaonHasTOF = 0; - bool bachPionHasTOF = 0; - - 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 (bachelor.hasTPC()) { // same cuts for Omega and Xi - LOG(debug) << "TPCSignal bachelor " << bachelor.sign() << "/" << bachelor.tpcInnerParam() << "/" << bachelor.tpcSignal(); - if (nSigmaTPC[0] < cfgCutsPID->get(0u, 0u) || nSigmaTPC[0] > cfgCutsPID->get(0u, 1u)) { - continue; - } + 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; } - registry.fill(HIST("h_PIDcutsOmega"), 3, massOmega); - 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)) { - 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_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 (!isBachelorSurvived) { continue; } - registry.fill(HIST("h_PIDcutsXi"), 5, massXi); - - 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, true, mDCA); // always filling in MC - - 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, true, dDCA); // always filling in MC - - bool isGoodCascade = false; - - int motherParticleID = -1; - - 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().mothers_first_as(); - if (abs(v0part.pdgCode()) == 3122 && v0part.has_mothers()) { - const auto motherV0 = v0part.mothers_as()[0]; - // const auto motherBach = bachelor.mcParticle().mothers_as()[0]; - if (v0part.mothersIds()[0] == bachelor.mcParticle().mothersIds()[0]) { - if (abs(motherV0.pdgCode()) == 3312 || abs(motherV0.pdgCode()) == 3334) { - isGoodCascade = true; - motherParticleID = v0part.mothersIds()[0]; - } - } - } - } - } - - bool isGoodMatch = ((motherParticleID == ITStrack.mcParticleId())) ? true : false; - - int pdgCodePrimary = -1; - if (isGoodCascade && isGoodMatch) { - if (track.mcParticle().has_mothers()) { - const auto primary = track.mcParticle().mothers_as()[0]; - pdgCodePrimary = primary.pdgCode(); - } + if (nSigmaTPC[2] < cfgCutsPID->get(2u, 0u) || nSigmaTPC[2] > cfgCutsPID->get(2u, 1u)) { + continue; } - candidates.emplace_back(NPCascCandidate{track.globalIndex(), ITStrack.globalIndex(), trackedCascade.matchingChi2(), trackedCascade.itsClsSize(), isGoodMatch, isGoodCascade, pdgCodePrimary, - primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), - track.pt(), track.eta(), track.phi(), - protonTrack.pt(), protonTrack.eta(), pionTrack.pt(), pionTrack.eta(), bachelor.pt(), bachelor.eta(), - 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.matchingChi2, c.itsClusSize, c.isGoodMatch, c.isGoodCascade, c.pdgCodePrimary, - 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.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); + mRegistry.fill(HIST("h_PIDcutsOmega"), 5, 1.675); + mRegistry.fill(HIST("h_PIDcutsXi"), 5, 1.322); - void processTrackedCascadesData(CollisionsCandidatesRun3 const& /*collisions*/, - aod::AssignedTrackedCascades const& trackedCascades, aod::Cascades const& /*cascades*/, - aod::V0s const& /*v0s*/, TracksExtData const& /*tracks*/, - aod::BCsWithTimestamps const&) - { - candidates.clear(); - for (const auto& trackedCascade : trackedCascades) { - bool isOmega{false}; - - auto collision = trackedCascade.collision_as(); - 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& track = trackedCascade.track_as(); - const auto& ITStrack = trackedCascade.itsTrack_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; + o2::track::TrackParCov ntCascadeTrack; + 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]); + ntCascadeTrack = mDCAFitter.createParentTrackParCov(); + ntCascadeTrack.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; } - - // PV - registry.fill(HIST("h_PV_x"), primaryVertex.getX()); - registry.fill(HIST("h_PV_y"), primaryVertex.getY()); - registry.fill(HIST("h_PV_z"), primaryVertex.getZ()); + 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 @@ -700,142 +509,302 @@ 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); + //// Omega hypohesis -> 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; } - 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(); + 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]; + } + } + } + } + } } - bachPionNClusTPC = bachelor.tpcNClsFound(); /// by default cascade = Xi - bachPionNClusITS = bachelor.itsNCls(); /// by default cascade = Xi - bool bachKaonHasTOF = 0; - bool bachPionHasTOF = 0; + if (cascCpa < cfgMinCosPA) { + continue; + } if (isOmega) { - bachKaonHasTOF = bachelor.hasTOF(); + mRegistry.fill(HIST("h_PIDcutsOmega"), 6, massOmega); } - bachPionHasTOF = bachelor.hasTOF(); - - // if (!bachelor.hasTOF() && !ptrack.hasTOF() && !ntrack.hasTOF() ) { - // LOG(debug)<< "no TOF: "<(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}, deltaPtCascade{-1.e10f}, cascITSclsSize{-1.e10f}, matchingChi2{-1.e10f}; + bool hasReassociatedClusters{false}, hasFakeReassociation{false}; + int trackedCascGlobalIndex{-1}, itsTrackGlobalIndex{-1}, cascITSclusters{-1}; + if constexpr (requires { candidate.track(); }) { + const auto& track = candidate.template track_as(); + const auto& ITStrack = candidate.template itsTrack_as(); + if (cfgRedoPV && ITStrack.isPVContributor()) { + if (!recalculatePV(collision, tracks, ITStrack.globalIndex(), primaryVertex)) { + continue; + } + } + cascPVContribs |= ITStrack.isPVContributor() << 0; + 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(); + deltaPtCascade = std::hypot(cascadeMomentum[0], cascadeMomentum[1]) - track.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; + hasFakeReassociation = track.mcMask() & (1 << 15); + } + itsTrackPDG = ITStrack.has_mcParticle() ? ITStrack.mcParticle().pdgCode() : 0; + } + } else { + o2::base::Propagator::Instance()->propagateToDCA(primaryVertex, ntCascadeTrack, mBz, 2.f, matCorr, &motherDCA); + } + uint32_t toiMask = 0x0; + if (mToiMap.count(bc.globalBC())) { + toiMask = mToiMap[bc.globalBC()]; + } + candidates.emplace_back(NPCascCandidate{mRunNumber, mcParticleID, trackedCascGlobalIndex, itsTrackGlobalIndex, candidate.collisionId(), matchingChi2, deltaPtITSCascade, deltaPtCascade, cascITSclsSize, hasReassociatedClusters, hasFakeReassociation, 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(), collision.multFT0C(), collision.multFV0A(), collision.multFT0M(), collision.centFT0C(), collision.centFV0A(), collision.centFT0M(), collision.multNTracksGlobal(), toiMask, collision.selection_bit(aod::evsel::kNoSameBunchPileup)}); + } + } - registry.fill(HIST("h_PIDcutsXi"), 1, massXi); - registry.fill(HIST("h_PIDcutsOmega"), 1, massOmega); + template + void fillDataTable(auto const& candidates) + { + for (const auto& c : candidates) { + getDataTable()(mRunNumber, c.matchingChi2, c.deltaPtITS, 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.multFV0A, c.multFT0M, c.centFT0C, c.centFV0A, c.centFT0M, c.multNTracksGlobal, c.toiMask, c.noSameBunchPileup); + } + } - if (protonTrack.tpcNClsFound() < cfgCutNclusTPC || pionTrack.tpcNClsFound() < cfgCutNclusTPC) { - LOG(debug) << "no tpcNClsFound: " << bachelor.tpcNClsFound() << "/" << protonTrack.tpcNClsFound() << "/" << pionTrack.tpcNClsFound(); + 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; } - 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; + auto particle = mcParticles.iteratorAt(c.mcParticleId); + int motherDecayDaughters{0}; + if (c.isFromBeauty || c.isFromCharm) { + auto mom = particle.template mothers_as()[0]; + auto daughters = mom.template daughters_as(); + motherDecayDaughters = daughters.size(); + for (const auto& d : daughters) { + if (std::abs(d.pdgCode()) == 11 || std::abs(d.pdgCode()) == 13) { + motherDecayDaughters *= -1; + break; } } } + auto mcCollision = particle.template mcCollision_as(); + auto recCollision = collisions.iteratorAt(c.collisionID); + + getMCtable()(mRunNumber, c.matchingChi2, c.deltaPtITS, 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.multFV0A, c.multFT0M, c.centFT0C, c.centFV0A, c.centFT0M, + particle.pt(), particle.eta(), particle.phi(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), + particle.pdgCode(), mcCollision.posX() - particle.vx(), mcCollision.posY() - particle.vy(), + mcCollision.posZ() - particle.vz(), mcCollision.globalIndex() == recCollision.mcCollisionId(), c.hasFakeReassociation, motherDecayDaughters, c.multNTracksGlobal, c.toiMask, c.noSameBunchPileup); + } + } - 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; - } - } + template + auto& getMCtable() + { + if constexpr (std::is_same_v) { + return NPCTableMCNT; + } else { + return NPCTableMC; + } + } - if (!isBachelorSurvived) { - continue; - } + template + auto& getDataTable() + { + if constexpr (std::is_same_v) { + return NPCTableNT; + } else { + return NPCTable; + } + } - LOG(debug) << "TPCSignal protonTrack " << protonTrack.sign() << "/" << protonTrack.tpcInnerParam() << "/" << protonTrack.tpcSignal(); - if (nSigmaTPC[2] < cfgCutsPID->get(2u, 0u) || nSigmaTPC[2] > cfgCutsPID->get(2u, 1u)) { - continue; - } + 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, tracks, trackedCascades, gCandidates); + fillMCtable(mcParticles, collisions, gCandidates); + } + PROCESS_SWITCH(NonPromptCascadeTask, processTrackedCascadesMC, "process cascades from strangeness tracking: MC analysis", true); - if (isOmega) { - registry.fill(HIST("h_PIDcutsOmega"), 4, massOmega); - } - registry.fill(HIST("h_PIDcutsXi"), 4, massXi); + 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, tracks, cascades, gCandidatesNT); + fillMCtable(mcParticles, collisions, gCandidatesNT); + fillMultHistos(collisions); + } + PROCESS_SWITCH(NonPromptCascadeTask, processCascadesMC, "process cascades: MC analysis", false); - LOG(debug) << "TPCSignal ntrack " << pionTrack.sign() << "/" << pionTrack.tpcInnerParam() << "/" << pionTrack.tpcSignal(); - if (nSigmaTPC[3] < cfgCutsPID->get(3u, 0u) || nSigmaTPC[3] > cfgCutsPID->get(3u, 1u)) { + void processGenParticles(aod::McParticles const& mcParticles) + { + for (const auto& p : mcParticles) { + auto absCode = std::abs(p.pdgCode()); + if (absCode != 3312 && absCode != 3334) { continue; } - - if (isOmega) { - registry.fill(HIST("h_PIDcutsOmega"), 5, massOmega); - invMassACOmega->Fill(massOmega); - registry.fill(HIST("h_massvspt_Omega"), massOmega, track.pt()); + auto fromHF = isFromHF(p); + int pdgCodeMom = p.has_mothers() ? p.template mothers_as()[0].pdgCode() : 0; + auto mcCollision = p.template mcCollision_as(); + int motherDecayDaughters{0}; + if (fromHF[0] || fromHF[1]) { + auto mom = p.template mothers_as()[0]; + auto daughters = mom.template daughters_as(); + motherDecayDaughters = daughters.size(); + for (const auto& d : daughters) { + if (std::abs(d.pdgCode()) == 11 || std::abs(d.pdgCode()) == 13) { + motherDecayDaughters *= -1; + break; + } + } } + 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], motherDecayDaughters); + } + } + PROCESS_SWITCH(NonPromptCascadeTask, processGenParticles, "process gen cascades: MC analysis", false); - 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()); + void processTrackedCascadesData(CollisionCandidatesRun3 const& collisions, + aod::AssignedTrackedCascades const& trackedCascades, aod::Cascades const& /*cascades*/, + aod::V0s const& /*v0s*/, TracksExtData const& tracks, + aod::BCsWithTimestamps const&) + { + mProcessCounter[0]++; + zorroAccounting(collisions); + fillCandidatesVector(collisions, tracks, trackedCascades, gCandidates); + fillDataTable(gCandidates); + } + PROCESS_SWITCH(NonPromptCascadeTask, processTrackedCascadesData, "process cascades from strangeness tracking: Data analysis", false); - motherDCA mDCA; - fillCascadeDCA(track, protonTrack, pionTrack, primaryVertex, isOmega, mDCA); - daughtersDCA dDCA; - fillDauDCA(trackedCascade, bachelor, protonTrack, pionTrack, primaryVertex, isOmega, dDCA); + void processCascadesData(CollisionCandidatesRun3 const& collisions, aod::Cascades const& cascades, + aod::V0s const& /*v0s*/, TracksExtData const& tracks, + aod::BCsWithTimestamps const&) + { + mProcessCounter[1]++; + zorroAccounting(collisions); + fillCandidatesVector(collisions, tracks, cascades, gCandidatesNT); + fillDataTable(gCandidatesNT); + fillMultHistos(collisions); + } + PROCESS_SWITCH(NonPromptCascadeTask, processCascadesData, "process cascades: Data analysis", false); - candidates.emplace_back(NPCascCandidate{track.globalIndex(), ITStrack.globalIndex(), trackedCascade.matchingChi2(), trackedCascade.itsClsSize(), 0, 0, -1, - primaryVertex.getX(), primaryVertex.getY(), primaryVertex.getZ(), - track.pt(), track.eta(), track.phi(), - protonTrack.pt(), protonTrack.eta(), pionTrack.pt(), pionTrack.eta(), bachelor.pt(), bachelor.eta(), - 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()}); + int getMCMult(aod::McParticles const& mcParticles, int mcCollId) + { + int mult = 0; + for (auto const& mcp : mcParticles) { + if (mcp.mcCollisionId() == mcCollId) { + // multiplicity definition: + bool accept = mcp.isPhysicalPrimary(); + accept = accept && (mcp.eta() < 0.5) && (mcp.eta() > -0.5); + int q = 0; + auto pdgEntry = TDatabasePDG::Instance()->GetParticle(mcp.pdgCode()); + if (pdgEntry) { + q = int(std::round(pdgEntry->Charge() / 3.0)); + } else { + // LOG(warn) << "No pdg assuming neutral"; + } + accept = accept && (q != 0); + if (accept) { + ++mult; + } + } } - - for (auto& c : candidates) { - - NPCTable(c.matchingChi2, c.itsClusSize, - 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.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); + return mult; + } + void processNegMC(CollisionsWithLabel const& colls, aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + { + // std::cout << "ProcNegMC" << std::endl; + std::vector mcReconstructed(mcCollisions.size(), 0); + for (auto const& col : colls) { + int mcCollId = col.mcCollisionId(); // col.template mcCollision_as(); + // auto mc = col.mcCollision(); + // int mcId = mc.globalIndex(); + // std::cout << "globalIndex:" << mcId << " colID:" << mcCollId << std::endl; + int mult = getMCMult(mcParticles, mcCollId); + mcReconstructed[mcCollId] = 1; + mRegistry.fill(HIST("hNTracksMCVsTracksReco"), mult, col.multNTracksGlobal()); + } + for (auto const& mc : mcCollisions) { + int gindex = mc.globalIndex(); + // std::cout << "mc globalIndex:" << gindex << std::endl; + if (!mcReconstructed[gindex]) { + int mult = getMCMult(mcParticles, gindex); + // std::cout << "===> unreconstructed:" << mult << std::endl; + mRegistry.fill(HIST("hNTracksMCNotInReco"), mult); + } } } - PROCESS_SWITCH(NonPromptCascadeTask, processTrackedCascadesData, "process cascades from strangeness tracking: Data analysis", false); + PROCESS_SWITCH(NonPromptCascadeTask, processNegMC, "process mc", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/phik0sanalysis.cxx b/PWGLF/Tasks/Strangeness/phik0sanalysis.cxx deleted file mode 100644 index 36f2398357a..00000000000 --- a/PWGLF/Tasks/Strangeness/phik0sanalysis.cxx +++ /dev/null @@ -1,1724 +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 Stefano Cannito (stefano.cannito@cern.ch) - -#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" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -namespace -{ -static constexpr int nMultBin = 10; - -constexpr float flowmPhiInc[nMultBin] = {1.01074f, 1.01073f, 1.01072f, 1.01074f, 1.01075f, 1.01074f, 1.01075f, 1.01074f, 1.01073f, 1.01074f}; -constexpr float fupmPhiInc[nMultBin] = {1.02778f, 1.02777f, 1.02776f, 1.02778f, 1.02779f, 1.02778f, 1.02779f, 1.02778f, 1.02777f, 1.02778f}; - -constexpr float flowmPhiFCut[nMultBin] = {1.01072f, 1.01073f, 1.01072f, 1.01074f, 1.01075f, 1.01076f, 1.01076f, 1.01076f, 1.01075f, 1.01073f}; -constexpr float fupmPhiFCut[nMultBin] = {1.02776f, 1.02777f, 1.02776f, 1.02778f, 1.02779f, 1.02778f, 1.02778f, 1.02778f, 1.02779f, 1.02777f}; - -constexpr float flowmPhiSCut[nMultBin] = {1.01072f, 1.01074f, 1.01070f, 1.01076f, 1.01075f, 1.01077f, 1.01075f, 1.01075f, 1.01076f, 1.01077f}; -constexpr float fupmPhiSCut[nMultBin] = {1.02776f, 1.02778f, 1.02774f, 1.02780f, 1.02779f, 1.02781f, 1.02779f, 1.02779f, 1.02780f, 1.02774f}; - -static constexpr float multBin[nMultBin + 1] = {0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 70.0, 100.0}; - -static constexpr std::string_view PhiK0SSEInc[nMultBin] = {"h2PhiK0SSEInc_0_1", "h2PhiK0SSEInc_1_5", "h2PhiK0SSEInc_5_10", "h2PhiK0SSEInc_10_15", "h2PhiK0SSEInc_15_20", - "h2PhiK0SSEInc_20_30", "h2PhiK0SSEInc_30_40", "h2PhiK0SSEInc_40_50", "h2PhiK0SSEInc_50_70", "h2PhiK0SSEInc_70_100"}; -static constexpr std::string_view PhiK0SSEFCut[nMultBin] = {"h2PhiK0SSEFCut_0_1", "h2PhiK0SSEFCut_1_5", "h2PhiK0SSEFCut_5_10", "h2PhiK0SSEFCut_10_15", "h2PhiK0SSEFCut_15_20", - "h2PhiK0SSEFCut_20_30", "h2PhiK0SSEFCut_30_40", "h2PhiK0SSEFCut_40_50", "h2PhiK0SSEFCut_50_70", "h2PhiK0SSEFCut_70_100"}; -static constexpr std::string_view PhiK0SSESCut[nMultBin] = {"h2PhiK0SSESCut_0_1", "h2PhiK0SSESCut_1_5", "h2PhiK0SSESCut_5_10", "h2PhiK0SSESCut_10_15", "h2PhiK0SSESCut_15_20", - "h2PhiK0SSESCut_20_30", "h2PhiK0SSESCut_30_40", "h2PhiK0SSESCut_40_50", "h2PhiK0SSESCut_50_70", "h2PhiK0SSESCut_70_100"}; - -static constexpr std::string_view PhiPiSEInc[nMultBin] = {"h2PhiPiSEInc_0_1", "h2PhiPiSEInc_1_5", "h2PhiPiSEInc_5_10", "h2PhiPiSEInc_10_15", "h2PhiPiSEInc_15_20", - "h2PhiPiSEInc_20_30", "h2PhiPiSEInc_30_40", "h2PhiPiSEInc_40_50", "h2PhiPiSEInc_50_70", "h2PhiPiSEInc_70_100"}; -static constexpr std::string_view PhiPiSEFCut[nMultBin] = {"h2PhiPiSEFCut_0_1", "h2PhiPiSEFCut_1_5", "h2PhiPiSEFCut_5_10", "h2PhiPiSEFCut_10_15", "h2PhiPiSEFCut_15_20", - "h2PhiPiSEFCut_20_30", "h2PhiPiSEFCut_30_40", "h2PhiPiSEFCut_40_50", "h2PhiPiSEFCut_50_70", "h2PhiPiSEFCut_70_100"}; -static constexpr std::string_view PhiPiSESCut[nMultBin] = {"h2PhiPiSESCut_0_1", "h2PhiPiSESCut_1_5", "h2PhiPiSESCut_5_10", "h2PhiPiSESCut_10_15", "h2PhiPiSESCut_15_20", - "h2PhiPiSESCut_20_30", "h2PhiPiSESCut_30_40", "h2PhiPiSESCut_40_50", "h2PhiPiSESCut_50_70", "h2PhiPiSESCut_70_100"}; - -static constexpr std::string_view MCPhiK0SSEInc[nMultBin] = {"h2RecMCPhiK0SSEInc_0_1", "h2RecMCPhiK0SSEInc_1_5", "h2RecMCPhiK0SSEInc_5_10", "h2RecMCPhiK0SSEInc_10_15", "h2RecMCPhiK0SSEInc_15_20", - "h2RecMCPhiK0SSEInc_20_30", "h2RecMCPhiK0SSEInc_30_40", "h2RecMCPhiK0SSEInc_40_50", "h2RecMCPhiK0SSEInc_50_70", "h2RecMCPhiK0SSEInc_70_100"}; -static constexpr std::string_view MCPhiK0SSEFCut[nMultBin] = {"h2RecMCPhiK0SSEFCut_0_1", "h2RecMCPhiK0SSEFCut_1_5", "h2RecMCPhiK0SSEFCut_5_10", "h2RecMCPhiK0SSEFCut_10_15", "h2RecMCPhiK0SSEFCut_15_20", - "h2RecMCPhiK0SSEFCut_20_30", "h2RecMCPhiK0SSEFCut_30_40", "h2RecMCPhiK0SSEFCut_40_50", "h2RecMCPhiK0SSEFCut_50_70", "h2RecMCPhiK0SSEFCut_70_100"}; -static constexpr std::string_view MCPhiK0SSESCut[nMultBin] = {"h2RecMCPhiK0SSESCut_0_1", "h2RecMCPhiK0SSESCut_1_5", "h2RecMCPhiK0SSESCut_5_10", "h2RecMCPhiK0SSESCut_10_15", "h2RecMCPhiK0SSESCut_15_20", - "h2RecMCPhiK0SSESCut_20_30", "h2RecMCPhiK0SSESCut_30_40", "h2RecMCPhiK0SSESCut_40_50", "h2RecMCPhiK0SSESCut_50_70", "h2RecMCPhiK0SSESCut_70_100"}; - -static constexpr std::string_view MCPhiPiSEInc[nMultBin] = {"h2RecMCPhiPiSEInc_0_1", "h2RecMCPhiPiSEInc_1_5", "h2RecMCPhiPiSEInc_5_10", "h2RecMCPhiPiSEInc_10_15", "h2RecMCPhiPiSEInc_15_20", - "h2RecMCPhiPiSEInc_20_30", "h2RecMCPhiPiSEInc_30_40", "h2RecMCPhiPiSEInc_40_50", "h2RecMCPhiPiSEInc_50_70", "h2RecMCPhiPiSEInc_70_100"}; -static constexpr std::string_view MCPhiPiSEFCut[nMultBin] = {"h2RecMCPhiPiSEFCut_0_1", "h2RecMCPhiPiSEFCut_1_5", "h2RecMCPhiPiSEFCut_5_10", "h2RecMCPhiPiSEFCut_10_15", "h2RecMCPhiPiSEFCut_15_20", - "h2RecMCPhiPiSEFCut_20_30", "hRecMCPhiPiSEFCut_30_40", "h2RecMCPhiPiSEFCut_40_50", "h2RecMCPhiPiSEFCut_50_70", "h2RecMCPhiPiSEFCut_70_100"}; -static constexpr std::string_view MCPhiPiSESCut[nMultBin] = {"h2RecMCPhiPiSESCut_0_1", "h2RecMCPhiPiSESCut_1_5", "h2RecMCPhiPiSESCut_5_10", "h2RecMCPhiPiSESCut_10_15", "h2RecMCPhiPiSESCut_15_20", - "h2RecMCPhiPiSESCut_20_30", "h2RecMCPhiPiSESCut_30_40", "h2RecMCPhiPiSESCut_40_50", "h2RecMCPhiPiSESCut_50_70", "h2RecMCPhiPiSESCut_70_100"}; -} // namespace - -struct phik0shortanalysis { - // Histograms are defined with HistogramRegistry - HistogramRegistry eventHist{"eventHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MCeventHist{"MCeventHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry PhicandHist{"PhicandHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry K0SHist{"K0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry PhipurHist{"PhipurHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry PhiK0SHist{"PhiK0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MCPhiK0SHist{"MCPhiK0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry PhiPionHist{"PhiPionHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry MCPhiPionHist{"MCPhiPionHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - - // Configurable for event selection - Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; - - // Configurables for V0 selection - 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 etaMax{"etaMax", 0.8f, "eta max"}; - - Configurable v0setting_cospa{"v0setting_cospa", 0.98, "V0 CosPA"}; - Configurable v0setting_radius{"v0setting_radius", 0.5, "v0radius"}; - Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 1, "DCA 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 NSigmaTPCPion{"NSigmaTPCPion", 4.0, "NSigmaTPCPion"}; - - // Configurables on K0S mass - Configurable lowmK0S{"lowmK0S", 0.48, "Lower limit on K0Short mass"}; - Configurable upmK0S{"upmK0S", 0.52, "Upper limit on K0Short mass"}; - - // Configurables on Phi mass - Configurable nBins{"nBins", 15, "N bins in cfgPhimassaxis"}; - Configurable> lowmPhiInc{"lowmPhiInc", std::vector{flowmPhiInc, flowmPhiInc + nMultBin}, "Lower limits on Phi mass Inclusive"}; - Configurable> upmPhiInc{"upmPhiInc", std::vector{fupmPhiInc, fupmPhiInc + nMultBin}, "Upper limits on Phi mass Inclusive"}; - Configurable> lowmPhiFCut{"lowmPhiFCut", std::vector{flowmPhiFCut, flowmPhiFCut + nMultBin}, "Lower limits on Phi mass First Cut"}; - Configurable> upmPhiFCut{"upmPhiFCut", std::vector{fupmPhiFCut, fupmPhiFCut + nMultBin}, "Upper limits on Phi mass First Cut"}; - Configurable> lowmPhiSCut{"lowmPhiSCut", std::vector{flowmPhiSCut, flowmPhiSCut + nMultBin}, "Lower limits on Phi mass Second Cut"}; - Configurable> upmPhiSCut{"upmPhiSCut", std::vector{fupmPhiSCut, fupmPhiSCut + nMultBin}, "Upper limits on Phi mass Second Cut"}; - - // Configurables for phi selection - Configurable cMinPtcut{"cMinPtcut", 0.15, "Track minimum pt cut"}; - Configurable cfgCutCharge{"cfgCutCharge", 0.0, "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 cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; - Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; - - Configurable isNoTOF{"isNoTOF", false, "isNoTOF"}; - Configurable nsigmaCutTPCKa{"nsigmacutTPC", 3.0, "Value of the TPC Nsigma cut"}; - Configurable nsigmaCutCombinedKa{"nsigmaCutCombined", 3.0, "Value of the TOF Nsigma cut"}; - - // Configurables for pions(extra with respect to a few of those defined for V0) - Configurable minITSnCls{"minITSnCls", 4.0f, "min number of ITS clusters"}; - Configurable maxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"}; - Configurable dcaxyMax{"dcaxyMax", 0.1f, "Maximum DCAxy to primary vertex"}; - Configurable dcazMax{"dcazMax", 0.1f, "Maximum DCAz to primary vertex"}; - Configurable NSigmaTOFPion{"NSigmaTOFPion", 5.0, "NSigmaTOFPion"}; - - // Configurables for invariant mass histograms filling - Configurable cfgFirstCutonDeltay{"cgfFirstCutonDeltay", 0.5, "First upper bound on Deltay selection"}; - Configurable cfgSecondCutonDeltay{"cgfSecondCutonDeltay", 0.2, "Second upper bound on Deltay selection"}; - - // Configurable for event mixing - Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; - - // Configurable axis - 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"}; - - // Constants - double massKa = o2::constants::physics::MassKPlus; - double massPi = o2::constants::physics::MassPiPlus; - - // 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) > v0setting_dcapostopv && nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv && aod::v0data::dcaV0daughters < v0setting_dcav0dau); - - // 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; - - // 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 > cfgCutCharge; - Partition negTracks = aod::track::signed1Pt < cfgCutCharge; - - Partition posMCTracks = aod::track::signed1Pt > cfgCutCharge; - Partition negMCTracks = aod::track::signed1Pt < cfgCutCharge; - - // Necessary to flag INEL>0 events in GenMC - Service pdgDB; - - void init(InitContext const&) - { - // Axes - AxisSpec K0SmassAxis = {200, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - AxisSpec PhimassAxis = {200, 0.9f, 1.2f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - AxisSpec vertexZAxis = {100, -15.f, 15.f, "vrtx_{Z} [cm]"}; - AxisSpec deltayAxis = {16, 0.0f, 0.8f, "|#it{#Deltay}|"}; - AxisSpec multAxis = {120, 0.0f, 120.0f, "centFT0M"}; - AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; - std::vector cfgPhimassAxisInc; - std::vector cfgPhimassAxisFCut; - std::vector cfgPhimassAxisSCut; - for (int i = 0; i < nMultBin; i++) { - cfgPhimassAxisInc.push_back({nBins, lowmPhiInc->at(i), upmPhiInc->at(i), "#it{M}_{inv} [GeV/#it{c}^{2}]"}); - cfgPhimassAxisFCut.push_back({nBins, lowmPhiFCut->at(i), upmPhiFCut->at(i), "#it{M}_{inv} [GeV/#it{c}^{2}]"}); - cfgPhimassAxisSCut.push_back({nBins, lowmPhiSCut->at(i), upmPhiSCut->at(i), "#it{M}_{inv} [GeV/#it{c}^{2}]"}); - } - - // Histograms - // Number of events per selection - eventHist.add("hEventSelection", "hEventSelection", kTH1F, {{5, -0.5f, 4.5f}}); - eventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); - eventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); - eventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "posZ cut"); - eventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "INEL>0 cut"); - eventHist.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "With at least a #phi cand"); - - // Event information - eventHist.add("hVertexZ", "hVertexZ", kTH1F, {vertexZAxis}); - eventHist.add("hMultiplicityPercent", "Multiplicity Percentile", kTH1F, {multAxis}); - - // Number of MC events per selection for Rec and Gen - MCeventHist.add("hRecMCEventSelection", "hRecMCEventSelection", kTH1F, {{7, -0.5f, 6.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 #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 rec coll"); - MCeventHist.get(HIST("hGenMCEventSelection"))->GetXaxis()->SetBinLabel(5, "With at least a #phi"); - - // MC Event information for Rec and Gen - MCeventHist.add("hRecMCVertexZ", "hRecMCVertexZ", kTH1F, {vertexZAxis}); - MCeventHist.add("hRecMCMultiplicityPercent", "RecMC Multiplicity Percentile", kTH1F, {multAxis}); - - MCeventHist.add("hGenMCVertexZ", "hGenMCVertexZ", kTH1F, {vertexZAxis}); - MCeventHist.add("hGenMCMultiplicityPercent", "GenMC Multiplicity Percentile", kTH1F, {multAxis}); - - // Phi tpological/PID cuts - PhicandHist.add("hEta", "Eta distribution", kTH1F, {{200, -1.0f, 1.0f}}); - PhicandHist.add("hDcaxy", "Dcaxy distribution", kTH1F, {{200, -1.0f, 1.0f}}); - PhicandHist.add("hDcaz", "Dcaz distribution", kTH1F, {{200, -1.0f, 1.0f}}); - PhicandHist.add("hNsigmaKaonTPC", "NsigmaKaon TPC distribution", kTH2F, {ptAxis, {100, -10.0f, 10.0f}}); - PhicandHist.add("hNsigmaKaonTOF", "NsigmaKaon TOF distribution", kTH2F, {ptAxis, {100, -10.0f, 10.0f}}); - - // K0S topological/PID cuts - K0SHist.add("hDCAV0Daughters", "hDCAV0Daughters", kTH1F, {{55, 0.0f, 2.2f}}); - K0SHist.add("hV0CosPA", "hV0CosPA", kTH1F, {{100, 0.95f, 1.f}}); - K0SHist.add("hNSigmaPosPionFromK0S", "hNSigmaPosPionFromK0Short", kTH2F, {ptAxis, {100, -5.f, 5.f}}); - K0SHist.add("hNSigmaNegPionFromK0S", "hNSigmaNegPionFromK0Short", kTH2F, {ptAxis, {100, -5.f, 5.f}}); - - // Phi invariant mass for computing purities and normalisation - PhipurHist.add("h2PhipurInvMass", "Invariant mass of Phi for Purity (no K0S/Pi)", kTH2F, {multAxis, PhimassAxis}); - PhipurHist.add("h2PhipurK0SInvMassInclusive", "Invariant mass of Phi for Purity (K0S) Inclusive", kTH2F, {multAxis, PhimassAxis}); - PhipurHist.add("h2PhipurK0SInvMassFirstCut", "Invariant mass of Phi for Purity (K0S) Deltay < FirstCut", kTH2F, {multAxis, PhimassAxis}); - PhipurHist.add("h2PhipurK0SInvMassSecondCut", "Invariant mass of Phi for Purity (K0S) Deltay < SecondCut", kTH2F, {multAxis, PhimassAxis}); - PhipurHist.add("h3PhipurPiInvMassInclusive", "Invariant mass of Phi for Purity (Pi) Inclusive", kTH3F, {multAxis, ptAxis, PhimassAxis}); - PhipurHist.add("h3PhipurPiInvMassFirstCut", "Invariant mass of Phi for Purity (Pi) Deltay < FirstCut", kTH3F, {multAxis, ptAxis, PhimassAxis}); - PhipurHist.add("h3PhipurPiInvMassSecondCut", "Invariant mass of Phi for Purity (Pi) Deltay < SecondCut", kTH3F, {multAxis, ptAxis, PhimassAxis}); - - // 2D mass for Phi and K0S for Same Event and Mixed Event - for (int i = 0; i < nMultBin; i++) { - PhiK0SHist.add(PhiK0SSEInc[i].data(), "2D Invariant mass of Phi and K0Short for Same Event Inclusive", kTH2F, {K0SmassAxis, cfgPhimassAxisInc.at(i)}); - PhiK0SHist.add(PhiK0SSEFCut[i].data(), "2D Invariant mass of Phi and K0Short for Same Event Deltay < FirstCut", kTH2F, {K0SmassAxis, cfgPhimassAxisFCut.at(i)}); - PhiK0SHist.add(PhiK0SSESCut[i].data(), "2D Invariant mass of Phi and K0Short for Same Event Deltay < SecondCut", kTH2F, {K0SmassAxis, cfgPhimassAxisSCut.at(i)}); - } - - PhiK0SHist.add("h3PhiK0SInvMassMixedEventInclusive", "2D Invariant mass of Phi and K0Short for Mixed Event Inclusive", kTH3F, {multAxis, K0SmassAxis, PhimassAxis}); - PhiK0SHist.add("h3PhiK0SInvMassMixedEventFirstCut", "2D Invariant mass of Phi and K0Short for Mixed Event Deltay < FirstCut", kTH3F, {multAxis, K0SmassAxis, PhimassAxis}); - PhiK0SHist.add("h3PhiK0SInvMassMixedEventSecondCut", "2D Invariant mass of Phi and K0Short for Mixed Event Deltay < SecondCut", kTH3F, {multAxis, K0SmassAxis, PhimassAxis}); - - // MC 2D mass for Phi and K0S - for (int i = 0; i < nMultBin; i++) { - MCPhiK0SHist.add(MCPhiK0SSEInc[i].data(), "2D Invariant mass of Phi and K0Short for RecMC Inclusive", kTH2F, {K0SmassAxis, cfgPhimassAxisInc.at(i)}); - MCPhiK0SHist.add(MCPhiK0SSEFCut[i].data(), "2D Invariant mass of Phi and K0Short for RecMC Deltay < FirstCut", kTH2F, {K0SmassAxis, cfgPhimassAxisFCut.at(i)}); - MCPhiK0SHist.add(MCPhiK0SSESCut[i].data(), "2D Invariant mass of Phi and K0Short for RecMC Deltay < SecondCut", kTH2F, {K0SmassAxis, cfgPhimassAxisSCut.at(i)}); - } - - // GenMC pT of K0S coupled to Phi - MCPhiK0SHist.add("h1PhiK0SGenMCInclusive", "K0Short coupled to Phi for GenMC Inclusive", kTH1F, {{10, -0.5f, 9.5f}}); - MCPhiK0SHist.add("h1PhiK0SGenMCFirstCut", "K0Short coupled to Phi for GenMC Deltay < FirstCut", kTH1F, {{10, -0.5f, 9.5f}}); - MCPhiK0SHist.add("h1PhiK0SGenMCSecondCut", "K0Short coupled to Phi for GenMC Deltay < SecondCut", kTH1F, {{10, -0.5f, 9.5f}}); - - // Phi mass vs Pion NSigma dE/dx for Same Event and Mixed Event - for (int i = 0; i < nMultBin; i++) { - PhiPionHist.add(PhiPiSEInc[i].data(), "Phi Invariant mass vs Pion nSigma TPC/TOF for Same Event Inclusive", kTHnSparseF, {ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, cfgPhimassAxisInc.at(i)}); - PhiPionHist.add(PhiPiSEFCut[i].data(), "Phi Invariant mass vs Pion nSigma TPC/TOF for Same Event Deltay < FirstCut", kTHnSparseF, {ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, cfgPhimassAxisFCut.at(i)}); - PhiPionHist.add(PhiPiSESCut[i].data(), "Phi Invariant mass vs Pion nSigma TPC/TOF for Same Event Deltay < SecondCut", kTHnSparseF, {ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, cfgPhimassAxisSCut.at(i)}); - } - - PhiPionHist.add("h4PhiInvMassPiNSigmadEdxMixedEventInclusive", "Phi Invariant mass vs Pion nSigma TPC/TOF for Mixed Event Inclusive", kTHnSparseF, {multAxis, ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, PhimassAxis}); - PhiPionHist.add("h4PhiInvMassPiNSigmadEdxMixedEventFirstCut", "Phi Invariant mass vs Pion nSigma TPC/TOF for Mixed Event Deltay < FirstCut", kTHnSparseF, {multAxis, ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, PhimassAxis}); - PhiPionHist.add("h4PhiInvMassPiNSigmadEdxMixedEventSecondCut", "Phi Invariant mass vs Pion nSigma TPC/TOF for Mixed Event Deltay < SecondCut", kTHnSparseF, {multAxis, ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, PhimassAxis}); - - // MC Phi mass vs Pion NSigma dE/dx - for (int i = 0; i < nMultBin; i++) { - MCPhiPionHist.add(MCPhiPiSEInc[i].data(), "Phi Invariant mass vs Pion nSigma TPC/TOF for RecMC Inclusive", kTHnSparseF, {ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, cfgPhimassAxisInc.at(i)}); - MCPhiPionHist.add(MCPhiPiSEFCut[i].data(), "Phi Invariant mass vs Pion nSigma TPC/TOF for RecMC Deltay < FirstCut", kTHnSparseF, {ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, cfgPhimassAxisFCut.at(i)}); - MCPhiPionHist.add(MCPhiPiSESCut[i].data(), "Phi Invariant mass vs Pion nSigma TPC/TOF for RecMC Deltay < SecondCut", kTHnSparseF, {ptAxis, {100, -10.0f, 10.0f}, {100, -10.0f, 10.0f}, cfgPhimassAxisSCut.at(i)}); - } - - // GenMC pT of Pion coupled to Phi - MCPhiPionHist.add("h1PhiPiGenMCInclusive", "Pion coupled to Phi for GenMC Inclusive", kTH1F, {{10, -0.5f, 9.5f}}); - MCPhiPionHist.add("h1PhiPiGenMCFirstCut", "Pion coupled to Phi for GenMC Deltay < FirstCut", kTH1F, {{10, -0.5f, 9.5f}}); - MCPhiPionHist.add("h1PhiPiGenMCSecondCut", "Pion coupled to Phi for GenMC Deltay < SecondCut", kTH1F, {{10, -0.5f, 9.5f}}); - } - - // Event selection and QA filling - template - bool acceptEventQA(const T& collision, bool QA) - { - if constexpr (!isMC) { // data event - if (QA) - eventHist.fill(HIST("hEventSelection"), 0); // all collisions - if (!collision.sel8()) - return false; - if (QA) - eventHist.fill(HIST("hEventSelection"), 1); // sel8 collisions - if (std::abs(collision.posZ()) > cutzvertex) - return false; - if (QA) { - eventHist.fill(HIST("hEventSelection"), 2); // vertex-Z selected - eventHist.fill(HIST("hVertexZ"), collision.posZ()); - } - if (!collision.isInelGt0()) - return false; - if (QA) - eventHist.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 (collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && QA) - MCeventHist.fill(HIST("hRecMCEventSelection"), 3); // kNoITSROFrameBorder collisions (not requested in the selection, but useful for QA) - 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() < minTPCnClsFound) - return false; - if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) - return false; - if (track.tpcChi2NCl() > maxChi2TPC) - 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() < v0setting_cospa) - return false; - if (v0.v0radius() < v0setting_radius) - return false; - - if (std::abs(daughter1.tpcNSigmaPi()) > NSigmaTPCPion) - return false; - if (std::abs(daughter2.tpcNSigmaPi()) > NSigmaTPCPion) - return false; - return true; - } - - // Topological track selection - template - bool selectionTrackResonance(const T& 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; - } - - // PIDKaon track selection - template - bool selectionPIDKaon(const T& candidate) - { - if (!isNoTOF && candidate.hasTOF() && (candidate.tofNSigmaKa() * candidate.tofNSigmaKa() + candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa()) < (nsigmaCutCombinedKa * nsigmaCutCombinedKa)) - return true; - if (!isNoTOF && !candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) - return true; - if (isNoTOF && std::abs(candidate.tpcNSigmaKa()) < nsigmaCutTPCKa) - return true; - return false; - } - - // Reconstruct the Phi - template - TLorentzVector recMother(const T1& candidate1, const T2& candidate2, float masscand1, float masscand2) - { - TLorentzVector daughter1, daughter2, mother; - - daughter1.SetXYZM(candidate1.px(), candidate1.py(), candidate1.pz(), masscand1); // set the daughter1 4-momentum - daughter2.SetXYZM(candidate2.px(), candidate2.py(), candidate2.pz(), masscand2); // set the daughter2 4-momentum - mother = daughter1 + daughter2; // calculate the mother 4-momentum - - return mother; - } - - // Topological selection for pions - template - bool selectionPion(const T& track) - { - if (!track.hasITS()) - return false; - if (track.itsNCls() < minITSnCls) - return false; - if (track.itsChi2NCl() > maxChi2ITS) - return false; - - if (track.pt() < 1.2) { - 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.pt() > 0.5) { - if (!track.hasTOF()) - return false; - } - - if (std::abs(track.dcaXY()) > dcaxyMax) - return false; - if (std::abs(track.dcaZ()) > dcazMax) - return false; - return true; - } - - // Fill 2D invariant mass histogram for V0 and Phi - template - void fillInvMass2D(TLorentzVector V0, const std::vector listPhi, float multiplicity, double weightInclusive, double weightLtFirstCut, double weightLtSecondCut) - { - double massV0 = V0.M(); - double rapidityV0 = V0.Rapidity(); - - for (unsigned int phitag = 0; phitag < listPhi.size(); phitag++) { - double massPhi = listPhi[phitag].M(); - double rapidityPhi = listPhi[phitag].Rapidity(); - double deltay = std::abs(rapidityV0 - rapidityPhi); - - if constexpr (!isMix) { // same event - PhiK0SHist.fill(HIST(PhiK0SSEInc[iBin]), massV0, massPhi, weightInclusive); - if (deltay > cfgFirstCutonDeltay) - continue; - PhiK0SHist.fill(HIST(PhiK0SSEFCut[iBin]), massV0, massPhi, weightLtFirstCut); - if (deltay > cfgSecondCutonDeltay) - continue; - PhiK0SHist.fill(HIST(PhiK0SSESCut[iBin]), massV0, massPhi, weightLtSecondCut); - } else { // mixed event - PhiK0SHist.fill(HIST("h3PhiK0SInvMassMixedEventInclusive"), multiplicity, massV0, massPhi, weightInclusive); - if (deltay > cfgFirstCutonDeltay) - continue; - PhiK0SHist.fill(HIST("h3PhiK0SInvMassMixedEventFirstCut"), multiplicity, massV0, massPhi, weightLtFirstCut); - if (deltay > cfgSecondCutonDeltay) - continue; - PhiK0SHist.fill(HIST("h3PhiK0SInvMassMixedEventSecondCut"), multiplicity, massV0, massPhi, weightLtSecondCut); - } - - if constexpr (isMC) { // MC event - MCPhiK0SHist.fill(HIST(MCPhiK0SSEInc[iBin]), massV0, massPhi, weightInclusive); - if (deltay > cfgFirstCutonDeltay) - continue; - MCPhiK0SHist.fill(HIST(MCPhiK0SSEFCut[iBin]), massV0, massPhi, weightLtFirstCut); - if (deltay > cfgSecondCutonDeltay) - continue; - MCPhiK0SHist.fill(HIST(MCPhiK0SSESCut[iBin]), massV0, massPhi, weightLtSecondCut); - } - } - } - - // Fill Phi invariant mass vs Pion nSigmadE/dx histogram - template - void fillInvMassNSigma(TLorentzVector Pi, float nSigmaTPCPi, float nSigmaTOFPi, const std::vector listPhi, float multiplicity, double weightInclusive, double weightLtFirstCut, double weightLtSecondCut) - { - double rapidityPi = Pi.Rapidity(); - double ptPi = Pi.Pt(); - - for (unsigned int phitag = 0; phitag < listPhi.size(); phitag++) { - double massPhi = listPhi[phitag].M(); - double rapidityPhi = listPhi[phitag].Rapidity(); - double deltay = std::abs(rapidityPi - rapidityPhi); - - if constexpr (!isMix) { // same event - PhiPionHist.fill(HIST(PhiPiSEInc[iBin]), ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightInclusive); - if (deltay > cfgFirstCutonDeltay) - continue; - PhiPionHist.fill(HIST(PhiPiSEFCut[iBin]), ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightLtFirstCut); - if (deltay > cfgSecondCutonDeltay) - continue; - PhiPionHist.fill(HIST(PhiPiSESCut[iBin]), ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightLtSecondCut); - } else { // mixed event - PhiPionHist.fill(HIST("h4PhiInvMassPiNSigmadEdxMixedEventInclusive"), multiplicity, ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightInclusive); - if (deltay > cfgFirstCutonDeltay) - continue; - PhiPionHist.fill(HIST("h4PhiInvMassPiNSigmadEdxMixedEventFirstCut"), multiplicity, ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightLtFirstCut); - if (deltay > cfgSecondCutonDeltay) - continue; - PhiPionHist.fill(HIST("h4PhiInvMassPiNSigmadEdxMixedEventSecondCut"), multiplicity, ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightLtSecondCut); - } - - if constexpr (isMC) { // MC event - MCPhiPionHist.fill(HIST(MCPhiPiSEInc[iBin]), ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightInclusive); - if (deltay > cfgFirstCutonDeltay) - continue; - MCPhiPionHist.fill(HIST(MCPhiPiSEFCut[iBin]), ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightLtFirstCut); - if (deltay > cfgSecondCutonDeltay) - continue; - MCPhiPionHist.fill(HIST(MCPhiPiSESCut[iBin]), ptPi, nSigmaTPCPi, nSigmaTOFPi, massPhi, weightLtSecondCut); - } - } - } - - 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(); - eventHist.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; - - for (auto track1 : posThisColl) { // loop over all selected tracks - if (!selectionTrackResonance(track1) || !selectionPIDKaon(track1)) - continue; // topological and PID selection - - PhicandHist.fill(HIST("hEta"), track1.eta()); - PhicandHist.fill(HIST("hDcaxy"), track1.dcaXY()); - PhicandHist.fill(HIST("hDcaz"), track1.dcaZ()); - PhicandHist.fill(HIST("hNsigmaKaonTPC"), track1.tpcInnerParam(), track1.tpcNSigmaKa()); - PhicandHist.fill(HIST("hNsigmaKaonTOF"), track1.tpcInnerParam(), track1.tofNSigmaKa()); - - auto track1ID = track1.globalIndex(); - - // Loop over all negative candidates - for (auto track2 : negThisColl) { - if (!selectionTrackResonance(track2) || !selectionPIDKaon(track2)) - continue; // topological and PID selection - - auto track2ID = track2.globalIndex(); - if (track2ID == track1ID) - continue; // condition to avoid double counting of pair - - TLorentzVector recPhi; - recPhi = recMother(track1, track2, massKa, massKa); - if (recPhi.Rapidity() > 0.8) - continue; - - if (!isCountedPhi) { - eventHist.fill(HIST("hEventSelection"), 4); // at least a Phi candidate in the event - isCountedPhi = true; - } - - PhipurHist.fill(HIST("h2PhipurInvMass"), multiplicity, recPhi.M()); - - bool isCountedK0SInclusive = false, isCountedK0SFirstCut = false, isCountedK0SSecondCut = false; - - // 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 (!isFilledhV0) { - K0SHist.fill(HIST("hDCAV0Daughters"), v0.dcaV0daughters()); - K0SHist.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) { - K0SHist.fill(HIST("hNSigmaPosPionFromK0S"), posDaughterTrack.tpcInnerParam(), posDaughterTrack.tpcNSigmaPi()); - K0SHist.fill(HIST("hNSigmaNegPionFromK0S"), negDaughterTrack.tpcInnerParam(), negDaughterTrack.tpcNSigmaPi()); - } - } - - TLorentzVector recK0S; - recK0S.SetXYZM(v0.px(), v0.py(), v0.pz(), v0.mK0Short()); - - if (recK0S.Rapidity() > 0.8) - continue; - if (!isCountedK0SInclusive) { - PhipurHist.fill(HIST("h2PhipurK0SInvMassInclusive"), multiplicity, recPhi.M()); - isCountedK0SInclusive = true; - } - if (std::abs(recK0S.Rapidity() - recPhi.Rapidity()) > cfgFirstCutonDeltay) - continue; - if (!isCountedK0SFirstCut) { - PhipurHist.fill(HIST("h2PhipurK0SInvMassFirstCut"), multiplicity, recPhi.M()); - isCountedK0SFirstCut = true; - } - if (std::abs(recK0S.Rapidity() - recPhi.Rapidity()) > cfgSecondCutonDeltay) - continue; - if (!isCountedK0SSecondCut) { - PhipurHist.fill(HIST("h2PhipurK0SInvMassSecondCut"), multiplicity, recPhi.M()); - isCountedK0SSecondCut = true; - } - } - isFilledhV0 = true; - - bool isCountedPiInclusive = false, isCountedPiFirstCut = false, isCountedPiSecondCut = false; - - // Loop over all primary pion candidates - for (const auto& track : fullTracks) { - if (!selectionPion(track)) - continue; - - TLorentzVector recPi; - recPi.SetXYZM(track.px(), track.py(), track.pz(), massPi); - - if (recPi.Rapidity() > 0.8) - continue; - if (!isCountedPiInclusive) { - PhipurHist.fill(HIST("h3PhipurPiInvMassInclusive"), multiplicity, recPi.Pt(), recPhi.M()); - isCountedPiInclusive = true; - } - if (std::abs(recPi.Rapidity() - recPhi.Rapidity()) > cfgFirstCutonDeltay) - continue; - if (!isCountedPiFirstCut) { - PhipurHist.fill(HIST("h3PhipurPiInvMassFirstCut"), multiplicity, recPi.Pt(), recPhi.M()); - isCountedPiFirstCut = true; - } - if (std::abs(recPi.Rapidity() - recPhi.Rapidity()) > cfgSecondCutonDeltay) - continue; - if (!isCountedPiSecondCut) { - PhipurHist.fill(HIST("h3PhipurPiInvMassSecondCut"), multiplicity, recPi.Pt(), recPhi.M()); - isCountedPiSecondCut = true; - } - } - } - } - } - - 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(); - eventHist.fill(HIST("hMultiplicityPercent"), multiplicity); - - int iBin = 0; - for (int i = 0; i < nMultBin; i++) { - if (multBin[i] < multiplicity && multiplicity <= multBin[i + 1]) { - iBin = i; - break; - } - } - - // 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; - - TLorentzVector recK0S; - recK0S.SetXYZM(v0.px(), v0.py(), v0.pz(), v0.mK0Short()); - if (recK0S.Rapidity() > 0.8) - continue; - - std::vector listrecPhi; - int countInclusive = 0, countLtFirstCut = 0, countLtSecondCut = 0; - - // Phi reconstruction - // Loop over positive candidates - for (auto track1 : posThisColl) { // loop over all selected tracks - if (!selectionTrackResonance(track1) || !selectionPIDKaon(track1)) - continue; // topological and PID selection - - auto track1ID = track1.globalIndex(); - - // Loop over all negative candidates - for (auto track2 : negThisColl) { - if (!selectionTrackResonance(track2) || !selectionPIDKaon(track2)) - continue; // topological and PID selection - - auto track2ID = track2.globalIndex(); - if (track2ID == track1ID) - continue; // condition to avoid double counting of pair - - TLorentzVector recPhi; - recPhi = recMother(track1, track2, massKa, massKa); - if (recPhi.Rapidity() > 0.8) - continue; - - listrecPhi.push_back(recPhi); - - if (lowmPhiInc->at(iBin) <= recPhi.M() && recPhi.M() <= upmPhiInc->at(iBin)) - countInclusive++; - if (std::abs(recK0S.Rapidity() - recPhi.Rapidity()) > cfgFirstCutonDeltay) - continue; - if (lowmPhiFCut->at(iBin) <= recPhi.M() && recPhi.M() <= upmPhiFCut->at(iBin)) - countLtFirstCut++; - if (std::abs(recK0S.Rapidity() - recPhi.Rapidity()) > cfgSecondCutonDeltay) - continue; - if (lowmPhiSCut->at(iBin) <= recPhi.M() && recPhi.M() <= upmPhiSCut->at(iBin)) - countLtSecondCut++; - } - } - - float weightInclusive = 1. / static_cast(countInclusive); - float weightLtFirstCut = 1. / static_cast(countLtFirstCut); - float weightLtSecondCut = 1. / static_cast(countLtSecondCut); - - switch (iBin) { - case 0: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 1: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 2: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 3: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 4: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 5: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 6: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 7: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 8: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 9: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - default: - break; - } - } - } - - 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(); - eventHist.fill(HIST("hMultiplicityPercent"), multiplicity); - - int iBin = 0; - for (int i = 0; i < nMultBin; i++) { - if (multBin[i] < multiplicity && multiplicity <= multBin[i + 1]) { - iBin = i; - break; - } - } - - // 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)) - continue; - - TLorentzVector recPi; - recPi.SetXYZM(track.px(), track.py(), track.pz(), massPi); - if (recPi.Rapidity() > 0.8) - continue; - - std::vector listrecPhi; - int countInclusive = 0, countLtFirstCut = 0, countLtSecondCut = 0; - - // Phi reconstruction - // Loop over positive candidates - for (auto track1 : posThisColl) { // loop over all selected tracks - if (!selectionTrackResonance(track1) || !selectionPIDKaon(track1)) - continue; // topological and PID selection - - auto track1ID = track1.globalIndex(); - - // Loop over all negative candidates - for (auto track2 : negThisColl) { - if (!selectionTrackResonance(track2) || !selectionPIDKaon(track2)) - continue; // topological and PID selection - - auto track2ID = track2.globalIndex(); - if (track2ID == track1ID) - continue; // condition to avoid double counting of pair - - TLorentzVector recPhi; - recPhi = recMother(track1, track2, massKa, massKa); - if (recPhi.Rapidity() > 0.8) - continue; - - listrecPhi.push_back(recPhi); - - if (lowmPhiInc->at(iBin) <= recPhi.M() && recPhi.M() <= upmPhiInc->at(iBin)) - countInclusive++; - if (std::abs(recPi.Rapidity() - recPhi.Rapidity()) > cfgFirstCutonDeltay) - continue; - if (lowmPhiFCut->at(iBin) <= recPhi.M() && recPhi.M() <= upmPhiFCut->at(iBin)) - countLtFirstCut++; - if (std::abs(recPi.Rapidity() - recPhi.Rapidity()) > cfgSecondCutonDeltay) - continue; - if (lowmPhiSCut->at(iBin) <= recPhi.M() && recPhi.M() <= upmPhiSCut->at(iBin)) - countLtSecondCut++; - } - } - - float nsigmaTPC, nsigmaTOF; - if (track.hasTPC()) - nsigmaTPC = track.tpcNSigmaPi(); - else - nsigmaTPC = -9.99; - if (track.hasTOF()) - nsigmaTOF = track.tofNSigmaPi(); - else - nsigmaTOF = -9.99; - - float weightInclusive = 1. / static_cast(countInclusive); - float weightLtFirstCut = 1. / static_cast(countLtFirstCut); - float weightLtSecondCut = 1. / static_cast(countLtSecondCut); - - switch (iBin) { - case 0: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 1: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 2: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 3: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 4: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 5: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 6: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 7: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 8: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 9: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - default: - break; - } - } - } - - PROCESS_SWITCH(phik0shortanalysis, processSEPhiPion, "Process Same Event for Phi-Pion Analysis", false); - - void processMEPhiK0S(soa::Filtered const& collisions, FullTracks const&, FullV0s const& V0s, V0DauTracks const&) - { - // Mixing the events with similar vertex z and multiplicity - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicity}, true}; - for (auto const& [collision1, collision2] : o2::soa::selfCombinations(binningOnPositions, cfgNoMixedEvents, -1, collisions, collisions)) { - if (!collision1.isInelGt0() || !collision2.isInelGt0()) - continue; - - float multiplicity = collision1.centFT0M(); - - int iBin = 0; - for (int i = 0; i < nMultBin; i++) { - if (multBin[i] < multiplicity && multiplicity <= multBin[i + 1]) { - iBin = i; - break; - } - } - - // Defining V0s from collision1 - auto V0ThisColl = V0s.sliceByCached(aod::v0::collisionId, collision1.globalIndex(), cache); - - // Defining positive and negative tracks for phi reconstruction from collision1 and collision2, respectively - auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); - auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - - for (const auto& v0 : V0ThisColl) { - const auto& posDaughterTrack = v0.posTrack_as(); - const auto& negDaughterTrack = v0.negTrack_as(); - - // Cut on V0 dynamic columns - if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) - continue; - - TLorentzVector recK0S; - recK0S.SetXYZM(v0.px(), v0.py(), v0.pz(), v0.mK0Short()); - if (recK0S.Rapidity() > 0.8) - continue; - - std::vector listrecPhi; - int countInclusive = 0, countLtFirstCut = 0, countLtSecondCut = 0; - - // Combinatorial background simulation - for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posThisColl, negThisColl))) { - if (!selectionTrackResonance(track1) || !selectionPIDKaon(track1) || !selectionTrackResonance(track2) || !selectionPIDKaon(track2)) - continue; // topological and PID selection - - TLorentzVector recPhi; - recPhi = recMother(track1, track2, massKa, massKa); - if (recPhi.Rapidity() > 0.8) - continue; - - listrecPhi.push_back(recPhi); - - countInclusive++; - if (std::abs(recK0S.Rapidity() - recPhi.Rapidity()) > cfgFirstCutonDeltay) - continue; - countLtFirstCut++; - if (std::abs(recK0S.Rapidity() - recPhi.Rapidity()) > cfgSecondCutonDeltay) - continue; - countLtSecondCut++; - } - - float weightInclusive = 1. / static_cast(countInclusive); - float weightLtFirstCut = 1. / static_cast(countLtFirstCut); - float weightLtSecondCut = 1. / static_cast(countLtSecondCut); - - switch (iBin) { - case 0: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 1: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 2: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 3: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 4: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 5: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 6: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 7: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 8: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 9: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - default: - break; - } - } - } - } - - PROCESS_SWITCH(phik0shortanalysis, processMEPhiK0S, "Process Mixed Event for Phi-K0S Analysis", false); - - void processMEPhiPion(soa::Filtered const& collisions, FullTracks const& fullTracks) - { - // Mixing the events with similar vertex z and multiplicity - BinningTypeVertexContributor binningOnPositions{{axisVertex, axisMultiplicity}, true}; - for (auto const& [collision1, collision2] : o2::soa::selfCombinations(binningOnPositions, cfgNoMixedEvents, -1, collisions, collisions)) { - if (!collision1.isInelGt0() || !collision2.isInelGt0()) - continue; - - float multiplicity = collision1.centFT0M(); - - int iBin = 0; - for (int i = 0; i < nMultBin; i++) { - if (multBin[i] < multiplicity && multiplicity <= multBin[i + 1]) { - iBin = i; - break; - } - } - - // Defining V0s from collision1 - auto trackThisColl = fullTracks.sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); - - // Defining positive and negative tracks for phi reconstruction from collision1 and collision2, respectively - auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); - auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); - - for (const auto& track : trackThisColl) { - - if (!selectionPion(track)) - continue; - - TLorentzVector recPi; - recPi.SetXYZM(track.px(), track.py(), track.pz(), massPi); - if (recPi.Rapidity() > 0.8) - continue; - - std::vector listrecPhi; - int countInclusive = 0, countLtFirstCut = 0, countLtSecondCut = 0; - - // Combinatorial background simulation - for (auto& [track1, track2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posThisColl, negThisColl))) { - if (!selectionTrackResonance(track1) || !selectionPIDKaon(track1) || !selectionTrackResonance(track2) || !selectionPIDKaon(track2)) - continue; // topological and PID selection - - TLorentzVector recPhi; - recPhi = recMother(track1, track2, massKa, massKa); - if (recPhi.Rapidity() > 0.8) - continue; - - listrecPhi.push_back(recPhi); - - countInclusive++; - if (std::abs(recPi.Rapidity() - recPhi.Rapidity()) > cfgFirstCutonDeltay) - continue; - countLtFirstCut++; - if (std::abs(recPi.Rapidity() - recPhi.Rapidity()) > cfgSecondCutonDeltay) - continue; - countLtSecondCut++; - } - - float nsigmaTPC, nsigmaTOF; - if (track.hasTPC()) - nsigmaTPC = track.tpcNSigmaPi(); - else - nsigmaTPC = -9.99; - if (track.hasTOF()) - nsigmaTOF = track.tofNSigmaPi(); - else - nsigmaTOF = -9.99; - - float weightInclusive = 1. / static_cast(countInclusive); - float weightLtFirstCut = 1. / static_cast(countLtFirstCut); - float weightLtSecondCut = 1. / static_cast(countLtSecondCut); - - switch (iBin) { - case 0: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 1: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 2: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 3: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 4: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 5: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 6: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 7: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 8: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 9: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - default: - break; - } - } - } - } - - PROCESS_SWITCH(phik0shortanalysis, processMEPhiPion, "Process Mixed Event for Phi-Pion Analysis", false); - - void processRecMCPhiK0S(SimCollisions::iterator const& collision, FullMCTracks const&, FullV0s const& V0s, V0DauMCTracks const&, MCCollisions const&, aod::McParticles const&) - { - if (!acceptEventQA(collision, true)) - return; - - float multiplicity = collision.centFT0M(); - eventHist.fill(HIST("hRecMCMultiplicityPercent"), multiplicity); - - int iBin = 0; - for (int i = 0; i < nMultBin; i++) { - if (multBin[i] < multiplicity && multiplicity <= multBin[i + 1]) { - iBin = i; - break; - } - } - - // 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) { - const auto& posDaughterTrack = v0.posTrack_as(); - const auto& negDaughterTrack = v0.negTrack_as(); - if (!posDaughterTrack.has_mcParticle() || !negDaughterTrack.has_mcParticle()) - continue; - - auto posMCDaughterTrack = posDaughterTrack.mcParticle_as(); - auto negMCDaughterTrack = negDaughterTrack.mcParticle_as(); - if (posMCDaughterTrack.pdgCode() != 211 || negMCDaughterTrack.pdgCode() != -211) - continue; - if (!posMCDaughterTrack.has_mothers() || !negMCDaughterTrack.has_mothers()) - continue; - - int pdgParentv0 = 0; - bool isPhysPrim = false; - for (const auto& particleMotherOfNeg : negMCDaughterTrack.mothers_as()) { - for (const auto& particleMotherOfPos : posMCDaughterTrack.mothers_as()) { - if (particleMotherOfNeg == particleMotherOfPos) { - pdgParentv0 = particleMotherOfNeg.pdgCode(); - isPhysPrim = particleMotherOfNeg.isPhysicalPrimary(); - } - } - } - if (pdgParentv0 != 310 || !isPhysPrim) - continue; - - if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) - continue; - - TLorentzVector recK0S; - recK0S.SetXYZM(v0.px(), v0.py(), v0.pz(), v0.mK0Short()); - if (recK0S.Rapidity() > 0.8) - continue; - - std::vector listrecPhi; - int countInclusive = 0, countLtFirstCut = 0, countLtSecondCut = 0; - - // Phi reconstruction - for (auto track1 : posThisColl) { // loop over all selected tracks - if (!selectionTrackResonance(track1) || !selectionPIDKaon(track1)) - continue; // topological and PID selection - - auto track1ID = track1.globalIndex(); - - if (!track1.has_mcParticle()) - continue; - - for (auto track2 : negThisColl) { - if (!selectionTrackResonance(track2) || !selectionPIDKaon(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 MCtrack1 = track1.mcParticle_as(); - auto MCtrack2 = track2.mcParticle_as(); - if (MCtrack1.pdgCode() != 321 || MCtrack2.pdgCode() != -321) - continue; - if (!MCtrack1.has_mothers() || !MCtrack2.has_mothers()) - continue; - if (!MCtrack1.isPhysicalPrimary() || !MCtrack2.isPhysicalPrimary()) - continue; - - int pdgParentPhi = 0; - for (const auto& MotherOfMCtrack1 : MCtrack1.mothers_as()) { - for (const auto& MotherOfMCtrack2 : MCtrack2.mothers_as()) { - if (MotherOfMCtrack1 == MotherOfMCtrack2) { - pdgParentPhi = MotherOfMCtrack1.pdgCode(); - } - } - } - - if (pdgParentPhi != 333) - continue; - - TLorentzVector recPhi; - recPhi = recMother(track1, track2, massKa, massKa); - if (recPhi.Rapidity() > 0.8) - continue; - - listrecPhi.push_back(recPhi); - - countInclusive++; - if (std::abs(recK0S.Rapidity() - recPhi.Rapidity()) > cfgFirstCutonDeltay) - continue; - countLtFirstCut++; - if (std::abs(recK0S.Rapidity() - recPhi.Rapidity()) > cfgSecondCutonDeltay) - continue; - countLtSecondCut++; - } - } - - float weightInclusive = 1. / static_cast(countInclusive); - float weightLtFirstCut = 1. / static_cast(countLtFirstCut); - float weightLtSecondCut = 1. / static_cast(countLtSecondCut); - - switch (iBin) { - case 0: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 1: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 2: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 3: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 4: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 5: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 6: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 7: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 8: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 9: { - fillInvMass2D(recK0S, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - default: - break; - } - } - } - - PROCESS_SWITCH(phik0shortanalysis, processRecMCPhiK0S, "Process RecMC for Phi-K0S Analysis", false); - - void processRecMCPhiPion(SimCollisions::iterator const& collision, FullMCTracks const& fullMCTracks, MCCollisions const&, aod::McParticles const&) - { - if (!acceptEventQA(collision, true)) - return; - - float multiplicity = collision.centFT0M(); - eventHist.fill(HIST("hRecMCMultiplicityPercent"), multiplicity); - - int iBin = 0; - for (int i = 0; i < nMultBin; i++) { - if (multBin[i] < multiplicity && multiplicity <= multBin[i + 1]) { - iBin = i; - break; - } - } - - // 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 (!track.has_mcParticle()) - continue; - - auto MCtrack = track.mcParticle_as(); - if (std::abs(MCtrack.pdgCode()) != 211 || !MCtrack.isPhysicalPrimary()) - continue; - - // Pion selection - if (!selectionPion(track)) - continue; - - TLorentzVector recPi; - recPi.SetXYZM(track.px(), track.py(), track.pz(), massPi); - if (recPi.Rapidity() > 0.8) - continue; - - std::vector listrecPhi; - int countInclusive = 0, countLtFirstCut = 0, countLtSecondCut = 0; - - // Phi reconstruction - for (auto track1 : posThisColl) { // loop over all selected tracks - if (!selectionTrackResonance(track1) || !selectionPIDKaon(track1)) - continue; // topological and PID selection - - auto track1ID = track1.globalIndex(); - - if (!track1.has_mcParticle()) - continue; - - for (auto track2 : negThisColl) { - if (!selectionTrackResonance(track2) || !selectionPIDKaon(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 MCtrack1 = track1.mcParticle_as(); - auto MCtrack2 = track2.mcParticle_as(); - if (MCtrack1.pdgCode() != 321 || MCtrack2.pdgCode() != -321) - continue; - if (!MCtrack1.has_mothers() || !MCtrack2.has_mothers()) - continue; - if (!MCtrack1.isPhysicalPrimary() || !MCtrack2.isPhysicalPrimary()) - continue; - - int pdgParentPhi = 0; - for (const auto& MotherOfMCtrack1 : MCtrack1.mothers_as()) { - for (const auto& MotherOfMCtrack2 : MCtrack2.mothers_as()) { - if (MotherOfMCtrack1 == MotherOfMCtrack2) { - pdgParentPhi = MotherOfMCtrack1.pdgCode(); - } - } - } - - if (pdgParentPhi != 333) - continue; - - TLorentzVector recPhi; - recPhi = recMother(track1, track2, massKa, massKa); - if (recPhi.Rapidity() > 0.8) - continue; - - listrecPhi.push_back(recPhi); - - countInclusive++; - if (std::abs(recPi.Rapidity() - recPhi.Rapidity()) > cfgFirstCutonDeltay) - continue; - countLtFirstCut++; - if (std::abs(recPi.Rapidity() - recPhi.Rapidity()) > cfgSecondCutonDeltay) - continue; - countLtSecondCut++; - } - } - - float nsigmaTPC, nsigmaTOF; - if (track.hasTPC()) - nsigmaTPC = track.tpcNSigmaPi(); - else - nsigmaTPC = -9.99; - if (track.hasTOF()) - nsigmaTOF = track.tofNSigmaPi(); - else - nsigmaTOF = -9.99; - - float weightInclusive = 1. / static_cast(countInclusive); - float weightLtFirstCut = 1. / static_cast(countLtFirstCut); - float weightLtSecondCut = 1. / static_cast(countLtSecondCut); - - switch (iBin) { - case 0: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 1: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 2: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 3: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 4: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 5: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 6: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 7: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 8: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - case 9: { - fillInvMassNSigma(recPi, nsigmaTPC, nsigmaTOF, listrecPhi, multiplicity, weightInclusive, weightLtFirstCut, weightLtSecondCut); - break; - } - default: - break; - } - } - } - - PROCESS_SWITCH(phik0shortanalysis, processRecMCPhiPion, "Process RecMC for Phi-Pion Analysis", false); - - void processGenMCPhiK0S(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 - - if (collisions.size() < 1) - return; - - bool isAssocColl = false; - for (auto collision : collisions) { - if (acceptEventQA(collision, false)) { - isAssocColl = true; - break; - } - } - if (!isAssocColl) - return; - MCeventHist.fill(HIST("hGenMCEventSelection"), 3); // with at least a rec collision - - float multiplicity = mcCollision.centFT0M(); - eventHist.fill(HIST("hGenMCMultiplicityPercent"), multiplicity); - - int iBin = 0; - for (int i = 0; i < nMultBin; i++) { - if (multBin[i] < multiplicity && multiplicity <= multBin[i + 1]) { - iBin = i; - break; - } - } - int iCenter = iBin - 1; - - bool isCountedPhiInclusive = false, isCountedPhiFirstCut = false, isCountedPhiSecondCut = false; - - for (auto mcParticle1 : mcParticles) { - if (mcParticle1.pdgCode() != 310) - continue; - if (mcParticle1.y() > 0.8) - continue; - - for (auto mcParticle2 : mcParticles) { - if (mcParticle2.pdgCode() != 333) - continue; - auto kDaughters = mcParticle2.daughters_as(); - if (kDaughters.size() != 2) - continue; - bool isPosKaon = false, isNegKaon = false; - for (auto kDaughter : kDaughters) { - if (kDaughter.pdgCode() == 321) - isPosKaon = true; - if (kDaughter.pdgCode() == -321) - isNegKaon = true; - } - if (!isPosKaon || !isNegKaon) - continue; - if (mcParticle2.y() > 0.8) - continue; - - if (!isCountedPhiInclusive) { - MCPhiK0SHist.fill(HIST("h1PhiK0SGenMCInclusive"), iCenter); - isCountedPhiInclusive = true; - } - if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgFirstCutonDeltay) - continue; - if (!isCountedPhiFirstCut) { - MCPhiK0SHist.fill(HIST("h1PhiK0SGenMCFirstCut"), iCenter); - isCountedPhiFirstCut = true; - } - if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgSecondCutonDeltay) - continue; - if (!isCountedPhiSecondCut) { - MCPhiK0SHist.fill(HIST("h1PhiK0SGenMCSecondCut"), iCenter); - isCountedPhiSecondCut = true; - } - } - } - } - - 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) - { - 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 - - if (collisions.size() < 1) - return; - - bool isAssocColl = false; - for (auto collision : collisions) { - if (acceptEventQA(collision, false)) { - isAssocColl = true; - break; - } - } - if (!isAssocColl) - return; - MCeventHist.fill(HIST("hGenMCEventSelection"), 3); // with at least a rec collision - - float multiplicity = mcCollision.centFT0M(); - eventHist.fill(HIST("hGenMCMultiplicityPercent"), multiplicity); - - int iBin = 0; - for (int i = 0; i < nMultBin; i++) { - if (multBin[i] < multiplicity && multiplicity <= multBin[i + 1]) { - iBin = i; - break; - } - } - int iCenter = iBin - 1; - - bool isCountedPhiInclusive = false, isCountedPhiFirstCut = false, isCountedPhiSecondCut = false; - - for (auto mcParticle1 : mcParticles) { - if (std::abs(mcParticle1.pdgCode()) != 211) - continue; - if (mcParticle1.y() > 0.8) - continue; - - for (auto mcParticle2 : mcParticles) { - if (mcParticle2.pdgCode() != 333) - continue; - auto kDaughters = mcParticle2.daughters_as(); - if (kDaughters.size() != 2) - continue; - bool isPosKaon = false, isNegKaon = false; - for (auto kDaughter : kDaughters) { - if (kDaughter.pdgCode() == 321) - isPosKaon = true; - if (kDaughter.pdgCode() == -321) - isNegKaon = true; - } - if (!isPosKaon || !isNegKaon) - continue; - if (mcParticle2.y() > 0.8) - continue; - - if (!isCountedPhiInclusive) { - MCPhiPionHist.fill(HIST("h1PhiPionGenMCInclusive"), iCenter); - isCountedPhiInclusive = true; - } - if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgFirstCutonDeltay) - continue; - if (!isCountedPhiFirstCut) { - MCPhiPionHist.fill(HIST("h1PhiPionGenMCFirstCut"), iCenter); - isCountedPhiFirstCut = true; - } - if (std::abs(mcParticle1.y() - mcParticle2.y()) > cfgSecondCutonDeltay) - continue; - if (!isCountedPhiSecondCut) { - MCPhiPionHist.fill(HIST("h1PhiPionGenMCSecondCut"), iCenter); - isCountedPhiSecondCut = true; - } - } - } - } - - PROCESS_SWITCH(phik0shortanalysis, processGenMCPhiPion, "Process GenMC for Phi-Pion Analysis", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"lf-phik0shortanalysis"})}; -} diff --git a/PWGLF/Tasks/Strangeness/phik0shortanalysis.cxx b/PWGLF/Tasks/Strangeness/phik0shortanalysis.cxx new file mode 100644 index 00000000000..cacee6ced5d --- /dev/null +++ b/PWGLF/Tasks/Strangeness/phik0shortanalysis.cxx @@ -0,0 +1,3488 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/Core/TableHelper.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#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; +using namespace o2::aod::track; + +enum { + kGlobalplusITSonly = 0, + kGlobalonly, + kITSonly +}; + +enum { + kSpAll = 0, + kSpPion, + kSpKaon, + kSpProton, + kSpOther, + kSpStrangeDecay, + kSpNotPrimary +}; + +enum { + kNoGenpTVar = 0, + kGenpTup, + kGenpTdown +}; + +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}; + HistogramRegistry mePhiK0SHist{"mePhiK0SHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry mePhiPionHist{"mePhiPionHist", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + struct : ConfigurableGroup { + Configurable isData{"isData", true, "Data"}; + Configurable isMC{"isMC", true, "MC"}; + Configurable isClosure{"isClosure", true, "MC Closure"}; + + Configurable isDataNewProc{"isDataNewProc", true, "New procedure for Data"}; + Configurable isMCNewProc{"isMCNewProc", true, "New procedure for MC"}; + Configurable isClosureNewProc{"isClosureNewProc", true, "New procedure for MC Closure"}; + Configurable isMENewProc{"isMENewProc", true, "New procedure for ME"}; + } analysisModeConfigs; + + // 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 cfgMinAbsCharge{"cfgMinAbsCharge", 3.0f, "Cut on absolute charge"}; + Configurable cfgGlobalWoDCATrack{"cfgGlobalWoDCATrack", true, "Global track selection without DCA"}; + Configurable cfgPVContributor{"cfgPVContributor", true, "PV contributor track selection"}; + Configurable cMinChargedParticlePtcut{"cMinChargedParticlePtcut", 0.1f, "Track minimum pt cut"}; + Configurable cMinKaonPtcut{"cMinKaonPtcut", 0.15f, "Track minimum pt cut"}; + Configurable etaMax{"etaMax", 0.8f, "eta max"}; + Configurable pTToUseTOF{"pTToUseTOF", 0.5f, "pT above which use TOF"}; + 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.2f, "Track minimum pt cut"}; + Configurable minTPCnClsFound{"minTPCnClsFound", 70, "min number of found TPC clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70, "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"}; + + Configurable applyExtraPhiCuts{"applyExtraPhiCuts", false, "Enable extra phi cut"}; + Configurable> extraPhiCuts{"extraPhiCuts", {3.07666f, 3.12661f, 0.03f, 6.253f}, "Extra phi cuts"}; + } 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"}; + + // Configurables on phi selection + struct : ConfigurableGroup { + 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"}; + + Configurable minPhiPt{"minPhiPt", 0.4f, "Minimum pT for Phi"}; + Configurable maxPhiPt{"maxPhiPt", 10.0f, "Maximum pT for Phi"}; + } phiConfigs; + + // 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"}; + + Configurable lowMK0S{"lowMK0S", 0.48f, "Lower limit on K0Short mass"}; + Configurable upMK0S{"upMK0S", 0.52f, "Upper limit on K0Short mass"}; + } v0Configs; + + // 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.2, 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 + struct : ConfigurableGroup { + Configurable nBinsY{"nBinsY", 20, "Number of bins in y axis"}; + Configurable nBinsDeltaY{"nBinsDeltaY", 20, "Number of bins in deltay axis"}; + Configurable cfgYAcceptance{"cfgYAcceptance", 0.5f, "Rapidity acceptance"}; + 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", {0.5f}, "Rapidity acceptance bins"}; + } deltaYConfigs; + + // 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 applyEfficiency{"applyEfficiency", false, "Use efficiency for filling histograms"}; + + // Configurables for dN/deta with phi computation + Configurable filterOnGenPhi{"filterOnGenPhi", 1, "Filter on Gen Phi (0: K+K- pair like Phi, 1: proper Phi)"}; + Configurable filterOnRecoPhi{"filterOnRecoPhi", 1, "Filter on Reco Phi (0: without PDG, 1: with PDG)"}; + Configurable fillMcPartsForAllReco{"fillMcPartsForAllReco", false, "Fill MC particles for all associated reco collisions"}; + + // Configurable for event mixing + Configurable cfgNoMixedEvents{"cfgNoMixedEvents", 5, "Number of mixed events per event"}; + + // Configurable for CCDB + Configurable useCCDB{"useCCDB", false, "Use CCDB for corrections"}; + 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"}; + Configurable ccdbEfficiencyPath{"ccdbEfficiencyPath", "Users/s/scannito/Efficiencies", "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 track flags + 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; + + // 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 filters on tracks + 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) && + ncheckbit(aod::track::trackCutFlag, TrackSelectionDCA) && + ncheckbit(aod::track::trackCutFlag, TrackSelectionFlags::kInAcceptanceTracks); + + // 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 FilteredTracks = soa::Filtered; + using FullMCTracks = soa::Join; + using FilteredMCTracks = soa::Filtered; + + using V0DauTracks = soa::Join; + using V0DauMCTracks = soa::Join; + + // Defining binning policy and axis for mixed event + ConfigurableAxis axisVertexMixing{"axisVertexMixing", {20, -10, 10}, "Z vertex axis binning for mixing"}; + ConfigurableAxis axisCentralityMixing{"axisCentralityMixing", {20, 0, 100}, "Multiplicity percentil binning for mixing"}; + + using BinningTypeVertexCent = ColumnBinningPolicy; + BinningTypeVertexCent binningOnVertexAndCent{{axisVertexMixing, axisCentralityMixing}, true}; + + // Cache for manual slicing + SliceCache cache; + + // Preslice for manual slicing + struct : PresliceGroup { + Preslice trackPerCollision = aod::track::collisionId; + Preslice mcPartPerMCCollision = aod::mcparticle::mcCollisionId; + Preslice v0PerCollision = aod::v0::collisionId; + } preslices; + + // Positive and negative tracks partitions + Partition posTracks = aod::track::signed1Pt > trackConfigs.cfgCutCharge; + Partition negTracks = aod::track::signed1Pt < trackConfigs.cfgCutCharge; + + Partition posFiltTracks = aod::track::signed1Pt > trackConfigs.cfgCutCharge; + Partition negFiltTracks = aod::track::signed1Pt < trackConfigs.cfgCutCharge; + + Partition posMCTracks = aod::track::signed1Pt > trackConfigs.cfgCutCharge; + Partition negMCTracks = aod::track::signed1Pt < trackConfigs.cfgCutCharge; + + Partition posFiltMCTracks = aod::track::signed1Pt > trackConfigs.cfgCutCharge; + Partition negFiltMCTracks = 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)); + + // Efficiecy maps + TH3F* effMapPhi; + TH3F* effMapK0S; + TH3F* effMapPionTPC; + TH3F* effMapPionTPCTOF; + + void init(InitContext&) + { + // Axes + AxisSpec massPhiAxis = {200, 0.9f, 1.2f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec sigmassPhiAxis = {phiConfigs.nBinsMPhi, phiConfigs.lowMPhi, phiConfigs.upMPhi, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec massK0SAxis = {200, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec nSigmaPiAxis = {100, -10.0f, 10.0f, "N#sigma #pi"}; + AxisSpec vertexZAxis = {100, -cutZVertex, cutZVertex, "vrtx_{Z} [cm]"}; + AxisSpec etaAxis = {16, -trackConfigs.etaMax, trackConfigs.etaMax, "#eta"}; + AxisSpec yAxis = {deltaYConfigs.nBinsY, -deltaYConfigs.cfgYAcceptance, deltaYConfigs.cfgYAcceptance, "#it{y}"}; + AxisSpec deltayAxis = {deltaYConfigs.nBinsDeltaY, -1.0f, 1.0f, "#Delta#it{y}"}; + AxisSpec deltaphiAxis = {72, -o2::constants::math::PIHalf, o2::constants::math::PIHalf * 3, "#Delta#varphi"}; + AxisSpec phiAxis = {629, 0, o2::constants::math::TwoPI, "#phi"}; + AxisSpec multAxis = {120, 0.0f, 120.0f, "centFT0M"}; + AxisSpec binnedmultAxis{(std::vector)binsMult, "centFT0M"}; + AxisSpec pTPhiAxis = {120, 0.0f, 12.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec binnedpTPhiAxis{(std::vector)binspTPhi, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pTK0SAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec binnedpTK0SAxis{(std::vector)binspTK0S, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pTPiAxis = {50, 0.0f, 5.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}); + dataEventHist.add("h2VertexZvsMult", "Vertex Z vs Multiplicity Percentile", kTH2F, {vertexZAxis, binnedmultAxis}); + + // Eta distribution for dN/deta values estimation in Data + dataEventHist.add("h5EtaDistribution", "Eta vs multiplicity in Data", kTHnSparseF, {vertexZAxis, binnedmultAxis, etaAxis, phiAxis, {3, -0.5f, 2.5f}}); + + // 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("hRecoMCVertexZ", "hRecoMCVertexZ", kTH1F, {vertexZAxis}); + mcEventHist.add("hUnbinnedRecoMCMultiplicityPercent", "RecoMC Multiplicity Percentile", kTH1F, {multAxis}); + mcEventHist.add("hRecoMCMultiplicityPercent", "RecoMC Multiplicity Percentile", kTH1F, {binnedmultAxis}); + mcEventHist.add("hRecoMCMultiplicityPercentWithPhi", "RecoMC Multiplicity Percentile in Events with a Phi Candidate", kTH1F, {binnedmultAxis}); + mcEventHist.add("h2RecoMCVertexZvsMult", "RecoMC Vertex Z vs Multiplicity Percentile", kTH2F, {vertexZAxis, binnedmultAxis}); + mcEventHist.add("hSplitVertexZ", "Split in z-vtx", kTH1F, {{100, -5.0f, 5.0f}}); + + mcEventHist.add("hGenMCVertexZ", "hGenMCVertexZ", kTH1F, {vertexZAxis}); + mcEventHist.add("hGenMCMultiplicityPercent", "GenMC Multiplicity Percentile", kTH1F, {binnedmultAxis}); + mcEventHist.add("hGenMCAssocRecoMultiplicityPercent", "GenMC AssocReco Multiplicity Percentile", kTH1F, {binnedmultAxis}); + mcEventHist.add("h2GenMCAssocRecoVertexZvsMult", "GenMC AssocReco Vertex Z vs Multiplicity Percentile", kTH2F, {vertexZAxis, binnedmultAxis}); + mcEventHist.add("hGenMCRecoMultiplicityPercent", "GenMCReco Multiplicity Percentile", kTH1F, {binnedmultAxis}); + + // Eta distribution for dN/deta values estimation in MC + mcEventHist.add("h6RecoMCEtaDistribution", "Eta vs multiplicity in MCReco", kTHnSparseF, {vertexZAxis, binnedmultAxis, etaAxis, phiAxis, {6, -0.5f, 5.5f}, {3, -0.5f, 2.5f}}); + + mcEventHist.add("h5GenMCEtaDistribution", "Eta vs multiplicity in MCGen", kTHnSparseF, {binnedmultAxis, etaAxis, phiAxis, {6, -0.5f, 5.5f}, {3, -0.5f, 2.5f}}); + mcEventHist.add("h6GenMCAssocRecoEtaDistribution", "Eta vs multiplicity in MCGen Assoc Reco", kTHnSparseF, {vertexZAxis, binnedmultAxis, etaAxis, phiAxis, {6, -0.5f, 5.5f}, {3, -0.5f, 2.5f}}); + mcEventHist.add("h6GenMCAllAssocRecoEtaDistribution", "Eta vs multiplicity in MCGen Reco", kTHnSparseF, {vertexZAxis, binnedmultAxis, etaAxis, phiAxis, {6, -0.5f, 5.5f}, {3, -0.5f, 2.5f}}); + + // 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}}); + + if (analysisModeConfigs.isData) { + // 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(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + dataPhiHist.get(HIST("h4PhipurK0SData"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + dataPhiHist.get(HIST("h4PhipurK0SData"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.cfgDeltaYAcceptanceBins->at(i))); + } + + dataPhiHist.add("h4PhipurPiData", "Invariant mass of Phi for Purity (Pi) in Data", kTHnSparseF, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + dataPhiHist.get(HIST("h4PhipurPiData"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + dataPhiHist.get(HIST("h4PhipurPiData"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.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)"}}); + + if (analysisModeConfigs.isClosure) { + // 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(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + closureMCPhiHist.get(HIST("h4PhipurK0SMCClosure"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + closureMCPhiHist.get(HIST("h4PhipurK0SMCClosure"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.cfgDeltaYAcceptanceBins->at(i))); + } + + closureMCPhiHist.add("h4PhipurPiMCClosure", "Invariant mass of Phi for Purity (Pi) in MCClosure", kTHnSparseF, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + closureMCPhiHist.get(HIST("h4PhipurPiMCClosure"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + closureMCPhiHist.get(HIST("h4PhipurPiMCClosure"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.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}}); + + if (analysisModeConfigs.isData) { + // 2D mass of Phi and K0S for Data + dataPhiK0SHist.add("h5PhiK0SData", "2D Invariant mass of Phi and K0Short for Data", kTHnSparseF, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + dataPhiK0SHist.get(HIST("h5PhiK0SData"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.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}); + + if (analysisModeConfigs.isMC) { + // RecMC K0S coupled to Phi + mcPhiK0SHist.add("h4PhiK0SMCReco", "K0S coupled to Phi in MCReco", kTHnSparseF, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTK0SAxis, massK0SAxis}); + mcPhiK0SHist.get(HIST("h4PhiK0SMCReco"))->GetAxis(0)->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiK0SHist.get(HIST("h4PhiK0SMCReco"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.cfgDeltaYAcceptanceBins->at(i))); + } + + // GenMC K0S coupled to Phi + mcPhiK0SHist.add("h3PhiK0SMCGen", "K0S coupled toPhi in MCGen", kTH3F, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTK0SAxis}); + mcPhiK0SHist.get(HIST("h3PhiK0SMCGen"))->GetXaxis()->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiK0SHist.get(HIST("h3PhiK0SMCGen"))->GetXaxis()->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.cfgDeltaYAcceptanceBins->at(i))); + } + + mcPhiK0SHist.add("h3PhiK0SMCGenAssocReco", "K0S coupled toPhi in MCGen Associated MCReco Collision", kTH3F, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTK0SAxis}); + mcPhiK0SHist.get(HIST("h3PhiK0SMCGenAssocReco"))->GetXaxis()->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiK0SHist.get(HIST("h3PhiK0SMCGenAssocReco"))->GetXaxis()->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.cfgDeltaYAcceptanceBins->at(i))); + } + } + + if (analysisModeConfigs.isClosure) { + // 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(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + closureMCPhiK0SHist.get(HIST("h5PhiK0SMCClosure"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.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}); + } + + if (analysisModeConfigs.isData) { + // 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(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + dataPhiPionHist.get(HIST("h6PhiPiData"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.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)"}}); + + if (analysisModeConfigs.isMC) { + // RecMC Pion coupled to Phi with TPC + mcPhiPionHist.add("h4PhiPiTPCMCReco", "Pion coupled to Phi in MCReco (TPC)", kTHnSparseF, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiPionHist.get(HIST("h4PhiPiTPCMCReco"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.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(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiPionHist.get(HIST("h5PhiPiTPCTOFMCReco"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.cfgDeltaYAcceptanceBins->at(i))); + } + + mcPhiPionHist.add("h3PhiPiMCGen", "Pion coupled to Phi in MCGen", kTH3F, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPiAxis}); + mcPhiPionHist.get(HIST("h3PhiPiMCGen"))->GetXaxis()->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiPionHist.get(HIST("h3PhiPiMCGen"))->GetXaxis()->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.cfgDeltaYAcceptanceBins->at(i))); + } + + mcPhiPionHist.add("h3PhiPiMCGenAssocReco", "Pion coupled to Phi in MCGen Associated Reco Collision", kTH3F, {{static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1.0f - 0.5f)}, binnedmultAxis, binnedpTPiAxis}); + mcPhiPionHist.get(HIST("h3PhiPiMCGenAssocReco"))->GetXaxis()->SetBinLabel(1, "Inclusive"); + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + mcPhiPionHist.get(HIST("h3PhiPiMCGenAssocReco"))->GetXaxis()->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.cfgDeltaYAcceptanceBins->at(i))); + } + } + + if (analysisModeConfigs.isClosure) { + // 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(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1), -0.5f, static_cast(deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + closureMCPhiPionHist.get(HIST("h6PhiPiMCClosure"))->GetAxis(0)->SetBinLabel(i + 2, Form("|Delta#it{y}| < %.1f", deltaYConfigs.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}}); + } + + if (analysisModeConfigs.isMC) { + // 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}); + } + + if (analysisModeConfigs.isDataNewProc) { + // Histograms for new analysis procedure (to be finalized and renamed deleting other histograms) + dataPhiHist.add("h3PhiDataNewProc", "Invariant mass of Phi in Data", kTH3F, {binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + dataPhiK0SHist.add("h5PhiK0SDataNewProc", "2D Invariant mass of Phi and K0Short in Data", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTK0SAxis, massK0SAxis, massPhiAxis}); + dataPhiPionHist.add("h5PhiPiTPCDataNewProc", "Phi Invariant mass vs Pion nSigma TPC in Data", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTPiAxis, nSigmaPiAxis, massPhiAxis}); + dataPhiPionHist.add("h5PhiPiTOFDataNewProc", "Phi Invariant mass vs Pion nSigma TOF in Data", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTPiAxis, nSigmaPiAxis, massPhiAxis}); + + dataPhiK0SHist.add("h5PhiK0SData2PartCorr", "Deltay vs deltaphi for Phi and K0Short in Data", kTHnSparseF, {binnedmultAxis, binnedpTPhiAxis, binnedpTK0SAxis, deltayAxis, deltaphiAxis}); + dataPhiPionHist.add("h5PhiPiData2PartCorr", "Deltay vs deltaphi for Phi and Pion in Data", kTHnSparseF, {binnedmultAxis, binnedpTPhiAxis, binnedpTPiAxis, deltayAxis, deltaphiAxis}); + } + + if (analysisModeConfigs.isClosureNewProc) { + closureMCPhiHist.add("h3PhiMCClosureNewProc", "Invariant mass of Phi in MC Closure test", kTH3F, {binnedmultAxis, binnedpTPhiAxis, massPhiAxis}); + closureMCPhiK0SHist.add("h5PhiK0SMCClosureNewProc", "2D Invariant mass of Phi and K0Short in MC Closure Test", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTK0SAxis, massK0SAxis, massPhiAxis}); + closureMCPhiPionHist.add("h5PhiPiTPCMCClosureNewProc", "Phi Invariant mass vs Pion nSigma TPC in MC Closure Test", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTPiAxis, nSigmaPiAxis, massPhiAxis}); + closureMCPhiPionHist.add("h5PhiPiTOFMCClosureNewProc", "Phi Invariant mass vs Pion nSigma TOF in MC Closure Test", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTPiAxis, nSigmaPiAxis, massPhiAxis}); + } + + if (analysisModeConfigs.isMENewProc) { + mePhiK0SHist.add("h5PhiK0SMENewProc", "2D Invariant mass of Phi and K0Short in Mixed Event", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTK0SAxis, massK0SAxis, massPhiAxis}); + mePhiPionHist.add("h5PhiPiTPCMENewProc", "Phi Invariant mass vs Pion nSigma TPC in Mixed Event", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTPiAxis, nSigmaPiAxis, massPhiAxis}); + mePhiPionHist.add("h5PhiPiTOFMENewProc", "Phi Invariant mass vs Pion nSigma TOF in Mixed Event", kTHnSparseF, {deltayAxis, binnedmultAxis, binnedpTPiAxis, nSigmaPiAxis, massPhiAxis}); + } + + if (analysisModeConfigs.isMCNewProc) { + mcPhiHist.add("h4PhiMCRecoNewProc", "Phi in MCReco", kTHnSparseF, {vertexZAxis, binnedmultAxis, pTPhiAxis, yAxis}); + mcK0SHist.add("h4K0SMCRecoNewProc", "K0S in MCReco", kTHnSparseF, {vertexZAxis, binnedmultAxis, pTK0SAxis, yAxis}); + mcPionHist.add("h4PiMCRecoNewProc", "Pion in MCReco", kTHnSparseF, {vertexZAxis, binnedmultAxis, pTPiAxis, yAxis}); + mcPionHist.add("h4PiMCReco2NewProc", "Pion in MCReco", kTHnSparseF, {vertexZAxis, binnedmultAxis, pTPiAxis, yAxis}); + + mcPhiHist.add("h3PhiMCGenNewProc", "Phi in MCGen", kTH3F, {binnedmultAxis, pTPhiAxis, yAxis}); + mcK0SHist.add("h3K0SMCGenNewProc", "K0S in MCGen", kTH3F, {binnedmultAxis, pTK0SAxis, yAxis}); + mcPionHist.add("h3PiMCGenNewProc", "Pion in MCGen", kTH3F, {binnedmultAxis, pTPiAxis, yAxis}); + + mcPhiHist.add("h4PhiMCGenAssocRecoNewProc", "Phi in MCGen Associated MCReco", kTHnSparseF, {vertexZAxis, binnedmultAxis, pTPhiAxis, yAxis}); + mcK0SHist.add("h4K0SMCGenAssocRecoNewProc", "K0S in MCGen Associated MCReco", kTHnSparseF, {vertexZAxis, binnedmultAxis, pTK0SAxis, yAxis}); + mcPionHist.add("h4PiMCGenAssocRecoNewProc", "Pion in MCGen Associated MCReco", kTHnSparseF, {vertexZAxis, binnedmultAxis, pTPiAxis, yAxis}); + } + + // Initialize CCDB only if purity or efficiencies are requested in the task + if (useCCDB) { + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + if (fillMethodSingleWeight) + getPhiPurityFunctionsFromCCDB(); + + if (applyEfficiency) { + getEfficiencyMapsFromCCDB(); + } else { + effMapPhi = nullptr; + effMapK0S = nullptr; + effMapPionTPC = nullptr; + effMapPionTPCTOF = nullptr; + } + } + } + + // 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("hRecoMCVertexZ"), 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 doQA) + { + 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 (doQA) { + 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 (doQA) { + 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() < trackConfigs.pTToUseTOF && std::abs(track.tpcNSigmaKa()) < trackConfigs.nSigmaCutTPCKa) + return true; + if (track.pt() >= trackConfigs.pTToUseTOF && 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 doQA) + { + if (!track.isGlobalTrackWoDCA()) + return false; + + if (track.itsNCls() < trackConfigs.minITSnCls) + return false; + if (track.tpcNClsFound() < trackConfigs.minTPCnClsFound) + return false; + + if (track.pt() < trackConfigs.cMinPionPtcut) + return false; + + if constexpr (isTOFChecked) { + if (track.pt() >= trackConfigs.pTToUseTOF && !track.hasTOF()) + return false; + } + + if (doQA) { + 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 (doQA) { + 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; + } + + template + bool eventHasRecoPhi(const T1& posTracks, const T2& negTracks) + { + int nPhi = 0; + + for (const auto& track1 : posTracks) { + if (!selectionTrackResonance(track1, false) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + for (const auto& track2 : negTracks) { + 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() < phiConfigs.minPhiPt) + continue; + if (recPhi.M() < phiConfigs.lowMPhi || recPhi.M() > phiConfigs.upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.cfgYAcceptance) + continue; + + nPhi++; + } + } + + if (nPhi > 0) + return true; + return false; + } + + template + bool eventHasRecoPhiWPDG(const T1& posTracks, const T2& negTracks, const T3& mcParticles) + { + int nPhi = 0; + + for (const auto& track1 : posTracks) { + if (!selectionTrackResonance(track1, false) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + if (!track1.has_mcParticle()) + continue; + auto mcTrack1 = mcParticles.rawIteratorAt(track1.mcParticleId()); + if (mcTrack1.pdgCode() != PDG_t::kKPlus || !mcTrack1.isPhysicalPrimary()) + continue; + + for (const auto& track2 : negTracks) { + 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 = mcParticles.rawIteratorAt(track2.mcParticleId()); + if (mcTrack2.pdgCode() != PDG_t::kKMinus || !mcTrack2.isPhysicalPrimary()) + continue; + + const auto mcTrack1MotherIndexes = mcTrack1.mothersIds(); + const auto mcTrack2MotherIndexes = mcTrack2.mothersIds(); + + float pTMother = -1.0f; + float yMother = -1.0f; + bool isMCMotherPhi = false; + + for (const auto& mcTrack1MotherIndex : mcTrack1MotherIndexes) { + for (const auto& mcTrack2MotherIndex : mcTrack2MotherIndexes) { + if (mcTrack1MotherIndex != mcTrack2MotherIndex) + continue; + + const auto mother = mcParticles.rawIteratorAt(mcTrack1MotherIndex); + if (mother.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + + pTMother = mother.pt(); + yMother = mother.y(); + isMCMotherPhi = true; + } + } + + if (!isMCMotherPhi) + continue; + if (pTMother < phiConfigs.minPhiPt || std::abs(yMother) > deltaYConfigs.cfgYAcceptance) + continue; + + nPhi++; + } + } + + if (nPhi > 0) + return true; + return false; + } + + template + bool eventHasGenKPair(const T& mcParticles) + { + int nKPair = 0; + + for (const auto& mcParticle1 : mcParticles) { + if (!mcParticle1.isPhysicalPrimary() || std::abs(mcParticle1.eta()) > trackConfigs.etaMax) + continue; + + for (const auto& mcParticle2 : mcParticles) { + if (!mcParticle2.isPhysicalPrimary() || std::abs(mcParticle2.eta()) > trackConfigs.etaMax) + continue; + + if ((mcParticle1.pdgCode() != PDG_t::kKPlus || mcParticle2.pdgCode() != PDG_t::kKMinus) && + (mcParticle1.pdgCode() != PDG_t::kKMinus || mcParticle2.pdgCode() != PDG_t::kKPlus)) + continue; + + ROOT::Math::PxPyPzMVector genKPair = recMother(mcParticle1, mcParticle2, massKa, massKa); + if (genKPair.Pt() < phiConfigs.minPhiPt) + continue; + if (genKPair.M() < phiConfigs.lowMPhi || genKPair.M() > phiConfigs.upMPhi) + continue; + if (std::abs(genKPair.Rapidity()) > deltaYConfigs.cfgYAcceptance) + continue; + + nKPair++; + } + } + + if (nKPair > 0) + return true; + return false; + } + + template + bool eventHasGenPhi(const T& mcParticles) + { + int nPhi = 0; + + for (const auto& mcParticle : mcParticles) { + if (mcParticle.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (mcParticle.pt() < phiConfigs.minPhiPt) + continue; + if (std::abs(mcParticle.y()) > deltaYConfigs.cfgYAcceptance) + continue; + + auto kDaughters = mcParticle.template 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; + + nPhi++; + } + + if (nPhi > 0) + return true; + return false; + } + + template + bool selectionChargedGenParticle(const T& mcParticle) + { + if (!mcParticle.isPhysicalPrimary() || std::abs(mcParticle.eta()) > trackConfigs.etaMax) + return false; + + auto pdgTrack = pdgDB->GetParticle(mcParticle.pdgCode()); + if (pdgTrack == nullptr) + return false; + if (std::abs(pdgTrack->Charge()) < trackConfigs.cfgMinAbsCharge) + return false; + + return true; + } + + int fromPDGToEnum(int pdgCode) + { + int pid = kSpAll; + switch (std::abs(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; + } + + return pid; + } + + // Get phi-meson purity functions from CCDB + void getPhiPurityFunctionsFromCCDB() + { + TList* listPhiPurityFunctions = ccdb->get(ccdbPurityPath); + if (!listPhiPurityFunctions) + LOG(error) << "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()); + } + + void getEfficiencyMapsFromCCDB() + { + TList* listEfficiencyMaps = ccdb->get(ccdbEfficiencyPath); + if (!listEfficiencyMaps) + LOG(error) << "Problem getting TList object with efficiency maps!"; + + effMapPhi = static_cast(listEfficiencyMaps->FindObject("h3EfficiencyPhi")); + if (!effMapPhi) { + LOG(error) << "Problem getting efficiency map for Phi!"; + return; + } + effMapK0S = static_cast(listEfficiencyMaps->FindObject("h3EfficiencyK0S")); + if (!effMapK0S) { + LOG(error) << "Problem getting efficiency map for K0S!"; + return; + } + effMapPionTPC = static_cast(listEfficiencyMaps->FindObject("h3EfficiencyPionTPC")); + if (!effMapPionTPC) { + LOG(error) << "Problem getting efficiency map for Pion with TPC!"; + return; + } + effMapPionTPCTOF = static_cast(listEfficiencyMaps->FindObject("h3EfficiencyPionTPCTOF")); + if (!effMapPionTPCTOF) { + LOG(error) << "Problem getting efficiency map for Pion with TPC and TOF!"; + return; + } + } + + // 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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(V0.yK0Short() - Phi.Rapidity()) > deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(V0.yK0Short() - Phi.Rapidity()) > deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(Pi.rapidity(massPi) - Phi.Rapidity()) > deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(Pi.rapidity(massPi) - Phi.Rapidity()) > deltaYConfigs.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 processPhiPurityData(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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.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(deltaYConfigs.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 (v0Configs.lowMK0S < v0.mK0Short() && v0.mK0Short() < v0Configs.upMK0S) { + dataK0SHist.fill(HIST("hNSigmaPosPionFromK0S"), posDaughterTrack.tpcInnerParam(), posDaughterTrack.tpcNSigmaPi()); + dataK0SHist.fill(HIST("hNSigmaNegPionFromK0S"), negDaughterTrack.tpcInnerParam(), negDaughterTrack.tpcNSigmaPi()); + } + } + + if (std::abs(v0.yK0Short()) > deltaYConfigs.cfgYAcceptance) + continue; + + countsK0S.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + countsK0S.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsK0S.at(i) > 0) + dataPhiHist.fill(HIST("h4PhipurK0SData"), i, multiplicity, recPhi.Pt(), recPhi.M()); + } + + isFilledhV0 = true; + + std::vector countsPi(deltaYConfigs.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)) > deltaYConfigs.cfgYAcceptance) + continue; + + countsPi.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + countsPi.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.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, processPhiPurityData, "Process function for Phi Purities in Data", true); + + void processPhiK0SData(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()) > deltaYConfigs.cfgYAcceptance) + continue; + + std::vector listrecPhi; + std::vector counts(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1, 0); + std::vector weights(deltaYConfigs.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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + if (recPhi.M() < phiConfigs.lowMPhi || recPhi.M() > phiConfigs.upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + weights.at(i + 1) *= (1 - phiPurity); + } + } + } + + if (fillMethodMultipleWeights) { + for (size_t i = 0; i < deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1 - weights.at(i) : 0); + } + fillInvMass(v0, multiplicity, weights); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiK0SData, "Process function for Phi-K0S Correlations in Data", false); + + void processPhiPionData(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)) > deltaYConfigs.cfgYAcceptance) + continue; + + std::vector listrecPhi; + std::vector counts(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1, 0); + std::vector weights(deltaYConfigs.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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + if (recPhi.M() < phiConfigs.lowMPhi || recPhi.M() > phiConfigs.upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + weights.at(i + 1) *= (1 - phiPurity); + } + } + } + + if (fillMethodMultipleWeights) { + for (size_t i = 0; i < deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1 - weights.at(i) : 0); + } + fillNSigma(track, multiplicity, weights); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiPionData, "Process function for Phi-Pion Correlations in Data", false); + + void processPhiMCReco(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("hUnbinnedRecoMCMultiplicityPercent"), 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("hRecoMCMultiplicityPercent"), 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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + + mcPhiHist.fill(HIST("h3PhiRapiditySmearing"), genmultiplicity, recPhi.Rapidity(), mcMotherPhi.y()); + + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.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()) > deltaYConfigs.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()) > deltaYConfigs.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()) > deltaYConfigs.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)) > deltaYConfigs.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()) > deltaYConfigs.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()) > deltaYConfigs.cfgSCutOnDeltaY) + continue; + if (!isCountedPi.at(2)) { + mcPhiHist.fill(HIST("h3PhieffPiInvMassSCut"), genmultiplicity, track.pt(), recPhi.M()); + isCountedPi.at(2) = true; + } + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiMCReco, "Process function for Phi in MCReco (to be removed)", false); + + void processPhiK0SMCReco(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()) > deltaYConfigs.cfgYAcceptance) + continue; + + mcK0SHist.fill(HIST("h3K0SMCReco"), genmultiplicity, v0mcparticle.pt(), v0.mK0Short()); + + std::vector counts(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1, 0); + + for (const auto& mcParticle : mcParticlesThisColl) { + if (mcParticle.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (mcParticle.pt() < phiConfigs.minPhiPt || mcParticle.pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(mcParticle.y()) > deltaYConfigs.cfgYAcceptance) + continue; + + counts.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0mcparticle.y() - mcParticle.y()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (counts.at(i) > 0) + mcPhiK0SHist.fill(HIST("h4PhiK0SMCReco"), i, genmultiplicity, v0mcparticle.pt(), v0.mK0Short()); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiK0SMCReco, "Process function for Phi-K0S Correlations Efficiency correction in MCReco", false); + + void processPhiPionMCReco(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()) > deltaYConfigs.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(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1, 0); + + for (const auto& mcParticle : mcParticlesThisColl) { + if (mcParticle.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (mcParticle.pt() < phiConfigs.minPhiPt || mcParticle.pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(mcParticle.y()) > deltaYConfigs.cfgYAcceptance) + continue; + + countsTPC.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(mcTrack.y() - mcParticle.y()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + countsTPC.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsTPC.at(i) > 0) + mcPhiPionHist.fill(HIST("h4PhiPiTPCMCReco"), i, genmultiplicity, mcTrack.pt(), track.tpcNSigmaPi()); + } + + if (track.pt() >= trackConfigs.pTToUseTOF && !track.hasTOF()) + continue; + + mcPionHist.fill(HIST("h4PiTPCTOFMCReco"), genmultiplicity, mcTrack.pt(), track.tpcNSigmaPi(), track.tofNSigmaPi()); + + std::vector countsTPCTOF(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1, 0); + + for (const auto& mcParticle : mcParticlesThisColl) { + if (mcParticle.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + if (mcParticle.pt() < phiConfigs.minPhiPt || mcParticle.pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(mcParticle.y()) > deltaYConfigs.cfgYAcceptance) + continue; + + countsTPCTOF.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(mcTrack.y() - mcParticle.y()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + countsTPCTOF.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsTPCTOF.at(i) > 0) + mcPhiPionHist.fill(HIST("h5PhiPiTPCTOFMCReco"), i, genmultiplicity, mcTrack.pt(), track.tpcNSigmaPi(), track.tofNSigmaPi()); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiPionMCReco, "Process function for Phi-Pion Correlations Efficiency correction in MCReco", false); + + void processPhiPurityMCClosure(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("hRecoMCMultiplicityPercent"), 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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.cfgYAcceptance) + continue; + + if (!isCountedPhi) { + mcEventHist.fill(HIST("hRecMCEventSelection"), 7); // at least a Phi candidate in the event + mcEventHist.fill(HIST("hRecoMCMultiplicityPercentWithPhi"), genmultiplicity); + isCountedPhi = true; + } + + if (fillMethodSingleWeight) + weight *= (1 - getPhiPurity(genmultiplicity, recPhi)); + + closureMCPhiHist.fill(HIST("h3PhipurMCClosure"), genmultiplicity, recPhi.Pt(), recPhi.M()); + + std::vector countsK0S(deltaYConfigs.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()) > deltaYConfigs.cfgYAcceptance) + continue; + + countsK0S.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + countsK0S.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + if (countsK0S.at(i) > 0) + closureMCPhiHist.fill(HIST("h4PhipurK0SInvMass"), i, genmultiplicity, recPhi.Pt(), recPhi.M()); + } + + std::vector countsPi(deltaYConfigs.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)) > deltaYConfigs.cfgYAcceptance) + continue; + + countsPi.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + countsPi.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.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, processPhiPurityMCClosure, "Process function for Phi Purities in MCClosure", false); + + void processPhiK0SMCClosure(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()) > deltaYConfigs.cfgYAcceptance) + continue; + + std::vector listrecPhi; + std::vector counts(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1, 0); + std::vector weights(deltaYConfigs.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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + if (recPhi.M() < phiConfigs.lowMPhi || recPhi.M() > phiConfigs.upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(v0.yK0Short() - recPhi.Rapidity()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + weights.at(i + 1) *= (1 - phiPurity); + } + } + } + + if (fillMethodMultipleWeights) { + for (size_t i = 0; i < deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1 - weights.at(i) : 0); + } + fillInvMass(v0, genmultiplicity, weights); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiK0SMCClosure, "Process function for Phi-K0S Correlations in MCClosure", false); + + void processPhiPionMCClosure(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)) > deltaYConfigs.cfgYAcceptance) + continue; + + std::vector listrecPhi; + std::vector counts(deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1, 0); + std::vector weights(deltaYConfigs.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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + if (recPhi.M() < phiConfigs.lowMPhi || recPhi.M() > phiConfigs.upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(track.rapidity(massPi) - recPhi.Rapidity()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + weights.at(i + 1) *= (1 - phiPurity); + } + } + } + + if (fillMethodMultipleWeights) { + for (size_t i = 0; i < deltaYConfigs.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 < deltaYConfigs.cfgDeltaYAcceptanceBins->size() + 1; i++) { + weights.at(i) = (counts.at(i) > 0 ? 1 - weights.at(i) : 0); + } + fillNSigma(track, genmultiplicity, weights); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiPionMCClosure, "Process function for Phi-Pion Correlations in MCClosure", false); + + void processPhiMCGen(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()) > deltaYConfigs.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()) > deltaYConfigs.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()) > deltaYConfigs.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()) > deltaYConfigs.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()) > deltaYConfigs.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()) > deltaYConfigs.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()) > deltaYConfigs.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, processPhiMCGen, "Process function for Phi in MCGen (to be removed)", false); + + void processPhiK0SMCGen(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()) > deltaYConfigs.cfgYAcceptance) + continue; + + mcK0SHist.fill(HIST("h2K0SMCGen"), genmultiplicity, mcParticle1.pt()); + if (isAssocColl) + mcK0SHist.fill(HIST("h2K0SMCGenAssocReco"), genmultiplicity, mcParticle1.pt()); + + std::vector counts(deltaYConfigs.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() < phiConfigs.minPhiPt || mcParticle2.pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(mcParticle2.y()) > deltaYConfigs.cfgYAcceptance) + continue; + + counts.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(mcParticle1.y() - mcParticle2.y()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.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, processPhiK0SMCGen, "Process function for Phi-K0S Correlations Efficiency correction in MCGen", false); + + void processPhiPionMCGen(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()) > deltaYConfigs.cfgYAcceptance) + continue; + + mcPionHist.fill(HIST("h2PiMCGen"), genmultiplicity, mcParticle1.pt()); + if (isAssocColl) + mcPionHist.fill(HIST("h2PiMCGenAssocReco"), genmultiplicity, mcParticle1.pt()); + + std::vector counts(deltaYConfigs.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() < phiConfigs.minPhiPt || mcParticle2.pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(mcParticle2.y()) > deltaYConfigs.cfgYAcceptance) + continue; + + counts.at(0)++; + for (size_t i = 0; i < deltaYConfigs.cfgDeltaYAcceptanceBins->size(); i++) { + if (std::abs(mcParticle1.y() - mcParticle2.y()) > deltaYConfigs.cfgDeltaYAcceptanceBins->at(i)) + continue; + counts.at(i + 1)++; + } + } + + for (size_t i = 0; i < deltaYConfigs.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, processPhiPionMCGen, "Process function for Phi-Pion Correlations Efficiency correction in MCGen", false); + + // dN/deta procedure + void processdNdetaWPhiData(SelCollisions::iterator const& collision, FilteredTracks const& filteredTracks) + { + // Check if the event selection is passed + if (!acceptEventQA(collision, true)) + return; + + auto posThisColl = posFiltTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negThisColl = negFiltTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + // Check if the event contains a phi candidate + if (!eventHasRecoPhi(posThisColl, negThisColl)) + return; + + dataEventHist.fill(HIST("hMultiplicityPercent"), collision.centFT0M()); + dataEventHist.fill(HIST("h2VertexZvsMult"), collision.posZ(), collision.centFT0M()); + + for (const auto& track : filteredTracks) { + if (trackConfigs.applyExtraPhiCuts && ((track.phi() > trackConfigs.extraPhiCuts->at(0) && track.phi() < trackConfigs.extraPhiCuts->at(1)) || + track.phi() <= trackConfigs.extraPhiCuts->at(2) || track.phi() >= trackConfigs.extraPhiCuts->at(3))) + continue; + + dataEventHist.fill(HIST("h5EtaDistribution"), collision.posZ(), collision.centFT0M(), track.eta(), track.phi(), kGlobalplusITSonly); + if (track.hasTPC()) { + dataEventHist.fill(HIST("h5EtaDistribution"), collision.posZ(), collision.centFT0M(), track.eta(), track.phi(), kGlobalonly); + } else { + dataEventHist.fill(HIST("h5EtaDistribution"), collision.posZ(), collision.centFT0M(), track.eta(), track.phi(), kITSonly); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processdNdetaWPhiData, "Process function for dN/deta values in Data", false); + + void processdNdetaWPhiMC(MCCollisions const& mcCollisions, SimCollisions const& collisions, FilteredMCTracks const& filteredMCTracks, aod::McParticles const& mcParticles) + { + std::vector> collsGrouped(mcCollisions.size()); + + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) + continue; + const auto& mcCollision = collision.mcCollision_as(); + collsGrouped[mcCollision.globalIndex()].push_back(collision.globalIndex()); + } + + for (const auto& mcCollision : mcCollisions) { + auto mcParticlesThisMcColl = mcParticles.sliceBy(preslices.mcPartPerMCCollision, mcCollision.globalIndex()); + + if (!pwglf::isINELgtNmc(mcParticlesThisMcColl, 0, pdgDB)) + continue; + switch (filterOnGenPhi) { + case 0: + if (!eventHasGenKPair(mcParticlesThisMcColl)) + continue; + break; + case 1: + if (!eventHasGenPhi(mcParticlesThisMcColl)) + continue; + break; + default: + break; + } + + uint64_t numberAssocColl = 0; + std::vector zVtxs; + + auto& collIndexesThisMcColl = collsGrouped[mcCollision.globalIndex()]; + + for (const auto& collisionIndex : collIndexesThisMcColl) { + auto collision = collisions.rawIteratorAt(collisionIndex); + + if (acceptEventQA(collision, false)) { + auto filteredMCTracksThisColl = filteredMCTracks.sliceBy(preslices.trackPerCollision, collision.globalIndex()); + + posFiltMCTracks.bindTable(filteredMCTracksThisColl); + negFiltMCTracks.bindTable(filteredMCTracksThisColl); + + switch (filterOnRecoPhi) { + case 0: + if (!eventHasRecoPhi(posFiltMCTracks, negFiltMCTracks)) + continue; + break; + case 1: + if (!eventHasRecoPhiWPDG(posFiltMCTracks, negFiltMCTracks, mcParticles)) + continue; + break; + default: + break; + } + + mcEventHist.fill(HIST("hRecoMCMultiplicityPercent"), mcCollision.centFT0M()); + mcEventHist.fill(HIST("h2RecoMCVertexZvsMult"), collision.posZ(), mcCollision.centFT0M()); + + zVtxs.push_back(collision.posZ()); + + for (const auto& track : filteredMCTracksThisColl) { + if (trackConfigs.applyExtraPhiCuts && ((track.phi() > trackConfigs.extraPhiCuts->at(0) && track.phi() < trackConfigs.extraPhiCuts->at(1)) || + track.phi() <= trackConfigs.extraPhiCuts->at(2) || track.phi() >= trackConfigs.extraPhiCuts->at(3))) + continue; + if (!track.has_mcParticle()) + continue; + + auto mcTrack = track.mcParticle(); + if (!mcTrack.isPhysicalPrimary() || std::abs(mcTrack.eta()) > trackConfigs.etaMax) + continue; + + mcEventHist.fill(HIST("h6RecoMCEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcTrack.eta(), mcTrack.phi(), kSpAll, kGlobalplusITSonly); + if (track.hasTPC()) { + mcEventHist.fill(HIST("h6RecoMCEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcTrack.eta(), mcTrack.phi(), kSpAll, kGlobalonly); + } else { + mcEventHist.fill(HIST("h6RecoMCEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcTrack.eta(), mcTrack.phi(), kSpAll, kITSonly); + } + + int pid = fromPDGToEnum(mcTrack.pdgCode()); + mcEventHist.fill(HIST("h6RecoMCEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcTrack.eta(), mcTrack.phi(), pid, kGlobalplusITSonly); + } + + if (fillMcPartsForAllReco) { + for (const auto& mcParticle : mcParticlesThisMcColl) { + if (!selectionChargedGenParticle(mcParticle)) + continue; + + mcEventHist.fill(HIST("h6GenMCAllAssocRecoEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kNoGenpTVar); + if (mcParticle.pt() < trackConfigs.cMinChargedParticlePtcut) { + mcEventHist.fill(HIST("h6GenMCAllAssocRecoEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTup, -10.0f * mcParticle.pt() + 2.0f); + mcEventHist.fill(HIST("h6GenMCAllAssocRecoEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTdown, 5.0f * mcParticle.pt() + 0.5f); + } else { + mcEventHist.fill(HIST("h6GenMCAllAssocRecoEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTup); + mcEventHist.fill(HIST("h6GenMCAllAssocRecoEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTdown); + } + + int pid = fromPDGToEnum(mcParticle.pdgCode()); + mcEventHist.fill(HIST("h6GenMCAllAssocRecoEtaDistribution"), collision.posZ(), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), pid, kNoGenpTVar); + } + } + + numberAssocColl++; + } + } + + mcEventHist.fill(HIST("hGenMCMultiplicityPercent"), mcCollision.centFT0M()); + + if (numberAssocColl > 0) { + float zVtxRef = zVtxs[0]; + if (zVtxs.size() > 1) { + for (size_t i = 1; i < zVtxs.size(); ++i) { + mcEventHist.fill(HIST("hSplitVertexZ"), zVtxs[i] - zVtxRef); + } + } + + mcEventHist.fill(HIST("hGenMCAssocRecoMultiplicityPercent"), mcCollision.centFT0M()); + mcEventHist.fill(HIST("h2GenMCAssocRecoVertexZvsMult"), zVtxRef, mcCollision.centFT0M()); + } + + for (const auto& mcParticle : mcParticlesThisMcColl) { + if (!selectionChargedGenParticle(mcParticle)) + continue; + + int pid = fromPDGToEnum(mcParticle.pdgCode()); + + mcEventHist.fill(HIST("h5GenMCEtaDistribution"), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kNoGenpTVar); + if (mcParticle.pt() < trackConfigs.cMinChargedParticlePtcut) { + mcEventHist.fill(HIST("h5GenMCEtaDistribution"), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTup, -10.0f * mcParticle.pt() + 2.0f); + mcEventHist.fill(HIST("h5GenMCEtaDistribution"), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTdown, 5.0f * mcParticle.pt() + 0.5f); + } else { + mcEventHist.fill(HIST("h5GenMCEtaDistribution"), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTup); + mcEventHist.fill(HIST("h5GenMCEtaDistribution"), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTdown); + } + mcEventHist.fill(HIST("h5GenMCEtaDistribution"), mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), pid, kNoGenpTVar); + + if (numberAssocColl > 0) { + float zVtxRef = zVtxs[0]; + + mcEventHist.fill(HIST("h6GenMCAssocRecoEtaDistribution"), zVtxRef, mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kNoGenpTVar); + if (mcParticle.pt() < trackConfigs.cMinChargedParticlePtcut) { + mcEventHist.fill(HIST("h6GenMCAssocRecoEtaDistribution"), zVtxRef, mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTup, -10.0f * mcParticle.pt() + 2.0f); + mcEventHist.fill(HIST("h6GenMCAssocRecoEtaDistribution"), zVtxRef, mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTdown, 5.0f * mcParticle.pt() + 0.5f); + } else { + mcEventHist.fill(HIST("h6GenMCAssocRecoEtaDistribution"), zVtxRef, mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTup); + mcEventHist.fill(HIST("h6GenMCAssocRecoEtaDistribution"), zVtxRef, mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), kSpAll, kGenpTdown); + } + mcEventHist.fill(HIST("h6GenMCAssocRecoEtaDistribution"), zVtxRef, mcCollision.centFT0M(), mcParticle.eta(), mcParticle.phi(), pid, kNoGenpTVar); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processdNdetaWPhiMC, "Process function for dN/deta values in MC", false); + + // New 2D analysis procedure + void processPhiK0SPionData2D(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; + + // 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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.cfgYAcceptance) + continue; + + if (!isCountedPhi) { + dataEventHist.fill(HIST("hEventSelection"), 4); // at least a Phi candidate in the event + dataEventHist.fill(HIST("hMultiplicityPercentWithPhi"), multiplicity); + isCountedPhi = true; + } + + float efficiencyPhi = 1.0f; + if (applyEfficiency) { + efficiencyPhi = effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()); + if (efficiencyPhi == 0) + efficiencyPhi = 1.0f; + } + float weightPhi = applyEfficiency ? 1.0f / efficiencyPhi : 1.0f; + dataPhiHist.fill(HIST("h3PhiDataNewProc"), multiplicity, recPhi.Pt(), recPhi.M(), weightPhi); + + // 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 (v0Configs.lowMK0S < v0.mK0Short() && v0.mK0Short() < v0Configs.upMK0S) { + dataK0SHist.fill(HIST("hNSigmaPosPionFromK0S"), posDaughterTrack.tpcInnerParam(), posDaughterTrack.tpcNSigmaPi()); + dataK0SHist.fill(HIST("hNSigmaNegPionFromK0S"), negDaughterTrack.tpcInnerParam(), negDaughterTrack.tpcNSigmaPi()); + } + } + + if (std::abs(v0.yK0Short()) > deltaYConfigs.cfgYAcceptance) + continue; + + float efficiencyPhiK0S = 1.0f; + if (applyEfficiency) { + efficiencyPhiK0S = effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapK0S->Interpolate(multiplicity, v0.pt(), v0.yK0Short()); + if (efficiencyPhiK0S == 0) + efficiencyPhiK0S = 1.0f; + } + float weightPhiK0S = applyEfficiency ? 1.0f / efficiencyPhiK0S : 1.0f; + dataPhiK0SHist.fill(HIST("h5PhiK0SDataNewProc"), v0.yK0Short() - recPhi.Rapidity(), multiplicity, v0.pt(), v0.mK0Short(), recPhi.M(), weightPhiK0S); + } + + isFilledhV0 = true; + + // Loop over all primary pion candidates + for (const auto& track : fullTracks) { + if (!selectionPion(track, false)) + continue; + + if (std::abs(track.rapidity(massPi)) > deltaYConfigs.cfgYAcceptance) + continue; + + float efficiencyPhiPion = 1.0f; + if (applyEfficiency) { + efficiencyPhiPion = track.pt() < trackConfigs.pTToUseTOF ? effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapPionTPC->Interpolate(multiplicity, track.pt(), track.rapidity(massPi)) : effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapPionTPCTOF->Interpolate(multiplicity, track.pt(), track.rapidity(massPi)); + if (efficiencyPhiPion == 0) + efficiencyPhiPion = 1.0f; + } + float weightPhiPion = applyEfficiency ? 1.0f / efficiencyPhiPion : 1.0f; + dataPhiPionHist.fill(HIST("h5PhiPiTPCDataNewProc"), track.rapidity(massPi) - recPhi.Rapidity(), multiplicity, track.pt(), track.tpcNSigmaPi(), recPhi.M(), weightPhiPion); + if (track.hasTOF()) + dataPhiPionHist.fill(HIST("h5PhiPiTOFDataNewProc"), track.rapidity(massPi) - recPhi.Rapidity(), multiplicity, track.pt(), track.tofNSigmaPi(), recPhi.M(), weightPhiPion); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiK0SPionData2D, "Process function for Phi-K0S and Phi-Pion Correlations in Data2D", false); + + void processPhiK0SPionMCClosure2D(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("hRecoMCMultiplicityPercent"), 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, 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() < phiConfigs.minPhiPt || recPhi.Pt() > phiConfigs.maxPhiPt) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.cfgYAcceptance) + continue; + + if (!isCountedPhi) { + mcEventHist.fill(HIST("hRecMCEventSelection"), 7); // at least a Phi candidate in the event + mcEventHist.fill(HIST("hRecoMCMultiplicityPercentWithPhi"), genmultiplicity); + isCountedPhi = true; + } + + float efficiencyPhi = 1.0f; + if (applyEfficiency) { + efficiencyPhi = effMapPhi->Interpolate(genmultiplicity, recPhi.Pt(), recPhi.Rapidity()); + if (efficiencyPhi == 0) + efficiencyPhi = 1.0f; + } + float weightPhi = applyEfficiency ? 1.0f / efficiencyPhi : 1.0f; + closureMCPhiHist.fill(HIST("h3PhiMCClosureNewProc"), genmultiplicity, recPhi.Pt(), recPhi.M(), weightPhi); + + // 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()) > deltaYConfigs.cfgYAcceptance) + continue; + + float efficiencyPhiK0S = 1.0f; + if (applyEfficiency) { + efficiencyPhiK0S = effMapPhi->Interpolate(genmultiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapK0S->Interpolate(genmultiplicity, v0.pt(), v0.yK0Short()); + if (efficiencyPhiK0S == 0) + efficiencyPhiK0S = 1.0f; + } + float weightPhiK0S = applyEfficiency ? 1.0f / efficiencyPhiK0S : 1.0f; + closureMCPhiK0SHist.fill(HIST("h5PhiK0SMCClosureNewProc"), v0.yK0Short() - recPhi.Rapidity(), genmultiplicity, v0.pt(), v0.mK0Short(), recPhi.M(), weightPhiK0S); + } + + // 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)) > deltaYConfigs.cfgYAcceptance) + continue; + + float efficiencyPhiPion = 1.0f; + if (applyEfficiency) { + efficiencyPhiPion = track.pt() < trackConfigs.pTToUseTOF ? effMapPhi->Interpolate(genmultiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapPionTPC->Interpolate(genmultiplicity, track.pt(), track.rapidity(massPi)) : effMapPhi->Interpolate(genmultiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapPionTPCTOF->Interpolate(genmultiplicity, track.pt(), track.rapidity(massPi)); + if (efficiencyPhiPion == 0) + efficiencyPhiPion = 1.0f; + } + float weightPhiPion = applyEfficiency ? 1.0f / efficiencyPhiPion : 1.0f; + closureMCPhiPionHist.fill(HIST("h5PhiPiTPCMCClosureNewProc"), track.rapidity(massPi) - recPhi.Rapidity(), genmultiplicity, track.pt(), track.tpcNSigmaPi(), recPhi.M(), weightPhiPion); + if (track.hasTOF()) + closureMCPhiPionHist.fill(HIST("h5PhiPiTOFMCClosureNewProc"), track.rapidity(massPi) - recPhi.Rapidity(), genmultiplicity, track.pt(), track.tofNSigmaPi(), recPhi.M(), weightPhiPion); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiK0SPionMCClosure2D, "Process function for Phi-K0S and Phi-Pion Correlations in MCClosure2D", false); + + void processPhiK0SMixingEvent2D(SelCollisions const& collisions, FullTracks const& fullTracks, FullV0s const& V0s, V0DauTracks const&) + { + auto tracksV0sTuple = std::make_tuple(fullTracks, V0s); + Pair pairPhiK0S{binningOnVertexAndCent, cfgNoMixedEvents, -1, collisions, tracksV0sTuple, &cache}; + + for (auto const& [collision1, tracks1, collision2, v0s2] : pairPhiK0S) { + float multiplicity = collision1.centFT0M(); + + Partition posMixTracks = aod::track::signed1Pt > trackConfigs.cfgCutCharge; + posMixTracks.bindTable(tracks1); + Partition negMixTracks = aod::track::signed1Pt < trackConfigs.cfgCutCharge; + negMixTracks.bindTable(tracks1); + + for (const auto& [posTrack1, negTrack1, v0] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posMixTracks, negMixTracks, v0s2))) { + if (!selectionTrackResonance(posTrack1, true) || !selectionPIDKaonpTdependent(posTrack1)) + continue; + if (!selectionTrackResonance(negTrack1, true) || !selectionPIDKaonpTdependent(negTrack1)) + continue; + if (posTrack1.globalIndex() == negTrack1.globalIndex()) + continue; + + ROOT::Math::PxPyPzMVector recPhi = recMother(posTrack1, negTrack1, massKa, massKa); + if (recPhi.Pt() < phiConfigs.minPhiPt) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.cfgYAcceptance) + continue; + + const auto& posDaughterTrack = v0.posTrack_as(); + const auto& negDaughterTrack = v0.negTrack_as(); + + if (!selectionV0(v0, posDaughterTrack, negDaughterTrack)) + continue; + if (v0Configs.cfgFurtherV0Selection && !furtherSelectionV0(v0, collision2)) + continue; + if (std::abs(v0.yK0Short()) > deltaYConfigs.cfgYAcceptance) + continue; + + float efficiencyPhiK0S = 1.0f; + if (applyEfficiency) { + efficiencyPhiK0S = effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapK0S->Interpolate(multiplicity, v0.pt(), v0.yK0Short()); + if (efficiencyPhiK0S == 0) + efficiencyPhiK0S = 1.0f; + } + float weightPhiK0S = applyEfficiency ? 1.0f / efficiencyPhiK0S : 1.0f; + mePhiK0SHist.fill(HIST("h5PhiK0SMENewProc"), v0.yK0Short() - recPhi.Rapidity(), multiplicity, v0.pt(), v0.mK0Short(), recPhi.M(), weightPhiK0S); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiK0SMixingEvent2D, "Process Mixed Event for Phi-K0S Analysis 2D", false); + + void processPhiPionMixingEvent2D(SelCollisions const& collisions, FullTracks const& fullTracks) + { + auto tracksTuple = std::make_tuple(fullTracks); + SameKindPair pairPhiPion{binningOnVertexAndCent, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; + + for (auto const& [collision1, tracks1, collision2, tracks2] : pairPhiPion) { + float multiplicity = collision1.centFT0M(); + + Partition posMixTracks = aod::track::signed1Pt > trackConfigs.cfgCutCharge; + posMixTracks.bindTable(tracks1); + Partition negMixTracks = aod::track::signed1Pt < trackConfigs.cfgCutCharge; + negMixTracks.bindTable(tracks1); + + for (const auto& [posTrack1, negTrack1, track] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posMixTracks, negMixTracks, tracks2))) { + if (!selectionTrackResonance(posTrack1, true) || !selectionPIDKaonpTdependent(posTrack1)) + continue; + if (!selectionTrackResonance(negTrack1, true) || !selectionPIDKaonpTdependent(negTrack1)) + continue; + if (posTrack1.globalIndex() == negTrack1.globalIndex()) + continue; + + ROOT::Math::PxPyPzMVector recPhi = recMother(posTrack1, negTrack1, massKa, massKa); + if (recPhi.Pt() < phiConfigs.minPhiPt) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.cfgYAcceptance) + continue; + + if (!selectionPion(track, false)) + continue; + if (std::abs(track.rapidity(massPi)) > deltaYConfigs.cfgYAcceptance) + continue; + + float efficiencyPhiPion = 1.0f; + if (applyEfficiency) { + efficiencyPhiPion = track.pt() < trackConfigs.pTToUseTOF ? effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapPionTPC->Interpolate(multiplicity, track.pt(), track.rapidity(massPi)) : effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapPionTPCTOF->Interpolate(multiplicity, track.pt(), track.rapidity(massPi)); + if (efficiencyPhiPion == 0) + efficiencyPhiPion = 1.0f; + } + float weightPhiPion = applyEfficiency ? 1.0f / efficiencyPhiPion : 1.0f; + mePhiPionHist.fill(HIST("h5PhiPiTPCMENewProc"), track.rapidity(massPi) - recPhi.Rapidity(), multiplicity, track.pt(), track.tpcNSigmaPi(), recPhi.M(), weightPhiPion); + if (track.hasTOF()) + mePhiPionHist.fill(HIST("h5PhiPiTOFMENewProc"), track.rapidity(massPi) - recPhi.Rapidity(), multiplicity, track.pt(), track.tofNSigmaPi(), recPhi.M(), weightPhiPion); + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiPionMixingEvent2D, "Process Mixed Event for Phi-Pion Analysis 2D", false); + + void processAllPartMC(MCCollisions const& mcCollisions, SimCollisions const& collisions, FullMCTracks const& fullMCTracks, FullMCV0s const& V0s, V0DauMCTracks const&, aod::McParticles const& mcParticles) + { + + std::vector> collsGrouped(mcCollisions.size()); + + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) + continue; + const auto& mcCollision = collision.mcCollision_as(); + collsGrouped[mcCollision.globalIndex()].push_back(collision.globalIndex()); + } + + for (const auto& mcCollision : mcCollisions) { + auto mcParticlesThisMcColl = mcParticles.sliceBy(preslices.mcPartPerMCCollision, mcCollision.globalIndex()); + + if (!pwglf::isINELgtNmc(mcParticlesThisMcColl, 0, pdgDB)) + continue; + switch (filterOnGenPhi) { + case 0: + if (!eventHasGenKPair(mcParticlesThisMcColl)) + continue; + break; + case 1: + if (!eventHasGenPhi(mcParticlesThisMcColl)) + continue; + break; + default: + break; + } + + uint64_t numberAssocColl = 0; + std::vector zVtxs; + + auto& collIndexesThisMcColl = collsGrouped[mcCollision.globalIndex()]; + + for (const auto& collisionIndex : collIndexesThisMcColl) { + auto collision = collisions.rawIteratorAt(collisionIndex); + + if (acceptEventQA(collision, false)) { + auto fullMCTracksThisColl = fullMCTracks.sliceBy(preslices.trackPerCollision, collision.globalIndex()); + auto v0sThisColl = V0s.sliceBy(preslices.v0PerCollision, collision.globalIndex()); + + posMCTracks.bindTable(fullMCTracksThisColl); + negMCTracks.bindTable(fullMCTracksThisColl); + + switch (filterOnRecoPhi) { + case 0: + if (!eventHasRecoPhi(posMCTracks, negMCTracks)) + continue; + break; + case 1: + if (!eventHasRecoPhiWPDG(posMCTracks, negMCTracks, mcParticles)) + continue; + break; + default: + break; + } + + mcEventHist.fill(HIST("hRecoMCMultiplicityPercent"), mcCollision.centFT0M()); + mcEventHist.fill(HIST("h2RecoMCVertexZvsMult"), collision.posZ(), mcCollision.centFT0M()); + + zVtxs.push_back(collision.posZ()); + + if ((filterOnGenPhi != 0 && filterOnGenPhi != 1) && (filterOnRecoPhi != 0 && filterOnRecoPhi != 1)) { + for (const auto& track1 : posMCTracks) { // loop over all selected tracks + if (!selectionTrackResonance(track1, false) || !selectionPIDKaonpTdependent(track1)) + continue; // topological and PID selection + + auto track1ID = track1.globalIndex(); + + if (!track1.has_mcParticle()) + continue; + auto mcTrack1 = mcParticles.rawIteratorAt(track1.mcParticleId()); + if (mcTrack1.pdgCode() != PDG_t::kKPlus || !mcTrack1.isPhysicalPrimary()) + continue; + + for (const auto& track2 : negMCTracks) { + 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 = mcParticles.rawIteratorAt(track2.mcParticleId()); + if (mcTrack2.pdgCode() != PDG_t::kKMinus || !mcTrack2.isPhysicalPrimary()) + continue; + + const auto mcTrack1MotherIndexes = mcTrack1.mothersIds(); + const auto mcTrack2MotherIndexes = mcTrack2.mothersIds(); + + float pTMother = -1.0f; + float yMother = -1.0f; + bool isMCMotherPhi = false; + + for (const auto& mcTrack1MotherIndex : mcTrack1MotherIndexes) { + for (const auto& mcTrack2MotherIndex : mcTrack2MotherIndexes) { + if (mcTrack1MotherIndex != mcTrack2MotherIndex) + continue; + + const auto mother = mcParticles.rawIteratorAt(mcTrack1MotherIndex); + if (mother.pdgCode() != o2::constants::physics::Pdg::kPhi) + continue; + + pTMother = mother.pt(); + yMother = mother.y(); + isMCMotherPhi = true; + } + } + + if (!isMCMotherPhi) + continue; + if (pTMother < phiConfigs.minPhiPt || std::abs(yMother) > deltaYConfigs.cfgYAcceptance) + continue; + + mcPhiHist.fill(HIST("h4PhiMCRecoNewProc"), collision.posZ(), mcCollision.centFT0M(), pTMother, yMother); + } + } + } + + for (const auto& v0 : v0sThisColl) { + if (!v0.has_mcParticle()) + continue; + + auto v0mcparticle = mcParticles.rawIteratorAt(v0.mcParticleId()); + 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(v0mcparticle.y()) > deltaYConfigs.cfgYAcceptance) + continue; + + mcK0SHist.fill(HIST("h4K0SMCRecoNewProc"), collision.posZ(), mcCollision.centFT0M(), v0mcparticle.pt(), v0mcparticle.y()); + } + + for (const auto& track : fullMCTracksThisColl) { + // Pion selection + if (!selectionPion(track, false)) + continue; + + if (!track.has_mcParticle()) + continue; + + auto mcTrack = mcParticles.rawIteratorAt(track.mcParticleId()); + if (std::abs(mcTrack.pdgCode()) != PDG_t::kPiPlus) + continue; + + if (std::abs(mcTrack.y()) > deltaYConfigs.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("h4PiMCRecoNewProc"), collision.posZ(), mcCollision.centFT0M(), mcTrack.pt(), mcTrack.y()); + + if (track.pt() >= trackConfigs.pTToUseTOF && !track.hasTOF()) + continue; + + mcPionHist.fill(HIST("h4PiMCReco2NewProc"), collision.posZ(), mcCollision.centFT0M(), mcTrack.pt(), mcTrack.y()); + } + + numberAssocColl++; + } + } + + mcEventHist.fill(HIST("hGenMCMultiplicityPercent"), mcCollision.centFT0M()); + + if (numberAssocColl > 0) { + float zVtxRef = zVtxs[0]; + if (zVtxs.size() > 1) { + for (size_t i = 1; i < zVtxs.size(); ++i) { + mcEventHist.fill(HIST("hSplitVertexZ"), zVtxs[i] - zVtxRef); + } + } + + mcEventHist.fill(HIST("hGenMCAssocRecoMultiplicityPercent"), mcCollision.centFT0M()); + mcEventHist.fill(HIST("h2GenMCAssocRecoVertexZvsMult"), zVtxRef, mcCollision.centFT0M()); + } + + for (const auto& mcParticle : mcParticlesThisMcColl) { + if (std::abs(mcParticle.y()) > deltaYConfigs.cfgYAcceptance) + continue; + + if (filterOnGenPhi != 0 && filterOnGenPhi != 1) { + // Phi selection + if (mcParticle.pdgCode() == o2::constants::physics::Pdg::kPhi && mcParticle.pt() >= phiConfigs.minPhiPt) { + mcPhiHist.fill(HIST("h3PhiMCGenNewProc"), mcCollision.centFT0M(), mcParticle.pt(), mcParticle.y()); + if (numberAssocColl > 0) { + float zVtxRef = zVtxs[0]; + mcPhiHist.fill(HIST("h4PhiMCGenAssocRecoNewProc"), zVtxRef, mcCollision.centFT0M(), mcParticle.pt(), mcParticle.y()); + } + } + } + + // K0S selection + if (mcParticle.pdgCode() == PDG_t::kK0Short && mcParticle.isPhysicalPrimary() && mcParticle.pt() >= v0Configs.v0SettingMinPt) { + mcK0SHist.fill(HIST("h3K0SMCGenNewProc"), mcCollision.centFT0M(), mcParticle.pt(), mcParticle.y()); + if (numberAssocColl > 0) { + float zVtxRef = zVtxs[0]; + mcK0SHist.fill(HIST("h4K0SMCGenAssocRecoNewProc"), zVtxRef, mcCollision.centFT0M(), mcParticle.pt(), mcParticle.y()); + } + } + + // Pion selection + if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus && mcParticle.isPhysicalPrimary() && mcParticle.pt() >= trackConfigs.cMinPionPtcut) { + mcPionHist.fill(HIST("h3PiMCGenNewProc"), mcCollision.centFT0M(), mcParticle.pt(), mcParticle.y()); + if (numberAssocColl > 0) { + float zVtxRef = zVtxs[0]; + mcPionHist.fill(HIST("h4PiMCGenAssocRecoNewProc"), zVtxRef, mcCollision.centFT0M(), mcParticle.pt(), mcParticle.y()); + } + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processAllPartMC, "Process function for all particles (not for phi if triggered on it) in MC", false); + + // New 2D analysis procedure + void processPhiK0SPionDeltayDeltaphiData2D(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); + + if (!eventHasRecoPhi(posThisColl, negThisColl)) + return; + + dataEventHist.fill(HIST("hEventSelection"), 4); // at least a Phi candidate in the event + + bool isCountedPhi = false; + bool isFilledhV0 = false; + + // 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() < phiConfigs.minPhiPt) + continue; + if (recPhi.M() < phiConfigs.lowMPhi || recPhi.M() > phiConfigs.upMPhi) + continue; + if (std::abs(recPhi.Rapidity()) > deltaYConfigs.cfgYAcceptance) + continue; + + if (!isCountedPhi) + isCountedPhi = true; + + float efficiencyPhi = 1.0f; + if (applyEfficiency) { + efficiencyPhi = effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()); + if (efficiencyPhi == 0) + efficiencyPhi = 1.0f; + } + float weightPhi = applyEfficiency ? 1.0f / efficiencyPhi : 1.0f; + dataPhiHist.fill(HIST("h3PhiDataNewProc"), multiplicity, recPhi.Pt(), recPhi.M(), weightPhi); + + // 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 (v0Configs.lowMK0S < v0.mK0Short() && v0.mK0Short() < v0Configs.upMK0S) { + dataK0SHist.fill(HIST("hNSigmaPosPionFromK0S"), posDaughterTrack.tpcInnerParam(), posDaughterTrack.tpcNSigmaPi()); + dataK0SHist.fill(HIST("hNSigmaNegPionFromK0S"), negDaughterTrack.tpcInnerParam(), negDaughterTrack.tpcNSigmaPi()); + } + } + + if (std::abs(v0.yK0Short()) > deltaYConfigs.cfgYAcceptance) + continue; + + float efficiencyPhiK0S = 1.0f; + if (applyEfficiency) { + efficiencyPhiK0S = effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapK0S->Interpolate(multiplicity, v0.pt(), v0.yK0Short()); + if (efficiencyPhiK0S == 0) + efficiencyPhiK0S = 1.0f; + } + float weightPhiK0S = applyEfficiency ? 1.0f / efficiencyPhiK0S : 1.0f; + dataPhiK0SHist.fill(HIST("h5PhiK0SData2PartCorr"), multiplicity, recPhi.Pt(), v0.pt(), recPhi.Rapidity() - v0.yK0Short(), recPhi.Phi() - v0.phi(), weightPhiK0S); + } + + isFilledhV0 = true; + + // Loop over all primary pion candidates + for (const auto& track : fullTracks) { + if (!selectionPion(track, false)) + continue; + + if (std::abs(track.rapidity(massPi)) > deltaYConfigs.cfgYAcceptance) + continue; + + float efficiencyPhiPion = 1.0f; + if (applyEfficiency) { + efficiencyPhiPion = track.pt() < trackConfigs.pTToUseTOF ? effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapPionTPC->Interpolate(multiplicity, track.pt(), track.rapidity(massPi)) : effMapPhi->Interpolate(multiplicity, recPhi.Pt(), recPhi.Rapidity()) * effMapPionTPCTOF->Interpolate(multiplicity, track.pt(), track.rapidity(massPi)); + if (efficiencyPhiPion == 0) + efficiencyPhiPion = 1.0f; + } + float weightPhiPion = applyEfficiency ? 1.0f / efficiencyPhiPion : 1.0f; + dataPhiPionHist.fill(HIST("h5PhiPiData2PartCorr"), multiplicity, recPhi.Pt(), track.pt(), recPhi.Rapidity() - track.rapidity(massPi), recPhi.Phi() - track.phi(), weightPhiPion); + } + } + } + } + + PROCESS_SWITCH(Phik0shortanalysis, processPhiK0SPionDeltayDeltaphiData2D, "Process function for Phi-K0S and Phi-Pion Deltay and Deltaphi 2D Correlations in Data", 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 343c5ba4287..cce52ba691b 100644 --- a/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx @@ -9,8 +9,7 @@ // 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 // *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -20,396 +19,1579 @@ // gianni.shigeru.setoue.liveraro@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFSigmaTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/ASoA.h" -#include "ReconstructionDataFormats/Track.h" +#include "Common/CCDB/ctpRateFetcher.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/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include #include #include -#include #include #include -#include +#include + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; + using std::array; -using std::cout; -using std::endl; +using MCSigma0s = soa::Join; +using Sigma0s = soa::Join; + +static const std::vector PhotonSels = {"NoSel", "V0Type", "DCADauToPV", + "DCADau", "DauTPCCR", "TPCNSigmaEl", "V0pT", + "Y", "V0Radius", "RZCut", "Armenteros", "CosPA", + "PsiPair", "Phi", "Mass"}; -using V0MCSigmas = soa::Join; -using V0Sigmas = soa::Join; +static const std::vector LambdaSels = {"NoSel", "V0Radius", "DCADau", "Armenteros", + "CosPA", "Y", "TPCCR", "DauITSCls", "Lifetime", + "TPCTOFPID", "DCADauToPV", "Mass"}; + +static const std::vector DirList = {"BeforeSel", "AfterSel"}; struct sigmaanalysis { + Service ccdb; + ctpRateFetcher rateFetcher; + + //__________________________________________________ + // For manual sliceBy + // SliceCache cache; + PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - // master analysis switches - // Configurable analyseSigma{"analyseSigma", false, "process Sigma-like candidates"}; - // Configurable analyseAntiSigma{"analyseAntiSigma", false, "process AntiSigma-like candidates"}; + // Event level + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; + Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; + 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"}; + 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 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"}; + + } eventSelections; + + // Generated Sigma0s + Configurable mc_keepOnlyFromGenerator{"mc_keepOnlyFromGenerator", true, "if true, consider only particles from generator to calculate efficiency."}; + + // QA + Configurable fillBkgQAhistos{"fillBkgQAhistos", false, "if true, fill MC QA histograms for Bkg study. Only works with MC."}; + Configurable fillResoQAhistos{"fillResoQAhistos", false, "if true, fill MC QA histograms for pT resolution study. Only works with MC."}; // Analysis strategy: - Configurable fUseMLSel{"fUseMLSel", true, "Flag to use ML selection. If False, the standard selection is applied."}; - Configurable fProcessMonteCarlo{"fProcessMonteCarlo", false, "Flag to process MC data."}; - - // 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 LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 2.5, "Max DCA V0 Daughters (cm)"}; - Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.5, "Min V0 radius (cm)"}; - Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 180, "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.2, "Min lambda alpha absolute value (AP plot)"}; - Configurable LambdaMaxAlpha{"LambdaMaxAlpha", 0.9, "Max lambda alpha absolute value (AP plot)"}; - Configurable LambdaMinv0cospa{"LambdaMinv0cospa", 0.95, "Min V0 CosPA"}; - Configurable LambdaWindow{"LambdaWindow", 0.01, "Mass window around expected (in GeV/c2)"}; - - //// Photon standard criteria: - Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 0.9, "Max pseudorapidity of daughter tracks"}; - Configurable PhotonDauMinPt{"PhotonDauMinPt", 0.05, "Min daughter pT (GeV/c)"}; - Configurable PhotonMinDCADauToPv{"PhotonMinDCADauToPv", 0.05, "Min DCA daughter To PV (cm)"}; - Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 2.5, "Max DCA V0 Daughters (cm)"}; - Configurable PhotonMinTPCCrossedRows{"PhotonMinTPCCrossedRows", 55, "Min daughter TPC Crossed Rows"}; - Configurable PhotonMinTPCNSigmas{"PhotonMinTPCNSigmas", -6, "Min TPC NSigmas for daughters"}; - Configurable PhotonMaxTPCNSigmas{"PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; - Configurable PhotonMinPt{"PhotonMinPt", 0.02, "Min photon pT (GeV/c)"}; - Configurable PhotonMaxPt{"PhotonMaxPt", 50.0, "Max photon pT (GeV/c)"}; - Configurable PhotonMaxPseudoRap{"PhotonMaxPseudoRap", 0.9, "Max photon pseudorapidity"}; - Configurable PhotonMinRadius{"PhotonMinRadius", 0.5, "Min photon conversion radius (cm)"}; - Configurable PhotonMaxRadius{"PhotonMaxRadius", 180, "Max photon conversion radius (cm)"}; - Configurable PhotonMaxZ{"PhotonMaxZ", 240, "Max photon conversion point z value (cm)"}; - Configurable PhotonMaxQt{"PhotonMaxQt", 0.06, "Max photon qt value (AP plot) (GeV/c)"}; - Configurable PhotonMaxAlpha{"PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; - Configurable PhotonMinV0cospa{"PhotonMinV0cospa", 0.90, "Min V0 CosPA"}; - Configurable PhotonMaxMass{"PhotonMaxMass", 0.15, "Max photon mass (GeV/c^{2})"}; - // TODO: Include PsiPair selection + Configurable doMCAssociation{"doMCAssociation", false, "Flag to process only signal candidates. Use only with processMonteCarlo!"}; + Configurable selRecoFromGenerator{"selRecoFromGenerator", false, "Flag to process only signal candidates from generator"}; + Configurable doPhotonLambdaSelQA{"doPhotonLambdaSelQA", false, "Flag to fill photon and lambda QA histos!"}; + + // For Selection: + //// Lambda criteria:: + struct : ConfigurableGroup { + 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"}; + 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 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 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"}; + + } lambdaSelections; + + //// Photon criteria: + struct : ConfigurableGroup { + Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; + Configurable Photonv0TypeSel{"Photonv0TypeSel", 7, "select on a certain V0 type (leave negative if no selection desired)"}; + 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 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 to reject photons, region 1 (leave negative if no selection desired)"}; + Configurable PhotonPhiMax1{"PhotonPhiMax1", -1, "Phi max value to reject photons, region 1 (leave negative if no selection desired)"}; + Configurable PhotonPhiMin2{"PhotonPhiMin2", -1, "Phi max value to reject photons, region 2 (leave negative if no selection desired)"}; + Configurable PhotonPhiMax2{"PhotonPhiMax2", -1, "Phi min value to reject photons, region 2 (leave negative if no selection desired)"}; + } photonSelections; + + struct : ConfigurableGroup { + Configurable Sigma0MaxRap{"Sigma0MaxRap", 0.5, "Max sigma0 rapidity"}; + Configurable Sigma0MaxRadius{"Sigma0MaxRadius", 200, "Max sigma0 decay radius"}; + Configurable Sigma0MaxDCADau{"Sigma0MaxDCADau", 50, "Max sigma0 DCA between daughters"}; + Configurable Sigma0MaxOPAngle{"Sigma0MaxOPAngle", 7, "Max sigma0 OP Angle between daughters"}; + } sigma0Selections; + + struct : ConfigurableGroup { + Configurable Pi0MaxRap{"Pi0MaxRap", 0.5, "Max sigma0 rapidity"}; + Configurable Pi0MaxRadius{"Pi0MaxRadius", 200, "Max sigma0 decay radius"}; + Configurable Pi0MaxDCADau{"Pi0MaxDCADau", 50, "Max sigma0 DCA between daughters"}; + } pi0Selections; // Axis // base properties - 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 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 axisRapidity{"axisRapidity", {100, -1.0f, 1.0f}, "Rapidity"}; + 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", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; + ConfigurableAxis axisNch{"axisNch", {300, 0.0f, 3000.0f}, "N_{ch}"}; + ConfigurableAxis axisGeneratorIds{"axisGeneratorIds", {256, -0.5f, 255.5f}, "axis for generatorIds"}; // Invariant Mass - ConfigurableAxis axisSigmaMass{"axisSigmaMass", {200, 1.16f, 1.23f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; - ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, "M_{#Lambda} (GeV/c^{2})"}; - ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.1f}, "M_{#Gamma}"}; + ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 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", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; + ConfigurableAxis axisPi0Mass{"axisPi0Mass", {200, 0.08f, 0.18f}, "M_{#Pi^{0}}"}; // 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 + // Track quality, PID and other axes ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; - ConfigurableAxis axisITSclus{"axisITSclus", {7, 0.0f, 7.0f}, "N ITS Clusters"}; + 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", {100, 0, 100}, "Chi2 Per Ncl"}; // 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 axisPointingAngle{"axisPointingAngle", {20, 0.0f, 2.0f}, "pointing angle (rad)"}; - ConfigurableAxis axisV0Radius{"axisV0Radius", {20, 0.0f, 60.0f}, "V0 2D radius (cm)"}; + ConfigurableAxis axisV0Radius{"axisV0Radius", {240, 0.0f, 120.0f}, "V0 radius (cm)"}; + ConfigurableAxis axisV0PairRadius{"axisV0PairRadius", {200, 0.0f, 20.0f}, "V0Pair 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 axisPA{"axisPA", {100, 0.0f, 1}, "Pointing angle"}; + ConfigurableAxis axisPsiPair{"axisPsiPair", {250, -5.0f, 5.0f}, "Psipair for photons"}; + ConfigurableAxis axisPhi{"axisPhi", {200, 0, 2 * o2::constants::math::PI}, "Phi for photons"}; + ConfigurableAxis axisZ{"axisZ", {120, -120.0f, 120.0f}, "V0 Z position (cm)"}; + + ConfigurableAxis axisCandSel{"axisCandSel", {20, 0.5f, +20.5f}, "Candidate Selection"}; // ML ConfigurableAxis MLProb{"MLOutput", {100, 0.0f, 1.0f}, ""}; - int nSigmaCandidates = 0; + void init(InitContext const&) { - // Event counter - histos.add("hEventCentrality", "hEventCentrality", kTH1F, {axisCentrality}); - - // For Signal Extraction - histos.add("h3dMassSigma0", "h3dMassSigma0", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); - histos.add("h3dMassAntiSigma0", "h3dMassAntiSigma0", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); - - // All candidates received - // 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", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); - histos.add("GeneralQA/h2dArmenterosSelected", "h2dArmenterosSelected", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); - histos.add("GeneralQA/hMassSigma0All", "hMassSigma0All", kTH1F, {axisSigmaMass}); - - // Candidates Counters - histos.add("GeneralQA/hCandidateAnalysisSelection", "hCandidateAnalysisSelection", kTH1F, {{22, -0.5f, +21.5f}}); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(1, "Photon Mass Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(2, "Photon DauEta Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(3, "Photon DauPt Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(4, "Photon DCAToPV Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(5, "Photon DCADau Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(6, "Photon TPCCrossedRows Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(7, "Photon PosTPCSigma Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(8, "Photon NegTPCSigma Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(9, "Photon Pt Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(10, "Photon Eta Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(11, "Photon Radius Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(12, "Photon Zconv Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(13, "Photon QT Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(14, "Photon Alpha Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(15, "Photon CosPA Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(16, "Lambda Mass Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(17, "Lambda DCAToPV Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(18, "Lambda Radius Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(19, "Lambda DCADau Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(20, "Lambda QT Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(21, "Lambda Alpha Cut"); - histos.get(HIST("GeneralQA/hCandidateAnalysisSelection"))->GetXaxis()->SetBinLabel(22, "Lambda CosPA Cut"); - - // Sigma0 QA - histos.add("Sigma0/hMassSigma0", "hMassSigma0", kTH1F, {axisSigmaMass}); - histos.add("Sigma0/hPtSigma0", "hPtSigma0", kTH1F, {axisPt}); - histos.add("Sigma0/hRapiditySigma0", "hRapiditySigma0", kTH1F, {axisRapidity}); - - // Sigma0 QA - histos.add("AntiSigma0/hMassSigma0", "hMassSigma0", kTH1F, {axisSigmaMass}); - histos.add("AntiSigma0/hPtSigma0", "hPtSigma0", kTH1F, {axisPt}); - histos.add("AntiSigma0/hRapiditySigma0", "hRapiditySigma0", kTH1F, {axisRapidity}); - - // Gamma QA - histos.add("Gamma/hMassGamma", "hMassGamma", kTH1F, {axisSigmaMass}); - histos.add("Gamma/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("Gamma/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("Gamma/hDCADaughters", "hDCADaughters", kTH1F, {axisDCAdau}); - histos.add("Gamma/hPointingAngle", "hPointingAngle", kTH1F, {axisPointingAngle}); - histos.add("Gamma/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); - histos.add("Gamma/hMLOutputGamma", "hMLOutputGamma", kTH1F, {MLProb}); - histos.add("Gamma/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("Gamma/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("Gamma/h2dPhotonRadiusVsPt", "hPhotonRadiusVsPt", {HistType::kTH2F, {axisPt, axisRadius}}); - histos.add("Gamma/h2dPhotonMassVsMLScore", "h2dPhotonMassVsMLScore", {HistType::kTH2F, {MLProb, axisSigmaMass}}); - - // Lambda QA - histos.add("Lambda/hMassLambda", "hMassLambda", kTH1F, {axisLambdaMass}); - histos.add("Lambda/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("Lambda/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("Lambda/hDCADaughters", "hDCADaughters", kTH1F, {axisDCAdau}); - histos.add("Lambda/hPointingAngle", "hPointingAngle", kTH1F, {axisPointingAngle}); - histos.add("Lambda/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); - histos.add("Lambda/hMLOutputLambda", "hMLOutputLambda", kTH1F, {MLProb}); - histos.add("Lambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("Lambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("Lambda/h2dLambdaRadiusVsPt", "hLambdaRadiusVsPt", {HistType::kTH2F, {axisPt, axisRadius}}); - histos.add("Lambda/h2dLambdaMassVsMLScore", "h2dLambdaMassVsMLScore", {HistType::kTH2F, {MLProb, axisLambdaMass}}); - - // AntiLambda QA - histos.add("AntiLambda/hMassAntiLambda", "hMassAntiLambda", kTH1F, {axisLambdaMass}); - histos.add("AntiLambda/hPosDCAToPV", "hPosDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("AntiLambda/hNegDCAToPV", "hNegDCAToPV", kTH1F, {axisDCAtoPV}); - histos.add("AntiLambda/hDCADaughters", "hDCADaughters", kTH1F, {axisDCAdau}); - histos.add("AntiLambda/hPointingAngle", "hPointingAngle", kTH1F, {axisPointingAngle}); - histos.add("AntiLambda/hV0Radius", "hV0Radius", kTH1F, {axisV0Radius}); - histos.add("AntiLambda/hMLOutputAntiLambda", "hMLOutputAntiLambda", kTH1F, {MLProb}); - histos.add("AntiLambda/h2dPositiveITSvsTPCpts", "h2dPositiveITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("AntiLambda/h2dNegativeITSvsTPCpts", "h2dNegativeITSvsTPCpts", kTH2F, {axisTPCrows, axisITSclus}); - histos.add("AntiLambda/h2dAntiLambdaRadiusVsPt", "h2dAntiLambdaRadiusVsPt", {HistType::kTH2F, {axisPt, axisRadius}}); - histos.add("AntiLambda/h2dAntiLambdaMassVsMLScore", "h2dAntiLambdaMassVsMLScore", {HistType::kTH2F, {MLProb, axisLambdaMass}}); - - if (fProcessMonteCarlo) { - // Event counter - histos.add("hMCEventCentrality", "hMCEventCentrality", kTH1F, {axisCentrality}); - - // For Signal Extraction - histos.add("h3dMCMassSigma0", "h3dMCMassSigma0", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); - - histos.add("GeneralQA/h2dMCArmenterosAll", "h2dMCArmenterosAll", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); - histos.add("GeneralQA/h2dMCArmenterosSelected", "h2dMCArmenterosSelected", {HistType::kTH2F, {axisAPAlpha, axisAPQt}}); - - // Sigma0 QA - histos.add("GeneralQA/hMCMassSigma0All", "hMCMassSigma0All", kTH1F, {axisSigmaMass}); - histos.add("GeneralQA/hMCPtSigma0All", "hMCPtSigma0All", kTH1F, {axisPt}); - histos.add("Sigma0/hMCMassSigma0", "hMCMassSigma0", kTH1F, {axisSigmaMass}); - histos.add("Sigma0/hMCPtSigma0", "hMCPtSigma0", kTH1F, {axisPt}); + LOGF(info, "Initializing now: cross-checking correctness..."); + if ((doprocessRealData + doprocessMonteCarlo + doprocessPi0RealData + doprocessPi0MonteCarlo > 1) || + (doprocessGeneratedRun3 + doprocessPi0GeneratedRun3 > 1)) { + LOGF(fatal, "You have enabled more than one process function. Please check your configuration! Aborting now."); } - } - // Apply selections in sigma candidates - template - bool processSigmaCandidate(TV0Object const& cand) - { - 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; + // setting CCDB service + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); - // Lambda selection: - if (cand.lambdaBDTScore() <= Lambda_MLThreshold) - return false; + // Event Counters + histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisCentrality}); - // AntiLambda selection: - if (cand.antilambdaBDTScore() <= AntiLambda_MLThreshold) - return false; + histos.add("hEventSelection", "hEventSelection", kTH1D, {{21, -0.5f, +20.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 { - if (TMath::Abs(cand.photonMass()) > PhotonMaxMass) - return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 0.); - if ((TMath::Abs(cand.photonPosEta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(cand.photonNegEta()) > PhotonMaxDauPseudoRap)) + 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"); + + if (fGetIR) { + histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); + histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1D, {axisIRBinning}); + histos.add("GeneralQA/hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2D, {axisCentrality, axisIRBinning}); + } + + if (doprocessRealData || doprocessMonteCarlo) { + for (const auto& histodir : DirList) { + + histos.add(histodir + "/Photon/hTrackCode", "hTrackCode", kTH1D, {{11, 0.5f, 11.5f}}); + histos.add(histodir + "/Photon/hV0Type", "hV0Type", kTH1D, {{8, 0.5f, 8.5f}}); + histos.add(histodir + "/Photon/hDCANegToPV", "hDCANegToPV", kTH1D, {axisDCAtoPV}); + histos.add(histodir + "/Photon/hDCAPosToPV", "hDCAPosToPV", kTH1D, {axisDCAtoPV}); + histos.add(histodir + "/Photon/hDCADau", "hDCADau", kTH1D, {axisDCAdau}); + histos.add(histodir + "/Photon/hPosTPCCR", "hPosTPCCR", kTH1D, {axisTPCrows}); + histos.add(histodir + "/Photon/hNegTPCCR", "hNegTPCCR", kTH1D, {axisTPCrows}); + histos.add(histodir + "/Photon/hPosTPCNSigmaEl", "hPosTPCNSigmaEl", kTH1D, {axisTPCNSigma}); + histos.add(histodir + "/Photon/hNegTPCNSigmaEl", "hNegTPCNSigmaEl", kTH1D, {axisTPCNSigma}); + + histos.add(histodir + "/Photon/hpT", "hpT", kTH1D, {axisPt}); + histos.add(histodir + "/Photon/hY", "hY", kTH1D, {axisRapidity}); + histos.add(histodir + "/Photon/hPosEta", "hPosEta", kTH1D, {axisRapidity}); + histos.add(histodir + "/Photon/hNegEta", "hNegEta", kTH1D, {axisRapidity}); + histos.add(histodir + "/Photon/hRadius", "hRadius", kTH1D, {axisV0Radius}); + histos.add(histodir + "/Photon/hZ", "hZ", kTH1D, {axisZ}); + histos.add(histodir + "/Photon/h2dRZCut", "h2dRZCut", kTH2D, {axisZ, axisV0Radius}); + histos.add(histodir + "/Photon/h2dRZPlane", "h2dRZPlane", kTH2D, {axisZ, axisV0Radius}); + histos.add(histodir + "/Photon/hCosPA", "hCosPA", kTH1D, {axisCosPA}); + histos.add(histodir + "/Photon/hPsiPair", "hPsiPair", kTH1D, {axisPsiPair}); + histos.add(histodir + "/Photon/hPhi", "hPhi", kTH1D, {axisPhi}); + histos.add(histodir + "/Photon/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisPhotonMass}); + histos.add(histodir + "/Photon/hMass", "hMass", kTH1D, {axisPhotonMass}); + + histos.add(histodir + "/Lambda/hTrackCode", "hTrackCode", kTH1D, {{11, 0.5f, 11.5f}}); + histos.add(histodir + "/Lambda/hRadius", "hRadius", kTH1D, {axisV0Radius}); + histos.add(histodir + "/Lambda/hDCADau", "hDCADau", kTH1D, {axisDCAdau}); + histos.add(histodir + "/Lambda/hCosPA", "hCosPA", kTH1D, {axisCosPA}); + histos.add(histodir + "/Lambda/hY", "hY", kTH1D, {axisRapidity}); + histos.add(histodir + "/Lambda/hPosEta", "hPosEta", kTH1D, {axisRapidity}); + histos.add(histodir + "/Lambda/hNegEta", "hNegEta", kTH1D, {axisRapidity}); + histos.add(histodir + "/Lambda/hPosTPCCR", "hPosTPCCR", kTH1D, {axisTPCrows}); + histos.add(histodir + "/Lambda/hNegTPCCR", "hNegTPCCR", kTH1D, {axisTPCrows}); + histos.add(histodir + "/Lambda/hPosITSCls", "hPosITSCls", kTH1D, {axisNCls}); + histos.add(histodir + "/Lambda/hNegITSCls", "hNegITSCls", kTH1D, {axisNCls}); + histos.add(histodir + "/Lambda/hPosChi2PerNc", "hPosChi2PerNc", kTH1D, {axisChi2PerNcl}); + histos.add(histodir + "/Lambda/hNegChi2PerNc", "hNegChi2PerNc", kTH1D, {axisChi2PerNcl}); + histos.add(histodir + "/Lambda/hLifeTime", "hLifeTime", kTH1D, {axisLifetime}); + histos.add(histodir + "/Lambda/h2dTPCvsTOFNSigma_LambdaPr", "h2dTPCvsTOFNSigma_LambdaPr", kTH2D, {axisTPCNSigma, axisTOFNSigma}); + histos.add(histodir + "/Lambda/h2dTPCvsTOFNSigma_LambdaPi", "h2dTPCvsTOFNSigma_LambdaPi", kTH2D, {axisTPCNSigma, axisTOFNSigma}); + histos.add(histodir + "/Lambda/hLambdaDCANegToPV", "hLambdaDCANegToPV", kTH1D, {axisDCAtoPV}); + histos.add(histodir + "/Lambda/hLambdaDCAPosToPV", "hLambdaDCAPosToPV", kTH1D, {axisDCAtoPV}); + histos.add(histodir + "/Lambda/hLambdapT", "hLambdapT", kTH1D, {axisPt}); + histos.add(histodir + "/Lambda/hLambdaMass", "hLambdaMass", kTH1D, {axisLambdaMass}); + histos.add(histodir + "/Lambda/h3dLambdaMass", "h3dLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + histos.add(histodir + "/Lambda/h2dTPCvsTOFNSigma_ALambdaPr", "h2dTPCvsTOFNSigma_ALambdaPr", kTH2D, {axisTPCNSigma, axisTOFNSigma}); + histos.add(histodir + "/Lambda/h2dTPCvsTOFNSigma_ALambdaPi", "h2dTPCvsTOFNSigma_ALambdaPi", kTH2D, {axisTPCNSigma, axisTOFNSigma}); + histos.add(histodir + "/Lambda/hALambdaDCANegToPV", "hALambdaDCANegToPV", kTH1D, {axisDCAtoPV}); + histos.add(histodir + "/Lambda/hALambdaDCAPosToPV", "hALambdaDCAPosToPV", kTH1D, {axisDCAtoPV}); + histos.add(histodir + "/Lambda/hALambdapT", "hALambdapT", kTH1D, {axisPt}); + histos.add(histodir + "/Lambda/hAntiLambdaMass", "hAntiLambdaMass", kTH1D, {axisLambdaMass}); + histos.add(histodir + "/Lambda/h3dAntiLambdaMass", "h3dAntiLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + + histos.add(histodir + "/h2dArmenteros", "h2dArmenteros", kTH2D, {axisAPAlpha, axisAPQt}); + + histos.add(histodir + "/Sigma0/hMass", "hMass", kTH1D, {axisSigmaMass}); + histos.add(histodir + "/Sigma0/hPt", "hPt", kTH1D, {axisPt}); + histos.add(histodir + "/Sigma0/hY", "hY", kTH1D, {axisRapidity}); + histos.add(histodir + "/Sigma0/hRadius", "hRadius", kTH1D, {axisV0PairRadius}); + histos.add(histodir + "/Sigma0/h2dRadiusVspT", "h2dRadiusVspT", kTH2D, {axisV0PairRadius, axisPt}); + histos.add(histodir + "/Sigma0/hDCAPairDau", "hDCAPairDau", kTH1D, {axisDCAdau}); + histos.add(histodir + "/Sigma0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); + histos.add(histodir + "/Sigma0/h3dOPAngleVsMass", "h3dOPAngleVsMass", kTH3D, {{140, 0.0f, +7.0f}, axisPt, axisSigmaMass}); + + histos.add(histodir + "/ASigma0/hMass", "hMass", kTH1D, {axisSigmaMass}); + histos.add(histodir + "/ASigma0/hPt", "hPt", kTH1D, {axisPt}); + histos.add(histodir + "/ASigma0/hY", "hY", kTH1D, {axisRapidity}); + histos.add(histodir + "/ASigma0/hRadius", "hRadius", kTH1D, {axisV0PairRadius}); + histos.add(histodir + "/ASigma0/h2dRadiusVspT", "h2dRadiusVspT", kTH2D, {axisV0PairRadius, axisPt}); + histos.add(histodir + "/ASigma0/hDCAPairDau", "hDCAPairDau", kTH1D, {axisDCAdau}); + histos.add(histodir + "/ASigma0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); + histos.add(histodir + "/ASigma0/h3dOPAngleVsMass", "h3dOPAngleVsMass", kTH3D, {{140, 0.0f, +7.0f}, axisPt, axisSigmaMass}); + + // Process MC + if (doprocessMonteCarlo) { + histos.add(histodir + "/MC/Photon/hV0ToCollAssoc", "hV0ToCollAssoc", kTH1D, {{2, 0.0f, 2.0f}}); + histos.add(histodir + "/MC/Photon/hPt", "hPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/Photon/hMCPt", "hMCPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/Photon/hPosTPCNSigmaEl", "hPosTPCNSigmaEl", kTH1D, {axisTPCNSigma}); + histos.add(histodir + "/MC/Photon/hNegTPCNSigmaEl", "hNegTPCNSigmaEl", kTH1D, {axisTPCNSigma}); + histos.add(histodir + "/MC/Photon/h2dPAVsPt", "h2dPAVsPt", kTH2D, {axisPA, axisPt}); + histos.add(histodir + "/MC/Photon/hPt_BadCollAssig", "hPt_BadCollAssig", kTH1D, {axisPt}); + histos.add(histodir + "/MC/Photon/h2dPAVsPt_BadCollAssig", "h2dPAVsPt_BadCollAssig", kTH2D, {axisPA, axisPt}); + + histos.add(histodir + "/MC/Lambda/hV0ToCollAssoc", "hV0ToCollAssoc", kTH1D, {{2, 0.0f, 2.0f}}); + histos.add(histodir + "/MC/Lambda/hPt", "hPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/Lambda/hMCPt", "hMCPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/Lambda/h3dTPCvsTOFNSigma_Pr", "h3dTPCvsTOFNSigma_Pr", kTH3D, {axisTPCNSigma, axisTOFNSigma, axisPt}); + histos.add(histodir + "/MC/Lambda/h3dTPCvsTOFNSigma_Pi", "h3dTPCvsTOFNSigma_Pi", kTH3D, {axisTPCNSigma, axisTOFNSigma, axisPt}); + + histos.add(histodir + "/MC/ALambda/hV0ToCollAssoc", "hV0ToCollAssoc", kTH1D, {{2, 0.0f, 2.0f}}); + histos.add(histodir + "/MC/ALambda/hPt", "hPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/ALambda/hMCPt", "hMCPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/ALambda/h3dTPCvsTOFNSigma_Pr", "h3dTPCvsTOFNSigma_Pr", kTH3D, {axisTPCNSigma, axisTOFNSigma, axisPt}); + histos.add(histodir + "/MC/ALambda/h3dTPCvsTOFNSigma_Pi", "h3dTPCvsTOFNSigma_Pi", kTH3D, {axisTPCNSigma, axisTOFNSigma, axisPt}); + + histos.add(histodir + "/MC/h2dArmenteros", "h2dArmenteros", kTH2D, {axisAPAlpha, axisAPQt}); + + histos.add(histodir + "/MC/Sigma0/hPt", "hPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/Sigma0/hMCPt", "hMCPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/Sigma0/hMass", "hMass", kTH1D, {axisSigmaMass}); + histos.add(histodir + "/MC/Sigma0/hMCProcess", "hMCProcess", kTH1D, {{50, -0.5f, 49.5f}}); + histos.add(histodir + "/MC/Sigma0/hGenRadius", "hGenRadius", kTH1D, {axisV0PairRadius}); + histos.add(histodir + "/MC/Sigma0/h2dMCPtVsLambdaMCPt", "h2dMCPtVsLambdaMCPt", kTH2D, {axisPt, axisPt}); + histos.add(histodir + "/MC/Sigma0/h2dMCPtVsPhotonMCPt", "h2dMCPtVsPhotonMCPt", kTH2D, {axisPt, axisPt}); + histos.add(histodir + "/MC/Sigma0/h2dMCProcessVsGenRadius", "h2dMCProcessVsGenRadius", kTH2D, {{50, -0.5f, 49.5f}, axisV0PairRadius}); + histos.add(histodir + "/MC/Sigma0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); + histos.add(histodir + "/MC/Sigma0/h3dMCProcess", "h3dMCProcess", kTH3D, {{50, -0.5f, 49.5f}, axisPt, axisSigmaMass}); + + histos.add(histodir + "/MC/ASigma0/hPt", "hPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/ASigma0/hMCPt", "hMCPt", kTH1D, {axisPt}); + histos.add(histodir + "/MC/ASigma0/hMass", "hMass", kTH1D, {axisSigmaMass}); + histos.add(histodir + "/MC/ASigma0/hMCProcess", "hMCProcess", kTH1D, {{50, -0.5f, 49.5f}}); + histos.add(histodir + "/MC/ASigma0/hGenRadius", "hGenRadius", kTH1D, {axisV0PairRadius}); + histos.add(histodir + "/MC/ASigma0/h2dMCPtVsLambdaMCPt", "h2dMCPtVsLambdaMCPt", kTH2D, {axisPt, axisPt}); + histos.add(histodir + "/MC/ASigma0/h2dMCPtVsPhotonMCPt", "h2dMCPtVsPhotonMCPt", kTH2D, {axisPt, axisPt}); + histos.add(histodir + "/MC/ASigma0/h2dMCProcessVsGenRadius", "h2dMCProcessVsGenRadius", kTH2D, {{50, -0.5f, 49.5f}, axisV0PairRadius}); + histos.add(histodir + "/MC/ASigma0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); + histos.add(histodir + "/MC/ASigma0/h3dMCProcess", "h3dMCProcess", kTH3D, {{50, -0.5f, 49.5f}, axisPt, axisSigmaMass}); + + // 1/pT Resolution: + if (fillResoQAhistos && histodir == "BeforeSel") { + histos.add(histodir + "/MC/Reso/h3dGammaPtResoVsTPCCR", "h3dGammaPtResoVsTPCCR", kTH3D, {axisInvPt, axisDeltaPt, axisTPCrows}); + histos.add(histodir + "/MC/Reso/h3dGammaPtResoVsTPCCR", "h3dGammaPtResoVsTPCCR", kTH3D, {axisInvPt, axisDeltaPt, axisTPCrows}); + histos.add(histodir + "/MC/Reso/h2dGammaPtResolution", "h2dGammaPtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add(histodir + "/MC/Reso/h2dLambdaPtResolution", "h2dLambdaPtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add(histodir + "/MC/Reso/h3dLambdaPtResoVsTPCCR", "h3dLambdaPtResoVsTPCCR", kTH3D, {axisInvPt, axisDeltaPt, axisTPCrows}); + histos.add(histodir + "/MC/Reso/h3dLambdaPtResoVsTPCCR", "h3dLambdaPtResoVsTPCCR", kTH3D, {axisInvPt, axisDeltaPt, axisTPCrows}); + histos.add(histodir + "/MC/Reso/h2dAntiLambdaPtResolution", "h2dAntiLambdaPtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add(histodir + "/MC/Reso/h3dAntiLambdaPtResoVsTPCCR", "h3dAntiLambdaPtResoVsTPCCR", kTH3D, {axisInvPt, axisDeltaPt, axisTPCrows}); + histos.add(histodir + "/MC/Reso/h3dAntiLambdaPtResoVsTPCCR", "h3dAntiLambdaPtResoVsTPCCR", kTH3D, {axisInvPt, axisDeltaPt, axisTPCrows}); + histos.add(histodir + "/MC/Reso/h2dSigma0PtResolution", "h2dSigma0PtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add(histodir + "/MC/Reso/h2dAntiSigma0PtResolution", "h2dAntiSigma0PtResolution", kTH2D, {axisInvPt, axisDeltaPt}); + histos.add(histodir + "/MC/Reso/h2dSigma0RadiusResolution", "h2dSigma0RadiusResolution", kTH2D, {axisPt, axisDeltaPt}); + histos.add(histodir + "/MC/Reso/h2dASigma0RadiusResolution", "h2dASigma0RadiusResolution", kTH2D, {axisPt, axisDeltaPt}); + } + + // For background decomposition study + if (fillBkgQAhistos) { + histos.add(histodir + "/MC/BkgStudy/h2dPtVsMassSigma_All", "h2dPtVsMassSigma_All", kTH2D, {axisPt, axisSigmaMass}); + histos.add(histodir + "/MC/BkgStudy/h2dPtVsMassSigma_TrueDaughters", "h2dPtVsMassSigma_TrueDaughters", kTH2D, {axisPt, axisSigmaMass}); + histos.add(histodir + "/MC/BkgStudy/h2dTrueDaughtersMatrix", "h2dTrueDaughtersMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add(histodir + "/MC/BkgStudy/h2dPtVsMassSigma_TrueGammaFakeLambda", "h2dPtVsMassSigma_TrueGammaFakeLambda", kTH2D, {axisPt, axisSigmaMass}); + histos.add(histodir + "/MC/BkgStudy/h2dPtVsMassSigma_FakeGammaTrueLambda", "h2dPtVsMassSigma_FakeGammaTrueLambda", kTH2D, {axisPt, axisSigmaMass}); + histos.add(histodir + "/MC/BkgStudy/h2dPtVsMassSigma_FakeDaughters", "h2dPtVsMassSigma_FakeDaughters", kTH2D, {axisPt, axisSigmaMass}); + } + } + } + + // Selections + histos.add("Selection/Photon/hCandidateSel", "hCandidateSel", kTH1D, {axisCandSel}); + histos.add("Selection/Lambda/hCandidateSel", "hCandidateSel", kTH1D, {axisCandSel}); + + // For background decomposition study + if (fillBkgQAhistos && doprocessMonteCarlo) { + histos.add("BkgStudy/h2dPtVsMassSigma_All", "h2dPtVsMassSigma_All", kTH2D, {axisPt, axisSigmaMass}); + histos.add("BkgStudy/h2dPtVsMassSigma_TrueDaughters", "h2dPtVsMassSigma_TrueDaughters", kTH2D, {axisPt, axisSigmaMass}); + histos.add("BkgStudy/h2dPtVsMassSigma_TrueGammaFakeLambda", "h2dPtVsMassSigma_TrueGammaFakeLambda", kTH2D, {axisPt, axisSigmaMass}); + histos.add("BkgStudy/h2dPtVsMassSigma_FakeGammaTrueLambda", "h2dPtVsMassSigma_FakeGammaTrueLambda", kTH2D, {axisPt, axisSigmaMass}); + histos.add("BkgStudy/h2dPtVsMassSigma_FakeDaughters", "h2dPtVsMassSigma_FakeDaughters", kTH2D, {axisPt, axisSigmaMass}); + histos.add("BkgStudy/h2dTrueDaughtersMatrix", "h2dTrueDaughtersMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add("BkgStudy/h2dTrueGammaFakeLambdaMatrix", "h2dTrueGammaFakeLambdaMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add("BkgStudy/h2dFakeGammaTrueLambdaMatrix", "h2dFakeGammaTrueLambdaMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + histos.add("BkgStudy/h2dFakeDaughtersMatrix", "h2dFakeDaughtersMatrix", kTHnSparseD, {{10001, -5000.5f, +5000.5f}, {10001, -5000.5f, +5000.5f}}); + } + + for (size_t i = 0; i < PhotonSels.size(); ++i) { + const auto& sel = PhotonSels[i]; + + histos.add(Form("Selection/Photon/h2d%s", sel.c_str()), ("h2d" + sel).c_str(), kTH2D, {axisPt, axisPhotonMass}); + histos.get(HIST("Selection/Photon/hCandidateSel"))->GetXaxis()->SetBinLabel(i + 1, sel.c_str()); + histos.add(Form("Selection/Sigma0/h2dPhoton%s", sel.c_str()), ("h2dPhoton" + sel).c_str(), kTH2D, {axisPt, axisSigmaMass}); + } + + for (size_t i = 0; i < LambdaSels.size(); ++i) { + const auto& sel = LambdaSels[i]; + + histos.add(Form("Selection/Lambda/h2d%s", sel.c_str()), ("h2d" + sel).c_str(), kTH2D, {axisPt, axisLambdaMass}); + histos.get(HIST("Selection/Lambda/hCandidateSel"))->GetXaxis()->SetBinLabel(i + 1, sel.c_str()); + histos.add(Form("Selection/Sigma0/h2dLambda%s", sel.c_str()), ("h2dLambda" + sel).c_str(), kTH2D, {axisPt, axisSigmaMass}); + } + } + + if (doprocessPi0RealData || doprocessPi0MonteCarlo) { + histos.add("Pi0/hMass", "hMass", kTH1D, {axisPi0Mass}); + histos.add("Pi0/hPt", "hPt", kTH1D, {axisPt}); + histos.add("Pi0/hY", "hY", kTH1D, {axisRapidity}); + histos.add("Pi0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + histos.add("Pi0/h3dMass_MCAssociated", "h3dMass_MCAssociated", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + } + + if (doprocessGeneratedRun3 || doprocessPi0GeneratedRun3) { + + histos.add("Gen/hGenEvents", "hGenEvents", kTH2D, {{axisNch}, {2, -0.5f, +1.5f}}); + histos.get(HIST("Gen/hGenEvents"))->GetYaxis()->SetBinLabel(1, "All gen. events"); + histos.get(HIST("Gen/hGenEvents"))->GetYaxis()->SetBinLabel(2, "Gen. with at least 1 rec. events"); + + histos.add("Gen/hGenEventCentrality", "hGenEventCentrality", kTH1D, {axisCentrality}); + histos.add("Gen/hCentralityVsNcoll_beforeEvSel", "hCentralityVsNcoll_beforeEvSel", kTH2D, {axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("Gen/hCentralityVsNcoll_afterEvSel", "hCentralityVsNcoll_afterEvSel", kTH2D, {axisCentrality, {50, -0.5f, 49.5f}}); + histos.add("Gen/hCentralityVsMultMC", "hCentralityVsMultMC", kTH2D, {axisCentrality, axisNch}); + + histos.add("Gen/hEventPVzMC", "hEventPVzMC", kTH1D, {{100, -20.0f, +20.0f}}); + histos.add("Gen/hCentralityVsPVzMC", "hCentralityVsPVzMC", kTH2D, {{101, 0.0f, 101.0f}, {100, -20.0f, +20.0f}}); + + // Sigma0 specific + if (doprocessGeneratedRun3) { + histos.add("Gen/h2dGenSigma0", "h2dGenSigma0", kTH2D, {axisCentrality, axisPt}); + histos.add("Gen/h2dGenAntiSigma0", "h2dGenAntiSigma0", kTH2D, {axisCentrality, axisPt}); + histos.add("Gen/h2dGenSigma0VsMultMC_RecoedEvt", "h2dGenSigma0VsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("Gen/h2dGenAntiSigma0VsMultMC_RecoedEvt", "h2dGenAntiSigma0VsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("Gen/h2dGenSigma0VsMultMC", "h2dGenSigma0VsMultMC", kTH2D, {axisNch, axisPt}); + histos.add("Gen/h2dGenAntiSigma0VsMultMC", "h2dGenAntiSigma0VsMultMC", kTH2D, {axisNch, axisPt}); + + } else { // Pi0 specific + histos.add("Gen/h2dGenPi0VsMultMC_RecoedEvt", "h2dGenPi0VsMultMC_RecoedEvt", kTH2D, {axisNch, axisPt}); + histos.add("Gen/h2dGenPi0", "h2dGenPi0", kTH2D, {axisCentrality, axisPt}); + histos.add("Gen/h2dGenPi0VsMultMC", "h2dGenPi0VsMultMC", kTH2D, {axisNch, axisPt}); + } + } + } + + // ______________________________________________________ + // Check whether the collision passes our collision selections + // Should work with collisions, mccollisions, stracollisions and stramccollisions tables! + template + bool IsEventAccepted(TCollision const& collision, bool fillHists) + { + 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; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 1.); - if ((cand.photonPosPt() < PhotonDauMinPt) || (cand.photonNegPt() < PhotonDauMinPt)) + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 2.); - if ((TMath::Abs(cand.photonDCAPosPV()) < PhotonMinDCADauToPv) || (TMath::Abs(cand.photonDCANegPV()) < PhotonMinDCADauToPv)) + } + 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; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 3.); - if (cand.photonDCADau() > PhotonMaxDCAV0Dau) + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* Below min occupancy */); + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 4.); - if ((cand.photonPosTPCCrossedRows() < PhotonMinTPCCrossedRows) || (cand.photonNegTPCCrossedRows() < PhotonMinTPCCrossedRows)) + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17 /* Above max occupancy */); + } + + // Fetch interaction rate only if required (in order to limit ccdb calls) + float interactionRate = (fGetIR) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource, fIRCrashOnNull) * 1.e-3 : -1; + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + if (fGetIR) { + if (interactionRate < 0) + histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", collision.runNumber()), 1); // This lists all run numbers without IR info! + + histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); + } + + 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 */); + + // Fill centrality histogram after event selection + if (fillHists) + histos.fill(HIST("hEventCentrality"), centrality); + + return true; + } + + // ______________________________________________________ + // 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) + { + std::vector listBestCollisionIdx(mcCollisions.size()); + for (auto const& mcCollision : mcCollisions) { + auto groupedCollisions = collisions.sliceBy(perMcCollision, 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; + } + } + // 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(); + } + } + listBestCollisionIdx[mcCollision.globalIndex()] = bestCollisionIndex; + } + return listBestCollisionIdx; + } + + // ______________________________________________________ + // 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("Gen/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, false)) { + continue; + } + + if (biggestNContribs < collision.multPVTotalContributors()) { + biggestNContribs = collision.multPVTotalContributors(); + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + } + + nCollisions++; + atLeastOne = true; + } + + histos.fill(HIST("Gen/hCentralityVsNcoll_beforeEvSel"), centrality, groupedCollisions.size()); + histos.fill(HIST("Gen/hCentralityVsNcoll_afterEvSel"), centrality, nCollisions); + histos.fill(HIST("Gen/hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("Gen/hCentralityVsPVzMC"), centrality, mcCollision.posZ()); + histos.fill(HIST("Gen/hEventPVzMC"), mcCollision.posZ()); + + if (atLeastOne) { + histos.fill(HIST("Gen/hGenEvents"), mcCollision.multMCNParticlesEta05(), 1 /* at least 1 rec. event*/); + histos.fill(HIST("Gen/hGenEventCentrality"), centrality); + } + } + return; + } + + // ______________________________________________________ + // Simulated processing (subscribes to MC information too) + template + void analyzeGenerated(TMCCollisions const& mcCollisions, TCollisions const& collisions, TGenParticles const& genParticles) + { + fillGeneratedEventProperties(mcCollisions, collisions); + std::vector listBestCollisionIdx = getListOfRecoCollIndices(mcCollisions, collisions); + + for (auto& genParticle : genParticles) { + float centrality = 100.5f; + + // Has MC collision + if (!genParticle.has_straMCCollision()) + continue; + + // Selection on the source (generator/transport) + if (!genParticle.producedByGenerator() && mc_keepOnlyFromGenerator) + continue; + + // Select corresponding mc collision && Basic event selection + auto mcCollision = genParticle.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; + } + } + + //______________________________________________________________________________ + // Generated Sigma0 processing + if constexpr (requires { genParticle.sigma0MCPt(); }) { + + float ptmc = genParticle.sigma0MCPt(); + + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + if (genParticle.isSigma0()) + histos.fill(HIST("Gen/h2dGenSigma0VsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + + else + histos.fill(HIST("Gen/h2dGenAntiSigma0VsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + + if (genParticle.isSigma0()) { + histos.fill(HIST("Gen/h2dGenSigma0"), centrality, ptmc); + histos.fill(HIST("Gen/h2dGenSigma0VsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } else { + histos.fill(HIST("Gen/h2dGenAntiSigma0"), centrality, ptmc); + histos.fill(HIST("Gen/h2dGenAntiSigma0VsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + //______________________________________________________________________________ + // Generated Pi0 processing + if constexpr (requires { genParticle.pi0MCPt(); }) { + float ptmc = genParticle.pi0MCPt(); + + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("Gen/h2dGenPi0VsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + + histos.fill(HIST("Gen/h2dGenPi0"), centrality, ptmc); + histos.fill(HIST("Gen/h2dGenPi0VsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + } + + //__________________________________________ + template + int retrieveV0TrackCode(TSigma0Object const& sigma) + { + + int TrkCode = 10; // 1: TPC-only, 2: TPC+Something, 3: ITS-Only, 4: ITS+TPC + Something, 10: anything else + + if (isGamma) { + if (sigma.photonPosTrackCode() == 1 && sigma.photonNegTrackCode() == 1) + TrkCode = 1; + if ((sigma.photonPosTrackCode() != 1 && sigma.photonNegTrackCode() == 1) || (sigma.photonPosTrackCode() == 1 && sigma.photonNegTrackCode() != 1)) + TrkCode = 2; + if (sigma.photonPosTrackCode() == 3 && sigma.photonNegTrackCode() == 3) + TrkCode = 3; + if (sigma.photonPosTrackCode() == 2 || sigma.photonNegTrackCode() == 2) + TrkCode = 4; + } else { + if (sigma.lambdaPosTrackCode() == 1 && sigma.lambdaNegTrackCode() == 1) + TrkCode = 1; + if ((sigma.lambdaPosTrackCode() != 1 && sigma.lambdaNegTrackCode() == 1) || (sigma.lambdaPosTrackCode() == 1 && sigma.lambdaNegTrackCode() != 1)) + TrkCode = 2; + if (sigma.lambdaPosTrackCode() == 3 && sigma.lambdaNegTrackCode() == 3) + TrkCode = 3; + if (sigma.lambdaPosTrackCode() == 2 || sigma.lambdaNegTrackCode() == 2) + TrkCode = 4; + } + + return TrkCode; + } + + template + void getResolution(TSigma0Object const& sigma) + { + + //_______________________________________ + // Gamma MC association + if (sigma.photonPDGCode() == 22) { + if (sigma.photonmcpt() > 0) { + histos.fill(HIST("BeforeSel/MC/Reso/h3dGammaPtResoVsTPCCR"), 1.f / sigma.lambdamcpt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdamcpt(), -1 * sigma.photonNegTPCCrossedRows()); // 1/pT resolution + histos.fill(HIST("BeforeSel/MC/Reso/h3dGammaPtResoVsTPCCR"), 1.f / sigma.lambdamcpt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdamcpt(), sigma.photonPosTPCCrossedRows()); // 1/pT resolution + histos.fill(HIST("BeforeSel/MC/Reso/h2dGammaPtResolution"), 1.f / sigma.photonmcpt(), 1.f / sigma.photonPt() - 1.f / sigma.photonmcpt()); // pT resolution + } + } + + //_______________________________________ + // Lambda MC association + if (sigma.lambdaPDGCode() == 3122) { + if (sigma.lambdamcpt() > 0) { + histos.fill(HIST("BeforeSel/MC/Reso/h2dLambdaPtResolution"), 1.f / sigma.lambdamcpt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdamcpt()); // 1/pT resolution + histos.fill(HIST("BeforeSel/MC/Reso/h3dLambdaPtResoVsTPCCR"), 1.f / sigma.lambdamcpt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdamcpt(), -1 * sigma.lambdaNegTPCCrossedRows()); // 1/pT resolution + histos.fill(HIST("BeforeSel/MC/Reso/h3dLambdaPtResoVsTPCCR"), 1.f / sigma.lambdamcpt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdamcpt(), sigma.lambdaPosTPCCrossedRows()); // 1/pT resolution + } + } + + //_______________________________________ + // AntiLambda MC association + if (sigma.lambdaPDGCode() == -3122) { + if (sigma.lambdamcpt() > 0) { + histos.fill(HIST("BeforeSel/MC/Reso/h2dAntiLambdaPtResolution"), 1.f / sigma.lambdamcpt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdamcpt()); // pT resolution + histos.fill(HIST("BeforeSel/MC/Reso/h3dAntiLambdaPtResoVsTPCCR"), 1.f / sigma.lambdamcpt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdamcpt(), -1 * sigma.lambdaNegTPCCrossedRows()); // 1/pT resolution + histos.fill(HIST("BeforeSel/MC/Reso/h3dAntiLambdaPtResoVsTPCCR"), 1.f / sigma.lambdamcpt(), 1.f / sigma.lambdaPt() - 1.f / sigma.lambdamcpt(), sigma.lambdaPosTPCCrossedRows()); // 1/pT resolution + } + } + + //_______________________________________ + // Sigma and AntiSigma MC association + if (sigma.isSigma0()) { + histos.fill(HIST("BeforeSel/MC/Reso/h2dSigma0RadiusResolution"), sigma.mcpt(), sigma.radius() - sigma.mcradius()); // pT resolution + if (sigma.mcpt() > 0) + histos.fill(HIST("BeforeSel/MC/Reso/h2dSigma0PtResolution"), 1.f / sigma.mcpt(), 1.f / sigma.pt() - 1.f / sigma.mcpt()); // pT resolution + } + if (sigma.isAntiSigma0()) { + histos.fill(HIST("BeforeSel/MC/Reso/h2dASigma0RadiusResolution"), sigma.mcpt(), sigma.radius() - sigma.mcradius()); // pT resolution + if (sigma.mcpt() > 0) + histos.fill(HIST("BeforeSel/MC/Reso/h2dAntiSigma0PtResolution"), 1.f / sigma.mcpt(), 1.f / sigma.pt() - 1.f / sigma.mcpt()); // pT resolution + } + } + + // To save histograms for background analysis + template + void runBkgAnalysis(TSigma0Object const& sigma) + { + // Check whether it is before or after selections + static constexpr std::string_view MainDir[] = {"BeforeSel", "AfterSel"}; + + bool fIsSigma = sigma.isSigma0(); + bool fIsAntiSigma = sigma.isAntiSigma0(); + int PhotonPDGCode = sigma.photonPDGCode(); + int PhotonPDGCodeMother = sigma.photonPDGCodeMother(); + int LambdaPDGCode = sigma.lambdaPDGCode(); + int LambdaPDGCodeMother = sigma.lambdaPDGCodeMother(); + float sigmapT = sigma.pt(); + float sigmaMass = sigma.sigma0Mass(); + + histos.fill(HIST(MainDir[mode]) + HIST("/MC/BkgStudy/h2dPtVsMassSigma_All"), sigmapT, sigmaMass); + + //_______________________________________ + // Real Gamma x Real Lambda - but not from the same sigma0/antisigma0! + if ((PhotonPDGCode == 22) && ((LambdaPDGCode == 3122) || (LambdaPDGCode == -3122)) && (!fIsSigma && !fIsAntiSigma)) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/BkgStudy/h2dPtVsMassSigma_TrueDaughters"), sigmapT, sigmaMass); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/BkgStudy/h2dTrueDaughtersMatrix"), LambdaPDGCodeMother, PhotonPDGCodeMother); + } + + //_______________________________________ + // Real Gamma x fake Lambda + if ((PhotonPDGCode == 22) && (LambdaPDGCode != 3122) && (LambdaPDGCode != -3122)) + histos.fill(HIST(MainDir[mode]) + HIST("/MC/BkgStudy/h2dPtVsMassSigma_TrueGammaFakeLambda"), sigmapT, sigmaMass); + + //_______________________________________ + // Fake Gamma x Real Lambda + if ((PhotonPDGCode != 22) && ((LambdaPDGCode == 3122) || (LambdaPDGCode == -3122))) + histos.fill(HIST(MainDir[mode]) + HIST("/MC/BkgStudy/h2dPtVsMassSigma_FakeGammaTrueLambda"), sigmapT, sigmaMass); + + //_______________________________________ + // Fake Gamma x Fake Lambda + if ((PhotonPDGCode != 22) && (LambdaPDGCode != 3122) && (LambdaPDGCode != -3122)) + histos.fill(HIST(MainDir[mode]) + HIST("/MC/BkgStudy/h2dPtVsMassSigma_FakeDaughters"), sigmapT, sigmaMass); + } + + template + void fillHistos(TSigma0Object const& sigma, TCollision const& collision) + { + + // Check whether it is before or after selections + static constexpr std::string_view MainDir[] = {"BeforeSel", "AfterSel"}; + + // Get V0trackCode + int GammaTrkCode = retrieveV0TrackCode(sigma); + int LambdaTrkCode = retrieveV0TrackCode(sigma); + + float photonRZLineCut = TMath::Abs(sigma.photonZconv()) * TMath::Tan(2 * TMath::ATan(TMath::Exp(-photonSelections.PhotonMaxDauEta))) - photonSelections.PhotonLineCutZ0; + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + //_______________________________________ + // Photon + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hTrackCode"), GammaTrkCode); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hV0Type"), sigma.photonV0Type()); + + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hDCANegToPV"), sigma.photonDCANegPV()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hDCAPosToPV"), sigma.photonDCAPosPV()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hDCADau"), sigma.photonDCADau()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hPosTPCCR"), sigma.photonPosTPCCrossedRows()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hNegTPCCR"), sigma.photonNegTPCCrossedRows()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hPosTPCNSigmaEl"), sigma.photonPosTPCNSigmaEl()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hNegTPCNSigmaEl"), sigma.photonNegTPCNSigmaEl()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hpT"), sigma.photonPt()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hY"), sigma.photonY()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hPosEta"), sigma.photonPosEta()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hNegEta"), sigma.photonNegEta()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hRadius"), sigma.photonRadius()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hZ"), sigma.photonZconv()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/h2dRZCut"), sigma.photonRadius(), photonRZLineCut); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/h2dRZPlane"), sigma.photonZconv(), sigma.photonRadius()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hCosPA"), sigma.photonCosPA()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hPsiPair"), sigma.photonPsiPair()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hPhi"), sigma.photonPhi()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/h3dMass"), centrality, sigma.photonPt(), sigma.photonMass()); + histos.fill(HIST(MainDir[mode]) + HIST("/Photon/hMass"), sigma.photonMass()); + + //_______________________________________ + // Lambdas + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hTrackCode"), LambdaTrkCode); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hRadius"), sigma.lambdaRadius()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hDCADau"), sigma.lambdaDCADau()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hCosPA"), sigma.lambdaCosPA()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hY"), sigma.lambdaY()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hPosEta"), sigma.lambdaPosEta()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hNegEta"), sigma.lambdaNegEta()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hPosTPCCR"), sigma.lambdaPosTPCCrossedRows()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hNegTPCCR"), sigma.lambdaNegTPCCrossedRows()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hPosITSCls"), sigma.lambdaPosITSCls()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hNegITSCls"), sigma.lambdaNegITSCls()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hPosChi2PerNc"), sigma.lambdaPosChi2PerNcl()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hNegChi2PerNc"), sigma.lambdaNegChi2PerNcl()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hLifeTime"), sigma.lambdaLifeTime()); + + //_______________________________________ + // Sigmas and Lambdas + histos.fill(HIST(MainDir[mode]) + HIST("/h2dArmenteros"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST(MainDir[mode]) + HIST("/h2dArmenteros"), sigma.lambdaAlpha(), sigma.lambdaQt()); + + if (sigma.lambdaAlpha() > 0) { + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/h2dTPCvsTOFNSigma_LambdaPr"), sigma.lambdaPosPrTPCNSigma(), sigma.lambdaPrTOFNSigma()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/h2dTPCvsTOFNSigma_LambdaPi"), sigma.lambdaNegPiTPCNSigma(), sigma.lambdaPiTOFNSigma()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hLambdaDCANegToPV"), sigma.lambdaDCANegPV()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hLambdaDCAPosToPV"), sigma.lambdaDCAPosPV()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hLambdapT"), sigma.lambdaPt()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hLambdaMass"), sigma.lambdaMass()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/h3dLambdaMass"), centrality, sigma.lambdaPt(), sigma.lambdaMass()); + + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hMass"), sigma.sigma0Mass()); + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hPt"), sigma.pt()); + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hY"), sigma.sigma0Y()); + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hRadius"), sigma.radius()); + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/h2dRadiusVspT"), sigma.radius(), sigma.pt()); + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hDCAPairDau"), sigma.dcadaughters()); + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/h3dMass"), centrality, sigma.pt(), sigma.sigma0Mass()); + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/h3dOPAngleVsMass"), sigma.opAngle(), sigma.pt(), sigma.sigma0Mass()); + } else { + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/h2dTPCvsTOFNSigma_ALambdaPr"), sigma.lambdaNegPrTPCNSigma(), sigma.aLambdaPrTOFNSigma()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/h2dTPCvsTOFNSigma_ALambdaPi"), sigma.lambdaPosPiTPCNSigma(), sigma.aLambdaPiTOFNSigma()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hALambdaDCANegToPV"), sigma.lambdaDCANegPV()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hALambdaDCAPosToPV"), sigma.lambdaDCAPosPV()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hALambdapT"), sigma.lambdaPt()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/hAntiLambdaMass"), sigma.antilambdaMass()); + histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/h3dAntiLambdaMass"), centrality, sigma.lambdaPt(), sigma.antilambdaMass()); + + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hMass"), sigma.sigma0Mass()); + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hPt"), sigma.pt()); + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hY"), sigma.sigma0Y()); + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hRadius"), sigma.radius()); + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/h2dRadiusVspT"), sigma.radius(), sigma.pt()); + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hDCAPairDau"), sigma.dcadaughters()); + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/h3dMass"), centrality, sigma.pt(), sigma.sigma0Mass()); + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/h3dOPAngleVsMass"), sigma.opAngle(), sigma.pt(), sigma.sigma0Mass()); + } + + //_______________________________________ + // MC specific + if (doprocessMonteCarlo) { + if constexpr (requires { sigma.lambdaPDGCode(); sigma.photonPDGCode(); }) { + + //_______________________________________ + // Gamma MC association + if (sigma.photonPDGCode() == 22) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Photon/hV0ToCollAssoc"), sigma.photonIsCorrectlyAssoc()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Photon/hPt"), sigma.photonPt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Photon/hMCPt"), sigma.photonmcpt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Photon/hPosTPCNSigmaEl"), sigma.photonPosTPCNSigmaEl()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Photon/hNegTPCNSigmaEl"), sigma.photonNegTPCNSigmaEl()); + + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Photon/h2dPAVsPt"), TMath::ACos(sigma.photonCosPA()), sigma.photonmcpt()); + + if (!sigma.photonIsCorrectlyAssoc()) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Photon/hPt_BadCollAssig"), sigma.photonmcpt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Photon/h2dPAVsPt_BadCollAssig"), TMath::ACos(sigma.photonCosPA()), sigma.photonmcpt()); + } + } + + //_______________________________________ + // Lambda MC association + if (sigma.lambdaPDGCode() == 3122) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Lambda/hV0ToCollAssoc"), sigma.lambdaIsCorrectlyAssoc()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Lambda/hPt"), sigma.lambdaPt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Lambda/hMCPt"), sigma.lambdamcpt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Lambda/h3dTPCvsTOFNSigma_Pr"), sigma.lambdaPosPrTPCNSigma(), sigma.lambdaPrTOFNSigma(), sigma.lambdaPt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Lambda/h3dTPCvsTOFNSigma_Pi"), sigma.lambdaNegPiTPCNSigma(), sigma.lambdaPiTOFNSigma(), sigma.lambdaPt()); + } + + //_______________________________________ + // AntiLambda MC association + if (sigma.lambdaPDGCode() == -3122) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ALambda/hV0ToCollAssoc"), sigma.lambdaIsCorrectlyAssoc()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ALambda/hPt"), sigma.lambdaPt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ALambda/hMCPt"), sigma.lambdamcpt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ALambda/h3dTPCvsTOFNSigma_Pr"), sigma.lambdaNegPrTPCNSigma(), sigma.aLambdaPrTOFNSigma(), sigma.lambdaPt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ALambda/h3dTPCvsTOFNSigma_Pi"), sigma.lambdaPosPiTPCNSigma(), sigma.aLambdaPiTOFNSigma(), sigma.lambdaPt()); + } + + //_______________________________________ + // Sigma0 MC association + if (sigma.isSigma0()) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/h2dArmenteros"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/h2dArmenteros"), sigma.lambdaAlpha(), sigma.lambdaQt()); + + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hPt"), sigma.pt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hMCPt"), sigma.mcpt()); + + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/h2dMCPtVsLambdaMCPt"), sigma.mcpt(), sigma.lambdamcpt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/h2dMCPtVsPhotonMCPt"), sigma.mcpt(), sigma.photonmcpt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hMass"), sigma.sigma0Mass()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/h3dMass"), centrality, sigma.mcpt(), sigma.sigma0Mass()); + + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hMCProcess"), sigma.mcprocess()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hGenRadius"), sigma.mcradius()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/h2dMCProcessVsGenRadius"), sigma.mcprocess(), sigma.mcradius()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/h3dMCProcess"), sigma.mcprocess(), sigma.mcpt(), sigma.sigma0Mass()); + } + + //_______________________________________ + // AntiSigma0 MC association + if (sigma.isAntiSigma0()) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/h2dArmenteros"), sigma.photonAlpha(), sigma.photonQt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/h2dArmenteros"), sigma.lambdaAlpha(), sigma.lambdaQt()); + + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hPt"), sigma.pt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hMCPt"), sigma.mcpt()); + + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h2dMCPtVsLambdaMCPt"), sigma.mcpt(), sigma.lambdamcpt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h2dMCPtVsPhotonMCPt"), sigma.mcpt(), sigma.photonmcpt()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hMass"), sigma.sigma0Mass()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h3dMass"), centrality, sigma.mcpt(), sigma.sigma0Mass()); + + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hMCProcess"), sigma.mcprocess()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hGenRadius"), sigma.mcradius()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h2dMCProcessVsGenRadius"), sigma.mcprocess(), sigma.mcradius()); + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h3dMCProcess"), sigma.mcprocess(), sigma.mcpt(), sigma.sigma0Mass()); + } + + // For background studies: + if (fillBkgQAhistos) + runBkgAnalysis(sigma); + + //_______________________________________ + // pT resolution histos + if ((mode == 0) && fillResoQAhistos) + getResolution(sigma); + } + } + } + + template + void fillSelHistos(TSigma0Object const& sigma, int PDGRequired) + { + + static constexpr std::string_view PhotonSelsLocal[] = {"NoSel", "V0Type", "DCADauToPV", + "DCADau", "DauTPCCR", "TPCNSigmaEl", "V0pT", + "Y", "V0Radius", "RZCut", "Armenteros", "CosPA", + "PsiPair", "Phi", "Mass"}; + + static constexpr std::string_view LambdaSelsLocal[] = {"NoSel", "V0Radius", "DCADau", "Armenteros", + "CosPA", "Y", "TPCCR", "DauITSCls", "Lifetime", + "TPCTOFPID", "DCADauToPV", "Mass"}; + + if (PDGRequired == 22) { + if constexpr (selection_index >= 0 && selection_index < (int)std::size(PhotonSelsLocal)) { + histos.fill(HIST("Selection/Photon/hCandidateSel"), selection_index); + histos.fill(HIST("Selection/Photon/h2d") + HIST(PhotonSelsLocal[selection_index]), sigma.photonPt(), sigma.photonMass()); + histos.fill(HIST("Selection/Sigma0/h2dPhoton") + HIST(PhotonSelsLocal[selection_index]), sigma.pt(), sigma.sigma0Mass()); + } + } + + if (PDGRequired == 3122) { + if constexpr (selection_index >= 0 && selection_index < (int)std::size(LambdaSelsLocal)) { + histos.fill(HIST("Selection/Lambda/hCandidateSel"), selection_index); + histos.fill(HIST("Selection/Lambda/h2d") + HIST(LambdaSelsLocal[selection_index]), sigma.lambdaPt(), sigma.lambdaMass()); + histos.fill(HIST("Selection/Sigma0/h2dLambda") + HIST(LambdaSelsLocal[selection_index]), sigma.pt(), sigma.sigma0Mass()); + } + } + } + + // Apply specific selections for photons + template + bool selectPhoton(TV0Object const& cand) + { + fillSelHistos<0>(cand, 22); + if (cand.photonV0Type() != photonSelections.Photonv0TypeSel && photonSelections.Photonv0TypeSel > -1) + return false; + + fillSelHistos<1>(cand, 22); + if ((TMath::Abs(cand.photonDCAPosPV()) < photonSelections.PhotonMinDCADauToPv) || (TMath::Abs(cand.photonDCANegPV()) < photonSelections.PhotonMinDCADauToPv)) + return false; + + fillSelHistos<2>(cand, 22); + if (TMath::Abs(cand.photonDCADau()) > photonSelections.PhotonMaxDCAV0Dau) + return false; + + fillSelHistos<3>(cand, 22); + if ((cand.photonPosTPCCrossedRows() < photonSelections.PhotonMinTPCCrossedRows) || (cand.photonNegTPCCrossedRows() < photonSelections.PhotonMinTPCCrossedRows)) + return false; + + fillSelHistos<4>(cand, 22); + if (((cand.photonPosTPCNSigmaEl() < photonSelections.PhotonMinTPCNSigmas) || (cand.photonPosTPCNSigmaEl() > photonSelections.PhotonMaxTPCNSigmas))) + return false; + + if (((cand.photonNegTPCNSigmaEl() < photonSelections.PhotonMinTPCNSigmas) || (cand.photonNegTPCNSigmaEl() > photonSelections.PhotonMaxTPCNSigmas))) + return false; + + fillSelHistos<5>(cand, 22); + if ((cand.photonPt() < photonSelections.PhotonMinPt) || (cand.photonPt() > photonSelections.PhotonMaxPt)) + return false; + + fillSelHistos<6>(cand, 22); + if ((TMath::Abs(cand.photonY()) > photonSelections.PhotonMaxRap) || (TMath::Abs(cand.photonPosEta()) > photonSelections.PhotonMaxDauEta) || (TMath::Abs(cand.photonNegEta()) > photonSelections.PhotonMaxDauEta)) + return false; + + fillSelHistos<7>(cand, 22); + if ((cand.photonRadius() < photonSelections.PhotonMinRadius) || (cand.photonRadius() > photonSelections.PhotonMaxRadius)) + return false; + + fillSelHistos<8>(cand, 22); + float photonRZLineCut = TMath::Abs(cand.photonZconv()) * TMath::Tan(2 * TMath::ATan(TMath::Exp(-photonSelections.PhotonMaxDauEta))) - photonSelections.PhotonLineCutZ0; + if ((TMath::Abs(cand.photonRadius()) < photonRZLineCut) || (TMath::Abs(cand.photonZconv()) > photonSelections.PhotonMaxZ)) + return false; + + fillSelHistos<9>(cand, 22); + if (cand.photonQt() > photonSelections.PhotonMaxQt) + return false; + + if (TMath::Abs(cand.photonAlpha()) > photonSelections.PhotonMaxAlpha) + return false; + + fillSelHistos<10>(cand, 22); + if (cand.photonCosPA() < photonSelections.PhotonMinV0cospa) + return false; + + fillSelHistos<11>(cand, 22); + if (TMath::Abs(cand.photonPsiPair()) > photonSelections.PhotonPsiPairMax) + return false; + + fillSelHistos<12>(cand, 22); + if ((((cand.photonPhi() > photonSelections.PhotonPhiMin1) && (cand.photonPhi() < photonSelections.PhotonPhiMax1)) || ((cand.photonPhi() > photonSelections.PhotonPhiMin2) && (cand.photonPhi() < photonSelections.PhotonPhiMax2))) && ((photonSelections.PhotonPhiMin1 != -1) && (photonSelections.PhotonPhiMax1 != -1) && (photonSelections.PhotonPhiMin2 != -1) && (photonSelections.PhotonPhiMax2 != -1))) + return false; + + fillSelHistos<13>(cand, 22); + if (TMath::Abs(cand.photonMass()) > photonSelections.PhotonMaxMass) + return false; + + fillSelHistos<14>(cand, 22); + return true; + } + + // Apply specific selections for lambdas + template + bool selectLambda(TV0Object const& cand) + { + fillSelHistos<0>(cand, 3122); + if ((cand.lambdaRadius() < lambdaSelections.LambdaMinv0radius) || (cand.lambdaRadius() > lambdaSelections.LambdaMaxv0radius)) + return false; + + fillSelHistos<1>(cand, 3122); + if (TMath::Abs(cand.lambdaDCADau()) > lambdaSelections.LambdaMaxDCAV0Dau) + return false; + + fillSelHistos<2>(cand, 3122); + if ((cand.lambdaQt() < lambdaSelections.LambdaMinQt) || (cand.lambdaQt() > lambdaSelections.LambdaMaxQt)) + return false; + + if ((TMath::Abs(cand.lambdaAlpha()) < lambdaSelections.LambdaMinAlpha) || (TMath::Abs(cand.lambdaAlpha()) > lambdaSelections.LambdaMaxAlpha)) + return false; + + fillSelHistos<3>(cand, 3122); + if (cand.lambdaCosPA() < lambdaSelections.LambdaMinv0cospa) + return false; + + fillSelHistos<4>(cand, 3122); + if ((TMath::Abs(cand.lambdaY()) > lambdaSelections.LambdaMaxRap) || (TMath::Abs(cand.lambdaPosEta()) > lambdaSelections.LambdaMaxDauEta) || (TMath::Abs(cand.lambdaNegEta()) > lambdaSelections.LambdaMaxDauEta)) + return false; + + fillSelHistos<5>(cand, 3122); + if ((cand.lambdaPosTPCCrossedRows() < lambdaSelections.LambdaMinTPCCrossedRows) || (cand.lambdaNegTPCCrossedRows() < lambdaSelections.LambdaMinTPCCrossedRows)) + return false; + + fillSelHistos<6>(cand, 3122); + // 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() < lambdaSelections.LambdaMinITSclusters && (!lambdaSelections.LambdaRejectPosITSafterburner || posIsFromAfterburner)) + return false; + if (cand.lambdaNegITSCls() < lambdaSelections.LambdaMinITSclusters && (!lambdaSelections.LambdaRejectNegITSafterburner || negIsFromAfterburner)) + return false; + + fillSelHistos<7>(cand, 3122); + if (cand.lambdaLifeTime() > lambdaSelections.LambdaMaxLifeTime) + return false; + + // Separating lambda and antilambda selections: + fillSelHistos<8>(cand, 3122); + if (cand.lambdaAlpha() > 0) { // Lambda selection + // TPC Selection + if (lambdaSelections.fselLambdaTPCPID && (TMath::Abs(cand.lambdaPosPrTPCNSigma()) > lambdaSelections.LambdaMaxTPCNSigmas)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 5.); - if ((cand.photonPosTPCNSigma() < PhotonMinTPCNSigmas) || (cand.photonPosTPCNSigma() > PhotonMaxTPCNSigmas)) + if (lambdaSelections.fselLambdaTPCPID && (TMath::Abs(cand.lambdaNegPiTPCNSigma()) > lambdaSelections.LambdaMaxTPCNSigmas)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 6.); - if ((cand.photonNegTPCNSigma() < PhotonMinTPCNSigmas) || (cand.photonNegTPCNSigma() > PhotonMaxTPCNSigmas)) + + // TOF Selection + if (lambdaSelections.fselLambdaTOFPID && (TMath::Abs(cand.lambdaPrTOFNSigma()) > lambdaSelections.LambdaPrMaxTOFNSigmas)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 7.); - if ((cand.photonPt() < PhotonMinPt) || (cand.photonPt() > PhotonMaxPt)) + if (lambdaSelections.fselLambdaTOFPID && (TMath::Abs(cand.lambdaPiTOFNSigma()) > lambdaSelections.LambdaPiMaxTOFNSigmas)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 8.); - if (TMath::Abs(cand.photonEta()) > PhotonMaxPseudoRap) + + // DCA Selection + fillSelHistos<9>(cand, 3122); + if ((TMath::Abs(cand.lambdaDCAPosPV()) < lambdaSelections.LambdaMinDCAPosToPv) || (TMath::Abs(cand.lambdaDCANegPV()) < lambdaSelections.LambdaMinDCANegToPv)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 9.); - if ((cand.photonRadius() < PhotonMinRadius) || (cand.photonRadius() > PhotonMaxRadius)) + + // Mass Selection + fillSelHistos<10>(cand, 3122); + if (TMath::Abs(cand.lambdaMass() - o2::constants::physics::MassLambda0) > lambdaSelections.LambdaWindow) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 10.); - if (TMath::Abs(cand.photonZconv()) > PhotonMaxZ) + + fillSelHistos<11>(cand, 3122); + + } else { // AntiLambda selection + + // TPC Selection + if (lambdaSelections.fselLambdaTPCPID && (TMath::Abs(cand.lambdaPosPiTPCNSigma()) > lambdaSelections.LambdaMaxTPCNSigmas)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 11.); - if (cand.photonQt() > PhotonMaxQt) + if (lambdaSelections.fselLambdaTPCPID && (TMath::Abs(cand.lambdaNegPrTPCNSigma()) > lambdaSelections.LambdaMaxTPCNSigmas)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 12.); - if (TMath::Abs(cand.photonAlpha()) > PhotonMaxAlpha) + + // TOF Selection + if (lambdaSelections.fselLambdaTOFPID && (TMath::Abs(cand.aLambdaPrTOFNSigma()) > lambdaSelections.LambdaPrMaxTOFNSigmas)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 13.); - if (cand.photonCosPA() < PhotonMinV0cospa) + if (lambdaSelections.fselLambdaTOFPID && (TMath::Abs(cand.aLambdaPiTOFNSigma()) > lambdaSelections.LambdaPiMaxTOFNSigmas)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 14.); - // Lambda selection - if (TMath::Abs(cand.lambdaMass() - 1.115683) > LambdaWindow) + // DCA Selection + fillSelHistos<9>(cand, 3122); + if ((TMath::Abs(cand.lambdaDCAPosPV()) < lambdaSelections.ALambdaMinDCAPosToPv) || (TMath::Abs(cand.lambdaDCANegPV()) < lambdaSelections.ALambdaMinDCANegToPv)) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 15.); - if ((TMath::Abs(cand.lambdaDCAPosPV()) < LambdaMinDCAPosToPv) || (TMath::Abs(cand.lambdaDCANegPV()) < LambdaMinDCANegToPv)) - return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 16.); - if ((cand.lambdaRadius() < LambdaMinv0radius) || (cand.lambdaRadius() > LambdaMaxv0radius)) + + // Mass Selection + fillSelHistos<10>(cand, 3122); + if (TMath::Abs(cand.antilambdaMass() - o2::constants::physics::MassLambda0) > lambdaSelections.LambdaWindow) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 17.); - if (TMath::Abs(cand.lambdaDCADau()) > LambdaMaxDCAV0Dau) + + fillSelHistos<11>(cand, 3122); + } + + return true; + } + + // Apply selections in sigma0 candidates + template + bool processSigma0Candidate(TSigma0Object const& cand) + { + // Photon specific selections + if (!selectPhoton(cand)) + return false; + + // Lambda specific selections + if (!selectLambda(cand)) + return false; + + // Sigma0 specific selections + // Rapidity + if constexpr (requires { cand.sigma0MCY(); }) { // MC + if (TMath::Abs(cand.sigma0MCY()) > sigma0Selections.Sigma0MaxRap) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 18.); - if ((cand.lambdaQt() < LambdaMinQt) || (cand.lambdaQt() > LambdaMaxQt)) + } else { // Real data + if (TMath::Abs(cand.sigma0Y()) > sigma0Selections.Sigma0MaxRap) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 19.); - if ((TMath::Abs(cand.lambdaAlpha()) < LambdaMinAlpha) || (TMath::Abs(cand.lambdaAlpha()) > LambdaMaxAlpha)) + } + + // V0Pair Radius + if (cand.radius() > sigma0Selections.Sigma0MaxRadius) + return false; + + // DCA V0Pair Daughters + if (cand.dcadaughters() > sigma0Selections.Sigma0MaxDCADau) + return false; + + // Opening Angle + if (cand.opAngle() > sigma0Selections.Sigma0MaxOPAngle) + return false; + + return true; + } + + // Main analysis function + template + void analyzeRecoeSigma0s(TCollisions const& collisions, TSigma0s const& fullSigma0s) + { + // Custom grouping + std::vector> sigma0grouped(collisions.size()); + + for (const auto& sigma0 : fullSigma0s) { + sigma0grouped[sigma0.straCollisionId()].push_back(sigma0.globalIndex()); + } + + // Collisions loop + for (const auto& coll : collisions) { + + // Event selection + if (!IsEventAccepted(coll, true)) + continue; + + // Sigma0s loop + for (size_t i = 0; i < sigma0grouped[coll.globalIndex()].size(); i++) { + auto sigma0 = fullSigma0s.rawIteratorAt(sigma0grouped[coll.globalIndex()][i]); + + // if MC + if constexpr (requires { sigma0.isSigma0(); sigma0.isAntiSigma0(); }) { + if (doMCAssociation && !(sigma0.isSigma0() || sigma0.isAntiSigma0())) + continue; + + if (selRecoFromGenerator && !sigma0.isProducedByGenerator()) + continue; + } + + // Fill histos before any selection + fillHistos<0>(sigma0, coll); + + // Select sigma0 candidates + if (!processSigma0Candidate(sigma0)) + continue; + + // Fill histos after all selections + fillHistos<1>(sigma0, coll); + } + } + } + + // Apply selections in sigma0 candidates + template + bool processPi0Candidate(TPi0Object const& cand) + { + if ((cand.photon1V0Type() != photonSelections.Photonv0TypeSel || cand.photon2V0Type() != photonSelections.Photonv0TypeSel) && photonSelections.Photonv0TypeSel > -1) + return false; + + if ((TMath::Abs(cand.photon1DCAPosPV()) < photonSelections.PhotonMinDCADauToPv) || + (TMath::Abs(cand.photon2DCAPosPV()) < photonSelections.PhotonMinDCADauToPv) || + (TMath::Abs(cand.photon1DCANegPV()) < photonSelections.PhotonMinDCADauToPv) || + (TMath::Abs(cand.photon2DCANegPV()) < photonSelections.PhotonMinDCADauToPv)) + return false; + + if ((TMath::Abs(cand.photon1DCADau()) > photonSelections.PhotonMaxDCAV0Dau) || (TMath::Abs(cand.photon2DCADau()) > photonSelections.PhotonMaxDCAV0Dau)) + return false; + + if ((cand.photon1PosTPCCrossedRows() < photonSelections.PhotonMinTPCCrossedRows) || + (cand.photon2PosTPCCrossedRows() < photonSelections.PhotonMinTPCCrossedRows) || + (cand.photon1NegTPCCrossedRows() < photonSelections.PhotonMinTPCCrossedRows) || + (cand.photon2NegTPCCrossedRows() < photonSelections.PhotonMinTPCCrossedRows)) + return false; + + if (((cand.photon1PosTPCNSigmaEl() < photonSelections.PhotonMinTPCNSigmas) || + (cand.photon1PosTPCNSigmaEl() > photonSelections.PhotonMaxTPCNSigmas)) || + ((cand.photon2PosTPCNSigmaEl() < photonSelections.PhotonMinTPCNSigmas) || + (cand.photon2PosTPCNSigmaEl() > photonSelections.PhotonMaxTPCNSigmas))) + return false; + + if (((cand.photon1NegTPCNSigmaEl() < photonSelections.PhotonMinTPCNSigmas) || + (cand.photon1NegTPCNSigmaEl() > photonSelections.PhotonMaxTPCNSigmas)) || + ((cand.photon2NegTPCNSigmaEl() < photonSelections.PhotonMinTPCNSigmas) || + (cand.photon2NegTPCNSigmaEl() > photonSelections.PhotonMaxTPCNSigmas))) + return false; + + if (((cand.photon1Pt() < photonSelections.PhotonMinPt) || + (cand.photon1Pt() > photonSelections.PhotonMaxPt)) || + ((cand.photon2Pt() < photonSelections.PhotonMinPt) || + (cand.photon2Pt() > photonSelections.PhotonMaxPt))) + return false; + + if ((TMath::Abs(cand.photon1Y()) > photonSelections.PhotonMaxRap) || (TMath::Abs(cand.photon1PosEta()) > photonSelections.PhotonMaxDauEta) || (TMath::Abs(cand.photon1NegEta()) > photonSelections.PhotonMaxDauEta)) + return false; + + if ((TMath::Abs(cand.photon2Y()) > photonSelections.PhotonMaxRap) || (TMath::Abs(cand.photon2PosEta()) > photonSelections.PhotonMaxDauEta) || (TMath::Abs(cand.photon2NegEta()) > photonSelections.PhotonMaxDauEta)) + return false; + + if (((cand.photon1Radius() < photonSelections.PhotonMinRadius) || (cand.photon1Radius() > photonSelections.PhotonMaxRadius)) || + ((cand.photon2Radius() < photonSelections.PhotonMinRadius) || (cand.photon2Radius() > photonSelections.PhotonMaxRadius))) + return false; + + if ((cand.photon1Qt() > photonSelections.PhotonMaxQt) || cand.photon2Qt() > photonSelections.PhotonMaxQt) + return false; + + if ((TMath::Abs(cand.photon1Alpha()) > photonSelections.PhotonMaxAlpha) || (TMath::Abs(cand.photon2Alpha()) > photonSelections.PhotonMaxAlpha)) + return false; + + if ((cand.photon1CosPA() < photonSelections.PhotonMinV0cospa) || (cand.photon2CosPA() < photonSelections.PhotonMinV0cospa)) + return false; + + if ((TMath::Abs(cand.photon1Mass()) > photonSelections.PhotonMaxMass) || (TMath::Abs(cand.photon2Mass()) > photonSelections.PhotonMaxMass)) + return false; + + // Pi0 specific selections + if constexpr (requires { cand.pi0MCY(); }) { // MC + if (TMath::Abs(cand.pi0MCY()) > pi0Selections.Pi0MaxRap) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 20.); - if (cand.lambdaCosPA() < LambdaMinv0cospa) + } else { // DATA + if (TMath::Abs(cand.pi0Y()) > pi0Selections.Pi0MaxRap) return false; - histos.fill(HIST("GeneralQA/hCandidateAnalysisSelection"), 21.); } + // V0Pair Radius + if (cand.radius() > pi0Selections.Pi0MaxRadius) + return false; + + // DCA V0Pair Daughters + if (cand.dcadaughters() > pi0Selections.Pi0MaxDCADau) + return false; + return true; } - // This process function cross-checks index correctness - // void processCounterQA(V0Sigmas const& v0s) - // { - // for (auto& gamma : v0s) { - // histos.fill(HIST("hGammaIndices"), gamma.globalIndex()); - // histos.fill(HIST("hCollIndices"), gamma.straCollisionId()); - // histos.fill(HIST("h2dIndices"), gamma.straCollisionId(), gamma.globalIndex()); - // } - // } - - void processMonteCarlo(aod::Sigma0Collision const& coll, V0MCSigmas const& v0s) + // Main Pi0 QA analysis function + template + void analyzeRecoePi0s(TCollisions const& collisions, TPi0s const& fullPi0s) { - histos.fill(HIST("hMCEventCentrality"), coll.centFT0C()); - for (auto& sigma : v0s) { // selecting Sigma0-like candidates - if (sigma.isSigma()) { - histos.fill(HIST("GeneralQA/h2dMCArmenterosAll"), sigma.photonAlpha(), sigma.photonQt()); - histos.fill(HIST("GeneralQA/h2dMCArmenterosAll"), sigma.lambdaAlpha(), sigma.lambdaQt()); - histos.fill(HIST("GeneralQA/hMCMassSigma0All"), sigma.sigmaMass()); - histos.fill(HIST("GeneralQA/hMCPtSigma0All"), sigma.sigmapT()); - - if (!processSigmaCandidate(sigma)) + // Custom grouping + std::vector> pi0grouped(collisions.size()); + + for (const auto& pi0 : fullPi0s) { + pi0grouped[pi0.straCollisionId()].push_back(pi0.globalIndex()); + } + + // Collisions loop + for (const auto& coll : collisions) { + + // Event selection + if (!IsEventAccepted(coll, true)) + continue; + + // Pi0s loop + float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); + + for (size_t i = 0; i < pi0grouped[coll.globalIndex()].size(); i++) { + auto pi0 = fullPi0s.rawIteratorAt(pi0grouped[coll.globalIndex()][i]); + + // Select sigma0 candidates + if (!processPi0Candidate(pi0)) continue; - histos.fill(HIST("GeneralQA/h2dMCArmenterosSelected"), sigma.photonAlpha(), sigma.photonQt()); - histos.fill(HIST("GeneralQA/h2dMCArmenterosSelected"), sigma.lambdaAlpha(), sigma.lambdaQt()); + // If MC + if constexpr (requires { pi0.isPi0(); }) { + if (selRecoFromGenerator && !pi0.isProducedByGenerator()) + continue; - histos.fill(HIST("Sigma0/hMCMassSigma0"), sigma.sigmaMass()); - histos.fill(HIST("Sigma0/hMCPtSigma0"), sigma.sigmapT()); + if (pi0.isPi0()) + histos.fill(HIST("Pi0/h3dMass_MCAssociated"), centrality, pi0.mcpt(), pi0.pi0Mass()); + } - histos.fill(HIST("h3dMCMassSigma0"), coll.centFT0C(), sigma.sigmapT(), sigma.sigmaMass()); + // Fill histos after all selections + histos.fill(HIST("Pi0/hMass"), pi0.pi0Mass()); + histos.fill(HIST("Pi0/hPt"), pi0.pt()); + histos.fill(HIST("Pi0/hY"), pi0.pi0Y()); + histos.fill(HIST("Pi0/h3dMass"), centrality, pi0.pt(), pi0.pi0Mass()); } } } - void processRealData(aod::Sigma0Collision const& coll, V0Sigmas const& v0s) + void processRealData(soa::Join const& collisions, Sigma0s const& fullSigma0s) { - histos.fill(HIST("hEventCentrality"), coll.centFT0C()); - for (auto& sigma : v0s) { // selecting Sigma0-like candidates - histos.fill(HIST("GeneralQA/h2dArmenterosAll"), sigma.photonAlpha(), sigma.photonQt()); - histos.fill(HIST("GeneralQA/h2dArmenterosAll"), sigma.lambdaAlpha(), sigma.lambdaQt()); - histos.fill(HIST("GeneralQA/hMassSigma0All"), sigma.sigmaMass()); - - nSigmaCandidates++; - if (nSigmaCandidates % 50000 == 0) { - LOG(info) << "Sigma0 Candidates processed: " << nSigmaCandidates; - } - if (!processSigmaCandidate(sigma)) - continue; + analyzeRecoeSigma0s(collisions, fullSigma0s); + } + + void processMonteCarlo(soa::Join const& collisions, MCSigma0s const& fullSigma0s) + { + analyzeRecoeSigma0s(collisions, fullSigma0s); + } - histos.fill(HIST("GeneralQA/h2dArmenterosSelected"), sigma.photonAlpha(), sigma.photonQt()); - histos.fill(HIST("GeneralQA/h2dArmenterosSelected"), sigma.lambdaAlpha(), sigma.lambdaQt()); + // Simulated processing in Run 3 + void processGeneratedRun3(soa::Join const& mcCollisions, soa::Join const& collisions, soa::Join const& Sigma0Gens) + { + analyzeGenerated(mcCollisions, collisions, Sigma0Gens); + } - histos.fill(HIST("Sigma0/hMassSigma0"), sigma.sigmaMass()); - histos.fill(HIST("Sigma0/hPtSigma0"), sigma.sigmapT()); - histos.fill(HIST("Sigma0/hRapiditySigma0"), sigma.sigmaRapidity()); - histos.fill(HIST("h3dMassSigma0"), coll.centFT0C(), sigma.sigmapT(), sigma.sigmaMass()); + // _____________________________________________________ + // Pi0 QA + void processPi0RealData(soa::Join const& collisions, soa::Join const& fullPi0s) + { + analyzeRecoePi0s(collisions, fullPi0s); + } - histos.fill(HIST("Gamma/hMassGamma"), sigma.lambdaMass()); - histos.fill(HIST("Lambda/hMassLambda"), sigma.photonMass()); - } + void processPi0MonteCarlo(soa::Join const& collisions, soa::Join const& fullPi0s) + { + analyzeRecoePi0s(collisions, fullPi0s); } - // PROCESS_SWITCH(sigmaanalysis, processCounterQA, "Check standard counter correctness", true); - PROCESS_SWITCH(sigmaanalysis, processMonteCarlo, "Do Monte-Carlo-based analysis", false); + void processPi0GeneratedRun3(soa::Join const& mcCollisions, soa::Join const& collisions, soa::Join const& Pi0Gens) + { + analyzeGenerated(mcCollisions, collisions, Pi0Gens); + } + + // _____________________________________________________ PROCESS_SWITCH(sigmaanalysis, processRealData, "Do real data analysis", true); + PROCESS_SWITCH(sigmaanalysis, processMonteCarlo, "Do Monte-Carlo-based analysis", false); + PROCESS_SWITCH(sigmaanalysis, processGeneratedRun3, "process MC generated Run 3", false); + PROCESS_SWITCH(sigmaanalysis, processPi0RealData, "Do real data analysis for pi0 QA", false); + PROCESS_SWITCH(sigmaanalysis, processPi0MonteCarlo, "Do Monte-Carlo-based analysis for pi0 QA", false); + PROCESS_SWITCH(sigmaanalysis, processPi0GeneratedRun3, "process MC generated Run 3 for pi0 QA", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/sjetTreeCreator.cxx b/PWGLF/Tasks/Strangeness/sjetTreeCreator.cxx new file mode 100644 index 00000000000..08bb83a3c89 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/sjetTreeCreator.cxx @@ -0,0 +1,514 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file sjetTreeCreator.cxx +/// \brief Task for building a TTree with information about the jet, its consistuents, +/// to be used as input for machine learning s-jet identification. +/// \author Lorenzo Bernardinis (lorenzo.bernardinis@cern.ch) +/// +/// Inspired by PWGJE/Tasks/bjetTreeCreator.cxx + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetTaggingUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGJE/DataModel/JetTagging.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include +#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; + +namespace o2::aod +{ +namespace jet_info +{ +// 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, jetMass, float); //! The jet mass +DECLARE_SOA_COLUMN(JetFlavor, jetFlavor, int16_t); //! The jet flavor (b, c, s or udg) +DECLARE_SOA_COLUMN(JetR, jetR, int16_t); //! The jet radius +} // namespace jet_info + +DECLARE_SOA_TABLE(sjetParams, "AOD", "SJETPARAM", + o2::soa::Index<>, + jet_info::JetpT, + jet_info::JetEta, + jet_info::JetPhi, + jet_info::NTracks, + jet_info::JetMass, + jet_info::JetFlavor, + jet_info::JetR); + +using sjetParam = sjetParams::iterator; + +namespace track_info +{ +DECLARE_SOA_INDEX_COLUMN(sjetParam, 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, dotProdTrackJet, float); //! The dot product between the track and the jet +DECLARE_SOA_COLUMN(DotProdTrackJetOverJet, dotProdTrackJetOverJet, float); //! The dot product between the track and the jet over the jet momentum +DECLARE_SOA_COLUMN(DeltaRJetTrack, deltaRJetTrack, float); //! The DR jet-track +DECLARE_SOA_COLUMN(SignedIP2D, signedIP2D, float); //! The track signed 2D IP +DECLARE_SOA_COLUMN(SignedIP2DSign, signedIP2DSign, float); //! The track signed 2D IP significance +DECLARE_SOA_COLUMN(SignedIPz, signedIPz, float); //! The track signed z IP +DECLARE_SOA_COLUMN(SignedIPzSign, signedIPzSign, float); //! The track signed z IP significance +DECLARE_SOA_COLUMN(SignedIP3DSign, signedIP3DSign, float); //! The track signed 3D IP significance +DECLARE_SOA_COLUMN(MomFraction, momFraction, float); //! The track momentum fraction of the jets +DECLARE_SOA_COLUMN(DeltaRTrackVertex, deltaRTrackVertex, 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, trackOrigin, int); //! The track origin label for GNN track origin predictions +DECLARE_SOA_COLUMN(TrackVtxIndex, trackVtxIndex, 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 track_info + +DECLARE_SOA_TABLE(sjetTracksParams, "AOD", "SJETTRACKSPARAM", + o2::soa::Index<>, + track_info::sjetParamId, + track_info::TrackpT, + track_info::TrackEta, + track_info::DotProdTrackJet, + track_info::DotProdTrackJetOverJet, + track_info::DeltaRJetTrack, + track_info::SignedIP2D, + track_info::SignedIP2DSign, + track_info::SignedIPz, + track_info::SignedIPzSign, + track_info::SignedIP3DSign, + track_info::MomFraction, + track_info::DeltaRTrackVertex); + +using sjetTracksParam = sjetTracksParams::iterator; + +DECLARE_SOA_TABLE(sjetTracksParamsExtra, "AOD", "SJETTRACKSEXTRA", + // o2::soa::Index<>, + track_info::TrackPhi, + track_info::TrackCharge, + track_info::TrackITSChi2NCl, + track_info::TrackTPCChi2NCl, + track_info::TrackITSNCls, + track_info::TrackTPCNCls, + track_info::TrackTPCNCrossedRows); + +using sjetTracksParamExtra = sjetTracksParamsExtra::iterator; + +namespace constituents +{ +DECLARE_SOA_INDEX_COLUMN(sjetParam, jetindex); +DECLARE_SOA_ARRAY_INDEX_COLUMN(sjetTracksParam, tracks); +} // namespace constituents + +DECLARE_SOA_TABLE(sjetConstituents, "AOD", "SJETCONSTIT", + constituents::sjetParamId, + constituents::sjetTracksParamIds); + +} // namespace o2::aod + +struct SjetTreeCreator { + + Produces sjetParamsTable; + Produces sjetTracksParamsTable; + Produces sjetTracksExtraTable; + Produces sjetConstituentsTable; + + 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 maxIPxy{"maxIPxy", 10, "maximum track DCA in xy plane"}; + Configurable maxIPz{"maxIPz", 10, "maximum track DCA in z direction"}; + + // 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 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_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_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}}}); + + if (doprocessMCJets) { + registry.add("h2_SIPs2D_jetpT_hfjet", "2D IP significance hf-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_hfjet", "3D IP significance hf-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_jetMass_jetpT_hfjet", "Jet mass hf-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("h_jetpT_detector_hfjet", "Jet transverse momentum hf-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + + registry.add("h2_SIPs2D_jetpT_sjet", "2D IP significance s-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_sjet", "3D IP significance s-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_jetMass_jetpT_sjet", "Jet mass s-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("h_jetpT_detector_sjet", "Jet transverse momentum s-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + + registry.add("h2_SIPs2D_jetpT_udgjet", "2D IP significance udg-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_SIPs3D_jetpT_udgjet", "3D IP significance udg-jets;#it{p}_{T,jet} (GeV/#it{c});IPs", {HistType::kTH2F, {{200, 0., 200.}, {100, -50.0, 50.0}}}); + registry.add("h2_jetMass_jetpT_udgjet", "Jet mass udg-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("h_jetpT_detector_udgjet", "Jet transverse momentum udg-jets;#it{p}_{T,jet} (GeV/#it{c})", {HistType::kTH1F, {{200, 0., 200.0}}}); + + // Jet information + 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., o2::constants::math::TwoPI}}}); + 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.}}}); + + registry.add("h_jet_flav", "jet_flav;jet flavor;Entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}); + auto hJetFlavor = registry.get(HIST("h_jet_flav")); + hJetFlavor->GetXaxis()->SetBinLabel(1, "no mcparticle"); // bin 1 + hJetFlavor->GetXaxis()->SetBinLabel(2, "hf-jet"); // bin 2 --> flavour number 1+2 + hJetFlavor->GetXaxis()->SetBinLabel(3, "s-jet"); // bin 3 --> flavour number 7 + hJetFlavor->GetXaxis()->SetBinLabel(4, "udg-jet"); // bin 4 --> flavour number 6 + + // Track information + 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., o2::constants::math::TwoPI}}}); + 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.}}}); + } + } + + // 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(); + } + + template + void analyzeJetTrackInfo(AnyCollision const& /*collision*/, + AnalysisJet const& analysisJet, + AnyTracks const& /*allTracks*/, + AnyOriginalTracks const&, + std::vector& trackIndices, + int 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); + + 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 == JetTaggingSpecies::beauty || jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_SIPs2D_jetpT_hfjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_hfjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } else if (jetFlavor == JetTaggingSpecies::strange) { + registry.fill(HIST("h2_SIPs2D_jetpT_sjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_sjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } else { + registry.fill(HIST("h2_SIPs2D_jetpT_udgjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXY()) / constituent.sigmadcaXY(), eventweight); + registry.fill(HIST("h2_SIPs3D_jetpT_udgjet"), analysisJet.pt(), sign * std::abs(constituent.dcaXYZ()) / constituent.sigmadcaXYZ(), eventweight); + } + + auto origConstit = constituent.template track_as(); + + // Track information + 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); + + if (produceTree) { + sjetTracksExtraTable(/*sjetParamsTable.lastIndex() + 1, */ + origConstit.phi(), + constituent.sign(), + origConstit.itsChi2NCl(), + origConstit.tpcChi2NCl(), + origConstit.itsNCls(), + origConstit.tpcNClsFound(), + origConstit.tpcNClsCrossedRows()); + + sjetTracksParamsTable(sjetParamsTable.lastIndex() + 1, + constituent.pt(), + constituent.eta(), + dotProduct, + dotProduct / analysisJet.p(), + deltaRJetTrack, + std::abs(constituent.dcaXY()) * sign, + constituent.sigmadcaXY(), + std::abs(constituent.dcaZ()) * sign, + constituent.sigmadcaZ(), + constituent.sigmadcaXYZ(), + constituent.p() / analysisJet.p(), + 0.); + } + trackIndices.push_back(sjetTracksParamsTable.lastIndex()); + } + } + } + + void processDummy(FilteredCollision::iterator const& /*collision*/) + { + } + PROCESS_SWITCH(SjetTreeCreator, processDummy, "Dummy process function turned on by default", true); + + using MCDJetTable = soa::Filtered>; + + using MCPJetTable = soa::Filtered>; + + using FilteredCollisionMCD = soa::Filtered>; + + Preslice mcParticlesPerCollision = aod::jmcparticle::mcCollisionId; + Preslice mcpJetsPerCollision = aod::jet::mcCollisionId; + + using MCDJetTableNoSV = soa::Filtered>; + + using JetParticleswID = soa::Join; + + void processMCJets(FilteredCollisionMCD::iterator const& collision, + aod::JMcCollisions const&, + MCDJetTableNoSV const& MCDjets, + MCPJetTable const& MCPjets, + JetTracksMCDwID const& allTracks, + JetParticleswID const& MCParticles, + OriginalTracks const& origTracks) + { + 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 (const auto& jetR : jetRadiiValues) { + if (analysisJet.r() == static_cast(jetR * 100)) { + jetIncluded = true; + break; + } + } + + if (!jetIncluded) { + continue; + } + + std::vector indicesTracks; + + int16_t jetFlavorIdx = 0; + int16_t jetFlavor = 0; + + for (const auto& mcpjet : analysisJet.template matchedJetGeo_as()) { + jetFlavor = jettaggingutilities::getSJetFlavor(mcpjet, mcParticlesPerColl); + } + + if (jetFlavor == JetTaggingSpecies::strange) { + jetFlavorIdx = 2; + } else if (jetFlavor == JetTaggingSpecies::udg) { + jetFlavorIdx = 3; + } else if (jetFlavor == JetTaggingSpecies::charm || jetFlavor == JetTaggingSpecies::beauty) { + jetFlavorIdx = 1; + } else { + jetFlavorIdx = jetFlavor; + } + + if ((jetFlavor != JetTaggingSpecies::strange) && + (static_cast(std::rand()) / RAND_MAX < getReductionFactor(analysisJet.pt()))) { + continue; + } + + float eventWeight = analysisJet.eventWeight(); + + analyzeJetTrackInfo(collision, analysisJet, allTracks, origTracks, indicesTracks, jetFlavor, eventWeight); + + registry.fill(HIST("h2_jetMass_jetpT"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h2_nTracks_jetpT"), analysisJet.pt(), indicesTracks.size()); + + // Jet info + 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"), jetFlavorIdx); + registry.fill(HIST("h_n_trks"), indicesTracks.size()); + registry.fill(HIST("h_jet_mass"), analysisJet.mass()); + + if (jetFlavor == JetTaggingSpecies::beauty || jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_jetMass_jetpT_hfjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_hfjet"), analysisJet.pt(), eventWeight); + } else if (jetFlavor == JetTaggingSpecies::strange) { + registry.fill(HIST("h2_jetMass_jetpT_sjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_sjet"), analysisJet.pt(), eventWeight); + } else { + registry.fill(HIST("h2_jetMass_jetpT_udgjet"), analysisJet.pt(), analysisJet.mass(), eventWeight); + registry.fill(HIST("h_jetpT_detector_udgjet"), analysisJet.pt(), eventWeight); + } + + if (produceTree) { + sjetConstituentsTable(sjetParamsTable.lastIndex() + 1, indicesTracks); + sjetParamsTable(analysisJet.pt(), + analysisJet.eta(), + analysisJet.phi(), + indicesTracks.size(), + analysisJet.mass(), + jetFlavor, + analysisJet.r()); + } + } + } + PROCESS_SWITCH(SjetTreeCreator, processMCJets, "jet information in MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/strangeCascTrack.cxx b/PWGLF/Tasks/Strangeness/strangeCascTrack.cxx new file mode 100644 index 00000000000..95016b22001 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/strangeCascTrack.cxx @@ -0,0 +1,1207 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file strangeCascTrack.cxx +/// \brief Analysis of strangeness tracking efficiency via primary production of Omega and Xi in Run 3 +/// \author Yakiv Paroviak (yakiv.paroviak@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include + +#include "TF1.h" +#include "TF2.h" +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::constants::math; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// tables for derived data +using DerCollisionWMults = soa::Join; +using DerCascDatas = soa::Join; +using DerTraCascDatas = soa::Join; + +// tables for derived MC +using DerMCGenCascades = soa::Join; +using DerMCRecCollisions = soa::Join; +using DerMCRecCascDatas = soa::Join; +using DerMCRecTraCascDatas = soa::Join; + +// tables for PID selection +using DauTracks = soa::Join; + +struct StrangeCascTrack { + + Service ccdb; + Service pdgDB; + + PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // subprocess switches: + // Configurable doProcessDirectData{"doProcessDirectData", false, "true for direct data, false for derived data"}; + + Configurable doProcesspp{"doProcesspp", true, "true for pp"}; + Configurable doProcessPbPb{"doProcessPbPb", false, "true for PbPb"}; + Configurable doProcessOO{"doProcessOO", false, "true for OO"}; + Configurable doProcesspO{"doProcesspO", false, "true for pO"}; + + Configurable doApplyEventCuts{"doApplyEventCuts", true, "apply general event cuts"}; // event filter - PVz, sel8, INEL>0 + // Xi selections + Configurable doApplyPtCutsXi{"doApplyPtCutsXi", true, "apply pt cuts (Xi)"}; // ignore particles with extremely low efficiencies + Configurable doApplyGenCutsXi{"doApplyGenCutsXi", true, "apply general cuts (Xi)"}; // general cascade cuts - cosPA, TPC hits etc. + Configurable doApplyTPCPIDXi{"doApplyTPCPIDXi", true, "apply tpc pid to dau tracks (Xi)"}; + Configurable doApplyTOFPIDXi{"doApplyTOFPIDXi", true, "apply tof pid to dau tracks (Xi)"}; + // Omega selections + Configurable doApplyPtCutsOmega{"doApplyPtCutsOmega", true, "apply pt cuts (Omega)"}; + Configurable doApplyGenCutsOmega{"doApplyGenCutsOmega", true, "apply general cuts (Omega)"}; + Configurable doApplyTPCPIDOmega{"doApplyTPCPIDOmega", true, "apply tpc pid to dau tracks (Omega)"}; + Configurable doApplyTOFPIDOmega{"doApplyTOFPIDOmega", true, "apply tof pid to dau tracks (Omega)"}; + Configurable doCompetingMassRej{"doCompetingMassRej", true, "competing mass rejection (Omega)"}; + // efficiency and purity corrections on the fly (warning: to be avoided because interpolation causes errors): + // only correct by pt + Configurable doApplyEfficiency1D{"doApplyEfficiency1D", false, "apply efficiency correction"}; + Configurable doPropagateEfficiency1D{"doPropagateEfficiency1D", false, "apply efficiency propagation"}; + Configurable doApplyPurity1D{"doApplyPurity1D", false, "apply purity correction"}; + Configurable doPropagatePurity1D{"doPropagatePurity1D", false, "apply purity propagation"}; + // correct by both pt and mult + Configurable doApplyEfficiency2D{"doApplyEfficiency2D", false, "apply efficiency correction"}; + Configurable doPropagateEfficiency2D{"doPropagateEfficiency2D", false, "apply efficiency propagation"}; + Configurable doApplyPurity2D{"doApplyPurity2D", false, "apply purity correction"}; + Configurable doPropagatePurity2D{"doPropagatePurity2D", false, "apply purity propagation"}; + Configurable ccdburl{"ccdburl", "http://alice-ccdb.cern.ch", "url of the ccdb repository to use"}; + Configurable efficiencyCCDBPathpp{"efficiencyCCDBPathpp", "Users/y/yparovia/LHC24f4d", "Path of the efficiency and purity corrections (pp)"}; + Configurable efficiencyCCDBPathPbPb{"efficiencyCCDBPathPbPb", "Users/y/yparovia/LHC25f3", "Path of the efficiency and purity corrections (PbPb)"}; + Configurable efficiencyCCDBPathOO{"efficiencyCCDBPathOO", "Users/y/yparovia/LHC25h3", "Path of the efficiency and purity corrections (OO)"}; + Configurable efficiencyCCDBPathpO{"efficiencyCCDBPathpO", "Users/y/yparovia/LHC25h2", "Path of the efficiency and purity corrections (pO)"}; + + // event and dau track selection + struct : ConfigurableGroup { + // event cuts + Configurable cutDoINEL{"cutDoINEL", true, "choose events with INEL>0"}; + Configurable cutZVertex{"cutZVertex", 10.0f, "max Z-vertex position"}; + Configurable cutDoSel8{"cutDoSel8", true, "choose events with sel8"}; + // cascade cuts + Configurable cutDoPropagateDCA{"cutDoPropagateDCA", false, "choose events with sel8"}; + Configurable cutPropDCAtoPVxy{"cutPropDCAtoPVxy", 0.02f, "max cascade dca to PV in xy - propagated"}; + Configurable cutPropDCAtoPVz{"cutPropDCAtoPVz", 0.02f, "max cascade dca to PV in z - propagated"}; + Configurable cutNClsTPC{"cutNClsTPC", 70, "min number of found TPC clusters for dau tracks"}; + Configurable cutMinV0CosPA{"cutMinV0CosPA", -1.1f, "min V0 cosPA"}; + Configurable cutMaxV0CosPA{"cutMaxV0CosPA", 1.1f, "max V0 cosPA"}; + Configurable cutMinBachCosPA{"cutMinBachCosPA", -1.1f, "min Bachelor cosPA"}; + Configurable cutMaxBachCosPA{"cutMaxBachCosPA", 1.1f, "max Bachelor cosPA"}; + Configurable cutMinCascCosPA{"cutMinCascCosPA", 0.995f, "min cascade cosPA"}; + Configurable cutRapidity{"cutRapidity", 0.5f, "max rapidity"}; + Configurable cutDauEta{"cutDauEta", 1.0f, "max eta of dau tracks"}; + Configurable cutCompMassRej{"cutCompMassRej", 0.008f, "Competing mass rejection"}; + // minimum and maximum desired pt + Configurable cutMinPtXiStd{"cutMinPtXiStd", 0.0f, "min pt for standard Xi"}; + Configurable cutMaxPtXiStd{"cutMaxPtXiStd", 15.0f, "min pt for standard Xi"}; + Configurable cutMinPtXiTra{"cutMinPtXiTra", 0.5f, "min pt for tracked Xi"}; + Configurable cutMaxPtXiTra{"cutMaxPtXiTra", 15.0f, "min pt for standard Xi"}; + Configurable cutMinPtOmegaStd{"cutMinPtOmegaStd", 0.5f, "min pt for standard Omega"}; + Configurable cutMaxPtOmegaStd{"cutMaxPtOmegaStd", 15.0f, "min pt for standard Omega"}; + Configurable cutMinPtOmegaTra{"cutMinPtOmegaTra", 1.0f, "min pt for tracked Omega"}; + Configurable cutMaxPtOmegaTra{"cutMaxPtOmegaTra", 15.0f, "min pt for standard Omega"}; + // TPC PID selection + Configurable cutNSigmaTPCPion{"cutNSigmaTPCPion", 4, "cutNSigmaTPCPion"}; + Configurable cutNSigmaTPCKaon{"cutNSigmaTPCKaon", 4, "cutNSigmaTPCKaon"}; + Configurable cutNSigmaTPCProton{"cutNSigmaTPCProton", 4, "cutNSigmaTPCProton"}; + // TOF PID selection + Configurable cutNSigmaTOFXi{"cutNSigmaTOFXi", 3, "cutNSigmaTOFXi"}; + Configurable cutNSigmaTOFOmega{"cutNSigmaTOFOmega", 3, "cutNSigmaTOFOmega"}; + } selCuts; + + // axes + struct : ConfigurableGroup { + ConfigurableAxis axisEta{"axisEta", {102, -2.01, 2.01}, "#eta"}; + ConfigurableAxis axisDCAxy{"axisDCAxy", {500, 0., 0.5}, "cm"}; + ConfigurableAxis axisDCAz{"axisDCAz", {500, 0., 0.5}, "cm"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 5.0, 6.0, 10.0}, "p_{T} (GeV/c)"}; + ConfigurableAxis axisMult{"axisMult", {VARIABLE_WIDTH, 0.0f, 5.0, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 70.0f, 100.0f}, "FT0 mult %"}; + ConfigurableAxis axisOmegaMass{"axisOmegaMass", {2000, 1.6, 1.8}, "#Omega M_{inv} (GeV/c^{2})"}; + ConfigurableAxis axisXiMass{"axisXiMass", {2000, 1.2, 1.4}, "#Xi M_{inv} (GeV/c^{2})"}; + } axesConfig; + + // cascade reconstruction Types + static constexpr std::string_view TypeNames[] = {"Standard", "Tracked"}; + + // for efficiency and purity corrections + TH1F* hEfficiencyOmegaStd1D; + TH1F* hEfficiencyOmegaTra1D; + TH1F* hEfficiencyXiStd1D; + TH1F* hEfficiencyXiTra1D; + + TH1F* hEfficiencyErrOmegaStd1D; + TH1F* hEfficiencyErrOmegaTra1D; + TH1F* hEfficiencyErrXiStd1D; + TH1F* hEfficiencyErrXiTra1D; + + TH1F* hPurityOmegaStd1D; + TH1F* hPurityOmegaTra1D; + TH1F* hPurityXiStd1D; + TH1F* hPurityXiTra1D; + + TH1F* hPurityErrOmegaStd1D; + TH1F* hPurityErrOmegaTra1D; + TH1F* hPurityErrXiStd1D; + TH1F* hPurityErrXiTra1D; + + TH2F* hEfficiencyOmegaStd2D; + TH2F* hEfficiencyOmegaTra2D; + TH2F* hEfficiencyXiStd2D; + TH2F* hEfficiencyXiTra2D; + + TH2F* hEfficiencyErrOmegaStd2D; + TH2F* hEfficiencyErrOmegaTra2D; + TH2F* hEfficiencyErrXiStd2D; + TH2F* hEfficiencyErrXiTra2D; + + TH2F* hPurityOmegaStd2D; + TH2F* hPurityOmegaTra2D; + TH2F* hPurityXiStd2D; + TH2F* hPurityXiTra2D; + + TH2F* hPurityErrOmegaStd2D; + TH2F* hPurityErrOmegaTra2D; + TH2F* hPurityErrXiStd2D; + TH2F* hPurityErrXiTra2D; + + int mRunNumber; + // loads efficiencies and purities + void initEfficiencyFromCCDB(int64_t runNumber, int64_t timestamp) + { + if (mRunNumber == runNumber) { + return; + } + mRunNumber = runNumber; + LOG(info) << "Loading efficiencies and purities from CCDB for run " << mRunNumber << " now..."; + auto timeStamp = timestamp; + + std::string efficiencyCCDBPath = [&]() { + if (doProcesspp) { + return efficiencyCCDBPathpp; + } else if (doProcesspO) { + return efficiencyCCDBPathpO; + } else if (doProcessPbPb) { + return efficiencyCCDBPathPbPb; + } + return efficiencyCCDBPathOO; + }(); + + TList* listEfficiencies = ccdb->getForTimeStamp(efficiencyCCDBPath, timeStamp); + + if (!listEfficiencies) { + LOG(fatal) << "Problem getting TList object with efficiencies and purities!"; + } + + hEfficiencyOmegaStd1D = static_cast(listEfficiencies->FindObject("Eff_Omega_Standard_byPt")); + hEfficiencyOmegaTra1D = static_cast(listEfficiencies->FindObject("Eff_Omega_Tracked_byPt")); + hEfficiencyXiStd1D = static_cast(listEfficiencies->FindObject("Eff_Xi_Standard_byPt")); + hEfficiencyXiTra1D = static_cast(listEfficiencies->FindObject("Eff_Xi_Tracked_byPt")); + hEfficiencyErrOmegaStd1D = static_cast(listEfficiencies->FindObject("EffErr_Omega_Standard_byPt")); + hEfficiencyErrOmegaTra1D = static_cast(listEfficiencies->FindObject("EffErr_Omega_Tracked_byPt")); + hEfficiencyErrXiStd1D = static_cast(listEfficiencies->FindObject("EffErr_Xi_Standard_byPt")); + hEfficiencyErrXiTra1D = static_cast(listEfficiencies->FindObject("EffErr_Xi_Tracked_byPt")); + hPurityOmegaStd1D = static_cast(listEfficiencies->FindObject("Pur_Omega_Standard_byPt")); + hPurityOmegaTra1D = static_cast(listEfficiencies->FindObject("Pur_Omega_Tracked_byPt")); + hPurityXiStd1D = static_cast(listEfficiencies->FindObject("Pur_Xi_Standard_byPt")); + hPurityXiTra1D = static_cast(listEfficiencies->FindObject("Pur_Xi_Tracked_byPt")); + hPurityErrOmegaStd1D = static_cast(listEfficiencies->FindObject("PurErr_Omega_Standard_byPt")); + hPurityErrOmegaTra1D = static_cast(listEfficiencies->FindObject("PurErr_Omega_Tracked_byPt")); + hPurityErrXiStd1D = static_cast(listEfficiencies->FindObject("PurErr_Xi_Standard_byPt")); + hPurityErrXiTra1D = static_cast(listEfficiencies->FindObject("PurErr_Xi_Tracked_byPt")); + + hEfficiencyOmegaStd2D = static_cast(listEfficiencies->FindObject("Eff_Omega_Standard_byPtMult")); + hEfficiencyOmegaTra2D = static_cast(listEfficiencies->FindObject("Eff_Omega_Tracked_byPtMult")); + hEfficiencyXiStd2D = static_cast(listEfficiencies->FindObject("Eff_Xi_Standard_byPtMult")); + hEfficiencyXiTra2D = static_cast(listEfficiencies->FindObject("Eff_Xi_Tracked_byPtMult")); + hEfficiencyErrOmegaStd2D = static_cast(listEfficiencies->FindObject("EffErr_Omega_Standard_byPtMult")); + hEfficiencyErrOmegaTra2D = static_cast(listEfficiencies->FindObject("EffErr_Omega_Tracked_byPtMult")); + hEfficiencyErrXiStd2D = static_cast(listEfficiencies->FindObject("EffErr_Xi_Standard_byPtMult")); + hEfficiencyErrXiTra2D = static_cast(listEfficiencies->FindObject("EffErr_Xi_Tracked_byPtMult")); + hPurityOmegaStd2D = static_cast(listEfficiencies->FindObject("Pur_Omega_Standard_byPtMult")); + hPurityOmegaTra2D = static_cast(listEfficiencies->FindObject("Pur_Omega_Tracked_byPtMult")); + hPurityXiStd2D = static_cast(listEfficiencies->FindObject("Pur_Xi_Standard_byPtMult")); + hPurityXiTra2D = static_cast(listEfficiencies->FindObject("Pur_Xi_Tracked_byPtMult")); + hPurityErrOmegaStd2D = static_cast(listEfficiencies->FindObject("PurErr_Omega_Standard_byPtMult")); + hPurityErrOmegaTra2D = static_cast(listEfficiencies->FindObject("PurErr_Omega_Tracked_byPtMult")); + hPurityErrXiStd2D = static_cast(listEfficiencies->FindObject("PurErr_Xi_Standard_byPtMult")); + hPurityErrXiTra2D = static_cast(listEfficiencies->FindObject("PurErr_Xi_Tracked_byPtMult")); + + if (doPropagateEfficiency1D && (!hEfficiencyErrOmegaStd1D || !hEfficiencyErrOmegaTra1D || !hEfficiencyErrXiStd1D || !hEfficiencyErrXiTra1D)) + LOG(fatal) << "Problem getting hEfficiencyUncertainty!"; + if (doPropagatePurity1D && (!hPurityErrOmegaStd1D || !hPurityErrOmegaTra1D || !hPurityErrXiStd1D || !hPurityErrXiTra1D)) + LOG(fatal) << "Problem getting hPurityUncertainty!"; + LOG(info) << "Efficiencies and purities now loaded for " << mRunNumber; + + if (doPropagateEfficiency2D && (!hEfficiencyErrOmegaStd2D || !hEfficiencyErrOmegaTra2D || !hEfficiencyErrXiStd2D || !hEfficiencyErrXiTra2D)) + LOG(fatal) << "Problem getting hEfficiencyUncertainty!"; + if (doPropagatePurity2D && (!hPurityErrOmegaStd2D || !hPurityErrOmegaTra2D || !hPurityErrXiStd2D || !hPurityErrXiTra2D)) + LOG(fatal) << "Problem getting hPurityUncertainty!"; + LOG(info) << "Efficiencies and purities now loaded for " << mRunNumber; + } + // general info about processed events + template + void fillEvents(TEvent const& collision) + { + histos.fill(HIST("NoSel-Events/EvCounter"), 0.5); + double mult = (doProcesspp || doProcesspO) ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("NoSel-Events/Mult"), mult); + double pvx = collision.posX(); + double pvy = collision.posY(); + double pvz = collision.posZ(); + histos.fill(HIST("NoSel-Events/PVxy"), pvx, pvy); + histos.fill(HIST("NoSel-Events/PVz"), pvz); + } + // checks general selection criteria for collisions + template + bool isValidEvent(TEvent collision) + { + bool passedAllSels = true; + if (!selCuts.cutDoINEL || collision.multNTracksPVeta1() > 0) + histos.fill(HIST("Rec-Events/EvFilter"), 0.5); + else + passedAllSels = false; + if (std::abs(collision.posZ()) < selCuts.cutZVertex) + histos.fill(HIST("Rec-Events/EvFilter"), 1.5); + else + passedAllSels = false; + if (!selCuts.cutDoSel8 || collision.sel8()) + histos.fill(HIST("Rec-Events/EvFilter"), 2.5); + else + passedAllSels = false; + if (passedAllSels) + histos.fill(HIST("Rec-Events/EvFilter"), 3.5); + return passedAllSels; + } + // checks cascade pt + template + bool isValidPt(TCascade cascade, TString particle, int Type) + { + bool passedSel = true; + double ptMin = 0.0; + double ptMax = 0.0; + if (Type == 1 && particle == "Xi") { + ptMin = selCuts.cutMinPtXiTra; + ptMax = selCuts.cutMaxPtXiTra; + } + if (Type == 1 && particle == "Omega") { + ptMin = selCuts.cutMinPtOmegaTra; + ptMax = selCuts.cutMaxPtOmegaTra; + } + if (Type == 0 && particle == "Xi") { + ptMin = selCuts.cutMinPtXiStd; + ptMax = selCuts.cutMaxPtXiStd; + } + if (Type == 0 && particle == "Omega") { + ptMin = selCuts.cutMinPtOmegaStd; + ptMax = selCuts.cutMaxPtOmegaStd; + } + if (cascade.pt() < ptMin || cascade.pt() > ptMax) + passedSel = false; + // histos.fill(HIST(Form("%s/Rec/Filters%s", TypeNames[Type].data(), particle)), 0.5); + return passedSel; + } + // checks general selection criteria for cascades + template + std::array isValidCasc(TEvent collision, TCascade cascade, TStdCascade stdcasc, TString particle) + { + bool passedAllSels = true; + // cascade rapidity + bool passedRapidity = true; + double y; + if (particle == "Xi") + y = std::abs(cascade.yXi()); + else + y = std::abs(cascade.yOmega()); + if (y > selCuts.cutRapidity) { + passedRapidity = false; + passedAllSels = false; + } + // daughter track pseudorapidity + bool passedDauEta = true; + double bachEta = std::abs(cascade.bacheloreta()); + double negEta = std::abs(cascade.negativeeta()); + double posEta = std::abs(cascade.positiveeta()); + if (bachEta > selCuts.cutDauEta || negEta > selCuts.cutDauEta || posEta > selCuts.cutDauEta) { + passedDauEta = false; + passedAllSels = false; + } + // daughter found TPC clusters + bool passedTPCCls = true; + const auto& posTrack = stdcasc.template posTrackExtra_as(); + const auto& negTrack = stdcasc.template negTrackExtra_as(); + const auto& bachTrack = stdcasc.template bachTrackExtra_as(); + double posCls = posTrack.tpcClusters(); + double negCls = negTrack.tpcClusters(); + double bachCls = bachTrack.tpcClusters(); + if (posCls < selCuts.cutNClsTPC || negCls < selCuts.cutNClsTPC || bachCls < selCuts.cutNClsTPC) { + passedTPCCls = false; + passedAllSels = false; + } + // V0 cosPA + bool passedV0CosPA = true; + double v0cospa = cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + if (v0cospa < selCuts.cutMinV0CosPA || v0cospa > selCuts.cutMaxV0CosPA) { + passedV0CosPA = false; + passedAllSels = false; + } + // Bachelor cosPA + bool passedBachCosPA = true; + double bachcospa = stdcasc.bachBaryonCosPA(); + if (bachcospa < selCuts.cutMinBachCosPA || bachcospa > selCuts.cutMaxBachCosPA) { + passedBachCosPA = false; + passedAllSels = false; + } + // Cascade cosPA + bool passedCascCosPA = true; + double casccospa = cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + if (casccospa < selCuts.cutMinCascCosPA) { + passedCascCosPA = false; + passedAllSels = false; + } + // Propagated cacade DCAxy to PV + bool passedPropDCAxy = true; + if (selCuts.cutDoPropagateDCA && cascade.dcaXYCascToPV() > selCuts.cutPropDCAtoPVxy) { + passedPropDCAxy = false; + passedAllSels = false; + } + // Propagated cacade DCAz to PV + bool passedPropDCAz = true; + if (selCuts.cutDoPropagateDCA && cascade.dcaZCascToPV() > selCuts.cutPropDCAtoPVz) { + passedPropDCAz = false; + passedAllSels = false; + } + return {passedRapidity, passedDauEta, passedTPCCls, passedV0CosPA, passedBachCosPA, passedCascCosPA, passedPropDCAxy, passedPropDCAz, passedAllSels}; + } + // checks TPC PID of dau tracks + template + bool passesTPC(TCascade cascade, TString particle) + { + bool passedSel = true; + const auto& posTrack = cascade.template posTrackExtra_as(); + const auto& negTrack = cascade.template negTrackExtra_as(); + const auto& bachTrack = cascade.template bachTrackExtra_as(); + if (cascade.sign() < 0) { + if (std::abs(posTrack.tpcNSigmaPr()) > selCuts.cutNSigmaTPCProton) { + passedSel = false; + } + if (std::abs(negTrack.tpcNSigmaPi()) > selCuts.cutNSigmaTPCPion) { + passedSel = false; + } + if ((particle == "Xi" && std::abs(bachTrack.tpcNSigmaPi()) > selCuts.cutNSigmaTPCPion) || + (particle == "Omega" && std::abs(bachTrack.tpcNSigmaKa()) > selCuts.cutNSigmaTPCKaon)) { + passedSel = false; + } + } else { + if (std::abs(negTrack.tpcNSigmaPr()) > selCuts.cutNSigmaTPCProton) { + passedSel = false; + } + if (std::abs(posTrack.tpcNSigmaPi()) > selCuts.cutNSigmaTPCPion) { + passedSel = false; + } + if ((particle == "Xi" && std::abs(bachTrack.tpcNSigmaPi()) > selCuts.cutNSigmaTPCPion) || + (particle == "Omega" && std::abs(bachTrack.tpcNSigmaKa()) > selCuts.cutNSigmaTPCKaon)) { + passedSel = false; + } + } + return passedSel; + } + // checks TOF PID of dau tracks + template + bool passesTOF(TCascade cascade, TString particle) + { + bool passedSel = true; + if (particle == "Xi") + passedSel = cascade.tofXiCompatibility(selCuts.cutNSigmaTOFXi); + if (particle == "Omega") + passedSel = cascade.tofOmegaCompatibility(selCuts.cutNSigmaTOFOmega); + return passedSel; + } + // checks whether gen cascade corresponds to PDG code + template + bool isValidPDG(TCascade cascade, TString particle) + { + if (particle == "Xi" && std::abs(cascade.pdgCode()) == PDG_t::kXiMinus) + return true; + if (particle == "Omega" && std::abs(cascade.pdgCode()) == PDG_t::kOmegaMinus) + return true; + return false; + } + // checks whether rec cascade is a truth primary xi or omega + template + bool isMCTruth(const TCascade& cascade, TString particle) + { + if constexpr (requires { cascade.has_cascMCCore(); }) { // safety check: discard rec cascade without gen reference + auto cascmccore = cascade.template cascMCCore_as(); + if (!cascmccore.isPhysicalPrimary()) + return false; + int pdg = std::abs(cascmccore.pdgCode()); + if (particle == "Xi") + return (pdg == PDG_t::kXiMinus); + if (particle == "Omega") + return (pdg == PDG_t::kOmegaMinus); + } + return false; + } + // applies purities and efficiencies + void fillHist(std::shared_ptr hist, double binFillThn[], float efficiency, float effUncert, float purity, float purityUncert) + { + float previousContent, previousError2, currentContent, currentError2; + int bin = hist->GetBin(binFillThn); + previousContent = hist->GetBinContent(bin); + previousError2 = hist->GetBinError2(bin); + currentContent = previousContent + purity / (efficiency); + currentError2 = previousError2 + std::pow(purity / (efficiency), 2) + std::pow(purityUncert / (efficiency), 2) + std::pow(effUncert * purity, 2) / std::pow(efficiency, 4); + hist->SetBinContent(bin, currentContent); + hist->SetBinError2(bin, currentError2); + } + // calculates DCA from cosPA + template + double calculateDCA(TEvent collision, double cosPA, double decX, double decY, double decZ) + { + double pvX = collision.posX(); + double pvY = collision.posX(); + double pvZ = collision.posX(); + double sinPA = std::sqrt(1 - cosPA * cosPA); + double dca = sinPA * std::sqrt(std::pow(decX - pvX, 2) + std::pow(decY - pvY, 2) + std::pow(decZ - pvZ, 2)); + return dca; + } + // applies selections for and fills histograms + template + void analyseCascs(TEvent collision, TCascs cascades) + { + int64_t casccollid = 0; + for (auto const& cascade : cascades) { + + if constexpr (requires { cascade.topologyChi2(); }) { + if (!cascade.has_standardCascade()) + continue; // safety check: dismisses tracked cascades without proper reference + } + + // for tracked cascades, make a reference to standard table + auto stdCasc = [&]() { + if constexpr (requires { cascade.topologyChi2(); }) { + if constexpr (requires { collision.straMCCollisionId(); }) { + return cascade.template standardCascade_as(); + } else { + return cascade.template standardCascade_as(); + } + } else { + return cascade; + } + }(); + + // Type 1 for tracked cascades, Type 0 for standard + static constexpr int Type = [&]() { + if constexpr (requires { cascade.topologyChi2(); }) { + return 1; + } else { + return 0; + } + }(); + + float efficiencyOmega = 1.0f; + float efficiencyXi = 1.0f; + float efficiencyOmegaErr = 0.0f; + float efficiencyXiErr = 0.0f; + float purityOmega = 1.0f; + float purityXi = 1.0f; + float purityOmegaErr = 0.0f; + float purityXiErr = 0.0f; + + double mult = (doProcesspp || doProcesspO) ? collision.centFT0M() : collision.centFT0C(); // ion collisions use FT0C for multiplicity, pp uses both + + if (doApplyEfficiency1D) { + if constexpr (requires { cascade.topologyChi2(); }) { + efficiencyOmega = hEfficiencyOmegaTra1D->Interpolate(cascade.pt()); + efficiencyXi = hEfficiencyXiTra1D->Interpolate(cascade.pt()); + if (doPropagateEfficiency1D) { + efficiencyOmegaErr = hEfficiencyErrOmegaTra1D->Interpolate(cascade.pt()); + efficiencyXiErr = hEfficiencyErrXiTra1D->Interpolate(cascade.pt()); + } + if (efficiencyOmega == 0) { // check for zero efficiency, do not apply if the case + efficiencyOmega = 1.; + efficiencyOmegaErr = 0.; + } + if (efficiencyXi == 0) { // check for zero efficiency, do not apply if the case + efficiencyXi = 1.; + efficiencyXiErr = 0.; + } + } else { + efficiencyOmega = hEfficiencyOmegaStd1D->Interpolate(cascade.pt()); + efficiencyXi = hEfficiencyXiStd1D->Interpolate(cascade.pt()); + if (doPropagateEfficiency1D) { + efficiencyOmegaErr = hEfficiencyErrOmegaStd1D->Interpolate(cascade.pt()); + efficiencyXiErr = hEfficiencyErrXiStd1D->Interpolate(cascade.pt()); + } + if (efficiencyOmega == 0) { // check for zero efficiency, do not apply if the case + efficiencyOmega = 1.; + efficiencyOmegaErr = 0.; + } + if (efficiencyXi == 0) { // check for zero efficiency, do not apply if the case + efficiencyXi = 1.; + efficiencyXiErr = 0.; + } + } + } + + if (doApplyEfficiency2D) { + if constexpr (requires { cascade.topologyChi2(); }) { + efficiencyOmega = hEfficiencyOmegaTra2D->Interpolate(cascade.pt(), mult); + efficiencyXi = hEfficiencyXiTra2D->Interpolate(cascade.pt(), mult); + if (doPropagateEfficiency2D) { + efficiencyOmegaErr = hEfficiencyErrOmegaTra2D->Interpolate(cascade.pt(), mult); + efficiencyXiErr = hEfficiencyErrXiTra2D->Interpolate(cascade.pt(), mult); + } + if (efficiencyOmega == 0) { // check for zero efficiency, do not apply if the case + efficiencyOmega = 1.; + efficiencyOmegaErr = 0.; + } + if (efficiencyXi == 0) { // check for zero efficiency, do not apply if the case + efficiencyXi = 1.; + efficiencyXiErr = 0.; + } + } else { + efficiencyOmega = hEfficiencyOmegaStd2D->Interpolate(cascade.pt(), mult); + efficiencyXi = hEfficiencyXiStd2D->Interpolate(cascade.pt(), mult); + if (doPropagateEfficiency2D) { + efficiencyOmegaErr = hEfficiencyErrOmegaStd2D->Interpolate(cascade.pt(), mult); + efficiencyXiErr = hEfficiencyErrXiStd2D->Interpolate(cascade.pt(), mult); + } + if (efficiencyOmega == 0) { // check for zero efficiency, do not apply if the case + efficiencyOmega = 1.; + efficiencyOmegaErr = 0.; + } + if (efficiencyXi == 0) { // check for zero efficiency, do not apply if the case + efficiencyXi = 1.; + efficiencyXiErr = 0.; + } + } + } + + if (doApplyPurity1D) { + if constexpr (requires { cascade.topologyChi2(); }) { + purityOmega = hPurityOmegaTra1D->Interpolate(cascade.pt()); + purityXi = hPurityXiTra1D->Interpolate(cascade.pt()); + if (doPropagatePurity1D) { + purityOmegaErr = hPurityErrOmegaTra1D->Interpolate(cascade.pt()); + purityXiErr = hPurityErrXiTra1D->Interpolate(cascade.pt()); + } + if (purityOmega == 0) { // check for zero purity, do not apply if the case + purityOmega = 1.; + purityOmegaErr = 0.; + } + if (purityXi == 0) { // check for zero purity, do not apply if the case + purityXi = 1.; + purityXiErr = 0.; + } + } else { + purityOmega = hPurityOmegaStd1D->Interpolate(cascade.pt()); + purityXi = hPurityXiStd1D->Interpolate(cascade.pt()); + if (doPropagatePurity1D) { + purityOmegaErr = hPurityErrOmegaStd1D->Interpolate(cascade.pt()); + purityXiErr = hPurityErrXiStd1D->Interpolate(cascade.pt()); + } + if (purityOmega == 0) { // check for zero purity, do not apply if the case + purityOmega = 1.; + purityOmegaErr = 0.; + } + if (purityXi == 0) { // check for zero purity, do not apply if the case + purityXi = 1.; + purityXiErr = 0.; + } + } + } + + if (doApplyPurity2D) { + if constexpr (requires { cascade.topologyChi2(); }) { + purityOmega = hPurityOmegaTra2D->Interpolate(cascade.pt(), mult); + purityXi = hPurityXiTra2D->Interpolate(cascade.pt(), mult); + if (doPropagatePurity2D) { + purityOmegaErr = hPurityErrOmegaTra2D->Interpolate(cascade.pt(), mult); + purityXiErr = hPurityErrXiTra2D->Interpolate(cascade.pt(), mult); + } + if (purityOmega == 0) { // check for zero purity, do not apply if the case + purityOmega = 1.; + purityOmegaErr = 0.; + } + if (purityXi == 0) { // check for zero purity, do not apply if the case + purityXi = 1.; + purityXiErr = 0.; + } + } else { + purityOmega = hPurityOmegaStd2D->Interpolate(cascade.pt(), mult); + purityXi = hPurityXiStd2D->Interpolate(cascade.pt(), mult); + if (doPropagatePurity2D) { + purityOmegaErr = hPurityErrOmegaStd2D->Interpolate(cascade.pt(), mult); + purityXiErr = hPurityErrXiStd2D->Interpolate(cascade.pt(), mult); + } + if (purityOmega == 0) { // check for zero purity, do not apply if the case + purityOmega = 1.; + purityOmegaErr = 0.; + } + if (purityXi == 0) { // check for zero purity, do not apply if the case + purityXi = 1.; + purityXiErr = 0.; + } + } + } + + // fill multiplicity for events with >=1 cascade + if (collision.index() != casccollid) { + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/EvMult"), mult); + if constexpr (requires { collision.straMCCollisionId(); }) { + if (isMCTruth(stdCasc, "Xi") || isMCTruth(stdCasc, "Omega")) { + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/EvMult"), mult); + } + } + casccollid = collision.index(); + } + + double massXi = cascade.mXi(); + double massOmega = cascade.mOmega(); + double pt = cascade.pt(); + double v0cosPA = cascade.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + double casccosPA = cascade.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + double calcDCA = calculateDCA(collision, casccosPA, cascade.x(), cascade.y(), cascade.z()); + double bachEta = cascade.bacheloreta(); + double negEta = cascade.negativeeta(); + double posEta = cascade.positiveeta(); + // fill filters for no cascade selections + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/PropDCAxy"), cascade.dcaXYCascToPV()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/PropDCAz"), cascade.dcaZCascToPV()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/CalcDCA"), calcDCA); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/BachCosPA"), stdCasc.bachBaryonCosPA()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/V0CosPA"), v0cosPA); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/CascCosPA"), casccosPA); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/RapidityXi"), cascade.yXi()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/RapidityOmega"), cascade.yOmega()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/EtaDau"), bachEta); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/EtaDau"), negEta); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/Filters/EtaDau"), posEta); + // fill inv mass for no cascade selections + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/MassXi"), massXi); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel/MassOmega"), massOmega); + // fill filters and inv mass for no cascade selections (MC truth) + if constexpr (requires { collision.straMCCollisionId(); }) { + if (isMCTruth(stdCasc, "Xi") || isMCTruth(stdCasc, "Omega")) { + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/PropDCAxy"), cascade.dcaXYCascToPV()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/PropDCAz"), cascade.dcaZCascToPV()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/CalcDCA"), calcDCA); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/BachCosPA"), stdCasc.bachBaryonCosPA()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/V0CosPA"), v0cosPA); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/CascCosPA"), casccosPA); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/EtaDau"), bachEta); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/EtaDau"), negEta); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/EtaDau"), posEta); + if (isMCTruth(stdCasc, "Xi")) { + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/RapidityXi"), cascade.yXi()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/MassXi"), massXi); + } + if (isMCTruth(stdCasc, "Omega")) { + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/Filters/RapidityOmega"), cascade.yOmega()); + histos.fill(HIST(TypeNames[Type]) + HIST("/NoSel-Truth/MassOmega"), massOmega); + } + } + } + // start checking selections + bool passedAllSelsXi = true; + bool passedAllSelsOmega = true; + bool fillTruthXi = false; + bool fillTruthOmega = false; + if constexpr (requires { collision.straMCCollisionId(); }) { + if (isMCTruth(stdCasc, "Xi")) { + fillTruthXi = true; + } + } + if constexpr (requires { collision.straMCCollisionId(); }) { + if (isMCTruth(stdCasc, "Omega")) { + fillTruthOmega = true; + } + } + // apply pt cuts + if (doApplyPtCutsXi) { + if (isValidPt(cascade, "Xi", Type)) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersXi"), 0.5); + if (fillTruthXi) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersXi"), 0.5); + } else { + passedAllSelsXi = false; + } + } + if (doApplyPtCutsOmega) { + if (isValidPt(cascade, "Omega", Type)) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersOmega"), 0.5); + if (fillTruthOmega) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersOmega"), 0.5); + } else { + passedAllSelsOmega = false; + } + } + // apply general cascade cuts + if (doApplyGenCutsXi) { + auto genSels = isValidCasc(collision, cascade, stdCasc, "Xi"); + for (size_t i = 0; i < std::size(genSels); ++i) { + if (genSels[i]) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/GenFiltersXi"), (i + 0.5)); + if (fillTruthXi) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/GenFiltersXi"), (i + 0.5)); + } + } + if (genSels[std::size(genSels) - 1]) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersXi"), 1.5); + if (fillTruthXi) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersXi"), 1.5); + } else { + passedAllSelsXi = false; + } + } + if (doApplyGenCutsOmega) { + auto genSels = isValidCasc(collision, cascade, stdCasc, "Omega"); + for (size_t i = 0; i < std::size(genSels); ++i) { + if (genSels[i]) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/GenFiltersOmega"), (i + 0.5)); + if (fillTruthOmega) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/GenFiltersOmega"), (i + 0.5)); + } + } + if (genSels[std::size(genSels) - 1]) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersOmega"), 1.5); + if (fillTruthOmega) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersOmega"), 1.5); + } else { + passedAllSelsOmega = false; + } + } + // apply tpc pid + if (doApplyTPCPIDXi) { + if (passesTPC(stdCasc, "Xi")) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersXi"), 2.5); + if (fillTruthXi) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersXi"), 2.5); + } else { + passedAllSelsXi = false; + } + } + if (doApplyTPCPIDOmega) { + if (passesTPC(stdCasc, "Omega")) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersOmega"), 2.5); + if (fillTruthOmega) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersOmega"), 2.5); + } else { + passedAllSelsOmega = false; + } + } + // apply tof pid + if (doApplyTOFPIDXi) { + if (passesTOF(stdCasc, "Xi")) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersXi"), 3.5); + if (fillTruthXi) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersXi"), 3.5); + } else { + passedAllSelsXi = false; + } + } + if (doApplyTOFPIDOmega) { + if (passesTOF(stdCasc, "Omega")) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersOmega"), 3.5); + if (fillTruthOmega) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersOmega"), 3.5); + } else { + passedAllSelsOmega = false; + } + } + // apply competing mass rej + if (doCompetingMassRej) { + if ((std::abs(massXi - o2::constants::physics::MassXiMinus) > selCuts.cutCompMassRej)) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersOmega"), 4.5); + if (fillTruthOmega) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersOmega"), 4.5); + } else { + passedAllSelsOmega = false; + } + } + + // fil rec histograms + if (passedAllSelsXi || passedAllSelsOmega) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/EvMult"), mult); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/PropDCAxy"), cascade.dcaXYCascToPV()); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/PropDCAz"), cascade.dcaZCascToPV()); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/CalcDCA"), calcDCA); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/BachCosPA"), stdCasc.bachBaryonCosPA()); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/V0CosPA"), v0cosPA); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/CascCosPA"), casccosPA); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/EtaDau"), bachEta); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/EtaDau"), negEta); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/EtaDau"), posEta); + if (passedAllSelsXi) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/RapidityXi"), cascade.yXi()); + if (passedAllSelsOmega) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/Filters/RapidityOmega"), cascade.yOmega()); + if (fillTruthXi || fillTruthOmega) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/EvMult"), mult); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/PropDCAxy"), cascade.dcaXYCascToPV()); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/PropDCAz"), cascade.dcaZCascToPV()); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/CalcDCA"), calcDCA); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/BachCosPA"), stdCasc.bachBaryonCosPA()); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/V0CosPA"), v0cosPA); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/CascCosPA"), casccosPA); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/EtaDau"), bachEta); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/EtaDau"), negEta); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/EtaDau"), posEta); + if (passedAllSelsXi) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/RapidityXi"), cascade.yXi()); + if (passedAllSelsOmega) + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Filters/RapidityOmega"), cascade.yOmega()); + } + } + double binFillXi[3] = {massXi, pt, mult}; + if (passedAllSelsXi) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersXi"), 4.5); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/MassXi"), massXi); + fillHist(histos.get(HIST(TypeNames[Type]) + HIST("/Rec/Xi")), binFillXi, efficiencyXi, efficiencyXiErr, purityXi, purityXiErr); + if (fillTruthXi) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersXi"), 4.5); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/MassXi"), massXi); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Xi"), massXi, pt, mult); + } + } + double binFillOmega[3] = {massOmega, pt, mult}; + if (passedAllSelsOmega) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/FiltersOmega"), 5.5); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec/MassOmega"), massOmega); + fillHist(histos.get(HIST(TypeNames[Type]) + HIST("/Rec/Omega")), binFillOmega, efficiencyOmega, efficiencyOmegaErr, purityOmega, purityOmegaErr); + if (fillTruthOmega) { + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/FiltersOmega"), 5.5); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/MassOmega"), massOmega); + histos.fill(HIST(TypeNames[Type]) + HIST("/Rec-Truth/Omega"), massOmega, pt, mult); + } + } + } + } + + void init(InitContext const&) + { + // for all events processing + histos.add("NoSel-Events/EvCounter", "Event Counter", kTH1F, {{1, 0, 1}}); + histos.add("NoSel-Events/PVxy", "PV xy position", kTH2F, {{200, -0.1, 0.1}, {200, -0.1, 0.1}}); + histos.add("NoSel-Events/PVz", "PV z position", kTH1F, {{100, -20, 20}}); + histos.add("NoSel-Events/Mult", "Multiplicity", kTH1F, {axesConfig.axisMult}); + // for all events processing + histos.add("Rec-Events/EvCounter", "Event Counter", kTH1F, {{1, 0, 1}}); + histos.add("Rec-Events/PVxy", "PV xy position", kTH2F, {{200, -0.1, 0.1}, {200, -0.1, 0.1}}); + histos.add("Rec-Events/PVz", "PV z position", kTH1F, {{100, -20, 20}}); + histos.add("Rec-Events/Mult", "Multiplicity", kTH1F, {axesConfig.axisMult}); + histos.add("Rec-Events/EvFilter", "Event Filter", kTH1F, {{4, 0, 4}}); + histos.get(HIST("Rec-Events/EvFilter"))->GetXaxis()->SetBinLabel(1, "INEL>0"); + histos.get(HIST("Rec-Events/EvFilter"))->GetXaxis()->SetBinLabel(2, "PVz cut"); + histos.get(HIST("Rec-Events/EvFilter"))->GetXaxis()->SetBinLabel(3, "sel8"); + histos.get(HIST("Rec-Events/EvFilter"))->GetXaxis()->SetBinLabel(4, "all"); + // for cascade processing + static_for<0, 1>([&](auto Type) { + // no selections applied + histos.add(Form("%s/NoSel/Filters/PropDCAxy", TypeNames[Type].data()), "DCA to xy (propagated)", kTH1F, {axesConfig.axisDCAxy}); + histos.add(Form("%s/NoSel/Filters/PropDCAz", TypeNames[Type].data()), "DCA to z (propagated)", kTH1F, {axesConfig.axisDCAz}); + histos.add(Form("%s/NoSel/Filters/CalcDCA", TypeNames[Type].data()), "DCA (calculated)", kTH1F, {axesConfig.axisDCAxy}); + histos.add(Form("%s/NoSel/Filters/BachCosPA", TypeNames[Type].data()), "Bachelor cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel/Filters/V0CosPA", TypeNames[Type].data()), "V0 cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel/Filters/CascCosPA", TypeNames[Type].data()), "V0 cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel/Filters/RapidityXi", TypeNames[Type].data()), "y under Xi hypothesis", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel/Filters/RapidityOmega", TypeNames[Type].data()), "y under Omega hypothesis", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel/Filters/EtaDau", TypeNames[Type].data()), "|#eta| of dau tracks", kTH1F, {axesConfig.axisEta}); + histos.add(Form("%s/NoSel/EvMult", TypeNames[Type].data()), "Multiplicity of events with >=1 cascade", kTH1F, {axesConfig.axisMult}); + histos.add(Form("%s/NoSel/MassXi", TypeNames[Type].data()), "Invariant mass hypothesis", kTH1F, {axesConfig.axisXiMass}); + histos.add(Form("%s/NoSel/MassOmega", TypeNames[Type].data()), "Invariant mass hypothesis", kTH1F, {axesConfig.axisOmegaMass}); + // mc truth for no selectrion + histos.add(Form("%s/NoSel-Truth/Filters/PropDCAxy", TypeNames[Type].data()), "DCA to xy (propagated)", kTH1F, {axesConfig.axisDCAxy}); + histos.add(Form("%s/NoSel-Truth/Filters/PropDCAz", TypeNames[Type].data()), "DCA to z (propagated)", kTH1F, {axesConfig.axisDCAz}); + histos.add(Form("%s/NoSel-Truth/Filters/CalcDCA", TypeNames[Type].data()), "DCA (calculated)", kTH1F, {axesConfig.axisDCAxy}); + histos.add(Form("%s/NoSel-Truth/Filters/BachCosPA", TypeNames[Type].data()), "Bachelor cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel-Truth/Filters/V0CosPA", TypeNames[Type].data()), "V0 cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel-Truth/Filters/CascCosPA", TypeNames[Type].data()), "V0 cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel-Truth/Filters/RapidityXi", TypeNames[Type].data()), "y under Xi hypothesis", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel-Truth/Filters/RapidityOmega", TypeNames[Type].data()), "y under Omega hypothesis", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/NoSel-Truth/Filters/EtaDau", TypeNames[Type].data()), "|#eta| of dau tracks", kTH1F, {axesConfig.axisEta}); + histos.add(Form("%s/NoSel-Truth/EvMult", TypeNames[Type].data()), "Multiplicity of events with >=1 cascade", kTH1F, {axesConfig.axisMult}); + histos.add(Form("%s/NoSel-Truth/MassXi", TypeNames[Type].data()), "Invariant mass hypothesis", kTH1F, {axesConfig.axisXiMass}); + histos.add(Form("%s/NoSel-Truth/MassOmega", TypeNames[Type].data()), "Invariant mass hypothesis", kTH1F, {axesConfig.axisOmegaMass}); + // xi and omega selection statistics + histos.add(Form("%s/Rec/FiltersXi", TypeNames[Type].data()), "main cascade filters for Xi", kTH1F, {{5, 0, 5}}); + histos.add(Form("%s/Rec/GenFiltersXi", TypeNames[Type].data()), "general cascade filters for Xi", kTH1F, {{9, 0, 9}}); + histos.add(Form("%s/Rec/FiltersOmega", TypeNames[Type].data()), "main cascade filters for Omega", kTH1F, {{6, 0, 6}}); + histos.add(Form("%s/Rec/GenFiltersOmega", TypeNames[Type].data()), "general cascade filters for Omega", kTH1F, {{9, 0, 9}}); + histos.add(Form("%s/Rec/Filters/PropDCAxy", TypeNames[Type].data()), "DCA to xy (propagated)", kTH1F, {axesConfig.axisDCAxy}); + histos.add(Form("%s/Rec/Filters/PropDCAz", TypeNames[Type].data()), "DCA to z (propagated)", kTH1F, {axesConfig.axisDCAz}); + histos.add(Form("%s/Rec/Filters/CalcDCA", TypeNames[Type].data()), "DCA (calculated)", kTH1F, {axesConfig.axisDCAxy}); + histos.add(Form("%s/Rec/Filters/BachCosPA", TypeNames[Type].data()), "Bachelor cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec/Filters/V0CosPA", TypeNames[Type].data()), "V0 cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec/Filters/CascCosPA", TypeNames[Type].data()), "V0 cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec/Filters/RapidityXi", TypeNames[Type].data()), "y under Xi hypothesis", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec/Filters/RapidityOmega", TypeNames[Type].data()), "y under Omega hypothesis", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec/Filters/EtaDau", TypeNames[Type].data()), "|#eta| of dau tracks", kTH1F, {axesConfig.axisEta}); + // passed all applied sels + histos.add(Form("%s/Rec/EvMult", TypeNames[Type].data()), "Multiplicity of events with >=1 cascade", kTH1F, {axesConfig.axisMult}); + histos.add(Form("%s/Rec/MassXi", TypeNames[Type].data()), "Invariant mass hypothesis", kTH1F, {axesConfig.axisXiMass}); + histos.add(Form("%s/Rec/MassOmega", TypeNames[Type].data()), "Invariant mass hypothesis", kTH1F, {axesConfig.axisOmegaMass}); + histos.add(Form("%s/Rec/Xi", TypeNames[Type].data()), "", kTHnD, {axesConfig.axisXiMass, axesConfig.axisPt, axesConfig.axisMult}); + histos.add(Form("%s/Rec/Omega", TypeNames[Type].data()), "", kTHnD, {axesConfig.axisOmegaMass, axesConfig.axisPt, axesConfig.axisMult}); + // mc truth for all passed selections + // xi and omega truth selection statistics + histos.add(Form("%s/Rec-Truth/FiltersXi", TypeNames[Type].data()), "main cascade filters for Xi", kTH1F, {{5, 0, 5}}); + histos.add(Form("%s/Rec-Truth/GenFiltersXi", TypeNames[Type].data()), "general cascade filters for Xi", kTH1F, {{9, 0, 9}}); + histos.add(Form("%s/Rec-Truth/FiltersOmega", TypeNames[Type].data()), "main cascade filters for Omega", kTH1F, {{6, 0, 6}}); + histos.add(Form("%s/Rec-Truth/GenFiltersOmega", TypeNames[Type].data()), "general cascade filters for Omega", kTH1F, {{9, 0, 9}}); + histos.add(Form("%s/Rec-Truth/Filters/PropDCAxy", TypeNames[Type].data()), "DCA to xy (propagated)", kTH1F, {axesConfig.axisDCAxy}); + histos.add(Form("%s/Rec-Truth/Filters/PropDCAz", TypeNames[Type].data()), "DCA to z (propagated)", kTH1F, {axesConfig.axisDCAz}); + histos.add(Form("%s/Rec-Truth/Filters/CalcDCA", TypeNames[Type].data()), "DCA (calculated)", kTH1F, {axesConfig.axisDCAxy}); + histos.add(Form("%s/Rec-Truth/Filters/BachCosPA", TypeNames[Type].data()), "Bachelor cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec-Truth/Filters/V0CosPA", TypeNames[Type].data()), "V0 cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec-Truth/Filters/CascCosPA", TypeNames[Type].data()), "V0 cosPA", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec-Truth/Filters/RapidityXi", TypeNames[Type].data()), "y under Xi hypothesis", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec-Truth/Filters/RapidityOmega", TypeNames[Type].data()), "y under Omega hypothesis", kTH1F, {{200, -1.0, 1.0}}); + histos.add(Form("%s/Rec-Truth/Filters/EtaDau", TypeNames[Type].data()), "|#eta| of dau tracks", kTH1F, {axesConfig.axisEta}); + // truth that passed all sels + histos.add(Form("%s/Rec-Truth/EvMult", TypeNames[Type].data()), "Multiplicity of events with >=1 cascade", kTH1F, {axesConfig.axisMult}); + histos.add(Form("%s/Rec-Truth/MassXi", TypeNames[Type].data()), "Invariant mass hypothesis", kTH1F, {axesConfig.axisXiMass}); + histos.add(Form("%s/Rec-Truth/MassOmega", TypeNames[Type].data()), "Invariant mass hypothesis", kTH1F, {axesConfig.axisOmegaMass}); + histos.add(Form("%s/Rec-Truth/Omega", TypeNames[Type].data()), "", kTHnD, {axesConfig.axisOmegaMass, axesConfig.axisPt, axesConfig.axisMult}); + histos.add(Form("%s/Rec-Truth/Xi", TypeNames[Type].data()), "", kTHnD, {axesConfig.axisXiMass, axesConfig.axisPt, axesConfig.axisMult}); + }); + // for MC-specific processing + histos.add("MC/Gen/EvCounter", "Event Counter", kTH1F, {{1, 0, 1}}); + histos.add("MC/Gen/Xi", "Xi", kTH2F, {axesConfig.axisPt, axesConfig.axisMult}); // generated Xis + histos.add("MC/Gen/Omega", "Omega", kTH2F, {axesConfig.axisPt, axesConfig.axisMult}); // generated Omegas + histos.add("MC/Gen/PrimaryXi", "Xi primaries", kTH2F, {axesConfig.axisPt, axesConfig.axisMult}); // generated primary Xis + histos.add("MC/Gen/PrimaryOmega", "Omega primaries in |y|", kTH2F, {axesConfig.axisPt, axesConfig.axisMult}); // generated primary Omegas + histos.add("MC/Gen/PrimaryXiRapidity", "Xi primaries", kTH2F, {axesConfig.axisPt, axesConfig.axisMult}); // generated primary Xis in selected rapidity range + histos.add("MC/Gen/PrimaryOmegaRapidity", "Omega primaries in |y|", kTH2F, {axesConfig.axisPt, axesConfig.axisMult}); // generated primary Omegas in selected rapidity range + // label filter statistic bins for standard cascs + histos.get(HIST("Standard/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(1, "p_{T}"); + histos.get(HIST("Standard/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(2, "gen"); + histos.get(HIST("Standard/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(3, "TPC"); + histos.get(HIST("Standard/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(4, "TOF"); + histos.get(HIST("Standard/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(5, "all"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(1, "casc |y|"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(2, "dau |#eta|"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(3, "dau TPC cls"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(4, "V0CosPA"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(5, "BachCosPA"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(6, "CascCosPA"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(7, "PropDCAxy"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(8, "PropDCAz"); + histos.get(HIST("Standard/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(9, "all"); + histos.get(HIST("Standard/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(1, "p_{T}"); + histos.get(HIST("Standard/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(2, "gen"); + histos.get(HIST("Standard/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(3, "TPC"); + histos.get(HIST("Standard/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(4, "TOF"); + histos.get(HIST("Standard/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(5, "CMR"); + histos.get(HIST("Standard/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(6, "all"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(1, "casc |y|"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(2, "dau |#eta|"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(3, "dau TPC cls"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(4, "V0CosPA"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(5, "BachCosPA"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(6, "CascCosPA"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(7, "PropDCAxy"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(8, "PropDCAz"); + histos.get(HIST("Standard/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(9, "all"); + histos.get(HIST("Standard/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(1, "p_{T}"); + histos.get(HIST("Standard/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(2, "gen"); + histos.get(HIST("Standard/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(3, "TPC"); + histos.get(HIST("Standard/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(4, "TOF"); + histos.get(HIST("Standard/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(5, "all"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(1, "casc |y|"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(2, "dau |#eta|"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(3, "dau TPC cls"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(4, "V0CosPA"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(5, "BachCosPA"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(6, "CascCosPA"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(7, "PropDCAxy"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(8, "PropDCAz"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(9, "all"); + histos.get(HIST("Standard/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(1, "p_{T}"); + histos.get(HIST("Standard/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(2, "gen"); + histos.get(HIST("Standard/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(3, "TPC"); + histos.get(HIST("Standard/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(4, "TOF"); + histos.get(HIST("Standard/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(5, "CMR"); + histos.get(HIST("Standard/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(6, "all"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(1, "casc |y|"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(2, "dau |#eta|"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(3, "dau TPC cls"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(4, "V0CosPA"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(5, "BachCosPA"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(6, "CascCosPA"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(7, "PropDCAxy"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(8, "PropDCAz"); + histos.get(HIST("Standard/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(9, "all"); + // label filter statistic bins for tracked cascs + histos.get(HIST("Tracked/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(1, "p_{T}"); + histos.get(HIST("Tracked/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(2, "gen"); + histos.get(HIST("Tracked/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(3, "TPC"); + histos.get(HIST("Tracked/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(4, "TOF"); + histos.get(HIST("Tracked/Rec/FiltersXi"))->GetXaxis()->SetBinLabel(5, "all"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(1, "casc |y|"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(2, "dau |#eta|"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(3, "dau TPC cls"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(4, "V0CosPA"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(5, "BachCosPA"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(6, "CascCosPA"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(7, "PropDCAxy"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(8, "PropDCAz"); + histos.get(HIST("Tracked/Rec/GenFiltersXi"))->GetXaxis()->SetBinLabel(9, "all"); + histos.get(HIST("Tracked/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(1, "p_{T}"); + histos.get(HIST("Tracked/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(2, "gen"); + histos.get(HIST("Tracked/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(3, "TPC"); + histos.get(HIST("Tracked/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(4, "TOF"); + histos.get(HIST("Tracked/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(5, "CMR"); + histos.get(HIST("Tracked/Rec/FiltersOmega"))->GetXaxis()->SetBinLabel(6, "all"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(1, "casc |y|"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(2, "dau |#eta|"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(3, "dau TPC cls"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(4, "V0CosPA"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(5, "BachCosPA"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(6, "CascCosPA"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(7, "PropDCAxy"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(8, "PropDCAz"); + histos.get(HIST("Tracked/Rec/GenFiltersOmega"))->GetXaxis()->SetBinLabel(9, "all"); + histos.get(HIST("Tracked/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(1, "p_{T}"); + histos.get(HIST("Tracked/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(2, "gen"); + histos.get(HIST("Tracked/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(3, "TPC"); + histos.get(HIST("Tracked/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(4, "TOF"); + histos.get(HIST("Tracked/Rec-Truth/FiltersXi"))->GetXaxis()->SetBinLabel(5, "all"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(1, "casc |y|"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(2, "dau |#eta|"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(3, "dau TPC cls"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(4, "V0CosPA"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(5, "BachCosPA"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(6, "CascCosPA"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(7, "PropDCAxy"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(8, "PropDCAz"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersXi"))->GetXaxis()->SetBinLabel(9, "all"); + histos.get(HIST("Tracked/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(1, "p_{T}"); + histos.get(HIST("Tracked/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(2, "gen"); + histos.get(HIST("Tracked/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(3, "TPC"); + histos.get(HIST("Tracked/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(4, "TOF"); + histos.get(HIST("Tracked/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(5, "CMR"); + histos.get(HIST("Tracked/Rec-Truth/FiltersOmega"))->GetXaxis()->SetBinLabel(6, "all"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(1, "casc |y|"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(2, "dau |#eta|"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(3, "dau TPC cls"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(4, "V0CosPA"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(5, "BachCosPA"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(6, "CascCosPA"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(7, "PropDCAxy"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(8, "PropDCAz"); + histos.get(HIST("Tracked/Rec-Truth/GenFiltersOmega"))->GetXaxis()->SetBinLabel(9, "all"); + } + + void processDerivedData(DerCollisionWMults::iterator const& collision, DerCascDatas const& allCascs, DerTraCascDatas const& traCascs, DauTracks const&) + { + fillEvents(collision); // save info about all processed events + if (doApplyEfficiency1D || doApplyPurity1D || doApplyEfficiency2D || doApplyPurity2D) { + initEfficiencyFromCCDB(collision.runNumber(), collision.timestamp()); + } + if (isValidEvent(collision)) { + histos.fill(HIST("Rec-Events/EvCounter"), 0.5); + histos.fill(HIST("Rec-Events/PVxy"), collision.posX(), collision.posY()); + histos.fill(HIST("Rec-Events/PVz"), collision.posZ()); + double mult = (doProcesspp || doProcesspO) ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("Rec-Events/Mult"), mult); + analyseCascs(collision, allCascs); // process all cascades + analyseCascs(collision, traCascs); // process tracked cascades + } + } + + void processDerivedMCGen(aod::StraMCCollisions const& genColls, DerMCGenCascades const& genCascs, soa::Join const& recColls) + { + for (auto const& genColl : genColls) { + histos.fill(HIST("MC/Gen/EvCounter"), 0.5); // generated events statistics + // (for efficiency calculation) only take reconstructed events + auto slicedRecColls = recColls.sliceBy(perMcCollision, genColl.globalIndex()); + for (auto const& recColl : slicedRecColls) { + double cascMult = (doProcesspp || doProcesspO) ? recColl.centFT0M() : recColl.centFT0C(); + int64_t genCollId = recColl.straMCCollisionId(); + for (auto const& casc : genCascs) { + if (casc.straMCCollisionId() != genCollId) + continue; // safety check + double cascPt = std::sqrt(std::pow(casc.pxMC(), 2) + std::pow(casc.pyMC(), 2)); + if (isValidPDG(casc, "Xi")) + histos.fill(HIST("MC/Gen/Xi"), cascPt, cascMult); + if (isValidPDG(casc, "Omega")) + histos.fill(HIST("MC/Gen/Omega"), cascPt, cascMult); + if (casc.isPhysicalPrimary()) { + if (isValidPDG(casc, "Xi")) { + histos.fill(HIST("MC/Gen/PrimaryXi"), cascPt, cascMult); + if (std::abs(casc.rapidityMC(0)) < selCuts.cutRapidity) + histos.fill(HIST("MC/Gen/PrimaryXiRapidity"), cascPt, cascMult); + } + if (isValidPDG(casc, "Omega")) { + histos.fill(HIST("MC/Gen/PrimaryOmega"), cascPt, cascMult); + if (std::abs(casc.rapidityMC(2)) < selCuts.cutRapidity) + histos.fill(HIST("MC/Gen/PrimaryOmegaRapidity"), cascPt, cascMult); + } + } + } + } + } + } + + void processDerivedMCRec(DerMCRecCollisions::iterator const& collision, DerMCRecCascDatas const& allCascs, DerMCRecTraCascDatas const& traCascs, DauTracks const&, DerMCGenCascades const&) + { + fillEvents(collision); // save info about all processed events + if (doApplyEfficiency1D || doApplyPurity1D || doApplyEfficiency2D || doApplyPurity2D) { + initEfficiencyFromCCDB(collision.runNumber(), collision.timestamp()); + } + if (isValidEvent(collision)) { + histos.fill(HIST("Rec-Events/EvCounter"), 0.5); + histos.fill(HIST("Rec-Events/PVxy"), collision.posX(), collision.posY()); + histos.fill(HIST("Rec-Events/PVz"), collision.posZ()); + double mult = (doProcesspp || doProcesspO) ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("Rec-Events/Mult"), mult); + analyseCascs(collision, allCascs); // process all cascades + analyseCascs(collision, traCascs); // process tracked cascades + } + } + + PROCESS_SWITCH(StrangeCascTrack, processDerivedData, "process derived data", true); + PROCESS_SWITCH(StrangeCascTrack, processDerivedMCGen, "process derived generated mc data", false); + PROCESS_SWITCH(StrangeCascTrack, processDerivedMCRec, "process derived reconstructed mc data", false); // mc and data are mutually exclusive! +}; + +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..c9e34ae9092 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/strangenessInJets.cxx @@ -0,0 +1,2001 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 Calivà (alberto.caliva@cern.ch) +/// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) +/// \author Nicolò Jacazio (nicolo.jacazio@cern.ch) +/// \author Sara Pucillo (sara.pucillo@cern.ch) +/// +/// \since May 22, 2024 + +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGLF/DataModel/LFInJets.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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::math; +using std::array; + +// Define convenient aliases for joined AOD tables +using SelCollisions = soa::Join; +using SimCollisions = soa::Join; +using DaughterTracks = soa::Join; +using DaughterTracksMC = soa::Join; + +struct StrangenessInJets { + + // Instantiate the CCDB service and API interface + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + // Instantiate the Zorro processor for skimmed data and define an output object + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // Define histogram registries + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Global analysis parameters + enum ParticleOfInterest { kV0Particles = 0, + kCascades, + kPions, + kKaons, + kProtons, + kParticles }; + Configurable> enabledSignals{"enabledSignals", {1, 0, 0, 0, 0}, "Enable particles"}; + Configurable minJetPt{"minJetPt", 10.0, "Minimum reconstructed pt of the jet (GeV/c)"}; + Configurable rJet{"rJet", 0.3, "Jet resolution parameter (R)"}; + Configurable zVtx{"zVtx", 10.0, "Maximum z-vertex position"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "eta gap from detector edge"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Enable processing of skimmed data"}; + Configurable triggerName{"triggerName", "fOmega", "Software trigger name"}; + + // Track analysis parameters + Configurable minITSnCls{"minITSnCls", 4, "Minimum number of ITS clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 80, "Minimum number of TPC crossed rows"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "Maximum chi2 per cluster TPC"}; + Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; + Configurable etaMax{"etaMax", +0.8f, "Maximum eta"}; + Configurable ptMinV0Proton{"ptMinV0Proton", 0.3f, "Minimum pt of protons from V0"}; + Configurable ptMaxV0Proton{"ptMaxV0Proton", 10.0f, "Maximum pt of protons from V0"}; + Configurable ptMinV0Pion{"ptMinV0Pion", 0.1f, "Minimum pt of pions from V0"}; + Configurable ptMaxV0Pion{"ptMaxV0Pion", 1.5f, "Maximum pt of pions from V0"}; + Configurable ptMinK0Pion{"ptMinK0Pion", 0.3f, "Minimum pt of pions from K0"}; + Configurable ptMaxK0Pion{"ptMaxK0Pion", 10.0f, "Maximum pt of pions 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 requireITS{"requireITS", false, "Require ITS hit"}; + Configurable requireTOF{"requireTOF", false, "Require TOF hit"}; + + // V0 analysis parameters + Configurable minimumV0Radius{"minimumV0Radius", 0.5f, "Minimum V0 Radius"}; + Configurable maximumV0Radius{"maximumV0Radius", 40.0f, "Maximum V0 Radius"}; + Configurable dcanegtoPVmin{"dcanegtoPVmin", 0.1f, "Minimum DCA of negative track to primary vertex"}; + Configurable dcapostoPVmin{"dcapostoPVmin", 0.1f, "Minimum DCA of positive track to primary vertex"}; + Configurable v0cospaMin{"v0cospaMin", 0.99f, "Minimum V0 cosine of pointing angle"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum DCA between V0 daughters"}; + + // Cascade analysis parameters + Configurable minimumCascRadius{"minimumCascRadius", 0.1f, "Minimum cascade radius"}; + Configurable maximumCascRadius{"maximumCascRadius", 40.0f, "Maximum cascade radius"}; + Configurable casccospaMin{"casccospaMin", 0.99f, "Minimum cascade cosine of pointing angle"}; + Configurable dcabachtopvMin{"dcabachtopvMin", 0.1f, "Minimum DCA of bachelor to primary vertex"}; + Configurable dcaV0topvMin{"dcaV0topvMin", 0.1f, "Minimum DCA of V0 to primary vertex"}; + Configurable dcaCascDaughtersMax{"dcaCascDaughtersMax", 0.5f, "Maximum DCA between daughters"}; + Configurable deltaMassXi{"deltaMassXi", 0.02f, "Mass window for Xi rejection"}; + Configurable deltaMassOmega{"deltaMassOmega", 0.02f, "Mass window for Omega rejection"}; + Configurable deltaMassLambda{"deltaMassLambda", 0.02f, "Mass window for Lambda inclusion"}; + + struct : ConfigurableGroup { + ConfigurableAxis longLivedBinsNsigma{"longLivedBinsNsigma", {200, -10.f, 10.f}, "Binning of nSigma axis"}; + ConfigurableAxis longLivedBinsPt{"longLivedBinsPt", {VARIABLE_WIDTH, -5.0, -4.8, -4.6, -4.4, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1.0, -0.95, -0.9, -0.85, -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.18, -0.16, -0.14, -0.12, -0.1, 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 longLivedBinsDca{"longLivedBinsDca", {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"}; + } longLivedOptions; + + // Instantiate utility class for jet background subtraction + JetBkgSubUtils backgroundSub; + + // Initialize CCDB access and histogram registry for Zorro processing + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerName.value); + zorro.populateHistRegistry(registryData, bc.runNumber()); + } + } + + void init(InitContext const&) + { + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + int enabled = 0; + auto checkEnabled = [&](const ParticleOfInterest particle) { + LOG(info) << "Checking if " << particle << " are enabled"; + if (enabledSignals.value[particle]) { + LOG(info) << particle << " are enabled"; + return 1; + } + return 0; + }; + enabled += checkEnabled(ParticleOfInterest::kV0Particles); + enabled += checkEnabled(ParticleOfInterest::kCascades); + enabled += checkEnabled(ParticleOfInterest::kPions); + enabled += checkEnabled(ParticleOfInterest::kKaons); + enabled += checkEnabled(ParticleOfInterest::kProtons); + if (enabled == 0) { + LOG(fatal) << "At least one particle species must be enabled for the analysis. Please check the configuration of the task." << endl; + } + + // Define binning and axis specifications for multiplicity, eta, pT, PID, and invariant mass histograms + std::vector multBinning = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; + AxisSpec multAxis = {multBinning, "FT0C percentile"}; + const AxisSpec ptAxis{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}; + 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})"}; + const AxisSpec ptAxisLongLived{longLivedOptions.longLivedBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec nsigmaTOFAxis{longLivedOptions.longLivedBinsNsigma, "n#sigma_{TOF}"}; + const AxisSpec nsigmaTPCAxis{longLivedOptions.longLivedBinsNsigma, "n#sigma_{TPC}"}; + const AxisSpec dcaAxis{longLivedOptions.longLivedBinsDca, "DCA_{xy} (cm)"}; + + // Histograms for real data + if (doprocessDerivedAnalysis) { + 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}); + 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}); + 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}); + 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}); + } + + if (doprocessData) { + + // Event counters + 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"}}); + + // Histograms for analysis of strange hadrons + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + 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}); + 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}); + } + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + 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}); + 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}); + } + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryData.add("Pion_in_jet", "Pion_in_jet", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Pion_in_ue", "Pion_in_ue", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryData.add("Kaon_in_jet", "Kaon_in_jet", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Kaon_in_ue", "Kaon_in_ue", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryData.add("Proton_in_jet", "Proton_in_jet", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Proton_in_ue", "Proton_in_ue", HistType::kTHnSparseF, {multBinning, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + } + + // Histograms for mc generated + if (doprocessMCgenerated) { + + // Event counter + registryMC.add("number_of_events_mc_gen", "number of gen events in mc", HistType::kTH1D, {{10, 0, 10, "Event Cuts"}}); + registryMC.add("number_of_events_vsmultiplicity_gen", "number of events vs multiplicity", HistType::kTH1D, {{101, 0, 101, "Multiplicity percentile"}}); + + // Histograms for analysis + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + 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}); + } + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.add("XiPos_generated_jet", "XiPos_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiPos_generated_ue", "XiPos_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_generated_jet", "XiNeg_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_generated_ue", "XiNeg_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_generated_jet", "OmegaPos_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_generated_ue", "OmegaPos_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_generated_jet", "OmegaNeg_generated_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_generated_ue", "OmegaNeg_generated_ue", HistType::kTH2F, {multBinning, ptAxis}); + } + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.add("Pion_generated_in_jet", "Pion_generated_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Pion_generated_in_ue", "Pion_generated_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.add("Kaon_generated_in_jet", "Kaon_generated_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Kaon_generated_in_ue", "Kaon_generated_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.add("Proton_generated_in_jet", "Proton_generated_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Proton_generated_in_ue", "Proton_generated_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + } + + // Histograms for mc reconstructed + if (doprocessMCreconstructed) { + + // Event counter + registryMC.add("number_of_events_mc_rec", "number of rec events in mc", HistType::kTH1D, {{10, 0, 10, "Event Cuts"}}); + registryMC.add("number_of_events_vsmultiplicity_rec", "number of events vs multiplicity", HistType::kTH1D, {{101, 0, 101, "Multiplicity percentile"}}); + + // Histograms for analysis + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + 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}); + // Histograms for secondary hadrons + registryMC.add("K0s_reconstructed_jet_incl", "K0s_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("K0s_reconstructed_ue_incl", "K0s_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_jet_incl", "Lambda_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_ue_incl", "Lambda_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_jet_incl", "AntiLambda_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_ue_incl", "AntiLambda_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + } + + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.add("XiPos_reconstructed_jet", "XiPos_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiPos_reconstructed_ue", "XiPos_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_reconstructed_jet", "XiNeg_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("XiNeg_reconstructed_ue", "XiNeg_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_reconstructed_jet", "OmegaPos_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaPos_reconstructed_ue", "OmegaPos_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_reconstructed_jet", "OmegaNeg_reconstructed_jet", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("OmegaNeg_reconstructed_ue", "OmegaNeg_reconstructed_ue", HistType::kTH2F, {multBinning, ptAxis}); + } + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.add("Pion_reconstructed_in_jet", "Pion_reconstructed_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Pion_reconstructed_in_ue", "Pion_reconstructed_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.add("Kaon_reconstructed_in_jet", "Kaon_reconstructed_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Kaon_reconstructed_in_ue", "Kaon_reconstructed_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.add("Proton_reconstructed_in_jet", "Proton_reconstructed_in_jet", HistType::kTH2F, {multBinning, ptAxisLongLived}); + registryMC.add("Proton_reconstructed_in_ue", "Proton_reconstructed_in_ue", HistType::kTH2F, {multBinning, ptAxisLongLived}); + } + } + } + + /* + // Calculation of perpendicular axes + void getPerpendicularAxis(TVector3 p, TVector3& u, double sign) + { + // initialization + double ux(0), uy(0), uz(0); + + // components of vector p + const double px = p.X(); + const double py = p.Y(); + const 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 + const double a = px * px + py * py; + const double b = 2.0 * px * pz * pz; + const double c = pz * pz * pz * pz - py * py * py * py - px * px * py * py; + const 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; + } + */ + + // Delta phi calculation + 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; + } + + // Check if particle is a physical primary or a decay product of a heavy-flavor hadron + bool isPhysicalPrimaryOrFromHF(aod::McParticle const& particle, aod::McParticles const& mcParticles) + { + // Keep only pi, K, p, e, mu + int pdg = std::abs(particle.pdgCode()); + if (!(pdg == PDG_t::kPiPlus || pdg == PDG_t::kKPlus || pdg == PDG_t::kProton || pdg == PDG_t::kElectron || pdg == PDG_t::kMuonMinus)) + return false; + + // Constants for identifying heavy-flavor (charm and bottom) content from PDG codes + static constexpr int CharmQuark = 4; + static constexpr int BottomQuark = 5; + static constexpr int Hundreds = 100; + static constexpr int Thousands = 1000; + + // Check if particle is from heavy-flavor decay + bool fromHF = false; + if (particle.has_mothers()) { + auto mother = mcParticles.iteratorAt(particle.mothersIds()[0]); + int motherPdg = std::abs(mother.pdgCode()); + fromHF = (motherPdg / Hundreds == CharmQuark || motherPdg / Hundreds == BottomQuark || motherPdg / Thousands == CharmQuark || motherPdg / Thousands == BottomQuark); + } + + // Select only physical primary particles or from heavy-flavor + return (particle.isPhysicalPrimary() || fromHF); + } + + // Compute two transverse directions orthogonal to vector p + void getPerpendicularDirections(const TVector3& p, TVector3& u1, TVector3& u2) + { + // Get momentum components + double px = p.X(); + double py = p.Y(); + double pz = p.Z(); + + // Precompute squared terms + double px2 = px * px; + double py2 = py * py; + double pz2 = pz * pz; + double pz4 = pz2 * pz2; + + // Case 1: vector along z-axis -> undefined perpendiculars + if (px == 0 && py == 0) { + u1.SetXYZ(0, 0, 0); + u2.SetXYZ(0, 0, 0); + return; + } + + // Case 2: px = 0 -> avoid division by zero + if (px == 0 && py != 0) { + double ux = std::sqrt(py2 - pz4 / py2); + double uy = -pz2 / py; + u1.SetXYZ(ux, uy, pz); + u2.SetXYZ(-ux, uy, pz); + return; + } + + // Case 3: py = 0 -> avoid division by zero + if (py == 0 && px != 0) { + double ux = -pz2 / px; + double uy = std::sqrt(px2 - pz4 / px2); + u1.SetXYZ(ux, uy, pz); + u2.SetXYZ(ux, -uy, pz); + return; + } + + // General case: solve quadratic for perpendicular vectors + 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; + + // Invalid or degenerate solutions + if (delta < 0 || a == 0) { + u1.SetXYZ(0, 0, 0); + u2.SetXYZ(0, 0, 0); + return; + } + + // Solution 1 + double u1x = (-b + std::sqrt(delta)) / (2.0 * a); + double u1y = (-pz2 - px * u1x) / py; + u1.SetXYZ(u1x, u1y, pz); + + // Solution 2 + double u2x = (-b - std::sqrt(delta)) / (2.0 * a); + double u2y = (-pz2 - px * u2x) / py; + u2.SetXYZ(u2x, u2y, pz); + } + + // Find ITS hit + template + bool hasITSHitOnLayer(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 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 ((!hasITSHitOnLayer(track, 1)) && (!hasITSHitOnLayer(track, 2)) && (!hasITSHitOnLayer(track, 3))) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minTpcCr) + return false; + if (track.tpcChi2NCl() > maxChi2Tpc) + return false; + if (track.itsChi2NCl() > maxChi2Its) + return false; + if (std::fabs(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; + } + + // Lambda selections + template + bool passedLambdaSelection(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack) + { + // Single-track selections + if (!passedSingleTrackSelection(ptrack) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum of lambda daughters + TVector3 proton(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pion(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selection on pt of Lambda daughters + if (proton.Pt() < ptMinV0Proton || proton.Pt() > ptMaxV0Proton) + return false; + if (pion.Pt() < ptMinV0Pion || 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): positive track = proton, negative track = pion + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID selections (TOF): positive track = proton, negative track = pion + 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) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum AntiLambda daughters + TVector3 pion(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 proton(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selections on pt of Antilambda daughters + if (proton.Pt() < ptMinV0Proton || proton.Pt() > ptMaxV0Proton) + return false; + if (pion.Pt() < ptMinV0Pion || 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): negative track = proton, positive track = pion + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + + // PID selections (TOF): negative track = proton, positive track = pion + 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) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum of K0s daughters + TVector3 pionPos(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pionNeg(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selections on pt of K0s daughters + if (pionPos.Pt() < ptMinK0Pion || pionPos.Pt() > ptMaxK0Pion) + return false; + if (pionNeg.Pt() < ptMinK0Pion || 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) + { + // Single-track selections on cascade daughters + 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 || ntrack.pt() > ptMaxV0Proton) + return false; + if (ptrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + return false; + } + + // Xi- selection (Xi- -> L + pi-) + if (btrack.sign() < 0) { + if (ptrack.pt() < ptMinV0Proton || ptrack.pt() > ptMaxV0Proton) + return false; + if (ntrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassPionCharged); + const double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + 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; + } + + // Reject candidates compatible with Omega + if (std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < deltaMassOmega) + return false; + return true; + } + + // Omega selections + template + bool passedOmegaSelection(const Omega& casc, const TrackPos& ptrack, const TrackNeg& ntrack, const TrackBac& btrack, const Coll& coll) + { + // Single-track selections on cascade daughters + 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 || ntrack.pt() > ptMaxV0Proton) + return false; + if (ptrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + return false; + } + + // Omega- selection (Omega- -> L + K-) + if (btrack.sign() < 0) { + if (ptrack.pt() < ptMinV0Proton || ptrack.pt() > ptMaxV0Proton) + return false; + if (ntrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + 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; + } + + // Reject candidates compatible with Xi + if (std::fabs(casc.mXi() - o2::constants::physics::MassXiMinus) < deltaMassXi) + 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.tpcNClsCrossedRows() < minNCrossedRowsTPC) + 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; + } + + // Process data + void processData(SelCollisions::iterator const& collision, aod::V0Datas const& fullV0s, + aod::CascDataExt const& Cascades, DaughterTracks const& tracks, + aod::BCsWithTimestamps const&) + { + // Fill event counter before event selection + registryData.fill(HIST("number_of_events_data"), 0.5); + + // Get the bunch crossing (BC) information associated with the collision + auto bc = collision.template bc_as(); + + // Initialize CCDB objects using the BC info + initCCDB(bc); + + // If skimmed processing is enabled, skip this event unless it passes Zorro selection + if (cfgSkimmedProcessing && !zorro.isSelected(collision.template bc_as().globalBC())) { + return; + } + + // Fill event counter after zorro selection + registryData.fill(HIST("number_of_events_data"), 1.5); + + // Event selection + if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx) + return; + + // Fill event counter after event selection + registryData.fill(HIST("number_of_events_data"), 2.5); + + // Loop over reconstructed tracks + std::vector fjParticles; + for (auto const& track : tracks) { + + // Require that tracks pass selection criteria + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + + // Reject empty events + if (fjParticles.size() < 1) + return; + registryData.fill(HIST("number_of_events_data"), 3.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] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Jet selection + bool isAtLeastOneJetSelected = false; + std::vector selectedJet; + std::vector ue1; + std::vector ue2; + + // Loop over reconstructed jets + for (const auto& jet : jets) { + + // Jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - 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; + isAtLeastOneJetSelected = true; + + // Calculation of perpendicular cones + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Store jet and UE axes + selectedJet.emplace_back(jetAxis); + ue1.emplace_back(ueAxis1); + ue2.emplace_back(ueAxis2); + } + if (!isAtLeastOneJetSelected) + return; + + // Fill event counter with events with at least one jet + registryData.fill(HIST("number_of_events_data"), 4.5); + + // Event multiplicity + const float multiplicity = collision.centFT0M(); + + // Fill event multiplicity + registryData.fill(HIST("number_of_events_vsmultiplicity"), multiplicity); + + // Loop over selected jets + for (int i = 0; i < static_cast(selectedJet.size()); i++) { + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + for (const auto& v0 : fullV0s) { + // Get V0 daughters + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + TVector3 v0dir(v0.px(), v0.py(), v0.pz()); + + // Calculate distance from jet and UE axes + const float deltaEtaJet = v0dir.Eta() - selectedJet[i].Eta(); + const float deltaPhiJet = getDeltaPhi(v0dir.Phi(), selectedJet[i].Phi()); + const float deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const float deltaEtaUe1 = v0dir.Eta() - ue1[i].Eta(); + const float deltaPhiUe1 = getDeltaPhi(v0dir.Phi(), ue1[i].Phi()); + const float deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const float deltaEtaUe2 = v0dir.Eta() - ue2[i].Eta(); + const float deltaPhiUe2 = getDeltaPhi(v0dir.Phi(), ue2[i].Phi()); + const 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()); + } + } + } + } + + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + for (const auto& casc : Cascades) { + // Get cascade daughters + const auto& bach = casc.bachelor_as(); + const auto& pos = casc.posTrack_as(); + const auto& neg = casc.negTrack_as(); + TVector3 cascadeDir(casc.px(), casc.py(), casc.pz()); + + // Calculate distance from jet and UE axes + const double deltaEtaJet = cascadeDir.Eta() - selectedJet[i].Eta(); + const double deltaPhiJet = getDeltaPhi(cascadeDir.Phi(), selectedJet[i].Phi()); + const double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const double deltaEtaUe1 = cascadeDir.Eta() - ue1[i].Eta(); + const double deltaPhiUe1 = getDeltaPhi(cascadeDir.Phi(), ue1[i].Phi()); + const double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const double deltaEtaUe2 = cascadeDir.Eta() - ue2[i].Eta(); + const double deltaPhiUe2 = getDeltaPhi(cascadeDir.Phi(), ue2[i].Phi()); + const double 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()); + } + } + } + } + if (enabledSignals.value[ParticleOfInterest::kPions] || enabledSignals.value[ParticleOfInterest::kKaons] || enabledSignals.value[ParticleOfInterest::kProtons]) { + for (const auto& trk : tracks) { + + if (!passedSingleTrackSelection(trk)) { + continue; + } + + const double deltaEtaJet = trk.eta() - selectedJet[i].Eta(); + const double deltaPhiJet = getDeltaPhi(trk.phi(), selectedJet[i].Phi()); + const double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const double deltaEtaUe1 = trk.eta() - ue1[i].Eta(); + const double deltaPhiUe1 = getDeltaPhi(trk.phi(), ue1[i].Phi()); + const double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const double deltaEtaUe2 = trk.eta() - ue2[i].Eta(); + const double deltaPhiUe2 = getDeltaPhi(trk.phi(), ue2[i].Phi()); + const double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + if (deltaRjet < rJet) { + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryData.fill(HIST("Pion_in_jet"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.dcaXY()); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryData.fill(HIST("Kaon_in_jet"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.dcaXY()); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryData.fill(HIST("Proton_in_jet"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.dcaXY()); + } + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryData.fill(HIST("Pion_in_ue"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaPi(), trk.tofNSigmaPi(), trk.dcaXY()); + } + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryData.fill(HIST("Kaon_in_ue"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaKa(), trk.tofNSigmaKa(), trk.dcaXY()); + } + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryData.fill(HIST("Proton_in_ue"), multiplicity, trk.pt() * trk.sign(), trk.tpcNSigmaPr(), trk.tofNSigmaPr(), trk.dcaXY()); + } + } + } + } + } + } + PROCESS_SWITCH(StrangenessInJets, processData, "Process data", true); + + // Define per-collision preslices for V0s, cascades, MC particles, and daughter tracks + Preslice perCollisionV0 = o2::aod::v0data::collisionId; + Preslice perCollisionCasc = o2::aod::cascade::collisionId; + Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; + Preslice perCollisionTrk = o2::aod::track::collisionId; + + // Generated MC events + void processMCgenerated(soa::Join const& collisions, aod::McParticles const& mcParticles) + { + // Define per-event particle containers + std::vector fjParticles; + std::vector strHadronMomentum; + std::vector pdg; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Loop over all simulated collision events + for (const auto& collision : collisions) { + + // Clear containers at the start of the event loop + fjParticles.clear(); + strHadronMomentum.clear(); + pdg.clear(); + + // Fill event counter before any selection + registryMC.fill(HIST("number_of_events_mc_gen"), 0.5); + + // Need to apply event selection to simulated events + registryMC.fill(HIST("number_of_events_mc_gen"), 1.5); + + // Require vertex position within the allowed z range + if (std::fabs(collision.posZ()) > zVtx) + continue; + + // Fill event counter after selection on z-vertex + registryMC.fill(HIST("number_of_events_mc_gen"), 2.5); + + // Multiplicity of generated event + double genMultiplicity = collision.centFT0M(); + + // MC particles per collision + auto mcParticlesPerColl = mcParticles.sliceBy(perMCCollision, collision.globalIndex()); + + // Loop over all MC particles and select physical primaries within acceptance + for (const auto& particle : mcParticlesPerColl) { + + // Store properties of strange hadrons + int pdgAbs = std::abs(particle.pdgCode()); + if (particle.isPhysicalPrimary() && (pdgAbs == kK0Short || pdgAbs == kLambda0 || pdgAbs == kXiMinus || pdgAbs == kOmegaMinus)) { + pdg.emplace_back(particle.pdgCode()); + strHadronMomentum.emplace_back(particle.px(), particle.py(), particle.pz()); + } + + // Select physical primary particles or HF decay products + if (!isPhysicalPrimaryOrFromHF(particle, mcParticles)) + continue; + + double minPtParticle = 0.1; + if (particle.eta() < etaMin || particle.eta() > etaMax || particle.pt() < minPtParticle) + continue; + + // Build 4-momentum assuming charged pion mass + static constexpr float MassPionChargedSquared = o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged; + const double energy = std::sqrt(particle.p() * particle.p() + MassPionChargedSquared); + fastjet::PseudoJet fourMomentum(particle.px(), particle.py(), particle.pz(), energy); + fourMomentum.set_user_index(particle.pdgCode()); + fjParticles.emplace_back(fourMomentum); + } + + // Skip events with no particles + if (fjParticles.size() < 1) + continue; + registryMC.fill(HIST("number_of_events_mc_gen"), 3.5); + + // Cluster MC particles into jets using anti-kt algorithm + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + + // Estimate background energy density (rho) in perpendicular cone + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Loop over clustered jets + for (const auto& jet : jets) { + + // Jet must be fully contained in acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - deltaEtaEdge)) + continue; + + // Subtract background energy from jet + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + + // Apply jet pT threshold + if (jetMinusBkg.pt() < minJetPt) + continue; + registryMC.fill(HIST("number_of_events_mc_gen"), 4.5); + registryMC.fill(HIST("number_of_events_vsmultiplicity_gen"), genMultiplicity); + + // Set up two perpendicular cone axes for underlying event estimation + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Loop over strange hadrons + int index = -1; + for (const auto& hadron : strHadronMomentum) { + + // Particle index + index++; + + // Compute distance of particles from jet and UE axes + double deltaEtaJet = hadron.Eta() - jetAxis.Eta(); + double deltaPhiJet = getDeltaPhi(hadron.Phi(), jetAxis.Phi()); + double deltaRJet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = hadron.Eta() - ueAxis1.Eta(); + double deltaPhiUe1 = getDeltaPhi(hadron.Phi(), ueAxis1.Phi()); + double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = hadron.Eta() - ueAxis2.Eta(); + double deltaPhiUe2 = getDeltaPhi(hadron.Phi(), ueAxis2.Phi()); + double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Select particles inside jet + if (deltaRJet < coneRadius) { + switch (pdg[index]) { + case kK0Short: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0Bar: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kXiMinus: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiNeg_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kXiPlusBar: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiPos_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaMinus: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaNeg_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaPlusBar: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaPos_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kPiPlus: + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kKPlus: + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kProton: + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kPiMinus: + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kKMinus: + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kProtonBar: + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ll_generated_in_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + default: + break; + } + } + + // Select particles inside UE cones + if (deltaRUe1 < coneRadius || deltaRUe2 < coneRadius) { + switch (pdg[index]) { + case kK0Short: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0Bar: + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kXiMinus: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiNeg_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kXiPlusBar: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiPos_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaMinus: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaNeg_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaPlusBar: + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaPos_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kPiPlus: + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kKPlus: + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kProton: + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kPiMinus: + if (enabledSignals.value[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kKMinus: + if (enabledSignals.value[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kProtonBar: + if (enabledSignals.value[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("ll_generated_in_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + default: + break; + } + } + } + } + } + } + PROCESS_SWITCH(StrangenessInJets, processMCgenerated, "process generated events", false); + + // Reconstructed MC events + void processMCreconstructed(SimCollisions const& collisions, soa::Join const&, + DaughterTracksMC const& mcTracks, aod::V0Datas const& fullV0s, + aod::CascDataExt const& Cascades, const aod::McParticles&) + { + // Define per-event containers + std::vector fjParticles; + std::vector selectedJet; + std::vector ue1; + std::vector ue2; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Loop over reconstructed collisions + for (const auto& collision : collisions) { + + if (!collision.has_mcCollision()) { + continue; + } + + const auto& mcCollision = collision.mcCollision_as>(); + + // Clear containers at the start of the event loop + fjParticles.clear(); + selectedJet.clear(); + ue1.clear(); + ue2.clear(); + + // Fill event counter before any selection + registryMC.fill(HIST("number_of_events_mc_rec"), 0.5); + if (!collision.sel8()) + continue; + + // Fill event counter after event selection + registryMC.fill(HIST("number_of_events_mc_rec"), 1.5); + if (std::fabs(collision.posZ()) > zVtx) + continue; + + // Fill event counter after selection on z-vertex + registryMC.fill(HIST("number_of_events_mc_rec"), 2.5); + + // Event multiplicity + const float multiplicity = mcCollision.centFT0M(); + + // Number of V0 and cascades per collision + auto v0sPerColl = fullV0s.sliceBy(perCollisionV0, collision.globalIndex()); + auto cascPerColl = Cascades.sliceBy(perCollisionCasc, collision.globalIndex()); + auto tracksPerColl = mcTracks.sliceBy(perCollisionTrk, collision.globalIndex()); + + // Loop over reconstructed tracks + for (auto const& track : tracksPerColl) { + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + + // Reject empty events + if (fjParticles.size() < 1) + continue; + registryMC.fill(HIST("number_of_events_mc_rec"), 3.5); + + // Cluster particles using the anti-kt algorithm + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Jet selection + bool isAtLeastOneJetSelected = false; + + // Loop over clustered jets + for (const auto& jet : jets) { + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - 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; + isAtLeastOneJetSelected = true; + + // Perpendicular cones + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Store selected jet and UE cone axes + selectedJet.emplace_back(jetAxis); + ue1.emplace_back(ueAxis1); + ue2.emplace_back(ueAxis2); + } + if (!isAtLeastOneJetSelected) + continue; + + // Fill event counter for events with at least one selected jet + registryMC.fill(HIST("number_of_events_mc_rec"), 4.5); + registryMC.fill(HIST("number_of_events_vsmultiplicity_rec"), multiplicity); + + // Loop over selected jets + for (int i = 0; i < static_cast(selectedJet.size()); i++) { + + // V0 particles + if (enabledSignals.value[ParticleOfInterest::kV0Particles]) { + for (const auto& v0 : v0sPerColl) { + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + TVector3 v0dir(v0.px(), v0.py(), v0.pz()); + + // Get MC particles + if (!pos.has_mcParticle() || !neg.has_mcParticle()) + continue; + auto posParticle = pos.mcParticle_as(); + auto negParticle = neg.mcParticle_as(); + if (!posParticle.has_mothers() || !negParticle.has_mothers()) + continue; + + // Select particles originating from the same parent + 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; + + // Compute distance from jet and UE axes + double deltaEtaJet = v0dir.Eta() - selectedJet[i].Eta(); + double deltaPhiJet = getDeltaPhi(v0dir.Phi(), selectedJet[i].Phi()); + double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = v0dir.Eta() - ue1[i].Eta(); + double deltaPhiUe1 = getDeltaPhi(v0dir.Phi(), ue1[i].Phi()); + double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = v0dir.Eta() - ue2[i].Eta(); + double deltaPhiUe2 = getDeltaPhi(v0dir.Phi(), ue2[i].Phi()); + double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // K0s + if (passedK0ShortSelection(v0, pos, neg) && pdgParent == kK0Short && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("K0s_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("K0s_reconstructed_ue"), multiplicity, v0.pt()); + } + } + // Lambda + if (passedLambdaSelection(v0, pos, neg) && pdgParent == kLambda0 && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_ue"), multiplicity, v0.pt()); + } + } + // AntiLambda + if (passedAntiLambdaSelection(v0, pos, neg) && pdgParent == kLambda0Bar && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_ue"), multiplicity, v0.pt()); + } + } + + // Fill inclusive spectra + // K0s + if (passedK0ShortSelection(v0, pos, neg) && pdgParent == kK0Short) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("K0s_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("K0s_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + // Lambda + if (passedLambdaSelection(v0, pos, neg) && pdgParent == kLambda0) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + // AntiLambda + if (passedAntiLambdaSelection(v0, pos, neg) && pdgParent == kLambda0Bar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + } + } + + // Cascades + if (enabledSignals.value[ParticleOfInterest::kCascades]) { + for (const auto& casc : cascPerColl) { + auto bach = casc.bachelor_as(); + auto pos = casc.posTrack_as(); + auto neg = casc.negTrack_as(); + + // Get MC particles + if (!bach.has_mcParticle() || !pos.has_mcParticle() || !neg.has_mcParticle()) + continue; + auto posParticle = pos.mcParticle_as(); + auto negParticle = neg.mcParticle_as(); + auto bachParticle = bach.mcParticle_as(); + if (!posParticle.has_mothers() || !negParticle.has_mothers() || !bachParticle.has_mothers()) + continue; + + // Select particles originating from the same parent + int pdgParent(0); + bool isPhysPrim = false; + 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; + isPhysPrim = particleMotherOfBach.isPhysicalPrimary(); + pdgParent = particleMotherOfBach.pdgCode(); + } + } + } + if (pdgParent == 0) + continue; + if (!isPhysPrim) + continue; + + // Compute distances from jet and UE axes + TVector3 cascadeDir(casc.px(), casc.py(), casc.pz()); + double deltaEtaJet = cascadeDir.Eta() - selectedJet[i].Eta(); + double deltaPhiJet = getDeltaPhi(cascadeDir.Phi(), selectedJet[i].Phi()); + double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = cascadeDir.Eta() - ue1[i].Eta(); + double deltaPhiUe1 = getDeltaPhi(cascadeDir.Phi(), ue1[i].Phi()); + double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = cascadeDir.Eta() - ue2[i].Eta(); + double deltaPhiUe2 = getDeltaPhi(cascadeDir.Phi(), ue2[i].Phi()); + double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Xi+ + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() > 0 && pdgParent == kXiPlusBar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("XiPos_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("XiPos_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Xi- + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() < 0 && pdgParent == kXiMinus) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("XiNeg_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("XiNeg_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Omega+ + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() > 0 && pdgParent == kOmegaPlusBar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("OmegaPos_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("OmegaPos_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Omega- + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() < 0 && pdgParent == kOmegaMinus) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("OmegaNeg_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("OmegaNeg_reconstructed_ue"), multiplicity, casc.pt()); + } + } + } + } + } + } + } + PROCESS_SWITCH(StrangenessInJets, processMCreconstructed, "process reconstructed events", false); + + // Postprocessing + void processDerivedAnalysis(aod::V0InJets const& v0s, aod::CascInJets const& cascades) + { + for (const auto& v0 : v0s) { + + if (v0.v0negITSlayers() < minITSnCls || v0.v0posITSlayers() < minITSnCls) + continue; + if (v0.v0negtpcCrossedRows() < minNCrossedRowsTPC || v0.v0postpcCrossedRows() < minNCrossedRowsTPC) + continue; + if (v0.v0negTPCChi2() > maxChi2TPC || v0.v0posTPCChi2() > maxChi2TPC) + continue; + if (v0.v0cospa() < v0cospaMin) + continue; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + continue; + if (std::fabs(v0.v0dcav0daughters()) > dcaV0DaughtersMax) + continue; + if (std::fabs(v0.v0dcapostopv()) < dcapostoPVmin) + continue; + if (std::fabs(v0.v0dcanegtopv()) < dcanegtoPVmin) + continue; + // PID selections (TPC) -- K0s + if (v0.ntpcsigmapospi() < nsigmaTPCmin || v0.ntpcsigmapospi() > nsigmaTPCmax) + continue; + if (v0.ntpcsigmanegpi() < nsigmaTPCmin || v0.ntpcsigmanegpi() > nsigmaTPCmax) + continue; + + // PID selections (TOF) -- K0s + if (requireTOF) { + if (v0.ntofsigmapospi() < nsigmaTOFmin || v0.ntofsigmapospi() > nsigmaTOFmax) + continue; + if (v0.ntofsigmanegpi() < nsigmaTOFmin || v0.ntofsigmanegpi() > nsigmaTOFmax) + continue; + } + // PID selections (TPC): positive track = proton, negative track = pion -- Lam + if (v0.ntpcsigmapospr() < nsigmaTPCmin || v0.ntpcsigmapospr() > nsigmaTPCmax) + continue; + if (v0.ntpcsigmanegpi() < nsigmaTPCmin || v0.ntpcsigmanegpi() > nsigmaTPCmax) + continue; + + // PID selections (TOF): positive track = proton, negative track = pion -- Lam + if (requireTOF) { + if (v0.ntofsigmapospr() < nsigmaTOFmin || v0.ntofsigmapospr() > nsigmaTOFmax) + continue; + if (v0.ntofsigmanegpi() < nsigmaTOFmin || v0.ntofsigmanegpi() > nsigmaTOFmax) + continue; + } + // PID selections (TPC): negative track = proton, positive track = pion --- ALam + if (v0.ntpcsigmapospi() < nsigmaTPCmin || v0.ntpcsigmapospi() > nsigmaTPCmax) + continue; + if (v0.ntpcsigmanegpr() < nsigmaTPCmin || v0.ntpcsigmanegpr() > nsigmaTPCmax) + continue; + + // PID selections (TOF): negative track = proton, positive track = pion --- ALam + if (requireTOF) { + if (v0.ntofsigmapospi() < nsigmaTOFmin || v0.ntofsigmapospi() > nsigmaTOFmax) + continue; + if (v0.ntofsigmanegpr() < nsigmaTOFmin || v0.ntofsigmanegpr() > nsigmaTOFmax) + continue; + } + + if (v0.isUE()) { + registryData.fill(HIST("K0s_in_ue"), v0.multft0m(), v0.pt(), v0.massk0short()); + registryData.fill(HIST("Lambda_in_ue"), v0.multft0m(), v0.pt(), v0.masslambda()); + registryData.fill(HIST("AntiLambda_in_ue"), v0.multft0m(), v0.pt(), v0.massantilambda()); + } else if (v0.isJC()) { + registryData.fill(HIST("K0s_in_jet"), v0.multft0m(), v0.pt(), v0.massk0short()); + registryData.fill(HIST("Lambda_in_jet"), v0.multft0m(), v0.pt(), v0.masslambda()); + registryData.fill(HIST("AntiLambda_in_jet"), v0.multft0m(), v0.pt(), v0.massantilambda()); + } + } + + for (const auto& casc : cascades) { + + if (casc.v0negITSlayers() < minITSnCls || casc.v0posITSlayers() < minITSnCls || casc.bachITSlayers() < minITSnCls) + continue; + if (casc.v0negtpcCrossedRows() < minNCrossedRowsTPC || casc.v0postpcCrossedRows() < minNCrossedRowsTPC || + casc.bachtpcCrossedRows() < minNCrossedRowsTPC) + continue; + if (casc.v0negTPCChi2() > maxChi2TPC || casc.v0posTPCChi2() > maxChi2TPC || casc.bachTPCChi2() > maxChi2TPC) + continue; + if (casc.v0cospa() < v0cospaMin) + continue; + if (casc.casccospa() < casccospaMin) + continue; + if (casc.v0radius() < minimumV0Radius || casc.v0radius() > maximumV0Radius) + continue; + if (casc.cascradius() < minimumCascRadius || casc.cascradius() > maximumCascRadius) + continue; + if (std::fabs(casc.v0dcav0daughters()) > dcaV0DaughtersMax) + continue; + if (std::fabs(casc.v0dcapostopv()) < dcapostoPVmin) + continue; + if (std::fabs(casc.v0dcanegtopv()) < dcanegtoPVmin) + continue; + if (std::fabs(casc.dcabachtopv()) < dcabachtopvMin) + continue; + if (std::fabs(casc.dcav0topv()) < dcaV0topvMin) + continue; + if (std::fabs(casc.dcacascdaughters()) > dcaCascDaughtersMax) + continue; + // Xi + // Xi+ selection (Xi+ -> antiL + pi+) + if (casc.sign() > 0) { + // PID selections (TPC) + if (casc.ntpcsigmanegpr() < nsigmaTPCmin || casc.ntpcsigmanegpr() > nsigmaTPCmax) + continue; + if (casc.ntpcsigmapospi() < nsigmaTPCmin || casc.ntpcsigmapospi() > nsigmaTPCmax) + continue; + + // PID selections (TOF) + if (requireTOF) { + if (casc.ntofsigmanegpr() < nsigmaTOFmin || casc.ntofsigmanegpr() > nsigmaTOFmax) + continue; + if (casc.ntofsigmapospi() < nsigmaTOFmin || casc.ntofsigmapospi() > nsigmaTOFmax) + continue; + } + } + // Xi- selection (Xi- -> L + pi-) + if (casc.sign() < 0) { + // PID selections (TPC) + if (casc.ntpcsigmapospr() < nsigmaTPCmin || casc.ntpcsigmapospr() > nsigmaTPCmax) + continue; + if (casc.ntpcsigmanegpi() < nsigmaTPCmin || casc.ntpcsigmanegpi() > nsigmaTPCmax) + continue; + + // PID selections (TOF) + if (requireTOF) { + if (casc.ntofsigmapospr() < nsigmaTOFmin || casc.ntofsigmapospr() > nsigmaTOFmax) + continue; + if (casc.ntofsigmanegpi() < nsigmaTOFmin || casc.ntofsigmanegpi() > nsigmaTOFmax) + continue; + } + } + + // PID selection on bachelor + if (casc.ntpcsigmabachpi() < nsigmaTPCmin || casc.ntpcsigmabachpi() > nsigmaTPCmax) + continue; + + // PID selections (TOF) + if (requireTOF) { + if (casc.ntofsigmabachpi() < nsigmaTOFmin || casc.ntofsigmabachpi() > nsigmaTOFmax) + continue; + } + // V0 mass window + if (std::fabs(casc.masslambda() - o2::constants::physics::MassLambda0) > deltaMassLambda) + continue; + // Reject candidates compatible with Omega + if (std::fabs(casc.massomega() - o2::constants::physics::MassOmegaMinus) < deltaMassOmega) + continue; + + // Omega + // Omega+ selection (Omega+ -> antiL + K+) + if (casc.sign() > 0) { + // PID selections (TPC) + if (casc.ntpcsigmanegpr() < nsigmaTPCmin || casc.ntpcsigmanegpr() > nsigmaTPCmax) + continue; + if (casc.ntpcsigmapospi() < nsigmaTPCmin || casc.ntpcsigmapospi() > nsigmaTPCmax) + continue; + + // PID selections (TOF) + if (requireTOF) { + if (casc.ntofsigmanegpr() < nsigmaTOFmin || casc.ntofsigmanegpr() > nsigmaTOFmax) + continue; + if (casc.ntofsigmapospi() < nsigmaTOFmin || casc.ntofsigmapospi() > nsigmaTOFmax) + continue; + } + } + + // Omega- selection (Omega- -> L + K-) + if (casc.sign() < 0) { + // PID selections (TPC) + if (casc.ntpcsigmapospr() < nsigmaTPCmin || casc.ntpcsigmapospr() > nsigmaTPCmax) + continue; + if (casc.ntpcsigmanegpi() < nsigmaTPCmin || casc.ntpcsigmanegpi() > nsigmaTPCmax) + continue; + + // PID selections (TOF) + if (requireTOF) { + if (casc.ntofsigmapospr() < nsigmaTOFmin || casc.ntofsigmapospr() > nsigmaTOFmax) + continue; + if (casc.ntofsigmanegpi() < nsigmaTOFmin || casc.ntofsigmanegpi() > nsigmaTOFmax) + continue; + } + } + + // PID selection on bachelor + if (casc.ntpcsigmabachka() < nsigmaTPCmin || casc.ntpcsigmabachka() > nsigmaTPCmax) + continue; + + // PID selections (TOF) + if (requireTOF) { + if (casc.ntofsigmabachka() < nsigmaTOFmin || casc.ntofsigmabachka() > nsigmaTOFmax) + continue; + } + // V0 mass window + if (std::fabs(casc.masslambda() - o2::constants::physics::MassLambda0) > deltaMassLambda) + continue; + + // Reject candidates compatible with Xi + if (std::fabs(casc.massxi() - o2::constants::physics::MassXiMinus) < deltaMassXi) + continue; + + if (casc.isUE()) { + if (casc.sign() < 0) { + registryData.fill(HIST("XiNeg_in_ue"), casc.multft0m(), casc.pt(), casc.massxi()); + registryData.fill(HIST("OmegaNeg_in_ue"), casc.multft0m(), casc.pt(), casc.massomega()); + } else if (casc.sign() > 0) { + registryData.fill(HIST("XiPos_in_ue"), casc.multft0m(), casc.pt(), casc.massxi()); + registryData.fill(HIST("OmegaPos_in_ue"), casc.multft0m(), casc.pt(), casc.massomega()); + } + } else if (casc.isJC()) { + if (casc.sign() < 0) { + registryData.fill(HIST("XiNeg_in_jet"), casc.multft0m(), casc.pt(), casc.massxi()); + registryData.fill(HIST("OmegaNeg_in_jet"), casc.multft0m(), casc.pt(), casc.massomega()); + } else if (casc.sign() > 0) { + registryData.fill(HIST("XiPos_in_jet"), casc.multft0m(), casc.pt(), casc.massxi()); + registryData.fill(HIST("OmegaPos_in_jet"), casc.multft0m(), casc.pt(), casc.massomega()); + } + } + } + } + PROCESS_SWITCH(StrangenessInJets, processDerivedAnalysis, "Postprocessing for derived data analysis", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx b/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx new file mode 100644 index 00000000000..2e65d0e7c61 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx @@ -0,0 +1,1922 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file strangenessInJetsIons.cxx +/// +/// \brief Task for analysis of strangeness in jets in light-ion collisions +/// \author Lorenzo Bernardinis (lorenzo.bernardinis@cern.ch) +/// +/// Based on PWGLF/Tasks/Strangeness/strangenessInJets.cxx +/// \since 11/2025 + +#include "PWGJE/Core/JetBkgSubUtils.h" +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/Core/JetUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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::math; +using std::array; + +// Define convenient aliases for joined AOD tables +using SelCollisions = soa::Join; +using SimCollisions = soa::Join; +using DaughterTracks = soa::Join; +using DaughterTracksMC = soa::Join; + +struct StrangenessInJetsIons { + + // Instantiate the CCDB service and API interface + Service ccdb; + o2::ccdb::CcdbApi ccdbApi; + + // Instantiate the Zorro processor for skimmed data and define an output object + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + // Define histogram registries + HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Global analysis parameters + // List of Particles + enum ParticleOfInterest { kV0Particles, + kCascades, + kPions, + kKaons, + kProtons }; + std::vector particleOfInterestKeys = { + ParticleOfInterest::kV0Particles, + ParticleOfInterest::kCascades, + ParticleOfInterest::kPions, + ParticleOfInterest::kKaons, + ParticleOfInterest::kProtons}; + std::map particleOfInterestDict; + + Configurable> particleOfInterest{"particleOfInterest", {0, 0, 0, 0, 0}, "Particles to study: [K0 and Lambda, Xi and Omega, Pion, Kaon, Proton]"}; + Configurable minJetPt{"minJetPt", 10.0, "Minimum reconstructed pt of the jet (GeV/c)"}; + Configurable rJet{"rJet", 0.3, "Jet resolution parameter (R)"}; + Configurable zVtx{"zVtx", 10.0, "Maximum z-vertex position"}; + Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "eta gap from detector edge"}; + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Enable processing of skimmed data"}; + Configurable triggerName{"triggerName", "fOmega", "Software trigger name"}; + + // Event selection + Configurable isApplySameBunchPileup{"isApplySameBunchPileup", true, "Enable SameBunchPileup cut"}; + Configurable isApplyGoodZvtxFT0vsPV{"isApplyGoodZvtxFT0vsPV", true, "Enable GoodZvtxFT0vsPV cut"}; + + // Track analysis parameters + Configurable minITSnCls{"minITSnCls", 4, "Minimum number of ITS clusters"}; + Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 70, "Minimum number of TPC crossed rows"}; + Configurable maxChi2TPC{"maxChi2TPC", 4.0f, "Maximum chi2 per cluster TPC"}; + Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; + Configurable etaMax{"etaMax", +0.8f, "Maximum eta"}; + Configurable ptMinV0Proton{"ptMinV0Proton", 0.3f, "Minimum pt of protons from V0"}; + Configurable ptMaxV0Proton{"ptMaxV0Proton", 10.0f, "Maximum pt of protons from V0"}; + Configurable ptMinV0Pion{"ptMinV0Pion", 0.1f, "Minimum pt of pions from V0"}; + Configurable ptMaxV0Pion{"ptMaxV0Pion", 1.5f, "Maximum pt of pions from V0"}; + Configurable ptMinK0Pion{"ptMinK0Pion", 0.3f, "Minimum pt of pions from K0"}; + Configurable ptMaxK0Pion{"ptMaxK0Pion", 10.0f, "Maximum pt of pions 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 requireITS{"requireITS", false, "Require ITS hit"}; + Configurable requireTOF{"requireTOF", false, "Require TOF hit"}; + + // V0 analysis parameters + Configurable minimumV0Radius{"minimumV0Radius", 1.2f, "Minimum V0 Radius (cm)"}; + Configurable maximumV0Radius{"maximumV0Radius", 40.0f, "Maximum V0 Radius (cm)"}; + Configurable v0cospaMin{"v0cospaMin", 0.995f, "Minimum V0 cosine of pointing angle"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 1.0f, "Maximum DCA between V0 daughters"}; + Configurable requireV0type{"requireV0type", true, "Require V0 type Cut"}; + Configurable v0type{"v0type", 1, "0: 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"}; + // K0S parameters + Configurable dcaNegToPVminK0s{"dcaNegToPVminK0s", 0.1f, "Minimum DCA of negative track to primary vertex in K0S decays (cm)"}; + Configurable dcaPosToPVminK0s{"dcaPosToPVminK0s", 0.1f, "Minimum DCA of positive track to primary vertex in K0S decays (cm)"}; + Configurable requireArmenterosCut{"requireArmenterosCut", true, "Require Armenteros Cut"}; + Configurable paramArmenterosCut{"paramArmenterosCut", 2.0f, "Parameter Armenteros Cut (K0S only). This parameters multiplies qtarm"}; + Configurable ctauK0s{"ctauK0s", 20.0f, "C tau K0S (cm)"}; + // Lambda/anti-Lambda paramaters + Configurable dcaProtonToPVmin{"dcaProtonToPVmin", 0.05f, "Minimum DCA of proton/anti-proton track to primary vertex in Lambda/anti-Lambda decays (cm)"}; + Configurable dcaPionToPVmin{"dcaPionToPVmin", 0.2f, "Minimum DCA of pion-/pion+ track to primary vertex in Lambda/anti-Lambda decays (cm)"}; + Configurable ctauLambda{"ctauLambda", 30.0f, "C tau Lambda (cm)"}; + + // Cascade analysis parameters + Configurable minimumCascRadius{"minimumCascRadius", 0.1f, "Minimum cascade radius"}; + Configurable maximumCascRadius{"maximumCascRadius", 40.0f, "Maximum cascade radius"}; + Configurable casccospaMin{"casccospaMin", 0.99f, "Minimum cascade cosine of pointing angle"}; + Configurable dcabachtopvMin{"dcabachtopvMin", 0.1f, "Minimum DCA of bachelor to primary vertex"}; + Configurable dcaV0topvMin{"dcaV0topvMin", 0.1f, "Minimum DCA of V0 to primary vertex"}; + Configurable dcaCascDaughtersMax{"dcaCascDaughtersMax", 0.5f, "Maximum DCA between daughters"}; + Configurable dcaNegToPVminV0{"dcaNegToPVminV0", 0.1f, "Minimum DCA of V0 negative track to primary vertex in cascades"}; + Configurable dcaPosToPVminV0{"dcaPosToPVminV0", 0.1f, "Minimum DCA of V0 positive track to primary vertex in cascades"}; + Configurable deltaMassXi{"deltaMassXi", 0.02f, "Mass window for Xi rejection"}; + Configurable deltaMassOmega{"deltaMassOmega", 0.02f, "Mass window for Omega rejection"}; + Configurable deltaMassLambda{"deltaMassLambda", 0.02f, "Mass window for Lambda inclusion"}; + + struct : ConfigurableGroup { + ConfigurableAxis longLivedBinsNsigma{"longLivedBinsNsigma", {200, -10.f, 10.f}, "Binning of nSigma axis"}; + ConfigurableAxis longLivedBinsPt{"longLivedBinsPt", {VARIABLE_WIDTH, -5.0, -4.8, -4.6, -4.4, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1.0, -0.95, -0.9, -0.85, -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.18, -0.16, -0.14, -0.12, -0.1, 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 longLivedBinsDca{"longLivedBinsDca", {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"}; + } longLivedOptions; + + // Instantiate utility class for jet background subtraction + JetBkgSubUtils backgroundSub; + + // Initialize CCDB access and histogram registry for Zorro processing + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), triggerName.value); + zorro.populateHistRegistry(registryData, bc.runNumber()); + } + } + + void init(InitContext const&) + { + if (cfgSkimmedProcessing) { + zorroSummary.setObject(zorro.getZorroSummary()); + } + + // Define binning and axis specifications for multiplicity, eta, pT, PID, and invariant mass histograms + std::vector multBinning = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; + AxisSpec multAxis = {multBinning, "FT0M percentile"}; + const AxisSpec ptAxis{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}; + 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})"}; + const AxisSpec ptAxisLongLived{longLivedOptions.longLivedBinsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec nsigmaTOFAxis{longLivedOptions.longLivedBinsNsigma, "n#sigma_{TOF}"}; + const AxisSpec nsigmaTPCAxis{longLivedOptions.longLivedBinsNsigma, "n#sigma_{TPC}"}; + const AxisSpec dcaAxis{longLivedOptions.longLivedBinsDca, "DCA_{xy} (cm)"}; + + // Join enum ParticleOfInterest and the configurable vector particlesOfInterest in a map particleOfInterestDict + const std::vector& particleOnOff = particleOfInterest; + bool atLeastOneParticle = false; + for (size_t i = 0; i < particleOfInterestKeys.size(); i++) { + ParticleOfInterest p = particleOfInterestKeys[i]; + particleOfInterestDict[p] = particleOnOff.at(i); + if (particleOnOff[i] > 0) { + atLeastOneParticle = true; + LOG(info) << "Selecting particle " << p << endl; + } + } + + if (!atLeastOneParticle) { + LOG(fatal) << "No particles selected. Select at least one particle." << endl; + } + + // Histograms for checks + registryQC.add("V0_type", "V0_type", HistType::kTH1F, {{10, -0.5, 9.5, "V0 type"}}); + + // Histograms for real data + if (doprocessData) { + + // Event counters + 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.5, 100.5, "Multiplicity percentile"}}); + + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(1, "All collisions"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(2, "Zorro selection"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(3, "sel8"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(4, "posZ cut"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(5, "kNoSameBunchPileup"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(6, "kIsGoodZvtxFT0vsPV"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(7, "No empty events"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(8, "At least one jet"); + + // Histograms for analysis of strange hadrons + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryData.add("Lambda_in_jet", "Lambda_in_jet", HistType::kTH3F, {multAxis, ptAxis, invMassLambdaAxis}); + registryData.add("AntiLambda_in_jet", "AntiLambda_in_jet", HistType::kTH3F, {multAxis, ptAxis, invMassLambdaAxis}); + registryData.add("Lambda_in_ue", "Lambda_in_ue", HistType::kTH3F, {multAxis, ptAxis, invMassLambdaAxis}); + registryData.add("AntiLambda_in_ue", "AntiLambda_in_ue", HistType::kTH3F, {multAxis, ptAxis, invMassLambdaAxis}); + registryData.add("K0s_in_jet", "K0s_in_jet", HistType::kTH3F, {multAxis, ptAxis, invMassK0sAxis}); + registryData.add("K0s_in_ue", "K0s_in_ue", HistType::kTH3F, {multAxis, ptAxis, invMassK0sAxis}); + } + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryData.add("XiPos_in_jet", "XiPos_in_jet", HistType::kTH3F, {multAxis, ptAxis, invMassXiAxis}); + registryData.add("XiPos_in_ue", "XiPos_in_ue", HistType::kTH3F, {multAxis, ptAxis, invMassXiAxis}); + registryData.add("XiNeg_in_jet", "XiNeg_in_jet", HistType::kTH3F, {multAxis, ptAxis, invMassXiAxis}); + registryData.add("XiNeg_in_ue", "XiNeg_in_ue", HistType::kTH3F, {multAxis, ptAxis, invMassXiAxis}); + registryData.add("OmegaPos_in_jet", "OmegaPos_in_jet", HistType::kTH3F, {multAxis, ptAxis, invMassOmegaAxis}); + registryData.add("OmegaPos_in_ue", "OmegaPos_in_ue", HistType::kTH3F, {multAxis, ptAxis, invMassOmegaAxis}); + registryData.add("OmegaNeg_in_jet", "OmegaNeg_in_jet", HistType::kTH3F, {multAxis, ptAxis, invMassOmegaAxis}); + registryData.add("OmegaNeg_in_ue", "OmegaNeg_in_ue", HistType::kTH3F, {multAxis, ptAxis, invMassOmegaAxis}); + } + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryData.add("Pion_in_jet", "Pion_in_jet", HistType::kTHnSparseF, {multAxis, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Pion_in_ue", "Pion_in_ue", HistType::kTHnSparseF, {multAxis, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryData.add("Kaon_in_jet", "Kaon_in_jet", HistType::kTHnSparseF, {multAxis, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Kaon_in_ue", "Kaon_in_ue", HistType::kTHnSparseF, {multAxis, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryData.add("Proton_in_jet", "Proton_in_jet", HistType::kTHnSparseF, {multAxis, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + registryData.add("Proton_in_ue", "Proton_in_ue", HistType::kTHnSparseF, {multAxis, ptAxisLongLived, nsigmaTPCAxis, nsigmaTOFAxis, dcaAxis}); + } + } + + // Histograms for mc generated + if (doprocessMCgenerated) { + + // Event counter + registryMC.add("number_of_events_mc_gen", "number of gen events in mc", HistType::kTH1D, {{10, 0, 10, "Event Cuts"}}); + + registryMC.get(HIST("number_of_events_mc_gen"))->GetXaxis()->SetBinLabel(1, "All collisions"); + registryMC.get(HIST("number_of_events_mc_gen"))->GetXaxis()->SetBinLabel(2, "posZ cut"); + registryMC.get(HIST("number_of_events_mc_gen"))->GetXaxis()->SetBinLabel(3, "No empty events"); + registryMC.get(HIST("number_of_events_mc_gen"))->GetXaxis()->SetBinLabel(4, "jet pT cut"); + + // Add histogram to store multiplicity of the event + registryMC.add("number_of_events_vsmultiplicity_gen", "number of events vs multiplicity", HistType::kTH1D, {{101, -0.5, 100.5, "Multiplicity percentile"}}); + + // Histograms for analysis + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.add("K0s_generated_jet", "K0s_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("K0s_generated_ue", "K0s_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("Lambda_generated_jet", "Lambda_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("Lambda_generated_ue", "Lambda_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("AntiLambda_generated_jet", "AntiLambda_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("AntiLambda_generated_ue", "AntiLambda_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + } + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.add("XiPos_generated_jet", "XiPos_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("XiPos_generated_ue", "XiPos_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("XiNeg_generated_jet", "XiNeg_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("XiNeg_generated_ue", "XiNeg_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaPos_generated_jet", "OmegaPos_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaPos_generated_ue", "OmegaPos_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaNeg_generated_jet", "OmegaNeg_generated_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaNeg_generated_ue", "OmegaNeg_generated_ue", HistType::kTH2F, {multAxis, ptAxis}); + } + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.add("Pion_generated_jet", "Pion_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("Pion_generated_ue", "Pion_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + } + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.add("Kaon_generated_jet", "Kaon_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("Kaon_generated_ue", "Kaon_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + } + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.add("Proton_generated_jet", "Proton_generated_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("Proton_generated_ue", "Proton_generated_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + } + } + + // Histograms for mc reconstructed + if (doprocessMCreconstructed) { + + // Event counter + registryMC.add("number_of_events_mc_rec", "number of rec events in mc", HistType::kTH1D, {{10, 0, 10, "Event Cuts"}}); + + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(1, "All collisions"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(2, "sel8"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(3, "posZ cut"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(4, "kNoSameBunchPileup"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(5, "kIsGoodZvtxFT0vsPV"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(6, "No empty events"); + + // Add histogram to store multiplicity of the event + registryMC.add("number_of_events_vsmultiplicity_rec", "number of events vs multiplicity", HistType::kTH1D, {{101, -0.5, 100.5, "Multiplicity percentile"}}); + + // Histograms for analysis + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.add("K0s_reconstructed_jet", "K0s_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("K0s_reconstructed_ue", "K0s_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("Lambda_reconstructed_jet", "Lambda_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("Lambda_reconstructed_ue", "Lambda_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("AntiLambda_reconstructed_jet", "AntiLambda_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("AntiLambda_reconstructed_ue", "AntiLambda_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + // Histograms for secondary hadrons + registryMC.add("K0s_reconstructed_jet_incl", "K0s_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("K0s_reconstructed_ue_incl", "K0s_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_jet_incl", "Lambda_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("Lambda_reconstructed_ue_incl", "Lambda_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_jet_incl", "AntiLambda_reconstructed_jet_incl", HistType::kTH2F, {multBinning, ptAxis}); + registryMC.add("AntiLambda_reconstructed_ue_incl", "AntiLambda_reconstructed_ue_incl", HistType::kTH2F, {multBinning, ptAxis}); + } + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.add("XiPos_reconstructed_jet", "XiPos_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("XiPos_reconstructed_ue", "XiPos_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("XiNeg_reconstructed_jet", "XiNeg_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("XiNeg_reconstructed_ue", "XiNeg_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaPos_reconstructed_jet", "OmegaPos_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaPos_reconstructed_ue", "OmegaPos_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaNeg_reconstructed_jet", "OmegaNeg_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxis}); + registryMC.add("OmegaNeg_reconstructed_ue", "OmegaNeg_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxis}); + } + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.add("Pion_reconstructed_jet", "Pion_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("Pion_reconstructed_ue", "Pion_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + } + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.add("Kaon_reconstructed_jet", "Kaon_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("Kaon_reconstructed_ue", "Kaon_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + } + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.add("Proton_reconstructed_jet", "Proton_reconstructed_jet", HistType::kTH2F, {multAxis, ptAxisLongLived}); + registryMC.add("Proton_reconstructed_ue", "Proton_reconstructed_ue", HistType::kTH2F, {multAxis, ptAxisLongLived}); + } + } + } + + /* + // Calculation of perpendicular axes + void getPerpendicularAxis(TVector3 p, TVector3& u, double sign) + { + // initialization + double ux(0), uy(0), uz(0); + + // components of vector p + const double px = p.X(); + const double py = p.Y(); + const 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 + const double a = px * px + py * py; + const double b = 2.0 * px * pz * pz; + const double c = pz * pz * pz * pz - py * py * py * py - px * px * py * py; + const 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; + } + */ + + // Delta phi calculation + 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; + } + + // Check if particle is a physical primary or a decay product of a heavy-flavor hadron + bool isPhysicalPrimaryOrFromHF(aod::McParticle const& particle, aod::McParticles const& mcParticles) + { + // Keep only pi, K, p, e, mu + int pdg = std::abs(particle.pdgCode()); + if (!(pdg == PDG_t::kPiPlus || pdg == PDG_t::kKPlus || pdg == PDG_t::kProton || pdg == PDG_t::kElectron || pdg == PDG_t::kMuonMinus)) + return false; + + // Constants for identifying heavy-flavor (charm and bottom) content from PDG codes + static constexpr int kCharmQuark = 4; + static constexpr int kBottomQuark = 5; + static constexpr int hundreds = 100; + static constexpr int thousands = 1000; + + // Check if particle is from heavy-flavor decay + bool fromHF = false; + if (particle.has_mothers()) { + auto mother = mcParticles.iteratorAt(particle.mothersIds()[0]); + int motherPdg = std::abs(mother.pdgCode()); + fromHF = (motherPdg / hundreds == kCharmQuark || motherPdg / hundreds == kBottomQuark || motherPdg / thousands == kCharmQuark || motherPdg / thousands == kBottomQuark); + } + + // Select only physical primary particles or from heavy-flavor + return (particle.isPhysicalPrimary() || fromHF); + } + + // Compute two transverse directions orthogonal to vector p + void getPerpendicularDirections(const TVector3& p, TVector3& u1, TVector3& u2) + { + // Get momentum components + double px = p.X(); + double py = p.Y(); + double pz = p.Z(); + + // Precompute squared terms + double px2 = px * px; + double py2 = py * py; + double pz2 = pz * pz; + double pz4 = pz2 * pz2; + + // Case 1: vector along z-axis -> undefined perpendiculars + if (px == 0 && py == 0) { + u1.SetXYZ(0, 0, 0); + u2.SetXYZ(0, 0, 0); + return; + } + + // Case 2: px = 0 -> avoid division by zero + if (px == 0 && py != 0) { + double ux = std::sqrt(py2 - pz4 / py2); + double uy = -pz2 / py; + u1.SetXYZ(ux, uy, pz); + u2.SetXYZ(-ux, uy, pz); + return; + } + + // Case 3: py = 0 -> avoid division by zero + if (py == 0 && px != 0) { + double ux = -pz2 / px; + double uy = std::sqrt(px2 - pz4 / px2); + u1.SetXYZ(ux, uy, pz); + u2.SetXYZ(ux, -uy, pz); + return; + } + + // General case: solve quadratic for perpendicular vectors + 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; + + // Invalid or degenerate solutions + if (delta < 0 || a == 0) { + u1.SetXYZ(0, 0, 0); + u2.SetXYZ(0, 0, 0); + return; + } + + // Solution 1 + double u1x = (-b + std::sqrt(delta)) / (2.0 * a); + double u1y = (-pz2 - px * u1x) / py; + u1.SetXYZ(u1x, u1y, pz); + + // Solution 2 + double u2x = (-b - std::sqrt(delta)) / (2.0 * a); + double u2y = (-pz2 - px * u2x) / py; + u2.SetXYZ(u2x, u2y, pz); + } + + // Find ITS hit + template + bool hasITSHitOnLayer(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 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 ((!hasITSHitOnLayer(track, 1)) && (!hasITSHitOnLayer(track, 2)) && (!hasITSHitOnLayer(track, 3))) + return false; + if (!track.hasTPC()) + return false; + if (track.tpcNClsCrossedRows() < minTpcCr) + return false; + if (track.tpcChi2NCl() > maxChi2Tpc) + return false; + if (track.itsChi2NCl() > maxChi2Its) + return false; + if (std::fabs(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; + } + + // Lambda selections + template + bool passedLambdaSelection(const Lambda& v0, const TrackPos& ptrack, const TrackNeg& ntrack, const TVector3& vtxPos) + { + // Single-track selections + if (!passedSingleTrackSelection(ptrack) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum of lambda daughters + TVector3 proton(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pion(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selection on pt of Lambda daughters + if (proton.Pt() < ptMinV0Proton || proton.Pt() > ptMaxV0Proton) + return false; + if (pion.Pt() < ptMinV0Pion || pion.Pt() > ptMaxV0Pion) + return false; + + // V0 selections + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + if (v0.distovertotmom(vtxPos.X(), vtxPos.Y(), vtxPos.Z()) * o2::constants::physics::MassLambda0 > ctauLambda) + return false; + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + if (std::fabs(v0.dcapostopv()) < dcaProtonToPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcaPionToPVmin) + return false; + if (v0.v0Type() != v0type && requireV0type) { + registryQC.fill(HIST("V0_type"), v0.v0Type()); + return false; + } + + // PID selections (TPC): positive track = proton, negative track = pion + if (ptrack.tpcNSigmaPr() < nsigmaTPCmin || ptrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPi() < nsigmaTPCmin || ntrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + + // PID selections (TOF): positive track = proton, negative track = pion + 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, const TVector3& vtxPos) + { + // Single-track selections + if (!passedSingleTrackSelection(ptrack) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum AntiLambda daughters + TVector3 pion(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 proton(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selections on pt of Antilambda daughters + if (proton.Pt() < ptMinV0Proton || proton.Pt() > ptMaxV0Proton) + return false; + if (pion.Pt() < ptMinV0Pion || pion.Pt() > ptMaxV0Pion) + return false; + + // V0 selections + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + if (v0.distovertotmom(vtxPos.X(), vtxPos.Y(), vtxPos.Z()) * o2::constants::physics::MassLambda0 > ctauLambda) + return false; + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + if (std::fabs(v0.dcapostopv()) < dcaPionToPVmin) + return false; + if (std::fabs(v0.dcanegtopv()) < dcaProtonToPVmin) + return false; + if (v0.v0Type() != v0type && requireV0type) { + registryQC.fill(HIST("V0_type"), v0.v0Type()); + return false; + } + + // PID selections (TPC): negative track = proton, positive track = pion + if (ptrack.tpcNSigmaPi() < nsigmaTPCmin || ptrack.tpcNSigmaPi() > nsigmaTPCmax) + return false; + if (ntrack.tpcNSigmaPr() < nsigmaTPCmin || ntrack.tpcNSigmaPr() > nsigmaTPCmax) + return false; + + // PID selections (TOF): negative track = proton, positive track = pion + 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, const TVector3& vtxPos) + { + // Single-Track Selections + if (!passedSingleTrackSelection(ptrack) || !passedSingleTrackSelection(ntrack)) + return false; + + // Momentum of K0s daughters + TVector3 pionPos(v0.pxpos(), v0.pypos(), v0.pzpos()); + TVector3 pionNeg(v0.pxneg(), v0.pyneg(), v0.pzneg()); + + // Selections on pt of K0s daughters + if (pionPos.Pt() < ptMinK0Pion || pionPos.Pt() > ptMaxK0Pion) + return false; + if (pionNeg.Pt() < ptMinK0Pion || pionNeg.Pt() > ptMaxK0Pion) + return false; + + // Armenteros-Podolanski cut + if (std::abs(v0.alpha()) >= (paramArmenterosCut * v0.qtarm()) && (requireArmenterosCut)) + return false; + + // V0 selections + if (v0.v0cosPA() < v0cospaMin) + return false; + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + if (v0.distovertotmom(vtxPos.X(), vtxPos.Y(), vtxPos.Z()) * o2::constants::physics::MassK0Short > ctauK0s) + return false; + if (std::fabs(v0.dcaV0daughters()) > dcaV0DaughtersMax) + return false; + if (std::fabs(v0.dcapostopv()) < dcaPosToPVminK0s) + return false; + if (std::fabs(v0.dcanegtopv()) < dcaNegToPVminK0s) + return false; + if (v0.v0Type() != v0type && requireV0type) { + registryQC.fill(HIST("V0_type"), v0.v0Type()); + 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) + { + // Single-track selections on cascade daughters + 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 || ntrack.pt() > ptMaxV0Proton) + return false; + if (ptrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + return false; + } + + // Xi- selection (Xi- -> L + pi-) + if (btrack.sign() < 0) { + if (ptrack.pt() < ptMinV0Proton || ptrack.pt() > ptMaxV0Proton) + return false; + if (ntrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassPionCharged); + const double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + 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()) < dcaPosToPVminV0) + return false; + if (std::fabs(casc.dcanegtopv()) < dcaNegToPVminV0) + 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; + } + + // Reject candidates compatible with Omega + if (std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < deltaMassOmega) + return false; + return true; + } + + // Omega selections + template + bool passedOmegaSelection(const Omega& casc, const TrackPos& ptrack, const TrackNeg& ntrack, const TrackBac& btrack, const Coll& coll) + { + // Single-track selections on cascade daughters + 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 || ntrack.pt() > ptMaxV0Proton) + return false; + if (ptrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + return false; + } + + // Omega- selection (Omega- -> L + K-) + if (btrack.sign() < 0) { + if (ptrack.pt() < ptMinV0Proton || ptrack.pt() > ptMaxV0Proton) + return false; + if (ntrack.pt() < ptMinV0Pion || 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; + } + + // Require that V0 is compatible with Lambda + ROOT::Math::PxPyPzMVector pProton; + ROOT::Math::PxPyPzMVector pPion; + pProton.SetCoordinates(ptrack.px(), ptrack.py(), ptrack.pz(), o2::constants::physics::MassProton); + pPion.SetCoordinates(ntrack.px(), ntrack.py(), ntrack.pz(), o2::constants::physics::MassPionCharged); + double mLambda = (pProton + pPion).M(); + if (std::fabs(mLambda - o2::constants::physics::MassLambda0) > deltaMassLambda) + 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()) < dcaPosToPVminV0) + return false; + if (std::fabs(casc.dcanegtopv()) < dcaNegToPVminV0) + 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; + } + + // Reject candidates compatible with Xi + if (std::fabs(casc.mXi() - o2::constants::physics::MassXiMinus) < deltaMassXi) + 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.tpcNClsCrossedRows() < minNCrossedRowsTPC) + 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; + } + + // Event selection for MC Reco collision + template + bool selectRecoEvent(const coll& recoColl) + { + if (!recoColl.sel8()) + return false; + + if (std::fabs(recoColl.posZ()) > zVtx) + return false; + + if (isApplySameBunchPileup && !recoColl.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return false; + + if (isApplyGoodZvtxFT0vsPV && !recoColl.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return false; + + return true; + } + + // Process data + void processData(SelCollisions::iterator const& collision, aod::V0Datas const& fullV0s, + aod::CascDataExt const& Cascades, DaughterTracks const& tracks, + aod::BCsWithTimestamps const&) + { + // Fill event counter before event selection + registryData.fill(HIST("number_of_events_data"), 0.5); + + // Get the bunch crossing (BC) information associated with the collision + auto bc = collision.template bc_as(); + + // Initialize CCDB objects using the BC info + initCCDB(bc); + + // If skimmed processing is enabled, skip this event unless it passes Zorro selection + if (cfgSkimmedProcessing && !zorro.isSelected(collision.template bc_as().globalBC())) { + return; + } + + // Fill event counter after zorro selection + registryData.fill(HIST("number_of_events_data"), 1.5); + + // Event selection + if (!collision.sel8()) + return; + + // Fill event counter after sel8 selection + registryData.fill(HIST("number_of_events_data"), 2.5); + + // Require vertex position within the allowed z range + if (std::fabs(collision.posZ()) > zVtx) + return; + + // Fill event counter after z vertex selection + registryData.fill(HIST("number_of_events_data"), 3.5); + + // Reject collisions associated to the same found BC + if (isApplySameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + + // Fill event counter after selection kNoSameBunchPileup + registryData.fill(HIST("number_of_events_data"), 4.5); + + // Compatible z_vtx from FT0 and from PV + if (isApplyGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + + // Fill event counter after selection kIsGoodZvtxFT0vsPV + registryData.fill(HIST("number_of_events_data"), 5.5); + + // Loop over reconstructed tracks + std::vector fjParticles; + for (auto const& track : tracks) { + + // Require that tracks pass selection criteria + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + + // Reject empty events + if (fjParticles.size() < 1) + return; + registryData.fill(HIST("number_of_events_data"), 6.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] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Jet selection + bool isAtLeastOneJetSelected = false; + std::vector selectedJet; + std::vector ue1; + std::vector ue2; + + // Loop over reconstructed jets + for (const auto& jet : jets) { + + // Jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - 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; + isAtLeastOneJetSelected = true; + + // Calculation of perpendicular cones + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Store jet and UE axes + selectedJet.emplace_back(jetAxis); + ue1.emplace_back(ueAxis1); + ue2.emplace_back(ueAxis2); + } + if (!isAtLeastOneJetSelected) + return; + + // Fill event counter with events with at least one jet + registryData.fill(HIST("number_of_events_data"), 7.5); + + // Event multiplicity + const float multiplicity = collision.centFT0M(); + + // Fill event multiplicity + registryData.fill(HIST("number_of_events_vsmultiplicity"), multiplicity); + + // Loop over selected jets + for (int i = 0; i < static_cast(selectedJet.size()); i++) { + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { // V0s + for (const auto& v0 : fullV0s) { + + // Get V0 daughters + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + TVector3 v0dir(v0.px(), v0.py(), v0.pz()); + + // Calculate distance from jet and UE axes + const float deltaEtaJet = v0dir.Eta() - selectedJet[i].Eta(); + const float deltaPhiJet = getDeltaPhi(v0dir.Phi(), selectedJet[i].Phi()); + const float deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const float deltaEtaUe1 = v0dir.Eta() - ue1[i].Eta(); + const float deltaPhiUe1 = getDeltaPhi(v0dir.Phi(), ue1[i].Phi()); + const float deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const float deltaEtaUe2 = v0dir.Eta() - ue2[i].Eta(); + const float deltaPhiUe2 = getDeltaPhi(v0dir.Phi(), ue2[i].Phi()); + const float deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Vertex position vector + TVector3 vtxPos(collision.posX(), collision.posY(), collision.posZ()); + + // K0s + if (passedK0ShortSelection(v0, pos, neg, vtxPos)) { + 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, vtxPos)) { + 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, vtxPos)) { + 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()); + } + } + } + } + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { // Cascades + for (const auto& casc : Cascades) { + // Get cascade daughters + const auto& bach = casc.bachelor_as(); + const auto& pos = casc.posTrack_as(); + const auto& neg = casc.negTrack_as(); + TVector3 cascadeDir(casc.px(), casc.py(), casc.pz()); + + // Calculate distance from jet and UE axes + const double deltaEtaJet = cascadeDir.Eta() - selectedJet[i].Eta(); + const double deltaPhiJet = getDeltaPhi(cascadeDir.Phi(), selectedJet[i].Phi()); + const double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const double deltaEtaUe1 = cascadeDir.Eta() - ue1[i].Eta(); + const double deltaPhiUe1 = getDeltaPhi(cascadeDir.Phi(), ue1[i].Phi()); + const double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const double deltaEtaUe2 = cascadeDir.Eta() - ue2[i].Eta(); + const double deltaPhiUe2 = getDeltaPhi(cascadeDir.Phi(), ue2[i].Phi()); + const double 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()); + } + } + } + } + if (particleOfInterestDict[ParticleOfInterest::kPions] || + particleOfInterestDict[ParticleOfInterest::kKaons] || + particleOfInterestDict[ParticleOfInterest::kProtons]) { + for (const auto& trk : tracks) { + + if (!passedSingleTrackSelection(trk)) { + continue; + } + + const double deltaEtaJet = trk.eta() - selectedJet[i].Eta(); + const double deltaPhiJet = getDeltaPhi(trk.phi(), selectedJet[i].Phi()); + const double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + const double deltaEtaUe1 = trk.eta() - ue1[i].Eta(); + const double deltaPhiUe1 = getDeltaPhi(trk.phi(), ue1[i].Phi()); + const double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + const double deltaEtaUe2 = trk.eta() - ue2[i].Eta(); + const double deltaPhiUe2 = getDeltaPhi(trk.phi(), ue2[i].Phi()); + const double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + float nsigmaTPC = 0.f; + float nsigmaTOF = 0.f; + + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + nsigmaTPC = trk.tpcNSigmaPi(); + nsigmaTOF = trk.tofNSigmaPi(); + if (deltaRjet < rJet) { + registryData.fill(HIST("Pion_in_jet"), multiplicity, trk.pt() * trk.sign(), nsigmaTPC, nsigmaTOF, trk.dcaXY()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("Pion_in_ue"), multiplicity, trk.pt() * trk.sign(), nsigmaTPC, nsigmaTOF, trk.dcaXY()); + } + } + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + nsigmaTPC = trk.tpcNSigmaKa(); + nsigmaTOF = trk.tofNSigmaKa(); + if (deltaRjet < rJet) { + registryData.fill(HIST("Kaon_in_jet"), multiplicity, trk.pt() * trk.sign(), nsigmaTPC, nsigmaTOF, trk.dcaXY()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("Kaon_in_ue"), multiplicity, trk.pt() * trk.sign(), nsigmaTPC, nsigmaTOF, trk.dcaXY()); + } + } + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + nsigmaTPC = trk.tpcNSigmaPr(); + nsigmaTOF = trk.tofNSigmaPr(); + if (deltaRjet < rJet) { + registryData.fill(HIST("Proton_in_jet"), multiplicity, trk.pt() * trk.sign(), nsigmaTPC, nsigmaTOF, trk.dcaXY()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryData.fill(HIST("Proton_in_ue"), multiplicity, trk.pt() * trk.sign(), nsigmaTPC, nsigmaTOF, trk.dcaXY()); + } + } + } + } + } + } + PROCESS_SWITCH(StrangenessInJetsIons, processData, "Process data", true); + + // Define per-collision preslices for V0s, cascades, MC particles, and daughter tracks + 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 processMCgenerated(aod::McCollisions const& collisions, + SimCollisions const& mcRecoCollisions, + aod::McParticles const& mcParticles) + { + // Define per-event particle containers + std::vector fjParticles; + std::vector strHadronMomentum; + std::vector pdg; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Loop over MC collisions + for (const auto& collision : collisions) { + // Get multiplicity from RECO MC + // Select RECO collisions for which "mcCollisionsID" = collision.globalIndex() + float multiplicity = -999; + + // Retrieve multiplicity from the corresponding MC RECO collision + for (const auto& recoColl : mcRecoCollisions) { + if (collision.globalIndex() == recoColl.mcCollisionId()) { + if (!recoColl.has_mcCollision()) { + continue; + } + + if (!selectRecoEvent(recoColl)) + continue; + + multiplicity = recoColl.centFT0M(); + // LOGF(info, " MC GEN index: %d", collision.globalIndex()); + // LOGF(info, " MC RECO index: %d", recoColl.mcCollisionId()); + // LOGF(info, " multiplicity: %f", multiplicity); + break; + } + } + + if (multiplicity == -999) + continue; + + // Clear containers at the start of the event loop + fjParticles.clear(); + strHadronMomentum.clear(); + pdg.clear(); + + // Fill event counter before any selection + registryMC.fill(HIST("number_of_events_mc_gen"), 0.5); + + // Require vertex position within the allowed z range + if (std::fabs(collision.posZ()) > zVtx) + return; + + // Fill event counter after selection on z-vertex + registryMC.fill(HIST("number_of_events_mc_gen"), 1.5); + + // Multiplicity of generated event retrived from corresponding MC RECO collision + float genMultiplicity = multiplicity; + + // MC particles per collision + auto mcParticlesPerColl = mcParticles.sliceBy(perMCCollision, collision.globalIndex()); + + // Loop over all MC particles and select physical primaries within acceptance + for (const auto& particle : mcParticlesPerColl) { + // Store properties of strange hadrons + int pdgAbs = std::abs(particle.pdgCode()); + if (particle.isPhysicalPrimary() && (pdgAbs == kK0Short || pdgAbs == kLambda0 || pdgAbs == kXiMinus || pdgAbs == kOmegaMinus)) { + pdg.emplace_back(particle.pdgCode()); + strHadronMomentum.emplace_back(particle.px(), particle.py(), particle.pz()); + } + // Select physical primary particles or HF decay products + if (!isPhysicalPrimaryOrFromHF(particle, mcParticles)) + continue; + + double minPtParticle = 0.1; + if (particle.eta() < etaMin || particle.eta() > etaMax || particle.pt() < minPtParticle) + continue; + + // Build 4-momentum assuming charged pion mass + static constexpr float kMassPionChargedSquared = o2::constants::physics::MassPionCharged * o2::constants::physics::MassPionCharged; + const double energy = std::sqrt(particle.p() * particle.p() + kMassPionChargedSquared); + fastjet::PseudoJet fourMomentum(particle.px(), particle.py(), particle.pz(), energy); + fourMomentum.set_user_index(particle.pdgCode()); + fjParticles.emplace_back(fourMomentum); + } + + // Skip events with no particles + if (fjParticles.size() < 1) + continue; + registryMC.fill(HIST("number_of_events_mc_gen"), 2.5); + + // Cluster MC particles into jets using anti-kt algorithm + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + + // Estimate background energy density (rho) in perpendicular cone + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Loop over clustered jets + for (const auto& jet : jets) { + + // Jet must be fully contained in acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - deltaEtaEdge)) + continue; + + // Subtract background energy from jet + auto jetForSub = jet; + fastjet::PseudoJet jetMinusBkg = backgroundSub.doRhoAreaSub(jetForSub, rhoPerp, rhoMPerp); + + // Apply jet pT threshold + if (jetMinusBkg.pt() < minJetPt) + continue; + registryMC.fill(HIST("number_of_events_mc_gen"), 3.5); + registryMC.fill(HIST("number_of_events_vsmultiplicity_gen"), genMultiplicity); + + // Set up two perpendicular cone axes for underlying event estimation + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + double coneRadius = std::sqrt(jet.area() / PI); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Loop over strange hadrons + int index = -1; + for (const auto& hadron : strHadronMomentum) { + // Particle index + index++; + + // Compute distance of particles from jet and UE axes + double deltaEtaJet = hadron.Eta() - jetAxis.Eta(); + double deltaPhiJet = getDeltaPhi(hadron.Phi(), jetAxis.Phi()); + double deltaRJet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = hadron.Eta() - ueAxis1.Eta(); + double deltaPhiUe1 = getDeltaPhi(hadron.Phi(), ueAxis1.Phi()); + double deltaRUe1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = hadron.Eta() - ueAxis2.Eta(); + double deltaPhiUe2 = getDeltaPhi(hadron.Phi(), ueAxis2.Phi()); + double deltaRUe2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Select particles inside jet + if (deltaRJet < coneRadius) { + switch (pdg[index]) { + case kK0Short: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0Bar: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kXiMinus: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiNeg_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kXiPlusBar: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiPos_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaMinus: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaNeg_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaPlusBar: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaPos_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kPiPlus: + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("Pion_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kKPlus: + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("Kaon_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kProton: + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("Proton_generated_jet"), genMultiplicity, hadron.Pt()); + } + break; + case kPiMinus: + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("Pion_generated_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kKMinus: + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("Kaon_generated_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kProtonBar: + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("Proton_generated_jet"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + default: + break; + } + } + + // Select particles inside UE cones + if (deltaRUe1 < coneRadius || deltaRUe2 < coneRadius) { + switch (pdg[index]) { + case kK0Short: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("K0s_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("Lambda_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kLambda0Bar: + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + registryMC.fill(HIST("AntiLambda_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kXiMinus: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiNeg_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kXiPlusBar: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("XiPos_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaMinus: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaNeg_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kOmegaPlusBar: + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + registryMC.fill(HIST("OmegaPos_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kPiPlus: + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("Pion_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kKPlus: + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("Kaon_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kProton: + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("Proton_generated_ue"), genMultiplicity, hadron.Pt()); + } + break; + case kPiMinus: + if (particleOfInterestDict[ParticleOfInterest::kPions]) { + registryMC.fill(HIST("Pion_generated_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kKMinus: + if (particleOfInterestDict[ParticleOfInterest::kKaons]) { + registryMC.fill(HIST("Kaon_generated_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + case kProtonBar: + if (particleOfInterestDict[ParticleOfInterest::kProtons]) { + registryMC.fill(HIST("Proton_generated_ue"), genMultiplicity, hadron.Pt() * -1.f); + } + break; + default: + break; + } + } + } + } + } + } + PROCESS_SWITCH(StrangenessInJetsIons, processMCgenerated, "Process MC generated events", false); + + // Reconstructed MC events + void processMCreconstructed(SimCollisions const& collisions, + DaughterTracksMC const& mcTracks, aod::V0Datas const& fullV0s, + aod::CascDataExt const& Cascades, const aod::McParticles&) + { + // Define per-event containers + std::vector fjParticles; + std::vector selectedJet; + std::vector ue1; + std::vector ue2; + + // Jet and area definitions + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet); + fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0)); + + // Loop over reconstructed collisions + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + + // Clear containers at the start of the event loop + fjParticles.clear(); + selectedJet.clear(); + ue1.clear(); + ue2.clear(); + + // Fill event counter before any selection + registryMC.fill(HIST("number_of_events_mc_rec"), 0.5); + if (!collision.sel8()) + continue; + + // Fill event counter after event selection + registryMC.fill(HIST("number_of_events_mc_rec"), 1.5); + if (std::fabs(collision.posZ()) > zVtx) + continue; + + // Fill event counter after selection on z-vertex + registryMC.fill(HIST("number_of_events_mc_rec"), 2.5); + + // Reject collisions associated to the same found BC + if (isApplySameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + continue; + + // Fill event counter after selection kNoSameBunchPileup + registryMC.fill(HIST("number_of_events_mc_rec"), 3.5); + + // Compatible z_vtx from FT0 and from PV + if (isApplyGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + continue; + + // Fill event counter after selection kIsGoodZvtxFT0vsPV + registryMC.fill(HIST("number_of_events_mc_rec"), 4.5); + + // Event multiplicity + const float multiplicity = collision.centFT0M(); + + // Number of V0 and cascades per collision + auto v0sPerColl = fullV0s.sliceBy(perCollisionV0, collision.globalIndex()); + auto cascPerColl = Cascades.sliceBy(perCollisionCasc, collision.globalIndex()); + auto tracksPerColl = mcTracks.sliceBy(perCollisionTrk, collision.globalIndex()); + + // Loop over reconstructed tracks + for (auto const& track : tracksPerColl) { + if (!passedTrackSelectionForJetReconstruction(track)) + continue; + + // 4-momentum representation of a particle + fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(o2::constants::physics::MassPionCharged)); + fjParticles.emplace_back(fourMomentum); + } + + // Reject empty events + if (fjParticles.size() < 1) + continue; + registryMC.fill(HIST("number_of_events_mc_rec"), 5.5); + + // Cluster particles using the anti-kt algorithm + fastjet::ClusterSequenceArea cs(fjParticles, jetDef, areaDef); + std::vector jets = fastjet::sorted_by_pt(cs.inclusive_jets()); + auto [rhoPerp, rhoMPerp] = jetutilities::estimateRhoPerpCone(fjParticles, jets[0], rJet); + + // Jet selection + bool isAtLeastOneJetSelected = false; + + // Loop over clustered jets + for (const auto& jet : jets) { + + // jet must be fully contained in the acceptance + if ((std::fabs(jet.eta()) + rJet) > (etaMax - 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; + isAtLeastOneJetSelected = true; + + // Perpendicular cones + TVector3 jetAxis(jet.px(), jet.py(), jet.pz()); + TVector3 ueAxis1(0, 0, 0), ueAxis2(0, 0, 0); + getPerpendicularDirections(jetAxis, ueAxis1, ueAxis2); + if (ueAxis1.Mag() == 0 || ueAxis2.Mag() == 0) { + continue; + } + + // Store selected jet and UE cone axes + selectedJet.emplace_back(jetAxis); + ue1.emplace_back(ueAxis1); + ue2.emplace_back(ueAxis2); + } + if (!isAtLeastOneJetSelected) + continue; + + // Fill event counter for events with at least one selected jet + registryMC.fill(HIST("number_of_events_mc_rec"), 4.5); + registryMC.fill(HIST("number_of_events_vsmultiplicity_rec"), multiplicity); + + // Loop over selected jets + for (int i = 0; i < static_cast(selectedJet.size()); i++) { + + // V0 particles + if (particleOfInterestDict[ParticleOfInterest::kV0Particles]) { + for (const auto& v0 : v0sPerColl) { + const auto& pos = v0.posTrack_as(); + const auto& neg = v0.negTrack_as(); + TVector3 v0dir(v0.px(), v0.py(), v0.pz()); + + // Get MC particles + if (!pos.has_mcParticle() || !neg.has_mcParticle()) + continue; + auto posParticle = pos.mcParticle_as(); + auto negParticle = neg.mcParticle_as(); + if (!posParticle.has_mothers() || !negParticle.has_mothers()) + continue; + + // Select particles originating from the same parent + 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; + + // Compute distance from jet and UE axes + double deltaEtaJet = v0dir.Eta() - selectedJet[i].Eta(); + double deltaPhiJet = getDeltaPhi(v0dir.Phi(), selectedJet[i].Phi()); + double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = v0dir.Eta() - ue1[i].Eta(); + double deltaPhiUe1 = getDeltaPhi(v0dir.Phi(), ue1[i].Phi()); + double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = v0dir.Eta() - ue2[i].Eta(); + double deltaPhiUe2 = getDeltaPhi(v0dir.Phi(), ue2[i].Phi()); + double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Vertex position vector + TVector3 vtxPos(collision.posX(), collision.posY(), collision.posZ()); + + // K0s + if (passedK0ShortSelection(v0, pos, neg, vtxPos) && pdgParent == kK0Short && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("K0s_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("K0s_reconstructed_ue"), multiplicity, v0.pt()); + } + } + // Lambda + if (passedLambdaSelection(v0, pos, neg, vtxPos) && pdgParent == kLambda0 && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_ue"), multiplicity, v0.pt()); + } + } + // AntiLambda + if (passedAntiLambdaSelection(v0, pos, neg, vtxPos) && pdgParent == kLambda0Bar && isPhysPrim) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_jet"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_ue"), multiplicity, v0.pt()); + } + } + + // Fill inclusive spectra + // K0s + if (passedK0ShortSelection(v0, pos, neg, vtxPos) && pdgParent == kK0Short) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("K0s_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("K0s_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + // Lambda + if (passedLambdaSelection(v0, pos, neg, vtxPos) && pdgParent == kLambda0) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("Lambda_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + // AntiLambda + if (passedAntiLambdaSelection(v0, pos, neg, vtxPos) && pdgParent == kLambda0Bar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_jet_incl"), multiplicity, v0.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("AntiLambda_reconstructed_ue_incl"), multiplicity, v0.pt()); + } + } + } + } + + // Cascades + if (particleOfInterestDict[ParticleOfInterest::kCascades]) { + for (const auto& casc : cascPerColl) { + auto bach = casc.bachelor_as(); + auto pos = casc.posTrack_as(); + auto neg = casc.negTrack_as(); + + // Get MC particles + if (!bach.has_mcParticle() || !pos.has_mcParticle() || !neg.has_mcParticle()) + continue; + auto posParticle = pos.mcParticle_as(); + auto negParticle = neg.mcParticle_as(); + auto bachParticle = bach.mcParticle_as(); + if (!posParticle.has_mothers() || !negParticle.has_mothers() || !bachParticle.has_mothers()) + continue; + + // Select particles originating from the same parent + int pdgParent(0); + bool isPhysPrim = false; + 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; + isPhysPrim = particleMotherOfBach.isPhysicalPrimary(); + pdgParent = particleMotherOfBach.pdgCode(); + } + } + } + if (pdgParent == 0) + continue; + if (!isPhysPrim) + continue; + + // Compute distances from jet and UE axes + TVector3 cascadeDir(casc.px(), casc.py(), casc.pz()); + double deltaEtaJet = cascadeDir.Eta() - selectedJet[i].Eta(); + double deltaPhiJet = getDeltaPhi(cascadeDir.Phi(), selectedJet[i].Phi()); + double deltaRjet = std::sqrt(deltaEtaJet * deltaEtaJet + deltaPhiJet * deltaPhiJet); + double deltaEtaUe1 = cascadeDir.Eta() - ue1[i].Eta(); + double deltaPhiUe1 = getDeltaPhi(cascadeDir.Phi(), ue1[i].Phi()); + double deltaRue1 = std::sqrt(deltaEtaUe1 * deltaEtaUe1 + deltaPhiUe1 * deltaPhiUe1); + double deltaEtaUe2 = cascadeDir.Eta() - ue2[i].Eta(); + double deltaPhiUe2 = getDeltaPhi(cascadeDir.Phi(), ue2[i].Phi()); + double deltaRue2 = std::sqrt(deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2); + + // Xi+ + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() > 0 && pdgParent == kXiPlusBar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("XiPos_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("XiPos_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Xi- + if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() < 0 && pdgParent == kXiMinus) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("XiNeg_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("XiNeg_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Omega+ + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() > 0 && pdgParent == kOmegaPlusBar) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("OmegaPos_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("OmegaPos_reconstructed_ue"), multiplicity, casc.pt()); + } + } + // Omega- + if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() < 0 && pdgParent == kOmegaMinus) { + if (deltaRjet < rJet) { + registryMC.fill(HIST("OmegaNeg_reconstructed_jet"), multiplicity, casc.pt()); + } + if (deltaRue1 < rJet || deltaRue2 < rJet) { + registryMC.fill(HIST("OmegaNeg_reconstructed_ue"), multiplicity, casc.pt()); + } + } + } + } + } + } + } + PROCESS_SWITCH(StrangenessInJetsIons, processMCreconstructed, "process reconstructed events", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/strangeness_in_jets.cxx b/PWGLF/Tasks/Strangeness/strangeness_in_jets.cxx deleted file mode 100644 index 0029bf064fe..00000000000 --- a/PWGLF/Tasks/Strangeness/strangeness_in_jets.cxx +++ /dev/null @@ -1,1559 +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), Francesca Ercolessi (francesca.ercolessi@cern.ch) -/// \since May 22, 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/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::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; -using std::array; - -using SelCollisions = soa::Join; -using SimCollisions = soa::Join; - -using FullTracks = soa::Join; - -using MCTracks = soa::Join; - -struct strangeness_in_jets { - - // Analysis Histograms: Data - HistogramRegistry registryData{ - "registryData", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - // MC Histograms - HistogramRegistry registryMC{ - "registryMC", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - // QC Histograms - HistogramRegistry registryQC{ - "registryQC", - {}, - OutputObjHandlingPolicy::AnalysisObject, - true, - true}; - - // Global Parameters - Configurable particle_of_interest{"particle_of_interest", 0, "0=v0, 1=cascade, 2=pions"}; - Configurable ptLeadingMin{"ptLeadingMin", 5.0f, "pt leading min"}; - Configurable Rjet{"Rjet", 0.3f, "jet resolution parameter R"}; - Configurable Rmax{"Rmax", 0.3f, "radius of the jet and UE cones"}; - Configurable zVtx{"zVtx", 10.0f, "z vertex cut"}; - - // 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 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 ptMin_V0_proton{"ptMin_V0_proton", 0.3f, "pt min of proton from V0"}; - Configurable ptMax_V0_proton{"ptMax_V0_proton", 10.0f, "pt max of proton from V0"}; - Configurable ptMin_V0_pion{"ptMin_V0_pion", 0.1f, "pt min of pion from V0"}; - Configurable ptMax_V0_pion{"ptMax_V0_pion", 1.5f, "pt max of pion from V0"}; - Configurable ptMin_K0_pion{"ptMin_K0_pion", 0.3f, "pt min of pion from K0"}; - Configurable ptMax_K0_pion{"ptMax_K0_pion", 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 dcaxyMax{"dcaxyMax", 0.1f, "Maximum DCAxy to primary vertex"}; - Configurable dcazMax{"dcazMax", 0.1f, "Maximum DCAz to primary vertex"}; - Configurable yMin{"yMin", -0.5f, "minimum y"}; - Configurable yMax{"yMax", +0.5f, "maximum y"}; - 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"}; - - // List of Particles - enum option { vzeros, - cascades, - pions }; - - void init(InitContext const&) - { - // Event Counters - registryData.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{10, 0, 10, "Event Cuts"}}); - registryMC.add("number_of_events_mc", "number of events in mc", HistType::kTH1F, {{10, 0, 10, "Event Cuts"}}); - registryQC.add("deltaPt_leading", "deltaPt leading part", HistType::kTH1F, {{1000, -0.1, 0.1, "#Delta p_{T}"}}); - - // Multiplicity Binning - std::vector multBinning = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; - AxisSpec multAxis = {multBinning, "FT0C percentile"}; - - // Histograms for pions (data) - registryData.add("piplus_tpc_in_jet", "piplus_tpc_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10, 10, "n#sigma_{TPC}"}}); - registryData.add("piplus_tof_in_jet", "piplus_tof_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10, 10, "n#sigma_{TOF}"}}); - registryData.add("piplus_tpc_in_ue", "piplus_tpc_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10, 10, "n#sigma_{TPC}"}}); - registryData.add("piplus_tof_in_ue", "piplus_tof_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10, 10, "n#sigma_{TOF}"}}); - registryData.add("piminus_tpc_in_jet", "piminus_tpc_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10, 10, "n#sigma_{TPC}"}}); - registryData.add("piminus_tof_in_jet", "piminus_tof_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10, 10, "n#sigma_{TOF}"}}); - registryData.add("piminus_tpc_in_ue", "piminus_tpc_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10, 10, "n#sigma_{TPC}"}}); - registryData.add("piminus_tof_in_ue", "piminus_tof_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -10, 10, "n#sigma_{TOF}"}}); - registryData.add("piplus_dcaxy_in_jet", "piplus_dcaxy_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); - registryData.add("piplus_dcaxy_in_ue", "piplus_dcaxy_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); - registryData.add("piminus_dcaxy_in_jet", "piminus_dcaxy_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); - registryData.add("piminus_dcaxy_in_ue", "piminus_dcaxy_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); - - // Histograms for lambda (data) - registryData.add("Lambda_in_jet", "Lambda_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.09, 1.14, "m_{p#pi} (GeV/#it{c}^{2})"}}); - registryData.add("AntiLambda_in_jet", "AntiLambda_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.09, 1.14, "m_{p#pi} (GeV/#it{c}^{2})"}}); - registryData.add("Lambda_in_ue", "Lambda_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.09, 1.14, "m_{p#pi} (GeV/#it{c}^{2})"}}); - registryData.add("AntiLambda_in_ue", "AntiLambda_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.09, 1.14, "m_{p#pi} (GeV/#it{c}^{2})"}}); - - // Histograms for K0s (data) - registryData.add("K0s_in_jet", "K0s_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 0.44, 0.56, "m_{#pi#pi} (GeV/#it{c}^{2})"}}); - registryData.add("K0s_in_ue", "K0s_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 0.44, 0.56, "m_{#pi#pi} (GeV/#it{c}^{2})"}}); - - // Histograms for xi (data) - registryData.add("XiPos_in_jet", "XiPos_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.28, 1.36, "m_{p#pi#pi} (GeV/#it{c}^{2})"}}); - registryData.add("XiPos_in_ue", "XiPos_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.28, 1.36, "m_{p#pi#pi} (GeV/#it{c}^{2})"}}); - registryData.add("XiNeg_in_jet", "XiNeg_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.28, 1.36, "m_{p#pi#pi} (GeV/#it{c}^{2})"}}); - registryData.add("XiNeg_in_ue", "XiNeg_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.28, 1.36, "m_{p#pi#pi} (GeV/#it{c}^{2})"}}); - - // Histograms for omega (data) - registryData.add("OmegaPos_in_jet", "OmegaPos_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.63, 1.71, "m_{p#piK} (GeV/#it{c}^{2})"}}); - registryData.add("OmegaPos_in_ue", "OmegaPos_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.63, 1.71, "m_{p#piK} (GeV/#it{c}^{2})"}}); - registryData.add("OmegaNeg_in_jet", "OmegaNeg_in_jet", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.63, 1.71, "m_{p#piK} (GeV/#it{c}^{2})"}}); - registryData.add("OmegaNeg_in_ue", "OmegaNeg_in_ue", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, 1.63, 1.71, "m_{p#piK} (GeV/#it{c}^{2})"}}); - - // Histograms for efficiency (generated) - registryMC.add("K0s_generated", "K0s_generated", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("Lambda_generated", "Lambda_generated", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("AntiLambda_generated", "AntiLambda_generated", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("XiPos_generated", "XiPos_generated", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("XiNeg_generated", "XiNeg_generated", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("OmegaPos_generated", "OmegaPos_generated", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("OmegaNeg_generated", "OmegaNeg_generated", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // Histograms for efficiency (reconstructed) - registryMC.add("K0s_reconstructed", "K0s_reconstructed", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("Lambda_reconstructed", "Lambda_reconstructed", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("AntiLambda_reconstructed", "AntiLambda_reconstructed", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("XiPos_reconstructed", "XiPos_reconstructed", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("XiNeg_reconstructed", "XiNeg_reconstructed", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("OmegaPos_reconstructed", "OmegaPos_reconstructed", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("OmegaNeg_reconstructed", "OmegaNeg_reconstructed", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // Histograms for secondary hadrons - registryMC.add("K0s_reconstructed_incl", "K0s_reconstructed_incl", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("Lambda_reconstructed_incl", "Lambda_reconstructed_incl", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("AntiLambda_reconstructed_incl", "AntiLambda_reconstructed_incl", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // Histograms for 2d reweighting (K0s) - registryMC.add("K0s_eta_pt_jet", "K0s_eta_pt_jet", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - registryMC.add("K0s_eta_pt_ue", "K0s_eta_pt_ue", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - registryMC.add("K0s_eta_pt_pythia", "K0s_eta_pt_pythia", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - - // Histograms for 2d reweighting (Lambda) - registryMC.add("Lambda_eta_pt_jet", "Lambda_eta_pt_jet", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - registryMC.add("Lambda_eta_pt_ue", "Lambda_eta_pt_ue", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - registryMC.add("Lambda_eta_pt_pythia", "Lambda_eta_pt_pythia", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - - // Histograms for 2d reweighting (Xi) - registryMC.add("Xi_eta_pt_jet", "Xi_eta_pt_jet", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - registryMC.add("Xi_eta_pt_ue", "Xi_eta_pt_ue", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - registryMC.add("Xi_eta_pt_pythia", "Xi_eta_pt_pythia", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - - // Histograms for 2d reweighting (Omega) - registryMC.add("Omega_eta_pt_jet", "Omega_eta_pt_jet", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - registryMC.add("Omega_eta_pt_ue", "Omega_eta_pt_ue", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - registryMC.add("Omega_eta_pt_pythia", "Omega_eta_pt_pythia", HistType::kTH2F, {{100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {18, -0.9, 0.9, "#eta"}}); - - // Histograms for efficiency (pions) - registryMC.add("pi_plus_gen", "pi_plus_gen", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("pi_plus_rec_tpc", "pi_plus_rec_tpc", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("pi_plus_rec_tof", "pi_plus_rec_tof", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("pi_minus_gen", "pi_minus_gen", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("pi_minus_rec_tpc", "pi_minus_rec_tpc", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - registryMC.add("pi_minus_rec_tof", "pi_minus_rec_tof", HistType::kTH2F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}}); - - // MC Templates - registryMC.add("piplus_dcaxy_prim", "piplus_dcaxy_prim", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); - registryMC.add("piminus_dcaxy_prim", "piminus_dcaxy_prim", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); - registryMC.add("piplus_dcaxy_sec", "piplus_dcaxy_sec", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); - registryMC.add("piminus_dcaxy_sec", "piminus_dcaxy_sec", HistType::kTH3F, {multBinning, {100, 0.0, 10.0, "#it{p}_{T} (GeV/#it{c})"}, {200, -1, 1, "DCA_{xy} (cm)"}}); - } - - template - bool passedTrackSelectionForJets(const chargedTrack& 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 (abs(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 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 (track.tpcChi2NCl() > maxChi2TPC) - return false; - if (track.itsChi2NCl() > maxChi2ITS) - return false; - if (track.eta() < etaMin || track.eta() > etaMax) - return false; - if (TMath::Abs(track.dcaZ()) > dcazMax) - return false; - - // Rapidity Selection - TLorentzVector lorentzVect; - lorentzVect.SetXYZM(track.px(), track.py(), track.pz(), 0.13957021); - if (lorentzVect.Rapidity() < yMin || lorentzVect.Rapidity() > yMax) - 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() < ptMin_V0_proton) - return false; - if (proton.Pt() > ptMax_V0_proton) - return false; - if (pion.Pt() < ptMin_V0_pion) - return false; - if (pion.Pt() > ptMax_V0_pion) - return false; - - // V0 Selections - if (v0.v0cosPA() < v0cospaMin) - return false; - if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) - return false; - if (v0.dcaV0daughters() > dcaV0DaughtersMax) - return false; - if (v0.dcapostopv() < dcapostoPVmin) - return false; - if (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; - } - - // Rapidity Selection - TLorentzVector lorentzVect; - lorentzVect.SetXYZM(v0.px(), v0.py(), v0.pz(), 1.115683); - if (lorentzVect.Rapidity() < yMin || lorentzVect.Rapidity() > yMax) - 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() < ptMin_V0_proton) - return false; - if (proton.Pt() > ptMax_V0_proton) - return false; - if (pion.Pt() < ptMin_V0_pion) - return false; - if (pion.Pt() > ptMax_V0_pion) - return false; - - // V0 Selections - if (v0.v0cosPA() < v0cospaMin) - return false; - if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) - return false; - if (v0.dcaV0daughters() > dcaV0DaughtersMax) - return false; - if (v0.dcapostopv() < dcapostoPVmin) - return false; - if (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; - } - - // Rapidity Selection - TLorentzVector lorentzVect; - lorentzVect.SetXYZM(v0.px(), v0.py(), v0.pz(), 1.115683); - if (lorentzVect.Rapidity() < yMin || lorentzVect.Rapidity() > yMax) - 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 pion_pos(v0.pxpos(), v0.pypos(), v0.pzpos()); - TVector3 pion_neg(v0.pxneg(), v0.pyneg(), v0.pzneg()); - - if (pion_pos.Pt() < ptMin_K0_pion) - return false; - if (pion_pos.Pt() > ptMax_K0_pion) - return false; - if (pion_neg.Pt() < ptMin_K0_pion) - return false; - if (pion_neg.Pt() > ptMax_K0_pion) - return false; - - // V0 Selections - if (v0.v0cosPA() < v0cospaMin) - return false; - if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) - return false; - if (v0.dcaV0daughters() > dcaV0DaughtersMax) - return false; - if (v0.dcapostopv() < dcapostoPVmin) - return false; - if (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; - } - - // Rapidity Selection - TLorentzVector lorentzVect; - lorentzVect.SetXYZM(v0.px(), v0.py(), v0.pz(), 0.497614); - if (lorentzVect.Rapidity() < yMin || lorentzVect.Rapidity() > yMax) - 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() < ptMin_V0_proton) - return false; - if (ntrack.pt() > ptMax_V0_proton) - return false; - if (ptrack.pt() < ptMin_V0_pion) - return false; - if (ptrack.pt() > ptMax_V0_pion) - 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() < ptMin_V0_proton) - return false; - if (ptrack.pt() > ptMax_V0_proton) - return false; - if (ntrack.pt() < ptMin_V0_pion) - return false; - if (ntrack.pt() > ptMax_V0_pion) - 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 (casc.dcaV0daughters() > dcaV0DaughtersMax) - return false; - if (casc.dcapostopv() < dcapostoPVmin) - return false; - if (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 (casc.dcabachtopv() < dcabachtopvMin) - return false; - if (casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ()) < dcaV0topvMin) - return false; - if (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; - } - - // Rapidity Selection - TLorentzVector lorentzVect; - lorentzVect.SetXYZM(casc.px(), casc.py(), casc.pz(), 1.32171); - if (lorentzVect.Rapidity() < yMin || lorentzVect.Rapidity() > yMax) - 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() < ptMin_V0_proton) - return false; - if (ntrack.pt() > ptMax_V0_proton) - return false; - if (ptrack.pt() < ptMin_V0_pion) - return false; - if (ptrack.pt() > ptMax_V0_pion) - 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() < ptMin_V0_proton) - return false; - if (ptrack.pt() > ptMax_V0_proton) - return false; - if (ntrack.pt() < ptMin_V0_pion) - return false; - if (ntrack.pt() > ptMax_V0_pion) - 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 (casc.dcaV0daughters() > dcaV0DaughtersMax) - return false; - if (casc.dcapostopv() < dcapostoPVmin) - return false; - if (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 (casc.dcabachtopv() < dcabachtopvMin) - return false; - if (casc.dcav0topv(coll.posX(), coll.posY(), coll.posZ()) < dcaV0topvMin) - return false; - if (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; - } - - // Rapidity Selection - TLorentzVector lorentzVect; - lorentzVect.SetXYZM(casc.px(), casc.py(), casc.pz(), 1.6724); - if (lorentzVect.Rapidity() < yMin || lorentzVect.Rapidity() > yMax) - 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 (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) - { - if (track.p() < 0.6 && abs(track.tpcNSigmaPi()) < 3.0) - return true; - if (track.p() > 0.6 && abs(track.tpcNSigmaPi()) < 3.0 && abs(track.tofNSigmaPi()) < 3.0) - return true; - return false; - } - - 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; - } - - 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; - } - - void get_perpendicular_axis(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 * 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 - 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 * sqrt(delta)) / (2.0 * a); - uy = (-pz * pz - px * ux) / py; - uz = pz; - u.SetXYZ(ux, uy, uz); - return; - } - - void processData(SelCollisions::iterator const& collision, aod::V0Datas const& fullV0s, aod::CascDataExt const& Cascades, aod::V0sLinked const& /*V0linked*/, FullTracks const& tracks) - { - 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); - - // Find Leading Particle - std::vector particle_ID; - int leading_ID(0); - float ptMax(0); - - // Track Index - int i = -1; - for (auto track : tracks) { - - i++; - if (!passedTrackSelectionForJets(track)) - continue; - - if (track.pt() > ptMax) { - leading_ID = i; - ptMax = track.pt(); - } - particle_ID.push_back(i); - } - - if (ptMax < ptLeadingMin) - return; - registryData.fill(HIST("number_of_events_data"), 3.5); - - auto const& leading_track = tracks.iteratorAt(leading_ID); - TVector3 p_leading(leading_track.px(), leading_track.py(), leading_track.pz()); - int nParticles = static_cast(particle_ID.size()); - - // Jet Finder - int exit(0); - int nPartAssociated(0); - 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 / (Rjet * Rjet); - 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); - - // Jet Axis - TVector3 jet_axis(p_leading.X(), p_leading.Y(), p_leading.Z()); - - // Cut events with jet not fully inside acceptance - if ((abs(jet_axis.Eta()) + Rmax) > etaMax) - return; - registryData.fill(HIST("number_of_events_data"), 4.5); - - // Perpendicular Cones for UE - TVector3 ue_axis1(0.0, 0.0, 0.0); - TVector3 ue_axis2(0.0, 0.0, 0.0); - get_perpendicular_axis(jet_axis, ue_axis1, +1.0); - get_perpendicular_axis(jet_axis, 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; - registryData.fill(HIST("number_of_events_data"), 5.5); - - // Event multiplicity - float multiplicity = collision.centFT0M(); - - // Vzeros - if (particle_of_interest == option::vzeros) { - for (auto& v0 : fullV0s) { - - const auto& pos = v0.posTrack_as(); - const auto& neg = v0.negTrack_as(); - TVector3 v0dir(v0.px(), v0.py(), v0.pz()); - - float deltaEta_jet = v0dir.Eta() - jet_axis.Eta(); - float deltaPhi_jet = GetDeltaPhi(v0dir.Phi(), jet_axis.Phi()); - float deltaR_jet = sqrt(deltaEta_jet * deltaEta_jet + deltaPhi_jet * deltaPhi_jet); - float deltaEta_ue1 = v0dir.Eta() - ue_axis1.Eta(); - float deltaPhi_ue1 = GetDeltaPhi(v0dir.Phi(), ue_axis1.Phi()); - float deltaR_ue1 = sqrt(deltaEta_ue1 * deltaEta_ue1 + deltaPhi_ue1 * deltaPhi_ue1); - float deltaEta_ue2 = v0dir.Eta() - ue_axis2.Eta(); - float deltaPhi_ue2 = GetDeltaPhi(v0dir.Phi(), ue_axis2.Phi()); - float deltaR_ue2 = sqrt(deltaEta_ue2 * deltaEta_ue2 + deltaPhi_ue2 * deltaPhi_ue2); - - // K0s - if (passedK0ShortSelection(v0, pos, neg)) { - if (deltaR_jet < Rmax) { - registryData.fill(HIST("K0s_in_jet"), multiplicity, v0.pt(), v0.mK0Short()); - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryData.fill(HIST("K0s_in_ue"), multiplicity, v0.pt(), v0.mK0Short()); - } - } - // Lambda - if (passedLambdaSelection(v0, pos, neg)) { - if (deltaR_jet < Rmax) { - registryData.fill(HIST("Lambda_in_jet"), multiplicity, v0.pt(), v0.mLambda()); - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryData.fill(HIST("Lambda_in_ue"), multiplicity, v0.pt(), v0.mLambda()); - } - } - // AntiLambda - if (passedAntiLambdaSelection(v0, pos, neg)) { - if (deltaR_jet < Rmax) { - registryData.fill(HIST("AntiLambda_in_jet"), multiplicity, v0.pt(), v0.mAntiLambda()); - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryData.fill(HIST("AntiLambda_in_ue"), multiplicity, v0.pt(), v0.mAntiLambda()); - } - } - } - } - - // Cascades - if (particle_of_interest == option::cascades) { - for (auto& casc : Cascades) { - - auto bach = casc.bachelor_as(); - auto pos = casc.posTrack_as(); - auto neg = casc.negTrack_as(); - - TVector3 cascade_dir(casc.px(), casc.py(), casc.pz()); - float deltaEta_jet = cascade_dir.Eta() - jet_axis.Eta(); - float deltaPhi_jet = GetDeltaPhi(cascade_dir.Phi(), jet_axis.Phi()); - float deltaR_jet = sqrt(deltaEta_jet * deltaEta_jet + deltaPhi_jet * deltaPhi_jet); - float deltaEta_ue1 = cascade_dir.Eta() - ue_axis1.Eta(); - float deltaPhi_ue1 = GetDeltaPhi(cascade_dir.Phi(), ue_axis1.Phi()); - float deltaR_ue1 = sqrt(deltaEta_ue1 * deltaEta_ue1 + deltaPhi_ue1 * deltaPhi_ue1); - float deltaEta_ue2 = cascade_dir.Eta() - ue_axis2.Eta(); - float deltaPhi_ue2 = GetDeltaPhi(cascade_dir.Phi(), ue_axis2.Phi()); - float deltaR_ue2 = sqrt(deltaEta_ue2 * deltaEta_ue2 + deltaPhi_ue2 * deltaPhi_ue2); - - // Xi+ - if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() > 0) { - if (deltaR_jet < Rmax) { - registryData.fill(HIST("XiPos_in_jet"), multiplicity, casc.pt(), casc.mXi()); - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryData.fill(HIST("XiPos_in_ue"), multiplicity, casc.pt(), casc.mXi()); - } - } - // Xi- - if (passedXiSelection(casc, pos, neg, bach, collision) && bach.sign() < 0) { - if (deltaR_jet < Rmax) { - registryData.fill(HIST("XiNeg_in_jet"), multiplicity, casc.pt(), casc.mXi()); - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryData.fill(HIST("XiNeg_in_ue"), multiplicity, casc.pt(), casc.mXi()); - } - } - // Omega+ - if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() > 0) { - if (deltaR_jet < Rmax) { - registryData.fill(HIST("OmegaPos_in_jet"), multiplicity, casc.pt(), casc.mOmega()); - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryData.fill(HIST("OmegaPos_in_ue"), multiplicity, casc.pt(), casc.mOmega()); - } - } - // Omega- - if (passedOmegaSelection(casc, pos, neg, bach, collision) && bach.sign() < 0) { - if (deltaR_jet < Rmax) { - registryData.fill(HIST("OmegaNeg_in_jet"), multiplicity, casc.pt(), casc.mOmega()); - } - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) { - registryData.fill(HIST("OmegaNeg_in_ue"), multiplicity, casc.pt(), casc.mOmega()); - } - } - } - } - - // Pions - if (particle_of_interest == option::pions) { - for (auto track : tracks) { - - if (!passedTrackSelectionForPions(track)) - continue; - - TVector3 track_dir(track.px(), track.py(), track.pz()); - float deltaEta_jet = track_dir.Eta() - jet_axis.Eta(); - float deltaPhi_jet = GetDeltaPhi(track_dir.Phi(), jet_axis.Phi()); - float deltaR_jet = sqrt(deltaEta_jet * deltaEta_jet + deltaPhi_jet * deltaPhi_jet); - float deltaEta_ue1 = track_dir.Eta() - ue_axis1.Eta(); - float deltaPhi_ue1 = GetDeltaPhi(track_dir.Phi(), ue_axis1.Phi()); - float deltaR_ue1 = sqrt(deltaEta_ue1 * deltaEta_ue1 + deltaPhi_ue1 * deltaPhi_ue1); - float deltaEta_ue2 = track_dir.Eta() - ue_axis2.Eta(); - float deltaPhi_ue2 = GetDeltaPhi(track_dir.Phi(), ue_axis2.Phi()); - float deltaR_ue2 = sqrt(deltaEta_ue2 * deltaEta_ue2 + deltaPhi_ue2 * deltaPhi_ue2); - - bool isInJet = false; - bool isInUe = false; - if (deltaR_jet < Rmax) - isInJet = true; - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) - isInUe = true; - - if (isHighPurityPion(track) && 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()); - } - if (isHighPurityPion(track) && track.sign() < 0) { - 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 (TMath::Abs(track.dcaXY()) > dcaxyMax) - continue; - - // TPC - if (isInJet && track.sign() > 0) { - registryData.fill(HIST("piplus_tpc_in_jet"), multiplicity, track.pt(), track.tpcNSigmaPi()); - } - if (isInUe && track.sign() > 0) { - registryData.fill(HIST("piplus_tpc_in_ue"), multiplicity, track.pt(), track.tpcNSigmaPi()); - } - if (isInJet && track.sign() < 0) { - registryData.fill(HIST("piminus_tpc_in_jet"), multiplicity, track.pt(), track.tpcNSigmaPi()); - } - if (isInUe && track.sign() < 0) { - registryData.fill(HIST("piminus_tpc_in_ue"), multiplicity, track.pt(), track.tpcNSigmaPi()); - } - if (track.tpcNSigmaPi() < nsigmaTPCmin || track.tpcNSigmaPi() > nsigmaTPCmax) - continue; - if (!track.hasTOF()) - continue; - - // TOF - if (isInJet && track.sign() > 0) { - registryData.fill(HIST("piplus_tof_in_jet"), multiplicity, track.pt(), track.tofNSigmaPi()); - } - if (isInUe && track.sign() > 0) { - registryData.fill(HIST("piplus_tof_in_ue"), multiplicity, track.pt(), track.tofNSigmaPi()); - } - if (isInJet && track.sign() < 0) { - registryData.fill(HIST("piminus_tof_in_jet"), multiplicity, track.pt(), track.tofNSigmaPi()); - } - if (isInUe && track.sign() < 0) { - registryData.fill(HIST("piminus_tof_in_ue"), multiplicity, track.pt(), track.tofNSigmaPi()); - } - } - } - } - PROCESS_SWITCH(strangeness_in_jets, processData, "Process data", true); - - 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, aod::McCollisions const& /*mcCollisions*/, 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 (abs(collision.posZ()) > 10.0) - continue; - - registryMC.fill(HIST("number_of_events_mc"), 2.5); - float multiplicity = collision.centFT0M(); - - auto v0s_per_coll = fullV0s.sliceBy(perCollisionV0, collision.globalIndex()); - auto casc_per_coll = Cascades.sliceBy(perCollisionCasc, collision.globalIndex()); - auto mcParticles_per_coll = mcParticles.sliceBy(perMCCollision, collision.globalIndex()); - auto tracks_per_coll = mcTracks.sliceBy(perCollisionTrk, collision.globalIndex()); - - for (auto& v0 : v0s_per_coll) { - - 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 pdg_parent(0); - bool isPhysPrim = false; - for (auto& particleMotherOfNeg : negParticle.mothers_as()) { - for (auto& particleMotherOfPos : posParticle.mothers_as()) { - if (particleMotherOfNeg == particleMotherOfPos) { - pdg_parent = particleMotherOfNeg.pdgCode(); - isPhysPrim = particleMotherOfNeg.isPhysicalPrimary(); - } - } - } - if (pdg_parent == 0) - continue; - - // K0s - if (passedK0ShortSelection(v0, pos, neg) && pdg_parent == 310) { - registryMC.fill(HIST("K0s_reconstructed_incl"), multiplicity, v0.pt()); - } - if (passedLambdaSelection(v0, pos, neg) && pdg_parent == 3122) { - registryMC.fill(HIST("Lambda_reconstructed_incl"), multiplicity, v0.pt()); - } - if (passedAntiLambdaSelection(v0, pos, neg) && pdg_parent == -3122) { - registryMC.fill(HIST("AntiLambda_reconstructed_incl"), multiplicity, v0.pt()); - } - if (!isPhysPrim) - continue; - - // K0s - if (passedK0ShortSelection(v0, pos, neg) && pdg_parent == 310) { - registryMC.fill(HIST("K0s_reconstructed"), multiplicity, v0.pt()); - } - if (passedLambdaSelection(v0, pos, neg) && pdg_parent == 3122) { - registryMC.fill(HIST("Lambda_reconstructed"), multiplicity, v0.pt()); - } - if (passedAntiLambdaSelection(v0, pos, neg) && pdg_parent == -3122) { - registryMC.fill(HIST("AntiLambda_reconstructed"), multiplicity, v0.pt()); - } - } - - // Cascades - for (auto& casc : casc_per_coll) { - 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 pdg_parent(0); - for (auto& particleMotherOfNeg : negParticle.mothers_as()) { - for (auto& particleMotherOfPos : posParticle.mothers_as()) { - for (auto& particleMotherOfBach : bachParticle.mothers_as()) { - if (particleMotherOfNeg != particleMotherOfPos) - continue; - if (abs(particleMotherOfNeg.pdgCode()) != 3122) - continue; - if (!particleMotherOfBach.isPhysicalPrimary()) - continue; - pdg_parent = particleMotherOfBach.pdgCode(); - } - } - } - if (pdg_parent == 0) - continue; - - // Xi+ - if (passedXiSelection(casc, pos, neg, bach, collision) && pdg_parent == -3312) { - registryMC.fill(HIST("XiPos_reconstructed"), multiplicity, casc.pt()); - } - // Xi- - if (passedXiSelection(casc, pos, neg, bach, collision) && pdg_parent == 3312) { - registryMC.fill(HIST("XiNeg_reconstructed"), multiplicity, casc.pt()); - } - // Omega+ - if (passedOmegaSelection(casc, pos, neg, bach, collision) && pdg_parent == -3334) { - registryMC.fill(HIST("OmegaPos_reconstructed"), multiplicity, casc.pt()); - } - // Omega- - if (passedOmegaSelection(casc, pos, neg, bach, collision) && pdg_parent == 3334) { - registryMC.fill(HIST("OmegaNeg_reconstructed"), multiplicity, casc.pt()); - } - } - - // Reconstructed Tracks - for (auto track : tracks_per_coll) { - - // Get MC Particle - if (!track.has_mcParticle()) - continue; - // Track Selection - if (!passedTrackSelectionForPions(track)) - continue; - - const auto particle = track.mcParticle(); - if (abs(particle.pdgCode()) != 211) - continue; - - if (particle.isPhysicalPrimary()) { - if (track.sign() > 0) - registryMC.fill(HIST("piplus_dcaxy_prim"), multiplicity, track.pt(), track.dcaXY()); - if (track.sign() < 0) - registryMC.fill(HIST("piminus_dcaxy_prim"), multiplicity, track.pt(), track.dcaXY()); - } - - if (!particle.isPhysicalPrimary()) { - if (track.sign() > 0) - registryMC.fill(HIST("piplus_dcaxy_sec"), multiplicity, track.pt(), track.dcaXY()); - if (track.sign() < 0) - registryMC.fill(HIST("piminus_dcaxy_sec"), multiplicity, track.pt(), track.dcaXY()); - } - - if (TMath::Abs(track.dcaXY()) > dcaxyMax) - continue; - - if (track.tpcNSigmaPi() < nsigmaTPCmin || track.tpcNSigmaPi() > nsigmaTPCmax) - continue; - - if (!particle.isPhysicalPrimary()) - continue; - - if (track.sign() > 0) - registryMC.fill(HIST("pi_plus_rec_tpc"), multiplicity, track.pt()); - if (track.sign() < 0) - registryMC.fill(HIST("pi_minus_rec_tpc"), multiplicity, track.pt()); - - if (!track.hasTOF()) - continue; - if (track.tofNSigmaPi() < nsigmaTOFmin || track.tofNSigmaPi() > nsigmaTOFmax) - continue; - - if (track.sign() > 0) - registryMC.fill(HIST("pi_plus_rec_tof"), multiplicity, track.pt()); - if (track.sign() < 0) - registryMC.fill(HIST("pi_minus_rec_tof"), multiplicity, track.pt()); - } - - for (auto& mcParticle : mcParticles_per_coll) { - - if (mcParticle.y() < yMin || mcParticle.y() > yMax) - continue; - if (!mcParticle.isPhysicalPrimary()) - continue; - - // Pi+ - if (mcParticle.pdgCode() == 211) { - registryMC.fill(HIST("pi_plus_gen"), multiplicity, mcParticle.pt()); - } - // Pi- - if (mcParticle.pdgCode() == -211) { - registryMC.fill(HIST("pi_minus_gen"), multiplicity, mcParticle.pt()); - } - // K0s - if (mcParticle.pdgCode() == 310) { - registryMC.fill(HIST("K0s_generated"), multiplicity, mcParticle.pt()); - registryMC.fill(HIST("K0s_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); - } - // Lambda - if (mcParticle.pdgCode() == 3122) { - registryMC.fill(HIST("Lambda_generated"), multiplicity, mcParticle.pt()); - registryMC.fill(HIST("Lambda_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); - } - // AntiLambda - if (mcParticle.pdgCode() == -3122) { - registryMC.fill(HIST("AntiLambda_generated"), multiplicity, mcParticle.pt()); - registryMC.fill(HIST("Lambda_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); - } - // Xi Pos - if (mcParticle.pdgCode() == -3312) { - registryMC.fill(HIST("XiPos_generated"), multiplicity, mcParticle.pt()); - registryMC.fill(HIST("Xi_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); - } - // Xi Neg - if (mcParticle.pdgCode() == 3312) { - registryMC.fill(HIST("XiNeg_generated"), multiplicity, mcParticle.pt()); - registryMC.fill(HIST("Xi_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); - } - // Omega Pos - if (mcParticle.pdgCode() == -3334) { - registryMC.fill(HIST("OmegaPos_generated"), multiplicity, mcParticle.pt()); - registryMC.fill(HIST("Omega_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); - } - // Omega Neg - if (mcParticle.pdgCode() == 3334) { - registryMC.fill(HIST("OmegaNeg_generated"), multiplicity, mcParticle.pt()); - registryMC.fill(HIST("Omega_eta_pt_pythia"), mcParticle.pt(), mcParticle.eta()); - } - } - } - } - PROCESS_SWITCH(strangeness_in_jets, processMCefficiency, "Process MC Efficiency", false); - - void processWeights(SimCollisions const& collisions, aod::McParticles const& mcParticles) - { - // Loop over MC Collisions - for (const auto& collision : collisions) { - - // Selection on z_{vertex} - if (abs(collision.posZ()) > 10) - continue; - - // MC Particles per Collision - auto mcParticles_per_coll = mcParticles.sliceBy(perMCCollision, collision.globalIndex()); - - std::vector particle_ID; - int leading_ID = 0; - float pt_max(0); - int i = -1; - - for (auto& particle : mcParticles_per_coll) { - - // Global Index - // int i = particle.globalIndex(); - i++; - - // Select Primary Particles - float deltaX = particle.vx() - collision.posX(); - float deltaY = particle.vy() - collision.posY(); - float deltaZ = particle.vz() - collision.posZ(); - float deltaR = sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ); - if (deltaR > 0.1) - continue; - - // Pseudorapidity Selection - if (abs(particle.eta()) > 0.8) - continue; - - if (particle.pt() < 0.15) - continue; - - // PDG Selection - int pdg = abs(particle.pdgCode()); - if ((pdg != 11) && (pdg != 211) && (pdg != 321) && (pdg != 2212)) - continue; - - // 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()); - registryQC.fill(HIST("deltaPt_leading"), pt_max - leading_track.pt()); - - // Labels - int exit(0); - int 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 / (Rjet * Rjet); - 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); - - // Jet Axis - TVector3 jet_axis(p_leading.X(), p_leading.Y(), p_leading.Z()); - - if ((abs(jet_axis.Eta()) + Rmax) > etaMax) - return; - - // Perpendicular Cones for UE - TVector3 ue_axis1(0.0, 0.0, 0.0); - TVector3 ue_axis2(0.0, 0.0, 0.0); - get_perpendicular_axis(jet_axis, ue_axis1, +1.0); - get_perpendicular_axis(jet_axis, 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; - - // Generated Particles - for (auto& particle : mcParticles_per_coll) { - - // PDG Selection - int pdg = particle.pdgCode(); - - if (!particle.isPhysicalPrimary()) - continue; - if (particle.y() < yMin || particle.y() > yMax) - continue; - - TVector3 p_particle(particle.px(), particle.py(), particle.pz()); - float deltaEta_jet = p_particle.Eta() - jet_axis.Eta(); - float deltaPhi_jet = GetDeltaPhi(p_particle.Phi(), jet_axis.Phi()); - float deltaR_jet = sqrt(deltaEta_jet * deltaEta_jet + deltaPhi_jet * deltaPhi_jet); - float deltaEta_ue1 = p_particle.Eta() - ue_axis1.Eta(); - float deltaPhi_ue1 = GetDeltaPhi(p_particle.Phi(), ue_axis1.Phi()); - float deltaR_ue1 = sqrt(deltaEta_ue1 * deltaEta_ue1 + deltaPhi_ue1 * deltaPhi_ue1); - float deltaEta_ue2 = p_particle.Eta() - ue_axis2.Eta(); - float deltaPhi_ue2 = GetDeltaPhi(p_particle.Phi(), ue_axis2.Phi()); - float deltaR_ue2 = sqrt(deltaEta_ue2 * deltaEta_ue2 + deltaPhi_ue2 * deltaPhi_ue2); - - // Fill K0s - if (abs(pdg) == 310) { - if (deltaR_jet < Rmax) - registryMC.fill(HIST("K0s_eta_pt_jet"), particle.pt(), particle.eta()); - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) - registryMC.fill(HIST("K0s_eta_pt_ue"), particle.pt(), particle.eta()); - } - - // Fill Lambda - if (abs(pdg) == 3122) { - if (deltaR_jet < Rmax) - registryMC.fill(HIST("Lambda_eta_pt_jet"), particle.pt(), particle.eta()); - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) - registryMC.fill(HIST("Lambda_eta_pt_ue"), particle.pt(), particle.eta()); - } - - // Fill Xi - if (abs(pdg) == 3312) { - if (deltaR_jet < Rmax) - registryMC.fill(HIST("Xi_eta_pt_jet"), particle.pt(), particle.eta()); - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) - registryMC.fill(HIST("Xi_eta_pt_ue"), particle.pt(), particle.eta()); - } - - // Fill Omega - if (abs(pdg) == 3334) { - if (deltaR_jet < Rmax) - registryMC.fill(HIST("Omega_eta_pt_jet"), particle.pt(), particle.eta()); - if (deltaR_ue1 < Rmax || deltaR_ue2 < Rmax) - registryMC.fill(HIST("Omega_eta_pt_ue"), particle.pt(), particle.eta()); - } - } - } - } - PROCESS_SWITCH(strangeness_in_jets, processWeights, "Process Weights", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/Tasks/Strangeness/strangenessderivedbinnedinfo.cxx b/PWGLF/Tasks/Strangeness/strangenessderivedbinnedinfo.cxx new file mode 100644 index 00000000000..2dc24f9d944 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/strangenessderivedbinnedinfo.cxx @@ -0,0 +1,843 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file strangenessderivedbinnedinfo.cxx +/// \brief analysis task producing V0/cascade info in binned format +/// +/// \author Romain Schotter , Austrian Academy of Sciences & SMI +// +// ================ +// +// This code loops over V0Cores and CascCores tables 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 +// + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// 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 namespace o2::aod::rctsel; + +using DauTracks = soa::Join; +using V0Candidates = soa::Join; +using CascadeCandidates = soa::Join; + +struct strangenessderivedbinnedinfo { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // master analysis switches + Configurable analyseK0Short{"analyseK0Short", true, "process K0Short-like candidates"}; + Configurable analyseLambda{"analyseLambda", false, "process Lambda-like candidates"}; + Configurable analyseAntiLambda{"analyseAntiLambda", false, "process AntiLambda-like candidates"}; + Configurable analyseXi{"analyseXi", false, "process Xi-like candidates"}; + Configurable analyseOmega{"analyseOmega", false, "process Omega-like candidates"}; + Configurable isPP{"isPP", true, "If running on pp collision, switch it on true"}; + + // for running over skimmed dataset + Configurable doPPAnalysis{"doPPAnalysis", false, "if in pp, set to true"}; + 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"}; + 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 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"}; + } eventSelections; + + static constexpr float defaultSqrtScalingParameters[1][4] = {{0.1, 0.1, 0, 128}}; + + // preselection options + struct : ConfigurableGroup { + std::string prefix = "encodingOpts"; + Configurable useSqrtEncodingForOccupancy{"useSqrtEncodingForOccupancy", false, "Store sqrt(occupancy) instead of occupancy"}; + Configurable useSqrtEncodingForRadius{"useSqrtEncodingForRadius", false, "Store sqrt(radius) instead of radius"}; + Configurable useSqrtScalingForEncodingPt{"useSqrtScalingForEncodingPt", false, "Store sqrt scaling(pT) instead of pT"}; + Configurable> sqrtScalingParameters{"sqrtScalingParameters", {defaultSqrtScalingParameters[0], 4, {"sigma0", "sigma1", "clampMin", "clampMax"}}, "Sqrt scaling parameters"}; + } encodingOpts; + + 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 requireTPConly{"v0Selections.requireTPConly", false, "require 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) + Configurable tpcPidNsigmaCut{"v0Selections.tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + } 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) + Configurable tpcPidNsigmaCut{"cascSelections.tpcPidNsigmaCut", 5, "tpcPidNsigmaCut"}; + } cascSelections; + + 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}; + + // 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; + ctpRateFetcher rateFetcher; + 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 axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f}, "Centrality"}; + ConfigurableAxis axisOccupancy{"axisOccupancy", {VARIABLE_WIDTH, 0.0f, 1000.0f, 3000.0f, 10000.0f, 30000.0f}, "Occupancy"}; + + // topological variable QA axes + ConfigurableAxis axisMass{"axisV0Mass", {25, -0.05f, 0.05f}, "Invariant mass (GeV/#it{c}^{2})"}; + ConfigurableAxis axisPhi{"axisPhi", {36, 0.0f, constants::math::TwoPI}, "#varphi (rad)"}; + ConfigurableAxis axisEta{"axisEta", {10, -1.0f, 1.0f}, "Pseudo-rapidity #eta"}; + ConfigurableAxis axisRadius{"axisRadius", {10, 0.0f, 250.0f}, "Decay radius (cm)"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 4.0f, 5.0f, 7.0f, 9.0f, 11.0f, 15.0f, 30.0f}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisAlphaV0{"axisAlphaV0", {1, -1.0f, 1.f}, "V0 #alpha Armenteros"}; + ConfigurableAxis axisPtArmV0{"axisPtArmV0", {1, 0.0f, 10.f}, "V0 #it{p}_{T} Armenteros"}; + + // PDG database + Service pdgDB; + + // Sqrt scaling function + // Author: Marian Ivanov + int codeSqrtScaling(float val, float sigma0, float sigma1, int clampMin, int clampMax) + { + float code_f = std::asinh((sigma1 * val) / sigma0) / sigma0; + return std::clamp(static_cast(std::round(code_f)), clampMin, clampMax); + } + + // Function to decode the sqrt scaling + // Author: Marian Ivanov + float decodeSqrtScaling(int code, float sigma0, float sigma1) + { + float code_f = static_cast(code); + return (sigma0 / sigma1) * std::sinh(sigma0 * code_f); + } + + void init(InitContext const&) + { + if (analyseK0Short + analyseLambda + analyseAntiLambda + analyseXi + analyseOmega > 1) { + LOGF(fatal, "Cannot enable several particles at the same time. Please choose one."); + } + + // Initialise the RCTFlagsChecker + rctFlagsChecker.init(rctConfigurations.cfgRCTLabel.value, rctConfigurations.cfgCheckZDC, rctConfigurations.cfgTreatLimitedAcceptanceAsBad); + + // Event Counters + histos.add("hEventSelection", "hEventSelection", kTH1D, {{21, -0.5f, +20.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.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"); + + histos.add("hEventCentrality", "hEventCentrality", kTH1F, {{100, 0.0f, +100.0f}}); + histos.add("hEventOccupancy", "hEventOccupancy", kTH1F, {axisOccupancy}); + + histos.add("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc", "h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc", kTHnSparseF, {axisMass, axisPt, axisPhi, axisEta, axisPtArmV0, axisAlphaV0, axisRadius, axisCentrality, axisOccupancy}); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(0)->SetName("Mass"); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(1)->SetName("Pt"); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(2)->SetName("Phi"); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(3)->SetName("Eta"); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(4)->SetName("V0PtArm"); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(5)->SetName("V0Alpha"); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(6)->SetName("Radius"); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(7)->SetName("Centrality"); + histos.get(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"))->GetAxis(8)->SetName("Occupancy"); + + 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()); + } + } + + 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 */); + } + + // 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 */); + + return true; + } + + template + void fillEventHistograms(TCollision collision, float& centrality, float& occupancy) + { + if (isPP) { // + centrality = collision.centFT0M(); + } else { + centrality = collision.centFT0C(); + occupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (encodingOpts.useSqrtEncodingForOccupancy) + occupancy = std::sqrt(occupancy); + } + histos.fill(HIST("hEventCentrality"), centrality); + histos.fill(HIST("hEventOccupancy"), occupancy); + + return; + } + + template + bool isV0Selected(TV0 v0, TCollision collision, float rapidity) + // precalculate this information so that a check is one mask operation, not many + { + // + // Base topological variables + // + + // v0 radius min/max selections + if (v0.v0radius() < v0Selections.v0radius) + return false; + if (v0.v0radius() > v0Selections.v0radiusMax) + return false; + // DCA proton and pion to PV for Lambda and AntiLambda decay hypotheses + if (analyseK0Short) { + if (std::fabs(v0.dcapostopv()) < v0Selections.dcapiontopv) + return false; + if (std::fabs(v0.dcanegtopv()) < v0Selections.dcapiontopv) + return false; + } + if (analyseLambda) { + if (std::fabs(v0.dcapostopv()) < v0Selections.dcaprotontopv) + return false; + if (std::fabs(v0.dcanegtopv()) < v0Selections.dcapiontopv) + return false; + } + if (analyseAntiLambda) { + if (std::fabs(v0.dcapostopv()) < v0Selections.dcapiontopv) + return false; + if (std::fabs(v0.dcanegtopv()) < v0Selections.dcaprotontopv) + return false; + } + // V0 cosine of pointing angle + if (v0.v0cosPA() < v0Selections.v0cospa) + return false; + // DCA between v0 daughters + if (v0.dcaV0daughters() > v0Selections.dcav0dau) + return false; + // DCA V0 to prim vtx + if (v0.dcav0topv() < v0Selections.dcav0topv) + return false; + + // + // rapidity + // + if (std::fabs(rapidity) > v0Selections.rapidityCut) + return false; + + // + // competing mass rejection + // + if ((analyseLambda || analyseAntiLambda) && std::fabs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0Selections.compMassRejection) + return false; + if (analyseK0Short && std::fabs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0Selections.compMassRejection) + return false; + + auto posTrackExtra = v0.template posTrackExtra_as(); + auto negTrackExtra = v0.template negTrackExtra_as(); + + // + // ITS quality flags + // + if (posTrackExtra.itsNCls() < v0Selections.minITSclusters) + return false; + if (negTrackExtra.itsNCls() < v0Selections.minITSclusters) + return false; + + // + // TPC quality flags + // + if (posTrackExtra.tpcCrossedRows() < v0Selections.minTPCrows) + return false; + if (negTrackExtra.tpcCrossedRows() < v0Selections.minTPCrows) + return false; + + // + // TPC PID + // + if (analyseK0Short) { + if (std::fabs(posTrackExtra.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) + return false; + if (std::fabs(negTrackExtra.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) + return false; + } + if (analyseLambda) { + if (std::fabs(posTrackExtra.tpcNSigmaPr()) > v0Selections.tpcPidNsigmaCut) + return false; + if (std::fabs(negTrackExtra.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) + return false; + } + if (analyseAntiLambda) { + if (std::fabs(posTrackExtra.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) + return false; + if (std::fabs(negTrackExtra.tpcNSigmaPr()) > v0Selections.tpcPidNsigmaCut) + return false; + } + + // + // ITS only tag + if (v0Selections.requirePosITSonly && posTrackExtra.tpcCrossedRows() > 0) + return false; + if (v0Selections.requireNegITSonly && negTrackExtra.tpcCrossedRows() > 0) + return false; + + // + // TPC only tag + if (v0Selections.requireTPConly && posTrackExtra.detectorMap() != o2::aod::track::TPC) + return false; + if (v0Selections.requireTPConly && negTrackExtra.detectorMap() != o2::aod::track::TPC) + return false; + + // + // proper lifetime + if ((analyseLambda || analyseAntiLambda) && + v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 > lifetimecut->get("lifetimecutLambda")) + return false; + if (analyseK0Short && + v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short > lifetimecut->get("lifetimecutK0S")) + return false; + + // + // armenteros + if (v0Selections.armPodCut > 1e-4 && v0.qtarm() * v0Selections.armPodCut < std::fabs(v0.alpha())) + return false; + + return true; + } + + template + bool isCascadeSelected(TCascade casc, TCollision collision, float rapidity) + // 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; + + // + // competing mass rejection + // + if (analyseXi && std::fabs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < cascSelections.compMassRejection) + return false; + if (analyseOmega && 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 (analyseXi && std::fabs(bachTrackExtra.tpcNSigmaPi()) > cascSelections.tpcPidNsigmaCut) + return false; + if (analyseOmega && 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; + } + + // + // 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 (analyseXi && distOverTotMom * o2::constants::physics::MassXiMinus / ctauXiPDG > cascSelections.cascProperLifeTime) + return false; + if (analyseOmega && distOverTotMom * o2::constants::physics::MassOmegaMinus / ctauOmegaPDG > cascSelections.cascProperLifeTime) + return false; + + return true; + } + + // ______________________________________________________ + // Real data processing - no MC subscription + void process(soa::Join::iterator const& collision, V0Candidates const& fullV0s, CascadeCandidates const& fullCascades, DauTracks const&) + { + // Fire up CCDB + if (cfgSkimmedProcessing) { + initCCDB(collision); + } + + if (!isEventAccepted(collision, true)) { + return; + } + + if (cfgSkimmedProcessing) { + zorro.isSelected(collision.globalBC()); /// Just let Zorro do the accounting + } + + float centrality = -1; + float occupancy = -1; + fillEventHistograms(collision, centrality, occupancy); + + // __________________________________________ + // perform main analysis + // + if (analyseK0Short || analyseLambda || analyseAntiLambda) { // Look at V0s + 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 + + float pT = encodingOpts.useSqrtScalingForEncodingPt ? codeSqrtScaling(v0.pt(), encodingOpts.sqrtScalingParameters->get("sigma0"), encodingOpts.sqrtScalingParameters->get("sigma1"), encodingOpts.sqrtScalingParameters->get("clampMin"), encodingOpts.sqrtScalingParameters->get("clampMax")) : v0.pt(); + float decayRadius = encodingOpts.useSqrtEncodingForRadius ? std::sqrt(v0.v0radius()) : v0.v0radius(); + + if (analyseK0Short && isV0Selected(v0, collision, v0.yK0Short())) { + histos.fill(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"), v0.mK0Short() - o2::constants::physics::MassK0Short, pT, v0.phi(), v0.eta(), v0.qtarm(), v0.alpha(), decayRadius, centrality, occupancy); + } + if (analyseLambda && isV0Selected(v0, collision, v0.yLambda())) { + histos.fill(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"), v0.mLambda() - o2::constants::physics::MassLambda0, pT, v0.phi(), v0.eta(), v0.qtarm(), v0.alpha(), decayRadius, centrality, occupancy); + } + if (analyseAntiLambda && isV0Selected(v0, collision, v0.yLambda())) { + histos.fill(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"), v0.mAntiLambda() - o2::constants::physics::MassLambda0, pT, v0.phi(), v0.eta(), v0.qtarm(), v0.alpha(), decayRadius, centrality, occupancy); + } + } // end v0 loop + } + + if (analyseXi || analyseOmega) { // Look at Cascades + 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 + + float pT = encodingOpts.useSqrtScalingForEncodingPt ? codeSqrtScaling(cascade.pt(), encodingOpts.sqrtScalingParameters->get("sigma0"), encodingOpts.sqrtScalingParameters->get("sigma1"), encodingOpts.sqrtScalingParameters->get("clampMin"), encodingOpts.sqrtScalingParameters->get("clampMax")) : cascade.pt(); + float decayRadius = encodingOpts.useSqrtEncodingForRadius ? std::sqrt(cascade.cascradius()) : cascade.cascradius(); + + if (analyseXi && isCascadeSelected(cascade, collision, cascade.yXi())) { + histos.fill(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"), cascade.m(1) - o2::constants::physics::MassXiMinus, pT, cascade.phi(), cascade.eta(), 0., 0., decayRadius, centrality, occupancy); + } + if (analyseOmega && isCascadeSelected(cascade, collision, cascade.yOmega())) { + histos.fill(HIST("h9dMassPtPhiEtaPtArmV0AlphaV0RadiusCentOcc"), cascade.m(2) - o2::constants::physics::MassOmegaMinus, pT, cascade.phi(), cascade.eta(), 0., 0., decayRadius, centrality, occupancy); + } + } // end cascade loop + } + } +}; + +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..e1e87e5b532 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/taskLambdaSpinCorr.cxx @@ -0,0 +1,1358 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 +/// \author sourav.kundu@cern.ch + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector2D.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" + +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using namespace o2::aod::rctsel; + +using dauTracks = soa::Join; +using v0Candidates = soa::Join; + +struct LfTaskLambdaSpinCorr { + + Service ccdb; + + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + 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", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + // mixing + Configurable cosCalculation{"cosCalculation", 0, "cos calculation"}; + Configurable mixingCombination{"mixingCombination", 0, "mixing Combination"}; + Configurable cfgCutOccupancy{"cfgCutOccupancy", 2000, "Occupancy cut"}; + ConfigurableAxis axisVertex{"axisVertex", {5, -10, 10}, "vertex axis for bin"}; + ConfigurableAxis axisMultiplicityClass{"axisMultiplicityClass", {8, 0, 80}, "multiplicity percentile for bin"}; + Configurable nMix{"nMix", 5, "number of event mixing"}; + Configurable ptMix{"ptMix", 1.0, "pt cut on mixing"}; + Configurable etaMix{"etaMix", 0.4, "eta cut on mixing"}; + Configurable phiMix{"phiMix", 0.2, "phi cut on mixing"}; + // fill output + Configurable additionalEvSel{"additionalEvSel", false, "additionalEvSel"}; + Configurable additionalEvSel3{"additionalEvSel3", false, "additionalEvSel3"}; + Configurable additionalEvSel4{"additionalEvSel4", false, "additionalEvSel4"}; + Configurable additionalEvSel5{"additionalEvSel5", false, "additionalEvSel5"}; + Configurable fillGEN{"fillGEN", false, "filling generated histograms"}; + Configurable fillQA{"fillQA", false, "filling QA 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"}; + + // Configs for track + Configurable cfgCutPt{"cfgCutPt", 0.2, "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 confV0PtMax{"confV0PtMax", 0.f, "Maximum 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"}; + Configurable iMNbinspair{"iMNbinspair", 400, "Number of bins in invariant mass pair"}; + Configurable lbinIMpair{"lbinIMpair", 0.0, "lower bin value in IMpair histograms"}; + Configurable hbinIMpair{"hbinIMpair", 8.0, "higher bin value in IMpair 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"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + RCTFlagsChecker rctChecker; + void init(o2::framework::InitContext&) + { + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + AxisSpec thnAxisInvMass{iMNbins, lbinIM, hbinIM, "#it{M} (GeV/#it{c}^{2})"}; + AxisSpec thnAxisInvMasspair{iMNbinspair, lbinIMpair, hbinIMpair, "#it{M} (GeV/#it{c}^{2})"}; + histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{10, 0, 10.0}}); + histos.add("hPtDiff", "hPtDiff", kTH1F, {{1000, 0, 100.0}}); + histos.add("hPhiDiff", "hPhiDiff", kTH1F, {{800, -8.0, 8.0}}); + histos.add("hRDiff", "hRDiff", kTH1F, {{640, -16.0, 16.0}}); + histos.add("hv0Mult", "hv0Mult", kTH1F, {{10001, -0.5, 10000.5}}); + histos.add("hCentrality", "Centrality distribution", kTH1F, {{configcentAxis}}); + histos.add("hSparseLambdaLambda", "hSparseLambdaLambda", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseLambdaAntiLambda", "hSparseLambdaAntiLambda", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseAntiLambdaAntiLambda", "hSparseAntiLambdaAntiLambda", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + + histos.add("hSparseLambdaLambdaMixed", "hSparseLambdaLambdaMixed", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseLambdaAntiLambdaMixed", "hSparseLambdaAntiLambdaMixed", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseAntiLambdaAntiLambdaMixed", "hSparseAntiLambdaAntiLambdaMixed", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + + if (fillQA) { + ///////// along quantization axes/////////// + histos.add("hSparseLambdaLambdaQA", "hSparseLambdaLambdaQA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseLambdaAntiLambdaQA", "hSparseLambdaAntiLambdaQA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseAntiLambdaAntiLambdaQA", "hSparseAntiLambdaAntiLambdaQA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + } + if (fillGEN) { + histos.add("hSparseLambdaLambdaMC", "hSparseLambdaLambdaMC", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseLambdaAntiLambdaMC", "hSparseLambdaAntiLambdaMC", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseAntiLambdaAntiLambdaMC", "hSparseAntiLambdaAntiLambdaMC", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + if (fillQA) { + histos.add("hSparseLambdaLambdaMCQA", "hSparseLambdaLambdaMCQA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseLambdaAntiLambdaMCQA", "hSparseLambdaAntiLambdaMCQA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, true); + histos.add("hSparseAntiLambdaAntiLambdaMCQA", "hSparseAntiLambdaAntiLambdaMCQA", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisInvMass, configthnAxisPol, configcentAxis, thnAxisInvMasspair}, 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 (pT > confV0PtMax) { + 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.09; + const double maxMass = 1.14; + 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& particle1, const ROOT::Math::PxPyPzMVector& particle2, + const ROOT::Math::PxPyPzMVector& daughpart1, const ROOT::Math::PxPyPzMVector& daughpart2, + double centrality, int datatype) + { + + // auto particle1Dummy = ROOT::Math::PxPyPzMVector(particle1.Px(), particle1.Py(), particle1.Pz(), 1.115683); + // auto particle2Dummy = ROOT::Math::PxPyPzMVector(particle2.Px(), particle2.Py(), particle2.Pz(), 1.115683); + auto particle1Dummy = ROOT::Math::PxPyPzMVector(particle1.Px(), particle1.Py(), particle1.Pz(), particle1.M()); + auto particle2Dummy = ROOT::Math::PxPyPzMVector(particle2.Px(), particle2.Py(), particle2.Pz(), particle2.M()); + auto pairDummy = particle1Dummy + particle2Dummy; + + // auto pairParticle = particle1 + particle2; + + ROOT::Math::Boost boostPairToCM{pairDummy.BoostToCM()}; // boosting vector for pair CM + // Boosting both Lambdas to Lambda-Lambda pair rest frame + auto lambda1CM = boostPairToCM(particle1Dummy); + auto lambda2CM = boostPairToCM(particle2Dummy); + + // 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); + + auto cosThetaDiff = -999.0; + if (cosCalculation == 0) { + cosThetaDiff = proton1LambdaRF.Vect().Unit().Dot(proton2LambdaRF.Vect().Unit()); + } + + if (cosCalculation == 1) { + ROOT::Math::XYZVector quantizationAxis = lambda1CM.Vect().Unit(); + double cosTheta1 = proton1LambdaRF.Vect().Unit().Dot(quantizationAxis); + double cosTheta2 = proton2LambdaRF.Vect().Unit().Dot(quantizationAxis); + cosThetaDiff = cosTheta1 * cosTheta2; + } + double deltaPhi = RecoDecay::constrainAngle(particle1.Phi() - particle2.Phi(), 0.0); + double deltaR = TMath::Sqrt(TMath::Power(particle1.Eta() - particle2.Eta(), 2.0) + TMath::Power(deltaPhi, 2.0)); + if (datatype == 0) { + if (tag1 && tag3) { + histos.fill(HIST("hSparseLambdaLambda"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag2 && tag4) { + histos.fill(HIST("hSparseAntiLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag1 && tag4) { + histos.fill(HIST("hSparseLambdaAntiLambda"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag2 && tag3) { + histos.fill(HIST("hSparseLambdaAntiLambda"), particle2.M(), particle1.M(), cosThetaDiff, centrality, deltaR); + } + } + + if (datatype == 1) { + if (tag1 && tag3) { + histos.fill(HIST("hSparseLambdaLambdaMC"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag2 && tag4) { + histos.fill(HIST("hSparseAntiLambdaAntiLambdaMC"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag1 && tag4) { + histos.fill(HIST("hSparseLambdaAntiLambdaMC"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag2 && tag3) { + histos.fill(HIST("hSparseLambdaAntiLambdaMC"), particle2.M(), particle1.M(), cosThetaDiff, centrality, deltaR); + } + } + + if (datatype == 2) { + if (tag1 && tag3) { + histos.fill(HIST("hSparseLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag2 && tag4) { + histos.fill(HIST("hSparseAntiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag1 && tag4) { + histos.fill(HIST("hSparseLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, centrality, deltaR); + } + if (tag2 && tag3) { + histos.fill(HIST("hSparseLambdaAntiLambdaMixed"), particle2.M(), particle1.M(), cosThetaDiff, centrality, deltaR); + } + } + } + + 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 + } + + return {lambdaTag, aLambdaTag, true}; // Valid candidate + } + + std::tuple getLambdaTagsDD(const auto& v0, const auto& collision) + { + auto postrack = v0.template posTrackExtra_as(); + auto negtrack = v0.template negTrackExtra_as(); + + int lambdaTag = 0; + int aLambdaTag = 0; + + 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 + } + + return {lambdaTag, aLambdaTag, true}; // Valid candidate + } + + std::tuple getLambdaTagsMC(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 lambda0, antiLambda0, proton0, pion0, antiProton0, antiPion0; + ROOT::Math::PxPyPzMVector lambda, antiLambda, proton, pion, antiProton, antiPion; + ROOT::Math::PxPyPzMVector lambda2, antiLambda2, proton2, pion2, antiProton2, antiPion2; + ROOT::Math::PxPyPzMVector lambdamc, antiLambdamc, protonmc, pionmc, antiProtonmc, antiPionmc; + ROOT::Math::PxPyPzMVector lambda2mc, antiLambda2mc, proton2mc, pion2mc, antiProton2mc, antiPion2mc; + + 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 EventCandidates = soa::Filtered>; + using AllTrackCandidates = soa::Join; + using ResoV0s = aod::V0Datas; + + void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& /*tracks*/, ResoV0s const& V0s) + { + histos.fill(HIST("hEvtSelInfo"), 0.5); + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 1.5); + if (!collision.sel8()) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 2.5); + auto centrality = collision.centFT0C(); + int occupancy = collision.trackOccupancyInTimeRange(); + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 3.5); + if (additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 4.5); + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 5.5); + if (additionalEvSel5 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 6.5); + if (occupancy > cfgCutOccupancy) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 7.5); + histos.fill(HIST("hCentrality"), centrality); + for (const auto& v0 : V0s) { + auto [lambdaTag, aLambdaTag, isValid] = getLambdaTags(v0, collision); + if (!isValid) { + continue; + } + if (lambdaTag && aLambdaTag) { + 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); + lambda = 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); + antiLambda = antiProton + pion; + } + if (lambdaTag && (lambda.M() < lbinIM || lambda.M() > hbinIM)) { + continue; + } + if (aLambdaTag && (antiLambda.M() < lbinIM || antiLambda.M() > hbinIM)) { + continue; + } + auto postrack1 = v0.template posTrack_as(); + auto negtrack1 = v0.template negTrack_as(); + + // 2nd loop for combination of lambda lambda + for (const auto& v02 : V0s) { + if (v02.index() <= v0.index()) { + continue; + } + auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTags(v02, collision); + if (!isValid2) { + continue; + } + if (lambdaTag2 && aLambdaTag2) { + 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); + lambda2 = 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); + antiLambda2 = antiProton2 + pion2; + } + if (lambdaTag2 && (lambda2.M() < lbinIM || lambda2.M() > hbinIM)) { + continue; + } + if (aLambdaTag2 && (antiLambda2.M() < lbinIM || antiLambda2.M() > hbinIM)) { + continue; + } + auto postrack2 = v02.template posTrack_as(); + auto negtrack2 = v02.template negTrack_as(); + if (postrack1.globalIndex() == postrack2.globalIndex() || negtrack1.globalIndex() == negtrack2.globalIndex()) { + continue; + } + if (lambdaTag && lambdaTag2) { + fillHistograms(1, 0, 1, 0, lambda, lambda2, proton, proton2, centrality, 0); + } + if (aLambdaTag && aLambdaTag2) { + fillHistograms(0, 1, 0, 1, antiLambda, antiLambda2, antiProton, antiProton2, centrality, 0); + } + if (lambdaTag && aLambdaTag2) { + fillHistograms(1, 0, 0, 1, lambda, antiLambda2, proton, antiProton2, centrality, 0); + } + if (aLambdaTag && lambdaTag2) { + fillHistograms(0, 1, 1, 0, antiLambda, lambda2, antiProton, proton2, centrality, 0); + } + } + } + } + PROCESS_SWITCH(LfTaskLambdaSpinCorr, processData, "Process data", false); + + // Processing Event Mixing + SliceCache cache; + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{axisVertex, axisMultiplicityClass}, true}; + Preslice tracksPerCollisionV0 = aod::v0data::collisionId; + void processME(EventCandidates const& collisions, AllTrackCandidates const&, ResoV0s const& V0s) + { + for (auto& [collision1, collision2] : selfCombinations(colBinning, nMix, -1, collisions, collisions)) { + // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.index(), collision2.index()); + if (rctCut.requireRCTFlagChecker && !rctChecker(collision1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctChecker(collision2)) { + continue; + } + int occupancy1 = collision1.trackOccupancyInTimeRange(); + int occupancy2 = collision2.trackOccupancyInTimeRange(); + + if (collision1.index() == collision2.index()) { + continue; + } + if (!collision1.sel8() || !collision2.sel8()) { + continue; + } + if (additionalEvSel && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (occupancy1 > cfgCutOccupancy) { + continue; + } + if (additionalEvSel && (!collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (occupancy2 > cfgCutOccupancy) { + continue; + } + + if (additionalEvSel3 && (!collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (additionalEvSel4 && !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + if (additionalEvSel5 && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + + if (additionalEvSel3 && (!collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (additionalEvSel4 && !collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + if (additionalEvSel5 && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + + auto centrality = collision1.centFT0C(); + auto groupV01 = V0s.sliceBy(tracksPerCollisionV0, collision1.globalIndex()); + auto groupV02 = V0s.sliceBy(tracksPerCollisionV0, collision1.globalIndex()); + auto groupV03 = V0s.sliceBy(tracksPerCollisionV0, collision2.globalIndex()); + // for (auto& [t1, t2, t3] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV01, groupV02, groupV03))) { + // LOGF(info, "Mixed event collisions: (%d, %d, %d)", t1.collisionId(),t2.collisionId(),t3.collisionId()); + + // auto maxV0Size = 1400; + // if (groupV01.size() > maxV0Size || groupV02.size() > maxV0Size || groupV03.size() > maxV0Size) { + // continue; + // } + // bool pairStatus[1500][1500] = {{false}}; + + size_t rows = groupV03.size() + 20; + size_t cols = groupV01.size() + 20; + std::vector> pairStatus(rows, std::vector(cols, false)); + histos.fill(HIST("hv0Mult"), groupV01.size()); + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV01, groupV02))) { + bool pairfound = false; + if (t2.index() <= t1.index()) { + continue; + } + if (t1.collisionId() != t2.collisionId()) { + continue; + } + + auto [lambdaTag1, aLambdaTag1, isValid1] = getLambdaTags(t1, collision1); + auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTags(t2, collision1); + if (!isValid1) { + continue; + } + if (!isValid2) { + continue; + } + if (lambdaTag1 && aLambdaTag1) { + continue; + } + if (lambdaTag2 && aLambdaTag2) { + 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() || negtrack1.globalIndex() == negtrack2.globalIndex()) { + continue; + } + // auto samePairSumPt = t1.pt() + t2.pt(); + double deltaPhiSame = RecoDecay::constrainAngle(t1.phi() - t2.phi(), 0.0); + auto samePairR = TMath::Sqrt(TMath::Power(deltaPhiSame, 2.0) + TMath::Power(t1.eta() - t2.eta(), 2.0)); + + if (lambdaTag1) { + proton0 = ROOT::Math::PxPyPzMVector(t1.pxpos(), t1.pypos(), t1.pzpos(), o2::constants::physics::MassProton); + antiPion0 = ROOT::Math::PxPyPzMVector(t1.pxneg(), t1.pyneg(), t1.pzneg(), o2::constants::physics::MassPionCharged); + lambda0 = proton0 + antiPion0; + } + if (aLambdaTag1) { + antiProton0 = ROOT::Math::PxPyPzMVector(t1.pxneg(), t1.pyneg(), t1.pzneg(), o2::constants::physics::MassProton); + pion0 = ROOT::Math::PxPyPzMVector(t1.pxpos(), t1.pypos(), t1.pzpos(), o2::constants::physics::MassPionCharged); + antiLambda0 = antiProton0 + pion0; + } + if (lambdaTag1 && (lambda0.M() < lbinIM || lambda0.M() > hbinIM)) { + continue; + } + if (aLambdaTag1 && (antiLambda0.M() < lbinIM || antiLambda0.M() > hbinIM)) { + continue; + } + if (lambdaTag2) { + proton = ROOT::Math::PxPyPzMVector(t2.pxpos(), t2.pypos(), t2.pzpos(), o2::constants::physics::MassProton); + antiPion = ROOT::Math::PxPyPzMVector(t2.pxneg(), t2.pyneg(), t2.pzneg(), o2::constants::physics::MassPionCharged); + lambda = proton + antiPion; + } + if (aLambdaTag2) { + antiProton = ROOT::Math::PxPyPzMVector(t2.pxneg(), t2.pyneg(), t2.pzneg(), o2::constants::physics::MassProton); + pion = ROOT::Math::PxPyPzMVector(t2.pxpos(), t2.pypos(), t2.pzpos(), o2::constants::physics::MassPionCharged); + antiLambda = antiProton + pion; + } + if (lambdaTag2 && (lambda.M() < lbinIM || lambda.M() > hbinIM)) { + continue; + } + if (aLambdaTag2 && (antiLambda.M() < lbinIM || antiLambda.M() > hbinIM)) { + continue; + } + for (const auto& t3 : groupV03) { + // if (pairStatus[t3.index()][t2.index()]) { + // LOGF(info, "repeat match found v0 id: (%d, %d)", t3.index(), t2.index()); + // continue; + // } + if (pairStatus[t3.index()][t2.index()]) { + continue; + } + if (t1.collisionId() == t3.collisionId()) { + continue; + } + auto [lambdaTag3, aLambdaTag3, isValid3] = getLambdaTags(t3, collision2); + if (!isValid3) { + continue; + } + if (lambdaTag3 && aLambdaTag3) { + continue; + } + if (lambdaTag1 != lambdaTag3 || aLambdaTag1 != aLambdaTag3) { + continue; + } + + if (lambdaTag3) { + proton2 = ROOT::Math::PxPyPzMVector(t3.pxpos(), t3.pypos(), t3.pzpos(), o2::constants::physics::MassProton); + antiPion2 = ROOT::Math::PxPyPzMVector(t3.pxneg(), t3.pyneg(), t3.pzneg(), o2::constants::physics::MassPionCharged); + lambda2 = proton2 + antiPion2; + } + if (aLambdaTag3) { + antiProton2 = ROOT::Math::PxPyPzMVector(t3.pxneg(), t3.pyneg(), t3.pzneg(), o2::constants::physics::MassProton); + pion2 = ROOT::Math::PxPyPzMVector(t3.pxpos(), t3.pypos(), t3.pzpos(), o2::constants::physics::MassPionCharged); + antiLambda2 = antiProton2 + pion2; + } + if (lambdaTag3 && (lambda2.M() < lbinIM || lambda2.M() > hbinIM)) { + continue; + } + if (aLambdaTag3 && (antiLambda2.M() < lbinIM || antiLambda2.M() > hbinIM)) { + continue; + } + double deltaPhiMix = RecoDecay::constrainAngle(t3.phi() - t2.phi(), 0.0); + auto mixPairR = TMath::Sqrt(TMath::Power(deltaPhiMix, 2.0) + TMath::Power(t3.eta() - t2.eta(), 2.0)); + auto etaDiff = t1.eta() - t3.eta(); + auto phiDiff = RecoDecay::constrainAngle(t1.phi() - t3.phi(), 0.0); + + histos.fill(HIST("hPtDiff"), t1.pt() - t3.pt()); + histos.fill(HIST("hPhiDiff"), phiDiff); + histos.fill(HIST("hRDiff"), etaDiff); + + if (mixingCombination == 0 && std::abs(t1.pt() - t3.pt()) > ptMix) { + continue; + } + if (mixingCombination == 0 && t1.eta() * t3.eta() > 0 && std::abs(etaDiff) > etaMix) { + continue; + } + if (mixingCombination == 0 && phiDiff > phiMix) { + continue; + } + + if (mixingCombination == 1 && std::abs(t1.pt() - t3.pt()) > ptMix) { + continue; + } + if (mixingCombination == 1 && std::abs(mixPairR - samePairR) > etaMix) { + continue; + } + + if (lambdaTag2 && lambdaTag3) { + fillHistograms(1, 0, 1, 0, lambda, lambda2, proton, proton2, centrality, 2); + } else if (aLambdaTag2 && aLambdaTag3) { + fillHistograms(0, 1, 0, 1, antiLambda, antiLambda2, antiProton, antiProton2, centrality, 2); + } else if (lambdaTag2 && aLambdaTag3) { + fillHistograms(1, 0, 0, 1, lambda, antiLambda2, proton, antiProton2, centrality, 2); + } else if (aLambdaTag2 && lambdaTag3) { + fillHistograms(0, 1, 1, 0, antiLambda, lambda2, antiProton, proton2, centrality, 2); + } else { + continue; + } + pairfound = true; + pairStatus[t3.index()][t2.index()] = true; + // LOGF(info, "v0 id: (%d, %d)", t3.index(), t2.index()); + if (pairfound) { + // LOGF(info, "Pair found"); + break; + } + } + } + } + } + PROCESS_SWITCH(LfTaskLambdaSpinCorr, processME, "Process data ME", true); + + Filter v0der = (nabs(aod::v0data::dcapostopv) > cMinV0DCAPr && nabs(aod::v0data::dcanegtopv) > cMinV0DCAPi && nabs(aod::v0data::dcaV0daughters) < confV0DCADaughMax); + using v0Cand = soa::Filtered; + + // void processDerivedData(soa::Join::iterator const& collision, v0Candidates const& V0s, dauTracks const&) + void processDerivedData(soa::Join::iterator const& collision, v0Cand const& V0s, dauTracks const&) + { + histos.fill(HIST("hEvtSelInfo"), 0.5); + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 1.5); + if (!collision.sel8()) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 2.5); + auto centrality = collision.centFT0C(); + int occupancy = collision.trackOccupancyInTimeRange(); + if (additionalEvSel && (!collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 3.5); + if (additionalEvSel3 && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 4.5); + if (additionalEvSel4 && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 5.5); + if (additionalEvSel5 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 6.5); + if (occupancy > cfgCutOccupancy) { + return; + } + histos.fill(HIST("hEvtSelInfo"), 7.5); + histos.fill(HIST("hCentrality"), centrality); + + for (const auto& v0 : V0s) { + auto [lambdaTag, aLambdaTag, isValid] = getLambdaTagsDD(v0, collision); + if (!isValid) { + continue; + } + + if (lambdaTag && aLambdaTag) { + 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); + lambda = 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); + antiLambda = antiProton + pion; + } + + if (lambdaTag && (lambda.M() < lbinIM || lambda.M() > hbinIM)) { + continue; + } + if (aLambdaTag && (antiLambda.M() < lbinIM || antiLambda.M() > hbinIM)) { + continue; + } + + // auto postrack1 = v0.template posTrackExtra_as(); + // auto negtrack1 = v0.template negTrackExtra_as(); + + // 2nd loop for combination of lambda lambda + for (const auto& v02 : V0s) { + if (v02.index() <= v0.index()) { + continue; + } + auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTagsDD(v02, collision); + if (!isValid2) { + continue; + } + if (lambdaTag2 && aLambdaTag2) { + 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); + lambda2 = 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); + antiLambda2 = antiProton2 + pion2; + } + + if (lambdaTag2 && (lambda2.M() < lbinIM || lambda2.M() > hbinIM)) { + continue; + } + if (aLambdaTag2 && (antiLambda2.M() < lbinIM || antiLambda2.M() > hbinIM)) { + continue; + } + + // auto postrack2 = v02.template posTrackExtra_as(); + // auto negtrack2 = v02.template negTrackExtra_as(); + if (v0.posTrackExtraId() == v02.posTrackExtraId() || v0.negTrackExtraId() == v02.negTrackExtraId()) { + continue; + } + + if (lambdaTag && lambdaTag2) { + fillHistograms(1, 0, 1, 0, lambda, lambda2, proton, proton2, centrality, 0); + } + if (aLambdaTag && aLambdaTag2) { + fillHistograms(0, 1, 0, 1, antiLambda, antiLambda2, antiProton, antiProton2, centrality, 0); + } + if (lambdaTag && aLambdaTag2) { + fillHistograms(1, 0, 0, 1, lambda, antiLambda2, proton, antiProton2, centrality, 0); + } + if (aLambdaTag && lambdaTag2) { + fillHistograms(0, 1, 1, 0, antiLambda, lambda2, antiProton, proton2, centrality, 0); + } + } + } + } + PROCESS_SWITCH(LfTaskLambdaSpinCorr, processDerivedData, "Process derived data", true); + + // Preslice tracksPerCollisionV0Mixed = o2::aod::v0data::straCollisionId; // for derived data only + Preslice tracksPerCollisionV0Mixed = o2::aod::v0data::straCollisionId; // for derived data only + // void processDerivedDataMixed(soa::Join const& collisions, v0Candidates const& V0s, dauTracks const&) + void processDerivedDataMixed(soa::Join const& collisions, v0Cand const& V0s, dauTracks const&) + + { + + for (auto& [collision1, collision2] : selfCombinations(colBinning, nMix, -1, collisions, collisions)) { + // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.index(), collision2.index()); + if (rctCut.requireRCTFlagChecker && !rctChecker(collision1)) { + continue; + } + if (rctCut.requireRCTFlagChecker && !rctChecker(collision2)) { + continue; + } + int occupancy1 = collision1.trackOccupancyInTimeRange(); + int occupancy2 = collision2.trackOccupancyInTimeRange(); + + if (collision1.index() == collision2.index()) { + continue; + } + if (!collision1.sel8() || !collision2.sel8()) { + continue; + } + if (additionalEvSel && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (occupancy1 > cfgCutOccupancy) { + continue; + } + if (additionalEvSel && (!collision2.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision2.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + if (occupancy2 > cfgCutOccupancy) { + continue; + } + if (additionalEvSel3 && (!collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (additionalEvSel4 && !collision1.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + if (additionalEvSel5 && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + + if (additionalEvSel3 && (!collision2.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision2.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (additionalEvSel4 && !collision2.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + continue; + } + if (additionalEvSel5 && !collision2.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + continue; + } + auto centrality = collision1.centFT0C(); + // auto groupV01 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision1.globalIndex()); + // auto groupV02 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision1.globalIndex()); + // auto groupV03 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision2.globalIndex()); + auto groupV01 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision1.index()); + auto groupV02 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision1.index()); + auto groupV03 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision2.index()); + + size_t rows = groupV03.size() + 1600; + size_t cols = groupV01.size() + 1600; + std::vector> pairStatus(rows, std::vector(cols, false)); + histos.fill(HIST("hv0Mult"), groupV01.size()); + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV01, groupV02))) { + bool pairfound = false; + if (t2.index() <= t1.index()) { + continue; + } + if (t1.straCollisionId() != t2.straCollisionId()) { + continue; + } + + auto [lambdaTag1, aLambdaTag1, isValid1] = getLambdaTagsDD(t1, collision1); + auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTagsDD(t2, collision1); + if (!isValid1) { + continue; + } + if (!isValid2) { + continue; + } + if (lambdaTag1 && aLambdaTag1) { + continue; + } + if (lambdaTag2 && aLambdaTag2) { + continue; + } + // auto postrack1 = t1.template posTrackExtra_as(); + // auto negtrack1 = t1.template negTrackExtra_as(); + // auto postrack2 = t2.template posTrackExtra_as(); + // auto negtrack2 = t2.template negTrackExtra_as(); + if (t1.posTrackExtraId() == t2.posTrackExtraId() || t1.negTrackExtraId() == t2.negTrackExtraId()) { + continue; + } + // auto samePairSumPt = t1.pt() + t2.pt(); + // auto samePairR = TMath::Sqrt(TMath::Power(t1.phi() - t2.phi(), 2.0) + TMath::Power(t1.eta() - t2.eta(), 2.0)); + + double deltaPhiSame = RecoDecay::constrainAngle(t1.phi() - t2.phi(), 0.0); + auto samePairR = TMath::Sqrt(TMath::Power(deltaPhiSame, 2.0) + TMath::Power(t1.eta() - t2.eta(), 2.0)); + + if (lambdaTag1) { + proton0 = ROOT::Math::PxPyPzMVector(t1.pxpos(), t1.pypos(), t1.pzpos(), o2::constants::physics::MassProton); + antiPion0 = ROOT::Math::PxPyPzMVector(t1.pxneg(), t1.pyneg(), t1.pzneg(), o2::constants::physics::MassPionCharged); + lambda0 = proton0 + antiPion0; + } + if (aLambdaTag1) { + antiProton0 = ROOT::Math::PxPyPzMVector(t1.pxneg(), t1.pyneg(), t1.pzneg(), o2::constants::physics::MassProton); + pion0 = ROOT::Math::PxPyPzMVector(t1.pxpos(), t1.pypos(), t1.pzpos(), o2::constants::physics::MassPionCharged); + antiLambda0 = antiProton0 + pion0; + } + if (lambdaTag1 && (lambda0.M() < lbinIM || lambda0.M() > hbinIM)) { + continue; + } + if (aLambdaTag1 && (antiLambda0.M() < lbinIM || antiLambda0.M() > hbinIM)) { + continue; + } + if (lambdaTag2) { + proton = ROOT::Math::PxPyPzMVector(t2.pxpos(), t2.pypos(), t2.pzpos(), o2::constants::physics::MassProton); + antiPion = ROOT::Math::PxPyPzMVector(t2.pxneg(), t2.pyneg(), t2.pzneg(), o2::constants::physics::MassPionCharged); + lambda = proton + antiPion; + } + if (aLambdaTag2) { + antiProton = ROOT::Math::PxPyPzMVector(t2.pxneg(), t2.pyneg(), t2.pzneg(), o2::constants::physics::MassProton); + pion = ROOT::Math::PxPyPzMVector(t2.pxpos(), t2.pypos(), t2.pzpos(), o2::constants::physics::MassPionCharged); + antiLambda = antiProton + pion; + } + if (lambdaTag2 && (lambda.M() < lbinIM || lambda.M() > hbinIM)) { + continue; + } + if (aLambdaTag2 && (antiLambda.M() < lbinIM || antiLambda.M() > hbinIM)) { + continue; + } + + for (const auto& t3 : groupV03) { + if (pairStatus[t3.index()][t2.index()]) { + continue; + } + if (t1.straCollisionId() == t3.straCollisionId()) { + continue; + } + auto [lambdaTag3, aLambdaTag3, isValid3] = getLambdaTagsDD(t3, collision2); + if (!isValid3) { + continue; + } + if (lambdaTag3 && aLambdaTag3) { + continue; + } + if (lambdaTag1 != lambdaTag3 || aLambdaTag1 != aLambdaTag3) { + continue; + } + + if (lambdaTag3) { + proton2 = ROOT::Math::PxPyPzMVector(t3.pxpos(), t3.pypos(), t3.pzpos(), o2::constants::physics::MassProton); + antiPion2 = ROOT::Math::PxPyPzMVector(t3.pxneg(), t3.pyneg(), t3.pzneg(), o2::constants::physics::MassPionCharged); + lambda2 = proton2 + antiPion2; + } + if (aLambdaTag3) { + antiProton2 = ROOT::Math::PxPyPzMVector(t3.pxneg(), t3.pyneg(), t3.pzneg(), o2::constants::physics::MassProton); + pion2 = ROOT::Math::PxPyPzMVector(t3.pxpos(), t3.pypos(), t3.pzpos(), o2::constants::physics::MassPionCharged); + antiLambda2 = antiProton2 + pion2; + } + if (lambdaTag3 && (lambda2.M() < lbinIM || lambda2.M() > hbinIM)) { + continue; + } + + if (aLambdaTag3 && (antiLambda2.M() < lbinIM || antiLambda2.M() > hbinIM)) { + continue; + } + + double deltaPhiMix = RecoDecay::constrainAngle(t3.phi() - t2.phi(), 0.0); + auto mixPairR = TMath::Sqrt(TMath::Power(deltaPhiMix, 2.0) + TMath::Power(t3.eta() - t2.eta(), 2.0)); + + auto etaDiff = t1.eta() - t3.eta(); + auto phiDiff = RecoDecay::constrainAngle(t1.phi() - t3.phi(), 0.0); + + histos.fill(HIST("hPtDiff"), t1.pt() - t3.pt()); + histos.fill(HIST("hPhiDiff"), phiDiff); + histos.fill(HIST("hRDiff"), etaDiff); + + if (mixingCombination == 0 && std::abs(t1.pt() - t3.pt()) > ptMix) { + continue; + } + if (mixingCombination == 0 && t1.eta() * t3.eta() > 0 && std::abs(etaDiff) > etaMix) { + continue; + } + if (mixingCombination == 0 && phiDiff > phiMix) { + continue; + } + if (mixingCombination == 1 && std::abs(t1.pt() - t3.pt()) > ptMix) { + continue; + } + if (mixingCombination == 1 && std::abs(mixPairR - samePairR) > etaMix) { + continue; + } + if (lambdaTag2 && lambdaTag3) { + fillHistograms(1, 0, 1, 0, lambda, lambda2, proton, proton2, centrality, 2); + } else if (aLambdaTag2 && aLambdaTag3) { + fillHistograms(0, 1, 0, 1, antiLambda, antiLambda2, antiProton, antiProton2, centrality, 2); + } else if (lambdaTag2 && aLambdaTag3) { + fillHistograms(1, 0, 0, 1, lambda, antiLambda2, proton, antiProton2, centrality, 2); + } else if (aLambdaTag2 && lambdaTag3) { + fillHistograms(0, 1, 1, 0, antiLambda, lambda2, antiProton, proton2, centrality, 2); + } else { + continue; + } + pairfound = true; + pairStatus[t3.index()][t2.index()] = true; + if (pairfound) { + break; + } + } + } + } + } + + PROCESS_SWITCH(LfTaskLambdaSpinCorr, processDerivedDataMixed, "Process mixed derived data", true); + + using CollisionMCRecTableCentFT0C = soa::Join; + using TrackMCRecTable = soa::Join; + using V0TrackCandidatesMC = soa::Join; + + void processMC(CollisionMCRecTableCentFT0C::iterator const& collision, TrackMCRecTable const& /*tracks*/, V0TrackCandidatesMC const& V0s) + { + + // for (const auto& RecCollis : collision) { + if (!collision.sel8()) { + return; + } + if (std::abs(collision.posZ()) > cfgCutVertex) { + return; + } + auto centrality = collision.centFT0C(); + histos.fill(HIST("hCentrality"), centrality); + for (const auto& v0 : V0s) { + auto [lambdaTag, aLambdaTag, isValid] = getLambdaTagsMC(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); + lambda = 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); + antiLambda = antiProton + pion; + } + if (lambdaTag && aLambdaTag) { + continue; + } + auto postrack1 = v0.template posTrack_as(); + auto negtrack1 = v0.template negTrack_as(); + // 2nd loop for combination of lambda lambda + for (const auto& v02 : V0s) { + if (v02.index() <= v0.index()) { + continue; + } + auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTagsMC(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); + lambda2 = 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); + antiLambda2 = antiProton2 + pion2; + } + if (lambdaTag && aLambdaTag) { + continue; + } + auto postrack2 = v02.template posTrack_as(); + auto negtrack2 = v02.template negTrack_as(); + if (postrack1.globalIndex() == postrack2.globalIndex() || negtrack1.globalIndex() == negtrack2.globalIndex()) { + continue; // no shared decay products + } + if (lambdaTag && lambdaTag2) { + fillHistograms(1, 0, 1, 0, lambda, lambda2, proton, proton2, centrality, 0); + } + if (aLambdaTag && aLambdaTag2) { + fillHistograms(0, 1, 0, 1, antiLambda, antiLambda2, antiProton, antiProton2, centrality, 0); + } + if (lambdaTag && aLambdaTag2) { + fillHistograms(1, 0, 0, 1, lambda, antiLambda2, proton, antiProton2, centrality, 0); + } + if (aLambdaTag && lambdaTag2) { + fillHistograms(0, 1, 1, 0, antiLambda, lambda2, antiProton, proton2, centrality, 0); + } + } + } + } + PROCESS_SWITCH(LfTaskLambdaSpinCorr, processMC, "Process montecarlo", false); + + // Processing Event Mixing MC + void processMEMC(CollisionMCRecTableCentFT0C const& collisions, TrackMCRecTable const&, V0TrackCandidatesMC const& V0s) + { + for (auto& [collision1, collision2] : selfCombinations(colBinning, nMix, -1, collisions, collisions)) { + // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.index(), collision2.index()); + + if (collision1.index() == collision2.index()) { + continue; + } + if (!collision1.sel8() || !collision2.sel8()) { + continue; + } + if (std::abs(collision1.posZ()) > cfgCutVertex) { + continue; + } + if (std::abs(collision2.posZ()) > cfgCutVertex) { + continue; + } + + auto centrality = collision1.centFT0C(); + auto groupV01 = V0s.sliceBy(tracksPerCollisionV0, collision1.globalIndex()); + auto groupV02 = V0s.sliceBy(tracksPerCollisionV0, collision1.globalIndex()); + auto groupV03 = V0s.sliceBy(tracksPerCollisionV0, collision2.globalIndex()); + // for (auto& [t1, t2, t3] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV01, groupV02, groupV03))) { + // LOGF(info, "Mixed event collisions: (%d, %d, %d)", t1.collisionId(),t2.collisionId(),t3.collisionId()); + auto maxV0Size = 1100; + if (groupV01.size() > maxV0Size || groupV02.size() > maxV0Size || groupV03.size() > maxV0Size) { + continue; + } + bool pairStatus[1150][1150] = {{false}}; + for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupV01, groupV02))) { + bool pairfound = false; + if (t2.index() <= t1.index()) { + continue; + } + if (t1.collisionId() != t2.collisionId()) { + continue; + } + auto [lambdaTag1, aLambdaTag1, isValid1] = getLambdaTagsMC(t1, collision1); + auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTagsMC(t2, collision1); + if (!isValid1) { + continue; + } + if (!isValid2) { + continue; + } + if (lambdaTag1 && aLambdaTag1) { + continue; + } + if (lambdaTag2 && aLambdaTag2) { + 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() || negtrack1.globalIndex() == negtrack2.globalIndex()) { + continue; + } + for (const auto& t3 : groupV03) { + if (pairStatus[t3.index()][t2.index()]) { + // LOGF(info, "repeat match found v0 id: (%d, %d)", t3.index(), t2.index()); + continue; + } + if (t1.collisionId() == t3.collisionId()) { + continue; + } + auto [lambdaTag3, aLambdaTag3, isValid3] = getLambdaTagsMC(t3, collision2); + if (!isValid3) { + continue; + } + if (lambdaTag3 && aLambdaTag3) { + continue; + } + if (lambdaTag1 != lambdaTag3 || aLambdaTag1 != aLambdaTag3) { + continue; + } + if (std::abs(t1.pt() - t3.pt()) > ptMix) { + continue; + } + if (std::abs(t1.eta() - t3.eta()) > etaMix) { + continue; + } + if (std::abs(t1.phi() - t3.phi()) > phiMix) { + continue; + } + if (lambdaTag2) { + proton = ROOT::Math::PxPyPzMVector(t2.pxpos(), t2.pypos(), t2.pzpos(), o2::constants::physics::MassProton); + antiPion = ROOT::Math::PxPyPzMVector(t2.pxneg(), t2.pyneg(), t2.pzneg(), o2::constants::physics::MassPionCharged); + lambda = proton + antiPion; + } + if (aLambdaTag2) { + antiProton = ROOT::Math::PxPyPzMVector(t2.pxneg(), t2.pyneg(), t2.pzneg(), o2::constants::physics::MassProton); + pion = ROOT::Math::PxPyPzMVector(t2.pxpos(), t2.pypos(), t2.pzpos(), o2::constants::physics::MassPionCharged); + antiLambda = antiProton + pion; + } + if (lambdaTag3) { + proton2 = ROOT::Math::PxPyPzMVector(t3.pxpos(), t3.pypos(), t3.pzpos(), o2::constants::physics::MassProton); + antiPion2 = ROOT::Math::PxPyPzMVector(t3.pxneg(), t3.pyneg(), t3.pzneg(), o2::constants::physics::MassPionCharged); + lambda2 = proton2 + antiPion2; + } + if (aLambdaTag3) { + antiProton2 = ROOT::Math::PxPyPzMVector(t3.pxneg(), t3.pyneg(), t3.pzneg(), o2::constants::physics::MassProton); + pion2 = ROOT::Math::PxPyPzMVector(t3.pxpos(), t3.pypos(), t3.pzpos(), o2::constants::physics::MassPionCharged); + antiLambda2 = antiProton2 + pion2; + } + if (lambdaTag2 && lambdaTag3) { + fillHistograms(1, 0, 1, 0, lambda, lambda2, proton, proton2, centrality, 2); + } + if (aLambdaTag2 && aLambdaTag3) { + fillHistograms(0, 1, 0, 1, antiLambda, antiLambda2, antiProton, antiProton2, centrality, 2); + } + if (lambdaTag2 && aLambdaTag3) { + fillHistograms(1, 0, 0, 1, lambda, antiLambda2, proton, antiProton2, centrality, 2); + } + if (aLambdaTag2 && lambdaTag3) { + fillHistograms(0, 1, 1, 0, antiLambda, lambda2, antiProton, proton2, centrality, 2); + } + pairfound = true; + pairStatus[t3.index()][t2.index()] = true; + if (pairfound) { + // LOGF(info, "Pair found"); + break; + } + } + } + } + } + PROCESS_SWITCH(LfTaskLambdaSpinCorr, processMEMC, "Process MC ME", false); +}; +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Strangeness/v0postprocessing.cxx b/PWGLF/Tasks/Strangeness/v0postprocessing.cxx index 1844390a3da..ef65d5996b8 100644 --- a/PWGLF/Tasks/Strangeness/v0postprocessing.cxx +++ b/PWGLF/Tasks/Strangeness/v0postprocessing.cxx @@ -13,24 +13,24 @@ /// \author Francesca Ercolessi (francesca.ercolessi@cern.ch) /// \since -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/v0qaanalysis.h" + #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" 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,20 +43,74 @@ 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", 1, "hasTOF1Leg"}; + Configurable hasTOF1Leg{"hasTOF1Leg", 0, "hasTOF1Leg"}; + Configurable paramArmenterosCut{"paramArmenterosCut", 0.2, "parameter Armenteros Cut"}; + Configurable doArmenterosCut{"doArmenterosCut", 1, "do Armenteros Cut for K0s"}; + Configurable doArmenterosCutLam{"doArmenterosCutLam", 1, "do Armenteros Cut for Lam"}; + 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}}}); @@ -66,169 +120,399 @@ 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::kTH3F, {{250, 0.0f, 25.0f}, {200, 0.4f, 0.6f}, {100, 0.f, 100.f}}}); + 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("hFDVsPtLambdaVsMotherPt_DoubleCharged_MC", ";p_{T} [GeV/c] (V0);p_{T}^{gen} [GeV/c] (#Xi^{-}); percentile", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {250, 0.0f, 25.0f}, {100, 0.f, 100.f}}}); + registry.add("hFDVsPtLambdaVsMotherPt_MCRatio_MC", ";p_{T} [GeV/c] (V0);p_{T}^{gen} [GeV/c] (#Xi^{-/0}); percentile", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {250, 0.0f, 25.0f}, {100, 0.f, 100.f}}}); + 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("hFDVsPtAntiLambdaVsMotherPt_DoubleCharged_MC", ";p_{T} [GeV/c] (V0);p_{T}^{gen} [GeV/c] (#bar{#Xi}^{+});percentile", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {250, 0.0f, 25.0f}, {100, 0.f, 100.f}}}); + registry.add("hFDVsPtAntiLambdaVsMotherPt_MCRatio_MC", ";p_{T} [GeV/c] (V0);p_{T}^{gen} [GeV/c] (#bar{#Xi}^{+/0});percentile", {HistType::kTH3F, {{250, 0.0f, 25.0f}, {250, 0.0f, 25.0f}, {100, 0.f, 100.f}}}); } - // 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) - continue; - if (evSel && candidate.evflag() < 1) - continue; - if (hasTOF1Leg && !candidate.poshastof() && !candidate.neghastof()) - continue; - if (hasTOF2Leg && (!candidate.poshastof() || !candidate.neghastof())) + 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.1 && + 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.multft0m(), 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 && + (!doArmenterosCutLam || candidate.qtarm() < (paramArmenterosCut * std::abs(candidate.alpha())))) { + + 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 && 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()); + } else if (std::abs(candidate.masslambda() - o2::constants::physics::MassLambda0) < 0.01) { + if (candidate.pdgcodemother() == 3312) { + registry.fill(HIST("hFDVsPtLambdaVsMotherPt_DoubleCharged_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.multft0m()); + } + if (candidate.pdgcodemother() == 3312 || candidate.pdgcodemother() == 3322) { + registry.fill(HIST("hFDVsPtLambdaVsMotherPt_MCRatio_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.multft0m()); + } + } + } + + 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 && + (!doArmenterosCutLam || candidate.qtarm() < (paramArmenterosCut * std::abs(candidate.alpha())))) { + + 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 (isMC && candidate.pdgcode() == -3122 && candidate.isdauantilambda()) { + + if (candidate.isphysprimary() == 1) { + registry.fill(HIST("hMassAntiLambda_MC"), candidate.massantilambda()); + registry.fill(HIST("hMassVsPtAntiLambdaVsCentFT0M_MC"), candidate.v0pt(), candidate.multft0m(), candidate.massantilambda()); + } else if (std::abs(candidate.massantilambda() - o2::constants::physics::MassLambda0) < 0.01) { + if (candidate.pdgcodemother() == -3312) { + registry.fill(HIST("hFDVsPtAntiLambdaVsMotherPt_DoubleCharged_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.multft0m()); + } + if (candidate.pdgcodemother() == -3312 || candidate.pdgcodemother() == -3322) { + registry.fill(HIST("hFDVsPtAntiLambdaVsMotherPt_MCRatio_MC"), candidate.v0pt(), candidate.v0motherpt(), candidate.multft0m()); + } + } + } + + 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..59dae0fe140 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx @@ -0,0 +1,1023 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "CommonUtils/StringUtils.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include "TPDGCode.h" + +#include +#include +#include +#include + +// 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; +std::vector> kaonSplit; +std::vector> lambdaSplit; +std::vector> antilambdaSplit; +} // 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 rKaonshSplitMassPlotsPerPtBin{"KaonshSplitMassPlotsPerPtBin", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambdaSplitMassPlotsPerPtBin{"LambdaSplitMassPlotsPerPtBin", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rAntilambdaSplitMassPlotsPerPtBin{"AntilambdaSplitMassPlotsPerPtBin", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rFeeddownMatrices{"FeeddownMatrices", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rMCCorrections{"MCCorrections", {}, 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"}; + + // 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"}; + Configurable itsMinHits{"itsMinHits", 1.0, "Minimum Hits of Daughter Tracks in the ITS"}; + + // Configurables switches for event selection + Configurable dosel8{"dosel8", true, "Enable sel8 event selection"}; + Configurable doNoTimeFrameBorder{"doNoTimeFrameBorder", true, "Enable NoTimeFrameBorder event selection"}; + Configurable doNoITSROFrameBorder{"doNoITSROFrameBorder", true, "Enable NoITSROFrameBorder event selection"}; + Configurable doIsTriggerTVX{"doIsTriggerTVX", true, "Enable IsTriggerTVX event selection"}; + Configurable docutZVertex{"docutZVertex", true, "Enable cutZVertex event selection"}; + Configurable doIsVertexTOFmatched{"doIsVertexTOFmatched", true, "Enable IsVertexTOFmatched event selection"}; + Configurable doNoSameBunchPileup{"doNoSameBunchPileup", true, "Enable NoSameBunchPileup event selection"}; + Configurable doIsVertexITSTPC{"doIsVertexITSTPC", true, "Enable IsVertexITSTPC event selection"}; + Configurable doisInelGt0{"doisInelGt0", true, "Enable isInelGt0 event selection"}; + + // Configurables switches for v0 selection + Configurable doRapidityCut{"doRapidityCut", true, "Enable rapidity v0 selection"}; + Configurable doDaughterPseudorapidityCut{"doDaughterPseudorapidityCut", true, "Enable Daughter pseudorapidity v0 selection"}; + Configurable doisNotITSAfterburner{"doisNotITSAfterburner", true, "Enable Tracks do not come from Afterburner"}; + Configurable doitsMinHits{"doitsMinHits", true, "Enable ITS Minimum hits"}; + + // Configurables switches for K0sh selection + Configurable dotruthk0sh{"dotruthk0sh", true, "Enable K0sh MC Matching"}; + Configurable doK0shTPCPID{"doK0shTPCPID", true, "Enable K0sh TPC PID"}; + Configurable doK0shcomptmasscut{"doK0shcomptmasscut", true, "Enable K0sh Competitive V0 Mass Cut"}; + Configurable doK0shMaxct{"doK0shMaxct", true, "Enable K0sh Max ct Cut"}; + Configurable doK0shArmenterosCut{"doK0shArmenterosCut", true, "Enable K0sh Armenteros Cut"}; + Configurable doK0shcosPACut{"doK0shcosPACut", true, "Enable K0sh cosPA Topological Cut"}; + Configurable doK0shDCAdauCut{"doK0shDCAdauCut", true, "Enable K0sh DCA daughters Topological Cut"}; + Configurable doK0shv0radiusCut{"doK0shv0radiusCut", true, "Enable K0sh v0radius Topological Cut"}; + Configurable doK0shdcaposdautopv{"doK0shdcaposdautopv", true, "Enable K0sh DCA pos daughter to PV Topological Cut"}; + Configurable doK0shdcanegdautopv{"doK0shdcanegdautopv", true, "Enable K0sh DCA neg daughter to PV Topological Cut"}; + + // Configurables switches for Lambda selection + Configurable dotruthLambda{"dotruthLambda", true, "Enable Lambda MC Matching"}; + Configurable doLambdaTPCPID{"doLambdaTPCPID", true, "Enable Lambda TPC PID"}; + Configurable doLambdacomptmasscut{"doLambdacomptmasscut", true, "Enable Lambda Competitive V0 Mass Cut"}; + Configurable doLambdaMaxct{"doLambdaMaxct", true, "Enable Lambda Max ct Cut"}; + Configurable doLambdaArmenterosCut{"doLambdaArmenterosCut", true, "Enable Lambda Armenteros Cut"}; + Configurable doLambdacosPACut{"doLambdacosPACut", true, "Enable Lambda cosPA Topological Cut"}; + Configurable doLambdaDCAdauCut{"doLambdaDCAdauCut", true, "Enable Lambda DCA daughters Topological Cut"}; + Configurable doLambdav0radiusCut{"doLambdav0radiusCut", true, "Enable Lambda v0radius Topological Cut"}; + Configurable doLambdadcaposdautopv{"doLambdadcaposdautopv", true, "Enable Lambda DCA pos daughter to PV Topological Cut"}; + Configurable doLambdadcanegdautopv{"doLambdadcanegdautopv", true, "Enable Lambda DCA neg daughter to PV Topological Cut"}; + + // Configurables switches for Lambda selection + Configurable dotruthAntilambda{"dotruthAntilambda", true, "Enable Antilambda MC Matching"}; + Configurable doAntilambdaTPCPID{"doAntilambdaTPCPID", true, "Enable Antilambda TPC PID"}; + Configurable doAntilambdacomptmasscut{"doAntilambdacomptmasscut", true, "Enable Antilambda Competitive V0 Mass Cut"}; + Configurable doAntilambdaMaxct{"doAntilambdaMaxct", true, "Enable Antilambda Max ct Cut"}; + Configurable doAntilambdaArmenterosCut{"doAntilambdaArmenterosCut", true, "Enable Antilambda Armenteros Cut"}; + Configurable doAntilambdacosPACut{"doAntilambdacosPACut", true, "Enable Antilambda cosPA Topological Cut"}; + Configurable doAntilambdaDCAdauCut{"doAntilambdaDCAdauCut", true, "Enable Antilambda DCA daughters Topological Cut"}; + Configurable doAntilambdav0radiusCut{"doAntilambdav0radiusCut", true, "Enable Antilambda v0radius Topological Cut"}; + Configurable doAntilambdadcaposdautopv{"doAntilambdadcaposdautopv", true, "Enable Antilambda DCA pos daughter to PV Topological Cut"}; + Configurable doAntilambdadcanegdautopv{"doAntilambdadcanegdautopv", true, "Enable Antilambda DCA neg daughter to PV Topological Cut"}; + + // Configurable Kaonsh 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 kaonshmaxct{"kaonshmaxct", 20.00, "K0sh maximum ct value"}; + Configurable k0shparamArmenterosCut{"k0shparamArmenterosCut", 0.2, "K0sh Armenteros Cut on parameter"}; + + // Configurable Lambda 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 lambdamaxct{"lambdamaxct", 30.00, "Lambda maximum ct value"}; + Configurable lambdaparamArmenterosCut{"lambdaparamArmenterosCut", 0.2, "Lambda Armenteros Cut on parameter"}; + + // Configurable Antilambda 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"}; + Configurable antilambdamaxct{"antilambdamaxct", 30.00, "Antilambda maximum ct value"}; + Configurable antilambdaparamArmenterosCut{"antilambdaparamArmenterosCut", 0.2, "Antilambda Armenteros Cut on parameter"}; + + // 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&) + { + // 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, ','); + + // Calculate number of histograms for each particle type + int nKaonHistograms = pthistos::kaonPtBins.size() - 1; + int nLambdaHistograms = pthistos::lambdaPtBins.size() - 1; + int nAntilambdaHistograms = pthistos::antilambdaPtBins.size() - 1; + + pthistos::kaonPt.resize(nKaonHistograms); // number of Kaon Pt histograms to expect + pthistos::lambdaPt.resize(nLambdaHistograms); // number of Lambda histograms to expect + pthistos::antilambdaPt.resize(nAntilambdaHistograms); // number of Antilambda histograms to expect + pthistos::kaonSplit.resize(nKaonHistograms); // number of Kaon Split Pt histograms to expect + pthistos::lambdaSplit.resize(nLambdaHistograms); // number of Lambda Split Pt histograms to expect + pthistos::antilambdaSplit.resize(nAntilambdaHistograms); // number of Antilambda Split Pt histograms to expect + + // initialize and convert tokenized strings into vector of doubles for AxisSpec + std::vector kaonptedgevalues(pthistos::kaonPtBins.size()); + std::vector lambdaptedgevalues(pthistos::lambdaPtBins.size()); + std::vector antilambdaPtedgevalues(pthistos::antilambdaPtBins.size()); + for (size_t i = 0; i < pthistos::kaonPtBins.size(); i++) { + kaonptedgevalues[i] = std::stod(pthistos::kaonPtBins[i]); + } + for (size_t i = 0; i < pthistos::lambdaPtBins.size(); i++) { + lambdaptedgevalues[i] = std::stod(pthistos::lambdaPtBins[i]); + } + for (size_t i = 0; i < pthistos::antilambdaPtBins.size(); 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 centAxis = {100, 0.0f, 100.0f, "#it{Centrality} (%)"}; + AxisSpec armenterosQtAxis = {nBinsArmenteros, 0.0f, 0.3f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec armenterosasymAxis = {nBinsArmenteros, -1.f, 1.f, "#it{p}^{+}_{||}-#it{p}^{-}_{||}/#it{p}^{+}_{||}+#it{p}^{-}_{||}"}; + AxisSpec vertexZAxis = {nBins, -11.0f, 11.0f, "vrtx_{Z} [cm]"}; + AxisSpec partCutsAxis{10, 0.0f, 10.0f, "Cut index"}; + + std::vector kaonhistvalue(nKaonHistograms + 1); + std::vector lambdahistvalue(nLambdaHistograms + 1); + std::vector antilambdahistvalue(nAntilambdaHistograms + 1); + // K0short Histogram Pt Bin Edges (and Split) + for (int i = 0; i < nKaonHistograms + 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 the string-value to a "_" + kaonhistvalue[i] = kaonptbin; // filling bin edges list + } + // Lambda Histograms Pt Bin Edges (same as K0s above) + for (int i = 0; i < nLambdaHistograms + 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 < nAntilambdaHistograms + 1; i++) { + std::string antilambdaPtbin = pthistos::antilambdaPtBins[i]; + size_t pos = antilambdaPtbin.find("."); + antilambdaPtbin[pos] = '_'; + antilambdahistvalue[i] = antilambdaPtbin; + } + + // General Plots + rPtAnalysis.add("hNEvents", "hNEvents", {HistType::kTH1D, {{7, 0.f, 7.f}}}); + rPtAnalysis.add("hNRecEvents_Data", "hNRecEvents_Data", {HistType::kTH1D, {{1, 0.f, 1.f}}}); + rPtAnalysis.add("hNV0s", "hNV0s", {HistType::kTH1D, {{10, 0.f, 10.f}}}); + rPtAnalysis.add("hNK0sh", "hNK0sh", {HistType::kTH1D, {{11, 0.f, 11.f}}}); + rPtAnalysis.add("hNLambda", "hNLambda", {HistType::kTH1D, {{11, 0.f, 11.f}}}); + rPtAnalysis.add("hNAntilambda", "hNAntilambda", {HistType::kTH1D, {{11, 0.f, 11.f}}}); + 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, -1.0f, 1.0f}}}); + + // Adding Kzerosh Histograms to registry + if (kzeroAnalysis == true) { + rPtAnalysis.add("hMassK0ShortvsCuts", "hMassK0ShortvsCuts", {HistType::kTH2F, {{partCutsAxis}, {k0ShortMassAxis}}}); + rPtAnalysis.add("hArmenterosPodolanskiPlotK0sh", "hArmenterosPodolanskiPlotK0sh", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); + rPtAnalysis.add("hNSigmaPosPionFromK0s", "hNSigmaPosPionFromK0s", {HistType::kTH2F, {{100, -5.f, 5.f}, {k0ShortPtAxis}}}); + rPtAnalysis.add("hNSigmaNegPionFromK0s", "hNSigmaNegPionFromK0s", {HistType::kTH2F, {{100, -5.f, 5.f}, {k0ShortPtAxis}}}); + rPtAnalysis.add("hK0shV0radius", "hK0shV0radius", {HistType::kTH1F, {{nBins, 0.0f, 50.0f}}}); + rPtAnalysis.add("hK0shcosPA", "hK0shcosPA", {HistType::kTH1F, {{nBins, 0.95f, 1.0f}}}); + rPtAnalysis.add("hK0shDCAV0Daughters", "hK0shDCAV0Daughters", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + rPtAnalysis.add("hK0shDCAPosDaughter", "hK0shDCAPosDaughter", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + rPtAnalysis.add("hK0shDCANegDaughter", "hK0shDCANegDaughter", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + for (int i = 0; i < nKaonHistograms; i++) { + pthistos::kaonPt[i] = rKaonshMassPlotsPerPtBin.add(fmt::format("hK0shPt_vs_Cent_from_{0}_to_{1}", kaonhistvalue[i], kaonhistvalue[i + 1]).c_str(), fmt::format("K0s mass vs centrality, pT from {0} to {1}", kaonhistvalue[i], kaonhistvalue[i + 1]).c_str(), {HistType::kTH2D, {{k0ShortMassAxis}, {centAxis}}}); + pthistos::kaonSplit[i] = rKaonshSplitMassPlotsPerPtBin.add(fmt::format("hK0shSplitPt_vs_Cent_from_{0}_to_{1}", kaonhistvalue[i], kaonhistvalue[i + 1]).c_str(), fmt::format("Split K0s mass vs centrality, pT from {0} to {1}", kaonhistvalue[i], kaonhistvalue[i + 1]).c_str(), {HistType::kTH2D, {{k0ShortMassAxis}, {centAxis}}}); + } + rFeeddownMatrices.add("hK0shFeeddownMatrix", "hK0shFeeddownMatrix", {HistType::kTH3D, {k0ShortPtAxis, k0ShortPtAxis, centAxis}}); + rFeeddownMatrices.add("hK0shPhiFeeddownMatrix", "hK0shPhiFeeddownMatrix", {HistType::kTH3D, {k0ShortPtAxis, k0ShortPtAxis, centAxis}}); + } + // Adding Lambda Histograms + if (lambdaAnalysis == true) { + // same method as in Kzerosh above + rPtAnalysis.add("hMassLambdavsCuts", "hMassLambdavsCuts", {HistType::kTH2F, {{partCutsAxis}, {k0ShortMassAxis}}}); + rPtAnalysis.add("hArmenterosPodolanskiPlotLambda", "hArmenterosPodolanskiPlotLambda", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); + rPtAnalysis.add("hNSigmaPosProtonFromLambdas", "hNSigmaPosProtonFromLambdas", {HistType::kTH2F, {{100, -5.f, 5.f}, {lambdaPtAxis}}}); + rPtAnalysis.add("hNSigmaNegPionFromLambdas", "hNSigmaNegPionFromLambdas", {HistType::kTH2F, {{100, -5.f, 5.f}, {lambdaPtAxis}}}); + rPtAnalysis.add("hLambdaV0radius", "hLambdaV0radius", {HistType::kTH1F, {{nBins, 0.0f, 50.0f}}}); + rPtAnalysis.add("hLambdacosPA", "hLambdacosPA", {HistType::kTH1F, {{nBins, 0.95f, 1.0f}}}); + rPtAnalysis.add("hLambdaDCAV0Daughters", "hLambdaDCAV0Daughters", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + rPtAnalysis.add("hLambdaDCAPosDaughter", "hLambdaDCAPosDaughter", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + rPtAnalysis.add("hLambdaDCANegDaughter", "hLambdaDCANegDaughter", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + + for (int i = 0; i < nLambdaHistograms; i++) { + pthistos::lambdaPt[i] = rLambdaMassPlotsPerPtBin.add(fmt::format("hLambdaPt_vs_Cent_from_{0}_to_{1}", lambdahistvalue[i], lambdahistvalue[i + 1]).c_str(), fmt::format("Lambda mass vs centrality, pT from {0} to {1}", lambdahistvalue[i], lambdahistvalue[i + 1]).c_str(), {HistType::kTH2D, {{lambdaMassAxis}, {centAxis}}}); + pthistos::lambdaSplit[i] = rLambdaSplitMassPlotsPerPtBin.add(fmt::format("hLambdaSplitPt_vs_Cent_from_{0}_to_{1}", lambdahistvalue[i], lambdahistvalue[i + 1]).c_str(), fmt::format("Split Lambda mass vs centrality, pT from {0} to {1}", lambdahistvalue[i], lambdahistvalue[i + 1]).c_str(), {HistType::kTH2D, {{lambdaMassAxis}, {centAxis}}}); + } + // lambdafeeddown matrices + rFeeddownMatrices.add("hLambdaFeeddownMatrix", "hLambdaFeeddownMatrix", {HistType::kTH3D, {lambdaPtAxis, lambdaPtAxis, centAxis}}); + rFeeddownMatrices.add("hLambdaXiMinusFeeddownMatrix", "hLambdaXiMinusFeeddownMatrix", {HistType::kTH3D, {lambdaPtAxis, lambdaPtAxis, centAxis}}); + rFeeddownMatrices.add("hLambdaXiZeroFeeddownMatrix", "hLambdaXiZeroFeeddownMatrix", {HistType::kTH3D, {lambdaPtAxis, lambdaPtAxis, centAxis}}); + rFeeddownMatrices.add("hLambdaOmegaFeeddownMatrix", "hLambdaOmegaFeeddownMatrix", {HistType::kTH3D, {lambdaPtAxis, lambdaPtAxis, centAxis}}); + } + // Adding Antilambda Histograms + if (antiLambdaAnalysis == true) { + // same method as in Lambda and Kzerosh above + rPtAnalysis.add("hMassAntilambdavsCuts", "hMassAntilambdavsCuts", {HistType::kTH2F, {{partCutsAxis}, {k0ShortMassAxis}}}); + rPtAnalysis.add("hArmenterosPodolanskiPlotAntilambda", "hArmenterosPodolanskiPlotAntilambda", {HistType::kTH2F, {{armenterosasymAxis}, {armenterosQtAxis}}}); + rPtAnalysis.add("hNSigmaPosPionFromAntilambdas", "hNSigmaPosPionFromAntilambdas", {HistType::kTH2F, {{100, -5.f, 5.f}, {antilambdaPtAxis}}}); + rPtAnalysis.add("hNSigmaNegProtonFromAntilambdas", "hNSigmaNegProtonFromAntilambdas", {HistType::kTH2F, {{100, -5.f, 5.f}, {antilambdaPtAxis}}}); + rPtAnalysis.add("hAntilambdaV0radius", "hAntilambdaV0radius", {HistType::kTH1F, {{nBins, 0.0f, 50.0f}}}); + rPtAnalysis.add("hAntilambdacosPA", "hAntilambdacosPA", {HistType::kTH1F, {{nBins, 0.95f, 1.0f}}}); + rPtAnalysis.add("hAntilambdaDCAV0Daughters", "hAntilambdaDCAV0Daughters", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + rPtAnalysis.add("hAntilambdaDCAPosDaughter", "hAntilambdaDCAPosDaughter", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + rPtAnalysis.add("hAntilambdaDCANegDaughter", "hAntilambdaDCANegDaughter", {HistType::kTH1F, {{nBins, 0.0f, 2.2f}}}); + for (int i = 0; i < nAntilambdaHistograms; i++) { + pthistos::antilambdaPt[i] = rAntilambdaMassPlotsPerPtBin.add(fmt::format("hAntilambdaPt_vs_Cent_from_{0}_to_{1}", antilambdahistvalue[i], antilambdahistvalue[i + 1]).c_str(), fmt::format("Antilambda mass vs centrality, pT from {0} to {1}", antilambdahistvalue[i], antilambdahistvalue[i + 1]).c_str(), {HistType::kTH2D, {{antiLambdaMassAxis}, {centAxis}}}); + pthistos::antilambdaSplit[i] = rAntilambdaSplitMassPlotsPerPtBin.add(fmt::format("hAntilambdaSplitPt_vs_Cent_from_{0}_to_{1}", antilambdahistvalue[i], antilambdahistvalue[i + 1]).c_str(), fmt::format("Split Antilambda mass vs centrality, pT from {0} to {1}", antilambdahistvalue[i], antilambdahistvalue[i + 1]).c_str(), {HistType::kTH2D, {{antiLambdaMassAxis}, {centAxis}}}); + } + // antilambdafeeddown matrices + rFeeddownMatrices.add("hAntiLambdaFeeddownMatrix", "hAntiLambdaFeeddownMatrix", {HistType::kTH3D, {antilambdaPtAxis, antilambdaPtAxis, centAxis}}); + rFeeddownMatrices.add("hAntiLambdaXiPlusFeeddownMatrix", "hAntiLambdaXiPlusFeeddownMatrix", {HistType::kTH3D, {antilambdaPtAxis, antilambdaPtAxis, centAxis}}); + rFeeddownMatrices.add("hAntiLambdaAntiXiZeroFeeddownMatrix", "hAntiLambdaAntiXiZeroFeeddownMatrix", {HistType::kTH3D, {antilambdaPtAxis, antilambdaPtAxis, centAxis}}); + rFeeddownMatrices.add("hAntiLambdaAntiOmegaFeeddownMatrix", "hAntiLambdaAntiOmegaFeeddownMatrix", {HistType::kTH3D, {antilambdaPtAxis, antilambdaPtAxis, centAxis}}); + } + + // Particle Level Corrections + rMCCorrections.add("hK0ShNoMCParticle", "hK0ShNoMCParticle", {HistType::kTH1D, {k0ShortPtAxis}}); + rMCCorrections.add("hK0ShBeforeEventSelectionPtSpectrum", "hK0ShBeforeEventSelectionPtSpectrum", {HistType::kTH2D, {k0ShortPtAxis, centAxis}}); + rMCCorrections.add("hLambdaBeforeEventSelectionPtSpectrum", "hLambdaBeforeEventSelectionPtSpectrum", {HistType::kTH2D, {lambdaPtAxis, centAxis}}); + rMCCorrections.add("hAntilambdaBeforeEventSelectionPtSpectrum", "hAntilambdaBeforeEventSelectionPtSpectrum", {HistType::kTH2D, {antilambdaPtAxis, centAxis}}); + rMCCorrections.add("hK0ShAfterEventSelectionPtSpectrum", "hK0ShAfterEventSelectionPtSpectrum", {HistType::kTH2D, {k0ShortPtAxis, centAxis}}); + rMCCorrections.add("hLambdaAfterEventSelectionPtSpectrum", "hLambdaAfterEventSelectionPtSpectrum", {HistType::kTH2D, {lambdaPtAxis, centAxis}}); + rMCCorrections.add("hAntilambdaAfterEventSelectionPtSpectrum", "hAntilambdaAfterEventSelectionPtSpectrum", {HistType::kTH2D, {antilambdaPtAxis, centAxis}}); + + // Event and V0s Corrections + rMCCorrections.add("hNEvents_Corrections", "hNEvents_Corrections", {HistType::kTH1D, {{10, 0.f, 10.f}}}); + rMCCorrections.add("hNRecEvents_MC", "hNRecEvents_MC", {HistType::kTH1D, {{1, 0.f, 1.f}}}); + + // Generated Level Pt Spectrums (with rapidity cut) + rMCCorrections.add("GenParticleRapidity", "GenParticleRapidity", {HistType::kTH1F, {{nBins, -10.0f, 10.0f}}}); + rMCCorrections.add("hK0ShGeneratedPtSpectrum", "hK0ShGeneratedPtSpectrum", {HistType::kTH2D, {k0ShortPtAxis, centAxis}}); + rMCCorrections.add("hLambdaGeneratedPtSpectrum", "hLambdaGeneratedPtSpectrum", {HistType::kTH2D, {lambdaPtAxis, centAxis}}); + rMCCorrections.add("hAntilambdaGeneratedPtSpectrum", "hAntilambdaGeneratedPtSpectrum", {HistType::kTH2D, {antilambdaPtAxis, centAxis}}); + rMCCorrections.add("hXiMinusGeneratedPtSpectrum", "hXiMinusGeneratedPtSpectrum", {HistType::kTH2D, {lambdaPtAxis, centAxis}}); + rMCCorrections.add("hXiZeroGeneratedPtSpectrum", "hXiZeroGeneratedPtSpectrum", {HistType::kTH2D, {lambdaPtAxis, centAxis}}); + rMCCorrections.add("hOmegaGeneratedPtSpectrum", "hOmegaGeneratedPtSpectrum", {HistType::kTH2D, {lambdaPtAxis, centAxis}}); + rMCCorrections.add("hXiPlusGeneratedPtSpectrum", "hXiPlusGeneratedPtSpectrum", {HistType::kTH2D, {antilambdaPtAxis, centAxis}}); + rMCCorrections.add("hAntiXiZeroGeneratedPtSpectrum", "hAntiXiZeroGeneratedPtSpectrum", {HistType::kTH2D, {antilambdaPtAxis, centAxis}}); + rMCCorrections.add("hAntiOmegaGeneratedPtSpectrum", "hAntiOmegaGeneratedPtSpectrum", {HistType::kTH2D, {antilambdaPtAxis, centAxis}}); + rMCCorrections.add("hPhiGeneratedPtSpectrum", "hPhiGeneratedPtSpectrum", {HistType::kTH2D, {k0ShortPtAxis, centAxis}}); + } + + // Event selection function + template + bool acceptEvent(TCollision const& collision) + { + rPtAnalysis.fill(HIST("hNEvents"), 0.5); + rPtAnalysis.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "All"); + if (dosel8 && !collision.sel8()) { + return false; + } + rPtAnalysis.fill(HIST("hNEvents"), 1.5); + rPtAnalysis.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "sel 8"); + if (doNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + rPtAnalysis.fill(HIST("hNEvents"), 2.5); + rPtAnalysis.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(3, "NoTimeFrameBorder"); + if (doNoITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + rPtAnalysis.fill(HIST("hNEvents"), 3.5); + rPtAnalysis.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(4, "NoITSROFrameBorder"); + if (doIsTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + rPtAnalysis.fill(HIST("hNEvents"), 4.5); + rPtAnalysis.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(5, "IsTriggerTVX"); + if (docutZVertex && !(std::abs(collision.posZ()) < cutZVertex)) { + return false; + } + rPtAnalysis.fill(HIST("hNEvents"), 5.5); + rPtAnalysis.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(6, "cutZVertex"); + if (doisInelGt0 && !collision.isInelGt0()) { + return false; + } + rPtAnalysis.fill(HIST("hNEvents"), 6.5); + rPtAnalysis.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(7, "isInelGt0"); + // Cut Plots + rPtAnalysis.fill(HIST("hVertexZRec"), collision.posZ()); + return true; + } + + // V0 selection function + template + bool acceptV0(TV0 const& v0) + { + const auto& posDaughterTrack = v0.template posTrack_as(); // Positive Daughter track + const auto& negDaughterTrack = v0.template negTrack_as(); // Negative Daughter track + + rPtAnalysis.fill(HIST("hNV0s"), 0.5); + rPtAnalysis.get(HIST("hNV0s"))->GetXaxis()->SetBinLabel(1, "All V0s"); + if (doDaughterPseudorapidityCut && !(std::abs(posDaughterTrack.eta()) < etadau && std::abs(negDaughterTrack.eta()) < etadau)) { // Daughters Pseudorapidity Cut + return false; + } + rPtAnalysis.fill(HIST("hNV0s"), 1.5); + rPtAnalysis.get(HIST("hNV0s"))->GetXaxis()->SetBinLabel(2, "Dau Pseudorapidity"); + if (doisNotITSAfterburner && (posDaughterTrack.isITSAfterburner() || negDaughterTrack.isITSAfterburner())) { // ITS After Burner on daughter tracks + return false; + } + rPtAnalysis.fill(HIST("hNV0s"), 2.5); + rPtAnalysis.get(HIST("hNV0s"))->GetXaxis()->SetBinLabel(3, "ITS Afterburner"); + if (doitsMinHits && !(posDaughterTrack.itsNCls() >= itsMinHits && negDaughterTrack.itsNCls() >= itsMinHits)) { // Minimum hits in the ITS + return false; + } + rPtAnalysis.fill(HIST("hNV0s"), 3.5); + rPtAnalysis.get(HIST("hNV0s"))->GetXaxis()->SetBinLabel(4, "ITS Min Hits"); + // Cut Plots + rPtAnalysis.fill(HIST("hV0EtaDaughters"), v0.template posTrack_as().eta()); + rPtAnalysis.fill(HIST("hV0EtaDaughters"), v0.template negTrack_as().eta()); + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlot"), v0.alpha(), v0.qtarm()); + return true; + } + + // K0sh selection function + template + bool acceptK0sh(TV0 const& v0) + { + const auto& posDaughterTrack = v0.template posTrack_as(); // Positive Daughter track + const auto& negDaughterTrack = v0.template negTrack_as(); // Negative Daughter track + + rPtAnalysis.fill(HIST("hNK0sh"), 0.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(1, "All"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 0.5, v0.mK0Short()); + + if (doRapidityCut && (std::abs(v0.rapidity(0)) > rapidityCut)) { // V0 Rapidity Cut + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 1.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(2, "Rapidity"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 1.5, v0.mK0Short()); + if (doK0shTPCPID && (std::abs(posDaughterTrack.tpcNSigmaPi()) > nSigmaTPCPion || std::abs(negDaughterTrack.tpcNSigmaPi()) > nSigmaTPCPion)) { // TPC PID for two pions + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 2.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(3, "TPC_PID"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 2.5, v0.mK0Short()); + if (doK0shcomptmasscut && ((std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < compv0masscut) || (std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < compv0masscut))) { // Kzero competitive v0 mass cut (cut out Lambdas and Anti-Lambdas) + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 3.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(4, "Compt_Mass"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 3.5, v0.mK0Short()); + if (doK0shMaxct && (v0.v0radius() > kaonshmaxct)) { // K0sh max ct + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 4.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(5, "Max_ct"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 4.5, v0.mK0Short()); + if (doK0shArmenterosCut && (v0.qtarm() < (k0shparamArmenterosCut * std::abs(v0.alpha())))) { // K0sh Armenteros Cut + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 5.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(6, "Armenteros"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 5.5, v0.mK0Short()); + if (doK0shcosPACut && (v0.v0cosPA() < kaonshSettingcosPA)) { // K0sh cosPA Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 6.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(7, "cosPA"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 6.5, v0.mK0Short()); + if (doK0shDCAdauCut && (v0.dcaV0daughters() > kaonshSettingdcav0dau)) { // K0sh DCAdaughters Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 7.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(8, "DCAdau"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 7.5, v0.mK0Short()); + if (doK0shv0radiusCut && (v0.v0radius() < kaonshSettingradius)) { // K0sh v0radius Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 8.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(9, "v0radius"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 8.5, v0.mK0Short()); + if (doK0shdcaposdautopv && (std::abs(v0.dcapostopv()) < kaonshSettingdcapostopv)) { // K0sh DCAPosDaughterToPV Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 9.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(10, "DCAPosDautoPV"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 9.5, v0.mK0Short()); + if (doK0shdcanegdautopv && (std::abs(v0.dcanegtopv()) < kaonshSettingdcanegtopv)) { // K0sh DCANegDaughterToPV Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNK0sh"), 10.5); + rPtAnalysis.get(HIST("hNK0sh"))->GetXaxis()->SetBinLabel(11, "DCANegDautoPV"); + rPtAnalysis.fill(HIST("hMassK0ShortvsCuts"), 10.5, v0.mK0Short()); + + // Cut Plots + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlotK0sh"), v0.alpha(), v0.qtarm()); + rPtAnalysis.fill(HIST("hNSigmaPosPionFromK0s"), posDaughterTrack.tpcNSigmaPi(), posDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hNSigmaNegPionFromK0s"), negDaughterTrack.tpcNSigmaPi(), negDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hK0shcosPA"), v0.v0cosPA()); + rPtAnalysis.fill(HIST("hK0shV0radius"), v0.v0radius()); + rPtAnalysis.fill(HIST("hK0shDCAV0Daughters"), v0.dcaV0daughters()); + rPtAnalysis.fill(HIST("hK0shDCAPosDaughter"), v0.dcapostopv()); + rPtAnalysis.fill(HIST("hK0shDCANegDaughter"), v0.dcanegtopv()); + rPtAnalysis.fill(HIST("V0Rapidity"), v0.rapidity(0)); + return true; + } + + // Lambda selection function + template + bool acceptLambda(TV0 const& v0) + { + const auto& posDaughterTrack = v0.template posTrack_as(); // Positive Daughter track + const auto& negDaughterTrack = v0.template negTrack_as(); // Negative Daughter track + + rPtAnalysis.fill(HIST("hNLambda"), 0.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(1, "All"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 0.5, v0.mLambda()); + + if (doRapidityCut && (std::abs(v0.rapidity(1)) > rapidityCut)) { // V0 Rapidity Cut + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 1.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(2, "Rapidity"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 1.5, v0.mLambda()); + if (doLambdaTPCPID && ((std::abs(posDaughterTrack.tpcNSigmaPr()) > nSigmaTPCProton) || (std::abs(negDaughterTrack.tpcNSigmaPi()) > nSigmaTPCPion))) { // TPC PID on daughter pion and proton for Lambda + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 2.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(3, "TPC_PID"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 2.5, v0.mLambda()); + if (doLambdacomptmasscut && ((std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < compv0masscut) || (std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < compv0masscut))) { // Lambda competitive v0 mass cut (cut out Kaons) + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 3.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(4, "Compt_Mass"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 3.5, v0.mLambda()); + if (doLambdaMaxct && (v0.v0radius() > lambdamaxct)) { // Lambda max ct + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 4.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(5, "Max_ct"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 4.5, v0.mLambda()); + if (doLambdaArmenterosCut && v0.qtarm() < (lambdaparamArmenterosCut * std::abs(v0.alpha()))) { // Lambda Armenteros Cut + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 5.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(6, "Armenteros"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 5.5, v0.mLambda()); + if (doLambdacosPACut && (v0.v0cosPA() < lambdaSettingcosPA)) { // Lambda cosPA Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 6.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(7, "cosPA"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 6.5, v0.mLambda()); + if (doLambdaDCAdauCut && (v0.dcaV0daughters() > lambdaSettingdcav0dau)) { // Lambda DCAdaughters Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 7.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(8, "DCAdau"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 7.5, v0.mLambda()); + if (doLambdav0radiusCut && (v0.v0radius() < lambdaSettingradius)) { // Lambda v0radius Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 8.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(9, "v0radius"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 8.5, v0.mLambda()); + if (doLambdadcaposdautopv && (std::abs(v0.dcapostopv()) < lambdaSettingdcapostopv)) { // Lambda DCAPosDaughterToPV Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 9.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(10, "DCAPosDautoPV"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 9.5, v0.mLambda()); + if (doLambdadcanegdautopv && (std::abs(v0.dcanegtopv()) < lambdaSettingdcanegtopv)) { // Lambda DCANegDaughterToPV Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNLambda"), 10.5); + rPtAnalysis.get(HIST("hNLambda"))->GetXaxis()->SetBinLabel(11, "DCANegDautoPV"); + rPtAnalysis.fill(HIST("hMassLambdavsCuts"), 10.5, v0.mLambda()); + + // Cut Plots + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlotLambda"), v0.alpha(), v0.qtarm()); + rPtAnalysis.fill(HIST("hNSigmaPosProtonFromLambdas"), posDaughterTrack.tpcNSigmaPr(), posDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hNSigmaNegPionFromLambdas"), negDaughterTrack.tpcNSigmaPi(), negDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hLambdacosPA"), v0.v0cosPA()); + rPtAnalysis.fill(HIST("hLambdaV0radius"), v0.v0radius()); + rPtAnalysis.fill(HIST("hLambdaDCAV0Daughters"), v0.dcaV0daughters()); + rPtAnalysis.fill(HIST("hLambdaDCAPosDaughter"), v0.dcapostopv()); + rPtAnalysis.fill(HIST("hLambdaDCANegDaughter"), v0.dcanegtopv()); + rPtAnalysis.fill(HIST("V0Rapidity"), v0.rapidity(1)); + return true; + } + + // Antilambda selection function + template + bool acceptAntilambda(TV0 const& v0) + { + const auto& posDaughterTrack = v0.template posTrack_as(); // Positive Daughter track + const auto& negDaughterTrack = v0.template negTrack_as(); // Negative Daughter track + + rPtAnalysis.fill(HIST("hNAntilambda"), 0.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(1, "All"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 0.5, v0.mAntiLambda()); + + if (doRapidityCut && (std::abs(v0.rapidity(2)) > rapidityCut)) { // V0 Rapidity Cut + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 1.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(2, "Rapidity"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 1.5, v0.mAntiLambda()); + if (doAntilambdaTPCPID && (std::abs(negDaughterTrack.tpcNSigmaPr()) > nSigmaTPCProton || std::abs(posDaughterTrack.tpcNSigmaPi()) > nSigmaTPCPion)) { // TPC PID on daughter pion and proton for AntiLambda + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 2.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(3, "TPC_PID"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 2.5, v0.mAntiLambda()); + if (doAntilambdacomptmasscut && ((std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < compv0masscut) || (std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < compv0masscut))) { // Antilambda competitive v0 mass cut (cut out Kaons) + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 3.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(4, "Compt_Mass"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 3.5, v0.mAntiLambda()); + if (doAntilambdaMaxct && (v0.v0radius() > antilambdamaxct)) { // Antilambda max ct + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 4.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(5, "Max_ct"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 4.5, v0.mAntiLambda()); + if (doAntilambdaArmenterosCut && (v0.qtarm() < (antilambdaparamArmenterosCut * std::abs(v0.alpha())))) { // Antilambda Armenteros Cut + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 5.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(6, "Armenteros"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 5.5, v0.mAntiLambda()); + if (doAntilambdacosPACut && (v0.v0cosPA() < antilambdaSettingcosPA)) { // Antilambda cosPA Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 6.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(7, "cosPA"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 6.5, v0.mAntiLambda()); + if (doAntilambdaDCAdauCut && (v0.dcaV0daughters() > antilambdaSettingdcav0dau)) { // Antilambda DCAdaughters Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 7.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(8, "DCAdau"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 7.5, v0.mAntiLambda()); + if (doAntilambdav0radiusCut && (v0.v0radius() < antilambdaSettingradius)) { // Antilambda v0radius Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 8.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(9, "v0radius"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 8.5, v0.mAntiLambda()); + if (doAntilambdadcaposdautopv && (std::abs(v0.dcapostopv()) < antilambdaSettingdcapostopv)) { // Antilambda DCAPosDaughterToPV Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 9.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(10, "DCAPosDautoPV"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 9.5, v0.mAntiLambda()); + if (doAntilambdadcanegdautopv && (std::abs(v0.dcanegtopv()) < antilambdaSettingdcanegtopv)) { // Antilambda DCANegDaughterToPV Topological Cut + return false; + } + rPtAnalysis.fill(HIST("hNAntilambda"), 10.5); + rPtAnalysis.get(HIST("hNAntilambda"))->GetXaxis()->SetBinLabel(11, "DCANegDautoPV"); + rPtAnalysis.fill(HIST("hMassAntilambdavsCuts"), 10.5, v0.mAntiLambda()); + + // Cut plots + rPtAnalysis.fill(HIST("hArmenterosPodolanskiPlotAntilambda"), v0.alpha(), v0.qtarm()); + rPtAnalysis.fill(HIST("hNSigmaPosPionFromAntilambdas"), posDaughterTrack.tpcNSigmaPr(), posDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hNSigmaNegProtonFromAntilambdas"), negDaughterTrack.tpcNSigmaPi(), negDaughterTrack.tpcInnerParam()); + rPtAnalysis.fill(HIST("hAntilambdacosPA"), v0.v0cosPA()); + rPtAnalysis.fill(HIST("hAntilambdaV0radius"), v0.v0radius()); + rPtAnalysis.fill(HIST("hAntilambdaDCAV0Daughters"), v0.dcaV0daughters()); + rPtAnalysis.fill(HIST("hAntilambdaDCAPosDaughter"), v0.dcapostopv()); + rPtAnalysis.fill(HIST("hAntilambdaDCANegDaughter"), v0.dcanegtopv()); + rPtAnalysis.fill(HIST("V0Rapidity"), v0.rapidity(2)); + return true; + } + + // Defining the type of the daughter tracks + using DaughterTracks = soa::Join; + o2::framework::Service pdgDB; + + void genMCProcess( + soa::Join::iterator const& mcCollision, + soa::SmallGroups> const& collisions, + aod::McParticles const& mcParticles) + { + // Event Efficiency, Event Split and V0 Signal Loss Corrections + rMCCorrections.fill(HIST("hNEvents_Corrections"), 0.5); // Event Efficiency Denominator + if (std::abs(mcCollision.posZ()) > cutZVertex) { + return; + } + if (!pwglf::isINELgtNmc(mcParticles, 0, pdgDB)) { + return; + } + // Particles (of interest) Generated Pt Spectrum and Signal Loss Denominator Loop + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.y()) < rapidityCut) { + if (mcParticle.isPhysicalPrimary()) { + rMCCorrections.fill(HIST("GenParticleRapidity"), mcParticle.y()); + if (mcParticle.pdgCode() == kK0Short) // kzero matched + { + rMCCorrections.fill(HIST("hK0ShGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kLambda0) // lambda matched + { + rMCCorrections.fill(HIST("hLambdaGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kLambda0Bar) // antilambda matched + { + rMCCorrections.fill(HIST("hAntilambdaGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kXiMinus) // Xi Minus matched + { + rMCCorrections.fill(HIST("hXiMinusGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kXi0) // Xi Zero matched + { + rMCCorrections.fill(HIST("hXiZeroGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kOmegaMinus) // Omega matched + { + rMCCorrections.fill(HIST("hOmegaGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kXiPlusBar) // Xi Plus matched + { + rMCCorrections.fill(HIST("hXiPlusGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == -kXi0) // Anti-Xi Zero matched + { + rMCCorrections.fill(HIST("hAntiXiZeroGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kOmegaPlusBar) // Anti-Omega matched + { + rMCCorrections.fill(HIST("hAntiOmegaGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kPhi) // Phi + { + rMCCorrections.fill(HIST("hPhiGeneratedPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + } + } + } + // Signal Loss Numenator Loop + for (const auto& collision : collisions) { + rMCCorrections.fill(HIST("hNEvents_Corrections"), 1.5); // Number of Events Reconsctructed + if (!acceptEvent(collision)) { // Event Selection + return; + } + rMCCorrections.fill(HIST("hNEvents_Corrections"), 2.5); // Event Split Denomimator and Event Efficiency Numenator + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + if (std::abs(mcParticle.y()) > rapidityCut) { + continue; + } + if (mcParticle.pdgCode() == kK0Short) // kzero matched + { + rMCCorrections.fill(HIST("hK0ShAfterEventSelectionPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kLambda0) // lambda matched + { + rMCCorrections.fill(HIST("hLambdaAfterEventSelectionPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + if (mcParticle.pdgCode() == kLambda0Bar) // antilambda matched + { + rMCCorrections.fill(HIST("hAntilambdaAfterEventSelectionPtSpectrum"), mcParticle.pt(), mcCollision.centFT0M()); + } + } + } + // End of Signal Loss Numenator Loop + } + // This is the Process for the MC reconstructed Data + void recMCProcess(soa::Join::iterator const& collision, + // soa::Join const& /*mcCollisions*/, + soa::Join const& V0s, + DaughterTracks const&, // no need to define a variable for tracks, if we don't access them directly + aod::McParticles const& /*mcParticles*/) + { + // 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, ','); + pthistos::kaonPtBins = o2::utils::Str::tokenize(kzeroSettingPtBinsString, ','); + + // Calculate number of histograms for each particle type + int nKaonHistograms = pthistos::kaonPtBins.size() - 1; + int nLambdaHistograms = pthistos::lambdaPtBins.size() - 1; + int nAntilambdaHistograms = pthistos::antilambdaPtBins.size() - 1; + + // initialize and convert tokenized strings into vector of doubles for Pt Bin Edges + std::vector kaonptedgevalues(nKaonHistograms + 1); + std::vector lambdaptedgevalues(nLambdaHistograms + 1); + std::vector antilambdaPtedgevalues(nAntilambdaHistograms + 1); + + for (int i = 0; i < nKaonHistograms + 1; i++) { + kaonptedgevalues[i] = std::stod(pthistos::kaonPtBins[i]); + } + for (int i = 0; i < nLambdaHistograms + 1; i++) { + lambdaptedgevalues[i] = std::stod(pthistos::lambdaPtBins[i]); + } + for (int i = 0; i < nAntilambdaHistograms + 1; i++) { + antilambdaPtedgevalues[i] = std::stod(pthistos::antilambdaPtBins[i]); + } + if (!acceptEvent(collision)) { // Event Selection + return; + } + rMCCorrections.fill(HIST("hNRecEvents_MC"), 0.5); // Event Split Numenator + + // if (collision.has_mcCollision()) + { + + // const auto& mcCollision = collision.mcCollision_as>(); + + // std::cout<<"Measured: "<Fill(v0.mK0Short(), collision.centFT0M()); // filling the k0s namespace histograms for K0sh Splitting Numerator + } + } + // K0sh Signla Split Numerator End + if (v0.has_mcParticle()) { + auto v0mcParticle = v0.mcParticle(); + if (dotruthk0sh && (v0mcParticle.pdgCode() == kK0Short)) { // kzero matched + if (v0mcParticle.isPhysicalPrimary()) { + for (int i = 0; i < nKaonHistograms; 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(), collision.centFT0M()); // filling the k0s namespace histograms + } + } + } + if (!v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); // Get mothers + if (!v0mothers.empty()) { + auto& v0mcParticleMother = v0mothers.front(); // First mother + rFeeddownMatrices.fill(HIST("hK0shFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + if (v0mcParticleMother.pdgCode() == kPhi) { // Phi Mother Matched + rFeeddownMatrices.fill(HIST("hK0shPhiFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + } + } + } + } + } + } + } + // lambda analysis + if (lambdaAnalysis == true) { + if (acceptLambda(v0)) { // Lambda Selections + // Lambda Signal Split Numerator Start + for (int i = 0; i < nLambdaHistograms; i++) { + if (lambdaptedgevalues[i] <= v0.pt() && v0.pt() < lambdaptedgevalues[i + 1]) { + pthistos::lambdaSplit[i]->Fill(v0.mLambda(), collision.centFT0M()); + } + } + // Lambda Signal Split Numerator End + if (v0.has_mcParticle()) { + auto v0mcParticle = v0.mcParticle(); + if (dotruthLambda && (v0mcParticle.pdgCode() == kLambda0)) { // lambda matched + if (v0mcParticle.isPhysicalPrimary()) { + for (int i = 0; i < nLambdaHistograms; i++) { + if (lambdaptedgevalues[i] <= v0.pt() && v0.pt() < lambdaptedgevalues[i + 1]) { + pthistos::lambdaPt[i]->Fill(v0.mLambda(), collision.centFT0M()); + } + } + } + if (!v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); // Get mothers + if (!v0mothers.empty()) { + auto& v0mcParticleMother = v0mothers.front(); // First mother + rFeeddownMatrices.fill(HIST("hLambdaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + if (v0mcParticleMother.pdgCode() == kXiMinus) { // Xi Minus Mother Matched + rFeeddownMatrices.fill(HIST("hLambdaXiMinusFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + } + if (v0mcParticleMother.pdgCode() == kXi0) { // Xi Zero Mother Matched + rFeeddownMatrices.fill(HIST("hLambdaXiZeroFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + } + if (v0mcParticleMother.pdgCode() == kOmegaMinus) { // Omega Mother Matched + rFeeddownMatrices.fill(HIST("hLambdaOmegaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + } + } + } + } + } + } + } + // antilambda analysis + if (antiLambdaAnalysis == true) { + if (acceptAntilambda(v0)) { // Antilambda Selections + // Antilambda Signal Split Numerator End + for (int i = 0; i < nAntilambdaHistograms; i++) { + if (antilambdaPtedgevalues[i] <= v0.pt() && v0.pt() < antilambdaPtedgevalues[i + 1]) { + pthistos::antilambdaSplit[i]->Fill(v0.mAntiLambda(), collision.centFT0M()); + } + } + // Antilambda Signal Split Numerator End + if (v0.has_mcParticle()) { + auto v0mcParticle = v0.mcParticle(); + if (dotruthAntilambda && (v0mcParticle.pdgCode() == kLambda0Bar)) { // antilambda matched + if (v0mcParticle.isPhysicalPrimary()) { + for (int i = 0; i < nAntilambdaHistograms; i++) { + if (antilambdaPtedgevalues[i] <= v0.pt() && v0.pt() < antilambdaPtedgevalues[i + 1]) { + pthistos::antilambdaPt[i]->Fill(v0.mAntiLambda(), collision.centFT0M()); + } + } + } + if (!v0mcParticle.isPhysicalPrimary()) { + auto v0mothers = v0mcParticle.mothers_as(); // Get mothers + if (!v0mothers.empty()) { + auto& v0mcParticleMother = v0mothers.front(); // First mother + rFeeddownMatrices.fill(HIST("hAntiLambdaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + if (v0mcParticleMother.pdgCode() == kXiPlusBar) { // Xi Plus Mother Matched + rFeeddownMatrices.fill(HIST("hAntiLambdaXiPlusFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + } + if (v0mcParticleMother.pdgCode() == -kXi0) { // Anti-Xi Zero Mother Matched + rFeeddownMatrices.fill(HIST("hAntiLambdaAntiXiZeroFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + } + if (v0mcParticleMother.pdgCode() == kOmegaPlusBar) { // Anti-Omega (minus) Mother Matched + rFeeddownMatrices.fill(HIST("hAntiLambdaAntiOmegaFeeddownMatrix"), v0mcParticle.pt(), v0mcParticleMother.pt(), collision.centFT0M()); + } + } + } + } + } + } + } + } + } + } + // This is the process for Real Data + void dataProcess(soa::Join::iterator const& collision, + aod::V0Datas const& V0s, + DaughterTracks const&) + { + // 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, ','); + pthistos::kaonPtBins = o2::utils::Str::tokenize(kzeroSettingPtBinsString, ','); + + // Calculate number of histograms for each particle type + int nKaonHistograms = pthistos::kaonPtBins.size() - 1; + int nLambdaHistograms = pthistos::lambdaPtBins.size() - 1; + int nAntilambdaHistograms = pthistos::antilambdaPtBins.size() - 1; + + // initialize and convert tokenized strings into vector of doubles for Pt Bin Edges + std::vector kaonptedgevalues(nKaonHistograms + 1); + std::vector lambdaptedgevalues(nLambdaHistograms + 1); + std::vector antilambdaPtedgevalues(nAntilambdaHistograms + 1); + + for (int i = 0; i < nKaonHistograms + 1; i++) { + kaonptedgevalues[i] = std::stod(pthistos::kaonPtBins[i]); + } + for (int i = 0; i < nLambdaHistograms + 1; i++) { + lambdaptedgevalues[i] = std::stod(pthistos::lambdaPtBins[i]); + } + for (int i = 0; i < nAntilambdaHistograms + 1; i++) { + antilambdaPtedgevalues[i] = std::stod(pthistos::antilambdaPtBins[i]); + } + + if (!acceptEvent(collision)) { // Event Selection + return; + } + rPtAnalysis.fill(HIST("hNRecEvents_Data"), 0.5); // Number of Reconstructed Events + + for (const auto& v0 : V0s) { + // 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 (!acceptV0(v0)) { // V0 Selection + continue; + } + // kzero analysis + if (kzeroAnalysis == true) { + if (acceptK0sh(v0)) { // K0sh Selection + for (int i = 0; i < nKaonHistograms; 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(), collision.centFT0M()); // filling the k0s namespace histograms + } + } + } + } + // lambda analysis + if (lambdaAnalysis == true) { + if (acceptLambda(v0)) { // Lambda Selection + for (int i = 0; i < nLambdaHistograms; i++) { + if (lambdaptedgevalues[i] <= v0.pt() && v0.pt() < lambdaptedgevalues[i + 1]) { + pthistos::lambdaPt[i]->Fill(v0.mLambda(), collision.centFT0M()); + } + } + } + } + // anti-lambda analysis + if (antiLambdaAnalysis == true) { + if (acceptAntilambda(v0)) { // Antilambda Selection + for (int i = 0; i < nAntilambdaHistograms; i++) { + if (lambdaptedgevalues[i] <= v0.pt() && v0.pt() < lambdaptedgevalues[i + 1]) { + pthistos::antilambdaPt[i]->Fill(v0.mAntiLambda(), collision.centFT0M()); + } + } + } + } + } + } + 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,", false); + // PROCESS_SWITCH(V0PtInvMassPlots, genMCProcessDerived, "Process Run 3 MC Generated", false); + // PROCESS_SWITCH(V0PtInvMassPlots, recMCProcessDerived, "Process Run 3 MC Reconstructed", false); + // PROCESS_SWITCH(V0PtInvMassPlots, dataProcessDerived, "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 index 4a2c8b18d91..72dd56799e2 100644 --- a/PWGLF/Tasks/Strangeness/v0topologicalcuts.cxx +++ b/PWGLF/Tasks/Strangeness/v0topologicalcuts.cxx @@ -9,29 +9,37 @@ // 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, +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 "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Common/DataModel/EventSelection.h" #include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Common/DataModel/PIDResponse.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include "CommonUtils/StringUtils.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include // 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 cosPACut[20]; +static std::vector cosPAcuts; std::shared_ptr dcaCut[20]; static std::vector dcacuts; std::shared_ptr v0radiusCut[20]; @@ -43,8 +51,8 @@ static std::vector dcanegtopvcuts; } // namespace cuthistoskzerosh namespace cuthistoslambda { -std::shared_ptr cospaCut[20]; -static std::vector cospacuts; +std::shared_ptr cosPACut[20]; +static std::vector cosPAcuts; std::shared_ptr dcaCut[20]; static std::vector dcacuts; std::shared_ptr v0radiusCut[20]; @@ -56,8 +64,8 @@ static std::vector dcanegtopvcuts; } // namespace cuthistoslambda namespace cuthistosantilambda { -std::shared_ptr cospaCut[20]; -static std::vector cospacuts; +std::shared_ptr cosPACut[20]; +static std::vector cosPAcuts; std::shared_ptr dcaCut[20]; static std::vector dcacuts; std::shared_ptr v0radiusCut[20]; @@ -73,596 +81,604 @@ using namespace o2::framework::expressions; struct v0topologicalcuts { // Histogram Registry includes different V0 Parameteres for all V0s and individual MC-V0s with MC-matching - HistogramRegistry rV0Parameters_MC_V0match{"V0Parameters_MC_V0Match", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rV0Parameters_MC_K0Smatch{"V0Parameters_MC_K0SMatch", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rV0Parameters_MC_Lambdamatch{"V0Parameters_MC_LambdaMatch", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rV0Parameters_MC_AntiLambdamatch{"V0Parameters_MC_AntiLambdaMatch", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rV0Parameters_Data{"rV0Parameters_Data", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - + 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 rKzeroShort_cospaCut{"KzeroShort_cospaCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rKzeroShort_dcaCut{"KzeroShort_dcaCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rKzeroShort_v0radiusCut{"KzeroShort_v0radiusCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rKzeroShort_dcapostopCut{"KzeroShort_dcapostopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rKzeroShort_dcanegtopCut{"KzeroShort_dcanegtopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - + 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 rLambda_cospaCut{"Lambda_cospaCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rLambda_dcaCut{"Lambda_dcaCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rLambda_v0radiusCut{"Lambda_v0radiusCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rLambda_dcapostopCut{"Lambda_dcapostopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rLambda_dcanegtopCut{"Lambda_dcanegtopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - + 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 rAntiLambda_cospaCut{"AntiLambda_cospaCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rAntiLambda_dcaCut{"AntiLambda_dcaCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rAntiLambda_v0radiusCut{"AntiLambda_v0radiusCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rAntiLambda_dcapostopCut{"AntiLambda_dcapostopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - HistogramRegistry rAntiLambda_dcanegtopCut{"AntiLambda_dcanegtopvCuts", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + 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 kzeroshsetting_cospacuts_string{"kzerosetting_cospacuts", {"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 kzeroshsetting_dcacuts_string{"kzerosetting_dcacuts", {"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 kzeroshsetting_v0radius_string{"kzerosetting_v0radiuscuts", {"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 kzeroshsetting_dcapostopv_string{"kzerosetting_dcapostopvcuts", {"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 kzeroshsetting_dcanegtopv_string{"kzerosetting_dcanegtopvcuts", {"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 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 lambdasetting_cospacuts_string{"lambdasetting_cospacuts", {"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"}, "Lambda cosPA Cut Values"}; - Configurable lambdasetting_dcacuts_string{"lambdasetting_dcacuts", {"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 lambdasetting_v0radius_string{"lambdasetting_v0radiuscuts", {"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 lambdasetting_dcapostopv_string{"lambdasetting_dcapostopvcuts", {"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 lambdasetting_dcanegtopv_string{"lambdasetting_dcanegtopvcuts", {"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 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 antilambdasetting_cospacuts_string{"antilambdasetting_cospacuts", {"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 antilambdasetting_dcacuts_string{"antilambdasetting_dcacuts", {"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 antilambdasetting_v0radius_string{"antilambdasetting_v0radiuscuts", {"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 antilambdasetting_dcapostopv_string{"antilambdasetting_dcapostopvcuts", {"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 antilambdasetting_dcanegtopv_string{"antilambdasetting_dcanegtopvcuts", {"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"}; + 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 - size_t commapos = 0; - std::string token1; - std::string kzeroshsetting_cospacuts = kzeroshsetting_cospacuts_string; - std::string kzeroshsetting_dcacuts = kzeroshsetting_dcacuts_string; - std::string kzeroshsetting_v0radiuscuts = kzeroshsetting_v0radius_string; - std::string kzeroshsetting_dcapostopvcuts = kzeroshsetting_dcapostopv_string; - std::string kzeroshsetting_dcanegtopvcuts = kzeroshsetting_dcanegtopv_string; - + // 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 - for (int i = 0; i < 20; i++) { - commapos = kzeroshsetting_cospacuts.find(","); // find comma that separates the values in the string - token1 = kzeroshsetting_cospacuts.substr(0, commapos); // store the substring (first individual value) - cuthistoskzerosh::cospacuts.push_back(token1); // fill the namespace with the value - kzeroshsetting_cospacuts.erase(0, commapos + 1); // erase the value from the set string so it moves to the next - } - for (int i = 0; i < 20; i++) { - commapos = kzeroshsetting_dcacuts.find(","); - token1 = kzeroshsetting_dcacuts.substr(0, commapos); - cuthistoskzerosh::dcacuts.push_back(token1); - kzeroshsetting_dcacuts.erase(0, commapos + 1); - } - for (int i = 0; i < 20; i++) { - commapos = kzeroshsetting_v0radiuscuts.find(","); - token1 = kzeroshsetting_v0radiuscuts.substr(0, commapos); - cuthistoskzerosh::v0radiuscuts.push_back(token1); - kzeroshsetting_v0radiuscuts.erase(0, commapos + 1); - } - for (int i = 0; i < 20; i++) { - commapos = kzeroshsetting_dcapostopvcuts.find(","); - token1 = kzeroshsetting_dcapostopvcuts.substr(0, commapos); - cuthistoskzerosh::dcapostopvcuts.push_back(token1); - kzeroshsetting_dcapostopvcuts.erase(0, commapos + 1); - } - for (int i = 0; i < 20; i++) { - commapos = kzeroshsetting_dcanegtopvcuts.find(","); - token1 = kzeroshsetting_dcanegtopvcuts.substr(0, commapos); - cuthistoskzerosh::dcanegtopvcuts.push_back(token1); - kzeroshsetting_dcanegtopvcuts.erase(0, commapos + 1); - } + 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) - std::string lambdasetting_cospacuts = lambdasetting_cospacuts_string; - std::string lambdasetting_dcacuts = lambdasetting_dcacuts_string; - std::string lambdasetting_v0radiuscuts = lambdasetting_v0radius_string; - std::string lambdasetting_dcapostopvcuts = lambdasetting_dcapostopv_string; - std::string lambdasetting_dcanegtopvcuts = lambdasetting_dcanegtopv_string; - - for (int i = 0; i < 20; i++) { - commapos = lambdasetting_cospacuts.find(","); - token1 = lambdasetting_cospacuts.substr(0, commapos); - cuthistoslambda::cospacuts.push_back(token1); - lambdasetting_cospacuts.erase(0, commapos + 1); + 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 (int i = 0; i < 20; i++) { - commapos = lambdasetting_dcacuts.find(","); - token1 = lambdasetting_dcacuts.substr(0, commapos); - cuthistoslambda::dcacuts.push_back(token1); - lambdasetting_dcacuts.erase(0, commapos + 1); + 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 (int i = 0; i < 20; i++) { - commapos = lambdasetting_v0radiuscuts.find(","); - token1 = lambdasetting_v0radiuscuts.substr(0, commapos); - cuthistoslambda::v0radiuscuts.push_back(token1); - lambdasetting_v0radiuscuts.erase(0, commapos + 1); + 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 (int i = 0; i < 20; i++) { - commapos = lambdasetting_dcapostopvcuts.find(","); - token1 = lambdasetting_dcapostopvcuts.substr(0, commapos); - cuthistoslambda::dcapostopvcuts.push_back(token1); - lambdasetting_dcapostopvcuts.erase(0, commapos + 1); + 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 (int i = 0; i < 20; i++) { - commapos = lambdasetting_dcanegtopvcuts.find(","); - token1 = lambdasetting_dcanegtopvcuts.substr(0, commapos); - cuthistoslambda::dcanegtopvcuts.push_back(token1); - lambdasetting_dcanegtopvcuts.erase(0, commapos + 1); + 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}}}); } - // antilambda filling namespace with configurable strings (same as in Lambdas and Kzeros above) - std::string antilambdasetting_cospacuts = antilambdasetting_cospacuts_string; - std::string antilambdasetting_dcacuts = antilambdasetting_dcacuts_string; - std::string antilambdasetting_v0radiuscuts = antilambdasetting_v0radius_string; - std::string antilambdasetting_dcapostopvcuts = antilambdasetting_dcapostopv_string; - std::string antilambdasetting_dcanegtopvcuts = antilambdasetting_dcanegtopv_string; - - for (int i = 0; i < 20; i++) { - commapos = antilambdasetting_cospacuts.find(","); - token1 = antilambdasetting_cospacuts.substr(0, commapos); - cuthistosantilambda::cospacuts.push_back(token1); - antilambdasetting_cospacuts.erase(0, commapos + 1); + 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 (int i = 0; i < 20; i++) { - commapos = antilambdasetting_dcacuts.find(","); - token1 = antilambdasetting_dcacuts.substr(0, commapos); - cuthistosantilambda::dcacuts.push_back(token1); - antilambdasetting_dcacuts.erase(0, commapos + 1); + 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 (int i = 0; i < 20; i++) { - commapos = antilambdasetting_v0radiuscuts.find(","); - token1 = antilambdasetting_v0radiuscuts.substr(0, commapos); - cuthistosantilambda::v0radiuscuts.push_back(token1); - antilambdasetting_v0radiuscuts.erase(0, commapos + 1); + 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 (int i = 0; i < 20; i++) { - commapos = antilambdasetting_dcapostopvcuts.find(","); - token1 = antilambdasetting_dcapostopvcuts.substr(0, commapos); - cuthistosantilambda::dcapostopvcuts.push_back(token1); - antilambdasetting_dcapostopvcuts.erase(0, commapos + 1); + 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 (int i = 0; i < 20; i++) { - commapos = antilambdasetting_dcanegtopvcuts.find(","); - token1 = antilambdasetting_dcanegtopvcuts.substr(0, commapos); - cuthistosantilambda::dcanegtopvcuts.push_back(token1); - antilambdasetting_dcanegtopvcuts.erase(0, commapos + 1); + 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}}}); } - // Axes for the three invariant mass plots - AxisSpec K0ShortMassAxis = {nBins, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - AxisSpec LambdaMassAxis = {nBins, 1.085f, 1.145f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - AxisSpec AntiLambdaMassAxis = {nBins, 1.085f, 1.145f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - - // adding the invariant mass histograms to their Registries using the namespace for kzeros, lambdas and antilambdas - for (int i = 0; i < 20; i++) { - cuthistoskzerosh::cospaCut[i] = rKzeroShort_cospaCut.add(fmt::format("hKzerocospaCut_{}", cuthistoskzerosh::cospacuts[i]).data(), fmt::format("hKzerocospaCut_{}", cuthistoskzerosh::cospacuts[i]).data(), {HistType::kTH1D, {{K0ShortMassAxis}}}); - cuthistoskzerosh::dcaCut[i] = rKzeroShort_dcaCut.add(fmt::format("hKzerodcaCut_{}", cuthistoskzerosh::dcacuts[i]).data(), fmt::format("hKzerodcaCut_{}", cuthistoskzerosh::dcacuts[i]).data(), {HistType::kTH1D, {{K0ShortMassAxis}}}); - cuthistoskzerosh::v0radiusCut[i] = rKzeroShort_v0radiusCut.add(fmt::format("hKzerov0radiusCut_{}", cuthistoskzerosh::v0radiuscuts[i]).data(), fmt::format("hKzerov0radiusCuts_{}", cuthistoskzerosh::v0radiuscuts[i]).data(), {HistType::kTH1D, {{K0ShortMassAxis}}}); - cuthistoskzerosh::dcapostopCut[i] = rKzeroShort_dcapostopCut.add(fmt::format("hKzerodcapostopCut_{}", cuthistoskzerosh::dcapostopvcuts[i]).data(), fmt::format("hKzerodcapostopCut_{}", cuthistoskzerosh::dcapostopvcuts[i]).data(), {HistType::kTH1D, {{K0ShortMassAxis}}}); - cuthistoskzerosh::dcanegtopCut[i] = rKzeroShort_dcanegtopCut.add(fmt::format("hKzerodcanegtopCut_{}", cuthistoskzerosh::dcanegtopvcuts[i]).data(), fmt::format("hKzerodcanegtopCut_{}", cuthistoskzerosh::dcanegtopvcuts[i]).data(), {HistType::kTH1D, {{K0ShortMassAxis}}}); + 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 (int i = 0; i < 20; i++) { - cuthistoslambda::cospaCut[i] = rLambda_cospaCut.add(fmt::format("hLambdacospaCut_{}", cuthistoslambda::cospacuts[i]).data(), fmt::format("hLambdacospaCut_{}", cuthistoslambda::cospacuts[i]).data(), {HistType::kTH1D, {{LambdaMassAxis}}}); - cuthistoslambda::dcaCut[i] = rLambda_dcaCut.add(fmt::format("hLambdadcaCut_{}", cuthistoslambda::dcacuts[i]).data(), fmt::format("hLambdadcaCut_{}", cuthistoslambda::dcacuts[i]).data(), {HistType::kTH1D, {{LambdaMassAxis}}}); - cuthistoslambda::v0radiusCut[i] = rLambda_v0radiusCut.add(fmt::format("hLambdav0radiusCut_{}", cuthistoslambda::v0radiuscuts[i]).data(), fmt::format("hLambdav0radiusCuts_{}", cuthistoslambda::v0radiuscuts[i]).data(), {HistType::kTH1D, {{LambdaMassAxis}}}); - cuthistoslambda::dcapostopCut[i] = rLambda_dcapostopCut.add(fmt::format("hLambdadcapostopCut_{}", cuthistoslambda::dcapostopvcuts[i]).data(), fmt::format("hLambdadcapostopCut_{}", cuthistoslambda::dcapostopvcuts[i]).data(), {HistType::kTH1D, {{LambdaMassAxis}}}); - cuthistoslambda::dcanegtopCut[i] = rLambda_dcanegtopCut.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::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 (int i = 0; i < 20; i++) { - cuthistosantilambda::cospaCut[i] = rAntiLambda_cospaCut.add(fmt::format("hAntiLambdacospaCut_{}", cuthistosantilambda::cospacuts[i]).data(), fmt::format("hAntiLambdacospaCut_{}", cuthistosantilambda::cospacuts[i]).data(), {HistType::kTH1D, {{AntiLambdaMassAxis}}}); - cuthistosantilambda::dcaCut[i] = rAntiLambda_dcaCut.add(fmt::format("hAntiLambdadcaCut_{}", cuthistosantilambda::dcacuts[i]).data(), fmt::format("hAntiLambdadcaCut_{}", cuthistosantilambda::dcacuts[i]).data(), {HistType::kTH1D, {{AntiLambdaMassAxis}}}); - cuthistosantilambda::v0radiusCut[i] = rAntiLambda_v0radiusCut.add(fmt::format("hAntiLambdav0radiusCut_{}", cuthistosantilambda::v0radiuscuts[i]).data(), fmt::format("hAntiLambdav0radiusCuts_{}", cuthistosantilambda::v0radiuscuts[i]).data(), {HistType::kTH1D, {{AntiLambdaMassAxis}}}); - cuthistosantilambda::dcapostopCut[i] = rAntiLambda_dcapostopCut.add(fmt::format("hAntiLambdadcapostopCut_{}", cuthistosantilambda::dcapostopvcuts[i]).data(), fmt::format("hAntiLambdadcapostopCut_{}", cuthistosantilambda::dcapostopvcuts[i]).data(), {HistType::kTH1D, {{AntiLambdaMassAxis}}}); - cuthistosantilambda::dcanegtopCut[i] = rAntiLambda_dcanegtopCut.add(fmt::format("hAntiLambdadcanegtopCut_{}", cuthistosantilambda::dcanegtopvcuts[i]).data(), fmt::format("hAntiLambdadcanegtopCut_{}", cuthistosantilambda::dcanegtopvcuts[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/PID cut histograms added and MC-matched - rV0Parameters_MC_V0match.add("hDCAV0Daughters_V0_Match", "hDCAV0Daughters_No_Match", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); - rV0Parameters_MC_V0match.add("hV0CosPA_V0_Match", "hV0CosPA_No_Match", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); - rV0Parameters_MC_V0match.add("hV0Radius_V0_Match", "hV0Radius_No_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); - rV0Parameters_MC_V0match.add("hV0Radius_V0_Match_Full", "hV0Radius_No_Match_Full", {HistType::kTH1F, {{nBins, 0.0f, 40.0f}}}); - rV0Parameters_MC_V0match.add("hDCAPostoPV_V0_Match", "hDCAPostoPV_No_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); - rV0Parameters_MC_V0match.add("hDCANegtoPV_V0_Match", "hDCANegtoPV_No_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); + // 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 - rV0Parameters_MC_K0Smatch.add("hDCAV0Daughters_KzeroMC_Match", "hDCAV0Daughters_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); - rV0Parameters_MC_K0Smatch.add("hV0CosPA_KzeroMC_Match", "hV0CosPA_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); - rV0Parameters_MC_K0Smatch.add("hV0Radius_KzeroMC_Match", "hV0Radius_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.2f, 5.0f}}}); - rV0Parameters_MC_K0Smatch.add("hDCAPostoPV_KzeroMC_Match", "hDCAPostoPV_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); - rV0Parameters_MC_K0Smatch.add("hDCANegtoPV_KzeroMC_Match", "hDCANegtoPV_KzeroMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); + 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 - rV0Parameters_MC_Lambdamatch.add("hDCAV0Daughters_LambdaMC_Match", "hDCAV0Daughters_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); - rV0Parameters_MC_Lambdamatch.add("hV0CosPA_LambdaMC_Match", "hV0CosPA_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); - rV0Parameters_MC_Lambdamatch.add("hV0Radius_LambdaMC_Match", "hV0Radius_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.2f, 5.0f}}}); - rV0Parameters_MC_Lambdamatch.add("hDCAPostoPV_LambdaMC_Match", "hDCAPostoPV_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); - rV0Parameters_MC_Lambdamatch.add("hDCANegtoPV_LambdaMC_Match", "hDCANegtoPV_LambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); + 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 - rV0Parameters_MC_AntiLambdamatch.add("hDCAV0Daughters_AntiLambdaMC_Match", "hDCAV0Daughters_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); - rV0Parameters_MC_AntiLambdamatch.add("hV0CosPA_AntiLambdaMC_Match", "hV0CosPA_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); - rV0Parameters_MC_AntiLambdamatch.add("hV0Radius_AntiLambdaMC_Match", "hV0Radius_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.2f, 5.0f}}}); - rV0Parameters_MC_AntiLambdamatch.add("hDCAPostoPV_AntiLambdaMC_Match", "hDCANegtoPV_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); - rV0Parameters_MC_AntiLambdamatch.add("hDCANegtoPV_AntiLambdaMC_Match", "hDCANegtoPV_AntiLambdaMC_Match", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); + 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 - rV0Parameters_Data.add("hDCAV0Daughters_V0_Data", "hDCAV0Daughters_V0_Data", {HistType::kTH1F, {{nBins, 0.0f, 1.2f}}}); - rV0Parameters_Data.add("hV0CosPA_V0_Data", "hV0CosPA_V0_Data", {HistType::kTH1F, {{nBins, 0.95f, 1.f}}}); - rV0Parameters_Data.add("hV0Radius_V0_Data", "hV0Radius_V0_Data", {HistType::kTH1F, {{nBins, 0.2f, 5.0f}}}); - rV0Parameters_Data.add("hDCAPostoPV_V0_Data", "hDCAPostoPV_V0_Data", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); - rV0Parameters_Data.add("hDCANegtoPV_V0_Data", "hDCANegtoPV_V0_Data", {HistType::kTH1F, {{nBins, 0.0f, 5.0f}}}); - rV0Parameters_Data.add("hMassK0ShortNoCuts_V0_Data", "hMassK0ShortNoCuts_V0_Data", {HistType::kTH1F, {{K0ShortMassAxis}}}); - rV0Parameters_Data.add("hMassLambdaNoCuts_V0_Data", "hMassLambdaNoCuts_V0_Data", {HistType::kTH1F, {{LambdaMassAxis}}}); - rV0Parameters_Data.add("hMassAntilambdaNoCuts_V0_Data", "hMassAntilambdaNoCuts_V0_Data", {HistType::kTH1F, {{AntiLambdaMassAxis}}}); + 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; + using DaughterTracks = soa::Join; // This is the Process for the MC reconstructed Data - void RecMCprocess(soa::Filtered>::iterator const&, + 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) { - - // filling histograms with V0 values - rV0Parameters_MC_V0match.fill(HIST("hDCAV0Daughters_V0_Match"), v0.dcaV0daughters()); - rV0Parameters_MC_V0match.fill(HIST("hV0CosPA_V0_Match"), v0.v0cosPA()); - rV0Parameters_MC_V0match.fill(HIST("hV0Radius_V0_Match"), v0.v0radius()); - rV0Parameters_MC_V0match.fill(HIST("hV0Radius_V0_Match_Full"), v0.v0radius()); - rV0Parameters_MC_V0match.fill(HIST("hDCAPostoPV_V0_Match"), v0.dcapostopv()); - rV0Parameters_MC_V0match.fill(HIST("hDCANegtoPV_V0_Match"), v0.dcanegtopv()); - - // 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 - - rV0Parameters_MC_K0Smatch.fill(HIST("hDCAV0Daughters_KzeroMC_Match"), v0.dcaV0daughters()); - rV0Parameters_MC_K0Smatch.fill(HIST("hV0CosPA_KzeroMC_Match"), v0.v0cosPA()); - rV0Parameters_MC_K0Smatch.fill(HIST("hV0Radius_KzeroMC_Match"), v0.v0radius()); - rV0Parameters_MC_K0Smatch.fill(HIST("hDCAPostoPV_KzeroMC_Match"), v0.dcapostopv()); - rV0Parameters_MC_K0Smatch.fill(HIST("hDCANegtoPV_KzeroMC_Match"), v0.dcanegtopv()); - - for (int j = 0; j < 20; 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) + 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()); + } + } } } - for (int j = 0; j < 20; 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()); + 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()); + } + } } } - for (int j = 0; j < 20; 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()); + 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()); + } + } } } - for (int j = 0; j < 20; j++) { - std::string dcapostopcut = cuthistoskzerosh::dcapostopvcuts[j]; - size_t pos = dcapostopcut.find("_"); - dcapostopcut[pos] = '.'; - const float dcapostopcutvalue = std::stod(dcapostopcut); - if (v0.dcapostopv() > dcapostopcutvalue) { - cuthistoskzerosh::dcapostopCut[j]->Fill(v0.mK0Short()); + } + } + } + } + // 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 (int j = 0; j < 20; j++) { - std::string dcanegtopcut = cuthistoskzerosh::dcanegtopvcuts[j]; - size_t pos = dcanegtopcut.find("_"); - dcanegtopcut[pos] = '.'; - const float dcanegtopcutvalue = std::stod(dcanegtopcut); - if (v0.dcanegtopv() > dcanegtopcutvalue) { - cuthistoskzerosh::dcanegtopCut[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 (v0mcParticle.pdgCode() == 3122) { // lambda matched - rV0Parameters_MC_Lambdamatch.fill(HIST("hDCAV0Daughters_LambdaMC_Match"), v0.dcaV0daughters()); - rV0Parameters_MC_Lambdamatch.fill(HIST("hV0CosPA_LambdaMC_Match"), v0.v0cosPA()); - rV0Parameters_MC_Lambdamatch.fill(HIST("hV0Radius_LambdaMC_Match"), v0.v0radius()); - rV0Parameters_MC_Lambdamatch.fill(HIST("hDCAPostoPV_LambdaMC_Match"), v0.dcapostopv()); - rV0Parameters_MC_Lambdamatch.fill(HIST("hDCANegtoPV_LambdaMC_Match"), v0.dcanegtopv()); - - // for explanation look at the first Kzero plot above - for (int j = 0; j < 20; 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()); + 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 (int j = 0; j < 20; 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::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 (int j = 0; j < 20; 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::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 (int j = 0; j < 20; j++) { - std::string dcapostopcutlambda = cuthistoslambda::dcapostopvcuts[j]; - size_t pos = dcapostopcutlambda.find("_"); - dcapostopcutlambda[pos] = '.'; - const float dcapostopcutlambdavalue = std::stod(dcapostopcutlambda); - if (v0.dcapostopv() > dcapostopcutlambdavalue) { - cuthistoslambda::dcapostopCut[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 (int j = 0; j < 20; j++) { - std::string dcanegtopcutlambda = cuthistoslambda::dcanegtopvcuts[j]; - size_t pos = dcanegtopcutlambda.find("_"); - dcanegtopcutlambda[pos] = '.'; - const float dcanegtopcutlambdavalue = std::stod(dcanegtopcutlambda); - if (v0.dcanegtopv() > dcanegtopcutlambdavalue) { - cuthistoslambda::dcanegtopCut[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 - rV0Parameters_MC_AntiLambdamatch.fill(HIST("hDCAV0Daughters_AntiLambdaMC_Match"), v0.dcaV0daughters()); - rV0Parameters_MC_AntiLambdamatch.fill(HIST("hV0CosPA_AntiLambdaMC_Match"), v0.v0cosPA()); - rV0Parameters_MC_AntiLambdamatch.fill(HIST("hV0Radius_AntiLambdaMC_Match"), v0.v0radius()); - rV0Parameters_MC_AntiLambdamatch.fill(HIST("hDCAPostoPV_AntiLambdaMC_Match"), v0.dcapostopv()); - rV0Parameters_MC_AntiLambdamatch.fill(HIST("hDCANegtoPV_AntiLambdaMC_Match"), v0.dcanegtopv()); - // for explanation look at the first Kzero plot above - for (int j = 0; j < 20; 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()); + // 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 (int j = 0; j < 20; 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::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 (int j = 0; j < 20; 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::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 (int j = 0; j < 20; j++) { - std::string dcapostopantilambda = cuthistosantilambda::dcapostopvcuts[j]; - size_t pos = dcapostopantilambda.find("_"); - dcapostopantilambda[pos] = '.'; - const float dcapostopcutantilambdavalue = std::stod(dcapostopantilambda); - if (v0.dcapostopv() > dcapostopcutantilambdavalue) { - cuthistosantilambda::dcapostopCut[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 (int j = 0; j < 20; j++) { - std::string dcanegtopantilambda = cuthistosantilambda::dcanegtopvcuts[j]; - size_t pos = dcanegtopantilambda.find("_"); - dcanegtopantilambda[pos] = '.'; - const float dcanegtopcutantilambdavalue = std::stod(dcanegtopantilambda); - if (v0.dcanegtopv() > dcanegtopcutantilambdavalue) { - cuthistosantilambda::dcanegtopCut[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&, - aod::V0Datas const& V0s) - { - // filling histograms with the different V0 parameters - for (const auto& v0 : V0s) { - rV0Parameters_Data.fill(HIST("hMassK0ShortNoCuts_V0_Data"), v0.mK0Short()); - rV0Parameters_Data.fill(HIST("hMassLambdaNoCuts_V0_Data"), v0.mLambda()); - rV0Parameters_Data.fill(HIST("hMassAntiLambdaNoCuts_V0_Data"), v0.mAntiLambda()); - rV0Parameters_Data.fill(HIST("hDCAV0Daughters_V0_Data"), v0.dcaV0daughters()); - rV0Parameters_Data.fill(HIST("hV0CosPA_V0_Data"), v0.v0cosPA()); - rV0Parameters_Data.fill(HIST("hV0Radius_V0_Data"), v0.v0radius()); - rV0Parameters_Data.fill(HIST("hV0Radius_Full_V0_Data"), v0.v0radius()); - rV0Parameters_Data.fill(HIST("hDCAPostoPV_V0_Data"), v0.dcapostopv()); - rV0Parameters_Data.fill(HIST("hDCANegtoPV_V0_Data"), v0.dcanegtopv()); - - // 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 (int j = 0; j < 20; 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 (int j = 0; j < 20; 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 (int j = 0; j < 20; 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 (int j = 0; j < 20; j++) { - std::string dcapostopcut = cuthistoskzerosh::dcapostopvcuts[j]; - size_t pos = dcapostopcut.find("_"); - dcapostopcut[pos] = '.'; - const float dcapostopcutvalue = std::stod(dcapostopcut); - if (v0.dcapostopv() > dcapostopcutvalue) { - cuthistoskzerosh::dcapostopCut[j]->Fill(v0.mK0Short()); - } - } - for (int j = 0; j < 20; j++) { - std::string dcanegtopcut = cuthistoskzerosh::dcanegtopvcuts[j]; - size_t pos = dcanegtopcut.find("_"); - dcanegtopcut[pos] = '.'; - const float dcanegtopcutvalue = std::stod(dcanegtopcut); - if (v0.dcanegtopv() > dcanegtopcutvalue) { - cuthistoskzerosh::dcanegtopCut[j]->Fill(v0.mK0Short()); - } - } - // 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 (int j = 0; j < 20; 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 (int j = 0; j < 20; 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 (int j = 0; j < 20; 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 (int j = 0; j < 20; j++) { - std::string dcapostopcutlambda = cuthistoslambda::dcapostopvcuts[j]; - size_t pos = dcapostopcutlambda.find("_"); - dcapostopcutlambda[pos] = '.'; - const float dcapostopcutlambdavalue = std::stod(dcapostopcutlambda); - if (v0.dcapostopv() > dcapostopcutlambdavalue) { - cuthistoslambda::dcapostopCut[j]->Fill(v0.mLambda()); - } - } - for (int j = 0; j < 20; j++) { - std::string dcanegtopcutlambda = cuthistoslambda::dcanegtopvcuts[j]; - size_t pos = dcanegtopcutlambda.find("_"); - dcanegtopcutlambda[pos] = '.'; - const float dcanegtopcutlambdavalue = std::stod(dcanegtopcutlambda); - if (v0.dcanegtopv() > dcanegtopcutlambdavalue) { - cuthistoslambda::dcanegtopCut[j]->Fill(v0.mLambda()); - } - } - // Filling the five 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 - for (int j = 0; j < 20; 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 (int j = 0; j < 20; 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 (int j = 0; j < 20; 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 (int j = 0; j < 20; j++) { - std::string dcapostopantilambda = cuthistosantilambda::dcapostopvcuts[j]; - size_t pos = dcapostopantilambda.find("_"); - dcapostopantilambda[pos] = '.'; - const float dcapostopcutantilambdavalue = std::stod(dcapostopantilambda); - if (v0.dcapostopv() > dcapostopcutantilambdavalue) { - cuthistosantilambda::dcapostopCut[j]->Fill(v0.mAntiLambda()); - } - } - for (int j = 0; j < 20; j++) { - std::string dcanegtopantilambda = cuthistosantilambda::dcanegtopvcuts[j]; - size_t pos = dcanegtopantilambda.find("_"); - dcanegtopantilambda[pos] = '.'; - const float dcanegtopcutantilambdavalue = std::stod(dcanegtopantilambda); - if (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); + PROCESS_SWITCH(v0topologicalcuts, recMCProcess, "Process Run 3 MC:Reconstructed", true); + PROCESS_SWITCH(v0topologicalcuts, dataProcess, "Process Run 3 Data,", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/vzero_cascade_absorption.cxx b/PWGLF/Tasks/Strangeness/vzero_cascade_absorption.cxx index 6ca2e43ba69..d2d7ce98e62 100644 --- a/PWGLF/Tasks/Strangeness/vzero_cascade_absorption.cxx +++ b/PWGLF/Tasks/Strangeness/vzero_cascade_absorption.cxx @@ -12,25 +12,29 @@ /// \author Alberto Caliva (alberto.caliva@cern.ch) /// \since September 26, 2023 -#include -#include -#include -#include -#include -#include +#include "PWGLF/DataModel/LFStrangenessTables.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 "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include + +#include using namespace o2; using namespace o2::framework; diff --git a/PWGLF/Tasks/Strangeness/xiLambdaCorr.cxx b/PWGLF/Tasks/Strangeness/xiLambdaCorr.cxx new file mode 100644 index 00000000000..6e737616695 --- /dev/null +++ b/PWGLF/Tasks/Strangeness/xiLambdaCorr.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. + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/Core/RecoDecay.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "TDatabasePDG.h" +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using Collisions = soa::Join::iterator; +using FullV0s = soa::Join; +using FullCascades = soa::Join; +using TracksFull = soa::Join; + +struct xiLambdaCorr { + ConfigurableAxis zVtxAxis{"zVtxBins", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; + // binning of (anti)lambda mass QA histograms + ConfigurableAxis massLambdaAxis{"massLambdaAxis", {100, o2::constants::physics::MassLambda - 0.05f, o2::constants::physics::MassLambda + 0.05f}, "binning for the lambda invariant-mass"}; + ConfigurableAxis massXiAxis{"massXiAxis", {100, o2::constants::physics::MassXiMinus - 0.05f, o2::constants::physics::MassXiMinus + 0.05f}, "binning for the Xi invariant-mass"}; + ConfigurableAxis massXiLambdaAxis{"massXiLambdaAxis", {200, o2::constants::physics::MassXiMinus + o2::constants::physics::MassLambda, o2::constants::physics::MassXiMinus + o2::constants::physics::MassLambda + 0.1f}, "binning for the Xi+Lambda invariant-mass"}; + ConfigurableAxis cosPAxis{"cosPAxis", {10, 0.99f, 1.f}, "binning for the cosine of the pointing angle"}; + + Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; + Configurable etaMax{"etaMax", 0.9f, "maximum eta"}; + ConfigurableAxis momAxis{"momAxisFine", {50, 0.f, 10.f}, "momentum axis binning"}; + ConfigurableAxis mixTypeAxis{"mixTypeAxis", {4, -0.5f, 3.5f}, "mixing type axis"}; // xi - lambda , xi - anti-lambda, anti-xi - lambda, anti-xi - anti-lambda + + Configurable cascPtMin{"cascPtMin", 1.f, "minimum (anti)casc pT (GeV/c)"}; + Configurable cascPtMax{"cascPtMax", 4.f, "maximum (anti)casc pT (GeV/c)"}; + + Configurable minNTPCClus{"minNTPCClus", 100, "Minimum number of TPC clusters"}; + Configurable minCascCosPA{"minCascCosPA", 0.99f, "Minimum cosine of the pointing angle of the cascade"}; + Configurable minV0CosPA{"minV0CosPA", 0.97f, "Minimum cosine of the pointing angle of the V0"}; + + 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 lambdaPtMin{"lambdaPtMin", 0.5f, "minimum (anti)lambda pT (GeV/c)"}; + Configurable lambdaPtMax{"lambdaPtMax", 4.f, "maximum (anti)lambda pT (GeV/c)"}; + Configurable dcaLambdaDauToPV{"dcaLambdaDauToPV", 0.05f, "DCA of the lambda daughter to the primary vertex"}; + Configurable minLambdaCosPA{"minLambdaCosPA", 0.99f, "Minimum cosine of the pointing angle of the lambda"}; + + Configurable mLambdaWindow{"mLambdaWindow", 0.02f, "mLambdaWindow"}; + Configurable mXiWindow{"mXiWindow", 0.02f, "mXiWindow"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + template + bool selectTrack(T const& track) + { + if (track.tpcNClsFound() < minNTPCClus) { + return false; + } + return true; + } + + void init(o2::framework::InitContext&) + { + // event QA + histos.add("QA/zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); + histos.add("QA/massLambda", ";#it{p}_{T} (GeV/#it{c});#it{m}_{#Lambda} (GeV/#it{c}^{2})", HistType::kTH2F, {momAxis, massLambdaAxis}); + histos.add("QA/massXi", ";#it{p}_{T} (GeV/#it{c});#it{m}_{#Xi} (GeV/#it{c}^{2})", HistType::kTH2F, {momAxis, massXiAxis}); + histos.add("xiMinusLambda", "", {HistType::kTHnSparseF, {massXiLambdaAxis, momAxis, massXiAxis, massLambdaAxis, cosPAxis, cosPAxis, mixTypeAxis}}); + } + + template + bool isSelectedCasc(C const& collision, T const&, FullCascades::iterator const& casc) + { + + if (std::abs(casc.positiveeta()) > 0.9 || std::abs(casc.negativeeta()) > 0.9 || std::abs(casc.bacheloreta()) > 0.9) { + return false; + } + + auto bachelor = casc.bachTrackExtra_as(); + auto posDau = casc.posTrackExtra_as(); + auto negDau = casc.negTrackExtra_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.mXi() > o2::constants::physics::MassXiMinus - mXiWindow && casc.mXi() < o2::constants::physics::MassXiMinus + mXiWindow) { + massInWindow = true; + } + + if (!massInWindow) { + return false; + } + histos.fill(HIST("QA/massXi"), casc.pt(), casc.mXi()); + return true; + }; + + template + bool isSelectedLambda(T const&, FullV0s::iterator const& v0) + { + auto posDau = v0.posTrackExtra_as(); + auto negDau = v0.negTrackExtra_as(); + + if (std::abs(v0.positiveeta()) > 0.9 || std::abs(v0.negativeeta()) > 0.9) { + return false; + } + + if (!selectTrack(posDau) || !selectTrack(negDau)) { + return false; + } + if (v0.alpha() > 0) { + if (TMath::Abs(posDau.tpcNSigmaPr()) > nSigmaTPCCut || TMath::Abs(negDau.tpcNSigmaPi()) > nSigmaTPCCut) { + return false; + } + } else { + if (TMath::Abs(posDau.tpcNSigmaPi()) > nSigmaTPCCut || TMath::Abs(negDau.tpcNSigmaPr()) > nSigmaTPCCut) { + return false; + } + } + + if (TMath::Abs(v0.dcapostopv()) < dcaLambdaDauToPV || TMath::Abs(v0.dcanegtopv()) < dcaLambdaDauToPV) { + return false; + } + + if (v0.v0cosPA() < minLambdaCosPA) { + return false; + } + if (TMath::Abs(v0.eta()) > etaMax) { + return false; + } + // mass cuts + bool massInWindow = false; + float massLambda = v0.alpha() > 0 ? v0.mLambda() : v0.mAntiLambda(); + if (v0.mLambda() > o2::constants::physics::MassLambda - mLambdaWindow && v0.mLambda() < o2::constants::physics::MassLambda + mLambdaWindow) { + massInWindow = true; + } + if (!massInWindow) { + return false; + } + histos.fill(HIST("QA/massLambda"), v0.pt(), massLambda); + return true; + }; + + template + void fillXiLambda(C const& collision, T const& tracks, FullV0s const& v0s, FullCascades const& cascades) + { + for (auto& casc : cascades) { + if (!isSelectedCasc(collision, tracks, casc)) { + continue; + } + for (auto& v0 : v0s) { + if (!isSelectedLambda(tracks, v0)) { + continue; + } + if (casc.posTrackExtraId() == v0.posTrackExtraId() || casc.posTrackExtraId() == v0.negTrackExtraId()) { + continue; + } + + int mixType = -1; + if (casc.sign() > 0 && v0.alpha() > 0) { + mixType = 0; // xi - lambda + } else if (casc.sign() > 0 && v0.alpha() < 0) { + mixType = 1; // xi - anti-lambda + } else if (casc.sign() < 0 && v0.alpha() > 0) { + mixType = 2; // anti-xi - lambda + } else if (casc.sign() < 0 && v0.alpha() < 0) { + mixType = 3; // anti-xi - anti-lambda + } + + ROOT::Math::LorentzVector> cascMom4D(casc.px(), casc.py(), casc.pz(), o2::constants::physics::MassXiMinus); + ROOT::Math::LorentzVector> lambdaMom4D{v0.px(), v0.py(), v0.pz(), o2::constants::physics::MassLambda}; + auto xiLambdaMom4D = cascMom4D + lambdaMom4D; + float massLambda = v0.alpha() > 0 ? v0.mLambda() : v0.mAntiLambda(); + float massXi = casc.mXi(); + float cosPAxi = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + float cosPAlambda = v0.v0cosPA(); + histos.fill(HIST("xiMinusLambda"), xiLambdaMom4D.M(), xiLambdaMom4D.Pt(), massXi, massLambda, cosPAxi, cosPAlambda, mixType); + } + } + }; + + void processData(Collisions const& collision, TracksFull const& tracks, FullV0s const& v0s, FullCascades const& cascades) + { + + 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; + + histos.fill(HIST("QA/zVtx"), collision.posZ()); + fillXiLambda(collision, tracks, v0s, cascades); + } + PROCESS_SWITCH(xiLambdaCorr, processData, "Process data", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Utils/CMakeLists.txt b/PWGLF/Utils/CMakeLists.txt index bc3fd97b824..51048b896a5 100644 --- a/PWGLF/Utils/CMakeLists.txt +++ b/PWGLF/Utils/CMakeLists.txt @@ -15,4 +15,4 @@ o2physics_add_library(v0SelectionGroup o2physics_target_root_dictionary(v0SelectionGroup HEADERS v0SelectionGroup.h - LINKDEF v0SelectionGroupLinkDef.h) + LINKDEF v0SelectionGroupLinkDef.h) \ No newline at end of file diff --git a/PWGLF/Utils/collisionCuts.h b/PWGLF/Utils/collisionCuts.h index 97278cbec9d..b1a80cfe075 100644 --- a/PWGLF/Utils/collisionCuts.h +++ b/PWGLF/Utils/collisionCuts.h @@ -16,15 +16,17 @@ /// original author: Laura Serksnyte, TU München /// /// \author Bong-Hwi Lim +/// \author Hirak Kumar Koley #ifndef PWGLF_UTILS_COLLISIONCUTS_H_ #define PWGLF_UTILS_COLLISIONCUTS_H_ +#include "Common/DataModel/EventSelection.h" + #include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" -#include "Common/DataModel/EventSelection.h" -using namespace o2::framework; +#include namespace o2::analysis { @@ -45,6 +47,8 @@ class CollisonCuts kFlagBunchPileup, kFlagZvtxFT0vsPV, kFlagOccupancy, + kNoCollInTimeRangeStandard, + kNoCollInTimeRangeNarrow, kAllpassed }; @@ -56,14 +60,12 @@ class CollisonCuts /// \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, bool triggerTVXsel = false, int trackOccupancyInTimeRangeMax = -1) + 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; @@ -72,64 +74,90 @@ class CollisonCuts 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}}); // z-vertex histogram after event selections - mHistogramRegistry->add("Event/posZ_noCut", "; vtx_{z} (cm); Entries", kTH1F, {{250, -12.5, 12.5}}); // z-vertex histogram before all selections + 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/posZ_ITSOnly", "; vtx_{z} (cm); Entries", kTH1F, {{250, -12.5, 12.5}}); - mHistogramRegistry->add("Event/posZ_ITSTPC", "; vtx_{z} (cm); Entries", kTH1F, {{250, -12.5, 12.5}}); - mHistogramRegistry->add("Event/trackOccupancyInTimeRange_noCut", "; Occupancy; Entries", kTH1F, {{500, 0., 20000.}}); - mHistogramRegistry->add("CollCutCounts", "; ; Entries", kTH1F, {{11, 0., 11.}}); - - 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::kAllpassed), "Allpassed"); + 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 Check Run3: %d \n Trigger TVX selection: %d \n Apply time frame border cut: %d \n Apply ITS-TPC vertex: %d \n Apply Z-vertex time difference: %d \n Apply Pileup rejection: %d \n Apply NoITSRO frame border cut: %d \n Track occupancy in time range max: %d", - mZvtxMax, mCheckTrigger, mTrigger, mCheckOffline, mCheckIsRun3, mTriggerTVXselection, mApplyTFBorderCut, mApplyITSTPCvertex, mApplyZvertexTimedifference, mApplyPileupRejection, mApplyNoITSROBorderCut, mtrackOccupancyInTimeRangeMax); + 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); + } } /// Set MB selection void setTriggerTVX(bool triggerTVXsel) { mTriggerTVXselection = triggerTVXsel; } - /// Scan the trigger alias of the event - void setInitialTriggerScan(bool checkTrigger) { mInitialTriggerScan = checkTrigger; } - /// Set the time frame border cut void setApplyTFBorderCut(bool applyTFBorderCut) { mApplyTFBorderCut = applyTFBorderCut; } /// Set the ITS-TPC matching cut 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; } @@ -139,82 +167,147 @@ 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 /// \return whether or not the collisions fulfills the specified selections template - bool isSelected(T const& col) + bool isSelected(T const& col, const bool QA = true) { - mHistogramRegistry->fill(HIST("Event/posZ_noCut"), col.posZ()); - mHistogramRegistry->fill(HIST("Event/trackOccupancyInTimeRange_noCut"), col.trackOccupancyInTimeRange()); - mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kAllEvent); + if (QA) { + 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; } - mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagZvertex); + if (mInitialColBitScan) { + for (const auto& bit : bitList) { + if (col.selection_bit(bit)) { + LOGF(info, "Trigger %d fired", bit); + } + } + mInitialColBitScan = false; + } + if (QA) { + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagZvertex); + } if (mCheckIsRun3) { // Run3 case if (!col.selection_bit(aod::evsel::kIsTriggerTVX) && mTriggerTVXselection) { LOGF(debug, "Offline selection TVX failed (Run3)"); return false; } - mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagTrigerTVX); + if (QA) { + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagTrigerTVX); + } if (!col.selection_bit(aod::evsel::kNoTimeFrameBorder) && mApplyTFBorderCut) { LOGF(debug, "Time frame border cut failed"); return false; } - mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagTimeFrameBorder); + if (QA) { + 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 (QA) { + 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 (QA) { + 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 (QA) { + 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 (QA) { + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagBunchPileup); + } + if (!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow) && mApplyCollInTimeRangeNarrow) { + LOGF(debug, "NoCollInTimeRangeNarrow selection failed"); + return false; + } + if (QA) { + 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; } - mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagZvtxFT0vsPV); + if (QA) { + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagZvtxFT0vsPV); + } if (mtrackOccupancyInTimeRangeMax > 0 && col.trackOccupancyInTimeRange() > mtrackOccupancyInTimeRangeMax) { LOGF(debug, "trackOccupancyInTimeRange selection failed"); return false; } - mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagOccupancy); + if (mtrackOccupancyInTimeRangeMin > 0 && col.trackOccupancyInTimeRange() < mtrackOccupancyInTimeRangeMin) { + LOGF(debug, "trackOccupancyInTimeRange selection failed"); + return false; + } + if (QA) { + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kFlagOccupancy); + } + if ((!col.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) && mApplyCollInTimeRangeStandard) { + LOGF(debug, "NoCollInTimeRangeStandard selection failed"); + return false; + } + if (QA) { + 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; + } + if (QA) { + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kAllpassed); + } + } + if (QA) { + mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kAllpassed); } - mHistogramRegistry->fill(HIST("CollCutCounts"), EvtSel::kAllpassed); return true; } @@ -231,7 +324,6 @@ class CollisonCuts } else { mHistogramRegistry->fill(HIST("Event/posZ_ITSTPC"), col.posZ()); } - mHistogramRegistry->fill(HIST("Event/CentFV0A"), col.centFV0A()); mHistogramRegistry->fill(HIST("Event/CentFT0M"), col.centFT0M()); mHistogramRegistry->fill(HIST("Event/CentFT0C"), col.centFT0C()); mHistogramRegistry->fill(HIST("Event/CentFT0A"), col.centFT0A()); @@ -251,21 +343,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 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 mInitialTriggerScan = false; ///< Check trigger when the event is first selected - bool mApplyTFBorderCut = false; ///< Apply time frame border cut - bool mApplyITSTPCvertex = false; ///< Apply at least one ITS-TPC track for vertexing - 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) - int mtrackOccupancyInTimeRangeMax = -1; ///< Maximum trackOccupancyInTimeRange cut (-1 no cut) + 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/decay3bodyBuilderHelper.h b/PWGLF/Utils/decay3bodyBuilderHelper.h new file mode 100644 index 00000000000..80d7995684f --- /dev/null +++ b/PWGLF/Utils/decay3bodyBuilderHelper.h @@ -0,0 +1,894 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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_DECAY3BODYBUILDERHELPER_H_ +#define PWGLF_UTILS_DECAY3BODYBUILDERHELPER_H_ + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "DCAFitter/DCAFitterN.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsVertexing/SVertexHypothesis.h" +#include "Framework/AnalysisDataModel.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include + +#ifndef HomogeneousField +#define HomogeneousField +#endif + +/// includes KFParticle +#include "KFPTrack.h" +#include "KFPVertex.h" +#include "KFParticle.h" +#include "KFParticleBase.h" +#include "KFVertex.h" + +namespace o2 +{ +namespace pwglf +{ + +//_______________________________________________________________________ +// Deca3body information storage +struct decay3bodyCandidate { + // indexing + int collisionID = -1; + int decay3bodyID = -1; + int protonID = -1; + int pionID = -1; + int deuteronID = -1; + + // daughter properties + std::array momProton = {0.0f, 0.0f, 0.0f}; + std::array momPion = {0.0f, 0.0f, 0.0f}; + std::array momDeuteron = {0.0f, 0.0f, 0.0f}; + std::array posProton = {0.0f, 0.0f, 0.0f}; + std::array posPion = {0.0f, 0.0f, 0.0f}; + std::array posDeuteron = {0.0f, 0.0f, 0.0f}; + std::array trackDCAxyToPV = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + std::array trackDCAToPV = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + std::array trackDCAxyToPVprop = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + std::array trackDCAToPVprop = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + std::array tpcNsigma = {0.0f, 0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron, 3 - bach with pion hyp + double tofNsigmaDeuteron = 0.0f; + std::array averageITSClSize = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + std::array tpcNCl = {0.0f, 0.0f, 0.0f}; // 0 - proton, 1 - pion, 2 - deuteron + int pidForTrackingDeuteron = 0; + + // vertex properties + float mass; + float massV0; + int sign; + float momentum[3]; + float position[3]; + float chi2 = 0.0f; + float trackedClSize = 0.0f; + float cosPA = 0.0f; // cosine of pointing angle + float ctau = 0.0f; // ctau of the candidate + float daughterDCAtoSVaverage = 0.0f; // average of quadratic sum of daughter DCAs to SV + std::array daughterDCAtoSV = {0.0f, 0.0f, 0.0f}; // 0 - pos, 1 - neg, 2 - bach + + // covariance matrix + float covProton[21] = {0.0f}; + float covPion[21] = {0.0f}; + float covDeuteron[21] = {0.0f}; + float covariance[21] = {0.0f}; +}; + +//_______________________________________________________________________ +// builder helper class +class decay3bodyBuilderHelper +{ + public: + decay3bodyBuilderHelper() + { + fitter3body.setPropagateToPCA(true); + fitter3body.setMaxR(200.); //->maxRIni3body + fitter3body.setMinParamChange(1e-3); + fitter3body.setMinRelChi2Change(0.9); + fitter3body.setMaxDZIni(1e9); + fitter3body.setMaxDXYIni(4.0f); + fitter3body.setMaxChi2(1e9); + fitter3body.setUseAbsDCA(true); + + fitterV0.setPropagateToPCA(true); + fitterV0.setMaxR(200.); + fitterV0.setMinParamChange(1e-3); + fitterV0.setMinRelChi2Change(0.9); + fitterV0.setMaxDZIni(1e9); + fitterV0.setMaxChi2(1e9); + fitterV0.setUseAbsDCA(true); + + // mag field has to be set later + fitter3body.setBz(-999.9f); // will NOT make sense if not changed + }; + + o2::vertexing::DCAFitterN<2> fitterV0; // 2-prong o2 dca fitter + o2::vertexing::DCAFitterN<3> fitter3body; // 3-prong o2 dca fitter + + decay3bodyCandidate decay3body; // storage for Decay3body candidate properties + + o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; + o2::vertexing::SVertexHypothesis mV0Hyps; // 0 - Lambda, 1 - AntiLambda + + // decay3body candidate criteria + struct { + // daughter tracks + float maxEtaDaughters; + int minTPCNClProton; + int minTPCNClPion; + int minTPCNClDeuteron; + float minDCAProtonToPV; + float minDCAPionToPV; + float minDCADeuteronToPV; + float minDCAProtonToPVprop; + float minDCAPionToPVprop; + float minDCADeuteronToPVprop; + float minPtProton; + float minPtPion; + float minPtDeuteron; + float maxPtProton; + float maxPtPion; + float maxPtDeuteron; + float maxTPCnSigma; + double minTOFnSigmaDeuteron; + double maxTOFnSigmaDeuteron; + float minPDeuteronUseTOF; + float maxDCADauToSVaverage; + // candidate + float maxRapidity; + float minPt; + float maxPt; + float minMass; + float maxMass; + float minCtau; + float maxCtau; + float minCosPA; + float maxChi2; + } decay3bodyselections; + + // SVertexer selection criteria + struct { + float minPt2V0; + float maxTgl2V0; + float maxDCAXY2ToMeanVertex3bodyV0; + float minCosPAXYMeanVertex3bodyV0; + float minCosPA3bodyV0; + float maxRDiffV03body; + float minPt3Body; + float maxTgl3Body; + float maxDCAXY3Body; + float maxDCAZ3Body; + } svertexerselections; + + //_______________________________________________________________________ + // build Decay3body from three tracks, including V0 building. + template + bool buildDecay3BodyCandidate(TCollision const& collision, + TTrack const& trackProton, + TTrack const& trackPion, + TTrack const& trackDeuteron, + int decay3bodyIndex, + double tofNsigmaDeuteron, + float trackedClSize, + bool useKFParticle = false, + bool kfSetTopologicalConstraint = false, + bool useSelections = true, + bool useChi2Selection = true, + bool useTPCforPion = false, + bool acceptTPCOnly = false, + bool askOnlyITSMatch = true, + bool calculateCovariance = true, + bool isEventMixing = false, + bool doApplySVertexerCuts = false) + { + int collisionIndex = collision.globalIndex(); + float pvX = collision.posX(); + float pvY = collision.posY(); + float pvZ = collision.posZ(); + + auto trackParCovProton = getTrackParCov(trackProton); + auto trackParCovPion = getTrackParCov(trackPion); + auto trackParCovDeuteron = getTrackParCov(trackDeuteron); + + decay3body.collisionID = collisionIndex; + decay3body.decay3bodyID = decay3bodyIndex; + decay3body.protonID = trackProton.globalIndex(); + decay3body.pionID = trackPion.globalIndex(); + decay3body.deuteronID = trackDeuteron.globalIndex(); + + //_______________________________________________________________________ + // track selections + if (useSelections) { + // proton track quality + if (trackProton.tpcNClsFound() < decay3bodyselections.minTPCNClProton) { + decay3body = {}; + return false; + } + // pion track quality + if (useTPCforPion) { + if (trackPion.tpcNClsFound() < decay3bodyselections.minTPCNClPion) { + decay3body = {}; + return false; + } + } + // deuteron track quality + if (trackDeuteron.tpcNClsFound() < decay3bodyselections.minTPCNClDeuteron) { + decay3body = {}; + return false; + } + + // track eta + if (std::fabs(trackProton.eta()) > decay3bodyselections.maxEtaDaughters) { + decay3body = {}; + return false; + } + if (std::fabs(trackPion.eta()) > decay3bodyselections.maxEtaDaughters) { + decay3body = {}; + return false; + } + if (std::fabs(trackDeuteron.eta()) > decay3bodyselections.maxEtaDaughters) { + decay3body = {}; + return false; + } + + // TPC only + if (!acceptTPCOnly) { + if (askOnlyITSMatch) { + if (!trackProton.hasITS() || !trackPion.hasITS() || !trackDeuteron.hasITS()) { + decay3body = {}; + return false; + } + } else { + bool isProtonTPCOnly = !trackProton.hasITS() && !trackProton.hasTOF() && !trackProton.hasTRD(); + bool isPionTPCOnly = !trackPion.hasITS() && !trackPion.hasTOF() && !trackPion.hasTRD(); + bool isDeuteronTPCOnly = !trackDeuteron.hasITS() && !trackDeuteron.hasTOF() && !trackDeuteron.hasTRD(); + if (isProtonTPCOnly || isPionTPCOnly || isDeuteronTPCOnly) { + decay3body = {}; + return false; + } + } + } + + // daughter TPC PID + if (std::fabs(trackProton.tpcNSigmaPr()) > decay3bodyselections.maxTPCnSigma) { + decay3body = {}; + return false; + } + if (useTPCforPion && std::fabs(trackPion.tpcNSigmaPi()) > decay3bodyselections.maxTPCnSigma) { + decay3body = {}; + return false; + } + if (std::fabs(trackDeuteron.tpcNSigmaDe()) > decay3bodyselections.maxTPCnSigma) { + decay3body = {}; + return false; + } + + // deuteron TOF PID + if ((tofNsigmaDeuteron < decay3bodyselections.minTOFnSigmaDeuteron || tofNsigmaDeuteron > decay3bodyselections.maxTOFnSigmaDeuteron) && trackDeuteron.p() > decay3bodyselections.minPDeuteronUseTOF) { + decay3body = {}; + return false; + } + } // end of selections + + //_______________________________________________________________________ + // daughter track DCA to PV associated with decay3body --> computed with KFParticle + float pvXY[2] = {pvX, pvY}; + float pv[3] = {pvX, pvY, pvZ}; + auto trackParCovProtonCopy = trackParCovProton; + auto trackParCovPionCopy = trackParCovPion; + auto trackParCovDeuteronCopy = trackParCovDeuteron; + KFParticle kfproton = createKFParticleFromTrackParCov(trackParCovProtonCopy, trackProton.sign(), constants::physics::MassProton); + KFParticle kfpion = createKFParticleFromTrackParCov(trackParCovPionCopy, trackPion.sign(), constants::physics::MassPionCharged); + KFParticle kfdeuteron = createKFParticleFromTrackParCov(trackParCovDeuteronCopy, trackDeuteron.sign(), constants::physics::MassDeuteron); + + // proton DCA to PV + decay3body.trackDCAxyToPV[0] = kfproton.GetDistanceFromVertexXY(pvXY); + decay3body.trackDCAToPV[0] = kfproton.GetDistanceFromVertex(pv); + // pion DCA to PV + decay3body.trackDCAxyToPV[1] = kfpion.GetDistanceFromVertexXY(pvXY); + decay3body.trackDCAToPV[1] = kfpion.GetDistanceFromVertex(pv); + // deuteron DCA to PV + decay3body.trackDCAxyToPV[2] = kfdeuteron.GetDistanceFromVertexXY(pvXY); + decay3body.trackDCAToPV[2] = kfdeuteron.GetDistanceFromVertex(pv); + // selection + if (useSelections) { + if (decay3body.trackDCAToPV[0] < decay3bodyselections.minDCAProtonToPV) { + decay3body = {}; + return false; + } + if (decay3body.trackDCAToPV[1] < decay3bodyselections.minDCAPionToPV) { + decay3body = {}; + return false; + } + if (decay3body.trackDCAToPV[2] < decay3bodyselections.minDCADeuteronToPV) { + decay3body = {}; + return false; + } + } + + //_______________________________________________________________________ + // daughter track DCA to PV associated with decay3body --> with O2 Propagator + o2::dataformats::VertexBase mPV; + o2::dataformats::DCA mDcaInfoCov; + auto trackParCovProtonCopyProp = trackParCovProton; + auto trackParCovPionCopyProp = trackParCovPion; + auto trackParCovDeuteronCopyProp = trackParCovDeuteron; + mPV.setPos({pvX, pvY, pvZ}); + mPV.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + + // proton track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovProtonCopyProp, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); + decay3body.trackDCAxyToPVprop[0] = mDcaInfoCov.getY(); + auto trackProtonDCAzToPVprop = mDcaInfoCov.getZ(); + decay3body.trackDCAToPVprop[0] = std::sqrt(decay3body.trackDCAxyToPVprop[0] * decay3body.trackDCAxyToPVprop[0] + trackProtonDCAzToPVprop * trackProtonDCAzToPVprop); + if (useSelections) { + if (decay3body.trackDCAToPVprop[0] < decay3bodyselections.minDCAProtonToPVprop) { + decay3body = {}; + return false; + } + } + // pion track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovPionCopyProp, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); + decay3body.trackDCAxyToPVprop[1] = mDcaInfoCov.getY(); + auto trackPionDCAzToPVprop = mDcaInfoCov.getZ(); + decay3body.trackDCAToPVprop[1] = std::sqrt(decay3body.trackDCAxyToPVprop[1] * decay3body.trackDCAxyToPVprop[1] + trackPionDCAzToPVprop * trackPionDCAzToPVprop); + if (useSelections) { + if (decay3body.trackDCAToPVprop[1] < decay3bodyselections.minDCAPionToPVprop) { + decay3body = {}; + return false; + } + } + // deuteron track + o2::base::Propagator::Instance()->propagateToDCABxByBz(mPV, trackParCovDeuteronCopyProp, 2.f, fitter3body.getMatCorrType(), &mDcaInfoCov); + decay3body.trackDCAxyToPVprop[2] = mDcaInfoCov.getY(); + auto trackDeuteronDCAzToPVprop = mDcaInfoCov.getZ(); + decay3body.trackDCAToPVprop[2] = std::sqrt(decay3body.trackDCAxyToPVprop[2] * decay3body.trackDCAxyToPVprop[2] + trackDeuteronDCAzToPVprop * trackDeuteronDCAzToPVprop); + if (useSelections) { + if (decay3body.trackDCAToPVprop[2] < decay3bodyselections.minDCADeuteronToPVprop) { + decay3body = {}; + return false; + } + } + + //_______________________________________________________________________ + // fit 3body vertex + if (!useKFParticle) { + fitVertexWithDCAFitter(trackProton, trackPion, trackDeuteron, calculateCovariance); + } else { + fitVertexWithKF(collision, trackProton, trackPion, trackDeuteron, kfSetTopologicalConstraint, calculateCovariance); + } + + //_______________________________________________________________________ + // get vertex information + // daughter pT + auto trackProtonPt = std::sqrt(decay3body.momProton[0] * decay3body.momProton[0] + decay3body.momProton[1] * decay3body.momProton[1]); + auto trackPionPt = std::sqrt(decay3body.momPion[0] * decay3body.momPion[0] + decay3body.momPion[1] * decay3body.momPion[1]); + auto trackDeuteronPt = std::sqrt(decay3body.momDeuteron[0] * decay3body.momDeuteron[0] + decay3body.momDeuteron[1] * decay3body.momDeuteron[1]); + + // daughter DCA to SV + // proton daughter + decay3body.daughterDCAtoSV[0] = std::hypot( + decay3body.posProton[0] - decay3body.position[0], + decay3body.posProton[1] - decay3body.position[1], + decay3body.posProton[2] - decay3body.position[2]); + // pion daughter + decay3body.daughterDCAtoSV[1] = std::hypot( + decay3body.posPion[0] - decay3body.position[0], + decay3body.posPion[1] - decay3body.position[1], + decay3body.posPion[2] - decay3body.position[2]); + // deuteron daughter + decay3body.daughterDCAtoSV[2] = std::hypot( + decay3body.posDeuteron[0] - decay3body.position[0], + decay3body.posDeuteron[1] - decay3body.position[1], + decay3body.posDeuteron[2] - decay3body.position[2]); + + // DCA daughters to SV average of quadratic sum + decay3body.daughterDCAtoSVaverage = (decay3body.daughterDCAtoSV[0] * decay3body.daughterDCAtoSV[0] + + decay3body.daughterDCAtoSV[1] * decay3body.daughterDCAtoSV[1] + + decay3body.daughterDCAtoSV[2] * decay3body.daughterDCAtoSV[2]) / + 3; + + //_____________________________________________________ + // selections after vertex fit + if (useSelections) { + // daughter pT + // proton + if (trackProtonPt < decay3bodyselections.minPtProton || trackProtonPt > decay3bodyselections.maxPtProton) { + decay3body = {}; + return false; + } + // pion + if (trackPionPt < decay3bodyselections.minPtPion || trackPionPt > decay3bodyselections.maxPtPion) { + decay3body = {}; + return false; + } + // deuteron + if (trackDeuteronPt < decay3bodyselections.minPtDeuteron || trackDeuteronPt > decay3bodyselections.maxPtDeuteron) { + decay3body = {}; + return false; + } + + // daughter DCAs at SV + if (decay3body.daughterDCAtoSVaverage > decay3bodyselections.maxDCADauToSVaverage) { + decay3body = {}; + return false; + } + + // rapidity + float rapidity = RecoDecay::y(std::array{decay3body.momentum[0], decay3body.momentum[1], decay3body.momentum[2]}, o2::constants::physics::MassHyperTriton); + if (std::fabs(rapidity) > decay3bodyselections.maxRapidity) { + decay3body = {}; + return false; + } + + // pT + float pT = RecoDecay::pt(std::array{decay3body.momentum[0], decay3body.momentum[1], decay3body.momentum[2]}); + if (pT < decay3bodyselections.minPt || pT > decay3bodyselections.maxPt) { + decay3body = {}; + return false; + } + + // mass window + if (decay3body.mass < decay3bodyselections.minMass || decay3body.mass > decay3bodyselections.maxMass) { + decay3body = {}; + return false; + } + + // vertex chi2 + if (useChi2Selection && decay3body.chi2 > decay3bodyselections.maxChi2) { + decay3body = {}; + return false; + } + } + + // pointing angle + float cpa = RecoDecay::cpa(std::array{pvX, pvY, pvZ}, std::array{decay3body.position[0], decay3body.position[1], decay3body.position[2]}, std::array{decay3body.momentum[0], decay3body.momentum[1], decay3body.momentum[2]}); + if (useSelections) { + if (cpa < decay3bodyselections.minCosPA) { + decay3body = {}; + return false; + } + } + decay3body.cosPA = cpa; + + // ctau + float P = RecoDecay::sqrtSumOfSquares(decay3body.momentum[0], decay3body.momentum[1], decay3body.momentum[2]); + float ctau = std::sqrt(std::pow(decay3body.position[0] - pvX, 2) + std::pow(decay3body.position[1] - pvY, 2) + std::pow(decay3body.position[2] - pvZ, 2)) / (P + 1E-10) * o2::constants::physics::MassHyperTriton; + if (useSelections) { + if (ctau < decay3bodyselections.minCtau || ctau > decay3bodyselections.maxCtau) { + decay3body = {}; + return false; + } + } + decay3body.ctau = ctau; + + //_______________________________________________________________________ + // SVertexer selections in case of event mixing + if (isEventMixing && doApplySVertexerCuts) { + applySVertexerCuts(collision, trackProton, trackPion, trackDeuteron, /*applyV0Cut = */ true); + } + + //_______________________________________________________________________ + // fill remaining candidate information + // daughter PID + decay3body.tpcNsigma[0] = trackProton.tpcNSigmaPr(); + decay3body.tpcNsigma[1] = trackPion.tpcNSigmaPi(); + decay3body.tpcNsigma[2] = trackDeuteron.tpcNSigmaDe(); + decay3body.tpcNsigma[3] = trackDeuteron.tpcNSigmaPi(); + // recalculated bachelor TOF PID + decay3body.tofNsigmaDeuteron = tofNsigmaDeuteron; + + // average ITS cluster size of daughter tracks + double averageClusterSizeProton(0), averageClusterSizePion(0), averageClusterSizeDeuteron(0); + int nClsProton(0), nClsPion(0), nClsDeuteron(0); + for (int i = 0; i < 7; i++) { + int clusterSizePr = trackProton.itsClsSizeInLayer(i); + int clusterSizePi = trackPion.itsClsSizeInLayer(i); + int clusterSizeDe = trackDeuteron.itsClsSizeInLayer(i); + averageClusterSizeProton += static_cast(clusterSizePr); + averageClusterSizePion += static_cast(clusterSizePi); + averageClusterSizeDeuteron += static_cast(clusterSizeDe); + if (clusterSizePr > 0) + nClsProton++; + if (clusterSizePi > 0) + nClsPion++; + if (clusterSizeDe > 0) + nClsDeuteron++; + } + averageClusterSizeProton = averageClusterSizeProton / static_cast(nClsProton); + averageClusterSizePion = averageClusterSizePion / static_cast(nClsPion); + averageClusterSizeDeuteron = averageClusterSizeDeuteron / static_cast(nClsDeuteron); + decay3body.averageITSClSize[0] = averageClusterSizeProton; + decay3body.averageITSClSize[1] = averageClusterSizePion; + decay3body.averageITSClSize[2] = averageClusterSizeDeuteron; + + // number of TPC clusters + decay3body.tpcNCl[0] = trackProton.tpcNClsFound(); + decay3body.tpcNCl[1] = trackPion.tpcNClsFound(); + decay3body.tpcNCl[2] = trackDeuteron.tpcNClsFound(); + + // PID for tracking of deuteron track + decay3body.pidForTrackingDeuteron = trackDeuteron.pidForTracking(); + + // tracked cluster size + decay3body.trackedClSize = trackedClSize; + + return true; + } + + //___________________________________________________________________________________ + // functionality to fit 3body vertex with KFParticle and fill vertex information + template + void fitVertexWithKF(TCollision const& collision, + TTrack const& trackProton, + TTrack const& trackPion, + TTrack const& trackDeuteron, + bool kfSetTopologicalConstraint = true, + bool calculateCovariance = true) + { + // get TrackParCov daughters + auto trackParCovProton = getTrackParCov(trackProton); + auto trackParCovPion = getTrackParCov(trackPion); + auto trackParCovDeuteron = getTrackParCov(trackDeuteron); + + // initialise KF primary vertex + KFVertex kfpVertex = createKFPVertexFromCollision(collision); + KFParticle kfpv(kfpVertex); + + // create KFParticle objects + KFParticle kfpProton, kfpPion, kfpDeuteron; + kfpProton = createKFParticleFromTrackParCov(trackParCovProton, trackProton.sign(), constants::physics::MassProton); + kfpPion = createKFParticleFromTrackParCov(trackParCovPion, trackPion.sign(), constants::physics::MassPionCharged); + kfpDeuteron = createKFParticleFromTrackParCov(trackParCovDeuteron, trackDeuteron.sign(), constants::physics::MassDeuteron); + + // construct V0 vertex + 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." << e.what(); + return; + } + + // construct vertex + KFParticle KFH3L; + int nDaughters3body = 3; + const KFParticle* Daughters3body[3] = {&kfpProton, &kfpPion, &kfpDeuteron}; + KFH3L.SetConstructMethod(2); + try { + KFH3L.Construct(Daughters3body, nDaughters3body); + } catch (std::runtime_error& e) { + LOG(debug) << "Failed to create Hyper triton 3-body vertex." << e.what(); + return; + } + + // topological constraint + if (kfSetTopologicalConstraint) { + KFH3L.SetProductionVertex(kfpv); + KFH3L.TransportToDecayVertex(); + } + + // get vertex position and momentum + decay3body.position[0] = KFH3L.GetX(); + decay3body.position[1] = KFH3L.GetY(); + decay3body.position[2] = KFH3L.GetZ(); + decay3body.momentum[0] = KFH3L.GetPx(); + decay3body.momentum[1] = KFH3L.GetPy(); + decay3body.momentum[2] = KFH3L.GetPz(); + + // get sign + decay3body.sign = KFH3L.GetQ() / std::abs(KFH3L.GetQ()); + + // transport all daughter tracks to hypertriton vertex + kfpProton.TransportToPoint(decay3body.position); + kfpPion.TransportToPoint(decay3body.position); + kfpDeuteron.TransportToPoint(decay3body.position); + + // daughter positions + decay3body.posProton[0] = kfpProton.GetX(); + decay3body.posProton[1] = kfpProton.GetY(); + decay3body.posProton[2] = kfpProton.GetZ(); + decay3body.posPion[0] = kfpPion.GetX(); + decay3body.posPion[1] = kfpPion.GetY(); + decay3body.posPion[2] = kfpPion.GetZ(); + decay3body.posDeuteron[0] = kfpDeuteron.GetX(); + decay3body.posDeuteron[1] = kfpDeuteron.GetY(); + decay3body.posDeuteron[2] = kfpDeuteron.GetZ(); + + // daughter momenta + decay3body.momProton[0] = kfpProton.GetPx(); + decay3body.momProton[1] = kfpProton.GetPy(); + decay3body.momProton[2] = kfpProton.GetPz(); + decay3body.momPion[0] = kfpPion.GetPx(); + decay3body.momPion[1] = kfpPion.GetPy(); + decay3body.momPion[2] = kfpPion.GetPz(); + decay3body.momDeuteron[0] = kfpDeuteron.GetPx(); + decay3body.momDeuteron[1] = kfpDeuteron.GetPy(); + decay3body.momDeuteron[2] = kfpDeuteron.GetPz(); + + // candidate mass + float mass, massErr; + KFH3L.GetMass(mass, massErr); + decay3body.mass = mass; + + // V0 mass + float massV0, massV0Err; + KFV0.GetMass(massV0, massV0Err); + decay3body.massV0 = massV0; + + // vertex chi2 + decay3body.chi2 = KFH3L.GetChi2() / KFH3L.GetNDF(); + + // caluclate covariance matrices + if (calculateCovariance) { + // candidate covariance matrix + std::array covKF; + for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) + covKF[i] = KFH3L.GetCovariance(i); + decay3body.covariance[i] = covKF[i]; + } + // daughter track covariance matrices + for (int i = 0; i < 21; i++) { // get covariance matrix elements (lower triangle) + decay3body.covProton[i] = kfpProton.GetCovariance(i); + decay3body.covPion[i] = kfpPion.GetCovariance(i); + decay3body.covDeuteron[i] = kfpDeuteron.GetCovariance(i); + } + } + + return; + } + + //_______________________________________________________________________ + // functionality to fit 3body vertex with DCAFitter + template + void fitVertexWithDCAFitter(TTrack const& trackProton, + TTrack const& trackPion, + TTrack const& trackDeuteron, + bool calculateCovariance = true) + { + // get TrackParCov daughters + auto trackParCovProton = getTrackParCov(trackProton); + auto trackParCovPion = getTrackParCov(trackPion); + auto trackParCovDeuteron = getTrackParCov(trackDeuteron); + + // fit the vertex + int n3bodyVtx = fitter3body.process(trackParCovProton, trackParCovPion, trackParCovDeuteron); + if (n3bodyVtx == 0) { // discard this pair + return; + } + + // get vertex position + const auto& vtxXYZ = fitter3body.getPCACandidate(); + for (int i = 0; i < 3; i++) { + decay3body.position[i] = vtxXYZ[i]; + } + + // get daughter momenta + const auto& propagatedTrackProton = fitter3body.getTrack(0); + const auto& propagatedTrackPion = fitter3body.getTrack(1); + const auto& propagatedTrackDeuteron = fitter3body.getTrack(2); + propagatedTrackProton.getPxPyPzGlo(decay3body.momProton); + propagatedTrackPion.getPxPyPzGlo(decay3body.momPion); + propagatedTrackDeuteron.getPxPyPzGlo(decay3body.momDeuteron); + propagatedTrackProton.getXYZGlo(decay3body.posProton); + propagatedTrackPion.getXYZGlo(decay3body.posPion); + propagatedTrackDeuteron.getXYZGlo(decay3body.posDeuteron); + + // get daughter positions at vertex + + // calculate candidate momentum + decay3body.momentum[0] = decay3body.momProton[0] + decay3body.momPion[0] + decay3body.momDeuteron[0]; + decay3body.momentum[1] = decay3body.momProton[1] + decay3body.momPion[1] + decay3body.momDeuteron[1]; + decay3body.momentum[2] = decay3body.momProton[2] + decay3body.momPion[2] + decay3body.momDeuteron[2]; + + // candidate and V0 mass + decay3body.mass = RecoDecay::m( + std::array{std::array{decay3body.momProton[0], decay3body.momProton[1], decay3body.momProton[2]}, + std::array{decay3body.momPion[0], decay3body.momPion[1], decay3body.momPion[2]}, + std::array{decay3body.momDeuteron[0], decay3body.momDeuteron[1], decay3body.momDeuteron[2]}}, + std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged, o2::constants::physics::MassDeuteron}); + decay3body.massV0 = RecoDecay::m( + std::array{std::array{decay3body.momProton[0], decay3body.momProton[1], decay3body.momProton[2]}, + std::array{decay3body.momPion[0], decay3body.momPion[1], decay3body.momPion[2]}}, + std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPionCharged}); + + // vertex chi2 at PCA + decay3body.chi2 = fitter3body.getChi2AtPCACandidate(); + + // candidate sign + decay3body.sign = trackDeuteron.sign(); + + // caluclate covariance matrices + if (calculateCovariance) { + // candidate position covariance matrix + auto covVtxV = fitter3body.calcPCACovMatrix(0); + decay3body.covariance[0] = covVtxV(0, 0); + decay3body.covariance[1] = covVtxV(1, 0); + decay3body.covariance[2] = covVtxV(1, 1); + decay3body.covariance[3] = covVtxV(2, 0); + decay3body.covariance[4] = covVtxV(2, 1); + decay3body.covariance[5] = covVtxV(2, 2); + // daughter covariance matrices + std::array covTproton = {0.}; + std::array covTpion = {0.}; + std::array covTdeuteron = {0.}; + propagatedTrackProton.getCovXYZPxPyPzGlo(covTproton); + propagatedTrackPion.getCovXYZPxPyPzGlo(covTpion); + propagatedTrackDeuteron.getCovXYZPxPyPzGlo(covTdeuteron); + for (int i = 0; i < 21; i++) { + decay3body.covProton[i] = covTproton[i]; + decay3body.covPion[i] = covTpion[i]; + decay3body.covDeuteron[i] = covTdeuteron[i]; + } + // candidate momentum covairance matrix + constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component + for (int i = 0; i < 6; i++) { + decay3body.covariance[MomInd[i]] = covTproton[MomInd[i]] + covTpion[MomInd[i]] + covTdeuteron[MomInd[i]]; + } + /// WARNING: position-momentum covariances are not calculated in the DCAFitter - remain zero + } + + return; + } + + //_______________________________________________________________________ + // functionality to apply SVertexer cuts in case of event mixing + template + void applySVertexerCuts(TCollision const& collision, + TTrack const& trackProton, + TTrack const& trackPion, + TTrack const& trackDeuteron, + bool applyV0Cut = true) + { + // get TrackParCov daughters + auto trackParCovProton = getTrackParCov(trackProton); + auto trackParCovPion = getTrackParCov(trackPion); + auto trackParCovDeuteron = getTrackParCov(trackDeuteron); + + 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 + mV0Hyps.set(o2::track::PID::Lambda, o2::track::PID::Proton, o2::track::PID::Pion, pidCutsLambda, fitter3body.getBz()); + + int nV0 = fitterV0.process(trackParCovProton, trackParCovPion); + if (nV0 == 0) { + return; + } + + std::array v0pos = {0.}; + const auto& v0vtxXYZ = fitterV0.getPCACandidate(); + for (int i = 0; i < 3; i++) { + v0pos[i] = v0vtxXYZ[i]; + } + const int cand = 0; + if (!fitterV0.isPropagateTracksToVertexDone(cand) && !fitterV0.propagateTracksToVertex(cand)) { + return; + } + + const auto& trProtonProp = fitterV0.getTrack(0, cand); + const auto& trPionProp = fitterV0.getTrack(1, cand); + std::array pProtonV0{}, pPionV0{}; + trProtonProp.getPxPyPzGlo(pProtonV0); + trPionProp.getPxPyPzGlo(pPionV0); + std::array pV0 = {pProtonV0[0] + pPionV0[0], pProtonV0[1] + pPionV0[1], pProtonV0[2] + pPionV0[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 (applyV0Cut && pt2V0 <= svertexerselections.minPt2V0) { + return; + } + if (applyV0Cut && pV0[2] * pV0[2] / pt2V0 > svertexerselections.maxTgl2V0) { // tgLambda cut + return; + } + + float p2V0 = pt2V0 + pV0[2] * pV0[2], ptV0 = std::sqrt(pt2V0); + // apply mass selections + float p2Proton = pProtonV0[0] * pProtonV0[0] + pProtonV0[1] * pProtonV0[1] + pProtonV0[2] * pProtonV0[2], p2Pion = pPionV0[0] * pPionV0[0] + pPionV0[1] * pPionV0[1] + pPionV0[2] * pPionV0[2]; + bool good3bodyV0Hyp = false; + float massForLambdaHyp = mV0Hyps.calcMass(p2Proton, p2Pion, p2V0); + if (massForLambdaHyp - mV0Hyps.getMassV0Hyp() < mV0Hyps.getMargin(ptV0)) { + good3bodyV0Hyp = true; + } + if (applyV0Cut && !good3bodyV0Hyp) { + return; + } + + float dcaX = dxv0 - pV0[0] * tDCAXY, dcaY = dyv0 - pV0[1] * tDCAXY, dca2 = dcaX * dcaX + dcaY * dcaY; + float cosPAXY = prodXYv0 / rv0 * ptV0; + if (applyV0Cut && dca2 > svertexerselections.maxDCAXY2ToMeanVertex3bodyV0) { + return; + } + // FIXME: V0 cosPA cut to be investigated + if (applyV0Cut && cosPAXY < svertexerselections.minCosPAXYMeanVertex3bodyV0) { + return; + } + // 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(); + float dy = v0pos[1] - collision.posY(); + float dz = v0pos[2] - collision.posZ(); + float prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; + float v0CosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); + if (applyV0Cut && v0CosPA < svertexerselections.minCosPA3bodyV0) { + return; + } + + // 3body vertex + int n3bodyVtx = fitter3body.process(trackParCovProton, trackParCovPion, trackParCovDeuteron); + if (n3bodyVtx == 0) { // discard this pair + return; + } + const auto& vertexXYZ = fitter3body.getPCACandidatePos(); + std::array pos = {0.}; + for (int i = 0; i < 3; i++) { + pos[i] = vertexXYZ[i]; + } + + std::array pProton = {0.}, pPion = {0.}, pDeuteron{0.}; + const auto& propagatedTrackProton = fitter3body.getTrack(0); + const auto& propagatedTrackPion = fitter3body.getTrack(1); + const auto& propagatedTrackDeuteron = fitter3body.getTrack(2); + propagatedTrackProton.getPxPyPzGlo(pProton); + propagatedTrackPion.getPxPyPzGlo(pPion); + propagatedTrackDeuteron.getPxPyPzGlo(pDeuteron); + std::array p3B = {pProton[0] + pPion[0] + pDeuteron[0], pProton[1] + pPion[1] + pDeuteron[1], pProton[2] + pPion[2] + pDeuteron[2]}; + + float r3body = std::hypot(pos[0], pos[1]); + if (r3body < 0.5) { + return; + } + + // Cut for the compatibility of V0 and 3body vertex + float deltaR = std::abs(rv0 - r3body); + if (deltaR > svertexerselections.maxRDiffV03body) { + return; + } + + float pt3B = std::hypot(p3B[0], p3B[1]); + if (pt3B < svertexerselections.minPt3Body) { // pt cut + return; + } + if (p3B[2] / pt3B > svertexerselections.maxTgl3Body) { // tgLambda cut + return; + } + + // H3L DCA Check + auto track3B = o2::track::TrackParCov(vertexXYZ, p3B, trackDeuteron.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()) > svertexerselections.maxDCAXY3Body || std::abs(dca.getZ()) > svertexerselections.maxDCAZ3Body) { + return; + } + + return; + } + + 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)); + } +}; + +} // namespace pwglf +} // namespace o2 + +#endif // PWGLF_UTILS_DECAY3BODYBUILDERHELPER_H_ diff --git a/PWGLF/Utils/inelGt.h b/PWGLF/Utils/inelGt.h index f0a3514adc1..55c661c606a 100644 --- a/PWGLF/Utils/inelGt.h +++ b/PWGLF/Utils/inelGt.h @@ -19,6 +19,12 @@ #ifndef PWGLF_UTILS_INELGT_H_ #define PWGLF_UTILS_INELGT_H_ +#include +#include + +#include + +#include #include namespace o2 @@ -65,7 +71,7 @@ bool isINELgtNmc(TMcParticles particles, int nChToSatisfySelection, pdgDatabase ParticlesEtaAndCharge.resize(nParticles); auto etaChargeConditionFunc = [](EtaCharge elem) { - return ((TMath::Abs(elem.eta) < 1.0) && (TMath::Abs(elem.charge) > 0.001)); + return ((std::abs(elem.eta) < 1.0) && (std::abs(elem.charge) > 0.001)); }; if (std::count_if(ParticlesEtaAndCharge.begin(), ParticlesEtaAndCharge.end(), etaChargeConditionFunc) > nChToSatisfySelection) { @@ -92,7 +98,7 @@ struct ParticleCounter { bool mSelectPrimaries = true; pdgDatabase* mPdgDatabase; - float countMultInAcceptance(const aod::McParticles& mcParticles, const float etamin, const float etamax) + float countMultInAcceptance(const o2::aod::McParticles& mcParticles, const float etamin, const float etamax) { // static_assert(etamin < etamax, "etamin must be smaller than etamax"); float counter = 0; @@ -120,7 +126,7 @@ struct ParticleCounter { return counter; } - float countEnergyInAcceptance(const aod::McParticles& mcParticles, const float etamin, const float etamax, const bool requireNeutral = false) + float countEnergyInAcceptance(const o2::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; @@ -137,10 +143,10 @@ struct ParticleCounter { } // is neutral if (requireNeutral) { - if (abs(p->Charge()) > 1e-3) + if (std::abs(p->Charge()) > 1e-3) continue; } else { - if (abs(p->Charge()) <= 1e-3) + if (std::abs(p->Charge()) <= 1e-3) continue; } // in acceptance @@ -151,16 +157,20 @@ struct ParticleCounter { 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 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 countFT0A(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, 3.5f, 4.9f); } + float countFT0C(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -3.3f, -2.1f); } + float countFV0A(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, 2.2f, 5.1f); } + float countV0A(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, 2.8f, 5.1f); } + float countV0C(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -3.7f, -1.7f); } + float countFDDA(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, 4.9f, 6.3f); } + float countFDDC(const o2::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 countZNA(const o2::aod::McParticles& mcParticles) { return countEnergyInAcceptance(mcParticles, 8.8f, 100.f, true); } + float countZNC(const o2::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 countITSIB(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -2.f, 2.f); } + float countEta05(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -0.5f, 0.5f); } + float countEta08(const o2::aod::McParticles& mcParticles) { return countMultInAcceptance(mcParticles, -0.8f, 0.8f); } }; } // namespace pwglf diff --git a/PWGLF/Utils/mcParticle.h b/PWGLF/Utils/mcParticle.h index dc0f476cc8a..e85d98ca5f0 100644 --- a/PWGLF/Utils/mcParticle.h +++ b/PWGLF/Utils/mcParticle.h @@ -53,6 +53,8 @@ class PIDExtended 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"); @@ -71,59 +73,60 @@ class PIDExtended 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_assert(PIDCountsUntilAl == o2::track::PID::NIDs, "PID::NIDs mismatch"); - static constexpr ID PIDCounts = 17; // Number of indices defined in PID.h - static_assert(PIDCounts == o2::track::PID::NIDsTot, "PID::NIDsTot 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}; + 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 = 17; - static constexpr ID MuonPlus = 18; - static constexpr ID PionMinus = 19; - static constexpr ID KaonMinus = 20; - static constexpr ID AntiProton = 21; - static constexpr ID AntiDeuteron = 22; - static constexpr ID AntiTriton = 23; - static constexpr ID AntiHelium3 = 24; - static constexpr ID AntiAlpha = 25; - static constexpr ID AntiLambda = 26; - static constexpr ID AntiHyperTriton = 27; - static constexpr ID AntiHyperhydrog4 = 28; - static constexpr ID XiPlus = 29; - static constexpr ID OmegaPlus = 30; + 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 = 31; - static constexpr ID AntiNeutron = 32; - static constexpr ID HyperHelium4 = 33; - static constexpr ID AntiHyperHelium4 = 34; - static constexpr ID Phi = 35; - - static constexpr ID BZero = 36; - static constexpr ID BPlus = 37; - static constexpr ID BS = 38; - static constexpr ID D0 = 39; - static constexpr ID DPlus = 40; - static constexpr ID DS = 41; - static constexpr ID DStar = 42; - static constexpr ID ChiC1 = 43; - static constexpr ID JPsi = 44; - static constexpr ID LambdaB0 = 45; - static constexpr ID LambdaCPlus = 46; - static constexpr ID OmegaC0 = 47; - static constexpr ID SigmaC0 = 48; - static constexpr ID SigmaCPlusPlus = 49; - static constexpr ID X3872 = 50; - static constexpr ID Xi0 = 51; - static constexpr ID XiB0 = 52; - static constexpr ID XiCCPlusPlus = 53; - static constexpr ID XiCPlus = 54; - static constexpr ID XiC0 = 55; - static constexpr ID NIDsTot = 56; + 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 @@ -143,6 +146,8 @@ class PIDExtended 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 @@ -157,10 +162,10 @@ class PIDExtended "AntiHyperhydrog4", // AntiHyperhydrog4 "XiPlus", // XiPlus "OmegaPlus", // OmegaPlus + "AntiHyperHelium4", // AntiHyperHelium4 + "AntiHyperHelium5", // AntiHyperHelium5 "Neutron", // Neutron "AntiNeutron", // AntiNeutron - "HyperHelium4", // HyperHelium4 - "AntiHyperHelium4", // AntiHyperHelium4 "Phi", // Phi "BZero", // BZero "BPlus", // BPlus @@ -244,6 +249,10 @@ class PIDExtended 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: diff --git a/PWGLF/Utils/nucleiUtils.h b/PWGLF/Utils/nucleiUtils.h new file mode 100644 index 00000000000..66cc1cb7318 --- /dev/null +++ b/PWGLF/Utils/nucleiUtils.h @@ -0,0 +1,570 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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_NUCLEIUTILS_H_ +#define PWGLF_UTILS_NUCLEIUTILS_H_ + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +#include "DataFormatsTPC/BetheBlochAleph.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include "TMCProcess.h" + +#include +#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; + int nContrib; + 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 +{ + +struct SlimCandidate { + float pt = -999.f; + float eta = -999.f; + float phi = -999.f; + float tpcInnerParam = -999.f; + uint32_t clusterSizesITS = 0.f; + float TPCsignal = -999.f; + float beta = -999.f; + float DCAxy = -999.f; + float DCAz = -999.f; + uint16_t flags = 0; + int pdgCode = 0; + int motherPdgCode = 0; + float ptGenerated = -999.f; + float etaGenerated = -999.f; + float phiGenerated = -999.f; + float centrality = -1.f; + uint64_t mcProcess = TMCProcess::kPNoProcess; +}; + +enum Species { + kPr = 0, + kDe = 1, + kTr = 2, + kHe = 3, + kAl = 4, + kNspecies = 5 +}; + +enum Flags { + 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 +}; + +constexpr int getSpeciesFromPdg(int pdg) +{ + switch (std::abs(pdg)) { + case PDG_t::kProton: + return Species::kPr; + case o2::constants::physics::Pdg::kDeuteron: + return Species::kDe; + case o2::constants::physics::Pdg::kTriton: + return Species::kTr; + case o2::constants::physics::Pdg::kHelium3: + return Species::kHe; + case o2::constants::physics::Pdg::kAlpha: + return Species::kAl; + default: + return -1; + } +} + +bool checkSpeciesValidity(const int species) +{ + if (species < 0 || species > Species::kNspecies) { + return false; + } + return true; +} + +constexpr int speciesToProcessDefault[Species::kNspecies][1]{ + {0}, + {0}, + {0}, + {0}, + {0}}; +constexpr int useCentralTpcCalibrationDefault[Species::kNspecies][1]{ + {1}, + {1}, + {1}, + {1}, + {1}}; +constexpr double bbMomScalingDefault[Species::kNspecies][2]{ + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}}; +constexpr double betheBlochDefault[Species::kNspecies][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[Species::kNspecies][2]{ + {-5., 5.}, + {-5., 5.}, + {-5., 5.}, + {-5., 5.}, + {-5., 5.}}; +constexpr double nSigmaTOFdefault[Species::kNspecies][2]{ + {-5., 5.}, + {-5., 5.}, + {-5., 5.}, + {-5., 5.}, + {-5., 5.}}; +constexpr double DCAcutDefault[Species::kNspecies][2]{ + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}, + {1., 1.}}; +constexpr int TreeConfigDefault[Species::kNspecies][2]{ + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; +constexpr int FlowHistDefault[Species::kNspecies][1]{ + {0}, + {0}, + {0}, + {0}, + {0}}; +constexpr int DCAHistDefault[Species::kNspecies][2]{ + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; +constexpr double DownscalingDefault[Species::kNspecies][1]{ + {1.}, + {1.}, + {1.}, + {1.}, + {1.}}; +// constexpr bool storeTreesDefault[Species::kNspecies]{false, false, false, false, false}; +constexpr float charges[Species::kNspecies]{1.f, 1.f, 1.f, 2.f, 2.f}; +constexpr float masses[Species::kNspecies]{MassProton, MassDeuteron, MassTriton, MassHelium3, MassAlpha}; +constexpr int pdgCodes[Species::kNspecies]{PDG_t::kProton, o2::constants::physics::Pdg::kDeuteron, o2::constants::physics::Pdg::kTriton, o2::constants::physics::Pdg::kHelium3, o2::constants::physics::Pdg::kAlpha}; +static constexpr std::string_view cNames[] = {"proton", "deuteron", "triton", "He3", "alpha"}; +static const std::vector names{"proton", "deuteron", "triton", "He3", "alpha"}; +static const std::vector matter{"M", "A"}; +static const std::vector pidName{"TPC", "TOF"}; +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[Species::kNspecies][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"}; + +// Event selections + +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}}; + +template // move to nucleiUtils +bool eventSelection(const Tcollision& collision, HistogramRegistry& registry, LabeledArray eventSelections, const float cutVertex) +{ + if (!registry.contains(HIST("hVtxZBefore"))) { + registry.add("hVtxZBefore", "Vertex distribution in Z before selections;Z (cm)", {HistType::kTH1F, {{400, -20.0, 20.0}}}); + } + if (!registry.contains(HIST("hVtxZ"))) { + registry.add("hVtxZ", "Vertex distribution in Z;Z (cm)", {HistType::kTH1F, {{400, -20.0, 20.0}}}); + } + if (!registry.contains(HIST("hEventSelections"))) { + registry.add("hEventSelections", "hEventSelections", {HistType::kTH1D, {{evSel::kNevSels + 1, -0.5f, static_cast(evSel::kNevSels) + 0.5f}}}); + } + registry.fill(HIST("hEventSelections"), 0); + registry.fill(HIST("hVtxZBefore"), collision.posZ()); + + if (eventSelections.get(evSel::kTVX) && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + registry.fill(HIST("hEventSelections"), evSel::kTVX + 1); + + if (eventSelections.get(evSel::kZvtx) && std::abs(collision.posZ()) > cutVertex) { + return false; + } + registry.fill(HIST("hEventSelections"), evSel::kZvtx + 1); + + if (eventSelections.get(evSel::kTFborder) && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + registry.fill(HIST("hEventSelections"), evSel::kTFborder + 1); + + if (eventSelections.get(evSel::kITSROFborder) && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + registry.fill(HIST("hEventSelections"), evSel::kITSROFborder + 1); + + if (eventSelections.get(evSel::kNoSameBunchPileup) && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + registry.fill(HIST("hEventSelections"), evSel::kNoSameBunchPileup + 1); + + if (eventSelections.get(evSel::kIsGoodZvtxFT0vsPV) && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + registry.fill(HIST("hEventSelections"), evSel::kIsGoodZvtxFT0vsPV + 1); + + if (eventSelections.get(evSel::kIsGoodITSLayersAll) && !collision.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + registry.fill(HIST("hEventSelections"), evSel::kIsGoodITSLayersAll + 1); + + if constexpr ( + requires { + collision.triggereventep(); + }) { + if (eventSelections.get(evSel::kIsEPtriggered) && !collision.triggereventep()) { + return false; + } + registry.fill(HIST("hEventSelections"), evSel::kIsEPtriggered + 1); + } + registry.fill(HIST("hVtxZ"), collision.posZ()); + + return true; +} + +template +float getCentrality(Tcollision const& collision, const int centralityEstimator) +{ + if constexpr (!o2::aod::HasCentrality) { // requires aod::CentFV0As, aod::CentFT0Ms, aod::CentFT0As, aod::CentFT0Cs, aod::CentNTPVs + return -1.f; + } + if (centralityEstimator == centDetectors::kFV0A) { + return collision.centFV0A(); + } else if (centralityEstimator == centDetectors::kFT0M) { + return collision.centFT0M(); + } else if (centralityEstimator == centDetectors::kFT0A) { + return collision.centFT0A(); + } else if (centralityEstimator == centDetectors::kFT0C) { + return collision.centFT0C(); + } else { + LOG(warning) << "Centrality estimator not valid. Possible values: (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3). Centrality set to -1."; + } + return -1.f; +} + +// Track selections + +enum trackSelection { + kNoCuts = 0, + kTrackCuts = 1, + kPidCuts = 2, + kNtrackSelections = 3 +}; +static const std::array(trackSelection::kNtrackSelections)> trackSelectionLabels{"All", "Track cuts", "PID cuts"}; + +template +void createHistogramRegistryNucleus(HistogramRegistry& registry) +{ + + constexpr int index = iSpecies; + if (!checkSpeciesValidity(index)) { + std::runtime_error("species contains invalid nucleus index"); + } + + registry.add(fmt::format("{}/hTrackSelections", cNames[index]).c_str(), (fmt::format("{} track selections;", cNames[index]) + std::string("Selection step; Counts")).c_str(), HistType::kTH1D, {{trackSelection::kNtrackSelections, -0.5f, static_cast(trackSelection::kNtrackSelections) - 0.5f}}); + registry.add(fmt::format("{}/hPtReconstructed", cNames[index]).c_str(), (fmt::format("{} - reconstructed variables;", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c}); Counts")).c_str(), HistType::kTH1F, {{240, -6.0f, 6.0f}}); + registry.add(fmt::format("{}/h3PtVsEtaVsCentralityReconstructed", cNames[index]).c_str(), (fmt::format("{} - reconstructed variables;", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c}); #eta; CentralityFT0C (%)")).c_str(), HistType::kTH3F, {{240, -6.0f, 6.0f}, {40, -1.0f, 1.f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3PhiVsEtaVsCentralityReconstructed", cNames[index]).c_str(), (fmt::format("{} - reconstructed variables;", cNames[index]) + std::string("#phi (radians); #eta; CentralityFT0C (%)")).c_str(), HistType::kTH3F, {{40, 0, o2::constants::math::TwoPI}, {40, -1.0f, 1.f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3DCAxyVsPtVsCentrality", cNames[index]).c_str(), (fmt::format(";", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c}); DCA_{xy} (cm); CentralityFT0C (%)")).c_str(), HistType::kTH3F, {{240, -6.0f, 6.0f}, {200, -0.5f, 0.5f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3DCAzVsPtVsCentrality", cNames[index]).c_str(), (fmt::format("{};", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c}); DCA_{z} (cm); CentralityFT0C (%)")).c_str(), HistType::kTH3F, {{240, -6.0f, 6.0f}, {200, -0.5f, 0.5f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3NsigmaTPC_preselectionVsCentrality", cNames[index]).c_str(), (fmt::format("Nsigma{} TPC distribution;", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c});") + fmt::format("n#sigma_{{TPC}}({}); CentralityFT0C (%)", cNames[index])).c_str(), HistType::kTH3F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3NsigmaTPCVsCentrality", cNames[index]).c_str(), (fmt::format("Nsigma{} TPC distribution;", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c});") + fmt::format("n#sigma_{{TPC}}({}); Centrality FT0C (%)", cNames[index])).c_str(), HistType::kTH3F, {{20, -5.0f, 5.0f}, {200, -5.0f, 5.0f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3NsigmaITS_preselectionVsCentrality", cNames[index]).c_str(), (fmt::format("Nsigma{} ITS distribution;", cNames[index]) + std::string("signed #it{p}_{T} / |#it{Z}| (GeV/#it{c});") + fmt::format("n#sigma_{{ITS}}({}); Centrality FT0C (%)", cNames[index])).c_str(), HistType::kTH3F, {{50, -5.0f, 5.0f}, {120, -3.0f, 3.0f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3NsigmaITSVsCentrality", cNames[index]).c_str(), (fmt::format("Nsigma{} ITS distribution;", cNames[index]) + std::string("signed #it{p}_{T} / |#it{Z}| (GeV/#it{c});") + fmt::format("n#sigma_{{ITS}}({}); Centrality FT0C (%)", cNames[index])).c_str(), HistType::kTH3F, {{50, -5.0f, 5.0f}, {120, -3.0f, 3.0f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3NsigmaTOF_preselectionVsCentrality", cNames[index]).c_str(), (fmt::format("Nsigma{} TOF distribution;", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c});") + fmt::format("n#sigma_{{TOF}}({}); Centrality FT0C (%)", cNames[index])).c_str(), HistType::kTH3F, {{100, -5.0f, 5.0f}, {400, -10.0f, 10.0f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3NsigmaTOFVsCentrality", cNames[index]).c_str(), (fmt::format("Nsigma{} TOF distribution;", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c});") + fmt::format("n#sigma_{{TOF}}({}); Centrality FT0C (%)", cNames[index], cNames[index])).c_str(), HistType::kTH3F, {{20, -5.0f, 5.0f}, {200, -5.0f, 5.0f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3BetaVsPtVsCentrality", cNames[index]).c_str(), (fmt::format("{};", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c}); #beta; CentralityFT0C (%)")).c_str(), HistType::kTH3F, {{240, -6.0f, 6.0f}, {100, 0.0f, 1.0f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3dEdxVsPVsCentrality", cNames[index]).c_str(), (fmt::format("dEdx distribution for {};", cNames[index]) + std::string("#it{p} (GeV/#it{c}); d#it{E}/d#it{x} (a.u.); Centrality FT0C (%)")).c_str(), HistType::kTH3F, {{200, -6.0f, 6.0f}, {100, 0.0f, 2000.0f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3ClusterSizeVsPtVsCentrality", cNames[index]).c_str(), (fmt::format("{};", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c}); Cluster size ITS; CentralityFT0C (%)")).c_str(), HistType::kTH3F, {{240, -6.0f, 6.0f}, {90, 0.f, 15.f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/hPtGenerated", cNames[index]).c_str(), (fmt::format("{} - generated variables;", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c}); Counts")).c_str(), HistType::kTH1F, {{240, -6.0f, 6.0f}}); + registry.add(fmt::format("{}/h3PtVsEtaVsCentralityGenerated", cNames[index]).c_str(), (fmt::format("{} - generated variables;", cNames[index]) + std::string("#it{p}_{T} / |#it{Z}| (GeV/#it{c}); #eta; CentralityFT0C (%)")).c_str(), HistType::kTH3F, {{240, -6.0f, 6.0f}, {40, -1.0f, 1.f}, {20, 0.0f, 100.0f}}); + registry.add(fmt::format("{}/h3PhiVsEtaVsCentralityGenerated", cNames[index]).c_str(), (fmt::format("{} - generated variables;", cNames[index]) + std::string("#phi (radians); #eta; CentralityFT0C (%)")).c_str(), HistType::kTH3F, {{40, 0, o2::constants::math::TwoPI}, {40, -1.0f, 1.f}, {20, 0.0f, 100.0f}}); + + for (size_t iSel = 0; iSel < trackSelection::kNtrackSelections; iSel++) { + registry.get(HIST(cNames[index]) + HIST("/hTrackSelections"))->GetXaxis()->SetBinLabel(iSel + 1, trackSelectionLabels[iSel].c_str()); + } +}; + +// PID manager class + +class PidManager +{ + + public: + explicit PidManager(const int species, const float* tpcBetheBlochParams = nullptr) + : mSpecies(species) + { + if (!checkSpeciesValidity(species)) { + std::runtime_error("species contains invalid nucleus index"); + } + + if (!tpcBetheBlochParams) { + mUseTpcCentralCalibration = true; + return; + } + + for (int i = 0; i < 6; i++) { + mTpcBetheBlochParams[i] = tpcBetheBlochParams[i]; + } + } + PidManager() = default; + ~PidManager() = default; + + // TOF + template + float getBetaTOF(const Ttrack& track) + { + if (!track.hasTOF()) + return -999.f; + float beta = o2::pid::tof::Beta::GetBeta(track); + return std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked + } + + template + float getMassTOF(const Ttrack& track) + { + if (!track.hasTOF()) + return -999.f; + const float charge{1.f + static_cast(mSpecies == Species::kHe || mSpecies == Species::kAl)}; + const float beta = getBetaTOF(track); + return track.tpcInnerParam() * charge * std::sqrt(1.f / (beta * beta) - 1.f); + } + + template + float getNSigmaTOF(const Ttrack& track) + { + if (!track.hasTOF()) + return -999.f; + + switch (mSpecies) { + case Species::kPr: + return track.tofNSigmaPr(); + case Species::kDe: + return track.tofNSigmaDe(); + case Species::kTr: + return track.tofNSigmaTr(); + case Species::kHe: + return track.tofNSigmaHe(); + case Species::kAl: + return track.tofNSigmaAl(); + default: + return -999.f; + } + } + + // ITS + template + float getClusterSizeCosLambdaITS(const Ttrack& track) + { + return mResponseITS.averageClusterSize(track.itsClusterSizes()) / std::cosh(track.eta()); + } + + float getClusterSizeCosLambdaITS(const u_int32_t clusterSizesITS, const float eta) + { + return mResponseITS.averageClusterSize(clusterSizesITS) / std::cosh(eta); + } + + template + float getNSigmaITS(const Ttrack& track) + { + switch (mSpecies) { + case Species::kPr: + return mResponseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()); + case Species::kDe: + return mResponseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()); + case Species::kTr: + return mResponseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()); + case Species::kHe: + return mResponseITS.nSigmaITS(track.itsClusterSizes(), 2. * track.p(), track.eta()); + case Species::kAl: + return mResponseITS.nSigmaITS(track.itsClusterSizes(), 2. * track.p(), track.eta()); + default: + return -999.f; + } + } + + // TPC + float getExpectedTPCsignal(const float p) + { + if (mUseTpcCentralCalibration) + return -999.f; + + float pScaled = p * mMomScaling[0] + mMomScaling[1]; + float betaGamma = pScaled / masses[mSpecies]; + return tpc::BetheBlochAleph(betaGamma, + mTpcBetheBlochParams[0], + mTpcBetheBlochParams[1], + mTpcBetheBlochParams[2], + mTpcBetheBlochParams[3], + mTpcBetheBlochParams[4]); + } + + template + float getNSigmaTPC(const Ttrack& track) + { + if (mUseTpcCentralCalibration) { + return getNSigmaTPCcentral(track); + } + float expectedSignal = getExpectedTPCsignal(track.tpcInnerParam()); + float resolution = mTpcBetheBlochParams[5]; + return (track.tpcSignal() - expectedSignal) / (expectedSignal * resolution); + } + + protected: + // TPC + template + float getNSigmaTPCcentral(const Ttrack& track) + { + switch (mSpecies) { + case Species::kPr: + return track.tpcNSigmaPr(); + case Species::kDe: + return track.tpcNSigmaDe(); + case Species::kTr: + return track.tpcNSigmaTr(); + case Species::kHe: + return track.tpcNSigmaHe(); + case Species::kAl: + return track.tpcNSigmaAl(); + default: + return -999.f; + } + } + + private: + float mTpcBetheBlochParams[6]; + bool mUseTpcCentralCalibration = true; // this just becomes a check for the null pointer in the parameters + o2::aod::ITSResponse mResponseITS; + float mMomScaling[2]{1., 0.}; + int mSpecies; +}; + +} // namespace nuclei + +#endif // PWGLF_UTILS_NUCLEIUTILS_H_ diff --git a/PWGLF/Utils/pidTOFGeneric.h b/PWGLF/Utils/pidTOFGeneric.h new file mode 100644 index 00000000000..3e7dfd58c23 --- /dev/null +++ b/PWGLF/Utils/pidTOFGeneric.h @@ -0,0 +1,496 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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.h +/// \brief Utilities to recalculate secondary tracks TOF PID +/// \author Yuanzhe Wang +/// + +#ifndef PWGLF_UTILS_PIDTOFGENERIC_H_ +#define PWGLF_UTILS_PIDTOFGENERIC_H_ +#include "CollisionTypeHelper.h" +#include "MetadataHelper.h" +#include "TableHelper.h" + +#include "Common/Core/PID/PIDTOF.h" + +#include "CommonDataFormat/InteractionRecord.h" + +#include +#include + +namespace o2::aod +{ + +namespace pidtofgeneric +{ + +// Configuration common to all tasks, copied from pidTOFMerge.cxx but add metadataInfo as a member variable +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; } + + o2::common::core::MetadataHelper metadataInfo; // additional member variable to store metadata information compared to pidTOFMerge.cxx + + 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; +}; + +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::TOFResoParamsV3 mRespParamsV3; + 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::TOFResoParamsV3 const& para) + { + mRespParamsV3.setParameters(para); + } + + void SetPidType(o2::track::PID::ID pidId) + { + pidType = pidId; + } + + template + float GetTOFNSigma(o2::track::PID::ID pidId, const ParamType& parameters, TTrack const& track, TCollision const& originalcol, TCollision const& correctedcol, bool EnableBCAO2D = true); + + template + float GetTOFNSigma(const ParamType& parameters, TTrack const& track, TCollision const& originalcol, TCollision const& correctedcol, bool EnableBCAO2D = true); + + template + float GetTOFNSigma(const ParamType& parameters, TTrack const& track); + template + float GetTOFNSigma(o2::track::PID::ID pidId, const ParamType& parameters, TTrack const& track); + + template + float CalculateTOFNSigma(o2::track::PID::ID pidId, const ParamType& parameters, TTrack const& track, double tofsignal, double evTime, double evTimeErr) + { + + float expSigma, tofNsigma = -999; + + switch (pidId) { + case 0: + expSigma = responseEl.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseEl.GetCorrectedExpectedSignal(parameters, track)) / expSigma; + break; + case 1: + expSigma = responseMu.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseMu.GetCorrectedExpectedSignal(parameters, track)) / expSigma; + break; + case 2: + expSigma = responsePi.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responsePi.GetCorrectedExpectedSignal(parameters, track)) / expSigma; + break; + case 3: + expSigma = responseKa.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseKa.GetCorrectedExpectedSignal(parameters, track)) / expSigma; + break; + case 4: + expSigma = responsePr.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responsePr.GetCorrectedExpectedSignal(parameters, track)) / expSigma; + break; + case 5: + expSigma = responseDe.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseDe.GetCorrectedExpectedSignal(parameters, track)) / expSigma; + break; + case 6: + expSigma = responseTr.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseTr.GetCorrectedExpectedSignal(parameters, track)) / expSigma; + break; + case 7: + expSigma = responseHe.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseHe.GetCorrectedExpectedSignal(parameters, track)) / expSigma; + break; + case 8: + expSigma = responseAl.GetExpectedSigma(parameters, track, tofsignal, evTimeErr); + tofNsigma = (tofsignal - evTime - responseAl.GetCorrectedExpectedSignal(parameters, 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, const ParamType& parameters, 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() * std::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, parameters, track, tofsignal, evTime, evTimeErr); + return tofNsigma; +} + +template +template +float TofPidNewCollision::GetTOFNSigma(const ParamType& parameters, TTrack const& track, TCollision const& originalcol, TCollision const& correctedcol, bool EnableBCAO2D) +{ + return GetTOFNSigma(pidType, parameters, track, originalcol, correctedcol, EnableBCAO2D); +} + +template +template +float TofPidNewCollision::GetTOFNSigma(o2::track::PID::ID pidId, const ParamType& parameters, TTrack const& track) +{ + + if (!track.has_collision() || !track.hasTOF()) { + return -999; + } + + float mMassHyp = o2::track::pid_constants::sMasses2Z[track.pidForTracking()]; + float expTime = track.length() * std::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, parameters, track, tofsignal, evTime, evTimeErr); + return tofNsigma; +} + +template +template +float TofPidNewCollision::GetTOFNSigma(const ParamType& parameters, TTrack const& track) +{ + return GetTOFNSigma(pidType, parameters, track); +} + +} // namespace pidtofgeneric +} // namespace o2::aod + +#endif // PWGLF_UTILS_PIDTOFGENERIC_H_ diff --git a/PWGLF/Utils/rsnOutput.h b/PWGLF/Utils/rsnOutput.h index 7d61441462c..f6540cd6d48 100644 --- a/PWGLF/Utils/rsnOutput.h +++ b/PWGLF/Utils/rsnOutput.h @@ -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. // @@ -9,20 +9,19 @@ // 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_ -#include -#include -#include - #include "Framework/HistogramRegistry.h" #include "Framework/Logger.h" -using namespace o2::framework; +#include +#include +#include namespace o2::analysis { @@ -47,10 +46,10 @@ enum class PairType { likemm, unliketrue, unlikegen, + unlikegenold, mixingpm, - mixingpp, - mixingmm, mixingmp, + rotationpm, all }; @@ -70,41 +69,58 @@ enum class PairAxisType { unknown }; +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 PairAxis +namespace pair_axis { std::vector names{"im", "pt", "mu", "ce", "ns1", "ns2", "eta", "y", "vz", "mum", "cem", "vzm"}; } -namespace SystematicsAxis +namespace systematic_axis { std::vector names{"ncl"}; } + class Output { public: virtual ~Output() = default; - virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, 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, bool /*produceRotational*/ = 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(PairAxis::names[static_cast(i)])) { - LOGF(fatal, "rsn::Output::Error: Order in allAxes is not correct !!! Expected axis '%s' and has '%s'.", aname.c_str(), PairAxis::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)); @@ -120,27 +136,27 @@ 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(SystematicsAxis::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(), SystematicsAxis::names[static_cast(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 currentType_sys; - for (auto& c : sysAxes) { - currentType_sys = type_sys(c); - if (currentType_sys >= SystematicsAxisType::unknown) { - LOGF(warning, "Found unknown axis (rsn::SystematicsAxisType = %d)!!! Skipping ...", static_cast(currentType_sys)); + 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(currentType_sys)]); - mCurrentAxisTypesSys.push_back(currentType_sys); + mCurrentAxesSys.push_back(allAxes_sys[static_cast(currentTypeSys)]); + mCurrentAxisTypesSys.push_back(currentTypeSys); } if (mFillPointSys != nullptr) @@ -148,14 +164,14 @@ class Output mFillPointSys = new double[mCurrentAxisTypesSys.size()]; LOGF(info, "Number of systematic axis added: %d", mCurrentAxesSys.size()); - mPairHistoSys = new HistogramConfigSpec(HistType::kTHnSparseF, mCurrentAxesSys); + 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); @@ -165,7 +181,7 @@ class Output void fillSparseSys(const T& h, double* point) { int i = 0; - for (auto& at : mCurrentAxisTypesSys) { + for (const auto& at : mCurrentAxisTypesSys) { mFillPointSys[i++] = point[static_cast(at)]; } mHistogramRegistry->get(h)->Fill(mFillPointSys); @@ -190,55 +206,55 @@ 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 fillRotationpm(double* point) = 0; virtual void fillSystematics(double* point) = 0; PairAxisType type(std::string name) { - auto it = std::find(PairAxis::names.begin(), PairAxis::names.end(), name); - if (it == PairAxis::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(PairAxis::names.begin(), it)); + return static_cast(std::distance(pair_axis::names.begin(), it)); } - SystematicsAxisType type_sys(std::string name) + SystematicsAxisType typeSys(std::string name) { - auto it = std::find(SystematicsAxis::names.begin(), SystematicsAxis::names.end(), name); - if (it == SystematicsAxis::names.end()) { + 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(SystematicsAxis::names.begin(), it)); + return static_cast(std::distance(systematic_axis::names.begin(), it)); } std::string name(PairAxisType type) { - return PairAxis::names[(static_cast(type))]; + return pair_axis::names[(static_cast(type))]; } - std::string name_sys(SystematicsAxisType type) + std::string nameSys(SystematicsAxisType type) { - return SystematicsAxis::names[(static_cast(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; - HistogramConfigSpec* mPairHistoSys = 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 mCurrentAxesSys; std::vector mCurrentAxisTypesSys; double* mFillPoint = nullptr; double* mFillPointSys = nullptr; @@ -247,12 +263,11 @@ class Output class OutputSparse : public Output { public: - virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, 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, bool produceRotational = false, o2::framework::HistogramRegistry* registry = nullptr) { - Output::init(sparseAxes, allAxes, sysAxes, allAxes_sys, produceTrue, eventMixing, produceLikesign, registry); + Output::init(sparseAxes, allAxes, sysAxes, allAxes_sys, produceTrue, eventMixing, produceLikesign, produceRotational, registry); mHistogramRegistry->add("unlikepm", "Unlike pm", *mPairHisto); - // mHistogramRegistry->add("unlikemp", "Unlike mp", *mPairHisto); if (produceLikesign) { mHistogramRegistry->add("likepp", "Like PP", *mPairHisto); mHistogramRegistry->add("likemm", "Like MM", *mPairHisto); @@ -260,16 +275,15 @@ 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); - mHistogramRegistry->add("mixingmm", "Event Mixing mm", *mPairHisto); - } mHistogramRegistry->add("mixingmp", "Event Mixing mp", *mPairHisto); } - + if (produceRotational) { + mHistogramRegistry->add("rotationpm", "Rotational pm", *mPairHisto); + } mHistogramRegistry->add("Mapping/systematics", "Systematics mapping", *mPairHistoSys); } @@ -306,18 +320,18 @@ class OutputSparse : public Output case PairType::unlikegen: fillUnlikegen(point); break; + case PairType::unlikegenold: + fillUnlikegenOld(point); + break; case PairType::mixingpm: fillMixingpm(point); break; - case PairType::mixingpp: - fillMixingpp(point); - break; - case PairType::mixingmm: - fillMixingmm(point); - break; case PairType::mixingmp: fillMixingmp(point); break; + case PairType::rotationpm: + fillRotationpm(point); + break; default: break; } @@ -335,37 +349,34 @@ class OutputSparse : public Output { fillSparse(HIST("likepp"), point); } - virtual void fillLikemm(double* point) { fillSparse(HIST("likemm"), point); } - virtual void fillUnliketrue(double* point) { fillSparse(HIST("unliketrue"), point); } - virtual void fillUnlikegen(double* point) { fillSparse(HIST("unlikegen"), point); } - virtual void fillMixingpm(double* point) - { - fillSparse(HIST("mixingpm"), point); - } - virtual void fillMixingpp(double* point) + virtual void fillUnlikegenOld(double* point) { - fillSparse(HIST("mixingpp"), point); + fillSparse(HIST("unlikegenold"), point); } - virtual void fillMixingmm(double* point) + virtual void fillMixingpm(double* point) { - fillSparse(HIST("mixingmm"), point); + fillSparse(HIST("mixingpm"), point); } virtual void fillMixingmp(double* point) { fillSparse(HIST("mixingmp"), point); } + virtual void fillRotationpm(double* point) + { + fillSparse(HIST("rotationpm"), point); + } virtual void fillSystematics(double* point) { fillSparse(HIST("Mapping/systematics"), point); diff --git a/PWGLF/Utils/strangenessBuilderHelper.h b/PWGLF/Utils/strangenessBuilderHelper.h new file mode 100644 index 00000000000..46210d0dcfe --- /dev/null +++ b/PWGLF/Utils/strangenessBuilderHelper.h @@ -0,0 +1,1336 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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(debug, "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; + float v0DCAToPVxy = 0.0f; + float v0DCAToPVz = 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 + // --- useSelections: meant to maximize recovery, but beware high cost in CPU + // --- calculateProngDCAtoPV: optionally don't propagate prongs to PV, saves + // CPU, of interest when dealing with de-duplication (variable not checked) + 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) + { + v0 = {}; // safe initialization: start new + + 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() && !positiveTrack.hasTRD() && !positiveTrack.hasTOF()) { + v0 = {}; + return false; + } + if (!acceptTPCOnly && !negativeTrack.hasITS() && !negativeTrack.hasTRD() && !negativeTrack.hasTOF()) { + v0 = {}; + return false; + } + } + + if constexpr (calculateProngDCAtoPV) { + // Calculate DCA with respect to the collision associated to the V0 + std::array dcaInfo; + + // do DCA to PV on TrackPar copies and not TrackParCov + // TrackPar preferred: don't calculate multiple scattering / CovMat changes + // Spares CPU since variables not checked + o2::track::TrackPar positiveTrackParamCopy(positiveTrackParam); + o2::track::TrackPar negativeTrackParamCopy(negativeTrackParam); + + dcaInfo[0] = dcaInfo[1] = 999.0f; // by default, take large value to make sure candidate accepted + 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.dcapostopv) { + v0 = {}; + return false; + } + } + + dcaInfo[0] = dcaInfo[1] = 999.0f; // by default, take large value to make sure candidate accepted + 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; + } + } + } else { + v0.positiveDCAxy = 0.0f; // default invalid + v0.negativeDCAxy = 0.0f; // default invalid + } + + // Perform DCA fit + int nCand = 0; + fitter.setCollinear(useCollinearFit); + try { + nCand = fitter.process(positiveTrackParam, negativeTrackParam); + } catch (...) { + v0 = {}; + fitter.setCollinear(false); // even if returned, reset + return false; + } + if (nCand == 0) { + v0 = {}; + fitter.setCollinear(false); // even if returned, reset + return false; + } + fitter.setCollinear(false); // proper cleaning: when exiting this loop, always reset to not collinear + + // Calculate DCAToPV of the V0 + o2::track::TrackPar V0Temp = fitter.createParentTrackPar(); + V0Temp.setAbsCharge(0); // charge zero + std::array dcaV0Info; + + // propagate to collision vertex + dcaV0Info[0] = dcaV0Info[1] = 999.0f; // default DCA: large, use with care if propagation fails + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, V0Temp, 2.f, fitter.getMatCorrType(), &dcaV0Info); + v0.v0DCAToPVxy = dcaV0Info[0]; + v0.v0DCAToPVz = dcaV0Info[1]; + + 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 + std::array dcaInfo; + + // do DCA to PV on TrackPar copies and not TrackParCov + // TrackPar preferred: don't calculate multiple scattering / CovMat changes + // Spares CPU since variables not checked + o2::track::TrackPar positiveTrackParamCopy(positiveTrackParam); + o2::track::TrackPar negativeTrackParamCopy(negativeTrackParam); + + dcaInfo[0] = dcaInfo[1] = 999.0f; // by default, take large value to make sure candidate accepted + 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; + } + + dcaInfo[0] = dcaInfo[1] = 999.0f; // reset to default value + 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) + { + cascade = {}; // initialize / empty (extra safety) + + // 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 + std::array dcaInfo; + dcaInfo[0] = dcaInfo[1] = 999.0f; // by default, take large value to make sure candidate accepted + + 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) + { + cascade = {}; // initialize / empty (extra safety) + + //*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<*>~<* + // 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 + std::array dcaInfo; + dcaInfo[0] = dcaInfo[1] = 999.0f; // by default, take large value to make sure candidate accepted + + auto bachTrackPar = getTrackPar(bachelorTrack); + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, bachTrackPar, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.bachelorDCAxy = dcaInfo[0]; + + dcaInfo[0] = dcaInfo[1] = 999.0f; // by default, take large value to make sure candidate accepted + o2::track::TrackParCov posTrackParCovForDCA = getTrackParCov(positiveTrack); + o2::base::Propagator::Instance()->propagateToDCABxByBz({pvX, pvY, pvZ}, posTrackParCovForDCA, 2.f, fitter.getMatCorrType(), &dcaInfo); + cascade.positiveDCAxy = dcaInfo[0]; + + dcaInfo[0] = dcaInfo[1] = 999.0f; // by default, take large value to make sure candidate accepted + 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 + std::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 + std::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 + std::array dcaInfo; + dcaInfo[0] = dcaInfo[1] = 999.0f; // by default, take large value + + // 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/strangenessBuilderModule.h b/PWGLF/Utils/strangenessBuilderModule.h new file mode 100644 index 00000000000..61371ff59ec --- /dev/null +++ b/PWGLF/Utils/strangenessBuilderModule.h @@ -0,0 +1,2581 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file strangenessBuilderModule.h +/// \brief strangeness builder module +/// \author ALICE + +#ifndef PWGLF_UTILS_STRANGENESSBUILDERMODULE_H_ +#define PWGLF_UTILS_STRANGENESSBUILDERMODULE_H_ + +// simple checkers, but ensure 8 bit integers +#define BITSET(var, nbit) ((var) |= (static_cast(1) << static_cast(nbit))) + +#include "TableHelper.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/strangenessBuilderHelper.h" + +#include "Common/Core/TPCVDriftManager.h" + +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/Configurable.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/HistogramSpec.h" + +#include +#include +#include +#include +#include +#include + +//__________________________________________ +// strangeness builder module + +namespace o2 +{ +namespace pwglf +{ +namespace strangenessbuilder // avoid polluting other namespaces +{ + +// statics necessary for the configurables in this namespace +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}}; + +// 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 }; + +enum V0PreSelection : uint8_t { selGamma = 0, + selK0Short, + selLambda, + selAntiLambda }; + +enum CascPreSelection : uint8_t { selXiMinus = 0, + selXiPlus, + selOmegaMinus, + selOmegaPlus }; + +static constexpr float defaultK0MassWindowParameters[1][4] = {{2.81882e-03, 1.14057e-03, 1.72138e-03, 5.00262e-01}}; +static constexpr float defaultLambdaWindowParameters[1][4] = {{1.17518e-03, 1.24099e-04, 5.47937e-03, 3.08009e-01}}; +static constexpr float defaultXiMassWindowParameters[1][4] = {{1.43210e-03, 2.03561e-04, 2.43187e-03, 7.99668e-01}}; +static constexpr float defaultOmMassWindowParameters[1][4] = {{1.43210e-03, 2.03561e-04, 2.43187e-03, 7.99668e-01}}; + +static constexpr float defaultLifetimeCuts[1][4] = {{20, 60, 40, 20}}; + +struct products : o2::framework::ProducesGroup { + //__________________________________________________ + // V0 tables + o2::framework::Produces v0indices; // standard part of V0Datas + o2::framework::Produces v0cores; // standard part of V0Datas + o2::framework::Produces v0covs; // for decay chain reco + + //__________________________________________________ + // cascade tables + o2::framework::Produces cascidx; // standard part of CascDatas + o2::framework::Produces kfcascidx; // standard part of KFCascDatas + o2::framework::Produces tracascidx; // standard part of TraCascDatas + o2::framework::Produces cascdata; // standard part of CascDatas + o2::framework::Produces kfcascdata; // standard part of KFCascDatas + o2::framework::Produces tracascdata; // standard part of TraCascDatas + o2::framework::Produces casccovs; // for decay chain reco + o2::framework::Produces kfcasccovs; // for decay chain reco + o2::framework::Produces tracasccovs; // for decay chain reco + + //__________________________________________________ + // interlink tables + o2::framework::Produces v0dataLink; // de-refs V0s -> V0Data + o2::framework::Produces cascdataLink; // de-refs Cascades -> CascData + o2::framework::Produces kfcascdataLink; // de-refs Cascades -> KFCascData + o2::framework::Produces tracascdataLink; // de-refs Cascades -> TraCascData + + //__________________________________________________ + // secondary auxiliary tables + o2::framework::Produces v0trackXs; // for decay chain reco + o2::framework::Produces cascTrackXs; // for decay chain reco + + //__________________________________________________ + // further auxiliary / optional if desired + o2::framework::Produces cascbb; + o2::framework::Produces v0daucovs; // covariances of daughter tracks + o2::framework::Produces v0daucovIUs; // covariances of daughter tracks + o2::framework::Produces v0dauPositions; // auxiliary debug information + o2::framework::Produces v0dauPositionsIU; // auxiliary debug information + o2::framework::Produces v0ivanovs; // information for Marian's tests + + //__________________________________________________ + // MC information: V0 + o2::framework::Produces v0labels; // MC labels for V0s + o2::framework::Produces v0mccores; // mc info storage + o2::framework::Produces v0CoreMCLabels; // interlink V0Cores -> V0MCCores + o2::framework::Produces v0mccollref; // references collisions from V0MCCores + + // MC information: Cascades + o2::framework::Produces casclabels; // MC labels for cascades + o2::framework::Produces kfcasclabels; // MC labels for KF cascades + o2::framework::Produces tracasclabels; // MC labels for tracked cascades + o2::framework::Produces bbtags; // bb tags (inv structure tagging in mc) + o2::framework::Produces cascmccores; // mc info storage + o2::framework::Produces cascCoreMClabels; // interlink CascCores -> CascMCCores + o2::framework::Produces cascmccollrefs; // references MC collisions from MC cascades + + //__________________________________________________ + // cascade interlinks + // FIXME: commented out until strangederivedbuilder adjusted accordingly + // o2::framework::Produces cascToTraRefs; // cascades -> tracked + // o2::framework::Produces cascToKFRefs; // cascades -> KF + // o2::framework::Produces traToCascRefs; // tracked -> cascades + // o2::framework::Produces kfToCascRefs; // KF -> cascades + + //__________________________________________________ + // Findable tags + o2::framework::Produces v0FoundTag; + o2::framework::Produces cascFoundTag; +}; + +// strangenessBuilder: 1st-order configurables +struct coreConfigurables : o2::framework::ConfigurableGroup { + o2::framework::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 + + // first order deduplication implementation + // more algorithms to be added as necessary + o2::framework::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) + o2::framework::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"}; + + o2::framework::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"}; + + // test the possibility of refitting with material corrections (DCA Fitter option) + o2::framework::Configurable refitWithMaterialCorrection{"refitWithMaterialCorrection", false, "do refit after material corrections were applied"}; +}; + +// strangenessBuilder: V0 building options +struct v0Configurables : o2::framework::ConfigurableGroup { + std::string prefix = "v0BuilderOpts"; + o2::framework::Configurable generatePhotonCandidates{"generatePhotonCandidates", false, "generate gamma conversion candidates (V0s using TPC-only tracks)"}; + o2::framework::Configurable moveTPCOnlyTracks{"moveTPCOnlyTracks", true, "if dealing with TPC-only tracks, move them according to TPC drift / time info"}; + + // baseline conditionals of V0 building + o2::framework::Configurable minCrossedRows{"minCrossedRows", 50, "minimum TPC crossed rows for daughter tracks"}; + o2::framework::Configurable dcanegtopv{"dcanegtopv", .1, "DCA Neg To PV"}; + o2::framework::Configurable dcapostopv{"dcapostopv", .1, "DCA Pos To PV"}; + o2::framework::Configurable v0cospa{"v0cospa", 0.95, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0) + o2::framework::Configurable dcav0dau{"dcav0dau", 1.0, "DCA V0 Daughters"}; + o2::framework::Configurable v0radius{"v0radius", 0.9, "v0radius"}; + o2::framework::Configurable maxDaughterEta{"maxDaughterEta", 5.0, "Maximum daughter eta (in abs value)"}; + + // MC builder options + o2::framework::Configurable mc_populateV0MCCoresSymmetric{"mc_populateV0MCCoresSymmetric", false, "populate V0MCCores table for derived data analysis, keep V0MCCores joinable with V0Cores"}; + o2::framework::Configurable mc_populateV0MCCoresAsymmetric{"mc_populateV0MCCoresAsymmetric", true, "populate V0MCCores table for derived data analysis, create V0Cores -> V0MCCores interlink. Saves only labeled V0s."}; + o2::framework::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!"}; + o2::framework::Configurable mc_rapidityWindow{"mc_rapidityWindow", 0.5, "rapidity window to save non-recoed candidates"}; + o2::framework::Configurable mc_keepOnlyPhysicalPrimary{"mc_keepOnlyPhysicalPrimary", false, "Keep only physical primary generated V0s if not recoed"}; + o2::framework::Configurable mc_addGeneratedK0Short{"mc_addGeneratedK0Short", true, "add V0MCCore entry for generated, not-recoed K0Short"}; + o2::framework::Configurable mc_addGeneratedLambda{"mc_addGeneratedLambda", true, "add V0MCCore entry for generated, not-recoed Lambda"}; + o2::framework::Configurable mc_addGeneratedAntiLambda{"mc_addGeneratedAntiLambda", true, "add V0MCCore entry for generated, not-recoed AntiLambda"}; + o2::framework::Configurable mc_addGeneratedGamma{"mc_addGeneratedGamma", false, "add V0MCCore entry for generated, not-recoed Gamma"}; + o2::framework::Configurable mc_addGeneratedGammaMakeCollinear{"mc_addGeneratedGammaMakeCollinear", true, "when adding findable gammas, mark them as collinear"}; + o2::framework::Configurable mc_findableDetachedV0{"mc_findableDetachedV0", false, "if true, generate findable V0s that have collisionId -1. Caution advised."}; +}; + +// strangenessBuilder: cascade building options +struct cascadeConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "cascadeBuilderOpts"; + o2::framework::Configurable useCascadeMomentumAtPrimVtx{"useCascadeMomentumAtPrimVtx", false, "use cascade momentum at PV"}; + + // conditionals + o2::framework::Configurable minCrossedRows{"minCrossedRows", 50, "minimum TPC crossed rows for daughter tracks"}; + o2::framework::Configurable dcabachtopv{"dcabachtopv", .05, "DCA Bach To PV"}; + o2::framework::Configurable cascradius{"cascradius", 0.9, "cascradius"}; + o2::framework::Configurable casccospa{"casccospa", 0.95, "casccospa"}; + o2::framework::Configurable dcacascdau{"dcacascdau", 1.0, "DCA cascade Daughters"}; + o2::framework::Configurable lambdaMassWindow{"lambdaMassWindow", .010, "Distance from Lambda mass (does not apply to KF path)"}; + o2::framework::Configurable maxDaughterEta{"maxDaughterEta", 5.0, "Maximum daughter eta (in abs value)"}; + + // KF building specific + o2::framework::Configurable kfTuneForOmega{"kfTuneForOmega", false, "if enabled, take main cascade properties from Omega fit instead of Xi fit (= default)"}; + o2::framework::Configurable kfConstructMethod{"kfConstructMethod", 2, "KF Construct Method"}; + o2::framework::Configurable kfUseV0MassConstraint{"kfUseV0MassConstraint", true, "KF: use Lambda mass constraint"}; + o2::framework::Configurable kfUseCascadeMassConstraint{"kfUseCascadeMassConstraint", false, "KF: use Cascade mass constraint - WARNING: not adequate for inv mass analysis of Xi"}; + o2::framework::Configurable kfDoDCAFitterPreMinimV0{"kfDoDCAFitterPreMinimV0", true, "KF: do DCAFitter pre-optimization before KF fit to include material corrections for V0"}; + o2::framework::Configurable kfDoDCAFitterPreMinimCasc{"kfDoDCAFitterPreMinimCasc", true, "KF: do DCAFitter pre-optimization before KF fit to include material corrections for Xi"}; + + // MC builder options + o2::framework::Configurable mc_populateCascMCCoresSymmetric{"mc_populateCascMCCoresSymmetric", false, "populate CascMCCores table for derived data analysis, keep CascMCCores joinable with CascCores"}; + o2::framework::Configurable mc_populateCascMCCoresAsymmetric{"mc_populateCascMCCoresAsymmetric", true, "populate CascMCCores table for derived data analysis, create CascCores -> CascMCCores interlink. Saves only labeled Cascades."}; + o2::framework::Configurable mc_addGeneratedXiMinus{"mc_addGeneratedXiMinus", true, "add CascMCCore entry for generated, not-recoed XiMinus"}; + o2::framework::Configurable mc_addGeneratedXiPlus{"mc_addGeneratedXiPlus", true, "add CascMCCore entry for generated, not-recoed XiPlus"}; + o2::framework::Configurable mc_addGeneratedOmegaMinus{"mc_addGeneratedOmegaMinus", true, "add CascMCCore entry for generated, not-recoed OmegaMinus"}; + o2::framework::Configurable mc_addGeneratedOmegaPlus{"mc_addGeneratedOmegaPlus", true, "add CascMCCore entry for generated, not-recoed OmegaPlus"}; + o2::framework::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!"}; + o2::framework::Configurable mc_rapidityWindow{"mc_rapidityWindow", 0.5, "rapidity window to save non-recoed candidates"}; + o2::framework::Configurable mc_keepOnlyPhysicalPrimary{"mc_keepOnlyPhysicalPrimary", false, "Keep only physical primary generated cascades if not recoed"}; + o2::framework::Configurable mc_findableDetachedCascade{"mc_findableDetachedCascade", false, "if true, generate findable cascades that have collisionId -1. Caution advised."}; +}; + +// preselection options +struct preSelectOpts : o2::framework::ConfigurableGroup { + std::string prefix = "preSelectOpts"; + o2::framework::Configurable preselectOnlyDesiredV0s{"preselectOnlyDesiredV0s", false, "preselect only V0s with compatible TPC PID and mass info"}; + o2::framework::Configurable preselectOnlyDesiredCascades{"preselectOnlyDesiredCascades", false, "preselect only Cascades with compatible TPC PID and mass info"}; + + // lifetime preselection options + // apply lifetime cuts to V0 and cascade candidates + // unit of measurement: centimeters + // lifetime of K0Short ~2.6844 cm, no feeddown and plenty to cut + // lifetime of Lambda ~7.9 cm but keep in mind feeddown from cascades + // lifetime of Xi ~4.91 cm + // lifetime of Omega ~2.461 cm + o2::framework::Configurable> lifetimeCut{"lifetimeCut", {defaultLifetimeCuts[0], 4, {"lifetimeCutK0S", "lifetimeCutLambda", "lifetimeCutXi", "lifetimeCutOmega"}}, "Lifetime cut for V0s and cascades (cm)"}; + + // mass preselection options + o2::framework::Configurable massCutPhoton{"massCutPhoton", 0.3, "Photon max mass"}; + o2::framework::Configurable> massCutK0{"massCutK0", {defaultK0MassWindowParameters[0], 4, {"constant", "linear", "expoConstant", "expoRelax"}}, "mass parameters for K0"}; + o2::framework::Configurable> massCutLambda{"massCutLambda", {defaultLambdaWindowParameters[0], 4, {"constant", "linear", "expoConstant", "expoRelax"}}, "mass parameters for Lambda"}; + o2::framework::Configurable> massCutXi{"massCutXi", {defaultXiMassWindowParameters[0], 4, {"constant", "linear", "expoConstant", "expoRelax"}}, "mass parameters for Xi"}; + o2::framework::Configurable> massCutOm{"massCutOm", {defaultOmMassWindowParameters[0], 4, {"constant", "linear", "expoConstant", "expoRelax"}}, "mass parameters for Omega"}; + o2::framework::Configurable massWindownumberOfSigmas{"massWindownumberOfSigmas", 20, "number of sigmas around mass peaks to keep"}; + o2::framework::Configurable massWindowSafetyMargin{"massWindowSafetyMargin", 0.001, "Extra mass window safety margin (in GeV/c2)"}; + + // TPC PID preselection options + o2::framework::Configurable maxTPCpidNsigma{"maxTPCpidNsigma", 5.0, "Maximum TPC PID N sigma (in abs value)"}; +}; + +class BuilderModule +{ + public: + BuilderModule() + { + // constructor + } + + // mass windows + float getMassSigmaK0Short(float pt) + { + return preSelectOpts.massCutK0->get("constant") + pt * preSelectOpts.massCutK0->get("linear") + preSelectOpts.massCutK0->get("expoConstant") * TMath::Exp(-pt / preSelectOpts.massCutK0->get("expoRelax")); + } + float getMassSigmaLambda(float pt) + { + return preSelectOpts.massCutLambda->get("constant") + pt * preSelectOpts.massCutLambda->get("linear") + preSelectOpts.massCutLambda->get("expoConstant") * TMath::Exp(-pt / preSelectOpts.massCutLambda->get("expoRelax")); + } + float getMassSigmaXi(float pt) + { + return preSelectOpts.massCutXi->get("constant") + pt * preSelectOpts.massCutXi->get("linear") + preSelectOpts.massCutXi->get("expoConstant") * TMath::Exp(-pt / preSelectOpts.massCutXi->get("expoRelax")); + } + float getMassSigmaOmega(float pt) + { + return preSelectOpts.massCutOm->get("constant") + pt * preSelectOpts.massCutOm->get("linear") + preSelectOpts.massCutOm->get("expoConstant") * TMath::Exp(-pt / preSelectOpts.massCutOm->get("expoRelax")); + } + + int nEnabledTables = 0; + + // helper object + o2::pwglf::strangenessBuilderHelper straHelper; + + // for handling TPC-only tracks (photons) + int mRunNumber; + 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; + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* + + 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 + + // declaration of structs here + // (N.B.: will be invisible to the outside, create your own copies) + o2::pwglf::strangenessbuilder::coreConfigurables baseOpts; + o2::pwglf::strangenessbuilder::v0Configurables v0BuilderOpts; + o2::pwglf::strangenessbuilder::cascadeConfigurables cascadeBuilderOpts; + o2::pwglf::strangenessbuilder::preSelectOpts preSelectOpts; + + template + void init(TBaseConfigurables const& inputBaseOpts, TV0Configurables const& inputV0BuilderOpts, TCascadeConfigurables const& inputCascadeBuilderOpts, TPreSelOpts const& inputPreSelectOpts, THistoRegistry& histos, TInitContext& context) + { + // read in configurations from the task where it's used + // could be grouped even further, but should work + baseOpts = inputBaseOpts; + v0BuilderOpts = inputV0BuilderOpts; + cascadeBuilderOpts = inputCascadeBuilderOpts; + preSelectOpts = inputPreSelectOpts; + + baseOpts.mEnabledTables.resize(nTables, 0); + + LOGF(info, "Checking if strangeness building is required"); + auto& workflows = context.services().template get(); + + nEnabledTables = 0; + + constexpr int kTablesConst = nTables; // silence warning + TString listOfRequestors[kTablesConst]; + for (int i = 0; i < nTables; i++) { + int f = baseOpts.enabledTables->get(tableNames[i].c_str(), "enable"); + if (f == 1) { + baseOpts.mEnabledTables[i] = 1; + listOfRequestors[i] = "manual enabling"; + } + if (f == -1) { + // autodetect this table in other devices + for (o2::framework::DeviceSpec const& device : workflows.devices) { + // Step 1: check if this device subscribed to the V0data table + for (auto const& input : device.inputs) { + if (o2::framework::DataSpecUtils::partialMatch(input.matcher, o2::header::DataOrigin("AOD"))) { + auto&& [origin, description, version] = o2::framework::DataSpecUtils::asConcreteDataMatcher(input.matcher); + std::string tableNameWithVersion = tableNames[i]; + if (version > 0) { + tableNameWithVersion += Form("_%03d", version); + } + if (input.matcher.binding == tableNameWithVersion) { + LOGF(info, "Device %s has subscribed to %s (version %i)", device.name, tableNames[i], version); + listOfRequestors[i].Append(Form("%s ", device.name.c_str())); + baseOpts.mEnabledTables[i] = 1; + nEnabledTables++; + } + } + } + } + } + } + + if (nEnabledTables == 0) { + LOGF(info, "Strangeness building not required. Will suppress all functionality, including logs, from this point forward."); + return; + } + + // setup bookkeeping histogram + auto h = histos.template add("hTableBuildingStatistics", "hTableBuildingStatistics", o2::framework::kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + auto h2 = histos.template add("hInputStatistics", "hInputStatistics", o2::framework::kTH1D, {{nTablesConst, -0.5f, static_cast(nTablesConst)}}); + h2->SetTitle("Input table sizes"); + + if (v0BuilderOpts.generatePhotonCandidates.value == true) { + auto hDeduplicationStatistics = histos.template add("hDeduplicationStatistics", "hDeduplicationStatistics", o2::framework::kTH1D, {{2, -0.5f, 1.5f}}); + hDeduplicationStatistics->GetXaxis()->SetBinLabel(1, "AO2D V0s"); + hDeduplicationStatistics->GetXaxis()->SetBinLabel(2, "Deduplicated V0s"); + } + + if (preSelectOpts.preselectOnlyDesiredV0s.value == true) { + auto hPreselectionV0s = histos.template add("hPreselectionV0s", "hPreselectionV0s", o2::framework::kTH1D, {{16, -0.5f, 15.5f}}); + hPreselectionV0s->GetXaxis()->SetBinLabel(1, "Not preselected"); + hPreselectionV0s->GetXaxis()->SetBinLabel(2, "#gamma"); + hPreselectionV0s->GetXaxis()->SetBinLabel(3, "K^{0}_{S}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(4, "#gamma, K^{0}_{S}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(5, "#Lambda"); + hPreselectionV0s->GetXaxis()->SetBinLabel(6, "#gamma, #Lambda"); + hPreselectionV0s->GetXaxis()->SetBinLabel(7, "K^{0}_{S}, #Lambda"); + hPreselectionV0s->GetXaxis()->SetBinLabel(8, "#gamma, K^{0}_{S}, #Lambda"); + hPreselectionV0s->GetXaxis()->SetBinLabel(9, "#bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(10, "#gamma, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(11, "K^{0}_{S}, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(12, "#gamma, K^{0}_{S}, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(13, "#Lambda, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(14, "#gamma, #Lambda, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(15, "K^{0}_{S}, #Lambda, #bar{#Lambda}"); + hPreselectionV0s->GetXaxis()->SetBinLabel(16, "#gamma, K^{0}_{S}, #Lambda, #bar{#Lambda}"); + } + + if (preSelectOpts.preselectOnlyDesiredCascades.value == true) { + auto hPreselectionCascades = histos.template add("hPreselectionCascades", "hPreselectionCascades", o2::framework::kTH1D, {{16, -0.5f, 15.5f}}); + hPreselectionCascades->GetXaxis()->SetBinLabel(1, "Not preselected"); + hPreselectionCascades->GetXaxis()->SetBinLabel(2, "#Xi^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(3, "#Xi^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(4, "#Xi^{-}, #Xi^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(5, "#Omega^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(6, "#Xi^{-}, #Omega^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(7, "#Xi^{+}, #Omega^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(8, "#Xi^{-}, #Xi^{+}, #Omega^{-}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(9, "#Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(10, "#Xi^{-}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(11, "#Xi^{+}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(12, "#Xi^{-}, #Xi^{+}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(13, "#Omega^{-}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(14, "#Xi^{-}, #Omega^{-}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(15, "#Xi^{+}, #Omega^{-}, #Omega^{+}"); + hPreselectionCascades->GetXaxis()->SetBinLabel(16, "#Xi^{-}, #Xi^{+}, #Omega^{-}, #Omega^{+}"); + } + + if (baseOpts.mc_findableMode.value > 0) { + // save statistics of findable candidate processing + auto hFindable = histos.template add("hFindableStatistics", "hFindableStatistics", o2::framework::kTH1D, {{6, -0.5f, 5.5f}}); + hFindable->SetTitle(Form("Findable mode: %i", static_cast(baseOpts.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"); + } + + auto hPrimaryV0s = histos.template add("hPrimaryV0s", "hPrimaryV0s", o2::framework::kTH1D, {{2, -0.5f, 1.5f}}); + hPrimaryV0s->GetXaxis()->SetBinLabel(1, "All V0s"); + hPrimaryV0s->GetXaxis()->SetBinLabel(2, "Primary V0s"); + + mRunNumber = 0; + + 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()); + if (baseOpts.mEnabledTables[i] == false) { + h->SetBinContent(i + 1, -1); // mark disabled tables, distinguish from zero counts + } + } + + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, " Strangeness builder: basic configuration listing"); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + if (baseOpts.mc_findableMode.value == 1) { + LOGF(info, " ===> findable mode 1 is enabled: complement reco-ed with non-found findable"); + } + if (baseOpts.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 (baseOpts.mEnabledTables[i]) { + LOGF(info, " -~> Table enabled: %s, requested by %s", tableNames[i], listOfRequestors[i].Data()); + 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, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + + // 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; + + // Set option to refit with material corrections + straHelper.fitter.setRefitWithMatCorr(baseOpts.refitWithMaterialCorrection.value); + } + + // 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(TCCDB& ccdb, 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(); + + // Fetch magnetic field from ccdb for current collision + auto magneticField = o2::base::Propagator::Instance()->getNominalBz(); + LOG(info) << "Configuring for timestamp " << timestamp << " with magnetic field of " << magneticField << " kG"; + + // Set magnetic field value once known + straHelper.fitter.setBz(magneticField); + + 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(THistoRegistry& histos, 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 (baseOpts.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 (baseOpts.mc_findableMode.value < 2) { + // keep all unless de-duplication active + ao2dV0toV0List.resize(v0s.size(), -1); // -1 means keep, -2 means do not keep + + if (baseOpts.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)) { + continue; + } + } + 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)) { + continue; + } + } + } // end TPC drift treatment + + // process candidate with helper, generate properties for consulting + // first 'false' : do not apply selections: do as much as possible to preserve + // second 'false': do not calculate prong DCA to PV, unnecessary, costly if XIU = 83.1f + // 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 && baseOpts.deduplicationAlgorithm.value == 1) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + if (bestDCADaughtersIndex == ic && baseOpts.deduplicationAlgorithm.value == 2) { + ao2dV0toV0List[v0tableGrouped[iV0].V0Ids[ic]] = -1; // keep best only + } + if (bestDCADaughtersIndex == ic && bestPointingAngleIndex == ic && baseOpts.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 (baseOpts.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() == PDG_t::kK0Short && v0BuilderOpts.mc_addGeneratedK0Short.value > 0) || + (originParticle.pdgCode() == PDG_t::kLambda0 && v0BuilderOpts.mc_addGeneratedLambda.value > 0) || + (originParticle.pdgCode() == PDG_t::kLambda0Bar && v0BuilderOpts.mc_addGeneratedAntiLambda.value > 0) || + (originParticle.pdgCode() == PDG_t::kGamma && 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 (baseOpts.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 == PDG_t::kGamma) { + 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 (baseOpts.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 == PDG_t::kGamma) { + 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, (baseOpts.mc_findableMode.value > 0)); + + // Cascade part if cores are requested, skip otherwise + if (baseOpts.mEnabledTables[kStoredCascCores] || baseOpts.mEnabledTables[kStoredKFCascCores]) { + if (baseOpts.mc_findableMode.value < 2) { + // simple passthrough: copy existing cascades to build list + for (const auto& cascade : cascades) { + auto const& v0 = cascade.v0(); + 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 (baseOpts.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() == PDG_t::kXiMinus && cascadeBuilderOpts.mc_addGeneratedXiMinus.value > 0) || + (originParticle.pdgCode() == PDG_t::kXiPlusBar && cascadeBuilderOpts.mc_addGeneratedXiPlus.value > 0) || + (originParticle.pdgCode() == PDG_t::kOmegaMinus && cascadeBuilderOpts.mc_addGeneratedOmegaMinus.value > 0) || + (originParticle.pdgCode() == PDG_t::kOmegaPlusBar && 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) != PDG_t::kLambda0) { + 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()) != PDG_t::kXiMinus && std::abs(v0OriginParticle.pdgCode()) != PDG_t::kOmegaMinus) { + 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 (baseOpts.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 (baseOpts.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 (baseOpts.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, (baseOpts.mc_findableMode.value > 0)); + } + + LOGF(debug, "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 (baseOpts.useV0BufferForCascades.value == false) { + return; // don't attempt to mark needlessly + } + if (baseOpts.mEnabledTables[kStoredCascCores]) { + for (const auto& cascade : cascadeList) { + if (cascade.v0Id < 0) + continue; + 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 (baseOpts.mEnabledTables[kStoredTraCascCores] && baseOpts.mc_findableMode.value == 0) { + trackedCascadeCount = trackedCascades.size(); + for (const auto& trackedCascade : trackedCascades) { + auto const& cascade = trackedCascade.cascade(); + 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(THistoRegistry& histos, TCollisions const& collisions, TV0s const& v0s, TTracks const& tracks, TMCParticles const& mcParticles, TProducts& products) + { + // 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 (!v0BuilderOpts.generatePhotonCandidates.value && v0.v0Type > 1) { + // skip photons if not requested + products.v0dataLink(-1, -1); + continue; + } + + if (!baseOpts.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)) { + products.v0dataLink(-1, -1); + continue; + } + } + + 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)) { + products.v0dataLink(-1, -1); + continue; + } + } + } + + if (!straHelper.buildV0Candidate(v0.collisionId, pvX, pvY, pvZ, posTrack, negTrack, posTrackPar, negTrackPar, v0.isCollinearV0, baseOpts.mEnabledTables[kV0Covs], v0BuilderOpts.generatePhotonCandidates)) { + products.v0dataLink(-1, -1); + continue; + } + if constexpr (requires { posTrack.tpcNSigmaEl(); }) { + if (preSelectOpts.preselectOnlyDesiredV0s) { + float lPt = RecoDecay::sqrtSumOfSquares( + straHelper.v0.positiveMomentum[0] + straHelper.v0.negativeMomentum[0], + straHelper.v0.positiveMomentum[1] + straHelper.v0.negativeMomentum[1]); + + float lPtot = RecoDecay::sqrtSumOfSquares( + straHelper.v0.positiveMomentum[0] + straHelper.v0.negativeMomentum[0], + straHelper.v0.positiveMomentum[1] + straHelper.v0.negativeMomentum[1], + straHelper.v0.positiveMomentum[2] + straHelper.v0.negativeMomentum[2]); + + float lLengthTraveled = RecoDecay::sqrtSumOfSquares( + straHelper.v0.position[0] - pvX, + straHelper.v0.position[1] - pvY, + straHelper.v0.position[2] - pvZ); + + uint8_t maskV0Preselection = 0; + + if ( // photon PID, mass, lifetime selection + std::abs(posTrack.tpcNSigmaEl()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaEl()) < preSelectOpts.maxTPCpidNsigma && + std::abs(straHelper.v0.massGamma) < preSelectOpts.massCutPhoton) { + BITSET(maskV0Preselection, selGamma); + } + + if ( // K0Short PID, mass, lifetime selection + std::abs(posTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassKaonNeutral * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutK0S") && + std::abs(straHelper.v0.massK0Short - o2::constants::physics::MassKaonNeutral) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaK0Short(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskV0Preselection, selK0Short); + } + + if ( // Lambda PID, mass, lifetime selection + std::abs(posTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + std::abs(straHelper.v0.massLambda - o2::constants::physics::MassLambda) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaLambda(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskV0Preselection, selLambda); + } + + if ( // antiLambda PID, mass, lifetime selection + std::abs(posTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + std::abs(straHelper.v0.massAntiLambda - o2::constants::physics::MassLambda) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaLambda(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskV0Preselection, selAntiLambda); + } + + histos.fill(HIST("hPreselectionV0s"), maskV0Preselection); + + if (maskV0Preselection == 0) { + products.v0dataLink(-1, -1); + continue; + } + } + } + if (v0Map[iv0] == -1 && baseOpts.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 (baseOpts.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 (baseOpts.mEnabledTables[kV0TrackXs]) { + // further decay chains may need this + products.v0trackXs(straHelper.v0.positiveTrackX, straHelper.v0.negativeTrackX); + histos.fill(HIST("hTableBuildingStatistics"), kV0TrackXs); + } + if (baseOpts.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 (baseOpts.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 (baseOpts.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 (baseOpts.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 ((baseOpts.mEnabledTables[kV0MCCores] || baseOpts.mEnabledTables[kMcV0Labels] || baseOpts.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 (baseOpts.mEnabledTables[kMcV0Labels]) { + products.v0labels(thisInfo.label, thisInfo.motherLabel); + histos.fill(HIST("hTableBuildingStatistics"), kMcV0Labels); + } + + // Construct found tag + if (baseOpts.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 (baseOpts.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); + histos.fill(HIST("hPrimaryV0s"), 0); + if (thisInfo.isPhysicalPrimary) + histos.fill(HIST("hPrimaryV0s"), 1); + } + if (baseOpts.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 (baseOpts.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 (baseOpts.mEnabledTables[kV0CoreMCLabels]) { + products.v0CoreMCLabels(thisV0MCCoreIndex); // interlink index + histos.fill(HIST("hTableBuildingStatistics"), kV0CoreMCLabels); + } + } + } // enabled tables check + } // constexpr requires check + } else { + products.v0dataLink(-1, -1); + } + } + + // finish populating V0MCCores if in asymmetric mode + if constexpr (soa::is_table) { + if (v0BuilderOpts.mc_populateV0MCCoresAsymmetric && (baseOpts.mEnabledTables[kV0MCCores] || baseOpts.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_keepOnlyPhysicalPrimary && !mcParticle.isPhysicalPrimary()) + continue; // skip secondary MC V0s + + if ( + (v0BuilderOpts.mc_addGeneratedK0Short && mcParticle.pdgCode() == PDG_t::kK0Short) || + (v0BuilderOpts.mc_addGeneratedLambda && mcParticle.pdgCode() == PDG_t::kLambda0) || + (v0BuilderOpts.mc_addGeneratedAntiLambda && mcParticle.pdgCode() == PDG_t::kLambda0Bar) || + (v0BuilderOpts.mc_addGeneratedGamma && mcParticle.pdgCode() == PDG_t::kGamma)) { + 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() != TMCProcess::kPDecay) + 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 (baseOpts.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); + histos.fill(HIST("hPrimaryV0s"), 0); + if (info.isPhysicalPrimary) + histos.fill(HIST("hPrimaryV0s"), 1); + } + if (baseOpts.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(THistoRegistry& histos, TCollisions const& collisions, TCascades const& cascades, TTracks const& tracks, TMCParticles const& mcParticles, TProducts& products) + { + // 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 (!baseOpts.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 (baseOpts.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 (cascade.v0Id < 0 || 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, + baseOpts.mEnabledTables[kCascBBs], + cascadeBuilderOpts.useCascadeMomentumAtPrimVtx, + baseOpts.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, + baseOpts.mEnabledTables[kCascBBs], + cascadeBuilderOpts.useCascadeMomentumAtPrimVtx, + baseOpts.mEnabledTables[kCascCovs])) { + products.cascdataLink(-1); + interlinks.cascadeToCascCores.push_back(-1); + continue; // didn't work out, skip + } + } + nCascades++; + + if constexpr (requires { posTrack.tpcNSigmaEl(); }) { + if (preSelectOpts.preselectOnlyDesiredCascades) { + float lPt = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.bachelorMomentum[0] + straHelper.cascade.positiveMomentum[0] + straHelper.cascade.negativeMomentum[0], + straHelper.cascade.bachelorMomentum[1] + straHelper.cascade.positiveMomentum[1] + straHelper.cascade.negativeMomentum[1]); + + float lPtot = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.bachelorMomentum[0] + straHelper.cascade.positiveMomentum[0] + straHelper.cascade.negativeMomentum[0], + straHelper.cascade.bachelorMomentum[1] + straHelper.cascade.positiveMomentum[1] + straHelper.cascade.negativeMomentum[1], + straHelper.cascade.bachelorMomentum[2] + straHelper.cascade.positiveMomentum[2] + straHelper.cascade.negativeMomentum[2]); + + float lV0Ptot = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.positiveMomentum[0] + straHelper.cascade.negativeMomentum[0], + straHelper.cascade.positiveMomentum[1] + straHelper.cascade.negativeMomentum[1], + straHelper.cascade.positiveMomentum[2] + straHelper.cascade.negativeMomentum[2]); + + float lLengthTraveled = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.cascadePosition[0] - pvX, + straHelper.cascade.cascadePosition[1] - pvY, + straHelper.cascade.cascadePosition[2] - pvZ); + + float lV0LengthTraveled = RecoDecay::sqrtSumOfSquares( + straHelper.cascade.v0Position[0] - straHelper.cascade.cascadePosition[0], + straHelper.cascade.v0Position[1] - straHelper.cascade.cascadePosition[1], + straHelper.cascade.v0Position[2] - straHelper.cascade.cascadePosition[2]); + + uint8_t maskCascadePreselection = 0; + + if ( // XiMinus PID and mass selection + straHelper.cascade.charge < 0 && + std::abs(posTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(bachTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lV0LengthTraveled / (lV0Ptot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + o2::constants::physics::MassXiMinus * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutXi") && + std::abs(straHelper.cascade.massXi - o2::constants::physics::MassXiMinus) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaXi(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskCascadePreselection, selXiMinus); + } + + if ( // XiPlus PID and mass selection + straHelper.cascade.charge > 0 && + std::abs(posTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(bachTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lV0LengthTraveled / (lV0Ptot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + o2::constants::physics::MassXiMinus * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutXi") && + std::abs(straHelper.cascade.massXi - o2::constants::physics::MassXiMinus) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaXi(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskCascadePreselection, selXiPlus); + } + + if ( // OmegaMinus PID and mass selection + straHelper.cascade.charge < 0 && + std::abs(posTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(bachTrack.tpcNSigmaKa()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lV0LengthTraveled / (lV0Ptot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + o2::constants::physics::MassOmegaMinus * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutOmega") && + std::abs(straHelper.cascade.massOmega - o2::constants::physics::MassOmegaMinus) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaOmega(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskCascadePreselection, selOmegaMinus); + } + + if ( // OmegaPlus PID and mass selection + straHelper.cascade.charge > 0 && + std::abs(posTrack.tpcNSigmaPi()) < preSelectOpts.maxTPCpidNsigma && + std::abs(negTrack.tpcNSigmaPr()) < preSelectOpts.maxTPCpidNsigma && + std::abs(bachTrack.tpcNSigmaKa()) < preSelectOpts.maxTPCpidNsigma && + o2::constants::physics::MassLambda * lV0LengthTraveled / (lV0Ptot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutLambda") && + o2::constants::physics::MassOmegaMinus * lLengthTraveled / (lPtot + 1e-13) < preSelectOpts.lifetimeCut->get("lifetimeCutOmega") && + std::abs(straHelper.cascade.massOmega - o2::constants::physics::MassOmegaMinus) < preSelectOpts.massWindownumberOfSigmas * getMassSigmaOmega(lPt) + preSelectOpts.massWindowSafetyMargin) { + BITSET(maskCascadePreselection, selOmegaPlus); + } + + histos.fill(HIST("hPreselectionCascades"), maskCascadePreselection); + + if (maskCascadePreselection == 0) { + products.cascdataLink(-1); + interlinks.cascadeToCascCores.push_back(-1); + continue; + } + } + } + + // generate analysis tables as required + if (baseOpts.mEnabledTables[kCascIndices]) { + products.cascidx(cascade.globalId, + straHelper.cascade.positiveTrack, straHelper.cascade.negativeTrack, + straHelper.cascade.bachelorTrack, straHelper.cascade.collisionId); + histos.fill(HIST("hTableBuildingStatistics"), kCascIndices); + } + if (baseOpts.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 (baseOpts.mEnabledTables[kCascTrackXs]) { + products.cascTrackXs(straHelper.cascade.positiveTrackX, straHelper.cascade.negativeTrackX, straHelper.cascade.bachelorTrackX); + histos.fill(HIST("hTableBuildingStatistics"), kCascTrackXs); + } + if (baseOpts.mEnabledTables[kCascBBs]) { + products.cascbb(straHelper.cascade.bachBaryonCosPA, straHelper.cascade.bachBaryonDCAxyToPV); + histos.fill(HIST("hTableBuildingStatistics"), kCascBBs); + } + if (baseOpts.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 ((baseOpts.mEnabledTables[kCascMCCores] || baseOpts.mEnabledTables[kMcCascLabels] || baseOpts.mEnabledTables[kCascMCCollRefs])) { + extractMonteCarloProperties(posTrack, negTrack, bachTrack, mcParticles); + + // Construct label table (note: this will be joinable with CascDatas) + if (baseOpts.mEnabledTables[kMcCascLabels]) { + products.casclabels( + thisCascInfo.label, thisCascInfo.motherLabel); + histos.fill(HIST("hTableBuildingStatistics"), kMcCascLabels); + } + + // Construct found tag + if (baseOpts.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 (baseOpts.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 (baseOpts.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 (baseOpts.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 (baseOpts.mEnabledTables[kMcCascBBTags]) { + bool bbTag = false; + if (bachTrack.has_mcParticle()) { + auto bachelorParticle = bachTrack.template mcParticle_as(); + if (bachelorParticle.pdgCode() == PDG_t::kPiPlus) { // 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() == PDG_t::kProtonBar) { + for (const auto& baryonMother : baryonParticle.template mothers_as()) { + for (const auto& pionMother : bachelorParticle.template mothers_as()) { + if (baryonMother.globalIndex() == pionMother.globalIndex() && baryonMother.pdgCode() == PDG_t::kLambda0Bar) { + bbTag = true; + } + } + } + } + } + } // end if-pion + if (bachelorParticle.pdgCode() == PDG_t::kPiMinus) { // 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() == PDG_t::kProton) { + for (const auto& baryonMother : baryonParticle.template mothers_as()) { + for (const auto& pionMother : bachelorParticle.template mothers_as()) { + if (baryonMother.globalIndex() == pionMother.globalIndex() && baryonMother.pdgCode() == PDG_t::kLambda0) { + 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 ((baseOpts.mEnabledTables[kCascMCCores] || baseOpts.mEnabledTables[kMcCascLabels] || baseOpts.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_keepOnlyPhysicalPrimary && !mcParticle.isPhysicalPrimary()) + continue; // skip secondary MC cascades + + if ( + (cascadeBuilderOpts.mc_addGeneratedXiMinus && mcParticle.pdgCode() == PDG_t::kXiMinus) || + (cascadeBuilderOpts.mc_addGeneratedXiPlus && mcParticle.pdgCode() == PDG_t::kXiPlusBar) || + (cascadeBuilderOpts.mc_addGeneratedOmegaMinus && mcParticle.pdgCode() == PDG_t::kOmegaMinus) || + (cascadeBuilderOpts.mc_addGeneratedOmegaPlus && mcParticle.pdgCode() == PDG_t::kOmegaPlusBar)) { + 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() != TMCProcess::kPDecay) // check whether the daughter comes from a decay + continue; + + if (std::abs(dau.pdgCode()) == PDG_t::kPiPlus || std::abs(dau.pdgCode()) == PDG_t::kKPlus) { + 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()) == PDG_t::kProton) { + thisCascInfo.pdgCodeV0 = dau.pdgCode(); + + for (const auto& v0Dau : dau.template daughters_as()) { + if (v0Dau.getProcess() != TMCProcess::kPDecay) + 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 (baseOpts.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 (baseOpts.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(THistoRegistry& histos, TCollisions const& collisions, TCascades const& cascades, TTracks const& tracks, TMCParticles const& mcParticles, TProducts& products) + { + if (!baseOpts.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, + baseOpts.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 (baseOpts.mEnabledTables[kKFCascIndices]) { + products.kfcascidx(cascade.globalId, + straHelper.cascade.positiveTrack, straHelper.cascade.negativeTrack, + straHelper.cascade.bachelorTrack, straHelper.cascade.collisionId); + histos.fill(HIST("hTableBuildingStatistics"), kKFCascIndices); + } + if (baseOpts.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 (baseOpts.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 ((baseOpts.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(THistoRegistry& histos, TCollisions const& collisions, TStrangeTracks const& cascadeTracks, TMCParticles const& mcParticles, TProducts& products) + { + if (!baseOpts.mEnabledTables[kStoredTraCascCores] || baseOpts.mc_findableMode.value != 0) { + return; // don't do if no request for cascades in place or findable mode used + } + int nCascades = 0; + std::vector traCascIndices(cascadeList.size(), -1); + // 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, + baseOpts.mEnabledTables[kCascBBs], + cascadeBuilderOpts.useCascadeMomentumAtPrimVtx, + baseOpts.mEnabledTables[kCascCovs])) { + continue; // didn't work out, skip + } + + // recalculate DCAxy, DCAz with strange track + auto strangeTrackParCov = getTrackParCov(strangeTrack); + std::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 (baseOpts.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 (baseOpts.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 + traCascIndices[cascade.globalIndex()] = products.tracascdata.lastIndex(); + } + if (baseOpts.mEnabledTables[kCascCovs]) { + std::array traCovMat = {0.}; + strangeTrackParCov.getCovXYZPxPyPzGlo(traCovMat); + float traCovMatArray[o2::track::kLabCovMatSize]; + for (int ii = 0; ii < o2::track::kLabCovMatSize; 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 ((baseOpts.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 + + for (std::size_t icascade = 0; icascade < cascadeList.size(); icascade++) { + products.tracascdataLink(traCascIndices[icascade]); + } + 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()) == PDG_t::kMuonMinus && 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(TCCDB& ccdb, THistoRegistry& histos, TCollisions const& collisions, TMCCollisions const& mccollisions, TV0s const& v0s, TCascades const& cascades, TTrackedCascades const& trackedCascades, TTracks const& tracks, TBCs const& bcs, TMCParticles const& mcParticles, TProducts& products) + { + if (nEnabledTables == 0) { + return; // fully suppressed + } + + if (!initCCDB(ccdb, bcs, collisions)) + return; + + // reset vectors for cascade interlinks + resetInterlinks(); + + // prepare v0List, cascadeList + prepareBuildingLists(histos, collisions, mccollisions, v0s, cascades, tracks, mcParticles); + + // mark V0s that will be buffered for the cascade building + markV0sUsedInCascades(v0List, cascadeList, trackedCascades); + + // build V0s + buildV0s(histos, collisions, v0List, tracks, mcParticles, products); + + // build cascades + buildCascades(histos, collisions, cascadeList, tracks, mcParticles, products); + buildKFCascades(histos, collisions, cascadeList, tracks, mcParticles, products); + + // build tracked cascades only if subscription is Run 3 like (doesn't exist in Run 2) + if constexpr (soa::is_table) { + buildTrackedCascades(histos, collisions, trackedCascades, mcParticles, products); + } + + populateCascadeInterlinks(); + } +}; // end BuilderModule + +} // namespace strangenessbuilder +} // namespace pwglf +} // namespace o2 + +#endif // PWGLF_UTILS_STRANGENESSBUILDERMODULE_H_ diff --git a/PWGLF/Utils/strangenessMasks.h b/PWGLF/Utils/strangenessMasks.h new file mode 100644 index 00000000000..dbf84deacd6 --- /dev/null +++ b/PWGLF/Utils/strangenessMasks.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. +// +/// \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 in cm +const float ctauxiPDG = 4.91; +const float ctauomegaPDG = 2.46; + +const float ctauk0shortPDG = 2.68; +const float ctaulambdaPDG = 7.85; + +// 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 index ba78c417376..c0b32c2574e 100644 --- a/PWGLF/Utils/svPoolCreator.h +++ b/PWGLF/Utils/svPoolCreator.h @@ -29,7 +29,7 @@ using namespace o2::framework::expressions; using std::array; using CollBracket = o2::math_utils::Bracket; -constexpr auto bOffsetMax = 241; // track compatibility can never go beyond 6 mus (ITS) +constexpr uint64_t bOffsetMax = 241; // track compatibility can never go beyond 6 mus (ITS) struct TrackCand { int Idxtr; @@ -45,11 +45,18 @@ struct SVCand { 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) { @@ -66,48 +73,49 @@ class svPoolCreator o2::vertexing::DCAFitterN<2>* getFitter() { return &fitter; } std::array, 4> getTrackCandPool() { return trackCandPool; } - template - void fillBC2Coll(const C& collisions, aod::BCsWithTimestamps const&) + template + void fillBC2Coll(const C& collisions, BC 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; + 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&) + template + void appendTrackCand(const T& trackCand, const C& collisions, int pdgHypo, o2::aod::AmbiguousTracks const& ambiTracks, BC const&) { if (pdgHypo != track0Pdg && pdgHypo != track1Pdg) { LOG(debug) << "Wrong pdg hypothesis"; return; } bool isDau0 = pdgHypo == track0Pdg; - uint64_t globalBC = -1; + 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(); + 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 = -1; + if (!ambTrack.has_bc() || ambTrack.bc_as().size() == 0) { + globalBC = BcInvalid; break; } - globalBC = ambTrack.bc_as().begin().globalBC(); + globalBC = ambTrack.bc_as().begin().globalBC(); break; } } else { - globalBC = -1; + globalBC = BcInvalid; } - if (globalBC == -1) { + if (globalBC == BcInvalid) { return; } @@ -121,18 +129,24 @@ class svPoolCreator } firstBC++; } + if (firstCollIdx == -1) { + return; + } + // 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(); + uint64_t collBC = collision.template bc_as().globalBC(); int collIdx = collision.globalIndex(); - int64_t bcOffset = globalBC - (int64_t)collBC; - if (std::abs(bcOffset) > bOffsetMax && bcOffset < 0) { - break; - } else if (std::abs(bcOffset) > bOffsetMax && bcOffset > 0) { - continue; + 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.}; diff --git a/PWGMM/Lumi/Tasks/CMakeLists.txt b/PWGMM/Lumi/Tasks/CMakeLists.txt index 87b7e7fe919..4003fa5c2d9 100644 --- a/PWGMM/Lumi/Tasks/CMakeLists.txt +++ b/PWGMM/Lumi/Tasks/CMakeLists.txt @@ -39,4 +39,9 @@ o2physics_add_dpl_workflow(lumistab SOURCES lumiStability.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lumi-stability-light-ions + SOURCES lumiStabilityLightIons.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCCDB O2Physics::AnalysisCore COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGMM/Lumi/Tasks/LumiFDDFT0.cxx b/PWGMM/Lumi/Tasks/LumiFDDFT0.cxx index 878e0482f7c..c5609cbbd9a 100644 --- a/PWGMM/Lumi/Tasks/LumiFDDFT0.cxx +++ b/PWGMM/Lumi/Tasks/LumiFDDFT0.cxx @@ -10,41 +10,37 @@ // or submit itself to any jurisdiction. // author: akhuntia@cern.ch -#include -#include -#include -#include - #include "Common/Core/TrackSelection.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/Multiplicity.h" -#include "CommonUtils/NameConf.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/GeomConstants.h" +#include "CommonUtils/NameConf.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsFDD/Digit.h" +#include "DataFormatsFIT/Triggers.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsVertexing/PVertexer.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/RunningWorkflowInfo.h" #include "Framework/runDataProcessing.h" -#include "Framework/AnalysisDataModel.h" - -#include "DetectorsVertexing/PVertexer.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/Vertex.h" -#include "DataFormatsFDD/Digit.h" -#include "DataFormatsFIT/Triggers.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" - -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "CommonConstants/GeomConstants.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CcdbApi.h" -#include "DataFormatsCalibration/MeanVertexObject.h" +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -66,9 +62,10 @@ DECLARE_SOA_COLUMN(VertexXY, vertexXY, double); DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); DECLARE_SOA_COLUMN(VertexChi2, vertexChi2, double); DECLARE_SOA_COLUMN(NContrib, nContrib, int); +DECLARE_SOA_COLUMN(InputMask, inputMask, uint64_t); //! CTP input mask // Information for FDD -DECLARE_SOA_COLUMN(isFDD, isfdd, bool); +DECLARE_SOA_COLUMN(IsFDD, isfdd, bool); DECLARE_SOA_COLUMN(TCMTriggerFDD, tcmTriggerfdd, uint8_t); DECLARE_SOA_COLUMN(TimeAFDD, timeAfdd, double); DECLARE_SOA_COLUMN(TimeCFDD, timeCfdd, double); @@ -78,43 +75,61 @@ DECLARE_SOA_COLUMN(ChargeAFDD, chargeAfdd, double); DECLARE_SOA_COLUMN(ChargeCFDD, chargeCfdd, double); // Information for FT0 -DECLARE_SOA_COLUMN(isFT0, isft0, bool); +DECLARE_SOA_COLUMN(IsFT0, isft0, bool); DECLARE_SOA_COLUMN(TCMTriggerFT0, tcmTriggerft0, uint8_t); DECLARE_SOA_COLUMN(TimeAFT0, timeAft0, double); DECLARE_SOA_COLUMN(TimeCFT0, timeCft0, double); DECLARE_SOA_COLUMN(ChargeAFT0, chargeAft0, double); DECLARE_SOA_COLUMN(ChargeCFT0, chargeCft0, double); +// information for FV0 +DECLARE_SOA_COLUMN(IsFV0, isfv0, bool); +DECLARE_SOA_COLUMN(TCMTriggerFV0, tcmTriggerfv0, uint8_t); +DECLARE_SOA_COLUMN(TimeAFV0, timeAfv0, double); // Only FV0-A time +DECLARE_SOA_COLUMN(ChargeAFV0, chargeAfv0, double); // Only FV0-A charge + } // namespace full -DECLARE_SOA_TABLE(EventInfo, "AOD", "EventInfo", full::TimeStamp, full::VertexX, +DECLARE_SOA_TABLE(EventInfo, "AOD", "EventInfo", full::TimeStamp, full::InputMask, full::VertexX, full::VertexY, full::VertexZ, full::GlobalBC, full::VertexChi2, full::NContrib, - full::isFDD, full::TCMTriggerFDD, + full::IsFDD, full::TCMTriggerFDD, full::TimeAFDD, full::TimeCFDD, full::ChargeAFDD, full::ChargeCFDD, - full::isFT0, full::TCMTriggerFT0, + full::IsFT0, full::TCMTriggerFT0, full::TimeAFT0, full::TimeCFT0, - full::ChargeAFT0, full::ChargeCFT0); + full::ChargeAFT0, full::ChargeCFT0, full::IsFV0, + full::TCMTriggerFV0, full::TimeAFV0, full::ChargeAFV0); DECLARE_SOA_TABLE(EventInfoFDD, "AOD", "EventInfoFDD", full::TimeStamp, full::GlobalBC, - full::TCMTriggerFDD, full::TimeAFDD, + full::InputMask, full::TCMTriggerFDD, full::TimeAFDD, full::TimeCFDD, full::IsCoinAmpFDDA, full::IsCoinAmpFDDC, full::ChargeAFDD, full::ChargeCFDD); DECLARE_SOA_TABLE(EventInfoFT0, "AOD", "EventInfoFT0", full::TimeStamp, full::GlobalBC, - full::TCMTriggerFT0, full::TimeAFT0, + full::InputMask, full::TCMTriggerFT0, full::TimeAFT0, full::TimeCFT0, full::ChargeAFT0, full::ChargeCFT0); +DECLARE_SOA_TABLE(EventInfoFV0, "AOD", "EventInfoFV0", + full::TimeStamp, full::GlobalBC, + full::InputMask, full::TCMTriggerFV0, full::TimeAFV0, + full::ChargeAFV0); + +DECLARE_SOA_TABLE(EventInfoCTP, "AOD", "EventInfoCTP", + full::TimeStamp, full::GlobalBC, + full::InputMask); + } // namespace o2::aod struct LumiFDDFT0 { Produces rowEventInfo; Produces rowEventInfofdd; Produces rowEventInfoft0; + Produces rowEventInfofv0; + Produces rowEventInfoCTP; Service ccdb; const char* ccdbpath_grp = "GLO/Config/GRPMagField"; const char* ccdburl = "http://alice-ccdb.cern.ch"; @@ -123,6 +138,8 @@ struct LumiFDDFT0 { Configurable fttimestamp{"fttimestamp", 1668080173000, "First time of time stamp"}; Configurable nContribMax{"nContribMax", 2500, "Maximum number of contributors"}; Configurable nContribMin{"nContribMin", 10, "Minimum number of contributors"}; + Configurable useRelTimeStamp{"useRelTimeStamp", false, "timestamp info stored as relative to fttimestamp"}; + Configurable cfgKeepOnlyNonZeroCTPMask{"cfgKeepOnlyNonZeroCTPMask", false, "Keep only events with non-zero CTP mask"}; HistogramRegistry histos{ "histos", @@ -147,10 +164,10 @@ struct LumiFDDFT0 { { {"BCFDD", "", {HistType::kTH1F, {{nBCsPerOrbit + 1, -0.5f, nBCsPerOrbit + 0.5f, "x"}}}}, // {"BCFT0", "", {HistType::kTH1F, {{nBCsPerOrbit + 1, -0.5f, nBCsPerOrbit + 0.5f, "x"}}}}, // + {"BCFV0", "", {HistType::kTH1F, {{nBCsPerOrbit + 1, -0.5f, nBCsPerOrbit + 0.5f, "x"}}}}, // }}; bool doPVrefit = true; - void init(InitContext&) { if (doprocessLite == true && doprocessFull == true) { @@ -165,11 +182,11 @@ struct LumiFDDFT0 { mRunNumber = 0; } - void processFull(soa::Join::iterator const& collision, aod::FDDs const& /*fdds*/, aod::FT0s const& /*ft0s*/, aod::BCsWithTimestamps const&, + void processFull(soa::Join::iterator const& collision, aod::FDDs const& /*fdds*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/, aod::BCsWithTimestamps const&, o2::soa::Join const& unfiltered_tracks) { - auto bc = collision.bc_as(); + const auto& bc = collision.bc_as(); Long64_t relTS = bc.timestamp() - fttimestamp; Long64_t globalBC = bc.globalBC(); std::vector vec_globID_contr = {}; @@ -239,6 +256,10 @@ struct LumiFDDFT0 { double chargecFT0 = 0.; uint8_t mTriggerFT0 = 0; + double timeaFV0 = -999.; + double chargeaFV0 = 0.; + uint8_t mTriggerFV0 = 0; + if (doPVrefit && PVrefit_doable) { auto Pvtx_refitted = vertexer.refitVertex(vec_useTrk_PVrefit, Pvtx); chi2 = Pvtx_refitted.getChi2(); @@ -249,38 +270,49 @@ struct LumiFDDFT0 { // refitYY = Pvtx_refitted.getSigmaY2(); // refitXY = Pvtx_refitted.getSigmaXY(); - // now get information for FDD - if (collision.has_foundFDD()) { - auto fdd = collision.foundFDD(); - mTriggerFDD = fdd.triggerMask(); - timeaFDD = fdd.timeA(); - timecFDD = fdd.timeC(); - for (auto amplitude : fdd.chargeA()) { - chargeaFDD += amplitude; - } - for (auto amplitude : fdd.chargeC()) { - chargecFDD += amplitude; - } - } // fdd - - if (collision.has_foundFT0()) { - auto ft0 = collision.foundFT0(); - mTriggerFT0 = ft0.triggerMask(); - timeaFT0 = ft0.timeA(); - timecFT0 = ft0.timeC(); - for (auto amplitude : ft0.amplitudeA()) { - chargeaFT0 += amplitude; - } + } // pv refit - for (auto amplitude : ft0.amplitudeC()) { - chargecFT0 += amplitude; - } - } // ft0 + // now get information for FDD + if (collision.has_foundFDD()) { + const auto& fdd = collision.foundFDD(); + mTriggerFDD = fdd.triggerMask(); + timeaFDD = fdd.timeA(); + timecFDD = fdd.timeC(); + for (const auto& amplitude : fdd.chargeA()) { + chargeaFDD += amplitude; + } + for (const auto& amplitude : fdd.chargeC()) { + chargecFDD += amplitude; + } + } // fdd + + if (collision.has_foundFT0()) { + const auto& ft0 = collision.foundFT0(); + mTriggerFT0 = ft0.triggerMask(); + timeaFT0 = ft0.timeA(); + timecFT0 = ft0.timeC(); + for (const auto& amplitude : ft0.amplitudeA()) { + chargeaFT0 += amplitude; + } - } // pv refit - rowEventInfo(relTS, refitX, refitY, refitZ, globalBC, chi2, nContrib, collision.has_foundFDD(), + for (const auto& amplitude : ft0.amplitudeC()) { + chargecFT0 += amplitude; + } + } // ft0 + + // FV0 + if (collision.has_foundFV0()) { + const auto& fv0 = collision.foundFV0(); + mTriggerFV0 = fv0.triggerMask(); + timeaFV0 = fv0.time(); + for (const auto& amplitude : fv0.amplitude()) { + chargeaFV0 += amplitude; + } + } // fv0 + + rowEventInfo(relTS, bc.inputMask(), refitX, refitY, refitZ, globalBC, chi2, nContrib, collision.has_foundFDD(), mTriggerFDD, timeaFDD, timecFDD, chargeaFDD, chargecFDD, collision.has_foundFT0(), mTriggerFT0, timeaFT0, - timecFT0, chargeaFT0, chargecFT0); + timecFT0, chargeaFT0, chargecFT0, collision.has_foundFV0(), mTriggerFV0, timeaFV0, chargeaFV0); histos.fill(HIST("chisquare_Refitted"), chi2); if (nContrib > nContribMin && nContrib < nContribMax && @@ -313,19 +345,33 @@ struct LumiFDDFT0 { }; PROCESS_SWITCH(LumiFDDFT0, processFull, "Process FDD", true); - void processLite(aod::FDDs const& fdds, aod::FT0s const& ft0s, aod::BCsWithTimestamps const&) + void processLite(aod::FDDs const& fdds, aod::FT0s const& ft0s, aod::FV0As const& fv0s, aod::BCsWithTimestamps const& bcs) { + // table to store CTP input mask, globalBC and timestamp + for (const auto& bc : bcs) { + if (!bc.timestamp()) + continue; + if (bc.inputMask() == 0 && cfgKeepOnlyNonZeroCTPMask) // No trigger inputs active + continue; + + if (useRelTimeStamp) { + Long64_t relTS = bc.timestamp() - fttimestamp; + rowEventInfoCTP(relTS, bc.globalBC(), bc.inputMask()); + } else { + rowEventInfoCTP(bc.timestamp(), bc.globalBC(), bc.inputMask()); + } + } // Scan over the FDD table and store charge and time along with globalBC - for (auto& fdd : fdds) { - auto bc = fdd.bc_as(); + for (const auto& fdd : fdds) { + const auto& bc = fdd.bc_as(); if (!bc.timestamp()) continue; if (mRunNumber != bc.runNumber()) { o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp(ccdbpath_grp, bc.timestamp()); if (grpo != nullptr) { o2::base::Propagator::initFieldFromGRP(grpo); - std::cout << "run " << bc.runNumber() << std::endl; + LOG(info) << "run " << bc.runNumber(); } else { LOGF(fatal, "GRP object is not available in CCDB for run=%d at timestamp=%llu", @@ -362,12 +408,12 @@ struct LumiFDDFT0 { bool isCoinA = checkAnyCoincidence(channelA); bool isCoinC = checkAnyCoincidence(channelC); - rowEventInfofdd(relTS, globalBC, fdd.triggerMask(), fdd.timeA(), fdd.timeC(), isCoinA, isCoinC, chargeaFDD, chargecFDD); + rowEventInfofdd(relTS, globalBC, bc.inputMask(), fdd.triggerMask(), fdd.timeA(), fdd.timeC(), isCoinA, isCoinC, chargeaFDD, chargecFDD); } // end of fdd table // Scan over the FT0 table and store charge and time along with globalBC - for (auto& ft0 : ft0s) { - auto bc = ft0.bc_as(); + for (const auto& ft0 : ft0s) { + const auto& bc = ft0.bc_as(); if (!bc.timestamp()) continue; Long64_t relTS = bc.timestamp() - fttimestamp; @@ -376,14 +422,31 @@ struct LumiFDDFT0 { histoslite.fill(HIST("BCFT0"), localBC); double chargeaFT0 = 0.; double chargecFT0 = 0.; - for (auto amplitude : ft0.amplitudeA()) { + for (const auto& amplitude : ft0.amplitudeA()) { chargeaFT0 += amplitude; } - for (auto amplitude : ft0.amplitudeC()) { + for (const auto& amplitude : ft0.amplitudeC()) { chargecFT0 += amplitude; } - rowEventInfoft0(relTS, globalBC, ft0.triggerMask(), ft0.timeA(), ft0.timeC(), chargeaFT0, chargecFT0); + rowEventInfoft0(relTS, globalBC, bc.inputMask(), ft0.triggerMask(), ft0.timeA(), ft0.timeC(), chargeaFT0, chargecFT0); } // end of ft0 table + + // Scan over the FV0 table and store charge and time along with globalBC + for (const auto& fv0 : fv0s) { + auto bc = fv0.bc_as(); + if (!bc.timestamp()) + continue; + Long64_t relTS = bc.timestamp() - fttimestamp; + Long64_t globalBC = bc.globalBC(); + int localBC = globalBC % nBCsPerOrbit; + histoslite.fill(HIST("BCFV0"), localBC); + + double chargeaFV0 = 0.; + for (const auto& amplitude : fv0.amplitude()) { + chargeaFV0 += amplitude; + } + rowEventInfofv0(relTS, globalBC, bc.inputMask(), fv0.triggerMask(), fv0.time(), chargeaFV0); + } // end of fv0 table }; PROCESS_SWITCH(LumiFDDFT0, processLite, "Process FDD and FT0 info", false); @@ -402,6 +465,6 @@ struct LumiFDDFT0 { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec w{adaptAnalysisTask(cfgc, TaskName{"LumiFDDFT0"})}; + WorkflowSpec w{adaptAnalysisTask(cfgc)}; return w; } diff --git a/PWGMM/Lumi/Tasks/lumiStability.cxx b/PWGMM/Lumi/Tasks/lumiStability.cxx index ee2f7b8b497..9584561af67 100644 --- a/PWGMM/Lumi/Tasks/lumiStability.cxx +++ b/PWGMM/Lumi/Tasks/lumiStability.cxx @@ -8,30 +8,42 @@ // In applying this license CERN does not 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 "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/ASoAHelpers.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonDataFormat/BunchFilling.h" #include "DataFormatsFDD/Digit.h" #include "DataFormatsFT0/Digit.h" #include "DataFormatsFV0/Digit.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" #include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using BCsWithTimestamps = soa::Join; +// using CollisionWithFDD = soa::Join; -int nBCsPerOrbit = 3564; - -struct lumiStabilityTask { +struct LumiStabilityTask { // Histogram registry: an object to hold your histograms HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -39,60 +51,201 @@ struct lumiStabilityTask { 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; + parameters::GRPLHCIFData* grplhcif = nullptr; + int nBCsPerOrbit = 3564; + int lastRunNumber = -1; + int64_t currentTFid = -1; + int nOrbits = nOrbitsConf; + double minOrbit = minOrbitConf; + int minTimeFDD = 30; + 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 axisCounts{5, -0.5, 4.5}; - const AxisSpec axisTriggger{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{static_cast(static_cast(43200) / (nOrbitsPerTF * 89e-6)), 0., 43200, ""}; // t in seconds. Histo for 12 hrs. Each bin contain one time frame (128/32 orbits for 2022/2023). + const AxisSpec timeAxis{1200, 0., 1200., "#bf{t-t_{SOF} (min)}"}; + + 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}}); + histos.add("TFsPerMinute", "TFs seen in this minute (to account for failed jobs);#bf{t-t_{SOF} (min)};#bf{#it{N}_{TFs}}", kTH1F, {timeAxis}); + + // time 32.766 is dummy time // histo about triggers - histos.add("FDD/hCounts", "0 CountVertexFDD - 1 CountPFPVertexCoincidencesFDD - 2 CountPFPTriggerCoincidencesFDD - 3 CountPPVertexCoincidencesFDD - 4 CountPPTriggerCoincidencesFDD; Number; counts", kTH1F, {axisCounts}); - histos.add("FDD/bcVertexTrigger", "vertex trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVertexTriggerCoincidence", "vertex trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVertexTriggerCoincidencePFP", "vertex trigger per BC (FDD) with coincidences and Past Future Protection;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVertexTriggerCoincidencePP", "vertex trigger per BC (FDD) with coincidences and Past Protection;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVertexTriggerBothSidesCoincidencePFP", "vertex per BC (FDD) with coincidences, at least one side trigger and Past Future Protection;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVertexTriggerBothSidesCoincidencePP", "vertex per BC (FDD) with coincidences, at least one side trigger and Past Protection;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcSCentralTrigger", "scentral trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcSCentralTriggerCoincidence", "scentral trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVSCTrigger", "vertex and scentral trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVSCTriggerCoincidence", "vertex and scentral trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcCentralTrigger", "central trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcCentralTriggerCoincidence", "central trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVCTrigger", "vertex and central trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FDD/bcVCTriggerCoincidence", "vertex and central trigger per BC (FDD) with coincidences;BC in FDD; counts", kTH1F, {axisTriggger}); - - histos.add("FT0/hCounts", "0 CountVertexFT0 - 1 CountPFPVertexCoincidencesFT0 - 2 CountPFPTriggerCoincidencesFT0 - 3 CountPPVertexCoincidencesFT0 - 4 CountPPTriggerCoincidencesFT0; Number; counts", kTH1F, {axisCounts}); - histos.add("FT0/bcVertexTrigger", "vertex trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTriggger}); - histos.add("FT0/bcVertexTriggerPFP", "vertex trigger per BC (FT0) with Past Future Protection;BC in FT0; counts", kTH1F, {axisTriggger}); - histos.add("FT0/bcVertexTriggerPP", "vertex trigger per BC (FT0) with Past Protection;BC in FT0; counts", kTH1F, {axisTriggger}); - histos.add("FT0/bcVertexTriggerBothSidesPFP", "vertex per BC (FDD) with coincidences, at least one side trigger and Past Future Protection;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FT0/bcVertexTriggerBothSidesPP", "vertex per BC (FDD) with coincidences, at least one side trigger and Past Protection;BC in FDD; counts", kTH1F, {axisTriggger}); - histos.add("FT0/bcSCentralTrigger", "Scentral trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTriggger}); - histos.add("FT0/bcVSCTrigger", "vertex and Scentral trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTriggger}); - histos.add("FT0/bcCentralTrigger", "central trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTriggger}); - histos.add("FT0/bcVCTrigger", "vertex and central trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTriggger}); - - histos.add("FV0/hCounts", "0 CountCentralFV0 - 1 CountPFPCentralFV0 - 2 CountPFPOutInFV0 - 3 CountPPCentralFV0 - 4 CountPPOutInFV0; Number; counts", kTH1F, {axisCounts}); - histos.add("FV0/bcOutTrigger", "Out trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTriggger}); - histos.add("FV0/bcInTrigger", "In trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTriggger}); - histos.add("FV0/bcSCenTrigger", "SCen trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTriggger}); - histos.add("FV0/bcCenTrigger", "Central trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTriggger}); - histos.add("FV0/bcCenTriggerPFPCentral", "Central trigger per BC (FV0) with PFP in central trigger;BC in V0; counts", kTH1F, {axisTriggger}); - histos.add("FV0/bcCenTriggerPPCentral", "Central trigger per BC (FV0) with PP in central trigger;BC in V0; counts", kTH1F, {axisTriggger}); - histos.add("FV0/bcCenTriggerPFPOutIn", "Central trigger per BC (FV0) with PFP in Out and In trigger;BC in V0; counts", kTH1F, {axisTriggger}); - histos.add("FV0/bcCenTriggerPPOutIn", "Central trigger per BC (FV0) with PP in Out and In trigger;BC in V0; counts", kTH1F, {axisTriggger}); + histos.add("FDD/hCounts", "0 FDDCount - 1 FDDVertexCount - 2 FDDPPVertexCount - 3 FDDCoincidencesVertexCount - 4 FDDPPCoincidencesVertexCount - 5 FDDPPBotSidesCount; Number; counts", kTH1F, {axisCounts}); + histos.add("FDD/nBCsVsTime", "Time of TVX triggered BCs since the start of fill. FDD;;#bf{#it{N}_{BC}}", kTH1F, {timeAxis}); + histos.add("FDD/nBCsVsTimeLeadingBC", "Time of TVX triggered BCs since the start of fill. FDD;;#bf{#it{N}_{BC}}", kTH1F, {timeAxis}); + histos.add("FDD/bcVertexTriggerCTP", "vertex trigger per BC (FDD);BC in FDD; counts", kTH1F, {axisTrigger}); + 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/hTimeForRateCTP", "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("FDD/hTimeForRateLeadingBCCTP", "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/nBCsVsTime", "Time of TVX triggered BCs since the start of fill. FT0;;#bf{#it{N}_{BC}}", kTH1F, {timeAxis}); + histos.add("FT0/nBCsVsTimeLeadingBC", "Time of TVX triggered BCs since the start of fill. FT0;;#bf{#it{N}_{BC}}", kTH1F, {timeAxis}); + histos.add("FT0/bcVertexTriggerCTP", "vertex trigger per BC (FT0);BC in FT0; counts", kTH1F, {axisTrigger}); + 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/hTimeForRateCTP", "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("FT0/hTimeForRateLeadingBCCTP", "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/bcChargeTriggerCTP", "Out trigger per BC (FV0);BC in V0; counts", kTH1F, {axisTrigger}); + 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}}); + histos.add("FV0/hTimeForRateCTP", "Counts by time in FV0;t (in seconds) in FV0; counts", kTH1F, {axisTimeRate}); + histos.add("FV0/hTimeForRateLeadingBCCTP", "Counts by time in FV0;t (in seconds) in FV0; counts", kTH1F, {axisTimeRate}); } bool checkAnyCoincidence(const std::vector& channels) { - constexpr std::pair pair0 = {0, 4}; - constexpr std::pair pair1 = {1, 5}; - constexpr std::pair pair2 = {2, 6}; - constexpr std::pair pair3 = {3, 7}; - constexpr std::array, 4> channelPairs = {pair0, pair1, pair2, pair3}; - // std::map channelPairs = {{0, 4}, {1, 5}, {2, 6}, {3, 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; @@ -101,31 +254,202 @@ struct lumiStabilityTask { return false; } - void processMain(aod::FDDs const& fdds, aod::FT0s const& ft0s, aod::FV0As const& fv0s, aod::BCsWithTimestamps const&) + float getTimeSinceSOF(const auto& bc) { + return (bc.timestamp() - grplhcif->getFillNumberTime()) / 1e3 / 60; // Convert to minutes + } + + 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++; + + // access CCDB for data or anchored MC only + int64_t ts = bcs.iteratorAt(0).timestamp(); + + // access colliding and beam-gas bc patterns + 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& bc : bcs) { + if (bc.timestamp() == 0) { + continue; + } + + std::bitset<64> ctpInputMask(bc.inputMask()); + bool trgFDD = ctpInputMask[15]; + bool trgFT0 = ctpInputMask[2]; + bool trgFV0 = ctpInputMask[9]; + + int64_t globalBC = bc.globalBC(); + int localBC = globalBC % nBCsPerOrbit; + + float timeSinceSOF = getTimeSinceSOF(bc); + + int64_t thisTFid = (globalBC - bcSOR) / nBCsPerTF; + + if (thisTFid != currentTFid) { + currentTFid = thisTFid; + histos.fill(HIST("TFsPerMinute"), timeSinceSOF); + } + + if (trgFDD) { + histos.fill(HIST("FDD/bcVertexTriggerCTP"), localBC + 7); + if (bcPatternB[localBC]) { + histos.fill(HIST("FDD/nBCsVsTime"), timeSinceSOF); + histos.fill(HIST("FDD/hTimeForRateCTP"), (bc.timestamp() - tsSOR) * 1.e-3); // Converting ms into seconds + } + } + if (trgFT0) { + histos.fill(HIST("FT0/bcVertexTriggerCTP"), localBC); + if (bcPatternB[localBC]) { + histos.fill(HIST("FT0/nBCsVsTime"), timeSinceSOF); + histos.fill(HIST("FT0/hTimeForRateCTP"), (bc.timestamp() - tsSOR) * 1.e-3); // Converting ms into seconds + } + } + if (trgFV0) { + histos.fill(HIST("FV0/bcChargeTriggerCTP"), localBC); + if (bcPatternB[localBC]) { + histos.fill(HIST("FV0/hTimeForRateCTP"), (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) { + if (trgFDD) { + histos.fill(HIST("FDD/nBCsVsTimeLeadingBC"), timeSinceSOF); + histos.fill(HIST("FDD/hTimeForRateLeadingBCCTP"), (bc.timestamp() - tsSOR) * 1.e-3); + } + if (trgFT0) { + histos.fill(HIST("FT0/nBCsVsTimeLeadingBC"), timeSinceSOF); + histos.fill(HIST("FT0/hTimeForRateLeadingBCCTP"), (bc.timestamp() - tsSOR) * 1.e-3); + } + if (trgFV0) { + histos.fill(HIST("FV0/hTimeForRateLeadingBCCTP"), (bc.timestamp() - tsSOR) * 1.e-3); + } + } + // } + } // loop over bcs + for (auto const& fdd : fdds) { auto bc = fdd.bc_as(); 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) { + int minLimit = 0; + int maxNChanels = 8; + for (auto i = 0; i < maxNChanels; i++) { + if (sideA[i] > minLimit) { channelA.push_back(i); } - if (SideC[i] > 0) { + if (sideC[i] > minLimit) { channelC.push_back(i); } } @@ -133,10 +457,171 @@ struct lumiStabilityTask { bool isCoinA = checkAnyCoincidence(channelA); bool isCoinC = checkAnyCoincidence(channelC); + histos.fill(HIST("FDD/hCounts"), 0); if (vertex) { + histos.fill(HIST("hOrbitFDDVertex"), orbit - minOrbit); + histos.fill(HIST("FDD/hCounts"), 1); histos.fill(HIST("FDD/bcVertexTrigger"), localBC); + + 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() > minTimeFDD) { + 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() > minTimeFDD) { + 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() > minTimeFDD || fdd.timeC() > minTimeFDD) { + histos.fill(HIST("FDD/hCountsTime2022"), 0); + histos.fill(HIST("FDD/hInvTimevsBC2022"), localBC); + } + if (fdd.timeA() < minTimeFDD && fdd.timeC() < minTimeFDD) { + 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() > minTimeFDD) { + 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() > minTimeFDD) { + 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() > minTimeFDD || fdd.timeC() > minTimeFDD) { + histos.fill(HIST("FDD/hCountsTime"), 0); + histos.fill(HIST("FDD/hInvTimevsBC"), localBC); + } + if (fdd.timeA() < minTimeFDD && fdd.timeC() < minTimeFDD) { + 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 @@ -148,23 +633,25 @@ struct lumiStabilityTask { if (fdd.globalIndex() - deltaIndex < 0) { break; } - const auto& fdd_past = fdds.iteratorAt(fdd.globalIndex() - deltaIndex); - deltaBC = fdd.bcId() - fdd_past.bcId(); + const auto& fddPast = fdds.iteratorAt(fdd.globalIndex() - deltaIndex); + auto bcPast = fddPast.bc_as(); + deltaBC = globalBC - bcPast.globalBC(); if (deltaBC < myMaxDeltaBCFDD) { - std::bitset<8> fddTriggersPast = fdd_past.triggerMask(); + 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 = fdd_past.chargeA(); - auto SideCPast = fdd_past.chargeC(); + 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) { + int maxNChanels = 8; + for (auto i = 0; i < maxNChanels; i++) { + if (sideAPast[i] > 0) { channelAPast.push_back(i); } - if (SideCPast[i] > 0) { + if (sideCPast[i] > 0) { channelCPast.push_back(i); } } @@ -179,65 +666,15 @@ struct lumiStabilityTask { deltaIndex = 0; deltaBC = 0; - bool futureActivityFDDVertexCoincidences = false; - bool futureActivityFDDTriggerACoincidenceA = false; - bool futureActivityFDDTriggerCCoincidenceC = false; - while (deltaBC < myMaxDeltaBCFDD) { - deltaIndex++; - if (fdd.globalIndex() + deltaIndex >= fdds.size()) { - break; - } - const auto& fdd_future = fdds.iteratorAt(fdd.globalIndex() + deltaIndex); - deltaBC = fdd_future.bcId() - fdd.bcId(); - - if (deltaBC < myMaxDeltaBCFDD) { - std::bitset<8> fddTriggersFuture = fdd_future.triggerMask(); - bool vertexFuture = fddTriggersFuture[o2::fdd::Triggers::bitVertex]; - bool triggerAFuture = fddTriggersFuture[o2::fdd::Triggers::bitA]; - bool triggerCFuture = fddTriggersFuture[o2::fdd::Triggers::bitC]; - auto SideAFuture = fdd_future.chargeA(); - auto SideCFuture = fdd_future.chargeC(); - std::vector channelAFuture; - std::vector channelCFuture; - for (auto i = 0; i < 8; i++) { - if (SideAFuture[i] > 0) { - channelAFuture.push_back(i); - } - if (SideCFuture[i] > 0) { - channelCFuture.push_back(i); - } - } - - bool isCoinAFuture = checkAnyCoincidence(channelAFuture); - bool isCoinCFuture = checkAnyCoincidence(channelCFuture); - futureActivityFDDVertexCoincidences |= (vertexFuture & isCoinAFuture & isCoinCFuture); - futureActivityFDDTriggerACoincidenceA |= (triggerAFuture & isCoinAFuture); - futureActivityFDDTriggerCCoincidenceC |= (triggerCFuture & isCoinCFuture); - } - } - - histos.fill(HIST("FDD/hCounts"), 0); - if ((pastActivityFDDTriggerACoincidenceA || futureActivityFDDTriggerACoincidenceA) == true || (pastActivityFDDTriggerCCoincidenceC || futureActivityFDDTriggerCCoincidenceC) == true) { - histos.fill(HIST("FDD/hCounts"), 2); - } else { - histos.fill(HIST("FDD/bcVertexTriggerBothSidesCoincidencePFP"), localBC); - } - if (pastActivityFDDTriggerACoincidenceA == true || pastActivityFDDTriggerCCoincidenceC == true) { + if (pastActivityFDDVertexCoincidences == false) { histos.fill(HIST("FDD/hCounts"), 4); - } else { - histos.fill(HIST("FDD/bcVertexTriggerBothSidesCoincidencePP"), localBC); - } - if (pastActivityFDDVertexCoincidences == true || futureActivityFDDVertexCoincidences == true) { - histos.fill(HIST("FDD/hCounts"), 1); - } else { - histos.fill(HIST("FDD/bcVertexTriggerCoincidencePFP"), localBC); - } - if (pastActivityFDDVertexCoincidences == true) { - histos.fill(HIST("FDD/hCounts"), 3); - } else { 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) { @@ -267,7 +704,7 @@ 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(); @@ -275,16 +712,78 @@ struct lumiStabilityTask { 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::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); + 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() > minTimeFDD) { + 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() > minTimeFDD) { + 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() > minTimeFDD || ft0.timeC() > minTimeFDD) { + histos.fill(HIST("FT0/hCountsTime"), 0); + histos.fill(HIST("FT0/hInvTimevsBC"), localBC); + } + if (ft0.timeA() < minTimeFDD && ft0.timeC() < minTimeFDD) { + 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 @@ -296,11 +795,12 @@ struct lumiStabilityTask { if (ft0.globalIndex() - deltaIndex < 0) { break; } - const auto& ft0_past = ft0s.iteratorAt(ft0.globalIndex() - deltaIndex); - deltaBC = ft0.bcId() - ft0_past.bcId(); + const auto& ft0Past = ft0s.iteratorAt(ft0.globalIndex() - deltaIndex); + auto bcPast = ft0Past.bc_as(); + deltaBC = globalBC - bcPast.globalBC(); if (deltaBC < myMaxDeltaBCFT0) { - std::bitset<8> fT0TriggersPast = ft0_past.triggerMask(); + 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]; @@ -313,49 +813,14 @@ struct lumiStabilityTask { deltaIndex = 0; deltaBC = 0; - bool futureActivityFT0Vertex = false; - bool futureActivityFT0TriggerA = false; - bool futureActivityFT0TriggerC = false; - while (deltaBC < myMaxDeltaBCFT0) { - deltaIndex++; - if (ft0.globalIndex() + deltaIndex >= ft0s.size()) { - break; - } - const auto& ft0_future = ft0s.iteratorAt(ft0.globalIndex() + deltaIndex); - deltaBC = ft0_future.bcId() - ft0.bcId(); - - if (deltaBC < myMaxDeltaBCFT0) { - std::bitset<8> fT0TriggersFuture = ft0_future.triggerMask(); - bool vertexFuture = fT0TriggersFuture[o2::ft0::Triggers::bitVertex]; - bool triggerAFuture = fT0TriggersFuture[o2::ft0::Triggers::bitA]; - bool triggerCFuture = fT0TriggersFuture[o2::ft0::Triggers::bitC]; - - futureActivityFT0Vertex |= vertexFuture; - futureActivityFT0TriggerA |= triggerAFuture; - futureActivityFT0TriggerC |= triggerCFuture; - } - } - - histos.fill(HIST("FT0/hCounts"), 0); - if ((pastActivityFT0TriggerA || futureActivityFT0TriggerA) == true || (pastActivityFT0TriggerC || futureActivityFT0TriggerC) == true) { + histos.fill(HIST("FT0/hCounts"), 1); + if (pastActivityFT0Vertex == false) { histos.fill(HIST("FT0/hCounts"), 2); - } else { - histos.fill(HIST("FT0/bcVertexTriggerBothSidesPFP"), localBC); - } - if (pastActivityFT0TriggerA == true || pastActivityFT0TriggerC == true) { - histos.fill(HIST("FT0/hCounts"), 4); - } else { - histos.fill(HIST("FT0/bcVertexTriggerBothSidesPP"), localBC); - } - if (pastActivityFT0Vertex == true || futureActivityFT0Vertex == true) { - histos.fill(HIST("FT0/hCounts"), 1); - } else { - histos.fill(HIST("FT0/bcVertexTriggerPFP"), localBC); + histos.fill(HIST("FT0/bcVertexTriggerPP"), localBC); } - if (pastActivityFT0Vertex == true) { + if (pastActivityFT0TriggerA == false || pastActivityFT0TriggerC == false) { histos.fill(HIST("FT0/hCounts"), 3); - } else { - histos.fill(HIST("FT0/bcVertexTriggerPP"), localBC); + histos.fill(HIST("FT0/bcVertexTriggerBothSidesPP"), localBC); } } // vertex true @@ -383,8 +848,9 @@ struct lumiStabilityTask { 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::fv0::Triggers::bitAOut]; @@ -405,8 +871,26 @@ struct lumiStabilityTask { } if (aCen) { + histos.fill(HIST("hOrbitFV0Central"), orbit - minOrbit); histos.fill(HIST("FV0/bcCenTrigger"), 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; @@ -417,11 +901,12 @@ struct lumiStabilityTask { if (fv0.globalIndex() - deltaIndex < 0) { break; } - const auto& fv0_past = fv0s.iteratorAt(fv0.globalIndex() - deltaIndex); - deltaBC = fv0.bcId() - fv0_past.bcId(); + const auto& fv0Past = fv0s.iteratorAt(fv0.globalIndex() - deltaIndex); + auto bcPast = fv0Past.bc_as(); + deltaBC = globalBC - bcPast.globalBC(); if (deltaBC < myMaxDeltaBCFV0) { - std::bitset<8> fv0Triggers = fv0_past.triggerMask(); + 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]; @@ -442,11 +927,11 @@ struct lumiStabilityTask { if (fv0.globalIndex() + deltaIndex >= fv0s.size()) { break; } - const auto& fv0_future = fv0s.iteratorAt(fv0.globalIndex() + deltaIndex); - deltaBC = fv0_future.bcId() - fv0.bcId(); + const auto& fv0Future = fv0s.iteratorAt(fv0.globalIndex() + deltaIndex); + deltaBC = fv0Future.bcId() - fv0.bcId(); if (deltaBC < myMaxDeltaBCFV0) { - std::bitset<8> fv0Triggers = fv0_future.triggerMask(); + 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]; @@ -480,13 +965,25 @@ struct lumiStabilityTask { } } } // loop over V0 events - } // end processMain + } // 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, processMain, "Process FDD and FT0 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/Lumi/Tasks/lumiStabilityLightIons.cxx b/PWGMM/Lumi/Tasks/lumiStabilityLightIons.cxx new file mode 100644 index 00000000000..a1bddbdfee0 --- /dev/null +++ b/PWGMM/Lumi/Tasks/lumiStabilityLightIons.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. +// +/// \file lumiStabilityLightIons.cxx +/// \brief Analysis over BCs to study the luminosity stability along time +/// +/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt, Stefanie Mrozinski (stefanie.mrozinski@cern.ch) - Goethe University Frankfurt + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/MetadataHelper.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +o2::common::core::MetadataHelper metadataInfo; // Metadata helper + +using MyBCs = soa::Join; + +struct LumiStabilityLightIons { + Configurable cfgDoFT0Vtx{"cfgDoFT0Vtx", true, "Create and fill histograms for the FT0 vertex trigger"}; + Configurable cfgDoFT0CE{"cfgDoFT0CE", true, "Create and fill histograms for the FT0 centrality trigger"}; + Configurable cfgDoFDD{"cfgDoFDD", true, "Create and fill histograms for the FDD trigger"}; + Configurable cfgDo1ZNC{"cfgDo1ZNC", true, "Create and fill histograms for the 1ZNC trigger"}; + + Configurable cfgDoBCA{"cfgDoBCA", false, "Create and fill histograms for the BCs of type A"}; + Configurable cfgDoBCB{"cfgDoBCB", true, "Create and fill histograms for the BCs of type B"}; + Configurable cfgDoBCC{"cfgDoBCC", false, "Create and fill histograms for the BCs of type C"}; + Configurable cfgDoBCE{"cfgDoBCE", false, "Create and fill histograms for the BCs of type E"}; + Configurable cfgDoBCL{"cfgDoBCL", false, "Create and fill histograms for leading BCs of type B"}; + Configurable cfgDoBCSL{"cfgDoBCSL", false, "Create and fill histograms for super-leading BCs (no preceding FT0/FDD activity) of type B"}; + + Configurable cfgRequireNoT0ForSLBC{"cfgRequireNoT0ForSLBC", false, "Require no T0 signal for definition of super leading BC (otherwise only no FDD)"}; + + Configurable cfgEmptyBCsBeforeLeadingBC{"cfgEmptyBCsBeforeLeadingBC", 5, "Minimum number of empty BCs before a leading BC to identify it as such"}; + + std::bitset beamPatternA, beamPatternC; + std::bitset bcPatternA, bcPatternC, bcPatternB, bcPatternE, bcPatternL; + + std::string strLPMProductionTag = ""; // MC production tag to be retrieved from AO2D metadata + + const int nBCsPerOrbit = 3564; + + parameters::GRPLHCIFData* mLHCIFdata = nullptr; + int mRunNumber = -1; + ctpRateFetcher mRateFetcher; + bool isLeadingBC = false; + + HistogramRegistry mHistManager{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + const int nTriggers = 5; + enum TriggerAliases { kAllBCs = 0, + kFT0Vtx = 1, + kFT0CE = 2, + kFDD = 3, + k1ZNC = 4 }; + + const int nBCCategories = 6; + enum BCCategories { kBCA = 0, // A side BCs (bunch-crossings that had beam only from A side) + kBCB = 1, // B type BCs (bunch-crossings that had beam from both sides) + kBCC = 2, // C side BCs (bunch-crossings that had beam only from C side) + kBCE = 3, // empty BCs (bunch-crossings that did not have beam from either side) + kBCL = 4, // leading BCs (bunch-crossings that did not have interacting bunches for a configurable number of preceding BCs) + kBCSL = 5 }; // super-leading BCs (bunch-crossings that did not have FDD/FT0 activity for a configurable number of preceding BCs) + + static constexpr std::string_view NBCsVsTimeHistNames[5][6] = + {{"AllBCs/BC_A/nBCsVsTime", "AllBCs/BC_B/nBCsVsTime", "AllBCs/BC_C/nBCsVsTime", "AllBCs/BC_E/nBCsVsTime", "AllBCs/BC_L/nBCsVsTime", "AllBCs/BC_SL/nBCsVsTime"}, + {"FT0VTx/BC_A/nBCsVsTime", "FT0VTx/BC_B/nBCsVsTime", "FT0VTx/BC_C/nBCsVsTime", "FT0VTx/BC_E/nBCsVsTime", "FT0VTx/BC_L/nBCsVsTime", "FT0VTx/BC_SL/nBCsVsTime"}, + {"FT0CE/BC_A/nBCsVsTime", "FT0CE/BC_B/nBCsVsTime", "FT0CE/BC_C/nBCsVsTime", "FT0CE/BC_E/nBCsVsTime", "FT0CE/BC_L/nBCsVsTime", "FT0CE/BC_SL/nBCsVsTime"}, + {"FDD/BC_A/nBCsVsTime", "FDD/BC_B/nBCsVsTime", "FDD/BC_C/nBCsVsTime", "FDD/BC_E/nBCsVsTime", "FDD/BC_L/nBCsVsTime", "FDD/BC_SL/nBCsVsTime"}, + {"1ZNC/BC_A/nBCsVsTime", "1ZNC/BC_B/nBCsVsTime", "1ZNC/BC_C/nBCsVsTime", "1ZNC/BC_E/nBCsVsTime", "1ZNC/BC_L/nBCsVsTime", "1ZNC/BC_SL/nBCsVsTime"}}; + + static constexpr std::string_view NBCsVsBCIDHistNames[5][6] = + {{"AllBCs/BC_A/nBCsVsBCID", "AllBCs/BC_B/nBCsVsBCID", "AllBCs/BC_C/nBCsVsBCID", "AllBCs/BC_E/nBCsVsBCID", "AllBCs/BC_L/nBCsVsBCID", "AllBCs/BC_SL/nBCsVsBCID"}, + {"FT0VTx/BC_A/nBCsVsBCID", "FT0VTx/BC_B/nBCsVsBCID", "FT0VTx/BC_C/nBCsVsBCID", "FT0VTx/BC_E/nBCsVsBCID", "FT0VTx/BC_L/nBCsVsBCID", "FT0VTx/BC_SL/nBCsVsBCID"}, + {"FT0CE/BC_A/nBCsVsBCID", "FT0CE/BC_B/nBCsVsBCID", "FT0CE/BC_C/nBCsVsBCID", "FT0CE/BC_E/nBCsVsBCID", "FT0CE/BC_L/nBCsVsBCID", "FT0CE/BC_SL/nBCsVsBCID"}, + {"FDD/BC_A/nBCsVsBCID", "FDD/BC_B/nBCsVsBCID", "FDD/BC_C/nBCsVsBCID", "FDD/BC_E/nBCsVsBCID", "FDD/BC_L/nBCsVsBCID", "FDD/BC_SL/nBCsVsBCID"}, + {"1ZNC/BC_A/nBCsVsBCID", "1ZNC/BC_B/nBCsVsBCID", "1ZNC/BC_C/nBCsVsBCID", "1ZNC/BC_E/nBCsVsBCID", "1ZNC/BC_L/nBCsVsBCID", "1ZNC/BC_SL/nBCsVsBCID"}}; + + int64_t bcSOR; + int nBCsPerTF; + int64_t currentTFid = -1; + + void init(InitContext&) + { + strLPMProductionTag = metadataInfo.get("LPMProductionTag"); // to extract info from ccdb by the tag + + LOG(info) << "strLPMProductionTag: " << strLPMProductionTag; + + AxisSpec timeAxis{1440, 0., 1440., "#bf{t-t_{SOF} (min)}"}, bcIDAxis{3600, 0., 3600., "#bf{BC ID in orbit}"}; + + for (int iTrigger = 0; iTrigger < nTriggers; iTrigger++) { + if ((iTrigger == kAllBCs) || (iTrigger == kFT0Vtx && cfgDoFT0Vtx) || (iTrigger == kFT0CE && cfgDoFT0CE) || (iTrigger == kFDD && cfgDoFDD) || (iTrigger == k1ZNC && cfgDo1ZNC)) { + for (int iBCCategory = 0; iBCCategory < nBCCategories; iBCCategory++) { + if ((iBCCategory == kBCA && cfgDoBCA) || (iBCCategory == kBCB && cfgDoBCB) || (iBCCategory == kBCC && cfgDoBCC) || (iBCCategory == kBCE && cfgDoBCE) || (iBCCategory == kBCL && cfgDoBCL)) { + mHistManager.add(Form("%s", std::string(NBCsVsTimeHistNames[iTrigger][iBCCategory]).c_str()), "Time of triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1D, {timeAxis}); + mHistManager.add(Form("%s", std::string(NBCsVsBCIDHistNames[iTrigger][iBCCategory]).c_str()), "BC ID of triggered BCs;#bf{BC ID in orbit};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis}); + } + } + if (cfgDoBCSL && (iTrigger == kFT0Vtx || iTrigger == kFDD)) { // only for FT0Vtx and FDD fill super-leading BC histograms + mHistManager.add(Form("%s", std::string(NBCsVsTimeHistNames[iTrigger][5]).c_str()), "Time of triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1D, {timeAxis}); + mHistManager.add(Form("%s", std::string(NBCsVsBCIDHistNames[iTrigger][5]).c_str()), "BC ID of triggered BCs;#bf{BC ID in orbit};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis}); + } + } + } + + if (cfgDoBCSL) { + mHistManager.add("FITQA/BCHasFT0", "Does the BC have FT0?;BC has FT0;TVX triggered according to CTP;#bf{#it{N}_{BC}}", HistType::kTH2D, {{2, -0.5, 1.5}, {2, -0.5, 1.5}}); + mHistManager.get(HIST("FITQA/BCHasFT0")).get()->GetYaxis()->SetBinLabel(1, "No CTP trigger"); + mHistManager.get(HIST("FITQA/BCHasFT0")).get()->GetYaxis()->SetBinLabel(2, "CTP triggered"); + mHistManager.get(HIST("FITQA/BCHasFT0")).get()->GetXaxis()->SetBinLabel(1, "No found FT0"); + mHistManager.get(HIST("FITQA/BCHasFT0")).get()->GetXaxis()->SetBinLabel(2, "Found FT0"); + mHistManager.add("FITQA/BCHasFDD", "Does the BC have FDD?;BC has FDD;FDD triggered according to CTP;#bf{#it{N}_{BC}}", HistType::kTH2D, {{2, -0.5, 1.5}, {2, -0.5, 1.5}}); + mHistManager.get(HIST("FITQA/BCHasFDD")).get()->GetYaxis()->SetBinLabel(1, "No CTP trigger"); + mHistManager.get(HIST("FITQA/BCHasFDD")).get()->GetYaxis()->SetBinLabel(2, "CTP triggered"); + mHistManager.get(HIST("FITQA/BCHasFDD")).get()->GetXaxis()->SetBinLabel(1, "No found FDD"); + mHistManager.get(HIST("FITQA/BCHasFDD")).get()->GetXaxis()->SetBinLabel(2, "Found FDD"); + } + + mHistManager.add("FT0Vtx_EvSel/nBCsVsTime", "Time of TVX triggered BCs since the start of fill;;#bf{#it{N}_{BC}}", HistType::kTH1D, {timeAxis}); + mHistManager.add("nBCsVsBCID", "Time of TVX triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis}); + mHistManager.add("TFsPerMinute", "TFs seen in this minute (to account for failed jobs);#bf{t-t_{SOF} (min)};#bf{#it{N}_{TFs}}", HistType::kTH1D, {timeAxis}); + + if (cfgDo1ZNC) { + AxisSpec zdcTimeAxis{200, -50., 50.}; + mHistManager.add("ZDCQA/BCHasZDC", "Does the BC have ZDC?;BC has ZDC;Has ZNC according to CTP;#bf{#it{N}_{BC}}", HistType::kTH2D, {{2, -0.5, 1.5}, {2, -0.5, 1.5}}); + mHistManager.get(HIST("ZDCQA/BCHasZDC")).get()->GetYaxis()->SetBinLabel(1, "No CTP trigger"); + mHistManager.get(HIST("ZDCQA/BCHasZDC")).get()->GetYaxis()->SetBinLabel(2, "CTP triggered"); + mHistManager.get(HIST("ZDCQA/BCHasZDC")).get()->GetXaxis()->SetBinLabel(1, "No found ZDC"); + mHistManager.get(HIST("ZDCQA/BCHasZDC")).get()->GetXaxis()->SetBinLabel(2, "Good ZDC"); + mHistManager.add("ZDCQA/ZNCTimeVsEnergy", "ZDC properties in BCs with found ZDC;Energy;#bf{ZNC arrival time (ns)};#bf{#it{N}_{BC}}", HistType::kTH2D, {{1501, -10, 1.5E4}, zdcTimeAxis}); + mHistManager.add("ZDCQA/ZDCTimes", "Correlation between ZNA and ZNC timing;#bf{ZNC arrival time (ns)};#bf{ZNA arrival time (ns)}", HistType::kTH2D, {zdcTimeAxis, zdcTimeAxis}); + mHistManager.add("ZDCQA/ZNATime", "Time of the ZNA signal;#bf{ZNA arrival time (ns)};#bf{#it{N}_{BC}}", HistType::kTH1D, {zdcTimeAxis}); + mHistManager.add("ZDCQA/ZNCTime", "Time of the ZNC signal;#bf{ZNC arrival time (ns)};#bf{#it{N}_{BC}}", HistType::kTH1D, {zdcTimeAxis}); + } + } + + void setLHCIFData(const auto& bc) + { + if (mRunNumber == bc.runNumber()) + return; + + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + uint64_t timeStamp = bc.timestamp(); + + std::map metadata; + mLHCIFdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); + if (mLHCIFdata == nullptr) + LOG(fatal) << "GRPLHCIFData not in database, timestamp:" << timeStamp; + mRunNumber = bc.runNumber(); + LOG(info) << "LHCIF data fetched for run " << mRunNumber << " and timestamp " << timeStamp; + + beamPatternA = mLHCIFdata->getBunchFilling().getBeamPattern(0); + beamPatternC = mLHCIFdata->getBunchFilling().getBeamPattern(1); + bcPatternA = beamPatternA & ~beamPatternC; + bcPatternC = ~beamPatternA & beamPatternC; + bcPatternB = beamPatternA & beamPatternC; + bcPatternE = ~beamPatternA & ~beamPatternC; + + // Create bcPatternL: leading BCs of type B that follow at least "cfgEmptyBCsBeforeLeadingBC" empty BCs + bcPatternL.reset(); // Initialize all bits to false + LOG(info) << "Starting to create bcPatternL from bcPatternB"; + LOG(info) << "Total number of BCs to check: " << o2::constants::lhc::LHCMaxBunches; + + int totalLeadingBCs = 0; + for (int iBC = 0; iBC < o2::constants::lhc::LHCMaxBunches; iBC++) { + if (bcPatternB[iBC]) { // Check if current BC is of type B + int emptyBCsBefore = 0; // Count how many consecutive BCs before this one are NOT type B + for (int j = 1; j <= cfgEmptyBCsBeforeLeadingBC; j++) { + int prevBC = (iBC - j + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // Protection for BCs at small indices to check the end of the orbit + if (!bcPatternB[prevBC]) { + emptyBCsBefore++; + } else { + break; // Stop counting if we hit a type B BC + } + } + if (emptyBCsBefore >= cfgEmptyBCsBeforeLeadingBC) { // If we found at least cfgEmptyBCsBeforeLeadingBC empty BCs before this one, mark it as leading + bcPatternL[iBC] = true; + totalLeadingBCs++; + } + } + } + LOG(info) << "bcPatternL creation complete. Total leading BCs found: " << totalLeadingBCs; + + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), mRunNumber, strLPMProductionTag); + bcSOR = runInfo.orbitSOR * nBCsPerOrbit; // first bc of the first orbit + LOG(info) << "BC SOR: " << bcSOR << " (orbit SOR: " << runInfo.orbitSOR << ") NBCs per orbit: " << nBCsPerOrbit; + nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; // duration of TF in bcs + + return; + } + + float getTimeSinceSOF(const auto& bc) + { + return (bc.timestamp() - mLHCIFdata->getFillNumberTime()) / 1e3 / 60; // Convert to minutes + } + + template + void fillHistograms(float timeSinceSOF, int64_t localBC) + { + mHistManager.fill(HIST(NBCsVsTimeHistNames[iTrigger][iBCCategory]), timeSinceSOF); + mHistManager.fill(HIST(NBCsVsBCIDHistNames[iTrigger][iBCCategory]), localBC); + } + + void processZDCQA(MyBCs const& bcs, aod::Zdcs const&) + { + const int maxTimeZDC = 50; // Maximum time the histogram allows before setting a dummy value + const int dummyZDCTime = 42.f; // Time value to indicate missing ZDC time + for (const auto& bc : bcs) { + + std::bitset<64> ctpInputMask(bc.inputMask()); + + bool zdcHit = !bc.has_zdc() ? 0 : ((bc.zdc().energyCommonZNC() > -1 && std::abs(bc.zdc().timeZNC()) < 1E5) ? 1 : 0); + mHistManager.fill(HIST("ZDCQA/BCHasZDC"), zdcHit, ctpInputMask.test(25) ? 1 : 0); + if (!bc.has_zdc()) + continue; + + mHistManager.fill(HIST("ZDCQA/ZNCTimeVsEnergy"), bc.zdc().energyCommonZNC() > -1 ? bc.zdc().energyCommonZNC() : -1, std::abs(bc.zdc().timeZNC()) < maxTimeZDC ? bc.zdc().timeZNC() : dummyZDCTime); + + float timeZNA = bc.zdc().timeZNA(); + float timeZNC = bc.zdc().timeZNC(); + + if (std::abs(timeZNA) > maxTimeZDC) { + timeZNA = dummyZDCTime; // set dummy value for missing ZDC times to be able to plot them + mHistManager.fill(HIST("ZDCQA/ZNCTime"), timeZNC); + } + if (std::abs(timeZNC) > maxTimeZDC) { + timeZNC = dummyZDCTime; // set dummy value for missing ZDC times to be able to plot them + if (timeZNA != dummyZDCTime) // If ZNA and ZNC are both missing, do not fill the ZNA histogram with the dummy value + mHistManager.fill(HIST("ZDCQA/ZNATime"), timeZNA); + } + + mHistManager.fill(HIST("ZDCQA/ZDCTimes"), timeZNA, timeZNC); + } + } + PROCESS_SWITCH(LumiStabilityLightIons, processZDCQA, "process QA for the ZDC triggers (light ions and PbPb)", false); + + void processSLBunches(MyBCs const& bcs, aod::FT0s const&, aod::FDDs const&) + { + int64_t globalBCIdOfLastBCWithActivity = 0; + for (const auto& bc : bcs) { + if (bc.timestamp() == 0) + continue; + + setLHCIFData(bc); + + std::bitset<64> ctpInputMask(bc.inputMask()); + + mHistManager.fill(HIST("FITQA/BCHasFT0"), bc.has_ft0(), ctpInputMask.test(2)); + mHistManager.fill(HIST("FITQA/BCHasFDD"), bc.has_fdd(), ctpInputMask.test(15)); + + int64_t globalBC = bc.globalBC(); + + if (globalBC - globalBCIdOfLastBCWithActivity < cfgEmptyBCsBeforeLeadingBC) + continue; // not a super-leading BC + + if (bc.has_fdd() || (cfgRequireNoT0ForSLBC && bc.has_ft0())) + globalBCIdOfLastBCWithActivity = globalBC; + + float timeSinceSOF = getTimeSinceSOF(bc); + + int localBC = globalBC % nBCsPerOrbit; + + if (!bcPatternB[localBC]) + continue; + + if (ctpInputMask.test(2)) + fillHistograms(timeSinceSOF, localBC); + if (ctpInputMask.test(15)) + fillHistograms(timeSinceSOF, localBC); + } + } + PROCESS_SWITCH(LumiStabilityLightIons, processSLBunches, "process trigger counting of TVX and FDD for bunches without preceding single-arm activity", false); + + void process(MyBCs const& bcs, aod::FT0s const&) + { + for (const auto& bc : bcs) { + + if (bc.timestamp() == 0) + continue; + + setLHCIFData(bc); + + float timeSinceSOF = getTimeSinceSOF(bc); + + if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) + mHistManager.fill(HIST("FT0Vtx_EvSel/nBCsVsTime"), timeSinceSOF); + + int64_t globalBC = bc.globalBC(); + int localBC = globalBC % nBCsPerOrbit; + + int64_t thisTFid = (globalBC - bcSOR) / nBCsPerTF; + + if (thisTFid != currentTFid) { + currentTFid = thisTFid; + mHistManager.fill(HIST("TFsPerMinute"), timeSinceSOF); + } + + std::bitset<64> ctpInputMask(bc.inputMask()); + + for (int iTrigger = 0; iTrigger < nTriggers; iTrigger++) { + if ((iTrigger == kAllBCs) || (iTrigger == kFT0Vtx && cfgDoFT0Vtx) || (iTrigger == kFT0CE && cfgDoFT0CE) || (iTrigger == kFDD && cfgDoFDD) || (iTrigger == k1ZNC && cfgDo1ZNC)) { + for (int iBCCategory = 0; iBCCategory < nBCCategories - 1; iBCCategory++) { // Don't do SL BCs here + if ((iBCCategory == kBCA && cfgDoBCA) || (iBCCategory == kBCB && cfgDoBCB) || (iBCCategory == kBCC && cfgDoBCC) || (iBCCategory == kBCE && cfgDoBCE) || (iBCCategory == kBCL && cfgDoBCL)) { + if (iTrigger == kAllBCs) { + if (iBCCategory == kBCA && bcPatternA[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCB && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCC && bcPatternC[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCE && bcPatternE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCL && bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + } + if (iTrigger == kFT0Vtx && ctpInputMask.test(2)) { + if (iBCCategory == kBCA && bcPatternA[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCB && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCC && bcPatternC[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCE && bcPatternE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCL && bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + } + if (iTrigger == kFT0CE && ctpInputMask.test(4)) { + if (iBCCategory == kBCA && bcPatternA[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCB && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCC && bcPatternC[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCE && bcPatternE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCL && bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + } + if (iTrigger == kFDD && ctpInputMask.test(15)) { + if (iBCCategory == kBCA && bcPatternA[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCB && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCC && bcPatternC[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCE && bcPatternE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCL && bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + } + if (iTrigger == k1ZNC && ctpInputMask.test(25)) { + if (iBCCategory == kBCA && bcPatternA[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCB && bcPatternB[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCC && bcPatternC[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCE && bcPatternE[localBC]) + fillHistograms(timeSinceSOF, localBC); + if (iBCCategory == kBCL && bcPatternL[localBC]) + fillHistograms(timeSinceSOF, localBC); + } + } + } + } + } + mHistManager.fill(HIST("nBCsVsBCID"), localBC); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + metadataInfo.initMetadata(cfgc); + return WorkflowSpec{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 c47f2a8e315..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 diff --git a/PWGMM/Mult/DataModel/ReducedTables.h b/PWGMM/Mult/DataModel/ReducedTables.h index 8b9cdb45ba7..fbdd68b89db 100644 --- a/PWGMM/Mult/DataModel/ReducedTables.h +++ b/PWGMM/Mult/DataModel/ReducedTables.h @@ -25,12 +25,8 @@ 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 { @@ -63,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 @@ -93,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, \ @@ -110,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 @@ -134,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 @@ -161,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, \ @@ -178,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 { @@ -204,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 @@ -217,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/DataModel/bestCollisionTable.h b/PWGMM/Mult/DataModel/bestCollisionTable.h index 0abde63f3cc..0b4ee5440bc 100644 --- a/PWGMM/Mult/DataModel/bestCollisionTable.h +++ b/PWGMM/Mult/DataModel/bestCollisionTable.h @@ -8,6 +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. +/// +/// \file bestCollisionTable.h +/// \brief This code produces tables including central and MFT tracks based on smallest DCAxy/DCAz approach +/// \author Anton Alkin +/// \author Sarah Herrmann +/// \author Gyula Bencedi +/// \author Tulika Tripathy #ifndef PWGMM_MULT_DATAMODEL_BESTCOLLISIONTABLE_H_ #define PWGMM_MULT_DATAMODEL_BESTCOLLISIONTABLE_H_ @@ -33,6 +40,7 @@ DECLARE_SOA_COLUMN(AmbDegree, ambDegree, int); // degree of ambiguity of the tra DECLARE_SOA_COLUMN(BestDCAXY, bestDCAXY, float); DECLARE_SOA_COLUMN(BestDCAX, bestDCAX, float); DECLARE_SOA_COLUMN(BestDCAY, bestDCAY, float); +DECLARE_SOA_COLUMN(BestDCAZ, bestDCAZ, float); DECLARE_SOA_COLUMN(PtStatic, pts, float); DECLARE_SOA_COLUMN(PStatic, ps, float); DECLARE_SOA_COLUMN(EtaStatic, etas, float); @@ -49,12 +57,27 @@ DECLARE_SOA_TABLE(BestCollisionsFwd, "AOD", "BESTCOLLFWD", o2::soa::Index<>, pwg aod::fwdtrack::BestCollisionId, aod::fwdtrack::BestDCAXY, fwdtrack::BestDCAX, fwdtrack::BestDCAY); // beware: depending on which process produced this table, // it can be joined with either MFTAmbiguousTracks OR MFTTracks + DECLARE_SOA_TABLE(BestCollFwdExtra, "AOD", "BESTCOLLFWDE", fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Tgl, fwdtrack::Signed1Pt, fwdtrack::PtStatic, fwdtrack::PStatic, fwdtrack::EtaStatic, fwdtrack::PhiStatic); // Snp does not exist +DECLARE_SOA_TABLE(BestCollisionsFwd3d, "AOD", "BESTCOLLFWD3D", + o2::soa::Index<>, + pwgmm::indices::MFTTrackId, + aod::fwdtrack::AmbDegree, + aod::fwdtrack::BestCollisionId, + aod::fwdtrack::BestDCAXY, + aod::fwdtrack::BestDCAZ); + +DECLARE_SOA_TABLE(BestCollisionsFwd3dExtra, "AOD", "BESTCOLLFWD3DE", + fwdtrack::X, fwdtrack::Y, + fwdtrack::Z, fwdtrack::Tgl, fwdtrack::Signed1Pt, + fwdtrack::PtStatic, fwdtrack::PStatic, fwdtrack::EtaStatic, + fwdtrack::PhiStatic); // Snp does not exist + DECLARE_SOA_TABLE(ReassignedTracksCore, "AOD", "CRRETRACKS", aod::track::BestCollisionId, pwgmm::indices::TrackId, diff --git a/PWGMM/Mult/TableProducer/CMakeLists.txt b/PWGMM/Mult/TableProducer/CMakeLists.txt index 9b1ddb5e997..4d5bf59fe89 100644 --- a/PWGMM/Mult/TableProducer/CMakeLists.txt +++ b/PWGMM/Mult/TableProducer/CMakeLists.txt @@ -25,7 +25,7 @@ o2physics_add_dpl_workflow(reducer-post COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(track-propagation - SOURCES trackPropagation.cxx + SOURCES ambiguousTrackPropagation.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsCommonDataFormats COMPONENT_NAME Analysis) diff --git a/PWGMM/Mult/TableProducer/trackPropagation.cxx b/PWGMM/Mult/TableProducer/ambiguousTrackPropagation.cxx similarity index 67% rename from PWGMM/Mult/TableProducer/trackPropagation.cxx rename to PWGMM/Mult/TableProducer/ambiguousTrackPropagation.cxx index a1dffe08dbf..69c0845e0e0 100644 --- a/PWGMM/Mult/TableProducer/trackPropagation.cxx +++ b/PWGMM/Mult/TableProducer/ambiguousTrackPropagation.cxx @@ -8,33 +8,38 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// +/// \file ambiguousTrackPropagation.cxx +/// \brief This code loops over central and MFT tracks and among the compatible +/// collisions to this track, picks the one with the smallest DCAxy/DCAz and puts it +/// in a table +/// \author Anton Alkin +/// \author Sarah Herrmann +/// \author Gyula Bencedi +/// \author Tulika Tripathy -// \file trackPropagation.cxx -// \author Anton Alkin -// \author Sarah Herrmann -// -// \brief This code loops over central and MFT tracks and among the compatible -// collisions to this track, picks the one with the smallest DCAxy and puts it -// in a table +#include "bestCollisionTable.h" -#include "CCDB/BasicCCDBManager.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/GeomConstants.h" #include "DataFormatsParameters/GRPMagField.h" #include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/TrackFwd.h" + #include "Math/MatrixFunctions.h" #include "Math/SMatrix.h" - -#include "Field/MagneticField.h" #include "TGeoGlobalMagField.h" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "bestCollisionTable.h" +#include +#include using SMatrix55 = ROOT::Math::SMatrix>; using SMatrix5 = ROOT::Math::SVector; @@ -46,32 +51,35 @@ using namespace o2; using namespace o2::framework; using namespace o2::aod::track; -AxisSpec DCAxyAxis = {500, -1, 50}; - struct AmbiguousTrackPropagation { - // Produces tracksBestCollisions; Produces fwdtracksBestCollisions; + Produces fwdtracksBestCollisions3d; + Produces fwdtracksBestCollisions3dExtra; Produces fwdtracksBestCollExtra; Produces tracksReassignedCore; Produces tracksReassignedExtra; 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 + float bZ = 0; // Magnetic field for MFT + static constexpr double kCenterMFT[3] = {0, 0, -61.4}; // Field at center of MFT o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; o2::parameters::GRPMagField* grpmag = nullptr; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdburl{"ccdburl", "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"}; Configurable mVtxPath{"mVtxPath", "GLO/Calib/MeanVertex", "Path of the mean vertex file"}; Configurable produceExtra{"produceExtra", false, "Produce table with refitted track parameters"}; Configurable produceHistos{"produceHistos", false, "Produce control histograms"}; + Configurable removeTrivialAssoc{"removeTrivialAssoc", false, "Skip trivial associations"}; + + ConfigurableAxis binsDCAxy{"binsDCAxy", {200, -1., 1.}, ""}; + ConfigurableAxis binsDCAz{"binsDCAz", {200, -1., 1.}, ""}; HistogramRegistry registry{ "registry", @@ -84,18 +92,30 @@ struct AmbiguousTrackPropagation { void init(o2::framework::InitContext& /*initContext*/) { + + AxisSpec dcaXYAxis = {binsDCAxy, "dcaXYAxis", "dcaXYAxis"}; + AxisSpec dcaZAxis = {binsDCAz, "dcaZAxis", "dcaZAxis"}; + ccdb->setURL(ccdburl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); if (produceHistos) { - if (doprocessMFT || doprocessMFTReassoc) { + if (doprocessMFT || doprocessMFTReassoc || doprocessMFTReassoc3D) { 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({"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 (doprocessMFTReassoc3D) { + registry.add({"TracksAmbDegreeWoTrivial", " ; N_{coll}^{comp}", {HistType::kTH1F, {{41, -0.5, 40.5}}}}); + registry.add({"TracksFirstDCAXY", " ; DCA_{XY} (cm)", {HistType::kTH1F, {dcaXYAxis}}}); + registry.add({"TracksFirstDCAZ", " ; DCA_{Z} (cm)", {HistType::kTH1F, {dcaZAxis}}}); + registry.add({"TracksDCAZ", " ; DCA_{Z} (cm)", {HistType::kTH1F, {dcaZAxis}}}); + registry.add({"ReassignedDCAZ", " ; DCA_{Z} (cm)", {HistType::kTH1F, {dcaZAxis}}}); + registry.add({"TracksOrigDCAZ", " ; DCA_{Z} (wrt orig coll) (cm)", {HistType::kTH1F, {dcaZAxis}}}); + } } if (doprocessCentral) { registry.add({"PropagationFailures", "", {HistType::kTH1F, {{5, 0.5, 5.5}}}}); @@ -122,18 +142,18 @@ struct AmbiguousTrackPropagation { o2::base::Propagator::initFieldFromGRP(grpmag); runNumber = bc.runNumber(); - if (doprocessMFT || doprocessMFTReassoc) { + if (doprocessMFT || doprocessMFTReassoc || doprocessMFTReassoc3D) { o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); - Bz = field->getBz(centerMFT); - LOG(info) << "The field at the center of the MFT is Bz = " << Bz; + bZ = field->getBz(kCenterMFT); + LOG(info) << "The field at the center of the MFT is bZ = " << bZ; } } - static constexpr TrackSelectionFlags::flagtype trackSelectionITS = + static constexpr TrackSelectionFlags::flagtype kTrackSelectionITS = TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF | TrackSelectionFlags::kITSHits; - static constexpr TrackSelectionFlags::flagtype trackSelectionTPC = + static constexpr TrackSelectionFlags::flagtype kTrackSelectionTPC = TrackSelectionFlags::kTPCNCls | TrackSelectionFlags::kTPCCrossedRowsOverNCls | TrackSelectionFlags::kTPCChi2NDF; @@ -150,21 +170,21 @@ struct AmbiguousTrackPropagation { auto bc = bcs.begin(); initCCDB(bc); - gpu::gpustd::array dcaInfo; + std::array dcaInfo; float bestDCA[2]; o2::track::TrackParametrization bestTrackPar; - for (auto& track : tracks) { + for (auto const& track : tracks) { dcaInfo[0] = track.dcaXY(); // DCAxy dcaInfo[1] = track.dcaZ(); // DCAz bestDCA[0] = dcaInfo[0]; bestDCA[1] = dcaInfo[1]; auto bestCol = track.has_collision() ? track.collisionId() : -1; - if ((track.trackCutFlag() & trackSelectionITS) != trackSelectionITS) { + if ((track.trackCutFlag() & kTrackSelectionITS) != kTrackSelectionITS) { continue; } if ((track.detectorMap() & (uint8_t)o2::aod::track::TPC) == (uint8_t)o2::aod::track::TPC) { - if ((track.trackCutFlag() & trackSelectionTPC) != trackSelectionTPC) { + if ((track.trackCutFlag() & kTrackSelectionTPC) != kTrackSelectionTPC) { continue; } } @@ -181,7 +201,7 @@ struct AmbiguousTrackPropagation { } auto compatibleColls = track.compatibleColl(); int failures = 0; - for (auto& collision : compatibleColls) { + for (auto const& collision : compatibleColls) { auto propagated = o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, matCorr, &dcaInfo); if (!propagated) { ++failures; @@ -239,7 +259,7 @@ struct AmbiguousTrackPropagation { float bestDCA = 0.f, bestDCAx = 0.f, bestDCAy = 0.f; o2::track::TrackParCovFwd bestTrackPar; - for (auto& atrack : atracks) { + for (auto const& atrack : atracks) { dcaInfo = 999; // DCAxy bestDCA = 999; @@ -254,14 +274,14 @@ struct AmbiguousTrackPropagation { int degree = 0; // degree of ambiguity of the track auto compatibleBCs = atrack.bc_as(); - for (auto& bc : compatibleBCs) { + for (auto const& bc : compatibleBCs) { if (!bc.has_collisions()) { continue; } auto collisions = bc.collisions(); for (auto const& collision : collisions) { degree++; - trackPar.propagateToZhelix(collision.posZ(), Bz); // track parameters propagation to the position of the z vertex + trackPar.propagateToZhelix(collision.posZ(), bZ); // track parameters propagation to the position of the z vertex const auto dcaX(trackPar.getX() - collision.posX()); const auto dcaY(trackPar.getY() - collision.posY()); @@ -325,7 +345,7 @@ struct AmbiguousTrackPropagation { float bestDCA = 0.f, bestDCAx = 0.f, bestDCAy = 0.f; o2::track::TrackParCovFwd bestTrackPar; - for (auto& track : tracks) { + for (auto const& track : tracks) { dcaInfo = 999; // DCAxy bestDCA = 999; @@ -345,9 +365,9 @@ struct AmbiguousTrackPropagation { SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); o2::track::TrackParCovFwd trackPar{track.z(), tpars, tcovs, track.chi2()}; - for (auto& collision : compatibleColls) { + for (auto const& collision : compatibleColls) { - trackPar.propagateToZhelix(collision.posZ(), Bz); // track parameters propagation to the position of the z vertex + trackPar.propagateToZhelix(collision.posZ(), bZ); // track parameters propagation to the position of the z vertex const auto dcaX(trackPar.getX() - collision.posX()); const auto dcaY(trackPar.getY() - collision.posY()); @@ -394,6 +414,100 @@ struct AmbiguousTrackPropagation { } } PROCESS_SWITCH(AmbiguousTrackPropagation, processMFTReassoc, "Fill BestCollisionsFwd for MFT ambiguous tracks with the new data model", false); + + void processMFTReassoc3D(MFTTracksWColls const& tracks, aod::Collisions const&, ExtBCs const& bcs) + { + if (bcs.size() == 0) { + return; + } + if (tracks.size() == 0) { + return; + } + auto bc = bcs.begin(); + initCCDB(bc); + + std::array dcaInfOrig; + std::array dcaInfo; + double bestDCA[2]; + o2::track::TrackParCovFwd bestTrackPar; + + for (auto const& track : tracks) { + dcaInfOrig[0] = 999.f; // original DCAx from propagation + dcaInfOrig[1] = 999.f; // original DCAy from propagation + dcaInfOrig[2] = 999.f; // original DCAz from propagation + dcaInfo[0] = 999.f; // calcualted DCAxy + dcaInfo[1] = 999.f; // calculated DCAz - same as original + bestDCA[0] = 999.f; // minimal DCAxy + bestDCA[1] = 999.f; // minimal DCAz + + auto bestCol = track.has_collision() ? track.collisionId() : -1; + + if (removeTrivialAssoc) { + if (track.compatibleCollIds().empty() || (track.compatibleCollIds().size() == 1 && bestCol == track.compatibleCollIds()[0])) { + if (produceHistos) { + registry.fill(HIST("TracksAmbDegreeWoTrivial"), track.compatibleCollIds().size()); + } + continue; + } + } + + auto compatibleColls = track.compatibleColl(); + + 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()}; + + for (auto const& collision : compatibleColls) { + + trackPar.propagateToDCAhelix(bZ, {collision.posX(), collision.posY(), collision.posZ()}, dcaInfOrig); + dcaInfo[0] = std::sqrt(dcaInfOrig[0] * dcaInfOrig[0] + dcaInfOrig[1] * dcaInfOrig[1]); + dcaInfo[1] = dcaInfOrig[2]; + + if ((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 ((track.collisionId() != collision.globalIndex()) && produceHistos) { + registry.fill(HIST("DeltaZ"), track.collision().posZ() - collision.posZ()); // deltaZ between the 1st coll zvtx and the other compatible ones + registry.fill(HIST("TracksFirstDCAXY"), dcaInfo[0]); + registry.fill(HIST("TracksFirstDCAZ"), dcaInfo[1]); + } + if (produceHistos) { + registry.fill(HIST("TracksDCAXY"), dcaInfo[0]); + registry.fill(HIST("TracksDCAZ"), dcaInfo[1]); + } + + if ((collision.globalIndex() == track.collisionId()) && produceHistos) { + registry.fill(HIST("TracksOrigDCAXY"), dcaInfo[0]); + registry.fill(HIST("TracksOrigDCAZ"), dcaInfo[1]); + } + } + if ((bestCol != track.collisionId()) && produceHistos) { + // reassigned + registry.fill(HIST("ReassignedDCAXY"), bestDCA[0]); + registry.fill(HIST("ReassignedDCAZ"), bestDCA[1]); + } + if (produceHistos) { + int isAmbiguous = 0; + registry.fill(HIST("TracksAmbDegree"), compatibleColls.size()); + if (compatibleColls.size() > 1) { + isAmbiguous = 1; + } + registry.fill(HIST("TrackIsAmb"), isAmbiguous); + } + + fwdtracksBestCollisions3d(track.globalIndex(), compatibleColls.size(), bestCol, bestDCA[0], bestDCA[1]); + if (produceExtra) { + fwdtracksBestCollisions3dExtra(bestTrackPar.getX(), bestTrackPar.getY(), bestTrackPar.getZ(), + bestTrackPar.getTgl(), bestTrackPar.getInvQPt(), bestTrackPar.getPt(), + bestTrackPar.getP(), bestTrackPar.getEta(), bestTrackPar.getPhi()); + } + } + } + PROCESS_SWITCH(AmbiguousTrackPropagation, processMFTReassoc3D, "Fill ReassignedTracks for MFT ambiguous tracks", false); }; //**************************************************************************************** diff --git a/PWGMM/Mult/TableProducer/percentiles.cxx b/PWGMM/Mult/TableProducer/percentiles.cxx index 1f746ecea97..c11fca858f8 100644 --- a/PWGMM/Mult/TableProducer/percentiles.cxx +++ b/PWGMM/Mult/TableProducer/percentiles.cxx @@ -42,16 +42,15 @@ struct Binner { Preslice perMcCol = aod::mcparticle::mcCollisionId; Preslice perCol = aod::track::collisionId; - ConfigurableAxis multBinning{"multBinning", {301, -0.5, 300.5}, ""}; + ConfigurableAxis multBinning{"multBinning", {302, -1.5, 300.5}, ""}; ConfigurableAxis centBinning{"centBinning", {VARIABLE_WIDTH, 0, 1, 5, 10, 15, 20, 30, 40, 50, 70, 100}, ""}; - AxisSpec SmallMultAxis = {100, 0.5, 100.5}; // 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) + bool isChargedParticle(int code) const { static auto p = pdg->GetParticle(code); if (p == nullptr) { @@ -86,7 +85,6 @@ struct Binner { void init(InitContext const&) { AxisSpec MultAxis = {multBinning}; - AxisSpec CentAxis = {centBinning}; h.add({"hFT0M", "; N_{part} in FT0M acc", {HistType::kTH1F, {MultAxis}}}); h.add({"hFT0C", "; N_{part} in FT0C acc", {HistType::kTH1F, {MultAxis}}}); if (dobin) { @@ -95,10 +93,13 @@ struct Binner { ccdb->setLocalObjectValidityChecking(); } if (docalibrateAdvanced) { - h.add({"hCorrelate", " ; N_{part}^{FT0M}; N_{part}^{FT0C}; N_{trk}^{#eta = 0}", {HistType::kTHnSparseF, {MultAxis, MultAxis, SmallMultAxis}}}); + 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) { - h.add({"hTrkAt0vsFT0M", " ; N_{trk}^{#eta = 0}; FT0M percentile", {HistType::kTH2F, {SmallMultAxis, CentAxis}}}); + AxisSpec CentAxis = {centBinning}; + h.add({"hTrkAt0vsFT0M", " ; N_{trk}^{#eta = 0}; FT0M percentile", {HistType::kTH2F, {MultAxis, CentAxis}}}); } } @@ -130,7 +131,7 @@ struct Binner { PROCESS_SWITCH(Binner, calibrate, "Create binnings", true); - using ExColsMC = soa::Join; + 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 &&) @@ -142,7 +143,7 @@ struct Binner { Filter fTracksEta = nabs(aod::track::eta) < 0.5f; void calibrateAdvanced(aod::McCollision const& mcc, - soa::SmallGroups const& collisions, + soa::SmallGroups const& collisions, Particles const&, soa::Filtered const& tracks) { @@ -165,17 +166,22 @@ struct Binner { 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) { - return; + nTrkAt0 = -1; + cent = -1; } - h.fill(HIST("hCorrelate"), nFT0M, nFT0C, nTrkAt0); + h.fill(HIST("hCorrelate"), nFT0M, nFT0C, nTrkAt0, cent); } PROCESS_SWITCH(Binner, calibrateAdvanced, "Create binning matched to dN/deta", false); diff --git a/PWGMM/Mult/Tasks/CMakeLists.txt b/PWGMM/Mult/Tasks/CMakeLists.txt index 4828a7ea434..aae28c5eef1 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 @@ -74,3 +79,8 @@ o2physics_add_dpl_workflow(flattenicty-chrg SOURCES flattenicty-chrg.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pseudo-eff-mft + SOURCES pseudoEffMFT.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2::MFTBase O2::DataFormatsMFT O2::MFTTracking O2::ITSMFTSimulation O2::ITSMFTWorkflow + COMPONENT_NAME Analysis) diff --git a/PWGMM/Mult/Tasks/dndeta-hi.cxx b/PWGMM/Mult/Tasks/dndeta-hi.cxx index 7ac1bc49bb5..d479a3138e3 100644 --- a/PWGMM/Mult/Tasks/dndeta-hi.cxx +++ b/PWGMM/Mult/Tasks/dndeta-hi.cxx @@ -9,29 +9,24 @@ // 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 - +#include "Index.h" #include "bestCollisionTable.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" + +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + #include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/MathConstants.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" @@ -41,14 +36,21 @@ #include "Framework/O2DatabasePDGPlugin.h" #include "Framework/RuntimeError.h" #include "Framework/runDataProcessing.h" -#include "Index.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/Track.h" -#include "PWGHF/Core/SelectorCuts.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" -#include "PWGHF/DataModel/CandidateSelectionTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include using namespace o2; using namespace o2::framework; diff --git a/PWGMM/Mult/Tasks/dndeta-mft.cxx b/PWGMM/Mult/Tasks/dndeta-mft.cxx index 7d52a606226..f70cc1d638a 100644 --- a/PWGMM/Mult/Tasks/dndeta-mft.cxx +++ b/PWGMM/Mult/Tasks/dndeta-mft.cxx @@ -1,4 +1,4 @@ -// Copyright 2020-2022 CERN and copyright holders of ALICE O2. +// Copyright 2020-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. // diff --git a/PWGMM/Mult/Tasks/dndeta.cxx b/PWGMM/Mult/Tasks/dndeta.cxx index 0d3ff49cd3f..220bdbdebb8 100644 --- a/PWGMM/Mult/Tasks/dndeta.cxx +++ b/PWGMM/Mult/Tasks/dndeta.cxx @@ -50,8 +50,9 @@ 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 response matrix"}; Configurable useProcId{"use-process-id", true, "Use process ID from generator"}; @@ -111,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(); @@ -124,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()); @@ -142,57 +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({NpvcZvtx.data(), "; N_{PVc}; 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, {{static_cast(EvSelBins::kRejected), 0.5, static_cast(EvSelBins::kRejected) + 0.5}, CentAxis}}}); - auto hstat = binnedRegistry.get(HIST(EventSelection)); - auto* x = hstat->GetXaxis(); + 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", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({NpvcZvtx.data(), "; N_{PVc}; 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({EtaZvtx_gt0.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({EtaZvtx_PVgt0.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({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}}}); } } @@ -203,36 +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({NpvcZvxtGen.data(), "; N_{PVc}; Z_{vtx} (cm); events", {HistType::kTH2F, {MultAxis, ZAxis}}}); - 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()); @@ -251,36 +261,45 @@ struct MultiplicityCounter { effLabels += " ; process ID"; effAxes.push_back(ProcAxis); } - 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({NpvcZvxtGen.data(), "; N_{PVc}; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {MultAxis, ZAxis, CentAxis}}}); - binnedRegistry.add({EtaZvtxGen.data(), "; #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {EtaAxis, ZAxis, CentAxis}}}); + 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(), 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, 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()); @@ -290,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}}}); } } } @@ -373,18 +392,13 @@ struct MultiplicityCounter { auto col = collisions.begin(); for (auto& colid : colids) { col.moveByIndex(colid - col.globalIndex()); - 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); + 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()); } } } @@ -448,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) { @@ -456,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); } } } @@ -479,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), static_cast(EvSelBins::kAll), 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), static_cast(EvSelBins::kSelected), 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(); @@ -503,57 +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()) { + 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); + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedPVgt0), c, o); } if (Ntrks > 0) { - binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedgt0), c); + 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); + binnedRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z, c, o); } if (INELgt0PV) { - binnedRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z, c); + binnedRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z, c, o); } } } - binnedRegistry.fill(HIST(NtrkZvtx), Ntrks, z, c); - binnedRegistry.fill(HIST(NpvcZvtx), groupPVContrib.size(), z, c); + 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(NpvcZvtx), groupPVContrib.size(), z); + inclusiveRegistry.fill(HIST(NtrkZvtx), Ntrks, z, o); + inclusiveRegistry.fill(HIST(NpvcZvtx), groupPVContrib.size(), z, o); } } else { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kRejected), 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) { @@ -575,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); } } } @@ -634,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); } } } @@ -658,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), static_cast(EvSelBins::kAll), 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), static_cast(EvSelBins::kSelected), 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(); @@ -682,21 +688,21 @@ 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()) { + 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); + binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedPVgt0), c, o); } if (Ntrks > 0) { - binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kSelectedgt0), c); + 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); + 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); + binnedRegistry.fill(HIST(EtaZvtx_PVgt0), track.track_as().eta(), z, c, o); } } for (auto& track : tracks) { @@ -707,29 +713,29 @@ struct MultiplicityCounter { continue; } if (Ntrks > 0) { - binnedRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z, c); + binnedRegistry.fill(HIST(EtaZvtx_gt0), track.eta(), z, c, o); } if (INELgt0PV) { - binnedRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z, c); + binnedRegistry.fill(HIST(EtaZvtx_PVgt0), track.eta(), z, c, o); } } } - binnedRegistry.fill(HIST(NtrkZvtx), Ntrks, z, c); - binnedRegistry.fill(HIST(NpvcZvtx), groupPVContrib.size(), z, c); + 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) { @@ -740,21 +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(NpvcZvtx), groupPVContrib.size(), z); + inclusiveRegistry.fill(HIST(NtrkZvtx), Ntrks, z, o); + inclusiveRegistry.fill(HIST(NpvcZvtx), groupPVContrib.size(), z, o); } } else { - if constexpr (hasRecoCent()) { - binnedRegistry.fill(HIST(EventSelection), static_cast(EvSelBins::kRejected), 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); } } } @@ -846,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); } } } @@ -904,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); } } } @@ -1054,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; } @@ -1081,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); } } } @@ -1128,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); } } } @@ -1171,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); } } } @@ -1215,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; } @@ -1237,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); } } } @@ -1279,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); } } } @@ -1476,6 +1459,7 @@ struct MultiplicityCounter { std::vector NrecPerCol; std::vector c_recPerCol; + std::vector OccuPerCol; std::vector NPVPerCol; std::vector NFT0APerCol; std::vector NFT0CPerCol; @@ -1489,23 +1473,19 @@ 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(); - } else if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - if constexpr (requires { mcCollision.gencentFT0C(); }) { - c_gen = mcCollision.gencentFT0C(); - } - } else if (C::template contains()) { - if constexpr (requires { mcCollision.gencentFT0M(); }) { - c_gen = mcCollision.gencentFT0M(); - } + 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(); @@ -1518,170 +1498,159 @@ struct MultiplicityCounter { auto moreThanOne = 0; LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), collisions.size()); - [[maybe_unused]] float min_c_rec = 2e2; - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { + float min_c_rec = 2e2; for (auto& collision : collisions) { if (!useEvSel || isCollisionSelected(collision)) { - float c = -1; - if constexpr (C::template contains()) { - c = collision.centFT0C(); - } else if (C::template contains()) { - c = collision.centFT0M(); - } + 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) + } + } } - if constexpr (hasRecoCent() && !hasSimCent()) { - if (std::abs(c_gen + 1) < 1e-6) { - 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(); - } - 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; 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(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); - binnedRegistry.fill(HIST(NpvcZvxtGen), groupPVcontrib.size(), 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()); + 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()) { - if constexpr (soa::is_soa_join_v) { - if constexpr (MC::template contains()) { - if (useProcId) { - binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i], mcCollision.processId()); - } else { - 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 { - binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i]); + 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()); @@ -1690,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()); @@ -1698,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 @@ -1708,18 +1677,13 @@ struct MultiplicityCounter { Particles const& particles, FiTracks const& tracks) { float c_gen = -1; - // add generated centrality estimation - if constexpr (hasSimCent()) { - c_gen = mcCollision.centrality(); - } else if constexpr (hasRecoCent()) { - if constexpr (C::template contains()) { - if constexpr (requires { mcCollision.gencentFT0C(); }) { - c_gen = mcCollision.gencentFT0C(); - } - } else if (C::template contains()) { - if constexpr (requires { mcCollision.gencentFT0M(); }) { - c_gen = mcCollision.gencentFT0M(); - } + 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); } } @@ -1731,47 +1695,47 @@ struct MultiplicityCounter { NrecPerCol.clear(); c_recPerCol.clear(); + OccuPerCol.clear(); NPVPerCol.clear(); NFT0APerCol.clear(); NFT0CPerCol.clear(); NFDDAPerCol.clear(); NFDDCPerCol.clear(); - [[maybe_unused]] float min_c_rec = 2e2; - if constexpr (hasRecoCent()) { + if constexpr (has_reco_cent) { + float min_c_rec = 2e2; for (auto& collision : collisions) { if (!useEvSel || isCollisionSelected(collision)) { - float c = -1; - if constexpr (C::template contains()) { - c = collision.centFT0C(); - } else if (C::template contains()) { - c = collision.centFT0M(); - } + 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) + } + } } - - if constexpr (hasRecoCent() && !hasSimCent()) { - if (std::abs(c_gen + 1) < 1e-6) { - 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(); - } - 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); @@ -1781,126 +1745,114 @@ struct MultiplicityCounter { 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(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); - binnedRegistry.fill(HIST(NpvcZvxtGen), groupPVcontrib.size(), 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()); + 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()) { - if constexpr (soa::is_soa_join_v) { - if constexpr (MC::template contains()) { - if (useProcId) { - binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i], mcCollision.processId()); - } else { - 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 { - binnedRegistry.fill(HIST(EfficiencyMult), nCharged, mcCollision.posZ(), c_recPerCol[i]); + 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()); @@ -1909,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; diff --git a/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx new file mode 100644 index 00000000000..c8a26100cbd --- /dev/null +++ b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx @@ -0,0 +1,3372 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "Functions.h" +#include "Index.h" +#include "bestCollisionTable.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 "CCDB/BasicCCDBManager.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/RuntimeError.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +#include "TMCProcess.h" +#include "TPDGCode.h" + +#include +#include +#include +#include +#include +#include +#include + +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; +using namespace o2::aod::rctsel; + +auto static constexpr kMinCharge = 3.f; +auto static constexpr kIntZero = 0; +auto static constexpr kZero = 0.f; + +enum TrkSel { + trkSelAll, + trkSelNCls, + trkSelChi2Ncl, + trkSelEta, + trkSelPhiCut, + trkSelPt, + trkSelCA, + nTrkSel +}; + +enum TrkBestSel { + trkBestSelAll, + trkBestSelCollID, + trkBestSelDCAxyCut, + trkBestSelDCAzCut, + trkBestSelNumReassoc, + nTrkBestSel +}; + +enum AmbTrkType { + kNonAmb = 0, + kOrphan = 1, + kNonAmbSame = 2, + kAmb = 3, + kAmbGt1 = 4, + nAmbTrkType +}; + +struct DndetaMFTPbPb { + SliceCache cache; + + std::array, 4> hCollAssoc; + std::array, 4> hReAssoc; + std::array, 6> hDCAMc; + + enum OccupancyEst { TrkITS = 1, + Ft0C }; + + HistogramRegistry registry{ + "registry", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry qaregistry{ + "qaregistry", + {}, + OutputObjHandlingPolicy::AnalysisObject, + false, + true}; + + Configurable cfgDoIR{"cfgDoIR", false, "Flag to retrieve Interaction rate from CCDB"}; + Configurable cfgUseIRCut{"cfgUseIRCut", false, "Flag to cut on IR rate"}; + Configurable cfgIRCrashOnNull{"cfgIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash"}; + Configurable cfgIRSource{"cfgIRSource", "ZNC hadronic", "Estimator of the interaction rate (Pb-Pb: ZNC hadronic)"}; + Configurable cfgUseTrackSel{"cfgUseTrackSel", false, "Flag to apply track selection"}; + Configurable cfgUseParticleSel{"cfgUseParticleSel", false, "Flag to apply particle selection"}; + Configurable cfgRemoveReassigned{"cfgRemoveReassigned", false, "Remove reassgined tracks"}; + + struct : ConfigurableGroup { + ConfigurableAxis interactionRateBins{"interactionRateBins", {500, 0, 50}, "Binning for the interaction rate (kHz)"}; + 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)"}; + ConfigurableAxis pvBins{"pvBins", {501, -0.5, 500.5}, ""}; + ConfigurableAxis fv0aMultBins{"fv0aMultBins", {501, -0.5, 500.5}, ""}; + ConfigurableAxis ft0aMultBins{"ft0aMultBins", {501, -0.5, 500.5}, ""}; + ConfigurableAxis ft0cMultBins{"ft0cMultBins", {501, -0.5, 500.5}, ""}; + ConfigurableAxis ptBins{"ptBins", {101, -0.5, 10.5}, "pT binning (GeV/c)"}; + ConfigurableAxis multBins{"multBins", {701, -0.5, 700.5}, "Multiplicity binning"}; + ConfigurableAxis zvtxBins{"zvtxBins", {60, -30., 30.}, "Z-vtx binning (cm)"}; + ConfigurableAxis deltaZBins{"deltaZBins", {800, -10., 10.}, "Delta Z-vtx binning (cm)"}; + ConfigurableAxis dcaXYBins{"dcaXYBins", {800, -1., 1.}, "DCAxy binning (cm)"}; + ConfigurableAxis dcaZBins{"dcaZBins", {800, -1., 1.}, "DCAz binning (cm)"}; + ConfigurableAxis phiBins{"phiBins", {629, 0., TwoPI}, "#varphi binning (rad)"}; + ConfigurableAxis etaBins{"etaBins", {20, -4., -2.}, "#eta binning"}; + ConfigurableAxis chiSqPerNclBins{"chiSqPerNclBins", {100, 0, 100}, "#chi^{2} binning"}; + ConfigurableAxis nClBins{"nClBins", {10, 0.5, 10.5}, "number of clusters binning"}; + } binOpt; + + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", false, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_fw", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCuts; + + 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 useChi2Cut{"useChi2Cut", false, "use track chi2 cut"}; + Configurable maxChi2NCl{"maxChi2NCl", 1000.f, "maximum chi2 per MFT clusters"}; + Configurable usePtCut{"usePtCut", false, "use track pT cut"}; + Configurable minPt{"minPt", 0., "minimum pT of the MFT tracks"}; + Configurable requireCA{"requireCA", false, "Use Cellular Automaton track-finding algorithm"}; + Configurable maxDCAxy{"maxDCAxy", 0.01f, "Cut on dca XY"}; + Configurable maxDCAz{"maxDCAz", 0.01f, "Cut on dca Z"}; + } trackCuts; + + struct : ConfigurableGroup { + Configurable maxZvtx{"maxZvtx", 20.0f, "maximum cut on z-vtx (cm)"}; + Configurable minZvtx{"minZvtx", -20.0f, "minimum cut on z-vtx (cm)"}; + 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 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 requireRejectSameBunchPileup{"requireRejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", true, " requireNoCollInTimeRangeStrict"}; + Configurable requireNoCollInRofStrict{"requireNoCollInRofStrict", false, "requireNoCollInRofStrict"}; + Configurable requireNoCollInRofStandard{"requireNoCollInRofStandard", false, "requireNoCollInRofStandard"}; + Configurable requireNoHighMultCollInPrevRof{"requireNoHighMultCollInPrevRof", false, "requireNoHighMultCollInPrevRof"}; + 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 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; + + 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"}; + + int mRunNumber{-1}; + uint64_t mSOR{0}; + float mMinSeconds{-1.}; + std::unordered_map gHadronicRate; + ctpRateFetcher rateFetcher; + TH2* gCurrentHadronicRate; + RCTFlagsChecker rctChecker; + + std::vector ambiguousTrkIds; + std::vector reassignedTrkIds; + std::vector ambiguousTrkIdsMC; + std::vector reassignedTrkIdsMC; + + /// @brief init function, definition of histograms + void init(InitContext&) + { + const AxisSpec pvAxis = {binOpt.pvBins, "PV", "PV axis"}; + const AxisSpec multFV0aAxis = {binOpt.fv0aMultBins, "fv0a", "FV0AMult axis"}; + const AxisSpec multFT0aAxis = {binOpt.ft0aMultBins, "ft0a", "FT0AMult axis"}; + const AxisSpec multFT0cAxis = {binOpt.ft0cMultBins, "ft0c", "FT0CMult axis"}; + const AxisSpec centralityAxis = {binOpt.centralityBins, "Centrality", "centrality axis"}; + const AxisSpec occupancyAxis = {binOpt.occupancyBins, "Occupancy", "occupancy axis"}; + const AxisSpec irAxis = {binOpt.interactionRateBins, "Interaction Rate", "IR axis"}; + const AxisSpec ptAxis = {binOpt.ptBins, "Pt axis (GeV/c)"}; + const AxisSpec multAxis = {binOpt.multBins, "N_{trk} axis"}; + const AxisSpec zAxis = {binOpt.zvtxBins, "Z-vtx axis"}; + const AxisSpec deltaZAxis = {binOpt.deltaZBins, "Delta Z-vtx axis"}; + const AxisSpec dcaxyAxis = {binOpt.dcaXYBins, "DCA-xy axis"}; + const AxisSpec dcazAxis = {binOpt.dcaZBins, "DCA-z axis"}; + const AxisSpec phiAxis = {binOpt.phiBins, "#phi axis"}; + const AxisSpec etaAxis = {binOpt.etaBins, "#eta axis"}; + const AxisSpec chiSqAxis = {binOpt.chiSqPerNclBins, "Chi2 axis"}; + const AxisSpec nclsAxis = {binOpt.nClBins, "Number of clusters axis"}; + + rctChecker.init(rctCuts.cfgEvtRCTFlagCheckerLabel, rctCuts.cfgEvtRCTFlagCheckerZDCCheck, rctCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + 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("Events/hEvtSel", "hEvtSel", HistType::kTH1F, + {{15, -0.5f, +14.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, "kNoCollInTimeRangeStrict"); + hev->GetXaxis()->SetBinLabel(9, "kNoCollInRofStrict"); + hev->GetXaxis()->SetBinLabel(10, "kNoCollInRofStandard"); + hev->GetXaxis()->SetBinLabel(11, "kNoHighMultCollInPrevRof"); + hev->GetXaxis()->SetBinLabel(12, "Below min occup."); + hev->GetXaxis()->SetBinLabel(13, "Above max occup."); + hev->GetXaxis()->SetBinLabel(14, "RCT Flag Checker"); + + registry.add("Tracks/hBestTrkSel", "Number of best tracks; Cut; #Tracks Passed Cut", {HistType::kTH1F, {{nTrkBestSel, -0.5, +nTrkBestSel - 0.5}}}); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelAll + 1, "All"); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelCollID + 1, "Assigned (ID>=0)"); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelDCAxyCut + 1, "DCA xy cut"); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelDCAzCut + 1, "DCA z cut"); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelNumReassoc + 1, "Reassociated"); + + registry.add("Tracks/hTrkSel", "Number of tracks; Cut; #Tracks Passed Cut", {HistType::kTH1F, {{nTrkSel, -0.5, +nTrkSel - 0.5}}}); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelAll + 1, "All"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNCls + 1, "Ncl cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelChi2Ncl + 1, "#chi^{2}/Ncl cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelEta + 1, "#eta cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPhiCut + 1, "#varphi cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPt + 1, "#it{p}_{T} cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelCA + 1, "Tracking algorithm (CA)"); + + 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"); + + 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"); + + registry.add("Events/hInteractionRate", "; occupancy; IR (kHz)", kTH2F, {occupancyAxis, irAxis}); + + 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, {chiSqAxis, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Chi2", + "; #chi^{2};", + {HistType::kTH2F, {chiSqAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/NclustersEta", + "; nClusters; #eta; occupancy", + {HistType::kTHnSparseF, {nclsAxis, etaAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/NchSel", + "; N_{ch}; occupancy", + {HistType::kTH2F, {multAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/NchBestSel", + "; 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, {nclsAxis, etaAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/DCA3d", + "; p_{T} (GeV/c); #eta; DCA_{XY} (cm); DCA_{Z} (cm); occupancy", + {HistType::kTHnSparseF, {ptAxis, etaAxis, dcaxyAxis, dcazAxis, 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/OrigTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {etaAxis, zAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/OrigTracksPhiEta", + "; #varphi; #eta; occupancy", + {HistType::kTHnSparseF, {phiAxis, etaAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/RestTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, {etaAxis, zAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/RestTracksPhiEta", + "; #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"); + + registry.add("Events/Centrality/hInteractionRate", "; centrality; occupancy; IR (kHz)", kTHnSparseF, {centralityAxis, occupancyAxis, irAxis}); + + qaregistry.add({"Events/Centrality/hCent", + "; centrality; occupancy", + {HistType::kTH2F, {centralityAxis, 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/NchBestSel", + "; N_{ch}; centrality; occupancy", + {HistType::kTHnSparseF, {multAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add( + {"Tracks/Centrality/Chi2Eta", + "; #chi^{2}; #it{#eta}; centrality; occupancy", + {HistType::kTHnSparseF, + {chiSqAxis, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/Chi2", + "; #chi^{2}; centrality; occupancy", + {HistType::kTHnSparseF, + {chiSqAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/NclustersEta", + "; nClusters; #eta; centrality; occupancy", + {HistType::kTHnSparseF, + {nclsAxis, 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, + {nclsAxis, 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/DCA3d", + "; p_{T} (GeV/c); #eta; DCA_{XY} (cm); DCA_{Z} (cm); centrality; occupancy", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, dcaxyAxis, dcazAxis, 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}}}); + qaregistry.add({"Tracks/Centrality/OrigTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, + {etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/OrigTracksPhiEta", + "; #varphi; #eta; occupancy", + {HistType::kTHnSparseF, + {phiAxis, etaAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/RestTracksEtaZvtx", + "; #eta; #it{z}_{vtx} (cm); occupancy", + {HistType::kTHnSparseF, + {etaAxis, zAxis, centralityAxis, occupancyAxis}}}); + qaregistry.add({"Tracks/Centrality/RestTracksPhiEta", + "; #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 (doprocessTrkEffIdxBestInlusive) { + qaregistry.add({"Tracks/hPtEtaEffGenFakeBest", + "; p_{T} (GeV/c); #eta", + {HistType::kTH2F, + {ptAxis, etaAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffGenBest", + "; p_{T} (GeV/c); #eta", + {HistType::kTH2F, + {ptAxis, etaAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffPrimBest", + "; p_{T} (GeV/c); #eta", + {HistType::kTH2F, + {ptAxis, etaAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffSecBest", + "; p_{T} (GeV/c); #eta", + {HistType::kTH2F, + {ptAxis, etaAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffGenDuplBest", + "; p_{T} (GeV/c); #eta", + {HistType::kTH2F, + {ptAxis, etaAxis}}}); + qaregistry.add({"Tracks/hPtEtaEffDuplBest", + "; p_{T} (GeV/c); #eta", + {HistType::kTH2F, + {ptAxis, etaAxis}}}); + qaregistry.add({"Tracks/NmftTrkPerPartBest", + "; #it{N}_{mft tracks per particle}", + {HistType::kTH1F, {multAxis}}}); + } + + if (doprocessTrkEffIdxBestCentFT0C) { + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffGenFakeBest", + "; p_{T} (GeV/c); #eta; centrality", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffGenBest", + "; p_{T} (GeV/c); #eta; centrality", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffPrimBest", + "; p_{T} (GeV/c); #eta; centrality", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffSecBest", + "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffGenDuplBest", + "; p_{T} (GeV/c); #eta; centrality", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis}}}); + qaregistry.add( + {"Tracks/Centrality/hPtEtaEffDuplBest", + "; p_{T} (GeV/c); #eta; centrality", + {HistType::kTHnSparseF, + {ptAxis, etaAxis, centralityAxis}}}); + qaregistry.add( + {"Tracks/Centrality/NmftTrkPerPartBest", + "; #it{N}_{mft tracks per particle}; centrality", + {HistType::kTHnSparseF, {multAxis, 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::kTHnSparseF, {ptAxis, phiAxis, etaAxis, zAxis, 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, phiAxis, etaAxis, zAxis, 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 (doprocessCheckAmbiguousMftTracks) { + qaregistry.add({"Tracks/hMftTracksAmbDegree", + " ; N_{coll}^{comp}", + {HistType::kTH1F, {{41, -0.5, 40.5}}}}); + qaregistry.add({"Tracks/hMftTracksAmbDegreeWithTrivial", + " ; N_{coll}^{comp}", + {HistType::kTH1F, {{41, -0.5, 40.5}}}}); + // qaregistry.add({"Tracks/hAmbTrackType", + // " ; Ambiguous track type", + // {HistType::kTH1F, {{5, -0.5, 4.5}}}}); + + qaregistry.add("Tracks/hAmbTrackType", "hAmbTrackType", {HistType::kTH1F, {{AmbTrkType::nAmbTrkType, -0.5, +AmbTrkType::nAmbTrkType - 0.5}}}); + std::string labelAmbiguity[AmbTrkType::nAmbTrkType]; + labelAmbiguity[AmbTrkType::kOrphan] = "orphan"; + labelAmbiguity[AmbTrkType::kNonAmb] = "nonAmbiguous"; + labelAmbiguity[AmbTrkType::kNonAmbSame] = "trkInCollTabHasSameAssoc"; + labelAmbiguity[AmbTrkType::kAmb] = "trkInCollTabHasDiffAssoc"; + labelAmbiguity[AmbTrkType::kAmbGt1] = "trkInCollTabHasGt1Assoc"; + qaregistry.get(HIST("Tracks/hAmbTrackType"))->SetMinimum(0.1); + + for (int iBin = 0; iBin < AmbTrkType::nAmbTrkType; iBin++) { + qaregistry.get(HIST("Tracks/hAmbTrackType"))->GetXaxis()->SetBinLabel(iBin + 1, labelAmbiguity[iBin].data()); + } + } + + if (doprocessCollAssocMC) { + // tracks not associated to any collision + hCollAssoc[0] = qaregistry.add("TrackToColl/hNonAssocTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis}); + // tracks associasted to a collision + hCollAssoc[1] = qaregistry.add("TrackToColl/hAssocTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis}); + // tracks associated to the correct collision considering only first reco collision (based on the MC collision index) + hCollAssoc[2] = qaregistry.add("TrackToColl/hGoodAssocTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis}); + // tracks associated to the correct collision considering all ambiguous reco collisions (based on the MC collision index) + hCollAssoc[3] = qaregistry.add("TrackToColl/hGoodAssocTracksAmb", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis}); + qaregistry.add("TrackToColl/histFracTracksFakeMcColl", "Fraction of tracks originating from fake collision; fraction; entries", {HistType::kTH1F, {{101, 0., 1.01}}}); + qaregistry.add("TrackToColl/histFracGoodTracks", "Fraction of tracks originating from the correct collision; fraction; entries", {HistType::kTH1F, {{101, 0., 1.01}}}); + qaregistry.add("TrackToColl/histAmbTrackNumColls", "Number of collisions associated to an ambiguous track; no. collisions; entries", {HistType::kTH1F, {{30, -0.5, 29.5}}}); + } + + if (doprocessReAssocMC) { + // tracks not associated to any collision + hReAssoc[0] = qaregistry.add("ReAssoc/hNonAssocTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis}); + // tracks associasted to a collision + hReAssoc[1] = qaregistry.add("ReAssoc/hAssocTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis}); + // tracks associated to the correct collision considering only first reco collision (based on the MC collision index) + hReAssoc[2] = qaregistry.add("ReAssoc/hGoodAssocTracks", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis}); + // tracks associated to the correct collision considering all ambiguous reco collisions (based on the MC collision index) + hReAssoc[3] = qaregistry.add("ReAssoc/hGoodAssocTracksAmb", ";#it{p}_{T}^{reco} (GeV/#it{c});#it{#eta}^{reco};#it{Z}_{vtx}^{reco}#minus#it{Z}_{vtx}^{gen} (cm)", HistType::kTHnSparseF, {ptAxis, etaAxis, deltaZAxis}); + } + + 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}}}); + } + + if (doprocessCorrelationwBestTracksInclusive) { + qaregistry.add("Events/hMultMFTvsFT0A", "MultMFT_vs_FT0A", {HistType::kTH2F, {multAxis, multFT0aAxis}}); + qaregistry.add("Events/hMultMFTvsFT0C", "MultMFT_vs_FT0C", {HistType::kTH2F, {multAxis, multFT0cAxis}}); + qaregistry.add("Events/hNPVtracksVsFT0C", "NPVtracks_vs_FT0C", {HistType::kTH2F, {pvAxis, multFT0cAxis}}); + qaregistry.add("Events/hMultMFTvsFV0A", "MultMFT_vs_FV0A", {HistType::kTH2F, {multAxis, multFV0aAxis}}); + qaregistry.add("Events/hNPVtracksVsMultMFT", "NPVtracks_vs_MultMFT", {HistType::kTH2F, {pvAxis, multAxis}}); + } + + if (doprocessSecondariesMCInlcusive || doprocessSecondariesMCCentFT0C) { + auto hNevt = registry.add("Events/hNGenRecColls", "Number of generated and reconstructed MC collisions", HistType::kTH1F, {{3, 0.5, 3.5}}); + hNevt->GetXaxis()->SetBinLabel(1, "Reconstructed collisions"); + hNevt->GetXaxis()->SetBinLabel(2, "Generated collisions"); + if (doprocessSecondariesMCInlcusive) { + registry.add({"Events/EvtGenRec", ";status", {HistType::kTH1F, {{3, 0.5, 3.5}}}}); + auto heff = registry.get(HIST("Events/EvtGenRec")); + auto* h = heff->GetXaxis(); + h->SetBinLabel(1, "All generated"); + h->SetBinLabel(2, "All reconstructed"); + h->SetBinLabel(3, "Selected reconstructed"); + registry.add({"Tracks/THnRecAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnRec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnRecNonAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnRecAmbRest", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnGenPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnGenSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnGenSecWeak", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnGenSecMat", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnGenPrimAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnGenSecAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnGenSecWeakAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + registry.add({"Tracks/THnGenSecMatAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis}}}); + } + if (doprocessSecondariesMCCentFT0C) { + registry.add({"Events/Centrality/EvtGenRec", ";status;centrality", {HistType::kTH2F, {{3, 0.5, 3.5}, centralityAxis}}}); + auto heff = registry.get(HIST("Events/Centrality/EvtGenRec")); + auto* h = heff->GetXaxis(); + h->SetBinLabel(1, "All generated"); + h->SetBinLabel(2, "All reconstructed"); + h->SetBinLabel(3, "Selected reconstructed"); + registry.add({"Tracks/Centrality/THnRecAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnRec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnRecNonAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnRecAmbRest", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnGenPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnGenSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnGenSecWeak", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnGenSecMat", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnGenPrimAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnGenSecAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnGenSecWeakAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnGenSecMatAmb", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, centralityAxis}}}); + } + } + + if (doprocessDCAReassocMcInclusive || doprocessDCAReassocMcCentFT0C) { + auto hNevt = registry.add("Events/hNGenRecCollsReassoc", "Number of generated and reconstructed MC collisions", HistType::kTH1F, {{3, 0.5, 3.5}}); + hNevt->GetXaxis()->SetBinLabel(1, "Reconstructed collisions"); + hNevt->GetXaxis()->SetBinLabel(2, "Generated collisions"); + if (doprocessDCAReassocMcInclusive) { + registry.add({"Events/EvtGenRecReassoc", ";status", {HistType::kTH2F, {{3, 0.5, 3.5}, occupancyAxis}}}); + auto heff = registry.get(HIST("Events/EvtGenRecReassoc")); + auto* h = heff->GetXaxis(); + h->SetBinLabel(1, "All generated"); + h->SetBinLabel(2, "All reconstructed"); + h->SetBinLabel(3, "Selected reconstructed"); + registry.add({"Tracks/THnDCAxyBestRec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestRecFake", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenTruthPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenPrimWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenTruthPrimWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenTruthSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenSecWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenTruthSecWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenSecWeak", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + registry.add({"Tracks/THnDCAxyBestGenSecMat", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm)", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis}}}); + } + if (doprocessDCAReassocMcCentFT0C) { + registry.add({"Events/Centrality/EvtGenRecReassoc", ";status;centrality", {HistType::kTHnSparseF, {{3, 0.5, 3.5}, centralityAxis, occupancyAxis}}}); + auto heff = registry.get(HIST("Events/Centrality/EvtGenRecReassoc")); + heff->GetAxis(0)->SetBinLabel(1, "All generated"); + heff->GetAxis(0)->SetBinLabel(2, "All reconstructed"); + heff->GetAxis(0)->SetBinLabel(3, "Selected reconstructed"); + registry.add({"Tracks/Centrality/THnDCAxyBestRec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestRecFake", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenTruthPrim", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenPrimWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenTruthPrimWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenTruthSec", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenSecWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenTruthSecWrongColl", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenSecWeak", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + registry.add({"Tracks/Centrality/THnDCAxyBestGenSecMat", "; p_{T} (GeV/c); #eta; Z_{vtx} (cm); DCA_{XY} (cm); DCA_{Z} (cm); centrality", {HistType::kTHnSparseF, {ptAxis, etaAxis, zAxis, dcaxyAxis, dcazAxis, centralityAxis}}}); + } + } + } + + /// Filters - tracks + Filter filtTrkEta = (aod::fwdtrack::eta < trackCuts.maxEta) && + (aod::fwdtrack::eta > trackCuts.minEta); + Filter filtATrackID = (aod::fwdtrack::bestCollisionId >= kIntZero); + Filter filtATrackDCAxy = (nabs(aod::fwdtrack::bestDCAXY) < trackCuts.maxDCAxy); + Filter filtATrackDCAz = (nabs(aod::fwdtrack::bestDCAZ) < trackCuts.maxDCAz); + + /// Filters - mc particles + Filter primaries = (aod::mcparticle::flags & (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary && (aod::mcparticle::eta < trackCuts.maxEta) && (aod::mcparticle::eta > trackCuts.minEta); + + /// Joined tables + using FullBCs = soa::Join; + using CollBCs = soa::Join; + // Collisions + 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 CollisionsWithMCLabels = soa::Join; + + using CollGenCent = CollsGenCentFT0C::iterator; + using CollsCorr = soa::Join; + // Tracks + using MFTTracksLabeled = soa::Join; + using MftTracksWColls = soa::Join; + using MftTracksWCollsMC = soa::Join; + + using BestTracksMC = soa::Join; + + /// Filtered tables + using FiltMftTracks = soa::Filtered; + using FiltMcMftTracks = soa::Filtered; + using FiltBestTracks = soa::Filtered; + using FiltMcBestTracks = soa::Filtered; + + using FiltParticles = soa::Filtered; + + template + bool isBestTrackSelected(const B& besttrack) + { + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelAll); + } + if (besttrack.bestCollisionId() < kIntZero) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelCollID); + } + if (std::abs(besttrack.bestDCAXY()) >= trackCuts.maxDCAxy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelDCAxyCut); + } + if (std::abs(besttrack.bestDCAZ()) >= trackCuts.maxDCAxy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelDCAzCut); + } + return true; + } + + template + bool isTrackSelected(const T& track) + { + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelAll); + } + if (track.nClusters() < trackCuts.minNclusterMft) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelNCls); + } + if (trackCuts.useChi2Cut) { + float nclMft = std::max(2.0f * track.nClusters() - 5.0f, 1.0f); + float mftChi2NCl = track.chi2() / nclMft; + if (mftChi2NCl > trackCuts.maxChi2NCl) + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelChi2Ncl); + } + if (track.eta() < trackCuts.minEta || track.eta() > trackCuts.maxEta) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelEta); + } + 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; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelPhiCut); + } + if (trackCuts.usePtCut && track.pt() < trackCuts.minPt) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelPt); + } + if (trackCuts.requireCA && !track.isCA()) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelCA); + } + return true; + } + + template + int countTracks(T const& tracks, float z, float c, float occ) + { + auto nTrk = 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 < kZero || 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; + ambiguousTrkIds.reserve(besttracks.size()); + reassignedTrkIds.reserve(besttracks.size()); + for (auto const& atrack : besttracks) { + if (!isBestTrackSelected(atrack)) { + continue; + } + auto itrack = atrack.template mfttrack_as(); + if (!isTrackSelected(itrack)) { + continue; + } + ambiguousTrkIds.emplace_back(atrack.mfttrackId()); + ++nATrk; + if (fillHis) { + float phi = itrack.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < kZero || 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/DCA3d"), itrack.pt(), itrack.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), c, occ); + qaregistry.fill(HIST("Tracks/Centrality/NclustersEtaBest"), itrack.nClusters(), 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/DCA3d"), itrack.pt(), itrack.eta(), atrack.bestDCAXY(), atrack.bestDCAZ(), occ); + qaregistry.fill(HIST("Tracks/NclustersEtaBest"), itrack.nClusters(), itrack.eta(), occ); + qaregistry.fill(HIST("Tracks/TrackAmbDegree"), atrack.ambDegree(), occ); + } + } + + if (itrack.has_collision() && itrack.collisionId() != atrack.bestCollisionId()) { + reassignedTrkIds.emplace_back(atrack.mfttrackId()); + if (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelNumReassoc); + float phi = itrack.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < kZero || TwoPI < phi) { + continue; + } + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/ReTracksEtaZvtx"), itrack.eta(), itrack.template collision_as().posZ(), c, occ); + qaregistry.fill(HIST("Tracks/Centrality/ReTracksPhiEta"), phi, itrack.eta(), c, occ); + } else { + qaregistry.fill(HIST("Tracks/ReTracksEtaZvtx"), itrack.eta(), itrack.template collision_as().posZ(), occ); + qaregistry.fill(HIST("Tracks/ReTracksPhiEta"), phi, itrack.eta(), occ); + } + } + } + } + + for (auto const& track : tracks) { + if (!isTrackSelected(track)) { + continue; + } + float phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < kZero || TwoPI < phi) { + continue; + } + if (fillHis) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/OrigTracksEtaZvtx"), track.eta(), z, c, occ); + qaregistry.fill(HIST("Tracks/Centrality/OrigTracksPhiEta"), phi, track.eta(), c, occ); + } else { + qaregistry.fill(HIST("Tracks/OrigTracksEtaZvtx"), track.eta(), z, occ); + qaregistry.fill(HIST("Tracks/OrigTracksPhiEta"), phi, track.eta(), occ); + } + } + if (std::find(ambiguousTrkIds.begin(), ambiguousTrkIds.end(), track.globalIndex()) != ambiguousTrkIds.end()) { + continue; + } + if (std::find(reassignedTrkIds.begin(), reassignedTrkIds.end(), track.globalIndex()) != reassignedTrkIds.end()) { + continue; + } + // ++nATrk; // use for testing purposes only! + if (fillHis) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/RestTracksEtaZvtx"), track.eta(), z, c, occ); + qaregistry.fill(HIST("Tracks/Centrality/RestTracksPhiEta"), phi, track.eta(), c, occ); + // registry.fill(HIST("Tracks/Centrality/EtaZvtxBest"), track.eta(), z, c, occ); + // registry.fill(HIST("Tracks/Centrality/PhiEtaBest"), phi, track.eta(), c, occ); + // qaregistry.fill(HIST("Tracks/Centrality/NclustersEtaBest"), track.nClusters(), track.eta(), c, occ); + } else { + qaregistry.fill(HIST("Tracks/RestTracksEtaZvtx"), track.eta(), z, occ); + qaregistry.fill(HIST("Tracks/RestTracksPhiEta"), phi, track.eta(), occ); + // registry.fill(HIST("Tracks/EtaZvtxBest"), track.eta(), z, occ); + // registry.fill(HIST("Tracks/PhiEtaBest"), phi, track.eta(), occ); + // qaregistry.fill(HIST("Tracks/NclustersEtaBest"), track.nClusters(), track.eta(), occ); + } + } + } + if (fillHis) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/NchBestSel"), nATrk, c, occ); + } else { + qaregistry.fill(HIST("Tracks/NchBestSel"), nATrk, occ); + } + } + ambiguousTrkIds.clear(); + ambiguousTrkIds.shrink_to_fit(); + reassignedTrkIds.clear(); + reassignedTrkIds.shrink_to_fit(); + return nATrk; + } + + template + int countPart(P const& particles) + { + auto nCharged = 0; + for (auto const& particle : particles) { + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if (cfgUseParticleSel && !isParticleSelected(particle)) { + continue; + } + if (particle.eta() < trackCuts.minEta || particle.eta() > trackCuts.maxEta) { + continue; + } + nCharged++; + } + return nCharged; + } + + template + bool isParticleSelected(P const& particle) + { + if (particle.eta() < trackCuts.minEta || particle.eta() > trackCuts.maxEta) { + return false; + } + if (trackCuts.usephiCut) { + float phi = particle.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 + 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; + } + + void initHadronicRate(CollBCs::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 + float 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(eventCuts.maxIR - eventCuts.minIR); + gHadronicRate[mRunNumber] = registry.add(Form("HadronicRate/%i", mRunNumber), ";Time since SOR (s);Hadronic rate (kHz)", kTH2D, {axisSeconds, {hadronicRateBins, eventCuts.minIR, eventCuts.maxIR}}).get(); + } + gCurrentHadronicRate = gHadronicRate[mRunNumber]; + } + + template + bool isGoodEvent(C const& collision) + { + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 0); + } + if (!collision.sel8()) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 1); + } + if (eventCuts.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 2); + } + if (eventCuts.requireRejectSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 3); + } + if (collision.posZ() <= eventCuts.minZvtx || collision.posZ() >= eventCuts.maxZvtx) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 4); + } + if (eventCuts.requireNoCollInTimeRangeStd && + !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 5); + } + if (eventCuts.requireNoCollInTimeRangeNarrow && + !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 6); + } + if (eventCuts.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 7); + } + if (eventCuts.requireNoCollInRofStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 8); + } + if (eventCuts.requireNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 9); + } + if (eventCuts.requireNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 10); + } + if (eventCuts.minOccupancy >= 0 && + getOccupancy(collision, eventCuts.occupancyEstimator) < + eventCuts.minOccupancy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 11); + } + if (eventCuts.maxOccupancy >= 0 && + getOccupancy(collision, eventCuts.occupancyEstimator) > + eventCuts.maxOccupancy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 12); + } + + if (rctCuts.requireRCTFlagChecker && !rctChecker(collision)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 13); + } + 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) >= kMinCharge; + } + + 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; + } + if (cfgUseParticleSel && !isParticleSelected(particle)) { + continue; + } + + float phi = particle.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < kZero || 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 < kZero || 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(); + 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 (cfgDoIR) { + initHadronicRate(bc); + float ir = !cfgIRSource.value.empty() ? rateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), cfgIRSource, cfgIRCrashOnNull) * 1.e-3 : -1; + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/hInteractionRate"), c, occ, ir); + } else { + registry.fill(HIST("Events/hInteractionRate"), occ, ir); + } + float seconds = bc.timestamp() * 1.e-3 - mMinSeconds; + if (cfgUseIRCut && (ir < eventCuts.minIR || ir > eventCuts.maxIR)) { // cut on hadronic rate + return; + } + gCurrentHadronicRate->Fill(seconds, ir); + } + + auto z = collision.posZ(); + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/Selection"), 2., c, occ); + } else { + 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 BestCollisionsFwd3d + /// 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(); + 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 (cfgDoIR) { + initHadronicRate(bc); + float ir = !cfgIRSource.value.empty() ? rateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), cfgIRSource, cfgIRCrashOnNull) * 1.e-3 : -1; + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/hInteractionRate"), c, occ, ir); + } else { + registry.fill(HIST("Events/hInteractionRate"), occ, ir); + } + float seconds = bc.timestamp() * 1.e-3 - mMinSeconds; + if (cfgUseIRCut && (ir < eventCuts.minIR || ir > eventCuts.maxIR)) { // cut on hadronic rate + return; + } + gCurrentHadronicRate->Fill(seconds, ir); + } + + 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); + } else { + registry.fill(HIST("Events/Selection"), 2., occ); + } + + 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 BestCollisionsFwd3d 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 BestCollisionsFwd3d 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 " + "BestCollisionsFwd3d 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 BestCollisionsFwd3d 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 " + "BestCollisionsFwd3d 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 BestCollisionsFwd3d table", + false); + + Preslice perCol = o2::aod::fwdtrack::collisionId; + PresliceUnsorted recColPerMcCol = + aod::mccollisionlabel::mcCollisionId; + Partition mcSample = (aod::mcparticle::eta < trackCuts.maxEta) && (aod::mcparticle::eta > trackCuts.minEta); + + /// @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 crecMin = 105.f; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float c = getRecoCent(collision); + if (c < crecMin) { + crecMin = c; + } + } + } + if (cGen < 0) + cGen = crecMin; + } + + 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::BestCollisionsFwd3d 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 crecMin = 105.f; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float c = getRecoCent(collision); + if (c < crecMin) { + crecMin = c; + } + } + } + if (cGen < 0) + cGen = crecMin; + } + + 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::BestCollisionsFwd3d (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::BestCollisionsFwd3d", + 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::BestCollisionsFwd3d", + 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::BestCollisionsFwd3d", + 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::BestCollisionsFwd3d", + 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::BestCollisionsFwd3d", + false); + + using ParticlesI = soa::Join; + Partition primariesI = (aod::mcparticle::flags & (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary && (aod::mcparticle::eta < trackCuts.maxEta) && (aod::mcparticle::eta > trackCuts.minEta); + + Preslice perMCCol = aod::mcparticle::mcCollisionId; + + template + void processTrkEffIdxBest( + typename soa::Join const& collisions, + MC const& /*mccollisions*/, ParticlesI const& /*particles*/, + BestTracksMC const& atracks) + { + for (auto const& collision : collisions) { + if (!isGoodEvent(collision)) { + continue; + } + if (!collision.has_mcCollision()) { + continue; + } + + float crec = getRecoCent(collision); + auto mcCollision = collision.mcCollision(); + + if (eventCuts.useZDiffCut) { + if (std::abs(collision.posZ() - mcCollision.posZ()) > eventCuts.maxZvtxDiff) { + continue; + } + } + + auto partsPerCol = primariesI->sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache); + partsPerCol.bindExternalIndices(&atracks); + for (auto const& particle : partsPerCol) { + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if (cfgUseParticleSel && !isParticleSelected(particle)) { + 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/hPtEtaEffGenBest"), particle.pt(), particle.eta(), crec); + } + } + } else { + if (particle.eta() > trackCuts.minEta && particle.eta() < trackCuts.maxEta) { + if (std::abs(mcCollision.posZ()) < eventCuts.maxZvtx) { + qaregistry.fill(HIST("Tracks/hPtEtaEffGenBest"), particle.pt(), particle.eta()); + } + } + } + // MC rec + if (particle.has_mfttracks()) { + auto iscounted = false; + auto ncnt = 0; + auto relatedTracks = particle.template mfttracks_as(); + for (auto const& track : relatedTracks) { + if (!isBestTrackSelected(track)) { + continue; + } + ++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/hPtEtaEffPrimBest"), particle.pt(), particle.eta(), crec); + } + iscounted = true; + } + } + if (ncnt > 1) { // secondaries + if (track.eta() > trackCuts.minEta && track.eta() < trackCuts.maxEta) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEtaEffSecBest"), particle.pt(), particle.eta(), crec); + } + } + } else { + if (track.eta() > trackCuts.minEta && track.eta() < trackCuts.maxEta) { + if (!iscounted) { // primaries + if (std::abs(mcCollision.posZ()) < eventCuts.maxZvtx) { + qaregistry.fill(HIST("Tracks/hPtEtaEffPrimBest"), particle.pt(), particle.eta()); + } + iscounted = true; + } + } + if (ncnt > 1) { // secondaries + if (track.eta() > trackCuts.minEta && track.eta() < trackCuts.maxEta) { + qaregistry.fill(HIST("Tracks/hPtEtaEffSecBest"), particle.pt(), particle.eta()); + } + } + } + + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/NmftTrkPerPartBest"), ncnt, crec); + } else { + qaregistry.fill(HIST("Tracks/NmftTrkPerPartBest"), ncnt); + } + + if (relatedTracks.size() > 1) { // duplicates + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEtaEffGenDuplBest"), particle.pt(), particle.eta(), crec); + for (auto const& track : relatedTracks) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEtaEffDuplBest"), track.pt(), track.eta(), crec); + } + } else { + qaregistry.fill(HIST("Tracks/hPtEtaEffGenDuplBest"), particle.pt(), particle.eta()); + for (auto const& track : relatedTracks) { + qaregistry.fill(HIST("Tracks/hPtEtaEffDuplBest"), track.pt(), track.eta()); + } + } + } + } + } else { + // MC FAKES + 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/hPtEtaEffGenFakeBest"), particle.pt(), particle.eta(), crec); + } + } + } else { + if (particle.eta() > trackCuts.minEta && particle.eta() < trackCuts.maxEta) { + if (std::abs(mcCollision.posZ()) < eventCuts.maxZvtx) { + qaregistry.fill(HIST("Tracks/hPtEtaEffGenFakeBest"), particle.pt(), particle.eta()); + } + } + } + } + } + } + } + + void processTrkEffIdxBestInlusive( + soa::Join const& collisions, + aod::McCollisions const& mccollisions, ParticlesI const& particles, + BestTracksMC const& atracks) + { + processTrkEffIdxBest(collisions, mccollisions, particles, atracks); + } + PROCESS_SWITCH(DndetaMFTPbPb, processTrkEffIdxBestInlusive, "Process tracking efficiency best (inclusive, indexed)", false); + + void processTrkEffIdxBestCentFT0C( + soa::Join const& collisions, + aod::McCollisions const& mccollisions, ParticlesI const& particles, + BestTracksMC const& atracks) + { + processTrkEffIdxBest(collisions, mccollisions, particles, atracks); + } + PROCESS_SWITCH(DndetaMFTPbPb, processTrkEffIdxBestCentFT0C, "Process tracking efficiency best (in FT0C centrality bins, indexed)", false); + + /// @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; + } + if (cfgUseParticleSel && !isParticleSelected(particle)) { + 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 BestCollisionsFwd3d 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 (cfgUseParticleSel && !isParticleSelected(particle)) { + continue; + } + if constexpr (has_reco_cent) { + if (particle.eta() > trackCuts.minEta && particle.eta() < trackCuts.maxEta) { + qaregistry.fill(HIST("Tracks/Centrality/hPtPhiEtaZvtxEffBestGen"), particle.pt(), particle.phi(), particle.eta(), mcCollision.posZ(), crec, occrec); + } + } else { + if (particle.eta() > trackCuts.minEta && particle.eta() < trackCuts.maxEta) { + qaregistry.fill(HIST("Tracks/hPtPhiEtaZvtxEffBestGen"), particle.pt(), particle.phi(), particle.eta(), mcCollision.posZ(), occrec); + } + } + } + + ambiguousTrkIdsMC.reserve(besttracks.size()); + reassignedTrkIdsMC.reserve(besttracks.size()); + + for (auto const& track : besttracks) { + ambiguousTrkIdsMC.emplace_back(track.mfttrackId()); + if (!isBestTrackSelected(track)) { + continue; + } + auto itrack = track.mfttrack_as(); + if (itrack.collisionId() != track.bestCollisionId()) { + reassignedTrkIdsMC.emplace_back(track.mfttrackId()); + } + if (!isTrackSelected(itrack)) { + continue; + } + if (itrack.has_mcParticle()) { + auto particle = itrack.mcParticle_as(); + if (itrack.eta() > trackCuts.minEta && itrack.eta() < trackCuts.maxEta) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtPhiEtaZvtxEffBestRec"), + particle.pt(), particle.phi(), particle.eta(), + mcCollision.posZ(), crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hPtPhiEtaZvtxEffBestRec"), particle.pt(), + particle.phi(), particle.eta(), mcCollision.posZ(), + occrec); + } + } + } else { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEffBestFakeRec"), itrack.pt(), itrack.phi(), itrack.eta(), mcCollision.posZ(), crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hPtEffBestFakeRec"), itrack.pt(), itrack.phi(), itrack.eta(), mcCollision.posZ(), occrec); + } + } + } + + for (auto const& track : tracks) { + if (std::find(ambiguousTrkIdsMC.begin(), ambiguousTrkIdsMC.end(), track.globalIndex()) != ambiguousTrkIdsMC.end()) { + continue; + } + if (std::find(reassignedTrkIdsMC.begin(), reassignedTrkIdsMC.end(), track.globalIndex()) != reassignedTrkIdsMC.end()) { + continue; + } + if (!isTrackSelected(track)) { + continue; + } + if (track.has_mcParticle()) { + auto particle = track.mcParticle_as(); + if (track.eta() > trackCuts.minEta && track.eta() < trackCuts.maxEta) { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtPhiEtaZvtxEffBestRec"), + particle.pt(), particle.phi(), particle.eta(), + mcCollision.posZ(), crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hPtPhiEtaZvtxEffBestRec"), particle.pt(), + particle.phi(), particle.eta(), mcCollision.posZ(), + occrec); + } + } + } else { + if constexpr (has_reco_cent) { + qaregistry.fill(HIST("Tracks/Centrality/hPtEffBestFakeRec"), track.pt(), track.phi(), track.eta(), mcCollision.posZ(), crec, occrec); + } else { + qaregistry.fill(HIST("Tracks/hPtEffBestFakeRec"), track.pt(), track.phi(), track.eta(), mcCollision.posZ(), occrec); + } + } + } + ambiguousTrkIdsMC.clear(); + ambiguousTrkIdsMC.shrink_to_fit(); + reassignedTrkIdsMC.clear(); + reassignedTrkIdsMC.shrink_to_fit(); + } + + 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 BestCollisionsFwd3d)", + 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 BestCollisionsFwd3d)", + 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 + void processCheckAmbiguousMftTracks(aod::Collisions const&, MftTracksWColls const& tracks) + { + for (auto const& track : tracks) { + auto trkCollId = track.has_collision() ? track.collisionId() : -1; + auto ids = track.compatibleCollIds(); + if (ids.empty() || (ids.size() == 1 && trkCollId == ids[0])) { + qaregistry.fill(HIST("Tracks/hMftTracksAmbDegreeWithTrivial"), track.compatibleCollIds().size()); + if (ids.empty()) { + qaregistry.fill(HIST("Tracks/hAmbTrackType"), AmbTrkType::kOrphan); + } + if (ids.size() == 1 && trkCollId == ids[0]) { + qaregistry.fill(HIST("Tracks/hAmbTrackType"), AmbTrkType::kNonAmb); + } + continue; + } + qaregistry.fill(HIST("Tracks/hMftTracksAmbDegree"), track.compatibleCollIds().size()); + + if (track.compatibleCollIds().size() > 0) { + if (track.compatibleCollIds().size() == 1) { + if (track.collisionId() != track.compatibleCollIds()[0]) { + qaregistry.fill(HIST("Tracks/hAmbTrackType"), AmbTrkType::kAmb); + } else { + qaregistry.fill(HIST("Tracks/hAmbTrackType"), AmbTrkType::kNonAmbSame); + } + } else { + qaregistry.fill(HIST("Tracks/hAmbTrackType"), AmbTrkType::kAmbGt1); + } + } + } + } + + PROCESS_SWITCH(DndetaMFTPbPb, processCheckAmbiguousMftTracks, "Process checks for Ambiguous MFT tracks (inclusive)", false); + + Partition tracksInAcc = (aod::fwdtrack::eta < trackCuts.maxEta) && (aod::fwdtrack::eta > trackCuts.minEta); + + template + void processCheckAssocMC(C const& collisions, + MftTracksWCollsMC const& tracks, + aod::McParticles const& /*particles*/, + aod::McCollisions const& /*mccollisions*/ + ) + { + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + // auto mcCollision = collision.template mcCollision_as(); + auto tracksInColl = tracksInAcc->sliceByCached(aod::fwdtrack::collisionId, collision.globalIndex(), cache); + int nTrk = 0, nFakeTrk = 0, nGoodTrk = 0; + for (const auto& track : tracksInColl) { + if (!track.has_mcParticle()) { + continue; + } + nTrk++; + auto particle = track.mcParticle(); + + if ((particle.mcCollisionId() != collision.mcCollision().globalIndex())) { + nFakeTrk++; + continue; + } + if (collision.mcCollisionId() == particle.mcCollisionId()) { + nGoodTrk++; + } + } + float frac = (nTrk > 0) ? static_cast(nGoodTrk) / nTrk : -1.; + qaregistry.fill(HIST("TrackToColl/histFracGoodTracks"), frac); + float fracFake = (nTrk > 0) ? static_cast(nFakeTrk) / nTrk : -1.; + qaregistry.fill(HIST("TrackToColl/histFracTracksFakeMcColl"), fracFake); + } + + for (auto const& track : tracks) { + uint index = uint(track.collisionId() >= 0); + if (track.has_mcParticle()) { + // auto particle = track.mcParticle_as(); + auto particle = track.mcParticle(); + bool isAmbiguous = (track.compatibleCollIds().size() != 1); + if (isAmbiguous) { + qaregistry.fill(HIST("TrackToColl/histAmbTrackNumColls"), track.compatibleCollIds().size()); + } + float deltaZ = -999.f; + if (index) { + auto collision = track.collision_as(); + auto mcCollision = particle.mcCollision_as(); + deltaZ = collision.posZ() - mcCollision.posZ(); + if (collision.has_mcCollision() && collision.mcCollisionId() == particle.mcCollisionId()) { + hCollAssoc[index + 1]->Fill(track.pt(), track.eta(), deltaZ); + } else { + if (isAmbiguous) { + for (const auto& collIdx : track.compatibleCollIds()) { + auto ambCollision = collisions.rawIteratorAt(collIdx); + if (ambCollision.has_mcCollision() && ambCollision.mcCollisionId() == particle.mcCollisionId()) { + hCollAssoc[index + 2]->Fill(track.pt(), track.eta(), deltaZ); + break; + } + } + } + } + } + hCollAssoc[index]->Fill(track.pt(), track.eta(), deltaZ); + } else { + hCollAssoc[index]->Fill(track.pt(), track.eta(), -999.f); + } + } + } + + void processCollAssocMC(CollisionsWithMCLabels const& collisions, + MftTracksWCollsMC const& tracks, + aod::McParticles const& particles, + aod::McCollisions const& mccollisions) + { + processCheckAssocMC(collisions, tracks, particles, mccollisions); + } + PROCESS_SWITCH(DndetaMFTPbPb, processCollAssocMC, "Process collision-association information, requires extra table from TrackToCollisionAssociation task (fillTableOfCollIdsPerTrack=true)", false); + + template + void processCheckReAssocMC(C const& /*collisions*/, + soa::SmallGroups const& besttracks, + FiltMcMftTracks const& /*tracks*/, + FiltParticles const& /*particles*/, + aod::McCollisions const& /*mccollisions*/ + ) + { + for (auto const& track : besttracks) { + uint index = uint(track.bestCollisionId() >= 0); // assigned + if (!isBestTrackSelected(track)) { + continue; + } + auto itrack = track.mfttrack_as(); + + if (cfgRemoveReassigned) { + if (itrack.collisionId() != track.bestCollisionId()) { + continue; + } + } + if (!isTrackSelected(itrack)) { + continue; + } + if (itrack.has_mcParticle()) { + auto particle = itrack.mcParticle_as(); + + float deltaZ = -999.f; + if (index) { + auto collision = itrack.collision_as(); + auto mcCollision = particle.mcCollision_as(); + deltaZ = collision.posZ() - mcCollision.posZ(); + if (collision.has_mcCollision() && collision.mcCollisionId() == particle.mcCollisionId()) { + hReAssoc[index + 1]->Fill(itrack.pt(), itrack.eta(), deltaZ); + } else { + hReAssoc[index + 2]->Fill(itrack.pt(), itrack.eta(), deltaZ); + } + } + hReAssoc[index]->Fill(itrack.pt(), itrack.eta(), deltaZ); + } else { + hReAssoc[index]->Fill(itrack.pt(), itrack.eta(), -999.f); + } + } + } + + void processReAssocMC(CollisionsWithMCLabels const& collisions, + soa::SmallGroups const& besttracks, + FiltMcMftTracks const& tracks, + FiltParticles const& particles, + aod::McCollisions const& mccollisions) + { + processCheckReAssocMC(collisions, besttracks, tracks, particles, mccollisions); + } + PROCESS_SWITCH(DndetaMFTPbPb, processReAssocMC, "Process re-association information based on BestCollisionsFwd3d table", 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); + + Preslice mftTrkCompCollperCol = o2::aod::fwdtrack::collisionId; + + /// @brief process template function for DCA MC checks + template + void processSecondariesMC(typename soa::Join const& collisions, + MftTracksWCollsMC const& tracks, + MC const& mcCollisions, + aod::McParticles const& /*particles*/ + ) + { + registry.fill(HIST("Events/hNGenRecColls"), 1.f, collisions.size()); + registry.fill(HIST("Events/hNGenRecColls"), 2.f, mcCollisions.size()); + + float cGen = -1; + if constexpr (has_reco_cent) { + float crecMin = 105.f; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float c = getRecoCent(collision); + if (c < crecMin) { + crecMin = c; + } + } + } + if (cGen < 0) + cGen = crecMin; + } + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtGenRec"), 1., cGen); + } else { + registry.fill(HIST("Events/EvtGenRec"), 1.); + } + + for (const auto& collision : collisions) { + float crec = getRecoCent(collision); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtGenRec"), 2., crec); + } else { + registry.fill(HIST("Events/EvtGenRec"), 2.); + } + + if (!isGoodEvent(collision)) { + continue; + } + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtGenRec"), 3., crec); + } else { + registry.fill(HIST("Events/EvtGenRec"), 3.); + } + + if (!collision.has_mcCollision()) { + continue; + } + + auto trkPerColl = tracks.sliceBy(mftTrkCompCollperCol, collision.globalIndex()); + for (auto const& track : trkPerColl) { + if (!isTrackSelected(track)) { + continue; + } + if (!track.has_collision()) { + continue; + } + auto trkCollId = track.has_collision() ? track.collisionId() : -1; + auto ids = track.compatibleCollIds(); + bool isAmbiguous = (ids.size() != 1); + + if (isAmbiguous) { + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnRecAmb"), track.pt(), track.eta(), collision.posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnRecAmb"), track.pt(), track.eta(), collision.posZ()); + } + } else { + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnRec"), track.pt(), track.eta(), collision.posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnRec"), track.pt(), track.eta(), collision.posZ()); + } + if (trkCollId == ids[0]) { + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnRecNonAmb"), track.pt(), track.eta(), collision.posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnRecNonAmb"), track.pt(), track.eta(), collision.posZ()); + } + } + if (trkCollId != ids[0]) { + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnRecAmbRest"), track.pt(), track.eta(), collision.posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnRecAmbRest"), track.pt(), track.eta(), collision.posZ()); + } + } + } + + uint index = uint(track.collisionId() >= 0); + + if (!track.has_mcParticle()) { + LOGP(debug, "No MC particle for track, skip..."); + continue; + } + + auto particle = track.template mcParticle_as(); + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if (particle.eta() <= trackCuts.minEta || particle.eta() >= trackCuts.maxEta) { + continue; + } + if (cfgUseParticleSel && !isParticleSelected(particle)) { + continue; + } + + if (index) { + auto mcCollision = particle.template mcCollision_as(); + if (eventCuts.useZDiffCut) { + if (std::abs(collision.posZ() - mcCollision.posZ()) > eventCuts.maxZvtxDiff) { + continue; + } + } + + if (collision.has_mcCollision() && collision.mcCollisionId() == particle.mcCollisionId()) { + if (!particle.isPhysicalPrimary()) { // Secondaries (weak decays and material) + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnGenSec"), particle.pt(), particle.eta(), particle.mcCollision().posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnGenSec"), particle.pt(), particle.eta(), particle.mcCollision().posZ()); + } + if (particle.getProcess() == TMCProcess::kPDecay) { // Particles from decay + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnGenSecWeak"), particle.pt(), particle.eta(), particle.mcCollision().posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnGenSecWeak"), particle.pt(), particle.eta(), particle.mcCollision().posZ()); + } + } else { // Particles from the material + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnGenSecMat"), particle.pt(), particle.eta(), particle.mcCollision().posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnGenSecMat"), particle.pt(), particle.eta(), particle.mcCollision().posZ()); + } + } + } else { // Primaries + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnGenPrim"), particle.pt(), particle.eta(), particle.mcCollision().posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnGenPrim"), particle.pt(), particle.eta(), particle.mcCollision().posZ()); + } + } + } else { + if (isAmbiguous) { + for (const auto& collIdx : track.compatibleCollIds()) { + auto ambCollision = collisions.rawIteratorAt(collIdx); + if (ambCollision.has_mcCollision() && ambCollision.mcCollisionId() == particle.mcCollisionId()) { + if (!particle.isPhysicalPrimary()) { // Secondaries (weak decays and material) + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnGenSecAmb"), particle.pt(), particle.eta(), particle.mcCollision().posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnGenSecAmb"), particle.pt(), particle.eta(), particle.mcCollision().posZ()); + } + if (particle.getProcess() == TMCProcess::kPDecay) { // Particles from decay + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnGenSecWeakAmb"), particle.pt(), particle.eta(), particle.mcCollision().posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnGenSecWeakAmb"), particle.pt(), particle.eta(), particle.mcCollision().posZ()); + } + } else { // Particles from the material + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnGenSecMatAmb"), particle.pt(), particle.eta(), particle.mcCollision().posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnGenSecMatAmb"), particle.pt(), particle.eta(), particle.mcCollision().posZ()); + } + } + } else { // Primaries + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnGenPrimAmb"), particle.pt(), particle.eta(), particle.mcCollision().posZ(), crec); + } else { + registry.fill(HIST("Tracks/THnGenPrimAmb"), particle.pt(), particle.eta(), particle.mcCollision().posZ()); + } + } + break; + } + } + } + } + } + } + } + } + + void processSecondariesMCInlcusive(soa::Join const& collisions, + MftTracksWCollsMC const& tracks, + aod::McCollisions const& mccollisions, + aod::McParticles const& particles) + { + processSecondariesMC(collisions, tracks, mccollisions, particles); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processSecondariesMCInlcusive, "Process secondaries checks (Inclusive)", false); + + void processSecondariesMCCentFT0C(soa::Join const& collisions, + MftTracksWCollsMC const& tracks, + aod::McCollisions const& mccollisions, + aod::McParticles const& particles) + { + processSecondariesMC(collisions, tracks, mccollisions, particles); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processSecondariesMCCentFT0C, "Process secondaries checks (in FT0C centrality bins)", false); + + template + void processDCAReassocMc(typename soa::Join const& collisions, + MC const& mcCollisions, + aod::McParticles const& /*particles*/, + BestTracksMC const& besttracks, + FiltMcMftTracks const& /*tracks*/ + ) + { + registry.fill(HIST("Events/hNGenRecCollsReassoc"), 1.f, collisions.size()); + registry.fill(HIST("Events/hNGenRecCollsReassoc"), 2.f, mcCollisions.size()); + + float cGen = -1; + if constexpr (has_reco_cent) { + float crecMin = 105.f; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float c = getRecoCent(collision); + if (c < crecMin) { + crecMin = c; + } + } + } + if (cGen < 0) + cGen = crecMin; + } + float occGen = -1.; + for (const auto& collision : collisions) { + if (isGoodEvent(collision)) { + float o = getOccupancy(collision, eventCuts.occupancyEstimator); + if (o > occGen) { + occGen = o; + } + } + } + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtGenRecReassoc"), 1., cGen, occGen); + } else { + registry.fill(HIST("Events/EvtGenRecReassoc"), 1., occGen); + } + + for (const auto& collision : collisions) { + auto occ = getOccupancy(collision, eventCuts.occupancyEstimator); + float crec = getRecoCent(collision); + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtGenRecReassoc"), 2., crec, occ); + } else { + registry.fill(HIST("Events/EvtGenRecReassoc"), 2., occ); + } + + if (!isGoodEvent(collision)) { + continue; + } + + if constexpr (has_reco_cent) { + registry.fill(HIST("Events/Centrality/EvtGenRecReassoc"), 3., crec, occ); + } else { + registry.fill(HIST("Events/EvtGenRecReassoc"), 3., occ); + } + + if (!collision.has_mcCollision()) { + continue; + } + + auto perCollisionASample = besttracks.sliceBy(perColU, collision.globalIndex()); + for (auto const& atrack : perCollisionASample) { + if (!isBestTrackSelected(atrack)) { + continue; + } + auto itrack = atrack.template mfttrack_as(); + + if (!isTrackSelected(itrack)) { + continue; + } + float phi = itrack.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < kZero || TwoPI < phi) { + continue; + } + + if (!itrack.has_collision()) { + continue; + } + if (cfgRemoveReassigned) { + if (itrack.collisionId() != atrack.bestCollisionId()) { + continue; + } + } + + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestRec"), itrack.pt(), itrack.eta(), collision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); + } else { + registry.fill(HIST("Tracks/THnDCAxyBestRec"), itrack.pt(), itrack.eta(), collision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); + } + + if (itrack.has_mcParticle()) { + auto particle = itrack.template mcParticle_as(); + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if (particle.eta() <= trackCuts.minEta || particle.eta() >= trackCuts.maxEta) { + continue; + } + if (cfgUseParticleSel && !isParticleSelected(particle)) { + continue; + } + + const auto dcaXtruth(particle.vx() - particle.mcCollision().posX()); + const auto dcaYtruth(particle.vy() - particle.mcCollision().posY()); + const auto dcaZtruth(particle.vz() - particle.mcCollision().posZ()); + auto dcaXYtruth = std::sqrt(dcaXtruth * dcaXtruth + dcaYtruth * dcaYtruth); + auto mcCollision = particle.template mcCollision_as(); + + if (eventCuts.useZDiffCut) { + if (std::abs(collision.posZ() - mcCollision.posZ()) > eventCuts.maxZvtxDiff) { + continue; + } + } + + if (collision.has_mcCollision() && collision.mcCollisionId() == particle.mcCollisionId()) { + if (!particle.isPhysicalPrimary()) { // Secondaries (weak decays and material) + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenSec"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenTruthSec"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth, crec); + } else { + registry.fill(HIST("Tracks/THnDCAxyBestGenSec"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); + registry.fill(HIST("Tracks/THnDCAxyBestGenTruthSec"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth); + } + if (particle.getProcess() == TMCProcess::kPDecay) { // Particles from decay + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenSecWeak"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); + } else { + registry.fill(HIST("Tracks/THnDCAxyBestGenSecWeak"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); + } + } else { // Particles from the material + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenSecMat"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); + } else { + registry.fill(HIST("Tracks/THnDCAxyBestGenSecMat"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); + } + } + } else { // Primaries + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenPrim"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenTruthPrim"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth, crec); + } else { + registry.fill(HIST("Tracks/THnDCAxyBestGenPrim"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); + registry.fill(HIST("Tracks/THnDCAxyBestGenTruthPrim"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth); + } + } + } else { // Wrong collision + if (!particle.isPhysicalPrimary()) { // Secondaries (weak decays and material) + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenSecWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenTruthSecWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth, crec); + } else { + registry.fill(HIST("Tracks/THnDCAxyBestGenSecWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); + registry.fill(HIST("Tracks/THnDCAxyBestGenTruthSecWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth); + } + } else { // Primaries + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenPrimWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestGenTruthPrimWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth, crec); + } else { + registry.fill(HIST("Tracks/THnDCAxyBestGenPrimWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); + registry.fill(HIST("Tracks/THnDCAxyBestGenTruthPrimWrongColl"), particle.pt(), particle.eta(), mcCollision.posZ(), dcaXYtruth, dcaZtruth); + } + } + } + } else { + LOGP(debug, "No MC particle for ambiguous itrack, skip..."); + if constexpr (has_reco_cent) { + registry.fill(HIST("Tracks/Centrality/THnDCAxyBestRecFake"), itrack.pt(), itrack.eta(), collision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ(), crec); + } else { + registry.fill(HIST("Tracks/THnDCAxyBestRecFake"), itrack.pt(), itrack.eta(), collision.posZ(), atrack.bestDCAXY(), atrack.bestDCAZ()); + } + } + } + } + } + + void processDCAReassocMcInclusive(soa::Join const& collisions, + aod::McCollisions const& mccollisions, + aod::McParticles const& particles, + BestTracksMC const& besttracks, + FiltMcMftTracks const& tracks) + { + processDCAReassocMc(collisions, mccollisions, particles, besttracks, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDCAReassocMcInclusive, "Process MC DCA checks using re-association information based on BestCollisionsFwd3d table (Inclusive)", false); + + void processDCAReassocMcCentFT0C(soa::Join const& collisions, + aod::McCollisions const& mccollisions, + aod::McParticles const& particles, + BestTracksMC const& besttracks, + FiltMcMftTracks const& tracks) + { + processDCAReassocMc(collisions, mccollisions, particles, besttracks, tracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processDCAReassocMcCentFT0C, "Process MC DCA checks using re-association information based on BestCollisionsFwd3d table (in FT0C centrality bins)", false); + + template + void processCorrelationwBestTracks(typename C::iterator const& collision, FiltMftTracks const& /*tracks*/, soa::SmallGroups const& besttracks) + { + if (!isGoodEvent(collision)) { + return; + } + + auto nBestTrks = 0; + for (auto const& atrack : besttracks) { + if (cfgUseTrackSel && !isBestTrackSelected(atrack)) { + continue; + } + auto itrack = atrack.template mfttrack_as(); + if (itrack.eta() < trackCuts.minEta || itrack.eta() > trackCuts.maxEta) { + continue; + } + if (cfgUseTrackSel && !isTrackSelected(itrack)) { + continue; + } + nBestTrks++; + } + qaregistry.fill(HIST("Events/hMultMFTvsFT0A"), nBestTrks, collision.multFT0A()); + qaregistry.fill(HIST("Events/hMultMFTvsFT0C"), nBestTrks, collision.multFT0C()); + qaregistry.fill(HIST("Events/hNPVtracksVsFT0C"), collision.multNTracksPV(), collision.multFT0C()); + qaregistry.fill(HIST("Events/hMultMFTvsFV0A"), nBestTrks, collision.multFV0A()); + qaregistry.fill(HIST("Events/hNPVtracksVsMultMFT"), collision.multNTracksPV(), nBestTrks); + } + + void processCorrelationwBestTracksInclusive(CollsCorr::iterator const& collision, FiltMftTracks const& tracks, soa::SmallGroups const& besttracks) + { + processCorrelationwBestTracks(collision, tracks, besttracks); + } + + PROCESS_SWITCH(DndetaMFTPbPb, processCorrelationwBestTracksInclusive, "Do correlation study based on BestCollisionsFwd3d table", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGMM/Mult/Tasks/flattenicty-chrg.cxx b/PWGMM/Mult/Tasks/flattenicty-chrg.cxx index 75f628f613a..fbfa4ab578d 100644 --- a/PWGMM/Mult/Tasks/flattenicty-chrg.cxx +++ b/PWGMM/Mult/Tasks/flattenicty-chrg.cxx @@ -1,4 +1,4 @@ -// Copyright 2020-2022 CERN and copyright holders of ALICE O2. +// Copyright 2020-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. // diff --git a/PWGMM/Mult/Tasks/heavy-ion-mult.cxx b/PWGMM/Mult/Tasks/heavy-ion-mult.cxx index 61778ff522e..9d8fdf30a2a 100644 --- a/PWGMM/Mult/Tasks/heavy-ion-mult.cxx +++ b/PWGMM/Mult/Tasks/heavy-ion-mult.cxx @@ -18,21 +18,20 @@ // 3. https://github.com/AliceO2Group/O2Physics/blob/master/PWGMM/Mult/Tasks/puremc-dndeta.cxx // 4. O2 analysis tutorial: https://indico.cern.ch/event/1267433/ -#include -#include -#include -#include -#include - +#include "Index.h" #include "bestCollisionTable.h" -#include "CCDB/BasicCCDBManager.h" -#include "Common/Core/trackUtilities.h" + +#include "PWGLF/DataModel/LFStrangenessTables.h" + #include "Common/CCDB/EventSelectionParams.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/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/MathConstants.h" #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" @@ -43,20 +42,29 @@ #include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/Track.h" +#include +#include + +#include +#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; -using CollisionDataTable = 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 CollisionMCRecTable = soa::SmallGroups>; using TrackMCRecTable = soa::Join; using FilTrackMCRecTable = soa::Filtered; +using v0trackcandidates = soa::Join; enum { kTrackTypebegin = 0, @@ -74,6 +82,19 @@ enum { 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; @@ -86,7 +107,7 @@ static constexpr TrackSelectionFlags::flagtype trackSelectionDCA = static constexpr TrackSelectionFlags::flagtype trackSelectionDCAXYonly = TrackSelectionFlags::kDCAxy; -AxisSpec axisEvent{9, 0.5, 9.5, "#Event", "EventAxis"}; +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"}; @@ -94,6 +115,9 @@ 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 { @@ -105,6 +129,13 @@ 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 FV0AmultHistBin{"FV0AMultDistBinning", {501, -0.5, 500.5}, ""}; @@ -112,6 +143,7 @@ struct HeavyIonMultiplicity { ConfigurableAxis FT0CmultHistBin{"FT0CMultDistBinning", {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"}; @@ -122,16 +154,26 @@ struct HeavyIonMultiplicity { 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 axisFV0AMult = {FV0AmultHistBin}; - AxisSpec axisFT0AMult = {FT0AmultHistBin}; - AxisSpec axisFT0CMult = {FT0CmultHistBin}; + 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}; + AxisSpec axisPT = {pTHistBin, "pT", "pTAxis"}; + AxisSpec axisOccupancy = {OccupancyBin, "occupancy", "OccupancyAxis"}; histos.add("EventHist", "EventHist", kTH1D, {axisEvent}, false); histos.add("VtxZHist", "VtxZHist", kTH1D, {axisVtxZ}, false); @@ -147,29 +189,32 @@ struct HeavyIonMultiplicity { 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("CentPercentileHist", "CentPercentileHist", kTH1D, {axisCent}, false); - histos.add("CentHistInsideTrackloop", "CentHistInsideTrackloop", kTH1D, {axisCent}, false); histos.add("hdatamult", "hdatamult", kTHnSparseD, {axisVtxZ, axisMult, CentAxis}, false); - histos.add("hdatadndeta", "hdatadndeta", kTHnSparseD, {axisVtxZ, CentAxis, axisEta, axisPhi, axisPT, AxisTrackType}, false); - histos.add("hdatazvtxcent", "hdatazvtxcent", kTH2D, {axisVtxZ, CentAxis}, false); - histos.add("PhiVsEtaHistBeforePhiCut", "PhiVsEtaHistBeforePhiCut", kTH2D, {axisPhi2, axisEta}, false); - histos.add("PhiVsEtaHistAfterPhiCut", "PhiVsEtaHistAfterPhiCut", kTH2D, {axisPhi2, axisEta}, 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 (doprocessMonteCarlo || doprocessMCpTefficiency || doprocessMCcheckFakeTracks) { + if (doprocessMonteCarlo || doprocessMCpTefficiency || doprocessMCcheckFakeTracks || doprocessMCfillspecies) { histos.add("CentPercentileMCRecHist", "CentPercentileMCRecHist", kTH1D, {axisCent}, false); - histos.add("hmczvtxcent", "hmczvtxcent", kTH2D, {axisVtxZ, CentAxis}, false); + histos.add("hmczvtxcent", "hmczvtxcent", kTH3D, {axisVtxZ, CentAxis, axisOccupancy}, false); } if (doprocessMonteCarlo) { - histos.add("MCCentHistInsideTrackloop", "MCCentHistInsideTrackloop", kTH1D, {axisCent}, false); - histos.add("MCrecPhiVsEtaHistBeforePhiCut", "MCrecPhiVsEtaHistBeforePhiCut", kTH2D, {axisPhi2, axisEta}, false); - histos.add("MCrecPhiVsEtaHistAfterPhiCut", "MCrecPhiVsEtaHistAfterPhiCut", kTH2D, {axisPhi2, axisEta}, false); - histos.add("hmcrecdndeta", "hmcrecdndeta", kTHnSparseD, {axisVtxZ, CentAxis, axisEta, axisPhi}, false); + 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); - histos.add("hdndeta0_5", "hdndeta0_5", kTH1D, {axisEta}, false); + } + + if (doprocessMCfillspecies) { + histos.add("FillMCrecSpecies", "FillMCrecSpecies", kTHnSparseD, {CentAxis, axisOccupancy, axisEta, AxisSpecies}, false); + histos.add("FillMCgenSpecies", "FillMCgenSpecies", kTHnSparseD, {CentAxis, axisEta, AxisSpecies}, false); } if (doprocessMCpTefficiency) { @@ -195,8 +240,50 @@ struct HeavyIonMultiplicity { 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) { @@ -242,9 +329,43 @@ struct HeavyIonMultiplicity { } 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), @@ -254,54 +375,42 @@ 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"), collision.centFT0C()); - histos.fill(HIST("hdatazvtxcent"), collision.posZ(), collision.centFT0C()); + 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; for (auto& track : tracks) { - if (std::abs(track.eta()) >= etaRange) { + if (!IsTrackSelected(track)) { continue; } - histos.fill(HIST("PhiVsEtaHistBeforePhiCut"), track.phi(), track.eta()); - if (IsApplyExtraPhiCut) { - if ((track.phi() > 3.07666 && track.phi() < 3.12661) || track.phi() <= 0.03 || track.phi() >= 6.253) { - continue; - } - } - histos.fill(HIST("PhiVsEtaHistAfterPhiCut"), track.phi(), track.eta()); + histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta()); NchTracks++; - histos.fill(HIST("CentHistInsideTrackloop"), collision.centFT0C()); - histos.fill(HIST("hdatadndeta"), collision.posZ(), collision.centFT0C(), track.eta(), track.phi(), track.pt(), kGlobalplusITS); - + histos.fill(HIST("hdatadndeta"), collision.posZ(), SelectColCentrality(collision), OccupancyValue, track.eta(), track.phi(), kGlobalplusITS); if (track.hasTPC()) { - histos.fill(HIST("hdatadndeta"), collision.posZ(), collision.centFT0C(), track.eta(), track.phi(), track.pt(), kGlobalonly); + histos.fill(HIST("hdatadndeta"), collision.posZ(), SelectColCentrality(collision), OccupancyValue, track.eta(), track.phi(), kGlobalonly); } else { - histos.fill(HIST("hdatadndeta"), collision.posZ(), collision.centFT0C(), track.eta(), track.phi(), track.pt(), kITSonly); + histos.fill(HIST("hdatadndeta"), collision.posZ(), SelectColCentrality(collision), OccupancyValue, track.eta(), track.phi(), kITSonly); } } - histos.fill(HIST("hdatamult"), collision.posZ(), NchTracks, collision.centFT0C()); + histos.fill(HIST("hdatamult"), collision.posZ(), NchTracks, SelectColCentrality(collision)); } - PROCESS_SWITCH(HeavyIonMultiplicity, processData, "process data CentFT0C", false); void processCorrelation(CollisionDataTable::iterator const& collision, FilTrackDataTable const& tracks) { - if (!IsEventSelected(collision)) { return; } - - if (std::abs(collision.posZ()) > VtxRange) { + if (std::abs(collision.posZ()) >= VtxRange) { return; } - histos.fill(HIST("VtxZHist"), collision.posZ()); + auto NchTracks = 0; for (auto& track : tracks) { if (std::abs(track.eta()) >= etaRange) { @@ -309,106 +418,64 @@ struct HeavyIonMultiplicity { } 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); void processMonteCarlo(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) { - for (auto& RecCollision : RecCollisions) { - if (!IsEventSelected(RecCollision)) { continue; } - histos.fill(HIST("VtxZHist"), RecCollision.posZ()); - histos.fill(HIST("CentPercentileMCRecHist"), RecCollision.centFT0C()); - histos.fill(HIST("hmczvtxcent"), RecCollision.posZ(), RecCollision.centFT0C()); + 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) { + if (!IsTrackSelected(Rectrack)) { continue; } - histos.fill(HIST("MCrecPhiVsEtaHistBeforePhiCut"), Rectrack.phi(), Rectrack.eta()); - if (IsApplyExtraPhiCut) { - if ((Rectrack.phi() > 3.07666 && Rectrack.phi() < 3.12661) || Rectrack.phi() <= 0.03 || Rectrack.phi() >= 6.253) { - continue; - } - } - histos.fill(HIST("MCrecPhiVsEtaHistAfterPhiCut"), Rectrack.phi(), Rectrack.eta()); - histos.fill(HIST("MCCentHistInsideTrackloop"), RecCollision.centFT0C()); - histos.fill(HIST("hmcrecdndeta"), RecCollision.posZ(), RecCollision.centFT0C(), Rectrack.eta(), Rectrack.phi()); - if (RecCollision.centFT0C() >= 0 && RecCollision.centFT0C() < 5.0) { - histos.fill(HIST("hdndeta0_5"), Rectrack.eta()); - } + 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 (!particle.isPhysicalPrimary()) { - continue; - } - - if (!particle.producedByGenerator()) { + if (!IsGenTrackSelected(particle)) { continue; } - - auto pdgParticle = pdg->GetParticle(particle.pdgCode()); - if (pdgParticle == nullptr) { - continue; - } - - if (std::abs(pdgParticle->Charge()) < 3) { - continue; - } - - if (std::abs(particle.eta()) >= etaRange) { - continue; - } - if (IsApplyExtraPhiCut) { - if ((particle.phi() > 3.07666 && particle.phi() < 3.12661) || particle.phi() <= 0.03 || particle.phi() >= 6.253) { - continue; - } - } - histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), RecCollision.centFT0C(), particle.eta(), particle.phi(), kNoGenpTVar); - + histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), SelectColCentrality(RecCollision), particle.eta(), particle.phi(), kNoGenpTVar); if (particle.pt() < 0.1) { - histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), RecCollision.centFT0C(), particle.eta(), particle.phi(), kGenpTup, -10.0 * particle.pt() + 2); - histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), RecCollision.centFT0C(), particle.eta(), particle.phi(), kGenpTdown, 5.0 * particle.pt() + 0.5); + 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(), RecCollision.centFT0C(), particle.eta(), particle.phi(), kGenpTup); - histos.fill(HIST("hmcgendndeta"), RecCollision.posZ(), RecCollision.centFT0C(), particle.eta(), particle.phi(), kGenpTdown); + 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 + } // 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; } - - if (std::abs(RecCollision.posZ()) > VtxRange) { + if (std::abs(RecCollision.posZ()) >= VtxRange) { continue; } - histos.fill(HIST("VtxZHist"), RecCollision.posZ()); - histos.fill(HIST("CentPercentileMCRecHist"), RecCollision.centFT0C()); - histos.fill(HIST("hmczvtxcent"), RecCollision.posZ(), RecCollision.centFT0C()); + 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) { @@ -418,63 +485,41 @@ struct HeavyIonMultiplicity { if (Rectrack.has_mcParticle()) { auto mcpart = Rectrack.mcParticle(); if (mcpart.isPhysicalPrimary()) { - histos.fill(HIST("hmcrecdndpt"), RecCollision.centFT0C(), mcpart.pt()); + histos.fill(HIST("hmcrecdndpt"), SelectColCentrality(RecCollision), mcpart.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) { - continue; - } - - if (std::abs(particle.eta()) >= etaRange) { + if (!IsGenTrackSelected(particle)) { continue; } - histos.fill(HIST("hmcgendndpt"), RecCollision.centFT0C(), particle.pt(), kNoGenpTVar); + histos.fill(HIST("hmcgendndpt"), SelectColCentrality(RecCollision), particle.pt(), kNoGenpTVar); if (particle.pt() < 0.1) { - histos.fill(HIST("hmcgendndpt"), RecCollision.centFT0C(), particle.pt(), kGenpTup, -10.0 * particle.pt() + 2); - histos.fill(HIST("hmcgendndpt"), RecCollision.centFT0C(), particle.pt(), kGenpTdown, 5.0 * particle.pt() + 0.5); + 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"), RecCollision.centFT0C(), particle.pt(), kGenpTup); - histos.fill(HIST("hmcgendndpt"), RecCollision.centFT0C(), particle.pt(), kGenpTdown); + 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); void processMCcheckFakeTracks(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCollisions, FilTrackMCRecTable const& RecTracks) { - for (auto& RecCollision : RecCollisions) { - if (!IsEventSelected(RecCollision)) { continue; } - - if (std::abs(RecCollision.posZ()) > VtxRange) { + if (std::abs(RecCollision.posZ()) >= VtxRange) { continue; } - histos.fill(HIST("VtxZHist"), RecCollision.posZ()); - histos.fill(HIST("CentPercentileMCRecHist"), RecCollision.centFT0C()); - histos.fill(HIST("hmczvtxcent"), RecCollision.posZ(), RecCollision.centFT0C()); + 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) { @@ -484,24 +529,150 @@ struct HeavyIonMultiplicity { if (!Rectrack.hasTPC()) { continue; } - histos.fill(HIST("hTracksCount"), RecCollision.centFT0C(), 1); + 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"), RecCollision.centFT0C(), i + 3); + histos.fill(HIST("hTracksCount"), SelectColCentrality(RecCollision), i + 3); break; } } if (IsFakeITStracks) { continue; } - histos.fill(HIST("hTracksCount"), RecCollision.centFT0C(), 2); + histos.fill(HIST("hTracksCount"), SelectColCentrality(RecCollision), 2); } } } - PROCESS_SWITCH(HeavyIonMultiplicity, processMCcheckFakeTracks, "Check Fake tracks", false); + + void processMCfillspecies(CollisionMCTrueTable::iterator const&, CollisionMCRecTable const& RecCollisions, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + 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; + } + } + 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, processStrangeYield, "Strange particle yield", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGMM/Mult/Tasks/pseudoEffMFT.cxx b/PWGMM/Mult/Tasks/pseudoEffMFT.cxx new file mode 100644 index 00000000000..d8dc1990329 --- /dev/null +++ b/PWGMM/Mult/Tasks/pseudoEffMFT.cxx @@ -0,0 +1,1199 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// +/// \file pseudoEffMFT.cxx +/// \brief Task for calculating pseudo-efficiency of MFT disks; based on PWGDQ/Tasks/taskMFTTrkEfficiency.cxx +/// \author Gyula Bencedi, gyula.bencedi@cern.ch +/// \since OCT 2025 + +#include "Functions.h" +#include "Index.h" +#include "bestCollisionTable.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.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 "CCDB/BasicCCDBManager.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/RuntimeError.h" +#include "Framework/runDataProcessing.h" +#include "MathUtils/Utils.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include +#include +#include + +#include "TPDGCode.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +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; +using namespace o2::aod::rctsel; + +namespace mft_xy +{ +constexpr float kMx[936] = { + -8.8, -8.8, 8.2, 8.2, 9.9, 9.9, -9.9, -9.9, -8.2, -8.2, + 8.8, 8.8, -7.1, -7.1, -7.1, -5.4, -5.4, -5.4, -3.7, -3.7, + -3.7, -2, -2, -2, -0.3, -0.3, -0.3, 1.4, 1.4, 1.4, + 3.1, 3.1, 3.1, 4.8, 4.8, 4.8, 6.5, 6.5, 6.5, -6.5, + -6.5, -6.5, -4.8, -4.8, -4.8, -3.1, -3.1, -3.1, -1.4, -1.4, + -1.4, 0.3, 0.3, 0.3, 2, 2, 2, 3.7, 3.7, 3.7, + 5.4, 5.4, 5.4, 7.1, 7.1, 7.1, -8.8, -8.8, 8.2, 8.2, + 9.9, 9.9, -9.9, -9.9, -8.2, -8.2, 8.8, 8.8, -7.1, -7.1, + -7.1, -5.4, -5.4, -5.4, -3.7, -3.7, -3.7, -2, -2, -2, + -0.3, -0.3, -0.3, 1.4, 1.4, 1.4, 3.1, 3.1, 3.1, 4.8, + 4.8, 4.8, 6.5, 6.5, 6.5, -6.5, -6.5, -6.5, -4.8, -4.8, + -4.8, -3.1, -3.1, -3.1, -1.4, -1.4, -1.4, 0.3, 0.3, 0.3, + 2, 2, 2, 3.7, 3.7, 3.7, 5.4, 5.4, 5.4, 7.1, + 7.1, 7.1, -10.5, -10.5, 9.9, 9.9, -9.9, -9.9, 10.5, 10.5, + -8.8, -8.8, -8.8, -7.1, -7.1, -7.1, -2, -2, -2, -0.3, + -0.3, -0.3, 1.4, 1.4, 1.4, 6.5, 6.5, 6.5, 8.2, 8.2, + 8.2, -8.2, -8.2, -8.2, -6.5, -6.5, -6.5, -1.4, -1.4, -1.4, + 0.3, 0.3, 0.3, 2, 2, 2, 7.1, 7.1, 7.1, 8.8, + 8.8, 8.8, -5.4, -5.4, -5.4, -5.4, -3.7, -3.7, -3.7, -3.7, + 3.1, 3.1, 3.1, 3.1, 4.8, 4.8, 4.8, 4.8, -4.8, -4.8, + -4.8, -4.8, -3.1, -3.1, -3.1, -3.1, 3.7, 3.7, 3.7, 3.7, + 5.4, 5.4, 5.4, 5.4, -12.2, -12.2, -12.2, -10.5, -10.5, -10.5, + 9.9, 9.9, 9.9, 11.6, 11.6, 11.6, 13.3, 13.3, 13.3, -13.3, + -13.3, -13.3, -11.6, -11.6, -11.6, -9.9, -9.9, -9.9, 10.5, 10.5, + 10.5, 12.2, 12.2, 12.2, -8.8, -8.8, -8.8, -8.8, -7.1, -7.1, + -7.1, -7.1, -5.4, -5.4, -5.4, -5.4, -3.7, -3.7, -3.7, -3.7, + -2, -2, -2, -2, -0.3, -0.3, -0.3, -0.3, 1.4, 1.4, + 1.4, 1.4, 3.1, 3.1, 3.1, 3.1, 4.8, 4.8, 4.8, 4.8, + 6.5, 6.5, 6.5, 6.5, 8.2, 8.2, 8.2, 8.2, -8.2, -8.2, + -8.2, -8.2, -6.5, -6.5, -6.5, -6.5, -4.8, -4.8, -4.8, -4.8, + -3.1, -3.1, -3.1, -3.1, -1.4, -1.4, -1.4, -1.4, 0.3, 0.3, + 0.3, 0.3, 2, 2, 2, 2, 3.7, 3.7, 3.7, 3.7, + 5.4, 5.4, 5.4, 5.4, 7.1, 7.1, 7.1, 7.1, 8.8, 8.8, + 8.8, 8.8, -13.9, -13.9, -13.9, -12.2, -12.2, -12.2, 11.6, 11.6, + 11.6, 13.3, 13.3, 13.3, -13.3, -13.3, -13.3, -11.6, -11.6, -11.6, + 12.2, 12.2, 12.2, 13.9, 13.9, 13.9, -10.5, -10.5, -10.5, -10.5, + -8.8, -8.8, -8.8, -8.8, -3.7, -3.7, -3.7, -3.7, -2, -2, + -2, -2, -0.3, -0.3, -0.3, -0.3, 1.4, 1.4, 1.4, 1.4, + 3.1, 3.1, 3.1, 3.1, 8.2, 8.2, 8.2, 8.2, 9.9, 9.9, + 9.9, 9.9, -9.9, -9.9, -9.9, -9.9, -8.2, -8.2, -8.2, -8.2, + -3.1, -3.1, -3.1, -3.1, -1.4, -1.4, -1.4, -1.4, 0.3, 0.3, + 0.3, 0.3, 2, 2, 2, 2, 3.7, 3.7, 3.7, 3.7, + 8.8, 8.8, 8.8, 8.8, 10.5, 10.5, 10.5, 10.5, -7.1, -7.1, + -7.1, -7.1, -7.1, -5.4, -5.4, -5.4, -5.4, -5.4, 4.8, 4.8, + 4.8, 4.8, 4.8, 6.5, 6.5, 6.5, 6.5, 6.5, -6.5, -6.5, + -6.5, -6.5, -6.5, -4.8, -4.8, -4.8, -4.8, -4.8, 5.4, 5.4, + 5.4, 5.4, 5.4, 7.1, 7.1, 7.1, 7.1, 7.1, 8.8, 8.8, + -8.2, -8.2, -9.9, -9.9, 9.9, 9.9, 8.2, 8.2, -8.8, -8.8, + 7.1, 7.1, 7.1, 5.4, 5.4, 5.4, 3.7, 3.7, 3.7, 2, + 2, 2, 0.3, 0.3, 0.3, -1.4, -1.4, -1.4, -3.1, -3.1, + -3.1, -4.8, -4.8, -4.8, -6.5, -6.5, -6.5, 6.5, 6.5, 6.5, + 4.8, 4.8, 4.8, 3.1, 3.1, 3.1, 1.4, 1.4, 1.4, -0.3, + -0.3, -0.3, -2, -2, -2, -3.7, -3.7, -3.7, -5.4, -5.4, + -5.4, -7.1, -7.1, -7.1, 8.8, 8.8, -8.2, -8.2, -9.9, -9.9, + 9.9, 9.9, 8.2, 8.2, -8.8, -8.8, 7.1, 7.1, 7.1, 5.4, + 5.4, 5.4, 3.7, 3.7, 3.7, 2, 2, 2, 0.3, 0.3, + 0.3, -1.4, -1.4, -1.4, -3.1, -3.1, -3.1, -4.8, -4.8, -4.8, + -6.5, -6.5, -6.5, 6.5, 6.5, 6.5, 4.8, 4.8, 4.8, 3.1, + 3.1, 3.1, 1.4, 1.4, 1.4, -0.3, -0.3, -0.3, -2, -2, + -2, -3.7, -3.7, -3.7, -5.4, -5.4, -5.4, -7.1, -7.1, -7.1, + 10.5, 10.5, -9.9, -9.9, 9.9, 9.9, -10.5, -10.5, 8.8, 8.8, + 8.8, 7.1, 7.1, 7.1, 2, 2, 2, 0.3, 0.3, 0.3, + -1.4, -1.4, -1.4, -6.5, -6.5, -6.5, -8.2, -8.2, -8.2, 8.2, + 8.2, 8.2, 6.5, 6.5, 6.5, 1.4, 1.4, 1.4, -0.3, -0.3, + -0.3, -2, -2, -2, -7.1, -7.1, -7.1, -8.8, -8.8, -8.8, + 5.4, 5.4, 5.4, 5.4, 3.7, 3.7, 3.7, 3.7, -3.1, -3.1, + -3.1, -3.1, -4.8, -4.8, -4.8, -4.8, 4.8, 4.8, 4.8, 4.8, + 3.1, 3.1, 3.1, 3.1, -3.7, -3.7, -3.7, -3.7, -5.4, -5.4, + -5.4, -5.4, 12.2, 12.2, 12.2, 10.5, 10.5, 10.5, -9.9, -9.9, + -9.9, -11.6, -11.6, -11.6, -13.3, -13.3, -13.3, 13.3, 13.3, 13.3, + 11.6, 11.6, 11.6, 9.9, 9.9, 9.9, -10.5, -10.5, -10.5, -12.2, + -12.2, -12.2, 8.8, 8.8, 8.8, 8.8, 7.1, 7.1, 7.1, 7.1, + 5.4, 5.4, 5.4, 5.4, 3.7, 3.7, 3.7, 3.7, 2, 2, + 2, 2, 0.3, 0.3, 0.3, 0.3, -1.4, -1.4, -1.4, -1.4, + -3.1, -3.1, -3.1, -3.1, -4.8, -4.8, -4.8, -4.8, -6.5, -6.5, + -6.5, -6.5, -8.2, -8.2, -8.2, -8.2, 8.2, 8.2, 8.2, 8.2, + 6.5, 6.5, 6.5, 6.5, 4.8, 4.8, 4.8, 4.8, 3.1, 3.1, + 3.1, 3.1, 1.4, 1.4, 1.4, 1.4, -0.3, -0.3, -0.3, -0.3, + -2, -2, -2, -2, -3.7, -3.7, -3.7, -3.7, -5.4, -5.4, + -5.4, -5.4, -7.1, -7.1, -7.1, -7.1, -8.8, -8.8, -8.8, -8.8, + 13.9, 13.9, 13.9, 12.2, 12.2, 12.2, -11.6, -11.6, -11.6, -13.3, + -13.3, -13.3, 13.3, 13.3, 13.3, 11.6, 11.6, 11.6, -12.2, -12.2, + -12.2, -13.9, -13.9, -13.9, 10.5, 10.5, 10.5, 10.5, 8.8, 8.8, + 8.8, 8.8, 3.7, 3.7, 3.7, 3.7, 2, 2, 2, 2, + 0.3, 0.3, 0.3, 0.3, -1.4, -1.4, -1.4, -1.4, -3.1, -3.1, + -3.1, -3.1, -8.2, -8.2, -8.2, -8.2, -9.9, -9.9, -9.9, -9.9, + 9.9, 9.9, 9.9, 9.9, 8.2, 8.2, 8.2, 8.2, 3.1, 3.1, + 3.1, 3.1, 1.4, 1.4, 1.4, 1.4, -0.3, -0.3, -0.3, -0.3, + -2, -2, -2, -2, -3.7, -3.7, -3.7, -3.7, -8.8, -8.8, + -8.8, -8.8, -10.5, -10.5, -10.5, -10.5, 7.1, 7.1, 7.1, 7.1, + 7.1, 5.4, 5.4, 5.4, 5.4, 5.4, -4.8, -4.8, -4.8, -4.8, + -4.8, -6.5, -6.5, -6.5, -6.5, -6.5, 6.5, 6.5, 6.5, 6.5, + 6.5, 4.8, 4.8, 4.8, 4.8, 4.8, -5.4, -5.4, -5.4, -5.4, + -5.4, -7.1, -7.1, -7.1, -7.1, -7.1}; + +constexpr float kMy[936] = { + -1.7, -4.715, -1.7, -4.715, -1.7, -4.715, -1.7, -4.715, -1.7, -4.715, + -1.7, -4.715, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, + -7.73, -3.546, -6.561, -9.576, -3.8, -6.815, -9.83, -3.706, -6.721, -9.736, + -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, + -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -3.706, -6.721, + -9.736, -3.8, -6.815, -9.83, -3.546, -6.561, -9.576, -1.7, -4.715, -7.73, + -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -1.7, -4.715, + -1.7, -4.715, -1.7, -4.715, -1.7, -4.715, -1.7, -4.715, -1.7, -4.715, + -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -3.546, -6.561, -9.576, + -3.8, -6.815, -9.83, -3.706, -6.721, -9.736, -1.7, -4.715, -7.73, -1.7, + -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, + -7.73, -1.7, -4.715, -7.73, -3.706, -6.721, -9.736, -3.8, -6.815, -9.83, + -3.546, -6.561, -9.576, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, + -4.715, -7.73, -1.7, -4.715, -1.7, -4.715, -1.7, -4.715, -1.7, -4.715, + -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -3.55, -6.565, -9.58, -3.8, + -6.815, -9.83, -3.71, -6.725, -9.74, -1.7, -4.715, -7.73, -1.7, -4.715, + -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -3.71, -6.725, -9.74, + -3.8, -6.815, -9.83, -3.55, -6.565, -9.58, -1.7, -4.715, -7.73, -1.7, + -4.715, -7.73, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, + -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, + -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, + -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, + -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, + -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, + -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, + -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, -3.5, -6.515, -9.53, -12.545, + -4.735, -7.75, -10.765, -13.78, -4.9, -7.915, -10.93, -13.945, -4.84, -7.855, + -10.87, -13.885, -3.97, -6.985, -10, -13.015, -1.7, -4.715, -7.73, -10.745, + -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, + -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, + -3.97, -6.985, -10, -13.015, -4.84, -7.855, -10.87, -13.885, -4.9, -7.915, + -10.93, -13.945, -4.735, -7.75, -10.765, -13.78, -3.5, -6.515, -9.53, -12.545, + -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, + -7.73, -10.745, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, + -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, + -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -1.7, -4.715, -7.73, -10.745, + -1.7, -4.715, -7.73, -10.745, -4.125, -7.14, -10.155, -13.17, -5.155, -8.17, + -11.185, -14.2, -5.3, -8.315, -11.33, -14.345, -5.245, -8.26, -11.275, -14.29, + -4.5, -7.515, -10.53, -13.545, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, + -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, + -4.5, -7.515, -10.53, -13.545, -5.245, -8.26, -11.275, -14.29, -5.3, -8.315, + -11.33, -14.345, -5.155, -8.17, -11.185, -14.2, -4.125, -7.14, -10.155, -13.17, + -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, -7.73, -10.745, -1.7, -4.715, + -7.73, -10.745, -13.76, -1.7, -4.715, -7.73, -10.745, -13.76, -1.7, -4.715, + -7.73, -10.745, -13.76, -1.7, -4.715, -7.73, -10.745, -13.76, -1.7, -4.715, + -7.73, -10.745, -13.76, -1.7, -4.715, -7.73, -10.745, -13.76, -1.7, -4.715, + -7.73, -10.745, -13.76, -1.7, -4.715, -7.73, -10.745, -13.76, 1.7, 4.715, + 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, + 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 3.546, + 6.561, 9.576, 3.8, 6.815, 9.83, 3.706, 6.721, 9.736, 1.7, 4.715, + 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, + 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 3.706, 6.721, 9.736, 3.8, + 6.815, 9.83, 3.546, 6.561, 9.576, 1.7, 4.715, 7.73, 1.7, 4.715, + 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, + 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, 7.73, 1.7, + 4.715, 7.73, 1.7, 4.715, 7.73, 3.546, 6.561, 9.576, 3.8, 6.815, + 9.83, 3.706, 6.721, 9.736, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, + 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, + 4.715, 7.73, 3.706, 6.721, 9.736, 3.8, 6.815, 9.83, 3.546, 6.561, + 9.576, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, + 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, 1.7, 4.715, + 7.73, 1.7, 4.715, 7.73, 3.55, 6.565, 9.58, 3.8, 6.815, 9.83, + 3.71, 6.725, 9.74, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, + 4.715, 7.73, 1.7, 4.715, 7.73, 3.71, 6.725, 9.74, 3.8, 6.815, + 9.83, 3.55, 6.565, 9.58, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, + 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, + 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, + 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, + 7.73, 10.745, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, + 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, + 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, + 4.715, 7.73, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, + 1.7, 4.715, 7.73, 10.745, 3.5, 6.515, 9.53, 12.545, 4.735, 7.75, + 10.765, 13.78, 4.9, 7.915, 10.93, 13.945, 4.84, 7.855, 10.87, 13.885, + 3.97, 6.985, 10, 13.015, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, + 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, + 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, 3.97, 6.985, + 10, 13.015, 4.84, 7.855, 10.87, 13.885, 4.9, 7.915, 10.93, 13.945, + 4.735, 7.75, 10.765, 13.78, 3.5, 6.515, 9.53, 12.545, 1.7, 4.715, + 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, + 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, + 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, + 7.73, 1.7, 4.715, 7.73, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, + 7.73, 10.745, 4.125, 7.14, 10.155, 13.17, 5.155, 8.17, 11.185, 14.2, + 5.3, 8.315, 11.33, 14.345, 5.245, 8.26, 11.275, 14.29, 4.5, 7.515, + 10.53, 13.545, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, + 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, 4.5, 7.515, + 10.53, 13.545, 5.245, 8.26, 11.275, 14.29, 5.3, 8.315, 11.33, 14.345, + 5.155, 8.17, 11.185, 14.2, 4.125, 7.14, 10.155, 13.17, 1.7, 4.715, + 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, 1.7, 4.715, 7.73, 10.745, + 13.76, 1.7, 4.715, 7.73, 10.745, 13.76, 1.7, 4.715, 7.73, 10.745, + 13.76, 1.7, 4.715, 7.73, 10.745, 13.76, 1.7, 4.715, 7.73, 10.745, + 13.76, 1.7, 4.715, 7.73, 10.745, 13.76, 1.7, 4.715, 7.73, 10.745, + 13.76, 1.7, 4.715, 7.73, 10.745, 13.76}; +} // namespace mft_xy + +auto static constexpr kMinCharge = 3.f; +auto static constexpr kIntZero = 0; +auto static constexpr kZero = 0.f; +auto static constexpr kIntOne = 1; +auto static constexpr kNlayers = 10; +auto static constexpr kNhits = 15; +auto static constexpr kDisks = 5; + +enum TrkSel { + trkSelAll, + trkSelNCls, + trkSelChi2Ncl, + trkSelEta, + trkSelPhiCut, + trkSelPt, + trkSelCA, + nTrkSel +}; + +enum TrkBestSel { + trkBestSelAll, + trkBestSelCollID, + trkBestSelDCAxyCut, + trkBestSelDCAzCut, + trkBestSelWoAmbiguous, + nTrkBestSel +}; + +enum OccupancyEst { TrkITS = 1, + Ft0C +}; + +struct PseudoEffMFT { + + HistogramRegistry registry{ + "registry", + {}, + OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgDoIR{"cfgDoIR", false, "Flag to retrieve Interaction rate from CCDB"}; + Configurable cfgUseIRCut{"cfgUseIRCut", false, "Flag to cut on IR rate"}; + Configurable cfgIRCrashOnNull{"cfgIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash"}; + Configurable cfgIRSource{"cfgIRSource", "ZNC hadronic", "Estimator of the interaction rate (Pb-Pb: ZNC hadronic)"}; + Configurable cfgUseEventkSel{"cfgUseEventkSel", false, "Flag to apply event selection"}; + Configurable cfgUseTrackSel{"cfgUseTrackSel", false, "Flag to apply track selection"}; + Configurable cfgUseParticleSel{"cfgUseParticleSel", false, "Flag to apply particle selection"}; + Configurable cfgUseCcdbForRun{"cfgUseCcdbForRun", false, "Get ccdb object based on run number instead of timestamp"}; + Configurable cfgRejectDeadChips{"cfgRejectDeadChips", true, "Reject tracks passing by dead chips per MFT layer "}; + Configurable cfgDeadMapCcdbPath{"cfgDeadMapCcdbPath", "MFT/Calib/TimeDeadMap", "CCDB path for MFT dead map"}; + + struct : ConfigurableGroup { + ConfigurableAxis interactionRateBins{"interactionRateBins", {500, 0, 50}, "Binning for the interaction rate (kHz)"}; + 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)"}; + ConfigurableAxis ptBins{"ptBins", {11, -0.5, 10.5}, "pT binning (GeV/c)"}; + ConfigurableAxis phiBins{"phiBins", {63, 0., TwoPI}, "#varphi binning (rad)"}; + ConfigurableAxis etaBins{"etaBins", {20, -4., -2.}, "#eta binning"}; + Configurable nEtaBins{"nEtaBins", 400, "Number of Eta bins"}; + Configurable nPhiBins{"nPhiBins", 400, "Number of Phi bins"}; + } binOpt; + + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", false, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_fw", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCuts; + + 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 useChi2Cut{"useChi2Cut", false, "use track chi2 cut"}; + Configurable maxChi2NCl{"maxChi2NCl", 1000.f, "maximum chi2 per MFT clusters"}; + Configurable usePtCut{"usePtCut", false, "use track pT cut"}; + Configurable minPt{"minPt", 0., "minimum pT of the MFT tracks"}; + Configurable requireCA{"requireCA", false, "Use Cellular Automaton track-finding algorithm"}; + Configurable excludeAmbiguous{"excludeAmbiguous", false, "Exclude Ambiguous tracks"}; + Configurable maxDCAxy{"maxDCAxy", 0.01f, "Cut on dca XY"}; + Configurable maxDCAz{"maxDCAz", 0.01f, "Cut on dca Z"}; + } trackCuts; + + struct : ConfigurableGroup { + Configurable maxZvtx{"maxZvtx", 20.0f, "maximum cut on z-vtx (cm)"}; + Configurable minZvtx{"minZvtx", -20.0f, "minimum cut on z-vtx (cm)"}; + 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 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 requireRejectSameBunchPileup{"requireRejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", true, " requireNoCollInTimeRangeStrict"}; + Configurable requireNoCollInRofStrict{"requireNoCollInRofStrict", false, "requireNoCollInRofStrict"}; + Configurable requireNoCollInRofStandard{"requireNoCollInRofStandard", false, "requireNoCollInRofStandard"}; + Configurable requireNoHighMultCollInPrevRof{"requireNoHighMultCollInPrevRof", false, "requireNoHighMultCollInPrevRof"}; + 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 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; + + 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"}; + Configurable ccdbPath{"ccdbPath", "MFT/Calib/TimeDeadMap", "ccdb path to MFT deadmap"}; + + int nBCsPerOrbit = 3564; + uint64_t mOrbit; + uint64_t mPrevOrbit; + o2::itsmft::TimeDeadMap* deadmap = nullptr; + std::array, 10> chipsPerLayer{}; + std::array layerMasks; + const o2::itsmft::ChipMappingMFT mapping; + const std::array chipMap = mapping.getChipMappingData(); + + float dX = 1.7; + float dY = 3.015; + std::array layersZ = {-45.3, -46.7, -48.6, -50.0, -52.4, -53.8, -67.7, -69.1, -76.1, -77.5}; + + int mRunNumber{-1}; + uint64_t mSOR{0}; + float mMinSeconds{-1.}; + std::unordered_map gHadronicRate; + ctpRateFetcher rateFetcher; + TH2* gCurrentHadronicRate; + RCTFlagsChecker rctChecker; + + /// @brief init function, definition of histograms + void init(InitContext&) + { + const AxisSpec centralityAxis = {binOpt.centralityBins, "Centrality", "centrality axis"}; + const AxisSpec occupancyAxis = {binOpt.occupancyBins, "Occupancy", "occupancy axis"}; + const AxisSpec irAxis = {binOpt.interactionRateBins, "Interaction Rate", "IR axis"}; + const AxisSpec ptAxis = {binOpt.ptBins, "Pt axis (GeV/c)"}; + const AxisSpec phiAxis = {binOpt.phiBins, "#phi axis"}; + const AxisSpec etaAxis = {binOpt.etaBins, "#eta axis"}; + + rctChecker.init(rctCuts.cfgEvtRCTFlagCheckerLabel, rctCuts.cfgEvtRCTFlagCheckerZDCCheck, rctCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(ccdbNoLaterThan.value); + ccdb->setFatalWhenNull(false); + + auto hev = registry.add("Events/hEvtSel", "hEvtSel", HistType::kTH1F, + {{15, -0.5f, +14.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, "kNoCollInTimeRangeStrict"); + hev->GetXaxis()->SetBinLabel(9, "kNoCollInRofStrict"); + hev->GetXaxis()->SetBinLabel(10, "kNoCollInRofStandard"); + hev->GetXaxis()->SetBinLabel(11, "kNoHighMultCollInPrevRof"); + hev->GetXaxis()->SetBinLabel(12, "Below min occup."); + hev->GetXaxis()->SetBinLabel(13, "Above max occup."); + hev->GetXaxis()->SetBinLabel(14, "RCT Flag Checker"); + + registry.add("Tracks/hBestTrkSel", "Number of best tracks; Cut; #Tracks Passed Cut", {HistType::kTH1F, {{nTrkBestSel, -0.5, +nTrkBestSel - 0.5}}}); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelAll + 1, "All"); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelCollID + 1, "Assigned (ID>=0)"); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelDCAxyCut + 1, "DCA xy cut"); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelDCAzCut + 1, "DCA z cut"); + registry.get(HIST("Tracks/hBestTrkSel"))->GetXaxis()->SetBinLabel(trkBestSelWoAmbiguous + 1, "No Ambiguous"); + + registry.add("Tracks/hTrkSel", "Number of tracks; Cut; #Tracks Passed Cut", {HistType::kTH1F, {{nTrkSel, -0.5, +nTrkSel - 0.5}}}); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelAll + 1, "All"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNCls + 1, "Ncl cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelChi2Ncl + 1, "#chi^{2}/Ncl cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelEta + 1, "#eta cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPhiCut + 1, "#varphi cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPt + 1, "#it{p}_{T} cut"); + registry.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelCA + 1, "Tracking algorithm (CA)"); + + 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"); + + if (doprocessPseudoEffInclusive || doprocessPseudoEffMCInlusive || + doprocessPseudoEffCentFT0C || doprocessPseudoEffMCCentFT0C) { + registry.add("Events/hInteractionRate", "; IR (kHz)", kTH1F, {irAxis}); + for (int i = 0; i < kNlayers; i++) { + layerMasks[i] = new TH2I("", "", binOpt.nEtaBins, trackCuts.minEta, trackCuts.maxEta, binOpt.nPhiBins, -PI, +PI); + } + + const AxisSpec axisMFtBitMap{1031, -0.5, 1030.5, "axisMFtBitMap"}; + registry.add("hMftBitMap", "hMftBitMap", {HistType::kTH1F, {axisMFtBitMap}}); + + const AxisSpec axisNhits{15, -0.5, 15.5, ""}; + const char* elabels[15] = {"N12", "N10", "N02", "N34", "N30", "N04", "N56", "N50", "N06", "N78", "N70", "N08", "N910", "N90", "N010"}; + HistogramConfigSpec defaultNhitsEtaPtPhi({HistType::kTHnF, {{axisNhits}, {etaAxis}, {ptAxis}, {phiAxis}}}); + HistogramConfigSpec defaultNhitsCentEtaPtPhi({HistType::kTHnF, {{axisNhits}, {etaAxis}, {ptAxis}, {phiAxis}, {centralityAxis}}}); + + if (doprocessPseudoEffInclusive) { + registry.add("hEtaPtPhi", "hEtaPtPhi", defaultNhitsEtaPtPhi); + auto hEtaPtPhi = registry.get(HIST("hEtaPtPhi")); + for (int i = 0; i < kNhits; i++) { + hEtaPtPhi->GetAxis(0)->SetBinLabel(i + 1, elabels[i]); + } + } + + if (doprocessPseudoEffCentFT0C) { + registry.add("Cent/hEtaPtPhi", "hEtaPtPhi", defaultNhitsCentEtaPtPhi); + auto hEtaPtPhi = registry.get(HIST("Cent/hEtaPtPhi")); + for (int i = 0; i < kNhits; i++) { + hEtaPtPhi->GetAxis(0)->SetBinLabel(i + 1, elabels[i]); + } + } + + if (doprocessPseudoEffMCInlusive) { + registry.add("hPtRecVsGen", "; #it{p}_{T} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c}) Gen", {HistType::kTH2F, {{ptAxis}, {ptAxis}}}); + registry.add("hEtaRecVsGen", "; #eta; #eta Gen", {HistType::kTH2F, {{etaAxis}, {etaAxis}}}); + registry.add("hPhiRecVsGen", "; #varphi; #varphi Gen", {HistType::kTH2F, {{phiAxis}, {phiAxis}}}); + registry.add("hEtaPtPhiGen", "hEtaPtPhiGen", defaultNhitsEtaPtPhi); + auto hEtaPtPhiGen = registry.get(HIST("hEtaPtPhiGen")); + for (int i = 0; i < kNhits; i++) { + hEtaPtPhiGen->GetAxis(0)->SetBinLabel(i + 1, elabels[i]); + } + registry.add("hMftBitMapGen", "hMftBitMapGen", {HistType::kTH1F, {axisMFtBitMap}}); + } + + if (doprocessPseudoEffMCCentFT0C) { + registry.add("Cent/hPtRecVsGen", "; #it{p}_{T} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c}) Gen", {HistType::kTHnF, {{ptAxis}, {ptAxis}, {centralityAxis}}}); + registry.add("Cent/hEtaRecVsGen", "; #eta; #eta Gen", {HistType::kTHnF, {{etaAxis}, {etaAxis}, {centralityAxis}}}); + registry.add("Cent/hPhiRecVsGen", "; #varphi; #varphi Gen", {HistType::kTHnF, {{phiAxis}, {phiAxis}, {centralityAxis}}}); + registry.add("Cent/hEtaPtPhiGen", "hEtaPtPhiGen", defaultNhitsCentEtaPtPhi); + auto hEtaPtPhiGen = registry.get(HIST("Cent/hEtaPtPhiGen")); + for (int i = 0; i < kNhits; i++) { + hEtaPtPhiGen->GetAxis(0)->SetBinLabel(i + 1, elabels[i]); + } + } + } + } + + /// Filters - tracks + Filter filtTrkEta = (aod::fwdtrack::eta < trackCuts.maxEta) && (aod::fwdtrack::eta > trackCuts.minEta); + Filter filtATrackID = (aod::fwdtrack::bestCollisionId >= 0); + Filter filtATrackDCAxy = (nabs(aod::fwdtrack::bestDCAXY) < trackCuts.maxDCAxy); + Filter filtATrackDCAz = (nabs(aod::fwdtrack::bestDCAZ) < trackCuts.maxDCAz); + /// Filters - mc particles + Filter primaries = (aod::mcparticle::flags & (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary) == (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary && (aod::mcparticle::eta < trackCuts.maxEta) && (aod::mcparticle::eta > trackCuts.minEta); + + /// Joined tables + using FullBCs = soa::Join; + using CollBCs = soa::Join; + using Colls = soa::Join; + using CollsCentFT0C = soa::Join; + + using MFTTracksLabeled = soa::Join; + + /// Filtered tables + using FiltMftTracks = soa::Filtered; + using FiltMcMftTracks = soa::Filtered; + using FiltParticles = soa::Filtered; + + template + ObjType* getForTsOrRun(std::string const& fullPath, int64_t timestamp, int runNumber) + { + if (cfgUseCcdbForRun) { + return ccdb->getForRun(fullPath, runNumber); + } else { + return ccdb->getForTimeStamp(fullPath, timestamp); + } + } + + void initCCDB(CollBCs::iterator const& bc) + { + auto timestamp = bc.timestamp(); + auto runnumber = bc.runNumber(); + if (cfgRejectDeadChips) { + deadmap = getForTsOrRun(cfgDeadMapCcdbPath, timestamp, runnumber); + if (deadmap != nullptr) { + LOGF(info, "Using deadmap for run %d", bc.runNumber()); + } else { + LOGF(fatal, "DeadMap is not available in CCDB for run=%d at timestamp=%llu", bc.runNumber(), bc.timestamp()); + } + } + } + + void decodeChipVector(std::vector& inChips, std::array, 10>& outChipsPerLayer) + { + bool prevIsDead = false; + uint16_t lastDead = 0; + for (auto const& chip : inChips) { + if (chip & static_cast(0x8000)) { + auto firstChip = chip - 0x8000; + outChipsPerLayer[chipMap[firstChip].layer].push_back(firstChip); + prevIsDead = true; + lastDead = static_cast(firstChip); + } else { + if (prevIsDead) { + for (int i = 1; i < chip - lastDead; i++) { + outChipsPerLayer[chipMap[i + lastDead].layer].push_back(i + lastDead); + } + } + outChipsPerLayer[chipMap[chip].layer].push_back(chip); + prevIsDead = false; + } + } + } + + std::tuple computeEtaPhiCoverage(float posX, float posY, float dX, float dY, float z) + { + float x1 = posX - dX / 2.0; + float x2 = posX + dX / 2.0; + float y1 = posY - dY / 2.0; + float y2 = posY + dY / 2.0; + + std::vector etas; + std::vector phis; + etas.reserve(4); + phis.reserve(4); + + for (auto const& x : {x1, x2}) { + for (auto const& y : {y1, y2}) { + float r = std::sqrt(x * x + y * y); + float theta = std::atan2(r, z); + float eta = -std::log(std::tan(theta / 2.0)); + float phi = std::atan2(y, x); + etas.push_back(eta); + phis.push_back(phi); + } + } + + float etaMin = *std::min_element(etas.begin(), etas.end()); + float etaMax = *std::max_element(etas.begin(), etas.end()); + float phiMin = *std::min_element(phis.begin(), phis.end()); + float phiMax = *std::max_element(phis.begin(), phis.end()); + + RecoDecay::constrainAngle(phiMax - phiMin, 0.f); + + phiMin = *std::min_element(phis.begin(), phis.end()); + phiMax = *std::max_element(phis.begin(), phis.end()); + + return std::make_tuple(etaMin, etaMax, phiMin, phiMax); + } + + void applyChipToMask(TH2* mask, float etaMin, float etaMax, float phiMin, float phiMax) + { + if (!mask) + return; + + int etaBinMin = mask->GetXaxis()->FindBin(etaMin); + int etaBinMax = mask->GetXaxis()->FindBin(etaMax); + int phiBinMin = mask->GetYaxis()->FindBin(phiMin); + int phiBinMax = mask->GetYaxis()->FindBin(phiMax); + + for (int iEta = etaBinMin; iEta <= etaBinMax; ++iEta) { + for (int iPhi = phiBinMin; iPhi <= phiBinMax; ++iPhi) { + mask->SetBinContent(iEta, iPhi, 1.0); + } + } + } + + void computeExclusionMap(int layer) + { + auto chips = chipsPerLayer[layer]; + float z = layersZ[layer]; + for (const auto& chip : chips) { + float posX = mft_xy::kMx[chip]; + float posY = mft_xy::kMy[chip]; + auto [etaMin, etaMax, phi_min, phi_max] = computeEtaPhiCoverage(posX, posY, dX, dY, z); + applyChipToMask(layerMasks[layer], etaMin, etaMax, phi_min, phi_max); + } + } + + bool isExcluded(float eta, float phi, int layer) + { + int binEta = layerMasks[layer]->GetXaxis()->FindBin(eta); + int binPhi = layerMasks[layer]->GetYaxis()->FindBin(phi); + bool isBad = (layerMasks[layer]->GetBinContent(binEta, binPhi) > 0); + return isBad; + } + + bool isHitAtDisk(uint16_t map, int ilayer) + { + LOGP(debug, " map %i --> %i", map, (map >> (ilayer * 6)) & 0x3F); + return (map >> (ilayer * 6)) & 0x3F; + } + + template + void fillHistos(float cent, float eta, float pt, float phi, uint16_t map) + { + if constexpr (!isMC) { + registry.fill(HIST("hMftBitMap"), map); + } else { + registry.fill(HIST("hMftBitMapGen"), map); + } + + bool iN[10]; + for (int ilayer = 0; ilayer < kNlayers; ilayer++) { + iN[ilayer] = false; + bool ishit = isHitAtDisk(map, ilayer); + if (ishit) { + iN[ilayer] = true; + } + } + + for (int i = 0; i < kDisks; i++) { + if (iN[2 * i] && iN[2 * i + 1]) { + if constexpr (!isMC) { + if constexpr (isCent) { + registry.get(HIST("Cent/hEtaPtPhi"))->Fill(3 * i, eta, pt, phi, cent); + } else { + registry.get(HIST("hEtaPtPhi"))->Fill(3 * i, eta, pt, phi); + } + } else { + if constexpr (isCent) { + registry.get(HIST("Cent/hEtaPtPhiGen"))->Fill(3 * i, eta, pt, phi, cent); + } else { + registry.get(HIST("hEtaPtPhiGen"))->Fill(3 * i, eta, pt, phi); + } + } + } + if (iN[2 * i] && (!iN[2 * i + 1]) && !isExcluded(eta, phi, 2 * i + 1)) { + if constexpr (!isMC) { + if constexpr (isCent) { + registry.get(HIST("Cent/hEtaPtPhi"))->Fill(3 * i + 1, eta, pt, phi, cent); + } else { + registry.get(HIST("hEtaPtPhi"))->Fill(3 * i + 1, eta, pt, phi); + } + } else { + if constexpr (isCent) { + registry.get(HIST("Cent/hEtaPtPhiGen"))->Fill(3 * i + 1, eta, pt, phi, cent); + } else { + registry.get(HIST("hEtaPtPhiGen"))->Fill(3 * i + 1, eta, pt, phi); + } + } + } + if ((!iN[2 * i]) && iN[2 * i + 1] && !isExcluded(eta, phi, 2 * i)) { + if constexpr (!isMC) { + if constexpr (isCent) { + registry.get(HIST("Cent/hEtaPtPhi"))->Fill(3 * i + 2, eta, pt, phi, cent); + } else { + registry.get(HIST("hEtaPtPhi"))->Fill(3 * i + 2, eta, pt, phi); + } + } else { + if constexpr (isCent) { + registry.get(HIST("Cent/hEtaPtPhiGen"))->Fill(3 * i + 2, eta, pt, phi, cent); + } else { + registry.get(HIST("hEtaPtPhiGen"))->Fill(3 * i + 2, eta, pt, phi); + } + } + } + } + } + + template + bool isBestTrackSelected(const B& besttrack) + { + if (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelAll); + } + if (besttrack.bestCollisionId() < kIntZero) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelCollID); + } + if (std::abs(besttrack.bestDCAXY()) >= trackCuts.maxDCAxy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelDCAxyCut); + } + if (std::abs(besttrack.bestDCAZ()) >= trackCuts.maxDCAxy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelDCAzCut); + } + if (trackCuts.excludeAmbiguous && besttrack.ambDegree() > kIntOne) { + return false; + } + if (fillHis) { + registry.fill(HIST("Tracks/hBestTrkSel"), trkBestSelWoAmbiguous); + } + return true; + } + + template + bool isTrackSelected(const T& track) + { + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelAll); + } + if (track.nClusters() < trackCuts.minNclusterMft) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelNCls); + } + if (trackCuts.useChi2Cut) { + float nclMft = std::max(2.0f * track.nClusters() - 5.0f, 1.0f); + float mftChi2NCl = track.chi2() / nclMft; + if (mftChi2NCl > trackCuts.maxChi2NCl) + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelChi2Ncl); + } + if (track.eta() < trackCuts.minEta || track.eta() > trackCuts.maxEta) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelEta); + } + 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; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelPhiCut); + } + if (trackCuts.usePtCut && track.pt() < trackCuts.minPt) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelPt); + } + if (trackCuts.requireCA && !track.isCA()) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Tracks/hTrkSel"), trkSelCA); + } + return true; + } + + template + bool isParticleSelected(P const& particle) + { + if (particle.eta() < trackCuts.minEta || particle.eta() > trackCuts.maxEta) { + return false; + } + if (trackCuts.usephiCut) { + float phi = particle.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 + 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; + } + + void initHadronicRate(CollBCs::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 + float 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(eventCuts.maxIR - eventCuts.minIR); + gHadronicRate[mRunNumber] = registry.add(Form("HadronicRate/%i", mRunNumber), ";Time since SOR (s);Hadronic rate (kHz)", kTH2D, {axisSeconds, {hadronicRateBins, eventCuts.minIR, eventCuts.maxIR}}).get(); + } + gCurrentHadronicRate = gHadronicRate[mRunNumber]; + } + + template + bool isGoodEvent(C const& collision) + { + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 0); + } + if (!collision.sel8()) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 1); + } + if (eventCuts.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 2); + } + if (eventCuts.requireRejectSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 3); + } + if (collision.posZ() <= eventCuts.minZvtx || collision.posZ() >= eventCuts.maxZvtx) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 4); + } + if (eventCuts.requireNoCollInTimeRangeStd && + !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 5); + } + if (eventCuts.requireNoCollInTimeRangeNarrow && + !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 6); + } + if (eventCuts.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 7); + } + if (eventCuts.requireNoCollInRofStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 8); + } + if (eventCuts.requireNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 9); + } + if (eventCuts.requireNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 10); + } + if (eventCuts.minOccupancy >= 0 && + getOccupancy(collision, eventCuts.occupancyEstimator) < + eventCuts.minOccupancy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 11); + } + if (eventCuts.maxOccupancy >= 0 && + getOccupancy(collision, eventCuts.occupancyEstimator) > + eventCuts.maxOccupancy) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 12); + } + + if (rctCuts.requireRCTFlagChecker && !rctChecker(collision)) { + return false; + } + if constexpr (fillHis) { + registry.fill(HIST("Events/hEvtSel"), 13); + } + 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) >= kMinCharge; + } + + /// @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(PseudoEffMFT, processTagging, "Collect event sample stats", true); + + template + void processPseudoEff(typename C::iterator const& collision, + FiltMftTracks const& /*tracks*/, + soa::SmallGroups const& besttracks, + CollBCs const& /*bcs*/) + { + auto bcFound = collision.template foundBC_as(); + + if (cfgDoIR) { + initHadronicRate(bcFound); + float ir = !cfgIRSource.value.empty() ? rateFetcher.fetch(ccdb.service, bcFound.timestamp(), bcFound.runNumber(), cfgIRSource, cfgIRCrashOnNull) * 1.e-3 : -1; + registry.fill(HIST("Events/hInteractionRate"), ir); + float seconds = bcFound.timestamp() * 1.e-3 - mMinSeconds; + if (cfgUseIRCut && (ir < eventCuts.minIR || ir > eventCuts.maxIR)) { // cut on hadronic rate + return; + } + gCurrentHadronicRate->Fill(seconds, ir); + } + + for (auto const& atrack : besttracks) { + if (cfgUseTrackSel && !isBestTrackSelected(atrack)) { + continue; + } + auto track = atrack.mfttrack_as(); + if (!track.has_collision()) { + continue; + } + const auto& coll = track.collision_as(); + if (cfgRejectDeadChips) { + auto bc = coll.template bc_as(); + int currentRun = bc.runNumber(); + if (mRunNumber != currentRun) { + initCCDB(bc); + mRunNumber = currentRun; + auto orbits = deadmap->getEvolvingMapKeys(); + } + if (mOrbit != (bc.globalBC() / nBCsPerOrbit)) { + mOrbit = (bc.globalBC() / nBCsPerOrbit); + std::vector encodeChips; + auto lowerOrbit = deadmap->getMapAtOrbit(mOrbit, encodeChips); + if ((mOrbit - lowerOrbit) > mPrevOrbit) { + for (int i = 0; i < kNlayers; i++) { + chipsPerLayer[i].clear(); + } + // for (auto& v : chipsPerLayer) { + // v.clear(); + // } + // for (auto& h : layerMasks) { + // if (h) + // h->Reset("ICES"); + // } + decodeChipVector(encodeChips, chipsPerLayer); + for (int i = 0; i < kNlayers; i++) { + computeExclusionMap(i); + } + mPrevOrbit = mOrbit - lowerOrbit; + } + } + } + + if (cfgUseEventkSel && !isGoodEvent(coll)) { + continue; + } + if (cfgUseTrackSel && !isTrackSelected(track)) { + continue; + } + + auto eta = track.eta(); + auto pt = track.pt(); + auto phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < kZero || TwoPI < phi) { + continue; + } + auto map = track.mftClusterSizesAndTrackFlags(); + fillHistos>(getRecoCent(collision), eta, pt, phi, map); + } + } + + void processPseudoEffInclusive(Colls::iterator const& collision, + FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& bcs) + { + processPseudoEff(collision, tracks, besttracks, bcs); + } + + PROCESS_SWITCH(PseudoEffMFT, processPseudoEffInclusive, "Process PseudoEffMFT data/reco (inclusive)", true); + + void processPseudoEffCentFT0C(CollsCentFT0C::iterator const& collision, + FiltMftTracks const& tracks, + soa::SmallGroups const& besttracks, + CollBCs const& bcs) + { + processPseudoEff(collision, tracks, besttracks, bcs); + } + + PROCESS_SWITCH(PseudoEffMFT, processPseudoEffCentFT0C, "Process PseudoEffMFT data/reco (in FT0C centrality bins)", false); + + template + void processPseudoEffMC(typename soa::Join::iterator const& collision, + MC const& /*mccollisions*/, + FiltParticles const& /*particles*/, + FiltMcMftTracks const& /*tracks*/, + soa::SmallGroups const& besttracks) + { + if (cfgUseEventkSel && !isGoodEvent(collision)) { + return; + } + if (!collision.has_mcCollision()) { + return; + } + auto mcCollision = collision.mcCollision(); + if (eventCuts.useZDiffCut) { + if (std::abs(collision.posZ() - mcCollision.posZ()) > eventCuts.maxZvtxDiff) { + return; + } + } + + for (auto const& atrack : besttracks) { + if (cfgUseTrackSel && !isBestTrackSelected(atrack)) { + continue; + } + auto track = atrack.mfttrack_as(); + auto eta = track.eta(); + auto pt = track.pt(); + + auto phi = track.phi(); + o2::math_utils::bringTo02Pi(phi); + if (phi < kZero || TwoPI < phi) { + continue; + } + + auto map = track.mftClusterSizesAndTrackFlags(); + if (cfgUseTrackSel && !isTrackSelected(track)) { + continue; + } + if (!track.has_mcParticle()) { + LOGF(warning, "No MC particle for track, skipping..."); + continue; + } + auto particle = track.template mcParticle_as(); + + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if (cfgUseParticleSel && !isParticleSelected(particle)) { + continue; + } + + auto partphi = particle.phi(); + o2::math_utils::bringTo02Pi(partphi); + if (partphi < 0.f || TwoPI < partphi) { + continue; + } + + float cGen = getRecoCent(collision); + if constexpr (has_reco_cent) { + registry.fill(HIST("Cent/hPtRecVsGen"), pt, particle.pt(), cGen); + registry.fill(HIST("Cent/hEtaRecVsGen"), eta, particle.eta(), cGen); + registry.fill(HIST("Cent/hPhiRecVsGen"), phi, partphi, cGen); + } else { + registry.fill(HIST("hPtRecVsGen"), pt, particle.pt()); + registry.fill(HIST("hEtaRecVsGen"), eta, particle.eta()); + registry.fill(HIST("hPhiRecVsGen"), phi, partphi); + } + fillHistos, true>(cGen, particle.eta(), particle.pt(), partphi, map); + } + } + + void processPseudoEffMCInlusive(soa::Join::iterator const& collision, + aod::McCollisions const& mccollisions, + FiltParticles const& particles, + FiltMcMftTracks const& tracks, + soa::SmallGroups const& besttracks) + { + processPseudoEffMC(collision, mccollisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(PseudoEffMFT, processPseudoEffMCInlusive, "Process PseudoEffMFT mc generated (inclusive)", false); + + void processPseudoEffMCCentFT0C(soa::Join::iterator const& collision, + aod::McCollisions const& mccollisions, + FiltParticles const& particles, + FiltMcMftTracks const& tracks, + soa::SmallGroups const& besttracks) + { + processPseudoEffMC(collision, mccollisions, particles, tracks, besttracks); + } + + PROCESS_SWITCH(PseudoEffMFT, processPseudoEffMCCentFT0C, "Process PseudoEffMFT mc generated (in FT0C centrality bins)", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGMM/UE/Tasks/CMakeLists.txt b/PWGMM/UE/Tasks/CMakeLists.txt index 19a0ecba60a..f9ee32c6e10 100644 --- a/PWGMM/UE/Tasks/CMakeLists.txt +++ b/PWGMM/UE/Tasks/CMakeLists.txt @@ -19,7 +19,7 @@ o2physics_add_dpl_workflow(ue-zdc-analysis PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(ue-lambdak0sflattenicity - SOURCES lambdak0sflattenicity.cxx +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..a4ea4bb22ac --- /dev/null +++ b/PWGMM/UE/Tasks/dedxAnalysis.cxx @@ -0,0 +1,1174 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.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/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/Logger.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/V0.h" + +#include "TF1.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; +using BCsRun3 = soa::Join; + +struct DedxAnalysis { + + // dE/dx for all charged particles + HistogramRegistry registryDeDx{ + "registryDeDx", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + // Constant values + static constexpr int kEtaIntervals = 8; + static constexpr int kParticlesType = 4; + float tpcCut = 0.6; + float pionMin = 0.35; + float pionMax = 0.45; + float elTofCut = 0.1; + float pionTofCut = 1.0; + float invMassCut = 0.01; + float invMassCutGamma = 0.0015; + float pTcut = 2.0; + + // Event cut labels + enum EvCutLabel { + AllEv = 1, + SelEigth, + ZVtxCut + }; + + // Track primary label + enum TrkPriCutLabel { + AllPri = 1, + SelectionPrim, + PhiVarCutPri, + NTPCClCutPri, + NITSClCutPri + }; + + // Track secondary lebel + enum TrkSecCutLabel { + AllSec = 1, + V0CosPA, + V0DecayRadius, + V0Daughters, + TPCRefit, + PhiVarCutSec, + NTPCClCutSec, + NITSClCutSec, + V0RapidityK0s, + V0ProperLifetimeK0s, + V0RapidityLambda, + V0ProperLifetimeLambda, + V0RapidityAntiLambda, + V0ProperLifetimeAntiLambda + }; + // Configurable Parameters + // Tracks cuts + Configurable minTPCnClsFound{"minTPCnClsFound", 70.0f, + "min number of found TPC clusters"}; + Configurable minITSnCls{"minITSnCls", 70.0f, + "min number of ITS 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 maxZDistanceToIP{"maxZDistanceToIP", 10.0f, + "max z distance to IP"}; + 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", 0.1f, "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 v0rapidityCut{"v0rapidityCut", 0.5f, "V0 rapidity cut"}; + Configurable v0ProperLifetimeCutK0s{"v0ProperLifetimeCutK0s", 20.f, "V0 proper lifetime cut for K0s"}; + Configurable v0ProperLifetimeCutLambda{"v0ProperLifetimeCutLambda", 30.f, "V0 proper lifetime cut for Lambda"}; + 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"}; + Configurable phiVarCut{"phiVarCut", true, "phi var cut"}; + Configurable nTPCClCut{"nTPCClCut", true, "number of clusters in TPC cut"}; + Configurable nITSClCut{"nITSClCut", true, "number of clusters in ITS cut"}; + // Histograms names + static constexpr std::string_view kDedxvsMomentumPos[kParticlesType] = {"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[kParticlesType] = {"dEdx_vs_Momentum_all_Neg", "dEdx_vs_Momentum_Pi_v0_Neg", "dEdx_vs_Momentum_Pr_v0_Neg", "dEdx_vs_Momentum_El_v0_Neg"}; + // Ncl TPC + static constexpr std::string_view kNclTPCDedxMomentumNegBefore[kEtaIntervals] = {"Ncl_TPC_vs_dEdx_vs_Momentum_Neg_1_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_2_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_3_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_4_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_5_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_6_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_7_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_8_Before"}; + static constexpr std::string_view kNclTPCDedxMomentumPosBefore[kEtaIntervals] = {"Ncl_TPC_vs_dEdx_vs_Momentum_Pos_1_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_2_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_3_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_4_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_5_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_6_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_7_Before", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_8_Before"}; + static constexpr std::string_view kNclTPCDedxMomentumNegAfter[kEtaIntervals] = {"Ncl_TPC_vs_dEdx_vs_Momentum_Neg_1_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_2_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_3_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_4_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_5_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_6_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_7_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Neg_8_After"}; + static constexpr std::string_view kNclTPCDedxMomentumPosAfter[kEtaIntervals] = {"Ncl_TPC_vs_dEdx_vs_Momentum_Pos_1_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_2_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_3_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_4_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_5_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_6_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_7_After", "Ncl_TPC_vs_dEdx_vs_Momentum_Pos_8_After"}; + // Ncl TPC + static constexpr std::string_view kNclITSDedxMomentumNegBefore[kEtaIntervals] = {"Ncl_ITS_vs_dEdx_vs_Momentum_Neg_1_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_2_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_3_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_4_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_5_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_6_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_7_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_8_Before"}; + static constexpr std::string_view kNclITSDedxMomentumPosBefore[kEtaIntervals] = {"Ncl_ITS_vs_dEdx_vs_Momentum_Pos_1_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_2_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_3_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_4_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_5_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_6_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_7_Before", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_8_Before"}; + static constexpr std::string_view kNclITSDedxMomentumNegAfter[kEtaIntervals] = {"Ncl_ITS_vs_dEdx_vs_Momentum_Neg_1_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_2_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_3_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_4_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_5_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_6_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_7_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Neg_8_After"}; + static constexpr std::string_view kNclITSDedxMomentumPosAfter[kEtaIntervals] = {"Ncl_ITS_vs_dEdx_vs_Momentum_Pos_1_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_2_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_3_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_4_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_5_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_6_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_7_After", "Ncl_ITS_vs_dEdx_vs_Momentum_Pos_8_After"}; + static constexpr double EtaCut[kEtaIntervals + 1] = {-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}, ""}; + + // phi cut fits + TF1* fphiCutHigh = nullptr; + TF1* fphiCutLow = nullptr; + Service ccdb; + + 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, 2}); + selectedTracks.SetMaxChi2PerClusterITS(maxChi2ITS); + selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / std::pow(pt, 1.1f); }); + selectedTracks.SetMaxDcaZ(maxDCAz); + selectedTracks.SetRequireGoldenChi2(true); + + return selectedTracks; + } + + TrackSelection mySelectionPrim; + + void init(InitContext const&) + { + AxisSpec dedxAxis{100, 0.0, 100.0, "dE/dx (a. u.)"}; + AxisSpec ptAxis = {binP, "pT (GeV/c)"}; + AxisSpec etaAxis{8, -0.8, 0.8, "#eta"}; + AxisSpec pAxis = {binP, "#it{p}/Z (GeV/c)"}; + fphiCutLow = new TF1("StandardPhiCutLow", "0.119297/x/x+pi/18.0-0.000379693", 0, 50); + fphiCutHigh = new TF1("StandardPhiCutHigh", "0.16685/x+pi/18.0+0.00981942", 0, 50); + 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}}); + + // pt vs p + registryDeDx.add( + "heta_vs_p_vs_pt_all_Neg", "eta_vs_p_vs_pT", HistType::kTH3F, + {{etaAxis}, {ptAxis}, {pAxis}}); + registryDeDx.add( + "heta_vs_p_vs_pt_all_Pos", "eta_vs_p_vs_pT", HistType::kTH3F, + {{etaAxis}, {ptAxis}, {pAxis}}); + + // De/Dx for ch and v0 particles + for (int i = 0; i < kParticlesType; ++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}}); + // phi cut + if (phiVarCut) { + registryDeDx.add( + "hpt_vs_phi_Ncl_TPC_After", "phi cut", HistType::kTH3F, + {{ptAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl}"}}); + + registryDeDx.add( + "hpt_vs_phi_Ncl_TPC_Before", "phi cut", HistType::kTH3F, + {{ptAxis}, {100, 0.0, 0.4, "#varphi^{'}"}, {100, 0, 160, "N_{cl}"}}); + + // Ncl vs de/dx TPC + + for (int i = 0; i < kEtaIntervals; ++i) { + registryDeDx.add(kNclTPCDedxMomentumPosBefore[i].data(), "Ncl TPC vs dE/dx vs Momentum Positive before", HistType::kTH3F, + {{100, 0, 160, "N_{cl}^{TPC}"}, {dedxAxis}, {pAxis}}); + registryDeDx.add(kNclTPCDedxMomentumNegBefore[i].data(), "Ncl TPC vs dE/dx vs Momentum Negative before", HistType::kTH3F, + {{100, 0, 160, "N_{cl}^{TPC}"}, {dedxAxis}, {pAxis}}); + if (nTPCClCut) { + registryDeDx.add(kNclTPCDedxMomentumPosAfter[i].data(), "Ncl TPC vs dE/dx vs Momentum Positive after", HistType::kTH3F, + {{100, 0, 160, "N_{cl}^{TPC}"}, {dedxAxis}, {pAxis}}); + registryDeDx.add(kNclTPCDedxMomentumNegAfter[i].data(), "Ncl TPC vs dE/dx vs Momentum Negative after", HistType::kTH3F, + {{100, 0, 160, "N_{cl}^{TPC}"}, {dedxAxis}, {pAxis}}); + } + } + } + + // Ncl vs de/dx ITS + if (nITSClCut) { + for (int i = 0; i < kEtaIntervals; ++i) { + registryDeDx.add(kNclITSDedxMomentumPosBefore[i].data(), "Ncl ITS vs dE/dx vs Momentum Positive before", HistType::kTH3F, + {{100, 0, 160, "N_{cl}^{ITS}"}, {dedxAxis}, {pAxis}}); + registryDeDx.add(kNclITSDedxMomentumNegBefore[i].data(), "Ncl ITS vs dE/dx vs Momentum Negative before", HistType::kTH3F, + {{100, 0, 160, "N_{cl}^{ITS}"}, {dedxAxis}, {pAxis}}); + + registryDeDx.add(kNclITSDedxMomentumPosAfter[i].data(), "Ncl ITS vs dE/dx vs Momentum Positive after", HistType::kTH3F, + {{100, 0, 160, "N_{cl}^{ITS}"}, {dedxAxis}, {pAxis}}); + registryDeDx.add(kNclITSDedxMomentumNegAfter[i].data(), "Ncl ITS vs dE/dx vs Momentum Negative after", HistType::kTH3F, + {{100, 0, 160, "N_{cl}^{ITS}"}, {dedxAxis}, {pAxis}}); + } + } + + // beta plot + 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)"}}); + + // Event Counter + registryDeDx.add("evsel", "events selected", HistType::kTH1F, {{3, 0.5, 3.5, ""}}); + auto hstat = registryDeDx.get(HIST("evsel")); + auto* x = hstat->GetXaxis(); + x->SetBinLabel(1, "AllEv"); + x->SetBinLabel(2, "SelEigth"); + x->SetBinLabel(3, "ZVtxCut"); + + // Track Counter + registryDeDx.add("trackselAll", "track selected all particles", HistType::kTH1F, {{5, 0.5, 5.5, ""}}); + auto htrackAll = registryDeDx.get(HIST("trackselAll")); + auto* xAll = htrackAll->GetXaxis(); + xAll->SetBinLabel(1, "AllPri"); + xAll->SetBinLabel(2, "SelectionPrim"); + xAll->SetBinLabel(3, "PhiVarCutPri"); + xAll->SetBinLabel(4, "NTPCClCutPri"); + xAll->SetBinLabel(5, "NITSClCutPri"); + + registryDeDx.add("trackselSec", "track selected sec particles", HistType::kTH1F, {{13, 0.5, 13.5, ""}}); + auto htrackSec = registryDeDx.get(HIST("trackselSec")); + auto* xSec = htrackSec->GetXaxis(); + xSec->SetBinLabel(1, "AllSec"); + xSec->SetBinLabel(2, "V0CosPA"); + xSec->SetBinLabel(3, "V0DecayRadius"); + xSec->SetBinLabel(4, "V0Daughters"); + xSec->SetBinLabel(5, "TPCRefit"); + xSec->SetBinLabel(6, "PhiVarCutSec"); + xSec->SetBinLabel(7, "NTPCClCutSec"); + xSec->SetBinLabel(8, "NITSClCutSec"); + xSec->SetBinLabel(9, "V0RapidityK0s"); + xSec->SetBinLabel(10, "V0ProperLifetimeK0s"); + xSec->SetBinLabel(11, "V0RapidityLambda"); + xSec->SetBinLabel(12, "V0ProperLifetimeLambda"); + xSec->SetBinLabel(13, "V0RapidityAntiLambda"); + xSec->SetBinLabel(14, "V0ProperLifetimeAntiLambda"); + + mySelectionPrim = myTrackSelection(); + } + + // Single-Track Selection + template + bool passedSingleTrackSelection(const T1& track, const C& /*collision*/) + { + // Single-Track Selections + 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; + } + + // General V0 Selections + template + bool passedV0Selection(const T1& v0, const C& /*collision*/) + { + if (v0.v0cosPA() < v0cospaMin) + return false; + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0CosPA); + + if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius) + return false; + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0DecayRadius); + + if (v0.dcaV0daughters() > dcaV0DaughtersMax) + return false; + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0Daughters); + + 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() > tpcCut) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(ptrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > tpcCut) { + 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() > tpcCut) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(ptrack.tofNSigmaPr()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > tpcCut) { + 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() > tpcCut) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(ptrack.tofNSigmaPi()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > tpcCut) { + 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() > tpcCut) { + if (!ptrack.hasTOF()) + return false; + if (std::abs(ptrack.tofNSigmaEl()) > nsigmaTOFmax) + return false; + } + + if (ntrack.tpcInnerParam() > tpcCut) { + 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; + } + // Magnetic field + int getMagneticField(uint64_t timestamp) + { + 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(); + } + + // Phi cut + template + bool passedPhiVarCut(const T& trk, float magField, const TF1& fphiCutLow, const TF1& fphiCutHigh) + { + float pt = trk.pt(); + float phi = trk.phi(); + int charge = trk.sign(); + float eta = trk.eta(); + float sigP = trk.sign() * trk.tpcInnerParam(); + auto nTPCCl = trk.tpcNClsFound(); + + if (pt < pTcut) + return true; + + if (magField < 0) // for negatve polarity field + phi = o2::constants::math::TwoPI - phi; + if (charge < 0) // for negatve charge + phi = o2::constants::math::TwoPI - phi; + + // to center gap in the middle + phi += o2::constants::math::PI / 18.0f; + phi = std::fmod(phi, o2::constants::math::PI / 9.0f); + + registryDeDx.fill(HIST("hpt_vs_phi_Ncl_TPC_Before"), pt, phi, nTPCCl); + + // cut phi + if (phi < fphiCutHigh.Eval(pt) && phi > fphiCutLow.Eval(pt)) + return false; // reject track + + if (eta > EtaCut[0] && eta < EtaCut[1]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[0]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[0]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[1] && eta < EtaCut[2]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[1]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[1]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[2] && eta < EtaCut[3]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[2]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[2]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[3] && eta < EtaCut[4]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[3]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[3]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[4] && eta < EtaCut[5]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[4]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[4]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[5] && eta < EtaCut[6]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[5]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[5]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[6] && eta < EtaCut[7]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[6]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[6]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[7] && eta < EtaCut[8]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegBefore[7]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosBefore[7]), nTPCCl, trk.tpcSignal(), sigP); + } + } + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::PhiVarCutPri); + + if (nTPCClCut) { + // cut Ncl + if (nTPCCl < minTPCnClsFound) + return false; + + registryDeDx.fill(HIST("hpt_vs_phi_Ncl_TPC_After"), pt, phi, nTPCCl); + + if (eta > EtaCut[0] && eta < EtaCut[1]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[0]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[0]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[1] && eta < EtaCut[2]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[1]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[1]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[2] && eta < EtaCut[3]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[2]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[2]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[3] && eta < EtaCut[4]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[3]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[3]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[4] && eta < EtaCut[5]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[4]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[4]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[5] && eta < EtaCut[6]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[5]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[5]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[6] && eta < EtaCut[7]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[6]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[6]), nTPCCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[7] && eta < EtaCut[8]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclTPCDedxMomentumNegAfter[7]), nTPCCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclTPCDedxMomentumPosAfter[7]), nTPCCl, trk.tpcSignal(), sigP); + } + } + } + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::NTPCClCutPri); + return true; + } + + // NclCutITS + template + bool passedNITSClCut(const T& trk) + { + float eta = trk.eta(); + float sigP = trk.sign() * trk.tpcInnerParam(); + auto nITSCl = trk.itsNCls(); + + if (eta > EtaCut[0] && eta < EtaCut[1]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegBefore[0]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosBefore[0]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[1] && eta < EtaCut[2]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegBefore[1]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosBefore[1]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[2] && eta < EtaCut[3]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegBefore[2]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosBefore[2]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[3] && eta < EtaCut[4]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegBefore[3]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosBefore[3]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[4] && eta < EtaCut[5]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegBefore[4]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosBefore[4]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[5] && eta < EtaCut[6]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegBefore[5]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosBefore[5]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[6] && eta < EtaCut[7]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegBefore[6]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosBefore[6]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[7] && eta < EtaCut[8]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegBefore[7]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosBefore[7]), nITSCl, trk.tpcSignal(), sigP); + } + } + + if (nITSCl < minITSnCls) + return false; + + if (eta > EtaCut[0] && eta < EtaCut[1]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegAfter[0]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosAfter[0]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[1] && eta < EtaCut[2]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegAfter[1]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosAfter[1]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[2] && eta < EtaCut[3]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegAfter[2]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosAfter[2]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[3] && eta < EtaCut[4]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegAfter[3]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosAfter[3]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[4] && eta < EtaCut[5]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegAfter[4]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosAfter[4]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[5] && eta < EtaCut[6]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegAfter[5]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosAfter[5]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[6] && eta < EtaCut[7]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegAfter[6]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosAfter[6]), nITSCl, trk.tpcSignal(), sigP); + } + } else if (eta > EtaCut[7] && eta < EtaCut[8]) { + if (sigP < 0) { + registryDeDx.fill(HIST(kNclITSDedxMomentumNegAfter[7]), nITSCl, trk.tpcSignal(), std::abs(sigP)); + } else { + registryDeDx.fill(HIST(kNclITSDedxMomentumPosAfter[7]), nITSCl, trk.tpcSignal(), sigP); + } + } + + return true; + } + + // Phi cut Secondaries + template + bool passedPhiCutSecondaries(const T& trk, float magField, const TF1& fphiCutLow, const TF1& fphiCutHigh) + { + float pt = trk.pt(); + float phi = trk.phi(); + int charge = trk.sign(); + + if (pt < pTcut) + return true; + + if (magField < 0) // for negatve polarity field + phi = o2::constants::math::TwoPI - phi; + if (charge < 0) // for negatve charge + phi = o2::constants::math::TwoPI - phi; + + // to center gap in the middle + phi += o2::constants::math::PI / 18.0f; + phi = std::fmod(phi, o2::constants::math::PI / 9.0f); + + // cut phi + if (phi < fphiCutHigh.Eval(pt) && phi > fphiCutLow.Eval(pt)) + return false; // reject track + + return true; + } + + // NclCutTPC + template + bool passedNTPCClCutSecondaries(const T& trk) + { + auto nTPCCl = trk.tpcNClsFound(); + + if (nTPCCl < minTPCnClsFound) + return false; + + return true; + } + + // NclCutITS primary + template + bool passedNITSClCutSecondaries(const T& trk) + { + auto nITSCl = trk.itsNCls(); + + if (nITSCl < minITSnCls) + return false; + + return true; + } + + // Process Data + void process(SelectedCollisions::iterator const& collision, + aod::V0Datas const& fullV0s, PIDTracks const& tracks) + { + registryDeDx.fill(HIST("evsel"), EvCutLabel::AllEv); + // Event Selection + if (!collision.sel8()) + return; + + registryDeDx.fill(HIST("evsel"), EvCutLabel::SelEigth); + + if (std::abs(collision.posZ()) > maxZDistanceToIP) + return; + + registryDeDx.fill(HIST("evsel"), EvCutLabel::ZVtxCut); + + // Event Counter + registryDeDx.fill(HIST("histRecVtxZData"), collision.posZ()); + + // For magnetic field + const auto& foundBC = collision.foundBC_as(); + const uint64_t timeStamp{foundBC.timestamp()}; + const int magField{getMagneticField(timeStamp)}; + + for (const auto& trk : tracks) { + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::AllPri); + // track Selection + if (!mySelectionPrim.IsSelected(trk)) + continue; + + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::SelectionPrim); + + // phi and Ncl cut + if (phiVarCut) { + if (!passedPhiVarCut(trk, magField, *fphiCutLow, *fphiCutHigh)) + continue; + } + + // NCl cut ITS + if (nITSClCut) { + if (!passedNITSClCut(trk)) + continue; + } + registryDeDx.fill(HIST("trackselAll"), TrkPriCutLabel::NITSClCutPri); + + float signedP = trk.sign() * trk.tpcInnerParam(); + + // MIP calibration for pions + if (trk.tpcInnerParam() >= pionMin && trk.tpcInnerParam() <= pionMax) { + 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 < kEtaIntervals; ++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) < elTofCut) { // 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 < kEtaIntervals; ++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() > pionTofCut && trk.beta() < pionTofCut + 0.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 < kEtaIntervals; ++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 < kEtaIntervals; ++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()); + registryDeDx.fill(HIST("heta_vs_p_vs_pt_all_Pos"), trk.eta(), trk.pt(), signedP); + } else { + registryDeDx.fill(HIST(kDedxvsMomentumNeg[0]), std::abs(signedP), trk.tpcSignal() * 50 / calibrationFactorNeg->at(i), trk.eta()); + registryDeDx.fill(HIST("heta_vs_p_vs_pt_all_Neg"), trk.eta(), trk.pt(), std::abs(signedP)); + } + } + } + } + } + + // Loop over Reconstructed V0s + if (!calibrationMode) { + for (const auto& v0 : fullV0s) { + + // Standard V0 Selections + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::AllSec); + if (!passedV0Selection(v0, collision)) { + 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; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::TPCRefit); + // phi and Ncl cut + if (phiVarCut) { + if (!passedPhiCutSecondaries(posTrack, magField, *fphiCutLow, *fphiCutHigh)) + continue; + + if (!passedPhiCutSecondaries(negTrack, magField, *fphiCutLow, *fphiCutHigh)) + continue; + } + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel ::PhiVarCutSec); + + if (nTPCClCut) { + if (!passedNTPCClCutSecondaries(posTrack)) + continue; + + if (!passedNTPCClCutSecondaries(negTrack)) + continue; + } + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel ::NTPCClCutSec); + + if (nITSClCut) { + if (!passedNITSClCutSecondaries(posTrack)) + continue; + + if (!passedNITSClCutSecondaries(negTrack)) + continue; + } + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel ::NITSClCutSec); + + 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)) { + + if (std::abs(v0.rapidity(MassK0Short)) > v0rapidityCut) + continue; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityK0s); + float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassK0Short; + + if (properLifetime > v0ProperLifetimeCutK0s) + continue; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeK0s); + + 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) > invMassCut) { + continue; + } + + for (int i = 0; i < kEtaIntervals; ++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)) { + + if (std::abs(v0.rapidity(MassLambda)) > v0rapidityCut) + continue; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityLambda); + float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda; + + if (properLifetime > v0ProperLifetimeCutLambda) + continue; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeLambda); + + 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) > invMassCut) { + continue; + } + + for (int i = 0; i < kEtaIntervals; ++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)) { + + if (std::abs(v0.rapidity(MassLambda)) > v0rapidityCut) + continue; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0RapidityAntiLambda); + float properLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda; + + if (properLifetime > v0ProperLifetimeCutLambda) + continue; + + registryDeDx.fill(HIST("trackselSec"), TrkSecCutLabel::V0ProperLifetimeAntiLambda); + + 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) > invMassCut) { + continue; + } + + for (int i = 0; i < kEtaIntervals; ++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) > invMassCutGamma) { + continue; + } + + for (int i = 0; i < kEtaIntervals; ++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..3a4bb9a2843 --- /dev/null +++ b/PWGMM/UE/Tasks/dedx_analysys.cxx @@ -0,0 +1,569 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.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/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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/lambdak0sflattenicity.cxx b/PWGMM/UE/Tasks/lambdak0sflattenicity.cxx deleted file mode 100755 index f949a2fbed4..00000000000 --- a/PWGMM/UE/Tasks/lambdak0sflattenicity.cxx +++ /dev/null @@ -1,1051 +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. -/// -/// 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 -/// For any suggestions, commets or questions, Please write to Suraj Prasad (Suraj.Prasad@cern.ch) - -#include -#include - -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" -#include "Framework/runDataProcessing.h" - -#include "ReconstructionDataFormats/Track.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/TrackSelectionTables.h" - -#include - -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "Common/DataModel/PIDResponse.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -struct lambdak0sflattenicity { - // Histograms are defined with HistogramRegistry - 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 rFlattenicity{"flattenicity", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - - static constexpr std::string_view nhEst[8] = { - "eGlobaltrack", "eFV0", "e1flatencityFV0", "eFT0", "e1flatencityFT0", "eFV0FT0C", "e1flatencityFV0FT0C", "ePtTrig"}; - static constexpr std::string_view tEst[8] = { - "GlobalTrk", "FV0", "1-flatencity_FV0", "FT0", "1-flatencityFT0", "FV0_FT0C", "1-flatencity_FV0_FT0C", "PtTrig"}; - static constexpr std::string_view nhPtEst[8] = { - "ptVsGlobaltrack", "ptVsFV0", "ptVs1flatencityFV0", "ptVsFT0", "ptVs1flatencityFT0", "ptVsFV0FT0C", "ptVs1flatencityFV0FT0C", "pTVsPtTrig"}; - - // Configurable for histograms - Configurable nBinsVz{"nBinsVz", 100, "N bins in Vz"}; - Configurable nBinsK0sMass{"nBinsK0sMass", 200, "N bins in K0sMass"}; - Configurable nBinsLambdaMass{"nBinsLambdaMass", 200, "N bins in LambdaMass"}; - Configurable nBinspT{"nBinspT", 250, "N bins in pT"}; - - // Configurable for event selection - Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; - - // Configurables for Flattenicity - Configurable applyCalibCh{"applyCalibCh", false, "equalize FV0"}; - Configurable applyCalibVtx{"applyCalibVtx", false, "equalize FV0 vs vtx"}; - Configurable applyNorm{"applyNorm", false, "normalization to eta"}; - - // Common Configurable parameters for V0 selection - Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 1, "DCA 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 parameters for V0 selection for KOs - Configurable v0setting_cospaK0s{"v0setting_cospa_K0s", 0.97, "V0 CosPA for K0s"}; - Configurable v0setting_radiusK0s{"v0setting_radius_K0s", 0.5, "v0radius for K0s"}; - Configurable v0setting_ctauK0s{"v0setting_ctau_K0s", 20, "v0ctau for K0s"}; - - // Configurable parameters for V0 selection for Lambda - Configurable v0setting_cospaLambda{"v0setting_cospa_Lambda", 0.995, "V0 CosPA for Lambda"}; - Configurable v0setting_radiusLambda{"v0setting_radius_Lambda", 0.5, "v0radius for Lambda"}; - Configurable v0setting_ctauLambda{"v0setting_ctau_Lambda", 30, "v0ctau for Lambda"}; - - // Configurable parameters for PID selection - Configurable NSigmaTPCPion{"NSigmaTPCPion", 5, "NSigmaTPCPion"}; - Configurable NSigmaTPCProton{"NSigmaTPCProton", 5, "NSigmaTPCProton"}; - - // Configurable v0daughter_etacut{"V0DaughterEtaCut", 0.8, "V0DaughterEtaCut"}; - Configurable v0_etacut{"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"}; - - void init(InitContext const&) - { - // Axes - AxisSpec K0sMassAxis = {nBinsK0sMass, 0.45f, 0.55f, "#it{M}_{#pi^{+}#pi^{-}} [GeV/#it{c}^{2}]"}; - AxisSpec LambdaMassAxis = {nBinsLambdaMass, 1.015f, 1.215f, "#it{M}_{p#pi^{-}} [GeV/#it{c}^{2}]"}; - AxisSpec AntiLambdaMassAxis = {nBinsLambdaMass, 1.015f, 1.215f, "#it{M}_{#pi^{+}#bar{p}} [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})"}; - - 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::kTH1F, {vertexZAxis}}); - rEventSelection.add("hEventsRejected", "hEventsRejected", {HistType::kTH1F, {{11, -0.5, 10.5}}}); - rEventSelection.add("hEventsSelected", "hEventsSelected", {HistType::kTH1F, {{11, -0.5, 10.5}}}); - - if (doprocessGenMC) { - rEventSelection.add("hVertexZGen", "hVertexZGen", {HistType::kTH1F, {vertexZAxis}}); - rEventSelection.add("hEventSelectionMCGen", "hEventSelectionMCGen", {HistType::kTH1F, {{11, -0.5, 10.5}}}); - } - // K0s reconstruction - // Mass - rKzeroShort.add("hMassK0s", "hMassK0s", {HistType::kTH1F, {K0sMassAxis}}); - rKzeroShort.add("hMassK0sSelected", "hMassK0sSelected", {HistType::kTH1F, {K0sMassAxis}}); - - // K0s topological/PID cuts - rKzeroShort.add("hrapidityK0s", "hrapidityK0s", {HistType::kTH1F, {{40, -2.0f, 2.0f, "y"}}}); - rKzeroShort.add("hctauK0s", "hctauK0s", {HistType::kTH1F, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); - rKzeroShort.add("h2DdecayRadiusK0s", "h2DdecayRadiusK0s", {HistType::kTH1F, {{100, 0.0f, 1.0f, "Decay Radius (cm)"}}}); - rKzeroShort.add("hDCAV0DaughtersK0s", "hDCAV0DaughtersK0s", {HistType::kTH1F, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); - rKzeroShort.add("hV0CosPAK0s", "hV0CosPAK0s", {HistType::kTH1F, {{100, 0.95f, 1.f, "CosPA"}}}); - rKzeroShort.add("hNSigmaPosPionFromK0s", "hNSigmaPosPionFromK0s", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); - rKzeroShort.add("hNSigmaNegPionFromK0s", "hNSigmaNegPionFromK0s", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); - rKzeroShort.add("hMassK0spT", "hMassK0spT", {HistType::kTH2F, {{K0sMassAxis}, {ptAxis}}}); - - if (doprocessGenMC) { - rKzeroShort.add("hPtK0ShortGen", "hPtK0ShortGen", {HistType::kTH1F, {ptAxis}}); - rKzeroShort.add("K0sCounterMCGen", "K0sCounterMCGen", {HistType::kTH1F, {{10, 0, 10}}}); - } - // Lambda reconstruction - // Mass - rLambda.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {LambdaMassAxis}}); - rLambda.add("hMassLambdaSelected", "hMassLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); - - // Lambda topological/PID cuts - rLambda.add("hDCAV0DaughtersLambda", "hDCAV0DaughtersLambda", {HistType::kTH1F, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); - rLambda.add("hV0CosPALambda", "hV0CosPALambda", {HistType::kTH1F, {{100, 0.95f, 1.f, "CosPA"}}}); - rLambda.add("hNSigmaPosPionFromLambda", "hNSigmaPosPionFromLambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); - rLambda.add("hNSigmaNegPionFromLambda", "hNSigmaNegPionFromLambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); - rLambda.add("hrapidityLambda", "hrapidityLambda", {HistType::kTH1F, {{40, -2.0f, 2.0f, "y"}}}); - rLambda.add("hctauLambda", "hctauLambda", {HistType::kTH1F, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); - rLambda.add("h2DdecayRadiusLambda", "h2DdecayRadiusLambda", {HistType::kTH1F, {{100, 0.0f, 1.0f, "c#tau (cm)"}}}); - rLambda.add("hMassLambdapT", "hMassLambdapT", {HistType::kTH2F, {{LambdaMassAxis}, {ptAxis}}}); - - if (doprocessGenMC) { - rLambda.add("hPtLambdaGen", "hPtLambdaGen", {HistType::kTH1F, {ptAxis}}); - rLambda.add("LambdaCounterMCGen", "LambdaCounterMCGen", {HistType::kTH1F, {{10, 0, 10}}}); - } - // AntiLambda reconstruction - // Mass - rAntiLambda.add("hMassAntiLambda", "hMassAntiLambda", {HistType::kTH1F, {AntiLambdaMassAxis}}); - rAntiLambda.add("hMassAntiLambdaSelected", "hMassAntiLambdaSelected", {HistType::kTH1F, {AntiLambdaMassAxis}}); - - // AntiLambda topological/PID cuts - rAntiLambda.add("hDCAV0DaughtersAntiLambda", "hDCAV0DaughtersAntiLambda", {HistType::kTH1F, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); - rAntiLambda.add("hV0CosPAAntiLambda", "hV0CosPAAntiLambda", {HistType::kTH1F, {{100, 0.95f, 1.f, "CosPA"}}}); - rAntiLambda.add("hNSigmaPosPionFromAntiLambda", "hNSigmaPosPionFromAntiLambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); - rAntiLambda.add("hNSigmaNegPionFromAntiLambda", "hNSigmaNegPionFromAntiLambda", {HistType::kTH2F, {{100, -5.f, 5.f}, {ptAxis}}}); - rAntiLambda.add("hrapidityAntiLambda", "hrapidityAntiLambda", {HistType::kTH1F, {{40, -2.0f, 2.0f, "y"}}}); - rAntiLambda.add("hctauAntiLambda", "hctauAntiLambda", {HistType::kTH1F, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); - rAntiLambda.add("h2DdecayRadiusAntiLambda", "h2DdecayRadiusAntiLambda", {HistType::kTH1F, {{100, 0.0f, 1.0f, "c#tau (cm)"}}}); - rAntiLambda.add("hMassAntiLambdapT", "hMassAntiLambdapT", {HistType::kTH2F, {{AntiLambdaMassAxis}, {ptAxis}}}); - - if (doprocessGenMC) { - rAntiLambda.add("hPtAntiLambdaGen", "hPtAntiLambdaGen", {HistType::kTH1F, {ptAxis}}); - rAntiLambda.add("AntiLambdaCounterMCGen", "AntiLambdaCounterMCGen", {HistType::kTH1F, {{10, 0, 10}}}); - } - - rFlattenicity.add("hEv", "Ev", HistType::kTH1F, {{6, -0.5, 5.5, "index activated detector"}}); - rFlattenicity.add("hFV0amplRing1to4", "FV01to4", HistType::kTH1F, {{4000, -0.5, +49999.5, "FV0 amplitude"}}); - rFlattenicity.add("hFT0Aampl", "FTAampl", HistType::kTH1F, {{50000, -0.5, +199999.5, "FT0A amplitude"}}); - rFlattenicity.add("hFT0Campl", "FTCampl", HistType::kTH1F, {{10000, -0.5, +4999.5, "FT0C amplitude"}}); - rFlattenicity.add("hFT0C", "FT0C", HistType::kTH1F, {{50000, -0.5, 199999.5, "FT0C amplitudes"}}); - rFlattenicity.add("hFT0A", "FT0A", HistType::kTH1F, {{2000, -0.5, 1999.5, "FT0A amplitudes"}}); - - // estimators - for (int i_e = 0; i_e < 8; ++i_e) { - rFlattenicity.add( - nhEst[i_e].data(), "", HistType::kTH2F, {{nBinsEst[i_e], lowEdgeEst[i_e], upEdgeEst[i_e], tEst[i_e].data()}, {100, -0.5, +99.5, "Global track"}}); - } - - // vs pT - for (int i_e = 0; i_e < 8; ++i_e) { - rFlattenicity.add(nhPtEst[i_e].data(), "", HistType::kTProfile, {{nBinsEst[i_e], lowEdgeEst[i_e], upEdgeEst[i_e], tEst[i_e].data()}}); - } - - rFlattenicity.add("fMultFv0", "FV0 amp", HistType::kTH1F, {{5000, -0.5, +199999.5, "FV0 amplitude"}}); - rFlattenicity.add("hAmpV0VsCh", "", HistType::kTH2F, {{48, -0.5, 47.5, "channel"}, {500, -0.5, +19999.5, "FV0 amplitude"}}); - rFlattenicity.add("hAmpV0VsChBeforeCalibration", "", HistType::kTH2F, {{48, -0.5, 47.5, "channel"}, {500, -0.5, +19999.5, "FV0 amplitude"}}); - - rFlattenicity.add("hAmpT0AVsChBeforeCalibration", "", HistType::kTH2F, {{24, -0.5, 23.5, "channel"}, {600, -0.5, +5999.5, "FT0A amplitude"}}); - rFlattenicity.add("hAmpT0CVsChBeforeCalibration", "", HistType::kTH2F, {{28, -0.5, 27.5, "channel"}, {600, -0.5, +5999.5, "FT0C amplitude"}}); - - rFlattenicity.add("hAmpT0AVsCh", "", HistType::kTH2F, {{24, -0.5, 23.5, "channel"}, {600, -0.5, +5999.5, "FT0A amplitude"}}); - rFlattenicity.add("hAmpT0CVsCh", "", HistType::kTH2F, {{28, -0.5, 27.5, "channel"}, {600, -0.5, +5999.5, "FT0C amplitude"}}); - - rFlattenicity.add("hFlatFT0CvsFlatFT0A", "", HistType::kTH2F, {{20, -0.01, +1.01, "flatenicity (FT0C)"}, {20, -0.01, +1.01, "flatenicity (FT0A)"}}); - rFlattenicity.add("fEtaPhiFv0", "eta vs phi", HistType::kTH2F, {{8, 0.0, 2 * M_PI, "#phi (rad)"}, {5, 2.2, 5.1, "#eta"}}); - - rFlattenicity.add("hAmpV0vsVtxBeforeCalibration", "", HistType::kTH2F, {{30, -15.0, +15.0, "Trk mult"}, {1000, -0.5, +39999.5, "FV0 amplitude"}}); - rFlattenicity.add("hAmpT0AvsVtxBeforeCalibration", "", HistType::kTH2F, {{30, -15.0, +15.0, "Vtx_z"}, {600, -0.5, +5999.5, "FT0A amplitude"}}); - rFlattenicity.add("hAmpT0CvsVtxBeforeCalibration", "", HistType::kTH2F, {{30, -15.0, +15.0, "Vtx_z"}, {600, -0.5, +5999.5, "FT0C amplitude"}}); - - rFlattenicity.add("hAmpV0vsVtx", "", HistType::kTH2F, {{30, -15.0, +15.0, "Trk mult"}, {1000, -0.5, +39999.5, "FV0 amplitude"}}); - rFlattenicity.add("hAmpT0AvsVtx", "", HistType::kTH2F, {{30, -15.0, +15.0, "Vtx_z"}, {600, -0.5, +5999.5, "FT0A amplitude"}}); - rFlattenicity.add("hAmpT0CvsVtx", "", HistType::kTH2F, {{30, -15.0, +15.0, "Vtx_z"}, {600, -0.5, +5999.5, "FT0C amplitude"}}); - - if (doprocessDataRun3 && (doprocessRecMC || doprocessGenMC)) { - LOGF(fatal, "Both Data and MC are both set to true; try again with only one of them set to true"); - } - if (!doprocessDataRun3 && !(doprocessRecMC || doprocessGenMC)) { - LOGF(fatal, "Both Data and MC set to false; try again with only one of them set to false"); - } - if ((doprocessRecMC && !doprocessGenMC) || (!doprocessRecMC && doprocessGenMC)) { - LOGF(fatal, "MCRec and MCGen are set to opposite switches, try again with both set to either true or false"); - } - } - - int getT0ASector(int i_ch) - { - int i_sec_t0a = -1; - for (int i_sec = 0; i_sec < 24; ++i_sec) { - if (i_ch >= 4 * i_sec && i_ch <= 3 + 4 * i_sec) { - i_sec_t0a = i_sec; - break; - } - } - return i_sec_t0a; - } - - int getT0CSector(int i_ch) - { - int i_sec_t0c = -1; - for (int i_sec = 0; i_sec < 28; ++i_sec) { - if (i_ch >= 4 * i_sec && i_ch <= 3 + 4 * i_sec) { - i_sec_t0c = i_sec; - break; - } - } - return i_sec_t0c; - } - - int getFV0Ring(int i_ch) - { - int i_ring = -1; - if (i_ch < 8) { - i_ring = 0; - } else if (i_ch >= 8 && i_ch < 16) { - i_ring = 1; - } else if (i_ch >= 16 && i_ch < 24) { - i_ring = 2; - } else if (i_ch >= 24 && i_ch < 32) { - i_ring = 3; - } else { - i_ring = 4; - } - return i_ring; - } - - int getFV0IndexPhi(int i_ch) - { - int i_ring = -1; - - if (i_ch >= 0 && i_ch < 8) { - if (i_ch < 4) { - i_ring = i_ch; - } else { - if (i_ch == 7) { - i_ring = 4; - } else if (i_ch == 6) { - i_ring = 5; - } else if (i_ch == 5) { - i_ring = 6; - } else if (i_ch == 4) { - i_ring = 7; - } - } - } else if (i_ch >= 8 && i_ch < 16) { - if (i_ch < 12) { - i_ring = i_ch; - } else { - if (i_ch == 15) { - i_ring = 12; - } else if (i_ch == 14) { - i_ring = 13; - } else if (i_ch == 13) { - i_ring = 14; - } else if (i_ch == 12) { - i_ring = 15; - } - } - } else if (i_ch >= 16 && i_ch < 24) { - if (i_ch < 20) { - i_ring = i_ch; - } else { - if (i_ch == 23) { - i_ring = 20; - } else if (i_ch == 22) { - i_ring = 21; - } else if (i_ch == 21) { - i_ring = 22; - } else if (i_ch == 20) { - i_ring = 23; - } - } - } else if (i_ch >= 24 && i_ch < 32) { - if (i_ch < 28) { - i_ring = i_ch; - } else { - if (i_ch == 31) { - i_ring = 28; - } else if (i_ch == 30) { - i_ring = 29; - } else if (i_ch == 29) { - i_ring = 30; - } else if (i_ch == 28) { - i_ring = 31; - } - } - } else if (i_ch == 32) { - i_ring = 32; - } else if (i_ch == 40) { - i_ring = 33; - } else if (i_ch == 33) { - i_ring = 34; - } else if (i_ch == 41) { - i_ring = 35; - } else if (i_ch == 34) { - i_ring = 36; - } else if (i_ch == 42) { - i_ring = 37; - } else if (i_ch == 35) { - i_ring = 38; - } else if (i_ch == 43) { - i_ring = 39; - } else if (i_ch == 47) { - i_ring = 40; - } else if (i_ch == 39) { - i_ring = 41; - } else if (i_ch == 46) { - i_ring = 42; - } else if (i_ch == 38) { - i_ring = 43; - } else if (i_ch == 45) { - i_ring = 44; - } else if (i_ch == 37) { - i_ring = 45; - } else if (i_ch == 44) { - i_ring = 46; - } else if (i_ch == 36) { - i_ring = 47; - } - return i_ring; - } - - 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 sRho_tmp = 0; - for (int iCell = 0; iCell < entries; ++iCell) { - sRho_tmp += TMath::Power(1.0 * signals[iCell] - mRho, 2); - } - sRho_tmp /= (1.0 * entries * entries); - float sRho = TMath::Sqrt(sRho_tmp); - if (mRho > 0) { - flat = sRho / mRho; - } - return flat; - } - float pdgmassK0s = 0.497614; - float pdgmassLambda = 1.115683; - // V0A signal and flatenicity calculation - static constexpr float calib[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 calibT0C[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 calibT0A[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 biningVtxt[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 calibFV0vtx[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 calibFT0Avtx[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 calibFT0Cvtx[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 nEta5 = 2; // FT0C + FT0A - static constexpr float weigthsEta5[nEta5] = {0.0490638, 0.010958415}; - static constexpr float deltaEeta5[nEta5] = {1.1, 1.2}; - - static constexpr int nEta6 = 2; // FT0C + FV0 - static constexpr float weigthsEta6[nEta6] = {0.0490638, 0.00353962}; - static constexpr float deltaEeta6[nEta6] = {1.1, 2.9}; - - static constexpr int innerFV0 = 32; - static constexpr float maxEtaFV0 = 5.1; - static constexpr float minEtaFV0 = 2.2; - static constexpr float detaFV0 = (maxEtaFV0 - minEtaFV0) / 5.0; - - static constexpr int nCells = 48; // 48 sectors in FV0 - std::array RhoLattice; - std::array ampchannel; - std::array ampchannelBefore; - static constexpr int nCellsT0A = 24; - std::array RhoLatticeT0A; - static constexpr int nCellsT0C = 28; - std::array RhoLatticeT0C; - - std::array estimator; - - template - bool isEventSelected(TCollision const& collision) - { - rEventSelection.fill(HIST("hEventsSelected"), 0); - - if (collision.isInelGt0() == false) { - rEventSelection.fill(HIST("hEventsRejected"), 1); - return false; - } - rEventSelection.fill(HIST("hEventsSelected"), 1); - - if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - rEventSelection.fill(HIST("hEventsRejected"), 2); - return false; - } - rEventSelection.fill(HIST("hEventsSelected"), 2); - - if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - rEventSelection.fill(HIST("hEventsRejected"), 3); - return false; - } - rEventSelection.fill(HIST("hEventsSelected"), 3); - - if (!collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - rEventSelection.fill(HIST("hEventsRejected"), 4); - return false; - } - rEventSelection.fill(HIST("hEventsSelected"), 4); - - if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - rEventSelection.fill(HIST("hEventsRejected"), 5); - return false; - } - rEventSelection.fill(HIST("hEventsSelected"), 5); - - if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - rEventSelection.fill(HIST("hEventsRejected"), 6); - return false; - } - rEventSelection.fill(HIST("hEventsSelected"), 6); - - return true; - } - - // ============== Flattenicity estimation begins ===================== // - template - void EstimateFlattenicity(TCollision const& collision, Tracks const& tracks) - { - const int nDetVtx = 3; - TGraph* gVtx[nDetVtx]; - const char* nameDet[nDetVtx] = {"AmpV0", "AmpT0A", "AmpT0C"}; - - float ampl5[nEta5] = {0, 0}; - float ampl6[nEta6] = {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, biningVtxt[i_v], calibFV0vtx[i_v]); - } - for (int i_v = 0; i_v < 30; ++i_v) { - gVtx[1]->SetPoint(i_v, biningVtxt[i_v], calibFT0Avtx[i_v]); - } - for (int i_v = 0; i_v < 30; ++i_v) { - gVtx[2]->SetPoint(i_v, biningVtxt[i_v], calibFT0Cvtx[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 (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 ampl_ch = fv0.amplitude()[ich]; - int ringindex = getFV0Ring(channelv0); - int channelv0phi = getFV0IndexPhi(channelv0); - etav0 = maxEtaFV0 - (detaFV0 / 2.0) * (2.0 * ringindex + 1); - if (channelv0 < innerFV0) { - phiv0 = (2.0 * (channelv0phi - 8 * ringindex) + 1) * M_PI / (8.0); - } else { - phiv0 = ((2.0 * channelv0phi) + 1 - 64.0) * 2.0 * M_PI / (32.0); - } - ampchannelBefore[channelv0phi] = ampl_ch; - if (applyCalibCh) { - ampl_ch *= calib[channelv0phi]; - } - sumAmpFV0 += ampl_ch; - - if (channelv0 >= 8) { // exclude the 1st ch, eta 2.2,4.52 - sumAmpFV01to4Ch += ampl_ch; - } - rFlattenicity.fill(HIST("fEtaPhiFv0"), phiv0, etav0, ampl_ch); - ampchannel[channelv0phi] = ampl_ch; - if (channelv0 < innerFV0) { - RhoLattice[channelv0phi] = ampl_ch; - } else { - RhoLattice[channelv0phi] = ampl_ch / 2.0; // two channels per bin - } - } - - rFlattenicity.fill(HIST("hAmpV0vsVtxBeforeCalibration"), vtxZ, sumAmpFV0); - if (applyCalibVtx) { - sumAmpFV0 *= gVtx[0]->Eval(vtxZ); - sumAmpFV01to4Ch *= gVtx[0]->Eval(vtxZ); - } - rFlattenicity.fill(HIST("hAmpV0vsVtx"), vtxZ, sumAmpFV0); - } - - float flattenicityfv0 = 9999; - flattenicityfv0 = GetFlatenicity({RhoLattice.data(), RhoLattice.size()}); - - // global tracks - float ptT = 0.; - int multGlob = 0; - for (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 (collision.has_foundFT0()) { - auto ft0 = collision.foundFT0(); - 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; - rFlattenicity.fill(HIST("hAmpT0AVsChBeforeCalibration"), sector, amplitude); - if (applyCalibCh) { - amplitude *= calibT0A[sector]; - } - rFlattenicity.fill(HIST("hAmpT0AVsCh"), sector, amplitude); - } - sumAmpFT0A += amplitude; - 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; - rFlattenicity.fill(HIST("hAmpT0CVsChBeforeCalibration"), sector, amplitude); - if (applyCalibCh) { - amplitude *= calibT0C[sector]; - } - rFlattenicity.fill(HIST("hAmpT0CVsCh"), sector, amplitude); - } - rFlattenicity.fill(HIST("hFT0C"), amplitude); - } - - rFlattenicity.fill(HIST("hAmpT0AvsVtxBeforeCalibration"), vtxZ, sumAmpFT0A); - rFlattenicity.fill(HIST("hAmpT0CvsVtxBeforeCalibration"), vtxZ, sumAmpFT0C); - if (applyCalibVtx) { - sumAmpFT0A *= gVtx[1]->Eval(vtxZ); - sumAmpFT0C *= gVtx[2]->Eval(vtxZ); - } - rFlattenicity.fill(HIST("hAmpT0AvsVtx"), vtxZ, sumAmpFT0A); - rFlattenicity.fill(HIST("hAmpT0CvsVtx"), vtxZ, sumAmpFT0C); - } - float flatenicity_t0a = 9999; - flatenicity_t0a = GetFlatenicity({RhoLatticeT0A.data(), RhoLatticeT0A.size()}); - float flatenicity_t0c = 9999; - flatenicity_t0c = GetFlatenicity({RhoLatticeT0C.data(), RhoLatticeT0C.size()}); - - bool isOK_estimator5 = false; - bool isOK_estimator6 = false; - float combined_estimator5 = 0; - float combined_estimator6 = 0; - - for (int i_e = 0; i_e < 8; ++i_e) { - estimator[i_e] = 0; - } - - if (collision.has_foundFV0() && collision.has_foundFT0()) { - float all_weights = 0; - // option 5 - ampl5[0] = sumAmpFT0C; - ampl5[1] = sumAmpFT0A; - if (sumAmpFT0C > 0 && sumAmpFT0A > 0) { - isOK_estimator5 = true; - } - if (isOK_estimator5) { - if (applyNorm) { - all_weights = 0; - for (int i_5 = 0; i_5 < nEta5; ++i_5) { - combined_estimator5 += - ampl5[i_5] * weigthsEta5[i_5] / deltaEeta5[i_5]; - all_weights += weigthsEta5[i_5]; - } - combined_estimator5 /= all_weights; - } else { - for (int i_5 = 0; i_5 < nEta5; ++i_5) { - combined_estimator5 += ampl5[i_5] * weigthsEta5[i_5]; - } - } - } - // option 6: FT0C + FV0 - ampl6[0] = sumAmpFT0C; - ampl6[1] = sumAmpFV0; - if (sumAmpFT0C > 0 && sumAmpFV0 > 0) { - isOK_estimator6 = true; - } - if (isOK_estimator6) { - if (applyNorm) { - all_weights = 0; - for (int i_6 = 0; i_6 < nEta6; ++i_6) { - combined_estimator6 += - ampl6[i_6] * weigthsEta6[i_6] / deltaEeta6[i_6]; - all_weights += weigthsEta6[i_6]; - } - combined_estimator6 /= all_weights; - } else { - for (int i_6 = 0; i_6 < nEta6; ++i_6) { - combined_estimator6 += ampl6[i_6] * weigthsEta6[i_6]; - } - } - } - 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] = combined_estimator5; - float flatenicity_ft0 = (flatenicity_t0a + flatenicity_t0c) / 2.0; - estimator[4] = 1.0 - flatenicity_ft0; - estimator[5] = combined_estimator6; - float flatenicity_ft0v0 = 0.5 * flattenicityfv0 + 0.5 * flatenicity_t0c; - estimator[6] = 1.0 - flatenicity_ft0v0; - estimator[7] = ptT; - - rFlattenicity.fill(HIST(nhEst[0]), estimator[0], estimator[0]); - rFlattenicity.fill(HIST(nhEst[1]), estimator[1], estimator[0]); - rFlattenicity.fill(HIST(nhEst[2]), estimator[2], estimator[0]); - rFlattenicity.fill(HIST(nhEst[3]), estimator[3], estimator[0]); - rFlattenicity.fill(HIST(nhEst[4]), estimator[4], estimator[0]); - rFlattenicity.fill(HIST(nhEst[5]), estimator[5], estimator[0]); - rFlattenicity.fill(HIST(nhEst[6]), estimator[6], estimator[0]); - rFlattenicity.fill(HIST(nhEst[7]), estimator[7], estimator[0]); - - // plot pt vs estimators - for (auto& track : tracks) { - if (!track.isGlobalTrack()) { - continue; - } - float pt = track.pt(); - rFlattenicity.fill(HIST(nhPtEst[0]), estimator[0], pt); - rFlattenicity.fill(HIST(nhPtEst[1]), estimator[1], pt); - rFlattenicity.fill(HIST(nhPtEst[2]), estimator[2], pt); - rFlattenicity.fill(HIST(nhPtEst[3]), estimator[3], pt); - rFlattenicity.fill(HIST(nhPtEst[4]), estimator[4], pt); - rFlattenicity.fill(HIST(nhPtEst[5]), estimator[5], pt); - rFlattenicity.fill(HIST(nhPtEst[6]), estimator[6], pt); - rFlattenicity.fill(HIST(nhPtEst[7]), estimator[7], pt); - } - - 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"), flatenicity_t0c, flatenicity_t0a); - } - } - // ====================== Flattenicity estimation ends ===================== - - // Defining filters for events (event selection) - // Processed events will be already fulfilling the event selection requirements - Filter eventFilter = (o2::aod::evsel::sel8 == true); - Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); - - // Filters on V0s - // Cannot filter on dynamic columns, so we cut on DCA to PV and DCA between daughters only - Filter preFilterV0 = (nabs(aod::v0data::dcapostopv) > v0setting_dcapostopv && - nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv && - aod::v0data::dcaV0daughters < v0setting_dcav0dau); - - Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut); - using TrackCandidates = soa::Filtered>; - - void processDataRun3(soa::Filtered>::iterator const& collision, - soa::Filtered const& V0s, TrackCandidates const& tracks, soa::Join const& /*bcs*/, - aod::MFTTracks const& /*mfttracks*/, aod::FT0s const& /*ft0s*/, - aod::FV0As const& /*fv0s*/) - { - if (!(isEventSelected(collision))) { // Checking if the event passes the selection criteria - return; - } - - auto vtxZ = collision.posZ(); - auto vtxY = collision.posY(); - auto vtxX = collision.posX(); - - EstimateFlattenicity(collision, tracks); - - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - - for (const auto& v0 : V0s) { - const auto& posDaughterTrack = v0.posTrack_as(); - const auto& negDaughterTrack = v0.negTrack_as(); - - if (TMath::Abs(posDaughterTrack.eta()) > 0.8 || TMath::Abs(negDaughterTrack.eta()) > 0.8) { - 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 = TMath::Sqrt(TMath::Power(decayvtxX - vtxX, 2) + TMath::Power(decayvtxY - vtxY, 2) + TMath::Power(decayvtxZ - vtxZ, 2)); - float v0p = TMath::Sqrt(v0.pt() * v0.pt() + v0.pz() * v0.pz()); - - float ctauK0s = decaylength * massK0s / v0p; - float ctauLambda = decaylength * massLambda / v0p; - float ctauAntiLambda = decaylength * massAntiLambda / v0p; - - // Cut on dynamic columns for K0s - - if (v0.v0cosPA() >= v0setting_cospaK0s && v0.v0radius() >= v0setting_radiusK0s && TMath::Abs(posDaughterTrack.tpcNSigmaPi()) <= NSigmaTPCPion && TMath::Abs(negDaughterTrack.tpcNSigmaPi()) <= NSigmaTPCPion && ctauK0s < v0setting_ctauK0s && TMath::Abs(v0.rapidity(0)) <= 0.5 && TMath::Abs(massLambda - pdgmassLambda) > 0.005 && TMath::Abs(massAntiLambda - pdgmassLambda) > 0.005) { - - 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()); - - // 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() >= v0setting_cospaLambda && v0.v0radius() >= v0setting_radiusLambda && TMath::Abs(posDaughterTrack.tpcNSigmaPr()) <= NSigmaTPCProton && TMath::Abs(negDaughterTrack.tpcNSigmaPi()) <= NSigmaTPCPion && ctauLambda < v0setting_ctauLambda && TMath::Abs(v0.rapidity(1)) <= 0.5 && TMath::Abs(massK0s - pdgmassK0s) > 0.01) { - - 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()); - - // 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() >= v0setting_cospaLambda && v0.v0radius() >= v0setting_radiusLambda && TMath::Abs(posDaughterTrack.tpcNSigmaPi()) <= NSigmaTPCPion && TMath::Abs(negDaughterTrack.tpcNSigmaPr()) <= NSigmaTPCProton && ctauAntiLambda < v0setting_ctauLambda && TMath::Abs(v0.rapidity(2)) <= 0.5 && TMath::Abs(massK0s - pdgmassK0s) > 0.01) { - - 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()); - - // 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>; - void processRecMC(soa::Filtered>::iterator const& collision, - soa::Filtered> const& V0s, - TrackCandidatesMC const& tracks, - soa::Join const& /*bcs*/, - aod::MFTTracks const& /*mfttracks*/, aod::FT0s const& /*ft0s*/, - aod::FV0As const& /*fv0s*/, aod::McParticles const&) - { - if (!(isEventSelected(collision))) { // Checking if the event passes the selection criteria - return; - } - - auto vtxZ = collision.posZ(); - auto vtxY = collision.posY(); - auto vtxX = collision.posX(); - - EstimateFlattenicity(collision, tracks); - - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - - for (const auto& v0 : V0s) { - - const auto& posDaughterTrack = v0.posTrack_as(); - const auto& negDaughterTrack = v0.negTrack_as(); - - if (!posDaughterTrack.has_mcParticle() || !negDaughterTrack.has_mcParticle()) { - continue; - } - if (TMath::Abs(posDaughterTrack.eta()) > 0.8 || TMath::Abs(negDaughterTrack.eta()) > 0.8) { - continue; - } - - auto mcnegtrack = negDaughterTrack.mcParticle_as(); - auto mcpostrack = posDaughterTrack.mcParticle_as(); - - 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 = TMath::Sqrt(TMath::Power(decayvtxX - vtxX, 2) + TMath::Power(decayvtxY - vtxY, 2) + TMath::Power(decayvtxZ - vtxZ, 2)); - float v0p = TMath::Sqrt(v0.pt() * v0.pt() + v0.pz() * v0.pz()); - - float ctauK0s = decaylength * massK0s / v0p; - float ctauLambda = decaylength * massLambda / v0p; - float ctauAntiLambda = decaylength * massAntiLambda / v0p; - - // Cut on dynamic columns for K0s - - for (auto& particleMotherOfNeg : mcnegtrack.mothers_as()) { - for (auto& particleMotherOfPos : mcpostrack.mothers_as()) { - if (particleMotherOfNeg == particleMotherOfPos && (particleMotherOfNeg.pdgCode() == 3122 || particleMotherOfNeg.pdgCode() == -3122 || particleMotherOfNeg.pdgCode() == 310) && particleMotherOfNeg.isPhysicalPrimary()) { - - if (particleMotherOfNeg.pdgCode() == 310 && v0.v0cosPA() >= v0setting_cospaK0s && v0.v0radius() >= v0setting_radiusK0s && TMath::Abs(posDaughterTrack.tpcNSigmaPi()) <= NSigmaTPCPion && TMath::Abs(negDaughterTrack.tpcNSigmaPi()) <= NSigmaTPCPion && ctauK0s < v0setting_ctauK0s && TMath::Abs(v0.rapidity(0)) <= 0.5 && TMath::Abs(massLambda - pdgmassLambda) > 0.005 && TMath::Abs(massAntiLambda - pdgmassLambda) > 0.005) { - - 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()); - - // 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 (particleMotherOfNeg.pdgCode() == 3122 && v0.v0cosPA() >= v0setting_cospaLambda && v0.v0radius() >= v0setting_radiusLambda && TMath::Abs(posDaughterTrack.tpcNSigmaPr()) <= NSigmaTPCProton && TMath::Abs(negDaughterTrack.tpcNSigmaPi()) <= NSigmaTPCPion && ctauLambda < v0setting_ctauLambda && TMath::Abs(v0.rapidity(1)) <= 0.5 && TMath::Abs(massK0s - pdgmassK0s) > 0.01) { - - 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()); - - // 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 (particleMotherOfNeg.pdgCode() == -3122 && v0.v0cosPA() >= v0setting_cospaLambda && v0.v0radius() >= v0setting_radiusLambda && TMath::Abs(posDaughterTrack.tpcNSigmaPi()) <= NSigmaTPCPion && TMath::Abs(negDaughterTrack.tpcNSigmaPr()) <= NSigmaTPCProton && ctauAntiLambda < v0setting_ctauLambda && TMath::Abs(v0.rapidity(2)) <= 0.5 && TMath::Abs(massK0s - pdgmassK0s) > 0.01) { - - 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()); - - // 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()); - } - } - } - } - } - } - } - - // Filter posZFilterMC = (nabs(o2::aod::mccollision::posZ) < cutzvertex); - void processGenMC(o2::aod::McCollision const& mcCollision, - const soa::SmallGroups>& collisions, - o2::aod::McParticles const& mcParticles) - { - // if (collisions.size() < 1) // to process generated collisions that've been reconstructed at least once - // { - // return; - // } - - std::vector SelectedEvents(collisions.size()); - int nevts = 0; - for (const auto& collision : collisions) { - if (!collision.sel8()) { - continue; - } - SelectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); - } - SelectedEvents.resize(nevts); - - const auto evtReconstructedAndSelected = std::find(SelectedEvents.begin(), SelectedEvents.end(), mcCollision.globalIndex()) != SelectedEvents.end(); - - rEventSelection.fill(HIST("hEventSelectionMCGen"), 0); - - if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection - return; - } - rEventSelection.fill(HIST("hEventSelectionMCGen"), 1); // hSelAndRecoMcCollCounter - - if (abs(mcCollision.posZ()) > cutzvertex) { // 10cm - return; - } - rEventSelection.fill(HIST("hEventSelectionMCGen"), 2); - - rEventSelection.fill(HIST("hVertexZGen"), mcCollision.posZ()); - - for (const auto& mcParticle : mcParticles) { - - if (mcParticle.isPhysicalPrimary() && mcParticle.y() < 0.5) { - if (!mcParticle.has_daughters()) { - continue; - } - - if (mcParticle.pdgCode() == 310) { - rKzeroShort.fill(HIST("K0sCounterMCGen"), 0); - rKzeroShort.fill(HIST("hPtK0ShortGen"), mcParticle.pt()); - for (auto& mcparticleDaughter0 : mcParticle.daughters_as()) { - for (auto& mcparticleDaughter1 : mcParticle.daughters_as()) { - if (mcparticleDaughter0.pdgCode() == 211 && mcparticleDaughter1.pdgCode() == -211) { - rKzeroShort.fill(HIST("K0sCounterMCGen"), 1); - } - } - } - } - - if (mcParticle.pdgCode() == 3122) { - rLambda.fill(HIST("LambdaCounterMCGen"), 0); - rLambda.fill(HIST("hPtLambdaGen"), mcParticle.pt()); - for (auto& mcparticleDaughter0 : mcParticle.daughters_as()) { - for (auto& mcparticleDaughter1 : mcParticle.daughters_as()) { - if (mcparticleDaughter0.pdgCode() == -211 && mcparticleDaughter1.pdgCode() == 2212) { - rLambda.fill(HIST("LambdaCounterMCGen"), 1); - } - } - } - } - - if (mcParticle.pdgCode() == -3122) { - rAntiLambda.fill(HIST("AntiLambdaCounterMCGen"), 0.5); - rAntiLambda.fill(HIST("hPtAntiLambdaGen"), mcParticle.pt()); - for (auto& mcparticleDaughter0 : mcParticle.daughters_as()) { - for (auto& mcparticleDaughter1 : mcParticle.daughters_as()) { - if (mcparticleDaughter0.pdgCode() == 211 && mcparticleDaughter1.pdgCode() == -2212) { - rAntiLambda.fill(HIST("AntiLambdaCounterMCGen"), 1); - } - } - } - } - } - } - } - - PROCESS_SWITCH(lambdak0sflattenicity, processDataRun3, "Process Run 3 Data", false); - PROCESS_SWITCH(lambdak0sflattenicity, processRecMC, "Process Run 3 mc, reconstructed", true); - PROCESS_SWITCH(lambdak0sflattenicity, processGenMC, "Process Run 3 mc, generated", true); -}; - -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 bb05d7d2540..ec5294f7248 100644 --- a/PWGMM/UE/Tasks/ue-zdc-analysys.cxx +++ b/PWGMM/UE/Tasks/ue-zdc-analysys.cxx @@ -355,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 { diff --git a/PWGMM/UE/Tasks/uecharged.cxx b/PWGMM/UE/Tasks/uecharged.cxx index 82457880fe6..0ce3891c324 100644 --- a/PWGMM/UE/Tasks/uecharged.cxx +++ b/PWGMM/UE/Tasks/uecharged.cxx @@ -8,39 +8,48 @@ // In applying this license CERN does 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@nucleares.unam.mx) +/// \file uecharged.cxx +/// \brief Underlying event analysis task /// \since November 2021 -/// \last update: July 2024 +/// \last update: October 2025 -#include -#include +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" +#include "PWGLF/Utils/mcParticle.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" #include "Framework/O2DatabasePDGPlugin.h" - +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/Track.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/Core/TrackSelection.h" -#include "Common/Core/TrackSelectionDefaults.h" -#include "TDatabasePDG.h" +#include "TPDGCode.h" +#include #include #include -#include #include -// TODO: implement 50% stat for MC closure vs 50% for testing, add flag for weak decays +#include +#include + +// TODO: implement 50% stat for MC closure vs 50% for testing, add flag for weak +// decays using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using BCsRun3 = soa::Join; struct ueCharged { @@ -53,11 +62,11 @@ struct ueCharged { selectedTracks.SetRequireTPCRefit(true); // selectedTracks.SetRequireGoldenChi2(true); selectedTracks.SetMinNCrossedRowsTPC(70); - selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.4f); + 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.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / std::pow(pt, 1.1f); }); selectedTracks.SetMaxDcaZ(2.f); return selectedTracks; } @@ -70,7 +79,7 @@ struct ueCharged { selectedTracks.SetRequireTPCRefit(true); // selectedTracks.SetRequireGoldenChi2(true); selectedTracks.SetMinNCrossedRowsTPC(70); - selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.4f); + selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.8f); selectedTracks.SetMaxChi2PerClusterTPC(4.f); selectedTracks.SetRequireHitsInITSLayers(1, {0, 1}); // one hit in any SPD layer selectedTracks.SetMaxChi2PerClusterITS(36.f); @@ -83,45 +92,70 @@ struct ueCharged { TrackSelection mySelectionOpenDCA; Service pdg; - float DeltaPhi(float phia, float phib, float rangeMin, float rangeMax); + float deltaPhi(float phia, float phib, float rangeMin, float rangeMax); + // Configurable for event selection Configurable isRun3{"isRun3", true, "is Run3 dataset"}; - Configurable timeEvsel{"timeEvsel", true, "TPC Time frame boundary cut"}; 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 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 analyzeEvandTracksel{"analyzeEvandTracksel", true, "Analyze the event and track selection"}; + Configurable cfgINELCut{"cfgINELCut", 0, "INEL event selection: 0 no sel, 1 INEL>0, 2 INEL>1"}; // acceptance cuts Configurable cfgTrkEtaCut{"cfgTrkEtaCut", 0.8f, "Eta range for tracks"}; Configurable cfgTrkLowPtCut{"cfgTrkLowPtCut", 0.15f, "Minimum constituent pT"}; HistogramRegistry ue; - static constexpr std::string_view pNumDenMeasuredPS[3] = {"pNumDenMeasuredPS_NS", "pNumDenMeasuredPS_AS", "pNumDenMeasuredPS_TS"}; - static constexpr std::string_view pSumPtMeasuredPS[3] = {"pSumPtMeasuredPS_NS", "pSumPtMeasuredPS_AS", "pSumPtMeasuredPS_TS"}; + static constexpr std::string_view pNumDenMeasuredPS[3] = { + "pNumDenMeasuredPS_NS", "pNumDenMeasuredPS_AS", "pNumDenMeasuredPS_TS"}; + static constexpr std::string_view pSumPtMeasuredPS[3] = { + "pSumPtMeasuredPS_NS", "pSumPtMeasuredPS_AS", "pSumPtMeasuredPS_TS"}; static constexpr std::string_view hPhi[3] = {"hPhi_NS", "hPhi_AS", "hPhi_TS"}; // data driven correction - static constexpr std::string_view hNumDenMCDd[3] = {"hNumDenMCDd_NS", "hNumDenMCDd_AS", "hNumDenMCDd_TS"}; - static constexpr std::string_view hSumPtMCDd[3] = {"hSumPtMCDd_NS", "hSumPtMCDd_AS", "hSumPtMCDd_TS"}; - static constexpr std::string_view hNumDenMCMatchDd[3] = {"hNumDenMCMatchDd_NS", "hNumDenMCMatchDd_AS", "hNumDenMCMatchDd_TS"}; - static constexpr std::string_view hSumPtMCMatchDd[3] = {"hSumPtMCMatchDd_NS", "hSumPtMCMatchDd_AS", "hSumPtMCMatchDd_TS"}; + static constexpr std::string_view hNumDenMCDd[3] = { + "hNumDenMCDd_NS", "hNumDenMCDd_AS", "hNumDenMCDd_TS"}; + static constexpr std::string_view hSumPtMCDd[3] = { + "hSumPtMCDd_NS", "hSumPtMCDd_AS", "hSumPtMCDd_TS"}; + static constexpr std::string_view hNumDenMCMatchDd[3] = { + "hNumDenMCMatchDd_NS", "hNumDenMCMatchDd_AS", "hNumDenMCMatchDd_TS"}; + static constexpr std::string_view hSumPtMCMatchDd[3] = { + "hSumPtMCMatchDd_NS", "hSumPtMCMatchDd_AS", "hSumPtMCMatchDd_TS"}; // hist data for corrections - static constexpr std::string_view hPtVsPtLeadingData[3] = {"hPtVsPtLeadingData_NS", "hPtVsPtLeadingData_AS", "hPtVsPtLeadingData_TS"}; - static constexpr std::string_view pNumDenData[3] = {"pNumDenData_NS", "pNumDenData_AS", "pNumDenData_TS"}; - static constexpr std::string_view pSumPtData[3] = {"pSumPtData_NS", "pSumPtData_AS", "pSumPtData_TS"}; + static constexpr std::string_view hPtVsPtLeadingData[3] = { + "hPtVsPtLeadingData_NS", "hPtVsPtLeadingData_AS", + "hPtVsPtLeadingData_TS"}; + static constexpr std::string_view pNumDenData[3] = { + "pNumDenData_NS", "pNumDenData_AS", "pNumDenData_TS"}; + static constexpr std::string_view pSumPtData[3] = { + "pSumPtData_NS", "pSumPtData_AS", "pSumPtData_TS"}; // hist data true - static constexpr std::string_view hPtVsPtLeadingTrue[3] = {"hPtVsPtLeadingTrue_NS", "hPtVsPtLeadingTrue_AS", "hPtVsPtLeadingTrue_TS"}; + static constexpr std::string_view hPtVsPtLeadingTrue[3] = { + "hPtVsPtLeadingTrue_NS", "hPtVsPtLeadingTrue_AS", + "hPtVsPtLeadingTrue_TS"}; + static constexpr std::string_view hPtVsPtLeadingTruePS[3] = { + "hPtVsPtLeadingTruePS_NS", "hPtVsPtLeadingTruePS_AS", + "hPtVsPtLeadingTruePS_TS"}; // all wo detector effects - static constexpr std::string_view pNumDenTrueAll[3] = {"pNumDenTrueAll_NS", "pNumDenTrueAll_AS", "pNumDenTrueAll_TS"}; - static constexpr std::string_view pSumPtTrueAll[3] = {"pSumPtTrueAll_NS", "pSumPtTrueAll_AS", "pSumPtTrueAll_TS"}; + static constexpr std::string_view pNumDenTrueAll[3] = { + "pNumDenTrueAll_NS", "pNumDenTrueAll_AS", "pNumDenTrueAll_TS"}; + static constexpr std::string_view pSumPtTrueAll[3] = { + "pSumPtTrueAll_NS", "pSumPtTrueAll_AS", "pSumPtTrueAll_TS"}; // true, 50% - static constexpr std::string_view pNumDenTrue[3] = {"pNumDenTrue_NS", "pNumDenTrue_AS", "pNumDenTrue_TS"}; - static constexpr std::string_view pSumPtTrue[3] = {"pSumPtTrue_NS", "pSumPtTrue_AS", "pSumPtTrue_TS"}; - - // this must have all event selection effects, but it has not been implemented 50% - static constexpr std::string_view pNumDenTruePS[3] = {"pNumDenTruePS_NS", "pNumDenTruePS_AS", "pNumDenTruePS_TS"}; - static constexpr std::string_view pSumPtTruePS[3] = {"pSumPtTruePS_NS", "pSumPtTruePS_AS", "pSumPtTruePS_TS"}; - static constexpr std::string_view hPhiTrue[3] = {"hPhiTrue_NS", "hPhiTrue_AS", "hPhiTrue_TS"}; - - OutputObj f_Eff{"fpara"}; + static constexpr std::string_view pNumDenTrue[3] = { + "pNumDenTrue_NS", "pNumDenTrue_AS", "pNumDenTrue_TS"}; + static constexpr std::string_view pSumPtTrue[3] = { + "pSumPtTrue_NS", "pSumPtTrue_AS", "pSumPtTrue_TS"}; + // this must have all event selection effects, but it has not been implemented + // 50% + static constexpr std::string_view pNumDenTruePS[3] = { + "pNumDenTruePS_NS", "pNumDenTruePS_AS", "pNumDenTruePS_TS"}; + static constexpr std::string_view pSumPtTruePS[3] = { + "pSumPtTruePS_NS", "pSumPtTruePS_AS", "pSumPtTruePS_TS"}; + static constexpr std::string_view hPhiTrue[3] = {"hPhiTrue_NS", "hPhiTrue_AS", + "hPhiTrue_TS"}; + + OutputObj fEff{"fpara"}; void init(InitContext const&); template @@ -133,55 +167,70 @@ struct ueCharged { template void processTrue(const C& mcCollision, const P& particles); + template + void analyzeEventAndTrackSelection(const C& collision, const T& tracks); + Filter trackFilter = (nabs(aod::track::eta) < cfgTrkEtaCut) && (aod::track::pt > cfgTrkLowPtCut); using CollisionTableMCTrue = aod::McCollisions; - using CollisionTableMC = soa::SmallGroups>; + using CollisionTableMC = soa::SmallGroups>; using TrackTableMC = soa::Filtered>; using ParticleTableMC = aod::McParticles; Preslice perCollision = aod::track::collisionId; - void processMC(CollisionTableMCTrue::iterator const& mcCollision, CollisionTableMC const& collisions, TrackTableMC const& tracks, ParticleTableMC const& particles); + void processMC(CollisionTableMCTrue::iterator const& mcCollision, + CollisionTableMC const& collisions, TrackTableMC const& tracks, + ParticleTableMC const& particles, aod::FT0s const&, + BCsRun3 const&); PROCESS_SWITCH(ueCharged, processMC, "process MC", false); - using CollisionTableMCData = soa::Join; + using CollisionTableMCData = soa::Join; using TrackTableMCData = soa::Filtered>; - void processDataMC(CollisionTableMCData::iterator const& collision, TrackTableMCData const& tracks, ParticleTableMC const& particles, aod::McCollisions const& mcCollisions); + void processDataMC(CollisionTableMCData::iterator const& collision, + TrackTableMCData const& tracks, + ParticleTableMC const& particles, + aod::McCollisions const& mcCollisions); PROCESS_SWITCH(ueCharged, processDataMC, "process data MC", false); - using CollisionTableData = soa::Join; + using CollisionTableData = soa::Join; using TrackTableData = soa::Filtered>; - void processData(CollisionTableData::iterator const& collision, TrackTableData const& tracks); + void processData(CollisionTableData::iterator const& collision, + TrackTableData const& tracks, aod::FT0s const&, + BCsRun3 const&); PROCESS_SWITCH(ueCharged, processData, "process data", false); // add new method }; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec workflow{}; workflow.push_back(adaptAnalysisTask(cfgc)); return workflow; } + // implementation -float ueCharged::DeltaPhi(float phia, float phib, - float rangeMin = -M_PI / 2.0, float rangeMax = 3.0 * M_PI / 2.0) +float ueCharged::deltaPhi(float phia, float phib, + float rangeMin = -o2::constants::math::PI / 2.0, + float rangeMax = 3.0 * o2::constants::math::PI / + 2.0) { float dphi = -999; if (phia < 0) { - phia += 2 * M_PI; - } else if (phia > 2 * M_PI) { - phia -= 2 * M_PI; + phia += 2 * o2::constants::math::PI; + } else if (phia > 2 * o2::constants::math::PI) { + phia -= 2 * o2::constants::math::PI; } if (phib < 0) { - phib += 2 * M_PI; - } else if (phib > 2 * M_PI) { - phib -= 2 * M_PI; + phib += 2 * o2::constants::math::PI; + } else if (phib > 2 * o2::constants::math::PI) { + phib -= 2 * o2::constants::math::PI; } dphi = phib - phia; if (dphi < rangeMin) { - dphi += 2 * M_PI; + dphi += 2 * o2::constants::math::PI; } else if (dphi > rangeMax) { - dphi -= 2 * M_PI; + dphi -= 2 * o2::constants::math::PI; } return dphi; @@ -193,32 +242,59 @@ 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"}; + 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.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"}; + 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.3)*((0.221456)+x*(3.4271)+x*x*(-6.7668))+(x>=0.3&&x<2.1)*((0.610649)+(0.148627)*x+(-0.0772185)*x*x+(0.0157586)*x*x*x)+(x>=2.1)*(0.726557)", 0., 1e5)); + fEff.setObject(new TF1("fpara", + "(x<0.3)*((0.315318)+x*(2.38596)+x*x*(-4.388)) +" + "(x>=0.3&&x<1.8)*((0.604051)+(0.154763)*x+(-0.103004)*" + "x*x+(0.0266487)*x*x*x) +" + "(x>=1.8&&x<14.)*((0.700444)+(-0.00115506)*x+(0." + "000667608)*x*x+(-3.82915e-05)*x*x*x) +" + "(x>=14)*((0.731778)+(-0.000994634)*x)", + 0., 1e5)); if (doprocessMC) { ue.add("hPtOut", "pT all rec; pT; Nch", HistType::kTH1D, {ptAxis}); ue.add("hPtInPrim", "pT mc prim; pT; Nch", HistType::kTH1D, {ptAxis}); - ue.add("hPtInPrimGen", "pT mc prim all gen; pT; Nch", HistType::kTH1D, {ptAxis}); + ue.add("hPtInPrimGen", "pT mc prim all gen; pT; Nch", HistType::kTH1D, + {ptAxis}); ue.add("hPtOutPrim", "pT rec prim; pT; Nch", HistType::kTH1D, {ptAxis}); ue.add("hPtOutSec", "pT rec sec; pT; Nch", HistType::kTH1D, {ptAxis}); - ue.add("hPtDCAall", "all MC; DCA_xy; Nch", HistType::kTH2D, {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); - ue.add("hPtDCAPrimary", "primary; DCA_xy; Nch", HistType::kTH2D, {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); - ue.add("hPtDCAWeak", "Weak decays; DCA_xy; Nch", HistType::kTH2D, {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); - ue.add("hPtDCAMat", "Material; DCA_xy; Nch", HistType::kTH2D, {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); - - ue.add("hmultTrue", "mult true", HistType::kTH1F, {{200, -0.5, 199.5, " "}}); - ue.add("hmultTrueGen", "mult true all Gen", HistType::kTH1F, {{200, -0.5, 199.5, " "}}); + ue.add("hPtDCAall", "all MC; DCA_xy; Nch", HistType::kTH2D, + {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); + ue.add("hPtDCAPrimary", "primary; DCA_xy; Nch", HistType::kTH2D, + {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); + ue.add("hPtDCAWeak", "Weak decays; DCA_xy; Nch", HistType::kTH2D, + {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); + ue.add("hPtDCAMat", "Material; DCA_xy; Nch", HistType::kTH2D, + {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); + ue.add("hmultTrue", "mult true", HistType::kTH1F, + {{200, -0.5, 199.5, " "}}); + ue.add("hmultTrueGen", "mult true all Gen", HistType::kTH1F, + {{200, -0.5, 199.5, " "}}); ue.add("hvtxZmc", "vtxZ mctrue", HistType::kTH1F, {{40, -20.0, 20.0, " "}}); - ue.add("hPtLeadingTrue", "true pTleading after physics selection", HistType::kTH1D, {ptAxist}); + ue.add("hPtLeadingTrue", "true pTleading after physics selection", + HistType::kTH1D, {ptAxist}); for (int i = 0; i < 3; ++i) { ue.add(hPtVsPtLeadingTrue[i].data(), " ", HistType::kTH2D, {{ptAxist}, {ptAxis}}); + ue.add(hPtVsPtLeadingTruePS[i].data(), " ", HistType::kTH2D, {{ptAxist}, {ptAxis}}); ue.add(pNumDenTrueAll[i].data(), "", HistType::kTProfile, {ptAxist}); ue.add(pSumPtTrueAll[i].data(), "", HistType::kTProfile, {ptAxist}); ue.add(pNumDenTrue[i].data(), "", HistType::kTProfile, {ptAxist}); @@ -227,72 +303,218 @@ void ueCharged::init(InitContext const&) ue.add(pSumPtTruePS[i].data(), "", HistType::kTProfile, {ptAxist}); } for (int i = 0; i < 3; ++i) { - ue.add(hPhiTrue[i].data(), "all charged true; #Delta#phi; Counts", HistType::kTH1D, {{64, -M_PI / 2.0, 3.0 * M_PI / 2.0, ""}}); + ue.add(hPhiTrue[i].data(), "all charged true; #Delta#phi; Counts", + HistType::kTH1D, + {{64, -o2::constants::math::PI / 2.0, + 3.0 * o2::constants::math::PI / 2.0, ""}}); } } + ue.add("hStat", "TotalEvents", HistType::kTH1F, {{1, 0.5, 1.5, " "}}); ue.add("hmultRec", "mult rec", HistType::kTH1F, {{200, -0.5, 199.5, " "}}); ue.add("hdNdeta", "dNdeta", HistType::kTH1F, {{50, -2.5, 2.5, " "}}); - ue.add("vtxZEta", ";#eta;vtxZ", HistType::kTH2F, {{50, -2.5, 2.5, " "}, {60, -30, 30, " "}}); - ue.add("phiEta", ";#eta;#varphi", HistType::kTH2F, {{50, -2.5, 2.5}, {200, 0., 2 * M_PI, " "}}); + ue.add("vtxZEta", ";#eta;vtxZ", HistType::kTH2F, + {{50, -2.5, 2.5, " "}, {60, -30, 30, " "}}); + ue.add("phiEta", ";#eta;#varphi", HistType::kTH2F, + {{50, -2.5, 2.5}, {200, 0., 2 * o2::constants::math::PI, " "}}); ue.add("hvtxZ", "vtxZ", HistType::kTH1F, {{40, -20.0, 20.0, " "}}); - 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}); + ue.add("hPtLeadingRecPS", "rec pTleading after physics selection", + HistType::kTH1D, {ptAxist}); + ue.add("hPtLeadingMeasured", "measured pTleading after physics selection", + HistType::kTH1D, {ptAxist}); + ue.add("hPtLeadingVsTracks", "", HistType::kTProfile, {{ptAxist}}); + + auto h = ue.get(HIST("hCounter")); + h->GetXaxis()->SetBinLabel(1, "Events read"); + h->GetXaxis()->SetBinLabel(2, "INEL"); + h->GetXaxis()->SetBinLabel(3, "Sel8"); + h->GetXaxis()->SetBinLabel(4, "NoSameBunchPileup"); + h->GetXaxis()->SetBinLabel(5, "IsGoodZvtxFT0vsPV"); + h->GetXaxis()->SetBinLabel(6, "posZ passed"); for (int i = 0; i < 3; ++i) { - ue.add(pNumDenMeasuredPS[i].data(), "Number Density; ; #LT #it{N}_{trk} #GT", HistType::kTProfile, {ptAxist}); - ue.add(pSumPtMeasuredPS[i].data(), "Total #it{p}_{T}; ; #LT#sum#it{p}_{T}#GT", HistType::kTProfile, {ptAxist}); - ue.add(hPhi[i].data(), "all charged; #Delta#phi; Counts", HistType::kTH1D, {{64, -M_PI / 2.0, 3.0 * M_PI / 2.0, ""}}); + ue.add(pNumDenMeasuredPS[i].data(), + "Number Density; ; #LT #it{N}_{trk} #GT", HistType::kTProfile, + {ptAxist}); + ue.add(pSumPtMeasuredPS[i].data(), + "Total #it{p}_{T}; ; #LT#sum#it{p}_{T}#GT", HistType::kTProfile, + {ptAxist}); + ue.add(hPhi[i].data(), "all charged; #Delta#phi; Counts", HistType::kTH1D, + {{64, -o2::constants::math::PI / 2.0, + 3.0 * o2::constants::math::PI / 2.0, ""}}); } // Data driven for (int i = 0; i < 3; ++i) { - ue.add(hNumDenMCDd[i].data(), " ", HistType::kTH2D, {{ptAxist}, {100, -0.5, 99.5, "#it{N}_{trk}"}}); + ue.add(hNumDenMCDd[i].data(), " ", HistType::kTH2D, + {{ptAxist}, {100, -0.5, 99.5, "#it{N}_{trk}"}}); ue.add(hSumPtMCDd[i].data(), " ", HistType::kTH2D, {{ptAxist}, {ptAxis}}); - ue.add(hNumDenMCMatchDd[i].data(), " ", HistType::kTH2D, {{ptAxist}, {100, -0.5, 99.5, "#it{N}_{trk}"}}); - ue.add(hSumPtMCMatchDd[i].data(), " ", HistType::kTH2D, {{ptAxist}, {ptAxis}}); + ue.add(hNumDenMCMatchDd[i].data(), " ", HistType::kTH2D, + {{ptAxist}, {100, -0.5, 99.5, "#it{N}_{trk}"}}); + ue.add(hSumPtMCMatchDd[i].data(), " ", HistType::kTH2D, + {{ptAxist}, {ptAxis}}); } for (int i = 0; i < 3; ++i) { - ue.add(hPtVsPtLeadingData[i].data(), " ", HistType::kTH2D, {{ptAxist}, {ptAxis}}); + ue.add(hPtVsPtLeadingData[i].data(), " ", HistType::kTH2D, + {{ptAxist}, {ptAxis}}); ue.add(pNumDenData[i].data(), "", HistType::kTProfile, {ptAxist}); ue.add(pSumPtData[i].data(), "", HistType::kTProfile, {ptAxist}); } ue.add("hPtLeadingData", " ", HistType::kTH1D, {{ptAxist}}); - ue.add("hPTVsDCAData", " ", HistType::kTH2D, {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); - ue.add("hEtaLeadingVsPtLeading", " ", HistType::kTH2D, {{ptAxist}, {50, -2.5, 2.5, "#eta"}}); + ue.add("hPTVsDCAData", " ", HistType::kTH2D, + {{ptAxis}, {121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); + ue.add("hEtaLeadingVsPtLeading", " ", HistType::kTH2D, + {{ptAxist}, {50, -2.5, 2.5, "#eta"}}); + + if (analyzeEvandTracksel) { + + const AxisSpec axisVtxZ{500, -25., 25., ""}; + ue.add("hVtxFT0VsVtxCol", " ", HistType::kTH2D, + {{axisVtxZ}, {axisVtxZ}}); // FT0-vertex vs z-vertex from collisions + ue.add("hVtxFT0VsVtxCol_afterSel8", " ", HistType::kTH2D, + {{axisVtxZ}, {axisVtxZ}}); + ue.add("hVtxFT0VsVtxCol_afterPile", " ", HistType::kTH2D, + {{axisVtxZ}, {axisVtxZ}}); + ue.add("hVtxFT0VsVtxCol_afterGoodZvtx", " ", HistType::kTH2D, + {{axisVtxZ}, {axisVtxZ}}); + ue.add("hvtxZ_before", "vtxZ befer ev selection", HistType::kTH1F, + {{40, -20.0, 20.0, " "}}); + ue.add("hvtxZ_after", "vtxZ befer ev after", HistType::kTH1F, + {{40, -20.0, 20.0, " "}}); + + const AxisSpec axisMultT0M{1000, 0., 8000., "T0M multiplicity"}; + ue.add("hVtxFT0MinusVtxColVsMultT0M", "", kTH2F, + {{axisVtxZ}, {axisMultT0M}}); // FT0-vertex minus z-vertex from + // collisions vs multiplicity + ue.add("postselection_track/hT0MVsTracks", "", HistType::kTH2D, + {{axisMultT0M}, {200, 0., 200.}}); + ue.add("postselection_track/hVtxFT0VsTracks", "", HistType::kTH2D, + {{axisVtxZ}, {200, 0., 200.}}); + ue.add("postselection_track/hVtxVsTracks", "", HistType::kTH2D, + {{axisVtxZ}, {200, 0., 200.}}); + + // its histograms + ue.add("preselection_track/ITS/itsNCls", + "number of found ITS clusters;# clusters ITS", kTH1D, + {{8, -0.5, 7.5}}); + ue.add("preselection_track/ITS/itsChi2NCl", + "chi2 per ITS cluster;chi2 / cluster ITS", kTH1D, {{100, 0, 40}}); + ue.add("preselection_track/ITS/itsClusterMap", "ITS cluster map", kTH1D, + {{128, -0.5, 127.5}}); + ue.add("postselection_track/ITS/itsNCls", + "number of found ITS clusters;# clusters ITS", kTH1D, + {{8, -0.5, 7.5}}); + ue.add("postselection_track/ITS/itsChi2NCl", + "chi2 per ITS cluster;chi2 / cluster ITS", kTH1D, {{100, 0, 40}}); + ue.add("postselection_track/ITS/itsClusterMap", "ITS cluster map", kTH1D, + {{128, -0.5, 127.5}}); + + // tpc histograms + ue.add("preselection_track/TPC/tpcNClsFindable", + "number of findable TPC clusters;# findable clusters TPC", kTH1D, + {{165, -0.5, 164.5}}); + ue.add("preselection_track/TPC/tpcNClsFound", + "number of found TPC clusters;# clusters TPC", kTH1D, + {{165, -0.5, 164.5}}); + ue.add("preselection_track/TPC/tpcNClsShared", + "number of shared TPC clusters;# shared clusters TPC", kTH1D, + {{165, -0.5, 164.5}}); + ue.add("preselection_track/TPC/tpcCrossedRows", + "number of crossed TPC rows;# crossed rows TPC", kTH1D, + {{165, -0.5, 164.5}}); + ue.add("preselection_track/TPC/tpcFractionSharedCls", + "fraction of shared TPC clusters;fraction shared clusters TPC", + kTH1D, {{100, 0., 1.}}); + ue.add("preselection_track/TPC/tpcCrossedRowsOverFindableCls", + "crossed TPC rows over findable clusters;crossed rows / findable " + "clusters TPC", + kTH1D, {{60, 0.7, 1.3}}); + ue.add("preselection_track/TPC/tpcChi2NCl", + "chi2 per cluster in TPC;chi2 / cluster TPC", kTH1D, {{100, 0, 10}}); + ue.add("postselection_track/TPC/tpcNClsFindable", + "number of findable TPC clusters;# findable clusters TPC", kTH1D, + {{165, -0.5, 164.5}}); + ue.add("postselection_track/TPC/tpcNClsFound", + "number of found TPC clusters;# clusters TPC", kTH1D, + {{165, -0.5, 164.5}}); + ue.add("postselection_track/TPC/tpcNClsShared", + "number of shared TPC clusters;# shared clusters TPC", kTH1D, + {{165, -0.5, 164.5}}); + ue.add("postselection_track/TPC/tpcCrossedRows", + "number of crossed TPC rows;# crossed rows TPC", kTH1D, + {{165, -0.5, 164.5}}); + ue.add("postselection_track/TPC/tpcFractionSharedCls", + "fraction of shared TPC clusters;fraction shared clusters TPC", + kTH1D, {{100, 0., 1.}}); + ue.add("postselection_track/TPC/tpcCrossedRowsOverFindableCls", + "crossed TPC rows over findable clusters;crossed rows / findable " + "clusters TPC", + kTH1D, {{60, 0.7, 1.3}}); + ue.add("postselection_track/TPC/tpcChi2NCl", + "chi2 per cluster in TPC;chi2 / cluster TPC", kTH1D, {{100, 0, 10}}); + + // general + ue.add("preselection_track/hvtxZ", "vtxZ before track selection", + HistType::kTH1D, {{40, -20.0, 20.0, " "}}); + ue.add("preselection_track/hvtxXY", "vtxXY before track selection", + HistType::kTH1D, {{121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); + ue.add("preselection_track/htracks", "tracks before track selection", + HistType::kTH1D, {{100, 0., 100., "N_{tracks}"}}); + ue.add("postselection_track/hvtxZ", "vtxZ after track selection", + HistType::kTH1D, {{40, -20.0, 20.0, "#it{DCA}_{z} (cm) "}}); + ue.add("postselection_track/hvtxXY", "vtxXY after track selection", + HistType::kTH1D, {{121, -3.025, 3.025, "#it{DCA}_{xy} (cm)"}}); + ue.add("postselection_track/htracks", "tracks after track selection", + HistType::kTH1D, {{100, 0., 100., "N_{tracks}"}}); + } } -void ueCharged::processMC(CollisionTableMCTrue::iterator const& mcCollision, CollisionTableMC const& collisions, TrackTableMC const& tracks, ParticleTableMC const& particles) +void ueCharged::processMC(CollisionTableMCTrue::iterator const& mcCollision, + CollisionTableMC const& collisions, + TrackTableMC const& tracks, + ParticleTableMC const& particles, aod::FT0s const&, + BCsRun3 const&) { if (collisions.size() != 0) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { auto curTracks = tracks.sliceBy(perCollision, collision.globalIndex()); processMeasMC(collision, curTracks, particles); + if (analyzeEvandTracksel) { + analyzeEventAndTrackSelection(collision, curTracks); + } break; // for now look only at first collision... } } processTrue(mcCollision, particles); } -void ueCharged::processDataMC(CollisionTableMCData::iterator const& collision, TrackTableMCData const& tracks, ParticleTableMC const& particles, aod::McCollisions const& /*mcCollisions*/) +void ueCharged::processDataMC(CollisionTableMCData::iterator const& collision, + TrackTableMCData const& tracks, + ParticleTableMC const& particles, + aod::McCollisions const& /*mcCollisions*/) { processMeasMC(collision, tracks, particles); } -void ueCharged::processData(CollisionTableData::iterator const& collision, TrackTableData const& tracks) + +void ueCharged::processData(CollisionTableData::iterator const& collision, + TrackTableData const& tracks, aod::FT0s const&, + BCsRun3 const&) { processMeas(collision, tracks); + if (analyzeEvandTracksel) { + analyzeEventAndTrackSelection(collision, tracks); + } } template void ueCharged::processTrue(const C& mcCollision, const P& particles) { int multTrue = 0; - int multTrueINEL = 0; - for (auto& particle : particles) { + // int multTrueINEL = 0; + for (const auto& particle : particles) { auto pdgParticle = pdg->GetParticle(particle.pdgCode()); if (!pdgParticle || pdgParticle->Charge() == 0.) { continue; @@ -301,7 +523,7 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles) continue; } if (std::abs(particle.eta()) <= 1.0) { - multTrueINEL++; + // multTrueINEL++; } if (std::abs(particle.eta()) >= cfgTrkEtaCut) { continue; @@ -313,7 +535,16 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles) ue.fill(HIST("hPtInPrimGen"), particle.pt()); } ue.fill(HIST("hmultTrueGen"), multTrue); - if (std::abs(mcCollision.posZ()) > 10.f && multTrueINEL <= 0) { + + if (cfgINELCut == 1 && !o2::pwglf::isINELgt0mc(particles, pdg)) { + return; + } + + if (cfgINELCut == 2 && !o2::pwglf::isINELgt1mc(particles, pdg)) { + return; + } + + if (std::abs(mcCollision.posZ()) > 10.f) { return; } @@ -323,7 +554,7 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles) double flPhiTrue = 0; int flIndexTrue = 0; - for (auto& particle : particles) { + for (const auto& particle : particles) { auto pdgParticle = pdg->GetParticle(particle.pdgCode()); if (!pdgParticle || pdgParticle->Charge() == 0.) { continue; @@ -348,19 +579,19 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles) } } ue.fill(HIST("hPtLeadingTrue"), flPtTrue); - std::vector ue_true; - ue_true.clear(); - int nchm_toptrue[3]; - double sumptm_toptrue[3]; + std::vector ueTrue; + ueTrue.clear(); + int nchmTopTrue[3]; + double sumptmTopTrue[3]; for (int i = 0; i < 3; ++i) { - nchm_toptrue[i] = 0; - sumptm_toptrue[i] = 0; + nchmTopTrue[i] = 0; + sumptmTopTrue[i] = 0; } - std::vector ptArrayTrue; - std::vector phiArrayTrue; + std::vector ptArrayTrue; + std::vector phiArrayTrue; std::vector indexArrayTrue; - for (auto& particle : particles) { + for (const auto& particle : particles) { auto pdgParticle = pdg->GetParticle(particle.pdgCode()); if (!pdgParticle || pdgParticle->Charge() == 0.) { @@ -379,69 +610,85 @@ void ueCharged::processTrue(const C& mcCollision, const P& particles) if (flIndexTrue == particle.globalIndex()) { continue; } - double DPhi = DeltaPhi(particle.phi(), flPhiTrue); + double dPhi = deltaPhi(particle.phi(), flPhiTrue); // definition of the topological regions - if (TMath::Abs(DPhi) < M_PI / 3.0) { // near side - ue.fill(HIST(hPhiTrue[0]), DPhi); + if (std::abs(dPhi) < o2::constants::math::PI / 3.0) { // near side + ue.fill(HIST(hPhiTrue[0]), dPhi); ue.fill(HIST(hPtVsPtLeadingTrue[0]), flPtTrue, particle.pt()); - nchm_toptrue[0]++; - sumptm_toptrue[0] += particle.pt(); - } else if (TMath::Abs(DPhi - M_PI) < M_PI / 3.0) { // away side - ue.fill(HIST(hPhiTrue[1]), DPhi); + nchmTopTrue[0]++; + sumptmTopTrue[0] += particle.pt(); + } else if (std::abs(dPhi - o2::constants::math::PI) < + o2::constants::math::PI / 3.0) { // away side + ue.fill(HIST(hPhiTrue[1]), dPhi); ue.fill(HIST(hPtVsPtLeadingTrue[1]), flPtTrue, particle.pt()); - nchm_toptrue[1]++; - sumptm_toptrue[1] += particle.pt(); + nchmTopTrue[1]++; + sumptmTopTrue[1] += particle.pt(); } else { // transverse side - ue.fill(HIST(hPhiTrue[2]), DPhi); + ue.fill(HIST(hPhiTrue[2]), dPhi); ue.fill(HIST(hPtVsPtLeadingTrue[2]), flPtTrue, particle.pt()); - nchm_toptrue[2]++; - sumptm_toptrue[2] += particle.pt(); + nchmTopTrue[2]++; + sumptmTopTrue[2] += particle.pt(); } } for (int i_reg = 0; i_reg < 3; ++i_reg) { - ue_true.push_back(1.0 * nchm_toptrue[i_reg]); + ueTrue.push_back(1.0 * nchmTopTrue[i_reg]); } for (int i_reg = 0; i_reg < 3; ++i_reg) { - ue_true.push_back(sumptm_toptrue[i_reg]); + ueTrue.push_back(sumptmTopTrue[i_reg]); } - ue.fill(HIST(pNumDenTrueAll[0]), flPtTrue, ue_true[0]); - ue.fill(HIST(pSumPtTrueAll[0]), flPtTrue, ue_true[3]); + ue.fill(HIST(pNumDenTrueAll[0]), flPtTrue, ueTrue[0]); + ue.fill(HIST(pSumPtTrueAll[0]), flPtTrue, ueTrue[3]); - ue.fill(HIST(pNumDenTrueAll[1]), flPtTrue, ue_true[1]); - ue.fill(HIST(pSumPtTrueAll[1]), flPtTrue, ue_true[4]); + ue.fill(HIST(pNumDenTrueAll[1]), flPtTrue, ueTrue[1]); + ue.fill(HIST(pSumPtTrueAll[1]), flPtTrue, ueTrue[4]); - ue.fill(HIST(pNumDenTrueAll[2]), flPtTrue, ue_true[2]); - ue.fill(HIST(pSumPtTrueAll[2]), flPtTrue, ue_true[5]); + ue.fill(HIST(pNumDenTrueAll[2]), flPtTrue, ueTrue[2]); + ue.fill(HIST(pSumPtTrueAll[2]), flPtTrue, ueTrue[5]); ptArrayTrue.clear(); phiArrayTrue.clear(); indexArrayTrue.clear(); } + template void ueCharged::processMeas(const C& collision, const T& tracks) { ue.fill(HIST("hCounter"), 0); - if (!collision.sel8()) { + if (cfgINELCut == 1 && !collision.isInelGt0()) { + return; + } + + if (cfgINELCut == 2 && !collision.isInelGt1()) { return; } ue.fill(HIST("hCounter"), 1); - if (timeEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + if (sel8 && !collision.sel8()) { + return; + } + + if (removeITSROFBorder && + (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || + !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { return; } ue.fill(HIST("hCounter"), 2); - if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + + if (piluprejection && + !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { return; } ue.fill(HIST("hCounter"), 3); - if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + + if (goodzvertex && + !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { return; } @@ -464,11 +711,12 @@ void ueCharged::processMeas(const C& collision, const T& tracks) double flEta = 0; int flIndex = 0; int multRec = 0; - for (auto& track : tracks) { + int track_multiplicity = 0; + for (const auto& track : tracks) { if (!mySelectionPrim.IsSelected(track)) { continue; } - + track_multiplicity++; ue.fill(HIST("hdNdeta"), track.eta()); ue.fill(HIST("vtxZEta"), track.eta(), vtxZ); ue.fill(HIST("phiEta"), track.eta(), track.phi()); @@ -485,20 +733,21 @@ void ueCharged::processMeas(const C& collision, const T& tracks) ue.fill(HIST("hPtLeadingMeasured"), flPt); ue.fill(HIST("hPtLeadingRecPS"), flPt); ue.fill(HIST("hEtaLeadingVsPtLeading"), flPt, flEta); + ue.fill(HIST("hPtLeadingVsTracks"), flPt, track_multiplicity); - std::vector ue_rec; - ue_rec.clear(); - int nchm_top[3]; - double sumptm_top[3]; + std::vector ueRec; + ueRec.clear(); + int nchmTop[3]; + double sumptmTop[3]; for (int i = 0; i < 3; ++i) { - nchm_top[i] = 0; - sumptm_top[i] = 0; + nchmTop[i] = 0; + sumptmTop[i] = 0; } - std::vector ptArray; - std::vector phiArray; + std::vector ptArray; + std::vector phiArray; std::vector indexArray; - for (auto& track : tracks) { + for (const auto& track : tracks) { if (mySelectionOpenDCA.IsSelected(track)) { ue.fill(HIST("hPTVsDCAData"), track.pt(), track.dcaXY()); @@ -506,7 +755,7 @@ void ueCharged::processMeas(const C& collision, const T& tracks) if (mySelectionPrim.IsSelected(track)) { // applying the efficiency twice for the misrec of leading particle - if (f_Eff->Eval(track.pt()) > gRandom->Uniform(0, 1)) { + if (fEff->Eval(track.pt()) > gRandom->Uniform(0, 1)) { ptArray.push_back(track.pt()); phiArray.push_back(track.phi()); indexArray.push_back(track.globalIndex()); @@ -517,55 +766,56 @@ void ueCharged::processMeas(const C& collision, const T& tracks) continue; } - double DPhi = DeltaPhi(track.phi(), flPhi); + double dPhi = deltaPhi(track.phi(), flPhi); // definition of the topological regions - if (TMath::Abs(DPhi) < M_PI / 3.0) { // near side - ue.fill(HIST(hPhi[0]), DPhi); + if (std::abs(dPhi) < o2::constants::math::PI / 3.0) { // near side + ue.fill(HIST(hPhi[0]), dPhi); ue.fill(HIST(hPtVsPtLeadingData[0]), flPt, track.pt()); - nchm_top[0]++; - sumptm_top[0] += track.pt(); - } else if (TMath::Abs(DPhi - M_PI) < M_PI / 3.0) { // away side - ue.fill(HIST(hPhi[1]), DPhi); + nchmTop[0]++; + sumptmTop[0] += track.pt(); + } else if (std::abs(dPhi - o2::constants::math::PI) < + o2::constants::math::PI / 3.0) { // away side + ue.fill(HIST(hPhi[1]), dPhi); ue.fill(HIST(hPtVsPtLeadingData[1]), flPt, track.pt()); - nchm_top[1]++; - sumptm_top[1] += track.pt(); + nchmTop[1]++; + sumptmTop[1] += track.pt(); } else { // transverse side - ue.fill(HIST(hPhi[2]), DPhi); + ue.fill(HIST(hPhi[2]), dPhi); ue.fill(HIST(hPtVsPtLeadingData[2]), flPt, track.pt()); - nchm_top[2]++; - sumptm_top[2] += track.pt(); + nchmTop[2]++; + sumptmTop[2] += track.pt(); } } } for (int i_reg = 0; i_reg < 3; ++i_reg) { - ue_rec.push_back(1.0 * nchm_top[i_reg]); + ueRec.push_back(1.0 * nchmTop[i_reg]); } for (int i_reg = 0; i_reg < 3; ++i_reg) { - ue_rec.push_back(sumptm_top[i_reg]); + ueRec.push_back(sumptmTop[i_reg]); } // add flags for Vtx, PS, ev sel - ue.fill(HIST(pNumDenMeasuredPS[0]), flPt, ue_rec[0]); - ue.fill(HIST(pNumDenData[0]), flPt, ue_rec[0]); - ue.fill(HIST(pSumPtMeasuredPS[0]), flPt, ue_rec[3]); - ue.fill(HIST(pSumPtData[0]), flPt, ue_rec[3]); + ue.fill(HIST(pNumDenMeasuredPS[0]), flPt, ueRec[0]); + ue.fill(HIST(pNumDenData[0]), flPt, ueRec[0]); + ue.fill(HIST(pSumPtMeasuredPS[0]), flPt, ueRec[3]); + ue.fill(HIST(pSumPtData[0]), flPt, ueRec[3]); - ue.fill(HIST(pNumDenMeasuredPS[1]), flPt, ue_rec[1]); - ue.fill(HIST(pNumDenData[1]), flPt, ue_rec[1]); - ue.fill(HIST(pSumPtMeasuredPS[1]), flPt, ue_rec[4]); - ue.fill(HIST(pSumPtData[1]), flPt, ue_rec[4]); + ue.fill(HIST(pNumDenMeasuredPS[1]), flPt, ueRec[1]); + ue.fill(HIST(pNumDenData[1]), flPt, ueRec[1]); + ue.fill(HIST(pSumPtMeasuredPS[1]), flPt, ueRec[4]); + ue.fill(HIST(pSumPtData[1]), flPt, ueRec[4]); - ue.fill(HIST(pNumDenMeasuredPS[2]), flPt, ue_rec[2]); - ue.fill(HIST(pNumDenData[2]), flPt, ue_rec[2]); - ue.fill(HIST(pSumPtMeasuredPS[2]), flPt, ue_rec[5]); - ue.fill(HIST(pSumPtData[2]), flPt, ue_rec[5]); + ue.fill(HIST(pNumDenMeasuredPS[2]), flPt, ueRec[2]); + ue.fill(HIST(pNumDenData[2]), flPt, ueRec[2]); + ue.fill(HIST(pSumPtMeasuredPS[2]), flPt, ueRec[5]); + ue.fill(HIST(pSumPtData[2]), flPt, ueRec[5]); ue.fill(HIST("hPtLeadingData"), flPt); // Compute data driven (DD) missidentification correction - Float_t flPtdd = 0; // leading pT - Float_t flPhidd = 0; + float flPtdd = 0; // leading pT + float flPhidd = 0; int flIndexdd = 0; int ntrkdd = ptArray.size(); @@ -576,47 +826,48 @@ void ueCharged::processMeas(const C& collision, const T& tracks) flIndexdd = indexArray[i]; } } - int nchm_topdd[3]; - double sumptm_topdd[3]; + int nchmTopdd[3]; + double sumptmTopdd[3]; for (int i = 0; i < 3; ++i) { - nchm_topdd[i] = 0; - sumptm_topdd[i] = 0; + nchmTopdd[i] = 0; + sumptmTopdd[i] = 0; } for (int i = 0; i < ntrkdd; ++i) { if (indexArray[i] == flIndexdd) { continue; } - double DPhi = DeltaPhi(phiArray[i], flPhidd); - if (TMath::Abs(DPhi) < M_PI / 3.0) { // near side - nchm_topdd[0]++; - sumptm_topdd[0] += ptArray[i]; - } else if (TMath::Abs(DPhi - M_PI) < M_PI / 3.0) { // away side - nchm_topdd[1]++; - sumptm_topdd[1] += ptArray[i]; + double dPhi = deltaPhi(phiArray[i], flPhidd); + if (std::abs(dPhi) < o2::constants::math::PI / 3.0) { // near side + nchmTopdd[0]++; + sumptmTopdd[0] += ptArray[i]; + } else if (std::abs(dPhi - o2::constants::math::PI) < + o2::constants::math::PI / 3.0) { // away side + nchmTopdd[1]++; + sumptmTopdd[1] += ptArray[i]; } else { // transverse side - nchm_topdd[2]++; - sumptm_topdd[2] += ptArray[i]; + nchmTopdd[2]++; + sumptmTopdd[2] += ptArray[i]; } } - ue.fill(HIST(hNumDenMCDd[0]), flPtdd, nchm_topdd[0]); - ue.fill(HIST(hSumPtMCDd[0]), flPtdd, sumptm_topdd[0]); + ue.fill(HIST(hNumDenMCDd[0]), flPtdd, nchmTopdd[0]); + ue.fill(HIST(hSumPtMCDd[0]), flPtdd, sumptmTopdd[0]); - ue.fill(HIST(hNumDenMCDd[1]), flPtdd, nchm_topdd[1]); - ue.fill(HIST(hSumPtMCDd[1]), flPtdd, sumptm_topdd[1]); + ue.fill(HIST(hNumDenMCDd[1]), flPtdd, nchmTopdd[1]); + ue.fill(HIST(hSumPtMCDd[1]), flPtdd, sumptmTopdd[1]); - ue.fill(HIST(hNumDenMCDd[2]), flPtdd, nchm_topdd[2]); - ue.fill(HIST(hSumPtMCDd[2]), flPtdd, sumptm_topdd[2]); + ue.fill(HIST(hNumDenMCDd[2]), flPtdd, nchmTopdd[2]); + ue.fill(HIST(hSumPtMCDd[2]), flPtdd, sumptmTopdd[2]); if (flIndexdd == flIndex) { - ue.fill(HIST(hNumDenMCMatchDd[0]), flPtdd, nchm_topdd[0]); - ue.fill(HIST(hSumPtMCMatchDd[0]), flPtdd, sumptm_topdd[0]); + ue.fill(HIST(hNumDenMCMatchDd[0]), flPtdd, nchmTopdd[0]); + ue.fill(HIST(hSumPtMCMatchDd[0]), flPtdd, sumptmTopdd[0]); - ue.fill(HIST(hNumDenMCMatchDd[1]), flPtdd, nchm_topdd[1]); - ue.fill(HIST(hSumPtMCMatchDd[1]), flPtdd, sumptm_topdd[1]); + ue.fill(HIST(hNumDenMCMatchDd[1]), flPtdd, nchmTopdd[1]); + ue.fill(HIST(hSumPtMCMatchDd[1]), flPtdd, sumptmTopdd[1]); - ue.fill(HIST(hNumDenMCMatchDd[2]), flPtdd, nchm_topdd[2]); - ue.fill(HIST(hSumPtMCMatchDd[2]), flPtdd, sumptm_topdd[2]); + ue.fill(HIST(hNumDenMCMatchDd[2]), flPtdd, nchmTopdd[2]); + ue.fill(HIST(hSumPtMCMatchDd[2]), flPtdd, sumptmTopdd[2]); } ptArray.clear(); phiArray.clear(); @@ -624,10 +875,17 @@ void ueCharged::processMeas(const C& collision, const T& tracks) } template -void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& particles) +void ueCharged::processMeasMC(const C& collision, const T& tracks, + const P& particles) { - ue.fill(HIST("hCounter"), 0); + if (cfgINELCut == 1 && !o2::pwglf::isINELgt0mc(particles, pdg)) { + return; + } + + if (cfgINELCut == 2 && !o2::pwglf::isINELgt1mc(particles, pdg)) { + return; + } ue.fill(HIST("hStat"), collision.size()); auto vtxZ = collision.posZ(); @@ -637,7 +895,7 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part double flPhiTrue = 0; int flIndexTrue = 0; - for (auto& particle : particles) { + for (const auto& particle : particles) { auto pdgParticle = pdg->GetParticle(particle.pdgCode()); if (!pdgParticle || pdgParticle->Charge() == 0.) { continue; @@ -660,19 +918,19 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part } } // ue.fill(HIST("hmultTrue"), multTrue); - std::vector ue_true; - ue_true.clear(); - int nchm_toptrue[3]; - double sumptm_toptrue[3]; + std::vector ueTrue; + ueTrue.clear(); + int nchmTopTrue[3]; + double sumptmTopTrue[3]; for (int i = 0; i < 3; ++i) { - nchm_toptrue[i] = 0; - sumptm_toptrue[i] = 0; + nchmTopTrue[i] = 0; + sumptmTopTrue[i] = 0; } - std::vector ptArrayTrue; - std::vector phiArrayTrue; + std::vector ptArrayTrue; + std::vector phiArrayTrue; std::vector indexArrayTrue; - for (auto& particle : particles) { + for (const auto& particle : particles) { auto pdgParticle = pdg->GetParticle(particle.pdgCode()); if (!pdgParticle || pdgParticle->Charge() == 0.) { @@ -691,81 +949,99 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part if (flIndexTrue == particle.globalIndex()) { continue; } - double DPhi = DeltaPhi(particle.phi(), flPhiTrue); + double dPhi = deltaPhi(particle.phi(), flPhiTrue); // definition of the topological regions - if (TMath::Abs(DPhi) < M_PI / 3.0) { // near side - nchm_toptrue[0]++; - sumptm_toptrue[0] += particle.pt(); - } else if (TMath::Abs(DPhi - M_PI) < M_PI / 3.0) { // away side - nchm_toptrue[1]++; - sumptm_toptrue[1] += particle.pt(); + if (std::abs(dPhi) < o2::constants::math::PI / 3.0) { // near side + nchmTopTrue[0]++; + sumptmTopTrue[0] += particle.pt(); + } else if (std::abs(dPhi - o2::constants::math::PI) < + o2::constants::math::PI / 3.0) { // away side + nchmTopTrue[1]++; + sumptmTopTrue[1] += particle.pt(); } else { // transverse side - nchm_toptrue[2]++; - sumptm_toptrue[2] += particle.pt(); + nchmTopTrue[2]++; + sumptmTopTrue[2] += particle.pt(); } } for (int i_reg = 0; i_reg < 3; ++i_reg) { - ue_true.push_back(1.0 * nchm_toptrue[i_reg]); + ueTrue.push_back(1.0 * nchmTopTrue[i_reg]); } for (int i_reg = 0; i_reg < 3; ++i_reg) { - ue_true.push_back(sumptm_toptrue[i_reg]); + ueTrue.push_back(sumptmTopTrue[i_reg]); } - ue.fill(HIST(pNumDenTrue[0]), flPtTrue, ue_true[0]); - ue.fill(HIST(pSumPtTrue[0]), flPtTrue, ue_true[3]); + ue.fill(HIST(pNumDenTrue[0]), flPtTrue, ueTrue[0]); + ue.fill(HIST(pSumPtTrue[0]), flPtTrue, ueTrue[3]); - ue.fill(HIST(pNumDenTrue[1]), flPtTrue, ue_true[1]); - ue.fill(HIST(pSumPtTrue[1]), flPtTrue, ue_true[4]); + ue.fill(HIST(pNumDenTrue[1]), flPtTrue, ueTrue[1]); + ue.fill(HIST(pSumPtTrue[1]), flPtTrue, ueTrue[4]); - ue.fill(HIST(pNumDenTrue[2]), flPtTrue, ue_true[2]); - ue.fill(HIST(pSumPtTrue[2]), flPtTrue, ue_true[5]); + ue.fill(HIST(pNumDenTrue[2]), flPtTrue, ueTrue[2]); + ue.fill(HIST(pSumPtTrue[2]), flPtTrue, ueTrue[5]); ptArrayTrue.clear(); phiArrayTrue.clear(); indexArrayTrue.clear(); - if (!collision.sel8()) { + ue.fill(HIST("hCounter"), 0); + + if (cfgINELCut == 1 && !collision.isInelGt0()) { return; } + + if (cfgINELCut == 2 && !collision.isInelGt1()) { + return; + } + ue.fill(HIST("hCounter"), 1); - if (timeEvsel && (!collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder))) { + + if (sel8 && !collision.sel8()) { + return; + } + + if (removeITSROFBorder && + (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || + !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { return; } ue.fill(HIST("hCounter"), 2); - if (piluprejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + + if (piluprejection && + !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { return; } ue.fill(HIST("hCounter"), 3); - if (goodzvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + + if (goodzvertex && + !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { return; } + ue.fill(HIST("hCounter"), 4); - // only PS if ((std::abs(collision.posZ()) >= 10.f)) { return; } - ue.fill(HIST("hCounter"), 5); - ue.fill(HIST(pNumDenTruePS[0]), flPtTrue, ue_true[0]); - ue.fill(HIST(pSumPtTruePS[0]), flPtTrue, ue_true[3]); + ue.fill(HIST("hCounter"), 5); - ue.fill(HIST(pNumDenTruePS[1]), flPtTrue, ue_true[1]); - ue.fill(HIST(pSumPtTruePS[1]), flPtTrue, ue_true[4]); + ue.fill(HIST(pNumDenTruePS[0]), flPtTrue, ueTrue[0]); + ue.fill(HIST(pSumPtTruePS[0]), flPtTrue, ueTrue[3]); - ue.fill(HIST(pNumDenTruePS[2]), flPtTrue, ue_true[2]); - ue.fill(HIST(pSumPtTruePS[2]), flPtTrue, ue_true[5]); + ue.fill(HIST(pNumDenTruePS[1]), flPtTrue, ueTrue[1]); + ue.fill(HIST(pSumPtTruePS[1]), flPtTrue, ueTrue[4]); - // ue.fill(HIST("hCounter"), 2); + ue.fill(HIST(pNumDenTruePS[2]), flPtTrue, ueTrue[2]); + ue.fill(HIST(pSumPtTruePS[2]), flPtTrue, ueTrue[5]); ue.fill(HIST("hvtxZ"), vtxZ); // loop over MC true particles int multTrue = 0; - for (auto& particle : particles) { + for (const auto& particle : particles) { auto pdgParticle = pdg->GetParticle(particle.pdgCode()); if (!pdgParticle || pdgParticle->Charge() == 0.) { continue; @@ -781,7 +1057,24 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part continue; } ue.fill(HIST("hPtInPrim"), particle.pt()); + + // remove the autocorrelation + if (flIndexTrue == particle.globalIndex()) { + continue; + } + double dPhi = deltaPhi(particle.phi(), flPhiTrue); + + // definition of the topological regions + if (std::abs(dPhi) < o2::constants::math::PI / 3.0) { // near side + ue.fill(HIST(hPtVsPtLeadingTruePS[0]), flPtTrue, particle.pt()); + } else if (std::abs(dPhi - o2::constants::math::PI) < + o2::constants::math::PI / 3.0) { // away side + ue.fill(HIST(hPtVsPtLeadingTruePS[1]), flPtTrue, particle.pt()); + } else { // transverse side + ue.fill(HIST(hPtVsPtLeadingTruePS[2]), flPtTrue, particle.pt()); + } } + ue.fill(HIST("hmultTrue"), multTrue); // loop over selected tracks @@ -789,11 +1082,13 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part double flPhi = 0; int flIndex = 0; int multRec = 0; - for (auto& track : tracks) { + int track_multiplicity = 0; + + for (const auto& track : tracks) { if (!mySelectionPrim.IsSelected(track)) { continue; } - + track_multiplicity++; ue.fill(HIST("hdNdeta"), track.eta()); ue.fill(HIST("vtxZEta"), track.eta(), vtxZ); ue.fill(HIST("phiEta"), track.eta(), track.phi()); @@ -805,22 +1100,24 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part flIndex = track.globalIndex(); } } + + ue.fill(HIST("hPtLeadingVsTracks"), flPt, track_multiplicity); ue.fill(HIST("hmultRec"), multRec); ue.fill(HIST("hPtLeadingMeasured"), flPt); ue.fill(HIST("hPtLeadingRecPS"), flPt); - std::vector ue_rec; - ue_rec.clear(); - int nchm_top[3]; - double sumptm_top[3]; + std::vector ueRec; + ueRec.clear(); + int nchmTop[3]; + double sumptmTop[3]; for (int i = 0; i < 3; ++i) { - nchm_top[i] = 0; - sumptm_top[i] = 0; + nchmTop[i] = 0; + sumptmTop[i] = 0; } - std::vector ptArray; - std::vector phiArray; + std::vector ptArray; + std::vector phiArray; std::vector indexArray; - for (auto& track : tracks) { + for (const auto& track : tracks) { if (mySelectionOpenDCA.IsSelected(track)) { // TODO: set cuts w/o DCA cut ue.fill(HIST("hPTVsDCAData"), track.pt(), track.dcaXY()); @@ -833,7 +1130,7 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part if (mySelectionOpenDCA.IsSelected(track)) { ue.fill(HIST("hPtDCAall"), track.pt(), track.dcaXY()); } - const auto& particle = track.template mcParticle_as(); + const auto& particle = track.mcParticle(); if (particle.isPhysicalPrimary()) { if (mySelectionPrim.IsSelected(track)) { @@ -849,7 +1146,8 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part ue.fill(HIST("hPtOutSec"), track.pt()); } if (mySelectionOpenDCA.IsSelected(track)) { - if (particle.producedByGenerator()) { // i guess these are from decays + if (particle + .producedByGenerator()) { // i guess these are from decays ue.fill(HIST("hPtDCAWeak"), track.pt(), track.dcaXY()); } else { //// i guess these are from material ue.fill(HIST("hPtDCAMat"), track.pt(), track.dcaXY()); @@ -861,7 +1159,7 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part if (mySelectionPrim.IsSelected(track)) { // applying the efficiency twice for the misrec of leading particle - if (f_Eff->Eval(track.pt()) > gRandom->Uniform(0, 1)) { + if (fEff->Eval(track.pt()) > gRandom->Uniform(0, 1)) { ptArray.push_back(track.pt()); phiArray.push_back(track.phi()); indexArray.push_back(track.globalIndex()); @@ -872,55 +1170,56 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part continue; } - double DPhi = DeltaPhi(track.phi(), flPhi); + double dPhi = deltaPhi(track.phi(), flPhi); // definition of the topological regions - if (TMath::Abs(DPhi) < M_PI / 3.0) { // near side - ue.fill(HIST(hPhi[0]), DPhi); + if (std::abs(dPhi) < o2::constants::math::PI / 3.0) { // near side + ue.fill(HIST(hPhi[0]), dPhi); ue.fill(HIST(hPtVsPtLeadingData[0]), flPt, track.pt()); - nchm_top[0]++; - sumptm_top[0] += track.pt(); - } else if (TMath::Abs(DPhi - M_PI) < M_PI / 3.0) { // away side - ue.fill(HIST(hPhi[1]), DPhi); + nchmTop[0]++; + sumptmTop[0] += track.pt(); + } else if (std::abs(dPhi - o2::constants::math::PI) < + o2::constants::math::PI / 3.0) { // away side + ue.fill(HIST(hPhi[1]), dPhi); ue.fill(HIST(hPtVsPtLeadingData[1]), flPt, track.pt()); - nchm_top[1]++; - sumptm_top[1] += track.pt(); + nchmTop[1]++; + sumptmTop[1] += track.pt(); } else { // transverse side - ue.fill(HIST(hPhi[2]), DPhi); + ue.fill(HIST(hPhi[2]), dPhi); ue.fill(HIST(hPtVsPtLeadingData[2]), flPt, track.pt()); - nchm_top[2]++; - sumptm_top[2] += track.pt(); + nchmTop[2]++; + sumptmTop[2] += track.pt(); } } } for (int i_reg = 0; i_reg < 3; ++i_reg) { - ue_rec.push_back(1.0 * nchm_top[i_reg]); + ueRec.push_back(1.0 * nchmTop[i_reg]); } for (int i_reg = 0; i_reg < 3; ++i_reg) { - ue_rec.push_back(sumptm_top[i_reg]); + ueRec.push_back(sumptmTop[i_reg]); } // add flags for Vtx, PS, ev sel - ue.fill(HIST(pNumDenMeasuredPS[0]), flPt, ue_rec[0]); - ue.fill(HIST(pNumDenData[0]), flPt, ue_rec[0]); - ue.fill(HIST(pSumPtMeasuredPS[0]), flPt, ue_rec[3]); - ue.fill(HIST(pSumPtData[0]), flPt, ue_rec[3]); + ue.fill(HIST(pNumDenMeasuredPS[0]), flPt, ueRec[0]); + ue.fill(HIST(pNumDenData[0]), flPt, ueRec[0]); + ue.fill(HIST(pSumPtMeasuredPS[0]), flPt, ueRec[3]); + ue.fill(HIST(pSumPtData[0]), flPt, ueRec[3]); - ue.fill(HIST(pNumDenMeasuredPS[1]), flPt, ue_rec[1]); - ue.fill(HIST(pNumDenData[1]), flPt, ue_rec[1]); - ue.fill(HIST(pSumPtMeasuredPS[1]), flPt, ue_rec[4]); - ue.fill(HIST(pSumPtData[1]), flPt, ue_rec[4]); + ue.fill(HIST(pNumDenMeasuredPS[1]), flPt, ueRec[1]); + ue.fill(HIST(pNumDenData[1]), flPt, ueRec[1]); + ue.fill(HIST(pSumPtMeasuredPS[1]), flPt, ueRec[4]); + ue.fill(HIST(pSumPtData[1]), flPt, ueRec[4]); - ue.fill(HIST(pNumDenMeasuredPS[2]), flPt, ue_rec[2]); - ue.fill(HIST(pNumDenData[2]), flPt, ue_rec[2]); - ue.fill(HIST(pSumPtMeasuredPS[2]), flPt, ue_rec[5]); - ue.fill(HIST(pSumPtData[2]), flPt, ue_rec[5]); + ue.fill(HIST(pNumDenMeasuredPS[2]), flPt, ueRec[2]); + ue.fill(HIST(pNumDenData[2]), flPt, ueRec[2]); + ue.fill(HIST(pSumPtMeasuredPS[2]), flPt, ueRec[5]); + ue.fill(HIST(pSumPtData[2]), flPt, ueRec[5]); ue.fill(HIST("hPtLeadingData"), flPt); // Compute data driven (DD) missidentification correction - Float_t flPtdd = 0; // leading pT - Float_t flPhidd = 0; + float flPtdd = 0; // leading pT + float flPhidd = 0; int flIndexdd = 0; int ntrkdd = ptArray.size(); @@ -931,49 +1230,187 @@ void ueCharged::processMeasMC(const C& collision, const T& tracks, const P& part flIndexdd = indexArray[i]; } } - int nchm_topdd[3]; - double sumptm_topdd[3]; + int nchmTopdd[3]; + double sumptmTopdd[3]; for (int i = 0; i < 3; ++i) { - nchm_topdd[i] = 0; - sumptm_topdd[i] = 0; + nchmTopdd[i] = 0; + sumptmTopdd[i] = 0; } for (int i = 0; i < ntrkdd; ++i) { if (indexArray[i] == flIndexdd) { continue; } - double DPhi = DeltaPhi(phiArray[i], flPhidd); - if (TMath::Abs(DPhi) < M_PI / 3.0) { // near side - nchm_topdd[0]++; - sumptm_topdd[0] += ptArray[i]; - } else if (TMath::Abs(DPhi - M_PI) < M_PI / 3.0) { // away side - nchm_topdd[1]++; - sumptm_topdd[1] += ptArray[i]; + double dPhi = deltaPhi(phiArray[i], flPhidd); + if (std::abs(dPhi) < o2::constants::math::PI / 3.0) { // near side + nchmTopdd[0]++; + sumptmTopdd[0] += ptArray[i]; + } else if (std::abs(dPhi - o2::constants::math::PI) < + o2::constants::math::PI / 3.0) { // away side + nchmTopdd[1]++; + sumptmTopdd[1] += ptArray[i]; } else { // transverse side - nchm_topdd[2]++; - sumptm_topdd[2] += ptArray[i]; + nchmTopdd[2]++; + sumptmTopdd[2] += ptArray[i]; } } - ue.fill(HIST(hNumDenMCDd[0]), flPtdd, nchm_topdd[0]); - ue.fill(HIST(hSumPtMCDd[0]), flPtdd, sumptm_topdd[0]); + ue.fill(HIST(hNumDenMCDd[0]), flPtdd, nchmTopdd[0]); + ue.fill(HIST(hSumPtMCDd[0]), flPtdd, sumptmTopdd[0]); - ue.fill(HIST(hNumDenMCDd[1]), flPtdd, nchm_topdd[1]); - ue.fill(HIST(hSumPtMCDd[1]), flPtdd, sumptm_topdd[1]); + ue.fill(HIST(hNumDenMCDd[1]), flPtdd, nchmTopdd[1]); + ue.fill(HIST(hSumPtMCDd[1]), flPtdd, sumptmTopdd[1]); - ue.fill(HIST(hNumDenMCDd[2]), flPtdd, nchm_topdd[2]); - ue.fill(HIST(hSumPtMCDd[2]), flPtdd, sumptm_topdd[2]); + ue.fill(HIST(hNumDenMCDd[2]), flPtdd, nchmTopdd[2]); + ue.fill(HIST(hSumPtMCDd[2]), flPtdd, sumptmTopdd[2]); if (flIndexdd == flIndex) { - ue.fill(HIST(hNumDenMCMatchDd[0]), flPtdd, nchm_topdd[0]); - ue.fill(HIST(hSumPtMCMatchDd[0]), flPtdd, sumptm_topdd[0]); + ue.fill(HIST(hNumDenMCMatchDd[0]), flPtdd, nchmTopdd[0]); + ue.fill(HIST(hSumPtMCMatchDd[0]), flPtdd, sumptmTopdd[0]); - ue.fill(HIST(hNumDenMCMatchDd[1]), flPtdd, nchm_topdd[1]); - ue.fill(HIST(hSumPtMCMatchDd[1]), flPtdd, sumptm_topdd[1]); + ue.fill(HIST(hNumDenMCMatchDd[1]), flPtdd, nchmTopdd[1]); + ue.fill(HIST(hSumPtMCMatchDd[1]), flPtdd, sumptmTopdd[1]); - ue.fill(HIST(hNumDenMCMatchDd[2]), flPtdd, nchm_topdd[2]); - ue.fill(HIST(hSumPtMCMatchDd[2]), flPtdd, sumptm_topdd[2]); + ue.fill(HIST(hNumDenMCMatchDd[2]), flPtdd, nchmTopdd[2]); + ue.fill(HIST(hSumPtMCMatchDd[2]), flPtdd, sumptmTopdd[2]); } ptArray.clear(); phiArray.clear(); indexArray.clear(); } + +template +void ueCharged::analyzeEventAndTrackSelection(const C& collision, + const T& tracks) +{ + + if (cfgINELCut == 1 && !collision.isInelGt0()) { + return; + } + + if (cfgINELCut == 2 && !collision.isInelGt1()) { + return; + } + + // z-vertex from FT0 vs PV analysis + + const auto& foundBC = collision.template foundBC_as(); + + if (foundBC.has_ft0()) { + ue.fill(HIST("hVtxFT0VsVtxCol"), foundBC.ft0().posZ(), collision.posZ()); + } + + ue.fill(HIST("hvtxZ_before"), collision.posZ()); + + if (sel8 && !collision.sel8()) { + return; + } + + if (removeITSROFBorder && + (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX) || + !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { + return; + } + + if (foundBC.has_ft0()) { + ue.fill(HIST("hVtxFT0VsVtxCol_afterSel8"), foundBC.ft0().posZ(), + collision.posZ()); + } + + if (piluprejection && + !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } + + if (foundBC.has_ft0()) { + ue.fill(HIST("hVtxFT0VsVtxCol_afterPile"), foundBC.ft0().posZ(), + collision.posZ()); + } + + if (goodzvertex && + !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + + if (foundBC.has_ft0()) { + ue.fill(HIST("hVtxFT0VsVtxCol_afterGoodZvtx"), foundBC.ft0().posZ(), + collision.posZ()); + } + + ue.fill(HIST("hvtxZ_after"), collision.posZ()); + + // analysis of the track selection + + int tracks_before = 0; + int tracks_after = 0; + + for (auto& track : tracks) { + + if (track.hasITS() && track.hasTPC()) { + ue.fill(HIST("preselection_track/ITS/itsNCls"), track.itsNCls()); + ue.fill(HIST("preselection_track/ITS/itsChi2NCl"), track.itsChi2NCl()); + ue.fill(HIST("preselection_track/ITS/itsClusterMap"), + track.itsClusterMap()); + ue.fill(HIST("preselection_track/TPC/tpcNClsFindable"), + track.tpcNClsFindable()); + ue.fill(HIST("preselection_track/TPC/tpcNClsFound"), + track.tpcNClsFound()); + ue.fill(HIST("preselection_track/TPC/tpcNClsShared"), + track.tpcNClsShared()); + ue.fill(HIST("preselection_track/TPC/tpcCrossedRows"), + track.tpcNClsCrossedRows()); + ue.fill(HIST("preselection_track/TPC/tpcCrossedRowsOverFindableCls"), + track.tpcCrossedRowsOverFindableCls()); + ue.fill(HIST("preselection_track/TPC/tpcFractionSharedCls"), + track.tpcFractionSharedCls()); + ue.fill(HIST("preselection_track/TPC/tpcChi2NCl"), track.tpcChi2NCl()); + ue.fill(HIST("preselection_track/hvtxZ"), track.dcaZ()); + ue.fill(HIST("preselection_track/hvtxXY"), track.dcaXY()); + tracks_before++; + } + + if (mySelectionPrim.IsSelected(track)) { + if (track.hasITS() && track.hasTPC()) { + ue.fill(HIST("postselection_track/ITS/itsNCls"), track.itsNCls()); + ue.fill(HIST("postselection_track/ITS/itsChi2NCl"), track.itsChi2NCl()); + ue.fill(HIST("postselection_track/ITS/itsClusterMap"), + track.itsClusterMap()); + ue.fill(HIST("postselection_track/TPC/tpcNClsFindable"), + track.tpcNClsFindable()); + ue.fill(HIST("postselection_track/TPC/tpcNClsFound"), + track.tpcNClsFound()); + ue.fill(HIST("postselection_track/TPC/tpcNClsShared"), + track.tpcNClsShared()); + ue.fill(HIST("postselection_track/TPC/tpcCrossedRows"), + track.tpcNClsCrossedRows()); + ue.fill(HIST("postselection_track/TPC/tpcCrossedRowsOverFindableCls"), + track.tpcCrossedRowsOverFindableCls()); + ue.fill(HIST("postselection_track/TPC/tpcFractionSharedCls"), + track.tpcFractionSharedCls()); + ue.fill(HIST("postselection_track/TPC/tpcChi2NCl"), track.tpcChi2NCl()); + ue.fill(HIST("postselection_track/hvtxZ"), track.dcaZ()); + ue.fill(HIST("postselection_track/hvtxXY"), track.dcaXY()); + tracks_after++; + } + } + } + + ue.fill(HIST("postselection_track/htracks"), tracks_after); + ue.fill(HIST("preselection_track/htracks"), tracks_before); + + // FT0 + float multT0A = foundBC.has_ft0() ? foundBC.ft0().sumAmpA() : -999.f; + float multT0C = foundBC.has_ft0() ? foundBC.ft0().sumAmpC() : -999.f; + + // z-vertex from FT0 vs PV + if (foundBC.has_ft0()) { + ue.fill(HIST("hVtxFT0MinusVtxColVsMultT0M"), + foundBC.ft0().posZ() - collision.posZ(), multT0A + multT0C); + } + + ue.fill(HIST("postselection_track/hT0MVsTracks"), multT0A + multT0C, + tracks_after); + ue.fill(HIST("postselection_track/hVtxFT0VsTracks"), foundBC.ft0().posZ(), + tracks_after); + ue.fill(HIST("postselection_track/hVtxVsTracks"), collision.posZ(), + tracks_after); +} diff --git a/PWGUD/AQC/CMakeLists.txt b/PWGUD/AQC/CMakeLists.txt index d7574e1bcb1..134d2db4bfc 100644 --- a/PWGUD/AQC/CMakeLists.txt +++ b/PWGUD/AQC/CMakeLists.txt @@ -22,4 +22,9 @@ o2physics_add_dpl_workflow(fittest o2physics_add_dpl_workflow(udqcmidrap SOURCES udQCmidRap.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGCutparHolder - COMPONENT_NAME Analysis) \ No newline at end of file + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(ud-qc-muon + SOURCES udQcMuon.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGCutparHolder + COMPONENT_NAME Analysis) diff --git a/PWGUD/AQC/FITtest.cxx b/PWGUD/AQC/FITtest.cxx index bdeaaa34426..8cada664d74 100644 --- a/PWGUD/AQC/FITtest.cxx +++ b/PWGUD/AQC/FITtest.cxx @@ -13,18 +13,20 @@ /// \author Anisa Khatun, anisa.khatun@cern.ch /// \since 04.08.2023 -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "ReconstructionDataFormats/BCRange.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "CommonConstants/LHCConstants.h" +#include "CommonConstants/LHCConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/BCRange.h" + #include "TLorentzVector.h" using namespace o2; diff --git a/PWGUD/AQC/udQC.cxx b/PWGUD/AQC/udQC.cxx index b3bc5198a0f..3da67d1f683 100644 --- a/PWGUD/AQC/udQC.cxx +++ b/PWGUD/AQC/udQC.cxx @@ -14,6 +14,7 @@ /// \author Paul Buehler, paul.buehler@oeaw.ac.at /// \since 04.05.2023 +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" @@ -68,6 +69,8 @@ struct UDQC { using ATs = aod::AmbiguousTracks; using AFTs = aod::AmbiguousFwdTracks; + Partition goodTracks = requireGlobalTrackInFilter(); + void init(InitContext& context) { // initialize global variables @@ -191,8 +194,13 @@ struct UDQC { aod::Zdcs& zdcs, aod::Calos& calos, aod::V0s const& v0s, aod::Cascades const& cascades) { - LOGF(debug, " Start %i", abcrs.size()); + // LOGF(debug, " Start %i", abcrs.size()); + + if (!tracks.size()) + return; + if (collision.numContrib() < 1) + return; bool isDGcandidate = true; registry.get(HIST("collisions/Stat"))->Fill(0., isDGcandidate * 1.); @@ -214,7 +222,7 @@ struct UDQC { // vertex tracks normally gives PV contributors from collisions registry.get(HIST("collisions/vtxTracks"))->Fill(collision.numContrib()); // global tracks - Partition goodTracks = requireGlobalTrackInFilter(); + // Partition goodTracks = requireGlobalTrackInFilter(); goodTracks.bindTable(tracks); registry.get(HIST("collisions/globalTracks"))->Fill(goodTracks.size()); @@ -248,7 +256,7 @@ struct UDQC { if (track.tpcSignal() > maxdEdxTPC) { maxdEdxTPC = track.tpcSignal(); - LOGF(debug, " New maxdEdx TPC %f", maxdEdxTPC); + // LOGF(debug, " New maxdEdx TPC %f", maxdEdxTPC); } // TOF hit? @@ -256,7 +264,7 @@ struct UDQC { registry.get(HIST("tracks/dEdxTOF"))->Fill(track.p() / track.sign(), track.beta()); if (track.tofSignal() > maxdEdxTOF) { maxdEdxTOF = track.tofSignal(); - LOGF(debug, " New maxdEdx TOF %f", maxdEdxTOF); + // LOGF(debug, " New maxdEdx TOF %f", maxdEdxTOF); } // No vertex track with TOF hit? @@ -281,7 +289,7 @@ struct UDQC { if (collision.numContrib() > 0) { rgtrwTOF /= collision.numContrib(); } - LOGF(debug, " PV tracks with TOF: %f [1]", rgtrwTOF); + // LOGF(debug, " PV tracks with TOF: %f [1]", rgtrwTOF); registry.get(HIST("collisions/tResvsrTOFTracks"))->Fill(collision.collisionTimeRes(), rgtrwTOF); registry.get(HIST("collisions/tResvsTOFTrkNoPV"))->Fill(collision.collisionTimeRes(), norgtrwTOF); @@ -429,7 +437,7 @@ struct UDQC { } // 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()); + // 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; } @@ -521,7 +529,7 @@ struct UDQC { registry.get(HIST("DG/etaminus"))->Fill(track.eta(), track.phi()); } - LOGF(debug, "dEdx TPC %f TOF %i %f", track.tpcSignal(), track.hasTOF(), track.hasTOF() ? track.tofSignal() : 0.); + // LOGF(debug, "dEdx TPC %f TOF %i %f", track.tpcSignal(), track.hasTOF(), track.hasTOF() ? track.tofSignal() : 0.); if (collision.numContrib() == 2) { registry.get(HIST("DG/dEdxTPC"))->Fill(track.tpcInnerParam() / track.sign(), track.tpcSignal()); registry.get(HIST("DG/trkDCAxy"))->Fill(track.dcaXY()); @@ -562,7 +570,7 @@ struct UDQC { void processCleanFIT1(CC const& collision, BCs const& bct0s, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, aod::FDDs const& /*fdds*/) { - LOGF(debug, "(); @@ -677,7 +685,7 @@ struct UDQC { // ............................................................................................................... void processFV0(aod::FV0As const& fv0s, BCs const&) { - LOGF(info, " %d", fv0s.size()); + // LOGF(info, " %d", fv0s.size()); if (fv0s.size() <= 0) { return; } @@ -695,7 +703,7 @@ struct UDQC { // ............................................................................................................... void processFT0(aod::FT0s const& ft0s, aod::FT0sCorrected const& ft0scorr, BCs const&) { - LOGF(debug, " %d", ft0s.size()); + // LOGF(debug, " %d", ft0s.size()); for (auto const& collision : ft0scorr) { if (collision.t0ACorrectedValid()) { @@ -729,7 +737,7 @@ struct UDQC { // ............................................................................................................... void processFDD(aod::FDDs const& fdds, BCs const&) { - LOGF(debug, " %d", fdds.size()); + // LOGF(debug, " %d", fdds.size()); for (auto fdd : fdds) { @@ -751,7 +759,7 @@ struct UDQC { // ............................................................................................................... void processZDC(aod::Zdc const& zdc) { - LOGF(debug, " %d", zdc.size()); + // LOGF(debug, " %d", zdc.size()); // Zdc energies registry.get(HIST("ZdcEnergies"))->Fill(0., zdc.energyZEM1()); diff --git a/PWGUD/AQC/udQCmidRap.cxx b/PWGUD/AQC/udQCmidRap.cxx index e7178cfa042..acb35f21f57 100644 --- a/PWGUD/AQC/udQCmidRap.cxx +++ b/PWGUD/AQC/udQCmidRap.cxx @@ -64,6 +64,8 @@ struct UDQCmid { using ATs = aod::AmbiguousTracks; using AFTs = aod::AmbiguousFwdTracks; + Partition goodTracks = requireGlobalTrackInFilter(); + void init(InitContext& context) { // initialize global variables @@ -132,7 +134,7 @@ struct UDQCmid { } } - // ............................................................................................................................................... + //............................................................................................................................................... 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*/, @@ -150,7 +152,7 @@ struct UDQCmid { // vertex tracks normally gives PV contributors from collisions registry.get(HIST("collisions/vtxTracks"))->Fill(collision.numContrib()); // global tracks - Partition goodTracks = requireGlobalTrackInFilter(); + goodTracks.bindTable(tracks); registry.get(HIST("collisions/globalTracks"))->Fill(goodTracks.size()); @@ -223,7 +225,7 @@ struct UDQCmid { registry.get(HIST("DG/hMassAll"))->Fill(ivm.M()); } } // coll - } // dgcand + } // dgcand // loop over all tracks float rgtrwTOF = 0.; @@ -322,7 +324,7 @@ struct UDQCmid { if (track.hasTOF()) { registry.get(HIST("DG/dEdxTOF"))->Fill(track.p() / track.sign(), track.beta()); } // fill TOF - } // pv contributor + } // pv contributor } } // Inavariant mass after FIT @@ -489,7 +491,7 @@ struct UDQCmid { // update #PV contributors in collisions with empty FT0 && FV0&& FDCC registry.get(HIST("fpPVC2"))->Fill(collision.numContrib(), 1.); } // fdd - } // fvo + } // fvo } // ft0 } diff --git a/PWGUD/AQC/udQcMuon.cxx b/PWGUD/AQC/udQcMuon.cxx new file mode 100644 index 00000000000..eaa5f59bc8b --- /dev/null +++ b/PWGUD/AQC/udQcMuon.cxx @@ -0,0 +1,795 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file udQcMuon.cxx +/// \brief A task for Asynchronus Quality Control for Ultra-perimpheral and Diffraction (AQC-UD) +/// \author Anisa Khatun, anisa.khatun@cern.ch +/// \author Paul Buehler, paul.buehler@oeaw.ac.at +/// \author Sara Haidlova, sara.haidlova@cern.ch +/// \since 28.09.2025 + +#include "PWGUD/Core/UDHelpers.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/FT0Corrected.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/StaticFor.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/BCRange.h" + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct UdQcMuon { + + SliceCache cache; + Preslice perBCzdc = aod::zdc::bcId; + Preslice perBCcalo = aod::calo::bcId; + + static constexpr std::string_view KhcFIT1s[5] = {"CleanFIT1/FV0A", "CleanFIT1/FT0A", "CleanFIT1/FT0C", "CleanFIT1/FDDA", "CleanFIT1/FDDC"}; + static constexpr std::string_view KhcFIT2s[5] = {"CleanFIT2/FV0A", "CleanFIT2/FT0A", "CleanFIT2/FT0C", "CleanFIT2/FDDA", "CleanFIT2/FDDC"}; + static constexpr std::string_view KhcRelBCs[5] = {"CleanFIT2/BCFV0A", "CleanFIT2/BCFT0A", "CleanFIT2/BCFT0C", "CleanFIT2/BCFDDA", "CleanFIT2/BCFDDC"}; + + // get a DGCutparHolder + DGCutparHolder diffCuts = DGCutparHolder(); + Configurable dgCuts{"dgCuts", {}, "DG event cuts"}; + Configurable withAmbTrackAnalysis{"withAmbTrackAnalysis", false, "with ambiguous tracks analysis"}; + Configurable withAmbFwdTrackAnalysis{"withAmbFwdTrackAnalysis", false, "with ambiguous forward tracks analysis"}; + Configurable doCleanFITBC{"doCleanFITBC", false, "Require cleanFIT in compatible BCs"}; + Configurable rapCut{"rapCut", 0.9f, "choose event in midrapidity"}; + Configurable itsNClsCut{"itsNClsCut", 4, "minimal number of ITS clusters"}; + Configurable itsChi2NCls{"itsChi2NCls", 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"}; + + // structures to hold information about the possible BCs the ambiguous tracks/FwdTracks belong to + o2::dataformats::bcRanges abcrs = o2::dataformats::bcRanges("ambiguous_tracks"); + o2::dataformats::bcRanges afbcrs = o2::dataformats::bcRanges("ambiguous_fwdtracks"); + + // inivinitialize HistogramRegistry + HistogramRegistry registry{ + "registry", + {}}; + + // define abbreviations + using CCs = soa::Join; + using CC = CCs::iterator; + using BCs = soa::Join; + using TCs = soa::Join; + using FWs = aod::FwdTracks; + using ATs = aod::AmbiguousTracks; + using AFTs = aod::AmbiguousFwdTracks; + + Partition goodTracks = requireGlobalTrackInFilter(); + + void init(InitContext& context) + { + diffCuts = (DGCutparHolder)dgCuts; + + // add histograms for the different process functions + if (context.mOptions.get("processMain")) { + + // collisions + registry.add("collisions/Stat", "Cut statistics; Selection criterion; Collisions", {HistType::kTH1F, {{20, -0.5, 19.5}}}); + registry.add("collisions/Tracks", "Number of tracks; Number of tracks; Collisions", {HistType::kTH1F, {{300, 0.5, 300.5}}}); + registry.add("collisions/vtxTracks", "Number of vertex tracks; Number of contributors; Collisions", {HistType::kTH1F, {{300, 0.5, 300.5}}}); + registry.add("collisions/globalTracks", "Number of global tracks; Number of global tracks; Collisions", {HistType::kTH1F, {{300, 0.5, 300.5}}}); + registry.add("collisions/posxy", "Vertex position in x and y direction; V_x; V_y; Collisions", {HistType::kTH2F, {{100, -0.5, 0.5}, {100, -0.5, 0.5}}}); + registry.add("collisions/posz", "Vertex position in z direction; V_z; Collisions", {HistType::kTH1F, {{1000, -100., 100.}}}); + registry.add("collisions/netCharge", "All: net charge; Net charge; collisions with PV tracks", {HistType::kTH1F, {{21, -10.5, 10.5}}}); + registry.add("collisions/notPVTracks", "Not PV tracks; Track status bit; Not PV tracks", {HistType::kTH1F, {{17, -0.5, 16.5}}}); + registry.add("collisions/tResvsrTOFTracks", "Number of PV tracks with TOF hit versus collision time resolution; Collision time resolution [ns]; Fraction of PV tracks with TOF hit; Collisions", {HistType::kTH2F, {{1000, 0., 1.E3}, {101, -0.01, 1.01}}}); + registry.add("collisions/tResvsTOFTrkNoPV", "Number of No PV tracks with TOF hit versus collision time resolution; Collision time resolution [ns]; Fraction of No PV tracks with TOF hit; Collisions", {HistType::kTH2F, {{1000, 0., 1.E3}, {101, -0.01, 1.01}}}); + + // tracks + registry.add("tracks/Stat", "Track bits as function of pT; Track pT; Track bit; Tracks", {HistType::kTH2F, {{100, 0., 5.}, {8, 0.5, 8.5}}}); + registry.add("tracks/etapt", "eta versus pT of all tracks; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("tracks/etapt2", "eta versus pT of all quality tracks; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("tracks/etapt3", "eta versus pT of all global tracks; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("tracks/etapt4", "eta versus pT of tracks with ITS Only; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("tracks/etapt5", "eta versus pT of all tracks without TOF; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("tracks/etapt6", "eta versus pT of tracks with TPC Only; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("tracks/etapt7", "eta versus pT of tracks with TRD Only; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("tracks/etapt8", "eta versus pT of tracks with TOF Only; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + + registry.add("tracks/dEdxTPC", "TPC signal versus signed track momentum; Signed track momentum [GeV/c]; TPC signal; Tracks", {HistType::kTH2F, {{120, -6., 6.}, {1000, 0., 1000.}}}); + registry.add("tracks/dEdxTOF", "TOF signal versus signed track momentum; Signed track momentum [GeV/c]; TOF signal; Tracks", {HistType::kTH2F, {{1000, 0., 10.}, {1000, 0., 10.}}}); + + // DG + registry.add("DG/PVposxy", "DG: Vertex position in x and y direction; V_x [mm]; V_y [mm]; DG collisions", {HistType::kTH2F, {{100, -0.5, 0.5}, {100, -0.5, 0.5}}}); + registry.add("DG/PVposz", "DG: Vertex position in z direction; V_z; DG collisions", {HistType::kTH1F, {{1000, -100., 100.}}}); + registry.add("DG/netCharge", "DG: net charge; Net charge; DG collisions", {HistType::kTH1F, {{21, -10.5, 10.5}}}); + registry.add("DG/TrackStat", "Track bits as function of pT; Track pT; Track bit; Tracks", {HistType::kTH2F, {{100, 0., 5.}, {10, 0.5, 10.5}}}); + + registry.add("DG/etapt", "DG: eta versus pT of all tracks; eta of track; p_T of track [GeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("DG/etapt2", "DG: eta versus pT of all quality tracks; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("DG/etapt3", "DG: eta versus pT of all global tracks; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("DG/etapt4", "DG: eta versus pT of all TPC clusers; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("DG/etapt5", "DG: eta versus pT of frac.TPCSharedClusters; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("DG/etapt6", "DG: eta versus pT of all tracks with ITS; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("DG/etapt7", "DG: eta versus pT of all tracks with TPC; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("DG/etapt8", "DG: eta versus pT of all tracks with TRD; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + registry.add("DG/etapt9", "DG: eta versus pT of all tracks with TOF; eta of track; p_T of track [MeV/c^2]; Tracks", {HistType::kTH2F, {{80, -2., 2.}, {100, 0., 5.}}}); + + 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/IVMptSys", "DG: Invariant mass versus p_{T, system}; Invarian mass [GeV/c^2]; p_{T, system} [GeV/c]; DG collisions", {HistType::kTH2F, {{100, 0., 5.}, {400, 0., 4.0}}}); + 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, {{1000, 0., 10.}, {350, 0., 3.5}}}); + registry.add("DG/etaplus", "DG: eta of positive tracks; eta of track", {HistType::kTH2F, {{1000, -5., 5.}, {120, -6., 6., "#phi"}}}); + registry.add("DG/etaminus", "DG: eta of negative tracks; eta of track", {HistType::kTH2F, {{1000, -5., 5.}, {120, -6., 6., "#phi"}}}); + registry.add("DG/hMass", "DG: Invariant mass of pions; Invarian mass [GeV/c^2]", {HistType::kTH1F, {{1000, 0., 10.}}}); + registry.add("DG/trkDCAxy", "DG: Track DCA of XY; DCAxy", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("DG/trkDCAz", "DG: Track DCA of XY; DCAz", {HistType::kTH1F, {{100, -1., 1.}}}); + } + 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}}}); + } + if (context.mOptions.get("processCleanFIT1")) { + registry.add("CleanFIT1/cleanFIT1", "#cleanFIT1", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT1/cF1FV0Aamp", "#cF1FV0Aamp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT1/cF1FT0Aamp", "#cF1FT0Aamp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT1/cF1FT0Camp", "#cF1FT0Camp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT1/cF1FDDAamp", "#cF1FDDAamp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT1/cF1FDDCamp", "#cF1FDDCamp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + + constexpr int N = static_cast(std::size(KhcFIT1s)); + + for (auto n{0}; n < N; n++) { + registry.add(KhcFIT1s[n].data(), KhcFIT1s[n].data(), {HistType::kTH2F, {{20, -0.5, 19.5}, {2, -0.5, 1.5}}}); + } + } + if (context.mOptions.get("processCleanFIT2")) { + registry.add("CleanFIT2/cleanFIT2", "#cleanFIT2", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT2/cF2FV0Aamp", "#cF2FV0Aamp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT2/cF2FT0Aamp", "#cF2FT0Aamp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT2/cF2FT0Camp", "#cF2FT0Camp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT2/cF2FDDAamp", "#cF2FDDAamp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + registry.add("CleanFIT2/cF2FDDCamp", "#cF2FDDCamp", {HistType::kTH2F, {{20, -0.5, 19.5}, {1000, -0.5, 999.5}}}); + + constexpr int N_t = static_cast(std::size(KhcFIT2s)); + for (auto n{0}; n < N_t; n++) { + registry.add(KhcFIT2s[n].data(), KhcFIT2s[n].data(), {HistType::kTH2F, {{20, -0.5, 19.5}, {2, -0.5, 1.5}}}); + registry.add(KhcRelBCs[n].data(), KhcRelBCs[n].data(), {HistType::kTH1F, {{3564, -0.5, 3563.5}}}); + } + } + if (context.mOptions.get("processFV0")) { + registry.add("FV0/FV0A", "#FV0A", {HistType::kTH2F, {{48, -0.5, 47.5}, {2000, 0., 2000.}}}); + registry.add("FV0/hV0A", "Time FV0A", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + } + if (context.mOptions.get("processFT0")) { + registry.add("FT0/FT0A", "#FT0A", {HistType::kTH2F, {{96, -0.5, 95.5}, {400, 0., 400.}}}); + registry.add("FT0/FT0C", "#FT0C", {HistType::kTH2F, {{112, -0.5, 111.5}, {400, 0., 400.}}}); + registry.add("FT0/hT0A", "Time FT0 A side", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + registry.add("FT0/hT0C", "Time FT0 C side", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + registry.add("FT0/hT0ACorr", "Corrected Time FT0 A side", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + registry.add("FT0/hT0CCorr", "Corrected Time FT0 C side", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + registry.add("FT0/hT0AC", "Average Time FT0", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + } + if (context.mOptions.get("processFDD")) { + registry.add("FDD/FDDA", "#FDDA", {HistType::kTH2F, {{8, -0.5, 7.5}, {100, 0., 100.}}}); + registry.add("FDD/FDDC", "#FDDC", {HistType::kTH2F, {{8, -0.5, 7.5}, {100, 0., 100.}}}); + registry.add("FDD/hFDDA", " Avg Time FDD A side", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + registry.add("FDD/hFDDC", " Avg Time FDD C side", {HistType::kTH1F, {{500, -5.0, 5.0}}}); + } + if (context.mOptions.get("processZDC")) { + registry.add("ZdcEnergies", "#ZdcEnergies", {HistType::kTH2F, {{22, -0.5, 21.5}, {100, 0., 1000.}}}); + } + } + + // ............................................................................................................... + 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) + { + // LOGF(debug, " Start %i", abcrs.size()); + + if (!tracks.size()) + return; + if (collision.numContrib() < 1) + return; + + bool isDGcandidate = true; + registry.get(HIST("collisions/Stat"))->Fill(0., isDGcandidate * 1.); + + auto netChargeAll = 0; + for (auto const& trk : tracks) { + if (trk.isPVContributor()) { + netChargeAll += trk.sign(); + } + } + + // update collision histograms + // vertex position + registry.get(HIST("collisions/posxy"))->Fill(collision.posX(), collision.posY()); + registry.get(HIST("collisions/posz"))->Fill(collision.posZ()); + registry.get(HIST("collisions/netCharge"))->Fill(netChargeAll); + // tracks + registry.get(HIST("collisions/Tracks"))->Fill(tracks.size()); + // vertex tracks normally gives PV contributors from collisions + registry.get(HIST("collisions/vtxTracks"))->Fill(collision.numContrib()); + // global tracks + // Partition goodTracks = requireGlobalTrackInFilter(); + goodTracks.bindTable(tracks); + registry.get(HIST("collisions/globalTracks"))->Fill(goodTracks.size()); + + // loop over all tracks + float rgtrwTOF = 0.; + float norgtrwTOF = 0.; + for (auto const& track : tracks) { + // update PV track stats + if (track.isPVContributor()) { + registry.get(HIST("tracks/Stat"))->Fill(track.pt(), 1., 1.); + registry.get(HIST("tracks/Stat"))->Fill(track.pt(), 2., track.isQualityTrack() * 1.); + registry.get(HIST("tracks/Stat"))->Fill(track.pt(), 3., track.isGlobalTrack() * 1.); + registry.get(HIST("tracks/Stat"))->Fill(track.pt(), 4., (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) * 1.); // tracks with only ITS + registry.get(HIST("tracks/Stat"))->Fill(track.pt(), 5., (track.hasITS() && track.hasTPC() && track.hasTRD() && !track.hasTOF()) * 1.); // tracks without TOF + registry.get(HIST("tracks/Stat"))->Fill(track.pt(), 6., (!track.hasITS() && track.hasTPC() && !track.hasTRD() && !track.hasTOF()) * 1.); // tracks with only TPC + registry.get(HIST("tracks/Stat"))->Fill(track.pt(), 7., (!track.hasITS() && !track.hasTPC() && track.hasTRD() && !track.hasTOF()) * 1.); // tracks with only TRD + registry.get(HIST("tracks/Stat"))->Fill(track.pt(), 8., (!track.hasITS() && !track.hasTPC() && !track.hasTRD() && track.hasTOF()) * 1.); // tracks with only TOF + + // update eta vs pt histograms + registry.get(HIST("tracks/etapt"))->Fill(track.eta(), track.pt(), 1.); + registry.get(HIST("tracks/etapt2"))->Fill(track.eta(), track.pt(), track.isQualityTrack() * 1.); + registry.get(HIST("tracks/etapt3"))->Fill(track.eta(), track.pt(), track.isGlobalTrack() * 1.); + registry.get(HIST("tracks/etapt4"))->Fill(track.eta(), track.pt(), (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) * 1.); // tracks with only ITS + registry.get(HIST("tracks/etapt5"))->Fill(track.eta(), track.pt(), (track.hasITS() && track.hasTPC() && track.hasTRD() && !track.hasTOF()) * 1.); // tracks without TOF + registry.get(HIST("tracks/etapt6"))->Fill(track.eta(), track.pt(), (!track.hasITS() && track.hasTPC() && !track.hasTRD() && !track.hasTOF()) * 1.); // tracks with only TPC + registry.get(HIST("tracks/etapt7"))->Fill(track.eta(), track.pt(), (!track.hasITS() && !track.hasTPC() && track.hasTRD() && !track.hasTOF()) * 1.); // tracks with only TRD + registry.get(HIST("tracks/etapt8"))->Fill(track.eta(), track.pt(), (!track.hasITS() && !track.hasTPC() && !track.hasTRD() && track.hasTOF()) * 1.); // tracks with only TOF + + // update dEdx histograms + registry.get(HIST("tracks/dEdxTPC"))->Fill(track.tpcInnerParam() / track.sign(), track.tpcSignal()); + + // TOF hit? + if (track.hasTOF()) { + registry.get(HIST("tracks/dEdxTOF"))->Fill(track.p() / track.sign(), track.beta()); + + // No vertex track with TOF hit? + if (!track.isPVContributor()) { + norgtrwTOF += 1.; + } + + // vertex track with TOF hit? + if (track.isPVContributor()) { + rgtrwTOF += 1.; + } + } + } + } // closing track loop + + // fraction of No PV and PV tracks with TOF hit + if (collision.numContrib() > 0) { + norgtrwTOF /= collision.numContrib(); + rgtrwTOF /= collision.numContrib(); + } + + // LOGF(debug, " PV tracks with TOF: %f [1]", rgtrwTOF); + registry.get(HIST("collisions/tResvsrTOFTracks"))->Fill(collision.collisionTimeRes(), rgtrwTOF); + registry.get(HIST("collisions/tResvsTOFTrkNoPV"))->Fill(collision.collisionTimeRes(), norgtrwTOF); + + // is it a DG candidate? + // 1. DG = no FIT signal in compatible BCs + // 2. & no ZDC signal in compatible BCs + // 3. & no Calo signal in compatible BCs + // 4. & no V0s + // 5. & no Cascades + // 6. & number of forward tracks = 0 + // 7. & no global track which is not a vertex track + // 8. & no vertex track which is not a global track + // 9. & ntrMin <= number of vertex tracks <= ntrMax + isDGcandidate = true; + + // get BCrange to test for FIT signals + auto bcSlice = udhelpers::compatibleBCs(collision, diffCuts.NDtcoll(), bct0s, diffCuts.minNBCs()); + + // 1. no FIT signal in bcSlice / collision + if (doCleanFITBC) { + for (auto const& bc : bcSlice) { + if (!udhelpers::cleanFIT(bc, diffCuts.maxFITtime(), diffCuts.FITAmpLimits())) { + isDGcandidate = false; + break; + } + } + } else { + if (!udhelpers::cleanFITCollision(collision, diffCuts.maxFITtime(), diffCuts.FITAmpLimits())) { + isDGcandidate = false; + } + } + registry.get(HIST("collisions/Stat"))->Fill(1., isDGcandidate * 1.); + + // 2. no Zdc signal in bcSlice + std::vector lims(10, 0.); + for (auto const& bc : bcSlice) { + if (!udhelpers::cleanZDC(bc, zdcs, lims, cache)) { + isDGcandidate = false; + break; + } + } + registry.get(HIST("collisions/Stat"))->Fill(2., isDGcandidate * 1.); + + // 3. no Calo signal in bcSlice + for (auto const& bc : bcSlice) { + if (!udhelpers::cleanCalo(bc, calos, lims, cache)) { + isDGcandidate = false; + break; + } + } + registry.get(HIST("collisions/Stat"))->Fill(3., isDGcandidate * 1.); + + // 4. no V0s + isDGcandidate &= (v0s.size() == 0); + registry.get(HIST("collisions/Stat"))->Fill(4., isDGcandidate * 1.); + + // 5. no Cascades + isDGcandidate &= (cascades.size() == 0); + registry.get(HIST("collisions/Stat"))->Fill(5., isDGcandidate * 1.); + + // 6. number of forward tracks = 0 + isDGcandidate &= (fwdtracks.size() == 0); + registry.get(HIST("collisions/Stat"))->Fill(6., isDGcandidate * 1.); + + // 7. Check for global tracks which are no vtx tracks + bool globalAndVtx = isDGcandidate; + bool vtxAndGlobal = isDGcandidate; + for (auto const& track : tracks) { + if (track.isGlobalTrack() && !track.isPVContributor()) { + globalAndVtx = false; + } + if (track.isPVContributor() && !track.isGlobalTrack()) { + vtxAndGlobal = false; + } + } + registry.get(HIST("collisions/Stat"))->Fill(7., globalAndVtx * 1.); + + // 8. check a given bc for possible ambiguous Tracks + auto noAmbTracks = isDGcandidate; + for (auto const& bc : bcSlice) { + if (abcrs.isInRange(bc.globalIndex())) { + noAmbTracks = false; + break; + } + } + registry.get(HIST("collisions/Stat"))->Fill(8., noAmbTracks * 1.); // noAmbTracks + + // 9. check a given bc for possible ambiguous FwdTracks + auto noAmbFwdTracks = isDGcandidate; + for (auto const& bc : bcSlice) { + if (afbcrs.isInRange(bc.globalIndex())) { + noAmbFwdTracks = false; + break; + } + } + registry.get(HIST("collisions/Stat"))->Fill(9., noAmbFwdTracks * 1.); // noAmbFwdTracks + + // 10. number of vertex tracks <= n not sure + isDGcandidate &= (collision.numContrib() >= diffCuts.minNTracks()); + registry.get(HIST("collisions/Stat"))->Fill(10., isDGcandidate * 1.); + isDGcandidate &= (collision.numContrib() <= diffCuts.maxNTracks()); + registry.get(HIST("collisions/Stat"))->Fill(11., isDGcandidate * 1.); + + // 11. fraction of PV tracks with TOF hit + isDGcandidate &= (rgtrwTOF >= diffCuts.minRgtrwTOF()); + registry.get(HIST("collisions/Stat"))->Fill(12., isDGcandidate * 1.); + // 8. check for vertex tracks which are no global tracks + isDGcandidate &= globalAndVtx; + if (diffCuts.globalTracksOnly()) { + isDGcandidate &= vtxAndGlobal; + } + registry.get(HIST("collisions/Stat"))->Fill(19., isDGcandidate * 1.); + + // 12. net charge and invariant mass + bool goodetas = true; + int countGT = 0; + std::vector trkIdx; + if (isDGcandidate) { + // check good quality of the tracks + for (auto const& track : tracks) { + // update histogram for rejectedTracks/notPVtracks + if (!track.isPVContributor()) { + registry.get(HIST("collisions/notPVTracks"))->Fill(0., 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(1., track.isGlobalTrackSDD() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(2., track.passedTrackType() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(3., track.passedPtRange() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(4., track.passedEtaRange() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(5., track.passedTPCNCls() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(6., track.passedTPCCrossedRows() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(7., track.passedTPCCrossedRowsOverNCls() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(8., track.passedTPCChi2NDF() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(9., track.passedTPCRefit() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(10., track.passedITSNCls() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(11., track.passedITSChi2NDF() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(12., track.passedITSRefit() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(13., track.passedITSHits() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(14., track.passedGoldenChi2() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(15., track.passedDCAxy() * 1.); + registry.get(HIST("collisions/notPVTracks"))->Fill(16., track.passedDCAz() * 1.); + continue; + } + if (RecoDecay::eta(std::array{track.px(), track.py(), track.pz()}) <= diffCuts.minEta() || RecoDecay::eta(std::array{track.px(), track.py(), track.pz()}) >= diffCuts.maxEta()) { + goodetas = false; + continue; + } + if (!track.hasITS()) { + continue; + } + if (track.itsChi2NCl() > itsChi2NCls) { + continue; + } + if (!track.hasTPC()) { + continue; + } + if (track.tpcChi2NCl() > tpcChi2NCls) { + continue; + } + if (track.tpcNClsCrossedRows() < tpcNClsCrossedRowsCut) { + continue; + } + countGT++; + trkIdx.push_back(track.index()); + } + } + isDGcandidate &= goodetas; + registry.get(HIST("collisions/Stat"))->Fill(14., isDGcandidate * 1.); + + float massMu = o2::constants::physics::MassMuonMinus; + // DGcandidates with 2 good tracks -> to be optimised for different number of candidates + int tG = 2; + if (isDGcandidate && countGT == tG) { + + auto trkDaughter1 = tracks.iteratorAt(trkIdx[0]); + auto trkDaughter2 = tracks.iteratorAt(trkIdx[1]); + + // vertex position of DG events + registry.get(HIST("DG/PVposxy"))->Fill(collision.posX(), collision.posY()); + registry.get(HIST("DG/PVposz"))->Fill(collision.posZ()); + + // tracks with opposite charges -> to be optimised for different numbers + if ((trkDaughter1.sign() * trkDaughter2.sign()) != -1) { + return; + } + + if (RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaEl(), trkDaughter2.tpcNSigmaEl()) > RecoDecay::sumOfSquares(trkDaughter1.tpcNSigmaMu(), trkDaughter2.tpcNSigmaMu())) { + 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); + + if (std::abs(rapJpsi) > rapCut) { + return; + } + + registry.get(HIST("DG/hMass"))->Fill(massJpsi); + registry.get(HIST("DG/IVMptSys2PVtrk"))->Fill(massJpsi, RecoDecay::pt(mother)); + + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter1.pt(), 1., 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter1.pt(), 2., trkDaughter1.isQualityTrack() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter1.pt(), 3., trkDaughter1.isGlobalTrack() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter1.pt(), 4., trkDaughter1.tpcNClsFound() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter1.pt(), 5., trkDaughter1.tpcFractionSharedCls() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter1.pt(), 10, trkDaughter1.dcaXY() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter1.pt(), 11, trkDaughter1.dcaZ() * 1.); + + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter2.pt(), 1., 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter2.pt(), 2., trkDaughter2.isQualityTrack() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter2.pt(), 3., trkDaughter2.isGlobalTrack() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter2.pt(), 4., trkDaughter2.tpcNClsFound() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter2.pt(), 5., trkDaughter2.tpcFractionSharedCls() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter2.pt(), 10, trkDaughter2.dcaXY() * 1.); + registry.get(HIST("DG/TrackStat"))->Fill(trkDaughter2.pt(), 11, trkDaughter2.dcaZ() * 1.); + + registry.get(HIST("DG/etapt"))->Fill(trkDaughter1.eta(), trkDaughter1.pt(), 1.); + registry.get(HIST("DG/etapt2"))->Fill(trkDaughter1.eta(), trkDaughter1.pt(), trkDaughter1.isQualityTrack() * 1.); + registry.get(HIST("DG/etapt3"))->Fill(trkDaughter1.eta(), trkDaughter1.pt(), trkDaughter1.isGlobalTrack() * 1.); + registry.get(HIST("DG/etapt4"))->Fill(trkDaughter1.eta(), trkDaughter1.pt(), trkDaughter1.tpcNClsFound() * 1.); + registry.get(HIST("DG/etapt5"))->Fill(trkDaughter1.eta(), trkDaughter1.pt(), trkDaughter1.tpcFractionSharedCls() * 1.); + + registry.get(HIST("DG/etapt"))->Fill(trkDaughter2.eta(), trkDaughter2.pt(), 1.); + registry.get(HIST("DG/etapt2"))->Fill(trkDaughter2.eta(), trkDaughter2.pt(), trkDaughter2.isQualityTrack() * 1.); + registry.get(HIST("DG/etapt3"))->Fill(trkDaughter2.eta(), trkDaughter2.pt(), trkDaughter2.isGlobalTrack() * 1.); + registry.get(HIST("DG/etapt4"))->Fill(trkDaughter2.eta(), trkDaughter2.pt(), trkDaughter2.tpcNClsFound() * 1.); + registry.get(HIST("DG/etapt5"))->Fill(trkDaughter2.eta(), trkDaughter2.pt(), trkDaughter2.tpcFractionSharedCls() * 1.); + + if (trkDaughter1.sign() > 0 || trkDaughter2.sign() > 0) { + registry.get(HIST("DG/etaplus"))->Fill(trkDaughter1.eta(), trkDaughter1.phi()); + registry.get(HIST("DG/etaplus"))->Fill(trkDaughter2.eta(), trkDaughter2.phi()); + } + if (trkDaughter1.sign() < 0 || trkDaughter2.sign() < 0) { + registry.get(HIST("DG/etaminus"))->Fill(trkDaughter1.eta(), trkDaughter1.phi()); + registry.get(HIST("DG/etaminus"))->Fill(trkDaughter2.eta(), trkDaughter2.phi()); + } + + registry.get(HIST("DG/dEdxTPC"))->Fill(trkDaughter1.tpcInnerParam() / trkDaughter1.sign(), trkDaughter1.tpcSignal()); + registry.get(HIST("DG/trkDCAxy"))->Fill(trkDaughter1.dcaXY()); + registry.get(HIST("DG/trkDCAz"))->Fill(trkDaughter1.dcaZ()); + + registry.get(HIST("DG/dEdxTPC"))->Fill(trkDaughter2.tpcInnerParam() / trkDaughter2.sign(), trkDaughter2.tpcSignal()); + registry.get(HIST("DG/trkDCAxy"))->Fill(trkDaughter2.dcaXY()); + registry.get(HIST("DG/trkDCAz"))->Fill(trkDaughter2.dcaZ()); + + if (trkDaughter1.hasTOF()) { + registry.get(HIST("DG/dEdxTOF"))->Fill(trkDaughter1.p() / trkDaughter1.sign(), trkDaughter1.beta()); + } + if (trkDaughter2.hasTOF()) { + registry.get(HIST("DG/dEdxTOF"))->Fill(trkDaughter2.p() / trkDaughter2.sign(), trkDaughter2.beta()); + } + } + } + } + PROCESS_SWITCH(UdQcMuon, processMain, "Process Main", true); + + // ............................................................................................................... + // Distribution of number of PV contributors for all collisions and those with empty FT0 + void processFewProng(CC const& collision, BCs const& /*bct0s*/, + aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, aod::FDDs const& /*fdds*/) + { + // count collisions + registry.get(HIST("fpStat"))->Fill(1., 1.); + registry.get(HIST("allPVC"))->Fill(collision.numContrib(), 1.); + + // check FT0 to be empty + auto bc = collision.foundBC_as(); + if (udhelpers::cleanFT0(bc, diffCuts.maxFITtime(), 0., 0.)) { + // only collisions with empty FT0 arrive here + registry.get(HIST("fpStat"))->Fill(2., 1.); + + // update #PV contributors in collisions with empty FT0 + registry.get(HIST("fpPVC"))->Fill(collision.numContrib(), 1.); + } + } + PROCESS_SWITCH(UdQcMuon, processFewProng, "Process FewProng", true); + + // ............................................................................................................................................. + void processCleanFIT1(CC const& collision, BCs const& bct0s, + aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, aod::FDDs const& /*fdds*/) + { + // LOGF(debug, "(5, 1000000.); + bool isDGcandidate = true; + int maxNDtcoll = 20; + for (int NDtcoll = 0; NDtcoll < maxNDtcoll; NDtcoll++) { + auto bcSlice = udhelpers::compatibleBCs(collision, NDtcoll, bct0s, 0); + + // do for diffCuts.FITAmpLimits + ampFV0A = ampFT0A = ampFT0C = ampFDDA = ampFDDC = 0.; + isDGcandidate = true; + for (auto const& bc : bcSlice) { + isDGcandidate &= udhelpers::cleanFIT(bc, diffCuts.maxFITtime(), diffCuts.FITAmpLimits()); + + if (bc.has_foundFV0()) { + ampFV0A += udhelpers::FV0AmplitudeA(bc.foundFV0()); + } + if (bc.has_foundFT0()) { + ampFT0A += udhelpers::FT0AmplitudeA(bc.foundFT0()); + ampFT0C += udhelpers::FT0AmplitudeA(bc.foundFT0()); + } + if (bc.has_foundFDD()) { + ampFDDA += udhelpers::FDDAmplitudeA(bc.foundFDD()); + ampFDDC += udhelpers::FDDAmplitudeA(bc.foundFDD()); + } + } + registry.get(HIST("CleanFIT1/cleanFIT1"))->Fill(NDtcoll, isDGcandidate * 1.); + if (isDGcandidate) { + registry.get(HIST("CleanFIT1/cF1FV0Aamp"))->Fill(NDtcoll, ampFV0A); + registry.get(HIST("CleanFIT1/cF1FT0Aamp"))->Fill(NDtcoll, ampFT0A); + registry.get(HIST("CleanFIT1/cF1FT0Camp"))->Fill(NDtcoll, ampFT0C); + registry.get(HIST("CleanFIT1/cF1FDDAamp"))->Fill(NDtcoll, ampFDDA); + registry.get(HIST("CleanFIT1/cF1FDDCamp"))->Fill(NDtcoll, ampFDDC); + } + + // loop over single detectors + static_for<0, 4>([&](auto n) { + fitLims[n] = 0.; + isDGcandidate = true; + for (auto const& bc : bcSlice) { + isDGcandidate &= udhelpers::cleanFIT(bc, diffCuts.maxFITtime(), fitLims); + } + constexpr int Index = n.value; + registry.fill(HIST(KhcFIT1s[Index]), NDtcoll, isDGcandidate * 1.); + fitLims[n] = 1000000.; + }); + } + } + + PROCESS_SWITCH(UdQcMuon, processCleanFIT1, "Process CleanFitTest1", true); + // ............................................................................................................................................. + + void processCleanFIT2(CC const& collision, BCs const& bct0s, + aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, aod::FDDs const& /*fdds*/) + { + // LOGF(debug, "(); + bcnum = collbc.globalBC() % o2::constants::lhc::LHCMaxBunches; + } + // test influence of BCrange width using a series of nMinBC + float ampFV0A, ampFT0A, ampFT0C, ampFDDA, ampFDDC; + auto fitLims = std::vector(5, 1000000.); + bool isDGcandidate = true; + int nMaxBC = 20; + for (int nMinBC = 0; nMinBC < nMaxBC; nMinBC++) { + auto bcSlice = udhelpers::compatibleBCs(collision, 0, bct0s, nMinBC); + ampFV0A = ampFT0A = ampFT0C = ampFDDA = ampFDDC = 0.; + isDGcandidate = true; + for (auto const& bc : bcSlice) { + isDGcandidate &= udhelpers::cleanFIT(bc, diffCuts.maxFITtime(), diffCuts.FITAmpLimits()); + + if (bc.has_foundFV0()) { + ampFV0A += udhelpers::FV0AmplitudeA(bc.foundFV0()); + } + if (bc.has_foundFT0()) { + ampFT0A += udhelpers::FT0AmplitudeA(bc.foundFT0()); + ampFT0C += udhelpers::FT0AmplitudeA(bc.foundFT0()); + } + if (bc.has_foundFDD()) { + ampFDDA += udhelpers::FDDAmplitudeA(bc.foundFDD()); + ampFDDC += udhelpers::FDDAmplitudeA(bc.foundFDD()); + } + } + registry.get(HIST("CleanFIT2/cleanFIT2"))->Fill(nMinBC, isDGcandidate * 1.); + + if (isDGcandidate) { + registry.get(HIST("CleanFIT2/cF2FV0Aamp"))->Fill(nMinBC, ampFV0A); + registry.get(HIST("CleanFIT2/cF2FT0Aamp"))->Fill(nMinBC, ampFT0A); + registry.get(HIST("CleanFIT2/cF2FT0Camp"))->Fill(nMinBC, ampFT0C); + registry.get(HIST("CleanFIT2/cF2FDDAamp"))->Fill(nMinBC, ampFDDA); + registry.get(HIST("CleanFIT2/cF2FDDCamp"))->Fill(nMinBC, ampFDDC); + } + + // loop over single detectors + static_for<0, 4>([&](auto n) { + fitLims[n] = 0.; + isDGcandidate = true; + for (auto const& bc : bcSlice) { + isDGcandidate &= udhelpers::cleanFIT(bc, diffCuts.maxFITtime(), fitLims); // DG + } + constexpr int Index = n.value; + registry.fill(HIST(KhcFIT2s[Index]), nMinBC, isDGcandidate * 1.); + registry.fill(HIST(KhcRelBCs[Index]), static_cast(bcnum), isDGcandidate * 1.); + fitLims[n] = 1000000.; + }); + } + } + + PROCESS_SWITCH(UdQcMuon, processCleanFIT2, "Process CleanFitTest2", true); + + // ............................................................................................................... + void processFV0(aod::FV0As const& fv0s, BCs const&) + { + // LOGF(info, " %d", fv0s.size()); + if (fv0s.size() <= 0) { + return; + } + + for (auto const& fv0 : fv0s) { + registry.get(HIST("FV0/hV0A"))->Fill(fv0.time()); + // side A + for (size_t ind = 0; ind < fv0.channel().size(); ind++) { + registry.get(HIST("FV0/FV0A"))->Fill((fv0.channel())[ind], (fv0.amplitude())[ind]); + } + } + }; + PROCESS_SWITCH(UdQcMuon, processFV0, "Process FV0", true); + + // ............................................................................................................... + void processFT0(aod::FT0s const& ft0s, aod::FT0sCorrected const& ft0scorr, BCs const&) + { + // LOGF(debug, " %d", ft0s.size()); + for (auto const& collision : ft0scorr) { + + if (collision.t0ACorrectedValid()) { + registry.get(HIST("FT0/hT0ACorr"))->Fill(collision.t0ACorrected()); + } + if (collision.t0CCorrectedValid()) { + registry.get(HIST("FT0/hT0CCorr"))->Fill(collision.t0CCorrected()); + } + + if (collision.t0CCorrectedValid() && collision.t0ACorrectedValid()) { + registry.get(HIST("FT0/hT0AC"))->Fill(collision.t0AC()); + } + } + for (auto const& ft0 : ft0s) { + registry.get(HIST("FT0/hT0A"))->Fill(ft0.timeA()); + registry.get(HIST("FT0/hT0C"))->Fill(ft0.timeC()); + + // side A + for (size_t ind = 0; ind < ft0.channelA().size(); ind++) { + registry.get(HIST("FT0/FT0A"))->Fill((ft0.channelA())[ind], (ft0.amplitudeA())[ind]); + } + + // side C + for (size_t ind = 0; ind < ft0.channelC().size(); ind++) { + registry.get(HIST("FT0/FT0C"))->Fill((ft0.channelC())[ind], (ft0.amplitudeC())[ind]); + } + } + }; + PROCESS_SWITCH(UdQcMuon, processFT0, "Process FT0", true); + + // ............................................................................................................... + void processFDD(aod::FDDs const& fdds, BCs const&) + { + // LOGF(debug, " %d", fdds.size()); + + for (auto const& fdd : fdds) { + + registry.get(HIST("FDD/hFDDA"))->Fill(fdd.timeA()); + registry.get(HIST("FDD/hFDDC"))->Fill(fdd.timeC()); + // side A + int maxInd = 8; + for (auto ind = 0; ind < maxInd; ind++) { + registry.get(HIST("FDD/FDDA"))->Fill(ind, (fdd.chargeA())[ind]); + } + + // side C + for (auto ind = 0; ind < maxInd; ind++) { + registry.get(HIST("FDD/FDDC"))->Fill(ind, (fdd.chargeC())[ind]); + } + } + }; + PROCESS_SWITCH(UdQcMuon, processFDD, "Process FDD", true); + + // ............................................................................................................... + void processZDC(aod::Zdc const& zdc) + { + // LOGF(debug, " %d", zdc.size()); + + // Zdc energies + registry.get(HIST("ZdcEnergies"))->Fill(0., zdc.energyZEM1()); + registry.get(HIST("ZdcEnergies"))->Fill(1., zdc.energyZEM2()); + registry.get(HIST("ZdcEnergies"))->Fill(2., zdc.energyCommonZNA()); + registry.get(HIST("ZdcEnergies"))->Fill(3., zdc.energyCommonZNC()); + registry.get(HIST("ZdcEnergies"))->Fill(4., zdc.energyCommonZPA()); + registry.get(HIST("ZdcEnergies"))->Fill(5., zdc.energyCommonZPC()); + registry.get(HIST("ZdcEnergies"))->Fill(6., (zdc.energySectorZNA())[0]); + registry.get(HIST("ZdcEnergies"))->Fill(7., (zdc.energySectorZNA())[1]); + registry.get(HIST("ZdcEnergies"))->Fill(8., (zdc.energySectorZNA())[2]); + registry.get(HIST("ZdcEnergies"))->Fill(9., (zdc.energySectorZNA())[3]); + registry.get(HIST("ZdcEnergies"))->Fill(10., (zdc.energySectorZNC())[0]); + registry.get(HIST("ZdcEnergies"))->Fill(11., (zdc.energySectorZNC())[1]); + registry.get(HIST("ZdcEnergies"))->Fill(12., (zdc.energySectorZNC())[2]); + registry.get(HIST("ZdcEnergies"))->Fill(13., (zdc.energySectorZNC())[3]); + registry.get(HIST("ZdcEnergies"))->Fill(14., (zdc.energySectorZPA())[0]); + registry.get(HIST("ZdcEnergies"))->Fill(15., (zdc.energySectorZPA())[1]); + registry.get(HIST("ZdcEnergies"))->Fill(16., (zdc.energySectorZPA())[2]); + registry.get(HIST("ZdcEnergies"))->Fill(17., (zdc.energySectorZPA())[3]); + registry.get(HIST("ZdcEnergies"))->Fill(18., (zdc.energySectorZPC())[0]); + registry.get(HIST("ZdcEnergies"))->Fill(19., (zdc.energySectorZPC())[1]); + registry.get(HIST("ZdcEnergies"))->Fill(20., (zdc.energySectorZPC())[2]); + registry.get(HIST("ZdcEnergies"))->Fill(21., (zdc.energySectorZPC())[3]); + }; + PROCESS_SWITCH(UdQcMuon, processZDC, "Process ZDC", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} 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/DGPIDSelector.cxx b/PWGUD/Core/DGPIDSelector.cxx index afd3ff24b63..04dab87ef7a 100644 --- a/PWGUD/Core/DGPIDSelector.cxx +++ b/PWGUD/Core/DGPIDSelector.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. - +#include #include #include "CommonConstants/PhysicsConstants.h" #include "DGPIDSelector.h" @@ -144,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); @@ -236,7 +236,7 @@ void DGAnaparHolder::Setptsys(float min, float max) mMaxptsys = max; } -void DGAnaparHolder::SetnCombine(int nComb) +void DGAnaparHolder::SetnCombine(std::size_t nComb) { mNCombine = nComb; } @@ -300,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]); } } @@ -523,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 a4b0fcf145b..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}, @@ -152,7 +152,7 @@ struct DGAnaparHolder { void Seteta(float, float); void SetAlpha(float, float); void Setptsys(float, float); - void SetnCombine(int); + void SetnCombine(std::size_t); void SetnetCharges(std::vector); void SetunlikeCharges(std::vector); void SetlikeCharges(std::vector); @@ -180,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; } @@ -216,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/SGSelector.h b/PWGUD/Core/SGSelector.h index 4845818f244..2c5868df303 100644 --- a/PWGUD/Core/SGSelector.h +++ b/PWGUD/Core/SGSelector.h @@ -8,45 +8,67 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +// +/// \file SGSelector.h +/// \author Alexander Bylinkin +/// \author Adam Matyja +/// \since 2023-11-21 +/// \brief Support class holding tools to work with Single Gap selection in central barrel UPCs +/// #ifndef PWGUD_CORE_SGSELECTOR_H_ #define PWGUD_CORE_SGSELECTOR_H_ -#include -#include "TDatabasePDG.h" -#include "TLorentzVector.h" -#include "Framework/Logger.h" -#include "Framework/AnalysisTask.h" -#include "PWGUD/Core/UDHelpers.h" #include "PWGUD/Core/SGCutParHolder.h" +#include "PWGUD/Core/UDHelpers.h" + +#include "Common/CCDB/RCTSelectionFlags.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/Logger.h" + +#include template struct SelectionResult { - int value; // The original integer return value - BC* bc; // Pointer to the BC object + int value; // The original integer return value + const BC* bc; // Pointer to the BC object +}; + +namespace o2::aod::sgselector +{ +enum TrueGap : int { + NoGap = -1, // no gap due to change of threshold(s) in any of FV0, FT0A, ZNA, FT0C, ZNC + SingleGapA = 0, // initially single gap at A side event + SingleGapC = 1, // initially single gap at C side event + DoubleGap = 2, // initially double gap event + NoUpc = 3, // initially no UPC event with default thresholds (FT0A=150, FT0C=50) + TrkOutOfRange = 4, // to many tracks (>100 default) + BadDoubleGap = 5 // unknows status of double gap check with changed thresholds }; +} // namespace o2::aod::sgselector class SGSelector { public: - SGSelector() : fPDG(TDatabasePDG::Instance()) {} + SGSelector() : myRCTChecker{"CBT"}, myRCTCheckerHadron{"CBT_hadronPID"}, myRCTCheckerZDC{"CBT", true}, myRCTCheckerHadronZDC{"CBT_hadronPID", true} {} template - int Print(SGCutParHolder /*diffCuts*/, CC& collision, BCs& /*bcRange*/, TCs& /*tracks*/, FWs& /*fwdtracks*/) + int Print(SGCutParHolder const& /*diffCuts*/, CC const& collision, BCs const& /*bcRange*/, TCs const& /*tracks*/, FWs const& /*fwdtracks*/) { LOGF(info, "Size of array %i", collision.size()); return 1; } template - SelectionResult IsSelected(SGCutParHolder diffCuts, CC& collision, BCs& bcRange, BC& oldbc) + SelectionResult IsSelected(SGCutParHolder const& diffCuts, CC const& collision, BCs const& bcRange, BC const& oldbc) { // LOGF(info, "Collision %f", collision.collisionTime()); // LOGF(info, "Number of close BCs: %i", bcRange.size()); SelectionResult result; result.bc = &oldbc; if (collision.numContrib() < diffCuts.minNTracks() || collision.numContrib() > diffCuts.maxNTracks()) { - result.value = 4; + result.value = o2::aod::sgselector::TrkOutOfRange; // 4 return result; } auto newbc = oldbc; @@ -72,9 +94,9 @@ class SGSelector newbc = bc; gC = false; } - } + } // end of loop over bc range if (!gA && !gC) { - result.value = 3; + result.value = o2::aod::sgselector::NoUpc; // gap = 3 return result; } if (gA && gC) { // loop once again for so-called DG events to get the most active FT0 BC @@ -101,53 +123,96 @@ class SGSelector result.bc = &newbc; // LOGF(info, "Old BC: %i, New BC: %i",oldbc.globalBC(), newbc.globalBC()); result.bc = &newbc; - result.value = gA && gC ? 2 : (gA ? 0 : 1); + // result.value = gA && gC ? 2 : (gA ? 0 : 1); + result.value = gA && gC ? o2::aod::sgselector::DoubleGap : (gA ? o2::aod::sgselector::SingleGapA : o2::aod::sgselector::SingleGapC); return result; } template int FwdTrkSelector(TFwdTrack const& fwdtrack) { - if (fwdtrack.trackType() == 0 || fwdtrack.trackType() == 3) + // if (fwdtrack.trackType() == 0 || fwdtrack.trackType() == 3) + if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack || fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) return 1; else return 0; } template - int trueGap(CC& collision, float fv0, float ft0a, float ft0c, float zdc_cut) + int trueGap(CC const& collision, const float fv0, const float ft0a, const float ft0c, const float zdc_cut) { - float fit_cut[3] = {fv0, ft0a, ft0c}; + const 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) { + // float FV0A, FT0A, FT0C, ZNA, ZNC; + const float FV0A = collision.totalFV0AmplitudeA(); + const float FT0A = collision.totalFT0AmplitudeA(); + const float FT0C = collision.totalFT0AmplitudeC(); + const float ZNA = collision.energyCommonZNA(); + const float ZNC = collision.energyCommonZNC(); + if (gap == o2::aod::sgselector::SingleGapA) { // gap == 0 if (FV0A > fit_cut[0] || FT0A > fit_cut[1] || ZNA > zdc_cut) - true_gap = -1; - } else if (gap == 1) { + true_gap = o2::aod::sgselector::NoGap; // -1 + } else if (gap == o2::aod::sgselector::SingleGapC) { // gap == 1 if (FT0C > fit_cut[2] || ZNC > zdc_cut) - true_gap = -1; - } else if (gap == 2) { - if ((FV0A > fit_cut[0] || FT0A > fit_cut[1] || ZNA > zdc_cut) && (FT0C > fit_cut[2] || ZNC > zdc_cut)) - true_gap = -1; - 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 ((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; + true_gap = o2::aod::sgselector::NoGap; // -1 + } else if (gap == o2::aod::sgselector::DoubleGap) { // gap == 2 + if ((FV0A > fit_cut[0] || FT0A > fit_cut[1] || ZNA > zdc_cut) && (FT0C > fit_cut[2] || ZNC > zdc_cut)) { + true_gap = o2::aod::sgselector::NoGap; // -1 + } else if ((FV0A > fit_cut[0] || FT0A > fit_cut[1] || ZNA > zdc_cut) && (FT0C <= fit_cut[2] && ZNC <= zdc_cut)) { + true_gap = o2::aod::sgselector::SingleGapC; // 1 + } else if ((FV0A <= fit_cut[0] && FT0A <= fit_cut[1] && ZNA <= zdc_cut) && (FT0C > fit_cut[2] || ZNC > zdc_cut)) { + true_gap = o2::aod::sgselector::SingleGapA; // 0 + } else if (FV0A <= fit_cut[0] && FT0A <= fit_cut[1] && ZNA <= zdc_cut && FT0C <= fit_cut[2] && ZNC <= zdc_cut) { + true_gap = o2::aod::sgselector::DoubleGap; // 2 + } else { + LOGF(info, "Something wrong with DG"); + true_gap = o2::aod::sgselector::BadDoubleGap; // 5 + } } return true_gap; } + // check CBT flags + template + bool isCBTOk(CC const& collision) + { + if (myRCTChecker(collision)) + return true; + return false; + } + + // check CBT+hadronPID flags + template + bool isCBTHadronOk(CC const& collision) + { + if (myRCTCheckerHadron(collision)) + return true; + return false; + } + + // check CBT+ZDC flags + template + bool isCBTZdcOk(CC const& collision) + { + if (myRCTCheckerZDC(collision)) + return true; + return false; + } + + // check CBT+hadronPID+ZDC flags + template + bool isCBTHadronZdcOk(CC const& collision) + { + if (myRCTCheckerHadronZDC(collision)) + return true; + return false; + } + private: - TDatabasePDG* fPDG; + o2::aod::rctsel::RCTFlagsChecker myRCTChecker; + o2::aod::rctsel::RCTFlagsChecker myRCTCheckerHadron; + o2::aod::rctsel::RCTFlagsChecker myRCTCheckerZDC; + o2::aod::rctsel::RCTFlagsChecker myRCTCheckerHadronZDC; }; #endif // PWGUD_CORE_SGSELECTOR_H_ diff --git a/PWGUD/Core/SGTrackSelector.h b/PWGUD/Core/SGTrackSelector.h index 1b68ab0ddba..455eaf24ac1 100644 --- a/PWGUD/Core/SGTrackSelector.h +++ b/PWGUD/Core/SGTrackSelector.h @@ -16,21 +16,20 @@ #ifndef PWGUD_CORE_SGTRACKSELECTOR_H_ #define PWGUD_CORE_SGTRACKSELECTOR_H_ -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/DataModel/UDTables.h" + #include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" -#include "iostream" -#include "PWGUD/DataModel/UDTables.h" -#include "PWGUD/Core/SGSelector.h" -#include +#include "Framework/runDataProcessing.h" + #include "TVector3.h" -using namespace std; -using namespace o2; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; +#include + +#include +#include + template int trackselector(const T& track, const std::vector& params) { diff --git a/PWGUD/Core/UDHelpers.h b/PWGUD/Core/UDHelpers.h index 32349280419..a4137784ac5 100644 --- a/PWGUD/Core/UDHelpers.h +++ b/PWGUD/Core/UDHelpers.h @@ -16,21 +16,22 @@ #ifndef PWGUD_CORE_UDHELPERS_H_ #define PWGUD_CORE_UDHELPERS_H_ -#include -#include -#include "TLorentzVector.h" -#include "Framework/Logger.h" -#include "DataFormatsFT0/Digit.h" -#include "DataFormatsFIT/Triggers.h" -#include "CommonConstants/LHCConstants.h" +#include "PWGUD/Core/DGCutparHolder.h" +#include "PWGUD/Core/UPCHelpers.h" + #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" #include "Common/DataModel/PIDResponse.h" -#include "PWGUD/Core/UPCHelpers.h" -#include "PWGUD/Core/DGCutparHolder.h" +#include "Common/DataModel/TrackSelectionTables.h" -using namespace o2; -using namespace o2::framework; +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsFIT/Triggers.h" +#include "DataFormatsFT0/Digit.h" +#include "Framework/Logger.h" + +#include "TLorentzVector.h" + +#include +#include // namespace with helpers for UD framework namespace udhelpers @@ -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; } } @@ -651,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)) @@ -676,74 +673,64 @@ 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, o2::aod::FT0s const& ft0s, o2::aod::FV0As const& fv0as, o2::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); } // ----------------------------------------------------------------------------- template -bool cleanZDC(T const& bc, aod::Zdcs& zdcs, std::vector& /*lims*/, SliceCache& cache) +bool cleanZDC(T const& bc, o2::aod::Zdcs& zdcs, std::vector& /*lims*/, o2::framework::SliceCache& cache) { - const auto& ZdcBC = zdcs.sliceByCached(aod::zdc::bcId, bc.globalIndex(), cache); + const auto& ZdcBC = zdcs.sliceByCached(o2::aod::zdc::bcId, bc.globalIndex(), cache); return (ZdcBC.size() == 0); } // ----------------------------------------------------------------------------- template -bool cleanCalo(T const& bc, aod::Calos& calos, std::vector& /*lims*/, SliceCache& cache) +bool cleanCalo(T const& bc, o2::aod::Calos& calos, std::vector& /*lims*/, o2::framework::SliceCache& cache) { - const auto& CaloBC = calos.sliceByCached(aod::calo::bcId, bc.globalIndex(), cache); + const auto& CaloBC = calos.sliceByCached(o2::aod::calo::bcId, bc.globalIndex(), cache); return (CaloBC.size() == 0); } // ----------------------------------------------------------------------------- // check if all tracks come from same MCCollision template -int64_t sameMCCollision(T tracks, aod::McCollisions, aod::McParticles) +int64_t sameMCCollision(T tracks, o2::aod::McCollisions, o2::aod::McParticles) { int64_t colID = -1; for (auto const& track : tracks) { @@ -755,14 +742,14 @@ int64_t sameMCCollision(T tracks, aod::McCollisions, aod::McParticles) 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); } } @@ -775,7 +762,7 @@ int64_t sameMCCollision(T tracks, aod::McCollisions, aod::McParticles) template bool isPythiaCDE(T MCparts) { - for (auto mcpart : MCparts) { + for (const auto& mcpart : MCparts) { if (mcpart.pdgCode() == 9900110) { return true; } @@ -794,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; @@ -802,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; @@ -857,6 +857,11 @@ int isOfInterest(T MCparts) return 3; } + // Upcgen + if (isUpcgen(MCparts)) { + return 4; + } + return 0; } diff --git a/PWGUD/Core/UPCHelpers.h b/PWGUD/Core/UPCHelpers.h index 03ff2475c8c..a7ca4b63af4 100644 --- a/PWGUD/Core/UPCHelpers.h +++ b/PWGUD/Core/UPCHelpers.h @@ -12,16 +12,17 @@ #ifndef PWGUD_CORE_UPCHELPERS_H_ #define PWGUD_CORE_UPCHELPERS_H_ -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/CCDB/EventSelectionParams.h" -#include "CommonConstants/LHCConstants.h" -#include "TLorentzVector.h" #include "UPCCutparHolder.h" + #include "PWGUD/DataModel/UDTables.h" -using namespace o2::framework; -using namespace o2::framework::expressions; +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/EventSelection.h" + +#include "CommonConstants/LHCConstants.h" +#include "Framework/AnalysisDataModel.h" + +#include "TLorentzVector.h" using BCsWithBcSels = o2::soa::Join; diff --git a/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h b/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h index df0f4d0c260..2a53f2f41f8 100644 --- a/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h +++ b/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h @@ -16,21 +16,19 @@ #ifndef PWGUD_CORE_UPCJPSICENTRALBARRELCORRHELPER_H_ #define PWGUD_CORE_UPCJPSICENTRALBARRELCORRHELPER_H_ -#include #include "CommonConstants/MathConstants.h" -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace std; +#include +#include +#include -enum ParticleType { +/*enum ParticleType { P_ELECTRON = 0, P_MUON = 1, P_PROTON = 2 -}; +};*/ -template +/*template int testPIDhypoTPC(T trackPID) { float nSigmaTPC[3]; @@ -71,7 +69,7 @@ int testPIDhypo(T trackPID) } else { return -1; } -} +}*/ float* correlation(TLorentzVector* lv1, TLorentzVector* lv2, TLorentzVector* lv) { @@ -217,4 +215,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/UPCPairCuts.h b/PWGUD/Core/UPCPairCuts.h new file mode 100644 index 00000000000..f53b419ffda --- /dev/null +++ b/PWGUD/Core/UPCPairCuts.h @@ -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. + +/// \brief Functions which cut on particle pairs (decays, conversions, two-track cuts) adapted for data from UD tables +/// Based on the code "PWGCF/Core/PairCuts.h" made by Jan Fiete Grosse-Oetringhaus +/// Author: + +#ifndef PWGUD_CORE_UPCPAIRCUTS_H_ +#define PWGUD_CORE_UPCPAIRCUTS_H_ + +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" + +#include "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" + +#include + +class UPCPairCuts +{ + public: + enum Particle { Photon = 0, + K0, + Lambda, + Phi, + Rho, + ParticlesLastEntry }; + + void setHistogramRegistry(o2::framework::HistogramRegistry* registry) { histogramRegistry = registry; } + + void setPairCut(Particle particle, float cut) + { + LOGF(info, "Enabled pair cut for %d with value %f", static_cast(particle), cut); + mCuts[particle] = cut; + if (histogramRegistry != nullptr && histogramRegistry->contains(HIST("ControlConvResonances")) == false) { + histogramRegistry->add("ControlConvResonances", "", {o2::framework::HistType::kTH2F, {{6, -0.5, 5.5, "id"}, {500, -0.5, 0.5, "delta mass"}}}); + } + } + + void setTwoTrackCuts(float distance = 0.02f, float radius = 0.8f) + { + LOGF(info, "Enabled two-track cut with distance %f and radius %f", distance, radius); + mTwoTrackDistance = distance; + mTwoTrackRadius = radius; + + if (histogramRegistry != nullptr && histogramRegistry->contains(HIST("TwoTrackDistancePt_0")) == false) { + histogramRegistry->add("TwoTrackDistancePt_0", "", {o2::framework::HistType::kTH3F, {{100, -0.15, 0.15, "#Delta#eta"}, {100, -0.05, 0.05, "#Delta#varphi^{*}_{min}"}, {20, 0, 10, "#Delta p_{T}"}}}); + histogramRegistry->addClone("TwoTrackDistancePt_0", "TwoTrackDistancePt_1"); + } + } + + template + bool conversionCuts(T const& track1, T const& track2); + + template + bool twoTrackCut(T const& track1, T const& track2); + + protected: + float mCuts[ParticlesLastEntry] = {-1}; + float mTwoTrackDistance = -1; // distance below which the pair is flagged as to be removed + float mTwoTrackRadius = 0.8f; // radius at which the two track cuts are applied + int magField = 5; // magField: B field in kG + + o2::framework::HistogramRegistry* histogramRegistry = nullptr; // if set, control histograms are stored here + + template + bool conversionCut(T const& track1, T const& track2, Particle conv, double cut); + + template + double getInvMassSquared(T const& track1, double m0_1, T const& track2, double m0_2); + + template + double getInvMassSquaredFast(T const& track1, double m0_1, T const& track2, double m0_2); + + template + float getDPhiStar(T const& track1, T const& track2, float radius, int magField); +}; + +template +bool UPCPairCuts::conversionCuts(T const& track1, T const& track2) +{ + // skip if like sign + if (track1.sign() * track2.sign() > 0) { + return false; + } + + for (int i = 0; i < static_cast(ParticlesLastEntry); i++) { + Particle particle = static_cast(i); + if (mCuts[i] > 0) { + if (conversionCut(track1, track2, particle, mCuts[i])) { + return true; + } + if (particle == Lambda) { + if (conversionCut(track2, track1, particle, mCuts[i])) { + return true; + } + } + } + } + + return false; +} + +template +bool UPCPairCuts::twoTrackCut(T const& track1, T const& track2) +{ + // the variables & cut have been developed in Run 1 by the CF - HBT group + // + // Parameters: + // magField: B field in kG + + auto deta = eta(track1.px(), track1.py(), track1.pz()) - eta(track2.px(), track2.py(), track2.pz()); + + // optimization + if (std::fabs(deta) < mTwoTrackDistance * 2.5 * 3) { + // check first boundaries to see if is worth to loop and find the minimum + float dphistar1 = getDPhiStar(track1, track2, mTwoTrackRadius, magField); + float dphistar2 = getDPhiStar(track1, track2, 2.5, magField); + + const float kLimit = mTwoTrackDistance * 3; + + if (std::fabs(dphistar1) < kLimit || std::fabs(dphistar2) < kLimit || dphistar1 * dphistar2 < 0) { + float dphistarminabs = 1e5; + float dphistarmin = 1e5; + for (Double_t rad = mTwoTrackRadius; rad < 2.51; rad += 0.01) { + float dphistar = getDPhiStar(track1, track2, rad, magField); + + float dphistarabs = std::fabs(dphistar); + + if (dphistarabs < dphistarminabs) { + dphistarmin = dphistar; + dphistarminabs = dphistarabs; + } + } + + if (histogramRegistry != nullptr) { + histogramRegistry->fill(HIST("TwoTrackDistancePt_0"), deta, dphistarmin, std::fabs(track1.pt() - track2.pt())); + } + + if (dphistarminabs < mTwoTrackDistance && std::fabs(deta) < mTwoTrackDistance) { + // LOGF(debug, "Removed track pair %ld %ld with %f %f %f %f %d %f %f %d %d", track1.index(), track2.index(), deta, dphistarminabs, track1.phi2(), track1.pt(), track1.sign(), track2.phi2(), track2.pt(), track2.sign(), magField); + return true; + } + + if (histogramRegistry != nullptr) { + histogramRegistry->fill(HIST("TwoTrackDistancePt_1"), deta, dphistarmin, std::fabs(track1.pt() - track2.pt())); + } + } + } + + return false; +} + +template +bool UPCPairCuts::conversionCut(T const& track1, T const& track2, Particle conv, double cut) +{ + // LOGF(info, "pt is %f %f", track1.pt(), track2.pt()); + + if (cut < 0) { + return false; + } + + double massD1, massD2, massM; + + switch (conv) { + case Photon: + massD1 = o2::constants::physics::MassElectron; + massD2 = o2::constants::physics::MassElectron; + massM = 0; + break; + case K0: + massD1 = o2::constants::physics::MassPiPlus; + massD2 = o2::constants::physics::MassPiPlus; + massM = o2::constants::physics::MassK0; + break; + case Lambda: + massD1 = o2::constants::physics::MassProton; + massD2 = o2::constants::physics::MassPiPlus; + massM = o2::constants::physics::MassLambda0; + break; + case Phi: + massD1 = o2::constants::physics::MassKPlus; + massD2 = o2::constants::physics::MassKPlus; + massM = o2::constants::physics::MassPhi; + break; + case Rho: + massD1 = o2::constants::physics::MassPiPlus; + massD2 = o2::constants::physics::MassPiPlus; + massM = 0.770; + break; + default: + LOGF(fatal, "Particle now known"); + return false; + break; + } + + auto massC = getInvMassSquaredFast(track1, massD1, track2, massD2); + + if (std::fabs(massC - massM * massM) > cut * 5) { + return false; + } + + massC = getInvMassSquared(track1, massD1, track2, massD2); + + if (histogramRegistry != nullptr) { + histogramRegistry->fill(HIST("ControlConvResonances"), static_cast(conv), massC - massM * massM); + } + + if (massC > (massM - cut) * (massM - cut) && massC < (massM + cut) * (massM + cut)) { + return true; + } + + return false; +} + +template +double UPCPairCuts::getInvMassSquared(T const& track1, double m0_1, T const& track2, double m0_2) +{ + // 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 (eta(track1.px(), track1.py(), track1.pz()) < -1e-10 || eta(track1.px(), track1.py(), track1.pz()) > 1e-10) { + float expTmp = std::exp(-eta(track1.px(), track1.py(), track1.pz())); + tantheta1 = 2.0 * expTmp / (1.0 - expTmp * expTmp); + } + + float tantheta2 = 1e10; + if (eta(track2.px(), track2.py(), track2.pz()) < -1e-10 || eta(track2.px(), track2.py(), track2.pz()) > 1e-10) { + float expTmp = std::exp(-eta(track2.px(), track2.py(), track2.pz())); + 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(phi(track1.px(), track1.py()) - phi(track2.px(), track2.py())) + 1.0 / tantheta1 / tantheta2))); + + // LOGF(debug, "%f %f %f %f %f %f %f %f %f", pt1, eta1, phi1, pt2, eta2, phi2, m0_1, m0_2, mass2); + + return mass2; +} + +template +double UPCPairCuts::getInvMassSquaredFast(T const& track1, double m0_1, T const& track2, double m0_2) +{ + // calculate inv mass squared approximately + + const float eta1 = eta(track1.px(), track1.py(), track1.pz()); + const float eta2 = eta(track2.px(), track2.py(), track2.pz()); + const float phi1 = phi(track1.px(), track1.py()); + const float phi2 = phi(track2.px(), track2.py()); + const float pt1 = track1.pt(); + const float pt2 = track2.pt(); + + float tantheta1 = 1e10f; + + if (eta1 < -1e-10f || eta1 > 1e-10f) { + float expTmp = 1.0f - eta1 + eta1 * eta1 / 2.0f - eta1 * eta1 * eta1 / 6.0f + eta1 * eta1 * eta1 * eta1 / 24.0f; + tantheta1 = 2.0f * expTmp / (1.0f - expTmp * expTmp); + } + + float tantheta2 = 1e10f; + if (eta2 < -1e-10f || eta2 > 1e-10f) { + float expTmp = 1.0f - eta2 + eta2 * eta2 / 2.0f - eta2 * eta2 * eta2 / 6.0f + eta2 * eta2 * eta2 * eta2 / 24.0f; + tantheta2 = 2.0f * expTmp / (1.0f - expTmp * expTmp); + } + + float e1squ = m0_1 * m0_1 + pt1 * pt1 * (1.0f + 1.0f / tantheta1 / tantheta1); + float e2squ = m0_2 * m0_2 + pt2 * pt2 * (1.0f + 1.0f / tantheta2 / tantheta2); + + // fold onto 0...pi + float deltaPhi = std::fabs(phi1 - phi2); + while (deltaPhi > o2::constants::math::TwoPI) { + deltaPhi -= o2::constants::math::TwoPI; + } + if (deltaPhi > o2::constants::math::PI) { + deltaPhi = o2::constants::math::TwoPI - deltaPhi; + } + + float cosDeltaPhi = 0; + if (deltaPhi < o2::constants::math::PI / 3.0f) { + cosDeltaPhi = 1.0 - deltaPhi * deltaPhi / 2 + deltaPhi * deltaPhi * deltaPhi * deltaPhi / 24; + } else if (deltaPhi < 2.0f * o2::constants::math::PI / 3.0f) { + cosDeltaPhi = -(deltaPhi - o2::constants::math::PI / 2) + 1.0 / 6 * std::pow((deltaPhi - o2::constants::math::PI / 2), 3); + } else { + cosDeltaPhi = -1.0f + 1.0f / 2.0f * (deltaPhi - o2::constants::math::PI) * (deltaPhi - o2::constants::math::PI) - 1.0f / 24.0f * std::pow(deltaPhi - o2::constants::math::PI, 4.0f); + } + + double mass2 = m0_1 * m0_1 + m0_2 * m0_2 + 2.0f * (std::sqrt(e1squ * e2squ) - (pt1 * pt2 * (cosDeltaPhi + 1.0f / tantheta1 / tantheta2))); + + // LOGF(debug, "%f %f %f %f %f %f %f %f %f", pt1, eta1, phi1, pt2, eta2, phi2, m0_1, m0_2, mass2); + + return mass2; +} + +template +float UPCPairCuts::getDPhiStar(T const& track1, T const& track2, float radius, int magField) +{ + // + // calculates dphistar + // + + auto phi1 = phi(track1.px(), track1.py()); + auto pt1 = track1.pt(); + auto charge1 = track1.sign(); + + auto phi2 = phi(track2.px(), track2.py()); + auto pt2 = track2.pt(); + auto charge2 = track2.sign(); + + float dphistar = phi1 - phi2 - charge1 * std::asin(0.015 * magField * radius / pt1) + charge2 * std::asin(0.015 * magField * radius / pt2); + + if (dphistar > o2::constants::math::PI) { + dphistar = o2::constants::math::TwoPI - dphistar; + } + if (dphistar < -o2::constants::math::PI) { + dphistar = -o2::constants::math::TwoPI - dphistar; + } + if (dphistar > o2::constants::math::PI) { // might look funny but is needed + dphistar = o2::constants::math::TwoPI - dphistar; + } + + return dphistar; +} + +#endif // PWGUD_CORE_UPCPAIRCUTS_H_ diff --git a/PWGUD/Core/UPCTauCentralBarrelHelperRL.h b/PWGUD/Core/UPCTauCentralBarrelHelperRL.h index 4b757fdc963..41af7ec5d78 100644 --- a/PWGUD/Core/UPCTauCentralBarrelHelperRL.h +++ b/PWGUD/Core/UPCTauCentralBarrelHelperRL.h @@ -8,27 +8,45 @@ // In applying this license CERN does 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 + +/// \file UPCTauCentralBarrelHelperRL.h +/// \brief Personal helper file to analyze tau events from UPC collisions /// \author Roman Lavicka, roman.lavicka@cern.ch /// \since 27.10.2022 +/// #ifndef PWGUD_CORE_UPCTAUCENTRALBARRELHELPERRL_H_ #define PWGUD_CORE_UPCTAUCENTRALBARRELHELPERRL_H_ -#include -#include +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; +#include +#include 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) @@ -106,18 +124,18 @@ int testPIDhypothesis(T trackPIDinfo, float maxNsigmaTPC = 5.0, float maxNsigmaT } 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 { printDebugMessage("Something is wrong with track PDG selector"); @@ -144,6 +162,31 @@ int enumMyParticle(int valuePDG) } } +int trackPDGfromEnum(int trackEnum) +// reads pdg value and returns particle number as in enumMyParticle +{ + if (trackEnum == P_ELECTRON) { + return 11; + } else if (trackEnum == P_MUON) { + return 13; + } else if (trackEnum == P_PION) { + return 211; + } else if (trackEnum == P_KAON) { + return 321; + } else if (trackEnum == P_PROTON) { + return 2212; + } else { + 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 { @@ -188,16 +231,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..ed05772364e --- /dev/null +++ b/PWGUD/Core/decayTree.cxx @@ -0,0 +1,1221 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "decayTree.h" + +#include +#include + +#include +#include +#include +#include +#include + +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..59421098605 --- /dev/null +++ b/PWGUD/Core/decayTree.h @@ -0,0 +1,996 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/Logger.h" +#include "Framework/O2DatabasePDGPlugin.h" + +#include "TDatabasePDG.h" +#include "TLorentzVector.h" + +#include +#include +#include +#include + +// ----------------------------------------------------------------------------- +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, o2::framework::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(o2::framework::HistogramRegistry& registry) + { + // definitions + auto etax = o2::framework::AxisSpec(100, -1.5, 1.5); + auto nSax = o2::framework::AxisSpec(300, -15.0, 15.0); + auto chi2ax = o2::framework::AxisSpec(100, 0.0, 5.0); + auto nClax = o2::framework::AxisSpec(170, 0.0, 170.0); + auto angax = o2::framework::AxisSpec(315, 0.0, 3.15); + auto dcaxyax = o2::framework::AxisSpec(400, -0.2, 0.2); + auto dcazax = o2::framework::AxisSpec(600, -0.3, 0.3); + auto sTPCax = o2::framework::AxisSpec(1000, 0., 1000.); + + std::string base; + std::string hname; + std::string annot; + fhistPointers.clear(); + for (const auto& res : getResonances()) { + auto max = o2::framework::AxisSpec(res->nmassBins(), res->massHistRange()[0], res->massHistRange()[1]); + auto momax = o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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 = o2::framework::AxisSpec(d1->nmomBins(), d1->momHistRange()[0], d1->momHistRange()[1]); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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 = o2::framework::AxisSpec(res->nmassBins(), d1->massHistRange()[0], d1->massHistRange()[1]); + fhistPointers.insert({hname, registry.add(hname.c_str(), annot.c_str(), {o2::framework::HistType::kTH2F, {max, max1}})}); + } + } + + // daughters vs daughters + for (auto i = 0; i < static_cast(ndaughs - 1); i++) { + auto d1 = getResonance(daughs[i]); + auto max1 = o2::framework::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 = o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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(), {o2::framework::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/TauEventTables.h b/PWGUD/DataModel/TauEventTables.h new file mode 100644 index 00000000000..f508cbc2c4d --- /dev/null +++ b/PWGUD/DataModel/TauEventTables.h @@ -0,0 +1,224 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TauEventTables.h +/// \author Roman Lavička +/// \since 2025-04-23 +/// \brief A table to store information about events preselected to be candidates for UPC gammagamma->tautau +/// + +#ifndef ALISW_TAUEVENTTABLES_H +#define ALISW_TAUEVENTTABLES_H + +#include "Framework/AnalysisDataModel.h" + +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]); +// truth event +DECLARE_SOA_COLUMN(TrueChannel, trueChannel, int); +DECLARE_SOA_COLUMN(TrueHasRecoColl, trueHasRecoColl, bool); +DECLARE_SOA_COLUMN(TruePosX, truePosX, float); +DECLARE_SOA_COLUMN(TruePosY, truePosY, float); +DECLARE_SOA_COLUMN(TruePosZ, truePosZ, float); +// truth particles +DECLARE_SOA_COLUMN(TrueTauPx, trueTauPx, float[2]); +DECLARE_SOA_COLUMN(TrueTauPy, trueTauPy, float[2]); +DECLARE_SOA_COLUMN(TrueTauPz, trueTauPz, float[2]); +DECLARE_SOA_COLUMN(TrueDaugPx, trueDaugPx, float[2]); +DECLARE_SOA_COLUMN(TrueDaugPy, trueDaugPy, float[2]); +DECLARE_SOA_COLUMN(TrueDaugPz, trueDaugPz, float[2]); +DECLARE_SOA_COLUMN(TrueDaugPdgCode, trueDaugPdgCode, int[2]); +// additional info +DECLARE_SOA_COLUMN(ProblematicEvent, problematicEvent, bool); + +} // 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); + +DECLARE_SOA_TABLE(TrueTauTwoTracks, "AOD", "TRUETAUTWOTRACK", + 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, + tau_tree::TrueChannel, + tau_tree::TrueHasRecoColl, + tau_tree::TruePosX, + tau_tree::TruePosY, + tau_tree::TruePosZ, + tau_tree::TrueTauPx, + tau_tree::TrueTauPy, + tau_tree::TrueTauPz, + tau_tree::TrueDaugPx, + tau_tree::TrueDaugPy, + tau_tree::TrueDaugPz, + tau_tree::TrueDaugPdgCode, + tau_tree::ProblematicEvent); + +} // namespace o2::aod + +#endif // ALISW_TAUEVENTTABLES_H diff --git a/PWGUD/DataModel/TauThreeProngEventTables.h b/PWGUD/DataModel/TauThreeProngEventTables.h new file mode 100644 index 00000000000..b670e8b7f69 --- /dev/null +++ b/PWGUD/DataModel/TauThreeProngEventTables.h @@ -0,0 +1,157 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TauThreeProngEventTables.h +/// \author Adam Matyja , IFJ PAN, Cracow +/// \since 2025-09-06 +/// \brief A table to store information about events preselected to be candidates for UPC gammagamma->tautau in 1+3 ot 3+3 topology +/// + +#ifndef PWGUD_DATAMODEL_TAUTHREEPRONGEVENTTABLES_H_ +#define PWGUD_DATAMODEL_TAUTHREEPRONGEVENTTABLES_H_ + +#include "Framework/AnalysisDataModel.h" +// derived tables for tautau->4 (=1+3) tracks +namespace o2::aod +{ +namespace tautree +{ +// 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, int8_t); +DECLARE_SOA_COLUMN(RctOk, rctOk, 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, int8_t); +DECLARE_SOA_COLUMN(OccupancyInTime, occupancyInTime, int); +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, double); +DECLARE_SOA_COLUMN(Trs, trs, int8_t); +DECLARE_SOA_COLUMN(Trofs, trofs, int8_t); +DECLARE_SOA_COLUMN(Hmpr, hmpr, int8_t); +DECLARE_SOA_COLUMN(Tfb, tfb, int8_t); +DECLARE_SOA_COLUMN(ItsRofb, itsRofb, int8_t); +DECLARE_SOA_COLUMN(Sbp, sbp, int8_t); +DECLARE_SOA_COLUMN(ZvtxFT0vsPv, zvtxFT0vsPv, int8_t); +DECLARE_SOA_COLUMN(VtxITSTPC, vtxITSTPC, int8_t); +DECLARE_SOA_COLUMN(ZdcAenergy, zdcAenergy, float); +DECLARE_SOA_COLUMN(ZdcCenergy, zdcCenergy, float); +// DECLARE_SOA_COLUMN(Qtot, qtot, int8_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[6]); +DECLARE_SOA_COLUMN(TrkPy, trkPy, float[6]); +DECLARE_SOA_COLUMN(TrkPz, trkPz, float[6]); +DECLARE_SOA_COLUMN(TrkSign, trkSign, int[6]); +DECLARE_SOA_COLUMN(TrkDCAxy, trkDCAxy, float[6]); +DECLARE_SOA_COLUMN(TrkDCAz, trkDCAz, float[6]); +DECLARE_SOA_COLUMN(TrkTPCcr, trkTPCcr, int[6]); +DECLARE_SOA_COLUMN(TrkTPCfind, trkTPCfind, int[6]); +DECLARE_SOA_COLUMN(TrkTPCchi2, trkTPCchi2, float[6]); +DECLARE_SOA_COLUMN(TrkITSchi2, trkITSchi2, float[6]); +DECLARE_SOA_COLUMN(TrkITScl, trkITScl, int[6]); +// PID +DECLARE_SOA_COLUMN(TrkTPCsignal, trkTPCsignal, float[6]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaEl, trkTPCnSigmaEl, float[6]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaPi, trkTPCnSigmaPi, float[6]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaKa, trkTPCnSigmaKa, float[6]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaPr, trkTPCnSigmaPr, float[6]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaMu, trkTPCnSigmaMu, float[6]); +DECLARE_SOA_COLUMN(TrkTOFbeta, trkTOFbeta, float[6]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaEl, trkTOFnSigmaEl, float[6]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaPi, trkTOFnSigmaPi, float[6]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaKa, trkTOFnSigmaKa, float[6]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaPr, trkTOFnSigmaPr, float[6]); +DECLARE_SOA_COLUMN(TrkTOFnSigmaMu, trkTOFnSigmaMu, float[6]); +DECLARE_SOA_COLUMN(TrkTOFchi2, trkTOFchi2, float[6]); +// truth event +DECLARE_SOA_COLUMN(TrueChannel, trueChannel, int); +DECLARE_SOA_COLUMN(TrueHasRecoColl, trueHasRecoColl, bool); +// DECLARE_SOA_COLUMN(TruePosX, truePosX, float); +// DECLARE_SOA_COLUMN(TruePosY, truePosY, float); +DECLARE_SOA_COLUMN(TruePosZ, truePosZ, float); +// truth tau particles // index 0: tau+ // index 1: tau - +DECLARE_SOA_COLUMN(TrueTauPx, trueTauPx, float[2]); +DECLARE_SOA_COLUMN(TrueTauPy, trueTauPy, float[2]); +DECLARE_SOA_COLUMN(TrueTauPz, trueTauPz, float[2]); +// truth tau daughter particles +DECLARE_SOA_COLUMN(TrueDaugPx, trueDaugPx, float[6]); +DECLARE_SOA_COLUMN(TrueDaugPy, trueDaugPy, float[6]); +DECLARE_SOA_COLUMN(TrueDaugPz, trueDaugPz, float[6]); +DECLARE_SOA_COLUMN(TrueDaugPdgCode, trueDaugPdgCode, int[6]); +DECLARE_SOA_COLUMN(Problem, problem, int8_t); +} // namespace tautree + +DECLARE_SOA_TABLE(DataTauFourTracks, "AOD", "TAUFOURTRACK", + tautree::RunNumber, tautree::Bc, tautree::TotalTracks, tautree::NumContrib, + tautree::RctOk, + // tautree::GlobalNonPVtracks, + // tautree::PosX, tautree::PosY, + tautree::PosZ, + tautree::FlagUPC, tautree::OccupancyInTime, tautree::HadronicRate, + // + tautree::Trs, tautree::Trofs, tautree::Hmpr, + tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, + tautree::ZdcAenergy, tautree::ZdcCenergy, + // tautree::Qtot, + tautree::TotalFT0AmplitudeA, tautree::TotalFT0AmplitudeC, tautree::TotalFV0AmplitudeA, + // tautree::TimeFT0A, tautree::TimeFT0C, tautree::TimeFV0A, + tautree::TrkPx, tautree::TrkPy, tautree::TrkPz, + tautree::TrkSign, + tautree::TrkDCAxy, tautree::TrkDCAz, + tautree::TrkTPCcr, + tautree::TrkTPCfind, tautree::TrkTPCchi2, tautree::TrkITSchi2, tautree::TrkITScl, + tautree::TrkTPCsignal, tautree::TrkTPCnSigmaEl, tautree::TrkTPCnSigmaPi, tautree::TrkTPCnSigmaKa, tautree::TrkTPCnSigmaPr, tautree::TrkTPCnSigmaMu, + tautree::TrkTOFbeta, tautree::TrkTOFnSigmaEl, tautree::TrkTOFnSigmaPi, tautree::TrkTOFnSigmaKa, tautree::TrkTOFnSigmaPr, tautree::TrkTOFnSigmaMu, + tautree::TrkTOFchi2); + +DECLARE_SOA_TABLE(TrueTauFourTracks, "AOD", "TRUETAU", + tautree::RunNumber, tautree::Bc, tautree::TotalTracks, tautree::NumContrib, + tautree::RctOk, + // tautree::GlobalNonPVtracks, + // tautree::PosX, tautree::PosY, + tautree::PosZ, + tautree::FlagUPC, tautree::OccupancyInTime, tautree::HadronicRate, + tautree::Trs, tautree::Trofs, tautree::Hmpr, + tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, + tautree::ZdcAenergy, tautree::ZdcCenergy, + // tautree::Qtot, + tautree::TotalFT0AmplitudeA, tautree::TotalFT0AmplitudeC, tautree::TotalFV0AmplitudeA, + // tautree::TimeFT0A, tautree::TimeFT0C, tautree::TimeFV0A, + tautree::TrkPx, tautree::TrkPy, tautree::TrkPz, + tautree::TrkSign, + tautree::TrkDCAxy, tautree::TrkDCAz, + tautree::TrkTPCcr, + tautree::TrkTPCfind, tautree::TrkTPCchi2, tautree::TrkITSchi2, tautree::TrkITScl, + tautree::TrkTPCsignal, tautree::TrkTPCnSigmaEl, tautree::TrkTPCnSigmaPi, tautree::TrkTPCnSigmaKa, tautree::TrkTPCnSigmaPr, tautree::TrkTPCnSigmaMu, + tautree::TrkTOFbeta, tautree::TrkTOFnSigmaEl, tautree::TrkTOFnSigmaPi, tautree::TrkTOFnSigmaKa, tautree::TrkTOFnSigmaPr, tautree::TrkTOFnSigmaMu, + tautree::TrkTOFchi2, + tautree::TrueChannel, + tautree::TrueHasRecoColl, + tautree::TruePosZ, + tautree::TrueTauPx, tautree::TrueTauPy, tautree::TrueTauPz, + tautree::TrueDaugPx, tautree::TrueDaugPy, tautree::TrueDaugPz, + tautree::TrueDaugPdgCode, + tautree::Problem); + +} // namespace o2::aod + +#endif // PWGUD_DATAMODEL_TAUTHREEPRONGEVENTTABLES_H_ diff --git a/PWGUD/DataModel/TwoTracksEventTables.h b/PWGUD/DataModel/TwoTracksEventTables.h new file mode 100644 index 00000000000..73be3f3c438 --- /dev/null +++ b/PWGUD/DataModel/TwoTracksEventTables.h @@ -0,0 +1,226 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TwoTracksEventTables.h +/// \author Roman Lavička +/// \since 2025-06-20 +/// \brief A table to store information about events preselected to have exactly two tracks. +/// \brief Good for UPC gammagamma (->elel,mumu,tautau) and gammalead (vector mesons) +/// \brief If MC, careful with filling the mother +/// + +#ifndef PWGUD_DATAMODEL_TWOTRACKSEVENTTABLES_H_ +#define PWGUD_DATAMODEL_TWOTRACKSEVENTTABLES_H_ + +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace two_tracks_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]); +// truth event +DECLARE_SOA_COLUMN(TrueChannel, trueChannel, int); +DECLARE_SOA_COLUMN(TrueHasRecoColl, trueHasRecoColl, bool); +DECLARE_SOA_COLUMN(TruePosX, truePosX, float); +DECLARE_SOA_COLUMN(TruePosY, truePosY, float); +DECLARE_SOA_COLUMN(TruePosZ, truePosZ, float); +// truth particles +DECLARE_SOA_COLUMN(TrueMotherPx, trueMotherPx, float[2]); +DECLARE_SOA_COLUMN(TrueMotherPy, trueMotherPy, float[2]); +DECLARE_SOA_COLUMN(TrueMotherPz, trueMotherPz, float[2]); +DECLARE_SOA_COLUMN(TrueDaugPx, trueDaugPx, float[2]); +DECLARE_SOA_COLUMN(TrueDaugPy, trueDaugPy, float[2]); +DECLARE_SOA_COLUMN(TrueDaugPz, trueDaugPz, float[2]); +DECLARE_SOA_COLUMN(TrueDaugPdgCode, trueDaugPdgCode, int[2]); +// additional info +DECLARE_SOA_COLUMN(ProblematicEvent, problematicEvent, bool); + +} // namespace two_tracks_tree +DECLARE_SOA_TABLE(TwoTracks, "AOD", "TWOTRACK", + two_tracks_tree::RunNumber, + two_tracks_tree::Bc, + two_tracks_tree::TotalTracks, + two_tracks_tree::NumContrib, + two_tracks_tree::GlobalNonPVtracks, + two_tracks_tree::PosX, + two_tracks_tree::PosY, + two_tracks_tree::PosZ, + two_tracks_tree::RecoMode, + two_tracks_tree::OccupancyInTime, + two_tracks_tree::HadronicRate, + two_tracks_tree::Trs, + two_tracks_tree::Trofs, + two_tracks_tree::Hmpr, + two_tracks_tree::Tfb, + two_tracks_tree::ItsRofb, + two_tracks_tree::Sbp, + two_tracks_tree::ZvtxFT0vsPv, + two_tracks_tree::VtxITSTPC, + two_tracks_tree::TotalFT0AmplitudeA, + two_tracks_tree::TotalFT0AmplitudeC, + two_tracks_tree::TotalFV0AmplitudeA, + two_tracks_tree::EnergyCommonZNA, + two_tracks_tree::EnergyCommonZNC, + two_tracks_tree::TimeFT0A, + two_tracks_tree::TimeFT0C, + two_tracks_tree::TimeFV0A, + two_tracks_tree::TimeZNA, + two_tracks_tree::TimeZNC, + two_tracks_tree::TrkPx, + two_tracks_tree::TrkPy, + two_tracks_tree::TrkPz, + two_tracks_tree::TrkSign, + two_tracks_tree::TrkDCAxy, + two_tracks_tree::TrkDCAz, + two_tracks_tree::TrkTimeRes, + two_tracks_tree::Trk1ITSclusterSizes, + two_tracks_tree::Trk2ITSclusterSizes, + two_tracks_tree::TrkTPCsignal, + two_tracks_tree::TrkTPCnSigmaEl, + two_tracks_tree::TrkTPCnSigmaMu, + two_tracks_tree::TrkTPCnSigmaPi, + two_tracks_tree::TrkTPCnSigmaKa, + two_tracks_tree::TrkTPCnSigmaPr, + two_tracks_tree::TrkTPCinnerParam, + two_tracks_tree::TrkTOFsignal, + two_tracks_tree::TrkTOFnSigmaEl, + two_tracks_tree::TrkTOFnSigmaMu, + two_tracks_tree::TrkTOFnSigmaPi, + two_tracks_tree::TrkTOFnSigmaKa, + two_tracks_tree::TrkTOFnSigmaPr, + two_tracks_tree::TrkTOFexpMom); + +DECLARE_SOA_TABLE(TrueTwoTracks, "AOD", "TRUETWOTRACK", + two_tracks_tree::RunNumber, + two_tracks_tree::Bc, + two_tracks_tree::TotalTracks, + two_tracks_tree::NumContrib, + two_tracks_tree::GlobalNonPVtracks, + two_tracks_tree::PosX, + two_tracks_tree::PosY, + two_tracks_tree::PosZ, + two_tracks_tree::RecoMode, + two_tracks_tree::OccupancyInTime, + two_tracks_tree::HadronicRate, + two_tracks_tree::Trs, + two_tracks_tree::Trofs, + two_tracks_tree::Hmpr, + two_tracks_tree::Tfb, + two_tracks_tree::ItsRofb, + two_tracks_tree::Sbp, + two_tracks_tree::ZvtxFT0vsPv, + two_tracks_tree::VtxITSTPC, + two_tracks_tree::TotalFT0AmplitudeA, + two_tracks_tree::TotalFT0AmplitudeC, + two_tracks_tree::TotalFV0AmplitudeA, + two_tracks_tree::EnergyCommonZNA, + two_tracks_tree::EnergyCommonZNC, + two_tracks_tree::TimeFT0A, + two_tracks_tree::TimeFT0C, + two_tracks_tree::TimeFV0A, + two_tracks_tree::TimeZNA, + two_tracks_tree::TimeZNC, + two_tracks_tree::TrkPx, + two_tracks_tree::TrkPy, + two_tracks_tree::TrkPz, + two_tracks_tree::TrkSign, + two_tracks_tree::TrkDCAxy, + two_tracks_tree::TrkDCAz, + two_tracks_tree::TrkTimeRes, + two_tracks_tree::Trk1ITSclusterSizes, + two_tracks_tree::Trk2ITSclusterSizes, + two_tracks_tree::TrkTPCsignal, + two_tracks_tree::TrkTPCnSigmaEl, + two_tracks_tree::TrkTPCnSigmaMu, + two_tracks_tree::TrkTPCnSigmaPi, + two_tracks_tree::TrkTPCnSigmaKa, + two_tracks_tree::TrkTPCnSigmaPr, + two_tracks_tree::TrkTPCinnerParam, + two_tracks_tree::TrkTOFsignal, + two_tracks_tree::TrkTOFnSigmaEl, + two_tracks_tree::TrkTOFnSigmaMu, + two_tracks_tree::TrkTOFnSigmaPi, + two_tracks_tree::TrkTOFnSigmaKa, + two_tracks_tree::TrkTOFnSigmaPr, + two_tracks_tree::TrkTOFexpMom, + two_tracks_tree::TrueChannel, + two_tracks_tree::TrueHasRecoColl, + two_tracks_tree::TruePosX, + two_tracks_tree::TruePosY, + two_tracks_tree::TruePosZ, + two_tracks_tree::TrueMotherPx, + two_tracks_tree::TrueMotherPy, + two_tracks_tree::TrueMotherPz, + two_tracks_tree::TrueDaugPx, + two_tracks_tree::TrueDaugPy, + two_tracks_tree::TrueDaugPz, + two_tracks_tree::TrueDaugPdgCode, + two_tracks_tree::ProblematicEvent); + +} // namespace o2::aod + +#endif // PWGUD_DATAMODEL_TWOTRACKSEVENTTABLES_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 ece6b952678..8a4251ec74d 100644 --- a/PWGUD/DataModel/UDTables.h +++ b/PWGUD/DataModel/UDTables.h @@ -8,18 +8,29 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +// +/// \file UDTables.h +/// \brief Defines tables and colums for derived data used by UD group +/// \author Paul Buhler , Wiena +/// \since January 2023 +/// \author Sasha Bylinkin , Bergen +/// \since January 2024 +/// \author Adam Matyja , INP PAN Krakow, Poland +/// \since May 2025 #ifndef PWGUD_DATAMODEL_UDTABLES_H_ #define PWGUD_DATAMODEL_UDTABLES_H_ -#include -#include +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/TrackSelectionTables.h" + #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" + +#include +#include namespace o2::aod { @@ -29,7 +40,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 +64,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 +97,35 @@ 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); +// information about mask names -> Common/CCDB/RCTSelectionFlags.h +// DECLARE_SOA_COLUMN(Rct, rct, uint32_t); //! run condition table mask +DECLARE_SOA_BITMAP_COLUMN(Rct, rct, 32); //! run condition table mask + // 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 +181,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 +191,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 +228,60 @@ 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 + +DECLARE_SOA_TABLE_VERSIONED(UDCollisionSelExtras_003, "AOD", "UDCOLSELEXTRA", 3, + 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 + udcollision::Rct); //! RCT mask + // central barrel-specific selections DECLARE_SOA_TABLE(UDCollisionsSelsCent, "AOD", "UDCOLSELCNT", udcollision::DBcTOR, @@ -208,11 +304,15 @@ DECLARE_SOA_TABLE(UDCollsLabels, "AOD", "UDCOLLSLABEL", DECLARE_SOA_TABLE(UDMcCollsLabels, "AOD", "UDMCCOLLSLABEL", udcollision::UDMcCollisionId); +using UDCollisions = UDCollisions_001; +using UDCollisionSelExtras = UDCollisionSelExtras_003; + 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 +364,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, @@ -372,18 +476,32 @@ DECLARE_SOA_TABLE(UDFwdIndices, "AOD", "UDFWDINDEX", udfwdmatchindex::MFTTrackId); // Muon track quality details -DECLARE_SOA_TABLE(UDFwdTracksExtra, "AOD", "UDFWDTRACKEXTRA", - fwdtrack::TrackType, +// Version with only MCH-MID tracks +DECLARE_SOA_TABLE(UDFwdTracksExtra_000, "AOD", "UDFWDTRACKEXTRA", fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMID, - fwdtrack::Chi2MatchMCHMFT, fwdtrack::MCHBitMap, 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; diff --git a/PWGUD/TableProducer/CMakeLists.txt b/PWGUD/TableProducer/CMakeLists.txt index 2406868718c..651a51bddc6 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::AnalysisCCDB O2Physics::EventFilteringUtils 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,32 @@ 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(two-tracks-event-table-producer + SOURCES twoTracksEventTableProducer.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) + +o2physics_add_dpl_workflow(tau-three-prong-event-table-producer + SOURCES tauThreeProngEventTableProducer.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..7d5a6297ba1 --- /dev/null +++ b/PWGUD/TableProducer/Converters/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. + +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) + +o2physics_add_dpl_workflow(collisionselextras-converter-v003 + SOURCES UDCollisionSelExtrasV003Converter.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/UDCollisionSelExtrasV003Converter.cxx b/PWGUD/TableProducer/Converters/UDCollisionSelExtrasV003Converter.cxx new file mode 100644 index 00000000000..a41b2c4efa6 --- /dev/null +++ b/PWGUD/TableProducer/Converters/UDCollisionSelExtrasV003Converter.cxx @@ -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 UDCollisionSelExtrasV003Converter.cxx +/// \brief Converts UDCollisionSelExtras table from version 000 to 003 and 001 to 003 and 002 to 003 +/// \author Adam Matyja + +#include "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; + +// Converts UDCollisions for version 000 to 003 and 001 to 003 and 002 to 003 +struct UDCollisionSelExtrasV003Converter { + Produces udCollisionSelExtras_003; + + void init(InitContext const&) + { + if (!doprocessV000ToV003 && !doprocessV001ToV003 && !doprocessV002ToV003) { + LOGF(fatal, "Neither processV000ToV003 nor processV001ToV003 nor processV002ToV003 is enabled. Please choose one!"); + } + if (static_cast(doprocessV000ToV003) + static_cast(doprocessV001ToV003) + static_cast(doprocessV002ToV003) > 1) { + LOGF(fatal, "More than one among processV000ToV003, processV001ToV003, processV002ToV003 is enabled. Please choose only one!"); + } + } + + void processV000ToV003(o2::aod::UDCollisionSelExtras_000 const& collisions) + { + + for (const auto& collision : collisions) { + + udCollisionSelExtras_003(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 + 0); // dummy rct + } + } + PROCESS_SWITCH(UDCollisionSelExtrasV003Converter, processV000ToV003, "process v000-to-v003 conversion", false); + + void processV001ToV003(o2::aod::UDCollisionSelExtras_001 const& collisions) + { + + for (const auto& collision : collisions) { + + udCollisionSelExtras_003(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 + 0); // dummy rct + } + } + PROCESS_SWITCH(UDCollisionSelExtrasV003Converter, processV001ToV003, "process v001-to-v003 conversion", false); + + void processV002ToV003(o2::aod::UDCollisionSelExtras_002 const& collisions) + { + + for (const auto& collision : collisions) { + + udCollisionSelExtras_003(collision.chFT0A(), + collision.chFT0C(), + collision.chFDDA(), + collision.chFDDC(), + collision.chFV0A(), + collision.occupancyInTime(), + collision.hadronicRate(), + collision.trs(), + collision.trofs(), + collision.hmpr(), + collision.tfb(), + collision.itsROFb(), + collision.sbp(), + collision.zVtxFT0vPV(), + collision.vtxITSTPC(), + 0); // dummy rct + } + } + PROCESS_SWITCH(UDCollisionSelExtrasV003Converter, processV002ToV003, "process v002-to-v003 conversion", true); +}; + +/// Spawn the extended table for UDCollisionSelExtras003 to avoid the call to the internal spawner and a consequent circular dependency +// struct UDCollisionSelExtrasSpawner { +// Spawns udCollisionSelExtras_003; +// }; + +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/DGBCCandProducer.h b/PWGUD/TableProducer/DGBCCandProducer.h index 07717afbfde..5bdc09498c6 100644 --- a/PWGUD/TableProducer/DGBCCandProducer.h +++ b/PWGUD/TableProducer/DGBCCandProducer.h @@ -16,15 +16,13 @@ #ifndef PWGUD_TABLEPRODUCER_DGBCCANDPRODUCER_H_ #define PWGUD_TABLEPRODUCER_DGBCCANDPRODUCER_H_ -#include -#include #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" -#include "MathUtils/Utils.h" #include "Framework/DataTypes.h" +#include "MathUtils/Utils.h" -using namespace o2; -using namespace o2::framework; +#include +#include namespace o2::aod { diff --git a/PWGUD/TableProducer/DGCandProducer.cxx b/PWGUD/TableProducer/DGCandProducer.cxx index e0a6f5df303..5f9a4d4bb79 100644 --- a/PWGUD/TableProducer/DGCandProducer.cxx +++ b/PWGUD/TableProducer/DGCandProducer.cxx @@ -12,29 +12,35 @@ // \brief Saves relevant information of DG candidates // \author Paul Buehler, paul.buehler@oeaw.ac.at -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "PWGUD/DataModel/UDTables.h" -#include "PWGUD/Core/UPCHelpers.h" #include "PWGUD/Core/DGSelector.h" +#include "PWGUD/Core/UPCHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" + +#include "CCDB/BasicCCDBManager.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Vertex.h" + +#include +#include +#include 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 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; @@ -48,10 +54,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; @@ -64,6 +93,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) @@ -133,120 +165,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", "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", "", "", ""}; - - 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.); + getHist(TH1, histdir + "/Stat")->Fill(0., 1.); // nominal BC if (!collision.has_foundBC()) { return; } - registry.get(HIST("reco/Stat"))->Fill(1., 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()); @@ -256,18 +325,28 @@ struct DGCandProducer { auto isDGEvent = dgSelector.IsSelected(diffCuts, collision, bcRange, tracks, fwdtracks); // save DG candidates - registry.get(HIST("reco/Stat"))->Fill(isDGEvent + 2, 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, @@ -278,17 +357,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, collision.rct_raw()); 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()); } @@ -315,7 +395,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) { @@ -331,13 +411,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 { @@ -347,6 +475,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; @@ -366,8 +498,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(), @@ -380,6 +514,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 @@ -406,38 +542,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, @@ -452,6 +625,7 @@ struct McDGCandProducer { mcpart.pz(), mcpart.e()); mcPartIsSaved[mcpart.globalIndex()] = outputMcParticles.lastIndex(); + LOGF(debug, " mcpart %d -> udmcpart %d", mcpart.globalIndex(), mcPartIsSaved[mcpart.globalIndex()]); } } } @@ -482,7 +656,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) { @@ -503,30 +677,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 @@ -536,36 +690,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) @@ -574,16 +734,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 @@ -596,19 +759,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()); @@ -626,12 +794,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(); @@ -643,17 +812,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 a38dc6a334c..c3cb33cb43e 100644 --- a/PWGUD/TableProducer/SGCandProducer.cxx +++ b/PWGUD/TableProducer/SGCandProducer.cxx @@ -8,29 +8,74 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +// +/// \file SGCandProducer.cxx +/// \brief Produces PWGUD derived table from standard tables +/// +/// \author Alexander Bylinkin , Uniersity of Bergen +/// \since 23.11.2023 +/// \author Adam Matyja , INP PAN Krakow, Poland +/// \since May 2025 +// + +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UPCHelpers.h" +#include "PWGUD/DataModel/UDTables.h" -#include -#include "Framework/ASoA.h" -#include "Framework/AnalysisDataModel.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/DataModel/EventSelection.h" + +#include "CCDB/BasicCCDBManager.h" #include "CommonConstants/LHCConstants.h" #include "DataFormatsFIT/Triggers.h" - -#include "Framework/runDataProcessing.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" -#include "PWGUD/DataModel/UDTables.h" -#include "PWGUD/Core/UPCHelpers.h" -#include "PWGUD/Core/SGSelector.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Vertex.h" + +#include +#include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::dataformats; +using namespace o2::aod::rctsel; + +#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 +83,37 @@ 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"}; + Configurable storeSG{"storeSG", true, "Store SG events in the output"}; + Configurable storeDG{"storeDG", true, "Store DG events in the output"}; + + Configurable isGoodRCTCollision{"isGoodRCTCollision", true, "Check RCT flags for FT0,ITS,TPC and tracking"}; + Configurable isGoodRCTZdc{"isGoodRCTZdc", false, "Check RCT flags for ZDC if present in run"}; + + // 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; + + // initialize RCT flag checker + RCTFlagsChecker myRCTChecker{"CBT"}; // 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 +124,9 @@ struct SGCandProducer { HistogramRegistry registry{ "registry", {}}; + std::map histPointers; - // 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; + int runNumber = -1; // function to update UDFwdTracks, UDFwdTracksExtra template @@ -121,6 +175,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(), @@ -143,49 +205,144 @@ struct SGCandProducer { outputTracksLabel(track.globalIndex()); } - void init(InitContext&) + // function to process trigger counters, accounting for BC selection bits + void processCountersTrg(BCs const& bcs, aod::FT0s const&, aod::Zdcs const&) { - sameCuts = (SGCutParHolder)SGCuts; - registry.add("reco/Stat", "Cut statistics; Selection criterion; Collisions", {HistType::kTH1F, {{14, -0.5, 13.5}}}); + const auto& firstBc = bcs.iteratorAt(0); + if (runNumber != firstBc.runNumber()) + runNumber = firstBc.runNumber(); + + auto hCountersTrg = getHist(TH1, "reco/hCountersTrg"); + auto hCountersTrgBcSel = getHist(TH1, "reco/hCountersTrgBcSel"); + auto hLumi = getHist(TH1, "reco/hLumi"); + auto hLumiBcSel = getHist(TH1, "reco/hLumiBcSel"); + + // Cross sections in ub. Using dummy -1 if lumi estimator is not reliable + float csTCE = 10.36e6; + const float csZEM = 415.2e6; // see AN: https://alice-notes.web.cern.ch/node/1515 + const float csZNC = 214.5e6; // see AN: https://alice-notes.web.cern.ch/node/1515 + if (runNumber > 543437 && runNumber < 543514) { + csTCE = 8.3e6; + } + if (runNumber >= 543514) { + csTCE = 4.10e6; // see AN: https://alice-notes.web.cern.ch/node/1515 + } + + for (const auto& bc : bcs) { + bool hasFT0 = bc.has_foundFT0(); + bool hasZDC = bc.has_foundZDC(); + if (!hasFT0 && !hasZDC) + continue; + bool isSelectedBc = true; + if (rejectAtTFBoundary && !bc.selection_bit(aod::evsel::kNoTimeFrameBorder)) + isSelectedBc = false; + if (noITSROFrameBorder && !bc.selection_bit(aod::evsel::kNoITSROFrameBorder)) + isSelectedBc = false; + if (hasFT0) { + auto ft0TrgMask = bc.ft0().triggerMask(); + if (TESTBIT(ft0TrgMask, o2::fit::Triggers::bitVertex)) { + hCountersTrg->Fill("TVX", 1); + if (isSelectedBc) + hCountersTrgBcSel->Fill("TVX", 1); + } + if (TESTBIT(ft0TrgMask, o2::fit::Triggers::bitVertex) && TESTBIT(ft0TrgMask, o2::fit::Triggers::bitCen)) { + hCountersTrg->Fill("TCE", 1); + hLumi->Fill("TCE", 1. / csTCE); + if (isSelectedBc) { + hCountersTrgBcSel->Fill("TCE", 1); + hLumiBcSel->Fill("TCE", 1. / csTCE); + } + } + } + if (hasZDC) { + if (bc.selection_bit(aod::evsel::kIsBBZNA) || bc.selection_bit(aod::evsel::kIsBBZNC)) { + hCountersTrg->Fill("ZEM", 1); + hLumi->Fill("ZEM", 1. / csZEM); + if (isSelectedBc) { + hCountersTrgBcSel->Fill("ZEM", 1); + hLumiBcSel->Fill("ZEM", 1. / csZEM); + } + } + if (bc.selection_bit(aod::evsel::kIsBBZNC)) { + hCountersTrg->Fill("ZNC", 1); + hLumi->Fill("ZNC", 1. / csZNC); + if (isSelectedBc) { + hCountersTrgBcSel->Fill("ZNC", 1); + hLumiBcSel->Fill("ZNC", 1. / csZNC); + } + } + } + } } - // 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) + PROCESS_SWITCH(SGCandProducer, processCountersTrg, "Produce trigger counters and luminosity histograms", true); + + // 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; } - registry.get(HIST("reco/Stat"))->Fill(1., 1.); + 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(2., 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(3., 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(4., 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(5., 1.); + getHist(TH1, histdir + "/Stat")->Fill(5., 1.); // nominal BC if (!collision.has_foundBC()) { return; } - registry.get(HIST("reco/Stat"))->Fill(6., 1.); - auto bc = collision.foundBC_as(); + getHist(TH1, histdir + "/Stat")->Fill(6., 1.); + // RCT CBT for collision check + if (isGoodRCTCollision && !myRCTChecker(collision)) { + return; + } + getHist(TH1, histdir + "/Stat")->Fill(7., 1.); + // RCT CBT+ZDC for collision check + if (isGoodRCTZdc && !myRCTChecker(collision)) { + return; + } + getHist(TH1, histdir + "/Stat")->Fill(8., 1.); + + // + const int trs = collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) ? 1 : 0; + const int trofs = collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard) ? 1 : 0; + const int hmpr = collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof) ? 1 : 0; + const int tfb = collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) ? 1 : 0; + const int itsROFb = collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) ? 1 : 0; + const int sbp = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup) ? 1 : 0; + const int zVtxFT0vPv = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) ? 1 : 0; + const 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 @@ -193,25 +350,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 + 8, 1.); - if (issgevent <= 2) { - // LOGF(info, "Current BC: %i, %i, %i", bc.globalBC(), newbc.globalBC(), issgevent); + getHist(TH1, histdir + "/Stat")->Fill(issgevent + 10, 1.); + if ((storeDG && issgevent == o2::aod::sgselector::DoubleGap) || (storeSG && (issgevent == o2::aod::sgselector::SingleGapA || issgevent == o2::aod::sgselector::SingleGapC))) { + 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); + const uint8_t chFT0A = 0; + const uint8_t chFT0C = 0; + const uint8_t chFDDA = 0; + const uint8_t chFDDC = 0; + const uint8_t chFV0A = 0; + const int occ = collision.trackOccupancyInTimeRange(); + udhelpers::getFITinfo(fitInfo, newbc, bcs, ft0s, fv0as, fdds); + const 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, @@ -221,6 +388,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, collision.rct_raw()); outputCollsLabels(collision.globalIndex()); if (newbc.has_zdc()) { auto zdc = newbc.zdc(); @@ -229,32 +397,510 @@ 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 (const 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 (const 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}}})}); + + const AxisSpec axisCountersTrg{10, 0.5, 10.5, ""}; + histPointers.insert({"reco/hCountersTrg", registry.add("reco/hCountersTrg", "Trigger counts before selections; Trigger; Counts", {HistType::kTH1F, {axisCountersTrg}})}); + histPointers.insert({"reco/hCountersTrgBcSel", registry.add("reco/hCountersTrgSel", "Trigger counts after BC selections; Trigger; Counts", {HistType::kTH1F, {axisCountersTrg}})}); + histPointers.insert({"reco/hLumi", registry.add("reco/hLumi", "Integrated luminosity before selections; Trigger; Luminosity, 1/#mub", {HistType::kTH1F, {axisCountersTrg}})}); + histPointers.insert({"reco/hLumiBcSel", registry.add("reco/hLumiBcSel", "Integrated luminosity before selections; Trigger; Luminosity, 1/#mub", {HistType::kTH1F, {axisCountersTrg}})}); + auto hCountersTrg = getHist(TH1, "reco/hCountersTrg"); + auto hCountersTrgBcSel = getHist(TH1, "reco/hCountersTrgBcSel"); + auto hLumi = getHist(TH1, "reco/hLumi"); + auto hLumiBcSel = getHist(TH1, "reco/hLumiBcSel"); + for (const auto& h : {hCountersTrg, hCountersTrgBcSel, hLumi, hLumiBcSel}) { + h->GetXaxis()->SetBinLabel(1, "TVX"); + h->GetXaxis()->SetBinLabel(2, "TCE"); + h->GetXaxis()->SetBinLabel(3, "ZEM"); + h->GetXaxis()->SetBinLabel(4, "ZNC"); + } + } + 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}}})}); + } + + if (isGoodRCTZdc) { + myRCTChecker.init("CBT", true); + } + } + + // 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 (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 (const auto& mcpart : McParts) { + if (mcPartIsSaved.find(mcpart.globalIndex()) == mcPartIsSaved.end()) { + // mothers + newmids.clear(); + auto oldmids = mcpart.mothersIds(); + for (const 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 (const 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 (const 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 47da6d3ffbd..2208060bd59 100644 --- a/PWGUD/TableProducer/UPCCandidateProducer.cxx +++ b/PWGUD/TableProducer/UPCCandidateProducer.cxx @@ -12,16 +12,27 @@ /// \author Diana Krupova, diana.krupova@cern.ch /// \since 04.06.2024 -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" +#include "PWGUD/Core/UPCCutparHolder.h" +#include "PWGUD/Core/UPCHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + #include "Common/CCDB/EventSelectionParams.h" #include "Common/DataModel/EventSelection.h" + #include "CommonConstants/LHCConstants.h" #include "DataFormatsFIT/Triggers.h" -#include "PWGUD/Core/UPCCutparHolder.h" -#include "PWGUD/Core/UPCHelpers.h" -#include "PWGUD/DataModel/UDTables.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include +#include +#include +#include using namespace o2::framework; using namespace o2::framework::expressions; @@ -52,6 +63,7 @@ struct UpcCandProducer { Produces eventCandidatesSels; Produces eventCandidatesSelsCent; Produces eventCandidatesSelsFwd; + Produces eventCandidatesSelExtras; Produces udZdcsReduced; @@ -72,7 +84,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"}; @@ -86,10 +98,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; @@ -112,6 +130,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}); @@ -466,10 +487,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*/) @@ -678,6 +700,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, @@ -720,9 +782,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*/, @@ -737,7 +800,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, @@ -758,7 +821,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; @@ -779,7 +842,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(); } @@ -791,7 +854,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(); } @@ -870,7 +933,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(); @@ -884,7 +947,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()); @@ -916,8 +979,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, @@ -935,7 +1002,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(); @@ -949,7 +1016,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()); @@ -981,8 +1048,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, @@ -1002,12 +1073,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::AmbiguousFwdTracks const& ambFwdTracks, - BCsWithBcSels const& bcs, + TBCs const& bcs, o2::aod::Collisions const& collisions, o2::aod::FT0s const& ft0s, o2::aod::FDDs const& fdds, @@ -1157,9 +1229,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, @@ -1181,7 +1257,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); @@ -1207,13 +1283,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) @@ -1224,7 +1301,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, @@ -1251,7 +1328,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(); } @@ -1261,7 +1338,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(); } @@ -1273,14 +1350,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.; @@ -1297,7 +1393,7 @@ struct UpcCandProducer { 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{}; @@ -1312,7 +1408,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()); @@ -1329,6 +1425,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); @@ -1343,8 +1441,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); @@ -1356,8 +1457,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()) { @@ -1378,14 +1503,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, 0); eventCandidatesSelsFwd(fitInfo.distClosestBcV0A, fitInfo.distClosestBcT0A, amplitudesT0A, @@ -1404,15 +1534,17 @@ 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, - 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) @@ -1424,7 +1556,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, @@ -1436,10 +1568,10 @@ struct UpcCandProducer { bcs, collisions, fwdTracks, ambFwdTracks, ambFwdTrBCs); - collectForwardTracks(bcsMatchedTrIdsGlobal, - o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack, - 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; }); @@ -1456,10 +1588,20 @@ struct UpcCandProducer { 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(); + uint64_t globalBC = ft0.bc_as().globalBC(); mapGlobalBcWithT0A[globalBC] = ft0.globalIndex(); } @@ -1469,7 +1611,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(); } @@ -1481,13 +1623,32 @@ 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 nFDDs = mapGlobalBcWithFDD.size(); // todo: calculate position of UD collision? float dummyX = 0.; @@ -1498,20 +1659,59 @@ struct UpcCandProducer { std::vector selTrackIdsGlobal{}; - // storing n-prong matches int32_t candID = 0; - for (auto& pair : bcsMatchedTrIdsGlobal) { // candidates with MFT + for (auto& pair : bcsMatchedTrIdsGlobal) { auto globalBC = static_cast(pair.first); - const auto& fwdTrackIDs = pair.second; - int32_t nMFTs = fwdTrackIDs.size(); - if (nMFTs > fNFwdProngs) // too many tracks + const auto& fwdTrackIDs = pair.second; // Forward tracks (Global with MFT) + if (fwdTrackIDs.size() != 2) { // ensure we have two MFT tracks continue; - std::vector trkCandIDs{}; + } + + // 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; + } - if (nMFTs == fNFwdProngs) { + 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; @@ -1524,6 +1724,16 @@ struct UpcCandProducer { 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); @@ -1538,8 +1748,20 @@ 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(); + // 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); @@ -1551,8 +1773,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()) { @@ -1573,14 +1819,19 @@ struct UpcCandProducer { 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, 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, trs, trofs, hmpr, tfb, itsROFb, sbp, zVtxFT0vPv, vtxITSTPC, 0); eventCandidatesSelsFwd(fitInfo.distClosestBcV0A, fitInfo.distClosestBcT0A, amplitudesT0A, @@ -1598,6 +1849,7 @@ struct UpcCandProducer { bcsMatchedTrIdsGlobal.clear(); mapGlobalBcWithT0A.clear(); mapGlobalBcWithV0A.clear(); + mapGlobalBcWithFDD.clear(); } // data processors @@ -1628,7 +1880,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, @@ -1674,7 +1926,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, @@ -1697,7 +1949,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, @@ -1714,7 +1966,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, @@ -1737,7 +1989,7 @@ struct UpcCandProducer { void processForwardGlobal(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, @@ -1751,13 +2003,35 @@ struct UpcCandProducer { (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 candidates in forward region", false); PROCESS_SWITCH(UpcCandProducer, processForwardGlobal, "Produce candidates in forward region with MFT", true); - PROCESS_SWITCH(UpcCandProducer, processForwardMC, "Produce caniddates in forward region with MC information", false); + 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 20db4b41959..52fa510b176 100644 --- a/PWGUD/TableProducer/fwdTrackPropagation.cxx +++ b/PWGUD/TableProducer/fwdTrackPropagation.cxx @@ -99,7 +99,7 @@ struct FwdTrackPropagation { if (run != fRun) { fRun = run; - std::map metadata; + std::map metadata; auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(fCCDBApi, run); auto ts = soreor.first; auto grpmag = fCCDBApi.retrieveFromTFileAny("GLO/Config/GRPMagField", metadata, ts); @@ -142,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..ec08a426f35 --- /dev/null +++ b/PWGUD/TableProducer/tauEventTableProducer.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. +// +/// \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/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/TauEventTables.h" +#include "PWGUD/DataModel/UDTables.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" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct TauEventTableProducer { + Produces tauTwoTracks; + Produces trueTauTwoTracks; + + // 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 cutRCTflag{"cutRCTflag", 0, {"0 = off, 1 = CBT, 2 = CBT+ZDC, 3 = CBThadron, 4 = CBThadron+ZDC"}}; + 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 cutEvTFb{"cutEvTFb", true, {"Event selection bit kNoTimeFrameBorder"}}; + Configurable cutEvITSROFb{"cutEvITSROFb", true, {"Event selection bit kNoITSROFrameBorder"}}; + Configurable cutEvSbp{"cutEvSbp", true, {"Event selection bit kNoSameBunchPileup"}}; + Configurable cutEvZvtxFT0vPV{"cutEvZvtxFT0vPV", false, {"Event selection bit kIsGoodZvtxFT0vsPV"}}; + Configurable cutEvVtxITSTPC{"cutEvVtxITSTPC", true, {"Event selection bit kIsVertexITSTPC"}}; + 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; + + // init + void init(InitContext&) + { + if (verboseInfo) + printMediumMessage("INIT METHOD"); + + mySetITShitsRule(cutGlobalTrack.cutITShitsRule); + + histos.add("Truth/hTroubles", "Counter of unwanted issues;;Number of troubles (-)", HistType::kTH1D, {{15, 0.5, 15.5}}); + + } // 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 isGoodRCTflag(C const& coll) + { + switch (cutSample.cutRCTflag) { + case 1: + return sgSelector.isCBTOk(coll); + case 2: + return sgSelector.isCBTZdcOk(coll); + case 3: + return sgSelector.isCBTHadronOk(coll); + case 4: + return sgSelector.isCBTHadronZdcOk(coll); + default: + return true; + } + } + + template + bool isGoodROFtime(C const& coll) + { + + // kNoTimeFrameBorder + if (cutSample.cutEvTFb && !coll.tfb()) + return false; + + // kNoITSROFrameBorder + if (cutSample.cutEvITSROFb && !coll.itsROFb()) + return false; + + // kNoSameBunchPileup + if (cutSample.cutEvSbp && !coll.sbp()) + return false; + + // kIsGoodZvtxFT0vsPV + if (cutSample.cutEvZvtxFT0vPV && !coll.zVtxFT0vPV()) + return false; + + // kIsVertexITSTPC + if (cutSample.cutEvVtxITSTPC && !coll.vtxITSTPC()) + return false; + + // 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; // good ITS-TPC matching means ITS ch2 is not negative + } + // 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) + { + + if (!isGoodRCTflag(collision)) + return; + + if (!isGoodROFtime(collision)) + return; + + int gapSide = collision.gapSide(); + int trueGapSide = sgSelector.trueGap(collision, cutSample.cutTrueGapSideFV0, cutSample.cutTrueGapSideFT0A, cutSample.cutTrueGapSideFT0C, cutSample.cutTrueGapSideZDC); + if (cutSample.useTrueGap) + gapSide = trueGapSide; + 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); + + PresliceUnsorted partPerMcCollision = aod::udmcparticle::udMcCollisionId; + PresliceUnsorted colPerMcCollision = aod::udcollision::udMcCollisionId; + PresliceUnsorted trackPerMcParticle = aod::udmctracklabel::udMcParticleId; + Preslice trackPerCollision = aod::udtrack::udCollisionId; // sorted preslice used because the pair track-collision is already sorted in processDataSG function + + void processMonteCarlo(aod::UDMcCollisions const& mccollisions, + aod::UDMcParticles const& parts, + FullMCSGUDCollisions const& recolls, + FullMCUDTracks const& trks) + { + // start loop over generated collisions + for (const auto& mccoll : mccollisions) { + + // prepare local variables for output table + int32_t runNumber = -999; + int bc = -999; + int nTrks[3] = {-999, -999, -999}; // totalTracks, numContrib, globalNonPVtracks + float vtxPos[3] = {-999., -999., -999.}; + int recoMode = -999; + int occupancy = -999.; + double hadronicRate = -999.; + int bcSels[8] = {-999, -999, -999, -999, -999, -999, -999, -999}; + float amplitudesFIT[3] = {-999., -999., -999.}; // FT0A, FT0C, FV0 + float timesFIT[3] = {-999., -999., -999.}; // FT0A, FT0C, FV0 + + float px[2] = {-999., -999.}; + float py[2] = {-999., -999.}; + float pz[2] = {-999., -999.}; + int sign[2] = {-999, -999}; + float dcaxy[2] = {-999., -999.}; + float dcaz[2] = {-999., -999.}; + float trkTimeRes[2] = {-999., -999.}; + uint32_t itsClusterSizesTrk1 = 4294967295; + uint32_t itsClusterSizesTrk2 = 4294967295; + float tpcSignal[2] = {-999, -999}; + float tpcEl[2] = {-999, -999}; + float tpcMu[2] = {-999, -999}; + float tpcPi[2] = {-999, -999}; + float tpcKa[2] = {-999, -999}; + float tpcPr[2] = {-999, -999}; + float tpcIP[2] = {-999, -999}; + float tofSignal[2] = {-999, -999}; + float tofEl[2] = {-999, -999}; + float tofMu[2] = {-999, -999}; + float tofPi[2] = {-999, -999}; + float tofKa[2] = {-999, -999}; + float tofPr[2] = {-999, -999}; + float tofEP[2] = {-999, -999}; + + int trueChannel = -1; + bool trueHasRecoColl = false; + float trueTauX[2] = {-999., -999.}; + float trueTauY[2] = {-999., -999.}; + float trueTauZ[2] = {-999., -999.}; + float trueDaugX[2] = {-999., -999.}; + float trueDaugY[2] = {-999., -999.}; + float trueDaugZ[2] = {-999., -999.}; + int trueDaugPdgCode[2] = {-999, -999}; + bool problem = false; + + // find reconstructed collisions associated to the generated collision + auto const& collFromMcColls = recolls.sliceBy(colPerMcCollision, mccoll.globalIndex()); + // check the generated collision was reconstructed + if (collFromMcColls.size() > 0) { // get the truth and reco-level info + trueHasRecoColl = true; + // check there is exactly one reco-level collision associated to generated collision + if (collFromMcColls.size() > 1) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 1 reco collision. Skipping this event."); + histos.get(HIST("Truth/hTroubles"))->Fill(1); + problem = true; + continue; + } + // grap reco-level collision + auto const& collFromMcColl = collFromMcColls.iteratorAt(0); + // grab tracks from the reco-level collision to get info to match measured data tables (processDataSG function) + auto const& trksFromColl = trks.sliceBy(trackPerCollision, collFromMcColl.globalIndex()); + int countTracksPerCollision = 0; + int countGoodNonPVtracks = 0; + for (auto const& trkFromColl : trksFromColl) { + countTracksPerCollision++; + if (!trkFromColl.isPVContributor()) { + countGoodNonPVtracks++; + continue; + } + } + + // fill info for reconstructed collision + runNumber = collFromMcColl.runNumber(); + bc = collFromMcColl.globalBC(); + nTrks[0] = countTracksPerCollision; + nTrks[1] = collFromMcColl.numContrib(); + nTrks[2] = countGoodNonPVtracks; + vtxPos[0] = collFromMcColl.posX(); + vtxPos[1] = collFromMcColl.posY(); + vtxPos[2] = collFromMcColl.posZ(); + recoMode = collFromMcColl.flags(); + occupancy = collFromMcColl.occupancyInTime(); + hadronicRate = collFromMcColl.hadronicRate(); + bcSels[0] = collFromMcColl.trs(); + bcSels[1] = collFromMcColl.trofs(); + bcSels[2] = collFromMcColl.hmpr(); + bcSels[3] = collFromMcColl.tfb(); + bcSels[4] = collFromMcColl.itsROFb(); + bcSels[5] = collFromMcColl.sbp(); + bcSels[6] = collFromMcColl.zVtxFT0vPV(); + bcSels[7] = collFromMcColl.vtxITSTPC(); + amplitudesFIT[0] = collFromMcColl.totalFT0AmplitudeA(); + amplitudesFIT[1] = collFromMcColl.totalFT0AmplitudeC(); + amplitudesFIT[2] = collFromMcColl.totalFV0AmplitudeA(); + timesFIT[0] = collFromMcColl.timeFT0A(); + timesFIT[1] = collFromMcColl.timeFT0C(); + timesFIT[2] = collFromMcColl.timeFV0A(); + + // get particles associated to generated collision + auto const& partsFromMcColl = parts.sliceBy(partPerMcCollision, mccoll.globalIndex()); + int countMothers = 0; + for (const auto& particle : partsFromMcColl) { + // select only tauons with checking if particle has no mother + if (particle.has_mothers()) + continue; + countMothers++; + // check the generated collision does not have more than 2 tauons + if (countMothers > 2) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 2 no mother particles. Breaking the particle loop."); + histos.get(HIST("Truth/hTroubles"))->Fill(2); + problem = true; + break; + } + // fill info for each tau + trueTauX[countMothers - 1] = particle.px(); + trueTauY[countMothers - 1] = particle.py(); + trueTauZ[countMothers - 1] = particle.pz(); + + // get daughters of the tau + const auto& daughters = particle.daughters_as(); + int countDaughters = 0; + for (const auto& daughter : daughters) { + // check if it is the charged particle (= no pi0 or neutrino) + if (enumMyParticle(daughter.pdgCode()) == -1) + continue; + countDaughters++; + // check there is only 1 charged daughter related to 1 tau + if (countDaughters > 1) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 1 charged daughters of no mother particles. Breaking the daughter loop."); + histos.get(HIST("Truth/hTroubles"))->Fill(3); + problem = true; + break; + } + // fill info for each daughter + trueDaugX[countMothers - 1] = daughter.px(); + trueDaugY[countMothers - 1] = daughter.py(); + trueDaugZ[countMothers - 1] = daughter.pz(); + trueDaugPdgCode[countMothers - 1] = daughter.pdgCode(); + + // get tracks associated to MC daughter (how well the daughter was reconstructed) + auto const& tracksFromDaughter = trks.sliceBy(trackPerMcParticle, daughter.globalIndex()); + // check there is exactly 1 track per 1 particle + if (tracksFromDaughter.size() > 1) { + if (verboseInfo) + printLargeMessage("Daughter has more than 1 associated track. Skipping this daughter."); + histos.get(HIST("Truth/hTroubles"))->Fill(4); + problem = true; + continue; + } + // grab the track and fill info for reconstructed track (should be done twice) + const auto& trk = tracksFromDaughter.iteratorAt(0); + px[countMothers - 1] = trk.px(); + py[countMothers - 1] = trk.py(); + pz[countMothers - 1] = trk.pz(); + sign[countMothers - 1] = trk.sign(); + dcaxy[countMothers - 1] = trk.dcaXY(); + dcaz[countMothers - 1] = trk.dcaZ(); + trkTimeRes[countMothers - 1] = trk.trackTimeRes(); + if (countMothers == 1) { + itsClusterSizesTrk1 = trk.itsClusterSizes(); + } else { + itsClusterSizesTrk2 = trk.itsClusterSizes(); + } + tpcSignal[countMothers - 1] = trk.tpcSignal(); + tpcEl[countMothers - 1] = trk.tpcNSigmaEl(); + tpcMu[countMothers - 1] = trk.tpcNSigmaMu(); + tpcPi[countMothers - 1] = trk.tpcNSigmaPi(); + tpcKa[countMothers - 1] = trk.tpcNSigmaKa(); + tpcPr[countMothers - 1] = trk.tpcNSigmaPr(); + tpcIP[countMothers - 1] = trk.tpcInnerParam(); + tofSignal[countMothers - 1] = trk.tofSignal(); + tofEl[countMothers - 1] = trk.tofNSigmaEl(); + tofMu[countMothers - 1] = trk.tofNSigmaMu(); + tofPi[countMothers - 1] = trk.tofNSigmaPi(); + tofKa[countMothers - 1] = trk.tofNSigmaKa(); + tofPr[countMothers - 1] = trk.tofNSigmaPr(); + tofEP[countMothers - 1] = trk.tofExpMom(); + } // daughters + } // particles + } else { // get only the truth information. The reco-level info is left on default + // get particles associated to generated collision + auto const& partsFromMcColl = parts.sliceBy(partPerMcCollision, mccoll.globalIndex()); + int countMothers = 0; + for (const auto& particle : partsFromMcColl) { + // select only tauons with checking if particle has no mother + if (particle.has_mothers()) + continue; + countMothers++; + // check the generated collision does not have more than 2 tauons + if (countMothers > 2) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 2 no mother particles. Breaking the particle loop."); + histos.get(HIST("Truth/hTroubles"))->Fill(12); + problem = true; + break; + } + // fill info for each tau + trueTauX[countMothers - 1] = particle.px(); + trueTauY[countMothers - 1] = particle.py(); + trueTauZ[countMothers - 1] = particle.pz(); + + // get daughters of the tau + const auto& daughters = particle.daughters_as(); + int countDaughters = 0; + for (const auto& daughter : daughters) { + // select only the charged particle (= no pi0 or neutrino) + if (enumMyParticle(daughter.pdgCode()) == -1) + continue; + countDaughters++; + // check there is only 1 charged daughter related to 1 tau + if (countDaughters > 1) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 1 charged daughters of no mother particles. Breaking the daughter loop."); + histos.get(HIST("Truth/hTroubles"))->Fill(13); + problem = true; + break; + } + // fill info for each daughter + trueDaugX[countMothers - 1] = daughter.px(); + trueDaugY[countMothers - 1] = daughter.py(); + trueDaugZ[countMothers - 1] = daughter.pz(); + trueDaugPdgCode[countMothers - 1] = daughter.pdgCode(); + } // daughters + } // particles + } // collisions + + // decide the channel and set the variable. Only two cahnnels suported now. + if ((enumMyParticle(trueDaugPdgCode[0]) == P_ELECTRON) && (enumMyParticle(trueDaugPdgCode[1]) == P_ELECTRON)) + trueChannel = CH_EE; + if ((enumMyParticle(trueDaugPdgCode[0]) == P_ELECTRON) && ((enumMyParticle(trueDaugPdgCode[1]) == P_PION) || (enumMyParticle(trueDaugPdgCode[1]) == P_MUON))) + trueChannel = CH_EMUPI; + if ((enumMyParticle(trueDaugPdgCode[1]) == P_ELECTRON) && ((enumMyParticle(trueDaugPdgCode[0]) == P_PION) || (enumMyParticle(trueDaugPdgCode[0]) == P_MUON))) + trueChannel = CH_EMUPI; + + trueTauTwoTracks(runNumber, bc, nTrks[0], nTrks[1], nTrks[2], vtxPos[0], vtxPos[1], vtxPos[2], + recoMode, occupancy, hadronicRate, bcSels[0], bcSels[1], bcSels[2], + bcSels[3], bcSels[4], bcSels[5], bcSels[6], bcSels[7], + amplitudesFIT[0], amplitudesFIT[1], amplitudesFIT[2], -999., -999., // no ZDC info in MC + timesFIT[0], timesFIT[1], timesFIT[2], -999., -999., // no ZDC info in MC + px, py, pz, sign, dcaxy, dcaz, trkTimeRes, + itsClusterSizesTrk1, itsClusterSizesTrk2, + tpcSignal, tpcEl, tpcMu, tpcPi, tpcKa, tpcPr, tpcIP, + tofSignal, tofEl, tofMu, tofPi, tofKa, tofPr, tofEP, + trueChannel, trueHasRecoColl, mccoll.posX(), mccoll.posY(), mccoll.posZ(), + trueTauX, trueTauY, trueTauZ, trueDaugX, trueDaugY, trueDaugZ, trueDaugPdgCode, problem); + } // mccollisions + } + 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/tauThreeProngEventTableProducer.cxx b/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx new file mode 100644 index 00000000000..baea03e1d59 --- /dev/null +++ b/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx @@ -0,0 +1,1543 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file tauThreeProngEventTableProducer.cxx +/// \brief Produces derived table from UD tables for tau pair production (3 prong) +/// +/// \author Adam Matyja , IFJ PAN, Cracow +/// \since 2025-09-06 +// +// to run it execute: +// copts="--configuration json://tautauMC_modified_new.json -b" +// for MC +// oopts="--aod-writer-json saveDerivedConfig.json" +// for data +// oopts="--aod-writer-json saveDerivedConfigData.json" +// o2-analysis-ud-tau-three-prong-event-table-producer $copts $oopts > output.log + +//// C++ headers +#include "Math/Vector4D.h" + +#include +#include +#include +#include +#include +// +//// O2 headers +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.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/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +// #include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/Core/DGPIDSelector.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/TauThreeProngEventTables.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Common/Core/RecoDecay.h" + +#include "TPDGCode.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +enum MyRecoProblem { + NO_PROBLEM = 0, // no problem + MANY_RECO = 1, // more than 1 reconstructed collision + TOO_MANY_DAUGHTERS = 2, // more than 6 daughters from 2 taus + TWO_TRACKS = 3 // more than 1 associated track to MC particle (tau daughter) +}; + +enum MyParticle { + MyOtherParticle = -1, + MyElectron = 1, + MyMuon = 2, + MyPion = 3, + MyKaon = 4 +}; + +struct TauThreeProngEventTableProducer { + Produces trueTauFourTracks; + Produces dataTauFourTracks; + + // Global varialbes + // Service pdg; + SGSelector sgSelector; + + // initialize histogram registry + HistogramRegistry registrySkim{ + "registrySkim", + {}}; + + //// 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 cutRCTflag{"cutRCTflag", 0, {"0 = off, 1 = CBT, 2 = CBT+ZDC, 3 = CBThadron, 4 = CBThadron+ZDC"}}; + // 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 cutEvTFb{"cutEvTFb", true, {"Event selection bit kNoTimeFrameBorder"}}; + // Configurable cutEvITSROFb{"cutEvITSROFb", true, {"Event selection bit kNoITSROFrameBorder"}}; + // Configurable cutEvSbp{"cutEvSbp", true, {"Event selection bit kNoSameBunchPileup"}}; + // Configurable cutEvZvtxFT0vPV{"cutEvZvtxFT0vPV", false, {"Event selection bit kIsGoodZvtxFT0vsPV"}}; + // Configurable cutEvVtxITSTPC{"cutEvVtxITSTPC", true, {"Event selection bit kIsVertexITSTPC"}}; + // 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; + + // configurables + 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{"ptAxis", {120, 0., 4.}, "#it{p} (GeV/#it{c})"}; + // ConfigurableAxis dedxAxis{"dedxAxis", {100, 20., 160.}, "dE/dx"}; + // ConfigurableAxis minvAxis{"minvAxis", {100, 0.5, 5.0}, "M_{inv} (GeV/#it{c}^{2})"}; + // ConfigurableAxis phiAxis{"phiAxis", {120, 0., 3.2}, "#phi"}; + Configurable verbose{"verbose", {}, "Additional print outs"}; + + // cut selection configurables + // 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"}; + // Configurable maxNsigmaPiVetocut{"maxNsigmaPiVetocut", 4., "max Nsigma for Pion veto cut"}; + // 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 minTrkPtcut{"minTrkPtcut", 0.1, "min Pt for each charged track cut, default=100MeV/c"}; + Configurable nPVtrackscut{"nPVtrackscut", 4, "number of PV contributors, default=4"}; + 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", 2, "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"}; + + // adam + 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; + + // roman + ////using FullUDTracks = soa::Join; + ////using FullSGUDCollisions = soa::Join; + ////using FullSGUDCollision = FullSGUDCollisions::iterator; + using FullMCUDTracks = soa::Join; + using FullMCSGUDCollisions = soa::Join; + // using FullMCSGUDCollision = FullMCSGUDCollisions::iterator; + + // init + void init(InitContext&) + { + + // 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{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"}; + // 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})"}; + // const AxisSpec acoAxis{100, 0., 1., "A^{1+3}"}; + + // mySetITShitsRule(cutGlobalTrack.cutITShitsRule); + + if (doprocessDoSkim) { + registrySkim.add("skim/efficiency", ";efficeincy;events", {HistType::kTH1F, {{10, 0., 10.}}}); + registrySkim.get(HIST("skim/efficiency"))->GetXaxis()->SetBinLabel(1, "1: All"); + registrySkim.get(HIST("skim/efficiency"))->GetXaxis()->SetBinLabel(2, "2: Gap=012"); + registrySkim.get(HIST("skim/efficiency"))->GetXaxis()->SetBinLabel(3, "3: Gap=2"); + registrySkim.get(HIST("skim/efficiency"))->GetXaxis()->SetBinLabel(4, "4: PVcont=4"); + registrySkim.get(HIST("skim/efficiency"))->GetXaxis()->SetBinLabel(5, "5: |#eta^{tr}|<0.9"); + registrySkim.get(HIST("skim/efficiency"))->GetXaxis()->SetBinLabel(6, "6: p_{T}^{tr}>0.1"); + registrySkim.get(HIST("skim/efficiency"))->GetXaxis()->SetBinLabel(7, "7: N_{TOF}^{tr}>1"); + registrySkim.get(HIST("skim/efficiency"))->GetXaxis()->SetBinLabel(8, "8: FIT veto"); + + registrySkim.add("skim/gapSide", ";Gap;events", {HistType::kTH1F, {{10, -1., 9.}}}); + registrySkim.add("skim/trueGapSide", ";TrueGap;events", {HistType::kTH1F, {{10, -1., 9.}}}); + registrySkim.add("skim/etaTrk", ";#eta^{trk};events", {HistType::kTH1F, {{100, -1.5, 1.5}}}); + registrySkim.add("skim/ptTrk", ";p_{T}^{trk};events", {HistType::kTH1F, {{100, 0., 5.}}}); + registrySkim.add("skim/phiTrk", ";#phi^{trk};events", {HistType::kTH1F, {{128, -3.2, 3.2}}}); + registrySkim.add("skim/nTof", ";N_{TOFtrk};events", {HistType::kTH1F, {{10, -1., 9.}}}); + } + if (doprocessMonteCarlo) { + registrySkim.add("skim/efficiencyMC", ";efficeincy;events", {HistType::kTH1F, {{10, 0., 10.}}}); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(1, "1: All"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(2, "2: N^{#tau}=2"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(3, "3: |y^{#tau}| <= 0.9"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(4, "4: 4 or 6 trk"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(5, "5: 4 trk"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(6, "6: 6 trk"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(7, "7: |#eta^{ch}|<0.9"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(8, "8: 7+4 trk"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(9, "9: 7+6 trk"); + + registrySkim.add("skim/problemMC", ";problem;events", {HistType::kTH1F, {{10, 0., 10.}}}); + + registrySkim.add("skim/nTauMC", ";N_{#tau};events", {HistType::kTH1F, {{10, 0., 10.}}}); + registrySkim.add("skim/tauRapidityMC", ";y_{#tau};events", {HistType::kTH1F, {{100, -2.5, 2.5}}}); + registrySkim.add("skim/tauPhiMC", ";#phi^{#tau};events", {HistType::kTH1F, {{100, 0, 6.4}}}); + registrySkim.add("skim/tauEtaMC", ";#eta^{#tau};events", {HistType::kTH1F, {{100, -2.5, 2.5}}}); + registrySkim.add("skim/tauPtMC", ";p_{T}^{#tau};events", {HistType::kTH1F, {{100, 0, 5.}}}); + registrySkim.add("skim/tauDeltaEtaMC", ";#Delta#eta^{#tau};events ", {HistType::kTH1F, {{100, -5., 5.}}}); + registrySkim.add("skim/tauDeltaPhiMC", ";#Delta#phi^{#tau}(deg.);events", {HistType::kTH1F, {{100, 131., 181}}}); + registrySkim.add("skim/nChPartMC", ";N^{ch. part};events", {HistType::kTH1F, {{10, 0, 10.}}}); + registrySkim.add("skim/daughterPhiMC", ";#phi^{daughter};events", {HistType::kTH1F, {{100, 0, 6.4}}}); + registrySkim.add("skim/daughterEtaMC", ";#eta^{daughter};events", {HistType::kTH1F, {{100, -4., 4.}}}); + registrySkim.add("skim/daughterPtMC", ";p_{T}^{daughter};events", {HistType::kTH1F, {{100, 0, 5.0}}}); + } + + // histos.add("Truth/hTroubles", "Counter of unwanted issues;;Number of troubles (-)", HistType::kTH1D, {{15, 0.5, 15.5}}); + + } // end init + + 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(ROOT::Math::LorentzVector> p, ROOT::Math::LorentzVector> 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 scalarAsymMC(auto particle1, auto particle2) + { + // auto pt1 = pt(particle1.px(), particle1.py()); + auto pt1 = RecoDecay::pt(particle1.px(), particle1.py()); + // auto pt2 = pt(particle2.px(), particle2.py()); + auto pt2 = RecoDecay::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; + } + + template + int trackCheck(T track) + { + // 1 + if (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) + return 0; + else if (!track.hasITS() && track.hasTPC() && !track.hasTRD() && !track.hasTOF()) + return 1; + else if (!track.hasITS() && !track.hasTPC() && track.hasTRD() && !track.hasTOF()) + return 2; + else if (!track.hasITS() && !track.hasTPC() && !track.hasTRD() && track.hasTOF()) + return 3; + // 2 + else if (track.hasITS() && track.hasTPC() && !track.hasTRD() && !track.hasTOF()) + return 4; + else if (track.hasITS() && !track.hasTPC() && track.hasTRD() && !track.hasTOF()) + return 5; + else if (track.hasITS() && !track.hasTPC() && !track.hasTRD() && track.hasTOF()) + return 6; + else if (!track.hasITS() && track.hasTPC() && track.hasTRD() && !track.hasTOF()) + return 7; + else if (!track.hasITS() && track.hasTPC() && !track.hasTRD() && track.hasTOF()) + return 8; + else if (!track.hasITS() && !track.hasTPC() && track.hasTRD() && track.hasTOF()) + return 9; + // 3 + else if (track.hasITS() && track.hasTPC() && track.hasTRD() && !track.hasTOF()) + return 10; + else if (track.hasITS() && track.hasTPC() && !track.hasTRD() && track.hasTOF()) + return 11; + else if (track.hasITS() && !track.hasTPC() && track.hasTRD() && track.hasTOF()) + return 12; + else if (!track.hasITS() && track.hasTPC() && track.hasTRD() && track.hasTOF()) + return 13; + // 4 + else if (track.hasITS() && track.hasTPC() && track.hasTRD() && track.hasTOF()) + return 14; + return -1; + } + + // to be appied later + // // 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; + // } + + // check ITS clusters, how many -1,0,1,7 + 10 if 0,1,2 layers were fired + // analysis track quality check + template + int numberOfItsClustersCheck(T track) + { + if (!track.hasITS()) + return -1; + int nITSbits = 0; + int firstThreeLayers = 0; + const int threeLayers = 3; + const int maxITSlayers = 7; + uint32_t clusterSizes = track.itsClusterSizes(); + for (int layer = 0; layer < maxITSlayers; layer++) { + if ((clusterSizes >> (layer * 4)) & 0xf) { + nITSbits++; + if (layer < threeLayers) // 3 + firstThreeLayers++; + } + } // end of loop over ITS bits + if (firstThreeLayers == threeLayers) // 3 + nITSbits += 10; + + return nITSbits; + } + + // RCT check + template + int isGoodRCTflag(C const& coll) + { + if (sgSelector.isCBTHadronZdcOk(coll)) + return 4; + else if (sgSelector.isCBTHadronOk(coll)) + return 3; + else if (sgSelector.isCBTZdcOk(coll)) + return 2; + else if (sgSelector.isCBTOk(coll)) + return 1; + else + return 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) + // { + // + // // kNoTimeFrameBorder + // if (cutSample.cutEvTFb && !coll.tfb()) + // return false; + // + // // kNoITSROFrameBorder + // if (cutSample.cutEvITSROFb && !coll.itsROFb()) + // return false; + // + // // kNoSameBunchPileup + // if (cutSample.cutEvSbp && !coll.sbp()) + // return false; + // + // // kIsGoodZvtxFT0vsPV + // if (cutSample.cutEvZvtxFT0vPV && !coll.zVtxFT0vPV()) + // return false; + // + // // kIsVertexITSTPC + // if (cutSample.cutEvVtxITSTPC && !coll.vtxITSTPC()) + // return false; + // + // // 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; // good ITS-TPC matching means ITS ch2 is not negative + // } + // // 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; + // } + + int enumMyParticle(int valuePDG) + // reads pdg value and returns particle number as in enumMyParticle + { + if (std::abs(valuePDG) == kElectron) { // 11 e+ or e- + return MyElectron; // 1 + } else if (std::abs(valuePDG) == kMuonMinus) { // 13 mu+ or mu - + return MyMuon; // 2 + } else if (std::abs(valuePDG) == kPiPlus) { // 211 pi+ (or pi-) + return MyPion; // 3 + } else if (std::abs(valuePDG) == kKPlus) { // 321 K+ (or K-) + return MyKaon; // 4 + } else { + if (verbose) + LOGF(info, "PDG value not found in enumMyParticle. Returning -1."); + return MyOtherParticle; // -1 + } + } + + // skimming: only 4 tracks selection in data + void processDoSkim(UDCollisionFull2 const& dgcand, UDTracksFull const& dgtracks, PVTracks const& PVContributors) + { + registrySkim.get(HIST("skim/efficiency"))->Fill(0., 1.); + + int gapSide = dgcand.gapSide(); + registrySkim.get(HIST("skim/gapSide"))->Fill(gapSide); + // if (gapSide < 0 || gapSide > 2) + if (gapSide < o2::aod::sgselector::SingleGapA || gapSide > o2::aod::sgselector::DoubleGap) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(1., 1.); + + int truegapSide = sgSelector.trueGap(dgcand, cutFV0, cutFT0A, cutFT0C, cutZDC); + gapSide = truegapSide; + registrySkim.get(HIST("skim/trueGapSide"))->Fill(gapSide); + 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; + // int8_t qtot = 0; + // TLorentzVector p; + ROOT::Math::LorentzVector> p; + for (const auto& trk : PVContributors) { + // qtot += trk.sign(); + // p.SetXYZM(trk.px(), trk.py(), trk.pz(), MassPiPlus); + p.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(trk.px(), trk.py(), trk.pz(), MassPiPlus)); + registrySkim.get(HIST("skim/etaTrk"))->Fill(p.Eta()); + registrySkim.get(HIST("skim/ptTrk"))->Fill(trk.pt()); + registrySkim.get(HIST("skim/phiTrk"))->Fill(p.Phi()); + + if (std::abs(p.Eta()) < trkEtacut) + nEtaIn15++; // 0.9 is a default + if (trk.pt() > minTrkPtcut) // 0.1 GeV/c + npT100++; + if (trk.hasTOF()) + nTofTrk++; + } // end of loop over PV tracks + + if (PVContributors.size() != nPVtrackscut) // 4 + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(3., 1.); + + if (nEtaIn15 != nPVtrackscut) // 4 + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(4., 1.); + + if (npT100 != nPVtrackscut) // 4 + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(5., 1.); + + registrySkim.get(HIST("skim/nTof"))->Fill(nTofTrk); + if (nTofTrk < nTofTrkMinCut) + return; + registrySkim.get(HIST("skim/efficiency"))->Fill(6., 1.); + + // + // FIT informaton + // + auto bitMin = 16 - mFITvetoWindow; // default is +- 2 bc (2 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.); + + // RCT variable + int rct = 0; + rct = isGoodRCTflag(dgcand); + + // + // variables per track + // + int counterTmp = 0; + float px[6] = {-999., -999., -999., -999., -999., -999.}; + float py[6] = {-999., -999., -999., -999., -999., -999.}; + float pz[6] = {-999., -999., -999., -999., -999., -999.}; + int sign[6] = {-99, -99, -99, -99, -99, -99}; + float dcaZ[6] = {-999., -999., -999., -999., -999., -999.}; + float dcaXY[6] = {-999., -999., -999., -999., -999., -999.}; + + float tmpDedx[6] = {-999., -999., -999., -999., -999., -999.}; + float tmpTofNsigmaEl[6] = {-999., -999., -999., -999., -999., -999.}; + float tmpTofNsigmaPi[6] = {-999., -999., -999., -999., -999., -999.}; + float tmpTofNsigmaKa[6] = {-999., -999., -999., -999., -999., -999.}; + float tmpTofNsigmaPr[6] = {-999., -999., -999., -999., -999., -999.}; + float tmpTofNsigmaMu[6] = {-999., -999., -999., -999., -999., -999.}; + + float nSigmaEl[6] = {-999., -999., -999., -999., -999., -999.}; + float nSigmaPi[6] = {-999., -999., -999., -999., -999., -999.}; + float nSigmaPr[6] = {-999., -999., -999., -999., -999., -999.}; + float nSigmaKa[6] = {-999., -999., -999., -999., -999., -999.}; + float nSigmaMu[6] = {-999., -999., -999., -999., -999., -999.}; + float chi2TOF[6] = {-999., -999., -999., -999., -999., -999.}; + int nclTPCcrossedRows[6] = {-999, -999, -999, -999, -999, -999}; + int nclTPCfind[6] = {-999, -999, -999, -999, -999, -999}; + float nclTPCchi2[6] = {-999., -999., -999., -999., -999., -999.}; + float trkITSchi2[6] = {-999., -999., -999., -999., -999., -999.}; + int trkITScl[6] = {-999, -999, -999, -999, -999, -999}; + + // double trkTime[4]; + // float trkTimeRes[4]; + float trkTofSignal[6] = {-999., -999., -999., -999., -999., -999.}; + + for (const auto& trk : PVContributors) { + if (counterTmp > nPVtrackscut - 1) + continue; // >5 -> continue default + 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(); + + if (trk.hasTOF()) + chi2TOF[counterTmp] = trk.tofChi2(); + + nclTPCcrossedRows[counterTmp] = trk.tpcNClsCrossedRows(); + nclTPCfind[counterTmp] = trk.tpcNClsFindable(); + nclTPCchi2[counterTmp] = trk.tpcChi2NCl(); + trkITSchi2[counterTmp] = trk.itsChi2NCl(); + trkITScl[counterTmp] = numberOfItsClustersCheck(trk); + + // trkTime[counterTmp] = trk.trackTime(); + // trkTimeRes[counterTmp] = trk.trackTimeRes(); + counterTmp++; + } + + dataTauFourTracks(dgcand.runNumber(), + dgcand.globalBC(), // is it necessary + dgtracks.size(), + dgcand.numContrib(), + rct, + // dgcand.posX(), dgcand.posY(), + dgcand.posZ(), + dgcand.flags(), + dgcand.occupancyInTime(), + dgcand.hadronicRate(), // is it necessary + dgcand.trs(), dgcand.trofs(), dgcand.hmpr(), // to test it + dgcand.tfb(), dgcand.itsROFb(), dgcand.sbp(), dgcand.zVtxFT0vPV(), dgcand.vtxITSTPC(), + energyZNA, energyZNC, + // qtot, <<-------- comment out + dgcand.totalFT0AmplitudeA(), dgcand.totalFT0AmplitudeC(), dgcand.totalFV0AmplitudeA(), + // dgcand.timeFT0A(), dgcand.timeFT0C(), dgcand.timeFV0A(), + px, py, pz, sign, + dcaXY, dcaZ, + nclTPCcrossedRows, nclTPCfind, nclTPCchi2, trkITSchi2, trkITScl, + tmpDedx, nSigmaEl, nSigmaPi, nSigmaKa, nSigmaPr, nSigmaMu, + trkTofSignal, tmpTofNsigmaEl, tmpTofNsigmaPi, tmpTofNsigmaKa, tmpTofNsigmaPr, tmpTofNsigmaMu, + chi2TOF); + } // end of skim process processDoSkim + PROCESS_SWITCH(TauThreeProngEventTableProducer, processDoSkim, "Run over SG Producer tables to produce skimmed data", false); + + // void processDataSG(FullSGUDCollision const& collision, + // FullUDTracks const& tracks) + // { + // + // if (!isGoodRCTflag(collision)) + // return; + // + // if (!isGoodROFtime(collision)) + // return; + // + // int gapSide = collision.gapSide(); + // int trueGapSide = sgSelector.trueGap(collision, cutSample.cutTrueGapSideFV0, cutSample.cutTrueGapSideFT0A, cutSample.cutTrueGapSideFT0C, cutSample.cutTrueGapSideZDC); + // if (cutSample.useTrueGap) + // gapSide = trueGapSide; + // 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); + + // PresliceUnsorted partPerMcCollision = aod::udmcparticle::udMcCollisionId; + // PresliceUnsorted colPerMcCollision = aod::udcollision::udMcCollisionId; + // PresliceUnsorted trackPerMcParticle = aod::udmctracklabel::udMcParticleId; + // Preslice trackPerCollision = aod::udtrack::udCollisionId; // sorted preslice used because the pair track-collision is already sorted in processDataSG function + // + // void processMonteCarlo(aod::UDMcCollisions const& mccollisions, + // aod::UDMcParticles const& parts, + // FullMCSGUDCollisions const& recolls, + // FullMCUDTracks const& trks) + + PresliceUnsorted partPerMcCollision = aod::udmcparticle::udMcCollisionId; + PresliceUnsorted colPerMcCollision = aod::udcollision::udMcCollisionId; + PresliceUnsorted trackPerMcParticle = aod::udmctracklabel::udMcParticleId; + Preslice trackPerCollision = aod::udtrack::udCollisionId; // sorted preslice used because the pair track-collision is already sorted in processDataSG function + + void processMonteCarlo(aod::UDMcCollisions const& mcCollisions, + aod::UDMcParticles const& mcParticles, + FullMCSGUDCollisions const& collisions, + FullMCUDTracks const& tracks) + { + // registrySkim.get(HIST("skim/efficiencyMC"))->Fill(0., 1.); + + const int fourTracks = 4; + const int sixTracks = 6; + const int oneProng = 1; + const int threeProng = 3; + + if (verbose) + LOGF(info, "0. UDMcCollision size %d, Collisions size %d, UDtracks %d, UDMcParticles %d", mcCollisions.size(), collisions.size(), tracks.size(), mcParticles.size()); + + // temporary variables + float tmpRapidity = -999.; + float trueTauEta[2] = {-999., -999.}; + float trueTauPhi[2] = {-999., -999.}; + + // init variables for tree + float trueTauX[2] = {-999., -999.}; + float trueTauY[2] = {-999., -999.}; + float trueTauZ[2] = {-999., -999.}; + + bool tauInRapidity = true; + bool partFromTauInEta = true; + + // start loop over generated collisions + for (const auto& mccoll : mcCollisions) { + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(0., 1.); // all MC collisions + + // set up default values per colission + trueTauX[0] = -999.; + trueTauY[0] = -999.; + trueTauZ[0] = -999.; + trueTauX[1] = -999.; + trueTauY[1] = -999.; + trueTauZ[1] = -999.; + + tauInRapidity = true; + partFromTauInEta = true; + + // get particles associated to generated collision + auto const& tmpPartsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); + if (verbose) + LOGF(info, "1. part from MC coll %d", tmpPartsFromMcColl.size()); + int countMothers = 0; + const int desiredNMothers = 2; + for (const auto& particle : tmpPartsFromMcColl) { + if (verbose) + LOGF(info, "2. MC part pdg %d", particle.pdgCode()); + if (std::abs(particle.pdgCode()) != kTauMinus) + continue; // 15 = tau_minus + // if (std::abs(particle.pdgCode()) != 15) continue; // 15 = tau_minus + if (countMothers < desiredNMothers) { // < 2 + // fill info for each tau + trueTauX[countMothers] = particle.px(); + trueTauY[countMothers] = particle.py(); + trueTauZ[countMothers] = particle.pz(); + tmpRapidity = rapidity(particle.e(), trueTauZ[countMothers]); + trueTauEta[countMothers] = RecoDecay::eta(std::array{particle.px(), particle.py(), particle.pz()}); + trueTauPhi[countMothers] = RecoDecay::phi(particle.px(), particle.py()); + + if (verbose) + LOGF(info, "tau P(%f,%f,%f), e %f, y %f", particle.px(), particle.py(), particle.pz(), particle.e(), tmpRapidity); + registrySkim.get(HIST("skim/tauRapidityMC"))->Fill(tmpRapidity); + registrySkim.get(HIST("skim/tauPhiMC"))->Fill(trueTauPhi[countMothers]); + registrySkim.get(HIST("skim/tauEtaMC"))->Fill(trueTauEta[countMothers]); + registrySkim.get(HIST("skim/tauPtMC"))->Fill(RecoDecay::pt(particle.px(), particle.py())); + if (std::abs(tmpRapidity) > trkEtacut) { // 0.9 + tauInRapidity = false; + if (verbose) + LOGF(info, "tau y %f", tmpRapidity); + } // rapidity check + } // number of taus + countMothers++; + } // end of loop over MC paricles + registrySkim.get(HIST("skim/nTauMC"))->Fill(countMothers); + if (countMothers != desiredNMothers) { // 2 + if (verbose) + LOGF(info, "Truth collision has number of mother particles (taus) %d different than 2. Jump to the next MC event.", countMothers); + continue; + } + + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(1., 1.); // exactly 2 taus + + if (!tauInRapidity) { // tau NOT in rapidity -> continue + if (verbose) + LOGF(info, "At least one mother particle (taus) out of rapidity (|y|<0.9). Jump to the next MC event."); + continue; + } + + // delta eta and delta phi between taus + registrySkim.get(HIST("skim/tauDeltaEtaMC"))->Fill(trueTauEta[0] - trueTauEta[1]); + registrySkim.get(HIST("skim/tauDeltaPhiMC"))->Fill(calculateDeltaPhi(trueTauPhi[0], trueTauPhi[1]) * 180. / o2::constants::math::PI); + + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(2., 1.); // |y_tau| <= 0.9 + countMothers = 0; + int nChargedDaughtersTau[2] = {0, 0}; + int nElec = 0; + int nMuon = 0; + int nPi = 0; + int particleType = -1; + int zerothTau = -10; + int trueChannel = -1; + int countPi0 = -1; + + for (const auto& particle : tmpPartsFromMcColl) { + if (std::abs(particle.pdgCode()) != kTauMinus) + continue; // 15 = tau_minus + const auto& daughters = particle.daughters_as(); + for (const auto& daughter : daughters) { + particleType = enumMyParticle(daughter.pdgCode()); + if (particleType == MyOtherParticle) { // -1 + continue; + } else { + nChargedDaughtersTau[countMothers]++; + if (particleType == MyElectron) // 1 + nElec++; + else if (particleType == MyMuon) // 2 + nMuon++; + else if (particleType == MyPion) // 3 + nPi++; + } + + if (std::abs(RecoDecay::eta(std::array{daughter.px(), daughter.py(), daughter.pz()})) > trkEtacut) // 0.9 + partFromTauInEta = false; + registrySkim.get(HIST("skim/daughterPhiMC"))->Fill(RecoDecay::phi(daughter.px(), daughter.py())); + registrySkim.get(HIST("skim/daughterEtaMC"))->Fill(RecoDecay::eta(std::array{daughter.px(), daughter.py(), daughter.pz()})); + registrySkim.get(HIST("skim/daughterPtMC"))->Fill(RecoDecay::pt(daughter.px(), daughter.py())); + } + countMothers++; + if (countMothers >= desiredNMothers) // 2 + break; + } // end of loop over MC particles + + registrySkim.get(HIST("skim/nChPartMC"))->Fill(nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); // N charged particles from taus + // check number of charged particles in MC event + if ((nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != fourTracks) && (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != sixTracks)) { + if (verbose) + LOGF(info, "Different from 4/6 charged particles (%d) from both taus. Jump to the next MC event.", nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); + continue; + } + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(3., 1.); // 1+3 (3+3) topology + if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(4., 1.); + } else if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == sixTracks) { // 6 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(5., 1.); + } + + if (!partFromTauInEta) { + if (verbose) + LOGF(info, "At least one daughter particle from taus out of pseudo-rapidity (|eta|<0.9). Jump to the next MC event."); + continue; + } + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(6., 1.); // particles from tau in |eta|<0.9 + if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(7., 1.); + } else if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == sixTracks) { // 6 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(8., 1.); + } + + if (nChargedDaughtersTau[0] == oneProng) // 1 + zerothTau = 0; + else if (nChargedDaughtersTau[1] == oneProng) // 1 + zerothTau = 1; + else if (nChargedDaughtersTau[0] == threeProng && nChargedDaughtersTau[1] == threeProng) // 3 and 3 + zerothTau = 0; + + // prepare local variables for output table + int32_t runNumber = -999; + int bc = -999; + // int nTrks[3] = {-999, -999, -999}; // totalTracks, numContrib, globalNonPVtracks + int totalTracks = -999; + int8_t nPVcontrib = -99; + int rct = -999; + // float vtxPos[3] = {-999., -999., -999.}; + float zVertex = -999; + + int8_t recoMode = -99; + int occupancy = -999; + double hadronicRate = -999.; + int8_t bcSels[8] = {-99, -99, -99, -99, -99, -99, -99, -99}; + // zdc information - there i sno information in MC + float energyZNA = -999.; + float energyZNC = -999.; + + float amplitudesFIT[3] = {-999., -999., -999.}; // FT0A, FT0C, FV0 + // float timesFIT[3] = {-999., -999., -999.}; // FT0A, FT0C, FV0 + // track momentum and sign + float px[6] = {-999., -999., -999., -999., -999., -999.}; + float py[6] = {-999., -999., -999., -999., -999., -999.}; + float pz[6] = {-999., -999., -999., -999., -999., -999.}; + int sign[6] = {-99, -99, -99, -99, -99, -99}; + + float dcaXY[6] = {-999., -999., -999., -999., -999., -999.}; + float dcaZ[6] = {-999., -999., -999., -999., -999., -999.}; + + int nclTPCcrossedRows[6] = {-999, -999, -999, -999, -999, -999}; + int nclTPCfind[6] = {-999, -999, -999, -999, -999, -999}; + float nclTPCchi2[6] = {-999., -999., -999., -999., -999., -999.}; + float trkITSchi2[6] = {-999., -999., -999., -999., -999., -999.}; + int trkITScl[6] = {-999, -999, -999, -999, -999, -999}; + + // float trkTimeRes[2] = {-999., -999.}; + // uint32_t itsClusterSizesTrk1 = 4294967295; + // uint32_t itsClusterSizesTrk2 = 4294967295; + float tpcSignal[6] = {-999, -999, -999, -999, -999, -999}; + float tpcEl[6] = {-999, -999, -999, -999, -999, -999}; + float tpcMu[6] = {-999, -999, -999, -999, -999, -999}; + float tpcPi[6] = {-999, -999, -999, -999, -999, -999}; + float tpcKa[6] = {-999, -999, -999, -999, -999, -999}; + float tpcPr[6] = {-999, -999, -999, -999, -999, -999}; + // float tpcIP[2] = {-999, -999}; + float tofSignal[6] = {-999, -999, -999, -999, -999, -999}; + float tofEl[6] = {-999, -999, -999, -999, -999, -999}; + float tofMu[6] = {-999, -999, -999, -999, -999, -999}; + float tofPi[6] = {-999, -999, -999, -999, -999, -999}; + float tofKa[6] = {-999, -999, -999, -999, -999, -999}; + float tofPr[6] = {-999, -999, -999, -999, -999, -999}; + // float tofEP[2] = {-999, -999}; + float chi2TOF[6] = {-999., -999., -999., -999., -999., -999.}; + + bool trueHasRecoColl = false; + float trueDaugX[6] = {-999., -999., -999., -999., -999., -999.}; + float trueDaugY[6] = {-999., -999., -999., -999., -999., -999.}; + float trueDaugZ[6] = {-999., -999., -999., -999., -999., -999.}; + int trueDaugPdgCode[6] = {-999, -999, -999, -999, -999, -999}; + // bool problem = false; + MyRecoProblem problem = NO_PROBLEM; + registrySkim.get(HIST("skim/problemMC"))->Fill(NO_PROBLEM); + + // tau tau event type + // 1 = e+3pi + // 2 = mu+3pi + // 3 = pi+3pi + // 4 = 3pi+3pi + + if (nElec == oneProng && nPi == threeProng) // 1 + 3 + trueChannel = 1; + else if (nMuon == oneProng && nPi == threeProng) // 1 + 3 + trueChannel = 2; + else if (nPi == fourTracks) // 4 + trueChannel = 3; + else if (nPi == sixTracks) // 6 + trueChannel = 4; + + // find reconstructed collisions associated to the generated collision + auto const& collFromMcColls = collisions.sliceBy(colPerMcCollision, mccoll.globalIndex()); + if (verbose) + LOGF(info, "coll from MC Coll %d", collFromMcColls.size()); + // check the generated collision was reconstructed + if (collFromMcColls.size() > 0) { // get the truth and reco-level info + if (verbose) + LOGF(info, "MC Collision has reconstructed collision!"); + trueHasRecoColl = true; + // check there is exactly one reco-level collision associated to generated collision + if (collFromMcColls.size() > 1) { + if (verbose) + LOGF(info, "Truth collision has more than 1 reco collision. Skipping this event."); + // histos.get(HIST("Truth/hTroubles"))->Fill(1); + // problem = true; + problem = MANY_RECO; + registrySkim.get(HIST("skim/problemMC"))->Fill(MANY_RECO); + continue; + } + // grap reco-level collision + auto const& collFromMcColl = collFromMcColls.iteratorAt(0); + // grab tracks from the reco-level collision to get info to match measured data tables (processDataSG function) + auto const& trksFromColl = tracks.sliceBy(trackPerCollision, collFromMcColl.globalIndex()); + // int countTracksPerCollision = 0; + // int countGoodNonPVtracks = 0; + // for (auto const& trkFromColl : trksFromColl) { + // // countTracksPerCollision++; + // if (!trkFromColl.isPVContributor()) { + // countGoodNonPVtracks++; + // continue; + // } + // } + + // fill info for reconstructed collision + runNumber = collFromMcColl.runNumber(); + bc = collFromMcColl.globalBC(); + totalTracks = trksFromColl.size(); + // nTrks[0] = countTracksPerCollision; + nPVcontrib = collFromMcColl.numContrib(); + // nTrks[1] = collFromMcColl.numContrib(); + // nTrks[2] = countGoodNonPVtracks; + rct = isGoodRCTflag(collFromMcColl); + zVertex = collFromMcColl.posZ(); + // vtxPos[0] = collFromMcColl.posX(); + // vtxPos[1] = collFromMcColl.posY(); + // vtxPos[2] = collFromMcColl.posZ(); + + recoMode = collFromMcColl.flags(); + occupancy = collFromMcColl.occupancyInTime(); + hadronicRate = collFromMcColl.hadronicRate(); + bcSels[0] = collFromMcColl.trs(); + bcSels[1] = collFromMcColl.trofs(); + bcSels[2] = collFromMcColl.hmpr(); + bcSels[3] = collFromMcColl.tfb(); + bcSels[4] = collFromMcColl.itsROFb(); + bcSels[5] = collFromMcColl.sbp(); + bcSels[6] = collFromMcColl.zVtxFT0vPV(); + bcSels[7] = collFromMcColl.vtxITSTPC(); + // energyZNA = collFromMcColl.energyCommonZNA(); + // energyZNC = collFromMcColl.energyCommonZNC(); + // if (energyZNA < 0) + // energyZNA = -1.; + // if (energyZNC < 0) + // energyZNC = -1.; + + amplitudesFIT[0] = collFromMcColl.totalFT0AmplitudeA(); + amplitudesFIT[1] = collFromMcColl.totalFT0AmplitudeC(); + amplitudesFIT[2] = collFromMcColl.totalFV0AmplitudeA(); + // timesFIT[0] = collFromMcColl.timeFT0A(); + // timesFIT[1] = collFromMcColl.timeFT0C(); + // timesFIT[2] = collFromMcColl.timeFV0A(); + + // get particles associated to generated collision + auto const& partsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); + if (verbose) + LOGF(info, "part from MC coll %d", partsFromMcColl.size()); + // int countMothers = 0; + int countDaughters = 0; + countPi0 = 0; + for (const auto& particle : partsFromMcColl) { + if (verbose) + LOGF(info, "Reco coll; part pdg %d", particle.pdgCode()); + // select only tauons with checking if particle has no mother + // in UPC MC taus have mothers + // if (particle.has_mothers()) + if (std::abs(particle.pdgCode()) != kTauMinus) + continue; // 15 = tau_minus + + // get daughters of the tau + const auto& daughters = particle.daughters_as(); + // int countDaughters = 0; + for (const auto& daughter : daughters) { + if (verbose) + LOGF(info, "With Coll; daug pdg %d", daughter.pdgCode()); + // check if it is the charged particle (= no pi0 or neutrino) + if (enumMyParticle(daughter.pdgCode()) == MyOtherParticle) // -1 + continue; + countDaughters++; + if (daughter.pdgCode() == kPi0) + countPi0++; + + // check whether 1+3 or 3+3 topology is present + if (countDaughters > sixTracks) { // 6 + if (verbose) + LOGF(info, "Truth collision has more than 6 charged daughters from 2 taus. Breaking the daughter loop."); + // histos.get(HIST("Truth/hTroubles"))->Fill(3); + // problem = true; + problem = TOO_MANY_DAUGHTERS; + registrySkim.get(HIST("skim/problemMC"))->Fill(TOO_MANY_DAUGHTERS); + + break; + } + + // fill info for each daughter + trueDaugX[countDaughters - 1] = daughter.px(); + trueDaugY[countDaughters - 1] = daughter.py(); + trueDaugZ[countDaughters - 1] = daughter.pz(); + trueDaugPdgCode[countDaughters - 1] = daughter.pdgCode(); + + // get tracks associated to MC daughter (how well the daughter was reconstructed) + auto const& tracksFromDaughter = tracks.sliceBy(trackPerMcParticle, daughter.globalIndex()); + // check there is exactly 1 track per 1 particle + if (tracksFromDaughter.size() > 1) { + if (verbose) + LOGF(info, "Daughter has more than 1 associated track. Skipping this daughter."); + // histos.get(HIST("Truth/hTroubles"))->Fill(4); + // problem = true; + problem = TWO_TRACKS; + registrySkim.get(HIST("skim/problemMC"))->Fill(TWO_TRACKS); + continue; + } + // grab the track and fill info for reconstructed track (should be done 4 or 6 times) + const auto& trk = tracksFromDaughter.iteratorAt(0); + if (verbose) + LOGF(info, "p(%f,%f,%f)", trk.px(), trk.py(), trk.pz()); + px[countDaughters - 1] = trk.px(); + py[countDaughters - 1] = trk.py(); + pz[countDaughters - 1] = trk.pz(); + sign[countDaughters - 1] = trk.sign(); + dcaXY[countDaughters - 1] = trk.dcaXY(); + dcaZ[countDaughters - 1] = trk.dcaZ(); + // trkTimeRes[countMothers - 1] = trk.trackTimeRes(); + // if (countMothers == 1) { + // itsClusterSizesTrk1 = trk.itsClusterSizes(); + // } else { + // itsClusterSizesTrk2 = trk.itsClusterSizes(); + // } + + nclTPCcrossedRows[countDaughters - 1] = trk.tpcNClsCrossedRows(); + nclTPCfind[countDaughters - 1] = trk.tpcNClsFindable(); + nclTPCchi2[countDaughters - 1] = trk.tpcChi2NCl(); + trkITSchi2[countDaughters - 1] = trk.itsChi2NCl(); + trkITScl[countDaughters - 1] = numberOfItsClustersCheck(trk); + + tpcSignal[countDaughters - 1] = trk.tpcSignal(); + tpcEl[countDaughters - 1] = trk.tpcNSigmaEl(); + tpcMu[countDaughters - 1] = trk.tpcNSigmaMu(); + tpcPi[countDaughters - 1] = trk.tpcNSigmaPi(); + tpcKa[countDaughters - 1] = trk.tpcNSigmaKa(); + tpcPr[countDaughters - 1] = trk.tpcNSigmaPr(); + // tpcIP[countDaughters - 1] = trk.tpcInnerParam(); + + tofSignal[countDaughters - 1] = trk.beta(); + tofEl[countDaughters - 1] = trk.tofNSigmaEl(); + tofMu[countDaughters - 1] = trk.tofNSigmaMu(); + tofPi[countDaughters - 1] = trk.tofNSigmaPi(); + tofKa[countDaughters - 1] = trk.tofNSigmaKa(); + tofPr[countDaughters - 1] = trk.tofNSigmaPr(); + // tofEP[countMothers - 1] = trk.tofExpMom(); + if (trk.hasTOF()) + chi2TOF[countDaughters - 1] = trk.tofChi2(); + + } // daughters + } // particles + } else { // get only the truth information. The reco-level info is left on default + if (verbose) + LOGF(info, "MC Collision has NO reconstructed collision!"); + // get particles associated to generated collision + auto const& partsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); + if (verbose) + LOGF(info, "NO Coll; partsFromMcColl in MC %d", partsFromMcColl.size()); + // int countMothers = 0; + int countDaughters = 0; + countPi0 = 0; + for (const auto& particle : partsFromMcColl) { + if (verbose) + LOGF(info, "No Coll; part Gid %d, Id %d, pdg %d, hasM %d, hasD %d", particle.globalIndex(), particle.index(), particle.pdgCode(), particle.has_mothers(), particle.has_daughters()); + // select only tauons with checking if particle has no mother + // in UPC MC taus have mothers + // if (particle.has_mothers()) + if (std::abs(particle.pdgCode()) != kTauMinus) // 15 + continue; + // countMothers++; + // check the generated collision does not have more than 2 tauons + // if (countMothers > 2) { + // if (verbose) + // LOGF(info,"Truth collision has more than 2 no mother particles. Breaking the particle loop."); + // // histos.get(HIST("Truth/hTroubles"))->Fill(12); + // // problem = true; + // break; + // } + // // fill info for each tau + // trueTauX[countMothers - 1] = particle.px(); + // trueTauY[countMothers - 1] = particle.py(); + // trueTauZ[countMothers - 1] = particle.pz(); + + // get daughters of the tau + const auto& daughters = particle.daughters_as(); + if (verbose) + LOGF(info, "NO coll; N_daughters %d", daughters.size()); + // int countDaughters = 0; + for (const auto& daughter : daughters) { + if (verbose) + LOGF(info, "NO Coll; daug id %d, pdg %d", daughter.globalIndex(), daughter.pdgCode()); + // select only the charged particle (= no pi0 or neutrino) + if (enumMyParticle(daughter.pdgCode()) == -1) + continue; + countDaughters++; + if (daughter.pdgCode() == kPi0) + countPi0++; + + // check whether 1+3 or 3+3 topology is present + if (countDaughters > sixTracks) { // 6 + if (verbose) + LOGF(info, "Truth collision has more than 6 charged daughters from taus. Breaking the daughter loop."); + // histos.get(HIST("Truth/hTroubles"))->Fill(13); + // problem = true; + registrySkim.get(HIST("skim/problemMC"))->Fill(TOO_MANY_DAUGHTERS); + problem = TOO_MANY_DAUGHTERS; + break; + } + // fill info for each daughter + trueDaugX[countDaughters - 1] = daughter.px(); + trueDaugY[countDaughters - 1] = daughter.py(); + trueDaugZ[countDaughters - 1] = daughter.pz(); + trueDaugPdgCode[countDaughters - 1] = daughter.pdgCode(); + } // daughters + if (verbose) + LOGF(info, "End of daughters"); + } // particles + } // collisions + + // decide the channel and set the variable. + trueChannel = trueChannel + countPi0 * 10 + zerothTau * 100; + + // LOGF(info, "Should be written!"); + trueTauFourTracks(runNumber, + bc, // is it necessary + totalTracks, + nPVcontrib, + rct, + // dgcand.posX(), dgcand.posY(), + zVertex, + recoMode, + occupancy, + hadronicRate, // is it necessary + bcSels[0], bcSels[1], bcSels[2], // to test it + bcSels[3], bcSels[4], bcSels[5], bcSels[6], bcSels[7], + energyZNA, energyZNC, + // qtot, <<-------- comment out + amplitudesFIT[0], amplitudesFIT[1], amplitudesFIT[2], + // timesFIT[0], timesFIT[1], timesFIT[2], + px, py, pz, sign, + dcaXY, dcaZ, + nclTPCcrossedRows, nclTPCfind, nclTPCchi2, trkITSchi2, trkITScl, + tpcSignal, tpcEl, tpcPi, tpcKa, tpcPr, tpcMu, + tofSignal, tofEl, tofPi, tofKa, tofPr, tofMu, + chi2TOF, + // + trueChannel, + trueHasRecoColl, + mccoll.posZ(), + trueTauX, trueTauY, trueTauZ, + trueDaugX, trueDaugY, trueDaugZ, + trueDaugPdgCode, problem); + } // mccollisions + } // end of processMonteCarlo + PROCESS_SWITCH(TauThreeProngEventTableProducer, 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/twoTracksEventTableProducer.cxx b/PWGUD/TableProducer/twoTracksEventTableProducer.cxx new file mode 100644 index 00000000000..55e5396df12 --- /dev/null +++ b/PWGUD/TableProducer/twoTracksEventTableProducer.cxx @@ -0,0 +1,777 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file twoTracksEventTableProducer.cxx +/// \brief Produces derived table from UD tables +/// +/// \author Roman Lavicka , Austrian Academy of Sciences & SMI +/// \since 20.06.2025 +// + +// C++ headers +#include +#include +#include +#include +#include + +// O2 headers +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/TwoTracksEventTables.h" +#include "PWGUD/DataModel/UDTables.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" + +// ROOT +#include "Math/Vector4D.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +struct TwoTracksEventTableProducer { + Produces twoTracks; + Produces trueTwoTracks; + + // Global varialbes + Service pdg; + SGSelector sgSelector; + int nSelection{0}; + + 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", 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 cutRCTflag{"cutRCTflag", 0, {"0 = off, 1 = CBT, 2 = CBT+ZDC, 3 = CBThadron, 4 = CBThadron+ZDC"}}; + 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 cutEvTFb{"cutEvTFb", true, {"Event selection bit kNoTimeFrameBorder"}}; + Configurable cutEvITSROFb{"cutEvITSROFb", true, {"Event selection bit kNoITSROFrameBorder"}}; + Configurable cutEvSbp{"cutEvSbp", true, {"Event selection bit kNoSameBunchPileup"}}; + Configurable cutEvZvtxFT0vPV{"cutEvZvtxFT0vPV", false, {"Event selection bit kIsGoodZvtxFT0vsPV"}}; + Configurable cutEvVtxITSTPC{"cutEvVtxITSTPC", true, {"Event selection bit kIsVertexITSTPC"}}; + 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 preselAtLeastOneTOFtrack{"preselAtLeastOneTOFtrack", false, {"At least one track is required to hit TOF."}}; + Configurable preselBothAreTOFtracks{"preselBothAreTOFtracks", false, {"Both tracks are required to hit TOF."}}; + Configurable preselUseMinMomentumOnBothTracks{"preselUseMinMomentumOnBothTracks", false, {"Both tracks are required to fill requirement on minimum momentum."}}; + Configurable preselMinTrackMomentum{"preselMinTrackMomentum", 0.1, {"Requirement on minimum momentum of the track."}}; + Configurable preselSystemPtCut{"preselSystemPtCut", 0.0, {"By default, cut on maximum system pT."}}; + Configurable preselUseOppositeSystemPtCut{"preselUseOppositeSystemPtCut", false, {"Negates the system pT cut (cut on minimum system pT)."}}; + Configurable preselMinInvariantMass{"preselMinInvariantMass", 2.0, {"Requirement on minimum system invariant mass."}}; + Configurable preselMaxInvariantMass{"preselMaxInvariantMass", 5.0, {"Requirement on maximum system invariant mass."}}; + } 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; + + // init + void init(InitContext&) + { + if (verboseInfo) + printMediumMessage("INIT METHOD"); + + mySetITShitsRule(cutGlobalTrack.cutITShitsRule); + + histos.add("Reco/hSelections", "Effect of selections;;Number of events (-)", HistType::kTH1D, {{50, 0.5, 50.5}}); + histos.add("Truth/hTroubles", "Counter of unwanted issues;;Number of troubles (-)", HistType::kTH1D, {{15, 0.5, 15.5}}); + + } // end init + + template + bool isGoodFITtime(C const& coll, float maxFITtime) + { + + // FTOA + if ((std::abs(coll.timeFT0A()) > maxFITtime) && coll.timeFT0A() > -998.) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // FTOC + if ((std::abs(coll.timeFT0C()) > maxFITtime) && coll.timeFT0C() > -998.) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + return true; + } + + template + bool isGoodRCTflag(C const& coll) + { + switch (cutSample.cutRCTflag) { + case 1: + return sgSelector.isCBTOk(coll); + case 2: + return sgSelector.isCBTZdcOk(coll); + case 3: + return sgSelector.isCBTHadronOk(coll); + case 4: + return sgSelector.isCBTHadronZdcOk(coll); + default: + return true; + } + } + + template + bool isGoodROFtime(C const& coll) + { + + // kNoTimeFrameBorder + if (cutSample.cutEvTFb && !coll.tfb()) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // kNoITSROFrameBorder + if (cutSample.cutEvITSROFb && !coll.itsROFb()) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // kNoSameBunchPileup + if (cutSample.cutEvSbp && !coll.sbp()) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // kIsGoodZvtxFT0vsPV + if (cutSample.cutEvZvtxFT0vPV && !coll.zVtxFT0vPV()) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // kIsVertexITSTPC + if (cutSample.cutEvVtxITSTPC && !coll.vtxITSTPC()) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // Occupancy + if (coll.occupancyInTime() > cutSample.cutEvOccupancy) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // kNoCollInTimeRangeStandard + if (cutSample.cutEvTrs && !coll.trs()) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // kNoCollInRofStandard + if (cutSample.cutEvTrofs && !coll.trofs()) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // kNoHighMultCollInPrevRof + if (cutSample.cutEvHmpr && !coll.hmpr()) + return false; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + 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; // good ITS-TPC matching means ITS ch2 is not negative + } + // TOF + if (track.hasTOF()) { + if (track.tpcChi2NCl() > cutGlobalTrack.cutMaxTOFchi2) + return false; // TOF chi2 + } + + return true; + } + + template + float findRightMass(T const& trk1, T const& trk2) + // choose the right mass for the tracks based on comparing combined sigma + // good for same-type particles decays + { + float nSigmasTPCsqrt[5]; + nSigmasTPCsqrt[P_ELECTRON] = std::sqrt(trk1.tpcNSigmaEl() * trk1.tpcNSigmaEl() + trk2.tpcNSigmaEl() * trk2.tpcNSigmaEl()); + nSigmasTPCsqrt[P_MUON] = std::sqrt(trk1.tpcNSigmaMu() * trk1.tpcNSigmaMu() + trk2.tpcNSigmaMu() * trk2.tpcNSigmaMu()); + nSigmasTPCsqrt[P_PION] = std::sqrt(trk1.tpcNSigmaPi() * trk1.tpcNSigmaPi() + trk2.tpcNSigmaPi() * trk2.tpcNSigmaPi()); + nSigmasTPCsqrt[P_KAON] = std::sqrt(trk1.tpcNSigmaKa() * trk1.tpcNSigmaKa() + trk2.tpcNSigmaKa() * trk2.tpcNSigmaKa()); + nSigmasTPCsqrt[P_PROTON] = std::sqrt(trk1.tpcNSigmaPr() * trk1.tpcNSigmaPr() + trk2.tpcNSigmaPr() * trk2.tpcNSigmaPr()); + + int enumChoiceTPC = std::distance(std::begin(nSigmasTPCsqrt), + std::min_element(std::begin(nSigmasTPCsqrt), std::end(nSigmasTPCsqrt))); + + return pdg->Mass(trackPDGfromEnum(enumChoiceTPC)); + } + + void processDataSG(FullSGUDCollision const& collision, + FullUDTracks const& tracks) + { + + nSelection = 0; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + if (!isGoodRCTflag(collision)) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + if (!isGoodROFtime(collision)) + return; + + int gapSide = collision.gapSide(); + int trueGapSide = sgSelector.trueGap(collision, cutSample.cutTrueGapSideFV0, cutSample.cutTrueGapSideFT0A, cutSample.cutTrueGapSideFT0C, cutSample.cutTrueGapSideZDC); + if (cutSample.useTrueGap) + gapSide = trueGapSide; + if (gapSide != cutSample.whichGapSide) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + if (!isGoodFITtime(collision, cutSample.cutFITtime)) + return; + + if (cutSample.useNumContribs && (collision.numContrib() != cutSample.cutNumContribs)) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + if (cutSample.useRecoFlag && (collision.flags() != cutSample.cutRecoFlag)) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + 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 + + // Critical selection, without it the rest of the process function will fail + if (countGoodPVtracks != 2) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + const auto& trk1 = tracks.iteratorAt(vecTrkIdx[0]); + const auto& trk2 = tracks.iteratorAt(vecTrkIdx[1]); + + float thisMass = findRightMass(trk1, trk2); + + // prepare lorentz vectors to create system + ROOT::Math::LorentzVector> twoTrackMother, daug[2]; + daug[0].SetPxPyPzE(trk1.px(), trk1.py(), trk1.pz(), energy(thisMass, trk1.px(), trk1.py(), trk1.pz())); + daug[1].SetPxPyPzE(trk2.px(), trk2.py(), trk2.pz(), energy(thisMass, trk2.px(), trk2.py(), trk2.pz())); + twoTrackMother = daug[0] + daug[1]; + float thisPt = pt(twoTrackMother.px(), twoTrackMother.py()); + + // Apply system selections + // invariant mass + if (twoTrackMother.M() < cutPreselect.preselMinInvariantMass || twoTrackMother.M() > cutPreselect.preselMaxInvariantMass) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // system pt + if (cutPreselect.preselUseOppositeSystemPtCut ? thisPt < cutPreselect.preselSystemPtCut : thisPt > cutPreselect.preselSystemPtCut) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // one track momentum + if (daug[0].P() < cutPreselect.preselMinTrackMomentum && daug[1].P() < cutPreselect.preselMinTrackMomentum) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // both tracks momentum + if (cutPreselect.preselUseMinMomentumOnBothTracks && (daug[0].P() < cutPreselect.preselMinTrackMomentum || daug[1].P() < cutPreselect.preselMinTrackMomentum)) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // track in TOF + if (cutPreselect.preselAtLeastOneTOFtrack && (!trk1.hasTOF() && !trk2.hasTOF())) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + // tracks in TOF + if (cutPreselect.preselBothAreTOFtracks && (!trk1.hasTOF() || !trk2.hasTOF())) + return; + histos.get(HIST("Reco/hSelections"))->Fill(nSelection); + nSelection++; + + 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] = {collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC()}; + + twoTracks(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(TwoTracksEventTableProducer, processDataSG, "Iterate UD tables with measured data created by SG-Candidate-Producer.", false); + + PresliceUnsorted partPerMcCollision = aod::udmcparticle::udMcCollisionId; + PresliceUnsorted colPerMcCollision = aod::udcollision::udMcCollisionId; + PresliceUnsorted trackPerMcParticle = aod::udmctracklabel::udMcParticleId; + Preslice trackPerCollision = aod::udtrack::udCollisionId; // sorted preslice used because the pair track-collision is already sorted in processDataSG function + + void processMonteCarlo(aod::UDMcCollisions const& mccollisions, + aod::UDMcParticles const& parts, + FullMCSGUDCollisions const& recolls, + FullMCUDTracks const& trks) + { + // start loop over generated collisions + for (const auto& mccoll : mccollisions) { + + // prepare local variables for output table + int32_t runNumber = -999; + int bc = -999; + int nTrks[3] = {-999, -999, -999}; // totalTracks, numContrib, globalNonPVtracks + float vtxPos[3] = {-999., -999., -999.}; + int recoMode = -999; + int occupancy = -999.; + double hadronicRate = -999.; + int bcSels[8] = {-999, -999, -999, -999, -999, -999, -999, -999}; + float amplitudesFIT[3] = {-999., -999., -999.}; // FT0A, FT0C, FV0 + float timesFIT[3] = {-999., -999., -999.}; // FT0A, FT0C, FV0 + + float px[2] = {-999., -999.}; + float py[2] = {-999., -999.}; + float pz[2] = {-999., -999.}; + int sign[2] = {-999, -999}; + float dcaxy[2] = {-999., -999.}; + float dcaz[2] = {-999., -999.}; + float trkTimeRes[2] = {-999., -999.}; + uint32_t itsClusterSizesTrk1 = 4294967295; + uint32_t itsClusterSizesTrk2 = 4294967295; + float tpcSignal[2] = {-999, -999}; + float tpcEl[2] = {-999, -999}; + float tpcMu[2] = {-999, -999}; + float tpcPi[2] = {-999, -999}; + float tpcKa[2] = {-999, -999}; + float tpcPr[2] = {-999, -999}; + float tpcIP[2] = {-999, -999}; + float tofSignal[2] = {-999, -999}; + float tofEl[2] = {-999, -999}; + float tofMu[2] = {-999, -999}; + float tofPi[2] = {-999, -999}; + float tofKa[2] = {-999, -999}; + float tofPr[2] = {-999, -999}; + float tofEP[2] = {-999, -999}; + + int trueChannel = -1; + bool trueHasRecoColl = false; + float trueMotherX[2] = {-999., -999.}; + float trueMotherY[2] = {-999., -999.}; + float trueMotherZ[2] = {-999., -999.}; + float trueDaugX[2] = {-999., -999.}; + float trueDaugY[2] = {-999., -999.}; + float trueDaugZ[2] = {-999., -999.}; + int trueDaugPdgCode[2] = {-999, -999}; + bool problem = false; + + // find reconstructed collisions associated to the generated collision + auto const& collFromMcColls = recolls.sliceBy(colPerMcCollision, mccoll.globalIndex()); + // check the generated collision was reconstructed + if (collFromMcColls.size() > 0) { // get the truth and reco-level info + trueHasRecoColl = true; + // check there is exactly one reco-level collision associated to generated collision + if (collFromMcColls.size() > 1) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 1 reco collision. Skipping this event."); + histos.get(HIST("Truth/hTroubles"))->Fill(1); + problem = true; + continue; + } + // grap reco-level collision + auto const& collFromMcColl = collFromMcColls.iteratorAt(0); + // grab tracks from the reco-level collision to get info to match measured data tables (processDataSG function) + auto const& trksFromColl = trks.sliceBy(trackPerCollision, collFromMcColl.globalIndex()); + int countTracksPerCollision = 0; + int countGoodNonPVtracks = 0; + for (auto const& trkFromColl : trksFromColl) { + countTracksPerCollision++; + if (!trkFromColl.isPVContributor()) { + countGoodNonPVtracks++; + continue; + } + } + + // fill info for reconstructed collision + runNumber = collFromMcColl.runNumber(); + bc = collFromMcColl.globalBC(); + nTrks[0] = countTracksPerCollision; + nTrks[1] = collFromMcColl.numContrib(); + nTrks[2] = countGoodNonPVtracks; + vtxPos[0] = collFromMcColl.posX(); + vtxPos[1] = collFromMcColl.posY(); + vtxPos[2] = collFromMcColl.posZ(); + recoMode = collFromMcColl.flags(); + occupancy = collFromMcColl.occupancyInTime(); + hadronicRate = collFromMcColl.hadronicRate(); + bcSels[0] = collFromMcColl.trs(); + bcSels[1] = collFromMcColl.trofs(); + bcSels[2] = collFromMcColl.hmpr(); + bcSels[3] = collFromMcColl.tfb(); + bcSels[4] = collFromMcColl.itsROFb(); + bcSels[5] = collFromMcColl.sbp(); + bcSels[6] = collFromMcColl.zVtxFT0vPV(); + bcSels[7] = collFromMcColl.vtxITSTPC(); + amplitudesFIT[0] = collFromMcColl.totalFT0AmplitudeA(); + amplitudesFIT[1] = collFromMcColl.totalFT0AmplitudeC(); + amplitudesFIT[2] = collFromMcColl.totalFV0AmplitudeA(); + timesFIT[0] = collFromMcColl.timeFT0A(); + timesFIT[1] = collFromMcColl.timeFT0C(); + timesFIT[2] = collFromMcColl.timeFV0A(); + + // get particles associated to generated collision + auto const& partsFromMcColl = parts.sliceBy(partPerMcCollision, mccoll.globalIndex()); + int countMothers = 0; + for (const auto& particle : partsFromMcColl) { + // select only mothers with checking if particle has no mother + if (particle.has_mothers()) + continue; + countMothers++; + // check the generated collision does not have more than 2 mothers + if (countMothers > 2) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 2 no mother particles. Breaking the particle loop."); + histos.get(HIST("Truth/hTroubles"))->Fill(2); + problem = true; + break; + } + // fill info for each mother + trueMotherX[countMothers - 1] = particle.px(); + trueMotherY[countMothers - 1] = particle.py(); + trueMotherZ[countMothers - 1] = particle.pz(); + + // get daughters of the tau + const auto& daughters = particle.daughters_as(); + int countDaughters = 0; + for (const auto& daughter : daughters) { + // check if it is the charged particle (= no pi0 or neutrino) + if (enumMyParticle(daughter.pdgCode()) == -1) + continue; + countDaughters++; + // check there is only 1 charged daughter related to 1 tau + if (countDaughters > 1) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 1 charged daughters of no mother particles. Breaking the daughter loop."); + histos.get(HIST("Truth/hTroubles"))->Fill(3); + problem = true; + break; + } + // fill info for each daughter + trueDaugX[countMothers - 1] = daughter.px(); + trueDaugY[countMothers - 1] = daughter.py(); + trueDaugZ[countMothers - 1] = daughter.pz(); + trueDaugPdgCode[countMothers - 1] = daughter.pdgCode(); + + // get tracks associated to MC daughter (how well the daughter was reconstructed) + auto const& tracksFromDaughter = trks.sliceBy(trackPerMcParticle, daughter.globalIndex()); + // check there is exactly 1 track per 1 particle + if (tracksFromDaughter.size() > 1) { + if (verboseInfo) + printLargeMessage("Daughter has more than 1 associated track. Skipping this daughter."); + histos.get(HIST("Truth/hTroubles"))->Fill(4); + problem = true; + continue; + } + // grab the track and fill info for reconstructed track (should be done twice) + const auto& trk = tracksFromDaughter.iteratorAt(0); + px[countMothers - 1] = trk.px(); + py[countMothers - 1] = trk.py(); + pz[countMothers - 1] = trk.pz(); + sign[countMothers - 1] = trk.sign(); + dcaxy[countMothers - 1] = trk.dcaXY(); + dcaz[countMothers - 1] = trk.dcaZ(); + trkTimeRes[countMothers - 1] = trk.trackTimeRes(); + if (countMothers == 1) { + itsClusterSizesTrk1 = trk.itsClusterSizes(); + } else { + itsClusterSizesTrk2 = trk.itsClusterSizes(); + } + tpcSignal[countMothers - 1] = trk.tpcSignal(); + tpcEl[countMothers - 1] = trk.tpcNSigmaEl(); + tpcMu[countMothers - 1] = trk.tpcNSigmaMu(); + tpcPi[countMothers - 1] = trk.tpcNSigmaPi(); + tpcKa[countMothers - 1] = trk.tpcNSigmaKa(); + tpcPr[countMothers - 1] = trk.tpcNSigmaPr(); + tpcIP[countMothers - 1] = trk.tpcInnerParam(); + tofSignal[countMothers - 1] = trk.tofSignal(); + tofEl[countMothers - 1] = trk.tofNSigmaEl(); + tofMu[countMothers - 1] = trk.tofNSigmaMu(); + tofPi[countMothers - 1] = trk.tofNSigmaPi(); + tofKa[countMothers - 1] = trk.tofNSigmaKa(); + tofPr[countMothers - 1] = trk.tofNSigmaPr(); + tofEP[countMothers - 1] = trk.tofExpMom(); + } // daughters + } // particles + } else { // get only the truth information. The reco-level info is left on default + // get particles associated to generated collision + auto const& partsFromMcColl = parts.sliceBy(partPerMcCollision, mccoll.globalIndex()); + int countMothers = 0; + for (const auto& particle : partsFromMcColl) { + // select only tauons with checking if particle has no mother + if (particle.has_mothers()) + continue; + countMothers++; + // check the generated collision does not have more than 2 mothers + if (countMothers > 2) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 2 no mother particles. Breaking the particle loop."); + histos.get(HIST("Truth/hTroubles"))->Fill(12); + problem = true; + break; + } + // fill info for each tau + trueMotherX[countMothers - 1] = particle.px(); + trueMotherY[countMothers - 1] = particle.py(); + trueMotherZ[countMothers - 1] = particle.pz(); + + // get daughters of the tau + const auto& daughters = particle.daughters_as(); + int countDaughters = 0; + for (const auto& daughter : daughters) { + // select only the charged particle (= no pi0 or neutrino) + if (enumMyParticle(daughter.pdgCode()) == -1) + continue; + countDaughters++; + // check there is only 1 charged daughter related to 1 tau + if (countDaughters > 1) { + if (verboseInfo) + printLargeMessage("Truth collision has more than 1 charged daughters of no mother particles. Breaking the daughter loop."); + histos.get(HIST("Truth/hTroubles"))->Fill(13); + problem = true; + break; + } + // fill info for each daughter + trueDaugX[countMothers - 1] = daughter.px(); + trueDaugY[countMothers - 1] = daughter.py(); + trueDaugZ[countMothers - 1] = daughter.pz(); + trueDaugPdgCode[countMothers - 1] = daughter.pdgCode(); + } // daughters + } // particles + } // collisions + + // decide the channel and set the variable. Only two cahnnels suported now. + if ((enumMyParticle(trueDaugPdgCode[0]) == P_ELECTRON) && (enumMyParticle(trueDaugPdgCode[1]) == P_ELECTRON)) + trueChannel = CH_EE; + if ((enumMyParticle(trueDaugPdgCode[0]) == P_ELECTRON) && ((enumMyParticle(trueDaugPdgCode[1]) == P_PION) || (enumMyParticle(trueDaugPdgCode[1]) == P_MUON))) + trueChannel = CH_EMUPI; + if ((enumMyParticle(trueDaugPdgCode[1]) == P_ELECTRON) && ((enumMyParticle(trueDaugPdgCode[0]) == P_PION) || (enumMyParticle(trueDaugPdgCode[0]) == P_MUON))) + trueChannel = CH_EMUPI; + + trueTwoTracks(runNumber, bc, nTrks[0], nTrks[1], nTrks[2], vtxPos[0], vtxPos[1], vtxPos[2], + recoMode, occupancy, hadronicRate, bcSels[0], bcSels[1], bcSels[2], + bcSels[3], bcSels[4], bcSels[5], bcSels[6], bcSels[7], + amplitudesFIT[0], amplitudesFIT[1], amplitudesFIT[2], -999., -999., // no ZDC info in MC + timesFIT[0], timesFIT[1], timesFIT[2], -999., -999., // no ZDC info in MC + px, py, pz, sign, dcaxy, dcaz, trkTimeRes, + itsClusterSizesTrk1, itsClusterSizesTrk2, + tpcSignal, tpcEl, tpcMu, tpcPi, tpcKa, tpcPr, tpcIP, + tofSignal, tofEl, tofMu, tofPi, tofKa, tofPr, tofEP, + trueChannel, trueHasRecoColl, mccoll.posX(), mccoll.posY(), mccoll.posZ(), + trueMotherX, trueMotherY, trueMotherZ, trueDaugX, trueDaugY, trueDaugZ, trueDaugPdgCode, problem); + } // mccollisions + } + PROCESS_SWITCH(TwoTracksEventTableProducer, 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 521a4bcc53b..89cd087ef28 100644 --- a/PWGUD/Tasks/CMakeLists.txt +++ b/PWGUD/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(upc-polarisation-jpsi-incoh + SOURCES upcPolarisationJpsiIncoh.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(upc SOURCES upcAnalysis.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase @@ -19,6 +24,16 @@ 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 @@ -113,8 +128,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) @@ -124,7 +140,7 @@ o2physics_add_dpl_workflow(polarisation-rho COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(upc-jpsi-corr - SOURCES upcJpsiCentralBarrelCorr.cxx + SOURCES upcJpsiCorr.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGPIDSelector COMPONENT_NAME Analysis) @@ -135,7 +151,7 @@ o2physics_add_dpl_workflow(exclusive-phi o2physics_add_dpl_workflow(upc-photonuclear-jmg SOURCES upcPhotonuclearAnalysisJMG.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::ReconstructionDataFormats O2::DetectorsBase O2::DetectorsCommonDataFormats + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2::ReconstructionDataFormats O2::DetectorsBase O2::DetectorsCommonDataFormats COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(exclusive-two-protons @@ -153,6 +169,11 @@ o2physics_add_dpl_workflow(exclusive-phi-leptons 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 @@ -168,7 +189,77 @@ o2physics_add_dpl_workflow(sg-exclusive-phi 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) + +o2physics_add_dpl_workflow(analysis-mc-dpm-jet-sg-v3 + SOURCES analysisMCDPMJetSGv3.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-test-rct-tables + SOURCES upcTestRctTables.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGUD/Tasks/FwdMuonsUPC.cxx b/PWGUD/Tasks/FwdMuonsUPC.cxx new file mode 100644 index 00000000000..0c4b3d81e3b --- /dev/null +++ b/PWGUD/Tasks/FwdMuonsUPC.cxx @@ -0,0 +1,1035 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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(TrackTypep, trackTypep, int); +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); +DECLARE_SOA_COLUMN(TrackTypen, trackTypen, int); +// 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::TrackTypep, + dimu::EnergyN, dimu::Pxn, dimu::Pyn, dimu::Pzn, dimu::Ptn, dimu::Etan, dimu::Phin, dimu::TrackTypen, + 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(GenM, genM, float); +DECLARE_SOA_COLUMN(GenPt, genPt, float); +DECLARE_SOA_COLUMN(GenRap, genRap, float); +DECLARE_SOA_COLUMN(GenPhi, genPhi, float); +DECLARE_SOA_COLUMN(GenPhiAv, genPhiAv, float); +DECLARE_SOA_COLUMN(GenPhiCh, genPhiCh, float); +// tracks positive (p) and negative (n) +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 gendimu + +namespace o2::aod +{ +DECLARE_SOA_TABLE(GenDimu, "AOD", "GENDIMU", + gendimu::GenM, gendimu::GenPt, gendimu::GenRap, gendimu::GenPhi, + gendimu::GenPhiAv, gendimu::GenPhiCh, + gendimu::GenPtp, gendimu::GenEtap, gendimu::GenPhip, + gendimu::GenPtn, gendimu::GenEtan, gendimu::GenPhin); +} // 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(TrackTypep, trackTypep, int); +DECLARE_SOA_COLUMN(Ptn, ptn, float); +DECLARE_SOA_COLUMN(Etan, etan, float); +DECLARE_SOA_COLUMN(Phin, phin, float); +DECLARE_SOA_COLUMN(TrackTypen, trackTypen, int); +// 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::TrackTypep, + recodimu::Ptn, recodimu::Etan, recodimu::Phin, recodimu::TrackTypen, + 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.; +float kEtaMin = -4.0; +float kEtaMax = -2.5; +const float kPtMin = 0.; + +const float kMaxAmpV0A = 100.; +const int kReqMatchMIDTracks = 2; +const int kReqMatchMFTTracks = 2; +const int kMaxChi2MFTMatch = 30; +const float kMaxZDCTime = 2.; +const float kMaxZDCTimeHisto = 10.; +const int kMuonPDG = 13; + +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"}; + // my track type + // 0 = MCH-MID-MFT + // 1 = MCH-MID + Configurable myTrackType{"myTrackType", 3, "My track type"}; + + 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}; + + std::vector ptFitBinningHalfWidth = { + 0.00, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.035, 0.04, 0.045, 0.05, + 0.055, 0.06, 0.065, 0.07, 0.075, 0.08, 0.085, 0.09, 0.095, 0.10, + 0.105, 0.11, 0.115, 0.12, 0.125, 0.13, 0.135, 0.14, 0.145, 0.15, + 0.1625, 0.175, 0.1875, 0.20, 0.225, 0.25, 0.275, 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.25, + 2.50, 2.75, 3.00, 3.25, 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 axisPtFit2 = {ptFitBinningHalfWidth, "#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("hPtFit2", "Transverse momentum of muon pairs;;#counts", kTH1D, {axisPtFit2}); + 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("hPtFit2", "Transverse momentum of muon pairs;;#counts", kTH1D, {axisPtFit2}); + 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(kMuonPDG); + 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; + float halfUnity = 0.5; + if (sign1 > 0) { + tDiffCh = p1 - p2; + if (gRandom->Rndm() > halfUnity) + tDiffAv = p1 - p2; + else + tDiffAv = p2 - p1; + } else { + tDiffCh = p2 - p1; + if (gRandom->Rndm() > halfUnity) + 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] > kMaxAmpV0A) + return; + } + } + + // select opposite charge events only + if (cand.netCharge() != 0) { + registry.fill(HIST("hSameSign"), cand.numContrib()); + return; + } + + // MCH-MID match selection + int nMIDs = 0; + if (tr1.chi2MatchMCHMID() > 0) + nMIDs++; + if (tr2.chi2MatchMCHMID() > 0) + nMIDs++; + if (nMIDs != kReqMatchMIDTracks) + return; + + // MFT-MID match selection (if MFT is requested by the trackType) + if (myTrackType == 0) { + // if MFT is requested check that the tracks is inside the MFT acceptance + kEtaMin = -3.6; + kEtaMax = -2.5; + + int nMFT = 0; + if (tr1.chi2MatchMCHMFT() > 0 && tr1.chi2MatchMCHMFT() < kMaxChi2MFTMatch) + nMFT++; + if (tr2.chi2MatchMCHMFT() > 0 && tr2.chi2MatchMCHMFT() < kMaxChi2MFTMatch) + nMFT++; + if (nMFT != kReqMatchMFTTracks) + return; + } + + // track selection + if (!isMuonSelected(*tr1)) + return; + if (!isMuonSelected(*tr2)) + return; + + // form Lorentz vectors + TLorentzVector p1, p2; + auto mMu = particleMass(kMuonPDG); + 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) < kMaxZDCTimeHisto) + registry.fill(HIST("hTimeZNA"), zdc.timeA); + if (std::abs(zdc.timeC) < kMaxZDCTimeHisto) + 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) < kMaxZDCTime) + neutronA = true; + if (std::abs(zdc.timeC) < kMaxZDCTime) + 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("hPtFit2"), 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(), static_cast(myTrackType), + p2.E(), p2.Px(), p2.Py(), p2.Pz(), p2.Pt(), p2.PseudoRapidity(), p2.Phi(), static_cast(myTrackType), + 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(), static_cast(myTrackType), + p1.E(), p1.Px(), p1.Py(), p1.Pz(), p1.Pt(), p1.PseudoRapidity(), p1.Phi(), static_cast(myTrackType), + 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()) != kMuonPDG && std::abs(McPart2.pdgCode()) != kMuonPDG) + LOGF(debug, "PDG codes: %d | %d", McPart1.pdgCode(), McPart2.pdgCode()); + + // create Lorentz vectors + TLorentzVector p1, p2; + auto mMu = particleMass(kMuonPDG); + 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()) != kMuonPDG && std::abs(McPart2.pdgCode()) != kMuonPDG) + 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] > kMaxAmpV0A) + return; + } + } + + // select opposite charge events only + if (cand.netCharge() != 0) { + registry.fill(HIST("hSameSign"), cand.numContrib()); + return; + } + + // MCH-MID match selection + int nMIDs = 0; + if (tr1.chi2MatchMCHMID() > 0) + nMIDs++; + if (tr2.chi2MatchMCHMID() > 0) + nMIDs++; + if (nMIDs != kReqMatchMIDTracks) + return; + + // MFT-MID match selection (if MFT is requested by the trackType) + if (myTrackType == 0) { + // if MFT is requested check that the tracks is inside the MFT acceptance + kEtaMin = -3.6; + kEtaMax = -2.5; + + int nMFT = 0; + if (tr1.chi2MatchMCHMFT() > 0 && tr1.chi2MatchMCHMFT() < kMaxChi2MFTMatch) + nMFT++; + if (tr2.chi2MatchMCHMFT() > 0 && tr2.chi2MatchMCHMFT() < kMaxChi2MFTMatch) + nMFT++; + if (nMFT != kReqMatchMFTTracks) + return; + } + + // track selection + if (!isMuonSelected(*tr1)) + return; + if (!isMuonSelected(*tr2)) + return; + + // form Lorentz vectors + TLorentzVector p1, p2; + auto mMu = particleMass(kMuonPDG); + 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("hPtFit2"), 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(), static_cast(myTrackType), + p2.Pt(), p2.PseudoRapidity(), p2.Phi(), static_cast(myTrackType), + // 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(), static_cast(myTrackType), + p1.Pt(), p1.PseudoRapidity(), p1.Phi(), static_cast(myTrackType), + // 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/analysisMCDPMJetSGv3.cxx b/PWGUD/Tasks/analysisMCDPMJetSGv3.cxx new file mode 100644 index 00000000000..4347871377a --- /dev/null +++ b/PWGUD/Tasks/analysisMCDPMJetSGv3.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. +/// \file AnalysisMCDPMJetSGv3.cxx +/// \brief Process MC DPMJet events for inclusive studies. +/// +/// \author Simone Ragoni + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Framework/ASoAHelpers.h" +// #include "TDatabasePDG.h" +#include "PWGUD/Core/UPCHelpers.h" +#include "PWGUD/DataModel/UDTables.h" +// #include "TLorentzVector.h" +// #include "TVector3.h" +#include "Math/LorentzVector.h" // ROOT::Math::LorentzVector +#include "Math/PxPyPzM4D.h" // ROOT::Math::PxPyPzM4D +#include "TMath.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct AnalysisMCDPMJetSGv3 { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // TDatabasePDG* fPDG = TDatabasePDG::Instance(); + + Configurable nBinsPt{"nBinsPt", 100, "N bins in pT histo"}; + + // using myCompleteTracks = soa::Join; + // using myFilteredTracks = soa::Filtered; + using BCs = soa::Join; + + Preslice perCollision = aod::track::collisionId; + Preslice perMcCollision = o2::aod::mcparticle::mcCollisionId; + // using MCTCs = soa::Join; + // using MCTC = MCTCs::iterator; + // define abbreviations + using CCs = soa::Join; + using CC = CCs::iterator; + using MCparticles = aod::UDMcParticles::iterator; + using TCs = soa::Join; + // using TCs = soa::Join; + using TC = TCs::iterator; + using LorentzVectorM = ROOT::Math::LorentzVector>; + + double massPion = 0.; + double massKaon = 0.; + double massProton = 0.; + const int codePion = 211; + const int codeKaon = 321; + const int codeProton = 2212; + + void init(InitContext const&) + { + // TParticlePDG* pionPDG = fPDG->GetParticle(codePion); + // if (pionPDG != nullptr) { + // massPion = pionPDG->Mass(); + // } + // TParticlePDG* kaonPDG = fPDG->GetParticle(codeKaon); + // if (kaonPDG != nullptr) { + // massKaon = kaonPDG->Mass(); + // } + // TParticlePDG* protonPDG = fPDG->GetParticle(codeProton); + // if (protonPDG != nullptr) { + // massProton = protonPDG->Mass(); + // } + massPion = o2::constants::physics::MassPionCharged; + massKaon = o2::constants::physics::MassKaonCharged; + massProton = o2::constants::physics::MassProton; + + // define axes you want to use + const AxisSpec axisCounter{10, 0, 10, ""}; + const AxisSpec axisEta{100, -1.5, +1.5, "#eta"}; + const AxisSpec axisPt{5000, 0, 5, "p_{T}"}; + const AxisSpec axisPtSmall{1000, 0, 1, "p_{T}"}; + const AxisSpec axisMass{nBinsPt, 0, 5, "m_{#pi#pi}"}; + const AxisSpec axisMassSmall{nBinsPt, 0, 2, "m_{#pi#pi}"}; + const AxisSpec axisDeltaPt{100, -1.0, +1.0, "#Delta(p_{T})"}; + const AxisSpec axisBC{1000, -10000.0, +10000.0, "BCs"}; + const AxisSpec axisBCext{100000, -10000000.0, +10000000.0, "BCs"}; + const AxisSpec axisCosTheta{100, -1.0, +1.0, "cos#theta"}; + const AxisSpec axisPhi{600, -o2::constants::math::PI, -o2::constants::math::PI, "#varphi"}; + + // create histograms + histos.add("hdEdx", "p vs dE/dx Signal", kTH2F, {{100, 0.0, 3.0}, {1000, 0.0, 2000.0}}); + histos.add("hSigmaPion", "p vs dE/dx sigma pion TPC ", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaPionTruth", "p vs dE/dx sigma pion TPC truth", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaPionTOF", "p vs dE/dx sigma pion TOF ", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaPionTruthTOF", "p vs dE/dx sigma pion TOF truth", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaKaon", "p vs dE/dx sigma kaon TPC ", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaKaonTruth", "p vs dE/dx sigma kaon TPC truth", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaKaonTOF", "p vs dE/dx sigma kaon TOF ", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaKaonTruthTOF", "p vs dE/dx sigma kaon TOF truth", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaProton", "p vs dE/dx sigma proton TPC ", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaProtonTruth", "p vs dE/dx sigma proton TPC truth", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaProtonTOF", "p vs dE/dx sigma proton TOF ", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + histos.add("hSigmaProtonTruthTOF", "p vs dE/dx sigma proton TOF truth", kTH2F, {{300, 0.0, 3.0}, {200, -10.0, 10.0}}); + + histos.add("hVisibleMultiVsGeneratedMulti", "Multiplicity correlation", kTH2F, {{10000, -0.5, 9999.5}, {1000, -0.5, 999.5}}); + + histos.add("eventCounter", "eventCounter", kTH1F, {axisCounter}); + histos.add("ptResolution", "ptResolution", kTH2F, {axisPt, axisDeltaPt}); + + histos.add("ptGeneratedPion", "ptGeneratedPion", kTH1F, {axisPt}); + histos.add("ptGeneratedKaon", "ptGeneratedKaon", kTH1F, {axisPt}); + histos.add("ptGeneratedProton", "ptGeneratedProton", kTH1F, {axisPt}); + histos.add("ptGeneratedPionAxE", "ptGeneratedPionAxE", kTH1F, {axisPt}); + histos.add("ptGeneratedKaonAxE", "ptGeneratedKaonAxE", kTH1F, {axisPt}); + histos.add("ptGeneratedProtonAxE", "ptGeneratedProtonAxE", kTH1F, {axisPt}); + histos.add("ptGeneratedProtonAxEPos", "ptGeneratedProtonAxEPos", kTH1F, {axisPt}); + histos.add("ptGeneratedProtonAxENeg", "ptGeneratedProtonAxENeg", kTH1F, {axisPt}); + histos.add("ptReconstructedPion", "ptReconstructedPion", kTH1F, {axisPt}); + histos.add("ptReconstructedKaon", "ptReconstructedKaon", kTH1F, {axisPt}); + histos.add("ptReconstructedProton", "ptReconstructedProton", kTH1F, {axisPt}); + histos.add("ptReconstructedProtonPos", "ptReconstructedProtonPos", kTH1F, {axisPt}); + histos.add("ptReconstructedProtonNeg", "ptReconstructedProtonNeg", kTH1F, {axisPt}); + histos.add("ptReconstructedPionTOF", "ptReconstructedPionTOF", kTH1F, {axisPt}); + histos.add("ptReconstructedKaonTOF", "ptReconstructedKaonTOF", kTH1F, {axisPt}); + histos.add("ptReconstructedProtonTOF", "ptReconstructedProtonTOF", kTH1F, {axisPt}); + + histos.add("allreconstructedPFPion", "allreconstructedPFPion", kTH1F, {axisPt}); + histos.add("allreconstructedPFKaon", "allreconstructedPFKaon", kTH1F, {axisPt}); + histos.add("allreconstructedPFProton", "allreconstructedPFProton", kTH1F, {axisPt}); + histos.add("allreconstructedPFProtonPos", "allreconstructedPFProtonPos", kTH1F, {axisPt}); + histos.add("allreconstructedPFProtonNeg", "allreconstructedPFProtonNeg", kTH1F, {axisPt}); + histos.add("allreconstructedPFPionTOF", "allreconstructedPFPionTOF", kTH1F, {axisPt}); + histos.add("allreconstructedPFKaonTOF", "allreconstructedPFKaonTOF", kTH1F, {axisPt}); + histos.add("allreconstructedPFProtonTOF", "allreconstructedPFProtonTOF", kTH1F, {axisPt}); + + histos.add("numberOfRecoCollisions", "numberOfRecoCollisions", kTH1F, {{100, -0.5f, 99.5f}}); + histos.add("numberOfRecoCollisions2", "numberOfRecoCollisions2", kTH1F, {{100, -0.5f, 99.5f}}); + histos.add("numberOfTracksMC", "numberOfTracksMC", kTH1F, {{100, -0.5f, 99.5f}}); + histos.add("numberOfTracksReco", "numberOfTracksReco", kTH1F, {{100, -0.5f, 99.5f}}); + + histos.add("bcResolution", "bcResolution", kTH1F, {axisBC}); + histos.add("mcbcHistogram", "mcbcHistogram", kTH1F, {axisBCext}); + histos.add("bcHistogram", "bcHistogram", kTH1F, {axisBCext}); + histos.add("mcbcModuloOrbitHistogram", "mcbcModuloOrbitHistogram", kTH1F, {axisBC}); + histos.add("bcModuloOrbitHistogram", "bcModuloOrbitHistogram", kTH1F, {axisBC}); + } + //----------------------------------------------------------------------------------------------------------------------- + void processSim(aod::UDMcCollision const& mcCollision, aod::UDMcParticles const& mcParticles) + { + // histos.fill(HIST("eventCounter"), 0.5); + + // auto massPion = 0.; + // TParticlePDG pionPDG = fPDG->GetParticle(codePion); + // massPion = pionPDG.Mass(); + // auto massKaon = 0.; + // TParticlePDG kaonPDG = fPDG->GetParticle(codeKaon); + // massKaon = kaonPDG.Mass(); + // auto massProton = 0.; + // TParticlePDG protonPDG = fPDG->GetParticle(codeProton); + // massProton = protonPDG.Mass(); + histos.fill(HIST("numberOfTracksMC"), mcParticles.size()); + histos.fill(HIST("eventCounter"), mcCollision.size()); + // LOGF(info, "New event! mcParticles.size() = %d", mcParticles.size()); + + int counterMC = 0; + int counter = 0; + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary()) + continue; + counterMC += 1; + // if(mcParticle.isPhysicalPrimary()) counterMC += 1; + LorentzVectorM protoMC( + mcParticle.px(), + mcParticle.py(), + mcParticle.pz(), + massPion); + double etaMax = 0.8; + double ptMin = 0.1; + if (std::fabs(protoMC.Eta()) < etaMax && protoMC.Pt() > ptMin) { + counter += 1; + } + if (!mcParticle.isPhysicalPrimary()) + continue; + // if(mcParticle.isPhysicalPrimary() && fabs(mcParticle.eta())<0.9){ // do this in the context of the MC loop ! (context matters!!!) + // LorentzVectorM pMC; + LorentzVectorM pMC(mcParticle.px(), mcParticle.py(), mcParticle.pz(), massPion); + if (std::abs(mcParticle.pdgCode()) == codePion) { + // histos.fill(HIST("ptGeneratedPion"), mcParticle.pt()); + // LorentzVectorM pMC(mcParticle.px(), mcParticle.py(), mcParticle.pz(), massPion); + histos.fill(HIST("ptGeneratedPion"), pMC.Pt()); + } + if (std::abs(mcParticle.pdgCode()) == codeKaon) { + // histos.fill(HIST("ptGenerateKaon"), mcParticle.pt()); + // LorentzVectorM pMC(mcParticle.px(), mcParticle.py(), mcParticle.pz(), massKaon); + pMC.SetM(massKaon); + histos.fill(HIST("ptGeneratedKaon"), pMC.Pt()); + } + if (std::abs(mcParticle.pdgCode()) == codeProton) { + // histos.fill(HIST("ptGeneratedProton"), mcParticle.pt()); + // LorentzVectorM pMC(mcParticle.px(), mcParticle.py(), mcParticle.pz(), massProton); + pMC.SetM(massProton); + histos.fill(HIST("ptGeneratedProton"), pMC.Pt()); + } + double yMax = 0.8; + if (std::abs(pMC.Rapidity()) < yMax) { + if (std::abs(mcParticle.pdgCode()) == codePion) + histos.fill(HIST("ptGeneratedPionAxE"), pMC.Pt()); + if (std::abs(mcParticle.pdgCode()) == codeKaon) + histos.fill(HIST("ptGeneratedKaonAxE"), pMC.Pt()); + if (std::abs(mcParticle.pdgCode()) == codeProton) + histos.fill(HIST("ptGeneratedProtonAxE"), pMC.Pt()); + if (mcParticle.pdgCode() == codeProton) { + histos.fill(HIST("ptGeneratedProtonAxEPos"), pMC.Pt()); + } else { + histos.fill(HIST("ptGeneratedProtonAxENeg"), pMC.Pt()); + } + } + } + histos.fill(HIST("hVisibleMultiVsGeneratedMulti"), counterMC, counter); + } + PROCESS_SWITCH(AnalysisMCDPMJetSGv3, processSim, "processSim", true); + + void processReco(CC const& collision, + TCs const& tracks, + // aod::UDMcCollisions const& /*mccollisions*/, + aod::UDMcParticles const& mcParticles) + { + histos.fill(HIST("numberOfRecoCollisions"), 88.); // number of times coll was reco-ed + histos.fill(HIST("numberOfRecoCollisions"), collision.size()); // number of times coll was reco-ed + histos.fill(HIST("numberOfRecoCollisions2"), mcParticles.size()); + Partition pvContributors = aod::udtrack::isPVContributor == true; + pvContributors.bindTable(tracks); + + // auto massPion = 0.; + // TParticlePDG pionPDG = fPDG->GetParticle(codePion); + // massPion = pionPDG.Mass(); + // auto massKaon = 0.; + // TParticlePDG kaonPDG = fPDG->GetParticle(codeKaon); + // massKaon = kaonPDG.Mass(); + // auto massProton = 0.; + // TParticlePDG protonPDG = fPDG->GetParticle(codeProton); + // massProton = protonPDG.Mass(); + + histos.fill(HIST("numberOfTracksReco"), tracks.size()); + // double etaMax = 0.8; + double yMax = 0.8; + double sigmaMax = 3.; + double ptMin = 0.1; + int nFindableMin = 70; + double dcaZlimit = 2.; + + // int counter = 0; + for (const auto& track : tracks) { + if (track.isPVContributor()) { + int nFindable = track.tpcNClsFindable(); + if (nFindable < nFindableMin) { + continue; + } + // int NMinusFound = track.tpcNClsFindableMinusFound(); + // int NCluster = NFindable - NMinusFound; + // if (NCluster < 70) { + // continue; + // } + if (track.pt() < ptMin) { + continue; + } + if (!(std::abs(track.dcaZ()) < dcaZlimit)) { + continue; + } + double dcaLimit = 0.0105 + 0.035 / std::pow(track.pt(), 1.1); + if (!(std::abs(track.dcaXY()) < dcaLimit)) { + continue; + } + + double momentum = std::sqrt(track.px() * track.px() + track.py() * track.py() + track.pz() * track.pz()); + double dEdx = track.tpcSignal(); + histos.fill(HIST("hdEdx"), momentum, dEdx); + + LorentzVectorM pion(track.px(), track.py(), track.pz(), o2::constants::physics::MassPionCharged); + LorentzVectorM kaon(track.px(), track.py(), track.pz(), o2::constants::physics::MassKaonCharged); + LorentzVectorM proton(track.px(), track.py(), track.pz(), o2::constants::physics::MassProton); + auto nSigmaPi = -999.; + auto nSigmaKa = -999.; + auto nSigmaPr = -999.; + auto nSigmaPiTOF = -999.; + auto nSigmaKaTOF = -999.; + auto nSigmaPrTOF = -999.; + // This section makes templates + if (track.hasTPC()) { + nSigmaPi = track.tpcNSigmaPi(); + nSigmaKa = track.tpcNSigmaKa(); + nSigmaPr = track.tpcNSigmaPr(); + if (std::abs(nSigmaPi) < sigmaMax && std::abs(pion.Rapidity()) < yMax) { + histos.fill(HIST("hSigmaPion"), track.pt(), nSigmaPi); + if (track.has_udMcParticle()) { + auto mcParticle = track.udMcParticle(); + // if(abs(mcParticle.pdgCode())==codePion && mcParticle.isPhysicalPrimary()) howManyPionsHavePionMCandPrimaries += 1; + if (std::abs(mcParticle.pdgCode()) == codePion) { + histos.fill(HIST("hSigmaPionTruth"), track.pt(), nSigmaPi); + histos.fill(HIST("allreconstructedPFPion"), track.pt()); + if (mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("ptReconstructedPion"), track.pt()); + } + } + } + } + if (std::abs(nSigmaKa) < sigmaMax && std::abs(kaon.Rapidity()) < yMax) { + histos.fill(HIST("hSigmaKaon"), track.pt(), nSigmaKa); + if (track.has_udMcParticle()) { + auto mcParticle = track.udMcParticle(); + if (std::abs(mcParticle.pdgCode()) == codeKaon) { + histos.fill(HIST("hSigmaKaonTruth"), track.pt(), nSigmaKa); + histos.fill(HIST("allreconstructedPFKaon"), track.pt()); + if (mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("ptReconstructedKaon"), track.pt()); + } + } + } + } + if (std::abs(nSigmaPr) < sigmaMax && std::abs(proton.Rapidity()) < yMax) { + histos.fill(HIST("hSigmaProton"), track.pt(), nSigmaPr); + if (track.has_udMcParticle()) { + auto mcParticle = track.udMcParticle(); + if (std::abs(mcParticle.pdgCode()) == codeProton) { + histos.fill(HIST("hSigmaProtonTruth"), track.pt(), nSigmaPr); + histos.fill(HIST("allreconstructedPFProton"), track.pt()); + if (mcParticle.pdgCode() == codeProton) { + histos.fill(HIST("allreconstructedPFProtonPos"), track.pt()); + } else { + histos.fill(HIST("allreconstructedPFProtonNeg"), track.pt()); + } + if (mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("ptReconstructedProton"), track.pt()); + if (mcParticle.pdgCode() == codeProton) { + histos.fill(HIST("ptReconstructedProtonPos"), track.pt()); + } else { + histos.fill(HIST("ptReconstructedProtonNeg"), track.pt()); + } + } + } + } + } + } + if (track.hasTPC() && track.hasTOF()) { + // if (track.hasTOF()) { + nSigmaPiTOF = track.tofNSigmaPi(); + nSigmaKaTOF = track.tofNSigmaKa(); + nSigmaPrTOF = track.tofNSigmaPr(); + if (std::abs(nSigmaPiTOF) < sigmaMax && std::abs(pion.Rapidity()) < yMax) { + histos.fill(HIST("hSigmaPionTOF"), track.pt(), nSigmaPiTOF); + if (track.has_udMcParticle()) { + auto mcParticle = track.udMcParticle(); + // if(abs(mcParticle.pdgCode())==codePion && mcParticle.isPhysicalPrimary()) howManyPionsHavePionMCandPrimaries += 1; + if (std::abs(mcParticle.pdgCode()) == codePion) { + histos.fill(HIST("hSigmaPionTruthTOF"), track.pt(), nSigmaPiTOF); + histos.fill(HIST("allreconstructedPFPionTOF"), track.pt()); + if (mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("ptReconstructedPionTOF"), track.pt()); + } + } + } + } + if (std::abs(nSigmaKaTOF) < sigmaMax && std::abs(kaon.Rapidity()) < yMax) { + histos.fill(HIST("hSigmaKaonTOF"), track.pt(), nSigmaKaTOF); + if (track.has_udMcParticle()) { + auto mcParticle = track.udMcParticle(); + if (std::abs(mcParticle.pdgCode()) == codeKaon) { + histos.fill(HIST("hSigmaKaonTruthTOF"), track.pt(), nSigmaKaTOF); + histos.fill(HIST("allreconstructedPFKaonTOF"), track.pt()); + if (mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("ptReconstructedKaonTOF"), track.pt()); + } + } + } + } + if (std::abs(nSigmaPrTOF) < sigmaMax && std::abs(proton.Rapidity()) < yMax) { + histos.fill(HIST("hSigmaProtonTOF"), track.pt(), nSigmaPrTOF); + if (track.has_udMcParticle()) { + auto mcParticle = track.udMcParticle(); + if (std::abs(mcParticle.pdgCode()) == codeProton) { + histos.fill(HIST("hSigmaProtonTruthTOF"), track.pt(), nSigmaPrTOF); + histos.fill(HIST("allreconstructedPFProtonTOF"), track.pt()); + if (mcParticle.isPhysicalPrimary()) { + histos.fill(HIST("ptReconstructedProtonTOF"), track.pt()); + } + } + } + } + } + // counter++; + // histos.fill(HIST("hVisibleMultiVsGeneratedMulti"), counterMC, counter); + // histos.fill(HIST("hVisibleMultiVsGeneratedMulti"), mcParticles.size(), counter); + } + } // track loop + + // } // collision loop + } + PROCESS_SWITCH(AnalysisMCDPMJetSGv3, processReco, "processReco", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} 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..d7283115434 100644 --- a/PWGUD/Tasks/dgCandAnalyzer.cxx +++ b/PWGUD/Tasks/dgCandAnalyzer.cxx @@ -13,18 +13,19 @@ // \author Paul Buehler, paul.buehler@oeaw.ac.at // \since 06.06.2022 -#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" +#include "PWGUD/Core/DGPIDSelector.h" +#include "PWGUD/Core/UDGoodRunSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/UDTables.h" #include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPLHCIFData.h" #include "CommonConstants/LHCConstants.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGUD/DataModel/UDTables.h" -#include "PWGUD/Core/UDHelpers.h" -#include "PWGUD/Core/DGPIDSelector.h" -#include "PWGUD/Core/UDGoodRunSelector.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include +#include using namespace o2; using namespace o2::framework; @@ -217,7 +218,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 +278,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..072ae2d961c --- /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 +#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 index 95da9600f67..eb5170bb400 100644 --- a/PWGUD/Tasks/exclusivePentaquark.cxx +++ b/PWGUD/Tasks/exclusivePentaquark.cxx @@ -8,15 +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. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "iostream" +#include "PWGUD/Core/SGSelector.h" #include "PWGUD/DataModel/UDTables.h" -#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGUD/Core/SGSelector.h" +#include + +#include using std::array; using namespace std; using namespace o2; diff --git a/PWGUD/Tasks/exclusivePhi.cxx b/PWGUD/Tasks/exclusivePhi.cxx index eed29b6fdfc..c0850b4b84d 100644 --- a/PWGUD/Tasks/exclusivePhi.cxx +++ b/PWGUD/Tasks/exclusivePhi.cxx @@ -9,14 +9,17 @@ // 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 "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" -#include "Common/DataModel/PIDResponse.h" +#include + +#include +#include using std::array; using namespace std; @@ -626,7 +629,7 @@ struct ExclusivePhi { // auto ksize = allTracksAreITSonlyAndFourITSclusters.size(); registry.fill(HIST("hTracksITSonly"), allTracksAreITSonlyAndFourITSclusters.size()); - for (int kaon = 0; kaon < allTracksAreITSonlyAndFourITSclusters.size(); kaon++) { + for (std::size_t kaon = 0; kaon < allTracksAreITSonlyAndFourITSclusters.size(); kaon++) { int clusterSize[7]; double averageClusterSize = 0.; @@ -647,7 +650,7 @@ struct ExclusivePhi { } } } // Kaon Band - } // end of process + } // end of process }; // end of struct diff --git a/PWGUD/Tasks/exclusivePhiLeptons.cxx b/PWGUD/Tasks/exclusivePhiLeptons.cxx index 136d9a789f2..cb2d8834862 100644 --- a/PWGUD/Tasks/exclusivePhiLeptons.cxx +++ b/PWGUD/Tasks/exclusivePhiLeptons.cxx @@ -8,15 +8,18 @@ // In applying this license CERN does 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/Core/SGSelector.h" #include "PWGUD/DataModel/UDTables.h" -#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGUD/Core/SGSelector.h" +#include + +#include +#include using std::array; using namespace std; using namespace o2; @@ -37,7 +40,7 @@ struct ExclusivePhiLeptons { 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"}; + Configurable electronsInTOF{"eTOF", 2, "electrons in TOF"}; // defining histograms using histogram registry HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; diff --git a/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx b/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx new file mode 100644 index 00000000000..ecc65174f26 --- /dev/null +++ b/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx @@ -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. +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "TLorentzVector.h" +#include + +#include +#include +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..8cefae2262c --- /dev/null +++ b/PWGUD/Tasks/exclusiveRhoTo4Pi.cxx @@ -0,0 +1,1473 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TPDGCode.h" +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using PtEtaPhiMVector = ROOT::Math::PtEtaPhiMVector; +using Boost = ROOT::Math::Boost; +using XYZVectorF = ROOT::Math::XYZVectorF; +using PxPyPzEVector = ROOT::Math::PxPyPzEVector; +using PxPyPzMVector = ROOT::Math::PxPyPzMVector; + +struct ExclusiveRhoTo4Pi { + SGSelector sgSelector; + // Numbers for background estimation + int zero = 0; + int one = 1; + int two = 2; + int three = 3; + int four = 4; + // PDG Codes and rho mass + double mRho0 = 0.77526; // GeV/c^2 + int rhoPrime = 30113; + // Pb-Pb at 5.36 TeV + double halfSqrtSnn = 2680.; + double massOfLead208 = 193.6823; + double momentumBeam = std::sqrt(halfSqrtSnn * halfSqrtSnn * 208 * 208 - massOfLead208 * massOfLead208); + // Run Numbers + static int runNos[113]; + static int numRunNums; + // Histogram Registry + HistogramRegistry histosDataCounter{"Counters", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosQA{"QA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosPID{"PID", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosKin{"Kinematics", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histos4piKin{"Four-Pion-Kinematics", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry histosMCtruth{"MC-Truth", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // Debugging + Configurable debugMode{"debugMode", false, "Enable Debug Mode"}; + // Configurable Event parameters + Configurable ifUPC{"ifUPC", 1, "Enable UPC reconstruction only"}; + Configurable vZCut{"vZCut", 10., "Vertex Cut"}; + Configurable fv0Cut{"fv0Cut", 50., "FV0A threshold"}; + Configurable ft0aCut{"ft0aCut", 50., "FT0A threshold"}; + Configurable ft0cCut{"ft0cCut", 50., "FT0C threshold"}; + Configurable zdcMaxAmp{"zdcMaxAmp", 0, "ZDC max amplitude to be 0n"}; + Configurable zdcMaxTime{"zdcMaxTime", 2, "ZDC max time in ns"}; + Configurable maxNpvContrib{"maxNpvContrib", 4, "Max Number of PV Contributors (Must be > 4)"}; + Configurable sbpCut{"sbpCut", 1, "Sbp"}; + Configurable itsROFbCut{"itsROFbCut", 1, "itsROFbCut"}; + Configurable vtxITSTPCcut{"vtxITSTPCcut", 1, "vtxITSTPCcut"}; + Configurable tfbCut{"tfbCut", 1, "tfbCut"}; + // Configurable Track parameters + Configurable useOnlyPVtracks{"useOnlyPVtracks", true, "Use Only PV tracks"}; + Configurable pTcut{"pTcut", 0.15, "Track Pt"}; + Configurable etaCut{"etaCut", 0.9, "Track Pseudorapidity"}; + Configurable dcaXYcut{"dcaXYcut", 0, "dcaXY cut"}; + Configurable dcaZcut{"dcaZcut", 2, "dcaZ cut"}; + Configurable useITStracksOnly{"useITStracksOnly", true, "only use tracks with hit in ITS"}; + Configurable useTPCtracksOnly{"useTPCtracksOnly", true, "only use tracks with hit in TPC"}; + Configurable itsChi2NClsCut{"itsChi2NClsCut", 36, "ITS Chi2NCls"}; + Configurable tpcChi2NClsCut{"tpcChi2NClsCut", 4.0, "TPC Chi2NCls"}; + Configurable tpcNClsCrossedRowsCut{"tpcNClsCrossedRowsCut", 70, "Min TPC Findable Clusters"}; + // Configurable PID parameters + Configurable ifCircularNSigmaCut{"ifCircularNSigmaCut", true, "Use circular nsigma cut for PID"}; + Configurable useTOF{"useTOF", true, "if track has TOF use TOF"}; + Configurable nSigmaTPCcut{"nSigmaTPCcut", 5, "TPC cut"}; + Configurable nSigmaTOFcut{"nSigmaTOFcut", 5, "TOF cut"}; + // Axis Configurations + ConfigurableAxis pTAxis{"pTAxis", {1000, 0, 1}, "Axis for pT histograms"}; + ConfigurableAxis etaAxis{"etaAxis", {1000, -1.1, 1.1}, "Axis for Eta histograms"}; + ConfigurableAxis rapidityAxis{"rapidityAxis", {1000, -2.5, 2.5}, "Axis for Rapidity histograms"}; + ConfigurableAxis invMassAxis{"invMassAxis", {1000, 1, 2.5}, "Axis for Phi histograms"}; + ConfigurableAxis phiAxis{"phiAxis", {360, -1 * o2::constants::math::PI, o2::constants::math::PI}, "Axis for Phi histograms"}; + ConfigurableAxis cosThetaAxis{"cosThetaAxis", {360, -1, 1}, "Axis for cos Theta histograms"}; + // Fine Axis Specs + AxisSpec neutronClassAxis = {5, 0, 5}; + AxisSpec runNumberAxis = {113, 0, 113}; + AxisSpec fitAxis = {500, -10, 200}; + AxisSpec dcaAxis = {2000, -0.15, 0.15}; + AxisSpec nSigmaAxis = {1000, -15, 12}; + AxisSpec piPtAxis = {1000, 0, 10}; + AxisSpec pvContributorAxis = {50, 0, 50}; + + void init(InitContext const&) + { + // QA plots: Event and Track Counter + histosDataCounter.add("EventsCounts_vs_runNo", "Event Counter Run by Run; Run Number; Number of Events", kTH2F, {runNumberAxis, {14, 0, 14}}); + histosDataCounter.add("TracksCounts_vs_runNo", "Track Counter Run by Run; Run Number; Number of Track", kTH2F, {runNumberAxis, {13, 0, 13}}); + // QA plots: all events + histosQA.add("Events/all/UPCmode", "UPC mode; Events", kTH1F, {{5, 0, 5}}); + histosQA.add("Events/all/GapSide", "Gap Side;Gap Side; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/all/TrueGapSide", "True Gap Side; True Gap Side; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/all/isCBTOk", "isCBTOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/all/isCBTHadronOk", "isCBTHadronOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/all/isCBTZdcOk", "isCBTZdcOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/all/isCBTHadronZdcOk", "isCBTHadronZdcOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/all/FT0A", "T0A amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/all/FT0C", "T0C amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/all/FV0A", "V0A amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/all/ZDC", ";ZDC A;ZDC C;time ZDC A [ns];time ZDC C [ns]", kTHnSparseF, {{200, -10, 1000}, {200, -10, 1000}, {400, -10, 50}, {400, -10, 10}}); + histosQA.add("Events/all/FDDA", "FDD A signal; FDD A signal; Events", kTH1F, {{500, 0.0, 2000}}); + histosQA.add("Events/all/FDDC", "FDD C signal; FDD C signal; Events", kTH1F, {{500, 0.0, 2000}}); + histosQA.add("Events/all/vertexX", "Vertex X; Vertex X [cm]; Events", kTH1F, {{1000, -0.04, -0.015}}); + histosQA.add("Events/all/vertexY", "Vertex Y; Vertex Y [cm]; Events", kTH1F, {{1000, -0.02, 0.02}}); + histosQA.add("Events/all/vertexZ", "Vertex Z; Vertex Z [cm]; Events", kTH1F, {{1000, -11, 11}}); + histosQA.add("Events/all/occupancy", "Occupancy; Occupancy; Events", kTH1F, {{20000, 0, 20000}}); + histosQA.add("Events/all/nPVContributors", "Number of PV Contributors; Number of PV Contributors; Events", kTH1F, {pvContributorAxis}); + // QA plots: event selection-selected events + histosQA.add("Events/selected/UPCmode", "UPC mode; Events", kTH1F, {{5, 0, 5}}); + histosQA.add("Events/selected/GapSide", "Gap Side;Gap Side; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/selected/TrueGapSide", "True Gap Side; True Gap Side; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/selected/isCBTOk", "isCBTOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/selected/isCBTHadronOk", "isCBTHadronOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/selected/isCBTZdcOk", "isCBTZdcOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/selected/isCBTHadronZdcOk", "isCBTHadronZdcOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/selected/FT0A", "T0A amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/selected/FT0C", "T0C amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/selected/FV0A", "V0A amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/selected/ZDC", ";ZDC A;ZDC C;time ZDC A [ns];time ZDC C [ns]", kTHnSparseF, {{200, -10, 1000}, {200, -10, 1000}, {400, -10, 50}, {400, -10, 10}}); + histosQA.add("Events/selected/FDDA", "FDD A signal; FDD A signal; Events", kTH1F, {{500, 0.0, 2000}}); + histosQA.add("Events/selected/FDDC", "FDD C signal; FDD C signal; Events", kTH1F, {{500, 0.0, 2000}}); + histosQA.add("Events/selected/vertexX", "Vertex X; Vertex X [cm]; Events", kTH1F, {{1000, -0.04, -0.015}}); + histosQA.add("Events/selected/vertexY", "Vertex Y; Vertex Y [cm]; Events", kTH1F, {{1000, -0.02, 0.02}}); + histosQA.add("Events/selected/vertexZ", "Vertex Z; Vertex Z [cm]; Events", kTH1F, {{1000, -11, 11}}); + histosQA.add("Events/selected/occupancy", "Occupancy; Occupancy; Events", kTH1F, {{20000, 0, 20000}}); + histosQA.add("Events/selected/nPVContributors", "Number of PV Contributors; Number of PV Contributors; Events", kTH1F, {pvContributorAxis}); + // QA plots: event selection-4 pion events + histosQA.add("Events/4pion/UPCmode", "UPC mode; Events", kTH1F, {{5, 0, 5}}); + histosQA.add("Events/4pion/GapSide", "Gap Side;Gap Side; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/4pion/TrueGapSide", "True Gap Side; True Gap Side; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/4pion/isCBTOk", "isCBTOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/4pion/isCBTHadronOk", "isCBTHadronOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/4pion/isCBTZdcOk", "isCBTZdcOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/4pion/isCBTHadronZdcOk", "isCBTHadronZdcOk; bool; Events", kTH1F, {{4, 0, 4}}); + histosQA.add("Events/4pion/FT0A", "T0A amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/4pion/FT0C", "T0C amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/4pion/FV0A", "V0A amplitude", kTH1F, {fitAxis}); + histosQA.add("Events/4pion/ZDC", "; ZDC A; ZDC C; time ZDC A; time ZDC C", kTHnSparseF, {{200, -10, 1000}, {200, -10, 1000}, {400, -10, 50}, {400, -10, 10}}); + histosQA.add("Events/4pion/FDDA", "FDD A signal; FDD A signal; Events", kTH1F, {{500, 0.0, 2000}}); + histosQA.add("Events/4pion/FDDC", "FDD C signal; FDD C signal; Events", kTH1F, {{500, 0.0, 2000}}); + histosQA.add("Events/4pion/vertexX", "Vertex X; Vertex X [cm]; Events", kTH1F, {{2000, -0.04, -0.015}}); + histosQA.add("Events/4pion/vertexY", "Vertex Y; Vertex Y [cm]; Events", kTH1F, {{2000, -0.02, 0.02}}); + histosQA.add("Events/4pion/vertexZ", "Vertex Z; Vertex Z [cm]; Events", kTH1F, {{1000, -11, 11}}); + histosQA.add("Events/4pion/occupancy", "Occupancy; Occupancy; Events", kTH1F, {{20000, 0, 20000}}); + histosQA.add("Events/4pion/nPVContributors", "Number of PV Contributors; Number of PV Contributors; Events", kTH1F, {pvContributorAxis}); + // QA plots: All tracks in selected events + histosQA.add("Tracks/all/isPVcontributor", "isPVcontributor; True or not; Counts", kTH1F, {{3, 0, 3}}); + histosQA.add("Tracks/all/dcaXY", "dcaXY; dcaXY [cm]; Counts", kTH1F, {dcaAxis}); + histosQA.add("Tracks/all/dcaZ", "dcaZ; dcaZ [cm]; Counts", kTH1F, {dcaAxis}); + histosQA.add("Tracks/all/itsChi2NCl", "ITS Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{500, 0, 50}}); + histosQA.add("Tracks/all/itsChi2", "ITS Chi2; ITS Chi2; Counts", kTH1F, {{500, 0, 50}}); + histosQA.add("Tracks/all/tpcChi2NCl", "TPC Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{250, 0, 10}}); + histosQA.add("Tracks/all/tpcNClsCrossedRows", "TPC N Cls Findable; N Cls Findable; Counts", kTH1F, {{360, 0, 180}}); + // QA plots: Selected tracks in selected events + histosQA.add("Tracks/selected/isPVcontributor", "isPVcontributor; True or not; Counts", kTH1F, {{3, 0, 3}}); + histosQA.add("Tracks/selected/dcaXY", "dcaXY; dcaXY [cm]; Counts", kTH1F, {dcaAxis}); + histosQA.add("Tracks/selected/dcaZ", "dcaZ; dcaZ [cm]; Counts", kTH1F, {dcaAxis}); + histosQA.add("Tracks/selected/itsChi2NCl", "ITS Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{500, 0, 50}}); + histosQA.add("Tracks/selected/itsChi2", "ITS Chi2; ITS Chi2; Counts", kTH1F, {{500, 0, 50}}); + histosQA.add("Tracks/selected/tpcChi2NCl", "TPC Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{250, 0, 50}}); + histosQA.add("Tracks/selected/tpcNClsCrossedRows", "TPC N Cls Findable; N Cls Findable; Counts", kTH1F, {{360, 0, 180}}); + // QA plots: Pion tracks in selected events + histosQA.add("Tracks/pions/isPVcontributor", "isPVcontributor; True or not; Counts", kTH1F, {{3, 0, 3}}); + histosQA.add("Tracks/pions/dcaXY", "dcaXY; dcaXY [cm]; Counts", kTH1F, {dcaAxis}); + histosQA.add("Tracks/pions/dcaZ", "dcaZ; dcaZ [cm]; Counts", kTH1F, {dcaAxis}); + histosQA.add("Tracks/pions/itsChi2NCl", "ITS Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{250, 0, 50}}); + histosQA.add("Tracks/pions/itsChi2", "ITS Chi2; ITS Chi2; Counts", kTH1F, {{500, 0, 50}}); + histosQA.add("Tracks/pions/tpcChi2NCl", "TPC Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{250, 0, 50}}); + histosQA.add("Tracks/pions/tpcNClsCrossedRows", "TPC N Cls Findable; N Cls Findable; Counts", kTH1F, {{360, 0, 180}}); + // QA plots: Pion tracks from 4pi in selected events + histosQA.add("Tracks/pions-from-4pi/isPVcontributor", "isPVcontributor; True or not; Counts", kTH1F, {{3, 0, 3}}); + histosQA.add("Tracks/pions-from-4pi/dcaXY", "dcaXY; dcaXY [cm]; Counts", kTH1F, {dcaAxis}); + histosQA.add("Tracks/pions-from-4pi/dcaZ", "dcaZ; dcaZ [cm]; Counts", kTH1F, {dcaAxis}); + histosQA.add("Tracks/pions-from-4pi/itsChi2NCl", "ITS Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{250, 0, 50}}); + histosQA.add("Tracks/pions-from-4pi/itsChi2", "ITS Chi2; ITS Chi2; Counts", kTH1F, {{500, 0, 50}}); + histosQA.add("Tracks/pions-from-4pi/tpcChi2NCl", "TPC Chi2/NCl; Chi2/NCl; Counts", kTH1F, {{250, 0, 50}}); + histosQA.add("Tracks/pions-from-4pi/tpcNClsCrossedRows", "TPC N Cls Findable; N Cls Findable; Counts", kTH1F, {{360, 0, 180}}); + // QA plots: PID- All tracks + histosPID.add("all/tpcSignal", "TPC dEdx vs p; p [GeV/c]; dEdx [a.u.]", kTH2F, {{500, 0, 3}, {5000, 0.0, 600}}); + histosPID.add("all/tpcNSigmaPi", "TPC nSigma Pion for all tracks in selected events; Events", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tpcNSigmaKa", "TPC nSigma Kaon for all tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tpcNSigmaPr", "TPC nSigma Proton for all tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tpcNSigmaEl", "TPC nSigma Electron for all tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tpcNSigmaMu", "TPC nSigma Muon for all tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tofBeta", "TOF beta vs p ; p [GeV/c]; #beta", kTH2F, {{500, 0, 10}, {1500, 0.0, 1.5}}); + histosPID.add("all/tofNSigmaPi", "TOF nSigma Pion for all tracks in selected events; Events", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tofNSigmaKa", "TOF nSigma Kaon for all tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tofNSigmaPr", "TOF nSigma Proton for all tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tofNSigmaEl", "TOF nSigma Electron for all tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("all/tofNSigmaMu", "TOF nSigma Muon for all tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + // QA plots: PID- Selected tracks + histosPID.add("selected/tpcSignal", "TPC dEdx vs p; p [GeV/c]; dEdx [a.u.]", kTH2F, {{500, 0, 3}, {5000, 0.0, 600.0}}); + histosPID.add("selected/tpcNSigmaPi", "TPC nSigma Pion for all selected tracks in selected events; Events", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tpcNSigmaKa", "TPC nSigma Kaon for all selected tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tpcNSigmaPr", "TPC nSigma Proton for all selected tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tpcNSigmaEl", "TPC nSigma Electron for all selected tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tpcNSigmaMu", "TPC nSigma Muon for all selected tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tofBeta", "TOF beta vs p; p [GeV/c]; #beta", kTH2F, {{500, 0, 2}, {1500, 0.0, 1.5}}); + histosPID.add("selected/tofNSigmaPi", "TOF nSigma Pion for all selected tracks in selected events; Events", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tofNSigmaKa", "TOF nSigma Kaon for all selected tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tofNSigmaPr", "TOF nSigma Proton for all selected tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tofNSigmaEl", "TOF nSigma Electron for all selected tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("selected/tofNSigmaMu", "TOF nSigma Muon for all selected tracks in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + // QA plots: PID- Pion tracks + histosPID.add("pions/tpcSignal", "TPC dEdx vs p; p [GeV/c]; dEdx [a.u.]", kTH2F, {{500, 0, 3}, {5000, 0.0, 600.0}}); + histosPID.add("pions/tpcNSigmaPi", "TPC nSigma Pion for all selected pions in selected events; Events", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tpcNSigmaKa", "TPC nSigma Kaon for all selected pions in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tpcNSigmaPr", "TPC nSigma Proton for all selected pions in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tpcNSigmaEl", "TPC nSigma Electron for all selected pions in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tpcNSigmaMu", "TPC nSigma Muon for all selected pions in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tofBeta", "TOF beta vs p; p [GeV/c]; #beta", kTH2F, {{500, 0, 10}, {1500, 0.0, 1.5}}); + histosPID.add("pions/tofNSigmaPi", "TOF nSigma Pion for all selected pions in selected events; Events", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tofNSigmaKa", "TOF nSigma Kaon for all selected pions in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tofNSigmaPr", "TOF nSigma Proton for all selected pions in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tofNSigmaEl", "TOF nSigma Electron for all selected pions in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions/tofNSigmaMu", "TOF nSigma Muon for all selected pions in selected events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + // QA plots: PID- Pion tracks from 4pi events + histosPID.add("pions-from-4pi/tpcSignal", "TPC dEdx vs p; p [GeV/c]; dEdx [a.u.]", kTH2F, {{500, 0, 3}, {5000, 0.0, 600.0}}); + histosPID.add("pions-from-4pi/tpcNSigmaPi", "TPC nSigma Pion for all pions from 4-pi events; Events", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tpcNSigmaKa", "TPC nSigma Kaon for all pions from 4-pi events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tpcNSigmaPr", "TPC nSigma Proton for all pions from 4-pi events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tpcNSigmaEl", "TPC nSigma Electron for all pions from 4-pi events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tpcNSigmaMu", "TPC nSigma Muon for all pions from 4-pi events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tofBeta", "TOF beta vs p; p [GeV/c]; #beta", kTH2F, {{500, 0, 10}, {1500, 0.0, 1.5}}); + histosPID.add("pions-from-4pi/tofNSigmaPi", "TOF nSigma Pion for all pions from 4-pi events; Events", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tofNSigmaKa", "TOF nSigma Kaon for all pions from 4-pi eventsn; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tofNSigmaPr", "TOF nSigma Proton for all pions from 4-pi events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tofNSigmaEl", "TOF nSigma Electron for all pions from 4-pi events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + histosPID.add("pions-from-4pi/tofNSigmaMu", "TOF nSigma for all pions from 4-pi events; Entries", kTH2F, {nSigmaAxis, piPtAxis}); + // Kinematics for all particles + histosKin.add("all", ";pT [GeV/c]; #eta;#varphi", kTH3F, {pTAxis, etaAxis, phiAxis}); + histosKin.add("selected", ";pT [GeV/c]; #eta;#varphi", kTH3F, {pTAxis, etaAxis, phiAxis}); + histosKin.add("pions", ";pT [GeV/c]; #eta;#varphi", kTH3F, {pTAxis, etaAxis, phiAxis}); + histosKin.add("pions-from-4pion", ";pT [GeV/c]; #eta;#varphi;y ", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis}); + // Rho Prime Kinematics + histos4piKin.add("two-pion", ";p_{T}^{4#pi} [GeV/c] ;m_{#pi^{+}#pi^{-}} [GeV/c^2];m_{#pi^{+}#pi^{-}} [GeV/c^2];m_{#pi^{+}#pi^{-}} [GeV/c^2];m_{#pi^{+}#pi^{-}} [GeV/c^2];m_{4#pi} [GeV/c^{2}]", kTHnSparseF, {{100, 0, 2}, {100, 0, 2}, {100, 0, 2}, {100, 0, 2}, invMassAxis}); + histos4piKin.add("zero-charge", ";pT [GeV/c]; #eta; #varphi [rad];y; m_{4#pi} [GeV/c^{2}]; Collin-Soper cos(#theta); Collin-Soper #varphi [rad];Run Number; Neutron Class", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis, invMassAxis, cosThetaAxis, phiAxis, runNumberAxis, neutronClassAxis}); + histos4piKin.add("non-zero-charge", ";pT [GeV/c]; #eta; #varphi [rad];y; m_{4#pi} [GeV/c^{2}];Run Number; Neutron Class", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis, invMassAxis, runNumberAxis, neutronClassAxis}); + histos4piKin.add("3piMinus-1piPlus", ";pT [GeV/c]; #eta; #varphi [rad];y; m_{4#pi} [GeV/c^{2}]; Run Number; Neutron Class", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis, invMassAxis, runNumberAxis, neutronClassAxis}); + histos4piKin.add("3piPlus-1piMinus", ";pT [GeV/c]; #eta; #varphi [rad];y; m_{4#pi} [GeV/c^{2}]; Run Number; Neutron Class", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis, invMassAxis, runNumberAxis, neutronClassAxis}); + histos4piKin.add("4piPlus", ";pT [GeV/c]; #eta; #varphi [rad];y; m_{4#pi} [GeV/c^{2}]; Run Number; Neutron Class", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis, invMassAxis, runNumberAxis, neutronClassAxis}); + histos4piKin.add("4piMinus", ";pT [GeV/c]; #eta; #varphi [rad];y; m_{4#pi} [GeV/c^{2}]; Run Number; Neutron Class", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis, invMassAxis, runNumberAxis, neutronClassAxis}); + // MC truth + histosMCtruth.add("4-pi-pions", ";pT [GeV/c]; #eta;#varphi;y ", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis, runNumberAxis}); + histosMCtruth.add("Four-pion", ";pT [GeV/c]; #eta; #varphi [rad];y; m_{4#pi} [GeV/c^{2}];Run Number", kTHnSparseF, {pTAxis, etaAxis, phiAxis, rapidityAxis, invMassAxis, runNumberAxis}); + //_______________________________________________________________________________________________________________________________________________ + setHistBinLabels(); + if (debugMode) { + histosDataCounter.print(); + histosQA.print(); + histosPID.print(); + histosKin.print(); + histos4piKin.print(); + histosMCtruth.print(); + } + } // End of init function + + using UDtracks = soa::Join; + using UDCollisions = soa::Join; + + void processData(UDCollisions::iterator const& collision, UDtracks const& tracks) + { + + int runIndex = getRunNumberIndex(collision.runNumber()); + int neutClass = getNeutronClass(collision); + + histosQA.fill(HIST("Events/all/UPCmode"), collision.flags()); + histosQA.fill(HIST("Events/all/GapSide"), collision.gapSide()); + histosQA.fill(HIST("Events/all/TrueGapSide"), sgSelector.trueGap(collision, fv0Cut, ft0aCut, ft0cCut, 1e6)); + histosQA.fill(HIST("Events/all/isCBTOk"), sgSelector.isCBTOk(collision)); + histosQA.fill(HIST("Events/all/isCBTHadronOk"), sgSelector.isCBTHadronOk(collision)); + histosQA.fill(HIST("Events/all/isCBTZdcOk"), sgSelector.isCBTZdcOk(collision)); + histosQA.fill(HIST("Events/all/isCBTHadronZdcOk"), sgSelector.isCBTHadronZdcOk(collision)); + histosQA.fill(HIST("Events/all/vertexX"), collision.posX()); + histosQA.fill(HIST("Events/all/vertexY"), collision.posY()); + histosQA.fill(HIST("Events/all/vertexZ"), collision.posZ()); + histosQA.fill(HIST("Events/all/occupancy"), collision.occupancyInTime()); + histosQA.fill(HIST("Events/all/FV0A"), collision.totalFV0AmplitudeA()); + histosQA.fill(HIST("Events/all/FT0A"), collision.totalFT0AmplitudeA()); + histosQA.fill(HIST("Events/all/FT0C"), collision.totalFT0AmplitudeC()); + histosQA.fill(HIST("Events/all/ZDC"), collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC()); + histosQA.fill(HIST("Events/all/FDDA"), collision.totalFDDAmplitudeA()); + histosQA.fill(HIST("Events/all/FDDC"), collision.totalFDDAmplitudeC()); + histosQA.fill(HIST("Events/all/nPVContributors"), collision.numContrib()); + + if (!isGoodEvent(collision)) { + return; + } + + histosQA.fill(HIST("Events/selected/UPCmode"), collision.flags()); + histosQA.fill(HIST("Events/selected/GapSide"), collision.gapSide()); + histosQA.fill(HIST("Events/selected/TrueGapSide"), sgSelector.trueGap(collision, fv0Cut, ft0aCut, ft0cCut, 1e6)); + histosQA.fill(HIST("Events/selected/isCBTOk"), sgSelector.isCBTOk(collision)); + histosQA.fill(HIST("Events/selected/isCBTHadronOk"), sgSelector.isCBTHadronOk(collision)); + histosQA.fill(HIST("Events/selected/isCBTZdcOk"), sgSelector.isCBTZdcOk(collision)); + histosQA.fill(HIST("Events/selected/isCBTHadronZdcOk"), sgSelector.isCBTHadronZdcOk(collision)); + histosQA.fill(HIST("Events/selected/vertexX"), collision.posX()); + histosQA.fill(HIST("Events/selected/vertexY"), collision.posY()); + histosQA.fill(HIST("Events/selected/vertexZ"), collision.posZ()); + histosQA.fill(HIST("Events/selected/occupancy"), collision.occupancyInTime()); + histosQA.fill(HIST("Events/selected/FV0A"), collision.totalFV0AmplitudeA()); + histosQA.fill(HIST("Events/selected/FT0A"), collision.totalFT0AmplitudeA()); + histosQA.fill(HIST("Events/selected/FT0C"), collision.totalFT0AmplitudeC()); + histosQA.fill(HIST("Events/selected/ZDC"), collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC()); + histosQA.fill(HIST("Events/selected/FDDA"), collision.totalFDDAmplitudeA()); + histosQA.fill(HIST("Events/selected/FDDC"), collision.totalFDDAmplitudeC()); + histosQA.fill(HIST("Events/selected/nPVContributors"), collision.numContrib()); + + std::vector selectedPionTracks; + std::vector selectedPionPlusTracks; + std::vector selectedPionMinusTracks; + + for (const auto& t0 : tracks) { + + PxPyPzMVector tVector(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassPionCharged); + + // QA-Tracks before selection + histosQA.fill(HIST("Tracks/all/isPVcontributor"), t0.isPVContributor()); + histosQA.fill(HIST("Tracks/all/dcaXY"), t0.dcaXY()); + histosQA.fill(HIST("Tracks/all/dcaZ"), t0.dcaZ()); + histosQA.fill(HIST("Tracks/all/itsChi2NCl"), t0.itsChi2NCl()); + histosQA.fill(HIST("Tracks/all/itsChi2"), t0.itsChi2NCl() * t0.itsNCls()); + histosQA.fill(HIST("Tracks/all/tpcChi2NCl"), t0.tpcChi2NCl()); + histosQA.fill(HIST("Tracks/all/tpcNClsCrossedRows"), t0.tpcNClsCrossedRows()); + + // PID before track selection + histosPID.fill(HIST("all/tpcSignal"), tVector.P(), t0.tpcSignal()); + histosPID.fill(HIST("all/tpcNSigmaPi"), t0.tpcNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("all/tpcNSigmaKa"), t0.tpcNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("all/tpcNSigmaPr"), t0.tpcNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("all/tpcNSigmaEl"), t0.tpcNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("all/tpcNSigmaMu"), t0.tpcNSigmaMu(), tVector.Pt()); + histosPID.fill(HIST("all/tofBeta"), tVector.P(), t0.beta()); + histosPID.fill(HIST("all/tofNSigmaPi"), t0.tofNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("all/tofNSigmaKa"), t0.tofNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("all/tofNSigmaPr"), t0.tofNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("all/tofNSigmaEl"), t0.tofNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("all/tofNSigmaMu"), t0.tofNSigmaMu(), tVector.Pt()); + + // Kinematics for all particles before selection + histosKin.fill(HIST("all"), tVector.Pt(), tVector.Eta(), tVector.Phi()); + + // Selecting good tracks + if (!isGoodTrack(t0)) { + continue; + } + + // QA-Tracks after selection + histosQA.fill(HIST("Tracks/selected/isPVcontributor"), t0.isPVContributor()); + histosQA.fill(HIST("Tracks/selected/dcaXY"), t0.dcaXY()); + histosQA.fill(HIST("Tracks/selected/dcaZ"), t0.dcaZ()); + histosQA.fill(HIST("Tracks/selected/itsChi2NCl"), t0.itsChi2NCl()); + histosQA.fill(HIST("Tracks/selected/itsChi2"), t0.itsChi2NCl() * t0.itsNCls()); + histosQA.fill(HIST("Tracks/selected/tpcChi2NCl"), t0.tpcChi2NCl()); + histosQA.fill(HIST("Tracks/selected/tpcNClsCrossedRows"), t0.tpcNClsCrossedRows()); + + // PID after track selection before selecting pions + histosPID.fill(HIST("selected/tpcSignal"), tVector.P(), t0.tpcSignal()); + histosPID.fill(HIST("selected/tpcNSigmaPi"), t0.tpcNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("selected/tpcNSigmaKa"), t0.tpcNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("selected/tpcNSigmaPr"), t0.tpcNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("selected/tpcNSigmaEl"), t0.tpcNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("selected/tpcNSigmaMu"), t0.tpcNSigmaMu(), tVector.Pt()); + histosPID.fill(HIST("selected/tofBeta"), tVector.P(), t0.beta()); + histosPID.fill(HIST("selected/tofNSigmaPi"), t0.tofNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("selected/tofNSigmaKa"), t0.tofNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("selected/tofNSigmaPr"), t0.tofNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("selected/tofNSigmaEl"), t0.tofNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("selected/tofNSigmaMu"), t0.tofNSigmaMu(), tVector.Pt()); + + // Kinematics for all particles after track selection before selecting pions + histosKin.fill(HIST("selected"), tVector.Pt(), tVector.Eta(), tVector.Phi()); + + if (ifPion(t0, useTOF, nSigmaTPCcut, nSigmaTOFcut, ifCircularNSigmaCut)) { + + selectedPionTracks.push_back(t0); + + // QA-Tracks after selecting pions + histosQA.fill(HIST("Tracks/pions/isPVcontributor"), t0.isPVContributor()); + histosQA.fill(HIST("Tracks/pions/dcaXY"), t0.dcaXY()); + histosQA.fill(HIST("Tracks/pions/dcaZ"), t0.dcaZ()); + histosQA.fill(HIST("Tracks/pions/itsChi2NCl"), t0.itsChi2NCl()); + histosQA.fill(HIST("Tracks/pions/itsChi2"), t0.itsChi2NCl() * t0.itsNCls()); + histosQA.fill(HIST("Tracks/pions/tpcChi2NCl"), t0.tpcChi2NCl()); + histosQA.fill(HIST("Tracks/pions/tpcNClsCrossedRows"), t0.tpcNClsCrossedRows()); + + // PID after selecting pions + histosPID.fill(HIST("pions/tpcSignal"), tVector.P(), t0.tpcSignal()); + histosPID.fill(HIST("pions/tpcNSigmaPi"), t0.tpcNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("pions/tpcNSigmaKa"), t0.tpcNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("pions/tpcNSigmaPr"), t0.tpcNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("pions/tpcNSigmaEl"), t0.tpcNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("pions/tpcNSigmaMu"), t0.tpcNSigmaMu(), tVector.Pt()); + histosPID.fill(HIST("pions/tofBeta"), tVector.P(), t0.beta()); + histosPID.fill(HIST("pions/tofNSigmaPi"), t0.tofNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("pions/tofNSigmaKa"), t0.tofNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("pions/tofNSigmaPr"), t0.tofNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("pions/tofNSigmaEl"), t0.tofNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("pions/tofNSigmaMu"), t0.tofNSigmaMu(), tVector.Pt()); + + // Kinematics for pions + histosKin.fill(HIST("pions"), tVector.Pt(), tVector.Eta(), tVector.Phi()); + + if (t0.sign() == 1) { + selectedPionPlusTracks.push_back(t0); + } + if (t0.sign() == -1) { + selectedPionMinusTracks.push_back(t0); + } + } // End of Selection PID Pion + } // End of loop over tracks + + int numSelectedPionTracks = static_cast(selectedPionTracks.size()); + int numPiPlusTracks = static_cast(selectedPionPlusTracks.size()); + int numPionMinusTracks = static_cast(selectedPionMinusTracks.size()); + + // event should have exactly 4 pions + if (numSelectedPionTracks != four) { + return; + } + + // Selecting Events with net charge = 0 + if (numPionMinusTracks == two && numPiPlusTracks == two) { + + // QA-Events-4pion + histosQA.fill(HIST("Events/4pion/UPCmode"), collision.flags()); + histosQA.fill(HIST("Events/4pion/GapSide"), collision.gapSide()); + histosQA.fill(HIST("Events/4pion/TrueGapSide"), sgSelector.trueGap(collision, fv0Cut, ft0aCut, ft0cCut, 1e6)); + histosQA.fill(HIST("Events/4pion/isCBTOk"), sgSelector.isCBTOk(collision)); + histosQA.fill(HIST("Events/4pion/isCBTHadronOk"), sgSelector.isCBTHadronOk(collision)); + histosQA.fill(HIST("Events/4pion/isCBTZdcOk"), sgSelector.isCBTZdcOk(collision)); + histosQA.fill(HIST("Events/4pion/isCBTHadronZdcOk"), sgSelector.isCBTHadronZdcOk(collision)); + histosQA.fill(HIST("Events/4pion/vertexX"), collision.posX()); + histosQA.fill(HIST("Events/4pion/vertexY"), collision.posY()); + histosQA.fill(HIST("Events/4pion/vertexZ"), collision.posZ()); + histosQA.fill(HIST("Events/4pion/occupancy"), collision.occupancyInTime()); + histosQA.fill(HIST("Events/4pion/FV0A"), collision.totalFV0AmplitudeA()); + histosQA.fill(HIST("Events/4pion/FT0A"), collision.totalFT0AmplitudeA()); + histosQA.fill(HIST("Events/4pion/FT0C"), collision.totalFT0AmplitudeC()); + histosQA.fill(HIST("Events/4pion/ZDC"), collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC()); + histosQA.fill(HIST("Events/4pion/FDDA"), collision.totalFDDAmplitudeA()); + histosQA.fill(HIST("Events/4pion/FDDC"), collision.totalFDDAmplitudeC()); + histosQA.fill(HIST("Events/4pion/nPVContributors"), collision.numContrib()); + + for (int i = 0; i < four; i++) { + PxPyPzMVector tVector(selectedPionTracks[i].px(), selectedPionTracks[i].py(), selectedPionTracks[i].pz(), o2::constants::physics::MassPionCharged); + // Tracks QA for all four pions + histosQA.fill(HIST("Tracks/pions-from-4pi/isPVcontributor"), selectedPionTracks[i].isPVContributor()); + histosQA.fill(HIST("Tracks/pions-from-4pi/dcaXY"), selectedPionTracks[i].dcaXY()); + histosQA.fill(HIST("Tracks/pions-from-4pi/dcaZ"), selectedPionTracks[i].dcaZ()); + histosQA.fill(HIST("Tracks/pions-from-4pi/itsChi2NCl"), selectedPionTracks[i].itsChi2NCl()); + histosQA.fill(HIST("Tracks/pions-from-4pi/itsChi2"), selectedPionTracks[i].itsChi2NCl() * selectedPionTracks[i].itsNCls()); + histosQA.fill(HIST("Tracks/pions-from-4pi/tpcChi2NCl"), selectedPionTracks[i].tpcChi2NCl()); + histosQA.fill(HIST("Tracks/pions-from-4pi/tpcNClsCrossedRows"), selectedPionTracks[i].tpcNClsCrossedRows()); + // PID for all four pions + histosPID.fill(HIST("pions-from-4pi/tpcSignal"), tVector.P(), selectedPionTracks[i].tpcSignal()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaPi"), selectedPionTracks[i].tpcNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaKa"), selectedPionTracks[i].tpcNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaPr"), selectedPionTracks[i].tpcNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaEl"), selectedPionTracks[i].tpcNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaMu"), selectedPionTracks[i].tpcNSigmaMu(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofBeta"), tVector.P(), selectedPionTracks[i].beta()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaPi"), selectedPionTracks[i].tofNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaKa"), selectedPionTracks[i].tofNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaPr"), selectedPionTracks[i].tofNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaEl"), selectedPionTracks[i].tofNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaMu"), selectedPionTracks[i].tofNSigmaMu(), tVector.Pt()); + } + + PxPyPzMVector p1(selectedPionPlusTracks[0].px(), selectedPionPlusTracks[0].py(), selectedPionPlusTracks[0].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p2(selectedPionPlusTracks[1].px(), selectedPionPlusTracks[1].py(), selectedPionPlusTracks[1].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p3(selectedPionMinusTracks[0].px(), selectedPionMinusTracks[0].py(), selectedPionMinusTracks[0].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p4(selectedPionMinusTracks[1].px(), selectedPionMinusTracks[1].py(), selectedPionMinusTracks[1].pz(), o2::constants::physics::MassPionCharged); + + // Kinematics for pions from 4 pion events + histosKin.fill(HIST("pions-from-4pion"), p1.Pt(), p1.Eta(), p1.Phi(), p1.Rapidity()); + histosKin.fill(HIST("pions-from-4pion"), p2.Pt(), p2.Eta(), p2.Phi(), p2.Rapidity()); + histosKin.fill(HIST("pions-from-4pion"), p3.Pt(), p3.Eta(), p3.Phi(), p3.Rapidity()); + histosKin.fill(HIST("pions-from-4pion"), p4.Pt(), p4.Eta(), p4.Phi(), p4.Rapidity()); + + PxPyPzMVector p1234 = p1 + p2 + p3 + p4; + PxPyPzMVector p13 = p1 + p3; + PxPyPzMVector p14 = p1 + p4; + PxPyPzMVector p23 = p2 + p3; + PxPyPzMVector p24 = p2 + p4; + + // Two Pion Mass combinations + histos4piKin.fill(HIST("two-pion"), p1234.Pt(), p13.M(), p14.M(), p23.M(), p24.M(), p1234.M()); + + double fourPiPhiPair1 = collinSoperPhi(p13, p1234); + double fourPiPhiPair2 = collinSoperPhi(p14, p1234); + double fourPiPhiPair3 = collinSoperPhi(p23, p1234); + double fourPiPhiPair4 = collinSoperPhi(p24, p1234); + + double fourPiCosThetaPair1 = collinSoperCosTheta(p13, p1234); + double fourPiCosThetaPair2 = collinSoperCosTheta(p14, p1234); + double fourPiCosThetaPair3 = collinSoperCosTheta(p23, p1234); + double fourPiCosThetaPair4 = collinSoperCosTheta(p24, p1234); + + double mDiff13 = std::abs((p13.M() - mRho0)); + double mDiff14 = std::abs((p14.M() - mRho0)); + double mDiff23 = std::abs((p23.M() - mRho0)); + double mDiff24 = std::abs((p24.M() - mRho0)); + if ((mDiff13 < mDiff14) && (mDiff13 < mDiff23) && (mDiff13 < mDiff24)) { + histos4piKin.fill(HIST("zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), fourPiCosThetaPair1, fourPiPhiPair1, runIndex, neutClass); + } else if ((mDiff14 < mDiff13) && (mDiff14 < mDiff23) && (mDiff14 < mDiff24)) { + histos4piKin.fill(HIST("zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), fourPiCosThetaPair2, fourPiPhiPair2, runIndex, neutClass); + } else if ((mDiff23 < mDiff13) && (mDiff23 < mDiff14) && (mDiff23 < mDiff24)) { + histos4piKin.fill(HIST("zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), fourPiCosThetaPair3, fourPiPhiPair3, runIndex, neutClass); + } else if ((mDiff24 < mDiff13) && (mDiff24 < mDiff14) && (mDiff24 < mDiff23)) { + histos4piKin.fill(HIST("zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), fourPiCosThetaPair4, fourPiPhiPair4, runIndex, neutClass); + } + } // End of Analysis for 0 charge events + + // Selecting Events with net charge != 0 for estimation of background + if (numPionMinusTracks != two && numPiPlusTracks != two) { + PxPyPzMVector p1(selectedPionTracks[0].px(), selectedPionTracks[0].py(), selectedPionTracks[0].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p2(selectedPionTracks[1].px(), selectedPionTracks[1].py(), selectedPionTracks[1].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p3(selectedPionTracks[2].px(), selectedPionTracks[2].py(), selectedPionTracks[2].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p4(selectedPionTracks[3].px(), selectedPionTracks[3].py(), selectedPionTracks[3].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p1234 = p1 + p2 + p3 + p4; + // Kinematics for 4 pion system from non 0 charge events + if (numPionMinusTracks == three && numPiPlusTracks == one) { + histos4piKin.fill(HIST("3piMinus-1piPlus"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } else if (numPionMinusTracks == one && numPiPlusTracks == three) { + histos4piKin.fill(HIST("3piPlus-1piMinus"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } else if (numPionMinusTracks == four && numPiPlusTracks == zero) { + histos4piKin.fill(HIST("4piMinus"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } else if (numPionMinusTracks == zero && numPiPlusTracks == four) { + histos4piKin.fill(HIST("4piPlus"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } + histos4piKin.fill(HIST("non-zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } // End of Analysis for non 0 charge events + } // End of 4 Pion Analysis Process function for Pass5 Data + + void processEventCounter(UDCollisions::iterator const& collision) + { + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 0); + // RCT flag + if (!sgSelector.isCBTHadronZdcOk(collision)) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 1); + // UPC mode + if (collision.flags() != ifUPC) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 2); + // vtxITSTPC + if (collision.vtxITSTPC() != vtxITSTPCcut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 3); + // sbp + if (collision.sbp() != sbpCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 4); + // itsROFb + if (collision.itsROFb() != itsROFbCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 5); + // tfb + if (collision.tfb() != tfbCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 6); + // FT0A + if (collision.totalFT0AmplitudeA() > ft0aCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 7); + // FT0C + if (collision.totalFT0AmplitudeC() > ft0cCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 8); + // FV0A + if (collision.totalFV0AmplitudeA() > fv0Cut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 9); + // numContributors + if (collision.numContrib() > maxNpvContrib) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 10); + // vertexZ + if (std::abs(collision.posZ()) > vZCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 11); + } // End of processCounter function + + void processTrackCounter(UDCollisions::iterator const& collision, UDtracks const& tracks) + { + + int runIndex = getRunNumberIndex(collision.runNumber()); + + if (!isGoodEvent(collision)) { + return; + } + + for (const auto& track : tracks) { + + // total tracks + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 0); + + PxPyPzMVector trackVector(track.px(), track.py(), track.pz(), o2::constants::physics::MassPionCharged); + + // pt cut + if (trackVector.Pt() < pTcut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 1); + + // eta cut + if (std::abs(trackVector.Eta()) > etaCut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 2); + + // DCA Z cut + if (std::abs(track.dcaZ()) > dcaZcut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 3); + + // DCA XY cut + float maxDCAxy = 0.0105 + 0.035 / std::pow(trackVector.Pt(), 1.1); + if (dcaXYcut == 0 && (std::fabs(track.dcaXY()) > maxDCAxy)) { + continue; + } else if (dcaXYcut != 0 && (std::fabs(track.dcaXY()) > dcaXYcut)) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 4); + + // ITS Track only + if (useITStracksOnly && !track.hasITS()) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 5); + + // TPC Track only + if (useTPCtracksOnly && !track.hasTPC()) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 6); + + // ITS Chi2 N Clusters cut + if (track.hasITS() && track.itsChi2NCl() > itsChi2NClsCut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 7); + + // TPC Chi2 N Clusters cut + if (track.hasTPC() && track.tpcChi2NCl() > tpcChi2NClsCut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 8); + + // TPC N Clusters Findable cut + if (track.hasTPC() && track.tpcNClsCrossedRows() < tpcNClsCrossedRowsCut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 9); + + // Selection PID Pion + if (ifPion(track, useTOF, nSigmaTPCcut, nSigmaTOFcut, ifCircularNSigmaCut)) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 10); + + // is PV contributor + if (track.isPVContributor() != useOnlyPVtracks) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 11); + + } // End of loop over tracks + } // End of processCounter function + + using MCtracks = soa::Join; + using MCCollisions = soa::Join; + + void processMCgen(aod::UDMcCollisions::iterator const&, aod::UDMcParticles const& mcParticles, aod::BCs const& bcs) + { + + if (bcs.size() == 0) { + return; + } + auto bc = bcs.begin(); + int runIndex = getRunNumberIndex(bc.runNumber()); + + for (const auto& particle : mcParticles) { + PxPyPzMVector p1234; + if ((particle.pdgCode() != rhoPrime) || (particle.daughters_as().size() != four)) { + continue; + } + for (const auto& daughter : particle.daughters_as()) { + PxPyPzMVector dVector(daughter.px(), daughter.py(), daughter.pz(), o2::constants::physics::MassPionCharged); + if (daughter.pdgCode() == PDG_t::kPiPlus) { + histosMCtruth.fill(HIST("4-pi-pions"), dVector.Pt(), dVector.Eta(), dVector.Phi(), dVector.Rapidity(), runIndex); + p1234 = p1234 + dVector; + } + if (daughter.pdgCode() == PDG_t::kPiMinus) { + histosMCtruth.fill(HIST("4-pi-pions"), dVector.Pt(), dVector.Eta(), dVector.Phi(), dVector.Rapidity(), runIndex); + p1234 = p1234 + dVector; + } + } // End of loop over daughters + histosMCtruth.fill(HIST("Four-pion"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex); + } // End of loop over MC particles + } // End of processMCgen function + + void processMCrec(MCCollisions::iterator const& collision, MCtracks const& tracks) + { + + int runIndex = getRunNumberIndex(collision.runNumber()); + int neutClass = getNeutronClass(collision); + + histosQA.fill(HIST("Events/all/UPCmode"), collision.flags()); + histosQA.fill(HIST("Events/all/GapSide"), collision.gapSide()); + histosQA.fill(HIST("Events/all/TrueGapSide"), sgSelector.trueGap(collision, fv0Cut, ft0aCut, ft0cCut, 1e6)); + histosQA.fill(HIST("Events/all/isCBTOk"), sgSelector.isCBTOk(collision)); + histosQA.fill(HIST("Events/all/isCBTHadronOk"), sgSelector.isCBTHadronOk(collision)); + histosQA.fill(HIST("Events/all/isCBTZdcOk"), sgSelector.isCBTZdcOk(collision)); + histosQA.fill(HIST("Events/all/isCBTHadronZdcOk"), sgSelector.isCBTHadronZdcOk(collision)); + histosQA.fill(HIST("Events/all/vertexX"), collision.posX()); + histosQA.fill(HIST("Events/all/vertexY"), collision.posY()); + histosQA.fill(HIST("Events/all/vertexZ"), collision.posZ()); + histosQA.fill(HIST("Events/all/occupancy"), collision.occupancyInTime()); + histosQA.fill(HIST("Events/all/FV0A"), collision.totalFV0AmplitudeA()); + histosQA.fill(HIST("Events/all/FT0A"), collision.totalFT0AmplitudeA()); + histosQA.fill(HIST("Events/all/FT0C"), collision.totalFT0AmplitudeC()); + histosQA.fill(HIST("Events/all/ZDC"), collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC()); + histosQA.fill(HIST("Events/all/FDDA"), collision.totalFDDAmplitudeA()); + histosQA.fill(HIST("Events/all/FDDC"), collision.totalFDDAmplitudeC()); + histosQA.fill(HIST("Events/all/nPVContributors"), collision.numContrib()); + + if ((!isGoodEvent(collision)) || (!collision.has_udMcCollision())) { + return; + } + + histosQA.fill(HIST("Events/selected/UPCmode"), collision.flags()); + histosQA.fill(HIST("Events/selected/GapSide"), collision.gapSide()); + histosQA.fill(HIST("Events/selected/TrueGapSide"), sgSelector.trueGap(collision, fv0Cut, ft0aCut, ft0cCut, 1e6)); + histosQA.fill(HIST("Events/selected/isCBTOk"), sgSelector.isCBTOk(collision)); + histosQA.fill(HIST("Events/selected/isCBTHadronOk"), sgSelector.isCBTHadronOk(collision)); + histosQA.fill(HIST("Events/selected/isCBTZdcOk"), sgSelector.isCBTZdcOk(collision)); + histosQA.fill(HIST("Events/selected/isCBTHadronZdcOk"), sgSelector.isCBTHadronZdcOk(collision)); + histosQA.fill(HIST("Events/selected/vertexX"), collision.posX()); + histosQA.fill(HIST("Events/selected/vertexY"), collision.posY()); + histosQA.fill(HIST("Events/selected/vertexZ"), collision.posZ()); + histosQA.fill(HIST("Events/selected/occupancy"), collision.occupancyInTime()); + histosQA.fill(HIST("Events/selected/FV0A"), collision.totalFV0AmplitudeA()); + histosQA.fill(HIST("Events/selected/FT0A"), collision.totalFT0AmplitudeA()); + histosQA.fill(HIST("Events/selected/FT0C"), collision.totalFT0AmplitudeC()); + histosQA.fill(HIST("Events/selected/ZDC"), collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC()); + histosQA.fill(HIST("Events/selected/FDDA"), collision.totalFDDAmplitudeA()); + histosQA.fill(HIST("Events/selected/FDDC"), collision.totalFDDAmplitudeC()); + histosQA.fill(HIST("Events/selected/nPVContributors"), collision.numContrib()); + + std::vector selectedPionTracks; + std::vector selectedPionPlusTracks; + std::vector selectedPionMinusTracks; + + for (const auto& t0 : tracks) { + + PxPyPzMVector tVector(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassPionCharged); + + // QA-Tracks before selection + histosQA.fill(HIST("Tracks/all/isPVcontributor"), t0.isPVContributor()); + histosQA.fill(HIST("Tracks/all/dcaXY"), t0.dcaXY()); + histosQA.fill(HIST("Tracks/all/dcaZ"), t0.dcaZ()); + histosQA.fill(HIST("Tracks/all/itsChi2NCl"), t0.itsChi2NCl()); + histosQA.fill(HIST("Tracks/all/itsChi2"), t0.itsChi2NCl() * t0.itsNCls()); + histosQA.fill(HIST("Tracks/all/tpcChi2NCl"), t0.tpcChi2NCl()); + histosQA.fill(HIST("Tracks/all/tpcNClsCrossedRows"), t0.tpcNClsCrossedRows()); + + // PID before track selection + histosPID.fill(HIST("all/tpcSignal"), tVector.P(), t0.tpcSignal()); + histosPID.fill(HIST("all/tpcNSigmaPi"), t0.tpcNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("all/tpcNSigmaKa"), t0.tpcNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("all/tpcNSigmaPr"), t0.tpcNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("all/tpcNSigmaEl"), t0.tpcNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("all/tpcNSigmaMu"), t0.tpcNSigmaMu(), tVector.Pt()); + histosPID.fill(HIST("all/tofBeta"), tVector.P(), t0.beta()); + histosPID.fill(HIST("all/tofNSigmaPi"), t0.tofNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("all/tofNSigmaKa"), t0.tofNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("all/tofNSigmaPr"), t0.tofNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("all/tofNSigmaEl"), t0.tofNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("all/tofNSigmaMu"), t0.tofNSigmaMu(), tVector.Pt()); + + // Kinematics for all particles before selection + histosKin.fill(HIST("all"), tVector.Pt(), tVector.Eta(), tVector.Phi()); + + // Selecting good tracks + if ((!isGoodTrack(t0)) || (!t0.has_udMcParticle())) { + continue; + } + + // QA-Tracks after selection + histosQA.fill(HIST("Tracks/selected/isPVcontributor"), t0.isPVContributor()); + histosQA.fill(HIST("Tracks/selected/dcaXY"), t0.dcaXY()); + histosQA.fill(HIST("Tracks/selected/dcaZ"), t0.dcaZ()); + histosQA.fill(HIST("Tracks/selected/itsChi2NCl"), t0.itsChi2NCl()); + histosQA.fill(HIST("Tracks/selected/itsChi2"), t0.itsChi2NCl() * t0.itsNCls()); + histosQA.fill(HIST("Tracks/selected/tpcChi2NCl"), t0.tpcChi2NCl()); + histosQA.fill(HIST("Tracks/selected/tpcNClsCrossedRows"), t0.tpcNClsCrossedRows()); + + // PID after track selection before selecting pions + histosPID.fill(HIST("selected/tpcSignal"), tVector.P(), t0.tpcSignal()); + histosPID.fill(HIST("selected/tpcNSigmaPi"), t0.tpcNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("selected/tpcNSigmaKa"), t0.tpcNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("selected/tpcNSigmaPr"), t0.tpcNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("selected/tpcNSigmaEl"), t0.tpcNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("selected/tpcNSigmaMu"), t0.tpcNSigmaMu(), tVector.Pt()); + histosPID.fill(HIST("selected/tofBeta"), tVector.P(), t0.beta()); + histosPID.fill(HIST("selected/tofNSigmaPi"), t0.tofNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("selected/tofNSigmaKa"), t0.tofNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("selected/tofNSigmaPr"), t0.tofNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("selected/tofNSigmaEl"), t0.tofNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("selected/tofNSigmaMu"), t0.tofNSigmaMu(), tVector.Pt()); + + // Kinematics for all particles after track selection before selecting pions + histosKin.fill(HIST("selected"), tVector.Pt(), tVector.Eta(), tVector.Phi()); + + if (ifPion(t0, useTOF, nSigmaTPCcut, nSigmaTOFcut, ifCircularNSigmaCut)) { + + selectedPionTracks.push_back(t0); + + // QA-Tracks after selecting pions + histosQA.fill(HIST("Tracks/pions/isPVcontributor"), t0.isPVContributor()); + histosQA.fill(HIST("Tracks/pions/dcaXY"), t0.dcaXY()); + histosQA.fill(HIST("Tracks/pions/dcaZ"), t0.dcaZ()); + histosQA.fill(HIST("Tracks/pions/itsChi2NCl"), t0.itsChi2NCl()); + histosQA.fill(HIST("Tracks/pions/itsChi2"), t0.itsChi2NCl() * t0.itsNCls()); + histosQA.fill(HIST("Tracks/pions/tpcChi2NCl"), t0.tpcChi2NCl()); + histosQA.fill(HIST("Tracks/pions/tpcNClsCrossedRows"), t0.tpcNClsCrossedRows()); + + // PID after selecting pions + histosPID.fill(HIST("pions/tpcSignal"), tVector.P(), t0.tpcSignal()); + histosPID.fill(HIST("pions/tpcNSigmaPi"), t0.tpcNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("pions/tpcNSigmaKa"), t0.tpcNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("pions/tpcNSigmaPr"), t0.tpcNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("pions/tpcNSigmaEl"), t0.tpcNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("pions/tpcNSigmaMu"), t0.tpcNSigmaMu(), tVector.Pt()); + histosPID.fill(HIST("pions/tofBeta"), tVector.P(), t0.beta()); + histosPID.fill(HIST("pions/tofNSigmaPi"), t0.tofNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("pions/tofNSigmaKa"), t0.tofNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("pions/tofNSigmaPr"), t0.tofNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("pions/tofNSigmaEl"), t0.tofNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("pions/tofNSigmaMu"), t0.tofNSigmaMu(), tVector.Pt()); + + // Kinematics for pions + histosKin.fill(HIST("pions"), tVector.Pt(), tVector.Eta(), tVector.Phi()); + + if (t0.sign() == 1) { + selectedPionPlusTracks.push_back(t0); + } + if (t0.sign() == -1) { + selectedPionMinusTracks.push_back(t0); + } + } // End of Selection PID Pion + } // End of loop over tracks + + int numSelectedPionTracks = static_cast(selectedPionTracks.size()); + int numPiPlusTracks = static_cast(selectedPionPlusTracks.size()); + int numPionMinusTracks = static_cast(selectedPionMinusTracks.size()); + + // event should have exactly 4 pions + if (numSelectedPionTracks != four) { + return; + } + + // Selecting Events with net charge = 0 + if (numPionMinusTracks == two && numPiPlusTracks == two) { + + // QA-Events-4pion + histosQA.fill(HIST("Events/4pion/UPCmode"), collision.flags()); + histosQA.fill(HIST("Events/4pion/GapSide"), collision.gapSide()); + histosQA.fill(HIST("Events/4pion/TrueGapSide"), sgSelector.trueGap(collision, fv0Cut, ft0aCut, ft0cCut, 1e6)); + histosQA.fill(HIST("Events/4pion/isCBTOk"), sgSelector.isCBTOk(collision)); + histosQA.fill(HIST("Events/4pion/isCBTHadronOk"), sgSelector.isCBTHadronOk(collision)); + histosQA.fill(HIST("Events/4pion/isCBTZdcOk"), sgSelector.isCBTZdcOk(collision)); + histosQA.fill(HIST("Events/4pion/isCBTHadronZdcOk"), sgSelector.isCBTHadronZdcOk(collision)); + histosQA.fill(HIST("Events/4pion/vertexX"), collision.posX()); + histosQA.fill(HIST("Events/4pion/vertexY"), collision.posY()); + histosQA.fill(HIST("Events/4pion/vertexZ"), collision.posZ()); + histosQA.fill(HIST("Events/4pion/occupancy"), collision.occupancyInTime()); + histosQA.fill(HIST("Events/4pion/FV0A"), collision.totalFV0AmplitudeA()); + histosQA.fill(HIST("Events/4pion/FT0A"), collision.totalFT0AmplitudeA()); + histosQA.fill(HIST("Events/4pion/FT0C"), collision.totalFT0AmplitudeC()); + histosQA.fill(HIST("Events/4pion/ZDC"), collision.energyCommonZNA(), collision.energyCommonZNC(), collision.timeZNA(), collision.timeZNC()); + histosQA.fill(HIST("Events/4pion/FDDA"), collision.totalFDDAmplitudeA()); + histosQA.fill(HIST("Events/4pion/FDDC"), collision.totalFDDAmplitudeC()); + histosQA.fill(HIST("Events/4pion/nPVContributors"), collision.numContrib()); + + for (int i = 0; i < four; i++) { + PxPyPzMVector tVector(selectedPionTracks[i].px(), selectedPionTracks[i].py(), selectedPionTracks[i].pz(), o2::constants::physics::MassPionCharged); + // Tracks QA for all four pions + histosQA.fill(HIST("Tracks/pions-from-4pi/isPVcontributor"), selectedPionTracks[i].isPVContributor()); + histosQA.fill(HIST("Tracks/pions-from-4pi/dcaXY"), selectedPionTracks[i].dcaXY()); + histosQA.fill(HIST("Tracks/pions-from-4pi/dcaZ"), selectedPionTracks[i].dcaZ()); + histosQA.fill(HIST("Tracks/pions-from-4pi/itsChi2NCl"), selectedPionTracks[i].itsChi2NCl()); + histosQA.fill(HIST("Tracks/pions-from-4pi/itsChi2"), selectedPionTracks[i].itsChi2NCl() * selectedPionTracks[i].itsNCls()); + histosQA.fill(HIST("Tracks/pions-from-4pi/tpcChi2NCl"), selectedPionTracks[i].tpcChi2NCl()); + histosQA.fill(HIST("Tracks/pions-from-4pi/tpcNClsCrossedRows"), selectedPionTracks[i].tpcNClsCrossedRows()); + // PID for all four pions + histosPID.fill(HIST("pions-from-4pi/tpcSignal"), tVector.P(), selectedPionTracks[i].tpcSignal()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaPi"), selectedPionTracks[i].tpcNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaKa"), selectedPionTracks[i].tpcNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaPr"), selectedPionTracks[i].tpcNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaEl"), selectedPionTracks[i].tpcNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tpcNSigmaMu"), selectedPionTracks[i].tpcNSigmaMu(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofBeta"), tVector.P(), selectedPionTracks[i].beta()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaPi"), selectedPionTracks[i].tofNSigmaPi(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaKa"), selectedPionTracks[i].tofNSigmaKa(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaPr"), selectedPionTracks[i].tofNSigmaPr(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaEl"), selectedPionTracks[i].tofNSigmaEl(), tVector.Pt()); + histosPID.fill(HIST("pions-from-4pi/tofNSigmaMu"), selectedPionTracks[i].tofNSigmaMu(), tVector.Pt()); + } + + PxPyPzMVector p1(selectedPionPlusTracks[0].px(), selectedPionPlusTracks[0].py(), selectedPionPlusTracks[0].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p2(selectedPionPlusTracks[1].px(), selectedPionPlusTracks[1].py(), selectedPionPlusTracks[1].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p3(selectedPionMinusTracks[0].px(), selectedPionMinusTracks[0].py(), selectedPionMinusTracks[0].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p4(selectedPionMinusTracks[1].px(), selectedPionMinusTracks[1].py(), selectedPionMinusTracks[1].pz(), o2::constants::physics::MassPionCharged); + + // Kinematics for pions from 4 pion events + histosKin.fill(HIST("pions-from-4pion"), p1.Pt(), p1.Eta(), p1.Phi(), p1.Rapidity()); + histosKin.fill(HIST("pions-from-4pion"), p2.Pt(), p2.Eta(), p2.Phi(), p2.Rapidity()); + histosKin.fill(HIST("pions-from-4pion"), p3.Pt(), p3.Eta(), p3.Phi(), p3.Rapidity()); + histosKin.fill(HIST("pions-from-4pion"), p4.Pt(), p4.Eta(), p4.Phi(), p4.Rapidity()); + + PxPyPzMVector p1234 = p1 + p2 + p3 + p4; + PxPyPzMVector p13 = p1 + p3; + PxPyPzMVector p14 = p1 + p4; + PxPyPzMVector p23 = p2 + p3; + PxPyPzMVector p24 = p2 + p4; + + // Two Pion Mass combinations + histos4piKin.fill(HIST("two-pion"), p1234.Pt(), p13.M(), p14.M(), p23.M(), p24.M(), p1234.M()); + + double fourPiPhiPair1 = collinSoperPhi(p13, p1234); + double fourPiPhiPair2 = collinSoperPhi(p14, p1234); + double fourPiPhiPair3 = collinSoperPhi(p23, p1234); + double fourPiPhiPair4 = collinSoperPhi(p24, p1234); + + double fourPiCosThetaPair1 = collinSoperCosTheta(p13, p1234); + double fourPiCosThetaPair2 = collinSoperCosTheta(p14, p1234); + double fourPiCosThetaPair3 = collinSoperCosTheta(p23, p1234); + double fourPiCosThetaPair4 = collinSoperCosTheta(p24, p1234); + + double mDiff13 = std::abs((p13.M() - mRho0)); + double mDiff14 = std::abs((p14.M() - mRho0)); + double mDiff23 = std::abs((p23.M() - mRho0)); + double mDiff24 = std::abs((p24.M() - mRho0)); + if ((mDiff13 < mDiff14) && (mDiff13 < mDiff23) && (mDiff13 < mDiff24)) { + histos4piKin.fill(HIST("zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), fourPiCosThetaPair1, fourPiPhiPair1, runIndex, neutClass); + } else if ((mDiff14 < mDiff13) && (mDiff14 < mDiff23) && (mDiff14 < mDiff24)) { + histos4piKin.fill(HIST("zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), fourPiCosThetaPair2, fourPiPhiPair2, runIndex, neutClass); + } else if ((mDiff23 < mDiff13) && (mDiff23 < mDiff14) && (mDiff23 < mDiff24)) { + histos4piKin.fill(HIST("zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), fourPiCosThetaPair3, fourPiPhiPair3, runIndex, neutClass); + } else if ((mDiff24 < mDiff13) && (mDiff24 < mDiff14) && (mDiff24 < mDiff23)) { + histos4piKin.fill(HIST("zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), fourPiCosThetaPair4, fourPiPhiPair4, runIndex, neutClass); + } + } // End of Analysis for 0 charge events + + // Selecting Events with net charge != 0 for estimation of background + if (numPionMinusTracks != two && numPiPlusTracks != two) { + PxPyPzMVector p1(selectedPionTracks[0].px(), selectedPionTracks[0].py(), selectedPionTracks[0].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p2(selectedPionTracks[1].px(), selectedPionTracks[1].py(), selectedPionTracks[1].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p3(selectedPionTracks[2].px(), selectedPionTracks[2].py(), selectedPionTracks[2].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p4(selectedPionTracks[3].px(), selectedPionTracks[3].py(), selectedPionTracks[3].pz(), o2::constants::physics::MassPionCharged); + PxPyPzMVector p1234 = p1 + p2 + p3 + p4; + // Kinematics for 4 pion system from non 0 charge events + if (numPionMinusTracks == three && numPiPlusTracks == one) { + histos4piKin.fill(HIST("3piMinus-1piPlus"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } else if (numPionMinusTracks == one && numPiPlusTracks == three) { + histos4piKin.fill(HIST("3piPlus-1piMinus"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } else if (numPionMinusTracks == four && numPiPlusTracks == zero) { + histos4piKin.fill(HIST("4piMinus"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } else if (numPionMinusTracks == zero && numPiPlusTracks == four) { + histos4piKin.fill(HIST("4piPlus"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } + histos4piKin.fill(HIST("non-zero-charge"), p1234.Pt(), p1234.Eta(), p1234.Phi(), p1234.Rapidity(), p1234.M(), runIndex, neutClass); + } // End of Analysis for non 0 charge events + } // End of 4 Pion Analysis Process function for Pass5 Data + + void processEventCounterMC(MCCollisions::iterator const& collision) + { + + if (!collision.has_udMcCollision()) { + return; + } + + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 0); + // RCT flag + if (!sgSelector.isCBTHadronZdcOk(collision)) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 1); + // UPC mode + if (collision.flags() != ifUPC) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 2); + // vtxITSTPC + if (collision.vtxITSTPC() != vtxITSTPCcut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 3); + // sbp + if (collision.sbp() != sbpCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 4); + // itsROFb + if (collision.itsROFb() != itsROFbCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 5); + // tfb + if (collision.tfb() != tfbCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 6); + // FT0A + if (collision.totalFT0AmplitudeA() > ft0aCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 7); + // FT0C + if (collision.totalFT0AmplitudeC() > ft0cCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 8); + // FV0A + if (collision.totalFV0AmplitudeA() > fv0Cut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 9); + // numContributors + if (collision.numContrib() > maxNpvContrib) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 10); + // vertexZ + if (std::abs(collision.posZ()) > vZCut) { + return; + } + histosDataCounter.fill(HIST("EventsCounts_vs_runNo"), getRunNumberIndex(collision.runNumber()), 11); + } // End of processCounter function + + void processTrackCounterMC(MCCollisions::iterator const& collision, MCtracks const& tracks) + { + + int runIndex = getRunNumberIndex(collision.runNumber()); + + if (!collision.has_udMcCollision()) { + return; + } + + if (!isGoodEvent(collision)) { + return; + } + + for (const auto& track : tracks) { + if (!track.has_udMcParticle()) { + continue; + } + // total tracks + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 0); + + PxPyPzMVector trackVector(track.px(), track.py(), track.pz(), o2::constants::physics::MassPionCharged); + + // pt cut + if (trackVector.Pt() < pTcut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 1); + + // eta cut + if (std::abs(trackVector.Eta()) > etaCut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 2); + + // DCA Z cut + if (std::abs(track.dcaZ()) > dcaZcut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 3); + + // DCA XY cut + float maxDCAxy = 0.0105 + 0.035 / std::pow(trackVector.Pt(), 1.1); + if (dcaXYcut == 0 && (std::fabs(track.dcaXY()) > maxDCAxy)) { + continue; + } else if (dcaXYcut != 0 && (std::fabs(track.dcaXY()) > dcaXYcut)) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 4); + + // ITS Track only + if (useITStracksOnly && !track.hasITS()) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 5); + + // TPC Track only + if (useTPCtracksOnly && !track.hasTPC()) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 6); + + // ITS Chi2 N Clusters cut + if (track.hasITS() && track.itsChi2NCl() > itsChi2NClsCut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 7); + + // TPC Chi2 N Clusters cut + if (track.hasTPC() && track.tpcChi2NCl() > tpcChi2NClsCut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 8); + + // TPC N Clusters Findable cut + if (track.hasTPC() && track.tpcNClsCrossedRows() < tpcNClsCrossedRowsCut) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 9); + + // Selection PID Pion + if (ifPion(track, useTOF, nSigmaTPCcut, nSigmaTOFcut, ifCircularNSigmaCut)) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 10); + + // is PV contributor + if (track.isPVContributor() != useOnlyPVtracks) { + continue; + } + histosDataCounter.fill(HIST("TracksCounts_vs_runNo"), runIndex, 11); + + } // End of loop over tracks + } // End of processCounter function + + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processData, "Data Analysis Function", true); + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processEventCounter, "Event Counter Function", true); + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processTrackCounter, "Track Counter Function", true); + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processMCgen, "MC generated Analysis Function", false); + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processMCrec, "MC reconstructed Analysis Function", false); + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processEventCounterMC, "MC Event Counter Function", false); + PROCESS_SWITCH(ExclusiveRhoTo4Pi, processTrackCounterMC, "MC Track Counter Function", false); + + double collinSoperPhi(PxPyPzMVector twoPionVector, PxPyPzMVector fourPionVector) + { + PxPyPzEVector pProjCM(0., 0., -momentumBeam, halfSqrtSnn * 208); // projectile + PxPyPzEVector pTargCM(0., 0., momentumBeam, halfSqrtSnn * 208); // target + // Boost to center of mass frame + Boost boosTo4PiCM{fourPionVector.BoostToCM()}; + XYZVectorF twoPionVectorCM{(boosTo4PiCM(twoPionVector).Vect()).Unit()}; + XYZVectorF beam1CM{(boosTo4PiCM(pProjCM).Vect()).Unit()}; + XYZVectorF beam2CM{(boosTo4PiCM(pTargCM).Vect()).Unit()}; + // Axes + XYZVectorF zaxisCS{((beam1CM.Unit() - beam2CM.Unit()).Unit())}; + XYZVectorF yaxisCS{(beam1CM.Cross(beam2CM)).Unit()}; + XYZVectorF xaxisCS{(yaxisCS.Cross(zaxisCS)).Unit()}; + double phi = std::atan2(yaxisCS.Dot(twoPionVectorCM), xaxisCS.Dot(twoPionVectorCM)); + return phi; + } + + double collinSoperCosTheta(PxPyPzMVector twoPionVector, PxPyPzMVector fourPionVector) + { + PxPyPzEVector pProjCM(0., 0., -momentumBeam, halfSqrtSnn * 208); // projectile + PxPyPzEVector pTargCM(0., 0., momentumBeam, halfSqrtSnn * 208); // target + // Boost to center of mass frame + Boost boosTo4PiCM{fourPionVector.BoostToCM()}; + XYZVectorF twoPionVectorCM{(boosTo4PiCM(twoPionVector).Vect()).Unit()}; + XYZVectorF beam1CM{(boosTo4PiCM(pProjCM).Vect()).Unit()}; + XYZVectorF beam2CM{(boosTo4PiCM(pTargCM).Vect()).Unit()}; + // Axes + XYZVectorF zaxisCS{((beam1CM.Unit() - beam2CM.Unit()).Unit())}; + double cosThetaCS = zaxisCS.Dot(twoPionVectorCM); + return cosThetaCS; + } + + template + bool isGoodEvent(C const& coll) + { + + // Check if the Event is reconstructed in UPC mode and passes RCT + if ((coll.flags() != ifUPC) || (!sgSelector.isCBTHadronZdcOk(coll))) { + return false; + } + + // Vertex Z cut + if (std::abs(coll.posZ()) > vZCut) { + return false; + } + + // FIT cuts + if ((coll.totalFV0AmplitudeA() > fv0Cut) || (coll.totalFT0AmplitudeA() > ft0aCut) || (coll.totalFT0AmplitudeC() > ft0cCut)) { + return false; + } + + // BC selection + if ((coll.sbp() != sbpCut) || (coll.itsROFb() != itsROFbCut) || (coll.tfb() != tfbCut) || (coll.vtxITSTPC() != vtxITSTPCcut)) { + return false; + } + + // Number of contributors to primary vertex + if (coll.numContrib() > maxNpvContrib) { + return false; + } + + return true; + } // End of Good Event function + + template + bool isGoodTrack(T const& track) + { + PxPyPzMVector trackVector(track.px(), track.py(), track.pz(), o2::constants::physics::MassPionCharged); + // pt cut + if (trackVector.Pt() < pTcut) { + return false; + } + // eta cut + if (std::fabs(trackVector.Eta()) > etaCut) { + return false; + } + // DCA Z cut + if (std::fabs(track.dcaZ()) > dcaZcut) { + return false; + } + // DCA XY cut + float maxDCAxy = 0.0105 + 0.035 / std::pow(trackVector.Pt(), 1.1); + if (dcaXYcut == 0 && (std::fabs(track.dcaXY()) > maxDCAxy)) { + return false; + } else if (dcaXYcut != 0 && (std::fabs(track.dcaXY()) > dcaXYcut)) { + return false; + } + // ITS Track only + if (useITStracksOnly && !track.hasITS()) { + return false; + } + // TPC Track only + if (useTPCtracksOnly && !track.hasTPC()) { + return false; + } + // ITS Chi2 per N Clusters cut + if (track.hasITS() && track.itsChi2NCl() > itsChi2NClsCut) { + return false; + } + // TPC Chi2 N Clusters cut + if (track.hasTPC() && track.tpcChi2NCl() > tpcChi2NClsCut) { + return false; + } + // TPC N Clusters Findable cut + if (track.hasTPC() && track.tpcNClsCrossedRows() < tpcNClsCrossedRowsCut) { + return false; + } + if (useOnlyPVtracks && !track.isPVContributor()) { + return false; + } + // All cuts passed + return true; + } // End of Track Selection function + + template + bool ifPion(const T& candidate, bool use_tof, float nsigmatpc_cut, float nsigmatof_cut, bool ifCircularNSigmaCut) + { + if (ifCircularNSigmaCut) { + if (use_tof && candidate.hasTOF() && (candidate.tofNSigmaPi() * candidate.tofNSigmaPi() + candidate.tpcNSigmaPi() * candidate.tpcNSigmaPi()) < (nsigmatof_cut * 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; + } else { + if (use_tof && candidate.hasTOF() && (std::abs(candidate.tofNSigmaPi()) < nsigmatpc_cut) && (std::abs(candidate.tpcNSigmaPi()) < nsigmatpc_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 + int getNeutronClass(C const& coll) + { + + bool aXn = coll.energyCommonZNA() > zdcMaxAmp && coll.timeZNA() < zdcMaxTime; + bool a0n = coll.energyCommonZNA() <= zdcMaxAmp; + bool cXn = coll.energyCommonZNC() > zdcMaxAmp && coll.timeZNC() < zdcMaxTime; + bool c0n = coll.energyCommonZNC() <= zdcMaxAmp; + + if (aXn && cXn) { + return 1; // XnXn + } else if (aXn && c0n) { + return 2; // Xn0n + } else if (a0n && cXn) { + return 3; // 0nXn + } else if (a0n && c0n) { + return 4; // 0n0n + } else { + return 0; // undefined + } + } // End of getting neutron class + + int getRunNumberIndex(int runNumber) + { + for (int i = 0; i < numRunNums; ++i) { + if (runNos[i] == runNumber) { + return i; + } + } + return -1; // Not found + } // End of getRunNumberIndex function + + std::string strFormat(double value, int precision = 2) + { + std::ostringstream oss; + oss << std::fixed << std::setprecision(precision) << value; + return oss.str(); + } + + void setHistBinLabels() + { + + // Event cuts labels + std::string eventLabels[12] = { + "No Cuts", + "isCBTHadronOk", + "UPC or STD", + "vtxITSTPC=" + strFormat(vtxITSTPCcut, 0), + "sbp=" + strFormat(sbpCut, 0), + "itsROFb=" + strFormat(itsROFbCut, 0), + "tfb=" + strFormat(tfbCut, 0), + "FT0A<=" + strFormat(fv0Cut), + "FT0C<=" + strFormat(ft0cCut), + "FV0A<=" + strFormat(ft0aCut), + "n PV Contrib < " + std::to_string(maxNpvContrib), + "V_{z} < " + strFormat(vZCut) + " cm"}; + int numEventCuts = 12; + + // Tracks cuts labels + std::string trackLabels[12] = { + "No Cuts", + "pT>" + strFormat(pTcut) + " GeV/c", + "|#eta|<" + strFormat(etaCut), + "DCA Z<" + strFormat(dcaZcut) + " cm", + "DCA XY cut", + "hasITS = " + std::to_string(useITStracksOnly), + "hasTPC = " + std::to_string(useTPCtracksOnly), + "itsChi2NCl<" + strFormat(itsChi2NClsCut), + "tpcChi2NCl<" + strFormat(tpcChi2NClsCut), + "tpcNClsCrossedRows>" + strFormat(tpcNClsCrossedRowsCut), + "#pi tracks (TPC+TOF)", + "isPVContributor"}; + int numTrackCuts = 12; + + auto h1 = histosDataCounter.get(HIST("EventsCounts_vs_runNo")); + auto h2 = histosDataCounter.get(HIST("TracksCounts_vs_runNo")); + auto h3 = histos4piKin.get(HIST("zero-charge")); + auto h4 = histos4piKin.get(HIST("non-zero-charge")); + auto h5 = histosMCtruth.get(HIST("Four-pion")); + + for (int i = 0; i < numEventCuts; ++i) { + h1->GetYaxis()->SetBinLabel(i + 1, eventLabels[i].c_str()); + } + for (int i = 0; i < numTrackCuts; ++i) { + h2->GetYaxis()->SetBinLabel(i + 1, trackLabels[i].c_str()); + } + for (int i = 0; i < numRunNums; ++i) { + std::string runLabel = std::to_string(runNos[i]); + h1->GetXaxis()->SetBinLabel(i + 1, runLabel.c_str()); + h2->GetXaxis()->SetBinLabel(i + 1, runLabel.c_str()); + h3->GetAxis(7)->SetBinLabel(i + 1, runLabel.c_str()); + h4->GetAxis(5)->SetBinLabel(i + 1, runLabel.c_str()); + h5->GetAxis(5)->SetBinLabel(i + 1, runLabel.c_str()); + } + + h3->GetAxis(8)->SetBinLabel(2, "XnXn"); + h3->GetAxis(8)->SetBinLabel(3, "Xn0n"); + h3->GetAxis(8)->SetBinLabel(4, "0nXn"); + h3->GetAxis(8)->SetBinLabel(5, "0n0n"); + + h4->GetAxis(6)->SetBinLabel(2, "XnXn"); + h4->GetAxis(6)->SetBinLabel(3, "Xn0n"); + h4->GetAxis(6)->SetBinLabel(4, "0nXn"); + h4->GetAxis(6)->SetBinLabel(5, "0n0n"); + + } // end of setHistBinLabels function + +}; // End of Struct exclusiveRhoTo4Pi + +int ExclusiveRhoTo4Pi::runNos[113] = { + 544013, 544028, 544032, 544091, 544095, 544098, 544116, 544121, 544122, 544123, + 544124, 544184, 544185, 544389, 544390, 544391, 544392, 544451, 544454, 544474, + 544475, 544476, 544477, 544490, 544491, 544492, 544508, 544510, 544511, 544512, + 544514, 544515, 544518, 544548, 544549, 544550, 544551, 544564, 544565, 544567, + 544568, 544580, 544582, 544583, 544585, 544614, 544640, 544652, 544653, 544672, + 544674, 544692, 544693, 544694, 544696, 544739, 544742, 544754, 544767, 544794, + 544795, 544797, 544813, 544868, 544886, 544887, 544896, 544911, 544913, 544914, + 544917, 544931, 544947, 544961, 544963, 544964, 544968, 544991, 544992, 545004, + 545008, 545009, 545041, 545042, 545044, 545047, 545060, 545062, 545063, 545064, + 545066, 545086, 545103, 545117, 545171, 545184, 545185, 545210, 545222, 545223, + 545246, 545249, 545262, 545289, 545291, 545294, 545295, 545296, 545311, 545312, + 545332, 545345, 545367}; + +int ExclusiveRhoTo4Pi::numRunNums = 113; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/exclusiveTwoProtons.cxx b/PWGUD/Tasks/exclusiveTwoProtons.cxx index 72032b06906..d22c92cccbc 100644 --- a/PWGUD/Tasks/exclusiveTwoProtons.cxx +++ b/PWGUD/Tasks/exclusiveTwoProtons.cxx @@ -8,15 +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. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "iostream" +#include "PWGUD/Core/SGSelector.h" #include "PWGUD/DataModel/UDTables.h" -#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGUD/Core/SGSelector.h" +#include + +#include using std::array; using namespace std; using namespace o2; diff --git a/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx b/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx index 0e0aa7c83dd..521096634e9 100644 --- a/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx +++ b/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx @@ -8,15 +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. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "iostream" +#include "PWGUD/Core/SGSelector.h" #include "PWGUD/DataModel/UDTables.h" -#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGUD/Core/SGSelector.h" +#include + +#include using std::array; using namespace std; using namespace o2; diff --git a/PWGUD/Tasks/flowCorrelationsUpc.cxx b/PWGUD/Tasks/flowCorrelationsUpc.cxx new file mode 100644 index 00000000000..baf24af6f94 --- /dev/null +++ b/PWGUD/Tasks/flowCorrelationsUpc.cxx @@ -0,0 +1,291 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "PWGCF/Core/CorrelationContainer.h" +#include "PWGCF/Core/PairCuts.h" +#include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include "TRandom3.h" + +#include + +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") + O2_DEFINE_CONFIGURABLE(cfgSampleSize, double, 10, "Sample size for mixed event") + O2_DEFINE_CONFIGURABLE(cfgUsePtOrder, bool, true, "enable trigger pT < associated pT cut") + O2_DEFINE_CONFIGURABLE(cfgUsePtOrderInMixEvent, bool, true, "enable trigger pT < associated pT cut in mixed event") + + 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"}; + ConfigurableAxis axisSample{"axisSample", {cfgSampleSize, 0, cfgSampleSize}, "sample axis for 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, {{axisSample, 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 + }; + + // 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) // 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"), fSampleIndex, posZ, track1.pt()); + } + + for (auto const& track2 : tracks2) { + + if (track1.globalIndex() == track2.globalIndex()) + continue; // For pt-differential correlations, skip if the trigger and associate are the same track + if (system == SameEvent && track1.pt() <= track2.pt()) + continue; // Without pt-differential correlations, skip if the trigger pt is less than the associate pt + + 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, 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(UDCollisionsFull::iterator const& collision, UdTracksFull const& tracks) + { + if (std::abs(collision.posZ()) > cfgZVtxCut) { + return; + } + if (tracks.size() < cfgMinMult || tracks.size() > cfgMaxMult) { + return; + } + + int gapSide = collision.gapSide(); + const int minGapSide = 0; + const int maxGapSide = 2; + if (gapSide < minGapSide || gapSide > maxGapSide) { + 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); // 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); + } + } + 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..147325ee9c5 --- /dev/null +++ b/PWGUD/Tasks/flowCumulantsUpc.cxx @@ -0,0 +1,1059 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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 "FlowContainer.h" +#include "GFW.h" +#include "GFWCumulant.h" +#include "GFWPowerArray.h" +#include "GFWWeights.h" + +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UPCHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" +#include + +#include "Math/LorentzVector.h" +#include "Math/PxPyPzM4D.h" +#include "TList.h" +#include "TMath.h" +#include "TVector3.h" +#include +#include +#include +#include + +#include +#include +#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 { + + // resort + // Preslice perCollision = aod::track::collisionId; + PresliceUnsorted perMcCollision = o2::aod::udmcparticle::udMcCollisionId; + // Preslice perCol = aod::track::collisionId; + + 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"}; + + // 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"}; + OutputObj fFCMc{FlowContainer("FlowContainerMC")}; + OutputObj fWeightsMc{GFWWeights("weightsMC")}; + + // define global variables + GFW* fGFW = new GFW(); + GFW* fGFWMC = new GFW(); + std::vector corrconfigs; + std::vector corrconfigsmc; + TAxis* fPtAxis; + TRandom3* fRndm = new TRandom3(0); + TRandom3* fRndmMc = 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 MCparticles = aod::UDMcParticles::iterator; + 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("hCentMC", hCentTitle.c_str(), {HistType::kTH1D, {{90, 0, 90}}}); + registry.add("hVtxZMC", "Vexter Z distribution", {HistType::kTH1D, {axisVertex}}); + registry.add("hMultMC", "Multiplicity distribution", {HistType::kTH1D, {{3000, 0.5, 3000.5}}}); + registry.add("numberOfTracksMC", "Number of tracks per event", {HistType::kTH1D, {{1000, 0, 1000}}}); + 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}}); + + registry.add("hPxMc", "Px distribution of MC truth particles", {HistType::kTH1D, {{100, -10, 10}}}); + registry.add("hPyMc", "Px distribution of MC truth particles", {HistType::kTH1D, {{100, -10, 10}}}); + registry.add("hPzMc", "Px distribution of MC truth particles", {HistType::kTH1D, {{100, -10, 10}}}); + registry.add("hweightMc", "weight distribution of MC truth particles", {HistType::kTH1D, {{100, 0, 1}}}); + registry.add("hPhiMC", "#phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hPhiWeightedMC", "corrected #phi distribution", {HistType::kTH1D, {axisPhi}}); + registry.add("hEtaMC", "#eta distribution", {HistType::kTH1D, {axisEta}}); + registry.add("hPtMC", "p_{T} distribution before cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hPtRefMC", "p_{T} distribution after cut", {HistType::kTH1D, {axisPtHist}}); + registry.add("hChi2prTPCclsMC", "#chi^{2}/cluster for the TPC track segment", {HistType::kTH1D, {{100, 0., 5.}}}); + registry.add("hChi2prITSclsMC", "#chi^{2}/cluster for the ITS track", {HistType::kTH1D, {{100, 0., 50.}}}); + registry.add("hnTPCCluMC", "Number of found TPC clusters", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hnITSCluMC", "Number of found ITS clusters", {HistType::kTH1D, {{100, 0, 20}}}); + registry.add("hnTPCCrossedRowMC", "Number of crossed TPC Rows", {HistType::kTH1D, {{100, 40, 180}}}); + registry.add("hDCAzMC", "DCAz after cuts; DCAz (cm); Pt", {HistType::kTH2D, {{200, -0.5, 0.5}, {200, 0, 5}}}); + registry.add("hDCAxyMC", "DCAxy after cuts; DCAxy (cm); Pt", {HistType::kTH2D, {{200, -0.5, 0.5}, {200, 0, 5}}}); + registry.add("eventCounterMC", "Number of MC Event;; Count", {HistType::kTH1D, {{5, 0, 5}}}); + registry.add("hTrackCorrection2dMC", "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); + fWeightsMc->setPtBins(nPtBins, ptBins); + fWeightsMc->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); + fFCMc->SetName("FlowContainerMC"); + fFCMc->SetXAxis(fPtAxis); + fFCMc->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); + + fGFWMC->AddRegion("full", -0.8, 0.8, 1, 1); + fGFWMC->AddRegion("refN00", -0.8, 0., 1, 1); // gap0 negative region + fGFWMC->AddRegion("refP00", 0., 0.8, 1, 1); // gap0 positve region + fGFWMC->AddRegion("refN02", -0.8, -0.1, 1, 1); // gap2 negative region + fGFWMC->AddRegion("refP02", 0.1, 0.8, 1, 1); // gap2 positve region + fGFWMC->AddRegion("refN04", -0.8, -0.2, 1, 1); // gap4 negative region + fGFWMC->AddRegion("refP04", 0.2, 0.8, 1, 1); // gap4 positve region + fGFWMC->AddRegion("refN06", -0.8, -0.3, 1, 1); // gap6 negative region + fGFWMC->AddRegion("refP06", 0.3, 0.8, 1, 1); // gap6 positve region + fGFWMC->AddRegion("refN08", -0.8, -0.4, 1, 1); + fGFWMC->AddRegion("refP08", 0.4, 0.8, 1, 1); + fGFWMC->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFWMC->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFWMC->AddRegion("refN12", -0.8, -0.6, 1, 1); + fGFWMC->AddRegion("refP12", 0.6, 0.8, 1, 1); + fGFWMC->AddRegion("refN14", -0.8, -0.7, 1, 1); + fGFWMC->AddRegion("refP14", 0.7, 0.8, 1, 1); + fGFWMC->AddRegion("refN", -0.8, -0.4, 1, 1); + fGFWMC->AddRegion("refP", 0.4, 0.8, 1, 1); + fGFWMC->AddRegion("refM", -0.4, 0.4, 1, 1); + fGFWMC->AddRegion("poiN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("olN", -0.8, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->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)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("full {3 -3}", "ChFull32", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("full {4 -4}", "ChFull42", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("full {2 2 2 -2 -2 -2}", "ChFull26", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN04 {2} refP04 {-2}", "Ch04Gap22", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN06 {2} refP06 {-2}", "Ch06Gap22", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN08 {2} refP08 {-2}", "Ch08Gap22", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN12 {2} refP12 {-2}", "Ch12Gap22", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN04 {3} refP04 {-3}", "Ch04Gap32", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN06 {3} refP06 {-3}", "Ch06Gap32", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN08 {3} refP08 {-3}", "Ch08Gap32", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN10 {3} refP10 {-3}", "Ch10Gap32", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN12 {3} refP12 {-3}", "Ch12Gap32", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN04 {4} refP04 {-4}", "Ch04Gap42", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN06 {4} refP06 {-4}", "Ch06Gap42", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN08 {4} refP08 {-4}", "Ch08Gap42", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN10 {4} refP10 {-4}", "Ch10Gap42", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN12 {4} refP12 {-4}", "Ch12Gap42", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN {2} refP {-2}", "ChGap22", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("poifull full | olfull {2 2 -2 -2}", "ChFull24", kTRUE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("poifull full | olfull {2 2 2 -2 -2 -2}", "ChFull26", kTRUE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("poiN10 refN10 | olN10 {3} refP10 {-3}", "Ch10Gap32", kTRUE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("poiN10 refN10 | olN10 {4} refP10 {-4}", "Ch10Gap42", kTRUE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("full {4 -2 -2}", "ChFull422", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN04 {-2 -2} refP04 {4}", "Ch04GapA422", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN04 {4} refP04 {-2 -2}", "Ch04GapB422", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN10 {-2 -2} refP10 {4}", "Ch10GapA422", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN10 {4} refP10 {-2 -2}", "Ch10GapB422", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("full {3 2 -3 -2}", "ChFull3232", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("full {4 2 -4 -2}", "ChFull4242", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN04 {3 2} refP04 {-3 -2}", "Ch04Gap3232", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN04 {4 2} refP04 {-4 -2}", "Ch04Gap4242", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN04 {2 2} refP04 {-2 -2}", "Ch04Gap24", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN10 {3 2} refP10 {-3 -2}", "Ch10Gap3232", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN10 {4 2} refP10 {-4 -2}", "Ch10Gap4242", kFALSE)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig("refN10 {2 2} refP10 {-2 -2}", "Ch10Gap24", kFALSE)); + corrconfigsmc.push_back(fGFWMC->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)); + corrconfigsmc.push_back(fGFWMC->GetCorrelatorConfig(userDefineGFWCorr.at(i).c_str(), userDefineGFWName.at(i).c_str(), kFALSE)); + } + } + fGFW->CreateRegions(); + fGFWMC->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; + } + + template + void fillProfileMC(const GFW::CorrConfig& corrconf, const ConstStr& tarName, const double& cent) + { + double dnx, val; + dnx = fGFWMC->Calculate(corrconf, 0, kTRUE).real(); + if (dnx == 0) { + return; + } + if (!corrconf.pTDif) { + val = fGFWMC->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + registry.fill(tarName, cent, val, dnx); + } + return; + } + return; + } + + void fillFCMC(const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFWMC->Calculate(corrconf, 0, kTRUE).real(); + if (!corrconf.pTDif) { + if (dnx == 0) { + return; + } + val = fGFWMC->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + fFCMc->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + } + return; + } + for (auto i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFWMC->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) { + continue; + } + val = fGFWMC->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + fFCMc->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 + constexpr int kSigmaCut = 5; + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > kSigmaCut * 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); + } + constexpr int kSigmaCut = 5; + if (!(std::fabs(collision.multFV0A() - fT0AV0AMean->Eval(collision.multFT0A())) > kSigmaCut * fT0AV0ASigma->Eval(collision.multFT0A()))) { + registry.fill(HIST("hEventCountTentative"), 9.5); + } + } + + template + bool trackSelected(TTrack track) + { + // UPC selection + if (!track.isPVContributor()) { + return false; + } + constexpr float kDcazCut = 2.0; + if (!(std::fabs(track.dcaZ()) < kDcazCut)) { + return false; + } + double dcaLimit = 0.0105 + 0.035 / std::pow(track.pt(), 1.1); + if (!(std::fabs(track.dcaXY()) < dcaLimit)) { + 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(UDCollisionsFull::iterator const& collision, UdTracksFull const& tracks) + // { + // std::cout << "Processing collision============================================== " << std::endl; + + // registry.fill(HIST("hEventCount"), 0.5); + // int gapSide = collision.gapSide(); + // constexpr int kGapSideSelection = 0; + // constexpr int kGapSideOppositeSelection = 2; + // if (gapSide < kGapSideSelection || gapSide > kGapSideOppositeSelection) { + // return; + // } + + // int trueGapSide = sgSelector.trueGap(collision, cfgCutFV0, cfgCutFT0A, cfgCutFT0C, cfgCutZDC); + // gapSide = trueGapSide; + // if (gapSide == cfgGapSideSelection) { + // return; + // } + // registry.fill(HIST("hEventCount"), 1.5); + // float cent = 100; + // 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(); + + // // // 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("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); + // } + // } + // PROCESS_SWITCH(FlowCumulantsUpc, process, "process", false); + + //----------------------------------------------------------------------------------------------------------------------- + void processSim(aod::UDMcCollisions const& mcCollisions, aod::UDMcParticles const& mcParticles) + { + LOG(info) << "Processing MC collision======================== " << std::endl; + + // std::cout << mcParicles::IndexudmcCollisions.is_sorted(); + + for (const auto& mcCollision : mcCollisions) { + auto groupedUDMcParticles = mcParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); + registry.fill(HIST("eventCounterMC"), 0.5); + + // registry.fill(HIST("hEventCount"), 1.5); + float cent = 50; + float vtxz = 0; + + vtxz = mcCollision.posZ(); + registry.fill(HIST("hVtxZMC"), vtxz); + registry.fill(HIST("eventCounterMC"), mcCollision.size()); + registry.fill(HIST("hMultMC"), groupedUDMcParticles.size()); + registry.fill(HIST("hCentMC"), cent); + + auto massPion = o2::constants::physics::MassPionCharged; + registry.fill(HIST("numberOfTracksMC"), groupedUDMcParticles.size()); + // LOGF(info, "New event! mcParticles.size() = %d", mcParticles.size()); + + float lRandomMc = fRndmMc->Rndm(); + fGFWMC->Clear(); + + // // track weights + float weff = 1, wacc = 1; + double nTracksCorrected = 0; + float independent = cent; + if (cfgUseNch) { + independent = static_cast(groupedUDMcParticles.size()); + } + + LOG(info) << "mcParticles.size() = " << groupedUDMcParticles.size() << std::endl; + + for (const auto& mcParticle : groupedUDMcParticles) { + + LOG(info) << "filling mc particle px: " << mcParticle.px() << ", py: " << mcParticle.py() << ", pz: " << mcParticle.pz() << std::endl; + + // output information from mcparticles + registry.fill(HIST("hPxMc"), mcParticle.px()); + registry.fill(HIST("hPyMc"), mcParticle.py()); + registry.fill(HIST("hPzMc"), mcParticle.pz()); + registry.fill(HIST("hweightMc"), mcParticle.weight()); + + if (!mcParticle.isPhysicalPrimary()) { + LOG(info) << "mcParticle.isPhysicalPrimary() = " << mcParticle.isPhysicalPrimary() << std::endl; + continue; + } + + std::array momentum = {mcParticle.px(), mcParticle.py(), mcParticle.pz()}; + double energy = std::sqrt(momentum[0] * momentum[0] + momentum[1] * momentum[1] + momentum[2] * momentum[2] + massPion * massPion); + ROOT::Math::LorentzVector> protoMC(momentum[0], momentum[1], momentum[2], energy); + constexpr double kEtaCut = 0.8; + constexpr double kPtCut = 0.1; + if (!(std::fabs(protoMC.Eta()) < kEtaCut && protoMC.Pt() > kPtCut)) { + LOG(info) << "protoMC.Eta() = " << protoMC.Eta() << ", protoMC.Pt() = " << protoMC.Pt() << std::endl; + continue; + } + // auto momentum = std::array{mcParticle.px(), mcParticle.py(), mcParticle.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) { + fWeightsMc->fill(phi, eta, vtxz, pt, cent, 0); + } + } else { + fWeightsMc->fill(phi, eta, vtxz, pt, cent, 0); + } + } + if (!setCurrentParticleWeights(weff, wacc, phi, eta, pt, vtxz)) { + continue; + } + + if (withinPtRef) { + registry.fill(HIST("hPhiMC"), phi); + registry.fill(HIST("hPhiWeightedMC"), phi, wacc); + registry.fill(HIST("hEtaMC"), eta); + registry.fill(HIST("hPtRefMC"), pt); + // registry.fill(HIST("hDCAzMC"), track.dcaZ(), track.pt()); + // registry.fill(HIST("hDCAxyMC"), track.dcaXY(), track.pt()); + nTracksCorrected += weff; + } + if (withinPtRef) { + fGFWMC->Fill(eta, fPtAxis->FindBin(pt) - 1, phi, wacc * weff, 1); + } + if (withinPtPOI) { + fGFWMC->Fill(eta, fPtAxis->FindBin(pt) - 1, phi, wacc * weff, 2); + } + if (withinPtPOI && withinPtRef) { + fGFWMC->Fill(eta, fPtAxis->FindBin(pt) - 1, phi, wacc * weff, 4); + } + LOG(info) << "successfully filled" << std::endl; + } + registry.fill(HIST("hTrackCorrection2dMC"), mcParticles.size(), nTracksCorrected); + // Filling Flow Container + for (uint l_ind = 0; l_ind < corrconfigsmc.size(); l_ind++) { + LOG(info) << "filling flow container for MC" << std::endl; + fillFCMC(corrconfigsmc.at(l_ind), independent, lRandomMc); + } + } + } + PROCESS_SWITCH(FlowCumulantsUpc, processSim, "processSim", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/polarisationRho.cxx b/PWGUD/Tasks/polarisationRho.cxx index 994c921a6df..c10e86baad6 100644 --- a/PWGUD/Tasks/polarisationRho.cxx +++ b/PWGUD/Tasks/polarisationRho.cxx @@ -11,7 +11,7 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" -#include "iostream" +#include #include "PWGUD/DataModel/UDTables.h" #include #include "TLorentzVector.h" diff --git a/PWGUD/Tasks/sgD0Analyzer.cxx b/PWGUD/Tasks/sgD0Analyzer.cxx index b5c35b9deec..7e4c2019434 100644 --- a/PWGUD/Tasks/sgD0Analyzer.cxx +++ b/PWGUD/Tasks/sgD0Analyzer.cxx @@ -13,17 +13,19 @@ // \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 "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" +#include + +#include using namespace std; using namespace o2; using namespace o2::aod; diff --git a/PWGUD/Tasks/sgExcUniverse.cxx b/PWGUD/Tasks/sgExcUniverse.cxx index f7dd3691c25..6178d4cb0b0 100644 --- a/PWGUD/Tasks/sgExcUniverse.cxx +++ b/PWGUD/Tasks/sgExcUniverse.cxx @@ -13,17 +13,17 @@ // \author Sasha Bylinkin, alexander.bylinkin@gmail.com // \since April 2023 -#include "Framework/runDataProcessing.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + #include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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" +#include "TTree.h" +#include "TVector3.h" using namespace o2; using namespace o2::framework; diff --git a/PWGUD/Tasks/sgExclOmega.cxx b/PWGUD/Tasks/sgExclOmega.cxx index 3e24048e621..858b0499caa 100644 --- a/PWGUD/Tasks/sgExclOmega.cxx +++ b/PWGUD/Tasks/sgExclOmega.cxx @@ -13,17 +13,19 @@ // \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 "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" +#include + +#include using namespace std; using namespace o2; using namespace o2::aod; diff --git a/PWGUD/Tasks/sgExclusivePhi.cxx b/PWGUD/Tasks/sgExclusivePhi.cxx index b9840c9b167..c4bed3d1456 100644 --- a/PWGUD/Tasks/sgExclusivePhi.cxx +++ b/PWGUD/Tasks/sgExclusivePhi.cxx @@ -9,15 +9,18 @@ // 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/Core/SGSelector.h" #include "PWGUD/DataModel/UDTables.h" -#include + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGUD/Core/SGSelector.h" +#include + +#include +#include using std::array; using namespace std; @@ -654,7 +657,7 @@ struct sgExclusivePhi { } } } // end of two tracks only loop - } // vertex cut + } // vertex cut if (allTracksAreKaonsBandPID.size() == 2) { @@ -679,7 +682,7 @@ struct sgExclusivePhi { // auto ksize = allTracksAreITSonlyAndFourITSclusters.size(); registry.fill(HIST("hTracksITSonly"), allTracksAreITSonlyAndFourITSclusters.size()); - for (int kaon = 0; kaon < allTracksAreITSonlyAndFourITSclusters.size(); kaon++) { + for (std::size_t kaon = 0; kaon < allTracksAreITSonlyAndFourITSclusters.size(); kaon++) { int clusterSize[7]; double averageClusterSize = 0.; @@ -730,8 +733,8 @@ struct sgExclusivePhi { } } } // Kaon Band - } // double gap - } // end of process + } // double gap + } // end of process }; // end of struct diff --git a/PWGUD/Tasks/sgExclusivePhiITSselections.cxx b/PWGUD/Tasks/sgExclusivePhiITSselections.cxx new file mode 100644 index 00000000000..1e3fe149e59 --- /dev/null +++ b/PWGUD/Tasks/sgExclusivePhiITSselections.cxx @@ -0,0 +1,401 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGUD/Core/SGSelector.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "TLorentzVector.h" +#include + +#include +#include + +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 73d42421b87..60464ed6cf4 100644 --- a/PWGUD/Tasks/sgFITAnalyzer.cxx +++ b/PWGUD/Tasks/sgFITAnalyzer.cxx @@ -13,18 +13,20 @@ // \author Sasha Bylinkin, alexander.bylinkin@gmail.com // \since April 2023 -#include "Framework/runDataProcessing.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Common/DataModel/PIDResponseTOF.h" + #include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.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" +#include "TTree.h" +#include "TVector3.h" using namespace o2; using namespace o2::framework; diff --git a/PWGUD/Tasks/sgFourPiAnalyzer.cxx b/PWGUD/Tasks/sgFourPiAnalyzer.cxx index fb437863ed8..13979d87c38 100644 --- a/PWGUD/Tasks/sgFourPiAnalyzer.cxx +++ b/PWGUD/Tasks/sgFourPiAnalyzer.cxx @@ -13,21 +13,24 @@ // \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 "PWGUD/DataModel/UDTables.h" + +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/DataTypes.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" #include "MathUtils/Utils.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include + #include "TLorentzVector.h" +#include + +#include using namespace std; using namespace o2; using namespace o2::aod; diff --git a/PWGUD/Tasks/sgInclJpsi.cxx b/PWGUD/Tasks/sgInclJpsi.cxx index 7e0557ef5f0..eba36e3845c 100644 --- a/PWGUD/Tasks/sgInclJpsi.cxx +++ b/PWGUD/Tasks/sgInclJpsi.cxx @@ -13,17 +13,19 @@ // \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 "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + #include "TLorentzVector.h" +#include + +#include using namespace std; using namespace o2; using namespace o2::aod; @@ -297,7 +299,7 @@ struct SGInclJpsi { 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 diff --git a/PWGUD/Tasks/sgPIDAnalyzer.cxx b/PWGUD/Tasks/sgPIDAnalyzer.cxx new file mode 100644 index 00000000000..c3038cee058 --- /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 "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/SGTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "TFile.h" +#include "TTree.h" +#include "TVector3.h" +#include +#include + +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 index 7ecea94c66d..2792dee4be2 100644 --- a/PWGUD/Tasks/sgPIDSpectra.cxx +++ b/PWGUD/Tasks/sgPIDSpectra.cxx @@ -13,17 +13,17 @@ // \author Sasha Bylinkin, alexander.bylinkin@gmail.com // \since April 2023 -#include "Framework/runDataProcessing.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + #include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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" +#include "TTree.h" +#include "TVector3.h" using namespace o2; using namespace o2::framework; diff --git a/PWGUD/Tasks/sgPIDSpectraTable.cxx b/PWGUD/Tasks/sgPIDSpectraTable.cxx new file mode 100644 index 00000000000..bd781969afc --- /dev/null +++ b/PWGUD/Tasks/sgPIDSpectraTable.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. +// +// \Single Gap Event Analyzer +// \author Sasha Bylinkin, alexander.bylinkin@gmail.com +// \since April 2023 +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/SGTrackSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/SGTables.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "TFile.h" +#include "TTree.h" +#include "TVector3.h" + +#include + +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 index 215c5d236a1..1a3ed6604e2 100644 --- a/PWGUD/Tasks/sgSixPiAnalyzer.cxx +++ b/PWGUD/Tasks/sgSixPiAnalyzer.cxx @@ -13,22 +13,24 @@ // \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 "PWGUD/DataModel/UDTables.h" + +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/DataTypes.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" #include "MathUtils/Utils.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include #include "TLorentzVector.h" +#include + +#include using namespace std; using namespace o2; using namespace o2::aod; diff --git a/PWGUD/Tasks/sgSpectraAnalyzer.cxx b/PWGUD/Tasks/sgSpectraAnalyzer.cxx index cffb6014300..1d73df42642 100644 --- a/PWGUD/Tasks/sgSpectraAnalyzer.cxx +++ b/PWGUD/Tasks/sgSpectraAnalyzer.cxx @@ -13,18 +13,19 @@ // \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 "PWGUD/Core/RLhelper.h" -#include +#include "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +#include +// #include "PWGUD/Core/RLhelper.h" #include "TLorentzVector.h" +#include using namespace std; using namespace o2; using namespace o2::aod; diff --git a/PWGUD/Tasks/sgTwoPiAnalyzer.cxx b/PWGUD/Tasks/sgTwoPiAnalyzer.cxx index a9ff6b9e517..7a2c8aefc3c 100644 --- a/PWGUD/Tasks/sgTwoPiAnalyzer.cxx +++ b/PWGUD/Tasks/sgTwoPiAnalyzer.cxx @@ -13,28 +13,48 @@ // \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 "PWGUD/DataModel/UDTables.h" + +#include "Common/DataModel/TrackSelectionTables.h" + #include "Framework/ASoA.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/DataTypes.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" #include "MathUtils/Utils.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include #include "TLorentzVector.h" +#include + +#include 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"}; @@ -129,7 +149,7 @@ struct SGTwoPiAnalyzer { } // Apply pion hypothesis and create pairs // Opposite sign pairs - + rhoByRun(collision.runNumber(), collision.flags(), gapSide, collision.energyCommonZNA(), collision.energyCommonZNC(), v01.Pt(), v01.Eta(), v01.M(), sign); if (sign == 0) { registry.fill(HIST("os_2Pi_pT"), v01.Pt()); registry.fill(HIST("os_2Pi_eTa"), v01.Eta()); diff --git a/PWGUD/Tasks/sginclusivePhiKstarSD.cxx b/PWGUD/Tasks/sginclusivePhiKstarSD.cxx index a7b9e859e10..1800150c1a3 100644 --- a/PWGUD/Tasks/sginclusivePhiKstarSD.cxx +++ b/PWGUD/Tasks/sginclusivePhiKstarSD.cxx @@ -8,601 +8,1639 @@ // In applying this license CERN does 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 Sandeep Dudi, sandeep.dudi3@gmail.com -// \since May 2024 +// +/// \file sginclusivePhiKstarSD.cxx +/// \brief Single Gap Event Analyzer for phi and Kstar +/// \author Sandeep Dudi , Subhadeep Mandal +/// \since May 2024 -#include -#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 "PWGUD/Core/SGTrackSelector.h" -#include "Common/DataModel/PIDResponse.h" +#include "PWGUD/Core/UPCHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Vertex.h" + +#include "Math/GenVector/Boost.h" +#include "Math/Vector3D.h" +#include "Math/Vector4D.h" +#include "TPDGCode.h" +#include #include -#include "TLorentzVector.h" + +#include +#include +#include +#include +#include + 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 -#define mmuon 0.1057 +using namespace o2::constants::physics; + +// GapSide enum +using o2::aod::sgselector::DoubleGap; +using o2::aod::sgselector::SingleGapA; +using o2::aod::sgselector::SingleGapC; -struct SGResonanceAnalyzer { +struct SginclusivePhiKstarSD { SGSelector sgSelector; + Service pdg; + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rQA{"QA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - Configurable FV0_cut{"FV0", 50., "FV0A threshold"}; - Configurable FT0A_cut{"FT0A", 50., "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", 0., "ZDC threshold"}; + 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 useOccCut{"useOccCut", false, "Turn on/off Occupancy cut"}; + Configurable confgOccCut{"confgOccCut", 1000., "Occupancy cut"}; + Configurable useHadronicRateCut{"useHadronicRateCut", false, "Turn on/off hadronicRate cut"}; + Configurable confgHadronicRateMax{"confgHadronicRateMax", 1000., "Maximum hadronicRate cut"}; + Configurable confgHadronicRateMin{"confgHadronicRateMin", 0., "Minimum hadronicRate cut"}; + Configurable useTrs{"useTrs", false, "kNoCollInTimeRangeStandard cut"}; + Configurable useTrofs{"useTrofs", false, "kNoCollInRofStandard cut"}; + Configurable useHmpr{"useHmpr", false, "kNoHighMultCollInPrevRof cut"}; + Configurable useTfb{"useTfb", false, "kNoTimeFrameBorder cut"}; + Configurable useItsrofb{"useItsrofb", false, "kNoITSROFrameBorder cut"}; + Configurable useSbp{"useSbp", false, "kNoSameBunchPileup cut"}; + Configurable useZvtxftovpv{"useZvtxftovpv", false, "kIsGoodZvtxFT0vsPV cut"}; + Configurable useVtxItsTpc{"useVtxItsTpc", false, "kIsVertexITSTPC cut"}; + Configurable usenumContrib{"usenumContrib", false, "numContrib cut for event selection"}; + Configurable upcflag{"upcflag", -1, "upc run selection, -1 = off, 0 = std, 1 = upc"}; + Configurable cutRCTflag{"cutRCTflag", 0, {"0 = off, 1 = CBT, 2 = CBT+ZDC, 3 = CBThadron, 4 = CBThadron+ZDC"}}; // 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.15, "Track pt cut"}; + 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 useMultCut{"useMultCut", false, "Multipicity cut on good tracks"}; - Configurable EtaGapMin{"EtaGapMin", 0.0, "Track eta min"}; - Configurable EtaGapMax{"EtaGapMax", 0.9, "Track eta min"}; - Configurable EtaDG{"EtaDG", 0.5, "Track eta DG"}; + Configurable rapiditycut{"rapiditycut", true, "Rapidity Cut"}; + Configurable rapiditycutvalue{"rapiditycutvalue", 0.5, "Rapidity Cut value"}; - Configurable nsigmatpc_cut{"nsigmatpc", 3.0, "nsigma tpc cut"}; - Configurable nsigmatof_cut{"nsigmatof", 9.0, "nsigma tof cut"}; + 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 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{"min_track", 1, "min track"}; - Configurable maxtrack{"max_track", 50, "max track"}; + Configurable mintrack{"mintrack", 1, "min track"}; + Configurable maxtrack{"maxtrack", 150, "max track"}; + Configurable useTof{"useTof", true, "TOF PID"}; + Configurable ccut{"ccut", true, "TPC + TOF PID"}; + Configurable kaoncut{"kaoncut", false, " kaon slection cut for kstar "}; - Configurable use_tof{"Use_TOF", true, "TOF PID"}; - Configurable QA{"QA", true, ""}; - Configurable rapidity_gap{"rapidity_gap", true, ""}; + Configurable qa{"qa", false, "QA plots for Data (turn qaMC to 0)"}; + Configurable qaMC{"qaMC", false, "QA plots for MC (turn qa for data to 0)"}; + Configurable exclusive{"exclusive", false, "for double gap side "}; Configurable phi{"phi", true, ""}; Configurable rho{"rho", true, ""}; Configurable kstar{"kstar", true, ""}; - void init(InitContext const&) + 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", 40, "40 = PhiA, 44 PhiC, 41 = K*0A, 45 = K*0C"}; + + ConfigurableAxis axisphimass{"axisphimass", {220, 0.98, 1.2}, ""}; + ConfigurableAxis axiskstarmass{"axiskstarmass", {400, 0.0, 2.0}, ""}; + ConfigurableAxis axisrhomass{"axisrhomass", {200, 1.0, 2.0}, ""}; + ConfigurableAxis axispt{"axispt", {200, 0.0, 20.0}, ""}; + ConfigurableAxis axisrapdity{"axisrapdity", {40, -2.0, 2.0}, ""}; + + int numTwoTracks = 2; + int numFourTracks = 4; + + void init(InitContext const& context) { + registry.add("hEventCutFlow", "No. of events after event cuts", kTH1F, {{20, 0, 20}}); + std::shared_ptr hCutFlow = registry.get(HIST("hEventCutFlow")); + + auto check = [](bool enabled) { return enabled ? "" : " #otimes"; }; // check if a cut is enabled and put #otimes if not enabled beside that label + + std::vector eveCutLabels = { + "All Events", + "Gapside (0 to 2)", + Form("|Vz| < %.1f", vzCut.value), + Form("Occupancy < %.0f%s", confgOccCut.value, check(useOccCut.value)), + Form("%.1e < Hadronic Rate < %.1e%s", confgHadronicRateMin.value, confgHadronicRateMax.value, check(useHadronicRateCut.value)), + std::string("kNoCollInTimeRangeStandard") + check(useTrs.value), + std::string("kNoCollInRofStandard") + check(useTrofs.value), + std::string("kNoHighMultCollInPrevRof") + check(useHmpr.value), + std::string("kNoTimeFrameBorder") + check(useTfb.value), + std::string("kNoITSROFrameBorder") + check(useItsrofb.value), + std::string("kNoSameBunchPileup") + check(useSbp.value), + std::string("kIsGoodZvtxFT0vsPV") + check(useZvtxftovpv.value), + std::string("kIsVertexITSTPC") + check(useVtxItsTpc.value), + Form("RCTFlag = %d%s", cutRCTflag.value, check(cutRCTflag.value > 0)), + Form("upcFlag = %d%s", upcflag.value, check(upcflag.value != -1)), + Form("%d < numContrib < %d%s", mintrack.value, maxtrack.value, check(usenumContrib.value))}; + + for (size_t i = 0; i < eveCutLabels.size(); ++i) { + hCutFlow->GetXaxis()->SetBinLabel(i + 1, eveCutLabels[i].c_str()); + } + 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}}); + + registry.add("hRotation", "hRotation", kTH1F, {{360, 0.0, o2::constants::math::TwoPI}}); + if (phi) { - registry.add("os_KK_pT_0", "pt kaon pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {220, 0.9, 1.12}}); - registry.add("os_KK_pT_1", "pt kaon pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {220, 0.9, 1.12}}); - registry.add("os_KK_pT_2", "pt kaon pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {220, 0.9, 1.12}}); - registry.add("os_KK_ls_pT_0", "kaon pair like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {220, 0.9, 1.12}}); - registry.add("os_KK_ls_pT_1", "kaon pair like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {220, 0.9, 1.12}}); - registry.add("os_KK_ls_pT_2", "kaon pair like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {220, 0.9, 1.12}}); + registry.add("os_KK_pT_0", "pt kaon pair", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_pT_1", "pt kaon pair", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_pT_2", "pt kaon pair", kTH3F, {axisphimass, axisrapdity, axispt}); + + registry.add("os_KK_lsMM_pT_0", "kaon pair Negative like sign", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_lsPP_pT_0", "kaon pair Positive like sign", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_lsMM_pT_1", "kaon pair Negative like sign", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_lsPP_pT_1", "kaon pair Positive like sign", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_ls_pT_2", "kaon pair like sign", kTH3F, {axisphimass, axisrapdity, axispt}); + + registry.add("os_KK_mix_pT_0", "kaon pair mix event", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_mix_pT_1", "kaon pair mix event", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_mix_pT_2", "kaon pair mix event", kTH3F, {axisphimass, axisrapdity, axispt}); + + registry.add("os_KK_rot_pT_0", "kaon pair rotional event", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_rot_pT_1", "kaon pair rotional event", kTH3F, {axisphimass, axisrapdity, axispt}); + registry.add("os_KK_rot_pT_2", "kaon pair rotional event", kTH3F, {axisphimass, axisrapdity, axispt}); } if (rho) { - registry.add("os_pp_pT_0", "pt pion pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {350, 0.0, 3.5}}); - registry.add("os_pp_pT_1", "pt pion pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {350, 0.0, 3.5}}); - registry.add("os_pp_pT_2", "pt pion pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {350, 0.0, 3.5}}); - registry.add("os_pp_ls_pT_0", "pion pair like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {350, 0.0, 3.5}}); - registry.add("os_pp_ls_pT_1", "pion pair like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {350, 0.0, 3.5}}); - registry.add("os_pp_ls_pT_2", "pion pair like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {350, 0.0, 3.5}}); + registry.add("os_pp_pT_0", "pt pion pair", kTH3F, {axisrhomass, axisrapdity, axispt}); + registry.add("os_pp_pT_1", "pt pion pair", kTH3F, {axisrhomass, axisrapdity, axispt}); + registry.add("os_pp_pT_2", "pt pion pair", kTH3F, {axisrhomass, axisrapdity, axispt}); + registry.add("os_pp_ls_pT_0", "pion pair like sign", kTH3F, {axisrhomass, axisrapdity, axispt}); + registry.add("os_pp_ls_pT_1", "pion pair like sign", kTH3F, {axisrhomass, axisrapdity, axispt}); + registry.add("os_pp_ls_pT_2", "pion pair like sign", kTH3F, {axisrhomass, axisrapdity, axispt}); } if (kstar) { - registry.add("os_pk_pT_0", "pion-kaon pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {400, 0.0, 2.0}}); - registry.add("os_pk_pT_1", "pion-kaon pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {400, 0.0, 2.0}}); - registry.add("os_pk_pT_2", "pion-kaon pair", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {400, 0.0, 2.0}}); - registry.add("os_pk_ls_pT_0", "pion-kaon pair like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {400, 0.0, 2.0}}); - registry.add("os_pk_ls_pT_1", "pion-kaon like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {400, 0.0, 2.0}}); - registry.add("os_pk_ls_pT_2", "pion-kaon like sign", kTH3F, {{100, 0.0, 10.0}, {80, -2.0, 2.0}, {400, 0.0, 2.0}}); - } - // QA plots - if (QA) { - registry.add("tpc_dedx", "p vs dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); - registry.add("tpc_dedx_kaon", "p#k dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); - registry.add("tpc_dedx_pion", "p#pi dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); - registry.add("tpc_dedx_kaon_1", "tpc+tof pid cut p#k dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); - registry.add("tpc_dedx_kaon_2", "tpc+tof pid cut1 p#k dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.0}}); - registry.add("tpc_dedx_pion_1", "tpc+tof pid cut p#pi dE/dx", kTH2F, {{100, 0.0, 10.0}, {5000, 0.0, 5000.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("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 (rapidity_gap) { - 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("mult_0_pt", "mult0_pt", kTH1F, {{150, 0, 150}}); - registry.add("mult_1_pt", "mult1_pt", kTH1F, {{150, 0, 150}}); - registry.add("mult_2_pt", "mult2_pt", kTH1F, {{150, 0, 150}}); - registry.add("mult_0_pt1", "mult0_pt1", kTH1F, {{150, 0, 150}}); - registry.add("mult_1_pt1", "mult1_pt1", kTH1F, {{150, 0, 150}}); - registry.add("mult_2_pt1", "mult2_pt1", kTH1F, {{150, 0, 150}}); - registry.add("mult_0_pt2", "mult0_pt2", kTH1F, {{150, 0, 150}}); - registry.add("mult_1_pt2", "mult1_pt2", kTH1F, {{150, 0, 150}}); - registry.add("mult_2_pt2", "mult2_pt2", 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("os_pk_pT_0", "pion-kaon pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_pT_1", "pion-kaon pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_pT_2", "pion-kaon pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + + registry.add("os_pk_mix_pT_0", "pion-kaon mix pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_mix_pT_1", "pion-kaon mix pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_mix_pT_2", "pion-kaon mix pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + + registry.add("os_pk_rot_pT_0", "pion-kaon rotional pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_rot_pT_1", "pion-kaon rotional pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_rot_pT_2", "pion-kaon rotional pair", kTH3F, {axiskstarmass, axisrapdity, axispt}); + + registry.add("os_pk_lsMM_pT_0", "pion-kaon pair Negative like sign", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_lsPP_pT_0", "pion-kaon pair Positive like sign", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_lsMM_pT_1", "pion-kaon pair Negative like sign", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_lsPP_pT_1", "pion-kaon pair Positive like sign", kTH3F, {axiskstarmass, axisrapdity, axispt}); + registry.add("os_pk_ls_pT_2", "pion-kaon like sign", kTH3F, {axiskstarmass, axisrapdity, axispt}); + } + // qa plots + if (qa) { + // Occupancy + rQA.add("hOcc_before", "Occupancy distribution before event cuts", kTH1F, {{1000, 0, 50000}}); + rQA.add("hOcc_after", "Occupancy distribution after all event cuts", kTH1F, {{1000, 0, 10000}}); + + // DCA + rQA.add("hDcaxy_all_before", "DCAxy Distribution of all tracks before track selection; DCAxy (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + rQA.add("hDcaz_all_before", "DCAz Distribution of all tracks before track selection; DCAz (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + + rQA.add("hDcaxy_all_after", "DCAxy Distribution of all tracks after track selection; DCAxy (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + rQA.add("hDcaz_all_after", "DCAz Distribution of all tracks after track selection; DCAz (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + + rQA.add("hDcaxy_pi", "DCAxy Distribution of selected pions; DCAxy (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + rQA.add("hDcaz_pi", "DCAz Distribution of selected pions; DCAz (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + + rQA.add("hDcaxy_ka", "DCAxy Distribution of selected kaons; DCAxy (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + rQA.add("hDcaz_ka", "DCAz Distribution of selected kaons; DCAz (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + + // Vx, Vy, Vz + rQA.add("hVertexX", "Vertex X distribution; Vertex X (cm); Counts", kTH1F, {{400, -0.1, 0.1}}); + rQA.add("hVertexY", "Vertex Y distribution; Vertex Y (cm); Counts", kTH1F, {{200, -0.05, 0.05}}); + rQA.add("hVertexZ", "VertexZ distribution; Vertex Z (cm); Counts", kTH1F, {{600, -15.0, 15.0}}); + + // TPC, TOF PID + rQA.add("tpc_dedx", "p vs dE/dx of all particles; #it{p} (GeV/#it{c}); TPC dE/dx (a.u.)", kTH2F, {{500, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + rQA.add("tpc_dedx_kaon", "p vs dE/dx of selected kaons; #it{p} (GeV/#it{c}); TPC dE/dx (a.u.)", kTH2F, {{500, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + rQA.add("tpc_dedx_pion", "p vs dE/dx of selected pions; #it{p} (GeV/#it{c}); TPC dE/dx (a.u.)", kTH2F, {{500, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + rQA.add("tof_beta", "p vs #beta of all particles; #it{p} (GeV/#it{c}); TOF #beta", kTH2F, {{500, 0.0, 10.0}, {500, 0.0, 1.0}}); + rQA.add("tof_beta_kaon", "p vs #beta of selected kaons; #it{p} (GeV/#it{c}); TOF #beta", kTH2F, {{500, 0.0, 10.0}, {500, 0.0, 1.0}}); + rQA.add("tof_beta_pion", "p vs #beta of selected pions; #it{p} (GeV/#it{c}); TOF #beta", kTH2F, {{500, 0.0, 10.0}, {500, 0.0, 1.0}}); + + rQA.add("tpc_nsigma_kaon_all", "Kaon n#sigma_{TPC} of all tracks; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tpc_nsigma_pion_all", "Pion n#sigma_{TPC} of all tracks; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tpc_nsigma_kaon", "Kaon n#sigma_{TPC} of selected kaons; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tpc_nsigma_pion", "Pion n#sigma_{TPC} of selected pions; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + + rQA.add("tof_nsigma_kaon_all", "Kaon n#sigma_{TOF} of all tracks; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tof_nsigma_pion_all", "Pion n#sigma_{TOF} of all tracks; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tof_nsigma_kaon", "Kaon n#sigma_{TOF} of selected kaons; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tof_nsigma_pion", "Pion n#sigma_{TPC} of selected pions; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + + rQA.add("tpc_tof_nsigma_kaon", "n#sigma TPC vs TOF; n#sigma_{TPC}^{K}; n#sigma_{TOF}^{K}", kTH2F, {{100, -10.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tpc_tof_nsigma_pion", "n#sigma TPC vs TOF; n#sigma_{TPC}^{#pi}; n#sigma_{TOF}^{#pi}", kTH2F, {{100, -10.0, 10.0}, {100, -10.0, 10.0}}); + + // Rapidity, pseudorapisdity + rQA.add("hEta_all_after", "Pseudorapidity of all tracks after track selection; #eta; Counts", kTH1F, {{400, -1.0, 1.0}}); + + rQA.add("hEta_ka", "Pseudorapidity of selected Kaons; #eta; Counts", kTH1F, {{400, -1.0, 1.0}}); + rQA.add("hRap_ka", "Rapidity of selected Kaons; y; Counts", kTH1F, {{400, -1.0, 1.0}}); + + rQA.add("hEta_pi", "Pseudorapidity of selected Pions; #eta; Counts", kTH1F, {{400, -1.0, 1.0}}); + rQA.add("hRap_pi", "Rapidity of selected Pions; y; Counts", kTH1F, {{400, -1.0, 1.0}}); + + // Detector Signals + rQA.add("FT0A_2", "T0A amplitude", kTH1F, {{500, 0.0, 500.0}}); + rQA.add("FT0A_0", "T0A amplitude", kTH1F, {{500, 0.0, 500.0}}); + rQA.add("FT0A_1", "T0A amplitude", kTH1F, {{20000, 0.0, 20000.0}}); + rQA.add("FT0C_2", "T0C amplitude", kTH1F, {{500, 0.0, 500.0}}); + rQA.add("FT0C_0", "T0C amplitude", kTH1F, {{20000, 0.0, 20000.0}}); + rQA.add("FT0C_1", "T0C amplitude", kTH1F, {{500, 0.0, 500.0}}); + rQA.add("ZDC_A_2", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("ZDC_A_0", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("ZDC_A_1", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("ZDC_C_2", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("ZDC_C_0", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("ZDC_C_1", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("V0A_2", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + rQA.add("V0A_0", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + rQA.add("V0A_1", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); } 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 (rapidity_gap && phi) { - registry.add("os_kk_mass_rap", "phi mass", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kk_mass_rap1", "phi mass", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kk_mass_rap2", "phi mass", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kk_mass1_rap", "phi mass gap1", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kk_mass1_rap1", "phi mass gap1", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kk_mass1_rap2", "phi mass gap1", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kk_mass2_rap", "phi mass DG", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kk_mass2_rap1", "phi mass DG", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kk_mass2_rap2", "phi mass DG", kTH3F, {{220, 0.98, 1.12}, {80, -2.0, 2.0}, {100, 0, 10}}); - } - - if (rapidity_gap && kstar) { - registry.add("os_kp_mass_rap", "kstar mass", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kp_mass_rap1", "kstar mass", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kp_mass_rap2", "kstar mass", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kp_mass1_rap", "kstar mass gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kp_mass1_rap1", "kstar mass gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kp_mass1_rap2", "kstar mass gap1", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kp_mass2_rap", "kstar mass DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kp_mass2_rap1", "kstar mass DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); - registry.add("os_kp_mass2_rap2", "kstar mass DG", kTH3F, {{400, 0.0, 2.0}, {80, -2.0, 2.0}, {100, 0, 10}}); + + 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}}); + + 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); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{220, 0.98, 1.2}, {200, 0.0, 10.0}}}); + registry.add("MC/genM", "Generated events; Mass (GeV/#it{c}^2)", {HistType::kTH1F, {{220, 0.98, 1.2}}}); + registry.add("MC/genM_1", "Generated events; Mass (GeV/#it{c}^2)", {HistType::kTH1F, {{220, 0.98, 1.2}}}); + + registry.add("MC/accMPtRap_phi_G", "Generated Phi; Mass (GeV/#it{c}^2); #it{p}_{T} (GeV/#it{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); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}}}); + registry.add("MC/accMPtRap", "Generated events in acceptance; Mass (GeV/#it{c}^2); #it{p}_{T} (GeV/#it{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/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{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); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 2.0}, {200, 0.0, 10.0}}}); + registry.add("MC/genM_k", "Generated events; Mass (GeV/#it{c}^2)", {HistType::kTH1F, {{400, 0., 2.0}}}); + registry.add("MC/genM_1_k", "Generated events; Mass (GeV/#it{c}^2)", {HistType::kTH1F, {{400, 0., 2.0}}}); + + registry.add("MC/accEtaPt_k", "Generated events in acceptance; eta (1); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 2.0}, {200, 0.0, 10.0}}}); + registry.add("MC/accMPtRap_k", "Generated events in acceptance; Mass (GeV/#it{c}^2); #it{p}_{T} (GeV/#it{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/#it{c}^2)", {HistType::kTH1F, {{400, 0., 2.0}}}); + } + if (context.mOptions.get("processReco")) { + + registry.add("Reco/hEventCutFlowMC", "No. of events after event cuts in MC", kTH1F, {{20, 0, 20}}); + std::shared_ptr hCutFlowMC = registry.get(HIST("Reco/hEventCutFlowMC")); + + std::vector eveCutLabelsMC = { + "All Events", + "has_udMcCollision", + Form("generatorsID = %d", generatedId.value), + Form("GapsideMC = %d", gapsideMC.value), + Form("|Vz| < %.1f", vzCut.value), + Form("Occupancy < %.0f%s", confgOccCut.value, check(useOccCut.value)), + Form("%.1e < Hadronic Rate < %.1e%s", confgHadronicRateMin.value, confgHadronicRateMax.value, check(useHadronicRateCut.value)), + std::string("kNoCollInTimeRangeStandard") + check(useTrs.value), + std::string("kNoCollInRofStandard") + check(useTrofs.value), + std::string("kNoHighMultCollInPrevRof") + check(useHmpr.value), + std::string("kNoTimeFrameBorder") + check(useTfb.value), + std::string("kNoITSROFrameBorder") + check(useItsrofb.value), + std::string("kNoSameBunchPileup") + check(useSbp.value), + std::string("kIsGoodZvtxFT0vsPV") + check(useZvtxftovpv.value), + std::string("kIsVertexITSTPC") + check(useVtxItsTpc.value), + Form("RCTFlag = %d%s", cutRCTflag.value, check(cutRCTflag.value > 0)), + Form("upcFlag = %d%s", upcflag.value, check(upcflag.value != -1)), + Form("%d < numContrib < %d%s", mintrack.value, maxtrack.value, check(usenumContrib.value))}; + + for (size_t i = 0; i < eveCutLabelsMC.size(); ++i) { + hCutFlowMC->GetXaxis()->SetBinLabel(i + 1, eveCutLabelsMC[i].c_str()); + } + + 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/#it{c}^2); #it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{220, 0.98, 1.20}, {200, 0.0, 10.0}}}); + registry.add("Reco/selMPtRap", "Reconstructed events in acceptance; Mass (GeV/#it{c}^2); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{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;#it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{200, 0.0, 10.0}}}); + registry.add("Reco/selM", "Reconstructed events in acceptance; Mass (GeV/#it{c}^2); ", {HistType::kTH1F, {{220, 0.98, 1.20}}}); + registry.add("Reco/mcEtaPt", "Generated events in acceptance; eta (1); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 2.0}, {200, 0.0, 10.0}}}); + registry.add("Reco/selMPtRap_k", "Reconstructed events in acceptance; Mass (GeV/#it{c}^2); #it{p}_{T} (GeV/#it{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/#it{c}^2); #it{p}_{T} (GeV/#it{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;#it{p}_{T} (GeV/#it{c})", {HistType::kTH1F, {{200, 0.0, 10.0}}}); + registry.add("Reco/selM_k", "Reconstructed events in acceptance; Mass (GeV/#it{c}^2); ", {HistType::kTH1F, {{400, 0., 2.0}}}); + registry.add("Reco/selM_k_K", "Reconstructed events in acceptance; Mass (GeV/#it{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 plots + if (qaMC) { + // Occupancy + rQA.add("hOcc_before_mc", "Occupancy distribution before event cuts", kTH1F, {{1000, 0, 50000}}); + rQA.add("hOcc_after_mc", "Occupancy distribution after all event cuts", kTH1F, {{1000, 0, 10000}}); + + // DCA + rQA.add("hDcaxy_all_before_mc", "DCAxy Distribution of all tracks before track selection; DCAxy (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + rQA.add("hDcaz_all_before_mc", "DCAz Distribution of all tracks before track selection; DCAz (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + + rQA.add("hDcaxy_all_after_mc", "DCAxy Distribution of all tracks after track selection; DCAxy (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + rQA.add("hDcaz_all_after_mc", "DCAz Distribution of all tracks after track selection; DCAz (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + + rQA.add("hDcaxy_pi_mc", "DCAxy Distribution of selected pions; DCAxy (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + rQA.add("hDcaz_pi_mc", "DCAz Distribution of selected pions; DCAz (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + + rQA.add("hDcaxy_ka_mc", "DCAxy Distribution of selected kaons; DCAxy (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + rQA.add("hDcaz_ka_mc", "DCAz Distribution of selected kaons; DCAz (cm); Counts", kTH1F, {{400, -0.2, 0.2}}); + + // Vx, Vy, Vz + rQA.add("hVertexX_mc", "Vertex X distribution; Vertex X (cm); Counts", kTH1F, {{400, -0.1, 0.1}}); + rQA.add("hVertexY_mc", "Vertex Y distribution; Vertex Y (cm); Counts", kTH1F, {{200, -0.05, 0.05}}); + rQA.add("hVertexZ_mc", "VertexZ distribution; Vertex Z (cm); Counts", kTH1F, {{600, -15.0, 15.0}}); + + // TPC, TOF PID + rQA.add("tpc_dedx_mc", "p vs dE/dx of all particles; #it{p} (GeV/#it{c}); TPC dE/dx (a.u.)", kTH2F, {{500, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + rQA.add("tpc_dedx_kaon_mc", "p vs dE/dx of selected kaons; #it{p} (GeV/#it{c}); TPC dE/dx (a.u.)", kTH2F, {{500, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + rQA.add("tpc_dedx_pion_mc", "p vs dE/dx of selected pions; #it{p} (GeV/#it{c}); TPC dE/dx (a.u.)", kTH2F, {{500, 0.0, 10.0}, {5000, 0.0, 5000.0}}); + rQA.add("tof_beta_mc", "p vs #beta of all particles; #it{p} (GeV/#it{c}); TOF #beta", kTH2F, {{500, 0.0, 10.0}, {500, 0.0, 1.0}}); + rQA.add("tof_beta_kaon_mc", "p vs #beta of selected kaons; #it{p} (GeV/#it{c}); TOF #beta", kTH2F, {{500, 0.0, 10.0}, {500, 0.0, 1.0}}); + rQA.add("tof_beta_pion_mc", "p vs #beta of selected pions; #it{p} (GeV/#it{c}); TOF #beta", kTH2F, {{500, 0.0, 10.0}, {500, 0.0, 1.0}}); + + rQA.add("tpc_nsigma_kaon_all_mc", "Kaon n#sigma_{TPC} of all tracks; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tpc_nsigma_pion_all_mc", "Pion n#sigma_{TPC} of all tracks; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tpc_nsigma_kaon_mc", "Kaon n#sigma_{TPC} of selected kaons; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}^{K}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tpc_nsigma_pion_mc", "Pion n#sigma_{TPC} of selected pions; #it{p}_{T} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + + rQA.add("tof_nsigma_kaon_all_mc", "Kaon n#sigma_{TOF} of all tracks; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tof_nsigma_pion_all_mc", "Pion n#sigma_{TOF} of all tracks; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tof_nsigma_kaon_mc", "Kaon n#sigma_{TOF} of selected kaons; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}^{K}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tof_nsigma_pion_mc", "Pion n#sigma_{TPC} of selected pions; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}^{#pi}", kTH2F, {{100, 0.0, 10.0}, {100, -10.0, 10.0}}); + + rQA.add("tpc_tof_nsigma_kaon_mc", "n#sigma TPC vs TOF; n#sigma_{TPC}^{K}; n#sigma_{TOF}^{K}", kTH2F, {{100, -10.0, 10.0}, {100, -10.0, 10.0}}); + rQA.add("tpc_tof_nsigma_pion_mc", "n#sigma TPC vs TOF; n#sigma_{TPC}^{#pi}; n#sigma_{TOF}^{#pi}", kTH2F, {{100, -10.0, 10.0}, {100, -10.0, 10.0}}); + + // Rapidity, pseudorapisdity + rQA.add("hEta_all_after_mc", "Pseudorapidity of all tracks after track selection; #eta; Counts", kTH1F, {{400, -1.0, 1.0}}); + + rQA.add("hEta_ka_mc", "Pseudorapidity of selected Kaons; #eta; Counts", kTH1F, {{400, -1.0, 1.0}}); + rQA.add("hRap_ka_mc", "Rapidity of selected Kaons; y; Counts", kTH1F, {{400, -1.0, 1.0}}); + + rQA.add("hEta_pi_mc", "Pseudorapidity of selected Pions; #eta; Counts", kTH1F, {{400, -1.0, 1.0}}); + rQA.add("hRap_pi_mc", "Rapidity of selected Pions; y; Counts", kTH1F, {{400, -1.0, 1.0}}); + + // Detector signals + rQA.add("FT0A_0_mc", "T0A amplitude", kTH1F, {{500, 0.0, 500.0}}); + rQA.add("FT0A_1_mc", "T0A amplitude", kTH1F, {{20000, 0.0, 20000.0}}); + rQA.add("FT0C_0_mc", "T0C amplitude", kTH1F, {{20000, 0.0, 20000.0}}); + rQA.add("FT0C_1_mc", "T0C amplitude", kTH1F, {{500, 0.0, 500.0}}); + rQA.add("ZDC_A_0_mc", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("ZDC_A_1_mc", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("ZDC_C_0_mc", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("ZDC_C_1_mc", "ZDC amplitude", kTH1F, {{2000, 0.0, 1000.0}}); + rQA.add("V0A_0_mc", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + rQA.add("V0A_1_mc", "V0A amplitude", kTH1F, {{1000, 0.0, 1000.0}}); + } + } } } - using udtracks = soa::Join; - using udtracksfull = soa::Join; - using UDCollisionsFull = soa::Join; // - using UDCollisionFull = UDCollisionsFull::iterator; - void process(UDCollisionFull const& collision, udtracksfull const& tracks) + //_____________________________________________________________________________ + double cosThetaCollinsSoperFrame(ROOT::Math::PxPyPzMVector pair1, + ROOT::Math::PxPyPzMVector pair2, + ROOT::Math::PxPyPzMVector 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; + } + + double phiCollinsSoperFrame(ROOT::Math::PxPyPzMVector pair1, ROOT::Math::PxPyPzMVector pair2, ROOT::Math::PxPyPzMVector 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; + } + + template + bool isGoodRCTflag(const C& coll) { - TLorentzVector v0; - TLorentzVector v1; - TLorentzVector v01; + switch (cutRCTflag) { + case 1: + return sgSelector.isCBTOk(coll); + case 2: + return sgSelector.isCBTZdcOk(coll); + case 3: + return sgSelector.isCBTHadronOk(coll); + case 4: + return sgSelector.isCBTHadronZdcOk(coll); + default: + return true; + } + } + + template + std::pair selectionEvent(const C& collision, bool fillHist = false) + { + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 0); + + // Gapside logic int gapSide = collision.gapSide(); - 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[0], FIT_cut[1], FIT_cut[2], ZDC_cut); - registry.fill(HIST("GapSide"), gapSide); - registry.fill(HIST("TrueGapSide"), truegapSide); + float fitCut[5] = {fv0Cut, ft0aCut, ft0cCut, fddaCut, fddcCut}; + int truegapSide = sgSelector.trueGap(collision, fitCut[0], fitCut[1], fitCut[2], zdcCut); + + if (fillHist) { + registry.fill(HIST("GapSide"), gapSide); + registry.fill(HIST("TrueGapSide"), truegapSide); + } + gapSide = truegapSide; - if (gapSide < 0 || gapSide > 2) + + if (gapSide < SingleGapA || gapSide > DoubleGap) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 1); + + if (std::abs(collision.posZ()) > vzCut) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 2); + + if (useOccCut && (std::abs(collision.occupancyInTime()) > confgOccCut)) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 3); + + if (useHadronicRateCut && (std::abs(collision.hadronicRate()) > confgHadronicRateMax || std::abs(collision.hadronicRate()) < confgHadronicRateMin)) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 4); + + if (useTrs && collision.trs() != 1) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 5); + + if (useTrofs && collision.trofs() != 1) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 6); + + if (useHmpr && collision.hmpr() != 1) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 7); + + if (useTfb && collision.tfb() != 1) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 8); + + if (useItsrofb && collision.itsROFb() != 1) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 9); + + if (useSbp && collision.sbp() != 1) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 10); + + if (useZvtxftovpv && collision.zVtxFT0vPV() != 1) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 11); + + if (useVtxItsTpc && collision.vtxITSTPC() != 1) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 12); + + if (!isGoodRCTflag(collision)) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 13); + + if (upcflag != -1 && collision.flags() != upcflag) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 14); + + if (usenumContrib && (collision.numContrib() < mintrack || collision.numContrib() > maxtrack)) + return {false, gapSide}; + if (fillHist) + registry.fill(HIST("hEventCutFlow"), 15); + + return {true, gapSide}; + } + + 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; + } + + //------------------------------------------------------------------------------------------------------ + + using UDtracksfull = soa::Join; + using UDCollisionsFull = soa::Join; // + using UDCollisionFull = UDCollisionsFull::iterator; + + void process(UDCollisionFull const& collision, UDtracksfull const& tracks) + { + if (qa) + rQA.fill(HIST("hOcc_before"), collision.occupancyInTime()); + + ROOT::Math::PxPyPzMVector v0; + ROOT::Math::PxPyPzMVector v1; + ROOT::Math::PxPyPzMVector v01; + + ROOT::Math::PxPyPzMVector phiv; + ROOT::Math::PxPyPzMVector phiv1; + + std::vector onlyPionTracksp; + std::vector rawPionTracksp; + + std::vector onlyPionTrackspm; + std::vector rawPionTrackspm; + + std::vector onlyPionTracksn; + std::vector rawPionTracksn; + + std::vector parameters = {pvCut, dcazCut, dcaxyCut, tpcChi2Cut, tpcNClsFindableCut, itsChi2Cut, etaCut, ptCut}; + + auto [eventSelected, gapSide] = selectionEvent(collision, true); + if (!eventSelected) return; - Int_t mult = collision.numContrib(); - if (gapSide == 0) { + + int mult = collision.numContrib(); + + if (gapSide == SingleGapA) { registry.fill(HIST("gap_mult0"), mult); } - if (gapSide == 1) { + if (gapSide == SingleGapC) { registry.fill(HIST("gap_mult1"), mult); } - if (gapSide == 2) { + if (gapSide == DoubleGap) { registry.fill(HIST("gap_mult2"), mult); } - if (mult < mintrack || mult > maxtrack) - return; - Int_t mult0 = 0; - Int_t mult1 = 0; - Int_t mult2 = 0; - Int_t mult_pt[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; - Int_t trackgapA = 0; - Int_t trackgapC = 0; - Int_t trackDG = 0; - Int_t trackextra = 0; - Int_t trackextraDG = 0; - for (auto track1 : tracks) { + + if (qa) + rQA.fill(HIST("hOcc_after"), collision.occupancyInTime()); + + int mult0 = 0; + int mult1 = 0; + int mult2 = 0; + if (qa) { + rQA.fill(HIST("hVertexX"), collision.posX()); + rQA.fill(HIST("hVertexY"), collision.posY()); + rQA.fill(HIST("hVertexZ"), collision.posZ()); + } + + for (const auto& track1 : tracks) { + if (qa) { + rQA.fill(HIST("hDcaxy_all_before"), track1.dcaXY()); + rQA.fill(HIST("hDcaz_all_before"), track1.dcaZ()); + } + if (!trackselector(track1, parameters)) continue; - v0.SetXYZM(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassPionCharged); - if (gapSide == 0) { - mult0++; - if (v0.Pt() < 1.0) { - mult_pt[0]++; - } - if (v0.Pt() >= 1.0 && v0.Pt() < 3.0) { - mult_pt[1]++; - } - if (v0.Pt() >= 3.0) { - mult_pt[2]++; - } - } - if (gapSide == 1) { - mult1++; - if (v0.Pt() < 1.0) { - mult_pt[3]++; - } - if (v0.Pt() >= 1.0 && v0.Pt() < 3.0) { - mult_pt[4]++; - } - if (v0.Pt() >= 3.0) { - mult_pt[5]++; - } + + v0.SetCoordinates(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassPionCharged); + + if (qa) { + rQA.fill(HIST("hDcaxy_all_after"), track1.dcaXY()); + rQA.fill(HIST("hDcaz_all_after"), track1.dcaZ()); + rQA.fill(HIST("hEta_all_after"), v0.Eta()); } - if (gapSide == 2) { - mult2++; - if (v0.Pt() < 1.0) { - mult_pt[6]++; - } - if (v0.Pt() >= 1.0 && v0.Pt() < 3.0) { - mult_pt[7]++; + + if (selectionPIDPion1(track1)) { + onlyPionTrackspm.push_back(v0); + rawPionTrackspm.push_back(track1); + if (track1.sign() == 1) { + onlyPionTracksp.push_back(v0); + rawPionTracksp.push_back(track1); } - if (v0.Pt() >= 3.0) { - mult_pt[8]++; + if (track1.sign() == -1) { + onlyPionTracksn.push_back(v0); + rawPionTracksn.push_back(track1); } } - if (TMath::Abs(v0.Eta()) < EtaDG) { - trackDG++; - } - if (v0.Eta() > EtaGapMin && v0.Eta() < EtaGapMax) { - trackgapA++; - } - if (v0.Eta() < EtaGapMin && v0.Eta() > -EtaGapMax) { - trackgapC++; + if (gapSide == SingleGapA) { + mult0++; } - if (TMath::Abs(v0.Eta()) > EtaGapMax || TMath::Abs(v0.Eta()) < EtaGapMin) { - trackextra++; + if (gapSide == SingleGapC) { + mult1++; } - if (TMath::Abs(v0.Eta()) > EtaDG) { - trackextraDG++; + if (gapSide == DoubleGap) { + mult2++; } - if (QA) { - registry.fill(HIST("tpc_dedx"), v0.P(), track1.tpcSignal()); - if (std::abs(track1.tpcNSigmaKa()) < 3.0) { - registry.fill(HIST("tpc_dedx_kaon"), v0.P(), track1.tpcSignal()); - } else if (std::abs(track1.tpcNSigmaPi()) < 3.0) { - registry.fill(HIST("tpc_dedx_pion"), v0.P(), track1.tpcSignal()); - } - if (selectionPIDKaon(track1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { - registry.fill(HIST("tpc_dedx_kaon_1"), v0.P(), track1.tpcSignal()); - registry.fill(HIST("tpc_nsigma_kaon"), v0.Pt(), track1.tpcNSigmaKa()); - registry.fill(HIST("tpc_tof_nsigma_kaon"), track1.tpcNSigmaKa(), track1.tofNSigmaKa()); - } - if (selectionPIDKaon(track1, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(track1.tpcNSigmaPi()) > 3.0) { - registry.fill(HIST("tpc_dedx_kaon_2"), v0.P(), track1.tpcSignal()); + if (qa) { + rQA.fill(HIST("tpc_dedx"), v0.P(), track1.tpcSignal()); + rQA.fill(HIST("tof_beta"), v0.P(), track1.beta()); + rQA.fill(HIST("tof_nsigma_kaon_all"), v0.Pt(), track1.tofNSigmaKa()); + rQA.fill(HIST("tof_nsigma_pion_all"), v0.Pt(), track1.tofNSigmaPi()); + rQA.fill(HIST("tpc_nsigma_kaon_all"), v0.Pt(), track1.tpcNSigmaKa()); + rQA.fill(HIST("tpc_nsigma_pion_all"), v0.Pt(), track1.tpcNSigmaPi()); + + if (selectionPIDKaon1(track1)) { + rQA.fill(HIST("tpc_dedx_kaon"), v0.P(), track1.tpcSignal()); + rQA.fill(HIST("tof_beta_kaon"), v0.P(), track1.beta()); + rQA.fill(HIST("tpc_nsigma_kaon"), v0.Pt(), track1.tpcNSigmaKa()); + rQA.fill(HIST("tof_nsigma_kaon"), v0.Pt(), track1.tofNSigmaKa()); + rQA.fill(HIST("tpc_tof_nsigma_kaon"), track1.tpcNSigmaKa(), track1.tofNSigmaKa()); + rQA.fill(HIST("hEta_ka"), v0.Eta()); + rQA.fill(HIST("hRap_ka"), v0.Rapidity()); + rQA.fill(HIST("hDcaxy_ka"), track1.dcaXY()); + rQA.fill(HIST("hDcaz_ka"), track1.dcaZ()); } - if (selectionPIDPion(track1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { - registry.fill(HIST("tpc_dedx_pion_1"), v0.P(), track1.tpcSignal()); - registry.fill(HIST("tpc_nsigma_pion"), v0.Pt(), track1.tpcNSigmaPi()); - registry.fill(HIST("tpc_tof_nsigma_pion"), track1.tpcNSigmaPi(), track1.tofNSigmaPi()); + + if (selectionPIDPion1(track1)) { + rQA.fill(HIST("tpc_dedx_pion"), v0.P(), track1.tpcSignal()); + rQA.fill(HIST("tof_beta_pion"), v0.P(), track1.beta()); + rQA.fill(HIST("tpc_nsigma_pion"), v0.Pt(), track1.tpcNSigmaPi()); + rQA.fill(HIST("tof_nsigma_pion"), v0.Pt(), track1.tofNSigmaPi()); + rQA.fill(HIST("tpc_tof_nsigma_pion"), track1.tpcNSigmaPi(), track1.tofNSigmaPi()); + rQA.fill(HIST("hEta_pi"), v0.Eta()); + rQA.fill(HIST("hRap_pi"), v0.Rapidity()); + rQA.fill(HIST("hDcaxy_pi"), track1.dcaXY()); + rQA.fill(HIST("hDcaz_pi"), track1.dcaZ()); } } } - 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); - registry.fill(HIST("mult_0_pt"), mult_pt[0]); - registry.fill(HIST("mult_1_pt"), mult_pt[1]); - registry.fill(HIST("mult_2_pt"), mult_pt[2]); - } - 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); - registry.fill(HIST("mult_0_pt1"), mult_pt[3]); - registry.fill(HIST("mult_1_pt1"), mult_pt[4]); - registry.fill(HIST("mult_2_pt1"), mult_pt[5]); + if (gapSide == SingleGapA) { + if (useMultCut && (mult0 < mintrack || mult0 > maxtrack)) + return; + registry.fill(HIST("mult_0"), mult0); + } + if (gapSide == SingleGapC) { + if (useMultCut && (mult1 < mintrack || mult1 > maxtrack)) + return; + registry.fill(HIST("mult_1"), mult1); + } + if (qa) { + if (gapSide == SingleGapA) { + rQA.fill(HIST("V0A_0"), collision.totalFV0AmplitudeA()); + rQA.fill(HIST("FT0A_0"), collision.totalFT0AmplitudeA()); + rQA.fill(HIST("FT0C_0"), collision.totalFT0AmplitudeC()); + rQA.fill(HIST("ZDC_A_0"), collision.energyCommonZNA()); + rQA.fill(HIST("ZDC_C_0"), collision.energyCommonZNC()); } - 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); - registry.fill(HIST("mult_0_pt2"), mult_pt[6]); - registry.fill(HIST("mult_1_pt2"), mult_pt[7]); - registry.fill(HIST("mult_2_pt2"), mult_pt[8]); + if (gapSide == SingleGapC) { + rQA.fill(HIST("V0A_1"), collision.totalFV0AmplitudeA()); + rQA.fill(HIST("FT0A_1"), collision.totalFT0AmplitudeA()); + rQA.fill(HIST("FT0C_1"), collision.totalFT0AmplitudeC()); + rQA.fill(HIST("ZDC_A_1"), collision.energyCommonZNA()); + rQA.fill(HIST("ZDC_C_1"), collision.energyCommonZNC()); } - if (rapidity_gap) { - 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); + } + 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.SetCoordinates(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + if (rapiditycut && std::abs(v01.Rapidity()) > rapiditycutvalue) + continue; + + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == SingleGapA) { + registry.fill(HIST("os_KK_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); } - if (gapSide == 1) { - registry.fill(HIST("event_rap_gap"), 5); - registry.fill(HIST("rap1_mult2"), trackgapA); + if (gapSide == SingleGapC) { + registry.fill(HIST("os_KK_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); } - if (gapSide == 2) { - registry.fill(HIST("event_rap_gap"), 8); - registry.fill(HIST("rap2_mult2"), trackgapA); + if (exclusive && gapSide == DoubleGap && mult2 == numTwoTracks) { + registry.fill(HIST("os_KK_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); } } - if (trackDG > 0 && trackextraDG == 0) { - if (gapSide == 0) { - registry.fill(HIST("event_rap_gap"), 3); - registry.fill(HIST("rap_mult3"), trackDG); + // samesignpair + if (t0.sign() == t1.sign()) { + if (gapSide == SingleGapA) { + if (t0.sign() < 0) + registry.fill(HIST("os_KK_lsMM_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + else + registry.fill(HIST("os_KK_lsPP_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); } - if (gapSide == 1) { - registry.fill(HIST("event_rap_gap"), 6); - registry.fill(HIST("rap1_mult3"), trackDG); + if (gapSide == SingleGapC) { + if (t0.sign() < 0) + registry.fill(HIST("os_KK_lsMM_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + else + registry.fill(HIST("os_KK_lsPP_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); } - if (gapSide == 2) { - registry.fill(HIST("event_rap_gap"), 9); - registry.fill(HIST("rap2_mult3"), trackDG); + if (exclusive && gapSide == DoubleGap && mult2 == numTwoTracks) { + registry.fill(HIST("os_KK_ls_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); } } - } - } - if (rapidity_gap) { - if (trackgapC > 0 && trackgapA == 0 && trackextra == 0) { - for (auto& [t0, t1] : combinations(tracks, tracks)) { - if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) - continue; - if (phi && selectionPIDKaon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && selectionPIDKaon(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { - // 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); + 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.SetCoordinates(rotkaonPx, rotkaonPy, t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassKaonCharged); v01 = v0 + v1; - // Opposite sign pairs + if (rapiditycut && std::abs(v01.Rapidity()) > rapiditycutvalue) + continue; + if (t0.sign() != t1.sign()) { - if (gapSide == 0) { - registry.fill(HIST("os_kk_mass_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + if (gapSide == SingleGapA) { + registry.fill(HIST("os_KK_rot_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); } - if (gapSide == 1) { - registry.fill(HIST("os_kk_mass1_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + if (gapSide == SingleGapC) { + registry.fill(HIST("os_KK_rot_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); } - if (gapSide == 2) { - registry.fill(HIST("os_kk_mass2_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + if (exclusive && gapSide == DoubleGap && mult2 == numTwoTracks) { + registry.fill(HIST("os_KK_rot_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); } } } - if (kstar && selectionPIDKaon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(t0.tpcNSigmaPi()) > 3.0 && selectionPIDPion(t1, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(t1.tpcNSigmaKa()) > 3.0) { - // 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); + } + } + } + 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) && selectionPIDKaon1(t1)) { + v0.SetCoordinates(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassProton); + v1.SetCoordinates(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + if (rapiditycut && std::abs(v01.Rapidity()) > rapiditycutvalue) + continue; + + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == SingleGapA) { + registry.fill(HIST("os_pp_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == SingleGapC) { + registry.fill(HIST("os_pp_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (exclusive && gapSide == DoubleGap && mult2 == numTwoTracks) { + registry.fill(HIST("os_pp_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } // same sign pair + if (t0.sign() == t1.sign()) { + if (gapSide == SingleGapA) { + registry.fill(HIST("os_pp_ls_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == SingleGapC) { + registry.fill(HIST("os_pp_ls_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (exclusive && gapSide == DoubleGap && mult2 == numTwoTracks) { + 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.SetCoordinates(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + if (rapiditycut && std::abs(v01.Rapidity()) > rapiditycutvalue) + continue; + + // Opposite sign pairs + if (t0.sign() != t1.sign()) { + if (gapSide == SingleGapA) { + registry.fill(HIST("os_pk_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == SingleGapC) { + registry.fill(HIST("os_pk_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (exclusive && gapSide == DoubleGap && mult2 == numTwoTracks) { + registry.fill(HIST("os_pk_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); + } + } // same sign pair + if (t0.sign() == t1.sign()) { + if (gapSide == SingleGapA) { + if (t0.sign() < 0) + registry.fill(HIST("os_pk_lsMM_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + else + registry.fill(HIST("os_pk_lsPP_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (gapSide == SingleGapC) { + if (t0.sign() < 0) + registry.fill(HIST("os_pk_lsMM_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + else + registry.fill(HIST("os_pk_lsPP_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); + } + if (exclusive && gapSide == DoubleGap && mult2 == numTwoTracks) { + 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.SetCoordinates(rotkaonPx, rotkaonPy, t0.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); v01 = v0 + v1; - // Opposite sign pairs + if (rapiditycut && std::abs(v01.Rapidity()) > rapiditycutvalue) + continue; + if (t0.sign() != t1.sign()) { - if (gapSide == 0) { - registry.fill(HIST("os_kp_mass_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + if (gapSide == SingleGapA) { + registry.fill(HIST("os_pk_rot_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); } - if (gapSide == 1) { - registry.fill(HIST("os_kp_mass1_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + if (gapSide == SingleGapC) { + registry.fill(HIST("os_pk_rot_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); } - if (gapSide == 2) { - registry.fill(HIST("os_kp_mass2_rap"), v01.M(), v01.Rapidity(), v01.Pt()); + if (exclusive && gapSide == DoubleGap && mult2 == numTwoTracks) { + registry.fill(HIST("os_pk_rot_pT_2"), v01.M(), v01.Rapidity(), v01.Pt()); } } } } } + } + if (fourpion) { + if (gapSide == DoubleGap && mult2 == numFourTracks) { + ROOT::Math::PxPyPzMVector pair1, pair2, pair3, pair4; + if (static_cast(onlyPionTracksp.size()) == numTwoTracks && static_cast(onlyPionTracksn.size()) == numTwoTracks) { + ROOT::Math::PxPyPzMVector k1 = onlyPionTracksp.at(0); + ROOT::Math::PxPyPzMVector k2 = onlyPionTracksp.at(1); + ROOT::Math::PxPyPzMVector k3 = onlyPionTracksn.at(0); + ROOT::Math::PxPyPzMVector 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 (static_cast(onlyPionTracksp.size()) != numTwoTracks && static_cast(onlyPionTracksn.size()) != numTwoTracks) { + if (static_cast(onlyPionTracksp.size()) + static_cast(onlyPionTracksn.size()) != numFourTracks) + return; + ROOT::Math::PxPyPzMVector l1 = onlyPionTrackspm.at(0); + ROOT::Math::PxPyPzMVector l2 = onlyPionTrackspm.at(1); + ROOT::Math::PxPyPzMVector l3 = onlyPionTrackspm.at(2); + ROOT::Math::PxPyPzMVector 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; - if (trackgapC == 0 && trackgapA > 0 && trackextra == 0) { - for (auto& [t0, t1] : combinations(tracks, tracks)) { - if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + 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*/) + { + ROOT::Math::PxPyPzMVector v0; + ROOT::Math::PxPyPzMVector v1; + ROOT::Math::PxPyPzMVector v01; + + 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)) { + + auto [eventSelected1, gapSide1] = selectionEvent(collision1, false); + auto [eventSelected2, gapSide2] = selectionEvent(collision2, false); + if (!eventSelected1 || !eventSelected2) + continue; + + if (gapSide1 != gapSide2) + 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.SetCoordinates(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(track2.px(), track2.py(), track2.pz(), o2::constants::physics::MassKaonCharged); + v01 = v0 + v1; + if (rapiditycut && std::abs(v01.Rapidity()) > rapiditycutvalue) continue; - if (phi && selectionPIDKaon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && selectionPIDKaon(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { - // 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()); - } + // Opposite sign pairs + if (track1.sign() != track2.sign()) { + if (gapSide1 == SingleGapA) { + registry.fill(HIST("os_KK_mix_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); } - } - if (kstar && selectionPIDKaon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(t0.tpcNSigmaPi()) > 3.0 && selectionPIDPion(t1, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(t1.tpcNSigmaKa()) > 3.0) { - // 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 (gapSide1 == SingleGapC) { + registry.fill(HIST("os_KK_mix_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); } } } } - if (trackDG > 0 && trackextraDG == 0) { - for (auto& [t0, t1] : combinations(tracks, tracks)) { - if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + 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.SetCoordinates(track1.px(), track1.py(), track1.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(track2.px(), track2.py(), track2.pz(), o2::constants::physics::MassPionCharged); + v01 = v0 + v1; + if (rapiditycut && std::abs(v01.Rapidity()) > rapiditycutvalue) continue; - if (phi && selectionPIDKaon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && selectionPIDKaon(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { - // 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()); - } + // Opposite sign pairs + if (track1.sign() != track2.sign()) { + if (gapSide1 == SingleGapA) { + registry.fill(HIST("os_pk_mix_pT_0"), v01.M(), v01.Rapidity(), v01.Pt()); } - } - if (kstar && selectionPIDKaon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(t0.tpcNSigmaPi()) > 3.0 && selectionPIDPion(t1, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(t1.tpcNSigmaKa()) > 3.0) { - // 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 (gapSide1 == SingleGapC) { + registry.fill(HIST("os_pk_mix_pT_1"), v01.M(), v01.Rapidity(), v01.Pt()); } } } } } + } + PROCESS_SWITCH(SginclusivePhiKstarSD, mixprocess, "Process Mixed event", false); - for (auto& [t0, t1] : combinations(tracks, tracks)) { - if (!trackselector(t0, parameters) || !trackselector(t1, parameters)) + // 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 + ROOT::Math::PxPyPzMVector v0; + ROOT::Math::PxPyPzMVector v1; + ROOT::Math::PxPyPzMVector v01; + ROOT::Math::PxPyPzMVector vkstar; + ROOT::Math::PxPyPzMVector vphi; + for (const auto& mccollision : mccollisions) { + if (mccollision.generatorsID() != generatedId) continue; - if (phi && selectionPIDKaon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && selectionPIDKaon(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { - // 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.Pt(), v01.Rapidity(), v01.M()); - } - if (gapSide == 1) { - registry.fill(HIST("os_KK_pT_1"), v01.Pt(), v01.Rapidity(), v01.M()); - } - if (gapSide == 2) { - registry.fill(HIST("os_KK_pT_2"), v01.Pt(), v01.Rapidity(), v01.M()); + 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.SetCoordinates(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassPionCharged); + } else { + v0.SetCoordinates(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassPionCharged); + v1.SetCoordinates(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassKaonCharged); } - } - // samesignpair - if (t0.sign() == t1.sign()) { - if (gapSide == 0) { - registry.fill(HIST("os_KK_ls_pT_0"), v01.Pt(), v01.Rapidity(), v01.M()); + 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 (gapSide == 1) { - registry.fill(HIST("os_KK_ls_pT_1"), v01.Pt(), v01.Rapidity(), v01.M()); + 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.SetCoordinates(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 (gapSide == 2) { - registry.fill(HIST("os_KK_ls_pT_2"), v01.Pt(), v01.Rapidity(), v01.M()); + 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 (rho && selectionPIDPion(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && selectionPIDPion(t1, use_tof, nsigmatpc_cut, nsigmatof_cut)) { - v0.SetXYZM(t0.px(), t0.py(), t0.pz(), o2::constants::physics::MassPionCharged); - v1.SetXYZM(t1.px(), t1.py(), t1.pz(), o2::constants::physics::MassPionCharged); + + if (std::abs(tr1.pdgCode()) != kKPlus || std::abs(tr2.pdgCode()) != kKPlus) + continue; + v0.SetCoordinates(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassKaonCharged); + v1.SetCoordinates(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassKaonCharged); + if (tr1.pdgCode() == tr2.pdgCode()) + continue; v01 = v0 + v1; - // Opposite sign pairs - if (t0.sign() != t1.sign()) { - if (gapSide == 0) { - registry.fill(HIST("os_pp_pT_0"), v01.Pt(), v01.Rapidity(), v01.M()); - } - if (gapSide == 1) { - registry.fill(HIST("os_pp_pT_1"), v01.Pt(), v01.Rapidity(), v01.M()); - } - if (gapSide == 2) { - registry.fill(HIST("os_pp_pT_2"), v01.Pt(), v01.Rapidity(), v01.M()); - } - } // same sign pair - if (t0.sign() == t1.sign()) { - if (gapSide == 0) { - registry.fill(HIST("os_pp_ls_pT_0"), v01.Pt(), v01.Rapidity(), v01.M()); - } - if (gapSide == 1) { - registry.fill(HIST("os_pp_ls_pT_1"), v01.Pt(), v01.Rapidity(), v01.M()); + 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.SetCoordinates(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; + } } - if (gapSide == 2) { - registry.fill(HIST("os_pp_ls_pT_2"), v01.Pt(), v01.Rapidity(), v01.M()); + 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.); } - if (kstar && selectionPIDKaon(t0, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(t0.tpcNSigmaPi()) > 3.0 && selectionPIDPion(t1, use_tof, nsigmatpc_cut, nsigmatof_cut) && std::abs(t1.tpcNSigmaKa()) > 3.0) { - 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.Pt(), v01.Rapidity(), v01.M()); - } - if (gapSide == 1) { - registry.fill(HIST("os_pk_pT_1"), v01.Pt(), v01.Rapidity(), v01.M()); + // 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.); } - if (gapSide == 2) { - registry.fill(HIST("os_pk_pT_2"), v01.Pt(), v01.Rapidity(), v01.M()); + } 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*/) + { + registry.fill(HIST("Reco/hEventCutFlowMC"), 0); + + if (!collision.has_udMcCollision()) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 1); + + if (qaMC) + rQA.fill(HIST("hOcc_before_mc"), collision.occupancyInTime()); + + auto mccoll = collision.udMcCollision(); + if (mccoll.generatorsID() != generatedId) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 2); + + 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.); + registry.get(HIST("Reco/Stat"))->Fill(truegapSide, 1.); + if (truegapSide != gapsideMC) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 3); + // Partition pvContributors = aod::udtrack::isPVContributor == true; + // pvContributors.bindTable(tracks); + + if (std::abs(collision.posZ()) > vzCut) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 4); + + if (useOccCut && (std::abs(collision.occupancyInTime()) > confgOccCut)) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 5); + + if (useHadronicRateCut && (std::abs(collision.hadronicRate()) > confgHadronicRateMax || std::abs(collision.hadronicRate()) < confgHadronicRateMin)) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 6); + + if (useTrs && collision.trs() != 1) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 7); + + if (useTrofs && collision.trofs() != 1) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 8); + + if (useHmpr && collision.hmpr() != 1) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 9); + + if (useTfb && collision.tfb() != 1) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 10); + + if (useItsrofb && collision.itsROFb() != 1) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 11); + + if (useSbp && collision.sbp() != 1) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 12); + + if (useZvtxftovpv && collision.zVtxFT0vPV() != 1) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 13); + + if (useVtxItsTpc && collision.vtxITSTPC() != 1) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 14); + + if (!isGoodRCTflag(collision)) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 15); + + if (upcflag != -1 && collision.flags() != upcflag) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 16); + + if (usenumContrib && (collision.numContrib() < mintrack || collision.numContrib() > maxtrack)) + return; + registry.fill(HIST("Reco/hEventCutFlowMC"), 17); + + if (qaMC) + rQA.fill(HIST("hOcc_after_mc"), collision.occupancyInTime()); + + // registry.get(HIST("Reco/nPVContributors"))->Fill(pvContributors.size(), 1.); + ROOT::Math::PxPyPzMVector vphi; + ROOT::Math::PxPyPzMVector vkstar; + ROOT::Math::PxPyPzMVector v0; + ROOT::Math::PxPyPzMVector vr0; + ROOT::Math::PxPyPzMVector vr1; + ROOT::Math::PxPyPzMVector vr01; + ROOT::Math::PxPyPzMVector vr0g; + ROOT::Math::PxPyPzMVector vr1g; + ROOT::Math::PxPyPzMVector vr01g; + int t1 = 0; + if (truegapSide == SingleGapA) { + if (qaMC) { + rQA.fill(HIST("V0A_0_mc"), collision.totalFV0AmplitudeA()); + rQA.fill(HIST("FT0A_0_mc"), collision.totalFT0AmplitudeA()); + rQA.fill(HIST("FT0C_0_mc"), collision.totalFT0AmplitudeC()); + rQA.fill(HIST("ZDC_A_0_mc"), collision.energyCommonZNA()); + rQA.fill(HIST("ZDC_C_0_mc"), collision.energyCommonZNC()); + } + } + if (truegapSide == SingleGapC) { + if (qaMC) { + rQA.fill(HIST("V0A_1_mc"), collision.totalFV0AmplitudeA()); + rQA.fill(HIST("FT0A_1_mc"), collision.totalFT0AmplitudeA()); + rQA.fill(HIST("FT0C_1_mc"), collision.totalFT0AmplitudeC()); + rQA.fill(HIST("ZDC_A_1_mc"), collision.energyCommonZNA()); + rQA.fill(HIST("ZDC_C_1_mc"), collision.energyCommonZNC()); + } + } + for (const auto& tr1 : tracks) { + if (!tr1.has_udMcParticle()) + continue; + auto mcPart1 = tr1.udMcParticle(); + + if (qaMC) { + rQA.fill(HIST("hDcaxy_all_before_mc"), tr1.dcaXY()); + rQA.fill(HIST("hDcaz_all_before_mc"), tr1.dcaZ()); + } + + 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.SetCoordinates(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassPionCharged); + + if (qaMC) { + rQA.fill(HIST("hDcaxy_all_after_mc"), tr1.dcaXY()); + rQA.fill(HIST("hDcaz_all_after_mc"), tr1.dcaZ()); + rQA.fill(HIST("hEta_all_after_mc"), v0.Eta()); + + rQA.fill(HIST("tpc_dedx_mc"), v0.P(), tr1.tpcSignal()); + rQA.fill(HIST("tof_beta_mc"), v0.P(), tr1.beta()); + rQA.fill(HIST("tof_nsigma_kaon_all_mc"), v0.Pt(), tr1.tofNSigmaKa()); + rQA.fill(HIST("tof_nsigma_pion_all_mc"), v0.Pt(), tr1.tofNSigmaPi()); + rQA.fill(HIST("tpc_nsigma_kaon_all_mc"), v0.Pt(), tr1.tpcNSigmaKa()); + rQA.fill(HIST("tpc_nsigma_pion_all_mc"), v0.Pt(), tr1.tpcNSigmaPi()); + } + if (selectionPIDKaon1(tr1)) { + if (qaMC) { + rQA.fill(HIST("tpc_dedx_kaon_mc"), v0.P(), tr1.tpcSignal()); + rQA.fill(HIST("tof_beta_kaon_mc"), v0.P(), tr1.beta()); + rQA.fill(HIST("tpc_nsigma_kaon_mc"), v0.Pt(), tr1.tpcNSigmaKa()); + rQA.fill(HIST("tof_nsigma_kaon_mc"), v0.Pt(), tr1.tofNSigmaKa()); + rQA.fill(HIST("tpc_tof_nsigma_kaon_mc"), tr1.tpcNSigmaKa(), tr1.tofNSigmaKa()); + rQA.fill(HIST("hEta_ka_mc"), v0.Eta()); + rQA.fill(HIST("hRap_ka_mc"), v0.Rapidity()); + rQA.fill(HIST("hDcaxy_ka_mc"), tr1.dcaXY()); + rQA.fill(HIST("hDcaz_ka_mc"), tr1.dcaZ()); + } + } + if (selectionPIDPion1(tr1)) { + if (qaMC) { + rQA.fill(HIST("tpc_dedx_pion_mc"), v0.P(), tr1.tpcSignal()); + rQA.fill(HIST("tof_beta_pion_mc"), v0.P(), tr1.beta()); + rQA.fill(HIST("tpc_nsigma_pion_mc"), v0.Pt(), tr1.tpcNSigmaPi()); + rQA.fill(HIST("tof_nsigma_pion_mc"), v0.Pt(), tr1.tofNSigmaPi()); + rQA.fill(HIST("tpc_tof_nsigma_pion_mc"), tr1.tpcNSigmaPi(), tr1.tofNSigmaPi()); + rQA.fill(HIST("hEta_pi_mc"), v0.Eta()); + rQA.fill(HIST("hRap_pi_mc"), v0.Rapidity()); + rQA.fill(HIST("hDcaxy_pi_mc"), tr1.dcaXY()); + rQA.fill(HIST("hDcaz_pi_mc"), tr1.dcaZ()); + } + } + + t1++; + vr0.SetCoordinates(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.SetCoordinates(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.SetCoordinates(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; + } + } } - } // same sign pair - if (t0.sign() == t1.sign()) { - if (gapSide == 0) { - registry.fill(HIST("os_pk_ls_pT_0"), v01.Pt(), v01.Rapidity(), v01.M()); + vr0g.SetCoordinates(mcPart1.px(), mcPart1.py(), mcPart1.pz(), o2::constants::physics::MassKaonCharged); + vr1g.SetCoordinates(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.); } - if (gapSide == 1) { - registry.fill(HIST("os_pk_ls_pT_1"), v01.Pt(), v01.Rapidity(), v01.M()); + 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.SetCoordinates(tr1.px(), tr1.py(), tr1.pz(), o2::constants::physics::MassPionCharged); + vr1.SetCoordinates(tr2.px(), tr2.py(), tr2.pz(), o2::constants::physics::MassKaonCharged); + vr0g.SetCoordinates(mcPart1.px(), mcPart1.py(), mcPart1.pz(), o2::constants::physics::MassPionCharged); + vr1g.SetCoordinates(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.SetCoordinates(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; + } } - if (gapSide == 2) { - registry.fill(HIST("os_pk_ls_pT_2"), v01.Pt(), v01.Rapidity(), v01.M()); + 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)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGUD/Tasks/testMcStdTabsRl.cxx b/PWGUD/Tasks/testMcStdTabsRl.cxx new file mode 100644 index 00000000000..9748b28784f --- /dev/null +++ b/PWGUD/Tasks/testMcStdTabsRl.cxx @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \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/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" + +// ROOT headers +#include "Math/Vector4D.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}; + + // declare configurables + Configurable useMcgenidGetGeneratorID{"useMcgenidGetGeneratorID", true, {"Use o2::mcgenid::getGeneratorId instead of o2::mccollision::getGeneratorId; default it true."}}; + + struct : ConfigurableGroup { + ConfigurableAxis zzAxisNtracks{"zzAxisNtracks", {100, -0.5, 99.5}, "Number of tracks in collision"}; + ConfigurableAxis zzAxisNparticles{"zzAxisNparticles", {100, -0.5, 99.5}, "Number of particles in collision"}; + ConfigurableAxis zzAxisNprocesses{"zzAxisNprocesses", {1000, -0.5, 999.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) + { + + const auto genID = useMcgenidGetGeneratorID ? o2::mcgenid::getGeneratorId(collision.getGeneratorId()) : collision.getGeneratorId(); + + histos.get(HIST("Events/Truth/hGenIDvsCountCollisions"))->Fill(genID, 1); + histos.get(HIST("Events/Truth/hGenIDvsNparticles"))->Fill(genID, particles.size()); + + ROOT::Math::LorentzVector> mother; + for (const auto& particle : particles) { + histos.get(HIST("Events/Truth/hGenIDvsPDGcodesAll"))->Fill(genID, 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(genID, particle.pdgCode()); + histos.get(HIST("Events/Truth/hGenIDvsMotherMass"))->Fill(genID, mother.M()); + histos.get(HIST("Events/Truth/hGenIDvsMotherPt"))->Fill(genID, particle.pt()); + histos.get(HIST("Events/Truth/hGenIDvsMotherRap"))->Fill(genID, particle.y()); + const auto& daughters = particle.daughters_as(); + histos.get(HIST("Events/Truth/hGenIDvsNdaughters"))->Fill(genID, daughters.size()); + for (const auto& daughter : daughters) { + histos.get(HIST("Events/Truth/hGenIDvsPDGcodesDaughters"))->Fill(genID, 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/upcForward.cxx b/PWGUD/Tasks/upcForward.cxx index 3a3c6ec722d..bebcf0b2be2 100644 --- a/PWGUD/Tasks/upcForward.cxx +++ b/PWGUD/Tasks/upcForward.cxx @@ -18,7 +18,7 @@ for now AO2D.root I am using is #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Common/DataModel/EventSelection.h" -#include "iostream" +#include #include #include #include diff --git a/PWGUD/Tasks/upcJpsiCentralBarrelCorr.cxx b/PWGUD/Tasks/upcJpsiCentralBarrelCorr.cxx deleted file mode 100644 index 3c461999f34..00000000000 --- a/PWGUD/Tasks/upcJpsiCentralBarrelCorr.cxx +++ /dev/null @@ -1,1434 +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, 2.0f, 4.5f}, "M_#it{inv} (GeV/#it{c}^{2})"}; - ConfigurableAxis IVMAxisWide{"IVMAxisWide", {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}"}; - ConfigurableAxis betaTOFAxis{"betaTOFAxis", {100.0f, 0, 1.5}, "TOF #beta"}; - ConfigurableAxis sigmaAxis{"sigmaAxis", {20, -10, 10}, "#sigma"}; - - // configurable cuts (modify in json) - Configurable TPCNClsCrossedRows{"TPCNClsCrossedRows", 70, "number of crossed rows in TPC"}; - Configurable TOFBothTracks{"TOFBothTracks", false, "both candidate tracks have TOF hits"}; - Configurable TOFAtLeastOneTrack{"TOFAtLeastOneTrack", false, "at least candidate tracks has TOF hits"}; - Configurable TOFOneTrack{"TOFOneTrack", false, "one candidate track has TOF hits"}; - 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 TPCNsigmaCut{"TPCNsigmaCut", false, "cut on nSigma"}; - Configurable TPCPIDOnly{"TPCPIDOnly", false, "Only TPC PID"}; - Configurable smallestPID{"smallestPID", false, "Use smallest PID hypo."}; - Configurable DCAcut{"DCAcut", false, "DCA cut from run2."}; - Configurable TPCNSigmaMu{"TPCNSigmaMu", 3, "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", 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 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"}; - - // initialize histogram registry - HistogramRegistry Statistics{ - "Statistics", - {}}; - - HistogramRegistry RawData{ - "RawData", - {}}; - - HistogramRegistry PVContributors{ - "PVContributors", - {}}; - - HistogramRegistry TG{ - "TG", - {}}; - - 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 axisIVMWide{IVMAxisWide, "IVM axis wide"}; - 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, ""}; - const AxisSpec axisBetaTOF{betaTOFAxis, ""}; - const AxisSpec axisSigma{sigmaAxis, ""}; - - // 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}}); - Statistics.add("Statistics/hNumberGTelSigma", "hNumberGTelSigma", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberGTmuSigma", "hNumberGTmuSigma", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberGTpSigma", "hNumberGTpSigma", {HistType::kTH1F, {axisCounter}}); - Statistics.add("Statistics/hNumberGTpSigmaTOF", "hNumberGTpSigmaTOF", {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/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - 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/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - 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}}); - - // TG histograms - TG.add("TG/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axispt}}); - TG.add("TG/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axiseta}}); - TG.add("TG/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); - TG.add("TG/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axispt}}); - TG.add("TG/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axiseta}}); - TG.add("TG/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); - TG.add("TG/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - TG.add("TG/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - TG.add("TG/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - TG.add("TG/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - TG.add("TG/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - TG.add("TG/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - TG.add("TG/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - TG.add("TG/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - TG.add("TG/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - TG.add("TG/TPC/hNsigmaMu", "hNsigmaMu", HistType::kTH1F, {axisSigma}); - TG.add("TG/TPC/hNsigmaEl", "hNsigmaEl", HistType::kTH1F, {axisSigma}); - TG.add("TG/TPC/hNsigmaPr", "hNsigmaPr", HistType::kTH1F, {axisSigma}); - TG.add("TG/TPC/TPCPosSignal", "TPCPosSignal", HistType::kTH1F, {axisTPC}); - TG.add("TG/TPC/TPCNegSignal", "TPCNegSignal", HistType::kTH1F, {axisTPC}); - TG.add("TG/TOF/hNsigmaMu", "hNsigmaMu", HistType::kTH1F, {axisSigma}); - TG.add("TG/TOF/hNsigmaEl", "hNsigmaEl", HistType::kTH1F, {axisSigma}); - TG.add("TG/TOF/hNsigmaPr", "hNsigmaPr", HistType::kTH1F, {axisSigma}); - - // TGmu histograms - TGmu.add("TGmu/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axispt}}); - TGmu.add("TGmu/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axiseta}}); - TGmu.add("TGmu/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); - TGmu.add("TGmu/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axispt}}); - TGmu.add("TGmu/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axiseta}}); - TGmu.add("TGmu/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); - TGmu.add("TGmu/hNsigmaMu", "hNsigmaMu", HistType::kTH1F, {axisSigma}); - TGmu.add("TGmu/hNsigmaMuTOF", "hNsigmaMuTOF", HistType::kTH1F, {axisSigma}); - TGmu.add("TGmu/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - TGmu.add("TGmu/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - TGmu.add("TGmu/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - TGmu.add("TGmu/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - TGmu.add("TGmu/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - TGmu.add("TGmu/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - TGmu.add("TGmu/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - TGmu.add("TGmu/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - TGmu.add("TGmu/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // TGmuCand histograms - TGmuCand.add("TGmuCand/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axispt}}); - TGmuCand.add("TGmuCand/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axiseta}}); - TGmuCand.add("TGmuCand/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); - TGmuCand.add("TGmuCand/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axispt}}); - TGmuCand.add("TGmuCand/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axiseta}}); - TGmuCand.add("TGmuCand/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); - TGmuCand.add("TGmuCand/hTrackITSNcls1", "hTrackITSNcls1", {HistType::kTH1F, {axisCounter}}); - TGmuCand.add("TGmuCand/hTrackITSNcls2", "hTrackITSNcls2", {HistType::kTH1F, {axisCounter}}); - TGmuCand.add("TGmuCand/hPairPt", "hPairPt", {HistType::kTH1F, {axispt}}); - TGmuCand.add("TGmuCand/hPairIVM", "hPairIVM", {HistType::kTH1F, {axisIVMWide}}); - TGmuCand.add("TGmuCand/hJpsiPt", "hJpsiPt", {HistType::kTH1F, {axispt}}); - TGmuCand.add("TGmuCand/hJpsiRap", "hJpsiRap", {HistType::kTH1F, {axiseta}}); - TGmuCand.add("TGmuCand/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - TGmuCand.add("TGmuCand/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - TGmuCand.add("TGmuCand/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - TGmuCand.add("TGmuCand/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - TGmuCand.add("TGmuCand/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - TGmuCand.add("TGmuCand/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - TGmuCand.add("TGmuCand/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - TGmuCand.add("TGmuCand/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - TGmuCand.add("TGmuCand/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // TGel histograms - TGel.add("TGel/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axispt}}); - TGel.add("TGel/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axiseta}}); - TGel.add("TGel/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); - TGel.add("TGel/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axispt}}); - TGel.add("TGel/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axiseta}}); - TGel.add("TGel/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); - TGel.add("TGel/hNsigmaEl", "hNsigmaEl", HistType::kTH1F, {axisSigma}); - TGel.add("TGel/hNsigmaElTOF", "hNsigmaElTOF", HistType::kTH1F, {axisSigma}); - TGel.add("TGel/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - TGel.add("TGel/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - TGel.add("TGel/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - TGel.add("TGel/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - TGel.add("TGel/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - TGel.add("TGel/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - TGel.add("TGel/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - TGel.add("TGel/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - TGel.add("TGel/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // TGelCand histograms - TGelCand.add("TGelCand/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axispt}}); - TGelCand.add("TGelCand/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axiseta}}); - TGelCand.add("TGelCand/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); - TGelCand.add("TGelCand/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axispt}}); - TGelCand.add("TGelCand/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axiseta}}); - TGelCand.add("TGelCand/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); - TGelCand.add("TGelCand/hTrackITSNcls1", "hTrackITSNcls1", {HistType::kTH1F, {axisCounter}}); - TGelCand.add("TGelCand/hTrackITSNcls2", "hTrackITSNcls2", {HistType::kTH1F, {axisCounter}}); - TGelCand.add("TGelCand/hPairPt", "hPairPt", {HistType::kTH1F, {axispt}}); - TGelCand.add("TGelCand/hPairIVM", "hPairIVM", {HistType::kTH1F, {axisIVMWide}}); - TGelCand.add("TGelCand/hJpsiPt", "hJpsiPt", {HistType::kTH1F, {axispt}}); - TGelCand.add("TGelCand/hJpsiRap", "hJpsiRap", {HistType::kTH1F, {axiseta}}); - TGelCand.add("TGelCand/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - TGelCand.add("TGelCand/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - TGelCand.add("TGelCand/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - TGelCand.add("TGelCand/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - TGelCand.add("TGelCand/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - TGelCand.add("TGelCand/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - TGelCand.add("TGelCand/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - TGelCand.add("TGelCand/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - TGelCand.add("TGelCand/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // TGp histograms - TGp.add("TGp/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axispt}}); - TGp.add("TGp/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axiseta}}); - TGp.add("TGp/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); - TGp.add("TGp/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axispt}}); - TGp.add("TGp/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axiseta}}); - TGp.add("TGp/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); - TGp.add("TGp/hNsigmaMu", "hNsigmaMu", HistType::kTH1F, {axisSigma}); - TGp.add("TGp/hNsigmaMuTOF", "hNsigmaMuTOF", HistType::kTH1F, {axisSigma}); - TGp.add("TGp/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - TGp.add("TGp/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - TGp.add("TGp/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - TGp.add("TGp/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - TGp.add("TGp/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - TGp.add("TGp/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - TGp.add("TGp/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - TGp.add("TGp/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - TGp.add("TGp/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // TGpCand histograms - TGpCand.add("TGpCand/hTrackPt1", "hTrackPt1", {HistType::kTH1F, {axispt}}); - TGpCand.add("TGpCand/hTrackEta1", "hTrackEta1", {HistType::kTH1F, {axiseta}}); - TGpCand.add("TGpCand/hTrackPhi1", "hTrackPhi1", {HistType::kTH1F, {axisPhi}}); - TGpCand.add("TGpCand/hTrackPt2", "hTrackPt2", {HistType::kTH1F, {axispt}}); - TGpCand.add("TGpCand/hTrackEta2", "hTrackEta2", {HistType::kTH1F, {axiseta}}); - TGpCand.add("TGpCand/hTrackPhi2", "hTrackPhi2", {HistType::kTH1F, {axisPhi}}); - TGpCand.add("TGpCand/hTrackITSNcls1", "hTrackITSNcls1", {HistType::kTH1F, {axisCounter}}); - TGpCand.add("TGpCand/hTrackITSNcls2", "hTrackITSNcls2", {HistType::kTH1F, {axisCounter}}); - TGpCand.add("TGpCand/hPairPt", "hPairPt", {HistType::kTH1F, {axispt}}); - TGpCand.add("TGpCand/hPairIVM", "hPairIVM", {HistType::kTH1F, {axisIVMWide}}); - TGpCand.add("TGpCand/hJpsiPt", "hJpsiPt", {HistType::kTH1F, {axispt}}); - TGpCand.add("TGpCand/hJpsiRap", "hJpsiRap", {HistType::kTH1F, {axiseta}}); - TGpCand.add("TGpCand/PID/hTPCVsP", "hTPCVsP", {HistType::kTH2F, {axisp, axisTPC}}); - TGpCand.add("TGpCand/PID/hTPCVsPt", "hTPCVsPt", {HistType::kTH2F, {axispt, axisTPC}}); - TGpCand.add("TGpCand/PID/hTPCVsPhi", "hTPCVsPhi", {HistType::kTH2F, {axisPhi, axisTPC}}); - TGpCand.add("TGpCand/PID/hTPCVsEta", "hTPCVsEta", {HistType::kTH2F, {axiseta, axisTPC}}); - TGpCand.add("TGpCand/PID/hTOFVsP", "hTOFVsP", {HistType::kTH2F, {axisp, axisTOF}}); - TGpCand.add("TGpCand/PID/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - TGpCand.add("TGpCand/PID/hTOFVsPt", "hTOFVsPt", {HistType::kTH2F, {axispt, axisTOF}}); - TGpCand.add("TGpCand/PID/hTOFVsPhi", "hTOFVsPhi", {HistType::kTH2F, {axisPhi, axisTOF}}); - TGpCand.add("TGpCand/PID/hTOFVsEta", "hTOFVsEta", {HistType::kTH2F, {axiseta, axisTOF}}); - - // 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/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - 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/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - 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/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - 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/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - 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/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - 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/hBetaTOFVsP", "hBetaTOFVsP", {HistType::kTH2F, {axisp, axisBetaTOF}}); - 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 (DCAcut) { - float dcaXYCut = 0.0105f + 0.0350f / pow(track.pt(), 1.1f); - if (abs(track.dcaXY()) > dcaXYCut) { - return false; - } - } else { - 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 (std::abs(rapJpsi) > RapCut) { - return false; - } - - if (massJpsi < 2.0f) { - 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/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.beta()); - 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/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkPx, trkPy, trkPz), track.beta()); - 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; - int countGTMuSigma = 0; - int countGTElSigma = 0; - int countGTPSigma = 0; - int countGTPSigmaTOF = 0; - std::vector trkIdx; - // loop over tracks with selections - for (auto& track : tracks) { - // select primary vertex contributors - if (track.isPVContributor() != 1) { - continue; - } - // select good tracks - if (GoodTrackCuts(track) != 1) { - continue; - } - countGT++; - trkIdx.push_back(track.index()); - if (smallestPID) { - int hypoID; - if (TPCPIDOnly) { - hypoID = testPIDhypoTPC(track); - } else { - hypoID = testPIDhypo(track); - } - if (hypoID == P_ELECTRON || hypoID == P_MUON || hypoID == P_PROTON) { - 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(3., countGTselected); - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(4., countGTel); - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(5., countGTmu); - - 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); - } - if (std::abs(track.tpcNSigmaMu()) < 3) { - countGTMuSigma++; - } - if (std::abs(track.tpcNSigmaEl()) < 3) { - countGTElSigma++; - } - if (std::abs(track.tpcNSigmaPr()) < 3) { - countGTPSigma++; - } - if (std::abs(track.tofNSigmaPr()) < 3) { - countGTPSigmaTOF++; - } - } - - Statistics.get(HIST("Statistics/hNumberOfTracks"))->Fill(2., countGT); - Statistics.get(HIST("Statistics/hNumberGT"))->Fill(countGT); - Statistics.get(HIST("Statistics/hNumberGTelSigma"))->Fill(countGTElSigma); - Statistics.get(HIST("Statistics/hNumberGTmuSigma"))->Fill(countGTMuSigma); - Statistics.get(HIST("Statistics/hNumberGTpSigma"))->Fill(countGTPSigma); - Statistics.get(HIST("Statistics/hNumberGTpSigmaTOF"))->Fill(countGTPSigmaTOF); - - 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()) > 0) { - 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()}; - - TG.get(HIST("TG/hTrackPt1"))->Fill(trkDaughter1.pt()); - TG.get(HIST("TG/hTrackPt2"))->Fill(trkDaughter2.pt()); - TG.get(HIST("TG/hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); - TG.get(HIST("TG/hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); - TG.get(HIST("TG/hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); - TG.get(HIST("TG/hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); - - if (trkDaughter1.hasTPC()) { - TG.get(HIST("TG/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - TG.get(HIST("TG/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - TG.get(HIST("TG/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - TG.get(HIST("TG/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - TG.get(HIST("TG/TPC/hNsigmaMu"))->Fill(trkDaughter1.tpcNSigmaMu()); - TG.get(HIST("TG/TPC/hNsigmaEl"))->Fill(trkDaughter1.tpcNSigmaEl()); - TG.get(HIST("TG/TPC/hNsigmaPr"))->Fill(trkDaughter1.tpcNSigmaPr()); - if (trkDaughter1.sign() > 0) { - TG.get(HIST("TG/TPC/TPCPosSignal"))->Fill(trkDaughter1.tpcSignal()); - } else { - TG.get(HIST("TG/TPC/TPCNegSignal"))->Fill(trkDaughter1.tpcSignal()); - } - } - if (trkDaughter2.hasTPC()) { - TG.get(HIST("TG/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - TG.get(HIST("TG/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - TG.get(HIST("TG/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - TG.get(HIST("TG/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - TG.get(HIST("TG/TPC/hNsigmaMu"))->Fill(trkDaughter2.tpcNSigmaMu()); - TG.get(HIST("TG/TPC/hNsigmaEl"))->Fill(trkDaughter2.tpcNSigmaEl()); - TG.get(HIST("TG/TPC/hNsigmaPr"))->Fill(trkDaughter2.tpcNSigmaPr()); - if (trkDaughter2.sign() > 0) { - TG.get(HIST("TG/TPC/TPCPosSignal"))->Fill(trkDaughter2.tpcSignal()); - } else { - TG.get(HIST("TG/TPC/TPCNegSignal"))->Fill(trkDaughter2.tpcSignal()); - } - } - if (trkDaughter1.hasTOF()) { - TG.get(HIST("TG/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - TG.get(HIST("TG/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - TG.get(HIST("TG/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - TG.get(HIST("TG/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - TG.get(HIST("TG/TOF/hNsigmaMu"))->Fill(trkDaughter1.tofNSigmaMu()); - TG.get(HIST("TG/TOF/hNsigmaEl"))->Fill(trkDaughter1.tofNSigmaEl()); - TG.get(HIST("TG/TOF/hNsigmaPr"))->Fill(trkDaughter1.tofNSigmaPr()); - } - if (trkDaughter2.hasTOF()) { - TG.get(HIST("TG/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - TG.get(HIST("TG/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - TG.get(HIST("TG/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - TG.get(HIST("TG/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - TG.get(HIST("TG/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - TG.get(HIST("TG/TOF/hNsigmaMu"))->Fill(trkDaughter2.tofNSigmaMu()); - TG.get(HIST("TG/TOF/hNsigmaEl"))->Fill(trkDaughter2.tofNSigmaEl()); - TG.get(HIST("TG/TOF/hNsigmaPr"))->Fill(trkDaughter2.tofNSigmaPr()); - } - - 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()}; - - if (TOFBothTracks) { - if (!trkDaughter1.hasTOF() || !trkDaughter2.hasTOF()) - return; - } - if (TOFOneTrack) { - if ((trkDaughter1.hasTOF() && trkDaughter2.hasTOF()) || (!trkDaughter1.hasTOF() && !trkDaughter2.hasTOF())) - return; - } - if (TOFAtLeastOneTrack) { - if (!trkDaughter1.hasTOF() && !trkDaughter2.hasTOF()) - return; - } - - 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/hTrackPt1"))->Fill(trkDaughter1.pt()); - TGel.get(HIST("TGel/hTrackPt2"))->Fill(trkDaughter2.pt()); - TGel.get(HIST("TGel/hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); - TGel.get(HIST("TGel/hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); - TGel.get(HIST("TGel/hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); - TGel.get(HIST("TGel/hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); - - if (trkDaughter1.hasTPC()) { - TGel.get(HIST("TGel/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - TGel.get(HIST("TGel/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - TGel.get(HIST("TGel/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - TGel.get(HIST("TGel/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - TGel.get(HIST("TGel/hNsigmaEl"))->Fill(trkDaughter1.tpcNSigmaEl()); - } - if (trkDaughter2.hasTPC()) { - TGel.get(HIST("TGel/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - TGel.get(HIST("TGel/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - TGel.get(HIST("TGel/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - TGel.get(HIST("TGel/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - TGel.get(HIST("TGel/hNsigmaEl"))->Fill(trkDaughter2.tpcNSigmaEl()); - } - if (trkDaughter1.hasTOF()) { - TGel.get(HIST("TGel/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - TGel.get(HIST("TGel/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - TGel.get(HIST("TGel/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - TGel.get(HIST("TGel/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - TGel.get(HIST("TGel/hNsigmaElTOF"))->Fill(trkDaughter1.tofNSigmaEl()); - } - if (trkDaughter2.hasTOF()) { - TGel.get(HIST("TGel/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - TGel.get(HIST("TGel/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - TGel.get(HIST("TGel/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - TGel.get(HIST("TGel/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - TGel.get(HIST("TGel/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - TGel.get(HIST("TGel/hNsigmaElTOF"))->Fill(trkDaughter2.tofNSigmaEl()); - } - - if (CandidateCuts(massJpsi, rapJpsi) != 1) { - return; - } - - TGelCand.get(HIST("TGelCand/hTrackPt1"))->Fill(trkDaughter1.pt()); - TGelCand.get(HIST("TGelCand/hTrackPt2"))->Fill(trkDaughter2.pt()); - TGelCand.get(HIST("TGelCand/hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); - TGelCand.get(HIST("TGelCand/hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); - TGelCand.get(HIST("TGelCand/hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); - TGelCand.get(HIST("TGelCand/hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); - TGelCand.get(HIST("TGelCand/hTrackITSNcls1"))->Fill(trkDaughter1.itsNCls()); - TGelCand.get(HIST("TGelCand/hTrackITSNcls2"))->Fill(trkDaughter2.itsNCls()); - TGelCand.get(HIST("TGelCand/hPairPt"))->Fill(RecoDecay::pt(mother)); - TGelCand.get(HIST("TGelCand/hPairIVM"))->Fill(massJpsi); - - if (trkDaughter1.hasTPC()) { - TGelCand.get(HIST("TGelCand/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - TGelCand.get(HIST("TGelCand/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - TGelCand.get(HIST("TGelCand/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - TGelCand.get(HIST("TGelCand/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - TGelCand.get(HIST("TGelCand/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - TGelCand.get(HIST("TGelCand/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - TGelCand.get(HIST("TGelCand/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - TGelCand.get(HIST("TGelCand/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - if (trkDaughter1.hasTOF()) { - TGelCand.get(HIST("TGelCand/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - TGelCand.get(HIST("TGelCand/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - TGelCand.get(HIST("TGelCand/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - TGelCand.get(HIST("TGelCand/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - TGelCand.get(HIST("TGelCand/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - TGelCand.get(HIST("TGelCand/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - TGelCand.get(HIST("TGelCand/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - TGelCand.get(HIST("TGelCand/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - TGelCand.get(HIST("TGelCand/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - } - - if (RecoDecay::pt(mother) < 0.2f) { - JPsiToEl.get(HIST("JPsiToEl/Coherent/hIVM"))->Fill(massJpsi); - } else { - JPsiToEl.get(HIST("JPsiToEl/Incoherent/hIVM"))->Fill(massJpsi); - } - - if (massJpsi < maxJpsiMass && massJpsi > minJpsiMass) { - TGelCand.get(HIST("TGelCand/hJpsiPt"))->Fill(RecoDecay::pt(mother)); - TGelCand.get(HIST("TGelCand/hJpsiRap"))->Fill(rapJpsi); - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - 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/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); - 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/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Coherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - 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); - - 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; - } // end coherent electrons - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - 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/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); - 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/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - JPsiToEl.get(HIST("JPsiToEl/Incoherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - 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); - - 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 incoherent electrons - } // end mass cut - } // end electrons - 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()}; - if (TOFBothTracks) { - if (!trkDaughter1.hasTOF() || !trkDaughter2.hasTOF()) - return; - } - if (TOFOneTrack) { - if ((trkDaughter1.hasTOF() && trkDaughter2.hasTOF()) || (!trkDaughter1.hasTOF() && !trkDaughter2.hasTOF())) - return; - } - if (TOFAtLeastOneTrack) { - if (!trkDaughter1.hasTOF() && !trkDaughter2.hasTOF()) - return; - } - - 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/hTrackPt1"))->Fill(trkDaughter1.pt()); - TGmu.get(HIST("TGmu/hTrackPt2"))->Fill(trkDaughter2.pt()); - TGmu.get(HIST("TGmu/hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); - TGmu.get(HIST("TGmu/hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); - TGmu.get(HIST("TGmu/hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); - TGmu.get(HIST("TGmu/hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); - - if (trkDaughter1.hasTPC()) { - TGmu.get(HIST("TGmu/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - TGmu.get(HIST("TGmu/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - TGmu.get(HIST("TGmu/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - TGmu.get(HIST("TGmu/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - TGmu.get(HIST("TGmu/hNsigmaMu"))->Fill(trkDaughter1.tpcNSigmaMu()); - } - if (trkDaughter2.hasTPC()) { - TGmu.get(HIST("TGmu/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - TGmu.get(HIST("TGmu/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - TGmu.get(HIST("TGmu/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - TGmu.get(HIST("TGmu/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - TGmu.get(HIST("TGmu/hNsigmaMu"))->Fill(trkDaughter2.tpcNSigmaMu()); - } - if (trkDaughter1.hasTOF()) { - TGmu.get(HIST("TGmu/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - TGmu.get(HIST("TGmu/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - TGmu.get(HIST("TGmu/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - TGmu.get(HIST("TGmu/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - TGmu.get(HIST("TGmu/hNsigmaMuTOF"))->Fill(trkDaughter1.tofNSigmaMu()); - } - if (trkDaughter2.hasTOF()) { - TGmu.get(HIST("TGmu/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - TGmu.get(HIST("TGmu/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - TGmu.get(HIST("TGmu/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - TGmu.get(HIST("TGmu/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - TGmu.get(HIST("TGmu/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - TGmu.get(HIST("TGmu/hNsigmaMuTOF"))->Fill(trkDaughter1.tofNSigmaMu()); - } - - if (CandidateCuts(massJpsi, rapJpsi) != 1) { - return; - } - - TGmuCand.get(HIST("TGmuCand/hTrackPt1"))->Fill(trkDaughter1.pt()); - TGmuCand.get(HIST("TGmuCand/hTrackPt2"))->Fill(trkDaughter2.pt()); - TGmuCand.get(HIST("TGmuCand/hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); - TGmuCand.get(HIST("TGmuCand/hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); - TGmuCand.get(HIST("TGmuCand/hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); - TGmuCand.get(HIST("TGmuCand/hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); - TGmuCand.get(HIST("TGmuCand/hTrackITSNcls1"))->Fill(trkDaughter1.itsNCls()); - TGmuCand.get(HIST("TGmuCand/hTrackITSNcls2"))->Fill(trkDaughter2.itsNCls()); - TGmuCand.get(HIST("TGmuCand/hPairPt"))->Fill(RecoDecay::pt(mother)); - TGmuCand.get(HIST("TGmuCand/hPairIVM"))->Fill(massJpsi); - - if (trkDaughter1.hasTPC()) { - TGmuCand.get(HIST("TGmuCand/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - TGmuCand.get(HIST("TGmuCand/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - if (trkDaughter1.hasTOF()) { - TGmuCand.get(HIST("TGmuCand/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - TGmuCand.get(HIST("TGmuCand/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - TGmuCand.get(HIST("TGmuCand/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - TGmuCand.get(HIST("TGmuCand/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - } - - if (RecoDecay::pt(mother) < 0.2f) { - JPsiToMu.get(HIST("JPsiToMu/Coherent/hIVM"))->Fill(massJpsi); - } else { - JPsiToMu.get(HIST("JPsiToMu/Incoherent/hIVM"))->Fill(massJpsi); - } - - if (massJpsi < maxJpsiMass && massJpsi > minJpsiMass) { - TGmuCand.get(HIST("TGmuCand/hJpsiPt"))->Fill(RecoDecay::pt(mother)); - TGmuCand.get(HIST("TGmuCand/hJpsiRap"))->Fill(rapJpsi); - - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - 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()); - } - if (trkDaughter1.hasTOF()) { - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Coherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - } - // 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); - - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - 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()); - } - if (trkDaughter1.hasTOF()) { - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - JPsiToMu.get(HIST("JPsiToMu/Incoherent/PID/hTOFVsPhi"))->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); - - 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 (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); - - TGp.get(HIST("TGp/hTrackPt1"))->Fill(trkDaughter1.pt()); - TGp.get(HIST("TGp/hTrackPt2"))->Fill(trkDaughter2.pt()); - TGp.get(HIST("TGp/hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); - TGp.get(HIST("TGp/hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); - TGp.get(HIST("TGp/hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); - TGp.get(HIST("TGp/hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); - - if (trkDaughter1.hasTPC()) { - TGp.get(HIST("TGp/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - TGp.get(HIST("TGp/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - TGp.get(HIST("TGp/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - TGp.get(HIST("TGp/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - TGp.get(HIST("TGp/hNsigmaMu"))->Fill(trkDaughter1.tpcNSigmaPr()); - } - if (trkDaughter2.hasTPC()) { - TGp.get(HIST("TGp/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - TGp.get(HIST("TGp/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - TGp.get(HIST("TGp/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - TGp.get(HIST("TGp/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - TGp.get(HIST("TGp/hNsigmaMu"))->Fill(trkDaughter2.tpcNSigmaPr()); - } - if (trkDaughter1.hasTOF()) { - TGp.get(HIST("TGp/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - TGp.get(HIST("TGp/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - TGp.get(HIST("TGp/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - TGp.get(HIST("TGp/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - TGp.get(HIST("TGp/hNsigmaMuTOF"))->Fill(trkDaughter1.tofNSigmaPr()); - } - if (trkDaughter2.hasTOF()) { - TGp.get(HIST("TGp/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - TGp.get(HIST("TGp/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - TGp.get(HIST("TGp/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - TGp.get(HIST("TGp/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - TGp.get(HIST("TGp/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - TGp.get(HIST("TGp/hNsigmaMuTOF"))->Fill(trkDaughter2.tofNSigmaPr()); - } - - if (CandidateCuts(massJpsi, rapJpsi) != 1) { - return; - } - - TGpCand.get(HIST("TGpCand/hTrackPt1"))->Fill(trkDaughter1.pt()); - TGpCand.get(HIST("TGpCand/hTrackPt2"))->Fill(trkDaughter2.pt()); - TGpCand.get(HIST("TGpCand/hTrackEta1"))->Fill(RecoDecay::eta(daughter1)); - TGpCand.get(HIST("TGpCand/hTrackEta2"))->Fill(RecoDecay::eta(daughter2)); - TGpCand.get(HIST("TGpCand/hTrackPhi1"))->Fill(RecoDecay::phi(daughter1)); - TGpCand.get(HIST("TGpCand/hTrackPhi2"))->Fill(RecoDecay::phi(daughter2)); - TGpCand.get(HIST("TGpCand/hTrackITSNcls1"))->Fill(trkDaughter1.itsNCls()); - TGpCand.get(HIST("TGpCand/hTrackITSNcls2"))->Fill(trkDaughter2.itsNCls()); - TGpCand.get(HIST("TGpCand/hPairPt"))->Fill(RecoDecay::pt(mother)); - TGpCand.get(HIST("TGpCand/hPairIVM"))->Fill(massJpsi); - - if (trkDaughter1.hasTPC()) { - TGpCand.get(HIST("TGpCand/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - TGpCand.get(HIST("TGpCand/PID/hTPCVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tpcSignal()); - TGpCand.get(HIST("TGpCand/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tpcSignal()); - TGpCand.get(HIST("TGpCand/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tpcSignal()); - } - if (trkDaughter2.hasTPC()) { - TGpCand.get(HIST("TGpCand/PID/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - TGpCand.get(HIST("TGpCand/PID/hTPCVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tpcSignal()); - TGpCand.get(HIST("TGpCand/PID/hTPCVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tpcSignal()); - TGpCand.get(HIST("TGpCand/PID/hTPCVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tpcSignal()); - } - if (trkDaughter1.hasTOF()) { - TGpCand.get(HIST("TGpCand/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - TGpCand.get(HIST("TGpCand/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - TGpCand.get(HIST("TGpCand/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - TGpCand.get(HIST("TGpCand/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - TGpCand.get(HIST("TGpCand/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - TGpCand.get(HIST("TGpCand/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - TGpCand.get(HIST("TGpCand/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - TGpCand.get(HIST("TGpCand/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - TGpCand.get(HIST("TGpCand/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - } - - if (RecoDecay::pt(mother) < 0.2f) { - JPsiToP.get(HIST("JPsiToP/Coherent/hIVM"))->Fill(massJpsi); - } else { - JPsiToP.get(HIST("JPsiToP/Incoherent/hIVM"))->Fill(massJpsi); - } - - if (massJpsi < maxJpsiMass && massJpsi > minJpsiMass) { - TGpCand.get(HIST("TGpCand/hJpsiPt"))->Fill(RecoDecay::pt(mother)); - TGpCand.get(HIST("TGpCand/hJpsiRap"))->Fill(rapJpsi); - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - 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()); - } - if (trkDaughter1.hasTOF()) { - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Coherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - } - // 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); - } // end coherent - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tpcSignal()); - 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/hTPCVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tpcSignal()); - 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()); - } - if (trkDaughter1.hasTOF()) { - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter1.px(), trkDaughter1.py(), trkDaughter1.pz()), trkDaughter1.beta()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTOFVsPt"))->Fill(trkDaughter1.pt(), trkDaughter1.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter1), trkDaughter1.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter1), trkDaughter1.tofSignal()); - } - if (trkDaughter2.hasTOF()) { - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hBetaTOFVsP"))->Fill(RecoDecay::sqrtSumOfSquares(trkDaughter2.px(), trkDaughter2.py(), trkDaughter2.pz()), trkDaughter2.beta()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTOFVsPt"))->Fill(trkDaughter2.pt(), trkDaughter2.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTOFVsEta"))->Fill(RecoDecay::eta(daughter2), trkDaughter2.tofSignal()); - JPsiToP.get(HIST("JPsiToP/Incoherent/PID/hTOFVsPhi"))->Fill(RecoDecay::phi(daughter2), trkDaughter2.tofSignal()); - } - // 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); - } // end incoherent - } // end mass cut - } // 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..ad0145dae34 --- /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 "CommonConstants/MathConstants.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Common/Core/RecoDecay.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 index 81834492eca..fd1b467951b 100644 --- a/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx +++ b/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx @@ -8,57 +8,132 @@ // In applying this license CERN does 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" +/// \file upcPhotonuclearAnalysisJMG.cxx +/// \brief Task for photonuclear UPC analysis for azimuthal correlation: selection, histograms and observables. +/// \author Josué Martínez García + +#include "PWGCF/Core/CorrelationContainer.h" +#include "PWGUD/Core/UPCPairCuts.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/UDTables.h" #include "Common/CCDB/EventSelectionParams.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 "PWGUD/DataModel/UDTables.h" -#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/MathConstants.h" +#include "DataFormatsParameters/GRPObject.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/StepTHn.h" +#include "Framework/runDataProcessing.h" + +#include + +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace constants::math; +namespace o2::aod +{ +namespace tree +{ +DECLARE_SOA_COLUMN(PtSideA, ptSideA, std::vector); +DECLARE_SOA_COLUMN(RapSideA, rapSideA, std::vector); +DECLARE_SOA_COLUMN(PhiSideA, phiSideA, std::vector); +DECLARE_SOA_COLUMN(TpcSignalSideA, tpcSignalSideA, std::vector); +DECLARE_SOA_COLUMN(TofSignalSideA, tofSignalSideA, std::vector); +DECLARE_SOA_COLUMN(TpcNSigmaPiSideA, tpcNSigmaPiSideA, std::vector); +DECLARE_SOA_COLUMN(TofNSigmaPiSideA, tofNSigmaPiSideA, std::vector); +DECLARE_SOA_COLUMN(TpcNSigmaKaSideA, tpcNSigmaKaSideA, std::vector); +DECLARE_SOA_COLUMN(TofNSigmaKaSideA, tofNSigmaKaSideA, std::vector); +DECLARE_SOA_COLUMN(PtSideC, ptSideC, std::vector); +DECLARE_SOA_COLUMN(RapSideC, rapSideC, std::vector); +DECLARE_SOA_COLUMN(PhiSideC, phiSideC, std::vector); +DECLARE_SOA_COLUMN(TpcSignalSideC, tpcSignalSideC, std::vector); +DECLARE_SOA_COLUMN(TofSignalSideC, tofSignalSideC, std::vector); +DECLARE_SOA_COLUMN(TpcNSigmaPiSideC, tpcNSigmaPiSideC, std::vector); +DECLARE_SOA_COLUMN(TofNSigmaPiSideC, tofNSigmaPiSideC, std::vector); +DECLARE_SOA_COLUMN(TpcNSigmaKaSideC, tpcNSigmaKaSideC, std::vector); +DECLARE_SOA_COLUMN(TofNSigmaKaSideC, tofNSigmaKaSideC, std::vector); +DECLARE_SOA_COLUMN(NchSideA, nchSideA, int); +DECLARE_SOA_COLUMN(MultiplicitySideA, multiplicitySideA, int); +DECLARE_SOA_COLUMN(NchSideC, nchSideC, int); +DECLARE_SOA_COLUMN(MultiplicitySideC, multiplicitySideC, int); +} // namespace tree +DECLARE_SOA_TABLE(TREE, "AOD", "Tree", + tree::PtSideA, + tree::RapSideA, + tree::PhiSideA, + tree::TpcSignalSideA, + tree::TofSignalSideA, + tree::TpcNSigmaPiSideA, + tree::TofNSigmaPiSideA, + tree::TpcNSigmaKaSideA, + tree::TofNSigmaKaSideA, + tree::PtSideC, + tree::RapSideC, + tree::PhiSideC, + tree::TpcSignalSideC, + tree::TofSignalSideC, + tree::TpcNSigmaPiSideC, + tree::TofNSigmaPiSideC, + tree::TpcNSigmaKaSideC, + tree::TofNSigmaKaSideC, + tree::NchSideA, + tree::MultiplicitySideA, + tree::NchSideC, + tree::MultiplicitySideC); +} // namespace o2::aod -struct upcPhotonuclearAnalysisJMG { +static constexpr float CFGPairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; +constexpr float kThreeHalfPi = 1.5f * PI; +struct UpcPhotonuclearAnalysisJMG { + + Produces tree; 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"}}; + Configurable minMultiplicity{"minMultiplicity", 2, {"Range on multiplicity"}}; + Configurable range1Max{"range1Max", 10, {"Range on multiplicity"}}; + Configurable range2Min{"range2Min", 11, {"Range on multiplicity"}}; + Configurable range2Max{"range2Max", 20, {"Range on multiplicity"}}; + Configurable range3Min{"range3Min", 21, {"Range on multiplicity"}}; + Configurable range3Max{"range3Max", 30, {"Range on multiplicity"}}; + Configurable range4Min{"range4Min", 31, {"Range on multiplicity"}}; + Configurable range4Max{"range4Max", 40, {"Range on multiplicity"}}; + Configurable range5Min{"range5Min", 41, {"Range on multiplicity"}}; + Configurable range5Max{"range5Max", 50, {"Range on multiplicity"}}; + Configurable nEventsMixed{"nEventsMixed", 3, {"Events to be Mixed"}}; + Configurable factorEventsMixed{"factorEventsMixed", 100, {"factorEventsMixed to events mixed"}}; + Configurable myZVtxCut{"myZVtxCut", 10., {"My collision cut"}}; + Configurable myTimeZNACut{"myTimeZNACut", 2., {"My collision cut"}}; + Configurable myTimeZNCCut{"myTimeZNCCut", 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"}}; + Configurable cutGapAMyEnergyZNA{"cutGapAMyEnergyZNA", 0., {"My collision cut. A Gap"}}; + // Configurable cutAGapMyAmplitudeFT0AMax{"cutAGapMyAmplitudeFT0AMax", 200., {"My collision cut. A Gap"}}; + Configurable cutGapAMyEnergyZNC{"cutGapAMyEnergyZNC", 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"}}; + Configurable cutGapCMyEnergyZNA{"cutGapCMyEnergyZNA", 1., {"My collision cut. C Gap"}}; + // Configurable cutCGapMyAmplitudeFT0AMin{"cutCGapMyAmplitudeFT0AMin", 0., {"My collision cut. A Gap"}}; + Configurable cutGapCMyEnergyZNC{"cutGapCMyEnergyZNC", 0., {"My collision cut. C Gap"}}; + // Configurable cutCGapMyAmplitudeFT0CMax{"cutCGapMyAmplitudeFT0CMax", 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 cutMyptMin{"cutMyptMin", 0.2, {"My Track cut"}}; + Configurable cutMyptMax{"cutMyptMax", 3., {"My Track cut"}}; + Configurable cutMyetaMin{"cutMyetaMin", -0.8, {"My Track cut"}}; + Configurable cutMyetaMax{"cutMyetaMax", 0.8, {"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"}}; @@ -72,34 +147,102 @@ struct upcPhotonuclearAnalysisJMG { Configurable cutMyTPCNClsCrossedRowsOverNClsFindableMin{"cutMyTPCNClsCrossedRowsOverNClsFindableMin", 0.8f, {"My Track cut"}}; Configurable cutMyTPCNClsOverFindableNClsMin{"cutMyTPCNClsOverFindableNClsMin", 0.5f, {"My Track cut"}}; Configurable cutMyTPCChi2NclMax{"cutMyTPCChi2NclMax", 4.f, {"My Track cut"}}; + Configurable myWeightMin{"myWeightMin", 0.2f, {"My Track cut"}}; + Configurable myWeightMax{"myWeightMax", 5.f, {"My Track cut"}}; + Configurable myEpsilonToWeight{"myEpsilonToWeight", 1e-6f, {"NUA correction"}}; + Configurable useEpsilon{"useEpsilon", false, {"NUA correction"}}; + Configurable useNMax{"useNMax", true, {"NUA correction"}}; + Configurable> cfgPairCut{"cfgPairCut", + {CFGPairCutDefaults[0], + 5, + {"Photon", "K0", "Lambda", "Phi", "Rho"}}, + "Pair cuts on various particles"}; + Configurable cfgTwoTrackCut{"cfgTwoTrackCut", -1, {"Two track cut"}}; + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {32, -PIHalf, kThreeHalfPi}, "delta phi axis for histograms"}; + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {32, -1.6, 1.6}, "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}, "pt associated axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110.1}, "multiplicity / multiplicity 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"}; + + Filter collisionZVtxFilter = nabs(aod::collision::posZ) < myZVtxCut; + Filter collisionZNTimeFilter = nabs(aod::udzdc::timeZNA) < myTimeZNACut && nabs(aod::udzdc::timeZNC) < myTimeZNCCut; + Filter collisionZNeEnergyFilter = (aod::udzdc::energyCommonZNA < cutGapAMyEnergyZNA && aod::udzdc::energyCommonZNC >= cutGapAMyEnergyZNC) || (aod::udzdc::energyCommonZNA >= cutGapCMyEnergyZNA && aod::udzdc::energyCommonZNC < cutGapCMyEnergyZNC); + Filter collisioSGFilter = aod::udcollision::gapSide == uint8_t(0) || aod::udcollision::gapSide == uint8_t(1); + + using FullSGUDCollision = soa::Filtered>; + using FullUDTracks = soa::Join; - using FullSGUDCollision = soa::Join::iterator; - using FullUDTracks = soa::Join; + // Output definitions + OutputObj same{"sameEvent"}; + OutputObj mixed{"mixedEvent"}; + // OutputObj sameGapSideA{"sameEventGapSideA"}; + // OutputObj mixedGapSideA{"mixedEventGapSideA"}; + // OutputObj sameGapSideC{"sameEventGapSideC"}; + // OutputObj mixedGapSideC{"mixedEventGapSideC"}; + + UPCPairCuts mPairCuts; + bool doPairCuts = false; void init(InitContext const&) { const AxisSpec axisCollision{4, -0.5, 3.5}; - const AxisSpec axisZvtx{40, -20., 20.}; + const AxisSpec axisZvtx{20, -10., 10.}; 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 axisPhi{64, 0., TwoPI}; + const AxisSpec axisEta{32, -0.8, 0.8}; + const AxisSpec axisNch{601, -0.5, 600.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}; + const AxisSpec axisCountTracks{17, -0.5, 16.5}; + + histos.add("yields", "multiplicity vs pT vs eta", {HistType::kTH3F, {{100, 0, 100, "multiplicity"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); + histos.add("etaphi", "multiplicity vs eta vs phi", {HistType::kTH3F, {{100, 0, 100, "multiplicity"}, {100, -2, 2, "#eta"}, {64, 0., TwoPI, "#varphi"}}}); + histos.add("etaphiVtx", "vertex Z vs eta vs phi", {HistType::kTH3F, {{20, -10., 10., "vertex Z"}, {32, -0.8, 0.8, "#eta"}, {64, 0., TwoPI, "#varphi"}}}); + histos.add("sameEvent2D", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_2_10", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_11_20", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_21_30", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_31_40", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("sameEvent_41_50", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent2D", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_2_10", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_11_20", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_21_30", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_31_40", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + histos.add("mixedEvent_41_50", "#Delta #eta vs #Delta #phi", {HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}}); + const int maxMixBin = axisMultiplicity->size() * axisVertex->size(); + histos.add("eventcount", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); + mPairCuts.setHistogramRegistry(&histos); + if (cfgPairCut->get("Photon") > 0 || cfgPairCut->get("K0") > 0 || cfgPairCut->get("Lambda") > 0 || + cfgPairCut->get("Phi") > 0 || cfgPairCut->get("Rho") > 0) { + mPairCuts.setPairCut(UPCPairCuts::Photon, cfgPairCut->get("Photon")); + mPairCuts.setPairCut(UPCPairCuts::K0, cfgPairCut->get("K0")); + mPairCuts.setPairCut(UPCPairCuts::Lambda, cfgPairCut->get("Lambda")); + mPairCuts.setPairCut(UPCPairCuts::Phi, cfgPairCut->get("Phi")); + mPairCuts.setPairCut(UPCPairCuts::Rho, cfgPairCut->get("Rho")); + doPairCuts = true; + } histos.add("Events/hCountCollisions", "0 total - 1 side A - 2 side C - 3 both side; Number of analysed collision; counts", kTH1F, {axisCollision}); + histos.add("Events/hCountCollisionsMixed", "0 total - 1 side A - 2 side C - 3 both side; Number of analysed collision; counts", kTH1F, {axisCollision}); + histos.add("Tracks/hTracksAfterCuts", " ; ; counts", kTH1F, {axisCountTracks}); // 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/hTrackTOFSignnalP", "#it{TOF signal vs p}; #it{p*charge}; #it{TOF signal}", 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}); @@ -112,8 +255,9 @@ struct upcPhotonuclearAnalysisJMG { 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/hZVtx", "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/hMultiplicity", "#it{Multiplicity} distribution; #it{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}); @@ -123,12 +267,14 @@ struct upcPhotonuclearAnalysisJMG { 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.add("Events/SGsideA/hTrackPV", "#it{Nch vs Nch(PV)}; #it{N_{ch}(PV)}; #it{N_{ch}}", kTH2F, {axisNch, axisNch}); // 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/hTrackTOFSignnalP", "#it{TOF signal vs p}; #it{p*charge}; #it{TOF signal}", 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}); @@ -141,8 +287,9 @@ struct upcPhotonuclearAnalysisJMG { 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/hZVtx", "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/hMultiplicity", "#it{Multiplicity} distribution; #it{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}); @@ -152,80 +299,83 @@ struct upcPhotonuclearAnalysisJMG { 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.add("Events/SGsideC/hTrackPV", "#it{Nch vs Nch(PV)}; #it{N_{ch}(PV)}; #it{N_{ch}}", kTH2F, {axisNch, axisNch}); - // 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}); + std::vector corrAxis = {{axisDeltaEta, "#Delta#eta"}, + {axisPtAssoc, "p_{T} (GeV/c)"}, + {axisPtTrigger, "p_{T} (GeV/c)"}, + {axisMultiplicity, "multiplicity / multiplicity"}, + {axisDeltaPhi, "#Delta#varphi (rad)"}, + {axisVertex, "z-vtx (cm)"}}; + std::vector effAxis = {{axisEtaEfficiency, "#eta"}, + {axisEtaEfficiency, "#eta"}, + {axisPtEfficiency, "p_{T} (GeV/c)"}, + {axisVertexEfficiency, "z-vtx (cm)"}}; + same.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, {})); + mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, {})); + // sameGapSideA.setObject(new CorrelationContainer("sameEventGapSideA", "sameEventGapSideA", corrAxis, effAxis, {})); + // mixedGapSideA.setObject(new CorrelationContainer("mixedEventGapSideA", "mixedEventGapSideA", corrAxis, effAxis, {})); + // sameGapSideC.setObject(new CorrelationContainer("sameEventGapSideC", "sameEventGapSideC", corrAxis, effAxis, {})); + // mixedGapSideC.setObject(new CorrelationContainer("mixedEventGapSideC", "mixedEventGapSideC", corrAxis, effAxis, {})); } - 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; - } + std::vector vtxBinsEdges{VARIABLE_WIDTH, -10.0f, -7.0f, -5.0f, -2.5f, 0.0f, 2.5f, 5.0f, 7.0f, 10.0f}; + std::vector gapSideBinsEdges{VARIABLE_WIDTH, -0.5, 0.5, 1.5}; + + struct SameEventTag { + }; + struct MixedEventTag { + }; + + SliceCache cache; + // int countEvents = 0; + // int countGapA = 0; + // int countGapC = 0; + + // Binning only on PosZ without multiplicity + using BinningType = ColumnBinningPolicy; + // BinningType bindingOnVtx{{vtxBinsEdges, gapSideBinsEdges}, true}; + // using BinningType = ColumnBinningPolicy; + // BinningType bindingOnVtx{{vtxBinsEdges}, true}; + // SameKindPair pairs{bindingOnVtx, nEventsMixed, -1, &cache}; template bool isCollisionCutSG(CSG const& collision, int SideGap) { + bool gapSideA = (collision.energyCommonZNA() < cutGapAMyEnergyZNA) && (collision.energyCommonZNC() >= cutGapAMyEnergyZNC); + bool gapSideC = (collision.energyCommonZNA() >= cutGapCMyEnergyZNA) && (collision.energyCommonZNC() < cutGapCMyEnergyZNC); + 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; - } + case 0: // Gap in A side + return gapSideA; // 0n - A side && Xn - C Side + // 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; - } + case 1: // Gap in C side + return gapSideC; // Xn - A side && 0n - C Side + // 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; - } + default: + return false; break; } - return true; + } + + template + bool isCollisionCutSG(CSG const& collision) + { + return isCollisionCutSG(collision, 0) || isCollisionCutSG(collision, 1); } template bool isTrackCut(T const& track) { + if (track.sign() != 1 && track.sign() != -1) { + return false; + } if (track.pt() < cutMyptMin || track.pt() > cutMyptMax) { return false; } @@ -245,6 +395,9 @@ struct upcPhotonuclearAnalysisJMG { return false; } } + if (track.isPVContributor() == false) { + return false; + } // Quality Track // ITS if (cutMyHasITS && !track.hasITS()) { @@ -281,19 +434,129 @@ struct upcPhotonuclearAnalysisJMG { return true; } - void processSG(FullSGUDCollision const& reconstructedCollision, FullUDTracks const& reconstructedTracks) + template + void fillQAUD(const TTracks tracks, float multiplicity) + { + for (const auto& track : tracks) { + if (isTrackCut(track) == false) { + continue; + } + float phiVal = RecoDecay::constrainAngle(phi(track.px(), track.py()), 0.f); + histos.fill(HIST("yields"), multiplicity, track.pt(), eta(track.px(), track.py(), track.pz())); + histos.fill(HIST("etaphi"), multiplicity, eta(track.px(), track.py(), track.pz()), phiVal); + } + } + + template + bool fillCollisionUD(TTarget target, float multiplicity) + { + target->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); + target->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + return true; + } + + template + void fillCorrelationsUD(TTarget target, const TTracks& tracks1, const TTracks& tracks2, float multiplicity, float posZ, TTag) + { + for (const auto& track1 : tracks1) { + if (isTrackCut(track1) == false) { + return; + } + float phi1 = phi(track1.px(), track1.py()); + phi1 = RecoDecay::constrainAngle(phi1, 0.f); + float eta1 = eta(track1.px(), track1.py(), track1.pz()); + target->getTriggerHist()->Fill(CorrelationContainer::kCFStepReconstructed, track1.pt(), multiplicity, posZ, 1.0); + for (const auto& track2 : tracks2) { + if (track1 == track2) { + continue; + } + if (isTrackCut(track2) == false) { + return; + } + float phi2 = phi(track2.px(), track2.py()); + phi2 = RecoDecay::constrainAngle(phi2, 0.f); + float eta2 = eta(track2.px(), track2.py(), track2.pz()); + /*if (doPairCuts && mPairCuts.conversionCuts(track1, track2)) { + continue; + }*/ + float deltaPhi = phi1 - phi2; + float deltaEta = eta1 - eta2; + deltaPhi = RecoDecay::constrainAngle(deltaPhi, -PIHalf); + target->getPairHist()->Fill(CorrelationContainer::kCFStepReconstructed, + deltaEta, + track2.pt(), track1.pt(), + multiplicity, + deltaPhi, + posZ); + if constexpr (std::is_same_v) { + if (minMultiplicity <= multiplicity) { + histos.fill(HIST("sameEvent2D"), deltaEta, deltaPhi); + } + if (minMultiplicity <= multiplicity && multiplicity <= range1Max) { + histos.fill(HIST("sameEvent_2_10"), deltaEta, deltaPhi); + } + if (range2Min <= multiplicity && multiplicity <= range2Max) { + histos.fill(HIST("sameEvent_11_20"), deltaEta, deltaPhi); + } + if (range3Min <= multiplicity && multiplicity <= range3Max) { + histos.fill(HIST("sameEvent_21_30"), deltaEta, deltaPhi); + } + if (range4Min <= multiplicity && multiplicity <= range4Max) { + histos.fill(HIST("sameEvent_31_40"), deltaEta, deltaPhi); + } + if (range5Min <= multiplicity && multiplicity <= range5Max) { + histos.fill(HIST("sameEvent_41_50"), deltaEta, deltaPhi); + } + } else if constexpr (std::is_same_v) { + if (minMultiplicity <= multiplicity) { + histos.fill(HIST("mixedEvent2D"), deltaEta, deltaPhi); + } + if (minMultiplicity <= multiplicity && multiplicity <= range1Max) { + histos.fill(HIST("mixedEvent_2_10"), deltaEta, deltaPhi); + } + if (range2Min <= multiplicity && multiplicity <= range2Max) { + histos.fill(HIST("mixedEvent_11_20"), deltaEta, deltaPhi); + } + if (range3Min <= multiplicity && multiplicity <= range3Max) { + histos.fill(HIST("mixedEvent_21_30"), deltaEta, deltaPhi); + } + if (range4Min <= multiplicity && multiplicity <= range4Max) { + histos.fill(HIST("mixedEvent_31_40"), deltaEta, deltaPhi); + } + if (range5Min <= multiplicity && multiplicity <= range5Max) { + histos.fill(HIST("mixedEvent_41_50"), deltaEta, deltaPhi); + } + } + } + } + } + + void processSG(FullSGUDCollision::iterator const& reconstructedCollision, FullUDTracks const& reconstructedTracks) { histos.fill(HIST("Events/hCountCollisions"), 0); - int SGside = reconstructedCollision.gapSide(); + int sgSide = reconstructedCollision.gapSide(); int nTracksCharged = 0; float sumPt = 0; + int nchPVGapSideA = 0; + int nchPVGapSideC = 0; + int nchGapSideA = 0; + int nchGapSideC = 0; + std::vector vTrackPtSideA, vTrackEtaSideA, vTrackPhiSideA, vTrackTPCSignalSideA, vTrackTOFSignalSideA, vTrackTPCNSigmaPiSideA, vTrackTOFNSigmaPiSideA, vTrackTPCNSigmaKaSideA, vTrackTOFNSigmaKaSideA; + std::vector vTrackPtSideC, vTrackEtaSideC, vTrackPhiSideC, vTrackTPCSignalSideC, vTrackTOFSignalSideC, vTrackTPCNSigmaPiSideC, vTrackTOFNSigmaPiSideC, vTrackTPCNSigmaKaSideC, vTrackTOFNSigmaKaSideC; - if (isGlobalCollisionCut(reconstructedCollision) == false) { - return; + int nTracksChargedSideA(-222), nTracksChargedSideC(-222); + int multiplicitySideA(-222), multiplicitySideC(-222); + + for (const auto& track : reconstructedTracks) { + if (isTrackCut(track) == false) { + continue; + } + float phiVal = RecoDecay::constrainAngle(phi(track.px(), track.py()), 0.f); + histos.fill(HIST("etaphiVtx"), reconstructedCollision.posZ(), eta(track.px(), track.py(), track.pz()), phiVal); } - switch (SGside) { - case 0: // for side A + switch (sgSide) { + case 0: // gap for side A if (isCollisionCutSG(reconstructedCollision, 0) == false) { return; } @@ -304,39 +567,57 @@ struct upcPhotonuclearAnalysisJMG { 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/hZVtx"), 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()); + for (const auto& track : reconstructedTracks) { + // LOGF(debug, "Filling tracks. Gap Side A"); + ++nchGapSideA; + if (track.isPVContributor() == true) { + ++nchPVGapSideA; + } + if (isTrackCut(track) == false) { + continue; } + nTracksCharged++; + sumPt += track.pt(); + float phiVal = RecoDecay::constrainAngle(phi(track.px(), track.py()), 0.f); + histos.fill(HIST("Tracks/SGsideA/hTrackPt"), track.pt()); + histos.fill(HIST("Tracks/SGsideA/hTrackPhi"), phiVal); + 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/hTrackTOFSignnalP"), momentum(track.px(), track.py(), track.pz()) * track.sign(), track.tofSignal()); + vTrackPtSideA.push_back(track.pt()); + vTrackEtaSideA.push_back(eta(track.px(), track.py(), track.pz())); + vTrackPhiSideA.push_back(phiVal); + vTrackTPCSignalSideA.push_back(track.tpcSignal()); + vTrackTOFSignalSideA.push_back(track.tofSignal()); + vTrackTPCNSigmaPiSideA.push_back(track.tpcNSigmaPi()); + vTrackTOFNSigmaPiSideA.push_back(track.tofNSigmaPi()); + vTrackTPCNSigmaKaSideA.push_back(track.tpcNSigmaKa()); + vTrackTOFNSigmaKaSideA.push_back(track.tofNSigmaKa()); + + 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/hMultiplicity"), reconstructedTracks.size()); histos.fill(HIST("Events/SGsideA/hPtVSNch"), nTracksCharged, (sumPt / nTracksCharged)); + histos.fill(HIST("Events/SGsideA/hTrackPV"), nchPVGapSideA, nchGapSideA); + nTracksChargedSideA = nTracksCharged; + multiplicitySideA = reconstructedTracks.size(); nTracksCharged = sumPt = 0; break; - case 1: // for side C + case 1: // gap for side C if (isCollisionCutSG(reconstructedCollision, 1) == false) { return; } @@ -347,86 +628,330 @@ struct upcPhotonuclearAnalysisJMG { 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/hZVtx"), 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()); + for (const auto& track : reconstructedTracks) { + ++nchGapSideC; + if (track.isPVContributor() == true) { + ++nchPVGapSideC; + } + if (isTrackCut(track) == false) { + continue; } + nTracksCharged++; + sumPt += track.pt(); + float phiVal = RecoDecay::constrainAngle(phi(track.px(), track.py()), 0.f); + histos.fill(HIST("Tracks/SGsideC/hTrackPt"), track.pt()); + histos.fill(HIST("Tracks/SGsideC/hTrackPhi"), phiVal); + 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/hTrackTOFSignnalP"), momentum(track.px(), track.py(), track.pz()) * track.sign(), track.tofSignal()); + vTrackPtSideC.push_back(track.pt()); + vTrackEtaSideC.push_back(eta(track.px(), track.py(), track.pz())); + vTrackPhiSideC.push_back(phiVal); + vTrackTPCSignalSideC.push_back(track.tpcSignal()); + vTrackTOFSignalSideC.push_back(track.tofSignal()); + vTrackTPCNSigmaPiSideC.push_back(track.tpcNSigmaPi()); + vTrackTOFNSigmaPiSideC.push_back(track.tofNSigmaPi()); + vTrackTPCNSigmaKaSideC.push_back(track.tpcNSigmaKa()); + vTrackTOFNSigmaKaSideC.push_back(track.tofNSigmaKa()); + + 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/hMultiplicity"), reconstructedTracks.size()); histos.fill(HIST("Events/SGsideC/hPtVSNch"), nTracksCharged, (sumPt / nTracksCharged)); + histos.fill(HIST("Events/SGsideC/hTrackPV"), nchPVGapSideC, nchGapSideC); + nTracksChargedSideC = nTracksCharged; + multiplicitySideC = reconstructedTracks.size(); nTracksCharged = sumPt = 0; break; - case 2: // for both sides - if (isCollisionCutSG(reconstructedCollision, 2) == false) { + default: + return; + break; + } + tree(vTrackPtSideA, vTrackEtaSideA, vTrackPhiSideA, vTrackTPCSignalSideA, vTrackTOFSignalSideA, vTrackTPCNSigmaPiSideA, vTrackTOFNSigmaPiSideA, vTrackTPCNSigmaKaSideA, vTrackTOFNSigmaKaSideA, vTrackPtSideC, vTrackEtaSideC, vTrackPhiSideC, vTrackTPCSignalSideA, vTrackTOFSignalSideA, vTrackTPCNSigmaPiSideA, vTrackTOFNSigmaPiSideA, vTrackTPCNSigmaKaSideA, vTrackTOFNSigmaKaSideA, nTracksChargedSideA, multiplicitySideA, nTracksChargedSideC, multiplicitySideC); + // nTracksChargedSideA = nTracksChargedSideC = multiplicitySideA = multiplicitySideC = 0; + } + + PROCESS_SWITCH(UpcPhotonuclearAnalysisJMG, processSG, "Process in UD tables", true); + + void processMixed(FullSGUDCollision const& reconstructedCollision, FullUDTracks const& reconstructedTracks) + { + // (void)reconstructedCollision; + // int sgSide = reconstructedCollision.gapSide(); + // int sgSide = 0; + + // int maxCount = 0; + // int maxCountGapA = 0; + // int maxCountGapC = 0; + + // if (auto histEventCount = histos.get(HIST("eventcount"))) { + // int binA = histEventCount->GetXaxis()->FindBin(-2); Gap A + // int binC = histEventCount->GetXaxis()->FindBin(-1); Gap C + + // maxCount = histEventCount->GetBinContent(binA) * factorEventsMixed; + // maxCountGapA = histEventCount->GetBinContent(binA) * factorEventsMixed; + // maxCountGapC = histEventCount->GetBinContent(binC) * factorEventsMixed; + // } + + BinningType bindingOnVtx{{vtxBinsEdges, gapSideBinsEdges}, true}; + // BinningType bindingOnVtx{{vtxBinsEdges}, true}; + auto tracksTuple = std::make_tuple(reconstructedTracks); + SameKindPair pairs{bindingOnVtx, nEventsMixed, -1, reconstructedCollision, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (collision1.size() == 0 || collision2.size() == 0) { + // LOGF(info, "One or both collisions are empty."); + continue; + } + + // if (countGapA >= maxCountGapA && countGapC >= maxCountGapC) { + // break; + // } + + float multiplicity = 0; + + histos.fill(HIST("Events/hCountCollisionsMixed"), 0); + + if (isCollisionCutSG(collision1) == false || isCollisionCutSG(collision2) == false) { + continue; + } + histos.fill(HIST("Events/hCountCollisionsMixed"), 1); + // ++countEvents; + // LOGF(info, "In the pairs loop"); + for (const auto& track : tracks1) { + if (isTrackCut(track) == false) { + continue; + } + ++multiplicity; + } + // multiplicity = tracks1.size(); + if (fillCollisionUD(mixed, multiplicity) == false) { + return; + } + histos.fill(HIST("Events/hCountCollisionsMixed"), 2); + // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ()})); + // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ(), collision1.gapSide()})); + fillCorrelationsUD(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), MixedEventTag{}); + // LOGF(info, "Filling mixed events"); + + // if (collision1.gapSide() == 0 && collision2.gapSide() == 0) { gap on side A + // if (isCollisionCutSG(collision1, 0) == false && isCollisionCutSG(collision2, 0) == false) { + // continue; + // } + // std::cout << "Counts for Gap A: " << countGapA << " Maximum Count for Gap A " << maxCountGapA << std::endl; + // ++countGapA; + // LOGF(info, "In the pairs loop, gap side A"); + // multiplicity = tracks1.size(); + // if (fillCollisionUD(mixedGapSideA, multiplicity) == false) { + // return; + // } + // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ()})); + // histos.fill(HIST("eventcount"), bindingOnVtx.getBin({collision1.posZ(), collision1.gapSide()})); + // fillCorrelationsUD(mixedGapSideA, tracks1, tracks2, multiplicity, collision1.posZ()); + // LOGF(info, "Filling mixedGapSideA events, Gap for side A"); + // } + + // if (collision1.gapSide() == 1 && collision2.gapSide() == 1) { gap on side C + // if (isCollisionCutSG(collision1, 1) == false && isCollisionCutSG(collision2, 1) == false) { + // continue; + // } + // std::cout << "Counts for Gap C: " << countGapC << " Maximum Count for Gap C" << maxCountGapC << std::endl; + // ++countGapC; + // LOGF(info, "In the pairs loop, gap side C"); + // multiplicity = tracks1.size(); + // if (fillCollisionUD(mixedGapSideC, multiplicity) == false) { + // return; + // } + // fillCorrelationsUD(mixedGapSideC, tracks1, tracks2, multiplicity, collision1.posZ()); + // LOGF(info, "Filling mixedGapSideC events, Gap for side C"); + // } else { + // continue; + // } + } + } + + PROCESS_SWITCH(UpcPhotonuclearAnalysisJMG, processMixed, "Process mixed events", true); + + void processSame(FullSGUDCollision::iterator const& reconstructedCollision, FullUDTracks const& reconstructedTracks) + { + // int sgSide = reconstructedCollision.gapSide(); + float multiplicity = 0; + + if (isCollisionCutSG(reconstructedCollision) == false) { + return; + } + + // Configure track flow histogram labels + auto hFlow = histos.get(HIST("Tracks/hTracksAfterCuts")); + hFlow->GetXaxis()->SetBinLabel(1, "All tracks"); + hFlow->GetXaxis()->SetBinLabel(2, "Track sign"); + hFlow->GetXaxis()->SetBinLabel(3, "p_{T} range"); + hFlow->GetXaxis()->SetBinLabel(4, "#eta range"); + hFlow->GetXaxis()->SetBinLabel(5, "dcaZ"); + hFlow->GetXaxis()->SetBinLabel(6, "dcaXY"); + hFlow->GetXaxis()->SetBinLabel(7, "PV contrib cut"); + hFlow->GetXaxis()->SetBinLabel(8, "has ITS cut"); + hFlow->GetXaxis()->SetBinLabel(9, "N clusters ITS cut"); + hFlow->GetXaxis()->SetBinLabel(10, "#chi^{2} N cluster ITS cut"); + hFlow->GetXaxis()->SetBinLabel(11, "has TPC cut"); + hFlow->GetXaxis()->SetBinLabel(12, "N clusters crossed row TPC cut"); + hFlow->GetXaxis()->SetBinLabel(13, "(N cluster findable - N cluster minus findable) TPC cut"); + hFlow->GetXaxis()->SetBinLabel(14, "N cluster findable TPC cut"); + hFlow->GetXaxis()->SetBinLabel(15, "(N cluster crossed row / N cluster findable) TPC cut"); + hFlow->GetXaxis()->SetBinLabel(16, "(N cluster findable - N cluster minus findable) / N cluster findable cut"); + hFlow->GetXaxis()->SetBinLabel(17, "#chi^{2} N cluster TPC cut"); + + for (const auto& track : reconstructedTracks) { + histos.fill(HIST("Tracks/hTracksAfterCuts"), 0); + if (track.sign() != 1 && track.sign() != -1) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 1); + if (track.pt() < cutMyptMin || track.pt() > cutMyptMax) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 2); + if (eta(track.px(), track.py(), track.pz()) < cutMyetaMin || eta(track.px(), track.py(), track.pz()) > cutMyetaMax) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 3); + if (std::abs(track.dcaZ()) > cutMydcaZmax) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 4); + if (cutMydcaXYusePt) { + float maxDCA = 0.0105f + 0.0350f / std::pow(track.pt(), 1.1f); + if (std::abs(track.dcaXY()) > maxDCA) { + continue; + } + } else { + if (std::abs(track.dcaXY()) > cutMydcaXYmax) { + continue; + } + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 5); + if (track.isPVContributor() == false) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 6); + // Quality Track + // ITS + if (cutMyHasITS && !track.hasITS()) { + continue; // ITS refit + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 7); + if (track.itsNCls() < cutMyITSNClsMin) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 8); + if (track.itsChi2NCl() > cutMyITSChi2NClMax) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 9); + // TPC + if (cutMyHasTPC && !track.hasTPC()) { + continue; // TPC refit + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 10); + if (track.tpcNClsCrossedRows() < cutMyTPCNClsCrossedRowsMin) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 11); + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < cutMyTPCNClsMin) { + continue; // tpcNClsFound() + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 12); + if (track.tpcNClsFindable() < cutMyTPCNClsFindableMin) { + continue; + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 13); + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < cutMyTPCNClsCrossedRowsOverNClsFindableMin) { + continue; // + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 14); + if ((static_cast(track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) / static_cast(track.tpcNClsFindable())) < cutMyTPCNClsCrossedRowsOverNClsFindableMin) { + continue; // + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 15); + if (track.tpcChi2NCl() > cutMyTPCChi2NclMax) { + continue; // TPC chi2 + } + histos.fill(HIST("Tracks/hTracksAfterCuts"), 16); + + if (isTrackCut(track) == false) { + continue; + } + ++multiplicity; + } + // multiplicity = reconstructedTracks.size(); + if (fillCollisionUD(same, multiplicity) == false) { + return; + } + // LOGF(debug, "Filling same events"); + histos.fill(HIST("eventcount"), -2); + if (minMultiplicity <= multiplicity && multiplicity <= range1Max) { + histos.fill(HIST("eventcount"), 1); + } else if (range2Min <= multiplicity && multiplicity <= range2Max) { + histos.fill(HIST("eventcount"), 2); + } else if (range3Min <= multiplicity && multiplicity <= range3Max) { + histos.fill(HIST("eventcount"), 3); + } else if (range4Min <= multiplicity && multiplicity <= range4Max) { + histos.fill(HIST("eventcount"), 4); + } else if (range5Min <= multiplicity && multiplicity <= range5Max) { + histos.fill(HIST("eventcount"), 5); + } + fillQAUD(reconstructedTracks, multiplicity); + fillCorrelationsUD(same, reconstructedTracks, reconstructedTracks, multiplicity, reconstructedCollision.posZ(), SameEventTag{}); + + /*switch (sgSide) { + case 0: // gap for side A + if (isCollisionCutSG(reconstructedCollision, 0) == false) { + return; + } + multiplicity = reconstructedTracks.size(); + if (fillCollisionUD(sameGapSideA, multiplicity) == false) { + return; + } + LOGF(info, "Filling sameGapSideA events"); + histos.fill(HIST("eventcount"), -2); + fillQAUD(reconstructedTracks); + fillCorrelationsUD(sameGapSideA, reconstructedTracks, reconstructedTracks, multiplicity, reconstructedCollision.posZ()); + break; + case 1: // gap for side C + if (isCollisionCutSG(reconstructedCollision, 1) == 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()); - } + multiplicity = reconstructedTracks.size(); + if (fillCollisionUD(sameGapSideC, multiplicity) == false) { + return; } - histos.fill(HIST("Events/SGsideBoth/hNch"), nTracksCharged); - histos.fill(HIST("Events/SGsideBoth/hPtVSNch"), nTracksCharged, (sumPt / nTracksCharged)); - nTracksCharged = sumPt = 0; + histos.fill(HIST("eventcount"), -1); + // LOGF(info, "Filling sameGapSideC events"); + fillCorrelationsUD(sameGapSideC, reconstructedTracks, reconstructedTracks, multiplicity, reconstructedCollision.posZ()); break; default: return; break; - } + }*/ } - PROCESS_SWITCH(upcPhotonuclearAnalysisJMG, processSG, "Process in UD tables", true); + + PROCESS_SWITCH(UpcPhotonuclearAnalysisJMG, processSame, "Process same event", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"upcphotonuclear"})}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGUD/Tasks/upcPionAnalysis.cxx b/PWGUD/Tasks/upcPionAnalysis.cxx index bd7157dc702..fc215ea1822 100644 --- a/PWGUD/Tasks/upcPionAnalysis.cxx +++ b/PWGUD/Tasks/upcPionAnalysis.cxx @@ -9,11 +9,11 @@ // 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 #include "PWGUD/DataModel/UDTables.h" #include #include @@ -67,7 +67,7 @@ struct UPCPionAnalysis { // defining histograms using histogram registry HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; - //_____________________________________________________________________________ + //_____________________________________________________________________________________________ Double_t CosThetaHelicityFrame(TLorentzVector pionPositive, TLorentzVector pionNegative, TLorentzVector possibleRhoZero) @@ -405,7 +405,7 @@ struct UPCPionAnalysis { 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 + // 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}}); @@ -427,7 +427,7 @@ struct UPCPionAnalysis { } using udtracks = soa::Join; - using udtracksfull = soa::Join; + using udtracksfull = soa::Join; using UDCollisionsFull = soa::Join; //__________________________________________________________________________ // Main process @@ -476,17 +476,21 @@ struct UPCPionAnalysis { registry.fill(HIST("hSelectionCounter"), 5); for (auto t : tracks) { - if (!t.isPVContributor()) { - continue; - } - int NFindable = t.tpcNClsFindable(); - int NMinusFound = t.tpcNClsFindableMinusFound(); - int NCluster = NFindable - NMinusFound; + /*if (!t.isPVContributor()) { + continue; + }*/ - if (NCluster < TPC_cluster) { + 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(); @@ -586,7 +590,7 @@ struct UPCPionAnalysis { } } } - //_____________________________________ + //_____________________________________________________________________________________________________ // Six pions analysis if (collision.numContrib() == 6) { if ((rawPionTracks.size() == 6) && (onlyPionTracks.size() == 6)) { diff --git a/PWGUD/Tasks/upcPolarisationJpsiIncoh.cxx b/PWGUD/Tasks/upcPolarisationJpsiIncoh.cxx new file mode 100644 index 00000000000..88d8f36d18d --- /dev/null +++ b/PWGUD/Tasks/upcPolarisationJpsiIncoh.cxx @@ -0,0 +1,325 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file upcPolarisationJpsiIncoh.cxx +/// \brief Workflow to analyse UPC forward events and perform J/psi polarization selections +/// \author Niveditha Ram, IP2I +/// \ingroup PWGUD +/// executable name: o2-analysis-ud-upc-polarisation-jpsiincoh + +#include "PWGUD/DataModel/UDTables.h" + +#include "Common/Core/RecoDecay.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TMath.h" +#include "TRandom3.h" +#include "TSystem.h" + +#include +#include + +using namespace ROOT::Math; + +// 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(Pt, pt, float); +DECLARE_SOA_COLUMN(Rap, rap, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace dimu + +namespace o2::aod +{ +DECLARE_SOA_TABLE(DiMu, "AOD", "DIMU", + dimu::RunNumber, + dimu::M, dimu::Pt, dimu::Rap, dimu::Phi); +} // 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 kRAbsMax = 89.5; +const float kPDca = 200.; +float kEtaMin = -4.0; +float kEtaMax = -2.5; +const float kPtMin = 0.; +const float kMaxAmpV0A = 100.; +const int kReqMatchMIDTracks = 2; +const int kReqMatchMFTTracks = 2; +const int kMaxChi2MFTMatch = 30; +struct UpcPolarisationJpsiIncoh { + + using CandidatesFwd = soa::Join; + using ForwardTracks = soa::Join; + using CompleteFwdTracks = soa::Join; + + Produces dimuSel; + // defining histograms using histogram registry: different histos for the different process functions + HistogramRegistry registry{"registry", {}, 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"}; + // 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"}; + // my track type + // 0 = MCH-MID-MFT + // 1 = MCH-MID + Configurable myTrackType{"myTrackType", 1, "My track type"}; + + void init(InitContext&) + { + // axis + const AxisSpec axisPt{nBinsPt, lowPt, highPt, "#it{p}_{T} GeV/#it{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"}; + // 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("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}); + } + + // 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()); + } + } + + // 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(); + float pt = RecoDecay::pt(fwdTrack.px(), fwdTrack.py()); + float eta = RecoDecay::eta(std::array{fwdTrack.px(), fwdTrack.py(), fwdTrack.pz()}); + if (eta < kEtaMin || eta > kEtaMax) + return false; + if (pt < kPtMin) + return false; + if (rAbs < kRAbsMin || rAbs > kRAbsMax) + return false; + if (pDca > kPDca) + return false; + return true; + } + + // 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) + { + // 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] > kMaxAmpV0A) + return; + } + } + + // MCH-MID match selection + int nMIDs = 0; + if (tr1.chi2MatchMCHMID() > 0) + nMIDs++; + if (tr2.chi2MatchMCHMID() > 0) + nMIDs++; + if (nMIDs != kReqMatchMIDTracks) + return; + // MFT-MID match selection (if MFT is requested by the trackType) + if (myTrackType == 0) { + // if MFT is requested check that the tracks is inside the MFT acceptance + kEtaMin = -3.6; + kEtaMax = -2.5; + + int nMFT = 0; + if (tr1.chi2MatchMCHMFT() > 0 && tr1.chi2MatchMCHMFT() < kMaxChi2MFTMatch) + nMFT++; + if (tr2.chi2MatchMCHMFT() > 0 && tr2.chi2MatchMCHMFT() < kMaxChi2MFTMatch) + nMFT++; + if (nMFT != kReqMatchMFTTracks) + return; + } + // track selection + if (!isMuonSelected(*tr1)) + return; + if (!isMuonSelected(*tr2)) + return; + + // form Lorentz vectors + auto mMu = o2::constants::physics::MassMuonMinus; + LorentzVector> p1(tr1.px(), tr1.py(), tr1.pz(), mMu); + LorentzVector> p2(tr2.px(), tr2.py(), tr2.pz(), mMu); + LorentzVector 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; + // fill the histos without looking at neutron emission + registry.fill(HIST("hMass"), p.M()); + registry.fill(HIST("hPt"), p.Pt()); + registry.fill(HIST("hEta"), p.Eta()); + registry.fill(HIST("hRapidity"), p.Rapidity()); + registry.fill(HIST("hPhi"), p.Phi()); + + dimuSel(cand.runNumber(), p.M(), p.Pt(), p.Rapidity(), p.Phi()); + } + // PROCESS FUNCTION + void processData(CandidatesFwd const& eventCandidates, + o2::aod::UDZdcsReduced const& ZDCs, + ForwardTracks const& fwdTracks) + { + + // map with the tracks + std::unordered_map> tracksPerCand; + // takes a tracks table with a coloumn of collision ID and makes it into a map of collision ID to each track. + 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); + processCand(cand, tr1, tr2); + } + } + + PROCESS_SWITCH(UpcPolarisationJpsiIncoh, processData, "", true); +}; + +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..8baf7f42206 --- /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 "PWGUD/Core/SGSelector.h" + +#include "Common/Core/TrackSelection.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +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..70535203937 --- /dev/null +++ b/PWGUD/Tasks/upcRhoAnalysis.cxx @@ -0,0 +1,1054 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TPDGCode.h" + +#include +#include +#include +#include +#include +#include + +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; +using FullMcUdCollision = soa::Join::iterator; + +namespace o2::aod +{ +namespace reco_tree +{ +// event info +DECLARE_SOA_COLUMN(RecoSetting, recoSetting, uint16_t); +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); +DECLARE_SOA_COLUMN(NeutronClass, neutronClass, int); +// 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::RecoSetting, 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::NeutronClass, + 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); +DECLARE_SOA_COLUMN(RunNumber, runNumber, 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::RunNumber, + 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; + + SGSelector sgSelector; + + const float pcEtaCut = 0.9; // physics coordination recommendation + const std::vector runNumbers = {544013, 544028, 544032, 544091, 544095, 544098, 544116, 544121, 544122, 544123, 544124, 544184, 544185, 544389, 544390, 544391, 544392, 544451, 544454, 544474, 544475, 544476, 544477, 544490, 544491, 544492, 544508, 544510, 544511, 544512, 544514, 544515, 544518, 544548, 544549, 544550, 544551, 544564, 544565, 544567, 544568, 544580, 544582, 544583, 544585, 544614, 544640, 544652, 544653, 544672, 544674, 544692, 544693, 544694, 544696, 544739, 544742, 544754, 544767, 544794, 544795, 544797, 544813, 544868, 544886, 544887, 544896, 544911, 544913, 544914, 544917, 544931, 544947, 544961, 544963, 544964, 544968, 544991, 544992, 545004, 545008, 545009, 545041, 545042, 545044, 545047, 545060, 545062, 545063, 545064, 545066, 545086, 545103, 545117, 545171, 545184, 545185, 545210, 545222, 545223, 545246, 545249, 545262, 545289, 545291, 545294, 545295, 545296, 545311, 545312, 545332, 545345, 545367}; + AxisSpec runNumberAxis = {static_cast(runNumbers.size()), 0.5, static_cast(runNumbers.size()) + 0.5, "run number"}; + + Configurable numPions{"numPions", 2, "required number of pions in the event"}; + + Configurable isPO{"isPO", false, "process proton-oxygen data"}; + + Configurable cutGapSide{"cutGapSide", true, "apply gap side cut"}; + Configurable gapSide{"gapSide", 2, "required gap side"}; + Configurable useTrueGap{"useTrueGap", false, "use true gap"}; + 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 requireTof{"requireTof", false, "require TOF signal"}; + Configurable useRecoFlag{"useRecoFlag", false, "use reco flag for event selection"}; + Configurable cutRecoFlag{"cutRecoFlag", 1, "0 = std mode, 1 = upc mode"}; + Configurable useRctFlag{"useRctFlag", false, "use RCT flags for event selection"}; + Configurable cutRctFlag{"cutRctFlag", 0, "0 = off, 1 = CBT, 2 = CBT+ZDC, 3 = CBThadron, 4 = CBThadron+ZDC"}; + + Configurable selectRuns{"selectRuns", false, "select runs from the list"}; + Configurable> selectedRuns{"selectedRuns", {544013, 544028, 544032, 544091, 544095, 544098, 544116, 544121, 544122, 544123, 544124, 544184, 544185, 544389, 544390, 544391, 544392, 544451, 544454, 544474, 544475, 544476, 544477, 544490, 544491, 544492, 544508, 544510, 544511, 544512, 544514, 544515, 544518, 544548, 544549, 544550, 544551, 544564, 544565, 544567, 544568, 544580, 544582, 544583, 544585, 544614, 544640, 544652, 544653, 544672, 544674, 544692, 544693, 544694, 544696, 544739, 544742, 544754, 544767, 544794, 544795, 544797, 544813, 544868, 544886, 544887, 544896, 544913, 544914, 544917, 544931, 544947, 544961, 544963, 544964, 544968, 544992, 545009, 545044, 545047, 545063, 545064, 545066, 545185, 545210, 545223, 545249, 545291, 545294, 545295, 545296, 545312}, "list of selected runs"}; + + Configurable collisionsPosZMaxCut{"collisionsPosZMaxCut", 10.0, "max Z position cut on collisions"}; + Configurable cutNumContribs{"cutNumContribs", true, "cut on number of contributors"}; + Configurable collisionsNumContribsMaxCut{"collisionsNumContribsMaxCut", 2, "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 rejectLowerProbPairs{"rejectLowerProbPairs", false, "reject track pairs with lower El or Ka PID radii"}; + Configurable tracksDcaMaxCut{"tracksDcaMaxCut", 1.0, "max DCA cut on tracks"}; + Configurable tracksMinItsNClsCut{"tracksMinItsNClsCut", 4, "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", 130, "min TPC crossed rows cut"}; + Configurable tracksMinTpcChi2NClCut{"tracksMinTpcChi2NClCut", 1.0, "min TPC chi2/Ncls cut"}; + Configurable tracksMaxTpcChi2NClCut{"tracksMaxTpcChi2NClCut", 3.0, "max TPC chi2/Ncls cut"}; + Configurable tracksMinTpcNClsCrossedOverFindableCut{"tracksMinTpcNClsCrossedOverFindableCut", 1.0, "min TPC crossed rows / findable clusters cut"}; + Configurable tracksMinPtCut{"tracksMinPtCut", 0.1, "min pT cut on tracks"}; + + Configurable systemMassMinCut{"systemMassMinCut", 0.5, "min M cut for reco system"}; + Configurable systemMassMaxCut{"systemMassMaxCut", 1.0, "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", {400, 0.0, 4.0}, "#it{m} (GeV/#it{c}^{2})"}; + ConfigurableAxis ptAxis{"ptAxis", {400, 0.0, 4.0}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis pt2Axis{"pt2Axis", {1000, 0.0, 1.0}, "#it{p}_{T}^{2} (GeV^{2}/#it{c}^{2})"}; + ConfigurableAxis etaAxis{"etaAxis", {300, -1.5, 1.5}, "#it{#eta}"}; + ConfigurableAxis yAxis{"yAxis", {300, -1.5, 1.5}, "#it{y}"}; + ConfigurableAxis phiAxis{"phiAxis", {180, 0.0, o2::constants::math::TwoPI}, "#it{#phi} (rad)"}; + ConfigurableAxis deltaPhiAxis{"deltaPhiAxis", {182, -o2::constants::math::PI, o2::constants::math::PI}, "#Delta#it{#phi} (rad)"}; + ConfigurableAxis znCommonEnergyAxis{"znCommonEnergyAxis", {250, -5.0, 20.0}, "ZN common energy (TeV)"}; + ConfigurableAxis znTimeAxis{"znTimeAxis", {200, -10.0, 10.0}, "ZN time (ns)"}; + ConfigurableAxis nSigmaAxis{"nSigmaAxis", {600, -30.0, 30.0}, "TPC #it{n#sigma}"}; + + 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& context) + { + // QA // + // collisions + rQC.add("QC/collisions/all/hPosXY", ";vertex #it{x} (cm);vertex #it{y} (cm);counts", kTH2D, {{2000, -0.1, 0.1}, {2000, -0.1, 0.1}}); + rQC.add("QC/collisions/all/hPosZ", ";vertex #it{z} (cm);counts", kTH1D, {{400, -20.0, 20.0}}); + rQC.add("QC/collisions/all/hNumContrib", ";number of PV 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, {{160, 0.0, 160.0}}); + rQC.add("QC/collisions/all/hTotalFT0AmplitudeC", ";FT0C amplitude;counts", kTH1D, {{160, 0.0, 160.0}}); + rQC.add("QC/collisions/all/hTotalFV0AmplitudeA", ";FV0A amplitude;counts", kTH1D, {{300, 0.0, 300.0}}); + rQC.add("QC/collisions/all/hTotalFDDAmplitudeA", ";FDDA amplitude;counts", kTH1D, {{160, 0.0, 160.0}}); + rQC.add("QC/collisions/all/hTotalFDDAmplitudeC", ";FDDC amplitude;counts", kTH1D, {{50, 0.0, 50.0}}); + rQC.add("QC/collisions/all/hTimeFT0A", ";FT0A time (ns);counts", kTH1D, {{500, -10.0, 40.0}}); + rQC.add("QC/collisions/all/hTimeFT0C", ";FT0C time (ns);counts", kTH1D, {{500, -10.0, 40.0}}); + rQC.add("QC/collisions/all/hTimeFV0A", ";FV0A time (ns);counts", kTH1D, {{500, -10.0, 40.0}}); + rQC.add("QC/collisions/all/hTimeFDDA", ";FDDA time (ns);counts", kTH1D, {{500, -10.0, 40.0}}); + rQC.add("QC/collisions/all/hTimeFDDC", ";FDDC time (ns);counts", kTH1D, {{500, -10.0, 40.0}}); + // events with selected rho candidates + rQC.addClone("QC/collisions/all/", "QC/collisions/trackSelections/"); + rQC.addClone("QC/collisions/all/", "QC/collisions/systemSelections/"); + + std::vector collisionSelectionCounterLabels = {"all collisions", "rapidity gap", "ITS-TPC vertex", "same bunch pile-up", "ITS ROF border", "TF border", "#it{z} position", "number of contributors", "RCT selections", "reco flag selection"}; + rQC.add("QC/collisions/hSelectionCounter", ";;collisions passing selections", kTH1D, {{static_cast(collisionSelectionCounterLabels.size()), -0.5, static_cast(collisionSelectionCounterLabels.size()) - 0.5}}); + rQC.add("QC/collisions/hSelectionCounterPerRun", ";;run number;collisions passing selections", kTH2D, {{static_cast(collisionSelectionCounterLabels.size()), -0.5, static_cast(collisionSelectionCounterLabels.size()) - 0.5}, runNumberAxis}); + for (int i = 0; i < static_cast(collisionSelectionCounterLabels.size()); ++i) { + rQC.get(HIST("QC/collisions/hSelectionCounter"))->GetXaxis()->SetBinLabel(i + 1, collisionSelectionCounterLabels[i].c_str()); + rQC.get(HIST("QC/collisions/hSelectionCounterPerRun"))->GetXaxis()->SetBinLabel(i + 1, collisionSelectionCounterLabels[i].c_str()); + } + // tracks + rQC.add("QC/tracks/all/hTpcNSigmaPi", ";TPC #it{n#sigma}(#pi);counts", kTH1D, {nSigmaAxis}); + rQC.add("QC/tracks/all/hTpcNSigmaEl", ";TPC #it{n#sigma}(e);counts", kTH1D, {nSigmaAxis}); + rQC.add("QC/tracks/all/hTpcNSigmaKa", ";TPC #it{n#sigma}(K);counts", kTH1D, {nSigmaAxis}); + rQC.add("QC/tracks/all/hDcaXYZ", ";track #it{DCA}_{z} (cm);track #it{DCA}_{xy} (cm);counts", kTH2D, {{1000, -5.0, 5.0}, {400, -2.0, 2.0}}); + rQC.add("QC/tracks/all/hItsNCls", ";ITS #it{N}_{cls};counts", kTH1D, {{11, -0.5, 10.5}}); + rQC.add("QC/tracks/all/hItsChi2NCl", ";ITS #it{#chi}^{2}/#it{N}_{cls};counts", kTH1D, {{200, 0.0, 20.0}}); + rQC.add("QC/tracks/all/hTpcChi2NCl", ";TPC #it{#chi}^{2}/#it{N}_{cls};counts", kTH1D, {{200, 0.0, 20.0}}); + rQC.add("QC/tracks/all/hTpcNCls", ";found TPC #it{N}_{cls};counts", kTH1D, {{160, 0.0, 160.0}}); // tpcNClsFindable() - track.tpcNClsFindableMinusFound + rQC.add("QC/tracks/all/hTpcNClsCrossedRows", ";TPC crossed rows;counts", kTH1D, {{160, 0.0, 160.0}}); + rQC.add("QC/tracks/all/hTpcNClsCrossedRowsOverNClsFindable", ";TPC crossed rows/findable #it{N}_{cls};counts", kTH1D, {{300, 0.5, 2.5}}); + rQC.add("QC/tracks/all/hPt", ";#it{p}_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + rQC.add("QC/tracks/all/hEta", ";#it{#eta};counts", kTH1D, {etaAxis}); + rQC.add("QC/tracks/all/hPhi", ";#it{#phi} (rad);counts", kTH1D, {phiAxis}); + rQC.add("QC/tracks/all/hTpcSignalVsP", ";|#it{p}| (GeV/#it{c});TPC d#it{E}/d#it{x} signal (arb. units);counts", kTH2D, {ptAxis, {500, 0.0, 500.0}}); + rQC.add("QC/tracks/all/hTpcSignalVsPt", ";#it{p}_{T} (GeV/#it{c});TPC d#it{E}/d#it{x} signal (arb. units);counts", kTH2D, {ptAxis, {500, 0.0, 500.0}}); + // tracks passing selections + rQC.addClone("QC/tracks/all/", "QC/tracks/trackSelections/"); + rQC.addClone("QC/tracks/all/", "QC/tracks/systemSelections/"); + rQC.add("QC/tracks/trackSelections/hRemainingTracks", ";remaining tracks;counts", kTH1D, {{21, -0.5, 20.5}}); + rQC.add("QC/tracks/trackSelections/hTpcNSigmaPi2D", ";TPC #it{n#sigma}(#pi)_{leading};TPC #it{n#sigma}(#pi)_{subleading};counts", kTH2D, {nSigmaAxis, nSigmaAxis}); + rQC.add("QC/tracks/trackSelections/hTpcNSigmaEl2D", ";TPC #it{n#sigma}(e)_{leading};TPC #it{n#sigma}(e)_{subleading};counts", kTH2D, {nSigmaAxis, nSigmaAxis}); + rQC.add("QC/tracks/trackSelections/hTpcNSigmaKa2D", ";TPC #it{n#sigma}(K)_{leading};TPC #it{n#sigma}(K)_{subleading};counts", kTH2D, {nSigmaAxis, nSigmaAxis}); + // selection counter + std::vector trackSelectionCounterLabels = {"all tracks", "PV contributor", "ITS hit", "ITS #it{N}_{cls}", "itsClusterMap check", "ITS #it{#chi}^{2}/#it{N}_{cls}", "TPC hit", "found TPC #it{N}_{cls}", "TPC #it{#chi}^{2}/#it{N}_{cls}", "TPC crossed rows", + "TPC crossed rows/#it{N}_{cls}", + "TOF requirement", + "#it{p}_{T}", "#it{DCA}", "#it{#eta}", "exactly 2 tracks", "PID"}; + rQC.add("QC/tracks/hSelectionCounter", ";;tracks passing selections", kTH1D, {{static_cast(trackSelectionCounterLabels.size()), -0.5, static_cast(trackSelectionCounterLabels.size()) - 0.5}}); + rQC.add("QC/tracks/hSelectionCounterPerRun", ";;run number;tracks passing selections", kTH2D, {{static_cast(trackSelectionCounterLabels.size()), -0.5, static_cast(trackSelectionCounterLabels.size()) - 0.5}, runNumberAxis}); + for (int i = 0; i < static_cast(trackSelectionCounterLabels.size()); ++i) { + rQC.get(HIST("QC/tracks/hSelectionCounter"))->GetXaxis()->SetBinLabel(i + 1, trackSelectionCounterLabels[i].c_str()); + rQC.get(HIST("QC/tracks/hSelectionCounterPerRun"))->GetXaxis()->SetBinLabel(i + 1, trackSelectionCounterLabels[i].c_str()); + } + for (int i = 0; i < static_cast(runNumbers.size()); ++i) { + rQC.get(HIST("QC/tracks/hSelectionCounterPerRun"))->GetYaxis()->SetBinLabel(i + 1, std::to_string(runNumbers[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}}); + rQC.get(HIST("QC/tracks/hTofHitCheck"))->GetXaxis()->SetBinLabel(1, "no hit"); + rQC.get(HIST("QC/tracks/hTofHitCheck"))->GetXaxis()->SetBinLabel(2, "hit"); + rQC.get(HIST("QC/tracks/hTofHitCheck"))->GetYaxis()->SetBinLabel(1, "no hit"); + rQC.get(HIST("QC/tracks/hTofHitCheck"))->GetYaxis()->SetBinLabel(2, "hit"); + // PID "radii" plots + rQC.add("QC/tracks/hPiPIDRadius", ";#it{n#sigma}(#pi) radius;counts", kTH1D, {{1000, 0.0, 10.0}}); + rQC.add("QC/tracks/hElPIDRadius", ";#it{n#sigma}(e) radius;counts", kTH1D, {{1000, 0.0, 10.0}}); + rQC.add("QC/tracks/hKaPIDRadius", ";#it{n#sigma}(K) radius;counts", kTH1D, {{1000, 0.0, 10.0}}); + + // TRACKS (2D) + rTracks.add("tracks/trackSelections/unlike-sign/hPt", ";#it{p}_{T leading} (GeV/#it{c});#it{p}_{T subleading} (GeV/#it{c});counts", kTH2D, {ptAxis, ptAxis}); + rTracks.add("tracks/trackSelections/unlike-sign/hEta", ";#it{#eta}_{leading};#it{#eta}_{subleading};counts", kTH2D, {etaAxis, etaAxis}); + rTracks.add("tracks/trackSelections/unlike-sign/hPhi", ";#it{#phi}_{leading} (rad);#it{#phi}_{subleading} (rad);counts", kTH2D, {phiAxis, phiAxis}); + rTracks.addClone("tracks/trackSelections/unlike-sign/", "tracks/trackSelections/like-sign/positive/"); + rTracks.addClone("tracks/trackSelections/unlike-sign/", "tracks/trackSelections/like-sign/negative/"); + rTracks.addClone("tracks/trackSelections/", "tracks/systemSelections/"); + + // SYSTEM + rSystem.add("system/all/unlike-sign/hM", ";#it{m} (GeV/#it{c}^{2});counts", kTH1D, {mAxis}); + rSystem.add("system/all/unlike-sign/hRecoSettingVsM", ";#it{m} (GeV/#it{c}^{2});reco setting;counts", kTH2D, {mAxis, {2, -0.5, 1.5}}); + rSystem.add("system/all/unlike-sign/hPt", ";#it{p}_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + rSystem.add("system/all/unlike-sign/hPt2", ";#it{p}_{T}^{2} (GeV^{2}/#it{c}^{2});counts", kTH1D, {pt2Axis}); + rSystem.add("system/all/unlike-sign/hPtVsM", ";#it{m} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c});counts", kTH2D, {mAxis, ptAxis}); + rSystem.add("system/all/unlike-sign/hY", ";#it{y};counts", kTH1D, {yAxis}); + rSystem.add("system/all/unlike-sign/hPhi", ";#it{#phi} (rad);counts", kTH1D, {phiAxis}); + rSystem.add("system/all/unlike-sign/hPhiRandom", ";#Delta#it{#phi}_{random} (rad);counts", kTH1D, {deltaPhiAxis}); + rSystem.add("system/all/unlike-sign/hPhiCharge", ";#Delta#it{#phi}_{charge} (rad);counts", kTH1D, {deltaPhiAxis}); + rSystem.add("system/all/unlike-sign/hPhiRandomVsM", ";#it{m} (GeV/#it{c}^{2});#Delta#it{#phi}_{random} (rad);counts", kTH2D, {mAxis, deltaPhiAxis}); + rSystem.add("system/all/unlike-sign/hPhiChargeVsM", ";#it{m} (GeV/#it{c}^{2});#Delta#it{#phi}_{charge} (rad);counts", kTH2D, {mAxis, deltaPhiAxis}); + // 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/AnAn/"); + // clones for neutron classes + rSystem.addClone("system/selected/AnAn/", "system/selected/0n0n/"); + rSystem.addClone("system/selected/AnAn/", "system/selected/Xn0n/"); + rSystem.addClone("system/selected/AnAn/", "system/selected/0nXn/"); + rSystem.addClone("system/selected/AnAn/", "system/selected/XnXn/"); + + if (context.mOptions.get("processMCdata") || context.mOptions.get("processMCdataWithBCs")) { + // MC + // collisions + rMC.add("MC/collisions/hPosXY", ";vertex #it{x} (cm);vertex #it{y} (cm);counts", kTH2D, {{2000, -0.1, 0.1}, {2000, -0.1, 0.1}}); + rMC.add("MC/collisions/hPosZ", ";vertex #it{z} (cm);counts", kTH1D, {{400, -20.0, 20.0}}); + rMC.add("MC/collisions/hNPions", ";number of pions;counts", kTH1D, {{11, -0.5, 10.5}}); + if (context.mOptions.get("processCollisionRecoCheck")) + rMC.add("MC/collisions/hNumOfCollisionRecos", ";number of collision reconstructions;counts", kTH1D, {{6, -0.5, 5.5}}); + // tracks + rMC.add("MC/tracks/all/hPdgCode", ";pdg code;counts", kTH1D, {{2001, -1000.5, 1000.5}}); + rMC.add("MC/tracks/all/hMotherPdgCode", ";mother 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", ";#it{p}_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + rMC.add("MC/tracks/all/hEta", ";#it{#eta};counts", kTH1D, {etaAxis}); + rMC.add("MC/tracks/all/hPhi", ";#it{#phi} (rad);counts", kTH1D, {phiAxis}); + rMC.addClone("MC/tracks/all/", "MC/tracks/primaries/"); + rMC.addClone("MC/tracks/all/", "MC/tracks/prodByGen/"); + rMC.add("MC/tracks/hPt", ";#it{p}_{T leading} (GeV/#it{c});#it{p}_{T subleading} (GeV/#it{c});counts", kTH2D, {ptAxis, ptAxis}); + rMC.add("MC/tracks/hEta", ";#it{#eta}_{leading};#it{#eta}_{subleading};counts", kTH2D, {etaAxis, etaAxis}); + rMC.add("MC/tracks/hPhi", ";#it{#phi}_{leading} (rad);#it{#phi}_{subleading} (rad);counts", kTH2D, {phiAxis, phiAxis}); + // resolution + rMC.add("MC/resolution/tracks/hPt", ";#it{p}_{T, reco} - #it{p}_{T, true} (GeV/#it{c});counts", kTH1D, {{200, -1.0, 1.0}}); + rMC.add("MC/resolution/tracks/hEta", ";#it{#eta}_{reco} - #it{#eta}_{true};counts", kTH1D, {{200, -0.2, 0.2}}); + rMC.add("MC/resolution/tracks/hPhi", ";#it{#phi}_{reco} - #it{#phi}_{true} (rad);counts", kTH1D, {{200, -0.2, 0.2}}); + // system + rMC.add("MC/system/hM", ";#it{m} (GeV/#it{c}^{2});counts", kTH1D, {mAxis}); + rMC.add("MC/system/hPt", ";#it{p}_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); + rMC.add("MC/system/hPt2", ";#it{p}_{T}^{2} (GeV^{2}/#it{c}^{2});counts", kTH1D, {pt2Axis}); + rMC.add("MC/system/hPtVsM", ";#it{m} (GeV/#it{c}^{2});#it{p}_{T} (GeV/#it{c});counts", kTH2D, {mAxis, ptAxis}); + rMC.add("MC/system/hY", ";#it{y};counts", kTH1D, {yAxis}); + rMC.add("MC/system/hPhi", ";#it{#phi} (rad);counts", kTH1D, {phiAxis}); + rMC.add("MC/system/hPhiRandom", ";#Delta#it{#phi}_{random} (rad);counts", kTH1D, {deltaPhiAxis}); + rMC.add("MC/system/hPhiCharge", ";#Delta#it{#phi}_{charge} (rad);counts", kTH1D, {deltaPhiAxis}); + rMC.add("MC/system/hPhiRandomVsM", ";#it{m} (GeV/#it{c}^{2});#Delta#it{#phi} (rad);counts", kTH2D, {mAxis, deltaPhiAxis}); + rMC.add("MC/system/hPhiChargeVsM", ";#it{m} (GeV/#it{c}^{2});#Delta#it{#phi} (rad);counts", kTH2D, {mAxis, deltaPhiAxis}); + rMC.addClone("MC/system/", "MC/system/selected/"); + } + } + + static constexpr std::string_view AppliedSelections[3] = {"all/", "trackSelections/", "systemSelections/"}; + static constexpr std::string_view ChargeLabel[3] = {"unlike-sign/", "like-sign/positive/", "like-sign/negative/"}; + static constexpr std::string_view NeutronClass[5] = {"AnAn/", "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"), std::abs(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); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPhiRandomVsM"), mass, phiRandom); + rSystem.fill(HIST("system/") + HIST(AppliedSelections[cuts]) + HIST(ChargeLabel[charge]) + HIST("hPhiChargeVsM"), mass, phiCharge); + } else { + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hM"), mass); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPt"), pt); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPt2"), pt * pt); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPtVsM"), mass, pt); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hY"), rapidity); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPhi"), phi); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPhiRandom"), phiRandom); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPhiCharge"), phiCharge); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPhiRandomVsM"), mass, phiRandom); + rSystem.fill(HIST("system/") + HIST("selected/") + HIST(NeutronClass[neutronClass]) + HIST(ChargeLabel[charge]) + HIST("hPhiChargeVsM"), mass, phiCharge); + } + } + + 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 isGoodRctFlag(const C& collision) + { + switch (cutRctFlag) { + case 1: + return sgSelector.isCBTOk(collision); + case 2: + return sgSelector.isCBTZdcOk(collision); + case 3: + return sgSelector.isCBTHadronOk(collision); + case 4: + return sgSelector.isCBTHadronZdcOk(collision); + default: + return true; + } + } + + template + bool collisionPassesCuts(const C& collision, int runIndex) // collision cuts + { + if (!isPO) { + if (!collision.vtxITSTPC()) + return false; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 2); + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 2, runIndex); + + if (!collision.sbp()) + return false; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 3); + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 3, runIndex); + } + + if (!collision.itsROFb()) + return false; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 4); + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 4, runIndex); + + if (!collision.tfb()) + return false; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 5); + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 5, runIndex); + + if (std::abs(collision.posZ()) > collisionsPosZMaxCut) + return false; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 6); + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 6, runIndex); + + if (cutNumContribs) { + if (collision.numContrib() > collisionsNumContribsMaxCut) + return false; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 7); + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 7, runIndex); + } + + if (useRctFlag) { + if (!isGoodRctFlag(collision)) // check RCT flags + return false; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 8); + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 8, runIndex); + } + + if (useRecoFlag) { + if (collision.flags() != cutRecoFlag) // check reconstruction mode + return false; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 9); + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 9, runIndex); + } + + // if all selections passed + return true; + } + + template + bool trackPassesCuts(const T& track, int runIndex) // track cuts (PID done separately) + { + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 0); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 0, runIndex); + + if (!track.isPVContributor()) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 1); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 1, runIndex); + + if (!track.hasITS()) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 2); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 2, runIndex); + + if (track.itsNCls() < tracksMinItsNClsCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 3); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 3, runIndex); + + if (!cutItsLayers(track.itsClusterMap())) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 4); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 4, runIndex); + + if (track.itsChi2NCl() > tracksMaxItsChi2NClCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 5); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 5, runIndex); + + if (!track.hasTPC()) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 6); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 6, runIndex); + + if ((track.tpcNClsFindable() - track.tpcNClsFindableMinusFound()) < tracksMinTpcNClsCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 7); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 7, runIndex); + + if (track.tpcChi2NCl() > tracksMaxTpcChi2NClCut || track.tpcChi2NCl() < tracksMinTpcChi2NClCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 8); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 8, runIndex); + + if (track.tpcNClsCrossedRows() < tracksMinTpcNClsCrossedRowsCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 9); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 9, runIndex); + + if ((static_cast(track.tpcNClsCrossedRows()) / static_cast(track.tpcNClsFindable())) < tracksMinTpcNClsCrossedOverFindableCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 10); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 10, runIndex); + + if (requireTof) { + if (!track.hasTOF()) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 11); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 11, runIndex); + } + + if (track.pt() < tracksMinPtCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 12); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 12, runIndex); + + 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"), 13); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 13, runIndex); + + if (std::abs(eta(track.px(), track.py(), track.pz())) > pcEtaCut) + return false; + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 14); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 14, runIndex); + + // if all selections passed + return true; + } + + template + bool tracksPassPID(const T& cutTracks) // n-dimensional pion PID cut + { + float radiusPi = 0.0, radiusEl = 0.0, radiusKa = 0.0; + for (const auto& track : cutTracks) { + radiusEl += std::pow(track.tpcNSigmaEl(), 2); + radiusKa += std::pow(track.tpcNSigmaKa(), 2); + radiusPi += std::pow(track.tpcNSigmaPi(), 2); + } + rQC.fill(HIST("QC/tracks/hPiPIDRadius"), std::sqrt(radiusPi)); + rQC.fill(HIST("QC/tracks/hElPIDRadius"), std::sqrt(radiusEl)); + rQC.fill(HIST("QC/tracks/hKaPIDRadius"), std::sqrt(radiusKa)); + if (rejectLowerProbPairs) + return ((radiusPi < std::pow(tracksTpcNSigmaPiCut, 2)) && (radiusPi < radiusEl) && (radiusPi < radiusKa)); + else + return radiusPi < std::pow(tracksTpcNSigmaPiCut, 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() / std::abs(track.pdgCode()); + return charge; + } + + bool systemPassesCuts(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& cutTracksLVs) // reconstruct system from 4-vectors + { + ROOT::Math::PxPyPzMVector system; + for (const auto& trackLV : cutTracksLVs) + system += trackLV; + return system; + } + + double deltaPhi(const ROOT::Math::PxPyPzMVector& p1, const ROOT::Math::PxPyPzMVector& p2) + { + double dPhi = p1.Phi() - p2.Phi(); + dPhi = std::fmod(dPhi + o2::constants::math::PI, o2::constants::math::TwoPI) - o2::constants::math::PI; // normalize to (-pi, pi) + return dPhi; + } + + 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 + ROOT::Math::PxPyPzMVector p1 = cutTracksLVs[indices[0]], p2 = cutTracksLVs[indices[1]]; + ROOT::Math::PxPyPzMVector pPlus = p1 + p2, pMinus = p1 - p2; + return deltaPhi(pPlus, pMinus); + } + + template + float getPhiCharge(const T& cutTracks, const std::vector& cutTracksLVs) + { // two possible definitions of phi: charge-based assignment + ROOT::Math::PxPyPzMVector p1, p2; + p1 = (cutTracks[0].sign() > 0) ? cutTracksLVs[0] : cutTracksLVs[1]; + p2 = (cutTracks[0].sign() > 0) ? cutTracksLVs[1] : cutTracksLVs[0]; + ROOT::Math::PxPyPzMVector pPlus = p1 + p2, pMinus = p1 - p2; + return deltaPhi(pPlus, pMinus); + } + + template + float getPhiChargeMC(const T& cutTracks, const std::vector& cutTracksLVs) + { // the same as for data but using pdg code instead of charge + ROOT::Math::PxPyPzMVector p1, p2; + p1 = (cutTracks[0].pdgCode() > 0) ? cutTracksLVs[0] : cutTracksLVs[1]; + p2 = (cutTracks[0].pdgCode() > 0) ? cutTracksLVs[1] : cutTracksLVs[0]; + ROOT::Math::PxPyPzMVector pPlus = p1 + p2, pMinus = p1 - p2; + return deltaPhi(pPlus, pMinus); + } + + // function to obtain index of run from the run number vector + // search for passed run number in the vector and return its index +1 to use in the filling of a histogram + int getRunIndex(int runNumber, const std::vector& runNumbers) + { + auto it = std::find(runNumbers.begin(), runNumbers.end(), runNumber); + if (it != runNumbers.end()) { + return std::distance(runNumbers.begin(), it) + 1; // +1 to avoid 0 bin in histogram + } else { + return 0; // return 0 if run number not found + } + } + + template + void processReco(C const& collision, T const& tracks, const int runIndex) + { + // check if the collision run number is contained within the selectedRuns vector + if (selectRuns && getRunIndex(collision.runNumber(), selectedRuns) == 0) + return; + + fillCollisionQcHistos<0>(collision); // fill QC histograms before cuts + if (!collisionPassesCuts(collision, runIndex)) // apply collision cuts + return; + + int neutronClass = -1; + bool xnxn = false, onon = false, xnon = false, onxn = false; + float energyCommonZNA = collision.energyCommonZNA(), energyCommonZNC = collision.energyCommonZNC(); + float timeZNA = collision.timeZNA(), timeZNC = collision.timeZNC(); + if (std::isinf(energyCommonZNA)) + energyCommonZNA = -999; + if (std::isinf(energyCommonZNC)) + energyCommonZNC = -999; + if (std::isinf(timeZNA)) + timeZNA = -999; + if (std::isinf(timeZNC)) + timeZNC = -999; + + if (energyCommonZNA <= znCommonEnergyCut && energyCommonZNC <= znCommonEnergyCut) { + onon = true; + neutronClass = 0; + } + if (energyCommonZNA > znCommonEnergyCut && std::abs(timeZNA) <= znTimeCut && energyCommonZNC <= znCommonEnergyCut) { + xnon = true; + neutronClass = 1; + } + if (energyCommonZNA <= znCommonEnergyCut && energyCommonZNC > znCommonEnergyCut && std::abs(timeZNC) <= znTimeCut) { + onxn = true; + neutronClass = 2; + } + if (energyCommonZNA > znCommonEnergyCut && std::abs(timeZNA) <= znTimeCut && + energyCommonZNC > znCommonEnergyCut && std::abs(timeZNC) <= znTimeCut) { + xnxn = true; + neutronClass = 3; + } + + std::vector cutTracks; // store selected tracks + for (const auto& track : tracks) { + fillTrackQcHistos<0>(track); // fill QC histograms before cuts + + if (!trackPassesCuts(track, runIndex)) // apply track cuts + continue; + cutTracks.push_back(track); + } + rQC.fill(HIST("QC/tracks/trackSelections/hRemainingTracks"), cutTracks.size()); + + if (static_cast(cutTracks.size()) != numPions) // further consider only two pion systems + return; + for (int i = 0; i < numPions; i++) { + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 15); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 15, runIndex); + } + rQC.fill(HIST("QC/tracks/trackSelections/hTpcNSigmaPi2D"), cutTracks[0].tpcNSigmaPi(), cutTracks[1].tpcNSigmaPi()); + rQC.fill(HIST("QC/tracks/trackSelections/hTpcNSigmaEl2D"), cutTracks[0].tpcNSigmaEl(), cutTracks[1].tpcNSigmaEl()); + rQC.fill(HIST("QC/tracks/trackSelections/hTpcNSigmaKa2D"), cutTracks[0].tpcNSigmaKa(), cutTracks[1].tpcNSigmaKa()); + + // create a vector of 4-vectors for selected tracks + std::vector cutTracksLVs; + for (const auto& cutTrack : cutTracks) { + cutTracksLVs.push_back(ROOT::Math::PxPyPzMVector(cutTrack.px(), cutTrack.py(), cutTrack.pz(), o2::constants::physics::MassPionCharged)); // apriori assume pion mass + } + + // 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]; + + auto positiveTrack = cutTracks[0].sign() > 0 ? cutTracks[0] : cutTracks[1]; + auto negativeTrack = cutTracks[0].sign() > 0 ? cutTracks[1] : cutTracks[0]; + + 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] = {positiveTrack.sign(), negativeTrack.sign()}; + float trackPts[2] = {positiveTrack.pt(), negativeTrack.pt()}; + float trackEtas[2] = {eta(positiveTrack.px(), positiveTrack.py(), positiveTrack.pz()), eta(negativeTrack.px(), negativeTrack.py(), negativeTrack.pz())}; + float trackPhis[2] = {phi(positiveTrack.px(), positiveTrack.py()), phi(negativeTrack.px(), negativeTrack.py())}; + float trackPiPIDs[2] = {positiveTrack.tpcNSigmaPi(), negativeTrack.tpcNSigmaPi()}; + float trackElPIDs[2] = {positiveTrack.tpcNSigmaEl(), negativeTrack.tpcNSigmaEl()}; + float trackKaPIDs[2] = {positiveTrack.tpcNSigmaKa(), negativeTrack.tpcNSigmaKa()}; + float trackDcaXYs[2] = {positiveTrack.dcaXY(), negativeTrack.dcaXY()}; + float trackDcaZs[2] = {positiveTrack.dcaZ(), negativeTrack.dcaZ()}; + float trackTpcSignals[2] = {positiveTrack.tpcSignal(), negativeTrack.tpcSignal()}; + recoTree(collision.flags(), 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(), + energyCommonZNA, energyCommonZNC, timeZNA, timeZNC, neutronClass, + phiRandom, phiCharge, trackSigns, trackPts, trackEtas, trackPhis, trackPiPIDs, trackElPIDs, trackKaPIDs, trackDcaXYs, trackDcaZs, trackTpcSignals); + + if (!tracksPassPID(cutTracks)) // apply PID cut + return; + + for (const auto& cutTrack : cutTracks) { + rQC.fill(HIST("QC/tracks/hSelectionCounter"), 16); + rQC.fill(HIST("QC/tracks/hSelectionCounterPerRun"), 16, runIndex); + fillTrackQcHistos<1>(cutTrack); // fill QC histograms after cuts + } + rQC.fill(HIST("QC/tracks/hTofHitCheck"), leadingMomentumTrack.hasTOF(), subleadingMomentumTrack.hasTOF()); + fillCollisionQcHistos<1>(collision); // fill QC histograms after track selections + + ROOT::Math::PxPyPzMVector 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<1, 0>(leadingPt, subleadingPt, leadingEta, subleadingEta, leadingPhi, subleadingPhi); + fillSystemHistos<0, 0, 0>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + rSystem.fill(HIST("system/all/unlike-sign/hRecoSettingVsM"), mass, collision.flags()); + break; + + case 2: + fillTrack2dHistos<1, 1>(leadingPt, subleadingPt, leadingEta, subleadingEta, leadingPhi, subleadingPhi); + fillSystemHistos<0, 0, 1>(mass, pT, rapidity, systemPhi, phiRandom, phiCharge); + break; + + case -2: + fillTrack2dHistos<1, 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; + + // fill histograms for system passing cuts + switch (totalCharge) { + case 0: + fillCollisionQcHistos<2>(collision); + for (const auto& cutTrack : cutTracks) + fillTrackQcHistos<2>(cutTrack); + fillTrack2dHistos<2, 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<2, 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<2, 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, const int runNumber) + { + 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.producedByGenerator()) { + rMC.fill(HIST("MC/tracks/prodByGen/hPdgCode"), mcParticle.pdgCode()); + rMC.fill(HIST("MC/tracks/prodByGen/hProducedByGenerator"), mcParticle.producedByGenerator()); + rMC.fill(HIST("MC/tracks/prodByGen/hIsPhysicalPrimary"), mcParticle.isPhysicalPrimary()); + rMC.fill(HIST("MC/tracks/prodByGen/hPt"), pt(mcParticle.px(), mcParticle.py())); + rMC.fill(HIST("MC/tracks/prodByGen/hEta"), eta(mcParticle.px(), mcParticle.py(), mcParticle.pz())); + rMC.fill(HIST("MC/tracks/prodByGen/hPhi"), phi(mcParticle.px(), mcParticle.py())); + } + if (mcParticle.isPhysicalPrimary()) { + rMC.fill(HIST("MC/tracks/primaries/hPdgCode"), mcParticle.pdgCode()); + rMC.fill(HIST("MC/tracks/primaries/hProducedByGenerator"), mcParticle.producedByGenerator()); + rMC.fill(HIST("MC/tracks/primaries/hIsPhysicalPrimary"), mcParticle.isPhysicalPrimary()); + rMC.fill(HIST("MC/tracks/primaries/hPt"), pt(mcParticle.px(), mcParticle.py())); + rMC.fill(HIST("MC/tracks/primaries/hEta"), eta(mcParticle.px(), mcParticle.py(), mcParticle.pz())); + rMC.fill(HIST("MC/tracks/primaries/hPhi"), phi(mcParticle.px(), mcParticle.py())); + } + if (mcParticle.has_daughters()) { + rMC.fill(HIST("MC/tracks/all/hMotherPdgCode"), mcParticle.pdgCode()); + if (mcParticle.pdgCode() != kRho770_0) + continue; // consider only rho0s + for (const auto& daughter : mcParticle.template daughters_as()) { + if (!daughter.isPhysicalPrimary() || std::abs(daughter.pdgCode()) != kPiPlus) + continue; + cutMcParticles.push_back(daughter); + ROOT::Math::PxPyPzMVector pionLV; + pionLV.SetPxPyPzE(daughter.px(), daughter.py(), daughter.pz(), daughter.e()); + mcParticlesLVs.push_back(pionLV); + } + } + } + rMC.fill(HIST("MC/collisions/hNPions"), cutMcParticles.size()); + + if (static_cast(cutMcParticles.size()) != numPions) + return; + if (mcParticlesLVs.size() != cutMcParticles.size()) // sanity check + return; + if (tracksTotalChargeMC(cutMcParticles) != 0) // shouldn't happen in theory + return; + + ROOT::Math::PxPyPzMVector 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); + rMC.fill(HIST("MC/system/hPhiRandomVsM"), mass, phiRandom); + rMC.fill(HIST("MC/system/hPhiChargeVsM"), mass, 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); + rMC.fill(HIST("MC/system/selected/hPhiRandomVsM"), mass, phiRandom); + rMC.fill(HIST("MC/system/selected/hPhiChargeVsM"), mass, phiCharge); + } + + // fill mcTree + auto positivePion = cutMcParticles[0].pdgCode() > 0 ? cutMcParticles[0] : cutMcParticles[1]; + auto negativePion = cutMcParticles[0].pdgCode() > 0 ? cutMcParticles[1] : cutMcParticles[0]; + int localBc = mcCollision.globalBC() % o2::constants::lhc::LHCMaxBunches; + int trackSigns[2] = {positivePion.pdgCode() / std::abs(positivePion.pdgCode()), negativePion.pdgCode() / std::abs(negativePion.pdgCode())}; + float trackPts[2] = {pt(positivePion.px(), positivePion.py()), pt(negativePion.px(), negativePion.py())}; + float trackEtas[2] = {eta(positivePion.px(), positivePion.py(), positivePion.pz()), eta(negativePion.px(), negativePion.py(), negativePion.pz())}; + float trackPhis[2] = {phi(positivePion.px(), positivePion.py()), phi(negativePion.px(), negativePion.py())}; + mcTree(localBc, runNumber, + 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) + { + int runIndex = getRunIndex(collision.runNumber(), runNumbers); + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 0); // all collisions + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 0, runIndex); + + if (cutGapSide && collision.gapSide() != gapSide) + return; + if (useTrueGap && (collision.gapSide() != sgSelector.trueGap(collision, cutTrueGapSideFV0, cutTrueGapSideFT0A, cutTrueGapSideFT0C, cutTrueGapSideZDC))) // check true gap side + return; + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 1); // only double-gap collisions + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 1, runIndex); + + processReco(collision, tracks, runIndex); + } + PROCESS_SWITCH(UpcRhoAnalysis, processSGdata, "analyse SG data", true); + + void processDGdata(FullUdDgCollision const& collision, FullUdTracks const& tracks) + { + int runIndex = getRunIndex(collision.runNumber(), runNumbers); + rQC.fill(HIST("QC/collisions/hSelectionCounter"), 1); // no single-gap collisions in dataset + rQC.fill(HIST("QC/collisions/hSelectionCounterPerRun"), 1, runIndex); + + processReco(collision, tracks, runIndex); + } + PROCESS_SWITCH(UpcRhoAnalysis, processDGdata, "analyse DG data", false); + + void processMCdata(aod::UDMcCollision const& mcCollision, aod::UDMcParticles const& mcParticles) + { + processMC(mcCollision, mcParticles, -1); + } + PROCESS_SWITCH(UpcRhoAnalysis, processMCdata, "analyse MC data", false); + + void processMCdataWithBCs(aod::UDMcCollision const& mcCollision, aod::UDMcParticles const& mcParticles, aod::BCs const& bcs) + { + int runNumber = -1; + if (bcs.size() != 0) { + auto bc = bcs.begin(); + runNumber = bc.runNumber(); + } + processMC(mcCollision, mcParticles, runNumber); + } + PROCESS_SWITCH(UpcRhoAnalysis, processMCdataWithBCs, "analyse MC data with BCs (only with on-the-fly skimming)", false); + + void processCollisionRecoCheck(aod::UDMcCollision 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..f8f03970ff0 --- /dev/null +++ b/PWGUD/Tasks/upcRhoPrimeAnalysis.cxx @@ -0,0 +1,425 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "Math/Vector4D.h" +#include "TH1F.h" +#include "TH2F.h" + +#include "random" +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +// Define UD tables +using UDtracks = soa::Join; +using UDCollisions = soa::Join; + +namespace o2::aod +{ +namespace fourpi +{ +// Declare columns +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); // Run number for event identification +DECLARE_SOA_COLUMN(M, m, double); // Invariant mass of the system +DECLARE_SOA_COLUMN(Pt, pt, double); // Transverse momentum of the system +DECLARE_SOA_COLUMN(Eta, eta, double); // Pseudorapidity of the system +DECLARE_SOA_COLUMN(Phi, phi, double); // Azimuthal angle of the system +DECLARE_SOA_COLUMN(PosX, posX, double); // Vertex X position +DECLARE_SOA_COLUMN(PosY, posY, double); // Vertex Y position +DECLARE_SOA_COLUMN(PosZ, posZ, double); // Vertex Z position +DECLARE_SOA_COLUMN(TotalCharge, totalCharge, int); // Total charge of selected tracks +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); // FT0A amplitude +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); // FT0C amplitude +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); // FV0A amplitude +DECLARE_SOA_COLUMN(NumContrib, numContrib, int32_t); // Number of primary vertex contributors +DECLARE_SOA_COLUMN(Sign, sign, std::vector); // Track charges +DECLARE_SOA_COLUMN(TrackPt, trackPt, std::vector); // Track pT values +DECLARE_SOA_COLUMN(TrackEta, trackEta, std::vector); // Track eta values +DECLARE_SOA_COLUMN(TrackPhi, trackPhi, std::vector); // Track phi values +DECLARE_SOA_COLUMN(TPCNSigmaEl, tpcNSigmaEl, std::vector); // TPC nσ for electrons +DECLARE_SOA_COLUMN(TPCNSigmaPi, tpcNSigmaPi, std::vector); // TPC nσ for pions +DECLARE_SOA_COLUMN(TPCNSigmaKa, tpcNSigmaKa, std::vector); // TPC nσ for kaons +DECLARE_SOA_COLUMN(TPCNSigmaPr, tpcNSigmaPr, std::vector); // TPC nσ for protons +DECLARE_SOA_COLUMN(TrackID, trackID, std::vector); // Track identifiers +DECLARE_SOA_COLUMN(IsReconstructedWithUPC, isReconstructedWithUPC, bool); // UPC mode reconstruction flag +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); // ZNA timing +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); // ZNC timing +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); // ZNA energy +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); // ZNC energy +DECLARE_SOA_COLUMN(IsChargeZero, isChargeZero, bool); // Neutral system flag +DECLARE_SOA_COLUMN(OccupancyInTime, occupancyInTime, int); // Occupancy in time +DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, double); // Hadronic interaction rate +} // namespace fourpi + +// Define the output +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::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, + fourpi::IsChargeZero, fourpi::OccupancyInTime, fourpi::HadronicRate); +} // namespace o2::aod + +struct upcRhoPrimeAnalysis { + Produces systemTree; + + // System selection configuration + Configurable systemYCut{"systemYCut", 0.5, "Max Rapidity of rho prime"}; + Configurable systemPtCut{"systemPtCut", 0.1, "Min Pt of rho prime"}; + Configurable systemMassMinCut{"systemMassMinCut", 0.8, "Min Mass of rho prime"}; + Configurable systemMassMaxCut{"systemMassMaxCut", 2.2, "Max Mass of rho prime"}; + Configurable etaCut{"etaCut", 0.9, "Track Pseudorapidity"}; + + // Event selection configuration + Configurable vZCut{"vZCut", 10.0, "Cut on vertex Z position"}; + Configurable numPVContrib{"numPVContrib", 4, "Number of PV contributors"}; + Configurable fv0Cut{"fv0Cut", 50.0, "FV0 amplitude cut"}; + Configurable ft0aCut{"ft0aCut", 50.0, "FT0A amplitude cut"}; + Configurable ft0cCut{"ft0cCut", 50.0, "FT0C amplitude cut"}; + Configurable zdcCut{"zdcCut", 0.0, "ZDC energy cut"}; + Configurable sbpCut{"sbpCut", true, "SBP cut"}; + Configurable itsROFbCut{"itsROFbCut", true, "ITS ROFb cut"}; + Configurable vtxITSTPCcut{"vtxITSTPCcut", true, "Vertex ITS-TPC cut"}; + Configurable tfbCut{"tfbCut", true, "TFB cut"}; + Configurable specifyGapSide{"specifyGapSide", true, "specify gap side for SG/DG produced data"}; + Configurable gapSide{"gapSide", 2, "gap side for SG produced data"}; + + // Track selection configuration + Configurable useOnlyPVtracks{"useOnlyPVtracks", true, "Use only PV tracks"}; + Configurable tpcChi2NClsCut{"tpcChi2NClsCut", 5.0, "TPC chi2/N clusters cut"}; + Configurable itsChi2NClsCut{"itsChi2NClsCut", 36.0, "ITS chi2/N clusters cut"}; + Configurable nSigmaTPCcut{"nSigmaTPCcut", 5.0, "TPC nSigma cut"}; + Configurable dcaXYcut{"dcaXYcut", 0, "dcaXY cut"}; + Configurable dcaZcut{"dcaZcut", 2, "dcaZ cut"}; + Configurable minTPCFindableClusters{"minTPCFindableClusters", 70, "Minimum number of findable TPC clusters"}; + + // Define histogram registry + HistogramRegistry registry{ + "registry", + {// Event flow histograms + {"Events/Flow", "Event flow;Cut;Counts", {HistType::kTH1F, {{9, 0, 9}}}}, + {"Events/VertexZ", "Vertex Z;z (cm);Counts", {HistType::kTH1F, {{200, -20, 20}}}}, + {"Events/NumContrib", "Number of contributors;N_{contrib};Counts", {HistType::kTH1F, {{100, 0, 100}}}}, + {"Events/FV0Amplitude", "FV0 amplitude;Amplitude;Counts", {HistType::kTH1F, {{200, 0, 200}}}}, + {"Events/FT0AmplitudeA", "FT0A amplitude;Amplitude;Counts", {HistType::kTH1F, {{200, 0, 200}}}}, + {"Events/FT0AmplitudeC", "FT0C amplitude;Amplitude;Counts", {HistType::kTH1F, {{200, 0, 200}}}}, + {"Events/ZDCEnergy", "ZDC energy;Energy (TeV);Counts", {HistType::kTH1F, {{200, 0, 2}}}}, + + // Track quality histograms + {"Tracks/Pt", "Track p_{T};p_{T} (GeV/c);Counts", {HistType::kTH1F, {{200, 0, 2}}}}, + {"Tracks/Eta", "Track #eta;#eta;Counts", {HistType::kTH1F, {{200, -2, 2}}}}, + {"Tracks/TPCNSigmaPi", "TPC n#sigma for #pi;n#sigma;Counts", {HistType::kTH1F, {{200, -10, 10}}}}, + {"Tracks/TPCChi2NCl", "TPC #chi^{2}/N_{cls};#chi^{2}/N_{cls};Counts", {HistType::kTH1F, {{200, 0, 20}}}}, + {"Tracks/ITSChi2NCl", "ITS #chi^{2}/N_{cls};#chi^{2}/N_{cls};Counts", {HistType::kTH1F, {{200, 0, 50}}}}, + {"Tracks/RejectionReasons", "Track rejection reasons;Reason;Counts", {HistType::kTH1F, {{12, 0, 12}}}}, + {"Tracks/DCASpectrum", "Track DCA spectrum;DCA (cm);Counts", {HistType::kTH1F, {{100, 0, 5}}}}, + {"Tracks/ChargeDistribution", "Track charge distribution;Charge;Counts", {HistType::kTH1F, {{3, -1.5, 1.5}}}}, + {"Tracks/TPCClusters", "TPC clusters findable;N_{clusters};Counts", {HistType::kTH1F, {{100, 0, 200}}}}, + + // System kinematics histograms + {"System/hM", ";m (GeV/#it{c}^{2});counts", {HistType::kTH1F, {{1000, 0.0, 10.0}}}}, + {"System/hPt", ";p_{T} (GeV/#it{c});counts", {HistType::kTH1F, {{1000, 0.0, 10.0}}}}, + {"System/hEta", ";#eta;counts", {HistType::kTH1F, {{180, -0.9, 0.9}}}}, + {"System/hPhi", ";#phi;counts", {HistType::kTH1F, {{180, 0.0, 6.28}}}}, + {"System/hY", ";y;counts", {HistType::kTH1F, {{180, -0.9, 0.9}}}}, + + // Comparison histograms + {"Cuts/MBefore", "Mass before cuts;m (GeV/c^{2});Counts", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"Cuts/MAfter", "Mass after cuts;m (GeV/c^{2});Counts", {HistType::kTH1F, {{1000, 0, 10}}}}, + {"Cuts/PtBefore", "p_{T} before cuts;p_{T} (GeV/c);Counts", {HistType::kTH1F, {{1000, 0, 1}}}}, + {"Cuts/PtAfter", "p_{T} after cuts;p_{T} (GeV/c);Counts", {HistType::kTH1F, {{1000, 0, 10}}}}}}; + + void init(InitContext&) + { + // Configure event flow histogram labels + auto hFlow = registry.get(HIST("Events/Flow")); + hFlow->GetXaxis()->SetBinLabel(1, "All events"); + hFlow->GetXaxis()->SetBinLabel(2, "ITS-TPC cut"); + hFlow->GetXaxis()->SetBinLabel(3, "SBP cut"); + hFlow->GetXaxis()->SetBinLabel(4, "ITS ROFb cut"); + hFlow->GetXaxis()->SetBinLabel(5, "TFB cut"); + hFlow->GetXaxis()->SetBinLabel(6, "Gap Side cut"); + hFlow->GetXaxis()->SetBinLabel(7, "PV contrib cut"); + hFlow->GetXaxis()->SetBinLabel(8, "Z vtx cut"); + hFlow->GetXaxis()->SetBinLabel(9, "4 tracks cut"); + + // Configure track rejection reasons histogram labels + auto hReject = registry.get(HIST("Tracks/RejectionReasons")); + hReject->GetXaxis()->SetBinLabel(1, "All Tracks"); + hReject->GetXaxis()->SetBinLabel(2, "PV Contributor"); + hReject->GetXaxis()->SetBinLabel(3, "Has ITS+TPC"); + hReject->GetXaxis()->SetBinLabel(4, "pT > 0.1 GeV/c"); + hReject->GetXaxis()->SetBinLabel(5, "TPC chi2/cluster"); + hReject->GetXaxis()->SetBinLabel(6, "ITS chi2/cluster"); + hReject->GetXaxis()->SetBinLabel(7, "TPC clusters findable"); + hReject->GetXaxis()->SetBinLabel(8, "TPC nSigmaPi"); + hReject->GetXaxis()->SetBinLabel(9, "Eta acceptance"); + hReject->GetXaxis()->SetBinLabel(10, "DCAz cut"); + hReject->GetXaxis()->SetBinLabel(11, "DCAxy cut"); + hReject->GetXaxis()->SetBinLabel(12, "Accepted Tracks"); + } + + void process(UDCollisions::iterator const& collision, UDtracks const& tracks) + { + // Count all processed events + registry.fill(HIST("Events/Flow"), 0); + + // Fill basic event diagnostics + registry.fill(HIST("Events/VertexZ"), collision.posZ()); + registry.fill(HIST("Events/NumContrib"), collision.numContrib()); + registry.fill(HIST("Events/FV0Amplitude"), collision.totalFV0AmplitudeA()); + registry.fill(HIST("Events/FT0AmplitudeA"), collision.totalFT0AmplitudeA()); + registry.fill(HIST("Events/FT0AmplitudeC"), collision.totalFT0AmplitudeC()); + registry.fill(HIST("Events/ZDCEnergy"), collision.energyCommonZNA()); + registry.fill(HIST("Events/ZDCEnergy"), collision.energyCommonZNC()); + + // Apply event selection cuts in sequence + if (collision.vtxITSTPC() != vtxITSTPCcut) + return; + registry.fill(HIST("Events/Flow"), 1); + + if (collision.sbp() != sbpCut) + return; + registry.fill(HIST("Events/Flow"), 2); + + if (collision.itsROFb() != itsROFbCut) + return; + registry.fill(HIST("Events/Flow"), 3); + + if (collision.tfb() != tfbCut) + return; + registry.fill(HIST("Events/Flow"), 4); + + if (specifyGapSide && collision.gapSide() != gapSide) + return; + if (collision.totalFV0AmplitudeA() > fv0Cut) + return; + if (collision.totalFT0AmplitudeA() > ft0aCut) + return; + if (collision.totalFT0AmplitudeC() > ft0cCut) + return; + if (collision.energyCommonZNA() > zdcCut || collision.energyCommonZNC() > zdcCut) + return; + registry.fill(HIST("Events/Flow"), 5); + + if (collision.numContrib() != numPVContrib) + return; + registry.fill(HIST("Events/Flow"), 6); + + if (std::abs(collision.posZ()) > vZCut) + return; + registry.fill(HIST("Events/Flow"), 7); + + std::vector posPions; + std::vector negPions; + posPions.reserve(2); + negPions.reserve(2); + + // Loop over all tracks in the event + for (const auto& track : tracks) { + registry.fill(HIST("Tracks/RejectionReasons"), 0); // Count all tracks + + // Track selection criteria applied in sequence: + if (useOnlyPVtracks && !track.isPVContributor()) { + registry.fill(HIST("Tracks/RejectionReasons"), 1); + continue; + } + + if (!track.hasITS() || !track.hasTPC()) { + registry.fill(HIST("Tracks/RejectionReasons"), 2); + continue; + } + + // Fill track spectra + registry.fill(HIST("Tracks/Pt"), track.pt()); + registry.fill(HIST("Tracks/Eta"), eta(track.px(), track.py(), track.pz())); + registry.fill(HIST("Tracks/TPCNSigmaPi"), track.tpcNSigmaPi()); + registry.fill(HIST("Tracks/TPCChi2NCl"), track.tpcChi2NCl()); + registry.fill(HIST("Tracks/ITSChi2NCl"), track.itsChi2NCl()); + registry.fill(HIST("Tracks/DCASpectrum"), std::hypot(track.dcaXY(), track.dcaZ())); + registry.fill(HIST("Tracks/ChargeDistribution"), track.sign()); + registry.fill(HIST("Tracks/TPCClusters"), track.tpcNClsFindable()); + + if (track.pt() <= 0.1f) { + registry.fill(HIST("Tracks/RejectionReasons"), 3); + continue; + } + + if (track.tpcChi2NCl() > tpcChi2NClsCut) { + registry.fill(HIST("Tracks/RejectionReasons"), 4); + continue; + } + if (track.itsChi2NCl() > itsChi2NClsCut) { + registry.fill(HIST("Tracks/RejectionReasons"), 5); + continue; + } + + if (track.tpcNClsFindable() < minTPCFindableClusters) { + registry.fill(HIST("Tracks/RejectionReasons"), 6); + continue; + } + + if (std::abs(track.tpcNSigmaPi()) > nSigmaTPCcut) { + registry.fill(HIST("Tracks/RejectionReasons"), 7); + continue; + } + + float trackEta = eta(track.px(), track.py(), track.pz()); + if (std::abs(trackEta) > etaCut) { + registry.fill(HIST("Tracks/RejectionReasons"), 8); + continue; + } + + if (std::abs(track.dcaZ()) > dcaZcut) { + registry.fill(HIST("Tracks/RejectionReasons"), 9); + continue; + } + + float maxDCAxy = 0.0105 + 0.035 / std::pow(track.pt(), 1.1); + if (dcaXYcut == 0 && (std::fabs(track.dcaXY()) > maxDCAxy)) { + registry.fill(HIST("Tracks/RejectionReasons"), 10); + continue; + } else if (dcaXYcut != 0 && (std::fabs(track.dcaXY()) > dcaXYcut)) { + registry.fill(HIST("Tracks/RejectionReasons"), 10); + continue; + } + + // Track passed all selection criteria + registry.fill(HIST("Tracks/RejectionReasons"), 11); + + if (track.sign() > 0 && posPions.size() < 2) { + posPions.push_back(track); + } else if (track.sign() < 0 && negPions.size() < 2) { + negPions.push_back(track); + } + + if (posPions.size() == 2 && negPions.size() == 2) + break; + } + + if (posPions.size() != 2 || negPions.size() != 2) { + return; + } + registry.fill(HIST("Events/Flow"), 8); + + std::vector selectedTracks; + selectedTracks.insert(selectedTracks.end(), posPions.begin(), posPions.end()); + selectedTracks.insert(selectedTracks.end(), negPions.begin(), negPions.end()); + + // Reconstruct the 4-pion system + ROOT::Math::PxPyPzMVector fourPionSystem; + std::vector pionFourVectors; + + for (const auto& track : selectedTracks) { + ROOT::Math::PxPyPzMVector pionVec( + track.px(), track.py(), track.pz(), + o2::constants::physics::MassPionCharged); + fourPionSystem += pionVec; + pionFourVectors.push_back(pionVec); + } + + // Fill pre-cut system histograms + registry.fill(HIST("Cuts/MBefore"), fourPionSystem.M()); + registry.fill(HIST("Cuts/PtBefore"), fourPionSystem.Pt()); + + // Apply system-level kinematic cuts + if (fourPionSystem.M() < systemMassMinCut || fourPionSystem.M() > systemMassMaxCut) + return; + if (fourPionSystem.Pt() > systemPtCut) + return; + if (std::abs(fourPionSystem.Rapidity()) > systemYCut) + return; + + // Fill post-cut system histograms + registry.fill(HIST("Cuts/MAfter"), fourPionSystem.M()); + registry.fill(HIST("Cuts/PtAfter"), fourPionSystem.Pt()); + registry.fill(HIST("System/hM"), fourPionSystem.M()); + registry.fill(HIST("System/hPt"), fourPionSystem.Pt()); + registry.fill(HIST("System/hEta"), fourPionSystem.Eta()); + registry.fill(HIST("System/hPhi"), fourPionSystem.Phi() + o2::constants::math::PI); + registry.fill(HIST("System/hY"), fourPionSystem.Rapidity()); + + std::vector trackPts, trackEtas, trackPhis; + std::vector trackSigns, trackIDs; + std::vector tpcNSigmasEl, tpcNSigmasPi, tpcNSigmasKa, tpcNSigmasPr; + + for (size_t i = 0; i < selectedTracks.size(); i++) { + const auto& track = selectedTracks[i]; + trackPts.push_back(track.pt()); + trackEtas.push_back(eta(track.px(), track.py(), track.pz())); + trackPhis.push_back(phi(track.px(), track.py())); + trackSigns.push_back(track.sign()); + tpcNSigmasEl.push_back(track.tpcNSigmaEl()); + tpcNSigmasPi.push_back(track.tpcNSigmaPi()); + tpcNSigmasKa.push_back(track.tpcNSigmaKa()); + tpcNSigmasPr.push_back(track.tpcNSigmaPr()); + trackIDs.push_back(i); + } + + bool isReconstructedWithUPC = (collision.flags() == 1); + + // Fill the output + systemTree( + collision.runNumber(), + fourPionSystem.M(), + fourPionSystem.Pt(), + fourPionSystem.Rapidity(), + fourPionSystem.Phi(), + collision.posX(), + collision.posY(), + collision.posZ(), + 0, // Total charge = 0 + collision.totalFT0AmplitudeA(), + collision.totalFT0AmplitudeC(), + collision.totalFV0AmplitudeA(), + collision.numContrib(), + trackSigns, + trackPts, + trackEtas, + trackPhis, + tpcNSigmasEl, + tpcNSigmasPi, + tpcNSigmasKa, + tpcNSigmasPr, + trackIDs, + isReconstructedWithUPC, + collision.timeZNA(), + collision.timeZNC(), + collision.energyCommonZNA(), + collision.energyCommonZNC(), + true, // Always charge zero for our selection + collision.occupancyInTime(), + collision.hadronicRate()); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/upcTauCentralBarrelRL.cxx b/PWGUD/Tasks/upcTauCentralBarrelRL.cxx deleted file mode 100644 index 965bfb6f327..00000000000 --- a/PWGUD/Tasks/upcTauCentralBarrelRL.cxx +++ /dev/null @@ -1,2581 +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" -#include "PWGUD/Core/SGSelector.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; - SGSelector sgSelector; - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - // declare configurables - Configurable verboseInfo{"verboseInfo", true, {"Print general info to terminal; default it true."}}; - 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{"FV0", 100, "FV0A threshold for SG selector"}; - Configurable cutMyGapSideFT0A{"FT0A", 200., "FT0A threshold for SG selector"}; - Configurable cutMyGapSideFT0C{"FT0C", 100., "FT0C threshold for SG selector"}; - Configurable cutMyGapSideZDC{"ZDC", 10., "ZDC threshold for SG selector"}; - Configurable usePIDwithTOF{"usePIDwithTOF", false, {"Determine whether also TOF should be used in testPIDhypothesis"}}; - Configurable usePIDwithTOFsigmaAfterTPC{"usePIDwithTOFsigmaAfterTPC", true, {"Determine whether cut on TOF n sigma should be used after TPC-based decision in testPIDhypothesis"}}; - Configurable cutMyTPCnSigmaEl{"cutMyTPCnSigmaEl", 3.f, {"n sigma cut on el in absolut values"}}; - Configurable cutMyTPCnSigmaMu{"cutMyTPCnSigmaMu", 3.f, {"n sigma cut on mu in absolut values"}}; - Configurable cutMyTPCnSigmaPi{"cutMyTPCnSigmaPi", 3.f, {"n sigma cut on pi in absolut values"}}; - Configurable cutMyNsigmaTPCPIDselector{"cutMyNsigmaTPCPIDselector", 35.f, {"n sigma TPC cut on all particles in absolut values for testPIDhypothesis"}}; - Configurable cutMyNsigmaTOFPIDselector{"cutMyNsigmaTOFPIDselector", 35.f, {"n sigma TOF cut on all particles in absolut values for testPIDhypothesis"}}; - 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"}}; - Configurable doMainHistos{"doMainHistos", true, {"Fill main histos"}}; - Configurable doPIDhistos{"doPIDhistos", true, {"Fill PID histos"}}; - Configurable doTwoTracks{"doTwoTracks", true, {"Define histos for two tracks and allow to fill them"}}; - Configurable doPionStudy{"doPionStudy", false, {"Define histos for two pions and allow to fill them"}}; - Configurable doMuonStudy{"doMuonStudy", false, {"Define histos for two muons and allow to fill them"}}; - Configurable doJpsiMuMuTests{"doJpsiMuMuTests", false, {"Define specific-tests histos for two muons and allow to fill them"}}; - Configurable doFourTracks{"doFourTracks", false, {"Define histos for four tracks and allow to fill them"}}; - Configurable doFourTrackPsi2S{"doFourTrackPsi2S", true, {"Define histos for Psi2S into four charged tracks (pi/mu) and allow to fill them"}}; - Configurable doSixTracks{"doSixTracks", false, {"Define histos for six tracks and allow to fill them"}}; - - 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 axisNtracks{30, -0.5, 29.5}; - 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 axisDCA{100, -0.5, 0.5}; - const AxisSpec axisAvgITSclsSizes{500, 0., 10.}; - const AxisSpec axisTPCdEdx{2000, 0., 200.}; - const AxisSpec axisTOFsignal{2500, -10000., 40000.}; - const AxisSpec axisNsigma{200, -10., 10.}; - 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("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, {axisNtracks}); - histos.add("Events/hNreconstructedPVGT", ";Number of good track particles from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {axisNtracks}); - histos.add("Events/hNreconstructedNotPVGT", ";Number of good track particles from NOT primary vertex in a collision (-);Number of events (-);Number of events (-)", HistType::kTH1D, {axisNtracks}); - histos.add("Events/hNreconstructedPVGTelectrons", ";Number of good track identified electrons from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {axisNtracks}); - histos.add("Events/hNreconstructedPVGTmuons", ";Number of good track identified muons from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {axisNtracks}); - histos.add("Events/hNreconstructedPVGTpions", ";Number of good track identified pions from primary vertex in a collision (-);Number of events (-)", HistType::kTH1D, {axisNtracks}); - 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, {axisNtracks}); - histos.add("Events/hChannelsRatio", ";Channels (-);Number of events (-)", HistType::kTH1D, {{10, -0.5, 9.5}}); - - 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/raw/PID/hTPCsignalVsZ", "All tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisZvtx, axisTPCdEdx}); - histos.add("Tracks/raw/PID/hTPCsignalVsP", "All tracks;Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/raw/PID/hTPCsignalVsEta", "All tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - histos.add("Tracks/raw/PID/hTPCsignalVsPhi", "All tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/raw/PID/hTOFsignalVsP", "All tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - 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, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/raw/PID/PosCharge/hTPCsignalVsEta", "Positively charged tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - histos.add("Tracks/raw/PID/PosCharge/hTPCsignalVsPhi", "Positively charged tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/raw/PID/PosCharge/hTOFsignalVsP", "Positively charged tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - 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, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/raw/PID/NegCharge/hTPCsignalVsEta", "Negatively charged tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - histos.add("Tracks/raw/PID/NegCharge/hTPCsignalVsPhi", "Negatively charged tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/raw/PID/NegCharge/hTOFsignalVsP", "Negatively charged tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - - 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("Tracks/GoodTrack/PID/hTPCsignalVsZ", "All good tracks;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/hTPCsignalVsEta", "All good tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/hTPCsignalVsPhi", "All good tracks;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/hTOFsignalVsP", "All good tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - 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, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/PosCharge/hTPCsignalVsEta", "Positively charged good tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - 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, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/PosCharge/hTOFsignalVsP", "Positively charged good tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - 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, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/NegCharge/hTPCsignalVsEta", "Negatively charged good tracks;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - 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, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/NegCharge/hTOFsignalVsP", "Negatively charged good tracks;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("Tracks/GoodTrack/PID/Electron/hTPCsignalVsZ", "Identified electrons;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Electron/hTPCsignalVsEta", "Identified electrons;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Electron/hTPCsignalVsPhi", "Identified electrons;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Electron/hTOFsignalVsP", "Identified electrons;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaVsP", "Identified electrons;Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaVsP", "Identified electrons;Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsMu", "Identified electrons;n#sigma^{#it{e}}_{TPC} (arb. units);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsMu", "Identified electrons;n#sigma^{#it{e}}_{TOF} (arb. units);n#sigma^{#mu}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsPi", "Identified electrons;n#sigma^{#it{e}}_{TPC} (arb. units);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsPi", "Identified electrons;n#sigma^{#it{e}}_{TOF} (arb. units);n#sigma^{#pi}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - 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, {axisNsigma, axisNsigma}); - 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, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Electron/hTPCnSigmaElVsPr", "Identified electrons;n#sigma^{#it{e}}_{TPC} (arb. units);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Electron/hTOFnSigmaElVsPr", "Identified electrons;n#sigma^{#it{e}}_{TOF} (arb. units);n#sigma^{p}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTPCsignalVsZ", "Identified muons;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Muon/hTPCsignalVsEta", "Identified muons;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Muon/hTPCsignalVsPhi", "Identified muons;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Muon/hTOFsignalVsP", "Identified muons;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaVsP", "Identified muons;Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaVsP", "Identified muons;Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsEl", "Identified muons;n#sigma^{#mu}_{TPC} (arb. units);n#sigma^{#it{e}}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsEl", "Identified muons;n#sigma^{#mu}_{TOF} (arb. units);n#sigma^{#it{e}}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsPi", "Identified muons;n#sigma^{#mu}_{TPC} (arb. units);n#sigma^{#pi}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsPi", "Identified muons;n#sigma^{#mu}_{TOF} (arb. units);n#sigma^{#pi}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsKa", "Identified muons;n#sigma^{#mu}_{TPC} (arb. units);n#sigma^{#it{K}}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsKa", "Identified muons;n#sigma^{#mu}_{TOF} (arb. units);n#sigma^{#it{K}}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTPCnSigmaMuVsPr", "Identified muons;n#sigma^{#mu}_{TPC} (arb. units);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Muon/hTOFnSigmaMuVsPr", "Identified muons;n#sigma^{#mu}_{TOF} (arb. units);n#sigma^{p}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTPCsignalVsZ", "Identified pions;Track z-vertex (cm);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Pion/hTPCsignalVsEta", "Identified pions;Track #eta (-);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisEta, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Pion/hTPCsignalVsPhi", "Identified pions;Track #phi (rad);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Pion/hTOFsignalVsP", "Identified pions;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaVsP", "Identified pions;Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaVsP", "Identified pions;Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsEl", "Identified pions;n#sigma^{#pi}_{TPC} (arb. units);n#sigma^{#it{e}}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsEl", "Identified pions;n#sigma^{#pi}_{TOF} (arb. units);n#sigma^{#it{e}}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsMu", "Identified pions;n#sigma^{#pi}_{TPC} (arb. units);n#sigma^{#mu}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsMu", "Identified pions;n#sigma^{#pi}_{TOF} (arb. units);n#sigma^{#mu}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsKa", "Identified pions;n#sigma^{#pi}_{TPC} (arb. units);n#sigma^{#it{K}}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsKa", "Identified pions;n#sigma^{#pi}_{TOF} (arb. units);n#sigma^{#it{K}}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTPCnSigmaPiVsPr", "Identified pions;n#sigma^{#pi}_{TPC} (arb. units);n#sigma^{p}_{TPC} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - histos.add("Tracks/GoodTrack/PID/Pion/hTOFnSigmaPiVsPr", "Identified pions;n#sigma^{#pi}_{TOF} (arb. units);n#sigma^{p}_{TOF} (arb. units)", HistType::kTH2D, {axisNsigma, axisNsigma}); - 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, {axisZvtx, axisTPCdEdx}); - 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, {axisMom, axisTPCdEdx}); - 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, {axisPt, axisTPCdEdx}); - 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, {axisEta, axisTPCdEdx}); - 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, {axisPhi, axisTPCdEdx}); - histos.add("Tracks/GoodTrack/PID/Others/hTOFsignalVsP", "Identified NOT electron/Muon/Pion;Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - - if (doTwoTracks) { - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/PID/hTOFsignalVsP", ";Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/TwoElectrons/hLeadingPvsOtherP", ";Leading #it{p} (GeV/c); Other #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingPwideVsOtherPwide", ";Leading #it{p} (GeV/c); Other #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingPtVsOtherPt", ";Leading #it{p_{T} (GeV/c); Other #it{p_{T} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingPhiVsOtherPhi", ";Leading #phi (rad); Other #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/TwoElectrons/hLeadingRapVsOtherRap", ";Leading #it{y} (-); Other #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsLP", ";Leading #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTPCsignalVsOP", ";Other #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsP", ";Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsLP", ";Leading #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTOFsignalVsOP", ";Other #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsLP", ";Leading #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTPCnSigmaVsOP", ";Other #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsLP", ";Leading #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/TwoElectrons/PID/hTOFnSigmaVsOP", ";Other #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/TwoMuons/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/TwoPions/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/ElectronMuon/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/ElectronPion/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/MuonPion/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/ElectronMuPi/hElectronPvsOtherP", ";Electron #it{p} (GeV/c); #mu/#pi #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/ElectronMuPi/hElectronPwideVsOtherPwide", ";Electron #it{p} (GeV/c); #mu/#pi #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/ElectronMuPi/hElectronPtVsOtherPt", ";Electron #it{p_{T} (GeV/c); #mu/#pi #it{p_{T} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/ElectronMuPi/hElectronPhiVsOtherPhi", ";Electron #phi (rad); #mu/#pi #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/ElectronMuPi/hElectronRapVsOtherRap", ";Electron #it{y} (-); #mu/#pi #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsEP", ";Electron #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsOP", ";#mu/#pi #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsP", ";Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsEP", ";Electron #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsOP", ";Other #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsEP", ";Electron #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsMP", ";Muon #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsPP", ";Pion #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEP", ";Electron #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsMP", ";Muon #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPP", ";Pion #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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/ElectronOther/hElectronPvsOtherP", ";Electron #it{p} (GeV/c); Other #it{p} (GeV/c)", HistType::kTH2D, {axisMom, axisMom}); - histos.add("EventTwoTracks/ElectronOther/hElectronPwideVsOtherPwide", ";Electron #it{p} (GeV/c); Other #it{p} (GeV/c)", HistType::kTH2D, {axisMomWide, axisMomWide}); - histos.add("EventTwoTracks/ElectronOther/hElectronPtVsOtherPt", ";Electron #it{p_{T} (GeV/c); Other #it{p_{T} (GeV/c)", HistType::kTH2D, {axisPt, axisPt}); - histos.add("EventTwoTracks/ElectronOther/hElectronPhiVsOtherPhi", ";Electron #phi (rad); Other #phi (rad)", HistType::kTH2D, {axisPhi, axisPhi}); - histos.add("EventTwoTracks/ElectronOther/hElectronRapVsOtherRap", ";Electron #it{y} (-); Other #it{y} (-)", HistType::kTH2D, {axisRap, axisRap}); - histos.add("EventTwoTracks/ElectronOther/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/ElectronOther/PID/hTPCsignalVsEP", ";Electron #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/ElectronOther/PID/hTPCsignalVsOP", ";#it{e}/#mu/#pi #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/ElectronOther/PID/hTOFsignalVsP", ";Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/ElectronOther/PID/hTOFsignalVsEP", ";Electron #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/ElectronOther/PID/hTOFsignalVsOP", ";Other #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsEP", ";Electron #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsMP", ";Muon #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsPP", ";Pion #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsEP", ";Electron #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsMP", ";Muon #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsPP", ";Pion #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - - if (doPionStudy) { - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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}); - } - - if (doMuonStudy) { - 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}); - if (doJpsiMuMuTests) { - 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}); - if (doJpsiMuMuTests) { - 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/hJpsiPt", ";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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - 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}); - if (doJpsiMuMuTests) { - 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}); - if (doJpsiMuMuTests) { - 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("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsLP", ";Leading #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsOP", ";Other #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsP", ";Track #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsLP", ";Leading #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsOP", ";Other #it{p} (GeV/c);TOF signal (arb. units)", HistType::kTH2D, {axisMom, axisTOFsignal}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsLP", ";Leading #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsOP", ";Other #it{p} (GeV/c);n#sigma_{TPC} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsP", ";Track #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsLP", ";Leading #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - histos.add("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsOP", ";Other #it{p} (GeV/c);n#sigma_{TOF} (arb. units)", HistType::kTH2D, {axisMom, axisNsigma}); - } - } - - if (doFourTracks) { - 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/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - histos.add("EventFourTracks/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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/WithElectron/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - histos.add("EventFourTracks/WithElectron/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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/WithMuon/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - histos.add("EventFourTracks/WithMuon/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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("EventFourTracks/WithPion/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - histos.add("EventFourTracks/WithPion/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - if (doFourTrackPsi2S) { - histos.add("EventFourTracks/MuonsPions/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventFourTracks/MuonsPions/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventFourTracks/MuonsPions/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventFourTracks/MuonsPions/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventFourTracks/MuonsPions/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventFourTracks/MuonsPions/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventFourTracks/MuonsPions/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventFourTracks/MuonsPions/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - - histos.add("EventFourTracks/Psi2StoMuMuPiPi/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventFourTracks/Psi2StoMuMuPiPi/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventFourTracks/Psi2StoMuMuPiPi/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventFourTracks/Psi2StoMuMuPiPi/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventFourTracks/Psi2StoMuMuPiPi/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventFourTracks/Psi2StoMuMuPiPi/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventFourTracks/Psi2StoMuMuPiPi/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventFourTracks/Psi2StoMuMuPiPi/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - - histos.add("EventFourTracks/Psi2StoElElPiPi/hInvariantMass", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMass}); - histos.add("EventFourTracks/Psi2StoElElPiPi/hInvariantMassWide", ";Invariant mass (GeV/c^{2});Number of events (-)", HistType::kTH1D, {axisInvMassWide}); - histos.add("EventFourTracks/Psi2StoElElPiPi/hMotherP", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMom}); - histos.add("EventFourTracks/Psi2StoElElPiPi/hMotherPwide", ";Mother #it{p} (GeV/c);Number of events (-)", HistType::kTH1D, {axisMomWide}); - histos.add("EventFourTracks/Psi2StoElElPiPi/hMotherPt", ";Mother #it{p_{T}} (GeV/c);Number of events (-)", HistType::kTH1D, {axisPt}); - histos.add("EventFourTracks/Psi2StoElElPiPi/hMotherPhi", ";Mother #phi (rad);Number of events (-)", HistType::kTH1D, {axisPhi}); - histos.add("EventFourTracks/Psi2StoElElPiPi/hMotherRapidity", ";Mother #it{y} (-);Number of events (-)", HistType::kTH1D, {axisRap}); - histos.add("EventFourTracks/Psi2StoElElPiPi/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - } - } - - if (doSixTracks) { - 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//hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - histos.add("EventSixTracks/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - - 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}); - histos.add("EventSixTracks/SixPions/hMotherMassVsPt", ";Invariant mass (GeV/c^{2});Mother #it{p_{T}} (GeV/c)", HistType::kTH2D, {axisInvMassWide, axisPt}); - histos.add("EventSixTracks/SixPions/PID/hTPCsignalVsP", ";Track #it{p} (GeV/c);TPC d#it{E}/d#it{x} (arb. units)", HistType::kTH2D, {axisMom, axisTPCdEdx}); - } - - } // end init - - // run (always called before process :( ) - void run(ProcessingContext&) - { - - if (verboseInfo) - printLargeMessage("RUN METHOD"); - printDebugMessage(Form("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 - int whatPsi2Schannel(T const& trkDaug1, T const& trkDaug2, T const& trkDaug3, T const& trkDaug4, std::vector& vecPIDidx) - { - TLorentzVector jpsi, daug[4]; - 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())); - // Find index of the two largest values - std::vector> vecPts; - for (int i = 0; i < 4; i++) { - vecPts.push_back(std::make_pair(static_cast(daug[i].Pt()), i)); - } - sort(vecPts.begin(), vecPts.end()); - int idx1L = vecPts[vecPts.size() - 1].second; - int idx2L = vecPts[vecPts.size() - 2].second; - int idx3L = vecPts[vecPts.size() - 3].second; - int idx4L = vecPts[vecPts.size() - 4].second; - // Create the jpsi - jpsi = daug[idx1L] + daug[idx2L]; - // The two smallest-pT tracks should be pions - if ((vecPIDidx[idx3L] == P_MUON || vecPIDidx[idx3L] == P_PION) && (vecPIDidx[idx4L] == P_MUON || vecPIDidx[idx4L] == P_PION)) { - // Branch into Jpsi to mumu and Jpsi to elel - if ((vecPIDidx[idx1L] == P_MUON || vecPIDidx[idx1L] == P_PION) && (vecPIDidx[idx2L] == P_MUON || vecPIDidx[idx2L] == P_PION)) { - // Is jpsi mass? - if (jpsi.M() < 2.9 || jpsi.M() > 3.3) - return 0; // Not Psi2S - return 1; - } else if (vecPIDidx[idx1L] == P_ELECTRON && vecPIDidx[idx2L] == P_ELECTRON) { - // Is jpsi mass? - if (jpsi.M() < 2.75 || jpsi.M() > 3.3) - return 0; // Not Psi2S - return 2; - } else { - return 0; // Not Psi2S - } - } else { - return 0; // Not Psi2S - } - } - - 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(1); - histos.get(HIST("Events/hNreconstructedTracks"))->Fill(reconstructedBarrelTracks.size()); - - // 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)); - 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 countPVGTpionsSelection = 0; - int countPVGTmuonsSelection = 0; - int countTOFtracks = 0; - int countTPCcls70 = 0; - int countTPCcls100 = 0; - int countTPCxRws70 = 0; - int countTPCxRws100 = 0; - std::vector vecPVidx; - std::vector vecPIDidx; - // 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)); - 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++; - 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, cutMyNsigmaTPCPIDselector, cutMyNsigmaTOFPIDselector, usePIDwithTOF, usePIDwithTOFsigmaAfterTPC); - vecPIDidx.push_back(hypothesisID); - 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++; - } - if (abs(track.tpcNSigmaPi()) < cutMyTPCnSigmaPi) - countPVGTpionsSelection++; - if (abs(track.tpcNSigmaMu()) < cutMyTPCnSigmaMu) - 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 && doTwoTracks) { - 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); - - 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()); - histos.get(HIST("EventTwoTracks/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - 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/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 (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/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - 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/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - 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/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - 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/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - 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/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - 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/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - 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/hElectronPvsOtherP"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].P() : daug[1].P(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].P() : daug[0].P()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPwideVsOtherPwide"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].P() : daug[1].P(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].P() : daug[0].P()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPtVsOtherPt"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].Pt() : daug[0].Pt()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronPhiVsOtherPhi"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Phi() : daug[1].Phi(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].Phi() : daug[0].Phi()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/hElectronRapVsOtherRap"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Rapidity() : daug[1].Rapidity(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? 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); - } - 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/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - 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()); - if (countPVGTelectrons == 2) { - histos.get(HIST("EventTwoTracks/ElectronOther/hElectronPvsOtherP"))->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/ElectronOther/hElectronPwideVsOtherPwide"))->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/ElectronOther/hElectronPtVsOtherPt"))->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/ElectronOther/hElectronPhiVsOtherPhi"))->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/ElectronOther/hElectronRapVsOtherRap"))->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())); - } else { - histos.get(HIST("EventTwoTracks/ElectronOther/hElectronPvsOtherP"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].P() : daug[1].P(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].P() : daug[0].P()); - histos.get(HIST("EventTwoTracks/ElectronOther/hElectronPwideVsOtherPwide"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].P() : daug[1].P(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].P() : daug[0].P()); - histos.get(HIST("EventTwoTracks/ElectronOther/hElectronPtVsOtherPt"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].Pt() : daug[0].Pt()); - histos.get(HIST("EventTwoTracks/ElectronOther/hElectronPhiVsOtherPhi"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Phi() : daug[1].Phi(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].Phi() : daug[0].Phi()); - histos.get(HIST("EventTwoTracks/ElectronOther/hElectronRapVsOtherRap"))->Fill((enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Rapidity() : daug[1].Rapidity(), (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[1].Rapidity() : daug[0].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 && doPionStudy) { - 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/hMotherMassVsPt"))->Fill(motherOfPions.M(), motherOfPions.Pt()); - 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 && doMuonStudy) { - 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); - histos.get(HIST("EventTwoTracks/MuonsSelection/hMotherMassVsPt"))->Fill(motherOfMuons.M(), motherOfMuons.Pt()); - if (motherOfMuons.M() > 2.9 && motherOfMuons.M() < 3.2) - histos.get(HIST("EventTwoTracks/MuonsSelection/hJpsiPt"))->Fill(motherOfMuons.Pt()); - if (doJpsiMuMuTests) { - 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 (doJpsiMuMuTests) { - 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 (doJpsiMuMuTests) { - 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 (doJpsiMuMuTests) { - 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 && doFourTracks) { - - 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]; - - 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()); - histos.get(HIST("EventFourTracks/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - - // 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()); - histos.get(HIST("EventFourTracks/WithPion/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - } - 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()); - histos.get(HIST("EventFourTracks/WithElectron/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - } - 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()); - histos.get(HIST("EventFourTracks/WithMuon/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - } - // Hunting down psi2s: broad acceptance - if (doFourTrackPsi2S) { - if (countPVGTpions == 4 || - (countPVGTpions == 3 && countPVGTmuons == 1) || - (countPVGTpions == 2 && countPVGTmuons == 2) || - (countPVGTpions == 1 && countPVGTmuons == 3) || - countPVGTmuons == 4) { - histos.get(HIST("EventFourTracks/MuonsPions/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/MuonsPions/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/MuonsPions/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/MuonsPions/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/MuonsPions/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventFourTracks/MuonsPions/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventFourTracks/MuonsPions/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventFourTracks/MuonsPions/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - } - // Hunting down psi2s: ideal case - if (whatPsi2Schannel(trkDaug1, trkDaug2, trkDaug3, trkDaug4, vecPIDidx) == 1) { - histos.get(HIST("EventFourTracks/Psi2StoMuMuPiPi/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/Psi2StoMuMuPiPi/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/Psi2StoMuMuPiPi/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/Psi2StoMuMuPiPi/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/Psi2StoMuMuPiPi/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventFourTracks/Psi2StoMuMuPiPi/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventFourTracks/Psi2StoMuMuPiPi/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventFourTracks/Psi2StoMuMuPiPi/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - } - if (whatPsi2Schannel(trkDaug1, trkDaug2, trkDaug3, trkDaug4, vecPIDidx) == 2) { - histos.get(HIST("EventFourTracks/Psi2StoElElPiPi/hInvariantMass"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/Psi2StoElElPiPi/hInvariantMassWide"))->Fill(mother.M()); - histos.get(HIST("EventFourTracks/Psi2StoElElPiPi/hMotherP"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/Psi2StoElElPiPi/hMotherPwide"))->Fill(mother.P()); - histos.get(HIST("EventFourTracks/Psi2StoElElPiPi/hMotherPt"))->Fill(mother.Pt()); - histos.get(HIST("EventFourTracks/Psi2StoElElPiPi/hMotherPhi"))->Fill(mother.Phi()); - histos.get(HIST("EventFourTracks/Psi2StoElElPiPi/hMotherRapidity"))->Fill(mother.Rapidity()); - histos.get(HIST("EventFourTracks/Psi2StoElElPiPi/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - } - } - } else if (countPVGTselected == 6 && doSixTracks) { - 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]; - - 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()); - histos.get(HIST("EventSixTracks/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - - // 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()); - histos.get(HIST("EventSixTracks/SixPions/hMotherMassVsPt"))->Fill(mother.M(), mother.Pt()); - } - } else { - printDebugMessage("Other particles"); - } - - } // end fillHistograms - - template - void fillPIDhistograms(C /*reconstructedCollision*/, Ts reconstructedBarrelTracks) - { - - if (isFirstReconstructedCollisions) { - isFirstReconstructedCollisions = false; - if (verboseInfo) - printLargeMessage("START LOOPING OVER RECONSTRUCTED COLLISIONS"); - } - - // Loop over tracks without selections - for (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()); - 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 countPVGTselected = 0; - int countPVGTelectrons = 0; - int countPVGTmuons = 0; - int countPVGTpions = 0; - int countPVGTmuonsSelection = 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; - } - float trkPx = track.px(); - float trkPy = track.py(); - float trkPz = track.pz(); - if (track.hasTPC()) { - // histos.get(HIST("Tracks/GoodTrack/PID/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - 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()); - 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/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - 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/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - 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, cutMyNsigmaTPCPIDselector, cutMyNsigmaTOFPIDselector, usePIDwithTOF, usePIDwithTOFsigmaAfterTPC); - if (hypothesisID == P_ELECTRON || hypothesisID == P_MUON || hypothesisID == P_PION) { - countPVGTselected++; - vecPVidx.push_back(track.index()); - if (hypothesisID == P_ELECTRON) { - countPVGTelectrons++; - // histos.get(HIST("Tracks/GoodTrack/PID/Electron/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - 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/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - 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++; - // histos.get(HIST("Tracks/GoodTrack/PID/Pion/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - 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/hTPCsignalVsZ"))->Fill(track.z(),track.tpcSignal()); - 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()); - } - } - if (abs(track.tpcNSigmaMu()) < cutMyTPCnSigmaMu) - countPVGTmuonsSelection++; - - } // Loop over tracks with selections - - if (countPVGTselected == 2 && doTwoTracks) { - TLorentzVector daug[2], pion[2], 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())); - 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())); - 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())); - - if (trkDaug1.hasTPC()) { - histos.get(HIST("EventTwoTracks/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (trkDaug1.hasTOF()) { - histos.get(HIST("EventTwoTracks/PID/hTOFsignalVsP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); - } - if (countPVGTelectrons == 2) { - 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 (countPVGTmuonsSelection == 2 && doMuonStudy) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); - if (trkDaug1.hasTOF()) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); - } - } - if (countPVGTmuons == 2) - histos.get(HIST("EventTwoTracks/TwoMuons/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 2) - histos.get(HIST("EventTwoTracks/TwoPions/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTmuons == 1) - histos.get(HIST("EventTwoTracks/ElectronMuon/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 1) - histos.get(HIST("EventTwoTracks/ElectronPion/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 1 && countPVGTmuons == 1) - histos.get(HIST("EventTwoTracks/MuonPion/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if ((countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1)) { - 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 ((countPVGTelectrons == 2) || (countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1)) { - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); - if (trkDaug1.hasTOF()) { - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFsignalVsP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); - } - } - } - if (trkDaug2.hasTPC()) { - histos.get(HIST("EventTwoTracks/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (trkDaug2.hasTOF()) { - histos.get(HIST("EventTwoTracks/PID/hTOFsignalVsP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); - } - if (countPVGTelectrons == 2) { - 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 (countPVGTmuonsSelection == 2 && doMuonStudy) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); - if (trkDaug1.hasTOF()) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); - } - } - if (countPVGTmuons == 2) - histos.get(HIST("EventTwoTracks/TwoMuons/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 2) - histos.get(HIST("EventTwoTracks/TwoPions/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTmuons == 1) - histos.get(HIST("EventTwoTracks/ElectronMuon/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 1) - histos.get(HIST("EventTwoTracks/ElectronPion/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 1 && countPVGTmuons == 1) - histos.get(HIST("EventTwoTracks/MuonPion/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if ((countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1)) { - 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 ((countPVGTelectrons == 2) || (countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1)) { - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); - if (trkDaug2.hasTOF()) { - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFsignalVsP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); - } - } - } - if (trkDaug1.hasTPC() && trkDaug2.hasTPC()) { - if (countPVGTelectrons == 2) { - 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 (countPVGTmuonsSelection == 2 && doMuonStudy) { - if (daug[0].P() > daug[1].P()) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsLP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsOP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsLP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsOP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); - if (trkDaug1.hasTOF()) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsLP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsLP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); - } - if (trkDaug2.hasTOF()) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsOP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsOP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); - } - } else { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsOP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCsignalVsLP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsOP"))->Fill(daug[0].P(), trkDaug1.tpcNSigmaEl()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTPCnSigmaVsLP"))->Fill(daug[1].P(), trkDaug2.tpcNSigmaEl()); - if (trkDaug1.hasTOF()) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsOP"))->Fill(daug[0].P(), trkDaug1.tofSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsOP"))->Fill(daug[0].P(), trkDaug1.tofNSigmaEl()); - } - if (trkDaug2.hasTOF()) { - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFsignalVsLP"))->Fill(daug[1].P(), trkDaug2.tofSignal()); - histos.get(HIST("EventTwoTracks/MuonsSelection/PID/hTOFnSigmaVsLP"))->Fill(daug[1].P(), trkDaug2.tofNSigmaEl()); - } - } - } - if ((countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1)) { - double electronPt = (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); - double electronPID = (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); - double electronNsigma = (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? trkDaug1.tpcNSigmaEl() : trkDaug2.tpcNSigmaEl(); - double otherPt = (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); - double otherPID = (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); - double otherNsigmaMu = (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) ? trkDaug1.tpcNSigmaMu() : trkDaug2.tpcNSigmaMu(); - double otherNsigmaPi = (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) ? trkDaug1.tpcNSigmaPi() : trkDaug2.tpcNSigmaPi(); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsEP"))->Fill(electronPt, electronPID); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCsignalVsOP"))->Fill(otherPt, otherPID); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsEP"))->Fill(electronPt, electronNsigma); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsMP"))->Fill(otherPt, otherNsigmaMu); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTPCnSigmaVsPP"))->Fill(otherPt, otherNsigmaPi); - if (trkDaug1.hasTOF()) { - if (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) { - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsEP"))->Fill(electronPt, trkDaug1.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEP"))->Fill(electronPt, trkDaug1.tofNSigmaEl()); - } else { - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsOP"))->Fill(otherPt, trkDaug1.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsMP"))->Fill(otherPt, trkDaug1.tofNSigmaMu()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPP"))->Fill(otherPt, trkDaug1.tofNSigmaPi()); - } - } - if (trkDaug2.hasTOF()) { - if (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) { - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsEP"))->Fill(electronPt, trkDaug2.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsEP"))->Fill(electronPt, trkDaug2.tofNSigmaEl()); - } else { - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFsignalVsOP"))->Fill(otherPt, trkDaug2.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsMP"))->Fill(otherPt, trkDaug2.tofNSigmaMu()); - histos.get(HIST("EventTwoTracks/ElectronMuPi/PID/hTOFnSigmaVsPP"))->Fill(otherPt, trkDaug2.tofNSigmaPi()); - } - } - } - if ((countPVGTelectrons == 2) || (countPVGTelectrons == 1 && countPVGTmuons == 1) || (countPVGTelectrons == 1 && countPVGTpions == 1)) { - double electronPt = (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); - double electronPID = (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); - double electronNsigma = (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) ? trkDaug1.tpcNSigmaEl() : trkDaug2.tpcNSigmaEl(); - double otherPt = (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) ? daug[0].Pt() : daug[1].Pt(); - double otherPID = (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); - double otherNsigmaMu = (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) ? trkDaug1.tpcNSigmaMu() : trkDaug2.tpcNSigmaMu(); - double otherNsigmaPi = (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) ? trkDaug1.tpcNSigmaPi() : trkDaug2.tpcNSigmaPi(); - if (countPVGTelectrons == 2) { - electronPt = (daug[0].Pt() > daug[1].Pt()) ? daug[0].Pt() : daug[1].Pt(); - electronPID = (daug[0].Pt() > daug[1].Pt()) ? trkDaug1.tpcSignal() : trkDaug2.tpcSignal(); - electronNsigma = (daug[0].Pt() > daug[1].Pt()) ? trkDaug1.tpcNSigmaEl() : trkDaug2.tpcNSigmaEl(); - otherPt = (daug[0].Pt() > daug[1].Pt()) ? daug[1].Pt() : daug[0].Pt(); - otherPID = (daug[0].Pt() > daug[1].Pt()) ? trkDaug2.tpcSignal() : trkDaug1.tpcSignal(); - otherNsigmaMu = (daug[0].Pt() > daug[1].Pt()) ? trkDaug2.tpcNSigmaMu() : trkDaug1.tpcNSigmaMu(); - otherNsigmaPi = (daug[0].Pt() > daug[1].Pt()) ? trkDaug2.tpcNSigmaPi() : trkDaug1.tpcNSigmaPi(); - } - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCsignalVsEP"))->Fill(electronPt, electronPID); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCsignalVsOP"))->Fill(otherPt, otherPID); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsEP"))->Fill(electronPt, electronNsigma); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsMP"))->Fill(otherPt, otherNsigmaMu); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTPCnSigmaVsPP"))->Fill(otherPt, otherNsigmaPi); - if (trkDaug1.hasTOF()) { - if (enumMyParticle(trackPDG(trkDaug1)) == P_ELECTRON) { - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFsignalVsEP"))->Fill(electronPt, trkDaug1.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsEP"))->Fill(electronPt, trkDaug1.tofNSigmaEl()); - } else { - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFsignalVsOP"))->Fill(otherPt, trkDaug1.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsMP"))->Fill(otherPt, trkDaug1.tofNSigmaMu()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsPP"))->Fill(otherPt, trkDaug1.tofNSigmaPi()); - } - } - if (trkDaug2.hasTOF()) { - if (enumMyParticle(trackPDG(trkDaug2)) == P_ELECTRON) { - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFsignalVsEP"))->Fill(electronPt, trkDaug2.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsEP"))->Fill(electronPt, trkDaug2.tofNSigmaEl()); - } else { - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFsignalVsOP"))->Fill(otherPt, trkDaug2.tofSignal()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsMP"))->Fill(otherPt, trkDaug2.tofNSigmaMu()); - histos.get(HIST("EventTwoTracks/ElectronOther/PID/hTOFnSigmaVsPP"))->Fill(otherPt, trkDaug2.tofNSigmaPi()); - } - } - } - } - } else if (countPVGTselected == 4 && doFourTracks) { - - TLorentzVector 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())); - - if (trkDaug1.hasTPC()) { - histos.get(HIST("EventFourTracks/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 4) - histos.get(HIST("EventFourTracks/WithPion/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 3) - histos.get(HIST("EventFourTracks/WithElectron/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 3 && countPVGTmuons == 1) - histos.get(HIST("EventFourTracks/WithMuon/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - } - if (trkDaug2.hasTPC()) { - histos.get(HIST("EventFourTracks/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 4) - histos.get(HIST("EventFourTracks/WithPion/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 3) - histos.get(HIST("EventFourTracks/WithElectron/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 3 && countPVGTmuons == 1) - histos.get(HIST("EventFourTracks/WithMuon/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - } - if (trkDaug3.hasTPC()) { - histos.get(HIST("EventFourTracks/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - if (countPVGTpions == 4) - histos.get(HIST("EventFourTracks/WithPion/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 3) - histos.get(HIST("EventFourTracks/WithElectron/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - if (countPVGTpions == 3 && countPVGTmuons == 1) - histos.get(HIST("EventFourTracks/WithMuon/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - } - if (trkDaug4.hasTPC()) { - histos.get(HIST("EventFourTracks/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - if (countPVGTpions == 4) - histos.get(HIST("EventFourTracks/WithPion/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - if (countPVGTelectrons == 1 && countPVGTpions == 3) - histos.get(HIST("EventFourTracks/WithElectron/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - if (countPVGTpions == 3 && countPVGTmuons == 1) - histos.get(HIST("EventFourTracks/WithMuon/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - } - } else if (countPVGTselected == 6 && doSixTracks) { - TLorentzVector 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())); - - if (trkDaug1.hasTPC()) { - histos.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - if (countPVGTpions == 6) - histos.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[0].P(), trkDaug1.tpcSignal()); - } - if (trkDaug2.hasTPC()) { - histos.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - if (countPVGTpions == 6) - histos.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[1].P(), trkDaug2.tpcSignal()); - } - if (trkDaug3.hasTPC()) { - histos.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - if (countPVGTpions == 6) - histos.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[2].P(), trkDaug3.tpcSignal()); - } - if (trkDaug4.hasTPC()) { - histos.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - if (countPVGTpions == 6) - histos.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[3].P(), trkDaug4.tpcSignal()); - } - if (trkDaug5.hasTPC()) { - histos.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[4].P(), trkDaug5.tpcSignal()); - if (countPVGTpions == 6) - histos.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[4].P(), trkDaug5.tpcSignal()); - } - if (trkDaug6.hasTPC()) { - histos.get(HIST("EventSixTracks/PID/hTPCsignalVsP"))->Fill(daug[5].P(), trkDaug6.tpcSignal()); - if (countPVGTpions == 6) - histos.get(HIST("EventSixTracks/SixPions/PID/hTPCsignalVsP"))->Fill(daug[5].P(), trkDaug6.tpcSignal()); - } - } else { - printDebugMessage("Other particles"); - } - - } // end fillPIDhistograms - - void processDGrecoLevel(FullUDCollision const& reconstructedCollision, - FullUDTracks const& reconstructedBarrelTracks) - { - countCollisions++; - - if (doMainHistos) - fillHistograms(reconstructedCollision, reconstructedBarrelTracks); - if (doPIDhistos) - fillPIDhistograms(reconstructedCollision, reconstructedBarrelTracks); - - } // end processDGrecoLevel - - void processSGrecoLevel(FullSGUDCollision const& reconstructedCollision, - FullUDTracks const& reconstructedBarrelTracks) - { - countCollisions++; - - int gapSide = reconstructedCollision.gapSide(); - int trueGapSide = sgSelector.trueGap(reconstructedCollision, cutMyGapSideFV0, cutMyGapSideFT0A, cutMyGapSideFT0C, cutMyGapSideZDC); - histos.fill(HIST("Events/UDtableGapSide"), gapSide); - histos.fill(HIST("Events/TrueGapSideDiffToTableValue"), gapSide - trueGapSide); - if (useTrueGap) - gapSide = trueGapSide; - - if (gapSide != whichGapSide) - return; - - if (doMainHistos) - fillHistograms(reconstructedCollision, reconstructedBarrelTracks); - if (doPIDhistos) - fillPIDhistograms(reconstructedCollision, reconstructedBarrelTracks); - - } // end processDGrecoLevel - - void processAnalysisFinished(FullUDCollision const&) - { - - if (verboseInfo) - printLargeMessage("END OF THIS DATAFRAME"); - printDebugMessage(Form("countCollisions = %d", countCollisions)); - 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..78e9f7b48ae --- /dev/null +++ b/PWGUD/Tasks/upcTauRl.cxx @@ -0,0 +1,2505 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/UDTables.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" + +// ROOT headers +#include "Math/Vector4D.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 cutRCTflag{"cutRCTflag", 0, {"0 = off, 1 = CBT, 2 = CBT+ZDC, 3 = CBThadron, 4 = CBThadron+ZDC"}}; + 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 cutEvTFb{"cutEvTFb", true, {"Event selection bit kNoTimeFrameBorder"}}; + Configurable cutEvITSROFb{"cutEvITSROFb", true, {"Event selection bit kNoITSROFrameBorder"}}; + Configurable cutEvSbp{"cutEvSbp", true, {"Event selection bit kNoSameBunchPileup"}}; + Configurable cutEvZvtxFT0vPV{"cutEvZvtxFT0vPV", false, {"Event selection bit kIsGoodZvtxFT0vsPV"}}; + Configurable cutEvVtxITSTPC{"cutEvVtxITSTPC", true, {"Event selection bit kIsVertexITSTPC"}}; + 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; // good ITS-TPC matching means ITS ch2 is not negative + } + // 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 isGoodRCTflag(C const& coll) + { + switch (cutSample.cutRCTflag) { + case 1: + return sgSelector.isCBTOk(coll); + case 2: + return sgSelector.isCBTZdcOk(coll); + case 3: + return sgSelector.isCBTHadronOk(coll); + case 4: + return sgSelector.isCBTHadronZdcOk(coll); + default: + return true; + } + } + + template + bool isGoodROFtime(C const& coll) + { + + // kNoTimeFrameBorder + if (cutSample.cutEvTFb && !coll.tfb()) + return false; + + // kNoITSROFrameBorder + if (cutSample.cutEvITSROFb && !coll.itsROFb()) + return false; + + // kNoSameBunchPileup + if (cutSample.cutEvSbp && !coll.sbp()) + return false; + + // kIsGoodZvtxFT0vsPV + if (cutSample.cutEvZvtxFT0vPV && !coll.zVtxFT0vPV()) + return false; + + // kIsVertexITSTPC + if (cutSample.cutEvVtxITSTPC && !coll.vtxITSTPC()) + return false; + + // 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) + { + ROOT::Math::LorentzVector> 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) { + ROOT::Math::LorentzVector> 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(); + + ROOT::Math::LorentzVector> 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) { + ROOT::Math::LorentzVector> daug[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) { + ROOT::Math::LorentzVector> 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) { + ROOT::Math::LorentzVector> 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 (!isGoodRCTflag(reconstructedCollision)) + 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 (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(); + + if (!isGoodRCTflag(reconstructedCollision)) + return; + + 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..d2dd61ade0c 100644 --- a/PWGUD/Tasks/upcTauTau13topo.cxx +++ b/PWGUD/Tasks/upcTauTau13topo.cxx @@ -9,47 +9,153 @@ // 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/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" -#include "TDatabasePDG.h" -#include "TLorentzVector.h" +// #include "TDatabasePDG.h" // not recommended in o2 +#include "Framework/O2DatabasePDGPlugin.h" + +// #include "TLorentzVector.h" +#include "Math/Vector4D.h" // #include "Common/DataModel/EventSelection.h" // #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "PWGUD/DataModel/UDTables.h" -#include "PWGUD/Core/UDHelpers.h" #include "PWGUD/Core/DGPIDSelector.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UDHelpers.h" +#include "PWGUD/DataModel/UDTables.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/PIDResponseTPC.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, int8_t); +DECLARE_SOA_COLUMN(RctOk, rctOk, 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, bool); +DECLARE_SOA_COLUMN(ItsRofb, itsRofb, bool); +DECLARE_SOA_COLUMN(Sbp, sbp, bool); +DECLARE_SOA_COLUMN(ZvtxFT0vsPv, zvtxFT0vsPv, bool); +DECLARE_SOA_COLUMN(VtxITSTPC, vtxITSTPC, bool); +DECLARE_SOA_COLUMN(ZdcAenergy, zdcAenergy, float); +DECLARE_SOA_COLUMN(ZdcCenergy, zdcCenergy, float); +DECLARE_SOA_COLUMN(Qtot, qtot, int8_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, int8_t[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(TrkTPCfind, trkTPCfind, int[4]); +DECLARE_SOA_COLUMN(TrkTPCchi2, trkTPCchi2, float[4]); +DECLARE_SOA_COLUMN(TrkITSchi2, trkITSchi2, float[4]); +DECLARE_SOA_COLUMN(TrkITScl, trkITScl, int[4]); + +DECLARE_SOA_COLUMN(TrkTPCsignal, trkTPCsignal, float[4]); +DECLARE_SOA_COLUMN(TrkTPCnSigmaEl, trkTPCnSigmaEl, 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(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::RctOk, + // 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::TrkTPCfind, tau_tree::TrkTPCchi2, tau_tree::TrkITSchi2, tau_tree::TrkITScl, + 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.5, 5.0}, "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 +163,1632 @@ 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})"}; + const AxisSpec acoAxis{100, 0., 1., "A^{1+3}"}; + + 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]); + + // 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}}}); + + // histograms mass3pi vs acoponarity MC true + registry1MC.add("controlMCtrue/cut0/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut20/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut33/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut21/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut24/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut25/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut28/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut22/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut29/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut26/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut34/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut30/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut27/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut35/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCtrue/cut23/h3piMassVsAco", "3#pi mass vs acoplanarity MC sig ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + + // histograms mass3pi vs acoponarity MC comb + registry1MC.add("controlMCcomb/cut0/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut20/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut33/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut21/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut24/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut25/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut28/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut22/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut29/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut26/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut34/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut30/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut27/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut35/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + registry1MC.add("controlMCcomb/cut23/h3piMassVsAco", "3#pi mass vs acoplanarity MC comb ;M_{inv}^{3#pi} (GeV/c^{2});A^{1+3};entries", {HistType::kTH2F, {minvAxis, acoAxis}}); + + } // 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)); } - float CalculateDeltaPhi(TLorentzVector p, TLorentzVector p1) + // helper function to calculate delta alpha + float deltaAlpha(auto particle1, auto particle2) { - 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; + + TVector3 vtmp(particle1.px(), particle1.py(), particle1.pz()); + TVector3 v1(particle2.px(), particle2.py(), particle2.pz()); + auto angle = v1.Angle(vtmp); + + return angle; + } + + // float invariantMass(float E, float px, float py, float pz) + // // Just a simple function to return invariant mass + // { + // return std::sqrt(E * E - px * px - py * py - pz * pz); + // } + + // float calculateDeltaPhi(TLorentzVector p, TLorentzVector p1) + float calculateDeltaPhi(ROOT::Math::LorentzVector> p, ROOT::Math::LorentzVector> 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 pt1 = RecoDecay::pt(particle1.px(), particle1.py()); + // auto pt2 = pt(particle2.px(), particle2.py()); + auto pt2 = RecoDecay::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); + float aco = 1. - pi3deltaPhi / o2::constants::math::PI; + registry.get(HIST("control/cut") + HIST(kHistoname[mode]) + HIST("/h3piMassVsAco"))->Fill(pi3invMass, aco); + } + + // 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); + float aco = 1. - pi3deltaPhi / o2::constants::math::PI; + registry1MC.get(HIST("controlMCtrue/cut") + HIST(kHistoname[mode]) + HIST("/h3piMassVsAco"))->Fill(pi3invMass, aco); + } + + // 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); + float aco = 1. - pi3deltaPhi / o2::constants::math::PI; + registry1MC.get(HIST("controlMCcomb/cut") + HIST(kHistoname[mode]) + HIST("/h3piMassVsAco"))->Fill(pi3invMass, aco); } template - int TrackCheck(T track) + int trackCheck(T track) { // 1 if (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) @@ -316,44 +1827,354 @@ 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(RecoDecay::eta(std::array{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; + } + + // check ITS clusters, how many -1,0,1,7 + 10 if 0,1,2 layers were fired + // analysis track quality check + template + int numberOfItsClustersCheck(T track) + { + if (!track.hasITS()) + return -1; + int nITSbits = 0; + int firstThreeLayers = 0; + uint32_t clusterSizes = track.itsClusterSizes(); + for (int layer = 0; layer < 7; layer++) { + if ((clusterSizes >> (layer * 4)) & 0xf) { + nITSbits++; + if (layer < 3) + firstThreeLayers++; + } + } // end of loop over ITS bits + if (firstThreeLayers == 3) + nITSbits += 10; + + return nITSbits; + } + + // RCT check + template + int isGoodRCTflag(C const& coll) + { + if (sgSelector.isCBTHadronZdcOk(coll)) + return 4; + else if (sgSelector.isCBTHadronOk(coll)) + return 3; + else if (sgSelector.isCBTZdcOk(coll)) + return 2; + else if (sgSelector.isCBTOk(coll)) + return 1; + else + return 0; + } + + // 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; - void process(UDCollisionFull const& dgcand, UDTracksFull const& dgtracks) + // PVContributors + Filter pVContributorFilter = aod::udtrack::isPVContributor == true; + using PVTracks = soa::Filtered; + + // 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; - TLorentzVector p; - TParticlePDG* pion = pdg->GetParticle(211); + int nITSbits = -1; + int npT100 = 0; + // TLorentzVector p; + ROOT::Math::LorentzVector> p; + // 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); + p.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(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 +2182,102 @@ 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; + // } - // if vz < 15 - if (TMath::Abs(dgcand.posZ()) >= zvertexcut) { // default = 15 + 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); + // p.SetXYZT(trk.px(), trk.py(), trk.pz(), energy(trk.px(), trk.py(), trk.pz(), MassPiPlus)); + p.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(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 < 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 +2287,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 +2335,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,35 +2351,83 @@ 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; + ROOT::Math::LorentzVector> p1, p2; + // TLorentzVector gammaPair[3][2]; + ROOT::Math::LorentzVector> gammaPair[3][2]; + float invMass2El[3][2]; // inv. mass squared + int counterTmp = 0; + bool flagIMGam2ePV[4] = {true, true, true, true}; + + for (const auto& trk : PVContributors) { + // p.SetXYZM(trk.px(), trk.py(), trk.pz(), MassElectron); + p.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(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); + p1.SetXYZT(trk1.px(), trk1.py(), trk1.pz(), RecoDecay::e(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.); + // p = TLorentzVector(0., 0., 0., 0.); + p.SetXYZT(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); + p1.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(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(); + float mass4pi = p.mag(); TVector3 v1(0, 0, 0); TVector3 vtmp(0, 0, 0); @@ -506,13 +2435,26 @@ 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); + p1.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(trk.px(), trk.py(), trk.pz(), MassPiPlus)); + // p2.SetXYZM(trk.px(), trk.py(), trk.pz(), MassElectron); + p2.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(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 +2465,182 @@ 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(); + } - p1.SetXYZM(trk.px(), trk.py(), trk.pz(), pion->Mass()); + // 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(), MassPiPlus); + p1.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(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); - pi3invMass[counterTmp] = (p - p1).Mag(); + 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 +2649,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 +2678,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 +2698,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 +2736,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 +2749,2529 @@ 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.); + } 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]); + } + } + } // end of pttot<0.15 cut30 - // 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; + // + // 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++) { + 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]); } } - } - if (counterTotal > 0) - registry.get(HIST("global/hEventEff"))->Fill(13., 1.); + } else { + if (verbose) { + LOGF(debug, " Candidate rejected: all electrons vetoed by Dphi"); + } + return; + } // end of Dphi - if (counterTotal == 1) { + // + // 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++) { - 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/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]); + } + } + } // end of ZNAC energy cut35 - 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 occupancy >=1000 + // + if (dgcand.occupancyInTime() >= 1000) { + if (verbose) { + LOGF(info, " Candidate rejected: occupancy is %f", dgcand.occupancyInTime()); + } + 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]); } } - 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 occupancy < 1000 cut23 - registry.get(HIST("global/hEventEff"))->Fill(14., 1.); - } else { // more than 1 electron candidate + // // 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(-8., 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; // generator + int countBoth = 0; // generator + primary + int countCharged = 0; // generator + primary + charged + int countChargedFromTau = 0; // generator + primary + charged + from tau + int countTau = 0; + + int countChargedOnly = 0; // charged only + int countChargedOnlyFromTau = 0; // charged only and from tau + + 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) { if (verbose) { - LOGF(debug, " Candidate rejected: more than one electron candidate"); + LOGF(info, " mcParticle pdg %d, gen %d, prim %d, bkg %d, process %d", mcParticle.pdgCode(), mcParticle.producedByGenerator(), mcParticle.isPhysicalPrimary(), mcParticle.fromBackgroundEvent(), mcParticle.getProcess()); } - } // end of Nelectrons check - } + // 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) { + if (mcParticle.pdgCode() != kGamma && std::abs(mcParticle.pdgCode()) != kNuE && std::abs(mcParticle.pdgCode()) != kNuMu && std::abs(mcParticle.pdgCode()) != kNuTau && mcParticle.pdgCode() != kK0Long && mcParticle.pdgCode() != kPi0) { + 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) { + if (std::abs(mother.pdgCode()) == kTauMinus) { + countChargedFromTau++; + } // mother is tau + } // mc particle has mother + } // veto neutral particles + } // physics primary + } // generator produced by + + // special case only for UPCgen, charged but not taus + if (std::abs(mcParticle.pdgCode()) != kTauMinus && mcParticle.pdgCode() != kGamma && std::abs(mcParticle.pdgCode()) != kNuE && std::abs(mcParticle.pdgCode()) != kNuMu && std::abs(mcParticle.pdgCode()) != kNuTau && mcParticle.pdgCode() != kK0Long && mcParticle.pdgCode() != kPi0) { + countChargedOnly++; + // case for UPCgen when all particles are not pimaries + if (!mcParticle.isPhysicalPrimary()) { + // all charged particles, not only from 1+3 topo + 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()); + } // end of UPCgen case + + if (mcParticle.has_mothers()) { + auto const& mother = mcParticle.mothers_first_as(); + if (std::abs(mother.pdgCode()) == kTauMinus) { // 15 + countChargedOnlyFromTau++; + } // mother is tau + } // mc particle has mother + } // veto neutral particles + // end of special case only for UPCgen + + // + // tau+/- + // + // if (std::abs(mcParticle.pdgCode()) == 15) { // tau+/- + if (std::abs(mcParticle.pdgCode()) == kTauMinus) { // 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()) == kPiPlus) { // 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()) == kElectron) { // 11 = electron + if (daughter.pdgCode() == kElectron) + 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()) == kMuonMinus) { // 13 + if (daughter.pdgCode() == kMuonMinus) // 13 + flagMuPlusMuMinus = true; + + registryMC.get(HIST("muonMC/hMCeta"))->Fill(daughter.eta()); + registryMC.get(HIST("muonMC/hMCphi"))->Fill(daughter.phi()); + registryMC.get(HIST("muonMC/hMCy"))->Fill(daughter.y()); + registryMC.get(HIST("muonMC/hMCpt"))->Fill(daughter.pt()); + + 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() == kPiMinus) // -211 + flagPiPlusPiMinus = true; + + registryMC.get(HIST("pionMC/hMCeta"))->Fill(mcPartTmp.eta()); + registryMC.get(HIST("pionMC/hMCphi"))->Fill(mcPartTmp.phi()); + registryMC.get(HIST("pionMC/hMCy"))->Fill(mcPartTmp.y()); + registryMC.get(HIST("pionMC/hMCpt"))->Fill(mcPartTmp.pt()); + + 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 + registryMC.get(HIST("tauMC/hNtaus"))->Fill(countTau); + 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); + registryMC.get(HIST("globalMC/hMCnPart"))->Fill(countPrim, 5); + registryMC.get(HIST("globalMC/hMCnPart"))->Fill(countChargedOnly, 6); + registryMC.get(HIST("globalMC/hMCnPart"))->Fill(countChargedOnlyFromTau, 7); + + if (countChargedFromTau == 2 || countChargedOnlyFromTau == 2) { + // 2 tracks candidates + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(-7., 1.); + } + if (countChargedFromTau == 6 || countChargedOnlyFromTau == 6) { + // 6 tracks candidates + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(-6., 1.); + } + + // if (countChargedFromTau != 4) + // return; + if (countChargedFromTau == 4 || countChargedOnlyFromTau == 4) { + // 4 tracks candidates + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(-5., 1.); // 4 tracks + if (electronFound && flagElPlusElMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(-4., 1.); // e- + else if (electronFound && !flagElPlusElMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(-3., 1.); // e+ + if (muonFound && flagMuPlusMuMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(-2., 1.); // mu- + else if (muonFound && !flagMuPlusMuMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(-1., 1.); // mu+ + if (singlePionFound && flagPiPlusPiMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(0., 1.); // pi- + else if (singlePionFound && !flagPiPlusPiMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(1., 1.); // pi+ + + if (!tauInRapidity) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(2., 1.); + if (!partFromTauInEta) + return; + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(3., 1.); + + if (electronFound && flagElPlusElMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(4., 1.); // e- + else if (electronFound && !flagElPlusElMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(5., 1.); // e+ + if (muonFound && flagMuPlusMuMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(6., 1.); // mu- + else if (muonFound && !flagMuPlusMuMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(7., 1.); // mu+ + if (singlePionFound && flagPiPlusPiMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(8., 1.); // pi- + else if (singlePionFound && !flagPiPlusPiMinus) + registryMC.get(HIST("globalMC/hMCefficiency"))->Fill(9., 1.); // pi+ + + } // end of 4 tracks candidate events + } // end of processSimpleMCSG + + // using LabeledTracks = soa::Join; + using LabeledTracks = soa::Join; + Preslice perCollision = aod::udtrack::udCollisionId; + // ZDC is not reproduced in MC, it is for a consistency + using FullMcUdCollisions = soa::Join; + // using FullMcUdCollisions = soa::Join; + // PresliceUnsorted colPerMcCollision = aod::udcollision::udMcCollisionId; + // PresliceUnsorted partPerMcCollision = aod::udmcparticle::udMcCollisionId; + + void processEfficiencyMCSG(aod::UDMcCollision const& mcCollision, + // void processEfficiencyMCSG(aod::UDMcCollisions const& mcCollisions, + // soa::SmallGroups> const& collisions, + // soa::SmallGroups> const& collisions, + soa::SmallGroups const& collisions, + // FullMcUdCollisions const& collisionsFull, + LabeledTracks const& tracks, + aod::UDMcParticles const& mcParticles) + // aod::UDMcParticles const& mcParts) + { + // LOGF(info, " Per DF: UDMcParticles size %d, UDMcCollisions size %d, FullMcUdCollisions size %d", mcParts.size(), mcCollisions.size(), collisionsFull.size()); + // LOGF(info, " Per DF: UDMcParticles size %d, UDMcCollisions size %d, FullMcUdCollisions size %d", mcParts.size(), mcCollisions.size(), collisions.size()); + LOGF(info, " UDMcCollision size %d, SmallGroups FullMcUdCollisions size %d, UDtracks %d, UDMcParticles %d", mcCollision.size(), collisions.size(), tracks.size(), mcParticles.size()); + + // loop over generated collisions + // for (const auto &mcCollision : mcCollisions) { + // LOGF(info, " Per mcCollision not sliced: UDMcParticles size %d, FullMcUdCollisions size %d", mcParts.size(), collisionsFull.size()); + + 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.getGeneratorID()); + 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.getGeneratorID() != generatorIDMC) + 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.); + ROOT::Math::LorentzVector> tmp(0., 0., 0., 0.); + + // get reconstructed collisions associated to generated collision + // auto const& collisions = collisionsFull.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + // LOGF(info, " per mcCollisions sliced collisions.size %d", collisions.size()); + + // get MC particles associated to generated collision + // auto const& mcParticles = mcParts.sliceBy(partPerMcCollision, mcCollision.globalIndex()); + // LOGF(info, " per mcCollisions sliced mcParticles.size %d", mcParticles.size()); + + for (const auto& mcParticle : mcParticles) { + // LOGF(info, " mcParticle pdg %d", mcParticle.pdgCode()); + 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.pdgCode() != kGamma && std::abs(mcParticle.pdgCode()) != kNuE && std::abs(mcParticle.pdgCode()) != kNuMu && std::abs(mcParticle.pdgCode()) != kNuTau && mcParticle.pdgCode() != kK0Long && mcParticle.pdgCode() != kPi0) { + if (mcParticle.has_mothers()) { + auto const& mother = mcParticle.mothers_first_as(); + // LOGF(info, " mcParticle has mother %d",mother.pdgCode()); + tmp.SetPxPyPzE(mother.px(), mother.py(), mother.pz(), mother.e()); + if (std::abs(mother.pdgCode()) == kTauMinus) { // 15 + if (std::abs(rapidity(mother.e(), mother.pz())) > 0.9) + // if (std::abs(tmp.Rapidity()) > 0.9) + tauInRapidity = false; + if (std::abs(RecoDecay::eta(std::array{mcParticle.px(), mcParticle.py(), mcParticle.pz()})) > 0.9) + // if (std::abs(tmp.Eta()) > 0.9) + partFromTauInEta = false; + + if (std::abs(mcParticle.pdgCode()) == kElectron) { // 11 + index1ProngMC = mcParticle.index(); + is1ProngElectronMC = true; + } else if (std::abs(mcParticle.pdgCode()) == kMuonMinus) { // 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(RecoDecay::eta(std::array{mcParticle.px(), mcParticle.py(), mcParticle.pz()})); + registryMC.get(HIST("globalMCrec/hMCphiGenCol"))->Fill(RecoDecay::phi(mcParticle.px(), mcParticle.py())); + registryMC.get(HIST("globalMCrec/hMCyGenCol"))->Fill(rapidity(mcParticle.e(), mcParticle.pz())); + registryMC.get(HIST("globalMCrec/hMCptGenCol"))->Fill(RecoDecay::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 = 3; // was -1 + int nDifferences = 0; + for (int i = 1; i < 4; i++) { + if (motherIndex1Pi != motherIndex[i]) { // the same mother (tau) 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] = {0, 0, 0}; // initialised of request + 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) + if (std::abs(tmpPion1MC.pdgCode()) == kPiPlus && std::abs(tmpPion2MC.pdgCode()) == kPiPlus && std::abs(tmpPion3MC.pdgCode()) == kPiPlus) // 211 211 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(RecoDecay::phi(tmp1ProngMC.px(), tmp1ProngMC.py()), RecoDecay::phi(tmpPion1MC.px(), tmpPion1MC.py()))); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiEpi"))->Fill(calculateDeltaPhi(RecoDecay::phi(tmp1ProngMC.px(), tmp1ProngMC.py()), RecoDecay::phi(tmpPion2MC.px(), tmpPion2MC.py()))); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiEpi"))->Fill(calculateDeltaPhi(RecoDecay::phi(tmp1ProngMC.px(), tmp1ProngMC.py()), RecoDecay::phi(tmpPion3MC.px(), tmpPion3MC.py()))); + // + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiPipi"))->Fill(calculateDeltaPhi(RecoDecay::phi(tmpPion1MC.px(), tmpPion1MC.py()), RecoDecay::phi(tmpPion2MC.px(), tmpPion2MC.py()))); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiPipi"))->Fill(calculateDeltaPhi(RecoDecay::phi(tmpPion1MC.px(), tmpPion1MC.py()), RecoDecay::phi(tmpPion3MC.px(), tmpPion3MC.py()))); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaPhiPipi"))->Fill(calculateDeltaPhi(RecoDecay::phi(tmpPion2MC.px(), tmpPion2MC.py()), RecoDecay::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 += RecoDecay::pt(tmpPion1MC.px(), tmpPion1MC.py()); + } + if (deltaAlpha2 < angleLimit) { + energyInCone += RecoDecay::pt(tmpPion2MC.px(), tmpPion2MC.py()); + } + if (deltaAlpha3 < angleLimit) { + energyInCone += RecoDecay::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(RecoDecay::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(RecoDecay::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/hMCinvmass4pi"))->Fill(RecoDecay::m(std::array{(tmp1ProngMC.px() + px3pi), (tmp1ProngMC.py() + py3pi), (tmp1ProngMC.pz() + pz3pi)}, (tmp1ProngMC.e() + en3pi))); + // registryMC.get(HIST("efficiencyMCEl/hMCinvmass3pi"))->Fill(invariantMass(en3pi, px3pi, py3pi, pz3pi)); + registryMC.get(HIST("efficiencyMCEl/hMCinvmass3pi"))->Fill(RecoDecay::m(std::array{px3pi, py3pi, pz3pi}, en3pi)); + registryMC.get(HIST("efficiencyMCEl/hMCdeltaphi13"))->Fill(calculateDeltaPhi(RecoDecay::phi(tmp1ProngMC.px(), tmp1ProngMC.py()), RecoDecay::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(RecoDecay::eta(std::array{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; + ROOT::Math::LorentzVector> p, p1; + // p.SetXYZM(0., 0., 0., 0.); + p.SetXYZT(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 = RecoDecay::eta(std::array{tmptrack.px(), tmptrack.py(), tmptrack.pz()}); + float tmpPhiData = RecoDecay::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 + p1.SetXYZT(v1.X(), v1.Y(), v1.Z(), RecoDecay::e(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)); + // p1.SetXYZT(v1.X(), v1.Y(), v1.Z(), energy(v1.X(), v1.Y(), v1.Z(), (std::abs(tmptrack.udMcParticle().pdgCode()) == 211 ? MassPiPlus : MassElectron))); + p1.SetXYZT(v1.X(), v1.Y(), v1.Z(), RecoDecay::e(v1.X(), v1.Y(), v1.Z(), (std::abs(tmptrack.udMcParticle().pdgCode()) == kPiPlus ? MassPiPlus : MassElectron))); // 211 + float tmpPt = RecoDecay::pt(tmptrack.udMcParticle().px(), tmptrack.udMcParticle().py()); + float tmpEta = RecoDecay::eta(std::array{tmptrack.udMcParticle().px(), tmptrack.udMcParticle().py(), tmptrack.udMcParticle().pz()}); + float tmpPhi = RecoDecay::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 + p1.SetXYZT(v1.X(), v1.Y(), v1.Z(), RecoDecay::e(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)); + p1.SetXYZT(v1.X(), v1.Y(), v1.Z(), RecoDecay::e(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 loop over mcCollisions + + } // 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; + int8_t qtot = 0; + // TLorentzVector p; + ROOT::Math::LorentzVector> p; + for (const auto& trk : PVContributors) { + qtot += trk.sign(); + // p.SetXYZM(trk.px(), trk.py(), trk.pz(), MassPiPlus); + p.SetXYZT(trk.px(), trk.py(), trk.pz(), RecoDecay::e(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.); + + // RCT variable + int rct = 0; + rct = isGoodRCTflag(dgcand); + + // + // variables per track + // + int counterTmp = 0; + float px[4], py[4], pz[4]; + int8_t 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 chi2TOF[4] = {-1., -1., -1., -1.}; + int nclTPCcrossedRows[4]; + int nclTPCfind[4]; + float nclTPCchi2[4]; + float trkITSchi2[4]; + int trkITScl[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(); + + if (trk.hasTOF()) + chi2TOF[counterTmp] = trk.tofChi2(); + // nclTPCfind[counterTmp] = trk.tpcNClsFindable(); + nclTPCcrossedRows[counterTmp] = trk.tpcNClsCrossedRows(); + + nclTPCfind[counterTmp] = trk.tpcNClsFindable(); + nclTPCchi2[counterTmp] = trk.tpcChi2NCl(); + trkITSchi2[counterTmp] = trk.itsChi2NCl(); + trkITScl[counterTmp] = numberOfItsClustersCheck(trk); + + // trkTime[counterTmp] = trk.trackTime(); + // trkTimeRes[counterTmp] = trk.trackTimeRes(); + counterTmp++; + } + + tauFourTracks(dgcand.runNumber(), + dgcand.globalBC(), // is it necessary + dgtracks.size(), + dgcand.numContrib(), + rct, + // 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, nclTPCfind, nclTPCchi2, trkITSchi2, trkITScl, + 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/upcTestRctTables.cxx b/PWGUD/Tasks/upcTestRctTables.cxx new file mode 100644 index 00000000000..5f6d1bd8db1 --- /dev/null +++ b/PWGUD/Tasks/upcTestRctTables.cxx @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +/// \file upcTestRctTables.cxx +/// \brief Tests Rct Tables in UD tabl;es +/// +/// \author Roman Lavicka , Austrian Academy of Sciences & SMI +/// \since 27.06.2025 +// + +// O2 headers +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/O2DatabasePDGPlugin.h" +#include "Framework/runDataProcessing.h" + +// O2Physics headers +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" +#include "PWGUD/DataModel/UDTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct UpcTestRctTables { + + // Global varialbes + SGSelector sgSelector; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // declare configurables + Configurable verboseInfo{"verboseInfo", false, {"Print general info to terminal; default it false."}}; + + using FullSGUDCollisions = soa::Join; + using FullSGUDCollision = FullSGUDCollisions::iterator; + + // init + void init(InitContext&) + { + if (verboseInfo) + printMediumMessage("INIT METHOD"); + + histos.add("OutputTable/hRCTflags", ";RCTflag (-);Number of passed collision (-)", HistType::kTH1D, {{5, -0.5, 4.5}}); + + } // end init + + void processDataSG(FullSGUDCollision const& reconstructedCollision) + { + + histos.get(HIST("OutputTable/hRCTflags"))->Fill(0); + + if (sgSelector.isCBTOk(reconstructedCollision)) + histos.get(HIST("OutputTable/hRCTflags"))->Fill(1); + + if (sgSelector.isCBTZdcOk(reconstructedCollision)) + histos.get(HIST("OutputTable/hRCTflags"))->Fill(2); + + if (sgSelector.isCBTHadronOk(reconstructedCollision)) + histos.get(HIST("OutputTable/hRCTflags"))->Fill(3); + + if (sgSelector.isCBTHadronZdcOk(reconstructedCollision)) + histos.get(HIST("OutputTable/hRCTflags"))->Fill(4); + + } // end processDataSG + + PROCESS_SWITCH(UpcTestRctTables, processDataSG, "Iterate UD tables with measured data created by SG-Candidate-Producer.", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGUD/Tasks/upcVetoAnalysis.cxx b/PWGUD/Tasks/upcVetoAnalysis.cxx index 0fc65232d0e..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" @@ -376,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 10bd68ee91e..87e07897aff 100755 --- a/Scripts/find_dependencies.py +++ b/Scripts/find_dependencies.py @@ -142,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: @@ -151,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 @@ -179,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) @@ -194,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 @@ -236,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", @@ -266,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 @@ -302,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") @@ -330,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() @@ -375,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/format_includes.awk b/Scripts/format_includes.awk new file mode 100644 index 00000000000..ac22332acc5 --- /dev/null +++ b/Scripts/format_includes.awk @@ -0,0 +1,21 @@ +#!/bin/awk -f + +# Fix include style. +# NB: Run before sorting. + +{ + if ($1 ~ /^#include/) { + h = substr($2, 2, length($2) - 2) + if ( h ~ /^(PWG[A-Z]{2}|Common|ALICE3|DPG|EventFiltering|Tools|Tutorials)\/.*\.h/ ) { $2 = "\""h"\"" } # O2Physics + else if ( h ~ /^(Algorithm|CCDB|Common[A-Z]|DataFormats|DCAFitter|Detectors|EMCAL|Field|Framework|FT0|FV0|GlobalTracking|GPU|ITS|MathUtils|MFT|MCH|MID|PHOS|PID|ReconstructionDataFormats|SimulationDataFormat|TOF|TPC|ZDC).*\/.*\.h/ ) { $2 = "<"h">" } # O2 + else if ( h ~ /^(T[A-Z]|Math\/|Roo[A-Z])[[:alnum:]\/]+\.h/ ) { $2 = "<"h">" } # ROOT + else if ( h ~ /^KF[A-Z][[:alnum:]]+\.h/ ) { $2 = "<"h">" } # KFParticle + else if ( h ~ /^(fastjet\/|onnxruntime)/ ) { $2 = "<"h">" } # FastJet, ONNX + else if ( h ~ /^.*DataModel\// ) { $2 = "\""h"\"" } # incomplete path to DataModel + else if ( h ~ /^([[:alnum:]_]+\/)+[[:alnum:]_]+\.h/ ) { $2 = "<"h">" } # other third-party + else if ( $2 ~ /^".*\./ ) { } # other local-looking file + else if ( h ~ /^[[:lower:]_]+\.h/ ) { $2 = "<"h">" } # C system + else if ( h ~ /^[[:lower:]_\/]+/ ) { $2 = "<"h">" } # C++ system + } + print +} diff --git a/Scripts/o2_linter.py b/Scripts/o2_linter.py new file mode 100644 index 00000000000..b334a694c1d --- /dev/null +++ b/Scripts/o2_linter.py @@ -0,0 +1,1793 @@ +#!/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): + ISO_CPP = 1 + LLVM = 2 + GOOGLE = 3 + PY_ZEN = 4 + PY_PEP8 = 5 + O2 = 6 + PWG_HF = 7 + LINTER_1 = 8 + LINTER_2 = 9 + + +references_list: "list[tuple[Reference, str, str]]" = [ + (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.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/"), + (Reference.O2, "ALICE O2 Coding Guidelines", "https://github.com/AliceO2Group/CodingGuidelines"), + ( + Reference.PWG_HF, + "PWG-HF guidelines", + "https://aliceo2group.github.io/analysis-framework/docs/advanced-specifics/pwghf.html#contribute", + ), + ( + Reference.LINTER_1, + "Proposal of the O2 linter", + "https://indico.cern.ch/event/1482467/#29-development-of-the-o2-linte", + ), + ( + Reference.LINTER_2, + "Update of the O2 linter", + "https://indico.cern.ch/event/1513748/#29-o2-linter-development", + ), +] + +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}:1: 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" \(.{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 1 + # 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_1] + 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_1] + 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_1] + 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_1] + 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_1, 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 = [Reference.LINTER_2] + 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_1, 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_1, 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_1, 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_1] + 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_1] + 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_2] + 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_1] + 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_1] + 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_1] + 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_1] + 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, Reference.LINTER_2] + suffixes = [".h", ".cxx", ".C"] + pattern_compare = r"([<>]=?|[!=]=)" + pattern_number = r"[\+-]?([\d\.]+(e[\+-]?\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(4)) 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_1] + 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_1] + + +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." + rationale = rationale_names + references = references_names + suffixes = [".h", ".cxx", ".C"] + + def __init__(self) -> None: + super().__init__() + keyword = r"(.+ )" # e.g. "static " + type_val = r"([\w:<>+\-*\/, ]+ )" # value type e.g. "std::array " + prefix = r"(\w+::)" # prefix with namespace or class, e.g. "MyClass::" + name_val = r"(\w+)" # name of the constant + array = r"(\[.*\])" # array declaration: "[...]" + assignment = r"( =|\(\d|{)" # value assignment, e.g. " = 2", " = expression", "(2)", "{2}", "{{...}}" + self.pattern = re.compile(rf"{keyword}?constexpr {type_val}?{prefix}*{name_val}{array}?{assignment}") + + def test_line(self, line: str) -> bool: + if is_comment_cpp(line): + return True + line = remove_comment_cpp(line) + if not (match := self.pattern.match(line)): + return True + constant_name = match.group(4) + # The actual test comes here. + 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 (match := re.match(rf"{self.keyword}( (class|struct))? (\w+)", line)): + return True + # Extract object name. + object_name = match.group(3) + # 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_1, 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_1] + 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_1] + 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_1] + 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 (match := re.match(r"((o2::)?framework::)?Configurable(\w+|<.+>) (\w+)( = )?{([^,{]+),", line)): + return not re.match(r"((o2::)?framework::)?Configurable", line) + # Extract Configurable name. + name_cpp = match.group(4) # nameCpp + name_json = match.group(6) # expecting "nameJson" + if name_json[0] != '"': # JSON name is not a literal string. + return True + name_json = name_json[1:-1] # Strip away quotation marks. + # The actual test comes here. + return is_lower_camel_case(name_cpp) and name_cpp == name_json + + +# PWG-HF + +references_hf = [Reference.LINTER_1, 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 = sorted(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 from the O2Physics directory 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 7f03cb1c4af..bec24fd7adc 100644 --- a/Tools/KFparticle/KFUtilities.h +++ b/Tools/KFparticle/KFUtilities.h @@ -22,15 +22,26 @@ #define HomogeneousField #endif +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include + #include // FIXME -#include "KFParticle.h" -#include "KFPTrack.h" -#include "KFPVertex.h" -#include "KFParticleBase.h" -#include "KFVertex.h" +#include +#include +#include +#include -#include "Common/Core/RecoDecay.h" +#include +#include +#include +#include +#include /// @brief Function to create a KFPVertex from the collision table in the AO2Ds. /// The Multiplicity table is required to set the number of real PV Contributors @@ -154,8 +165,8 @@ KFParticle createKFParticleFromTrackParCov(const o2::track::TrackParametrization /// @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; + std::array xyz, pxpypz; + std::array cv; // get parameters from kfParticle xyz[0] = kfParticle.GetX(); @@ -313,4 +324,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/KFparticle/qaKFParticle.cxx b/Tools/KFparticle/qaKFParticle.cxx index f4ffdf58a85..c634d0837a4 100644 --- a/Tools/KFparticle/qaKFParticle.cxx +++ b/Tools/KFparticle/qaKFParticle.cxx @@ -16,38 +16,43 @@ /// #include "Tools/KFparticle/qaKFParticle.h" + +#include "TableHelper.h" + #include -#include + #include #include -#include "TableHelper.h" + +#include /// includes O2 +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/Track.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" /// includes O2Physics -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/trackUtilities.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Tools/KFparticle/KFUtilities.h" /// includes KFParticle -#include "KFParticle.h" #include "KFPTrack.h" #include "KFPVertex.h" +#include "KFParticle.h" #include "KFParticleBase.h" #include "KFVertex.h" diff --git a/Tools/KFparticle/qaKFParticleLc.cxx b/Tools/KFparticle/qaKFParticleLc.cxx index 20da1eb6128..792acdff439 100644 --- a/Tools/KFparticle/qaKFParticleLc.cxx +++ b/Tools/KFparticle/qaKFParticleLc.cxx @@ -16,38 +16,43 @@ /// #include "Tools/KFparticle/qaKFParticleLc.h" + +#include "TableHelper.h" + #include -#include + #include #include -#include "TableHelper.h" + +#include /// includes O2 +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/runDataProcessing.h" #include "ReconstructionDataFormats/DCA.h" #include "ReconstructionDataFormats/Track.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" /// includes O2Physics -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "Common/Core/trackUtilities.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" -#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include "Tools/KFparticle/KFUtilities.h" /// includes KFParticle -#include "KFParticle.h" #include "KFPTrack.h" #include "KFPVertex.h" +#include "KFParticle.h" #include "KFParticleBase.h" #include "KFVertex.h" diff --git a/Tools/ML/MlResponse.h b/Tools/ML/MlResponse.h index 127512e52ee..c60946bcb03 100644 --- a/Tools/ML/MlResponse.h +++ b/Tools/ML/MlResponse.h @@ -17,21 +17,18 @@ #ifndef TOOLS_ML_MLRESPONSE_H_ #define TOOLS_ML_MLRESPONSE_H_ -#if __has_include() -#include -#else -#include -#endif +#include "Tools/ML/model.h" + +#include +#include +#include +#include +#include #include #include #include -#include "CCDB/CcdbApi.h" -#include "Framework/Array2D.h" - -#include "Tools/ML/model.h" - namespace o2 { namespace cuts_ml @@ -158,7 +155,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 0c29808c73c..a60abc65af5 100644 --- a/Tools/ML/model.cxx +++ b/Tools/ML/model.cxx @@ -17,9 +17,22 @@ /// \brief A general-purpose class with functions for ONNX model applications /// -// ONNX includes #include "Tools/ML/model.h" +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + namespace o2 { @@ -29,17 +42,17 @@ namespace ml std::string OnnxModel::printShape(const std::vector& v) { std::stringstream ss(""); - for (size_t i = 0; i < v.size() - 1; i++) + for (std::size_t i = 0; i < v.size() - 1; i++) ss << v[i] << "x"; ss << v[v.size() - 1]; return ss.str(); } -bool OnnxModel::checkHyperloop(bool verbose) +bool OnnxModel::checkHyperloop(const bool verbose) { /// Testing hyperloop core settings const char* alienCores = gSystem->Getenv("ALIEN_JDL_CPUCORES"); - bool alienCoresFound = (alienCores != NULL); + const bool alienCoresFound = (alienCores != NULL); if (alienCoresFound) { if (verbose) { LOGP(info, "Hyperloop test/Grid job detected! Number of cores = {}. Setting threads anyway to 1.", alienCores); @@ -55,7 +68,7 @@ bool OnnxModel::checkHyperloop(bool verbose) return alienCoresFound; } -void OnnxModel::initModel(std::string localPath, bool enableOptimizations, int threads, uint64_t from, uint64_t until) +void OnnxModel::initModel(const std::string& localPath, const bool enableOptimizations, const int threads, const uint64_t from, const uint64_t until) { assert(from <= until); @@ -75,39 +88,28 @@ 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) { + + Ort::AllocatorWithDefaultOptions const tmpAllocator; + for (std::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) { + for (std::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) { + for (std::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) { + for (std::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++) { + for (std::size_t i = 0; i < mInputNames.size(); i++) { LOG(info) << "\t" << mInputNames[i] << " : " << printShape(mInputShapes[i]); } LOG(info) << "Output Nodes:"; - for (size_t i = 0; i < mOutputNames.size(); i++) { + for (std::size_t i = 0; i < mOutputNames.size(); i++) { LOG(info) << "\t" << mOutputNames[i] << " : " << printShape(mOutputShapes[i]); } @@ -119,7 +121,7 @@ void OnnxModel::initModel(std::string localPath, bool enableOptimizations, int t LOG(info) << "--- Model initialized! ---"; } -void OnnxModel::setActiveThreads(int threads) +void OnnxModel::setActiveThreads(const int threads) { activeThreads = threads; if (!checkHyperloop(false)) { diff --git a/Tools/ML/model.h b/Tools/ML/model.h index bb1ac84a8ae..468c3dfd733 100644 --- a/Tools/ML/model.h +++ b/Tools/ML/model.h @@ -20,23 +20,18 @@ #ifndef TOOLS_ML_MODEL_H_ #define TOOLS_ML_MODEL_H_ -// C++ and system includes -#if __has_include() -#include -#else -#include -#endif -#include -#include -#include -#include -#include +#include -// ROOT includes -#include "TSystem.h" +#include -// O2 includes -#include "Framework/Logger.h" +#include +#include +#include +#include +#include +#include +#include +#include namespace o2 { @@ -52,7 +47,7 @@ class OnnxModel ~OnnxModel() = default; // Inferencing - void initModel(std::string, bool = false, int = 0, uint64_t = 0, uint64_t = 0); + void initModel(const std::string&, const bool = false, const int = 0, const uint64_t = 0, const uint64_t = 0); // template methods -- best to define them in header template @@ -62,10 +57,7 @@ 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; + const 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(); }); @@ -74,7 +66,6 @@ class OnnxModel 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(); @@ -96,55 +87,67 @@ class OnnxModel template T* evalModel(std::vector& input) { - int64_t size = input.size(); + const int64_t size = input.size(); 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 mem_info = + Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); - inputTensors.emplace_back(Ort::Value::CreateTensor(mem_info, input.data(), size, inputShape.data(), inputShape.size())); -#endif + inputTensors.emplace_back(Ort::Value::CreateTensor(memInfo, input.data(), size, inputShape.data(), inputShape.size())); LOG(debug) << "Input shape calculated from vector: " << printShape(inputShape); return evalModel(inputTensors); } + // For 2D inputs + template + T* evalModel(std::vector>& input) + { + std::vector inputTensors; + + Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); + + for (std::size_t iinput = 0; iinput < input.size(); iinput++) { + [[maybe_unused]] int totalSize = 1; + int64_t size = input[iinput].size(); + for (std::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 (std::size_t idim = 1; idim < mInputShapes[iinput].size(); idim++) { + inputShape.push_back(mInputShapes[iinput][idim]); + } + + inputTensors.emplace_back(Ort::Value::CreateTensor(memInfo, input[iinput].data(), size, inputShape.data(), inputShape.size())); + } + + 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; } - void setActiveThreads(int); + void setActiveThreads(const int); 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 @@ -161,7 +164,7 @@ class OnnxModel // Internal function for printing the shape of tensors std::string printShape(const std::vector&); - bool checkHyperloop(bool = true); + bool checkHyperloop(const bool = true); }; } // namespace ml diff --git a/Tools/PIDML/CMakeLists.txt b/Tools/PIDML/CMakeLists.txt index 012d2513685..d7be3345443 100644 --- a/Tools/PIDML/CMakeLists.txt +++ b/Tools/PIDML/CMakeLists.txt @@ -10,11 +10,23 @@ # or submit itself to any jurisdiction. o2physics_add_dpl_workflow(pid-ml-producer - SOURCES pidMLProducer.cxx + SOURCES pidMlProducer.cxx JOB_POOL analysis PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(pid-ml-batch-eff-and-pur-producer + SOURCES pidMlBatchEffAndPurProducer.cxx + JOB_POOL analysis + 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 SOURCES simpleApplyPidOnnxModel.cxx JOB_POOL analysis @@ -33,12 +45,6 @@ o2physics_add_dpl_workflow(qa-pid COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(qa-pid-ml - SOURCES qaPidML.cxx + SOURCES qaPidMl.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore ONNXRuntime::ONNXRuntime COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(kaon-pid-ml - SOURCES KaonPidTask.cxx - JOB_POOL analysis - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore ONNXRuntime::ONNXRuntime O2::CCDB O2Physics::DataModel - COMPONENT_NAME Analysis) diff --git a/Tools/PIDML/KaonPidTask.cxx b/Tools/PIDML/KaonPidTask.cxx deleted file mode 100644 index 19c0972be4a..00000000000 --- a/Tools/PIDML/KaonPidTask.cxx +++ /dev/null @@ -1,139 +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 task produces invariant mass vs. momentum and dEdX in TPC vs. momentum -/// for Kaons using ML PID from the PID ML ONNX Model. - -#include -#include -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "TLorentzVector.h" -#include "TDatabasePDG.h" -#include "Framework/AnalysisDataModel.h" -#include "Tools/PIDML/pidOnnxModel.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include "CommonConstants/PhysicsConstants.h" -#include "TMath.h" - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -namespace o2::aod -{ -using MyCollisions = soa::Join; -using MyTracks = soa::Join; -using MyCollision = MyCollisions::iterator; -using MyTrack = MyTracks::iterator; -} // namespace o2::aod - -struct KaonPidTask { - SliceCache cache; - Preslice perCol = aod::track::collisionId; - - std::shared_ptr pidModel; // creates a shared pointer to a new instance 'pidmodel'. - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - Configurable cfgZvtxCut{"cfgZvtxCut", 10, "Z vtx cut"}; - Configurable cfgEtaCut{"cfgEtaCut", 0.8, "Pseudorapidity cut"}; - Configurable cfgMaxPtCut{"cfgMaxPtCut", 3.0, "Max Pt cut"}; - Configurable cfgMinPtCut{"cfgMinPtCut", 0.5, "Min Pt cut"}; - Configurable cfgMinNSigmaTPCCut{"cfgMinNSigmaTPCCut", 3., "N-sigma TPC cut"}; - Configurable cfgChargeCut{"cfgChargeCut", 0., "N-sigma TPC cut"}; - Configurable cfgPathLocal{"local-path", ".", "base path to the local directory with ONNX models"}; - 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 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."}; - - o2::ccdb::CcdbApi ccdbApi; - - Filter collisionFilter = (nabs(aod::collision::posZ) < cfgZvtxCut); - Filter trackFilter = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgMinPtCut) && (aod::track::pt < cfgMaxPtCut); - - // Applying filters - using MyFilteredCollisions = soa::Filtered; - using MyFilteredCollision = MyFilteredCollisions::iterator; - - Partition positive = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgMinPtCut) && (aod::track::pt < cfgMaxPtCut) && (aod::track::signed1Pt > cfgChargeCut); - Partition negative = (nabs(aod::track::eta) < cfgEtaCut) && (aod::track::pt > cfgMinPtCut) && (aod::track::pt < cfgMaxPtCut) && (aod::track::signed1Pt < cfgChargeCut); - - void init(o2::framework::InitContext&) - { - AxisSpec vtxZAxis = {100, -20, 20}; - std::vector ptBinning = {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; - AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; - - 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); - - histos.add("hChargePos", ";z;", kTH1F, {{3, -1.5, 1.5}}); - histos.add("hChargeNeg", ";z;", kTH1F, {{3, -1.5, 1.5}}); - histos.add("hInvariantMass", ";M_{k^{+}k^{-}} (GeV/#it{c}^{2});", kTH1F, {{100, 0., 2.}}); - histos.add("hdEdXvsMomentum", ";P_{K^{+}K^{-}}; dE/dx in TPC (keV/cm)", kTH2F, {{100, 0., 4.}, {200, 20., 400.}}); - } - - void process(MyFilteredCollision const& coll, o2::aod::MyTracks const& /*tracks*/) - { - auto groupPositive = positive->sliceByCached(aod::track::collisionId, coll.globalIndex(), cache); - auto groupNegative = negative->sliceByCached(aod::track::collisionId, coll.globalIndex(), cache); - for (auto track : groupPositive) { - histos.fill(HIST("hChargePos"), track.sign()); - if (pidModel.get()->applyModelBoolean(track)) { - histos.fill(HIST("hdEdXvsMomentum"), track.p(), track.tpcSignal()); - } - } - - for (auto track : groupNegative) { - histos.fill(HIST("hChargeNeg"), track.sign()); - if (pidModel.get()->applyModelBoolean(track)) { - histos.fill(HIST("hdEdXvsMomentum"), track.p(), track.tpcSignal()); - } - } - - for (auto& [pos, neg] : combinations(soa::CombinationsFullIndexPolicy(groupPositive, groupNegative))) { - if (!(pidModel.get()->applyModelBoolean(pos)) || !(pidModel.get()->applyModelBoolean(neg))) { - continue; - } - - TLorentzVector part1Vec; - TLorentzVector part2Vec; - float mMassOne = TDatabasePDG::Instance()->GetParticle(cfgPid.value)->Mass(); - float mMassTwo = TDatabasePDG::Instance()->GetParticle(cfgPid.value)->Mass(); - - part1Vec.SetPtEtaPhiM(pos.pt(), pos.eta(), pos.phi(), mMassOne); - part2Vec.SetPtEtaPhiM(neg.pt(), neg.eta(), neg.phi(), mMassTwo); - - TLorentzVector sumVec(part1Vec); - sumVec += part2Vec; - - histos.fill(HIST("hInvariantMass"), sumVec.M()); - } - } -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; - return workflow; -} 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/pidML.h b/Tools/PIDML/pidMl.h similarity index 80% rename from Tools/PIDML/pidML.h rename to Tools/PIDML/pidMl.h index 821da7efc42..cb45360052c 100644 --- a/Tools/PIDML/pidML.h +++ b/Tools/PIDML/pidMl.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file pidML.h +/// \file pidMl.h /// \brief Data model for PID ML training. /// /// \author Maja Kabus @@ -17,8 +17,14 @@ #ifndef TOOLS_PIDML_PIDML_H_ #define TOOLS_PIDML_PIDML_H_ -#include "Framework/AnalysisDataModel.h" -#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include + +#include namespace o2::aod { @@ -32,16 +38,16 @@ DECLARE_SOA_COLUMN(Py, py, float); //! Non-dynam DECLARE_SOA_COLUMN(Pz, pz, float); //! Non-dynamic column with track z-momentum DECLARE_SOA_COLUMN(Sign, sign, float); //! Non-dynamic column with track sign DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, uint8_t); //! -DECLARE_SOA_COLUMN(TOFExpSignalDiffEl, tofExpSignalDiffEl, float); //! Difference between signal and expected for electron -DECLARE_SOA_COLUMN(TPCExpSignalDiffEl, tpcExpSignalDiffEl, float); //! Difference between signal and expected for electron -DECLARE_SOA_COLUMN(TOFExpSignalDiffMu, tofExpSignalDiffMu, float); //! Difference between signal and expected for muon -DECLARE_SOA_COLUMN(TPCExpSignalDiffMu, tpcExpSignalDiffMu, float); //! Difference between signal and expected for muon -DECLARE_SOA_COLUMN(TOFExpSignalDiffPi, tofExpSignalDiffPi, float); //! Difference between signal and expected for pion -DECLARE_SOA_COLUMN(TPCExpSignalDiffPi, tpcExpSignalDiffPi, float); //! Difference between signal and expected for pion -DECLARE_SOA_COLUMN(TOFExpSignalDiffKa, tofExpSignalDiffKa, float); //! Difference between signal and expected for kaon -DECLARE_SOA_COLUMN(TPCExpSignalDiffKa, tpcExpSignalDiffKa, float); //! Difference between signal and expected for kaon -DECLARE_SOA_COLUMN(TOFExpSignalDiffPr, tofExpSignalDiffPr, float); //! Difference between signal and expected for proton -DECLARE_SOA_COLUMN(TPCExpSignalDiffPr, tpcExpSignalDiffPr, float); //! Difference between signal and expected for proton +DECLARE_SOA_COLUMN(TofExpSignalDiffEl, tofExpSignalDiffEl, float); //! Difference between signal and expected for electron +DECLARE_SOA_COLUMN(TpcExpSignalDiffEl, tpcExpSignalDiffEl, float); //! Difference between signal and expected for electron +DECLARE_SOA_COLUMN(TofExpSignalDiffMu, tofExpSignalDiffMu, float); //! Difference between signal and expected for muon +DECLARE_SOA_COLUMN(TpcExpSignalDiffMu, tpcExpSignalDiffMu, float); //! Difference between signal and expected for muon +DECLARE_SOA_COLUMN(TofExpSignalDiffPi, tofExpSignalDiffPi, float); //! Difference between signal and expected for pion +DECLARE_SOA_COLUMN(TpcExpSignalDiffPi, tpcExpSignalDiffPi, float); //! Difference between signal and expected for pion +DECLARE_SOA_COLUMN(TofExpSignalDiffKa, tofExpSignalDiffKa, float); //! Difference between signal and expected for kaon +DECLARE_SOA_COLUMN(TpcExpSignalDiffKa, tpcExpSignalDiffKa, float); //! Difference between signal and expected for kaon +DECLARE_SOA_COLUMN(TofExpSignalDiffPr, tofExpSignalDiffPr, float); //! Difference between signal and expected for proton +DECLARE_SOA_COLUMN(TpcExpSignalDiffPr, tpcExpSignalDiffPr, float); //! Difference between signal and expected for proton } // namespace pidtracks DECLARE_SOA_TABLE(PidTracksDataMl, "AOD", "PIDTRACKSDATAML", //! Data tracks for prediction and domain adaptation aod::track::TPCSignal, @@ -63,7 +69,6 @@ DECLARE_SOA_TABLE(PidTracksDataMl, "AOD", "PIDTRACKSDATAML", //! Data tracks for aod::track::DcaXY, aod::track::DcaZ); DECLARE_SOA_TABLE(PidTracksData, "AOD", "PIDTRACKSDATA", //! Data tracks for comparative analysis - aod::cent::CentRun2V0M, aod::mult::MultFV0A, aod::mult::MultFV0C, pidtracks::MultFV0M, aod::mult::MultFT0A, aod::mult::MultFT0C, pidtracks::MultFT0M, aod::mult::MultZNA, aod::mult::MultZNC, @@ -90,34 +95,34 @@ DECLARE_SOA_TABLE(PidTracksData, "AOD", "PIDTRACKSDATA", //! Data tracks for com aod::track::DcaZ, pidtpc::TPCNSigmaEl, pidtpc::TPCExpSigmaEl, - pidtracks::TPCExpSignalDiffEl, + pidtracks::TpcExpSignalDiffEl, pidtof::TOFNSigmaEl, pidtof::TOFExpSigmaEl, - pidtracks::TOFExpSignalDiffEl, + pidtracks::TofExpSignalDiffEl, pidtpc::TPCNSigmaMu, pidtpc::TPCExpSigmaMu, - pidtracks::TPCExpSignalDiffMu, + pidtracks::TpcExpSignalDiffMu, pidtof::TOFNSigmaMu, pidtof::TOFExpSigmaMu, - pidtracks::TOFExpSignalDiffMu, + pidtracks::TofExpSignalDiffMu, pidtpc::TPCNSigmaPi, pidtpc::TPCExpSigmaPi, - pidtracks::TPCExpSignalDiffPi, + pidtracks::TpcExpSignalDiffPi, pidtof::TOFNSigmaPi, pidtof::TOFExpSigmaPi, - pidtracks::TOFExpSignalDiffPi, + pidtracks::TofExpSignalDiffPi, pidtpc::TPCNSigmaKa, pidtpc::TPCExpSigmaKa, - pidtracks::TPCExpSignalDiffKa, + pidtracks::TpcExpSignalDiffKa, pidtof::TOFNSigmaKa, pidtof::TOFExpSigmaKa, - pidtracks::TOFExpSignalDiffKa, + pidtracks::TofExpSignalDiffKa, pidtpc::TPCNSigmaPr, pidtpc::TPCExpSigmaPr, - pidtracks::TPCExpSignalDiffPr, + pidtracks::TpcExpSignalDiffPr, pidtof::TOFNSigmaPr, pidtof::TOFExpSigmaPr, - pidtracks::TOFExpSignalDiffPr); + pidtracks::TofExpSignalDiffPr); DECLARE_SOA_TABLE(PidTracksMcMl, "AOD", "PIDTRACKSMCML", //! MC tracks for training aod::track::TPCSignal, aod::track::TRDSignal, aod::track::TRDPattern, @@ -140,7 +145,6 @@ DECLARE_SOA_TABLE(PidTracksMcMl, "AOD", "PIDTRACKSMCML", //! MC tracks for train aod::mcparticle::PdgCode, pidtracks::IsPhysicalPrimary); DECLARE_SOA_TABLE(PidTracksMc, "AOD", "PIDTRACKSMC", //! MC tracks for comparative analysis - aod::cent::CentRun2V0M, aod::mult::MultFV0A, aod::mult::MultFV0C, pidtracks::MultFV0M, aod::mult::MultFT0A, aod::mult::MultFT0C, pidtracks::MultFT0M, aod::mult::MultZNA, aod::mult::MultZNC, @@ -167,34 +171,34 @@ DECLARE_SOA_TABLE(PidTracksMc, "AOD", "PIDTRACKSMC", //! MC tracks for comparati aod::track::DcaZ, pidtpc::TPCNSigmaEl, pidtpc::TPCExpSigmaEl, - pidtracks::TPCExpSignalDiffEl, + pidtracks::TpcExpSignalDiffEl, pidtof::TOFNSigmaEl, pidtof::TOFExpSigmaEl, - pidtracks::TOFExpSignalDiffEl, + pidtracks::TofExpSignalDiffEl, pidtpc::TPCNSigmaMu, pidtpc::TPCExpSigmaMu, - pidtracks::TPCExpSignalDiffMu, + pidtracks::TpcExpSignalDiffMu, pidtof::TOFNSigmaMu, pidtof::TOFExpSigmaMu, - pidtracks::TOFExpSignalDiffMu, + pidtracks::TofExpSignalDiffMu, pidtpc::TPCNSigmaPi, pidtpc::TPCExpSigmaPi, - pidtracks::TPCExpSignalDiffPi, + pidtracks::TpcExpSignalDiffPi, pidtof::TOFNSigmaPi, pidtof::TOFExpSigmaPi, - pidtracks::TOFExpSignalDiffPi, + pidtracks::TofExpSignalDiffPi, pidtpc::TPCNSigmaKa, pidtpc::TPCExpSigmaKa, - pidtracks::TPCExpSignalDiffKa, + pidtracks::TpcExpSignalDiffKa, pidtof::TOFNSigmaKa, pidtof::TOFExpSigmaKa, - pidtracks::TOFExpSignalDiffKa, + pidtracks::TofExpSignalDiffKa, pidtpc::TPCNSigmaPr, pidtpc::TPCExpSigmaPr, - pidtracks::TPCExpSignalDiffPr, + pidtracks::TpcExpSignalDiffPr, pidtof::TOFNSigmaPr, pidtof::TOFExpSigmaPr, - pidtracks::TOFExpSignalDiffPr, + pidtracks::TofExpSignalDiffPr, aod::mcparticle::PdgCode, pidtracks::IsPhysicalPrimary); } // namespace o2::aod diff --git a/Tools/PIDML/pidMlBatchEffAndPurProducer.cxx b/Tools/PIDML/pidMlBatchEffAndPurProducer.cxx new file mode 100644 index 00000000000..34ce845c79d --- /dev/null +++ b/Tools/PIDML/pidMlBatchEffAndPurProducer.cxx @@ -0,0 +1,266 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not 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.cxx +/// \brief Batch PID execution task. It produces derived data needed for ROOT script, which +/// generate PIDML neural network performance benchmark plots. +/// +/// \author Michał Olędzki +/// \author Marek Mytkowski + +#include "Tools/PIDML/pidOnnxModel.h" +#include "Tools/PIDML/pidUtils.h" +// +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#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; +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 KPatricleNames[KNPids] = {"proton", "kaon", "pion", "antipion", "antikaon", "antiproton"}; + + std::array, KNPids> hTracked; + std::array, KNPids> hMCPositive; + + o2::ccdb::CcdbApi ccdbApi; + + Configurable> pdgPids{"pdgPids", std::vector(KPids, KPids + KNPids), "list of PDG ids of particles to predict. Every subset of {2212, 321, 211, -211, -321, -2212} is correct value."}; + Configurable detectorMomentumLimits{"detectorMomentumLimits", MomentumLimitsMatrix(pidml_pt_cuts::defaultModelPLimits), "\"use {detector} when p >= y_{detector}\": array of 3 doubles [y_TPC, y_TOF, y_TRD]"}; + Configurable ccdbPath{"ccdbPath", "Users/m/mkabus/PIDML", "Base path to the CCDB directory with ONNX models"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; + Configurable useCcdb{"useCcdb", true, "Whether to autofetch ML model from CCDB. If false, local file will be used."}; + Configurable localPath{"localPath", "/home/mkabus/PIDML/", "Base path to the local directory with ONNX models"}; + Configurable useFixedTimestamp{"useFixedTimestamp", false, "Whether to use fixed timestamp from configurable instead of timestamp calculated from the data"}; + Configurable fixedTimestamp{"fixedTimestamp", 1524176895000, "Hardcoded timestamp for tests"}; + + Filter trackFilter = requireGlobalTrackInFilter(); + + using BigTracks = soa::Filtered>; + std::vector> models; + + void initHistos() + { + static const AxisSpec axisPt{50, 0, 3.1, "pt"}; + + static_for<0, KNPids - 1>([&](auto i) { + if (std::find(pdgPids.value.begin(), pdgPids.value.end(), KPids[i]) != pdgPids.value.end()) { + hTracked[i] = histos.add(Form("%s/hPtMCTracked", KParticleLabels[i].data()), Form("Tracked %ss vs pT", KPatricleNames[i].data()), kTH1F, {axisPt}); + hMCPositive[i] = histos.add(Form("%s/hPtMCPositive", KParticleLabels[i].data()), Form("MC Positive %ss vs pT", KPatricleNames[i].data()), kTH1F, {axisPt}); + } + }); + } + + void init(InitContext const&) + { + if (useCcdb) { + ccdbApi.init(ccdbUrl); + } + + initHistos(); + } + + std::optional getPartIndex(int32_t pdgCode) + { + std::optional index; + + if (std::find(pdgPids.value.begin(), pdgPids.value.end(), pdgCode) != pdgPids.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 (std::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, detectorMomentumLimits.value[kTPCTOF]) || tofMissing(track)) { + nSigma.composed = std::abs(nSigma.tpc); + } else { + nSigma.composed = std::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 (useCcdb && bc.runNumber() != CurrentRunNumber) { + uint64_t timestamp = useFixedTimestamp ? fixedTimestamp.value : bc.timestamp(); + for (const int32_t& pid : pdgPids.value) + models.emplace_back(PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, + ccdbApi, timestamp, pid, 1.1, &detectorMomentumLimits.value[0])); + } else { + for (const int32_t& pid : pdgPids.value) + models.emplace_back(PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, + ccdbApi, -1, pid, 1.1, &detectorMomentumLimits.value[0])); + } + + for (const auto& mcPart : mcParticles) { + // eta cut is done in requireGlobalTrackInFilter() so we cut it only here + if (mcPart.isPhysicalPrimary() && std::abs(mcPart.eta()) < kGlobalEtaCut) { + fillMCPositiveHist(mcPart.pdgCode(), mcPart.pt()); + } + } + + for (const 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 < pdgPids.value.size(); ++i) { + float mlCertainty = models[i].applyModel(track); + nSigma_t nSigma = getNSigma(track, pdgPids.value[i]); + bool isMCPid = mcPart.pdgCode() == pdgPids.value[i]; + + effAndPurPIDResult(track.index(), pdgPids.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..1441718b336 --- /dev/null +++ b/Tools/PIDML/pidMlEffAndPurProducer.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. + +/// \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 "Tools/PIDML/pidOnnxModel.h" +#include "Tools/PIDML/pidUtils.h" +// +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace pidml::pidutils; + +struct PidMlEffAndPurProducer { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable pdgPid{"pdgPid", 211, "PID to predict"}; + Configurable nSigmaCut{"nSigmaCut", 3.0f, "TPC and TOF PID nSigma cut"}; + Configurable detectorMomentumLimits{"detectorMomentumLimits", MomentumLimitsMatrix(pidml_pt_cuts::defaultModelPLimits), "use {detector} when p >= y_{detector}: array of 3 doubles [y_TPC, y_TOF, y_TRD]"}; + Configurable mlIdentCertaintyThreshold{"mlIdentCertaintyThreshold", 0.5, "Min certainty of the model to accept given mcPart to be of given kind"}; + + Configurable ccdbPath{"ccdbPath", "Users/m/mkabus/PIDML", "base path to the CCDB directory with ONNX models"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; + Configurable useCcdb{"useCcdb", true, "Whether to autofetch ML model from CCDB. If false, local file will be used."}; + Configurable localPath{"localPath", "/home/mkabus/PIDML", "base path to the local directory with ONNX models"}; + + Configurable useFixedTimestamp{"useFixedTimestamp", false, "Whether to use fixed timestamp from configurable instead of timestamp calculated from the data"}; + Configurable fixedTimestamp{"fixedTimestamp", 1524176895000, "Hardcoded timestamp for tests"}; + + o2::ccdb::CcdbApi ccdbApi; + int currentRunNumber = -1; + + Filter trackFilter = requireGlobalTrackInFilter(); + + using BigTracks = soa::Filtered>; + PidONNXModel pidModel; + + typedef struct nSigma_t { + double tpc, tof; + } nSigma_t; + + nSigma_t getNSigma(const BigTracks::iterator& track) + { + nSigma_t nSigma; + + switch (std::abs(pdgPid)) { + 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, const nSigma_t& nSigma) + { + // FIXME: for current particles it works, but there are some particles, + // which can have different sign and pdgSign + int sign = pdgPid > 0 ? 1 : -1; + if (track.sign() != sign) + return false; + + if (!inPLimit(track, detectorMomentumLimits.value[kTPCTOF]) || tofMissing(track)) { + if (std::abs(nSigma.tpc) >= nSigmaCut) + return false; + } else { + if (std::hypot(nSigma.tof, nSigma.tpc) >= nSigmaCut) + return false; + } + + return true; + } + + void init(InitContext const&) + { + if (useCcdb) { + ccdbApi.init(ccdbUrl); + } else { + pidModel = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, -1, + pdgPid.value, mlIdentCertaintyThreshold.value, &detectorMomentumLimits.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 (useCcdb && bc.runNumber() != currentRunNumber) { + uint64_t timestamp = useFixedTimestamp ? fixedTimestamp.value : bc.timestamp(); + pidModel = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, timestamp, + pdgPid.value, mlIdentCertaintyThreshold.value, &detectorMomentumLimits.value[0]); + } + + for (const auto& mcPart : mcParticles) { + // eta cut is included in requireGlobalTrackInFilter() so we cut it only here + if (mcPart.isPhysicalPrimary() && std::abs(mcPart.eta()) < kGlobalEtaCut && mcPart.pdgCode() == pidModel.mPid) { + histos.fill(HIST("hPtMCPositive"), mcPart.pt()); + } + } + + for (const 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 similarity index 71% rename from Tools/PIDML/pidMLProducer.cxx rename to Tools/PIDML/pidMlProducer.cxx index 81ec025510d..332a2a8209b 100644 --- a/Tools/PIDML/pidMLProducer.cxx +++ b/Tools/PIDML/pidMlProducer.cxx @@ -9,26 +9,44 @@ // 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. +/// \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 "Common/DataModel/Centrality.h" +#include "Tools/PIDML/pidMl.h" +#include "Tools/PIDML/pidUtils.h" +// #include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Tools/PIDML/pidML.h" + +#include +#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; - -#include "Framework/runDataProcessing.h" +using namespace pidml::pidutils; // Naming convention // Data: experimental data without simulation @@ -51,39 +69,36 @@ struct PidMlProducer { using BigTracksMC = soa::Filtered>; using MyCollisionML = aod::Collisions::iterator; - using MyCollision = soa::Join::iterator; + using MyCollision = soa::Join::iterator; - static constexpr float kEps = 1e-10f; - static constexpr float kMissingBeta = -999.0f; - static constexpr float kMissingTOFSignal = -999.0f; - static constexpr uint32_t nCharges = 2; + static constexpr uint32_t NCharges = 2; - static constexpr std::string_view histPrefixes[nCharges] = {"minus", "plus"}; + 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; + 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; + 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}; @@ -95,33 +110,33 @@ struct PidMlProducer { 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.}}); + 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}}); + 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 @@ -130,10 +145,10 @@ struct PidMlProducer { hTPCSigvsP[prefixInd]->Fill(track.p(), track.tpcSignal()); hTOFBetavsP[prefixInd]->Fill(track.p(), track.beta()); hTOFSigvsP[prefixInd]->Fill(track.p(), track.tofSignal()); - if (TMath::Abs(track.beta() - kMissingBeta) >= kEps) { - hFilteredTOFSigvsP[prefixInd]->Fill(track.p(), track.tofSignal()); + if (tofMissing(track)) { + hFilteredTOFSigvsP[prefixInd]->Fill(track.p(), kTOFMissingSignal); } else { - hFilteredTOFSigvsP[prefixInd]->Fill(track.p(), kMissingTOFSignal); + hFilteredTOFSigvsP[prefixInd]->Fill(track.p(), track.tofSignal()); } hTRDPattvsP[prefixInd]->Fill(track.p(), track.trdPattern()); hTRDSigvsP[prefixInd]->Fill(track.p(), track.trdSignal()); @@ -191,11 +206,35 @@ struct PidMlProducer { } } + 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(), track.trdSignal(), track.trdPattern(), - track.tofSignal(), track.beta(), + 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(), @@ -212,14 +251,13 @@ struct PidMlProducer { void processDataAll(MyCollision const& collision, BigTracksData const& tracks) { for (const auto& track : tracks) { - pidTracksTableData(collision.centRun2V0M(), - collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), + pidTracksTableData(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.tpcSignal(), getTRDSignal(track), getTRDPattern(track), track.trackEtaEmcal(), track.trackPhiEmcal(), - track.tofSignal(), track.beta(), + getTOFSignal(track), getTOFBeta(track), track.p(), track.pt(), track.px(), track.py(), track.pz(), track.sign(), track.x(), track.y(), track.z(), @@ -252,8 +290,8 @@ struct PidMlProducer { const auto mcParticle = track.mcParticle_as(); uint8_t isPrimary = static_cast(mcParticle.isPhysicalPrimary()); uint32_t pdgCode = mcParticle.pdgCode(); - pidTracksTableMCML(track.tpcSignal(), track.trdSignal(), track.trdPattern(), - track.tofSignal(), track.beta(), + 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(), @@ -278,14 +316,13 @@ struct PidMlProducer { 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(), + pidTracksTableMC(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.tpcSignal(), getTRDSignal(track), getTRDPattern(track), track.trackEtaEmcal(), track.trackPhiEmcal(), - track.tofSignal(), track.beta(), + getTOFSignal(track), getTOFBeta(track), track.p(), track.pt(), track.px(), track.py(), track.pz(), track.sign(), track.x(), track.y(), track.z(), diff --git a/Tools/PIDML/pidOnnxInterface.h b/Tools/PIDML/pidOnnxInterface.h index 0cf8b473d4a..6724e5c5167 100644 --- a/Tools/PIDML/pidOnnxInterface.h +++ b/Tools/PIDML/pidOnnxInterface.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file pidONNXInterface.h +/// \file pidOnnxInterface.h /// \brief A class that wraps PID ML ONNX model. See README.md for more detailed instructions. /// /// \author Maja Kabus @@ -17,44 +17,49 @@ #ifndef TOOLS_PIDML_PIDONNXINTERFACE_H_ #define TOOLS_PIDML_PIDONNXINTERFACE_H_ -#include -#include +#include "Tools/PIDML/pidOnnxModel.h" +// +#include +#include +#include + +#include +#include #include +#include #include -#include "Framework/Array2D.h" -#include "Tools/PIDML/pidOnnxModel.h" - namespace pidml_pt_cuts { -static constexpr int nPids = 6; -static constexpr int nCutVars = kNDetectors; -constexpr int pids[nPids] = {211, 321, 2212, -211, -321, -2212}; -auto pids_v = std::vector{pids, pids + nPids}; -constexpr double certainties[nPids] = {0.5, 0.5, 0.5, 0.5, 0.5, 0.5}; -auto certainties_v = std::vector{certainties, certainties + nPids}; +static constexpr int NPids = 6; +static constexpr int NCutVars = kNDetectors; +constexpr int Pids[NPids] = {211, 321, 2212, -211, -321, -2212}; +auto pidsV = std::vector{Pids, Pids + NPids}; +constexpr double Certainties[NPids] = {0.5, 0.5, 0.5, 0.5, 0.5, 0.5}; +auto certaintiesV = 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}}; - +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 +template 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) { + if (Pids.size() == 0) { LOG(fatal) << "PID ML Interface needs at least 1 output pid to predict"; } std::set tmp; - for (auto& pid : pids) { + for (const 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!"; } } @@ -63,14 +68,12 @@ struct PidONNXInterface { fillDefaultConfiguration(minCertaintiesFilled); } else { if (minCertainties.size() != mNPids) { - LOG(fatal) << "PID ML Interface: min certainties vector must be of the same size as the output pids vector"; + LOG(fatal) << "PID ML Interface: min Certainties vector must be of the same size as the output Pids vector"; } 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; @@ -80,32 +83,22 @@ struct PidONNXInterface { PidONNXInterface& operator=(const PidONNXInterface&) = delete; ~PidONNXInterface() = default; - template - float applyModel(const T& track, int pid) + float applyModel(const T::iterator& 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; return -1.0f; } - template - bool applyModelBoolean(const T& track, int pid) + bool applyModelBoolean(const T::iterator& 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 +109,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; + std::vector> mModels; + std::size_t mNPids{0}; + o2::framework::LabeledArray mPLimits; }; #endif // TOOLS_PIDML_PIDONNXINTERFACE_H_ diff --git a/Tools/PIDML/pidOnnxModel.h b/Tools/PIDML/pidOnnxModel.h index 8764496c25c..4ee88106ab0 100644 --- a/Tools/PIDML/pidOnnxModel.h +++ b/Tools/PIDML/pidOnnxModel.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file pidONNXModel.h +/// \file pidOnnxModel.h /// \brief A class that wraps PID ML ONNX model. See README.md for more detailed instructions. /// /// \author Maja Kabus @@ -17,23 +17,32 @@ #ifndef TOOLS_PIDML_PIDONNXMODEL_H_ #define TOOLS_PIDML_PIDONNXMODEL_H_ -#include +#include "Tools/PIDML/pidUtils.h" +// +#include +#include +#include + +#include +#include +#include +#include + #include +#include +#include +#include +#include +#include +#include #include -#include #include +#include +#include +#include +#include #include -#if __has_include() -#include -#else -#include -#endif -#include "rapidjson/document.h" -#include "rapidjson/filereadstream.h" - -#include "CCDB/CcdbApi.h" - enum PidMLDetector { kTPCOnly = 0, kTPCTOF, @@ -41,10 +50,19 @@ enum PidMLDetector { kNDetectors ///< number of available detectors configurations }; +using MomentumLimitsMatrix = std::array; + +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 MomentumLimitsMatrix 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 { -bool readJsonFile(const std::string& config, rapidjson::Document& d) +bool readJsonFile(std::string const& config, rapidjson::Document& d) { FILE* fp = fopen(config.data(), "rb"); if (!fp) { @@ -61,29 +79,24 @@ bool readJsonFile(const std::string& config, rapidjson::Document& d) } } // namespace +template 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 const& localPath, std::string const& ccdbPath, bool useCCDB, o2::ccdb::CcdbApi const& 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()); @@ -97,7 +110,6 @@ struct PidONNXModel { 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++) { @@ -119,44 +131,36 @@ struct PidONNXModel { PidONNXModel& operator=(const PidONNXModel&) = delete; ~PidONNXModel() = default; - template - float applyModel(const T& track) + float applyModel(const typename T::iterator& track) { return getModelOutput(track); } - template - bool applyModelBoolean(const T& track) + bool applyModelBoolean(const typename T::iterator& track) { return getModelOutput(track) >= mMinCertainty; } - PidMLDetector mDetector; - int mPid; - double mMinCertainty; + int mPid{0}; + double mMinCertainty{0}; 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; } - void downloadFromCCDB(o2::ccdb::CcdbApi& ccdbApi, std::string const& ccdbFile, uint64_t timestamp, std::string const& localDir, std::string const& localFile) + void downloadFromCCDB(o2::ccdb::CcdbApi const& ccdbApi, std::string const& ccdbFile, uint64_t timestamp, std::string const& localDir, std::string const& localFile) { std::map metadata; bool retrieveSuccess = ccdbApi.retrieveBlob(ccdbFile, localDir, metadata, timestamp, false, localFile); @@ -168,7 +172,7 @@ struct PidONNXModel { } } - void loadInputFiles(std::string const& localPath, std::string const& ccdbPath, bool useCCDB, o2::ccdb::CcdbApi& ccdbApi, uint64_t timestamp, int pid, std::string& modelPath) + void loadInputFiles(std::string const& localPath, std::string const& ccdbPath, bool useCCDB, o2::ccdb::CcdbApi const& ccdbApi, uint64_t timestamp, int pid, std::string& modelPath) { rapidjson::Document trainColumnsDoc; rapidjson::Document scalingParamsDoc; @@ -192,82 +196,83 @@ struct PidONNXModel { LOG(info) << "Using configuration files: " << localTrainColumnsPath << ", " << localScalingParamsPath; if (readJsonFile(localTrainColumnsPath, trainColumnsDoc)) { - for (auto& param : trainColumnsDoc["columns_for_training"].GetArray()) { - mTrainColumns.emplace_back(param.GetString()); + for (const auto& param : trainColumnsDoc["columns_for_training"].GetArray()) { + auto columnLabel = param.GetString(); + mTrainColumns.emplace_back(columnLabel); + mGetters.emplace_back(o2::soa::row_helpers::getColumnGetterByLabel(columnLabel)); } } if (readJsonFile(localScalingParamsPath, scalingParamsDoc)) { - for (auto& param : scalingParamsDoc["data"].GetArray()) { + for (const auto& param : scalingParamsDoc["data"].GetArray()) { mScalingParams[param[0].GetString()] = std::make_pair(param[1].GetFloat(), param[2].GetFloat()); } } } - template - std::vector createInputsSingle(const T& track) + static float scale(float value, const std::pair& scalingParams) { - // 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}; - - if (mDetector >= kTPCTOF) { - 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); - } - - return inputValues; + return (value - scalingParams.first) / scalingParams.second; } - // FIXME: Temporary solution, new networks will have sigmoid layer added - float sigmoid(float x) + std::vector getValues(const typename T::iterator& track) { - float value = std::max(-100.0f, std::min(100.0f, x)); - return 1.0f / (1.0f + std::exp(-value)); + std::vector output; + output.reserve(mTrainColumns.size()); + + bool useTOF = !pidml::pidutils::tofMissing(track) && pidml::pidutils::inPLimit(track, mPLimits[kTPCTOF]); + bool useTRD = !pidml::pidutils::trdMissing(track) && pidml::pidutils::inPLimit(track, mPLimits[kTPCTOFTRD]); + + for (uint32_t i = 0; i < mTrainColumns.size(); ++i) { + auto& columnLabel = mTrainColumns[i]; + + if ( + ((columnLabel == "fTRDSignal" || columnLabel == "fTRDPattern") && !useTRD) || + ((columnLabel == "fTOFSignal" || columnLabel == "fBeta") && !useTOF)) { + output.push_back(std::numeric_limits::quiet_NaN()); + continue; + } + + std::optional> scalingParams = std::nullopt; + + auto scalingParamsEntry = mScalingParams.find(columnLabel); + if (scalingParamsEntry != mScalingParams.end()) { + scalingParams = scalingParamsEntry->second; + } + + float value = mGetters[i](track); + + if (scalingParams) { + value = scale(value, scalingParams.value()); + } + + output.push_back(value); + } + + return output; } - template - float getModelOutput(const T& track) + float getModelOutput(const typename T::iterator& track) { - auto input_shape = mInputShapes[0]; - std::vector inputTensorValues = createInputsSingle(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 BatchSize = 1; + auto inputShape = mInputShapes[0]; + inputShape[0] = BatchSize; + + std::vector inputTensorValues = getValues(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 + Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); + inputTensors.emplace_back(Ort::Value::CreateTensor(memInfo, inputTensorValues.data(), inputTensorValues.size(), inputShape.data(), inputShape.size())); // Double-check the dimensions of the input tensor assert(inputTensors[0].IsTensor() && - inputTensors[0].GetTensorTypeAndShapeInfo().GetShape() == input_shape); + inputTensors[0].GetTensorTypeAndShapeInfo().GetShape() == inputShape); 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), @@ -277,15 +282,14 @@ struct PidONNXModel { 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 assert(outputTensors.size() == mOutputNames.size() && outputTensors[0].IsTensor()); 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 + const float* outputValue = outputTensors[0].GetTensorData(); + float certainty = *outputValue; return certainty; } catch (const Ort::Exception& exception) { LOG(error) << "Error running model inference: " << exception.what(); @@ -304,16 +308,14 @@ struct PidONNXModel { } std::vector mTrainColumns; + std::vector mGetters; std::map> mScalingParams; 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/qaPid.cxx b/Tools/PIDML/qaPid.cxx index 4efbbbc077a..25fba1ee6a0 100644 --- a/Tools/PIDML/qaPid.cxx +++ b/Tools/PIDML/qaPid.cxx @@ -9,26 +9,42 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// +/// \file qaPid.cxx /// \brief Task to check PID efficiency /// \author Łukasz Sawicki /// \since -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" +#include "Common/DataModel/PIDResponseCombined.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.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 EvaluatePid { +struct QaPid { double combinedSignal(float val1, float val2) { - return sqrt(pow(val1, 2) + pow(val2, 2)); + return std::sqrt(std::pow(val1, 2) + std::pow(val2, 2)); } int indexOfSmallestElement(const float array[], int size) @@ -41,113 +57,119 @@ struct EvaluatePid { return index; } + enum ContaminationIn { + kPion, + kProton, + kKaon + }; + void fillContaminationRegistry(int i, int pdgCode, double pt) { - if (i == 0) { - if (pdgCode == 211) { + if (i == ContaminationIn::kPion) { + if (pdgCode == PDG_t::kPiPlus) { histReg.fill(HIST("contamination/211in211"), pt); } - if (pdgCode == -211) { + if (pdgCode == PDG_t::kPiMinus) { histReg.fill(HIST("contamination/0211in211"), pt); } - if (pdgCode == 2212) { + if (pdgCode == PDG_t::kProton) { histReg.fill(HIST("contamination/2212in211"), pt); } - if (pdgCode == -2212) { + if (pdgCode == PDG_t::kProtonBar) { histReg.fill(HIST("contamination/02212in211"), pt); } - if (pdgCode == 321) { + if (pdgCode == PDG_t::kKPlus) { histReg.fill(HIST("contamination/321in211"), pt); } - if (pdgCode == -321) { + if (pdgCode == PDG_t::kKMinus) { histReg.fill(HIST("contamination/0321in211"), pt); } - if (pdgCode == 11) { + if (pdgCode == PDG_t::kElectron) { histReg.fill(HIST("contamination/11in211"), pt); } - if (pdgCode == -11) { + if (pdgCode == PDG_t::kPositron) { histReg.fill(HIST("contamination/011in211"), pt); } - if (pdgCode == 13) { + if (pdgCode == PDG_t::kMuonMinus) { histReg.fill(HIST("contamination/13in211"), pt); } - if (pdgCode == -13) { + if (pdgCode == PDG_t::kMuonPlus) { histReg.fill(HIST("contamination/013in211"), pt); } - } else if (i == 1) { - if (pdgCode == 211) { + } else if (i == ContaminationIn::kProton) { + if (pdgCode == PDG_t::kPiPlus) { histReg.fill(HIST("contamination/211in2212"), pt); } - if (pdgCode == -211) { + if (pdgCode == PDG_t::kPiMinus) { histReg.fill(HIST("contamination/0211in2212"), pt); } - if (pdgCode == 2212) { + if (pdgCode == PDG_t::kProton) { histReg.fill(HIST("contamination/2212in2212"), pt); } - if (pdgCode == -2212) { + if (pdgCode == PDG_t::kProtonBar) { histReg.fill(HIST("contamination/02212in2212"), pt); } - if (pdgCode == 321) { + if (pdgCode == PDG_t::kKPlus) { histReg.fill(HIST("contamination/321in2212"), pt); } - if (pdgCode == -321) { + if (pdgCode == PDG_t::kKMinus) { histReg.fill(HIST("contamination/0321in2212"), pt); } - if (pdgCode == 11) { + if (pdgCode == PDG_t::kElectron) { histReg.fill(HIST("contamination/11in2212"), pt); } - if (pdgCode == -11) { + if (pdgCode == PDG_t::kPositron) { histReg.fill(HIST("contamination/011in2212"), pt); } - if (pdgCode == 13) { + if (pdgCode == PDG_t::kMuonMinus) { histReg.fill(HIST("contamination/13in2212"), pt); } - if (pdgCode == -13) { + if (pdgCode == PDG_t::kMuonPlus) { histReg.fill(HIST("contamination/013in2212"), pt); } - } else if (i == 2) { - if (pdgCode == 211) { + } else if (i == ContaminationIn::kKaon) { + if (pdgCode == PDG_t::kPiPlus) { histReg.fill(HIST("contamination/211in321"), pt); } - if (pdgCode == -211) { + if (pdgCode == PDG_t::kPiMinus) { histReg.fill(HIST("contamination/0211in321"), pt); } - if (pdgCode == 2212) { + if (pdgCode == PDG_t::kProton) { histReg.fill(HIST("contamination/2212in321"), pt); } - if (pdgCode == -2212) { + if (pdgCode == PDG_t::kProtonBar) { histReg.fill(HIST("contamination/02212in321"), pt); } - if (pdgCode == 321) { + if (pdgCode == PDG_t::kKPlus) { histReg.fill(HIST("contamination/321in321"), pt); } - if (pdgCode == -321) { + if (pdgCode == PDG_t::kKMinus) { histReg.fill(HIST("contamination/0321in321"), pt); } - if (pdgCode == 11) { + if (pdgCode == PDG_t::kElectron) { histReg.fill(HIST("contamination/11in321"), pt); } - if (pdgCode == -11) { + if (pdgCode == PDG_t::kPositron) { histReg.fill(HIST("contamination/011in321"), pt); } - if (pdgCode == 13) { + if (pdgCode == PDG_t::kMuonMinus) { histReg.fill(HIST("contamination/13in321"), pt); } - if (pdgCode == -13) { + if (pdgCode == PDG_t::kMuonPlus) { histReg.fill(HIST("contamination/013in321"), pt); } } @@ -157,13 +179,13 @@ struct EvaluatePid { void fillPidHistos(const T& track, const int pdgCode, bool isPidTrue) { if (isPidTrue) { - histReg.fill(HIST(pidTrueRegistryNames[i]), track.pt()); + histReg.fill(HIST(PidTrueRegistryNames[i]), track.pt()); histReg.fill(HIST(TPCPidTrueRegistryNames[i]), track.p(), track.tpcSignal()); histReg.fill(HIST("TPCSignalPidTrue"), track.p(), track.tpcSignal()); histReg.fill(HIST("TOFSignalPidTrue"), track.p(), track.beta()); histReg.fill(HIST(TOFPidTrueRegistryNames[i]), track.p(), track.beta()); } else { - histReg.fill(HIST(pidFalseRegistryNames[i]), track.pt()); + histReg.fill(HIST(PidFalseRegistryNames[i]), track.pt()); histReg.fill(HIST(TPCPidFalseRegistryNames[i]), track.p(), track.tpcSignal()); histReg.fill(HIST("TPCSignalPidFalse"), track.p(), track.tpcSignal()); histReg.fill(HIST("TOFSignalPidFalse"), track.p(), track.beta()); @@ -177,8 +199,8 @@ struct EvaluatePid { // nb of particles (5 particles - Pi, Pr, Ka, e, mu, and 5 antiparticles) static const int numParticles = 10; - static constexpr std::string_view pidTrueRegistryNames[numParticles] = {"pidTrue/211", "pidTrue/2212", "pidTrue/321", "pidTrue/11", "pidTrue/13", "pidTrue/0211", "pidTrue/02212", "pidTrue/0321", "pidTrue/011", "pidTrue/013"}; - static constexpr std::string_view pidFalseRegistryNames[numParticles] = {"pidFalse/211", "pidFalse/2212", "pidFalse/321", "pidFalse/11", "pidFalse/13", "pidFalse/0211", "pidFalse/02212", "pidFalse/0321", "pidFalse/011", "pidFalse/013"}; + static constexpr std::string_view PidTrueRegistryNames[numParticles] = {"pidTrue/211", "pidTrue/2212", "pidTrue/321", "pidTrue/11", "pidTrue/13", "pidTrue/0211", "pidTrue/02212", "pidTrue/0321", "pidTrue/011", "pidTrue/013"}; + static constexpr std::string_view PidFalseRegistryNames[numParticles] = {"pidFalse/211", "pidFalse/2212", "pidFalse/321", "pidFalse/11", "pidFalse/13", "pidFalse/0211", "pidFalse/02212", "pidFalse/0321", "pidFalse/011", "pidFalse/013"}; static constexpr std::string_view TPCPidTrueRegistryNames[numParticles] = {"TPCPidTrue/211", "TPCPidTrue/2212", "TPCPidTrue/321", "TPCPidTrue/11", "TPCPidTrue/13", "TPCPidTrue/0211", "TPCPidTrue/02212", "TPCPidTrue/0321", "TPCPidTrue/011", "TPCPidTrue/013"}; static constexpr std::string_view TPCPidFalseRegistryNames[numParticles] = {"TPCPidFalse/211", "TPCPidFalse/2212", "TPCPidFalse/321", "TPCPidFalse/11", "TPCPidFalse/13", "TPCPidFalse/0211", "TPCPidFalse/02212", "TPCPidFalse/0321", "TPCPidFalse/011", "TPCPidFalse/013"}; @@ -186,13 +208,13 @@ struct EvaluatePid { static constexpr std::string_view TOFPidTrueRegistryNames[numParticles] = {"TOFPidTrue/211", "TOFPidTrue/2212", "TOFPidTrue/321", "TOFPidTrue/11", "TOFPidTrue/13", "TOFPidTrue/0211", "TOFPidTrue/02212", "TOFPidTrue/0321", "TOFPidTrue/011", "TOFPidTrue/013"}; static constexpr std::string_view TOFPidFalseRegistryNames[numParticles] = {"TOFPidFalse/211", "TOFPidFalse/2212", "TOFPidFalse/321", "TOFPidFalse/11", "TOFPidFalse/13", "TOFPidFalse/0211", "TOFPidFalse/02212", "TOFPidFalse/0321", "TOFPidFalse/011", "TOFPidFalse/013"}; - static constexpr int pdgCodes[numParticles] = {211, 2212, 321, 11, 13, -211, -2212, -321, -11, -13}; - static constexpr int pidToPdg[numParticles] = {11, 13, 211, 321, 2212, -11, -13, -211, -321, -2212}; - // charge with index i corresponds to i-th particle from pdgCodes array - static constexpr int particleCharge[numParticles] = {1, 1, 1, -1, -1, -1, -1, -1, 1, 1}; + static constexpr int PdgCodes[numParticles] = {211, 2212, 321, 11, 13, -211, -2212, -321, -11, -13}; + static constexpr int PidToPdg[numParticles] = {11, 13, 211, 321, 2212, -11, -13, -211, -321, -2212}; + // charge with index i corresponds to i-th particle from PdgCodes array + static constexpr int ParticleCharge[numParticles] = {1, 1, 1, -1, -1, -1, -1, -1, 1, 1}; // momentum value when to switch from pid based only on TPC (below the value) to combination of TPC and TOF (above the value) // i-th momentum corresponds to the i-th particle - static constexpr float pSwitch[numParticles] = {0.5, 0.8, 0.5, 0.5, 0.5, 0.5, 0.8, 0.5, 0.5, 0.5}; + static constexpr float PSwitch[numParticles] = {0.5, 0.8, 0.5, 0.5, 0.5, 0.5, 0.8, 0.5, 0.5, 0.5}; static const int maxP = 5; // nb of bins for TH1 hists @@ -323,26 +345,26 @@ struct EvaluatePid { {"TOFPidFalse/011", "PID false e^{+};p (GeV/c); TOF #beta", {HistType::kTH2F, {{binsNb2D, 0.2, 10}, {110, 0, 1.1}}}}}}; template - void pidSimple(const T& track, const int pdgCode, const float tpcNSigmas[], const float tofNSigmas[], int /*arrLen*/) + void pidSimple(const T& track, const int pdgCode, const float tpcNSigmas[], const float tofNSigmas[]) { /* Simplest possible PID, accept particle when: TPCSignal < X if p < Value or - sqrt(TPCSignal^2 + TOFSignal^2) < X if p > Value + std::sqrt(TPCSignal^2 + TOFSignal^2) < X if p > Value */ const float p = track.p(); - if ((p < pSwitch[i]) & (track.sign() == particleCharge[i])) { - if (abs(tpcNSigmas[i]) < nsigmacut.value) { - if (pdgCode == pdgCodes[i]) { + if ((p < PSwitch[i]) & (track.sign() == ParticleCharge[i])) { + if (std::abs(tpcNSigmas[i]) < nsigmacut.value) { + if (pdgCode == PdgCodes[i]) { fillPidHistos(track, pdgCode, true); } else { fillPidHistos(track, pdgCode, false); } } - } else if ((p >= pSwitch[i]) & (track.sign() == particleCharge[i])) { - if (sqrt(pow(tpcNSigmas[i], 2) + pow(tofNSigmas[i], 2)) < nsigmacut.value) { - if (pdgCode == pdgCodes[i]) { + } else if ((p >= PSwitch[i]) & (track.sign() == ParticleCharge[i])) { + if (std::sqrt(std::pow(tpcNSigmas[i], 2) + std::pow(tofNSigmas[i], 2)) < nsigmacut.value) { + if (pdgCode == PdgCodes[i]) { fillPidHistos(track, pdgCode, true); } else { fillPidHistos(track, pdgCode, false); @@ -351,36 +373,36 @@ struct EvaluatePid { } } - template - void pidMinStrategy(const T& track, const int pdgCode, const float tpcNSigmas[], const float tofNSigmas[], int arrLen) + template + void pidMinStrategy(const T& track, const int pdgCode, const float tpcNSigmas[], const float tofNSigmas[]) { const float p = track.p(); // list of Nsigmas for particles - float particleNSigma[arrLen]; + float particleNSigma[kArrLen]; // calculate Nsigmas for every particle - for (int j = 0; j < arrLen; ++j) { - if (p < pSwitch[j]) { - particleNSigma[j] = abs(tpcNSigmas[j]); - } else if (p >= pSwitch[j]) { + for (int j = 0; j < kArrLen; ++j) { + if (p < PSwitch[j]) { + particleNSigma[j] = std::abs(tpcNSigmas[j]); + } else { particleNSigma[j] = combinedSignal(tpcNSigmas[j], tofNSigmas[j]); } } - if ((p < pSwitch[i]) & (track.sign() == particleCharge[i])) { - float tmp_NSigma = abs(tpcNSigmas[i]); - if ((tmp_NSigma < nsigmacut.value) & (indexOfSmallestElement(particleNSigma, arrLen) == i)) { - if (pdgCode == pdgCodes[i]) { + if ((p < PSwitch[i]) & (track.sign() == ParticleCharge[i])) { + float tmpNSigma = std::abs(tpcNSigmas[i]); + if ((tmpNSigma < nsigmacut.value) & (indexOfSmallestElement(particleNSigma, kArrLen) == i)) { + if (pdgCode == PdgCodes[i]) { fillPidHistos(track, pdgCode, true); } else { fillPidHistos(track, pdgCode, false); } } - } else if ((p >= pSwitch[i]) & (track.sign() == particleCharge[i])) { - float tmp_NSigma = combinedSignal(tpcNSigmas[i], tofNSigmas[i]); - if ((tmp_NSigma < nsigmacut.value) & (indexOfSmallestElement(particleNSigma, arrLen) == i)) { - if (pdgCode == pdgCodes[i]) { + } else if ((p >= PSwitch[i]) & (track.sign() == ParticleCharge[i])) { + float tmpNSigma = combinedSignal(tpcNSigmas[i], tofNSigmas[i]); + if ((tmpNSigma < nsigmacut.value) & (indexOfSmallestElement(particleNSigma, kArrLen) == i)) { + if (pdgCode == PdgCodes[i]) { fillPidHistos(track, pdgCode, true); } else { fillPidHistos(track, pdgCode, false); @@ -389,45 +411,45 @@ struct EvaluatePid { } } - template - void pidExclusiveStrategy(const T& track, const int pdgCode, const float tpcNSigmas[], const float tofNSigmas[], int arrLen) + template + void pidExclusiveStrategy(const T& track, const int pdgCode, const float tpcNSigmas[], const float tofNSigmas[]) { const float p = track.p(); // list of Nsigmas for particles - float particleNSigma[arrLen]; + float particleNSigma[kArrLen]; // calculate Nsigmas for every particle - for (int j = 0; j < arrLen; ++j) { - if (p < pSwitch[j]) { - particleNSigma[j] = abs(tpcNSigmas[j]); - } else if (p >= pSwitch[j]) { + for (int j = 0; j < kArrLen; ++j) { + if (p < PSwitch[j]) { + particleNSigma[j] = std::abs(tpcNSigmas[j]); + } else { particleNSigma[j] = combinedSignal(tpcNSigmas[j], tofNSigmas[j]); } } // check how many particles satisfy the condition int counts = 0; - for (int j = 0; j < arrLen; ++j) { + for (int j = 0; j < kArrLen; ++j) { if (particleNSigma[j] < nsigmacut.value) { counts++; } } if (counts == 1) { - if ((p < pSwitch[i]) & (track.sign() == particleCharge[i])) { - float tmp_NSigma = abs(tpcNSigmas[i]); - if ((tmp_NSigma < nsigmacut.value) & (indexOfSmallestElement(particleNSigma, arrLen) == i)) { - if (pdgCode == pdgCodes[i]) { + if ((p < PSwitch[i]) & (track.sign() == ParticleCharge[i])) { + float tmpNSigma = std::abs(tpcNSigmas[i]); + if ((tmpNSigma < nsigmacut.value) & (indexOfSmallestElement(particleNSigma, kArrLen) == i)) { + if (pdgCode == PdgCodes[i]) { fillPidHistos(track, pdgCode, true); } else { fillPidHistos(track, pdgCode, false); } } - } else if ((p >= pSwitch[i]) & (track.sign() == particleCharge[i])) { - float tmp_NSigma = combinedSignal(tpcNSigmas[i], tofNSigmas[i]); - if ((tmp_NSigma < nsigmacut.value) & (indexOfSmallestElement(particleNSigma, arrLen) == i)) { - if (pdgCode == pdgCodes[i]) { + } else if ((p >= PSwitch[i]) & (track.sign() == ParticleCharge[i])) { + float tmpNSigma = combinedSignal(tpcNSigmas[i], tofNSigmas[i]); + if ((tmpNSigma < nsigmacut.value) & (indexOfSmallestElement(particleNSigma, kArrLen) == i)) { + if (pdgCode == PdgCodes[i]) { fillPidHistos(track, pdgCode, true); } else { fillPidHistos(track, pdgCode, false); @@ -442,8 +464,8 @@ struct EvaluatePid { { // Convert PID to PDG code // We don't identify particles with PID bigger than Proton, putting dummy code so they will be skipped. - int bayesPdg = track.bayesID() > o2::track::PID::Proton ? 999 : pidToPdg[track.bayesID()]; - if (track.bayesID() <= o2::track::PID::Proton && track.sign() == -1 * particleCharge[track.bayesID()]) { // Check if antiparticle + int bayesPdg = track.bayesID() > o2::track::PID::Proton ? 999 : PidToPdg[track.bayesID()]; + if (track.bayesID() <= o2::track::PID::Proton && track.sign() == -1 * ParticleCharge[track.bayesID()]) { // Check if antiparticle bayesPdg += numParticles / 2; } return bayesPdg; @@ -453,7 +475,7 @@ struct EvaluatePid { void pidBayes(const T& track, const int pdgCode, const int bayesPdg) { if (bayesPdg == pdgCode) { - if (pdgCode == pdgCodes[i]) { + if (pdgCode == PdgCodes[i]) { fillPidHistos(track, pdgCode, true); } else { fillPidHistos(track, pdgCode, false); @@ -465,34 +487,25 @@ struct EvaluatePid { void fillMcHistos(const T& track, const int pdgCode) { // pions - if (pdgCode == 211) { + if (pdgCode == PDG_t::kPiPlus) { histReg.fill(HIST("MC/211"), track.pt()); - } else if (pdgCode == -211) { + } else if (pdgCode == PDG_t::kPiMinus) { histReg.fill(HIST("MC/0211"), track.pt()); - } - // protons - else if (pdgCode == 2212) { + } /* protons */ else if (pdgCode == PDG_t::kProton) { histReg.fill(HIST("MC/2212"), track.pt()); - } else if (pdgCode == -2212) { + } else if (pdgCode == PDG_t::kProtonBar) { histReg.fill(HIST("MC/02212"), track.pt()); - } - // kaons - else if (pdgCode == 321) { + } /* kaons */ else if (pdgCode == PDG_t::kKPlus) { histReg.fill(HIST("MC/321"), track.pt()); - } else if (pdgCode == -321) { + } else if (pdgCode == PDG_t::kKMinus) { histReg.fill(HIST("MC/0321"), track.pt()); - } - // electrons - else if (pdgCode == 11) { + } /* electrons */ else if (pdgCode == PDG_t::kElectron) { histReg.fill(HIST("MC/11"), track.pt()); - ; - } else if (pdgCode == -11) { + } else if (pdgCode == PDG_t::kPositron) { histReg.fill(HIST("MC/011"), track.pt()); - } - // muons - else if (pdgCode == 13) { + } /* muons */ else if (pdgCode == PDG_t::kMuonMinus) { histReg.fill(HIST("MC/13"), track.pt()); - } else if (pdgCode == -13) { + } else if (pdgCode == PDG_t::kMuonPlus) { histReg.fill(HIST("MC/013"), track.pt()); } else { histReg.fill(HIST("MC/else"), track.pt()); @@ -503,11 +516,18 @@ struct EvaluatePid { Configurable strategy{"strategy", 1, "1-PID with Nsigma method, 2-PID with NSigma and condition for minimal Nsigma value for particle, 3-Exclusive condition for NSigma, 4-Bayesian PID"}; Filter trackFilter = requireGlobalTrackInFilter(); - using pidTracks = soa::Filtered>; + using PidTracks = soa::Filtered>; + + enum PIDStrategy { + kSimple = 1, + kMin = 2, + kExclusive = 3, + kBayes = 4 + }; - void process(pidTracks const& tracks, aod::McParticles const& /*mcParticles*/) + void process(PidTracks const& tracks, aod::McParticles const& /*mcParticles*/) { - for (auto& track : tracks) { + for (const auto& track : tracks) { auto particle = track.mcParticle_as(); int pdgCode = particle.pdgCode(); @@ -518,22 +538,22 @@ struct EvaluatePid { const float tpcNSigmas[numParticles] = {track.tpcNSigmaPi(), track.tpcNSigmaPr(), track.tpcNSigmaKa(), track.tpcNSigmaEl(), track.tpcNSigmaMu()}; const float tofNSigmas[numParticles] = {track.tofNSigmaPi(), track.tofNSigmaPr(), track.tofNSigmaKa(), track.tofNSigmaEl(), track.tofNSigmaMu()}; - if (strategy.value == 1) { + if (strategy.value == PIDStrategy::kSimple) { // Simplest strategy. PID with Nsigma method only static_for<0, 9>([&](auto i) { - pidSimple(track, pdgCode, tpcNSigmas, tofNSigmas, 5); + pidSimple(track, pdgCode, tpcNSigmas, tofNSigmas); }); - } else if (strategy.value == 2) { + } else if (strategy.value == PIDStrategy::kMin) { // PID with Nsigma method and additional condition. Selected particle's Nsigma value must be the lowest in order to count particle static_for<0, 9>([&](auto i) { - pidMinStrategy(track, pdgCode, tpcNSigmas, tofNSigmas, 5); + pidMinStrategy(track, pdgCode, tpcNSigmas, tofNSigmas); }); - } else if (strategy.value == 3) { + } else if (strategy.value == PIDStrategy::kExclusive) { // Particle is counted only if one can satisfy the PID NSigma condition static_for<0, 9>([&](auto i) { - pidExclusiveStrategy(track, pdgCode, tpcNSigmas, tofNSigmas, 5); + pidExclusiveStrategy(track, pdgCode, tpcNSigmas, tofNSigmas); }); - } else if (strategy.value == 4) { + } else if (strategy.value == PIDStrategy::kBayes) { int bayesPdg = getPdgFromPid(track); static_for<0, 9>([&](auto i) { pidBayes(track, pdgCode, bayesPdg); @@ -546,6 +566,6 @@ struct EvaluatePid { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), }; } diff --git a/Tools/PIDML/qaPidML.cxx b/Tools/PIDML/qaPidMl.cxx similarity index 72% rename from Tools/PIDML/qaPidML.cxx rename to Tools/PIDML/qaPidMl.cxx index accd055222c..01fca6457e1 100644 --- a/Tools/PIDML/qaPidML.cxx +++ b/Tools/PIDML/qaPidMl.cxx @@ -9,25 +9,39 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// +/// \file qaPidMl.cxx /// \brief Task to check ML PID efficiency. Based on Maja's simpleApplyPidOnnxModel.cxx code /// \author Łukasz Sawicki /// \since -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/StaticFor.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/PIDResponse.h" -#include #include "Tools/PIDML/pidOnnxModel.h" +// +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#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 pidml { +struct QaPidMl { static const int maxP = 5; // nb of bins for TH1 hists static const int binsNb = 100; @@ -35,8 +49,8 @@ struct pidml { static const int binsNb2D = 1000; static const int numParticles = 3; - static constexpr std::string_view pidTrueRegistryNames[numParticles] = {"pidTrue/211", "pidTrue/2212", "pidTrue/321"}; - static constexpr std::string_view pidFalseRegistryNames[numParticles] = {"pidFalse/211", "pidFalse/2212", "pidFalse/321"}; + static constexpr std::string_view PidTrueRegistryNames[numParticles] = {"pidTrue/211", "pidTrue/2212", "pidTrue/321"}; + static constexpr std::string_view PidFalseRegistryNames[numParticles] = {"pidFalse/211", "pidFalse/2212", "pidFalse/321"}; static constexpr std::string_view TPCPidTrueRegistryNames[numParticles] = {"TPCPidTrue/211", "TPCPidTrue/2212", "TPCPidTrue/321"}; static constexpr std::string_view TPCPidFalseRegistryNames[numParticles] = {"TPCPidFalse/211", "TPCPidFalse/2212", "TPCPidFalse/321"}; @@ -45,11 +59,11 @@ struct pidml { static constexpr std::string_view TOFPidFalseRegistryNames[numParticles] = {"TOFPidFalse/211", "TOFPidFalse/2212", "TOFPidFalse/321"}; // available particles: 211, 2212, 321 - static constexpr int particlesPdgCode[numParticles] = {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", @@ -129,113 +143,119 @@ struct pidml { {"TOFPidFalse/2212", "PID false p;p (GeV/c); TOF #beta", {HistType::kTH2F, {{binsNb2D, 0.2, 10}, {110, 0, 1.1}}}}, {"TOFPidFalse/321", "PID false K^{+};p (GeV/c); TOF #beta", {HistType::kTH2F, {{binsNb2D, 0.2, 10}, {110, 0, 1.1}}}}}}; + enum ContaminationIn { + kPion, + kProton, + kKaon + }; + void fillContaminationRegistry(int i, int pdgCode, double pt) { - if (i == 0) { - if (pdgCode == 211) { + if (i == ContaminationIn::kPion) { + if (pdgCode == PDG_t::kPiPlus) { histReg.fill(HIST("contamination/211in211"), pt); } - if (pdgCode == -211) { + if (pdgCode == PDG_t::kPiMinus) { histReg.fill(HIST("contamination/0211in211"), pt); } - if (pdgCode == 2212) { + if (pdgCode == PDG_t::kProton) { histReg.fill(HIST("contamination/2212in211"), pt); } - if (pdgCode == -2212) { + if (pdgCode == PDG_t::kProtonBar) { histReg.fill(HIST("contamination/02212in211"), pt); } - if (pdgCode == 321) { + if (pdgCode == PDG_t::kKPlus) { histReg.fill(HIST("contamination/321in211"), pt); } - if (pdgCode == -321) { + if (pdgCode == PDG_t::kKMinus) { histReg.fill(HIST("contamination/0321in211"), pt); } - if (pdgCode == 11) { + if (pdgCode == PDG_t::kElectron) { histReg.fill(HIST("contamination/11in211"), pt); } - if (pdgCode == -11) { + if (pdgCode == PDG_t::kPositron) { histReg.fill(HIST("contamination/011in211"), pt); } - if (pdgCode == 13) { + if (pdgCode == PDG_t::kMuonMinus) { histReg.fill(HIST("contamination/13in211"), pt); } - if (pdgCode == -13) { + if (pdgCode == PDG_t::kMuonPlus) { histReg.fill(HIST("contamination/013in211"), pt); } - } else if (i == 1) { - if (pdgCode == 211) { + } else if (i == ContaminationIn::kProton) { + if (pdgCode == PDG_t::kPiPlus) { histReg.fill(HIST("contamination/211in2212"), pt); } - if (pdgCode == -211) { + if (pdgCode == PDG_t::kPiMinus) { histReg.fill(HIST("contamination/0211in2212"), pt); } - if (pdgCode == 2212) { + if (pdgCode == PDG_t::kProton) { histReg.fill(HIST("contamination/2212in2212"), pt); } - if (pdgCode == -2212) { + if (pdgCode == PDG_t::kProtonBar) { histReg.fill(HIST("contamination/02212in2212"), pt); } - if (pdgCode == 321) { + if (pdgCode == PDG_t::kKPlus) { histReg.fill(HIST("contamination/321in2212"), pt); } - if (pdgCode == -321) { + if (pdgCode == PDG_t::kKMinus) { histReg.fill(HIST("contamination/0321in2212"), pt); } - if (pdgCode == 11) { + if (pdgCode == PDG_t::kElectron) { histReg.fill(HIST("contamination/11in2212"), pt); } - if (pdgCode == -11) { + if (pdgCode == PDG_t::kPositron) { histReg.fill(HIST("contamination/011in2212"), pt); } - if (pdgCode == 13) { + if (pdgCode == PDG_t::kMuonMinus) { histReg.fill(HIST("contamination/13in2212"), pt); } - if (pdgCode == -13) { + if (pdgCode == PDG_t::kMuonPlus) { histReg.fill(HIST("contamination/013in2212"), pt); } - } else if (i == 2) { - if (pdgCode == 211) { + } else if (i == ContaminationIn::kKaon) { + if (pdgCode == PDG_t::kPiPlus) { histReg.fill(HIST("contamination/211in321"), pt); } - if (pdgCode == -211) { + if (pdgCode == PDG_t::kPiMinus) { histReg.fill(HIST("contamination/0211in321"), pt); } - if (pdgCode == 2212) { + if (pdgCode == PDG_t::kProton) { histReg.fill(HIST("contamination/2212in321"), pt); } - if (pdgCode == -2212) { + if (pdgCode == PDG_t::kProtonBar) { histReg.fill(HIST("contamination/02212in321"), pt); } - if (pdgCode == 321) { + if (pdgCode == PDG_t::kKPlus) { histReg.fill(HIST("contamination/321in321"), pt); } - if (pdgCode == -321) { + if (pdgCode == PDG_t::kKMinus) { histReg.fill(HIST("contamination/0321in321"), pt); } - if (pdgCode == 11) { + if (pdgCode == PDG_t::kElectron) { histReg.fill(HIST("contamination/11in321"), pt); } - if (pdgCode == -11) { + if (pdgCode == PDG_t::kPositron) { histReg.fill(HIST("contamination/011in321"), pt); } - if (pdgCode == 13) { + if (pdgCode == PDG_t::kMuonMinus) { histReg.fill(HIST("contamination/13in321"), pt); } - if (pdgCode == -13) { + if (pdgCode == PDG_t::kMuonPlus) { histReg.fill(HIST("contamination/013in321"), pt); } } @@ -244,34 +264,35 @@ struct pidml { template void fillMcHistos(const T& track, const int pdgCode) { - // pions - if (pdgCode == 211) { + if (pdgCode == PDG_t::kPiPlus) { + // pions histReg.fill(HIST("MC/211"), track.pt()); - } else if (pdgCode == -211) { + } else if (pdgCode == PDG_t::kPiMinus) { + // antipions histReg.fill(HIST("MC/0211"), track.pt()); - } - // protons - else if (pdgCode == 2212) { + } else if (pdgCode == PDG_t::kProton) { + // protons histReg.fill(HIST("MC/2212"), track.pt()); - } else if (pdgCode == -2212) { + } else if (pdgCode == PDG_t::kProtonBar) { + // antiprotons histReg.fill(HIST("MC/02212"), track.pt()); - } - // kaons - else if (pdgCode == 321) { + } else if (pdgCode == PDG_t::kKPlus) { + // kaons histReg.fill(HIST("MC/321"), track.pt()); - } else if (pdgCode == -321) { + } else if (pdgCode == PDG_t::kKMinus) { + // antikaons histReg.fill(HIST("MC/0321"), track.pt()); - } - // electrons - else if (pdgCode == 11) { + } else if (pdgCode == PDG_t::kElectron) { + // electrons histReg.fill(HIST("MC/11"), track.pt()); - } else if (pdgCode == -11) { + } else if (pdgCode == PDG_t::kPositron) { + // positrons histReg.fill(HIST("MC/011"), track.pt()); - } - // muons - else if (pdgCode == 13) { + } else if (pdgCode == PDG_t::kMuonMinus) { + // muons histReg.fill(HIST("MC/13"), track.pt()); - } else if (pdgCode == -13) { + } else if (pdgCode == PDG_t::kMuonPlus) { + // antimuons histReg.fill(HIST("MC/013"), track.pt()); } else { histReg.fill(HIST("MC/else"), track.pt()); @@ -282,13 +303,13 @@ struct pidml { void fillPidHistos(const T& track, const int pdgCode, bool isPidTrue) { if (isPidTrue) { - histReg.fill(HIST(pidTrueRegistryNames[i]), track.pt()); + histReg.fill(HIST(PidTrueRegistryNames[i]), track.pt()); histReg.fill(HIST(TPCPidTrueRegistryNames[i]), track.p(), track.tpcSignal()); histReg.fill(HIST("TPCSignalPidTrue"), track.p(), track.tpcSignal()); histReg.fill(HIST("TOFSignalPidTrue"), track.p(), track.beta()); histReg.fill(HIST(TOFPidTrueRegistryNames[i]), track.p(), track.beta()); } else { - histReg.fill(HIST(pidFalseRegistryNames[i]), track.pt()); + histReg.fill(HIST(PidFalseRegistryNames[i]), track.pt()); histReg.fill(HIST(TPCPidFalseRegistryNames[i]), track.p(), track.tpcSignal()); histReg.fill(HIST("TPCSignalPidFalse"), track.p(), track.tpcSignal()); histReg.fill(HIST("TOFSignalPidFalse"), track.p(), track.beta()); @@ -299,26 +320,28 @@ struct pidml { } } - int getParticlePdg(float pidCertainties[]) + static constexpr float kCertaintyThreshold = 0.5f; + + int getParticlePdg(const float pidCertainties[]) { // index of the biggest value in an array int index = 0; // index of the second biggest value in an array - int smaller_index = 0; + int smallerIndex = 0; for (int j = 1; j < numParticles; j++) { if (pidCertainties[j] > pidCertainties[index]) { // assign new indexes - smaller_index = index; + smallerIndex = index; index = j; } } // return 0 if certainty with index 'index' is below 0.5 or two indexes have the same value, else map index to particle pdgCode - if ((pidCertainties[index] < 0.5f) | ((pidCertainties[index] == pidCertainties[smaller_index]) & (smaller_index != 0))) { + if ((pidCertainties[index] < kCertaintyThreshold) | ((pidCertainties[index] == pidCertainties[smallerIndex]) & (smallerIndex != 0))) { return 0; } else { - return particlesPdgCode[index]; + return ParticlesPdgCode[index]; } } @@ -326,19 +349,13 @@ 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) { - if (pdgCodeMC == particlesPdgCode[i]) { + if (pid == ParticlesPdgCode[i] && track.sign() == 1) { + if (pdgCodeMC == ParticlesPdgCode[i]) { fillPidHistos(track, pdgCodeMC, true); } else { fillPidHistos(track, pdgCodeMC, false); @@ -346,54 +363,43 @@ 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; - - 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{"useCCDB", 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 ccdbPath{"ccdbPath", "Users/m/mkabus/PIDML", "base path to the CCDB directory with ONNX models"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; + Configurable useCcdb{"useCcdb", true, "Whether to autofetch ML model from CCDB. If false, local file will be used."}; + Configurable localPath{"localPath", "/home/mkabus/PIDML/", "base path to the local directory with ONNX models"}; o2::ccdb::CcdbApi ccdbApi; int currentRunNumber = -1; + Filter trackFilter = requireGlobalTrackInFilter(); + using PidTracks = soa::Filtered>; + + // one model for one particle + PidONNXModel model211; + PidONNXModel model2212; + PidONNXModel model321; + void init(InitContext const&) { - if (cfgUseCCDB) { - ccdbApi.init(cfgCCDBURL); + if (useCcdb) { + ccdbApi.init(ccdbUrl); } 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(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, -1, PDG_t::kPiPlus, 0.5f, PSwitchValue[0]); + model2212 = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, -1, PDG_t::kProton, 0.5f, PSwitchValue[1]); + model321 = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, -1, PDG_t::kKPlus, 0.5f, PSwitchValue[2]); } } - Filter trackFilter = requireGlobalTrackInFilter(); - using pidTracks = soa::Filtered>; - void process(aod::Collisions const& collisions, pidTracks const& tracks, aod::McParticles const& /*mcParticles*/, aod::BCsWithTimestamps const&) + void process(aod::Collisions const& collisions, PidTracks const& tracks, aod::McParticles const& /*mcParticles*/, aod::BCsWithTimestamps const&) { 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); + if (useCcdb && bc.runNumber() != currentRunNumber) { + model211 = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, bc.timestamp(), PDG_t::kPiPlus, 0.5f, PSwitchValue[0]); + model2212 = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, bc.timestamp(), PDG_t::kProton, 0.5f, PSwitchValue[1]); + model321 = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, bc.timestamp(), PDG_t::kKPlus, 0.5f, PSwitchValue[2]); } - for (auto& track : tracks) { + for (const auto& track : tracks) { auto particle = track.mcParticle_as(); int pdgCodeMC = particle.pdgCode(); @@ -410,6 +416,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..268b0609c25 100644 --- a/Tools/PIDML/simpleApplyPidOnnxInterface.cxx +++ b/Tools/PIDML/simpleApplyPidOnnxInterface.cxx @@ -9,19 +9,30 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file simpleApplyPidInterface +/// \file simpleApplyPidOnnxInterface.cxx /// \brief A simple example for using PID obtained from the PID ML ONNX Interface. See README.md for more detailed instructions. /// /// \author Maja Kabus -#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/pidOnnxInterface.h" +// +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include +#include using namespace o2; using namespace o2::framework; @@ -38,21 +49,19 @@ DECLARE_SOA_COLUMN(Accepted, accepted, bool); //! Whether the model accepted par DECLARE_SOA_TABLE(MlPidResults, "AOD", "MLPIDRESULTS", o2::soa::Index<>, mlpidresult::TrackId, mlpidresult::Pid, mlpidresult::Accepted); } // namespace o2::aod -struct SimpleApplyOnnxInterface { - PidONNXInterface pidInterface; // One instance to manage all needed ONNX models +struct SimpleApplyPidOnnxInterface { + Configurable> ptCuts{"ptCuts", {pidml_pt_cuts::Cuts[0], pidml_pt_cuts::NPids, pidml_pt_cuts::NCutVars, pidml_pt_cuts::pidLabels, pidml_pt_cuts::cutVarLabels}, "pT cuts for each output pid and each detector configuration"}; + Configurable> pdgPids{"pdgPids", std::vector{pidml_pt_cuts::pidsV}, "PIDs to predict"}; + Configurable> mlIdentCertaintyThresholds{"mlIdentCertaintyThresholds", std::vector{pidml_pt_cuts::certaintiesV}, "Min certainties of the models to accept given particle to be of given kind"}; + Configurable autoMode{"autoMode", true, "Use automatic model matching: default pT cuts and min certainties"}; - Configurable> cfgPTCuts{"pT_cuts", {pidml_pt_cuts::cuts[0], pidml_pt_cuts::nPids, pidml_pt_cuts::nCutVars, pidml_pt_cuts::pidLabels, pidml_pt_cuts::cutVarLabels}, "pT cuts for each output pid and each detector configuration"}; - Configurable> cfgPids{"pids", std::vector{pidml_pt_cuts::pids_v}, "PIDs to predict"}; - Configurable> cfgCertainties{"certainties", std::vector{pidml_pt_cuts::certainties_v}, "Min certainties of the models to accept given particle to be of given kind"}; - Configurable cfgAutoMode{"autoMode", true, "Use automatic model matching: default pT cuts and min certainties"}; + Configurable ccdbPath{"ccdbPath", "Users/m/mkabus/PIDML", "base path to the CCDB directory with ONNX models"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; + Configurable useCcdb{"useCcdb", true, "Whether to autofetch ML model from CCDB. If false, local file will be used."}; + Configurable localPath{"localPath", "/home/mkabus/PIDML/", "base path to the local directory with ONNX models"}; - 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{"useCCDB", 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"}; + Configurable useFixedTimestamp{"useFixedTimestamp", false, "Whether to use fixed timestamp from configurable instead of timestamp calculated from the data"}; + Configurable fixedTimestamp{"fixedTimestamp", 1524176895000, "Hardcoded timestamp for tests"}; o2::ccdb::CcdbApi ccdbApi; int currentRunNumber = -1; @@ -65,25 +74,27 @@ struct SimpleApplyOnnxInterface { // Filter on isGlobalTrack (TracksSelection) using BigTracks = soa::Filtered>; + PidONNXInterface pidInterface; // One instance to manage all needed ONNX models + void init(InitContext const&) { - if (cfgUseCCDB) { - ccdbApi.init(cfgCCDBURL); + if (useCcdb) { + ccdbApi.init(ccdbUrl); } else { - pidInterface = PidONNXInterface(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, cfgPids.value, cfgPTCuts.value, cfgCertainties.value, cfgAutoMode.value); + pidInterface = PidONNXInterface(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, -1, pdgPids.value, ptCuts.value, mlIdentCertaintyThresholds.value, autoMode.value); } } void processCollisions(aod::Collisions const& collisions, BigTracks const& tracks, aod::BCsWithTimestamps const&) { auto bc = collisions.iteratorAt(0).bc_as(); - if (cfgUseCCDB && bc.runNumber() != currentRunNumber) { - uint64_t timestamp = cfgUseFixedTimestamp ? cfgTimestamp.value : bc.timestamp(); - pidInterface = PidONNXInterface(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, timestamp, cfgPids.value, cfgPTCuts.value, cfgCertainties.value, cfgAutoMode.value); + if (useCcdb && bc.runNumber() != currentRunNumber) { + uint64_t timestamp = useFixedTimestamp ? fixedTimestamp.value : bc.timestamp(); + pidInterface = PidONNXInterface(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, timestamp, pdgPids.value, ptCuts.value, mlIdentCertaintyThresholds.value, autoMode.value); } - for (auto& track : tracks) { - for (int pid : cfgPids.value) { + for (const auto& track : tracks) { + for (const int& pid : pdgPids.value) { bool accepted = pidInterface.applyModelBoolean(track, pid); LOGF(info, "collision id: %d track id: %d pid: %d accepted: %d p: %.3f; x: %.3f, y: %.3f, z: %.3f", track.collisionId(), track.index(), pid, accepted, track.p(), track.x(), track.y(), track.z()); @@ -91,12 +102,12 @@ struct SimpleApplyOnnxInterface { } } } - PROCESS_SWITCH(SimpleApplyOnnxInterface, processCollisions, "Process with collisions and bcs for CCDB", true); + PROCESS_SWITCH(SimpleApplyPidOnnxInterface, processCollisions, "Process with collisions and bcs for CCDB", true); void processTracksOnly(BigTracks const& tracks) { - for (auto& track : tracks) { - for (int pid : cfgPids.value) { + for (const auto& track : tracks) { + for (const int& pid : pdgPids.value) { bool accepted = pidInterface.applyModelBoolean(track, pid); LOGF(info, "collision id: %d track id: %d pid: %d accepted: %d p: %.3f; x: %.3f, y: %.3f, z: %.3f", track.collisionId(), track.index(), pid, accepted, track.p(), track.x(), track.y(), track.z()); @@ -104,11 +115,11 @@ struct SimpleApplyOnnxInterface { } } } - PROCESS_SWITCH(SimpleApplyOnnxInterface, processTracksOnly, "Process with tracks only -- faster but no CCDB", false); + PROCESS_SWITCH(SimpleApplyPidOnnxInterface, processTracksOnly, "Process with tracks only -- faster but no CCDB", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/Tools/PIDML/simpleApplyPidOnnxModel.cxx b/Tools/PIDML/simpleApplyPidOnnxModel.cxx index 00dc843ca47..57316713f03 100644 --- a/Tools/PIDML/simpleApplyPidOnnxModel.cxx +++ b/Tools/PIDML/simpleApplyPidOnnxModel.cxx @@ -9,18 +9,27 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file simpleApplyPidModel +/// \file simpleApplyPidOnnxModel.cxx /// \brief A simple example for using PID obtained from the PID ML ONNX Model. See README.md for more detailed instructions. /// /// \author Maja Kabus -#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 "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include using namespace o2; @@ -38,19 +47,17 @@ DECLARE_SOA_COLUMN(Accepted, accepted, bool); //! Whether the model accepted par DECLARE_SOA_TABLE(MlPidResults, "AOD", "MLPIDRESULTS", o2::soa::Index<>, mlpidresult::TrackId, mlpidresult::Pid, mlpidresult::Accepted); } // namespace o2::aod -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"}; +struct SimpleApplyPidOnnxModel { + Configurable pdgPid{"pdgPid", 211, "PID to predict"}; + Configurable certainty{"certainty", 0.5, "Min certainty of the model to accept given particle 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{"useCCDB", 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 ccdbPath{"ccdbPath", "Users/m/mkabus/PIDML", "base path to the CCDB directory with ONNX models"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "URL of the CCDB repository"}; + Configurable useCcdb{"useCcdb", true, "Whether to autofetch ML model from CCDB. If false, local file will be used."}; + Configurable localPath{"localPath", "/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"}; + Configurable useFixedTimestamp{"useFixedTimestamp", false, "Whether to use fixed timestamp from configurable instead of timestamp calculated from the data"}; + Configurable fixedTimestamp{"fixedTimestamp", 1524176895000, "Hardcoded timestamp for tests"}; o2::ccdb::CcdbApi ccdbApi; int currentRunNumber = -1; @@ -62,47 +69,48 @@ struct SimpleApplyOnnxModel { // TPC signal (FullTracks), TOF signal (TOFSignal), TOF beta (pidTOFbeta), dcaXY and dcaZ (TracksDCA) // Filter on isGlobalTrack (TracksSelection) using BigTracks = soa::Filtered>; + PidONNXModel pidModel; // One instance per model, e.g., one per each pid to predict void init(InitContext const&) { - if (cfgUseCCDB) { - ccdbApi.init(cfgCCDBURL); + if (useCcdb) { + ccdbApi.init(ccdbUrl); } else { - pidModel = PidONNXModel(cfgPathLocal.value, cfgPathCCDB.value, cfgUseCCDB.value, ccdbApi, -1, cfgPid.value, static_cast(cfgDetector.value), cfgCertainty.value); + pidModel = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, -1, pdgPid.value, certainty.value); } } void processCollisions(aod::Collisions const& collisions, BigTracks const& tracks, aod::BCsWithTimestamps const&) { 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); + if (useCcdb && bc.runNumber() != currentRunNumber) { + uint64_t timestamp = useFixedTimestamp ? fixedTimestamp.value : bc.timestamp(); + pidModel = PidONNXModel(localPath.value, ccdbPath.value, useCcdb.value, ccdbApi, timestamp, pdgPid.value, certainty.value); } - for (auto& track : tracks) { + for (const auto& track : tracks) { bool accepted = pidModel.applyModelBoolean(track); LOGF(info, "collision id: %d track id: %d accepted: %d p: %.3f; x: %.3f, y: %.3f, z: %.3f", track.collisionId(), track.index(), accepted, track.p(), track.x(), track.y(), track.z()); - pidMLResults(track.index(), cfgPid.value, accepted); + pidMLResults(track.index(), pdgPid.value, accepted); } } - PROCESS_SWITCH(SimpleApplyOnnxModel, processCollisions, "Process with collisions and bcs for CCDB", true); + PROCESS_SWITCH(SimpleApplyPidOnnxModel, processCollisions, "Process with collisions and bcs for CCDB", true); void processTracksOnly(BigTracks const& tracks) { - for (auto& track : tracks) { + for (const auto& track : tracks) { bool accepted = pidModel.applyModelBoolean(track); LOGF(info, "collision id: %d track id: %d accepted: %d p: %.3f; x: %.3f, y: %.3f, z: %.3f", track.collisionId(), track.index(), accepted, track.p(), track.x(), track.y(), track.z()); - pidMLResults(track.index(), cfgPid.value, accepted); + pidMLResults(track.index(), pdgPid.value, accepted); } } - PROCESS_SWITCH(SimpleApplyOnnxModel, processTracksOnly, "Process with tracks only -- faster but no CCDB", false); + PROCESS_SWITCH(SimpleApplyPidOnnxModel, processTracksOnly, "Process with tracks only -- faster but no CCDB", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } 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..aad14571c2d 100644 --- a/Tutorials/ML/applyMlSelection.cxx +++ b/Tutorials/ML/applyMlSelection.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2023 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,18 +11,19 @@ /// \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 +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" + +#include "Tools/ML/MlResponse.h" + #include "Framework/AnalysisTask.h" #include "Framework/HistogramRegistry.h" #include "Framework/runDataProcessing.h" -#include "Tools/ML/MlResponse.h" -#include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" - using namespace o2; using namespace o2::analysis; using namespace o2::framework; @@ -39,13 +40,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); @@ -113,26 +114,12 @@ struct applyMlSelection { // Retrieve model output and selection outcome // Fill BDT score histograms before selection - registry.fill(HIST("hPromptScoreBeforeSel"), outputMl[0]); // Fill histograms for selected candidates - bool isSelectedMlPiKK = true; - if (isSelectedMlPiKK) { - registry.fill(HIST("hMassAfterSelVsPt"), hfHelper.invMassDsToPiKK(candidate), candidate.pt()); - registry.fill(HIST("hPromptScoreAfterSelVsPt"), outputMl[0], candidate.pt()); - } outputMl.clear(); // not necessary in this case but for good measure // Perform ML selections for other mass hypothesis (Ds -> PhiPi -> KKPi) - std::vector inputFeaturesKKPi{candidate.cpa(), - candidate.cpaXY(), - candidate.decayLength(), - candidate.decayLengthXY(), - static_cast(hfHelper.deltaMassPhiDsToKKPi(candidate)), - candidate.impactParameterXY(), - static_cast(hfHelper.cos3PiKDsToKKPi(candidate)), - candidate.maxNormalisedDeltaIP()}; // Retrieve model output and selection outcome 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/ML/run_applyMlSelection.sh b/Tutorials/ML/run_applyMlSelection.sh index fe85f857771..8df339186ff 100755 --- a/Tutorials/ML/run_applyMlSelection.sh +++ b/Tutorials/ML/run_applyMlSelection.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2019-2023 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. # 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..bf15a1a13c9 --- /dev/null +++ b/Tutorials/PWGCF/EventPlane/src/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does 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) + +o2physics_add_dpl_workflow(spectator-plane-tutorial + SOURCES spectatorPlaneTutorial.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/EventPlane/src/spectatorPlaneTutorial.cxx b/Tutorials/PWGCF/EventPlane/src/spectatorPlaneTutorial.cxx new file mode 100644 index 00000000000..6790dd30ae5 --- /dev/null +++ b/Tutorials/PWGCF/EventPlane/src/spectatorPlaneTutorial.cxx @@ -0,0 +1,237 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file SpectatorPlaneTutorial.cxx +/// \author Noor Koster +/// \since 11/2025 +/// \brief This is a tutorial task to show how to use the ZDC q-vectors and the spectator plane resolution. + +#include "PWGCF/DataModel/SPTableZDC.h" + +#include "Common/Core/EventPlaneHelper.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/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/runDataProcessing.h" + +#include "TF1.h" +#include "TPDGCode.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; +// using namespace o2::analysis; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct SpectatorPlaneTutorial { + RCTFlagsChecker rctChecker; + + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgEvtUseRCTFlagChecker, bool, false, "Evt sel: use RCT flag checker"); + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerLabel, std::string, "CBT_hadronPID", "Evt sel: RCT flag checker label (CBT, CBT_hadronPID)"); // all Labels can be found in Common/CCDB/RCTSelectionFlags.h + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerZDCCheck, bool, false, "Evt sel: RCT flag checker ZDC check"); + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerLimitAcceptAsBad, bool, false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"); + } rctFlags; + + // settings for CCDB data + O2_DEFINE_CONFIGURABLE(cfgCCDBdir_QQ, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5/meanQQ/Default", "ccdb dir for average QQ values in 1% centrality bins"); + O2_DEFINE_CONFIGURABLE(cfgCCDBdir_SP, std::string, "Users/c/ckoster/ZDC/LHC23_zzh_pass4/SPPlaneRes", "ccdb dir for average event plane resolution in 1% centrality bins"); + // Confogirable axis + ConfigurableAxis axisCentrality{"axisCentrality", {20, 0, 100}, "Centrality bins for vn "}; + + // Configurables containing vector + float vtxZ = 10.0; + float etaMax = 0.8; + float ptMin = 0.2; + float ptMax = 10.0; + float dcaXYMax = 0.2; + float dcaZMax = 2.0; + + Filter collisionFilter = nabs(aod::collision::posZ) < vtxZ; + Filter trackFilter = nabs(aod::track::eta) < etaMax && aod::track::pt > ptMin&& aod::track::pt < ptMax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && nabs(aod::track::dcaXY) < dcaXYMax&& nabs(aod::track::dcaZ) < dcaZMax; + using GeneralCollisions = soa::Join; + using UnfilteredTracks = soa::Join; + + using UsedTracks = soa::Filtered; + using ZDCCollisions = soa::Filtered>; // IMPORTANT: ZDCCollisions must be used to get access to ZDC q-vectors --> PWGCF/DataModel/SPTableZDC.h & PWGCF/Flow/TableProducer/zdcQVectors.cxx + + // Connect to ccdb + Service ccdb; + + HistogramRegistry registry{"registry"}; + + 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 axisPhi = {60, 0, constants::math::TwoPI, "#varphi"}; + AxisSpec axisEta = {64, -1.6, 1.6, "#eta"}; + AxisSpec axisEtaVn = {8, -.8, .8, "#eta"}; + AxisSpec axisCent = {90, 0, 90, "Centrality(%)"}; + AxisSpec axisPhiPlane = {100, -constants::math::PI, constants::math::PI, "#Psi"}; + AxisSpec axisQQ = {100, -0.2, 0.2, "#LT Q_{X}^{A}Q_{Y}^{C} #GT"}; + + 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}"}; + + rctChecker.init(rctFlags.cfgEvtRCTFlagCheckerLabel, rctFlags.cfgEvtRCTFlagCheckerZDCCheck, rctFlags.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + registry.add("hCentrality", "Centrality; #Events; Centrality (%)", {HistType::kTH1D, {axisCent}}); + registry.add("hSPplaneA", "Spectator Plane Angle A; #Events; #Psi_{A}", {HistType::kTH1D, {axisPhiPlane}}); + registry.add("qAqCXY", "Qx ZDCA x Qy ZDCC vs cent ; #ltQ_{X}^{A}Q_{Y}^{C}#GT; Centrality (%)", {HistType::kTH2D, {axisCent, axisQQ}}); + // Add here the histograms for the spectator plane angle C + // registry.add(.........) + registry.add("hSPplaneAvsC", "Spectator Plane Angle A vs C; #Events; #Psi_{A}; #Psi_{C}", {HistType::kTH2D, {axisPhiPlane, axisPhiPlane}}); + registry.add("hSPplaneFull", "Spectator Plane Angle Full; #Events; #Psi_{Full}", {HistType::kTH1D, {axisPhiPlane}}); + + // Note: we will fill these with data from the CCDB, just to take a look! + registry.add("CalibHistos/hQQx", "QQx; #Events; QQx", {HistType::kTProfile, {axisCent}}); + registry.add("CalibHistos/hQQy", "QQy; #Events; QQy", {HistType::kTProfile, {axisCent}}); + registry.add("CalibHistos/hQQ", "QQ; #Events; QQx + QQy", {HistType::kTProfile, {axisCent}}); + // Add here the histograms for the cross-terms of the Q-vectors from the ZDC + + registry.add("CalibHistos/hEvPlaneRes", "Event Plane Resolution; #Events; Event Plane Resolution", {HistType::kTProfile, {axisCent}}); + + // Flow Histograms + registry.add("flow/v1A", "", {HistType::kTProfile, {axisPt}}); + registry.add("flow/v1C", "", {HistType::kTProfile, {axisPt}}); + + registry.add("flow/vnAxCxUxMH", "", {HistType::kTProfile, {axisCent}}); + registry.add("flow/vnAyCyUxMH", "", {HistType::kTProfile, {axisCent}}); + registry.add("flow/vnAxCyUyMH", "", {HistType::kTProfile, {axisCent}}); + registry.add("flow/vnAyCxUyMH", "", {HistType::kTProfile, {axisCent}}); + } + + void process(ZDCCollisions::iterator const& collision, aod::BCsWithTimestamps const&, UsedTracks const& tracks) + { + + auto bc = collision.bc_as(); + + float centrality = collision.centFT0C(); + registry.fill(HIST("hCentrality"), centrality); + + float centMin = 0; + float centMax = 80; + + if (centrality > centMax || centrality < centMin) + return; + + if (collision.isSelected() == false) + return; + + // Get the ZDC q-vectors + double qxA = collision.qxA(); + double qyA = collision.qyA(); + double qxC = collision.qxC(); + double qyC = collision.qyC(); + + // Calculate the spectator plane angles + double psiA = 1.0 * std::atan2(qyA, qxA); + registry.fill(HIST("hSPplaneA"), psiA); + + // Add the PsiA vs PsiC as a TH2D + + double psiC = 1.0 * std::atan2(qyC, qxC); + double psiFull = 1.0 * std::atan2(qyA + qyC, qxA + qxC); + registry.fill(HIST("hSPplaneFull"), psiFull); + + registry.fill(HIST("hSPplaneAvsC"), psiA, psiC); + + // Fill the q-vector correlations + registry.fill(HIST("qAqCXY"), centrality, qxA * qxC + qyA * qyC); + + double corrQQx = 1; + double corrQQy = 1; + double corrQQ = 1; + double evPlaneRes = 1; + + // Get QQ-correlations from CCDB + if (cfgCCDBdir_QQ.value.empty() == false) { + TList* list = ccdb->getForTimeStamp(cfgCCDBdir_QQ.value, bc.timestamp()); + TProfile* qAqCX = reinterpret_cast(list->FindObject("qAqCX")); + TProfile* qAqCY = reinterpret_cast(list->FindObject("qAqCY")); + TProfile* qAqCXY = reinterpret_cast(list->FindObject("qAqCXY")); + // The sum is qAqCXY + corrQQx = qAqCX->GetBinContent(centrality); + corrQQy = qAqCY->GetBinContent(centrality); + corrQQ = qAqCXY->GetBinContent(centrality); + registry.fill(HIST("CalibHistos/hQQx"), centrality, corrQQx); + registry.fill(HIST("CalibHistos/hQQy"), centrality, corrQQy); + registry.fill(HIST("CalibHistos/hQQ"), centrality, corrQQ); + } + // Get event plane resolution from CCDB + if (cfgCCDBdir_SP.value.empty() == false) { + evPlaneRes = ccdb->getForTimeStamp(cfgCCDBdir_SP.value, bc.timestamp())->GetBinContent(centrality); + registry.fill(HIST("CalibHistos/hEvPlaneRes"), centrality, evPlaneRes); + } + + for (const auto& track : tracks) { + + // constrain angle to 0 -> [0,0+2pi] + auto phi = RecoDecay::constrainAngle(track.phi(), 0); + + double ux = std::cos(phi); + double uy = std::sin(phi); + + double uxMH = std::cos(2 * phi); + double uyMH = std::sin(2 * phi); + + double v1A = (uy * qyA + ux * qxA) / std::sqrt(std::fabs(corrQQ)); + double v1C = (uy * qyC + ux * qxC) / std::sqrt(std::fabs(corrQQ)); + + double v2AxCxUxMH = (uxMH * qxA * qxC) / corrQQx; + double v2AyCyUxMH = (uxMH * qyA * qyC) / corrQQy; + double v2AxCyUyMH = (uyMH * qxA * qyC) / corrQQx; + double v2AyCxUyMH = (uyMH * qyA * qxC) / corrQQy; + + registry.fill(HIST("flow/v1A"), track.eta(), v1A); + registry.fill(HIST("flow/v1C"), track.eta(), v1C); + + registry.fill(HIST("flow/v2AxCxUxMH"), centrality, v2AxCxUxMH); + registry.fill(HIST("flow/v2AyCyUxMH"), centrality, v2AyCyUxMH); + registry.fill(HIST("flow/v2AxCyUyMH"), centrality, v2AxCyUyMH); + registry.fill(HIST("flow/v2AyCxUyMH"), centrality, v2AyCxUyMH); + } + } +}; + +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/PWGEM/pcm/CMakeLists.txt b/Tutorials/PWGEM/pcm/CMakeLists.txt index e2863ae717b..72b4616ef2d 100644 --- a/Tutorials/PWGEM/pcm/CMakeLists.txt +++ b/Tutorials/PWGEM/pcm/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019-2023 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. # diff --git a/Tutorials/PWGEM/pcm/pcmtutorial.cxx b/Tutorials/PWGEM/pcm/pcmtutorial.cxx index 1550f30ebeb..c10b4251991 100644 --- a/Tutorials/PWGEM/pcm/pcmtutorial.cxx +++ b/Tutorials/PWGEM/pcm/pcmtutorial.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2023 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. // diff --git a/Tutorials/PWGHF/DataModelMini.h b/Tutorials/PWGHF/DataModelMini.h index 40a430a4813..bbd1bdad009 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 @@ -17,7 +17,12 @@ #ifndef TUTORIALS_PWGHF_DATAMODELMINI_H_ #define TUTORIALS_PWGHF_DATAMODELMINI_H_ -#include "Framework/AnalysisDataModel.h" +#include "Common/Core/RecoDecay.h" + +#include +#include + +#include namespace o2::aod { @@ -28,7 +33,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 +44,8 @@ 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 prong indices + o2::soa::Index<>, hf_track_index::Prong0Id, hf_track_index::Prong1Id); @@ -48,43 +54,44 @@ namespace hf_cand_prong2 { // Candidate columns // collision properties -DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! collisions +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! collision // secondary vertex -DECLARE_SOA_COLUMN(XSecondaryVertex, xSecondaryVertex, float); //! x coordinate of the secondary vertex -DECLARE_SOA_COLUMN(YSecondaryVertex, ySecondaryVertex, float); //! y coordinate of the secondary vertex -DECLARE_SOA_COLUMN(ZSecondaryVertex, zSecondaryVertex, float); //! z coordinate of the secondary vertex -DECLARE_SOA_DYNAMIC_COLUMN(RSecondaryVertex, rSecondaryVertex, //! radius of the secondary vertex +DECLARE_SOA_COLUMN(XSecondaryVertex, xSecondaryVertex, float); //! x coordinate of the secondary vertex [cm] +DECLARE_SOA_COLUMN(YSecondaryVertex, ySecondaryVertex, float); //! y coordinate of the secondary vertex [cm] +DECLARE_SOA_COLUMN(ZSecondaryVertex, zSecondaryVertex, float); //! z coordinate of the secondary vertex [cm] +DECLARE_SOA_DYNAMIC_COLUMN(RSecondaryVertex, rSecondaryVertex, //! radius of the secondary vertex [cm] [](float xVtxS, float yVtxS) -> float { return RecoDecay::sqrtSumOfSquares(xVtxS, yVtxS); }); // prong properties -DECLARE_SOA_COLUMN(PxProng0, pxProng0, float); //! px of prong 0 -DECLARE_SOA_COLUMN(PyProng0, pyProng0, float); //! py of prong 0 -DECLARE_SOA_COLUMN(PzProng0, pzProng0, float); //! pz of prong 0 -DECLARE_SOA_DYNAMIC_COLUMN(PtProng0, ptProng0, //! pt of prong 0 +DECLARE_SOA_COLUMN(PxProng0, pxProng0, float); //! px of prong 0 [GeV/c] +DECLARE_SOA_COLUMN(PyProng0, pyProng0, float); //! py of prong 0 [GeV/c] +DECLARE_SOA_COLUMN(PzProng0, pzProng0, float); //! pz of prong 0 [GeV/c] +DECLARE_SOA_DYNAMIC_COLUMN(PtProng0, ptProng0, //! pt of prong 0 [GeV/c] [](float px, float py) -> float { return RecoDecay::pt(px, py); }); -DECLARE_SOA_COLUMN(PxProng1, pxProng1, float); //! px of prong 1 -DECLARE_SOA_COLUMN(PyProng1, pyProng1, float); //! py of prong 1 -DECLARE_SOA_COLUMN(PzProng1, pzProng1, float); //! pz of prong 1 -DECLARE_SOA_DYNAMIC_COLUMN(PtProng1, ptProng1, //! pt of prong 1 +DECLARE_SOA_COLUMN(PxProng1, pxProng1, float); //! px of prong 1 [GeV/c] +DECLARE_SOA_COLUMN(PyProng1, pyProng1, float); //! py of prong 1 [GeV/c] +DECLARE_SOA_COLUMN(PzProng1, pzProng1, float); //! pz of prong 1 [GeV/c] +DECLARE_SOA_DYNAMIC_COLUMN(PtProng1, ptProng1, //! pt of prong 1 [GeV/c] [](float px, float py) -> float { return RecoDecay::pt(px, py); }); // candidate properties -DECLARE_SOA_DYNAMIC_COLUMN(DecayLength, decayLength, //! decay length of candidate +DECLARE_SOA_DYNAMIC_COLUMN(DecayLength, decayLength, //! decay length of candidate [cm] [](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(Pt, pt, //! pt of candidate +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! pt of candidate [GeV/c] [](float px, float py) -> float { return RecoDecay::pt(px, py); }); -DECLARE_SOA_EXPRESSION_COLUMN(Px, px, //! px of candidate +DECLARE_SOA_EXPRESSION_COLUMN(Px, px, //! px of candidate [GeV/c] float, 1.f * pxProng0 + 1.f * pxProng1); -DECLARE_SOA_EXPRESSION_COLUMN(Py, py, //! py of candidate +DECLARE_SOA_EXPRESSION_COLUMN(Py, py, //! py of candidate [GeV/c] float, 1.f * pyProng0 + 1.f * pyProng1); -DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, //! pz of candidate +DECLARE_SOA_EXPRESSION_COLUMN(Pz, pz, //! pz of candidate [GeV/c] float, 1.f * pzProng0 + 1.f * pzProng1); -DECLARE_SOA_DYNAMIC_COLUMN(M, m, //! invariant mass of candidate +DECLARE_SOA_DYNAMIC_COLUMN(M, m, //! invariant mass of candidate [GeV/c^2] [](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 + o2::soa::Index<>, hf_cand_prong2::CollisionId, collision::PosX, collision::PosY, collision::PosZ, hf_cand_prong2::XSecondaryVertex, hf_cand_prong2::YSecondaryVertex, hf_cand_prong2::ZSecondaryVertex, @@ -98,24 +105,24 @@ 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 { // Candidate selection columns DECLARE_SOA_COLUMN(IsSelD0, isSelD0, int); //! selection flag for D0 -DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int); //! selection flag for D0 bar +DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int); //! selection flag for D0bar } // 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/README.md b/Tutorials/PWGHF/README.md index 47fe9b47805..ad9d43607d5 100644 --- a/Tutorials/PWGHF/README.md +++ b/Tutorials/PWGHF/README.md @@ -4,63 +4,73 @@ Welcome to the heavy-flavour analysis tutorial! -This directory contains the code and configuration for running a minimalistic version of the D0 analysis on Run 3 real data. +This directory contains the code and configuration for running a minimalistic version of the D0 analysis on Run 3 data. -See the [official PWG-HF O2 documentation](https://aliceo2group.github.io/analysis-framework/docs/advanced-specifics/pwghf.html) for the overview of the full heavy-flavour analysis framework. +See the [PWG-HF O2 documentation](https://aliceo2group.github.io/analysis-framework/docs/advanced-specifics/pwghf.html) for the overview of the full heavy-flavour analysis framework. ## Setup -1. Create a dedicated working directory on your device. - This is the directory, where you will put your input files, run the code and produce the output files, so it is a good idea to have it outside the O2Physics repository. -2. Put the input file(s) `AO2D.root` (and `AnalysisResults_trees.root`) in the working directory. -3. Load the O2Physics environment. +1. Create and enter a dedicated working directory on your device. + This is the directory, where you will put your input files, run the code, and produce the output files, so it is a good idea to have it outside the O2Physics repository. +1. Put the input file(s) `AO2D.root` (and `AnalysisResults_trees.root`) in the working directory (or in a dedicated directory for input data). +1. Copy the [`input_skim.txt`](input_skim.txt) and [`input_task.txt`](input_task.txt) files into the working directory and adjust the paths inside if needed. +1. Load the O2Physics environment. ## Skim production -The file `AnalysisResults_trees.root` contains a derived table with track index skims of 2-prong decay candidates. -This table contains paired track indices which point to the track table in the parent `AO2D.root` file. -It is produced from the `AO2D.root` file by a dedicated workflow `o2-analysistutorial-hf-skim-creator-mini` (implemented in [`skimCreatorMini.cxx`](skimCreatorMini.cxx)). +The mini skim creator workflow `o2-analysistutorial-hf-skim-creator-mini` (implemented in [`skimCreatorMini.cxx`](skimCreatorMini.cxx)) is a simplified version of the `o2-analysis-hf-track-index-skim-creator` workflow (implemented in [`trackIndexSkimCreator.cxx`](https://github.com/AliceO2Group/O2Physics/blob/master/PWGHF/TableProducer/trackIndexSkimCreator.cxx)) which is used for the central production of linked derived data for all HF analyses and which performs: -If you need to produce these derived skims, you can do that by executing the [`run_skim.sh`](run_skim.sh) bash script in the working directory: +- the HF event selection, +- the HF secondary-track selection, +- the HF secondary-vertex reconstruction and loose selection of found HF decay candidates. + +The mini skim creator processes the `AO2D.root` file(s) and produces a derived table [`HfT2Prongs`](DataModelMini.h) with track index skims of 2-prong decay candidates. +This table contains paired track indices which point to tracks in the track table in the parent `AO2D.root` file. + +These derived skims are produced by executing the [`run_skim.sh`](run_skim.sh) bash script in the working directory: ```bash -bash ~/alice/O2Physics/Tutorials/PWGHF/run_skim.sh +~/alice/O2Physics/Tutorials/PWGHF/run_skim.sh ``` -It will use the configuration from [`dpl-config_skim.json`](dpl-config_skim.json). +It processes files specified in `./input_skim.txt`, uses the configuration from [`dpl-config_skim.json`](dpl-config_skim.json), and produces the `./AnalysisResults_trees.root` file with the derived table and the `./AnalysisResults.root` file with control histograms. ## Mini task The mini task workflow `o2-analysistutorial-hf-task-mini` (implemented in [`taskMini.cxx`](taskMini.cxx)) is a simplified version of the D0 analysis chain part which includes: -- the 2-prong candidate creator, -- the D0 candidate selector, -- the D0 analysis task. +- the 2-prong candidate creator (for the full candidate reconstruction), +- the D0 candidate selector (for the candidate selection), +- the D0 analysis task (for the analysis of selected candidates and filling of output histograms). The first step (candidate creator) consumes the track index skim table and therefore needs the derived `AnalysisResults_trees.root` file as input. Processing the derived file requires access to the parent `AO2D.root` file. -The absolute path to the parent file is stored in the derived file but it can be overridden with the parameter `aod-parent-base-path-replacement` in the JSON configuration, -where one has to provide a replacement mask in the format `"old-path-to-parent;new-path-to-parent"`. +The absolute path to the parent file is stored in the derived file but it can be overridden with the command line parameter `--aod-parent-base-path-replacement "old-path-to-parent;new-path-to-parent"`. (If the parent and the derived files are both in the same directory, `new-path-to-parent` can be empty.) Run the mini task by executing the [`run_task.sh`](run_task.sh) bash script in the working directory: ```bash -bash ~/alice/O2Physics/Tutorials/PWGHF/run_task.sh +~/alice/O2Physics/Tutorials/PWGHF/run_task.sh ``` -It will use the configuration from [`dpl-config_task.json`](dpl-config_task.json) and produce the output file `AnalysisResults.root` with histograms in the working directory. +It processes files specified in `./input_task.txt`, uses the configuration from [`dpl-config_task.json`](dpl-config_task.json), and produces the `./AnalysisResults.root` file with histograms. -### Exercise tips +## Exercise tips -Organise your working environment so that you can easily switch between running the code in the working directory and modifying the code in the O2Physics repository. +Organise your working environment so that you can easily switch between running the code in the working directory, +modifying the code in the O2Physics repository, and recompiling the modified code in the build directory. -When you execute the bash script, the terminal output is saved in the `stdout.log` log file in the working directory. +When you execute the bash script, the terminal output is saved in the `./stdout.log` log file. If an error occurs, the script will report the non-zero exit code and ask you to check the log file to find the problem. +If you get errors that have to be tolerated, you need to remove the `--min-failure-level error` option from the command. + +The full O2 configuration is dumped at the end of processing into the `./dpl-config.json` file. +It is useful to compare it with the input configuration file to spot mismatches. -The full O2 configuration is dumped at the end of processing into the `dpl-config.json` file in the working directory. +See the [rebuilding instructions](https://aliceo2group.github.io/analysis-framework/docs/gettingstarted/installing.html#building-partially-for-development-using-ninja) in the analysis framework documentation for advice on compiling your code changes. -See the [rebuilding instructions](https://aliceo2group.github.io/analysis-framework/docs/gettingstarted/installing.html#building-partially-for-development-using-ninja) in the official O2 analysis framework documentation for advice on compiling your code changes. +See the [Troubleshooting](https://aliceo2group.github.io/analysis-framework/docs/troubleshooting/) section of the analysis framework documentation for debugging advice. -See the [Troubleshooting](https://aliceo2group.github.io/analysis-framework/docs/troubleshooting/) section of the official O2 analysis framework documentation for debugging advice. +Consider using the [Shell rc utilities](https://aliceo2group.github.io/analysis-framework/docs/tools/#shell-rc-utilities) for easier recompilation and debugging. diff --git a/Tutorials/PWGHF/dpl-config_skim.json b/Tutorials/PWGHF/dpl-config_skim.json index 07d172b2c9d..d2c5278a145 100644 --- a/Tutorials/PWGHF/dpl-config_skim.json +++ b/Tutorials/PWGHF/dpl-config_skim.json @@ -1,34 +1,477 @@ { "internal-dpl-clock": "", "internal-dpl-aod-reader": { + "aod-file-private": "@input_skim.txt", + "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": { - "verbose": "false", - "rct-path": "RCT/Info/RunInformation", - "orbit-reset-path": "CTP/Calib/OrbitReset", - "ccdb-url": "http://alice-ccdb.cern.ch", - "isRun2MC": "false" + "internal-dpl-aod-index-builder": "", + "mc-collision-converter": "", + "tracks-extra-v002-converter": { + "processV000ToV002": "false", + "processV001ToV002": "true" }, - "tracks-extra-converter": "", - "zdc-converter": "", - "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", - "processStandard": "false", - "processCovariance": "true" + "tracks-extra-spawner": "", + "eventselection-run3": { + "timestamp": { + "verbose": "false", + "fatalOnInvalidTimestamp": "false", + "rct-path": "RCT/Info/RunInformation", + "orbit-reset-path": "CTP/Calib/OrbitReset", + "isRun2MC": "-1" + }, + "bcselOpts": { + "amIneeded": "-1", + "triggerBcShift": "0", + "ITSROFrameStartBorderMargin": "-1", + "ITSROFrameEndBorderMargin": "-1", + "TimeFrameStartBorderMargin": "-1", + "TimeFrameEndBorderMargin": "-1", + "checkRunDurationLimits": "false", + "maxInactiveChipsPerLayer": { + "values": [ + "8", + "8", + "8", + "111", + "111", + "195", + "195" + ] + }, + "NumberOfOrbitsPerTF": "-1" + }, + "evselOpts": { + "amIneeded": "-1", + "muonSelection": "0", + "maxDiffZvtxFT0vsPV": "1", + "isMC": "-1", + "confSigmaBCforHighPtTracks": "4", + "TimeIntervalForOccupancyCalculationMin": "-40", + "TimeIntervalForOccupancyCalculationMax": "100", + "TimeRangeVetoOnCollStrict": "10", + "TimeRangeVetoOnCollNarrow": "0.25", + "FT0CamplPerCollCutVetoOnCollInTimeRange": "8000", + "FT0CamplPerCollCutVetoOnCollInROF": "5000", + "EpsilonVzDiffVetoInROF": "0.3", + "UseWeightsForOccupancyEstimator": "true", + "NumberOfOrbitsPerTF": "-1", + "VzDiffNsigma": "3", + "VzDiffMargin": "0.2" + }, + "lumiOpts": { + "amIneeded": "-1" + }, + "ccdburl": "http://alice-ccdb.cern.ch" + }, + "propagation-service": { + "ccdburl": "http://alice-ccdb.cern.ch", + "ccdb": { + "ccdb-url": "http://alice-ccdb.cern.ch", + "lutPath": "GLO/Param/MatLUTInner", + "grpmagPath": "GLO/Config/GRPMagField", + "grpPath": "GLO/GRP/GRP", + "mVtxPath": "GLO/Calib/MeanVertex" + }, + "enabledTables": { + "labels_rows": [ + "V0Indices", + "V0CoresBase", + "V0Covs", + "CascIndices", + "KFCascIndices", + "TraCascIndices", + "StoredCascCores", + "StoredKFCascCores", + "StoredTraCascCores", + "CascCovs", + "KFCascCovs", + "TraCascCovs", + "V0TrackXs", + "CascTrackXs", + "CascBBs", + "V0DauCovs", + "V0DauCovIUs", + "V0TraPosAtDCAs", + "V0TraPosAtIUs", + "V0Ivanovs", + "McV0Labels", + "V0MCCores", + "V0CoreMCLabels", + "V0MCCollRefs", + "McCascLabels", + "McKFCascLabels", + "McTraCascLabels", + "McCascBBTags", + "CascMCCores", + "CascCoreMCLabels", + "CascMCCollRefs", + "CascToTraRefs", + "CascToKFRefs", + "TraToCascRefs", + "KFToCascRefs", + "V0FoundTags", + "CascFoundTags" + ], + "labels_cols": [ + "enable" + ], + "values": [ + [ + "-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" + ] + ] + }, + "deduplicationAlgorithm": "1", + "useV0BufferForCascades": "false", + "mc_findableMode": "0", + "refitWithMaterialCorrection": "false", + "v0BuilderOpts": { + "generatePhotonCandidates": "false", + "moveTPCOnlyTracks": "true", + "minCrossedRows": "50", + "dcanegtopv": "0.05", + "dcapostopv": "0.05", + "v0cospa": "0.95", + "dcav0dau": "1", + "v0radius": "0.9", + "maxDaughterEta": "5", + "mc_populateV0MCCoresSymmetric": "true", + "mc_populateV0MCCoresAsymmetric": "false", + "mc_treatPiToMuDecays": "true", + "mc_rapidityWindow": "0.5", + "mc_keepOnlyPhysicalPrimary": "false", + "mc_addGeneratedK0Short": "true", + "mc_addGeneratedLambda": "true", + "mc_addGeneratedAntiLambda": "true", + "mc_addGeneratedGamma": "false", + "mc_addGeneratedGammaMakeCollinear": "true", + "mc_findableDetachedV0": "false" + }, + "cascadeBuilderOpts": { + "useCascadeMomentumAtPrimVtx": "false", + "minCrossedRows": "50", + "dcabachtopv": "0.05", + "cascradius": "0.9", + "casccospa": "0.95", + "dcacascdau": "1", + "lambdaMassWindow": "0.01", + "maxDaughterEta": "5", + "kfTuneForOmega": "false", + "kfConstructMethod": "2", + "kfUseV0MassConstraint": "true", + "kfUseCascadeMassConstraint": "false", + "kfDoDCAFitterPreMinimV0": "true", + "kfDoDCAFitterPreMinimCasc": "true", + "mc_populateCascMCCoresSymmetric": "true", + "mc_populateCascMCCoresAsymmetric": "false", + "mc_addGeneratedXiMinus": "true", + "mc_addGeneratedXiPlus": "true", + "mc_addGeneratedOmegaMinus": "true", + "mc_addGeneratedOmegaPlus": "true", + "mc_treatPiToMuDecays": "true", + "mc_rapidityWindow": "0.5", + "mc_keepOnlyPhysicalPrimary": "false", + "mc_findableDetachedCascade": "false" + }, + "preSelectOpts": { + "preselectOnlyDesiredV0s": "false", + "preselectOnlyDesiredCascades": "false", + "lifetimeCut": { + "labels_rows": "", + "labels_cols": [ + "lifetimeCutK0S", + "lifetimeCutLambda", + "lifetimeCutXi", + "lifetimeCutOmega" + ], + "values": [ + [ + "20", + "60", + "40", + "20" + ] + ] + }, + "massCutPhoton": "0.3", + "massCutK0": { + "labels_rows": "", + "labels_cols": [ + "constant", + "linear", + "expoConstant", + "expoRelax" + ], + "values": [ + [ + "0.00281882007", + "0.00114057004", + "0.00172138005", + "0.500262022" + ] + ] + }, + "massCutLambda": { + "labels_rows": "", + "labels_cols": [ + "constant", + "linear", + "expoConstant", + "expoRelax" + ], + "values": [ + [ + "0.00117517996", + "0.000124098995", + "0.00547936978", + "0.308008999" + ] + ] + }, + "massCutXi": { + "labels_rows": "", + "labels_cols": [ + "constant", + "linear", + "expoConstant", + "expoRelax" + ], + "values": [ + [ + "0.00143209996", + "0.000203560994", + "0.00243186997", + "0.799668014" + ] + ] + }, + "massCutOm": { + "labels_rows": "", + "labels_cols": [ + "constant", + "linear", + "expoConstant", + "expoRelax" + ], + "values": [ + [ + "0.00143209996", + "0.000203560994", + "0.00243186997", + "0.799668014" + ] + ] + }, + "massWindownumberOfSigmas": "20", + "massWindowSafetyMargin": "0.001", + "maxTPCpidNsigma": "5" + }, + "trackTuner": { + "debugInfo": "false", + "updateTrackDCAs": "false", + "updateTrackCovMat": "false", + "updateCurvature": "false", + "updateCurvatureIU": "false", + "updatePulls": "false", + "isInputFileFromCCDB": "false", + "pathInputFile": "", + "nameInputFile": "", + "pathFileQoverPt": "", + "nameFileQoverPt": "", + "usePvRefitCorrections": "false", + "qOverPtMC": "-1", + "qOverPtData": "-1", + "nPhiBins": "0", + "autoDetectDcaCalib": "false" + }, + "trackPropagation": { + "minPropagationDistance": "5", + "useTrackTuner": "false", + "useTrkPid": "false", + "fillTrackTunerTable": "false", + "trackTunerConfigSource": "1", + "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.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.4", + "4.8", + "5.2", + "5.6", + "6.0", + "6.5", + "7.0", + "7.5", + "8.0", + "9.0", + "10.0", + "11.0", + "12.0", + "13.0", + "14.0", + "15.0", + "17.0", + "19.0", + "21.0", + "23.0", + "25.0", + "30.0", + "35.0", + "40.0", + "50.0" + ] + } + }, + "processRealData": "false", + "processMonteCarlo": "true", + "processRealDataWithPID": "false", + "processMonteCarloWithPID": "false" }, "track-selection": { "isRun3": "true", @@ -42,12 +485,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..c679951e3db 100644 --- a/Tutorials/PWGHF/dpl-config_task.json +++ b/Tutorials/PWGHF/dpl-config_task.json @@ -1,52 +1,566 @@ { "internal-dpl-clock": "", "internal-dpl-aod-reader": { + "aod-file-private": "@input_task.txt", + "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": { - "verbose": "false", - "rct-path": "RCT/Info/RunInformation", - "orbit-reset-path": "CTP/Calib/OrbitReset", - "ccdb-url": "http://alice-ccdb.cern.ch", - "isRun2MC": "false" + "mc-collision-converter": "", + "tracks-extra-v002-converter": { + "processV000ToV002": "false", + "processV001ToV002": "true" }, - "tracks-extra-converter": "", - "zdc-converter": "", - "track-propagation": { + "tracks-extra-spawner": "", + "eventselection-run3": { + "timestamp": { + "verbose": "false", + "fatalOnInvalidTimestamp": "false", + "rct-path": "RCT/Info/RunInformation", + "orbit-reset-path": "CTP/Calib/OrbitReset", + "isRun2MC": "-1" + }, + "bcselOpts": { + "amIneeded": "-1", + "triggerBcShift": "0", + "ITSROFrameStartBorderMargin": "-1", + "ITSROFrameEndBorderMargin": "-1", + "TimeFrameStartBorderMargin": "-1", + "TimeFrameEndBorderMargin": "-1", + "checkRunDurationLimits": "false", + "maxInactiveChipsPerLayer": { + "values": [ + "8", + "8", + "8", + "111", + "111", + "195", + "195" + ] + }, + "NumberOfOrbitsPerTF": "-1" + }, + "evselOpts": { + "amIneeded": "-1", + "muonSelection": "0", + "maxDiffZvtxFT0vsPV": "1", + "isMC": "-1", + "confSigmaBCforHighPtTracks": "4", + "TimeIntervalForOccupancyCalculationMin": "-40", + "TimeIntervalForOccupancyCalculationMax": "100", + "TimeRangeVetoOnCollStrict": "10", + "TimeRangeVetoOnCollNarrow": "0.25", + "FT0CamplPerCollCutVetoOnCollInTimeRange": "8000", + "FT0CamplPerCollCutVetoOnCollInROF": "5000", + "EpsilonVzDiffVetoInROF": "0.3", + "UseWeightsForOccupancyEstimator": "true", + "NumberOfOrbitsPerTF": "-1", + "VzDiffNsigma": "3", + "VzDiffMargin": "0.2" + }, + "lumiOpts": { + "amIneeded": "-1" + }, + "ccdburl": "http://alice-ccdb.cern.ch" + }, + "pid-tpc-service": { + "ccdburl": "http://alice-ccdb.cern.ch", + "pidTPC": { + "param-file": "", + "ccdbPath": "Analysis/PID/TPC/Response", + "recoPass": "", + "ccdb-timestamp": "0", + "useNetworkCorrection": "false", + "autofetchNetworks": "true", + "skipTPCOnly": "-1", + "devicesRequiringTPCOnlyPID": { + "values": [ + "photon-conversion-builder" + ] + }, + "networkPathLocally": "network.onnx", + "networkPathCCDB": "Analysis/PID/TPC/ML", + "enableNetworkOptimizations": "false", + "networkSetNumThreads": "0", + "savedEdxsCorrected": "-1", + "useCorrecteddEdx": "false", + "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": "0", + "useNetworkPi": "1", + "useNetworkKa": "1", + "useNetworkPr": "1", + "useNetworkDe": "0", + "useNetworkTr": "0", + "useNetworkHe": "0", + "useNetworkAl": "0", + "networkBetaGammaCutoff": "0.45", + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF" + }, + "processTracksIU": "true", + "processTracksIUWithTracksQA": "false", + "processTracksMCIU": "false" + }, + "ft0-corrected-table": { + "resoFT0A": "20", + "resoFT0C": "20", + "addHistograms": "false", + "collisionSystem": "-2", "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", - "processStandard": "false", - "processCovariance": "true" + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "ccdb-timestamp": "-1", + "processStandard": "true", + "processWithBypassFT0timeInMC": "false" }, - "bc-selection-task": { - "triggerBcShift": "999", - "processRun2": "false", - "processRun3": "true" + "propagation-service": { + "ccdburl": "http://alice-ccdb.cern.ch", + "ccdb": { + "ccdb-url": "http://alice-ccdb.cern.ch", + "lutPath": "GLO/Param/MatLUTInner", + "grpmagPath": "GLO/Config/GRPMagField", + "grpPath": "GLO/GRP/GRP", + "mVtxPath": "GLO/Calib/MeanVertex" + }, + "enabledTables": { + "labels_rows": [ + "V0Indices", + "V0CoresBase", + "V0Covs", + "CascIndices", + "KFCascIndices", + "TraCascIndices", + "StoredCascCores", + "StoredKFCascCores", + "StoredTraCascCores", + "CascCovs", + "KFCascCovs", + "TraCascCovs", + "V0TrackXs", + "CascTrackXs", + "CascBBs", + "V0DauCovs", + "V0DauCovIUs", + "V0TraPosAtDCAs", + "V0TraPosAtIUs", + "V0Ivanovs", + "McV0Labels", + "V0MCCores", + "V0CoreMCLabels", + "V0MCCollRefs", + "McCascLabels", + "McKFCascLabels", + "McTraCascLabels", + "McCascBBTags", + "CascMCCores", + "CascCoreMCLabels", + "CascMCCollRefs", + "CascToTraRefs", + "CascToKFRefs", + "TraToCascRefs", + "KFToCascRefs", + "V0FoundTags", + "CascFoundTags" + ], + "labels_cols": [ + "enable" + ], + "values": [ + [ + "-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" + ] + ] + }, + "deduplicationAlgorithm": "1", + "useV0BufferForCascades": "false", + "mc_findableMode": "0", + "refitWithMaterialCorrection": "false", + "v0BuilderOpts": { + "generatePhotonCandidates": "false", + "moveTPCOnlyTracks": "true", + "minCrossedRows": "50", + "dcanegtopv": "0.05", + "dcapostopv": "0.05", + "v0cospa": "0.95", + "dcav0dau": "1", + "v0radius": "0.9", + "maxDaughterEta": "5", + "mc_populateV0MCCoresSymmetric": "true", + "mc_populateV0MCCoresAsymmetric": "false", + "mc_treatPiToMuDecays": "true", + "mc_rapidityWindow": "0.5", + "mc_keepOnlyPhysicalPrimary": "false", + "mc_addGeneratedK0Short": "true", + "mc_addGeneratedLambda": "true", + "mc_addGeneratedAntiLambda": "true", + "mc_addGeneratedGamma": "false", + "mc_addGeneratedGammaMakeCollinear": "true", + "mc_findableDetachedV0": "false" + }, + "cascadeBuilderOpts": { + "useCascadeMomentumAtPrimVtx": "false", + "minCrossedRows": "50", + "dcabachtopv": "0.05", + "cascradius": "0.9", + "casccospa": "0.95", + "dcacascdau": "1", + "lambdaMassWindow": "0.01", + "maxDaughterEta": "5", + "kfTuneForOmega": "false", + "kfConstructMethod": "2", + "kfUseV0MassConstraint": "true", + "kfUseCascadeMassConstraint": "false", + "kfDoDCAFitterPreMinimV0": "true", + "kfDoDCAFitterPreMinimCasc": "true", + "mc_populateCascMCCoresSymmetric": "true", + "mc_populateCascMCCoresAsymmetric": "false", + "mc_addGeneratedXiMinus": "true", + "mc_addGeneratedXiPlus": "true", + "mc_addGeneratedOmegaMinus": "true", + "mc_addGeneratedOmegaPlus": "true", + "mc_treatPiToMuDecays": "true", + "mc_rapidityWindow": "0.5", + "mc_keepOnlyPhysicalPrimary": "false", + "mc_findableDetachedCascade": "false" + }, + "preSelectOpts": { + "preselectOnlyDesiredV0s": "false", + "preselectOnlyDesiredCascades": "false", + "lifetimeCut": { + "labels_rows": "", + "labels_cols": [ + "lifetimeCutK0S", + "lifetimeCutLambda", + "lifetimeCutXi", + "lifetimeCutOmega" + ], + "values": [ + [ + "20", + "60", + "40", + "20" + ] + ] + }, + "massCutPhoton": "0.3", + "massCutK0": { + "labels_rows": "", + "labels_cols": [ + "constant", + "linear", + "expoConstant", + "expoRelax" + ], + "values": [ + [ + "0.00281882007", + "0.00114057004", + "0.00172138005", + "0.500262022" + ] + ] + }, + "massCutLambda": { + "labels_rows": "", + "labels_cols": [ + "constant", + "linear", + "expoConstant", + "expoRelax" + ], + "values": [ + [ + "0.00117517996", + "0.000124098995", + "0.00547936978", + "0.308008999" + ] + ] + }, + "massCutXi": { + "labels_rows": "", + "labels_cols": [ + "constant", + "linear", + "expoConstant", + "expoRelax" + ], + "values": [ + [ + "0.00143209996", + "0.000203560994", + "0.00243186997", + "0.799668014" + ] + ] + }, + "massCutOm": { + "labels_rows": "", + "labels_cols": [ + "constant", + "linear", + "expoConstant", + "expoRelax" + ], + "values": [ + [ + "0.00143209996", + "0.000203560994", + "0.00243186997", + "0.799668014" + ] + ] + }, + "massWindownumberOfSigmas": "20", + "massWindowSafetyMargin": "0.001", + "maxTPCpidNsigma": "5" + }, + "trackTuner": { + "debugInfo": "false", + "updateTrackDCAs": "false", + "updateTrackCovMat": "false", + "updateCurvature": "false", + "updateCurvatureIU": "false", + "updatePulls": "false", + "isInputFileFromCCDB": "false", + "pathInputFile": "", + "nameInputFile": "", + "pathFileQoverPt": "", + "nameFileQoverPt": "", + "usePvRefitCorrections": "false", + "qOverPtMC": "-1", + "qOverPtData": "-1", + "nPhiBins": "0", + "autoDetectDcaCalib": "false" + }, + "trackPropagation": { + "minPropagationDistance": "5", + "useTrackTuner": "false", + "useTrkPid": "false", + "fillTrackTunerTable": "false", + "trackTunerConfigSource": "1", + "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.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.4", + "4.8", + "5.2", + "5.6", + "6.0", + "6.5", + "7.0", + "7.5", + "8.0", + "9.0", + "10.0", + "11.0", + "12.0", + "13.0", + "14.0", + "15.0", + "17.0", + "19.0", + "21.0", + "23.0", + "25.0", + "30.0", + "35.0", + "40.0", + "50.0" + ] + } + }, + "processRealData": "false", + "processMonteCarlo": "true", + "processRealDataWithPID": "false", + "processMonteCarloWithPID": "false" }, - "event-selection-task": { - "syst": "pp", - "muonSelection": "0", - "customDeltaBC": "300", - "isMC": "false", - "processRun2": "false", - "processRun3": "true" + "tof-signal": { + "enableQaHistograms": "false", + "ccdb-url": "http://alice-ccdb.cern.ch", + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "ccdb-timestamp": "-1", + "timeShiftCCDBPathPos": "Analysis/PID/TOFOffsetPos", + "timeShiftCCDBPathNeg": "Analysis/PID/TOFOffsetPos", + "timeShiftCCDBPathPosMC": "", + "timeShiftCCDBPathNegMC": "", + "paramFileName": "", + "parametrizationPath": "TOF/Calib/Params", + "reconstructionPass": "metadata", + "reconstructionPassDefault": "unanchored", + "fatalOnPassNotAvailable": "false", + "enableTimeDependentResponse": "true", + "collisionSystem": "-1", + "autoSetProcessFunctions": "true", + "processRun3": "true", + "processRun2": "false" }, - "hf-candidate-creator2-prong": { + "hf-task-mini-candidate-creator-2prong": { "magneticField": "5", "propagateToPCA": "true", "useAbsDCA": "false", @@ -55,66 +569,21 @@ "minParamChange": "0.001", "minRelChi2Change": "0.9" }, - "pid-multiplicity": { - "processIU": "false", - "processStandard": "true" - }, - "tof-signal": { - "processRun3": "true", - "processRun2": "false" - }, - "tpc-pid-full": { - "param-file": "", - "ccdb-url": "http://alice-ccdb.cern.ch", - "ccdbPath": "Analysis/PID/TPC/Response", - "recoPass": "", - "ccdb-timestamp": "0", - "useNetworkCorrection": "false", - "autofetchNetworks": "true", - "skipTPCOnly": "false", - "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" - }, "tof-event-time": { "minMomentum": "0.5", "maxMomentum": "2", "maxEvTimeTOF": "100000", - "paramFileName": "", - "ccdb-url": "http://alice-ccdb.cern.ch", - "parametrizationPath": "TOF/Calib/Params", - "passName": "", - "ccdb-timestamp": "-1", - "loadResponseFromCCDB": "false", - "fatalOnPassNotAvailable": "true", "sel8TOFEvTime": "false", + "computeEvTimeWithTOF": "1", + "computeEvTimeWithFT0": "1", "maxNtracksInSet": "10", "processRun2": "false", - "processNoFT0": "true", - "processFT0": "false", - "processOnlyFT0": "false" + "processRun3": "true" }, - "hf-candidate-creator2-prong-expressions": "", - "tof-pid-full": { - "paramFileName": "", - "ccdb-url": "http://alice-ccdb.cern.ch", - "parametrizationPath": "TOF/Calib/Params", - "timeShiftCCDBPath": "", - "passName": "", - "ccdb-timestamp": "-1", - "loadResponseFromCCDB": "false", - "enableTimeDependentResponse": "false", - "fatalOnPassNotAvailable": "true", + "hf-task-mini-candidate-creator-2prong-expressions": "", + "tof-pid-merge": { + "enableQaHistograms": "false", + "enableTOFParamsForBetaMass": "false", "enableParticle": { "labels_rows": [ "El", @@ -128,51 +597,63 @@ "Al" ], "labels_cols": [ - "Enable" + "Enable", + "EnableFull" ], "values": [ [ + "-1", "-1" ], [ + "-1", "-1" ], [ + "-1", "-1" ], [ + "-1", "-1" ], [ + "-1", "-1" ], [ + "-1", "-1" ], [ + "-1", "-1" ], [ + "-1", "-1" ], [ + "-1", "-1" ] ] }, - "processWSlice": "true", - "processWoSlice": "false" + "processRun3": "true", + "processRun2": "false", + "processRun2BetaM": "false", + "processRun3BetaM": "true" }, - "hf-candidate-selector-d0": { + "hf-task-mini-candidate-selector-d0": { "ptCandMin": "0", "ptCandMax": "50", "ptPidTpcMin": "0.15", "ptPidTpcMax": "10", - "nSigmaTpc": "3", + "nSigmaTpcMax": "3", "cpaMin": "0.98", "massWindow": "0.4" }, - "hf-task-d0": { + "hf-task-mini-d0": { "selectionFlagD0": "1", "selectionFlagD0bar": "1" }, diff --git a/Tutorials/PWGHF/input_skim.txt b/Tutorials/PWGHF/input_skim.txt new file mode 100644 index 00000000000..518fe2342e0 --- /dev/null +++ b/Tutorials/PWGHF/input_skim.txt @@ -0,0 +1 @@ +AO2D.root diff --git a/Tutorials/PWGHF/input_task.txt b/Tutorials/PWGHF/input_task.txt new file mode 100644 index 00000000000..5cf3c50ca80 --- /dev/null +++ b/Tutorials/PWGHF/input_task.txt @@ -0,0 +1 @@ +AnalysisResults_trees.root diff --git a/Tutorials/PWGHF/run_skim.sh b/Tutorials/PWGHF/run_skim.sh old mode 100644 new mode 100755 index 788a2ffd460..83e85adde22 --- a/Tutorials/PWGHF/run_skim.sh +++ b/Tutorials/PWGHF/run_skim.sh @@ -11,7 +11,7 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -# @brief Bash script to produce derived data AnalysisResults_trees.root with 2-prong mini skims from Run 3 real-data input for the D0 mini task +# @brief Bash script to produce derived data AnalysisResults_trees.root with 2-prong mini skims from Run 3 input for the D0 mini task # # The input AO2D.root file is expected in the working directory. # @@ -27,18 +27,29 @@ DIR_THIS="$(dirname "$(realpath "$0")")" # O2 configuration file (in the same directory) 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" - -# 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 \ +# local command line options of O2 workflows (required per workflow) +OPTIONS_LOCAL=( + -b + --configuration json://"$JSON" + --aod-writer-keep "AOD/HFT2PRONG/0" +) + +# global command line options of O2 workflows (required only once) +OPTIONS_GLOBAL=( + --aod-memory-rate-limit 2000000000 + --shm-segment-size 16000000000 + --resources-monitoring 2 + --aod-file "@input_skim.txt" + --min-failure-level error +) + +# execute the mini skim creator workflow and its dependencies +o2-analysis-trackselection "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-mccollision-converter "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-event-selection-service "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-tracks-extra-v002-converter "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-propagationservice "${OPTIONS_LOCAL[@]}" | \ +o2-analysistutorial-hf-skim-creator-mini "${OPTIONS_LOCAL[@]}" "${OPTIONS_GLOBAL[@]}" \ > "$LOGFILE" 2>&1 # report status diff --git a/Tutorials/PWGHF/run_task.sh b/Tutorials/PWGHF/run_task.sh old mode 100644 new mode 100755 index 096ee292150..3f363c3279f --- a/Tutorials/PWGHF/run_task.sh +++ b/Tutorials/PWGHF/run_task.sh @@ -11,7 +11,7 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -# @brief Bash script to execute the D0 mini task on Run 3 real-data input +# @brief Bash script to execute the D0 mini task on Run 3 input # # The input AO2D.root, AnalysisResults_trees.root files are expected in the working directory. # @@ -27,22 +27,32 @@ DIR_THIS="$(dirname "$(realpath "$0")")" # O2 configuration file (in the same directory) 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" +# local command line options of O2 workflows (required per workflow) +OPTIONS_LOCAL=( + -b + --configuration json://"$JSON" + ) + +# global command line options of O2 workflows (required only once) +OPTIONS_GLOBAL=( + --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 + --aod-file "@input_task.txt" + --min-failure-level error +) # 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-analysis-pid-tpc-service "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-pid-tof-merge "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-ft0-corrected-table "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-mccollision-converter "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-event-selection-service "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-tracks-extra-v002-converter "${OPTIONS_LOCAL[@]}" | \ +o2-analysis-propagationservice "${OPTIONS_LOCAL[@]}" | \ +o2-analysistutorial-hf-task-mini "${OPTIONS_LOCAL[@]}" "${OPTIONS_GLOBAL[@]}" \ > "$LOGFILE" 2>&1 # report status diff --git a/Tutorials/PWGHF/skimCreatorMini.cxx b/Tutorials/PWGHF/skimCreatorMini.cxx index 6f20d6ac6fb..45135bfdef8 100644 --- a/Tutorials/PWGHF/skimCreatorMini.cxx +++ b/Tutorials/PWGHF/skimCreatorMini.cxx @@ -14,95 +14,98 @@ /// /// \author Vít Kučera , Inha University -// O2 -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - -// O2Physics +#include "Tutorials/PWGHF/DataModelMini.h" +// #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" #include "Common/DataModel/TrackSelectionTables.h" -// PWGHF -#include "Tutorials/PWGHF/DataModelMini.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::constants::physics; // 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.3f, "Min. track pT for 2-prong candidate [GeV/c]"}; + Configurable etaTrackMax{"etaTrackMax", 0.8f, "Max. pseudorapidity for 2-prong candidate"}; + Configurable dcaTrackMin{"dcaTrackMin", 0.0025f, "Min. DCA for 2-prong candidate [cm]"}; using TracksWDcaSel = soa::Join; - HistogramRegistry registry{ - "registry", - {}}; + HistogramRegistry registry{"registry"}; void init(InitContext&) { - const TString strTitle = "D^{0} candidates"; const TString strPt = "#it{p}_{T}^{track} (GeV/#it{c})"; const TString strEntries = "entries"; - registry.add("hPtNoCuts", "all tracks;" + strPt + ";" + strEntries, {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("hPtCuts2Prong", "tracks selected for 2-prong vertexing;" + strPt + ";" + strEntries, {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("hPtNoCuts", "all tracks;" + strPt + ";" + strEntries, {HistType::kTH1D, {{100, 0., 10.}}}); + registry.add("hPtCuts2Prong", "tracks selected for 2-prong vertexing;" + strPt + ";" + strEntries, {HistType::kTH1D, {{100, 0., 10.}}}); registry.add("hPtVsDcaXYToPvCuts2Prong", "tracks selected for 2-prong vertexing;" + strPt + ";" + "DCAxy to prim. vtx. (cm)" + ";" + strEntries, {HistType::kTH2F, {{100, 0., 10.}, {400, -2., 2.}}}); - registry.add("hEtaCuts2Prong", "tracks selected for 2-prong vertexing;#it{#eta};" + strEntries, {HistType::kTH1F, {{static_cast(1.2 * etaTrackMax * 100), -1.2 * etaTrackMax, 1.2 * etaTrackMax}}}); + registry.add("hEtaCuts2Prong", "tracks selected for 2-prong vertexing;#it{#eta};" + strEntries, {HistType::kTH1D, {{static_cast(1.2 * etaTrackMax * 100), -1.2 * etaTrackMax, 1.2 * etaTrackMax}}}); } - void process(TracksWDcaSel const& tracks) + void process(TracksWDcaSel::iterator const& track) { - for (const auto& track : tracks) { - bool statusProng = true; + const auto ptTrack{track.pt()}; + registry.fill(HIST("hPtNoCuts"), ptTrack); - auto ptTrack = track.pt(); - registry.fill(HIST("hPtNoCuts"), ptTrack); + bool statusProng{true}; - // pT cut - if (ptTrack < ptTrackMin) { - statusProng = false; - } - - // eta cut - auto etaTrack = track.eta(); - if (statusProng && std::abs(etaTrack) > etaTrackMax) { - statusProng = false; - } + // pT cut + if (ptTrack < ptTrackMin) { + statusProng = false; + } - // quality cut - if (!track.isGlobalTrackWoDCA()) { - statusProng = false; - } + // eta cut + const auto etaTrack{track.eta()}; + if (statusProng && std::abs(etaTrack) > etaTrackMax) { + statusProng = false; + } - // DCA cut - auto dcaXY = track.dcaXY(); - if (statusProng && std::abs(dcaXY) < dcaTrackMin) { - statusProng = false; - } + // quality cut + if (!track.isGlobalTrackWoDCA()) { + statusProng = false; + } - // fill histograms - if (statusProng) { - registry.fill(HIST("hPtCuts2Prong"), ptTrack); - registry.fill(HIST("hEtaCuts2Prong"), etaTrack); - registry.fill(HIST("hPtVsDcaXYToPvCuts2Prong"), ptTrack, dcaXY); - } + // DCA cut + const auto dcaXY{track.dcaXY()}; + if (statusProng && std::abs(dcaXY) < dcaTrackMin) { + statusProng = false; + } - // fill table row - rowSelectedTrack(statusProng); + // fill histograms + if (statusProng) { + registry.fill(HIST("hPtCuts2Prong"), ptTrack); + registry.fill(HIST("hEtaCuts2Prong"), etaTrack); + registry.fill(HIST("hPtVsDcaXYToPvCuts2Prong"), ptTrack, dcaXY); } + + // fill table row + rowSelectedTrack(statusProng); } }; @@ -110,35 +113,35 @@ 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 propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; + Configurable magneticField{"magneticField", 5.f, "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.f, "Reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4.f, "Reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3f, "Stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9f, "Stop iterations if chi2/chi2old > this"}; - o2::vertexing::DCAFitterN<2> fitter; // 2-prong vertex fitter + o2::vertexing::DCAFitterN<2> fitter{}; // 2-prong vertex fitter - using SelectedTracks = soa::Filtered>; + using SelectedTracks = soa::Filtered>; Filter filterSelectTracks = aod::hf_seltrack::isSelProng == true; - HistogramRegistry registry{ - "registry", - {// 2-prong histograms - {"hVtx2ProngX", "2-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}}, - {"hVtx2ProngY", "2-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -2., 2.}}}}, - {"hVtx2ProngZ", "2-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1F, {{1000, -20., 20.}}}}, - {"hMassD0ToPiK", "D^{0} candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}}}}; + HistogramRegistry registry{"registry"}; void init(InitContext&) { - // Configure the vertexer + // 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("hMassD0ToPiK", "D^{0} candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); + + // Configure the vertexer. fitter.setBz(magneticField); fitter.setPropagateToPCA(propagateToPCA); fitter.setMaxR(maxR); @@ -152,42 +155,49 @@ struct HfTrackIndexSkimCreator { SelectedTracks const& tracks) { // loop over positive tracks - for (const auto& trackPos1 : tracks) { - if (trackPos1.signed1Pt() < 0) { + for (const auto& trackPos : tracks) { + if (trackPos.signed1Pt() < 0) { continue; } - auto trackParVarPos1 = getTrackParCov(trackPos1); + const auto trackParVarPos{getTrackParCov(trackPos)}; // loop over negative tracks - for (const auto& trackNeg1 : tracks) { - if (trackNeg1.signed1Pt() > 0) { + for (const auto& trackNeg : tracks) { + if (trackNeg.signed1Pt() > 0) { continue; } - auto trackParVarNeg1 = getTrackParCov(trackNeg1); + const auto trackParVarNeg{getTrackParCov(trackNeg)}; - // secondary vertex reconstruction and further 2-prong selections - if (fitter.process(trackParVarPos1, trackParVarNeg1) == 0) { + // secondary-vertex reconstruction and further 2-prong selections + int nVtxFromFitter = 0; + try { + nVtxFromFitter = fitter.process(trackParVarPos, trackParVarNeg); + } catch (...) { + } + if (nVtxFromFitter == 0) { continue; } - // get secondary vertex + // get secondary vertex const auto& secondaryVertex = fitter.getPCACandidate(); // get track momenta - std::array pVec0; - std::array pVec1; + std::array pVec0{}; + std::array pVec1{}; fitter.getTrack(0).getPxPyPzGlo(pVec0); fitter.getTrack(1).getPxPyPzGlo(pVec1); // fill table row - rowTrackIndexProng2(trackPos1.globalIndex(), - trackNeg1.globalIndex()); + rowTrackIndexProng2(trackPos.globalIndex(), + trackNeg.globalIndex()); // fill histograms registry.fill(HIST("hVtx2ProngX"), secondaryVertex[0]); registry.fill(HIST("hVtx2ProngY"), secondaryVertex[1]); registry.fill(HIST("hVtx2ProngZ"), secondaryVertex[2]); - std::array, 2> arrMom = {pVec0, pVec1}; - auto mass2Prong = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}); - registry.fill(HIST("hMassD0ToPiK"), mass2Prong); + const std::array arrayMomenta{pVec0, pVec1}; + const auto massPiK{RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus})}; + registry.fill(HIST("hMassD0ToPiK"), massPiK); + // const auto massKPi{RecoDecay::m(arrayMomenta, std::array{MassKPlus, MassPiPlus})}; + // registry.fill(HIST("hMassD0ToPiK"), massKPi); } } } @@ -197,6 +207,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..e92553d8e50 100644 --- a/Tutorials/PWGHF/taskMini.cxx +++ b/Tutorials/PWGHF/taskMini.cxx @@ -14,56 +14,66 @@ /// /// \author Vít Kučera , Inha University -// O2 -#include "CommonConstants/PhysicsConstants.h" -#include "DCAFitter/DCAFitterN.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/HistogramRegistry.h" -#include "Framework/runDataProcessing.h" - -// O2Physics +#include "Tutorials/PWGHF/DataModelMini.h" +// +#include "PWGHF/Core/HfHelper.h" +// #include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelectorPID.h" #include "Common/Core/trackUtilities.h" -#include "Common/DataModel/PIDResponse.h" - -// PWGHF -#include "PWGHF/Core/HfHelper.h" -#include "Tutorials/PWGHF/DataModelMini.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include using namespace o2; using namespace o2::aod; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::constants::physics; // Candidate creation ===================================================================== /// 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 propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; + Configurable magneticField{"magneticField", 5.f, "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.f, "Reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4.f, "Reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3f, "Stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9f, "Stop iterations if chi2/chi2old > this"}; - o2::vertexing::DCAFitterN<2> fitter; // 2-prong vertex fitter - double massPiK{0.}; - double massKPi{0.}; + o2::vertexing::DCAFitterN<2> fitter{}; // 2-prong vertex fitter using TracksWithCov = soa::Join; - OutputObj hMass{TH1F("hMass", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", 500, 0., 5.)}; + HistogramRegistry registry{"registry"}; void init(InitContext&) { - // Configure the vertexer + registry.add("hMass", "D^{0} candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{500, 0., 5.}}}); + + // Configure the vertexer. fitter.setBz(magneticField); fitter.setPropagateToPCA(propagateToPCA); fitter.setMaxR(maxR); @@ -74,32 +84,30 @@ struct HfCandidateCreator2Prong { } void process(aod::Collisions const&, - aod::HfTrackIndexProng2 const& rowsTrackIndexProng2, + aod::HfT2Prongs const& rowsTrackIndexProng2, TracksWithCov const&) { // loop over pairs of track indices for (const auto& rowTrackIndexProng2 : rowsTrackIndexProng2) { - auto track0 = rowTrackIndexProng2.prong0_as(); - auto track1 = rowTrackIndexProng2.prong1_as(); - auto trackParVarPos1 = getTrackParCov(track0); - auto trackParVarNeg1 = getTrackParCov(track1); - auto collision = track0.collision(); + const auto& track0{rowTrackIndexProng2.prong0_as()}; + const auto& track1{rowTrackIndexProng2.prong1_as()}; + const auto trackParVarPos1{getTrackParCov(track0)}; + const auto trackParVarNeg1{getTrackParCov(track1)}; + const auto& collision{track0.collision()}; // reconstruct the 2-prong secondary vertex if (fitter.process(trackParVarPos1, trackParVarNeg1) == 0) { continue; } + // get secondary vertex const auto& secondaryVertex = fitter.getPCACandidate(); - auto trackParVar0 = fitter.getTrack(0); - auto trackParVar1 = fitter.getTrack(1); - // get track momenta - std::array pVec0; - std::array pVec1; - trackParVar0.getPxPyPzGlo(pVec0); - trackParVar1.getPxPyPzGlo(pVec1); + std::array pVec0{}; + std::array pVec1{}; + fitter.getTrack(0).getPxPyPzGlo(pVec0); + fitter.getTrack(1).getPxPyPzGlo(pVec1); - // fill candidate table rows + // fill candidate table row rowCandidateBase(collision.globalIndex(), collision.posX(), collision.posY(), collision.posZ(), secondaryVertex[0], secondaryVertex[1], secondaryVertex[2], @@ -109,41 +117,40 @@ struct HfCandidateCreator2Prong { // fill histograms // calculate invariant masses - auto arrayMomenta = std::array{pVec0, pVec1}; - massPiK = RecoDecay::m(arrayMomenta, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus}); - massKPi = RecoDecay::m(arrayMomenta, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); - hMass->Fill(massPiK); - // hMass->Fill(massKPi); + const std::array arrayMomenta{pVec0, pVec1}; + const auto massPiK{RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus})}; + registry.fill(HIST("hMass"), massPiK); + // const auto massKPi{RecoDecay::m(arrayMomenta, std::array{MassKPlus, MassPiPlus})}; + // registry.fill(HIST("hMass"), massKPi); } } }; /// 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.f, "Min. candidate pT [GeV/c] "}; + Configurable ptCandMax{"ptCandMax", 50.f, "Max. candidate pT [GeV/c]"}; // 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.15f, "Min. track pT for TPC PID [GeV/c]"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 5.f, "Max. track pT for TPC PID [GeV/c]"}; + Configurable nSigmaTpcMax{"nSigmaTpcMax", 3.f, "Max. TPC N_sigma"}; // 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.98f, "Min. cosine of pointing angle"}; + Configurable massWindow{"massWindow", 0.4f, "Half-width of the invariant-mass window [Gev/c^2]"}; - HfHelper hfHelper; - TrackSelectorPi selectorPion; - TrackSelectorKa selectorKaon; + TrackSelectorPi selectorPion{}; + TrackSelectorKa selectorKaon{}; using TracksWithPid = soa::Join 0) { - if (std::abs(hfHelper.invMassD0ToPiK(candidate) - o2::constants::physics::MassD0) > massWindow) { + if (std::abs(HfHelper::invMassD0ToPiK(candidate) - MassD0) > massWindow) { return false; } } else { - if (std::abs(hfHelper.invMassD0barToKPi(candidate) - o2::constants::physics::MassD0) > massWindow) { + if (std::abs(HfHelper::invMassD0barToKPi(candidate) - MassD0) > massWindow) { return false; } } return true; } - void process(aod::HfCandProng2 const& candidates, + void process(aod::HfTCand2Prong const& candidates, TracksWithPid const&) { // looping over 2-prong candidates @@ -205,19 +212,19 @@ struct HfCandidateSelectorD0 { int statusD0 = 0; int statusD0bar = 0; - auto trackPos = candidate.prong0_as(); // positive daughter - auto trackNeg = candidate.prong1_as(); // negative daughter - // conjugate-independent topological selection if (!selectionTopol(candidate)) { hfSelD0Candidate(statusD0, statusD0bar); continue; } - // conjugate-dependent topological selection for D0 - bool topolD0 = selectionTopolConjugate(candidate, trackPos, trackNeg); - // conjugate-dependent topological selection for D0bar - bool topolD0bar = selectionTopolConjugate(candidate, trackNeg, trackPos); + // conjugate-dependent topological selection + const auto& trackPos = candidate.prong0_as(); // positive daughter + const auto& trackNeg = candidate.prong1_as(); // negative daughter + // D0 hypothesis + const auto topolD0 = selectionTopolConjugate(candidate, trackPos, trackNeg); + // D0bar hypothesis + const auto topolD0bar = selectionTopolConjugate(candidate, trackNeg, trackPos); if (!topolD0 && !topolD0bar) { hfSelD0Candidate(statusD0, statusD0bar); @@ -225,10 +232,10 @@ struct HfCandidateSelectorD0 { } // track-level PID selection - int pidTrackPosKaon = selectorKaon.statusTpcOrTof(trackPos); - int pidTrackPosPion = selectorPion.statusTpcOrTof(trackPos); - int pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); - int pidTrackNegPion = selectorPion.statusTpcOrTof(trackNeg); + const auto pidTrackPosKaon = selectorKaon.statusTpcOrTof(trackPos); + const auto pidTrackPosPion = selectorPion.statusTpcOrTof(trackPos); + const auto pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg); + const auto pidTrackNegPion = selectorPion.statusTpcOrTof(trackNeg); int pidD0 = -1; int pidD0bar = -1; @@ -273,17 +280,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", - {}}; + HistogramRegistry registry{"registry"}; void init(InitContext&) { @@ -295,14 +298,14 @@ 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) { - registry.fill(HIST("hMass"), hfHelper.invMassD0ToPiK(candidate)); + registry.fill(HIST("hMass"), HfHelper::invMassD0ToPiK(candidate)); } if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hMass"), hfHelper.invMassD0barToKPi(candidate)); + registry.fill(HIST("hMass"), HfHelper::invMassD0barToKPi(candidate)); } registry.fill(HIST("hPtCand"), candidate.pt()); registry.fill(HIST("hCpaVsPtCand"), candidate.cpa(), candidate.pt()); @@ -314,8 +317,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 (wrong hyphenation) + adaptAnalysisTask(cfgc, TaskName{"hf-task-mini-candidate-creator-2prong-expressions"}), // o2-linter: disable=name/o2-task (wrong hyphenation) + 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..5022d4b602d --- /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::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()) > cMaxDCArToPVcut - Epsilon) + return false; + if (o2::aod::resomicrodaughter::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::resomicrodaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPrFlag())) < nSigmaCutTPC + Epsilon; + bool tofPass = candidate.hasTOF() ? std::abs(o2::aod::resomicrodaughter::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::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags())); + histos.fill(HIST("hDcaz_ResoMicroTracks"), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags())); + histos.fill(HIST("hNsigmaKaonTPC_ResoMicroTracks"), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(track.pidNSigmaPrFlag())); + if (track.hasTOF()) { + histos.fill(HIST("hNsigmaKaonTOF_ResoMicroTracks"), o2::aod::resomicrodaughter::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..6a9ca0389f0 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(Original) +add_subdirectory(Derived) -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/Derived/Analysis/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/Derived/Analysis/CMakeLists.txt new file mode 100644 index 00000000000..0e08d103af1 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/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-derived-skeleton + SOURCES strangeness_derived_skeleton.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-step0 + SOURCES strangeness_derived_step0.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-step1 + SOURCES strangeness_derived_step1.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-step2 + SOURCES strangeness_derived_step2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-step3 + SOURCES strangeness_derived_step3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-step4 + SOURCES strangeness_derived_step4.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + diff --git a/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_skeleton.json b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_skeleton.json new file mode 100644 index 00000000000..87d588b5e92 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_skeleton.json @@ -0,0 +1,20 @@ +{ + "internal-dpl-clock": "", + "internal-dpl-aod-reader": { + "aod-file-private": "@input_data.txt", + "time-limit": "0", + "orbit-offset-enumeration": "0", + "orbit-multiplier-enumeration": "0", + "start-value-enumeration": "0", + "end-value-enumeration": "-1", + "step-value-enumeration": "1" + }, + "internal-dpl-aod-spawner": "", + "strangeness_derived_tutorial": { + "nBins": "100", + "cutzvertex": "10" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step0.json b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step0.json new file mode 100644 index 00000000000..87d588b5e92 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step0.json @@ -0,0 +1,20 @@ +{ + "internal-dpl-clock": "", + "internal-dpl-aod-reader": { + "aod-file-private": "@input_data.txt", + "time-limit": "0", + "orbit-offset-enumeration": "0", + "orbit-multiplier-enumeration": "0", + "start-value-enumeration": "0", + "end-value-enumeration": "-1", + "step-value-enumeration": "1" + }, + "internal-dpl-aod-spawner": "", + "strangeness_derived_tutorial": { + "nBins": "100", + "cutzvertex": "10" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step1.json b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step1.json new file mode 100644 index 00000000000..77ae6a5bab8 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step1.json @@ -0,0 +1,31 @@ +{ + "internal-dpl-clock": "", + "internal-dpl-aod-reader": { + "aod-file-private": "@input_data.txt", + "time-limit": "0", + "orbit-offset-enumeration": "0", + "orbit-multiplier-enumeration": "0", + "start-value-enumeration": "0", + "end-value-enumeration": "-1", + "step-value-enumeration": "1" + }, + "strangeness_derived_tutorial": { + "nBins": "100", + "cutzvertex": "10", + "cascadesetting_cospa": "0.998", + "cascadesetting_v0cospa": "0.97", + "cascadesetting_dcacascdau": "1", + "cascadesetting_dcav0dau": "1", + "cascadesetting_dcabachtopv": "0.06", + "cascadesetting_dcapostopv": "0.06", + "cascadesetting_dcanegtopv": "0.06", + "cascadesetting_mindcav0topv": "0.01", + "cascadesetting_cascradius": "0.5", + "cascadesetting_v0radius": "1.2", + "cascadesetting_v0masswindow": "0.008", + "cascadesetting_competingmassrej": "0.008" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step2.json b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step2.json new file mode 100644 index 00000000000..29e4354e5ae --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step2.json @@ -0,0 +1,34 @@ +{ + "internal-dpl-clock": "", + "internal-dpl-aod-reader": { + "aod-file-private": "@input_data.txt", + "time-limit": "0", + "orbit-offset-enumeration": "0", + "orbit-multiplier-enumeration": "0", + "start-value-enumeration": "0", + "end-value-enumeration": "-1", + "step-value-enumeration": "1" + }, + "strangeness_derived_tutorial": { + "nBins": "100", + "cutzvertex": "10", + "cascadesetting_cospa": "0.998", + "cascadesetting_v0cospa": "0.96999999999999997", + "cascadesetting_dcacascdau": "1", + "cascadesetting_dcav0dau": "1", + "cascadesetting_dcabachtopv": "0.0599999987", + "cascadesetting_dcapostopv": "0.0599999987", + "cascadesetting_dcanegtopv": "0.0599999987", + "cascadesetting_mindcav0topv": "0.00999999978", + "cascadesetting_cascradius": "0.5", + "cascadesetting_v0radius": "1.20000005", + "cascadesetting_v0masswindow": "0.00800000038", + "cascadesetting_competingmassrej": "0.00800000038", + "NSigmaTPCPion": "3", + "NSigmaTPCKaon": "3", + "NSigmaTPCProton": "3" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step3.json b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step3.json new file mode 100644 index 00000000000..7a17dfb6429 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step3.json @@ -0,0 +1,212 @@ +{ + "internal-dpl-clock": "", + "internal-dpl-aod-reader": { + "aod-file-private": "@input_data.txt", + "time-limit": "0", + "orbit-offset-enumeration": "0", + "orbit-multiplier-enumeration": "0", + "start-value-enumeration": "0", + "end-value-enumeration": "-1", + "step-value-enumeration": "1" + }, + "strangenesstofpid": { + "v0Calibration.qaMassWindow": "0.005", + "axisP": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "axisRatioMethods": { + "values": [ + 400, + 0.8999999761581421, + 1.899999976158142 + ] + }, + "v0Calibration.qaCosPA": "0.999", + "rejectUndefinedTof": "1", + "v0Calibration.qaDCADau": "0.5", + "axisDeltaTime": { + "values": [ + 2000, + -1000, + 1000 + ] + }, + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "v0Calibration.qaTPCNSigma": "5", + "ccdb.lutPath": "GLO/Param/MatLUT", + "axisDeltaTimeVsPrimaryCalculation": { + "values": [ + 500, + -500, + 500 + ] + }, + "axisEta": { + "values": [ + 20, + -1, + 1 + ] + }, + "axisTimeLong": { + "values": [ + 3000, + -1500000, + 1500000 + ] + }, + "calculationMethod": "0", + "calculateCascades": "-1", + "cascadeCalibration.qaV0DCADau": "0.5", + "axisNSigma": { + "values": [ + 200, + -10, + 10 + ] + }, + "axisSmallP": { + "values": [ + 250, + 0, + 2.5 + ] + }, + "manualRunNumber": "544122", + "calculateV0TOFPIDs": "-1", + "cascadeCalibration.qaCascCosPA": "0.995", + "processDerivedData": "1", + "calculateV0s": "-1", + "cascadeCalibration.qaCascDCADau": "0.5", + "cascadeCalibration.qaMassWindow": "0.005", + "axisBCshift": { + "values": [ + 130, + -3006569.541579235, + 237032.45348549983 + ] + }, + "doBCshift": "1", + "useCustomRunNumber": "0", + "axisPosition": { + "values": [ + 400, + -400, + 400 + ] + }, + "processStandardData": "0", + "axisTime": { + "values": [ + 400, + 10000, + 50000 + ] + }, + "calculateCascTOFPIDs": "-1", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "calculateV0TOFDebugs": "-1", + "axisSnp": { + "values": [ + 220, + -1.100000023841858, + 1.100000023841858 + ] + }, + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "ccdb.grpPath": "GLO/GRP/GRP", + "doNSigmas": "1", + "calculateV0TOFBetas": "-1", + "reassociateTracks": "1", + "ccdb.nSigmaPath": "Users/d/ddobrigk/stratof", + "doQA": "0", + "cascadeCalibration.qaV0CosPA": "0.995", + "cascadeCalibration.qaTPCNSigma": "5", + "d_bz": "-999", + "tofPosition": "377.934", + "doQANSigma": "0" + }, + "strangeness_derived_tutorial": { + "nBins": "100", + "cutzvertex": "10", + "cascadesetting_cospa": "0.998", + "cascadesetting_v0cospa": "0.96999999999999997", + "cascadesetting_dcacascdau": "1", + "cascadesetting_dcav0dau": "1", + "cascadesetting_dcabachtopv": "0.0599999987", + "cascadesetting_dcapostopv": "0.0599999987", + "cascadesetting_dcanegtopv": "0.0599999987", + "cascadesetting_mindcav0topv": "0.00999999978", + "cascadesetting_cascradius": "0.5", + "cascadesetting_v0radius": "1.20000005", + "cascadesetting_v0masswindow": "0.00800000038", + "cascadesetting_competingmassrej": "0.00800000038", + "NSigmaTPCPion": "3", + "NSigmaTPCKaon": "3", + "NSigmaTPCProton": "3", + "NSigmaTOFPion": "3", + "NSigmaTOFKaon": "3", + "NSigmaTOFProton": "3" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step4.json b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step4.json new file mode 100644 index 00000000000..e0d4bcfffd5 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/configuration_step4.json @@ -0,0 +1,212 @@ +{ + "internal-dpl-clock": "", + "internal-dpl-aod-reader": { + "aod-file-private": "@input_data.txt", + "time-limit": "0", + "orbit-offset-enumeration": "0", + "orbit-multiplier-enumeration": "0", + "start-value-enumeration": "0", + "end-value-enumeration": "-1", + "step-value-enumeration": "1" + }, + "strangenesstofpid": { + "v0Calibration.qaMassWindow": "0.005", + "axisP": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "axisRatioMethods": { + "values": [ + 400, + 0.8999999761581421, + 1.899999976158142 + ] + }, + "v0Calibration.qaCosPA": "0.999", + "rejectUndefinedTof": "1", + "v0Calibration.qaDCADau": "0.5", + "axisDeltaTime": { + "values": [ + 2000, + -1000, + 1000 + ] + }, + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "v0Calibration.qaTPCNSigma": "5", + "ccdb.lutPath": "GLO/Param/MatLUT", + "axisDeltaTimeVsPrimaryCalculation": { + "values": [ + 500, + -500, + 500 + ] + }, + "axisEta": { + "values": [ + 20, + -1, + 1 + ] + }, + "axisTimeLong": { + "values": [ + 3000, + -1500000, + 1500000 + ] + }, + "calculationMethod": "0", + "calculateCascades": "1", + "cascadeCalibration.qaV0DCADau": "0.5", + "axisNSigma": { + "values": [ + 200, + -10, + 10 + ] + }, + "axisSmallP": { + "values": [ + 250, + 0, + 2.5 + ] + }, + "manualRunNumber": "544122", + "calculateV0TOFPIDs": "1", + "cascadeCalibration.qaCascCosPA": "0.995", + "processDerivedData": "1", + "calculateV0s": "-1", + "cascadeCalibration.qaCascDCADau": "0.5", + "cascadeCalibration.qaMassWindow": "0.005", + "axisBCshift": { + "values": [ + 130, + -3006569.541579235, + 237032.45348549983 + ] + }, + "doBCshift": "1", + "useCustomRunNumber": "0", + "axisPosition": { + "values": [ + 400, + -400, + 400 + ] + }, + "processStandardData": "0", + "axisTime": { + "values": [ + 400, + 10000, + 50000 + ] + }, + "calculateCascTOFPIDs": "1", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "calculateV0TOFDebugs": "1", + "axisSnp": { + "values": [ + 220, + -1.100000023841858, + 1.100000023841858 + ] + }, + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "ccdb.grpPath": "GLO/GRP/GRP", + "doNSigmas": "1", + "calculateV0TOFBetas": "-1", + "reassociateTracks": "1", + "ccdb.nSigmaPath": "Users/d/ddobrigk/stratof", + "doQA": "0", + "cascadeCalibration.qaV0CosPA": "0.995", + "cascadeCalibration.qaTPCNSigma": "5", + "d_bz": "-999", + "tofPosition": "377.934", + "doQANSigma": "0" + }, + "strangeness_derived_tutorial": { + "nBins": "100", + "cutzvertex": "10", + "cascadesetting_cospa": "0.998", + "cascadesetting_v0cospa": "0.96999999999999997", + "cascadesetting_dcacascdau": "1", + "cascadesetting_dcav0dau": "1", + "cascadesetting_dcabachtopv": "0.0599999987", + "cascadesetting_dcapostopv": "0.0599999987", + "cascadesetting_dcanegtopv": "0.0599999987", + "cascadesetting_mindcav0topv": "0.00999999978", + "cascadesetting_cascradius": "0.5", + "cascadesetting_v0radius": "1.20000005", + "cascadesetting_v0masswindow": "0.00800000038", + "cascadesetting_competingmassrej": "0.00800000038", + "NSigmaTPCPion": "3", + "NSigmaTPCKaon": "3", + "NSigmaTPCProton": "3", + "NSigmaTOFPion": "3", + "NSigmaTOFKaon": "3", + "NSigmaTOFProton": "3" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_skeleton.sh b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_skeleton.sh new file mode 100644 index 00000000000..ed8c18dc09c --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/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-derived-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/Derived/Analysis/run_step0.sh b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step0.sh new file mode 100644 index 00000000000..d916e41af6a --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step0.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="0" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step0.json" + +o2-analysistutorial-lf-strangeness-derived-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/Derived/Analysis/run_step1.sh b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step1.sh new file mode 100644 index 00000000000..f5f0b069d8b --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step1.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="1" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step1.json" + +o2-analysistutorial-lf-strangeness-derived-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/Derived/Analysis/run_step2.sh b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step2.sh new file mode 100644 index 00000000000..5729987a8c5 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step2.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="2" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step2.json" + +o2-analysistutorial-lf-strangeness-derived-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/Derived/Analysis/run_step3.sh b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step3.sh new file mode 100644 index 00000000000..e51731d18e4 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step3.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="3" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step3.json" + +o2-analysis-lf-strangenesstofpid ${OPTION} | o2-analysistutorial-lf-strangeness-derived-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/Derived/Analysis/run_step4.sh b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step4.sh new file mode 100644 index 00000000000..7b258879a22 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/run_step4.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="4" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step4.json" + +o2-analysis-lf-strangenesstofpid ${OPTION} | o2-analysistutorial-lf-strangeness-derived-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/Derived/Analysis/strangeness_derived_skeleton.cxx b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_skeleton.cxx new file mode 100644 index 00000000000..13b030a6b02 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_skeleton.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. +/// +/// \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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct strangeness_derived_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)"}; + + 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/Derived/Analysis/strangeness_derived_step0.cxx b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step0.cxx new file mode 100644 index 00000000000..fa3b71c7b35 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step0.cxx @@ -0,0 +1,84 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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_derived_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)"}; + + 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/Derived/Analysis/strangeness_derived_step1.cxx b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step1.cxx new file mode 100644 index 00000000000..f9211528626 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step1.cxx @@ -0,0 +1,144 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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_derived_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"}; + + 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 (std::abs(casc.mLambda() - o2::constants::physics::MassLambda) > 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 (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > 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/Derived/Analysis/strangeness_derived_step2.cxx b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step2.cxx new file mode 100644 index 00000000000..a52df4fc576 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step2.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. +/// +/// \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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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_derived_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"}; + + 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 (std::abs(casc.mLambda() - o2::constants::physics::MassLambda) > 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 (std::abs(posDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (std::abs(negDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } else { + if (std::abs(negDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (std::abs(posDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } + + // Fill histograms! (if possible) + if (std::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 (std::abs(bachDaughterTrackCasc.tpcNSigmaKa()) < NSigmaTPCKaon) { // Omega case + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > 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/Derived/Analysis/strangeness_derived_step3.cxx b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step3.cxx new file mode 100644 index 00000000000..8885e9ba425 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step3.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. +/// +/// \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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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_derived_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"}; + + 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 (std::abs(casc.mLambda() - o2::constants::physics::MassLambda) > 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 (std::abs(posDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (std::abs(negDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } else { + if (std::abs(negDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (std::abs(posDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } + + // TOF PID check + bool xiPassTOFSelection = true; + bool omegaPassTOFSelection = true; + if (casc.sign() < 0) { + if (casc.positiveHasTOF()) { + if (std::abs(casc.tofNSigmaXiLaPr()) > NSigmaTOFProton) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmLaPr()) > NSigmaTOFProton) { + omegaPassTOFSelection &= false; + } + } + if (casc.negativeHasTOF()) { + if (std::abs(casc.tofNSigmaXiLaPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmLaPi()) > NSigmaTOFPion) { + omegaPassTOFSelection &= false; + } + } + } else { + if (casc.positiveHasTOF()) { + if (std::abs(casc.tofNSigmaXiLaPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmLaPi()) > NSigmaTOFPion) { + omegaPassTOFSelection &= false; + } + } + if (casc.negativeHasTOF()) { + if (std::abs(casc.tofNSigmaXiLaPr()) > NSigmaTOFProton) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmLaPr()) > NSigmaTOFProton) { + omegaPassTOFSelection &= false; + } + } + } + + if (casc.bachelorHasTOF()) { + if (std::abs(casc.tofNSigmaXiPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmKa()) > NSigmaTOFKaon) { + omegaPassTOFSelection &= false; + } + } + + // Fill histograms! (if possible) + if (std::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 (std::abs(bachDaughterTrackCasc.tpcNSigmaKa()) < NSigmaTPCKaon) { // Omega case + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > 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/Derived/Analysis/strangeness_derived_step4.cxx b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step4.cxx new file mode 100644 index 00000000000..94169733f30 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/Analysis/strangeness_derived_step4.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. +/// +/// \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 "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.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_derived_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"}; + + 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 (std::abs(casc.mLambda() - o2::constants::physics::MassLambda) > 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 (std::abs(posDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (std::abs(negDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } else { + if (std::abs(negDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + continue; + } + if (std::abs(posDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + continue; + } + } + + // TOF PID check + bool xiPassTOFSelection = true; + bool omegaPassTOFSelection = true; + if (casc.sign() < 0) { + if (casc.positiveHasTOF()) { + if (std::abs(casc.tofNSigmaXiLaPr()) > NSigmaTOFProton) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmLaPr()) > NSigmaTOFProton) { + omegaPassTOFSelection &= false; + } + } + if (casc.negativeHasTOF()) { + if (std::abs(casc.tofNSigmaXiLaPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmLaPi()) > NSigmaTOFPion) { + omegaPassTOFSelection &= false; + } + } + } else { + if (casc.positiveHasTOF()) { + if (std::abs(casc.tofNSigmaXiLaPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmLaPi()) > NSigmaTOFPion) { + omegaPassTOFSelection &= false; + } + } + if (casc.negativeHasTOF()) { + if (std::abs(casc.tofNSigmaXiLaPr()) > NSigmaTOFProton) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmLaPr()) > NSigmaTOFProton) { + omegaPassTOFSelection &= false; + } + } + } + + if (casc.bachelorHasTOF()) { + if (std::abs(casc.tofNSigmaXiPi()) > NSigmaTOFPion) { + xiPassTOFSelection &= false; + } + if (std::abs(casc.tofNSigmaOmKa()) > NSigmaTOFKaon) { + omegaPassTOFSelection &= false; + } + } + + // Fill histograms! (if possible) + if (std::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 (std::abs(bachDaughterTrackCasc.tpcNSigmaKa()) < NSigmaTPCKaon) { // Omega case + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > 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 (std::abs(cascmccore.pdgCode()) == PDG_t::kXiMinus) { + if (std::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 (std::abs(cascmccore.pdgCode()) == PDG_t::kOmegaMinus) { + if (std::abs(bachDaughterTrackCasc.tpcNSigmaKa()) < NSigmaTPCKaon) { // Omega case + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > 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 (std::abs(cascmc.pdgCode()) == PDG_t::kXiMinus) { + rGenParticles.fill(HIST("hPtXiGen"), cascmc.ptMC()); + } + if (std::abs(cascmc.pdgCode()) == PDG_t::kOmegaMinus) { + rGenParticles.fill(HIST("hPtOmegaGen"), cascmc.ptMC()); + } + } + } + + PROCESS_SWITCH(strangeness_derived_tutorial, processRecMC, "Process Run 3 mc, reconstructed", true); + PROCESS_SWITCH(strangeness_derived_tutorial, processGenMC, "Process Run 3 mc, generated", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/Tutorials/PWGLF/Strangeness/Derived/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/Derived/CMakeLists.txt new file mode 100644 index 00000000000..f593f821726 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/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/Derived/DerivedDataProduction/Data/run.sh b/Tutorials/PWGLF/Strangeness/Derived/DerivedDataProduction/Data/run.sh new file mode 100644 index 00000000000..01daa27ed26 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/DerivedDataProduction/Data/run.sh @@ -0,0 +1,32 @@ +#!/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-trackselection ${OPTION} | +o2-analysis-ft0-corrected-table ${OPTION} | +o2-analysis-multcenttable ${OPTION} | +o2-analysis-event-selection-service ${OPTION} | +o2-analysis-pid-tpc-service ${OPTION} | +o2-analysis-pid-tof-merge ${OPTION} | +o2-analysis-propagationservice ${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/Derived/DerivedDataProduction/MC/runMC.sh b/Tutorials/PWGLF/Strangeness/Derived/DerivedDataProduction/MC/runMC.sh new file mode 100644 index 00000000000..94b0950c05e --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Derived/DerivedDataProduction/MC/runMC.sh @@ -0,0 +1,33 @@ +#!/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-trackselection ${OPTION} | +o2-analysis-ft0-corrected-table ${OPTION} | +o2-analysis-mccollisionextra ${OPTION} | +o2-analysis-multcenttable ${OPTION} | +o2-analysis-event-selection-service ${OPTION} | +o2-analysis-pid-tpc-service ${OPTION} | +o2-analysis-pid-tof-merge ${OPTION} | +o2-analysis-propagationservice ${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/Original/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/Original/CMakeLists.txt new file mode 100644 index 00000000000..2c0360b05d6 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/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. + +# Strangeness analysis tutorial +o2physics_add_dpl_workflow(strangeness-skeleton + SOURCES strangeness_skeleton.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +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/Original/configuration_skeleton.json b/Tutorials/PWGLF/Strangeness/Original/configuration_skeleton.json new file mode 100644 index 00000000000..f770087747e --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/configuration_skeleton.json @@ -0,0 +1,582 @@ +{ + "track-selection": { + "ptMax": "1e+10", + "produceTable": "-1", + "etaMin": "-1", + "isRun3": "1", + "itsMatching": "1", + "etaMax": "1", + "compatibilityIU": "0", + "dcaSetup": "0", + "ptMin": "0.1", + "produceFBextendedTable": "-1" + }, + "ft0-corrected-table": { + "ccdb-timestamp": "-1", + "resoFT0C": "20", + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "resoFT0A": "20", + "collisionSystem": "-2", + "addHistograms": "0", + "ccdb-url": "http://alice-ccdb.cern.ch", + "processWithBypassFT0timeInMC": "0", + "processStandard": "1" + }, + "mult-cent-table": { + "generatorName": "", + "processRun3WithGlobalCounters": "0", + "processMFT": "0", + "processRun3": "1", + "processCentralityRun2": "0", + "processRun2": "0", + "processMonteCarlo2Mults": "0", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "maxPtGlobalTrack": "1e+10", + "embedINELgtZEROselection": "0", + "minPtGlobalTrack": "0.15", + "autoConfigureProcess": "0", + "ccdbPathCentrality": "Centrality/Estimators", + "doVertexZeq": "1", + "ccdbPathVtxZ": "Centrality/Calibration", + "minNclsITSibGlobalTrack": "1", + "reconstructionPass": "", + "ccdburl": "http://alice-ccdb.cern.ch", + "processCentralityRun3": "1", + "minNclsITSGlobalTrack": "5", + "processMonteCarlo": "0" + }, + "eventselection-run3": { + "timestamp.fatalOnInvalidTimestamp": "0", + "evselOpts.NumberOfOrbitsPerTF": "-1", + "evselOpts.TimeRangeVetoOnCollNarrow": "0.25", + "evselOpts.VzDiffNsigma": "3", + "evselOpts.maxDiffZvtxFT0vsPV": "1", + "bcselOpts.checkRunDurationLimits": "0", + "evselOpts.amIneeded": "-1", + "evselOpts.EpsilonVzDiffVetoInROF": "0.3", + "evselOpts.isMC": "-1", + "bcselOpts.ITSROFrameStartBorderMargin": "-1", + "timestamp.isRun2MC": "-1", + "bcselOpts.TimeFrameStartBorderMargin": "-1", + "bcselOpts.triggerBcShift": "0", + "evselOpts.FT0CamplPerCollCutVetoOnCollInROF": "5000", + "timestamp.orbit-reset-path": "CTP/Calib/OrbitReset", + "evselOpts.TimeIntervalForOccupancyCalculationMin": "-40", + "evselOpts.TimeRangeVetoOnCollStrict": "10", + "timestamp.rct-path": "RCT/Info/RunInformation", + "bcselOpts.maxInactiveChipsPerLayer": { + "values": [ + 8, + 8, + 8, + 111, + 111, + 195, + 195 + ] + }, + "lumiOpts.amIneeded": "-1", + "evselOpts.confSigmaBCforHighPtTracks": "4", + "evselOpts.FT0CamplPerCollCutVetoOnCollInTimeRange": "8000", + "bcselOpts.ITSROFrameEndBorderMargin": "-1", + "evselOpts.VzDiffMargin": "0.2", + "bcselOpts.amIneeded": "-1", + "evselOpts.TimeIntervalForOccupancyCalculationMax": "100", + "ccdburl": "http://alice-ccdb.cern.ch", + "evselOpts.muonSelection": "0", + "evselOpts.UseWeightsForOccupancyEstimator": "1", + "timestamp.verbose": "0", + "bcselOpts.TimeFrameEndBorderMargin": "-1", + "bcselOpts.NumberOfOrbitsPerTF": "-1" + }, + "pid-tpc-service": { + "pidTPC.pid-tiny-mu": "-1", + "pidTPC.pid-tiny-el": "-1", + "pidTPC.ccdb-timestamp": "0", + "pidTPC.enableNetworkOptimizations": "1", + "pidTPC.pid-full-ka": "-1", + "pidTPC.skipTPCOnly": "-1", + "pidTPC.pid-tiny-al": "-1", + "pidTPC.networkPathCCDB": "Analysis/PID/TPC/ML", + "pidTPC.useNetworkAl": "0", + "pidTPC.autofetchNetworks": "1", + "pidTPC.useNetworkEl": "1", + "processTracksIU": "1", + "pidTPC.ccdbPath": "Analysis/PID/TPC/Response", + "pidTPC.useNetworkMu": "0", + "pidTPC.enableTuneOnDataTable": "-1", + "pidTPC.pid-full-mu": "-1", + "pidTPC.networkPathLocally": "network.onnx", + "processTracksIUWithTracksQA": "0", + "pidTPC.pid-full-el": "-1", + "pidTPC.pid-tiny-pi": "-1", + "pidTPC.ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "pidTPC.pid-tiny-tr": "-1", + "pidTPC.useNetworkDe": "0", + "pidTPC.pid-full-al": "-1", + "pidTPC.pid-tiny-he": "-1", + "pidTPC.useNetworkPr": "1", + "pidTPC.recoPass": "", + "pidTPC.pid-tiny-pr": "-1", + "pidTPC.useNetworkHe": "0", + "pidTPC.pid-tiny-de": "-1", + "pidTPC.useNetworkTr": "0", + "pidTPC.useNetworkPi": "1", + "pidTPC.pid-full-pi": "-1", + "pidTPC.useNetworkKa": "1", + "pidTPC.pid-full-he": "-1", + "pidTPC.pid-full-de": "-1", + "pidTPC.pid-full-tr": "-1", + "pidTPC.param-file": "", + "pidTPC.useCorrecteddEdx": "0", + "pidTPC.networkSetNumThreads": "0", + "pidTPC.pid-full-pr": "-1", + "pidTPC.pid-tiny-ka": "-1", + "pidTPC.networkBetaGammaCutoff": "0.45", + "pidTPC.devicesRequiringTPCOnlyPID": { + "values": [ + "photon-conversion-builder" + ] + }, + "pidTPC.useNetworkCorrection": "1", + "ccdburl": "http://alice-ccdb.cern.ch", + "pidTPC.savedEdxsCorrected": "-1", + "processTracksMCIU": "0" + }, + "propagation-service": { + "trackTuner.updateCurvature": "0", + "cascadeBuilderOpts.mc_findableDetachedCascade": "0", + "processMonteCarloWithPID": "0", + "cascadeBuilderOpts.minCrossedRows": "-1", + "preSelectOpts.preselectOnlyDesiredCascades": "1", + "v0BuilderOpts.mc_addGeneratedGammaMakeCollinear": "1", + "cascadeBuilderOpts.maxDaughterEta": "1.5", + "ccdb.lutPath": "GLO/Param/MatLUTInner", + "v0BuilderOpts.mc_addGeneratedK0Short": "0", + "cascadeBuilderOpts.dcabachtopv": "0.05", + "trackTuner.updateTrackCovMat": "0", + "cascadeBuilderOpts.useCascadeMomentumAtPrimVtx": "0", + "cascadeBuilderOpts.mc_addGeneratedOmegaPlus": "0", + "cascadeBuilderOpts.kfUseV0MassConstraint": "1", + "trackPropagation.fillTrackTunerTable": "0", + "v0BuilderOpts.v0radius": "0.9", + "cascadeBuilderOpts.kfConstructMethod": "2", + "v0BuilderOpts.dcanegtopv": "0.05", + "v0BuilderOpts.mc_addGeneratedLambda": "0", + "cascadeBuilderOpts.casccospa": "0.97", + "cascadeBuilderOpts.mc_addGeneratedOmegaMinus": "0", + "preSelectOpts.lifetimeCut": { + "values": [ + [ + 20, + 60, + 40, + 20 + ] + ] + }, + "trackPropagation.useTrackTuner": "0", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "preSelectOpts.maxTPCpidNsigma": "5", + "trackTuner.updateTrackDCAs": "0", + "cascadeBuilderOpts.kfTuneForOmega": "0", + "trackTuner.pathInputFile": "", + "preSelectOpts.preselectOnlyDesiredV0s": "1", + "preSelectOpts.massWindowSafetyMargin": "0.001", + "trackTuner.updateCurvatureIU": "0", + "cascadeBuilderOpts.mc_addGeneratedXiPlus": "0", + "preSelectOpts.massCutXi": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "trackPropagation.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.", + "v0BuilderOpts.minCrossedRows": "-1", + "processRealDataWithPID": "1", + "trackPropagation.trackTunerConfigSource": "1", + "refitWithMaterialCorrection": "0", + "cascadeBuilderOpts.cascradius": "0.9", + "cascadeBuilderOpts.mc_treatPiToMuDecays": "1", + "processRealData": "0", + "v0BuilderOpts.mc_populateV0MCCoresSymmetric": "1", + "preSelectOpts.massWindownumberOfSigmas": "20", + "trackTuner.usePvRefitCorrections": "0", + "v0BuilderOpts.mc_addGeneratedGamma": "0", + "v0BuilderOpts.moveTPCOnlyTracks": "1", + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "v0BuilderOpts.dcav0dau": "1.5", + "v0BuilderOpts.mc_keepOnlyPhysicalPrimary": "0", + "cascadeBuilderOpts.mc_rapidityWindow": "0.5", + "trackTuner.isInputFileFromCCDB": "0", + "trackTuner.nameInputFile": "", + "v0BuilderOpts.maxDaughterEta": "1.5", + "useV0BufferForCascades": "0", + "v0BuilderOpts.mc_addGeneratedAntiLambda": "0", + "v0BuilderOpts.v0cospa": "0.97", + "deduplicationAlgorithm": "1", + "cascadeBuilderOpts.lambdaMassWindow": "0.01", + "preSelectOpts.massCutOm": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "cascadeBuilderOpts.dcacascdau": "1.5", + "trackTuner.updatePulls": "0", + "processMonteCarlo": "0", + "v0BuilderOpts.mc_populateV0MCCoresAsymmetric": "0", + "preSelectOpts.massCutLambda": { + "values": [ + [ + 0.0011751799611374736, + 0.00012409899500198662, + 0.005479369778186083, + 0.30800899863243103 + ] + ] + }, + "trackTuner.nPhiBins": "0", + "cascadeBuilderOpts.mc_populateCascMCCoresSymmetric": "1", + "v0BuilderOpts.generatePhotonCandidates": "1", + "preSelectOpts.massCutK0": { + "values": [ + [ + 0.0028188200667500496, + 0.0011405700352042913, + 0.0017213800456374884, + 0.5002620220184326 + ] + ] + }, + "trackTuner.pathFileQoverPt": "", + "trackTuner.qOverPtMC": "-1", + "v0BuilderOpts.mc_rapidityWindow": "0.5", + "trackPropagation.axisPtQA": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "cascadeBuilderOpts.kfDoDCAFitterPreMinimCasc": "1", + "v0BuilderOpts.dcapostopv": "0.05", + "preSelectOpts.massCutPhoton": "0.3", + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "cascadeBuilderOpts.kfDoDCAFitterPreMinimV0": "1", + "cascadeBuilderOpts.mc_populateCascMCCoresAsymmetric": "0", + "v0BuilderOpts.mc_findableDetachedV0": "0", + "trackPropagation.useTrkPid": "0", + "trackTuner.nameFileQoverPt": "", + "cascadeBuilderOpts.kfUseCascadeMassConstraint": "0", + "trackTuner.qOverPtData": "-1", + "v0BuilderOpts.mc_treatPiToMuDecays": "1", + "trackTuner.debugInfo": "0", + "trackPropagation.minPropagationDistance": "5", + "ccdburl": "http://alice-ccdb.cern.ch", + "cascadeBuilderOpts.mc_keepOnlyPhysicalPrimary": "0", + "cascadeBuilderOpts.mc_addGeneratedXiMinus": "0", + "mc_findableMode": "0" + }, + "strangeness_tutorial": { + "nBins": "100", + "cutzvertex": "10" + } +} diff --git a/Tutorials/PWGLF/Strangeness/Original/configuration_step0.json b/Tutorials/PWGLF/Strangeness/Original/configuration_step0.json new file mode 100644 index 00000000000..f770087747e --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/configuration_step0.json @@ -0,0 +1,582 @@ +{ + "track-selection": { + "ptMax": "1e+10", + "produceTable": "-1", + "etaMin": "-1", + "isRun3": "1", + "itsMatching": "1", + "etaMax": "1", + "compatibilityIU": "0", + "dcaSetup": "0", + "ptMin": "0.1", + "produceFBextendedTable": "-1" + }, + "ft0-corrected-table": { + "ccdb-timestamp": "-1", + "resoFT0C": "20", + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "resoFT0A": "20", + "collisionSystem": "-2", + "addHistograms": "0", + "ccdb-url": "http://alice-ccdb.cern.ch", + "processWithBypassFT0timeInMC": "0", + "processStandard": "1" + }, + "mult-cent-table": { + "generatorName": "", + "processRun3WithGlobalCounters": "0", + "processMFT": "0", + "processRun3": "1", + "processCentralityRun2": "0", + "processRun2": "0", + "processMonteCarlo2Mults": "0", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "maxPtGlobalTrack": "1e+10", + "embedINELgtZEROselection": "0", + "minPtGlobalTrack": "0.15", + "autoConfigureProcess": "0", + "ccdbPathCentrality": "Centrality/Estimators", + "doVertexZeq": "1", + "ccdbPathVtxZ": "Centrality/Calibration", + "minNclsITSibGlobalTrack": "1", + "reconstructionPass": "", + "ccdburl": "http://alice-ccdb.cern.ch", + "processCentralityRun3": "1", + "minNclsITSGlobalTrack": "5", + "processMonteCarlo": "0" + }, + "eventselection-run3": { + "timestamp.fatalOnInvalidTimestamp": "0", + "evselOpts.NumberOfOrbitsPerTF": "-1", + "evselOpts.TimeRangeVetoOnCollNarrow": "0.25", + "evselOpts.VzDiffNsigma": "3", + "evselOpts.maxDiffZvtxFT0vsPV": "1", + "bcselOpts.checkRunDurationLimits": "0", + "evselOpts.amIneeded": "-1", + "evselOpts.EpsilonVzDiffVetoInROF": "0.3", + "evselOpts.isMC": "-1", + "bcselOpts.ITSROFrameStartBorderMargin": "-1", + "timestamp.isRun2MC": "-1", + "bcselOpts.TimeFrameStartBorderMargin": "-1", + "bcselOpts.triggerBcShift": "0", + "evselOpts.FT0CamplPerCollCutVetoOnCollInROF": "5000", + "timestamp.orbit-reset-path": "CTP/Calib/OrbitReset", + "evselOpts.TimeIntervalForOccupancyCalculationMin": "-40", + "evselOpts.TimeRangeVetoOnCollStrict": "10", + "timestamp.rct-path": "RCT/Info/RunInformation", + "bcselOpts.maxInactiveChipsPerLayer": { + "values": [ + 8, + 8, + 8, + 111, + 111, + 195, + 195 + ] + }, + "lumiOpts.amIneeded": "-1", + "evselOpts.confSigmaBCforHighPtTracks": "4", + "evselOpts.FT0CamplPerCollCutVetoOnCollInTimeRange": "8000", + "bcselOpts.ITSROFrameEndBorderMargin": "-1", + "evselOpts.VzDiffMargin": "0.2", + "bcselOpts.amIneeded": "-1", + "evselOpts.TimeIntervalForOccupancyCalculationMax": "100", + "ccdburl": "http://alice-ccdb.cern.ch", + "evselOpts.muonSelection": "0", + "evselOpts.UseWeightsForOccupancyEstimator": "1", + "timestamp.verbose": "0", + "bcselOpts.TimeFrameEndBorderMargin": "-1", + "bcselOpts.NumberOfOrbitsPerTF": "-1" + }, + "pid-tpc-service": { + "pidTPC.pid-tiny-mu": "-1", + "pidTPC.pid-tiny-el": "-1", + "pidTPC.ccdb-timestamp": "0", + "pidTPC.enableNetworkOptimizations": "1", + "pidTPC.pid-full-ka": "-1", + "pidTPC.skipTPCOnly": "-1", + "pidTPC.pid-tiny-al": "-1", + "pidTPC.networkPathCCDB": "Analysis/PID/TPC/ML", + "pidTPC.useNetworkAl": "0", + "pidTPC.autofetchNetworks": "1", + "pidTPC.useNetworkEl": "1", + "processTracksIU": "1", + "pidTPC.ccdbPath": "Analysis/PID/TPC/Response", + "pidTPC.useNetworkMu": "0", + "pidTPC.enableTuneOnDataTable": "-1", + "pidTPC.pid-full-mu": "-1", + "pidTPC.networkPathLocally": "network.onnx", + "processTracksIUWithTracksQA": "0", + "pidTPC.pid-full-el": "-1", + "pidTPC.pid-tiny-pi": "-1", + "pidTPC.ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "pidTPC.pid-tiny-tr": "-1", + "pidTPC.useNetworkDe": "0", + "pidTPC.pid-full-al": "-1", + "pidTPC.pid-tiny-he": "-1", + "pidTPC.useNetworkPr": "1", + "pidTPC.recoPass": "", + "pidTPC.pid-tiny-pr": "-1", + "pidTPC.useNetworkHe": "0", + "pidTPC.pid-tiny-de": "-1", + "pidTPC.useNetworkTr": "0", + "pidTPC.useNetworkPi": "1", + "pidTPC.pid-full-pi": "-1", + "pidTPC.useNetworkKa": "1", + "pidTPC.pid-full-he": "-1", + "pidTPC.pid-full-de": "-1", + "pidTPC.pid-full-tr": "-1", + "pidTPC.param-file": "", + "pidTPC.useCorrecteddEdx": "0", + "pidTPC.networkSetNumThreads": "0", + "pidTPC.pid-full-pr": "-1", + "pidTPC.pid-tiny-ka": "-1", + "pidTPC.networkBetaGammaCutoff": "0.45", + "pidTPC.devicesRequiringTPCOnlyPID": { + "values": [ + "photon-conversion-builder" + ] + }, + "pidTPC.useNetworkCorrection": "1", + "ccdburl": "http://alice-ccdb.cern.ch", + "pidTPC.savedEdxsCorrected": "-1", + "processTracksMCIU": "0" + }, + "propagation-service": { + "trackTuner.updateCurvature": "0", + "cascadeBuilderOpts.mc_findableDetachedCascade": "0", + "processMonteCarloWithPID": "0", + "cascadeBuilderOpts.minCrossedRows": "-1", + "preSelectOpts.preselectOnlyDesiredCascades": "1", + "v0BuilderOpts.mc_addGeneratedGammaMakeCollinear": "1", + "cascadeBuilderOpts.maxDaughterEta": "1.5", + "ccdb.lutPath": "GLO/Param/MatLUTInner", + "v0BuilderOpts.mc_addGeneratedK0Short": "0", + "cascadeBuilderOpts.dcabachtopv": "0.05", + "trackTuner.updateTrackCovMat": "0", + "cascadeBuilderOpts.useCascadeMomentumAtPrimVtx": "0", + "cascadeBuilderOpts.mc_addGeneratedOmegaPlus": "0", + "cascadeBuilderOpts.kfUseV0MassConstraint": "1", + "trackPropagation.fillTrackTunerTable": "0", + "v0BuilderOpts.v0radius": "0.9", + "cascadeBuilderOpts.kfConstructMethod": "2", + "v0BuilderOpts.dcanegtopv": "0.05", + "v0BuilderOpts.mc_addGeneratedLambda": "0", + "cascadeBuilderOpts.casccospa": "0.97", + "cascadeBuilderOpts.mc_addGeneratedOmegaMinus": "0", + "preSelectOpts.lifetimeCut": { + "values": [ + [ + 20, + 60, + 40, + 20 + ] + ] + }, + "trackPropagation.useTrackTuner": "0", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "preSelectOpts.maxTPCpidNsigma": "5", + "trackTuner.updateTrackDCAs": "0", + "cascadeBuilderOpts.kfTuneForOmega": "0", + "trackTuner.pathInputFile": "", + "preSelectOpts.preselectOnlyDesiredV0s": "1", + "preSelectOpts.massWindowSafetyMargin": "0.001", + "trackTuner.updateCurvatureIU": "0", + "cascadeBuilderOpts.mc_addGeneratedXiPlus": "0", + "preSelectOpts.massCutXi": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "trackPropagation.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.", + "v0BuilderOpts.minCrossedRows": "-1", + "processRealDataWithPID": "1", + "trackPropagation.trackTunerConfigSource": "1", + "refitWithMaterialCorrection": "0", + "cascadeBuilderOpts.cascradius": "0.9", + "cascadeBuilderOpts.mc_treatPiToMuDecays": "1", + "processRealData": "0", + "v0BuilderOpts.mc_populateV0MCCoresSymmetric": "1", + "preSelectOpts.massWindownumberOfSigmas": "20", + "trackTuner.usePvRefitCorrections": "0", + "v0BuilderOpts.mc_addGeneratedGamma": "0", + "v0BuilderOpts.moveTPCOnlyTracks": "1", + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "v0BuilderOpts.dcav0dau": "1.5", + "v0BuilderOpts.mc_keepOnlyPhysicalPrimary": "0", + "cascadeBuilderOpts.mc_rapidityWindow": "0.5", + "trackTuner.isInputFileFromCCDB": "0", + "trackTuner.nameInputFile": "", + "v0BuilderOpts.maxDaughterEta": "1.5", + "useV0BufferForCascades": "0", + "v0BuilderOpts.mc_addGeneratedAntiLambda": "0", + "v0BuilderOpts.v0cospa": "0.97", + "deduplicationAlgorithm": "1", + "cascadeBuilderOpts.lambdaMassWindow": "0.01", + "preSelectOpts.massCutOm": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "cascadeBuilderOpts.dcacascdau": "1.5", + "trackTuner.updatePulls": "0", + "processMonteCarlo": "0", + "v0BuilderOpts.mc_populateV0MCCoresAsymmetric": "0", + "preSelectOpts.massCutLambda": { + "values": [ + [ + 0.0011751799611374736, + 0.00012409899500198662, + 0.005479369778186083, + 0.30800899863243103 + ] + ] + }, + "trackTuner.nPhiBins": "0", + "cascadeBuilderOpts.mc_populateCascMCCoresSymmetric": "1", + "v0BuilderOpts.generatePhotonCandidates": "1", + "preSelectOpts.massCutK0": { + "values": [ + [ + 0.0028188200667500496, + 0.0011405700352042913, + 0.0017213800456374884, + 0.5002620220184326 + ] + ] + }, + "trackTuner.pathFileQoverPt": "", + "trackTuner.qOverPtMC": "-1", + "v0BuilderOpts.mc_rapidityWindow": "0.5", + "trackPropagation.axisPtQA": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "cascadeBuilderOpts.kfDoDCAFitterPreMinimCasc": "1", + "v0BuilderOpts.dcapostopv": "0.05", + "preSelectOpts.massCutPhoton": "0.3", + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "cascadeBuilderOpts.kfDoDCAFitterPreMinimV0": "1", + "cascadeBuilderOpts.mc_populateCascMCCoresAsymmetric": "0", + "v0BuilderOpts.mc_findableDetachedV0": "0", + "trackPropagation.useTrkPid": "0", + "trackTuner.nameFileQoverPt": "", + "cascadeBuilderOpts.kfUseCascadeMassConstraint": "0", + "trackTuner.qOverPtData": "-1", + "v0BuilderOpts.mc_treatPiToMuDecays": "1", + "trackTuner.debugInfo": "0", + "trackPropagation.minPropagationDistance": "5", + "ccdburl": "http://alice-ccdb.cern.ch", + "cascadeBuilderOpts.mc_keepOnlyPhysicalPrimary": "0", + "cascadeBuilderOpts.mc_addGeneratedXiMinus": "0", + "mc_findableMode": "0" + }, + "strangeness_tutorial": { + "nBins": "100", + "cutzvertex": "10" + } +} diff --git a/Tutorials/PWGLF/Strangeness/Original/configuration_step1.json b/Tutorials/PWGLF/Strangeness/Original/configuration_step1.json new file mode 100644 index 00000000000..9ee497ae15f --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/configuration_step1.json @@ -0,0 +1,587 @@ +{ + "track-selection": { + "ptMax": "1e+10", + "produceTable": "-1", + "etaMin": "-1", + "isRun3": "1", + "itsMatching": "1", + "etaMax": "1", + "compatibilityIU": "0", + "dcaSetup": "0", + "ptMin": "0.1", + "produceFBextendedTable": "-1" + }, + "ft0-corrected-table": { + "ccdb-timestamp": "-1", + "resoFT0C": "20", + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "resoFT0A": "20", + "collisionSystem": "-2", + "addHistograms": "0", + "ccdb-url": "http://alice-ccdb.cern.ch", + "processWithBypassFT0timeInMC": "0", + "processStandard": "1" + }, + "mult-cent-table": { + "generatorName": "", + "processRun3WithGlobalCounters": "0", + "processMFT": "0", + "processRun3": "1", + "processCentralityRun2": "0", + "processRun2": "0", + "processMonteCarlo2Mults": "0", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "maxPtGlobalTrack": "1e+10", + "embedINELgtZEROselection": "0", + "minPtGlobalTrack": "0.15", + "autoConfigureProcess": "0", + "ccdbPathCentrality": "Centrality/Estimators", + "doVertexZeq": "1", + "ccdbPathVtxZ": "Centrality/Calibration", + "minNclsITSibGlobalTrack": "1", + "reconstructionPass": "", + "ccdburl": "http://alice-ccdb.cern.ch", + "processCentralityRun3": "1", + "minNclsITSGlobalTrack": "5", + "processMonteCarlo": "0" + }, + "eventselection-run3": { + "timestamp.fatalOnInvalidTimestamp": "0", + "evselOpts.NumberOfOrbitsPerTF": "-1", + "evselOpts.TimeRangeVetoOnCollNarrow": "0.25", + "evselOpts.VzDiffNsigma": "3", + "evselOpts.maxDiffZvtxFT0vsPV": "1", + "bcselOpts.checkRunDurationLimits": "0", + "evselOpts.amIneeded": "-1", + "evselOpts.EpsilonVzDiffVetoInROF": "0.3", + "evselOpts.isMC": "-1", + "bcselOpts.ITSROFrameStartBorderMargin": "-1", + "timestamp.isRun2MC": "-1", + "bcselOpts.TimeFrameStartBorderMargin": "-1", + "bcselOpts.triggerBcShift": "0", + "evselOpts.FT0CamplPerCollCutVetoOnCollInROF": "5000", + "timestamp.orbit-reset-path": "CTP/Calib/OrbitReset", + "evselOpts.TimeIntervalForOccupancyCalculationMin": "-40", + "evselOpts.TimeRangeVetoOnCollStrict": "10", + "timestamp.rct-path": "RCT/Info/RunInformation", + "bcselOpts.maxInactiveChipsPerLayer": { + "values": [ + 8, + 8, + 8, + 111, + 111, + 195, + 195 + ] + }, + "lumiOpts.amIneeded": "-1", + "evselOpts.confSigmaBCforHighPtTracks": "4", + "evselOpts.FT0CamplPerCollCutVetoOnCollInTimeRange": "8000", + "bcselOpts.ITSROFrameEndBorderMargin": "-1", + "evselOpts.VzDiffMargin": "0.2", + "bcselOpts.amIneeded": "-1", + "evselOpts.TimeIntervalForOccupancyCalculationMax": "100", + "ccdburl": "http://alice-ccdb.cern.ch", + "evselOpts.muonSelection": "0", + "evselOpts.UseWeightsForOccupancyEstimator": "1", + "timestamp.verbose": "0", + "bcselOpts.TimeFrameEndBorderMargin": "-1", + "bcselOpts.NumberOfOrbitsPerTF": "-1" + }, + "pid-tpc-service": { + "pidTPC.pid-tiny-mu": "-1", + "pidTPC.pid-tiny-el": "-1", + "pidTPC.ccdb-timestamp": "0", + "pidTPC.enableNetworkOptimizations": "1", + "pidTPC.pid-full-ka": "-1", + "pidTPC.skipTPCOnly": "-1", + "pidTPC.pid-tiny-al": "-1", + "pidTPC.networkPathCCDB": "Analysis/PID/TPC/ML", + "pidTPC.useNetworkAl": "0", + "pidTPC.autofetchNetworks": "1", + "pidTPC.useNetworkEl": "1", + "processTracksIU": "1", + "pidTPC.ccdbPath": "Analysis/PID/TPC/Response", + "pidTPC.useNetworkMu": "0", + "pidTPC.enableTuneOnDataTable": "-1", + "pidTPC.pid-full-mu": "-1", + "pidTPC.networkPathLocally": "network.onnx", + "processTracksIUWithTracksQA": "0", + "pidTPC.pid-full-el": "-1", + "pidTPC.pid-tiny-pi": "-1", + "pidTPC.ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "pidTPC.pid-tiny-tr": "-1", + "pidTPC.useNetworkDe": "0", + "pidTPC.pid-full-al": "-1", + "pidTPC.pid-tiny-he": "-1", + "pidTPC.useNetworkPr": "1", + "pidTPC.recoPass": "", + "pidTPC.pid-tiny-pr": "-1", + "pidTPC.useNetworkHe": "0", + "pidTPC.pid-tiny-de": "-1", + "pidTPC.useNetworkTr": "0", + "pidTPC.useNetworkPi": "1", + "pidTPC.pid-full-pi": "-1", + "pidTPC.useNetworkKa": "1", + "pidTPC.pid-full-he": "-1", + "pidTPC.pid-full-de": "-1", + "pidTPC.pid-full-tr": "-1", + "pidTPC.param-file": "", + "pidTPC.useCorrecteddEdx": "0", + "pidTPC.networkSetNumThreads": "0", + "pidTPC.pid-full-pr": "-1", + "pidTPC.pid-tiny-ka": "-1", + "pidTPC.networkBetaGammaCutoff": "0.45", + "pidTPC.devicesRequiringTPCOnlyPID": { + "values": [ + "photon-conversion-builder" + ] + }, + "pidTPC.useNetworkCorrection": "1", + "ccdburl": "http://alice-ccdb.cern.ch", + "pidTPC.savedEdxsCorrected": "-1", + "processTracksMCIU": "0" + }, + "propagation-service": { + "trackTuner.updateCurvature": "0", + "cascadeBuilderOpts.mc_findableDetachedCascade": "0", + "processMonteCarloWithPID": "0", + "cascadeBuilderOpts.minCrossedRows": "-1", + "preSelectOpts.preselectOnlyDesiredCascades": "1", + "v0BuilderOpts.mc_addGeneratedGammaMakeCollinear": "1", + "cascadeBuilderOpts.maxDaughterEta": "1.5", + "ccdb.lutPath": "GLO/Param/MatLUTInner", + "v0BuilderOpts.mc_addGeneratedK0Short": "0", + "cascadeBuilderOpts.dcabachtopv": "0.05", + "trackTuner.updateTrackCovMat": "0", + "cascadeBuilderOpts.useCascadeMomentumAtPrimVtx": "0", + "cascadeBuilderOpts.mc_addGeneratedOmegaPlus": "0", + "cascadeBuilderOpts.kfUseV0MassConstraint": "1", + "trackPropagation.fillTrackTunerTable": "0", + "v0BuilderOpts.v0radius": "0.9", + "cascadeBuilderOpts.kfConstructMethod": "2", + "v0BuilderOpts.dcanegtopv": "0.05", + "v0BuilderOpts.mc_addGeneratedLambda": "0", + "cascadeBuilderOpts.casccospa": "0.97", + "cascadeBuilderOpts.mc_addGeneratedOmegaMinus": "0", + "preSelectOpts.lifetimeCut": { + "values": [ + [ + 20, + 60, + 40, + 20 + ] + ] + }, + "trackPropagation.useTrackTuner": "0", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "preSelectOpts.maxTPCpidNsigma": "5", + "trackTuner.updateTrackDCAs": "0", + "cascadeBuilderOpts.kfTuneForOmega": "0", + "trackTuner.pathInputFile": "", + "preSelectOpts.preselectOnlyDesiredV0s": "1", + "preSelectOpts.massWindowSafetyMargin": "0.001", + "trackTuner.updateCurvatureIU": "0", + "cascadeBuilderOpts.mc_addGeneratedXiPlus": "0", + "preSelectOpts.massCutXi": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "trackPropagation.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.", + "v0BuilderOpts.minCrossedRows": "-1", + "processRealDataWithPID": "1", + "trackPropagation.trackTunerConfigSource": "1", + "refitWithMaterialCorrection": "0", + "cascadeBuilderOpts.cascradius": "0.9", + "cascadeBuilderOpts.mc_treatPiToMuDecays": "1", + "processRealData": "0", + "v0BuilderOpts.mc_populateV0MCCoresSymmetric": "1", + "preSelectOpts.massWindownumberOfSigmas": "20", + "trackTuner.usePvRefitCorrections": "0", + "v0BuilderOpts.mc_addGeneratedGamma": "0", + "v0BuilderOpts.moveTPCOnlyTracks": "1", + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "v0BuilderOpts.dcav0dau": "1.5", + "v0BuilderOpts.mc_keepOnlyPhysicalPrimary": "0", + "cascadeBuilderOpts.mc_rapidityWindow": "0.5", + "trackTuner.isInputFileFromCCDB": "0", + "trackTuner.nameInputFile": "", + "v0BuilderOpts.maxDaughterEta": "1.5", + "useV0BufferForCascades": "0", + "v0BuilderOpts.mc_addGeneratedAntiLambda": "0", + "v0BuilderOpts.v0cospa": "0.97", + "deduplicationAlgorithm": "1", + "cascadeBuilderOpts.lambdaMassWindow": "0.01", + "preSelectOpts.massCutOm": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "cascadeBuilderOpts.dcacascdau": "1.5", + "trackTuner.updatePulls": "0", + "processMonteCarlo": "0", + "v0BuilderOpts.mc_populateV0MCCoresAsymmetric": "0", + "preSelectOpts.massCutLambda": { + "values": [ + [ + 0.0011751799611374736, + 0.00012409899500198662, + 0.005479369778186083, + 0.30800899863243103 + ] + ] + }, + "trackTuner.nPhiBins": "0", + "cascadeBuilderOpts.mc_populateCascMCCoresSymmetric": "1", + "v0BuilderOpts.generatePhotonCandidates": "1", + "preSelectOpts.massCutK0": { + "values": [ + [ + 0.0028188200667500496, + 0.0011405700352042913, + 0.0017213800456374884, + 0.5002620220184326 + ] + ] + }, + "trackTuner.pathFileQoverPt": "", + "trackTuner.qOverPtMC": "-1", + "v0BuilderOpts.mc_rapidityWindow": "0.5", + "trackPropagation.axisPtQA": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "cascadeBuilderOpts.kfDoDCAFitterPreMinimCasc": "1", + "v0BuilderOpts.dcapostopv": "0.05", + "preSelectOpts.massCutPhoton": "0.3", + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "cascadeBuilderOpts.kfDoDCAFitterPreMinimV0": "1", + "cascadeBuilderOpts.mc_populateCascMCCoresAsymmetric": "0", + "v0BuilderOpts.mc_findableDetachedV0": "0", + "trackPropagation.useTrkPid": "0", + "trackTuner.nameFileQoverPt": "", + "cascadeBuilderOpts.kfUseCascadeMassConstraint": "0", + "trackTuner.qOverPtData": "-1", + "v0BuilderOpts.mc_treatPiToMuDecays": "1", + "trackTuner.debugInfo": "0", + "trackPropagation.minPropagationDistance": "5", + "ccdburl": "http://alice-ccdb.cern.ch", + "cascadeBuilderOpts.mc_keepOnlyPhysicalPrimary": "0", + "cascadeBuilderOpts.mc_addGeneratedXiMinus": "0", + "mc_findableMode": "0" + }, + "strangeness_tutorial": { + "nBins": "100", + "cutzvertex": "10", + "v0setting_dcav0dau": "1", + "v0setting_dcapostopv": "0.06", + "v0setting_dcanegtopv": "0.06", + "v0setting_cospa": "0.998", + "v0setting_radius": "1.2" + } +} diff --git a/Tutorials/PWGLF/Strangeness/Original/configuration_step2.json b/Tutorials/PWGLF/Strangeness/Original/configuration_step2.json new file mode 100644 index 00000000000..a1b124d0ae7 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/configuration_step2.json @@ -0,0 +1,588 @@ +{ + "track-selection": { + "ptMax": "1e+10", + "produceTable": "-1", + "etaMin": "-1", + "isRun3": "1", + "itsMatching": "1", + "etaMax": "1", + "compatibilityIU": "0", + "dcaSetup": "0", + "ptMin": "0.1", + "produceFBextendedTable": "-1" + }, + "ft0-corrected-table": { + "ccdb-timestamp": "-1", + "resoFT0C": "20", + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "resoFT0A": "20", + "collisionSystem": "-2", + "addHistograms": "0", + "ccdb-url": "http://alice-ccdb.cern.ch", + "processWithBypassFT0timeInMC": "0", + "processStandard": "1" + }, + "mult-cent-table": { + "generatorName": "", + "processRun3WithGlobalCounters": "0", + "processMFT": "0", + "processRun3": "1", + "processCentralityRun2": "0", + "processRun2": "0", + "processMonteCarlo2Mults": "0", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "maxPtGlobalTrack": "1e+10", + "embedINELgtZEROselection": "0", + "minPtGlobalTrack": "0.15", + "autoConfigureProcess": "0", + "ccdbPathCentrality": "Centrality/Estimators", + "doVertexZeq": "1", + "ccdbPathVtxZ": "Centrality/Calibration", + "minNclsITSibGlobalTrack": "1", + "reconstructionPass": "", + "ccdburl": "http://alice-ccdb.cern.ch", + "processCentralityRun3": "1", + "minNclsITSGlobalTrack": "5", + "processMonteCarlo": "0" + }, + "eventselection-run3": { + "timestamp.fatalOnInvalidTimestamp": "0", + "evselOpts.NumberOfOrbitsPerTF": "-1", + "evselOpts.TimeRangeVetoOnCollNarrow": "0.25", + "evselOpts.VzDiffNsigma": "3", + "evselOpts.maxDiffZvtxFT0vsPV": "1", + "bcselOpts.checkRunDurationLimits": "0", + "evselOpts.amIneeded": "-1", + "evselOpts.EpsilonVzDiffVetoInROF": "0.3", + "evselOpts.isMC": "-1", + "bcselOpts.ITSROFrameStartBorderMargin": "-1", + "timestamp.isRun2MC": "-1", + "bcselOpts.TimeFrameStartBorderMargin": "-1", + "bcselOpts.triggerBcShift": "0", + "evselOpts.FT0CamplPerCollCutVetoOnCollInROF": "5000", + "timestamp.orbit-reset-path": "CTP/Calib/OrbitReset", + "evselOpts.TimeIntervalForOccupancyCalculationMin": "-40", + "evselOpts.TimeRangeVetoOnCollStrict": "10", + "timestamp.rct-path": "RCT/Info/RunInformation", + "bcselOpts.maxInactiveChipsPerLayer": { + "values": [ + 8, + 8, + 8, + 111, + 111, + 195, + 195 + ] + }, + "lumiOpts.amIneeded": "-1", + "evselOpts.confSigmaBCforHighPtTracks": "4", + "evselOpts.FT0CamplPerCollCutVetoOnCollInTimeRange": "8000", + "bcselOpts.ITSROFrameEndBorderMargin": "-1", + "evselOpts.VzDiffMargin": "0.2", + "bcselOpts.amIneeded": "-1", + "evselOpts.TimeIntervalForOccupancyCalculationMax": "100", + "ccdburl": "http://alice-ccdb.cern.ch", + "evselOpts.muonSelection": "0", + "evselOpts.UseWeightsForOccupancyEstimator": "1", + "timestamp.verbose": "0", + "bcselOpts.TimeFrameEndBorderMargin": "-1", + "bcselOpts.NumberOfOrbitsPerTF": "-1" + }, + "pid-tpc-service": { + "pidTPC.pid-tiny-mu": "-1", + "pidTPC.pid-tiny-el": "-1", + "pidTPC.ccdb-timestamp": "0", + "pidTPC.enableNetworkOptimizations": "1", + "pidTPC.pid-full-ka": "-1", + "pidTPC.skipTPCOnly": "-1", + "pidTPC.pid-tiny-al": "-1", + "pidTPC.networkPathCCDB": "Analysis/PID/TPC/ML", + "pidTPC.useNetworkAl": "0", + "pidTPC.autofetchNetworks": "1", + "pidTPC.useNetworkEl": "1", + "processTracksIU": "1", + "pidTPC.ccdbPath": "Analysis/PID/TPC/Response", + "pidTPC.useNetworkMu": "0", + "pidTPC.enableTuneOnDataTable": "-1", + "pidTPC.pid-full-mu": "-1", + "pidTPC.networkPathLocally": "network.onnx", + "processTracksIUWithTracksQA": "0", + "pidTPC.pid-full-el": "-1", + "pidTPC.pid-tiny-pi": "-1", + "pidTPC.ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "pidTPC.pid-tiny-tr": "-1", + "pidTPC.useNetworkDe": "0", + "pidTPC.pid-full-al": "-1", + "pidTPC.pid-tiny-he": "-1", + "pidTPC.useNetworkPr": "1", + "pidTPC.recoPass": "", + "pidTPC.pid-tiny-pr": "-1", + "pidTPC.useNetworkHe": "0", + "pidTPC.pid-tiny-de": "-1", + "pidTPC.useNetworkTr": "0", + "pidTPC.useNetworkPi": "1", + "pidTPC.pid-full-pi": "-1", + "pidTPC.useNetworkKa": "1", + "pidTPC.pid-full-he": "-1", + "pidTPC.pid-full-de": "-1", + "pidTPC.pid-full-tr": "-1", + "pidTPC.param-file": "", + "pidTPC.useCorrecteddEdx": "0", + "pidTPC.networkSetNumThreads": "0", + "pidTPC.pid-full-pr": "-1", + "pidTPC.pid-tiny-ka": "-1", + "pidTPC.networkBetaGammaCutoff": "0.45", + "pidTPC.devicesRequiringTPCOnlyPID": { + "values": [ + "photon-conversion-builder" + ] + }, + "pidTPC.useNetworkCorrection": "1", + "ccdburl": "http://alice-ccdb.cern.ch", + "pidTPC.savedEdxsCorrected": "-1", + "processTracksMCIU": "0" + }, + "propagation-service": { + "trackTuner.updateCurvature": "0", + "cascadeBuilderOpts.mc_findableDetachedCascade": "0", + "processMonteCarloWithPID": "0", + "cascadeBuilderOpts.minCrossedRows": "-1", + "preSelectOpts.preselectOnlyDesiredCascades": "1", + "v0BuilderOpts.mc_addGeneratedGammaMakeCollinear": "1", + "cascadeBuilderOpts.maxDaughterEta": "1.5", + "ccdb.lutPath": "GLO/Param/MatLUTInner", + "v0BuilderOpts.mc_addGeneratedK0Short": "0", + "cascadeBuilderOpts.dcabachtopv": "0.05", + "trackTuner.updateTrackCovMat": "0", + "cascadeBuilderOpts.useCascadeMomentumAtPrimVtx": "0", + "cascadeBuilderOpts.mc_addGeneratedOmegaPlus": "0", + "cascadeBuilderOpts.kfUseV0MassConstraint": "1", + "trackPropagation.fillTrackTunerTable": "0", + "v0BuilderOpts.v0radius": "0.9", + "cascadeBuilderOpts.kfConstructMethod": "2", + "v0BuilderOpts.dcanegtopv": "0.05", + "v0BuilderOpts.mc_addGeneratedLambda": "0", + "cascadeBuilderOpts.casccospa": "0.97", + "cascadeBuilderOpts.mc_addGeneratedOmegaMinus": "0", + "preSelectOpts.lifetimeCut": { + "values": [ + [ + 20, + 60, + 40, + 20 + ] + ] + }, + "trackPropagation.useTrackTuner": "0", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "preSelectOpts.maxTPCpidNsigma": "5", + "trackTuner.updateTrackDCAs": "0", + "cascadeBuilderOpts.kfTuneForOmega": "0", + "trackTuner.pathInputFile": "", + "preSelectOpts.preselectOnlyDesiredV0s": "1", + "preSelectOpts.massWindowSafetyMargin": "0.001", + "trackTuner.updateCurvatureIU": "0", + "cascadeBuilderOpts.mc_addGeneratedXiPlus": "0", + "preSelectOpts.massCutXi": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "trackPropagation.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.", + "v0BuilderOpts.minCrossedRows": "-1", + "processRealDataWithPID": "1", + "trackPropagation.trackTunerConfigSource": "1", + "refitWithMaterialCorrection": "0", + "cascadeBuilderOpts.cascradius": "0.9", + "cascadeBuilderOpts.mc_treatPiToMuDecays": "1", + "processRealData": "0", + "v0BuilderOpts.mc_populateV0MCCoresSymmetric": "1", + "preSelectOpts.massWindownumberOfSigmas": "20", + "trackTuner.usePvRefitCorrections": "0", + "v0BuilderOpts.mc_addGeneratedGamma": "0", + "v0BuilderOpts.moveTPCOnlyTracks": "1", + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "v0BuilderOpts.dcav0dau": "1.5", + "v0BuilderOpts.mc_keepOnlyPhysicalPrimary": "0", + "cascadeBuilderOpts.mc_rapidityWindow": "0.5", + "trackTuner.isInputFileFromCCDB": "0", + "trackTuner.nameInputFile": "", + "v0BuilderOpts.maxDaughterEta": "1.5", + "useV0BufferForCascades": "0", + "v0BuilderOpts.mc_addGeneratedAntiLambda": "0", + "v0BuilderOpts.v0cospa": "0.97", + "deduplicationAlgorithm": "1", + "cascadeBuilderOpts.lambdaMassWindow": "0.01", + "preSelectOpts.massCutOm": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "cascadeBuilderOpts.dcacascdau": "1.5", + "trackTuner.updatePulls": "0", + "processMonteCarlo": "0", + "v0BuilderOpts.mc_populateV0MCCoresAsymmetric": "0", + "preSelectOpts.massCutLambda": { + "values": [ + [ + 0.0011751799611374736, + 0.00012409899500198662, + 0.005479369778186083, + 0.30800899863243103 + ] + ] + }, + "trackTuner.nPhiBins": "0", + "cascadeBuilderOpts.mc_populateCascMCCoresSymmetric": "1", + "v0BuilderOpts.generatePhotonCandidates": "1", + "preSelectOpts.massCutK0": { + "values": [ + [ + 0.0028188200667500496, + 0.0011405700352042913, + 0.0017213800456374884, + 0.5002620220184326 + ] + ] + }, + "trackTuner.pathFileQoverPt": "", + "trackTuner.qOverPtMC": "-1", + "v0BuilderOpts.mc_rapidityWindow": "0.5", + "trackPropagation.axisPtQA": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "cascadeBuilderOpts.kfDoDCAFitterPreMinimCasc": "1", + "v0BuilderOpts.dcapostopv": "0.05", + "preSelectOpts.massCutPhoton": "0.3", + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "cascadeBuilderOpts.kfDoDCAFitterPreMinimV0": "1", + "cascadeBuilderOpts.mc_populateCascMCCoresAsymmetric": "0", + "v0BuilderOpts.mc_findableDetachedV0": "0", + "trackPropagation.useTrkPid": "0", + "trackTuner.nameFileQoverPt": "", + "cascadeBuilderOpts.kfUseCascadeMassConstraint": "0", + "trackTuner.qOverPtData": "-1", + "v0BuilderOpts.mc_treatPiToMuDecays": "1", + "trackTuner.debugInfo": "0", + "trackPropagation.minPropagationDistance": "5", + "ccdburl": "http://alice-ccdb.cern.ch", + "cascadeBuilderOpts.mc_keepOnlyPhysicalPrimary": "0", + "cascadeBuilderOpts.mc_addGeneratedXiMinus": "0", + "mc_findableMode": "0" + }, + "strangeness_tutorial": { + "nBins": "100", + "cutzvertex": "10", + "v0setting_dcav0dau": "1", + "v0setting_dcapostopv": "0.06", + "v0setting_dcanegtopv": "0.06", + "v0setting_cospa": "0.998", + "v0setting_radius": "1.2", + "NSigmaTPCPion": "4" + } +} diff --git a/Tutorials/PWGLF/Strangeness/Original/configuration_step3.json b/Tutorials/PWGLF/Strangeness/Original/configuration_step3.json new file mode 100644 index 00000000000..e5657b368af --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/configuration_step3.json @@ -0,0 +1,598 @@ +{ + "track-selection": { + "ptMax": "1e+10", + "produceTable": "-1", + "etaMin": "-1", + "isRun3": "1", + "itsMatching": "1", + "etaMax": "1", + "compatibilityIU": "0", + "dcaSetup": "0", + "ptMin": "0.1", + "produceFBextendedTable": "-1" + }, + "ft0-corrected-table": { + "ccdb-timestamp": "-1", + "resoFT0C": "20", + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "resoFT0A": "20", + "collisionSystem": "-2", + "addHistograms": "0", + "ccdb-url": "http://alice-ccdb.cern.ch", + "processWithBypassFT0timeInMC": "0", + "processStandard": "1" + }, + "mc-collision-extra": { + "poiEtaWindow": "0.8", + "processNoCentrality": "0", + "pdgCodeOfInterest": "3312", + "processWithCentrality": "1", + "processMcContexts": "0", + "pdgCodeAbsolute": "1" + }, + "mult-cent-table": { + "generatorName": "PYTHIA", + "processRun3WithGlobalCounters": "0", + "processMFT": "0", + "processRun3": "1", + "processCentralityRun2": "0", + "processRun2": "0", + "processMonteCarlo2Mults": "1", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "maxPtGlobalTrack": "1e+10", + "embedINELgtZEROselection": "0", + "minPtGlobalTrack": "0.15", + "autoConfigureProcess": "0", + "ccdbPathCentrality": "Centrality/Estimators", + "doVertexZeq": "1", + "ccdbPathVtxZ": "Centrality/Calibration", + "minNclsITSibGlobalTrack": "1", + "reconstructionPass": "", + "ccdburl": "http://alice-ccdb.cern.ch", + "processCentralityRun3": "1", + "minNclsITSGlobalTrack": "5", + "processMonteCarlo": "1" + }, + "eventselection-run3": { + "timestamp.fatalOnInvalidTimestamp": "0", + "evselOpts.NumberOfOrbitsPerTF": "-1", + "evselOpts.TimeRangeVetoOnCollNarrow": "0.25", + "evselOpts.VzDiffNsigma": "3", + "evselOpts.maxDiffZvtxFT0vsPV": "1", + "bcselOpts.checkRunDurationLimits": "0", + "evselOpts.amIneeded": "-1", + "evselOpts.EpsilonVzDiffVetoInROF": "0.3", + "evselOpts.isMC": "-1", + "bcselOpts.ITSROFrameStartBorderMargin": "-1", + "timestamp.isRun2MC": "-1", + "bcselOpts.TimeFrameStartBorderMargin": "-1", + "bcselOpts.triggerBcShift": "0", + "evselOpts.FT0CamplPerCollCutVetoOnCollInROF": "5000", + "timestamp.orbit-reset-path": "CTP/Calib/OrbitReset", + "evselOpts.TimeIntervalForOccupancyCalculationMin": "-40", + "evselOpts.TimeRangeVetoOnCollStrict": "10", + "timestamp.rct-path": "RCT/Info/RunInformation", + "bcselOpts.maxInactiveChipsPerLayer": { + "values": [ + 8, + 8, + 8, + 111, + 111, + 195, + 195 + ] + }, + "lumiOpts.amIneeded": "-1", + "evselOpts.confSigmaBCforHighPtTracks": "4", + "evselOpts.FT0CamplPerCollCutVetoOnCollInTimeRange": "8000", + "bcselOpts.ITSROFrameEndBorderMargin": "-1", + "evselOpts.VzDiffMargin": "0.2", + "bcselOpts.amIneeded": "-1", + "evselOpts.TimeIntervalForOccupancyCalculationMax": "100", + "ccdburl": "http://alice-ccdb.cern.ch", + "evselOpts.muonSelection": "0", + "evselOpts.UseWeightsForOccupancyEstimator": "1", + "timestamp.verbose": "0", + "bcselOpts.TimeFrameEndBorderMargin": "-1", + "bcselOpts.NumberOfOrbitsPerTF": "-1" + }, + "pid-tpc-service": { + "pidTPC.pid-tiny-mu": "-1", + "pidTPC.pid-tiny-el": "-1", + "pidTPC.ccdb-timestamp": "0", + "pidTPC.enableNetworkOptimizations": "1", + "pidTPC.pid-full-ka": "-1", + "pidTPC.skipTPCOnly": "-1", + "pidTPC.pid-tiny-al": "-1", + "pidTPC.networkPathCCDB": "Analysis/PID/TPC/ML", + "pidTPC.useNetworkAl": "0", + "pidTPC.autofetchNetworks": "1", + "pidTPC.useNetworkEl": "1", + "processTracksIU": "0", + "pidTPC.ccdbPath": "Analysis/PID/TPC/Response", + "pidTPC.useNetworkMu": "0", + "pidTPC.enableTuneOnDataTable": "-1", + "pidTPC.pid-full-mu": "-1", + "pidTPC.networkPathLocally": "network.onnx", + "processTracksIUWithTracksQA": "0", + "pidTPC.pid-full-el": "-1", + "pidTPC.pid-tiny-pi": "-1", + "pidTPC.ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "pidTPC.pid-tiny-tr": "-1", + "pidTPC.useNetworkDe": "0", + "pidTPC.pid-full-al": "-1", + "pidTPC.pid-tiny-he": "-1", + "pidTPC.useNetworkPr": "1", + "pidTPC.recoPass": "", + "pidTPC.pid-tiny-pr": "-1", + "pidTPC.useNetworkHe": "0", + "pidTPC.pid-tiny-de": "-1", + "pidTPC.useNetworkTr": "0", + "pidTPC.useNetworkPi": "1", + "pidTPC.pid-full-pi": "-1", + "pidTPC.useNetworkKa": "1", + "pidTPC.pid-full-he": "-1", + "pidTPC.pid-full-de": "-1", + "pidTPC.pid-full-tr": "-1", + "pidTPC.param-file": "", + "pidTPC.useCorrecteddEdx": "0", + "pidTPC.networkSetNumThreads": "0", + "pidTPC.pid-full-pr": "-1", + "pidTPC.pid-tiny-ka": "-1", + "pidTPC.networkBetaGammaCutoff": "0.45", + "pidTPC.devicesRequiringTPCOnlyPID": { + "values": [ + "photon-conversion-builder" + ] + }, + "pidTPC.useNetworkCorrection": "1", + "ccdburl": "http://alice-ccdb.cern.ch", + "pidTPC.savedEdxsCorrected": "-1", + "processTracksMCIU": "1" + }, + "propagation-service": { + "trackTuner.updateCurvature": "0", + "cascadeBuilderOpts.mc_findableDetachedCascade": "0", + "processMonteCarloWithPID": "0", + "cascadeBuilderOpts.minCrossedRows": "-1", + "preSelectOpts.preselectOnlyDesiredCascades": "0", + "v0BuilderOpts.mc_addGeneratedGammaMakeCollinear": "1", + "cascadeBuilderOpts.maxDaughterEta": "1.5", + "ccdb.lutPath": "GLO/Param/MatLUTInner", + "v0BuilderOpts.mc_addGeneratedK0Short": "1", + "cascadeBuilderOpts.dcabachtopv": "0.05", + "trackTuner.updateTrackCovMat": "0", + "cascadeBuilderOpts.useCascadeMomentumAtPrimVtx": "0", + "cascadeBuilderOpts.mc_addGeneratedOmegaPlus": "1", + "cascadeBuilderOpts.kfUseV0MassConstraint": "1", + "trackPropagation.fillTrackTunerTable": "0", + "v0BuilderOpts.v0radius": "0.9", + "cascadeBuilderOpts.kfConstructMethod": "2", + "v0BuilderOpts.dcanegtopv": "0.05", + "v0BuilderOpts.mc_addGeneratedLambda": "1", + "cascadeBuilderOpts.casccospa": "0.97", + "cascadeBuilderOpts.mc_addGeneratedOmegaMinus": "1", + "preSelectOpts.lifetimeCut": { + "values": [ + [ + 20, + 60, + 40, + 20 + ] + ] + }, + "trackPropagation.useTrackTuner": "0", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "preSelectOpts.maxTPCpidNsigma": "5", + "trackTuner.updateTrackDCAs": "0", + "cascadeBuilderOpts.kfTuneForOmega": "0", + "trackTuner.pathInputFile": "", + "preSelectOpts.preselectOnlyDesiredV0s": "0", + "preSelectOpts.massWindowSafetyMargin": "0.001", + "trackTuner.updateCurvatureIU": "0", + "cascadeBuilderOpts.mc_addGeneratedXiPlus": "1", + "preSelectOpts.massCutXi": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "trackPropagation.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.", + "v0BuilderOpts.minCrossedRows": "-1", + "processRealDataWithPID": "0", + "trackPropagation.trackTunerConfigSource": "1", + "refitWithMaterialCorrection": "0", + "cascadeBuilderOpts.cascradius": "0.9", + "cascadeBuilderOpts.mc_treatPiToMuDecays": "1", + "processRealData": "0", + "v0BuilderOpts.mc_populateV0MCCoresSymmetric": "0", + "preSelectOpts.massWindownumberOfSigmas": "20", + "trackTuner.usePvRefitCorrections": "0", + "v0BuilderOpts.mc_addGeneratedGamma": "1", + "v0BuilderOpts.moveTPCOnlyTracks": "1", + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "v0BuilderOpts.dcav0dau": "1.5", + "v0BuilderOpts.mc_keepOnlyPhysicalPrimary": "1", + "cascadeBuilderOpts.mc_rapidityWindow": "0.5", + "trackTuner.isInputFileFromCCDB": "0", + "trackTuner.nameInputFile": "", + "v0BuilderOpts.maxDaughterEta": "1.5", + "useV0BufferForCascades": "0", + "v0BuilderOpts.mc_addGeneratedAntiLambda": "1", + "v0BuilderOpts.v0cospa": "0.97", + "deduplicationAlgorithm": "1", + "cascadeBuilderOpts.lambdaMassWindow": "0.01", + "preSelectOpts.massCutOm": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "cascadeBuilderOpts.dcacascdau": "1.5", + "trackTuner.updatePulls": "0", + "processMonteCarlo": "1", + "v0BuilderOpts.mc_populateV0MCCoresAsymmetric": "1", + "preSelectOpts.massCutLambda": { + "values": [ + [ + 0.0011751799611374736, + 0.00012409899500198662, + 0.005479369778186083, + 0.30800899863243103 + ] + ] + }, + "trackTuner.nPhiBins": "0", + "cascadeBuilderOpts.mc_populateCascMCCoresSymmetric": "0", + "v0BuilderOpts.generatePhotonCandidates": "1", + "preSelectOpts.massCutK0": { + "values": [ + [ + 0.0028188200667500496, + 0.0011405700352042913, + 0.0017213800456374884, + 0.5002620220184326 + ] + ] + }, + "trackTuner.pathFileQoverPt": "", + "trackTuner.qOverPtMC": "-1", + "v0BuilderOpts.mc_rapidityWindow": "0.5", + "trackPropagation.axisPtQA": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "cascadeBuilderOpts.kfDoDCAFitterPreMinimCasc": "1", + "v0BuilderOpts.dcapostopv": "0.05", + "preSelectOpts.massCutPhoton": "0.3", + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "cascadeBuilderOpts.kfDoDCAFitterPreMinimV0": "1", + "cascadeBuilderOpts.mc_populateCascMCCoresAsymmetric": "1", + "v0BuilderOpts.mc_findableDetachedV0": "0", + "trackPropagation.useTrkPid": "0", + "trackTuner.nameFileQoverPt": "", + "cascadeBuilderOpts.kfUseCascadeMassConstraint": "0", + "trackTuner.qOverPtData": "-1", + "v0BuilderOpts.mc_treatPiToMuDecays": "1", + "trackTuner.debugInfo": "0", + "trackPropagation.minPropagationDistance": "5", + "ccdburl": "http://alice-ccdb.cern.ch", + "cascadeBuilderOpts.mc_keepOnlyPhysicalPrimary": "1", + "cascadeBuilderOpts.mc_addGeneratedXiMinus": "1", + "mc_findableMode": "0" + }, + "strangeness_tutorial": { + "nBins": "100", + "cutzvertex": "10", + "v0setting_dcav0dau": "1", + "v0setting_dcapostopv": "0.06", + "v0setting_dcanegtopv": "0.06", + "v0setting_cospa": "0.998", + "v0setting_radius": "1.2", + "NSigmaTPCPion": "4", + "processRecMC": "true", + "processGenMC": "true" + } +} diff --git a/Tutorials/PWGLF/Strangeness/Original/configuration_step4.json b/Tutorials/PWGLF/Strangeness/Original/configuration_step4.json new file mode 100644 index 00000000000..cdaf9f5a4ef --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/configuration_step4.json @@ -0,0 +1,606 @@ +{ + "track-selection": { + "ptMax": "1e+10", + "produceTable": "-1", + "etaMin": "-1", + "isRun3": "1", + "itsMatching": "1", + "etaMax": "1", + "compatibilityIU": "0", + "dcaSetup": "0", + "ptMin": "0.1", + "produceFBextendedTable": "-1" + }, + "ft0-corrected-table": { + "ccdb-timestamp": "-1", + "resoFT0C": "20", + "ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "resoFT0A": "20", + "collisionSystem": "-2", + "addHistograms": "0", + "ccdb-url": "http://alice-ccdb.cern.ch", + "processWithBypassFT0timeInMC": "0", + "processStandard": "1" + }, + "mc-collision-extra": { + "poiEtaWindow": "0.8", + "processNoCentrality": "0", + "pdgCodeOfInterest": "3312", + "processWithCentrality": "1", + "processMcContexts": "0", + "pdgCodeAbsolute": "1" + }, + "mult-cent-table": { + "generatorName": "PYTHIA", + "processRun3WithGlobalCounters": "0", + "processMFT": "0", + "processRun3": "1", + "processCentralityRun2": "0", + "processRun2": "0", + "processMonteCarlo2Mults": "1", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "maxPtGlobalTrack": "1e+10", + "embedINELgtZEROselection": "0", + "minPtGlobalTrack": "0.15", + "autoConfigureProcess": "0", + "ccdbPathCentrality": "Centrality/Estimators", + "doVertexZeq": "1", + "ccdbPathVtxZ": "Centrality/Calibration", + "minNclsITSibGlobalTrack": "1", + "reconstructionPass": "", + "ccdburl": "http://alice-ccdb.cern.ch", + "processCentralityRun3": "1", + "minNclsITSGlobalTrack": "5", + "processMonteCarlo": "1" + }, + "eventselection-run3": { + "timestamp.fatalOnInvalidTimestamp": "0", + "evselOpts.NumberOfOrbitsPerTF": "-1", + "evselOpts.TimeRangeVetoOnCollNarrow": "0.25", + "evselOpts.VzDiffNsigma": "3", + "evselOpts.maxDiffZvtxFT0vsPV": "1", + "bcselOpts.checkRunDurationLimits": "0", + "evselOpts.amIneeded": "-1", + "evselOpts.EpsilonVzDiffVetoInROF": "0.3", + "evselOpts.isMC": "-1", + "bcselOpts.ITSROFrameStartBorderMargin": "-1", + "timestamp.isRun2MC": "-1", + "bcselOpts.TimeFrameStartBorderMargin": "-1", + "bcselOpts.triggerBcShift": "0", + "evselOpts.FT0CamplPerCollCutVetoOnCollInROF": "5000", + "timestamp.orbit-reset-path": "CTP/Calib/OrbitReset", + "evselOpts.TimeIntervalForOccupancyCalculationMin": "-40", + "evselOpts.TimeRangeVetoOnCollStrict": "10", + "timestamp.rct-path": "RCT/Info/RunInformation", + "bcselOpts.maxInactiveChipsPerLayer": { + "values": [ + 8, + 8, + 8, + 111, + 111, + 195, + 195 + ] + }, + "lumiOpts.amIneeded": "-1", + "evselOpts.confSigmaBCforHighPtTracks": "4", + "evselOpts.FT0CamplPerCollCutVetoOnCollInTimeRange": "8000", + "bcselOpts.ITSROFrameEndBorderMargin": "-1", + "evselOpts.VzDiffMargin": "0.2", + "bcselOpts.amIneeded": "-1", + "evselOpts.TimeIntervalForOccupancyCalculationMax": "100", + "ccdburl": "http://alice-ccdb.cern.ch", + "evselOpts.muonSelection": "0", + "evselOpts.UseWeightsForOccupancyEstimator": "1", + "timestamp.verbose": "0", + "bcselOpts.TimeFrameEndBorderMargin": "-1", + "bcselOpts.NumberOfOrbitsPerTF": "-1" + }, + "pid-tpc-service": { + "pidTPC.pid-tiny-mu": "-1", + "pidTPC.pid-tiny-el": "-1", + "pidTPC.ccdb-timestamp": "0", + "pidTPC.enableNetworkOptimizations": "1", + "pidTPC.pid-full-ka": "-1", + "pidTPC.skipTPCOnly": "-1", + "pidTPC.pid-tiny-al": "-1", + "pidTPC.networkPathCCDB": "Analysis/PID/TPC/ML", + "pidTPC.useNetworkAl": "0", + "pidTPC.autofetchNetworks": "1", + "pidTPC.useNetworkEl": "1", + "processTracksIU": "0", + "pidTPC.ccdbPath": "Analysis/PID/TPC/Response", + "pidTPC.useNetworkMu": "0", + "pidTPC.enableTuneOnDataTable": "-1", + "pidTPC.pid-full-mu": "-1", + "pidTPC.networkPathLocally": "network.onnx", + "processTracksIUWithTracksQA": "0", + "pidTPC.pid-full-el": "-1", + "pidTPC.pid-tiny-pi": "-1", + "pidTPC.ccdb-path-grplhcif": "GLO/Config/GRPLHCIF", + "pidTPC.pid-tiny-tr": "-1", + "pidTPC.useNetworkDe": "0", + "pidTPC.pid-full-al": "-1", + "pidTPC.pid-tiny-he": "-1", + "pidTPC.useNetworkPr": "1", + "pidTPC.recoPass": "", + "pidTPC.pid-tiny-pr": "-1", + "pidTPC.useNetworkHe": "0", + "pidTPC.pid-tiny-de": "-1", + "pidTPC.useNetworkTr": "0", + "pidTPC.useNetworkPi": "1", + "pidTPC.pid-full-pi": "-1", + "pidTPC.useNetworkKa": "1", + "pidTPC.pid-full-he": "-1", + "pidTPC.pid-full-de": "-1", + "pidTPC.pid-full-tr": "-1", + "pidTPC.param-file": "", + "pidTPC.useCorrecteddEdx": "0", + "pidTPC.networkSetNumThreads": "0", + "pidTPC.pid-full-pr": "-1", + "pidTPC.pid-tiny-ka": "-1", + "pidTPC.networkBetaGammaCutoff": "0.45", + "pidTPC.devicesRequiringTPCOnlyPID": { + "values": [ + "photon-conversion-builder" + ] + }, + "pidTPC.useNetworkCorrection": "1", + "ccdburl": "http://alice-ccdb.cern.ch", + "pidTPC.savedEdxsCorrected": "-1", + "processTracksMCIU": "1" + }, + "propagation-service": { + "trackTuner.updateCurvature": "0", + "cascadeBuilderOpts.mc_findableDetachedCascade": "0", + "processMonteCarloWithPID": "0", + "cascadeBuilderOpts.minCrossedRows": "-1", + "preSelectOpts.preselectOnlyDesiredCascades": "0", + "v0BuilderOpts.mc_addGeneratedGammaMakeCollinear": "1", + "cascadeBuilderOpts.maxDaughterEta": "1.5", + "ccdb.lutPath": "GLO/Param/MatLUTInner", + "v0BuilderOpts.mc_addGeneratedK0Short": "1", + "cascadeBuilderOpts.dcabachtopv": "0.05", + "trackTuner.updateTrackCovMat": "0", + "cascadeBuilderOpts.useCascadeMomentumAtPrimVtx": "0", + "cascadeBuilderOpts.mc_addGeneratedOmegaPlus": "1", + "cascadeBuilderOpts.kfUseV0MassConstraint": "1", + "trackPropagation.fillTrackTunerTable": "0", + "v0BuilderOpts.v0radius": "0.9", + "cascadeBuilderOpts.kfConstructMethod": "2", + "v0BuilderOpts.dcanegtopv": "0.05", + "v0BuilderOpts.mc_addGeneratedLambda": "1", + "cascadeBuilderOpts.casccospa": "0.97", + "cascadeBuilderOpts.mc_addGeneratedOmegaMinus": "1", + "preSelectOpts.lifetimeCut": { + "values": [ + [ + 20, + 60, + 40, + 20 + ] + ] + }, + "trackPropagation.useTrackTuner": "0", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "preSelectOpts.maxTPCpidNsigma": "5", + "trackTuner.updateTrackDCAs": "0", + "cascadeBuilderOpts.kfTuneForOmega": "0", + "trackTuner.pathInputFile": "", + "preSelectOpts.preselectOnlyDesiredV0s": "0", + "preSelectOpts.massWindowSafetyMargin": "0.001", + "trackTuner.updateCurvatureIU": "0", + "cascadeBuilderOpts.mc_addGeneratedXiPlus": "1", + "preSelectOpts.massCutXi": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "trackPropagation.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.", + "v0BuilderOpts.minCrossedRows": "-1", + "processRealDataWithPID": "0", + "trackPropagation.trackTunerConfigSource": "1", + "refitWithMaterialCorrection": "0", + "cascadeBuilderOpts.cascradius": "0.9", + "cascadeBuilderOpts.mc_treatPiToMuDecays": "1", + "processRealData": "0", + "v0BuilderOpts.mc_populateV0MCCoresSymmetric": "0", + "preSelectOpts.massWindownumberOfSigmas": "20", + "trackTuner.usePvRefitCorrections": "0", + "v0BuilderOpts.mc_addGeneratedGamma": "1", + "v0BuilderOpts.moveTPCOnlyTracks": "1", + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "enabledTables": { + "values": [ + [ + -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 + ] + ] + }, + "v0BuilderOpts.dcav0dau": "1.5", + "v0BuilderOpts.mc_keepOnlyPhysicalPrimary": "1", + "cascadeBuilderOpts.mc_rapidityWindow": "0.5", + "trackTuner.isInputFileFromCCDB": "0", + "trackTuner.nameInputFile": "", + "v0BuilderOpts.maxDaughterEta": "1.5", + "useV0BufferForCascades": "0", + "v0BuilderOpts.mc_addGeneratedAntiLambda": "1", + "v0BuilderOpts.v0cospa": "0.97", + "deduplicationAlgorithm": "1", + "cascadeBuilderOpts.lambdaMassWindow": "0.01", + "preSelectOpts.massCutOm": { + "values": [ + [ + 0.0014320999616757035, + 0.00020356099412310869, + 0.002431869972497225, + 0.79966801404953 + ] + ] + }, + "cascadeBuilderOpts.dcacascdau": "1.5", + "trackTuner.updatePulls": "0", + "processMonteCarlo": "1", + "v0BuilderOpts.mc_populateV0MCCoresAsymmetric": "1", + "preSelectOpts.massCutLambda": { + "values": [ + [ + 0.0011751799611374736, + 0.00012409899500198662, + 0.005479369778186083, + 0.30800899863243103 + ] + ] + }, + "trackTuner.nPhiBins": "0", + "cascadeBuilderOpts.mc_populateCascMCCoresSymmetric": "0", + "v0BuilderOpts.generatePhotonCandidates": "1", + "preSelectOpts.massCutK0": { + "values": [ + [ + 0.0028188200667500496, + 0.0011405700352042913, + 0.0017213800456374884, + 0.5002620220184326 + ] + ] + }, + "trackTuner.pathFileQoverPt": "", + "trackTuner.qOverPtMC": "-1", + "v0BuilderOpts.mc_rapidityWindow": "0.5", + "trackPropagation.axisPtQA": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "cascadeBuilderOpts.kfDoDCAFitterPreMinimCasc": "1", + "v0BuilderOpts.dcapostopv": "0.05", + "preSelectOpts.massCutPhoton": "0.3", + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "cascadeBuilderOpts.kfDoDCAFitterPreMinimV0": "1", + "cascadeBuilderOpts.mc_populateCascMCCoresAsymmetric": "1", + "v0BuilderOpts.mc_findableDetachedV0": "0", + "trackPropagation.useTrkPid": "0", + "trackTuner.nameFileQoverPt": "", + "cascadeBuilderOpts.kfUseCascadeMassConstraint": "0", + "trackTuner.qOverPtData": "-1", + "v0BuilderOpts.mc_treatPiToMuDecays": "1", + "trackTuner.debugInfo": "0", + "trackPropagation.minPropagationDistance": "5", + "ccdburl": "http://alice-ccdb.cern.ch", + "cascadeBuilderOpts.mc_keepOnlyPhysicalPrimary": "1", + "cascadeBuilderOpts.mc_addGeneratedXiMinus": "1", + "mc_findableMode": "0" + }, + "strangeness_tutorial": { + "nBins": "100", + "cutzvertex": "10", + "v0setting_dcav0dau": "1", + "v0setting_dcapostopv": "0.06", + "v0setting_dcanegtopv": "0.06", + "v0setting_cospa": "0.998", + "v0setting_radius": "1.2", + "cascadesetting_cospa": "0.998", + "cascadesetting_dcacascdau": "1", + "cascadesetting_dcabachtopv": "0.06", + "cascadesetting_mindcav0topv": "1", + "cascadesetting_cascradius": "0.5", + "cascadesetting_v0masswindow": "0.010", + "dcanegtopv": "0.06", + "dcapostopv": "0.06", + "NSigmaTPCPion": "4", + "processRecMC": "true", + "processGenMC": "true" + } +} diff --git a/Tutorials/PWGLF/Strangeness/Original/run_skeleton.sh b/Tutorials/PWGLF/Strangeness/Original/run_skeleton.sh new file mode 100644 index 00000000000..b96bb4e4990 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/run_skeleton.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="skeleton" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_skeleton.json" + +o2-analysis-trackselection ${OPTION} | +o2-analysis-ft0-corrected-table ${OPTION} | +o2-analysis-multcenttable ${OPTION} | +o2-analysis-event-selection-service ${OPTION} | +o2-analysis-pid-tpc-service ${OPTION} | +o2-analysis-propagationservice ${OPTION} | +o2-analysistutorial-lf-strangeness-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${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/Original/run_step0.sh b/Tutorials/PWGLF/Strangeness/Original/run_step0.sh new file mode 100644 index 00000000000..1e895de996f --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/run_step0.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="0" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step0.json" + +o2-analysis-trackselection ${OPTION} | +o2-analysis-ft0-corrected-table ${OPTION} | +o2-analysis-multcenttable ${OPTION} | +o2-analysis-event-selection-service ${OPTION} | +o2-analysis-pid-tpc-service ${OPTION} | +o2-analysis-propagationservice ${OPTION} | +o2-analysistutorial-lf-strangeness-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/Original/run_step1.sh b/Tutorials/PWGLF/Strangeness/Original/run_step1.sh new file mode 100644 index 00000000000..03a327fd307 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/run_step1.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="1" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step1.json" + +o2-analysis-trackselection ${OPTION} | +o2-analysis-ft0-corrected-table ${OPTION} | +o2-analysis-multcenttable ${OPTION} | +o2-analysis-event-selection-service ${OPTION} | +o2-analysis-pid-tpc-service ${OPTION} | +o2-analysis-propagationservice ${OPTION} | +o2-analysistutorial-lf-strangeness-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/Original/run_step2.sh b/Tutorials/PWGLF/Strangeness/Original/run_step2.sh new file mode 100644 index 00000000000..27c596d1694 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/run_step2.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="2" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step2.json" + +o2-analysis-trackselection ${OPTION} | +o2-analysis-ft0-corrected-table ${OPTION} | +o2-analysis-multcenttable ${OPTION} | +o2-analysis-event-selection-service ${OPTION} | +o2-analysis-pid-tpc-service ${OPTION} | +o2-analysis-propagationservice ${OPTION} | +o2-analysistutorial-lf-strangeness-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/Original/run_step3.sh b/Tutorials/PWGLF/Strangeness/Original/run_step3.sh new file mode 100644 index 00000000000..ffaeea614a7 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/run_step3.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="3" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step3.json" + +o2-analysis-trackselection ${OPTION} | +o2-analysis-ft0-corrected-table ${OPTION} | +o2-analysis-mccollisionextra ${OPTION} | +o2-analysis-multcenttable ${OPTION} | +o2-analysis-event-selection-service ${OPTION} | +o2-analysis-pid-tpc-service ${OPTION} | +o2-analysis-propagationservice ${OPTION} | +o2-analysistutorial-lf-strangeness-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 \ No newline at end of file diff --git a/Tutorials/PWGLF/Strangeness/Original/run_step4.sh b/Tutorials/PWGLF/Strangeness/Original/run_step4.sh new file mode 100644 index 00000000000..fd98b1fa358 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/run_step4.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="4" +LOGFILE="log-STEP${STEP}.txt" + +#directory of this script +DIR_THIS=$PWD + +OPTION="-b --configuration json://configuration_step4.json" + +o2-analysis-trackselection ${OPTION} | +o2-analysis-ft0-corrected-table ${OPTION} | +o2-analysis-mccollisionextra ${OPTION} | +o2-analysis-multcenttable ${OPTION} | +o2-analysis-event-selection-service ${OPTION} | +o2-analysis-pid-tpc-service ${OPTION} | +o2-analysis-propagationservice ${OPTION} | +o2-analysistutorial-lf-strangeness-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/Original/strangeness_skeleton.cxx b/Tutorials/PWGLF/Strangeness/Original/strangeness_skeleton.cxx new file mode 100644 index 00000000000..761da227e3c --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/Original/strangeness_skeleton.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. +/// +/// \brief this is a starting point for the Strangeness tutorial +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct strangeness_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)"}; + + 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/strangeness_step0.cxx b/Tutorials/PWGLF/Strangeness/Original/strangeness_step0.cxx similarity index 99% rename from Tutorials/PWGLF/Strangeness/strangeness_step0.cxx rename to Tutorials/PWGLF/Strangeness/Original/strangeness_step0.cxx index a14b0a5aa3f..4c2b6569e09 100644 --- a/Tutorials/PWGLF/Strangeness/strangeness_step0.cxx +++ b/Tutorials/PWGLF/Strangeness/Original/strangeness_step0.cxx @@ -13,11 +13,13 @@ /// \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 "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step1.cxx b/Tutorials/PWGLF/Strangeness/Original/strangeness_step1.cxx similarity index 99% rename from Tutorials/PWGLF/Strangeness/strangeness_step1.cxx rename to Tutorials/PWGLF/Strangeness/Original/strangeness_step1.cxx index 70748658778..ca57646dc97 100644 --- a/Tutorials/PWGLF/Strangeness/strangeness_step1.cxx +++ b/Tutorials/PWGLF/Strangeness/Original/strangeness_step1.cxx @@ -13,11 +13,13 @@ /// \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 "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step2.cxx b/Tutorials/PWGLF/Strangeness/Original/strangeness_step2.cxx similarity index 96% rename from Tutorials/PWGLF/Strangeness/strangeness_step2.cxx rename to Tutorials/PWGLF/Strangeness/Original/strangeness_step2.cxx index 9701410db1b..f41aac138f5 100644 --- a/Tutorials/PWGLF/Strangeness/strangeness_step2.cxx +++ b/Tutorials/PWGLF/Strangeness/Original/strangeness_step2.cxx @@ -13,11 +13,12 @@ /// \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 "Common/DataModel/PIDResponse.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; @@ -108,10 +109,10 @@ struct strangeness_tutorial { if (v0.v0radius() < v0setting_radius) continue; - if (TMath::Abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } - if (TMath::Abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step3.cxx b/Tutorials/PWGLF/Strangeness/Original/strangeness_step3.cxx similarity index 95% rename from Tutorials/PWGLF/Strangeness/strangeness_step3.cxx rename to Tutorials/PWGLF/Strangeness/Original/strangeness_step3.cxx index 6121831fadb..16a71ee81e5 100644 --- a/Tutorials/PWGLF/Strangeness/strangeness_step3.cxx +++ b/Tutorials/PWGLF/Strangeness/Original/strangeness_step3.cxx @@ -13,11 +13,12 @@ /// \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 "Common/DataModel/PIDResponse.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; @@ -122,10 +123,10 @@ struct strangeness_tutorial { if (v0.v0radius() < v0setting_radius) continue; - if (TMath::Abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } - if (TMath::Abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } @@ -144,7 +145,7 @@ struct strangeness_tutorial { if (posDaughterTrack.has_mcParticle() && negDaughterTrack.has_mcParticle()) { // Checking that the daughter tracks come from particles and are not fake auto posParticle = posDaughterTrack.mcParticle(); auto negParticle = negDaughterTrack.mcParticle(); - if (posParticle.pdgCode() == 211 && negParticle.pdgCode() == -211) { // Checking that the daughter tracks are true pions + if (posParticle.pdgCode() == PDG_t::kPiPlus && negParticle.pdgCode() == PDG_t::kPiMinus) { // Checking that the daughter tracks are true pions rKzeroShort.fill(HIST("hMassK0ShortSelectedTruePions"), v0.mK0Short()); } } @@ -152,7 +153,7 @@ struct strangeness_tutorial { // Checking that the V0 is a true K0s if (v0.has_mcParticle()) { auto v0mcParticle = v0.mcParticle(); - if (v0mcParticle.pdgCode() == 310) { + if (v0mcParticle.pdgCode() == PDG_t::kK0Short) { rKzeroShort.fill(HIST("hMassK0ShortTrueRec"), v0.mK0Short()); rKzeroShort.fill(HIST("hPtK0ShortTrueRec"), v0.pt()); // To mimic distribution after the signal extraction } @@ -168,7 +169,7 @@ struct strangeness_tutorial { return; rEventSelection.fill(HIST("hVertexZGen"), mcCollision.posZ()); for (const auto& mcParticle : mcParticles) { - if (mcParticle.pdgCode() == 310) { + if (mcParticle.pdgCode() == PDG_t::kK0Short) { rGenParticles.fill(HIST("hPtK0ShortGen"), mcParticle.pt()); } } diff --git a/Tutorials/PWGLF/Strangeness/strangeness_step4.cxx b/Tutorials/PWGLF/Strangeness/Original/strangeness_step4.cxx similarity index 91% rename from Tutorials/PWGLF/Strangeness/strangeness_step4.cxx rename to Tutorials/PWGLF/Strangeness/Original/strangeness_step4.cxx index 544d4283932..eb8893e2cd2 100644 --- a/Tutorials/PWGLF/Strangeness/strangeness_step4.cxx +++ b/Tutorials/PWGLF/Strangeness/Original/strangeness_step4.cxx @@ -13,12 +13,12 @@ /// \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 "Common/DataModel/PIDResponse.h" -#include "Framework/O2DatabasePDGPlugin.h" + +#include "Common/DataModel/EventSelection.h" + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" using namespace o2; using namespace o2::framework; @@ -70,9 +70,6 @@ struct strangeness_tutorial { Configurable NSigmaTPCPion{"NSigmaTPCPion", 4, "NSigmaTPCPion"}; Configurable NSigmaTPCProton{"NSigmaTPCProton", 4, "NSigmaTPCProton"}; - // PDG data base - Service pdgDB; - void init(InitContext const&) { // Axes @@ -161,10 +158,10 @@ struct strangeness_tutorial { if (v0.v0radius() < v0setting_radius) continue; - if (TMath::Abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } - if (TMath::Abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } @@ -183,7 +180,7 @@ struct strangeness_tutorial { if (posDaughterTrack.has_mcParticle() && negDaughterTrack.has_mcParticle()) { // Checking that the daughter tracks come from particles and are not fake auto posParticle = posDaughterTrack.mcParticle(); auto negParticle = negDaughterTrack.mcParticle(); - if (posParticle.pdgCode() == 211 && negParticle.pdgCode() == -211) { // Checking that the daughter tracks are true pions + if (posParticle.pdgCode() == PDG_t::kPiPlus && negParticle.pdgCode() == PDG_t::kPiMinus) { // Checking that the daughter tracks are true pions rKzeroShort.fill(HIST("hMassK0ShortSelectedTruePions"), v0.mK0Short()); } } @@ -191,7 +188,7 @@ struct strangeness_tutorial { // Checking that the V0 is a true K0s if (v0.has_mcParticle()) { auto v0mcParticle = v0.mcParticle(); - if (v0mcParticle.pdgCode() == 310) { + if (v0mcParticle.pdgCode() == PDG_t::kK0Short) { rKzeroShort.fill(HIST("hMassK0ShortTrueRec"), v0.mK0Short()); rKzeroShort.fill(HIST("hPtK0ShortTrueRec"), v0.pt()); // To mimic distribution after the signal extraction } @@ -209,7 +206,7 @@ struct strangeness_tutorial { // Cut on dynamic columns if (casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_cospa) continue; - if (TMath::Abs(casc.mLambda() - pdgDB->Mass(3122)) > cascadesetting_v0masswindow) + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda) > cascadesetting_v0masswindow) continue; if (casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()) < cascadesetting_mindcav0topv) continue; @@ -217,21 +214,21 @@ struct strangeness_tutorial { continue; if (casc.sign() < 0) { - if (TMath::Abs(posDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + if (std::abs(posDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { continue; } - if (TMath::Abs(negDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(negDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } } else { - if (TMath::Abs(negDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { + if (std::abs(negDaughterTrackCasc.tpcNSigmaPr()) > NSigmaTPCProton) { continue; } - if (TMath::Abs(posDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(posDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } } - if (TMath::Abs(bachDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { + if (std::abs(bachDaughterTrackCasc.tpcNSigmaPi()) > NSigmaTPCPion) { continue; } @@ -242,7 +239,7 @@ struct strangeness_tutorial { // Checking that the cascade is a true Xi if (casc.has_mcParticle()) { const auto cascmcParticle = casc.mcParticle(); - if (TMath::Abs(cascmcParticle.pdgCode()) == 3312) { + if (std::abs(cascmcParticle.pdgCode()) == PDG_t::kXiMinus) { rXi.fill(HIST("hMassXiTrueRec"), casc.mXi()); } } @@ -257,10 +254,10 @@ struct strangeness_tutorial { return; rEventSelection.fill(HIST("hVertexZGen"), mcCollision.posZ()); for (const auto& mcParticle : mcParticles) { - if (mcParticle.pdgCode() == 310) { + if (mcParticle.pdgCode() == PDG_t::kK0Short) { rGenParticles.fill(HIST("hPtK0ShortGen"), mcParticle.pt()); } - if (TMath::Abs(mcParticle.pdgCode()) == 3312) { + if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { rGenParticles.fill(HIST("hPtXiGen"), mcParticle.pt()); } } 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/PWGUD/CMakeLists.txt b/Tutorials/PWGUD/CMakeLists.txt index da52aa07b26..8eeea02cd35 100644 --- a/Tutorials/PWGUD/CMakeLists.txt +++ b/Tutorials/PWGUD/CMakeLists.txt @@ -39,3 +39,23 @@ 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) + +o2physics_add_dpl_workflow(udtutorial-08 + SOURCES UDTutorial_08.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::SGCutParHolder + COMPONENT_NAME Analysis) + diff --git a/Tutorials/PWGUD/UDTutorial_05.cxx b/Tutorials/PWGUD/UDTutorial_05.cxx new file mode 100644 index 00000000000..40375c48614 --- /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 +#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..0060b68293e --- /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 +#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/PWGUD/UDTutorial_08.cxx b/Tutorials/PWGUD/UDTutorial_08.cxx new file mode 100644 index 00000000000..b9795210c87 --- /dev/null +++ b/Tutorials/PWGUD/UDTutorial_08.cxx @@ -0,0 +1,106 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does 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 UD tutorial demonstrating event selection using SGSelector. Processes raw AO2Ds. Dependency: o2-analysis-event-selection-service +// \author Sigurd Nese +// \since November 2025 + +#include "PWGUD/Core/SGSelector.h" + +#include +#include +#include + +using namespace o2::framework; + +// EvSels table contains connection between collision and BC +using MyEvents = o2::soa::Join; +// BcSels table contains connection between BC and FIT info. Run3MatchedToBCSparse table contains index into ZDC table. +using MyBCs = o2::soa::Join; + +struct UDTutorial08 { + + // Histogram setup + OutputObj hSelectionResult{TH1I("hSelectionResult", "hSelectionResult", 5, -0.5, 4.5)}; + OutputObj hSelectionResultAfterCut{TH1I("hSelectionResultAfterCut", "hSelectionResultAfterCut", 5, -0.5, 4.5)}; + OutputObj hZNAEnergy{TH1F("hZNAEnergy", "hZNAEnergy", 200, 0, 20)}; + OutputObj hZNAEnergyAfterCut{TH1F("hZNAEnergyAfterCut", "hZNAEnergyAfterCut", 200, 0, 20)}; + OutputObj hZNCEnergy{TH1F("hZNCEnergy", "hZNCEnergy", 200, 0, 20)}; + OutputObj hZNCEnergyAfterCut{TH1F("hZNCEnergyAfterCut", "hZNCEnergyAfterCut", 200, 0, 20)}; + // Create instance of the selector class which runs the gap selection algorithm + SGSelector sgSelector; + // Create instance of cut holder class to contain the user defined cuts + SGCutParHolder sgCuts = SGCutParHolder(); + + void init(o2::framework::InitContext&) + { + // Configure the gap selection criteria. Rest of the values are kept default + sgCuts.SetNDtcoll(1); // Time range to consider, in units of collision time resolution + sgCuts.SetMinNBCs(2); // Minimum number of BCs to check + sgCuts.SetNTracks(2, 100); // Reject collisions with < 2 tracks and > 100 tracks + sgCuts.SetMaxFITtime(34); // Reject collisions with FIT time > 34 ns in a compatible BC + sgCuts.SetFITAmpLimits({-1, // Don't use the FV0A for selection + 150, // Require FT0A amplitude to be below 150 in all compatible BCs to classify as gap + 50, // Require FT0C amplitude to be below 50 in all compatible BCs to classify as gap + -1, // Don't use the FDDA for selection + -1}); // Don't use the FDDC for selection + } + + void process(MyEvents::iterator const& collision, // Process collision by collision + MyBCs const& bcs, // We will check a range of bunch crossings + o2::aod::FT0s const&, // Must subscribe to the FIT tables for the SGSelector to access them + o2::aod::FDDs const&, + o2::aod::FV0As const&, + o2::aod::Zdcs const&) // Want to plot ZDC energies, so we need to subscribe to the ZDC table + { + // Find the bunch crossing assigned to this collision + auto bc = collision.foundBC_as(); + // Find the range of bunch crossings compatible with this collision + auto bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); + // Determine whether this event is single gap (A or C), double gap, or no gap + auto selectorResult = sgSelector.IsSelected(sgCuts, collision, bcRange, bc); + auto newbc = *(selectorResult.bc); + + // --- Process the event here: Apply cuts, save to derived tables, fill histograms... --- + + // Plot the outcome of the gap selection algorithm + hSelectionResult->Fill(selectorResult.value); + // Plot ZDC energies + if (newbc.has_zdc()) { + auto zdc = newbc.zdc(); + hZNAEnergy->Fill(zdc.energyCommonZNA()); + hZNCEnergy->Fill(zdc.energyCommonZNC()); + } else { + hZNAEnergy->Fill(-999); + hZNCEnergy->Fill(-999); + } + + // Apply a selection -- as an example, keep only events classified as single gap on C side + if (selectorResult.value != o2::aod::sgselector::SingleGapC) { + return; + } + hSelectionResultAfterCut->Fill(selectorResult.value); + if (newbc.has_zdc()) { + auto zdc = newbc.zdc(); + hZNAEnergyAfterCut->Fill(zdc.energyCommonZNA()); + hZNCEnergyAfterCut->Fill(zdc.energyCommonZNC()); + } else { + hZNAEnergyAfterCut->Fill(-999); + hZNCEnergyAfterCut->Fill(-999); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"udtutorial08"})}; +} diff --git a/Tutorials/src/eventMixing.cxx b/Tutorials/src/eventMixing.cxx index ff5c55da865..a1526740886 100644 --- a/Tutorials/src/eventMixing.cxx +++ b/Tutorials/src/eventMixing.cxx @@ -9,10 +9,13 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// +/// \file eventMixing.cxx /// \brief Example tasks for event mixing. -/// \author +/// \author Karwowska Maja /// \since +#include +#include "Framework/AnalysisDataModel.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" @@ -31,24 +34,24 @@ 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 struct MixedEvents { SliceCache cache; + Preslice perCollision = aod::track::collisionId; 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) + 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()); int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { // 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()}); @@ -60,7 +63,7 @@ struct MixedEvents { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); trackCount++; if (trackCount == 10) @@ -72,12 +75,14 @@ struct MixedEvents { struct MixedEventsInsideProcess { SliceCache cache; + Preslice perCollision = aod::track::collisionId; 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) - void process(aod::Collisions& collisions, aod::Tracks& tracks) + void process(aod::Collisions const& collisions, aod::Tracks const& tracks) + { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); @@ -85,7 +90,7 @@ struct MixedEventsInsideProcess { SameKindPair pair{binningOnPositions, 5, -1, collisions, tracksTuple, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); count++; if (count == 10) @@ -93,7 +98,7 @@ struct MixedEventsInsideProcess { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); trackCount++; if (trackCount == 10) @@ -105,21 +110,22 @@ struct MixedEventsInsideProcess { struct MixedEventsFilteredTracks { SliceCache cache; + Preslice perCollision = aod::track::collisionId; Filter trackFilter = aod::track::eta < 1.0f; - using myTracks = soa::Filtered; + using MyTracks = soa::Filtered; 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 + 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, myTracks const& tracks) + void process(aod::Collisions const& collisions, MyTracks const& tracks) { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); count++; if (count == 100) @@ -127,7 +133,7 @@ struct MixedEventsFilteredTracks { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { LOGF(info, "Mixed event tracks pair: (%d, %d) (%.2f, %.2f) < 1.0f from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), t1.eta(), t2.eta(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); trackCount++; if (trackCount == 10) @@ -139,19 +145,20 @@ struct MixedEventsFilteredTracks { struct MixedEventsJoinedCollisions { SliceCache cache; - using aodCollisions = soa::Join; + Preslice perCollision = aod::track::collisionId; + using AODCollisions = soa::Join; 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 + 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(aodCollisions& collisions, aod::Tracks const& tracks, aod::BCsWithTimestamps const&) + void process(AODCollisions const& collisions, aod::Tracks const& tracks, aod::BCsWithTimestamps const&) { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); count++; if (count == 10) @@ -159,8 +166,8 @@ struct MixedEventsJoinedCollisions { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { - LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision_as().index(), t2.collision_as().index()); trackCount++; if (trackCount == 10) break; @@ -171,19 +178,20 @@ struct MixedEventsJoinedCollisions { struct MixedEventsDynamicColumns { SliceCache cache; - using aodCollisions = soa::Join; + Preslice perCollison = aod::track::collisionId; + using AODCollisions = soa::Join; std::vector zBins{7, -7, 7}; std::vector multBins{VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 100.1}; using BinningType = ColumnBinningPolicy>; - BinningType corrBinning{{zBins, multBins}, true}; // true is for 'ignore overflows' (true by default) - SameKindPair pair{corrBinning, 5, -1, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored + BinningType corrBinning{{zBins, multBins}, true}; // true is for 'ignore overflows' (true by default) + SameKindPair pair{corrBinning, 5, -1, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored - void process(aodCollisions& collisions, aod::Tracks const& tracks) + void process(AODCollisions const& collisions, aod::Tracks const& tracks) { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); count++; if (count == 10) @@ -191,8 +199,8 @@ struct MixedEventsDynamicColumns { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { - LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision_as().index(), t2.collision_as().index()); trackCount++; if (trackCount == 10) break; @@ -203,10 +211,12 @@ struct MixedEventsDynamicColumns { struct MixedEventsVariousKinds { SliceCache cache; + Preslice perCollisionTrack = aod::track::collisionId; + Preslice perCollisionV0 = aod::v0::collisionId; 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) + BinningType binningOnPositions{{xBins, yBins}, true}; // true is for 'ignore overflows' (true by default) Pair 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, aod::V0s const& v0s) @@ -216,7 +226,7 @@ struct MixedEventsVariousKinds { int count = 0; // tracks1 is an aod::Tracks table of tracks belonging to collision c1 (aod::Collision::iterator) // tracks2 is an aod::V0s table of V0s belonging to collision c2 (aod::Collision::iterator) - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); count++; if (count == 100) @@ -224,7 +234,7 @@ struct MixedEventsVariousKinds { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); trackCount++; if (trackCount == 10) @@ -236,11 +246,12 @@ struct MixedEventsVariousKinds { struct MixedEventsTriple { SliceCache cache; + Preslice perCollision = aod::track::collisionId; 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}; std::vector zBins{7, -7, 7}; using BinningType = ColumnBinningPolicy; - BinningType binningOnPositions{{xBins, yBins, zBins}, true}; // true is for 'ignore overflows' (true by default) + BinningType binningOnPositions{{xBins, yBins, zBins}, true}; // true is for 'ignore overflows' (true by default) SameKindTriple triple{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) @@ -248,7 +259,7 @@ struct MixedEventsTriple { LOGF(info, "Input data Collisions %d, Tracks %d", collisions.size(), tracks.size()); int count = 0; - for (auto& [c1, tracks1, c2, tracks2, c3, tracks3] : triple) { + for (const auto& [c1, tracks1, c2, tracks2, c3, tracks3] : triple) { LOGF(info, "Mixed event collisions: (%d, %d, %d)", c1.globalIndex(), c2.globalIndex(), c3.globalIndex()); count++; if (count == 100) @@ -256,7 +267,7 @@ struct MixedEventsTriple { // Example of using tracks from mixed events -- iterate over all track triplets from the three collisions int trackCount = 0; - for (auto& [t1, t2, t3] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2, tracks3))) { + for (const auto& [t1, t2, t3] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2, tracks3))) { LOGF(info, "Mixed event tracks triple: (%d, %d, %d) from events (%d, %d, %d), track event: (%d, %d, %d)", t1.index(), t2.index(), t3.index(), c1.index(), c2.index(), c3.index(), t1.collision().index(), t2.collision().index(), t3.collision().index()); trackCount++; if (trackCount == 10) @@ -268,11 +279,13 @@ struct MixedEventsTriple { struct MixedEventsTripleVariousKinds { SliceCache cache; + Preslice perCollisionTrack = aod::track::collisionId; + Preslice perCollisionV0 = aod::v0::collisionId; 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}; std::vector zBins{7, -7, 7}; using BinningType = ColumnBinningPolicy; - BinningType binningOnPositions{{xBins, yBins, zBins}, true}; // true is for 'ignore overflows' (true by default) + BinningType binningOnPositions{{xBins, yBins, zBins}, true}; // true is for 'ignore overflows' (true by default) Triple triple{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, aod::V0s const& v0s) @@ -283,7 +296,7 @@ struct MixedEventsTripleVariousKinds { // tracks1 is an aod::Tracks table of tracks belonging to collision c1 (aod::Collision::iterator) // tracks2 is an aod::V0s table of V0s belonging to collision c2 (aod::Collision::iterator) // tracks3 is an aod::Tracks table of tracks belonging to collision c3 (aod::Collision::iterator) - for (auto& [c1, tracks1, c2, tracks2, c3, tracks3] : triple) { + for (const auto& [c1, tracks1, c2, tracks2, c3, tracks3] : triple) { LOGF(info, "Mixed event collisions: (%d, %d, %d)", c1.globalIndex(), c2.globalIndex(), c3.globalIndex()); count++; if (count == 100) @@ -291,7 +304,7 @@ struct MixedEventsTripleVariousKinds { // Example of using tracks from mixed events -- iterate over all track triplets from the three collisions int trackCount = 0; - for (auto& [t1, t2, t3] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2, tracks3))) { + for (const auto& [t1, t2, t3] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2, tracks3))) { LOGF(info, "Mixed event tracks triple: (%d, %d, %d) from events (%d, %d, %d), track event: (%d, %d, %d)", t1.index(), t2.index(), t3.index(), c1.index(), c2.index(), c3.index(), t1.collision().index(), t2.collision().index(), t3.collision().index()); trackCount++; if (trackCount == 10) @@ -304,7 +317,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) @@ -331,9 +344,9 @@ struct HashTask { void process(aod::Collisions const& collisions) { - for (auto& collision : collisions) { + for (const auto& collision : collisions) { int hash = getHash(xBins, yBins, collision.posX(), collision.posY()); - // LOGF(info, "Collision: %d (%f, %f, %f) hash: %d", collision.index(), collision.posX(), collision.posY(), collision.posZ(), hash); + LOGF(info, "Collision: %d (%f, %f, %f) hash: %d", collision.index(), collision.posX(), collision.posY(), collision.posZ(), hash); hashes(hash); } } @@ -341,16 +354,17 @@ struct HashTask { struct MixedEventsWithHashTask { SliceCache cache; - using myCollisions = soa::Join; + Preslice perCollision = aod::track::collisionId; + using MyCollision = soa::Join; NoBinningPolicy hashBin; - SameKindPair> pair{hashBin, 5, -1, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored + SameKindPair> pair{hashBin, 5, -1, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored - void process(myCollisions& collisions, aod::Tracks& tracks) + void process(MyCollision const& collisions, aod::Tracks const& tracks) { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); count++; if (count == 10) @@ -358,7 +372,7 @@ struct MixedEventsWithHashTask { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d)", t1.globalIndex(), t2.globalIndex(), c1.globalIndex(), c2.globalIndex()); trackCount++; if (trackCount == 10) @@ -370,27 +384,28 @@ struct MixedEventsWithHashTask { struct MixedEventsPartitionedTracks { SliceCache cache; + Preslice perCollision = aod::track::collisionId; Filter trackFilter = (aod::track::x > -0.8f) && (aod::track::x < 0.8f) && (aod::track::y > 1.0f); - using myTracks = soa::Filtered; + using MyTracks = soa::Filtered; - Configurable philow{"phiLow", 1.0f, "lowest phi"}; - Configurable phiup{"phiUp", 2.0f, "highest phi"}; + Configurable phiLow{"phiLow", 1.0f, "lowest phi"}; + Configurable phiUp{"phiUp", 2.0f, "highest phi"}; 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 + 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, myTracks const& tracks) + void process(aod::Collisions const& collisions, MyTracks const& tracks) { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); - for (auto& [c1, tracks1, c2, tracks2] : pair) { - Partition leftPhi1 = aod::track::phi < philow; - Partition leftPhi2 = aod::track::phi < philow; - Partition rightPhi1 = aod::track::phi >= phiup; - Partition rightPhi2 = aod::track::phi >= phiup; + for (const auto& [c1, tracks1, c2, tracks2] : pair) { + Partition leftPhi1 = aod::track::phi < phiLow; + Partition leftPhi2 = aod::track::phi < phiLow; + Partition rightPhi1 = aod::track::phi >= phiUp; + Partition rightPhi2 = aod::track::phi >= phiUp; leftPhi1.bindTable(tracks1); leftPhi2.bindTable(tracks2); rightPhi1.bindTable(tracks1); @@ -399,14 +414,14 @@ struct MixedEventsPartitionedTracks { LOGF(info, "Mixed event collisions: (%d, %d), tracks: (%d, %d), left phis: (%d, %d), right phis: (%d, %d)", c1.globalIndex(), c2.globalIndex(), tracks1.size(), tracks2.size(), leftPhi1.size(), leftPhi2.size(), rightPhi1.size(), rightPhi2.size()); // Example of using tracks from mixed events -- iterate over all track pairs from the two partitions from two collisions - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(leftPhi1, leftPhi2))) { - if (t1.phi() >= (float)philow || t2.phi() >= (float)philow) { - LOGF(info, "WRONG Mixed event left tracks pair: (%d, %d) from events (%d, %d), phi: (%.3f. %.3f) < %.3f", t1.index(), t2.index(), c1.index(), c2.index(), t1.phi(), t2.phi(), (float)philow); + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(leftPhi1, leftPhi2))) { + if (t1.phi() >= static_cast(phiLow) || t2.phi() >= static_cast(phiLow)) { + LOGF(info, "WRONG Mixed event left tracks pair: (%d, %d) from events (%d, %d), phi: (%.3f. %.3f) < %.3f", t1.index(), t2.index(), c1.index(), c2.index(), t1.phi(), t2.phi(), (float)phiLow); } } - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(rightPhi1, rightPhi2))) { - if (t1.phi() < (float)phiup || t2.phi() < (float)phiup) { - LOGF(info, "WRONG Mixed event right tracks pair: (%d, %d) from events (%d, %d), phi: (%.3f. %.3f) >= %.3f", t1.index(), t2.index(), c1.index(), c2.index(), t1.phi(), t2.phi(), (float)phiup); + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(rightPhi1, rightPhi2))) { + if (t1.phi() < static_cast(phiUp) || t2.phi() < static_cast(phiUp)) { + LOGF(info, "WRONG Mixed event right tracks pair: (%d, %d) from events (%d, %d), phi: (%.3f. %.3f) >= %.3f", t1.index(), t2.index(), c1.index(), c2.index(), t1.phi(), t2.phi(), (float)phiUp); } } } @@ -415,12 +430,12 @@ struct MixedEventsPartitionedTracks { struct MixedEventsLambdaBinning { SliceCache cache; - Preslice perCol = aod::track::collisionId; + Preslice perCollision = aod::track::collisionId; ConfigurableAxis axisVertex{"axisVertex", {14, -7, 7}, "vertex axis for histograms"}; ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0.0, 2.750, 5.250, 7.750, 12.750, 17.750, 22.750, 27.750, 32.750, 37.750, 42.750, 47.750, 52.750, 57.750, 62.750, 67.750, 72.750, 77.750, 82.750, 87.750, 92.750, 97.750, 250.1}, "multiplicity axis for histograms"}; - void process(aod::Collisions& collisions, aod::Tracks& tracks) + void process(aod::Collisions const& collisions, aod::Tracks const& tracks) { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); @@ -437,7 +452,7 @@ struct MixedEventsLambdaBinning { SameKindPair pair{binningWithLambda, 5, -1, collisions, tracksTuple, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { // NOTE that getBin() with FlexibleBinningPolicy needs explicit tuple construction int bin = binningWithLambda.getBin(std::tuple(getTracksSize(c1), c1.posZ())); @@ -448,7 +463,7 @@ struct MixedEventsLambdaBinning { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); trackCount++; if (trackCount == 10) @@ -463,6 +478,7 @@ struct MixedEventsCounters { // https://aliceo2group.github.io/analysis-framework/docs/tutorials/eventMixing.html#mixedeventscounters SliceCache cache; + Preslice perCollision = aod::track::collisionId; 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}; diff --git a/Tutorials/src/eventMixingValidation.cxx b/Tutorials/src/eventMixingValidation.cxx index 2db94b1d082..cc1933b0a25 100644 --- a/Tutorials/src/eventMixingValidation.cxx +++ b/Tutorials/src/eventMixingValidation.cxx @@ -9,11 +9,14 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// +/// \file eventMixingValidation.cxx /// \brief Validation tasks for event mixing. -/// \author +/// \author Karwowska Maja /// \since -#include +#include +#include "Framework/AnalysisDataModel.h" +#include "Framework/SliceCache.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/ASoAHelpers.h" @@ -28,22 +31,23 @@ using namespace o2::soa; struct MixedEventsEmptyTables { SliceCache cache; + Preslice perCollision = aod::track::collisionId; // Dummy filter to enforce empty tables Filter trackFilter = (aod::track::x > -0.8f) && (aod::track::x < -0.8f); - using myTracks = soa::Filtered; + using MyTracks = soa::Filtered; 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 + 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, myTracks const& tracks) + void process(aod::Collisions const& collisions, MyTracks const& tracks) { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); count++; if (count == 10) @@ -51,7 +55,7 @@ struct MixedEventsEmptyTables { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); trackCount++; if (trackCount == 10) @@ -63,6 +67,7 @@ struct MixedEventsEmptyTables { struct MixedEventsJoinedTracks { SliceCache cache; + Preslice perCollision = aod::track::collisionId; 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; @@ -74,7 +79,7 @@ struct MixedEventsJoinedTracks { LOGF(info, "Input data Collisions %d, Tracks %d ", collisions.size(), tracks.size()); int count = 0; - for (auto& [c1, tracks1, c2, tracks2] : pair) { + for (const auto& [c1, tracks1, c2, tracks2] : pair) { LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); count++; if (count == 100) @@ -82,7 +87,7 @@ struct MixedEventsJoinedTracks { // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions int trackCount = 0; - for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { + for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); trackCount++; if (trackCount == 10) @@ -94,6 +99,7 @@ struct MixedEventsJoinedTracks { // It should not compile // struct MixedEventsBadSubscription { +// Preslice perCollision = aod::track::collisionId; // 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; @@ -103,7 +109,7 @@ struct MixedEventsJoinedTracks { // void process(aod::Collisions const& collisions, aod::Tracks const& tracks) // { // int count = 0; -// for (auto& [c1, tracks1, c2, tracks2] : pair) { +// for (const auto& [c1, tracks1, c2, tracks2] : pair) { // LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex()); // count++; // if (count == 10) @@ -111,7 +117,7 @@ struct MixedEventsJoinedTracks { // // // Example of using tracks from mixed events -- iterate over all track pairs from the two collisions // int trackCount = 0; -// for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { +// for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { // LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d), track event: (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index(), t1.collision().index(), t2.collision().index()); // trackCount++; // if (trackCount == 10) 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/filters.cxx b/Tutorials/src/filters.cxx index a3c590b8bfd..7411db8b7ab 100644 --- a/Tutorials/src/filters.cxx +++ b/Tutorials/src/filters.cxx @@ -10,110 +10,65 @@ // or submit itself to any jurisdiction. /// /// \brief Filters are used to select specific rows of a table. -/// \author -/// \since +/// \author Anton Alkin (anton.alkin@cern.ch) +/// \file filters.cxx -#include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" -namespace o2::aod -{ -namespace etaphi -{ -DECLARE_SOA_COLUMN(NPhi, nphi, float); -DECLARE_SOA_EXPRESSION_COLUMN(CosPhi, cosphi, float, - ncos(aod::etaphi::nphi)); -} // namespace etaphi -namespace track -{ -DECLARE_SOA_EXPRESSION_COLUMN(SPt, spt, float, - nabs(aod::track::sigma1Pt / aod::track::signed1Pt)); -} -DECLARE_SOA_TABLE(TPhi, "AOD", "TPHI", - etaphi::NPhi); -DECLARE_SOA_EXTENDED_TABLE_USER(EPhi, TPhi, "EPHI", - aod::etaphi::CosPhi); -using etracks = soa::Join; -DECLARE_SOA_EXTENDED_TABLE_USER(MTracks, etracks, "MTRACK", - aod::track::SPt); -} // namespace o2::aod +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -// production of table o2::aod::TPhi -struct ProduceTPhi { - Produces tphi; - void process(aod::Tracks const& tracks) - { - for (auto& track : tracks) { - tphi(track.phi()); - } - } -}; - // Apply filters on Collisions, Tracks, and TPhi -struct SpawnExtendedTables { - // spawn the extended tables - Spawns ephi; - Spawns mtrk; - - Configurable ptlow{"ptlow", 0.5f, ""}; - Configurable ptup{"ptup", 2.0f, ""}; - Filter ptFilter_a = aod::track::pt > ptlow; - Filter ptFilter_b = aod::track::pt < ptup; +struct Filters { + Configurable ptLow{"ptLow", 0.5f, ""}; + Configurable ptUp{"ptUp", 2.0f, ""}; + Filter ptFilterA = aod::track::pt > ptLow; + Filter ptFilterB = aod::track::pt < ptUp; - Configurable etalow{"etalow", -1.0f, ""}; - Configurable etaup{"etaup", 1.0f, ""}; - Filter etafilter = (aod::track::eta < etaup) && (aod::track::eta > etalow); + Configurable etaLow{"etaLow", -1.0f, ""}; + Configurable etaUp{"etaUp", 1.0f, ""}; + Filter etafilter = (aod::track::eta < etaUp) && (aod::track::eta > etaLow); - float philow = 1.0f; - float phiup = 2.0f; - Filter phifilter = (aod::etaphi::nphi < phiup) && (aod::etaphi::nphi > philow); + Configurable phiLow{"phiLow", 1.0f, "Phi lower limit"}; + Configurable phiUp{"phiUp", 2.0f, "Phi upper limit"}; Configurable vtxZ{"vtxZ", 10.f, ""}; Filter posZfilter = nabs(aod::collision::posZ) < vtxZ; - Filter bitwiseFilter = (o2::aod::track::flags & static_cast(o2::aod::track::TPCrefit)) != 0u; + Filter bitwiseFilter = (aod::track::flags & static_cast(o2::aod::track::PVContributor)) == static_cast(o2::aod::track::PVContributor); - // process only collisions and tracks which pass all defined filter criteria - void process(soa::Filtered::iterator const& collision, soa::Filtered> const& tracks) - { - LOGF(info, "Collision: %d [N = %d out of %d], -%.1f < %.3f < %.1f", - collision.globalIndex(), tracks.size(), tracks.tableSize(), (float)vtxZ, collision.posZ(), (float)vtxZ); - for (auto& track : tracks) { - LOGF(info, "id = %d; eta: %.3f < %.3f < %.3f; phi: %.3f < %.3f < %.3f; pt: %.3f < %.3f < %.3f", - track.collisionId(), (float)etalow, track.eta(), (float)etaup, philow, track.nphi(), phiup, (float)ptlow, track.pt(), (float)ptup); - } - } -}; + // it is now possible to set filters as strings + // note that column designators need the full prefix, i.e. o2::aod:: + // configurables can be used with ncfg(type, value, name) + // where value is the default value + // name is the full name in JSON, with prefix if there is any + Configurable extraFilter{"extraFilter", "(o2::aod::track::phi < ncfg(float,2.0,phiUp)) && (o2::aod::track::phi > ncfg(float,1.0,phiLow))", "extra filter string"}; + Filter extraF; -struct ConsumeExtendedTables { - void process(aod::Collision const&, soa::Join const& tracks) + void init(InitContext&) { - for (auto& track : tracks) { - LOGF(info, "%.3f == %.3f", track.cosphi(), std::cos(track.phi())); + if (!extraFilter->empty()) { + // string-based filters need to be assigned in init() + extraF = Parser::parse(extraFilter); } } -}; -// tracks which are not tracklets -struct FilterTracks { - Filter notTracklet = aod::track::trackType != static_cast(aod::track::TrackTypeEnum::Run2Tracklet); - void process(aod::Collision const&, soa::Filtered const& tracks) + // process only collisions and tracks which pass all defined filter criteria + void process(soa::Filtered::iterator const& collision, soa::Filtered> const& tracks) { - for (auto& track : tracks) { - LOGF(info, "%.3f == %.3f", track.spt(), std::abs(track.sigma1Pt() / track.signed1Pt())); + LOGF(info, "Collision: %d [N = %d out of %d], -%.1f < %.3f < %.1f", + collision.globalIndex(), tracks.size(), tracks.tableSize(), (float)vtxZ, collision.posZ(), (float)vtxZ); + for (auto const& track : tracks) { + LOGP(info, "id = {}; eta: {} < {} < {}; phi: {} < {} < {}; pt: {} < {} < {}", + track.collisionId(), (float)etaLow, track.eta(), (float)etaUp, (float)phiLow, track.phi(), (float)phiUp, (float)ptLow, track.pt(), (float)ptUp); } } }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - }; + return {adaptAnalysisTask(cfgc)}; } 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 72c17a1cb29..17a4ad4bf33 100644 --- a/Tutorials/src/reweighting.cxx +++ b/Tutorials/src/reweighting.cxx @@ -28,11 +28,7 @@ // 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" @@ -82,11 +78,7 @@ 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 @@ -98,17 +90,11 @@ 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; @@ -120,11 +106,6 @@ 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())); @@ -142,7 +123,6 @@ struct CreateWeights { 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]); 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/cppcheck_config b/cppcheck_config new file mode 100644 index 00000000000..506d113f69d --- /dev/null +++ b/cppcheck_config @@ -0,0 +1,5 @@ +syntaxError +unknownMacro +missingIncludeSystem +missingInclude +unusedStructMember:*.h diff --git a/dependencies/FindKFParticle.cmake b/dependencies/FindKFParticle.cmake index 7c789c3f937..6821b601c66 100644 --- a/dependencies/FindKFParticle.cmake +++ b/dependencies/FindKFParticle.cmake @@ -17,7 +17,7 @@ #endif() find_path(KFPARTICLE_INCLUDE_DIR KFParticle.h - PATH_SUFFIXES "include" + PATH_SUFFIXES "include" "include/KFParticle" HINTS "$ENV{KFPARTICLE_ROOT}") find_library(KFPARTICLE_LIBPATH "KFParticle" PATH_SUFFIXES "lib" diff --git a/dependencies/O2PhysicsCompileFlags.cmake b/dependencies/O2PhysicsCompileFlags.cmake index 50967b17ea6..20078b607f7 100644 --- a/dependencies/O2PhysicsCompileFlags.cmake +++ b/dependencies/O2PhysicsCompileFlags.cmake @@ -14,7 +14,7 @@ include_guard() 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 "sign-compare") +set(O2PHYSICS_WARNINGS_COMMON_NO_ERROR "") # Enabled warnings supported by Clang only, not treated as errors set(O2PHYSICS_WARNINGS_CLANG_NO_ERROR "") @@ -81,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/o2linter_config b/o2linter_config new file mode 100644 index 00000000000..66b2d074f62 --- /dev/null +++ b/o2linter_config @@ -0,0 +1,15 @@ +# O2 linter warning categories +root/entity +external-pi +pi-multiple-fraction +doc/file +name/function-variable +name/macro +name/constexpr-constant +name/namespace +name/type +name/enum +name/class +name/struct +name/file-cpp +name/file-python